[Midnightbsd-cvs] src [9640] vendor/wpa/2.0: tag wpa supplicant/hostapd 2.0

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Oct 22 14:12:34 EDT 2017


Revision: 9640
          http://svnweb.midnightbsd.org/src/?rev=9640
Author:   laffer1
Date:     2017-10-22 14:12:33 -0400 (Sun, 22 Oct 2017)
Log Message:
-----------
tag wpa supplicant/hostapd 2.0

Added Paths:
-----------
    vendor/wpa/2.0/
    vendor/wpa/2.0/COPYING
    vendor/wpa/2.0/README
    vendor/wpa/2.0/hostapd/ChangeLog
    vendor/wpa/2.0/hostapd/Makefile
    vendor/wpa/2.0/hostapd/README
    vendor/wpa/2.0/hostapd/README-WPS
    vendor/wpa/2.0/hostapd/config_file.c
    vendor/wpa/2.0/hostapd/config_file.h
    vendor/wpa/2.0/hostapd/ctrl_iface.c
    vendor/wpa/2.0/hostapd/ctrl_iface.h
    vendor/wpa/2.0/hostapd/defconfig
    vendor/wpa/2.0/hostapd/dump_state.c
    vendor/wpa/2.0/hostapd/dump_state.h
    vendor/wpa/2.0/hostapd/eap_register.c
    vendor/wpa/2.0/hostapd/eap_register.h
    vendor/wpa/2.0/hostapd/hlr_auc_gw.c
    vendor/wpa/2.0/hostapd/hlr_auc_gw.txt
    vendor/wpa/2.0/hostapd/hostapd.conf
    vendor/wpa/2.0/hostapd/hostapd.eap_user
    vendor/wpa/2.0/hostapd/hostapd.eap_user_sqlite
    vendor/wpa/2.0/hostapd/hostapd_cli.c
    vendor/wpa/2.0/hostapd/main.c
    vendor/wpa/2.0/hostapd/nt_password_hash.c
    vendor/wpa/2.0/patches/openssl-0.9.8x-tls-extensions.patch
    vendor/wpa/2.0/src/Makefile
    vendor/wpa/2.0/src/ap/accounting.c
    vendor/wpa/2.0/src/ap/accounting.h
    vendor/wpa/2.0/src/ap/ap_config.c
    vendor/wpa/2.0/src/ap/ap_config.h
    vendor/wpa/2.0/src/ap/ap_drv_ops.c
    vendor/wpa/2.0/src/ap/ap_drv_ops.h
    vendor/wpa/2.0/src/ap/ap_list.c
    vendor/wpa/2.0/src/ap/ap_list.h
    vendor/wpa/2.0/src/ap/ap_mlme.c
    vendor/wpa/2.0/src/ap/ap_mlme.h
    vendor/wpa/2.0/src/ap/authsrv.c
    vendor/wpa/2.0/src/ap/authsrv.h
    vendor/wpa/2.0/src/ap/beacon.c
    vendor/wpa/2.0/src/ap/beacon.h
    vendor/wpa/2.0/src/ap/ctrl_iface_ap.c
    vendor/wpa/2.0/src/ap/ctrl_iface_ap.h
    vendor/wpa/2.0/src/ap/drv_callbacks.c
    vendor/wpa/2.0/src/ap/eap_user_db.c
    vendor/wpa/2.0/src/ap/gas_serv.c
    vendor/wpa/2.0/src/ap/gas_serv.h
    vendor/wpa/2.0/src/ap/hostapd.c
    vendor/wpa/2.0/src/ap/hostapd.h
    vendor/wpa/2.0/src/ap/hs20.c
    vendor/wpa/2.0/src/ap/hs20.h
    vendor/wpa/2.0/src/ap/hw_features.c
    vendor/wpa/2.0/src/ap/hw_features.h
    vendor/wpa/2.0/src/ap/iapp.c
    vendor/wpa/2.0/src/ap/iapp.h
    vendor/wpa/2.0/src/ap/ieee802_11.c
    vendor/wpa/2.0/src/ap/ieee802_11.h
    vendor/wpa/2.0/src/ap/ieee802_11_auth.c
    vendor/wpa/2.0/src/ap/ieee802_11_auth.h
    vendor/wpa/2.0/src/ap/ieee802_11_ht.c
    vendor/wpa/2.0/src/ap/ieee802_11_shared.c
    vendor/wpa/2.0/src/ap/ieee802_11_vht.c
    vendor/wpa/2.0/src/ap/ieee802_1x.c
    vendor/wpa/2.0/src/ap/ieee802_1x.h
    vendor/wpa/2.0/src/ap/p2p_hostapd.c
    vendor/wpa/2.0/src/ap/p2p_hostapd.h
    vendor/wpa/2.0/src/ap/peerkey_auth.c
    vendor/wpa/2.0/src/ap/pmksa_cache_auth.c
    vendor/wpa/2.0/src/ap/pmksa_cache_auth.h
    vendor/wpa/2.0/src/ap/preauth_auth.c
    vendor/wpa/2.0/src/ap/preauth_auth.h
    vendor/wpa/2.0/src/ap/sta_info.c
    vendor/wpa/2.0/src/ap/sta_info.h
    vendor/wpa/2.0/src/ap/tkip_countermeasures.c
    vendor/wpa/2.0/src/ap/tkip_countermeasures.h
    vendor/wpa/2.0/src/ap/utils.c
    vendor/wpa/2.0/src/ap/vlan_init.c
    vendor/wpa/2.0/src/ap/vlan_util.c
    vendor/wpa/2.0/src/ap/vlan_util.h
    vendor/wpa/2.0/src/ap/wmm.c
    vendor/wpa/2.0/src/ap/wnm_ap.c
    vendor/wpa/2.0/src/ap/wnm_ap.h
    vendor/wpa/2.0/src/ap/wpa_auth.c
    vendor/wpa/2.0/src/ap/wpa_auth.h
    vendor/wpa/2.0/src/ap/wpa_auth_ft.c
    vendor/wpa/2.0/src/ap/wpa_auth_glue.c
    vendor/wpa/2.0/src/ap/wpa_auth_glue.h
    vendor/wpa/2.0/src/ap/wpa_auth_i.h
    vendor/wpa/2.0/src/ap/wpa_auth_ie.c
    vendor/wpa/2.0/src/ap/wpa_auth_ie.h
    vendor/wpa/2.0/src/ap/wps_hostapd.c
    vendor/wpa/2.0/src/ap/wps_hostapd.h
    vendor/wpa/2.0/src/common/defs.h
    vendor/wpa/2.0/src/common/eapol_common.h
    vendor/wpa/2.0/src/common/gas.c
    vendor/wpa/2.0/src/common/gas.h
    vendor/wpa/2.0/src/common/ieee802_11_common.c
    vendor/wpa/2.0/src/common/ieee802_11_common.h
    vendor/wpa/2.0/src/common/ieee802_11_defs.h
    vendor/wpa/2.0/src/common/privsep_commands.h
    vendor/wpa/2.0/src/common/version.h
    vendor/wpa/2.0/src/common/wpa_common.c
    vendor/wpa/2.0/src/common/wpa_common.h
    vendor/wpa/2.0/src/common/wpa_ctrl.c
    vendor/wpa/2.0/src/common/wpa_ctrl.h
    vendor/wpa/2.0/src/crypto/Makefile
    vendor/wpa/2.0/src/crypto/aes-cbc.c
    vendor/wpa/2.0/src/crypto/aes-ccm.c
    vendor/wpa/2.0/src/crypto/aes-ctr.c
    vendor/wpa/2.0/src/crypto/aes-eax.c
    vendor/wpa/2.0/src/crypto/aes-encblock.c
    vendor/wpa/2.0/src/crypto/aes-gcm.c
    vendor/wpa/2.0/src/crypto/aes-internal-dec.c
    vendor/wpa/2.0/src/crypto/aes-internal-enc.c
    vendor/wpa/2.0/src/crypto/aes-internal.c
    vendor/wpa/2.0/src/crypto/aes-omac1.c
    vendor/wpa/2.0/src/crypto/aes-unwrap.c
    vendor/wpa/2.0/src/crypto/aes-wrap.c
    vendor/wpa/2.0/src/crypto/aes.h
    vendor/wpa/2.0/src/crypto/aes_i.h
    vendor/wpa/2.0/src/crypto/aes_wrap.h
    vendor/wpa/2.0/src/crypto/crypto.h
    vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c
    vendor/wpa/2.0/src/crypto/crypto_gnutls.c
    vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c
    vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c
    vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c
    vendor/wpa/2.0/src/crypto/crypto_internal.c
    vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c
    vendor/wpa/2.0/src/crypto/crypto_none.c
    vendor/wpa/2.0/src/crypto/crypto_nss.c
    vendor/wpa/2.0/src/crypto/crypto_openssl.c
    vendor/wpa/2.0/src/crypto/des-internal.c
    vendor/wpa/2.0/src/crypto/des_i.h
    vendor/wpa/2.0/src/crypto/dh_group5.c
    vendor/wpa/2.0/src/crypto/dh_group5.h
    vendor/wpa/2.0/src/crypto/dh_groups.c
    vendor/wpa/2.0/src/crypto/dh_groups.h
    vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c
    vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c
    vendor/wpa/2.0/src/crypto/fips_prf_internal.c
    vendor/wpa/2.0/src/crypto/fips_prf_nss.c
    vendor/wpa/2.0/src/crypto/fips_prf_openssl.c
    vendor/wpa/2.0/src/crypto/md4-internal.c
    vendor/wpa/2.0/src/crypto/md5-internal.c
    vendor/wpa/2.0/src/crypto/md5.c
    vendor/wpa/2.0/src/crypto/md5.h
    vendor/wpa/2.0/src/crypto/md5_i.h
    vendor/wpa/2.0/src/crypto/milenage.c
    vendor/wpa/2.0/src/crypto/milenage.h
    vendor/wpa/2.0/src/crypto/ms_funcs.c
    vendor/wpa/2.0/src/crypto/ms_funcs.h
    vendor/wpa/2.0/src/crypto/random.c
    vendor/wpa/2.0/src/crypto/random.h
    vendor/wpa/2.0/src/crypto/rc4.c
    vendor/wpa/2.0/src/crypto/sha1-internal.c
    vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c
    vendor/wpa/2.0/src/crypto/sha1-prf.c
    vendor/wpa/2.0/src/crypto/sha1-tlsprf.c
    vendor/wpa/2.0/src/crypto/sha1-tprf.c
    vendor/wpa/2.0/src/crypto/sha1.c
    vendor/wpa/2.0/src/crypto/sha1.h
    vendor/wpa/2.0/src/crypto/sha1_i.h
    vendor/wpa/2.0/src/crypto/sha256-internal.c
    vendor/wpa/2.0/src/crypto/sha256-prf.c
    vendor/wpa/2.0/src/crypto/sha256-tlsprf.c
    vendor/wpa/2.0/src/crypto/sha256.c
    vendor/wpa/2.0/src/crypto/sha256.h
    vendor/wpa/2.0/src/crypto/sha256_i.h
    vendor/wpa/2.0/src/crypto/tls.h
    vendor/wpa/2.0/src/crypto/tls_gnutls.c
    vendor/wpa/2.0/src/crypto/tls_internal.c
    vendor/wpa/2.0/src/crypto/tls_none.c
    vendor/wpa/2.0/src/crypto/tls_nss.c
    vendor/wpa/2.0/src/crypto/tls_openssl.c
    vendor/wpa/2.0/src/crypto/tls_schannel.c
    vendor/wpa/2.0/src/drivers/android_drv.h
    vendor/wpa/2.0/src/drivers/driver.h
    vendor/wpa/2.0/src/drivers/driver_atheros.c
    vendor/wpa/2.0/src/drivers/driver_bsd.c
    vendor/wpa/2.0/src/drivers/driver_common.c
    vendor/wpa/2.0/src/drivers/driver_hostap.c
    vendor/wpa/2.0/src/drivers/driver_hostap.h
    vendor/wpa/2.0/src/drivers/driver_madwifi.c
    vendor/wpa/2.0/src/drivers/driver_ndis.c
    vendor/wpa/2.0/src/drivers/driver_ndis.h
    vendor/wpa/2.0/src/drivers/driver_ndis_.c
    vendor/wpa/2.0/src/drivers/driver_nl80211.c
    vendor/wpa/2.0/src/drivers/driver_none.c
    vendor/wpa/2.0/src/drivers/driver_privsep.c
    vendor/wpa/2.0/src/drivers/driver_roboswitch.c
    vendor/wpa/2.0/src/drivers/driver_test.c
    vendor/wpa/2.0/src/drivers/driver_wext.c
    vendor/wpa/2.0/src/drivers/driver_wext.h
    vendor/wpa/2.0/src/drivers/driver_wired.c
    vendor/wpa/2.0/src/drivers/drivers.c
    vendor/wpa/2.0/src/drivers/drivers.mak
    vendor/wpa/2.0/src/drivers/drivers.mk
    vendor/wpa/2.0/src/drivers/linux_ioctl.c
    vendor/wpa/2.0/src/drivers/linux_ioctl.h
    vendor/wpa/2.0/src/drivers/linux_wext.h
    vendor/wpa/2.0/src/drivers/ndis_events.c
    vendor/wpa/2.0/src/drivers/netlink.c
    vendor/wpa/2.0/src/drivers/netlink.h
    vendor/wpa/2.0/src/drivers/nl80211_copy.h
    vendor/wpa/2.0/src/drivers/priv_netlink.h
    vendor/wpa/2.0/src/drivers/rfkill.c
    vendor/wpa/2.0/src/drivers/rfkill.h
    vendor/wpa/2.0/src/eap_common/chap.c
    vendor/wpa/2.0/src/eap_common/chap.h
    vendor/wpa/2.0/src/eap_common/eap_common.c
    vendor/wpa/2.0/src/eap_common/eap_common.h
    vendor/wpa/2.0/src/eap_common/eap_defs.h
    vendor/wpa/2.0/src/eap_common/eap_fast_common.c
    vendor/wpa/2.0/src/eap_common/eap_fast_common.h
    vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c
    vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h
    vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c
    vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h
    vendor/wpa/2.0/src/eap_common/eap_pax_common.c
    vendor/wpa/2.0/src/eap_common/eap_pax_common.h
    vendor/wpa/2.0/src/eap_common/eap_peap_common.c
    vendor/wpa/2.0/src/eap_common/eap_peap_common.h
    vendor/wpa/2.0/src/eap_common/eap_psk_common.c
    vendor/wpa/2.0/src/eap_common/eap_psk_common.h
    vendor/wpa/2.0/src/eap_common/eap_pwd_common.c
    vendor/wpa/2.0/src/eap_common/eap_pwd_common.h
    vendor/wpa/2.0/src/eap_common/eap_sake_common.c
    vendor/wpa/2.0/src/eap_common/eap_sake_common.h
    vendor/wpa/2.0/src/eap_common/eap_sim_common.c
    vendor/wpa/2.0/src/eap_common/eap_sim_common.h
    vendor/wpa/2.0/src/eap_common/eap_tlv_common.h
    vendor/wpa/2.0/src/eap_common/eap_ttls.h
    vendor/wpa/2.0/src/eap_common/eap_wsc_common.c
    vendor/wpa/2.0/src/eap_common/eap_wsc_common.h
    vendor/wpa/2.0/src/eap_common/ikev2_common.c
    vendor/wpa/2.0/src/eap_common/ikev2_common.h
    vendor/wpa/2.0/src/eap_peer/eap.c
    vendor/wpa/2.0/src/eap_peer/eap.h
    vendor/wpa/2.0/src/eap_peer/eap_aka.c
    vendor/wpa/2.0/src/eap_peer/eap_config.h
    vendor/wpa/2.0/src/eap_peer/eap_fast.c
    vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c
    vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h
    vendor/wpa/2.0/src/eap_peer/eap_gpsk.c
    vendor/wpa/2.0/src/eap_peer/eap_gtc.c
    vendor/wpa/2.0/src/eap_peer/eap_i.h
    vendor/wpa/2.0/src/eap_peer/eap_ikev2.c
    vendor/wpa/2.0/src/eap_peer/eap_leap.c
    vendor/wpa/2.0/src/eap_peer/eap_md5.c
    vendor/wpa/2.0/src/eap_peer/eap_methods.c
    vendor/wpa/2.0/src/eap_peer/eap_methods.h
    vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c
    vendor/wpa/2.0/src/eap_peer/eap_otp.c
    vendor/wpa/2.0/src/eap_peer/eap_pax.c
    vendor/wpa/2.0/src/eap_peer/eap_peap.c
    vendor/wpa/2.0/src/eap_peer/eap_psk.c
    vendor/wpa/2.0/src/eap_peer/eap_pwd.c
    vendor/wpa/2.0/src/eap_peer/eap_sake.c
    vendor/wpa/2.0/src/eap_peer/eap_sim.c
    vendor/wpa/2.0/src/eap_peer/eap_tls.c
    vendor/wpa/2.0/src/eap_peer/eap_tls_common.c
    vendor/wpa/2.0/src/eap_peer/eap_tls_common.h
    vendor/wpa/2.0/src/eap_peer/eap_tnc.c
    vendor/wpa/2.0/src/eap_peer/eap_ttls.c
    vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c
    vendor/wpa/2.0/src/eap_peer/eap_wsc.c
    vendor/wpa/2.0/src/eap_peer/ikev2.c
    vendor/wpa/2.0/src/eap_peer/ikev2.h
    vendor/wpa/2.0/src/eap_peer/mschapv2.c
    vendor/wpa/2.0/src/eap_peer/mschapv2.h
    vendor/wpa/2.0/src/eap_peer/tncc.c
    vendor/wpa/2.0/src/eap_peer/tncc.h
    vendor/wpa/2.0/src/eap_server/eap.h
    vendor/wpa/2.0/src/eap_server/eap_i.h
    vendor/wpa/2.0/src/eap_server/eap_methods.h
    vendor/wpa/2.0/src/eap_server/eap_server.c
    vendor/wpa/2.0/src/eap_server/eap_server_aka.c
    vendor/wpa/2.0/src/eap_server/eap_server_fast.c
    vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c
    vendor/wpa/2.0/src/eap_server/eap_server_gtc.c
    vendor/wpa/2.0/src/eap_server/eap_server_identity.c
    vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c
    vendor/wpa/2.0/src/eap_server/eap_server_md5.c
    vendor/wpa/2.0/src/eap_server/eap_server_methods.c
    vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c
    vendor/wpa/2.0/src/eap_server/eap_server_pax.c
    vendor/wpa/2.0/src/eap_server/eap_server_peap.c
    vendor/wpa/2.0/src/eap_server/eap_server_psk.c
    vendor/wpa/2.0/src/eap_server/eap_server_pwd.c
    vendor/wpa/2.0/src/eap_server/eap_server_sake.c
    vendor/wpa/2.0/src/eap_server/eap_server_sim.c
    vendor/wpa/2.0/src/eap_server/eap_server_tls.c
    vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c
    vendor/wpa/2.0/src/eap_server/eap_server_tnc.c
    vendor/wpa/2.0/src/eap_server/eap_server_ttls.c
    vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c
    vendor/wpa/2.0/src/eap_server/eap_server_wsc.c
    vendor/wpa/2.0/src/eap_server/eap_sim_db.c
    vendor/wpa/2.0/src/eap_server/eap_sim_db.h
    vendor/wpa/2.0/src/eap_server/eap_tls_common.h
    vendor/wpa/2.0/src/eap_server/ikev2.c
    vendor/wpa/2.0/src/eap_server/ikev2.h
    vendor/wpa/2.0/src/eap_server/tncs.c
    vendor/wpa/2.0/src/eap_server/tncs.h
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h
    vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c
    vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h
    vendor/wpa/2.0/src/l2_packet/l2_packet.h
    vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_none.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c
    vendor/wpa/2.0/src/p2p/
    vendor/wpa/2.0/src/radius/radius.c
    vendor/wpa/2.0/src/radius/radius.h
    vendor/wpa/2.0/src/radius/radius_client.c
    vendor/wpa/2.0/src/radius/radius_client.h
    vendor/wpa/2.0/src/radius/radius_das.c
    vendor/wpa/2.0/src/radius/radius_das.h
    vendor/wpa/2.0/src/radius/radius_server.c
    vendor/wpa/2.0/src/radius/radius_server.h
    vendor/wpa/2.0/src/rsn_supp/peerkey.c
    vendor/wpa/2.0/src/rsn_supp/peerkey.h
    vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c
    vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h
    vendor/wpa/2.0/src/rsn_supp/preauth.c
    vendor/wpa/2.0/src/rsn_supp/preauth.h
    vendor/wpa/2.0/src/rsn_supp/tdls.c
    vendor/wpa/2.0/src/rsn_supp/wpa.c
    vendor/wpa/2.0/src/rsn_supp/wpa.h
    vendor/wpa/2.0/src/rsn_supp/wpa_ft.c
    vendor/wpa/2.0/src/rsn_supp/wpa_i.h
    vendor/wpa/2.0/src/rsn_supp/wpa_ie.c
    vendor/wpa/2.0/src/rsn_supp/wpa_ie.h
    vendor/wpa/2.0/src/tls/Makefile
    vendor/wpa/2.0/src/tls/asn1.c
    vendor/wpa/2.0/src/tls/asn1.h
    vendor/wpa/2.0/src/tls/bignum.c
    vendor/wpa/2.0/src/tls/bignum.h
    vendor/wpa/2.0/src/tls/libtommath.c
    vendor/wpa/2.0/src/tls/pkcs1.c
    vendor/wpa/2.0/src/tls/pkcs1.h
    vendor/wpa/2.0/src/tls/pkcs5.c
    vendor/wpa/2.0/src/tls/pkcs5.h
    vendor/wpa/2.0/src/tls/pkcs8.c
    vendor/wpa/2.0/src/tls/pkcs8.h
    vendor/wpa/2.0/src/tls/rsa.c
    vendor/wpa/2.0/src/tls/rsa.h
    vendor/wpa/2.0/src/tls/tlsv1_client.c
    vendor/wpa/2.0/src/tls/tlsv1_client.h
    vendor/wpa/2.0/src/tls/tlsv1_client_i.h
    vendor/wpa/2.0/src/tls/tlsv1_client_read.c
    vendor/wpa/2.0/src/tls/tlsv1_client_write.c
    vendor/wpa/2.0/src/tls/tlsv1_common.c
    vendor/wpa/2.0/src/tls/tlsv1_common.h
    vendor/wpa/2.0/src/tls/tlsv1_cred.c
    vendor/wpa/2.0/src/tls/tlsv1_cred.h
    vendor/wpa/2.0/src/tls/tlsv1_record.c
    vendor/wpa/2.0/src/tls/tlsv1_record.h
    vendor/wpa/2.0/src/tls/tlsv1_server.c
    vendor/wpa/2.0/src/tls/tlsv1_server.h
    vendor/wpa/2.0/src/tls/tlsv1_server_i.h
    vendor/wpa/2.0/src/tls/tlsv1_server_read.c
    vendor/wpa/2.0/src/tls/tlsv1_server_write.c
    vendor/wpa/2.0/src/tls/x509v3.c
    vendor/wpa/2.0/src/tls/x509v3.h
    vendor/wpa/2.0/src/utils/Makefile
    vendor/wpa/2.0/src/utils/base64.c
    vendor/wpa/2.0/src/utils/base64.h
    vendor/wpa/2.0/src/utils/build_config.h
    vendor/wpa/2.0/src/utils/common.c
    vendor/wpa/2.0/src/utils/common.h
    vendor/wpa/2.0/src/utils/edit.c
    vendor/wpa/2.0/src/utils/edit.h
    vendor/wpa/2.0/src/utils/edit_readline.c
    vendor/wpa/2.0/src/utils/edit_simple.c
    vendor/wpa/2.0/src/utils/eloop.c
    vendor/wpa/2.0/src/utils/eloop.h
    vendor/wpa/2.0/src/utils/eloop_none.c
    vendor/wpa/2.0/src/utils/eloop_win.c
    vendor/wpa/2.0/src/utils/ext_password.c
    vendor/wpa/2.0/src/utils/ext_password.h
    vendor/wpa/2.0/src/utils/ext_password_i.h
    vendor/wpa/2.0/src/utils/ext_password_test.c
    vendor/wpa/2.0/src/utils/includes.h
    vendor/wpa/2.0/src/utils/ip_addr.c
    vendor/wpa/2.0/src/utils/ip_addr.h
    vendor/wpa/2.0/src/utils/list.h
    vendor/wpa/2.0/src/utils/os.h
    vendor/wpa/2.0/src/utils/os_internal.c
    vendor/wpa/2.0/src/utils/os_none.c
    vendor/wpa/2.0/src/utils/os_unix.c
    vendor/wpa/2.0/src/utils/os_win32.c
    vendor/wpa/2.0/src/utils/pcsc_funcs.c
    vendor/wpa/2.0/src/utils/pcsc_funcs.h
    vendor/wpa/2.0/src/utils/radiotap.h
    vendor/wpa/2.0/src/utils/radiotap_iter.h
    vendor/wpa/2.0/src/utils/state_machine.h
    vendor/wpa/2.0/src/utils/trace.c
    vendor/wpa/2.0/src/utils/trace.h
    vendor/wpa/2.0/src/utils/uuid.c
    vendor/wpa/2.0/src/utils/uuid.h
    vendor/wpa/2.0/src/utils/wpa_debug.c
    vendor/wpa/2.0/src/utils/wpa_debug.h
    vendor/wpa/2.0/src/utils/wpabuf.c
    vendor/wpa/2.0/src/utils/wpabuf.h
    vendor/wpa/2.0/src/wps/http_client.c
    vendor/wpa/2.0/src/wps/http_client.h
    vendor/wpa/2.0/src/wps/http_server.c
    vendor/wpa/2.0/src/wps/http_server.h
    vendor/wpa/2.0/src/wps/httpread.c
    vendor/wpa/2.0/src/wps/httpread.h
    vendor/wpa/2.0/src/wps/ndef.c
    vendor/wpa/2.0/src/wps/upnp_xml.c
    vendor/wpa/2.0/src/wps/upnp_xml.h
    vendor/wpa/2.0/src/wps/wps.c
    vendor/wpa/2.0/src/wps/wps.h
    vendor/wpa/2.0/src/wps/wps_attr_build.c
    vendor/wpa/2.0/src/wps/wps_attr_parse.c
    vendor/wpa/2.0/src/wps/wps_attr_parse.h
    vendor/wpa/2.0/src/wps/wps_attr_process.c
    vendor/wpa/2.0/src/wps/wps_common.c
    vendor/wpa/2.0/src/wps/wps_defs.h
    vendor/wpa/2.0/src/wps/wps_dev_attr.c
    vendor/wpa/2.0/src/wps/wps_dev_attr.h
    vendor/wpa/2.0/src/wps/wps_enrollee.c
    vendor/wpa/2.0/src/wps/wps_er.c
    vendor/wpa/2.0/src/wps/wps_er.h
    vendor/wpa/2.0/src/wps/wps_er_ssdp.c
    vendor/wpa/2.0/src/wps/wps_i.h
    vendor/wpa/2.0/src/wps/wps_registrar.c
    vendor/wpa/2.0/src/wps/wps_upnp.c
    vendor/wpa/2.0/src/wps/wps_upnp.h
    vendor/wpa/2.0/src/wps/wps_upnp_ap.c
    vendor/wpa/2.0/src/wps/wps_upnp_event.c
    vendor/wpa/2.0/src/wps/wps_upnp_i.h
    vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c
    vendor/wpa/2.0/src/wps/wps_upnp_web.c
    vendor/wpa/2.0/src/wps/wps_validate.c
    vendor/wpa/2.0/wpa_supplicant/.gitignore
    vendor/wpa/2.0/wpa_supplicant/ChangeLog
    vendor/wpa/2.0/wpa_supplicant/Makefile
    vendor/wpa/2.0/wpa_supplicant/README
    vendor/wpa/2.0/wpa_supplicant/README-HS20
    vendor/wpa/2.0/wpa_supplicant/README-P2P
    vendor/wpa/2.0/wpa_supplicant/README-WPS
    vendor/wpa/2.0/wpa_supplicant/ap.c
    vendor/wpa/2.0/wpa_supplicant/ap.h
    vendor/wpa/2.0/wpa_supplicant/autoscan.c
    vendor/wpa/2.0/wpa_supplicant/autoscan.h
    vendor/wpa/2.0/wpa_supplicant/autoscan_exponential.c
    vendor/wpa/2.0/wpa_supplicant/autoscan_periodic.c
    vendor/wpa/2.0/wpa_supplicant/bgscan.c
    vendor/wpa/2.0/wpa_supplicant/bgscan.h
    vendor/wpa/2.0/wpa_supplicant/bgscan_learn.c
    vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c
    vendor/wpa/2.0/wpa_supplicant/blacklist.c
    vendor/wpa/2.0/wpa_supplicant/blacklist.h
    vendor/wpa/2.0/wpa_supplicant/bss.c
    vendor/wpa/2.0/wpa_supplicant/bss.h
    vendor/wpa/2.0/wpa_supplicant/config.c
    vendor/wpa/2.0/wpa_supplicant/config.h
    vendor/wpa/2.0/wpa_supplicant/config_file.c
    vendor/wpa/2.0/wpa_supplicant/config_none.c
    vendor/wpa/2.0/wpa_supplicant/config_ssid.h
    vendor/wpa/2.0/wpa_supplicant/config_winreg.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c
    vendor/wpa/2.0/wpa_supplicant/dbus/Makefile
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c
    vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
    vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
    vendor/wpa/2.0/wpa_supplicant/defconfig
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
    vendor/wpa/2.0/wpa_supplicant/driver_i.h
    vendor/wpa/2.0/wpa_supplicant/eap_register.c
    vendor/wpa/2.0/wpa_supplicant/eapol_test.c
    vendor/wpa/2.0/wpa_supplicant/events.c
    vendor/wpa/2.0/wpa_supplicant/examples/dbus-listen-preq.py
    vendor/wpa/2.0/wpa_supplicant/examples/p2p/
    vendor/wpa/2.0/wpa_supplicant/examples/p2p-action-udhcp.sh
    vendor/wpa/2.0/wpa_supplicant/examples/p2p-action.sh
    vendor/wpa/2.0/wpa_supplicant/examples/udhcpd-p2p.conf
    vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py
    vendor/wpa/2.0/wpa_supplicant/examples/wps-ap-cli
    vendor/wpa/2.0/wpa_supplicant/examples/wps-nfc.py
    vendor/wpa/2.0/wpa_supplicant/gas_query.c
    vendor/wpa/2.0/wpa_supplicant/gas_query.h
    vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.h
    vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c
    vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h
    vendor/wpa/2.0/wpa_supplicant/interworking.c
    vendor/wpa/2.0/wpa_supplicant/interworking.h
    vendor/wpa/2.0/wpa_supplicant/main.c
    vendor/wpa/2.0/wpa_supplicant/main_none.c
    vendor/wpa/2.0/wpa_supplicant/main_winmain.c
    vendor/wpa/2.0/wpa_supplicant/main_winsvc.c
    vendor/wpa/2.0/wpa_supplicant/nfc_pw_token.c
    vendor/wpa/2.0/wpa_supplicant/notify.c
    vendor/wpa/2.0/wpa_supplicant/notify.h
    vendor/wpa/2.0/wpa_supplicant/offchannel.c
    vendor/wpa/2.0/wpa_supplicant/offchannel.h
    vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.h
    vendor/wpa/2.0/wpa_supplicant/preauth_test.c
    vendor/wpa/2.0/wpa_supplicant/scan.c
    vendor/wpa/2.0/wpa_supplicant/scan.h
    vendor/wpa/2.0/wpa_supplicant/sme.c
    vendor/wpa/2.0/wpa_supplicant/sme.h
    vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c
    vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c
    vendor/wpa/2.0/wpa_supplicant/utils/
    vendor/wpa/2.0/wpa_supplicant/wifi_display.c
    vendor/wpa/2.0/wpa_supplicant/wifi_display.h
    vendor/wpa/2.0/wpa_supplicant/win_if_list.c
    vendor/wpa/2.0/wpa_supplicant/wnm_sta.c
    vendor/wpa/2.0/wpa_supplicant/wnm_sta.h
    vendor/wpa/2.0/wpa_supplicant/wpa_cli.c
    vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c
    vendor/wpa/2.0/wpa_supplicant/wpa_priv.c
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.mk
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.sh
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_template.conf
    vendor/wpa/2.0/wpa_supplicant/wpas_glue.c
    vendor/wpa/2.0/wpa_supplicant/wpas_glue.h
    vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h

Removed Paths:
-------------
    vendor/wpa/2.0/COPYING
    vendor/wpa/2.0/README
    vendor/wpa/2.0/hostapd/.gitignore
    vendor/wpa/2.0/hostapd/ChangeLog
    vendor/wpa/2.0/hostapd/Makefile
    vendor/wpa/2.0/hostapd/README
    vendor/wpa/2.0/hostapd/README-WPS
    vendor/wpa/2.0/hostapd/config_file.c
    vendor/wpa/2.0/hostapd/config_file.h
    vendor/wpa/2.0/hostapd/ctrl_iface.c
    vendor/wpa/2.0/hostapd/ctrl_iface.h
    vendor/wpa/2.0/hostapd/defconfig
    vendor/wpa/2.0/hostapd/dump_state.c
    vendor/wpa/2.0/hostapd/dump_state.h
    vendor/wpa/2.0/hostapd/eap_register.c
    vendor/wpa/2.0/hostapd/eap_register.h
    vendor/wpa/2.0/hostapd/hlr_auc_gw.c
    vendor/wpa/2.0/hostapd/hostapd.conf
    vendor/wpa/2.0/hostapd/hostapd.eap_user
    vendor/wpa/2.0/hostapd/hostapd_cli.c
    vendor/wpa/2.0/hostapd/main.c
    vendor/wpa/2.0/hostapd/nt_password_hash.c
    vendor/wpa/2.0/src/Makefile
    vendor/wpa/2.0/src/ap/accounting.c
    vendor/wpa/2.0/src/ap/accounting.h
    vendor/wpa/2.0/src/ap/ap_config.c
    vendor/wpa/2.0/src/ap/ap_config.h
    vendor/wpa/2.0/src/ap/ap_drv_ops.c
    vendor/wpa/2.0/src/ap/ap_drv_ops.h
    vendor/wpa/2.0/src/ap/ap_list.c
    vendor/wpa/2.0/src/ap/ap_list.h
    vendor/wpa/2.0/src/ap/ap_mlme.c
    vendor/wpa/2.0/src/ap/ap_mlme.h
    vendor/wpa/2.0/src/ap/authsrv.c
    vendor/wpa/2.0/src/ap/authsrv.h
    vendor/wpa/2.0/src/ap/beacon.c
    vendor/wpa/2.0/src/ap/beacon.h
    vendor/wpa/2.0/src/ap/ctrl_iface_ap.c
    vendor/wpa/2.0/src/ap/ctrl_iface_ap.h
    vendor/wpa/2.0/src/ap/drv_callbacks.c
    vendor/wpa/2.0/src/ap/hostapd.c
    vendor/wpa/2.0/src/ap/hostapd.h
    vendor/wpa/2.0/src/ap/hw_features.c
    vendor/wpa/2.0/src/ap/hw_features.h
    vendor/wpa/2.0/src/ap/iapp.c
    vendor/wpa/2.0/src/ap/iapp.h
    vendor/wpa/2.0/src/ap/ieee802_11.c
    vendor/wpa/2.0/src/ap/ieee802_11.h
    vendor/wpa/2.0/src/ap/ieee802_11_auth.c
    vendor/wpa/2.0/src/ap/ieee802_11_auth.h
    vendor/wpa/2.0/src/ap/ieee802_11_ht.c
    vendor/wpa/2.0/src/ap/ieee802_1x.c
    vendor/wpa/2.0/src/ap/ieee802_1x.h
    vendor/wpa/2.0/src/ap/peerkey_auth.c
    vendor/wpa/2.0/src/ap/pmksa_cache_auth.c
    vendor/wpa/2.0/src/ap/pmksa_cache_auth.h
    vendor/wpa/2.0/src/ap/preauth_auth.c
    vendor/wpa/2.0/src/ap/preauth_auth.h
    vendor/wpa/2.0/src/ap/sta_info.c
    vendor/wpa/2.0/src/ap/sta_info.h
    vendor/wpa/2.0/src/ap/tkip_countermeasures.c
    vendor/wpa/2.0/src/ap/tkip_countermeasures.h
    vendor/wpa/2.0/src/ap/utils.c
    vendor/wpa/2.0/src/ap/vlan_init.c
    vendor/wpa/2.0/src/ap/wmm.c
    vendor/wpa/2.0/src/ap/wpa_auth.c
    vendor/wpa/2.0/src/ap/wpa_auth.h
    vendor/wpa/2.0/src/ap/wpa_auth_ft.c
    vendor/wpa/2.0/src/ap/wpa_auth_glue.c
    vendor/wpa/2.0/src/ap/wpa_auth_glue.h
    vendor/wpa/2.0/src/ap/wpa_auth_i.h
    vendor/wpa/2.0/src/ap/wpa_auth_ie.c
    vendor/wpa/2.0/src/ap/wpa_auth_ie.h
    vendor/wpa/2.0/src/ap/wps_hostapd.c
    vendor/wpa/2.0/src/ap/wps_hostapd.h
    vendor/wpa/2.0/src/common/defs.h
    vendor/wpa/2.0/src/common/eapol_common.h
    vendor/wpa/2.0/src/common/ieee802_11_common.c
    vendor/wpa/2.0/src/common/ieee802_11_common.h
    vendor/wpa/2.0/src/common/ieee802_11_defs.h
    vendor/wpa/2.0/src/common/privsep_commands.h
    vendor/wpa/2.0/src/common/version.h
    vendor/wpa/2.0/src/common/wpa_common.c
    vendor/wpa/2.0/src/common/wpa_common.h
    vendor/wpa/2.0/src/common/wpa_ctrl.c
    vendor/wpa/2.0/src/common/wpa_ctrl.h
    vendor/wpa/2.0/src/crypto/Makefile
    vendor/wpa/2.0/src/crypto/aes-cbc.c
    vendor/wpa/2.0/src/crypto/aes-ctr.c
    vendor/wpa/2.0/src/crypto/aes-eax.c
    vendor/wpa/2.0/src/crypto/aes-encblock.c
    vendor/wpa/2.0/src/crypto/aes-internal-dec.c
    vendor/wpa/2.0/src/crypto/aes-internal-enc.c
    vendor/wpa/2.0/src/crypto/aes-internal.c
    vendor/wpa/2.0/src/crypto/aes-omac1.c
    vendor/wpa/2.0/src/crypto/aes-unwrap.c
    vendor/wpa/2.0/src/crypto/aes-wrap.c
    vendor/wpa/2.0/src/crypto/aes.h
    vendor/wpa/2.0/src/crypto/aes_i.h
    vendor/wpa/2.0/src/crypto/aes_wrap.h
    vendor/wpa/2.0/src/crypto/crypto.h
    vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c
    vendor/wpa/2.0/src/crypto/crypto_gnutls.c
    vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c
    vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c
    vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c
    vendor/wpa/2.0/src/crypto/crypto_internal.c
    vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c
    vendor/wpa/2.0/src/crypto/crypto_none.c
    vendor/wpa/2.0/src/crypto/crypto_nss.c
    vendor/wpa/2.0/src/crypto/crypto_openssl.c
    vendor/wpa/2.0/src/crypto/des-internal.c
    vendor/wpa/2.0/src/crypto/des_i.h
    vendor/wpa/2.0/src/crypto/dh_group5.c
    vendor/wpa/2.0/src/crypto/dh_group5.h
    vendor/wpa/2.0/src/crypto/dh_groups.c
    vendor/wpa/2.0/src/crypto/dh_groups.h
    vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c
    vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c
    vendor/wpa/2.0/src/crypto/fips_prf_internal.c
    vendor/wpa/2.0/src/crypto/fips_prf_nss.c
    vendor/wpa/2.0/src/crypto/fips_prf_openssl.c
    vendor/wpa/2.0/src/crypto/md4-internal.c
    vendor/wpa/2.0/src/crypto/md5-internal.c
    vendor/wpa/2.0/src/crypto/md5-non-fips.c
    vendor/wpa/2.0/src/crypto/md5.c
    vendor/wpa/2.0/src/crypto/md5.h
    vendor/wpa/2.0/src/crypto/md5_i.h
    vendor/wpa/2.0/src/crypto/milenage.c
    vendor/wpa/2.0/src/crypto/milenage.h
    vendor/wpa/2.0/src/crypto/ms_funcs.c
    vendor/wpa/2.0/src/crypto/ms_funcs.h
    vendor/wpa/2.0/src/crypto/rc4.c
    vendor/wpa/2.0/src/crypto/sha1-internal.c
    vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c
    vendor/wpa/2.0/src/crypto/sha1-tlsprf.c
    vendor/wpa/2.0/src/crypto/sha1-tprf.c
    vendor/wpa/2.0/src/crypto/sha1.c
    vendor/wpa/2.0/src/crypto/sha1.h
    vendor/wpa/2.0/src/crypto/sha1_i.h
    vendor/wpa/2.0/src/crypto/sha256-internal.c
    vendor/wpa/2.0/src/crypto/sha256.c
    vendor/wpa/2.0/src/crypto/sha256.h
    vendor/wpa/2.0/src/crypto/tls.h
    vendor/wpa/2.0/src/crypto/tls_gnutls.c
    vendor/wpa/2.0/src/crypto/tls_internal.c
    vendor/wpa/2.0/src/crypto/tls_none.c
    vendor/wpa/2.0/src/crypto/tls_nss.c
    vendor/wpa/2.0/src/crypto/tls_openssl.c
    vendor/wpa/2.0/src/crypto/tls_schannel.c
    vendor/wpa/2.0/src/drivers/Apple80211.h
    vendor/wpa/2.0/src/drivers/MobileApple80211.c
    vendor/wpa/2.0/src/drivers/MobileApple80211.h
    vendor/wpa/2.0/src/drivers/driver.h
    vendor/wpa/2.0/src/drivers/driver_atheros.c
    vendor/wpa/2.0/src/drivers/driver_atmel.c
    vendor/wpa/2.0/src/drivers/driver_broadcom.c
    vendor/wpa/2.0/src/drivers/driver_bsd.c
    vendor/wpa/2.0/src/drivers/driver_hostap.c
    vendor/wpa/2.0/src/drivers/driver_hostap.h
    vendor/wpa/2.0/src/drivers/driver_iphone.m
    vendor/wpa/2.0/src/drivers/driver_ipw.c
    vendor/wpa/2.0/src/drivers/driver_madwifi.c
    vendor/wpa/2.0/src/drivers/driver_ndis.c
    vendor/wpa/2.0/src/drivers/driver_ndis.h
    vendor/wpa/2.0/src/drivers/driver_ndis_.c
    vendor/wpa/2.0/src/drivers/driver_ndiswrapper.c
    vendor/wpa/2.0/src/drivers/driver_nl80211.c
    vendor/wpa/2.0/src/drivers/driver_none.c
    vendor/wpa/2.0/src/drivers/driver_osx.m
    vendor/wpa/2.0/src/drivers/driver_privsep.c
    vendor/wpa/2.0/src/drivers/driver_ralink.c
    vendor/wpa/2.0/src/drivers/driver_ralink.h
    vendor/wpa/2.0/src/drivers/driver_roboswitch.c
    vendor/wpa/2.0/src/drivers/driver_test.c
    vendor/wpa/2.0/src/drivers/driver_wext.c
    vendor/wpa/2.0/src/drivers/driver_wext.h
    vendor/wpa/2.0/src/drivers/driver_wired.c
    vendor/wpa/2.0/src/drivers/drivers.c
    vendor/wpa/2.0/src/drivers/drivers.mak
    vendor/wpa/2.0/src/drivers/linux_ioctl.c
    vendor/wpa/2.0/src/drivers/linux_ioctl.h
    vendor/wpa/2.0/src/drivers/ndis_events.c
    vendor/wpa/2.0/src/drivers/netlink.c
    vendor/wpa/2.0/src/drivers/netlink.h
    vendor/wpa/2.0/src/drivers/nl80211_copy.h
    vendor/wpa/2.0/src/drivers/priv_netlink.h
    vendor/wpa/2.0/src/drivers/wireless_copy.h
    vendor/wpa/2.0/src/eap_common/chap.c
    vendor/wpa/2.0/src/eap_common/chap.h
    vendor/wpa/2.0/src/eap_common/eap_common.c
    vendor/wpa/2.0/src/eap_common/eap_common.h
    vendor/wpa/2.0/src/eap_common/eap_defs.h
    vendor/wpa/2.0/src/eap_common/eap_fast_common.c
    vendor/wpa/2.0/src/eap_common/eap_fast_common.h
    vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c
    vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h
    vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c
    vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h
    vendor/wpa/2.0/src/eap_common/eap_pax_common.c
    vendor/wpa/2.0/src/eap_common/eap_pax_common.h
    vendor/wpa/2.0/src/eap_common/eap_peap_common.c
    vendor/wpa/2.0/src/eap_common/eap_peap_common.h
    vendor/wpa/2.0/src/eap_common/eap_psk_common.c
    vendor/wpa/2.0/src/eap_common/eap_psk_common.h
    vendor/wpa/2.0/src/eap_common/eap_sake_common.c
    vendor/wpa/2.0/src/eap_common/eap_sake_common.h
    vendor/wpa/2.0/src/eap_common/eap_sim_common.c
    vendor/wpa/2.0/src/eap_common/eap_sim_common.h
    vendor/wpa/2.0/src/eap_common/eap_tlv_common.h
    vendor/wpa/2.0/src/eap_common/eap_ttls.h
    vendor/wpa/2.0/src/eap_common/eap_wsc_common.c
    vendor/wpa/2.0/src/eap_common/eap_wsc_common.h
    vendor/wpa/2.0/src/eap_common/ikev2_common.c
    vendor/wpa/2.0/src/eap_common/ikev2_common.h
    vendor/wpa/2.0/src/eap_peer/eap.c
    vendor/wpa/2.0/src/eap_peer/eap.h
    vendor/wpa/2.0/src/eap_peer/eap_aka.c
    vendor/wpa/2.0/src/eap_peer/eap_config.h
    vendor/wpa/2.0/src/eap_peer/eap_fast.c
    vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c
    vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h
    vendor/wpa/2.0/src/eap_peer/eap_gpsk.c
    vendor/wpa/2.0/src/eap_peer/eap_gtc.c
    vendor/wpa/2.0/src/eap_peer/eap_i.h
    vendor/wpa/2.0/src/eap_peer/eap_ikev2.c
    vendor/wpa/2.0/src/eap_peer/eap_leap.c
    vendor/wpa/2.0/src/eap_peer/eap_md5.c
    vendor/wpa/2.0/src/eap_peer/eap_methods.c
    vendor/wpa/2.0/src/eap_peer/eap_methods.h
    vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c
    vendor/wpa/2.0/src/eap_peer/eap_otp.c
    vendor/wpa/2.0/src/eap_peer/eap_pax.c
    vendor/wpa/2.0/src/eap_peer/eap_peap.c
    vendor/wpa/2.0/src/eap_peer/eap_psk.c
    vendor/wpa/2.0/src/eap_peer/eap_sake.c
    vendor/wpa/2.0/src/eap_peer/eap_sim.c
    vendor/wpa/2.0/src/eap_peer/eap_tls.c
    vendor/wpa/2.0/src/eap_peer/eap_tls_common.c
    vendor/wpa/2.0/src/eap_peer/eap_tls_common.h
    vendor/wpa/2.0/src/eap_peer/eap_tnc.c
    vendor/wpa/2.0/src/eap_peer/eap_ttls.c
    vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c
    vendor/wpa/2.0/src/eap_peer/eap_wsc.c
    vendor/wpa/2.0/src/eap_peer/ikev2.c
    vendor/wpa/2.0/src/eap_peer/ikev2.h
    vendor/wpa/2.0/src/eap_peer/mschapv2.c
    vendor/wpa/2.0/src/eap_peer/mschapv2.h
    vendor/wpa/2.0/src/eap_peer/tncc.c
    vendor/wpa/2.0/src/eap_peer/tncc.h
    vendor/wpa/2.0/src/eap_server/eap.h
    vendor/wpa/2.0/src/eap_server/eap_i.h
    vendor/wpa/2.0/src/eap_server/eap_methods.h
    vendor/wpa/2.0/src/eap_server/eap_server.c
    vendor/wpa/2.0/src/eap_server/eap_server_aka.c
    vendor/wpa/2.0/src/eap_server/eap_server_fast.c
    vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c
    vendor/wpa/2.0/src/eap_server/eap_server_gtc.c
    vendor/wpa/2.0/src/eap_server/eap_server_identity.c
    vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c
    vendor/wpa/2.0/src/eap_server/eap_server_md5.c
    vendor/wpa/2.0/src/eap_server/eap_server_methods.c
    vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c
    vendor/wpa/2.0/src/eap_server/eap_server_pax.c
    vendor/wpa/2.0/src/eap_server/eap_server_peap.c
    vendor/wpa/2.0/src/eap_server/eap_server_psk.c
    vendor/wpa/2.0/src/eap_server/eap_server_sake.c
    vendor/wpa/2.0/src/eap_server/eap_server_sim.c
    vendor/wpa/2.0/src/eap_server/eap_server_tls.c
    vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c
    vendor/wpa/2.0/src/eap_server/eap_server_tnc.c
    vendor/wpa/2.0/src/eap_server/eap_server_ttls.c
    vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c
    vendor/wpa/2.0/src/eap_server/eap_server_wsc.c
    vendor/wpa/2.0/src/eap_server/eap_sim_db.c
    vendor/wpa/2.0/src/eap_server/eap_sim_db.h
    vendor/wpa/2.0/src/eap_server/eap_tls_common.h
    vendor/wpa/2.0/src/eap_server/ikev2.c
    vendor/wpa/2.0/src/eap_server/ikev2.h
    vendor/wpa/2.0/src/eap_server/tncs.c
    vendor/wpa/2.0/src/eap_server/tncs.h
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h
    vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h
    vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c
    vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h
    vendor/wpa/2.0/src/l2_packet/l2_packet.h
    vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_none.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c
    vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c
    vendor/wpa/2.0/src/radius/radius.c
    vendor/wpa/2.0/src/radius/radius.h
    vendor/wpa/2.0/src/radius/radius_client.c
    vendor/wpa/2.0/src/radius/radius_client.h
    vendor/wpa/2.0/src/radius/radius_server.c
    vendor/wpa/2.0/src/radius/radius_server.h
    vendor/wpa/2.0/src/rsn_supp/peerkey.c
    vendor/wpa/2.0/src/rsn_supp/peerkey.h
    vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c
    vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h
    vendor/wpa/2.0/src/rsn_supp/preauth.c
    vendor/wpa/2.0/src/rsn_supp/preauth.h
    vendor/wpa/2.0/src/rsn_supp/wpa.c
    vendor/wpa/2.0/src/rsn_supp/wpa.h
    vendor/wpa/2.0/src/rsn_supp/wpa_ft.c
    vendor/wpa/2.0/src/rsn_supp/wpa_i.h
    vendor/wpa/2.0/src/rsn_supp/wpa_ie.c
    vendor/wpa/2.0/src/rsn_supp/wpa_ie.h
    vendor/wpa/2.0/src/tls/Makefile
    vendor/wpa/2.0/src/tls/asn1.c
    vendor/wpa/2.0/src/tls/asn1.h
    vendor/wpa/2.0/src/tls/bignum.c
    vendor/wpa/2.0/src/tls/bignum.h
    vendor/wpa/2.0/src/tls/libtommath.c
    vendor/wpa/2.0/src/tls/pkcs1.c
    vendor/wpa/2.0/src/tls/pkcs1.h
    vendor/wpa/2.0/src/tls/pkcs5.c
    vendor/wpa/2.0/src/tls/pkcs5.h
    vendor/wpa/2.0/src/tls/pkcs8.c
    vendor/wpa/2.0/src/tls/pkcs8.h
    vendor/wpa/2.0/src/tls/rsa.c
    vendor/wpa/2.0/src/tls/rsa.h
    vendor/wpa/2.0/src/tls/tlsv1_client.c
    vendor/wpa/2.0/src/tls/tlsv1_client.h
    vendor/wpa/2.0/src/tls/tlsv1_client_i.h
    vendor/wpa/2.0/src/tls/tlsv1_client_read.c
    vendor/wpa/2.0/src/tls/tlsv1_client_write.c
    vendor/wpa/2.0/src/tls/tlsv1_common.c
    vendor/wpa/2.0/src/tls/tlsv1_common.h
    vendor/wpa/2.0/src/tls/tlsv1_cred.c
    vendor/wpa/2.0/src/tls/tlsv1_cred.h
    vendor/wpa/2.0/src/tls/tlsv1_record.c
    vendor/wpa/2.0/src/tls/tlsv1_record.h
    vendor/wpa/2.0/src/tls/tlsv1_server.c
    vendor/wpa/2.0/src/tls/tlsv1_server.h
    vendor/wpa/2.0/src/tls/tlsv1_server_i.h
    vendor/wpa/2.0/src/tls/tlsv1_server_read.c
    vendor/wpa/2.0/src/tls/tlsv1_server_write.c
    vendor/wpa/2.0/src/tls/x509v3.c
    vendor/wpa/2.0/src/tls/x509v3.h
    vendor/wpa/2.0/src/utils/Makefile
    vendor/wpa/2.0/src/utils/base64.c
    vendor/wpa/2.0/src/utils/base64.h
    vendor/wpa/2.0/src/utils/build_config.h
    vendor/wpa/2.0/src/utils/common.c
    vendor/wpa/2.0/src/utils/common.h
    vendor/wpa/2.0/src/utils/eloop.c
    vendor/wpa/2.0/src/utils/eloop.h
    vendor/wpa/2.0/src/utils/eloop_none.c
    vendor/wpa/2.0/src/utils/eloop_win.c
    vendor/wpa/2.0/src/utils/includes.h
    vendor/wpa/2.0/src/utils/ip_addr.c
    vendor/wpa/2.0/src/utils/ip_addr.h
    vendor/wpa/2.0/src/utils/list.h
    vendor/wpa/2.0/src/utils/os.h
    vendor/wpa/2.0/src/utils/os_internal.c
    vendor/wpa/2.0/src/utils/os_none.c
    vendor/wpa/2.0/src/utils/os_unix.c
    vendor/wpa/2.0/src/utils/os_win32.c
    vendor/wpa/2.0/src/utils/pcsc_funcs.c
    vendor/wpa/2.0/src/utils/pcsc_funcs.h
    vendor/wpa/2.0/src/utils/radiotap.h
    vendor/wpa/2.0/src/utils/radiotap_iter.h
    vendor/wpa/2.0/src/utils/state_machine.h
    vendor/wpa/2.0/src/utils/trace.c
    vendor/wpa/2.0/src/utils/trace.h
    vendor/wpa/2.0/src/utils/uuid.c
    vendor/wpa/2.0/src/utils/uuid.h
    vendor/wpa/2.0/src/utils/wpa_debug.c
    vendor/wpa/2.0/src/utils/wpa_debug.h
    vendor/wpa/2.0/src/utils/wpabuf.c
    vendor/wpa/2.0/src/utils/wpabuf.h
    vendor/wpa/2.0/src/wps/http_client.c
    vendor/wpa/2.0/src/wps/http_client.h
    vendor/wpa/2.0/src/wps/http_server.c
    vendor/wpa/2.0/src/wps/http_server.h
    vendor/wpa/2.0/src/wps/httpread.c
    vendor/wpa/2.0/src/wps/httpread.h
    vendor/wpa/2.0/src/wps/ndef.c
    vendor/wpa/2.0/src/wps/upnp_xml.c
    vendor/wpa/2.0/src/wps/upnp_xml.h
    vendor/wpa/2.0/src/wps/wps.c
    vendor/wpa/2.0/src/wps/wps.h
    vendor/wpa/2.0/src/wps/wps_attr_build.c
    vendor/wpa/2.0/src/wps/wps_attr_parse.c
    vendor/wpa/2.0/src/wps/wps_attr_process.c
    vendor/wpa/2.0/src/wps/wps_common.c
    vendor/wpa/2.0/src/wps/wps_defs.h
    vendor/wpa/2.0/src/wps/wps_dev_attr.c
    vendor/wpa/2.0/src/wps/wps_dev_attr.h
    vendor/wpa/2.0/src/wps/wps_enrollee.c
    vendor/wpa/2.0/src/wps/wps_er.c
    vendor/wpa/2.0/src/wps/wps_er.h
    vendor/wpa/2.0/src/wps/wps_er_ssdp.c
    vendor/wpa/2.0/src/wps/wps_i.h
    vendor/wpa/2.0/src/wps/wps_nfc.c
    vendor/wpa/2.0/src/wps/wps_nfc_pn531.c
    vendor/wpa/2.0/src/wps/wps_registrar.c
    vendor/wpa/2.0/src/wps/wps_ufd.c
    vendor/wpa/2.0/src/wps/wps_upnp.c
    vendor/wpa/2.0/src/wps/wps_upnp.h
    vendor/wpa/2.0/src/wps/wps_upnp_ap.c
    vendor/wpa/2.0/src/wps/wps_upnp_event.c
    vendor/wpa/2.0/src/wps/wps_upnp_i.h
    vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c
    vendor/wpa/2.0/src/wps/wps_upnp_web.c
    vendor/wpa/2.0/wpa_supplicant/.gitignore
    vendor/wpa/2.0/wpa_supplicant/ChangeLog
    vendor/wpa/2.0/wpa_supplicant/Makefile
    vendor/wpa/2.0/wpa_supplicant/README
    vendor/wpa/2.0/wpa_supplicant/README-WPS
    vendor/wpa/2.0/wpa_supplicant/README-Windows.txt
    vendor/wpa/2.0/wpa_supplicant/ap.c
    vendor/wpa/2.0/wpa_supplicant/ap.h
    vendor/wpa/2.0/wpa_supplicant/bgscan.c
    vendor/wpa/2.0/wpa_supplicant/bgscan.h
    vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c
    vendor/wpa/2.0/wpa_supplicant/blacklist.c
    vendor/wpa/2.0/wpa_supplicant/blacklist.h
    vendor/wpa/2.0/wpa_supplicant/bss.c
    vendor/wpa/2.0/wpa_supplicant/bss.h
    vendor/wpa/2.0/wpa_supplicant/config.c
    vendor/wpa/2.0/wpa_supplicant/config.h
    vendor/wpa/2.0/wpa_supplicant/config_file.c
    vendor/wpa/2.0/wpa_supplicant/config_none.c
    vendor/wpa/2.0/wpa_supplicant/config_ssid.h
    vendor/wpa/2.0/wpa_supplicant/config_winreg.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c
    vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c
    vendor/wpa/2.0/wpa_supplicant/dbus/Makefile
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h
    vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c
    vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service
    vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service
    vendor/wpa/2.0/wpa_supplicant/defconfig
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
    vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
    vendor/wpa/2.0/wpa_supplicant/driver_i.h
    vendor/wpa/2.0/wpa_supplicant/eap_register.c
    vendor/wpa/2.0/wpa_supplicant/eapol_test.c
    vendor/wpa/2.0/wpa_supplicant/events.c
    vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py
    vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c
    vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h
    vendor/wpa/2.0/wpa_supplicant/main.c
    vendor/wpa/2.0/wpa_supplicant/main_none.c
    vendor/wpa/2.0/wpa_supplicant/main_symbian.cpp
    vendor/wpa/2.0/wpa_supplicant/main_winmain.c
    vendor/wpa/2.0/wpa_supplicant/main_winsvc.c
    vendor/wpa/2.0/wpa_supplicant/mlme.c
    vendor/wpa/2.0/wpa_supplicant/mlme.h
    vendor/wpa/2.0/wpa_supplicant/notify.c
    vendor/wpa/2.0/wpa_supplicant/notify.h
    vendor/wpa/2.0/wpa_supplicant/preauth_test.c
    vendor/wpa/2.0/wpa_supplicant/scan.c
    vendor/wpa/2.0/wpa_supplicant/scan.h
    vendor/wpa/2.0/wpa_supplicant/sme.c
    vendor/wpa/2.0/wpa_supplicant/sme.h
    vendor/wpa/2.0/wpa_supplicant/symbian/
    vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c
    vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c
    vendor/wpa/2.0/wpa_supplicant/vs2005/
    vendor/wpa/2.0/wpa_supplicant/win_if_list.c
    vendor/wpa/2.0/wpa_supplicant/wpa_cli.c
    vendor/wpa/2.0/wpa_supplicant/wpa_gui/
    vendor/wpa/2.0/wpa_supplicant/wpa_gui-qt4/
    vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c
    vendor/wpa/2.0/wpa_supplicant/wpa_priv.c
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.nsi
    vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h
    vendor/wpa/2.0/wpa_supplicant/wpas_glue.c
    vendor/wpa/2.0/wpa_supplicant/wpas_glue.h
    vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c
    vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h
    vendor/wpa/2.0/wpa_supplicant/xcode/

Deleted: vendor/wpa/2.0/COPYING
===================================================================
--- vendor/wpa/dist/COPYING	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/COPYING	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,340 +0,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-

-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-

-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-

-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-

-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-

-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) 19yy name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.

Copied: vendor/wpa/2.0/COPYING (from rev 9639, vendor/wpa/dist/COPYING)
===================================================================
--- vendor/wpa/2.0/COPYING	                        (rev 0)
+++ vendor/wpa/2.0/COPYING	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,22 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi> and contributors
+All Rights Reserved.
+
+
+See the README file for the current license terms.
+
+This software was previously distributed under BSD/GPL v2 dual license
+terms that allowed either of those license alternatives to be
+selected. As of February 11, 2012, the project has chosen to use only
+the BSD license option for future distribution. As such, the GPL v2
+license option is no longer used. It should be noted that the BSD
+license option (the one with advertisement clause removed) is compatible
+with GPL and as such, does not prevent use of this software in projects
+that use GPL.
+
+Some of the files may still include pointers to GPL version 2 license
+terms. However, such copyright and license notifications are maintained
+only for attribution purposes and any distribution of this software
+after February 11, 2012 is no longer under the GPL v2 option.

Deleted: vendor/wpa/2.0/README
===================================================================
--- vendor/wpa/dist/README	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,19 +0,0 @@
-wpa_supplicant and hostapd v0.6.x
----------------------------------
-
-Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi> and contributors
-All Rights Reserved.
-
-These program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-
-This package may include either wpa_supplicant, hostapd, or both. See
-README file respective subdirectories (wpa_supplicant/README or
-hostapd/README) for more details.
-
-Source code files have been moved around in v0.6.x releases and
-compared to earlier releases, the programs are now build by first
-going to a subdirectory (wpa_supplicant or hostapd) and creating
-build configuration (.config) and running 'make' there (for
-Linux/BSD/cygwin builds).

Copied: vendor/wpa/2.0/README (from rev 9639, vendor/wpa/dist/README)
===================================================================
--- vendor/wpa/2.0/README	                        (rev 0)
+++ vendor/wpa/2.0/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,56 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi> and contributors
+All Rights Reserved.
+
+These programs are licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+This package may include either wpa_supplicant, hostapd, or both. See
+README file respective subdirectories (wpa_supplicant/README or
+hostapd/README) for more details.
+
+Source code files were moved around in v0.6.x releases and compared to
+earlier releases, the programs are now built by first going to a
+subdirectory (wpa_supplicant or hostapd) and creating build
+configuration (.config) and running 'make' there (for Linux/BSD/cygwin
+builds).
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Deleted: vendor/wpa/2.0/hostapd/.gitignore
===================================================================
--- vendor/wpa/dist/hostapd/.gitignore	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/.gitignore	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,7 +0,0 @@
-*.d
-.config
-driver_conf.c
-hostapd
-hostapd_cli
-hlr_auc_gw
-nt_password_hash

Deleted: vendor/wpa/2.0/hostapd/ChangeLog
===================================================================
--- vendor/wpa/dist/hostapd/ChangeLog	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/ChangeLog	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,663 +0,0 @@
-ChangeLog for hostapd
-
-2010-09-07 - v0.7.3
-	* fixed re-association after WPS not initializing WPA state machine in
-	  some cases
-	* fixed WPS IE update on reconfiguration
-	* fixed WPS code not to proxy Probe Request frames for foreign SSIDs
-	* added WPS workaround for open networks and some known interop issues
-	* fixed WPS Diffie-Hellman derivation to use correct public key length
-	* fixed FT RRB messages on big endian CPUs
-	* changed WPS protection for brute force AP PIN attacks to disable AP
-	  PIN only temporarily (but with increasing time) to avoid usability
-	  issues on Label-only devices
-	* added wps_ap_pin command for more secure handling of AP PIN
-	  operations (e.g., to generate a random AP PIN and only use it for
-	  short amount of time)
-	* fixed HT STBC negotiation
-
-2010-04-18 - v0.7.2
-	* fix WPS internal Registrar use when an external Registrar is also
-	  active
-	* bsd: Cleaned up driver wrapper and added various low-level
-	  configuration options
-	* TNC: fixed issues with fragmentation
-	* EAP-TNC: add Flags field into fragment acknowledgement (needed to
-	  interoperate with other implementations; may potentially breaks
-	  compatibility with older wpa_supplicant/hostapd versions)
-	* cleaned up driver wrapper API for multi-BSS operations
-	* nl80211: fix multi-BSS and VLAN operations
-	* fix number of issues with IEEE 802.11r/FT; this version is not
-	  backwards compatible with old versions
-	* add SA Query Request processing in AP mode (IEEE 802.11w)
-	* fix IGTK PN in group rekeying (IEEE 802.11w)
-	* fix WPS PBC session overlap detection to use correct attribute
-	* hostapd_notif_Assoc() can now be called with all IEs to simplify
-	  driver wrappers
-	* work around interoperability issue with some WPS External Registrar
-	  implementations
-	* nl80211: fix WPS IE update
-	* hostapd_cli: add support for action script operations (run a script
-	  on hostapd events)
-	* fix DH padding with internal crypto code (mainly, for WPS)
-	* fix WPS association with both WPS IE and WPA/RSN IE present with
-	  driver wrappers that use hostapd MLME (e.g., nl80211)
-
-2010-01-16 - v0.7.1
-	* cleaned up driver wrapper API (struct wpa_driver_ops); the new API
-	  is not fully backwards compatible, so out-of-tree driver wrappers
-	  will need modifications
-	* cleaned up various module interfaces
-	* merge hostapd and wpa_supplicant developers' documentation into a
-	  single document
-	* fixed HT Capabilities IE with nl80211 drivers
-	* moved generic AP functionality code into src/ap
-	* WPS: handle Selected Registrar as union of info from all Registrars
-	* remove obsolte Prism54.org driver wrapper
-	* added internal debugging mechanism with backtrace support and memory
-	  allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
-	* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
-	* WPS: add support for dynamically selecting whether to provision the
-	  PSK as an ASCII passphrase or PSK
-	* added support for WDS (4-address frame) mode with per-station virtual
-	  interfaces (wds_sta=1 in config file; only supported with
-	  driver=nl80211 for now)
-	* fixed WPS Probe Request processing to handle missing required
-	  attribute
-	* fixed PKCS#12 use with OpenSSL 1.0.0
-	* detect bridge interface automatically so that bridge parameter in
-	  hostapd.conf becomes optional (though, it may now be used to
-	  automatically add then WLAN interface into a bridge with
-	  driver=nl80211)
-
-2009-11-21 - v0.7.0
-	* increased hostapd_cli ping interval to 5 seconds and made this
-	  configurable with a new command line options (-G<seconds>)
-	* driver_nl80211: use Linux socket filter to improve performance
-	* added support for external Registrars with WPS (UPnP transport)
-	* 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel
-	* driver_nl80211: fixed STA accounting data collection (TX/RX bytes
-	  reported correctly; TX/RX packets not yet available from kernel)
-	* added support for WPS USBA out-of-band mechanism with USB Flash
-	  Drives (UFD) (CONFIG_WPS_UFD=y)
-	* fixed EAPOL/EAP reauthentication when using an external RADIUS
-	  authentication server
-	* fixed TNC with EAP-TTLS
-	* fixed IEEE 802.11r key derivation function to match with the standard
-	  (note: this breaks interoperability with previous version) [Bug 303]
-	* fixed SHA-256 based key derivation function to match with the
-	  standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
-	  (note: this breaks interoperability with previous version) [Bug 307]
-	* added number of code size optimizations to remove unnecessary
-	  functionality from the program binary based on build configuration
-	  (part of this automatic; part configurable with CONFIG_NO_* build
-	  options)
-	* use shared driver wrapper files with wpa_supplicant
-	* driver_nl80211: multiple updates to provide support for new Linux
-	  nl80211/mac80211 functionality
-	* updated management frame protection to use IEEE Std 802.11w-2009
-	* fixed number of small WPS issues and added workarounds to
-	  interoperate with common deployed broken implementations
-	* added some IEEE 802.11n co-existance rules to disable 40 MHz channels
-	  or modify primary/secondary channels if needed based on neighboring
-	  networks
-	* added support for NFC out-of-band mechanism with WPS
-	* added preliminary support for IEEE 802.11r RIC processing
-
-2009-01-06 - v0.6.7
-	* added support for Wi-Fi Protected Setup (WPS)
-	  (hostapd can now be configured to act as an integrated WPS Registrar
-	  and provision credentials for WPS Enrollees using PIN and PBC
-	  methods; external wireless Registrar can configure the AP, but
-	  external WLAN Manager Registrars are not supported); WPS support can
-	  be enabled by adding CONFIG_WPS=y into .config and setting the
-	  runtime configuration variables in hostapd.conf (see WPS section in
-	  the example configuration file); new hostapd_cli commands wps_pin and
-	  wps_pbc are used to configure WPS negotiation; see README-WPS for
-	  more details
-	* added IEEE 802.11n HT capability configuration (ht_capab)
-	* added support for generating Country IE based on nl80211 regulatory
-	  information (added if ieee80211d=1 in configuration)
-	* fixed WEP authentication (both Open System and Shared Key) with
-	  mac80211
-	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
-	* added support for using driver_test over UDP socket
-	* changed EAP-GPSK to use the IANA assigned EAP method type 51
-	* updated management frame protection to use IEEE 802.11w/D7.0
-	* fixed retransmission of EAP requests if no response is received
-
-2008-11-23 - v0.6.6
-	* added a new configuration option, wpa_ptk_rekey, that can be used to
-	  enforce frequent PTK rekeying, e.g., to mitigate some attacks against
-	  TKIP deficiencies
-	* updated OpenSSL code for EAP-FAST to use an updated version of the
-	  session ticket overriding API that was included into the upstream
-	  OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
-	  needed with that version anymore)
-	* changed channel flags configuration to read the information from
-	  the driver (e.g., via driver_nl80211 when using mac80211) instead of
-	  using hostapd as the source of the regulatory information (i.e.,
-	  information from CRDA is now used with mac80211); this allows 5 GHz
-	  channels to be used with hostapd (if allowed in the current
-	  regulatory domain)
-	* fixed EAP-TLS message processing for the last TLS message if it is
-	  large enough to require fragmentation (e.g., if a large Session
-	  Ticket data is included)
-	* fixed listen interval configuration for nl80211 drivers
-
-2008-11-01 - v0.6.5
-	* added support for SHA-256 as X.509 certificate digest when using the
-	  internal X.509/TLSv1 implementation
-	* fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
-	  identity lengths)
-	* fixed internal TLSv1 implementation for abbreviated handshake (used
-	  by EAP-FAST server)
-	* added support for setting VLAN ID for STAs based on local MAC ACL
-	  (accept_mac_file) as an alternative for RADIUS server-based
-	  configuration
-	* updated management frame protection to use IEEE 802.11w/D6.0
-	  (adds a new association ping to protect against unauthenticated
-	  authenticate or (re)associate request frames dropping association)
-	* added support for using SHA256-based stronger key derivation for WPA2
-	  (IEEE 802.11w)
-	* added new "driver wrapper" for RADIUS-only configuration
-	  (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
-	* fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
-	  is enabled in configuration
-	* changed EAP-FAST configuration to use separate fields for A-ID and
-	  A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
-	  16-octet len binary value for better interoperability with some peer
-	  implementations; eap_fast_a_id is now configured as a hex string
-	* driver_nl80211: Updated to match the current Linux mac80211 AP mode
-	  configuration (wireless-testing.git and Linux kernel releases
-	  starting from 2.6.29)
-
-2008-08-10 - v0.6.4
-	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
-	  Identity Request if identity is already known
-	* added support for EAP Sequences in EAP-FAST Phase 2
-	* added support for EAP-TNC (Trusted Network Connect)
-	  (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
-	  changes needed to run two methods in sequence (IF-T) and the IF-IMV
-	  and IF-TNCCS interfaces from TNCS)
-	* added support for optional cryptobinding with PEAPv0
-	* added fragmentation support for EAP-TNC
-	* added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
-	  data
-	* added support for opportunistic key caching (OKC)
-
-2008-02-22 - v0.6.3
-	* fixed Reassociation Response callback processing when using internal
-	  MLME (driver_{hostap,nl80211,test}.c)
-	* updated FT support to use the latest draft, IEEE 802.11r/D9.0
-	* copy optional Proxy-State attributes into RADIUS response when acting
-	  as a RADIUS authentication server
-	* fixed EAPOL state machine to handle a case in which no response is
-	  received from the RADIUS authentication server; previous version
-	  could have triggered a crash in some cases after a timeout
-	* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
-	  be used
-	* added a workaround for EAP-SIM/AKA peers that include incorrect null
-	  termination in the username
-	* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
-	  attribute in notification messages only when using fast
-	  reauthentication
-	* fixed EAP-SIM Start response processing for fast reauthentication
-	  case
-	* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
-	  phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
-
-2008-01-01 - v0.6.2
-	* fixed EAP-SIM and EAP-AKA message parser to validate attribute
-	  lengths properly to avoid potential crash caused by invalid messages
-	* added data structure for storing allocated buffers (struct wpabuf);
-	  this does not affect hostapd usage, but many of the APIs changed
-	  and various interfaces (e.g., EAP) is not compatible with old
-	  versions
-	* added support for protecting EAP-AKA/Identity messages with
-	  AT_CHECKCODE (optional feature in RFC 4187)
-	* added support for protected result indication with AT_RESULT_IND for
-	  EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
-	* added support for configuring EAP-TTLS phase 2 non-EAP methods in
-	  EAP server configuration; previously all four were enabled for every
-	  phase 2 user, now all four are disabled by default and need to be
-	  enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
-	  TTLS-MSCHAPV2
-	* removed old debug printing mechanism and the related 'debug'
-	  parameter in the configuration file; debug verbosity is now set with
-	  -d (or -dd) command line arguments
-	* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
-	  only shared key/password authentication is supported in this version
-
-2007-11-24 - v0.6.1
-	* added experimental, integrated TLSv1 server implementation with the
-	  needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
-	  setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
-	  .config); this can be useful, e.g., if the target system does not
-	  have a suitable TLS library and a minimal code size is required
-	* added support for EAP-FAST server method to the integrated EAP
-	  server
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-07.txt)
-	* added a new configuration parameter, rsn_pairwise, to allow different
-	  pairwise cipher suites to be enabled for WPA and RSN/WPA2
-	  (note: if wpa_pairwise differs from rsn_pairwise, the driver will
-	  either need to support this or will have to use the WPA/RSN IEs from
-	  hostapd; currently, the included madwifi and bsd driver interfaces do
-	  not have support for this)
-	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
-
-2007-05-28 - v0.6.0
-	* added experimental IEEE 802.11r/D6.0 support
-	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
-	* updated EAP-PSK to use the IANA-allocated EAP type 47
-	* fixed EAP-PSK bit ordering of the Flags field
-	* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
-	  by reading wpa_psk_file [Bug 181]
-	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
-	* fixed IPv6 connection to RADIUS accounting server
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-04.txt)
-	* hlr_auc_gw: read GSM triplet file into memory and rotate through the
-	  entries instead of only using the same three triplets every time
-	  (this does not work properly with tests using multiple clients, but
-	  provides bit better triplet data for testing a single client; anyway,
-	  if a better quality triplets are needed, GSM-Milenage should be used
-	  instead of hardcoded triplet file)
-	* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
-	  in Success Request [Bug 203]
-	* added support for sending EAP-AKA Notifications in error cases
-	* updated to use IEEE 802.11w/D2.0 for management frame protection
-	  (still experimental)
-	* RADIUS server: added support for processing duplicate messages
-	  (retransmissions from RADIUS client) by replying with the previous
-	  reply
-
-2006-11-24 - v0.5.6
-	* added support for configuring and controlling multiple BSSes per
-	  radio interface (bss=<ifname> in hostapd.conf); this is only
-	  available with Devicescape and test driver interfaces
-	* fixed PMKSA cache update in the end of successful RSN
-	  pre-authentication
-	* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
-	  for each STA based on RADIUS Access-Accept attributes); this requires
-	  VLAN support from the kernel driver/802.11 stack and this is
-	  currently only available with Devicescape and test driver interfaces
-	* driver_madwifi: fixed configuration of unencrypted modes (plaintext
-	  and IEEE 802.1X without WEP)
-	* removed STAKey handshake since PeerKey handshake has replaced it in
-	  IEEE 802.11ma and there are no known deployments of STAKey
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-01.txt)
-	* added preliminary implementation of IEEE 802.11w/D1.0 (management
-	  frame protection)
-	  (Note: this requires driver support to work properly.)
-	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
-	* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
-	* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
-	  parameters from a text file to make it possible to implement proper
-	  GSM/UMTS authentication server for multiple SIM/USIM cards using
-	  EAP-SIM/EAP-AKA
-	* fixed session timeout processing with drivers that do not use
-	  ieee802_11.c (e.g., madwifi)
-
-2006-08-27 - v0.5.5
-	* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
-	  hostapd (e.g., to initialize wired network authentication based on an
-	  external signal)
-	* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
-	  using WPA2 even if PMKSA caching is not used
-	* added -P<pid file> argument for hostapd to write the current process
-	  id into a file
-	* added support for RADIUS Authentication Server MIB (RFC 2619)
-
-2006-06-20 - v0.5.4
-	* fixed nt_password_hash build [Bug 144]
-	* added PeerKey handshake implementation for IEEE 802.11e
-	  direct link setup (DLS) to replace STAKey handshake
-	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
-	  draft-clancy-emu-eap-shared-secret-00.txt)
-	* fixed a segmentation fault when RSN pre-authentication was completed
-	  successfully [Bug 152]
-
-2006-04-27 - v0.5.3
-	* do not build nt_password_hash and hlr_auc_gw by default to avoid
-	  requiring a TLS library for a successful build; these programs can be
-	  build with 'make nt_password_hash' and 'make hlr_auc_gw'
-	* added a new configuration option, eapol_version, that can be used to
-	  set EAPOL version to 1 (default is 2) to work around broken client
-	  implementations that drop EAPOL frames which use version number 2
-	  [Bug 89]
-	* added support for EAP-SAKE (no EAP method number allocated yet, so
-	  this is using the same experimental type 255 as EAP-PSK)
-	* fixed EAP-MSCHAPv2 message length validation
-
-2006-03-19 - v0.5.2
-	* fixed stdarg use in hostapd_logger(): if both stdout and syslog
-	  logging was enabled, hostapd could trigger a segmentation fault in
-	  vsyslog on some CPU -- C library combinations
-	* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
-	  program to make it easier to use for implementing real SS7 gateway;
-	  eap_sim_db is not anymore used as a file name for GSM authentication
-	  triplets; instead, it is path to UNIX domain socket that will be used
-	  to communicate with the external gateway program (e.g., hlr_auc_gw)
-	* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
-	  local information (GSM authentication triplets from a text file and
-	  hardcoded AKA authentication data); this can be used to test EAP-SIM
-	  and EAP-AKA
-	* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
-	  to make it possible to test EAP-AKA with real USIM cards (this is
-	  disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
-	  to enable this)
-	* driver_madwifi: added support for getting station RSN IE from
-	  madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
-	  broken with earlier change (r1357) in the driver
-	* changed EAP method registration to use a dynamic list of methods
-	  instead of a static list generated at build time
-	* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
-	  [Bug 125]
-	* added ap_max_inactivity configuration parameter
-
-2006-01-29 - v0.5.1
-	* driver_test: added better support for multiple APs and STAs by using
-	  a directory with sockets that include MAC address for each device in
-	  the name (test_socket=DIR:/tmp/test)
-	* added support for EAP expanded type (vendor specific EAP methods)
-
-2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
-	* added experimental STAKey handshake implementation for IEEE 802.11e
-	  direct link setup (DLS); note: this is disabled by default in both
-	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
-	  and stakey=1)
-	* added support for EAP methods to use callbacks to external programs
-	  by buffering a pending request and processing it after the EAP method
-	  is ready to continue
-	* improved EAP-SIM database interface to allow external request to GSM
-	  HLR/AuC without blocking hostapd process
-	* added support for using EAP-SIM pseudonyms and fast re-authentication
-	* added support for EAP-AKA in the integrated EAP authenticator
-	* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
-	  user database to allow EAP-SIM/AKA selection without extra roundtrip
-	  for EAP-Nak negotiation
-	* added support for storing EAP user password as NtPasswordHash instead
-	  of plaintext password when using MSCHAP or MSCHAPv2 for
-	  authentication (hash:<16-octet hex value>); added nt_password_hash
-	  tool for hashing password to generate NtPasswordHash
-
-2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
-	* driver_wired: fixed EAPOL sending to optionally use PAE group address
-	  as the destination instead of supplicant MAC address; this is
-	  disabled by default, but should be enabled with use_pae_group_addr=1
-	  in configuration file if the wired interface is used by only one
-	  device at the time (common switch configuration)
-	* driver_madwifi: configure driver to use TKIP countermeasures in order
-	  to get correct behavior (IEEE 802.11 association failing; previously,
-	  association succeeded, but hostpad forced disassociation immediately)
-	* driver_madwifi: added support for madwifi-ng
-
-2005-10-27 - v0.4.6
-	* added support for replacing user identity from EAP with RADIUS
-	  User-Name attribute from Access-Accept message, if that is included,
-	  for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
-	  tunneled identity into accounting messages when the RADIUS server
-	  does not support better way of doing this with Class attribute)
-	* driver_madwifi: fixed EAPOL packet receive for configuration where
-	  ath# is part of a bridge interface
-	* added a configuration file and log analyzer script for logwatch
-	* fixed EAPOL state machine step function to process all state
-	  transitions before processing new events; this resolves a race
-	  condition in which EAPOL-Start message could trigger hostapd to send
-	  two EAP-Response/Identity frames to the authentication server
-
-2005-09-25 - v0.4.5
-	* added client CA list to the TLS certificate request in order to make
-	  it easier for the client to select which certificate to use
-	* added experimental support for EAP-PSK
-	* added support for WE-19 (hostap, madwifi)
-
-2005-08-21 - v0.4.4
-	* fixed build without CONFIG_RSN_PREAUTH
-	* fixed FreeBSD build
-
-2005-06-26 - v0.4.3
-	* fixed PMKSA caching to copy User-Name and Class attributes so that
-	  RADIUS accounting gets correct information
-	* start RADIUS accounting only after successful completion of WPA
-	  4-Way Handshake if WPA-PSK is used
-	* fixed PMKSA caching for the case where STA (re)associates without
-	  first disassociating
-
-2005-06-12 - v0.4.2
-	* EAP-PAX is now registered as EAP type 46
-	* fixed EAP-PAX MAC calculation
-	* fixed EAP-PAX CK and ICK key derivation
-	* renamed eap_authenticator configuration variable to eap_server to
-	  better match with RFC 3748 (EAP) terminology
-	* driver_test: added support for testing hostapd with wpa_supplicant
-	  by using test driver interface without any kernel drivers or network
-	  cards
-
-2005-05-22 - v0.4.1
-	* fixed RADIUS server initialization when only auth or acct server
-	  is configured and the other one is left empty
-	* driver_madwifi: added support for RADIUS accounting
-	* driver_madwifi: added preliminary support for compiling against 'BSD'
-	  branch of madwifi CVS tree
-	* driver_madwifi: fixed pairwise key removal to allow WPA reauth
-	  without disassociation
-	* added support for reading additional certificates from PKCS#12 files
-	  and adding them to the certificate chain
-	* fixed RADIUS Class attribute processing to only use Access-Accept
-	  packets to update Class; previously, other RADIUS authentication
-	  packets could have cleared Class attribute
-	* added support for more than one Class attribute in RADIUS packets
-	* added support for verifying certificate revocation list (CRL) when
-	  using integrated EAP authenticator for EAP-TLS; new hostapd.conf
-	  options 'check_crl'; CRL must be included in the ca_cert file for now
-
-2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
-	* added support for including network information into
-	  EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
-	  (e.g., to implement draft-adrange-eap-network-discovery-07.txt)
-	* fixed a bug which caused some RSN pre-authentication cases to use
-	  freed memory and potentially crash hostapd
-	* fixed private key loading for cases where passphrase is not set
-	* added support for sending TLS alerts and aborting authentication
-	  when receiving a TLS alert
-	* fixed WPA2 to add PMKSA cache entry when using integrated EAP
-	  authenticator
-	* fixed PMKSA caching (EAP authentication was not skipped correctly
-	  with the new state machine changes from IEEE 802.1X draft)
-	* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
-	  and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
-	  to be added to .config to include IPv6 support); for RADIUS server,
-	  radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
-	  in RADIUS clients file can then use IPv6 format
-	* added experimental support for EAP-PAX
-	* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
-	  the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
-
-2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
-
-2005-01-23 - v0.3.5
-	* added support for configuring a forced PEAP version based on the
-	  Phase 1 identity
-	* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
-	  to terminate authentication
-	* fixed EAP identifier duplicate processing with the new IEEE 802.1X
-	  draft
-	* clear accounting data in the driver when starting a new accounting
-	  session
-	* driver_madwifi: filter wireless events based on ifindex to allow more
-	  than one network interface to be used
-	* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
-	  setting if the packet does not pass MIC verification (e.g., due to
-	  incorrect PSK); previously, message 1/4 was not tried again if an
-	  invalid message 2/4 was received
-	* fixed reconfiguration of RADIUS client retransmission timer when
-	  adding a new message to the pending list; previously, timer was not
-	  updated at this point and if there was a pending message with long
-	  time for the next retry, the new message needed to wait that long for
-	  its first retry, too
-
-2005-01-09 - v0.3.4
-	* added support for configuring multiple allowed EAP types for Phase 2
-	  authentication (EAP-PEAP, EAP-TTLS)
-	* fixed EAPOL-Start processing to trigger WPA reauthentication
-	  (previously, only EAPOL authentication was done)
-
-2005-01-02 - v0.3.3
-	* added support for EAP-PEAP in the integrated EAP authenticator
-	* added support for EAP-GTC in the integrated EAP authenticator
-	* added support for configuring list of EAP methods for Phase 1 so that
-	  the integrated EAP authenticator can, e.g., use the wildcard entry
-	  for EAP-TLS and EAP-PEAP
-	* added support for EAP-TTLS in the integrated EAP authenticator
-	* added support for EAP-SIM in the integrated EAP authenticator
-	* added support for using hostapd as a RADIUS authentication server
-	  with the integrated EAP authenticator taking care of EAP
-	  authentication (new hostapd.conf options: radius_server_clients and
-	  radius_server_auth_port); this is not included in default build; use
-	  CONFIG_RADIUS_SERVER=y in .config to include
-
-2004-12-19 - v0.3.2
-	* removed 'daemonize' configuration file option since it has not really
-	  been used at all for more than year
-	* driver_madwifi: fixed group key setup and added get_ssid method
-	* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
-
-2004-12-12 - v0.3.1
-	* added support for integrated EAP-TLS authentication (new hostapd.conf
-	  variables: ca_cert, server_cert, private_key, private_key_passwd);
-	  this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
-	  external RADIUS server
-	* added support for reading PKCS#12 (PFX) files (as a replacement for
-	  PEM/DER) to get certificate and private key (CONFIG_PKCS12)
-
-2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
-	* added support for Acct-{Input,Output}-Gigawords
-	* added support for Event-Timestamp (in RADIUS Accounting-Requests)
-	* added support for RADIUS Authentication Client MIB (RFC2618)
-	* added support for RADIUS Accounting Client MIB (RFC2620)
-	* made EAP re-authentication period configurable (eap_reauth_period)
-	* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
-	* fixed EAPOL state machine to stop if STA is removed during
-	  eapol_sm_step(); this fixes at least one segfault triggering bug with
-	  IEEE 802.11i pre-authentication
-	* added support for multiple WPA pre-shared keys (e.g., one for each
-	  client MAC address or keys shared by a group of clients);
-	  new hostapd.conf field wpa_psk_file for setting path to a text file
-	  containing PSKs, see hostapd.wpa_psk for an example
-	* added support for multiple driver interfaces to allow hostapd to be
-	  used with other drivers
-	* added wired authenticator driver interface (driver=wired in
-	  hostapd.conf, see wired.conf for example configuration)
-	* added madwifi driver interface (driver=madwifi in hostapd.conf, see
-	  madwifi.conf for example configuration; Note: include files from
-	  madwifi project is needed for building and a configuration file,
-	  .config, needs to be created in hostapd directory with
-	  CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
-	  build)
-	* fixed an alignment issue that could cause SHA-1 to fail on some
-	  platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
-	  align variables)
-	* fixed RADIUS reconnection after an error in sending interim
-	  accounting packets
-	* added hostapd control interface for external programs and an example
-	  CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
-	* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
-	  'hostapd_cli sta <addr>')
-	* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
-	* added support for strict GTK rekeying (wpa_strict_rekey in
-	  hostapd.conf)
-	* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
-	  (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
-	  IEEE 802.11F-2003)
-	* added Prism54 driver interface (driver=prism54 in hostapd.conf;
-	  note: .config needs to be created in hostapd directory with
-	  CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
-	  build)
-	* dual-licensed hostapd (GPLv2 and BSD licenses)
-	* fixed RADIUS accounting to generate a new session id for cases where
-	  a station reassociates without first being complete deauthenticated
-	* fixed STA disassociation handler to mark next timeout state to
-	  deauthenticate the station, i.e., skip long wait for inactivity poll
-	  and extra disassociation, if the STA disassociates without
-	  deauthenticating
-	* added integrated EAP authenticator that can be used instead of
-	  external RADIUS authentication server; currently, only EAP-MD5 is
-	  supported, so this cannot yet be used for key distribution; the EAP
-	  method interface is generic, though, so adding new EAP methods should
-	  be straightforward; new hostapd.conf variables: 'eap_authenticator'
-	  and 'eap_user_file'; this obsoletes "minimal authentication server"
-	  ('minimal_eap' in hostapd.conf) which is now removed
-	* added support for FreeBSD and driver interface for the BSD net80211
-	  layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
-	  .config); please note that some of the required kernel mods have not
-	  yet been committed
-
-2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
-	* fixed some accounting cases where Accounting-Start was sent when
-	  IEEE 802.1X port was being deauthorized
-
-2004-06-20 - v0.2.3
-	* modified RADIUS client to re-connect the socket in case of certain
-	  error codes that are generated when a network interface state is
-	  changes (e.g., when IP address changes or the interface is set UP)
-	* fixed couple of cases where EAPOL state for a station was freed
-	  twice causing a segfault for hostapd
-	* fixed couple of bugs in processing WPA deauthentication (freed data
-	  was used)
-
-2004-05-31 - v0.2.2
-	* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
-	* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
-	  cases where STAs dropped multicast frames as replay attacks
-	* added support for copying RADIUS Attribute 'Class' from
-	  authentication messages into accounting messages
-	* send canned EAP failure if RADIUS server sends Access-Reject without
-	  EAP message (previously, Supplicant was not notified in this case)
-	* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
-	  not start EAPOL state machines if the STA selected to use WPA-PSK)
-
-2004-05-06 - v0.2.1
-	* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
-	  - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
-	    (i.e., IEEE 802.11i/D3.0)
-	  - supports WPA-only, RSN-only, and mixed WPA/RSN mode
-	  - both WPA-PSK and WPA-RADIUS/EAP are supported
-	  - PMKSA caching and pre-authentication
-	  - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
-	    wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
-	    rsn_preauth, rsn_preauth_interfaces
-	* fixed interim accounting to remove any pending accounting messages
-	  to the STA before sending a new one
-
-2004-02-15 - v0.2.0
-	* added support for Acct-Interim-Interval:
-	  - draft-ietf-radius-acct-interim-01.txt
-	  - use Acct-Interim-Interval attribute from Access-Accept if local
-	    'radius_acct_interim_interval' is not set
-	  - allow different update intervals for each STA
-	* fixed event loop to call signal handlers only after returning from
-	  the real signal handler
-	* reset sta->timeout_next after successful association to make sure
-	  that the previously registered inactivity timer will not remove the
-	  STA immediately (e.g., if STA deauthenticates and re-associates
-	  before the timer is triggered).
-	* added new hostapd.conf variable, nas_identifier, that can be used to
-	  add an optional RADIUS Attribute, NAS-Identifier, into authentication
-	  and accounting messages
-	* added support for Accounting-On and Accounting-Off messages
-	* fixed accounting session handling to send Accounting-Start only once
-	  per session and not to send Accounting-Stop if the session was not
-	  initialized properly
-	* fixed Accounting-Stop statistics in cases where the message was
-	  previously sent after the kernel entry for the STA (and/or IEEE
-	  802.1X data) was removed
-
-
-Note:
-
-Older changes up to and including v0.1.0 are included in the ChangeLog
-of the Host AP driver.

Copied: vendor/wpa/2.0/hostapd/ChangeLog (from rev 9639, vendor/wpa/dist/hostapd/ChangeLog)
===================================================================
--- vendor/wpa/2.0/hostapd/ChangeLog	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/ChangeLog	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,849 @@
+ChangeLog for hostapd
+
+2013-01-12 - v2.0
+	* added AP-STA-DISCONNECTED ctrl_iface event
+	* improved debug logging (human readable event names, interface name
+	  included in more entries)
+	* added number of small changes to make it easier for static analyzers
+	  to understand the implementation
+	* added a workaround for Windows 7 Michael MIC failure reporting and
+	  use of the Secure bit in EAPOL-Key msg 3/4
+	* fixed number of small bugs (see git logs for more details)
+	* changed OpenSSL to read full certificate chain from server_cert file
+	* nl80211: number of updates to use new cfg80211/nl80211 functionality
+	  - replace monitor interface with nl80211 commands
+	  - additional information for driver-based AP SME
+	* EAP-pwd:
+	  - fix KDF for group 21 and zero-padding
+	  - added support for fragmentation
+	  - increased maximum number of hunting-and-pecking iterations
+	* avoid excessive Probe Response retries for broadcast Probe Request
+	  frames (only with drivers using hostapd SME/MLME)
+	* added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+	* fixed WPS operation stopping on dual concurrent AP
+	* added wps_rf_bands configuration parameter for overriding RF Bands
+	  value for WPS
+	* added support for getting per-device PSK from RADIUS Tunnel-Password
+	* added support for libnl 3.2 and newer
+	* increased initial group key handshake retransmit timeout to 500 ms
+	* added a workaround for 4-way handshake to update SNonce even after
+	  having sent EAPOL-Key 3/4 to avoid issues with some supplicant
+	  implementations that can change SNonce for each EAP-Key 2/4
+	* added a workaround for EAPOL-Key 4/4 using incorrect type value in
+	  WPA2 mode (some deployed stations use WPA type in that message)
+	* added a WPS workaround for mixed mode AP Settings with Windows 7
+	* changed WPS AP PIN disabling mechanism to disable the PIN after 10
+	  consecutive failures in addition to using the exponential lockout
+	  period
+	* added support for WFA Hotspot 2.0
+	  - GAS/ANQP advertisement of network information
+	  - disable_dgaf parameter to disable downstream group-addressed
+	    forwarding
+	* simplified licensing terms by selecting the BSD license as the only
+	  alternative
+	* EAP-SIM: fixed re-authentication not to update pseudonym
+	* EAP-SIM: use Notification round before EAP-Failure
+	* EAP-AKA: added support for AT_COUNTER_TOO_SMALL
+	* EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
+	* EAP-AKA': fixed identity for MK derivation
+	* EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+	  breaks interoperability with older versions
+	* EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
+	* changed ANonce to be a random number instead of Counter-based
+	* added support for canceling WPS operations with hostapd_cli wps_cancel
+	* fixed EAP/WPS to PSK transition on reassociation in cases where
+	  deauthentication is missed
+	* hlr_auc_gw enhancements:
+	  - a new command line parameter -u can be used to enable updating of
+	    SQN in Milenage file
+	  - use 5 bit IND for SQN updates
+	  - SQLite database can now be used to store Milenage information
+	* EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
+	  and reauth data
+	* added support for Chargeable-User-Identity (RFC 4372)
+	* added radius_auth_req_attr and radius_acct_req_attr configuration
+	  parameters to allow adding/overriding of RADIUS attributes in
+	  Access-Request and Accounting-Request packets
+	* added support for RADIUS dynamic authorization server (RFC 5176)
+	* added initial support for WNM operations
+	  - BSS max idle period
+	  - WNM-Sleep Mode
+	* added new WPS NFC ctrl_iface mechanism
+	  - removed obsoleted WPS_OOB command (including support for deprecated
+	    UFD config_method)
+	* added FT support for drivers that implement MLME internally
+	* added SA Query support for drivers that implement MLME internally
+	* removed default ACM=1 from AC_VO and AC_VI
+	* changed VENDOR-TEST EAP method to use proper private enterprise number
+	  (this will not interoperate with older versions)
+	* added hostapd.conf parameter vendor_elements to allow arbitrary vendor
+	  specific elements to be added to the Beacon and Probe Response frames
+	* added support for configuring GCMP cipher for IEEE 802.11ad
+	* added support for 256-bit AES with internal TLS implementation
+	* changed EAPOL transmission to use AC_VO if WMM is active
+	* fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
+	  correctly; invalid messages could have caused the hostapd process to
+	  terminate before this fix [CVE-2012-4445]
+	* limit number of active wildcard PINs for WPS Registrar to one to avoid
+	  confusing behavior with multiple wildcard PINs
+	* added a workaround for WPS PBC session overlap detection to avoid
+	  interop issues with deployed station implementations that do not
+	  remove active PBC indication from Probe Request frames properly
+	* added support for using SQLite for the eap_user database
+	* added Acct-Session-Id attribute into Access-Request messages
+	* fixed EAPOL frame transmission to non-QoS STAs with nl80211
+	  (do not send QoS frames if the STA did not negotiate use of QoS for
+	  this association)
+
+2012-05-10 - v1.0
+	* Add channel selection support in hostapd. See hostapd.conf.
+	* Add support for IEEE 802.11v Time Advertisement mechanism with UTC
+	  TSF offset. See hostapd.conf for config info.
+	* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+	  This allows the driver to use PS buffering of Deauthentication and
+	  Disassociation frames when the STA is in power save sleep. Only
+	  available with drivers that provide TX status events for Deauth/
+	  Disassoc frames (nl80211).
+	* Allow PMKSA caching to be disabled on the Authenticator. See
+	  hostap.conf config parameter disable_pmksa_caching.
+	* atheros: Add support for IEEE 802.11w configuration.
+	* bsd: Add support for setting HT values in IFM_MMASK.
+	* Allow client isolation to be configured with ap_isolate. Client
+	  isolation can be used to prevent low-level bridging of frames
+	  between associated stations in the BSS. By default, this bridging
+	  is allowed.
+	* Allow coexistance of HT BSSes with WEP/TKIP BSSes.
+	* Add require_ht config parameter, which can be used to configure
+	  hostapd to reject association with any station that does not support
+	  HT PHY.
+	* Add support for writing debug log to a file using "-f" option. Also
+	  add relog CLI command to re-open the log file.
+	* Add bridge handling for WDS STA interfaces. By default they are
+	  added to the configured bridge of the AP interface (if present),
+	  but the user can also specify a separate bridge using cli command
+	  wds_bridge.
+	* hostapd_cli:
+	  - Add wds_bridge command for specifying bridge for WDS STA
+	    interfaces.
+	  - Add relog command for reopening log file.
+	  - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+	    due to inactivity.
+	  - Add wps_config ctrl_interface command for configuring AP. This
+	    command can be used to configure the AP using the internal WPS
+	    registrar. It works in the same way as new AP settings received
+	    from an ER.
+	  - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+	  - Add command get version, that returns hostapd version string.
+	* WNM: Add BSS Transition Management Request for ESS Disassoc Imminent.
+	  Use hostapd_cli ess_disassoc (STA addr) (URL) to send the
+	  notification to the STA.
+	* Allow AP mode to disconnect STAs based on low ACK condition (when
+	  the data connection is not working properly, e.g., due to the STA
+	  going outside the range of the AP). Disabled by default, enable by
+	  config option disassoc_low_ack.
+	* Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+	  config file.
+	* WPS:
+	  - Send AP Settings as a wrapped Credential attribute to ctrl_iface
+	    in WPS-NEW-AP-SETTINGS.
+	  - Dispatch more WPS events through hostapd ctrl_iface.
+	  - Add mechanism for indicating non-standard WPS errors.
+	  - Change concurrent radio AP to use only one WPS UPnP instance.
+	  - Add wps_check_pin command for processing PIN from user input.
+	    UIs can use this command to process a PIN entered by a user and to
+	    validate the checksum digit (if present).
+	  - Add hostap_cli get_config command to display current AP config.
+	  - Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at
+	    runtime and support dynamic AP PIN management.
+	  - Disable AP PIN after 10 consecutive failures. Slow down attacks
+	    on failures up to 10.
+	  - Allow AP to start in Enrollee mode without AP PIN for probing,
+	    to be compatible with Windows 7.
+	  - Add Config Error into WPS-FAIL events to provide more info
+	    to the user on how to resolve the issue.
+	  - When controlling multiple interfaces:
+	     - apply WPS commands to all interfaces configured to use WPS
+	     - apply WPS config changes to all interfaces that use WPS
+	     - when an attack is detected on any interface, disable AP PIN on
+	       all interfaces
+	* WPS ER:
+	  - Show SetSelectedRegistrar events as ctrl_iface events.
+	  - Add special AP Setup Locked mode to allow read only ER.
+	    ap_setup_locked=2 can now be used to enable a special mode where
+	    WPS ER can learn the current AP settings, but cannot change them.
+	* WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+	  - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+	    for testing protocol extensibility.
+	  - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+	    workarounds.
+	  - Add support for AuthorizedMACs attribute.
+	* TDLS:
+	  - Allow TDLS use or TDLS channel switching in the BSS to be
+	    prohibited in the BSS, using config params tdls_prohibit and
+	    tdls_prohibit_chan_switch.
+	* EAP server: Add support for configuring fragment size (see
+	  fragment_size in hostapd.conf).
+	* wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+	  wlantest can be used to capture frames from a monitor interface
+	  for realtime capturing or from pcap files for offline analysis.
+	* Interworking: Support added for 802.11u. Enable in .config with
+	  CONFIG_INTERWORKING. See hostapd.conf for config parameters for
+	  interworking.
+	* Android: Add build and runtime support for Android hostapd.
+	* Add a new debug message level for excessive information. Use
+	  -ddd to enable.
+	* TLS: Add support for tls_disable_time_checks=1 in client mode.
+	* Internal TLS:
+	  - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+	    CONFIG_TLSV11.
+	  - Add domainComponent parser for X.509 names
+	* Reorder some IEs to get closer to IEEE 802.11 standard. Move
+	  WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+	  Move HT IEs to be later in (Re)Assoc Resp.
+	* Many bugfixes.
+
+2010-04-18 - v0.7.2
+	* fix WPS internal Registrar use when an external Registrar is also
+	  active
+	* bsd: Cleaned up driver wrapper and added various low-level
+	  configuration options
+	* TNC: fixed issues with fragmentation
+	* EAP-TNC: add Flags field into fragment acknowledgement (needed to
+	  interoperate with other implementations; may potentially breaks
+	  compatibility with older wpa_supplicant/hostapd versions)
+	* cleaned up driver wrapper API for multi-BSS operations
+	* nl80211: fix multi-BSS and VLAN operations
+	* fix number of issues with IEEE 802.11r/FT; this version is not
+	  backwards compatible with old versions
+	* add SA Query Request processing in AP mode (IEEE 802.11w)
+	* fix IGTK PN in group rekeying (IEEE 802.11w)
+	* fix WPS PBC session overlap detection to use correct attribute
+	* hostapd_notif_Assoc() can now be called with all IEs to simplify
+	  driver wrappers
+	* work around interoperability issue with some WPS External Registrar
+	  implementations
+	* nl80211: fix WPS IE update
+	* hostapd_cli: add support for action script operations (run a script
+	  on hostapd events)
+	* fix DH padding with internal crypto code (mainly, for WPS)
+	* fix WPS association with both WPS IE and WPA/RSN IE present with
+	  driver wrappers that use hostapd MLME (e.g., nl80211)
+
+2010-01-16 - v0.7.1
+	* cleaned up driver wrapper API (struct wpa_driver_ops); the new API
+	  is not fully backwards compatible, so out-of-tree driver wrappers
+	  will need modifications
+	* cleaned up various module interfaces
+	* merge hostapd and wpa_supplicant developers' documentation into a
+	  single document
+	* fixed HT Capabilities IE with nl80211 drivers
+	* moved generic AP functionality code into src/ap
+	* WPS: handle Selected Registrar as union of info from all Registrars
+	* remove obsolte Prism54.org driver wrapper
+	* added internal debugging mechanism with backtrace support and memory
+	  allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
+	* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
+	* WPS: add support for dynamically selecting whether to provision the
+	  PSK as an ASCII passphrase or PSK
+	* added support for WDS (4-address frame) mode with per-station virtual
+	  interfaces (wds_sta=1 in config file; only supported with
+	  driver=nl80211 for now)
+	* fixed WPS Probe Request processing to handle missing required
+	  attribute
+	* fixed PKCS#12 use with OpenSSL 1.0.0
+	* detect bridge interface automatically so that bridge parameter in
+	  hostapd.conf becomes optional (though, it may now be used to
+	  automatically add then WLAN interface into a bridge with
+	  driver=nl80211)
+
+2009-11-21 - v0.7.0
+	* increased hostapd_cli ping interval to 5 seconds and made this
+	  configurable with a new command line options (-G<seconds>)
+	* driver_nl80211: use Linux socket filter to improve performance
+	* added support for external Registrars with WPS (UPnP transport)
+	* 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel
+	* driver_nl80211: fixed STA accounting data collection (TX/RX bytes
+	  reported correctly; TX/RX packets not yet available from kernel)
+	* added support for WPS USBA out-of-band mechanism with USB Flash
+	  Drives (UFD) (CONFIG_WPS_UFD=y)
+	* fixed EAPOL/EAP reauthentication when using an external RADIUS
+	  authentication server
+	* fixed TNC with EAP-TTLS
+	* fixed IEEE 802.11r key derivation function to match with the standard
+	  (note: this breaks interoperability with previous version) [Bug 303]
+	* fixed SHA-256 based key derivation function to match with the
+	  standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+	  (note: this breaks interoperability with previous version) [Bug 307]
+	* added number of code size optimizations to remove unnecessary
+	  functionality from the program binary based on build configuration
+	  (part of this automatic; part configurable with CONFIG_NO_* build
+	  options)
+	* use shared driver wrapper files with wpa_supplicant
+	* driver_nl80211: multiple updates to provide support for new Linux
+	  nl80211/mac80211 functionality
+	* updated management frame protection to use IEEE Std 802.11w-2009
+	* fixed number of small WPS issues and added workarounds to
+	  interoperate with common deployed broken implementations
+	* added some IEEE 802.11n co-existence rules to disable 40 MHz channels
+	  or modify primary/secondary channels if needed based on neighboring
+	  networks
+	* added support for NFC out-of-band mechanism with WPS
+	* added preliminary support for IEEE 802.11r RIC processing
+
+2009-01-06 - v0.6.7
+	* added support for Wi-Fi Protected Setup (WPS)
+	  (hostapd can now be configured to act as an integrated WPS Registrar
+	  and provision credentials for WPS Enrollees using PIN and PBC
+	  methods; external wireless Registrar can configure the AP, but
+	  external WLAN Manager Registrars are not supported); WPS support can
+	  be enabled by adding CONFIG_WPS=y into .config and setting the
+	  runtime configuration variables in hostapd.conf (see WPS section in
+	  the example configuration file); new hostapd_cli commands wps_pin and
+	  wps_pbc are used to configure WPS negotiation; see README-WPS for
+	  more details
+	* added IEEE 802.11n HT capability configuration (ht_capab)
+	* added support for generating Country IE based on nl80211 regulatory
+	  information (added if ieee80211d=1 in configuration)
+	* fixed WEP authentication (both Open System and Shared Key) with
+	  mac80211
+	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+	* added support for using driver_test over UDP socket
+	* changed EAP-GPSK to use the IANA assigned EAP method type 51
+	* updated management frame protection to use IEEE 802.11w/D7.0
+	* fixed retransmission of EAP requests if no response is received
+
+2008-11-23 - v0.6.6
+	* added a new configuration option, wpa_ptk_rekey, that can be used to
+	  enforce frequent PTK rekeying, e.g., to mitigate some attacks against
+	  TKIP deficiencies
+	* updated OpenSSL code for EAP-FAST to use an updated version of the
+	  session ticket overriding API that was included into the upstream
+	  OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
+	  needed with that version anymore)
+	* changed channel flags configuration to read the information from
+	  the driver (e.g., via driver_nl80211 when using mac80211) instead of
+	  using hostapd as the source of the regulatory information (i.e.,
+	  information from CRDA is now used with mac80211); this allows 5 GHz
+	  channels to be used with hostapd (if allowed in the current
+	  regulatory domain)
+	* fixed EAP-TLS message processing for the last TLS message if it is
+	  large enough to require fragmentation (e.g., if a large Session
+	  Ticket data is included)
+	* fixed listen interval configuration for nl80211 drivers
+
+2008-11-01 - v0.6.5
+	* added support for SHA-256 as X.509 certificate digest when using the
+	  internal X.509/TLSv1 implementation
+	* fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
+	  identity lengths)
+	* fixed internal TLSv1 implementation for abbreviated handshake (used
+	  by EAP-FAST server)
+	* added support for setting VLAN ID for STAs based on local MAC ACL
+	  (accept_mac_file) as an alternative for RADIUS server-based
+	  configuration
+	* updated management frame protection to use IEEE 802.11w/D6.0
+	  (adds a new association ping to protect against unauthenticated
+	  authenticate or (re)associate request frames dropping association)
+	* added support for using SHA256-based stronger key derivation for WPA2
+	  (IEEE 802.11w)
+	* added new "driver wrapper" for RADIUS-only configuration
+	  (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
+	* fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
+	  is enabled in configuration
+	* changed EAP-FAST configuration to use separate fields for A-ID and
+	  A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
+	  16-octet len binary value for better interoperability with some peer
+	  implementations; eap_fast_a_id is now configured as a hex string
+	* driver_nl80211: Updated to match the current Linux mac80211 AP mode
+	  configuration (wireless-testing.git and Linux kernel releases
+	  starting from 2.6.29)
+
+2008-08-10 - v0.6.4
+	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
+	  Identity Request if identity is already known
+	* added support for EAP Sequences in EAP-FAST Phase 2
+	* added support for EAP-TNC (Trusted Network Connect)
+	  (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
+	  changes needed to run two methods in sequence (IF-T) and the IF-IMV
+	  and IF-TNCCS interfaces from TNCS)
+	* added support for optional cryptobinding with PEAPv0
+	* added fragmentation support for EAP-TNC
+	* added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
+	  data
+	* added support for opportunistic key caching (OKC)
+
+2008-02-22 - v0.6.3
+	* fixed Reassociation Response callback processing when using internal
+	  MLME (driver_{hostap,nl80211,test}.c)
+	* updated FT support to use the latest draft, IEEE 802.11r/D9.0
+	* copy optional Proxy-State attributes into RADIUS response when acting
+	  as a RADIUS authentication server
+	* fixed EAPOL state machine to handle a case in which no response is
+	  received from the RADIUS authentication server; previous version
+	  could have triggered a crash in some cases after a timeout
+	* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
+	  be used
+	* added a workaround for EAP-SIM/AKA peers that include incorrect null
+	  termination in the username
+	* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
+	  attribute in notification messages only when using fast
+	  reauthentication
+	* fixed EAP-SIM Start response processing for fast reauthentication
+	  case
+	* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
+	  phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
+
+2008-01-01 - v0.6.2
+	* fixed EAP-SIM and EAP-AKA message parser to validate attribute
+	  lengths properly to avoid potential crash caused by invalid messages
+	* added data structure for storing allocated buffers (struct wpabuf);
+	  this does not affect hostapd usage, but many of the APIs changed
+	  and various interfaces (e.g., EAP) is not compatible with old
+	  versions
+	* added support for protecting EAP-AKA/Identity messages with
+	  AT_CHECKCODE (optional feature in RFC 4187)
+	* added support for protected result indication with AT_RESULT_IND for
+	  EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
+	* added support for configuring EAP-TTLS phase 2 non-EAP methods in
+	  EAP server configuration; previously all four were enabled for every
+	  phase 2 user, now all four are disabled by default and need to be
+	  enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
+	  TTLS-MSCHAPV2
+	* removed old debug printing mechanism and the related 'debug'
+	  parameter in the configuration file; debug verbosity is now set with
+	  -d (or -dd) command line arguments
+	* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
+	  only shared key/password authentication is supported in this version
+
+2007-11-24 - v0.6.1
+	* added experimental, integrated TLSv1 server implementation with the
+	  needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+	  setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+	  .config); this can be useful, e.g., if the target system does not
+	  have a suitable TLS library and a minimal code size is required
+	* added support for EAP-FAST server method to the integrated EAP
+	  server
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-07.txt)
+	* added a new configuration parameter, rsn_pairwise, to allow different
+	  pairwise cipher suites to be enabled for WPA and RSN/WPA2
+	  (note: if wpa_pairwise differs from rsn_pairwise, the driver will
+	  either need to support this or will have to use the WPA/RSN IEs from
+	  hostapd; currently, the included madwifi and bsd driver interfaces do
+	  not have support for this)
+	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
+
+2007-05-28 - v0.6.0
+	* added experimental IEEE 802.11r/D6.0 support
+	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+	* updated EAP-PSK to use the IANA-allocated EAP type 47
+	* fixed EAP-PSK bit ordering of the Flags field
+	* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+	  by reading wpa_psk_file [Bug 181]
+	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
+	* fixed IPv6 connection to RADIUS accounting server
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-04.txt)
+	* hlr_auc_gw: read GSM triplet file into memory and rotate through the
+	  entries instead of only using the same three triplets every time
+	  (this does not work properly with tests using multiple clients, but
+	  provides bit better triplet data for testing a single client; anyway,
+	  if a better quality triplets are needed, GSM-Milenage should be used
+	  instead of hardcoded triplet file)
+	* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+	  in Success Request [Bug 203]
+	* added support for sending EAP-AKA Notifications in error cases
+	* updated to use IEEE 802.11w/D2.0 for management frame protection
+	  (still experimental)
+	* RADIUS server: added support for processing duplicate messages
+	  (retransmissions from RADIUS client) by replying with the previous
+	  reply
+
+2006-11-24 - v0.5.6
+	* added support for configuring and controlling multiple BSSes per
+	  radio interface (bss=<ifname> in hostapd.conf); this is only
+	  available with Devicescape and test driver interfaces
+	* fixed PMKSA cache update in the end of successful RSN
+	  pre-authentication
+	* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+	  for each STA based on RADIUS Access-Accept attributes); this requires
+	  VLAN support from the kernel driver/802.11 stack and this is
+	  currently only available with Devicescape and test driver interfaces
+	* driver_madwifi: fixed configuration of unencrypted modes (plaintext
+	  and IEEE 802.1X without WEP)
+	* removed STAKey handshake since PeerKey handshake has replaced it in
+	  IEEE 802.11ma and there are no known deployments of STAKey
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-01.txt)
+	* added preliminary implementation of IEEE 802.11w/D1.0 (management
+	  frame protection)
+	  (Note: this requires driver support to work properly.)
+	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+	* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+	* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+	  parameters from a text file to make it possible to implement proper
+	  GSM/UMTS authentication server for multiple SIM/USIM cards using
+	  EAP-SIM/EAP-AKA
+	* fixed session timeout processing with drivers that do not use
+	  ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+	* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+	  hostapd (e.g., to initialize wired network authentication based on an
+	  external signal)
+	* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+	  using WPA2 even if PMKSA caching is not used
+	* added -P<pid file> argument for hostapd to write the current process
+	  id into a file
+	* added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+	* fixed nt_password_hash build [Bug 144]
+	* added PeerKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS) to replace STAKey handshake
+	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+	  draft-clancy-emu-eap-shared-secret-00.txt)
+	* fixed a segmentation fault when RSN pre-authentication was completed
+	  successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+	* do not build nt_password_hash and hlr_auc_gw by default to avoid
+	  requiring a TLS library for a successful build; these programs can be
+	  build with 'make nt_password_hash' and 'make hlr_auc_gw'
+	* added a new configuration option, eapol_version, that can be used to
+	  set EAPOL version to 1 (default is 2) to work around broken client
+	  implementations that drop EAPOL frames which use version number 2
+	  [Bug 89]
+	* added support for EAP-SAKE (no EAP method number allocated yet, so
+	  this is using the same experimental type 255 as EAP-PSK)
+	* fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
+	* fixed stdarg use in hostapd_logger(): if both stdout and syslog
+	  logging was enabled, hostapd could trigger a segmentation fault in
+	  vsyslog on some CPU -- C library combinations
+	* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+	  program to make it easier to use for implementing real SS7 gateway;
+	  eap_sim_db is not anymore used as a file name for GSM authentication
+	  triplets; instead, it is path to UNIX domain socket that will be used
+	  to communicate with the external gateway program (e.g., hlr_auc_gw)
+	* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+	  local information (GSM authentication triplets from a text file and
+	  hardcoded AKA authentication data); this can be used to test EAP-SIM
+	  and EAP-AKA
+	* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+	  to make it possible to test EAP-AKA with real USIM cards (this is
+	  disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+	  to enable this)
+	* driver_madwifi: added support for getting station RSN IE from
+	  madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+	  broken with earlier change (r1357) in the driver
+	* changed EAP method registration to use a dynamic list of methods
+	  instead of a static list generated at build time
+	* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+	  [Bug 125]
+	* added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+	* driver_test: added better support for multiple APs and STAs by using
+	  a directory with sockets that include MAC address for each device in
+	  the name (test_socket=DIR:/tmp/test)
+	* added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+	* added experimental STAKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS); note: this is disabled by default in both
+	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+	  and stakey=1)
+	* added support for EAP methods to use callbacks to external programs
+	  by buffering a pending request and processing it after the EAP method
+	  is ready to continue
+	* improved EAP-SIM database interface to allow external request to GSM
+	  HLR/AuC without blocking hostapd process
+	* added support for using EAP-SIM pseudonyms and fast re-authentication
+	* added support for EAP-AKA in the integrated EAP authenticator
+	* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+	  user database to allow EAP-SIM/AKA selection without extra roundtrip
+	  for EAP-Nak negotiation
+	* added support for storing EAP user password as NtPasswordHash instead
+	  of plaintext password when using MSCHAP or MSCHAPv2 for
+	  authentication (hash:<16-octet hex value>); added nt_password_hash
+	  tool for hashing password to generate NtPasswordHash
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+	* driver_wired: fixed EAPOL sending to optionally use PAE group address
+	  as the destination instead of supplicant MAC address; this is
+	  disabled by default, but should be enabled with use_pae_group_addr=1
+	  in configuration file if the wired interface is used by only one
+	  device at the time (common switch configuration)
+	* driver_madwifi: configure driver to use TKIP countermeasures in order
+	  to get correct behavior (IEEE 802.11 association failing; previously,
+	  association succeeded, but hostpad forced disassociation immediately)
+	* driver_madwifi: added support for madwifi-ng
+
+2005-10-27 - v0.4.6
+	* added support for replacing user identity from EAP with RADIUS
+	  User-Name attribute from Access-Accept message, if that is included,
+	  for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
+	  tunneled identity into accounting messages when the RADIUS server
+	  does not support better way of doing this with Class attribute)
+	* driver_madwifi: fixed EAPOL packet receive for configuration where
+	  ath# is part of a bridge interface
+	* added a configuration file and log analyzer script for logwatch
+	* fixed EAPOL state machine step function to process all state
+	  transitions before processing new events; this resolves a race
+	  condition in which EAPOL-Start message could trigger hostapd to send
+	  two EAP-Response/Identity frames to the authentication server
+
+2005-09-25 - v0.4.5
+	* added client CA list to the TLS certificate request in order to make
+	  it easier for the client to select which certificate to use
+	* added experimental support for EAP-PSK
+	* added support for WE-19 (hostap, madwifi)
+
+2005-08-21 - v0.4.4
+	* fixed build without CONFIG_RSN_PREAUTH
+	* fixed FreeBSD build
+
+2005-06-26 - v0.4.3
+	* fixed PMKSA caching to copy User-Name and Class attributes so that
+	  RADIUS accounting gets correct information
+	* start RADIUS accounting only after successful completion of WPA
+	  4-Way Handshake if WPA-PSK is used
+	* fixed PMKSA caching for the case where STA (re)associates without
+	  first disassociating
+
+2005-06-12 - v0.4.2
+	* EAP-PAX is now registered as EAP type 46
+	* fixed EAP-PAX MAC calculation
+	* fixed EAP-PAX CK and ICK key derivation
+	* renamed eap_authenticator configuration variable to eap_server to
+	  better match with RFC 3748 (EAP) terminology
+	* driver_test: added support for testing hostapd with wpa_supplicant
+	  by using test driver interface without any kernel drivers or network
+	  cards
+
+2005-05-22 - v0.4.1
+	* fixed RADIUS server initialization when only auth or acct server
+	  is configured and the other one is left empty
+	* driver_madwifi: added support for RADIUS accounting
+	* driver_madwifi: added preliminary support for compiling against 'BSD'
+	  branch of madwifi CVS tree
+	* driver_madwifi: fixed pairwise key removal to allow WPA reauth
+	  without disassociation
+	* added support for reading additional certificates from PKCS#12 files
+	  and adding them to the certificate chain
+	* fixed RADIUS Class attribute processing to only use Access-Accept
+	  packets to update Class; previously, other RADIUS authentication
+	  packets could have cleared Class attribute
+	* added support for more than one Class attribute in RADIUS packets
+	* added support for verifying certificate revocation list (CRL) when
+	  using integrated EAP authenticator for EAP-TLS; new hostapd.conf
+	  options 'check_crl'; CRL must be included in the ca_cert file for now
+
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+	* added support for including network information into
+	  EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
+	  (e.g., to implement draft-adrange-eap-network-discovery-07.txt)
+	* fixed a bug which caused some RSN pre-authentication cases to use
+	  freed memory and potentially crash hostapd
+	* fixed private key loading for cases where passphrase is not set
+	* added support for sending TLS alerts and aborting authentication
+	  when receiving a TLS alert
+	* fixed WPA2 to add PMKSA cache entry when using integrated EAP
+	  authenticator
+	* fixed PMKSA caching (EAP authentication was not skipped correctly
+	  with the new state machine changes from IEEE 802.1X draft)
+	* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
+	  and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
+	  to be added to .config to include IPv6 support); for RADIUS server,
+	  radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
+	  in RADIUS clients file can then use IPv6 format
+	* added experimental support for EAP-PAX
+	* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
+	  the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+
+2005-01-23 - v0.3.5
+	* added support for configuring a forced PEAP version based on the
+	  Phase 1 identity
+	* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
+	  to terminate authentication
+	* fixed EAP identifier duplicate processing with the new IEEE 802.1X
+	  draft
+	* clear accounting data in the driver when starting a new accounting
+	  session
+	* driver_madwifi: filter wireless events based on ifindex to allow more
+	  than one network interface to be used
+	* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
+	  setting if the packet does not pass MIC verification (e.g., due to
+	  incorrect PSK); previously, message 1/4 was not tried again if an
+	  invalid message 2/4 was received
+	* fixed reconfiguration of RADIUS client retransmission timer when
+	  adding a new message to the pending list; previously, timer was not
+	  updated at this point and if there was a pending message with long
+	  time for the next retry, the new message needed to wait that long for
+	  its first retry, too
+
+2005-01-09 - v0.3.4
+	* added support for configuring multiple allowed EAP types for Phase 2
+	  authentication (EAP-PEAP, EAP-TTLS)
+	* fixed EAPOL-Start processing to trigger WPA reauthentication
+	  (previously, only EAPOL authentication was done)
+
+2005-01-02 - v0.3.3
+	* added support for EAP-PEAP in the integrated EAP authenticator
+	* added support for EAP-GTC in the integrated EAP authenticator
+	* added support for configuring list of EAP methods for Phase 1 so that
+	  the integrated EAP authenticator can, e.g., use the wildcard entry
+	  for EAP-TLS and EAP-PEAP
+	* added support for EAP-TTLS in the integrated EAP authenticator
+	* added support for EAP-SIM in the integrated EAP authenticator
+	* added support for using hostapd as a RADIUS authentication server
+	  with the integrated EAP authenticator taking care of EAP
+	  authentication (new hostapd.conf options: radius_server_clients and
+	  radius_server_auth_port); this is not included in default build; use
+	  CONFIG_RADIUS_SERVER=y in .config to include
+
+2004-12-19 - v0.3.2
+	* removed 'daemonize' configuration file option since it has not really
+	  been used at all for more than year
+	* driver_madwifi: fixed group key setup and added get_ssid method
+	* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
+
+2004-12-12 - v0.3.1
+	* added support for integrated EAP-TLS authentication (new hostapd.conf
+	  variables: ca_cert, server_cert, private_key, private_key_passwd);
+	  this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
+	  external RADIUS server
+	* added support for reading PKCS#12 (PFX) files (as a replacement for
+	  PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+	* added support for Acct-{Input,Output}-Gigawords
+	* added support for Event-Timestamp (in RADIUS Accounting-Requests)
+	* added support for RADIUS Authentication Client MIB (RFC2618)
+	* added support for RADIUS Accounting Client MIB (RFC2620)
+	* made EAP re-authentication period configurable (eap_reauth_period)
+	* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
+	* fixed EAPOL state machine to stop if STA is removed during
+	  eapol_sm_step(); this fixes at least one segfault triggering bug with
+	  IEEE 802.11i pre-authentication
+	* added support for multiple WPA pre-shared keys (e.g., one for each
+	  client MAC address or keys shared by a group of clients);
+	  new hostapd.conf field wpa_psk_file for setting path to a text file
+	  containing PSKs, see hostapd.wpa_psk for an example
+	* added support for multiple driver interfaces to allow hostapd to be
+	  used with other drivers
+	* added wired authenticator driver interface (driver=wired in
+	  hostapd.conf, see wired.conf for example configuration)
+	* added madwifi driver interface (driver=madwifi in hostapd.conf, see
+	  madwifi.conf for example configuration; Note: include files from
+	  madwifi project is needed for building and a configuration file,
+	  .config, needs to be created in hostapd directory with
+	  CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
+	  build)
+	* fixed an alignment issue that could cause SHA-1 to fail on some
+	  platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
+	  align variables)
+	* fixed RADIUS reconnection after an error in sending interim
+	  accounting packets
+	* added hostapd control interface for external programs and an example
+	  CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
+	* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
+	  'hostapd_cli sta <addr>')
+	* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
+	* added support for strict GTK rekeying (wpa_strict_rekey in
+	  hostapd.conf)
+	* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
+	  (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
+	  IEEE 802.11F-2003)
+	* added Prism54 driver interface (driver=prism54 in hostapd.conf;
+	  note: .config needs to be created in hostapd directory with
+	  CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
+	  build)
+	* dual-licensed hostapd (GPLv2 and BSD licenses)
+	* fixed RADIUS accounting to generate a new session id for cases where
+	  a station reassociates without first being complete deauthenticated
+	* fixed STA disassociation handler to mark next timeout state to
+	  deauthenticate the station, i.e., skip long wait for inactivity poll
+	  and extra disassociation, if the STA disassociates without
+	  deauthenticating
+	* added integrated EAP authenticator that can be used instead of
+	  external RADIUS authentication server; currently, only EAP-MD5 is
+	  supported, so this cannot yet be used for key distribution; the EAP
+	  method interface is generic, though, so adding new EAP methods should
+	  be straightforward; new hostapd.conf variables: 'eap_authenticator'
+	  and 'eap_user_file'; this obsoletes "minimal authentication server"
+	  ('minimal_eap' in hostapd.conf) which is now removed
+	* added support for FreeBSD and driver interface for the BSD net80211
+	  layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
+	  .config); please note that some of the required kernel mods have not
+	  yet been committed
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+	* fixed some accounting cases where Accounting-Start was sent when
+	  IEEE 802.1X port was being deauthorized
+
+2004-06-20 - v0.2.3
+	* modified RADIUS client to re-connect the socket in case of certain
+	  error codes that are generated when a network interface state is
+	  changes (e.g., when IP address changes or the interface is set UP)
+	* fixed couple of cases where EAPOL state for a station was freed
+	  twice causing a segfault for hostapd
+	* fixed couple of bugs in processing WPA deauthentication (freed data
+	  was used)
+
+2004-05-31 - v0.2.2
+	* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
+	* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
+	  cases where STAs dropped multicast frames as replay attacks
+	* added support for copying RADIUS Attribute 'Class' from
+	  authentication messages into accounting messages
+	* send canned EAP failure if RADIUS server sends Access-Reject without
+	  EAP message (previously, Supplicant was not notified in this case)
+	* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
+	  not start EAPOL state machines if the STA selected to use WPA-PSK)
+
+2004-05-06 - v0.2.1
+	* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
+	  - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
+	    (i.e., IEEE 802.11i/D3.0)
+	  - supports WPA-only, RSN-only, and mixed WPA/RSN mode
+	  - both WPA-PSK and WPA-RADIUS/EAP are supported
+	  - PMKSA caching and pre-authentication
+	  - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
+	    wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
+	    rsn_preauth, rsn_preauth_interfaces
+	* fixed interim accounting to remove any pending accounting messages
+	  to the STA before sending a new one
+
+2004-02-15 - v0.2.0
+	* added support for Acct-Interim-Interval:
+	  - draft-ietf-radius-acct-interim-01.txt
+	  - use Acct-Interim-Interval attribute from Access-Accept if local
+	    'radius_acct_interim_interval' is not set
+	  - allow different update intervals for each STA
+	* fixed event loop to call signal handlers only after returning from
+	  the real signal handler
+	* reset sta->timeout_next after successful association to make sure
+	  that the previously registered inactivity timer will not remove the
+	  STA immediately (e.g., if STA deauthenticates and re-associates
+	  before the timer is triggered).
+	* added new hostapd.conf variable, nas_identifier, that can be used to
+	  add an optional RADIUS Attribute, NAS-Identifier, into authentication
+	  and accounting messages
+	* added support for Accounting-On and Accounting-Off messages
+	* fixed accounting session handling to send Accounting-Start only once
+	  per session and not to send Accounting-Stop if the session was not
+	  initialized properly
+	* fixed Accounting-Stop statistics in cases where the message was
+	  previously sent after the kernel entry for the STA (and/or IEEE
+	  802.1X data) was removed
+
+
+Note:
+
+Older changes up to and including v0.1.0 are included in the ChangeLog
+of the Host AP driver.

Deleted: vendor/wpa/2.0/hostapd/Makefile
===================================================================
--- vendor/wpa/dist/hostapd/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,791 +0,0 @@
-ifndef CC
-CC=gcc
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
-
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
-
-# 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_OS
-ifdef CONFIG_NATIVE_WINDOWS
-CONFIG_OS=win32
-else
-CONFIG_OS=unix
-endif
-endif
-
-ifeq ($(CONFIG_OS), internal)
-CFLAGS += -DOS_NO_C_LIB_DEFINES
-endif
-
-ifdef CONFIG_NATIVE_WINDOWS
-CFLAGS += -DCONFIG_NATIVE_WINDOWS
-LIBS += -lws2_32
-endif
-
-OBJS += main.o
-OBJS += config_file.o
-
-OBJS += ../src/ap/hostapd.o
-OBJS += ../src/ap/wpa_auth_glue.o
-OBJS += ../src/ap/drv_callbacks.o
-OBJS += ../src/ap/ap_drv_ops.o
-OBJS += ../src/ap/utils.o
-OBJS += ../src/ap/authsrv.o
-OBJS += ../src/ap/ieee802_1x.o
-OBJS += ../src/ap/ap_config.o
-OBJS += ../src/ap/ieee802_11_auth.o
-OBJS += ../src/ap/sta_info.o
-OBJS += ../src/ap/wpa_auth.o
-OBJS += ../src/ap/tkip_countermeasures.o
-OBJS += ../src/ap/ap_mlme.o
-OBJS += ../src/ap/wpa_auth_ie.o
-OBJS += ../src/ap/preauth_auth.o
-OBJS += ../src/ap/pmksa_cache_auth.o
-
-NEED_RC4=y
-NEED_AES=y
-NEED_MD5=y
-NEED_SHA1=y
-
-OBJS += ../src/drivers/drivers.o
-CFLAGS += -DHOSTAPD
-
-ifdef CONFIG_WPA_TRACE
-CFLAGS += -DWPA_TRACE
-OBJS += ../src/utils/trace.o
-LDFLAGS += -rdynamic
-CFLAGS += -funwind-tables
-ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DWPA_TRACE_BFD
-LIBS += -lbfd
-LIBS_c += -lbfd
-endif
-endif
-
-OBJS += ../src/utils/eloop.o
-OBJS += ../src/utils/common.o
-OBJS += ../src/utils/wpa_debug.o
-OBJS += ../src/utils/wpabuf.o
-OBJS += ../src/utils/os_$(CONFIG_OS).o
-OBJS += ../src/utils/ip_addr.o
-
-OBJS += ../src/common/ieee802_11_common.o
-OBJS += ../src/common/wpa_common.o
-
-OBJS += ../src/eapol_auth/eapol_auth_sm.o
-
-
-ifndef CONFIG_NO_DUMP_STATE
-# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
-# a file (undefine it, if you want to save in binary size)
-CFLAGS += -DHOSTAPD_DUMP_STATE
-OBJS += dump_state.o
-OBJS += ../src/eapol_auth/eapol_auth_dump.o
-endif
-
-ifdef CONFIG_NO_RADIUS
-CFLAGS += -DCONFIG_NO_RADIUS
-CONFIG_NO_ACCOUNTING=y
-else
-OBJS += ../src/radius/radius.o
-OBJS += ../src/radius/radius_client.o
-endif
-
-ifdef CONFIG_NO_ACCOUNTING
-CFLAGS += -DCONFIG_NO_ACCOUNTING
-else
-OBJS += ../src/ap/accounting.o
-endif
-
-ifdef CONFIG_NO_VLAN
-CFLAGS += -DCONFIG_NO_VLAN
-else
-OBJS += ../src/ap/vlan_init.o
-endif
-
-ifdef CONFIG_NO_CTRL_IFACE
-CFLAGS += -DCONFIG_NO_CTRL_IFACE
-else
-OBJS += ctrl_iface.o
-OBJS += ../src/ap/ctrl_iface_ap.o
-endif
-
-OBJS += ../src/crypto/md5.o
-
-CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
-
-ifdef CONFIG_IAPP
-CFLAGS += -DCONFIG_IAPP
-OBJS += ../src/ap/iapp.o
-endif
-
-ifdef CONFIG_RSN_PREAUTH
-CFLAGS += -DCONFIG_RSN_PREAUTH
-CONFIG_L2_PACKET=y
-endif
-
-ifdef CONFIG_PEERKEY
-CFLAGS += -DCONFIG_PEERKEY
-OBJS += ../src/ap/peerkey_auth.o
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-endif
-
-ifdef CONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211R
-OBJS += ../src/ap/wpa_auth_ft.o
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-NEED_AES_UNWRAP=y
-endif
-
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
-endif
-
-include ../src/drivers/drivers.mak
-OBJS += $(DRV_AP_OBJS)
-CFLAGS += $(DRV_AP_CFLAGS)
-LDFLAGS += $(DRV_AP_LDFLAGS)
-LIBS += $(DRV_AP_LIBS)
-
-ifdef CONFIG_L2_PACKET
-ifdef CONFIG_DNET_PCAP
-ifdef CONFIG_L2_FREEBSD
-LIBS += -lpcap
-OBJS += ../src/l2_packet/l2_packet_freebsd.o
-else
-LIBS += -ldnet -lpcap
-OBJS += ../src/l2_packet/l2_packet_pcap.o
-endif
-else
-OBJS += ../src/l2_packet/l2_packet_linux.o
-endif
-else
-OBJS += ../src/l2_packet/l2_packet_none.o
-endif
-
-
-ifdef CONFIG_EAP_MD5
-CFLAGS += -DEAP_SERVER_MD5
-OBJS += ../src/eap_server/eap_server_md5.o
-CHAP=y
-endif
-
-ifdef CONFIG_EAP_TLS
-CFLAGS += -DEAP_SERVER_TLS
-OBJS += ../src/eap_server/eap_server_tls.o
-TLS_FUNCS=y
-endif
-
-ifdef CONFIG_EAP_PEAP
-CFLAGS += -DEAP_SERVER_PEAP
-OBJS += ../src/eap_server/eap_server_peap.o
-OBJS += ../src/eap_common/eap_peap_common.o
-TLS_FUNCS=y
-CONFIG_EAP_MSCHAPV2=y
-endif
-
-ifdef CONFIG_EAP_TTLS
-CFLAGS += -DEAP_SERVER_TTLS
-OBJS += ../src/eap_server/eap_server_ttls.o
-TLS_FUNCS=y
-CHAP=y
-endif
-
-ifdef CONFIG_EAP_MSCHAPV2
-CFLAGS += -DEAP_SERVER_MSCHAPV2
-OBJS += ../src/eap_server/eap_server_mschapv2.o
-MS_FUNCS=y
-endif
-
-ifdef CONFIG_EAP_GTC
-CFLAGS += -DEAP_SERVER_GTC
-OBJS += ../src/eap_server/eap_server_gtc.o
-endif
-
-ifdef CONFIG_EAP_SIM
-CFLAGS += -DEAP_SERVER_SIM
-OBJS += ../src/eap_server/eap_server_sim.o
-CONFIG_EAP_SIM_COMMON=y
-NEED_AES_CBC=y
-endif
-
-ifdef CONFIG_EAP_AKA
-CFLAGS += -DEAP_SERVER_AKA
-OBJS += ../src/eap_server/eap_server_aka.o
-CONFIG_EAP_SIM_COMMON=y
-NEED_SHA256=y
-NEED_AES_CBC=y
-endif
-
-ifdef CONFIG_EAP_AKA_PRIME
-CFLAGS += -DEAP_SERVER_AKA_PRIME
-endif
-
-ifdef CONFIG_EAP_SIM_COMMON
-OBJS += ../src/eap_common/eap_sim_common.o
-# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
-# replaced with another file implementating the interface specified in
-# eap_sim_db.h.
-OBJS += ../src/eap_server/eap_sim_db.o
-NEED_FIPS186_2_PRF=y
-endif
-
-ifdef CONFIG_EAP_PAX
-CFLAGS += -DEAP_SERVER_PAX
-OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o
-endif
-
-ifdef CONFIG_EAP_PSK
-CFLAGS += -DEAP_SERVER_PSK
-OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
-NEED_AES_OMAC1=y
-NEED_AES_ENCBLOCK=y
-NEED_AES_EAX=y
-endif
-
-ifdef CONFIG_EAP_SAKE
-CFLAGS += -DEAP_SERVER_SAKE
-OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o
-endif
-
-ifdef CONFIG_EAP_GPSK
-CFLAGS += -DEAP_SERVER_GPSK
-OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
-ifdef CONFIG_EAP_GPSK_SHA256
-CFLAGS += -DEAP_SERVER_GPSK_SHA256
-endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-endif
-
-ifdef CONFIG_EAP_VENDOR_TEST
-CFLAGS += -DEAP_SERVER_VENDOR_TEST
-OBJS += ../src/eap_server/eap_server_vendor_test.o
-endif
-
-ifdef CONFIG_EAP_FAST
-CFLAGS += -DEAP_SERVER_FAST
-OBJS += ../src/eap_server/eap_server_fast.o
-OBJS += ../src/eap_common/eap_fast_common.o
-TLS_FUNCS=y
-NEED_T_PRF=y
-NEED_AES_UNWRAP=y
-endif
-
-ifdef CONFIG_WPS
-CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
-OBJS += ../src/utils/uuid.o
-OBJS += ../src/ap/wps_hostapd.o
-OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o
-OBJS += ../src/wps/wps.o
-OBJS += ../src/wps/wps_common.o
-OBJS += ../src/wps/wps_attr_parse.o
-OBJS += ../src/wps/wps_attr_build.o
-OBJS += ../src/wps/wps_attr_process.o
-OBJS += ../src/wps/wps_dev_attr.o
-OBJS += ../src/wps/wps_enrollee.o
-OBJS += ../src/wps/wps_registrar.o
-NEED_DH_GROUPS=y
-NEED_SHA256=y
-NEED_BASE64=y
-NEED_AES_CBC=y
-NEED_MODEXP=y
-CONFIG_EAP=y
-
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
-ifdef CONFIG_WPS_NFC
-CFLAGS += -DCONFIG_WPS_NFC
-OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
-NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
-endif
-
-ifdef NEED_WPS_OOB
-CFLAGS += -DCONFIG_WPS_OOB
-endif
-
-ifdef CONFIG_WPS_UPNP
-CFLAGS += -DCONFIG_WPS_UPNP
-OBJS += ../src/wps/wps_upnp.o
-OBJS += ../src/wps/wps_upnp_ssdp.o
-OBJS += ../src/wps/wps_upnp_web.o
-OBJS += ../src/wps/wps_upnp_event.o
-OBJS += ../src/wps/wps_upnp_ap.o
-OBJS += ../src/wps/upnp_xml.o
-OBJS += ../src/wps/httpread.o
-OBJS += ../src/wps/http_client.o
-OBJS += ../src/wps/http_server.o
-endif
-
-endif
-
-ifdef CONFIG_EAP_IKEV2
-CFLAGS += -DEAP_SERVER_IKEV2
-OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
-OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
-NEED_DH_GROUPS=y
-NEED_DH_GROUPS_ALL=y
-NEED_MODEXP=y
-NEED_CIPHER=y
-endif
-
-ifdef CONFIG_EAP_TNC
-CFLAGS += -DEAP_SERVER_TNC
-OBJS += ../src/eap_server/eap_server_tnc.o
-OBJS += ../src/eap_server/tncs.o
-NEED_BASE64=y
-ifndef CONFIG_DRIVER_BSD
-LIBS += -ldl
-endif
-endif
-
-# Basic EAP functionality is needed for EAPOL
-OBJS += eap_register.o
-OBJS += ../src/eap_server/eap_server.o
-OBJS += ../src/eap_common/eap_common.o
-OBJS += ../src/eap_server/eap_server_methods.o
-OBJS += ../src/eap_server/eap_server_identity.o
-CFLAGS += -DEAP_SERVER_IDENTITY
-
-ifdef CONFIG_EAP
-CFLAGS += -DEAP_SERVER
-endif
-
-ifdef CONFIG_PKCS12
-CFLAGS += -DPKCS12_FUNCS
-endif
-
-ifdef MS_FUNCS
-OBJS += ../src/crypto/ms_funcs.o
-NEED_DES=y
-NEED_MD4=y
-endif
-
-ifdef CHAP
-OBJS += ../src/eap_common/chap.o
-endif
-
-ifdef TLS_FUNCS
-NEED_DES=y
-# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
-CFLAGS += -DEAP_TLS_FUNCS
-OBJS += ../src/eap_server/eap_server_tls_common.o
-NEED_TLS_PRF=y
-endif
-
-ifndef CONFIG_TLS
-CONFIG_TLS=openssl
-endif
-
-ifeq ($(CONFIG_TLS), openssl)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_openssl.o
-LIBS += -lssl
-endif
-OBJS += ../src/crypto/crypto_openssl.o
-HOBJS += ../src/crypto/crypto_openssl.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_openssl.o
-endif
-LIBS += -lcrypto
-LIBS_h += -lcrypto
-endif
-
-ifeq ($(CONFIG_TLS), gnutls)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_gnutls.o
-LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
-endif
-OBJS += ../src/crypto/crypto_gnutls.o
-HOBJS += ../src/crypto/crypto_gnutls.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_gnutls.o
-endif
-LIBS += -lgcrypt
-LIBS_h += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_schannel.o
-endif
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_nss.o
-endif
-LIBS += -lnss3
-LIBS_h += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), internal)
-ifndef CONFIG_CRYPTO
-CONFIG_CRYPTO=internal
-endif
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/crypto_internal-rsa.o
-OBJS += ../src/crypto/tls_internal.o
-OBJS += ../src/tls/tlsv1_common.o
-OBJS += ../src/tls/tlsv1_record.o
-OBJS += ../src/tls/tlsv1_cred.o
-OBJS += ../src/tls/tlsv1_server.o
-OBJS += ../src/tls/tlsv1_server_write.o
-OBJS += ../src/tls/tlsv1_server_read.o
-OBJS += ../src/tls/asn1.o
-OBJS += ../src/tls/rsa.o
-OBJS += ../src/tls/x509v3.o
-OBJS += ../src/tls/pkcs1.o
-OBJS += ../src/tls/pkcs5.o
-OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
-NEED_BASE64=y
-NEED_TLS_PRF=y
-NEED_MODEXP=y
-NEED_CIPHER=y
-CFLAGS += -DCONFIG_TLS_INTERNAL
-CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
-endif
-ifdef NEED_CIPHER
-NEED_DES=y
-OBJS += ../src/crypto/crypto_internal-cipher.o
-endif
-ifdef NEED_MODEXP
-OBJS += ../src/crypto/crypto_internal-modexp.o
-OBJS += ../src/tls/bignum.o
-endif
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS += ../src/crypto/crypto_libtomcrypt.o
-LIBS += -ltomcrypt -ltfm
-LIBS_h += -ltomcrypt -ltfm
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-ifeq ($(CONFIG_CRYPTO), internal)
-OBJS += ../src/crypto/crypto_internal.o
-NEED_AES_DEC=y
-CFLAGS += -DCONFIG_CRYPTO_INTERNAL
-ifdef CONFIG_INTERNAL_LIBTOMMATH
-CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
-ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
-CFLAGS += -DLTM_FAST
-endif
-else
-LIBS += -ltommath
-LIBS_h += -ltommath
-endif
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_DES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_MD5=y
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-ifeq ($(CONFIG_CRYPTO), cryptoapi)
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-endif
-endif
-
-ifeq ($(CONFIG_TLS), none)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_none.o
-CFLAGS += -DEAP_TLS_NONE
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD5=y
-endif
-OBJS += ../src/crypto/crypto_none.o
-OBJS_p += ../src/crypto/crypto_none.o
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-endif
-
-ifndef TLS_FUNCS
-OBJS += ../src/crypto/tls_none.o
-ifeq ($(CONFIG_TLS), internal)
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD5=y
-CONFIG_INTERNAL_RC4=y
-endif
-endif
-
-AESOBJS = # none so far
-ifdef CONFIG_INTERNAL_AES
-AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
-endif
-
-AESOBJS += ../src/crypto/aes-wrap.o
-ifdef NEED_AES_EAX
-AESOBJS += ../src/crypto/aes-eax.o
-NEED_AES_CTR=y
-endif
-ifdef NEED_AES_CTR
-AESOBJS += ../src/crypto/aes-ctr.o
-endif
-ifdef NEED_AES_ENCBLOCK
-AESOBJS += ../src/crypto/aes-encblock.o
-endif
-ifdef NEED_AES_OMAC1
-AESOBJS += ../src/crypto/aes-omac1.o
-endif
-ifdef NEED_AES_UNWRAP
-NEED_AES_DEC=y
-AESOBJS += ../src/crypto/aes-unwrap.o
-endif
-ifdef NEED_AES_CBC
-NEED_AES_DEC=y
-AESOBJS += ../src/crypto/aes-cbc.o
-endif
-ifdef NEED_AES_DEC
-ifdef CONFIG_INTERNAL_AES
-AESOBJS += ../src/crypto/aes-internal-dec.o
-endif
-endif
-ifdef NEED_AES
-OBJS += $(AESOBJS)
-endif
-
-ifdef NEED_SHA1
-SHA1OBJS += ../src/crypto/sha1.o
-ifdef CONFIG_INTERNAL_SHA1
-SHA1OBJS += ../src/crypto/sha1-internal.o
-ifdef NEED_FIPS186_2_PRF
-SHA1OBJS += ../src/crypto/fips_prf_internal.o
-endif
-endif
-SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
-ifdef NEED_T_PRF
-SHA1OBJS += ../src/crypto/sha1-tprf.o
-endif
-ifdef NEED_TLS_PRF
-SHA1OBJS += ../src/crypto/sha1-tlsprf.o
-endif
-endif
-
-ifdef NEED_SHA1
-OBJS += $(SHA1OBJS)
-endif
-
-ifdef NEED_MD5
-ifdef CONFIG_INTERNAL_MD5
-OBJS += ../src/crypto/md5-internal.o
-endif
-endif
-
-ifdef NEED_MD4
-ifdef CONFIG_INTERNAL_MD4
-OBJS += ../src/crypto/md4-internal.o
-endif
-endif
-
-ifdef NEED_DES
-ifdef CONFIG_INTERNAL_DES
-OBJS += ../src/crypto/des-internal.o
-endif
-endif
-
-ifdef NEED_RC4
-ifdef CONFIG_INTERNAL_RC4
-OBJS += ../src/crypto/rc4.o
-endif
-endif
-
-ifdef NEED_SHA256
-OBJS += ../src/crypto/sha256.o
-ifdef CONFIG_INTERNAL_SHA256
-OBJS += ../src/crypto/sha256-internal.o
-endif
-endif
-
-ifdef NEED_DH_GROUPS
-OBJS += ../src/crypto/dh_groups.o
-endif
-ifdef NEED_DH_GROUPS_ALL
-CFLAGS += -DALL_DH_GROUPS
-endif
-ifdef CONFIG_INTERNAL_DH_GROUP5
-ifdef NEED_DH_GROUPS
-OBJS += ../src/crypto/dh_group5.o
-endif
-endif
-
-ifdef CONFIG_RADIUS_SERVER
-CFLAGS += -DRADIUS_SERVER
-OBJS += ../src/radius/radius_server.o
-endif
-
-ifdef CONFIG_IPV6
-CFLAGS += -DCONFIG_IPV6
-endif
-
-ifdef CONFIG_DRIVER_RADIUS_ACL
-CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
-endif
-
-ifdef 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
-
-ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
-OBJS += ../src/ap/wmm.o
-OBJS += ../src/ap/ap_list.o
-OBJS += ../src/ap/ieee802_11.o
-OBJS += ../src/ap/hw_features.o
-CFLAGS += -DNEED_AP_MLME
-endif
-ifdef CONFIG_IEEE80211N
-OBJS += ../src/ap/ieee802_11_ht.o
-endif
-
-ifdef CONFIG_NO_STDOUT_DEBUG
-CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
-endif
-
-ALL=hostapd hostapd_cli
-
-all: verify_config $(ALL)
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-
-%.o: %.c
-	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
-	@$(E) "  CC " $<
-
-verify_config:
-	@if [ ! -r .config ]; then \
-		echo 'Building hostapd requires a configuration file'; \
-		echo '(.config). See README for more instructions. You can'; \
-		echo 'run "cp defconfig .config" to create an example'; \
-		echo 'configuration.'; \
-		exit 1; \
-	fi
-
-install: all
-	for i in $(ALL); do cp -f $$i /usr/local/bin/$$i; done
-
-../src/drivers/build.hostapd:
-	@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
-		$(MAKE) -C ../src/drivers clean; \
-	fi
-	@touch ../src/drivers/build.hostapd
-
-BCHECK=../src/drivers/build.hostapd
-
-hostapd: $(BCHECK) $(OBJS)
-	$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
-
-OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
-ifdef CONFIG_WPA_TRACE
-OBJS_c += ../src/utils/trace.o
-OBJS_c += ../src/utils/wpa_debug.o
-endif
-hostapd_cli: $(OBJS_c)
-	$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
-
-NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
-ifdef NEED_RC4
-ifdef CONFIG_INTERNAL_RC4
-NOBJS += ../src/crypto/rc4.o
-endif
-endif
-ifdef CONFIG_INTERNAL_MD5
-NOBJS += ../src/crypto/md5-internal.o
-endif
-NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
-NOBJS += ../src/utils/wpa_debug.o
-NOBJS += ../src/utils/wpabuf.o
-ifdef CONFIG_WPA_TRACE
-NOBJS += ../src/utils/trace.o
-LIBS_n += -lbfd
-endif
-ifdef TLS_FUNCS
-LIBS_n += -lcrypto
-endif
-
-HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
-HOBJS += ../src/crypto/aes-encblock.o
-ifdef CONFIG_INTERNAL_AES
-HOBJS += ../src/crypto/aes-internal.o
-HOBJS += ../src/crypto/aes-internal-enc.o
-endif
-
-nt_password_hash: $(NOBJS)
-	$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
-
-hlr_auc_gw: $(HOBJS)
-	$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
-
-clean:
-	$(MAKE) -C ../src clean
-	rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
-	rm -f *.d
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/hostapd/Makefile (from rev 9639, vendor/wpa/dist/hostapd/Makefile)
===================================================================
--- vendor/wpa/2.0/hostapd/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,907 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+# 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_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS += main.o
+OBJS += config_file.o
+
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/preauth_auth.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/beacon.o
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += ../src/drivers/drivers.o
+CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+HOBJS += ../src/utils/trace.o
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += dump_state.o
+OBJS += ../src/eapol_auth/eapol_auth_dump.o
+endif
+
+ifdef CONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += ../src/ap/accounting.o
+endif
+
+ifdef CONFIG_NO_VLAN
+CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += ../src/ap/vlan_init.o
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_util.o
+endif
+CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += ctrl_iface.o
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+OBJS += ../src/crypto/md5.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += ../src/ap/iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+OBJS += ../src/ap/peerkey_auth.o
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/ap/wpa_auth_ft.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
+
+ifdef CONFIG_IEEE80211N
+CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
+include ../src/drivers/drivers.mak
+OBJS += $(DRV_AP_OBJS)
+CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_none.o
+endif
+
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_SERVER_MD5
+OBJS += ../src/eap_server/eap_server_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_SERVER_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_SERVER_PEAP
+OBJS += ../src/eap_server/eap_server_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_SERVER_TTLS
+OBJS += ../src/eap_server/eap_server_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += ../src/eap_server/eap_server_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_SERVER_GTC
+OBJS += ../src/eap_server/eap_server_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SERVER_SIM
+OBJS += ../src/eap_server/eap_server_sim.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_SERVER_AKA
+OBJS += ../src/eap_server/eap_server_aka.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += ../src/eap_server/eap_sim_db.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_SERVER_PAX
+OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_SERVER_PSK
+OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SERVER_SAKE
+OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_SERVER_GPSK
+OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_SERVER_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_SERVER_PWD
+OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += ../src/eap_server/eap_server_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_SERVER_FAST
+OBJS += ../src/eap_server/eap_server_fast.o
+OBJS += ../src/eap_common/eap_fast_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
+CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+CFLAGS += -DEAP_SERVER_TNC
+OBJS += ../src/eap_server/eap_server_tnc.o
+OBJS += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.o
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_server_methods.o
+OBJS += ../src/eap_server/eap_server_identity.o
+CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_server_tls_common.o
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_gnutls.o
+HOBJS += ../src/crypto/crypto_gnutls.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_gnutls.o
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_schannel.o
+endif
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_nss.o
+LIBS += -lssl3
+endif
+OBJS += ../src/crypto/crypto_nss.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_nss.o
+endif
+LIBS += -lnss3
+LIBS_h += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o
+OBJS += ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/asn1.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+NEED_AES_DEC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
+endif
+
+AESOBJS += ../src/crypto/aes-wrap.o
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+ifdef NEED_AES_UNWRAP
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-unwrap.o
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-dec.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += ../src/crypto/md5-internal.o
+HOBJS += ../src/crypto/md5-internal.o
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += ../src/crypto/des-internal.o
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += ../src/crypto/rc4.o
+endif
+endif
+
+ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/sha256.o
+endif
+OBJS += ../src/crypto/sha256-prf.o
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+HOBJS += ../src/crypto/random.o
+HOBJS += ../src/utils/eloop.o
+HOBJS += $(SHA1OBJS)
+HOBJS += ../src/crypto/md5.o
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef 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
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
+
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
+ifdef CONFIG_P2P_MANAGER
+CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += ../src/ap/p2p_hostapd.o
+endif
+
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+CFLAGS += -DCONFIG_INTERWORKING
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+verify_config:
+	@if [ ! -r .config ]; then \
+		echo 'Building hostapd requires a configuration file'; \
+		echo '(.config). See README for more instructions. You can'; \
+		echo 'run "cp defconfig .config" to create an example'; \
+		echo 'configuration.'; \
+		exit 1; \
+	fi
+
+install: all
+	mkdir -p $(DESTDIR)/usr/local/bin
+	for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+
+../src/drivers/build.hostapd:
+	@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
+		$(MAKE) -C ../src/drivers clean; \
+	fi
+	@touch ../src/drivers/build.hostapd
+
+BCHECK=../src/drivers/build.hostapd
+
+hostapd: $(BCHECK) $(OBJS)
+	$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
+	@$(E) "  LD " $@
+
+ifdef CONFIG_WPA_TRACE
+OBJS_c += ../src/utils/trace.o
+endif
+hostapd_cli: $(OBJS_c)
+	$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
+	@$(E) "  LD " $@
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+NOBJS += ../src/crypto/rc4.o
+endif
+endif
+ifdef CONFIG_INTERNAL_MD5
+NOBJS += ../src/crypto/md5-internal.o
+endif
+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/utils/wpa_debug.o
+NOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+NOBJS += ../src/utils/trace.o
+LIBS_n += -lbfd
+endif
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
+HOBJS += ../src/crypto/aes-encblock.o
+ifdef CONFIG_INTERNAL_AES
+HOBJS += ../src/crypto/aes-internal.o
+HOBJS += ../src/crypto/aes-internal-enc.o
+endif
+
+nt_password_hash: $(NOBJS)
+	$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
+	@$(E) "  LD " $@
+
+hlr_auc_gw: $(HOBJS)
+	$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+	@$(E) "  LD " $@
+
+clean:
+	$(MAKE) -C ../src clean
+	rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+	rm -f *.d
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/hostapd/README
===================================================================
--- vendor/wpa/dist/hostapd/README	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,387 +0,0 @@
-hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
-	  Authenticator and RADIUS authentication server
-================================================================
-
-Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi> and contributors
-All Rights Reserved.
-
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-
-
-License
--------
-
-GPL v2:
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-(this copy of the license is in COPYING file)
-
-
-Alternatively, this software may be distributed, used, and modified
-under the terms of BSD license:
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name(s) of the above-listed copyright holder(s) nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-Introduction
-============
-
-Originally, hostapd was an optional user space component for Host AP
-driver. It adds more features to the basic IEEE 802.11 management
-included in the kernel driver: using external RADIUS authentication
-server for MAC address based access control, IEEE 802.1X Authenticator
-and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
-Authenticator and dynamic TKIP/CCMP keying.
-
-The current version includes support for other drivers, an integrated
-EAP server (i.e., allow full authentication without requiring
-an external RADIUS authentication server), and RADIUS authentication
-server for EAP authentication.
-
-
-Requirements
-------------
-
-Current hardware/software requirements:
-- drivers:
-	Host AP driver for Prism2/2.5/3.
-	(http://hostap.epitest.fi/)
-	Please note that station firmware version needs to be 1.7.0 or newer
-	to work in WPA mode.
-
-	madwifi driver for cards based on Atheros chip set (ar521x)
-	(http://sourceforge.net/projects/madwifi/)
-	Please note that you will need to add the correct path for
-	madwifi driver root directory in .config (see defconfig file for
-	an example: CFLAGS += -I<path>)
-
-	mac80211-based drivers that support AP mode (with driver=nl80211).
-	This includes drivers for Atheros (ath9k) and Broadcom (b43)
-	chipsets.
-
-	Any wired Ethernet driver for wired IEEE 802.1X authentication
-	(experimental code)
-
-	FreeBSD -current (with some kernel mods that have not yet been
-	committed when hostapd v0.3.0 was released)
-	BSD net80211 layer (e.g., Atheros driver)
-
-
-Build configuration
--------------------
-
-In order to be able to build hostapd, you will need to create a build
-time configuration file, .config that selects which optional
-components are included. See defconfig file for example configuration
-and list of available options.
-
-
-
-IEEE 802.1X
-===========
-
-IEEE Std 802.1X-2001 is a standard for port-based network access
-control. In case of IEEE 802.11 networks, a "virtual port" is used
-between each associated station and the AP. IEEE 802.11 specifies
-minimal authentication mechanism for stations, whereas IEEE 802.1X
-introduces a extensible mechanism for authenticating and authorizing
-users.
-
-IEEE 802.1X uses elements called Supplicant, Authenticator, Port
-Access Entity, and Authentication Server. Supplicant is a component in
-a station and it performs the authentication with the Authentication
-Server. An access point includes an Authenticator that relays the packets
-between a Supplicant and an Authentication Server. In addition, it has a
-Port Access Entity (PAE) with Authenticator functionality for
-controlling the virtual port authorization, i.e., whether to accept
-packets from or to the station.
-
-IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
-between a Supplicant and an Authenticator are sent using EAP over LAN
-(EAPOL) and the Authenticator relays these frames to the Authentication
-Server (and similarly, relays the messages from the Authentication
-Server to the Supplicant). The Authentication Server can be colocated with the
-Authenticator, in which case there is no need for additional protocol
-for EAP frame transmission. However, a more common configuration is to
-use an external Authentication Server and encapsulate EAP frame in the
-frames used by that server. RADIUS is suitable for this, but IEEE
-802.1X would also allow other mechanisms.
-
-Host AP driver includes PAE functionality in the kernel driver. It
-is a relatively simple mechanism for denying normal frames going to
-or coming from an unauthorized port. PAE allows IEEE 802.1X related
-frames to be passed between the Supplicant and the Authenticator even
-on an unauthorized port.
-
-User space daemon, hostapd, includes Authenticator functionality. It
-receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
-device that is also used with IEEE 802.11 management frames. The
-frames to the Supplicant are sent using the same device.
-
-The normal configuration of the Authenticator would use an external
-Authentication Server. hostapd supports RADIUS encapsulation of EAP
-packets, so the Authentication Server should be a RADIUS server, like
-FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
-relays the frames between the Supplicant and the Authentication
-Server. It also controls the PAE functionality in the kernel driver by
-controlling virtual port authorization, i.e., station-AP
-connection, based on the IEEE 802.1X state.
-
-When a station would like to use the services of an access point, it
-will first perform IEEE 802.11 authentication. This is normally done
-with open systems authentication, so there is no security. After
-this, IEEE 802.11 association is performed. If IEEE 802.1X is
-configured to be used, the virtual port for the station is set in
-Unauthorized state and only IEEE 802.1X frames are accepted at this
-point. The Authenticator will then ask the Supplicant to authenticate
-with the Authentication Server. After this is completed successfully,
-the virtual port is set to Authorized state and frames from and to the
-station are accepted.
-
-Host AP configuration for IEEE 802.1X
--------------------------------------
-
-The user space daemon has its own configuration file that can be used to
-define AP options. Distribution package contains an example
-configuration file (hostapd/hostapd.conf) that can be used as a basis
-for configuration. It includes examples of all supported configuration
-options and short description of each option. hostapd should be started
-with full path to the configuration file as the command line argument,
-e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
-LAN card, you can use one hostapd process for multiple interfaces by
-giving a list of configuration files (one per interface) in the command
-line.
-
-hostapd includes a minimal co-located IEEE 802.1X server which can be
-used to test IEEE 802.1X authentication. However, it should not be
-used in normal use since it does not provide any security. This can be
-configured by setting ieee8021x and minimal_eap options in the
-configuration file.
-
-An external Authentication Server (RADIUS) is configured with
-auth_server_{addr,port,shared_secret} options. In addition,
-ieee8021x and own_ip_addr must be set for this mode. With such
-configuration, the co-located Authentication Server is not used and EAP
-frames will be relayed using EAPOL between the Supplicant and the
-Authenticator and RADIUS encapsulation between the Authenticator and
-the Authentication Server. Other than this, the functionality is similar
-to the case with the co-located Authentication Server.
-
-Authentication Server and Supplicant
-------------------------------------
-
-Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
-Authentication Server with hostapd Authenticator. FreeRADIUS
-(http://www.freeradius.org/) has been successfully tested with hostapd
-Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
-XP Supplicants. EAP/TLS was used with Xsupplicant and
-EAP/MD5-Challenge with Windows XP.
-
-http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
-about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
-Cisco access point with Host AP driver, hostapd daemon, and a Prism2
-card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
-about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
-configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
-EAP/TLS use with WinXP Supplicant.
-
-Automatic WEP key configuration
--------------------------------
-
-EAP/TLS generates a session key that can be used to send WEP keys from
-an AP to authenticated stations. The Authenticator in hostapd can be
-configured to automatically select a random default/broadcast key
-(shared by all authenticated stations) with wep_key_len_broadcast
-option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
-wep_key_len_unicast option can be used to configure individual unicast
-keys for stations. This requires support for individual keys in the
-station driver.
-
-WEP keys can be automatically updated by configuring rekeying. This
-will improve security of the network since same WEP key will only be
-used for a limited period of time. wep_rekey_period option sets the
-interval for rekeying in seconds.
-
-
-WPA/WPA2
-========
-
-Features
---------
-
-Supported WPA/IEEE 802.11i features:
-- WPA-PSK ("WPA-Personal")
-- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
-- key management for CCMP, TKIP, WEP104, WEP40
-- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
-
-WPA
----
-
-The original security mechanism of IEEE 802.11 standard was not
-designed to be strong and has proved to be insufficient for most
-networks that require some kind of security. Task group I (Security)
-of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
-to address the flaws of the base standard and has in practice
-completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
-802.11 standard was approved in June 2004 and this amendment is likely
-to be published in July 2004.
-
-Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
-IEEE 802.11i work (draft 3.0) to define a subset of the security
-enhancements that can be implemented with existing wlan hardware. This
-is called Wi-Fi Protected Access<TM> (WPA). This has now become a
-mandatory component of interoperability testing and certification done
-by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
-site (http://www.wi-fi.org/OpenSection/protected_access.asp).
-
-IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
-for protecting wireless networks. WEP uses RC4 with 40-bit keys,
-24-bit initialization vector (IV), and CRC32 to protect against packet
-forgery. All these choices have proven to be insufficient: key space is
-too small against current attacks, RC4 key scheduling is insufficient
-(beginning of the pseudorandom stream should be skipped), IV space is
-too small and IV reuse makes attacks easier, there is no replay
-protection, and non-keyed authentication does not protect against bit
-flipping packet data.
-
-WPA is an intermediate solution for the security issues. It uses
-Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
-compromise on strong security and possibility to use existing
-hardware. It still uses RC4 for the encryption like WEP, but with
-per-packet RC4 keys. In addition, it implements replay protection,
-keyed packet authentication mechanism (Michael MIC).
-
-Keys can be managed using two different mechanisms. WPA can either use
-an external authentication server (e.g., RADIUS) and EAP just like
-IEEE 802.1X is using or pre-shared keys without need for additional
-servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
-respectively. Both mechanisms will generate a master session key for
-the Authenticator (AP) and Supplicant (client station).
-
-WPA implements a new key handshake (4-Way Handshake and Group Key
-Handshake) for generating and exchanging data encryption keys between
-the Authenticator and Supplicant. This handshake is also used to
-verify that both Authenticator and Supplicant know the master session
-key. These handshakes are identical regardless of the selected key
-management mechanism (only the method for generating master session
-key changes).
-
-
-IEEE 802.11i / WPA2
--------------------
-
-The design for parts of IEEE 802.11i that were not included in WPA has
-finished (May 2004) and this amendment to IEEE 802.11 was approved in
-June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
-version of WPA called WPA2. This includes, e.g., support for more
-robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
-to replace TKIP and optimizations for handoff (reduced number of
-messages in initial key handshake, pre-authentication, and PMKSA caching).
-
-Some wireless LAN vendors are already providing support for CCMP in
-their WPA products. There is no "official" interoperability
-certification for CCMP and/or mixed modes using both TKIP and CCMP, so
-some interoperability issues can be expected even though many
-combinations seem to be working with equipment from different vendors.
-Testing for WPA2 is likely to start during the second half of 2004.
-
-hostapd configuration for WPA/WPA2
-----------------------------------
-
-TODO
-
-# Enable WPA. Setting this variable configures the AP to require WPA (either
-# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
-# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
-# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
-# RADIUS authentication server must be configured, and WPA-EAP must be included
-# in wpa_key_mgmt.
-# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
-# and/or WPA2 (full IEEE 802.11i/RSN):
-# bit0 = WPA
-# bit1 = IEEE 802.11i/RSN (WPA2)
-#wpa=1
-
-# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
-# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
-# (8..63 characters) that will be converted to PSK. This conversion uses SSID
-# so the PSK changes when ASCII passphrase is used and the SSID is changed.
-#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
-#wpa_passphrase=secret passphrase
-
-# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
-# entries are separated with a space.
-#wpa_key_mgmt=WPA-PSK WPA-EAP
-
-# Set of accepted cipher suites (encryption algorithms) for pairwise keys
-# (unicast packets). This is a space separated list of algorithms:
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
-# Group cipher suite (encryption algorithm for broadcast and multicast frames)
-# is automatically selected based on this configuration. If only CCMP is
-# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
-# TKIP will be used as the group cipher.
-#wpa_pairwise=TKIP CCMP
-
-# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
-# seconds.
-#wpa_group_rekey=600
-
-# Time interval for rekeying GMK (master key used internally to generate GTKs
-# (in seconds).
-#wpa_gmk_rekey=86400
-
-# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
-# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
-# authentication and key handshake before actually associating with a new AP.
-#rsn_preauth=1
-#
-# Space separated list of interfaces from which pre-authentication frames are
-# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
-# interface that are used for connections to other APs. This could include
-# wired interfaces and WDS links. The normal wireless data interface towards
-# associated stations (e.g., wlan0) should not be added, since
-# pre-authentication is only used with APs other than the currently associated
-# one.
-#rsn_preauth_interfaces=eth0

Copied: vendor/wpa/2.0/hostapd/README (from rev 9639, vendor/wpa/dist/hostapd/README)
===================================================================
--- vendor/wpa/2.0/hostapd/README	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,372 @@
+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
+	  Authenticator and RADIUS authentication server
+================================================================
+
+Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi> and contributors
+All Rights Reserved.
+
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Introduction
+============
+
+Originally, hostapd was an optional user space component for Host AP
+driver. It adds more features to the basic IEEE 802.11 management
+included in the kernel driver: using external RADIUS authentication
+server for MAC address based access control, IEEE 802.1X Authenticator
+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
+Authenticator and dynamic TKIP/CCMP keying.
+
+The current version includes support for other drivers, an integrated
+EAP server (i.e., allow full authentication without requiring
+an external RADIUS authentication server), and RADIUS authentication
+server for EAP authentication.
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- drivers:
+	Host AP driver for Prism2/2.5/3.
+	(http://hostap.epitest.fi/)
+	Please note that station firmware version needs to be 1.7.0 or newer
+	to work in WPA mode.
+
+	madwifi driver for cards based on Atheros chip set (ar521x)
+	(http://sourceforge.net/projects/madwifi/)
+	Please note that you will need to add the correct path for
+	madwifi driver root directory in .config (see defconfig file for
+	an example: CFLAGS += -I<path>)
+
+	mac80211-based drivers that support AP mode (with driver=nl80211).
+	This includes drivers for Atheros (ath9k) and Broadcom (b43)
+	chipsets.
+
+	Any wired Ethernet driver for wired IEEE 802.1X authentication
+	(experimental code)
+
+	FreeBSD -current (with some kernel mods that have not yet been
+	committed when hostapd v0.3.0 was released)
+	BSD net80211 layer (e.g., Atheros driver)
+
+
+Build configuration
+-------------------
+
+In order to be able to build hostapd, you will need to create a build
+time configuration file, .config that selects which optional
+components are included. See defconfig file for example configuration
+and list of available options.
+
+
+
+IEEE 802.1X
+===========
+
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. In case of IEEE 802.11 networks, a "virtual port" is used
+between each associated station and the AP. IEEE 802.11 specifies
+minimal authentication mechanism for stations, whereas IEEE 802.1X
+introduces a extensible mechanism for authenticating and authorizing
+users.
+
+IEEE 802.1X uses elements called Supplicant, Authenticator, Port
+Access Entity, and Authentication Server. Supplicant is a component in
+a station and it performs the authentication with the Authentication
+Server. An access point includes an Authenticator that relays the packets
+between a Supplicant and an Authentication Server. In addition, it has a
+Port Access Entity (PAE) with Authenticator functionality for
+controlling the virtual port authorization, i.e., whether to accept
+packets from or to the station.
+
+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
+between a Supplicant and an Authenticator are sent using EAP over LAN
+(EAPOL) and the Authenticator relays these frames to the Authentication
+Server (and similarly, relays the messages from the Authentication
+Server to the Supplicant). The Authentication Server can be colocated with the
+Authenticator, in which case there is no need for additional protocol
+for EAP frame transmission. However, a more common configuration is to
+use an external Authentication Server and encapsulate EAP frame in the
+frames used by that server. RADIUS is suitable for this, but IEEE
+802.1X would also allow other mechanisms.
+
+Host AP driver includes PAE functionality in the kernel driver. It
+is a relatively simple mechanism for denying normal frames going to
+or coming from an unauthorized port. PAE allows IEEE 802.1X related
+frames to be passed between the Supplicant and the Authenticator even
+on an unauthorized port.
+
+User space daemon, hostapd, includes Authenticator functionality. It
+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
+device that is also used with IEEE 802.11 management frames. The
+frames to the Supplicant are sent using the same device.
+
+The normal configuration of the Authenticator would use an external
+Authentication Server. hostapd supports RADIUS encapsulation of EAP
+packets, so the Authentication Server should be a RADIUS server, like
+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
+relays the frames between the Supplicant and the Authentication
+Server. It also controls the PAE functionality in the kernel driver by
+controlling virtual port authorization, i.e., station-AP
+connection, based on the IEEE 802.1X state.
+
+When a station would like to use the services of an access point, it
+will first perform IEEE 802.11 authentication. This is normally done
+with open systems authentication, so there is no security. After
+this, IEEE 802.11 association is performed. If IEEE 802.1X is
+configured to be used, the virtual port for the station is set in
+Unauthorized state and only IEEE 802.1X frames are accepted at this
+point. The Authenticator will then ask the Supplicant to authenticate
+with the Authentication Server. After this is completed successfully,
+the virtual port is set to Authorized state and frames from and to the
+station are accepted.
+
+Host AP configuration for IEEE 802.1X
+-------------------------------------
+
+The user space daemon has its own configuration file that can be used to
+define AP options. Distribution package contains an example
+configuration file (hostapd/hostapd.conf) that can be used as a basis
+for configuration. It includes examples of all supported configuration
+options and short description of each option. hostapd should be started
+with full path to the configuration file as the command line argument,
+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
+LAN card, you can use one hostapd process for multiple interfaces by
+giving a list of configuration files (one per interface) in the command
+line.
+
+hostapd includes a minimal co-located IEEE 802.1X server which can be
+used to test IEEE 802.1X authentication. However, it should not be
+used in normal use since it does not provide any security. This can be
+configured by setting ieee8021x and minimal_eap options in the
+configuration file.
+
+An external Authentication Server (RADIUS) is configured with
+auth_server_{addr,port,shared_secret} options. In addition,
+ieee8021x and own_ip_addr must be set for this mode. With such
+configuration, the co-located Authentication Server is not used and EAP
+frames will be relayed using EAPOL between the Supplicant and the
+Authenticator and RADIUS encapsulation between the Authenticator and
+the Authentication Server. Other than this, the functionality is similar
+to the case with the co-located Authentication Server.
+
+Authentication Server and Supplicant
+------------------------------------
+
+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
+Authentication Server with hostapd Authenticator. FreeRADIUS
+(http://www.freeradius.org/) has been successfully tested with hostapd
+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
+XP Supplicants. EAP/TLS was used with Xsupplicant and
+EAP/MD5-Challenge with Windows XP.
+
+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
+Cisco access point with Host AP driver, hostapd daemon, and a Prism2
+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
+EAP/TLS use with WinXP Supplicant.
+
+Automatic WEP key configuration
+-------------------------------
+
+EAP/TLS generates a session key that can be used to send WEP keys from
+an AP to authenticated stations. The Authenticator in hostapd can be
+configured to automatically select a random default/broadcast key
+(shared by all authenticated stations) with wep_key_len_broadcast
+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
+wep_key_len_unicast option can be used to configure individual unicast
+keys for stations. This requires support for individual keys in the
+station driver.
+
+WEP keys can be automatically updated by configuring rekeying. This
+will improve security of the network since same WEP key will only be
+used for a limited period of time. wep_rekey_period option sets the
+interval for rekeying in seconds.
+
+
+WPA/WPA2
+========
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proved to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Testing for WPA2 is likely to start during the second half of 2004.
+
+hostapd configuration for WPA/WPA2
+----------------------------------
+
+TODO
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds.
+#wpa_group_rekey=600
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0

Deleted: vendor/wpa/2.0/hostapd/README-WPS
===================================================================
--- vendor/wpa/dist/hostapd/README-WPS	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/README-WPS	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,265 +0,0 @@
-hostapd and Wi-Fi Protected Setup (WPS)
-=======================================
-
-This document describes how the WPS implementation in hostapd can be
-configured and how an external component on an AP (e.g., web UI) is
-used to enable enrollment of client devices.
-
-
-Introduction to WPS
--------------------
-
-Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
-wireless network. It allows automated generation of random keys (WPA
-passphrase/PSK) and configuration of an access point and client
-devices. WPS includes number of methods for setting up connections
-with PIN method and push-button configuration (PBC) being the most
-commonly deployed options.
-
-While WPS can enable more home networks to use encryption in the
-wireless network, it should be noted that the use of the PIN and
-especially PBC mechanisms for authenticating the initial key setup is
-not very secure. As such, use of WPS may not be suitable for
-environments that require secure network access without chance for
-allowing outsiders to gain access during the setup phase.
-
-WPS uses following terms to describe the entities participating in the
-network setup:
-- access point: the WLAN access point
-- Registrar: a device that control a network and can authorize
-  addition of new devices); this may be either in the AP ("internal
-  Registrar") or in an external device, e.g., a laptop, ("external
-  Registrar")
-- Enrollee: a device that is being authorized to use the network
-
-It should also be noted that the AP and a client device may change
-roles (i.e., AP acts as an Enrollee and client device as a Registrar)
-when WPS is used to configure the access point.
-
-
-More information about WPS is available from Wi-Fi Alliance:
-http://www.wi-fi.org/wifi-protected-setup
-
-
-hostapd implementation
-----------------------
-
-hostapd includes an optional WPS component that can be used as an
-internal WPS Registrar to manage addition of new WPS enabled clients
-to the network. In addition, WPS Enrollee functionality in hostapd can
-be used to allow external WPS Registrars to configure the access
-point, e.g., for initial network setup. In addition, hostapd can proxy a
-WPS registration between a wireless Enrollee and an external Registrar
-(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
-
-
-hostapd configuration
----------------------
-
-WPS is an optional component that needs to be enabled in hostapd build
-configuration (.config). Here is an example configuration that
-includes WPS support and uses madwifi driver interface:
-
-CONFIG_DRIVER_MADWIFI=y
-CFLAGS += -I/usr/src/madwifi-0.9.3
-CONFIG_WPS=y
-CONFIG_WPS_UPNP=y
-
-
-Following section shows an example runtime configuration
-(hostapd.conf) that enables WPS:
-
-# Configure the driver and network interface
-driver=madwifi
-interface=ath0
-
-# WPA2-Personal configuration for the AP
-ssid=wps-test
-wpa=2
-wpa_key_mgmt=WPA-PSK
-wpa_pairwise=CCMP
-# Default WPA passphrase for legacy (non-WPS) clients
-wpa_passphrase=12345678
-# Enable random per-device PSK generation for WPS clients
-# Please note that the file has to exists for hostapd to start (i.e., create an
-# empty file as a starting point).
-wpa_psk_file=/etc/hostapd.psk
-
-# Enable control interface for PBC/PIN entry
-ctrl_interface=/var/run/hostapd
-
-# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
-eap_server=1
-
-# WPS configuration (AP configured, do not allow external WPS Registrars)
-wps_state=2
-ap_setup_locked=1
-# If UUID is not configured, it will be generated based on local MAC address.
-uuid=87654321-9abc-def0-1234-56789abc0000
-wps_pin_requests=/var/run/hostapd.pin-req
-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 display push_button keypad
-
-# if external Registrars are allowed, UPnP support could be added:
-#upnp_iface=br0
-#friendly_name=WPS Access Point
-
-
-External operations
--------------------
-
-WPS requires either a device PIN code (usually, 8-digit number) or a
-pushbutton event (for PBC) to allow a new WPS Enrollee to join the
-network. hostapd uses the control interface as an input channel for
-these events.
-
-When a client device (WPS Enrollee) connects to hostapd (WPS
-Registrar) in order to start PIN mode negotiation for WPS, an
-identifier (Enrollee UUID) is sent. hostapd will need to be configured
-with a device password (PIN) for this Enrollee. This is an operation
-that requires user interaction (assuming there are no pre-configured
-PINs on the AP for a set of Enrollee).
-
-The PIN request with information about the device is appended to the
-wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
-addition, hostapd control interface event is sent as a notification of
-a new device. The AP could use, e.g., a web UI for showing active
-Enrollees to the user and request a PIN for an Enrollee.
-
-The PIN request file has one line for every Enrollee that connected to
-the AP, but for which there was no PIN. Following information is
-provided for each Enrollee (separated with tabulators):
-- timestamp (seconds from 1970-01-01)
-- Enrollee UUID
-- MAC address
-- Device name
-- Manufacturer
-- Model Name
-- Model Number
-- Serial Number
-- Device category
-
-Example line in the /var/run/hostapd.pin-req file:
-1200188391	53b63a98-d29e-4457-a2ed-094d7e6a669c	Intel(R) Centrino(R)	Intel Corporation	Intel(R) Centrino(R)	-	-	1-0050F204-1
-
-Control interface data:
-WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
-For example:
-<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
-
-When the user enters a PIN for a pending Enrollee, e.g., on the web
-UI), hostapd needs to be notified of the new PIN over the control
-interface. This can be done either by using the UNIX domain socket
--based control interface directly (src/common/wpa_ctrl.c provides
-helper functions for using the interface) or by calling hostapd_cli.
-
-Example command to add a PIN (12345670) for an Enrollee:
-
-hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
-
-If the UUID-E is not available (e.g., Enrollee waits for the Registrar
-to be selected before connecting), wildcard UUID may be used to allow
-the PIN to be used once with any UUID:
-
-hostapd_cli wps_pin any 12345670
-
-To reduce likelihood of PIN being used with other devices or of
-forgetting an active PIN available for potential attackers, expiration
-time can be set for the new PIN:
-
-hostapd_cli wps_pin any 12345670 300
-
-
-After this, the Enrollee can connect to the AP again and complete WPS
-negotiation. At that point, a new, random WPA PSK is generated for the
-client device and the client can then use that key to connect to the
-AP to access the network.
-
-
-If the AP includes a pushbutton, WPS PBC mode can be used. It is
-enabled by pushing a button on both the AP and the client at about the
-same time (2 minute window). hostapd needs to be notified about the AP
-button pushed event over the control interface, e.g., by calling
-hostapd_cli:
-
-hostapd_cli wps_pbc
-
-At this point, the client has two minutes to complete WPS negotiation
-which will generate a new WPA PSK in the same way as the PIN method
-described above.
-
-
-When an external Registrar is used, the AP can act as an Enrollee and
-use its AP PIN. A static AP PIN (e.g., one one a label in the AP
-device) can be configured in hostapd.conf (ap_pin parameter). A more
-secure option is to use hostapd_cli wps_ap_pin command to enable the
-AP PIN only based on user action (and even better security by using a
-random AP PIN for each session, i.e., by using "wps_ap_pin random"
-command with a timeout value). Following commands are available for
-managing the dynamic AP PIN operations:
-
-hostapd_cli wps_ap_pin disable
-- disable AP PIN (i.e., do not allow external Registrars to use it to
-  learn the current AP settings or to reconfigure the AP)
-
-hostapd_cli wps_ap_pin random [timeout]
-- generate a random AP PIN and enable it
-- if the optional timeout parameter is given, the AP PIN will be enabled
-  for the specified number of seconds
-
-hostapd_cli wps_ap_pin get
-- fetch the current AP PIN
-
-hostapd_cli wps_ap_pin set <PIN> [timeout]
-- set the AP PIN and enable it
-- if the optional timeout parameter is given, the AP PIN will be enabled
-  for the specified number of seconds
-
-
-Credential generation and configuration changes
------------------------------------------------
-
-By default, hostapd generates credentials for Enrollees and processing
-AP configuration updates internally. However, it is possible to
-control these operations from external programs, if desired.
-
-The internal credential generation can be disabled with
-skip_cred_build=1 option in the configuration. extra_cred option will
-then need to be used to provide pre-configured Credential attribute(s)
-for hostapd to use. The exact data from this binary file will be sent,
-i.e., it will have to include valid WPS attributes. extra_cred can
-also be used to add additional networks if the Registrar is used to
-configure credentials for multiple networks.
-
-Processing of received configuration updates can be disabled with
-wps_cred_processing=1 option. When this is used, an external program
-is responsible for creating hostapd configuration files and processing
-configuration updates based on messages received from hostapd over
-control interface. This will also include the initial configuration on
-first successful registration if the AP is initially set in
-unconfigured state.
-
-Following control interface messages are sent out for external programs:
-
-WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
-For example:
-<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
-
-This can be used to tricker change from unconfigured to configured
-state (random configuration based on the first successful WPS
-registration). In addition, this can be used to update AP UI about the
-status of WPS registration progress.
-
-
-WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
-For example:
-<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
-
-This can be used to update the externally stored AP configuration and
-then update hostapd configuration (followed by restarting of hostapd).

Copied: vendor/wpa/2.0/hostapd/README-WPS (from rev 9639, vendor/wpa/dist/hostapd/README-WPS)
===================================================================
--- vendor/wpa/2.0/hostapd/README-WPS	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/README-WPS	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,340 @@
+hostapd and Wi-Fi Protected Setup (WPS)
+=======================================
+
+This document describes how the WPS implementation in hostapd can be
+configured and how an external component on an AP (e.g., web UI) is
+used to enable enrollment of client devices.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+  addition of new devices); this may be either in the AP ("internal
+  Registrar") or in an external device, e.g., a laptop, ("external
+  Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+hostapd implementation
+----------------------
+
+hostapd includes an optional WPS component that can be used as an
+internal WPS Registrar to manage addition of new WPS enabled clients
+to the network. In addition, WPS Enrollee functionality in hostapd can
+be used to allow external WPS Registrars to configure the access
+point, e.g., for initial network setup. In addition, hostapd can proxy a
+WPS registration between a wireless Enrollee and an external Registrar
+(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
+
+
+hostapd configuration
+---------------------
+
+WPS is an optional component that needs to be enabled in hostapd build
+configuration (.config). Here is an example configuration that
+includes WPS support and uses madwifi driver interface:
+
+CONFIG_DRIVER_MADWIFI=y
+CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_WPS=y
+CONFIG_WPS2=y
+CONFIG_WPS_UPNP=y
+
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
+
+Following section shows an example runtime configuration
+(hostapd.conf) that enables WPS:
+
+# Configure the driver and network interface
+driver=madwifi
+interface=ath0
+
+# WPA2-Personal configuration for the AP
+ssid=wps-test
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+# Default WPA passphrase for legacy (non-WPS) clients
+wpa_passphrase=12345678
+# Enable random per-device PSK generation for WPS clients
+# Please note that the file has to exists for hostapd to start (i.e., create an
+# empty file as a starting point).
+wpa_psk_file=/etc/hostapd.psk
+
+# Enable control interface for PBC/PIN entry
+ctrl_interface=/var/run/hostapd
+
+# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
+eap_server=1
+
+# WPS configuration (AP configured, do not allow external WPS Registrars)
+wps_state=2
+ap_setup_locked=1
+# If UUID is not configured, it will be generated based on local MAC address.
+uuid=87654321-9abc-def0-1234-56789abc0000
+wps_pin_requests=/var/run/hostapd.pin-req
+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 display push_button keypad
+
+# if external Registrars are allowed, UPnP support could be added:
+#upnp_iface=br0
+#friendly_name=WPS Access Point
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. hostapd uses the control interface as an input channel for
+these events.
+
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
+processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
+the checksum digit is incorrect, or the processed PIN (non-digit
+characters removed) if the PIN is valid.
+
+When a client device (WPS Enrollee) connects to hostapd (WPS
+Registrar) in order to start PIN mode negotiation for WPS, an
+identifier (Enrollee UUID) is sent. hostapd will need to be configured
+with a device password (PIN) for this Enrollee. This is an operation
+that requires user interaction (assuming there are no pre-configured
+PINs on the AP for a set of Enrollee).
+
+The PIN request with information about the device is appended to the
+wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
+addition, hostapd control interface event is sent as a notification of
+a new device. The AP could use, e.g., a web UI for showing active
+Enrollees to the user and request a PIN for an Enrollee.
+
+The PIN request file has one line for every Enrollee that connected to
+the AP, but for which there was no PIN. Following information is
+provided for each Enrollee (separated with tabulators):
+- timestamp (seconds from 1970-01-01)
+- Enrollee UUID
+- MAC address
+- Device name
+- Manufacturer
+- Model Name
+- Model Number
+- Serial Number
+- Device category
+
+Example line in the /var/run/hostapd.pin-req file:
+1200188391	53b63a98-d29e-4457-a2ed-094d7e6a669c	Intel(R) Centrino(R)	Intel Corporation	Intel(R) Centrino(R)	-	-	1-0050F204-1
+
+Control interface data:
+WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
+For example:
+<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
+
+When the user enters a PIN for a pending Enrollee, e.g., on the web
+UI), hostapd needs to be notified of the new PIN over the control
+interface. This can be done either by using the UNIX domain socket
+-based control interface directly (src/common/wpa_ctrl.c provides
+helper functions for using the interface) or by calling hostapd_cli.
+
+Example command to add a PIN (12345670) for an Enrollee:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
+
+If the UUID-E is not available (e.g., Enrollee waits for the Registrar
+to be selected before connecting), wildcard UUID may be used to allow
+the PIN to be used once with any UUID:
+
+hostapd_cli wps_pin any 12345670
+
+To reduce likelihood of PIN being used with other devices or of
+forgetting an active PIN available for potential attackers, expiration
+time in seconds can be set for the new PIN (value 0 indicates no
+expiration):
+
+hostapd_cli wps_pin any 12345670 300
+
+If the MAC address of the enrollee is known, it should be configured
+to allow the AP to advertise list of authorized enrollees:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
+	12345670 300 00:11:22:33:44:55
+
+
+After this, the Enrollee can connect to the AP again and complete WPS
+negotiation. At that point, a new, random WPA PSK is generated for the
+client device and the client can then use that key to connect to the
+AP to access the network.
+
+
+If the AP includes a pushbutton, WPS PBC mode can be used. It is
+enabled by pushing a button on both the AP and the client at about the
+same time (2 minute window). hostapd needs to be notified about the AP
+button pushed event over the control interface, e.g., by calling
+hostapd_cli:
+
+hostapd_cli wps_pbc
+
+At this point, the client has two minutes to complete WPS negotiation
+which will generate a new WPA PSK in the same way as the PIN method
+described above.
+
+
+When an external Registrar is used, the AP can act as an Enrollee and
+use its AP PIN. A static AP PIN (e.g., one one a label in the AP
+device) can be configured in hostapd.conf (ap_pin parameter). A more
+secure option is to use hostapd_cli wps_ap_pin command to enable the
+AP PIN only based on user action (and even better security by using a
+random AP PIN for each session, i.e., by using "wps_ap_pin random"
+command with a timeout value). Following commands are available for
+managing the dynamic AP PIN operations:
+
+hostapd_cli wps_ap_pin disable
+- disable AP PIN (i.e., do not allow external Registrars to use it to
+  learn the current AP settings or to reconfigure the AP)
+
+hostapd_cli wps_ap_pin random [timeout]
+- generate a random AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli wps_ap_pin get
+- fetch the current AP PIN
+
+hostapd_cli wps_ap_pin set <PIN> [timeout]
+- set the AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli get_config
+- display the current configuration
+
+hostapd_cli wps_config <new SSID> <auth> <encr> <new key>
+examples:
+  hostapd_cli wps_config testing WPA2PSK CCMP 12345678
+  hostapd_cli wps_config "no security" OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+Credential generation and configuration changes
+-----------------------------------------------
+
+By default, hostapd generates credentials for Enrollees and processing
+AP configuration updates internally. However, it is possible to
+control these operations from external programs, if desired.
+
+The internal credential generation can be disabled with
+skip_cred_build=1 option in the configuration. extra_cred option will
+then need to be used to provide pre-configured Credential attribute(s)
+for hostapd to use. The exact data from this binary file will be sent,
+i.e., it will have to include valid WPS attributes. extra_cred can
+also be used to add additional networks if the Registrar is used to
+configure credentials for multiple networks.
+
+Processing of received configuration updates can be disabled with
+wps_cred_processing=1 option. When this is used, an external program
+is responsible for creating hostapd configuration files and processing
+configuration updates based on messages received from hostapd over
+control interface. This will also include the initial configuration on
+first successful registration if the AP is initially set in
+unconfigured state.
+
+Following control interface messages are sent out for external programs:
+
+WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
+For example:
+<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
+
+This can be used to trigger change from unconfigured to configured
+state (random configuration based on the first successful WPS
+registration). In addition, this can be used to update AP UI about the
+status of WPS registration progress.
+
+
+WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
+For example:
+<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
+
+This can be used to update the externally stored AP configuration and
+then update hostapd configuration (followed by restarting of hostapd).
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the AP acts as an Enrollee, a local NFC tag with a password token
+can be used by touching the NFC interface of an external Registrar. The
+wps_nfc_token command is used to manage use of the NFC password token
+from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
+password token (in place of AP PIN) and "wps_nfc_token disable" disables
+the NFC password token.
+
+The NFC password token that is either pre-configured in the
+configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
+wpa_supplicant can be used to generate NFC password tokens during
+manufacturing (each AP needs to have its own random keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token. The output value from this command is a hexdump
+of the current AP configuration (WPS parameter requests this to include
+only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+When the NFC device on the AP reads an NFC tag with a MIME media type
+"application/vnd.wfa.wsc", the NDEF message payload (with or without
+NDEF encapsulation) can be delivered to hostapd using the
+following hostapd_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a password token, the token is added to the
+internal Registrar. This allows station Enrollee from which the password
+token was received to run through WPS protocol to provision the
+credential.

Deleted: vendor/wpa/2.0/hostapd/config_file.c
===================================================================
--- vendor/wpa/dist/hostapd/config_file.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/config_file.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2049 +0,0 @@
-/*
- * hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <grp.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/common.h"
-#include "utils/uuid.h"
-#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
-#include "eap_server/eap.h"
-#include "radius/radius_client.h"
-#include "ap/wpa_auth.h"
-#include "ap/ap_config.h"
-#include "config_file.h"
-
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
-#ifndef CONFIG_NO_VLAN
-static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
-					 const char *fname)
-{
-	FILE *f;
-	char buf[128], *pos, *pos2;
-	int line = 0, vlan_id;
-	struct hostapd_vlan *vlan;
-
-	f = fopen(fname, "r");
-	if (!f) {
-		wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		if (buf[0] == '\0')
-			continue;
-
-		if (buf[0] == '*') {
-			vlan_id = VLAN_ID_WILDCARD;
-			pos = buf + 1;
-		} else {
-			vlan_id = strtol(buf, &pos, 10);
-			if (buf == pos || vlan_id < 1 ||
-			    vlan_id > MAX_VLAN_ID) {
-				wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
-					   "line %d in '%s'", line, fname);
-				fclose(f);
-				return -1;
-			}
-		}
-
-		while (*pos == ' ' || *pos == '\t')
-			pos++;
-		pos2 = pos;
-		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
-			pos2++;
-		*pos2 = '\0';
-		if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
-			wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
-				   "in '%s'", line, fname);
-			fclose(f);
-			return -1;
-		}
-
-		vlan = os_malloc(sizeof(*vlan));
-		if (vlan == NULL) {
-			wpa_printf(MSG_ERROR, "Out of memory while reading "
-				   "VLAN interfaces from '%s'", fname);
-			fclose(f);
-			return -1;
-		}
-
-		os_memset(vlan, 0, sizeof(*vlan));
-		vlan->vlan_id = vlan_id;
-		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
-		if (bss->vlan_tail)
-			bss->vlan_tail->next = vlan;
-		else
-			bss->vlan = vlan;
-		bss->vlan_tail = vlan;
-	}
-
-	fclose(f);
-
-	return 0;
-}
-#endif /* CONFIG_NO_VLAN */
-
-
-static int hostapd_acl_comp(const void *a, const void *b)
-{
-	const struct mac_acl_entry *aa = a;
-	const struct mac_acl_entry *bb = b;
-	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
-}
-
-
-static int hostapd_config_read_maclist(const char *fname,
-				       struct mac_acl_entry **acl, int *num)
-{
-	FILE *f;
-	char buf[128], *pos;
-	int line = 0;
-	u8 addr[ETH_ALEN];
-	struct mac_acl_entry *newacl;
-	int vlan_id;
-
-	if (!fname)
-		return 0;
-
-	f = fopen(fname, "r");
-	if (!f) {
-		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		if (buf[0] == '\0')
-			continue;
-
-		if (hwaddr_aton(buf, addr)) {
-			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
-				   "line %d in '%s'", buf, line, fname);
-			fclose(f);
-			return -1;
-		}
-
-		vlan_id = 0;
-		pos = buf;
-		while (*pos != '\0' && *pos != ' ' && *pos != '\t')
-			pos++;
-		while (*pos == ' ' || *pos == '\t')
-			pos++;
-		if (*pos != '\0')
-			vlan_id = atoi(pos);
-
-		newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
-		if (newacl == NULL) {
-			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
-			fclose(f);
-			return -1;
-		}
-
-		*acl = newacl;
-		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
-		(*acl)[*num].vlan_id = vlan_id;
-		(*num)++;
-	}
-
-	fclose(f);
-
-	qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
-
-	return 0;
-}
-
-
-#ifdef EAP_SERVER
-static int hostapd_config_read_eap_user(const char *fname,
-					struct hostapd_bss_config *conf)
-{
-	FILE *f;
-	char buf[512], *pos, *start, *pos2;
-	int line = 0, ret = 0, num_methods;
-	struct hostapd_eap_user *user, *tail = NULL;
-
-	if (!fname)
-		return 0;
-
-	f = fopen(fname, "r");
-	if (!f) {
-		wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
-		return -1;
-	}
-
-	/* Lines: "user" METHOD,METHOD2 "password" (password optional) */
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		if (buf[0] == '\0')
-			continue;
-
-		user = NULL;
-
-		if (buf[0] != '"' && buf[0] != '*') {
-			wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
-				   "start) on line %d in '%s'", line, fname);
-			goto failed;
-		}
-
-		user = os_zalloc(sizeof(*user));
-		if (user == NULL) {
-			wpa_printf(MSG_ERROR, "EAP user allocation failed");
-			goto failed;
-		}
-		user->force_version = -1;
-
-		if (buf[0] == '*') {
-			pos = buf;
-		} else {
-			pos = buf + 1;
-			start = pos;
-			while (*pos != '"' && *pos != '\0')
-				pos++;
-			if (*pos == '\0') {
-				wpa_printf(MSG_ERROR, "Invalid EAP identity "
-					   "(no \" in end) on line %d in '%s'",
-					   line, fname);
-				goto failed;
-			}
-
-			user->identity = os_malloc(pos - start);
-			if (user->identity == NULL) {
-				wpa_printf(MSG_ERROR, "Failed to allocate "
-					   "memory for EAP identity");
-				goto failed;
-			}
-			os_memcpy(user->identity, start, pos - start);
-			user->identity_len = pos - start;
-
-			if (pos[0] == '"' && pos[1] == '*') {
-				user->wildcard_prefix = 1;
-				pos++;
-			}
-		}
-		pos++;
-		while (*pos == ' ' || *pos == '\t')
-			pos++;
-
-		if (*pos == '\0') {
-			wpa_printf(MSG_ERROR, "No EAP method on line %d in "
-				   "'%s'", line, fname);
-			goto failed;
-		}
-
-		start = pos;
-		while (*pos != ' ' && *pos != '\t' && *pos != '\0')
-			pos++;
-		if (*pos == '\0') {
-			pos = NULL;
-		} else {
-			*pos = '\0';
-			pos++;
-		}
-		num_methods = 0;
-		while (*start) {
-			char *pos3 = os_strchr(start, ',');
-			if (pos3) {
-				*pos3++ = '\0';
-			}
-			user->methods[num_methods].method =
-				eap_server_get_type(
-					start,
-					&user->methods[num_methods].vendor);
-			if (user->methods[num_methods].vendor ==
-			    EAP_VENDOR_IETF &&
-			    user->methods[num_methods].method == EAP_TYPE_NONE)
-			{
-				if (os_strcmp(start, "TTLS-PAP") == 0) {
-					user->ttls_auth |= EAP_TTLS_AUTH_PAP;
-					goto skip_eap;
-				}
-				if (os_strcmp(start, "TTLS-CHAP") == 0) {
-					user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
-					goto skip_eap;
-				}
-				if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
-					user->ttls_auth |=
-						EAP_TTLS_AUTH_MSCHAP;
-					goto skip_eap;
-				}
-				if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
-					user->ttls_auth |=
-						EAP_TTLS_AUTH_MSCHAPV2;
-					goto skip_eap;
-				}
-				wpa_printf(MSG_ERROR, "Unsupported EAP type "
-					   "'%s' on line %d in '%s'",
-					   start, line, fname);
-				goto failed;
-			}
-
-			num_methods++;
-			if (num_methods >= EAP_USER_MAX_METHODS)
-				break;
-		skip_eap:
-			if (pos3 == NULL)
-				break;
-			start = pos3;
-		}
-		if (num_methods == 0 && user->ttls_auth == 0) {
-			wpa_printf(MSG_ERROR, "No EAP types configured on "
-				   "line %d in '%s'", line, fname);
-			goto failed;
-		}
-
-		if (pos == NULL)
-			goto done;
-
-		while (*pos == ' ' || *pos == '\t')
-			pos++;
-		if (*pos == '\0')
-			goto done;
-
-		if (os_strncmp(pos, "[ver=0]", 7) == 0) {
-			user->force_version = 0;
-			goto done;
-		}
-
-		if (os_strncmp(pos, "[ver=1]", 7) == 0) {
-			user->force_version = 1;
-			goto done;
-		}
-
-		if (os_strncmp(pos, "[2]", 3) == 0) {
-			user->phase2 = 1;
-			goto done;
-		}
-
-		if (*pos == '"') {
-			pos++;
-			start = pos;
-			while (*pos != '"' && *pos != '\0')
-				pos++;
-			if (*pos == '\0') {
-				wpa_printf(MSG_ERROR, "Invalid EAP password "
-					   "(no \" in end) on line %d in '%s'",
-					   line, fname);
-				goto failed;
-			}
-
-			user->password = os_malloc(pos - start);
-			if (user->password == NULL) {
-				wpa_printf(MSG_ERROR, "Failed to allocate "
-					   "memory for EAP password");
-				goto failed;
-			}
-			os_memcpy(user->password, start, pos - start);
-			user->password_len = pos - start;
-
-			pos++;
-		} else if (os_strncmp(pos, "hash:", 5) == 0) {
-			pos += 5;
-			pos2 = pos;
-			while (*pos2 != '\0' && *pos2 != ' ' &&
-			       *pos2 != '\t' && *pos2 != '#')
-				pos2++;
-			if (pos2 - pos != 32) {
-				wpa_printf(MSG_ERROR, "Invalid password hash "
-					   "on line %d in '%s'", line, fname);
-				goto failed;
-			}
-			user->password = os_malloc(16);
-			if (user->password == NULL) {
-				wpa_printf(MSG_ERROR, "Failed to allocate "
-					   "memory for EAP password hash");
-				goto failed;
-			}
-			if (hexstr2bin(pos, user->password, 16) < 0) {
-				wpa_printf(MSG_ERROR, "Invalid hash password "
-					   "on line %d in '%s'", line, fname);
-				goto failed;
-			}
-			user->password_len = 16;
-			user->password_hash = 1;
-			pos = pos2;
-		} else {
-			pos2 = pos;
-			while (*pos2 != '\0' && *pos2 != ' ' &&
-			       *pos2 != '\t' && *pos2 != '#')
-				pos2++;
-			if ((pos2 - pos) & 1) {
-				wpa_printf(MSG_ERROR, "Invalid hex password "
-					   "on line %d in '%s'", line, fname);
-				goto failed;
-			}
-			user->password = os_malloc((pos2 - pos) / 2);
-			if (user->password == NULL) {
-				wpa_printf(MSG_ERROR, "Failed to allocate "
-					   "memory for EAP password");
-				goto failed;
-			}
-			if (hexstr2bin(pos, user->password,
-				       (pos2 - pos) / 2) < 0) {
-				wpa_printf(MSG_ERROR, "Invalid hex password "
-					   "on line %d in '%s'", line, fname);
-				goto failed;
-			}
-			user->password_len = (pos2 - pos) / 2;
-			pos = pos2;
-		}
-
-		while (*pos == ' ' || *pos == '\t')
-			pos++;
-		if (os_strncmp(pos, "[2]", 3) == 0) {
-			user->phase2 = 1;
-		}
-
-	done:
-		if (tail == NULL) {
-			tail = conf->eap_user = user;
-		} else {
-			tail->next = user;
-			tail = user;
-		}
-		continue;
-
-	failed:
-		if (user) {
-			os_free(user->password);
-			os_free(user->identity);
-			os_free(user);
-		}
-		ret = -1;
-		break;
-	}
-
-	fclose(f);
-
-	return ret;
-}
-#endif /* EAP_SERVER */
-
-
-#ifndef CONFIG_NO_RADIUS
-static int
-hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
-				int *num_server, const char *val, int def_port,
-				struct hostapd_radius_server **curr_serv)
-{
-	struct hostapd_radius_server *nserv;
-	int ret;
-	static int server_index = 1;
-
-	nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
-	if (nserv == NULL)
-		return -1;
-
-	*server = nserv;
-	nserv = &nserv[*num_server];
-	(*num_server)++;
-	(*curr_serv) = nserv;
-
-	os_memset(nserv, 0, sizeof(*nserv));
-	nserv->port = def_port;
-	ret = hostapd_parse_ip_addr(val, &nserv->addr);
-	nserv->index = server_index++;
-
-	return ret;
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-static int hostapd_config_parse_key_mgmt(int line, const char *value)
-{
-	int val = 0, last;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "WPA-PSK") == 0)
-			val |= WPA_KEY_MGMT_PSK;
-		else if (os_strcmp(start, "WPA-EAP") == 0)
-			val |= WPA_KEY_MGMT_IEEE8021X;
-#ifdef CONFIG_IEEE80211R
-		else if (os_strcmp(start, "FT-PSK") == 0)
-			val |= WPA_KEY_MGMT_FT_PSK;
-		else if (os_strcmp(start, "FT-EAP") == 0)
-			val |= WPA_KEY_MGMT_FT_IEEE8021X;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
-			val |= WPA_KEY_MGMT_PSK_SHA256;
-		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
-			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
-				   line, start);
-			os_free(buf);
-			return -1;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-
-	os_free(buf);
-	if (val == 0) {
-		wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
-			   "configured.", line);
-		return -1;
-	}
-
-	return val;
-}
-
-
-static int hostapd_config_parse_cipher(int line, const char *value)
-{
-	int val = 0, last;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "CCMP") == 0)
-			val |= WPA_CIPHER_CCMP;
-		else if (os_strcmp(start, "TKIP") == 0)
-			val |= WPA_CIPHER_TKIP;
-		else if (os_strcmp(start, "WEP104") == 0)
-			val |= WPA_CIPHER_WEP104;
-		else if (os_strcmp(start, "WEP40") == 0)
-			val |= WPA_CIPHER_WEP40;
-		else if (os_strcmp(start, "NONE") == 0)
-			val |= WPA_CIPHER_NONE;
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
-				   line, start);
-			os_free(buf);
-			return -1;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	if (val == 0) {
-		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
-			   line);
-		return -1;
-	}
-	return val;
-}
-
-
-static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
-				   char *val)
-{
-	size_t len = os_strlen(val);
-
-	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
-		return -1;
-
-	if (val[0] == '"') {
-		if (len < 2 || val[len - 1] != '"')
-			return -1;
-		len -= 2;
-		wep->key[keyidx] = os_malloc(len);
-		if (wep->key[keyidx] == NULL)
-			return -1;
-		os_memcpy(wep->key[keyidx], val + 1, len);
-		wep->len[keyidx] = len;
-	} else {
-		if (len & 1)
-			return -1;
-		len /= 2;
-		wep->key[keyidx] = os_malloc(len);
-		if (wep->key[keyidx] == NULL)
-			return -1;
-		wep->len[keyidx] = len;
-		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
-			return -1;
-	}
-
-	wep->keys_set++;
-
-	return 0;
-}
-
-
-static int hostapd_parse_rates(int **rate_list, char *val)
-{
-	int *list;
-	int count;
-	char *pos, *end;
-
-	os_free(*rate_list);
-	*rate_list = NULL;
-
-	pos = val;
-	count = 0;
-	while (*pos != '\0') {
-		if (*pos == ' ')
-			count++;
-		pos++;
-	}
-
-	list = os_malloc(sizeof(int) * (count + 2));
-	if (list == NULL)
-		return -1;
-	pos = val;
-	count = 0;
-	while (*pos != '\0') {
-		end = os_strchr(pos, ' ');
-		if (end)
-			*end = '\0';
-
-		list[count++] = atoi(pos);
-		if (!end)
-			break;
-		pos = end + 1;
-	}
-	list[count] = -1;
-
-	*rate_list = list;
-	return 0;
-}
-
-
-static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
-{
-	struct hostapd_bss_config *bss;
-
-	if (*ifname == '\0')
-		return -1;
-
-	bss = os_realloc(conf->bss, (conf->num_bss + 1) *
-			 sizeof(struct hostapd_bss_config));
-	if (bss == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
-			   "multi-BSS entry");
-		return -1;
-	}
-	conf->bss = bss;
-
-	bss = &(conf->bss[conf->num_bss]);
-	os_memset(bss, 0, sizeof(*bss));
-	bss->radius = os_zalloc(sizeof(*bss->radius));
-	if (bss->radius == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
-			   "multi-BSS RADIUS data");
-		return -1;
-	}
-
-	conf->num_bss++;
-	conf->last_bss = bss;
-
-	hostapd_config_defaults_bss(bss);
-	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
-	os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
-
-	return 0;
-}
-
-
-/* convert floats with one decimal place to value*10 int, i.e.,
- * "1.5" will return 15 */
-static int hostapd_config_read_int10(const char *value)
-{
-	int i, d;
-	char *pos;
-
-	i = atoi(value);
-	pos = os_strchr(value, '.');
-	d = 0;
-	if (pos) {
-		pos++;
-		if (*pos >= '0' && *pos <= '9')
-			d = *pos - '0';
-	}
-
-	return i * 10 + d;
-}
-
-
-static int valid_cw(int cw)
-{
-	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
-		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
-}
-
-
-enum {
-	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
-	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
-	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
-	IEEE80211_TX_QUEUE_DATA3 = 3, /* used for EDCA AC_BK data */
-	IEEE80211_TX_QUEUE_DATA4 = 4,
-	IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
-	IEEE80211_TX_QUEUE_BEACON = 7
-};
-
-static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
-				   char *val)
-{
-	int num;
-	char *pos;
-	struct hostapd_tx_queue_params *queue;
-
-	/* skip 'tx_queue_' prefix */
-	pos = name + 9;
-	if (os_strncmp(pos, "data", 4) == 0 &&
-	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
-		num = pos[4] - '0';
-		pos += 6;
-	} else if (os_strncmp(pos, "after_beacon_", 13) == 0) {
-		num = IEEE80211_TX_QUEUE_AFTER_BEACON;
-		pos += 13;
-	} else if (os_strncmp(pos, "beacon_", 7) == 0) {
-		num = IEEE80211_TX_QUEUE_BEACON;
-		pos += 7;
-	} else {
-		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
-		return -1;
-	}
-
-	queue = &conf->tx_queue[num];
-
-	if (os_strcmp(pos, "aifs") == 0) {
-		queue->aifs = atoi(val);
-		if (queue->aifs < 0 || queue->aifs > 255) {
-			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
-				   queue->aifs);
-			return -1;
-		}
-	} else if (os_strcmp(pos, "cwmin") == 0) {
-		queue->cwmin = atoi(val);
-		if (!valid_cw(queue->cwmin)) {
-			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
-				   queue->cwmin);
-			return -1;
-		}
-	} else if (os_strcmp(pos, "cwmax") == 0) {
-		queue->cwmax = atoi(val);
-		if (!valid_cw(queue->cwmax)) {
-			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
-				   queue->cwmax);
-			return -1;
-		}
-	} else if (os_strcmp(pos, "burst") == 0) {
-		queue->burst = hostapd_config_read_int10(val);
-	} else {
-		wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
-		return -1;
-	}
-
-	queue->configured = 1;
-
-	return 0;
-}
-
-
-static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
-				 char *val)
-{
-	int num, v;
-	char *pos;
-	struct hostapd_wmm_ac_params *ac;
-
-	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
-	pos = name + 7;
-	if (os_strncmp(pos, "be_", 3) == 0) {
-		num = 0;
-		pos += 3;
-	} else if (os_strncmp(pos, "bk_", 3) == 0) {
-		num = 1;
-		pos += 3;
-	} else if (os_strncmp(pos, "vi_", 3) == 0) {
-		num = 2;
-		pos += 3;
-	} else if (os_strncmp(pos, "vo_", 3) == 0) {
-		num = 3;
-		pos += 3;
-	} else {
-		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
-		return -1;
-	}
-
-	ac = &conf->wmm_ac_params[num];
-
-	if (os_strcmp(pos, "aifs") == 0) {
-		v = atoi(val);
-		if (v < 1 || v > 255) {
-			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
-			return -1;
-		}
-		ac->aifs = v;
-	} else if (os_strcmp(pos, "cwmin") == 0) {
-		v = atoi(val);
-		if (v < 0 || v > 12) {
-			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
-			return -1;
-		}
-		ac->cwmin = v;
-	} else if (os_strcmp(pos, "cwmax") == 0) {
-		v = atoi(val);
-		if (v < 0 || v > 12) {
-			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
-			return -1;
-		}
-		ac->cwmax = v;
-	} else if (os_strcmp(pos, "txop_limit") == 0) {
-		v = atoi(val);
-		if (v < 0 || v > 0xffff) {
-			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
-			return -1;
-		}
-		ac->txop_limit = v;
-	} else if (os_strcmp(pos, "acm") == 0) {
-		v = atoi(val);
-		if (v < 0 || v > 1) {
-			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
-			return -1;
-		}
-		ac->admission_control_mandatory = v;
-	} else {
-		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static int add_r0kh(struct hostapd_bss_config *bss, char *value)
-{
-	struct ft_remote_r0kh *r0kh;
-	char *pos, *next;
-
-	r0kh = os_zalloc(sizeof(*r0kh));
-	if (r0kh == NULL)
-		return -1;
-
-	/* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
-	pos = value;
-	next = os_strchr(pos, ' ');
-	if (next)
-		*next++ = '\0';
-	if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
-		wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
-		os_free(r0kh);
-		return -1;
-	}
-
-	pos = next;
-	next = os_strchr(pos, ' ');
-	if (next)
-		*next++ = '\0';
-	if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
-		wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
-		os_free(r0kh);
-		return -1;
-	}
-	r0kh->id_len = next - pos - 1;
-	os_memcpy(r0kh->id, pos, r0kh->id_len);
-
-	pos = next;
-	if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
-		wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
-		os_free(r0kh);
-		return -1;
-	}
-
-	r0kh->next = bss->r0kh_list;
-	bss->r0kh_list = r0kh;
-
-	return 0;
-}
-
-
-static int add_r1kh(struct hostapd_bss_config *bss, char *value)
-{
-	struct ft_remote_r1kh *r1kh;
-	char *pos, *next;
-
-	r1kh = os_zalloc(sizeof(*r1kh));
-	if (r1kh == NULL)
-		return -1;
-
-	/* 02:01:02:03:04:05 02:01:02:03:04:05
-	 * 000102030405060708090a0b0c0d0e0f */
-	pos = value;
-	next = os_strchr(pos, ' ');
-	if (next)
-		*next++ = '\0';
-	if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
-		wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
-		os_free(r1kh);
-		return -1;
-	}
-
-	pos = next;
-	next = os_strchr(pos, ' ');
-	if (next)
-		*next++ = '\0';
-	if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
-		wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
-		os_free(r1kh);
-		return -1;
-	}
-
-	pos = next;
-	if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
-		wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
-		os_free(r1kh);
-		return -1;
-	}
-
-	r1kh->next = bss->r1kh_list;
-	bss->r1kh_list = r1kh;
-
-	return 0;
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_IEEE80211N
-static int hostapd_config_ht_capab(struct hostapd_config *conf,
-				   const char *capab)
-{
-	if (os_strstr(capab, "[LDPC]"))
-		conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
-	if (os_strstr(capab, "[HT40-]")) {
-		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
-		conf->secondary_channel = -1;
-	}
-	if (os_strstr(capab, "[HT40+]")) {
-		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
-		conf->secondary_channel = 1;
-	}
-	if (os_strstr(capab, "[SMPS-STATIC]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
-		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
-	}
-	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
-		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
-	}
-	if (os_strstr(capab, "[GF]"))
-		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
-	if (os_strstr(capab, "[SHORT-GI-20]"))
-		conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
-	if (os_strstr(capab, "[SHORT-GI-40]"))
-		conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
-	if (os_strstr(capab, "[TX-STBC]"))
-		conf->ht_capab |= HT_CAP_INFO_TX_STBC;
-	if (os_strstr(capab, "[RX-STBC1]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
-		conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
-	}
-	if (os_strstr(capab, "[RX-STBC12]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
-		conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
-	}
-	if (os_strstr(capab, "[RX-STBC123]")) {
-		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
-		conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
-	}
-	if (os_strstr(capab, "[DELAYED-BA]"))
-		conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
-	if (os_strstr(capab, "[MAX-AMSDU-7935]"))
-		conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
-	if (os_strstr(capab, "[DSSS_CCK-40]"))
-		conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
-	if (os_strstr(capab, "[PSMP]"))
-		conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
-	if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
-		conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
-
-	return 0;
-}
-#endif /* CONFIG_IEEE80211N */
-
-
-static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
-				    struct hostapd_config *conf)
-{
-	if (bss->ieee802_1x && !bss->eap_server &&
-	    !bss->radius->auth_servers) {
-		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
-			   "EAP authenticator configured).");
-		return -1;
-	}
-
-	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
-	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
-	    bss->ssid.wpa_psk_file == NULL) {
-		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
-			   "is not configured.");
-		return -1;
-	}
-
-	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
-		size_t i;
-
-		for (i = 0; i < conf->num_bss; i++) {
-			if ((&conf->bss[i] != bss) &&
-			    (hostapd_mac_comp(conf->bss[i].bssid,
-					      bss->bssid) == 0)) {
-				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
-					   " on interface '%s' and '%s'.",
-					   MAC2STR(bss->bssid),
-					   conf->bss[i].iface, bss->iface);
-				return -1;
-			}
-		}
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if ((bss->wpa_key_mgmt &
-	     (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) &&
-	    (bss->nas_identifier == NULL ||
-	     os_strlen(bss->nas_identifier) < 1 ||
-	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
-		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
-			   "nas_identifier to be configured as a 1..48 octet "
-			   "string");
-		return -1;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211N
-	if (conf->ieee80211n && bss->wpa &&
-	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
-	    !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
-		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
-			   "requires CCMP to be enabled");
-		return -1;
-	}
-#endif /* CONFIG_IEEE80211N */
-
-	return 0;
-}
-
-
-static int hostapd_config_check(struct hostapd_config *conf)
-{
-	size_t i;
-
-	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
-		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
-			   "setting the country_code");
-		return -1;
-	}
-
-	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_config_check_bss(&conf->bss[i], conf))
-			return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * hostapd_config_read - Read and parse a configuration file
- * @fname: Configuration file name (including path, if needed)
- * Returns: Allocated configuration data structure
- */
-struct hostapd_config * hostapd_config_read(const char *fname)
-{
-	struct hostapd_config *conf;
-	struct hostapd_bss_config *bss;
-	FILE *f;
-	char buf[256], *pos;
-	int line = 0;
-	int errors = 0;
-	int pairwise;
-	size_t i;
-
-	f = fopen(fname, "r");
-	if (f == NULL) {
-		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
-			   "for reading.", fname);
-		return NULL;
-	}
-
-	conf = hostapd_config_defaults();
-	if (conf == NULL) {
-		fclose(f);
-		return NULL;
-	}
-
-	/* set default driver based on configuration */
-	conf->driver = wpa_drivers[0];
-	if (conf->driver == NULL) {
-		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
-		hostapd_config_free(conf);
-		fclose(f);
-		return NULL;
-	}
-
-	bss = conf->last_bss = conf->bss;
-
-	while (fgets(buf, sizeof(buf), f)) {
-		bss = conf->last_bss;
-		line++;
-
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		if (buf[0] == '\0')
-			continue;
-
-		pos = os_strchr(buf, '=');
-		if (pos == NULL) {
-			wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
-				   line, buf);
-			errors++;
-			continue;
-		}
-		*pos = '\0';
-		pos++;
-
-		if (os_strcmp(buf, "interface") == 0) {
-			os_strlcpy(conf->bss[0].iface, pos,
-				   sizeof(conf->bss[0].iface));
-		} else if (os_strcmp(buf, "bridge") == 0) {
-			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
-		} else if (os_strcmp(buf, "driver") == 0) {
-			int j;
-			/* clear to get error below if setting is invalid */
-			conf->driver = NULL;
-			for (j = 0; wpa_drivers[j]; j++) {
-				if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
-				{
-					conf->driver = wpa_drivers[j];
-					break;
-				}
-			}
-			if (conf->driver == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid/"
-					   "unknown driver '%s'", line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "debug") == 0) {
-			wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
-				   "configuration variable is not used "
-				   "anymore", line);
-		} else if (os_strcmp(buf, "logger_syslog_level") == 0) {
-			bss->logger_syslog_level = atoi(pos);
-		} else if (os_strcmp(buf, "logger_stdout_level") == 0) {
-			bss->logger_stdout_level = atoi(pos);
-		} else if (os_strcmp(buf, "logger_syslog") == 0) {
-			bss->logger_syslog = atoi(pos);
-		} else if (os_strcmp(buf, "logger_stdout") == 0) {
-			bss->logger_stdout = atoi(pos);
-		} else if (os_strcmp(buf, "dump_file") == 0) {
-			bss->dump_log_name = os_strdup(pos);
-		} else if (os_strcmp(buf, "ssid") == 0) {
-			bss->ssid.ssid_len = os_strlen(pos);
-			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
-			    bss->ssid.ssid_len < 1) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
-					   "'%s'", line, pos);
-				errors++;
-			} else {
-				os_memcpy(bss->ssid.ssid, pos,
-					  bss->ssid.ssid_len);
-				bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
-				bss->ssid.ssid_set = 1;
-			}
-		} else if (os_strcmp(buf, "macaddr_acl") == 0) {
-			bss->macaddr_acl = atoi(pos);
-			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
-			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
-			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
-				wpa_printf(MSG_ERROR, "Line %d: unknown "
-					   "macaddr_acl %d",
-					   line, bss->macaddr_acl);
-			}
-		} else if (os_strcmp(buf, "accept_mac_file") == 0) {
-			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
-							&bss->num_accept_mac))
-			{
-				wpa_printf(MSG_ERROR, "Line %d: Failed to "
-					   "read accept_mac_file '%s'",
-					   line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "deny_mac_file") == 0) {
-			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
-							&bss->num_deny_mac)) {
-				wpa_printf(MSG_ERROR, "Line %d: Failed to "
-					   "read deny_mac_file '%s'",
-					   line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wds_sta") == 0) {
-			bss->wds_sta = atoi(pos);
-		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
-			bss->ap_max_inactivity = atoi(pos);
-		} else if (os_strcmp(buf, "country_code") == 0) {
-			os_memcpy(conf->country, pos, 2);
-			/* FIX: make this configurable */
-			conf->country[2] = ' ';
-		} else if (os_strcmp(buf, "ieee80211d") == 0) {
-			conf->ieee80211d = atoi(pos);
-		} else if (os_strcmp(buf, "ieee8021x") == 0) {
-			bss->ieee802_1x = atoi(pos);
-		} else if (os_strcmp(buf, "eapol_version") == 0) {
-			bss->eapol_version = atoi(pos);
-			if (bss->eapol_version < 1 ||
-			    bss->eapol_version > 2) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
-					   "version (%d): '%s'.",
-					   line, bss->eapol_version, pos);
-				errors++;
-			} else
-				wpa_printf(MSG_DEBUG, "eapol_version=%d",
-					   bss->eapol_version);
-#ifdef EAP_SERVER
-		} else if (os_strcmp(buf, "eap_authenticator") == 0) {
-			bss->eap_server = atoi(pos);
-			wpa_printf(MSG_ERROR, "Line %d: obsolete "
-				   "eap_authenticator used; this has been "
-				   "renamed to eap_server", line);
-		} else if (os_strcmp(buf, "eap_server") == 0) {
-			bss->eap_server = atoi(pos);
-		} else if (os_strcmp(buf, "eap_user_file") == 0) {
-			if (hostapd_config_read_eap_user(pos, bss))
-				errors++;
-		} else if (os_strcmp(buf, "ca_cert") == 0) {
-			os_free(bss->ca_cert);
-			bss->ca_cert = os_strdup(pos);
-		} else if (os_strcmp(buf, "server_cert") == 0) {
-			os_free(bss->server_cert);
-			bss->server_cert = os_strdup(pos);
-		} else if (os_strcmp(buf, "private_key") == 0) {
-			os_free(bss->private_key);
-			bss->private_key = os_strdup(pos);
-		} else if (os_strcmp(buf, "private_key_passwd") == 0) {
-			os_free(bss->private_key_passwd);
-			bss->private_key_passwd = os_strdup(pos);
-		} else if (os_strcmp(buf, "check_crl") == 0) {
-			bss->check_crl = atoi(pos);
-		} else if (os_strcmp(buf, "dh_file") == 0) {
-			os_free(bss->dh_file);
-			bss->dh_file = os_strdup(pos);
-#ifdef EAP_SERVER_FAST
-		} else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
-			os_free(bss->pac_opaque_encr_key);
-			bss->pac_opaque_encr_key = os_malloc(16);
-			if (bss->pac_opaque_encr_key == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: No memory for "
-					   "pac_opaque_encr_key", line);
-				errors++;
-			} else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
-					      16)) {
-				wpa_printf(MSG_ERROR, "Line %d: Invalid "
-					   "pac_opaque_encr_key", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
-			size_t idlen = os_strlen(pos);
-			if (idlen & 1) {
-				wpa_printf(MSG_ERROR, "Line %d: Invalid "
-					   "eap_fast_a_id", line);
-				errors++;
-			} else {
-				os_free(bss->eap_fast_a_id);
-				bss->eap_fast_a_id = os_malloc(idlen / 2);
-				if (bss->eap_fast_a_id == NULL ||
-				    hexstr2bin(pos, bss->eap_fast_a_id,
-					       idlen / 2)) {
-					wpa_printf(MSG_ERROR, "Line %d: "
-						   "Failed to parse "
-						   "eap_fast_a_id", line);
-					errors++;
-				} else
-					bss->eap_fast_a_id_len = idlen / 2;
-			}
-		} else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
-			os_free(bss->eap_fast_a_id_info);
-			bss->eap_fast_a_id_info = os_strdup(pos);
-		} else if (os_strcmp(buf, "eap_fast_prov") == 0) {
-			bss->eap_fast_prov = atoi(pos);
-		} else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
-			bss->pac_key_lifetime = atoi(pos);
-		} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
-			bss->pac_key_refresh_time = atoi(pos);
-#endif /* EAP_SERVER_FAST */
-#ifdef EAP_SERVER_SIM
-		} 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_aka_result_ind") == 0) {
-			bss->eap_sim_aka_result_ind = atoi(pos);
-#endif /* EAP_SERVER_SIM */
-#ifdef EAP_SERVER_TNC
-		} else if (os_strcmp(buf, "tnc") == 0) {
-			bss->tnc = atoi(pos);
-#endif /* EAP_SERVER_TNC */
-#endif /* EAP_SERVER */
-		} else if (os_strcmp(buf, "eap_message") == 0) {
-			char *term;
-			bss->eap_req_id_text = os_strdup(pos);
-			if (bss->eap_req_id_text == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: Failed to "
-					   "allocate memory for "
-					   "eap_req_id_text", line);
-				errors++;
-				continue;
-			}
-			bss->eap_req_id_text_len =
-				os_strlen(bss->eap_req_id_text);
-			term = os_strstr(bss->eap_req_id_text, "\\0");
-			if (term) {
-				*term++ = '\0';
-				os_memmove(term, term + 1,
-					   bss->eap_req_id_text_len -
-					   (term - bss->eap_req_id_text) - 1);
-				bss->eap_req_id_text_len--;
-			}
-		} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
-			bss->default_wep_key_len = atoi(pos);
-			if (bss->default_wep_key_len > 13) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
-					   "key len %lu (= %lu bits)", line,
-					   (unsigned long)
-					   bss->default_wep_key_len,
-					   (unsigned long)
-					   bss->default_wep_key_len * 8);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
-			bss->individual_wep_key_len = atoi(pos);
-			if (bss->individual_wep_key_len < 0 ||
-			    bss->individual_wep_key_len > 13) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
-					   "key len %d (= %d bits)", line,
-					   bss->individual_wep_key_len,
-					   bss->individual_wep_key_len * 8);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
-			bss->wep_rekeying_period = atoi(pos);
-			if (bss->wep_rekeying_period < 0) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "period %d",
-					   line, bss->wep_rekeying_period);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
-			bss->eap_reauth_period = atoi(pos);
-			if (bss->eap_reauth_period < 0) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "period %d",
-					   line, bss->eap_reauth_period);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
-			bss->eapol_key_index_workaround = atoi(pos);
-#ifdef CONFIG_IAPP
-		} else if (os_strcmp(buf, "iapp_interface") == 0) {
-			bss->ieee802_11f = 1;
-			os_strlcpy(bss->iapp_iface, pos,
-				   sizeof(bss->iapp_iface));
-#endif /* CONFIG_IAPP */
-		} else if (os_strcmp(buf, "own_ip_addr") == 0) {
-			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
-					   "address '%s'", line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "nas_identifier") == 0) {
-			bss->nas_identifier = os_strdup(pos);
-#ifndef CONFIG_NO_RADIUS
-		} else if (os_strcmp(buf, "auth_server_addr") == 0) {
-			if (hostapd_config_read_radius_addr(
-				    &bss->radius->auth_servers,
-				    &bss->radius->num_auth_servers, pos, 1812,
-				    &bss->radius->auth_server)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
-					   "address '%s'", line, pos);
-				errors++;
-			}
-		} else if (bss->radius->auth_server &&
-			   os_strcmp(buf, "auth_server_port") == 0) {
-			bss->radius->auth_server->port = atoi(pos);
-		} else if (bss->radius->auth_server &&
-			   os_strcmp(buf, "auth_server_shared_secret") == 0) {
-			int len = os_strlen(pos);
-			if (len == 0) {
-				/* RFC 2865, Ch. 3 */
-				wpa_printf(MSG_ERROR, "Line %d: empty shared "
-					   "secret is not allowed.", line);
-				errors++;
-			}
-			bss->radius->auth_server->shared_secret =
-				(u8 *) os_strdup(pos);
-			bss->radius->auth_server->shared_secret_len = len;
-		} else if (os_strcmp(buf, "acct_server_addr") == 0) {
-			if (hostapd_config_read_radius_addr(
-				    &bss->radius->acct_servers,
-				    &bss->radius->num_acct_servers, pos, 1813,
-				    &bss->radius->acct_server)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
-					   "address '%s'", line, pos);
-				errors++;
-			}
-		} else if (bss->radius->acct_server &&
-			   os_strcmp(buf, "acct_server_port") == 0) {
-			bss->radius->acct_server->port = atoi(pos);
-		} else if (bss->radius->acct_server &&
-			   os_strcmp(buf, "acct_server_shared_secret") == 0) {
-			int len = os_strlen(pos);
-			if (len == 0) {
-				/* RFC 2865, Ch. 3 */
-				wpa_printf(MSG_ERROR, "Line %d: empty shared "
-					   "secret is not allowed.", line);
-				errors++;
-			}
-			bss->radius->acct_server->shared_secret =
-				(u8 *) os_strdup(pos);
-			bss->radius->acct_server->shared_secret_len = len;
-		} else if (os_strcmp(buf, "radius_retry_primary_interval") ==
-			   0) {
-			bss->radius->retry_primary_interval = atoi(pos);
-		} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
-		{
-			bss->acct_interim_interval = atoi(pos);
-#endif /* CONFIG_NO_RADIUS */
-		} else if (os_strcmp(buf, "auth_algs") == 0) {
-			bss->auth_algs = atoi(pos);
-			if (bss->auth_algs == 0) {
-				wpa_printf(MSG_ERROR, "Line %d: no "
-					   "authentication algorithms allowed",
-					   line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "max_num_sta") == 0) {
-			bss->max_num_sta = atoi(pos);
-			if (bss->max_num_sta < 0 ||
-			    bss->max_num_sta > MAX_STA_COUNT) {
-				wpa_printf(MSG_ERROR, "Line %d: Invalid "
-					   "max_num_sta=%d; allowed range "
-					   "0..%d", line, bss->max_num_sta,
-					   MAX_STA_COUNT);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wpa") == 0) {
-			bss->wpa = atoi(pos);
-		} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
-			bss->wpa_group_rekey = atoi(pos);
-		} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
-			bss->wpa_strict_rekey = atoi(pos);
-		} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
-			bss->wpa_gmk_rekey = atoi(pos);
-		} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
-			bss->wpa_ptk_rekey = atoi(pos);
-		} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
-			int len = os_strlen(pos);
-			if (len < 8 || len > 63) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
-					   "passphrase length %d (expected "
-					   "8..63)", line, len);
-				errors++;
-			} else {
-				os_free(bss->ssid.wpa_passphrase);
-				bss->ssid.wpa_passphrase = os_strdup(pos);
-			}
-		} else if (os_strcmp(buf, "wpa_psk") == 0) {
-			os_free(bss->ssid.wpa_psk);
-			bss->ssid.wpa_psk =
-				os_zalloc(sizeof(struct hostapd_wpa_psk));
-			if (bss->ssid.wpa_psk == NULL)
-				errors++;
-			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
-					    PMK_LEN) ||
-				 pos[PMK_LEN * 2] != '\0') {
-				wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
-					   "'%s'.", line, pos);
-				errors++;
-			} else {
-				bss->ssid.wpa_psk->group = 1;
-			}
-		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
-			os_free(bss->ssid.wpa_psk_file);
-			bss->ssid.wpa_psk_file = os_strdup(pos);
-			if (!bss->ssid.wpa_psk_file) {
-				wpa_printf(MSG_ERROR, "Line %d: allocation "
-					   "failed", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
-			bss->wpa_key_mgmt =
-				hostapd_config_parse_key_mgmt(line, pos);
-			if (bss->wpa_key_mgmt == -1)
-				errors++;
-		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
-			bss->wpa_pairwise =
-				hostapd_config_parse_cipher(line, pos);
-			if (bss->wpa_pairwise == -1 ||
-			    bss->wpa_pairwise == 0)
-				errors++;
-			else if (bss->wpa_pairwise &
-				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
-				  WPA_CIPHER_WEP104)) {
-				wpa_printf(MSG_ERROR, "Line %d: unsupported "
-					   "pairwise cipher suite '%s'",
-					   bss->wpa_pairwise, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
-			bss->rsn_pairwise =
-				hostapd_config_parse_cipher(line, pos);
-			if (bss->rsn_pairwise == -1 ||
-			    bss->rsn_pairwise == 0)
-				errors++;
-			else if (bss->rsn_pairwise &
-				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
-				  WPA_CIPHER_WEP104)) {
-				wpa_printf(MSG_ERROR, "Line %d: unsupported "
-					   "pairwise cipher suite '%s'",
-					   bss->rsn_pairwise, pos);
-				errors++;
-			}
-#ifdef CONFIG_RSN_PREAUTH
-		} else if (os_strcmp(buf, "rsn_preauth") == 0) {
-			bss->rsn_preauth = atoi(pos);
-		} else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
-			bss->rsn_preauth_interfaces = os_strdup(pos);
-#endif /* CONFIG_RSN_PREAUTH */
-#ifdef CONFIG_PEERKEY
-		} else if (os_strcmp(buf, "peerkey") == 0) {
-			bss->peerkey = atoi(pos);
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
-		} else if (os_strcmp(buf, "mobility_domain") == 0) {
-			if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
-			    hexstr2bin(pos, bss->mobility_domain,
-				       MOBILITY_DOMAIN_ID_LEN) != 0) {
-				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
-					   "mobility_domain '%s'", line, pos);
-				errors++;
-				continue;
-			}
-		} else if (os_strcmp(buf, "r1_key_holder") == 0) {
-			if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
-			    hexstr2bin(pos, bss->r1_key_holder,
-				       FT_R1KH_ID_LEN) != 0) {
-				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
-					   "r1_key_holder '%s'", line, pos);
-				errors++;
-				continue;
-			}
-		} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
-			bss->r0_key_lifetime = atoi(pos);
-		} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
-			bss->reassociation_deadline = atoi(pos);
-		} else if (os_strcmp(buf, "r0kh") == 0) {
-			if (add_r0kh(bss, pos) < 0) {
-				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
-					   "r0kh '%s'", line, pos);
-				errors++;
-				continue;
-			}
-		} else if (os_strcmp(buf, "r1kh") == 0) {
-			if (add_r1kh(bss, pos) < 0) {
-				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
-					   "r1kh '%s'", line, pos);
-				errors++;
-				continue;
-			}
-		} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
-			bss->pmk_r1_push = atoi(pos);
-#endif /* CONFIG_IEEE80211R */
-#ifndef CONFIG_NO_CTRL_IFACE
-		} else if (os_strcmp(buf, "ctrl_interface") == 0) {
-			os_free(bss->ctrl_interface);
-			bss->ctrl_interface = os_strdup(pos);
-		} else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
-#ifndef CONFIG_NATIVE_WINDOWS
-			struct group *grp;
-			char *endp;
-			const char *group = pos;
-
-			grp = getgrnam(group);
-			if (grp) {
-				bss->ctrl_interface_gid = grp->gr_gid;
-				bss->ctrl_interface_gid_set = 1;
-				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
-					   " (from group name '%s')",
-					   bss->ctrl_interface_gid, group);
-				continue;
-			}
-
-			/* Group name not found - try to parse this as gid */
-			bss->ctrl_interface_gid = strtol(group, &endp, 10);
-			if (*group == '\0' || *endp != '\0') {
-				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
-					   "'%s'", line, group);
-				errors++;
-				continue;
-			}
-			bss->ctrl_interface_gid_set = 1;
-			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
-				   bss->ctrl_interface_gid);
-#endif /* CONFIG_NATIVE_WINDOWS */
-#endif /* CONFIG_NO_CTRL_IFACE */
-#ifdef RADIUS_SERVER
-		} else if (os_strcmp(buf, "radius_server_clients") == 0) {
-			os_free(bss->radius_server_clients);
-			bss->radius_server_clients = os_strdup(pos);
-		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
-			bss->radius_server_auth_port = atoi(pos);
-		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
-			bss->radius_server_ipv6 = atoi(pos);
-#endif /* RADIUS_SERVER */
-		} else if (os_strcmp(buf, "test_socket") == 0) {
-			os_free(bss->test_socket);
-			bss->test_socket = os_strdup(pos);
-		} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
-			bss->use_pae_group_addr = atoi(pos);
-		} else if (os_strcmp(buf, "hw_mode") == 0) {
-			if (os_strcmp(pos, "a") == 0)
-				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
-			else if (os_strcmp(pos, "b") == 0)
-				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
-			else if (os_strcmp(pos, "g") == 0)
-				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-			else {
-				wpa_printf(MSG_ERROR, "Line %d: unknown "
-					   "hw_mode '%s'", line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "channel") == 0) {
-			conf->channel = atoi(pos);
-		} else if (os_strcmp(buf, "beacon_int") == 0) {
-			int val = atoi(pos);
-			/* MIB defines range as 1..65535, but very small values
-			 * cause problems with the current implementation.
-			 * Since it is unlikely that this small numbers are
-			 * useful in real life scenarios, do not allow beacon
-			 * period to be set below 15 TU. */
-			if (val < 15 || val > 65535) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "beacon_int %d (expected "
-					   "15..65535)", line, val);
-				errors++;
-			} else
-				conf->beacon_int = val;
-		} else if (os_strcmp(buf, "dtim_period") == 0) {
-			bss->dtim_period = atoi(pos);
-			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "dtim_period %d",
-					   line, bss->dtim_period);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "rts_threshold") == 0) {
-			conf->rts_threshold = atoi(pos);
-			if (conf->rts_threshold < 0 ||
-			    conf->rts_threshold > 2347) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "rts_threshold %d",
-					   line, conf->rts_threshold);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "fragm_threshold") == 0) {
-			conf->fragm_threshold = atoi(pos);
-			if (conf->fragm_threshold < 256 ||
-			    conf->fragm_threshold > 2346) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "fragm_threshold %d",
-					   line, conf->fragm_threshold);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "send_probe_response") == 0) {
-			int val = atoi(pos);
-			if (val != 0 && val != 1) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "send_probe_response %d (expected "
-					   "0 or 1)", line, val);
-			} else
-				conf->send_probe_response = val;
-		} else if (os_strcmp(buf, "supported_rates") == 0) {
-			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
-					   "list", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "basic_rates") == 0) {
-			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
-					   "list", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "preamble") == 0) {
-			if (atoi(pos))
-				conf->preamble = SHORT_PREAMBLE;
-			else
-				conf->preamble = LONG_PREAMBLE;
-		} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
-			bss->ignore_broadcast_ssid = atoi(pos);
-		} else if (os_strcmp(buf, "wep_default_key") == 0) {
-			bss->ssid.wep.idx = atoi(pos);
-			if (bss->ssid.wep.idx > 3) {
-				wpa_printf(MSG_ERROR, "Invalid "
-					   "wep_default_key index %d",
-					   bss->ssid.wep.idx);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wep_key0") == 0 ||
-			   os_strcmp(buf, "wep_key1") == 0 ||
-			   os_strcmp(buf, "wep_key2") == 0 ||
-			   os_strcmp(buf, "wep_key3") == 0) {
-			if (hostapd_config_read_wep(&bss->ssid.wep,
-						    buf[7] - '0', pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
-					   "key '%s'", line, buf);
-				errors++;
-			}
-#ifndef CONFIG_NO_VLAN
-		} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
-			bss->ssid.dynamic_vlan = 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, pos);
-				errors++;
-			}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-		} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
-			bss->ssid.vlan_tagged_interface = os_strdup(pos);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-#endif /* CONFIG_NO_VLAN */
-		} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
-			conf->ap_table_max_size = atoi(pos);
-		} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
-			conf->ap_table_expiration_time = atoi(pos);
-		} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
-			if (hostapd_config_tx_queue(conf, buf, pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid TX "
-					   "queue item", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wme_enabled") == 0 ||
-			   os_strcmp(buf, "wmm_enabled") == 0) {
-			bss->wmm_enabled = atoi(pos);
-		} else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
-			bss->wmm_uapsd = atoi(pos);
-		} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
-			   os_strncmp(buf, "wmm_ac_", 7) == 0) {
-			if (hostapd_config_wmm_ac(conf, buf, pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
-					   "ac item", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "bss") == 0) {
-			if (hostapd_config_bss(conf, pos)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid bss "
-					   "item", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "bssid") == 0) {
-			if (hwaddr_aton(pos, bss->bssid)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
-					   "item", line);
-				errors++;
-			}
-#ifdef CONFIG_IEEE80211W
-		} else if (os_strcmp(buf, "ieee80211w") == 0) {
-			bss->ieee80211w = atoi(pos);
-		} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
-			bss->assoc_sa_query_max_timeout = atoi(pos);
-			if (bss->assoc_sa_query_max_timeout == 0) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "assoc_sa_query_max_timeout", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
-		{
-			bss->assoc_sa_query_retry_timeout = atoi(pos);
-			if (bss->assoc_sa_query_retry_timeout == 0) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "assoc_sa_query_retry_timeout",
-					   line);
-				errors++;
-			}
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211N
-		} else if (os_strcmp(buf, "ieee80211n") == 0) {
-			conf->ieee80211n = atoi(pos);
-		} else if (os_strcmp(buf, "ht_capab") == 0) {
-			if (hostapd_config_ht_capab(conf, pos) < 0) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "ht_capab", line);
-				errors++;
-			}
-#endif /* CONFIG_IEEE80211N */
-		} else if (os_strcmp(buf, "max_listen_interval") == 0) {
-			bss->max_listen_interval = atoi(pos);
-		} else if (os_strcmp(buf, "okc") == 0) {
-			bss->okc = atoi(pos);
-#ifdef CONFIG_WPS
-		} else if (os_strcmp(buf, "wps_state") == 0) {
-			bss->wps_state = atoi(pos);
-			if (bss->wps_state < 0 || bss->wps_state > 2) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "wps_state", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
-			bss->ap_setup_locked = atoi(pos);
-		} else if (os_strcmp(buf, "uuid") == 0) {
-			if (uuid_str2bin(pos, bss->uuid)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
-					   line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wps_pin_requests") == 0) {
-			os_free(bss->wps_pin_requests);
-			bss->wps_pin_requests = os_strdup(pos);
-		} else if (os_strcmp(buf, "device_name") == 0) {
-			if (os_strlen(pos) > 32) {
-				wpa_printf(MSG_ERROR, "Line %d: Too long "
-					   "device_name", line);
-				errors++;
-			}
-			os_free(bss->device_name);
-			bss->device_name = os_strdup(pos);
-		} else if (os_strcmp(buf, "manufacturer") == 0) {
-			if (os_strlen(pos) > 64) {
-				wpa_printf(MSG_ERROR, "Line %d: Too long "
-					   "manufacturer", line);
-				errors++;
-			}
-			os_free(bss->manufacturer);
-			bss->manufacturer = os_strdup(pos);
-		} else if (os_strcmp(buf, "model_name") == 0) {
-			if (os_strlen(pos) > 32) {
-				wpa_printf(MSG_ERROR, "Line %d: Too long "
-					   "model_name", line);
-				errors++;
-			}
-			os_free(bss->model_name);
-			bss->model_name = os_strdup(pos);
-		} else if (os_strcmp(buf, "model_number") == 0) {
-			if (os_strlen(pos) > 32) {
-				wpa_printf(MSG_ERROR, "Line %d: Too long "
-					   "model_number", line);
-				errors++;
-			}
-			os_free(bss->model_number);
-			bss->model_number = os_strdup(pos);
-		} else if (os_strcmp(buf, "serial_number") == 0) {
-			if (os_strlen(pos) > 32) {
-				wpa_printf(MSG_ERROR, "Line %d: Too long "
-					   "serial_number", line);
-				errors++;
-			}
-			os_free(bss->serial_number);
-			bss->serial_number = os_strdup(pos);
-		} else if (os_strcmp(buf, "device_type") == 0) {
-			os_free(bss->device_type);
-			bss->device_type = os_strdup(pos);
-		} else if (os_strcmp(buf, "config_methods") == 0) {
-			os_free(bss->config_methods);
-			bss->config_methods = os_strdup(pos);
-		} else if (os_strcmp(buf, "os_version") == 0) {
-			if (hexstr2bin(pos, bss->os_version, 4)) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "os_version", line);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "ap_pin") == 0) {
-			os_free(bss->ap_pin);
-			bss->ap_pin = os_strdup(pos);
-		} else if (os_strcmp(buf, "skip_cred_build") == 0) {
-			bss->skip_cred_build = atoi(pos);
-		} else if (os_strcmp(buf, "extra_cred") == 0) {
-			os_free(bss->extra_cred);
-			bss->extra_cred =
-				(u8 *) os_readfile(pos, &bss->extra_cred_len);
-			if (bss->extra_cred == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: could not "
-					   "read Credentials from '%s'",
-					   line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
-			bss->wps_cred_processing = atoi(pos);
-		} else if (os_strcmp(buf, "ap_settings") == 0) {
-			os_free(bss->ap_settings);
-			bss->ap_settings =
-				(u8 *) os_readfile(pos, &bss->ap_settings_len);
-			if (bss->ap_settings == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: could not "
-					   "read AP Settings from '%s'",
-					   line, pos);
-				errors++;
-			}
-		} else if (os_strcmp(buf, "upnp_iface") == 0) {
-			bss->upnp_iface = os_strdup(pos);
-		} else if (os_strcmp(buf, "friendly_name") == 0) {
-			os_free(bss->friendly_name);
-			bss->friendly_name = os_strdup(pos);
-		} else if (os_strcmp(buf, "manufacturer_url") == 0) {
-			os_free(bss->manufacturer_url);
-			bss->manufacturer_url = os_strdup(pos);
-		} else if (os_strcmp(buf, "model_description") == 0) {
-			os_free(bss->model_description);
-			bss->model_description = os_strdup(pos);
-		} else if (os_strcmp(buf, "model_url") == 0) {
-			os_free(bss->model_url);
-			bss->model_url = os_strdup(pos);
-		} else if (os_strcmp(buf, "upc") == 0) {
-			os_free(bss->upc);
-			bss->upc = os_strdup(pos);
-#endif /* CONFIG_WPS */
-		} else {
-			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
-				   "item '%s'", line, buf);
-			errors++;
-		}
-	}
-
-	fclose(f);
-
-	for (i = 0; i < conf->num_bss; i++) {
-		bss = &conf->bss[i];
-
-		if (bss->individual_wep_key_len == 0) {
-			/* individual keys are not use; can use key idx0 for
-			 * broadcast keys */
-			bss->broadcast_key_idx_min = 0;
-		}
-
-		/* Select group cipher based on the enabled pairwise cipher
-		 * suites */
-		pairwise = 0;
-		if (bss->wpa & 1)
-			pairwise |= bss->wpa_pairwise;
-		if (bss->wpa & 2) {
-			if (bss->rsn_pairwise == 0)
-				bss->rsn_pairwise = bss->wpa_pairwise;
-			pairwise |= bss->rsn_pairwise;
-		}
-		if (pairwise & WPA_CIPHER_TKIP)
-			bss->wpa_group = WPA_CIPHER_TKIP;
-		else
-			bss->wpa_group = WPA_CIPHER_CCMP;
-
-		bss->radius->auth_server = bss->radius->auth_servers;
-		bss->radius->acct_server = bss->radius->acct_servers;
-
-		if (bss->wpa && bss->ieee802_1x) {
-			bss->ssid.security_policy = SECURITY_WPA;
-		} else if (bss->wpa) {
-			bss->ssid.security_policy = SECURITY_WPA_PSK;
-		} else if (bss->ieee802_1x) {
-			bss->ssid.security_policy = SECURITY_IEEE_802_1X;
-			bss->ssid.wep.default_len = bss->default_wep_key_len;
-		} else if (bss->ssid.wep.keys_set)
-			bss->ssid.security_policy = SECURITY_STATIC_WEP;
-		else
-			bss->ssid.security_policy = SECURITY_PLAINTEXT;
-	}
-
-	if (hostapd_config_check(conf))
-		errors++;
-
-	if (errors) {
-		wpa_printf(MSG_ERROR, "%d errors found in configuration file "
-			   "'%s'", errors, fname);
-		hostapd_config_free(conf);
-		conf = NULL;
-	}
-
-	return conf;
-}

Copied: vendor/wpa/2.0/hostapd/config_file.c (from rev 9639, vendor/wpa/dist/hostapd/config_file.c)
===================================================================
--- vendor/wpa/2.0/hostapd/config_file.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/config_file.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3122 @@
+/*
+ * hostapd / Configuration file parser
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "radius/radius_client.h"
+#include "ap/wpa_auth.h"
+#include "ap/ap_config.h"
+#include "config_file.h"
+
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+#ifndef CONFIG_NO_VLAN
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+					 const char *fname)
+{
+	FILE *f;
+	char buf[128], *pos, *pos2;
+	int line = 0, vlan_id;
+	struct hostapd_vlan *vlan;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (buf[0] == '*') {
+			vlan_id = VLAN_ID_WILDCARD;
+			pos = buf + 1;
+		} else {
+			vlan_id = strtol(buf, &pos, 10);
+			if (buf == pos || vlan_id < 1 ||
+			    vlan_id > MAX_VLAN_ID) {
+				wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
+					   "line %d in '%s'", line, fname);
+				fclose(f);
+				return -1;
+			}
+		}
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		pos2 = pos;
+		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+			pos2++;
+		*pos2 = '\0';
+		if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
+			wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
+				   "in '%s'", line, fname);
+			fclose(f);
+			return -1;
+		}
+
+		vlan = os_malloc(sizeof(*vlan));
+		if (vlan == NULL) {
+			wpa_printf(MSG_ERROR, "Out of memory while reading "
+				   "VLAN interfaces from '%s'", fname);
+			fclose(f);
+			return -1;
+		}
+
+		os_memset(vlan, 0, sizeof(*vlan));
+		vlan->vlan_id = vlan_id;
+		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+		if (bss->vlan_tail)
+			bss->vlan_tail->next = vlan;
+		else
+			bss->vlan = vlan;
+		bss->vlan_tail = vlan;
+	}
+
+	fclose(f);
+
+	return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+
+static int hostapd_acl_comp(const void *a, const void *b)
+{
+	const struct mac_acl_entry *aa = a;
+	const struct mac_acl_entry *bb = b;
+	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname,
+				       struct mac_acl_entry **acl, int *num)
+{
+	FILE *f;
+	char buf[128], *pos;
+	int line = 0;
+	u8 addr[ETH_ALEN];
+	struct mac_acl_entry *newacl;
+	int vlan_id;
+
+	if (!fname)
+		return 0;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (hwaddr_aton(buf, addr)) {
+			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
+				   "line %d in '%s'", buf, line, fname);
+			fclose(f);
+			return -1;
+		}
+
+		vlan_id = 0;
+		pos = buf;
+		while (*pos != '\0' && *pos != ' ' && *pos != '\t')
+			pos++;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (*pos != '\0')
+			vlan_id = atoi(pos);
+
+		newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+		if (newacl == NULL) {
+			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+			fclose(f);
+			return -1;
+		}
+
+		*acl = newacl;
+		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+		(*acl)[*num].vlan_id = vlan_id;
+		(*num)++;
+	}
+
+	fclose(f);
+
+	qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+
+	return 0;
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_config_read_eap_user(const char *fname,
+					struct hostapd_bss_config *conf)
+{
+	FILE *f;
+	char buf[512], *pos, *start, *pos2;
+	int line = 0, ret = 0, num_methods;
+	struct hostapd_eap_user *user, *tail = NULL;
+
+	if (!fname)
+		return 0;
+
+	if (os_strncmp(fname, "sqlite:", 7) == 0) {
+		os_free(conf->eap_user_sqlite);
+		conf->eap_user_sqlite = os_strdup(fname + 7);
+		return 0;
+	}
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
+		return -1;
+	}
+
+	/* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		user = NULL;
+
+		if (buf[0] != '"' && buf[0] != '*') {
+			wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
+				   "start) on line %d in '%s'", line, fname);
+			goto failed;
+		}
+
+		user = os_zalloc(sizeof(*user));
+		if (user == NULL) {
+			wpa_printf(MSG_ERROR, "EAP user allocation failed");
+			goto failed;
+		}
+		user->force_version = -1;
+
+		if (buf[0] == '*') {
+			pos = buf;
+		} else {
+			pos = buf + 1;
+			start = pos;
+			while (*pos != '"' && *pos != '\0')
+				pos++;
+			if (*pos == '\0') {
+				wpa_printf(MSG_ERROR, "Invalid EAP identity "
+					   "(no \" in end) on line %d in '%s'",
+					   line, fname);
+				goto failed;
+			}
+
+			user->identity = os_malloc(pos - start);
+			if (user->identity == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP identity");
+				goto failed;
+			}
+			os_memcpy(user->identity, start, pos - start);
+			user->identity_len = pos - start;
+
+			if (pos[0] == '"' && pos[1] == '*') {
+				user->wildcard_prefix = 1;
+				pos++;
+			}
+		}
+		pos++;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+
+		if (*pos == '\0') {
+			wpa_printf(MSG_ERROR, "No EAP method on line %d in "
+				   "'%s'", line, fname);
+			goto failed;
+		}
+
+		start = pos;
+		while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+			pos++;
+		if (*pos == '\0') {
+			pos = NULL;
+		} else {
+			*pos = '\0';
+			pos++;
+		}
+		num_methods = 0;
+		while (*start) {
+			char *pos3 = os_strchr(start, ',');
+			if (pos3) {
+				*pos3++ = '\0';
+			}
+			user->methods[num_methods].method =
+				eap_server_get_type(
+					start,
+					&user->methods[num_methods].vendor);
+			if (user->methods[num_methods].vendor ==
+			    EAP_VENDOR_IETF &&
+			    user->methods[num_methods].method == EAP_TYPE_NONE)
+			{
+				if (os_strcmp(start, "TTLS-PAP") == 0) {
+					user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-CHAP") == 0) {
+					user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+					user->ttls_auth |=
+						EAP_TTLS_AUTH_MSCHAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+					user->ttls_auth |=
+						EAP_TTLS_AUTH_MSCHAPV2;
+					goto skip_eap;
+				}
+				wpa_printf(MSG_ERROR, "Unsupported EAP type "
+					   "'%s' on line %d in '%s'",
+					   start, line, fname);
+				goto failed;
+			}
+
+			num_methods++;
+			if (num_methods >= EAP_MAX_METHODS)
+				break;
+		skip_eap:
+			if (pos3 == NULL)
+				break;
+			start = pos3;
+		}
+		if (num_methods == 0 && user->ttls_auth == 0) {
+			wpa_printf(MSG_ERROR, "No EAP types configured on "
+				   "line %d in '%s'", line, fname);
+			goto failed;
+		}
+
+		if (pos == NULL)
+			goto done;
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (*pos == '\0')
+			goto done;
+
+		if (os_strncmp(pos, "[ver=0]", 7) == 0) {
+			user->force_version = 0;
+			goto done;
+		}
+
+		if (os_strncmp(pos, "[ver=1]", 7) == 0) {
+			user->force_version = 1;
+			goto done;
+		}
+
+		if (os_strncmp(pos, "[2]", 3) == 0) {
+			user->phase2 = 1;
+			goto done;
+		}
+
+		if (*pos == '"') {
+			pos++;
+			start = pos;
+			while (*pos != '"' && *pos != '\0')
+				pos++;
+			if (*pos == '\0') {
+				wpa_printf(MSG_ERROR, "Invalid EAP password "
+					   "(no \" in end) on line %d in '%s'",
+					   line, fname);
+				goto failed;
+			}
+
+			user->password = os_malloc(pos - start);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password");
+				goto failed;
+			}
+			os_memcpy(user->password, start, pos - start);
+			user->password_len = pos - start;
+
+			pos++;
+		} else if (os_strncmp(pos, "hash:", 5) == 0) {
+			pos += 5;
+			pos2 = pos;
+			while (*pos2 != '\0' && *pos2 != ' ' &&
+			       *pos2 != '\t' && *pos2 != '#')
+				pos2++;
+			if (pos2 - pos != 32) {
+				wpa_printf(MSG_ERROR, "Invalid password hash "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password = os_malloc(16);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password hash");
+				goto failed;
+			}
+			if (hexstr2bin(pos, user->password, 16) < 0) {
+				wpa_printf(MSG_ERROR, "Invalid hash password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password_len = 16;
+			user->password_hash = 1;
+			pos = pos2;
+		} else {
+			pos2 = pos;
+			while (*pos2 != '\0' && *pos2 != ' ' &&
+			       *pos2 != '\t' && *pos2 != '#')
+				pos2++;
+			if ((pos2 - pos) & 1) {
+				wpa_printf(MSG_ERROR, "Invalid hex password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password = os_malloc((pos2 - pos) / 2);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password");
+				goto failed;
+			}
+			if (hexstr2bin(pos, user->password,
+				       (pos2 - pos) / 2) < 0) {
+				wpa_printf(MSG_ERROR, "Invalid hex password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password_len = (pos2 - pos) / 2;
+			pos = pos2;
+		}
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (os_strncmp(pos, "[2]", 3) == 0) {
+			user->phase2 = 1;
+		}
+
+	done:
+		if (tail == NULL) {
+			tail = conf->eap_user = user;
+		} else {
+			tail->next = user;
+			tail = user;
+		}
+		continue;
+
+	failed:
+		if (user) {
+			os_free(user->password);
+			os_free(user->identity);
+			os_free(user);
+		}
+		ret = -1;
+		break;
+	}
+
+	fclose(f);
+
+	return ret;
+}
+#endif /* EAP_SERVER */
+
+
+#ifndef CONFIG_NO_RADIUS
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+				int *num_server, const char *val, int def_port,
+				struct hostapd_radius_server **curr_serv)
+{
+	struct hostapd_radius_server *nserv;
+	int ret;
+	static int server_index = 1;
+
+	nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
+	if (nserv == NULL)
+		return -1;
+
+	*server = nserv;
+	nserv = &nserv[*num_server];
+	(*num_server)++;
+	(*curr_serv) = nserv;
+
+	os_memset(nserv, 0, sizeof(*nserv));
+	nserv->port = def_port;
+	ret = hostapd_parse_ip_addr(val, &nserv->addr);
+	nserv->index = server_index++;
+
+	return ret;
+}
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+	const char *pos;
+	char syntax;
+	struct hostapd_radius_attr *attr;
+	size_t len;
+
+	attr = os_zalloc(sizeof(*attr));
+	if (attr == NULL)
+		return NULL;
+
+	attr->type = atoi(value);
+
+	pos = os_strchr(value, ':');
+	if (pos == NULL) {
+		attr->val = wpabuf_alloc(1);
+		if (attr->val == NULL) {
+			os_free(attr);
+			return NULL;
+		}
+		wpabuf_put_u8(attr->val, 0);
+		return attr;
+	}
+
+	pos++;
+	if (pos[0] == '\0' || pos[1] != ':') {
+		os_free(attr);
+		return NULL;
+	}
+	syntax = *pos++;
+	pos++;
+
+	switch (syntax) {
+	case 's':
+		attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+		break;
+	case 'x':
+		len = os_strlen(pos);
+		if (len & 1)
+			break;
+		len /= 2;
+		attr->val = wpabuf_alloc(len);
+		if (attr->val == NULL)
+			break;
+		if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+			wpabuf_free(attr->val);
+			os_free(attr);
+			return NULL;
+		}
+		break;
+	case 'd':
+		attr->val = wpabuf_alloc(4);
+		if (attr->val)
+			wpabuf_put_be32(attr->val, atoi(pos));
+		break;
+	default:
+		os_free(attr);
+		return NULL;
+	}
+
+	if (attr->val == NULL) {
+		os_free(attr);
+		return NULL;
+	}
+
+	return attr;
+}
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+				    const char *val)
+{
+	char *secret;
+
+	secret = os_strchr(val, ' ');
+	if (secret == NULL)
+		return -1;
+
+	secret++;
+
+	if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+		return -1;
+
+	os_free(bss->radius_das_shared_secret);
+	bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
+	if (bss->radius_das_shared_secret == NULL)
+		return -1;
+	bss->radius_das_shared_secret_len = os_strlen(secret);
+
+	return 0;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA-PSK") == 0)
+			val |= WPA_KEY_MGMT_PSK;
+		else if (os_strcmp(start, "WPA-EAP") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211R
+		else if (os_strcmp(start, "FT-PSK") == 0)
+			val |= WPA_KEY_MGMT_FT_PSK;
+		else if (os_strcmp(start, "FT-EAP") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+		else if (os_strcmp(start, "SAE") == 0)
+			val |= WPA_KEY_MGMT_SAE;
+		else if (os_strcmp(start, "FT-SAE") == 0)
+			val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+
+	os_free(buf);
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
+			   "configured.", line);
+		return -1;
+	}
+
+	return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "CCMP") == 0)
+			val |= WPA_CIPHER_CCMP;
+		else if (os_strcmp(start, "GCMP") == 0)
+			val |= WPA_CIPHER_GCMP;
+		else if (os_strcmp(start, "TKIP") == 0)
+			val |= WPA_CIPHER_TKIP;
+		else if (os_strcmp(start, "WEP104") == 0)
+			val |= WPA_CIPHER_WEP104;
+		else if (os_strcmp(start, "WEP40") == 0)
+			val |= WPA_CIPHER_WEP40;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_CIPHER_NONE;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+			   line);
+		return -1;
+	}
+	return val;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+				   char *val)
+{
+	size_t len = os_strlen(val);
+
+	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+		return -1;
+
+	if (val[0] == '"') {
+		if (len < 2 || val[len - 1] != '"')
+			return -1;
+		len -= 2;
+		wep->key[keyidx] = os_malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		os_memcpy(wep->key[keyidx], val + 1, len);
+		wep->len[keyidx] = len;
+	} else {
+		if (len & 1)
+			return -1;
+		len /= 2;
+		wep->key[keyidx] = os_malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		wep->len[keyidx] = len;
+		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+			return -1;
+	}
+
+	wep->keys_set++;
+
+	return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+	int *list;
+	int count;
+	char *pos, *end;
+
+	os_free(*rate_list);
+	*rate_list = NULL;
+
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		if (*pos == ' ')
+			count++;
+		pos++;
+	}
+
+	list = os_malloc(sizeof(int) * (count + 2));
+	if (list == NULL)
+		return -1;
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		end = os_strchr(pos, ' ');
+		if (end)
+			*end = '\0';
+
+		list[count++] = atoi(pos);
+		if (!end)
+			break;
+		pos = end + 1;
+	}
+	list[count] = -1;
+
+	*rate_list = list;
+	return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+	struct hostapd_bss_config *bss;
+
+	if (*ifname == '\0')
+		return -1;
+
+	bss = os_realloc_array(conf->bss, conf->num_bss + 1,
+			       sizeof(struct hostapd_bss_config));
+	if (bss == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "multi-BSS entry");
+		return -1;
+	}
+	conf->bss = bss;
+
+	bss = &(conf->bss[conf->num_bss]);
+	os_memset(bss, 0, sizeof(*bss));
+	bss->radius = os_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "multi-BSS RADIUS data");
+		return -1;
+	}
+
+	conf->num_bss++;
+	conf->last_bss = bss;
+
+	hostapd_config_defaults_bss(bss);
+	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+	os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+	return 0;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+	int i, d;
+	char *pos;
+
+	i = atoi(value);
+	pos = os_strchr(value, '.');
+	d = 0;
+	if (pos) {
+		pos++;
+		if (*pos >= '0' && *pos <= '9')
+			d = *pos - '0';
+	}
+
+	return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+	IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+				   char *val)
+{
+	int num;
+	char *pos;
+	struct hostapd_tx_queue_params *queue;
+
+	/* skip 'tx_queue_' prefix */
+	pos = name + 9;
+	if (os_strncmp(pos, "data", 4) == 0 &&
+	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+		num = pos[4] - '0';
+		pos += 6;
+	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+		   os_strncmp(pos, "beacon_", 7) == 0) {
+		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+		return 0;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+		return -1;
+	}
+
+	if (num >= NUM_TX_QUEUES) {
+		/* for backwards compatibility, do not trigger failure */
+		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+		return 0;
+	}
+
+	queue = &conf->tx_queue[num];
+
+	if (os_strcmp(pos, "aifs") == 0) {
+		queue->aifs = atoi(val);
+		if (queue->aifs < 0 || queue->aifs > 255) {
+			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+				   queue->aifs);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "cwmin") == 0) {
+		queue->cwmin = atoi(val);
+		if (!valid_cw(queue->cwmin)) {
+			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+				   queue->cwmin);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "cwmax") == 0) {
+		queue->cwmax = atoi(val);
+		if (!valid_cw(queue->cwmax)) {
+			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+				   queue->cwmax);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "burst") == 0) {
+		queue->burst = hostapd_config_read_int10(val);
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int add_r0kh(struct hostapd_bss_config *bss, char *value)
+{
+	struct ft_remote_r0kh *r0kh;
+	char *pos, *next;
+
+	r0kh = os_zalloc(sizeof(*r0kh));
+	if (r0kh == NULL)
+		return -1;
+
+	/* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
+	pos = value;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+
+	pos = next;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+	r0kh->id_len = next - pos - 1;
+	os_memcpy(r0kh->id, pos, r0kh->id_len);
+
+	pos = next;
+	if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+
+	r0kh->next = bss->r0kh_list;
+	bss->r0kh_list = r0kh;
+
+	return 0;
+}
+
+
+static int add_r1kh(struct hostapd_bss_config *bss, char *value)
+{
+	struct ft_remote_r1kh *r1kh;
+	char *pos, *next;
+
+	r1kh = os_zalloc(sizeof(*r1kh));
+	if (r1kh == NULL)
+		return -1;
+
+	/* 02:01:02:03:04:05 02:01:02:03:04:05
+	 * 000102030405060708090a0b0c0d0e0f */
+	pos = value;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	pos = next;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	pos = next;
+	if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	r1kh->next = bss->r1kh_list;
+	bss->r1kh_list = r1kh;
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IEEE80211N
+static int hostapd_config_ht_capab(struct hostapd_config *conf,
+				   const char *capab)
+{
+	if (os_strstr(capab, "[LDPC]"))
+		conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
+	if (os_strstr(capab, "[HT40-]")) {
+		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		conf->secondary_channel = -1;
+	}
+	if (os_strstr(capab, "[HT40+]")) {
+		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		conf->secondary_channel = 1;
+	}
+	if (os_strstr(capab, "[SMPS-STATIC]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
+	}
+	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
+	}
+	if (os_strstr(capab, "[GF]"))
+		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+	if (os_strstr(capab, "[SHORT-GI-20]"))
+		conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
+	if (os_strstr(capab, "[SHORT-GI-40]"))
+		conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
+	if (os_strstr(capab, "[TX-STBC]"))
+		conf->ht_capab |= HT_CAP_INFO_TX_STBC;
+	if (os_strstr(capab, "[RX-STBC1]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
+	}
+	if (os_strstr(capab, "[RX-STBC12]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
+	}
+	if (os_strstr(capab, "[RX-STBC123]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
+	}
+	if (os_strstr(capab, "[DELAYED-BA]"))
+		conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
+	if (os_strstr(capab, "[MAX-AMSDU-7935]"))
+		conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
+	if (os_strstr(capab, "[DSSS_CCK-40]"))
+		conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
+	if (os_strstr(capab, "[PSMP]"))
+		conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+	if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
+		conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+#ifdef CONFIG_IEEE80211AC
+static int hostapd_config_vht_capab(struct hostapd_config *conf,
+				    const char *capab)
+{
+	if (os_strstr(capab, "[MAX-MPDU-7991]"))
+		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
+	if (os_strstr(capab, "[MAX-MPDU-11454]"))
+		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
+	if (os_strstr(capab, "[VHT160]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+	if (os_strstr(capab, "[VHT160-80PLUS80]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+	if (os_strstr(capab, "[VHT160-80PLUS80]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+	if (os_strstr(capab, "[RXLDPC]"))
+		conf->vht_capab |= VHT_CAP_RXLDPC;
+	if (os_strstr(capab, "[SHORT-GI-80]"))
+		conf->vht_capab |= VHT_CAP_SHORT_GI_80;
+	if (os_strstr(capab, "[SHORT-GI-160]"))
+		conf->vht_capab |= VHT_CAP_SHORT_GI_160;
+	if (os_strstr(capab, "[TX-STBC-2BY1]"))
+		conf->vht_capab |= VHT_CAP_TXSTBC;
+	if (os_strstr(capab, "[RX-STBC-1]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_1;
+	if (os_strstr(capab, "[RX-STBC-12]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_2;
+	if (os_strstr(capab, "[RX-STBC-123]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_3;
+	if (os_strstr(capab, "[RX-STBC-1234]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_4;
+	if (os_strstr(capab, "[SU-BEAMFORMER]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
+	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
+	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+	if (os_strstr(capab, "[MU-BEAMFORMER]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+	if (os_strstr(capab, "[VHT-TXOP-PS]"))
+		conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
+	if (os_strstr(capab, "[HTC-VHT]"))
+		conf->vht_capab |= VHT_CAP_HTC_VHT;
+	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+	if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
+	    (conf->vht_capab & VHT_CAP_HTC_VHT))
+		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
+	if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
+	    (conf->vht_capab & VHT_CAP_HTC_VHT))
+		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+	if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
+		conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+	if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+		conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
+	return 0;
+}
+#endif /* CONFIG_IEEE80211AC */
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf)
+{
+	if (bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
+		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+			   "EAP authenticator configured).");
+		return -1;
+	}
+
+	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
+	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+			   "is not configured.");
+		return -1;
+	}
+
+	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if ((&conf->bss[i] != bss) &&
+			    (hostapd_mac_comp(conf->bss[i].bssid,
+					      bss->bssid) == 0)) {
+				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+					   " on interface '%s' and '%s'.",
+					   MAC2STR(bss->bssid),
+					   conf->bss[i].iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    (bss->nas_identifier == NULL ||
+	     os_strlen(bss->nas_identifier) < 1 ||
+	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+			   "nas_identifier to be configured as a 1..48 octet "
+			   "string");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+			   "allowed, disabling HT capabilites");
+	}
+
+	if (conf->ieee80211n &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+			   "allowed, disabling HT capabilities");
+	}
+
+	if (conf->ieee80211n && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+			   "requires CCMP/GCMP to be enabled, disabling HT "
+			   "capabilities");
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+	if (bss->wps_state && bss->ignore_broadcast_ssid) {
+		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+			   "configuration forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+			   "disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->wpa &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+			   "WPA2/CCMP forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+	if (bss->hs20 &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+			   "configuration is required for Hotspot 2.0 "
+			   "functionality");
+		return -1;
+	}
+#endif /* CONFIG_HS20 */
+
+	return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+			   "setting the country_code");
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(&conf->bss[i], conf))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
+				    int line)
+{
+	size_t len = os_strlen(pos);
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+
+	struct hostapd_roaming_consortium *rc;
+
+	if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
+	    hexstr2bin(pos, oi, len / 2)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
+			   "'%s'", line, pos);
+		return -1;
+	}
+	len /= 2;
+
+	rc = os_realloc_array(bss->roaming_consortium,
+			      bss->roaming_consortium_count + 1,
+			      sizeof(struct hostapd_roaming_consortium));
+	if (rc == NULL)
+		return -1;
+
+	os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
+	rc[bss->roaming_consortium_count].len = len;
+
+	bss->roaming_consortium = rc;
+	bss->roaming_consortium_count++;
+
+	return 0;
+}
+
+
+static int parse_lang_string(struct hostapd_lang_string **array,
+			     unsigned int *count, char *pos)
+{
+	char *sep;
+	size_t clen, nlen;
+	struct hostapd_lang_string *ls;
+
+	sep = os_strchr(pos, ':');
+	if (sep == NULL)
+		return -1;
+	*sep++ = '\0';
+
+	clen = os_strlen(pos);
+	if (clen < 2)
+		return -1;
+	nlen = os_strlen(sep);
+	if (nlen > 252)
+		return -1;
+
+	ls = os_realloc_array(*array, *count + 1,
+			      sizeof(struct hostapd_lang_string));
+	if (ls == NULL)
+		return -1;
+
+	*array = ls;
+	ls = &(*array)[*count];
+	(*count)++;
+
+	os_memset(ls->lang, 0, sizeof(ls->lang));
+	os_memcpy(ls->lang, pos, clen);
+	ls->name_len = nlen;
+	os_memcpy(ls->name, sep, nlen);
+
+	return 0;
+}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+			    int line)
+{
+	if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+			   line, pos);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
+			       int line)
+{
+	size_t count;
+	char *pos;
+	u8 *info = NULL, *ipos;
+
+	/* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
+
+	count = 1;
+	for (pos = buf; *pos; pos++) {
+		if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+			goto fail;
+		if (*pos == ';')
+			count++;
+	}
+	if (1 + count * 3 > 0x7f)
+		goto fail;
+
+	info = os_zalloc(2 + 3 + count * 3);
+	if (info == NULL)
+		return -1;
+
+	ipos = info;
+	*ipos++ = 0; /* GUD - Version 1 */
+	*ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
+	*ipos++ = 0; /* PLMN List IEI */
+	/* ext(b8) | Length of PLMN List value contents(b7..1) */
+	*ipos++ = 1 + count * 3;
+	*ipos++ = count; /* Number of PLMNs */
+
+	pos = buf;
+	while (pos && *pos) {
+		char *mcc, *mnc;
+		size_t mnc_len;
+
+		mcc = pos;
+		mnc = os_strchr(pos, ',');
+		if (mnc == NULL)
+			goto fail;
+		*mnc++ = '\0';
+		pos = os_strchr(mnc, ';');
+		if (pos)
+			*pos++ = '\0';
+
+		mnc_len = os_strlen(mnc);
+		if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
+			goto fail;
+
+		/* BC coded MCC,MNC */
+		/* MCC digit 2 | MCC digit 1 */
+		*ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
+		/* MNC digit 3 | MCC digit 3 */
+		*ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
+			(mcc[2] - '0');
+		/* MNC digit 2 | MNC digit 1 */
+		*ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
+	}
+
+	os_free(bss->anqp_3gpp_cell_net);
+	bss->anqp_3gpp_cell_net = info;
+	bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
+	wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
+		    bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
+		   line, buf);
+	os_free(info);
+	return -1;
+}
+
+
+static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
+{
+	struct hostapd_nai_realm_data *realm;
+	size_t i, j, len;
+	int *offsets;
+	char *pos, *end, *rpos;
+
+	offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
+			    sizeof(int));
+	if (offsets == NULL)
+		return -1;
+
+	for (i = 0; i < bss->nai_realm_count; i++) {
+		realm = &bss->nai_realm_data[i];
+		for (j = 0; j < MAX_NAI_REALMS; j++) {
+			offsets[i * MAX_NAI_REALMS + j] =
+				realm->realm[j] ?
+				realm->realm[j] - realm->realm_buf : -1;
+		}
+	}
+
+	realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
+				 sizeof(struct hostapd_nai_realm_data));
+	if (realm == NULL) {
+		os_free(offsets);
+		return -1;
+	}
+	bss->nai_realm_data = realm;
+
+	/* patch the pointers after realloc */
+	for (i = 0; i < bss->nai_realm_count; i++) {
+		realm = &bss->nai_realm_data[i];
+		for (j = 0; j < MAX_NAI_REALMS; j++) {
+			int offs = offsets[i * MAX_NAI_REALMS + j];
+			if (offs >= 0)
+				realm->realm[j] = realm->realm_buf + offs;
+			else
+				realm->realm[j] = NULL;
+		}
+	}
+	os_free(offsets);
+
+	realm = &bss->nai_realm_data[bss->nai_realm_count];
+	os_memset(realm, 0, sizeof(*realm));
+
+	pos = buf;
+	realm->encoding = atoi(pos);
+	pos = os_strchr(pos, ',');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	end = os_strchr(pos, ',');
+	if (end) {
+		len = end - pos;
+		*end = '\0';
+	} else {
+		len = os_strlen(pos);
+	}
+
+	if (len > MAX_NAI_REALMLEN) {
+		wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
+			   "characters)", (int) len, MAX_NAI_REALMLEN);
+		goto fail;
+	}
+	os_memcpy(realm->realm_buf, pos, len);
+
+	if (end)
+		pos = end + 1;
+	else
+		pos = NULL;
+
+	while (pos && *pos) {
+		struct hostapd_nai_realm_eap *eap;
+
+		if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
+			wpa_printf(MSG_ERROR, "Too many EAP methods");
+			goto fail;
+		}
+
+		eap = &realm->eap_method[realm->eap_method_count];
+		realm->eap_method_count++;
+
+		end = os_strchr(pos, ',');
+		if (end == NULL)
+			end = pos + os_strlen(pos);
+
+		eap->eap_method = atoi(pos);
+		for (;;) {
+			pos = os_strchr(pos, '[');
+			if (pos == NULL || pos > end)
+				break;
+			pos++;
+			if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
+				wpa_printf(MSG_ERROR, "Too many auth params");
+				goto fail;
+			}
+			eap->auth_id[eap->num_auths] = atoi(pos);
+			pos = os_strchr(pos, ':');
+			if (pos == NULL || pos > end)
+				goto fail;
+			pos++;
+			eap->auth_val[eap->num_auths] = atoi(pos);
+			pos = os_strchr(pos, ']');
+			if (pos == NULL || pos > end)
+				goto fail;
+			pos++;
+			eap->num_auths++;
+		}
+
+		if (*end != ',')
+			break;
+
+		pos = end + 1;
+	}
+
+	/* Split realm list into null terminated realms */
+	rpos = realm->realm_buf;
+	i = 0;
+	while (*rpos) {
+		if (i >= MAX_NAI_REALMS) {
+			wpa_printf(MSG_ERROR, "Too many realms");
+			goto fail;
+		}
+		realm->realm[i++] = rpos;
+		rpos = os_strchr(rpos, ';');
+		if (rpos == NULL)
+			break;
+		*rpos++ = '\0';
+	}
+
+	bss->nai_realm_count++;
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
+	return -1;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+				 int line)
+{
+	u8 *conn_cap;
+	char *pos;
+
+	if (bss->hs20_connection_capability_len >= 0xfff0)
+		return -1;
+
+	conn_cap = os_realloc(bss->hs20_connection_capability,
+			      bss->hs20_connection_capability_len + 4);
+	if (conn_cap == NULL)
+		return -1;
+
+	bss->hs20_connection_capability = conn_cap;
+	conn_cap += bss->hs20_connection_capability_len;
+	pos = buf;
+	conn_cap[0] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	WPA_PUT_LE16(conn_cap + 1, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	conn_cap[3] = atoi(pos);
+	bss->hs20_connection_capability_len += 4;
+
+	return 0;
+}
+
+
+static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
+				  int line)
+{
+	u8 *wan_metrics;
+	char *pos;
+
+	/* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
+
+	wan_metrics = os_zalloc(13);
+	if (wan_metrics == NULL)
+		return -1;
+
+	pos = buf;
+	/* WAN Info */
+	if (hexstr2bin(pos, wan_metrics, 1) < 0)
+		goto fail;
+	pos += 2;
+	if (*pos != ':')
+		goto fail;
+	pos++;
+
+	/* Downlink Speed */
+	WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Uplink Speed */
+	WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Downlink Load */
+	wan_metrics[9] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Uplink Load */
+	wan_metrics[10] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* LMD */
+	WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
+
+	os_free(bss->hs20_wan_metrics);
+	bss->hs20_wan_metrics = wan_metrics;
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
+		   line, pos);
+	os_free(wan_metrics);
+	return -1;
+}
+
+
+static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
+					 char *pos, int line)
+{
+	if (parse_lang_string(&bss->hs20_oper_friendly_name,
+			      &bss->hs20_oper_friendly_name_count, pos)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid "
+			   "hs20_oper_friendly_name '%s'", line, pos);
+		return -1;
+	}
+	return 0;
+}
+#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 */
+
+
+static int hostapd_config_fill(struct hostapd_config *conf,
+			       struct hostapd_bss_config *bss,
+			       char *buf, char *pos, int line)
+{
+	int errors = 0;
+
+	{
+		if (os_strcmp(buf, "interface") == 0) {
+			os_strlcpy(conf->bss[0].iface, pos,
+				   sizeof(conf->bss[0].iface));
+		} else if (os_strcmp(buf, "bridge") == 0) {
+			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+		} else if (os_strcmp(buf, "wds_bridge") == 0) {
+			os_strlcpy(bss->wds_bridge, pos,
+				   sizeof(bss->wds_bridge));
+		} else if (os_strcmp(buf, "driver") == 0) {
+			int j;
+			/* clear to get error below if setting is invalid */
+			conf->driver = NULL;
+			for (j = 0; wpa_drivers[j]; j++) {
+				if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
+				{
+					conf->driver = wpa_drivers[j];
+					break;
+				}
+			}
+			if (conf->driver == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid/"
+					   "unknown driver '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "debug") == 0) {
+			wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
+				   "configuration variable is not used "
+				   "anymore", line);
+		} else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+			bss->logger_syslog_level = atoi(pos);
+		} else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+			bss->logger_stdout_level = atoi(pos);
+		} else if (os_strcmp(buf, "logger_syslog") == 0) {
+			bss->logger_syslog = atoi(pos);
+		} else if (os_strcmp(buf, "logger_stdout") == 0) {
+			bss->logger_stdout = atoi(pos);
+		} else if (os_strcmp(buf, "dump_file") == 0) {
+			bss->dump_log_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "ssid") == 0) {
+			bss->ssid.ssid_len = os_strlen(pos);
+			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+			    bss->ssid.ssid_len < 1) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+					   "'%s'", line, pos);
+				errors++;
+			} else {
+				os_memcpy(bss->ssid.ssid, pos,
+					  bss->ssid.ssid_len);
+				bss->ssid.ssid_set = 1;
+			}
+		} else if (os_strcmp(buf, "ssid2") == 0) {
+			size_t slen;
+			char *str = wpa_config_parse_string(pos, &slen);
+			if (str == NULL || slen < 1 ||
+				   slen > HOSTAPD_MAX_SSID_LEN) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+					   "'%s'", line, pos);
+				errors++;
+			} else {
+				os_memcpy(bss->ssid.ssid, str, slen);
+				bss->ssid.ssid_len = slen;
+				bss->ssid.ssid_set = 1;
+			}
+			os_free(str);
+		} else if (os_strcmp(buf, "utf8_ssid") == 0) {
+			bss->ssid.utf8_ssid = atoi(pos) > 0;
+		} else if (os_strcmp(buf, "macaddr_acl") == 0) {
+			bss->macaddr_acl = atoi(pos);
+			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "macaddr_acl %d",
+					   line, bss->macaddr_acl);
+			}
+		} else if (os_strcmp(buf, "accept_mac_file") == 0) {
+			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+							&bss->num_accept_mac))
+			{
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "read accept_mac_file '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "deny_mac_file") == 0) {
+			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+							&bss->num_deny_mac)) {
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "read deny_mac_file '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wds_sta") == 0) {
+			bss->wds_sta = atoi(pos);
+		} else if (os_strcmp(buf, "ap_isolate") == 0) {
+			bss->isolate = atoi(pos);
+		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+			bss->ap_max_inactivity = atoi(pos);
+		} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
+			bss->skip_inactivity_poll = atoi(pos);
+		} else if (os_strcmp(buf, "country_code") == 0) {
+			os_memcpy(conf->country, pos, 2);
+			/* FIX: make this configurable */
+			conf->country[2] = ' ';
+		} else if (os_strcmp(buf, "ieee80211d") == 0) {
+			conf->ieee80211d = atoi(pos);
+		} else if (os_strcmp(buf, "ieee8021x") == 0) {
+			bss->ieee802_1x = atoi(pos);
+		} else if (os_strcmp(buf, "eapol_version") == 0) {
+			bss->eapol_version = atoi(pos);
+			if (bss->eapol_version < 1 ||
+			    bss->eapol_version > 2) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
+					   "version (%d): '%s'.",
+					   line, bss->eapol_version, pos);
+				errors++;
+			} else
+				wpa_printf(MSG_DEBUG, "eapol_version=%d",
+					   bss->eapol_version);
+#ifdef EAP_SERVER
+		} else if (os_strcmp(buf, "eap_authenticator") == 0) {
+			bss->eap_server = atoi(pos);
+			wpa_printf(MSG_ERROR, "Line %d: obsolete "
+				   "eap_authenticator used; this has been "
+				   "renamed to eap_server", line);
+		} else if (os_strcmp(buf, "eap_server") == 0) {
+			bss->eap_server = atoi(pos);
+		} else if (os_strcmp(buf, "eap_user_file") == 0) {
+			if (hostapd_config_read_eap_user(pos, bss))
+				errors++;
+		} else if (os_strcmp(buf, "ca_cert") == 0) {
+			os_free(bss->ca_cert);
+			bss->ca_cert = os_strdup(pos);
+		} else if (os_strcmp(buf, "server_cert") == 0) {
+			os_free(bss->server_cert);
+			bss->server_cert = os_strdup(pos);
+		} else if (os_strcmp(buf, "private_key") == 0) {
+			os_free(bss->private_key);
+			bss->private_key = os_strdup(pos);
+		} else if (os_strcmp(buf, "private_key_passwd") == 0) {
+			os_free(bss->private_key_passwd);
+			bss->private_key_passwd = os_strdup(pos);
+		} else if (os_strcmp(buf, "check_crl") == 0) {
+			bss->check_crl = atoi(pos);
+		} else if (os_strcmp(buf, "dh_file") == 0) {
+			os_free(bss->dh_file);
+			bss->dh_file = os_strdup(pos);
+		} else if (os_strcmp(buf, "fragment_size") == 0) {
+			bss->fragment_size = atoi(pos);
+#ifdef EAP_SERVER_FAST
+		} else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+			os_free(bss->pac_opaque_encr_key);
+			bss->pac_opaque_encr_key = os_malloc(16);
+			if (bss->pac_opaque_encr_key == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: No memory for "
+					   "pac_opaque_encr_key", line);
+				errors++;
+			} else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
+					      16)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "pac_opaque_encr_key", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+			size_t idlen = os_strlen(pos);
+			if (idlen & 1) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "eap_fast_a_id", line);
+				errors++;
+			} else {
+				os_free(bss->eap_fast_a_id);
+				bss->eap_fast_a_id = os_malloc(idlen / 2);
+				if (bss->eap_fast_a_id == NULL ||
+				    hexstr2bin(pos, bss->eap_fast_a_id,
+					       idlen / 2)) {
+					wpa_printf(MSG_ERROR, "Line %d: "
+						   "Failed to parse "
+						   "eap_fast_a_id", line);
+					errors++;
+				} else
+					bss->eap_fast_a_id_len = idlen / 2;
+			}
+		} else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+			os_free(bss->eap_fast_a_id_info);
+			bss->eap_fast_a_id_info = os_strdup(pos);
+		} else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+			bss->eap_fast_prov = atoi(pos);
+		} else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+			bss->pac_key_lifetime = atoi(pos);
+		} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+			bss->pac_key_refresh_time = atoi(pos);
+#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_SIM
+		} 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_aka_result_ind") == 0) {
+			bss->eap_sim_aka_result_ind = atoi(pos);
+#endif /* EAP_SERVER_SIM */
+#ifdef EAP_SERVER_TNC
+		} else if (os_strcmp(buf, "tnc") == 0) {
+			bss->tnc = atoi(pos);
+#endif /* EAP_SERVER_TNC */
+#ifdef EAP_SERVER_PWD
+		} else if (os_strcmp(buf, "pwd_group") == 0) {
+			bss->pwd_group = atoi(pos);
+#endif /* EAP_SERVER_PWD */
+#endif /* EAP_SERVER */
+		} else if (os_strcmp(buf, "eap_message") == 0) {
+			char *term;
+			bss->eap_req_id_text = os_strdup(pos);
+			if (bss->eap_req_id_text == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "allocate memory for "
+					   "eap_req_id_text", line);
+				errors++;
+				return errors;
+			}
+			bss->eap_req_id_text_len =
+				os_strlen(bss->eap_req_id_text);
+			term = os_strstr(bss->eap_req_id_text, "\\0");
+			if (term) {
+				*term++ = '\0';
+				os_memmove(term, term + 1,
+					   bss->eap_req_id_text_len -
+					   (term - bss->eap_req_id_text) - 1);
+				bss->eap_req_id_text_len--;
+			}
+		} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
+			bss->default_wep_key_len = atoi(pos);
+			if (bss->default_wep_key_len > 13) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key len %lu (= %lu bits)", line,
+					   (unsigned long)
+					   bss->default_wep_key_len,
+					   (unsigned long)
+					   bss->default_wep_key_len * 8);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
+			bss->individual_wep_key_len = atoi(pos);
+			if (bss->individual_wep_key_len < 0 ||
+			    bss->individual_wep_key_len > 13) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key len %d (= %d bits)", line,
+					   bss->individual_wep_key_len,
+					   bss->individual_wep_key_len * 8);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+			bss->wep_rekeying_period = atoi(pos);
+			if (bss->wep_rekeying_period < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "period %d",
+					   line, bss->wep_rekeying_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+			bss->eap_reauth_period = atoi(pos);
+			if (bss->eap_reauth_period < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "period %d",
+					   line, bss->eap_reauth_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+			bss->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+		} else if (os_strcmp(buf, "iapp_interface") == 0) {
+			bss->ieee802_11f = 1;
+			os_strlcpy(bss->iapp_iface, pos,
+				   sizeof(bss->iapp_iface));
+#endif /* CONFIG_IAPP */
+		} else if (os_strcmp(buf, "own_ip_addr") == 0) {
+			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "nas_identifier") == 0) {
+			bss->nas_identifier = os_strdup(pos);
+#ifndef CONFIG_NO_RADIUS
+		} else if (os_strcmp(buf, "auth_server_addr") == 0) {
+			if (hostapd_config_read_radius_addr(
+				    &bss->radius->auth_servers,
+				    &bss->radius->num_auth_servers, pos, 1812,
+				    &bss->radius->auth_server)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (bss->radius->auth_server &&
+			   os_strcmp(buf, "auth_server_port") == 0) {
+			bss->radius->auth_server->port = atoi(pos);
+		} else if (bss->radius->auth_server &&
+			   os_strcmp(buf, "auth_server_shared_secret") == 0) {
+			int len = os_strlen(pos);
+			if (len == 0) {
+				/* RFC 2865, Ch. 3 */
+				wpa_printf(MSG_ERROR, "Line %d: empty shared "
+					   "secret is not allowed.", line);
+				errors++;
+			}
+			bss->radius->auth_server->shared_secret =
+				(u8 *) os_strdup(pos);
+			bss->radius->auth_server->shared_secret_len = len;
+		} else if (os_strcmp(buf, "acct_server_addr") == 0) {
+			if (hostapd_config_read_radius_addr(
+				    &bss->radius->acct_servers,
+				    &bss->radius->num_acct_servers, pos, 1813,
+				    &bss->radius->acct_server)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (bss->radius->acct_server &&
+			   os_strcmp(buf, "acct_server_port") == 0) {
+			bss->radius->acct_server->port = atoi(pos);
+		} else if (bss->radius->acct_server &&
+			   os_strcmp(buf, "acct_server_shared_secret") == 0) {
+			int len = os_strlen(pos);
+			if (len == 0) {
+				/* RFC 2865, Ch. 3 */
+				wpa_printf(MSG_ERROR, "Line %d: empty shared "
+					   "secret is not allowed.", line);
+				errors++;
+			}
+			bss->radius->acct_server->shared_secret =
+				(u8 *) os_strdup(pos);
+			bss->radius->acct_server->shared_secret_len = len;
+		} else if (os_strcmp(buf, "radius_retry_primary_interval") ==
+			   0) {
+			bss->radius->retry_primary_interval = atoi(pos);
+		} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
+		{
+			bss->acct_interim_interval = atoi(pos);
+		} else if (os_strcmp(buf, "radius_request_cui") == 0) {
+			bss->radius_request_cui = atoi(pos);
+		} else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+			struct hostapd_radius_attr *attr, *a;
+			attr = hostapd_parse_radius_attr(pos);
+			if (attr == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "radius_auth_req_attr", line);
+				errors++;
+			} else if (bss->radius_auth_req_attr == NULL) {
+				bss->radius_auth_req_attr = attr;
+			} else {
+				a = bss->radius_auth_req_attr;
+				while (a->next)
+					a = a->next;
+				a->next = attr;
+			}
+		} else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+			struct hostapd_radius_attr *attr, *a;
+			attr = hostapd_parse_radius_attr(pos);
+			if (attr == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "radius_acct_req_attr", line);
+				errors++;
+			} else if (bss->radius_acct_req_attr == NULL) {
+				bss->radius_acct_req_attr = attr;
+			} else {
+				a = bss->radius_acct_req_attr;
+				while (a->next)
+					a = a->next;
+				a->next = attr;
+			}
+		} else if (os_strcmp(buf, "radius_das_port") == 0) {
+			bss->radius_das_port = atoi(pos);
+		} else if (os_strcmp(buf, "radius_das_client") == 0) {
+			if (hostapd_parse_das_client(bss, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "DAS client", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+			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);
+#endif /* CONFIG_NO_RADIUS */
+		} else if (os_strcmp(buf, "auth_algs") == 0) {
+			bss->auth_algs = atoi(pos);
+			if (bss->auth_algs == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: no "
+					   "authentication algorithms allowed",
+					   line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "max_num_sta") == 0) {
+			bss->max_num_sta = atoi(pos);
+			if (bss->max_num_sta < 0 ||
+			    bss->max_num_sta > MAX_STA_COUNT) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "max_num_sta=%d; allowed range "
+					   "0..%d", line, bss->max_num_sta,
+					   MAX_STA_COUNT);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa") == 0) {
+			bss->wpa = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+			bss->wpa_group_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+			bss->wpa_strict_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+			bss->wpa_gmk_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+			bss->wpa_ptk_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+			int len = os_strlen(pos);
+			if (len < 8 || len > 63) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
+					   "passphrase length %d (expected "
+					   "8..63)", line, len);
+				errors++;
+			} else {
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = os_strdup(pos);
+				os_free(bss->ssid.wpa_psk);
+				bss->ssid.wpa_psk = NULL;
+			}
+		} else if (os_strcmp(buf, "wpa_psk") == 0) {
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk =
+				os_zalloc(sizeof(struct hostapd_wpa_psk));
+			if (bss->ssid.wpa_psk == NULL)
+				errors++;
+			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+					    PMK_LEN) ||
+				 pos[PMK_LEN * 2] != '\0') {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
+					   "'%s'.", line, pos);
+				errors++;
+			} else {
+				bss->ssid.wpa_psk->group = 1;
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = NULL;
+			}
+		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+			os_free(bss->ssid.wpa_psk_file);
+			bss->ssid.wpa_psk_file = os_strdup(pos);
+			if (!bss->ssid.wpa_psk_file) {
+				wpa_printf(MSG_ERROR, "Line %d: allocation "
+					   "failed", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+			bss->wpa_key_mgmt =
+				hostapd_config_parse_key_mgmt(line, pos);
+			if (bss->wpa_key_mgmt == -1)
+				errors++;
+		} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+			bss->wpa_psk_radius = atoi(pos);
+			if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wpa_psk_radius %d",
+					   line, bss->wpa_psk_radius);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+			bss->wpa_pairwise =
+				hostapd_config_parse_cipher(line, pos);
+			if (bss->wpa_pairwise == -1 ||
+			    bss->wpa_pairwise == 0)
+				errors++;
+			else if (bss->wpa_pairwise &
+				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+				  WPA_CIPHER_WEP104)) {
+				wpa_printf(MSG_ERROR, "Line %d: unsupported "
+					   "pairwise cipher suite '%s'",
+					   bss->wpa_pairwise, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+			bss->rsn_pairwise =
+				hostapd_config_parse_cipher(line, pos);
+			if (bss->rsn_pairwise == -1 ||
+			    bss->rsn_pairwise == 0)
+				errors++;
+			else if (bss->rsn_pairwise &
+				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+				  WPA_CIPHER_WEP104)) {
+				wpa_printf(MSG_ERROR, "Line %d: unsupported "
+					   "pairwise cipher suite '%s'",
+					   bss->rsn_pairwise, pos);
+				errors++;
+			}
+#ifdef CONFIG_RSN_PREAUTH
+		} else if (os_strcmp(buf, "rsn_preauth") == 0) {
+			bss->rsn_preauth = atoi(pos);
+		} else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+			bss->rsn_preauth_interfaces = os_strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+		} else if (os_strcmp(buf, "peerkey") == 0) {
+			bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+		} else if (os_strcmp(buf, "mobility_domain") == 0) {
+			if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+			    hexstr2bin(pos, bss->mobility_domain,
+				       MOBILITY_DOMAIN_ID_LEN) != 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "mobility_domain '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r1_key_holder") == 0) {
+			if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+			    hexstr2bin(pos, bss->r1_key_holder,
+				       FT_R1KH_ID_LEN) != 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r1_key_holder '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+			bss->r0_key_lifetime = atoi(pos);
+		} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+			bss->reassociation_deadline = atoi(pos);
+		} else if (os_strcmp(buf, "r0kh") == 0) {
+			if (add_r0kh(bss, pos) < 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r0kh '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r1kh") == 0) {
+			if (add_r1kh(bss, pos) < 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r1kh '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+			bss->pmk_r1_push = atoi(pos);
+		} else if (os_strcmp(buf, "ft_over_ds") == 0) {
+			bss->ft_over_ds = atoi(pos);
+#endif /* CONFIG_IEEE80211R */
+#ifndef CONFIG_NO_CTRL_IFACE
+		} else if (os_strcmp(buf, "ctrl_interface") == 0) {
+			os_free(bss->ctrl_interface);
+			bss->ctrl_interface = os_strdup(pos);
+		} else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
+			struct group *grp;
+			char *endp;
+			const char *group = pos;
+
+			grp = getgrnam(group);
+			if (grp) {
+				bss->ctrl_interface_gid = grp->gr_gid;
+				bss->ctrl_interface_gid_set = 1;
+				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+					   " (from group name '%s')",
+					   bss->ctrl_interface_gid, group);
+				return errors;
+			}
+
+			/* Group name not found - try to parse this as gid */
+			bss->ctrl_interface_gid = strtol(group, &endp, 10);
+			if (*group == '\0' || *endp != '\0') {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+					   "'%s'", line, group);
+				errors++;
+				return errors;
+			}
+			bss->ctrl_interface_gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+				   bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_NO_CTRL_IFACE */
+#ifdef RADIUS_SERVER
+		} else if (os_strcmp(buf, "radius_server_clients") == 0) {
+			os_free(bss->radius_server_clients);
+			bss->radius_server_clients = os_strdup(pos);
+		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+			bss->radius_server_auth_port = atoi(pos);
+		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+			bss->radius_server_ipv6 = atoi(pos);
+#endif /* RADIUS_SERVER */
+		} else if (os_strcmp(buf, "test_socket") == 0) {
+			os_free(bss->test_socket);
+			bss->test_socket = os_strdup(pos);
+		} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+			bss->use_pae_group_addr = atoi(pos);
+		} else if (os_strcmp(buf, "hw_mode") == 0) {
+			if (os_strcmp(pos, "a") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+			else if (os_strcmp(pos, "b") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+			else if (os_strcmp(pos, "g") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+			else if (os_strcmp(pos, "ad") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+			else {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "hw_mode '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+			if (os_strcmp(pos, "a") == 0)
+				bss->wps_rf_bands = WPS_RF_50GHZ;
+			else if (os_strcmp(pos, "g") == 0 ||
+				 os_strcmp(pos, "b") == 0)
+				bss->wps_rf_bands = WPS_RF_24GHZ;
+			else if (os_strcmp(pos, "ag") == 0 ||
+				 os_strcmp(pos, "ga") == 0)
+				bss->wps_rf_bands =
+					WPS_RF_24GHZ | WPS_RF_50GHZ;
+			else {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wps_rf_band '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "channel") == 0) {
+			conf->channel = atoi(pos);
+		} else if (os_strcmp(buf, "beacon_int") == 0) {
+			int val = atoi(pos);
+			/* MIB defines range as 1..65535, but very small values
+			 * cause problems with the current implementation.
+			 * Since it is unlikely that this small numbers are
+			 * useful in real life scenarios, do not allow beacon
+			 * period to be set below 15 TU. */
+			if (val < 15 || val > 65535) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "beacon_int %d (expected "
+					   "15..65535)", line, val);
+				errors++;
+			} else
+				conf->beacon_int = val;
+		} else if (os_strcmp(buf, "dtim_period") == 0) {
+			bss->dtim_period = atoi(pos);
+			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "dtim_period %d",
+					   line, bss->dtim_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "rts_threshold") == 0) {
+			conf->rts_threshold = atoi(pos);
+			if (conf->rts_threshold < 0 ||
+			    conf->rts_threshold > 2347) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "rts_threshold %d",
+					   line, conf->rts_threshold);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "fragm_threshold") == 0) {
+			conf->fragm_threshold = atoi(pos);
+			if (conf->fragm_threshold < 256 ||
+			    conf->fragm_threshold > 2346) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "fragm_threshold %d",
+					   line, conf->fragm_threshold);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "send_probe_response") == 0) {
+			int val = atoi(pos);
+			if (val != 0 && val != 1) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "send_probe_response %d (expected "
+					   "0 or 1)", line, val);
+			} else
+				conf->send_probe_response = val;
+		} else if (os_strcmp(buf, "supported_rates") == 0) {
+			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+					   "list", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "basic_rates") == 0) {
+			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+					   "list", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "preamble") == 0) {
+			if (atoi(pos))
+				conf->preamble = SHORT_PREAMBLE;
+			else
+				conf->preamble = LONG_PREAMBLE;
+		} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+			bss->ignore_broadcast_ssid = atoi(pos);
+		} else if (os_strcmp(buf, "wep_default_key") == 0) {
+			bss->ssid.wep.idx = atoi(pos);
+			if (bss->ssid.wep.idx > 3) {
+				wpa_printf(MSG_ERROR, "Invalid "
+					   "wep_default_key index %d",
+					   bss->ssid.wep.idx);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_key0") == 0 ||
+			   os_strcmp(buf, "wep_key1") == 0 ||
+			   os_strcmp(buf, "wep_key2") == 0 ||
+			   os_strcmp(buf, "wep_key3") == 0) {
+			if (hostapd_config_read_wep(&bss->ssid.wep,
+						    buf[7] - '0', pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key '%s'", line, buf);
+				errors++;
+			}
+#ifndef CONFIG_NO_VLAN
+		} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+			bss->ssid.dynamic_vlan = 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, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "vlan_naming") == 0) {
+			bss->ssid.vlan_naming = atoi(pos);
+			if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+			    bss->ssid.vlan_naming < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "naming scheme %d", line,
+                                           bss->ssid.vlan_naming);
+				errors++;
+                        }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+			bss->ssid.vlan_tagged_interface = os_strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#endif /* CONFIG_NO_VLAN */
+		} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+			conf->ap_table_max_size = atoi(pos);
+		} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+			conf->ap_table_expiration_time = atoi(pos);
+		} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+			if (hostapd_config_tx_queue(conf, buf, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid TX "
+					   "queue item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wme_enabled") == 0 ||
+			   os_strcmp(buf, "wmm_enabled") == 0) {
+			bss->wmm_enabled = atoi(pos);
+		} else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
+			bss->wmm_uapsd = atoi(pos);
+		} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
+			   os_strncmp(buf, "wmm_ac_", 7) == 0) {
+			if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+						  pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+					   "ac item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "bss") == 0) {
+			if (hostapd_config_bss(conf, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid bss "
+					   "item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "bssid") == 0) {
+			if (hwaddr_aton(pos, bss->bssid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
+					   "item", line);
+				errors++;
+			}
+#ifdef CONFIG_IEEE80211W
+		} else if (os_strcmp(buf, "ieee80211w") == 0) {
+			bss->ieee80211w = atoi(pos);
+		} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+			bss->assoc_sa_query_max_timeout = atoi(pos);
+			if (bss->assoc_sa_query_max_timeout == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "assoc_sa_query_max_timeout", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
+		{
+			bss->assoc_sa_query_retry_timeout = atoi(pos);
+			if (bss->assoc_sa_query_retry_timeout == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "assoc_sa_query_retry_timeout",
+					   line);
+				errors++;
+			}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211N
+		} else if (os_strcmp(buf, "ieee80211n") == 0) {
+			conf->ieee80211n = atoi(pos);
+		} else if (os_strcmp(buf, "ht_capab") == 0) {
+			if (hostapd_config_ht_capab(conf, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "ht_capab", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "require_ht") == 0) {
+			conf->require_ht = atoi(pos);
+#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
+			conf->ieee80211ac = atoi(pos);
+		} else if (os_strcmp(buf, "vht_capab") == 0) {
+			if (hostapd_config_vht_capab(conf, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "vht_capab", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "require_vht") == 0) {
+			conf->require_vht = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+			conf->vht_oper_chwidth = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
+		{
+			conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
+		{
+			conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+#endif /* CONFIG_IEEE80211AC */
+		} else if (os_strcmp(buf, "max_listen_interval") == 0) {
+			bss->max_listen_interval = atoi(pos);
+		} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
+			bss->disable_pmksa_caching = atoi(pos);
+		} else if (os_strcmp(buf, "okc") == 0) {
+			bss->okc = atoi(pos);
+#ifdef CONFIG_WPS
+		} else if (os_strcmp(buf, "wps_state") == 0) {
+			bss->wps_state = atoi(pos);
+			if (bss->wps_state < 0 || bss->wps_state > 2) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "wps_state", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+			bss->ap_setup_locked = atoi(pos);
+		} else if (os_strcmp(buf, "uuid") == 0) {
+			if (uuid_str2bin(pos, bss->uuid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
+					   line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+			os_free(bss->wps_pin_requests);
+			bss->wps_pin_requests = os_strdup(pos);
+		} else if (os_strcmp(buf, "device_name") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "device_name", line);
+				errors++;
+			}
+			os_free(bss->device_name);
+			bss->device_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "manufacturer") == 0) {
+			if (os_strlen(pos) > 64) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "manufacturer", line);
+				errors++;
+			}
+			os_free(bss->manufacturer);
+			bss->manufacturer = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_name") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "model_name", line);
+				errors++;
+			}
+			os_free(bss->model_name);
+			bss->model_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_number") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "model_number", line);
+				errors++;
+			}
+			os_free(bss->model_number);
+			bss->model_number = os_strdup(pos);
+		} else if (os_strcmp(buf, "serial_number") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "serial_number", line);
+				errors++;
+			}
+			os_free(bss->serial_number);
+			bss->serial_number = os_strdup(pos);
+		} else if (os_strcmp(buf, "device_type") == 0) {
+			if (wps_dev_type_str2bin(pos, bss->device_type))
+				errors++;
+		} else if (os_strcmp(buf, "config_methods") == 0) {
+			os_free(bss->config_methods);
+			bss->config_methods = os_strdup(pos);
+		} else if (os_strcmp(buf, "os_version") == 0) {
+			if (hexstr2bin(pos, bss->os_version, 4)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "os_version", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "ap_pin") == 0) {
+			os_free(bss->ap_pin);
+			bss->ap_pin = os_strdup(pos);
+		} else if (os_strcmp(buf, "skip_cred_build") == 0) {
+			bss->skip_cred_build = atoi(pos);
+		} else if (os_strcmp(buf, "extra_cred") == 0) {
+			os_free(bss->extra_cred);
+			bss->extra_cred =
+				(u8 *) os_readfile(pos, &bss->extra_cred_len);
+			if (bss->extra_cred == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: could not "
+					   "read Credentials from '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
+			bss->wps_cred_processing = atoi(pos);
+		} else if (os_strcmp(buf, "ap_settings") == 0) {
+			os_free(bss->ap_settings);
+			bss->ap_settings =
+				(u8 *) os_readfile(pos, &bss->ap_settings_len);
+			if (bss->ap_settings == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: could not "
+					   "read AP Settings from '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "upnp_iface") == 0) {
+			bss->upnp_iface = os_strdup(pos);
+		} else if (os_strcmp(buf, "friendly_name") == 0) {
+			os_free(bss->friendly_name);
+			bss->friendly_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "manufacturer_url") == 0) {
+			os_free(bss->manufacturer_url);
+			bss->manufacturer_url = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_description") == 0) {
+			os_free(bss->model_description);
+			bss->model_description = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_url") == 0) {
+			os_free(bss->model_url);
+			bss->model_url = os_strdup(pos);
+		} else if (os_strcmp(buf, "upc") == 0) {
+			os_free(bss->upc);
+			bss->upc = os_strdup(pos);
+		} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
+			bss->pbc_in_m1 = atoi(pos);
+#ifdef CONFIG_WPS_NFC
+		} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+			bss->wps_nfc_dev_pw_id = atoi(pos);
+			if (bss->wps_nfc_dev_pw_id < 0x10 ||
+			    bss->wps_nfc_dev_pw_id > 0xffff) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "wps_nfc_dev_pw_id value", line);
+				errors++;
+			}
+		} 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);
+		} 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);
+		} 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);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P_MANAGER
+		} else if (os_strcmp(buf, "manage_p2p") == 0) {
+			int manage = atoi(pos);
+			if (manage)
+				bss->p2p |= P2P_MANAGE;
+			else
+				bss->p2p &= ~P2P_MANAGE;
+		} else if (os_strcmp(buf, "allow_cross_connection") == 0) {
+			if (atoi(pos))
+				bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
+			else
+				bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
+#endif /* CONFIG_P2P_MANAGER */
+		} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
+			bss->disassoc_low_ack = atoi(pos);
+		} else if (os_strcmp(buf, "tdls_prohibit") == 0) {
+			int val = atoi(pos);
+			if (val)
+				bss->tdls |= TDLS_PROHIBIT;
+			else
+				bss->tdls &= ~TDLS_PROHIBIT;
+		} else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
+			int val = atoi(pos);
+			if (val)
+				bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
+			else
+				bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
+#ifdef CONFIG_RSN_TESTING
+		} else if (os_strcmp(buf, "rsn_testing") == 0) {
+			extern int rsn_testing;
+			rsn_testing = atoi(pos);
+#endif /* CONFIG_RSN_TESTING */
+		} else if (os_strcmp(buf, "time_advertisement") == 0) {
+			bss->time_advertisement = atoi(pos);
+		} else if (os_strcmp(buf, "time_zone") == 0) {
+			size_t tz_len = os_strlen(pos);
+			if (tz_len < 4 || tz_len > 255) {
+				wpa_printf(MSG_DEBUG, "Line %d: invalid "
+					   "time_zone", line);
+				errors++;
+				return errors;
+			}
+			os_free(bss->time_zone);
+			bss->time_zone = os_strdup(pos);
+			if (bss->time_zone == NULL)
+				errors++;
+#ifdef CONFIG_WNM
+		} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
+			bss->wnm_sleep_mode = atoi(pos);
+		} else if (os_strcmp(buf, "bss_transition") == 0) {
+			bss->bss_transition = atoi(pos);
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		} else if (os_strcmp(buf, "interworking") == 0) {
+			bss->interworking = atoi(pos);
+		} else if (os_strcmp(buf, "access_network_type") == 0) {
+			bss->access_network_type = atoi(pos);
+			if (bss->access_network_type < 0 ||
+			    bss->access_network_type > 15) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "access_network_type", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "internet") == 0) {
+			bss->internet = atoi(pos);
+		} else if (os_strcmp(buf, "asra") == 0) {
+			bss->asra = atoi(pos);
+		} else if (os_strcmp(buf, "esr") == 0) {
+			bss->esr = atoi(pos);
+		} else if (os_strcmp(buf, "uesa") == 0) {
+			bss->uesa = atoi(pos);
+		} else if (os_strcmp(buf, "venue_group") == 0) {
+			bss->venue_group = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "venue_type") == 0) {
+			bss->venue_type = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "hessid") == 0) {
+			if (hwaddr_aton(pos, bss->hessid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "hessid", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "roaming_consortium") == 0) {
+			if (parse_roaming_consortium(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "venue_name") == 0) {
+			if (parse_venue_name(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "network_auth_type") == 0) {
+			u8 auth_type;
+			u16 redirect_url_len;
+			if (hexstr2bin(pos, &auth_type, 1)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "network_auth_type '%s'",
+					   line, pos);
+				errors++;
+				return errors;
+			}
+			if (auth_type == 0 || auth_type == 2)
+				redirect_url_len = os_strlen(pos + 2);
+			else
+				redirect_url_len = 0;
+			os_free(bss->network_auth_type);
+			bss->network_auth_type =
+				os_malloc(redirect_url_len + 3 + 1);
+			if (bss->network_auth_type == NULL) {
+				errors++;
+				return errors;
+			}
+			*bss->network_auth_type = auth_type;
+			WPA_PUT_LE16(bss->network_auth_type + 1,
+				     redirect_url_len);
+			if (redirect_url_len)
+				os_memcpy(bss->network_auth_type + 3,
+					  pos + 2, redirect_url_len);
+			bss->network_auth_type_len = 3 + redirect_url_len;
+		} else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+			if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
+			{
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "ipaddr_type_availability '%s'",
+					   line, pos);
+				bss->ipaddr_type_configured = 0;
+				errors++;
+				return errors;
+			}
+			bss->ipaddr_type_configured = 1;
+		} else if (os_strcmp(buf, "domain_name") == 0) {
+			int j, num_domains, domain_len, domain_list_len = 0;
+			char *tok_start, *tok_prev;
+			u8 *domain_list, *domain_ptr;
+
+			domain_list_len = os_strlen(pos) + 1;
+			domain_list = os_malloc(domain_list_len);
+			if (domain_list == NULL) {
+				errors++;
+				return errors;
+			}
+
+			domain_ptr = domain_list;
+			tok_prev = pos;
+			num_domains = 1;
+			while ((tok_prev = os_strchr(tok_prev, ','))) {
+				num_domains++;
+				tok_prev++;
+			}
+			tok_prev = pos;
+			for (j = 0; j < num_domains; j++) {
+				tok_start = os_strchr(tok_prev, ',');
+				if (tok_start) {
+					domain_len = tok_start - tok_prev;
+					*domain_ptr = domain_len;
+					os_memcpy(domain_ptr + 1, tok_prev,
+						  domain_len);
+					domain_ptr += domain_len + 1;
+					tok_prev = ++tok_start;
+				} else {
+					domain_len = os_strlen(tok_prev);
+					*domain_ptr = domain_len;
+					os_memcpy(domain_ptr + 1, tok_prev,
+						  domain_len);
+					domain_ptr += domain_len + 1;
+				}
+			}
+
+			os_free(bss->domain_name);
+			bss->domain_name = domain_list;
+			bss->domain_name_len = domain_list_len;
+		} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+			if (parse_3gpp_cell_net(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "nai_realm") == 0) {
+			if (parse_nai_realm(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+			bss->gas_frag_limit = atoi(pos);
+		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+			bss->gas_comeback_delay = atoi(pos);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_RADIUS_TEST
+		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
+			os_free(bss->dump_msk_file);
+			bss->dump_msk_file = os_strdup(pos);
+#endif /* CONFIG_RADIUS_TEST */
+#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, "hs20_oper_friendly_name") == 0) {
+			if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+			if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+			if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+			u8 *oper_class;
+			size_t oper_class_len;
+			oper_class_len = os_strlen(pos);
+			if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "hs20_operating_class '%s'",
+					   line, pos);
+				errors++;
+				return errors;
+			}
+			oper_class_len /= 2;
+			oper_class = os_malloc(oper_class_len);
+			if (oper_class == NULL) {
+				errors++;
+				return errors;
+			}
+			if (hexstr2bin(pos, oper_class, oper_class_len)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "hs20_operating_class '%s'",
+					   line, pos);
+				os_free(oper_class);
+				errors++;
+				return errors;
+			}
+			os_free(bss->hs20_operating_class);
+			bss->hs20_operating_class = oper_class;
+			bss->hs20_operating_class_len = oper_class_len;
+#endif /* CONFIG_HS20 */
+		} 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)
+				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);
+				return 1;
+			}
+
+			wpabuf_free(bss->vendor_elements);
+			bss->vendor_elements = elems;
+		} else {
+			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
+				   "item '%s'", line, buf);
+			errors++;
+		}
+	}
+
+	return errors;
+}
+
+
+static void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+	int pairwise;
+
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for
+		 * broadcast keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	/* Select group cipher based on the enabled pairwise cipher
+	 * suites */
+	pairwise = 0;
+	if (bss->wpa & 1)
+		pairwise |= bss->wpa_pairwise;
+	if (bss->wpa & 2) {
+		if (bss->rsn_pairwise == 0)
+			bss->rsn_pairwise = bss->wpa_pairwise;
+		pairwise |= bss->rsn_pairwise;
+	}
+	if (pairwise & WPA_CIPHER_TKIP)
+		bss->wpa_group = WPA_CIPHER_TKIP;
+	else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+		 WPA_CIPHER_GCMP)
+		bss->wpa_group = WPA_CIPHER_GCMP;
+	else
+		bss->wpa_group = WPA_CIPHER_CCMP;
+
+	bss->radius->auth_server = bss->radius->auth_servers;
+	bss->radius->acct_server = bss->radius->acct_servers;
+
+	if (bss->wpa && bss->ieee802_1x) {
+		bss->ssid.security_policy = SECURITY_WPA;
+	} else if (bss->wpa) {
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	} else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+}
+
+
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
+	FILE *f;
+	char buf[512], *pos;
+	int line = 0;
+	int errors = 0;
+	size_t i;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+			   "for reading.", fname);
+		return NULL;
+	}
+
+	conf = hostapd_config_defaults();
+	if (conf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	/* set default driver based on configuration */
+	conf->driver = wpa_drivers[0];
+	if (conf->driver == NULL) {
+		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+		hostapd_config_free(conf);
+		fclose(f);
+		return NULL;
+	}
+
+	bss = conf->last_bss = conf->bss;
+
+	while (fgets(buf, sizeof(buf), f)) {
+		bss = conf->last_bss;
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		pos = os_strchr(buf, '=');
+		if (pos == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+				   line, buf);
+			errors++;
+			continue;
+		}
+		*pos = '\0';
+		pos++;
+		errors += hostapd_config_fill(conf, bss, buf, pos, line);
+	}
+
+	fclose(f);
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_set_security_params(&conf->bss[i]);
+
+	if (hostapd_config_check(conf))
+		errors++;
+
+#ifndef WPA_IGNORE_CONFIG_ERRORS
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d errors found in configuration file "
+			   "'%s'", errors, fname);
+		hostapd_config_free(conf);
+		conf = NULL;
+	}
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
+
+	return conf;
+}
+
+
+int hostapd_set_iface(struct hostapd_config *conf,
+		      struct hostapd_bss_config *bss, char *field, char *value)
+{
+	int errors;
+	size_t i;
+
+	errors = hostapd_config_fill(conf, bss, field, value, 0);
+	if (errors) {
+		wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
+			   "to value '%s'", field, value);
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_set_security_params(&conf->bss[i]);
+
+	if (hostapd_config_check(conf)) {
+		wpa_printf(MSG_ERROR, "Configuration check failed");
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/hostapd/config_file.h
===================================================================
--- vendor/wpa/dist/hostapd/config_file.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/config_file.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,20 +0,0 @@
-/*
- * hostapd / Configuration file parser
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CONFIG_FILE_H
-#define CONFIG_FILE_H
-
-struct hostapd_config * hostapd_config_read(const char *fname);
-
-#endif /* CONFIG_FILE_H */

Copied: vendor/wpa/2.0/hostapd/config_file.h (from rev 9639, vendor/wpa/dist/hostapd/config_file.h)
===================================================================
--- vendor/wpa/2.0/hostapd/config_file.h	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/config_file.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,17 @@
+/*
+ * hostapd / Configuration file parser
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_FILE_H
+#define CONFIG_FILE_H
+
+struct hostapd_config * hostapd_config_read(const char *fname);
+int hostapd_set_iface(struct hostapd_config *conf,
+		      struct hostapd_bss_config *bss, char *field,
+		      char *value);
+
+#endif /* CONFIG_FILE_H */

Deleted: vendor/wpa/2.0/hostapd/ctrl_iface.c
===================================================================
--- vendor/wpa/dist/hostapd/ctrl_iface.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/ctrl_iface.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,726 +0,0 @@
-/*
- * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <stddef.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
-#include "radius/radius_client.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "ap/ieee802_1x.h"
-#include "ap/wpa_auth.h"
-#include "ap/ieee802_11.h"
-#include "ap/sta_info.h"
-#include "ap/accounting.h"
-#include "ap/wps_hostapd.h"
-#include "ap/ctrl_iface_ap.h"
-#include "ctrl_iface.h"
-
-
-struct wpa_ctrl_dst {
-	struct wpa_ctrl_dst *next;
-	struct sockaddr_un addr;
-	socklen_t addrlen;
-	int debug_level;
-	int errors;
-};
-
-
-static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
-				    const char *buf, size_t len);
-
-
-static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
-				     struct sockaddr_un *from,
-				     socklen_t fromlen)
-{
-	struct wpa_ctrl_dst *dst;
-
-	dst = os_zalloc(sizeof(*dst));
-	if (dst == NULL)
-		return -1;
-	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
-	dst->addrlen = fromlen;
-	dst->debug_level = MSG_INFO;
-	dst->next = 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;
-}
-
-
-static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
-				     struct sockaddr_un *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) {
-			if (prev == NULL)
-				hapd->ctrl_dst = dst->next;
-			else
-				prev->next = dst->next;
-			os_free(dst);
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-				    (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
-			return 0;
-		}
-		prev = dst;
-		dst = dst->next;
-	}
-	return -1;
-}
-
-
-static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
-				    struct sockaddr_un *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;
-}
-
-
-static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
-				      const char *txtaddr)
-{
-	u8 addr[ETH_ALEN];
-	struct sta_info *sta;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
-
-	if (hwaddr_aton(txtaddr, addr))
-		return -1;
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
-		   "notification", MAC2STR(addr));
-	sta = ap_sta_add(hapd, addr);
-	if (sta == NULL)
-		return -1;
-
-	hostapd_new_assoc_sta(hapd, sta, 0);
-	return 0;
-}
-
-
-static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
-					     const char *txtaddr)
-{
-	u8 addr[ETH_ALEN];
-	struct sta_info *sta;
-	const char *pos;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
-
-	if (hwaddr_aton(txtaddr, addr))
-		return -1;
-
-	pos = os_strstr(txtaddr, " test=");
-	if (pos) {
-		struct ieee80211_mgmt mgmt;
-		int encrypt;
-		if (hapd->driver->send_frame == NULL)
-			return -1;
-		pos += 6;
-		encrypt = atoi(pos);
-		os_memset(&mgmt, 0, sizeof(mgmt));
-		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						  WLAN_FC_STYPE_DEAUTH);
-		os_memcpy(mgmt.da, addr, ETH_ALEN);
-		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-		mgmt.u.deauth.reason_code =
-			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-					     IEEE80211_HDRLEN +
-					     sizeof(mgmt.u.deauth),
-					     encrypt) < 0)
-			return -1;
-		return 0;
-	}
-
-	hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-	sta = ap_get_sta(hapd, addr);
-	if (sta)
-		ap_sta_deauthenticate(hapd, sta,
-				      WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-	return 0;
-}
-
-
-static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
-					   const char *txtaddr)
-{
-	u8 addr[ETH_ALEN];
-	struct sta_info *sta;
-	const char *pos;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
-
-	if (hwaddr_aton(txtaddr, addr))
-		return -1;
-
-	pos = os_strstr(txtaddr, " test=");
-	if (pos) {
-		struct ieee80211_mgmt mgmt;
-		int encrypt;
-		if (hapd->driver->send_frame == NULL)
-			return -1;
-		pos += 6;
-		encrypt = atoi(pos);
-		os_memset(&mgmt, 0, sizeof(mgmt));
-		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						  WLAN_FC_STYPE_DISASSOC);
-		os_memcpy(mgmt.da, addr, ETH_ALEN);
-		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-		mgmt.u.disassoc.reason_code =
-			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-					     IEEE80211_HDRLEN +
-					     sizeof(mgmt.u.deauth),
-					     encrypt) < 0)
-			return -1;
-		return 0;
-	}
-
-	hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-	sta = ap_get_sta(hapd, addr);
-	if (sta)
-		ap_sta_disassociate(hapd, sta,
-				    WLAN_REASON_PREV_AUTH_NOT_VALID);
-
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-#ifdef NEED_AP_MLME
-static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
-				       const char *txtaddr)
-{
-	u8 addr[ETH_ALEN];
-	u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
-
-	if (hwaddr_aton(txtaddr, addr) ||
-	    os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
-		return -1;
-
-	ieee802_11_send_sa_query_req(hapd, addr, trans_id);
-
-	return 0;
-}
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
-
-
-#ifdef CONFIG_WPS
-static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
-{
-	char *pin = os_strchr(txt, ' ');
-	char *timeout_txt;
-	int timeout;
-
-	if (pin == NULL)
-		return -1;
-	*pin++ = '\0';
-
-	timeout_txt = os_strchr(pin, ' ');
-	if (timeout_txt) {
-		*timeout_txt++ = '\0';
-		timeout = atoi(timeout_txt);
-	} else
-		timeout = 0;
-
-	return hostapd_wps_add_pin(hapd, txt, pin, timeout);
-}
-
-
-#ifdef CONFIG_WPS_OOB
-static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
-{
-	char *path, *method, *name;
-
-	path = os_strchr(txt, ' ');
-	if (path == NULL)
-		return -1;
-	*path++ = '\0';
-
-	method = os_strchr(path, ' ');
-	if (method == NULL)
-		return -1;
-	*method++ = '\0';
-
-	name = os_strchr(method, ' ');
-	if (name != NULL)
-		*name++ = '\0';
-
-	return hostapd_wps_start_oob(hapd, txt, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
-					 char *buf, size_t buflen)
-{
-	int timeout = 300;
-	char *pos;
-	const char *pin_txt;
-
-	pos = os_strchr(txt, ' ');
-	if (pos)
-		*pos++ = '\0';
-
-	if (os_strcmp(txt, "disable") == 0) {
-		hostapd_wps_ap_pin_disable(hapd);
-		return os_snprintf(buf, buflen, "OK\n");
-	}
-
-	if (os_strcmp(txt, "random") == 0) {
-		if (pos)
-			timeout = atoi(pos);
-		pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
-		if (pin_txt == NULL)
-			return -1;
-		return os_snprintf(buf, buflen, "%s", pin_txt);
-	}
-
-	if (os_strcmp(txt, "get") == 0) {
-		pin_txt = hostapd_wps_ap_pin_get(hapd);
-		if (pin_txt == NULL)
-			return -1;
-		return os_snprintf(buf, buflen, "%s", pin_txt);
-	}
-
-	if (os_strcmp(txt, "set") == 0) {
-		char *pin;
-		if (pos == NULL)
-			return -1;
-		pin = pos;
-		pos = os_strchr(pos, ' ');
-		if (pos) {
-			*pos++ = '\0';
-			timeout = atoi(pos);
-		}
-		if (os_strlen(pin) > buflen)
-			return -1;
-		if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
-			return -1;
-		return os_snprintf(buf, buflen, "%s", pin);
-	}
-
-	return -1;
-}
-#endif /* CONFIG_WPS */
-
-
-static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
-				       void *sock_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	char buf[256];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-	char *reply;
-	const int reply_size = 4096;
-	int reply_len;
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
-		return;
-	}
-	buf[res] = '\0';
-	wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
-
-	reply = os_malloc(reply_size);
-	if (reply == NULL) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-		return;
-	}
-
-	os_memcpy(reply, "OK\n", 3);
-	reply_len = 3;
-
-	if (os_strcmp(buf, "PING") == 0) {
-		os_memcpy(reply, "PONG\n", 5);
-		reply_len = 5;
-	} else if (os_strcmp(buf, "MIB") == 0) {
-		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
-		if (reply_len >= 0) {
-			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
-					  reply_size - reply_len);
-			if (res < 0)
-				reply_len = -1;
-			else
-				reply_len += res;
-		}
-		if (reply_len >= 0) {
-			res = ieee802_1x_get_mib(hapd, reply + reply_len,
-						 reply_size - reply_len);
-			if (res < 0)
-				reply_len = -1;
-			else
-				reply_len += res;
-		}
-#ifndef CONFIG_NO_RADIUS
-		if (reply_len >= 0) {
-			res = radius_client_get_mib(hapd->radius,
-						    reply + reply_len,
-						    reply_size - reply_len);
-			if (res < 0)
-				reply_len = -1;
-			else
-				reply_len += res;
-		}
-#endif /* CONFIG_NO_RADIUS */
-	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
-		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
-							 reply_size);
-	} else if (os_strncmp(buf, "STA ", 4) == 0) {
-		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
-						   reply_size);
-	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
-		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
-							reply_size);
-	} else if (os_strcmp(buf, "ATTACH") == 0) {
-		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "DETACH") == 0) {
-		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
-		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
-						    buf + 6))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
-		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
-		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
-		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
-			reply_len = -1;
-#ifdef CONFIG_IEEE80211W
-#ifdef NEED_AP_MLME
-	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
-		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
-			reply_len = -1;
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
-		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
-		if (hostapd_wps_button_pushed(hapd))
-			reply_len = -1;
-#ifdef CONFIG_WPS_OOB
-	} else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-		if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
-			reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
-	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
-		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
-							  reply, reply_size);
-#endif /* CONFIG_WPS */
-	} else {
-		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
-		reply_len = 16;
-	}
-
-	if (reply_len < 0) {
-		os_memcpy(reply, "FAIL\n", 5);
-		reply_len = 5;
-	}
-	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
-	os_free(reply);
-}
-
-
-static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
-{
-	char *buf;
-	size_t len;
-
-	if (hapd->conf->ctrl_interface == NULL)
-		return NULL;
-
-	len = os_strlen(hapd->conf->ctrl_interface) +
-		os_strlen(hapd->conf->iface) + 2;
-	buf = os_malloc(len);
-	if (buf == NULL)
-		return NULL;
-
-	os_snprintf(buf, len, "%s/%s",
-		    hapd->conf->ctrl_interface, hapd->conf->iface);
-	buf[len - 1] = '\0';
-	return buf;
-}
-
-
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
-				      const char *txt, size_t len)
-{
-	struct hostapd_data *hapd = ctx;
-	if (hapd == NULL)
-		return;
-	hostapd_ctrl_iface_send(hapd, level, txt, len);
-}
-
-
-int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
-{
-	struct sockaddr_un addr;
-	int s = -1;
-	char *fname = NULL;
-
-	hapd->ctrl_sock = -1;
-
-	if (hapd->conf->ctrl_interface == NULL)
-		return 0;
-
-	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
-		if (errno == EEXIST) {
-			wpa_printf(MSG_DEBUG, "Using existing control "
-				   "interface directory.");
-		} else {
-			perror("mkdir[ctrl_interface]");
-			goto fail;
-		}
-	}
-
-	if (hapd->conf->ctrl_interface_gid_set &&
-	    chown(hapd->conf->ctrl_interface, 0,
-		  hapd->conf->ctrl_interface_gid) < 0) {
-		perror("chown[ctrl_interface]");
-		return -1;
-	}
-
-	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
-	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
-		goto fail;
-
-	s = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket(PF_UNIX)");
-		goto fail;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-#ifdef __FreeBSD__
-	addr.sun_len = sizeof(addr);
-#endif /* __FreeBSD__ */
-	addr.sun_family = AF_UNIX;
-	fname = hostapd_ctrl_iface_path(hapd);
-	if (fname == NULL)
-		goto fail;
-	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
-	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
-			   strerror(errno));
-		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
-				   " allow connections - assuming it was left"
-				   "over from forced program termination");
-			if (unlink(fname) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   fname);
-				goto fail;
-			}
-			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
-			    0) {
-				perror("bind(PF_UNIX)");
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
-				   "ctrl_iface socket '%s'", fname);
-		} else {
-			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
-				   "be in use - cannot override it");
-			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
-				   "not used anymore", fname);
-			os_free(fname);
-			fname = NULL;
-			goto fail;
-		}
-	}
-
-	if (hapd->conf->ctrl_interface_gid_set &&
-	    chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
-		perror("chown[ctrl_interface/ifname]");
-		goto fail;
-	}
-
-	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-		perror("chmod[ctrl_interface/ifname]");
-		goto fail;
-	}
-	os_free(fname);
-
-	hapd->ctrl_sock = s;
-	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
-				 NULL);
-	hapd->msg_ctx = hapd;
-	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
-
-	return 0;
-
-fail:
-	if (s >= 0)
-		close(s);
-	if (fname) {
-		unlink(fname);
-		os_free(fname);
-	}
-	return -1;
-}
-
-
-void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
-{
-	struct wpa_ctrl_dst *dst, *prev;
-
-	if (hapd->ctrl_sock > -1) {
-		char *fname;
-		eloop_unregister_read_sock(hapd->ctrl_sock);
-		close(hapd->ctrl_sock);
-		hapd->ctrl_sock = -1;
-		fname = hostapd_ctrl_iface_path(hapd);
-		if (fname)
-			unlink(fname);
-		os_free(fname);
-
-		if (hapd->conf->ctrl_interface &&
-		    rmdir(hapd->conf->ctrl_interface) < 0) {
-			if (errno == ENOTEMPTY) {
-				wpa_printf(MSG_DEBUG, "Control interface "
-					   "directory not empty - leaving it "
-					   "behind");
-			} else {
-				perror("rmdir[ctrl_interface]");
-			}
-		}
-	}
-
-	dst = hapd->ctrl_dst;
-	while (dst) {
-		prev = dst;
-		dst = dst->next;
-		os_free(prev);
-	}
-}
-
-
-static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
-				    const char *buf, size_t len)
-{
-	struct wpa_ctrl_dst *dst, *next;
-	struct msghdr msg;
-	int idx;
-	struct iovec io[2];
-	char levelstr[10];
-
-	dst = hapd->ctrl_dst;
-	if (hapd->ctrl_sock < 0 || dst == NULL)
-		return;
-
-	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-	io[0].iov_base = levelstr;
-	io[0].iov_len = os_strlen(levelstr);
-	io[1].iov_base = (char *) buf;
-	io[1].iov_len = len;
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
-
-	idx = 0;
-	while (dst) {
-		next = dst->next;
-		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));
-			msg.msg_name = &dst->addr;
-			msg.msg_namelen = dst->addrlen;
-			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
-				int _errno = errno;
-				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
-					   "%d - %s",
-					   idx, errno, strerror(errno));
-				dst->errors++;
-				if (dst->errors > 10 || _errno == ENOENT) {
-					hostapd_ctrl_iface_detach(
-						hapd, &dst->addr,
-						dst->addrlen);
-				}
-			} else
-				dst->errors = 0;
-		}
-		idx++;
-		dst = next;
-	}
-}
-
-#endif /* CONFIG_NATIVE_WINDOWS */

Copied: vendor/wpa/2.0/hostapd/ctrl_iface.c (from rev 9639, vendor/wpa/dist/hostapd/ctrl_iface.c)
===================================================================
--- vendor/wpa/2.0/hostapd/ctrl_iface.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/ctrl_iface.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1453 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "radius/radius_client.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ieee802_1x.h"
+#include "ap/wpa_auth.h"
+#include "ap/ieee802_11.h"
+#include "ap/sta_info.h"
+#include "ap/wps_hostapd.h"
+#include "ap/ctrl_iface_ap.h"
+#include "ap/ap_drv_ops.h"
+#include "wps/wps_defs.h"
+#include "wps/wps.h"
+#include "config_file.h"
+#include "ctrl_iface.h"
+
+
+struct wpa_ctrl_dst {
+	struct wpa_ctrl_dst *next;
+	struct sockaddr_un addr;
+	socklen_t addrlen;
+	int debug_level;
+	int errors;
+};
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+				    const char *buf, size_t len);
+
+
+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+				     struct sockaddr_un *from,
+				     socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dst->next = 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;
+}
+
+
+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
+				     struct sockaddr_un *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) {
+			if (prev == NULL)
+				hapd->ctrl_dst = dst->next;
+			else
+				prev->next = dst->next;
+			os_free(dst);
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			return 0;
+		}
+		prev = dst;
+		dst = dst->next;
+	}
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
+				    struct sockaddr_un *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;
+}
+
+
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+				      const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+		   "notification", MAC2STR(addr));
+	sta = ap_sta_add(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	hostapd_new_assoc_sta(hapd, sta, 0);
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
+				       const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr) ||
+	    os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
+		return -1;
+
+	ieee802_11_send_sa_query_req(hapd, addr, trans_id);
+
+	return 0;
+}
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
+{
+	char *pin = os_strchr(txt, ' ');
+	char *timeout_txt;
+	int timeout;
+	u8 addr_buf[ETH_ALEN], *addr = NULL;
+	char *pos;
+
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	timeout_txt = os_strchr(pin, ' ');
+	if (timeout_txt) {
+		*timeout_txt++ = '\0';
+		timeout = atoi(timeout_txt);
+		pos = os_strchr(timeout_txt, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			if (hwaddr_aton(pos, addr_buf) == 0)
+				addr = addr_buf;
+		}
+	} else
+		timeout = 0;
+
+	return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
+}
+
+
+static int hostapd_ctrl_iface_wps_check_pin(
+	struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
+{
+	char pin[9];
+	size_t len;
+	char *pos;
+	int ret;
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+			      (u8 *) cmd, os_strlen(cmd));
+	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+		if (*pos < '0' || *pos > '9')
+			continue;
+		pin[len++] = *pos;
+		if (len == 9) {
+			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+			return -1;
+		}
+	}
+	if (len != 4 && len != 8) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+		return -1;
+	}
+	pin[len] = '\0';
+
+	if (len == 8) {
+		unsigned int pin_val;
+		pin_val = atoi(pin);
+		if (!wps_pin_valid(pin_val)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+			if (ret < 0 || (size_t) ret >= buflen)
+				return -1;
+			return ret;
+		}
+	}
+
+	ret = os_snprintf(buf, buflen, "%s", pin);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+
+	return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
+					       char *pos)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = hostapd_wps_nfc_tag_read(hapd, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
+						   char *cmd, char *reply,
+						   size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = hostapd_wps_nfc_config_token(hapd, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+						char *reply, size_t max_len,
+						int ndef)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = hostapd_wps_nfc_token_gen(hapd, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+					    char *cmd, char *reply,
+					    size_t max_len)
+{
+	if (os_strcmp(cmd, "WPS") == 0)
+		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+							    max_len, 0);
+
+	if (os_strcmp(cmd, "NDEF") == 0)
+		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+							    max_len, 1);
+
+	if (os_strcmp(cmd, "enable") == 0)
+		return hostapd_wps_nfc_token_enable(hapd);
+
+	if (os_strcmp(cmd, "disable") == 0) {
+		hostapd_wps_nfc_token_disable(hapd);
+		return 0;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
+					 char *buf, size_t buflen)
+{
+	int timeout = 300;
+	char *pos;
+	const char *pin_txt;
+
+	pos = os_strchr(txt, ' ');
+	if (pos)
+		*pos++ = '\0';
+
+	if (os_strcmp(txt, "disable") == 0) {
+		hostapd_wps_ap_pin_disable(hapd);
+		return os_snprintf(buf, buflen, "OK\n");
+	}
+
+	if (os_strcmp(txt, "random") == 0) {
+		if (pos)
+			timeout = atoi(pos);
+		pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(txt, "get") == 0) {
+		pin_txt = hostapd_wps_ap_pin_get(hapd);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(txt, "set") == 0) {
+		char *pin;
+		if (pos == NULL)
+			return -1;
+		pin = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			timeout = atoi(pos);
+		}
+		if (os_strlen(pin) > buflen)
+			return -1;
+		if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin);
+	}
+
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
+{
+	char *pos;
+	char *ssid, *auth, *encr = NULL, *key = NULL;
+
+	ssid = txt;
+	pos = os_strchr(txt, ' ');
+	if (!pos)
+		return -1;
+	*pos++ = '\0';
+
+	auth = pos;
+	pos = os_strchr(pos, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		encr = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			key = pos;
+		}
+	}
+
+	return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
+}
+#endif /* CONFIG_WPS */
+
+
+#ifdef CONFIG_WNM
+
+static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+						const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	int disassoc_timer;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	if (cmd[17] != ' ')
+		return -1;
+	disassoc_timer = atoi(cmd + 17);
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer =
+		host_to_le16(disassoc_timer);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+					   const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	const char *url;
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	url = cmd + 17;
+	if (*url != ' ')
+		return -1;
+	url++;
+	url_len = os_strlen(url);
+	if (url_len > 255)
+		return -1;
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	/* Session Information URL */
+	*pos++ = url_len;
+	os_memcpy(pos, url, url_len);
+	pos += url_len;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
+					 char *buf, size_t buflen)
+{
+	int ret;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
+			  "ssid=%s\n",
+			  MAC2STR(hapd->own_addr),
+			  wpa_ssid_txt(hapd->conf->ssid.ssid,
+				       hapd->conf->ssid.ssid_len));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+#ifdef CONFIG_WPS
+	ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
+			  hapd->conf->wps_state == 0 ? "disabled" :
+			  (hapd->conf->wps_state == 1 ? "not configured" :
+			   "configured"));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    hapd->conf->ssid.wpa_passphrase) {
+		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
+				  hapd->conf->ssid.wpa_passphrase);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    hapd->conf->ssid.wpa_psk &&
+	    hapd->conf->ssid.wpa_psk->group) {
+		char hex[PMK_LEN * 2 + 1];
+		wpa_snprintf_hex(hex, sizeof(hex),
+				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
+		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_WPS */
+
+	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
+		ret = os_snprintf(pos, end - pos, "key_mgmt=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#ifdef CONFIG_IEEE80211R
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+			ret = os_snprintf(pos, end - pos, "FT-PSK ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+			ret = os_snprintf(pos, end - pos, "FT-EAP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#endif /* CONFIG_IEEE80211W */
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	} else if (hapd->conf->wpa &&
+		   hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	} else if (hapd->conf->wpa &&
+		   hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
+		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
+			ret = os_snprintf(pos, end - pos, "CCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
+			ret = os_snprintf(pos, end - pos, "GCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+			ret = os_snprintf(pos, end - pos, "TKIP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
+		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+			ret = os_snprintf(pos, end - pos, "CCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
+			ret = os_snprintf(pos, end - pos, "GCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+			ret = os_snprintf(pos, end - pos, "TKIP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
+{
+	char *value;
+	int ret = 0;
+
+	value = os_strchr(cmd, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+	if (0) {
+#ifdef CONFIG_WPS_TESTING
+	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+		long int val;
+		val = strtol(value, NULL, 0);
+		if (val < 0 || val > 0xff) {
+			ret = -1;
+			wpa_printf(MSG_DEBUG, "WPS: Invalid "
+				   "wps_version_number %ld", val);
+		} else {
+			wps_version_number = val;
+			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+				   "version %u.%u",
+				   (wps_version_number & 0xf0) >> 4,
+				   wps_version_number & 0x0f);
+			hostapd_wps_update_ie(hapd);
+		}
+	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+		wps_testing_dummy_cred = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+			   wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
+		int val = atoi(value);
+		if (val <= 0)
+			ret = -1;
+		else
+			hapd->gas_frag_limit = val;
+#endif /* CONFIG_INTERWORKING */
+	} else {
+		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
+	}
+
+	return ret;
+}
+
+
+static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
+				  char *buf, size_t buflen)
+{
+	int res;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+	if (os_strcmp(cmd, "version") == 0) {
+		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+		if (res < 0 || (unsigned int) res >= buflen)
+			return -1;
+		return res;
+	}
+
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
+{
+	if (hostapd_enable_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Enabling of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
+{
+	if (hostapd_reload_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Reloading of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
+{
+	if (hostapd_disable_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Disabling of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+				       void *sock_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply;
+	const int reply_size = 4096;
+	int reply_len;
+	int level = MSG_DEBUG;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		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) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+		return;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "MIB") == 0) {
+		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+		if (reply_len >= 0) {
+			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
+					  reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+		if (reply_len >= 0) {
+			res = ieee802_1x_get_mib(hapd, reply + reply_len,
+						 reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+#ifndef CONFIG_NO_RADIUS
+		if (reply_len >= 0) {
+			res = radius_client_get_mib(hapd->radius,
+						    reply + reply_len,
+						    reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+#endif /* CONFIG_NO_RADIUS */
+	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
+		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+							 reply_size);
+	} else if (os_strncmp(buf, "STA ", 4) == 0) {
+		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+							reply_size);
+	} else if (os_strcmp(buf, "ATTACH") == 0) {
+		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+						    buf + 6))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
+		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
+			reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
+	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
+		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
+			reply_len = -1;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_check_pin(
+			hapd, buf + 14, reply, reply_size);
+	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
+		if (hostapd_wps_button_pushed(hapd, NULL))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+		if (hostapd_wps_cancel(hapd))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
+							  reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
+		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
+			hapd, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_nfc_token(
+			hapd, buf + 14, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_WNM
+	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
+			reply_len = -1;
+#endif /* CONFIG_WNM */
+	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
+		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
+							  reply_size);
+	} else if (os_strncmp(buf, "SET ", 4) == 0) {
+		if (hostapd_ctrl_iface_set(hapd, buf + 4))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET ", 4) == 0) {
+		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
+		if (hostapd_ctrl_iface_enable(hapd->iface))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
+		if (hostapd_ctrl_iface_reload(hapd->iface))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
+		if (hostapd_ctrl_iface_disable(hapd->iface))
+			reply_len = -1;
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+	os_free(reply);
+}
+
+
+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
+{
+	char *buf;
+	size_t len;
+
+	if (hapd->conf->ctrl_interface == NULL)
+		return NULL;
+
+	len = os_strlen(hapd->conf->ctrl_interface) +
+		os_strlen(hapd->conf->iface) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	os_snprintf(buf, len, "%s/%s",
+		    hapd->conf->ctrl_interface, hapd->conf->iface);
+	buf[len - 1] = '\0';
+	return buf;
+}
+
+
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+				      const char *txt, size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	if (hapd == NULL)
+		return;
+	hostapd_ctrl_iface_send(hapd, level, txt, len);
+}
+
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+	struct sockaddr_un addr;
+	int s = -1;
+	char *fname = NULL;
+
+	if (hapd->ctrl_sock > -1) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+		return 0;
+	}
+
+	if (hapd->conf->ctrl_interface == NULL)
+		return 0;
+
+	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+	if (hapd->conf->ctrl_interface_gid_set &&
+	    chown(hapd->conf->ctrl_interface, -1,
+		  hapd->conf->ctrl_interface_gid) < 0) {
+		perror("chown[ctrl_interface]");
+		return -1;
+	}
+
+#ifdef ANDROID
+	/*
+	 * Android is using umask 0077 which would leave the control interface
+	 * directory without group access. This breaks things since Wi-Fi
+	 * framework assumes that this directory can be accessed by other
+	 * applications in the wifi group. Fix this by adding group access even
+	 * if umask value would prevent this.
+	 */
+	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+#endif /* ANDROID */
+
+	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
+	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
+		goto fail;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = hostapd_ctrl_iface_path(hapd);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+			    0) {
+				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (hapd->conf->ctrl_interface_gid_set &&
+	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+		perror("chown[ctrl_interface/ifname]");
+		goto fail;
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+	hapd->ctrl_sock = s;
+	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+				 NULL);
+	hapd->msg_ctx = hapd;
+	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+	return 0;
+
+fail:
+	if (s >= 0)
+		close(s);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	return -1;
+}
+
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (hapd->ctrl_sock > -1) {
+		char *fname;
+		eloop_unregister_read_sock(hapd->ctrl_sock);
+		close(hapd->ctrl_sock);
+		hapd->ctrl_sock = -1;
+		fname = hostapd_ctrl_iface_path(hapd);
+		if (fname)
+			unlink(fname);
+		os_free(fname);
+
+		if (hapd->conf->ctrl_interface &&
+		    rmdir(hapd->conf->ctrl_interface) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+	}
+
+	dst = hapd->ctrl_dst;
+	while (dst) {
+		prev = dst;
+		dst = dst->next;
+		os_free(prev);
+	}
+}
+
+
+static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
+				  char *buf)
+{
+	if (hostapd_add_iface(interfaces, buf) < 0) {
+		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
+				     char *buf)
+{
+	if (hostapd_remove_iface(interfaces, buf) < 0) {
+		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+		return -1;
+	}
+	return 0;
+}
+
+
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+					      void *sock_ctx)
+{
+	void *interfaces = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char reply[24];
+	int reply_len;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
+		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
+		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
+			reply_len = -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
+			   "ignored");
+		reply_len = -1;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+}
+
+
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
+{
+	char *buf;
+	size_t len;
+
+	if (interface->global_iface_path == NULL)
+		return NULL;
+
+	len = os_strlen(interface->global_iface_path) +
+		os_strlen(interface->global_iface_name) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
+		    interface->global_iface_name);
+	buf[len - 1] = '\0';
+	return buf;
+}
+
+
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+	struct sockaddr_un addr;
+	int s = -1;
+	char *fname = NULL;
+
+	if (interface->global_iface_path == NULL) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
+		return 0;
+	}
+
+	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+	if (os_strlen(interface->global_iface_path) + 1 +
+	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
+		goto fail;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = hostapd_global_ctrl_iface_path(interface);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+			    0) {
+				perror("bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+	interface->global_ctrl_sock = s;
+	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+				 interface, NULL);
+
+	return 0;
+
+fail:
+	if (s >= 0)
+		close(s);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	return -1;
+}
+
+
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
+{
+	char *fname = NULL;
+
+	if (interfaces->global_ctrl_sock > -1) {
+		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
+		close(interfaces->global_ctrl_sock);
+		interfaces->global_ctrl_sock = -1;
+		fname = hostapd_global_ctrl_iface_path(interfaces);
+		if (fname) {
+			unlink(fname);
+			os_free(fname);
+		}
+
+		if (interfaces->global_iface_path &&
+		    rmdir(interfaces->global_iface_path) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+		os_free(interfaces->global_iface_path);
+		interfaces->global_iface_path = NULL;
+	}
+}
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+				    const char *buf, size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	struct msghdr msg;
+	int idx;
+	struct iovec io[2];
+	char levelstr[10];
+
+	dst = hapd->ctrl_dst;
+	if (hapd->ctrl_sock < 0 || dst == NULL)
+		return;
+
+	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+	io[0].iov_base = levelstr;
+	io[0].iov_len = os_strlen(levelstr);
+	io[1].iov_base = (char *) buf;
+	io[1].iov_len = len;
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+	idx = 0;
+	while (dst) {
+		next = dst->next;
+		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));
+			msg.msg_name = &dst->addr;
+			msg.msg_namelen = dst->addrlen;
+			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+				int _errno = errno;
+				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+					   "%d - %s",
+					   idx, errno, strerror(errno));
+				dst->errors++;
+				if (dst->errors > 10 || _errno == ENOENT) {
+					hostapd_ctrl_iface_detach(
+						hapd, &dst->addr,
+						dst->addrlen);
+				}
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+		dst = next;
+	}
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */

Deleted: vendor/wpa/2.0/hostapd/ctrl_iface.h
===================================================================
--- vendor/wpa/dist/hostapd/ctrl_iface.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/ctrl_iface.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,32 +0,0 @@
-/*
- * hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_H
-#define CTRL_IFACE_H
-
-#ifndef CONFIG_NO_CTRL_IFACE
-int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
-void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
-#else /* CONFIG_NO_CTRL_IFACE */
-static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
-{
-	return 0;
-}
-
-static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
-{
-}
-#endif /* CONFIG_NO_CTRL_IFACE */
-
-#endif /* CTRL_IFACE_H */

Copied: vendor/wpa/2.0/hostapd/ctrl_iface.h (from rev 9639, vendor/wpa/dist/hostapd/ctrl_iface.h)
===================================================================
--- vendor/wpa/2.0/hostapd/ctrl_iface.h	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/ctrl_iface.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,39 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifndef CONFIG_NO_CTRL_IFACE
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
+#else /* CONFIG_NO_CTRL_IFACE */
+static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline int
+hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+	return 0;
+}
+
+static inline void
+hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+}
+#endif /* CONFIG_NO_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */

Deleted: vendor/wpa/2.0/hostapd/defconfig
===================================================================
--- vendor/wpa/dist/hostapd/defconfig	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/defconfig	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,175 +0,0 @@
-# Example hostapd build time configuration
-#
-# This file lists the configuration options that are used when building the
-# hostapd binary. All lines starting with # are ignored. Configuration option
-# lines must be commented out complete, if they are not to be included, i.e.,
-# just setting VARIABLE=n is not disabling that variable.
-#
-# This file is included in Makefile, so variables like CFLAGS and LIBS can also
-# be modified from here. In most cass, these lines should use += in order not
-# to override previous values of the variables.
-
-# Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for wired authenticator
-#CONFIG_DRIVER_WIRED=y
-
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
-# Driver interface for drivers using the nl80211 kernel interface
-#CONFIG_DRIVER_NL80211=y
-# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
-# shipped with your distribution yet. If that is the case, you need to build
-# newer libnl version and point the hostapd build to use it.
-#LIBNL=/usr/src/libnl
-#CFLAGS += -I$(LIBNL)/include
-#LIBS += -L$(LIBNL)/lib
-
-# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
-#CONFIG_DRIVER_BSD=y
-#CFLAGS += -I/usr/local/include
-#LIBS += -L/usr/local/lib
-#LIBS_p += -L/usr/local/lib
-#LIBS_c += -L/usr/local/lib
-
-# Driver interface for no driver (e.g., RADIUS server only)
-#CONFIG_DRIVER_NONE=y
-
-# IEEE 802.11F/IAPP
-CONFIG_IAPP=y
-
-# WPA2/IEEE 802.11i RSN pre-authentication
-CONFIG_RSN_PREAUTH=y
-
-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
-CONFIG_PEERKEY=y
-
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
-
-# Integrated EAP server
-CONFIG_EAP=y
-
-# EAP-MD5 for the integrated EAP server
-CONFIG_EAP_MD5=y
-
-# EAP-TLS for the integrated EAP server
-CONFIG_EAP_TLS=y
-
-# EAP-MSCHAPv2 for the integrated EAP server
-CONFIG_EAP_MSCHAPV2=y
-
-# EAP-PEAP for the integrated EAP server
-CONFIG_EAP_PEAP=y
-
-# EAP-GTC for the integrated EAP server
-CONFIG_EAP_GTC=y
-
-# EAP-TTLS for the integrated EAP server
-CONFIG_EAP_TTLS=y
-
-# EAP-SIM for the integrated EAP server
-#CONFIG_EAP_SIM=y
-
-# EAP-AKA for the integrated EAP server
-#CONFIG_EAP_AKA=y
-
-# EAP-AKA' for the integrated EAP server
-# This requires CONFIG_EAP_AKA to be enabled, too.
-#CONFIG_EAP_AKA_PRIME=y
-
-# EAP-PAX for the integrated EAP server
-#CONFIG_EAP_PAX=y
-
-# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
-#CONFIG_EAP_PSK=y
-
-# EAP-SAKE for the integrated EAP server
-#CONFIG_EAP_SAKE=y
-
-# EAP-GPSK for the integrated EAP server
-#CONFIG_EAP_GPSK=y
-# Include support for optional SHA256 cipher suite in EAP-GPSK
-#CONFIG_EAP_GPSK_SHA256=y
-
-# EAP-FAST for the integrated EAP server
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
-# to add the needed functions.
-#CONFIG_EAP_FAST=y
-
-# Wi-Fi Protected Setup (WPS)
-#CONFIG_WPS=y
-# Enable UPnP support for external WPS Registrars
-#CONFIG_WPS_UPNP=y
-
-# EAP-IKEv2
-#CONFIG_EAP_IKEV2=y
-
-# Trusted Network Connect (EAP-TNC)
-#CONFIG_EAP_TNC=y
-
-# PKCS#12 (PFX) support (used to read private key and certificate file from
-# a file that usually has extension .p12 or .pfx)
-CONFIG_PKCS12=y
-
-# RADIUS authentication server. This provides access to the integrated EAP
-# server from external hosts using RADIUS.
-#CONFIG_RADIUS_SERVER=y
-
-# Build IPv6 support for RADIUS operations
-CONFIG_IPV6=y
-
-# IEEE Std 802.11r-2008 (Fast BSS Transition)
-#CONFIG_IEEE80211R=y
-
-# Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
-#CONFIG_DRIVER_RADIUS_ACL=y
-
-# IEEE 802.11n (High Throughput) support
-#CONFIG_IEEE80211N=y
-
-# Remove debugging code that is printing out debug messages to stdout.
-# This can be used to reduce the size of the hostapd considerably if debugging
-# code is not needed.
-#CONFIG_NO_STDOUT_DEBUG=y
-
-# Remove support for RADIUS accounting
-#CONFIG_NO_ACCOUNTING=y
-
-# Remove support for RADIUS
-#CONFIG_NO_RADIUS=y
-
-# Remove support for VLANs
-#CONFIG_NO_VLAN=y
-
-# Remove support for dumping state into a file on SIGUSR1 signal
-# This can be used to reduce binary size at the cost of disabling a debugging
-# option.
-#CONFIG_NO_DUMP_STATE=y
-
-# Enable tracing code for developer debugging
-# This tracks use of memory allocations and other registrations and reports
-# incorrect use with a backtrace of call (or allocation) location.
-#CONFIG_WPA_TRACE=y
-# For BSD, comment out these.
-#LIBS += -lexecinfo
-#LIBS_p += -lexecinfo
-#LIBS_c += -lexecinfo
-
-# Use libbfd to get more details for developer debugging
-# This enables use of libbfd to get more detailed symbols for the backtraces
-# generated by CONFIG_WPA_TRACE=y.
-#CONFIG_WPA_TRACE_BFD=y
-# For BSD, comment out these.
-#LIBS += -lbfd -liberty -lz
-#LIBS_p += -lbfd -liberty -lz
-#LIBS_c += -lbfd -liberty -lz

Copied: vendor/wpa/2.0/hostapd/defconfig (from rev 9639, vendor/wpa/dist/hostapd/defconfig)
===================================================================
--- vendor/wpa/2.0/hostapd/defconfig	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/defconfig	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,269 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd for the integrated EAP server (secure authentication with a password)
+#CONFIG_EAP_PWD=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WSC 2.0 support
+#CONFIG_WPS2=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+#CONFIG_IEEE80211N=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# IEEE 802.11ac (Very High Throughput) support
+#CONFIG_IEEE80211AC=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to a file: -f /tmp/hostapd.log
+# Disabled by default.
+#CONFIG_DEBUG_FILE=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+#CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Enable support for fully dynamic VLANs. This enables hostapd to
+# automatically create bridge and VLAN interfaces if necessary.
+#CONFIG_FULL_DYNAMIC_VLAN=y
+
+# Use netlink-based kernel API for VLAN operations instead of ioctl()
+# Note: This requires libnl 3.1 or newer.
+#CONFIG_VLAN_NETLINK=y
+
+# Remove support for dumping state into a file on SIGUSR1 signal
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# hostapd depends on strong random number generation being available from the
+# operating system. os_get_random() function is used to fetch random data when
+# needed, e.g., for key generation. On Linux and BSD systems, this works by
+# reading /dev/urandom. It should be noted that the OS entropy pool needs to be
+# properly initialized before hostapd is started. This is important especially
+# on embedded devices that do not have a hardware random number generator and
+# may by default start up with minimal entropy available for random number
+# generation.
+#
+# As a safety net, hostapd is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data
+# fetched from the OS. This by itself is not considered to be very strong, but
+# it may help in cases where the system pool is not initialized properly.
+# However, it is very strongly recommended that the system pool is initialized
+# with enough entropy either by using hardware assisted random number
+# generator or by storing state over device reboots.
+#
+# hostapd can be configured to maintain its own entropy store over restarts to
+# enhance random number generation. This is not perfect, but it is much more
+# secure than using the same sequence of random numbers after every reboot.
+# This can be enabled with -e<entropy file> command line option. The specified
+# file needs to be readable and writable by hostapd.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal hostapd random pool can be disabled.
+# This will save some in binary size and CPU use. However, this should only be
+# considered for builds that are known to be used on devices that meet the
+# requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used.
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms.
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
+#CONFIG_SQLITE=y

Deleted: vendor/wpa/2.0/hostapd/dump_state.c
===================================================================
--- vendor/wpa/dist/hostapd/dump_state.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/dump_state.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,184 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "radius/radius_client.h"
-#include "radius/radius_server.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "eap_server/eap.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "ap/sta_info.h"
-#include "dump_state.h"
-
-
-static void fprint_char(FILE *f, char c)
-{
-	if (c >= 32 && c < 127)
-		fprintf(f, "%c", c);
-	else
-		fprintf(f, "<%02x>", c);
-}
-
-
-static void ieee802_1x_dump_state(FILE *f, const char *prefix,
-				  struct sta_info *sta)
-{
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	if (sm == NULL)
-		return;
-
-	fprintf(f, "%sIEEE 802.1X:\n", prefix);
-
-	if (sm->identity) {
-		size_t i;
-		fprintf(f, "%sidentity=", prefix);
-		for (i = 0; i < sm->identity_len; i++)
-			fprint_char(f, sm->identity[i]);
-		fprintf(f, "\n");
-	}
-
-	fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
-		"Supplicant: %d (%s)\n", prefix,
-		sm->eap_type_authsrv,
-		eap_server_get_name(0, sm->eap_type_authsrv),
-		sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
-
-	fprintf(f, "%scached_packets=%s\n", prefix,
-		sm->last_recv_radius ? "[RX RADIUS]" : "");
-
-	eapol_auth_dump_state(f, prefix, sm);
-}
-
-
-/**
- * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
- */
-static void hostapd_dump_state(struct hostapd_data *hapd)
-{
-	FILE *f;
-	time_t now;
-	struct sta_info *sta;
-	int i;
-#ifndef CONFIG_NO_RADIUS
-	char *buf;
-#endif /* CONFIG_NO_RADIUS */
-
-	if (!hapd->conf->dump_log_name) {
-		wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
-			   "request");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
-		   hapd->conf->dump_log_name);
-	f = fopen(hapd->conf->dump_log_name, "w");
-	if (f == NULL) {
-		wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
-			   "writing.", hapd->conf->dump_log_name);
-		return;
-	}
-
-	time(&now);
-	fprintf(f, "hostapd state dump - %s", ctime(&now));
-	fprintf(f, "num_sta=%d num_sta_non_erp=%d "
-		"num_sta_no_short_slot_time=%d\n"
-		"num_sta_no_short_preamble=%d\n",
-		hapd->num_sta, hapd->iface->num_sta_non_erp,
-		hapd->iface->num_sta_no_short_slot_time,
-		hapd->iface->num_sta_no_short_preamble);
-
-	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
-		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
-
-		fprintf(f,
-			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
-			"  capability=0x%x listen_interval=%d\n",
-			sta->aid,
-			sta->flags,
-			(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
-			(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
-			(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
-			(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
-			(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
-			(sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" :
-			 ""),
-			(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
-			 ""),
-			(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
-			 "[SHORT_PREAMBLE]" : ""),
-			(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
-			(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
-			(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
-			(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
-			(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
-			(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
-			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
-			sta->capability,
-			sta->listen_interval);
-
-		fprintf(f, "  supported_rates=");
-		for (i = 0; i < sta->supported_rates_len; i++)
-			fprintf(f, "%02x ", sta->supported_rates[i]);
-		fprintf(f, "\n");
-
-		fprintf(f,
-			"  timeout_next=%s\n",
-			(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
-			 (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
-			  "DEAUTH")));
-
-		ieee802_1x_dump_state(f, "  ", sta);
-	}
-
-#ifndef CONFIG_NO_RADIUS
-	buf = os_malloc(4096);
-	if (buf) {
-		int count = radius_client_get_mib(hapd->radius, buf, 4096);
-		if (count < 0)
-			count = 0;
-		else if (count > 4095)
-			count = 4095;
-		buf[count] = '\0';
-		fprintf(f, "%s", buf);
-
-#ifdef RADIUS_SERVER
-		count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
-		if (count < 0)
-			count = 0;
-		else if (count > 4095)
-			count = 4095;
-		buf[count] = '\0';
-		fprintf(f, "%s", buf);
-#endif /* RADIUS_SERVER */
-
-		os_free(buf);
-	}
-#endif /* CONFIG_NO_RADIUS */
-	fclose(f);
-}
-
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
-{
-	size_t i;
-
-	for (i = 0; i < iface->num_bss; i++)
-		hostapd_dump_state(iface->bss[i]);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/hostapd/dump_state.c (from rev 9639, vendor/wpa/dist/hostapd/dump_state.c)
===================================================================
--- vendor/wpa/2.0/hostapd/dump_state.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/dump_state.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,180 @@
+/*
+ * hostapd / State dump
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <time.h>
+
+#include "utils/common.h"
+#include "radius/radius_client.h"
+#include "radius/radius_server.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "eap_server/eap.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/sta_info.h"
+#include "dump_state.h"
+
+
+static void fprint_char(FILE *f, char c)
+{
+	if (c >= 32 && c < 127)
+		fprintf(f, "%c", c);
+	else
+		fprintf(f, "<%02x>", c);
+}
+
+
+static void ieee802_1x_dump_state(FILE *f, const char *prefix,
+				  struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	fprintf(f, "%sIEEE 802.1X:\n", prefix);
+
+	if (sm->identity) {
+		size_t i;
+		fprintf(f, "%sidentity=", prefix);
+		for (i = 0; i < sm->identity_len; i++)
+			fprint_char(f, sm->identity[i]);
+		fprintf(f, "\n");
+	}
+
+	fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
+		"Supplicant: %d (%s)\n", prefix,
+		sm->eap_type_authsrv,
+		eap_server_get_name(0, sm->eap_type_authsrv),
+		sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
+
+	fprintf(f, "%scached_packets=%s\n", prefix,
+		sm->last_recv_radius ? "[RX RADIUS]" : "");
+
+	eapol_auth_dump_state(f, prefix, sm);
+}
+
+
+/**
+ * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
+ */
+static void hostapd_dump_state(struct hostapd_data *hapd)
+{
+	FILE *f;
+	time_t now;
+	struct sta_info *sta;
+	int i;
+#ifndef CONFIG_NO_RADIUS
+	char *buf;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (!hapd->conf->dump_log_name) {
+		wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
+			   "request");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
+		   hapd->conf->dump_log_name);
+	f = fopen(hapd->conf->dump_log_name, "w");
+	if (f == NULL) {
+		wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
+			   "writing.", hapd->conf->dump_log_name);
+		return;
+	}
+
+	time(&now);
+	fprintf(f, "hostapd state dump - %s", ctime(&now));
+	fprintf(f, "num_sta=%d num_sta_non_erp=%d "
+		"num_sta_no_short_slot_time=%d\n"
+		"num_sta_no_short_preamble=%d\n",
+		hapd->num_sta, hapd->iface->num_sta_non_erp,
+		hapd->iface->num_sta_no_short_slot_time,
+		hapd->iface->num_sta_no_short_preamble);
+
+	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
+
+		fprintf(f,
+			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+			"\n"
+			"  capability=0x%x listen_interval=%d\n",
+			sta->aid,
+			sta->flags,
+			(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+			(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+			(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
+			(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
+			(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
+			(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
+			(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+			 ""),
+			(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
+			 "[SHORT_PREAMBLE]" : ""),
+			(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+			(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
+			(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
+			(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
+			(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+			(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
+			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+			(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
+			sta->capability,
+			sta->listen_interval);
+
+		fprintf(f, "  supported_rates=");
+		for (i = 0; i < sta->supported_rates_len; i++)
+			fprintf(f, "%02x ", sta->supported_rates[i]);
+		fprintf(f, "\n");
+
+		fprintf(f,
+			"  timeout_next=%s\n",
+			(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
+			 (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
+			  "DEAUTH")));
+
+		ieee802_1x_dump_state(f, "  ", sta);
+	}
+
+#ifndef CONFIG_NO_RADIUS
+	buf = os_malloc(4096);
+	if (buf) {
+		int count = radius_client_get_mib(hapd->radius, buf, 4096);
+		if (count < 0)
+			count = 0;
+		else if (count > 4095)
+			count = 4095;
+		buf[count] = '\0';
+		fprintf(f, "%s", buf);
+
+#ifdef RADIUS_SERVER
+		count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
+		if (count < 0)
+			count = 0;
+		else if (count > 4095)
+			count = 4095;
+		buf[count] = '\0';
+		fprintf(f, "%s", buf);
+#endif /* RADIUS_SERVER */
+
+		os_free(buf);
+	}
+#endif /* CONFIG_NO_RADIUS */
+	fclose(f);
+}
+
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
+{
+	size_t i;
+
+	for (i = 0; i < iface->num_bss; i++)
+		hostapd_dump_state(iface->bss[i]);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/hostapd/dump_state.h
===================================================================
--- vendor/wpa/dist/hostapd/dump_state.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/dump_state.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,20 +0,0 @@
-/*
- * hostapd / State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DUMP_STATE_H
-#define DUMP_STATE_H
-
-int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
-
-#endif /* DUMP_STATE_H */

Copied: vendor/wpa/2.0/hostapd/dump_state.h (from rev 9639, vendor/wpa/dist/hostapd/dump_state.h)
===================================================================
--- vendor/wpa/2.0/hostapd/dump_state.h	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/dump_state.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,14 @@
+/*
+ * hostapd / State dump
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DUMP_STATE_H
+#define DUMP_STATE_H
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
+
+#endif /* DUMP_STATE_H */

Deleted: vendor/wpa/2.0/hostapd/eap_register.c
===================================================================
--- vendor/wpa/dist/hostapd/eap_register.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/eap_register.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,134 +0,0 @@
-/*
- * EAP method registration
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap_methods.h"
-#include "eap_register.h"
-
-
-/**
- * eap_server_register_methods - Register statically linked EAP server methods
- * Returns: 0 on success, -1 or -2 on failure
- *
- * This function is called at program initialization to register all EAP
- * methods that were linked in statically.
- */
-int eap_server_register_methods(void)
-{
-	int ret = 0;
-
-#ifdef EAP_SERVER_IDENTITY
-	if (ret == 0)
-		ret = eap_server_identity_register();
-#endif /* EAP_SERVER_IDENTITY */
-
-#ifdef EAP_SERVER_MD5
-	if (ret == 0)
-		ret = eap_server_md5_register();
-#endif /* EAP_SERVER_MD5 */
-
-#ifdef EAP_SERVER_TLS
-	if (ret == 0)
-		ret = eap_server_tls_register();
-#endif /* EAP_SERVER_TLS */
-
-#ifdef EAP_SERVER_MSCHAPV2
-	if (ret == 0)
-		ret = eap_server_mschapv2_register();
-#endif /* EAP_SERVER_MSCHAPV2 */
-
-#ifdef EAP_SERVER_PEAP
-	if (ret == 0)
-		ret = eap_server_peap_register();
-#endif /* EAP_SERVER_PEAP */
-
-#ifdef EAP_SERVER_TLV
-	if (ret == 0)
-		ret = eap_server_tlv_register();
-#endif /* EAP_SERVER_TLV */
-
-#ifdef EAP_SERVER_GTC
-	if (ret == 0)
-		ret = eap_server_gtc_register();
-#endif /* EAP_SERVER_GTC */
-
-#ifdef EAP_SERVER_TTLS
-	if (ret == 0)
-		ret = eap_server_ttls_register();
-#endif /* EAP_SERVER_TTLS */
-
-#ifdef EAP_SERVER_SIM
-	if (ret == 0)
-		ret = eap_server_sim_register();
-#endif /* EAP_SERVER_SIM */
-
-#ifdef EAP_SERVER_AKA
-	if (ret == 0)
-		ret = eap_server_aka_register();
-#endif /* EAP_SERVER_AKA */
-
-#ifdef EAP_SERVER_AKA_PRIME
-	if (ret == 0)
-		ret = eap_server_aka_prime_register();
-#endif /* EAP_SERVER_AKA_PRIME */
-
-#ifdef EAP_SERVER_PAX
-	if (ret == 0)
-		ret = eap_server_pax_register();
-#endif /* EAP_SERVER_PAX */
-
-#ifdef EAP_SERVER_PSK
-	if (ret == 0)
-		ret = eap_server_psk_register();
-#endif /* EAP_SERVER_PSK */
-
-#ifdef EAP_SERVER_SAKE
-	if (ret == 0)
-		ret = eap_server_sake_register();
-#endif /* EAP_SERVER_SAKE */
-
-#ifdef EAP_SERVER_GPSK
-	if (ret == 0)
-		ret = eap_server_gpsk_register();
-#endif /* EAP_SERVER_GPSK */
-
-#ifdef EAP_SERVER_VENDOR_TEST
-	if (ret == 0)
-		ret = eap_server_vendor_test_register();
-#endif /* EAP_SERVER_VENDOR_TEST */
-
-#ifdef EAP_SERVER_FAST
-	if (ret == 0)
-		ret = eap_server_fast_register();
-#endif /* EAP_SERVER_FAST */
-
-#ifdef EAP_SERVER_WSC
-	if (ret == 0)
-		ret = eap_server_wsc_register();
-#endif /* EAP_SERVER_WSC */
-
-#ifdef EAP_SERVER_IKEV2
-	if (ret == 0)
-		ret = eap_server_ikev2_register();
-#endif /* EAP_SERVER_IKEV2 */
-
-#ifdef EAP_SERVER_TNC
-	if (ret == 0)
-		ret = eap_server_tnc_register();
-#endif /* EAP_SERVER_TNC */
-
-	return ret;
-}

Copied: vendor/wpa/2.0/hostapd/eap_register.c (from rev 9639, vendor/wpa/dist/hostapd/eap_register.c)
===================================================================
--- vendor/wpa/2.0/hostapd/eap_register.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/eap_register.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,138 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "eap_server/eap_methods.h"
+#include "eap_register.h"
+
+
+/**
+ * eap_server_register_methods - Register statically linked EAP server methods
+ * Returns: 0 on success, -1 or -2 on failure
+ *
+ * This function is called at program initialization to register all EAP
+ * methods that were linked in statically.
+ */
+int eap_server_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+	if (ret == 0)
+		ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+	if (ret == 0)
+		ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+	if (ret == 0)
+		ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+	if (ret == 0)
+		ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+	if (ret == 0)
+		ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+	if (ret == 0)
+		ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+	if (ret == 0)
+		ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+	if (ret == 0)
+		ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+	if (ret == 0)
+		ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+	if (ret == 0)
+		ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (ret == 0)
+		ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+	if (ret == 0)
+		ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+	if (ret == 0)
+		ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+	if (ret == 0)
+		ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+	if (ret == 0)
+		ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+	if (ret == 0)
+		ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+	if (ret == 0)
+		ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+	if (ret == 0)
+		ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+	if (ret == 0)
+		ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+#ifdef EAP_SERVER_PWD
+	if (ret == 0)
+		ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/hostapd/eap_register.h
===================================================================
--- vendor/wpa/dist/hostapd/eap_register.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/eap_register.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,20 +0,0 @@
-/*
- * EAP method registration
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_REGISTER_H
-#define EAP_REGISTER_H
-
-int eap_server_register_methods(void);
-
-#endif /* EAP_REGISTER_H */

Copied: vendor/wpa/2.0/hostapd/eap_register.h (from rev 9639, vendor/wpa/dist/hostapd/eap_register.h)
===================================================================
--- vendor/wpa/2.0/hostapd/eap_register.h	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/eap_register.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,14 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_REGISTER_H
+#define EAP_REGISTER_H
+
+int eap_server_register_methods(void);
+
+#endif /* EAP_REGISTER_H */

Deleted: vendor/wpa/2.0/hostapd/hlr_auc_gw.c
===================================================================
--- vendor/wpa/dist/hostapd/hlr_auc_gw.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/hlr_auc_gw.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,714 +0,0 @@
-/*
- * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This is an example implementation of the EAP-SIM/AKA database/authentication
- * gateway interface to HLR/AuC. It is expected to be replaced with an
- * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
- * a local implementation of SIM triplet and AKA authentication data generator.
- *
- * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
- * to and external program, e.g., this hlr_auc_gw. This interface uses simple
- * text-based format:
- *
- * EAP-SIM / GSM triplet query/response:
- * SIM-REQ-AUTH <IMSI> <max_chal>
- * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
- * SIM-RESP-AUTH <IMSI> FAILURE
- *
- * EAP-AKA / UMTS query/response:
- * AKA-REQ-AUTH <IMSI>
- * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
- * AKA-RESP-AUTH <IMSI> FAILURE
- *
- * EAP-AKA / UMTS AUTS (re-synchronization):
- * AKA-AUTS <IMSI> <AUTS> <RAND>
- *
- * IMSI and max_chal are sent as an ASCII string,
- * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
- *
- * The example implementation here reads GSM authentication triplets from a
- * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
- * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
- * for real life authentication, but it is useful both as an example
- * implementation and for EAP-SIM testing.
- */
-
-#include "includes.h"
-#include <sys/un.h>
-
-#include "common.h"
-#include "crypto/milenage.h"
-
-static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
-static const char *socket_path;
-static int serv_sock = -1;
-
-/* GSM triplets */
-struct gsm_triplet {
-	struct gsm_triplet *next;
-	char imsi[20];
-	u8 kc[8];
-	u8 sres[4];
-	u8 _rand[16];
-};
-
-static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
-
-/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
-struct milenage_parameters {
-	struct milenage_parameters *next;
-	char imsi[20];
-	u8 ki[16];
-	u8 opc[16];
-	u8 amf[2];
-	u8 sqn[6];
-};
-
-static struct milenage_parameters *milenage_db = NULL;
-
-#define EAP_SIM_MAX_CHAL 3
-
-#define EAP_AKA_RAND_LEN 16
-#define EAP_AKA_AUTN_LEN 16
-#define EAP_AKA_AUTS_LEN 14
-#define EAP_AKA_RES_MAX_LEN 16
-#define EAP_AKA_IK_LEN 16
-#define EAP_AKA_CK_LEN 16
-
-
-static int open_socket(const char *path)
-{
-	struct sockaddr_un addr;
-	int s;
-
-	s = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket(PF_UNIX)");
-		return -1;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
-	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(PF_UNIX)");
-		close(s);
-		return -1;
-	}
-
-	return s;
-}
-
-
-static int read_gsm_triplets(const char *fname)
-{
-	FILE *f;
-	char buf[200], *pos, *pos2;
-	struct gsm_triplet *g = NULL;
-	int line, ret = 0;
-
-	if (fname == NULL)
-		return -1;
-
-	f = fopen(fname, "r");
-	if (f == NULL) {
-		printf("Could not open GSM tripler data file '%s'\n", fname);
-		return -1;
-	}
-
-	line = 0;
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		/* Parse IMSI:Kc:SRES:RAND */
-		buf[sizeof(buf) - 1] = '\0';
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0' && *pos != '\n')
-			pos++;
-		if (*pos == '\n')
-			*pos = '\0';
-		pos = buf;
-		if (*pos == '\0')
-			continue;
-
-		g = os_zalloc(sizeof(*g));
-		if (g == NULL) {
-			ret = -1;
-			break;
-		}
-
-		/* 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);
-			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);
-			ret = -1;
-			break;
-		}
-		pos = pos2 + 1;
-
-		/* SRES */
-		pos2 = strchr(pos, ':');
-		if (pos2 == NULL) {
-			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
-			       pos);
-			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);
-			ret = -1;
-			break;
-		}
-		pos = pos2 + 1;
-
-		g->next = gsm_db;
-		gsm_db = g;
-		g = NULL;
-	}
-	free(g);
-
-	fclose(f);
-
-	return ret;
-}
-
-
-static struct gsm_triplet * get_gsm_triplet(const char *imsi)
-{
-	struct gsm_triplet *g = gsm_db_pos;
-
-	while (g) {
-		if (strcmp(g->imsi, imsi) == 0) {
-			gsm_db_pos = g->next;
-			return g;
-		}
-		g = g->next;
-	}
-
-	g = gsm_db;
-	while (g && g != gsm_db_pos) {
-		if (strcmp(g->imsi, imsi) == 0) {
-			gsm_db_pos = g->next;
-			return g;
-		}
-		g = g->next;
-	}
-
-	return NULL;
-}
-
-
-static int read_milenage(const char *fname)
-{
-	FILE *f;
-	char buf[200], *pos, *pos2;
-	struct milenage_parameters *m = NULL;
-	int line, ret = 0;
-
-	if (fname == NULL)
-		return -1;
-
-	f = fopen(fname, "r");
-	if (f == NULL) {
-		printf("Could not open Milenage data file '%s'\n", fname);
-		return -1;
-	}
-
-	line = 0;
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		/* Parse IMSI Ki OPc AMF SQN */
-		buf[sizeof(buf) - 1] = '\0';
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0' && *pos != '\n')
-			pos++;
-		if (*pos == '\n')
-			*pos = '\0';
-		pos = buf;
-		if (*pos == '\0')
-			continue;
-
-		m = os_zalloc(sizeof(*m));
-		if (m == NULL) {
-			ret = -1;
-			break;
-		}
-
-		/* 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);
-			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);
-			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);
-			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);
-			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);
-			ret = -1;
-			break;
-		}
-		pos = pos2 + 1;
-
-		m->next = milenage_db;
-		milenage_db = m;
-		m = NULL;
-	}
-	free(m);
-
-	fclose(f);
-
-	return ret;
-}
-
-
-static struct milenage_parameters * get_milenage(const char *imsi)
-{
-	struct milenage_parameters *m = milenage_db;
-
-	while (m) {
-		if (strcmp(m->imsi, imsi) == 0)
-			break;
-		m = m->next;
-	}
-
-	return m;
-}
-
-
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
-{
-	int count, max_chal, ret;
-	char *pos;
-	char reply[1000], *rpos, *rend;
-	struct milenage_parameters *m;
-	struct gsm_triplet *g;
-
-	reply[0] = '\0';
-
-	pos = strchr(imsi, ' ');
-	if (pos) {
-		*pos++ = '\0';
-		max_chal = atoi(pos);
-		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
-			max_chal = EAP_SIM_MAX_CHAL;
-	} else
-		max_chal = EAP_SIM_MAX_CHAL;
-
-	rend = &reply[sizeof(reply)];
-	rpos = reply;
-	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
-	if (ret < 0 || ret >= rend - rpos)
-		return;
-	rpos += ret;
-
-	m = get_milenage(imsi);
-	if (m) {
-		u8 _rand[16], sres[4], kc[8];
-		for (count = 0; count < max_chal; count++) {
-			if (os_get_random(_rand, 16) < 0)
-				return;
-			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
-			*rpos++ = ' ';
-			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
-			*rpos++ = ':';
-			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
-			*rpos++ = ':';
-			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
-		}
-		*rpos = '\0';
-		goto send;
-	}
-
-	count = 0;
-	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
-		if (strcmp(g->imsi, imsi) != 0)
-			continue;
-
-		if (rpos < rend)
-			*rpos++ = ' ';
-		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
-		if (rpos < rend)
-			*rpos++ = ':';
-		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
-		if (rpos < rend)
-			*rpos++ = ':';
-		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
-		count++;
-	}
-
-	if (count == 0) {
-		printf("No GSM triplets found for %s\n", imsi);
-		ret = snprintf(rpos, rend - rpos, " FAILURE");
-		if (ret < 0 || ret >= rend - rpos)
-			return;
-		rpos += ret;
-	}
-
-send:
-	printf("Send: %s\n", reply);
-	if (sendto(s, reply, rpos - reply, 0,
-		   (struct sockaddr *) from, fromlen) < 0)
-		perror("send");
-}
-
-
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
-			 char *imsi)
-{
-	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
-	char reply[1000], *pos, *end;
-	u8 _rand[EAP_AKA_RAND_LEN];
-	u8 autn[EAP_AKA_AUTN_LEN];
-	u8 ik[EAP_AKA_IK_LEN];
-	u8 ck[EAP_AKA_CK_LEN];
-	u8 res[EAP_AKA_RES_MAX_LEN];
-	size_t res_len;
-	int ret;
-	struct milenage_parameters *m;
-
-	m = get_milenage(imsi);
-	if (m) {
-		if (os_get_random(_rand, EAP_AKA_RAND_LEN) < 0)
-			return;
-		res_len = EAP_AKA_RES_MAX_LEN;
-		inc_byte_array(m->sqn, 6);
-		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
-		       m->sqn[0], m->sqn[1], m->sqn[2],
-		       m->sqn[3], m->sqn[4], m->sqn[5]);
-		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
-				  autn, ik, ck, res, &res_len);
-	} else {
-		printf("Unknown IMSI: %s\n", imsi);
-#ifdef AKA_USE_FIXED_TEST_VALUES
-		printf("Using fixed test values for AKA\n");
-		memset(_rand, '0', EAP_AKA_RAND_LEN);
-		memset(autn, '1', EAP_AKA_AUTN_LEN);
-		memset(ik, '3', EAP_AKA_IK_LEN);
-		memset(ck, '4', EAP_AKA_CK_LEN);
-		memset(res, '2', EAP_AKA_RES_MAX_LEN);
-		res_len = EAP_AKA_RES_MAX_LEN;
-#else /* AKA_USE_FIXED_TEST_VALUES */
-		return;
-#endif /* AKA_USE_FIXED_TEST_VALUES */
-	}
-
-	pos = reply;
-	end = &reply[sizeof(reply)];
-	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
-	*pos++ = ' ';
-	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
-	*pos++ = ' ';
-	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
-	*pos++ = ' ';
-	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
-	*pos++ = ' ';
-	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
-
-	printf("Send: %s\n", reply);
-
-	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
-		   fromlen) < 0)
-		perror("send");
-}
-
-
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
-		     char *imsi)
-{
-	char *auts, *__rand;
-	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
-	struct milenage_parameters *m;
-
-	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
-
-	auts = strchr(imsi, ' ');
-	if (auts == NULL)
-		return;
-	*auts++ = '\0';
-
-	__rand = strchr(auts, ' ');
-	if (__rand == NULL)
-		return;
-	*__rand++ = '\0';
-
-	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
-	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
-	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
-		printf("Could not parse AUTS/RAND\n");
-		return;
-	}
-
-	m = get_milenage(imsi);
-	if (m == NULL) {
-		printf("Unknown IMSI: %s\n", imsi);
-		return;
-	}
-
-	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
-		printf("AKA-AUTS: Incorrect MAC-S\n");
-	} else {
-		memcpy(m->sqn, sqn, 6);
-		printf("AKA-AUTS: Re-synchronized: "
-		       "SQN=%02x%02x%02x%02x%02x%02x\n",
-		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
-	}
-}
-
-
-static int process(int s)
-{
-	char buf[1000];
-	struct sockaddr_un from;
-	socklen_t fromlen;
-	ssize_t res;
-
-	fromlen = sizeof(from);
-	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
-		       &fromlen);
-	if (res < 0) {
-		perror("recvfrom");
-		return -1;
-	}
-
-	if (res == 0)
-		return 0;
-
-	if ((size_t) res >= sizeof(buf))
-		res = sizeof(buf) - 1;
-	buf[res] = '\0';
-
-	printf("Received: %s\n", buf);
-
-	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
-		sim_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
-		aka_req_auth(s, &from, fromlen, buf + 13);
-	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
-		aka_auts(s, &from, fromlen, buf + 9);
-	else
-		printf("Unknown request: %s\n", buf);
-
-	return 0;
-}
-
-
-static void cleanup(void)
-{
-	struct gsm_triplet *g, *gprev;
-	struct milenage_parameters *m, *prev;
-
-	g = gsm_db;
-	while (g) {
-		gprev = g;
-		g = g->next;
-		free(gprev);
-	}
-
-	m = milenage_db;
-	while (m) {
-		prev = m;
-		m = m->next;
-		free(prev);
-	}
-
-	close(serv_sock);
-	unlink(socket_path);
-}
-
-
-static void handle_term(int sig)
-{
-	printf("Signal %d - terminate\n", sig);
-	exit(0);
-}
-
-
-static void usage(void)
-{
-	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
-	       "database/authenticator\n"
-	       "Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>\n"
-	       "\n"
-	       "usage:\n"
-	       "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
-	       "[-m<milenage file>]\n"
-	       "\n"
-	       "options:\n"
-	       "  -h = show this usage help\n"
-	       "  -s<socket path> = path for UNIX domain socket\n"
-	       "                    (default: %s)\n"
-	       "  -g<triplet file> = path for GSM authentication triplets\n"
-	       "  -m<milenage file> = path for Milenage keys\n",
-	       default_socket_path);
-}
-
-
-int main(int argc, char *argv[])
-{
-	int c;
-	char *milenage_file = NULL;
-	char *gsm_triplet_file = NULL;
-
-	socket_path = default_socket_path;
-
-	for (;;) {
-		c = getopt(argc, argv, "g:hm:s:");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'g':
-			gsm_triplet_file = optarg;
-			break;
-		case 'h':
-			usage();
-			return 0;
-		case 'm':
-			milenage_file = optarg;
-			break;
-		case 's':
-			socket_path = optarg;
-			break;
-		default:
-			usage();
-			return -1;
-		}
-	}
-
-	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
-		return -1;
-
-	if (milenage_file && read_milenage(milenage_file) < 0)
-		return -1;
-
-	serv_sock = open_socket(socket_path);
-	if (serv_sock < 0)
-		return -1;
-
-	printf("Listening for requests on %s\n", socket_path);
-
-	atexit(cleanup);
-	signal(SIGTERM, handle_term);
-	signal(SIGINT, handle_term);
-
-	for (;;)
-		process(serv_sock);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/hostapd/hlr_auc_gw.c (from rev 9639, vendor/wpa/dist/hostapd/hlr_auc_gw.c)
===================================================================
--- vendor/wpa/2.0/hostapd/hlr_auc_gw.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hlr_auc_gw.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1031 @@
+/*
+ * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+ * Copyright (c) 2005-2007, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface to HLR/AuC. It is expected to be replaced with an
+ * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
+ * a local implementation of SIM triplet and AKA authentication data generator.
+ *
+ * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
+ * to and external program, e.g., this hlr_auc_gw. This interface uses simple
+ * text-based format:
+ *
+ * EAP-SIM / GSM triplet query/response:
+ * SIM-REQ-AUTH <IMSI> <max_chal>
+ * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
+ * SIM-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS query/response:
+ * AKA-REQ-AUTH <IMSI>
+ * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+ * AKA-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS AUTS (re-synchronization):
+ * AKA-AUTS <IMSI> <AUTS> <RAND>
+ *
+ * IMSI and max_chal are sent as an ASCII string,
+ * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
+ *
+ * The example implementation here reads GSM authentication triplets from a
+ * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
+ * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
+ * for real life authentication, but it is useful both as an example
+ * implementation and for EAP-SIM/AKA/AKA' testing.
+ *
+ * SQN generation follows the not time-based Profile 2 described in
+ * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
+ * can be changed with a command line options if needed.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "crypto/milenage.h"
+#include "crypto/random.h"
+
+static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
+static const char *socket_path;
+static int serv_sock = -1;
+static char *milenage_file = NULL;
+static int update_milenage = 0;
+static int sqn_changes = 0;
+static int ind_len = 5;
+
+/* GSM triplets */
+struct gsm_triplet {
+	struct gsm_triplet *next;
+	char imsi[20];
+	u8 kc[8];
+	u8 sres[4];
+	u8 _rand[16];
+};
+
+static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
+
+/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
+struct milenage_parameters {
+	struct milenage_parameters *next;
+	char imsi[20];
+	u8 ki[16];
+	u8 opc[16];
+	u8 amf[2];
+	u8 sqn[6];
+	int set;
+};
+
+static struct milenage_parameters *milenage_db = NULL;
+
+#define EAP_SIM_MAX_CHAL 3
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+
+
+#ifdef CONFIG_SQLITE
+
+static sqlite3 *sqlite_db = NULL;
+static struct milenage_parameters db_tmp_milenage;
+
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+	char cmd[128];
+	os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+	return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_milenage(sqlite3 *db)
+{
+	char *err = NULL;
+	const char *sql =
+		"CREATE TABLE milenage("
+		"  imsi INTEGER PRIMARY KEY NOT NULL,"
+		"  ki CHAR(32) NOT NULL,"
+		"  opc CHAR(32) NOT NULL,"
+		"  amf CHAR(4) NOT NULL,"
+		"  sqn CHAR(12) NOT NULL"
+		");";
+
+	printf("Adding database table for milenage information\n");
+	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+		printf("SQLite error: %s\n", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+	sqlite3 *db;
+
+	if (sqlite3_open(db_file, &db)) {
+		printf("Failed to open database %s: %s\n",
+		       db_file, sqlite3_errmsg(db));
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	if (!db_table_exists(db, "milenage") &&
+	    db_table_create_milenage(db) < 0) {
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	return db;
+}
+
+
+static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct milenage_parameters *m = ctx;
+	int i;
+
+	m->set = 1;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
+			printf("Invalid ki value in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
+			printf("Invalid opcvalue in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
+			printf("Invalid amf value in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
+			printf("Invalid sqn value in database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
+{
+	char cmd[128];
+	unsigned long long imsi;
+
+	os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
+	imsi = atoll(imsi_txt);
+	os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
+		    "%llu", imsi);
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
+		    imsi);
+	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
+			 NULL) != SQLITE_OK)
+		return NULL;
+
+	if (!db_tmp_milenage.set)
+		return NULL;
+	return &db_tmp_milenage;
+}
+
+
+static int db_update_milenage_sqn(struct milenage_parameters *m)
+{
+	char cmd[128], val[13], *pos;
+
+	pos = val;
+	pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
+	*pos = '\0';
+	os_snprintf(cmd, sizeof(cmd),
+		    "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
+		    val, m->imsi);
+	if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+		printf("Failed to update SQN in database for IMSI %s\n",
+		       m->imsi);
+		return -1;
+	}
+	return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+static int open_socket(const char *path)
+{
+	struct sockaddr_un addr;
+	int s;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("hlr-auc-gw: bind(PF_UNIX)");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+
+
+static int read_gsm_triplets(const char *fname)
+{
+	FILE *f;
+	char buf[200], *pos, *pos2;
+	struct gsm_triplet *g = NULL;
+	int line, ret = 0;
+
+	if (fname == NULL)
+		return -1;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open GSM tripler data file '%s'\n", fname);
+		return -1;
+	}
+
+	line = 0;
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		/* Parse IMSI:Kc:SRES:RAND */
+		buf[sizeof(buf) - 1] = '\0';
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		pos = buf;
+		if (*pos == '\0')
+			continue;
+
+		g = os_zalloc(sizeof(*g));
+		if (g == NULL) {
+			ret = -1;
+			break;
+		}
+
+		/* 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);
+			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);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* SRES */
+		pos2 = strchr(pos, ':');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
+			       pos);
+			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);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		g->next = gsm_db;
+		gsm_db = g;
+		g = NULL;
+	}
+	os_free(g);
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static struct gsm_triplet * get_gsm_triplet(const char *imsi)
+{
+	struct gsm_triplet *g = gsm_db_pos;
+
+	while (g) {
+		if (strcmp(g->imsi, imsi) == 0) {
+			gsm_db_pos = g->next;
+			return g;
+		}
+		g = g->next;
+	}
+
+	g = gsm_db;
+	while (g && g != gsm_db_pos) {
+		if (strcmp(g->imsi, imsi) == 0) {
+			gsm_db_pos = g->next;
+			return g;
+		}
+		g = g->next;
+	}
+
+	return NULL;
+}
+
+
+static int read_milenage(const char *fname)
+{
+	FILE *f;
+	char buf[200], *pos, *pos2;
+	struct milenage_parameters *m = NULL;
+	int line, ret = 0;
+
+	if (fname == NULL)
+		return -1;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open Milenage data file '%s'\n", fname);
+		return -1;
+	}
+
+	line = 0;
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		/* Parse IMSI Ki OPc AMF SQN */
+		buf[sizeof(buf) - 1] = '\0';
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		pos = buf;
+		if (*pos == '\0')
+			continue;
+
+		m = os_zalloc(sizeof(*m));
+		if (m == NULL) {
+			ret = -1;
+			break;
+		}
+
+		/* 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);
+			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);
+			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);
+			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);
+			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);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		m->next = milenage_db;
+		milenage_db = m;
+		m = NULL;
+	}
+	os_free(m);
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static void update_milenage_file(const char *fname)
+{
+	FILE *f, *f2;
+	char buf[500], *pos;
+	char *end = buf + sizeof(buf);
+	struct milenage_parameters *m;
+	size_t imsi_len;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open Milenage data file '%s'\n", fname);
+		return;
+	}
+
+	snprintf(buf, sizeof(buf), "%s.new", fname);
+	f2 = fopen(buf, "w");
+	if (f2 == NULL) {
+		printf("Could not write Milenage data file '%s'\n", buf);
+		fclose(f);
+		return;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		/* IMSI Ki OPc AMF SQN */
+		buf[sizeof(buf) - 1] = '\0';
+
+		pos = strchr(buf, ' ');
+		if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
+			goto no_update;
+
+		imsi_len = pos - buf;
+
+		for (m = milenage_db; m; m = m->next) {
+			if (strncmp(buf, m->imsi, imsi_len) == 0 &&
+			    m->imsi[imsi_len] == '\0')
+				break;
+		}
+
+		if (!m)
+			goto no_update;
+
+		pos = buf;
+		pos += snprintf(pos, end - pos, "%s ", m->imsi);
+		pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
+		*pos++ = '\n';
+
+	no_update:
+		fprintf(f2, "%s", buf);
+	}
+
+	fclose(f2);
+	fclose(f);
+
+	snprintf(buf, sizeof(buf), "%s.bak", fname);
+	if (rename(fname, buf) < 0) {
+		perror("rename");
+		return;
+	}
+
+	snprintf(buf, sizeof(buf), "%s.new", fname);
+	if (rename(buf, fname) < 0) {
+		perror("rename");
+		return;
+	}
+
+}
+
+
+static struct milenage_parameters * get_milenage(const char *imsi)
+{
+	struct milenage_parameters *m = milenage_db;
+
+	while (m) {
+		if (strcmp(m->imsi, imsi) == 0)
+			break;
+		m = m->next;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (!m)
+		m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
+	return m;
+}
+
+
+static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	int count, max_chal, ret;
+	char *pos;
+	char reply[1000], *rpos, *rend;
+	struct milenage_parameters *m;
+	struct gsm_triplet *g;
+
+	reply[0] = '\0';
+
+	pos = strchr(imsi, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		max_chal = atoi(pos);
+		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+			max_chal = EAP_SIM_MAX_CHAL;
+	} else
+		max_chal = EAP_SIM_MAX_CHAL;
+
+	rend = &reply[sizeof(reply)];
+	rpos = reply;
+	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
+	if (ret < 0 || ret >= rend - rpos)
+		return;
+	rpos += ret;
+
+	m = get_milenage(imsi);
+	if (m) {
+		u8 _rand[16], sres[4], kc[8];
+		for (count = 0; count < max_chal; count++) {
+			if (random_get_bytes(_rand, 16) < 0)
+				return;
+			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+			*rpos++ = ' ';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
+		}
+		*rpos = '\0';
+		goto send;
+	}
+
+	count = 0;
+	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
+		if (strcmp(g->imsi, imsi) != 0)
+			continue;
+
+		if (rpos < rend)
+			*rpos++ = ' ';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
+		if (rpos < rend)
+			*rpos++ = ':';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
+		if (rpos < rend)
+			*rpos++ = ':';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
+		count++;
+	}
+
+	if (count == 0) {
+		printf("No GSM triplets found for %s\n", imsi);
+		ret = snprintf(rpos, rend - rpos, " FAILURE");
+		if (ret < 0 || ret >= rend - rpos)
+			return;
+		rpos += ret;
+	}
+
+send:
+	printf("Send: %s\n", reply);
+	if (sendto(s, reply, rpos - reply, 0,
+		   (struct sockaddr *) from, fromlen) < 0)
+		perror("send");
+}
+
+
+static void inc_sqn(u8 *sqn)
+{
+	u64 val, seq, ind;
+
+	/*
+	 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
+	 *
+	 * The mechanism used here is not time-based, so SEQ2 is void and
+	 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
+	 * of SEQ1 is 48 - ind_len bits.
+	 */
+
+	/* Increment both SEQ and IND by one */
+	val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
+	seq = (val >> ind_len) + 1;
+	ind = (val + 1) & ((1 << ind_len) - 1);
+	val = (seq << ind_len) | ind;
+	WPA_PUT_BE32(sqn, val >> 16);
+	WPA_PUT_BE16(sqn + 4, val & 0xffff);
+}
+
+
+static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
+	char reply[1000], *pos, *end;
+	u8 _rand[EAP_AKA_RAND_LEN];
+	u8 autn[EAP_AKA_AUTN_LEN];
+	u8 ik[EAP_AKA_IK_LEN];
+	u8 ck[EAP_AKA_CK_LEN];
+	u8 res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	int ret;
+	struct milenage_parameters *m;
+	int failed = 0;
+
+	m = get_milenage(imsi);
+	if (m) {
+		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
+			return;
+		res_len = EAP_AKA_RES_MAX_LEN;
+		inc_sqn(m->sqn);
+#ifdef CONFIG_SQLITE
+		db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+		sqn_changes = 1;
+		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+		       m->sqn[0], m->sqn[1], m->sqn[2],
+		       m->sqn[3], m->sqn[4], m->sqn[5]);
+		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
+				  autn, ik, ck, res, &res_len);
+	} else {
+		printf("Unknown IMSI: %s\n", imsi);
+#ifdef AKA_USE_FIXED_TEST_VALUES
+		printf("Using fixed test values for AKA\n");
+		memset(_rand, '0', EAP_AKA_RAND_LEN);
+		memset(autn, '1', EAP_AKA_AUTN_LEN);
+		memset(ik, '3', EAP_AKA_IK_LEN);
+		memset(ck, '4', EAP_AKA_CK_LEN);
+		memset(res, '2', EAP_AKA_RES_MAX_LEN);
+		res_len = EAP_AKA_RES_MAX_LEN;
+#else /* AKA_USE_FIXED_TEST_VALUES */
+		failed = 1;
+#endif /* AKA_USE_FIXED_TEST_VALUES */
+	}
+
+	pos = reply;
+	end = &reply[sizeof(reply)];
+	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+	if (failed) {
+		ret = snprintf(pos, end - pos, "FAILURE");
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		goto done;
+	}
+	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+
+done:
+	printf("Send: %s\n", reply);
+
+	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
+		   fromlen) < 0)
+		perror("send");
+}
+
+
+static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
+		     char *imsi)
+{
+	char *auts, *__rand;
+	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
+	struct milenage_parameters *m;
+
+	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
+
+	auts = strchr(imsi, ' ');
+	if (auts == NULL)
+		return;
+	*auts++ = '\0';
+
+	__rand = strchr(auts, ' ');
+	if (__rand == NULL)
+		return;
+	*__rand++ = '\0';
+
+	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
+	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
+		printf("Could not parse AUTS/RAND\n");
+		return;
+	}
+
+	m = get_milenage(imsi);
+	if (m == NULL) {
+		printf("Unknown IMSI: %s\n", imsi);
+		return;
+	}
+
+	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
+		printf("AKA-AUTS: Incorrect MAC-S\n");
+	} else {
+		memcpy(m->sqn, sqn, 6);
+		printf("AKA-AUTS: Re-synchronized: "
+		       "SQN=%02x%02x%02x%02x%02x%02x\n",
+		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+#ifdef CONFIG_SQLITE
+		db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+		sqn_changes = 1;
+	}
+}
+
+
+static int process(int s)
+{
+	char buf[1000];
+	struct sockaddr_un from;
+	socklen_t fromlen;
+	ssize_t res;
+
+	fromlen = sizeof(from);
+	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+		       &fromlen);
+	if (res < 0) {
+		perror("recvfrom");
+		return -1;
+	}
+
+	if (res == 0)
+		return 0;
+
+	if ((size_t) res >= sizeof(buf))
+		res = sizeof(buf) - 1;
+	buf[res] = '\0';
+
+	printf("Received: %s\n", buf);
+
+	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
+		sim_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
+		aka_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
+		aka_auts(s, &from, fromlen, buf + 9);
+	else
+		printf("Unknown request: %s\n", buf);
+
+	return 0;
+}
+
+
+static void cleanup(void)
+{
+	struct gsm_triplet *g, *gprev;
+	struct milenage_parameters *m, *prev;
+
+	if (update_milenage && milenage_file && sqn_changes)
+		update_milenage_file(milenage_file);
+
+	g = gsm_db;
+	while (g) {
+		gprev = g;
+		g = g->next;
+		os_free(gprev);
+	}
+
+	m = milenage_db;
+	while (m) {
+		prev = m;
+		m = m->next;
+		os_free(prev);
+	}
+
+	close(serv_sock);
+	unlink(socket_path);
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db) {
+		sqlite3_close(sqlite_db);
+		sqlite_db = NULL;
+	}
+#endif /* CONFIG_SQLITE */
+}
+
+
+static void handle_term(int sig)
+{
+	printf("Signal %d - terminate\n", sig);
+	exit(0);
+}
+
+
+static void usage(void)
+{
+	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
+	       "database/authenticator\n"
+	       "Copyright (c) 2005-2007, 2012, Jouni Malinen <j at w1.fi>\n"
+	       "\n"
+	       "usage:\n"
+	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
+	       "[-m<milenage file>] \\\n"
+	       "        [-D<DB file>] [-i<IND len in bits>]\n"
+	       "\n"
+	       "options:\n"
+	       "  -h = show this usage help\n"
+	       "  -u = update SQN in Milenage file on exit\n"
+	       "  -s<socket path> = path for UNIX domain socket\n"
+	       "                    (default: %s)\n"
+	       "  -g<triplet file> = path for GSM authentication triplets\n"
+	       "  -m<milenage file> = path for Milenage keys\n"
+	       "  -D<DB file> = path to SQLite database\n"
+	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
+	       default_socket_path);
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c;
+	char *gsm_triplet_file = NULL;
+	char *sqlite_db_file = NULL;
+
+	if (os_program_init())
+		return -1;
+
+	socket_path = default_socket_path;
+
+	for (;;) {
+		c = getopt(argc, argv, "D:g:hi:m:s:u");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'D':
+#ifdef CONFIG_SQLITE
+			sqlite_db_file = optarg;
+			break;
+#else /* CONFIG_SQLITE */
+			printf("No SQLite support included in the build\n");
+			return -1;
+#endif /* CONFIG_SQLITE */
+		case 'g':
+			gsm_triplet_file = optarg;
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'i':
+			ind_len = atoi(optarg);
+			if (ind_len < 0 || ind_len > 32) {
+				printf("Invalid IND length\n");
+				return -1;
+			}
+			break;
+		case 'm':
+			milenage_file = optarg;
+			break;
+		case 's':
+			socket_path = optarg;
+			break;
+		case 'u':
+			update_milenage = 1;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
+		usage();
+		return -1;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
+		return -1;
+#endif /* CONFIG_SQLITE */
+
+	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
+		return -1;
+
+	if (milenage_file && read_milenage(milenage_file) < 0)
+		return -1;
+
+	serv_sock = open_socket(socket_path);
+	if (serv_sock < 0)
+		return -1;
+
+	printf("Listening for requests on %s\n", socket_path);
+
+	atexit(cleanup);
+	signal(SIGTERM, handle_term);
+	signal(SIGINT, handle_term);
+
+	for (;;)
+		process(serv_sock);
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db) {
+		sqlite3_close(sqlite_db);
+		sqlite_db = NULL;
+	}
+#endif /* CONFIG_SQLITE */
+
+	os_program_deinit();
+
+	return 0;
+}

Copied: vendor/wpa/2.0/hostapd/hlr_auc_gw.txt (from rev 9639, vendor/wpa/dist/hostapd/hlr_auc_gw.txt)
===================================================================
--- vendor/wpa/2.0/hostapd/hlr_auc_gw.txt	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hlr_auc_gw.txt	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,104 @@
+HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+
+hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
+database/authentication gateway interface to HLR/AuC. It could be
+replaced with an implementation of SS7 gateway to GSM/UMTS
+authentication center (HLR/AuC). hostapd will send SIM/AKA
+authentication queries over a UNIX domain socket to and external
+program, e.g., hlr_auc_gw.
+
+hlr_auc_gw can be configured with GSM and UMTS authentication data with
+text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
+hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
+dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
+GSM triplet data is used for a more static configuration (e.g., triplets
+extracted from a SIM card).
+
+Alternatively, hlr_auc_gw can be built with support for an SQLite
+database for more dynamic operations. This is enabled by adding
+"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
+clean; make hlr_auc_gw" in this directory).
+
+hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
+hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
+is configured with command line parameters:
+
+hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
+        [-D<DB file>] [-i<IND len in bits>]
+
+options:
+  -h = show this usage help
+  -u = update SQN in Milenage file on exit
+  -s<socket path> = path for UNIX domain socket
+                    (default: /tmp/hlr_auc_gw.sock)
+  -g<triplet file> = path for GSM authentication triplets
+  -m<milenage file> = path for Milenage keys
+  -D<DB file> = path to SQLite database
+  -i<IND len in bits> = IND length for SQN (default: 5)
+
+
+The SQLite database can be initialized with sqlite, e.g., by running
+following commands in "sqlite3 /path/to/hlr_auc_gw.db":
+
+CREATE TABLE milenage(
+	imsi INTEGER PRIMARY KEY NOT NULL,
+	ki CHAR(32) NOT NULL,
+	opc CHAR(32) NOT NULL,
+	amf CHAR(4) NOT NULL,
+	sqn CHAR(12) NOT NULL
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+	232010000000000,
+	'90dca4eda45b53cf0f12d7c9c3bc6a89',
+	'cb9cccc4b9258e6dca4760379fb82581',
+	'61df',
+	'000000000000'
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+	555444333222111,
+	'5122250214c33e723a5dd523fc145fc0',
+	'981d464c7c52eb6e5036234984ad0bcf',
+	'c3ab',
+	'16f3b3f70fc1'
+);
+
+
+hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
+pseudonyms and reauth information into a SQLite database. This is
+configured with the db parameter within the eap_sim_db configuration
+option.
+
+
+"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
+Milenage parameters based on IMSI from the database. The database can be
+updated dynamically while hlr_auc_gw is running to add/remove/modify
+entries.
+
+
+Example configuration files for hostapd to operate as a RADIUS
+authentication server for EAP-SIM/AKA/AKA':
+
+hostapd.conf:
+
+driver=none
+radius_server_clients=hostapd.radius_clients
+eap_server=1
+eap_user_file=hostapd.eap_user
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
+eap_sim_aka_result_ind=1
+
+hostapd.radius_clients:
+
+0.0.0.0/0	radius
+
+hostapd.eap_user:
+
+"0"*	AKA
+"1"*	SIM
+"2"*	AKA
+"3"*	SIM
+"4"*	AKA
+"5"*	SIM
+"6"*	AKA'
+"7"*	AKA'
+"8"*	AKA'

Deleted: vendor/wpa/2.0/hostapd/hostapd.conf
===================================================================
--- vendor/wpa/dist/hostapd/hostapd.conf	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/hostapd.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1016 +0,0 @@
-##### hostapd configuration file ##############################################
-# Empty lines and lines starting with # are ignored
-
-# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
-# management frames); ath0 for madwifi
-interface=wlan0
-
-# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
-# configuration parameter, bridge, may be used to notify hostapd if the
-# interface is included in a bridge. This parameter is not used with Host AP
-# driver. If the bridge parameter is not set, the drivers will automatically
-# figure out the bridge interface (assuming sysfs is enabled and mounted to
-# /sys) and this parameter may not be needed.
-#
-# For nl80211, this parameter can be used to request the AP interface to be
-# added to the bridge automatically (brctl may refuse to do this before hostapd
-# has been started to change the interface mode). If needed, the bridge
-# interface is also created.
-#bridge=br0
-
-# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
-# default: hostap). nl80211 is used with all Linux mac80211 drivers.
-# Use driver=none if building hostapd as a standalone RADIUS server that does
-# not control any wireless/wired driver.
-# driver=hostap
-
-# hostapd event logger configuration
-#
-# Two output method: syslog and stdout (only usable if not forking to
-# background).
-#
-# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
-# modules):
-# bit 0 (1) = IEEE 802.11
-# bit 1 (2) = IEEE 802.1X
-# bit 2 (4) = RADIUS
-# bit 3 (8) = WPA
-# bit 4 (16) = driver interface
-# bit 5 (32) = IAPP
-# bit 6 (64) = MLME
-#
-# Levels (minimum value for logged events):
-#  0 = verbose debugging
-#  1 = debugging
-#  2 = informational messages
-#  3 = notification
-#  4 = warning
-#
-logger_syslog=-1
-logger_syslog_level=2
-logger_stdout=-1
-logger_stdout_level=2
-
-# Dump file for state information (on SIGUSR1)
-dump_file=/tmp/hostapd.dump
-
-# Interface for separate control program. If this is specified, hostapd
-# will create this directory and a UNIX domain socket for listening to requests
-# from external programs (CLI/GUI, etc.) for status information and
-# configuration. The socket file will be named based on the interface name, so
-# multiple hostapd processes/interfaces can be run at the same time if more
-# than one interface is used.
-# /var/run/hostapd is the recommended directory for sockets and by default,
-# hostapd_cli will use it when trying to connect with hostapd.
-ctrl_interface=/var/run/hostapd
-
-# Access control for the control interface can be configured by setting the
-# directory to allow only members of a group to use sockets. This way, it is
-# possible to run hostapd as root (since it needs to change network
-# configuration and open raw sockets) and still allow GUI/CLI components to be
-# run as non-root users. However, since the control interface can be used to
-# change the network configuration, this access needs to be protected in many
-# cases. By default, hostapd is configured to use gid 0 (root). If you
-# want to allow non-root users to use the contron interface, add a new group
-# and change this value to match with that group. Add users that should have
-# control interface access to this group.
-#
-# This variable can be a group name or gid.
-#ctrl_interface_group=wheel
-ctrl_interface_group=0
-
-
-##### IEEE 802.11 related configuration #######################################
-
-# SSID to be used in IEEE 802.11 management frames
-ssid=test
-
-# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
-# Set as needed to indicate country in which device is operating.
-# This can limit available channels and transmit power.
-#country_code=US
-
-# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
-# channels and transmit power levels based on the regulatory limits. The
-# country_code setting must be configured with the correct country for
-# IEEE 802.11d functions.
-# (default: 0 = disabled)
-#ieee80211d=1
-
-# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
-# Default: IEEE 802.11b
-hw_mode=a
-
-# Channel number (IEEE 802.11)
-# (default: 0, i.e., not set)
-# Please note that some drivers (e.g., madwifi) do not use this value from
-# hostapd and the channel will need to be configuration separately with
-# iwconfig.
-channel=60
-
-# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
-beacon_int=100
-
-# DTIM (delivery trafic information message) period (range 1..255):
-# number of beacons between DTIMs (1 = every beacon includes DTIM element)
-# (default: 2)
-dtim_period=2
-
-# Maximum number of stations allowed in station table. New stations will be
-# rejected after the station table is full. IEEE 802.11 has a limit of 2007
-# different association IDs, so this number should not be larger than that.
-# (default: 2007)
-max_num_sta=255
-
-# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
-# 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
-
-# Fragmentation threshold; 2346 = disabled (default); range 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
-
-# Rate configuration
-# Default is to enable all rates supported by the hardware. This configuration
-# item allows this list be filtered so that only the listed rates will be left
-# in the list. If the list is empty, all rates are used. This list can have
-# entries that are not in the list of rates the hardware supports (such entries
-# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
-# If this item is present, at least one rate have to be matching with the rates
-# hardware supports.
-# default: use the most common supported rate setting for the selected
-# hw_mode (i.e., this line can be removed from configuration file in most
-# cases)
-#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
-
-# Basic rate set configuration
-# List of rates (in 100 kbps) that are included in the basic rate set.
-# If this item is not included, usually reasonable default set is used.
-#basic_rates=10 20
-#basic_rates=10 20 55 110
-#basic_rates=60 120 240
-
-# Short Preamble
-# This parameter can be used to enable optional use of short preamble for
-# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
-# This applies only to IEEE 802.11b-compatible networks and this should only be
-# enabled if the local hardware supports use of short preamble. If any of the
-# associated STAs do not support short preamble, use of short preamble will be
-# disabled (and enabled when such STAs disassociate) dynamically.
-# 0 = do not allow use of short preamble (default)
-# 1 = allow use of short preamble
-#preamble=1
-
-# Station MAC address -based authentication
-# Please note that this kind of access control requires a driver that uses
-# hostapd to take care of management frame processing and as such, this can be
-# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
-# 0 = accept unless in deny list
-# 1 = deny unless in accept list
-# 2 = use external RADIUS server (accept/deny lists are searched first)
-macaddr_acl=0
-
-# Accept/deny lists are read from separate files (containing list of
-# MAC addresses, one per line). Use absolute path name to make sure that the
-# files can be read on SIGHUP configuration reloads.
-#accept_mac_file=/etc/hostapd.accept
-#deny_mac_file=/etc/hostapd.deny
-
-# IEEE 802.11 specifies two authentication algorithms. hostapd can be
-# configured to allow both of these or only one. Open system authentication
-# should be used with IEEE 802.1X.
-# Bit fields of allowed authentication algorithms:
-# bit 0 = Open System Authentication
-# bit 1 = Shared Key Authentication (requires WEP)
-auth_algs=3
-
-# Send empty SSID in beacons and ignore probe request frames that do not
-# specify full SSID, i.e., require stations to know SSID.
-# default: disabled (0)
-# 1 = send empty (length=0) SSID in beacon and ignore probe request for
-#     broadcast SSID
-# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
-#     with some clients that do not support empty SSID) and ignore probe
-#     requests for broadcast SSID
-ignore_broadcast_ssid=0
-
-# TX queue parameters (EDCF / bursting)
-# default for all these fields: not set, use hardware defaults
-# tx_queue_<queue name>_<param>
-# queues: data0, data1, data2, data3, after_beacon, beacon
-#		(data0 is the highest priority queue)
-# parameters:
-#   aifs: AIFS (default 2)
-#   cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
-#   cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
-#   burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
-#          bursting
-#
-# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
-# These parameters are used by the access point when transmitting frames
-# to the clients.
-#
-# Low priority / AC_BK = background
-#tx_queue_data3_aifs=7
-#tx_queue_data3_cwmin=15
-#tx_queue_data3_cwmax=1023
-#tx_queue_data3_burst=0
-# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
-#
-# Normal priority / AC_BE = best effort
-#tx_queue_data2_aifs=3
-#tx_queue_data2_cwmin=15
-#tx_queue_data2_cwmax=63
-#tx_queue_data2_burst=0
-# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
-#
-# High priority / AC_VI = video
-#tx_queue_data1_aifs=1
-#tx_queue_data1_cwmin=7
-#tx_queue_data1_cwmax=15
-#tx_queue_data1_burst=3.0
-# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
-#
-# Highest priority / AC_VO = voice
-#tx_queue_data0_aifs=1
-#tx_queue_data0_cwmin=3
-#tx_queue_data0_cwmax=7
-#tx_queue_data0_burst=1.5
-# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
-#
-# Special queues; normally not user configurable
-#
-#tx_queue_after_beacon_aifs=2
-#tx_queue_after_beacon_cwmin=15
-#tx_queue_after_beacon_cwmax=1023
-#tx_queue_after_beacon_burst=0
-#
-#tx_queue_beacon_aifs=2
-#tx_queue_beacon_cwmin=3
-#tx_queue_beacon_cwmax=7
-#tx_queue_beacon_burst=1.5
-
-# 802.1D Tag (= UP) to AC mappings
-# WMM specifies following mapping of data frames to different ACs. This mapping
-# can be configured using Linux QoS/tc and sch_pktpri.o module.
-# 802.1D Tag	802.1D Designation	Access Category	WMM Designation
-# 1		BK			AC_BK		Background
-# 2		-			AC_BK		Background
-# 0		BE			AC_BE		Best Effort
-# 3		EE			AC_BE		Best Effort
-# 4		CL			AC_VI		Video
-# 5		VI			AC_VI		Video
-# 6		VO			AC_VO		Voice
-# 7		NC			AC_VO		Voice
-# Data frames with no priority information: AC_BE
-# Management frames: AC_VO
-# PS-Poll frames: AC_BE
-
-# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
-# for 802.11a or 802.11g networks
-# These parameters are sent to WMM clients when they associate.
-# The parameters will be used by WMM clients for frames transmitted to the
-# access point.
-#
-# note - txop_limit is in units of 32microseconds
-# note - acm is admission control mandatory flag. 0 = admission control not
-# required, 1 = mandatory
-# note - here cwMin and cmMax are in exponent form. the actual cw value used
-# will be (2^n)-1 where n is the value given here
-#
-wmm_enabled=1
-#
-# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
-# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
-#uapsd_advertisement_enabled=1
-#
-# Low priority / AC_BK = background
-wmm_ac_bk_cwmin=4
-wmm_ac_bk_cwmax=10
-wmm_ac_bk_aifs=7
-wmm_ac_bk_txop_limit=0
-wmm_ac_bk_acm=0
-# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
-#
-# Normal priority / AC_BE = best effort
-wmm_ac_be_aifs=3
-wmm_ac_be_cwmin=4
-wmm_ac_be_cwmax=10
-wmm_ac_be_txop_limit=0
-wmm_ac_be_acm=0
-# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
-#
-# High priority / AC_VI = video
-wmm_ac_vi_aifs=2
-wmm_ac_vi_cwmin=3
-wmm_ac_vi_cwmax=4
-wmm_ac_vi_txop_limit=94
-wmm_ac_vi_acm=0
-# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
-#
-# Highest priority / AC_VO = voice
-wmm_ac_vo_aifs=2
-wmm_ac_vo_cwmin=2
-wmm_ac_vo_cwmax=3
-wmm_ac_vo_txop_limit=47
-wmm_ac_vo_acm=0
-# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
-
-# Static WEP key configuration
-#
-# The key number to use when transmitting.
-# It must be between 0 and 3, and the corresponding key must be set.
-# default: not set
-#wep_default_key=0
-# The WEP keys to use.
-# A key may be a quoted string or unquoted hexadecimal digits.
-# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
-# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
-# 128-bit (152-bit) WEP is used.
-# Only the default key must be supplied; the others are optional.
-# default: not set
-#wep_key0=123456789a
-#wep_key1="vwxyz"
-#wep_key2=0102030405060708090a0b0c0d
-#wep_key3=".2.4.6.8.0.23"
-
-# Station inactivity limit
-#
-# If a station does not send anything in ap_max_inactivity seconds, an
-# empty data frame is sent to it in order to verify whether it is
-# still in range. If this frame is not ACKed, the station will be
-# disassociated and then deauthenticated. This feature is used to
-# clear station table of old entries when the STAs move out of the
-# range.
-#
-# The station can associate again with the AP if it is still in range;
-# this inactivity poll is just used as a nicer way of verifying
-# inactivity; i.e., client will not report broken connection because
-# disassociation frame is not sent immediately without first polling
-# the STA with a data frame.
-# default: 300 (i.e., 5 minutes)
-#ap_max_inactivity=300
-
-# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
-# remain asleep). Default: 65535 (no limit apart from field size)
-#max_listen_interval=100
-
-# WDS (4-address frame) mode with per-station virtual interfaces
-# (only supported with driver=nl80211)
-# This mode allows associated stations to use 4-address frames to allow layer 2
-# bridging to be used.
-#wds_sta=1
-
-##### IEEE 802.11n related configuration ######################################
-
-# ieee80211n: Whether IEEE 802.11n (HT) is enabled
-# 0 = disabled (default)
-# 1 = enabled
-# Note: You will also need to enable WMM for full HT functionality.
-#ieee80211n=1
-
-# ht_capab: HT capabilities (list of flags)
-# LDPC coding capability: [LDPC] = supported
-# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
-#	channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
-#	with secondary channel below the primary channel
-#	(20 MHz only if neither is set)
-#	Note: There are limits on which channels can be used with HT40- and
-#	HT40+. Following table shows the channels that may be available for
-#	HT40- and HT40+ use per IEEE 802.11n Annex J:
-#	freq		HT40-		HT40+
-#	2.4 GHz		5-13		1-7 (1-9 in Europe/Japan)
-#	5 GHz		40,48,56,64	36,44,52,60
-#	(depending on the location, not all of these channels may be available
-#	for use)
-#	Please note that 40 MHz channels may switch their primary and secondary
-#	channels if needed or creation of 40 MHz channel maybe rejected based
-#	on overlapping BSSes. These changes are done automatically when hostapd
-#	is setting up the 40 MHz channel.
-# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
-#	(SMPS disabled if neither is set)
-# HT-greenfield: [GF] (disabled if not set)
-# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
-# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
-# Tx STBC: [TX-STBC] (disabled if not set)
-# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
-#	streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
-#	disabled if none of these set
-# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
-# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
-#	set)
-# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
-# PSMP support: [PSMP] (disabled if not set)
-# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
-#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
-
-##### IEEE 802.1X-2004 related configuration ##################################
-
-# Require IEEE 802.1X authorization
-#ieee8021x=1
-
-# IEEE 802.1X/EAPOL version
-# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
-# version 2. However, there are many client implementations that do not handle
-# the new version number correctly (they seem to drop the frames completely).
-# In order to make hostapd interoperate with these clients, the version number
-# can be set to the older version (1) with this configuration value.
-#eapol_version=2
-
-# Optional displayable message sent with EAP Request-Identity. The first \0
-# in this string will be converted to ASCII-0 (nul). This can be used to
-# separate network info (comma separated list of attribute=value pairs); see,
-# e.g., RFC 4284.
-#eap_message=hello
-#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
-
-# WEP rekeying (disabled if key lengths are not set or are set to 0)
-# Key lengths for default/broadcast and individual/unicast keys:
-# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
-# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
-#wep_key_len_broadcast=5
-#wep_key_len_unicast=5
-# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
-#wep_rekey_period=300
-
-# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
-# only broadcast keys are used)
-eapol_key_index_workaround=0
-
-# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
-# reauthentication).
-#eap_reauth_period=3600
-
-# Use PAE group address (01:80:c2:00:00:03) instead of individual target
-# address when sending EAPOL frames with driver=wired. This is the most common
-# mechanism used in wired authentication, but it also requires that the port
-# is only used by one station.
-#use_pae_group_addr=1
-
-##### Integrated EAP server ###################################################
-
-# Optionally, hostapd can be configured to use an integrated EAP server
-# to process EAP authentication locally without need for an external RADIUS
-# server. This functionality can be used both as a local authentication server
-# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
-
-# Use integrated EAP server instead of external RADIUS authentication
-# server. This is also needed if hostapd is configured to act as a RADIUS
-# authentication server.
-eap_server=0
-
-# Path for EAP server user database
-#eap_user_file=/etc/hostapd.eap_user
-
-# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
-#ca_cert=/etc/hostapd.ca.pem
-
-# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
-#server_cert=/etc/hostapd.server.pem
-
-# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
-# This may point to the same file as server_cert if both certificate and key
-# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
-# used by commenting out server_cert and specifying the PFX file as the
-# private_key.
-#private_key=/etc/hostapd.server.prv
-
-# Passphrase for private key
-#private_key_passwd=secret passphrase
-
-# Enable CRL verification.
-# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
-# valid CRL signed by the CA is required to be included in the ca_cert file.
-# This can be done by using PEM format for CA certificate and CRL and
-# concatenating these into one file. Whenever CRL changes, hostapd needs to be
-# restarted to take the new CRL into use.
-# 0 = do not verify CRLs (default)
-# 1 = check the CRL of the user certificate
-# 2 = check all CRLs in the certificate path
-#check_crl=1
-
-# 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. This parameter is required if anonymous EAP-FAST is used.
-# You can generate DH parameters file with OpenSSL, e.g.,
-# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
-#dh_file=/etc/hostapd.dh.pem
-
-# Configuration data for EAP-SIM database/authentication gateway interface.
-# This is a text string in implementation specific format. The example
-# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
-# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
-# prefix.
-#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
-
-# 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:
-# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
-#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
-
-# EAP-FAST authority identity (A-ID)
-# A-ID indicates the identity of the authority that issues PACs. The A-ID
-# should be unique across all issuing servers. In theory, this is a variable
-# length field, but due to some existing implementations requiring A-ID to be
-# 16 octets in length, it is strongly recommended to use that length for the
-# field to provid interoperability with deployed peer implementations. This
-# field is configured in hex format.
-#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
-
-# EAP-FAST authority identifier information (A-ID-Info)
-# This is a user-friendly name for the A-ID. For example, the enterprise name
-# and server name in a human-readable format. This field is encoded as UTF-8.
-#eap_fast_a_id_info=test server
-
-# Enable/disable different EAP-FAST provisioning modes:
-#0 = provisioning disabled
-#1 = only anonymous provisioning allowed
-#2 = only authenticated provisioning allowed
-#3 = both provisioning modes allowed (default)
-#eap_fast_prov=3
-
-# EAP-FAST PAC-Key lifetime in seconds (hard limit)
-#pac_key_lifetime=604800
-
-# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
-# limit). The server will generate a new PAC-Key when this number of seconds
-# (or fewer) of the lifetime remains.
-#pac_key_refresh_time=86400
-
-# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
-# (default: 0 = disabled).
-#eap_sim_aka_result_ind=1
-
-# Trusted Network Connect (TNC)
-# If enabled, TNC validation will be required before the peer is allowed to
-# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
-# EAP method is enabled, the peer will be allowed to connect without TNC.
-#tnc=1
-
-
-##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
-
-# Interface to be used for IAPP broadcast packets
-#iapp_interface=eth0
-
-
-##### RADIUS client configuration #############################################
-# for IEEE 802.1X with external Authentication Server, IEEE 802.11
-# authentication with external ACL for MAC addresses, and accounting
-
-# 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.
-# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
-# 48 octets long.
-#nas_identifier=ap.example.com
-
-# RADIUS authentication server
-#auth_server_addr=127.0.0.1
-#auth_server_port=1812
-#auth_server_shared_secret=secret
-
-# RADIUS accounting server
-#acct_server_addr=127.0.0.1
-#acct_server_port=1813
-#acct_server_shared_secret=secret
-
-# Secondary RADIUS servers; to be used if primary one does not reply to
-# RADIUS packets. These are optional and there can be more than one secondary
-# server listed.
-#auth_server_addr=127.0.0.2
-#auth_server_port=1812
-#auth_server_shared_secret=secret2
-#
-#acct_server_addr=127.0.0.2
-#acct_server_port=1813
-#acct_server_shared_secret=secret2
-
-# Retry interval for trying to return to the primary RADIUS server (in
-# seconds). RADIUS client code will automatically try to use the next server
-# when the current server is not replying to requests. If this interval is set,
-# primary server will be retried after configured amount of time even if the
-# currently used secondary server is still working.
-#radius_retry_primary_interval=600
-
-
-# Interim accounting update interval
-# If this is set (larger than 0) and acct_server is configured, hostapd will
-# send interim accounting updates every N seconds. Note: if set, this overrides
-# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
-# value should not be configured in hostapd.conf, if RADIUS server is used to
-# control the interim interval.
-# This value should not be less 600 (10 minutes) and must not be less than
-# 60 (1 minute).
-#radius_acct_interim_interval=600
-
-# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
-# is used for the stations. This information is parsed from following RADIUS
-# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
-# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
-# VLANID as a string). vlan_file option below must be configured if dynamic
-# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
-# used to set static client MAC address to VLAN ID mapping.
-# 0 = disabled (default)
-# 1 = option; use default interface if RADIUS server does not include VLAN ID
-# 2 = required; reject authentication if RADIUS server does not include VLAN ID
-#dynamic_vlan=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
-# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
-# interface and the line must include VLAN ID and interface name separated by
-# white space (space or tab).
-#vlan_file=/etc/hostapd.vlan
-
-# Interface where 802.1q tagged packets should appear when a RADIUS server is
-# used to determine which VLAN a station is on.  hostapd creates a bridge for
-# each VLAN.  Then hostapd adds a VLAN interface (associated with the interface
-# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
-# to the bridge.
-#vlan_tagged_interface=eth0
-
-
-##### RADIUS authentication server configuration ##############################
-
-# hostapd can be used as a RADIUS authentication server for other hosts. This
-# requires that the integrated EAP server is also enabled and both
-# authentication services are sharing the same configuration.
-
-# File name of the RADIUS clients configuration for the RADIUS server. If this
-# commented out, RADIUS server is disabled.
-#radius_server_clients=/etc/hostapd.radius_clients
-
-# The UDP port number for the RADIUS authentication server
-#radius_server_auth_port=1812
-
-# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
-#radius_server_ipv6=1
-
-
-##### WPA/IEEE 802.11i configuration ##########################################
-
-# Enable WPA. Setting this variable configures the AP to require WPA (either
-# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
-# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
-# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
-# RADIUS authentication server must be configured, and WPA-EAP must be included
-# in wpa_key_mgmt.
-# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
-# and/or WPA2 (full IEEE 802.11i/RSN):
-# bit0 = WPA
-# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
-#wpa=1
-
-# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
-# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
-# (8..63 characters) that will be converted to PSK. This conversion uses SSID
-# so the PSK changes when ASCII passphrase is used and the SSID is changed.
-# wpa_psk (dot11RSNAConfigPSKValue)
-# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
-#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
-#wpa_passphrase=secret passphrase
-
-# Optionally, WPA PSKs can be read from a separate text file (containing list
-# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
-# Use absolute path name to make sure that the files can be read on SIGHUP
-# configuration reloads.
-#wpa_psk_file=/etc/hostapd.wpa_psk
-
-# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
-# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
-# added to enable SHA256-based stronger algorithms.
-# (dot11RSNAConfigAuthenticationSuitesTable)
-#wpa_key_mgmt=WPA-PSK WPA-EAP
-
-# Set of accepted cipher suites (encryption algorithms) for pairwise keys
-# (unicast packets). This is a space separated list of algorithms:
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
-# Group cipher suite (encryption algorithm for broadcast and multicast frames)
-# is automatically selected based on this configuration. If only CCMP is
-# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
-# TKIP will be used as the group cipher.
-# (dot11RSNAConfigPairwiseCiphersTable)
-# Pairwise cipher for WPA (v1) (default: TKIP)
-#wpa_pairwise=TKIP CCMP
-# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
-#rsn_pairwise=CCMP
-
-# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
-# seconds. (dot11RSNAConfigGroupRekeyTime)
-#wpa_group_rekey=600
-
-# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
-# (dot11RSNAConfigGroupRekeyStrict)
-#wpa_strict_rekey=1
-
-# Time interval for rekeying GMK (master key used internally to generate GTKs
-# (in seconds).
-#wpa_gmk_rekey=86400
-
-# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
-# PTK to mitigate some attacks against TKIP deficiencies.
-#wpa_ptk_rekey=600
-
-# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
-# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
-# authentication and key handshake before actually associating with a new AP.
-# (dot11RSNAPreauthenticationEnabled)
-#rsn_preauth=1
-#
-# Space separated list of interfaces from which pre-authentication frames are
-# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
-# interface that are used for connections to other APs. This could include
-# wired interfaces and WDS links. The normal wireless data interface towards
-# associated stations (e.g., wlan0) should not be added, since
-# pre-authentication is only used with APs other than the currently associated
-# one.
-#rsn_preauth_interfaces=eth0
-
-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
-# allowed. This is only used with RSN/WPA2.
-# 0 = disabled (default)
-# 1 = enabled
-#peerkey=1
-
-# ieee80211w: Whether management frame protection (MFP) is enabled
-# 0 = disabled (default)
-# 1 = optional
-# 2 = required
-#ieee80211w=0
-
-# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
-# (maximum time to wait for a SA Query response)
-# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
-#assoc_sa_query_max_timeout=1000
-
-# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
-# (time between two subsequent SA Query requests)
-# dot11AssociationSAQueryRetryTimeout, 1...4294967295
-#assoc_sa_query_retry_timeout=201
-
-
-# okc: Opportunistic Key Caching (aka Proactive Key Caching)
-# Allow PMK cache to be shared opportunistically among configured interfaces
-# and BSSes (i.e., all configurations within a single hostapd process).
-# 0 = disabled (default)
-# 1 = enabled
-#okc=1
-
-
-##### IEEE 802.11r configuration ##############################################
-
-# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
-# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
-# same SSID) between which a STA can use Fast BSS Transition.
-# 2-octet identifier as a hex string.
-#mobility_domain=a1b2
-
-# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
-# 1 to 48 octet identifier.
-# This is configured with nas_identifier (see RADIUS client section above).
-
-# Default lifetime of the PMK-RO in minutes; range 1..65535
-# (dot11FTR0KeyLifetime)
-#r0_key_lifetime=10000
-
-# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
-# 6-octet identifier as a hex string.
-#r1_key_holder=000102030405
-
-# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
-# (dot11FTReassociationDeadline)
-#reassociation_deadline=1000
-
-# List of R0KHs in the same Mobility Domain
-# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
-# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
-# address when requesting PMK-R1 key from the R0KH that the STA used during the
-# Initial Mobility Domain Association.
-#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
-#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
-# And so on.. One line per R0KH.
-
-# List of R1KHs in the same Mobility Domain
-# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
-# This list is used to map R1KH-ID to a destination MAC address when sending
-# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
-# that can request PMK-R1 keys.
-#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
-#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
-# And so on.. One line per R1KH.
-
-# Whether PMK-R1 push is enabled at R0KH
-# 0 = do not push PMK-R1 to all configured R1KHs (default)
-# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
-#pmk_r1_push=1
-
-##### Neighbor table ##########################################################
-# Maximum number of entries kept in AP table (either for neigbor table or for
-# detecting Overlapping Legacy BSS Condition). The oldest entry will be
-# removed when adding a new entry that would make the list grow over this
-# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
-# enabled, so this field should not be set to 0 when using IEEE 802.11g.
-# default: 255
-#ap_table_max_size=255
-
-# Number of seconds of no frames received after which entries may be deleted
-# from the AP table. Since passive scanning is not usually performed frequently
-# this should not be set to very small value. In addition, there is no
-# guarantee that every scan cycle will receive beacon frames from the
-# neighboring APs.
-# default: 60
-#ap_table_expiration_time=3600
-
-
-##### Wi-Fi Protected Setup (WPS) #############################################
-
-# WPS state
-# 0 = WPS disabled (default)
-# 1 = WPS enabled, not configured
-# 2 = WPS enabled, configured
-#wps_state=2
-
-# AP can be configured into a locked state where new WPS Registrar are not
-# accepted, but previously authorized Registrars (including the internal one)
-# can continue to add new Enrollees.
-#ap_setup_locked=1
-
-# Universally Unique IDentifier (UUID; see RFC 4122) of the device
-# This value is used as the UUID for the internal WPS Registrar. If the AP
-# is also using UPnP, this value should be set to the device's UPnP UUID.
-# If not configured, UUID will be generated based on the local MAC address.
-#uuid=12345678-9abc-def0-1234-56789abcdef0
-
-# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
-# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
-# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
-# per-device PSKs is recommended as the more secure option (i.e., make sure to
-# set wpa_psk_file when using WPS with WPA-PSK).
-
-# When an Enrollee requests access to the network with PIN method, the Enrollee
-# PIN will need to be entered for the Registrar. PIN request notifications are
-# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
-# text file that could be used, e.g., to populate the AP administration UI with
-# pending PIN requests. If the following variable is set, the PIN requests will
-# be written to the configured file.
-#wps_pin_requests=/var/run/hostapd_wps_pin_requests
-
-# Device Name
-# User-friendly description of device; up to 32 octets encoded in UTF-8
-#device_name=Wireless AP
-
-# Manufacturer
-# The manufacturer of the device (up to 64 ASCII characters)
-#manufacturer=Company
-
-# Model Name
-# Model of the device (up to 32 ASCII characters)
-#model_name=WAP
-
-# Model Number
-# Additional device description (up to 32 ASCII characters)
-#model_number=123
-
-# Serial Number
-# Serial number of the device (up to 32 characters)
-#serial_number=12345
-
-# Primary Device Type
-# Used format: <categ>-<OUI>-<subcateg>
-# categ = Category as an integer value
-# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
-#       default WPS OUI
-# subcateg = OUI-specific Sub Category as an integer value
-# Examples:
-#   1-0050F204-1 (Computer / PC)
-#   1-0050F204-2 (Computer / Server)
-#   5-0050F204-1 (Storage / NAS)
-#   6-0050F204-1 (Network Infrastructure / AP)
-#device_type=6-0050F204-1
-
-# OS Version
-# 4-octet operating system version number (hex string)
-#os_version=01020300
-
-# Config Methods
-# List of the supported configuration methods
-# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
-#	nfc_interface push_button keypad
-#config_methods=label display push_button keypad
-
-# Static access point PIN for initial configuration and adding Registrars
-# If not set, hostapd will not allow external WPS Registrars to control the
-# access point. The AP PIN can also be set at runtime with hostapd_cli
-# wps_ap_pin command. Use of temporary (enabled by user action) and random
-# AP PIN is much more secure than configuring a static AP PIN here. As such,
-# use of the ap_pin parameter is not recommended if the AP device has means for
-# displaying a random PIN.
-#ap_pin=12345670
-
-# Skip building of automatic WPS credential
-# This can be used to allow the automatically generated Credential attribute to
-# be replaced with pre-configured Credential(s).
-#skip_cred_build=1
-
-# Additional Credential attribute(s)
-# This option can be used to add pre-configured Credential attributes into M8
-# message when acting as a Registrar. If skip_cred_build=1, this data will also
-# be able to override the Credential attribute that would have otherwise been
-# automatically generated based on network configuration. This configuration
-# option points to an external file that much contain the WPS Credential
-# attribute(s) as binary data.
-#extra_cred=hostapd.cred
-
-# Credential processing
-#   0 = process received credentials internally (default)
-#   1 = do not process received credentials; just pass them over ctrl_iface to
-#	external program(s)
-#   2 = process received credentials internally and pass them over ctrl_iface
-#	to external program(s)
-# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
-# extra_cred be used to provide the Credential data for Enrollees.
-#
-# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
-# both for Credential processing and for marking AP Setup Locked based on
-# validation failures of AP PIN. An external program is responsible on updating
-# the configuration appropriately in this case.
-#wps_cred_processing=0
-
-# AP Settings Attributes for M7
-# By default, hostapd generates the AP Settings Attributes for M7 based on the
-# current configuration. It is possible to override this by providing a file
-# with pre-configured attributes. This is similar to extra_cred file format,
-# but the AP Settings attributes are not encapsulated in a Credential
-# attribute.
-#ap_settings=hostapd.ap_settings
-
-# WPS UPnP interface
-# If set, support for external Registrars is enabled.
-#upnp_iface=br0
-
-# Friendly Name (required for UPnP)
-# Short description for end use. Should be less than 64 characters.
-#friendly_name=WPS Access Point
-
-# Manufacturer URL (optional for UPnP)
-#manufacturer_url=http://www.example.com/
-
-# Model Description (recommended for UPnP)
-# Long description for end user. Should be less than 128 characters.
-#model_description=Wireless Access Point
-
-# Model URL (optional for UPnP)
-#model_url=http://www.example.com/model/
-
-# Universal Product Code (optional for UPnP)
-# 12-digit, all-numeric code that identifies the consumer package.
-#upc=123456789012
-
-##### Multiple BSSID support ##################################################
-#
-# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
-# interfaces). Other BSSIDs can be added by using separator 'bss' with
-# default interface name to be allocated for the data packets of the new BSS.
-#
-# hostapd will generate BSSID mask based on the BSSIDs that are
-# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
-# not the case, the MAC address of the radio must be changed before starting
-# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
-# every secondary BSS, this limitation is not applied at hostapd and other
-# masks may be used if the driver supports them (e.g., swap the locally
-# administered bit)
-#
-# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
-# specified using the 'bssid' parameter.
-# If an explicit BSSID is specified, it must be chosen such that it:
-# - results in a valid MASK that covers it and the dev_addr
-# - is not the same as the MAC address of the radio
-# - is not the same as any other explicitly specified BSSID
-#
-# Please note that hostapd uses some of the values configured for the first BSS
-# as the defaults for the following BSSes. However, it is recommended that all
-# BSSes include explicit configuration of all relevant configuration items.
-#
-#bss=wlan0_0
-#ssid=test2
-# most of the above items can be used here (apart from radio interface specific
-# items, like channel)
-
-#bss=wlan0_1
-#bssid=00:13:10:95:fe:0b
-# ...

Copied: vendor/wpa/2.0/hostapd/hostapd.conf (from rev 9639, vendor/wpa/dist/hostapd/hostapd.conf)
===================================================================
--- vendor/wpa/2.0/hostapd/hostapd.conf	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hostapd.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1535 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
+# management frames); ath0 for madwifi
+interface=wlan0
+
+# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# configuration parameter, bridge, may be used to notify hostapd if the
+# interface is included in a bridge. This parameter is not used with Host AP
+# driver. If the bridge parameter is not set, the drivers will automatically
+# figure out the bridge interface (assuming sysfs is enabled and mounted to
+# /sys) and this parameter may not be needed.
+#
+# For nl80211, this parameter can be used to request the AP interface to be
+# added to the bridge automatically (brctl may refuse to do this before hostapd
+# has been started to change the interface mode). If needed, the bridge
+# interface is also created.
+#bridge=br0
+
+# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none if building hostapd as a standalone RADIUS server that does
+# not control any wireless/wired driver.
+# driver=hostap
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 5 (32) = IAPP
+# bit 6 (64) = MLME
+#
+# Levels (minimum value for logged events):
+#  0 = verbose debugging
+#  1 = debugging
+#  2 = informational messages
+#  3 = notification
+#  4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Dump file for state information (on SIGUSR1)
+dump_file=/tmp/hostapd.dump
+
+# Interface for separate control program. If this is specified, hostapd
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run hostapd as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, hostapd is configured to use gid 0 (root). If you
+# want to allow non-root users to use the contron interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
+
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
+
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=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)
+# Default: IEEE 802.11b
+hw_mode=g
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set)
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+channel=1
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery traffic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# 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
+
+# Fragmentation threshold; 2346 = disabled (default); range 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
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=3
+
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+#     broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+#     with some clients that do not support empty SSID) and ignore probe
+#     requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# Additional vendor specfic 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
+
+# TX queue parameters (EDCF / bursting)
+# tx_queue_<queue name>_<param>
+# queues: data0, data1, data2, data3, after_beacon, beacon
+#		(data0 is the highest priority queue)
+# parameters:
+#   aifs: AIFS (default 2)
+#   cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
+#   cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+#   burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
+#          bursting
+#
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# These parameters are used by the access point when transmitting frames
+# to the clients.
+#
+# Low priority / AC_BK = background
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
+#
+# Normal priority / AC_BE = best effort
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
+#
+# High priority / AC_VI = video
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
+#
+# Highest priority / AC_VO = voice
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+
+# 802.1D Tag (= UP) to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag	802.1D Designation	Access Category	WMM Designation
+# 1		BK			AC_BK		Background
+# 2		-			AC_BK		Background
+# 0		BE			AC_BE		Best Effort
+# 3		EE			AC_BE		Best Effort
+# 4		CL			AC_VI		Video
+# 5		VI			AC_VI		Video
+# 6		VO			AC_VO		Voice
+# 7		NC			AC_VO		Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
+
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# for 802.11a or 802.11g networks
+# These parameters are sent to WMM clients when they associate.
+# The parameters will be used by WMM clients for frames transmitted to the
+# access point.
+#
+# note - txop_limit is in units of 32microseconds
+# note - acm is admission control mandatory flag. 0 = admission control not
+# required, 1 = mandatory
+# note - here cwMin and cmMax are in exponent form. the actual cw value used
+# will be (2^n)-1 where n is the value given here
+#
+wmm_enabled=1
+#
+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
+#uapsd_advertisement_enabled=1
+#
+# Low priority / AC_BK = background
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
+#
+# Normal priority / AC_BE = best effort
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
+#
+# High priority / AC_VI = video
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
+#
+# Highest priority / AC_VO = voice
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
+
+# Disassociate stations based on excessive transmission failures or other
+# indications of connection loss. This depends on the driver capabilities and
+# may not be available with all drivers.
+#disassoc_low_ack=1
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+# WDS (4-address frame) mode with per-station virtual interfaces
+# (only supported with driver=nl80211)
+# This mode allows associated stations to use 4-address frames to allow layer 2
+# bridging to be used.
+#wds_sta=1
+
+# If bridge parameter is set, the WDS STA interface will be added to the same
+# bridge by default. This can be overridden with the wds_bridge parameter to
+# use a separate bridge.
+#wds_bridge=wds-br0
+
+# Client isolation can be used to prevent low-level bridging of frames between
+# associated stations in the BSS. By default, this bridging is allowed.
+#ap_isolate=1
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
+#ieee80211n=1
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+#	channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+#	with secondary channel below the primary channel
+#	(20 MHz only if neither is set)
+#	Note: There are limits on which channels can be used with HT40- and
+#	HT40+. Following table shows the channels that may be available for
+#	HT40- and HT40+ use per IEEE 802.11n Annex J:
+#	freq		HT40-		HT40+
+#	2.4 GHz		5-13		1-7 (1-9 in Europe/Japan)
+#	5 GHz		40,48,56,64	36,44,52,60
+#	(depending on the location, not all of these channels may be available
+#	for use)
+#	Please note that 40 MHz channels may switch their primary and secondary
+#	channels if needed or creation of 40 MHz channel maybe rejected based
+#	on overlapping BSSes. These changes are done automatically when hostapd
+#	is setting up the 40 MHz channel.
+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
+#	(SMPS disabled if neither is set)
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+#	streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+#	disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+#	set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# PSMP support: [PSMP] (disabled if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+# Require stations to support HT PHY (reject association if they do not)
+#require_ht=1
+
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+#   Beamformee's capability indicating the maximum number of beamformer
+#   antennas the beamformee can support when sending compressed beamforming
+#   feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+#  or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesnt 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
+#  mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+#  0 = (no feedback) if the STA does not provide VHT MFB (default)
+#  1 = reserved
+#  2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+#  3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+#      STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
+#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
+
+##### IEEE 802.1X-2004 related configuration ##################################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# IEEE 802.1X/EAPOL version
+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
+# version 2. However, there are many client implementations that do not handle
+# the new version number correctly (they seem to drop the frames completely).
+# In order to make hostapd interoperate with these clients, the version number
+# can be set to the older version (1) with this configuration value.
+#eapol_version=2
+
+# Optional displayable message sent with EAP Request-Identity. The first \0
+# in this string will be converted to ASCII-0 (nul). This can be used to
+# separate network info (comma separated list of attribute=value pairs); see,
+# e.g., RFC 4284.
+#eap_message=hello
+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+#eap_reauth_period=3600
+
+# Use PAE group address (01:80:c2:00:00:03) instead of individual target
+# address when sending EAPOL frames with driver=wired. This is the most common
+# mechanism used in wired authentication, but it also requires that the port
+# is only used by one station.
+#use_pae_group_addr=1
+
+##### Integrated EAP server ###################################################
+
+# Optionally, hostapd can be configured to use an integrated EAP server
+# to process EAP authentication locally without need for an external RADIUS
+# server. This functionality can be used both as a local authentication server
+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
+
+# Use integrated EAP server instead of external RADIUS authentication
+# server. This is also needed if hostapd is configured to act as a RADIUS
+# authentication server.
+eap_server=0
+
+# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# Enable CRL verification.
+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
+# valid CRL signed by the CA is required to be included in the ca_cert file.
+# This can be done by using PEM format for CA certificate and CRL and
+# concatenating these into one file. Whenever CRL changes, hostapd needs to be
+# restarted to take the new CRL into use.
+# 0 = do not verify CRLs (default)
+# 1 = check the CRL of the user certificate
+# 2 = check all CRLs in the certificate path
+#check_crl=1
+
+# 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. This parameter is required if anonymous EAP-FAST is used.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+#dh_file=/etc/hostapd.dh.pem
+
+# Fragment size for EAP methods
+#fragment_size=1400
+
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+
+# 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:
+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
+
+# EAP-FAST authority identity (A-ID)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations requiring A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provid interoperability with deployed peer implementations. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=1
+
+
+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
+
+# Interface to be used for IAPP broadcast packets
+#iapp_interface=eth0
+
+
+##### RADIUS client configuration #############################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# 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.
+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
+# 48 octets long.
+#nas_identifier=ap.example.com
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). vlan_file option below must be configured if dynamic
+# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
+# used to set static client MAC address to VLAN ID mapping.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=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
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on.  hostapd creates a bridge for
+# each VLAN.  Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
+
+##### RADIUS authentication server configuration ##############################
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP server is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
+#radius_server_ipv6=1
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+#	Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+#	Tunnel-Password
+#wpa_psk_radius=0
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# (dot11RSNAConfigAuthenticationSuitesTable)
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+# (dot11RSNAConfigPairwiseCiphersTable)
+# Pairwise cipher for WPA (v1) (default: TKIP)
+#wpa_pairwise=TKIP CCMP
+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+#rsn_pairwise=CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+#wpa_group_rekey=600
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+#wpa_ptk_rekey=600
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
+
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+
+# ieee80211w: Whether management frame protection (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+# disable_pmksa_caching: Disable PMKSA caching
+# This parameter can be used to disable caching of PMKSA created through EAP
+# authentication. RSN preauthentication may still end up using PMKSA caching if
+# it is enabled (rsn_preauth=1).
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#disable_pmksa_caching=0
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+
+##### IEEE 802.11r configuration ##############################################
+
+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
+# same SSID) between which a STA can use Fast BSS Transition.
+# 2-octet identifier as a hex string.
+#mobility_domain=a1b2
+
+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
+# 1 to 48 octet identifier.
+# This is configured with nas_identifier (see RADIUS client section above).
+
+# Default lifetime of the PMK-RO in minutes; range 1..65535
+# (dot11FTR0KeyLifetime)
+#r0_key_lifetime=10000
+
+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
+# 6-octet identifier as a hex string.
+#r1_key_holder=000102030405
+
+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
+# (dot11FTReassociationDeadline)
+#reassociation_deadline=1000
+
+# List of R0KHs in the same Mobility Domain
+# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
+# address when requesting PMK-R1 key from the R0KH that the STA used during the
+# Initial Mobility Domain Association.
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+# And so on.. One line per R0KH.
+
+# List of R1KHs in the same Mobility Domain
+# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# This list is used to map R1KH-ID to a destination MAC address when sending
+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
+# that can request PMK-R1 keys.
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+# And so on.. One line per R1KH.
+
+# Whether PMK-R1 push is enabled at R0KH
+# 0 = do not push PMK-R1 to all configured R1KHs (default)
+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
+#pmk_r1_push=1
+
+##### Neighbor table ##########################################################
+# Maximum number of entries kept in AP table (either for neigbor table or for
+# detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+#	nfc_interface push_button keypad virtual_display physical_display
+#	virtual_push_button physical_push_button
+#config_methods=label virtual_display virtual_push_button keypad
+
+# WPS capability discovery workaround for PBC with Windows 7
+# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
+# as a Registrar and using M1 from the AP. The config methods attribute in that
+# message is supposed to indicate only the configuration method supported by
+# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
+# PBC shall not be used and as such, the PushButton config method is removed
+# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
+# the PushButton config method is left in M1 (if included in config_methods
+# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
+# in the AP).
+#pbc_in_m1=1
+
+# Static access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+#   0 = process received credentials internally (default)
+#   1 = do not process received credentials; just pass them over ctrl_iface to
+#	external program(s)
+#   2 = process received credentials internally and pass them over ctrl_iface
+#	to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
+##### Wi-Fi Direct (P2P) ######################################################
+
+# Enable P2P Device management
+#manage_p2p=1
+
+# Allow cross connection
+#allow_cross_connection=1
+
+#### TDLS (IEEE 802.11z-2010) #################################################
+
+# Prohibit use of TDLS in this BSS
+#tdls_prohibit=1
+
+# Prohibit use of TDLS Channel Switching in this BSS
+#tdls_prohibit_chan_switch=1
+
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1  Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+#	0 = Realm formatted in accordance with IETF RFC 4282
+#	1 = UTF-8 formatted character string that is not formatted in
+#	    accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+#	1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+#	1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+#	5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+#	10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+#    (encoded as two hex digits)
+#    Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+#	1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+#	1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
+##### Multiple BSSID support ##################################################
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
+# every secondary BSS, this limitation is not applied at hostapd and other
+# masks may be used if the driver supports them (e.g., swap the locally
+# administered bit)
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...

Deleted: vendor/wpa/2.0/hostapd/hostapd.eap_user
===================================================================
--- vendor/wpa/dist/hostapd/hostapd.eap_user	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/hostapd.eap_user	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,91 +0,0 @@
-# hostapd user database for integrated EAP server
-
-# Each line must contain an identity, EAP method(s), and an optional password
-# separated with whitespace (space or tab). The identity and password must be
-# double quoted ("user"). Password can alternatively be stored as
-# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
-# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
-# that the plaintext password does not need to be included in the user file.
-# Password hash is stored as hash:<16-octets of hex data> without quotation
-# marks.
-
-# [2] flag in the end of the line can be used to mark users for tunneled phase
-# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
-# identity can be used in the unencrypted phase 1 and the real user identity
-# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
-# access is needed, two user entries is needed, one for phase 1 and another
-# with the same username for phase 2.
-#
-# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
-# password option.
-# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
-# password.
-# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
-#
-# * can be used as a wildcard to match any user identity. The main purposes for
-# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
-# avoid having to configure every certificate for EAP-TLS authentication. The
-# first matching entry is selected, so * should be used as the last phase 1
-# user entry.
-#
-# "prefix"* can be used to match the given prefix and anything after this. The
-# main purpose for this is to be able to avoid EAP method negotiation when the
-# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
-# is only allowed for phase 1 identities.
-#
-# Multiple methods can be configured to make the authenticator try them one by
-# one until the peer accepts one. The method names are separated with a
-# comma (,).
-#
-# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
-# version based on the Phase 1 identity. Without this flag, the EAP
-# authenticator advertises the highest supported version and select the version
-# based on the first PEAP packet from the supplicant.
-#
-# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
-# Tunneled EAP methods are configured with standard EAP method name and [2]
-# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
-# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
-# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
-# hash.
-
-# Phase 1 users
-"user"		MD5	"password"
-"test user"	MD5	"secret"
-"example user"	TLS
-"DOMAIN\user"	MSCHAPV2	"password"
-"gtc user"	GTC	"password"
-"pax user"	PAX	"unknown"
-"pax.user at example.com"	PAX	0123456789abcdef0123456789abcdef
-"psk user"	PSK	"unknown"
-"psk.user at example.com"	PSK	0123456789abcdef0123456789abcdef
-"sake.user at example.com"	SAKE	0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
-"ttls"		TTLS
-"not anonymous"	PEAP
-# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
-"0"*		AKA,TTLS,TLS,PEAP,SIM
-"1"*		SIM,TTLS,TLS,PEAP,AKA
-"2"*		AKA,TTLS,TLS,PEAP,SIM
-"3"*		SIM,TTLS,TLS,PEAP,AKA
-"4"*		AKA,TTLS,TLS,PEAP,SIM
-"5"*		SIM,TTLS,TLS,PEAP,AKA
-
-# Wildcard for all other identities
-*		PEAP,TTLS,TLS,SIM,AKA
-
-# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
-"t-md5"		MD5	"password"	[2]
-"DOMAIN\t-mschapv2"	MSCHAPV2	"password"	[2]
-"t-gtc"		GTC	"password"	[2]
-"not anonymous"	MSCHAPV2	"password"	[2]
-"user"		MD5,GTC,MSCHAPV2	"password"	[2]
-"test user"	MSCHAPV2	hash:000102030405060708090a0b0c0d0e0f	[2]
-"ttls-user"	TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2	"password"	[2]
-
-# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
-"0"*		AKA	[2]
-"1"*		SIM	[2]
-"2"*		AKA	[2]
-"3"*		SIM	[2]
-"4"*		AKA	[2]
-"5"*		SIM	[2]

Copied: vendor/wpa/2.0/hostapd/hostapd.eap_user (from rev 9639, vendor/wpa/dist/hostapd/hostapd.eap_user)
===================================================================
--- vendor/wpa/2.0/hostapd/hostapd.eap_user	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hostapd.eap_user	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,97 @@
+# hostapd user database for integrated EAP server
+
+# Each line must contain an identity, EAP method(s), and an optional password
+# separated with whitespace (space or tab). The identity and password must be
+# double quoted ("user"). Password can alternatively be stored as
+# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
+# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
+# that the plaintext password does not need to be included in the user file.
+# Password hash is stored as hash:<16-octets of hex data> without quotation
+# marks.
+
+# [2] flag in the end of the line can be used to mark users for tunneled phase
+# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
+# identity can be used in the unencrypted phase 1 and the real user identity
+# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
+# access is needed, two user entries is needed, one for phase 1 and another
+# with the same username for phase 2.
+#
+# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
+# password option.
+# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
+# password.
+# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
+#
+# * can be used as a wildcard to match any user identity. The main purposes for
+# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
+# avoid having to configure every certificate for EAP-TLS authentication. The
+# first matching entry is selected, so * should be used as the last phase 1
+# user entry.
+#
+# "prefix"* can be used to match the given prefix and anything after this. The
+# main purpose for this is to be able to avoid EAP method negotiation when the
+# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
+# is only allowed for phase 1 identities.
+#
+# Multiple methods can be configured to make the authenticator try them one by
+# one until the peer accepts one. The method names are separated with a
+# comma (,).
+#
+# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
+# version based on the Phase 1 identity. Without this flag, the EAP
+# authenticator advertises the highest supported version and select the version
+# based on the first PEAP packet from the supplicant.
+#
+# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
+# Tunneled EAP methods are configured with standard EAP method name and [2]
+# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
+# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
+# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
+# hash.
+
+# Phase 1 users
+"user"		MD5	"password"
+"test user"	MD5	"secret"
+"example user"	TLS
+"DOMAIN\user"	MSCHAPV2	"password"
+"gtc user"	GTC	"password"
+"pax user"	PAX	"unknown"
+"pax.user at example.com"	PAX	0123456789abcdef0123456789abcdef
+"psk user"	PSK	"unknown"
+"psk.user at example.com"	PSK	0123456789abcdef0123456789abcdef
+"sake.user at example.com"	SAKE	0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+"ttls"		TTLS
+"not anonymous"	PEAP
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
+"0"*		AKA,TTLS,TLS,PEAP,SIM
+"1"*		SIM,TTLS,TLS,PEAP,AKA
+"2"*		AKA,TTLS,TLS,PEAP,SIM
+"3"*		SIM,TTLS,TLS,PEAP,AKA
+"4"*		AKA,TTLS,TLS,PEAP,SIM
+"5"*		SIM,TTLS,TLS,PEAP,AKA
+"6"*		AKA'
+"7"*		AKA'
+"8"*		AKA'
+
+# Wildcard for all other identities
+*		PEAP,TTLS,TLS,SIM,AKA
+
+# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
+"t-md5"		MD5	"password"	[2]
+"DOMAIN\t-mschapv2"	MSCHAPV2	"password"	[2]
+"t-gtc"		GTC	"password"	[2]
+"not anonymous"	MSCHAPV2	"password"	[2]
+"user"		MD5,GTC,MSCHAPV2	"password"	[2]
+"test user"	MSCHAPV2	hash:000102030405060708090a0b0c0d0e0f	[2]
+"ttls-user"	TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2	"password"	[2]
+
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
+"0"*		AKA	[2]
+"1"*		SIM	[2]
+"2"*		AKA	[2]
+"3"*		SIM	[2]
+"4"*		AKA	[2]
+"5"*		SIM	[2]
+"6"*		AKA'	[2]
+"7"*		AKA'	[2]
+"8"*		AKA'	[2]

Copied: vendor/wpa/2.0/hostapd/hostapd.eap_user_sqlite (from rev 9639, vendor/wpa/dist/hostapd/hostapd.eap_user_sqlite)
===================================================================
--- vendor/wpa/2.0/hostapd/hostapd.eap_user_sqlite	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hostapd.eap_user_sqlite	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+	identity TEXT PRIMARY KEY,
+	methods TEXT,
+	password TEXT,
+	phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+	identity TEXT PRIMARY KEY,
+	methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');

Deleted: vendor/wpa/2.0/hostapd/hostapd_cli.c
===================================================================
--- vendor/wpa/dist/hostapd/hostapd_cli.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/hostapd_cli.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,904 +0,0 @@
-/*
- * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dirent.h>
-
-#include "common/wpa_ctrl.h"
-#include "common.h"
-#include "common/version.h"
-
-
-static const char *hostapd_cli_version =
-"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi> and contributors";
-
-
-static const char *hostapd_cli_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n";
-
-static const char *hostapd_cli_full_license =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-"GNU General Public License for more details.\n"
-"\n"
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"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 *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]  add WPS Enrollee PIN (Device Password)\n"
-"   wps_pbc              indicate button pushed to initiate PBC\n"
-#ifdef CONFIG_WPS_OOB
-"   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
-#endif /* CONFIG_WPS_OOB */
-"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
-#endif /* CONFIG_WPS */
-"   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";
-
-static struct wpa_ctrl *ctrl_conn;
-static int hostapd_cli_quit = 0;
-static int hostapd_cli_attached = 0;
-static const char *ctrl_iface_dir = "/var/run/hostapd";
-static char *ctrl_ifname = NULL;
-static const char *pid_file = NULL;
-static const char *action_file = NULL;
-static int ping_interval = 5;
-
-
-static void usage(void)
-{
-	fprintf(stderr, "%s\n", hostapd_cli_version);
-	fprintf(stderr,
-		"\n"
-		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
-		"[-a<path>] \\\n"
-		"                   [-G<ping interval>] [command..]\n"
-		"\n"
-		"Options:\n"
-		"   -h           help (show this usage text)\n"
-		"   -v           shown version information\n"
-		"   -p<path>     path to find control sockets (default: "
-		"/var/run/hostapd)\n"
-		"   -a<file>     run in daemon mode executing the action file "
-		"based on events\n"
-		"                from hostapd\n"
-		"   -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);
-}
-
-
-static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
-{
-	char *cfile;
-	int flen;
-
-	if (ifname == NULL)
-		return NULL;
-
-	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
-	cfile = malloc(flen);
-	if (cfile == NULL)
-		return NULL;
-	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
-
-	ctrl_conn = wpa_ctrl_open(cfile);
-	free(cfile);
-	return ctrl_conn;
-}
-
-
-static void hostapd_cli_close_connection(void)
-{
-	if (ctrl_conn == NULL)
-		return;
-
-	if (hostapd_cli_attached) {
-		wpa_ctrl_detach(ctrl_conn);
-		hostapd_cli_attached = 0;
-	}
-	wpa_ctrl_close(ctrl_conn);
-	ctrl_conn = NULL;
-}
-
-
-static void hostapd_cli_msg_cb(char *msg, size_t len)
-{
-	printf("%s\n", msg);
-}
-
-
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
-{
-	char buf[4096];
-	size_t len;
-	int ret;
-
-	if (ctrl_conn == NULL) {
-		printf("Not connected to hostapd - command dropped.\n");
-		return -1;
-	}
-	len = sizeof(buf) - 1;
-	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
-			       hostapd_cli_msg_cb);
-	if (ret == -2) {
-		printf("'%s' command timed out.\n", cmd);
-		return -2;
-	} else if (ret < 0) {
-		printf("'%s' command failed.\n", cmd);
-		return -1;
-	}
-	if (print) {
-		buf[len] = '\0';
-		printf("%s", buf);
-	}
-	return 0;
-}
-
-
-static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
-{
-	return _wpa_ctrl_command(ctrl, cmd, 1);
-}
-
-
-static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "PING");
-}
-
-
-static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "MIB");
-}
-
-
-static int hostapd_cli_exec(const char *program, const char *arg1,
-			    const char *arg2)
-{
-	char *cmd;
-	size_t len;
-	int res;
-	int ret = 0;
-
-	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
-	cmd = os_malloc(len);
-	if (cmd == NULL)
-		return -1;
-	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
-	if (res < 0 || (size_t) res >= len) {
-		os_free(cmd);
-		return -1;
-	}
-	cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
-	if (system(cmd) < 0)
-		ret = -1;
-#endif /* _WIN32_WCE */
-	os_free(cmd);
-
-	return ret;
-}
-
-
-static void hostapd_cli_action_process(char *msg, size_t len)
-{
-	const char *pos;
-
-	pos = msg;
-	if (*pos == '<') {
-		pos = os_strchr(pos, '>');
-		if (pos)
-			pos++;
-		else
-			pos = msg;
-	}
-
-	hostapd_cli_exec(action_file, ctrl_ifname, pos);
-}
-
-
-static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char buf[64];
-	if (argc != 1) {
-		printf("Invalid 'sta' command - exactly one argument, STA "
-		       "address, is required.\n");
-		return -1;
-	}
-	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char buf[64];
-	if (argc != 1) {
-		printf("Invalid 'new_sta' command - exactly one argument, STA "
-		       "address, is required.\n");
-		return -1;
-	}
-	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
-					  char *argv[])
-{
-	char buf[64];
-	if (argc < 1) {
-		printf("Invalid 'deauthenticate' command - exactly one "
-		       "argument, STA address, is required.\n");
-		return -1;
-	}
-	if (argc > 1)
-		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
-			    argv[0], argv[1]);
-	else
-		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
-					char *argv[])
-{
-	char buf[64];
-	if (argc < 1) {
-		printf("Invalid 'disassociate' command - exactly one "
-		       "argument, STA address, is required.\n");
-		return -1;
-	}
-	if (argc > 1)
-		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
-			    argv[0], argv[1]);
-	else
-		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
-				    char *argv[])
-{
-	char buf[64];
-	if (argc != 1) {
-		printf("Invalid 'sa_query' command - exactly one argument, "
-		       "STA address, is required.\n");
-		return -1;
-	}
-	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-#endif /* CONFIG_IEEE80211W */
-
-
-#ifdef CONFIG_WPS
-static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char buf[64];
-	if (argc < 2) {
-		printf("Invalid 'wps_pin' command - at least two arguments, "
-		       "UUID and PIN, are required.\n");
-		return -1;
-	}
-	if (argc > 2)
-		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
-			 argv[0], argv[1], argv[2]);
-	else
-		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "WPS_PBC");
-}
-
-
-#ifdef CONFIG_WPS_OOB
-static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 3 && argc != 4) {
-		printf("Invalid WPS_OOB command: need three or four "
-		       "arguments:\n"
-		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-		       "- PATH: path of OOB device like '/mnt'\n"
-		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
-		       "'cred'\n"
-		       "- DEV_NAME: (only for NFC) device name like "
-		       "'pn531'\n");
-		return -1;
-	}
-
-	if (argc == 3)
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
-				  argv[0], argv[1], argv[2]);
-	else
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
-				  argv[0], argv[1], argv[2], argv[3]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_OOB command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	char buf[64];
-	if (argc < 1) {
-		printf("Invalid 'wps_ap_pin' command - at least one argument "
-		       "is required.\n");
-		return -1;
-	}
-	if (argc > 2)
-		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
-			 argv[0], argv[1], argv[2]);
-	else if (argc > 1)
-		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
-			 argv[0], argv[1]);
-	else
-		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-#endif /* CONFIG_WPS */
-
-
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
-				char *addr, size_t addr_len)
-{
-	char buf[4096], *pos;
-	size_t len;
-	int ret;
-
-	if (ctrl_conn == NULL) {
-		printf("Not connected to hostapd - command dropped.\n");
-		return -1;
-	}
-	len = sizeof(buf) - 1;
-	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
-			       hostapd_cli_msg_cb);
-	if (ret == -2) {
-		printf("'%s' command timed out.\n", cmd);
-		return -2;
-	} else if (ret < 0) {
-		printf("'%s' command failed.\n", cmd);
-		return -1;
-	}
-
-	buf[len] = '\0';
-	if (memcmp(buf, "FAIL", 4) == 0)
-		return -1;
-	printf("%s", buf);
-
-	pos = buf;
-	while (*pos != '\0' && *pos != '\n')
-		pos++;
-	*pos = '\0';
-	os_strlcpy(addr, buf, addr_len);
-	return 0;
-}
-
-
-static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char addr[32], cmd[64];
-
-	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
-		return 0;
-	do {
-		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
-	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
-
-	return -1;
-}
-
-
-static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	printf("%s", commands_help);
-	return 0;
-}
-
-
-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);
-	return 0;
-}
-
-
-static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	hostapd_cli_quit = 1;
-	return 0;
-}
-
-
-static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	if (argc != 1) {
-		printf("Invalid LEVEL command: needs one argument (debug "
-		       "level)\n");
-		return 0;
-	}
-	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
-{
-	struct dirent *dent;
-	DIR *dir;
-
-	dir = opendir(ctrl_iface_dir);
-	if (dir == NULL) {
-		printf("Control interface directory '%s' could not be "
-		       "openned.\n", ctrl_iface_dir);
-		return;
-	}
-
-	printf("Available interfaces:\n");
-	while ((dent = readdir(dir))) {
-		if (strcmp(dent->d_name, ".") == 0 ||
-		    strcmp(dent->d_name, "..") == 0)
-			continue;
-		printf("%s\n", dent->d_name);
-	}
-	closedir(dir);
-}
-
-
-static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
-				     char *argv[])
-{
-	if (argc < 1) {
-		hostapd_cli_list_interfaces(ctrl);
-		return 0;
-	}
-
-	hostapd_cli_close_connection();
-	free(ctrl_ifname);
-	ctrl_ifname = strdup(argv[0]);
-
-	if (hostapd_cli_open_connection(ctrl_ifname)) {
-		printf("Connected to interface '%s.\n", ctrl_ifname);
-		if (wpa_ctrl_attach(ctrl_conn) == 0) {
-			hostapd_cli_attached = 1;
-		} else {
-			printf("Warning: Failed to attach to "
-			       "hostapd.\n");
-		}
-	} else {
-		printf("Could not connect to interface '%s' - re-trying\n",
-			ctrl_ifname);
-	}
-	return 0;
-}
-
-
-struct hostapd_cli_cmd {
-	const char *cmd;
-	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
-};
-
-static struct hostapd_cli_cmd hostapd_cli_commands[] = {
-	{ "ping", hostapd_cli_cmd_ping },
-	{ "mib", hostapd_cli_cmd_mib },
-	{ "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 },
-#ifdef CONFIG_IEEE80211W
-	{ "sa_query", hostapd_cli_cmd_sa_query },
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-	{ "wps_pin", hostapd_cli_cmd_wps_pin },
-	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
-#ifdef CONFIG_WPS_OOB
-	{ "wps_oob", hostapd_cli_cmd_wps_oob },
-#endif /* CONFIG_WPS_OOB */
-	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
-#endif /* CONFIG_WPS */
-	{ "help", hostapd_cli_cmd_help },
-	{ "interface", hostapd_cli_cmd_interface },
-	{ "level", hostapd_cli_cmd_level },
-	{ "license", hostapd_cli_cmd_license },
-	{ "quit", hostapd_cli_cmd_quit },
-	{ NULL, NULL }
-};
-
-
-static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	struct hostapd_cli_cmd *cmd, *match = NULL;
-	int count;
-
-	count = 0;
-	cmd = hostapd_cli_commands;
-	while (cmd->cmd) {
-		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
-			match = cmd;
-			count++;
-		}
-		cmd++;
-	}
-
-	if (count > 1) {
-		printf("Ambiguous command '%s'; possible commands:", argv[0]);
-		cmd = hostapd_cli_commands;
-		while (cmd->cmd) {
-			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
-			    0) {
-				printf(" %s", cmd->cmd);
-			}
-			cmd++;
-		}
-		printf("\n");
-	} else if (count == 0) {
-		printf("Unknown command '%s'\n", argv[0]);
-	} else {
-		match->handler(ctrl, argc - 1, &argv[1]);
-	}
-}
-
-
-static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
-				     int action_monitor)
-{
-	int first = 1;
-	if (ctrl_conn == NULL)
-		return;
-	while (wpa_ctrl_pending(ctrl)) {
-		char buf[256];
-		size_t len = sizeof(buf) - 1;
-		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
-			buf[len] = '\0';
-			if (action_monitor)
-				hostapd_cli_action_process(buf, len);
-			else {
-				if (in_read && first)
-					printf("\n");
-				first = 0;
-				printf("%s\n", buf);
-			}
-		} else {
-			printf("Could not read pending message.\n");
-			break;
-		}
-	}
-}
-
-
-static void hostapd_cli_interactive(void)
-{
-	const int max_args = 10;
-	char cmd[256], *res, *argv[max_args], *pos;
-	int argc;
-
-	printf("\nInteractive mode\n\n");
-
-	do {
-		hostapd_cli_recv_pending(ctrl_conn, 0, 0);
-		printf("> ");
-		alarm(ping_interval);
-		res = fgets(cmd, sizeof(cmd), stdin);
-		alarm(0);
-		if (res == NULL)
-			break;
-		pos = cmd;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		argc = 0;
-		pos = cmd;
-		for (;;) {
-			while (*pos == ' ')
-				pos++;
-			if (*pos == '\0')
-				break;
-			argv[argc] = pos;
-			argc++;
-			if (argc == max_args)
-				break;
-			while (*pos != '\0' && *pos != ' ')
-				pos++;
-			if (*pos == ' ')
-				*pos++ = '\0';
-		}
-		if (argc)
-			wpa_request(ctrl_conn, argc, argv);
-	} while (!hostapd_cli_quit);
-}
-
-
-static void hostapd_cli_cleanup(void)
-{
-	hostapd_cli_close_connection();
-	if (pid_file)
-		os_daemonize_terminate(pid_file);
-
-	os_program_deinit();
-}
-
-
-static void hostapd_cli_terminate(int sig)
-{
-	hostapd_cli_cleanup();
-	exit(0);
-}
-
-
-static void hostapd_cli_alarm(int sig)
-{
-	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
-		printf("Connection to hostapd lost - trying to reconnect\n");
-		hostapd_cli_close_connection();
-	}
-	if (!ctrl_conn) {
-		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
-		if (ctrl_conn) {
-			printf("Connection to hostapd re-established\n");
-			if (wpa_ctrl_attach(ctrl_conn) == 0) {
-				hostapd_cli_attached = 1;
-			} else {
-				printf("Warning: Failed to attach to "
-				       "hostapd.\n");
-			}
-		}
-	}
-	if (ctrl_conn)
-		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
-	alarm(ping_interval);
-}
-
-
-static void hostapd_cli_action(struct wpa_ctrl *ctrl)
-{
-	fd_set rfds;
-	int fd, res;
-	struct timeval tv;
-	char buf[256];
-	size_t len;
-
-	fd = wpa_ctrl_get_fd(ctrl);
-
-	while (!hostapd_cli_quit) {
-		FD_ZERO(&rfds);
-		FD_SET(fd, &rfds);
-		tv.tv_sec = ping_interval;
-		tv.tv_usec = 0;
-		res = select(fd + 1, &rfds, NULL, NULL, &tv);
-		if (res < 0 && errno != EINTR) {
-			perror("select");
-			break;
-		}
-
-		if (FD_ISSET(fd, &rfds))
-			hostapd_cli_recv_pending(ctrl, 0, 1);
-		else {
-			len = sizeof(buf) - 1;
-			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
-					     hostapd_cli_action_process) < 0 ||
-			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
-				printf("hostapd did not reply to PING "
-				       "command - exiting\n");
-				break;
-			}
-		}
-	}
-}
-
-
-int main(int argc, char *argv[])
-{
-	int interactive;
-	int warning_displayed = 0;
-	int c;
-	int daemonize = 0;
-
-	if (os_program_init())
-		return -1;
-
-	for (;;) {
-		c = getopt(argc, argv, "a:BhG:i:p:v");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'a':
-			action_file = optarg;
-			break;
-		case 'B':
-			daemonize = 1;
-			break;
-		case 'G':
-			ping_interval = atoi(optarg);
-			break;
-		case 'h':
-			usage();
-			return 0;
-		case 'v':
-			printf("%s\n", hostapd_cli_version);
-			return 0;
-		case 'i':
-			os_free(ctrl_ifname);
-			ctrl_ifname = os_strdup(optarg);
-			break;
-		case 'p':
-			ctrl_iface_dir = optarg;
-			break;
-		default:
-			usage();
-			return -1;
-		}
-	}
-
-	interactive = (argc == optind) && (action_file == NULL);
-
-	if (interactive) {
-		printf("%s\n\n%s\n\n", hostapd_cli_version,
-		       hostapd_cli_license);
-	}
-
-	for (;;) {
-		if (ctrl_ifname == NULL) {
-			struct dirent *dent;
-			DIR *dir = opendir(ctrl_iface_dir);
-			if (dir) {
-				while ((dent = readdir(dir))) {
-					if (os_strcmp(dent->d_name, ".") == 0
-					    ||
-					    os_strcmp(dent->d_name, "..") == 0)
-						continue;
-					printf("Selected interface '%s'\n",
-					       dent->d_name);
-					ctrl_ifname = os_strdup(dent->d_name);
-					break;
-				}
-				closedir(dir);
-			}
-		}
-		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
-		if (ctrl_conn) {
-			if (warning_displayed)
-				printf("Connection established.\n");
-			break;
-		}
-
-		if (!interactive) {
-			perror("Failed to connect to hostapd - "
-			       "wpa_ctrl_open");
-			return -1;
-		}
-
-		if (!warning_displayed) {
-			printf("Could not connect to hostapd - re-trying\n");
-			warning_displayed = 1;
-		}
-		os_sleep(1, 0);
-		continue;
-	}
-
-	signal(SIGINT, hostapd_cli_terminate);
-	signal(SIGTERM, hostapd_cli_terminate);
-	signal(SIGALRM, hostapd_cli_alarm);
-
-	if (interactive || action_file) {
-		if (wpa_ctrl_attach(ctrl_conn) == 0) {
-			hostapd_cli_attached = 1;
-		} else {
-			printf("Warning: Failed to attach to hostapd.\n");
-			if (action_file)
-				return -1;
-		}
-	}
-
-	if (daemonize && os_daemonize(pid_file))
-		return -1;
-
-	if (interactive)
-		hostapd_cli_interactive();
-	else if (action_file)
-		hostapd_cli_action(ctrl_conn);
-	else
-		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
-
-	os_free(ctrl_ifname);
-	hostapd_cli_cleanup();
-	return 0;
-}

Copied: vendor/wpa/2.0/hostapd/hostapd_cli.c (from rev 9639, vendor/wpa/dist/hostapd/hostapd_cli.c)
===================================================================
--- vendor/wpa/2.0/hostapd/hostapd_cli.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/hostapd_cli.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1134 @@
+/*
+ * hostapd - command line interface for hostapd daemon
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dirent.h>
+
+#include "common/wpa_ctrl.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "common/version.h"
+
+
+static const char *hostapd_cli_version =
+"hostapd_cli v" VERSION_STR "\n"
+"Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi> and contributors";
+
+
+static const char *hostapd_cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+static const char *hostapd_cli_full_license =
+"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 *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"
+#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";
+
+static struct wpa_ctrl *ctrl_conn;
+static int hostapd_cli_quit = 0;
+static int hostapd_cli_attached = 0;
+static const char *ctrl_iface_dir = "/var/run/hostapd";
+static char *ctrl_ifname = NULL;
+static const char *pid_file = NULL;
+static const char *action_file = NULL;
+static int ping_interval = 5;
+static int interactive = 0;
+
+
+static void usage(void)
+{
+	fprintf(stderr, "%s\n", hostapd_cli_version);
+	fprintf(stderr,
+		"\n"
+		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
+		"[-a<path>] \\\n"
+		"                   [-G<ping interval>] [command..]\n"
+		"\n"
+		"Options:\n"
+		"   -h           help (show this usage text)\n"
+		"   -v           shown version information\n"
+		"   -p<path>     path to find control sockets (default: "
+		"/var/run/hostapd)\n"
+		"   -a<file>     run in daemon mode executing the action file "
+		"based on events\n"
+		"                from hostapd\n"
+		"   -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);
+}
+
+
+static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
+{
+	char *cfile;
+	int flen;
+
+	if (ifname == NULL)
+		return NULL;
+
+	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
+	cfile = malloc(flen);
+	if (cfile == NULL)
+		return NULL;
+	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
+
+	ctrl_conn = wpa_ctrl_open(cfile);
+	free(cfile);
+	return ctrl_conn;
+}
+
+
+static void hostapd_cli_close_connection(void)
+{
+	if (ctrl_conn == NULL)
+		return;
+
+	if (hostapd_cli_attached) {
+		wpa_ctrl_detach(ctrl_conn);
+		hostapd_cli_attached = 0;
+	}
+	wpa_ctrl_close(ctrl_conn);
+	ctrl_conn = NULL;
+}
+
+
+static void hostapd_cli_msg_cb(char *msg, size_t len)
+{
+	printf("%s\n", msg);
+}
+
+
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+{
+	char buf[4096];
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to hostapd - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+			       hostapd_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+	if (print) {
+		buf[len] = '\0';
+		printf("%s", buf);
+	}
+	return 0;
+}
+
+
+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+{
+	return _wpa_ctrl_command(ctrl, cmd, 1);
+}
+
+
+static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "PING");
+}
+
+
+static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RELOG");
+}
+
+
+static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "MIB");
+}
+
+
+static int hostapd_cli_exec(const char *program, const char *arg1,
+			    const char *arg2)
+{
+	char *cmd;
+	size_t len;
+	int res;
+	int ret = 0;
+
+	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
+	cmd = os_malloc(len);
+	if (cmd == NULL)
+		return -1;
+	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+	if (res < 0 || (size_t) res >= len) {
+		os_free(cmd);
+		return -1;
+	}
+	cmd[len - 1] = '\0';
+#ifndef _WIN32_WCE
+	if (system(cmd) < 0)
+		ret = -1;
+#endif /* _WIN32_WCE */
+	os_free(cmd);
+
+	return ret;
+}
+
+
+static void hostapd_cli_action_process(char *msg, size_t len)
+{
+	const char *pos;
+
+	pos = msg;
+	if (*pos == '<') {
+		pos = os_strchr(pos, '>');
+		if (pos)
+			pos++;
+		else
+			pos = msg;
+	}
+
+	hostapd_cli_exec(action_file, ctrl_ifname, pos);
+}
+
+
+static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'sta' command - exactly one argument, STA "
+		       "address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'new_sta' command - exactly one argument, STA "
+		       "address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'deauthenticate' command - exactly one "
+		       "argument, STA address, is required.\n");
+		return -1;
+	}
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'disassociate' command - exactly one "
+		       "argument, STA address, is required.\n");
+		return -1;
+	}
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'sa_query' command - exactly one argument, "
+		       "STA address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char buf[256];
+	if (argc < 2) {
+		printf("Invalid 'wps_pin' command - at least two arguments, "
+		       "UUID and PIN, are required.\n");
+		return -1;
+	}
+	if (argc > 3)
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
+			 argv[0], argv[1], argv[2], argv[3]);
+	else if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
+			 argv[0], argv[1], argv[2]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 1 && argc != 2) {
+		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
+		       "- PIN to be verified\n");
+		return -1;
+	}
+
+	if (argc == 2)
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
+				  argv[0], argv[1]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
+				  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_CHECK_PIN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_PBC");
+}
+
+
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_tag_read' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 18 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
+						int argc, char *argv[])
+{
+	char cmd[64];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_config_token' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
+			  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+					 int argc, char *argv[])
+{
+	char cmd[64];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_token' command - one argument is "
+		       "required.\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_NFC_TOKEN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'wps_ap_pin' command - at least one argument "
+		       "is required.\n");
+		return -1;
+	}
+	if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
+			 argv[0], argv[1], argv[2]);
+	else if (argc > 1)
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
+			 argv[0], argv[1]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	char buf[256];
+	char ssid_hex[2 * 32 + 1];
+	char key_hex[2 * 64 + 1];
+	int i;
+
+	if (argc < 1) {
+		printf("Invalid 'wps_config' command - at least two arguments "
+		       "are required.\n");
+		return -1;
+	}
+
+	ssid_hex[0] = '\0';
+	for (i = 0; i < 32; i++) {
+		if (argv[0][i] == '\0')
+			break;
+		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
+	}
+
+	key_hex[0] = '\0';
+	if (argc > 3) {
+		for (i = 0; i < 64; i++) {
+			if (argv[3][i] == '\0')
+				break;
+			os_snprintf(&key_hex[i * 2], 3, "%02x",
+				    argv[3][i]);
+		}
+	}
+
+	if (argc > 3)
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
+			 ssid_hex, argv[1], argv[2], key_hex);
+	else if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
+			 ssid_hex, argv[1], argv[2]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
+			 ssid_hex, argv[1]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_WPS */
+
+
+static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+					     char *argv[])
+{
+	char buf[300];
+	int res;
+
+	if (argc < 2) {
+		printf("Invalid 'disassoc_imminent' command - two arguments "
+		       "(STA addr and Disassociation Timer) are needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	char buf[300];
+	int res;
+
+	if (argc < 2) {
+		printf("Invalid 'ess_disassoc' command - two arguments (STA "
+		       "addr and URL) are needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "GET_CONFIG");
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
+				char *addr, size_t addr_len)
+{
+	char buf[4096], *pos;
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to hostapd - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+			       hostapd_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (memcmp(buf, "FAIL", 4) == 0)
+		return -1;
+	printf("%s", buf);
+
+	pos = buf;
+	while (*pos != '\0' && *pos != '\n')
+		pos++;
+	*pos = '\0';
+	os_strlcpy(addr, buf, addr_len);
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char addr[32], cmd[64];
+
+	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+		return 0;
+	do {
+		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+	return -1;
+}
+
+
+static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	printf("%s", commands_help);
+	return 0;
+}
+
+
+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);
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	hostapd_cli_quit = 1;
+	if (interactive)
+		eloop_terminate();
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	if (argc != 1) {
+		printf("Invalid LEVEL command: needs one argument (debug "
+		       "level)\n");
+		return 0;
+	}
+	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
+{
+	struct dirent *dent;
+	DIR *dir;
+
+	dir = opendir(ctrl_iface_dir);
+	if (dir == NULL) {
+		printf("Control interface directory '%s' could not be "
+		       "openned.\n", ctrl_iface_dir);
+		return;
+	}
+
+	printf("Available interfaces:\n");
+	while ((dent = readdir(dir))) {
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+		printf("%s\n", dent->d_name);
+	}
+	closedir(dir);
+}
+
+
+static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	if (argc < 1) {
+		hostapd_cli_list_interfaces(ctrl);
+		return 0;
+	}
+
+	hostapd_cli_close_connection();
+	free(ctrl_ifname);
+	ctrl_ifname = strdup(argv[0]);
+
+	if (hostapd_cli_open_connection(ctrl_ifname)) {
+		printf("Connected to interface '%s.\n", ctrl_ifname);
+		if (wpa_ctrl_attach(ctrl_conn) == 0) {
+			hostapd_cli_attached = 1;
+		} else {
+			printf("Warning: Failed to attach to "
+			       "hostapd.\n");
+		}
+	} else {
+		printf("Could not connect to interface '%s' - re-trying\n",
+			ctrl_ifname);
+	}
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 2) {
+		printf("Invalid SET command: needs two arguments (variable "
+		       "name and value)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long SET command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid GET command: needs one argument (variable "
+		       "name)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long GET command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+struct hostapd_cli_cmd {
+	const char *cmd;
+	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+};
+
+static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+	{ "ping", hostapd_cli_cmd_ping },
+	{ "mib", hostapd_cli_cmd_mib },
+	{ "relog", hostapd_cli_cmd_relog },
+	{ "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 },
+#ifdef CONFIG_IEEE80211W
+	{ "sa_query", hostapd_cli_cmd_sa_query },
+#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 },
+#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 },
+#endif /* CONFIG_WPS_NFC */
+	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
+	{ "wps_config", hostapd_cli_cmd_wps_config },
+#endif /* CONFIG_WPS */
+	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
+	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+	{ "get_config", hostapd_cli_cmd_get_config },
+	{ "help", hostapd_cli_cmd_help },
+	{ "interface", hostapd_cli_cmd_interface },
+	{ "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 },
+	{ NULL, NULL }
+};
+
+
+static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	struct hostapd_cli_cmd *cmd, *match = NULL;
+	int count;
+
+	count = 0;
+	cmd = hostapd_cli_commands;
+	while (cmd->cmd) {
+		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
+			match = cmd;
+			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
+				/* we have an exact match */
+				count = 1;
+				break;
+			}
+			count++;
+		}
+		cmd++;
+	}
+
+	if (count > 1) {
+		printf("Ambiguous command '%s'; possible commands:", argv[0]);
+		cmd = hostapd_cli_commands;
+		while (cmd->cmd) {
+			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
+			    0) {
+				printf(" %s", cmd->cmd);
+			}
+			cmd++;
+		}
+		printf("\n");
+	} else if (count == 0) {
+		printf("Unknown command '%s'\n", argv[0]);
+	} else {
+		match->handler(ctrl, argc - 1, &argv[1]);
+	}
+}
+
+
+static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
+				     int action_monitor)
+{
+	int first = 1;
+	if (ctrl_conn == NULL)
+		return;
+	while (wpa_ctrl_pending(ctrl)) {
+		char buf[256];
+		size_t len = sizeof(buf) - 1;
+		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
+			buf[len] = '\0';
+			if (action_monitor)
+				hostapd_cli_action_process(buf, len);
+			else {
+				if (in_read && first)
+					printf("\n");
+				first = 0;
+				printf("%s\n", buf);
+			}
+		} else {
+			printf("Could not read pending message.\n");
+			break;
+		}
+	}
+}
+
+
+#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 hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
+{
+	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
+		printf("Connection to hostapd lost - trying to reconnect\n");
+		hostapd_cli_close_connection();
+	}
+	if (!ctrl_conn) {
+		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+		if (ctrl_conn) {
+			printf("Connection to hostapd re-established\n");
+			if (wpa_ctrl_attach(ctrl_conn) == 0) {
+				hostapd_cli_attached = 1;
+			} else {
+				printf("Warning: Failed to attach to "
+				       "hostapd.\n");
+			}
+		}
+	}
+	if (ctrl_conn)
+		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
+{
+	eloop_terminate();
+}
+
+
+static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+	char *argv[max_args];
+	int argc;
+	argc = tokenize_cmd(cmd, argv);
+	if (argc)
+		wpa_request(ctrl_conn, argc, argv);
+}
+
+
+static void hostapd_cli_edit_eof_cb(void *ctx)
+{
+	eloop_terminate();
+}
+
+
+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);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+
+	eloop_run();
+
+	edit_deinit(NULL, NULL);
+	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_cleanup(void)
+{
+	hostapd_cli_close_connection();
+	if (pid_file)
+		os_daemonize_terminate(pid_file);
+
+	os_program_deinit();
+}
+
+
+static void hostapd_cli_action(struct wpa_ctrl *ctrl)
+{
+	fd_set rfds;
+	int fd, res;
+	struct timeval tv;
+	char buf[256];
+	size_t len;
+
+	fd = wpa_ctrl_get_fd(ctrl);
+
+	while (!hostapd_cli_quit) {
+		FD_ZERO(&rfds);
+		FD_SET(fd, &rfds);
+		tv.tv_sec = ping_interval;
+		tv.tv_usec = 0;
+		res = select(fd + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0 && errno != EINTR) {
+			perror("select");
+			break;
+		}
+
+		if (FD_ISSET(fd, &rfds))
+			hostapd_cli_recv_pending(ctrl, 0, 1);
+		else {
+			len = sizeof(buf) - 1;
+			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+					     hostapd_cli_action_process) < 0 ||
+			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+				printf("hostapd did not reply to PING "
+				       "command - exiting\n");
+				break;
+			}
+		}
+	}
+}
+
+
+int main(int argc, char *argv[])
+{
+	int warning_displayed = 0;
+	int c;
+	int daemonize = 0;
+
+	if (os_program_init())
+		return -1;
+
+	for (;;) {
+		c = getopt(argc, argv, "a:BhG:i:p:v");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'a':
+			action_file = optarg;
+			break;
+		case 'B':
+			daemonize = 1;
+			break;
+		case 'G':
+			ping_interval = atoi(optarg);
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'v':
+			printf("%s\n", hostapd_cli_version);
+			return 0;
+		case 'i':
+			os_free(ctrl_ifname);
+			ctrl_ifname = os_strdup(optarg);
+			break;
+		case 'p':
+			ctrl_iface_dir = optarg;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	interactive = (argc == optind) && (action_file == NULL);
+
+	if (interactive) {
+		printf("%s\n\n%s\n\n", hostapd_cli_version,
+		       hostapd_cli_license);
+	}
+
+	if (eloop_init())
+		return -1;
+
+	for (;;) {
+		if (ctrl_ifname == NULL) {
+			struct dirent *dent;
+			DIR *dir = opendir(ctrl_iface_dir);
+			if (dir) {
+				while ((dent = readdir(dir))) {
+					if (os_strcmp(dent->d_name, ".") == 0
+					    ||
+					    os_strcmp(dent->d_name, "..") == 0)
+						continue;
+					printf("Selected interface '%s'\n",
+					       dent->d_name);
+					ctrl_ifname = os_strdup(dent->d_name);
+					break;
+				}
+				closedir(dir);
+			}
+		}
+		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+		if (ctrl_conn) {
+			if (warning_displayed)
+				printf("Connection established.\n");
+			break;
+		}
+
+		if (!interactive) {
+			perror("Failed to connect to hostapd - "
+			       "wpa_ctrl_open");
+			return -1;
+		}
+
+		if (!warning_displayed) {
+			printf("Could not connect to hostapd - re-trying\n");
+			warning_displayed = 1;
+		}
+		os_sleep(1, 0);
+		continue;
+	}
+
+	if (interactive || action_file) {
+		if (wpa_ctrl_attach(ctrl_conn) == 0) {
+			hostapd_cli_attached = 1;
+		} else {
+			printf("Warning: Failed to attach to hostapd.\n");
+			if (action_file)
+				return -1;
+		}
+	}
+
+	if (daemonize && os_daemonize(pid_file))
+		return -1;
+
+	if (interactive)
+		hostapd_cli_interactive();
+	else if (action_file)
+		hostapd_cli_action(ctrl_conn);
+	else
+		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+
+	os_free(ctrl_ifname);
+	eloop_destroy();
+	hostapd_cli_cleanup();
+	return 0;
+}

Deleted: vendor/wpa/2.0/hostapd/main.c
===================================================================
--- vendor/wpa/dist/hostapd/main.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/main.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,565 +0,0 @@
-/*
- * hostapd / main()
- * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <syslog.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "crypto/tls.h"
-#include "common/version.h"
-#include "drivers/driver.h"
-#include "eap_server/eap.h"
-#include "eap_server/tncs.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#include "config_file.h"
-#include "eap_register.h"
-#include "dump_state.h"
-#include "ctrl_iface.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-
-struct hapd_interfaces {
-	size_t count;
-	struct hostapd_iface **iface;
-};
-
-
-static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
-				      int (*cb)(struct hostapd_iface *iface,
-						void *ctx), void *ctx)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < interfaces->count; i++) {
-		ret = cb(interfaces->iface[i], ctx);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-
-#ifndef CONFIG_NO_HOSTAPD_LOGGER
-static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
-			      int level, const char *txt, size_t len)
-{
-	struct hostapd_data *hapd = ctx;
-	char *format, *module_str;
-	int maxlen;
-	int conf_syslog_level, conf_stdout_level;
-	unsigned int conf_syslog, conf_stdout;
-
-	maxlen = len + 100;
-	format = os_malloc(maxlen);
-	if (!format)
-		return;
-
-	if (hapd && hapd->conf) {
-		conf_syslog_level = hapd->conf->logger_syslog_level;
-		conf_stdout_level = hapd->conf->logger_stdout_level;
-		conf_syslog = hapd->conf->logger_syslog;
-		conf_stdout = hapd->conf->logger_stdout;
-	} else {
-		conf_syslog_level = conf_stdout_level = 0;
-		conf_syslog = conf_stdout = (unsigned int) -1;
-	}
-
-	switch (module) {
-	case HOSTAPD_MODULE_IEEE80211:
-		module_str = "IEEE 802.11";
-		break;
-	case HOSTAPD_MODULE_IEEE8021X:
-		module_str = "IEEE 802.1X";
-		break;
-	case HOSTAPD_MODULE_RADIUS:
-		module_str = "RADIUS";
-		break;
-	case HOSTAPD_MODULE_WPA:
-		module_str = "WPA";
-		break;
-	case HOSTAPD_MODULE_DRIVER:
-		module_str = "DRIVER";
-		break;
-	case HOSTAPD_MODULE_IAPP:
-		module_str = "IAPP";
-		break;
-	case HOSTAPD_MODULE_MLME:
-		module_str = "MLME";
-		break;
-	default:
-		module_str = NULL;
-		break;
-	}
-
-	if (hapd && hapd->conf && addr)
-		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
-			    hapd->conf->iface, MAC2STR(addr),
-			    module_str ? " " : "", module_str, txt);
-	else if (hapd && hapd->conf)
-		os_snprintf(format, maxlen, "%s:%s%s %s",
-			    hapd->conf->iface, module_str ? " " : "",
-			    module_str, txt);
-	else if (addr)
-		os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
-			    MAC2STR(addr), module_str ? " " : "",
-			    module_str, txt);
-	else
-		os_snprintf(format, maxlen, "%s%s%s",
-			    module_str, module_str ? ": " : "", txt);
-
-	if ((conf_stdout & module) && level >= conf_stdout_level) {
-		wpa_debug_print_timestamp();
-		printf("%s\n", format);
-	}
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	if ((conf_syslog & module) && level >= conf_syslog_level) {
-		int priority;
-		switch (level) {
-		case HOSTAPD_LEVEL_DEBUG_VERBOSE:
-		case HOSTAPD_LEVEL_DEBUG:
-			priority = LOG_DEBUG;
-			break;
-		case HOSTAPD_LEVEL_INFO:
-			priority = LOG_INFO;
-			break;
-		case HOSTAPD_LEVEL_NOTICE:
-			priority = LOG_NOTICE;
-			break;
-		case HOSTAPD_LEVEL_WARNING:
-			priority = LOG_WARNING;
-			break;
-		default:
-			priority = LOG_INFO;
-			break;
-		}
-		syslog(priority, "%s", format);
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	os_free(format);
-}
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */
-
-
-/**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
- */
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
-	struct hostapd_iface *hapd_iface = NULL;
-	struct hostapd_config *conf = NULL;
-	struct hostapd_data *hapd;
-	size_t i;
-
-	hapd_iface = os_zalloc(sizeof(*hapd_iface));
-	if (hapd_iface == NULL)
-		goto fail;
-
-	hapd_iface->reload_config = hostapd_reload_config;
-	hapd_iface->config_read_cb = hostapd_config_read;
-	hapd_iface->config_fname = os_strdup(config_file);
-	if (hapd_iface->config_fname == NULL)
-		goto fail;
-	hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
-	hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
-	hapd_iface->for_each_interface = hostapd_for_each_interface;
-
-	conf = hostapd_config_read(hapd_iface->config_fname);
-	if (conf == NULL)
-		goto fail;
-	hapd_iface->conf = conf;
-
-	hapd_iface->num_bss = conf->num_bss;
-	hapd_iface->bss = os_zalloc(conf->num_bss *
-				    sizeof(struct hostapd_data *));
-	if (hapd_iface->bss == NULL)
-		goto fail;
-
-	for (i = 0; i < conf->num_bss; i++) {
-		hapd = hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
-		if (hapd == NULL)
-			goto fail;
-		hapd->msg_ctx = hapd;
-	}
-
-	return hapd_iface;
-
-fail:
-	if (conf)
-		hostapd_config_free(conf);
-	if (hapd_iface) {
-		os_free(hapd_iface->config_fname);
-		os_free(hapd_iface->bss);
-		os_free(hapd_iface);
-	}
-	return NULL;
-}
-
-
-static int hostapd_driver_init(struct hostapd_iface *iface)
-{
-	struct wpa_init_params params;
-	size_t i;
-	struct hostapd_data *hapd = iface->bss[0];
-	struct hostapd_bss_config *conf = hapd->conf;
-	u8 *b = conf->bssid;
-
-	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
-		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
-		return -1;
-	}
-
-	/* Initialize the driver interface */
-	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
-		b = NULL;
-
-	os_memset(&params, 0, sizeof(params));
-	params.bssid = b;
-	params.ifname = hapd->conf->iface;
-	params.ssid = (const u8 *) hapd->conf->ssid.ssid;
-	params.ssid_len = hapd->conf->ssid.ssid_len;
-	params.test_socket = hapd->conf->test_socket;
-	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
-
-	params.num_bridge = hapd->iface->num_bss;
-	params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
-	if (params.bridge == NULL)
-		return -1;
-	for (i = 0; i < hapd->iface->num_bss; i++) {
-		struct hostapd_data *bss = hapd->iface->bss[i];
-		if (bss->conf->bridge[0])
-			params.bridge[i] = bss->conf->bridge;
-	}
-
-	params.own_addr = hapd->own_addr;
-
-	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
-	os_free(params.bridge);
-	if (hapd->drv_priv == NULL) {
-		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
-			   hapd->driver->name);
-		hapd->driver = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
-{
-	const struct wpa_driver_ops *driver;
-	void *drv_priv;
-	if (iface == NULL)
-		return;
-	driver = iface->bss[0]->driver;
-	drv_priv = iface->bss[0]->drv_priv;
-	hostapd_interface_deinit(iface);
-	if (driver && driver->hapd_deinit)
-		driver->hapd_deinit(drv_priv);
-	hostapd_interface_free(iface);
-}
-
-
-static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
-		       const char *config_fname, int debug)
-{
-	struct hostapd_iface *iface;
-	int k;
-
-	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
-	iface = hostapd_init(config_fname);
-	if (!iface)
-		return NULL;
-	iface->interfaces = interfaces;
-
-	for (k = 0; k < debug; k++) {
-		if (iface->bss[0]->conf->logger_stdout_level > 0)
-			iface->bss[0]->conf->logger_stdout_level--;
-	}
-
-	if (hostapd_driver_init(iface) ||
-	    hostapd_setup_interface(iface)) {
-		hostapd_interface_deinit_free(iface);
-		return NULL;
-	}
-
-	return iface;
-}
-
-
-/**
- * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
- */
-static void handle_term(int sig, void *signal_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
-	eloop_terminate();
-}
-
-
-#ifndef CONFIG_NATIVE_WINDOWS
-
-static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
-{
-	if (hostapd_reload_config(iface) < 0) {
-		wpa_printf(MSG_WARNING, "Failed to read new configuration "
-			   "file - continuing with old.");
-	}
-	return 0;
-}
-
-
-/**
- * handle_reload - SIGHUP handler to reload configuration
- */
-static void handle_reload(int sig, void *signal_ctx)
-{
-	struct hapd_interfaces *interfaces = signal_ctx;
-	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
-		   sig);
-	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
-}
-
-
-static void handle_dump_state(int sig, void *signal_ctx)
-{
-#ifdef HOSTAPD_DUMP_STATE
-	struct hapd_interfaces *interfaces = signal_ctx;
-	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
-#endif /* HOSTAPD_DUMP_STATE */
-}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-static int hostapd_global_init(struct hapd_interfaces *interfaces)
-{
-	hostapd_logger_register_cb(hostapd_logger_cb);
-
-	if (eap_server_register_methods()) {
-		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
-		return -1;
-	}
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		return -1;
-	}
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	eloop_register_signal(SIGHUP, handle_reload, interfaces);
-	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
-#endif /* CONFIG_NATIVE_WINDOWS */
-	eloop_register_signal_terminate(handle_term, interfaces);
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	openlog("hostapd", 0, LOG_DAEMON);
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	return 0;
-}
-
-
-static void hostapd_global_deinit(const char *pid_file)
-{
-#ifdef EAP_SERVER_TNC
-	tncs_global_deinit();
-#endif /* EAP_SERVER_TNC */
-
-	eloop_destroy();
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	closelog();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	eap_server_unregister_methods();
-
-	os_daemonize_terminate(pid_file);
-}
-
-
-static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
-			      const char *pid_file)
-{
-#ifdef EAP_SERVER_TNC
-	int tnc = 0;
-	size_t i, k;
-
-	for (i = 0; !tnc && i < ifaces->count; i++) {
-		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
-			if (ifaces->iface[i]->bss[0]->conf->tnc) {
-				tnc++;
-				break;
-			}
-		}
-	}
-
-	if (tnc && tncs_global_init() < 0) {
-		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
-		return -1;
-	}
-#endif /* EAP_SERVER_TNC */
-
-	if (daemonize && os_daemonize(pid_file)) {
-		perror("daemon");
-		return -1;
-	}
-
-	eloop_run();
-
-	return 0;
-}
-
-
-static void show_version(void)
-{
-	fprintf(stderr,
-		"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-2010, Jouni Malinen <j at w1.fi> "
-		"and contributors\n");
-}
-
-
-static void usage(void)
-{
-	show_version();
-	fprintf(stderr,
-		"\n"
-		"usage: hostapd [-hdBKtv] [-P <PID file>] "
-		"<configuration file(s)>\n"
-		"\n"
-		"options:\n"
-		"   -h   show this usage\n"
-		"   -d   show more debug messages (-dd for even more)\n"
-		"   -B   run daemon in the background\n"
-		"   -P   PID file\n"
-		"   -K   include key data in debug messages\n"
-		"   -t   include timestamps in some debug messages\n"
-		"   -v   show hostapd version\n");
-
-	exit(1);
-}
-
-
-int main(int argc, char *argv[])
-{
-	struct hapd_interfaces interfaces;
-	int ret = 1;
-	size_t i;
-	int c, debug = 0, daemonize = 0;
-	char *pid_file = NULL;
-
-	if (os_program_init())
-		return -1;
-
-	for (;;) {
-		c = getopt(argc, argv, "BdhKP:tv");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'h':
-			usage();
-			break;
-		case 'd':
-			debug++;
-			if (wpa_debug_level > 0)
-				wpa_debug_level--;
-			break;
-		case 'B':
-			daemonize++;
-			break;
-		case 'K':
-			wpa_debug_show_keys++;
-			break;
-		case 'P':
-			os_free(pid_file);
-			pid_file = os_rel2abs_path(optarg);
-			break;
-		case 't':
-			wpa_debug_timestamp++;
-			break;
-		case 'v':
-			show_version();
-			exit(1);
-			break;
-
-		default:
-			usage();
-			break;
-		}
-	}
-
-	if (optind == argc)
-		usage();
-
-	interfaces.count = argc - optind;
-	interfaces.iface = os_malloc(interfaces.count *
-				     sizeof(struct hostapd_iface *));
-	if (interfaces.iface == NULL) {
-		wpa_printf(MSG_ERROR, "malloc failed\n");
-		return -1;
-	}
-
-	if (hostapd_global_init(&interfaces))
-		return -1;
-
-	/* Initialize interfaces */
-	for (i = 0; i < interfaces.count; i++) {
-		interfaces.iface[i] = hostapd_interface_init(&interfaces,
-							     argv[optind + i],
-							     debug);
-		if (!interfaces.iface[i])
-			goto out;
-	}
-
-	if (hostapd_global_run(&interfaces, daemonize, pid_file))
-		goto out;
-
-	ret = 0;
-
- out:
-	/* Deinitialize all interfaces */
-	for (i = 0; i < interfaces.count; i++)
-		hostapd_interface_deinit_free(interfaces.iface[i]);
-	os_free(interfaces.iface);
-
-	hostapd_global_deinit(pid_file);
-	os_free(pid_file);
-
-	os_program_deinit();
-
-	return ret;
-}

Copied: vendor/wpa/2.0/hostapd/main.c (from rev 9639, vendor/wpa/dist/hostapd/main.c)
===================================================================
--- vendor/wpa/2.0/hostapd/main.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/main.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,657 @@
+/*
+ * hostapd / main()
+ * Copyright (c) 2002-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <syslog.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/random.h"
+#include "crypto/tls.h"
+#include "common/version.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "eap_server/tncs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "config_file.h"
+#include "eap_register.h"
+#include "dump_state.h"
+#include "ctrl_iface.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+struct hapd_global {
+	void **drv_priv;
+	size_t drv_count;
+};
+
+static struct hapd_global global;
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+			      int level, const char *txt, size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	char *format, *module_str;
+	int maxlen;
+	int conf_syslog_level, conf_stdout_level;
+	unsigned int conf_syslog, conf_stdout;
+
+	maxlen = len + 100;
+	format = os_malloc(maxlen);
+	if (!format)
+		return;
+
+	if (hapd && hapd->conf) {
+		conf_syslog_level = hapd->conf->logger_syslog_level;
+		conf_stdout_level = hapd->conf->logger_stdout_level;
+		conf_syslog = hapd->conf->logger_syslog;
+		conf_stdout = hapd->conf->logger_stdout;
+	} else {
+		conf_syslog_level = conf_stdout_level = 0;
+		conf_syslog = conf_stdout = (unsigned int) -1;
+	}
+
+	switch (module) {
+	case HOSTAPD_MODULE_IEEE80211:
+		module_str = "IEEE 802.11";
+		break;
+	case HOSTAPD_MODULE_IEEE8021X:
+		module_str = "IEEE 802.1X";
+		break;
+	case HOSTAPD_MODULE_RADIUS:
+		module_str = "RADIUS";
+		break;
+	case HOSTAPD_MODULE_WPA:
+		module_str = "WPA";
+		break;
+	case HOSTAPD_MODULE_DRIVER:
+		module_str = "DRIVER";
+		break;
+	case HOSTAPD_MODULE_IAPP:
+		module_str = "IAPP";
+		break;
+	case HOSTAPD_MODULE_MLME:
+		module_str = "MLME";
+		break;
+	default:
+		module_str = NULL;
+		break;
+	}
+
+	if (hapd && hapd->conf && addr)
+		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
+			    hapd->conf->iface, MAC2STR(addr),
+			    module_str ? " " : "", module_str, txt);
+	else if (hapd && hapd->conf)
+		os_snprintf(format, maxlen, "%s:%s%s %s",
+			    hapd->conf->iface, module_str ? " " : "",
+			    module_str, txt);
+	else if (addr)
+		os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
+			    MAC2STR(addr), module_str ? " " : "",
+			    module_str, txt);
+	else
+		os_snprintf(format, maxlen, "%s%s%s",
+			    module_str, module_str ? ": " : "", txt);
+
+	if ((conf_stdout & module) && level >= conf_stdout_level) {
+		wpa_debug_print_timestamp();
+		printf("%s\n", format);
+	}
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	if ((conf_syslog & module) && level >= conf_syslog_level) {
+		int priority;
+		switch (level) {
+		case HOSTAPD_LEVEL_DEBUG_VERBOSE:
+		case HOSTAPD_LEVEL_DEBUG:
+			priority = LOG_DEBUG;
+			break;
+		case HOSTAPD_LEVEL_INFO:
+			priority = LOG_INFO;
+			break;
+		case HOSTAPD_LEVEL_NOTICE:
+			priority = LOG_NOTICE;
+			break;
+		case HOSTAPD_LEVEL_WARNING:
+			priority = LOG_WARNING;
+			break;
+		default:
+			priority = LOG_INFO;
+			break;
+		}
+		syslog(priority, "%s", format);
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	os_free(format);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+static struct hostapd_iface * hostapd_init(const char *config_file)
+{
+	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_config *conf = NULL;
+	struct hostapd_data *hapd;
+	size_t i;
+
+	hapd_iface = os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL)
+		goto fail;
+
+	hapd_iface->config_fname = os_strdup(config_file);
+	if (hapd_iface->config_fname == NULL)
+		goto fail;
+
+	conf = hostapd_config_read(hapd_iface->config_fname);
+	if (conf == NULL)
+		goto fail;
+	hapd_iface->conf = conf;
+
+	hapd_iface->num_bss = conf->num_bss;
+	hapd_iface->bss = os_calloc(conf->num_bss,
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		goto fail;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd == NULL)
+			goto fail;
+		hapd->msg_ctx = hapd;
+	}
+
+	return hapd_iface;
+
+fail:
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->config_fname);
+		os_free(hapd_iface->bss);
+		os_free(hapd_iface);
+	}
+	return NULL;
+}
+
+
+static int hostapd_driver_init(struct hostapd_iface *iface)
+{
+	struct wpa_init_params params;
+	size_t i;
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 *b = conf->bssid;
+	struct wpa_driver_capa capa;
+
+	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
+		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
+		return -1;
+	}
+
+	/* Initialize the driver interface */
+	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
+		b = NULL;
+
+	os_memset(&params, 0, sizeof(params));
+	for (i = 0; wpa_drivers[i]; i++) {
+		if (wpa_drivers[i] != hapd->driver)
+			continue;
+
+		if (global.drv_priv[i] == NULL &&
+		    wpa_drivers[i]->global_init) {
+			global.drv_priv[i] = wpa_drivers[i]->global_init();
+			if (global.drv_priv[i] == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to initialize "
+					   "driver '%s'",
+					   wpa_drivers[i]->name);
+				return -1;
+			}
+		}
+
+		params.global_priv = global.drv_priv[i];
+		break;
+	}
+	params.bssid = b;
+	params.ifname = hapd->conf->iface;
+	params.ssid = hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.test_socket = hapd->conf->test_socket;
+	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
+
+	params.num_bridge = hapd->iface->num_bss;
+	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
+	if (params.bridge == NULL)
+		return -1;
+	for (i = 0; i < hapd->iface->num_bss; i++) {
+		struct hostapd_data *bss = hapd->iface->bss[i];
+		if (bss->conf->bridge[0])
+			params.bridge[i] = bss->conf->bridge;
+	}
+
+	params.own_addr = hapd->own_addr;
+
+	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
+	os_free(params.bridge);
+	if (hapd->drv_priv == NULL) {
+		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
+			   hapd->driver->name);
+		hapd->driver = NULL;
+		return -1;
+	}
+
+	if (hapd->driver->get_capa &&
+	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
+		iface->drv_flags = capa.flags;
+		iface->probe_resp_offloads = capa.probe_resp_offloads;
+	}
+
+	return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_interface_init(struct hapd_interfaces *interfaces,
+		       const char *config_fname, int debug)
+{
+	struct hostapd_iface *iface;
+	int k;
+
+	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+	iface = hostapd_init(config_fname);
+	if (!iface)
+		return NULL;
+	iface->interfaces = interfaces;
+
+	for (k = 0; k < debug; k++) {
+		if (iface->bss[0]->conf->logger_stdout_level > 0)
+			iface->bss[0]->conf->logger_stdout_level--;
+	}
+
+	if (iface->conf->bss[0].iface[0] != 0 ||
+	    hostapd_drv_none(iface->bss[0])) {
+		if (hostapd_driver_init(iface) ||
+			hostapd_setup_interface(iface)) {
+			hostapd_interface_deinit_free(iface);
+			return NULL;
+		}
+	}
+
+	return iface;
+}
+
+
+/**
+ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
+ */
+static void handle_term(int sig, void *signal_ctx)
+{
+	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
+	eloop_terminate();
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
+{
+	if (hostapd_reload_config(iface) < 0) {
+		wpa_printf(MSG_WARNING, "Failed to read new configuration "
+			   "file - continuing with old.");
+	}
+	return 0;
+}
+
+
+/**
+ * handle_reload - SIGHUP handler to reload configuration
+ */
+static void handle_reload(int sig, void *signal_ctx)
+{
+	struct hapd_interfaces *interfaces = signal_ctx;
+	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
+		   sig);
+	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
+}
+
+
+static void handle_dump_state(int sig, void *signal_ctx)
+{
+#ifdef HOSTAPD_DUMP_STATE
+	struct hapd_interfaces *interfaces = signal_ctx;
+	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
+#endif /* HOSTAPD_DUMP_STATE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+			       const char *entropy_file)
+{
+	int i;
+
+	os_memset(&global, 0, sizeof(global));
+
+	hostapd_logger_register_cb(hostapd_logger_cb);
+
+	if (eap_server_register_methods()) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		return -1;
+	}
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	random_init(entropy_file);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	eloop_register_signal(SIGHUP, handle_reload, interfaces);
+	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
+#endif /* CONFIG_NATIVE_WINDOWS */
+	eloop_register_signal_terminate(handle_term, interfaces);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	openlog("hostapd", 0, LOG_DAEMON);
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	for (i = 0; wpa_drivers[i]; i++)
+		global.drv_count++;
+	if (global.drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		return -1;
+	}
+	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
+	if (global.drv_priv == NULL)
+		return -1;
+
+	return 0;
+}
+
+
+static void hostapd_global_deinit(const char *pid_file)
+{
+	int i;
+
+	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
+		if (!global.drv_priv[i])
+			continue;
+		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
+	}
+	os_free(global.drv_priv);
+	global.drv_priv = NULL;
+
+#ifdef EAP_SERVER_TNC
+	tncs_global_deinit();
+#endif /* EAP_SERVER_TNC */
+
+	random_deinit();
+
+	eloop_destroy();
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	closelog();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	eap_server_unregister_methods();
+
+	os_daemonize_terminate(pid_file);
+}
+
+
+static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
+			      const char *pid_file)
+{
+#ifdef EAP_SERVER_TNC
+	int tnc = 0;
+	size_t i, k;
+
+	for (i = 0; !tnc && i < ifaces->count; i++) {
+		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
+			if (ifaces->iface[i]->bss[0]->conf->tnc) {
+				tnc++;
+				break;
+			}
+		}
+	}
+
+	if (tnc && tncs_global_init() < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
+		return -1;
+	}
+#endif /* EAP_SERVER_TNC */
+
+	if (daemonize && os_daemonize(pid_file)) {
+		perror("daemon");
+		return -1;
+	}
+
+	eloop_run();
+
+	return 0;
+}
+
+
+static void show_version(void)
+{
+	fprintf(stderr,
+		"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-2012, Jouni Malinen <j at w1.fi> "
+		"and contributors\n");
+}
+
+
+static void usage(void)
+{
+	show_version();
+	fprintf(stderr,
+		"\n"
+		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+		"\\\n"
+		"         [-g <global ctrl_iface>] <configuration file(s)>\n"
+		"\n"
+		"options:\n"
+		"   -h   show this usage\n"
+		"   -d   show more debug messages (-dd for even more)\n"
+		"   -B   run daemon in the background\n"
+		"   -e   entropy file\n"
+		"   -g   global control interface path\n"
+		"   -P   PID file\n"
+		"   -K   include key data in debug messages\n"
+#ifdef CONFIG_DEBUG_FILE
+		"   -f   log output to debug file instead of stdout\n"
+#endif /* CONFIG_DEBUG_FILE */
+		"   -t   include timestamps in some debug messages\n"
+		"   -v   show hostapd version\n");
+
+	exit(1);
+}
+
+
+static const char * hostapd_msg_ifname_cb(void *ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	if (hapd && hapd->iconf && hapd->iconf->bss)
+		return hapd->iconf->bss->iface;
+	return NULL;
+}
+
+
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+					 const char *path)
+{
+	char *pos;
+	os_free(interfaces->global_iface_path);
+	interfaces->global_iface_path = os_strdup(path);
+	if (interfaces->global_iface_path == NULL)
+		return -1;
+	pos = os_strrchr(interfaces->global_iface_path, '/');
+	if (pos == NULL) {
+		os_free(interfaces->global_iface_path);
+		interfaces->global_iface_path = NULL;
+		return -1;
+	}
+
+	*pos = '\0';
+	interfaces->global_iface_name = pos + 1;
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct hapd_interfaces interfaces;
+	int ret = 1;
+	size_t i;
+	int c, debug = 0, daemonize = 0;
+	char *pid_file = NULL;
+	const char *log_file = NULL;
+	const char *entropy_file = NULL;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&interfaces, 0, sizeof(interfaces));
+	interfaces.reload_config = hostapd_reload_config;
+	interfaces.config_read_cb = hostapd_config_read;
+	interfaces.for_each_interface = hostapd_for_each_interface;
+	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+	interfaces.driver_init = hostapd_driver_init;
+	interfaces.global_iface_path = NULL;
+	interfaces.global_iface_name = NULL;
+	interfaces.global_ctrl_sock = -1;
+
+	for (;;) {
+		c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'h':
+			usage();
+			break;
+		case 'd':
+			debug++;
+			if (wpa_debug_level > 0)
+				wpa_debug_level--;
+			break;
+		case 'B':
+			daemonize++;
+			break;
+		case 'e':
+			entropy_file = optarg;
+			break;
+		case 'f':
+			log_file = optarg;
+			break;
+		case 'K':
+			wpa_debug_show_keys++;
+			break;
+		case 'P':
+			os_free(pid_file);
+			pid_file = os_rel2abs_path(optarg);
+			break;
+		case 't':
+			wpa_debug_timestamp++;
+			break;
+		case 'v':
+			show_version();
+			exit(1);
+			break;
+		case 'g':
+			hostapd_get_global_ctrl_iface(&interfaces, optarg);
+			break;
+
+		default:
+			usage();
+			break;
+		}
+	}
+
+	if (optind == argc && interfaces.global_iface_path == NULL)
+		usage();
+
+	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
+
+	if (log_file)
+		wpa_debug_open_file(log_file);
+
+	interfaces.count = argc - optind;
+	if (interfaces.count) {
+		interfaces.iface = os_calloc(interfaces.count,
+					     sizeof(struct hostapd_iface *));
+		if (interfaces.iface == NULL) {
+			wpa_printf(MSG_ERROR, "malloc failed");
+			return -1;
+		}
+	}
+
+	if (hostapd_global_init(&interfaces, entropy_file))
+		return -1;
+
+	/* Initialize interfaces */
+	for (i = 0; i < interfaces.count; i++) {
+		interfaces.iface[i] = hostapd_interface_init(&interfaces,
+							     argv[optind + i],
+							     debug);
+		if (!interfaces.iface[i])
+			goto out;
+	}
+
+	hostapd_global_ctrl_iface_init(&interfaces);
+
+	if (hostapd_global_run(&interfaces, daemonize, pid_file))
+		goto out;
+
+	ret = 0;
+
+ out:
+	hostapd_global_ctrl_iface_deinit(&interfaces);
+	/* Deinitialize all interfaces */
+	for (i = 0; i < interfaces.count; i++)
+		hostapd_interface_deinit_free(interfaces.iface[i]);
+	os_free(interfaces.iface);
+
+	hostapd_global_deinit(pid_file);
+	os_free(pid_file);
+
+	if (log_file)
+		wpa_debug_close_file();
+
+	os_program_deinit();
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/hostapd/nt_password_hash.c
===================================================================
--- vendor/wpa/dist/hostapd/nt_password_hash.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/hostapd/nt_password_hash.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,53 +0,0 @@
-/*
- * hostapd - Plaintext password to NtPasswordHash
- * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-
-
-int main(int argc, char *argv[])
-{
-	unsigned char password_hash[16];
-	size_t i;
-	char *password, buf[64], *pos;
-
-	if (argc > 1)
-		password = argv[1];
-	else {
-		if (fgets(buf, sizeof(buf), stdin) == NULL) {
-			printf("Failed to read password\n");
-			return 1;
-		}
-		buf[sizeof(buf) - 1] = '\0';
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\r' || *pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		password = buf;
-	}
-
-	if (nt_password_hash((u8 *) password, strlen(password), password_hash))
-		return -1;
-	for (i = 0; i < sizeof(password_hash); i++)
-		printf("%02x", password_hash[i]);
-	printf("\n");
-
-	return 0;
-}

Copied: vendor/wpa/2.0/hostapd/nt_password_hash.c (from rev 9639, vendor/wpa/dist/hostapd/nt_password_hash.c)
===================================================================
--- vendor/wpa/2.0/hostapd/nt_password_hash.c	                        (rev 0)
+++ vendor/wpa/2.0/hostapd/nt_password_hash.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,47 @@
+/*
+ * hostapd - Plaintext password to NtPasswordHash
+ * Copyright (c) 2005, Jouni Malinen <j at 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/ms_funcs.h"
+
+
+int main(int argc, char *argv[])
+{
+	unsigned char password_hash[16];
+	size_t i;
+	char *password, buf[64], *pos;
+
+	if (argc > 1)
+		password = argv[1];
+	else {
+		if (fgets(buf, sizeof(buf), stdin) == NULL) {
+			printf("Failed to read password\n");
+			return 1;
+		}
+		buf[sizeof(buf) - 1] = '\0';
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\r' || *pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		password = buf;
+	}
+
+	if (nt_password_hash((u8 *) password, strlen(password), password_hash))
+		return -1;
+	for (i = 0; i < sizeof(password_hash); i++)
+		printf("%02x", password_hash[i]);
+	printf("\n");
+
+	return 0;
+}

Copied: vendor/wpa/2.0/patches/openssl-0.9.8x-tls-extensions.patch (from rev 9639, vendor/wpa/dist/patches/openssl-0.9.8x-tls-extensions.patch)
===================================================================
--- vendor/wpa/2.0/patches/openssl-0.9.8x-tls-extensions.patch	                        (rev 0)
+++ vendor/wpa/2.0/patches/openssl-0.9.8x-tls-extensions.patch	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,396 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8x does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
+--- openssl-0.9.8x.orig/ssl/s3_clnt.c	2011-12-26 21:38:28.000000000 +0200
++++ openssl-0.9.8x/ssl/s3_clnt.c	2012-07-07 10:46:31.501140621 +0300
+@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->session->cipher=pref_cipher ?
++				pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			}
++		}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
+--- openssl-0.9.8x.orig/ssl/s3_srvr.c	2012-02-16 17:21:17.000000000 +0200
++++ openssl-0.9.8x/ssl/s3_srvr.c	2012-07-07 10:46:31.501140621 +0300
+@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++			{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++			}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++			}
++		}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
+--- openssl-0.9.8x.orig/ssl/ssl_err.c	2012-03-12 16:50:55.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl_err.c	2012-07-07 10:46:31.501140621 +0300
+@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
+--- openssl-0.9.8x.orig/ssl/ssl.h	2012-03-12 16:50:55.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl.h	2012-07-07 10:46:31.501140621 +0300
+@@ -344,6 +344,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
+ 
+ DECLARE_STACK_OF(SSL_CIPHER)
+ 
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1050,6 +1054,18 @@ struct ssl_st
+ 
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS Session Ticket extension override */
++	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++	/* TLS Session Ticket extension callback */
++	tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++	void *tls_session_ticket_ext_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT		 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
+--- openssl-0.9.8x.orig/ssl/ssl_sess.c	2010-02-01 18:48:40.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl_sess.c	2012-07-07 10:46:31.501140621 +0300
+@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_ticket_ext_cb = cb;
++	s->tls_session_ticket_ext_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++	{
++	if (s->version >= TLS1_VERSION)
++		{
++		if (s->tlsext_session_ticket)
++			{
++			OPENSSL_free(s->tlsext_session_ticket);
++			s->tlsext_session_ticket = NULL;
++			}
++
++		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++		if (!s->tlsext_session_ticket)
++			{
++			SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++			return 0;
++			}
++
++		if (ext_data)
++			{
++			s->tlsext_session_ticket->length = ext_len;
++			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++			}
++		else
++			{
++			s->tlsext_session_ticket->length = 0;
++			s->tlsext_session_ticket->data = NULL;
++			}
++
++		return 1;
++		}
++
++	return 0;
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
+--- openssl-0.9.8x.orig/ssl/t1_lib.c	2012-01-04 16:25:10.000000000 +0200
++++ openssl-0.9.8x/ssl/t1_lib.c	2012-07-07 10:47:31.153140501 +0300
+@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->tlsext_session_ticket)
++		{
++		OPENSSL_free(s->tlsext_session_ticket);
++		}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (!s->new_session && s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tlsext_session_ticket &&
++			 s->tlsext_session_ticket->data)
++			{
++			ticklen = s->tlsext_session_ticket->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick,
++			       s->tlsext_session_ticket->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++			}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tlsext_session_ticket &&
++		    s->tlsext_session_ticket->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ 	    s->version != DTLS1_VERSION)
+@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+ 				return 0;
+ 			renegotiate_seen = 1;
+ 			}
++		else if (type == TLSEXT_TYPE_session_ticket)
++			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
++			}
+ 		else if (type == TLSEXT_TYPE_status_request &&
+ 		         s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+ 			{
+@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+ 			}
+ 		else if (type == TLSEXT_TYPE_session_ticket)
+ 			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
+ 			if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ 				|| (size > 0))
+ 				{
+@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				{
++				/* Indicate cache miss here and instead of
++				 * generating the session from ticket now,
++				 * trigger abbreviated handshake based on
++				 * external mechanism to calculate the master
++				 * secret later. */
++				return 0;
++				}
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
+--- openssl-0.9.8x.orig/ssl/tls1.h	2009-11-08 16:51:54.000000000 +0200
++++ openssl-0.9.8x/ssl/tls1.h	2012-07-07 10:46:31.501140621 +0300
+@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_session_ticket_ext_st
++	{
++	unsigned short length;
++	void *data;
++	};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num
+--- openssl-0.9.8x.orig/util/ssleay.num	2008-06-05 13:57:21.000000000 +0300
++++ openssl-0.9.8x/util/ssleay.num	2012-07-07 10:46:31.505140623 +0300
+@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
+ SSL_CTX_set_client_cert_engine          293	EXIST::FUNCTION:ENGINE
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	EXIST::FUNCTION:TLSEXT

Deleted: vendor/wpa/2.0/src/Makefile
===================================================================
--- vendor/wpa/dist/src/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,11 +0,0 @@
-SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps
-
-all:
-	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
-
-clean:
-	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
-	rm -f *~
-
-install:
-	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done

Copied: vendor/wpa/2.0/src/Makefile (from rev 9639, vendor/wpa/dist/src/Makefile)
===================================================================
--- vendor/wpa/2.0/src/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/src/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,11 @@
+SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
+
+all:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
+
+clean:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+	rm -f *~
+
+install:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done

Deleted: vendor/wpa/2.0/src/ap/accounting.c
===================================================================
--- vendor/wpa/dist/src/ap/accounting.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/accounting.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,499 +0,0 @@
-/*
- * hostapd / RADIUS Accounting
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "drivers/driver.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "hostapd.h"
-#include "ieee802_1x.h"
-#include "ap_config.h"
-#include "sta_info.h"
-#include "accounting.h"
-
-
-/* Default interval in seconds for polling TX/RX octets from the driver if
- * STA is not using interim accounting. This detects wrap arounds for
- * input/output octets and updates Acct-{Input,Output}-Gigawords. */
-#define ACCT_DEFAULT_UPDATE_INTERVAL 300
-
-static void accounting_sta_get_id(struct hostapd_data *hapd,
-				  struct sta_info *sta);
-
-
-static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
-					  struct sta_info *sta,
-					  int status_type)
-{
-	struct radius_msg *msg;
-	char buf[128];
-	u8 *val;
-	size_t len;
-	int i;
-
-	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
-			     radius_client_get_id(hapd->radius));
-	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
-		return NULL;
-	}
-
-	if (sta) {
-		radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
-
-		os_snprintf(buf, sizeof(buf), "%08X-%08X",
-			    sta->acct_session_id_hi, sta->acct_session_id_lo);
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
-					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Acct-Session-Id\n");
-			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)) {
-		printf("Could not add Acct-Status-Type\n");
-		goto fail;
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
-				       hapd->conf->ieee802_1x ?
-				       RADIUS_ACCT_AUTHENTIC_RADIUS :
-				       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
-		printf("Could not add Acct-Authentic\n");
-		goto fail;
-	}
-
-	if (sta) {
-		val = ieee802_1x_get_identity(sta->eapol_sm, &len);
-		if (!val) {
-			os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
-				    MAC2STR(sta->addr));
-			val = (u8 *) buf;
-			len = os_strlen(buf);
-		}
-
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
-					 len)) {
-			printf("Could not add User-Name\n");
-			goto fail;
-		}
-	}
-
-	if (hapd->conf->own_ip_addr.af == AF_INET &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
-		printf("Could not add NAS-IP-Address\n");
-		goto fail;
-	}
-
-#ifdef CONFIG_IPV6
-	if (hapd->conf->own_ip_addr.af == AF_INET6 &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
-		printf("Could not add NAS-IPv6-Address\n");
-		goto fail;
-	}
-#endif /* CONFIG_IPV6 */
-
-	if (hapd->conf->nas_identifier &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
-				 (u8 *) hapd->conf->nas_identifier,
-				 os_strlen(hapd->conf->nas_identifier))) {
-		printf("Could not add NAS-Identifier\n");
-		goto fail;
-	}
-
-	if (sta &&
-	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
-		printf("Could not add NAS-Port\n");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Called-Station-Id\n");
-		goto fail;
-	}
-
-	if (sta) {
-		os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
-			    MAC2STR(sta->addr));
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
-					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Calling-Station-Id\n");
-			goto fail;
-		}
-
-		if (!radius_msg_add_attr_int32(
-			    msg, RADIUS_ATTR_NAS_PORT_TYPE,
-			    RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
-			printf("Could not add NAS-Port-Type\n");
-			goto fail;
-		}
-
-		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
-			    radius_sta_rate(hapd, sta) / 2,
-			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
-			    radius_mode_txt(hapd));
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
-					 (u8 *) buf, os_strlen(buf))) {
-			printf("Could not add Connect-Info\n");
-			goto fail;
-		}
-
-		for (i = 0; ; i++) {
-			val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
-							  i);
-			if (val == NULL)
-				break;
-
-			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
-						 val, len)) {
-				printf("Could not add Class\n");
-				goto fail;
-			}
-		}
-	}
-
-	return msg;
-
- fail:
-	radius_msg_free(msg);
-	return NULL;
-}
-
-
-static int accounting_sta_update_stats(struct hostapd_data *hapd,
-				       struct sta_info *sta,
-				       struct hostap_sta_driver_data *data)
-{
-	if (hapd->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;
-
-	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);
-
-	return 0;
-}
-
-
-static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	int interval;
-
-	if (sta->acct_interim_interval) {
-		accounting_sta_interim(hapd, sta);
-		interval = sta->acct_interim_interval;
-	} else {
-		struct hostap_sta_driver_data data;
-		accounting_sta_update_stats(hapd, sta, &data);
-		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
-	}
-
-	eloop_register_timeout(interval, 0, accounting_interim_update,
-			       hapd, sta);
-}
-
-
-/**
- * accounting_sta_start - Start STA accounting
- * @hapd: hostapd BSS data
- * @sta: The station
- */
-void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct radius_msg *msg;
-	int interval;
-
-	if (sta->acct_session_started)
-		return;
-
-	accounting_sta_get_id(hapd, sta);
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_INFO,
-		       "starting accounting session %08X-%08X",
-		       sta->acct_session_id_hi, sta->acct_session_id_lo);
-
-	time(&sta->acct_session_start);
-	sta->last_rx_bytes = sta->last_tx_bytes = 0;
-	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
-	hapd->drv.sta_clear_stats(hapd, sta->addr);
-
-	if (!hapd->conf->radius->acct_server)
-		return;
-
-	if (sta->acct_interim_interval)
-		interval = sta->acct_interim_interval;
-	else
-		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
-	eloop_register_timeout(interval, 0, accounting_interim_update,
-			       hapd, sta);
-
-	msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
-	if (msg)
-		radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
-
-	sta->acct_session_started = 1;
-}
-
-
-static void accounting_sta_report(struct hostapd_data *hapd,
-				  struct sta_info *sta, int stop)
-{
-	struct radius_msg *msg;
-	int cause = sta->acct_terminate_cause;
-	struct hostap_sta_driver_data data;
-	u32 gigawords;
-
-	if (!hapd->conf->radius->acct_server)
-		return;
-
-	msg = accounting_msg(hapd, sta,
-			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
-			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
-	if (!msg) {
-		printf("Could not create RADIUS Accounting message\n");
-		return;
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
-				       time(NULL) - sta->acct_session_start)) {
-		printf("Could not add Acct-Session-Time\n");
-		goto fail;
-	}
-
-	if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
-		if (!radius_msg_add_attr_int32(msg,
-					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
-					       data.rx_packets)) {
-			printf("Could not add Acct-Input-Packets\n");
-			goto fail;
-		}
-		if (!radius_msg_add_attr_int32(msg,
-					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
-					       data.tx_packets)) {
-			printf("Could not add Acct-Output-Packets\n");
-			goto fail;
-		}
-		if (!radius_msg_add_attr_int32(msg,
-					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
-					       data.rx_bytes)) {
-			printf("Could not add Acct-Input-Octets\n");
-			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)) {
-			printf("Could not add Acct-Input-Gigawords\n");
-			goto fail;
-		}
-		if (!radius_msg_add_attr_int32(msg,
-					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
-					       data.tx_bytes)) {
-			printf("Could not add Acct-Output-Octets\n");
-			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)) {
-			printf("Could not add Acct-Output-Gigawords\n");
-			goto fail;
-		}
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
-				       time(NULL))) {
-		printf("Could not add Event-Timestamp\n");
-		goto fail;
-	}
-
-	if (eloop_terminated())
-		cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
-
-	if (stop && cause &&
-	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
-				       cause)) {
-		printf("Could not add Acct-Terminate-Cause\n");
-		goto fail;
-	}
-
-	radius_client_send(hapd->radius, msg,
-			   stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
-			   sta->addr);
-	return;
-
- fail:
-	radius_msg_free(msg);
-}
-
-
-/**
- * accounting_sta_interim - Send a interim STA accounting report
- * @hapd: hostapd BSS data
- * @sta: The station
- */
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	if (sta->acct_session_started)
-		accounting_sta_report(hapd, sta, 0);
-}
-
-
-/**
- * accounting_sta_stop - Stop STA accounting
- * @hapd: hostapd BSS data
- * @sta: The station
- */
-void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	if (sta->acct_session_started) {
-		accounting_sta_report(hapd, sta, 1);
-		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);
-		sta->acct_session_started = 0;
-	}
-}
-
-
-static void 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;
-}
-
-
-/**
- * accounting_receive - Process the RADIUS frames from Accounting Server
- * @msg: RADIUS response message
- * @req: RADIUS request message
- * @shared_secret: RADIUS shared secret
- * @shared_secret_len: Length of shared_secret in octets
- * @data: Context data (struct hostapd_data *)
- * Returns: Processing status
- */
-static RadiusRxResult
-accounting_receive(struct radius_msg *msg, struct radius_msg *req,
-		   const u8 *shared_secret, size_t shared_secret_len,
-		   void *data)
-{
-	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
-		printf("Unknown RADIUS message code\n");
-		return RADIUS_RX_UNKNOWN;
-	}
-
-	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Authenticator - dropped\n");
-		return RADIUS_RX_INVALID_AUTHENTICATOR;
-	}
-
-	return RADIUS_RX_PROCESSED;
-}
-
-
-static void accounting_report_state(struct hostapd_data *hapd, int on)
-{
-	struct radius_msg *msg;
-
-	if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
-		return;
-
-	/* Inform RADIUS server that accounting will start/stop so that the
-	 * server can close old accounting sessions. */
-	msg = accounting_msg(hapd, NULL,
-			     on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
-			     RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
-	if (!msg)
-		return;
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
-				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
-	{
-		printf("Could not add Acct-Terminate-Cause\n");
-		radius_msg_free(msg);
-		return;
-	}
-
-	radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
-}
-
-
-/**
- * accounting_init: Initialize accounting
- * @hapd: hostapd BSS data
- * Returns: 0 on success, -1 on failure
- */
-int accounting_init(struct hostapd_data *hapd)
-{
-	/* Acct-Session-Id should be unique over reboots. If reliable clock is
-	 * not available, this could be replaced with reboot counter, etc. */
-	hapd->acct_session_id_hi = time(NULL);
-
-	if (radius_client_register(hapd->radius, RADIUS_ACCT,
-				   accounting_receive, hapd))
-		return -1;
-
-	accounting_report_state(hapd, 1);
-
-	return 0;
-}
-
-
-/**
- * accounting_deinit: Deinitilize accounting
- * @hapd: hostapd BSS data
- */
-void accounting_deinit(struct hostapd_data *hapd)
-{
-	accounting_report_state(hapd, 0);
-}

Copied: vendor/wpa/2.0/src/ap/accounting.c (from rev 9639, vendor/wpa/dist/src/ap/accounting.c)
===================================================================
--- vendor/wpa/2.0/src/ap/accounting.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/accounting.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,476 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "drivers/driver.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "accounting.h"
+
+
+/* Default interval in seconds for polling TX/RX octets from the driver if
+ * STA is not using interim accounting. This detects wrap arounds for
+ * input/output octets and updates Acct-{Input,Output}-Gigawords. */
+#define ACCT_DEFAULT_UPDATE_INTERVAL 300
+
+static void accounting_sta_interim(struct hostapd_data *hapd,
+				   struct sta_info *sta);
+
+
+static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  int status_type)
+{
+	struct radius_msg *msg;
+	char buf[128];
+	u8 *val;
+	size_t len;
+	int i;
+	struct wpabuf *b;
+
+	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
+			     radius_client_get_id(hapd->radius));
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return NULL;
+	}
+
+	if (sta) {
+		radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+		os_snprintf(buf, sizeof(buf), "%08X-%08X",
+			    sta->acct_session_id_hi, sta->acct_session_id_lo);
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+					 (u8 *) buf, os_strlen(buf))) {
+			printf("Could not add Acct-Session-Id\n");
+			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)) {
+		printf("Could not add Acct-Status-Type\n");
+		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)) {
+		printf("Could not add Acct-Authentic\n");
+		goto fail;
+	}
+
+	if (sta) {
+		/* Use 802.1X identity if available */
+		val = ieee802_1x_get_identity(sta->eapol_sm, &len);
+
+		/* Use RADIUS ACL identity if 802.1X provides no identity */
+		if (!val && sta->identity) {
+			val = (u8 *) sta->identity;
+			len = os_strlen(sta->identity);
+		}
+
+		/* Use STA MAC if neither 802.1X nor RADIUS ACL provided
+		 * identity */
+		if (!val) {
+			os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
+				    MAC2STR(sta->addr));
+			val = (u8 *) buf;
+			len = os_strlen(buf);
+		}
+
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
+					 len)) {
+			printf("Could not add User-Name\n");
+			goto fail;
+		}
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
+				   msg) < 0)
+		goto fail;
+
+	if (sta) {
+		for (i = 0; ; i++) {
+			val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
+							  i);
+			if (val == NULL)
+				break;
+
+			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
+						 val, len)) {
+				printf("Could not add Class\n");
+				goto fail;
+			}
+		}
+
+		b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+		if (b &&
+		    !radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 wpabuf_head(b), wpabuf_len(b))) {
+			wpa_printf(MSG_ERROR, "Could not add CUI");
+			goto fail;
+		}
+
+		if (!b && sta->radius_cui &&
+		    !radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 (u8 *) sta->radius_cui,
+					 os_strlen(sta->radius_cui))) {
+			wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
+			goto fail;
+		}
+	}
+
+	return msg;
+
+ fail:
+	radius_msg_free(msg);
+	return NULL;
+}
+
+
+static int accounting_sta_update_stats(struct hostapd_data *hapd,
+				       struct sta_info *sta,
+				       struct hostap_sta_driver_data *data)
+{
+	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;
+
+	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);
+
+	return 0;
+}
+
+
+static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	int interval;
+
+	if (sta->acct_interim_interval) {
+		accounting_sta_interim(hapd, sta);
+		interval = sta->acct_interim_interval;
+	} else {
+		struct hostap_sta_driver_data data;
+		accounting_sta_update_stats(hapd, sta, &data);
+		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+	}
+
+	eloop_register_timeout(interval, 0, accounting_interim_update,
+			       hapd, sta);
+}
+
+
+/**
+ * accounting_sta_start - Start STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct radius_msg *msg;
+	struct os_time t;
+	int interval;
+
+	if (sta->acct_session_started)
+		return;
+
+	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);
+
+	os_get_time(&t);
+	sta->acct_session_start = t.sec;
+	sta->last_rx_bytes = sta->last_tx_bytes = 0;
+	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+	hostapd_drv_sta_clear_stats(hapd, sta->addr);
+
+	if (!hapd->conf->radius->acct_server)
+		return;
+
+	if (sta->acct_interim_interval)
+		interval = sta->acct_interim_interval;
+	else
+		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+	eloop_register_timeout(interval, 0, accounting_interim_update,
+			       hapd, sta);
+
+	msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
+	if (msg &&
+	    radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+		radius_msg_free(msg);
+
+	sta->acct_session_started = 1;
+}
+
+
+static void accounting_sta_report(struct hostapd_data *hapd,
+				  struct sta_info *sta, int stop)
+{
+	struct radius_msg *msg;
+	int cause = sta->acct_terminate_cause;
+	struct hostap_sta_driver_data data;
+	struct os_time now;
+	u32 gigawords;
+
+	if (!hapd->conf->radius->acct_server)
+		return;
+
+	msg = accounting_msg(hapd, sta,
+			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
+			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
+	if (!msg) {
+		printf("Could not create RADIUS Accounting message\n");
+		return;
+	}
+
+	os_get_time(&now);
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
+				       now.sec - sta->acct_session_start)) {
+		printf("Could not add Acct-Session-Time\n");
+		goto fail;
+	}
+
+	if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
+					       data.rx_packets)) {
+			printf("Could not add Acct-Input-Packets\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
+					       data.tx_packets)) {
+			printf("Could not add Acct-Output-Packets\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
+					       data.rx_bytes)) {
+			printf("Could not add Acct-Input-Octets\n");
+			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)) {
+			printf("Could not add Acct-Input-Gigawords\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
+					       data.tx_bytes)) {
+			printf("Could not add Acct-Output-Octets\n");
+			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)) {
+			printf("Could not add Acct-Output-Gigawords\n");
+			goto fail;
+		}
+	}
+
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+				       now.sec)) {
+		printf("Could not add Event-Timestamp\n");
+		goto fail;
+	}
+
+	if (eloop_terminated())
+		cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
+
+	if (stop && cause &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+				       cause)) {
+		printf("Could not add Acct-Terminate-Cause\n");
+		goto fail;
+	}
+
+	if (radius_client_send(hapd->radius, msg,
+			       stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+			       sta->addr) < 0)
+		goto fail;
+	return;
+
+ fail:
+	radius_msg_free(msg);
+}
+
+
+/**
+ * accounting_sta_interim - Send a interim STA accounting report
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+static void accounting_sta_interim(struct hostapd_data *hapd,
+				   struct sta_info *sta)
+{
+	if (sta->acct_session_started)
+		accounting_sta_report(hapd, sta, 0);
+}
+
+
+/**
+ * accounting_sta_stop - Stop STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (sta->acct_session_started) {
+		accounting_sta_report(hapd, sta, 1);
+		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);
+		sta->acct_session_started = 0;
+	}
+}
+
+
+void 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;
+}
+
+
+/**
+ * accounting_receive - Process the RADIUS frames from Accounting Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+accounting_receive(struct radius_msg *msg, struct radius_msg *req,
+		   const u8 *shared_secret, size_t shared_secret_len,
+		   void *data)
+{
+	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
+		printf("Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+		printf("Incoming RADIUS packet did not have correct "
+		       "Authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	return RADIUS_RX_PROCESSED;
+}
+
+
+static void accounting_report_state(struct hostapd_data *hapd, int on)
+{
+	struct radius_msg *msg;
+
+	if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
+		return;
+
+	/* Inform RADIUS server that accounting will start/stop so that the
+	 * server can close old accounting sessions. */
+	msg = accounting_msg(hapd, NULL,
+			     on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
+			     RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
+	if (!msg)
+		return;
+
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
+	{
+		printf("Could not add Acct-Terminate-Cause\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+		radius_msg_free(msg);
+}
+
+
+/**
+ * accounting_init: Initialize accounting
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+int accounting_init(struct hostapd_data *hapd)
+{
+	struct os_time now;
+
+	/* Acct-Session-Id should be unique over reboots. If reliable clock is
+	 * not available, this could be replaced with reboot counter, etc. */
+	os_get_time(&now);
+	hapd->acct_session_id_hi = now.sec;
+
+	if (radius_client_register(hapd->radius, RADIUS_ACCT,
+				   accounting_receive, hapd))
+		return -1;
+
+	accounting_report_state(hapd, 1);
+
+	return 0;
+}
+
+
+/**
+ * accounting_deinit: Deinitilize accounting
+ * @hapd: hostapd BSS data
+ */
+void accounting_deinit(struct hostapd_data *hapd)
+{
+	accounting_report_state(hapd, 0);
+}

Deleted: vendor/wpa/2.0/src/ap/accounting.h
===================================================================
--- vendor/wpa/dist/src/ap/accounting.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/accounting.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,45 +0,0 @@
-/*
- * hostapd / RADIUS Accounting
- * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef ACCOUNTING_H
-#define ACCOUNTING_H
-
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
-#ifdef CONFIG_NO_ACCOUNTING
-static inline void accounting_sta_start(struct hostapd_data *hapd,
-					struct sta_info *sta)
-{
-}
-
-static inline void accounting_sta_stop(struct hostapd_data *hapd,
-				       struct sta_info *sta)
-{
-}
-
-static inline int accounting_init(struct hostapd_data *hapd)
-{
-	return 0;
-}
-
-static inline void accounting_deinit(struct hostapd_data *hapd)
-{
-}
-#else /* CONFIG_NO_ACCOUNTING */
-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);
-void accounting_deinit(struct hostapd_data *hapd);
-#endif /* CONFIG_NO_ACCOUNTING */
-
-#endif /* ACCOUNTING_H */

Copied: vendor/wpa/2.0/src/ap/accounting.h (from rev 9639, vendor/wpa/dist/src/ap/accounting.h)
===================================================================
--- vendor/wpa/2.0/src/ap/accounting.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/accounting.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,44 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ACCOUNTING_H
+#define ACCOUNTING_H
+
+#ifdef CONFIG_NO_ACCOUNTING
+static inline void accounting_sta_get_id(struct hostapd_data *hapd,
+					 struct sta_info *sta)
+{
+}
+
+static inline void accounting_sta_start(struct hostapd_data *hapd,
+					struct sta_info *sta)
+{
+}
+
+static inline void accounting_sta_stop(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+}
+
+static inline int accounting_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void accounting_deinit(struct hostapd_data *hapd)
+{
+}
+#else /* CONFIG_NO_ACCOUNTING */
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+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);
+void accounting_deinit(struct hostapd_data *hapd);
+#endif /* CONFIG_NO_ACCOUNTING */
+
+#endif /* ACCOUNTING_H */

Deleted: vendor/wpa/2.0/src/ap/ap_config.c
===================================================================
--- vendor/wpa/dist/src/ap/ap_config.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_config.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,605 +0,0 @@
-/*
- * hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "crypto/sha1.h"
-#include "radius/radius_client.h"
-#include "common/ieee802_11_defs.h"
-#include "common/eapol_common.h"
-#include "eap_common/eap_wsc_common.h"
-#include "eap_server/eap.h"
-#include "wpa_auth.h"
-#include "sta_info.h"
-#include "ap_config.h"
-
-
-static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
-{
-	struct hostapd_vlan *vlan, *prev;
-
-	vlan = bss->vlan;
-	prev = NULL;
-	while (vlan) {
-		prev = vlan;
-		vlan = vlan->next;
-		os_free(prev);
-	}
-
-	bss->vlan = NULL;
-}
-
-
-void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
-{
-	bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
-	bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
-	bss->logger_syslog = (unsigned int) -1;
-	bss->logger_stdout = (unsigned int) -1;
-
-	bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
-
-	bss->wep_rekeying_period = 300;
-	/* use key0 in individual key and key1 in broadcast key */
-	bss->broadcast_key_idx_min = 1;
-	bss->broadcast_key_idx_max = 2;
-	bss->eap_reauth_period = 3600;
-
-	bss->wpa_group_rekey = 600;
-	bss->wpa_gmk_rekey = 86400;
-	bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-	bss->wpa_pairwise = WPA_CIPHER_TKIP;
-	bss->wpa_group = WPA_CIPHER_TKIP;
-	bss->rsn_pairwise = 0;
-
-	bss->max_num_sta = MAX_STA_COUNT;
-
-	bss->dtim_period = 2;
-
-	bss->radius_server_auth_port = 1812;
-	bss->ap_max_inactivity = AP_MAX_INACTIVITY;
-	bss->eapol_version = EAPOL_VERSION;
-
-	bss->max_listen_interval = 65535;
-
-#ifdef CONFIG_IEEE80211W
-	bss->assoc_sa_query_max_timeout = 1000;
-	bss->assoc_sa_query_retry_timeout = 201;
-#endif /* CONFIG_IEEE80211W */
-#ifdef EAP_SERVER_FAST
-	 /* both anonymous and authenticated provisioning */
-	bss->eap_fast_prov = 3;
-	bss->pac_key_lifetime = 7 * 24 * 60 * 60;
-	bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
-#endif /* EAP_SERVER_FAST */
-}
-
-
-struct hostapd_config * hostapd_config_defaults(void)
-{
-	struct hostapd_config *conf;
-	struct hostapd_bss_config *bss;
-	int i;
-	const int aCWmin = 4, aCWmax = 10;
-	const struct hostapd_wmm_ac_params ac_bk =
-		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
-	const struct hostapd_wmm_ac_params ac_be =
-		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
-	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
-		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
-	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
-		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
-
-	conf = os_zalloc(sizeof(*conf));
-	bss = os_zalloc(sizeof(*bss));
-	if (conf == NULL || bss == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
-			   "configuration data.");
-		os_free(conf);
-		os_free(bss);
-		return NULL;
-	}
-
-	bss->radius = os_zalloc(sizeof(*bss->radius));
-	if (bss->radius == NULL) {
-		os_free(conf);
-		os_free(bss);
-		return NULL;
-	}
-
-	hostapd_config_defaults_bss(bss);
-
-	conf->num_bss = 1;
-	conf->bss = bss;
-
-	conf->beacon_int = 100;
-	conf->rts_threshold = -1; /* use driver default: 2347 */
-	conf->fragm_threshold = -1; /* user driver default: 2346 */
-	conf->send_probe_response = 1;
-
-	for (i = 0; i < NUM_TX_QUEUES; i++)
-		conf->tx_queue[i].aifs = -1; /* use hw default */
-
-	conf->wmm_ac_params[0] = ac_be;
-	conf->wmm_ac_params[1] = ac_bk;
-	conf->wmm_ac_params[2] = ac_vi;
-	conf->wmm_ac_params[3] = ac_vo;
-
-	conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
-
-	return conf;
-}
-
-
-int hostapd_mac_comp(const void *a, const void *b)
-{
-	return os_memcmp(a, b, sizeof(macaddr));
-}
-
-
-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)
-{
-	FILE *f;
-	char buf[128], *pos;
-	int line = 0, ret = 0, len, ok;
-	u8 addr[ETH_ALEN];
-	struct hostapd_wpa_psk *psk;
-
-	if (!fname)
-		return 0;
-
-	f = fopen(fname, "r");
-	if (!f) {
-		wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
-		return -1;
-	}
-
-	while (fgets(buf, sizeof(buf), f)) {
-		line++;
-
-		if (buf[0] == '#')
-			continue;
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		if (buf[0] == '\0')
-			continue;
-
-		if (hwaddr_aton(buf, addr)) {
-			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
-				   "line %d in '%s'", buf, line, fname);
-			ret = -1;
-			break;
-		}
-
-		psk = os_zalloc(sizeof(*psk));
-		if (psk == NULL) {
-			wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
-			ret = -1;
-			break;
-		}
-		if (is_zero_ether_addr(addr))
-			psk->group = 1;
-		else
-			os_memcpy(psk->addr, addr, ETH_ALEN);
-
-		pos = buf + 17;
-		if (*pos == '\0') {
-			wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
-				   line, fname);
-			os_free(psk);
-			ret = -1;
-			break;
-		}
-		pos++;
-
-		ok = 0;
-		len = os_strlen(pos);
-		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
-			ok = 1;
-		else if (len >= 8 && len < 64) {
-			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
-				    4096, psk->psk, PMK_LEN);
-			ok = 1;
-		}
-		if (!ok) {
-			wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
-				   "'%s'", pos, line, fname);
-			os_free(psk);
-			ret = -1;
-			break;
-		}
-
-		psk->next = ssid->wpa_psk;
-		ssid->wpa_psk = psk;
-	}
-
-	fclose(f);
-
-	return ret;
-}
-
-
-static int hostapd_derive_psk(struct hostapd_ssid *ssid)
-{
-	ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
-	if (ssid->wpa_psk == NULL) {
-		wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
-		return -1;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "SSID",
-			  (u8 *) ssid->ssid, ssid->ssid_len);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
-			      (u8 *) ssid->wpa_passphrase,
-			      os_strlen(ssid->wpa_passphrase));
-	pbkdf2_sha1(ssid->wpa_passphrase,
-		    ssid->ssid, ssid->ssid_len,
-		    4096, ssid->wpa_psk->psk, PMK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
-			ssid->wpa_psk->psk, PMK_LEN);
-	return 0;
-}
-
-
-int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
-{
-	struct hostapd_ssid *ssid = &conf->ssid;
-
-	if (ssid->wpa_passphrase != NULL) {
-		if (ssid->wpa_psk != NULL) {
-			wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
-				   "instead of passphrase");
-		} else {
-			wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
-				   "passphrase");
-			if (hostapd_derive_psk(ssid) < 0)
-				return -1;
-		}
-		ssid->wpa_psk->group = 1;
-	}
-
-	if (ssid->wpa_psk_file) {
-		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
-						&conf->ssid))
-			return -1;
-	}
-
-	return 0;
-}
-
-
-int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
-{
-	int i;
-
-	if (a->idx != b->idx || a->default_len != b->default_len)
-		return 1;
-	for (i = 0; i < NUM_WEP_KEYS; i++)
-		if (a->len[i] != b->len[i] ||
-		    os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
-			return 1;
-	return 0;
-}
-
-
-static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
-				       int num_servers)
-{
-	int i;
-
-	for (i = 0; i < num_servers; i++) {
-		os_free(servers[i].shared_secret);
-	}
-	os_free(servers);
-}
-
-
-static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
-{
-	os_free(user->identity);
-	os_free(user->password);
-	os_free(user);
-}
-
-
-static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
-{
-	int i;
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		os_free(keys->key[i]);
-		keys->key[i] = NULL;
-	}
-}
-
-
-static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
-{
-	struct hostapd_wpa_psk *psk, *prev;
-	struct hostapd_eap_user *user, *prev_user;
-
-	if (conf == NULL)
-		return;
-
-	psk = conf->ssid.wpa_psk;
-	while (psk) {
-		prev = psk;
-		psk = psk->next;
-		os_free(prev);
-	}
-
-	os_free(conf->ssid.wpa_passphrase);
-	os_free(conf->ssid.wpa_psk_file);
-	hostapd_config_free_wep(&conf->ssid.wep);
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	os_free(conf->ssid.vlan_tagged_interface);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-	user = conf->eap_user;
-	while (user) {
-		prev_user = user;
-		user = user->next;
-		hostapd_config_free_eap_user(prev_user);
-	}
-
-	os_free(conf->dump_log_name);
-	os_free(conf->eap_req_id_text);
-	os_free(conf->accept_mac);
-	os_free(conf->deny_mac);
-	os_free(conf->nas_identifier);
-	hostapd_config_free_radius(conf->radius->auth_servers,
-				   conf->radius->num_auth_servers);
-	hostapd_config_free_radius(conf->radius->acct_servers,
-				   conf->radius->num_acct_servers);
-	os_free(conf->rsn_preauth_interfaces);
-	os_free(conf->ctrl_interface);
-	os_free(conf->ca_cert);
-	os_free(conf->server_cert);
-	os_free(conf->private_key);
-	os_free(conf->private_key_passwd);
-	os_free(conf->dh_file);
-	os_free(conf->pac_opaque_encr_key);
-	os_free(conf->eap_fast_a_id);
-	os_free(conf->eap_fast_a_id_info);
-	os_free(conf->eap_sim_db);
-	os_free(conf->radius_server_clients);
-	os_free(conf->test_socket);
-	os_free(conf->radius);
-	hostapd_config_free_vlan(conf);
-	if (conf->ssid.dyn_vlan_keys) {
-		struct hostapd_ssid *ssid = &conf->ssid;
-		size_t i;
-		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
-			if (ssid->dyn_vlan_keys[i] == NULL)
-				continue;
-			hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
-			os_free(ssid->dyn_vlan_keys[i]);
-		}
-		os_free(ssid->dyn_vlan_keys);
-		ssid->dyn_vlan_keys = NULL;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	{
-		struct ft_remote_r0kh *r0kh, *r0kh_prev;
-		struct ft_remote_r1kh *r1kh, *r1kh_prev;
-
-		r0kh = conf->r0kh_list;
-		conf->r0kh_list = NULL;
-		while (r0kh) {
-			r0kh_prev = r0kh;
-			r0kh = r0kh->next;
-			os_free(r0kh_prev);
-		}
-
-		r1kh = conf->r1kh_list;
-		conf->r1kh_list = NULL;
-		while (r1kh) {
-			r1kh_prev = r1kh;
-			r1kh = r1kh->next;
-			os_free(r1kh_prev);
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_WPS
-	os_free(conf->wps_pin_requests);
-	os_free(conf->device_name);
-	os_free(conf->manufacturer);
-	os_free(conf->model_name);
-	os_free(conf->model_number);
-	os_free(conf->serial_number);
-	os_free(conf->device_type);
-	os_free(conf->config_methods);
-	os_free(conf->ap_pin);
-	os_free(conf->extra_cred);
-	os_free(conf->ap_settings);
-	os_free(conf->upnp_iface);
-	os_free(conf->friendly_name);
-	os_free(conf->manufacturer_url);
-	os_free(conf->model_description);
-	os_free(conf->model_url);
-	os_free(conf->upc);
-#endif /* CONFIG_WPS */
-}
-
-
-/**
- * hostapd_config_free - Free hostapd configuration
- * @conf: Configuration data from hostapd_config_read().
- */
-void hostapd_config_free(struct hostapd_config *conf)
-{
-	size_t i;
-
-	if (conf == NULL)
-		return;
-
-	for (i = 0; i < conf->num_bss; i++)
-		hostapd_config_free_bss(&conf->bss[i]);
-	os_free(conf->bss);
-	os_free(conf->supported_rates);
-	os_free(conf->basic_rates);
-
-	os_free(conf);
-}
-
-
-/**
- * hostapd_maclist_found - Find a MAC address from a list
- * @list: MAC address list
- * @num_entries: Number of addresses in the list
- * @addr: Address to search for
- * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
- * Returns: 1 if address is in the list or 0 if not.
- *
- * 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)
-{
-	int start, end, middle, res;
-
-	start = 0;
-	end = num_entries - 1;
-
-	while (start <= end) {
-		middle = (start + end) / 2;
-		res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
-		if (res == 0) {
-			if (vlan_id)
-				*vlan_id = list[middle].vlan_id;
-			return 1;
-		}
-		if (res < 0)
-			start = middle + 1;
-		else
-			end = middle - 1;
-	}
-
-	return 0;
-}
-
-
-int hostapd_rate_found(int *list, int rate)
-{
-	int i;
-
-	if (list == NULL)
-		return 0;
-
-	for (i = 0; list[i] >= 0; i++)
-		if (list[i] == rate)
-			return 1;
-
-	return 0;
-}
-
-
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
-{
-	struct hostapd_vlan *v = vlan;
-	while (v) {
-		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
-			return v->ifname;
-		v = v->next;
-	}
-	return NULL;
-}
-
-
-const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
-			   const u8 *addr, const u8 *prev_psk)
-{
-	struct hostapd_wpa_psk *psk;
-	int next_ok = prev_psk == NULL;
-
-	for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
-		if (next_ok &&
-		    (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
-			return psk->psk;
-
-		if (psk->psk == prev_psk)
-			next_ok = 1;
-	}
-
-	return NULL;
-}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
-		     size_t identity_len, int phase2)
-{
-	struct hostapd_eap_user *user = conf->eap_user;
-
-#ifdef CONFIG_WPS
-	if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
-	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
-		static struct hostapd_eap_user wsc_enrollee;
-		os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
-		wsc_enrollee.methods[0].method = eap_server_get_type(
-			"WSC", &wsc_enrollee.methods[0].vendor);
-		return &wsc_enrollee;
-	}
-
-	if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
-	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
-		static struct hostapd_eap_user wsc_registrar;
-		os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
-		wsc_registrar.methods[0].method = eap_server_get_type(
-			"WSC", &wsc_registrar.methods[0].vendor);
-		wsc_registrar.password = (u8 *) conf->ap_pin;
-		wsc_registrar.password_len = conf->ap_pin ?
-			os_strlen(conf->ap_pin) : 0;
-		return &wsc_registrar;
-	}
-#endif /* CONFIG_WPS */
-
-	while (user) {
-		if (!phase2 && user->identity == NULL) {
-			/* Wildcard match */
-			break;
-		}
-
-		if (user->phase2 == !!phase2 && user->wildcard_prefix &&
-		    identity_len >= user->identity_len &&
-		    os_memcmp(user->identity, identity, user->identity_len) ==
-		    0) {
-			/* Wildcard prefix match */
-			break;
-		}
-
-		if (user->phase2 == !!phase2 &&
-		    user->identity_len == identity_len &&
-		    os_memcmp(user->identity, identity, identity_len) == 0)
-			break;
-		user = user->next;
-	}
-
-	return user;
-}

Copied: vendor/wpa/2.0/src/ap/ap_config.c (from rev 9639, vendor/wpa/dist/src/ap/ap_config.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_config.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_config.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,625 @@
+/*
+ * hostapd / Configuration helper functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "crypto/sha1.h"
+#include "radius/radius_client.h"
+#include "common/ieee802_11_defs.h"
+#include "common/eapol_common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap.h"
+#include "wpa_auth.h"
+#include "sta_info.h"
+#include "ap_config.h"
+
+
+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
+{
+	struct hostapd_vlan *vlan, *prev;
+
+	vlan = bss->vlan;
+	prev = NULL;
+	while (vlan) {
+		prev = vlan;
+		vlan = vlan->next;
+		os_free(prev);
+	}
+
+	bss->vlan = NULL;
+}
+
+
+void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+{
+	bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+	bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+	bss->logger_syslog = (unsigned int) -1;
+	bss->logger_stdout = (unsigned int) -1;
+
+	bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
+
+	bss->wep_rekeying_period = 300;
+	/* use key0 in individual key and key1 in broadcast key */
+	bss->broadcast_key_idx_min = 1;
+	bss->broadcast_key_idx_max = 2;
+	bss->eap_reauth_period = 3600;
+
+	bss->wpa_group_rekey = 600;
+	bss->wpa_gmk_rekey = 86400;
+	bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+	bss->wpa_pairwise = WPA_CIPHER_TKIP;
+	bss->wpa_group = WPA_CIPHER_TKIP;
+	bss->rsn_pairwise = 0;
+
+	bss->max_num_sta = MAX_STA_COUNT;
+
+	bss->dtim_period = 2;
+
+	bss->radius_server_auth_port = 1812;
+	bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+	bss->eapol_version = EAPOL_VERSION;
+
+	bss->max_listen_interval = 65535;
+
+	bss->pwd_group = 19; /* ECC: GF(p=256) */
+
+#ifdef CONFIG_IEEE80211W
+	bss->assoc_sa_query_max_timeout = 1000;
+	bss->assoc_sa_query_retry_timeout = 201;
+#endif /* CONFIG_IEEE80211W */
+#ifdef EAP_SERVER_FAST
+	 /* both anonymous and authenticated provisioning */
+	bss->eap_fast_prov = 3;
+	bss->pac_key_lifetime = 7 * 24 * 60 * 60;
+	bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
+#endif /* EAP_SERVER_FAST */
+
+	/* Set to -1 as defaults depends on HT in setup */
+	bss->wmm_enabled = -1;
+
+#ifdef CONFIG_IEEE80211R
+	bss->ft_over_ds = 1;
+#endif /* CONFIG_IEEE80211R */
+
+	bss->radius_das_time_window = 300;
+}
+
+
+struct hostapd_config * hostapd_config_defaults(void)
+{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
+	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
+	const int aCWmin = 4, aCWmax = 10;
+	const struct hostapd_wmm_ac_params ac_bk =
+		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+	const struct hostapd_wmm_ac_params ac_be =
+		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+	const struct hostapd_tx_queue_params txq_bk =
+		{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+	const struct hostapd_tx_queue_params txq_be =
+		{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
+	const struct hostapd_tx_queue_params txq_vi =
+		{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
+	const struct hostapd_tx_queue_params txq_vo =
+		{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+		  (ecw2cw(aCWmin) + 1) / 2 - 1, 15};
+
+#undef ecw2cw
+
+	conf = os_zalloc(sizeof(*conf));
+	bss = os_zalloc(sizeof(*bss));
+	if (conf == NULL || bss == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "configuration data.");
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+
+	bss->radius = os_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+
+	hostapd_config_defaults_bss(bss);
+
+	conf->num_bss = 1;
+	conf->bss = bss;
+
+	conf->beacon_int = 100;
+	conf->rts_threshold = -1; /* use driver default: 2347 */
+	conf->fragm_threshold = -1; /* user driver default: 2346 */
+	conf->send_probe_response = 1;
+
+	conf->wmm_ac_params[0] = ac_be;
+	conf->wmm_ac_params[1] = ac_bk;
+	conf->wmm_ac_params[2] = ac_vi;
+	conf->wmm_ac_params[3] = ac_vo;
+
+	conf->tx_queue[0] = txq_vo;
+	conf->tx_queue[1] = txq_vi;
+	conf->tx_queue[2] = txq_be;
+	conf->tx_queue[3] = txq_bk;
+
+	conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+
+	conf->ap_table_max_size = 255;
+	conf->ap_table_expiration_time = 60;
+
+	return conf;
+}
+
+
+int hostapd_mac_comp(const void *a, const void *b)
+{
+	return os_memcmp(a, b, sizeof(macaddr));
+}
+
+
+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)
+{
+	FILE *f;
+	char buf[128], *pos;
+	int line = 0, ret = 0, len, ok;
+	u8 addr[ETH_ALEN];
+	struct hostapd_wpa_psk *psk;
+
+	if (!fname)
+		return 0;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (hwaddr_aton(buf, addr)) {
+			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
+				   "line %d in '%s'", buf, line, fname);
+			ret = -1;
+			break;
+		}
+
+		psk = os_zalloc(sizeof(*psk));
+		if (psk == NULL) {
+			wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
+			ret = -1;
+			break;
+		}
+		if (is_zero_ether_addr(addr))
+			psk->group = 1;
+		else
+			os_memcpy(psk->addr, addr, ETH_ALEN);
+
+		pos = buf + 17;
+		if (*pos == '\0') {
+			wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
+				   line, fname);
+			os_free(psk);
+			ret = -1;
+			break;
+		}
+		pos++;
+
+		ok = 0;
+		len = os_strlen(pos);
+		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+			ok = 1;
+		else if (len >= 8 && len < 64) {
+			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+				    4096, psk->psk, PMK_LEN);
+			ok = 1;
+		}
+		if (!ok) {
+			wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
+				   "'%s'", pos, line, fname);
+			os_free(psk);
+			ret = -1;
+			break;
+		}
+
+		psk->next = ssid->wpa_psk;
+		ssid->wpa_psk = psk;
+	}
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static int hostapd_derive_psk(struct hostapd_ssid *ssid)
+{
+	ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+	if (ssid->wpa_psk == NULL) {
+		wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
+		return -1;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "SSID",
+			  (u8 *) ssid->ssid, ssid->ssid_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
+			      (u8 *) ssid->wpa_passphrase,
+			      os_strlen(ssid->wpa_passphrase));
+	pbkdf2_sha1(ssid->wpa_passphrase,
+		    ssid->ssid, ssid->ssid_len,
+		    4096, ssid->wpa_psk->psk, PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
+			ssid->wpa_psk->psk, PMK_LEN);
+	return 0;
+}
+
+
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+{
+	struct hostapd_ssid *ssid = &conf->ssid;
+
+	if (ssid->wpa_passphrase != NULL) {
+		if (ssid->wpa_psk != NULL) {
+			wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
+				   "instead of passphrase");
+		} else {
+			wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
+				   "passphrase");
+			if (hostapd_derive_psk(ssid) < 0)
+				return -1;
+		}
+		ssid->wpa_psk->group = 1;
+	}
+
+	if (ssid->wpa_psk_file) {
+		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+						&conf->ssid))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
+{
+	int i;
+
+	if (a->idx != b->idx || a->default_len != b->default_len)
+		return 1;
+	for (i = 0; i < NUM_WEP_KEYS; i++)
+		if (a->len[i] != b->len[i] ||
+		    os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
+			return 1;
+	return 0;
+}
+
+
+static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
+				       int num_servers)
+{
+	int i;
+
+	for (i = 0; i < num_servers; i++) {
+		os_free(servers[i].shared_secret);
+	}
+	os_free(servers);
+}
+
+
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+	for (; attr; attr = attr->next) {
+		if (attr->type == type)
+			return attr;
+	}
+	return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+	struct hostapd_radius_attr *prev;
+
+	while (attr) {
+		prev = attr;
+		attr = attr->next;
+		wpabuf_free(prev->val);
+		os_free(prev);
+	}
+}
+
+
+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+{
+	os_free(user->identity);
+	os_free(user->password);
+	os_free(user);
+}
+
+
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+	int i;
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		os_free(keys->key[i]);
+		keys->key[i] = NULL;
+	}
+}
+
+
+static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
+{
+	struct hostapd_wpa_psk *psk, *prev;
+	struct hostapd_eap_user *user, *prev_user;
+
+	if (conf == NULL)
+		return;
+
+	psk = conf->ssid.wpa_psk;
+	while (psk) {
+		prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
+
+	os_free(conf->ssid.wpa_passphrase);
+	os_free(conf->ssid.wpa_psk_file);
+	hostapd_config_free_wep(&conf->ssid.wep);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	os_free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	user = conf->eap_user;
+	while (user) {
+		prev_user = user;
+		user = user->next;
+		hostapd_config_free_eap_user(prev_user);
+	}
+	os_free(conf->eap_user_sqlite);
+
+	os_free(conf->dump_log_name);
+	os_free(conf->eap_req_id_text);
+	os_free(conf->accept_mac);
+	os_free(conf->deny_mac);
+	os_free(conf->nas_identifier);
+	hostapd_config_free_radius(conf->radius->auth_servers,
+				   conf->radius->num_auth_servers);
+	hostapd_config_free_radius(conf->radius->acct_servers,
+				   conf->radius->num_acct_servers);
+	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
+	os_free(conf->rsn_preauth_interfaces);
+	os_free(conf->ctrl_interface);
+	os_free(conf->ca_cert);
+	os_free(conf->server_cert);
+	os_free(conf->private_key);
+	os_free(conf->private_key_passwd);
+	os_free(conf->dh_file);
+	os_free(conf->pac_opaque_encr_key);
+	os_free(conf->eap_fast_a_id);
+	os_free(conf->eap_fast_a_id_info);
+	os_free(conf->eap_sim_db);
+	os_free(conf->radius_server_clients);
+	os_free(conf->test_socket);
+	os_free(conf->radius);
+	os_free(conf->radius_das_shared_secret);
+	hostapd_config_free_vlan(conf);
+	if (conf->ssid.dyn_vlan_keys) {
+		struct hostapd_ssid *ssid = &conf->ssid;
+		size_t i;
+		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+			if (ssid->dyn_vlan_keys[i] == NULL)
+				continue;
+			hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
+			os_free(ssid->dyn_vlan_keys[i]);
+		}
+		os_free(ssid->dyn_vlan_keys);
+		ssid->dyn_vlan_keys = NULL;
+	}
+
+	os_free(conf->time_zone);
+
+#ifdef CONFIG_IEEE80211R
+	{
+		struct ft_remote_r0kh *r0kh, *r0kh_prev;
+		struct ft_remote_r1kh *r1kh, *r1kh_prev;
+
+		r0kh = conf->r0kh_list;
+		conf->r0kh_list = NULL;
+		while (r0kh) {
+			r0kh_prev = r0kh;
+			r0kh = r0kh->next;
+			os_free(r0kh_prev);
+		}
+
+		r1kh = conf->r1kh_list;
+		conf->r1kh_list = NULL;
+		while (r1kh) {
+			r1kh_prev = r1kh;
+			r1kh = r1kh->next;
+			os_free(r1kh_prev);
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_WPS
+	os_free(conf->wps_pin_requests);
+	os_free(conf->device_name);
+	os_free(conf->manufacturer);
+	os_free(conf->model_name);
+	os_free(conf->model_number);
+	os_free(conf->serial_number);
+	os_free(conf->config_methods);
+	os_free(conf->ap_pin);
+	os_free(conf->extra_cred);
+	os_free(conf->ap_settings);
+	os_free(conf->upnp_iface);
+	os_free(conf->friendly_name);
+	os_free(conf->manufacturer_url);
+	os_free(conf->model_description);
+	os_free(conf->model_url);
+	os_free(conf->upc);
+	wpabuf_free(conf->wps_nfc_dh_pubkey);
+	wpabuf_free(conf->wps_nfc_dh_privkey);
+	wpabuf_free(conf->wps_nfc_dev_pw);
+#endif /* CONFIG_WPS */
+
+	os_free(conf->roaming_consortium);
+	os_free(conf->venue_name);
+	os_free(conf->nai_realm_data);
+	os_free(conf->network_auth_type);
+	os_free(conf->anqp_3gpp_cell_net);
+	os_free(conf->domain_name);
+
+#ifdef CONFIG_RADIUS_TEST
+	os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
+#ifdef CONFIG_HS20
+	os_free(conf->hs20_oper_friendly_name);
+	os_free(conf->hs20_wan_metrics);
+	os_free(conf->hs20_connection_capability);
+	os_free(conf->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+	wpabuf_free(conf->vendor_elements);
+}
+
+
+/**
+ * hostapd_config_free - Free hostapd configuration
+ * @conf: Configuration data from hostapd_config_read().
+ */
+void hostapd_config_free(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf == NULL)
+		return;
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_config_free_bss(&conf->bss[i]);
+	os_free(conf->bss);
+	os_free(conf->supported_rates);
+	os_free(conf->basic_rates);
+
+	os_free(conf);
+}
+
+
+/**
+ * hostapd_maclist_found - Find a MAC address from a list
+ * @list: MAC address list
+ * @num_entries: Number of addresses in the list
+ * @addr: Address to search for
+ * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
+ * Returns: 1 if address is in the list or 0 if not.
+ *
+ * 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)
+{
+	int start, end, middle, res;
+
+	start = 0;
+	end = num_entries - 1;
+
+	while (start <= end) {
+		middle = (start + end) / 2;
+		res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
+		if (res == 0) {
+			if (vlan_id)
+				*vlan_id = list[middle].vlan_id;
+			return 1;
+		}
+		if (res < 0)
+			start = middle + 1;
+		else
+			end = middle - 1;
+	}
+
+	return 0;
+}
+
+
+int hostapd_rate_found(int *list, int rate)
+{
+	int i;
+
+	if (list == NULL)
+		return 0;
+
+	for (i = 0; list[i] >= 0; i++)
+		if (list[i] == rate)
+			return 1;
+
+	return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+	struct hostapd_vlan *v = vlan;
+	while (v) {
+		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+			return v->ifname;
+		v = v->next;
+	}
+	return NULL;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk)
+{
+	struct hostapd_wpa_psk *psk;
+	int next_ok = prev_psk == NULL;
+
+	for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
+		if (next_ok &&
+		    (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
+			return psk->psk;
+
+		if (psk->psk == prev_psk)
+			next_ok = 1;
+	}
+
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/ap/ap_config.h
===================================================================
--- vendor/wpa/dist/src/ap/ap_config.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,396 +0,0 @@
-/*
- * hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HOSTAPD_CONFIG_H
-#define HOSTAPD_CONFIG_H
-
-#include "common/defs.h"
-#include "ip_addr.h"
-#include "common/wpa_common.h"
-
-#define MAX_STA_COUNT 2007
-#define MAX_VLAN_ID 4094
-
-typedef u8 macaddr[ETH_ALEN];
-
-struct mac_acl_entry {
-	macaddr addr;
-	int vlan_id;
-};
-
-struct hostapd_radius_servers;
-struct ft_remote_r0kh;
-struct ft_remote_r1kh;
-
-#define HOSTAPD_MAX_SSID_LEN 32
-
-#define NUM_WEP_KEYS 4
-struct hostapd_wep_keys {
-	u8 idx;
-	u8 *key[NUM_WEP_KEYS];
-	size_t len[NUM_WEP_KEYS];
-	int keys_set;
-	size_t default_len; /* key length used for dynamic key generation */
-};
-
-typedef enum hostap_security_policy {
-	SECURITY_PLAINTEXT = 0,
-	SECURITY_STATIC_WEP = 1,
-	SECURITY_IEEE_802_1X = 2,
-	SECURITY_WPA_PSK = 3,
-	SECURITY_WPA = 4
-} secpolicy;
-
-struct hostapd_ssid {
-	char ssid[HOSTAPD_MAX_SSID_LEN + 1];
-	size_t ssid_len;
-	int ssid_set;
-
-	char vlan[IFNAMSIZ + 1];
-	secpolicy security_policy;
-
-	struct hostapd_wpa_psk *wpa_psk;
-	char *wpa_passphrase;
-	char *wpa_psk_file;
-
-	struct hostapd_wep_keys wep;
-
-#define DYNAMIC_VLAN_DISABLED 0
-#define DYNAMIC_VLAN_OPTIONAL 1
-#define DYNAMIC_VLAN_REQUIRED 2
-	int dynamic_vlan;
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	char *vlan_tagged_interface;
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-	struct hostapd_wep_keys **dyn_vlan_keys;
-	size_t max_dyn_vlan_keys;
-};
-
-
-#define VLAN_ID_WILDCARD -1
-
-struct hostapd_vlan {
-	struct hostapd_vlan *next;
-	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
-	char ifname[IFNAMSIZ + 1];
-	int dynamic_vlan;
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-#define DVLAN_CLEAN_BR 	0x1
-#define DVLAN_CLEAN_VLAN	0x2
-#define DVLAN_CLEAN_VLAN_PORT	0x4
-#define DVLAN_CLEAN_WLAN_PORT	0x8
-	int clean;
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-};
-
-#define PMK_LEN 32
-struct hostapd_wpa_psk {
-	struct hostapd_wpa_psk *next;
-	int group;
-	u8 psk[PMK_LEN];
-	u8 addr[ETH_ALEN];
-};
-
-#define EAP_USER_MAX_METHODS 8
-struct hostapd_eap_user {
-	struct hostapd_eap_user *next;
-	u8 *identity;
-	size_t identity_len;
-	struct {
-		int vendor;
-		u32 method;
-	} methods[EAP_USER_MAX_METHODS];
-	u8 *password;
-	size_t password_len;
-	int phase2;
-	int force_version;
-	unsigned int wildcard_prefix:1;
-	unsigned int password_hash:1; /* whether password is hashed with
-				       * nt_password_hash() */
-	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
-};
-
-
-#define NUM_TX_QUEUES 8
-
-struct hostapd_tx_queue_params {
-	int aifs;
-	int cwmin;
-	int cwmax;
-	int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-	int configured;
-};
-
-struct hostapd_wmm_ac_params {
-	int cwmin;
-	int cwmax;
-	int aifs;
-	int txop_limit; /* in units of 32us */
-	int admission_control_mandatory;
-};
-
-
-/**
- * struct hostapd_bss_config - Per-BSS configuration
- */
-struct hostapd_bss_config {
-	char iface[IFNAMSIZ + 1];
-	char bridge[IFNAMSIZ + 1];
-
-	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
-
-	unsigned int logger_syslog; /* module bitfield */
-	unsigned int logger_stdout; /* module bitfield */
-
-	char *dump_log_name; /* file name for state dump (SIGUSR1) */
-
-	int max_num_sta; /* maximum number of STAs in station table */
-
-	int dtim_period;
-
-	int ieee802_1x; /* use IEEE 802.1X */
-	int eapol_version;
-	int eap_server; /* Use internal EAP server instead of external
-			 * RADIUS server */
-	struct hostapd_eap_user *eap_user;
-	char *eap_sim_db;
-	struct hostapd_ip_addr own_ip_addr;
-	char *nas_identifier;
-	struct hostapd_radius_servers *radius;
-	int acct_interim_interval;
-
-	struct hostapd_ssid ssid;
-
-	char *eap_req_id_text; /* optional displayable message sent with
-				* EAP Request-Identity */
-	size_t eap_req_id_text_len;
-	int eapol_key_index_workaround;
-
-	size_t default_wep_key_len;
-	int individual_wep_key_len;
-	int wep_rekeying_period;
-	int broadcast_key_idx_min, broadcast_key_idx_max;
-	int eap_reauth_period;
-
-	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
-	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
-					* frames */
-
-	enum {
-		ACCEPT_UNLESS_DENIED = 0,
-		DENY_UNLESS_ACCEPTED = 1,
-		USE_EXTERNAL_RADIUS_AUTH = 2
-	} macaddr_acl;
-	struct mac_acl_entry *accept_mac;
-	int num_accept_mac;
-	struct mac_acl_entry *deny_mac;
-	int num_deny_mac;
-	int wds_sta;
-
-	int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
-			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
-
-	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
-	int wpa_key_mgmt;
-#ifdef CONFIG_IEEE80211W
-	enum mfp_options ieee80211w;
-	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
-	unsigned int assoc_sa_query_max_timeout;
-	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
-	int assoc_sa_query_retry_timeout;
-#endif /* CONFIG_IEEE80211W */
-	int wpa_pairwise;
-	int wpa_group;
-	int wpa_group_rekey;
-	int wpa_strict_rekey;
-	int wpa_gmk_rekey;
-	int wpa_ptk_rekey;
-	int rsn_pairwise;
-	int rsn_preauth;
-	char *rsn_preauth_interfaces;
-	int peerkey;
-
-#ifdef CONFIG_IEEE80211R
-	/* IEEE 802.11r - Fast BSS Transition */
-	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
-	u8 r1_key_holder[FT_R1KH_ID_LEN];
-	u32 r0_key_lifetime;
-	u32 reassociation_deadline;
-	struct ft_remote_r0kh *r0kh_list;
-	struct ft_remote_r1kh *r1kh_list;
-	int pmk_r1_push;
-#endif /* CONFIG_IEEE80211R */
-
-	char *ctrl_interface; /* directory for UNIX domain sockets */
-#ifndef CONFIG_NATIVE_WINDOWS
-	gid_t ctrl_interface_gid;
-#endif /* CONFIG_NATIVE_WINDOWS */
-	int ctrl_interface_gid_set;
-
-	char *ca_cert;
-	char *server_cert;
-	char *private_key;
-	char *private_key_passwd;
-	int check_crl;
-	char *dh_file;
-	u8 *pac_opaque_encr_key;
-	u8 *eap_fast_a_id;
-	size_t eap_fast_a_id_len;
-	char *eap_fast_a_id_info;
-	int eap_fast_prov;
-	int pac_key_lifetime;
-	int pac_key_refresh_time;
-	int eap_sim_aka_result_ind;
-	int tnc;
-
-	char *radius_server_clients;
-	int radius_server_auth_port;
-	int radius_server_ipv6;
-
-	char *test_socket; /* UNIX domain socket path for driver_test */
-
-	int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
-				 * address instead of individual address
-				 * (for driver_wired.c).
-				 */
-
-	int ap_max_inactivity;
-	int ignore_broadcast_ssid;
-
-	int wmm_enabled;
-	int wmm_uapsd;
-
-	struct hostapd_vlan *vlan, *vlan_tail;
-
-	macaddr bssid;
-
-	/*
-	 * Maximum listen interval that STAs can use when associating with this
-	 * BSS. If a STA tries to use larger value, the association will be
-	 * denied with status code 51.
-	 */
-	u16 max_listen_interval;
-
-	int okc; /* Opportunistic Key Caching */
-
-	int wps_state;
-#ifdef CONFIG_WPS
-	int ap_setup_locked;
-	u8 uuid[16];
-	char *wps_pin_requests;
-	char *device_name;
-	char *manufacturer;
-	char *model_name;
-	char *model_number;
-	char *serial_number;
-	char *device_type;
-	char *config_methods;
-	u8 os_version[4];
-	char *ap_pin;
-	int skip_cred_build;
-	u8 *extra_cred;
-	size_t extra_cred_len;
-	int wps_cred_processing;
-	u8 *ap_settings;
-	size_t ap_settings_len;
-	char *upnp_iface;
-	char *friendly_name;
-	char *manufacturer_url;
-	char *model_description;
-	char *model_url;
-	char *upc;
-#endif /* CONFIG_WPS */
-};
-
-
-/**
- * struct hostapd_config - Per-radio interface configuration
- */
-struct hostapd_config {
-	struct hostapd_bss_config *bss, *last_bss;
-	size_t num_bss;
-
-	u16 beacon_int;
-	int rts_threshold;
-	int fragm_threshold;
-	u8 send_probe_response;
-	u8 channel;
-	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
-	enum {
-		LONG_PREAMBLE = 0,
-		SHORT_PREAMBLE = 1
-	} preamble;
-	enum {
-		CTS_PROTECTION_AUTOMATIC = 0,
-		CTS_PROTECTION_FORCE_ENABLED = 1,
-		CTS_PROTECTION_FORCE_DISABLED = 2,
-		CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
-	} cts_protection_type;
-
-	int *supported_rates;
-	int *basic_rates;
-
-	const struct wpa_driver_ops *driver;
-
-	int ap_table_max_size;
-	int ap_table_expiration_time;
-
-	char country[3]; /* first two octets: country code as described in
-			  * ISO/IEC 3166-1. Third octet:
-			  * ' ' (ascii 32): all environments
-			  * 'O': Outdoor environemnt only
-			  * 'I': Indoor environment only
-			  */
-
-	int ieee80211d;
-
-	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
-
-	/*
-	 * WMM AC parameters, in same order as 802.1D, i.e.
-	 * 0 = BE (best effort)
-	 * 1 = BK (background)
-	 * 2 = VI (video)
-	 * 3 = VO (voice)
-	 */
-	struct hostapd_wmm_ac_params wmm_ac_params[4];
-
-	int ht_op_mode_fixed;
-	u16 ht_capab;
-	int ieee80211n;
-	int secondary_channel;
-};
-
-
-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(struct hostapd_config *conf);
-int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
-			  const u8 *addr, int *vlan_id);
-int hostapd_rate_found(int *list, int rate);
-int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
-			struct hostapd_wep_keys *b);
-const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
-			   const u8 *addr, const u8 *prev_psk);
-int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
-const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
-					int vlan_id);
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
-		     size_t identity_len, int phase2);
-
-#endif /* HOSTAPD_CONFIG_H */

Copied: vendor/wpa/2.0/src/ap/ap_config.h (from rev 9639, vendor/wpa/dist/src/ap/ap_config.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_config.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,539 @@
+/*
+ * hostapd / Configuration definitions and helpers functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_CONFIG_H
+#define HOSTAPD_CONFIG_H
+
+#include "common/defs.h"
+#include "ip_addr.h"
+#include "common/wpa_common.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps.h"
+
+#define MAX_STA_COUNT 2007
+#define MAX_VLAN_ID 4094
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct mac_acl_entry {
+	macaddr addr;
+	int vlan_id;
+};
+
+struct hostapd_radius_servers;
+struct ft_remote_r0kh;
+struct ft_remote_r1kh;
+
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+	u8 idx;
+	u8 *key[NUM_WEP_KEYS];
+	size_t len[NUM_WEP_KEYS];
+	int keys_set;
+	size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+	SECURITY_PLAINTEXT = 0,
+	SECURITY_STATIC_WEP = 1,
+	SECURITY_IEEE_802_1X = 2,
+	SECURITY_WPA_PSK = 3,
+	SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+	u8 ssid[HOSTAPD_MAX_SSID_LEN];
+	size_t ssid_len;
+	unsigned int ssid_set:1;
+	unsigned int utf8_ssid:1;
+
+	char vlan[IFNAMSIZ + 1];
+	secpolicy security_policy;
+
+	struct hostapd_wpa_psk *wpa_psk;
+	char *wpa_passphrase;
+	char *wpa_psk_file;
+
+	struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+	int dynamic_vlan;
+#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
+#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
+#define DYNAMIC_VLAN_NAMING_END 2
+	int vlan_naming;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+	struct hostapd_wep_keys **dyn_vlan_keys;
+	size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+	struct hostapd_vlan *next;
+	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+	char ifname[IFNAMSIZ + 1];
+	int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 	0x1
+#define DVLAN_CLEAN_VLAN	0x2
+#define DVLAN_CLEAN_VLAN_PORT	0x4
+#define DVLAN_CLEAN_WLAN_PORT	0x8
+	int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
+#define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+	struct hostapd_sta_wpa_psk_short *next;
+	u8 psk[PMK_LEN];
+};
+
+struct hostapd_wpa_psk {
+	struct hostapd_wpa_psk *next;
+	int group;
+	u8 psk[PMK_LEN];
+	u8 addr[ETH_ALEN];
+};
+
+struct hostapd_eap_user {
+	struct hostapd_eap_user *next;
+	u8 *identity;
+	size_t identity_len;
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_MAX_METHODS];
+	u8 *password;
+	size_t password_len;
+	int phase2;
+	int force_version;
+	unsigned int wildcard_prefix:1;
+	unsigned int password_hash:1; /* whether password is hashed with
+				       * nt_password_hash() */
+	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+};
+
+struct hostapd_radius_attr {
+	u8 type;
+	struct wpabuf *val;
+	struct hostapd_radius_attr *next;
+};
+
+
+#define NUM_TX_QUEUES 4
+
+struct hostapd_tx_queue_params {
+	int aifs;
+	int cwmin;
+	int cwmax;
+	int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+	u8 len;
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
+struct hostapd_lang_string {
+	u8 lang[3];
+	u8 name_len;
+	u8 name[252];
+};
+
+#define MAX_NAI_REALMS 10
+#define MAX_NAI_REALMLEN 255
+#define MAX_NAI_EAP_METHODS 5
+#define MAX_NAI_AUTH_TYPES 4
+struct hostapd_nai_realm_data {
+	u8 encoding;
+	char realm_buf[MAX_NAI_REALMLEN + 1];
+	char *realm[MAX_NAI_REALMS];
+	u8 eap_method_count;
+	struct hostapd_nai_realm_eap {
+		u8 eap_method;
+		u8 num_auths;
+		u8 auth_id[MAX_NAI_AUTH_TYPES];
+		u8 auth_val[MAX_NAI_AUTH_TYPES];
+	} eap_method[MAX_NAI_EAP_METHODS];
+};
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
+	char iface[IFNAMSIZ + 1];
+	char bridge[IFNAMSIZ + 1];
+	char wds_bridge[IFNAMSIZ + 1];
+
+	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
+
+	unsigned int logger_syslog; /* module bitfield */
+	unsigned int logger_stdout; /* module bitfield */
+
+	char *dump_log_name; /* file name for state dump (SIGUSR1) */
+
+	int max_num_sta; /* maximum number of STAs in station table */
+
+	int dtim_period;
+
+	int ieee802_1x; /* use IEEE 802.1X */
+	int eapol_version;
+	int eap_server; /* Use internal EAP server instead of external
+			 * RADIUS server */
+	struct hostapd_eap_user *eap_user;
+	char *eap_user_sqlite;
+	char *eap_sim_db;
+	struct hostapd_ip_addr own_ip_addr;
+	char *nas_identifier;
+	struct hostapd_radius_servers *radius;
+	int acct_interim_interval;
+	int radius_request_cui;
+	struct hostapd_radius_attr *radius_auth_req_attr;
+	struct hostapd_radius_attr *radius_acct_req_attr;
+	int radius_das_port;
+	unsigned int radius_das_time_window;
+	int radius_das_require_event_timestamp;
+	struct hostapd_ip_addr radius_das_client_addr;
+	u8 *radius_das_shared_secret;
+	size_t radius_das_shared_secret_len;
+
+	struct hostapd_ssid ssid;
+
+	char *eap_req_id_text; /* optional displayable message sent with
+				* EAP Request-Identity */
+	size_t eap_req_id_text_len;
+	int eapol_key_index_workaround;
+
+	size_t default_wep_key_len;
+	int individual_wep_key_len;
+	int wep_rekeying_period;
+	int broadcast_key_idx_min, broadcast_key_idx_max;
+	int eap_reauth_period;
+
+	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
+	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
+					* frames */
+
+	enum {
+		ACCEPT_UNLESS_DENIED = 0,
+		DENY_UNLESS_ACCEPTED = 1,
+		USE_EXTERNAL_RADIUS_AUTH = 2
+	} macaddr_acl;
+	struct mac_acl_entry *accept_mac;
+	int num_accept_mac;
+	struct mac_acl_entry *deny_mac;
+	int num_deny_mac;
+	int wds_sta;
+	int isolate;
+
+	int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
+			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
+
+	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+	int wpa_key_mgmt;
+#ifdef CONFIG_IEEE80211W
+	enum mfp_options ieee80211w;
+	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
+	unsigned int assoc_sa_query_max_timeout;
+	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
+	int assoc_sa_query_retry_timeout;
+#endif /* CONFIG_IEEE80211W */
+	enum {
+		PSK_RADIUS_IGNORED = 0,
+		PSK_RADIUS_ACCEPTED = 1,
+		PSK_RADIUS_REQUIRED = 2
+	} wpa_psk_radius;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int wpa_ptk_rekey;
+	int rsn_pairwise;
+	int rsn_preauth;
+	char *rsn_preauth_interfaces;
+	int peerkey;
+
+#ifdef CONFIG_IEEE80211R
+	/* IEEE 802.11r - Fast BSS Transition */
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r1_key_holder[FT_R1KH_ID_LEN];
+	u32 r0_key_lifetime;
+	u32 reassociation_deadline;
+	struct ft_remote_r0kh *r0kh_list;
+	struct ft_remote_r1kh *r1kh_list;
+	int pmk_r1_push;
+	int ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+
+	char *ctrl_interface; /* directory for UNIX domain sockets */
+#ifndef CONFIG_NATIVE_WINDOWS
+	gid_t ctrl_interface_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+	int ctrl_interface_gid_set;
+
+	char *ca_cert;
+	char *server_cert;
+	char *private_key;
+	char *private_key_passwd;
+	int check_crl;
+	char *dh_file;
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	int eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	int fragment_size;
+	u16 pwd_group;
+
+	char *radius_server_clients;
+	int radius_server_auth_port;
+	int radius_server_ipv6;
+
+	char *test_socket; /* UNIX domain socket path for driver_test */
+
+	int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
+				 * address instead of individual address
+				 * (for driver_wired.c).
+				 */
+
+	int ap_max_inactivity;
+	int ignore_broadcast_ssid;
+
+	int wmm_enabled;
+	int wmm_uapsd;
+
+	struct hostapd_vlan *vlan, *vlan_tail;
+
+	macaddr bssid;
+
+	/*
+	 * Maximum listen interval that STAs can use when associating with this
+	 * BSS. If a STA tries to use larger value, the association will be
+	 * denied with status code 51.
+	 */
+	u16 max_listen_interval;
+
+	int disable_pmksa_caching;
+	int okc; /* Opportunistic Key Caching */
+
+	int wps_state;
+#ifdef CONFIG_WPS
+	int ap_setup_locked;
+	u8 uuid[16];
+	char *wps_pin_requests;
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u8 device_type[WPS_DEV_TYPE_LEN];
+	char *config_methods;
+	u8 os_version[4];
+	char *ap_pin;
+	int skip_cred_build;
+	u8 *extra_cred;
+	size_t extra_cred_len;
+	int wps_cred_processing;
+	u8 *ap_settings;
+	size_t ap_settings_len;
+	char *upnp_iface;
+	char *friendly_name;
+	char *manufacturer_url;
+	char *model_description;
+	char *model_url;
+	char *upc;
+	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	int wps_nfc_dev_pw_id;
+	struct wpabuf *wps_nfc_dh_pubkey;
+	struct wpabuf *wps_nfc_dh_privkey;
+	struct wpabuf *wps_nfc_dev_pw;
+#endif /* CONFIG_WPS */
+	int pbc_in_m1;
+
+#define P2P_ENABLED BIT(0)
+#define P2P_GROUP_OWNER BIT(1)
+#define P2P_GROUP_FORMATION BIT(2)
+#define P2P_MANAGE BIT(3)
+#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
+	int p2p;
+
+	int disassoc_low_ack;
+	int skip_inactivity_poll;
+
+#define TDLS_PROHIBIT BIT(0)
+#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
+	int tdls;
+	int disable_11n;
+	int disable_11ac;
+
+	/* IEEE 802.11v */
+	int time_advertisement;
+	char *time_zone;
+	int wnm_sleep_mode;
+	int bss_transition;
+
+	/* IEEE 802.11u - Interworking */
+	int interworking;
+	int access_network_type;
+	int internet;
+	int asra;
+	int esr;
+	int uesa;
+	int venue_info_set;
+	u8 venue_group;
+	u8 venue_type;
+	u8 hessid[ETH_ALEN];
+
+	/* IEEE 802.11u - Roaming Consortium list */
+	unsigned int roaming_consortium_count;
+	struct hostapd_roaming_consortium *roaming_consortium;
+
+	/* IEEE 802.11u - Venue Name duples */
+	unsigned int venue_name_count;
+	struct hostapd_lang_string *venue_name;
+
+	/* IEEE 802.11u - Network Authentication Type */
+	u8 *network_auth_type;
+	size_t network_auth_type_len;
+
+	/* IEEE 802.11u - IP Address Type Availability */
+	u8 ipaddr_type_availability;
+	u8 ipaddr_type_configured;
+
+	/* IEEE 802.11u - 3GPP Cellular Network */
+	u8 *anqp_3gpp_cell_net;
+	size_t anqp_3gpp_cell_net_len;
+
+	/* IEEE 802.11u - Domain Name */
+	u8 *domain_name;
+	size_t domain_name_len;
+
+	unsigned int nai_realm_count;
+	struct hostapd_nai_realm_data *nai_realm_data;
+
+	u16 gas_comeback_delay;
+	int gas_frag_limit;
+
+#ifdef CONFIG_HS20
+	int hs20;
+	int disable_dgaf;
+	unsigned int hs20_oper_friendly_name_count;
+	struct hostapd_lang_string *hs20_oper_friendly_name;
+	u8 *hs20_wan_metrics;
+	u8 *hs20_connection_capability;
+	size_t hs20_connection_capability_len;
+	u8 *hs20_operating_class;
+	u8 hs20_operating_class_len;
+#endif /* CONFIG_HS20 */
+
+	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+
+	struct wpabuf *vendor_elements;
+};
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+	struct hostapd_bss_config *bss, *last_bss;
+	size_t num_bss;
+
+	u16 beacon_int;
+	int rts_threshold;
+	int fragm_threshold;
+	u8 send_probe_response;
+	u8 channel;
+	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+	enum {
+		LONG_PREAMBLE = 0,
+		SHORT_PREAMBLE = 1
+	} preamble;
+
+	int *supported_rates;
+	int *basic_rates;
+
+	const struct wpa_driver_ops *driver;
+
+	int ap_table_max_size;
+	int ap_table_expiration_time;
+
+	char country[3]; /* first two octets: country code as described in
+			  * ISO/IEC 3166-1. Third octet:
+			  * ' ' (ascii 32): all environments
+			  * 'O': Outdoor environemnt only
+			  * 'I': Indoor environment only
+			  */
+
+	int ieee80211d;
+
+	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+	/*
+	 * WMM AC parameters, in same order as 802.1D, i.e.
+	 * 0 = BE (best effort)
+	 * 1 = BK (background)
+	 * 2 = VI (video)
+	 * 3 = VO (voice)
+	 */
+	struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+	int ht_op_mode_fixed;
+	u16 ht_capab;
+	int ieee80211n;
+	int secondary_channel;
+	int require_ht;
+	u32 vht_capab;
+	int ieee80211ac;
+	int require_vht;
+	u8 vht_oper_chwidth;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+};
+
+
+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(struct hostapd_config *conf);
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+			  const u8 *addr, int *vlan_id);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+			struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+					int vlan_id);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+
+#endif /* HOSTAPD_CONFIG_H */

Deleted: vendor/wpa/2.0/src/ap/ap_drv_ops.c
===================================================================
--- vendor/wpa/dist/src/ap/ap_drv_ops.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_drv_ops.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,621 +0,0 @@
-/*
- * hostapd - Driver operations
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "drivers/driver.h"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "ap_config.h"
-#include "ap_drv_ops.h"
-
-
-static int hostapd_sta_flags_to_drv(int flags)
-{
-	int res = 0;
-	if (flags & WLAN_STA_AUTHORIZED)
-		res |= WPA_STA_AUTHORIZED;
-	if (flags & WLAN_STA_WMM)
-		res |= WPA_STA_WMM;
-	if (flags & WLAN_STA_SHORT_PREAMBLE)
-		res |= WPA_STA_SHORT_PREAMBLE;
-	if (flags & WLAN_STA_MFP)
-		res |= WPA_STA_MFP;
-	return res;
-}
-
-
-static int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
-{
-	struct wpabuf *beacon, *proberesp;
-	int ret;
-
-	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
-		return 0;
-
-	beacon = hapd->wps_beacon_ie;
-	proberesp = hapd->wps_probe_resp_ie;
-
-	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp);
-
-	return ret;
-}
-
-
-static int hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg,
-			   size_t len)
-{
-	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
-		return 0;
-	return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
-}
-
-
-static int hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr,
-			      const u8 *data, size_t data_len, int encrypt)
-{
-	if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
-		return 0;
-	return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
-					     data_len, encrypt,
-					     hapd->own_addr);
-}
-
-
-static int hostapd_set_authorized(struct hostapd_data *hapd,
-				  struct sta_info *sta, int authorized)
-{
-	if (authorized) {
-		return hostapd_sta_set_flags(hapd, sta->addr,
-					     hostapd_sta_flags_to_drv(
-						     sta->flags),
-					     WPA_STA_AUTHORIZED, ~0);
-	}
-
-	return hostapd_sta_set_flags(hapd, sta->addr,
-				     hostapd_sta_flags_to_drv(sta->flags),
-				     0, ~WPA_STA_AUTHORIZED);
-}
-
-
-static int hostapd_set_key(const char *ifname, struct hostapd_data *hapd,
-			   enum wpa_alg alg, const u8 *addr, int key_idx,
-			   int set_tx, const u8 *seq, size_t seq_len,
-			   const u8 *key, size_t key_len)
-{
-	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
-		return 0;
-	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
-				     key_idx, set_tx, seq, seq_len, key,
-				     key_len);
-}
-
-
-static int hostapd_read_sta_data(struct hostapd_data *hapd,
-				 struct hostap_sta_driver_data *data,
-				 const u8 *addr)
-{
-	if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
-		return -1;
-	return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
-}
-
-
-static int hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
-{
-	if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
-		return 0;
-	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
-}
-
-
-static int hostapd_set_sta_flags(struct hostapd_data *hapd,
-				 struct sta_info *sta)
-{
-	int set_flags, total_flags, flags_and, flags_or;
-	total_flags = hostapd_sta_flags_to_drv(sta->flags);
-	set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
-	if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
-	     sta->auth_alg == WLAN_AUTH_FT) &&
-	    sta->flags & WLAN_STA_AUTHORIZED)
-		set_flags |= WPA_STA_AUTHORIZED;
-	flags_or = total_flags & set_flags;
-	flags_and = total_flags | ~set_flags;
-	return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
-				     flags_or, flags_and);
-}
-
-
-static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd,
-				     const char *ifname, int enabled)
-{
-	struct wpa_bss_params params;
-	os_memset(&params, 0, sizeof(params));
-	params.ifname = ifname;
-	params.enabled = enabled;
-	if (enabled) {
-		params.wpa = hapd->conf->wpa;
-		params.ieee802_1x = hapd->conf->ieee802_1x;
-		params.wpa_group = hapd->conf->wpa_group;
-		params.wpa_pairwise = hapd->conf->wpa_pairwise;
-		params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
-		params.rsn_preauth = hapd->conf->rsn_preauth;
-	}
-	return hostapd_set_ieee8021x(hapd, &params);
-}
-
-
-static int hostapd_set_radius_acl_auth(struct hostapd_data *hapd,
-				       const u8 *mac, int accepted,
-				       u32 session_timeout)
-{
-	if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
-		return 0;
-	return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
-						 session_timeout);
-}
-
-
-static int hostapd_set_radius_acl_expire(struct hostapd_data *hapd,
-					 const u8 *mac)
-{
-	if (hapd->driver == NULL ||
-	    hapd->driver->set_radius_acl_expire == NULL)
-		return 0;
-	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
-}
-
-
-static int hostapd_set_bss_params(struct hostapd_data *hapd,
-				  int use_protection)
-{
-	int ret = 0;
-	int preamble;
-#ifdef CONFIG_IEEE80211N
-	u8 buf[60], *ht_capab, *ht_oper, *pos;
-
-	pos = buf;
-	ht_capab = pos;
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	ht_oper = pos;
-	pos = hostapd_eid_ht_operation(hapd, pos);
-	if (pos > ht_oper && ht_oper > ht_capab &&
-	    hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
-				  ht_oper + 2, ht_oper[1])) {
-		wpa_printf(MSG_ERROR, "Could not set HT capabilities "
-			   "for kernel driver");
-		ret = -1;
-	}
-
-#endif /* CONFIG_IEEE80211N */
-
-	if (hostapd_set_cts_protect(hapd, use_protection)) {
-		wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->current_mode &&
-	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
-	    hostapd_set_short_slot_time(hapd,
-					hapd->iface->num_sta_no_short_slot_time
-					> 0 ? 0 : 1)) {
-		wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
-			   "in kernel driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->num_sta_no_short_preamble == 0 &&
-	    hapd->iconf->preamble == SHORT_PREAMBLE)
-		preamble = SHORT_PREAMBLE;
-	else
-		preamble = LONG_PREAMBLE;
-	if (hostapd_set_preamble(hapd, preamble)) {
-		wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-static int hostapd_set_beacon(struct hostapd_data *hapd,
-			      const u8 *head, size_t head_len,
-			      const u8 *tail, size_t tail_len, int dtim_period,
-			      int beacon_int)
-{
-	if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
-		return 0;
-	return hapd->driver->set_beacon(hapd->drv_priv,
-					head, head_len, tail, tail_len,
-					dtim_period, beacon_int);
-}
-
-
-static int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
-{
-	char force_ifname[IFNAMSIZ];
-	u8 if_addr[ETH_ALEN];
-	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL, NULL,
-			      force_ifname, if_addr);
-}
-
-static int hostapd_vlan_if_remove(struct hostapd_data *hapd,
-				  const char *ifname)
-{
-	return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
-}
-
-
-static int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr,
-			       int aid, int val)
-{
-	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
-		return 0;
-	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val);
-}
-
-
-static int hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
-				const u8 *addr, int vlan_id)
-{
-	if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
-		return 0;
-	return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
-					  vlan_id);
-}
-
-
-static int hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
-{
-	if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
-		return 0;
-	return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
-}
-
-
-static int hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr,
-			      int reason)
-{
-	if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
-		return 0;
-	return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
-					reason);
-}
-
-
-static int hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr,
-				int reason)
-{
-	if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
-		return 0;
-	return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
-					  reason);
-}
-
-
-static int hostapd_sta_add(struct hostapd_data *hapd,
-			   const u8 *addr, u16 aid, u16 capability,
-			   const u8 *supp_rates, size_t supp_rates_len,
-			   u16 listen_interval,
-			   const struct ieee80211_ht_capabilities *ht_capab)
-{
-	struct hostapd_sta_add_params params;
-
-	if (hapd->driver == NULL)
-		return 0;
-	if (hapd->driver->sta_add == NULL)
-		return 0;
-
-	os_memset(&params, 0, sizeof(params));
-	params.addr = addr;
-	params.aid = aid;
-	params.capability = capability;
-	params.supp_rates = supp_rates;
-	params.supp_rates_len = supp_rates_len;
-	params.listen_interval = listen_interval;
-	params.ht_capabilities = ht_capab;
-	return hapd->driver->sta_add(hapd->drv_priv, &params);
-}
-
-
-static int hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
-{
-	if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
-		return 0;
-	return hapd->driver->sta_remove(hapd->drv_priv, addr);
-}
-
-
-static int hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
-{
-	if (hapd->driver == NULL ||
-	    hapd->driver->hapd_set_countermeasures == NULL)
-		return 0;
-	return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
-}
-
-
-void hostapd_set_driver_ops(struct hostapd_driver_ops *ops)
-{
-	ops->set_ap_wps_ie = hostapd_set_ap_wps_ie;
-	ops->send_mgmt_frame = hostapd_send_mgmt_frame;
-	ops->send_eapol = hostapd_send_eapol;
-	ops->set_authorized = hostapd_set_authorized;
-	ops->set_key = hostapd_set_key;
-	ops->read_sta_data = hostapd_read_sta_data;
-	ops->sta_clear_stats = hostapd_sta_clear_stats;
-	ops->set_sta_flags = hostapd_set_sta_flags;
-	ops->set_drv_ieee8021x = hostapd_set_drv_ieee8021x;
-	ops->set_radius_acl_auth = hostapd_set_radius_acl_auth;
-	ops->set_radius_acl_expire = hostapd_set_radius_acl_expire;
-	ops->set_bss_params = hostapd_set_bss_params;
-	ops->set_beacon = hostapd_set_beacon;
-	ops->vlan_if_add = hostapd_vlan_if_add;
-	ops->vlan_if_remove = hostapd_vlan_if_remove;
-	ops->set_wds_sta = hostapd_set_wds_sta;
-	ops->set_sta_vlan = hostapd_set_sta_vlan;
-	ops->get_inact_sec = hostapd_get_inact_sec;
-	ops->sta_deauth = hostapd_sta_deauth;
-	ops->sta_disassoc = hostapd_sta_disassoc;
-	ops->sta_add = hostapd_sta_add;
-	ops->sta_remove = hostapd_sta_remove;
-	ops->set_countermeasures = hostapd_set_countermeasures;
-}
-
-
-int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
-{
-	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
-		return 0;
-	return hapd->driver->set_privacy(hapd->drv_priv, enabled);
-}
-
-
-int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
-			     size_t elem_len)
-{
-	if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
-		return 0;
-	return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len);
-}
-
-
-int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
-{
-	if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
-		return 0;
-	return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
-}
-
-
-int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
-{
-	if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
-		return 0;
-	return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
-}
-
-
-int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
-		   const char *ifname, const u8 *addr, void *bss_ctx,
-		   void **drv_priv, char *force_ifname, u8 *if_addr)
-{
-	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
-		return -1;
-	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
-				    bss_ctx, drv_priv, force_ifname, if_addr);
-}
-
-
-int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
-		      const char *ifname)
-{
-	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
-		return -1;
-	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
-}
-
-
-int hostapd_set_ieee8021x(struct hostapd_data *hapd,
-			  struct wpa_bss_params *params)
-{
-	if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
-		return 0;
-	return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
-}
-
-
-int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
-		       const u8 *addr, int idx, u8 *seq)
-{
-	if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
-		return 0;
-	return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
-					seq);
-}
-
-
-int hostapd_flush(struct hostapd_data *hapd)
-{
-	if (hapd->driver == NULL || hapd->driver->flush == NULL)
-		return 0;
-	return hapd->driver->flush(hapd->drv_priv);
-}
-
-
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int sec_channel_offset)
-{
-	struct hostapd_freq_params data;
-	if (hapd->driver == NULL)
-		return 0;
-	if (hapd->driver->set_freq == NULL)
-		return 0;
-	os_memset(&data, 0, sizeof(data));
-	data.mode = mode;
-	data.freq = freq;
-	data.channel = channel;
-	data.ht_enabled = ht_enabled;
-	data.sec_channel_offset = sec_channel_offset;
-	return hapd->driver->set_freq(hapd->drv_priv, &data);
-}
-
-int hostapd_set_rts(struct hostapd_data *hapd, int rts)
-{
-	if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
-		return 0;
-	return hapd->driver->set_rts(hapd->drv_priv, rts);
-}
-
-
-int hostapd_set_frag(struct hostapd_data *hapd, int frag)
-{
-	if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
-		return 0;
-	return hapd->driver->set_frag(hapd->drv_priv, frag);
-}
-
-
-int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
-			  int total_flags, int flags_or, int flags_and)
-{
-	if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
-		return 0;
-	return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
-					   flags_or, flags_and);
-}
-
-
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode)
-{
-	if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
-		return 0;
-	return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
-					   basic_rates, mode);
-}
-
-
-int hostapd_set_country(struct hostapd_data *hapd, const char *country)
-{
-	if (hapd->driver == NULL ||
-	    hapd->driver->set_country == NULL)
-		return 0;
-	return hapd->driver->set_country(hapd->drv_priv, country);
-}
-
-
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
-		return 0;
-	return hapd->driver->set_cts_protect(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_preamble(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
-		return 0;
-	return hapd->driver->set_preamble(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
-		return 0;
-	return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
-				int cw_min, int cw_max, int burst_time)
-{
-	if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
-		return 0;
-	return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
-						 cw_min, cw_max, burst_time);
-}
-
-
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask)
-{
-	if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
-		return 1;
-	return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
-}
-
-
-struct hostapd_hw_modes *
-hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
-			    u16 *flags)
-{
-	if (hapd->driver == NULL ||
-	    hapd->driver->get_hw_feature_data == NULL)
-		return NULL;
-	return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
-						 flags);
-}
-
-
-int hostapd_driver_commit(struct hostapd_data *hapd)
-{
-	if (hapd->driver == NULL || hapd->driver->commit == NULL)
-		return 0;
-	return hapd->driver->commit(hapd->drv_priv);
-}
-
-
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len)
-{
-	if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
-	    ht_capab == NULL || ht_oper == NULL)
-		return 0;
-	return hapd->driver->set_ht_params(hapd->drv_priv,
-					   ht_capab, ht_capab_len,
-					   ht_oper, ht_oper_len);
-}
-
-
-int hostapd_drv_none(struct hostapd_data *hapd)
-{
-	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
-}
-
-
-int hostapd_driver_scan(struct hostapd_data *hapd,
-			struct wpa_driver_scan_params *params)
-{
-	if (hapd->driver && hapd->driver->scan2)
-		return hapd->driver->scan2(hapd->drv_priv, params);
-	return -1;
-}
-
-
-struct wpa_scan_results * hostapd_driver_get_scan_results(
-	struct hostapd_data *hapd)
-{
-	if (hapd->driver && hapd->driver->get_scan_results2)
-		return hapd->driver->get_scan_results2(hapd->drv_priv);
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/ap/ap_drv_ops.c (from rev 9639, vendor/wpa/dist/src/ap/ap_drv_ops.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_drv_ops.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_drv_ops.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,634 @@
+/*
+ * hostapd - Driver operations
+ * Copyright (c) 2009-2010, Jouni Malinen <j at 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 "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "p2p_hostapd.h"
+#include "hs20.h"
+#include "ap_drv_ops.h"
+
+
+u32 hostapd_sta_flags_to_drv(u32 flags)
+{
+	int res = 0;
+	if (flags & WLAN_STA_AUTHORIZED)
+		res |= WPA_STA_AUTHORIZED;
+	if (flags & WLAN_STA_WMM)
+		res |= WPA_STA_WMM;
+	if (flags & WLAN_STA_SHORT_PREAMBLE)
+		res |= WPA_STA_SHORT_PREAMBLE;
+	if (flags & WLAN_STA_MFP)
+		res |= WPA_STA_MFP;
+	return res;
+}
+
+
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon_ret,
+			       struct wpabuf **proberesp_ret,
+			       struct wpabuf **assocresp_ret)
+{
+	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+	u8 buf[200], *pos;
+
+	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
+
+	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);
+	}
+	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);
+	}
+
+	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);
+	}
+	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 (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);
+	}
+
+#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);
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE) {
+		if (wpabuf_resize(&beacon, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(beacon, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(beacon, p - start);
+		}
+
+		if (wpabuf_resize(&proberesp, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(proberesp, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(proberesp, p - start);
+		}
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_WPS2
+	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);
+		wpabuf_free(a);
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE) {
+		if (wpabuf_resize(&assocresp, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(assocresp, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(assocresp, p - start);
+		}
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_WIFI_DISPLAY
+	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);
+		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);
+	}
+#endif /* CONFIG_HS20 */
+
+	*beacon_ret = beacon;
+	*proberesp_ret = proberesp;
+	*assocresp_ret = assocresp;
+
+	return 0;
+
+fail:
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+	return -1;
+}
+
+
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp)
+{
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int ret;
+
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		return -1;
+
+	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
+					  assocresp);
+
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+
+	return ret;
+}
+
+
+int hostapd_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized)
+{
+	if (authorized) {
+		return hostapd_sta_set_flags(hapd, sta->addr,
+					     hostapd_sta_flags_to_drv(
+						     sta->flags),
+					     WPA_STA_AUTHORIZED, ~0);
+	}
+
+	return hostapd_sta_set_flags(hapd, sta->addr,
+				     hostapd_sta_flags_to_drv(sta->flags),
+				     0, ~WPA_STA_AUTHORIZED);
+}
+
+
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int set_flags, total_flags, flags_and, flags_or;
+	total_flags = hostapd_sta_flags_to_drv(sta->flags);
+	set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
+	if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+	     sta->auth_alg == WLAN_AUTH_FT) &&
+	    sta->flags & WLAN_STA_AUTHORIZED)
+		set_flags |= WPA_STA_AUTHORIZED;
+	flags_or = total_flags & set_flags;
+	flags_and = total_flags | ~set_flags;
+	return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
+				     flags_or, flags_and);
+}
+
+
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+			      int enabled)
+{
+	struct wpa_bss_params params;
+	os_memset(&params, 0, sizeof(params));
+	params.ifname = ifname;
+	params.enabled = enabled;
+	if (enabled) {
+		params.wpa = hapd->conf->wpa;
+		params.ieee802_1x = hapd->conf->ieee802_1x;
+		params.wpa_group = hapd->conf->wpa_group;
+		params.wpa_pairwise = hapd->conf->wpa_pairwise;
+		params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
+		params.rsn_preauth = hapd->conf->rsn_preauth;
+#ifdef CONFIG_IEEE80211W
+		params.ieee80211w = hapd->conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+	}
+	return hostapd_set_ieee8021x(hapd, &params);
+}
+
+
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
+{
+	char force_ifname[IFNAMSIZ];
+	u8 if_addr[ETH_ALEN];
+	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
+			      NULL, NULL, force_ifname, if_addr, NULL);
+}
+
+
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
+{
+	return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
+}
+
+
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+			int val)
+{
+	const char *bridge = NULL;
+
+	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
+		return 0;
+	if (hapd->conf->wds_bridge[0])
+		bridge = hapd->conf->wds_bridge;
+	else if (hapd->conf->bridge[0])
+		bridge = hapd->conf->bridge;
+	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+					 bridge);
+}
+
+
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg)
+{
+	if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
+		return 0;
+	return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
+}
+
+
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
+		return 0;
+	return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+				      seq, status, ie, len);
+}
+
+
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
+		return 0;
+	return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+				       reassoc, status, ie, len);
+}
+
+
+int hostapd_sta_add(struct hostapd_data *hapd,
+		    const u8 *addr, u16 aid, u16 capability,
+		    const u8 *supp_rates, size_t supp_rates_len,
+		    u16 listen_interval,
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo)
+{
+	struct hostapd_sta_add_params params;
+
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->sta_add == NULL)
+		return 0;
+
+	os_memset(&params, 0, sizeof(params));
+	params.addr = addr;
+	params.aid = aid;
+	params.capability = capability;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+	params.listen_interval = listen_interval;
+	params.ht_capabilities = ht_capab;
+	params.flags = hostapd_sta_flags_to_drv(flags);
+	params.qosinfo = qosinfo;
+	return hapd->driver->sta_add(hapd->drv_priv, &params);
+}
+
+
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
+		return 0;
+	return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+				       tspec_ielen);
+}
+
+
+int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
+{
+	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
+		return 0;
+	return hapd->driver->set_privacy(hapd->drv_priv, enabled);
+}
+
+
+int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
+			     size_t elem_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
+		return 0;
+	return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len);
+}
+
+
+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
+		return 0;
+	return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
+}
+
+
+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
+		return 0;
+	return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
+}
+
+
+int hostapd_if_add(struct hostapd_data *hapd, 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)
+{
+	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+		return -1;
+	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
+				    bss_ctx, drv_priv, force_ifname, if_addr,
+				    bridge);
+}
+
+
+int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		      const char *ifname)
+{
+	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+		return -1;
+	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
+}
+
+
+int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+			  struct wpa_bss_params *params)
+{
+	if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
+		return 0;
+	return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
+}
+
+
+int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+		       const u8 *addr, int idx, u8 *seq)
+{
+	if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
+		return 0;
+	return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
+					seq);
+}
+
+
+int hostapd_flush(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->flush == NULL)
+		return 0;
+	return hapd->driver->flush(hapd->drv_priv);
+}
+
+
+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
+		     int channel, int ht_enabled, int sec_channel_offset)
+{
+	struct hostapd_freq_params data;
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->set_freq == NULL)
+		return 0;
+	os_memset(&data, 0, sizeof(data));
+	data.mode = mode;
+	data.freq = freq;
+	data.channel = channel;
+	data.ht_enabled = ht_enabled;
+	data.sec_channel_offset = sec_channel_offset;
+	return hapd->driver->set_freq(hapd->drv_priv, &data);
+}
+
+int hostapd_set_rts(struct hostapd_data *hapd, int rts)
+{
+	if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
+		return 0;
+	return hapd->driver->set_rts(hapd->drv_priv, rts);
+}
+
+
+int hostapd_set_frag(struct hostapd_data *hapd, int frag)
+{
+	if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
+		return 0;
+	return hapd->driver->set_frag(hapd->drv_priv, frag);
+}
+
+
+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+			  int total_flags, int flags_or, int flags_and)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+		return 0;
+	return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
+					   flags_or, flags_and);
+}
+
+
+int hostapd_set_country(struct hostapd_data *hapd, const char *country)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_country == NULL)
+		return 0;
+	return hapd->driver->set_country(hapd->drv_priv, country);
+}
+
+
+int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+				int cw_min, int cw_max, int burst_time)
+{
+	if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
+		return 0;
+	return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
+						 cw_min, cw_max, burst_time);
+}
+
+
+struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+			    u16 *flags)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->get_hw_feature_data == NULL)
+		return NULL;
+	return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
+						 flags);
+}
+
+
+int hostapd_driver_commit(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->commit == NULL)
+		return 0;
+	return hapd->driver->commit(hapd->drv_priv);
+}
+
+
+int hostapd_drv_none(struct hostapd_data *hapd)
+{
+	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
+}
+
+
+int hostapd_driver_scan(struct hostapd_data *hapd,
+			struct wpa_driver_scan_params *params)
+{
+	if (hapd->driver && hapd->driver->scan2)
+		return hapd->driver->scan2(hapd->drv_priv, params);
+	return -1;
+}
+
+
+struct wpa_scan_results * hostapd_driver_get_scan_results(
+	struct hostapd_data *hapd)
+{
+	if (hapd->driver && hapd->driver->get_scan_results2)
+		return hapd->driver->get_scan_results2(hapd->drv_priv);
+	return NULL;
+}
+
+
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			   int duration)
+{
+	if (hapd->driver && hapd->driver->set_noa)
+		return hapd->driver->set_noa(hapd->drv_priv, count, start,
+					     duration);
+	return -1;
+}
+
+
+int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
+			enum wpa_alg alg, const u8 *addr,
+			int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			const u8 *key, size_t key_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
+		return 0;
+	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
+				     key_idx, set_tx, seq, seq_len, key,
+				     key_len);
+}
+
+
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+			  const void *msg, size_t len, int noack)
+{
+	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+		return 0;
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+}
+
+
+int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
+			   const u8 *addr, int reason)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+		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)
+		return 0;
+	return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
+					  reason);
+}
+
+
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
+			 const u8 *peer, u8 *buf, u16 *buf_len)
+{
+	if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
+		return 0;
+	return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
+				      buf_len);
+}
+
+
+int hostapd_drv_send_action(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,
+					 hapd->own_addr, hapd->own_addr, data,
+					 len, 0);
+}

Deleted: vendor/wpa/2.0/src/ap/ap_drv_ops.h
===================================================================
--- vendor/wpa/dist/src/ap/ap_drv_ops.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_drv_ops.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,67 +0,0 @@
-/*
- * hostapd - Driver operations
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AP_DRV_OPS
-#define AP_DRV_OPS
-
-enum wpa_driver_if_type;
-struct wpa_bss_params;
-struct wpa_driver_scan_params;
-
-void hostapd_set_driver_ops(struct hostapd_driver_ops *ops);
-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);
-int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
-int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
-int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
-		   const char *ifname, const u8 *addr, void *bss_ctx,
-		   void **drv_priv, char *force_ifname, u8 *if_addr);
-int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
-		      const char *ifname);
-int hostapd_set_ieee8021x(struct hostapd_data *hapd,
-			  struct wpa_bss_params *params);
-int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
-		       const u8 *addr, int idx, u8 *seq);
-int hostapd_flush(struct hostapd_data *hapd);
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int sec_channel_offset);
-int hostapd_set_rts(struct hostapd_data *hapd, int rts);
-int hostapd_set_frag(struct hostapd_data *hapd, int frag);
-int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
-			  int total_flags, int flags_or, int flags_and);
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode);
-int hostapd_set_country(struct hostapd_data *hapd, const char *country);
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
-int hostapd_set_preamble(struct hostapd_data *hapd, int value);
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
-int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
-				int cw_min, int cw_max, int burst_time);
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask);
-struct hostapd_hw_modes *
-hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
-			    u16 *flags);
-int hostapd_driver_commit(struct hostapd_data *hapd);
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len);
-int hostapd_drv_none(struct hostapd_data *hapd);
-int hostapd_driver_scan(struct hostapd_data *hapd,
-			struct wpa_driver_scan_params *params);
-struct wpa_scan_results * hostapd_driver_get_scan_results(
-	struct hostapd_data *hapd);
-
-#endif /* AP_DRV_OPS */

Copied: vendor/wpa/2.0/src/ap/ap_drv_ops.h (from rev 9639, vendor/wpa/dist/src/ap/ap_drv_ops.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_drv_ops.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_drv_ops.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,216 @@
+/*
+ * hostapd - Driver operations
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_DRV_OPS
+#define AP_DRV_OPS
+
+enum wpa_driver_if_type;
+struct wpa_bss_params;
+struct wpa_driver_scan_params;
+struct ieee80211_ht_capabilities;
+
+u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp);
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
+int hostapd_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized);
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+			      int enabled);
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+			int val);
+int hostapd_sta_add(struct hostapd_data *hapd,
+		    const u8 *addr, u16 aid, u16 capability,
+		    const u8 *supp_rates, size_t supp_rates_len,
+		    u16 listen_interval,
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo);
+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);
+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
+int hostapd_if_add(struct hostapd_data *hapd, 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 hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		      const char *ifname);
+int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+			  struct wpa_bss_params *params);
+int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+		       const u8 *addr, int idx, u8 *seq);
+int hostapd_flush(struct hostapd_data *hapd);
+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
+		     int channel, int ht_enabled, int sec_channel_offset);
+int hostapd_set_rts(struct hostapd_data *hapd, int rts);
+int hostapd_set_frag(struct hostapd_data *hapd, int frag);
+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+			  int total_flags, int flags_or, int flags_and);
+int hostapd_set_country(struct hostapd_data *hapd, const char *country);
+int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+				int cw_min, int cw_max, int burst_time);
+struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+			    u16 *flags);
+int hostapd_driver_commit(struct hostapd_data *hapd);
+int hostapd_drv_none(struct hostapd_data *hapd);
+int hostapd_driver_scan(struct hostapd_data *hapd,
+			struct wpa_driver_scan_params *params);
+struct wpa_scan_results * hostapd_driver_get_scan_results(
+	struct hostapd_data *hapd);
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			   int duration);
+int hostapd_drv_set_key(const char *ifname,
+			struct hostapd_data *hapd,
+			enum wpa_alg alg, const u8 *addr,
+			int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			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_sta_deauth(struct hostapd_data *hapd,
+			   const u8 *addr, int reason);
+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
+			     const u8 *addr, int reason);
+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_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len);
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen);
+
+
+#include "drivers/driver.h"
+
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
+			 enum wnm_oper oper, const u8 *peer,
+			 u8 *buf, u16 *buf_len);
+
+static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
+						  int enabled)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->hapd_set_countermeasures == NULL)
+		return 0;
+	return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
+}
+
+static inline int hostapd_drv_set_sta_vlan(const char *ifname,
+					   struct hostapd_data *hapd,
+					   const u8 *addr, int vlan_id)
+{
+	if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+		return 0;
+	return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
+					  vlan_id);
+}
+
+static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
+					    const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+		return 0;
+	return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
+					 const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+		return 0;
+	return hapd->driver->sta_remove(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
+					      const u8 *addr, const u8 *data,
+					      size_t data_len, int encrypt,
+					      u32 flags)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
+		return 0;
+	return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
+					     data_len, encrypt,
+					     hapd->own_addr, flags);
+}
+
+static inline int hostapd_drv_read_sta_data(
+	struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
+	const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
+		return -1;
+	return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
+}
+
+static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
+					      const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
+		return 0;
+	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+				     struct wpa_driver_ap_params *params)
+{
+	if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
+		return 0;
+	return hapd->driver->set_ap(hapd->drv_priv, params);
+}
+
+static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
+						  const u8 *mac, int accepted,
+						  u32 session_timeout)
+{
+	if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
+		return 0;
+	return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
+						 session_timeout);
+}
+
+static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
+						    const u8 *mac)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_radius_acl_expire == NULL)
+		return 0;
+	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
+}
+
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+					   int auth_algs)
+{
+	if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+		return 0;
+	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+					   const u8 *own_addr, const u8 *addr,
+					   int qos)
+{
+	if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+		return;
+	hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
+#endif /* AP_DRV_OPS */

Deleted: vendor/wpa/2.0/src/ap/ap_list.c
===================================================================
--- vendor/wpa/dist/src/ap/ap_list.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_list.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,397 +0,0 @@
-/*
- * hostapd / AP table
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2003-2004, Instant802 Networks, Inc.
- * Copyright (c) 2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "beacon.h"
-#include "ap_list.h"
-
-
-/* AP list is a double linked list with head->prev pointing to the end of the
- * list and tail->next = NULL. Entries are moved to the head of the list
- * whenever a beacon has been received from the AP in question. The tail entry
- * in this link will thus be the least recently used entry. */
-
-
-static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	int i;
-
-	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
-	    iface->conf->channel != ap->channel)
-		return 0;
-
-	if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
-		return 1;
-
-	for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
-		int rate = (ap->supported_rates[i] & 0x7f) * 5;
-		if (rate == 60 || rate == 90 || rate > 110)
-			return 0;
-	}
-
-	return 1;
-}
-
-
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
-{
-	struct ap_info *s;
-
-	s = iface->ap_hash[STA_HASH(ap)];
-	while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
-		s = s->hnext;
-	return s;
-}
-
-
-static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	if (iface->ap_list) {
-		ap->prev = iface->ap_list->prev;
-		iface->ap_list->prev = ap;
-	} else
-		ap->prev = ap;
-	ap->next = iface->ap_list;
-	iface->ap_list = ap;
-}
-
-
-static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	if (iface->ap_list == ap)
-		iface->ap_list = ap->next;
-	else
-		ap->prev->next = ap->next;
-
-	if (ap->next)
-		ap->next->prev = ap->prev;
-	else if (iface->ap_list)
-		iface->ap_list->prev = ap->prev;
-}
-
-
-static void ap_ap_iter_list_add(struct hostapd_iface *iface,
-				struct ap_info *ap)
-{
-	if (iface->ap_iter_list) {
-		ap->iter_prev = iface->ap_iter_list->iter_prev;
-		iface->ap_iter_list->iter_prev = ap;
-	} else
-		ap->iter_prev = ap;
-	ap->iter_next = iface->ap_iter_list;
-	iface->ap_iter_list = ap;
-}
-
-
-static void ap_ap_iter_list_del(struct hostapd_iface *iface,
-				struct ap_info *ap)
-{
-	if (iface->ap_iter_list == ap)
-		iface->ap_iter_list = ap->iter_next;
-	else
-		ap->iter_prev->iter_next = ap->iter_next;
-
-	if (ap->iter_next)
-		ap->iter_next->iter_prev = ap->iter_prev;
-	else if (iface->ap_iter_list)
-		iface->ap_iter_list->iter_prev = ap->iter_prev;
-}
-
-
-static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
-	iface->ap_hash[STA_HASH(ap->addr)] = ap;
-}
-
-
-static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	struct ap_info *s;
-
-	s = iface->ap_hash[STA_HASH(ap->addr)];
-	if (s == NULL) return;
-	if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
-		iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
-		return;
-	}
-
-	while (s->hnext != NULL &&
-	       os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
-		s = s->hnext;
-	if (s->hnext != NULL)
-		s->hnext = s->hnext->hnext;
-	else
-		printf("AP: could not remove AP " MACSTR " from hash table\n",
-		       MAC2STR(ap->addr));
-}
-
-
-static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
-{
-	ap_ap_hash_del(iface, ap);
-	ap_ap_list_del(iface, ap);
-	ap_ap_iter_list_del(iface, ap);
-
-	iface->num_ap--;
-	os_free(ap);
-}
-
-
-static void hostapd_free_aps(struct hostapd_iface *iface)
-{
-	struct ap_info *ap, *prev;
-
-	ap = iface->ap_list;
-
-	while (ap) {
-		prev = ap;
-		ap = ap->next;
-		ap_free_ap(iface, prev);
-	}
-
-	iface->ap_list = NULL;
-}
-
-
-int ap_ap_for_each(struct hostapd_iface *iface,
-		   int (*func)(struct ap_info *s, void *data), void *data)
-{
-	struct ap_info *s;
-	int ret = 0;
-
-	s = iface->ap_list;
-
-	while (s) {
-		ret = func(s, data);
-		if (ret)
-			break;
-		s = s->next;
-	}
-
-	return ret;
-}
-
-
-static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
-{
-	struct ap_info *ap;
-
-	ap = os_zalloc(sizeof(struct ap_info));
-	if (ap == NULL)
-		return NULL;
-
-	/* initialize AP info data */
-	os_memcpy(ap->addr, addr, ETH_ALEN);
-	ap_ap_list_add(iface, ap);
-	iface->num_ap++;
-	ap_ap_hash_add(iface, ap);
-	ap_ap_iter_list_add(iface, ap);
-
-	if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
-		wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
-			   MACSTR " from AP table", MAC2STR(ap->prev->addr));
-		ap_free_ap(iface, ap->prev);
-	}
-
-	return ap;
-}
-
-
-void ap_list_process_beacon(struct hostapd_iface *iface,
-			    const struct ieee80211_mgmt *mgmt,
-			    struct ieee802_11_elems *elems,
-			    struct hostapd_frame_info *fi)
-{
-	struct ap_info *ap;
-	int new_ap = 0;
-	size_t len;
-	int set_beacon = 0;
-
-	if (iface->conf->ap_table_max_size < 1)
-		return;
-
-	ap = ap_get_ap(iface, mgmt->bssid);
-	if (!ap) {
-		ap = ap_ap_add(iface, mgmt->bssid);
-		if (!ap) {
-			printf("Failed to allocate AP information entry\n");
-			return;
-		}
-		new_ap = 1;
-	}
-
-	ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
-	ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
-	if (elems->ssid) {
-		len = elems->ssid_len;
-		if (len >= sizeof(ap->ssid))
-			len = sizeof(ap->ssid) - 1;
-		os_memcpy(ap->ssid, elems->ssid, len);
-		ap->ssid[len] = '\0';
-		ap->ssid_len = len;
-	}
-
-	os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
-	len = 0;
-	if (elems->supp_rates) {
-		len = elems->supp_rates_len;
-		if (len > WLAN_SUPP_RATES_MAX)
-			len = WLAN_SUPP_RATES_MAX;
-		os_memcpy(ap->supported_rates, elems->supp_rates, len);
-	}
-	if (elems->ext_supp_rates) {
-		int len2;
-		if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
-			len2 = WLAN_SUPP_RATES_MAX - len;
-		else
-			len2 = elems->ext_supp_rates_len;
-		os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
-			  len2);
-	}
-
-	ap->wpa = elems->wpa_ie != NULL;
-
-	if (elems->erp_info && elems->erp_info_len == 1)
-		ap->erp = elems->erp_info[0];
-	else
-		ap->erp = -1;
-
-	if (elems->ds_params && elems->ds_params_len == 1)
-		ap->channel = elems->ds_params[0];
-	else if (fi)
-		ap->channel = fi->channel;
-
-	if (elems->ht_capabilities)
-		ap->ht_support = 1;
-	else
-		ap->ht_support = 0;
-
-	ap->num_beacons++;
-	time(&ap->last_beacon);
-	if (fi) {
-		ap->ssi_signal = fi->ssi_signal;
-		ap->datarate = fi->datarate;
-	}
-
-	if (!new_ap && ap != iface->ap_list) {
-		/* move AP entry into the beginning of the list so that the
-		 * oldest entry is always in the end of the list */
-		ap_ap_list_del(iface, ap);
-		ap_ap_list_add(iface, ap);
-	}
-
-	if (!iface->olbc &&
-	    ap_list_beacon_olbc(iface, ap)) {
-		iface->olbc = 1;
-		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
-			   "protection", MAC2STR(ap->addr));
-		set_beacon++;
-	}
-
-#ifdef CONFIG_IEEE80211N
-	if (!iface->olbc_ht && !ap->ht_support) {
-		iface->olbc_ht = 1;
-		hostapd_ht_operation_update(iface);
-		wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
-			   " - enable protection", MAC2STR(ap->addr));
-		set_beacon++;
-	}
-#endif /* CONFIG_IEEE80211N */
-
-	if (set_beacon)
-		ieee802_11_set_beacons(iface);
-}
-
-
-static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_iface *iface = eloop_ctx;
-	time_t now;
-	struct ap_info *ap;
-	int set_beacon = 0;
-
-	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
-
-	if (!iface->ap_list)
-		return;
-
-	time(&now);
-
-	while (iface->ap_list) {
-		ap = iface->ap_list->prev;
-		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
-		    now)
-			break;
-
-		ap_free_ap(iface, ap);
-	}
-
-	if (iface->olbc || iface->olbc_ht) {
-		int olbc = 0;
-		int olbc_ht = 0;
-
-		ap = iface->ap_list;
-		while (ap && (olbc == 0 || olbc_ht == 0)) {
-			if (ap_list_beacon_olbc(iface, ap))
-				olbc = 1;
-			if (!ap->ht_support)
-				olbc_ht = 1;
-			ap = ap->next;
-		}
-		if (!olbc && iface->olbc) {
-			wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
-			iface->olbc = 0;
-			set_beacon++;
-		}
-#ifdef CONFIG_IEEE80211N
-		if (!olbc_ht && iface->olbc_ht) {
-			wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
-			iface->olbc_ht = 0;
-			hostapd_ht_operation_update(iface);
-			set_beacon++;
-		}
-#endif /* CONFIG_IEEE80211N */
-	}
-
-	if (set_beacon)
-		ieee802_11_set_beacons(iface);
-}
-
-
-int ap_list_init(struct hostapd_iface *iface)
-{
-	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
-	return 0;
-}
-
-
-void ap_list_deinit(struct hostapd_iface *iface)
-{
-	eloop_cancel_timeout(ap_list_timer, iface, NULL);
-	hostapd_free_aps(iface);
-}

Copied: vendor/wpa/2.0/src/ap/ap_list.c (from rev 9639, vendor/wpa/dist/src/ap/ap_list.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_list.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_list.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,377 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ap_list.h"
+
+
+/* AP list is a double linked list with head->prev pointing to the end of the
+ * list and tail->next = NULL. Entries are moved to the head of the list
+ * whenever a beacon has been received from the AP in question. The tail entry
+ * in this link will thus be the least recently used entry. */
+
+
+static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	int i;
+
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+	    iface->conf->channel != ap->channel)
+		return 0;
+
+	if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
+		return 1;
+
+	for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+		int rate = (ap->supported_rates[i] & 0x7f) * 5;
+		if (rate == 60 || rate == 90 || rate > 110)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+{
+	struct ap_info *s;
+
+	s = iface->ap_hash[STA_HASH(ap)];
+	while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
+		s = s->hnext;
+	return s;
+}
+
+
+static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	if (iface->ap_list) {
+		ap->prev = iface->ap_list->prev;
+		iface->ap_list->prev = ap;
+	} else
+		ap->prev = ap;
+	ap->next = iface->ap_list;
+	iface->ap_list = ap;
+}
+
+
+static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	if (iface->ap_list == ap)
+		iface->ap_list = ap->next;
+	else
+		ap->prev->next = ap->next;
+
+	if (ap->next)
+		ap->next->prev = ap->prev;
+	else if (iface->ap_list)
+		iface->ap_list->prev = ap->prev;
+}
+
+
+static void ap_ap_iter_list_add(struct hostapd_iface *iface,
+				struct ap_info *ap)
+{
+	if (iface->ap_iter_list) {
+		ap->iter_prev = iface->ap_iter_list->iter_prev;
+		iface->ap_iter_list->iter_prev = ap;
+	} else
+		ap->iter_prev = ap;
+	ap->iter_next = iface->ap_iter_list;
+	iface->ap_iter_list = ap;
+}
+
+
+static void ap_ap_iter_list_del(struct hostapd_iface *iface,
+				struct ap_info *ap)
+{
+	if (iface->ap_iter_list == ap)
+		iface->ap_iter_list = ap->iter_next;
+	else
+		ap->iter_prev->iter_next = ap->iter_next;
+
+	if (ap->iter_next)
+		ap->iter_next->iter_prev = ap->iter_prev;
+	else if (iface->ap_iter_list)
+		iface->ap_iter_list->iter_prev = ap->iter_prev;
+}
+
+
+static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
+	iface->ap_hash[STA_HASH(ap->addr)] = ap;
+}
+
+
+static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	struct ap_info *s;
+
+	s = iface->ap_hash[STA_HASH(ap->addr)];
+	if (s == NULL) return;
+	if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
+		iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL &&
+	       os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
+		s = s->hnext;
+	if (s->hnext != NULL)
+		s->hnext = s->hnext->hnext;
+	else
+		printf("AP: could not remove AP " MACSTR " from hash table\n",
+		       MAC2STR(ap->addr));
+}
+
+
+static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	ap_ap_hash_del(iface, ap);
+	ap_ap_list_del(iface, ap);
+	ap_ap_iter_list_del(iface, ap);
+
+	iface->num_ap--;
+	os_free(ap);
+}
+
+
+static void hostapd_free_aps(struct hostapd_iface *iface)
+{
+	struct ap_info *ap, *prev;
+
+	ap = iface->ap_list;
+
+	while (ap) {
+		prev = ap;
+		ap = ap->next;
+		ap_free_ap(iface, prev);
+	}
+
+	iface->ap_list = NULL;
+}
+
+
+int ap_ap_for_each(struct hostapd_iface *iface,
+		   int (*func)(struct ap_info *s, void *data), void *data)
+{
+	struct ap_info *s;
+	int ret = 0;
+
+	s = iface->ap_list;
+
+	while (s) {
+		ret = func(s, data);
+		if (ret)
+			break;
+		s = s->next;
+	}
+
+	return ret;
+}
+
+
+static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
+{
+	struct ap_info *ap;
+
+	ap = os_zalloc(sizeof(struct ap_info));
+	if (ap == NULL)
+		return NULL;
+
+	/* initialize AP info data */
+	os_memcpy(ap->addr, addr, ETH_ALEN);
+	ap_ap_list_add(iface, ap);
+	iface->num_ap++;
+	ap_ap_hash_add(iface, ap);
+	ap_ap_iter_list_add(iface, ap);
+
+	if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
+		wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
+			   MACSTR " from AP table", MAC2STR(ap->prev->addr));
+		ap_free_ap(iface, ap->prev);
+	}
+
+	return ap;
+}
+
+
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    const struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi)
+{
+	struct ap_info *ap;
+	struct os_time now;
+	int new_ap = 0;
+	size_t len;
+	int set_beacon = 0;
+
+	if (iface->conf->ap_table_max_size < 1)
+		return;
+
+	ap = ap_get_ap(iface, mgmt->bssid);
+	if (!ap) {
+		ap = ap_ap_add(iface, mgmt->bssid);
+		if (!ap) {
+			printf("Failed to allocate AP information entry\n");
+			return;
+		}
+		new_ap = 1;
+	}
+
+	ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
+	ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
+
+	if (elems->ssid) {
+		len = elems->ssid_len;
+		if (len >= sizeof(ap->ssid))
+			len = sizeof(ap->ssid) - 1;
+		os_memcpy(ap->ssid, elems->ssid, len);
+		ap->ssid[len] = '\0';
+		ap->ssid_len = len;
+	}
+
+	merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
+			  elems->supp_rates, elems->supp_rates_len,
+			  elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+	ap->wpa = elems->wpa_ie != NULL;
+
+	if (elems->erp_info && elems->erp_info_len == 1)
+		ap->erp = elems->erp_info[0];
+	else
+		ap->erp = -1;
+
+	if (elems->ds_params && elems->ds_params_len == 1)
+		ap->channel = elems->ds_params[0];
+	else if (fi)
+		ap->channel = fi->channel;
+
+	if (elems->ht_capabilities)
+		ap->ht_support = 1;
+	else
+		ap->ht_support = 0;
+
+	ap->num_beacons++;
+	os_get_time(&now);
+	ap->last_beacon = now.sec;
+	if (fi)
+		ap->datarate = fi->datarate;
+
+	if (!new_ap && ap != iface->ap_list) {
+		/* move AP entry into the beginning of the list so that the
+		 * oldest entry is always in the end of the list */
+		ap_ap_list_del(iface, ap);
+		ap_ap_list_add(iface, ap);
+	}
+
+	if (!iface->olbc &&
+	    ap_list_beacon_olbc(iface, ap)) {
+		iface->olbc = 1;
+		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
+			   "protection", MAC2STR(ap->addr));
+		set_beacon++;
+	}
+
+#ifdef CONFIG_IEEE80211N
+	if (!iface->olbc_ht && !ap->ht_support) {
+		iface->olbc_ht = 1;
+		hostapd_ht_operation_update(iface);
+		wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
+			   " - enable protection", MAC2STR(ap->addr));
+		set_beacon++;
+	}
+#endif /* CONFIG_IEEE80211N */
+
+	if (set_beacon)
+		ieee802_11_update_beacons(iface);
+}
+
+
+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+	struct os_time now;
+	struct ap_info *ap;
+	int set_beacon = 0;
+
+	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+
+	if (!iface->ap_list)
+		return;
+
+	os_get_time(&now);
+
+	while (iface->ap_list) {
+		ap = iface->ap_list->prev;
+		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
+		    now.sec)
+			break;
+
+		ap_free_ap(iface, ap);
+	}
+
+	if (iface->olbc || iface->olbc_ht) {
+		int olbc = 0;
+		int olbc_ht = 0;
+
+		ap = iface->ap_list;
+		while (ap && (olbc == 0 || olbc_ht == 0)) {
+			if (ap_list_beacon_olbc(iface, ap))
+				olbc = 1;
+			if (!ap->ht_support)
+				olbc_ht = 1;
+			ap = ap->next;
+		}
+		if (!olbc && iface->olbc) {
+			wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
+			iface->olbc = 0;
+			set_beacon++;
+		}
+#ifdef CONFIG_IEEE80211N
+		if (!olbc_ht && iface->olbc_ht) {
+			wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
+			iface->olbc_ht = 0;
+			hostapd_ht_operation_update(iface);
+			set_beacon++;
+		}
+#endif /* CONFIG_IEEE80211N */
+	}
+
+	if (set_beacon)
+		ieee802_11_update_beacons(iface);
+}
+
+
+int ap_list_init(struct hostapd_iface *iface)
+{
+	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+	return 0;
+}
+
+
+void ap_list_deinit(struct hostapd_iface *iface)
+{
+	eloop_cancel_timeout(ap_list_timer, iface, NULL);
+	hostapd_free_aps(iface);
+}

Deleted: vendor/wpa/2.0/src/ap/ap_list.h
===================================================================
--- vendor/wpa/dist/src/ap/ap_list.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_list.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,78 +0,0 @@
-/*
- * hostapd / AP table
- * Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2003-2004, Instant802 Networks, Inc.
- * Copyright (c) 2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AP_LIST_H
-#define AP_LIST_H
-
-struct ap_info {
-	/* Note: next/prev pointers are updated whenever a new beacon is
-	 * received because these are used to find the least recently used
-	 * entries. iter_next/iter_prev are updated only when adding new BSSes
-	 * and when removing old ones. These should be used when iterating
-	 * through the table in a manner that allows beacons to be received
-	 * during the iteration. */
-	struct ap_info *next; /* next entry in AP list */
-	struct ap_info *prev; /* previous entry in AP list */
-	struct ap_info *hnext; /* next entry in hash table list */
-	struct ap_info *iter_next; /* next entry in AP iteration list */
-	struct ap_info *iter_prev; /* previous entry in AP iteration list */
-	u8 addr[6];
-	u16 beacon_int;
-	u16 capability;
-	u8 supported_rates[WLAN_SUPP_RATES_MAX];
-	u8 ssid[33];
-	size_t ssid_len;
-	int wpa;
-	int erp; /* ERP Info or -1 if ERP info element not present */
-
-	int channel;
-	int datarate; /* in 100 kbps */
-	int ssi_signal;
-
-	int ht_support;
-
-	unsigned int num_beacons; /* number of beacon frames received */
-	time_t last_beacon;
-
-	int already_seen; /* whether API call AP-NEW has already fetched
-			   * information about this AP */
-};
-
-struct ieee802_11_elems;
-struct hostapd_frame_info;
-
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
-int ap_ap_for_each(struct hostapd_iface *iface,
-		   int (*func)(struct ap_info *s, void *data), void *data);
-void ap_list_process_beacon(struct hostapd_iface *iface,
-			    const struct ieee80211_mgmt *mgmt,
-			    struct ieee802_11_elems *elems,
-			    struct hostapd_frame_info *fi);
-#ifdef NEED_AP_MLME
-int ap_list_init(struct hostapd_iface *iface);
-void ap_list_deinit(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline int ap_list_init(struct hostapd_iface *iface)
-{
-	return 0;
-}
-
-static inline void ap_list_deinit(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
-
-#endif /* AP_LIST_H */

Copied: vendor/wpa/2.0/src/ap/ap_list.h (from rev 9639, vendor/wpa/dist/src/ap/ap_list.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_list.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_list.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_LIST_H
+#define AP_LIST_H
+
+struct ap_info {
+	/* Note: next/prev pointers are updated whenever a new beacon is
+	 * received because these are used to find the least recently used
+	 * entries. iter_next/iter_prev are updated only when adding new BSSes
+	 * and when removing old ones. These should be used when iterating
+	 * through the table in a manner that allows beacons to be received
+	 * during the iteration. */
+	struct ap_info *next; /* next entry in AP list */
+	struct ap_info *prev; /* previous entry in AP list */
+	struct ap_info *hnext; /* next entry in hash table list */
+	struct ap_info *iter_next; /* next entry in AP iteration list */
+	struct ap_info *iter_prev; /* previous entry in AP iteration list */
+	u8 addr[6];
+	u16 beacon_int;
+	u16 capability;
+	u8 supported_rates[WLAN_SUPP_RATES_MAX];
+	u8 ssid[33];
+	size_t ssid_len;
+	int wpa;
+	int erp; /* ERP Info or -1 if ERP info element not present */
+
+	int channel;
+	int datarate; /* in 100 kbps */
+
+	int ht_support;
+
+	unsigned int num_beacons; /* number of beacon frames received */
+	os_time_t last_beacon;
+
+	int already_seen; /* whether API call AP-NEW has already fetched
+			   * information about this AP */
+};
+
+struct ieee802_11_elems;
+struct hostapd_frame_info;
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
+int ap_ap_for_each(struct hostapd_iface *iface,
+		   int (*func)(struct ap_info *s, void *data), void *data);
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    const struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi);
+#ifdef NEED_AP_MLME
+int ap_list_init(struct hostapd_iface *iface);
+void ap_list_deinit(struct hostapd_iface *iface);
+#else /* NEED_AP_MLME */
+static inline int ap_list_init(struct hostapd_iface *iface)
+{
+	return 0;
+}
+
+static inline void ap_list_deinit(struct hostapd_iface *iface)
+{
+}
+#endif /* NEED_AP_MLME */
+
+#endif /* AP_LIST_H */

Deleted: vendor/wpa/2.0/src/ap/ap_mlme.c
===================================================================
--- vendor/wpa/dist/src/ap/ap_mlme.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_mlme.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,184 +0,0 @@
-/*
- * hostapd / IEEE 802.11 MLME
- * Copyright 2003-2006, Jouni Malinen <j at w1.fi>
- * Copyright 2003-2004, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "ieee802_11.h"
-#include "wpa_auth.h"
-#include "sta_info.h"
-#include "ap_mlme.h"
-
-
-#ifndef CONFIG_NO_HOSTAPD_LOGGER
-static const char * mlme_auth_alg_str(int alg)
-{
-	switch (alg) {
-	case WLAN_AUTH_OPEN:
-		return "OPEN_SYSTEM";
-	case WLAN_AUTH_SHARED_KEY:
-		return "SHARED_KEY";
-	case WLAN_AUTH_FT:
-		return "FT";
-	}
-
-	return "unknown";
-}
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */
-
-
-/**
- * mlme_authenticate_indication - Report the establishment of an authentication
- * relationship with a specific peer MAC entity
- * @hapd: BSS data
- * @sta: peer STA data
- *
- * MLME calls this function as a result of the establishment of an
- * authentication relationship with a specific peer MAC entity that
- * resulted from an authentication procedure that was initiated by
- * that specific peer MAC entity.
- *
- * PeerSTAAddress = sta->addr
- * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
- */
-void mlme_authenticate_indication(struct hostapd_data *hapd,
-				  struct sta_info *sta)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
-		       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);
-}
-
-
-/**
- * mlme_deauthenticate_indication - Report the invalidation of an
- * authentication relationship with a specific peer MAC entity
- * @hapd: BSS data
- * @sta: Peer STA data
- * @reason_code: ReasonCode from Deauthentication frame
- *
- * MLME calls this function as a result of the invalidation of an
- * authentication relationship with a specific peer MAC entity.
- *
- * PeerSTAAddress = sta->addr
- */
-void mlme_deauthenticate_indication(struct hostapd_data *hapd,
-				    struct sta_info *sta, u16 reason_code)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
-		       MAC2STR(sta->addr), reason_code);
-	mlme_deletekeys_request(hapd, sta);
-}
-
-
-/**
- * mlme_associate_indication - Report the establishment of an association with
- * a specific peer MAC entity
- * @hapd: BSS data
- * @sta: peer STA data
- *
- * MLME calls this function as a result of the establishment of an
- * association with a specific peer MAC entity that resulted from an
- * association procedure that was initiated by that specific peer MAC entity.
- *
- * PeerSTAAddress = sta->addr
- */
-void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-ASSOCIATE.indication(" MACSTR ")",
-		       MAC2STR(sta->addr));
-	if (sta->auth_alg != WLAN_AUTH_FT)
-		mlme_deletekeys_request(hapd, sta);
-}
-
-
-/**
- * mlme_reassociate_indication - Report the establishment of an reassociation
- * with a specific peer MAC entity
- * @hapd: BSS data
- * @sta: peer STA data
- *
- * MLME calls this function as a result of the establishment of an
- * reassociation with a specific peer MAC entity that resulted from a
- * reassociation procedure that was initiated by that specific peer MAC entity.
- *
- * PeerSTAAddress = sta->addr
- *
- * sta->previous_ap contains the "Current AP" information from ReassocReq.
- */
-void mlme_reassociate_indication(struct hostapd_data *hapd,
-				 struct sta_info *sta)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-REASSOCIATE.indication(" MACSTR ")",
-		       MAC2STR(sta->addr));
-	if (sta->auth_alg != WLAN_AUTH_FT)
-		mlme_deletekeys_request(hapd, sta);
-}
-
-
-/**
- * mlme_disassociate_indication - Report disassociation with a specific peer
- * MAC entity
- * @hapd: BSS data
- * @sta: Peer STA data
- * @reason_code: ReasonCode from Disassociation frame
- *
- * MLME calls this function as a result of the invalidation of an association
- * relationship with a specific peer MAC entity.
- *
- * PeerSTAAddress = sta->addr
- */
-void mlme_disassociate_indication(struct hostapd_data *hapd,
-				  struct sta_info *sta, u16 reason_code)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
-		       MAC2STR(sta->addr), reason_code);
-	mlme_deletekeys_request(hapd, sta);
-}
-
-
-void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
-				       const u8 *addr)
-{
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-MichaelMICFailure.indication(" MACSTR ")",
-		       MAC2STR(addr));
-}
-
-
-void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "MLME-DELETEKEYS.request(" MACSTR ")",
-		       MAC2STR(sta->addr));
-
-	if (sta->wpa_sm)
-		wpa_remove_ptk(sta->wpa_sm);
-}

Copied: vendor/wpa/2.0/src/ap/ap_mlme.c (from rev 9639, vendor/wpa/dist/src/ap/ap_mlme.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_mlme.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_mlme.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,178 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003-2006, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, 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 "ieee802_11.h"
+#include "wpa_auth.h"
+#include "sta_info.h"
+#include "ap_mlme.h"
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static const char * mlme_auth_alg_str(int alg)
+{
+	switch (alg) {
+	case WLAN_AUTH_OPEN:
+		return "OPEN_SYSTEM";
+	case WLAN_AUTH_SHARED_KEY:
+		return "SHARED_KEY";
+	case WLAN_AUTH_FT:
+		return "FT";
+	}
+
+	return "unknown";
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+
+/**
+ * mlme_authenticate_indication - Report the establishment of an authentication
+ * relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * authentication relationship with a specific peer MAC entity that
+ * resulted from an authentication procedure that was initiated by
+ * that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
+ */
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
+		       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);
+}
+
+
+/**
+ * mlme_deauthenticate_indication - Report the invalidation of an
+ * authentication relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Deauthentication frame
+ *
+ * MLME calls this function as a result of the invalidation of an
+ * authentication relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_associate_indication - Report the establishment of an association with
+ * a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * association with a specific peer MAC entity that resulted from an
+ * association procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-ASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	if (sta->auth_alg != WLAN_AUTH_FT)
+		mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_reassociate_indication - Report the establishment of an reassociation
+ * with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * reassociation with a specific peer MAC entity that resulted from a
+ * reassociation procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ *
+ * sta->previous_ap contains the "Current AP" information from ReassocReq.
+ */
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-REASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	if (sta->auth_alg != WLAN_AUTH_FT)
+		mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_disassociate_indication - Report disassociation with a specific peer
+ * MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Disassociation frame
+ *
+ * MLME calls this function as a result of the invalidation of an association
+ * relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr)
+{
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-MichaelMICFailure.indication(" MACSTR ")",
+		       MAC2STR(addr));
+}
+
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DELETEKEYS.request(" MACSTR ")",
+		       MAC2STR(sta->addr));
+
+	if (sta->wpa_sm)
+		wpa_remove_ptk(sta->wpa_sm);
+}

Deleted: vendor/wpa/2.0/src/ap/ap_mlme.h
===================================================================
--- vendor/wpa/dist/src/ap/ap_mlme.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ap_mlme.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,40 +0,0 @@
-/*
- * hostapd / IEEE 802.11 MLME
- * Copyright 2003, Jouni Malinen <j at w1.fi>
- * Copyright 2003-2004, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MLME_H
-#define MLME_H
-
-void mlme_authenticate_indication(struct hostapd_data *hapd,
-				  struct sta_info *sta);
-
-void mlme_deauthenticate_indication(struct hostapd_data *hapd,
-				    struct sta_info *sta, u16 reason_code);
-
-void mlme_associate_indication(struct hostapd_data *hapd,
-			       struct sta_info *sta);
-
-void mlme_reassociate_indication(struct hostapd_data *hapd,
-				 struct sta_info *sta);
-
-void mlme_disassociate_indication(struct hostapd_data *hapd,
-				  struct sta_info *sta, u16 reason_code);
-
-void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
-				       const u8 *addr);
-
-void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
-
-#endif /* MLME_H */

Copied: vendor/wpa/2.0/src/ap/ap_mlme.h (from rev 9639, vendor/wpa/dist/src/ap/ap_mlme.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ap_mlme.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ap_mlme.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,34 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MLME_H
+#define MLME_H
+
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta);
+
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code);
+
+void mlme_associate_indication(struct hostapd_data *hapd,
+			       struct sta_info *sta);
+
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta);
+
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code);
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr);
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* MLME_H */

Deleted: vendor/wpa/2.0/src/ap/authsrv.c
===================================================================
--- vendor/wpa/dist/src/ap/authsrv.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/authsrv.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,216 +0,0 @@
-/*
- * Authentication server setup
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "crypto/tls.h"
-#include "eap_server/eap.h"
-#include "eap_server/eap_sim_db.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "radius/radius_server.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "sta_info.h"
-#include "authsrv.h"
-
-
-#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA)
-#define EAP_SIM_DB
-#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */
-
-
-#ifdef EAP_SIM_DB
-static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
-				 struct sta_info *sta, void *ctx)
-{
-	if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0)
-		return 1;
-	return 0;
-}
-
-
-static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
-{
-	struct hostapd_data *hapd = ctx;
-	if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) {
-#ifdef RADIUS_SERVER
-		radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
-#endif /* RADIUS_SERVER */
-	}
-}
-#endif /* EAP_SIM_DB */
-
-
-#ifdef RADIUS_SERVER
-
-static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
-				       size_t identity_len, int phase2,
-				       struct eap_user *user)
-{
-	const struct hostapd_eap_user *eap_user;
-	int i, count;
-
-	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
-	if (eap_user == NULL)
-		return -1;
-
-	if (user == NULL)
-		return 0;
-
-	os_memset(user, 0, sizeof(*user));
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
-		user->methods[i].vendor = eap_user->methods[i].vendor;
-		user->methods[i].method = eap_user->methods[i].method;
-	}
-
-	if (eap_user->password) {
-		user->password = os_malloc(eap_user->password_len);
-		if (user->password == NULL)
-			return -1;
-		os_memcpy(user->password, eap_user->password,
-			  eap_user->password_len);
-		user->password_len = eap_user->password_len;
-		user->password_hash = eap_user->password_hash;
-	}
-	user->force_version = eap_user->force_version;
-	user->ttls_auth = eap_user->ttls_auth;
-
-	return 0;
-}
-
-
-static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
-{
-	struct radius_server_conf srv;
-	struct hostapd_bss_config *conf = hapd->conf;
-	os_memset(&srv, 0, sizeof(srv));
-	srv.client_file = conf->radius_server_clients;
-	srv.auth_port = conf->radius_server_auth_port;
-	srv.conf_ctx = conf;
-	srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
-	srv.ssl_ctx = hapd->ssl_ctx;
-	srv.msg_ctx = hapd->msg_ctx;
-	srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
-	srv.eap_fast_a_id = conf->eap_fast_a_id;
-	srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
-	srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
-	srv.eap_fast_prov = conf->eap_fast_prov;
-	srv.pac_key_lifetime = conf->pac_key_lifetime;
-	srv.pac_key_refresh_time = conf->pac_key_refresh_time;
-	srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
-	srv.tnc = conf->tnc;
-	srv.wps = hapd->wps;
-	srv.ipv6 = conf->radius_server_ipv6;
-	srv.get_eap_user = hostapd_radius_get_eap_user;
-	srv.eap_req_id_text = conf->eap_req_id_text;
-	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
-
-	hapd->radius_srv = radius_server_init(&srv);
-	if (hapd->radius_srv == NULL) {
-		wpa_printf(MSG_ERROR, "RADIUS server initialization failed.");
-		return -1;
-	}
-
-	return 0;
-}
-
-#endif /* RADIUS_SERVER */
-
-
-int authsrv_init(struct hostapd_data *hapd)
-{
-#ifdef EAP_TLS_FUNCS
-	if (hapd->conf->eap_server &&
-	    (hapd->conf->ca_cert || hapd->conf->server_cert ||
-	     hapd->conf->dh_file)) {
-		struct tls_connection_params params;
-
-		hapd->ssl_ctx = tls_init(NULL);
-		if (hapd->ssl_ctx == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
-			authsrv_deinit(hapd);
-			return -1;
-		}
-
-		os_memset(&params, 0, sizeof(params));
-		params.ca_cert = hapd->conf->ca_cert;
-		params.client_cert = hapd->conf->server_cert;
-		params.private_key = hapd->conf->private_key;
-		params.private_key_passwd = hapd->conf->private_key_passwd;
-		params.dh_file = hapd->conf->dh_file;
-
-		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
-			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
-			authsrv_deinit(hapd);
-			return -1;
-		}
-
-		if (tls_global_set_verify(hapd->ssl_ctx,
-					  hapd->conf->check_crl)) {
-			wpa_printf(MSG_ERROR, "Failed to enable check_crl");
-			authsrv_deinit(hapd);
-			return -1;
-		}
-	}
-#endif /* EAP_TLS_FUNCS */
-
-#ifdef EAP_SIM_DB
-	if (hapd->conf->eap_sim_db) {
-		hapd->eap_sim_db_priv =
-			eap_sim_db_init(hapd->conf->eap_sim_db,
-					hostapd_sim_db_cb, hapd);
-		if (hapd->eap_sim_db_priv == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
-				   "database interface");
-			authsrv_deinit(hapd);
-			return -1;
-		}
-	}
-#endif /* EAP_SIM_DB */
-
-#ifdef RADIUS_SERVER
-	if (hapd->conf->radius_server_clients &&
-	    hostapd_setup_radius_srv(hapd))
-		return -1;
-#endif /* RADIUS_SERVER */
-
-	return 0;
-}
-
-
-void authsrv_deinit(struct hostapd_data *hapd)
-{
-#ifdef RADIUS_SERVER
-	radius_server_deinit(hapd->radius_srv);
-	hapd->radius_srv = NULL;
-#endif /* RADIUS_SERVER */
-
-#ifdef EAP_TLS_FUNCS
-	if (hapd->ssl_ctx) {
-		tls_deinit(hapd->ssl_ctx);
-		hapd->ssl_ctx = NULL;
-	}
-#endif /* EAP_TLS_FUNCS */
-
-#ifdef EAP_SIM_DB
-	if (hapd->eap_sim_db_priv) {
-		eap_sim_db_deinit(hapd->eap_sim_db_priv);
-		hapd->eap_sim_db_priv = NULL;
-	}
-#endif /* EAP_SIM_DB */
-}

Copied: vendor/wpa/2.0/src/ap/authsrv.c (from rev 9639, vendor/wpa/dist/src/ap/authsrv.c)
===================================================================
--- vendor/wpa/2.0/src/ap/authsrv.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/authsrv.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,211 @@
+/*
+ * Authentication server setup
+ * Copyright (c) 2002-2009, Jouni Malinen <j at 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 "crypto/tls.h"
+#include "eap_server/eap.h"
+#include "eap_server/eap_sim_db.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "radius/radius_server.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "authsrv.h"
+
+
+#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA)
+#define EAP_SIM_DB
+#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */
+
+
+#ifdef EAP_SIM_DB
+static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
+				 struct sta_info *sta, void *ctx)
+{
+	if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0)
+		return 1;
+	return 0;
+}
+
+
+static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) {
+#ifdef RADIUS_SERVER
+		radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
+#endif /* RADIUS_SERVER */
+	}
+}
+#endif /* EAP_SIM_DB */
+
+
+#ifdef RADIUS_SERVER
+
+static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
+				       size_t identity_len, int phase2,
+				       struct eap_user *user)
+{
+	const struct hostapd_eap_user *eap_user;
+	int i;
+
+	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
+	if (eap_user == NULL)
+		return -1;
+
+	if (user == NULL)
+		return 0;
+
+	os_memset(user, 0, sizeof(*user));
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
+
+	if (eap_user->password) {
+		user->password = os_malloc(eap_user->password_len);
+		if (user->password == NULL)
+			return -1;
+		os_memcpy(user->password, eap_user->password,
+			  eap_user->password_len);
+		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
+	}
+	user->force_version = eap_user->force_version;
+	user->ttls_auth = eap_user->ttls_auth;
+
+	return 0;
+}
+
+
+static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
+{
+	struct radius_server_conf srv;
+	struct hostapd_bss_config *conf = hapd->conf;
+	os_memset(&srv, 0, sizeof(srv));
+	srv.client_file = conf->radius_server_clients;
+	srv.auth_port = conf->radius_server_auth_port;
+	srv.conf_ctx = hapd;
+	srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
+	srv.ssl_ctx = hapd->ssl_ctx;
+	srv.msg_ctx = hapd->msg_ctx;
+	srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
+	srv.eap_fast_a_id = conf->eap_fast_a_id;
+	srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
+	srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
+	srv.eap_fast_prov = conf->eap_fast_prov;
+	srv.pac_key_lifetime = conf->pac_key_lifetime;
+	srv.pac_key_refresh_time = conf->pac_key_refresh_time;
+	srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	srv.tnc = conf->tnc;
+	srv.wps = hapd->wps;
+	srv.ipv6 = conf->radius_server_ipv6;
+	srv.get_eap_user = hostapd_radius_get_eap_user;
+	srv.eap_req_id_text = conf->eap_req_id_text;
+	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
+	srv.pwd_group = conf->pwd_group;
+#ifdef CONFIG_RADIUS_TEST
+	srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+
+	hapd->radius_srv = radius_server_init(&srv);
+	if (hapd->radius_srv == NULL) {
+		wpa_printf(MSG_ERROR, "RADIUS server initialization failed.");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* RADIUS_SERVER */
+
+
+int authsrv_init(struct hostapd_data *hapd)
+{
+#ifdef EAP_TLS_FUNCS
+	if (hapd->conf->eap_server &&
+	    (hapd->conf->ca_cert || hapd->conf->server_cert ||
+	     hapd->conf->dh_file)) {
+		struct tls_connection_params params;
+
+		hapd->ssl_ctx = tls_init(NULL);
+		if (hapd->ssl_ctx == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+
+		os_memset(&params, 0, sizeof(params));
+		params.ca_cert = hapd->conf->ca_cert;
+		params.client_cert = hapd->conf->server_cert;
+		params.private_key = hapd->conf->private_key;
+		params.private_key_passwd = hapd->conf->private_key_passwd;
+		params.dh_file = hapd->conf->dh_file;
+
+		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
+			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+
+		if (tls_global_set_verify(hapd->ssl_ctx,
+					  hapd->conf->check_crl)) {
+			wpa_printf(MSG_ERROR, "Failed to enable check_crl");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+	}
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SIM_DB
+	if (hapd->conf->eap_sim_db) {
+		hapd->eap_sim_db_priv =
+			eap_sim_db_init(hapd->conf->eap_sim_db,
+					hostapd_sim_db_cb, hapd);
+		if (hapd->eap_sim_db_priv == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
+				   "database interface");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+	}
+#endif /* EAP_SIM_DB */
+
+#ifdef RADIUS_SERVER
+	if (hapd->conf->radius_server_clients &&
+	    hostapd_setup_radius_srv(hapd))
+		return -1;
+#endif /* RADIUS_SERVER */
+
+	return 0;
+}
+
+
+void authsrv_deinit(struct hostapd_data *hapd)
+{
+#ifdef RADIUS_SERVER
+	radius_server_deinit(hapd->radius_srv);
+	hapd->radius_srv = NULL;
+#endif /* RADIUS_SERVER */
+
+#ifdef EAP_TLS_FUNCS
+	if (hapd->ssl_ctx) {
+		tls_deinit(hapd->ssl_ctx);
+		hapd->ssl_ctx = NULL;
+	}
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SIM_DB
+	if (hapd->eap_sim_db_priv) {
+		eap_sim_db_deinit(hapd->eap_sim_db_priv);
+		hapd->eap_sim_db_priv = NULL;
+	}
+#endif /* EAP_SIM_DB */
+}

Deleted: vendor/wpa/2.0/src/ap/authsrv.h
===================================================================
--- vendor/wpa/dist/src/ap/authsrv.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/authsrv.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,21 +0,0 @@
-/*
- * Authentication server setup
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AUTHSRV_H
-#define AUTHSRV_H
-
-int authsrv_init(struct hostapd_data *hapd);
-void authsrv_deinit(struct hostapd_data *hapd);
-
-#endif /* AUTHSRV_H */

Copied: vendor/wpa/2.0/src/ap/authsrv.h (from rev 9639, vendor/wpa/dist/src/ap/authsrv.h)
===================================================================
--- vendor/wpa/2.0/src/ap/authsrv.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/authsrv.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,15 @@
+/*
+ * Authentication server setup
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTHSRV_H
+#define AUTHSRV_H
+
+int authsrv_init(struct hostapd_data *hapd);
+void authsrv_deinit(struct hostapd_data *hapd);
+
+#endif /* AUTHSRV_H */

Deleted: vendor/wpa/2.0/src/ap/beacon.c
===================================================================
--- vendor/wpa/dist/src/ap/beacon.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/beacon.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,456 +0,0 @@
-/*
- * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
- * Copyright (c) 2002-2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "ieee802_11.h"
-#include "wpa_auth.h"
-#include "wmm.h"
-#include "ap_config.h"
-#include "sta_info.h"
-#include "beacon.h"
-
-
-static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
-{
-	u8 erp = 0;
-
-	if (hapd->iface->current_mode == NULL ||
-	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
-		return 0;
-
-	switch (hapd->iconf->cts_protection_type) {
-	case CTS_PROTECTION_FORCE_ENABLED:
-		erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
-		break;
-	case CTS_PROTECTION_FORCE_DISABLED:
-		erp = 0;
-		break;
-	case CTS_PROTECTION_AUTOMATIC:
-		if (hapd->iface->olbc)
-			erp |= ERP_INFO_USE_PROTECTION;
-		/* continue */
-	case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
-		if (hapd->iface->num_sta_non_erp > 0) {
-			erp |= ERP_INFO_NON_ERP_PRESENT |
-				ERP_INFO_USE_PROTECTION;
-		}
-		break;
-	}
-	if (hapd->iface->num_sta_no_short_preamble > 0 ||
-	    hapd->iconf->preamble == LONG_PREAMBLE)
-		erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
-
-	return erp;
-}
-
-
-static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
-{
-	*eid++ = WLAN_EID_DS_PARAMS;
-	*eid++ = 1;
-	*eid++ = hapd->iconf->channel;
-	return eid;
-}
-
-
-static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
-{
-	if (hapd->iface->current_mode == NULL ||
-	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
-		return eid;
-
-	/* Set NonERP_present and use_protection bits if there
-	 * are any associated NonERP stations. */
-	/* TODO: use_protection bit can be set to zero even if
-	 * there are NonERP stations present. This optimization
-	 * might be useful if NonERP stations are "quiet".
-	 * See 802.11g/D6 E-1 for recommended practice.
-	 * In addition, Non ERP present might be set, if AP detects Non ERP
-	 * operation on other APs. */
-
-	/* Add ERP Information element */
-	*eid++ = WLAN_EID_ERP_INFO;
-	*eid++ = 1;
-	*eid++ = ieee802_11_erp_info(hapd);
-
-	return eid;
-}
-
-
-static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
-				    struct hostapd_channel_data *start,
-				    struct hostapd_channel_data *prev)
-{
-	if (end - pos < 3)
-		return pos;
-
-	/* first channel number */
-	*pos++ = start->chan;
-	/* number of channels */
-	*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
-	/* maximum transmit power level */
-	*pos++ = start->max_tx_power;
-
-	return pos;
-}
-
-
-static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
-				int max_len)
-{
-	u8 *pos = eid;
-	u8 *end = eid + max_len;
-	int i;
-	struct hostapd_hw_modes *mode;
-	struct hostapd_channel_data *start, *prev;
-	int chan_spacing = 1;
-
-	if (!hapd->iconf->ieee80211d || max_len < 6 ||
-	    hapd->iface->current_mode == NULL)
-		return eid;
-
-	*pos++ = WLAN_EID_COUNTRY;
-	pos++; /* length will be set later */
-	os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
-	pos += 3;
-
-	mode = hapd->iface->current_mode;
-	if (mode->mode == HOSTAPD_MODE_IEEE80211A)
-		chan_spacing = 4;
-
-	start = prev = NULL;
-	for (i = 0; i < mode->num_channels; i++) {
-		struct hostapd_channel_data *chan = &mode->channels[i];
-		if (chan->flag & HOSTAPD_CHAN_DISABLED)
-			continue;
-		if (start && prev &&
-		    prev->chan + chan_spacing == chan->chan &&
-		    start->max_tx_power == chan->max_tx_power) {
-			prev = chan;
-			continue; /* can use same entry */
-		}
-
-		if (start) {
-			pos = hostapd_eid_country_add(pos, end, chan_spacing,
-						      start, prev);
-			start = NULL;
-		}
-
-		/* Start new group */
-		start = prev = chan;
-	}
-
-	if (start) {
-		pos = hostapd_eid_country_add(pos, end, chan_spacing,
-					      start, prev);
-	}
-
-	if ((pos - eid) & 1) {
-		if (end - pos < 1)
-			return eid;
-		*pos++ = 0; /* pad for 16-bit alignment */
-	}
-
-	eid[1] = (pos - eid) - 2;
-
-	return pos;
-}
-
-
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
-			    struct sta_info *sta)
-{
-	const u8 *ie;
-	size_t ielen;
-
-	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
-	if (ie == NULL || ielen > len)
-		return eid;
-
-	os_memcpy(eid, ie, ielen);
-	return eid + ielen;
-}
-
-
-void handle_probe_req(struct hostapd_data *hapd,
-		      const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	struct ieee80211_mgmt *resp;
-	struct ieee802_11_elems elems;
-	char *ssid;
-	u8 *pos, *epos;
-	const u8 *ie;
-	size_t ssid_len, ie_len;
-	struct sta_info *sta = NULL;
-	size_t buflen;
-	size_t i;
-
-	ie = mgmt->u.probe_req.variable;
-	ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-
-	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
-		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    mgmt->sa, ie, ie_len) > 0)
-			return;
-
-	if (!hapd->iconf->send_probe_response)
-		return;
-
-	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
-			   MAC2STR(mgmt->sa));
-		return;
-	}
-
-	ssid = NULL;
-	ssid_len = 0;
-
-	if ((!elems.ssid || !elems.supp_rates)) {
-		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
-			   "without SSID or supported rates element",
-			   MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
-		wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
-			   "broadcast SSID ignored", MAC2STR(mgmt->sa));
-		return;
-	}
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-
-	if (elems.ssid_len == 0 ||
-	    (elems.ssid_len == hapd->conf->ssid.ssid_len &&
-	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
-	     0)) {
-		ssid = hapd->conf->ssid.ssid;
-		ssid_len = hapd->conf->ssid.ssid_len;
-		if (sta)
-			sta->ssid_probe = &hapd->conf->ssid;
-	}
-
-	if (!ssid) {
-		if (!(mgmt->da[0] & 0x01)) {
-			char ssid_txt[33];
-			ieee802_11_print_ssid(ssid_txt, elems.ssid,
-					      elems.ssid_len);
-			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
-				   " for foreign SSID '%s'",
-				   MAC2STR(mgmt->sa), ssid_txt);
-		}
-		return;
-	}
-
-	/* TODO: verify that supp_rates contains at least one matching rate
-	 * with AP configuration */
-#define MAX_PROBERESP_LEN 768
-	buflen = MAX_PROBERESP_LEN;
-#ifdef CONFIG_WPS
-	if (hapd->wps_probe_resp_ie)
-		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
-#endif /* CONFIG_WPS */
-	resp = os_zalloc(buflen);
-	if (resp == NULL)
-		return;
-	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
-
-	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_PROBE_RESP);
-	os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
-
-	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
-	resp->u.probe_resp.beacon_int =
-		host_to_le16(hapd->iconf->beacon_int);
-
-	/* hardware or low-level driver will setup seq_ctrl and timestamp */
-	resp->u.probe_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
-
-	pos = resp->u.probe_resp.variable;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-	pos += ssid_len;
-
-	/* Supported rates */
-	pos = hostapd_eid_supp_rates(hapd, pos);
-
-	/* DS Params */
-	pos = hostapd_eid_ds_params(hapd, pos);
-
-	pos = hostapd_eid_country(hapd, pos, epos - pos);
-
-	/* ERP Information element */
-	pos = hostapd_eid_erp_info(hapd, pos);
-
-	/* Extended supported rates */
-	pos = hostapd_eid_ext_supp_rates(hapd, pos);
-
-	/* RSN, MDIE, WPA */
-	pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
-
-#ifdef CONFIG_IEEE80211N
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
-
-	/* Wi-Fi Alliance WMM */
-	pos = hostapd_eid_wmm(hapd, pos);
-
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
-		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
-			  wpabuf_len(hapd->wps_probe_resp_ie));
-		pos += wpabuf_len(hapd->wps_probe_resp_ie);
-	}
-#endif /* CONFIG_WPS */
-
-	if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0)
-		perror("handle_probe_req: send");
-
-	os_free(resp);
-
-	wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
-		   "SSID", MAC2STR(mgmt->sa),
-		   elems.ssid_len == 0 ? "broadcast" : "our");
-}
-
-
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-	struct ieee80211_mgmt *head;
-	u8 *pos, *tail, *tailpos;
-	u16 capab_info;
-	size_t head_len, tail_len;
-
-#define BEACON_HEAD_BUF_SIZE 256
-#define BEACON_TAIL_BUF_SIZE 512
-	head = os_zalloc(BEACON_HEAD_BUF_SIZE);
-	tail_len = BEACON_TAIL_BUF_SIZE;
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->wps_beacon_ie)
-		tail_len += wpabuf_len(hapd->wps_beacon_ie);
-#endif /* CONFIG_WPS */
-	tailpos = tail = os_malloc(tail_len);
-	if (head == NULL || tail == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to set beacon data");
-		os_free(head);
-		os_free(tail);
-		return;
-	}
-
-	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_BEACON);
-	head->duration = host_to_le16(0);
-	os_memset(head->da, 0xff, ETH_ALEN);
-
-	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
-	head->u.beacon.beacon_int =
-		host_to_le16(hapd->iconf->beacon_int);
-
-	/* hardware or low-level driver will setup seq_ctrl and timestamp */
-	capab_info = hostapd_own_capab_info(hapd, NULL, 0);
-	head->u.beacon.capab_info = host_to_le16(capab_info);
-	pos = &head->u.beacon.variable[0];
-
-	/* SSID */
-	*pos++ = WLAN_EID_SSID;
-	if (hapd->conf->ignore_broadcast_ssid == 2) {
-		/* clear the data, but keep the correct length of the SSID */
-		*pos++ = hapd->conf->ssid.ssid_len;
-		os_memset(pos, 0, hapd->conf->ssid.ssid_len);
-		pos += hapd->conf->ssid.ssid_len;
-	} else if (hapd->conf->ignore_broadcast_ssid) {
-		*pos++ = 0; /* empty SSID */
-	} else {
-		*pos++ = hapd->conf->ssid.ssid_len;
-		os_memcpy(pos, hapd->conf->ssid.ssid,
-			  hapd->conf->ssid.ssid_len);
-		pos += hapd->conf->ssid.ssid_len;
-	}
-
-	/* Supported rates */
-	pos = hostapd_eid_supp_rates(hapd, pos);
-
-	/* DS Params */
-	pos = hostapd_eid_ds_params(hapd, pos);
-
-	head_len = pos - (u8 *) head;
-
-	tailpos = hostapd_eid_country(hapd, tailpos,
-				      tail + BEACON_TAIL_BUF_SIZE - tailpos);
-
-	/* ERP Information element */
-	tailpos = hostapd_eid_erp_info(hapd, tailpos);
-
-	/* Extended supported rates */
-	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
-
-	/* RSN, MDIE, WPA */
-	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-				  tailpos, NULL);
-
-#ifdef CONFIG_IEEE80211N
-	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
-	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
-
-	/* Wi-Fi Alliance WMM */
-	tailpos = hostapd_eid_wmm(hapd, tailpos);
-
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
-		os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
-			  wpabuf_len(hapd->wps_beacon_ie));
-		tailpos += wpabuf_len(hapd->wps_beacon_ie);
-	}
-#endif /* CONFIG_WPS */
-
-	tail_len = tailpos > tail ? tailpos - tail : 0;
-
-	if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len,
-				 tail, tail_len, hapd->conf->dtim_period,
-				 hapd->iconf->beacon_int))
-		wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
-			   "period");
-
-	os_free(tail);
-	os_free(head);
-
-	hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
-					  ERP_INFO_USE_PROTECTION));
-}
-
-
-void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-	size_t i;
-	for (i = 0; i < iface->num_bss; i++)
-		ieee802_11_set_beacon(iface->bss[i]);
-}
-
-#endif /* CONFIG_NATIVE_WINDOWS */

Copied: vendor/wpa/2.0/src/ap/beacon.c (from rev 9639, vendor/wpa/dist/src/ap/beacon.c)
===================================================================
--- vendor/wpa/2.0/src/ap/beacon.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/beacon.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,795 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "wps/wps_defs.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "wmm.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "hs20.h"
+
+
+#ifdef NEED_AP_MLME
+
+static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
+{
+	u8 erp = 0;
+
+	if (hapd->iface->current_mode == NULL ||
+	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return 0;
+
+	if (hapd->iface->olbc)
+		erp |= ERP_INFO_USE_PROTECTION;
+	if (hapd->iface->num_sta_non_erp > 0) {
+		erp |= ERP_INFO_NON_ERP_PRESENT |
+			ERP_INFO_USE_PROTECTION;
+	}
+	if (hapd->iface->num_sta_no_short_preamble > 0 ||
+	    hapd->iconf->preamble == LONG_PREAMBLE)
+		erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
+
+	return erp;
+}
+
+
+static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
+{
+	*eid++ = WLAN_EID_DS_PARAMS;
+	*eid++ = 1;
+	*eid++ = hapd->iconf->channel;
+	return eid;
+}
+
+
+static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->iface->current_mode == NULL ||
+	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return eid;
+
+	/* Set NonERP_present and use_protection bits if there
+	 * are any associated NonERP stations. */
+	/* TODO: use_protection bit can be set to zero even if
+	 * there are NonERP stations present. This optimization
+	 * might be useful if NonERP stations are "quiet".
+	 * See 802.11g/D6 E-1 for recommended practice.
+	 * In addition, Non ERP present might be set, if AP detects Non ERP
+	 * operation on other APs. */
+
+	/* Add ERP Information element */
+	*eid++ = WLAN_EID_ERP_INFO;
+	*eid++ = 1;
+	*eid++ = ieee802_11_erp_info(hapd);
+
+	return eid;
+}
+
+
+static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
+				    struct hostapd_channel_data *start,
+				    struct hostapd_channel_data *prev)
+{
+	if (end - pos < 3)
+		return pos;
+
+	/* first channel number */
+	*pos++ = start->chan;
+	/* number of channels */
+	*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
+	/* maximum transmit power level */
+	*pos++ = start->max_tx_power;
+
+	return pos;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+				int max_len)
+{
+	u8 *pos = eid;
+	u8 *end = eid + max_len;
+	int i;
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *start, *prev;
+	int chan_spacing = 1;
+
+	if (!hapd->iconf->ieee80211d || max_len < 6 ||
+	    hapd->iface->current_mode == NULL)
+		return eid;
+
+	*pos++ = WLAN_EID_COUNTRY;
+	pos++; /* length will be set later */
+	os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+	pos += 3;
+
+	mode = hapd->iface->current_mode;
+	if (mode->mode == HOSTAPD_MODE_IEEE80211A)
+		chan_spacing = 4;
+
+	start = prev = NULL;
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (start && prev &&
+		    prev->chan + chan_spacing == chan->chan &&
+		    start->max_tx_power == chan->max_tx_power) {
+			prev = chan;
+			continue; /* can use same entry */
+		}
+
+		if (start) {
+			pos = hostapd_eid_country_add(pos, end, chan_spacing,
+						      start, prev);
+			start = NULL;
+		}
+
+		/* Start new group */
+		start = prev = chan;
+	}
+
+	if (start) {
+		pos = hostapd_eid_country_add(pos, end, chan_spacing,
+					      start, prev);
+	}
+
+	if ((pos - eid) & 1) {
+		if (end - pos < 1)
+			return eid;
+		*pos++ = 0; /* pad for 16-bit alignment */
+	}
+
+	eid[1] = (pos - eid) - 2;
+
+	return pos;
+}
+
+
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+	const u8 *ie;
+	size_t ielen;
+
+	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+	if (ie == NULL || ielen > len)
+		return eid;
+
+	os_memcpy(eid, ie, ielen);
+	return eid + ielen;
+}
+
+
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+				   struct sta_info *sta,
+				   const struct ieee80211_mgmt *req,
+				   int is_p2p, size_t *resp_len)
+{
+	struct ieee80211_mgmt *resp;
+	u8 *pos, *epos;
+	size_t buflen;
+
+#define MAX_PROBERESP_LEN 768
+	buflen = MAX_PROBERESP_LEN;
+#ifdef CONFIG_WPS
+	if (hapd->wps_probe_resp_ie)
+		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_probe_resp_ie)
+		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
+	if (hapd->conf->vendor_elements)
+		buflen += wpabuf_len(hapd->conf->vendor_elements);
+	resp = os_zalloc(buflen);
+	if (resp == NULL)
+		return NULL;
+
+	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_PROBE_RESP);
+	if (req)
+		os_memcpy(resp->da, req->sa, ETH_ALEN);
+	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+	resp->u.probe_resp.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	resp->u.probe_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+	pos = resp->u.probe_resp.variable;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = hapd->conf->ssid.ssid_len;
+	os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+	pos += hapd->conf->ssid.ssid_len;
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+	/* ERP Information element */
+	pos = hostapd_eid_erp_info(hapd, pos);
+
+	/* Extended supported rates */
+	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+	/* RSN, MDIE, WPA */
+	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211N
+	pos = hostapd_eid_ht_capabilities(hapd, pos);
+	pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+	pos = hostapd_eid_ext_capab(hapd, pos);
+
+	pos = hostapd_eid_time_adv(hapd, pos);
+	pos = hostapd_eid_time_zone(hapd, pos);
+
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+
+#ifdef CONFIG_IEEE80211AC
+	pos = hostapd_eid_vht_capabilities(hapd, pos);
+	pos = hostapd_eid_vht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211AC */
+
+	/* Wi-Fi Alliance WMM */
+	pos = hostapd_eid_wmm(hapd, pos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
+			  wpabuf_len(hapd->wps_probe_resp_ie));
+		pos += wpabuf_len(hapd->wps_probe_resp_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+	    hapd->p2p_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+			  wpabuf_len(hapd->p2p_probe_resp_ie));
+		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_HS20
+	pos = hostapd_eid_hs20_indication(hapd, pos);
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->vendor_elements) {
+		os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
+			  wpabuf_len(hapd->conf->vendor_elements));
+		pos += wpabuf_len(hapd->conf->vendor_elements);
+	}
+
+	*resp_len = pos - (u8 *) resp;
+	return (u8 *) resp;
+}
+
+
+enum ssid_match_result {
+	NO_SSID_MATCH,
+	EXACT_SSID_MATCH,
+	WILDCARD_SSID_MATCH
+};
+
+static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
+					 const u8 *ssid, size_t ssid_len,
+					 const u8 *ssid_list,
+					 size_t ssid_list_len)
+{
+	const u8 *pos, *end;
+	int wildcard = 0;
+
+	if (ssid_len == 0)
+		wildcard = 1;
+	if (ssid_len == hapd->conf->ssid.ssid_len &&
+	    os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
+		return EXACT_SSID_MATCH;
+
+	if (ssid_list == NULL)
+		return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+
+	pos = ssid_list;
+	end = ssid_list + ssid_list_len;
+	while (pos + 1 <= end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[1] == 0)
+			wildcard = 1;
+		if (pos[1] == hapd->conf->ssid.ssid_len &&
+		    os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
+			return EXACT_SSID_MATCH;
+		pos += 2 + pos[1];
+	}
+
+	return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd,
+		      const struct ieee80211_mgmt *mgmt, size_t len,
+		      int ssi_signal)
+{
+	u8 *resp;
+	struct ieee802_11_elems elems;
+	const u8 *ie;
+	size_t ie_len;
+	struct sta_info *sta = NULL;
+	size_t i, resp_len;
+	int noack;
+	enum ssid_match_result res;
+
+	ie = mgmt->u.probe_req.variable;
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+		return;
+	ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
+		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
+					    mgmt->sa, mgmt->da, mgmt->bssid,
+					    ie, ie_len, ssi_signal) > 0)
+			return;
+
+	if (!hapd->iconf->send_probe_response)
+		return;
+
+	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+
+	if ((!elems.ssid || !elems.supp_rates)) {
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
+			   "without SSID or supported rates element",
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p && 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)) {
+			wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
+				   "due to mismatch with Requested Device "
+				   "Type");
+			wpabuf_free(wps);
+			return;
+		}
+		wpabuf_free(wps);
+	}
+
+	if (hapd->p2p && 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)) {
+			wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
+				   "due to mismatch with Device ID");
+			wpabuf_free(p2p);
+			return;
+		}
+		wpabuf_free(p2p);
+	}
+#endif /* CONFIG_P2P */
+
+	if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
+	    elems.ssid_list_len == 0) {
+		wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+			   "broadcast SSID ignored", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	    elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+		      P2P_WILDCARD_SSID_LEN) == 0) {
+		/* Process P2P Wildcard SSID like Wildcard SSID */
+		elems.ssid_len = 0;
+	}
+#endif /* CONFIG_P2P */
+
+	res = ssid_match(hapd, elems.ssid, elems.ssid_len,
+			 elems.ssid_list, elems.ssid_list_len);
+	if (res != NO_SSID_MATCH) {
+		if (sta)
+			sta->ssid_probe = &hapd->conf->ssid;
+	} else {
+		if (!(mgmt->da[0] & 0x01)) {
+			char ssid_txt[33];
+			ieee802_11_print_ssid(ssid_txt, elems.ssid,
+					      elems.ssid_len);
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for foreign SSID '%s' (DA " MACSTR ")%s",
+				   MAC2STR(mgmt->sa), ssid_txt,
+				   MAC2STR(mgmt->da),
+				   elems.ssid_list ? " (SSID list)" : "");
+		}
+		return;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	if (elems.interworking && elems.interworking_len >= 1) {
+		u8 ant = elems.interworking[0] & 0x0f;
+		if (ant != INTERWORKING_ANT_WILDCARD &&
+		    ant != hapd->conf->access_network_type) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching ANT %u ignored",
+				   MAC2STR(mgmt->sa), ant);
+			return;
+		}
+	}
+
+	if (elems.interworking &&
+	    (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+		const u8 *hessid;
+		if (elems.interworking_len == 7)
+			hessid = elems.interworking + 1;
+		else
+			hessid = elems.interworking + 1 + 2;
+		if (!is_broadcast_ether_addr(hessid) &&
+		    os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching HESSID " MACSTR
+				   " ignored",
+				   MAC2STR(mgmt->sa), MAC2STR(hessid));
+			return;
+		}
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	/* TODO: verify that supp_rates contains at least one matching rate
+	 * with AP configuration */
+
+	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+				      &resp_len);
+	if (resp == NULL)
+		return;
+
+	/*
+	 * If this is a broadcast probe request, apply no ack policy to avoid
+	 * excessive retries.
+	 */
+	noack = !!(res == WILDCARD_SSID_MATCH &&
+		   is_broadcast_ether_addr(mgmt->da));
+
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+		perror("handle_probe_req: send");
+
+	os_free(resp);
+
+	wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
+		   "SSID", MAC2STR(mgmt->sa),
+		   elems.ssid_len == 0 ? "broadcast" : "our");
+}
+
+
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+					size_t *resp_len)
+{
+	/* check probe response offloading caps and print warnings */
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+		return NULL;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+	    (!(hapd->iface->probe_resp_offloads &
+	       (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+		WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+		wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+			   "Probe Response while not supporting this");
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+		wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+			   "Probe Response while not supporting this");
+#endif  /* CONFIG_P2P */
+
+	if (hapd->conf->interworking &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+		wpa_printf(MSG_WARNING, "Device is trying to offload "
+			   "Interworking Probe Response while not supporting "
+			   "this");
+
+	/* Generate a Probe Response template for the non-P2P case */
+	return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *head = NULL;
+	u8 *tail = NULL;
+	size_t head_len = 0, tail_len = 0;
+	u8 *resp = NULL;
+	size_t resp_len = 0;
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
+	u16 capab_info;
+	u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
+
+	hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
+
+#define BEACON_HEAD_BUF_SIZE 256
+#define BEACON_TAIL_BUF_SIZE 512
+	head = os_zalloc(BEACON_HEAD_BUF_SIZE);
+	tail_len = BEACON_TAIL_BUF_SIZE;
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_beacon_ie)
+		tail_len += wpabuf_len(hapd->wps_beacon_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_beacon_ie)
+		tail_len += wpabuf_len(hapd->p2p_beacon_ie);
+#endif /* CONFIG_P2P */
+	if (hapd->conf->vendor_elements)
+		tail_len += wpabuf_len(hapd->conf->vendor_elements);
+	tailpos = tail = os_malloc(tail_len);
+	if (head == NULL || tail == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to set beacon data");
+		os_free(head);
+		os_free(tail);
+		return;
+	}
+
+	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_BEACON);
+	head->duration = host_to_le16(0);
+	os_memset(head->da, 0xff, ETH_ALEN);
+
+	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+	head->u.beacon.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+	head->u.beacon.capab_info = host_to_le16(capab_info);
+	pos = &head->u.beacon.variable[0];
+
+	/* SSID */
+	*pos++ = WLAN_EID_SSID;
+	if (hapd->conf->ignore_broadcast_ssid == 2) {
+		/* clear the data, but keep the correct length of the SSID */
+		*pos++ = hapd->conf->ssid.ssid_len;
+		os_memset(pos, 0, hapd->conf->ssid.ssid_len);
+		pos += hapd->conf->ssid.ssid_len;
+	} else if (hapd->conf->ignore_broadcast_ssid) {
+		*pos++ = 0; /* empty SSID */
+	} else {
+		*pos++ = hapd->conf->ssid.ssid_len;
+		os_memcpy(pos, hapd->conf->ssid.ssid,
+			  hapd->conf->ssid.ssid_len);
+		pos += hapd->conf->ssid.ssid_len;
+	}
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	head_len = pos - (u8 *) head;
+
+	tailpos = hostapd_eid_country(hapd, tailpos,
+				      tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
+	/* ERP Information element */
+	tailpos = hostapd_eid_erp_info(hapd, tailpos);
+
+	/* Extended supported rates */
+	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
+
+	/* RSN, MDIE, WPA */
+	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
+				  tailpos);
+
+#ifdef CONFIG_IEEE80211N
+	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
+	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211N */
+
+	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+
+	/*
+	 * TODO: Time Advertisement element should only be included in some
+	 * DTIM Beacon frames.
+	 */
+	tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+	tailpos = hostapd_eid_interworking(hapd, tailpos);
+	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
+#ifdef CONFIG_IEEE80211AC
+	tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+	tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AC */
+
+	/* Wi-Fi Alliance WMM */
+	tailpos = hostapd_eid_wmm(hapd, tailpos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
+		os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
+			  wpabuf_len(hapd->wps_beacon_ie));
+		tailpos += wpabuf_len(hapd->wps_beacon_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
+		os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
+			  wpabuf_len(hapd->p2p_beacon_ie));
+		tailpos += wpabuf_len(hapd->p2p_beacon_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_HS20
+	tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->vendor_elements) {
+		os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
+			  wpabuf_len(hapd->conf->vendor_elements));
+		tailpos += wpabuf_len(hapd->conf->vendor_elements);
+	}
+
+	tail_len = tailpos > tail ? tailpos - tail : 0;
+
+	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+	os_memset(&params, 0, sizeof(params));
+	params.head = (u8 *) head;
+	params.head_len = head_len;
+	params.tail = tail;
+	params.tail_len = tail_len;
+	params.proberesp = resp;
+	params.proberesp_len = resp_len;
+	params.dtim_period = hapd->conf->dtim_period;
+	params.beacon_int = hapd->iconf->beacon_int;
+	params.basic_rates = hapd->iface->basic_rates;
+	params.ssid = hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+	params.group_cipher = hapd->conf->wpa_group;
+	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params.auth_algs = hapd->conf->auth_algs;
+	params.wpa_version = hapd->conf->wpa;
+	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+		(hapd->conf->ieee802_1x &&
+		 (hapd->conf->default_wep_key_len ||
+		  hapd->conf->individual_wep_key_len));
+	switch (hapd->conf->ignore_broadcast_ssid) {
+	case 0:
+		params.hide_ssid = NO_SSID_HIDING;
+		break;
+	case 1:
+		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		break;
+	case 2:
+		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		break;
+	}
+	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+	params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+				ERP_INFO_USE_PROTECTION);
+	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+		hapd->iconf->preamble == SHORT_PREAMBLE;
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		params.short_slot_time =
+			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+	else
+		params.short_slot_time = -1;
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		params.ht_opmode = -1;
+	else
+		params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+	params.interworking = hapd->conf->interworking;
+	if (hapd->conf->interworking &&
+	    !is_zero_ether_addr(hapd->conf->hessid))
+		params.hessid = hapd->conf->hessid;
+	params.access_network_type = hapd->conf->access_network_type;
+	params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_HS20
+	params.disable_dgaf = hapd->conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
+	if (hostapd_drv_set_ap(hapd, &params))
+		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+
+	os_free(tail);
+	os_free(head);
+	os_free(resp);
+}
+
+
+void ieee802_11_set_beacons(struct hostapd_iface *iface)
+{
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++)
+		ieee802_11_set_beacon(iface->bss[i]);
+}
+
+
+/* only update beacons if started */
+void ieee802_11_update_beacons(struct hostapd_iface *iface)
+{
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++)
+		if (iface->bss[i]->beacon_set_done)
+			ieee802_11_set_beacon(iface->bss[i]);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */

Deleted: vendor/wpa/2.0/src/ap/beacon.h
===================================================================
--- vendor/wpa/dist/src/ap/beacon.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/beacon.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,36 +0,0 @@
-/*
- * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
- * Copyright (c) 2002-2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BEACON_H
-#define BEACON_H
-
-struct ieee80211_mgmt;
-
-void handle_probe_req(struct hostapd_data *hapd,
-		      const struct ieee80211_mgmt *mgmt, size_t len);
-#ifdef NEED_AP_MLME
-void ieee802_11_set_beacon(struct hostapd_data *hapd);
-void ieee802_11_set_beacons(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-}
-
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
-
-#endif /* BEACON_H */

Copied: vendor/wpa/2.0/src/ap/beacon.h (from rev 9639, vendor/wpa/dist/src/ap/beacon.h)
===================================================================
--- vendor/wpa/2.0/src/ap/beacon.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/beacon.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef BEACON_H
+#define BEACON_H
+
+struct ieee80211_mgmt;
+
+void handle_probe_req(struct hostapd_data *hapd,
+		      const struct ieee80211_mgmt *mgmt, size_t len,
+		      int ssi_signal);
+void ieee802_11_set_beacon(struct hostapd_data *hapd);
+void ieee802_11_set_beacons(struct hostapd_iface *iface);
+void ieee802_11_update_beacons(struct hostapd_iface *iface);
+
+#endif /* BEACON_H */

Deleted: vendor/wpa/2.0/src/ap/ctrl_iface_ap.c
===================================================================
--- vendor/wpa/dist/src/ap/ctrl_iface_ap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ctrl_iface_ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,104 +0,0 @@
-/*
- * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "hostapd.h"
-#include "ieee802_1x.h"
-#include "wpa_auth.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "wps_hostapd.h"
-#include "ctrl_iface_ap.h"
-
-
-static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
-				      struct sta_info *sta,
-				      char *buf, size_t buflen)
-{
-	int len, res, ret;
-
-	if (sta == NULL) {
-		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
-			return 0;
-		return ret;
-	}
-
-	len = 0;
-	ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
-			  MAC2STR(sta->addr));
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
-	if (res >= 0)
-		len += res;
-	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
-	if (res >= 0)
-		len += res;
-	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
-	if (res >= 0)
-		len += res;
-	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
-				      buflen - len);
-	if (res >= 0)
-		len += res;
-
-	return len;
-}
-
-
-int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
-				 char *buf, size_t buflen)
-{
-	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
-}
-
-
-int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
-			   char *buf, size_t buflen)
-{
-	u8 addr[ETH_ALEN];
-	int ret;
-
-	if (hwaddr_aton(txtaddr, addr)) {
-		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
-			return 0;
-		return ret;
-	}
-	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
-					  buf, buflen);
-}
-
-
-int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
-				char *buf, size_t buflen)
-{
-	u8 addr[ETH_ALEN];
-	struct sta_info *sta;
-	int ret;
-
-	if (hwaddr_aton(txtaddr, addr) ||
-	    (sta = ap_get_sta(hapd, addr)) == NULL) {
-		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
-			return 0;
-		return ret;
-	}		
-	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
-}

Copied: vendor/wpa/2.0/src/ap/ctrl_iface_ap.c (from rev 9639, vendor/wpa/dist/src/ap/ctrl_iface_ap.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ctrl_iface_ap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ctrl_iface_ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,297 @@
+/*
+ * Control interface for shared AP commands
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "wps_hostapd.h"
+#include "p2p_hostapd.h"
+#include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"
+
+
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+				     char *buf, size_t buflen)
+{
+	struct os_time now, age;
+	int len = 0, ret;
+
+	if (!sta->connected_time.sec)
+		return 0;
+
+	os_get_time(&now);
+	os_time_sub(&now, &sta->connected_time, &age);
+
+	ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+			  (unsigned int) age.sec);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+				      struct sta_info *sta,
+				      char *buf, size_t buflen)
+{
+	int len, res, ret;
+
+	if (sta == NULL) {
+		ret = os_snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}
+
+	len = 0;
+	ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
+			  MAC2STR(sta->addr));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
+				      buflen - len);
+	if (res >= 0)
+		len += res;
+	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+
+	res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+
+	return len;
+}
+
+
+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+				 char *buf, size_t buflen)
+{
+	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
+}
+
+
+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
+			   char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(txtaddr, addr)) {
+		ret = os_snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}
+	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
+					  buf, buflen);
+}
+
+
+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
+				char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	int ret;
+
+	if (hwaddr_aton(txtaddr, addr) ||
+	    (sta = ap_get_sta(hapd, addr)) == NULL) {
+		ret = os_snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}		
+	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
+}
+
+
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+				  u8 minor_reason_code, const u8 *addr)
+{
+	struct ieee80211_mgmt *mgmt;
+	int ret;
+	u8 *pos;
+
+	if (hapd->driver->send_frame == NULL)
+		return -1;
+
+	mgmt = os_zalloc(sizeof(*mgmt) + 100);
+	if (mgmt == NULL)
+		return -1;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+		" with minor reason code %u (stype=%u)",
+		MAC2STR(addr), minor_reason_code, stype);
+
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	if (stype == WLAN_FC_STYPE_DEAUTH) {
+		mgmt->u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+	} else {
+		mgmt->u.disassoc.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+	}
+
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = 4 + 3 + 1;
+	WPA_PUT_BE24(pos, OUI_WFA);
+	pos += 3;
+	*pos++ = P2P_OUI_TYPE;
+
+	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	*pos++ = minor_reason_code;
+
+	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+				       pos - (u8 *) mgmt, 1);
+	os_free(mgmt);
+
+	return ret < 0 ? -1 : 0;
+}
+#endif /* CONFIG_P2P_MANAGER */
+
+
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+				      const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	const char *pos;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+		txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DEAUTH);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
+#ifdef CONFIG_P2P_MANAGER
+	pos = os_strstr(txtaddr, " p2p=");
+	if (pos) {
+		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+					      atoi(pos + 5), addr);
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		ap_sta_deauthenticate(hapd, sta,
+				      WLAN_REASON_PREV_AUTH_NOT_VALID);
+	else if (addr[0] == 0xff)
+		hostapd_free_stas(hapd);
+
+	return 0;
+}
+
+
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+				    const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	const char *pos;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+		txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DISASSOC);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.disassoc.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
+#ifdef CONFIG_P2P_MANAGER
+	pos = os_strstr(txtaddr, " p2p=");
+	if (pos) {
+		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+					      atoi(pos + 5), addr);
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		ap_sta_disassociate(hapd, sta,
+				    WLAN_REASON_PREV_AUTH_NOT_VALID);
+	else if (addr[0] == 0xff)
+		hostapd_free_stas(hapd);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/ap/ctrl_iface_ap.h
===================================================================
--- vendor/wpa/dist/src/ap/ctrl_iface_ap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ctrl_iface_ap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,25 +0,0 @@
-/*
- * Control interface for shared AP commands
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_AP_H
-#define CTRL_IFACE_AP_H
-
-int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
-				 char *buf, size_t buflen);
-int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
-			   char *buf, size_t buflen);
-int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
-				char *buf, size_t buflen);
-
-#endif /* CTRL_IFACE_AP_H */

Copied: vendor/wpa/2.0/src/ap/ctrl_iface_ap.h (from rev 9639, vendor/wpa/dist/src/ap/ctrl_iface_ap.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ctrl_iface_ap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ctrl_iface_ap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * Control interface for shared AP commands
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_AP_H
+#define CTRL_IFACE_AP_H
+
+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+				 char *buf, size_t buflen);
+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
+			   char *buf, size_t buflen);
+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
+				char *buf, size_t buflen);
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+				      const char *txtaddr);
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+				    const char *txtaddr);
+
+#endif /* CTRL_IFACE_AP_H */

Deleted: vendor/wpa/2.0/src/ap/drv_callbacks.c
===================================================================
--- vendor/wpa/dist/src/ap/drv_callbacks.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/drv_callbacks.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,457 +0,0 @@
-/*
- * hostapd / Callback functions for driver wrappers
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "radius/radius.h"
-#include "drivers/driver.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
-#include "hostapd.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "accounting.h"
-#include "tkip_countermeasures.h"
-#include "iapp.h"
-#include "ieee802_1x.h"
-#include "wpa_auth.h"
-#include "wmm.h"
-#include "wps_hostapd.h"
-#include "ap_config.h"
-
-
-int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-			const u8 *ie, size_t ielen)
-{
-	struct sta_info *sta;
-	int new_assoc, res;
-	struct ieee802_11_elems elems;
-
-	if (addr == NULL) {
-		/*
-		 * This could potentially happen with unexpected event from the
-		 * driver wrapper. This was seen at least in one case where the
-		 * driver ended up being set to station mode while hostapd was
-		 * running, so better make sure we stop processing such an
-		 * event here.
-		 */
-		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
-			   "no address");
-		return -1;
-	}
-
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "associated");
-
-	ieee802_11_parse_elems(ie, ielen, &elems, 0);
-	if (elems.wps_ie) {
-		ie = elems.wps_ie - 2;
-		ielen = elems.wps_ie_len + 2;
-		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
-	} else if (elems.rsn_ie) {
-		ie = elems.rsn_ie - 2;
-		ielen = elems.rsn_ie_len + 2;
-		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
-	} else if (elems.wpa_ie) {
-		ie = elems.wpa_ie - 2;
-		ielen = elems.wpa_ie_len + 2;
-		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
-	} else {
-		ie = NULL;
-		ielen = 0;
-		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
-			   "(Re)AssocReq");
-	}
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta) {
-		accounting_sta_stop(hapd, sta);
-	} else {
-		sta = ap_sta_add(hapd, addr);
-		if (sta == NULL)
-			return -1;
-	}
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
-
-	if (hapd->conf->wpa) {
-		if (ie == NULL || ielen == 0) {
-			if (hapd->conf->wps_state) {
-				wpa_printf(MSG_DEBUG, "STA did not include "
-					   "WPA/RSN IE in (Re)Association "
-					   "Request - possible WPS use");
-				sta->flags |= WLAN_STA_MAYBE_WPS;
-				goto skip_wpa_check;
-			}
-
-			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
-			return -1;
-		}
-		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
-		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
-			sta->flags |= WLAN_STA_WPS;
-			goto skip_wpa_check;
-		}
-
-		if (sta->wpa_sm == NULL)
-			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
-							sta->addr);
-		if (sta->wpa_sm == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
-				   "machine");
-			return -1;
-		}
-		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
-					  ie, ielen, NULL, 0);
-		if (res != WPA_IE_OK) {
-			int resp;
-			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
-				   "rejected? (res %u)", res);
-			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
-			if (res == WPA_INVALID_GROUP)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-			else if (res == WPA_INVALID_PAIRWISE)
-				resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
-			else if (res == WPA_INVALID_AKMP)
-				resp = WLAN_REASON_AKMP_NOT_VALID;
-#ifdef CONFIG_IEEE80211W
-			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-				resp = WLAN_REASON_INVALID_IE;
-			else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
-#endif /* CONFIG_IEEE80211W */
-			else
-				resp = WLAN_REASON_INVALID_IE;
-			hapd->drv.sta_disassoc(hapd, sta->addr, resp);
-			ap_free_sta(hapd, sta);
-			return -1;
-		}
-	} else if (hapd->conf->wps_state) {
-		if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
-		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
-			sta->flags |= WLAN_STA_WPS;
-		} else
-			sta->flags |= WLAN_STA_MAYBE_WPS;
-	}
-skip_wpa_check:
-
-	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
-	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
-	wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
-
-	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
-
-	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
-
-	return 0;
-}
-
-
-void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
-{
-	struct sta_info *sta;
-
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "disassociated");
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL) {
-		wpa_printf(MSG_DEBUG, "Disassociation notification for "
-			   "unknown STA " MACSTR, MAC2STR(addr));
-		return;
-	}
-
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
-	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-	ap_free_sta(hapd, sta);
-}
-
-
-#ifdef HOSTAPD
-
-#ifdef NEED_AP_MLME
-
-static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
-{
-	u16 fc, type, stype;
-
-	/*
-	 * PS-Poll frames are 16 bytes. All other frames are
-	 * 24 bytes or longer.
-	 */
-	if (len < 16)
-		return NULL;
-
-	fc = le_to_host16(hdr->frame_control);
-	type = WLAN_FC_GET_TYPE(fc);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	switch (type) {
-	case WLAN_FC_TYPE_DATA:
-		if (len < 24)
-			return NULL;
-		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
-		case WLAN_FC_FROMDS | WLAN_FC_TODS:
-		case WLAN_FC_TODS:
-			return hdr->addr1;
-		case WLAN_FC_FROMDS:
-			return hdr->addr2;
-		default:
-			return NULL;
-		}
-	case WLAN_FC_TYPE_CTRL:
-		if (stype != WLAN_FC_STYPE_PSPOLL)
-			return NULL;
-		return hdr->addr1;
-	case WLAN_FC_TYPE_MGMT:
-		return hdr->addr3;
-	default:
-		return NULL;
-	}
-}
-
-
-#define HAPD_BROADCAST ((struct hostapd_data *) -1)
-
-static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
-					    const u8 *bssid)
-{
-	size_t i;
-
-	if (bssid == NULL)
-		return NULL;
-	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
-	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
-		return HAPD_BROADCAST;
-
-	for (i = 0; i < iface->num_bss; i++) {
-		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
-			return iface->bss[i];
-	}
-
-	return NULL;
-}
-
-
-static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
-					const u8 *frame, size_t len)
-{
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
-	u16 fc = le_to_host16(hdr->frame_control);
-	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
-	if (hapd == NULL || hapd == HAPD_BROADCAST)
-		return;
-
-	ieee802_11_rx_from_unknown(hapd, hdr->addr2,
-				   (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-				   (WLAN_FC_TODS | WLAN_FC_FROMDS));
-}
-
-
-static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
-{
-	struct hostapd_iface *iface = hapd->iface;
-	const struct ieee80211_hdr *hdr;
-	const u8 *bssid;
-	struct hostapd_frame_info fi;
-
-	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
-	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
-	if (bssid == NULL)
-		return;
-
-	hapd = get_hapd_bssid(iface, bssid);
-	if (hapd == NULL) {
-		u16 fc;
-		fc = le_to_host16(hdr->frame_control);
-
-		/*
-		 * Drop frames to unknown BSSIDs except for Beacon frames which
-		 * could be used to update neighbor information.
-		 */
-		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
-			hapd = iface->bss[0];
-		else
-			return;
-	}
-
-	os_memset(&fi, 0, sizeof(fi));
-	fi.datarate = rx_mgmt->datarate;
-	fi.ssi_signal = rx_mgmt->ssi_signal;
-
-	if (hapd == HAPD_BROADCAST) {
-		size_t i;
-		for (i = 0; i < iface->num_bss; i++)
-			ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
-					rx_mgmt->frame_len, &fi);
-	} else
-		ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
-}
-
-
-static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
-			       size_t len, u16 stype, int ok)
-{
-	struct ieee80211_hdr *hdr;
-	hdr = (struct ieee80211_hdr *) buf;
-	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
-	if (hapd == NULL || hapd == HAPD_BROADCAST)
-		return;
-	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
-}
-
-#endif /* NEED_AP_MLME */
-
-
-static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-				const u8 *ie, size_t ie_len)
-{
-	size_t i;
-	int ret = 0;
-
-	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
-		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    sa, ie, ie_len) > 0) {
-			ret = 1;
-			break;
-		}
-	}
-	return ret;
-}
-
-
-static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
-{
-	struct sta_info *sta = ap_get_sta(hapd, addr);
-	if (sta)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
-		   " - adding a new STA", MAC2STR(addr));
-	sta = ap_sta_add(hapd, addr);
-	if (sta) {
-		hostapd_new_assoc_sta(hapd, sta, 0);
-	} else {
-		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
-			   MAC2STR(addr));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
-				   const u8 *data, size_t data_len)
-{
-	struct hostapd_iface *iface = hapd->iface;
-	size_t j;
-
-	for (j = 0; j < iface->num_bss; j++) {
-		if (ap_get_sta(iface->bss[j], src)) {
-			hapd = iface->bss[j];
-			break;
-		}
-	}
-
-	ieee802_1x_receive(hapd, src, data, data_len);
-}
-
-
-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
-			  union wpa_event_data *data)
-{
-	struct hostapd_data *hapd = ctx;
-
-	switch (event) {
-	case EVENT_MICHAEL_MIC_FAILURE:
-		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
-		break;
-	case EVENT_SCAN_RESULTS:
-		if (hapd->iface->scan_cb)
-			hapd->iface->scan_cb(hapd->iface);
-		break;
-#ifdef CONFIG_IEEE80211R
-	case EVENT_FT_RRB_RX:
-		wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
-			      data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
-		break;
-#endif /* CONFIG_IEEE80211R */
-	case EVENT_WPS_BUTTON_PUSHED:
-		hostapd_wps_button_pushed(hapd);
-		break;
-#ifdef NEED_AP_MLME
-	case EVENT_TX_STATUS:
-		switch (data->tx_status.type) {
-		case WLAN_FC_TYPE_MGMT:
-			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
-					   data->tx_status.data_len,
-					   data->tx_status.stype,
-					   data->tx_status.ack);
-			break;
-		case WLAN_FC_TYPE_DATA:
-			hostapd_tx_status(hapd, data->tx_status.dst,
-					  data->tx_status.data,
-					  data->tx_status.data_len,
-					  data->tx_status.ack);
-			break;
-		}
-		break;
-	case EVENT_RX_FROM_UNKNOWN:
-		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
-					    data->rx_from_unknown.len);
-		break;
-	case EVENT_RX_MGMT:
-		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
-		break;
-#endif /* NEED_AP_MLME */
-	case EVENT_RX_PROBE_REQ:
-		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
-				     data->rx_probe_req.ie,
-				     data->rx_probe_req.ie_len);
-		break;
-	case EVENT_NEW_STA:
-		hostapd_event_new_sta(hapd, data->new_sta.addr);
-		break;
-	case EVENT_EAPOL_RX:
-		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
-				       data->eapol_rx.data,
-				       data->eapol_rx.data_len);
-		break;
-	case EVENT_ASSOC:
-		hostapd_notif_assoc(hapd, data->assoc_info.addr,
-				    data->assoc_info.req_ies,
-				    data->assoc_info.req_ies_len);
-		break;
-	case EVENT_DISASSOC:
-		if (data)
-			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
-		break;
-	case EVENT_DEAUTH:
-		if (data)
-			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
-		break;
-	}
-}
-
-#endif /* HOSTAPD */

Copied: vendor/wpa/2.0/src/ap/drv_callbacks.c (from rev 9639, vendor/wpa/dist/src/ap/drv_callbacks.c)
===================================================================
--- vendor/wpa/2.0/src/ap/drv_callbacks.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/drv_callbacks.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,837 @@
+/*
+ * hostapd / Callback functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j at 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 "radius/radius.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/random.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+#include "wnm_ap.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "accounting.h"
+#include "tkip_countermeasures.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "wps_hostapd.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "hw_features.h"
+
+
+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+			const u8 *req_ies, size_t req_ies_len, int reassoc)
+{
+	struct sta_info *sta;
+	int new_assoc, res;
+	struct ieee802_11_elems elems;
+	const u8 *ie;
+	size_t ielen;
+#ifdef CONFIG_IEEE80211R
+	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+	u8 *p = buf;
+#endif /* CONFIG_IEEE80211R */
+	u16 reason = WLAN_REASON_UNSPECIFIED;
+	u16 status = WLAN_STATUS_SUCCESS;
+
+	if (addr == NULL) {
+		/*
+		 * This could potentially happen with unexpected event from the
+		 * driver wrapper. This was seen at least in one case where the
+		 * driver ended up being set to station mode while hostapd was
+		 * running, so better make sure we stop processing such an
+		 * event here.
+		 */
+		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
+			   "no address");
+		return -1;
+	}
+	random_add_randomness(addr, ETH_ALEN);
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "associated");
+
+	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
+	if (elems.wps_ie) {
+		ie = elems.wps_ie - 2;
+		ielen = elems.wps_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
+	} else if (elems.rsn_ie) {
+		ie = elems.rsn_ie - 2;
+		ielen = elems.rsn_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
+	} else if (elems.wpa_ie) {
+		ie = elems.wpa_ie - 2;
+		ielen = elems.wpa_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
+	} else {
+		ie = NULL;
+		ielen = 0;
+		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
+			   "(Re)AssocReq");
+	}
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta) {
+		accounting_sta_stop(hapd, sta);
+
+		/*
+		 * Make sure that the previously registered inactivity timer
+		 * will not remove the STA immediately.
+		 */
+		sta->timeout_next = STA_NULLFUNC;
+	} else {
+		sta = ap_sta_add(hapd, addr);
+		if (sta == NULL) {
+			hostapd_drv_sta_disassoc(hapd, addr,
+						 WLAN_REASON_DISASSOC_AP_BUSY);
+			return -1;
+		}
+	}
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+#ifdef CONFIG_P2P
+	if (elems.p2p) {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+							  P2P_IE_VENDOR_TYPE);
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	wpabuf_free(sta->hs20_ie);
+	if (elems.hs20 && elems.hs20_len > 4) {
+		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+						 elems.hs20_len - 4);
+	} else
+		sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->wpa) {
+		if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
+			if (hapd->conf->wps_state) {
+				wpa_printf(MSG_DEBUG, "STA did not include "
+					   "WPA/RSN IE in (Re)Association "
+					   "Request - possible WPS use");
+				sta->flags |= WLAN_STA_MAYBE_WPS;
+				goto skip_wpa_check;
+			}
+#endif /* CONFIG_WPS */
+
+			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
+			return -1;
+		}
+#ifdef CONFIG_WPS
+		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
+		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+			struct wpabuf *wps;
+			sta->flags |= WLAN_STA_WPS;
+			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+							  WPS_IE_VENDOR_TYPE);
+			if (wps) {
+				if (wps_is_20(wps)) {
+					wpa_printf(MSG_DEBUG, "WPS: STA "
+						   "supports WPS 2.0");
+					sta->flags |= WLAN_STA_WPS2;
+				}
+				wpabuf_free(wps);
+			}
+			goto skip_wpa_check;
+		}
+#endif /* CONFIG_WPS */
+
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+				   "machine");
+			return -1;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  ie, ielen,
+					  elems.mdie, elems.mdie_len);
+		if (res != WPA_IE_OK) {
+			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
+				   "rejected? (res %u)", res);
+			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
+			if (res == WPA_INVALID_GROUP) {
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+			} else if (res == WPA_INVALID_PAIRWISE) {
+				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+			} else if (res == WPA_INVALID_AKMP) {
+				reason = WLAN_REASON_AKMP_NOT_VALID;
+				status = WLAN_STATUS_AKMP_NOT_VALID;
+			}
+#ifdef CONFIG_IEEE80211W
+			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
+				reason = WLAN_REASON_INVALID_IE;
+				status = WLAN_STATUS_INVALID_IE;
+			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+			}
+#endif /* CONFIG_IEEE80211W */
+			else {
+				reason = WLAN_REASON_INVALID_IE;
+				status = WLAN_STATUS_INVALID_IE;
+			}
+			goto fail;
+		}
+#ifdef CONFIG_IEEE80211W
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    sta->sa_query_count > 0)
+			ap_check_sa_query_timeout(hapd, sta);
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    (sta->auth_alg != WLAN_AUTH_FT)) {
+			/*
+			 * STA has already been associated with MFP and SA
+			 * Query timeout has not been reached. Reject the
+			 * association attempt temporarily and start SA Query,
+			 * if one is not pending.
+			 */
+
+			if (sta->sa_query_count == 0)
+				ap_sta_start_sa_query(hapd, sta);
+
+#ifdef CONFIG_IEEE80211R
+			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+
+			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+					  p - buf);
+#endif /* CONFIG_IEEE80211R */
+			return 0;
+		}
+
+		if (wpa_auth_uses_mfp(sta->wpa_sm))
+			sta->flags |= WLAN_STA_MFP;
+		else
+			sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+		if (sta->auth_alg == WLAN_AUTH_FT) {
+			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
+							 req_ies_len);
+			if (status != WLAN_STATUS_SUCCESS) {
+				if (status == WLAN_STATUS_INVALID_PMKID)
+					reason = WLAN_REASON_INVALID_IE;
+				if (status == WLAN_STATUS_INVALID_MDIE)
+					reason = WLAN_REASON_INVALID_IE;
+				if (status == WLAN_STATUS_INVALID_FTIE)
+					reason = WLAN_REASON_INVALID_IE;
+				goto fail;
+			}
+		}
+#endif /* CONFIG_IEEE80211R */
+	} else if (hapd->conf->wps_state) {
+#ifdef CONFIG_WPS
+		struct wpabuf *wps;
+		if (req_ies)
+			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+							  WPS_IE_VENDOR_TYPE);
+		else
+			wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+		if (wps && wps_validate_assoc_req(wps) < 0) {
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			wpabuf_free(wps);
+			goto fail;
+		}
+#endif /* CONFIG_WPS_STRICT */
+		if (wps) {
+			sta->flags |= WLAN_STA_WPS;
+			if (wps_is_20(wps)) {
+				wpa_printf(MSG_DEBUG, "WPS: STA supports "
+					   "WPS 2.0");
+				sta->flags |= WLAN_STA_WPS2;
+			}
+		} else
+			sta->flags |= WLAN_STA_MAYBE_WPS;
+		wpabuf_free(wps);
+#endif /* CONFIG_WPS */
+	}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_IEEE80211R
+	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
+					sta->auth_alg, req_ies, req_ies_len);
+
+	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#else /* CONFIG_IEEE80211R */
+	/* Keep compiler silent about unused variables */
+	if (status) {
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+	else
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+#ifdef CONFIG_P2P
+	if (req_ies) {
+		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+				      req_ies, req_ies_len);
+	}
+#endif /* CONFIG_P2P */
+
+	return 0;
+
+fail:
+#ifdef CONFIG_IEEE80211R
+	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#endif /* CONFIG_IEEE80211R */
+	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+	ap_free_sta(hapd, sta);
+	return -1;
+}
+
+
+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+
+	if (addr == NULL) {
+		/*
+		 * This could potentially happen with unexpected event from the
+		 * driver wrapper. This was seen at least in one case where the
+		 * driver ended up reporting a station mode event while hostapd
+		 * was running, so better make sure we stop processing such an
+		 * event here.
+		 */
+		wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
+			   "with no address");
+		return;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disassociated");
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Disassociation notification for "
+			   "unknown STA " MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	ap_free_sta(hapd, sta);
+}
+
+
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+
+	if (!sta || !hapd->conf->disassoc_low_ack)
+		return;
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
+		       "missing ACKs");
+	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
+	if (sta)
+		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+}
+
+
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+			     int offset)
+{
+#ifdef NEED_AP_MLME
+	int channel;
+
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
+		       "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+
+	hapd->iface->freq = freq;
+
+	channel = hostapd_hw_get_channel(hapd, freq);
+	if (!channel) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING, "driver switched to "
+			       "bad channel!");
+		return;
+	}
+
+	hapd->iconf->channel = channel;
+	hapd->iconf->ieee80211n = ht;
+	hapd->iconf->secondary_channel = offset;
+#endif /* NEED_AP_MLME */
+}
+
+
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len,
+			 int ssi_signal)
+{
+	size_t i;
+	int ret = 0;
+
+	if (sa == NULL || ie == NULL)
+		return -1;
+
+	random_add_randomness(sa, ETH_ALEN);
+	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
+		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
+					    sa, da, bssid, ie, ie_len,
+					    ssi_signal) > 0) {
+			ret = 1;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+#ifdef HOSTAPD
+
+#ifdef CONFIG_IEEE80211R
+static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
+					  const u8 *bssid,
+					  u16 auth_transaction, u16 status,
+					  const u8 *ies, size_t ies_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL)
+		return;
+
+	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+	sta->flags |= WLAN_STA_AUTH;
+
+	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void hostapd_notif_auth(struct hostapd_data *hapd,
+			       struct auth_info *rx_auth)
+{
+	struct sta_info *sta;
+	u16 status = WLAN_STATUS_SUCCESS;
+	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+	size_t resp_ies_len = 0;
+
+	sta = ap_get_sta(hapd, rx_auth->peer);
+	if (!sta) {
+		sta = ap_sta_add(hapd, rx_auth->peer);
+		if (sta == NULL) {
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+	}
+	sta->flags &= ~WLAN_STA_PREAUTH;
+	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+#ifdef CONFIG_IEEE80211R
+	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
+		sta->auth_alg = WLAN_AUTH_FT;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+				   "state machine");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
+				    rx_auth->auth_transaction, rx_auth->ies,
+				    rx_auth->ies_len,
+				    hostapd_notify_auth_ft_finish, hapd);
+		return;
+	}
+#endif /* CONFIG_IEEE80211R */
+fail:
+	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
+			 status, resp_ies, resp_ies_len);
+}
+
+
+static void hostapd_action_rx(struct hostapd_data *hapd,
+			      struct rx_action *action)
+{
+	struct sta_info *sta;
+
+        wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
+		   action->category, (int) action->len);
+
+	sta = ap_get_sta(hapd, action->sa);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+		return;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (action->category == WLAN_ACTION_FT) {
+		wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
+			   __func__, (int) action->len);
+		wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
+		wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
+			   __func__, (int) action->len);
+		ieee802_11_sa_query_action(hapd, action->sa,
+					   *(action->data + 1),
+					   action->data + 2);
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+	if (action->category == WLAN_ACTION_WNM) {
+		wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
+			   __func__, (int) action->len);
+		ieee802_11_rx_wnm_action_ap(hapd, action);
+	}
+#endif /* CONFIG_WNM */
+}
+
+
+#ifdef NEED_AP_MLME
+
+#define HAPD_BROADCAST ((struct hostapd_data *) -1)
+
+static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
+					    const u8 *bssid)
+{
+	size_t i;
+
+	if (bssid == NULL)
+		return NULL;
+	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
+	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
+		return HAPD_BROADCAST;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
+			return iface->bss[i];
+	}
+
+	return NULL;
+}
+
+
+static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
+					const u8 *bssid, const u8 *addr,
+					int wds)
+{
+	hapd = get_hapd_bssid(hapd->iface, bssid);
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
+
+	ieee802_11_rx_from_unknown(hapd, addr, wds);
+}
+
+
+static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	const struct ieee80211_hdr *hdr;
+	const u8 *bssid;
+	struct hostapd_frame_info fi;
+
+	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
+	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
+	if (bssid == NULL)
+		return;
+
+	hapd = get_hapd_bssid(iface, bssid);
+	if (hapd == NULL) {
+		u16 fc;
+		fc = le_to_host16(hdr->frame_control);
+
+		/*
+		 * Drop frames to unknown BSSIDs except for Beacon frames which
+		 * could be used to update neighbor information.
+		 */
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			hapd = iface->bss[0];
+		else
+			return;
+	}
+
+	os_memset(&fi, 0, sizeof(fi));
+	fi.datarate = rx_mgmt->datarate;
+	fi.ssi_signal = rx_mgmt->ssi_signal;
+
+	if (hapd == HAPD_BROADCAST) {
+		size_t i;
+		for (i = 0; i < iface->num_bss; i++)
+			ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
+					rx_mgmt->frame_len, &fi);
+	} else
+		ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
+
+	random_add_randomness(&fi, sizeof(fi));
+}
+
+
+static void hostapd_rx_action(struct hostapd_data *hapd,
+			      struct rx_action *rx_action)
+{
+	struct rx_mgmt rx_mgmt;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+		   " BSSID=" MACSTR " category=%u",
+		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+		   MAC2STR(rx_action->bssid), rx_action->category);
+	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+		    rx_action->data, rx_action->len);
+
+	buf = os_zalloc(24 + 1 + rx_action->len);
+	if (buf == NULL)
+		return;
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+		/*
+		 * Assume frame was protected; it would have been dropped if
+		 * not.
+		 */
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	}
+	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+	buf[24] = rx_action->category;
+	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+	rx_mgmt.frame = buf;
+	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+	hostapd_mgmt_rx(hapd, &rx_mgmt);
+	os_free(buf);
+}
+
+
+static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
+			       size_t len, u16 stype, int ok)
+{
+	struct ieee80211_hdr *hdr;
+	hdr = (struct ieee80211_hdr *) buf;
+	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
+	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
+		   " - adding a new STA", MAC2STR(addr));
+	sta = ap_sta_add(hapd, addr);
+	if (sta) {
+		hostapd_new_assoc_sta(hapd, sta, 0);
+	} else {
+		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
+				   const u8 *data, size_t data_len)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct sta_info *sta;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		if ((sta = ap_get_sta(iface->bss[j], src))) {
+			if (sta->flags & WLAN_STA_ASSOC) {
+				hapd = iface->bss[j];
+				break;
+			}
+		}
+	}
+
+	ieee802_1x_receive(hapd, src, data, data_len);
+}
+
+
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data)
+{
+	struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
+	    data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+		event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	switch (event) {
+	case EVENT_MICHAEL_MIC_FAILURE:
+		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
+		break;
+	case EVENT_SCAN_RESULTS:
+		if (hapd->iface->scan_cb)
+			hapd->iface->scan_cb(hapd->iface);
+		break;
+#ifdef CONFIG_IEEE80211R
+	case EVENT_FT_RRB_RX:
+		wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
+			      data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
+		break;
+#endif /* CONFIG_IEEE80211R */
+	case EVENT_WPS_BUTTON_PUSHED:
+		hostapd_wps_button_pushed(hapd, NULL);
+		break;
+#ifdef NEED_AP_MLME
+	case EVENT_TX_STATUS:
+		switch (data->tx_status.type) {
+		case WLAN_FC_TYPE_MGMT:
+			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
+					   data->tx_status.data_len,
+					   data->tx_status.stype,
+					   data->tx_status.ack);
+			break;
+		case WLAN_FC_TYPE_DATA:
+			hostapd_tx_status(hapd, data->tx_status.dst,
+					  data->tx_status.data,
+					  data->tx_status.data_len,
+					  data->tx_status.ack);
+			break;
+		}
+		break;
+	case EVENT_EAPOL_TX_STATUS:
+		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+					data->eapol_tx_status.data,
+					data->eapol_tx_status.data_len,
+					data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		hostapd_client_poll_ok(hapd, data->client_poll.addr);
+		break;
+	case EVENT_RX_FROM_UNKNOWN:
+		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+					    data->rx_from_unknown.addr,
+					    data->rx_from_unknown.wds);
+		break;
+	case EVENT_RX_MGMT:
+		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
+		break;
+#endif /* NEED_AP_MLME */
+	case EVENT_RX_PROBE_REQ:
+		if (data->rx_probe_req.sa == NULL ||
+		    data->rx_probe_req.ie == NULL)
+			break;
+		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+				     data->rx_probe_req.da,
+				     data->rx_probe_req.bssid,
+				     data->rx_probe_req.ie,
+				     data->rx_probe_req.ie_len,
+				     data->rx_probe_req.ssi_signal);
+		break;
+	case EVENT_NEW_STA:
+		hostapd_event_new_sta(hapd, data->new_sta.addr);
+		break;
+	case EVENT_EAPOL_RX:
+		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
+				       data->eapol_rx.data,
+				       data->eapol_rx.data_len);
+		break;
+	case EVENT_ASSOC:
+		hostapd_notif_assoc(hapd, data->assoc_info.addr,
+				    data->assoc_info.req_ies,
+				    data->assoc_info.req_ies_len,
+				    data->assoc_info.reassoc);
+		break;
+	case EVENT_DISASSOC:
+		if (data)
+			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
+		break;
+	case EVENT_DEAUTH:
+		if (data)
+			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
+		break;
+	case EVENT_STATION_LOW_ACK:
+		if (!data)
+			break;
+		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
+		break;
+	case EVENT_RX_ACTION:
+		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
+		    data->rx_action.bssid == NULL)
+			break;
+#ifdef NEED_AP_MLME
+		hostapd_rx_action(hapd, &data->rx_action);
+#endif /* NEED_AP_MLME */
+		hostapd_action_rx(hapd, &data->rx_action);
+		break;
+	case EVENT_AUTH:
+		hostapd_notif_auth(hapd, &data->auth);
+		break;
+	case EVENT_CH_SWITCH:
+		if (!data)
+			break;
+		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+					data->ch_switch.ht_enabled,
+					data->ch_switch.ch_offset);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
+		break;
+	}
+}
+
+#endif /* HOSTAPD */

Copied: vendor/wpa/2.0/src/ap/eap_user_db.c (from rev 9639, vendor/wpa/dist/src/ap/eap_user_db.c)
===================================================================
--- vendor/wpa/2.0/src/ap/eap_user_db.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/eap_user_db.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+	char *buf, *start;
+	int num_methods;
+
+	buf = os_strdup(methods);
+	if (buf == NULL)
+		return;
+
+	os_memset(&user->methods, 0, sizeof(user->methods));
+	num_methods = 0;
+	start = buf;
+	while (*start) {
+		char *pos3 = os_strchr(start, ',');
+		if (pos3)
+			*pos3++ = '\0';
+		user->methods[num_methods].method =
+			eap_server_get_type(start,
+					    &user->methods[num_methods].vendor);
+		if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+		    user->methods[num_methods].method == EAP_TYPE_NONE) {
+			if (os_strcmp(start, "TTLS-PAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-CHAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+				goto skip_eap;
+			}
+			wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+				   start);
+			os_free(buf);
+			return;
+		}
+
+		num_methods++;
+		if (num_methods >= EAP_MAX_METHODS)
+			break;
+	skip_eap:
+		if (pos3 == NULL)
+			break;
+		start = pos3;
+	}
+
+	os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct hostapd_eap_user *user = ctx;
+	int i;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+			os_free(user->password);
+			user->password_len = os_strlen(argv[i]);
+			user->password = (u8 *) os_strdup(argv[i]);
+			user->next = (void *) 1;
+		} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+			set_user_methods(user, argv[i]);
+		}
+	}
+
+	return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct hostapd_eap_user *user = ctx;
+	int i, id = -1, methods = -1;
+	size_t len;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "identity") == 0 && argv[i])
+			id = i;
+		else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+			methods = i;
+	}
+
+	if (id < 0 || methods < 0)
+		return 0;
+
+	len = os_strlen(argv[id]);
+	if (len <= user->identity_len &&
+	    os_memcmp(argv[id], user->identity, len) == 0 &&
+	    (user->password == NULL || len > user->password_len)) {
+		os_free(user->password);
+		user->password_len = os_strlen(argv[id]);
+		user->password = (u8 *) os_strdup(argv[id]);
+		user->next = (void *) 1;
+		set_user_methods(user, argv[methods]);
+	}
+
+	return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+		    size_t identity_len, int phase2)
+{
+	sqlite3 *db;
+	struct hostapd_eap_user *user = NULL;
+	char id_str[256], cmd[300];
+	size_t i;
+
+	if (identity_len >= sizeof(id_str))
+		return NULL;
+	os_memcpy(id_str, identity, identity_len);
+	id_str[identity_len] = '\0';
+	for (i = 0; i < identity_len; i++) {
+		if (id_str[i] >= 'a' && id_str[i] <= 'z')
+			continue;
+		if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+			continue;
+		if (id_str[i] >= '0' && id_str[i] <= '9')
+			continue;
+		if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+		    id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+		    id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+		    id_str[i] == '=' || id_str[i] == ' ')
+			continue;
+		wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+		return NULL;
+	}
+
+	os_free(hapd->tmp_eap_user.identity);
+	os_free(hapd->tmp_eap_user.password);
+	os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+	hapd->tmp_eap_user.phase2 = phase2;
+	hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+	if (hapd->tmp_eap_user.identity == NULL)
+		return NULL;
+	os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+	if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+		wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+			   hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT password,methods FROM users WHERE "
+		    "identity='%s' AND phase2=%d;", id_str, phase2);
+	wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+	if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+	    SQLITE_OK) {
+		wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+	} else if (hapd->tmp_eap_user.next)
+		user = &hapd->tmp_eap_user;
+
+	if (user == NULL && !phase2) {
+		os_snprintf(cmd, sizeof(cmd),
+			    "SELECT identity,methods FROM wildcards;");
+		wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+		if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+				 NULL) != SQLITE_OK) {
+			wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+				   "operation");
+		} else if (hapd->tmp_eap_user.next) {
+			user = &hapd->tmp_eap_user;
+			os_free(user->identity);
+			user->identity = user->password;
+			user->identity_len = user->password_len;
+			user->password = NULL;
+			user->password_len = 0;
+		}
+	}
+
+	sqlite3_close(db);
+
+	return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+		     size_t identity_len, int phase2)
+{
+	const struct hostapd_bss_config *conf = hapd->conf;
+	struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+	if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+		static struct hostapd_eap_user wsc_enrollee;
+		os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+		wsc_enrollee.methods[0].method = eap_server_get_type(
+			"WSC", &wsc_enrollee.methods[0].vendor);
+		return &wsc_enrollee;
+	}
+
+	if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+		static struct hostapd_eap_user wsc_registrar;
+		os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+		wsc_registrar.methods[0].method = eap_server_get_type(
+			"WSC", &wsc_registrar.methods[0].vendor);
+		wsc_registrar.password = (u8 *) conf->ap_pin;
+		wsc_registrar.password_len = conf->ap_pin ?
+			os_strlen(conf->ap_pin) : 0;
+		return &wsc_registrar;
+	}
+#endif /* CONFIG_WPS */
+
+	while (user) {
+		if (!phase2 && user->identity == NULL) {
+			/* Wildcard match */
+			break;
+		}
+
+		if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+		    identity_len >= user->identity_len &&
+		    os_memcmp(user->identity, identity, user->identity_len) ==
+		    0) {
+			/* Wildcard prefix match */
+			break;
+		}
+
+		if (user->phase2 == !!phase2 &&
+		    user->identity_len == identity_len &&
+		    os_memcmp(user->identity, identity, identity_len) == 0)
+			break;
+		user = user->next;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (user == NULL && conf->eap_user_sqlite) {
+		return eap_user_sqlite_get(hapd, identity, identity_len,
+					   phase2);
+	}
+#endif /* CONFIG_SQLITE */
+
+	return user;
+}

Copied: vendor/wpa/2.0/src/ap/gas_serv.c (from rev 9639, vendor/wpa/dist/src/ap/gas_serv.c)
===================================================================
--- vendor/wpa/2.0/src/ap/gas_serv.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/gas_serv.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1172 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "gas_serv.h"
+
+
+static struct gas_dialog_info *
+gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
+{
+	struct sta_info *sta;
+	struct gas_dialog_info *dia = NULL;
+	int i, j;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		/*
+		 * We need a STA entry to be able to maintain state for
+		 * the GAS query.
+		 */
+		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
+			   "GAS query");
+		sta = ap_sta_add(hapd, addr);
+		if (!sta) {
+			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
+				   " for GAS query", MAC2STR(addr));
+			return NULL;
+		}
+		sta->flags |= WLAN_STA_GAS;
+		/*
+		 * The default inactivity is 300 seconds. We don't need
+		 * it to be that long.
+		 */
+		ap_sta_session_timeout(hapd, sta, 5);
+	}
+
+	if (sta->gas_dialog == NULL) {
+		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+					    sizeof(struct gas_dialog_info));
+		if (sta->gas_dialog == NULL)
+			return NULL;
+	}
+
+	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
+		if (i == GAS_DIALOG_MAX)
+			i = 0;
+		if (sta->gas_dialog[i].valid)
+			continue;
+		dia = &sta->gas_dialog[i];
+		dia->valid = 1;
+		dia->index = i;
+		dia->dialog_token = dialog_token;
+		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
+		return dia;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
+		MACSTR " dialog_token %u. Consider increasing "
+		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
+
+	return NULL;
+}
+
+
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+		     u8 dialog_token)
+{
+	struct sta_info *sta;
+	int i;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
+			   MAC2STR(addr));
+		return NULL;
+	}
+	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
+		if (sta->gas_dialog[i].dialog_token != dialog_token ||
+		    !sta->gas_dialog[i].valid)
+			continue;
+		return &sta->gas_dialog[i];
+	}
+	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
+		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
+	return NULL;
+}
+
+
+void gas_serv_dialog_clear(struct gas_dialog_info *dia)
+{
+	wpabuf_free(dia->sd_resp);
+	os_memset(dia, 0, sizeof(*dia));
+}
+
+
+static void gas_serv_free_dialogs(struct hostapd_data *hapd,
+				  const u8 *sta_addr)
+{
+	struct sta_info *sta;
+	int i;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (sta == NULL || sta->gas_dialog == NULL)
+		return;
+
+	for (i = 0; i < GAS_DIALOG_MAX; i++) {
+		if (sta->gas_dialog[i].valid)
+			return;
+	}
+
+	os_free(sta->gas_dialog);
+	sta->gas_dialog = NULL;
+}
+
+
+#ifdef CONFIG_HS20
+static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
+				   struct wpabuf *buf)
+{
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+	wpabuf_put_u8(buf, 0); /* Reserved */
+	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+	if (hapd->conf->hs20_oper_friendly_name)
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+	if (hapd->conf->hs20_wan_metrics)
+		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+	if (hapd->conf->hs20_connection_capability)
+		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+	if (hapd->conf->nai_realm_data)
+		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+	if (hapd->conf->hs20_operating_class)
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+	gas_anqp_set_element_len(buf, len);
+}
+#endif /* CONFIG_HS20 */
+
+
+static void anqp_add_capab_list(struct hostapd_data *hapd,
+				struct wpabuf *buf)
+{
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
+	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
+	if (hapd->conf->venue_name)
+		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+	if (hapd->conf->network_auth_type)
+		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+	if (hapd->conf->roaming_consortium)
+		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+	if (hapd->conf->ipaddr_type_configured)
+		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+	if (hapd->conf->nai_realm_data)
+		wpabuf_put_le16(buf, ANQP_NAI_REALM);
+	if (hapd->conf->anqp_3gpp_cell_net)
+		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+	if (hapd->conf->domain_name)
+		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+#ifdef CONFIG_HS20
+	anqp_add_hs_capab_list(hapd, buf);
+#endif /* CONFIG_HS20 */
+	gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (hapd->conf->venue_name) {
+		u8 *len;
+		unsigned int i;
+		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
+		wpabuf_put_u8(buf, hapd->conf->venue_group);
+		wpabuf_put_u8(buf, hapd->conf->venue_type);
+		for (i = 0; i < hapd->conf->venue_name_count; i++) {
+			struct hostapd_lang_string *vn;
+			vn = &hapd->conf->venue_name[i];
+			wpabuf_put_u8(buf, 3 + vn->name_len);
+			wpabuf_put_data(buf, vn->lang, 3);
+			wpabuf_put_data(buf, vn->name, vn->name_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_network_auth_type(struct hostapd_data *hapd,
+				       struct wpabuf *buf)
+{
+	if (hapd->conf->network_auth_type) {
+		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
+		wpabuf_put_data(buf, hapd->conf->network_auth_type,
+				hapd->conf->network_auth_type_len);
+	}
+}
+
+
+static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+					struct wpabuf *buf)
+{
+	unsigned int i;
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
+	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
+		struct hostapd_roaming_consortium *rc;
+		rc = &hapd->conf->roaming_consortium[i];
+		wpabuf_put_u8(buf, rc->len);
+		wpabuf_put_data(buf, rc->oi, rc->len);
+	}
+	gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
+					       struct wpabuf *buf)
+{
+	if (hapd->conf->ipaddr_type_configured) {
+		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+		wpabuf_put_le16(buf, 1);
+		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
+	}
+}
+
+
+static void anqp_add_nai_realm_eap(struct wpabuf *buf,
+				   struct hostapd_nai_realm_data *realm)
+{
+	unsigned int i, j;
+
+	wpabuf_put_u8(buf, realm->eap_method_count);
+
+	for (i = 0; i < realm->eap_method_count; i++) {
+		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
+		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
+		wpabuf_put_u8(buf, eap->eap_method);
+		wpabuf_put_u8(buf, eap->num_auths);
+		for (j = 0; j < eap->num_auths; j++) {
+			wpabuf_put_u8(buf, eap->auth_id[j]);
+			wpabuf_put_u8(buf, 1);
+			wpabuf_put_u8(buf, eap->auth_val[j]);
+		}
+	}
+}
+
+
+static void anqp_add_nai_realm_data(struct wpabuf *buf,
+				    struct hostapd_nai_realm_data *realm,
+				    unsigned int realm_idx)
+{
+	u8 *realm_data_len;
+
+	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
+		   (int) os_strlen(realm->realm[realm_idx]));
+	realm_data_len = wpabuf_put(buf, 2);
+	wpabuf_put_u8(buf, realm->encoding);
+	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
+	wpabuf_put_str(buf, realm->realm[realm_idx]);
+	anqp_add_nai_realm_eap(buf, realm);
+	gas_anqp_set_element_len(buf, realm_data_len);
+}
+
+
+static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
+					   struct wpabuf *buf,
+					   const u8 *home_realm,
+					   size_t home_realm_len)
+{
+	unsigned int i, j, k;
+	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
+	struct hostapd_nai_realm_data *realm;
+	const u8 *pos, *realm_name, *end;
+	struct {
+		unsigned int realm_data_idx;
+		unsigned int realm_idx;
+	} matches[10];
+
+	pos = home_realm;
+	end = pos + home_realm_len;
+	if (pos + 1 > end) {
+		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) {
+			wpa_hexdump(MSG_DEBUG,
+				    "Truncated NAI Home Realm Query",
+				    home_realm, home_realm_len);
+			return -1;
+		}
+		encoding = *pos++;
+		realm_len = *pos++;
+		if (pos + realm_len > end) {
+			wpa_hexdump(MSG_DEBUG,
+				    "Truncated NAI Home Realm Query",
+				    home_realm, home_realm_len);
+			return -1;
+		}
+		realm_name = pos;
+		for (j = 0; j < hapd->conf->nai_realm_count &&
+			     num_matching < 10; j++) {
+			const u8 *rpos, *rend;
+			realm = &hapd->conf->nai_realm_data[j];
+			if (encoding != realm->encoding)
+				continue;
+
+			rpos = realm_name;
+			while (rpos < realm_name + realm_len &&
+			       num_matching < 10) {
+				for (rend = rpos;
+				     rend < realm_name + realm_len; rend++) {
+					if (*rend == ';')
+						break;
+				}
+				for (k = 0; k < MAX_NAI_REALMS &&
+					     realm->realm[k] &&
+					     num_matching < 10; k++) {
+					if ((int) os_strlen(realm->realm[k]) !=
+					    rend - rpos ||
+					    os_strncmp((char *) rpos,
+						       realm->realm[k],
+						       rend - rpos) != 0)
+						continue;
+					matches[num_matching].realm_data_idx =
+						j;
+					matches[num_matching].realm_idx = k;
+					num_matching++;
+				}
+				rpos = rend + 1;
+			}
+		}
+		pos += realm_len;
+	}
+
+	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+	wpabuf_put_le16(buf, num_matching);
+
+	/*
+	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
+	 * 2. all realms that share the same EAP methods in a NAI Realm Data
+	 * unit. The first format is likely to be bigger in size than the
+	 * second, but may be easier to parse and process by the receiver.
+	 */
+	for (i = 0; i < num_matching; i++) {
+		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
+			   matches[i].realm_data_idx, matches[i].realm_idx);
+		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
+		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
+	}
+	gas_anqp_set_element_len(buf, realm_list_len);
+	return 0;
+}
+
+
+static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
+			       const u8 *home_realm, size_t home_realm_len,
+			       int nai_realm, int nai_home_realm)
+{
+	if (nai_realm && hapd->conf->nai_realm_data) {
+		u8 *len;
+		unsigned int i, j;
+		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
+		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
+			u8 *realm_data_len, *realm_len;
+			struct hostapd_nai_realm_data *realm;
+
+			realm = &hapd->conf->nai_realm_data[i];
+			realm_data_len = wpabuf_put(buf, 2);
+			wpabuf_put_u8(buf, realm->encoding);
+			realm_len = wpabuf_put(buf, 1);
+			for (j = 0; realm->realm[j]; j++) {
+				if (j > 0)
+					wpabuf_put_u8(buf, ';');
+				wpabuf_put_str(buf, realm->realm[j]);
+			}
+			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
+			anqp_add_nai_realm_eap(buf, realm);
+			gas_anqp_set_element_len(buf, realm_data_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	} else if (nai_home_realm && hapd->conf->nai_realm_data) {
+		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
+						home_realm_len);
+	}
+}
+
+
+static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
+					   struct wpabuf *buf)
+{
+	if (hapd->conf->anqp_3gpp_cell_net) {
+		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+		wpabuf_put_le16(buf,
+				hapd->conf->anqp_3gpp_cell_net_len);
+		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
+				hapd->conf->anqp_3gpp_cell_net_len);
+	}
+}
+
+
+static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (hapd->conf->domain_name) {
+		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
+		wpabuf_put_data(buf, hapd->conf->domain_name,
+				hapd->conf->domain_name_len);
+	}
+}
+
+
+#ifdef CONFIG_HS20
+
+static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
+					    struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_oper_friendly_name) {
+		u8 *len;
+		unsigned int i;
+		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
+		{
+			struct hostapd_lang_string *vn;
+			vn = &hapd->conf->hs20_oper_friendly_name[i];
+			wpabuf_put_u8(buf, 3 + vn->name_len);
+			wpabuf_put_data(buf, vn->lang, 3);
+			wpabuf_put_data(buf, vn->name, vn->name_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_wan_metrics(struct hostapd_data *hapd,
+				 struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_wan_metrics) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_connection_capability(struct hostapd_data *hapd,
+					   struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_connection_capability) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
+				hapd->conf->hs20_connection_capability_len);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_operating_class(struct hostapd_data *hapd,
+				     struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_operating_class) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
+				hapd->conf->hs20_operating_class_len);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static struct wpabuf *
+gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+				unsigned int request,
+				struct gas_dialog_info *di,
+				const u8 *home_realm, size_t home_realm_len)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(1400);
+	if (buf == NULL)
+		return NULL;
+
+	if (request & ANQP_REQ_CAPABILITY_LIST)
+		anqp_add_capab_list(hapd, buf);
+	if (request & ANQP_REQ_VENUE_NAME)
+		anqp_add_venue_name(hapd, buf);
+	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
+		anqp_add_network_auth_type(hapd, buf);
+	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
+		anqp_add_roaming_consortium(hapd, buf);
+	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
+		anqp_add_ip_addr_type_availability(hapd, buf);
+	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
+		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
+				   request & ANQP_REQ_NAI_REALM,
+				   request & ANQP_REQ_NAI_HOME_REALM);
+	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
+		anqp_add_3gpp_cellular_network(hapd, buf);
+	if (request & ANQP_REQ_DOMAIN_NAME)
+		anqp_add_domain_name(hapd, buf);
+
+#ifdef CONFIG_HS20
+	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
+		anqp_add_hs_capab_list(hapd, buf);
+	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
+		anqp_add_operator_friendly_name(hapd, buf);
+	if (request & ANQP_REQ_WAN_METRICS)
+		anqp_add_wan_metrics(hapd, buf);
+	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
+		anqp_add_connection_capability(hapd, buf);
+	if (request & ANQP_REQ_OPERATING_CLASS)
+		anqp_add_operating_class(hapd, buf);
+#endif /* CONFIG_HS20 */
+
+	return buf;
+}
+
+
+static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
+{
+	struct gas_dialog_info *dia = eloop_data;
+
+	wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
+		   "dialog token %d", dia->dialog_token);
+
+	gas_serv_dialog_clear(dia);
+}
+
+
+struct anqp_query_info {
+	unsigned int request;
+	unsigned int remote_request;
+	const u8 *home_realm_query;
+	size_t home_realm_query_len;
+	u16 remote_delay;
+};
+
+
+static void set_anqp_req(unsigned int bit, const char *name, int local,
+			 unsigned int remote, u16 remote_delay,
+			 struct anqp_query_info *qi)
+{
+	qi->request |= bit;
+	if (local) {
+		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
+	} else if (bit & remote) {
+		wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
+		qi->remote_request |= bit;
+		if (remote_delay > qi->remote_delay)
+			qi->remote_delay = remote_delay;
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
+	}
+}
+
+
+static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+				  struct anqp_query_info *qi)
+{
+	switch (info_id) {
+	case ANQP_CAPABILITY_LIST:
+		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
+			     0, qi);
+		break;
+	case ANQP_VENUE_NAME:
+		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
+			     hapd->conf->venue_name != NULL, 0, 0, qi);
+		break;
+	case ANQP_NETWORK_AUTH_TYPE:
+		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
+			     hapd->conf->network_auth_type != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_ROAMING_CONSORTIUM:
+		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
+			     hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+		break;
+	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
+			     "IP Addr Type Availability",
+			     hapd->conf->ipaddr_type_configured,
+			     0, 0, qi);
+		break;
+	case ANQP_NAI_REALM:
+		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
+			     hapd->conf->nai_realm_data != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_3GPP_CELLULAR_NETWORK:
+		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
+			     "3GPP Cellular Network",
+			     hapd->conf->anqp_3gpp_cell_net != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_DOMAIN_NAME:
+		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
+			     hapd->conf->domain_name != NULL,
+			     0, 0, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+			   info_id);
+		break;
+	}
+}
+
+
+static void rx_anqp_query_list(struct hostapd_data *hapd,
+			       const u8 *pos, const u8 *end,
+			       struct anqp_query_info *qi)
+{
+	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
+		   (unsigned int) (end - pos) / 2);
+
+	while (pos + 2 <= end) {
+		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
+		pos += 2;
+	}
+}
+
+
+#ifdef CONFIG_HS20
+
+static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
+				  struct anqp_query_info *qi)
+{
+	switch (subtype) {
+	case HS20_STYPE_CAPABILITY_LIST:
+		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
+			     1, 0, 0, qi);
+		break;
+	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
+			     "Operator Friendly Name",
+			     hapd->conf->hs20_oper_friendly_name != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_WAN_METRICS:
+		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
+			     hapd->conf->hs20_wan_metrics != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_CONNECTION_CAPABILITY:
+		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
+			     "Connection Capability",
+			     hapd->conf->hs20_connection_capability != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_OPERATING_CLASS:
+		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
+			     hapd->conf->hs20_operating_class != NULL,
+			     0, 0, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
+			   subtype);
+		break;
+	}
+}
+
+
+static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
+				      const u8 *pos, const u8 *end,
+				      struct anqp_query_info *qi)
+{
+	qi->request |= ANQP_REQ_NAI_HOME_REALM;
+	qi->home_realm_query = pos;
+	qi->home_realm_query_len = end - pos;
+	if (hapd->conf->nai_realm_data != NULL) {
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
+			   "(local)");
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
+			   "available");
+	}
+}
+
+
+static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
+				    const u8 *pos, const u8 *end,
+				    struct anqp_query_info *qi)
+{
+	u32 oui;
+	u8 subtype;
+
+	if (pos + 4 > end) {
+		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
+			   "Query element");
+		return;
+	}
+
+	oui = WPA_GET_BE24(pos);
+	pos += 3;
+	if (oui != OUI_WFA) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
+			   oui);
+		return;
+	}
+
+	if (*pos != HS20_ANQP_OUI_TYPE) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
+			   *pos);
+		return;
+	}
+	pos++;
+
+	if (pos + 1 >= end)
+		return;
+
+	subtype = *pos++;
+	pos++; /* Reserved */
+	switch (subtype) {
+	case HS20_STYPE_QUERY_LIST:
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
+		while (pos < end) {
+			rx_anqp_hs_query_list(hapd, *pos, qi);
+			pos++;
+		}
+		break;
+	case HS20_STYPE_NAI_HOME_REALM_QUERY:
+		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
+			   "%u", subtype);
+		break;
+	}
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static void gas_serv_req_local_processing(struct hostapd_data *hapd,
+					  const u8 *sa, u8 dialog_token,
+					  struct anqp_query_info *qi)
+{
+	struct wpabuf *buf, *tx_buf;
+
+	buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+					      qi->home_realm_query,
+					      qi->home_realm_query_len);
+	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
+			buf);
+	if (!buf)
+		return;
+
+	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+	    hapd->conf->gas_comeback_delay) {
+		struct gas_dialog_info *di;
+		u16 comeback_delay = 1;
+
+		if (hapd->conf->gas_comeback_delay) {
+			/* Testing - allow overriding of the delay value */
+			comeback_delay = hapd->conf->gas_comeback_delay;
+		}
+
+		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
+			   "initial response - use GAS comeback");
+		di = gas_dialog_create(hapd, sa, dialog_token);
+		if (!di) {
+			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
+				   "for " MACSTR " (dialog token %u)",
+				   MAC2STR(sa), dialog_token);
+			wpabuf_free(buf);
+			return;
+		}
+		di->sd_resp = buf;
+		di->sd_resp_pos = 0;
+		tx_buf = gas_anqp_build_initial_resp_buf(
+			dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
+			NULL);
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
+		tx_buf = gas_anqp_build_initial_resp_buf(
+			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
+		wpabuf_free(buf);
+	}
+	if (!tx_buf)
+		return;
+
+	hostapd_drv_send_action(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)
+{
+	const u8 *pos = data;
+	const u8 *end = data + len;
+	const u8 *next;
+	u8 dialog_token;
+	u16 slen;
+	struct anqp_query_info qi;
+	const u8 *adv_proto;
+
+	if (len < 1 + 2)
+		return;
+
+	os_memset(&qi, 0, sizeof(qi));
+
+	dialog_token = *pos++;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
+		MAC2STR(sa), dialog_token);
+
+	if (*pos != WLAN_EID_ADV_PROTO) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
+		return;
+	}
+	adv_proto = pos++;
+
+	slen = *pos++;
+	next = pos + slen;
+	if (next > end || slen < 2) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Invalid IE in GAS Initial Request");
+		return;
+	}
+	pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
+		struct wpabuf *buf;
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Unsupported GAS advertisement protocol id %u",
+			*pos);
+		if (sa[0] & 0x01)
+			return; /* Invalid source address - drop silently */
+		buf = gas_build_initial_resp(
+			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
+			0, 2 + slen + 2);
+		if (buf == NULL)
+			return;
+		wpabuf_put_data(buf, adv_proto, 2 + slen);
+		wpabuf_put_le16(buf, 0); /* Query Response Length */
+		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+					wpabuf_head(buf), wpabuf_len(buf));
+		wpabuf_free(buf);
+		return;
+	}
+
+	pos = next;
+	/* Query Request */
+	if (pos + 2 > end)
+		return;
+	slen = WPA_GET_LE16(pos);
+	pos += 2;
+	if (pos + slen > end)
+		return;
+	end = pos + slen;
+
+	/* ANQP Query Request */
+	while (pos < end) {
+		u16 info_id, elen;
+
+		if (pos + 4 > end)
+			return;
+
+		info_id = WPA_GET_LE16(pos);
+		pos += 2;
+		elen = WPA_GET_LE16(pos);
+		pos += 2;
+
+		if (pos + elen > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
+			return;
+		}
+
+		switch (info_id) {
+		case ANQP_QUERY_LIST:
+			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
+			break;
+#ifdef CONFIG_HS20
+		case ANQP_VENDOR_SPECIFIC:
+			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
+			break;
+#endif /* CONFIG_HS20 */
+		default:
+			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
+				   "Request element %u", info_id);
+			break;
+		}
+
+		pos += elen;
+	}
+
+	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+}
+
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+			      struct gas_dialog_info *dialog)
+{
+	struct wpabuf *buf, *tx_buf;
+	u8 dialog_token = dialog->dialog_token;
+	size_t frag_len;
+
+	if (dialog->sd_resp == NULL) {
+		buf = gas_serv_build_gas_resp_payload(hapd,
+						      dialog->all_requested,
+						      dialog, NULL, 0);
+		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+			buf);
+		if (!buf)
+			goto tx_gas_response_done;
+		dialog->sd_resp = buf;
+		dialog->sd_resp_pos = 0;
+	}
+	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
+	    hapd->conf->gas_comeback_delay) {
+		u16 comeback_delay_tus = dialog->comeback_delay +
+			GAS_SERV_COMEBACK_DELAY_FUDGE;
+		u32 comeback_delay_secs, comeback_delay_usecs;
+
+		if (hapd->conf->gas_comeback_delay) {
+			/* Testing - allow overriding of the delay value */
+			comeback_delay_tus = hapd->conf->gas_comeback_delay;
+		}
+
+		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
+			   "%u) and comeback delay %u, "
+			   "requesting comebacks", (unsigned int) frag_len,
+			   (unsigned int) hapd->gas_frag_limit,
+			   dialog->comeback_delay);
+		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+							 WLAN_STATUS_SUCCESS,
+							 comeback_delay_tus,
+							 NULL);
+		if (tx_buf) {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
+			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+						dst,
+						wpabuf_head(tx_buf),
+						wpabuf_len(tx_buf));
+		}
+		wpabuf_free(tx_buf);
+
+		/* start a timer of 1.5 * comeback-delay */
+		comeback_delay_tus = comeback_delay_tus +
+			(comeback_delay_tus / 2);
+		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
+		comeback_delay_usecs = (comeback_delay_tus * 1024) -
+			(comeback_delay_secs * 1000000);
+		eloop_register_timeout(comeback_delay_secs,
+				       comeback_delay_usecs,
+				       gas_serv_clear_cached_ies, dialog,
+				       NULL);
+		goto tx_gas_response_done;
+	}
+
+	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+				dialog->sd_resp_pos, frag_len);
+	if (buf == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
+			"failed");
+		goto tx_gas_response_done;
+	}
+	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+						 WLAN_STATUS_SUCCESS, 0, buf);
+	wpabuf_free(buf);
+	if (tx_buf == NULL)
+		goto tx_gas_response_done;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
+		"Response (frag_id %d frag_len %d)",
+		dialog->sd_frag_id, (int) frag_len);
+	dialog->sd_frag_id++;
+
+	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	wpabuf_free(tx_buf);
+tx_gas_response_done:
+	gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
+					 const u8 *sa,
+					 const u8 *data, size_t len)
+{
+	struct gas_dialog_info *dialog;
+	struct wpabuf *buf, *tx_buf;
+	u8 dialog_token;
+	size_t frag_len;
+	int more = 0;
+
+	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
+	if (len < 1)
+		return;
+	dialog_token = *data;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
+		dialog_token);
+
+	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
+	if (!dialog) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
+			"response fragment for " MACSTR " dialog token %u",
+			MAC2STR(sa), dialog_token);
+
+		if (sa[0] & 0x01)
+			return; /* Invalid source address - drop silently */
+		tx_buf = gas_anqp_build_comeback_resp_buf(
+			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
+			0, NULL);
+		if (tx_buf == NULL)
+			return;
+		goto send_resp;
+	}
+
+	if (dialog->sd_resp == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
+			   dialog->requested, dialog->received);
+		if ((dialog->requested & dialog->received) !=
+		    dialog->requested) {
+			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
+				   "from remote processing");
+			gas_serv_dialog_clear(dialog);
+			tx_buf = gas_anqp_build_comeback_resp_buf(
+				dialog_token,
+				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
+				NULL);
+			if (tx_buf == NULL)
+				return;
+			goto send_resp;
+		}
+
+		buf = gas_serv_build_gas_resp_payload(hapd,
+						      dialog->all_requested,
+						      dialog, NULL, 0);
+		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+			buf);
+		if (!buf)
+			goto rx_gas_comeback_req_done;
+		dialog->sd_resp = buf;
+		dialog->sd_resp_pos = 0;
+	}
+	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+	if (frag_len > hapd->gas_frag_limit) {
+		frag_len = hapd->gas_frag_limit;
+		more = 1;
+	}
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
+		(unsigned int) frag_len);
+	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+				dialog->sd_resp_pos, frag_len);
+	if (buf == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
+			"buffer");
+		goto rx_gas_comeback_req_done;
+	}
+	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
+						  WLAN_STATUS_SUCCESS,
+						  dialog->sd_frag_id,
+						  more, 0, buf);
+	wpabuf_free(buf);
+	if (tx_buf == NULL)
+		goto rx_gas_comeback_req_done;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
+		"(frag_id %d more=%d frag_len=%d)",
+		dialog->sd_frag_id, more, (int) frag_len);
+	dialog->sd_frag_id++;
+	dialog->sd_resp_pos += frag_len;
+
+	if (more) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
+			"to be sent",
+			(int) (wpabuf_len(dialog->sd_resp) -
+			       dialog->sd_resp_pos));
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
+			"SD response sent");
+		gas_serv_dialog_clear(dialog);
+		gas_serv_free_dialogs(hapd, sa);
+	}
+
+send_resp:
+	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	wpabuf_free(tx_buf);
+	return;
+
+rx_gas_comeback_req_done:
+	gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
+				      int freq)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	size_t hdr_len;
+	const u8 *sa, *data;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+	if (hdr_len > len)
+		return;
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+		return;
+	sa = mgmt->sa;
+	len -= hdr_len;
+	data = &mgmt->u.action.u.public_action.action;
+	switch (data[0]) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+		break;
+	case WLAN_PA_GAS_COMEBACK_REQ:
+		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+		break;
+	}
+}
+
+
+int gas_serv_init(struct hostapd_data *hapd)
+{
+	hapd->public_action_cb = gas_serv_rx_public_action;
+	hapd->public_action_cb_ctx = hapd;
+	hapd->gas_frag_limit = 1400;
+	if (hapd->conf->gas_frag_limit > 0)
+		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
+	return 0;
+}
+
+
+void gas_serv_deinit(struct hostapd_data *hapd)
+{
+}

Copied: vendor/wpa/2.0/src/ap/gas_serv.h (from rev 9639, vendor/wpa/dist/src/ap/gas_serv.h)
===================================================================
--- vendor/wpa/2.0/src/ap/gas_serv.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/gas_serv.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERV_H
+#define GAS_SERV_H
+
+#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_NETWORK_AUTH_TYPE \
+	(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
+#define ANQP_REQ_ROAMING_CONSORTIUM \
+	(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
+	(1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_NAI_REALM \
+	(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
+#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
+	(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_DOMAIN_NAME \
+	(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_HS_CAPABILITY_LIST \
+	(0x10000 << HS20_STYPE_CAPABILITY_LIST)
+#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
+	(0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME)
+#define ANQP_REQ_WAN_METRICS \
+	(0x10000 << HS20_STYPE_WAN_METRICS)
+#define ANQP_REQ_CONNECTION_CAPABILITY \
+	(0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
+#define ANQP_REQ_NAI_HOME_REALM \
+	(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
+#define ANQP_REQ_OPERATING_CLASS \
+	(0x10000 << HS20_STYPE_OPERATING_CLASS)
+
+/* To account for latencies between hostapd and external ANQP processor */
+#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
+#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+
+struct gas_dialog_info {
+	u8 valid;
+	u8 index;
+	struct wpabuf *sd_resp; /* Fragmented response */
+	u8 dialog_token;
+	size_t sd_resp_pos; /* Offset in sd_resp */
+	u8 sd_frag_id;
+	u16 comeback_delay;
+
+	unsigned int requested;
+	unsigned int received;
+	unsigned int all_requested;
+};
+
+struct hostapd_data;
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+			      struct gas_dialog_info *dialog);
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+		     u8 dialog_token);
+void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
+
+int gas_serv_init(struct hostapd_data *hapd);
+void gas_serv_deinit(struct hostapd_data *hapd);
+
+#endif /* GAS_SERV_H */

Deleted: vendor/wpa/2.0/src/ap/hostapd.c
===================================================================
--- vendor/wpa/dist/src/ap/hostapd.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/hostapd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,887 +0,0 @@
-/*
- * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "radius/radius_client.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "authsrv.h"
-#include "sta_info.h"
-#include "accounting.h"
-#include "ap_list.h"
-#include "beacon.h"
-#include "iapp.h"
-#include "ieee802_1x.h"
-#include "ieee802_11_auth.h"
-#include "vlan_init.h"
-#include "wpa_auth.h"
-#include "wps_hostapd.h"
-#include "hw_features.h"
-#include "wpa_auth_glue.h"
-#include "ap_drv_ops.h"
-#include "ap_config.h"
-
-
-static int hostapd_flush_old_stations(struct hostapd_data *hapd);
-static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
-
-extern int wpa_debug_level;
-
-
-int hostapd_reload_config(struct hostapd_iface *iface)
-{
-	struct hostapd_data *hapd = iface->bss[0];
-	struct hostapd_config *newconf, *oldconf;
-	size_t j;
-
-	if (iface->config_read_cb == NULL)
-		return -1;
-	newconf = iface->config_read_cb(iface->config_fname);
-	if (newconf == NULL)
-		return -1;
-
-	/*
-	 * Deauthenticate all stations since the new configuration may not
-	 * allow them to use the BSS anymore.
-	 */
-	for (j = 0; j < iface->num_bss; j++)
-		hostapd_flush_old_stations(iface->bss[j]);
-
-#ifndef CONFIG_NO_RADIUS
-	/* TODO: update dynamic data based on changed configuration
-	 * items (e.g., open/close sockets, etc.) */
-	radius_client_flush(hapd->radius, 0);
-#endif /* CONFIG_NO_RADIUS */
-
-	oldconf = hapd->iconf;
-	hapd->iconf = newconf;
-	hapd->conf = &newconf->bss[0];
-	iface->conf = newconf;
-
-	if (hostapd_setup_wpa_psk(hapd->conf)) {
-		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
-			   "after reloading configuration");
-	}
-
-	if (hapd->conf->ieee802_1x || hapd->conf->wpa)
-		hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
-	else
-		hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
-
-	if (hapd->conf->wpa && hapd->wpa_auth == NULL)
-		hostapd_setup_wpa(hapd);
-	else if (hapd->conf->wpa) {
-		const u8 *wpa_ie;
-		size_t wpa_ie_len;
-		hostapd_reconfig_wpa(hapd);
-		wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
-		if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
-			wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
-				   "the kernel driver.");
-	} else if (hapd->wpa_auth) {
-		wpa_deinit(hapd->wpa_auth);
-		hapd->wpa_auth = NULL;
-		hostapd_set_privacy(hapd, 0);
-		hostapd_setup_encryption(hapd->conf->iface, hapd);
-		hostapd_set_generic_elem(hapd, (u8 *) "", 0);
-	}
-
-	ieee802_11_set_beacon(hapd);
-	hostapd_update_wps(hapd);
-
-	if (hapd->conf->ssid.ssid_set &&
-	    hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
-			     hapd->conf->ssid.ssid_len)) {
-		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
-		/* try to continue */
-	}
-
-	hostapd_config_free(oldconf);
-
-	wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
-
-	return 0;
-}
-
-
-static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
-					      char *ifname)
-{
-	int i;
-
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
-				      i == 0 ? 1 : 0, NULL, 0, NULL, 0)) {
-			wpa_printf(MSG_DEBUG, "Failed to clear default "
-				   "encryption keys (ifname=%s keyidx=%d)",
-				   ifname, i);
-		}
-	}
-#ifdef CONFIG_IEEE80211W
-	if (hapd->conf->ieee80211w) {
-		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
-			if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL,
-					      i, i == 0 ? 1 : 0, NULL, 0,
-					      NULL, 0)) {
-				wpa_printf(MSG_DEBUG, "Failed to clear "
-					   "default mgmt encryption keys "
-					   "(ifname=%s keyidx=%d)", ifname, i);
-			}
-		}
-	}
-#endif /* CONFIG_IEEE80211W */
-}
-
-
-static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
-{
-	hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
-	return 0;
-}
-
-
-static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
-{
-	int errors = 0, idx;
-	struct hostapd_ssid *ssid = &hapd->conf->ssid;
-
-	idx = ssid->wep.idx;
-	if (ssid->wep.default_len &&
-	    hapd->drv.set_key(hapd->conf->iface,
-			      hapd, WPA_ALG_WEP, NULL, idx,
-			      idx == ssid->wep.idx,
-			      NULL, 0, ssid->wep.key[idx],
-			      ssid->wep.len[idx])) {
-		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
-		errors++;
-	}
-
-	if (ssid->dyn_vlan_keys) {
-		size_t i;
-		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
-			const char *ifname;
-			struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
-			if (key == NULL)
-				continue;
-			ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-							    i);
-			if (ifname == NULL)
-				continue;
-
-			idx = key->idx;
-			if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL,
-					      idx, idx == key->idx, NULL, 0,
-					      key->key[idx], key->len[idx])) {
-				wpa_printf(MSG_WARNING, "Could not set "
-					   "dynamic VLAN WEP encryption.");
-				errors++;
-			}
-		}
-	}
-
-	return errors;
-}
-
-/**
- * hostapd_cleanup - Per-BSS cleanup (deinitialization)
- * @hapd: Pointer to BSS data
- *
- * This function is used to free all per-BSS data structures and resources.
- * This gets called in a loop for each BSS between calls to
- * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
- * is deinitialized. Most of the modules that are initialized in
- * hostapd_setup_bss() are deinitialized here.
- */
-static void hostapd_cleanup(struct hostapd_data *hapd)
-{
-	if (hapd->iface->ctrl_iface_deinit)
-		hapd->iface->ctrl_iface_deinit(hapd);
-
-	iapp_deinit(hapd->iapp);
-	hapd->iapp = NULL;
-	accounting_deinit(hapd);
-	hostapd_deinit_wpa(hapd);
-	vlan_deinit(hapd);
-	hostapd_acl_deinit(hapd);
-#ifndef CONFIG_NO_RADIUS
-	radius_client_deinit(hapd->radius);
-	hapd->radius = NULL;
-#endif /* CONFIG_NO_RADIUS */
-
-	hostapd_deinit_wps(hapd);
-
-	authsrv_deinit(hapd);
-
-	if (hapd->interface_added &&
-	    hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
-		wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
-			   hapd->conf->iface);
-	}
-
-	os_free(hapd->probereq_cb);
-	hapd->probereq_cb = NULL;
-}
-
-
-/**
- * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
- * @iface: Pointer to interface data
- *
- * This function is called before per-BSS data structures are deinitialized
- * with hostapd_cleanup().
- */
-static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
-{
-}
-
-
-/**
- * hostapd_cleanup_iface - Complete per-interface cleanup
- * @iface: Pointer to interface data
- *
- * This function is called after per-BSS data structures are deinitialized
- * with hostapd_cleanup().
- */
-static void hostapd_cleanup_iface(struct hostapd_iface *iface)
-{
-	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
-	iface->hw_features = NULL;
-	os_free(iface->current_rates);
-	iface->current_rates = NULL;
-	ap_list_deinit(iface);
-	hostapd_config_free(iface->conf);
-	iface->conf = NULL;
-
-	os_free(iface->config_fname);
-	os_free(iface->bss);
-	os_free(iface);
-}
-
-
-static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
-{
-	int i;
-
-	hostapd_broadcast_wep_set(hapd);
-
-	if (hapd->conf->ssid.wep.default_len) {
-		hostapd_set_privacy(hapd, 1);
-		return 0;
-	}
-
-	for (i = 0; i < 4; i++) {
-		if (hapd->conf->ssid.wep.key[i] &&
-		    hapd->drv.set_key(iface, 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_WARNING, "Could not set WEP "
-				   "encryption.");
-			return -1;
-		}
-		if (hapd->conf->ssid.wep.key[i] &&
-		    i == hapd->conf->ssid.wep.idx)
-			hostapd_set_privacy(hapd, 1);
-	}
-
-	return 0;
-}
-
-
-static int hostapd_flush_old_stations(struct hostapd_data *hapd)
-{
-	int ret = 0;
-
-	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "Flushing old station entries");
-	if (hostapd_flush(hapd)) {
-		wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
-		ret = -1;
-	}
-	wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
-
-	/* New Prism2.5/3 STA firmware versions seem to have issues with this
-	 * broadcast deauth frame. This gets the firmware in odd state where
-	 * nothing works correctly, so let's skip sending this for the hostap
-	 * driver. */
-	if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) {
-		u8 addr[ETH_ALEN];
-		os_memset(addr, 0xff, ETH_ALEN);
-		hapd->drv.sta_deauth(hapd, addr,
-				     WLAN_REASON_PREV_AUTH_NOT_VALID);
-	}
-
-	return ret;
-}
-
-
-/**
- * hostapd_validate_bssid_configuration - Validate BSSID configuration
- * @iface: Pointer to interface data
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to validate that the configured BSSIDs are valid.
- */
-static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
-{
-	u8 mask[ETH_ALEN] = { 0 };
-	struct hostapd_data *hapd = iface->bss[0];
-	unsigned int i = iface->conf->num_bss, bits = 0, j;
-	int res;
-	int auto_addr = 0;
-
-	if (hostapd_drv_none(hapd))
-		return 0;
-
-	/* Generate BSSID mask that is large enough to cover the BSSIDs. */
-
-	/* Determine the bits necessary to cover the number of BSSIDs. */
-	for (i--; i; i >>= 1)
-		bits++;
-
-	/* 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 (j)
-				auto_addr++;
-			continue;
-		}
-
-		for (i = 0; i < ETH_ALEN; i++) {
-			mask[i] |=
-				iface->conf->bss[j].bssid[i] ^
-				hapd->own_addr[i];
-		}
-	}
-
-	if (!auto_addr)
-		goto skip_mask_ext;
-
-	for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
-		;
-	j = 0;
-	if (i < ETH_ALEN) {
-		j = (5 - i) * 8;
-
-		while (mask[i] != 0) {
-			mask[i] >>= 1;
-			j++;
-		}
-	}
-
-	if (bits < j)
-		bits = j;
-
-	if (bits > 40) {
-		wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
-			   bits);
-		return -1;
-	}
-
-	os_memset(mask, 0xff, ETH_ALEN);
-	j = bits / 8;
-	for (i = 5; i > 5 - j; i--)
-		mask[i] = 0;
-	j = bits % 8;
-	while (j--)
-		mask[i] <<= 1;
-
-skip_mask_ext:
-	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
-		   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
-
-	res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
-	if (res == 0)
-		return 0;
-
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
-			   MACSTR " for start address " MACSTR ".",
-			   MAC2STR(mask), MAC2STR(hapd->own_addr));
-		return -1;
-	}
-
-	if (!auto_addr)
-		return 0;
-
-	for (i = 0; i < ETH_ALEN; i++) {
-		if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
-			wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
-				   " for start address " MACSTR ".",
-				   MAC2STR(mask), MAC2STR(hapd->own_addr));
-			wpa_printf(MSG_ERROR, "Start address must be the "
-				   "first address in the block (i.e., addr "
-				   "AND mask == addr).");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static int mac_in_conf(struct hostapd_config *conf, const void *a)
-{
-	size_t i;
-
-	for (i = 0; i < conf->num_bss; i++) {
-		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-
-
-
-/**
- * hostapd_setup_bss - Per-BSS setup (initialization)
- * @hapd: Pointer to BSS data
- * @first: Whether this BSS is the first BSS of an interface
- *
- * This function is used to initialize all per-BSS data structures and
- * resources. This gets called in a loop for each BSS when an interface is
- * initialized. Most of the modules that are initialized here will be
- * deinitialized in hostapd_cleanup().
- */
-static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
-{
-	struct hostapd_bss_config *conf = hapd->conf;
-	u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
-	int ssid_len, set_ssid;
-	char force_ifname[IFNAMSIZ];
-	u8 if_addr[ETH_ALEN];
-
-	if (!first) {
-		if (hostapd_mac_comp_empty(hapd->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 {
-			/* Allocate the configured BSSID. */
-			os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
-
-			if (hostapd_mac_comp(hapd->own_addr,
-					     hapd->iface->bss[0]->own_addr) ==
-			    0) {
-				wpa_printf(MSG_ERROR, "BSS '%s' may not have "
-					   "BSSID set to the MAC address of "
-					   "the radio", hapd->conf->iface);
-				return -1;
-			}
-		}
-
-		hapd->interface_added = 1;
-		if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
-				   hapd->conf->iface, hapd->own_addr, hapd,
-				   &hapd->drv_priv, force_ifname, if_addr)) {
-			wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
-				   MACSTR ")", MAC2STR(hapd->own_addr));
-			return -1;
-		}
-	}
-
-	hostapd_flush_old_stations(hapd);
-	hostapd_set_privacy(hapd, 0);
-
-	hostapd_broadcast_wep_clear(hapd);
-	if (hostapd_setup_encryption(hapd->conf->iface, hapd))
-		return -1;
-
-	/*
-	 * Fetch the SSID from the system and use it or,
-	 * if one was specified in the config file, verify they
-	 * match.
-	 */
-	ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
-	if (ssid_len < 0) {
-		wpa_printf(MSG_ERROR, "Could not read SSID from system");
-		return -1;
-	}
-	if (conf->ssid.ssid_set) {
-		/*
-		 * If SSID is specified in the config file and it differs
-		 * from what is being used then force installation of the
-		 * new SSID.
-		 */
-		set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
-			    os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
-	} else {
-		/*
-		 * No SSID in the config file; just use the one we got
-		 * from the system.
-		 */
-		set_ssid = 0;
-		conf->ssid.ssid_len = ssid_len;
-		os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
-		conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
-	}
-
-	if (!hostapd_drv_none(hapd)) {
-		wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
-			   " and ssid '%s'",
-			   hapd->conf->iface, MAC2STR(hapd->own_addr),
-			   hapd->conf->ssid.ssid);
-	}
-
-	if (hostapd_setup_wpa_psk(conf)) {
-		wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
-		return -1;
-	}
-
-	/* Set SSID for the kernel driver (to be used in beacon and probe
-	 * response frames) */
-	if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
-					 conf->ssid.ssid_len)) {
-		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
-		return -1;
-	}
-
-	if (wpa_debug_level == MSG_MSGDUMP)
-		conf->radius->msg_dumps = 1;
-#ifndef CONFIG_NO_RADIUS
-	hapd->radius = radius_client_init(hapd, conf->radius);
-	if (hapd->radius == NULL) {
-		wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
-		return -1;
-	}
-#endif /* CONFIG_NO_RADIUS */
-
-	if (hostapd_acl_init(hapd)) {
-		wpa_printf(MSG_ERROR, "ACL initialization failed.");
-		return -1;
-	}
-	if (hostapd_init_wps(hapd, conf))
-		return -1;
-
-	if (authsrv_init(hapd) < 0)
-		return -1;
-
-	if (ieee802_1x_init(hapd)) {
-		wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
-		return -1;
-	}
-
-	if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
-		return -1;
-
-	if (accounting_init(hapd)) {
-		wpa_printf(MSG_ERROR, "Accounting initialization failed.");
-		return -1;
-	}
-
-	if (hapd->conf->ieee802_11f &&
-	    (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
-		wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
-			   "failed.");
-		return -1;
-	}
-
-	if (hapd->iface->ctrl_iface_init &&
-	    hapd->iface->ctrl_iface_init(hapd)) {
-		wpa_printf(MSG_ERROR, "Failed to setup control interface");
-		return -1;
-	}
-
-	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
-		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
-		return -1;
-	}
-
-	ieee802_11_set_beacon(hapd);
-
-	return 0;
-}
-
-
-static void hostapd_tx_queue_params(struct hostapd_iface *iface)
-{
-	struct hostapd_data *hapd = iface->bss[0];
-	int i;
-	struct hostapd_tx_queue_params *p;
-
-	for (i = 0; i < NUM_TX_QUEUES; i++) {
-		p = &iface->conf->tx_queue[i];
-
-		if (!p->configured)
-			continue;
-
-		if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
-						p->cwmax, p->burst)) {
-			wpa_printf(MSG_DEBUG, "Failed to set TX queue "
-				   "parameters for queue %d.", i);
-			/* Continue anyway */
-		}
-	}
-}
-
-
-static int setup_interface(struct hostapd_iface *iface)
-{
-	struct hostapd_data *hapd = iface->bss[0];
-	size_t i;
-	char country[4];
-
-	/*
-	 * Make sure that all BSSes get configured with a pointer to the same
-	 * driver interface.
-	 */
-	for (i = 1; i < iface->num_bss; i++) {
-		iface->bss[i]->driver = hapd->driver;
-		iface->bss[i]->drv_priv = hapd->drv_priv;
-	}
-
-	if (hostapd_validate_bssid_configuration(iface))
-		return -1;
-
-	if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
-		os_memcpy(country, hapd->iconf->country, 3);
-		country[3] = '\0';
-		if (hostapd_set_country(hapd, country) < 0) {
-			wpa_printf(MSG_ERROR, "Failed to set country code");
-			return -1;
-		}
-	}
-
-	if (hostapd_get_hw_features(iface)) {
-		/* Not all drivers support this yet, so continue without hw
-		 * feature data. */
-	} else {
-		int ret = hostapd_select_hw_mode(iface);
-		if (ret < 0) {
-			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
-				   "channel. (%d)", ret);
-			return -1;
-		}
-		ret = hostapd_check_ht_capab(iface);
-		if (ret < 0)
-			return -1;
-		if (ret == 1) {
-			wpa_printf(MSG_DEBUG, "Interface initialization will "
-				   "be completed in a callback");
-			return 0;
-		}
-	}
-	return hostapd_setup_interface_complete(iface, 0);
-}
-
-
-int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
-{
-	struct hostapd_data *hapd = iface->bss[0];
-	size_t j;
-	u8 *prev_addr;
-
-	if (err) {
-		wpa_printf(MSG_ERROR, "Interface initialization failed");
-		eloop_terminate();
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "Completing interface initialization");
-	if (hapd->iconf->channel) {
-		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
-		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
-			   "Frequency: %d MHz",
-			   hostapd_hw_mode_txt(hapd->iconf->hw_mode),
-			   hapd->iconf->channel, iface->freq);
-
-		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
-				     hapd->iconf->channel,
-				     hapd->iconf->ieee80211n,
-				     hapd->iconf->secondary_channel)) {
-			wpa_printf(MSG_ERROR, "Could not set channel for "
-				   "kernel driver");
-			return -1;
-		}
-	}
-
-	if (hapd->iconf->rts_threshold > -1 &&
-	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
-		wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
-			   "kernel driver");
-		return -1;
-	}
-
-	if (hapd->iconf->fragm_threshold > -1 &&
-	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
-		wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
-			   "for kernel driver");
-		return -1;
-	}
-
-	prev_addr = hapd->own_addr;
-
-	for (j = 0; j < iface->num_bss; j++) {
-		hapd = iface->bss[j];
-		if (j)
-			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
-		if (hostapd_setup_bss(hapd, j == 0))
-			return -1;
-		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
-			prev_addr = hapd->own_addr;
-	}
-
-	hostapd_tx_queue_params(iface);
-
-	ap_list_init(iface);
-
-	if (hostapd_driver_commit(hapd) < 0) {
-		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
-			   "configuration", __func__);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
-		   iface->bss[0]->conf->iface);
-
-	return 0;
-}
-
-
-/**
- * hostapd_setup_interface - Setup of an interface
- * @iface: Pointer to interface data.
- * Returns: 0 on success, -1 on failure
- *
- * Initializes the driver interface, validates the configuration,
- * and sets driver parameters based on the configuration.
- * Flushes old stations, sets the channel, encryption,
- * beacons, and WDS links based on the configuration.
- */
-int hostapd_setup_interface(struct hostapd_iface *iface)
-{
-	int ret;
-
-	ret = setup_interface(iface);
-	if (ret) {
-		wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
-			   iface->bss[0]->conf->iface);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
- * @hapd_iface: Pointer to interface data
- * @conf: Pointer to per-interface configuration
- * @bss: Pointer to per-BSS configuration for this BSS
- * Returns: Pointer to allocated BSS data
- *
- * This function is used to allocate per-BSS data structure. This data will be
- * freed after hostapd_cleanup() is called for it during interface
- * deinitialization.
- */
-struct hostapd_data *
-hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
-		       struct hostapd_config *conf,
-		       struct hostapd_bss_config *bss)
-{
-	struct hostapd_data *hapd;
-
-	hapd = os_zalloc(sizeof(*hapd));
-	if (hapd == NULL)
-		return NULL;
-
-	hostapd_set_driver_ops(&hapd->drv);
-	hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
-	hapd->iconf = conf;
-	hapd->conf = bss;
-	hapd->iface = hapd_iface;
-	hapd->driver = hapd->iconf->driver;
-
-	return hapd;
-}
-
-
-void hostapd_interface_deinit(struct hostapd_iface *iface)
-{
-	size_t j;
-
-	if (iface == NULL)
-		return;
-
-	hostapd_cleanup_iface_pre(iface);
-	for (j = 0; j < iface->num_bss; j++) {
-		struct hostapd_data *hapd = iface->bss[j];
-		hostapd_free_stas(hapd);
-		hostapd_flush_old_stations(hapd);
-		hostapd_cleanup(hapd);
-	}
-}
-
-
-void hostapd_interface_free(struct hostapd_iface *iface)
-{
-	size_t j;
-	for (j = 0; j < iface->num_bss; j++)
-		os_free(iface->bss[j]);
-	hostapd_cleanup_iface(iface);
-}
-
-
-/**
- * hostapd_new_assoc_sta - Notify that a new station associated with the AP
- * @hapd: Pointer to BSS data
- * @sta: Pointer to the associated STA data
- * @reassoc: 1 to indicate this was a re-association; 0 = first association
- *
- * This function will be called whenever a station associates with the AP. It
- * can be called from ieee802_11.c for drivers that export MLME to hostapd and
- * from drv_callbacks.c based on driver events for drivers that take care of
- * management frames (IEEE 802.11 authentication and association) internally.
- */
-void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   int reassoc)
-{
-	if (hapd->tkip_countermeasures) {
-		hapd->drv.sta_deauth(hapd, sta->addr,
-				     WLAN_REASON_MICHAEL_MIC_FAILURE);
-		return;
-	}
-
-	hostapd_prune_associations(hapd, sta->addr);
-
-	/* IEEE 802.11F (IAPP) */
-	if (hapd->conf->ieee802_11f)
-		iapp_new_station(hapd->iapp, sta);
-
-	/* Start accounting here, if IEEE 802.1X and WPA are not used.
-	 * IEEE 802.1X/WPA code will start accounting after the station has
-	 * been authorized. */
-	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
-		accounting_sta_start(hapd, sta);
-
-	/* Start IEEE 802.1X authentication process for new stations */
-	ieee802_1x_new_station(hapd, sta);
-	if (reassoc) {
-		if (sta->auth_alg != WLAN_AUTH_FT &&
-		    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
-			wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
-	} else
-		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
-}

Copied: vendor/wpa/2.0/src/ap/hostapd.c (from rev 9639, vendor/wpa/dist/src/ap/hostapd.c)
===================================================================
--- vendor/wpa/2.0/src/ap/hostapd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hostapd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1403 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius_client.h"
+#include "radius/radius_das.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "authsrv.h"
+#include "sta_info.h"
+#include "accounting.h"
+#include "ap_list.h"
+#include "beacon.h"
+#include "iapp.h"
+#include "ieee802_1x.h"
+#include "ieee802_11_auth.h"
+#include "vlan_init.h"
+#include "wpa_auth.h"
+#include "wps_hostapd.h"
+#include "hw_features.h"
+#include "wpa_auth_glue.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "p2p_hostapd.h"
+#include "gas_serv.h"
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+
+extern int wpa_debug_level;
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+			       int (*cb)(struct hostapd_iface *iface,
+					 void *ctx), void *ctx)
+{
+	size_t i;
+	int ret;
+
+	for (i = 0; i < interfaces->count; i++) {
+		ret = cb(interfaces->iface[i], ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+
+static void hostapd_reload_bss(struct hostapd_data *hapd)
+{
+#ifndef CONFIG_NO_RADIUS
+	radius_client_reconfig(hapd->radius, hapd->conf->radius);
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hostapd_setup_wpa_psk(hapd->conf)) {
+		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
+			   "after reloading configuration");
+	}
+
+	if (hapd->conf->ieee802_1x || hapd->conf->wpa)
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
+	else
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+
+	if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
+		hostapd_setup_wpa(hapd);
+		if (hapd->wpa_auth)
+			wpa_init_keys(hapd->wpa_auth);
+	} else if (hapd->conf->wpa) {
+		const u8 *wpa_ie;
+		size_t wpa_ie_len;
+		hostapd_reconfig_wpa(hapd);
+		wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+		if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
+			wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+				   "the kernel driver.");
+	} else if (hapd->wpa_auth) {
+		wpa_deinit(hapd->wpa_auth);
+		hapd->wpa_auth = NULL;
+		hostapd_set_privacy(hapd, 0);
+		hostapd_setup_encryption(hapd->conf->iface, hapd);
+		hostapd_set_generic_elem(hapd, (u8 *) "", 0);
+	}
+
+	ieee802_11_set_beacon(hapd);
+	hostapd_update_wps(hapd);
+
+	if (hapd->conf->ssid.ssid_set &&
+	    hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
+			     hapd->conf->ssid.ssid_len)) {
+		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+		/* try to continue */
+	}
+	wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_config *newconf, *oldconf;
+	size_t j;
+
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->config_read_cb == NULL)
+		return -1;
+	newconf = iface->interfaces->config_read_cb(iface->config_fname);
+	if (newconf == NULL)
+		return -1;
+
+	/*
+	 * Deauthenticate all stations since the new configuration may not
+	 * allow them to use the BSS anymore.
+	 */
+	for (j = 0; j < iface->num_bss; j++) {
+		hostapd_flush_old_stations(iface->bss[j],
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+		hostapd_broadcast_wep_clear(iface->bss[j]);
+
+#ifndef CONFIG_NO_RADIUS
+		/* TODO: update dynamic data based on changed configuration
+		 * items (e.g., open/close sockets, etc.) */
+		radius_client_flush(iface->bss[j]->radius, 0);
+#endif /* CONFIG_NO_RADIUS */
+	}
+
+	oldconf = hapd->iconf;
+	iface->conf = newconf;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		hapd->iconf = newconf;
+		hapd->conf = &newconf->bss[j];
+		hostapd_reload_bss(hapd);
+	}
+
+	hostapd_config_free(oldconf);
+
+
+	return 0;
+}
+
+
+static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
+					      char *ifname)
+{
+	int i;
+
+	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)) {
+			wpa_printf(MSG_DEBUG, "Failed to clear default "
+				   "encryption keys (ifname=%s keyidx=%d)",
+				   ifname, i);
+		}
+	}
+#ifdef CONFIG_IEEE80211W
+	if (hapd->conf->ieee80211w) {
+		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
+			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
+						NULL, i, 0, NULL,
+						0, NULL, 0)) {
+				wpa_printf(MSG_DEBUG, "Failed to clear "
+					   "default mgmt encryption keys "
+					   "(ifname=%s keyidx=%d)", ifname, i);
+			}
+		}
+	}
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
+{
+	hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
+	return 0;
+}
+
+
+static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
+{
+	int errors = 0, idx;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+	idx = ssid->wep.idx;
+	if (ssid->wep.default_len &&
+	    hostapd_drv_set_key(hapd->conf->iface,
+				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+				1, NULL, 0, ssid->wep.key[idx],
+				ssid->wep.len[idx])) {
+		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
+		errors++;
+	}
+
+	if (ssid->dyn_vlan_keys) {
+		size_t i;
+		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+			const char *ifname;
+			struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
+			if (key == NULL)
+				continue;
+			ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+							    i);
+			if (ifname == NULL)
+				continue;
+
+			idx = key->idx;
+			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+						broadcast_ether_addr, idx, 1,
+						NULL, 0, key->key[idx],
+						key->len[idx])) {
+				wpa_printf(MSG_WARNING, "Could not set "
+					   "dynamic VLAN WEP encryption.");
+				errors++;
+			}
+		}
+	}
+
+	return errors;
+}
+
+
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
+	iapp_deinit(hapd->iapp);
+	hapd->iapp = NULL;
+	accounting_deinit(hapd);
+	hostapd_deinit_wpa(hapd);
+	vlan_deinit(hapd);
+	hostapd_acl_deinit(hapd);
+#ifndef CONFIG_NO_RADIUS
+	radius_client_deinit(hapd->radius);
+	hapd->radius = NULL;
+	radius_das_deinit(hapd->radius_das);
+	hapd->radius_das = NULL;
+#endif /* CONFIG_NO_RADIUS */
+
+	hostapd_deinit_wps(hapd);
+
+	authsrv_deinit(hapd);
+
+	if (hapd->interface_added &&
+	    hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+		wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
+			   hapd->conf->iface);
+	}
+
+	os_free(hapd->probereq_cb);
+	hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+	wpabuf_free(hapd->p2p_beacon_ie);
+	hapd->p2p_beacon_ie = NULL;
+	wpabuf_free(hapd->p2p_probe_resp_ie);
+	hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
+	wpabuf_free(hapd->time_adv);
+
+#ifdef CONFIG_INTERWORKING
+	gas_serv_deinit(hapd);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+	os_free(hapd->tmp_eap_user.identity);
+	os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
+}
+
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->ctrl_iface_deinit)
+		hapd->iface->interfaces->ctrl_iface_deinit(hapd);
+	hostapd_free_hapd_data(hapd);
+}
+
+
+/**
+ * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called before per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
+{
+}
+
+
+static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+{
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = NULL;
+	os_free(iface->current_rates);
+	iface->current_rates = NULL;
+	os_free(iface->basic_rates);
+	iface->basic_rates = NULL;
+	ap_list_deinit(iface);
+}
+
+
+/**
+ * hostapd_cleanup_iface - Complete per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called after per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+{
+	hostapd_cleanup_iface_partial(iface);
+	hostapd_config_free(iface->conf);
+	iface->conf = NULL;
+
+	os_free(iface->config_fname);
+	os_free(iface->bss);
+	os_free(iface);
+}
+
+
+static void hostapd_clear_wep(struct hostapd_data *hapd)
+{
+	if (hapd->drv_priv) {
+		hostapd_set_privacy(hapd, 0);
+		hostapd_broadcast_wep_clear(hapd);
+	}
+}
+
+
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
+{
+	int i;
+
+	hostapd_broadcast_wep_set(hapd);
+
+	if (hapd->conf->ssid.wep.default_len) {
+		hostapd_set_privacy(hapd, 1);
+		return 0;
+	}
+
+	/*
+	 * When IEEE 802.1X is not enabled, the driver may need to know how to
+	 * set authentication algorithms for static WEP.
+	 */
+	hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
+	for (i = 0; i < 4; i++) {
+		if (hapd->conf->ssid.wep.key[i] &&
+		    hostapd_drv_set_key(iface, 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_WARNING, "Could not set WEP "
+				   "encryption.");
+			return -1;
+		}
+		if (hapd->conf->ssid.wep.key[i] &&
+		    i == hapd->conf->ssid.wep.idx)
+			hostapd_set_privacy(hapd, 1);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
+{
+	int ret = 0;
+	u8 addr[ETH_ALEN];
+
+	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
+		return 0;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
+	if (hostapd_flush(hapd)) {
+		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+			"kernel driver");
+		ret = -1;
+	}
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
+	os_memset(addr, 0xff, ETH_ALEN);
+	hostapd_drv_sta_deauth(hapd, addr, reason);
+	hostapd_free_stas(hapd);
+
+	return ret;
+}
+
+
+/**
+ * hostapd_validate_bssid_configuration - Validate BSSID configuration
+ * @iface: Pointer to interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to validate that the configured BSSIDs are valid.
+ */
+static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
+{
+	u8 mask[ETH_ALEN] = { 0 };
+	struct hostapd_data *hapd = iface->bss[0];
+	unsigned int i = iface->conf->num_bss, bits = 0, j;
+	int auto_addr = 0;
+
+	if (hostapd_drv_none(hapd))
+		return 0;
+
+	/* Generate BSSID mask that is large enough to cover the BSSIDs. */
+
+	/* Determine the bits necessary to cover the number of BSSIDs. */
+	for (i--; i; i >>= 1)
+		bits++;
+
+	/* 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 (j)
+				auto_addr++;
+			continue;
+		}
+
+		for (i = 0; i < ETH_ALEN; i++) {
+			mask[i] |=
+				iface->conf->bss[j].bssid[i] ^
+				hapd->own_addr[i];
+		}
+	}
+
+	if (!auto_addr)
+		goto skip_mask_ext;
+
+	for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
+		;
+	j = 0;
+	if (i < ETH_ALEN) {
+		j = (5 - i) * 8;
+
+		while (mask[i] != 0) {
+			mask[i] >>= 1;
+			j++;
+		}
+	}
+
+	if (bits < j)
+		bits = j;
+
+	if (bits > 40) {
+		wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
+			   bits);
+		return -1;
+	}
+
+	os_memset(mask, 0xff, ETH_ALEN);
+	j = bits / 8;
+	for (i = 5; i > 5 - j; i--)
+		mask[i] = 0;
+	j = bits % 8;
+	while (j--)
+		mask[i] <<= 1;
+
+skip_mask_ext:
+	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
+		   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
+
+	if (!auto_addr)
+		return 0;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
+			wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
+				   " for start address " MACSTR ".",
+				   MAC2STR(mask), MAC2STR(hapd->own_addr));
+			wpa_printf(MSG_ERROR, "Start address must be the "
+				   "first address in the block (i.e., addr "
+				   "AND mask == addr).");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int mac_in_conf(struct hostapd_config *conf, const void *a)
+{
+	size_t i;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+
+static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
+				    struct radius_das_attrs *attr)
+{
+	/* TODO */
+	return 0;
+}
+
+
+static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
+					      struct radius_das_attrs *attr)
+{
+	struct sta_info *sta = NULL;
+	char buf[128];
+
+	if (attr->sta_addr)
+		sta = ap_get_sta(hapd, attr->sta_addr);
+
+	if (sta == NULL && attr->acct_session_id &&
+	    attr->acct_session_id_len == 17) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			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)
+				break;
+		}
+	}
+
+	if (sta == NULL && attr->cui) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			struct wpabuf *cui;
+			cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
+			if (cui && wpabuf_len(cui) == attr->cui_len &&
+			    os_memcmp(wpabuf_head(cui), attr->cui,
+				      attr->cui_len) == 0)
+				break;
+		}
+	}
+
+	if (sta == NULL && attr->user_name) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			u8 *identity;
+			size_t identity_len;
+			identity = ieee802_1x_get_identity(sta->eapol_sm,
+							   &identity_len);
+			if (identity &&
+			    identity_len == attr->user_name_len &&
+			    os_memcmp(identity, attr->user_name, identity_len)
+			    == 0)
+				break;
+		}
+	}
+
+	return sta;
+}
+
+
+static enum radius_das_res
+hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	if (hostapd_das_nas_mismatch(hapd, attr))
+		return RADIUS_DAS_NAS_MISMATCH;
+
+	sta = hostapd_das_find_sta(hapd, attr);
+	if (sta == NULL)
+		return RADIUS_DAS_SESSION_NOT_FOUND;
+
+	hostapd_drv_sta_deauth(hapd, sta->addr,
+			       WLAN_REASON_PREV_AUTH_NOT_VALID);
+	ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+	return RADIUS_DAS_SUCCESS;
+}
+
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_setup_bss - Per-BSS setup (initialization)
+ * @hapd: Pointer to BSS data
+ * @first: Whether this BSS is the first BSS of an interface
+ *
+ * This function is used to initialize all per-BSS data structures and
+ * resources. This gets called in a loop for each BSS when an interface is
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+	int ssid_len, set_ssid;
+	char force_ifname[IFNAMSIZ];
+	u8 if_addr[ETH_ALEN];
+
+	if (!first) {
+		if (hostapd_mac_comp_empty(hapd->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 {
+			/* Allocate the configured BSSID. */
+			os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+
+			if (hostapd_mac_comp(hapd->own_addr,
+					     hapd->iface->bss[0]->own_addr) ==
+			    0) {
+				wpa_printf(MSG_ERROR, "BSS '%s' may not have "
+					   "BSSID set to the MAC address of "
+					   "the radio", hapd->conf->iface);
+				return -1;
+			}
+		}
+
+		hapd->interface_added = 1;
+		if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
+				   hapd->conf->iface, hapd->own_addr, hapd,
+				   &hapd->drv_priv, force_ifname, if_addr,
+				   hapd->conf->bridge[0] ? hapd->conf->bridge :
+				   NULL)) {
+			wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+				   MACSTR ")", MAC2STR(hapd->own_addr));
+			return -1;
+		}
+	}
+
+	if (conf->wmm_enabled < 0)
+		conf->wmm_enabled = hapd->iconf->ieee80211n;
+
+	hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	hostapd_set_privacy(hapd, 0);
+
+	hostapd_broadcast_wep_clear(hapd);
+	if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+		return -1;
+
+	/*
+	 * Fetch the SSID from the system and use it or,
+	 * if one was specified in the config file, verify they
+	 * match.
+	 */
+	ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
+	if (ssid_len < 0) {
+		wpa_printf(MSG_ERROR, "Could not read SSID from system");
+		return -1;
+	}
+	if (conf->ssid.ssid_set) {
+		/*
+		 * If SSID is specified in the config file and it differs
+		 * from what is being used then force installation of the
+		 * new SSID.
+		 */
+		set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
+			    os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
+	} else {
+		/*
+		 * No SSID in the config file; just use the one we got
+		 * from the system.
+		 */
+		set_ssid = 0;
+		conf->ssid.ssid_len = ssid_len;
+		os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
+	}
+
+	if (!hostapd_drv_none(hapd)) {
+		wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+			   " and ssid \"%s\"",
+			   hapd->conf->iface, MAC2STR(hapd->own_addr),
+			   wpa_ssid_txt(hapd->conf->ssid.ssid,
+					hapd->conf->ssid.ssid_len));
+	}
+
+	if (hostapd_setup_wpa_psk(conf)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
+		return -1;
+	}
+
+	/* Set SSID for the kernel driver (to be used in beacon and probe
+	 * response frames) */
+	if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
+					 conf->ssid.ssid_len)) {
+		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+		return -1;
+	}
+
+	if (wpa_debug_level == MSG_MSGDUMP)
+		conf->radius->msg_dumps = 1;
+#ifndef CONFIG_NO_RADIUS
+	hapd->radius = radius_client_init(hapd, conf->radius);
+	if (hapd->radius == NULL) {
+		wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->radius_das_port) {
+		struct radius_das_conf das_conf;
+		os_memset(&das_conf, 0, sizeof(das_conf));
+		das_conf.port = hapd->conf->radius_das_port;
+		das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+		das_conf.shared_secret_len =
+			hapd->conf->radius_das_shared_secret_len;
+		das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+		das_conf.time_window = hapd->conf->radius_das_time_window;
+		das_conf.require_event_timestamp =
+			hapd->conf->radius_das_require_event_timestamp;
+		das_conf.ctx = hapd;
+		das_conf.disconnect = hostapd_das_disconnect;
+		hapd->radius_das = radius_das_init(&das_conf);
+		if (hapd->radius_das == NULL) {
+			wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+				   "failed.");
+			return -1;
+		}
+	}
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hostapd_acl_init(hapd)) {
+		wpa_printf(MSG_ERROR, "ACL initialization failed.");
+		return -1;
+	}
+	if (hostapd_init_wps(hapd, conf))
+		return -1;
+
+	if (authsrv_init(hapd) < 0)
+		return -1;
+
+	if (ieee802_1x_init(hapd)) {
+		wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
+		return -1;
+
+	if (accounting_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Accounting initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->ieee802_11f &&
+	    (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+		wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
+			   "failed.");
+		return -1;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	if (gas_serv_init(hapd)) {
+		wpa_printf(MSG_ERROR, "GAS server initialization failed");
+		return -1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->ctrl_iface_init &&
+	    hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Failed to setup control interface");
+		return -1;
+	}
+
+	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
+		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
+		return -1;
+	}
+
+	ieee802_11_set_beacon(hapd);
+
+	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+		return -1;
+
+	if (hapd->driver && hapd->driver->set_operstate)
+		hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+	return 0;
+}
+
+
+static void hostapd_tx_queue_params(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int i;
+	struct hostapd_tx_queue_params *p;
+
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
+		p = &iface->conf->tx_queue[i];
+
+		if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
+						p->cwmax, p->burst)) {
+			wpa_printf(MSG_DEBUG, "Failed to set TX queue "
+				   "parameters for queue %d.", i);
+			/* Continue anyway */
+		}
+	}
+}
+
+
+static int setup_interface(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	size_t i;
+	char country[4];
+
+	/*
+	 * Make sure that all BSSes get configured with a pointer to the same
+	 * driver interface.
+	 */
+	for (i = 1; i < iface->num_bss; i++) {
+		iface->bss[i]->driver = hapd->driver;
+		iface->bss[i]->drv_priv = hapd->drv_priv;
+	}
+
+	if (hostapd_validate_bssid_configuration(iface))
+		return -1;
+
+	if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+		os_memcpy(country, hapd->iconf->country, 3);
+		country[3] = '\0';
+		if (hostapd_set_country(hapd, country) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to set country code");
+			return -1;
+		}
+	}
+
+	if (hostapd_get_hw_features(iface)) {
+		/* Not all drivers support this yet, so continue without hw
+		 * feature data. */
+	} else {
+		int ret = hostapd_select_hw_mode(iface);
+		if (ret < 0) {
+			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
+				   "channel. (%d)", ret);
+			return -1;
+		}
+		ret = hostapd_check_ht_capab(iface);
+		if (ret < 0)
+			return -1;
+		if (ret == 1) {
+			wpa_printf(MSG_DEBUG, "Interface initialization will "
+				   "be completed in a callback");
+			return 0;
+		}
+	}
+	return hostapd_setup_interface_complete(iface, 0);
+}
+
+
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	size_t j;
+	u8 *prev_addr;
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "Interface initialization failed");
+		eloop_terminate();
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Completing interface initialization");
+	if (hapd->iconf->channel) {
+		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
+			   "Frequency: %d MHz",
+			   hostapd_hw_mode_txt(hapd->iconf->hw_mode),
+			   hapd->iconf->channel, iface->freq);
+
+		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+				     hapd->iconf->channel,
+				     hapd->iconf->ieee80211n,
+				     hapd->iconf->secondary_channel)) {
+			wpa_printf(MSG_ERROR, "Could not set channel for "
+				   "kernel driver");
+			return -1;
+		}
+	}
+
+	if (iface->current_mode) {
+		if (hostapd_prepare_rates(iface, iface->current_mode)) {
+			wpa_printf(MSG_ERROR, "Failed to prepare rates "
+				   "table.");
+			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_WARNING,
+				       "Failed to prepare rates table.");
+			return -1;
+		}
+	}
+
+	if (hapd->iconf->rts_threshold > -1 &&
+	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+		wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
+			   "kernel driver");
+		return -1;
+	}
+
+	if (hapd->iconf->fragm_threshold > -1 &&
+	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+		wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
+			   "for kernel driver");
+		return -1;
+	}
+
+	prev_addr = hapd->own_addr;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		if (j)
+			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+		if (hostapd_setup_bss(hapd, j == 0))
+			return -1;
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+			prev_addr = hapd->own_addr;
+	}
+
+	hostapd_tx_queue_params(iface);
+
+	ap_list_init(iface);
+
+	if (hostapd_driver_commit(hapd) < 0) {
+		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
+			   "configuration", __func__);
+		return -1;
+	}
+
+	/*
+	 * WPS UPnP module can be initialized only when the "upnp_iface" is up.
+	 * If "interface" and "upnp_iface" are the same (e.g., non-bridge
+	 * mode), the interface is up only after driver_commit, so initialize
+	 * WPS after driver_commit.
+	 */
+	for (j = 0; j < iface->num_bss; j++) {
+		if (hostapd_init_wps_complete(iface->bss[j]))
+			return -1;
+	}
+
+	if (hapd->setup_complete_cb)
+		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+
+	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+		   iface->bss[0]->conf->iface);
+
+	return 0;
+}
+
+
+/**
+ * hostapd_setup_interface - Setup of an interface
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initializes the driver interface, validates the configuration,
+ * and sets driver parameters based on the configuration.
+ * Flushes old stations, sets the channel, encryption,
+ * beacons, and WDS links based on the configuration.
+ */
+int hostapd_setup_interface(struct hostapd_iface *iface)
+{
+	int ret;
+
+	ret = setup_interface(iface);
+	if (ret) {
+		wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
+			   iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
+ * @hapd_iface: Pointer to interface data
+ * @conf: Pointer to per-interface configuration
+ * @bss: Pointer to per-BSS configuration for this BSS
+ * Returns: Pointer to allocated BSS data
+ *
+ * This function is used to allocate per-BSS data structure. This data will be
+ * freed after hostapd_cleanup() is called for it during interface
+ * deinitialization.
+ */
+struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss)
+{
+	struct hostapd_data *hapd;
+
+	hapd = os_zalloc(sizeof(*hapd));
+	if (hapd == NULL)
+		return NULL;
+
+	hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
+	hapd->iconf = conf;
+	hapd->conf = bss;
+	hapd->iface = hapd_iface;
+	hapd->driver = hapd->iconf->driver;
+	hapd->ctrl_sock = -1;
+
+	return hapd;
+}
+
+
+void hostapd_interface_deinit(struct hostapd_iface *iface)
+{
+	size_t j;
+
+	if (iface == NULL)
+		return;
+
+	hostapd_cleanup_iface_pre(iface);
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		hostapd_free_stas(hapd);
+		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+		hostapd_clear_wep(hapd);
+		hostapd_cleanup(hapd);
+	}
+}
+
+
+void hostapd_interface_free(struct hostapd_iface *iface)
+{
+	size_t j;
+	for (j = 0; j < iface->num_bss; j++)
+		os_free(iface->bss[j]);
+	hostapd_cleanup_iface(iface);
+}
+
+
+#ifdef HOSTAPD
+
+void hostapd_interface_deinit_free(struct hostapd_iface *iface)
+{
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+	if (iface == NULL)
+		return;
+	driver = iface->bss[0]->driver;
+	drv_priv = iface->bss[0]->drv_priv;
+	hostapd_interface_deinit(iface);
+	if (driver && driver->hapd_deinit && drv_priv)
+		driver->hapd_deinit(drv_priv);
+	hostapd_interface_free(iface);
+}
+
+
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
+{
+	if (hapd_iface->bss[0]->drv_priv != NULL) {
+		wpa_printf(MSG_ERROR, "Interface %s already enabled",
+			   hapd_iface->conf->bss[0].iface);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Enable interface %s",
+		   hapd_iface->conf->bss[0].iface);
+
+	if (hapd_iface->interfaces == NULL ||
+	    hapd_iface->interfaces->driver_init == NULL ||
+	    hapd_iface->interfaces->driver_init(hapd_iface) ||
+	    hostapd_setup_interface(hapd_iface)) {
+		hostapd_interface_deinit_free(hapd_iface);
+		return -1;
+	}
+	return 0;
+}
+
+
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
+{
+	size_t j;
+
+	wpa_printf(MSG_DEBUG, "Reload interface %s",
+		   hapd_iface->conf->bss[0].iface);
+	for (j = 0; j < hapd_iface->num_bss; j++) {
+		hostapd_flush_old_stations(hapd_iface->bss[j],
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+#ifndef CONFIG_NO_RADIUS
+		/* TODO: update dynamic data based on changed configuration
+		 * items (e.g., open/close sockets, etc.) */
+		radius_client_flush(hapd_iface->bss[j]->radius, 0);
+#endif  /* CONFIG_NO_RADIUS */
+
+		hostapd_reload_bss(hapd_iface->bss[j]);
+	}
+	return 0;
+}
+
+
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
+{
+	size_t j;
+	struct hostapd_bss_config *bss;
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+
+	if (hapd_iface == NULL)
+		return -1;
+	bss = hapd_iface->bss[0]->conf;
+	driver = hapd_iface->bss[0]->driver;
+	drv_priv = hapd_iface->bss[0]->drv_priv;
+
+	/* whatever hostapd_interface_deinit does */
+	for (j = 0; j < hapd_iface->num_bss; j++) {
+		struct hostapd_data *hapd = hapd_iface->bss[j];
+		hostapd_free_stas(hapd);
+		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+		hostapd_clear_wep(hapd);
+		hostapd_free_hapd_data(hapd);
+	}
+
+	if (driver && driver->hapd_deinit && drv_priv) {
+		driver->hapd_deinit(drv_priv);
+		hapd_iface->bss[0]->drv_priv = NULL;
+	}
+
+	/* From hostapd_cleanup_iface: These were initialized in
+	 * hostapd_setup_interface and hostapd_setup_interface_complete
+	 */
+	hostapd_cleanup_iface_partial(hapd_iface);
+	bss->wpa = 0;
+	bss->wpa_key_mgmt = -1;
+	bss->wpa_pairwise = -1;
+
+	wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+	return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_iface_alloc(struct hapd_interfaces *interfaces)
+{
+	struct hostapd_iface **iface, *hapd_iface;
+
+	iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
+				 sizeof(struct hostapd_iface *));
+	if (iface == NULL)
+		return NULL;
+	interfaces->iface = iface;
+	hapd_iface = interfaces->iface[interfaces->count] =
+		os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+			   "the interface", __func__);
+		return NULL;
+	}
+	interfaces->count++;
+	hapd_iface->interfaces = interfaces;
+
+	return hapd_iface;
+}
+
+
+static struct hostapd_config *
+hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
+		     const char *ctrl_iface)
+{
+	struct hostapd_bss_config *bss;
+	struct hostapd_config *conf;
+
+	/* Allocates memory for bss and conf */
+	conf = hostapd_config_defaults();
+	if (conf == NULL) {
+		 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+				"configuration", __func__);
+		return NULL;
+	}
+
+	conf->driver = wpa_drivers[0];
+	if (conf->driver == NULL) {
+		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+		hostapd_config_free(conf);
+		return NULL;
+	}
+
+	bss = conf->last_bss = conf->bss;
+
+	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+	bss->ctrl_interface = os_strdup(ctrl_iface);
+	if (bss->ctrl_interface == NULL) {
+		hostapd_config_free(conf);
+		return NULL;
+	}
+
+	/* Reading configuration file skipped, will be done in SET!
+	 * From reading the configuration till the end has to be done in
+	 * SET
+	 */
+	return conf;
+}
+
+
+static struct hostapd_iface * hostapd_data_alloc(
+	struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+{
+	size_t i;
+	struct hostapd_iface *hapd_iface =
+		interfaces->iface[interfaces->count - 1];
+	struct hostapd_data *hapd;
+
+	hapd_iface->conf = conf;
+	hapd_iface->num_bss = conf->num_bss;
+
+	hapd_iface->bss = os_zalloc(conf->num_bss *
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		return NULL;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd == NULL)
+			return NULL;
+		hapd->msg_ctx = hapd;
+	}
+
+	hapd_iface->interfaces = interfaces;
+
+	return hapd_iface;
+}
+
+
+int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+	struct hostapd_config *conf = NULL;
+	struct hostapd_iface *hapd_iface = NULL;
+	char *ptr;
+	size_t i;
+
+	ptr = os_strchr(buf, ' ');
+	if (ptr == NULL)
+		return -1;
+	*ptr++ = '\0';
+
+	for (i = 0; i < interfaces->count; i++) {
+		if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+			       buf)) {
+			wpa_printf(MSG_INFO, "Cannot add interface - it "
+				   "already exists");
+			return -1;
+		}
+	}
+
+	hapd_iface = hostapd_iface_alloc(interfaces);
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for interface", __func__);
+		goto fail;
+	}
+
+	conf = hostapd_config_alloc(interfaces, buf, ptr);
+	if (conf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for configuration", __func__);
+		goto fail;
+	}
+
+	hapd_iface = hostapd_data_alloc(interfaces, conf);
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for hostapd", __func__);
+		goto fail;
+	}
+
+	if (hapd_iface->interfaces &&
+	    hapd_iface->interfaces->ctrl_iface_init &&
+	    hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
+		wpa_printf(MSG_ERROR, "%s: Failed to setup control "
+			   "interface", __func__);
+		goto fail;
+	}
+	wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+	return 0;
+
+fail:
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->bss[interfaces->count]);
+		os_free(hapd_iface);
+	}
+	return -1;
+}
+
+
+int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+	struct hostapd_iface *hapd_iface;
+	size_t i, k = 0;
+
+	for (i = 0; i < interfaces->count; i++) {
+		hapd_iface = interfaces->iface[i];
+		if (hapd_iface == NULL)
+			return -1;
+		if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+			wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+			hostapd_interface_deinit_free(hapd_iface);
+			k = i;
+			while (k < (interfaces->count - 1)) {
+				interfaces->iface[k] =
+					interfaces->iface[k + 1];
+				k++;
+			}
+			interfaces->count--;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+#endif /* HOSTAPD */
+
+
+/**
+ * hostapd_new_assoc_sta - Notify that a new station associated with the AP
+ * @hapd: Pointer to BSS data
+ * @sta: Pointer to the associated STA data
+ * @reassoc: 1 to indicate this was a re-association; 0 = first association
+ *
+ * This function will be called whenever a station associates with the AP. It
+ * can be called from ieee802_11.c for drivers that export MLME to hostapd and
+ * from drv_callbacks.c based on driver events for drivers that take care of
+ * management frames (IEEE 802.11 authentication and association) internally.
+ */
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc)
+{
+	if (hapd->tkip_countermeasures) {
+		hostapd_drv_sta_deauth(hapd, sta->addr,
+				       WLAN_REASON_MICHAEL_MIC_FAILURE);
+		return;
+	}
+
+	hostapd_prune_associations(hapd, sta->addr);
+
+	/* IEEE 802.11F (IAPP) */
+	if (hapd->conf->ieee802_11f)
+		iapp_new_station(hapd->iapp, sta);
+
+#ifdef CONFIG_P2P
+	if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
+		sta->no_p2p_set = 1;
+		hapd->num_sta_no_p2p++;
+		if (hapd->num_sta_no_p2p == 1)
+			hostapd_p2p_non_p2p_sta_connected(hapd);
+	}
+#endif /* CONFIG_P2P */
+
+	/* Start accounting here, if IEEE 802.1X and WPA are not used.
+	 * IEEE 802.1X/WPA code will start accounting after the station has
+	 * been authorized. */
+	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+		os_get_time(&sta->connected_time);
+		accounting_sta_start(hapd, sta);
+	}
+
+	/* Start IEEE 802.1X authentication process for new stations */
+	ieee802_1x_new_station(hapd, sta);
+	if (reassoc) {
+		if (sta->auth_alg != WLAN_AUTH_FT &&
+		    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
+			wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
+	} else
+		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+		   __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,
+			       ap_handle_timer, hapd, sta);
+}

Deleted: vendor/wpa/2.0/src/ap/hostapd.h
===================================================================
--- vendor/wpa/dist/src/ap/hostapd.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/hostapd.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,276 +0,0 @@
-/*
- * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HOSTAPD_H
-#define HOSTAPD_H
-
-#include "common/defs.h"
-
-struct wpa_driver_ops;
-struct wpa_ctrl_dst;
-struct radius_server_data;
-struct upnp_wps_device_sm;
-struct hapd_interfaces;
-struct hostapd_data;
-struct sta_info;
-struct hostap_sta_driver_data;
-struct ieee80211_ht_capabilities;
-struct full_dynamic_vlan;
-
-struct hostapd_probereq_cb {
-	int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
-	void *ctx;
-};
-
-#define HOSTAPD_RATE_BASIC 0x00000001
-
-struct hostapd_rate_data {
-	int rate; /* rate in 100 kbps */
-	int flags; /* HOSTAPD_RATE_ flags */
-};
-
-struct hostapd_frame_info {
-	u32 channel;
-	u32 datarate;
-	u32 ssi_signal;
-};
-
-
-struct hostapd_driver_ops {
-	int (*set_ap_wps_ie)(struct hostapd_data *hapd);
-	int (*send_mgmt_frame)(struct hostapd_data *hapd, const void *msg,
-			       size_t len);
-	int (*send_eapol)(struct hostapd_data *hapd, const u8 *addr,
-			  const u8 *data, size_t data_len, int encrypt);
-	int (*set_authorized)(struct hostapd_data *hapd, struct sta_info *sta,
-			      int authorized);
-	int (*set_key)(const char *ifname, struct hostapd_data *hapd,
-		       enum wpa_alg alg, const u8 *addr, int key_idx,
-		       int set_tx, const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
-	int (*read_sta_data)(struct hostapd_data *hapd,
-			     struct hostap_sta_driver_data *data,
-			     const u8 *addr);
-	int (*sta_clear_stats)(struct hostapd_data *hapd, const u8 *addr);
-	int (*set_sta_flags)(struct hostapd_data *hapd, struct sta_info *sta);
-	int (*set_drv_ieee8021x)(struct hostapd_data *hapd, const char *ifname,
-				 int enabled);
-	int (*set_radius_acl_auth)(struct hostapd_data *hapd,
-				   const u8 *mac, int accepted,
-				   u32 session_timeout);
-	int (*set_radius_acl_expire)(struct hostapd_data *hapd,
-				     const u8 *mac);
-	int (*set_bss_params)(struct hostapd_data *hapd, int use_protection);
-	int (*set_beacon)(struct hostapd_data *hapd,
-			  const u8 *head, size_t head_len,
-			  const u8 *tail, size_t tail_len, int dtim_period,
-			  int beacon_int);
-	int (*vlan_if_add)(struct hostapd_data *hapd, const char *ifname);
-	int (*vlan_if_remove)(struct hostapd_data *hapd, const char *ifname);
-	int (*set_wds_sta)(struct hostapd_data *hapd, const u8 *addr, int aid,
-			   int val);
-	int (*set_sta_vlan)(const char *ifname, struct hostapd_data *hapd,
-			    const u8 *addr, int vlan_id);
-	int (*get_inact_sec)(struct hostapd_data *hapd, const u8 *addr);
-	int (*sta_deauth)(struct hostapd_data *hapd, const u8 *addr,
-			  int reason);
-	int (*sta_disassoc)(struct hostapd_data *hapd, const u8 *addr,
-			    int reason);
-	int (*sta_add)(struct hostapd_data *hapd,
-		       const u8 *addr, u16 aid, u16 capability,
-		       const u8 *supp_rates, size_t supp_rates_len,
-		       u16 listen_interval,
-		       const struct ieee80211_ht_capabilities *ht_capab);
-	int (*sta_remove)(struct hostapd_data *hapd, const u8 *addr);
-	int (*set_countermeasures)(struct hostapd_data *hapd, int enabled);
-};
-
-/**
- * struct hostapd_data - hostapd per-BSS data structure
- */
-struct hostapd_data {
-	struct hostapd_iface *iface;
-	struct hostapd_config *iconf;
-	struct hostapd_bss_config *conf;
-	int interface_added; /* virtual interface added for this BSS */
-
-	u8 own_addr[ETH_ALEN];
-
-	int num_sta; /* number of entries in sta_list */
-	struct sta_info *sta_list; /* STA info list head */
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-	struct sta_info *sta_hash[STA_HASH_SIZE];
-
-	/*
-	 * Bitfield for indicating which AIDs are allocated. Only AID values
-	 * 1-2007 are used and as such, the bit at index 0 corresponds to AID
-	 * 1.
-	 */
-#define AID_WORDS ((2008 + 31) / 32)
-	u32 sta_aid[AID_WORDS];
-
-	const struct wpa_driver_ops *driver;
-	void *drv_priv;
-	struct hostapd_driver_ops drv;
-
-	void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
-				 struct sta_info *sta, int reassoc);
-
-	void *msg_ctx; /* ctx for wpa_msg() calls */
-
-	struct radius_client_data *radius;
-	u32 acct_session_id_hi, acct_session_id_lo;
-
-	struct iapp_data *iapp;
-
-	struct hostapd_cached_radius_acl *acl_cache;
-	struct hostapd_acl_query_data *acl_queries;
-
-	struct wpa_authenticator *wpa_auth;
-	struct eapol_authenticator *eapol_auth;
-
-	struct rsn_preauth_interface *preauth_iface;
-	time_t michael_mic_failure;
-	int michael_mic_failures;
-	int tkip_countermeasures;
-
-	int ctrl_sock;
-	struct wpa_ctrl_dst *ctrl_dst;
-
-	void *ssl_ctx;
-	void *eap_sim_db_priv;
-	struct radius_server_data *radius_srv;
-
-	int parameter_set_count;
-
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	struct full_dynamic_vlan *full_dynamic_vlan;
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-	struct l2_packet_data *l2;
-	struct wps_context *wps;
-
-	struct wpabuf *wps_beacon_ie;
-	struct wpabuf *wps_probe_resp_ie;
-#ifdef CONFIG_WPS
-	unsigned int ap_pin_failures;
-	struct upnp_wps_device_sm *wps_upnp;
-	unsigned int ap_pin_lockout_time;
-#endif /* CONFIG_WPS */
-
-	struct hostapd_probereq_cb *probereq_cb;
-	size_t num_probereq_cb;
-
-	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
-				 int freq);
-	void *public_action_cb_ctx;
-
-	void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
-				   const u8 *uuid_e);
-	void *wps_reg_success_cb_ctx;
-};
-
-
-/**
- * struct hostapd_iface - hostapd per-interface data structure
- */
-struct hostapd_iface {
-	struct hapd_interfaces *interfaces;
-	void *owner;
-	int (*reload_config)(struct hostapd_iface *iface);
-	struct hostapd_config * (*config_read_cb)(const char *config_fname);
-	char *config_fname;
-	struct hostapd_config *conf;
-
-	size_t num_bss;
-	struct hostapd_data **bss;
-
-	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];
-	struct ap_info *ap_iter_list;
-
-	struct hostapd_hw_modes *hw_features;
-	int num_hw_features;
-	struct hostapd_hw_modes *current_mode;
-	/* Rates that are currently used (i.e., filtered copy of
-	 * current_mode->channels */
-	int num_rates;
-	struct hostapd_rate_data *current_rates;
-	int freq;
-
-	u16 hw_flags;
-
-	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
-	 * in 802.11g BSS) */
-	int num_sta_non_erp;
-
-	/* Number of associated stations that do not support Short Slot Time */
-	int num_sta_no_short_slot_time;
-
-	/* Number of associated stations that do not support Short Preamble */
-	int num_sta_no_short_preamble;
-
-	int olbc; /* Overlapping Legacy BSS Condition */
-
-	/* Number of HT associated stations that do not support greenfield */
-	int num_sta_ht_no_gf;
-
-	/* Number of associated non-HT stations */
-	int num_sta_no_ht;
-
-	/* Number of HT associated stations 20 MHz */
-	int num_sta_ht_20mhz;
-
-	/* Overlapping BSS information */
-	int olbc_ht;
-
-	u16 ht_op_mode;
-	void (*scan_cb)(struct hostapd_iface *iface);
-
-	int (*ctrl_iface_init)(struct hostapd_data *hapd);
-	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-
-	int (*for_each_interface)(struct hapd_interfaces *interfaces,
-				  int (*cb)(struct hostapd_iface *iface,
-					    void *ctx), void *ctx);
-};
-
-/* hostapd.c */
-int hostapd_reload_config(struct hostapd_iface *iface);
-struct hostapd_data *
-hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
-		       struct hostapd_config *conf,
-		       struct hostapd_bss_config *bss);
-int hostapd_setup_interface(struct hostapd_iface *iface);
-int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
-void hostapd_interface_deinit(struct hostapd_iface *iface);
-void hostapd_interface_free(struct hostapd_iface *iface);
-void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   int reassoc);
-
-/* utils.c */
-int hostapd_register_probereq_cb(struct hostapd_data *hapd,
-				 int (*cb)(void *ctx, const u8 *sa,
-					   const u8 *ie, size_t ie_len),
-				 void *ctx);
-void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
-
-/* drv_callbacks.c (TODO: move to somewhere else?) */
-int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-			const u8 *ie, size_t ielen);
-void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
-
-#endif /* HOSTAPD_H */

Copied: vendor/wpa/2.0/src/ap/hostapd.h (from rev 9639, vendor/wpa/dist/src/ap/hostapd.h)
===================================================================
--- vendor/wpa/2.0/src/ap/hostapd.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hostapd.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,309 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_H
+#define HOSTAPD_H
+
+#include "common/defs.h"
+#include "ap_config.h"
+
+struct wpa_driver_ops;
+struct wpa_ctrl_dst;
+struct radius_server_data;
+struct upnp_wps_device_sm;
+struct hostapd_data;
+struct sta_info;
+struct hostap_sta_driver_data;
+struct ieee80211_ht_capabilities;
+struct full_dynamic_vlan;
+enum wps_event;
+union wps_event_data;
+
+struct hostapd_iface;
+
+struct hapd_interfaces {
+	int (*reload_config)(struct hostapd_iface *iface);
+	struct hostapd_config * (*config_read_cb)(const char *config_fname);
+	int (*ctrl_iface_init)(struct hostapd_data *hapd);
+	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+	int (*for_each_interface)(struct hapd_interfaces *interfaces,
+				  int (*cb)(struct hostapd_iface *iface,
+					    void *ctx), void *ctx);
+	int (*driver_init)(struct hostapd_iface *iface);
+
+	size_t count;
+	int global_ctrl_sock;
+	char *global_iface_path;
+	char *global_iface_name;
+	struct hostapd_iface **iface;
+};
+
+
+struct hostapd_probereq_cb {
+	int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+		  const u8 *ie, size_t ie_len, int ssi_signal);
+	void *ctx;
+};
+
+#define HOSTAPD_RATE_BASIC 0x00000001
+
+struct hostapd_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* HOSTAPD_RATE_ flags */
+};
+
+struct hostapd_frame_info {
+	u32 channel;
+	u32 datarate;
+	int ssi_signal; /* dBm */
+};
+
+
+/**
+ * struct hostapd_data - hostapd per-BSS data structure
+ */
+struct hostapd_data {
+	struct hostapd_iface *iface;
+	struct hostapd_config *iconf;
+	struct hostapd_bss_config *conf;
+	int interface_added; /* virtual interface added for this BSS */
+
+	u8 own_addr[ETH_ALEN];
+
+	int num_sta; /* number of entries in sta_list */
+	struct sta_info *sta_list; /* STA info list head */
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+	struct sta_info *sta_hash[STA_HASH_SIZE];
+
+	/*
+	 * Bitfield for indicating which AIDs are allocated. Only AID values
+	 * 1-2007 are used and as such, the bit at index 0 corresponds to AID
+	 * 1.
+	 */
+#define AID_WORDS ((2008 + 31) / 32)
+	u32 sta_aid[AID_WORDS];
+
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+
+	void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
+				 struct sta_info *sta, int reassoc);
+
+	void *msg_ctx; /* ctx for wpa_msg() calls */
+	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;
+	struct radius_das_data *radius_das;
+
+	struct iapp_data *iapp;
+
+	struct hostapd_cached_radius_acl *acl_cache;
+	struct hostapd_acl_query_data *acl_queries;
+
+	struct wpa_authenticator *wpa_auth;
+	struct eapol_authenticator *eapol_auth;
+
+	struct rsn_preauth_interface *preauth_iface;
+	time_t michael_mic_failure;
+	int michael_mic_failures;
+	int tkip_countermeasures;
+
+	int ctrl_sock;
+	struct wpa_ctrl_dst *ctrl_dst;
+
+	void *ssl_ctx;
+	void *eap_sim_db_priv;
+	struct radius_server_data *radius_srv;
+
+	int parameter_set_count;
+
+	/* Time Advertisement */
+	u8 time_update_counter;
+	struct wpabuf *time_adv;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	struct full_dynamic_vlan *full_dynamic_vlan;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	struct l2_packet_data *l2;
+	struct wps_context *wps;
+
+	int beacon_set_done;
+	struct wpabuf *wps_beacon_ie;
+	struct wpabuf *wps_probe_resp_ie;
+#ifdef CONFIG_WPS
+	unsigned int ap_pin_failures;
+	unsigned int ap_pin_failures_consecutive;
+	struct upnp_wps_device_sm *wps_upnp;
+	unsigned int ap_pin_lockout_time;
+#endif /* CONFIG_WPS */
+
+	struct hostapd_probereq_cb *probereq_cb;
+	size_t num_probereq_cb;
+
+	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
+				 int freq);
+	void *public_action_cb_ctx;
+
+	int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
+				int freq);
+	void *vendor_action_cb_ctx;
+
+	void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
+				   const u8 *uuid_e);
+	void *wps_reg_success_cb_ctx;
+
+	void (*wps_event_cb)(void *ctx, enum wps_event event,
+			     union wps_event_data *data);
+	void *wps_event_cb_ctx;
+
+	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
+				  int authorized, const u8 *p2p_dev_addr);
+	void *sta_authorized_cb_ctx;
+
+	void (*setup_complete_cb)(void *ctx);
+	void *setup_complete_cb_ctx;
+
+#ifdef CONFIG_P2P
+	struct p2p_data *p2p;
+	struct p2p_group *p2p_group;
+	struct wpabuf *p2p_beacon_ie;
+	struct wpabuf *p2p_probe_resp_ie;
+
+	/* Number of non-P2P association stations */
+	int num_sta_no_p2p;
+
+	/* Periodic NoA (used only when no non-P2P clients in the group) */
+	int noa_enabled;
+	int noa_start;
+	int noa_duration;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+	struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
+};
+
+
+/**
+ * struct hostapd_iface - hostapd per-interface data structure
+ */
+struct hostapd_iface {
+	struct hapd_interfaces *interfaces;
+	void *owner;
+	char *config_fname;
+	struct hostapd_config *conf;
+
+	size_t num_bss;
+	struct hostapd_data **bss;
+
+	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];
+	struct ap_info *ap_iter_list;
+
+	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
+	struct hostapd_hw_modes *hw_features;
+	int num_hw_features;
+	struct hostapd_hw_modes *current_mode;
+	/* Rates that are currently used (i.e., filtered copy of
+	 * current_mode->channels */
+	int num_rates;
+	struct hostapd_rate_data *current_rates;
+	int *basic_rates;
+	int freq;
+
+	u16 hw_flags;
+
+	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+	 * in 802.11g BSS) */
+	int num_sta_non_erp;
+
+	/* Number of associated stations that do not support Short Slot Time */
+	int num_sta_no_short_slot_time;
+
+	/* Number of associated stations that do not support Short Preamble */
+	int num_sta_no_short_preamble;
+
+	int olbc; /* Overlapping Legacy BSS Condition */
+
+	/* Number of HT associated stations that do not support greenfield */
+	int num_sta_ht_no_gf;
+
+	/* Number of associated non-HT stations */
+	int num_sta_no_ht;
+
+	/* Number of HT associated stations 20 MHz */
+	int num_sta_ht_20mhz;
+
+	/* Overlapping BSS information */
+	int olbc_ht;
+
+	u16 ht_op_mode;
+	void (*scan_cb)(struct hostapd_iface *iface);
+};
+
+/* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+			       int (*cb)(struct hostapd_iface *iface,
+					 void *ctx), void *ctx);
+int hostapd_reload_config(struct hostapd_iface *iface);
+struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss);
+int hostapd_setup_interface(struct hostapd_iface *iface);
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
+void hostapd_interface_deinit(struct hostapd_iface *iface);
+void hostapd_interface_free(struct hostapd_iface *iface);
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc);
+void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+
+/* utils.c */
+int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
+					   const u8 *ie, size_t ie_len,
+					   int ssi_signal),
+				 void *ctx);
+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
+
+/* drv_callbacks.c (TODO: move to somewhere else?) */
+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+			const u8 *ie, size_t ielen, int reassoc);
+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len,
+			 int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+			     int offset);
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+		     size_t identity_len, int phase2);
+
+#endif /* HOSTAPD_H */

Copied: vendor/wpa/2.0/src/ap/hs20.c (from rev 9639, vendor/wpa/dist/src/ap/hs20.c)
===================================================================
--- vendor/wpa/2.0/src/ap/hs20.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hs20.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,31 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "hs20.h"
+
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
+{
+	if (!hapd->conf->hs20)
+		return eid;
+	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
+	*eid++ = 5;
+	WPA_PUT_BE24(eid, OUI_WFA);
+	eid += 3;
+	*eid++ = HS20_INDICATION_OUI_TYPE;
+	/* Hotspot Configuration: DGAF Enabled */
+	*eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
+	return eid;
+}

Copied: vendor/wpa/2.0/src/ap/hs20.h (from rev 9639, vendor/wpa/dist/src/ap/hs20.h)
===================================================================
--- vendor/wpa/2.0/src/ap/hs20.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hs20.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_H
+#define HS20_H
+
+struct hostapd_data;
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* HS20_H */

Deleted: vendor/wpa/2.0/src/ap/hw_features.c
===================================================================
--- vendor/wpa/dist/src/ap/hw_features.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/hw_features.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,731 +0,0 @@
-/*
- * hostapd / Hardware feature query and different modes
- * Copyright 2002-2003, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ap_drv_ops.h"
-#include "hw_features.h"
-
-
-void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
-			      size_t num_hw_features)
-{
-	size_t i;
-
-	if (hw_features == NULL)
-		return;
-
-	for (i = 0; i < num_hw_features; i++) {
-		os_free(hw_features[i].channels);
-		os_free(hw_features[i].rates);
-	}
-
-	os_free(hw_features);
-}
-
-
-int hostapd_get_hw_features(struct hostapd_iface *iface)
-{
-	struct hostapd_data *hapd = iface->bss[0];
-	int ret = 0, i, j;
-	u16 num_modes, flags;
-	struct hostapd_hw_modes *modes;
-
-	if (hostapd_drv_none(hapd))
-		return -1;
-	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
-	if (modes == NULL) {
-		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "Fetching hardware channel/rate support not "
-			       "supported.");
-		return -1;
-	}
-
-	iface->hw_flags = flags;
-
-	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
-	iface->hw_features = modes;
-	iface->num_hw_features = num_modes;
-
-	for (i = 0; i < num_modes; i++) {
-		struct hostapd_hw_modes *feature = &modes[i];
-		/* set flag for channels we can use in current regulatory
-		 * domain */
-		for (j = 0; j < feature->num_channels; j++) {
-			/*
-			 * Disable all channels that are marked not to allow
-			 * IBSS operation or active scanning. In addition,
-			 * disable all channels that require radar detection,
-			 * since that (in addition to full DFS) is not yet
-			 * supported.
-			 */
-			if (feature->channels[j].flag &
-			    (HOSTAPD_CHAN_NO_IBSS |
-			     HOSTAPD_CHAN_PASSIVE_SCAN |
-			     HOSTAPD_CHAN_RADAR))
-				feature->channels[j].flag |=
-					HOSTAPD_CHAN_DISABLED;
-			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
-				continue;
-			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
-				   "chan=%d freq=%d MHz max_tx_power=%d dBm",
-				   feature->mode,
-				   feature->channels[j].chan,
-				   feature->channels[j].freq,
-				   feature->channels[j].max_tx_power);
-		}
-	}
-
-	return ret;
-}
-
-
-static int hostapd_prepare_rates(struct hostapd_data *hapd,
-				 struct hostapd_hw_modes *mode)
-{
-	int i, num_basic_rates = 0;
-	int basic_rates_a[] = { 60, 120, 240, -1 };
-	int basic_rates_b[] = { 10, 20, -1 };
-	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
-	int *basic_rates;
-
-	if (hapd->iconf->basic_rates)
-		basic_rates = hapd->iconf->basic_rates;
-	else switch (mode->mode) {
-	case HOSTAPD_MODE_IEEE80211A:
-		basic_rates = basic_rates_a;
-		break;
-	case HOSTAPD_MODE_IEEE80211B:
-		basic_rates = basic_rates_b;
-		break;
-	case HOSTAPD_MODE_IEEE80211G:
-		basic_rates = basic_rates_g;
-		break;
-	default:
-		return -1;
-	}
-
-	if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
-				  basic_rates, mode->mode)) {
-		wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
-			   "module");
-	}
-
-	os_free(hapd->iface->current_rates);
-	hapd->iface->num_rates = 0;
-
-	hapd->iface->current_rates =
-		os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
-	if (!hapd->iface->current_rates) {
-		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
-			   "table.");
-		return -1;
-	}
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct hostapd_rate_data *rate;
-
-		if (hapd->iconf->supported_rates &&
-		    !hostapd_rate_found(hapd->iconf->supported_rates,
-					mode->rates[i]))
-			continue;
-
-		rate = &hapd->iface->current_rates[hapd->iface->num_rates];
-		rate->rate = mode->rates[i];
-		if (hostapd_rate_found(basic_rates, rate->rate)) {
-			rate->flags |= HOSTAPD_RATE_BASIC;
-			num_basic_rates++;
-		}
-		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
-			   hapd->iface->num_rates, rate->rate, rate->flags);
-		hapd->iface->num_rates++;
-	}
-
-	if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
-		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
-			   "rate sets (%d,%d).",
-			   hapd->iface->num_rates, num_basic_rates);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE80211N
-static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
-{
-	int sec_chan, ok, j, first;
-	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
-			  184, 192 };
-	size_t k;
-
-	if (!iface->conf->secondary_channel)
-		return 1; /* HT40 not used */
-
-	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
-	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
-		   "secondary channel: %d",
-		   iface->conf->channel, sec_chan);
-
-	/* Verify that HT40 secondary channel is an allowed 20 MHz
-	 * channel */
-	ok = 0;
-	for (j = 0; j < iface->current_mode->num_channels; j++) {
-		struct hostapd_channel_data *chan =
-			&iface->current_mode->channels[j];
-		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-		    chan->chan == sec_chan) {
-			ok = 1;
-			break;
-		}
-	}
-	if (!ok) {
-		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
-			   sec_chan);
-		return 0;
-	}
-
-	/*
-	 * Verify that HT40 primary,secondary channel pair is allowed per
-	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
-	 * 2.4 GHz rules allow all cases where the secondary channel fits into
-	 * the list of allowed channels (already checked above).
-	 */
-	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
-		return 1;
-
-	if (iface->conf->secondary_channel > 0)
-		first = iface->conf->channel;
-	else
-		first = sec_chan;
-
-	ok = 0;
-	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
-		if (first == allowed[k]) {
-			ok = 1;
-			break;
-		}
-	}
-	if (!ok) {
-		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
-			   iface->conf->channel,
-			   iface->conf->secondary_channel);
-		return 0;
-	}
-
-	return 1;
-}
-
-
-static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
-{
-	if (iface->conf->secondary_channel > 0) {
-		iface->conf->channel += 4;
-		iface->conf->secondary_channel = -1;
-	} else {
-		iface->conf->channel -= 4;
-		iface->conf->secondary_channel = 1;
-	}
-}
-
-
-static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
-					int *pri_chan, int *sec_chan)
-{
-	struct ieee80211_ht_operation *oper;
-	struct ieee802_11_elems elems;
-
-	*pri_chan = *sec_chan = 0;
-
-	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
-	if (elems.ht_operation &&
-	    elems.ht_operation_len >= sizeof(*oper)) {
-		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
-		*pri_chan = oper->control_chan;
-		if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
-			if (oper->ht_param &
-			    HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
-				*sec_chan = *pri_chan + 4;
-			else if (oper->ht_param &
-				 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
-				*sec_chan = *pri_chan - 4;
-		}
-	}
-}
-
-
-static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
-				     struct wpa_scan_results *scan_res)
-{
-	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
-	int bss_pri_chan, bss_sec_chan;
-	size_t i;
-	int match;
-
-	pri_chan = iface->conf->channel;
-	sec_chan = iface->conf->secondary_channel * 4;
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
-	if (iface->conf->secondary_channel > 0)
-		sec_freq = pri_freq + 20;
-	else
-		sec_freq = pri_freq - 20;
-
-	/*
-	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
-	 * channel, but not on selected PRI channel.
-	 */
-	pri_bss = sec_bss = 0;
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		if (bss->freq == pri_freq)
-			pri_bss++;
-		else if (bss->freq == sec_freq)
-			sec_bss++;
-	}
-	if (sec_bss && !pri_bss) {
-		wpa_printf(MSG_INFO, "Switch own primary and secondary "
-			   "channel to get secondary channel with no Beacons "
-			   "from other BSSes");
-		ieee80211n_switch_pri_sec(iface);
-	}
-
-	/*
-	 * Match PRI/SEC channel with any existing HT40 BSS on the same
-	 * channels that we are about to use (if already mixed order in
-	 * existing BSSes, use own preference).
-	 */
-	match = 0;
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
-		if (pri_chan == bss_pri_chan &&
-		    sec_chan == bss_sec_chan) {
-			match = 1;
-			break;
-		}
-	}
-	if (!match) {
-		for (i = 0; i < scan_res->num; i++) {
-			struct wpa_scan_res *bss = scan_res->res[i];
-			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
-						    &bss_sec_chan);
-			if (pri_chan == bss_sec_chan &&
-			    sec_chan == bss_pri_chan) {
-				wpa_printf(MSG_INFO, "Switch own primary and "
-					   "secondary channel due to BSS "
-					   "overlap with " MACSTR,
-					   MAC2STR(bss->bssid));
-				ieee80211n_switch_pri_sec(iface);
-				break;
-			}
-		}
-	}
-
-	return 1;
-}
-
-
-static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
-				      struct wpa_scan_results *scan_res)
-{
-	int pri_freq, sec_freq;
-	int affected_start, affected_end;
-	size_t i;
-
-	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
-	if (iface->conf->secondary_channel > 0)
-		sec_freq = pri_freq + 20;
-	else
-		sec_freq = pri_freq - 20;
-	affected_start = (pri_freq + sec_freq) / 2 - 25;
-	affected_end = (pri_freq + sec_freq) / 2 + 25;
-	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
-		   affected_start, affected_end);
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		int pri = bss->freq;
-		int sec = pri;
-		int sec_chan, pri_chan;
-
-		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
-		if (sec_chan) {
-			if (sec_chan < pri_chan)
-				sec = pri - 20;
-			else
-				sec = pri + 20;
-		}
-
-		if ((pri < affected_start || pri > affected_end) &&
-		    (sec < affected_start || sec > affected_end))
-			continue; /* not within affected channel range */
-
-		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
-			   " freq=%d pri=%d sec=%d",
-			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
-		if (sec_chan) {
-			if (pri_freq != pri || sec_freq != sec) {
-				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
-					   "mismatch with BSS " MACSTR
-					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
-					   MAC2STR(bss->bssid),
-					   pri, sec, pri_chan,
-					   sec > pri ? '+' : '-',
-					   pri_freq, sec_freq);
-				return 0;
-			}
-		}
-
-		/* TODO: 40 MHz intolerant */
-	}
-
-	return 1;
-}
-
-
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
-static void ieee80211n_check_scan(struct hostapd_iface *iface)
-{
-	struct wpa_scan_results *scan_res;
-	int oper40;
-
-	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
-	 * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
-
-	iface->scan_cb = NULL;
-
-	scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
-	if (scan_res == NULL) {
-		hostapd_setup_interface_complete(iface, 1);
-		return;
-	}
-
-	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
-		oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
-	else
-		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
-	wpa_scan_results_free(scan_res);
-
-	if (!oper40) {
-		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
-			   "channel pri=%d sec=%d based on overlapping BSSes",
-			   iface->conf->channel,
-			   iface->conf->channel +
-			   iface->conf->secondary_channel * 4);
-		iface->conf->secondary_channel = 0;
-		iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
-	}
-
-	hostapd_setup_interface_complete(iface, 0);
-}
-
-
-static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
-{
-	struct wpa_driver_scan_params params;
-
-	if (!iface->conf->secondary_channel)
-		return 0; /* HT40 not used */
-
-	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
-		   "40 MHz channel");
-	os_memset(&params, 0, sizeof(params));
-	/* TODO: scan only the needed frequency */
-	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to request a scan of "
-			   "neighboring BSSes");
-		return -1;
-	}
-
-	iface->scan_cb = ieee80211n_check_scan;
-	return 1;
-}
-
-
-static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
-{
-	u16 hw = iface->current_mode->ht_capab;
-	u16 conf = iface->conf->ht_capab;
-
-	if (!iface->conf->ieee80211n)
-		return 1;
-
-	if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
-	    !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [LDPC]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
-	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [HT40*]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
-	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [SMPS-*]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
-	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [GF]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
-	    !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [SHORT-GI-20]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
-	    !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [SHORT-GI-40]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [TX-STBC]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
-	    (hw & HT_CAP_INFO_RX_STBC_MASK)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [RX-STBC*]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_DELAYED_BA) &&
-	    !(hw & HT_CAP_INFO_DELAYED_BA)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [DELAYED-BA]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
-	    !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [MAX-AMSDU-7935]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
-	    !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [DSSS_CCK-40]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [PSMP]");
-		return 0;
-	}
-
-	if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
-	    !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [LSIG-TXOP-PROT]");
-		return 0;
-	}
-
-	return 1;
-}
-
-#endif /* CONFIG_IEEE80211N */
-
-
-int hostapd_check_ht_capab(struct hostapd_iface *iface)
-{
-#ifdef CONFIG_IEEE80211N
-	int ret;
-	ret = ieee80211n_check_40mhz(iface);
-	if (ret)
-		return ret;
-	if (!ieee80211n_allowed_ht40_channel_pair(iface))
-		return -1;
-	if (!ieee80211n_supported_ht_capab(iface))
-		return -1;
-#endif /* CONFIG_IEEE80211N */
-
-	return 0;
-}
-
-
-/**
- * hostapd_select_hw_mode - Select the hardware mode
- * @iface: Pointer to interface data.
- * Returns: 0 on success, -1 on failure
- *
- * Sets up the hardware mode, channel, rates, and passive scanning
- * based on the configuration.
- */
-int hostapd_select_hw_mode(struct hostapd_iface *iface)
-{
-	int i, j, ok;
-
-	if (iface->num_hw_features < 1)
-		return -1;
-
-	iface->current_mode = NULL;
-	for (i = 0; i < iface->num_hw_features; i++) {
-		struct hostapd_hw_modes *mode = &iface->hw_features[i];
-		if (mode->mode == iface->conf->hw_mode) {
-			iface->current_mode = mode;
-			break;
-		}
-	}
-
-	if (iface->current_mode == NULL) {
-		wpa_printf(MSG_ERROR, "Hardware does not support configured "
-			   "mode");
-		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_WARNING,
-			       "Hardware does not support configured mode "
-			       "(%d)", (int) iface->conf->hw_mode);
-		return -1;
-	}
-
-	ok = 0;
-	for (j = 0; j < iface->current_mode->num_channels; j++) {
-		struct hostapd_channel_data *chan =
-			&iface->current_mode->channels[j];
-		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-		    (chan->chan == iface->conf->channel)) {
-			ok = 1;
-			break;
-		}
-	}
-	if (iface->conf->channel == 0) {
-		/* TODO: could request a scan of neighboring BSSes and select
-		 * the channel automatically */
-		wpa_printf(MSG_ERROR, "Channel not configured "
-			   "(hw_mode/channel in hostapd.conf)");
-		return -1;
-	}
-	if (ok == 0 && iface->conf->channel != 0) {
-		hostapd_logger(iface->bss[0], NULL,
-			       HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_WARNING,
-			       "Configured channel (%d) not found from the "
-			       "channel list of current mode (%d) %s",
-			       iface->conf->channel,
-			       iface->current_mode->mode,
-			       hostapd_hw_mode_txt(iface->current_mode->mode));
-		iface->current_mode = NULL;
-	}
-
-	if (iface->current_mode == NULL) {
-		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_WARNING,
-			       "Hardware does not support configured channel");
-		return -1;
-	}
-
-	if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
-		wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
-		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
-					   HOSTAPD_LEVEL_WARNING,
-					   "Failed to prepare rates table.");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-const char * hostapd_hw_mode_txt(int mode)
-{
-	switch (mode) {
-	case HOSTAPD_MODE_IEEE80211A:
-		return "IEEE 802.11a";
-	case HOSTAPD_MODE_IEEE80211B:
-		return "IEEE 802.11b";
-	case HOSTAPD_MODE_IEEE80211G:
-		return "IEEE 802.11g";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
-{
-	int i;
-
-	if (!hapd->iface->current_mode)
-		return 0;
-
-	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
-		struct hostapd_channel_data *ch =
-			&hapd->iface->current_mode->channels[i];
-		if (ch->chan == chan)
-			return ch->freq;
-	}
-
-	return 0;
-}
-
-
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
-{
-	int i;
-
-	if (!hapd->iface->current_mode)
-		return 0;
-
-	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
-		struct hostapd_channel_data *ch =
-			&hapd->iface->current_mode->channels[i];
-		if (ch->freq == freq)
-			return ch->chan;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/ap/hw_features.c (from rev 9639, vendor/wpa/dist/src/ap/hw_features.c)
===================================================================
--- vendor/wpa/2.0/src/ap/hw_features.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hw_features.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,802 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "hw_features.h"
+
+
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features)
+{
+	size_t i;
+
+	if (hw_features == NULL)
+		return;
+
+	for (i = 0; i < num_hw_features; i++) {
+		os_free(hw_features[i].channels);
+		os_free(hw_features[i].rates);
+	}
+
+	os_free(hw_features);
+}
+
+
+int hostapd_get_hw_features(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int ret = 0, i, j;
+	u16 num_modes, flags;
+	struct hostapd_hw_modes *modes;
+
+	if (hostapd_drv_none(hapd))
+		return -1;
+	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
+	if (modes == NULL) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Fetching hardware channel/rate support not "
+			       "supported.");
+		return -1;
+	}
+
+	iface->hw_flags = flags;
+
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = modes;
+	iface->num_hw_features = num_modes;
+
+	for (i = 0; i < num_modes; i++) {
+		struct hostapd_hw_modes *feature = &modes[i];
+		/* set flag for channels we can use in current regulatory
+		 * domain */
+		for (j = 0; j < feature->num_channels; j++) {
+			/*
+			 * Disable all channels that are marked not to allow
+			 * IBSS operation or active scanning. In addition,
+			 * disable all channels that require radar detection,
+			 * since that (in addition to full DFS) is not yet
+			 * supported.
+			 */
+			if (feature->channels[j].flag &
+			    (HOSTAPD_CHAN_NO_IBSS |
+			     HOSTAPD_CHAN_PASSIVE_SCAN |
+			     HOSTAPD_CHAN_RADAR))
+				feature->channels[j].flag |=
+					HOSTAPD_CHAN_DISABLED;
+			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
+				   "chan=%d freq=%d MHz max_tx_power=%d dBm",
+				   feature->mode,
+				   feature->channels[j].chan,
+				   feature->channels[j].freq,
+				   feature->channels[j].max_tx_power);
+		}
+	}
+
+	return ret;
+}
+
+
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+			  struct hostapd_hw_modes *mode)
+{
+	int i, num_basic_rates = 0;
+	int basic_rates_a[] = { 60, 120, 240, -1 };
+	int basic_rates_b[] = { 10, 20, -1 };
+	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
+	int *basic_rates;
+
+	if (iface->conf->basic_rates)
+		basic_rates = iface->conf->basic_rates;
+	else switch (mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		basic_rates = basic_rates_a;
+		break;
+	case HOSTAPD_MODE_IEEE80211B:
+		basic_rates = basic_rates_b;
+		break;
+	case HOSTAPD_MODE_IEEE80211G:
+		basic_rates = basic_rates_g;
+		break;
+	case HOSTAPD_MODE_IEEE80211AD:
+		return 0; /* No basic rates for 11ad */
+	default:
+		return -1;
+	}
+
+	i = 0;
+	while (basic_rates[i] >= 0)
+		i++;
+	if (i)
+		i++; /* -1 termination */
+	os_free(iface->basic_rates);
+	iface->basic_rates = os_malloc(i * sizeof(int));
+	if (iface->basic_rates)
+		os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
+
+	os_free(iface->current_rates);
+	iface->num_rates = 0;
+
+	iface->current_rates =
+		os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
+	if (!iface->current_rates) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
+			   "table.");
+		return -1;
+	}
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct hostapd_rate_data *rate;
+
+		if (iface->conf->supported_rates &&
+		    !hostapd_rate_found(iface->conf->supported_rates,
+					mode->rates[i]))
+			continue;
+
+		rate = &iface->current_rates[iface->num_rates];
+		rate->rate = mode->rates[i];
+		if (hostapd_rate_found(basic_rates, rate->rate)) {
+			rate->flags |= HOSTAPD_RATE_BASIC;
+			num_basic_rates++;
+		}
+		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
+			   iface->num_rates, rate->rate, rate->flags);
+		iface->num_rates++;
+	}
+
+	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
+		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
+			   "rate sets (%d,%d).",
+			   iface->num_rates, num_basic_rates);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211N
+static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
+{
+	int sec_chan, ok, j, first;
+	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			  184, 192 };
+	size_t k;
+
+	if (!iface->conf->secondary_channel)
+		return 1; /* HT40 not used */
+
+	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
+	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
+		   "secondary channel: %d",
+		   iface->conf->channel, sec_chan);
+
+	/* Verify that HT40 secondary channel is an allowed 20 MHz
+	 * channel */
+	ok = 0;
+	for (j = 0; j < iface->current_mode->num_channels; j++) {
+		struct hostapd_channel_data *chan =
+			&iface->current_mode->channels[j];
+		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+		    chan->chan == sec_chan) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+			   sec_chan);
+		return 0;
+	}
+
+	/*
+	 * Verify that HT40 primary,secondary channel pair is allowed per
+	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+	 * 2.4 GHz rules allow all cases where the secondary channel fits into
+	 * the list of allowed channels (already checked above).
+	 */
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 1;
+
+	if (iface->conf->secondary_channel > 0)
+		first = iface->conf->channel;
+	else
+		first = sec_chan;
+
+	ok = 0;
+	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+		if (first == allowed[k]) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+			   iface->conf->channel,
+			   iface->conf->secondary_channel);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
+{
+	if (iface->conf->secondary_channel > 0) {
+		iface->conf->channel += 4;
+		iface->conf->secondary_channel = -1;
+	} else {
+		iface->conf->channel -= 4;
+		iface->conf->secondary_channel = 1;
+	}
+}
+
+
+static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
+					int *pri_chan, int *sec_chan)
+{
+	struct ieee80211_ht_operation *oper;
+	struct ieee802_11_elems elems;
+
+	*pri_chan = *sec_chan = 0;
+
+	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+	if (elems.ht_operation &&
+	    elems.ht_operation_len >= sizeof(*oper)) {
+		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+		*pri_chan = oper->control_chan;
+		if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
+			int sec = oper->ht_param &
+				HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+			if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+				*sec_chan = *pri_chan + 4;
+			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+				*sec_chan = *pri_chan - 4;
+		}
+	}
+}
+
+
+static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
+				     struct wpa_scan_results *scan_res)
+{
+	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
+	int bss_pri_chan, bss_sec_chan;
+	size_t i;
+	int match;
+
+	pri_chan = iface->conf->channel;
+	sec_chan = iface->conf->secondary_channel * 4;
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+
+	/*
+	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
+	 * channel, but not on selected PRI channel.
+	 */
+	pri_bss = sec_bss = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		if (bss->freq == pri_freq)
+			pri_bss++;
+		else if (bss->freq == sec_freq)
+			sec_bss++;
+	}
+	if (sec_bss && !pri_bss) {
+		wpa_printf(MSG_INFO, "Switch own primary and secondary "
+			   "channel to get secondary channel with no Beacons "
+			   "from other BSSes");
+		ieee80211n_switch_pri_sec(iface);
+	}
+
+	/*
+	 * Match PRI/SEC channel with any existing HT40 BSS on the same
+	 * channels that we are about to use (if already mixed order in
+	 * existing BSSes, use own preference).
+	 */
+	match = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+		if (pri_chan == bss_pri_chan &&
+		    sec_chan == bss_sec_chan) {
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {
+		for (i = 0; i < scan_res->num; i++) {
+			struct wpa_scan_res *bss = scan_res->res[i];
+			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
+						    &bss_sec_chan);
+			if (pri_chan == bss_sec_chan &&
+			    sec_chan == bss_pri_chan) {
+				wpa_printf(MSG_INFO, "Switch own primary and "
+					   "secondary channel due to BSS "
+					   "overlap with " MACSTR,
+					   MAC2STR(bss->bssid));
+				ieee80211n_switch_pri_sec(iface);
+				break;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
+				      struct wpa_scan_results *scan_res)
+{
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	size_t i;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		int pri = bss->freq;
+		int sec = pri;
+		int sec_chan, pri_chan;
+
+		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+		if (sec_chan) {
+			if (sec_chan < pri_chan)
+				sec = pri - 20;
+			else
+				sec = pri + 20;
+		}
+
+		if ((pri < affected_start || pri > affected_end) &&
+		    (sec < affected_start || sec > affected_end))
+			continue; /* not within affected channel range */
+
+		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+			   " freq=%d pri=%d sec=%d",
+			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+		if (sec_chan) {
+			if (pri_freq != pri || sec_freq != sec) {
+				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
+					   "mismatch with BSS " MACSTR
+					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+					   MAC2STR(bss->bssid),
+					   pri, sec, pri_chan,
+					   sec > pri ? '+' : '-',
+					   pri_freq, sec_freq);
+				return 0;
+			}
+		}
+
+		/* TODO: 40 MHz intolerant */
+	}
+
+	return 1;
+}
+
+
+static void ieee80211n_check_scan(struct hostapd_iface *iface)
+{
+	struct wpa_scan_results *scan_res;
+	int oper40;
+	int res;
+
+	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
+	 * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
+
+	iface->scan_cb = NULL;
+
+	scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
+	if (scan_res == NULL) {
+		hostapd_setup_interface_complete(iface, 1);
+		return;
+	}
+
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
+		oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
+	else
+		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
+	wpa_scan_results_free(scan_res);
+
+	if (!oper40) {
+		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
+			   "channel pri=%d sec=%d based on overlapping BSSes",
+			   iface->conf->channel,
+			   iface->conf->channel +
+			   iface->conf->secondary_channel * 4);
+		iface->conf->secondary_channel = 0;
+		iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+	}
+
+	res = ieee80211n_allowed_ht40_channel_pair(iface);
+	hostapd_setup_interface_complete(iface, !res);
+}
+
+
+static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
+					 struct wpa_driver_scan_params *params)
+{
+	/* Scan only the affected frequency range */
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	int i, pos;
+	struct hostapd_hw_modes *mode;
+
+	if (iface->current_mode == NULL)
+		return;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+
+	mode = iface->current_mode;
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	pos = 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (chan->freq < affected_start ||
+		    chan->freq > affected_end)
+			continue;
+		params->freqs[pos++] = chan->freq;
+	}
+}
+
+
+static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
+{
+	struct wpa_driver_scan_params params;
+
+	if (!iface->conf->secondary_channel)
+		return 0; /* HT40 not used */
+
+	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
+		   "40 MHz channel");
+	os_memset(&params, 0, sizeof(params));
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		ieee80211n_scan_channels_2g4(iface, &params);
+	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to request a scan of "
+			   "neighboring BSSes");
+		os_free(params.freqs);
+		return -1;
+	}
+	os_free(params.freqs);
+
+	iface->scan_cb = ieee80211n_check_scan;
+	return 1;
+}
+
+
+static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
+{
+	u16 hw = iface->current_mode->ht_capab;
+	u16 conf = iface->conf->ht_capab;
+
+	if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
+	    !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [LDPC]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [HT40*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
+	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SMPS-*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
+	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [GF]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
+	    !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SHORT-GI-20]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
+	    !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SHORT-GI-40]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [TX-STBC]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
+	    (hw & HT_CAP_INFO_RX_STBC_MASK)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [RX-STBC*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_DELAYED_BA) &&
+	    !(hw & HT_CAP_INFO_DELAYED_BA)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [DELAYED-BA]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
+	    !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [MAX-AMSDU-7935]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
+	    !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [DSSS_CCK-40]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [PSMP]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
+	    !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [LSIG-TXOP-PROT]");
+		return 0;
+	}
+
+	return 1;
+}
+
+#endif /* CONFIG_IEEE80211N */
+
+
+int hostapd_check_ht_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211N
+	int ret;
+	if (!iface->conf->ieee80211n)
+		return 0;
+	if (!ieee80211n_supported_ht_capab(iface))
+		return -1;
+	ret = ieee80211n_check_40mhz(iface);
+	if (ret)
+		return ret;
+	if (!ieee80211n_allowed_ht40_channel_pair(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211N */
+
+	return 0;
+}
+
+
+/**
+ * hostapd_select_hw_mode - Select the hardware mode
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, < 0 on failure
+ *
+ * Sets up the hardware mode, channel, rates, and passive scanning
+ * based on the configuration.
+ */
+int hostapd_select_hw_mode(struct hostapd_iface *iface)
+{
+	int i, j, ok;
+
+	if (iface->num_hw_features < 1)
+		return -1;
+
+	iface->current_mode = NULL;
+	for (i = 0; i < iface->num_hw_features; i++) {
+		struct hostapd_hw_modes *mode = &iface->hw_features[i];
+		if (mode->mode == iface->conf->hw_mode) {
+			iface->current_mode = mode;
+			break;
+		}
+	}
+
+	if (iface->current_mode == NULL) {
+		wpa_printf(MSG_ERROR, "Hardware does not support configured "
+			   "mode");
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured mode "
+			       "(%d) (hw_mode in hostapd.conf)",
+			       (int) iface->conf->hw_mode);
+		return -2;
+	}
+
+	ok = 0;
+	for (j = 0; j < iface->current_mode->num_channels; j++) {
+		struct hostapd_channel_data *chan =
+			&iface->current_mode->channels[j];
+		if (chan->chan == iface->conf->channel) {
+			if (chan->flag & HOSTAPD_CHAN_DISABLED) {
+				wpa_printf(MSG_ERROR,
+					   "channel [%i] (%i) is disabled for "
+					   "use in AP mode, flags: 0x%x%s%s%s",
+					   j, chan->chan, chan->flag,
+					   chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+					   " NO-IBSS" : "",
+					   chan->flag &
+					   HOSTAPD_CHAN_PASSIVE_SCAN ?
+					   " PASSIVE-SCAN" : "",
+					   chan->flag & HOSTAPD_CHAN_RADAR ?
+					   " RADAR" : "");
+			} else {
+				ok = 1;
+				break;
+			}
+		}
+	}
+	if (ok && iface->conf->secondary_channel) {
+		int sec_ok = 0;
+		int sec_chan = iface->conf->channel +
+			iface->conf->secondary_channel * 4;
+		for (j = 0; j < iface->current_mode->num_channels; j++) {
+			struct hostapd_channel_data *chan =
+				&iface->current_mode->channels[j];
+			if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+			    (chan->chan == sec_chan)) {
+				sec_ok = 1;
+				break;
+			}
+		}
+		if (!sec_ok) {
+			hostapd_logger(iface->bss[0], NULL,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_WARNING,
+				       "Configured HT40 secondary channel "
+				       "(%d) not found from the channel list "
+				       "of current mode (%d) %s",
+				       sec_chan, iface->current_mode->mode,
+				       hostapd_hw_mode_txt(
+					       iface->current_mode->mode));
+			ok = 0;
+		}
+	}
+	if (iface->conf->channel == 0) {
+		/* TODO: could request a scan of neighboring BSSes and select
+		 * the channel automatically */
+		wpa_printf(MSG_ERROR, "Channel not configured "
+			   "(hw_mode/channel in hostapd.conf)");
+		return -3;
+	}
+	if (ok == 0 && iface->conf->channel != 0) {
+		hostapd_logger(iface->bss[0], NULL,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Configured channel (%d) not found from the "
+			       "channel list of current mode (%d) %s",
+			       iface->conf->channel,
+			       iface->current_mode->mode,
+			       hostapd_hw_mode_txt(iface->current_mode->mode));
+		iface->current_mode = NULL;
+	}
+
+	if (iface->current_mode == NULL) {
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured channel");
+		return -4;
+	}
+
+	return 0;
+}
+
+
+const char * hostapd_hw_mode_txt(int mode)
+{
+	switch (mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		return "IEEE 802.11a";
+	case HOSTAPD_MODE_IEEE80211B:
+		return "IEEE 802.11b";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "IEEE 802.11g";
+	case HOSTAPD_MODE_IEEE80211AD:
+		return "IEEE 802.11ad";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->chan == chan)
+			return ch->freq;
+	}
+
+	return 0;
+}
+
+
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->freq == freq)
+			return ch->chan;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/ap/hw_features.h
===================================================================
--- vendor/wpa/dist/src/ap/hw_features.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/hw_features.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,62 +0,0 @@
-/*
- * hostapd / Hardware feature query and different modes
- * Copyright 2002-2003, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HW_FEATURES_H
-#define HW_FEATURES_H
-
-#ifdef NEED_AP_MLME
-void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
-			      size_t num_hw_features);
-int hostapd_get_hw_features(struct hostapd_iface *iface);
-int hostapd_select_hw_mode(struct hostapd_iface *iface);
-const char * hostapd_hw_mode_txt(int mode);
-int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
-int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
-int hostapd_check_ht_capab(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void
-hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
-			 size_t num_hw_features)
-{
-}
-
-static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
-{
-	return -1;
-}
-
-static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
-{
-	return -1;
-}
-
-static inline const char * hostapd_hw_mode_txt(int mode)
-{
-	return NULL;
-}
-
-static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
-{
-	return -1;
-}
-
-static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
-{
-	return 0;
-}
-
-#endif /* NEED_AP_MLME */
-
-#endif /* HW_FEATURES_H */

Copied: vendor/wpa/2.0/src/ap/hw_features.h (from rev 9639, vendor/wpa/dist/src/ap/hw_features.h)
===================================================================
--- vendor/wpa/2.0/src/ap/hw_features.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/hw_features.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef HW_FEATURES_H
+#define HW_FEATURES_H
+
+#ifdef NEED_AP_MLME
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features);
+int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_select_hw_mode(struct hostapd_iface *iface);
+const char * hostapd_hw_mode_txt(int mode);
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+			  struct hostapd_hw_modes *mode);
+#else /* NEED_AP_MLME */
+static inline void
+hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			 size_t num_hw_features)
+{
+}
+
+static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
+{
+	return -1;
+}
+
+static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
+{
+	return -100;
+}
+
+static inline const char * hostapd_hw_mode_txt(int mode)
+{
+	return NULL;
+}
+
+static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
+{
+	return -1;
+}
+
+static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
+{
+	return 0;
+}
+
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
+					struct hostapd_hw_modes *mode)
+{
+	return 0;
+}
+
+#endif /* NEED_AP_MLME */
+
+#endif /* HW_FEATURES_H */

Deleted: vendor/wpa/2.0/src/ap/iapp.c
===================================================================
--- vendor/wpa/dist/src/ap/iapp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/iapp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,535 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
- * and IEEE has withdrawn it. In other words, it is likely better to look at
- * using some other mechanism for AP-to-AP communication than extending the
- * implementation here.
- */
-
-/* TODO:
- * Level 1: no administrative or security support
- *	(e.g., static BSSID to IP address mapping in each AP)
- * Level 2: support for dynamic mapping of BSSID to IP address
- * Level 3: support for encryption and authentication of IAPP messages
- * - add support for MOVE-notify and MOVE-response (this requires support for
- *   finding out IP address for previous AP using RADIUS)
- * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
- *   reassociation to another AP
- * - implement counters etc. for IAPP MIB
- * - verify endianness of fields in IAPP messages; are they big-endian as
- *   used here?
- * - RADIUS connection for AP registration and BSSID to IP address mapping
- * - TCP connection for IAPP MOVE, CACHE
- * - broadcast ESP for IAPP ADD-notify
- * - ESP for IAPP MOVE messages
- * - security block sending/processing
- * - IEEE 802.11 context transfer
- */
-
-#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"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
-#include "iapp.h"
-
-
-#define IAPP_MULTICAST "224.0.1.178"
-#define IAPP_UDP_PORT 3517
-#define IAPP_TCP_PORT 3517
-
-struct iapp_hdr {
-	u8 version;
-	u8 command;
-	be16 identifier;
-	be16 length;
-	/* followed by length-6 octets of data */
-} __attribute__ ((packed));
-
-#define IAPP_VERSION 0
-
-enum IAPP_COMMAND {
-	IAPP_CMD_ADD_notify = 0,
-	IAPP_CMD_MOVE_notify = 1,
-	IAPP_CMD_MOVE_response = 2,
-	IAPP_CMD_Send_Security_Block = 3,
-	IAPP_CMD_ACK_Security_Block = 4,
-	IAPP_CMD_CACHE_notify = 5,
-	IAPP_CMD_CACHE_response = 6,
-};
-
-
-/* ADD-notify - multicast UDP on the local LAN */
-struct iapp_add_notify {
-	u8 addr_len; /* ETH_ALEN */
-	u8 reserved;
-	u8 mac_addr[ETH_ALEN];
-	be16 seq_num;
-} __attribute__ ((packed));
-
-
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
-struct iapp_layer2_update {
-	u8 da[ETH_ALEN]; /* broadcast */
-	u8 sa[ETH_ALEN]; /* STA addr */
-	be16 len; /* 6 */
-	u8 dsap; /* null DSAP address */
-	u8 ssap; /* null SSAP address, CR=Response */
-	u8 control;
-	u8 xid_info[3];
-} __attribute__ ((packed));
-
-
-/* MOVE-notify - unicast TCP */
-struct iapp_move_notify {
-	u8 addr_len; /* ETH_ALEN */
-	u8 reserved;
-	u8 mac_addr[ETH_ALEN];
-	u16 seq_num;
-	u16 ctx_block_len;
-	/* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-
-/* MOVE-response - unicast TCP */
-struct iapp_move_response {
-	u8 addr_len; /* ETH_ALEN */
-	u8 status;
-	u8 mac_addr[ETH_ALEN];
-	u16 seq_num;
-	u16 ctx_block_len;
-	/* followed by ctx_block_len bytes */
-} __attribute__ ((packed));
-
-enum {
-	IAPP_MOVE_SUCCESSFUL = 0,
-	IAPP_MOVE_DENIED = 1,
-	IAPP_MOVE_STALE_MOVE = 2,
-};
-
-
-/* CACHE-notify */
-struct iapp_cache_notify {
-	u8 addr_len; /* ETH_ALEN */
-	u8 reserved;
-	u8 mac_addr[ETH_ALEN];
-	u16 seq_num;
-	u8 current_ap[ETH_ALEN];
-	u16 ctx_block_len;
-	/* ctx_block_len bytes of context block followed by 16-bit context
-	 * timeout */
-} __attribute__ ((packed));
-
-
-/* CACHE-response - unicast TCP */
-struct iapp_cache_response {
-	u8 addr_len; /* ETH_ALEN */
-	u8 status;
-	u8 mac_addr[ETH_ALEN];
-	u16 seq_num;
-} __attribute__ ((packed));
-
-enum {
-	IAPP_CACHE_SUCCESSFUL = 0,
-	IAPP_CACHE_STALE_CACHE = 1,
-};
-
-
-/* Send-Security-Block - unicast TCP */
-struct iapp_send_security_block {
-	u8 iv[8];
-	u16 sec_block_len;
-	/* followed by sec_block_len bytes of security block */
-} __attribute__ ((packed));
-
-
-/* ACK-Security-Block - unicast TCP */
-struct iapp_ack_security_block {
-	u8 iv[8];
-	u8 new_ap_ack_authenticator[48];
-} __attribute__ ((packed));
-
-
-struct iapp_data {
-	struct hostapd_data *hapd;
-	u16 identifier; /* next IAPP identifier */
-	struct in_addr own, multicast;
-	int udp_sock;
-	int packet_sock;
-};
-
-
-static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
-{
-	char buf[128];
-	struct iapp_hdr *hdr;
-	struct iapp_add_notify *add;
-	struct sockaddr_in addr;
-
-	/* Send IAPP ADD-notify to remove possible association from other APs
-	 */
-
-	hdr = (struct iapp_hdr *) buf;
-	hdr->version = IAPP_VERSION;
-	hdr->command = IAPP_CMD_ADD_notify;
-	hdr->identifier = host_to_be16(iapp->identifier++);
-	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
-
-	add = (struct iapp_add_notify *) (hdr + 1);
-	add->addr_len = ETH_ALEN;
-	add->reserved = 0;
-	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
-
-	add->seq_num = host_to_be16(seq_num);
-	
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = iapp->multicast.s_addr;
-	addr.sin_port = htons(IAPP_UDP_PORT);
-	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
-		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
-		perror("sendto[IAPP-ADD]");
-}
-
-
-static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
-{
-	struct iapp_layer2_update msg;
-
-	/* Send Level 2 Update Frame to update forwarding tables in layer 2
-	 * bridge devices */
-
-	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
-	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
-
-	os_memset(msg.da, 0xff, ETH_ALEN);
-	os_memcpy(msg.sa, addr, ETH_ALEN);
-	msg.len = host_to_be16(6);
-	msg.dsap = 0; /* NULL DSAP address */
-	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
-	msg.control = 0xaf; /* XID response lsb.1111F101.
-			     * F=0 (no poll command; unsolicited frame) */
-	msg.xid_info[0] = 0x81; /* XID format identifier */
-	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
-	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
-				   * FIX: what is correct RW with 802.11? */
-
-	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
-		perror("send[L2 Update]");
-}
-
-
-/**
- * iapp_new_station - IAPP processing for a new STA
- * @iapp: IAPP data
- * @sta: The associated station
- */
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
-{
-	struct ieee80211_mgmt *assoc;
-	u16 seq;
-
-	if (iapp == NULL)
-		return;
-
-	assoc = sta->last_assoc_req;
-	seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
-
-	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
-	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
-		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
-	iapp_send_layer2_update(iapp, sta->addr);
-	iapp_send_add(iapp, sta->addr, seq);
-
-	if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
-	    WLAN_FC_STYPE_REASSOC_REQ) {
-		/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
-		 *                   Context Block, Timeout)
-		 */
-		/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
-		 * IP address */
-	}
-}
-
-
-static void iapp_process_add_notify(struct iapp_data *iapp,
-				    struct sockaddr_in *from,
-				    struct iapp_hdr *hdr, int len)
-{
-	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
-	struct sta_info *sta;
-
-	if (len != sizeof(*add)) {
-		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
-		       len, (unsigned long) sizeof(*add));
-		return;
-	}
-
-	sta = ap_get_sta(iapp->hapd, add->mac_addr);
-
-	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
-	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
-		       HOSTAPD_LEVEL_INFO,
-		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
-		       be_to_host16(add->seq_num),
-		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
-		       sta ? "" : " (STA not found)");
-
-	if (!sta)
-		return;
-
-	/* TODO: could use seq_num to try to determine whether last association
-	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
-	 * this is not really a reliable verification. */
-
-	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Removing STA due to IAPP ADD-notify");
-	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
-}
-
-
-/**
- * iapp_receive_udp - Process IAPP UDP frames
- * @sock: File descriptor for the socket
- * @eloop_ctx: IAPP data (struct iapp_data *)
- * @sock_ctx: Not used
- */
-static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct iapp_data *iapp = eloop_ctx;
-	int len, hlen;
-	unsigned char buf[128];
-	struct sockaddr_in from;
-	socklen_t fromlen;
-	struct iapp_hdr *hdr;
-
-	/* Handle incoming IAPP frames (over UDP/IP) */
-
-	fromlen = sizeof(from);
-	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (len < 0) {
-		perror("recvfrom");
-		return;
-	}
-
-	if (from.sin_addr.s_addr == iapp->own.s_addr)
-		return; /* ignore own IAPP messages */
-
-	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Received %d byte IAPP frame from %s%s\n",
-		       len, inet_ntoa(from.sin_addr),
-		       len < (int) sizeof(*hdr) ? " (too short)" : "");
-
-	if (len < (int) sizeof(*hdr))
-		return;
-
-	hdr = (struct iapp_hdr *) buf;
-	hlen = be_to_host16(hdr->length);
-	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "RX: version=%d command=%d id=%d len=%d\n",
-		       hdr->version, hdr->command,
-		       be_to_host16(hdr->identifier), hlen);
-	if (hdr->version != IAPP_VERSION) {
-		printf("Dropping IAPP frame with unknown version %d\n",
-		       hdr->version);
-		return;
-	}
-	if (hlen > len) {
-		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
-		return;
-	}
-	if (hlen < len) {
-		printf("Ignoring %d extra bytes from IAPP frame\n",
-		       len - hlen);
-		len = hlen;
-	}
-
-	switch (hdr->command) {
-	case IAPP_CMD_ADD_notify:
-		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
-		break;
-	case IAPP_CMD_MOVE_notify:
-		/* TODO: MOVE is using TCP; so move this to TCP handler once it
-		 * is implemented.. */
-		/* IAPP-MOVE.indication(MAC Address, New BSSID,
-		 * Sequence Number, AP Address, Context Block) */
-		/* TODO: process */
-		break;
-	default:
-		printf("Unknown IAPP command %d\n", hdr->command);
-		break;
-	}
-}
-
-
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
-{
-	struct ifreq ifr;
-	struct sockaddr_ll addr;
-	int ifindex;
-	struct sockaddr_in *paddr, uaddr;
-	struct iapp_data *iapp;
-	struct ip_mreqn mreq;
-
-	iapp = os_zalloc(sizeof(*iapp));
-	if (iapp == NULL)
-		return NULL;
-	iapp->hapd = hapd;
-	iapp->udp_sock = iapp->packet_sock = -1;
-
-	/* TODO:
-	 * open socket for sending and receiving IAPP frames over TCP
-	 */
-
-	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (iapp->udp_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
-	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-	ifindex = ifr.ifr_ifindex;
-
-	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFADDR)");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
-	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFADDR)\n",
-		       paddr->sin_family);
-		iapp_deinit(iapp);
-		return NULL;
-	}
-	iapp->own.s_addr = paddr->sin_addr.s_addr;
-
-	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFBRDADDR)");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
-	if (paddr->sin_family != AF_INET) {
-		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
-		       paddr->sin_family);
-		iapp_deinit(iapp);
-		return NULL;
-	}
-	inet_aton(IAPP_MULTICAST, &iapp->multicast);
-
-	os_memset(&uaddr, 0, sizeof(uaddr));
-	uaddr.sin_family = AF_INET;
-	uaddr.sin_port = htons(IAPP_UDP_PORT);
-	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
-		 sizeof(uaddr)) < 0) {
-		perror("bind[UDP]");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	os_memset(&mreq, 0, sizeof(mreq));
-	mreq.imr_multiaddr = iapp->multicast;
-	mreq.imr_address.s_addr = INADDR_ANY;
-	mreq.imr_ifindex = 0;
-	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
-		       sizeof(mreq)) < 0) {
-		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (iapp->packet_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sll_family = AF_PACKET;
-	addr.sll_ifindex = ifindex;
-	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
-		 sizeof(addr)) < 0) {
-		perror("bind[PACKET]");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
-				     iapp, NULL)) {
-		printf("Could not register read socket for IAPP.\n");
-		iapp_deinit(iapp);
-		return NULL;
-	}
-
-	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
-
-	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
-	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
-	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
-	 * is received, IAPP is not started. */
-
-	return iapp;
-}
-
-
-void iapp_deinit(struct iapp_data *iapp)
-{
-	struct ip_mreqn mreq;
-
-	if (iapp == NULL)
-		return;
-
-	if (iapp->udp_sock >= 0) {
-		os_memset(&mreq, 0, sizeof(mreq));
-		mreq.imr_multiaddr = iapp->multicast;
-		mreq.imr_address.s_addr = INADDR_ANY;
-		mreq.imr_ifindex = 0;
-		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
-			       &mreq, sizeof(mreq)) < 0) {
-			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
-		}
-
-		eloop_unregister_read_sock(iapp->udp_sock);
-		close(iapp->udp_sock);
-	}
-	if (iapp->packet_sock >= 0) {
-		eloop_unregister_read_sock(iapp->packet_sock);
-		close(iapp->packet_sock);
-	}
-	os_free(iapp);
-}

Copied: vendor/wpa/2.0/src/ap/iapp.c (from rev 9639, vendor/wpa/dist/src/ap/iapp.c)
===================================================================
--- vendor/wpa/2.0/src/ap/iapp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/iapp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,529 @@
+/*
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
+ * and IEEE has withdrawn it. In other words, it is likely better to look at
+ * using some other mechanism for AP-to-AP communication than extending the
+ * implementation here.
+ */
+
+/* TODO:
+ * Level 1: no administrative or security support
+ *	(e.g., static BSSID to IP address mapping in each AP)
+ * Level 2: support for dynamic mapping of BSSID to IP address
+ * Level 3: support for encryption and authentication of IAPP messages
+ * - add support for MOVE-notify and MOVE-response (this requires support for
+ *   finding out IP address for previous AP using RADIUS)
+ * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
+ *   reassociation to another AP
+ * - implement counters etc. for IAPP MIB
+ * - verify endianness of fields in IAPP messages; are they big-endian as
+ *   used here?
+ * - RADIUS connection for AP registration and BSSID to IP address mapping
+ * - TCP connection for IAPP MOVE, CACHE
+ * - broadcast ESP for IAPP ADD-notify
+ * - ESP for IAPP MOVE messages
+ * - security block sending/processing
+ * - IEEE 802.11 context transfer
+ */
+
+#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"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "iapp.h"
+
+
+#define IAPP_MULTICAST "224.0.1.178"
+#define IAPP_UDP_PORT 3517
+#define IAPP_TCP_PORT 3517
+
+struct iapp_hdr {
+	u8 version;
+	u8 command;
+	be16 identifier;
+	be16 length;
+	/* followed by length-6 octets of data */
+} __attribute__ ((packed));
+
+#define IAPP_VERSION 0
+
+enum IAPP_COMMAND {
+	IAPP_CMD_ADD_notify = 0,
+	IAPP_CMD_MOVE_notify = 1,
+	IAPP_CMD_MOVE_response = 2,
+	IAPP_CMD_Send_Security_Block = 3,
+	IAPP_CMD_ACK_Security_Block = 4,
+	IAPP_CMD_CACHE_notify = 5,
+	IAPP_CMD_CACHE_response = 6,
+};
+
+
+/* ADD-notify - multicast UDP on the local LAN */
+struct iapp_add_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	be16 seq_num;
+} __attribute__ ((packed));
+
+
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+	u8 da[ETH_ALEN]; /* broadcast */
+	u8 sa[ETH_ALEN]; /* STA addr */
+	be16 len; /* 6 */
+	u8 dsap; /* null DSAP address */
+	u8 ssap; /* null SSAP address, CR=Response */
+	u8 control;
+	u8 xid_info[3];
+} __attribute__ ((packed));
+
+
+/* MOVE-notify - unicast TCP */
+struct iapp_move_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u16 ctx_block_len;
+	/* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+
+/* MOVE-response - unicast TCP */
+struct iapp_move_response {
+	u8 addr_len; /* ETH_ALEN */
+	u8 status;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u16 ctx_block_len;
+	/* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+enum {
+	IAPP_MOVE_SUCCESSFUL = 0,
+	IAPP_MOVE_DENIED = 1,
+	IAPP_MOVE_STALE_MOVE = 2,
+};
+
+
+/* CACHE-notify */
+struct iapp_cache_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u8 current_ap[ETH_ALEN];
+	u16 ctx_block_len;
+	/* ctx_block_len bytes of context block followed by 16-bit context
+	 * timeout */
+} __attribute__ ((packed));
+
+
+/* CACHE-response - unicast TCP */
+struct iapp_cache_response {
+	u8 addr_len; /* ETH_ALEN */
+	u8 status;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+} __attribute__ ((packed));
+
+enum {
+	IAPP_CACHE_SUCCESSFUL = 0,
+	IAPP_CACHE_STALE_CACHE = 1,
+};
+
+
+/* Send-Security-Block - unicast TCP */
+struct iapp_send_security_block {
+	u8 iv[8];
+	u16 sec_block_len;
+	/* followed by sec_block_len bytes of security block */
+} __attribute__ ((packed));
+
+
+/* ACK-Security-Block - unicast TCP */
+struct iapp_ack_security_block {
+	u8 iv[8];
+	u8 new_ap_ack_authenticator[48];
+} __attribute__ ((packed));
+
+
+struct iapp_data {
+	struct hostapd_data *hapd;
+	u16 identifier; /* next IAPP identifier */
+	struct in_addr own, multicast;
+	int udp_sock;
+	int packet_sock;
+};
+
+
+static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
+{
+	char buf[128];
+	struct iapp_hdr *hdr;
+	struct iapp_add_notify *add;
+	struct sockaddr_in addr;
+
+	/* Send IAPP ADD-notify to remove possible association from other APs
+	 */
+
+	hdr = (struct iapp_hdr *) buf;
+	hdr->version = IAPP_VERSION;
+	hdr->command = IAPP_CMD_ADD_notify;
+	hdr->identifier = host_to_be16(iapp->identifier++);
+	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
+
+	add = (struct iapp_add_notify *) (hdr + 1);
+	add->addr_len = ETH_ALEN;
+	add->reserved = 0;
+	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
+
+	add->seq_num = host_to_be16(seq_num);
+	
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = iapp->multicast.s_addr;
+	addr.sin_port = htons(IAPP_UDP_PORT);
+	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
+		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		perror("sendto[IAPP-ADD]");
+}
+
+
+static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
+{
+	struct iapp_layer2_update msg;
+
+	/* Send Level 2 Update Frame to update forwarding tables in layer 2
+	 * bridge devices */
+
+	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+	os_memset(msg.da, 0xff, ETH_ALEN);
+	os_memcpy(msg.sa, addr, ETH_ALEN);
+	msg.len = host_to_be16(6);
+	msg.dsap = 0; /* NULL DSAP address */
+	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
+	msg.control = 0xaf; /* XID response lsb.1111F101.
+			     * F=0 (no poll command; unsolicited frame) */
+	msg.xid_info[0] = 0x81; /* XID format identifier */
+	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
+	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
+				   * FIX: what is correct RW with 802.11? */
+
+	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
+		perror("send[L2 Update]");
+}
+
+
+/**
+ * iapp_new_station - IAPP processing for a new STA
+ * @iapp: IAPP data
+ * @sta: The associated station
+ */
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
+{
+	struct ieee80211_mgmt *assoc;
+	u16 seq;
+
+	if (iapp == NULL)
+		return;
+
+	assoc = sta->last_assoc_req;
+	seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
+
+	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
+	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
+	iapp_send_layer2_update(iapp, sta->addr);
+	iapp_send_add(iapp, sta->addr, seq);
+
+	if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
+	    WLAN_FC_STYPE_REASSOC_REQ) {
+		/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
+		 *                   Context Block, Timeout)
+		 */
+		/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
+		 * IP address */
+	}
+}
+
+
+static void iapp_process_add_notify(struct iapp_data *iapp,
+				    struct sockaddr_in *from,
+				    struct iapp_hdr *hdr, int len)
+{
+	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
+	struct sta_info *sta;
+
+	if (len != sizeof(*add)) {
+		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
+		       len, (unsigned long) sizeof(*add));
+		return;
+	}
+
+	sta = ap_get_sta(iapp->hapd, add->mac_addr);
+
+	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
+	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_INFO,
+		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
+		       be_to_host16(add->seq_num),
+		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
+		       sta ? "" : " (STA not found)");
+
+	if (!sta)
+		return;
+
+	/* TODO: could use seq_num to try to determine whether last association
+	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
+	 * this is not really a reliable verification. */
+
+	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Removing STA due to IAPP ADD-notify");
+	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
+}
+
+
+/**
+ * iapp_receive_udp - Process IAPP UDP frames
+ * @sock: File descriptor for the socket
+ * @eloop_ctx: IAPP data (struct iapp_data *)
+ * @sock_ctx: Not used
+ */
+static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct iapp_data *iapp = eloop_ctx;
+	int len, hlen;
+	unsigned char buf[128];
+	struct sockaddr_in from;
+	socklen_t fromlen;
+	struct iapp_hdr *hdr;
+
+	/* Handle incoming IAPP frames (over UDP/IP) */
+
+	fromlen = sizeof(from);
+	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (len < 0) {
+		perror("recvfrom");
+		return;
+	}
+
+	if (from.sin_addr.s_addr == iapp->own.s_addr)
+		return; /* ignore own IAPP messages */
+
+	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Received %d byte IAPP frame from %s%s\n",
+		       len, inet_ntoa(from.sin_addr),
+		       len < (int) sizeof(*hdr) ? " (too short)" : "");
+
+	if (len < (int) sizeof(*hdr))
+		return;
+
+	hdr = (struct iapp_hdr *) buf;
+	hlen = be_to_host16(hdr->length);
+	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "RX: version=%d command=%d id=%d len=%d\n",
+		       hdr->version, hdr->command,
+		       be_to_host16(hdr->identifier), hlen);
+	if (hdr->version != IAPP_VERSION) {
+		printf("Dropping IAPP frame with unknown version %d\n",
+		       hdr->version);
+		return;
+	}
+	if (hlen > len) {
+		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+		return;
+	}
+	if (hlen < len) {
+		printf("Ignoring %d extra bytes from IAPP frame\n",
+		       len - hlen);
+		len = hlen;
+	}
+
+	switch (hdr->command) {
+	case IAPP_CMD_ADD_notify:
+		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+		break;
+	case IAPP_CMD_MOVE_notify:
+		/* TODO: MOVE is using TCP; so move this to TCP handler once it
+		 * is implemented.. */
+		/* IAPP-MOVE.indication(MAC Address, New BSSID,
+		 * Sequence Number, AP Address, Context Block) */
+		/* TODO: process */
+		break;
+	default:
+		printf("Unknown IAPP command %d\n", hdr->command);
+		break;
+	}
+}
+
+
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
+{
+	struct ifreq ifr;
+	struct sockaddr_ll addr;
+	int ifindex;
+	struct sockaddr_in *paddr, uaddr;
+	struct iapp_data *iapp;
+	struct ip_mreqn mreq;
+
+	iapp = os_zalloc(sizeof(*iapp));
+	if (iapp == NULL)
+		return NULL;
+	iapp->hapd = hapd;
+	iapp->udp_sock = iapp->packet_sock = -1;
+
+	/* TODO:
+	 * open socket for sending and receiving IAPP frames over TCP
+	 */
+
+	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (iapp->udp_sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	ifindex = ifr.ifr_ifindex;
+
+	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
+		perror("ioctl(SIOCGIFADDR)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+	if (paddr->sin_family != AF_INET) {
+		printf("Invalid address family %i (SIOCGIFADDR)\n",
+		       paddr->sin_family);
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	iapp->own.s_addr = paddr->sin_addr.s_addr;
+
+	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
+		perror("ioctl(SIOCGIFBRDADDR)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+	if (paddr->sin_family != AF_INET) {
+		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
+		       paddr->sin_family);
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	inet_aton(IAPP_MULTICAST, &iapp->multicast);
+
+	os_memset(&uaddr, 0, sizeof(uaddr));
+	uaddr.sin_family = AF_INET;
+	uaddr.sin_port = htons(IAPP_UDP_PORT);
+	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
+		 sizeof(uaddr)) < 0) {
+		perror("bind[UDP]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&mreq, 0, sizeof(mreq));
+	mreq.imr_multiaddr = iapp->multicast;
+	mreq.imr_address.s_addr = INADDR_ANY;
+	mreq.imr_ifindex = 0;
+	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
+		       sizeof(mreq)) < 0) {
+		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (iapp->packet_sock < 0) {
+		perror("socket[PF_PACKET,SOCK_RAW]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_ifindex = ifindex;
+	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
+		 sizeof(addr)) < 0) {
+		perror("bind[PACKET]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
+				     iapp, NULL)) {
+		printf("Could not register read socket for IAPP.\n");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+
+	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
+	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
+	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
+	 * is received, IAPP is not started. */
+
+	return iapp;
+}
+
+
+void iapp_deinit(struct iapp_data *iapp)
+{
+	struct ip_mreqn mreq;
+
+	if (iapp == NULL)
+		return;
+
+	if (iapp->udp_sock >= 0) {
+		os_memset(&mreq, 0, sizeof(mreq));
+		mreq.imr_multiaddr = iapp->multicast;
+		mreq.imr_address.s_addr = INADDR_ANY;
+		mreq.imr_ifindex = 0;
+		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
+			       &mreq, sizeof(mreq)) < 0) {
+			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+		}
+
+		eloop_unregister_read_sock(iapp->udp_sock);
+		close(iapp->udp_sock);
+	}
+	if (iapp->packet_sock >= 0) {
+		eloop_unregister_read_sock(iapp->packet_sock);
+		close(iapp->packet_sock);
+	}
+	os_free(iapp);
+}

Deleted: vendor/wpa/2.0/src/ap/iapp.h
===================================================================
--- vendor/wpa/dist/src/ap/iapp.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/iapp.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,45 +0,0 @@
-/*
- * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IAPP_H
-#define IAPP_H
-
-struct iapp_data;
-
-#ifdef CONFIG_IAPP
-
-void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
-struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
-void iapp_deinit(struct iapp_data *iapp);
-
-#else /* CONFIG_IAPP */
-
-static inline void iapp_new_station(struct iapp_data *iapp,
-				    struct sta_info *sta)
-{
-}
-
-static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
-					   const char *iface)
-{
-	return NULL;
-}
-
-static inline void iapp_deinit(struct iapp_data *iapp)
-{
-}
-
-#endif /* CONFIG_IAPP */
-
-#endif /* IAPP_H */

Copied: vendor/wpa/2.0/src/ap/iapp.h (from rev 9639, vendor/wpa/dist/src/ap/iapp.h)
===================================================================
--- vendor/wpa/2.0/src/ap/iapp.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/iapp.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,39 @@
+/*
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IAPP_H
+#define IAPP_H
+
+struct iapp_data;
+
+#ifdef CONFIG_IAPP
+
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
+void iapp_deinit(struct iapp_data *iapp);
+
+#else /* CONFIG_IAPP */
+
+static inline void iapp_new_station(struct iapp_data *iapp,
+				    struct sta_info *sta)
+{
+}
+
+static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
+					   const char *iface)
+{
+	return NULL;
+}
+
+static inline void iapp_deinit(struct iapp_data *iapp)
+{
+}
+
+#endif /* CONFIG_IAPP */
+
+#endif /* IAPP_H */

Deleted: vendor/wpa/2.0/src/ap/ieee802_11.c
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_11.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_11.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1755 +0,0 @@
-/*
- * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "crypto/crypto.h"
-#include "drivers/driver.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "wps/wps.h"
-#include "hostapd.h"
-#include "beacon.h"
-#include "ieee802_11_auth.h"
-#include "sta_info.h"
-#include "ieee802_1x.h"
-#include "wpa_auth.h"
-#include "wmm.h"
-#include "ap_list.h"
-#include "accounting.h"
-#include "ap_config.h"
-#include "ap_mlme.h"
-#include "ieee802_11.h"
-
-
-u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-	int i, num, count;
-
-	if (hapd->iface->current_rates == NULL)
-		return eid;
-
-	*pos++ = WLAN_EID_SUPP_RATES;
-	num = hapd->iface->num_rates;
-	if (num > 8) {
-		/* rest of the rates are encoded in Extended supported
-		 * rates element */
-		num = 8;
-	}
-
-	*pos++ = num;
-	count = 0;
-	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
-	     i++) {
-		count++;
-		*pos = hapd->iface->current_rates[i].rate / 5;
-		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
-			*pos |= 0x80;
-		pos++;
-	}
-
-	return pos;
-}
-
-
-u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-	int i, num, count;
-
-	if (hapd->iface->current_rates == NULL)
-		return eid;
-
-	num = hapd->iface->num_rates;
-	if (num <= 8)
-		return eid;
-	num -= 8;
-
-	*pos++ = WLAN_EID_EXT_SUPP_RATES;
-	*pos++ = num;
-	count = 0;
-	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
-	     i++) {
-		count++;
-		if (count <= 8)
-			continue; /* already in SuppRates IE */
-		*pos = hapd->iface->current_rates[i].rate / 5;
-		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
-			*pos |= 0x80;
-		pos++;
-	}
-
-	return pos;
-}
-
-
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int probe)
-{
-	int capab = WLAN_CAPABILITY_ESS;
-	int privacy;
-
-	if (hapd->iface->num_sta_no_short_preamble == 0 &&
-	    hapd->iconf->preamble == SHORT_PREAMBLE)
-		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
-
-	privacy = hapd->conf->ssid.wep.keys_set;
-
-	if (hapd->conf->ieee802_1x &&
-	    (hapd->conf->default_wep_key_len ||
-	     hapd->conf->individual_wep_key_len))
-		privacy = 1;
-
-	if (hapd->conf->wpa)
-		privacy = 1;
-
-	if (sta) {
-		int policy, def_klen;
-		if (probe && sta->ssid_probe) {
-			policy = sta->ssid_probe->security_policy;
-			def_klen = sta->ssid_probe->wep.default_len;
-		} else {
-			policy = sta->ssid->security_policy;
-			def_klen = sta->ssid->wep.default_len;
-		}
-		privacy = policy != SECURITY_PLAINTEXT;
-		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
-			privacy = 0;
-	}
-
-	if (privacy)
-		capab |= WLAN_CAPABILITY_PRIVACY;
-
-	if (hapd->iface->current_mode &&
-	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
-	    hapd->iface->num_sta_no_short_slot_time == 0)
-		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
-
-	return capab;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
-					    struct sta_info *sta, u8 *eid)
-{
-	u8 *pos = eid;
-	u32 timeout, tu;
-	struct os_time now, passed;
-
-	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-	*pos++ = 5;
-	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
-	tu = (passed.sec * 1000000 + passed.usec) / 1024;
-	if (hapd->conf->assoc_sa_query_max_timeout > tu)
-		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
-	else
-		timeout = 0;
-	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
-		timeout++; /* add some extra time for local timers */
-	WPA_PUT_LE32(pos, timeout);
-	pos += 4;
-
-	return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
-{
-	int i;
-	if (len > HOSTAPD_MAX_SSID_LEN)
-		len = HOSTAPD_MAX_SSID_LEN;
-	for (i = 0; i < len; i++) {
-		if (ssid[i] >= 32 && ssid[i] < 127)
-			buf[i] = ssid[i];
-		else
-			buf[i] = '.';
-	}
-	buf[len] = '\0';
-}
-
-
-static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
-			   u16 auth_transaction, const u8 *challenge,
-			   int iswep)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "authentication (shared key, transaction %d)",
-		       auth_transaction);
-
-	if (auth_transaction == 1) {
-		if (!sta->challenge) {
-			/* Generate a pseudo-random challenge */
-			u8 key[8];
-			time_t now;
-			int r;
-			sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
-			if (sta->challenge == NULL)
-				return WLAN_STATUS_UNSPECIFIED_FAILURE;
-
-			now = time(NULL);
-			r = random();
-			os_memcpy(key, &now, 4);
-			os_memcpy(key + 4, &r, 4);
-			rc4_skip(key, sizeof(key), 0,
-				 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
-		}
-		return 0;
-	}
-
-	if (auth_transaction != 3)
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-
-	/* Transaction 3 */
-	if (!iswep || !sta->challenge || !challenge ||
-	    os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO,
-			       "shared key authentication - invalid "
-			       "challenge-response");
-		return WLAN_STATUS_CHALLENGE_FAIL;
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "authentication OK (shared key)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
-	/* Station will be marked authenticated if it ACKs the
-	 * authentication reply. */
-#else
-	sta->flags |= WLAN_STA_AUTH;
-	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-#endif
-	os_free(sta->challenge);
-	sta->challenge = NULL;
-
-	return 0;
-}
-
-
-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)
-{
-	struct ieee80211_mgmt *reply;
-	u8 *buf;
-	size_t rlen;
-
-	rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
-	buf = os_zalloc(rlen);
-	if (buf == NULL)
-		return;
-
-	reply = (struct ieee80211_mgmt *) buf;
-	reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					    WLAN_FC_STYPE_AUTH);
-	os_memcpy(reply->da, dst, ETH_ALEN);
-	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(reply->bssid, bssid, ETH_ALEN);
-
-	reply->u.auth.auth_alg = host_to_le16(auth_alg);
-	reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
-	reply->u.auth.status_code = host_to_le16(resp);
-
-	if (ies && ies_len)
-		os_memcpy(reply->u.auth.variable, ies, ies_len);
-
-	wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
-		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
-		   MAC2STR(dst), auth_alg, auth_transaction,
-		   resp, (unsigned long) ies_len);
-	if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0)
-		perror("send_auth_reply: send");
-
-	os_free(buf);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
-				  u16 auth_transaction, u16 status,
-				  const u8 *ies, size_t ies_len)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta;
-
-	send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
-			status, ies, ies_len);
-
-	if (status != WLAN_STATUS_SUCCESS)
-		return;
-
-	sta = ap_get_sta(hapd, dst);
-	if (sta == NULL)
-		return;
-
-	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
-	sta->flags |= WLAN_STA_AUTH;
-	mlme_authenticate_indication(hapd, sta);
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-static void handle_auth(struct hostapd_data *hapd,
-			const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	u16 auth_alg, auth_transaction, status_code;
-	u16 resp = WLAN_STATUS_SUCCESS;
-	struct sta_info *sta = NULL;
-	int res;
-	u16 fc;
-	const u8 *challenge = NULL;
-	u32 session_timeout, acct_interim_interval;
-	int vlan_id = 0;
-	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
-	size_t resp_ies_len = 0;
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth - too short payload (len=%lu)\n",
-		       (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);
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
-	    2 + WLAN_AUTH_CHALLENGE_LEN &&
-	    mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
-	    mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
-		challenge = &mgmt->u.auth.variable[2];
-
-	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
-		   "auth_transaction=%d status_code=%d wep=%d%s",
-		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
-		   status_code, !!(fc & WLAN_FC_ISWEP),
-		   challenge ? " challenge" : "");
-
-	if (hapd->tkip_countermeasures) {
-		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
-		goto fail;
-	}
-
-	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
-	       auth_alg == WLAN_AUTH_OPEN) ||
-#ifdef CONFIG_IEEE80211R
-	      (hapd->conf->wpa &&
-	       (hapd->conf->wpa_key_mgmt &
-		(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
-	       auth_alg == WLAN_AUTH_FT) ||
-#endif /* CONFIG_IEEE80211R */
-	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
-	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
-		printf("Unsupported authentication algorithm (%d)\n",
-		       auth_alg);
-		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
-		goto fail;
-	}
-
-	if (!(auth_transaction == 1 ||
-	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
-		printf("Unknown authentication transaction number (%d)\n",
-		       auth_transaction);
-		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
-		goto fail;
-	}
-
-	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
-	}
-
-	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
-				      &session_timeout,
-				      &acct_interim_interval, &vlan_id);
-	if (res == HOSTAPD_ACL_REJECT) {
-		printf("Station " MACSTR " not allowed to authenticate.\n",
-		       MAC2STR(mgmt->sa));
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
-	}
-	if (res == HOSTAPD_ACL_PENDING) {
-		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
-			   " waiting for an external authentication",
-			   MAC2STR(mgmt->sa));
-		/* Authentication code will re-send the authentication frame
-		 * after it has received (and cached) information from the
-		 * external source. */
-		return;
-	}
-
-	sta = ap_sta_add(hapd, mgmt->sa);
-	if (!sta) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
-	}
-
-	if (vlan_id > 0) {
-		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       vlan_id) == NULL) {
-			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;
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
-	}
-
-	sta->flags &= ~WLAN_STA_PREAUTH;
-	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
-
-	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
-		sta->acct_interim_interval = acct_interim_interval;
-	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-		ap_sta_session_timeout(hapd, sta, session_timeout);
-	else
-		ap_sta_no_session_timeout(hapd, sta);
-
-	switch (auth_alg) {
-	case WLAN_AUTH_OPEN:
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "authentication OK (open system)");
-#ifdef IEEE80211_REQUIRE_AUTH_ACK
-		/* Station will be marked authenticated if it ACKs the
-		 * authentication reply. */
-#else
-		sta->flags |= WLAN_STA_AUTH;
-		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-		sta->auth_alg = WLAN_AUTH_OPEN;
-		mlme_authenticate_indication(hapd, sta);
-#endif
-		break;
-	case WLAN_AUTH_SHARED_KEY:
-		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
-				       fc & WLAN_FC_ISWEP);
-		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
-		mlme_authenticate_indication(hapd, sta);
-		if (sta->challenge && auth_transaction == 1) {
-			resp_ies[0] = WLAN_EID_CHALLENGE;
-			resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
-			os_memcpy(resp_ies + 2, sta->challenge,
-				  WLAN_AUTH_CHALLENGE_LEN);
-			resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
-		}
-		break;
-#ifdef CONFIG_IEEE80211R
-	case WLAN_AUTH_FT:
-		sta->auth_alg = WLAN_AUTH_FT;
-		if (sta->wpa_sm == NULL)
-			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
-							sta->addr);
-		if (sta->wpa_sm == NULL) {
-			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
-				   "state machine");
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto fail;
-		}
-		wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
-				    auth_transaction, mgmt->u.auth.variable,
-				    len - IEEE80211_HDRLEN -
-				    sizeof(mgmt->u.auth),
-				    handle_auth_ft_finish, hapd);
-		/* handle_auth_ft_finish() callback will complete auth. */
-		return;
-#endif /* CONFIG_IEEE80211R */
-	}
-
- fail:
-	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
-			auth_transaction + 1, resp, resp_ies, resp_ies_len);
-}
-
-
-static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	int i, j = 32, aid;
-
-	/* get a unique AID */
-	if (sta->aid > 0) {
-		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
-		return 0;
-	}
-
-	for (i = 0; i < AID_WORDS; i++) {
-		if (hapd->sta_aid[i] == (u32) -1)
-			continue;
-		for (j = 0; j < 32; j++) {
-			if (!(hapd->sta_aid[i] & BIT(j)))
-				break;
-		}
-		if (j < 32)
-			break;
-	}
-	if (j == 32)
-		return -1;
-	aid = i * 32 + j + 1;
-	if (aid > 2007)
-		return -1;
-
-	sta->aid = aid;
-	hapd->sta_aid[i] |= BIT(j);
-	wpa_printf(MSG_DEBUG, "  new AID %d", sta->aid);
-	return 0;
-}
-
-
-static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
-		      const u8 *ssid_ie, size_t ssid_ie_len)
-{
-	if (ssid_ie == NULL)
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-
-	if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
-	    os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
-		char ssid_txt[33];
-		ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO,
-			       "Station tried to associate with unknown SSID "
-			       "'%s'", ssid_txt);
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
-		     const u8 *wmm_ie, size_t wmm_ie_len)
-{
-	sta->flags &= ~WLAN_STA_WMM;
-	if (wmm_ie && hapd->conf->wmm_enabled) {
-		if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "invalid WMM element in association "
-				       "request");
-		else
-			sta->flags |= WLAN_STA_WMM;
-	}
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
-			   struct ieee802_11_elems *elems)
-{
-	if (!elems->supp_rates) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "No supported rates element in AssocReq");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	if (elems->supp_rates_len > sizeof(sta->supported_rates)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "Invalid supported rates element length %d",
-			       elems->supp_rates_len);
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
-	os_memcpy(sta->supported_rates, elems->supp_rates,
-		  elems->supp_rates_len);
-	sta->supported_rates_len = elems->supp_rates_len;
-
-	if (elems->ext_supp_rates) {
-		if (elems->supp_rates_len + elems->ext_supp_rates_len >
-		    sizeof(sta->supported_rates)) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE80211,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "Invalid supported rates element length"
-				       " %d+%d", elems->supp_rates_len,
-				       elems->ext_supp_rates_len);
-			return WLAN_STATUS_UNSPECIFIED_FAILURE;
-		}
-
-		os_memcpy(sta->supported_rates + elems->supp_rates_len,
-			  elems->ext_supp_rates, elems->ext_supp_rates_len);
-		sta->supported_rates_len += elems->ext_supp_rates_len;
-	}
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
-			   const u8 *ies, size_t ies_len, int reassoc)
-{
-	struct ieee802_11_elems elems;
-	u16 resp;
-	const u8 *wpa_ie;
-	size_t wpa_ie_len;
-
-	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "Station sent an invalid "
-			       "association request");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
-	if (resp != WLAN_STATUS_SUCCESS)
-		return resp;
-	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
-	if (resp != WLAN_STATUS_SUCCESS)
-		return resp;
-	resp = copy_supp_rates(hapd, sta, &elems);
-	if (resp != WLAN_STATUS_SUCCESS)
-		return resp;
-#ifdef CONFIG_IEEE80211N
-	resp = copy_sta_ht_capab(sta, elems.ht_capabilities,
-				 elems.ht_capabilities_len);
-	if (resp != WLAN_STATUS_SUCCESS)
-		return resp;
-#endif /* CONFIG_IEEE80211N */
-
-	if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
-		wpa_ie = elems.rsn_ie;
-		wpa_ie_len = elems.rsn_ie_len;
-	} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
-		   elems.wpa_ie) {
-		wpa_ie = elems.wpa_ie;
-		wpa_ie_len = elems.wpa_ie_len;
-	} else {
-		wpa_ie = NULL;
-		wpa_ie_len = 0;
-	}
-
-#ifdef CONFIG_WPS
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
-	if (hapd->conf->wps_state && elems.wps_ie) {
-		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
-			   "Request - assume WPS is used");
-		sta->flags |= WLAN_STA_WPS;
-		wpabuf_free(sta->wps_ie);
-		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
-							  WPS_IE_VENDOR_TYPE);
-		wpa_ie = NULL;
-		wpa_ie_len = 0;
-	} else if (hapd->conf->wps_state && wpa_ie == NULL) {
-		wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
-			   "(Re)Association Request - possible WPS use");
-		sta->flags |= WLAN_STA_MAYBE_WPS;
-	} else
-#endif /* CONFIG_WPS */
-	if (hapd->conf->wpa && wpa_ie == NULL) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO,
-			       "No WPA/RSN IE in association request");
-		return WLAN_STATUS_INVALID_IE;
-	}
-
-	if (hapd->conf->wpa && wpa_ie) {
-		int res;
-		wpa_ie -= 2;
-		wpa_ie_len += 2;
-		if (sta->wpa_sm == NULL)
-			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
-							sta->addr);
-		if (sta->wpa_sm == NULL) {
-			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
-				   "state machine");
-			return WLAN_STATUS_UNSPECIFIED_FAILURE;
-		}
-		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
-					  wpa_ie, wpa_ie_len,
-					  elems.mdie, elems.mdie_len);
-		if (res == WPA_INVALID_GROUP)
-			resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
-		else if (res == WPA_INVALID_PAIRWISE)
-			resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
-		else if (res == WPA_INVALID_AKMP)
-			resp = WLAN_STATUS_AKMP_NOT_VALID;
-		else if (res == WPA_ALLOC_FAIL)
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
-		else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
-		else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
-#endif /* CONFIG_IEEE80211W */
-		else if (res == WPA_INVALID_MDIE)
-			resp = WLAN_STATUS_INVALID_MDIE;
-		else if (res != WPA_IE_OK)
-			resp = WLAN_STATUS_INVALID_IE;
-		if (resp != WLAN_STATUS_SUCCESS)
-			return resp;
-#ifdef CONFIG_IEEE80211W
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
-		    sta->sa_query_count > 0)
-			ap_check_sa_query_timeout(hapd, sta);
-		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
-		    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
-			/*
-			 * STA has already been associated with MFP and SA
-			 * Query timeout has not been reached. Reject the
-			 * association attempt temporarily and start SA Query,
-			 * if one is not pending.
-			 */
-
-			if (sta->sa_query_count == 0)
-				ap_sta_start_sa_query(hapd, sta);
-
-			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
-		}
-
-		if (wpa_auth_uses_mfp(sta->wpa_sm))
-			sta->flags |= WLAN_STA_MFP;
-		else
-			sta->flags &= ~WLAN_STA_MFP;
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_IEEE80211R
-		if (sta->auth_alg == WLAN_AUTH_FT) {
-			if (!reassoc) {
-				wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
-					   "to use association (not "
-					   "re-association) with FT auth_alg",
-					   MAC2STR(sta->addr));
-				return WLAN_STATUS_UNSPECIFIED_FAILURE;
-			}
-
-			resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
-						       ies_len);
-			if (resp != WLAN_STATUS_SUCCESS)
-				return resp;
-		}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211N
-		if ((sta->flags & WLAN_STA_HT) &&
-		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE80211,
-				       HOSTAPD_LEVEL_INFO,
-				       "Station tried to use TKIP with HT "
-				       "association");
-			return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
-		}
-#endif /* CONFIG_IEEE80211N */
-	} else
-		wpa_auth_sta_no_wpa(sta->wpa_sm);
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
-			u16 reason_code)
-{
-	int send_len;
-	struct ieee80211_mgmt reply;
-
-	os_memset(&reply, 0, sizeof(reply));
-	reply.frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
-	os_memcpy(reply.da, addr, ETH_ALEN);
-	os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
-
-	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
-	reply.u.deauth.reason_code = host_to_le16(reason_code);
-
-	if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0)
-		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
-			   strerror(errno));
-}
-
-
-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)
-{
-	int send_len;
-	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
-	struct ieee80211_mgmt *reply;
-	u8 *p;
-
-	os_memset(buf, 0, sizeof(buf));
-	reply = (struct ieee80211_mgmt *) buf;
-	reply->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-			     (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
-			      WLAN_FC_STYPE_ASSOC_RESP));
-	os_memcpy(reply->da, sta->addr, ETH_ALEN);
-	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
-
-	send_len = IEEE80211_HDRLEN;
-	send_len += sizeof(reply->u.assoc_resp);
-	reply->u.assoc_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
-	reply->u.assoc_resp.status_code = host_to_le16(status_code);
-	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
-					       | BIT(14) | BIT(15));
-	/* Supported rates */
-	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
-	/* Extended supported rates */
-	p = hostapd_eid_ext_supp_rates(hapd, p);
-
-#ifdef CONFIG_IEEE80211R
-	if (status_code == WLAN_STATUS_SUCCESS) {
-		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
-		 * Transition Information, RSN, [RIC Response] */
-		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
-						buf + sizeof(buf) - p,
-						sta->auth_alg, ies, ies_len);
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
-	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
-		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_IEEE80211N
-	p = hostapd_eid_ht_capabilities(hapd, p);
-	p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
-
-	if (sta->flags & WLAN_STA_WMM)
-		p = hostapd_eid_wmm(hapd, p);
-
-#ifdef CONFIG_WPS
-	if (sta->flags & WLAN_STA_WPS) {
-		struct wpabuf *wps = wps_build_assoc_resp_ie();
-		if (wps) {
-			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
-			p += wpabuf_len(wps);
-			wpabuf_free(wps);
-		}
-	}
-#endif /* CONFIG_WPS */
-
-	send_len += p - reply->u.assoc_resp.variable;
-
-	if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0)
-		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
-			   strerror(errno));
-}
-
-
-static void handle_assoc(struct hostapd_data *hapd,
-			 const struct ieee80211_mgmt *mgmt, size_t len,
-			 int reassoc)
-{
-	u16 capab_info, listen_interval;
-	u16 resp = WLAN_STATUS_SUCCESS;
-	const u8 *pos;
-	int left, i;
-	struct sta_info *sta;
-
-	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
-				      sizeof(mgmt->u.assoc_req))) {
-		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
-		       "\n", reassoc, (unsigned long) len);
-		return;
-	}
-
-	if (reassoc) {
-		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
-		listen_interval = le_to_host16(
-			mgmt->u.reassoc_req.listen_interval);
-		wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
-			   " capab_info=0x%02x listen_interval=%d current_ap="
-			   MACSTR,
-			   MAC2STR(mgmt->sa), capab_info, listen_interval,
-			   MAC2STR(mgmt->u.reassoc_req.current_ap));
-		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
-		pos = mgmt->u.reassoc_req.variable;
-	} else {
-		capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
-		listen_interval = le_to_host16(
-			mgmt->u.assoc_req.listen_interval);
-		wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
-			   " capab_info=0x%02x listen_interval=%d",
-			   MAC2STR(mgmt->sa), capab_info, listen_interval);
-		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
-		pos = mgmt->u.assoc_req.variable;
-	}
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-#ifdef CONFIG_IEEE80211R
-	if (sta && sta->auth_alg == WLAN_AUTH_FT &&
-	    (sta->flags & WLAN_STA_AUTH) == 0) {
-		wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
-			   "prior to authentication since it is using "
-			   "over-the-DS FT", MAC2STR(mgmt->sa));
-	} else
-#endif /* CONFIG_IEEE80211R */
-	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "Station tried to "
-			       "associate before authentication "
-			       "(aid=%d flags=0x%x)",
-			       sta ? sta->aid : -1,
-			       sta ? sta->flags : 0);
-		send_deauth(hapd, mgmt->sa,
-			    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
-		return;
-	}
-
-	if (hapd->tkip_countermeasures) {
-		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
-		goto fail;
-	}
-
-	if (listen_interval > hapd->conf->max_listen_interval) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "Too large Listen Interval (%d)",
-			       listen_interval);
-		resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
-		goto fail;
-	}
-
-	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
-	 * is used */
-	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
-	if (resp != WLAN_STATUS_SUCCESS)
-		goto fail;
-
-	if (hostapd_get_aid(hapd, sta) < 0) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "No room for more AIDs");
-		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
-		goto fail;
-	}
-
-	sta->capability = capab_info;
-	sta->listen_interval = listen_interval;
-
-	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
-		sta->flags |= WLAN_STA_NONERP;
-	for (i = 0; i < sta->supported_rates_len; i++) {
-		if ((sta->supported_rates[i] & 0x7f) > 22) {
-			sta->flags &= ~WLAN_STA_NONERP;
-			break;
-		}
-	}
-	if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
-		sta->nonerp_set = 1;
-		hapd->iface->num_sta_non_erp++;
-		if (hapd->iface->num_sta_non_erp == 1)
-			ieee802_11_set_beacons(hapd->iface);
-	}
-
-	if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
-	    !sta->no_short_slot_time_set) {
-		sta->no_short_slot_time_set = 1;
-		hapd->iface->num_sta_no_short_slot_time++;
-		if (hapd->iface->current_mode->mode ==
-		    HOSTAPD_MODE_IEEE80211G &&
-		    hapd->iface->num_sta_no_short_slot_time == 1)
-			ieee802_11_set_beacons(hapd->iface);
-	}
-
-	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
-	else
-		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
-
-	if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
-	    !sta->no_short_preamble_set) {
-		sta->no_short_preamble_set = 1;
-		hapd->iface->num_sta_no_short_preamble++;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
-		    && hapd->iface->num_sta_no_short_preamble == 1)
-			ieee802_11_set_beacons(hapd->iface);
-	}
-
-#ifdef CONFIG_IEEE80211N
-	update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "association OK (aid %d)", sta->aid);
-	/* Station will be marked associated, after it acknowledges AssocResp
-	 */
-
-#ifdef CONFIG_IEEE80211W
-	if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
-		wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
-			   "SA Query procedure", reassoc ? "re" : "");
-		/* TODO: Send a protected Disassociate frame to the STA using
-		 * the old key and Reason Code "Previous Authentication no
-		 * longer valid". Make sure this is only sent protected since
-		 * unprotected frame would be received by the STA that is now
-		 * trying to associate.
-		 */
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	if (reassoc) {
-		os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
-			  ETH_ALEN);
-	}
-
-	if (sta->last_assoc_req)
-		os_free(sta->last_assoc_req);
-	sta->last_assoc_req = os_malloc(len);
-	if (sta->last_assoc_req)
-		os_memcpy(sta->last_assoc_req, mgmt, len);
-
-	/* Make sure that the previously registered inactivity timer will not
-	 * remove the STA immediately. */
-	sta->timeout_next = STA_NULLFUNC;
-
- fail:
-	send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
-}
-
-
-static void handle_disassoc(struct hostapd_data *hapd,
-			    const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	struct sta_info *sta;
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
-		printf("handle_disassoc - too short payload (len=%lu)\n",
-		       (unsigned long) len);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
-		   MAC2STR(mgmt->sa),
-		   le_to_host16(mgmt->u.disassoc.reason_code));
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL) {
-		printf("Station " MACSTR " trying to disassociate, but it "
-		       "is not associated.\n", MAC2STR(mgmt->sa));
-		return;
-	}
-
-	sta->flags &= ~WLAN_STA_ASSOC;
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "disassociated");
-	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-	/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
-	 * authenticated. */
-	accounting_sta_stop(hapd, sta);
-	ieee802_1x_free_station(sta);
-	hapd->drv.sta_remove(hapd, sta->addr);
-
-	if (sta->timeout_next == STA_NULLFUNC ||
-	    sta->timeout_next == STA_DISASSOC) {
-		sta->timeout_next = STA_DEAUTH;
-		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
-				       hapd, sta);
-	}
-
-	mlme_disassociate_indication(
-		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
-}
-
-
-static void handle_deauth(struct hostapd_data *hapd,
-			  const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	struct sta_info *sta;
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
-		printf("handle_deauth - too short payload (len=%lu)\n",
-		       (unsigned long) len);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR
-		   " reason_code=%d",
-		   MAC2STR(mgmt->sa),
-		   le_to_host16(mgmt->u.deauth.reason_code));
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL) {
-		printf("Station " MACSTR " trying to deauthenticate, but it "
-		       "is not authenticated.\n", MAC2STR(mgmt->sa));
-		return;
-	}
-
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
-	mlme_deauthenticate_indication(
-		hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
-	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-	ap_free_sta(hapd, sta);
-}
-
-
-static void handle_beacon(struct hostapd_data *hapd,
-			  const struct ieee80211_mgmt *mgmt, size_t len,
-			  struct hostapd_frame_info *fi)
-{
-	struct ieee802_11_elems elems;
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
-		printf("handle_beacon - too short payload (len=%lu)\n",
-		       (unsigned long) len);
-		return;
-	}
-
-	(void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
-				      len - (IEEE80211_HDRLEN +
-					     sizeof(mgmt->u.beacon)), &elems,
-				      0);
-
-	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
-}
-
-
-#ifdef CONFIG_IEEE80211W
-
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
-				  const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt mgmt;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
-		   MACSTR, MAC2STR(addr));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-	os_memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt.da, addr, ETH_ALEN);
-	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
-	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
-				     const struct ieee80211_mgmt *mgmt)
-{
-	struct sta_info *sta;
-	struct ieee80211_mgmt resp;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
-			   "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
-		   MACSTR, MAC2STR(mgmt->sa));
-
-	os_memset(&resp, 0, sizeof(resp));
-	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
-	resp.u.action.category = WLAN_ACTION_SA_QUERY;
-	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(resp.u.action.u.sa_query_req.trans_id,
-		  mgmt->u.action.u.sa_query_req.trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0)
-		perror("hostapd_sa_query_request: send");
-}
-
-
-static void hostapd_sa_query_action(struct hostapd_data *hapd,
-				    const struct ieee80211_mgmt *mgmt,
-				    size_t len)
-{
-	struct sta_info *sta;
-	const u8 *end;
-	int i;
-
-	end = mgmt->u.action.u.sa_query_resp.trans_id +
-		WLAN_SA_QUERY_TR_ID_LEN;
-	if (((u8 *) mgmt) + len < end) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
-			   "frame (len=%lu)", (unsigned long) len);
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
-		hostapd_sa_query_request(hapd, mgmt);
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
-			   "Action %d", mgmt->u.action.u.sa_query_resp.action);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	/* MLME-SAQuery.confirm */
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || sta->sa_query_trans_id == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
-			   "pending SA Query request found");
-		return;
-	}
-
-	for (i = 0; i < sta->sa_query_count; i++) {
-		if (os_memcmp(sta->sa_query_trans_id +
-			      i * WLAN_SA_QUERY_TR_ID_LEN,
-			      mgmt->u.action.u.sa_query_resp.trans_id,
-			      WLAN_SA_QUERY_TR_ID_LEN) == 0)
-			break;
-	}
-
-	if (i >= sta->sa_query_count) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
-			   "transaction identifier found");
-		return;
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Reply to pending SA Query received");
-	ap_sta_stop_sa_query(hapd, sta);
-}
-
-
-static int robust_action_frame(u8 category)
-{
-	return category != WLAN_ACTION_PUBLIC &&
-		category != WLAN_ACTION_HT;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
-static void handle_action(struct hostapd_data *hapd,
-			  const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	struct sta_info *sta;
-
-	if (len < IEEE80211_HDRLEN + 1) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "handle_action - too short payload (len=%lu)",
-			       (unsigned long) len);
-		return;
-	}
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-#ifdef CONFIG_IEEE80211W
-	if (sta && (sta->flags & WLAN_STA_MFP) &&
-	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
-	      robust_action_frame(mgmt->u.action.category))) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "Dropped unprotected Robust Action frame from "
-			       "an MFP STA");
-		return;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
-	case WLAN_ACTION_FT:
-	{
-		if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-			wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
-				   "frame from unassociated STA " MACSTR,
-				   MAC2STR(mgmt->sa));
-			return;
-		}
-
-		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
-				     len - IEEE80211_HDRLEN))
-			break;
-
-		return;
-	}
-#endif /* CONFIG_IEEE80211R */
-	case WLAN_ACTION_WMM:
-		hostapd_wmm_action(hapd, mgmt, len);
-		return;
-#ifdef CONFIG_IEEE80211W
-	case WLAN_ACTION_SA_QUERY:
-		hostapd_sa_query_action(hapd, mgmt, len);
-		return;
-#endif /* CONFIG_IEEE80211W */
-	case WLAN_ACTION_PUBLIC:
-		if (hapd->public_action_cb) {
-			hapd->public_action_cb(hapd->public_action_cb_ctx,
-					       (u8 *) mgmt, len,
-					       hapd->iface->freq);
-			return;
-		}
-		break;
-	}
-
-	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "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)) {
-		struct ieee80211_mgmt *resp;
-
-		/*
-		 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
-		 * Return the Action frame to the source without change
-		 * except that MSB of the Category set to 1.
-		 */
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
-			   "frame back to sender");
-		resp = os_malloc(len);
-		if (resp == NULL)
-			return;
-		os_memcpy(resp, mgmt, len);
-		os_memcpy(resp->da, resp->sa, ETH_ALEN);
-		os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
-		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
-		resp->u.action.category |= 0x80;
-
-		hapd->drv.send_mgmt_frame(hapd, resp, len);
-		os_free(resp);
-	}
-}
-
-
-/**
- * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
- * @hapd: hostapd BSS data structure (the BSS to which the management frame was
- * sent to)
- * @buf: management frame data (starting from IEEE 802.11 header)
- * @len: length of frame data in octets
- * @fi: meta data about received frame (signal level, etc.)
- *
- * Process all incoming IEEE 802.11 management frames. This will be called for
- * each frame received from the kernel driver through wlan#ap interface. In
- * addition, it can be called to re-inserted pending frames (e.g., when using
- * external RADIUS server as an MAC ACL).
- */
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
-		     struct hostapd_frame_info *fi)
-{
-	struct ieee80211_mgmt *mgmt;
-	int broadcast;
-	u16 fc, stype;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	if (stype == WLAN_FC_STYPE_BEACON) {
-		handle_beacon(hapd, mgmt, len, fi);
-		return;
-	}
-
-	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 &&
-	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
-		printf("MGMT: BSSID=" MACSTR " not our address\n",
-		       MAC2STR(mgmt->bssid));
-		return;
-	}
-
-
-	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-		handle_probe_req(hapd, mgmt, len);
-		return;
-	}
-
-	if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "MGMT: DA=" MACSTR " not our address",
-			       MAC2STR(mgmt->da));
-		return;
-	}
-
-	switch (stype) {
-	case WLAN_FC_STYPE_AUTH:
-		wpa_printf(MSG_DEBUG, "mgmt::auth");
-		handle_auth(hapd, mgmt, len);
-		break;
-	case WLAN_FC_STYPE_ASSOC_REQ:
-		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
-		handle_assoc(hapd, mgmt, len, 0);
-		break;
-	case WLAN_FC_STYPE_REASSOC_REQ:
-		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
-		handle_assoc(hapd, mgmt, len, 1);
-		break;
-	case WLAN_FC_STYPE_DISASSOC:
-		wpa_printf(MSG_DEBUG, "mgmt::disassoc");
-		handle_disassoc(hapd, mgmt, len);
-		break;
-	case WLAN_FC_STYPE_DEAUTH:
-		wpa_printf(MSG_DEBUG, "mgmt::deauth");
-		handle_deauth(hapd, mgmt, len);
-		break;
-	case WLAN_FC_STYPE_ACTION:
-		wpa_printf(MSG_DEBUG, "mgmt::action");
-		handle_action(hapd, mgmt, len);
-		break;
-	default:
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "unknown mgmt frame subtype %d", stype);
-		break;
-	}
-}
-
-
-static void handle_auth_cb(struct hostapd_data *hapd,
-			   const struct ieee80211_mgmt *mgmt,
-			   size_t len, int ok)
-{
-	u16 auth_alg, auth_transaction, status_code;
-	struct sta_info *sta;
-
-	if (!ok) {
-		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "did not acknowledge authentication response");
-		return;
-	}
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
-		printf("handle_auth_cb - too short payload (len=%lu)\n",
-		       (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) {
-		printf("handle_auth_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
-		return;
-	}
-
-	if (status_code == WLAN_STATUS_SUCCESS &&
-	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
-	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "authenticated");
-		sta->flags |= WLAN_STA_AUTH;
-	}
-}
-
-
-static void handle_assoc_cb(struct hostapd_data *hapd,
-			    const struct ieee80211_mgmt *mgmt,
-			    size_t len, int reassoc, int ok)
-{
-	u16 status;
-	struct sta_info *sta;
-	int new_assoc = 1;
-	struct ieee80211_ht_capabilities ht_cap;
-
-	if (!ok) {
-		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "did not acknowledge association response");
-		return;
-	}
-
-	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
-				      sizeof(mgmt->u.assoc_resp))) {
-		printf("handle_assoc_cb(reassoc=%d) - too short payload "
-		       "(len=%lu)\n", reassoc, (unsigned long) len);
-		return;
-	}
-
-	if (reassoc)
-		status = le_to_host16(mgmt->u.reassoc_resp.status_code);
-	else
-		status = le_to_host16(mgmt->u.assoc_resp.status_code);
-
-	sta = ap_get_sta(hapd, mgmt->da);
-	if (!sta) {
-		printf("handle_assoc_cb: STA " MACSTR " not found\n",
-		       MAC2STR(mgmt->da));
-		return;
-	}
-
-	if (status != WLAN_STATUS_SUCCESS)
-		goto fail;
-
-	/* Stop previous accounting session, if one is started, and allocate
-	 * new session id for the new session. */
-	accounting_sta_stop(hapd, sta);
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO,
-		       "associated (aid %d)",
-		       sta->aid);
-
-	if (sta->flags & WLAN_STA_ASSOC)
-		new_assoc = 0;
-	sta->flags |= WLAN_STA_ASSOC;
-	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
-	    sta->auth_alg == WLAN_AUTH_FT) {
-		/*
-		 * Open, static WEP, or FT protocol; no separate authorization
-		 * step.
-		 */
-		sta->flags |= WLAN_STA_AUTHORIZED;
-		wpa_msg(hapd->msg_ctx, MSG_INFO,
-			AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-	}
-
-	if (reassoc)
-		mlme_reassociate_indication(hapd, sta);
-	else
-		mlme_associate_indication(hapd, sta);
-
-#ifdef CONFIG_IEEE80211W
-	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.
-	 */
-	hapd->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 */
-
-	if (hapd->drv.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)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "Could not add STA to kernel driver");
-	}
-
-	if (sta->eapol_sm == NULL) {
-		/*
-		 * This STA does not use RADIUS server for EAP authentication,
-		 * so bind it to the selected VLAN interface now, since the
-		 * interface selection is not going to change anymore.
-		 */
-		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
-			goto fail;
-	} else if (sta->vlan_id) {
-		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
-		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
-			goto fail;
-	}
-
-	hapd->drv.set_sta_flags(hapd, sta);
-
-	if (sta->auth_alg == WLAN_AUTH_FT)
-		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
-	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);
-
- fail:
-	/* Copy of the association request is not needed anymore */
-	if (sta->last_assoc_req) {
-		os_free(sta->last_assoc_req);
-		sta->last_assoc_req = NULL;
-	}
-}
-
-
-/**
- * ieee802_11_mgmt_cb - Process management frame TX status callback
- * @hapd: hostapd BSS data structure (the BSS from which the management frame
- * was sent from)
- * @buf: management frame data (starting from IEEE 802.11 header)
- * @len: length of frame data in octets
- * @stype: management frame subtype from frame control field
- * @ok: Whether the frame was ACK'ed
- */
-void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
-			u16 stype, int ok)
-{
-	const struct ieee80211_mgmt *mgmt;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	switch (stype) {
-	case WLAN_FC_STYPE_AUTH:
-		wpa_printf(MSG_DEBUG, "mgmt::auth cb");
-		handle_auth_cb(hapd, mgmt, len, ok);
-		break;
-	case WLAN_FC_STYPE_ASSOC_RESP:
-		wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
-		handle_assoc_cb(hapd, mgmt, len, 0, ok);
-		break;
-	case WLAN_FC_STYPE_REASSOC_RESP:
-		wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
-		handle_assoc_cb(hapd, mgmt, len, 1, ok);
-		break;
-	case WLAN_FC_STYPE_PROBE_RESP:
-		wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
-		break;
-	case WLAN_FC_STYPE_DEAUTH:
-		/* ignore */
-		break;
-	case WLAN_FC_STYPE_ACTION:
-		wpa_printf(MSG_DEBUG, "mgmt::action cb");
-		break;
-	default:
-		printf("unknown mgmt cb frame subtype %d\n", stype);
-		break;
-	}
-}
-
-
-int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
-{
-	/* TODO */
-	return 0;
-}
-
-
-int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   char *buf, size_t buflen)
-{
-	/* TODO */
-	return 0;
-}
-
-
-void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
-		       const u8 *buf, size_t len, int ack)
-{
-	struct sta_info *sta;
-	struct hostapd_iface *iface = hapd->iface;
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL && iface->num_bss > 1) {
-		size_t j;
-		for (j = 0; j < iface->num_bss; j++) {
-			hapd = iface->bss[j];
-			sta = ap_get_sta(hapd, addr);
-			if (sta)
-				break;
-		}
-	}
-	if (sta == NULL)
-		return;
-	if (sta->flags & WLAN_STA_PENDING_POLL) {
-		wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
-			   "activity poll", MAC2STR(sta->addr),
-			   ack ? "ACKed" : "did not ACK");
-		if (ack)
-			sta->flags &= ~WLAN_STA_PENDING_POLL;
-	}
-
-	ieee802_1x_tx_status(hapd, sta, buf, len, ack);
-}
-
-
-void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
-				int wds)
-{
-	struct sta_info *sta;
-
-	sta = ap_get_sta(hapd, src);
-	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
-		if (wds && !(sta->flags & WLAN_STA_WDS)) {
-			wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
-				   "STA " MACSTR " (aid %u)",
-				   MAC2STR(sta->addr), sta->aid);
-			sta->flags |= WLAN_STA_WDS;
-			hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1);
-		}
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
-		   MACSTR, MAC2STR(src));
-	if (sta && (sta->flags & WLAN_STA_AUTH))
-		hapd->drv.sta_disassoc(
-			hapd, src,
-			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
-	else
-		hapd->drv.sta_deauth(
-			hapd, src,
-			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
-}
-
-
-#endif /* CONFIG_NATIVE_WINDOWS */

Copied: vendor/wpa/2.0/src/ap/ieee802_11.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2076 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+#include "hostapd.h"
+#include "beacon.h"
+#include "ieee802_11_auth.h"
+#include "sta_info.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "wmm.h"
+#include "ap_list.h"
+#include "accounting.h"
+#include "ap_config.h"
+#include "ap_mlme.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "wnm_ap.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
+
+	*pos++ = WLAN_EID_SUPP_RATES;
+	num = hapd->iface->num_rates;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+		num++;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+		num++;
+	if (num > 8) {
+		/* rest of the rates are encoded in Extended supported
+		 * rates element */
+		num = 8;
+	}
+
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
+	     i++) {
+		count++;
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
+
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
+		count++;
+		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+	}
+
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
+		count++;
+		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+	}
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
+
+	num = hapd->iface->num_rates;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+		num++;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+		num++;
+	if (num <= 8)
+		return eid;
+	num -= 8;
+
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
+	     i++) {
+		count++;
+		if (count <= 8)
+			continue; /* already in SuppRates IE */
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
+
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
+		count++;
+		if (count > 8)
+			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+	}
+
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
+		count++;
+		if (count > 8)
+			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+	}
+
+	return pos;
+}
+
+
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe)
+{
+	int capab = WLAN_CAPABILITY_ESS;
+	int privacy;
+
+	if (hapd->iface->num_sta_no_short_preamble == 0 &&
+	    hapd->iconf->preamble == SHORT_PREAMBLE)
+		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+	privacy = hapd->conf->ssid.wep.keys_set;
+
+	if (hapd->conf->ieee802_1x &&
+	    (hapd->conf->default_wep_key_len ||
+	     hapd->conf->individual_wep_key_len))
+		privacy = 1;
+
+	if (hapd->conf->wpa)
+		privacy = 1;
+
+	if (sta) {
+		int policy, def_klen;
+		if (probe && sta->ssid_probe) {
+			policy = sta->ssid_probe->security_policy;
+			def_klen = sta->ssid_probe->wep.default_len;
+		} else {
+			policy = sta->ssid->security_policy;
+			def_klen = sta->ssid->wep.default_len;
+		}
+		privacy = policy != SECURITY_PLAINTEXT;
+		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
+			privacy = 0;
+	}
+
+	if (privacy)
+		capab |= WLAN_CAPABILITY_PRIVACY;
+
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    hapd->iface->num_sta_no_short_slot_time == 0)
+		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+	return capab;
+}
+
+
+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
+{
+	int i;
+	if (len > HOSTAPD_MAX_SSID_LEN)
+		len = HOSTAPD_MAX_SSID_LEN;
+	for (i = 0; i < len; i++) {
+		if (ssid[i] >= 32 && ssid[i] < 127)
+			buf[i] = ssid[i];
+		else
+			buf[i] = '.';
+	}
+	buf[len] = '\0';
+}
+
+
+static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 auth_transaction, const u8 *challenge,
+			   int iswep)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "authentication (shared key, transaction %d)",
+		       auth_transaction);
+
+	if (auth_transaction == 1) {
+		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);
+			rc4_skip(key, sizeof(key), 0,
+				 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
+		}
+		return 0;
+	}
+
+	if (auth_transaction != 3)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	/* Transaction 3 */
+	if (!iswep || !sta->challenge || !challenge ||
+	    os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "shared key authentication - invalid "
+			       "challenge-response");
+		return WLAN_STATUS_CHALLENGE_FAIL;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "authentication OK (shared key)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+	/* Station will be marked authenticated if it ACKs the
+	 * authentication reply. */
+#else
+	sta->flags |= WLAN_STA_AUTH;
+	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+#endif
+	os_free(sta->challenge);
+	sta->challenge = NULL;
+
+	return 0;
+}
+
+
+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)
+{
+	struct ieee80211_mgmt *reply;
+	u8 *buf;
+	size_t rlen;
+
+	rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
+	buf = os_zalloc(rlen);
+	if (buf == NULL)
+		return;
+
+	reply = (struct ieee80211_mgmt *) buf;
+	reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					    WLAN_FC_STYPE_AUTH);
+	os_memcpy(reply->da, dst, ETH_ALEN);
+	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply->bssid, bssid, ETH_ALEN);
+
+	reply->u.auth.auth_alg = host_to_le16(auth_alg);
+	reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
+	reply->u.auth.status_code = host_to_le16(resp);
+
+	if (ies && ies_len)
+		os_memcpy(reply->u.auth.variable, ies, ies_len);
+
+	wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
+		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+		   MAC2STR(dst), auth_alg, auth_transaction,
+		   resp, (unsigned long) ies_len);
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+		perror("send_auth_reply: send");
+
+	os_free(buf);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
+				  u16 auth_transaction, u16 status,
+				  const u8 *ies, size_t ies_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
+			status, ies, ies_len);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		return;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL)
+		return;
+
+	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+	sta->flags |= WLAN_STA_AUTH;
+	mlme_authenticate_indication(hapd, sta);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+					     struct sta_info *sta)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+	/* TODO: Anti-Clogging Token (if requested) */
+	/* TODO: Scalar */
+	/* TODO: Element */
+
+	return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+					      struct sta_info *sta)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, sta->sae_send_confirm);
+	sta->sae_send_confirm++;
+	/* TODO: Confirm */
+
+	return buf;
+}
+
+
+static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
+			     const u8 *data, size_t len)
+{
+	wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+
+	/* Check Finite Cyclic Group */
+	if (len < 2)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (WPA_GET_LE16(data) != 19) {
+		wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+			   WPA_GET_LE16(data));
+		return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
+			      const u8 *data, size_t len)
+{
+	u16 rc;
+
+	wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
+
+	if (len < 2)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	rc = WPA_GET_LE16(data);
+	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
+			    const struct ieee80211_mgmt *mgmt, size_t len,
+			    u8 auth_transaction)
+{
+	u16 resp = WLAN_STATUS_SUCCESS;
+	struct wpabuf *data;
+
+	if (auth_transaction == 1) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "start SAE authentication (RX commit)");
+		resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
+					 ((u8 *) mgmt) + len -
+					 mgmt->u.auth.variable);
+		if (resp == WLAN_STATUS_SUCCESS)
+			sta->sae_state = SAE_COMMIT;
+	} else if (auth_transaction == 2) {
+		if (sta->sae_state != SAE_COMMIT) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "SAE confirm before commit");
+			resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+		}
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "SAE authentication (RX confirm)");
+		resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
+					  ((u8 *) mgmt) + len -
+					  mgmt->u.auth.variable);
+		if (resp == WLAN_STATUS_SUCCESS) {
+			sta->flags |= WLAN_STA_AUTH;
+			wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+			sta->auth_alg = WLAN_AUTH_SAE;
+			mlme_authenticate_indication(hapd, sta);
+		}
+	} else {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "unexpected SAE authentication transaction %u",
+			       auth_transaction);
+		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+	}
+
+	sta->auth_alg = WLAN_AUTH_SAE;
+
+	if (resp == WLAN_STATUS_SUCCESS) {
+		if (auth_transaction == 1)
+			data = auth_build_sae_commit(hapd, sta);
+		else
+			data = auth_build_sae_confirm(hapd, sta);
+		if (data == NULL)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	} else
+		data = NULL;
+
+	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+			auth_transaction, resp,
+			data ? wpabuf_head(data) : (u8 *) "",
+			data ? wpabuf_len(data) : 0);
+	wpabuf_free(data);
+}
+#endif /* CONFIG_SAE */
+
+
+static void handle_auth(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	u16 auth_alg, auth_transaction, status_code;
+	u16 resp = WLAN_STATUS_SUCCESS;
+	struct sta_info *sta = NULL;
+	int res;
+	u16 fc;
+	const u8 *challenge = NULL;
+	u32 session_timeout, acct_interim_interval;
+	int vlan_id = 0;
+	struct hostapd_sta_wpa_psk_short *psk = NULL;
+	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+	size_t resp_ies_len = 0;
+	char *identity = NULL;
+	char *radius_cui = NULL;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		printf("handle_auth - too short payload (len=%lu)\n",
+		       (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);
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
+	    2 + WLAN_AUTH_CHALLENGE_LEN &&
+	    mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
+	    mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
+		challenge = &mgmt->u.auth.variable[2];
+
+	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
+		   "auth_transaction=%d status_code=%d wep=%d%s",
+		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
+		   status_code, !!(fc & WLAN_FC_ISWEP),
+		   challenge ? " challenge" : "");
+
+	if (hapd->tkip_countermeasures) {
+		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		goto fail;
+	}
+
+	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
+	       auth_alg == WLAN_AUTH_OPEN) ||
+#ifdef CONFIG_IEEE80211R
+	      (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
+	       auth_alg == WLAN_AUTH_FT) ||
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	      (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+	       auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
+	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
+	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
+		printf("Unsupported authentication algorithm (%d)\n",
+		       auth_alg);
+		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+		goto fail;
+	}
+
+	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
+		printf("Unknown authentication transaction number (%d)\n",
+		       auth_transaction);
+		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+		goto fail;
+	}
+
+	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+		printf("Station " MACSTR " not allowed to authenticate.\n",
+		       MAC2STR(mgmt->sa));
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
+				      &session_timeout,
+				      &acct_interim_interval, &vlan_id,
+				      &psk, &identity, &radius_cui);
+
+	if (res == HOSTAPD_ACL_REJECT) {
+		printf("Station " MACSTR " not allowed to authenticate.\n",
+		       MAC2STR(mgmt->sa));
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+	if (res == HOSTAPD_ACL_PENDING) {
+		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+			   " waiting for an external authentication",
+			   MAC2STR(mgmt->sa));
+		/* Authentication code will re-send the authentication frame
+		 * after it has received (and cached) information from the
+		 * external source. */
+		return;
+	}
+
+	sta = ap_sta_add(hapd, mgmt->sa);
+	if (!sta) {
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	if (vlan_id > 0) {
+		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       vlan_id) == NULL) {
+			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;
+		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) {
+		sta->psk = psk;
+		psk = NULL;
+	} else {
+		sta->psk = NULL;
+	}
+
+	sta->identity = identity;
+	identity = NULL;
+	sta->radius_cui = radius_cui;
+	radius_cui = NULL;
+
+	sta->flags &= ~WLAN_STA_PREAUTH;
+	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+
+	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+		sta->acct_interim_interval = acct_interim_interval;
+	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+		ap_sta_session_timeout(hapd, sta, session_timeout);
+	else
+		ap_sta_no_session_timeout(hapd, sta);
+
+	switch (auth_alg) {
+	case WLAN_AUTH_OPEN:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "authentication OK (open system)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+		/* Station will be marked authenticated if it ACKs the
+		 * authentication reply. */
+#else
+		sta->flags |= WLAN_STA_AUTH;
+		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+		sta->auth_alg = WLAN_AUTH_OPEN;
+		mlme_authenticate_indication(hapd, sta);
+#endif
+		break;
+	case WLAN_AUTH_SHARED_KEY:
+		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
+				       fc & WLAN_FC_ISWEP);
+		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
+		mlme_authenticate_indication(hapd, sta);
+		if (sta->challenge && auth_transaction == 1) {
+			resp_ies[0] = WLAN_EID_CHALLENGE;
+			resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
+			os_memcpy(resp_ies + 2, sta->challenge,
+				  WLAN_AUTH_CHALLENGE_LEN);
+			resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
+		}
+		break;
+#ifdef CONFIG_IEEE80211R
+	case WLAN_AUTH_FT:
+		sta->auth_alg = WLAN_AUTH_FT;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+				   "state machine");
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
+				    auth_transaction, mgmt->u.auth.variable,
+				    len - IEEE80211_HDRLEN -
+				    sizeof(mgmt->u.auth),
+				    handle_auth_ft_finish, hapd);
+		/* handle_auth_ft_finish() callback will complete auth. */
+		return;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	case WLAN_AUTH_SAE:
+		handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+		return;
+#endif /* CONFIG_SAE */
+	}
+
+ fail:
+	os_free(identity);
+	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);
+}
+
+
+static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int i, j = 32, aid;
+
+	/* get a unique AID */
+	if (sta->aid > 0) {
+		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
+		return 0;
+	}
+
+	for (i = 0; i < AID_WORDS; i++) {
+		if (hapd->sta_aid[i] == (u32) -1)
+			continue;
+		for (j = 0; j < 32; j++) {
+			if (!(hapd->sta_aid[i] & BIT(j)))
+				break;
+		}
+		if (j < 32)
+			break;
+	}
+	if (j == 32)
+		return -1;
+	aid = i * 32 + j + 1;
+	if (aid > 2007)
+		return -1;
+
+	sta->aid = aid;
+	hapd->sta_aid[i] |= BIT(j);
+	wpa_printf(MSG_DEBUG, "  new AID %d", sta->aid);
+	return 0;
+}
+
+
+static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ssid_ie, size_t ssid_ie_len)
+{
+	if (ssid_ie == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
+	    os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
+		char ssid_txt[33];
+		ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "Station tried to associate with unknown SSID "
+			       "'%s'", ssid_txt);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *wmm_ie, size_t wmm_ie_len)
+{
+	sta->flags &= ~WLAN_STA_WMM;
+	sta->qosinfo = 0;
+	if (wmm_ie && hapd->conf->wmm_enabled) {
+		struct wmm_information_element *wmm;
+
+		if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "invalid WMM element in association "
+				       "request");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		sta->flags |= WLAN_STA_WMM;
+		wmm = (struct wmm_information_element *) wmm_ie;
+		sta->qosinfo = wmm->qos_info;
+	}
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
+			   struct ieee802_11_elems *elems)
+{
+	if (!elems->supp_rates) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "No supported rates element in AssocReq");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (elems->supp_rates_len + elems->ext_supp_rates_len >
+	    sizeof(sta->supported_rates)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Invalid supported rates element length %d+%d",
+			       elems->supp_rates_len,
+			       elems->ext_supp_rates_len);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->supported_rates_len = merge_byte_arrays(
+		sta->supported_rates, sizeof(sta->supported_rates),
+		elems->supp_rates, elems->supp_rates_len,
+		elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+			   const u8 *ies, size_t ies_len, int reassoc)
+{
+	struct ieee802_11_elems elems;
+	u16 resp;
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station sent an invalid "
+			       "association request");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	resp = copy_supp_rates(hapd, sta, &elems);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+#ifdef CONFIG_IEEE80211N
+	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
+				 elems.ht_capabilities_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
+	    !(sta->flags & WLAN_STA_HT)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station does not support "
+			       "mandatory HT PHY - reject association");
+		return WLAN_STATUS_ASSOC_DENIED_NO_HT;
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211AC
+	resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
+				  elems.vht_capabilities_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
+	    !(sta->flags & WLAN_STA_VHT)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station does not support "
+			       "mandatory VHT PHY - reject association");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+#endif /* CONFIG_IEEE80211AC */
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
+		wpa_ie = elems.rsn_ie;
+		wpa_ie_len = elems.rsn_ie_len;
+	} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
+		   elems.wpa_ie) {
+		wpa_ie = elems.wpa_ie;
+		wpa_ie_len = elems.wpa_ie_len;
+	} else {
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+	}
+
+#ifdef CONFIG_WPS
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+	if (hapd->conf->wps_state && elems.wps_ie) {
+		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
+			   "Request - assume WPS is used");
+		sta->flags |= WLAN_STA_WPS;
+		wpabuf_free(sta->wps_ie);
+		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+							  WPS_IE_VENDOR_TYPE);
+		if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+			wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+			sta->flags |= WLAN_STA_WPS2;
+		}
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+		if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
+				   "(Re)Association Request - reject");
+			return WLAN_STATUS_INVALID_IE;
+		}
+	} else if (hapd->conf->wps_state && wpa_ie == NULL) {
+		wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
+			   "(Re)Association Request - possible WPS use");
+		sta->flags |= WLAN_STA_MAYBE_WPS;
+	} else
+#endif /* CONFIG_WPS */
+	if (hapd->conf->wpa && wpa_ie == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "No WPA/RSN IE in association request");
+		return WLAN_STATUS_INVALID_IE;
+	}
+
+	if (hapd->conf->wpa && wpa_ie) {
+		int res;
+		wpa_ie -= 2;
+		wpa_ie_len += 2;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+				   "state machine");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  wpa_ie, wpa_ie_len,
+					  elems.mdie, elems.mdie_len);
+		if (res == WPA_INVALID_GROUP)
+			resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+		else if (res == WPA_INVALID_PAIRWISE)
+			resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		else if (res == WPA_INVALID_AKMP)
+			resp = WLAN_STATUS_AKMP_NOT_VALID;
+		else if (res == WPA_ALLOC_FAIL)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+		else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+		else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+#endif /* CONFIG_IEEE80211W */
+		else if (res == WPA_INVALID_MDIE)
+			resp = WLAN_STATUS_INVALID_MDIE;
+		else if (res != WPA_IE_OK)
+			resp = WLAN_STATUS_INVALID_IE;
+		if (resp != WLAN_STATUS_SUCCESS)
+			return resp;
+#ifdef CONFIG_IEEE80211W
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    sta->sa_query_count > 0)
+			ap_check_sa_query_timeout(hapd, sta);
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+			/*
+			 * STA has already been associated with MFP and SA
+			 * Query timeout has not been reached. Reject the
+			 * association attempt temporarily and start SA Query,
+			 * if one is not pending.
+			 */
+
+			if (sta->sa_query_count == 0)
+				ap_sta_start_sa_query(hapd, sta);
+
+			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+		}
+
+		if (wpa_auth_uses_mfp(sta->wpa_sm))
+			sta->flags |= WLAN_STA_MFP;
+		else
+			sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+		if (sta->auth_alg == WLAN_AUTH_FT) {
+			if (!reassoc) {
+				wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
+					   "to use association (not "
+					   "re-association) with FT auth_alg",
+					   MAC2STR(sta->addr));
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+			}
+
+			resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
+						       ies_len);
+			if (resp != WLAN_STATUS_SUCCESS)
+				return resp;
+		}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_SAE
+		if (wpa_auth_uses_sae(sta->wpa_sm) &&
+		    sta->auth_alg != WLAN_AUTH_SAE) {
+			wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+				   "SAE AKM after non-SAE auth_alg %u",
+				   MAC2STR(sta->addr), sta->auth_alg);
+			return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+		}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_IEEE80211N
+		if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
+		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Station tried to use TKIP with HT "
+				       "association");
+			return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+		}
+#endif /* CONFIG_IEEE80211N */
+	} else
+		wpa_auth_sta_no_wpa(sta->wpa_sm);
+
+#ifdef CONFIG_P2P
+	if (elems.p2p) {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+							  P2P_IE_VENDOR_TYPE);
+
+	} else {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = NULL;
+	}
+
+	p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	wpabuf_free(sta->hs20_ie);
+	if (elems.hs20 && elems.hs20_len > 4) {
+		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+						 elems.hs20_len - 4);
+	} else
+		sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
+			u16 reason_code)
+{
+	int send_len;
+	struct ieee80211_mgmt reply;
+
+	os_memset(&reply, 0, sizeof(reply));
+	reply.frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
+	os_memcpy(reply.da, addr, ETH_ALEN);
+	os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
+
+	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
+	reply.u.deauth.reason_code = host_to_le16(reason_code);
+
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
+			   strerror(errno));
+}
+
+
+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)
+{
+	int send_len;
+	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+	struct ieee80211_mgmt *reply;
+	u8 *p;
+
+	os_memset(buf, 0, sizeof(buf));
+	reply = (struct ieee80211_mgmt *) buf;
+	reply->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+			     (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
+			      WLAN_FC_STYPE_ASSOC_RESP));
+	os_memcpy(reply->da, sta->addr, ETH_ALEN);
+	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
+
+	send_len = IEEE80211_HDRLEN;
+	send_len += sizeof(reply->u.assoc_resp);
+	reply->u.assoc_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+	reply->u.assoc_resp.status_code = host_to_le16(status_code);
+	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
+					       | BIT(14) | BIT(15));
+	/* Supported rates */
+	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
+	/* Extended supported rates */
+	p = hostapd_eid_ext_supp_rates(hapd, p);
+
+#ifdef CONFIG_IEEE80211R
+	if (status_code == WLAN_STATUS_SUCCESS) {
+		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
+		 * Transition Information, RSN, [RIC Response] */
+		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
+						buf + sizeof(buf) - p,
+						sta->auth_alg, ies, ies_len);
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211N
+	p = hostapd_eid_ht_capabilities(hapd, p);
+	p = hostapd_eid_ht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211AC
+	p = hostapd_eid_vht_capabilities(hapd, p);
+	p = hostapd_eid_vht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
+	p = hostapd_eid_ext_capab(hapd, p);
+	p = hostapd_eid_bss_max_idle_period(hapd, p);
+
+	if (sta->flags & WLAN_STA_WMM)
+		p = hostapd_eid_wmm(hapd, p);
+
+#ifdef CONFIG_WPS
+	if ((sta->flags & WLAN_STA_WPS) ||
+	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
+		struct wpabuf *wps = wps_build_assoc_resp_ie();
+		if (wps) {
+			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
+			p += wpabuf_len(wps);
+			wpabuf_free(wps);
+		}
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if (sta->p2p_ie) {
+		struct wpabuf *p2p_resp_ie;
+		enum p2p_status_code status;
+		switch (status_code) {
+		case WLAN_STATUS_SUCCESS:
+			status = P2P_SC_SUCCESS;
+			break;
+		case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+			status = P2P_SC_FAIL_LIMIT_REACHED;
+			break;
+		default:
+			status = P2P_SC_FAIL_INVALID_PARAMS;
+			break;
+		}
+		p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
+		if (p2p_resp_ie) {
+			os_memcpy(p, wpabuf_head(p2p_resp_ie),
+				  wpabuf_len(p2p_resp_ie));
+			p += wpabuf_len(p2p_resp_ie);
+			wpabuf_free(p2p_resp_ie);
+		}
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE)
+		p = hostapd_eid_p2p_manage(hapd, p);
+#endif /* CONFIG_P2P_MANAGER */
+
+	send_len += p - reply->u.assoc_resp.variable;
+
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
+		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
+			   strerror(errno));
+}
+
+
+static void handle_assoc(struct hostapd_data *hapd,
+			 const struct ieee80211_mgmt *mgmt, size_t len,
+			 int reassoc)
+{
+	u16 capab_info, listen_interval;
+	u16 resp = WLAN_STATUS_SUCCESS;
+	const u8 *pos;
+	int left, i;
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
+				      sizeof(mgmt->u.assoc_req))) {
+		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+		       "\n", reassoc, (unsigned long) len);
+		return;
+	}
+
+	if (reassoc) {
+		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
+		listen_interval = le_to_host16(
+			mgmt->u.reassoc_req.listen_interval);
+		wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
+			   " capab_info=0x%02x listen_interval=%d current_ap="
+			   MACSTR,
+			   MAC2STR(mgmt->sa), capab_info, listen_interval,
+			   MAC2STR(mgmt->u.reassoc_req.current_ap));
+		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+		pos = mgmt->u.reassoc_req.variable;
+	} else {
+		capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
+		listen_interval = le_to_host16(
+			mgmt->u.assoc_req.listen_interval);
+		wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
+			   " capab_info=0x%02x listen_interval=%d",
+			   MAC2STR(mgmt->sa), capab_info, listen_interval);
+		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+		pos = mgmt->u.assoc_req.variable;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211R
+	if (sta && sta->auth_alg == WLAN_AUTH_FT &&
+	    (sta->flags & WLAN_STA_AUTH) == 0) {
+		wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
+			   "prior to authentication since it is using "
+			   "over-the-DS FT", MAC2STR(mgmt->sa));
+	} else
+#endif /* CONFIG_IEEE80211R */
+	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station tried to "
+			       "associate before authentication "
+			       "(aid=%d flags=0x%x)",
+			       sta ? sta->aid : -1,
+			       sta ? sta->flags : 0);
+		send_deauth(hapd, mgmt->sa,
+			    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+		return;
+	}
+
+	if (hapd->tkip_countermeasures) {
+		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		goto fail;
+	}
+
+	if (listen_interval > hapd->conf->max_listen_interval) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Too large Listen Interval (%d)",
+			       listen_interval);
+		resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
+		goto fail;
+	}
+
+	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
+	 * is used */
+	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
+	if (resp != WLAN_STATUS_SUCCESS)
+		goto fail;
+
+	if (hostapd_get_aid(hapd, sta) < 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "No room for more AIDs");
+		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+		goto fail;
+	}
+
+	sta->capability = capab_info;
+	sta->listen_interval = listen_interval;
+
+	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		sta->flags |= WLAN_STA_NONERP;
+	for (i = 0; i < sta->supported_rates_len; i++) {
+		if ((sta->supported_rates[i] & 0x7f) > 22) {
+			sta->flags &= ~WLAN_STA_NONERP;
+			break;
+		}
+	}
+	if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
+		sta->nonerp_set = 1;
+		hapd->iface->num_sta_non_erp++;
+		if (hapd->iface->num_sta_non_erp == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
+	    !sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 1;
+		hapd->iface->num_sta_no_short_slot_time++;
+		if (hapd->iface->current_mode->mode ==
+		    HOSTAPD_MODE_IEEE80211G &&
+		    hapd->iface->num_sta_no_short_slot_time == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+	else
+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    !sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 1;
+		hapd->iface->num_sta_no_short_preamble++;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+#ifdef CONFIG_IEEE80211N
+	update_ht_state(hapd, sta);
+#endif /* CONFIG_IEEE80211N */
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "association OK (aid %d)", sta->aid);
+	/* Station will be marked associated, after it acknowledges AssocResp
+	 */
+	sta->flags |= WLAN_STA_ASSOC_REQ_OK;
+
+#ifdef CONFIG_IEEE80211W
+	if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
+		wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
+			   "SA Query procedure", reassoc ? "re" : "");
+		/* TODO: Send a protected Disassociate frame to the STA using
+		 * the old key and Reason Code "Previous Authentication no
+		 * longer valid". Make sure this is only sent protected since
+		 * unprotected frame would be received by the STA that is now
+		 * trying to associate.
+		 */
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (reassoc) {
+		os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
+			  ETH_ALEN);
+	}
+
+	if (sta->last_assoc_req)
+		os_free(sta->last_assoc_req);
+	sta->last_assoc_req = os_malloc(len);
+	if (sta->last_assoc_req)
+		os_memcpy(sta->last_assoc_req, mgmt, len);
+
+	/* Make sure that the previously registered inactivity timer will not
+	 * remove the STA immediately. */
+	sta->timeout_next = STA_NULLFUNC;
+
+ fail:
+	send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+}
+
+
+static void handle_disassoc(struct hostapd_data *hapd,
+			    const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
+		printf("handle_disassoc - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
+		   MAC2STR(mgmt->sa),
+		   le_to_host16(mgmt->u.disassoc.reason_code));
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta == NULL) {
+		printf("Station " MACSTR " trying to disassociate, but it "
+		       "is not associated.\n", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disassociated");
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
+	 * authenticated. */
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+	hostapd_drv_sta_remove(hapd, sta->addr);
+
+	if (sta->timeout_next == STA_NULLFUNC ||
+	    sta->timeout_next == STA_DISASSOC) {
+		sta->timeout_next = STA_DEAUTH;
+		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+	}
+
+	mlme_disassociate_indication(
+		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+}
+
+
+static void handle_deauth(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+			"payload (len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
+		" reason_code=%d",
+		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+			"to deauthenticate, but it is not authenticated",
+			MAC2STR(mgmt->sa));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+			WLAN_STA_ASSOC_REQ_OK);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+	mlme_deauthenticate_indication(
+		hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	ap_free_sta(hapd, sta);
+}
+
+
+static void handle_beacon(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len,
+			  struct hostapd_frame_info *fi)
+{
+	struct ieee802_11_elems elems;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
+		printf("handle_beacon - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	(void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
+				      len - (IEEE80211_HDRLEN +
+					     sizeof(mgmt->u.beacon)), &elems,
+				      0);
+
+	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static void hostapd_sa_query_action(struct hostapd_data *hapd,
+				    const struct ieee80211_mgmt *mgmt,
+				    size_t len)
+{
+	const u8 *end;
+
+	end = mgmt->u.action.u.sa_query_resp.trans_id +
+		WLAN_SA_QUERY_TR_ID_LEN;
+	if (((u8 *) mgmt) + len < end) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
+			   "frame (len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	ieee802_11_sa_query_action(hapd, mgmt->sa,
+				   mgmt->u.action.u.sa_query_resp.action,
+				   mgmt->u.action.u.sa_query_resp.trans_id);
+}
+
+
+static int robust_action_frame(u8 category)
+{
+	return category != WLAN_ACTION_PUBLIC &&
+		category != WLAN_ACTION_HT;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WNM
+static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len)
+{
+	struct rx_action action;
+	if (len < IEEE80211_HDRLEN + 2)
+		return;
+	os_memset(&action, 0, sizeof(action));
+	action.da = mgmt->da;
+	action.sa = mgmt->sa;
+	action.bssid = mgmt->bssid;
+	action.category = mgmt->u.action.category;
+	action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
+	action.len = len - IEEE80211_HDRLEN - 1;
+	action.freq = hapd->iface->freq;
+	ieee802_11_rx_wnm_action_ap(hapd, &action);
+}
+#endif /* CONFIG_WNM */
+
+
+static void handle_action(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+	sta = ap_get_sta(hapd, mgmt->sa);
+
+	if (len < IEEE80211_HDRLEN + 1) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "handle_action - too short payload (len=%lu)",
+			       (unsigned long) len);
+		return;
+	}
+
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+	    (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
+			   "frame (category=%u) from unassociated STA " MACSTR,
+			   MAC2STR(mgmt->sa), mgmt->u.action.category);
+		return;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (sta && (sta->flags & WLAN_STA_MFP) &&
+	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
+	      robust_action_frame(mgmt->u.action.category))) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Dropped unprotected Robust Action frame from "
+			       "an MFP STA");
+		return;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	switch (mgmt->u.action.category) {
+#ifdef CONFIG_IEEE80211R
+	case WLAN_ACTION_FT:
+		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+				     len - IEEE80211_HDRLEN))
+			break;
+		return;
+#endif /* CONFIG_IEEE80211R */
+	case WLAN_ACTION_WMM:
+		hostapd_wmm_action(hapd, mgmt, len);
+		return;
+#ifdef CONFIG_IEEE80211W
+	case WLAN_ACTION_SA_QUERY:
+		hostapd_sa_query_action(hapd, mgmt, len);
+		return;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+	case WLAN_ACTION_WNM:
+		hostapd_wnm_action(hapd, sta, mgmt, len);
+		return;
+#endif /* CONFIG_WNM */
+	case WLAN_ACTION_PUBLIC:
+		if (hapd->public_action_cb) {
+			hapd->public_action_cb(hapd->public_action_cb_ctx,
+					       (u8 *) mgmt, len,
+					       hapd->iface->freq);
+			return;
+		}
+		break;
+	case WLAN_ACTION_VENDOR_SPECIFIC:
+		if (hapd->vendor_action_cb) {
+			if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
+						   (u8 *) mgmt, len,
+						   hapd->iface->freq) == 0)
+				return;
+		}
+		break;
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "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)) {
+		struct ieee80211_mgmt *resp;
+
+		/*
+		 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
+		 * Return the Action frame to the source without change
+		 * except that MSB of the Category set to 1.
+		 */
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
+			   "frame back to sender");
+		resp = os_malloc(len);
+		if (resp == NULL)
+			return;
+		os_memcpy(resp, mgmt, len);
+		os_memcpy(resp->da, resp->sa, ETH_ALEN);
+		os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+		resp->u.action.category |= 0x80;
+
+		if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+			wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
+				   "Action frame");
+		}
+		os_free(resp);
+	}
+}
+
+
+/**
+ * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
+ * @hapd: hostapd BSS data structure (the BSS to which the management frame was
+ * sent to)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @fi: meta data about received frame (signal level, etc.)
+ *
+ * Process all incoming IEEE 802.11 management frames. This will be called for
+ * each frame received from the kernel driver through wlan#ap interface. In
+ * addition, it can be called to re-inserted pending frames (e.g., when using
+ * external RADIUS server as an MAC ACL).
+ */
+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		     struct hostapd_frame_info *fi)
+{
+	struct ieee80211_mgmt *mgmt;
+	int broadcast;
+	u16 fc, stype;
+
+	if (len < 24)
+		return;
+
+	mgmt = (struct ieee80211_mgmt *) buf;
+	fc = le_to_host16(mgmt->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	if (stype == WLAN_FC_STYPE_BEACON) {
+		handle_beacon(hapd, mgmt, len, fi);
+		return;
+	}
+
+	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 &&
+#ifdef CONFIG_P2P
+	    /* Invitation responses can be sent with the peer MAC as BSSID */
+	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	      stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
+	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
+		printf("MGMT: BSSID=" MACSTR " not our address\n",
+		       MAC2STR(mgmt->bssid));
+		return;
+	}
+
+
+	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+		handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+		return;
+	}
+
+	if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "MGMT: DA=" MACSTR " not our address",
+			       MAC2STR(mgmt->da));
+		return;
+	}
+
+	switch (stype) {
+	case WLAN_FC_STYPE_AUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::auth");
+		handle_auth(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_ASSOC_REQ:
+		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
+		handle_assoc(hapd, mgmt, len, 0);
+		break;
+	case WLAN_FC_STYPE_REASSOC_REQ:
+		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
+		handle_assoc(hapd, mgmt, len, 1);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc");
+		handle_disassoc(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_DEAUTH:
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
+		handle_deauth(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_ACTION:
+		wpa_printf(MSG_DEBUG, "mgmt::action");
+		handle_action(hapd, mgmt, len);
+		break;
+	default:
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "unknown mgmt frame subtype %d", stype);
+		break;
+	}
+}
+
+
+static void handle_auth_cb(struct hostapd_data *hapd,
+			   const struct ieee80211_mgmt *mgmt,
+			   size_t len, int ok)
+{
+	u16 auth_alg, auth_transaction, status_code;
+	struct sta_info *sta;
+
+	if (!ok) {
+		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "did not acknowledge authentication response");
+		return;
+	}
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		printf("handle_auth_cb - too short payload (len=%lu)\n",
+		       (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) {
+		printf("handle_auth_cb: STA " MACSTR " not found\n",
+		       MAC2STR(mgmt->da));
+		return;
+	}
+
+	if (status_code == WLAN_STATUS_SUCCESS &&
+	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
+	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "authenticated");
+		sta->flags |= WLAN_STA_AUTH;
+	}
+}
+
+
+static void handle_assoc_cb(struct hostapd_data *hapd,
+			    const struct ieee80211_mgmt *mgmt,
+			    size_t len, int reassoc, int ok)
+{
+	u16 status;
+	struct sta_info *sta;
+	int new_assoc = 1;
+	struct ieee80211_ht_capabilities ht_cap;
+
+	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+				      sizeof(mgmt->u.assoc_resp))) {
+		printf("handle_assoc_cb(reassoc=%d) - too short payload "
+		       "(len=%lu)\n", reassoc, (unsigned long) len);
+		return;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		printf("handle_assoc_cb: STA " MACSTR " not found\n",
+		       MAC2STR(mgmt->da));
+		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;
+		return;
+	}
+
+	if (reassoc)
+		status = le_to_host16(mgmt->u.reassoc_resp.status_code);
+	else
+		status = le_to_host16(mgmt->u.assoc_resp.status_code);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		goto fail;
+
+	/* Stop previous accounting session, if one is started, and allocate
+	 * new session id for the new session. */
+	accounting_sta_stop(hapd, sta);
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO,
+		       "associated (aid %d)",
+		       sta->aid);
+
+	if (sta->flags & WLAN_STA_ASSOC)
+		new_assoc = 0;
+	sta->flags |= WLAN_STA_ASSOC;
+	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+	    sta->auth_alg == WLAN_AUTH_FT) {
+		/*
+		 * Open, static WEP, or FT protocol; no separate authorization
+		 * step.
+		 */
+		ap_sta_set_authorized(hapd, sta, 1);
+	}
+
+	if (reassoc)
+		mlme_reassociate_indication(hapd, sta);
+	else
+		mlme_associate_indication(hapd, sta);
+
+#ifdef CONFIG_IEEE80211W
+	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 */
+
+	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, sta->qosinfo)) {
+		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);
+
+		goto fail;
+	}
+
+	if (sta->flags & WLAN_STA_WDS)
+		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+
+	if (sta->eapol_sm == NULL) {
+		/*
+		 * This STA does not use RADIUS server for EAP authentication,
+		 * so bind it to the selected VLAN interface now, since the
+		 * interface selection is not going to change anymore.
+		 */
+		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+			goto fail;
+	} else if (sta->vlan_id) {
+		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
+		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+			goto fail;
+	}
+
+	hostapd_set_sta_flags(hapd, sta);
+
+	if (sta->auth_alg == WLAN_AUTH_FT)
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+	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);
+
+ fail:
+	/* Copy of the association request is not needed anymore */
+	if (sta->last_assoc_req) {
+		os_free(sta->last_assoc_req);
+		sta->last_assoc_req = NULL;
+	}
+}
+
+
+static void handle_deauth_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "deauth", MAC2STR(sta->addr));
+
+	ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "disassoc", MAC2STR(sta->addr));
+
+	ap_sta_disassoc_cb(hapd, sta);
+}
+
+
+/**
+ * ieee802_11_mgmt_cb - Process management frame TX status callback
+ * @hapd: hostapd BSS data structure (the BSS from which the management frame
+ * was sent from)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ * @ok: Whether the frame was ACK'ed
+ */
+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
+			u16 stype, int ok)
+{
+	const struct ieee80211_mgmt *mgmt;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	switch (stype) {
+	case WLAN_FC_STYPE_AUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::auth cb");
+		handle_auth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_ASSOC_RESP:
+		wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
+		handle_assoc_cb(hapd, mgmt, len, 0, ok);
+		break;
+	case WLAN_FC_STYPE_REASSOC_RESP:
+		wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
+		handle_assoc_cb(hapd, mgmt, len, 1, ok);
+		break;
+	case WLAN_FC_STYPE_PROBE_RESP:
+		wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
+		break;
+	case WLAN_FC_STYPE_DEAUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+		handle_deauth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+		handle_disassoc_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_ACTION:
+		wpa_printf(MSG_DEBUG, "mgmt::action cb");
+		break;
+	default:
+		printf("unknown mgmt cb frame subtype %d\n", stype);
+		break;
+	}
+}
+
+
+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
+		       const u8 *buf, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
+		return;
+	if (sta->flags & WLAN_STA_PENDING_POLL) {
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
+			   "activity poll", MAC2STR(sta->addr),
+			   ack ? "ACKed" : "did not ACK");
+		if (ack)
+			sta->flags &= ~WLAN_STA_PENDING_POLL;
+	}
+
+	ieee802_1x_tx_status(hapd, sta, buf, len, ack);
+}
+
+
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, dst);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
+			   MACSTR " that is not currently associated",
+			   MAC2STR(dst));
+		return;
+	}
+
+	ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (!(sta->flags & WLAN_STA_PENDING_POLL))
+		return;
+
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+		   "activity poll", MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
+				int wds)
+{
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, src);
+	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+		if (!hapd->conf->wds_sta)
+			return;
+
+		if (wds && !(sta->flags & WLAN_STA_WDS)) {
+			wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
+				   "STA " MACSTR " (aid %u)",
+				   MAC2STR(sta->addr), sta->aid);
+			sta->flags |= WLAN_STA_WDS;
+			hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+		}
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
+		   MACSTR, MAC2STR(src));
+	if (src[0] & 0x01) {
+		/* Broadcast bit set in SA?! Ignore the frame silently. */
+		return;
+	}
+
+	if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
+		wpa_printf(MSG_DEBUG, "Association Response to the STA has "
+			   "already been sent, but no TX status yet known - "
+			   "ignore Class 3 frame issue with " MACSTR,
+			   MAC2STR(src));
+		return;
+	}
+
+	if (sta && (sta->flags & WLAN_STA_AUTH))
+		hostapd_drv_sta_disassoc(
+			hapd, src,
+			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+	else
+		hostapd_drv_sta_deauth(
+			hapd, src,
+			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+}
+
+
+#endif /* CONFIG_NATIVE_WINDOWS */

Deleted: vendor/wpa/2.0/src/ap/ieee802_11.h
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_11.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_11.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,67 +0,0 @@
-/*
- * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IEEE802_11_H
-#define IEEE802_11_H
-
-struct hostapd_iface;
-struct hostapd_data;
-struct sta_info;
-struct hostapd_frame_info;
-struct ieee80211_ht_capabilities;
-
-void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
-		     struct hostapd_frame_info *fi);
-void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
-			u16 stype, int ok);
-void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
-#ifdef NEED_AP_MLME
-int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
-int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   char *buf, size_t buflen);
-#else /* NEED_AP_MLME */
-static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf,
-				     size_t buflen)
-{
-	return 0;
-}
-
-static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
-					 struct sta_info *sta,
-					 char *buf, size_t buflen)
-{
-	return 0;
-}
-#endif /* NEED_AP_MLME */
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
-			   int probe);
-u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-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);
-void hostapd_get_ht_capab(struct hostapd_data *hapd,
-			  struct ieee80211_ht_capabilities *ht_cap,
-			  struct ieee80211_ht_capabilities *neg_ht_cap);
-u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
-		      size_t ht_capab_len);
-void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
-void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
-		       const u8 *buf, size_t len, int ack);
-void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
-				int wds);
-
-#endif /* IEEE802_11_H */

Copied: vendor/wpa/2.0/src/ap/ieee802_11.h (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,81 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_H
+#define IEEE802_11_H
+
+struct hostapd_iface;
+struct hostapd_data;
+struct sta_info;
+struct hostapd_frame_info;
+struct ieee80211_ht_capabilities;
+
+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		     struct hostapd_frame_info *fi);
+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
+			u16 stype, int ok);
+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
+#ifdef NEED_AP_MLME
+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen);
+#else /* NEED_AP_MLME */
+static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf,
+				     size_t buflen)
+{
+	return 0;
+}
+
+static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
+					 struct sta_info *sta,
+					 char *buf, size_t buflen)
+{
+	return 0;
+}
+#endif /* NEED_AP_MLME */
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe);
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_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_vht_operation(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);
+void hostapd_get_ht_capab(struct hostapd_data *hapd,
+			  struct ieee80211_ht_capabilities *ht_cap,
+			  struct ieee80211_ht_capabilities *neg_ht_cap);
+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ht_capab, size_t ht_capab_len);
+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *vht_capab, size_t vht_capab_len);
+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
+		       const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack);
+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
+				int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+				const u8 *sa, const u8 action_type,
+				const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* IEEE802_11_H */

Deleted: vendor/wpa/2.0/src/ap/ieee802_11_auth.c
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_11_auth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_11_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,524 +0,0 @@
-/*
- * hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Access control list for IEEE 802.11 authentication can uses statically
- * configured ACL from configuration files or an external RADIUS server.
- * Results from external RADIUS queries are cached to allow faster
- * authentication frame processing.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "ieee802_11_auth.h"
-
-#define RADIUS_ACL_TIMEOUT 30
-
-
-struct hostapd_cached_radius_acl {
-	time_t timestamp;
-	macaddr addr;
-	int accepted; /* HOSTAPD_ACL_* */
-	struct hostapd_cached_radius_acl *next;
-	u32 session_timeout;
-	u32 acct_interim_interval;
-	int vlan_id;
-};
-
-
-struct hostapd_acl_query_data {
-	time_t timestamp;
-	u8 radius_id;
-	macaddr addr;
-	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
-	size_t auth_msg_len;
-	struct hostapd_acl_query_data *next;
-};
-
-
-#ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
-{
-	struct hostapd_cached_radius_acl *prev;
-
-	while (acl_cache) {
-		prev = acl_cache;
-		acl_cache = acl_cache->next;
-		os_free(prev);
-	}
-}
-
-
-static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
-				 u32 *session_timeout,
-				 u32 *acct_interim_interval, int *vlan_id)
-{
-	struct hostapd_cached_radius_acl *entry;
-	time_t now;
-
-	time(&now);
-	entry = hapd->acl_cache;
-
-	while (entry) {
-		if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-			if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
-				return -1; /* entry has expired */
-			if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-				if (session_timeout)
-					*session_timeout =
-						entry->session_timeout;
-			if (acct_interim_interval)
-				*acct_interim_interval =
-					entry->acct_interim_interval;
-			if (vlan_id)
-				*vlan_id = entry->vlan_id;
-			return entry->accepted;
-		}
-
-		entry = entry->next;
-	}
-
-	return -1;
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
-{
-	if (query == NULL)
-		return;
-	os_free(query->auth_msg);
-	os_free(query);
-}
-
-
-#ifndef CONFIG_NO_RADIUS
-static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
-				    struct hostapd_acl_query_data *query)
-{
-	struct radius_msg *msg;
-	char buf[128];
-
-	query->radius_id = radius_client_get_id(hapd->radius);
-	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
-	if (msg == NULL)
-		return -1;
-
-	radius_msg_make_authenticator(msg, addr, ETH_ALEN);
-
-	os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
-				 os_strlen(buf))) {
-		wpa_printf(MSG_DEBUG, "Could not add User-Name");
-		goto fail;
-	}
-
-	if (!radius_msg_add_attr_user_password(
-		    msg, (u8 *) buf, os_strlen(buf),
-		    hapd->conf->radius->auth_server->shared_secret,
-		    hapd->conf->radius->auth_server->shared_secret_len)) {
-		wpa_printf(MSG_DEBUG, "Could not add User-Password");
-		goto fail;
-	}
-
-	if (hapd->conf->own_ip_addr.af == AF_INET &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
-		wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
-		goto fail;
-	}
-
-#ifdef CONFIG_IPV6
-	if (hapd->conf->own_ip_addr.af == AF_INET6 &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
-		wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
-		goto fail;
-	}
-#endif /* CONFIG_IPV6 */
-
-	if (hapd->conf->nas_identifier &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
-				 (u8 *) hapd->conf->nas_identifier,
-				 os_strlen(hapd->conf->nas_identifier))) {
-		wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
-		    MAC2STR(addr));
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
-		goto fail;
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
-				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
-		wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
-				 (u8 *) buf, os_strlen(buf))) {
-		wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
-		goto fail;
-	}
-
-	radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
-	return 0;
-
- fail:
-	radius_msg_free(msg);
-	return -1;
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-/**
- * hostapd_allowed_address - Check whether a specified STA can be authenticated
- * @hapd: hostapd BSS data
- * @addr: MAC address of the STA
- * @msg: Authentication message
- * @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
- */
-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)
-{
-	if (session_timeout)
-		*session_timeout = 0;
-	if (acct_interim_interval)
-		*acct_interim_interval = 0;
-	if (vlan_id)
-		*vlan_id = 0;
-
-	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;
-
-	if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
-#ifdef CONFIG_NO_RADIUS
-		return HOSTAPD_ACL_REJECT;
-#else /* 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);
-		if (res == HOSTAPD_ACL_ACCEPT ||
-		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
-			return res;
-		if (res == HOSTAPD_ACL_REJECT)
-			return HOSTAPD_ACL_REJECT;
-
-		query = hapd->acl_queries;
-		while (query) {
-			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
-				/* pending query in RADIUS retransmit queue;
-				 * do not generate a new one */
-				return HOSTAPD_ACL_PENDING;
-			}
-			query = query->next;
-		}
-
-		if (!hapd->conf->radius->auth_server)
-			return HOSTAPD_ACL_REJECT;
-
-		/* No entry in the cache - query external RADIUS server */
-		query = os_zalloc(sizeof(*query));
-		if (query == NULL) {
-			wpa_printf(MSG_ERROR, "malloc for query data failed");
-			return HOSTAPD_ACL_REJECT;
-		}
-		time(&query->timestamp);
-		os_memcpy(query->addr, addr, ETH_ALEN);
-		if (hostapd_radius_acl_query(hapd, addr, query)) {
-			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
-				   "for ACL query.");
-			hostapd_acl_query_free(query);
-			return HOSTAPD_ACL_REJECT;
-		}
-
-		query->auth_msg = os_malloc(len);
-		if (query->auth_msg == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to allocate memory for "
-				   "auth frame.");
-			hostapd_acl_query_free(query);
-			return HOSTAPD_ACL_REJECT;
-		}
-		os_memcpy(query->auth_msg, msg, len);
-		query->auth_msg_len = len;
-		query->next = hapd->acl_queries;
-		hapd->acl_queries = query;
-
-		/* Queued data will be processed in hostapd_acl_recv_radius()
-		 * when RADIUS server replies to the sent Access-Request. */
-		return HOSTAPD_ACL_PENDING;
-#endif /* CONFIG_NO_RADIUS */
-	}
-
-	return HOSTAPD_ACL_REJECT;
-}
-
-
-#ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
-{
-	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
-
-	prev = NULL;
-	entry = hapd->acl_cache;
-
-	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
-			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
-				   " has expired.", MAC2STR(entry->addr));
-			if (prev)
-				prev->next = entry->next;
-			else
-				hapd->acl_cache = entry->next;
-#ifdef CONFIG_DRIVER_RADIUS_ACL
-			hapd->drv.set_radius_acl_expire(hapd, entry->addr);
-#endif /* CONFIG_DRIVER_RADIUS_ACL */
-			tmp = entry;
-			entry = entry->next;
-			os_free(tmp);
-			continue;
-		}
-
-		prev = entry;
-		entry = entry->next;
-	}
-}
-
-
-static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
-{
-	struct hostapd_acl_query_data *prev, *entry, *tmp;
-
-	prev = NULL;
-	entry = hapd->acl_queries;
-
-	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
-			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
-				   " has expired.", MAC2STR(entry->addr));
-			if (prev)
-				prev->next = entry->next;
-			else
-				hapd->acl_queries = entry->next;
-
-			tmp = entry;
-			entry = entry->next;
-			hostapd_acl_query_free(tmp);
-			continue;
-		}
-
-		prev = entry;
-		entry = entry->next;
-	}
-}
-
-
-/**
- * hostapd_acl_expire - ACL cache expiration callback
- * @eloop_ctx: struct hostapd_data *
- * @timeout_ctx: Not used
- */
-static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	time_t now;
-
-	time(&now);
-	hostapd_acl_expire_cache(hapd, now);
-	hostapd_acl_expire_queries(hapd, now);
-
-	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
-}
-
-
-/**
- * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
- * @msg: RADIUS response message
- * @req: RADIUS request message
- * @shared_secret: RADIUS shared secret
- * @shared_secret_len: Length of shared_secret in octets
- * @data: Context data (struct hostapd_data *)
- * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
- * was processed here) or RADIUS_RX_UNKNOWN if not.
- */
-static RadiusRxResult
-hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
-			const u8 *shared_secret, size_t shared_secret_len,
-			void *data)
-{
-	struct hostapd_data *hapd = data;
-	struct hostapd_acl_query_data *query, *prev;
-	struct hostapd_cached_radius_acl *cache;
-	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-
-	query = hapd->acl_queries;
-	prev = NULL;
-	while (query) {
-		if (query->radius_id == hdr->identifier)
-			break;
-		prev = query;
-		query = query->next;
-	}
-	if (query == NULL)
-		return RADIUS_RX_UNKNOWN;
-
-	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
-		   "message (id=%d)", query->radius_id);
-
-	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
-		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
-			   "correct authenticator - dropped\n");
-		return RADIUS_RX_INVALID_AUTHENTICATOR;
-	}
-
-	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
-	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
-		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
-			   "query", hdr->code);
-		return RADIUS_RX_UNKNOWN;
-	}
-
-	/* Insert Accept/Reject info into ACL cache */
-	cache = os_zalloc(sizeof(*cache));
-	if (cache == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
-		goto done;
-	}
-	time(&cache->timestamp);
-	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
-	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
-		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
-					      &cache->session_timeout) == 0)
-			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
-		else
-			cache->accepted = HOSTAPD_ACL_ACCEPT;
-
-		if (radius_msg_get_attr_int32(
-			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
-			    &cache->acct_interim_interval) == 0 &&
-		    cache->acct_interim_interval < 60) {
-			wpa_printf(MSG_DEBUG, "Ignored too small "
-				   "Acct-Interim-Interval %d for STA " MACSTR,
-				   cache->acct_interim_interval,
-				   MAC2STR(query->addr));
-			cache->acct_interim_interval = 0;
-		}
-
-		cache->vlan_id = radius_msg_get_vlanid(msg);
-	} else
-		cache->accepted = HOSTAPD_ACL_REJECT;
-	cache->next = hapd->acl_cache;
-	hapd->acl_cache = cache;
-
-#ifdef CONFIG_DRIVER_RADIUS_ACL
-	hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted,
-				      cache->session_timeout);
-#else /* CONFIG_DRIVER_RADIUS_ACL */
-#ifdef NEED_AP_MLME
-	/* Re-send original authentication frame for 802.11 processing */
-	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
-		   "successful RADIUS ACL query");
-	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
-#endif /* NEED_AP_MLME */
-#endif /* CONFIG_DRIVER_RADIUS_ACL */
-
- done:
-	if (prev == NULL)
-		hapd->acl_queries = query->next;
-	else
-		prev->next = query->next;
-
-	hostapd_acl_query_free(query);
-
-	return RADIUS_RX_PROCESSED;
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-/**
- * hostapd_acl_init: Initialize IEEE 802.11 ACL
- * @hapd: hostapd BSS data
- * Returns: 0 on success, -1 on failure
- */
-int hostapd_acl_init(struct hostapd_data *hapd)
-{
-#ifndef CONFIG_NO_RADIUS
-	if (radius_client_register(hapd->radius, RADIUS_AUTH,
-				   hostapd_acl_recv_radius, hapd))
-		return -1;
-
-	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
-#endif /* CONFIG_NO_RADIUS */
-
-	return 0;
-}
-
-
-/**
- * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
- * @hapd: hostapd BSS data
- */
-void hostapd_acl_deinit(struct hostapd_data *hapd)
-{
-	struct hostapd_acl_query_data *query, *prev;
-
-#ifndef CONFIG_NO_RADIUS
-	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
-
-	hostapd_acl_cache_free(hapd->acl_cache);
-#endif /* CONFIG_NO_RADIUS */
-
-	query = hapd->acl_queries;
-	while (query) {
-		prev = query;
-		query = query->next;
-		hostapd_acl_query_free(prev);
-	}
-}

Copied: vendor/wpa/2.0/src/ap/ieee802_11_auth.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11_auth.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11_auth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,643 @@
+/*
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Access control list for IEEE 802.11 authentication can uses statically
+ * configured ACL from configuration files or an external RADIUS server.
+ * Results from external RADIUS queries are cached to allow faster
+ * authentication frame processing.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/sha1.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+#include "ieee802_1x.h"
+#include "ieee802_11_auth.h"
+
+#define RADIUS_ACL_TIMEOUT 30
+
+
+struct hostapd_cached_radius_acl {
+	os_time_t timestamp;
+	macaddr addr;
+	int accepted; /* HOSTAPD_ACL_* */
+	struct hostapd_cached_radius_acl *next;
+	u32 session_timeout;
+	u32 acct_interim_interval;
+	int vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk;
+	char *identity;
+	char *radius_cui;
+};
+
+
+struct hostapd_acl_query_data {
+	os_time_t timestamp;
+	u8 radius_id;
+	macaddr addr;
+	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
+	size_t auth_msg_len;
+	struct hostapd_acl_query_data *next;
+};
+
+
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
+{
+	os_free(e->identity);
+	os_free(e->radius_cui);
+	hostapd_free_psk_list(e->psk);
+	os_free(e);
+}
+
+
+static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
+{
+	struct hostapd_cached_radius_acl *prev;
+
+	while (acl_cache) {
+		prev = acl_cache;
+		acl_cache = acl_cache->next;
+		hostapd_acl_cache_free_entry(prev);
+	}
+}
+
+
+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;
+}
+
+
+static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
+				 u32 *session_timeout,
+				 u32 *acct_interim_interval, int *vlan_id,
+				 struct hostapd_sta_wpa_psk_short **psk,
+				 char **identity, char **radius_cui)
+{
+	struct hostapd_cached_radius_acl *entry;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	for (entry = hapd->acl_cache; entry; entry = entry->next) {
+		if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
+			continue;
+
+		if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+			return -1; /* entry has expired */
+		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+			if (session_timeout)
+				*session_timeout = entry->session_timeout;
+		if (acct_interim_interval)
+			*acct_interim_interval =
+				entry->acct_interim_interval;
+		if (vlan_id)
+			*vlan_id = entry->vlan_id;
+		copy_psk_list(psk, entry->psk);
+		if (identity) {
+			if (entry->identity)
+				*identity = os_strdup(entry->identity);
+			else
+				*identity = NULL;
+		}
+		if (radius_cui) {
+			if (entry->radius_cui)
+				*radius_cui = os_strdup(entry->radius_cui);
+			else
+				*radius_cui = NULL;
+		}
+		return entry->accepted;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
+{
+	if (query == NULL)
+		return;
+	os_free(query->auth_msg);
+	os_free(query);
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
+				    struct hostapd_acl_query_data *query)
+{
+	struct radius_msg *msg;
+	char buf[128];
+
+	query->radius_id = radius_client_get_id(hapd->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
+	if (msg == NULL)
+		return -1;
+
+	radius_msg_make_authenticator(msg, addr, ETH_ALEN);
+
+	os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
+				 os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add User-Name");
+		goto fail;
+	}
+
+	if (!radius_msg_add_attr_user_password(
+		    msg, (u8 *) buf, os_strlen(buf),
+		    hapd->conf->radius->auth_server->shared_secret,
+		    hapd->conf->radius->auth_server->shared_secret_len)) {
+		wpa_printf(MSG_DEBUG, "Could not add User-Password");
+		goto fail;
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
+				   NULL, msg) < 0)
+		goto fail;
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(addr));
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
+		goto fail;
+	}
+
+	os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
+		goto fail;
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+		goto fail;
+	return 0;
+
+ fail:
+	radius_msg_free(msg);
+	return -1;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_allowed_address - Check whether a specified STA can be authenticated
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @msg: Authentication message
+ * @len: Length of msg in octets
+ * @session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
+ * @vlan_id: Buffer for returning VLAN ID
+ * @psk: Linked list buffer for returning WPA PSK
+ * @identity: Buffer for returning identity (from RADIUS)
+ * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ *
+ * The caller is responsible for freeing the returned *identity and *radius_cui
+ * values with os_free().
+ */
+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,
+			    struct hostapd_sta_wpa_psk_short **psk,
+			    char **identity, char **radius_cui)
+{
+	if (session_timeout)
+		*session_timeout = 0;
+	if (acct_interim_interval)
+		*acct_interim_interval = 0;
+	if (vlan_id)
+		*vlan_id = 0;
+	if (psk)
+		*psk = NULL;
+	if (identity)
+		*identity = NULL;
+	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;
+
+	if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
+#ifdef CONFIG_NO_RADIUS
+		return HOSTAPD_ACL_REJECT;
+#else /* CONFIG_NO_RADIUS */
+		struct hostapd_acl_query_data *query;
+		struct os_time t;
+
+		/* 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);
+		if (res == HOSTAPD_ACL_ACCEPT ||
+		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+			return res;
+		if (res == HOSTAPD_ACL_REJECT)
+			return HOSTAPD_ACL_REJECT;
+
+		query = hapd->acl_queries;
+		while (query) {
+			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
+				/* pending query in RADIUS retransmit queue;
+				 * do not generate a new one */
+				if (identity) {
+					os_free(*identity);
+					*identity = NULL;
+				}
+				if (radius_cui) {
+					os_free(*radius_cui);
+					*radius_cui = NULL;
+				}
+				return HOSTAPD_ACL_PENDING;
+			}
+			query = query->next;
+		}
+
+		if (!hapd->conf->radius->auth_server)
+			return HOSTAPD_ACL_REJECT;
+
+		/* No entry in the cache - query external RADIUS server */
+		query = os_zalloc(sizeof(*query));
+		if (query == NULL) {
+			wpa_printf(MSG_ERROR, "malloc for query data failed");
+			return HOSTAPD_ACL_REJECT;
+		}
+		os_get_time(&t);
+		query->timestamp = t.sec;
+		os_memcpy(query->addr, addr, ETH_ALEN);
+		if (hostapd_radius_acl_query(hapd, addr, query)) {
+			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
+				   "for ACL query.");
+			hostapd_acl_query_free(query);
+			return HOSTAPD_ACL_REJECT;
+		}
+
+		query->auth_msg = os_malloc(len);
+		if (query->auth_msg == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+				   "auth frame.");
+			hostapd_acl_query_free(query);
+			return HOSTAPD_ACL_REJECT;
+		}
+		os_memcpy(query->auth_msg, msg, len);
+		query->auth_msg_len = len;
+		query->next = hapd->acl_queries;
+		hapd->acl_queries = query;
+
+		/* Queued data will be processed in hostapd_acl_recv_radius()
+		 * when RADIUS server replies to the sent Access-Request. */
+		return HOSTAPD_ACL_PENDING;
+#endif /* CONFIG_NO_RADIUS */
+	}
+
+	return HOSTAPD_ACL_REJECT;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+{
+	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
+
+	prev = NULL;
+	entry = hapd->acl_cache;
+
+	while (entry) {
+		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
+				   " has expired.", MAC2STR(entry->addr));
+			if (prev)
+				prev->next = entry->next;
+			else
+				hapd->acl_cache = entry->next;
+			hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
+			tmp = entry;
+			entry = entry->next;
+			hostapd_acl_cache_free_entry(tmp);
+			continue;
+		}
+
+		prev = entry;
+		entry = entry->next;
+	}
+}
+
+
+static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
+				       os_time_t now)
+{
+	struct hostapd_acl_query_data *prev, *entry, *tmp;
+
+	prev = NULL;
+	entry = hapd->acl_queries;
+
+	while (entry) {
+		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
+				   " has expired.", MAC2STR(entry->addr));
+			if (prev)
+				prev->next = entry->next;
+			else
+				hapd->acl_queries = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			hostapd_acl_query_free(tmp);
+			continue;
+		}
+
+		prev = entry;
+		entry = entry->next;
+	}
+}
+
+
+/**
+ * hostapd_acl_expire - ACL cache expiration callback
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: Not used
+ */
+static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	hostapd_acl_expire_cache(hapd, now.sec);
+	hostapd_acl_expire_queries(hapd, now.sec);
+
+	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
+}
+
+
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+				    const u8 *shared_secret,
+				    size_t shared_secret_len,
+				    struct radius_msg *msg,
+				    struct radius_msg *req,
+				    struct hostapd_cached_radius_acl *cache)
+{
+	int passphraselen;
+	char *passphrase, *strpassphrase;
+	size_t i;
+	struct hostapd_sta_wpa_psk_short *psk;
+
+	/*
+	 * Decode all tunnel passwords as PSK and save them into a linked list.
+	 */
+	for (i = 0; ; i++) {
+		passphrase = radius_msg_get_tunnel_password(
+			msg, &passphraselen, shared_secret, shared_secret_len,
+			req, i);
+		/*
+		 * Passphrase is NULL iff there is no i-th Tunnel-Password
+		 * attribute in msg.
+		 */
+		if (passphrase == NULL)
+			break;
+		/*
+		 * 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);
+			psk->next = cache->psk;
+			cache->psk = psk;
+			psk = NULL;
+		}
+		os_free(strpassphrase);
+		os_free(psk);
+		os_free(passphrase);
+	}
+}
+
+
+/**
+ * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
+ * was processed here) or RADIUS_RX_UNKNOWN if not.
+ */
+static RadiusRxResult
+hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+			const u8 *shared_secret, size_t shared_secret_len,
+			void *data)
+{
+	struct hostapd_data *hapd = data;
+	struct hostapd_acl_query_data *query, *prev;
+	struct hostapd_cached_radius_acl *cache;
+	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+	struct os_time t;
+
+	query = hapd->acl_queries;
+	prev = NULL;
+	while (query) {
+		if (query->radius_id == hdr->identifier)
+			break;
+		prev = query;
+		query = query->next;
+	}
+	if (query == NULL)
+		return RADIUS_RX_UNKNOWN;
+
+	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
+		   "message (id=%d)", query->radius_id);
+
+	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
+			   "correct authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
+		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
+			   "query", hdr->code);
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	/* Insert Accept/Reject info into ACL cache */
+	cache = os_zalloc(sizeof(*cache));
+	if (cache == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
+		goto done;
+	}
+	os_get_time(&t);
+	cache->timestamp = t.sec;
+	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+		u8 *buf;
+		size_t len;
+
+		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
+					      &cache->session_timeout) == 0)
+			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
+		else
+			cache->accepted = HOSTAPD_ACL_ACCEPT;
+
+		if (radius_msg_get_attr_int32(
+			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
+			    &cache->acct_interim_interval) == 0 &&
+		    cache->acct_interim_interval < 60) {
+			wpa_printf(MSG_DEBUG, "Ignored too small "
+				   "Acct-Interim-Interval %d for STA " MACSTR,
+				   cache->acct_interim_interval,
+				   MAC2STR(query->addr));
+			cache->acct_interim_interval = 0;
+		}
+
+		cache->vlan_id = radius_msg_get_vlanid(msg);
+
+		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
+					msg, req, cache);
+
+		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+					    &buf, &len, NULL) == 0) {
+			cache->identity = os_zalloc(len + 1);
+			if (cache->identity)
+				os_memcpy(cache->identity, buf, len);
+		}
+		if (radius_msg_get_attr_ptr(
+			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+			    &buf, &len, NULL) == 0) {
+			cache->radius_cui = os_zalloc(len + 1);
+			if (cache->radius_cui)
+				os_memcpy(cache->radius_cui, buf, len);
+		}
+
+		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+		    !cache->psk)
+			cache->accepted = HOSTAPD_ACL_REJECT;
+	} else
+		cache->accepted = HOSTAPD_ACL_REJECT;
+	cache->next = hapd->acl_cache;
+	hapd->acl_cache = cache;
+
+#ifdef CONFIG_DRIVER_RADIUS_ACL
+	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
+					cache->session_timeout);
+#else /* CONFIG_DRIVER_RADIUS_ACL */
+#ifdef NEED_AP_MLME
+	/* Re-send original authentication frame for 802.11 processing */
+	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
+		   "successful RADIUS ACL query");
+	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_DRIVER_RADIUS_ACL */
+
+ done:
+	if (prev == NULL)
+		hapd->acl_queries = query->next;
+	else
+		prev->next = query->next;
+
+	hostapd_acl_query_free(query);
+
+	return RADIUS_RX_PROCESSED;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_acl_init: Initialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+int hostapd_acl_init(struct hostapd_data *hapd)
+{
+#ifndef CONFIG_NO_RADIUS
+	if (radius_client_register(hapd->radius, RADIUS_AUTH,
+				   hostapd_acl_recv_radius, hapd))
+		return -1;
+
+	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
+#endif /* CONFIG_NO_RADIUS */
+
+	return 0;
+}
+
+
+/**
+ * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ */
+void hostapd_acl_deinit(struct hostapd_data *hapd)
+{
+	struct hostapd_acl_query_data *query, *prev;
+
+#ifndef CONFIG_NO_RADIUS
+	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
+
+	hostapd_acl_cache_free(hapd->acl_cache);
+#endif /* CONFIG_NO_RADIUS */
+
+	query = hapd->acl_queries;
+	while (query) {
+		prev = query;
+		query = query->next;
+		hostapd_acl_query_free(prev);
+	}
+}
+
+
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
+{
+	while (psk) {
+		struct hostapd_sta_wpa_psk_short *prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
+}

Deleted: vendor/wpa/2.0/src/ap/ieee802_11_auth.h
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_11_auth.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_11_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,31 +0,0 @@
-/*
- * hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IEEE802_11_AUTH_H
-#define IEEE802_11_AUTH_H
-
-enum {
-	HOSTAPD_ACL_REJECT = 0,
-	HOSTAPD_ACL_ACCEPT = 1,
-	HOSTAPD_ACL_PENDING = 2,
-	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
-};
-
-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);
-int hostapd_acl_init(struct hostapd_data *hapd);
-void hostapd_acl_deinit(struct hostapd_data *hapd);
-
-#endif /* IEEE802_11_AUTH_H */

Copied: vendor/wpa/2.0/src/ap/ieee802_11_auth.h (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11_auth.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11_auth.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_AUTH_H
+#define IEEE802_11_AUTH_H
+
+enum {
+	HOSTAPD_ACL_REJECT = 0,
+	HOSTAPD_ACL_ACCEPT = 1,
+	HOSTAPD_ACL_PENDING = 2,
+	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
+};
+
+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,
+			    struct hostapd_sta_wpa_psk_short **psk,
+			    char **identity, char **radius_cui);
+int hostapd_acl_init(struct hostapd_data *hapd);
+void hostapd_acl_deinit(struct hostapd_data *hapd);
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
+
+#endif /* IEEE802_11_AUTH_H */

Deleted: vendor/wpa/2.0/src/ap/ieee802_11_ht.c
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_11_ht.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_11_ht.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,270 +0,0 @@
-/*
- * hostapd / IEEE 802.11n HT
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2007-2008, Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "sta_info.h"
-#include "beacon.h"
-#include "ieee802_11.h"
-
-
-u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
-{
-	struct ieee80211_ht_capabilities *cap;
-	u8 *pos = eid;
-
-	if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode)
-		return eid;
-
-	*pos++ = WLAN_EID_HT_CAP;
-	*pos++ = sizeof(*cap);
-
-	cap = (struct ieee80211_ht_capabilities *) pos;
-	os_memset(cap, 0, sizeof(*cap));
-	cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab);
-	cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params;
-	os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set,
-		  16);
-
-	/* TODO: ht_extended_capabilities (now fully disabled) */
-	/* TODO: tx_bf_capability_info (now fully disabled) */
-	/* TODO: asel_capabilities (now fully disabled) */
-
- 	pos += sizeof(*cap);
-
-	return pos;
-}
-
-
-u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
-{
-	struct ieee80211_ht_operation *oper;
-	u8 *pos = eid;
-
-	if (!hapd->iconf->ieee80211n)
-		return eid;
-
-	*pos++ = WLAN_EID_HT_OPERATION;
-	*pos++ = sizeof(*oper);
-
-	oper = (struct ieee80211_ht_operation *) pos;
-	os_memset(oper, 0, sizeof(*oper));
-
-	oper->control_chan = hapd->iconf->channel;
-	oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
-	if (hapd->iconf->secondary_channel == 1)
-		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
-			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
-	if (hapd->iconf->secondary_channel == -1)
-		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
-			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
-
-	pos += sizeof(*oper);
-
-	return pos;
-}
-
-
-/*
-op_mode
-Set to 0 (HT pure) under the followign conditions
-	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
-	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
-Set to 1 (HT non-member protection) if there may be non-HT STAs
-	in both the primary and the secondary channel
-Set to 2 if only HT STAs are associated in BSS,
-	however and at least one 20 MHz HT STA is associated
-Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
-	(currently non-GF HT station is considered as non-HT STA also)
-*/
-int hostapd_ht_operation_update(struct hostapd_iface *iface)
-{
-	u16 cur_op_mode, new_op_mode;
-	int op_mode_changes = 0;
-
-	if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
-		   __func__, iface->ht_op_mode);
-
-	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
-	    && iface->num_sta_ht_no_gf) {
-		iface->ht_op_mode |=
-			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
-		op_mode_changes++;
-	} else if ((iface->ht_op_mode &
-		    HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
-		   iface->num_sta_ht_no_gf == 0) {
-		iface->ht_op_mode &=
-			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
-		op_mode_changes++;
-	}
-
-	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
-	    (iface->num_sta_no_ht || iface->olbc_ht)) {
-		iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
-		op_mode_changes++;
-	} else if ((iface->ht_op_mode &
-		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
-		   (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
-		iface->ht_op_mode &=
-			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
-		op_mode_changes++;
-	}
-
-	/* Note: currently we switch to the MIXED op mode if HT non-greenfield
-	 * station is associated. Probably it's a theoretical case, since
-	 * it looks like all known HT STAs support greenfield.
-	 */
-	new_op_mode = 0;
-	if (iface->num_sta_no_ht ||
-	    (iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
-		new_op_mode = OP_MODE_MIXED;
-	else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
-		 && iface->num_sta_ht_20mhz)
-		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
-	else if (iface->olbc_ht)
-		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
-	else
-		new_op_mode = OP_MODE_PURE;
-
-	cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
-	if (cur_op_mode != new_op_mode) {
-		iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
-		iface->ht_op_mode |= new_op_mode;
-		op_mode_changes++;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
-		   __func__, iface->ht_op_mode, op_mode_changes);
-
-	return op_mode_changes;
-}
-
-
-u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
-		      size_t ht_capab_len)
-{
-	if (!ht_capab ||
-	    ht_capab_len < sizeof(struct ieee80211_ht_capabilities)) {
-		sta->flags &= ~WLAN_STA_HT;
-		os_free(sta->ht_capabilities);
-		sta->ht_capabilities = NULL;
-		return WLAN_STATUS_SUCCESS;
-	}
-
-	if (sta->ht_capabilities == NULL) {
-		sta->ht_capabilities =
-			os_zalloc(sizeof(struct ieee80211_ht_capabilities));
-		if (sta->ht_capabilities == NULL)
-			return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	sta->flags |= WLAN_STA_HT;
-	os_memcpy(sta->ht_capabilities, ht_capab,
-		  sizeof(struct ieee80211_ht_capabilities));
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	u16 ht_capab;
-
-	ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
-	wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: "
-		   "0x%04x", MAC2STR(sta->addr), ht_capab);
-	if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
-		if (!sta->no_ht_gf_set) {
-			sta->no_ht_gf_set = 1;
-			hapd->iface->num_sta_ht_no_gf++;
-		}
-		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num "
-			   "of non-gf stations %d",
-			   __func__, MAC2STR(sta->addr),
-			   hapd->iface->num_sta_ht_no_gf);
-	}
-	if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
-		if (!sta->ht_20mhz_set) {
-			sta->ht_20mhz_set = 1;
-			hapd->iface->num_sta_ht_20mhz++;
-		}
-		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of "
-			   "20MHz HT STAs %d",
-			   __func__, MAC2STR(sta->addr),
-			   hapd->iface->num_sta_ht_20mhz);
-	}
-}
-
-
-static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	if (!sta->no_ht_set) {
-		sta->no_ht_set = 1;
-		hapd->iface->num_sta_no_ht++;
-	}
-	if (hapd->iconf->ieee80211n) {
-		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of "
-			   "non-HT stations %d",
-			   __func__, MAC2STR(sta->addr),
-			   hapd->iface->num_sta_no_ht);
-	}
-}
-
-
-void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
-		update_sta_ht(hapd, sta);
-	else
-		update_sta_no_ht(hapd, sta);
-
-	if (hostapd_ht_operation_update(hapd->iface) > 0)
-		ieee802_11_set_beacons(hapd->iface);
-}
-
-
-void hostapd_get_ht_capab(struct hostapd_data *hapd,
-			  struct ieee80211_ht_capabilities *ht_cap,
-			  struct ieee80211_ht_capabilities *neg_ht_cap)
-{
-	u16 cap;
-
-	if (ht_cap == NULL)
-		return;
-	os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
-	cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
-	cap &= hapd->iconf->ht_capab;
-	cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
-
-	/*
-	 * STBC needs to be handled specially
-	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
-	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
-	 */
-	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK))
-		cap &= ~HT_CAP_INFO_TX_STBC;
-	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC))
-		cap &= ~HT_CAP_INFO_RX_STBC_MASK;
-
-	neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
-}

Copied: vendor/wpa/2.0/src/ap/ieee802_11_ht.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11_ht.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11_ht.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11_ht.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,273 @@
+/*
+ * hostapd / IEEE 802.11n HT
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_ht_capabilities *cap;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
+	    hapd->conf->disable_11n)
+		return eid;
+
+	*pos++ = WLAN_EID_HT_CAP;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_ht_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+	cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab);
+	cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params;
+	os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set,
+		  16);
+
+	/* TODO: ht_extended_capabilities (now fully disabled) */
+	/* TODO: tx_bf_capability_info (now fully disabled) */
+	/* TODO: asel_capabilities (now fully disabled) */
+
+ 	pos += sizeof(*cap);
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_ht_operation *oper;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		return eid;
+
+	*pos++ = WLAN_EID_HT_OPERATION;
+	*pos++ = sizeof(*oper);
+
+	oper = (struct ieee80211_ht_operation *) pos;
+	os_memset(oper, 0, sizeof(*oper));
+
+	oper->control_chan = hapd->iconf->channel;
+	oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
+	if (hapd->iconf->secondary_channel == 1)
+		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+	if (hapd->iconf->secondary_channel == -1)
+		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+
+	pos += sizeof(*oper);
+
+	return pos;
+}
+
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+	in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+	however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+*/
+int hostapd_ht_operation_update(struct hostapd_iface *iface)
+{
+	u16 cur_op_mode, new_op_mode;
+	int op_mode_changes = 0;
+
+	if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
+		   __func__, iface->ht_op_mode);
+
+	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+	    && iface->num_sta_ht_no_gf) {
+		iface->ht_op_mode |=
+			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	} else if ((iface->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+		   iface->num_sta_ht_no_gf == 0) {
+		iface->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	}
+
+	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+	    (iface->num_sta_no_ht || iface->olbc_ht)) {
+		iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	} else if ((iface->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+		   (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
+		iface->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	}
+
+	new_op_mode = 0;
+	if (iface->num_sta_no_ht)
+		new_op_mode = OP_MODE_MIXED;
+	else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+		 && iface->num_sta_ht_20mhz)
+		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+	else if (iface->olbc_ht)
+		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+	else
+		new_op_mode = OP_MODE_PURE;
+
+	cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+	if (cur_op_mode != new_op_mode) {
+		iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+		iface->ht_op_mode |= new_op_mode;
+		op_mode_changes++;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
+		   __func__, iface->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+}
+
+
+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ht_capab, size_t ht_capab_len)
+{
+	/* Disable HT caps for STAs associated to no-HT BSSes. */
+	if (!ht_capab ||
+	    ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
+	    hapd->conf->disable_11n) {
+		sta->flags &= ~WLAN_STA_HT;
+		os_free(sta->ht_capabilities);
+		sta->ht_capabilities = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (sta->ht_capabilities == NULL) {
+		sta->ht_capabilities =
+			os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+		if (sta->ht_capabilities == NULL)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_HT;
+	os_memcpy(sta->ht_capabilities, ht_capab,
+		  sizeof(struct ieee80211_ht_capabilities));
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	u16 ht_capab;
+
+	ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
+	wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: "
+		   "0x%04x", MAC2STR(sta->addr), ht_capab);
+	if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
+		if (!sta->no_ht_gf_set) {
+			sta->no_ht_gf_set = 1;
+			hapd->iface->num_sta_ht_no_gf++;
+		}
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num "
+			   "of non-gf stations %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_ht_no_gf);
+	}
+	if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
+		if (!sta->ht_20mhz_set) {
+			sta->ht_20mhz_set = 1;
+			hapd->iface->num_sta_ht_20mhz++;
+		}
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of "
+			   "20MHz HT STAs %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_ht_20mhz);
+	}
+}
+
+
+static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!sta->no_ht_set) {
+		sta->no_ht_set = 1;
+		hapd->iface->num_sta_no_ht++;
+	}
+	if (hapd->iconf->ieee80211n) {
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of "
+			   "non-HT stations %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_no_ht);
+	}
+}
+
+
+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
+		update_sta_ht(hapd, sta);
+	else
+		update_sta_no_ht(hapd, sta);
+
+	if (hostapd_ht_operation_update(hapd->iface) > 0)
+		ieee802_11_set_beacons(hapd->iface);
+}
+
+
+void hostapd_get_ht_capab(struct hostapd_data *hapd,
+			  struct ieee80211_ht_capabilities *ht_cap,
+			  struct ieee80211_ht_capabilities *neg_ht_cap)
+{
+	u16 cap;
+
+	if (ht_cap == NULL)
+		return;
+	os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
+	cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
+
+	/*
+	 * Mask out HT features we don't support, but don't overwrite
+	 * non-symmetric features like STBC and SMPS. Just because
+	 * we're not in dynamic SMPS mode the STA might still be.
+	 */
+	cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+		HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
+
+	/*
+	 * STBC needs to be handled specially
+	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+	 */
+	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK))
+		cap &= ~HT_CAP_INFO_TX_STBC;
+	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC))
+		cap &= ~HT_CAP_INFO_RX_STBC_MASK;
+
+	neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
+}

Copied: vendor/wpa/2.0/src/ap/ieee802_11_shared.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11_shared.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11_shared.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11_shared.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,458 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2012, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid)
+{
+	u8 *pos = eid;
+	u32 timeout, tu;
+	struct os_time now, passed;
+
+	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+	*pos++ = 5;
+	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout > tu)
+		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+	else
+		timeout = 0;
+	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+		timeout++; /* add some extra time for local timers */
+	WPA_PUT_LE32(pos, timeout);
+	pos += 4;
+
+	return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+				  const u8 *addr, const u8 *trans_id)
+{
+	struct ieee80211_mgmt mgmt;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+		   MACSTR, MAC2STR(addr));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	os_memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt.da, addr, ETH_ALEN);
+	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+		perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+					  const u8 *sa, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	struct ieee80211_mgmt resp;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+			   "from unassociated STA " MACSTR, MAC2STR(sa));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+		   MACSTR, MAC2STR(sa));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(resp.da, sa, ETH_ALEN);
+	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+	resp.u.action.category = WLAN_ACTION_SA_QUERY;
+	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+	os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+		perror("ieee80211_mgmt_sa_query_request: send");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+				const u8 action_type, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	int i;
+
+	if (action_type == WLAN_SA_QUERY_REQUEST) {
+		ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+		return;
+	}
+
+	if (action_type != WLAN_SA_QUERY_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+			   "Action %d", action_type);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	/* MLME-SAQuery.confirm */
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || sta->sa_query_trans_id == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+			   "pending SA Query request found");
+		return;
+	}
+
+	for (i = 0; i < sta->sa_query_count; i++) {
+		if (os_memcmp(sta->sa_query_trans_id +
+			      i * WLAN_SA_QUERY_TR_ID_LEN,
+			      trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+			break;
+	}
+
+	if (i >= sta->sa_query_count) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+			   "transaction identifier found");
+		return;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Reply to pending SA Query received");
+	ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = 0;
+
+	if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+		len = 5;
+	if (len < 4 && hapd->conf->interworking)
+		len = 4;
+	if (len < 3 && hapd->conf->wnm_sleep_mode)
+		len = 3;
+	if (len < 7 && hapd->conf->ssid.utf8_ssid)
+		len = 7;
+#ifdef CONFIG_WNM
+	if (len < 4)
+		len = 4;
+#endif /* CONFIG_WNM */
+	if (len == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = len;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+
+	*pos = 0x00;
+	if (hapd->conf->wnm_sleep_mode)
+		*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+	if (hapd->conf->bss_transition)
+		*pos |= 0x08; /* Bit 19 - BSS Transition */
+	pos++;
+
+	if (len < 4)
+		return pos;
+	*pos = 0x00;
+#ifdef CONFIG_WNM
+	*pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+	if (hapd->conf->time_advertisement == 2)
+		*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+	if (hapd->conf->interworking)
+		*pos |= 0x80; /* Bit 31 - Interworking */
+	pos++;
+
+	if (len < 5)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->tdls & TDLS_PROHIBIT)
+		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
+		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+	pos++;
+
+	if (len < 6)
+		return pos;
+	*pos = 0x00;
+	pos++;
+
+	if (len < 7)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->ssid.utf8_ssid)
+		*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+	pos++;
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_INTERWORKING;
+	len = pos++;
+
+	*pos = hapd->conf->access_network_type;
+	if (hapd->conf->internet)
+		*pos |= INTERWORKING_ANO_INTERNET;
+	if (hapd->conf->asra)
+		*pos |= INTERWORKING_ANO_ASRA;
+	if (hapd->conf->esr)
+		*pos |= INTERWORKING_ANO_ESR;
+	if (hapd->conf->uesa)
+		*pos |= INTERWORKING_ANO_UESA;
+	pos++;
+
+	if (hapd->conf->venue_info_set) {
+		*pos++ = hapd->conf->venue_group;
+		*pos++ = hapd->conf->venue_type;
+	}
+
+	if (!is_zero_ether_addr(hapd->conf->hessid)) {
+		os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+		pos += ETH_ALEN;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+	/* TODO: Separate configuration for ANQP? */
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_ADV_PROTO;
+	*pos++ = 2;
+	*pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+	*pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+	unsigned int i, count;
+
+	if (!hapd->conf->interworking ||
+	    hapd->conf->roaming_consortium == NULL ||
+	    hapd->conf->roaming_consortium_count == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+	len = pos++;
+
+	/* Number of ANQP OIs (in addition to the max 3 listed here) */
+	if (hapd->conf->roaming_consortium_count > 3 + 255)
+		*pos++ = 255;
+	else if (hapd->conf->roaming_consortium_count > 3)
+		*pos++ = hapd->conf->roaming_consortium_count - 3;
+	else
+		*pos++ = 0;
+
+	/* OU #1 and #2 Lengths */
+	*pos = hapd->conf->roaming_consortium[0].len;
+	if (hapd->conf->roaming_consortium_count > 1)
+		*pos |= hapd->conf->roaming_consortium[1].len << 4;
+	pos++;
+
+	if (hapd->conf->roaming_consortium_count > 3)
+		count = 3;
+	else
+		count = hapd->conf->roaming_consortium_count;
+
+	for (i = 0; i < count; i++) {
+		os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+			  hapd->conf->roaming_consortium[i].len);
+		pos += hapd->conf->roaming_consortium[i].len;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	if (hapd->time_adv == NULL &&
+	    hostapd_update_time_adv(hapd) < 0)
+		return eid;
+
+	if (hapd->time_adv == NULL)
+		return eid;
+
+	os_memcpy(eid, wpabuf_head(hapd->time_adv),
+		  wpabuf_len(hapd->time_adv));
+	eid += wpabuf_len(hapd->time_adv);
+
+	return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+	size_t len;
+
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	len = os_strlen(hapd->conf->time_zone);
+
+	*eid++ = WLAN_EID_TIME_ZONE;
+	*eid++ = len;
+	os_memcpy(eid, hapd->conf->time_zone, len);
+	eid += len;
+
+	return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+	const int elen = 2 + 1 + 10 + 5 + 1;
+	struct os_time t;
+	struct os_tm tm;
+	u8 *pos;
+
+	if (hapd->conf->time_advertisement != 2)
+		return 0;
+
+	if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+		return -1;
+
+	if (!hapd->time_adv) {
+		hapd->time_adv = wpabuf_alloc(elen);
+		if (hapd->time_adv == NULL)
+			return -1;
+		pos = wpabuf_put(hapd->time_adv, elen);
+	} else
+		pos = wpabuf_mhead_u8(hapd->time_adv);
+
+	*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+	*pos++ = 1 + 10 + 5 + 1;
+
+	*pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+	/* Time Value at TSF 0 */
+	/* FIX: need to calculate this based on the current TSF value */
+	WPA_PUT_LE16(pos, tm.year); /* Year */
+	pos += 2;
+	*pos++ = tm.month; /* Month */
+	*pos++ = tm.day; /* Day of month */
+	*pos++ = tm.hour; /* Hours */
+	*pos++ = tm.min; /* Minutes */
+	*pos++ = tm.sec; /* Seconds */
+	WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+	pos += 2;
+	*pos++ = 0; /* Reserved */
+
+	/* Time Error */
+	/* TODO: fill in an estimate on the error */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+
+	*pos++ = hapd->time_update_counter++;
+
+	return 0;
+}
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+	if (hapd->conf->ap_max_inactivity > 0) {
+		unsigned int val;
+		*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+		*pos++ = 3;
+		val = hapd->conf->ap_max_inactivity;
+		if (val > 68000)
+			val = 68000;
+		val *= 1000;
+		val /= 1024;
+		if (val == 0)
+			val = 1;
+		if (val > 65535)
+			val = 65535;
+		WPA_PUT_LE16(pos, val);
+		pos += 2;
+		*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+	}
+#endif /* CONFIG_WNM */
+
+	return pos;
+}

Copied: vendor/wpa/2.0/src/ap/ieee802_11_vht.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_11_vht.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_11_vht.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_11_vht.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,110 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of BSD license
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_vht_capabilities *cap;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
+	    hapd->conf->disable_11ac)
+		return eid;
+
+	*pos++ = WLAN_EID_VHT_CAP;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_vht_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+	cap->vht_capabilities_info = host_to_le32(
+		hapd->iface->current_mode->vht_capab);
+
+	/* Supported MCS set comes from hw */
+	os_memcpy(cap->vht_supported_mcs_set,
+	          hapd->iface->current_mode->vht_mcs_set, 8);
+
+	pos += sizeof(*cap);
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_vht_operation *oper;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
+		return eid;
+
+	*pos++ = WLAN_EID_VHT_OPERATION;
+	*pos++ = sizeof(*oper);
+
+	oper = (struct ieee80211_vht_operation *) pos;
+	os_memset(oper, 0, sizeof(*oper));
+
+	/*
+	 * center freq = 5 GHz + (5 * index)
+	 * So index 42 gives center freq 5.210 GHz
+	 * which is channel 42 in 5G band
+	 */
+	oper->vht_op_info_chan_center_freq_seg0_idx =
+		hapd->iconf->vht_oper_centr_freq_seg0_idx;
+	oper->vht_op_info_chan_center_freq_seg1_idx =
+		hapd->iconf->vht_oper_centr_freq_seg1_idx;
+
+	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+
+	/* VHT Basic MCS set comes from hw */
+	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
+	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
+	pos += sizeof(*oper);
+
+	return pos;
+}
+
+
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *vht_capab, size_t vht_capab_len)
+{
+	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
+	if (!vht_capab ||
+	    vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+	    hapd->conf->disable_11ac) {
+		sta->flags &= ~WLAN_STA_VHT;
+		os_free(sta->vht_capabilities);
+		sta->vht_capabilities = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (sta->vht_capabilities == NULL) {
+		sta->vht_capabilities =
+			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+		if (sta->vht_capabilities == NULL)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_VHT;
+	os_memcpy(sta->vht_capabilities, vht_capab,
+		  sizeof(struct ieee80211_vht_capabilities));
+
+	return WLAN_STATUS_SUCCESS;
+}

Deleted: vendor/wpa/2.0/src/ap/ieee802_1x.c
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_1x.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_1x.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2025 +0,0 @@
-/*
- * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "crypto/md5.h"
-#include "crypto/crypto.h"
-#include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "eap_server/eap.h"
-#include "eap_common/eap_wsc_common.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "hostapd.h"
-#include "accounting.h"
-#include "sta_info.h"
-#include "wpa_auth.h"
-#include "preauth_auth.h"
-#include "pmksa_cache_auth.h"
-#include "ap_config.h"
-#include "ieee802_1x.h"
-
-
-static void ieee802_1x_finished(struct hostapd_data *hapd,
-				struct sta_info *sta, int success);
-
-
-static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
-			    u8 type, const u8 *data, size_t datalen)
-{
-	u8 *buf;
-	struct ieee802_1x_hdr *xhdr;
-	size_t len;
-	int encrypt = 0;
-
-	len = sizeof(*xhdr) + datalen;
-	buf = os_zalloc(len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "malloc() failed for "
-			   "ieee802_1x_send(len=%lu)",
-			   (unsigned long) len);
-		return;
-	}
-
-	xhdr = (struct ieee802_1x_hdr *) buf;
-	xhdr->version = hapd->conf->eapol_version;
-	xhdr->type = type;
-	xhdr->length = host_to_be16(datalen);
-
-	if (datalen > 0 && data != NULL)
-		os_memcpy(xhdr + 1, data, datalen);
-
-	if (wpa_auth_pairwise_set(sta->wpa_sm))
-		encrypt = 1;
-	if (sta->flags & WLAN_STA_PREAUTH) {
-		rsn_preauth_send(hapd, sta, buf, len);
-	} else {
-		hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt);
-	}
-
-	os_free(buf);
-}
-
-
-void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
-				   struct sta_info *sta, int authorized)
-{
-	int res;
-
-	if (sta->flags & WLAN_STA_PREAUTH)
-		return;
-
-	if (authorized) {
-		if (!(sta->flags & WLAN_STA_AUTHORIZED))
-			wpa_msg(hapd->msg_ctx, MSG_INFO,
-				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-		sta->flags |= WLAN_STA_AUTHORIZED;
-		res = hapd->drv.set_authorized(hapd, sta, 1);
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
-	} else {
-		if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) ==
-		    (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC))
-			wpa_msg(hapd->msg_ctx, MSG_INFO,
-				AP_STA_DISCONNECTED MACSTR,
-				MAC2STR(sta->addr));
-		sta->flags &= ~WLAN_STA_AUTHORIZED;
-		res = hapd->drv.set_authorized(hapd, sta, 0);
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
-	}
-
-	if (res && errno != ENOENT) {
-		printf("Could not set station " MACSTR " flags for kernel "
-		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
-	}
-
-	if (authorized)
-		accounting_sta_start(hapd, sta);
-}
-
-
-static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
-				  struct sta_info *sta,
-				  int idx, int broadcast,
-				  u8 *key_data, size_t key_len)
-{
-	u8 *buf, *ekey;
-	struct ieee802_1x_hdr *hdr;
-	struct ieee802_1x_eapol_key *key;
-	size_t len, ekey_len;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL)
-		return;
-
-	len = sizeof(*key) + key_len;
-	buf = os_zalloc(sizeof(*hdr) + len);
-	if (buf == NULL)
-		return;
-
-	hdr = (struct ieee802_1x_hdr *) buf;
-	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
-	key->type = EAPOL_KEY_TYPE_RC4;
-	key->key_length = htons(key_len);
-	wpa_get_ntp_timestamp(key->replay_counter);
-
-	if (os_get_random(key->key_iv, sizeof(key->key_iv))) {
-		wpa_printf(MSG_ERROR, "Could not get random numbers");
-		os_free(buf);
-		return;
-	}
-
-	key->key_index = idx | (broadcast ? 0 : BIT(7));
-	if (hapd->conf->eapol_key_index_workaround) {
-		/* According to some information, WinXP Supplicant seems to
-		 * interpret bit7 as an indication whether the key is to be
-		 * activated, so make it possible to enable workaround that
-		 * sets this bit for all keys. */
-		key->key_index |= BIT(7);
-	}
-
-	/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
-	 * MSK[32..63] is used to sign the message. */
-	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
-		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
-			   "and signing EAPOL-Key");
-		os_free(buf);
-		return;
-	}
-	os_memcpy((u8 *) (key + 1), key_data, key_len);
-	ekey_len = sizeof(key->key_iv) + 32;
-	ekey = os_malloc(ekey_len);
-	if (ekey == NULL) {
-		wpa_printf(MSG_ERROR, "Could not encrypt key");
-		os_free(buf);
-		return;
-	}
-	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
-	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
-	rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
-	os_free(ekey);
-
-	/* This header is needed here for HMAC-MD5, but it will be regenerated
-	 * in ieee802_1x_send() */
-	hdr->version = hapd->conf->eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = host_to_be16(len);
-	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
-		 key->key_signature);
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
-		   " (%s index=%d)", MAC2STR(sm->addr),
-		   broadcast ? "broadcast" : "unicast", idx);
-	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
-	if (sta->eapol_sm)
-		sta->eapol_sm->dot1xAuthEapolFramesTx++;
-	os_free(buf);
-}
-
-
-#ifndef CONFIG_NO_VLAN
-static struct hostapd_wep_keys *
-ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
-{
-	struct hostapd_wep_keys *key;
-
-	key = os_zalloc(sizeof(*key));
-	if (key == NULL)
-		return NULL;
-
-	key->default_len = hapd->conf->default_wep_key_len;
-
-	if (key->idx >= hapd->conf->broadcast_key_idx_max ||
-	    key->idx < hapd->conf->broadcast_key_idx_min)
-		key->idx = hapd->conf->broadcast_key_idx_min;
-	else
-		key->idx++;
-
-	if (!key->key[key->idx])
-		key->key[key->idx] = os_malloc(key->default_len);
-	if (key->key[key->idx] == NULL ||
-	    os_get_random(key->key[key->idx], key->default_len)) {
-		printf("Could not generate random WEP key (dynamic VLAN).\n");
-		os_free(key->key[key->idx]);
-		key->key[key->idx] = NULL;
-		os_free(key);
-		return NULL;
-	}
-	key->len[key->idx] = key->default_len;
-
-	wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
-		   ifname, key->idx);
-	wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
-			key->key[key->idx], key->len[key->idx]);
-
-	if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1,
-			      NULL, 0, key->key[key->idx], key->len[key->idx]))
-		printf("Could not set dynamic VLAN WEP encryption key.\n");
-
-	hapd->drv.set_drv_ieee8021x(hapd, ifname, 1);
-
-	return key;
-}
-
-
-static struct hostapd_wep_keys *
-ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
-		     size_t vlan_id)
-{
-	const char *ifname;
-
-	if (vlan_id == 0)
-		return &ssid->wep;
-
-	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
-	    ssid->dyn_vlan_keys[vlan_id])
-		return ssid->dyn_vlan_keys[vlan_id];
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
-		   "state machine for VLAN ID %lu",
-		   (unsigned long) vlan_id);
-
-	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
-	if (ifname == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
-			   "cannot create group key state machine",
-			   (unsigned long) vlan_id);
-		return NULL;
-	}
-
-	if (ssid->dyn_vlan_keys == NULL) {
-		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
-		ssid->dyn_vlan_keys = os_zalloc(size);
-		if (ssid->dyn_vlan_keys == NULL)
-			return NULL;
-		ssid->max_dyn_vlan_keys = vlan_id;
-	}
-
-	if (ssid->max_dyn_vlan_keys < vlan_id) {
-		struct hostapd_wep_keys **na;
-		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
-		na = os_realloc(ssid->dyn_vlan_keys, size);
-		if (na == NULL)
-			return NULL;
-		ssid->dyn_vlan_keys = na;
-		os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
-			  (vlan_id - ssid->max_dyn_vlan_keys) *
-			  sizeof(ssid->dyn_vlan_keys[0]));
-		ssid->max_dyn_vlan_keys = vlan_id;
-	}
-
-	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
-
-	return ssid->dyn_vlan_keys[vlan_id];
-}
-#endif /* CONFIG_NO_VLAN */
-
-
-void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct eapol_authenticator *eapol = hapd->eapol_auth;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-#ifndef CONFIG_NO_VLAN
-	struct hostapd_wep_keys *key = NULL;
-	int vlan_id;
-#endif /* CONFIG_NO_VLAN */
-
-	if (sm == NULL || !sm->eap_if->eapKeyData)
-		return;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
-		   MAC2STR(sta->addr));
-
-#ifndef CONFIG_NO_VLAN
-	vlan_id = sta->vlan_id;
-	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
-		vlan_id = 0;
-
-	if (vlan_id) {
-		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
-		if (key && key->key[key->idx])
-			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
-					      key->key[key->idx],
-					      key->len[key->idx]);
-	} else
-#endif /* CONFIG_NO_VLAN */
-	if (eapol->default_wep_key) {
-		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
-				      eapol->default_wep_key,
-				      hapd->conf->default_wep_key_len);
-	}
-
-	if (hapd->conf->individual_wep_key_len > 0) {
-		u8 *ikey;
-		ikey = os_malloc(hapd->conf->individual_wep_key_len);
-		if (ikey == NULL ||
-		    os_get_random(ikey, hapd->conf->individual_wep_key_len)) {
-			wpa_printf(MSG_ERROR, "Could not generate random "
-				   "individual WEP key.");
-			os_free(ikey);
-			return;
-		}
-
-		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
-				ikey, hapd->conf->individual_wep_key_len);
-
-		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
-				      hapd->conf->individual_wep_key_len);
-
-		/* TODO: set encryption in TX callback, i.e., only after STA
-		 * has ACKed EAPOL-Key frame */
-		if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
-				      sta->addr, 0, 1, NULL, 0, ikey,
-				      hapd->conf->individual_wep_key_len)) {
-			wpa_printf(MSG_ERROR, "Could not set individual WEP "
-				   "encryption.");
-		}
-
-		os_free(ikey);
-	}
-}
-
-
-const char *radius_mode_txt(struct hostapd_data *hapd)
-{
-	switch (hapd->iface->conf->hw_mode) {
-	case HOSTAPD_MODE_IEEE80211A:
-		return "802.11a";
-	case HOSTAPD_MODE_IEEE80211G:
-		return "802.11g";
-	case HOSTAPD_MODE_IEEE80211B:
-	default:
-		return "802.11b";
-	}
-}
-
-
-int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	int i;
-	u8 rate = 0;
-
-	for (i = 0; i < sta->supported_rates_len; i++)
-		if ((sta->supported_rates[i] & 0x7f) > rate)
-			rate = sta->supported_rates[i] & 0x7f;
-
-	return rate;
-}
-
-
-#ifndef CONFIG_NO_RADIUS
-static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
-				      struct eapol_state_machine *sm,
-				      const u8 *eap, size_t len)
-{
-	const u8 *identity;
-	size_t identity_len;
-
-	if (len <= sizeof(struct eap_hdr) ||
-	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
-		return;
-
-	identity = eap_get_identity(sm->eap, &identity_len);
-	if (identity == NULL)
-		return;
-
-	/* Save station identity for future RADIUS packets */
-	os_free(sm->identity);
-	sm->identity = os_malloc(identity_len + 1);
-	if (sm->identity == NULL) {
-		sm->identity_len = 0;
-		return;
-	}
-
-	os_memcpy(sm->identity, identity, identity_len);
-	sm->identity_len = identity_len;
-	sm->identity[identity_len] = '\0';
-	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
-	sm->dot1xAuthEapolRespIdFramesRx++;
-}
-
-
-static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
-					  struct sta_info *sta,
-					  const u8 *eap, size_t len)
-{
-	struct radius_msg *msg;
-	char buf[128];
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL)
-		return;
-
-	ieee802_1x_learn_identity(hapd, sm, eap, len);
-
-	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
-		   "packet");
-
-	sm->radius_identifier = radius_client_get_id(hapd->radius);
-	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
-			     sm->radius_identifier);
-	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
-		return;
-	}
-
-	radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
-
-	if (sm->identity &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
-				 sm->identity, sm->identity_len)) {
-		printf("Could not add User-Name\n");
-		goto fail;
-	}
-
-	if (hapd->conf->own_ip_addr.af == AF_INET &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
-		printf("Could not add NAS-IP-Address\n");
-		goto fail;
-	}
-
-#ifdef CONFIG_IPV6
-	if (hapd->conf->own_ip_addr.af == AF_INET6 &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
-				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
-		printf("Could not add NAS-IPv6-Address\n");
-		goto fail;
-	}
-#endif /* CONFIG_IPV6 */
-
-	if (hapd->conf->nas_identifier &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
-				 (u8 *) hapd->conf->nas_identifier,
-				 os_strlen(hapd->conf->nas_identifier))) {
-		printf("Could not add NAS-Identifier\n");
-		goto fail;
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
-		printf("Could not add NAS-Port\n");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
-	buf[sizeof(buf) - 1] = '\0';
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Called-Station-Id\n");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
-		    MAC2STR(sta->addr));
-	buf[sizeof(buf) - 1] = '\0';
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Calling-Station-Id\n");
-		goto fail;
-	}
-
-	/* TODO: should probably check MTU from driver config; 2304 is max for
-	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
-	 */
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
-		printf("Could not add Framed-MTU\n");
-		goto fail;
-	}
-
-	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
-				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
-		printf("Could not add NAS-Port-Type\n");
-		goto fail;
-	}
-
-	if (sta->flags & WLAN_STA_PREAUTH) {
-		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
-			   sizeof(buf));
-	} else {
-		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
-			    radius_sta_rate(hapd, sta) / 2,
-			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
-			    radius_mode_txt(hapd));
-		buf[sizeof(buf) - 1] = '\0';
-	}
-	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Connect-Info\n");
-		goto fail;
-	}
-
-	if (eap && !radius_msg_add_eap(msg, eap, len)) {
-		printf("Could not add EAP-Message\n");
-		goto fail;
-	}
-
-	/* State attribute must be copied if and only if this packet is
-	 * Access-Request reply to the previous Access-Challenge */
-	if (sm->last_recv_radius &&
-	    radius_msg_get_hdr(sm->last_recv_radius)->code ==
-	    RADIUS_CODE_ACCESS_CHALLENGE) {
-		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
-					       RADIUS_ATTR_STATE);
-		if (res < 0) {
-			printf("Could not copy State attribute from previous "
-			       "Access-Challenge\n");
-			goto fail;
-		}
-		if (res > 0) {
-			wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
-		}
-	}
-
-	radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr);
-	return;
-
- fail:
-	radius_msg_free(msg);
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-static void handle_eap_response(struct hostapd_data *hapd,
-				struct sta_info *sta, struct eap_hdr *eap,
-				size_t len)
-{
-	u8 type, *data;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	if (sm == NULL)
-		return;
-
-	data = (u8 *) (eap + 1);
-
-	if (len < sizeof(*eap) + 1) {
-		printf("handle_eap_response: too short response data\n");
-		return;
-	}
-
-	sm->eap_type_supp = type = data[0];
-
-	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
-		       "id=%d len=%d) from STA: EAP Response-%s (%d)",
-		       eap->code, eap->identifier, be_to_host16(eap->length),
-		       eap_server_get_name(0, type), type);
-
-	sm->dot1xAuthEapolRespFramesRx++;
-
-	wpabuf_free(sm->eap_if->eapRespData);
-	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
-	sm->eapolEap = TRUE;
-}
-
-
-/* Process incoming EAP packet from Supplicant */
-static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
-		       u8 *buf, size_t len)
-{
-	struct eap_hdr *eap;
-	u16 eap_len;
-
-	if (len < sizeof(*eap)) {
-		printf("   too short EAP packet\n");
-		return;
-	}
-
-	eap = (struct eap_hdr *) buf;
-
-	eap_len = be_to_host16(eap->length);
-	wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
-		   eap->code, eap->identifier, eap_len);
-	if (eap_len < sizeof(*eap)) {
-		wpa_printf(MSG_DEBUG, "   Invalid EAP length");
-		return;
-	} else if (eap_len > len) {
-		wpa_printf(MSG_DEBUG, "   Too short frame to contain this EAP "
-			   "packet");
-		return;
-	} else if (eap_len < len) {
-		wpa_printf(MSG_DEBUG, "   Ignoring %lu extra bytes after EAP "
-			   "packet", (unsigned long) len - eap_len);
-	}
-
-	switch (eap->code) {
-	case EAP_CODE_REQUEST:
-		wpa_printf(MSG_DEBUG, " (request)");
-		return;
-	case EAP_CODE_RESPONSE:
-		wpa_printf(MSG_DEBUG, " (response)");
-		handle_eap_response(hapd, sta, eap, eap_len);
-		break;
-	case EAP_CODE_SUCCESS:
-		wpa_printf(MSG_DEBUG, " (success)");
-		return;
-	case EAP_CODE_FAILURE:
-		wpa_printf(MSG_DEBUG, " (failure)");
-		return;
-	default:
-		wpa_printf(MSG_DEBUG, " (unknown code)");
-		return;
-	}
-}
-
-
-static struct eapol_state_machine *
-ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	int flags = 0;
-	if (sta->flags & WLAN_STA_PREAUTH)
-		flags |= EAPOL_SM_PREAUTH;
-	if (sta->wpa_sm) {
-		flags |= EAPOL_SM_USES_WPA;
-		if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
-			flags |= EAPOL_SM_FROM_PMKSA_CACHE;
-	}
-	return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
-				sta->wps_ie, sta);
-}
-
-
-/**
- * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
- * @hapd: hostapd BSS data
- * @sa: Source address (sender of the EAPOL frame)
- * @buf: EAPOL frame
- * @len: Length of buf in octets
- *
- * This function is called for each incoming EAPOL frame from the interface
- */
-void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
-			size_t len)
-{
-	struct sta_info *sta;
-	struct ieee802_1x_hdr *hdr;
-	struct ieee802_1x_eapol_key *key;
-	u16 datalen;
-	struct rsn_pmksa_cache_entry *pmksa;
-
-	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
-	    !hapd->conf->wps_state)
-		return;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
-		   (unsigned long) len, MAC2STR(sa));
-	sta = ap_get_sta(hapd, sa);
-	if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
-			   "associated STA");
-		return;
-	}
-
-	if (len < sizeof(*hdr)) {
-		printf("   too short IEEE 802.1X packet\n");
-		return;
-	}
-
-	hdr = (struct ieee802_1x_hdr *) buf;
-	datalen = be_to_host16(hdr->length);
-	wpa_printf(MSG_DEBUG, "   IEEE 802.1X: version=%d type=%d length=%d",
-		   hdr->version, hdr->type, datalen);
-
-	if (len - sizeof(*hdr) < datalen) {
-		printf("   frame too short for this IEEE 802.1X packet\n");
-		if (sta->eapol_sm)
-			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
-		return;
-	}
-	if (len - sizeof(*hdr) > datalen) {
-		wpa_printf(MSG_DEBUG, "   ignoring %lu extra octets after "
-			   "IEEE 802.1X packet",
-			   (unsigned long) len - sizeof(*hdr) - datalen);
-	}
-
-	if (sta->eapol_sm) {
-		sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
-		sta->eapol_sm->dot1xAuthEapolFramesRx++;
-	}
-
-	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
-	if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
-	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
-	    (key->type == EAPOL_KEY_TYPE_WPA ||
-	     key->type == EAPOL_KEY_TYPE_RSN)) {
-		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
-			    sizeof(*hdr) + datalen);
-		return;
-	}
-
-	if ((!hapd->conf->ieee802_1x &&
-	     !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) ||
-	    wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
-		return;
-
-	if (!sta->eapol_sm) {
-		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
-		if (!sta->eapol_sm)
-			return;
-
-#ifdef CONFIG_WPS
-		if (!hapd->conf->ieee802_1x &&
-		    ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
-		     WLAN_STA_MAYBE_WPS)) {
-			/*
-			 * Delay EAPOL frame transmission until a possible WPS
-			 * STA initiates the handshake with EAPOL-Start.
-			 */
-			sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
-		}
-#endif /* CONFIG_WPS */
-
-		sta->eapol_sm->eap_if->portEnabled = TRUE;
-	}
-
-	/* since we support version 1, we can ignore version field and proceed
-	 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
-	/* TODO: actually, we are not version 1 anymore.. However, Version 2
-	 * does not change frame contents, so should be ok to process frames
-	 * more or less identically. Some changes might be needed for
-	 * verification of fields. */
-
-	switch (hdr->type) {
-	case IEEE802_1X_TYPE_EAP_PACKET:
-		handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
-		break;
-
-	case IEEE802_1X_TYPE_EAPOL_START:
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
-			       "from STA");
-		sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
-		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
-		if (pmksa) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
-				       "available - ignore it since "
-				       "STA sent EAPOL-Start");
-			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
-		}
-		sta->eapol_sm->eapolStart = TRUE;
-		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
-		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
-		break;
-
-	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
-			       "from STA");
-		sta->acct_terminate_cause =
-			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-		accounting_sta_stop(hapd, sta);
-		sta->eapol_sm->eapolLogoff = TRUE;
-		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
-		break;
-
-	case IEEE802_1X_TYPE_EAPOL_KEY:
-		wpa_printf(MSG_DEBUG, "   EAPOL-Key");
-		if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
-			wpa_printf(MSG_DEBUG, "   Dropped key data from "
-				   "unauthorized Supplicant");
-			break;
-		}
-		break;
-
-	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
-		wpa_printf(MSG_DEBUG, "   EAPOL-Encapsulated-ASF-Alert");
-		/* TODO: implement support for this; show data */
-		break;
-
-	default:
-		wpa_printf(MSG_DEBUG, "   unknown IEEE 802.1X packet type");
-		sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
-		break;
-	}
-
-	eapol_auth_step(sta->eapol_sm);
-}
-
-
-/**
- * ieee802_1x_new_station - Start IEEE 802.1X authentication
- * @hapd: hostapd BSS data
- * @sta: The station
- *
- * This function is called to start IEEE 802.1X authentication when a new
- * station completes IEEE 802.11 association.
- */
-void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct rsn_pmksa_cache_entry *pmksa;
-	int reassoc = 1;
-	int force_1x = 0;
-
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->conf->wpa &&
-	    (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
-		/*
-		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
-		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
-		 * authentication in this BSS.
-		 */
-		force_1x = 1;
-	}
-#endif /* CONFIG_WPS */
-
-	if ((!force_1x && !hapd->conf->ieee802_1x) ||
-	    wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
-		return;
-
-	if (sta->eapol_sm == NULL) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "start authentication");
-		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
-		if (sta->eapol_sm == NULL) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE8021X,
-				       HOSTAPD_LEVEL_INFO,
-				       "failed to allocate state machine");
-			return;
-		}
-		reassoc = 0;
-	}
-
-#ifdef CONFIG_WPS
-	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
-	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
-		/*
-		 * Delay EAPOL frame transmission until a possible WPS
-		 * initiates the handshake with EAPOL-Start.
-		 */
-		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
-	}
-#endif /* CONFIG_WPS */
-
-	sta->eapol_sm->eap_if->portEnabled = TRUE;
-
-	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
-	if (pmksa) {
-		int old_vlanid;
-
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
-		/* Setup EAPOL state machines to already authenticated state
-		 * because of existing PMKSA information in the cache. */
-		sta->eapol_sm->keyRun = TRUE;
-		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
-		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
-		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
-		sta->eapol_sm->authSuccess = TRUE;
-		if (sta->eapol_sm->eap)
-			eap_sm_notify_cached(sta->eapol_sm->eap);
-		old_vlanid = sta->vlan_id;
-		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
-		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			sta->vlan_id = 0;
-		ap_sta_bind_vlan(hapd, sta, old_vlanid);
-	} else {
-		if (reassoc) {
-			/*
-			 * Force EAPOL state machines to start
-			 * re-authentication without having to wait for the
-			 * Supplicant to send EAPOL-Start.
-			 */
-			sta->eapol_sm->reAuthenticate = TRUE;
-		}
-		eapol_auth_step(sta->eapol_sm);
-	}
-}
-
-
-void ieee802_1x_free_station(struct sta_info *sta)
-{
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL)
-		return;
-
-	sta->eapol_sm = NULL;
-
-#ifndef CONFIG_NO_RADIUS
-	radius_msg_free(sm->last_recv_radius);
-	radius_free_class(&sm->radius_class);
-#endif /* CONFIG_NO_RADIUS */
-
-	os_free(sm->identity);
-	eapol_auth_free(sm);
-}
-
-
-#ifndef CONFIG_NO_RADIUS
-static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
-					  struct sta_info *sta)
-{
-	u8 *eap;
-	size_t len;
-	struct eap_hdr *hdr;
-	int eap_type = -1;
-	char buf[64];
-	struct radius_msg *msg;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL || sm->last_recv_radius == NULL) {
-		if (sm)
-			sm->eap_if->aaaEapNoReq = TRUE;
-		return;
-	}
-
-	msg = sm->last_recv_radius;
-
-	eap = radius_msg_get_eap(msg, &len);
-	if (eap == NULL) {
-		/* RFC 3579, Chap. 2.6.3:
-		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
-		 * attribute */
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_WARNING, "could not extract "
-			       "EAP-Message from RADIUS message");
-		sm->eap_if->aaaEapNoReq = TRUE;
-		return;
-	}
-
-	if (len < sizeof(*hdr)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
-			       "received from authentication server");
-		os_free(eap);
-		sm->eap_if->aaaEapNoReq = TRUE;
-		return;
-	}
-
-	if (len > sizeof(*hdr))
-		eap_type = eap[sizeof(*hdr)];
-
-	hdr = (struct eap_hdr *) eap;
-	switch (hdr->code) {
-	case EAP_CODE_REQUEST:
-		if (eap_type >= 0)
-			sm->eap_type_authsrv = eap_type;
-		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
-			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
-			    "??",
-			    eap_type);
-		break;
-	case EAP_CODE_RESPONSE:
-		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
-			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
-			    "??",
-			    eap_type);
-		break;
-	case EAP_CODE_SUCCESS:
-		os_strlcpy(buf, "EAP Success", sizeof(buf));
-		break;
-	case EAP_CODE_FAILURE:
-		os_strlcpy(buf, "EAP Failure", sizeof(buf));
-		break;
-	default:
-		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
-		break;
-	}
-	buf[sizeof(buf) - 1] = '\0';
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
-		       "id=%d len=%d) from RADIUS server: %s",
-		       hdr->code, hdr->identifier, be_to_host16(hdr->length),
-		       buf);
-	sm->eap_if->aaaEapReq = TRUE;
-
-	wpabuf_free(sm->eap_if->aaaEapReqData);
-	sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
-}
-
-
-static void ieee802_1x_get_keys(struct hostapd_data *hapd,
-				struct sta_info *sta, struct radius_msg *msg,
-				struct radius_msg *req,
-				const u8 *shared_secret,
-				size_t shared_secret_len)
-{
-	struct radius_ms_mppe_keys *keys;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	if (sm == NULL)
-		return;
-
-	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
-				      shared_secret_len);
-
-	if (keys && keys->send && keys->recv) {
-		size_t len = keys->send_len + keys->recv_len;
-		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
-				keys->send, keys->send_len);
-		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
-				keys->recv, keys->recv_len);
-
-		os_free(sm->eap_if->aaaEapKeyData);
-		sm->eap_if->aaaEapKeyData = os_malloc(len);
-		if (sm->eap_if->aaaEapKeyData) {
-			os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
-				  keys->recv_len);
-			os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
-				  keys->send, keys->send_len);
-			sm->eap_if->aaaEapKeyDataLen = len;
-			sm->eap_if->aaaEapKeyAvailable = TRUE;
-		}
-	}
-
-	if (keys) {
-		os_free(keys->send);
-		os_free(keys->recv);
-		os_free(keys);
-	}
-}
-
-
-static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
-					  struct sta_info *sta,
-					  struct radius_msg *msg)
-{
-	u8 *class;
-	size_t class_len;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	int count, i;
-	struct radius_attr_data *nclass;
-	size_t nclass_count;
-
-	if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
-	    sm == NULL)
-		return;
-
-	radius_free_class(&sm->radius_class);
-	count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
-	if (count <= 0)
-		return;
-
-	nclass = os_zalloc(count * sizeof(struct radius_attr_data));
-	if (nclass == NULL)
-		return;
-
-	nclass_count = 0;
-
-	class = NULL;
-	for (i = 0; i < count; i++) {
-		do {
-			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
-						    &class, &class_len,
-						    class) < 0) {
-				i = count;
-				break;
-			}
-		} while (class_len < 1);
-
-		nclass[nclass_count].data = os_malloc(class_len);
-		if (nclass[nclass_count].data == NULL)
-			break;
-
-		os_memcpy(nclass[nclass_count].data, class, class_len);
-		nclass[nclass_count].len = class_len;
-		nclass_count++;
-	}
-
-	sm->radius_class.attr = nclass;
-	sm->radius_class.count = nclass_count;
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
-		   "attributes for " MACSTR,
-		   (unsigned long) sm->radius_class.count,
-		   MAC2STR(sta->addr));
-}
-
-
-/* Update sta->identity based on User-Name attribute in Access-Accept */
-static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
-					   struct sta_info *sta,
-					   struct radius_msg *msg)
-{
-	u8 *buf, *identity;
-	size_t len;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL)
-		return;
-
-	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
-				    NULL) < 0)
-		return;
-
-	identity = os_malloc(len + 1);
-	if (identity == NULL)
-		return;
-
-	os_memcpy(identity, buf, len);
-	identity[len] = '\0';
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
-		       "User-Name from Access-Accept '%s'",
-		       sm->identity ? (char *) sm->identity : "N/A",
-		       (char *) identity);
-
-	os_free(sm->identity);
-	sm->identity = identity;
-	sm->identity_len = len;
-}
-
-
-struct sta_id_search {
-	u8 identifier;
-	struct eapol_state_machine *sm;
-};
-
-
-static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
-					       struct sta_info *sta,
-					       void *ctx)
-{
-	struct sta_id_search *id_search = ctx;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm && sm->radius_identifier >= 0 &&
-	    sm->radius_identifier == id_search->identifier) {
-		id_search->sm = sm;
-		return 1;
-	}
-	return 0;
-}
-
-
-static struct eapol_state_machine *
-ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
-{
-	struct sta_id_search id_search;
-	id_search.identifier = identifier;
-	id_search.sm = NULL;
-	ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
-	return id_search.sm;
-}
-
-
-/**
- * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
- * @msg: RADIUS response message
- * @req: RADIUS request message
- * @shared_secret: RADIUS shared secret
- * @shared_secret_len: Length of shared_secret in octets
- * @data: Context data (struct hostapd_data *)
- * Returns: Processing status
- */
-static RadiusRxResult
-ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
-			const u8 *shared_secret, size_t shared_secret_len,
-			void *data)
-{
-	struct hostapd_data *hapd = data;
-	struct sta_info *sta;
-	u32 session_timeout = 0, termination_action, acct_interim_interval;
-	int session_timeout_set, old_vlanid = 0;
-	struct eapol_state_machine *sm;
-	int override_eapReq = 0;
-	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-
-	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
-	if (sm == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
-			   "station for this RADIUS message");
-		return RADIUS_RX_UNKNOWN;
-	}
-	sta = sm->sta;
-
-	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
-	 * present when packet contains an EAP-Message attribute */
-	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
-	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
-				0) < 0 &&
-	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
-			   "Message-Authenticator since it does not include "
-			   "EAP-Message");
-	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
-				     req, 1)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Message-Authenticator - dropped\n");
-		return RADIUS_RX_INVALID_AUTHENTICATOR;
-	}
-
-	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
-	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
-	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
-		printf("Unknown RADIUS message code\n");
-		return RADIUS_RX_UNKNOWN;
-	}
-
-	sm->radius_identifier = -1;
-	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
-		   MAC2STR(sta->addr));
-
-	radius_msg_free(sm->last_recv_radius);
-	sm->last_recv_radius = msg;
-
-	session_timeout_set =
-		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
-					   &session_timeout);
-	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
-				      &termination_action))
-		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
-
-	if (hapd->conf->acct_interim_interval == 0 &&
-	    hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
-	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
-				      &acct_interim_interval) == 0) {
-		if (acct_interim_interval < 60) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE8021X,
-				       HOSTAPD_LEVEL_INFO,
-				       "ignored too small "
-				       "Acct-Interim-Interval %d",
-				       acct_interim_interval);
-		} else
-			sta->acct_interim_interval = acct_interim_interval;
-	}
-
-
-	switch (hdr->code) {
-	case RADIUS_CODE_ACCESS_ACCEPT:
-		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-			sta->vlan_id = 0;
-#ifndef CONFIG_NO_VLAN
-		else {
-			old_vlanid = sta->vlan_id;
-			sta->vlan_id = radius_msg_get_vlanid(msg);
-		}
-		if (sta->vlan_id > 0 &&
-		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-					       sta->vlan_id)) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_INFO,
-				       "VLAN ID %d", sta->vlan_id);
-		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
-			sta->eapol_sm->authFail = TRUE;
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE8021X,
-				       HOSTAPD_LEVEL_INFO, "authentication "
-				       "server did not include required VLAN "
-				       "ID in Access-Accept");
-			break;
-		}
-#endif /* CONFIG_NO_VLAN */
-
-		if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
-			break;
-
-		/* RFC 3580, Ch. 3.17 */
-		if (session_timeout_set && termination_action ==
-		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
-			sm->reAuthPeriod = session_timeout;
-		} else if (session_timeout_set)
-			ap_sta_session_timeout(hapd, sta, session_timeout);
-
-		sm->eap_if->aaaSuccess = TRUE;
-		override_eapReq = 1;
-		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
-				    shared_secret_len);
-		ieee802_1x_store_radius_class(hapd, sta, msg);
-		ieee802_1x_update_sta_identity(hapd, sta, msg);
-		if (sm->eap_if->eapKeyAvailable &&
-		    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;
-		override_eapReq = 1;
-		break;
-	case RADIUS_CODE_ACCESS_CHALLENGE:
-		sm->eap_if->aaaEapReq = TRUE;
-		if (session_timeout_set) {
-			/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
-			sm->eap_if->aaaMethodTimeout = session_timeout;
-			hostapd_logger(hapd, sm->addr,
-				       HOSTAPD_MODULE_IEEE8021X,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "using EAP timeout of %d seconds (from "
-				       "RADIUS)",
-				       sm->eap_if->aaaMethodTimeout);
-		} else {
-			/*
-			 * Use dynamic retransmission behavior per EAP
-			 * specification.
-			 */
-			sm->eap_if->aaaMethodTimeout = 0;
-		}
-		break;
-	}
-
-	ieee802_1x_decapsulate_radius(hapd, sta);
-	if (override_eapReq)
-		sm->eap_if->aaaEapReq = FALSE;
-
-	eapol_auth_step(sm);
-
-	return RADIUS_RX_QUEUED;
-}
-#endif /* CONFIG_NO_RADIUS */
-
-
-void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct eapol_state_machine *sm = sta->eapol_sm;
-	if (sm == NULL)
-		return;
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
-
-#ifndef CONFIG_NO_RADIUS
-	radius_msg_free(sm->last_recv_radius);
-	sm->last_recv_radius = NULL;
-#endif /* CONFIG_NO_RADIUS */
-
-	if (sm->eap_if->eapTimeout) {
-		/*
-		 * Disconnect the STA since it did not reply to the last EAP
-		 * request and we cannot continue EAP processing (EAP-Failure
-		 * could only be sent if the EAP peer actually replied).
-		 */
-		sm->eap_if->portEnabled = FALSE;
-		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_PREV_AUTH_NOT_VALID);
-	}
-}
-
-
-static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
-{
-	struct eapol_authenticator *eapol = hapd->eapol_auth;
-
-	if (hapd->conf->default_wep_key_len < 1)
-		return 0;
-
-	os_free(eapol->default_wep_key);
-	eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
-	if (eapol->default_wep_key == NULL ||
-	    os_get_random(eapol->default_wep_key,
-			  hapd->conf->default_wep_key_len)) {
-		printf("Could not generate random WEP key.\n");
-		os_free(eapol->default_wep_key);
-		eapol->default_wep_key = NULL;
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
-			eapol->default_wep_key,
-			hapd->conf->default_wep_key_len);
-
-	return 0;
-}
-
-
-static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
-					struct sta_info *sta, void *ctx)
-{
-	if (sta->eapol_sm) {
-		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
-		eapol_auth_step(sta->eapol_sm);
-	}
-	return 0;
-}
-
-
-static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct eapol_authenticator *eapol = hapd->eapol_auth;
-
-	if (eapol->default_wep_key_idx >= 3)
-		eapol->default_wep_key_idx =
-			hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
-	else
-		eapol->default_wep_key_idx++;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
-		   eapol->default_wep_key_idx);
-		      
-	if (ieee802_1x_rekey_broadcast(hapd)) {
-		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
-			       "new broadcast key");
-		os_free(eapol->default_wep_key);
-		eapol->default_wep_key = NULL;
-		return;
-	}
-
-	/* TODO: Could setup key for RX here, but change default TX keyid only
-	 * after new broadcast key has been sent to all stations. */
-	if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL,
-			      eapol->default_wep_key_idx, 1, NULL, 0,
-			      eapol->default_wep_key,
-			      hapd->conf->default_wep_key_len)) {
-		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
-			       "new broadcast key");
-		os_free(eapol->default_wep_key);
-		eapol->default_wep_key = NULL;
-		return;
-	}
-
-	ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
-
-	if (hapd->conf->wep_rekeying_period > 0) {
-		eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
-				       ieee802_1x_rekey, hapd, NULL);
-	}
-}
-
-
-static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
-				  const u8 *data, size_t datalen)
-{
-#ifdef CONFIG_WPS
-	struct sta_info *sta = sta_ctx;
-
-	if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
-	    WLAN_STA_MAYBE_WPS) {
-		const u8 *identity;
-		size_t identity_len;
-		struct eapol_state_machine *sm = sta->eapol_sm;
-
-		identity = eap_get_identity(sm->eap, &identity_len);
-		if (identity &&
-		    ((identity_len == WSC_ID_ENROLLEE_LEN &&
-		      os_memcmp(identity, WSC_ID_ENROLLEE,
-				WSC_ID_ENROLLEE_LEN) == 0) ||
-		     (identity_len == WSC_ID_REGISTRAR_LEN &&
-		      os_memcmp(identity, WSC_ID_REGISTRAR,
-				WSC_ID_REGISTRAR_LEN) == 0))) {
-			wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
-				   "WLAN_STA_WPS");
-			sta->flags |= WLAN_STA_WPS;
-		}
-	}
-#endif /* CONFIG_WPS */
-
-	ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
-}
-
-
-static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
-				const u8 *data, size_t datalen)
-{
-#ifndef CONFIG_NO_RADIUS
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = sta_ctx;
-
-	ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
-#endif /* CONFIG_NO_RADIUS */
-}
-
-
-static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
-				 int preauth)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = sta_ctx;
-	if (preauth)
-		rsn_preauth_finished(hapd, sta, success);
-	else
-		ieee802_1x_finished(hapd, sta, success);
-}
-
-
-static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
-				   size_t identity_len, int phase2,
-				   struct eap_user *user)
-{
-	struct hostapd_data *hapd = ctx;
-	const struct hostapd_eap_user *eap_user;
-	int i, count;
-
-	eap_user = hostapd_get_eap_user(hapd->conf, identity,
-					identity_len, phase2);
-	if (eap_user == NULL)
-		return -1;
-
-	os_memset(user, 0, sizeof(*user));
-	user->phase2 = phase2;
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
-		user->methods[i].vendor = eap_user->methods[i].vendor;
-		user->methods[i].method = eap_user->methods[i].method;
-	}
-
-	if (eap_user->password) {
-		user->password = os_malloc(eap_user->password_len);
-		if (user->password == NULL)
-			return -1;
-		os_memcpy(user->password, eap_user->password,
-			  eap_user->password_len);
-		user->password_len = eap_user->password_len;
-	}
-	user->force_version = eap_user->force_version;
-	user->ttls_auth = eap_user->ttls_auth;
-
-	return 0;
-}
-
-
-static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta;
-	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL || sta->eapol_sm == NULL)
-		return 0;
-	return 1;
-}
-
-
-static void ieee802_1x_logger(void *ctx, const u8 *addr,
-			      eapol_logger_level level, const char *txt)
-{
-#ifndef CONFIG_NO_HOSTAPD_LOGGER
-	struct hostapd_data *hapd = ctx;
-	int hlevel;
-
-	switch (level) {
-	case EAPOL_LOGGER_WARNING:
-		hlevel = HOSTAPD_LEVEL_WARNING;
-		break;
-	case EAPOL_LOGGER_INFO:
-		hlevel = HOSTAPD_LEVEL_INFO;
-		break;
-	case EAPOL_LOGGER_DEBUG:
-	default:
-		hlevel = HOSTAPD_LEVEL_DEBUG;
-		break;
-	}
-
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
-		       txt);
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */
-}
-
-
-static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
-					   int authorized)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = sta_ctx;
-	ieee802_1x_set_sta_authorized(hapd, sta, authorized);
-}
-
-
-static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = sta_ctx;
-	ieee802_1x_abort_auth(hapd, sta);
-}
-
-
-static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = sta_ctx;
-	ieee802_1x_tx_key(hapd, sta);
-}
-
-
-static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
-				   enum eapol_event type)
-{
-	/* struct hostapd_data *hapd = ctx; */
-	struct sta_info *sta = sta_ctx;
-	switch (type) {
-	case EAPOL_AUTH_SM_CHANGE:
-		wpa_auth_sm_notify(sta->wpa_sm);
-		break;
-	case EAPOL_AUTH_REAUTHENTICATE:
-		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
-		break;
-	}
-}
-
-
-int ieee802_1x_init(struct hostapd_data *hapd)
-{
-	int i;
-	struct eapol_auth_config conf;
-	struct eapol_auth_cb cb;
-
-	os_memset(&conf, 0, sizeof(conf));
-	conf.ctx = hapd;
-	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
-	conf.wpa = hapd->conf->wpa;
-	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
-	conf.eap_server = hapd->conf->eap_server;
-	conf.ssl_ctx = hapd->ssl_ctx;
-	conf.msg_ctx = hapd->msg_ctx;
-	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
-	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
-	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
-	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
-	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
-	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
-	conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
-	conf.eap_fast_prov = hapd->conf->eap_fast_prov;
-	conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
-	conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
-	conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
-	conf.tnc = hapd->conf->tnc;
-	conf.wps = hapd->wps;
-
-	os_memset(&cb, 0, sizeof(cb));
-	cb.eapol_send = ieee802_1x_eapol_send;
-	cb.aaa_send = ieee802_1x_aaa_send;
-	cb.finished = _ieee802_1x_finished;
-	cb.get_eap_user = ieee802_1x_get_eap_user;
-	cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
-	cb.logger = ieee802_1x_logger;
-	cb.set_port_authorized = ieee802_1x_set_port_authorized;
-	cb.abort_auth = _ieee802_1x_abort_auth;
-	cb.tx_key = _ieee802_1x_tx_key;
-	cb.eapol_event = ieee802_1x_eapol_event;
-
-	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
-	if (hapd->eapol_auth == NULL)
-		return -1;
-
-	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
-	    hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
-		return -1;
-
-#ifndef CONFIG_NO_RADIUS
-	if (radius_client_register(hapd->radius, RADIUS_AUTH,
-				   ieee802_1x_receive_auth, hapd))
-		return -1;
-#endif /* CONFIG_NO_RADIUS */
-
-	if (hapd->conf->default_wep_key_len) {
-		for (i = 0; i < 4; i++)
-			hapd->drv.set_key(hapd->conf->iface, hapd,
-					  WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-					  NULL, 0);
-
-		ieee802_1x_rekey(hapd, NULL);
-
-		if (hapd->eapol_auth->default_wep_key == NULL)
-			return -1;
-	}
-
-	return 0;
-}
-
-
-void ieee802_1x_deinit(struct hostapd_data *hapd)
-{
-	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
-
-	if (hapd->driver != NULL &&
-	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
-		hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
-
-	eapol_auth_deinit(hapd->eapol_auth);
-	hapd->eapol_auth = NULL;
-}
-
-
-int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
-			 const u8 *buf, size_t len, int ack)
-{
-	struct ieee80211_hdr *hdr;
-	struct ieee802_1x_hdr *xhdr;
-	struct ieee802_1x_eapol_key *key;
-	u8 *pos;
-	const unsigned char rfc1042_hdr[ETH_ALEN] =
-		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-	if (sta == NULL)
-		return -1;
-	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
-		return 0;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	pos = (u8 *) (hdr + 1);
-	if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
-		return 0;
-	pos += sizeof(rfc1042_hdr);
-	if (WPA_GET_BE16(pos) != ETH_P_PAE)
-		return 0;
-	pos += 2;
-
-	xhdr = (struct ieee802_1x_hdr *) pos;
-	pos += sizeof(*xhdr);
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
-		   "type=%d length=%d - ack=%d",
-		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
-		   be_to_host16(xhdr->length), ack);
-
-	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
-	 * or Authenticator state machines, but EAPOL-Key packets are not
-	 * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
-	 * packets couple of times because otherwise STA keys become
-	 * unsynchronized with AP. */
-	if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
-	    pos + sizeof(*key) <= buf + len) {
-		key = (struct ieee802_1x_eapol_key *) pos;
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
-			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
-			       "frame (%scast index=%d)",
-			       key->key_index & BIT(7) ? "uni" : "broad",
-			       key->key_index & ~BIT(7));
-		/* TODO: re-send EAPOL-Key couple of times (with short delay
-		 * between them?). If all attempt fail, report error and
-		 * deauthenticate STA so that it will get new keys when
-		 * authenticating again (e.g., after returning in range).
-		 * Separate limit/transmit state needed both for unicast and
-		 * broadcast keys(?) */
-	}
-	/* TODO: could move unicast key configuration from ieee802_1x_tx_key()
-	 * to here and change the key only if the EAPOL-Key packet was Acked.
-	 */
-
-	return 1;
-}
-
-
-u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
-{
-	if (sm == NULL || sm->identity == NULL)
-		return NULL;
-
-	*len = sm->identity_len;
-	return sm->identity;
-}
-
-
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
-				 int idx)
-{
-	if (sm == NULL || sm->radius_class.attr == NULL ||
-	    idx >= (int) sm->radius_class.count)
-		return NULL;
-
-	*len = sm->radius_class.attr[idx].len;
-	return sm->radius_class.attr[idx].data;
-}
-
-
-const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
-{
-	if (sm == NULL)
-		return NULL;
-
-	*len = sm->eap_if->eapKeyDataLen;
-	return sm->eap_if->eapKeyData;
-}
-
-
-void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
-				    int enabled)
-{
-	if (sm == NULL)
-		return;
-	sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
-	eapol_auth_step(sm);
-}
-
-
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
-				  int valid)
-{
-	if (sm == NULL)
-		return;
-	sm->portValid = valid ? TRUE : FALSE;
-	eapol_auth_step(sm);
-}
-
-
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
-{
-	if (sm == NULL)
-		return;
-	if (pre_auth)
-		sm->flags |= EAPOL_SM_PREAUTH;
-	else
-		sm->flags &= ~EAPOL_SM_PREAUTH;
-}
-
-
-static const char * bool_txt(Boolean bool)
-{
-	return bool ? "TRUE" : "FALSE";
-}
-
-
-int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
-{
-	/* TODO */
-	return 0;
-}
-
-
-int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   char *buf, size_t buflen)
-{
-	int len = 0, ret;
-	struct eapol_state_machine *sm = sta->eapol_sm;
-
-	if (sm == NULL)
-		return 0;
-
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot1xPaePortNumber=%d\n"
-			  "dot1xPaePortProtocolVersion=%d\n"
-			  "dot1xPaePortCapabilities=1\n"
-			  "dot1xPaePortInitialize=%d\n"
-			  "dot1xPaePortReauthenticate=FALSE\n",
-			  sta->aid,
-			  EAPOL_VERSION,
-			  sm->initialize);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* dot1xAuthConfigTable */
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot1xAuthPaeState=%d\n"
-			  "dot1xAuthBackendAuthState=%d\n"
-			  "dot1xAuthAdminControlledDirections=%d\n"
-			  "dot1xAuthOperControlledDirections=%d\n"
-			  "dot1xAuthAuthControlledPortStatus=%d\n"
-			  "dot1xAuthAuthControlledPortControl=%d\n"
-			  "dot1xAuthQuietPeriod=%u\n"
-			  "dot1xAuthServerTimeout=%u\n"
-			  "dot1xAuthReAuthPeriod=%u\n"
-			  "dot1xAuthReAuthEnabled=%s\n"
-			  "dot1xAuthKeyTxEnabled=%s\n",
-			  sm->auth_pae_state + 1,
-			  sm->be_auth_state + 1,
-			  sm->adminControlledDirections,
-			  sm->operControlledDirections,
-			  sm->authPortStatus,
-			  sm->portControl,
-			  sm->quietPeriod,
-			  sm->serverTimeout,
-			  sm->reAuthPeriod,
-			  bool_txt(sm->reAuthEnabled),
-			  bool_txt(sm->keyTxEnabled));
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* dot1xAuthStatsTable */
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot1xAuthEapolFramesRx=%u\n"
-			  "dot1xAuthEapolFramesTx=%u\n"
-			  "dot1xAuthEapolStartFramesRx=%u\n"
-			  "dot1xAuthEapolLogoffFramesRx=%u\n"
-			  "dot1xAuthEapolRespIdFramesRx=%u\n"
-			  "dot1xAuthEapolRespFramesRx=%u\n"
-			  "dot1xAuthEapolReqIdFramesTx=%u\n"
-			  "dot1xAuthEapolReqFramesTx=%u\n"
-			  "dot1xAuthInvalidEapolFramesRx=%u\n"
-			  "dot1xAuthEapLengthErrorFramesRx=%u\n"
-			  "dot1xAuthLastEapolFrameVersion=%u\n"
-			  "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
-			  sm->dot1xAuthEapolFramesRx,
-			  sm->dot1xAuthEapolFramesTx,
-			  sm->dot1xAuthEapolStartFramesRx,
-			  sm->dot1xAuthEapolLogoffFramesRx,
-			  sm->dot1xAuthEapolRespIdFramesRx,
-			  sm->dot1xAuthEapolRespFramesRx,
-			  sm->dot1xAuthEapolReqIdFramesTx,
-			  sm->dot1xAuthEapolReqFramesTx,
-			  sm->dot1xAuthInvalidEapolFramesRx,
-			  sm->dot1xAuthEapLengthErrorFramesRx,
-			  sm->dot1xAuthLastEapolFrameVersion,
-			  MAC2STR(sm->addr));
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* dot1xAuthDiagTable */
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot1xAuthEntersConnecting=%u\n"
-			  "dot1xAuthEapLogoffsWhileConnecting=%u\n"
-			  "dot1xAuthEntersAuthenticating=%u\n"
-			  "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
-			  "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
-			  "dot1xAuthAuthFailWhileAuthenticating=%u\n"
-			  "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
-			  "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
-			  "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
-			  "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
-			  "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
-			  "dot1xAuthBackendResponses=%u\n"
-			  "dot1xAuthBackendAccessChallenges=%u\n"
-			  "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
-			  "dot1xAuthBackendAuthSuccesses=%u\n"
-			  "dot1xAuthBackendAuthFails=%u\n",
-			  sm->authEntersConnecting,
-			  sm->authEapLogoffsWhileConnecting,
-			  sm->authEntersAuthenticating,
-			  sm->authAuthSuccessesWhileAuthenticating,
-			  sm->authAuthTimeoutsWhileAuthenticating,
-			  sm->authAuthFailWhileAuthenticating,
-			  sm->authAuthEapStartsWhileAuthenticating,
-			  sm->authAuthEapLogoffWhileAuthenticating,
-			  sm->authAuthReauthsWhileAuthenticated,
-			  sm->authAuthEapStartsWhileAuthenticated,
-			  sm->authAuthEapLogoffWhileAuthenticated,
-			  sm->backendResponses,
-			  sm->backendAccessChallenges,
-			  sm->backendOtherRequestsToSupplicant,
-			  sm->backendAuthSuccesses,
-			  sm->backendAuthFails);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* dot1xAuthSessionStatsTable */
-	ret = os_snprintf(buf + len, buflen - len,
-			  /* TODO: dot1xAuthSessionOctetsRx */
-			  /* TODO: dot1xAuthSessionOctetsTx */
-			  /* TODO: dot1xAuthSessionFramesRx */
-			  /* TODO: dot1xAuthSessionFramesTx */
-			  "dot1xAuthSessionId=%08X-%08X\n"
-			  "dot1xAuthSessionAuthenticMethod=%d\n"
-			  "dot1xAuthSessionTime=%u\n"
-			  "dot1xAuthSessionTerminateCause=999\n"
-			  "dot1xAuthSessionUserName=%s\n",
-			  sta->acct_session_id_hi, sta->acct_session_id_lo,
-			  (wpa_key_mgmt_wpa_ieee8021x(
-				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
-			  1 : 2,
-			  (unsigned int) (time(NULL) -
-					  sta->acct_session_start),
-			  sm->identity);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	return len;
-}
-
-
-static void ieee802_1x_finished(struct hostapd_data *hapd,
-				struct sta_info *sta, int success)
-{
-	const u8 *key;
-	size_t len;
-	/* TODO: get PMKLifetime from WPA parameters */
-	static const int dot11RSNAConfigPMKLifetime = 43200;
-
-	key = ieee802_1x_get_key(sta->eapol_sm, &len);
-	if (success && key && len >= PMK_LEN &&
-	    wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
-			       sta->eapol_sm) == 0) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "Added PMKSA cache entry (IEEE 802.1X)");
-	}
-
-#ifdef CONFIG_WPS
-	if (!success && (sta->flags & WLAN_STA_WPS)) {
-		/*
-		 * Many devices require deauthentication after WPS provisioning
-		 * and some may not be be able to do that themselves, so
-		 * disconnect the client here.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
-			   "EAP-Failure");
-		/* Add a small sleep to increase likelihood of previously
-		 * requested EAP-Failure TX getting out before this should the
-		 * driver reorder operations.
-		 */
-		os_sleep(0, 10000);
-		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_PREV_AUTH_NOT_VALID);
-	}
-#endif /* CONFIG_WPS */
-}

Copied: vendor/wpa/2.0/src/ap/ieee802_1x.c (from rev 9639, vendor/wpa/dist/src/ap/ieee802_1x.c)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_1x.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_1x.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2242 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator
+ * Copyright (c) 2002-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "crypto/md5.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "eap_server/eap.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "accounting.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+#include "pmksa_cache_auth.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_1x.h"
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+				struct sta_info *sta, int success);
+
+
+static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
+			    u8 type, const u8 *data, size_t datalen)
+{
+	u8 *buf;
+	struct ieee802_1x_hdr *xhdr;
+	size_t len;
+	int encrypt = 0;
+
+	len = sizeof(*xhdr) + datalen;
+	buf = os_zalloc(len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "malloc() failed for "
+			   "ieee802_1x_send(len=%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	xhdr = (struct ieee802_1x_hdr *) buf;
+	xhdr->version = hapd->conf->eapol_version;
+	xhdr->type = type;
+	xhdr->length = host_to_be16(datalen);
+
+	if (datalen > 0 && data != NULL)
+		os_memcpy(xhdr + 1, data, datalen);
+
+	if (wpa_auth_pairwise_set(sta->wpa_sm))
+		encrypt = 1;
+	if (sta->flags & WLAN_STA_PREAUTH) {
+		rsn_preauth_send(hapd, sta, buf, len);
+	} else {
+		hostapd_drv_hapd_send_eapol(
+			hapd, sta->addr, buf, len,
+			encrypt, hostapd_sta_flags_to_drv(sta->flags));
+	}
+
+	os_free(buf);
+}
+
+
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized)
+{
+	int res;
+
+	if (sta->flags & WLAN_STA_PREAUTH)
+		return;
+
+	if (authorized) {
+		ap_sta_set_authorized(hapd, sta, 1);
+		res = hostapd_set_authorized(hapd, sta, 1);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
+	} else {
+		ap_sta_set_authorized(hapd, sta, 0);
+		res = hostapd_set_authorized(hapd, sta, 0);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
+	}
+
+	if (res && errno != ENOENT) {
+		printf("Could not set station " MACSTR " flags for kernel "
+		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+	}
+
+	if (authorized) {
+		os_get_time(&sta->connected_time);
+		accounting_sta_start(hapd, sta);
+	}
+}
+
+
+static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
+				  struct sta_info *sta,
+				  int idx, int broadcast,
+				  u8 *key_data, size_t key_len)
+{
+	u8 *buf, *ekey;
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	size_t len, ekey_len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	len = sizeof(*key) + key_len;
+	buf = os_zalloc(sizeof(*hdr) + len);
+	if (buf == NULL)
+		return;
+
+	hdr = (struct ieee802_1x_hdr *) buf;
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	key->type = EAPOL_KEY_TYPE_RC4;
+	WPA_PUT_BE16(key->key_length, key_len);
+	wpa_get_ntp_timestamp(key->replay_counter);
+
+	if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
+		wpa_printf(MSG_ERROR, "Could not get random numbers");
+		os_free(buf);
+		return;
+	}
+
+	key->key_index = idx | (broadcast ? 0 : BIT(7));
+	if (hapd->conf->eapol_key_index_workaround) {
+		/* According to some information, WinXP Supplicant seems to
+		 * interpret bit7 as an indication whether the key is to be
+		 * activated, so make it possible to enable workaround that
+		 * sets this bit for all keys. */
+		key->key_index |= BIT(7);
+	}
+
+	/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
+	 * MSK[32..63] is used to sign the message. */
+	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
+		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
+			   "and signing EAPOL-Key");
+		os_free(buf);
+		return;
+	}
+	os_memcpy((u8 *) (key + 1), key_data, key_len);
+	ekey_len = sizeof(key->key_iv) + 32;
+	ekey = os_malloc(ekey_len);
+	if (ekey == NULL) {
+		wpa_printf(MSG_ERROR, "Could not encrypt key");
+		os_free(buf);
+		return;
+	}
+	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
+	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
+	rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
+	os_free(ekey);
+
+	/* This header is needed here for HMAC-MD5, but it will be regenerated
+	 * in ieee802_1x_send() */
+	hdr->version = hapd->conf->eapol_version;
+	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+	hdr->length = host_to_be16(len);
+	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
+		 key->key_signature);
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
+		   " (%s index=%d)", MAC2STR(sm->addr),
+		   broadcast ? "broadcast" : "unicast", idx);
+	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
+	if (sta->eapol_sm)
+		sta->eapol_sm->dot1xAuthEapolFramesTx++;
+	os_free(buf);
+}
+
+
+#ifndef CONFIG_NO_VLAN
+static struct hostapd_wep_keys *
+ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
+{
+	struct hostapd_wep_keys *key;
+
+	key = os_zalloc(sizeof(*key));
+	if (key == NULL)
+		return NULL;
+
+	key->default_len = hapd->conf->default_wep_key_len;
+
+	if (key->idx >= hapd->conf->broadcast_key_idx_max ||
+	    key->idx < hapd->conf->broadcast_key_idx_min)
+		key->idx = hapd->conf->broadcast_key_idx_min;
+	else
+		key->idx++;
+
+	if (!key->key[key->idx])
+		key->key[key->idx] = os_malloc(key->default_len);
+	if (key->key[key->idx] == NULL ||
+	    random_get_bytes(key->key[key->idx], key->default_len)) {
+		printf("Could not generate random WEP key (dynamic VLAN).\n");
+		os_free(key->key[key->idx]);
+		key->key[key->idx] = NULL;
+		os_free(key);
+		return NULL;
+	}
+	key->len[key->idx] = key->default_len;
+
+	wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
+		   ifname, key->idx);
+	wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
+			key->key[key->idx], key->len[key->idx]);
+
+	if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+				broadcast_ether_addr, key->idx, 1,
+				NULL, 0, key->key[key->idx],
+				key->len[key->idx]))
+		printf("Could not set dynamic VLAN WEP encryption key.\n");
+
+	hostapd_set_drv_ieee8021x(hapd, ifname, 1);
+
+	return key;
+}
+
+
+static struct hostapd_wep_keys *
+ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
+		     size_t vlan_id)
+{
+	const char *ifname;
+
+	if (vlan_id == 0)
+		return &ssid->wep;
+
+	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
+	    ssid->dyn_vlan_keys[vlan_id])
+		return ssid->dyn_vlan_keys[vlan_id];
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
+		   "state machine for VLAN ID %lu",
+		   (unsigned long) vlan_id);
+
+	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+	if (ifname == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
+			   "cannot create group key state machine",
+			   (unsigned long) vlan_id);
+		return NULL;
+	}
+
+	if (ssid->dyn_vlan_keys == NULL) {
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		ssid->dyn_vlan_keys = os_zalloc(size);
+		if (ssid->dyn_vlan_keys == NULL)
+			return NULL;
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	if (ssid->max_dyn_vlan_keys < vlan_id) {
+		struct hostapd_wep_keys **na;
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		na = os_realloc(ssid->dyn_vlan_keys, size);
+		if (na == NULL)
+			return NULL;
+		ssid->dyn_vlan_keys = na;
+		os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
+			  (vlan_id - ssid->max_dyn_vlan_keys) *
+			  sizeof(ssid->dyn_vlan_keys[0]));
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
+
+	return ssid->dyn_vlan_keys[vlan_id];
+}
+#endif /* CONFIG_NO_VLAN */
+
+
+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+#ifndef CONFIG_NO_VLAN
+	struct hostapd_wep_keys *key = NULL;
+	int vlan_id;
+#endif /* CONFIG_NO_VLAN */
+
+	if (sm == NULL || !sm->eap_if->eapKeyData)
+		return;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
+		   MAC2STR(sta->addr));
+
+#ifndef CONFIG_NO_VLAN
+	vlan_id = sta->vlan_id;
+	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
+		vlan_id = 0;
+
+	if (vlan_id) {
+		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
+		if (key && key->key[key->idx])
+			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
+					      key->key[key->idx],
+					      key->len[key->idx]);
+	} else
+#endif /* CONFIG_NO_VLAN */
+	if (eapol->default_wep_key) {
+		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
+				      eapol->default_wep_key,
+				      hapd->conf->default_wep_key_len);
+	}
+
+	if (hapd->conf->individual_wep_key_len > 0) {
+		u8 *ikey;
+		ikey = os_malloc(hapd->conf->individual_wep_key_len);
+		if (ikey == NULL ||
+		    random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
+		{
+			wpa_printf(MSG_ERROR, "Could not generate random "
+				   "individual WEP key.");
+			os_free(ikey);
+			return;
+		}
+
+		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
+				ikey, hapd->conf->individual_wep_key_len);
+
+		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
+				      hapd->conf->individual_wep_key_len);
+
+		/* TODO: set encryption in TX callback, i.e., only after STA
+		 * has ACKed EAPOL-Key frame */
+		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+					sta->addr, 0, 1, NULL, 0, ikey,
+					hapd->conf->individual_wep_key_len)) {
+			wpa_printf(MSG_ERROR, "Could not set individual WEP "
+				   "encryption.");
+		}
+
+		os_free(ikey);
+	}
+}
+
+
+const char *radius_mode_txt(struct hostapd_data *hapd)
+{
+	switch (hapd->iface->conf->hw_mode) {
+	case HOSTAPD_MODE_IEEE80211AD:
+		return "802.11ad";
+	case HOSTAPD_MODE_IEEE80211A:
+		return "802.11a";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "802.11g";
+	case HOSTAPD_MODE_IEEE80211B:
+	default:
+		return "802.11b";
+	}
+}
+
+
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int i;
+	u8 rate = 0;
+
+	for (i = 0; i < sta->supported_rates_len; i++)
+		if ((sta->supported_rates[i] & 0x7f) > rate)
+			rate = sta->supported_rates[i] & 0x7f;
+
+	return rate;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
+				      struct eapol_state_machine *sm,
+				      const u8 *eap, size_t len)
+{
+	const u8 *identity;
+	size_t identity_len;
+
+	if (len <= sizeof(struct eap_hdr) ||
+	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+		return;
+
+	identity = eap_get_identity(sm->eap, &identity_len);
+	if (identity == NULL)
+		return;
+
+	/* Save station identity for future RADIUS packets */
+	os_free(sm->identity);
+	sm->identity = os_malloc(identity_len + 1);
+	if (sm->identity == NULL) {
+		sm->identity_len = 0;
+		return;
+	}
+
+	os_memcpy(sm->identity, identity, identity_len);
+	sm->identity_len = identity_len;
+	sm->identity[identity_len] = '\0';
+	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
+	sm->dot1xAuthEapolRespIdFramesRx++;
+}
+
+
+static int add_common_radius_sta_attr(struct hostapd_data *hapd,
+				      struct hostapd_radius_attr *req_attr,
+				      struct sta_info *sta,
+				      struct radius_msg *msg)
+{
+	char buf[128];
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_PORT) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Port");
+		return -1;
+	}
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(sta->addr));
+	buf[sizeof(buf) - 1] = '\0';
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
+		return -1;
+	}
+
+	if (sta->flags & WLAN_STA_PREAUTH) {
+		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
+			   sizeof(buf));
+	} else {
+		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+			    radius_sta_rate(hapd, sta) / 2,
+			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+			    radius_mode_txt(hapd));
+		buf[sizeof(buf) - 1] = '\0';
+	}
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_CONNECT_INFO) &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_ERROR, "Could not add Connect-Info");
+		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 (!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");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int add_common_radius_attr(struct hostapd_data *hapd,
+			   struct hostapd_radius_attr *req_attr,
+			   struct sta_info *sta,
+			   struct radius_msg *msg)
+{
+	char buf[128];
+	struct hostapd_radius_attr *attr;
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IP_ADDRESS) &&
+	    hapd->conf->own_ip_addr.af == AF_INET &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
+		return -1;
+	}
+
+#ifdef CONFIG_IPV6
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+	    hapd->conf->own_ip_addr.af == AF_INET6 &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
+		return -1;
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IDENTIFIER) &&
+	    hapd->conf->nas_identifier &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+				 (u8 *) hapd->conf->nas_identifier,
+				 os_strlen(hapd->conf->nas_identifier))) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
+		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';
+	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))) {
+		wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
+		return -1;
+	}
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_PORT_TYPE) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
+		return -1;
+	}
+
+	if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
+		return -1;
+
+	for (attr = req_attr; attr; attr = attr->next) {
+		if (!radius_msg_add_attr(msg, attr->type,
+					 wpabuf_head(attr->val),
+					 wpabuf_len(attr->val))) {
+			wpa_printf(MSG_ERROR, "Could not add RADIUS "
+				   "attribute");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  const u8 *eap, size_t len)
+{
+	struct radius_msg *msg;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	ieee802_1x_learn_identity(hapd, sm, eap, len);
+
+	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
+		   "packet");
+
+	sm->radius_identifier = radius_client_get_id(hapd->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+			     sm->radius_identifier);
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return;
+	}
+
+	radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+	if (sm->identity &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+				 sm->identity, sm->identity_len)) {
+		printf("Could not add User-Name\n");
+		goto fail;
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
+				   msg) < 0)
+		goto fail;
+
+	/* TODO: should probably check MTU from driver config; 2304 is max for
+	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
+	 */
+	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+					    RADIUS_ATTR_FRAMED_MTU) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+		printf("Could not add Framed-MTU\n");
+		goto fail;
+	}
+
+	if (eap && !radius_msg_add_eap(msg, eap, len)) {
+		printf("Could not add EAP-Message\n");
+		goto fail;
+	}
+
+	/* State attribute must be copied if and only if this packet is
+	 * Access-Request reply to the previous Access-Challenge */
+	if (sm->last_recv_radius &&
+	    radius_msg_get_hdr(sm->last_recv_radius)->code ==
+	    RADIUS_CODE_ACCESS_CHALLENGE) {
+		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
+					       RADIUS_ATTR_STATE);
+		if (res < 0) {
+			printf("Could not copy State attribute from previous "
+			       "Access-Challenge\n");
+			goto fail;
+		}
+		if (res > 0) {
+			wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
+		}
+	}
+
+	if (hapd->conf->radius_request_cui) {
+		const u8 *cui;
+		size_t cui_len;
+		/* Add previously learned CUI or nul CUI to request CUI */
+		if (sm->radius_cui) {
+			cui = wpabuf_head(sm->radius_cui);
+			cui_len = wpabuf_len(sm->radius_cui);
+		} else {
+			cui = (const u8 *) "\0";
+			cui_len = 1;
+		}
+		if (!radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 cui, cui_len)) {
+			wpa_printf(MSG_ERROR, "Could not add CUI");
+			goto fail;
+		}
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
+		goto fail;
+
+	return;
+
+ fail:
+	radius_msg_free(msg);
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static void handle_eap_response(struct hostapd_data *hapd,
+				struct sta_info *sta, struct eap_hdr *eap,
+				size_t len)
+{
+	u8 type, *data;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	data = (u8 *) (eap + 1);
+
+	if (len < sizeof(*eap) + 1) {
+		printf("handle_eap_response: too short response data\n");
+		return;
+	}
+
+	sm->eap_type_supp = type = data[0];
+
+	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+		       "id=%d len=%d) from STA: EAP Response-%s (%d)",
+		       eap->code, eap->identifier, be_to_host16(eap->length),
+		       eap_server_get_name(0, type), type);
+
+	sm->dot1xAuthEapolRespFramesRx++;
+
+	wpabuf_free(sm->eap_if->eapRespData);
+	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+	sm->eapolEap = TRUE;
+}
+
+
+/* Process incoming EAP packet from Supplicant */
+static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
+		       u8 *buf, size_t len)
+{
+	struct eap_hdr *eap;
+	u16 eap_len;
+
+	if (len < sizeof(*eap)) {
+		printf("   too short EAP packet\n");
+		return;
+	}
+
+	eap = (struct eap_hdr *) buf;
+
+	eap_len = be_to_host16(eap->length);
+	wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
+		   eap->code, eap->identifier, eap_len);
+	if (eap_len < sizeof(*eap)) {
+		wpa_printf(MSG_DEBUG, "   Invalid EAP length");
+		return;
+	} else if (eap_len > len) {
+		wpa_printf(MSG_DEBUG, "   Too short frame to contain this EAP "
+			   "packet");
+		return;
+	} else if (eap_len < len) {
+		wpa_printf(MSG_DEBUG, "   Ignoring %lu extra bytes after EAP "
+			   "packet", (unsigned long) len - eap_len);
+	}
+
+	switch (eap->code) {
+	case EAP_CODE_REQUEST:
+		wpa_printf(MSG_DEBUG, " (request)");
+		return;
+	case EAP_CODE_RESPONSE:
+		wpa_printf(MSG_DEBUG, " (response)");
+		handle_eap_response(hapd, sta, eap, eap_len);
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, " (success)");
+		return;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, " (failure)");
+		return;
+	default:
+		wpa_printf(MSG_DEBUG, " (unknown code)");
+		return;
+	}
+}
+
+
+static struct eapol_state_machine *
+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int flags = 0;
+	if (sta->flags & WLAN_STA_PREAUTH)
+		flags |= EAPOL_SM_PREAUTH;
+	if (sta->wpa_sm) {
+		flags |= EAPOL_SM_USES_WPA;
+		if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
+			flags |= EAPOL_SM_FROM_PMKSA_CACHE;
+	}
+	return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
+				sta->wps_ie, sta->p2p_ie, sta,
+				sta->identity, sta->radius_cui);
+}
+
+
+/**
+ * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
+ * @hapd: hostapd BSS data
+ * @sa: Source address (sender of the EAPOL frame)
+ * @buf: EAPOL frame
+ * @len: Length of buf in octets
+ *
+ * This function is called for each incoming EAPOL frame from the interface
+ */
+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
+			size_t len)
+{
+	struct sta_info *sta;
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	u16 datalen;
+	struct rsn_pmksa_cache_entry *pmksa;
+	int key_mgmt;
+
+	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+	    !hapd->conf->wps_state)
+		return;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
+		   (unsigned long) len, MAC2STR(sa));
+	sta = ap_get_sta(hapd, sa);
+	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
+			   "associated/Pre-authenticating STA");
+		return;
+	}
+
+	if (len < sizeof(*hdr)) {
+		printf("   too short IEEE 802.1X packet\n");
+		return;
+	}
+
+	hdr = (struct ieee802_1x_hdr *) buf;
+	datalen = be_to_host16(hdr->length);
+	wpa_printf(MSG_DEBUG, "   IEEE 802.1X: version=%d type=%d length=%d",
+		   hdr->version, hdr->type, datalen);
+
+	if (len - sizeof(*hdr) < datalen) {
+		printf("   frame too short for this IEEE 802.1X packet\n");
+		if (sta->eapol_sm)
+			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
+		return;
+	}
+	if (len - sizeof(*hdr) > datalen) {
+		wpa_printf(MSG_DEBUG, "   ignoring %lu extra octets after "
+			   "IEEE 802.1X packet",
+			   (unsigned long) len - sizeof(*hdr) - datalen);
+	}
+
+	if (sta->eapol_sm) {
+		sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
+		sta->eapol_sm->dot1xAuthEapolFramesRx++;
+	}
+
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
+	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
+	    (key->type == EAPOL_KEY_TYPE_WPA ||
+	     key->type == EAPOL_KEY_TYPE_RSN)) {
+		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
+			    sizeof(*hdr) + datalen);
+		return;
+	}
+
+	if (!hapd->conf->ieee802_1x &&
+	    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+			   "802.1X not enabled and WPS not used");
+		return;
+	}
+
+	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+			   "STA is using PSK");
+		return;
+	}
+
+	if (!sta->eapol_sm) {
+		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+		if (!sta->eapol_sm)
+			return;
+
+#ifdef CONFIG_WPS
+		if (!hapd->conf->ieee802_1x) {
+			u32 wflags = sta->flags & (WLAN_STA_WPS |
+						   WLAN_STA_WPS2 |
+						   WLAN_STA_MAYBE_WPS);
+			if (wflags == WLAN_STA_MAYBE_WPS ||
+			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+				/*
+				 * Delay EAPOL frame transmission until a
+				 * possible WPS STA initiates the handshake
+				 * with EAPOL-Start. Only allow the wait to be
+				 * skipped if the STA is known to support WPS
+				 * 2.0.
+				 */
+				wpa_printf(MSG_DEBUG, "WPS: Do not start "
+					   "EAPOL until EAPOL-Start is "
+					   "received");
+				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+			}
+		}
+#endif /* CONFIG_WPS */
+
+		sta->eapol_sm->eap_if->portEnabled = TRUE;
+	}
+
+	/* since we support version 1, we can ignore version field and proceed
+	 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
+	/* TODO: actually, we are not version 1 anymore.. However, Version 2
+	 * does not change frame contents, so should be ok to process frames
+	 * more or less identically. Some changes might be needed for
+	 * verification of fields. */
+
+	switch (hdr->type) {
+	case IEEE802_1X_TYPE_EAP_PACKET:
+		handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_START:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
+			       "from STA");
+		sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+		if (pmksa) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
+				       "available - ignore it since "
+				       "STA sent EAPOL-Start");
+			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
+		}
+		sta->eapol_sm->eapolStart = TRUE;
+		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
+		eap_server_clear_identity(sta->eapol_sm->eap);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
+			       "from STA");
+		sta->acct_terminate_cause =
+			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+		accounting_sta_stop(hapd, sta);
+		sta->eapol_sm->eapolLogoff = TRUE;
+		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
+		eap_server_clear_identity(sta->eapol_sm->eap);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_KEY:
+		wpa_printf(MSG_DEBUG, "   EAPOL-Key");
+		if (!ap_sta_is_authorized(sta)) {
+			wpa_printf(MSG_DEBUG, "   Dropped key data from "
+				   "unauthorized Supplicant");
+			break;
+		}
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+		wpa_printf(MSG_DEBUG, "   EAPOL-Encapsulated-ASF-Alert");
+		/* TODO: implement support for this; show data */
+		break;
+
+	default:
+		wpa_printf(MSG_DEBUG, "   unknown IEEE 802.1X packet type");
+		sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
+		break;
+	}
+
+	eapol_auth_step(sta->eapol_sm);
+}
+
+
+/**
+ * ieee802_1x_new_station - Start IEEE 802.1X authentication
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ *
+ * This function is called to start IEEE 802.1X authentication when a new
+ * station completes IEEE 802.11 association.
+ */
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct rsn_pmksa_cache_entry *pmksa;
+	int reassoc = 1;
+	int force_1x = 0;
+	int key_mgmt;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+		/*
+		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
+		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
+		 * authentication in this BSS.
+		 */
+		force_1x = 1;
+	}
+#endif /* CONFIG_WPS */
+
+	if (!force_1x && !hapd->conf->ieee802_1x) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
+			   "802.1X not enabled or forced for WPS");
+		/*
+		 * Clear any possible EAPOL authenticator state to support
+		 * reassociation change from WPS to PSK.
+		 */
+		ieee802_1x_free_station(sta);
+		return;
+	}
+
+	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
+		/*
+		 * Clear any possible EAPOL authenticator state to support
+		 * reassociation change from WPA-EAP to PSK.
+		 */
+		ieee802_1x_free_station(sta);
+		return;
+	}
+
+	if (sta->eapol_sm == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "start authentication");
+		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+		if (sta->eapol_sm == NULL) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO,
+				       "failed to allocate state machine");
+			return;
+		}
+		reassoc = 0;
+	}
+
+#ifdef CONFIG_WPS
+	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
+		/*
+		 * Delay EAPOL frame transmission until a possible WPS STA
+		 * initiates the handshake with EAPOL-Start. Only allow the
+		 * wait to be skipped if the STA is known to support WPS 2.0.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+			   "EAPOL-Start is received");
+		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+	}
+#endif /* CONFIG_WPS */
+
+	sta->eapol_sm->eap_if->portEnabled = TRUE;
+
+#ifdef CONFIG_IEEE80211R
+	if (sta->auth_alg == WLAN_AUTH_FT) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "PMK from FT - skip IEEE 802.1X/EAP");
+		/* Setup EAPOL state machines to already authenticated state
+		 * because of existing FT information from R0KH. */
+		sta->eapol_sm->keyRun = TRUE;
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+		sta->eapol_sm->authSuccess = TRUE;
+		sta->eapol_sm->authFail = FALSE;
+		if (sta->eapol_sm->eap)
+			eap_sm_notify_cached(sta->eapol_sm->eap);
+		/* TODO: get vlan_id from R0KH using RRB message */
+		return;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+	if (pmksa) {
+		int old_vlanid;
+
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
+		/* Setup EAPOL state machines to already authenticated state
+		 * because of existing PMKSA information in the cache. */
+		sta->eapol_sm->keyRun = TRUE;
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+		sta->eapol_sm->authSuccess = TRUE;
+		sta->eapol_sm->authFail = FALSE;
+		if (sta->eapol_sm->eap)
+			eap_sm_notify_cached(sta->eapol_sm->eap);
+		old_vlanid = sta->vlan_id;
+		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+		ap_sta_bind_vlan(hapd, sta, old_vlanid);
+	} else {
+		if (reassoc) {
+			/*
+			 * Force EAPOL state machines to start
+			 * re-authentication without having to wait for the
+			 * Supplicant to send EAPOL-Start.
+			 */
+			sta->eapol_sm->reAuthenticate = TRUE;
+		}
+		eapol_auth_step(sta->eapol_sm);
+	}
+}
+
+
+void ieee802_1x_free_station(struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	sta->eapol_sm = NULL;
+
+#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);
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta)
+{
+	struct wpabuf *eap;
+	const struct eap_hdr *hdr;
+	int eap_type = -1;
+	char buf[64];
+	struct radius_msg *msg;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL || sm->last_recv_radius == NULL) {
+		if (sm)
+			sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	msg = sm->last_recv_radius;
+
+	eap = radius_msg_get_eap(msg);
+	if (eap == NULL) {
+		/* RFC 3579, Chap. 2.6.3:
+		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
+		 * attribute */
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "could not extract "
+			       "EAP-Message from RADIUS message");
+		sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	if (wpabuf_len(eap) < sizeof(*hdr)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
+			       "received from authentication server");
+		wpabuf_free(eap);
+		sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	if (wpabuf_len(eap) > sizeof(*hdr))
+		eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
+
+	hdr = wpabuf_head(eap);
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (eap_type >= 0)
+			sm->eap_type_authsrv = eap_type;
+		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
+			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+			    "??",
+			    eap_type);
+		break;
+	case EAP_CODE_RESPONSE:
+		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
+			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+			    "??",
+			    eap_type);
+		break;
+	case EAP_CODE_SUCCESS:
+		os_strlcpy(buf, "EAP Success", sizeof(buf));
+		break;
+	case EAP_CODE_FAILURE:
+		os_strlcpy(buf, "EAP Failure", sizeof(buf));
+		break;
+	default:
+		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
+		break;
+	}
+	buf[sizeof(buf) - 1] = '\0';
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
+		       "id=%d len=%d) from RADIUS server: %s",
+		       hdr->code, hdr->identifier, be_to_host16(hdr->length),
+		       buf);
+	sm->eap_if->aaaEapReq = TRUE;
+
+	wpabuf_free(sm->eap_if->aaaEapReqData);
+	sm->eap_if->aaaEapReqData = eap;
+}
+
+
+static void ieee802_1x_get_keys(struct hostapd_data *hapd,
+				struct sta_info *sta, struct radius_msg *msg,
+				struct radius_msg *req,
+				const u8 *shared_secret,
+				size_t shared_secret_len)
+{
+	struct radius_ms_mppe_keys *keys;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
+				      shared_secret_len);
+
+	if (keys && keys->send && keys->recv) {
+		size_t len = keys->send_len + keys->recv_len;
+		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+				keys->send, keys->send_len);
+		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+				keys->recv, keys->recv_len);
+
+		os_free(sm->eap_if->aaaEapKeyData);
+		sm->eap_if->aaaEapKeyData = os_malloc(len);
+		if (sm->eap_if->aaaEapKeyData) {
+			os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
+				  keys->recv_len);
+			os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
+				  keys->send, keys->send_len);
+			sm->eap_if->aaaEapKeyDataLen = len;
+			sm->eap_if->aaaEapKeyAvailable = TRUE;
+		}
+	}
+
+	if (keys) {
+		os_free(keys->send);
+		os_free(keys->recv);
+		os_free(keys);
+	}
+}
+
+
+static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  struct radius_msg *msg)
+{
+	u8 *class;
+	size_t class_len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	int count, i;
+	struct radius_attr_data *nclass;
+	size_t nclass_count;
+
+	if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
+	    sm == NULL)
+		return;
+
+	radius_free_class(&sm->radius_class);
+	count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+	if (count <= 0)
+		return;
+
+	nclass = os_calloc(count, sizeof(struct radius_attr_data));
+	if (nclass == NULL)
+		return;
+
+	nclass_count = 0;
+
+	class = NULL;
+	for (i = 0; i < count; i++) {
+		do {
+			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+						    &class, &class_len,
+						    class) < 0) {
+				i = count;
+				break;
+			}
+		} while (class_len < 1);
+
+		nclass[nclass_count].data = os_malloc(class_len);
+		if (nclass[nclass_count].data == NULL)
+			break;
+
+		os_memcpy(nclass[nclass_count].data, class, class_len);
+		nclass[nclass_count].len = class_len;
+		nclass_count++;
+	}
+
+	sm->radius_class.attr = nclass;
+	sm->radius_class.count = nclass_count;
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
+		   "attributes for " MACSTR,
+		   (unsigned long) sm->radius_class.count,
+		   MAC2STR(sta->addr));
+}
+
+
+/* Update sta->identity based on User-Name attribute in Access-Accept */
+static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
+					   struct sta_info *sta,
+					   struct radius_msg *msg)
+{
+	u8 *buf, *identity;
+	size_t len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
+				    NULL) < 0)
+		return;
+
+	identity = os_malloc(len + 1);
+	if (identity == NULL)
+		return;
+
+	os_memcpy(identity, buf, len);
+	identity[len] = '\0';
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
+		       "User-Name from Access-Accept '%s'",
+		       sm->identity ? (char *) sm->identity : "N/A",
+		       (char *) identity);
+
+	os_free(sm->identity);
+	sm->identity = identity;
+	sm->identity_len = len;
+}
+
+
+/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
+static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
+				      struct sta_info *sta,
+				      struct radius_msg *msg)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct wpabuf *cui;
+	u8 *buf;
+	size_t len;
+
+	if (sm == NULL)
+		return;
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+				    &buf, &len, NULL) < 0)
+		return;
+
+	cui = wpabuf_alloc_copy(buf, len);
+	if (cui == NULL)
+		return;
+
+	wpabuf_free(sm->radius_cui);
+	sm->radius_cui = cui;
+}
+
+
+struct sta_id_search {
+	u8 identifier;
+	struct eapol_state_machine *sm;
+};
+
+
+static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
+					       struct sta_info *sta,
+					       void *ctx)
+{
+	struct sta_id_search *id_search = ctx;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm && sm->radius_identifier >= 0 &&
+	    sm->radius_identifier == id_search->identifier) {
+		id_search->sm = sm;
+		return 1;
+	}
+	return 0;
+}
+
+
+static struct eapol_state_machine *
+ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
+{
+	struct sta_id_search id_search;
+	id_search.identifier = identifier;
+	id_search.sm = NULL;
+	ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
+	return id_search.sm;
+}
+
+
+/**
+ * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
+			const u8 *shared_secret, size_t shared_secret_len,
+			void *data)
+{
+	struct hostapd_data *hapd = data;
+	struct sta_info *sta;
+	u32 session_timeout = 0, termination_action, acct_interim_interval;
+	int session_timeout_set, old_vlanid = 0;
+	struct eapol_state_machine *sm;
+	int override_eapReq = 0;
+	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+
+	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
+			   "station for this RADIUS message");
+		return RADIUS_RX_UNKNOWN;
+	}
+	sta = sm->sta;
+
+	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
+	 * present when packet contains an EAP-Message attribute */
+	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
+				0) < 0 &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
+			   "Message-Authenticator since it does not include "
+			   "EAP-Message");
+	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
+				     req, 1)) {
+		printf("Incoming RADIUS packet did not have correct "
+		       "Message-Authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
+		printf("Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	sm->radius_identifier = -1;
+	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
+		   MAC2STR(sta->addr));
+
+	radius_msg_free(sm->last_recv_radius);
+	sm->last_recv_radius = msg;
+
+	session_timeout_set =
+		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
+					   &session_timeout);
+	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
+				      &termination_action))
+		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
+
+	if (hapd->conf->acct_interim_interval == 0 &&
+	    hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
+	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
+				      &acct_interim_interval) == 0) {
+		if (acct_interim_interval < 60) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO,
+				       "ignored too small "
+				       "Acct-Interim-Interval %d",
+				       acct_interim_interval);
+		} else
+			sta->acct_interim_interval = acct_interim_interval;
+	}
+
+
+	switch (hdr->code) {
+	case RADIUS_CODE_ACCESS_ACCEPT:
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+#ifndef CONFIG_NO_VLAN
+		else {
+			old_vlanid = sta->vlan_id;
+			sta->vlan_id = radius_msg_get_vlanid(msg);
+		}
+		if (sta->vlan_id > 0 &&
+		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       sta->vlan_id)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "VLAN ID %d", sta->vlan_id);
+		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+			sta->eapol_sm->authFail = TRUE;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO, "authentication "
+				       "server did not include required VLAN "
+				       "ID in Access-Accept");
+			break;
+		}
+#endif /* CONFIG_NO_VLAN */
+
+		if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
+			break;
+
+		/* RFC 3580, Ch. 3.17 */
+		if (session_timeout_set && termination_action ==
+		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+			sm->reAuthPeriod = session_timeout;
+		} else if (session_timeout_set)
+			ap_sta_session_timeout(hapd, sta, session_timeout);
+
+		sm->eap_if->aaaSuccess = TRUE;
+		override_eapReq = 1;
+		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
+				    shared_secret_len);
+		ieee802_1x_store_radius_class(hapd, sta, msg);
+		ieee802_1x_update_sta_identity(hapd, sta, msg);
+		ieee802_1x_update_sta_cui(hapd, sta, msg);
+		if (sm->eap_if->eapKeyAvailable &&
+		    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;
+		override_eapReq = 1;
+		break;
+	case RADIUS_CODE_ACCESS_CHALLENGE:
+		sm->eap_if->aaaEapReq = TRUE;
+		if (session_timeout_set) {
+			/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
+			sm->eap_if->aaaMethodTimeout = session_timeout;
+			hostapd_logger(hapd, sm->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "using EAP timeout of %d seconds (from "
+				       "RADIUS)",
+				       sm->eap_if->aaaMethodTimeout);
+		} else {
+			/*
+			 * Use dynamic retransmission behavior per EAP
+			 * specification.
+			 */
+			sm->eap_if->aaaMethodTimeout = 0;
+		}
+		break;
+	}
+
+	ieee802_1x_decapsulate_radius(hapd, sta);
+	if (override_eapReq)
+		sm->eap_if->aaaEapReq = FALSE;
+
+	eapol_auth_step(sm);
+
+	return RADIUS_RX_QUEUED;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
+
+#ifndef CONFIG_NO_RADIUS
+	radius_msg_free(sm->last_recv_radius);
+	sm->last_recv_radius = NULL;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (sm->eap_if->eapTimeout) {
+		/*
+		 * Disconnect the STA since it did not reply to the last EAP
+		 * request and we cannot continue EAP processing (EAP-Failure
+		 * could only be sent if the EAP peer actually replied).
+		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+			MAC2STR(sta->addr));
+
+		sm->eap_if->portEnabled = FALSE;
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+	}
+}
+
+
+static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
+{
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+
+	if (hapd->conf->default_wep_key_len < 1)
+		return 0;
+
+	os_free(eapol->default_wep_key);
+	eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
+	if (eapol->default_wep_key == NULL ||
+	    random_get_bytes(eapol->default_wep_key,
+			     hapd->conf->default_wep_key_len)) {
+		printf("Could not generate random WEP key.\n");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
+			eapol->default_wep_key,
+			hapd->conf->default_wep_key_len);
+
+	return 0;
+}
+
+
+static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
+					struct sta_info *sta, void *ctx)
+{
+	if (sta->eapol_sm) {
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		eapol_auth_step(sta->eapol_sm);
+	}
+	return 0;
+}
+
+
+static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+
+	if (eapol->default_wep_key_idx >= 3)
+		eapol->default_wep_key_idx =
+			hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
+	else
+		eapol->default_wep_key_idx++;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
+		   eapol->default_wep_key_idx);
+		      
+	if (ieee802_1x_rekey_broadcast(hapd)) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
+			       "new broadcast key");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return;
+	}
+
+	/* TODO: Could setup key for RX here, but change default TX keyid only
+	 * after new broadcast key has been sent to all stations. */
+	if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+				broadcast_ether_addr,
+				eapol->default_wep_key_idx, 1, NULL, 0,
+				eapol->default_wep_key,
+				hapd->conf->default_wep_key_len)) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
+			       "new broadcast key");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return;
+	}
+
+	ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
+
+	if (hapd->conf->wep_rekeying_period > 0) {
+		eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
+				       ieee802_1x_rekey, hapd, NULL);
+	}
+}
+
+
+static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
+				  const u8 *data, size_t datalen)
+{
+#ifdef CONFIG_WPS
+	struct sta_info *sta = sta_ctx;
+
+	if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
+	    WLAN_STA_MAYBE_WPS) {
+		const u8 *identity;
+		size_t identity_len;
+		struct eapol_state_machine *sm = sta->eapol_sm;
+
+		identity = eap_get_identity(sm->eap, &identity_len);
+		if (identity &&
+		    ((identity_len == WSC_ID_ENROLLEE_LEN &&
+		      os_memcmp(identity, WSC_ID_ENROLLEE,
+				WSC_ID_ENROLLEE_LEN) == 0) ||
+		     (identity_len == WSC_ID_REGISTRAR_LEN &&
+		      os_memcmp(identity, WSC_ID_REGISTRAR,
+				WSC_ID_REGISTRAR_LEN) == 0))) {
+			wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
+				   "WLAN_STA_WPS");
+			sta->flags |= WLAN_STA_WPS;
+		}
+	}
+#endif /* CONFIG_WPS */
+
+	ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
+}
+
+
+static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
+				const u8 *data, size_t datalen)
+{
+#ifndef CONFIG_NO_RADIUS
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+
+	ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
+#endif /* CONFIG_NO_RADIUS */
+}
+
+
+static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
+				 int preauth)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	if (preauth)
+		rsn_preauth_finished(hapd, sta, success);
+	else
+		ieee802_1x_finished(hapd, sta, success);
+}
+
+
+static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
+				   size_t identity_len, int phase2,
+				   struct eap_user *user)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct hostapd_eap_user *eap_user;
+	int i;
+
+	eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
+	if (eap_user == NULL)
+		return -1;
+
+	os_memset(user, 0, sizeof(*user));
+	user->phase2 = phase2;
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
+
+	if (eap_user->password) {
+		user->password = os_malloc(eap_user->password_len);
+		if (user->password == NULL)
+			return -1;
+		os_memcpy(user->password, eap_user->password,
+			  eap_user->password_len);
+		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
+	}
+	user->force_version = eap_user->force_version;
+	user->ttls_auth = eap_user->ttls_auth;
+
+	return 0;
+}
+
+
+static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL || sta->eapol_sm == NULL)
+		return 0;
+	return 1;
+}
+
+
+static void ieee802_1x_logger(void *ctx, const u8 *addr,
+			      eapol_logger_level level, const char *txt)
+{
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+	struct hostapd_data *hapd = ctx;
+	int hlevel;
+
+	switch (level) {
+	case EAPOL_LOGGER_WARNING:
+		hlevel = HOSTAPD_LEVEL_WARNING;
+		break;
+	case EAPOL_LOGGER_INFO:
+		hlevel = HOSTAPD_LEVEL_INFO;
+		break;
+	case EAPOL_LOGGER_DEBUG:
+	default:
+		hlevel = HOSTAPD_LEVEL_DEBUG;
+		break;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
+		       txt);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+}
+
+
+static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
+					   int authorized)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_set_sta_authorized(hapd, sta, authorized);
+}
+
+
+static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_abort_auth(hapd, sta);
+}
+
+
+static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_tx_key(hapd, sta);
+}
+
+
+static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
+				   enum eapol_event type)
+{
+	/* struct hostapd_data *hapd = ctx; */
+	struct sta_info *sta = sta_ctx;
+	switch (type) {
+	case EAPOL_AUTH_SM_CHANGE:
+		wpa_auth_sm_notify(sta->wpa_sm);
+		break;
+	case EAPOL_AUTH_REAUTHENTICATE:
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+		break;
+	}
+}
+
+
+int ieee802_1x_init(struct hostapd_data *hapd)
+{
+	int i;
+	struct eapol_auth_config conf;
+	struct eapol_auth_cb cb;
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.ctx = hapd;
+	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
+	conf.wpa = hapd->conf->wpa;
+	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+	conf.eap_server = hapd->conf->eap_server;
+	conf.ssl_ctx = hapd->ssl_ctx;
+	conf.msg_ctx = hapd->msg_ctx;
+	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
+	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
+	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
+	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+	conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
+	conf.eap_fast_prov = hapd->conf->eap_fast_prov;
+	conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
+	conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+	conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+	conf.tnc = hapd->conf->tnc;
+	conf.wps = hapd->wps;
+	conf.fragment_size = hapd->conf->fragment_size;
+	conf.pwd_group = hapd->conf->pwd_group;
+	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+
+	os_memset(&cb, 0, sizeof(cb));
+	cb.eapol_send = ieee802_1x_eapol_send;
+	cb.aaa_send = ieee802_1x_aaa_send;
+	cb.finished = _ieee802_1x_finished;
+	cb.get_eap_user = ieee802_1x_get_eap_user;
+	cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
+	cb.logger = ieee802_1x_logger;
+	cb.set_port_authorized = ieee802_1x_set_port_authorized;
+	cb.abort_auth = _ieee802_1x_abort_auth;
+	cb.tx_key = _ieee802_1x_tx_key;
+	cb.eapol_event = ieee802_1x_eapol_event;
+
+	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
+	if (hapd->eapol_auth == NULL)
+		return -1;
+
+	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
+	    hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
+		return -1;
+
+#ifndef CONFIG_NO_RADIUS
+	if (radius_client_register(hapd->radius, RADIUS_AUTH,
+				   ieee802_1x_receive_auth, hapd))
+		return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hapd->conf->default_wep_key_len) {
+		for (i = 0; i < 4; i++)
+			hostapd_drv_set_key(hapd->conf->iface, hapd,
+					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+					    NULL, 0);
+
+		ieee802_1x_rekey(hapd, NULL);
+
+		if (hapd->eapol_auth->default_wep_key == NULL)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void ieee802_1x_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+
+	if (hapd->driver != NULL &&
+	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+
+	eapol_auth_deinit(hapd->eapol_auth);
+	hapd->eapol_auth = NULL;
+}
+
+
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 const u8 *buf, size_t len, int ack)
+{
+	struct ieee80211_hdr *hdr;
+	u8 *pos;
+	const unsigned char rfc1042_hdr[ETH_ALEN] =
+		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+	if (sta == NULL)
+		return -1;
+	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
+		return 0;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	pos = (u8 *) (hdr + 1);
+	if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
+		return 0;
+	pos += sizeof(rfc1042_hdr);
+	if (WPA_GET_BE16(pos) != ETH_P_PAE)
+		return 0;
+	pos += 2;
+
+	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+					  ack);
+}
+
+
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *buf, int len, int ack)
+{
+	const struct ieee802_1x_hdr *xhdr =
+		(const struct ieee802_1x_hdr *) buf;
+	const u8 *pos = buf + sizeof(*xhdr);
+	struct ieee802_1x_eapol_key *key;
+
+	if (len < (int) sizeof(*xhdr))
+		return 0;
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
+		   "type=%d length=%d - ack=%d",
+		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
+		   be_to_host16(xhdr->length), ack);
+
+	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+		return 0;
+
+	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+		const struct wpa_eapol_key *wpa;
+		wpa = (const struct wpa_eapol_key *) pos;
+		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
+		    wpa->type == EAPOL_KEY_TYPE_WPA)
+			wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
+						     sta->wpa_sm, ack);
+	}
+
+	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
+	 * or Authenticator state machines, but EAPOL-Key packets are not
+	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
+	 * packets couple of times because otherwise STA keys become
+	 * unsynchronized with AP. */
+	if (!ack && pos + sizeof(*key) <= buf + len) {
+		key = (struct ieee802_1x_eapol_key *) pos;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
+			       "frame (%scast index=%d)",
+			       key->key_index & BIT(7) ? "uni" : "broad",
+			       key->key_index & ~BIT(7));
+		/* TODO: re-send EAPOL-Key couple of times (with short delay
+		 * between them?). If all attempt fail, report error and
+		 * deauthenticate STA so that it will get new keys when
+		 * authenticating again (e.g., after returning in range).
+		 * Separate limit/transmit state needed both for unicast and
+		 * broadcast keys(?) */
+	}
+	/* TODO: could move unicast key configuration from ieee802_1x_tx_key()
+	 * to here and change the key only if the EAPOL-Key packet was Acked.
+	 */
+
+	return 1;
+}
+
+
+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
+{
+	if (sm == NULL || sm->identity == NULL)
+		return NULL;
+
+	*len = sm->identity_len;
+	return sm->identity;
+}
+
+
+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+				 int idx)
+{
+	if (sm == NULL || sm->radius_class.attr == NULL ||
+	    idx >= (int) sm->radius_class.count)
+		return NULL;
+
+	*len = sm->radius_class.attr[idx].len;
+	return sm->radius_class.attr[idx].data;
+}
+
+
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+	if (sm == NULL)
+		return NULL;
+	return sm->radius_cui;
+}
+
+
+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
+{
+	*len = 0;
+	if (sm == NULL)
+		return NULL;
+
+	*len = sm->eap_if->eapKeyDataLen;
+	return sm->eap_if->eapKeyData;
+}
+
+
+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
+				    int enabled)
+{
+	if (sm == NULL)
+		return;
+	sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+	eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
+				  int valid)
+{
+	if (sm == NULL)
+		return;
+	sm->portValid = valid ? TRUE : FALSE;
+	eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+{
+	if (sm == NULL)
+		return;
+	if (pre_auth)
+		sm->flags |= EAPOL_SM_PREAUTH;
+	else
+		sm->flags &= ~EAPOL_SM_PREAUTH;
+}
+
+
+static const char * bool_txt(Boolean bool)
+{
+	return bool ? "TRUE" : "FALSE";
+}
+
+
+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct os_time t;
+
+	if (sm == NULL)
+		return 0;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xPaePortNumber=%d\n"
+			  "dot1xPaePortProtocolVersion=%d\n"
+			  "dot1xPaePortCapabilities=1\n"
+			  "dot1xPaePortInitialize=%d\n"
+			  "dot1xPaePortReauthenticate=FALSE\n",
+			  sta->aid,
+			  EAPOL_VERSION,
+			  sm->initialize);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthConfigTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthPaeState=%d\n"
+			  "dot1xAuthBackendAuthState=%d\n"
+			  "dot1xAuthAdminControlledDirections=%d\n"
+			  "dot1xAuthOperControlledDirections=%d\n"
+			  "dot1xAuthAuthControlledPortStatus=%d\n"
+			  "dot1xAuthAuthControlledPortControl=%d\n"
+			  "dot1xAuthQuietPeriod=%u\n"
+			  "dot1xAuthServerTimeout=%u\n"
+			  "dot1xAuthReAuthPeriod=%u\n"
+			  "dot1xAuthReAuthEnabled=%s\n"
+			  "dot1xAuthKeyTxEnabled=%s\n",
+			  sm->auth_pae_state + 1,
+			  sm->be_auth_state + 1,
+			  sm->adminControlledDirections,
+			  sm->operControlledDirections,
+			  sm->authPortStatus,
+			  sm->portControl,
+			  sm->quietPeriod,
+			  sm->serverTimeout,
+			  sm->reAuthPeriod,
+			  bool_txt(sm->reAuthEnabled),
+			  bool_txt(sm->keyTxEnabled));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthStatsTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthEapolFramesRx=%u\n"
+			  "dot1xAuthEapolFramesTx=%u\n"
+			  "dot1xAuthEapolStartFramesRx=%u\n"
+			  "dot1xAuthEapolLogoffFramesRx=%u\n"
+			  "dot1xAuthEapolRespIdFramesRx=%u\n"
+			  "dot1xAuthEapolRespFramesRx=%u\n"
+			  "dot1xAuthEapolReqIdFramesTx=%u\n"
+			  "dot1xAuthEapolReqFramesTx=%u\n"
+			  "dot1xAuthInvalidEapolFramesRx=%u\n"
+			  "dot1xAuthEapLengthErrorFramesRx=%u\n"
+			  "dot1xAuthLastEapolFrameVersion=%u\n"
+			  "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
+			  sm->dot1xAuthEapolFramesRx,
+			  sm->dot1xAuthEapolFramesTx,
+			  sm->dot1xAuthEapolStartFramesRx,
+			  sm->dot1xAuthEapolLogoffFramesRx,
+			  sm->dot1xAuthEapolRespIdFramesRx,
+			  sm->dot1xAuthEapolRespFramesRx,
+			  sm->dot1xAuthEapolReqIdFramesTx,
+			  sm->dot1xAuthEapolReqFramesTx,
+			  sm->dot1xAuthInvalidEapolFramesRx,
+			  sm->dot1xAuthEapLengthErrorFramesRx,
+			  sm->dot1xAuthLastEapolFrameVersion,
+			  MAC2STR(sm->addr));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthDiagTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthEntersConnecting=%u\n"
+			  "dot1xAuthEapLogoffsWhileConnecting=%u\n"
+			  "dot1xAuthEntersAuthenticating=%u\n"
+			  "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthFailWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
+			  "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
+			  "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
+			  "dot1xAuthBackendResponses=%u\n"
+			  "dot1xAuthBackendAccessChallenges=%u\n"
+			  "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
+			  "dot1xAuthBackendAuthSuccesses=%u\n"
+			  "dot1xAuthBackendAuthFails=%u\n",
+			  sm->authEntersConnecting,
+			  sm->authEapLogoffsWhileConnecting,
+			  sm->authEntersAuthenticating,
+			  sm->authAuthSuccessesWhileAuthenticating,
+			  sm->authAuthTimeoutsWhileAuthenticating,
+			  sm->authAuthFailWhileAuthenticating,
+			  sm->authAuthEapStartsWhileAuthenticating,
+			  sm->authAuthEapLogoffWhileAuthenticating,
+			  sm->authAuthReauthsWhileAuthenticated,
+			  sm->authAuthEapStartsWhileAuthenticated,
+			  sm->authAuthEapLogoffWhileAuthenticated,
+			  sm->backendResponses,
+			  sm->backendAccessChallenges,
+			  sm->backendOtherRequestsToSupplicant,
+			  sm->backendAuthSuccesses,
+			  sm->backendAuthFails);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthSessionStatsTable */
+	os_get_time(&t);
+	ret = os_snprintf(buf + len, buflen - len,
+			  /* TODO: dot1xAuthSessionOctetsRx */
+			  /* TODO: dot1xAuthSessionOctetsTx */
+			  /* TODO: dot1xAuthSessionFramesRx */
+			  /* TODO: dot1xAuthSessionFramesTx */
+			  "dot1xAuthSessionId=%08X-%08X\n"
+			  "dot1xAuthSessionAuthenticMethod=%d\n"
+			  "dot1xAuthSessionTime=%u\n"
+			  "dot1xAuthSessionTerminateCause=999\n"
+			  "dot1xAuthSessionUserName=%s\n",
+			  sta->acct_session_id_hi, sta->acct_session_id_lo,
+			  (wpa_key_mgmt_wpa_ieee8021x(
+				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
+			  1 : 2,
+			  (unsigned int) (t.sec - sta->acct_session_start),
+			  sm->identity);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+				struct sta_info *sta, int success)
+{
+	const u8 *key;
+	size_t len;
+	/* TODO: get PMKLifetime from WPA parameters */
+	static const int dot11RSNAConfigPMKLifetime = 43200;
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &len);
+	if (success && key && len >= PMK_LEN &&
+	    wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+			       sta->eapol_sm) == 0) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Added PMKSA cache entry (IEEE 802.1X)");
+	}
+
+	if (!success) {
+		/*
+		 * Many devices require deauthentication after WPS provisioning
+		 * and some may not be be able to do that themselves, so
+		 * disconnect the client here. In addition, this may also
+		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
+		 * the EAPOL PAE state machine would remain in HELD state for
+		 * considerable amount of time and some EAP methods, like
+		 * EAP-FAST with anonymous provisioning, may require another
+		 * EAPOL authentication to be started to complete connection.
+		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+			"disconnection after EAP-Failure");
+		/* Add a small sleep to increase likelihood of previously
+		 * requested EAP-Failure TX getting out before this should the
+		 * driver reorder operations.
+		 */
+		os_sleep(0, 10000);
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+	}
+}

Deleted: vendor/wpa/2.0/src/ap/ieee802_1x.h
===================================================================
--- vendor/wpa/dist/src/ap/ieee802_1x.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/ieee802_1x.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,89 +0,0 @@
-/*
- * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IEEE802_1X_H
-#define IEEE802_1X_H
-
-struct hostapd_data;
-struct sta_info;
-struct eapol_state_machine;
-struct hostapd_config;
-struct hostapd_bss_config;
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-/* RFC 3580, 4. RC4 EAPOL-Key Frame */
-
-struct ieee802_1x_eapol_key {
-	u8 type;
-	u16 key_length;
-	u8 replay_counter[8]; /* does not repeat within the life of the keying
-			       * material used to encrypt the Key field;
-			       * 64-bit NTP timestamp MAY be used here */
-	u8 key_iv[16]; /* cryptographically random number */
-	u8 key_index; /* key flag in the most significant bit:
-		       * 0 = broadcast (default key),
-		       * 1 = unicast (key mapping key); key index is in the
-		       * 7 least significant bits */
-	u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
-			       * MS-MPPE-Send-Key as the key */
-
-	/* followed by key: if packet body length = 44 + key length, then the
-	 * key field (of key_length bytes) contains the key in encrypted form;
-	 * if packet body length = 44, key field is absent and key_length
-	 * represents the number of least significant octets from
-	 * MS-MPPE-Send-Key attribute to be used as the keying material;
-	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-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_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
-				   struct sta_info *sta, int authorized);
-void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
-int ieee802_1x_init(struct hostapd_data *hapd);
-void ieee802_1x_deinit(struct hostapd_data *hapd);
-int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
-			 const u8 *buf, size_t len, int ack);
-u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
-u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
-				 int idx);
-const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
-void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
-				    int enabled);
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
-				  int valid);
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
-int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
-int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-			   char *buf, size_t buflen);
-void hostapd_get_ntp_timestamp(u8 *buf);
-char *eap_type_text(u8 type);
-
-const char *radius_mode_txt(struct hostapd_data *hapd);
-int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
-
-#endif /* IEEE802_1X_H */

Copied: vendor/wpa/2.0/src/ap/ieee802_1x.h (from rev 9639, vendor/wpa/dist/src/ap/ieee802_1x.h)
===================================================================
--- vendor/wpa/2.0/src/ap/ieee802_1x.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/ieee802_1x.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,61 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator
+ * Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_H
+#define IEEE802_1X_H
+
+struct hostapd_data;
+struct sta_info;
+struct eapol_state_machine;
+struct hostapd_config;
+struct hostapd_bss_config;
+struct hostapd_radius_attr;
+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_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized);
+void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
+int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_deinit(struct hostapd_data *hapd);
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 const u8 *buf, size_t len, int ack);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *data, int len, int ack);
+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+				 int idx);
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
+				    int enabled);
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
+				  int valid);
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen);
+void hostapd_get_ntp_timestamp(u8 *buf);
+char *eap_type_text(u8 type);
+
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+int add_common_radius_attr(struct hostapd_data *hapd,
+			   struct hostapd_radius_attr *req_attr,
+			   struct sta_info *sta,
+			   struct radius_msg *msg);
+
+#endif /* IEEE802_1X_H */

Copied: vendor/wpa/2.0/src/ap/p2p_hostapd.c (from rev 9639, vendor/wpa/dist/src/ap/p2p_hostapd.c)
===================================================================
--- vendor/wpa/2.0/src/ap/p2p_hostapd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/p2p_hostapd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,114 @@
+/*
+ * hostapd / P2P integration
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * 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 "p2p/p2p.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "p2p_hostapd.h"
+
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			    char *buf, size_t buflen)
+{
+	if (sta->p2p_ie == NULL)
+		return 0;
+
+	return p2p_ie_text(sta->p2p_ie, buf, buf + buflen);
+}
+
+
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			int duration)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d "
+		   "duration=%d", count, start, duration);
+
+	if (count == 0) {
+		hapd->noa_enabled = 0;
+		hapd->noa_start = 0;
+		hapd->noa_duration = 0;
+	}
+
+	if (count != 255) {
+		wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set "
+			   "NoA parameters");
+		return hostapd_driver_set_noa(hapd, count, start, duration);
+	}
+
+	hapd->noa_enabled = 1;
+	hapd->noa_start = start;
+	hapd->noa_duration = duration;
+
+	if (hapd->num_sta_no_p2p == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update "
+			   "periodic NoA parameters");
+		return hostapd_driver_set_noa(hapd, count, start, duration);
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable "
+		   "periodic NoA");
+
+	return 0;
+}
+
+
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected");
+
+	if (hapd->noa_enabled) {
+		wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA");
+		hostapd_driver_set_noa(hapd, 0, 0, 0);
+	}
+}
+
+
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected");
+
+	if (hapd->noa_enabled) {
+		wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA");
+		hostapd_driver_set_noa(hapd, 255, hapd->noa_start,
+				       hapd->noa_duration);
+	}
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_P2P_MANAGER
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 bitmap;
+	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
+	*eid++ = 4 + 3 + 1;
+	WPA_PUT_BE24(eid, OUI_WFA);
+	eid += 3;
+	*eid++ = P2P_OUI_TYPE;
+
+	*eid++ = P2P_ATTR_MANAGEABILITY;
+	WPA_PUT_LE16(eid, 1);
+	eid += 2;
+	bitmap = P2P_MAN_DEVICE_MANAGEMENT;
+	if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
+		bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
+	bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
+	*eid++ = bitmap;
+
+	return eid;
+}
+#endif /* CONFIG_P2P_MANAGER */

Copied: vendor/wpa/2.0/src/ap/p2p_hostapd.h (from rev 9639, vendor/wpa/dist/src/ap/p2p_hostapd.h)
===================================================================
--- vendor/wpa/2.0/src/ap/p2p_hostapd.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/p2p_hostapd.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,35 @@
+/*
+ * hostapd / P2P integration
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef P2P_HOSTAPD_H
+#define P2P_HOSTAPD_H
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			    char *buf, size_t buflen);
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			int duration);
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd);
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd);
+
+
+#else /* CONFIG_P2P */
+
+static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  char *buf, size_t buflen)
+{
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* P2P_HOSTAPD_H */

Deleted: vendor/wpa/2.0/src/ap/peerkey_auth.c
===================================================================
--- vendor/wpa/dist/src/ap/peerkey_auth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/peerkey_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,401 +0,0 @@
-/*
- * hostapd - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "wpa_auth.h"
-#include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
-
-#ifdef CONFIG_PEERKEY
-
-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_stsl_negotiation *neg = timeout_ctx;
-#endif
-
-	/* TODO: ? */
-}
-
-
-struct wpa_stsl_search {
-	const u8 *addr;
-	struct wpa_state_machine *sm;
-};
-
-
-static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
-{
-	struct wpa_stsl_search *search = ctx;
-	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
-		search->sm = sm;
-		return 1;
-	}
-	return 0;
-}
-
-
-static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
-			       struct wpa_state_machine *sm, const u8 *peer,
-			       u16 mui, u16 error_type)
-{
-	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
-	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
-	u8 *pos;
-	struct rsn_error_kde error;
-
-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-			"Sending SMK Error");
-
-	pos = kde;
-
-	if (peer) {
-		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
-				  NULL, 0);
-	}
-
-	error.mui = host_to_be16(mui);
-	error.error_type = host_to_be16(error_type);
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
-			  (u8 *) &error, sizeof(error), NULL, 0);
-
-	__wpa_send_eapol(wpa_auth, sm,
-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
-			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
-			 NULL, NULL, kde, pos - kde, 0, 0, 0);
-}
-
-
-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
-{
-	struct wpa_eapol_ie_parse kde;
-	struct wpa_stsl_search search;
-	u8 *buf, *pos;
-	size_t buf_len;
-
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
-		return;
-	}
-
-	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
-	    kde.mac_addr_len < ETH_ALEN) {
-		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
-			   "SMK M1");
-		return;
-	}
-
-	/* Initiator = sm->addr; Peer = kde.mac_addr */
-
-	search.addr = kde.mac_addr;
-	search.sm = NULL;
-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
-	    0 || search.sm == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
-			   " aborted - STA not associated anymore",
-			   MAC2STR(kde.mac_addr));
-		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
-				   STK_ERR_STA_NR);
-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
-		return;
-	}
-
-	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
-	buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return;
-	/* Initiator RSN IE */
-	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
-	pos = buf + kde.rsn_ie_len;
-	/* Initiator MAC Address */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
-			  NULL, 0);
-
-	/* SMK M2:
-	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
-	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
-	 */
-
-	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
-			"Sending SMK M2");
-
-	__wpa_send_eapol(wpa_auth, search.sm,
-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
-			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
-			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
-
-	os_free(buf);
-}
-
-
-static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
-			    struct wpa_state_machine *sm,
-			    struct wpa_eapol_key *key,
-			    struct wpa_eapol_ie_parse *kde,
-			    const u8 *smk)
-{
-	u8 *buf, *pos;
-	size_t buf_len;
-	u32 lifetime;
-
-	/* SMK M4:
-	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
-	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
-	 *           Lifetime KDE)
-	 */
-
-	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
-		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
-	pos = buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return;
-
-	/* Initiator MAC Address */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
-			  NULL, 0);
-
-	/* Initiator Nonce */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
-			  NULL, 0);
-
-	/* SMK with PNonce */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
-			  key->key_nonce, WPA_NONCE_LEN);
-
-	/* Lifetime */
-	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
-			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
-
-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			"Sending SMK M4");
-
-	__wpa_send_eapol(wpa_auth, sm,
-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
-			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
-			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
-
-	os_free(buf);
-}
-
-
-static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
-			    struct wpa_state_machine *sm,
-			    struct wpa_eapol_key *key,
-			    struct wpa_eapol_ie_parse *kde,
-			    const u8 *smk, const u8 *peer)
-{
-	u8 *buf, *pos;
-	size_t buf_len;
-	u32 lifetime;
-
-	/* SMK M5:
-	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
-	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
-	 *                             Lifetime KDE))
-	 */
-
-	buf_len = kde->rsn_ie_len +
-		2 + RSN_SELECTOR_LEN + ETH_ALEN +
-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
-		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
-	pos = buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return;
-
-	/* Peer RSN IE */
-	os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
-	pos = buf + kde->rsn_ie_len;
-
-	/* Peer MAC Address */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
-
-	/* PNonce */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
-			  WPA_NONCE_LEN, NULL, 0);
-
-	/* SMK and INonce */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
-			  kde->nonce, WPA_NONCE_LEN);
-
-	/* Lifetime */
-	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
-			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
-
-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			"Sending SMK M5");
-
-	__wpa_send_eapol(wpa_auth, sm,
-			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
-			 WPA_KEY_INFO_SMK_MESSAGE,
-			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
-
-	os_free(buf);
-}
-
-
-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
-{
-	struct wpa_eapol_ie_parse kde;
-	struct wpa_stsl_search search;
-	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
-
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
-		return;
-	}
-
-	if (kde.rsn_ie == NULL ||
-	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
-	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
-		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
-			   "Nonce KDE in SMK M3");
-		return;
-	}
-
-	/* Peer = sm->addr; Initiator = kde.mac_addr;
-	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
-
-	search.addr = kde.mac_addr;
-	search.sm = NULL;
-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
-	    0 || search.sm == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
-			   " aborted - STA not associated anymore",
-			   MAC2STR(kde.mac_addr));
-		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
-				   STK_ERR_STA_NR);
-		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
-		return;
-	}
-
-	if (os_get_random(smk, PMK_LEN)) {
-		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
-		return;
-	}
-
-	/* SMK = PRF-256(Random number, "SMK Derivation",
-	 *               AA || Time || INonce || PNonce)
-	 */
-	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
-	pos = buf + ETH_ALEN;
-	wpa_get_ntp_timestamp(pos);
-	pos += 8;
-	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
-	pos += WPA_NONCE_LEN;
-	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
-#ifdef CONFIG_IEEE80211W
-	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
-		   smk, PMK_LEN);
-#else /* CONFIG_IEEE80211W */
-	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
-		 smk, PMK_LEN);
-#endif /* CONFIG_IEEE80211W */
-
-	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
-
-	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
-	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
-
-	/* Authenticator does not need SMK anymore and it is required to forget
-	 * it. */
-	os_memset(smk, 0, sizeof(*smk));
-}
-
-
-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
-		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
-{
-	struct wpa_eapol_ie_parse kde;
-	struct wpa_stsl_search search;
-	struct rsn_error_kde error;
-	u16 mui, error_type;
-
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
-		return;
-	}
-
-	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
-	    kde.error == NULL || kde.error_len < sizeof(error)) {
-		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
-			   "SMK Error");
-		return;
-	}
-
-	search.addr = kde.mac_addr;
-	search.sm = NULL;
-	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
-	    0 || search.sm == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
-			   "associated for SMK Error message from " MACSTR,
-			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
-		return;
-	}
-
-	os_memcpy(&error, kde.error, sizeof(error));
-	mui = be_to_host16(error.mui);
-	error_type = be_to_host16(error.error_type);
-	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-			 "STA reported SMK Error: Peer " MACSTR
-			 " MUI %d Error Type %d",
-			 MAC2STR(kde.mac_addr), mui, error_type);
-
-	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
-}
-
-
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
-		    struct wpa_stsl_negotiation *neg)
-{
-	struct wpa_stsl_negotiation *pos, *prev;
-
-	if (wpa_auth == NULL)
-		return -1;
-	pos = wpa_auth->stsl_negotiations;
-	prev = NULL;
-	while (pos) {
-		if (pos == neg) {
-			if (prev)
-				prev->next = pos->next;
-			else
-				wpa_auth->stsl_negotiations = pos->next;
-
-			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
-			os_free(pos);
-			return 0;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-
-	return -1;
-}
-
-#endif /* CONFIG_PEERKEY */

Copied: vendor/wpa/2.0/src/ap/peerkey_auth.c (from rev 9639, vendor/wpa/dist/src/ap/peerkey_auth.c)
===================================================================
--- vendor/wpa/2.0/src/ap/peerkey_auth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/peerkey_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,396 @@
+/*
+ * hostapd - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "wpa_auth.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+#ifdef CONFIG_PEERKEY
+
+static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_stsl_negotiation *neg = timeout_ctx;
+#endif
+
+	/* TODO: ? */
+}
+
+
+struct wpa_stsl_search {
+	const u8 *addr;
+	struct wpa_state_machine *sm;
+};
+
+
+static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
+{
+	struct wpa_stsl_search *search = ctx;
+	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
+		search->sm = sm;
+		return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
+			       struct wpa_state_machine *sm, const u8 *peer,
+			       u16 mui, u16 error_type)
+{
+	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
+	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
+	u8 *pos;
+	struct rsn_error_kde error;
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK Error");
+
+	pos = kde;
+
+	if (peer) {
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
+				  NULL, 0);
+	}
+
+	error.mui = host_to_be16(mui);
+	error.error_type = host_to_be16(error_type);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
+			  (u8 *) &error, sizeof(error), NULL, 0);
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
+			 NULL, NULL, kde, pos - kde, 0, 0, 0);
+}
+
+
+void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+	    kde.mac_addr_len < ETH_ALEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+			   "SMK M1");
+		return;
+	}
+
+	/* Initiator = sm->addr; Peer = kde.mac_addr */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+	/* Initiator RSN IE */
+	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
+	pos = buf + kde.rsn_ie_len;
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* SMK M2:
+	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
+	 */
+
+	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
+			"Sending SMK M2");
+
+	__wpa_send_eapol(wpa_auth, search.sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
+
+	os_free(buf);
+}
+
+
+static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M4:
+	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
+	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
+	 *           Lifetime KDE)
+	 */
+
+	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* Initiator Nonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
+			  NULL, 0);
+
+	/* SMK with PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
+			  key->key_nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M4");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
+
+	os_free(buf);
+}
+
+
+static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk, const u8 *peer)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M5:
+	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
+	 *                             Lifetime KDE))
+	 */
+
+	buf_len = kde->rsn_ie_len +
+		2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Peer RSN IE */
+	os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
+	pos = buf + kde->rsn_ie_len;
+
+	/* Peer MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
+
+	/* PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
+			  WPA_NONCE_LEN, NULL, 0);
+
+	/* SMK and INonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
+			  kde->nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M5");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
+
+	os_free(buf);
+}
+
+
+void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL ||
+	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
+			   "Nonce KDE in SMK M3");
+		return;
+	}
+
+	/* Peer = sm->addr; Initiator = kde.mac_addr;
+	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	if (random_get_bytes(smk, PMK_LEN)) {
+		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
+		return;
+	}
+
+	/* SMK = PRF-256(Random number, "SMK Derivation",
+	 *               AA || Time || INonce || PNonce)
+	 */
+	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	pos = buf + ETH_ALEN;
+	wpa_get_ntp_timestamp(pos);
+	pos += 8;
+	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
+#ifdef CONFIG_IEEE80211W
+	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		   smk, PMK_LEN);
+#else /* CONFIG_IEEE80211W */
+	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		 smk, PMK_LEN);
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
+
+	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
+	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
+
+	/* Authenticator does not need SMK anymore and it is required to forget
+	 * it. */
+	os_memset(smk, 0, sizeof(*smk));
+}
+
+
+void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	struct rsn_error_kde error;
+	u16 mui, error_type;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+		return;
+	}
+
+	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.error == NULL || kde.error_len < sizeof(error)) {
+		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
+			   "SMK Error");
+		return;
+	}
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
+			   "associated for SMK Error message from " MACSTR,
+			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
+		return;
+	}
+
+	os_memcpy(&error, kde.error, sizeof(error));
+	mui = be_to_host16(error.mui);
+	error_type = be_to_host16(error.error_type);
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "STA reported SMK Error: Peer " MACSTR
+			 " MUI %d Error Type %d",
+			 MAC2STR(kde.mac_addr), mui, error_type);
+
+	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
+}
+
+
+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+		    struct wpa_stsl_negotiation *neg)
+{
+	struct wpa_stsl_negotiation *pos, *prev;
+
+	if (wpa_auth == NULL)
+		return -1;
+	pos = wpa_auth->stsl_negotiations;
+	prev = NULL;
+	while (pos) {
+		if (pos == neg) {
+			if (prev)
+				prev->next = pos->next;
+			else
+				wpa_auth->stsl_negotiations = pos->next;
+
+			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
+			os_free(pos);
+			return 0;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	return -1;
+}
+
+#endif /* CONFIG_PEERKEY */

Deleted: vendor/wpa/2.0/src/ap/pmksa_cache_auth.c
===================================================================
--- vendor/wpa/dist/src/ap/pmksa_cache_auth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/pmksa_cache_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,425 +0,0 @@
-/*
- * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "sta_info.h"
-#include "ap_config.h"
-#include "pmksa_cache_auth.h"
-
-
-static const int pmksa_cache_max_entries = 1024;
-static const int dot11RSNAConfigPMKLifetime = 43200;
-
-struct rsn_pmksa_cache {
-#define PMKID_HASH_SIZE 128
-#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
-	struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
-	struct rsn_pmksa_cache_entry *pmksa;
-	int pmksa_count;
-
-	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
-	void *ctx;
-};
-
-
-static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
-
-
-static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
-{
-	if (entry == NULL)
-		return;
-	os_free(entry->identity);
-#ifndef CONFIG_NO_RADIUS
-	radius_free_class(&entry->radius_class);
-#endif /* CONFIG_NO_RADIUS */
-	os_free(entry);
-}
-
-
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
-				   struct rsn_pmksa_cache_entry *entry)
-{
-	struct rsn_pmksa_cache_entry *pos, *prev;
-
-	pmksa->pmksa_count--;
-	pmksa->free_cb(entry, pmksa->ctx);
-	pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
-	prev = NULL;
-	while (pos) {
-		if (pos == entry) {
-			if (prev != NULL) {
-				prev->hnext = pos->hnext;
-			} else {
-				pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
-					pos->hnext;
-			}
-			break;
-		}
-		prev = pos;
-		pos = pos->hnext;
-	}
-
-	pos = pmksa->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (pos == entry) {
-			if (prev != NULL)
-				prev->next = pos->next;
-			else
-				pmksa->pmksa = pos->next;
-			break;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-	_pmksa_cache_free_entry(entry);
-}
-
-
-static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
-{
-	struct rsn_pmksa_cache *pmksa = eloop_ctx;
-	struct os_time now;
-
-	os_get_time(&now);
-	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
-		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-		pmksa->pmksa = entry->next;
-		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
-			   MACSTR, MAC2STR(entry->spa));
-		pmksa_cache_free_entry(pmksa, entry);
-	}
-
-	pmksa_cache_set_expiration(pmksa);
-}
-
-
-static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
-{
-	int sec;
-	struct os_time now;
-
-	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
-	if (pmksa->pmksa == NULL)
-		return;
-	os_get_time(&now);
-	sec = pmksa->pmksa->expiration - now.sec;
-	if (sec < 0)
-		sec = 0;
-	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
-}
-
-
-static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
-					struct eapol_state_machine *eapol)
-{
-	if (eapol == NULL)
-		return;
-
-	if (eapol->identity) {
-		entry->identity = os_malloc(eapol->identity_len);
-		if (entry->identity) {
-			entry->identity_len = eapol->identity_len;
-			os_memcpy(entry->identity, eapol->identity,
-				  eapol->identity_len);
-		}
-	}
-
-#ifndef CONFIG_NO_RADIUS
-	radius_copy_class(&entry->radius_class, &eapol->radius_class);
-#endif /* CONFIG_NO_RADIUS */
-
-	entry->eap_type_authsrv = eapol->eap_type_authsrv;
-	entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
-}
-
-
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
-			       struct eapol_state_machine *eapol)
-{
-	if (entry == NULL || eapol == NULL)
-		return;
-
-	if (entry->identity) {
-		os_free(eapol->identity);
-		eapol->identity = os_malloc(entry->identity_len);
-		if (eapol->identity) {
-			eapol->identity_len = entry->identity_len;
-			os_memcpy(eapol->identity, entry->identity,
-				  entry->identity_len);
-		}
-		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
-				  eapol->identity, eapol->identity_len);
-	}
-
-#ifndef CONFIG_NO_RADIUS
-	radius_free_class(&eapol->radius_class);
-	radius_copy_class(&eapol->radius_class, &entry->radius_class);
-#endif /* CONFIG_NO_RADIUS */
-	if (eapol->radius_class.attr) {
-		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
-			   "PMKSA", (unsigned long) eapol->radius_class.count);
-	}
-
-	eapol->eap_type_authsrv = entry->eap_type_authsrv;
-	((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
-}
-
-
-static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
-				   struct rsn_pmksa_cache_entry *entry)
-{
-	struct rsn_pmksa_cache_entry *pos, *prev;
-
-	/* Add the new entry; order by expiration time */
-	pos = pmksa->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (pos->expiration > entry->expiration)
-			break;
-		prev = pos;
-		pos = pos->next;
-	}
-	if (prev == NULL) {
-		entry->next = pmksa->pmksa;
-		pmksa->pmksa = entry;
-	} else {
-		entry->next = prev->next;
-		prev->next = entry;
-	}
-	entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
-	pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
-
-	pmksa->pmksa_count++;
-	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
-		   MAC2STR(entry->spa));
-	wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
-}
-
-
-/**
- * pmksa_cache_auth_add - Add a PMKSA cache entry
- * @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)
- * @aa: Authenticator address
- * @spa: Supplicant address
- * @session_timeout: Session timeout
- * @eapol: Pointer to EAPOL state machine data
- * @akmp: WPA_KEY_MGMT_* used in key derivation
- * Returns: Pointer to the added PMKSA cache entry or %NULL on error
- *
- * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
- * cache. If an old entry is already in the cache for the same Supplicant,
- * this entry will be replaced with the new entry. PMKID will be calculated
- * based on the PMK.
- */
-struct rsn_pmksa_cache_entry *
-pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
-		     const u8 *pmk, size_t pmk_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_time now;
-
-	if (pmk_len > PMK_LEN)
-		return NULL;
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL)
-		return NULL;
-	os_memcpy(entry->pmk, pmk, pmk_len);
-	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
-		  wpa_key_mgmt_sha256(akmp));
-	os_get_time(&now);
-	entry->expiration = now.sec;
-	if (session_timeout > 0)
-		entry->expiration += session_timeout;
-	else
-		entry->expiration += dot11RSNAConfigPMKLifetime;
-	entry->akmp = akmp;
-	os_memcpy(entry->spa, spa, ETH_ALEN);
-	pmksa_cache_from_eapol_data(entry, eapol);
-
-	/* Replace an old entry for the same STA (if found) with the new entry
-	 */
-	pos = pmksa_cache_auth_get(pmksa, spa, NULL);
-	if (pos)
-		pmksa_cache_free_entry(pmksa, pos);
-
-	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
-		/* Remove the oldest entry to make room for the new entry */
-		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
-			   "entry (for " MACSTR ") to make room for new one",
-			   MAC2STR(pmksa->pmksa->spa));
-		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
-	}
-
-	pmksa_cache_link_entry(pmksa, entry);
-
-	return entry;
-}
-
-
-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)
-{
-	struct rsn_pmksa_cache_entry *entry;
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL)
-		return NULL;
-	os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
-	os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
-	entry->pmk_len = old_entry->pmk_len;
-	entry->expiration = old_entry->expiration;
-	entry->akmp = old_entry->akmp;
-	os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
-	entry->opportunistic = 1;
-	if (old_entry->identity) {
-		entry->identity = os_malloc(old_entry->identity_len);
-		if (entry->identity) {
-			entry->identity_len = old_entry->identity_len;
-			os_memcpy(entry->identity, old_entry->identity,
-				  old_entry->identity_len);
-		}
-	}
-#ifndef CONFIG_NO_RADIUS
-	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;
-	entry->opportunistic = 1;
-
-	pmksa_cache_link_entry(pmksa, entry);
-
-	return entry;
-}
-
-
-/**
- * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
- */
-void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
-{
-	struct rsn_pmksa_cache_entry *entry, *prev;
-	int i;
-
-	if (pmksa == NULL)
-		return;
-
-	entry = pmksa->pmksa;
-	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		_pmksa_cache_free_entry(prev);
-	}
-	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
-	for (i = 0; i < PMKID_HASH_SIZE; i++)
-		pmksa->pmkid[i] = NULL;
-	os_free(pmksa);
-}
-
-
-/**
- * pmksa_cache_auth_get - Fetch a PMKSA cache entry
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
- * @spa: Supplicant address or %NULL to match any
- * @pmkid: PMKID or %NULL to match any
- * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
- */
-struct rsn_pmksa_cache_entry *
-pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
-		     const u8 *spa, const u8 *pmkid)
-{
-	struct rsn_pmksa_cache_entry *entry;
-
-	if (pmkid)
-		entry = pmksa->pmkid[PMKID_HASH(pmkid)];
-	else
-		entry = pmksa->pmksa;
-	while (entry) {
-		if ((spa == NULL ||
-		     os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
-		    (pmkid == NULL ||
-		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
-			return entry;
-		entry = pmkid ? entry->hnext : entry->next;
-	}
-	return NULL;
-}
-
-
-/**
- * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
- * @aa: Authenticator address
- * @spa: Supplicant address
- * @pmkid: PMKID
- * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
- *
- * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
- */
-struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
-	struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
-	const u8 *pmkid)
-{
-	struct rsn_pmksa_cache_entry *entry;
-	u8 new_pmkid[PMKID_LEN];
-
-	entry = pmksa->pmksa;
-	while (entry) {
-		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
-			continue;
-		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
-			  wpa_key_mgmt_sha256(entry->akmp));
-		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
-			return entry;
-		entry = entry->next;
-	}
-	return NULL;
-}
-
-
-/**
- * pmksa_cache_auth_init - Initialize PMKSA cache
- * @free_cb: Callback function to be called when a PMKSA cache entry is freed
- * @ctx: Context pointer for free_cb function
- * Returns: Pointer to PMKSA cache data or %NULL on failure
- */
-struct rsn_pmksa_cache *
-pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				      void *ctx), void *ctx)
-{
-	struct rsn_pmksa_cache *pmksa;
-
-	pmksa = os_zalloc(sizeof(*pmksa));
-	if (pmksa) {
-		pmksa->free_cb = free_cb;
-		pmksa->ctx = ctx;
-	}
-
-	return pmksa;
-}

Copied: vendor/wpa/2.0/src/ap/pmksa_cache_auth.c (from rev 9639, vendor/wpa/dist/src/ap/pmksa_cache_auth.c)
===================================================================
--- vendor/wpa/2.0/src/ap/pmksa_cache_auth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/pmksa_cache_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,430 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "pmksa_cache_auth.h"
+
+
+static const int pmksa_cache_max_entries = 1024;
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_pmksa_cache {
+#define PMKID_HASH_SIZE 128
+#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
+	struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
+	struct rsn_pmksa_cache_entry *pmksa;
+	int pmksa_count;
+
+	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
+	void *ctx;
+};
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+	if (entry == NULL)
+		return;
+	os_free(entry->identity);
+	wpabuf_free(entry->cui);
+#ifndef CONFIG_NO_RADIUS
+	radius_free_class(&entry->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+	os_free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
+	pmksa->pmksa_count--;
+	pmksa->free_cb(entry, pmksa->ctx);
+	pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL) {
+				prev->hnext = pos->hnext;
+			} else {
+				pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
+					pos->hnext;
+			}
+			break;
+		}
+		prev = pos;
+		pos = pos->hnext;
+	}
+
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL)
+				prev->next = pos->next;
+			else
+				pmksa->pmksa = pos->next;
+			break;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+	_pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+			   MACSTR, MAC2STR(pmksa->pmksa->spa));
+		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+	}
+
+	pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+	int sec;
+	struct os_time now;
+
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	if (pmksa->pmksa == NULL)
+		return;
+	os_get_time(&now);
+	sec = pmksa->pmksa->expiration - now.sec;
+	if (sec < 0)
+		sec = 0;
+	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+}
+
+
+static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
+					struct eapol_state_machine *eapol)
+{
+	if (eapol == NULL)
+		return;
+
+	if (eapol->identity) {
+		entry->identity = os_malloc(eapol->identity_len);
+		if (entry->identity) {
+			entry->identity_len = eapol->identity_len;
+			os_memcpy(entry->identity, eapol->identity,
+				  eapol->identity_len);
+		}
+	}
+
+	if (eapol->radius_cui)
+		entry->cui = wpabuf_dup(eapol->radius_cui);
+
+#ifndef CONFIG_NO_RADIUS
+	radius_copy_class(&entry->radius_class, &eapol->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+
+	entry->eap_type_authsrv = eapol->eap_type_authsrv;
+	entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
+}
+
+
+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+			       struct eapol_state_machine *eapol)
+{
+	if (entry == NULL || eapol == NULL)
+		return;
+
+	if (entry->identity) {
+		os_free(eapol->identity);
+		eapol->identity = os_malloc(entry->identity_len);
+		if (eapol->identity) {
+			eapol->identity_len = entry->identity_len;
+			os_memcpy(eapol->identity, entry->identity,
+				  entry->identity_len);
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
+				  eapol->identity, eapol->identity_len);
+	}
+
+	if (entry->cui) {
+		wpabuf_free(eapol->radius_cui);
+		eapol->radius_cui = wpabuf_dup(entry->cui);
+	}
+
+#ifndef CONFIG_NO_RADIUS
+	radius_free_class(&eapol->radius_class);
+	radius_copy_class(&eapol->radius_class, &entry->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+	if (eapol->radius_class.attr) {
+		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
+			   "PMKSA", (unsigned long) eapol->radius_class.count);
+	}
+
+	eapol->eap_type_authsrv = entry->eap_type_authsrv;
+	((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+}
+
+
+static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
+	/* Add the new entry; order by expiration time */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos->expiration > entry->expiration)
+			break;
+		prev = pos;
+		pos = pos->next;
+	}
+	if (prev == NULL) {
+		entry->next = pmksa->pmksa;
+		pmksa->pmksa = entry;
+	} else {
+		entry->next = prev->next;
+		prev->next = entry;
+	}
+	entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
+
+	pmksa->pmksa_count++;
+	if (prev == NULL)
+		pmksa_cache_set_expiration(pmksa);
+	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
+		   MAC2STR(entry->spa));
+	wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
+}
+
+
+/**
+ * pmksa_cache_auth_add - Add a PMKSA cache entry
+ * @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)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Supplicant,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
+		     const u8 *pmk, size_t pmk_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_time now;
+
+	if (pmk_len > PMK_LEN)
+		return NULL;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmk, pmk, pmk_len);
+	entry->pmk_len = pmk_len;
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
+	os_get_time(&now);
+	entry->expiration = now.sec;
+	if (session_timeout > 0)
+		entry->expiration += session_timeout;
+	else
+		entry->expiration += dot11RSNAConfigPMKLifetime;
+	entry->akmp = akmp;
+	os_memcpy(entry->spa, spa, ETH_ALEN);
+	pmksa_cache_from_eapol_data(entry, eapol);
+
+	/* Replace an old entry for the same STA (if found) with the new entry
+	 */
+	pos = pmksa_cache_auth_get(pmksa, spa, NULL);
+	if (pos)
+		pmksa_cache_free_entry(pmksa, pos);
+
+	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+		/* Remove the oldest entry to make room for the new entry */
+		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
+			   "entry (for " MACSTR ") to make room for new one",
+			   MAC2STR(pmksa->pmksa->spa));
+		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+	}
+
+	pmksa_cache_link_entry(pmksa, entry);
+
+	return entry;
+}
+
+
+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)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+	os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
+	entry->pmk_len = old_entry->pmk_len;
+	entry->expiration = old_entry->expiration;
+	entry->akmp = old_entry->akmp;
+	os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
+	entry->opportunistic = 1;
+	if (old_entry->identity) {
+		entry->identity = os_malloc(old_entry->identity_len);
+		if (entry->identity) {
+			entry->identity_len = old_entry->identity_len;
+			os_memcpy(entry->identity, old_entry->identity,
+				  old_entry->identity_len);
+		}
+	}
+	if (old_entry->cui)
+		entry->cui = wpabuf_dup(old_entry->cui);
+#ifndef CONFIG_NO_RADIUS
+	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;
+	entry->opportunistic = 1;
+
+	pmksa_cache_link_entry(pmksa, entry);
+
+	return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev;
+	int i;
+
+	if (pmksa == NULL)
+		return;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		prev = entry;
+		entry = entry->next;
+		_pmksa_cache_free_entry(prev);
+	}
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	for (i = 0; i < PMKID_HASH_SIZE; i++)
+		pmksa->pmkid[i] = NULL;
+	os_free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_auth_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @spa: Supplicant address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
+		     const u8 *spa, const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	if (pmkid)
+		entry = pmksa->pmkid[PMKID_HASH(pmkid)];
+	else
+		entry = pmksa->pmksa;
+	while (entry) {
+		if ((spa == NULL ||
+		     os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
+		    (pmkid == NULL ||
+		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
+			return entry;
+		entry = pmkid ? entry->hnext : entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: PMKID
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ *
+ * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
+	struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
+	const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+	u8 new_pmkid[PMKID_LEN];
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
+			continue;
+		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
+			  wpa_key_mgmt_sha256(entry->akmp));
+		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
+			return entry;
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_auth_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				      void *ctx), void *ctx)
+{
+	struct rsn_pmksa_cache *pmksa;
+
+	pmksa = os_zalloc(sizeof(*pmksa));
+	if (pmksa) {
+		pmksa->free_cb = free_cb;
+		pmksa->ctx = ctx;
+	}
+
+	return pmksa;
+}

Deleted: vendor/wpa/2.0/src/ap/pmksa_cache_auth.h
===================================================================
--- vendor/wpa/dist/src/ap/pmksa_cache_auth.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/pmksa_cache_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,64 +0,0 @@
-/*
- * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PMKSA_CACHE_H
-#define PMKSA_CACHE_H
-
-#include "radius/radius.h"
-
-/**
- * struct rsn_pmksa_cache_entry - PMKSA cache entry
- */
-struct rsn_pmksa_cache_entry {
-	struct rsn_pmksa_cache_entry *next, *hnext;
-	u8 pmkid[PMKID_LEN];
-	u8 pmk[PMK_LEN];
-	size_t pmk_len;
-	os_time_t expiration;
-	int akmp; /* WPA_KEY_MGMT_* */
-	u8 spa[ETH_ALEN];
-
-	u8 *identity;
-	size_t identity_len;
-	struct radius_class_data radius_class;
-	u8 eap_type_authsrv;
-	int vlan_id;
-	int opportunistic;
-};
-
-struct rsn_pmksa_cache;
-
-struct rsn_pmksa_cache *
-pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				      void *ctx), void *ctx);
-void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa);
-struct rsn_pmksa_cache_entry *
-pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
-		     const u8 *spa, const u8 *pmkid);
-struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
-	struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
-	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 *aa, const u8 *spa, int session_timeout,
-		     struct eapol_state_machine *eapol, int akmp);
-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,
-			       struct eapol_state_machine *eapol);
-
-#endif /* PMKSA_CACHE_H */

Copied: vendor/wpa/2.0/src/ap/pmksa_cache_auth.h (from rev 9639, vendor/wpa/dist/src/ap/pmksa_cache_auth.h)
===================================================================
--- vendor/wpa/2.0/src/ap/pmksa_cache_auth.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/pmksa_cache_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,59 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+#include "radius/radius.h"
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+	struct rsn_pmksa_cache_entry *next, *hnext;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	os_time_t expiration;
+	int akmp; /* WPA_KEY_MGMT_* */
+	u8 spa[ETH_ALEN];
+
+	u8 *identity;
+	size_t identity_len;
+	struct wpabuf *cui;
+	struct radius_class_data radius_class;
+	u8 eap_type_authsrv;
+	int vlan_id;
+	int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+struct rsn_pmksa_cache *
+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				      void *ctx), void *ctx);
+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
+		     const u8 *spa, const u8 *pmkid);
+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
+	struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
+	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 *aa, const u8 *spa, int session_timeout,
+		     struct eapol_state_machine *eapol, int akmp);
+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,
+			       struct eapol_state_machine *eapol);
+
+#endif /* PMKSA_CACHE_H */

Deleted: vendor/wpa/2.0/src/ap/preauth_auth.c
===================================================================
--- vendor/wpa/dist/src/ap/preauth_auth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/preauth_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,279 +0,0 @@
-/*
- * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#ifdef CONFIG_RSN_PREAUTH
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "l2_packet/l2_packet.h"
-#include "common/wpa_common.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "ieee802_1x.h"
-#include "sta_info.h"
-#include "wpa_auth.h"
-#include "preauth_auth.h"
-
-#ifndef ETH_P_PREAUTH
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-#endif /* ETH_P_PREAUTH */
-
-static const int dot11RSNAConfigPMKLifetime = 43200;
-
-struct rsn_preauth_interface {
-	struct rsn_preauth_interface *next;
-	struct hostapd_data *hapd;
-	struct l2_packet_data *l2;
-	char *ifname;
-	int ifindex;
-};
-
-
-static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
-				const u8 *buf, size_t len)
-{
-	struct rsn_preauth_interface *piface = ctx;
-	struct hostapd_data *hapd = piface->hapd;
-	struct ieee802_1x_hdr *hdr;
-	struct sta_info *sta;
-	struct l2_ethhdr *ethhdr;
-
-	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
-		   "from interface '%s'", piface->ifname);
-	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
-		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
-			   "(len=%lu)", (unsigned long) len);
-		return;
-	}
-
-	ethhdr = (struct l2_ethhdr *) buf;
-	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
-
-	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
-			   MACSTR, MAC2STR(ethhdr->h_dest));
-		return;
-	}
-
-	sta = ap_get_sta(hapd, ethhdr->h_source);
-	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
-			   "STA " MACSTR, MAC2STR(sta->addr));
-		return;
-	}
-	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
-		sta = ap_sta_add(hapd, ethhdr->h_source);
-		if (sta == NULL)
-			return;
-		sta->flags = WLAN_STA_PREAUTH;
-
-		ieee802_1x_new_station(hapd, sta);
-		if (sta->eapol_sm == NULL) {
-			ap_free_sta(hapd, sta);
-			sta = NULL;
-		} else {
-			sta->eapol_sm->radius_identifier = -1;
-			sta->eapol_sm->portValid = TRUE;
-			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
-		}
-	}
-	if (sta == NULL)
-		return;
-	sta->preauth_iface = piface;
-	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
-			   len - sizeof(*ethhdr));
-}
-
-
-static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
-{
-	struct rsn_preauth_interface *piface;
-
-	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
-
-	piface = os_zalloc(sizeof(*piface));
-	if (piface == NULL)
-		return -1;
-	piface->hapd = hapd;
-
-	piface->ifname = os_strdup(ifname);
-	if (piface->ifname == NULL) {
-		goto fail1;
-	}
-
-	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
-				    rsn_preauth_receive, piface, 1);
-	if (piface->l2 == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
-			   "to ETH_P_PREAUTH");
-		goto fail2;
-	}
-
-	piface->next = hapd->preauth_iface;
-	hapd->preauth_iface = piface;
-	return 0;
-
-fail2:
-	os_free(piface->ifname);
-fail1:
-	os_free(piface);
-	return -1;
-}
-
-
-void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
-{
-	struct rsn_preauth_interface *piface, *prev;
-
-	piface = hapd->preauth_iface;
-	hapd->preauth_iface = NULL;
-	while (piface) {
-		prev = piface;
-		piface = piface->next;
-		l2_packet_deinit(prev->l2);
-		os_free(prev->ifname);
-		os_free(prev);
-	}
-}
-
-
-int rsn_preauth_iface_init(struct hostapd_data *hapd)
-{
-	char *tmp, *start, *end;
-
-	if (hapd->conf->rsn_preauth_interfaces == NULL)
-		return 0;
-
-	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
-	if (tmp == NULL)
-		return -1;
-	start = tmp;
-	for (;;) {
-		while (*start == ' ')
-			start++;
-		if (*start == '\0')
-			break;
-		end = os_strchr(start, ' ');
-		if (end)
-			*end = '\0';
-
-		if (rsn_preauth_iface_add(hapd, start)) {
-			rsn_preauth_iface_deinit(hapd);
-			os_free(tmp);
-			return -1;
-		}
-
-		if (end)
-			start = end + 1;
-		else
-			break;
-	}
-	os_free(tmp);
-	return 0;
-}
-
-
-static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
-		   MACSTR, MAC2STR(sta->addr));
-	ap_free_sta(hapd, sta);
-}
-
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-			  int success)
-{
-	const u8 *key;
-	size_t len;
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
-		       success ? "succeeded" : "failed");
-
-	key = ieee802_1x_get_key(sta->eapol_sm, &len);
-	if (len > PMK_LEN)
-		len = PMK_LEN;
-	if (success && key) {
-		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
-					       sta->addr,
-					       dot11RSNAConfigPMKLifetime,
-					       sta->eapol_sm) == 0) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "added PMKSA cache entry (pre-auth)");
-		} else {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "failed to add PMKSA cache entry "
-				       "(pre-auth)");
-		}
-	}
-
-	/*
-	 * Finish STA entry removal from timeout in order to avoid freeing
-	 * STA data before the caller has finished processing.
-	 */
-	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
-}
-
-
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-		      u8 *buf, size_t len)
-{
-	struct rsn_preauth_interface *piface;
-	struct l2_ethhdr *ethhdr;
-
-	piface = hapd->preauth_iface;
-	while (piface) {
-		if (piface == sta->preauth_iface)
-			break;
-		piface = piface->next;
-	}
-
-	if (piface == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
-			   "interface for " MACSTR, MAC2STR(sta->addr));
-		return;
-	}
-
-	ethhdr = os_malloc(sizeof(*ethhdr) + len);
-	if (ethhdr == NULL)
-		return;
-
-	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
-	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
-	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
-	os_memcpy(ethhdr + 1, buf, len);
-
-	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
-			   sizeof(*ethhdr) + len) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
-			   "l2_packet_send\n");
-	}
-	os_free(ethhdr);
-}
-
-
-void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
-}
-
-#endif /* CONFIG_RSN_PREAUTH */

Copied: vendor/wpa/2.0/src/ap/preauth_auth.c (from rev 9639, vendor/wpa/dist/src/ap/preauth_auth.c)
===================================================================
--- vendor/wpa/2.0/src/ap/preauth_auth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/preauth_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,273 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifdef CONFIG_RSN_PREAUTH
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "l2_packet/l2_packet.h"
+#include "common/wpa_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_1x.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+
+#ifndef ETH_P_PREAUTH
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+#endif /* ETH_P_PREAUTH */
+
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_preauth_interface {
+	struct rsn_preauth_interface *next;
+	struct hostapd_data *hapd;
+	struct l2_packet_data *l2;
+	char *ifname;
+	int ifindex;
+};
+
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+				const u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface = ctx;
+	struct hostapd_data *hapd = piface->hapd;
+	struct ieee802_1x_hdr *hdr;
+	struct sta_info *sta;
+	struct l2_ethhdr *ethhdr;
+
+	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
+		   "from interface '%s'", piface->ifname);
+	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
+			   "(len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	ethhdr = (struct l2_ethhdr *) buf;
+	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
+
+	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
+			   MACSTR, MAC2STR(ethhdr->h_dest));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, ethhdr->h_source);
+	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
+			   "STA " MACSTR, MAC2STR(sta->addr));
+		return;
+	}
+	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
+		sta = ap_sta_add(hapd, ethhdr->h_source);
+		if (sta == NULL)
+			return;
+		sta->flags = WLAN_STA_PREAUTH;
+
+		ieee802_1x_new_station(hapd, sta);
+		if (sta->eapol_sm == NULL) {
+			ap_free_sta(hapd, sta);
+			sta = NULL;
+		} else {
+			sta->eapol_sm->radius_identifier = -1;
+			sta->eapol_sm->portValid = TRUE;
+			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
+		}
+	}
+	if (sta == NULL)
+		return;
+	sta->preauth_iface = piface;
+	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
+			   len - sizeof(*ethhdr));
+}
+
+
+static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
+{
+	struct rsn_preauth_interface *piface;
+
+	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
+
+	piface = os_zalloc(sizeof(*piface));
+	if (piface == NULL)
+		return -1;
+	piface->hapd = hapd;
+
+	piface->ifname = os_strdup(ifname);
+	if (piface->ifname == NULL) {
+		goto fail1;
+	}
+
+	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
+				    rsn_preauth_receive, piface, 1);
+	if (piface->l2 == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
+			   "to ETH_P_PREAUTH");
+		goto fail2;
+	}
+
+	piface->next = hapd->preauth_iface;
+	hapd->preauth_iface = piface;
+	return 0;
+
+fail2:
+	os_free(piface->ifname);
+fail1:
+	os_free(piface);
+	return -1;
+}
+
+
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+	struct rsn_preauth_interface *piface, *prev;
+
+	piface = hapd->preauth_iface;
+	hapd->preauth_iface = NULL;
+	while (piface) {
+		prev = piface;
+		piface = piface->next;
+		l2_packet_deinit(prev->l2);
+		os_free(prev->ifname);
+		os_free(prev);
+	}
+}
+
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	char *tmp, *start, *end;
+
+	if (hapd->conf->rsn_preauth_interfaces == NULL)
+		return 0;
+
+	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
+	if (tmp == NULL)
+		return -1;
+	start = tmp;
+	for (;;) {
+		while (*start == ' ')
+			start++;
+		if (*start == '\0')
+			break;
+		end = os_strchr(start, ' ');
+		if (end)
+			*end = '\0';
+
+		if (rsn_preauth_iface_add(hapd, start)) {
+			rsn_preauth_iface_deinit(hapd);
+			os_free(tmp);
+			return -1;
+		}
+
+		if (end)
+			start = end + 1;
+		else
+			break;
+	}
+	os_free(tmp);
+	return 0;
+}
+
+
+static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
+		   MACSTR, MAC2STR(sta->addr));
+	ap_free_sta(hapd, sta);
+}
+
+
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success)
+{
+	const u8 *key;
+	size_t len;
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
+		       success ? "succeeded" : "failed");
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &len);
+	if (len > PMK_LEN)
+		len = PMK_LEN;
+	if (success && key) {
+		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
+					       sta->addr,
+					       dot11RSNAConfigPMKLifetime,
+					       sta->eapol_sm) == 0) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "added PMKSA cache entry (pre-auth)");
+		} else {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "failed to add PMKSA cache entry "
+				       "(pre-auth)");
+		}
+	}
+
+	/*
+	 * Finish STA entry removal from timeout in order to avoid freeing
+	 * STA data before the caller has finished processing.
+	 */
+	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
+}
+
+
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface;
+	struct l2_ethhdr *ethhdr;
+
+	piface = hapd->preauth_iface;
+	while (piface) {
+		if (piface == sta->preauth_iface)
+			break;
+		piface = piface->next;
+	}
+
+	if (piface == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
+			   "interface for " MACSTR, MAC2STR(sta->addr));
+		return;
+	}
+
+	ethhdr = os_malloc(sizeof(*ethhdr) + len);
+	if (ethhdr == NULL)
+		return;
+
+	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
+	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
+	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
+	os_memcpy(ethhdr + 1, buf, len);
+
+	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
+			   sizeof(*ethhdr) + len) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
+			   "l2_packet_send\n");
+	}
+	os_free(ethhdr);
+}
+
+
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
+}
+
+#endif /* CONFIG_RSN_PREAUTH */

Deleted: vendor/wpa/2.0/src/ap/preauth_auth.h
===================================================================
--- vendor/wpa/dist/src/ap/preauth_auth.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/preauth_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,58 +0,0 @@
-/*
- * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PREAUTH_H
-#define PREAUTH_H
-
-#ifdef CONFIG_RSN_PREAUTH
-
-int rsn_preauth_iface_init(struct hostapd_data *hapd);
-void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-			  int success);
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-		      u8 *buf, size_t len);
-void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
-
-#else /* CONFIG_RSN_PREAUTH */
-
-static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
-{
-	return 0;
-}
-
-static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
-{
-}
-
-static inline void rsn_preauth_finished(struct hostapd_data *hapd,
-					struct sta_info *sta,
-					int success)
-{
-}
-
-static inline void rsn_preauth_send(struct hostapd_data *hapd,
-				    struct sta_info *sta,
-				    u8 *buf, size_t len)
-{
-}
-
-static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
-					    struct sta_info *sta)
-{
-}
-
-#endif /* CONFIG_RSN_PREAUTH */
-
-#endif /* PREAUTH_H */

Copied: vendor/wpa/2.0/src/ap/preauth_auth.h (from rev 9639, vendor/wpa/dist/src/ap/preauth_auth.h)
===================================================================
--- vendor/wpa/2.0/src/ap/preauth_auth.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/preauth_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,52 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PREAUTH_H
+#define PREAUTH_H
+
+#ifdef CONFIG_RSN_PREAUTH
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd);
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success);
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len);
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_RSN_PREAUTH */
+
+static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void rsn_preauth_finished(struct hostapd_data *hapd,
+					struct sta_info *sta,
+					int success)
+{
+}
+
+static inline void rsn_preauth_send(struct hostapd_data *hapd,
+				    struct sta_info *sta,
+				    u8 *buf, size_t len)
+{
+}
+
+static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
+					    struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_RSN_PREAUTH */
+
+#endif /* PREAUTH_H */

Deleted: vendor/wpa/2.0/src/ap/sta_info.c
===================================================================
--- vendor/wpa/dist/src/ap/sta_info.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/sta_info.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,751 +0,0 @@
-/*
- * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "accounting.h"
-#include "ieee802_1x.h"
-#include "ieee802_11.h"
-#include "wpa_auth.h"
-#include "preauth_auth.h"
-#include "ap_config.h"
-#include "beacon.h"
-#include "ap_mlme.h"
-#include "vlan_init.h"
-#include "sta_info.h"
-
-static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
-				       struct sta_info *sta);
-static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
-#ifdef CONFIG_IEEE80211W
-static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
-#endif /* CONFIG_IEEE80211W */
-
-int ap_for_each_sta(struct hostapd_data *hapd,
-		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
-			      void *ctx),
-		    void *ctx)
-{
-	struct sta_info *sta;
-
-	for (sta = hapd->sta_list; sta; sta = sta->next) {
-		if (cb(hapd, sta, ctx))
-			return 1;
-	}
-
-	return 0;
-}
-
-
-struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
-{
-	struct sta_info *s;
-
-	s = hapd->sta_hash[STA_HASH(sta)];
-	while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
-		s = s->hnext;
-	return s;
-}
-
-
-static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct sta_info *tmp;
-
-	if (hapd->sta_list == sta) {
-		hapd->sta_list = sta->next;
-		return;
-	}
-
-	tmp = hapd->sta_list;
-	while (tmp != NULL && tmp->next != sta)
-		tmp = tmp->next;
-	if (tmp == NULL) {
-		wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
-			   "list.", MAC2STR(sta->addr));
-	} else
-		tmp->next = sta->next;
-}
-
-
-void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
-	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
-}
-
-
-static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	struct sta_info *s;
-
-	s = hapd->sta_hash[STA_HASH(sta->addr)];
-	if (s == NULL) return;
-	if (os_memcmp(s->addr, sta->addr, 6) == 0) {
-		hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
-		return;
-	}
-
-	while (s->hnext != NULL &&
-	       os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
-		s = s->hnext;
-	if (s->hnext != NULL)
-		s->hnext = s->hnext->hnext;
-	else
-		wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
-			   " from hash table", MAC2STR(sta->addr));
-}
-
-
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	int set_beacon = 0;
-
-	accounting_sta_stop(hapd, sta);
-
-	if (sta->flags & WLAN_STA_WDS)
-		hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
-
-	if (!(sta->flags & WLAN_STA_PREAUTH))
-		hapd->drv.sta_remove(hapd, sta->addr);
-
-	ap_sta_hash_del(hapd, sta);
-	ap_sta_list_del(hapd, sta);
-
-	if (sta->aid > 0)
-		hapd->sta_aid[(sta->aid - 1) / 32] &=
-			~BIT((sta->aid - 1) % 32);
-
-	hapd->num_sta--;
-	if (sta->nonerp_set) {
-		sta->nonerp_set = 0;
-		hapd->iface->num_sta_non_erp--;
-		if (hapd->iface->num_sta_non_erp == 0)
-			set_beacon++;
-	}
-
-	if (sta->no_short_slot_time_set) {
-		sta->no_short_slot_time_set = 0;
-		hapd->iface->num_sta_no_short_slot_time--;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
-		    && hapd->iface->num_sta_no_short_slot_time == 0)
-			set_beacon++;
-	}
-
-	if (sta->no_short_preamble_set) {
-		sta->no_short_preamble_set = 0;
-		hapd->iface->num_sta_no_short_preamble--;
-		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
-		    && hapd->iface->num_sta_no_short_preamble == 0)
-			set_beacon++;
-	}
-
-	if (sta->no_ht_gf_set) {
-		sta->no_ht_gf_set = 0;
-		hapd->iface->num_sta_ht_no_gf--;
-	}
-
-	if (sta->no_ht_set) {
-		sta->no_ht_set = 0;
-		hapd->iface->num_sta_no_ht--;
-	}
-
-	if (sta->ht_20mhz_set) {
-		sta->ht_20mhz_set = 0;
-		hapd->iface->num_sta_ht_20mhz--;
-	}
-
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
-	if (hostapd_ht_operation_update(hapd->iface) > 0)
-		set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
-
-	if (set_beacon)
-		ieee802_11_set_beacons(hapd->iface);
-
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
-
-	ieee802_1x_free_station(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 */
-
-	os_free(sta->last_assoc_req);
-	os_free(sta->challenge);
-
-#ifdef CONFIG_IEEE80211W
-	os_free(sta->sa_query_trans_id);
-	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-#endif /* CONFIG_IEEE80211W */
-
-	wpabuf_free(sta->wps_ie);
-
-	os_free(sta->ht_capabilities);
-
-	os_free(sta);
-}
-
-
-void hostapd_free_stas(struct hostapd_data *hapd)
-{
-	struct sta_info *sta, *prev;
-
-	sta = hapd->sta_list;
-
-	while (sta) {
-		prev = sta;
-		if (sta->flags & WLAN_STA_AUTH) {
-			mlme_deauthenticate_indication(
-				hapd, sta, WLAN_REASON_UNSPECIFIED);
-		}
-		sta = sta->next;
-		wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
-			   MAC2STR(prev->addr));
-		ap_free_sta(hapd, prev);
-	}
-}
-
-
-/**
- * ap_handle_timer - Per STA timer handler
- * @eloop_ctx: struct hostapd_data *
- * @timeout_ctx: struct sta_info *
- *
- * This function is called to check station activity and to remove inactive
- * stations.
- */
-void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	unsigned long next_time = 0;
-
-	if (sta->timeout_next == STA_REMOVE) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-			       "local deauth request");
-		ap_free_sta(hapd, sta);
-		return;
-	}
-
-	if ((sta->flags & WLAN_STA_ASSOC) &&
-	    (sta->timeout_next == STA_NULLFUNC ||
-	     sta->timeout_next == STA_DISASSOC)) {
-		int inactive_sec;
-		wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:",
-			   MAC2STR(sta->addr));
-		inactive_sec = hapd->drv.get_inact_sec(hapd, sta->addr);
-		if (inactive_sec == -1) {
-			wpa_printf(MSG_DEBUG, "Could not get station info "
-				   "from kernel driver for " MACSTR ".",
-				   MAC2STR(sta->addr));
-		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
-			   sta->flags & WLAN_STA_ASSOC) {
-			/* station activity detected; reset timeout state */
-			wpa_printf(MSG_DEBUG, "  Station has been active");
-			sta->timeout_next = STA_NULLFUNC;
-			next_time = hapd->conf->ap_max_inactivity -
-				inactive_sec;
-		}
-	}
-
-	if ((sta->flags & WLAN_STA_ASSOC) &&
-	    sta->timeout_next == STA_DISASSOC &&
-	    !(sta->flags & WLAN_STA_PENDING_POLL)) {
-		wpa_printf(MSG_DEBUG, "  Station has ACKed data poll");
-		/* data nullfunc frame poll did not produce TX errors; assume
-		 * station ACKed it */
-		sta->timeout_next = STA_NULLFUNC;
-		next_time = hapd->conf->ap_max_inactivity;
-	}
-
-	if (next_time) {
-		eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
-				       sta);
-		return;
-	}
-
-	if (sta->timeout_next == STA_NULLFUNC &&
-	    (sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
-		/* send data frame to poll STA and check whether this frame
-		 * is ACKed */
-		struct ieee80211_hdr hdr;
-
-		wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
-		sta->flags |= WLAN_STA_PENDING_POLL;
-
-		os_memset(&hdr, 0, sizeof(hdr));
-		if (hapd->driver &&
-		    os_strcmp(hapd->driver->name, "hostap") == 0) {
-			/*
-			 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
-			 * but it is apparently not retried so TX Exc events
-			 * are not received for it.
-			 */
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_DATA);
-		} else {
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_NULLFUNC);
-		}
-
-		hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-		os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
-			  ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
-
-		if (hapd->drv.send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0)
-			perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
-	} else if (sta->timeout_next != STA_REMOVE) {
-		int deauth = sta->timeout_next == STA_DEAUTH;
-
-		wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
-			   deauth ? "deauthentication" : "disassociation",
-			   MAC2STR(sta->addr));
-
-		if (deauth) {
-			hapd->drv.sta_deauth(hapd, sta->addr,
-					     WLAN_REASON_PREV_AUTH_NOT_VALID);
-		} else {
-			hapd->drv.sta_disassoc(
-				hapd, sta->addr,
-				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
-		}
-	}
-
-	switch (sta->timeout_next) {
-	case STA_NULLFUNC:
-		sta->timeout_next = STA_DISASSOC;
-		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
-				       hapd, sta);
-		break;
-	case STA_DISASSOC:
-		sta->flags &= ~WLAN_STA_ASSOC;
-		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-		if (!sta->acct_terminate_cause)
-			sta->acct_terminate_cause =
-				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
-		accounting_sta_stop(hapd, sta);
-		ieee802_1x_free_station(sta);
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "disassociated due to "
-			       "inactivity");
-		sta->timeout_next = STA_DEAUTH;
-		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
-				       hapd, sta);
-		mlme_disassociate_indication(
-			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
-		break;
-	case STA_DEAUTH:
-	case STA_REMOVE:
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-			       "inactivity");
-		if (!sta->acct_terminate_cause)
-			sta->acct_terminate_cause =
-				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
-		mlme_deauthenticate_indication(
-			hapd, sta,
-			WLAN_REASON_PREV_AUTH_NOT_VALID);
-		ap_free_sta(hapd, sta);
-		break;
-	}
-}
-
-
-static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	u8 addr[ETH_ALEN];
-
-	if (!(sta->flags & WLAN_STA_AUTH))
-		return;
-
-	mlme_deauthenticate_indication(hapd, sta,
-				       WLAN_REASON_PREV_AUTH_NOT_VALID);
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-		       "session timeout");
-	sta->acct_terminate_cause =
-		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
-	os_memcpy(addr, sta->addr, ETH_ALEN);
-	ap_free_sta(hapd, sta);
-	hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
-			    u32 session_timeout)
-{
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
-		       "seconds", session_timeout);
-	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
-	eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
-			       hapd, sta);
-}
-
-
-void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
-}
-
-
-struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
-{
-	struct sta_info *sta;
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta)
-		return sta;
-
-	wpa_printf(MSG_DEBUG, "  New STA");
-	if (hapd->num_sta >= hapd->conf->max_num_sta) {
-		/* FIX: might try to remove some old STAs first? */
-		wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
-			   hapd->num_sta, hapd->conf->max_num_sta);
-		return NULL;
-	}
-
-	sta = os_zalloc(sizeof(struct sta_info));
-	if (sta == NULL) {
-		wpa_printf(MSG_ERROR, "malloc failed");
-		return NULL;
-	}
-	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
-
-	/* initialize STA info data */
-	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
-			       ap_handle_timer, hapd, sta);
-	os_memcpy(sta->addr, addr, ETH_ALEN);
-	sta->next = hapd->sta_list;
-	hapd->sta_list = sta;
-	hapd->num_sta++;
-	ap_sta_hash_add(hapd, sta);
-	sta->ssid = &hapd->conf->ssid;
-	ap_sta_remove_in_other_bss(hapd, sta);
-
-	return sta;
-}
-
-
-static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
-
-	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
-		   MAC2STR(sta->addr));
-	if (hapd->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));
-		return -1;
-	}
-	return 0;
-}
-
-
-static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
-				       struct sta_info *sta)
-{
-	struct hostapd_iface *iface = hapd->iface;
-	size_t i;
-
-	for (i = 0; i < iface->num_bss; i++) {
-		struct hostapd_data *bss = iface->bss[i];
-		struct sta_info *sta2;
-		/* bss should always be set during operation, but it may be
-		 * NULL during reconfiguration. Assume the STA is not
-		 * associated to another BSS in that case to avoid NULL pointer
-		 * dereferences. */
-		if (bss == hapd || bss == NULL)
-			continue;
-		sta2 = ap_get_sta(bss, sta->addr);
-		if (!sta2)
-			continue;
-
-		ap_sta_disconnect(bss, sta2, sta2->addr,
-				  WLAN_REASON_PREV_AUTH_NOT_VALID);
-	}
-}
-
-
-void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
-			 u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
-		   hapd->conf->iface, MAC2STR(sta->addr));
-	sta->flags &= ~WLAN_STA_ASSOC;
-	ap_sta_remove(hapd, sta);
-	sta->timeout_next = STA_DEAUTH;
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
-			       ap_handle_timer, hapd, sta);
-	accounting_sta_stop(hapd, sta);
-	ieee802_1x_free_station(sta);
-
-	mlme_disassociate_indication(hapd, sta, reason);
-}
-
-
-void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
-			   u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
-		   hapd->conf->iface, MAC2STR(sta->addr));
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	ap_sta_remove(hapd, sta);
-	sta->timeout_next = STA_REMOVE;
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
-			       ap_handle_timer, hapd, sta);
-	accounting_sta_stop(hapd, sta);
-	ieee802_1x_free_station(sta);
-
-	mlme_deauthenticate_indication(hapd, sta, reason);
-}
-
-
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-		     int old_vlanid)
-{
-#ifndef CONFIG_NO_VLAN
-	const char *iface;
-	struct hostapd_vlan *vlan = NULL;
-	int ret;
-
-	/*
-	 * Do not proceed furthur if the vlan id remains same. We do not want
-	 * duplicate dynamic vlan entries.
-	 */
-	if (sta->vlan_id == old_vlanid)
-		return 0;
-
-	/*
-	 * During 1x reauth, if the vlan id changes, then remove the old id and
-	 * proceed furthur to add the new one.
-	 */
-	if (old_vlanid > 0)
-		vlan_remove_dynamic(hapd, old_vlanid);
-
-	iface = hapd->conf->iface;
-	if (sta->ssid->vlan[0])
-		iface = sta->ssid->vlan;
-
-	if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
-		sta->vlan_id = 0;
-	else if (sta->vlan_id > 0) {
-		vlan = hapd->conf->vlan;
-		while (vlan) {
-			if (vlan->vlan_id == sta->vlan_id ||
-			    vlan->vlan_id == VLAN_ID_WILDCARD) {
-				iface = vlan->ifname;
-				break;
-			}
-			vlan = vlan->next;
-		}
-	}
-
-	if (sta->vlan_id > 0 && vlan == NULL) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
-			       "binding station to (vlan_id=%d)",
-			       sta->vlan_id);
-		return -1;
-	} 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);
-			return -1;
-		}
-
-		iface = vlan->ifname;
-		if (vlan_setup_encryption_dyn(hapd, sta->ssid, 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 (sta->vlan_id > 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, sta->ssid, 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);
-		}
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
-		       "'%s'", iface);
-
-	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
-		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
-
-	ret = hapd->drv.set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
-	if (ret < 0) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
-			       "entry to vlan_id=%d", sta->vlan_id);
-	}
-	return ret;
-#else /* CONFIG_NO_VLAN */
-	return 0;
-#endif /* CONFIG_NO_VLAN */
-}
-
-
-#ifdef CONFIG_IEEE80211W
-
-int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	u32 tu;
-	struct os_time now, passed;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
-	tu = (passed.sec * 1000000 + passed.usec) / 1024;
-	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
-		hostapd_logger(hapd, sta->addr,
-			       HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "association SA Query timed out");
-		sta->sa_query_timed_out = 1;
-		os_free(sta->sa_query_trans_id);
-		sta->sa_query_trans_id = NULL;
-		sta->sa_query_count = 0;
-		eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	unsigned int timeout, sec, usec;
-	u8 *trans_id, *nbuf;
-
-	if (sta->sa_query_count > 0 &&
-	    ap_check_sa_query_timeout(hapd, sta))
-		return;
-
-	nbuf = os_realloc(sta->sa_query_trans_id,
-			  (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
-	if (nbuf == NULL)
-		return;
-	if (sta->sa_query_count == 0) {
-		/* Starting a new SA Query procedure */
-		os_get_time(&sta->sa_query_start);
-	}
-	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
-	sta->sa_query_trans_id = nbuf;
-	sta->sa_query_count++;
-
-	os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-	timeout = hapd->conf->assoc_sa_query_retry_timeout;
-	sec = ((timeout / 1000) * 1024) / 1000;
-	usec = (timeout % 1000) * 1024;
-	eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "association SA Query attempt %d", sta->sa_query_count);
-
-#ifdef NEED_AP_MLME
-	ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
-#endif /* NEED_AP_MLME */
-}
-
-
-void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	ap_sa_query_timer(hapd, sta);
-}
-
-
-void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
-{
-	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
-	os_free(sta->sa_query_trans_id);
-	sta->sa_query_trans_id = NULL;
-	sta->sa_query_count = 0;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
-void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
-		       const u8 *addr, u16 reason)
-{
-
-	if (sta == NULL && addr)
-		sta = ap_get_sta(hapd, addr);
-
-	if (addr)
-		hapd->drv.sta_deauth(hapd, addr, reason);
-
-	if (sta == NULL)
-		return;
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
-	sta->timeout_next = STA_REMOVE;
-}

Copied: vendor/wpa/2.0/src/ap/sta_info.c (from rev 9639, vendor/wpa/dist/src/ap/sta_info.c)
===================================================================
--- vendor/wpa/2.0/src/ap/sta_info.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/sta_info.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,971 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2011, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "drivers/driver.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "accounting.h"
+#include "ieee802_1x.h"
+#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ap_mlme.h"
+#include "vlan_init.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "gas_serv.h"
+#include "sta_info.h"
+
+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
+				       struct sta_info *sta);
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_IEEE80211W
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+
+int ap_for_each_sta(struct hostapd_data *hapd,
+		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
+			      void *ctx),
+		    void *ctx)
+{
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (cb(hapd, sta, ctx))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
+{
+	struct sta_info *s;
+
+	s = hapd->sta_hash[STA_HASH(sta)];
+	while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
+		s = s->hnext;
+	return s;
+}
+
+
+static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct sta_info *tmp;
+
+	if (hapd->sta_list == sta) {
+		hapd->sta_list = sta->next;
+		return;
+	}
+
+	tmp = hapd->sta_list;
+	while (tmp != NULL && tmp->next != sta)
+		tmp = tmp->next;
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
+			   "list.", MAC2STR(sta->addr));
+	} else
+		tmp->next = sta->next;
+}
+
+
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
+	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+
+static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct sta_info *s;
+
+	s = hapd->sta_hash[STA_HASH(sta->addr)];
+	if (s == NULL) return;
+	if (os_memcmp(s->addr, sta->addr, 6) == 0) {
+		hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL &&
+	       os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
+		s = s->hnext;
+	if (s->hnext != NULL)
+		s->hnext = s->hnext->hnext;
+	else
+		wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
+			   " from hash table", MAC2STR(sta->addr));
+}
+
+
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int set_beacon = 0;
+
+	accounting_sta_stop(hapd, sta);
+
+	/* just in case */
+	ap_sta_set_authorized(hapd, sta, 0);
+
+	if (sta->flags & WLAN_STA_WDS)
+		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
+
+	if (!(sta->flags & WLAN_STA_PREAUTH))
+		hostapd_drv_sta_remove(hapd, sta->addr);
+
+	ap_sta_hash_del(hapd, sta);
+	ap_sta_list_del(hapd, sta);
+
+	if (sta->aid > 0)
+		hapd->sta_aid[(sta->aid - 1) / 32] &=
+			~BIT((sta->aid - 1) % 32);
+
+	hapd->num_sta--;
+	if (sta->nonerp_set) {
+		sta->nonerp_set = 0;
+		hapd->iface->num_sta_non_erp--;
+		if (hapd->iface->num_sta_non_erp == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 0;
+		hapd->iface->num_sta_no_short_slot_time--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_slot_time == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 0;
+		hapd->iface->num_sta_no_short_preamble--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_ht_gf_set) {
+		sta->no_ht_gf_set = 0;
+		hapd->iface->num_sta_ht_no_gf--;
+	}
+
+	if (sta->no_ht_set) {
+		sta->no_ht_set = 0;
+		hapd->iface->num_sta_no_ht--;
+	}
+
+	if (sta->ht_20mhz_set) {
+		sta->ht_20mhz_set = 0;
+		hapd->iface->num_sta_ht_20mhz--;
+	}
+
+#ifdef CONFIG_P2P
+	if (sta->no_p2p_set) {
+		sta->no_p2p_set = 0;
+		hapd->num_sta_no_p2p--;
+		if (hapd->num_sta_no_p2p == 0)
+			hostapd_p2p_non_p2p_sta_disconnected(hapd);
+	}
+#endif /* CONFIG_P2P */
+
+#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+	if (hostapd_ht_operation_update(hapd->iface) > 0)
+		set_beacon++;
+#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+
+	if (set_beacon)
+		ieee802_11_set_beacons(hapd->iface);
+
+	wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
+		   __func__, MAC2STR(sta->addr));
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+
+	ieee802_1x_free_station(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 */
+
+	os_free(sta->last_assoc_req);
+	os_free(sta->challenge);
+
+#ifdef CONFIG_IEEE80211W
+	os_free(sta->sa_query_trans_id);
+	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_P2P
+	p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+	if (sta->gas_dialog) {
+		int i;
+		for (i = 0; i < GAS_DIALOG_MAX; i++)
+			gas_serv_dialog_clear(&sta->gas_dialog[i]);
+		os_free(sta->gas_dialog);
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	wpabuf_free(sta->wps_ie);
+	wpabuf_free(sta->p2p_ie);
+	wpabuf_free(sta->hs20_ie);
+
+	os_free(sta->ht_capabilities);
+	hostapd_free_psk_list(sta->psk);
+	os_free(sta->identity);
+	os_free(sta->radius_cui);
+
+	os_free(sta);
+}
+
+
+void hostapd_free_stas(struct hostapd_data *hapd)
+{
+	struct sta_info *sta, *prev;
+
+	sta = hapd->sta_list;
+
+	while (sta) {
+		prev = sta;
+		if (sta->flags & WLAN_STA_AUTH) {
+			mlme_deauthenticate_indication(
+				hapd, sta, WLAN_REASON_UNSPECIFIED);
+		}
+		sta = sta->next;
+		wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
+			   MAC2STR(prev->addr));
+		ap_free_sta(hapd, prev);
+	}
+}
+
+
+/**
+ * ap_handle_timer - Per STA timer handler
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: struct sta_info *
+ *
+ * This function is called to check station activity and to remove inactive
+ * stations.
+ */
+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	unsigned long next_time = 0;
+
+	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
+		   __func__, MAC2STR(sta->addr), sta->flags,
+		   sta->timeout_next);
+	if (sta->timeout_next == STA_REMOVE) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+			       "local deauth request");
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
+	if ((sta->flags & WLAN_STA_ASSOC) &&
+	    (sta->timeout_next == STA_NULLFUNC ||
+	     sta->timeout_next == STA_DISASSOC)) {
+		int inactive_sec;
+		/*
+		 * Add random value to timeout so that we don't end up bouncing
+		 * all stations at the same time if we have lots of associated
+		 * stations that are idle (but keep re-associating).
+		 */
+		int fuzz = os_random() % 20;
+		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
+		if (inactive_sec == -1) {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Check inactivity: Could not "
+				"get station info from kernel driver for "
+				MACSTR, MAC2STR(sta->addr));
+			/*
+			 * The driver may not support this functionality.
+			 * Anyway, try again after the next inactivity timeout,
+			 * but do not disconnect the station now.
+			 */
+			next_time = hapd->conf->ap_max_inactivity + fuzz;
+		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
+			   sta->flags & WLAN_STA_ASSOC) {
+			/* station activity detected; reset timeout state */
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been active %is ago",
+				MAC2STR(sta->addr), inactive_sec);
+			sta->timeout_next = STA_NULLFUNC;
+			next_time = hapd->conf->ap_max_inactivity + fuzz -
+				inactive_sec;
+		} else {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been "
+				"inactive too long: %d sec, max allowed: %d",
+				MAC2STR(sta->addr), inactive_sec,
+				hapd->conf->ap_max_inactivity);
+
+			if (hapd->conf->skip_inactivity_poll)
+				sta->timeout_next = STA_DISASSOC;
+		}
+	}
+
+	if ((sta->flags & WLAN_STA_ASSOC) &&
+	    sta->timeout_next == STA_DISASSOC &&
+	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
+	    !hapd->conf->skip_inactivity_poll) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+			" has ACKed data poll", MAC2STR(sta->addr));
+		/* data nullfunc frame poll did not produce TX errors; assume
+		 * station ACKed it */
+		sta->timeout_next = STA_NULLFUNC;
+		next_time = hapd->conf->ap_max_inactivity;
+	}
+
+	if (next_time) {
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%lu seconds)",
+			   __func__, MAC2STR(sta->addr), next_time);
+		eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
+				       sta);
+		return;
+	}
+
+	if (sta->timeout_next == STA_NULLFUNC &&
+	    (sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "  Polling STA");
+		sta->flags |= WLAN_STA_PENDING_POLL;
+		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+					sta->flags & WLAN_STA_WMM);
+	} else if (sta->timeout_next != STA_REMOVE) {
+		int deauth = sta->timeout_next == STA_DEAUTH;
+
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+			"Timeout, sending %s info to STA " MACSTR,
+			deauth ? "deauthentication" : "disassociation",
+			MAC2STR(sta->addr));
+
+		if (deauth) {
+			hostapd_drv_sta_deauth(
+				hapd, sta->addr,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
+		} else {
+			hostapd_drv_sta_disassoc(
+				hapd, sta->addr,
+				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+		}
+	}
+
+	switch (sta->timeout_next) {
+	case STA_NULLFUNC:
+		sta->timeout_next = STA_DISASSOC;
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
+			   __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
+		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+		break;
+	case STA_DISASSOC:
+		ap_sta_set_authorized(hapd, sta, 0);
+		sta->flags &= ~WLAN_STA_ASSOC;
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+		if (!sta->acct_terminate_cause)
+			sta->acct_terminate_cause =
+				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
+		accounting_sta_stop(hapd, sta);
+		ieee802_1x_free_station(sta);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "disassociated due to "
+			       "inactivity");
+		sta->timeout_next = STA_DEAUTH;
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
+			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
+		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+		mlme_disassociate_indication(
+			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+		break;
+	case STA_DEAUTH:
+	case STA_REMOVE:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+			       "inactivity (timer DEAUTH/REMOVE)");
+		if (!sta->acct_terminate_cause)
+			sta->acct_terminate_cause =
+				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
+		mlme_deauthenticate_indication(
+			hapd, sta,
+			WLAN_REASON_PREV_AUTH_NOT_VALID);
+		ap_free_sta(hapd, sta);
+		break;
+	}
+}
+
+
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	u8 addr[ETH_ALEN];
+
+	if (!(sta->flags & WLAN_STA_AUTH)) {
+		if (sta->flags & WLAN_STA_GAS) {
+			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
+				   "entry " MACSTR, MAC2STR(sta->addr));
+			ap_free_sta(hapd, sta);
+		}
+		return;
+	}
+
+	mlme_deauthenticate_indication(hapd, sta,
+				       WLAN_REASON_PREV_AUTH_NOT_VALID);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+		       "session timeout");
+	sta->acct_terminate_cause =
+		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
+	os_memcpy(addr, sta->addr, ETH_ALEN);
+	ap_free_sta(hapd, sta);
+	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			    u32 session_timeout)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
+		       "seconds", session_timeout);
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
+			       hapd, sta);
+}
+
+
+void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+}
+
+
+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return sta;
+
+	wpa_printf(MSG_DEBUG, "  New STA");
+	if (hapd->num_sta >= hapd->conf->max_num_sta) {
+		/* FIX: might try to remove some old STAs first? */
+		wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
+			   hapd->num_sta, hapd->conf->max_num_sta);
+		return NULL;
+	}
+
+	sta = os_zalloc(sizeof(struct sta_info));
+	if (sta == NULL) {
+		wpa_printf(MSG_ERROR, "malloc failed");
+		return NULL;
+	}
+	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
+	accounting_sta_get_id(hapd, sta);
+
+	/* initialize STA info data */
+	wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+		   __func__, MAC2STR(addr),
+		   hapd->conf->ap_max_inactivity);
+	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+			       ap_handle_timer, hapd, sta);
+	os_memcpy(sta->addr, addr, ETH_ALEN);
+	sta->next = hapd->sta_list;
+	hapd->sta_list = sta;
+	hapd->num_sta++;
+	ap_sta_hash_add(hapd, sta);
+	sta->ssid = &hapd->conf->ssid;
+	ap_sta_remove_in_other_bss(hapd, sta);
+
+	return sta;
+}
+
+
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+
+	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
+		   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));
+		return -1;
+	}
+	return 0;
+}
+
+
+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	size_t i;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		struct sta_info *sta2;
+		/* bss should always be set during operation, but it may be
+		 * NULL during reconfiguration. Assume the STA is not
+		 * associated to another BSS in that case to avoid NULL pointer
+		 * dereferences. */
+		if (bss == hapd || bss == NULL)
+			continue;
+		sta2 = ap_get_sta(bss, sta->addr);
+		if (!sta2)
+			continue;
+
+		ap_sta_disconnect(bss, sta2, sta2->addr,
+				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+	}
+}
+
+
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason)
+{
+	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_ASSOC;
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->timeout_next = STA_DEAUTH;
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
+		   __func__, MAC2STR(sta->addr),
+		   AP_MAX_INACTIVITY_AFTER_DISASSOC);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	sta->disassoc_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
+}
+
+
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason)
+{
+	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->timeout_next = STA_REMOVE;
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+		   __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,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+		      struct sta_info *sta, void *ctx)
+{
+	if (sta && (sta->flags & WLAN_STA_WPS)) {
+		ap_sta_deauthenticate(hapd, sta,
+				      WLAN_REASON_PREV_AUTH_NOT_VALID);
+		wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+			   __func__, MAC2STR(sta->addr));
+		return 1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_WPS */
+
+
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid)
+{
+#ifndef CONFIG_NO_VLAN
+	const char *iface;
+	struct hostapd_vlan *vlan = NULL;
+	int ret;
+
+	/*
+	 * Do not proceed furthur if the vlan id remains same. We do not want
+	 * duplicate dynamic vlan entries.
+	 */
+	if (sta->vlan_id == old_vlanid)
+		return 0;
+
+	/*
+	 * During 1x reauth, if the vlan id changes, then remove the old id and
+	 * proceed furthur to add the new one.
+	 */
+	if (old_vlanid > 0)
+		vlan_remove_dynamic(hapd, old_vlanid);
+
+	iface = hapd->conf->iface;
+	if (sta->ssid->vlan[0])
+		iface = sta->ssid->vlan;
+
+	if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+		sta->vlan_id = 0;
+	else if (sta->vlan_id > 0) {
+		vlan = hapd->conf->vlan;
+		while (vlan) {
+			if (vlan->vlan_id == sta->vlan_id ||
+			    vlan->vlan_id == VLAN_ID_WILDCARD) {
+				iface = vlan->ifname;
+				break;
+			}
+			vlan = vlan->next;
+		}
+	}
+
+	if (sta->vlan_id > 0 && vlan == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
+			       "binding station to (vlan_id=%d)",
+			       sta->vlan_id);
+		return -1;
+	} 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);
+			return -1;
+		}
+
+		iface = vlan->ifname;
+		if (vlan_setup_encryption_dyn(hapd, sta->ssid, 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 (sta->vlan_id > 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, sta->ssid, 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);
+		}
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
+		       "'%s'", iface);
+
+	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
+		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
+
+	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+	if (ret < 0) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
+			       "entry to vlan_id=%d", sta->vlan_id);
+	}
+	return ret;
+#else /* CONFIG_NO_VLAN */
+	return 0;
+#endif /* CONFIG_NO_VLAN */
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	u32 tu;
+	struct os_time now, passed;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
+		hostapd_logger(hapd, sta->addr,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "association SA Query timed out");
+		sta->sa_query_timed_out = 1;
+		os_free(sta->sa_query_trans_id);
+		sta->sa_query_trans_id = NULL;
+		sta->sa_query_count = 0;
+		eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	unsigned int timeout, sec, usec;
+	u8 *trans_id, *nbuf;
+
+	if (sta->sa_query_count > 0 &&
+	    ap_check_sa_query_timeout(hapd, sta))
+		return;
+
+	nbuf = os_realloc_array(sta->sa_query_trans_id,
+				sta->sa_query_count + 1,
+				WLAN_SA_QUERY_TR_ID_LEN);
+	if (nbuf == NULL)
+		return;
+	if (sta->sa_query_count == 0) {
+		/* Starting a new SA Query procedure */
+		os_get_time(&sta->sa_query_start);
+	}
+	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+	sta->sa_query_trans_id = nbuf;
+	sta->sa_query_count++;
+
+	os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	timeout = hapd->conf->assoc_sa_query_retry_timeout;
+	sec = ((timeout / 1000) * 1024) / 1000;
+	usec = (timeout % 1000) * 1024;
+	eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "association SA Query attempt %d", sta->sa_query_count);
+
+	ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
+}
+
+
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	ap_sa_query_timer(hapd, sta);
+}
+
+
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+	os_free(sta->sa_query_trans_id);
+	sta->sa_query_trans_id = NULL;
+	sta->sa_query_count = 0;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+			   int authorized)
+{
+	const u8 *dev_addr = NULL;
+#ifdef CONFIG_P2P
+	u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
+	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
+		return;
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p_group == NULL) {
+		if (sta->p2p_ie != NULL &&
+		    p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
+			dev_addr = addr;
+	} else
+		dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+	if (authorized) {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+				MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
+		sta->flags |= WLAN_STA_AUTHORIZED;
+	} else {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+				MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR,
+				MAC2STR(sta->addr));
+		sta->flags &= ~WLAN_STA_AUTHORIZED;
+	}
+
+	if (hapd->sta_authorized_cb)
+		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+					sta->addr, authorized, dev_addr);
+}
+
+
+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *addr, u16 reason)
+{
+
+	if (sta == NULL && addr)
+		sta = ap_get_sta(hapd, addr);
+
+	if (addr)
+		hostapd_drv_sta_deauth(hapd, addr, reason);
+
+	if (sta == NULL)
+		return;
+	ap_sta_set_authorized(hapd, sta, 0);
+	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 "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+		   __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,
+			       ap_handle_timer, hapd, sta);
+	sta->timeout_next = STA_REMOVE;
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	ap_sta_disassoc_cb_timeout(hapd, sta);
+}

Deleted: vendor/wpa/2.0/src/ap/sta_info.h
===================================================================
--- vendor/wpa/dist/src/ap/sta_info.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/sta_info.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,155 +0,0 @@
-/*
- * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef STA_INFO_H
-#define STA_INFO_H
-
-/* STA flags */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3)
-#define WLAN_STA_PERM BIT(4)
-#define WLAN_STA_AUTHORIZED BIT(5)
-#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-#define WLAN_STA_SHORT_PREAMBLE BIT(7)
-#define WLAN_STA_PREAUTH BIT(8)
-#define WLAN_STA_WMM BIT(9)
-#define WLAN_STA_MFP BIT(10)
-#define WLAN_STA_HT BIT(11)
-#define WLAN_STA_WPS BIT(12)
-#define WLAN_STA_MAYBE_WPS BIT(13)
-#define WLAN_STA_WDS BIT(14)
-#define WLAN_STA_NONERP BIT(31)
-
-/* Maximum number of supported rates (from both Supported Rates and Extended
- * Supported Rates IEs). */
-#define WLAN_SUPP_RATES_MAX 32
-
-
-struct sta_info {
-	struct sta_info *next; /* next entry in sta list */
-	struct sta_info *hnext; /* next entry in hash table list */
-	u8 addr[6];
-	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
-	u32 flags; /* Bitfield of WLAN_STA_* */
-	u16 capability;
-	u16 listen_interval; /* or beacon_int for APs */
-	u8 supported_rates[WLAN_SUPP_RATES_MAX];
-	int supported_rates_len;
-
-	unsigned int nonerp_set:1;
-	unsigned int no_short_slot_time_set:1;
-	unsigned int no_short_preamble_set:1;
-	unsigned int no_ht_gf_set:1;
-	unsigned int no_ht_set:1;
-	unsigned int ht_20mhz_set:1;
-
-	u16 auth_alg;
-	u8 previous_ap[6];
-
-	enum {
-		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
-	} timeout_next;
-
-	/* IEEE 802.1X related data */
-	struct eapol_state_machine *eapol_sm;
-
-	/* IEEE 802.11f (IAPP) related data */
-	struct ieee80211_mgmt *last_assoc_req;
-
-	u32 acct_session_id_hi;
-	u32 acct_session_id_lo;
-	time_t acct_session_start;
-	int acct_session_started;
-	int acct_terminate_cause; /* Acct-Terminate-Cause */
-	int acct_interim_interval; /* Acct-Interim-Interval */
-
-	unsigned long last_rx_bytes;
-	unsigned long last_tx_bytes;
-	u32 acct_input_gigawords; /* Acct-Input-Gigawords */
-	u32 acct_output_gigawords; /* Acct-Output-Gigawords */
-
-	u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
-
-	struct wpa_state_machine *wpa_sm;
-	struct rsn_preauth_interface *preauth_iface;
-
-	struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
-	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
-
-	int vlan_id;
-
-	struct ieee80211_ht_capabilities *ht_capabilities;
-
-#ifdef CONFIG_IEEE80211W
-	int sa_query_count; /* number of pending SA Query requests;
-			     * 0 = no SA Query in progress */
-	int sa_query_timed_out;
-	u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
-				* sa_query_count octets of pending SA Query
-				* transaction identifiers */
-	struct os_time sa_query_start;
-#endif /* CONFIG_IEEE80211W */
-
-	struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
-};
-
-
-/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
- * passed since last received frame from the station, a nullfunc data frame is
- * sent to the station. If this frame is not acknowledged and no other frames
- * have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY seconds. Similarily, 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_DEAUTH_DELAY (1)
-/* Number of seconds to keep STA entry with Authenticated flag after it has
- * been disassociated. */
-#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
-/* Number of seconds to keep STA entry after it has been deauthenticated. */
-#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
-
-
-struct hostapd_data;
-
-int ap_for_each_sta(struct hostapd_data *hapd,
-		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
-			      void *ctx),
-		    void *ctx);
-struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
-void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
-void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
-void hostapd_free_stas(struct hostapd_data *hapd);
-void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
-void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
-			    u32 session_timeout);
-void ap_sta_no_session_timeout(struct hostapd_data *hapd,
-			       struct sta_info *sta);
-struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
-void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
-			 u16 reason);
-void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
-			   u16 reason);
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
-		     int old_vlanid);
-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);
-void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
-		       const u8 *addr, u16 reason);
-
-#endif /* STA_INFO_H */

Copied: vendor/wpa/2.0/src/ap/sta_info.h (from rev 9639, vendor/wpa/dist/src/ap/sta_info.h)
===================================================================
--- vendor/wpa/2.0/src/ap/sta_info.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/sta_info.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,194 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef STA_INFO_H
+#define STA_INFO_H
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#define WLAN_STA_PERM BIT(4)
+#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WMM BIT(9)
+#define WLAN_STA_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#define WLAN_STA_WDS BIT(14)
+#define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_GAS BIT(17)
+#define WLAN_STA_VHT BIT(18)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
+#define WLAN_STA_NONERP BIT(31)
+
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs). */
+#define WLAN_SUPP_RATES_MAX 32
+
+
+struct sta_info {
+	struct sta_info *next; /* next entry in sta list */
+	struct sta_info *hnext; /* next entry in hash table list */
+	u8 addr[6];
+	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+	u32 flags; /* Bitfield of WLAN_STA_* */
+	u16 capability;
+	u16 listen_interval; /* or beacon_int for APs */
+	u8 supported_rates[WLAN_SUPP_RATES_MAX];
+	int supported_rates_len;
+	u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
+
+	unsigned int nonerp_set:1;
+	unsigned int no_short_slot_time_set:1;
+	unsigned int no_short_preamble_set:1;
+	unsigned int no_ht_gf_set:1;
+	unsigned int no_ht_set:1;
+	unsigned int ht_20mhz_set:1;
+	unsigned int no_p2p_set:1;
+
+	u16 auth_alg;
+	u8 previous_ap[6];
+
+	enum {
+		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+	} timeout_next;
+
+	u16 deauth_reason;
+	u16 disassoc_reason;
+
+	/* IEEE 802.1X related data */
+	struct eapol_state_machine *eapol_sm;
+
+	/* IEEE 802.11f (IAPP) related data */
+	struct ieee80211_mgmt *last_assoc_req;
+
+	u32 acct_session_id_hi;
+	u32 acct_session_id_lo;
+	time_t acct_session_start;
+	int acct_session_started;
+	int acct_terminate_cause; /* Acct-Terminate-Cause */
+	int acct_interim_interval; /* Acct-Interim-Interval */
+
+	unsigned long last_rx_bytes;
+	unsigned long last_tx_bytes;
+	u32 acct_input_gigawords; /* Acct-Input-Gigawords */
+	u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+
+	u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
+
+	struct wpa_state_machine *wpa_sm;
+	struct rsn_preauth_interface *preauth_iface;
+
+	struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
+	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+
+	int vlan_id;
+	 /* PSKs from RADIUS authentication server */
+	struct hostapd_sta_wpa_psk_short *psk;
+
+	char *identity; /* User-Name from RADIUS */
+	char *radius_cui; /* Chargeable-User-Identity from RADIUS */
+
+	struct ieee80211_ht_capabilities *ht_capabilities;
+	struct ieee80211_vht_capabilities *vht_capabilities;
+
+#ifdef CONFIG_IEEE80211W
+	int sa_query_count; /* number of pending SA Query requests;
+			     * 0 = no SA Query in progress */
+	int sa_query_timed_out;
+	u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+				* sa_query_count octets of pending SA Query
+				* transaction identifiers */
+	struct os_time sa_query_start;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_INTERWORKING
+#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
+	struct gas_dialog_info *gas_dialog;
+	u8 gas_dialog_next;
+#endif /* CONFIG_INTERWORKING */
+
+	struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
+	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
+	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+
+	struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+	enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
+	u16 sae_send_confirm;
+#endif /* CONFIG_SAE */
+};
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
+ * passed since last received frame from the station, a nullfunc data frame is
+ * sent to the station. If this frame is not acknowledged and no other frames
+ * have been received, the station will be disassociated after
+ * 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_DEAUTH_DELAY (1)
+/* Number of seconds to keep STA entry with Authenticated flag after it has
+ * been disassociated. */
+#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
+/* Number of seconds to keep STA entry after it has been deauthenticated. */
+#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
+
+
+struct hostapd_data;
+
+int ap_for_each_sta(struct hostapd_data *hapd,
+		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
+			      void *ctx),
+		    void *ctx);
+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_free_stas(struct hostapd_data *hapd);
+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			    u32 session_timeout);
+void ap_sta_no_session_timeout(struct hostapd_data *hapd,
+			       struct sta_info *sta);
+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason);
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason);
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+		      struct sta_info *sta, void *ctx);
+#endif /* CONFIG_WPS */
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid);
+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);
+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *addr, u16 reason);
+
+void ap_sta_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized);
+static inline int ap_sta_is_authorized(struct sta_info *sta)
+{
+	return sta->flags & WLAN_STA_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);
+
+#endif /* STA_INFO_H */

Deleted: vendor/wpa/2.0/src/ap/tkip_countermeasures.c
===================================================================
--- vendor/wpa/dist/src/ap/tkip_countermeasures.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/tkip_countermeasures.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,93 +0,0 @@
-/*
- * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "hostapd.h"
-#include "sta_info.h"
-#include "ap_mlme.h"
-#include "wpa_auth.h"
-#include "tkip_countermeasures.h"
-
-
-static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
-						void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	hapd->tkip_countermeasures = 0;
-	hapd->drv.set_countermeasures(hapd, 0);
-	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
-}
-
-
-static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
-{
-	struct sta_info *sta;
-
-	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
-
-	wpa_auth_countermeasures_start(hapd->wpa_auth);
-	hapd->tkip_countermeasures = 1;
-	hapd->drv.set_countermeasures(hapd, 1);
-	wpa_gtk_rekey(hapd->wpa_auth);
-	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
-	eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
-			       hapd, NULL);
-	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
-		hapd->drv.sta_deauth(hapd, sta->addr,
-				     WLAN_REASON_MICHAEL_MIC_FAILURE);
-		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
-				WLAN_STA_AUTHORIZED);
-		hapd->drv.sta_remove(hapd, sta->addr);
-	}
-}
-
-
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
-{
-	time_t now;
-
-	if (addr && local) {
-		struct sta_info *sta = ap_get_sta(hapd, addr);
-		if (sta != NULL) {
-			wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
-			hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
-				       HOSTAPD_LEVEL_INFO,
-				       "Michael MIC failure detected in "
-				       "received frame");
-			mlme_michaelmicfailure_indication(hapd, addr);
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "for not associated STA (" MACSTR
-				   ") ignored", MAC2STR(addr));
-			return;
-		}
-	}
-
-	time(&now);
-	if (now > hapd->michael_mic_failure + 60) {
-		hapd->michael_mic_failures = 1;
-	} else {
-		hapd->michael_mic_failures++;
-		if (hapd->michael_mic_failures > 1)
-			ieee80211_tkip_countermeasures_start(hapd);
-	}
-	hapd->michael_mic_failure = now;
-}

Copied: vendor/wpa/2.0/src/ap/tkip_countermeasures.c (from rev 9639, vendor/wpa/dist/src/ap/tkip_countermeasures.c)
===================================================================
--- vendor/wpa/2.0/src/ap/tkip_countermeasures.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/tkip_countermeasures.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,105 @@
+/*
+ * hostapd / TKIP countermeasures
+ * Copyright (c) 2002-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_mlme.h"
+#include "wpa_auth.h"
+#include "ap_drv_ops.h"
+#include "tkip_countermeasures.h"
+
+
+static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
+						void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	hapd->tkip_countermeasures = 0;
+	hostapd_drv_set_countermeasures(hapd, 0);
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
+}
+
+
+static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
+{
+	struct sta_info *sta;
+
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
+
+	wpa_auth_countermeasures_start(hapd->wpa_auth);
+	hapd->tkip_countermeasures = 1;
+	hostapd_drv_set_countermeasures(hapd, 1);
+	wpa_gtk_rekey(hapd->wpa_auth);
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+	eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
+			       hapd, NULL);
+	while ((sta = hapd->sta_list)) {
+		sta->acct_terminate_cause =
+			RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
+		if (sta->flags & WLAN_STA_AUTH) {
+			mlme_deauthenticate_indication(
+				hapd, sta,
+				WLAN_REASON_MICHAEL_MIC_FAILURE);
+		}
+		hostapd_drv_sta_deauth(hapd, sta->addr,
+				       WLAN_REASON_MICHAEL_MIC_FAILURE);
+		ap_free_sta(hapd, sta);
+	}
+}
+
+
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+{
+	struct os_time now;
+	int ret = 0;
+
+	if (addr && local) {
+		struct sta_info *sta = ap_get_sta(hapd, addr);
+		if (sta != NULL) {
+			wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
+			hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Michael MIC failure detected in "
+				       "received frame");
+			mlme_michaelmicfailure_indication(hapd, addr);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "for not associated STA (" MACSTR
+				   ") ignored", MAC2STR(addr));
+			return ret;
+		}
+	}
+
+	os_get_time(&now);
+	if (now.sec > hapd->michael_mic_failure + 60) {
+		hapd->michael_mic_failures = 1;
+	} else {
+		hapd->michael_mic_failures++;
+		if (hapd->michael_mic_failures > 1) {
+			ieee80211_tkip_countermeasures_start(hapd);
+			ret = 1;
+		}
+	}
+	hapd->michael_mic_failure = now.sec;
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/ap/tkip_countermeasures.h
===================================================================
--- vendor/wpa/dist/src/ap/tkip_countermeasures.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/tkip_countermeasures.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,20 +0,0 @@
-/*
- * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TKIP_COUNTERMEASURES_H
-#define TKIP_COUNTERMEASURES_H
-
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
-
-#endif /* TKIP_COUNTERMEASURES_H */

Copied: vendor/wpa/2.0/src/ap/tkip_countermeasures.h (from rev 9639, vendor/wpa/dist/src/ap/tkip_countermeasures.h)
===================================================================
--- vendor/wpa/2.0/src/ap/tkip_countermeasures.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/tkip_countermeasures.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,15 @@
+/*
+ * hostapd / TKIP countermeasures
+ * Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TKIP_COUNTERMEASURES_H
+#define TKIP_COUNTERMEASURES_H
+
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
+
+#endif /* TKIP_COUNTERMEASURES_H */

Deleted: vendor/wpa/2.0/src/ap/utils.c
===================================================================
--- vendor/wpa/dist/src/ap/utils.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/utils.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,88 +0,0 @@
-/*
- * AP mode helper functions
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "common/ieee802_11_defs.h"
-#include "sta_info.h"
-#include "hostapd.h"
-
-
-int hostapd_register_probereq_cb(struct hostapd_data *hapd,
-				 int (*cb)(void *ctx, const u8 *sa,
-					   const u8 *ie, size_t ie_len),
-				 void *ctx)
-{
-	struct hostapd_probereq_cb *n;
-
-	n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
-		       sizeof(struct hostapd_probereq_cb));
-	if (n == NULL)
-		return -1;
-
-	hapd->probereq_cb = n;
-	n = &hapd->probereq_cb[hapd->num_probereq_cb];
-	hapd->num_probereq_cb++;
-
-	n->cb = cb;
-	n->ctx = ctx;
-
-	return 0;
-}
-
-
-struct prune_data {
-	struct hostapd_data *hapd;
-	const u8 *addr;
-};
-
-static int prune_associations(struct hostapd_iface *iface, void *ctx)
-{
-	struct prune_data *data = ctx;
-	struct sta_info *osta;
-	struct hostapd_data *ohapd;
-	size_t j;
-
-	for (j = 0; j < iface->num_bss; j++) {
-		ohapd = iface->bss[j];
-		if (ohapd == data->hapd)
-			continue;
-		osta = ap_get_sta(ohapd, data->addr);
-		if (!osta)
-			continue;
-
-		ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
-	}
-
-	return 0;
-}
-
-/**
- * hostapd_prune_associations - Remove extraneous associations
- * @hapd: Pointer to BSS data for the most recent association
- * @addr: Associated STA address
- *
- * This function looks through all radios and BSS's for previous
- * (stale) associations of STA. If any are found they are removed.
- */
-void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
-{
-	struct prune_data data;
-	data.hapd = hapd;
-	data.addr = addr;
-	if (hapd->iface->for_each_interface)
-		hapd->iface->for_each_interface(hapd->iface->interfaces,
-						prune_associations, &data);
-}

Copied: vendor/wpa/2.0/src/ap/utils.c (from rev 9639, vendor/wpa/dist/src/ap/utils.c)
===================================================================
--- vendor/wpa/2.0/src/ap/utils.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/utils.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,85 @@
+/*
+ * AP mode helper functions
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "sta_info.h"
+#include "hostapd.h"
+
+
+int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
+					   const u8 *ie, size_t ie_len,
+					   int ssi_signal),
+				 void *ctx)
+{
+	struct hostapd_probereq_cb *n;
+
+	n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
+			     sizeof(struct hostapd_probereq_cb));
+	if (n == NULL)
+		return -1;
+
+	hapd->probereq_cb = n;
+	n = &hapd->probereq_cb[hapd->num_probereq_cb];
+	hapd->num_probereq_cb++;
+
+	n->cb = cb;
+	n->ctx = ctx;
+
+	return 0;
+}
+
+
+struct prune_data {
+	struct hostapd_data *hapd;
+	const u8 *addr;
+};
+
+static int prune_associations(struct hostapd_iface *iface, void *ctx)
+{
+	struct prune_data *data = ctx;
+	struct sta_info *osta;
+	struct hostapd_data *ohapd;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		ohapd = iface->bss[j];
+		if (ohapd == data->hapd)
+			continue;
+		osta = ap_get_sta(ohapd, data->addr);
+		if (!osta)
+			continue;
+
+		ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
+	}
+
+	return 0;
+}
+
+/**
+ * hostapd_prune_associations - Remove extraneous associations
+ * @hapd: Pointer to BSS data for the most recent association
+ * @addr: Associated STA address
+ *
+ * This function looks through all radios and BSS's for previous
+ * (stale) associations of STA. If any are found they are removed.
+ */
+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct prune_data data;
+	data.hapd = hapd;
+	data.addr = addr;
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->for_each_interface)
+		hapd->iface->interfaces->for_each_interface(
+			hapd->iface->interfaces, prune_associations, &data);
+}

Deleted: vendor/wpa/2.0/src/ap/vlan_init.c
===================================================================
--- vendor/wpa/dist/src/ap/vlan_init.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/vlan_init.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,903 +0,0 @@
-/*
- * hostapd / VLAN initialization
- * Copyright 2003, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "vlan_init.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>
-
-#include "drivers/priv_netlink.h"
-#include "utils/eloop.h"
-
-
-struct full_dynamic_vlan {
-	int s; /* socket on which to listen for new/removed interfaces. */
-};
-
-
-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;
-}
-
-
-static 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
-*/
-static int vlan_add(const char *if_name, int vid)
-{
-	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)
-{
-	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;
-}
-
-
-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;
-
-	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
-
-	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
-
-			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
-				    vlan->vlan_id);
-
-			if (!br_addbr(br_name))
-				vlan->clean |= DVLAN_CLEAN_BR;
-
-			ifconfig_up(br_name);
-
-			if (tagged_interface) {
-
-				if (!vlan_add(tagged_interface, vlan->vlan_id))
-					vlan->clean |= DVLAN_CLEAN_VLAN;
-
-				os_snprintf(vlan_ifname, sizeof(vlan_ifname),
-					    "vlan%d", vlan->vlan_id);
-
-				if (!br_addif(br_name, vlan_ifname))
-					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
-
-				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;
-
-	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
-
-	first = prev = vlan;
-
-	while (vlan) {
-		if (os_strcmp(ifname, vlan->ifname) == 0) {
-			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) {
-				os_snprintf(vlan_ifname, sizeof(vlan_ifname),
-					    "vlan%d", vlan->vlan_id);
-				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
-					br_delif(br_name, vlan_ifname);
-				ifconfig_down(vlan_ifname);
-
-				if (vlan->clean & DVLAN_CLEAN_VLAN)
-					vlan_rem(vlan_ifname);
-			}
-
-			if ((vlan->clean & DVLAN_CLEAN_BR) &&
-			    br_getnumports(br_name) == 0) {
-				ifconfig_down(br_name);
-				br_delbr(br_name);
-			}
-
-			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;
-
-	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);
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		char ifname[IFNAMSIZ + 1];
-
-		if (attr->rta_type == IFLA_IFNAME) {
-			int n = attr->rta_len - rta_len;
-			if (n < 0)
-				break;
-
-			os_memset(ifname, 0, sizeof(ifname));
-
-			if ((size_t) n > sizeof(ifname))
-				n = sizeof(ifname);
-			os_memcpy(ifname, ((char *) attr) + rta_len, n);
-
-			if (del)
-				vlan_dellink(ifname, hapd);
-			else
-				vlan_newlink(ifname, hapd);
-		}
-
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-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 (left >= (int) sizeof(*h)) {
-		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;
-		}
-
-		len = NLMSG_ALIGN(len);
-		left -= len;
-		h = (struct nlmsghdr *) ((char *) h + len);
-	}
-
-	if (left > 0) {
-		wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
-			   "netlink message", __func__, left);
-	}
-}
-
-
-static 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(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;
-}
-
-
-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);
-}
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
-			      struct hostapd_ssid *mssid, const char *dyn_vlan)
-{
-        int i;
-
-        if (dyn_vlan == NULL)
-		return 0;
-
-	/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
-	 * functions for setting up dynamic broadcast keys. */
-	for (i = 0; i < 4; i++) {
-		if (mssid->wep.key[i] &&
-		    hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
-				      i == mssid->wep.idx, NULL, 0,
-				      mssid->wep.key[i], mssid->wep.len[i])) {
-			wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
-				   "encryption for dynamic VLAN");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static int vlan_dynamic_add(struct hostapd_data *hapd,
-			    struct hostapd_vlan *vlan)
-{
-	while (vlan) {
-		if (vlan->vlan_id != VLAN_ID_WILDCARD) {
-			if (hapd->drv.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;
-				}
-			}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-			ifconfig_up(vlan->ifname);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-		}
-
-		vlan = vlan->next;
-	}
-
-	return 0;
-}
-
-
-static void vlan_dynamic_remove(struct hostapd_data *hapd,
-				struct hostapd_vlan *vlan)
-{
-	struct hostapd_vlan *next;
-
-	while (vlan) {
-		next = vlan->next;
-
-		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
-		    hapd->drv.vlan_if_remove(hapd, vlan->ifname)) {
-			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;
-	}
-}
-
-
-int vlan_init(struct hostapd_data *hapd)
-{
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
-		return -1;
-
-        return 0;
-}
-
-
-void vlan_deinit(struct hostapd_data *hapd)
-{
-	vlan_dynamic_remove(hapd, hapd->conf->vlan);
-
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-}
-
-
-struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
-				       struct hostapd_vlan *vlan,
-				       int vlan_id)
-{
-	struct hostapd_vlan *n;
-	char *ifname, *pos;
-
-	if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
-	    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;
-	pos = os_strchr(ifname, '#');
-	if (pos == NULL) {
-		os_free(ifname);
-		return NULL;
-	}
-	*pos++ = '\0';
-
-	n = os_zalloc(sizeof(*n));
-	if (n == NULL) {
-		os_free(ifname);
-		return NULL;
-	}
-
-	n->vlan_id = vlan_id;
-	n->dynamic_vlan = 1;
-
-	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
-		    pos);
-	os_free(ifname);
-
-	if (hapd->drv.vlan_if_add(hapd, n->ifname)) {
-		os_free(n);
-		return NULL;
-	}
-
-	n->next = hapd->conf->vlan;
-	hapd->conf->vlan = n;
-
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-	ifconfig_up(n->ifname);
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-	return n;
-}
-
-
-int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
-{
-	struct hostapd_vlan *vlan;
-
-	if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
-		return 1;
-
-	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
-
-	vlan = hapd->conf->vlan;
-	while (vlan) {
-		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
-			vlan->dynamic_vlan--;
-			break;
-		}
-		vlan = vlan->next;
-	}
-
-	if (vlan == NULL)
-		return 1;
-
-	if (vlan->dynamic_vlan == 0)
-		hapd->drv.vlan_if_remove(hapd, vlan->ifname);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/ap/vlan_init.c (from rev 9639, vendor/wpa/dist/src/ap/vlan_init.c)
===================================================================
--- vendor/wpa/2.0/src/ap/vlan_init.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/vlan_init.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,934 @@
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "vlan_init.h"
+#include "vlan_util.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>
+
+#include "drivers/priv_netlink.h"
+#include "utils/eloop.h"
+
+
+struct full_dynamic_vlan {
+	int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+
+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)
+{
+	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;
+}
+
+#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;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+	while (vlan) {
+		if (os_strcmp(ifname, vlan->ifname) == 0) {
+
+			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
+				    vlan->vlan_id);
+
+			if (!br_addbr(br_name))
+				vlan->clean |= 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);
+
+				ifconfig_up(tagged_interface);
+				if (!vlan_add(tagged_interface, vlan->vlan_id,
+					      vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN;
+
+				if (!br_addif(br_name, vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+
+				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;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+
+	first = prev = vlan;
+
+	while (vlan) {
+		if (os_strcmp(ifname, vlan->ifname) == 0) {
+			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);
+				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+					br_delif(br_name, vlan_ifname);
+				ifconfig_down(vlan_ifname);
+
+				if (vlan->clean & DVLAN_CLEAN_VLAN)
+					vlan_rem(vlan_ifname);
+			}
+
+			if ((vlan->clean & DVLAN_CLEAN_BR) &&
+			    br_getnumports(br_name) == 0) {
+				ifconfig_down(br_name);
+				br_delbr(br_name);
+			}
+
+			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;
+
+	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);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		char ifname[IFNAMSIZ + 1];
+
+		if (attr->rta_type == IFLA_IFNAME) {
+			int n = attr->rta_len - rta_len;
+			if (n < 0)
+				break;
+
+			os_memset(ifname, 0, sizeof(ifname));
+
+			if ((size_t) n > sizeof(ifname))
+				n = sizeof(ifname);
+			os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+			if (del)
+				vlan_dellink(ifname, hapd);
+			else
+				vlan_newlink(ifname, hapd);
+		}
+
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+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 (left >= (int) sizeof(*h)) {
+		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;
+		}
+
+		len = NLMSG_ALIGN(len);
+		left -= len;
+		h = (struct nlmsghdr *) ((char *) h + len);
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+			   "netlink message", __func__, left);
+	}
+}
+
+
+static 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;
+
+#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 */
+
+	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);
+}
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+			      struct hostapd_ssid *mssid, const char *dyn_vlan)
+{
+        int i;
+
+        if (dyn_vlan == NULL)
+		return 0;
+
+	/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
+	 * functions for setting up dynamic broadcast keys. */
+	for (i = 0; i < 4; i++) {
+		if (mssid->wep.key[i] &&
+		    hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
+					i == mssid->wep.idx, NULL, 0,
+					mssid->wep.key[i], mssid->wep.len[i]))
+		{
+			wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
+				   "encryption for dynamic VLAN");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int vlan_dynamic_add(struct hostapd_data *hapd,
+			    struct hostapd_vlan *vlan)
+{
+	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;
+				}
+			}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+			ifconfig_up(vlan->ifname);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+		}
+
+		vlan = vlan->next;
+	}
+
+	return 0;
+}
+
+
+static void vlan_dynamic_remove(struct hostapd_data *hapd,
+				struct hostapd_vlan *vlan)
+{
+	struct hostapd_vlan *next;
+
+	while (vlan) {
+		next = vlan->next;
+
+		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
+		    hostapd_vlan_if_remove(hapd, vlan->ifname)) {
+			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;
+	}
+}
+
+
+int vlan_init(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
+		return -1;
+
+        return 0;
+}
+
+
+void vlan_deinit(struct hostapd_data *hapd)
+{
+	vlan_dynamic_remove(hapd, hapd->conf->vlan);
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+}
+
+
+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+				       struct hostapd_vlan *vlan,
+				       int vlan_id)
+{
+	struct hostapd_vlan *n;
+	char *ifname, *pos;
+
+	if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
+	    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;
+	pos = os_strchr(ifname, '#');
+	if (pos == NULL) {
+		os_free(ifname);
+		return NULL;
+	}
+	*pos++ = '\0';
+
+	n = os_zalloc(sizeof(*n));
+	if (n == NULL) {
+		os_free(ifname);
+		return NULL;
+	}
+
+	n->vlan_id = vlan_id;
+	n->dynamic_vlan = 1;
+
+	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
+		    pos);
+	os_free(ifname);
+
+	if (hostapd_vlan_if_add(hapd, n->ifname)) {
+		os_free(n);
+		return NULL;
+	}
+
+	n->next = hapd->conf->vlan;
+	hapd->conf->vlan = n;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	ifconfig_up(n->ifname);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	return n;
+}
+
+
+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
+{
+	struct hostapd_vlan *vlan;
+
+	if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+		return 1;
+
+	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
+
+	vlan = hapd->conf->vlan;
+	while (vlan) {
+		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
+			vlan->dynamic_vlan--;
+			break;
+		}
+		vlan = vlan->next;
+	}
+
+	if (vlan == NULL)
+		return 1;
+
+	if (vlan->dynamic_vlan == 0)
+		hostapd_vlan_if_remove(hapd, vlan->ifname);
+
+	return 0;
+}

Copied: vendor/wpa/2.0/src/ap/vlan_util.c (from rev 9639, vendor/wpa/dist/src/ap/vlan_util.c)
===================================================================
--- vendor/wpa/2.0/src/ap/vlan_util.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/vlan_util.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,177 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev at fami-braun.de>
+ *
+ * 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 <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"
+
+/*
+ * Add a vlan interface with name 'vlan_if_name', 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 ret = -1;
+	struct nl_sock *handle = NULL;
+	struct nl_cache *cache = NULL;
+	struct rtnl_link *rlink = NULL;
+	int if_idx = 0;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
+		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
+
+	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   if_name);
+		return -1;
+	}
+
+	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   vlan_if_name);
+		return -1;
+	}
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+		goto vlan_add_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+		cache = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+		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 ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+		/* link does exist */
+		rtnl_link_put(rlink);
+		rlink = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
+			   vlan_if_name);
+		ret = 1;
+		goto vlan_add_error;
+	}
+
+	rlink = rtnl_link_alloc();
+	if (!rlink) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_set_type(rlink, "vlan") < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+		goto vlan_add_error;
+	}
+
+	rtnl_link_set_link(rlink, if_idx);
+	rtnl_link_set_name(rlink, vlan_if_name);
+
+	if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
+			   "vlan %d on %s (%d)",
+			   vlan_if_name, vid, if_name, if_idx);
+		goto vlan_add_error;
+	}
+
+	ret = 0;
+
+vlan_add_error:
+	if (rlink)
+		rtnl_link_put(rlink);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
+
+
+int vlan_rem(const char *if_name)
+{
+	int 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);
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+		goto vlan_rem_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+		goto vlan_rem_error;
+	}
+
+	if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+		cache = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+		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);
+		goto vlan_rem_error;
+	}
+
+	if (rtnl_link_delete(handle, rlink) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
+			   if_name);
+		goto vlan_rem_error;
+	}
+
+	ret = 0;
+
+vlan_rem_error:
+	if (rlink)
+		rtnl_link_put(rlink);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}

Copied: vendor/wpa/2.0/src/ap/vlan_util.h (from rev 9639, vendor/wpa/dist/src/ap/vlan_util.h)
===================================================================
--- vendor/wpa/2.0/src/ap/vlan_util.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/vlan_util.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,15 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev at fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_UTIL_H
+#define VLAN_UTIL_H
+
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
+int vlan_rem(const char *if_name);
+
+#endif /* VLAN_UTIL_H */

Deleted: vendor/wpa/2.0/src/ap/wmm.c
===================================================================
--- vendor/wpa/dist/src/ap/wmm.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wmm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,324 +0,0 @@
-/*
- * hostapd / WMM (Wi-Fi Multimedia)
- * Copyright 2002-2003, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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 "ieee802_11.h"
-#include "sta_info.h"
-#include "ap_config.h"
-#include "wmm.h"
-
-
-/* TODO: maintain separate sequence and fragment numbers for each AC
- * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WMM stations are receiving a certain group */
-
-
-static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
-{
-	u8 ret;
-	ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
-	if (acm)
-		ret |= WMM_AC_ACM;
-	ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
-	return ret;
-}
-
-
-static inline u8 wmm_ecw(int ecwmin, int ecwmax)
-{
-	return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
-		((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
-}
-
-
-/*
- * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
- * Response frames.
- */
-u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-	struct wmm_parameter_element *wmm =
-		(struct wmm_parameter_element *) (pos + 2);
-	int e;
-
-	if (!hapd->conf->wmm_enabled)
-		return eid;
-	eid[0] = WLAN_EID_VENDOR_SPECIFIC;
-	wmm->oui[0] = 0x00;
-	wmm->oui[1] = 0x50;
-	wmm->oui[2] = 0xf2;
-	wmm->oui_type = WMM_OUI_TYPE;
-	wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
-	wmm->version = WMM_VERSION;
-	wmm->qos_info = hapd->parameter_set_count & 0xf;
-
-	if (hapd->conf->wmm_uapsd)
-		wmm->qos_info |= 0x80;
-
-	/* fill in a parameter set record for each AC */
-	for (e = 0; e < 4; e++) {
-		struct wmm_ac_parameter *ac = &wmm->ac[e];
-		struct hostapd_wmm_ac_params *acp =
-			&hapd->iconf->wmm_ac_params[e];
-
-		ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
-					      acp->admission_control_mandatory,
-					      e);
-		ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
-		ac->txop_limit = host_to_le16(acp->txop_limit);
-	}
-
-	pos = (u8 *) (wmm + 1);
-	eid[1] = pos - eid - 2; /* element length */
-
-	return pos;
-}
-
-
-/* This function is called when a station sends an association request with
- * WMM info element. The function returns zero on success or non-zero on any
- * error in WMM element. eid does not include Element ID and Length octets. */
-int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
-{
-	struct wmm_information_element *wmm;
-
-	wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
-
-	if (len < sizeof(struct wmm_information_element)) {
-		wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
-			   (unsigned long) len);
-		return -1;
-	}
-
-	wmm = (struct wmm_information_element *) eid;
-	wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x  "
-		   "OUI type %d  OUI sub-type %d  version %d  QoS info 0x%x",
-		   wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
-		   wmm->oui_subtype, wmm->version, wmm->qos_info);
-	if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
-	    wmm->version != WMM_VERSION) {
-		wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
-			    const struct wmm_tspec_element *tspec,
-			    u8 action_code, u8 dialogue_token, u8 status_code)
-{
-	u8 buf[256];
-	struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
-	struct wmm_tspec_element *t = (struct wmm_tspec_element *)
-		m->u.action.u.wmm_action.variable;
-	int len;
-
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "action response - reason %d", status_code);
-	os_memset(buf, 0, sizeof(buf));
-	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					WLAN_FC_STYPE_ACTION);
-	os_memcpy(m->da, addr, ETH_ALEN);
-	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
-	m->u.action.category = WLAN_ACTION_WMM;
-	m->u.action.u.wmm_action.action_code = action_code;
-	m->u.action.u.wmm_action.dialog_token = dialogue_token;
-	m->u.action.u.wmm_action.status_code = status_code;
-	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
-	len = ((u8 *) (t + 1)) - buf;
-
-	if (hapd->drv.send_mgmt_frame(hapd, m, len) < 0)
-		perror("wmm_send_action: send");
-}
-
-
-int wmm_process_tspec(struct wmm_tspec_element *tspec)
-{
-	int medium_time, pps, duration;
-	int up, psb, dir, tid;
-	u16 val, surplus;
-
-	up = (tspec->ts_info[1] >> 3) & 0x07;
-	psb = (tspec->ts_info[1] >> 2) & 0x01;
-	dir = (tspec->ts_info[0] >> 5) & 0x03;
-	tid = (tspec->ts_info[0] >> 1) & 0x0f;
-	wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
-		   up, psb, dir, tid);
-	val = le_to_host16(tspec->nominal_msdu_size);
-	wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
-		   val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
-	wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
-		   le_to_host32(tspec->mean_data_rate));
-	wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
-		   le_to_host32(tspec->minimum_phy_rate));
-	val = le_to_host16(tspec->surplus_bandwidth_allowance);
-	wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
-		   val >> 13, 10000 * (val & 0x1fff) / 0x2000);
-
-	val = le_to_host16(tspec->nominal_msdu_size);
-	if (val == 0) {
-		wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
-		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
-	}
-	/* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
-	pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
-	wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
-		   pps);
-
-	if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
-		wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
-		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
-	}
-
-	duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
-		(le_to_host32(tspec->minimum_phy_rate) / 1000000) +
-		50 /* FIX: proper SIFS + ACK duration */;
-
-	/* unsigned binary number with an implicit binary point after the
-	 * leftmost 3 bits, i.e., 0x2000 = 1.0 */
-	surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
-	if (surplus <= 0x2000) {
-		wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
-			   "greater than unity");
-		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
-	}
-
-	medium_time = surplus * pps * duration / 0x2000;
-	wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
-
-	/*
-	 * TODO: store list of granted (and still active) TSPECs and check
-	 * whether there is available medium time for this request. For now,
-	 * just refuse requests that would by themselves take very large
-	 * portion of the available bandwidth.
-	 */
-	if (medium_time > 750000) {
-		wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
-			   "75%% of available bandwidth");
-		return WMM_ADDTS_STATUS_REFUSED;
-	}
-
-	/* Convert to 32 microseconds per second unit */
-	tspec->medium_time = host_to_le16(medium_time / 32);
-
-	return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
-}
-
-
-static void wmm_addts_req(struct hostapd_data *hapd,
-			  const struct ieee80211_mgmt *mgmt,
-			  struct wmm_tspec_element *tspec, size_t len)
-{
-	const u8 *end = ((const u8 *) mgmt) + len;
-	int res;
-
-	if ((const u8 *) (tspec + 1) > end) {
-		wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
-		   "from " MACSTR,
-		   mgmt->u.action.u.wmm_action.dialog_token,
-		   MAC2STR(mgmt->sa));
-
-	res = wmm_process_tspec(tspec);
-	wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
-
-	wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
-			mgmt->u.action.u.wmm_action.dialog_token, res);
-}
-
-
-void hostapd_wmm_action(struct hostapd_data *hapd,
-			const struct ieee80211_mgmt *mgmt, size_t len)
-{
-	int action_code;
-	int left = len - IEEE80211_HDRLEN - 4;
-	const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4;
-	struct ieee802_11_elems elems;
-	struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
-
-	/* check that the request comes from a valid station */
-	if (!sta ||
-	    (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
-	    (WLAN_STA_ASSOC | WLAN_STA_WMM)) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "wmm action received is not from associated wmm"
-			       " station");
-		/* TODO: respond with action frame refused status code */
-		return;
-	}
-
-	/* extract the tspec info element */
-	if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "hostapd_wmm_action - could not parse wmm "
-			       "action");
-		/* TODO: respond with action frame invalid parameters status
-		 * code */
-		return;
-	}
-
-	if (!elems.wmm_tspec ||
-	    elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
-		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "hostapd_wmm_action - missing or wrong length "
-			       "tspec");
-		/* TODO: respond with action frame invalid parameters status
-		 * code */
-		return;
-	}
-
-	/* TODO: check the request is for an AC with ACM set, if not, refuse
-	 * request */
-
-	action_code = mgmt->u.action.u.wmm_action.action_code;
-	switch (action_code) {
-	case WMM_ACTION_CODE_ADDTS_REQ:
-		wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
-			      (elems.wmm_tspec - 2), len);
-		return;
-#if 0
-	/* TODO: needed for client implementation */
-	case WMM_ACTION_CODE_ADDTS_RESP:
-		wmm_setup_request(hapd, mgmt, len);
-		return;
-	/* TODO: handle station teardown requests */
-	case WMM_ACTION_CODE_DELTS:
-		wmm_teardown(hapd, mgmt, len);
-		return;
-#endif
-	}
-
-	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "hostapd_wmm_action - unknown action code %d",
-		       action_code);
-}

Copied: vendor/wpa/2.0/src/ap/wmm.c (from rev 9639, vendor/wpa/dist/src/ap/wmm.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wmm.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wmm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,330 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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 "ieee802_11.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wmm.h"
+
+
+/* TODO: maintain separate sequence and fragment numbers for each AC
+ * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
+ * if only WMM stations are receiving a certain group */
+
+
+static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
+{
+	u8 ret;
+	ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
+	if (acm)
+		ret |= WMM_AC_ACM;
+	ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
+	return ret;
+}
+
+
+static inline u8 wmm_ecw(int ecwmin, int ecwmax)
+{
+	return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
+		((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
+}
+
+
+/*
+ * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
+ * Response frames.
+ */
+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	struct wmm_parameter_element *wmm =
+		(struct wmm_parameter_element *) (pos + 2);
+	int e;
+
+	if (!hapd->conf->wmm_enabled)
+		return eid;
+	eid[0] = WLAN_EID_VENDOR_SPECIFIC;
+	wmm->oui[0] = 0x00;
+	wmm->oui[1] = 0x50;
+	wmm->oui[2] = 0xf2;
+	wmm->oui_type = WMM_OUI_TYPE;
+	wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
+	wmm->version = WMM_VERSION;
+	wmm->qos_info = hapd->parameter_set_count & 0xf;
+
+	if (hapd->conf->wmm_uapsd &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+		wmm->qos_info |= 0x80;
+
+	wmm->reserved = 0;
+
+	/* fill in a parameter set record for each AC */
+	for (e = 0; e < 4; e++) {
+		struct wmm_ac_parameter *ac = &wmm->ac[e];
+		struct hostapd_wmm_ac_params *acp =
+			&hapd->iconf->wmm_ac_params[e];
+
+		ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
+					      acp->admission_control_mandatory,
+					      e);
+		ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
+		ac->txop_limit = host_to_le16(acp->txop_limit);
+	}
+
+	pos = (u8 *) (wmm + 1);
+	eid[1] = pos - eid - 2; /* element length */
+
+	return pos;
+}
+
+
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
+{
+	struct wmm_information_element *wmm;
+
+	wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
+
+	if (len < sizeof(struct wmm_information_element)) {
+		wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
+			   (unsigned long) len);
+		return 0;
+	}
+
+	wmm = (struct wmm_information_element *) eid;
+	wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x  "
+		   "OUI type %d  OUI sub-type %d  version %d  QoS info 0x%x",
+		   wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
+		   wmm->oui_subtype, wmm->version, wmm->qos_info);
+	if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
+	    wmm->version != WMM_VERSION) {
+		wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
+			    const struct wmm_tspec_element *tspec,
+			    u8 action_code, u8 dialogue_token, u8 status_code)
+{
+	u8 buf[256];
+	struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
+	struct wmm_tspec_element *t = (struct wmm_tspec_element *)
+		m->u.action.u.wmm_action.variable;
+	int len;
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "action response - reason %d", status_code);
+	os_memset(buf, 0, sizeof(buf));
+	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					WLAN_FC_STYPE_ACTION);
+	os_memcpy(m->da, addr, ETH_ALEN);
+	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+	m->u.action.category = WLAN_ACTION_WMM;
+	m->u.action.u.wmm_action.action_code = action_code;
+	m->u.action.u.wmm_action.dialog_token = dialogue_token;
+	m->u.action.u.wmm_action.status_code = status_code;
+	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
+	len = ((u8 *) (t + 1)) - buf;
+
+	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+		perror("wmm_send_action: send");
+}
+
+
+int wmm_process_tspec(struct wmm_tspec_element *tspec)
+{
+	int medium_time, pps, duration;
+	int up, psb, dir, tid;
+	u16 val, surplus;
+
+	up = (tspec->ts_info[1] >> 3) & 0x07;
+	psb = (tspec->ts_info[1] >> 2) & 0x01;
+	dir = (tspec->ts_info[0] >> 5) & 0x03;
+	tid = (tspec->ts_info[0] >> 1) & 0x0f;
+	wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
+		   up, psb, dir, tid);
+	val = le_to_host16(tspec->nominal_msdu_size);
+	wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
+		   val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
+	wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
+		   le_to_host32(tspec->mean_data_rate));
+	wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
+		   le_to_host32(tspec->minimum_phy_rate));
+	val = le_to_host16(tspec->surplus_bandwidth_allowance);
+	wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
+		   val >> 13, 10000 * (val & 0x1fff) / 0x2000);
+
+	val = le_to_host16(tspec->nominal_msdu_size);
+	if (val == 0) {
+		wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+	/* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
+	pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
+	wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
+		   pps);
+
+	if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
+		wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+
+	duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
+		(le_to_host32(tspec->minimum_phy_rate) / 1000000) +
+		50 /* FIX: proper SIFS + ACK duration */;
+
+	/* unsigned binary number with an implicit binary point after the
+	 * leftmost 3 bits, i.e., 0x2000 = 1.0 */
+	surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
+	if (surplus <= 0x2000) {
+		wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
+			   "greater than unity");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+
+	medium_time = surplus * pps * duration / 0x2000;
+	wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+
+	/*
+	 * TODO: store list of granted (and still active) TSPECs and check
+	 * whether there is available medium time for this request. For now,
+	 * just refuse requests that would by themselves take very large
+	 * portion of the available bandwidth.
+	 */
+	if (medium_time > 750000) {
+		wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
+			   "75%% of available bandwidth");
+		return WMM_ADDTS_STATUS_REFUSED;
+	}
+
+	/* Convert to 32 microseconds per second unit */
+	tspec->medium_time = host_to_le16(medium_time / 32);
+
+	return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
+}
+
+
+static void wmm_addts_req(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt,
+			  struct wmm_tspec_element *tspec, size_t len)
+{
+	const u8 *end = ((const u8 *) mgmt) + len;
+	int res;
+
+	if ((const u8 *) (tspec + 1) > end) {
+		wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
+		   "from " MACSTR,
+		   mgmt->u.action.u.wmm_action.dialog_token,
+		   MAC2STR(mgmt->sa));
+
+	res = wmm_process_tspec(tspec);
+	wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
+
+	wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+			mgmt->u.action.u.wmm_action.dialog_token, res);
+}
+
+
+void hostapd_wmm_action(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	int action_code;
+	int left = len - IEEE80211_HDRLEN - 4;
+	const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4;
+	struct ieee802_11_elems elems;
+	struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
+
+	/* check that the request comes from a valid station */
+	if (!sta ||
+	    (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
+	    (WLAN_STA_ASSOC | WLAN_STA_WMM)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "wmm action received is not from associated wmm"
+			       " station");
+		/* TODO: respond with action frame refused status code */
+		return;
+	}
+
+	/* extract the tspec info element */
+	if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wmm_action - could not parse wmm "
+			       "action");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	if (!elems.wmm_tspec ||
+	    elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wmm_action - missing or wrong length "
+			       "tspec");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	/* TODO: check the request is for an AC with ACM set, if not, refuse
+	 * request */
+
+	action_code = mgmt->u.action.u.wmm_action.action_code;
+	switch (action_code) {
+	case WMM_ACTION_CODE_ADDTS_REQ:
+		wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
+			      (elems.wmm_tspec - 2), len);
+		return;
+#if 0
+	/* TODO: needed for client implementation */
+	case WMM_ACTION_CODE_ADDTS_RESP:
+		wmm_setup_request(hapd, mgmt, len);
+		return;
+	/* TODO: handle station teardown requests */
+	case WMM_ACTION_CODE_DELTS:
+		wmm_teardown(hapd, mgmt, len);
+		return;
+#endif
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "hostapd_wmm_action - unknown action code %d",
+		       action_code);
+}

Copied: vendor/wpa/2.0/src/ap/wnm_ap.c (from rev 9639, vendor/wpa/dist/src/ap/wnm_ap.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wnm_ap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wnm_ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,271 @@
+/*
+ * hostapd - WNM
+ * Copyright (c) 2011-2012, 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 "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
+#include "wnm_ap.h"
+
+#define MAX_TFS_IE_LEN  1024
+
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+				   u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+	return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+				   u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+	return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.response */
+static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
+					 const u8 *addr, u8 dialog_token,
+					 u8 action_type, u16 intval)
+{
+	struct ieee80211_mgmt *mgmt;
+	int res;
+	size_t len;
+	size_t gtk_elem_len = 0;
+	size_t igtk_elem_len = 0;
+	struct wnm_sleep_element wnmsleep_ie;
+	u8 *wnmtfs_ie;
+	u8 wnmsleep_ie_len;
+	u16 wnmtfs_ie_len;
+	u8 *pos;
+	struct sta_info *sta;
+	enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
+		WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+		return -EINVAL;
+	}
+
+	/* WNM-Sleep Mode IE */
+	os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
+	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+	wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
+	wnmsleep_ie.len = wnmsleep_ie_len - 2;
+	wnmsleep_ie.action_type = action_type;
+	wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
+	wnmsleep_ie.intval = intval;
+
+	/* TFS IE(s) */
+	wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+	if (wnmtfs_ie == NULL)
+		return -1;
+	if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
+				    tfs_oper)) {
+		wnmtfs_ie_len = 0;
+		os_free(wnmtfs_ie);
+		wnmtfs_ie = NULL;
+	}
+
+#define MAX_GTK_SUBELEM_LEN 45
+#define MAX_IGTK_SUBELEM_LEN 26
+	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
+			 MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+	if (mgmt == NULL) {
+		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+			   "WNM-Sleep Response action frame");
+		return -1;
+	}
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP;
+	mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
+	pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
+	/* add key data if MFP is enabled */
+	if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+	    action_type != WNM_SLEEP_MODE_EXIT) {
+		mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
+	} else {
+		gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
+		pos += gtk_elem_len;
+		wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
+			   (int) gtk_elem_len);
+#ifdef CONFIG_IEEE80211W
+		res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
+		if (res < 0) {
+			os_free(wnmtfs_ie);
+			os_free(mgmt);
+			return -1;
+		}
+		igtk_elem_len = res;
+		pos += igtk_elem_len;
+		wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
+			   (int) igtk_elem_len);
+#endif /* CONFIG_IEEE80211W */
+
+		WPA_PUT_LE16((u8 *)
+			     &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
+			     gtk_elem_len + igtk_elem_len);
+	}
+	os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
+	/* copy TFS IE here */
+	pos += wnmsleep_ie_len;
+	if (wnmtfs_ie)
+		os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+
+	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
+		igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+
+	/* In driver, response frame should be forced to sent when STA is in
+	 * PS mode */
+	res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+				      mgmt->da, &mgmt->u.action.category, len);
+
+	if (!res) {
+		wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
+			   "frame");
+
+		/* when entering wnmsleep
+		 * 1. pause the node in driver
+		 * 2. mark the node so that AP won't update GTK/IGTK during
+		 * WNM Sleep
+		 */
+		if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
+			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
+					     addr, NULL, NULL);
+			wpa_set_wnmsleep(sta->wpa_sm, 1);
+		}
+		/* when exiting wnmsleep
+		 * 1. unmark the node
+		 * 2. start GTK/IGTK update if MFP is not used
+		 * 3. unpause the node in driver
+		 */
+		if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
+		     wnmsleep_ie.status ==
+		     WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
+		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
+			wpa_set_wnmsleep(sta->wpa_sm, 0);
+			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
+					     addr, NULL, NULL);
+			if (!wpa_auth_uses_mfp(sta->wpa_sm))
+				wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
+		}
+	} else
+		wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
+
+#undef MAX_GTK_SUBELEM_LEN
+#undef MAX_IGTK_SUBELEM_LEN
+	os_free(wnmtfs_ie);
+	os_free(mgmt);
+	return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
+				       const u8 *addr, const u8 *frm, int len)
+{
+	/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
+	const u8 *pos = frm;
+	u8 dialog_token;
+	struct wnm_sleep_element *wnmsleep_ie = NULL;
+	/* multiple TFS Req IE (assuming consecutive) */
+	u8 *tfsreq_ie_start = NULL;
+	u8 *tfsreq_ie_end = NULL;
+	u16 tfsreq_ie_len = 0;
+
+	dialog_token = *pos++;
+	while (pos + 1 < frm + len) {
+		u8 ie_len = pos[1];
+		if (pos + 2 + ie_len > frm + len)
+			break;
+		if (*pos == WLAN_EID_WNMSLEEP)
+			wnmsleep_ie = (struct wnm_sleep_element *) pos;
+		else if (*pos == WLAN_EID_TFS_REQ) {
+			if (!tfsreq_ie_start)
+				tfsreq_ie_start = (u8 *) pos;
+			tfsreq_ie_end = (u8 *) pos;
+		} else
+			wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
+				   *pos);
+		pos += ie_len + 2;
+	}
+
+	if (!wnmsleep_ie) {
+		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+		return;
+	}
+
+	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
+	    tfsreq_ie_start && tfsreq_ie_end &&
+	    tfsreq_ie_end - tfsreq_ie_start >= 0) {
+		tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
+			tfsreq_ie_start;
+		wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
+		/* pass the TFS Req IE(s) to driver for processing */
+		if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+					    &tfsreq_ie_len,
+					    WNM_SLEEP_TFS_REQ_IE_SET))
+			wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
+	}
+
+	ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
+				      wnmsleep_ie->action_type,
+				      wnmsleep_ie->intval);
+
+	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
+		/* clear the tfs after sending the resp frame */
+		ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+					&tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
+	}
+}
+
+
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+				struct rx_action *action)
+{
+	if (action->len < 1 || action->data == NULL)
+		return -1;
+
+	switch (action->data[0]) {
+	case WNM_BSS_TRANS_MGMT_QUERY:
+		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
+		/* TODO */
+		return -1;
+	case WNM_BSS_TRANS_MGMT_RESP:
+		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+			   "Response");
+		/* TODO */
+		return -1;
+	case WNM_SLEEP_MODE_REQ:
+		ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
+					   action->len - 1);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
+		   action->data[0], MAC2STR(action->sa));
+	return -1;
+}

Copied: vendor/wpa/2.0/src/ap/wnm_ap.h (from rev 9639, vendor/wpa/dist/src/ap/wnm_ap.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wnm_ap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wnm_ap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,17 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_AP_H
+#define WNM_AP_H
+
+struct rx_action;
+
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+				struct rx_action *action);
+
+#endif /* WNM_AP_H */

Deleted: vendor/wpa/2.0/src/ap/wpa_auth.c
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2651 +0,0 @@
-/*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/state_machine.h"
-#include "common/ieee802_11_defs.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "wpa_auth.h"
-#include "pmksa_cache_auth.h"
-#include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
-
-#define STATE_MACHINE_DATA struct wpa_state_machine
-#define STATE_MACHINE_DEBUG_PREFIX "WPA"
-#define STATE_MACHINE_ADDR sm->addr
-
-
-static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
-static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
-static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
-static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
-			      struct wpa_group *group);
-static void wpa_request_new_ptk(struct wpa_state_machine *sm);
-static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
-			  struct wpa_group *group);
-
-static const u32 dot11RSNAConfigGroupUpdateCount = 4;
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
-static const u32 eapol_key_timeout_first = 100; /* ms */
-static const u32 eapol_key_timeout_subseq = 1000; /* ms */
-
-/* TODO: make these configurable */
-static const int dot11RSNAConfigPMKLifetime = 43200;
-static const int dot11RSNAConfigPMKReauthThreshold = 70;
-static const int dot11RSNAConfigSATimeout = 60;
-
-
-static inline void wpa_auth_mic_failure_report(
-	struct wpa_authenticator *wpa_auth, const u8 *addr)
-{
-	if (wpa_auth->cb.mic_failure_report)
-		wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
-}
-
-
-static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
-				      const u8 *addr, wpa_eapol_variable var,
-				      int value)
-{
-	if (wpa_auth->cb.set_eapol)
-		wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
-}
-
-
-static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
-				     const u8 *addr, wpa_eapol_variable var)
-{
-	if (wpa_auth->cb.get_eapol == NULL)
-		return -1;
-	return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
-}
-
-
-static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
-					  const u8 *addr, const u8 *prev_psk)
-{
-	if (wpa_auth->cb.get_psk == NULL)
-		return NULL;
-	return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
-}
-
-
-static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
-				   const u8 *addr, u8 *msk, size_t *len)
-{
-	if (wpa_auth->cb.get_msk == NULL)
-		return -1;
-	return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
-}
-
-
-static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
-				   int vlan_id,
-				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
-{
-	if (wpa_auth->cb.set_key == NULL)
-		return -1;
-	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
-				    key, key_len);
-}
-
-
-static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
-				      const u8 *addr, int idx, u8 *seq)
-{
-	if (wpa_auth->cb.get_seqnum == NULL)
-		return -1;
-	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
-}
-
-
-static inline int
-wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
-		    const u8 *data, size_t data_len, int encrypt)
-{
-	if (wpa_auth->cb.send_eapol == NULL)
-		return -1;
-	return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
-				       encrypt);
-}
-
-
-int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
-			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
-			  void *cb_ctx)
-{
-	if (wpa_auth->cb.for_each_sta == NULL)
-		return 0;
-	return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
-}
-
-
-int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
-			   int (*cb)(struct wpa_authenticator *a, void *ctx),
-			   void *cb_ctx)
-{
-	if (wpa_auth->cb.for_each_auth == NULL)
-		return 0;
-	return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
-}
-
-
-void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
-		     logger_level level, const char *txt)
-{
-	if (wpa_auth->cb.logger == NULL)
-		return;
-	wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
-}
-
-
-void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
-		      logger_level level, const char *fmt, ...)
-{
-	char *format;
-	int maxlen;
-	va_list ap;
-
-	if (wpa_auth->cb.logger == NULL)
-		return;
-
-	maxlen = os_strlen(fmt) + 100;
-	format = os_malloc(maxlen);
-	if (!format)
-		return;
-
-	va_start(ap, fmt);
-	vsnprintf(format, maxlen, fmt, ap);
-	va_end(ap);
-
-	wpa_auth_logger(wpa_auth, addr, level, format);
-
-	os_free(format);
-}
-
-
-static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
-			       const u8 *addr)
-{
-	if (wpa_auth->cb.disconnect == NULL)
-		return;
-	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
-				WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
-{
-	int ret = 0;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-		ret = 1;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
-		ret = 1;
-#endif /* CONFIG_IEEE80211W */
-	return ret;
-}
-
-
-static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-
-	if (os_get_random(wpa_auth->group->GMK, WPA_GMK_LEN)) {
-		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
-			   "initialization.");
-	} else {
-		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
-	}
-
-	if (wpa_auth->conf.wpa_gmk_rekey) {
-		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
-				       wpa_rekey_gmk, wpa_auth, NULL);
-	}
-}
-
-
-static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_group *group;
-
-	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
-	for (group = wpa_auth->group; group; group = group->next) {
-		group->GTKReKey = TRUE;
-		do {
-			group->changed = FALSE;
-			wpa_group_sm_step(wpa_auth, group);
-		} while (group->changed);
-	}
-
-	if (wpa_auth->conf.wpa_group_rekey) {
-		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
-				       0, wpa_rekey_gtk, wpa_auth, NULL);
-	}
-}
-
-
-static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_state_machine *sm = timeout_ctx;
-
-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
-	wpa_request_new_ptk(sm);
-	wpa_sm_step(sm);
-}
-
-
-static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
-{
-	if (sm->pmksa == ctx)
-		sm->pmksa = NULL;
-	return 0;
-}
-
-
-static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
-				   void *ctx)
-{
-	struct wpa_authenticator *wpa_auth = ctx;
-	wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
-}
-
-
-static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_CCMP:
-		group->GTK_len = 16;
-		break;
-	case WPA_CIPHER_TKIP:
-		group->GTK_len = 32;
-		break;
-	case WPA_CIPHER_WEP104:
-		group->GTK_len = 13;
-		break;
-	case WPA_CIPHER_WEP40:
-		group->GTK_len = 5;
-		break;
-	}
-}
-
-
-static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-					 int vlan_id)
-{
-	struct wpa_group *group;
-	u8 buf[ETH_ALEN + 8 + sizeof(group)];
-	u8 rkey[32];
-
-	group = os_zalloc(sizeof(struct wpa_group));
-	if (group == NULL)
-		return NULL;
-
-	group->GTKAuthenticator = TRUE;
-	group->vlan_id = vlan_id;
-
-	wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
-
-	/* Counter = PRF-256(Random number, "Init Counter",
-	 *                   Local MAC Address || Time)
-	 */
-	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
-	wpa_get_ntp_timestamp(buf + ETH_ALEN);
-	os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
-	if (os_get_random(rkey, sizeof(rkey)) ||
-	    os_get_random(group->GMK, WPA_GMK_LEN)) {
-		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
-			   "initialization.");
-		os_free(group);
-		return NULL;
-	}
-
-	sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
-		 group->Counter, WPA_NONCE_LEN);
-
-	group->GInit = TRUE;
-	wpa_group_sm_step(wpa_auth, group);
-	group->GInit = FALSE;
-	wpa_group_sm_step(wpa_auth, group);
-
-	return group;
-}
-
-
-/**
- * wpa_init - Initialize WPA authenticator
- * @addr: Authenticator address
- * @conf: Configuration for WPA authenticator
- * @cb: Callback functions for WPA authenticator
- * Returns: Pointer to WPA authenticator data or %NULL on failure
- */
-struct wpa_authenticator * wpa_init(const u8 *addr,
-				    struct wpa_auth_config *conf,
-				    struct wpa_auth_callbacks *cb)
-{
-	struct wpa_authenticator *wpa_auth;
-
-	wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
-	if (wpa_auth == NULL)
-		return NULL;
-	os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
-	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
-	os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
-
-	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
-		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
-		os_free(wpa_auth);
-		return NULL;
-	}
-
-	wpa_auth->group = wpa_group_init(wpa_auth, 0);
-	if (wpa_auth->group == NULL) {
-		os_free(wpa_auth->wpa_ie);
-		os_free(wpa_auth);
-		return NULL;
-	}
-
-	wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
-						wpa_auth);
-	if (wpa_auth->pmksa == NULL) {
-		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
-		os_free(wpa_auth->wpa_ie);
-		os_free(wpa_auth);
-		return NULL;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
-	if (wpa_auth->ft_pmk_cache == NULL) {
-		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
-		os_free(wpa_auth->wpa_ie);
-		pmksa_cache_auth_deinit(wpa_auth->pmksa);
-		os_free(wpa_auth);
-		return NULL;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (wpa_auth->conf.wpa_gmk_rekey) {
-		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
-				       wpa_rekey_gmk, wpa_auth, NULL);
-	}
-
-	if (wpa_auth->conf.wpa_group_rekey) {
-		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
-				       wpa_rekey_gtk, wpa_auth, NULL);
-	}
-
-	return wpa_auth;
-}
-
-
-/**
- * wpa_deinit - Deinitialize WPA authenticator
- * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
- */
-void wpa_deinit(struct wpa_authenticator *wpa_auth)
-{
-	struct wpa_group *group, *prev;
-
-	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
-	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-
-#ifdef CONFIG_PEERKEY
-	while (wpa_auth->stsl_negotiations)
-		wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
-#endif /* CONFIG_PEERKEY */
-
-	pmksa_cache_auth_deinit(wpa_auth->pmksa);
-
-#ifdef CONFIG_IEEE80211R
-	wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
-	wpa_auth->ft_pmk_cache = NULL;
-#endif /* CONFIG_IEEE80211R */
-
-	os_free(wpa_auth->wpa_ie);
-
-	group = wpa_auth->group;
-	while (group) {
-		prev = group;
-		group = group->next;
-		os_free(prev);
-	}
-
-	os_free(wpa_auth);
-}
-
-
-/**
- * wpa_reconfig - Update WPA authenticator configuration
- * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
- * @conf: Configuration for WPA authenticator
- */
-int wpa_reconfig(struct wpa_authenticator *wpa_auth,
-		 struct wpa_auth_config *conf)
-{
-	struct wpa_group *group;
-	if (wpa_auth == NULL)
-		return 0;
-
-	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
-	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
-		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
-		return -1;
-	}
-
-	/*
-	 * Reinitialize GTK to make sure it is suitable for the new
-	 * configuration.
-	 */
-	group = wpa_auth->group;
-	wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
-	group->GInit = TRUE;
-	wpa_group_sm_step(wpa_auth, group);
-	group->GInit = FALSE;
-	wpa_group_sm_step(wpa_auth, group);
-
-	return 0;
-}
-
-
-struct wpa_state_machine *
-wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
-{
-	struct wpa_state_machine *sm;
-
-	sm = os_zalloc(sizeof(struct wpa_state_machine));
-	if (sm == NULL)
-		return NULL;
-	os_memcpy(sm->addr, addr, ETH_ALEN);
-
-	sm->wpa_auth = wpa_auth;
-	sm->group = wpa_auth->group;
-
-	return sm;
-}
-
-
-int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
-			    struct wpa_state_machine *sm)
-{
-	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
-		return -1;
-
-#ifdef CONFIG_IEEE80211R
-	if (sm->ft_completed) {
-		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-				"FT authentication already completed - do not "
-				"start 4-way handshake");
-		return 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (sm->started) {
-		os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
-		sm->ReAuthenticationRequest = TRUE;
-		return wpa_sm_step(sm);
-	}
-
-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-			"start authentication");
-	sm->started = 1;
-
-	sm->Init = TRUE;
-	if (wpa_sm_step(sm) == 1)
-		return 1; /* should not really happen */
-	sm->Init = FALSE;
-	sm->AuthenticationRequest = TRUE;
-	return wpa_sm_step(sm);
-}
-
-
-void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
-{
-	/* WPA/RSN was not used - clear WPA state. This is needed if the STA
-	 * reassociates back to the same AP while the previous entry for the
-	 * STA has not yet been removed. */
-	if (sm == NULL)
-		return;
-
-	sm->wpa_key_mgmt = 0;
-}
-
-
-static void wpa_free_sta_sm(struct wpa_state_machine *sm)
-{
-#ifdef CONFIG_IEEE80211R
-	os_free(sm->assoc_resp_ftie);
-#endif /* CONFIG_IEEE80211R */
-	os_free(sm->last_rx_eapol_key);
-	os_free(sm->wpa_ie);
-	os_free(sm);
-}
-
-
-void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return;
-
-	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"strict rekeying - force GTK rekey since STA "
-				"is leaving");
-		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
-		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
-				       NULL);
-	}
-
-	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
-	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
-	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
-	if (sm->in_step_loop) {
-		/* Must not free state machine while wpa_sm_step() is running.
-		 * Freeing will be completed in the end of wpa_sm_step(). */
-		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
-			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
-		sm->pending_deinit = 1;
-	} else
-		wpa_free_sta_sm(sm);
-}
-
-
-static void wpa_request_new_ptk(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return;
-
-	sm->PTKRequest = TRUE;
-	sm->PTK_valid = 0;
-}
-
-
-static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
-				    const u8 *replay_counter)
-{
-	int i;
-	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
-		if (!sm->key_replay[i].valid)
-			break;
-		if (os_memcmp(replay_counter, sm->key_replay[i].counter,
-			      WPA_REPLAY_COUNTER_LEN) == 0)
-			return 1;
-	}
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
-			       struct wpa_state_machine *sm,
-			       struct wpa_eapol_ie_parse *kde)
-{
-	struct wpa_ie_data ie;
-	struct rsn_mdie *mdie;
-
-	if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
-	    ie.num_pmkid != 1 || ie.pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
-			   "FT 4-way handshake message 2/4");
-		return -1;
-	}
-
-	os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
-		    sm->sup_pmk_r1_name, PMKID_LEN);
-
-	if (!kde->mdie || !kde->ftie) {
-		wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
-			   "message 2/4", kde->mdie ? "FTIE" : "MDIE");
-		return -1;
-	}
-
-	mdie = (struct rsn_mdie *) (kde->mdie + 2);
-	if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
-	    os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
-		return -1;
-	}
-
-	if (sm->assoc_resp_ftie &&
-	    (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
-	     os_memcmp(kde->ftie, sm->assoc_resp_ftie,
-		       2 + sm->assoc_resp_ftie[1]) != 0)) {
-		wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
-		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
-			    kde->ftie, kde->ftie_len);
-		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
-			    sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
-		return -1;
-	}
-
-	return 0;
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-void wpa_receive(struct wpa_authenticator *wpa_auth,
-		 struct wpa_state_machine *sm,
-		 u8 *data, size_t data_len)
-{
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *key;
-	u16 key_info, key_data_length;
-	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
-	       SMK_M1, SMK_M3, SMK_ERROR } msg;
-	char *msgtxt;
-	struct wpa_eapol_ie_parse kde;
-	int ft;
-	const u8 *eapol_key_ie;
-	size_t eapol_key_ie_len;
-
-	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
-		return;
-
-	if (data_len < sizeof(*hdr) + sizeof(*key))
-		return;
-
-	hdr = (struct ieee802_1x_hdr *) data;
-	key = (struct wpa_eapol_key *) (hdr + 1);
-	key_info = WPA_GET_BE16(key->key_info);
-	key_data_length = WPA_GET_BE16(key->key_data_length);
-	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
-		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
-			   "key_data overflow (%d > %lu)",
-			   key_data_length,
-			   (unsigned long) (data_len - sizeof(*hdr) -
-					    sizeof(*key)));
-		return;
-	}
-
-	if (sm->wpa == WPA_VERSION_WPA2) {
-		if (key->type != EAPOL_KEY_TYPE_RSN) {
-			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
-				   "unexpected type %d in RSN mode",
-				   key->type);
-			return;
-		}
-	} else {
-		if (key->type != EAPOL_KEY_TYPE_WPA) {
-			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
-				   "unexpected type %d in WPA mode",
-				   key->type);
-			return;
-		}
-	}
-
-	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
-	 * are set */
-
-	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
-	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
-		if (key_info & WPA_KEY_INFO_ERROR) {
-			msg = SMK_ERROR;
-			msgtxt = "SMK Error";
-		} else {
-			msg = SMK_M1;
-			msgtxt = "SMK M1";
-		}
-	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
-		msg = SMK_M3;
-		msgtxt = "SMK M3";
-	} else if (key_info & WPA_KEY_INFO_REQUEST) {
-		msg = REQUEST;
-		msgtxt = "Request";
-	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
-		msg = GROUP_2;
-		msgtxt = "2/2 Group";
-	} else if (key_data_length == 0) {
-		msg = PAIRWISE_4;
-		msgtxt = "4/4 Pairwise";
-	} else {
-		msg = PAIRWISE_2;
-		msgtxt = "2/4 Pairwise";
-	}
-
-	/* TODO: key_info type validation for PeerKey */
-	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
-	    msg == GROUP_2) {
-		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-		if (sm->pairwise == WPA_CIPHER_CCMP) {
-			if (wpa_use_aes_cmac(sm) &&
-			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-				wpa_auth_logger(wpa_auth, sm->addr,
-						LOGGER_WARNING,
-						"advertised support for "
-						"AES-128-CMAC, but did not "
-						"use it");
-				return;
-			}
-
-			if (!wpa_use_aes_cmac(sm) &&
-			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-				wpa_auth_logger(wpa_auth, sm->addr,
-						LOGGER_WARNING,
-						"did not use HMAC-SHA1-AES "
-						"with CCMP");
-				return;
-			}
-		}
-	}
-
-	if (key_info & WPA_KEY_INFO_REQUEST) {
-		if (sm->req_replay_counter_used &&
-		    os_memcmp(key->replay_counter, sm->req_replay_counter,
-			      WPA_REPLAY_COUNTER_LEN) <= 0) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
-					"received EAPOL-Key request with "
-					"replayed counter");
-			return;
-		}
-	}
-
-	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
-	    !wpa_replay_counter_valid(sm, key->replay_counter)) {
-		int i;
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-				 "received EAPOL-Key %s with unexpected "
-				 "replay counter", msgtxt);
-		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
-			if (!sm->key_replay[i].valid)
-				break;
-			wpa_hexdump(MSG_DEBUG, "pending replay counter",
-				    sm->key_replay[i].counter,
-				    WPA_REPLAY_COUNTER_LEN);
-		}
-		wpa_hexdump(MSG_DEBUG, "received replay counter",
-			    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
-		return;
-	}
-
-	switch (msg) {
-	case PAIRWISE_2:
-		if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
-		    sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) {
-			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 2/4 in "
-					 "invalid state (%d) - dropped",
-					 sm->wpa_ptk_state);
-			return;
-		}
-		if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
-				      &kde) < 0) {
-			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 2/4 with "
-					 "invalid Key Data contents");
-			return;
-		}
-		if (kde.rsn_ie) {
-			eapol_key_ie = kde.rsn_ie;
-			eapol_key_ie_len = kde.rsn_ie_len;
-		} else {
-			eapol_key_ie = kde.wpa_ie;
-			eapol_key_ie_len = kde.wpa_ie_len;
-		}
-		ft = sm->wpa == WPA_VERSION_WPA2 &&
-			wpa_key_mgmt_ft(sm->wpa_key_mgmt);
-		if (sm->wpa_ie == NULL ||
-		    wpa_compare_rsn_ie(ft,
-				       sm->wpa_ie, sm->wpa_ie_len,
-				       eapol_key_ie, eapol_key_ie_len)) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"WPA IE from (Re)AssocReq did not "
-					"match with msg 2/4");
-			if (sm->wpa_ie) {
-				wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
-					    sm->wpa_ie, sm->wpa_ie_len);
-			}
-			wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
-				    eapol_key_ie, eapol_key_ie_len);
-			/* MLME-DEAUTHENTICATE.request */
-			wpa_sta_disconnect(wpa_auth, sm->addr);
-			return;
-		}
-#ifdef CONFIG_IEEE80211R
-		if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
-			wpa_sta_disconnect(wpa_auth, sm->addr);
-			return;
-		}
-#endif /* CONFIG_IEEE80211R */
-		break;
-	case PAIRWISE_4:
-		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
-		    !sm->PTK_valid) {
-			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 4/4 in "
-					 "invalid state (%d) - dropped",
-					 sm->wpa_ptk_state);
-			return;
-		}
-		break;
-	case GROUP_2:
-		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
-		    || !sm->PTK_valid) {
-			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
-					 "received EAPOL-Key msg 2/2 in "
-					 "invalid state (%d) - dropped",
-					 sm->wpa_ptk_group_state);
-			return;
-		}
-		break;
-#ifdef CONFIG_PEERKEY
-	case SMK_M1:
-	case SMK_M3:
-	case SMK_ERROR:
-		if (!wpa_auth->conf.peerkey) {
-			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
-				   "PeerKey use disabled - ignoring message");
-			return;
-		}
-		if (!sm->PTK_valid) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key msg SMK in "
-					"invalid state - dropped");
-			return;
-		}
-		break;
-#else /* CONFIG_PEERKEY */
-	case SMK_M1:
-	case SMK_M3:
-	case SMK_ERROR:
-		return; /* STSL disabled - ignore SMK messages */
-#endif /* CONFIG_PEERKEY */
-	case REQUEST:
-		break;
-	}
-
-	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-			 "received EAPOL-Key frame (%s)", msgtxt);
-
-	if (key_info & WPA_KEY_INFO_ACK) {
-		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-				"received invalid EAPOL-Key: Key Ack set");
-		return;
-	}
-
-	if (!(key_info & WPA_KEY_INFO_MIC)) {
-		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-				"received invalid EAPOL-Key: Key MIC not set");
-		return;
-	}
-
-	sm->MICVerified = FALSE;
-	if (sm->PTK_valid) {
-		if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key with invalid MIC");
-			return;
-		}
-		sm->MICVerified = TRUE;
-		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
-	}
-
-	if (key_info & WPA_KEY_INFO_REQUEST) {
-		if (sm->MICVerified) {
-			sm->req_replay_counter_used = 1;
-			os_memcpy(sm->req_replay_counter, key->replay_counter,
-				  WPA_REPLAY_COUNTER_LEN);
-		} else {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key request with "
-					"invalid MIC");
-			return;
-		}
-
-		/*
-		 * TODO: should decrypt key data field if encryption was used;
-		 * even though MAC address KDE is not normally encrypted,
-		 * supplicant is allowed to encrypt it.
-		 */
-		if (msg == SMK_ERROR) {
-#ifdef CONFIG_PEERKEY
-			wpa_smk_error(wpa_auth, sm, key);
-#endif /* CONFIG_PEERKEY */
-			return;
-		} else if (key_info & WPA_KEY_INFO_ERROR) {
-			/* Supplicant reported a Michael MIC error */
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Error Request "
-					"(STA detected Michael MIC failure)");
-			wpa_auth_mic_failure_report(wpa_auth, sm->addr);
-			sm->dot11RSNAStatsTKIPRemoteMICFailures++;
-			wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
-			/* Error report is not a request for a new key
-			 * handshake, but since Authenticator may do it, let's
-			 * change the keys now anyway. */
-			wpa_request_new_ptk(sm);
-		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Request for new "
-					"4-Way Handshake");
-			wpa_request_new_ptk(sm);
-#ifdef CONFIG_PEERKEY
-		} else if (msg == SMK_M1) {
-			wpa_smk_m1(wpa_auth, sm, key);
-#endif /* CONFIG_PEERKEY */
-		} else if (key_data_length > 0 &&
-			   wpa_parse_kde_ies((const u8 *) (key + 1),
-					     key_data_length, &kde) == 0 &&
-			   kde.mac_addr) {
-		} else {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Request for GTK "
-					"rekeying");
-			/* FIX: why was this triggering PTK rekeying for the
-			 * STA that requested Group Key rekeying?? */
-			/* wpa_request_new_ptk(sta->wpa_sm); */
-			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-			wpa_rekey_gtk(wpa_auth, NULL);
-		}
-	} else {
-		/* Do not allow the same key replay counter to be reused. This
-		 * does also invalidate all other pending replay counters if
-		 * retransmissions were used, i.e., we will only process one of
-		 * the pending replies and ignore rest if more than one is
-		 * received. */
-		sm->key_replay[0].valid = FALSE;
-	}
-
-#ifdef CONFIG_PEERKEY
-	if (msg == SMK_M3) {
-		wpa_smk_m3(wpa_auth, sm, key);
-		return;
-	}
-#endif /* CONFIG_PEERKEY */
-
-	os_free(sm->last_rx_eapol_key);
-	sm->last_rx_eapol_key = os_malloc(data_len);
-	if (sm->last_rx_eapol_key == NULL)
-		return;
-	os_memcpy(sm->last_rx_eapol_key, data, data_len);
-	sm->last_rx_eapol_key_len = data_len;
-
-	sm->EAPOLKeyReceived = TRUE;
-	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
-	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
-	os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
-	wpa_sm_step(sm);
-}
-
-
-static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce,
-			   u8 *gtk, size_t gtk_len)
-{
-	u8 data[ETH_ALEN + WPA_NONCE_LEN];
-
-	/* GTK = PRF-X(GMK, "Group key expansion", AA || GNonce) */
-	os_memcpy(data, addr, ETH_ALEN);
-	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
-
-#ifdef CONFIG_IEEE80211W
-	sha256_prf(gmk, WPA_GMK_LEN, "Group key expansion",
-		   data, sizeof(data), gtk, gtk_len);
-#else /* CONFIG_IEEE80211W */
-	sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
-		 data, sizeof(data), gtk, gtk_len);
-#endif /* CONFIG_IEEE80211W */
-
-	wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
-}
-
-
-static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_authenticator *wpa_auth = eloop_ctx;
-	struct wpa_state_machine *sm = timeout_ctx;
-
-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
-	sm->TimeoutEvt = TRUE;
-	wpa_sm_step(sm);
-}
-
-
-void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
-		      struct wpa_state_machine *sm, int key_info,
-		      const u8 *key_rsc, const u8 *nonce,
-		      const u8 *kde, size_t kde_len,
-		      int keyidx, int encr, int force_version)
-{
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *key;
-	size_t len;
-	int alg;
-	int key_data_len, pad_len = 0;
-	u8 *buf, *pos;
-	int version, pairwise;
-	int i;
-
-	len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
-
-	if (force_version)
-		version = force_version;
-	else if (wpa_use_aes_cmac(sm))
-		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
-	else if (sm->pairwise == WPA_CIPHER_CCMP)
-		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
-
-	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
-		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
-		   "encr=%d)",
-		   version,
-		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
-		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
-		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
-		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
-		   pairwise, (unsigned long) kde_len, keyidx, encr);
-
-	key_data_len = kde_len;
-
-	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
-	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
-		pad_len = key_data_len % 8;
-		if (pad_len)
-			pad_len = 8 - pad_len;
-		key_data_len += pad_len + 8;
-	}
-
-	len += key_data_len;
-
-	hdr = os_zalloc(len);
-	if (hdr == NULL)
-		return;
-	hdr->version = wpa_auth->conf.eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = host_to_be16(len  - sizeof(*hdr));
-	key = (struct wpa_eapol_key *) (hdr + 1);
-
-	key->type = sm->wpa == WPA_VERSION_WPA2 ?
-		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	key_info |= version;
-	if (encr && sm->wpa == WPA_VERSION_WPA2)
-		key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
-	if (sm->wpa != WPA_VERSION_WPA2)
-		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
-	WPA_PUT_BE16(key->key_info, key_info);
-
-	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
-	switch (alg) {
-	case WPA_CIPHER_CCMP:
-		WPA_PUT_BE16(key->key_length, 16);
-		break;
-	case WPA_CIPHER_TKIP:
-		WPA_PUT_BE16(key->key_length, 32);
-		break;
-	case WPA_CIPHER_WEP40:
-		WPA_PUT_BE16(key->key_length, 5);
-		break;
-	case WPA_CIPHER_WEP104:
-		WPA_PUT_BE16(key->key_length, 13);
-		break;
-	}
-	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
-		WPA_PUT_BE16(key->key_length, 0);
-
-	/* FIX: STSL: what to use as key_replay_counter? */
-	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
-		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
-		os_memcpy(sm->key_replay[i].counter,
-			  sm->key_replay[i - 1].counter,
-			  WPA_REPLAY_COUNTER_LEN);
-	}
-	inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
-	os_memcpy(key->replay_counter, sm->key_replay[0].counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	sm->key_replay[0].valid = TRUE;
-
-	if (nonce)
-		os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
-
-	if (key_rsc)
-		os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
-
-	if (kde && !encr) {
-		os_memcpy(key + 1, kde, kde_len);
-		WPA_PUT_BE16(key->key_data_length, kde_len);
-	} else if (encr && kde) {
-		buf = os_zalloc(key_data_len);
-		if (buf == NULL) {
-			os_free(hdr);
-			return;
-		}
-		pos = buf;
-		os_memcpy(pos, kde, kde_len);
-		pos += kde_len;
-
-		if (pad_len)
-			*pos++ = 0xdd;
-
-		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
-				buf, key_data_len);
-		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
-		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-			if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
-				     (u8 *) (key + 1))) {
-				os_free(hdr);
-				os_free(buf);
-				return;
-			}
-			WPA_PUT_BE16(key->key_data_length, key_data_len);
-		} else {
-			u8 ek[32];
-			os_memcpy(key->key_iv,
-				  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
-			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
-			os_memcpy(ek, key->key_iv, 16);
-			os_memcpy(ek + 16, sm->PTK.kek, 16);
-			os_memcpy(key + 1, buf, key_data_len);
-			rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
-			WPA_PUT_BE16(key->key_data_length, key_data_len);
-		}
-		os_free(buf);
-	}
-
-	if (key_info & WPA_KEY_INFO_MIC) {
-		if (!sm->PTK_valid) {
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					"PTK not valid when sending EAPOL-Key "
-					"frame");
-			os_free(hdr);
-			return;
-		}
-		wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
-				  key->key_mic);
-	}
-
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
-			   1);
-	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
-			    sm->pairwise_set);
-	os_free(hdr);
-}
-
-
-static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
-			   struct wpa_state_machine *sm, int key_info,
-			   const u8 *key_rsc, const u8 *nonce,
-			   const u8 *kde, size_t kde_len,
-			   int keyidx, int encr)
-{
-	int timeout_ms;
-	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
-	int ctr;
-
-	if (sm == NULL)
-		return;
-
-	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
-			 keyidx, encr, 0);
-
-	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
-	if (ctr == 1)
-		timeout_ms = eapol_key_timeout_first;
-	else
-		timeout_ms = eapol_key_timeout_subseq;
-	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
-			       wpa_send_eapol_timeout, wpa_auth, sm);
-}
-
-
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
-{
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *key;
-	u16 key_info;
-	int ret = 0;
-	u8 mic[16];
-
-	if (data_len < sizeof(*hdr) + sizeof(*key))
-		return -1;
-
-	hdr = (struct ieee802_1x_hdr *) data;
-	key = (struct wpa_eapol_key *) (hdr + 1);
-	key_info = WPA_GET_BE16(key->key_info);
-	os_memcpy(mic, key->key_mic, 16);
-	os_memset(key->key_mic, 0, 16);
-	if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
-			      data, data_len, key->key_mic) ||
-	    os_memcmp(mic, key->key_mic, 16) != 0)
-		ret = -1;
-	os_memcpy(key->key_mic, mic, 16);
-	return ret;
-}
-
-
-void wpa_remove_ptk(struct wpa_state_machine *sm)
-{
-	sm->PTK_valid = FALSE;
-	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
-	wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, (u8 *) "",
-			 0);
-	sm->pairwise_set = FALSE;
-	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
-}
-
-
-int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
-{
-	int remove_ptk = 1;
-
-	if (sm == NULL)
-		return -1;
-
-	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			 "event %d notification", event);
-
-	switch (event) {
-	case WPA_AUTH:
-	case WPA_ASSOC:
-		break;
-	case WPA_DEAUTH:
-	case WPA_DISASSOC:
-		sm->DeauthenticationRequest = TRUE;
-		break;
-	case WPA_REAUTH:
-	case WPA_REAUTH_EAPOL:
-		if (!sm->started) {
-			/*
-			 * When using WPS, we may end up here if the STA
-			 * manages to re-associate without the previous STA
-			 * entry getting removed. Consequently, we need to make
-			 * sure that the WPA state machines gets initialized
-			 * properly at this point.
-			 */
-			wpa_printf(MSG_DEBUG, "WPA state machine had not been "
-				   "started - initialize now");
-			sm->started = 1;
-			sm->Init = TRUE;
-			if (wpa_sm_step(sm) == 1)
-				return 1; /* should not really happen */
-			sm->Init = FALSE;
-			sm->AuthenticationRequest = TRUE;
-			break;
-		}
-		if (sm->GUpdateStationKeys) {
-			/*
-			 * Reauthentication cancels the pending group key
-			 * update for this STA.
-			 */
-			sm->group->GKeyDoneStations--;
-			sm->GUpdateStationKeys = FALSE;
-			sm->PtkGroupInit = TRUE;
-		}
-		sm->ReAuthenticationRequest = TRUE;
-		break;
-	case WPA_ASSOC_FT:
-#ifdef CONFIG_IEEE80211R
-		wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
-			   "after association");
-		wpa_ft_install_ptk(sm);
-
-		/* Using FT protocol, not WPA auth state machine */
-		sm->ft_completed = 1;
-		return 0;
-#else /* CONFIG_IEEE80211R */
-		break;
-#endif /* CONFIG_IEEE80211R */
-	}
-
-#ifdef CONFIG_IEEE80211R
-	sm->ft_completed = 0;
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_frame_prot && event == WPA_AUTH)
-		remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
-
-	if (remove_ptk) {
-		sm->PTK_valid = FALSE;
-		os_memset(&sm->PTK, 0, sizeof(sm->PTK));
-
-		if (event != WPA_REAUTH_EAPOL)
-			wpa_remove_ptk(sm);
-	}
-
-	return wpa_sm_step(sm);
-}
-
-
-static enum wpa_alg wpa_alg_enum(int alg)
-{
-	switch (alg) {
-	case WPA_CIPHER_CCMP:
-		return WPA_ALG_CCMP;
-	case WPA_CIPHER_TKIP:
-		return WPA_ALG_TKIP;
-	case WPA_CIPHER_WEP104:
-	case WPA_CIPHER_WEP40:
-		return WPA_ALG_WEP;
-	default:
-		return WPA_ALG_NONE;
-	}
-}
-
-
-SM_STATE(WPA_PTK, INITIALIZE)
-{
-	SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
-	if (sm->Init) {
-		/* Init flag is not cleared here, so avoid busy
-		 * loop by claiming nothing changed. */
-		sm->changed = FALSE;
-	}
-
-	sm->keycount = 0;
-	if (sm->GUpdateStationKeys)
-		sm->group->GKeyDoneStations--;
-	sm->GUpdateStationKeys = FALSE;
-	if (sm->wpa == WPA_VERSION_WPA)
-		sm->PInitAKeys = FALSE;
-	if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
-	       * Local AA > Remote AA)) */) {
-		sm->Pair = TRUE;
-	}
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
-	wpa_remove_ptk(sm);
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
-	sm->TimeoutCtr = 0;
-	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
-		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
-				   WPA_EAPOL_authorized, 0);
-	}
-}
-
-
-SM_STATE(WPA_PTK, DISCONNECT)
-{
-	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
-	sm->Disconnect = FALSE;
-	wpa_sta_disconnect(sm->wpa_auth, sm->addr);
-}
-
-
-SM_STATE(WPA_PTK, DISCONNECTED)
-{
-	SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
-	sm->DeauthenticationRequest = FALSE;
-}
-
-
-SM_STATE(WPA_PTK, AUTHENTICATION)
-{
-	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
-	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
-	sm->PTK_valid = FALSE;
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
-			   1);
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
-	sm->AuthenticationRequest = FALSE;
-}
-
-
-SM_STATE(WPA_PTK, AUTHENTICATION2)
-{
-	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
-	os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
-	inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
-	sm->ReAuthenticationRequest = FALSE;
-	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
-	 * logical place than INITIALIZE since AUTHENTICATION2 can be
-	 * re-entered on ReAuthenticationRequest without going through
-	 * INITIALIZE. */
-	sm->TimeoutCtr = 0;
-}
-
-
-SM_STATE(WPA_PTK, INITPMK)
-{
-	u8 msk[2 * PMK_LEN];
-	size_t len = 2 * PMK_LEN;
-
-	SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
-#ifdef CONFIG_IEEE80211R
-	sm->xxkey_len = 0;
-#endif /* CONFIG_IEEE80211R */
-	if (sm->pmksa) {
-		wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
-		os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
-	} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
-		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
-			   "(len=%lu)", (unsigned long) len);
-		os_memcpy(sm->PMK, msk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
-		if (len >= 2 * PMK_LEN) {
-			os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
-			sm->xxkey_len = PMK_LEN;
-		}
-#endif /* CONFIG_IEEE80211R */
-	} else {
-		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
-	}
-
-	sm->req_replay_counter_used = 0;
-	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
-	 * will break reauthentication since EAPOL state machines may not be
-	 * get into AUTHENTICATING state that clears keyRun before WPA state
-	 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
-	 * state and takes PMK from the previously used AAA Key. This will
-	 * eventually fail in 4-Way Handshake because Supplicant uses PMK
-	 * derived from the new AAA Key. Setting keyRun = FALSE here seems to
-	 * be good workaround for this issue. */
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
-}
-
-
-SM_STATE(WPA_PTK, INITPSK)
-{
-	const u8 *psk;
-	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
-	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
-	if (psk) {
-		os_memcpy(sm->PMK, psk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
-		os_memcpy(sm->xxkey, psk, PMK_LEN);
-		sm->xxkey_len = PMK_LEN;
-#endif /* CONFIG_IEEE80211R */
-	}
-	sm->req_replay_counter_used = 0;
-}
-
-
-SM_STATE(WPA_PTK, PTKSTART)
-{
-	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
-	size_t pmkid_len = 0;
-
-	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
-	sm->PTKRequest = FALSE;
-	sm->TimeoutEvt = FALSE;
-
-	sm->TimeoutCtr++;
-	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
-		/* No point in sending the EAPOL-Key - we will disconnect
-		 * immediately following this. */
-		return;
-	}
-
-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			"sending 1/4 msg of 4-Way Handshake");
-	/*
-	 * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
-	 * one possible PSK for this STA.
-	 */
-	if (sm->wpa == WPA_VERSION_WPA2 &&
-	    wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
-		pmkid = buf;
-		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
-		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
-		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
-		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
-		if (sm->pmksa)
-			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
-				  sm->pmksa->pmkid, PMKID_LEN);
-		else {
-			/*
-			 * Calculate PMKID since no PMKSA cache entry was
-			 * available with pre-calculated PMKID.
-			 */
-			rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
-				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
-				  wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-		}
-	}
-	wpa_send_eapol(sm->wpa_auth, sm,
-		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
-		       sm->ANonce, pmkid, pmkid_len, 0, 0);
-}
-
-
-static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
-			  struct wpa_ptk *ptk)
-{
-	size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-		return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
-#endif /* CONFIG_IEEE80211R */
-
-	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
-		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
-		       (u8 *) ptk, ptk_len,
-		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
-	return 0;
-}
-
-
-SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
-{
-	struct wpa_ptk PTK;
-	int ok = 0;
-	const u8 *pmk = NULL;
-
-	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
-	sm->EAPOLKeyReceived = FALSE;
-
-	/* WPA with IEEE 802.1X: use the derived PMK from EAP
-	 * WPA-PSK: iterate through possible PSKs and select the one matching
-	 * the packet */
-	for (;;) {
-		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
-			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
-			if (pmk == NULL)
-				break;
-		} else
-			pmk = sm->PMK;
-
-		wpa_derive_ptk(sm, pmk, &PTK);
-
-		if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
-				       sm->last_rx_eapol_key_len) == 0) {
-			ok = 1;
-			break;
-		}
-
-		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
-			break;
-	}
-
-	if (!ok) {
-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"invalid MIC in msg 2/4 of 4-Way Handshake");
-		return;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
-		/*
-		 * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
-		 * with the value we derived.
-		 */
-		if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
-			      WPA_PMK_NAME_LEN) != 0) {
-			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-					"PMKR1Name mismatch in FT 4-way "
-					"handshake");
-			wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
-				    "Supplicant",
-				    sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
-			wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
-				    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-			return;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
-
-	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
-		/* PSK may have changed from the previous choice, so update
-		 * state machine data based on whatever PSK was selected here.
-		 */
-		os_memcpy(sm->PMK, pmk, PMK_LEN);
-	}
-
-	sm->MICVerified = TRUE;
-
-	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
-	sm->PTK_valid = TRUE;
-}
-
-
-SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
-{
-	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
-	sm->TimeoutCtr = 0;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
-	if (sm->mgmt_frame_prot) {
-		return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
-	}
-
-	return 0;
-}
-
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
-	struct wpa_igtk_kde igtk;
-	struct wpa_group *gsm = sm->group;
-
-	if (!sm->mgmt_frame_prot)
-		return pos;
-
-	igtk.keyid[0] = gsm->GN_igtk;
-	igtk.keyid[1] = 0;
-	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
-	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
-		os_memset(igtk.pn, 0, sizeof(igtk.pn));
-	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
-			  (const u8 *) &igtk, sizeof(igtk), NULL, 0);
-
-	return pos;
-}
-
-#else /* CONFIG_IEEE80211W */
-
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
-{
-	return 0;
-}
-
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
-{
-	return pos;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
-SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
-{
-	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
-	size_t gtk_len, kde_len;
-	struct wpa_group *gsm = sm->group;
-	u8 *wpa_ie;
-	int wpa_ie_len, secure, keyidx, encr = 0;
-
-	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
-	sm->TimeoutEvt = FALSE;
-
-	sm->TimeoutCtr++;
-	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
-		/* No point in sending the EAPOL-Key - we will disconnect
-		 * immediately following this. */
-		return;
-	}
-
-	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-	   GTK[GN], IGTK, [FTIE], [TIE * 2])
-	 */
-	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
-	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
-	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
-	wpa_ie = sm->wpa_auth->wpa_ie;
-	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
-	if (sm->wpa == WPA_VERSION_WPA &&
-	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
-	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
-		/* WPA-only STA, remove RSN IE */
-		wpa_ie = wpa_ie + wpa_ie[1] + 2;
-		wpa_ie_len = wpa_ie[1] + 2;
-	}
-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			"sending 3/4 msg of 4-Way Handshake");
-	if (sm->wpa == WPA_VERSION_WPA2) {
-		/* WPA2 send GTK in the 4-way handshake */
-		secure = 1;
-		gtk = gsm->GTK[gsm->GN - 1];
-		gtk_len = gsm->GTK_len;
-		keyidx = gsm->GN;
-		_rsc = rsc;
-		encr = 1;
-	} else {
-		/* WPA does not include GTK in msg 3/4 */
-		secure = 0;
-		gtk = NULL;
-		gtk_len = 0;
-		keyidx = 0;
-		_rsc = NULL;
-	}
-
-	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
-	if (gtk)
-		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
-		kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
-		kde_len += 300; /* FTIE + 2 * TIE */
-	}
-#endif /* CONFIG_IEEE80211R */
-	kde = os_malloc(kde_len);
-	if (kde == NULL)
-		return;
-
-	pos = kde;
-	os_memcpy(pos, wpa_ie, wpa_ie_len);
-	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);
-		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;
-	}
-#endif /* CONFIG_IEEE80211R */
-	if (gtk) {
-		u8 hdr[2];
-		hdr[0] = keyidx & 0x03;
-		hdr[1] = 0;
-		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
-				  gtk, gtk_len);
-	}
-	pos = ieee80211w_kde_add(sm, pos);
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
-		int res;
-		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 (res < 0) {
-			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
-				   "into EAPOL-Key Key Data");
-			os_free(kde);
-			return;
-		}
-		pos += res;
-
-		/* TIE[ReassociationDeadline] (TU) */
-		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-		*pos++ = 5;
-		*pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
-		WPA_PUT_LE32(pos, conf->reassociation_deadline);
-		pos += 4;
-
-		/* TIE[KeyLifetime] (seconds) */
-		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-		*pos++ = 5;
-		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
-		WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
-		pos += 4;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	wpa_send_eapol(sm->wpa_auth, sm,
-		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
-		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
-		       WPA_KEY_INFO_KEY_TYPE,
-		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
-	os_free(kde);
-}
-
-
-SM_STATE(WPA_PTK, PTKINITDONE)
-{
-	SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
-	sm->EAPOLKeyReceived = FALSE;
-	if (sm->Pair) {
-		enum wpa_alg alg;
-		int klen;
-		if (sm->pairwise == WPA_CIPHER_TKIP) {
-			alg = WPA_ALG_TKIP;
-			klen = 32;
-		} else {
-			alg = WPA_ALG_CCMP;
-			klen = 16;
-		}
-		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk1, klen)) {
-			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
-			return;
-		}
-		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
-		sm->pairwise_set = TRUE;
-
-		if (sm->wpa_auth->conf.wpa_ptk_rekey) {
-			eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
-			eloop_register_timeout(sm->wpa_auth->conf.
-					       wpa_ptk_rekey, 0, wpa_rekey_ptk,
-					       sm->wpa_auth, sm);
-		}
-
-		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
-			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
-					   WPA_EAPOL_authorized, 1);
-		}
-	}
-
-	if (0 /* IBSS == TRUE */) {
-		sm->keycount++;
-		if (sm->keycount == 2) {
-			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
-					   WPA_EAPOL_portValid, 1);
-		}
-	} else {
-		wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
-				   1);
-	}
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
-	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
-	if (sm->wpa == WPA_VERSION_WPA)
-		sm->PInitAKeys = TRUE;
-	else
-		sm->has_GTK = TRUE;
-	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
-			 "pairwise key handshake completed (%s)",
-			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
-
-#ifdef CONFIG_IEEE80211R
-	wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-SM_STEP(WPA_PTK)
-{
-	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
-
-	if (sm->Init)
-		SM_ENTER(WPA_PTK, INITIALIZE);
-	else if (sm->Disconnect
-		 /* || FIX: dot11RSNAConfigSALifetime timeout */)
-		SM_ENTER(WPA_PTK, DISCONNECT);
-	else if (sm->DeauthenticationRequest)
-		SM_ENTER(WPA_PTK, DISCONNECTED);
-	else if (sm->AuthenticationRequest)
-		SM_ENTER(WPA_PTK, AUTHENTICATION);
-	else if (sm->ReAuthenticationRequest)
-		SM_ENTER(WPA_PTK, AUTHENTICATION2);
-	else if (sm->PTKRequest)
-		SM_ENTER(WPA_PTK, PTKSTART);
-	else switch (sm->wpa_ptk_state) {
-	case WPA_PTK_INITIALIZE:
-		break;
-	case WPA_PTK_DISCONNECT:
-		SM_ENTER(WPA_PTK, DISCONNECTED);
-		break;
-	case WPA_PTK_DISCONNECTED:
-		SM_ENTER(WPA_PTK, INITIALIZE);
-		break;
-	case WPA_PTK_AUTHENTICATION:
-		SM_ENTER(WPA_PTK, AUTHENTICATION2);
-		break;
-	case WPA_PTK_AUTHENTICATION2:
-		if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
-		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
-				       WPA_EAPOL_keyRun) > 0)
-			SM_ENTER(WPA_PTK, INITPMK);
-		else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
-			 /* FIX: && 802.1X::keyRun */)
-			SM_ENTER(WPA_PTK, INITPSK);
-		break;
-	case WPA_PTK_INITPMK:
-		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
-				       WPA_EAPOL_keyAvailable) > 0)
-			SM_ENTER(WPA_PTK, PTKSTART);
-		else {
-			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			SM_ENTER(WPA_PTK, DISCONNECT);
-		}
-		break;
-	case WPA_PTK_INITPSK:
-		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
-			SM_ENTER(WPA_PTK, PTKSTART);
-		else {
-			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
-					"no PSK configured for the STA");
-			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			SM_ENTER(WPA_PTK, DISCONNECT);
-		}
-		break;
-	case WPA_PTK_PTKSTART:
-		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
-		    sm->EAPOLKeyPairwise)
-			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
-		else if (sm->TimeoutCtr >
-			 (int) dot11RSNAConfigPairwiseUpdateCount) {
-			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			SM_ENTER(WPA_PTK, DISCONNECT);
-		} else if (sm->TimeoutEvt)
-			SM_ENTER(WPA_PTK, PTKSTART);
-		break;
-	case WPA_PTK_PTKCALCNEGOTIATING:
-		if (sm->MICVerified)
-			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
-		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
-			 sm->EAPOLKeyPairwise)
-			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
-		else if (sm->TimeoutEvt)
-			SM_ENTER(WPA_PTK, PTKSTART);
-		break;
-	case WPA_PTK_PTKCALCNEGOTIATING2:
-		SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
-		break;
-	case WPA_PTK_PTKINITNEGOTIATING:
-		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
-		    sm->EAPOLKeyPairwise && sm->MICVerified)
-			SM_ENTER(WPA_PTK, PTKINITDONE);
-		else if (sm->TimeoutCtr >
-			 (int) dot11RSNAConfigPairwiseUpdateCount) {
-			wpa_auth->dot11RSNA4WayHandshakeFailures++;
-			SM_ENTER(WPA_PTK, DISCONNECT);
-		} else if (sm->TimeoutEvt)
-			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
-		break;
-	case WPA_PTK_PTKINITDONE:
-		break;
-	}
-}
-
-
-SM_STATE(WPA_PTK_GROUP, IDLE)
-{
-	SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
-	if (sm->Init) {
-		/* Init flag is not cleared here, so avoid busy
-		 * loop by claiming nothing changed. */
-		sm->changed = FALSE;
-	}
-	sm->GTimeoutCtr = 0;
-}
-
-
-SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
-{
-	u8 rsc[WPA_KEY_RSC_LEN];
-	struct wpa_group *gsm = sm->group;
-	u8 *kde, *pos, hdr[2];
-	size_t kde_len;
-
-	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
-
-	sm->GTimeoutCtr++;
-	if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
-		/* No point in sending the EAPOL-Key - we will disconnect
-		 * immediately following this. */
-		return;
-	}
-
-	if (sm->wpa == WPA_VERSION_WPA)
-		sm->PInitAKeys = FALSE;
-	sm->TimeoutEvt = FALSE;
-	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
-	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
-	if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
-		wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
-	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-			"sending 1/2 msg of Group Key Handshake");
-
-	if (sm->wpa == WPA_VERSION_WPA2) {
-		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
-			ieee80211w_kde_len(sm);
-		kde = os_malloc(kde_len);
-		if (kde == NULL)
-			return;
-
-		pos = kde;
-		hdr[0] = gsm->GN & 0x03;
-		hdr[1] = 0;
-		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
-				  gsm->GTK[gsm->GN - 1], gsm->GTK_len);
-		pos = ieee80211w_kde_add(sm, pos);
-	} else {
-		kde = gsm->GTK[gsm->GN - 1];
-		pos = kde + gsm->GTK_len;
-	}
-
-	wpa_send_eapol(sm->wpa_auth, sm,
-		       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
-		       WPA_KEY_INFO_ACK |
-		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
-		       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
-	if (sm->wpa == WPA_VERSION_WPA2)
-		os_free(kde);
-}
-
-
-SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
-{
-	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
-	sm->EAPOLKeyReceived = FALSE;
-	if (sm->GUpdateStationKeys)
-		sm->group->GKeyDoneStations--;
-	sm->GUpdateStationKeys = FALSE;
-	sm->GTimeoutCtr = 0;
-	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
-	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
-			 "group key handshake completed (%s)",
-			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
-	sm->has_GTK = TRUE;
-}
-
-
-SM_STATE(WPA_PTK_GROUP, KEYERROR)
-{
-	SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
-	if (sm->GUpdateStationKeys)
-		sm->group->GKeyDoneStations--;
-	sm->GUpdateStationKeys = FALSE;
-	sm->Disconnect = TRUE;
-}
-
-
-SM_STEP(WPA_PTK_GROUP)
-{
-	if (sm->Init || sm->PtkGroupInit) {
-		SM_ENTER(WPA_PTK_GROUP, IDLE);
-		sm->PtkGroupInit = FALSE;
-	} else switch (sm->wpa_ptk_group_state) {
-	case WPA_PTK_GROUP_IDLE:
-		if (sm->GUpdateStationKeys ||
-		    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
-			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
-		break;
-	case WPA_PTK_GROUP_REKEYNEGOTIATING:
-		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
-		    !sm->EAPOLKeyPairwise && sm->MICVerified)
-			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
-		else if (sm->GTimeoutCtr >
-			 (int) dot11RSNAConfigGroupUpdateCount)
-			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
-		else if (sm->TimeoutEvt)
-			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
-		break;
-	case WPA_PTK_GROUP_KEYERROR:
-		SM_ENTER(WPA_PTK_GROUP, IDLE);
-		break;
-	case WPA_PTK_GROUP_REKEYESTABLISHED:
-		SM_ENTER(WPA_PTK_GROUP, IDLE);
-		break;
-	}
-}
-
-
-static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
-			  struct wpa_group *group)
-{
-	int ret = 0;
-
-	/* FIX: is this the correct way of getting GNonce? */
-	os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
-	inc_byte_array(group->Counter, WPA_NONCE_LEN);
-	wpa_gmk_to_gtk(group->GMK, wpa_auth->addr, group->GNonce,
-		       group->GTK[group->GN - 1], group->GTK_len);
-
-#ifdef CONFIG_IEEE80211W
-	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		if (os_get_random(group->IGTK[group->GN_igtk - 4],
-				  WPA_IGTK_LEN) < 0) {
-			wpa_printf(MSG_INFO, "RSN: Failed to get new random "
-				   "IGTK");
-			ret = -1;
-		}
-		wpa_hexdump_key(MSG_DEBUG, "IGTK",
-				group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	return ret;
-}
-
-
-static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
-			       struct wpa_group *group)
-{
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
-	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
-	group->wpa_group_state = WPA_GROUP_GTK_INIT;
-
-	/* GTK[0..N] = 0 */
-	os_memset(group->GTK, 0, sizeof(group->GTK));
-	group->GN = 1;
-	group->GM = 2;
-#ifdef CONFIG_IEEE80211W
-	group->GN_igtk = 4;
-	group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
-	/* GTK[GN] = CalcGTK() */
-	wpa_gtk_update(wpa_auth, group);
-}
-
-
-static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
-{
-	if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"Not in PTKINITDONE; skip Group Key update");
-		return 0;
-	}
-	if (sm->GUpdateStationKeys) {
-		/*
-		 * This should not really happen, but just in case, make sure
-		 * we do not count the same STA twice in GKeyDoneStations.
-		 */
-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
-				"GUpdateStationKeys already set - do not "
-				"increment GKeyDoneStations");
-	} else {
-		sm->group->GKeyDoneStations++;
-		sm->GUpdateStationKeys = TRUE;
-	}
-	wpa_sm_step(sm);
-	return 0;
-}
-
-
-static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
-			      struct wpa_group *group)
-{
-	int tmp;
-
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
-	group->changed = TRUE;
-	group->wpa_group_state = WPA_GROUP_SETKEYS;
-	group->GTKReKey = FALSE;
-	tmp = group->GM;
-	group->GM = group->GN;
-	group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
-	tmp = group->GM_igtk;
-	group->GM_igtk = group->GN_igtk;
-	group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
-	/* "GKeyDoneStations = GNoStations" is done in more robust way by
-	 * counting the STAs that are marked with GUpdateStationKeys instead of
-	 * including all STAs that could be in not-yet-completed state. */
-	wpa_gtk_update(wpa_auth, group);
-
-	wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
-	wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
-		   group->GKeyDoneStations);
-}
-
-
-static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
-				  struct wpa_group *group)
-{
-	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
-		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
-	group->changed = TRUE;
-	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
-	wpa_auth_set_key(wpa_auth, group->vlan_id,
-			 wpa_alg_enum(wpa_auth->conf.wpa_group),
-			 NULL, group->GN, group->GTK[group->GN - 1],
-			 group->GTK_len);
-
-#ifdef CONFIG_IEEE80211W
-	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
-				 NULL, group->GN_igtk,
-				 group->IGTK[group->GN_igtk - 4],
-				 WPA_IGTK_LEN);
-	}
-#endif /* CONFIG_IEEE80211W */
-}
-
-
-static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
-			      struct wpa_group *group)
-{
-	if (group->GInit) {
-		wpa_group_gtk_init(wpa_auth, group);
-	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
-		   group->GTKAuthenticator) {
-		wpa_group_setkeysdone(wpa_auth, group);
-	} else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
-		   group->GTKReKey) {
-		wpa_group_setkeys(wpa_auth, group);
-	} else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
-		if (group->GKeyDoneStations == 0)
-			wpa_group_setkeysdone(wpa_auth, group);
-		else if (group->GTKReKey)
-			wpa_group_setkeys(wpa_auth, group);
-	}
-}
-
-
-static int wpa_sm_step(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return 0;
-
-	if (sm->in_step_loop) {
-		/* This should not happen, but if it does, make sure we do not
-		 * end up freeing the state machine too early by exiting the
-		 * recursive call. */
-		wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
-		return 0;
-	}
-
-	sm->in_step_loop = 1;
-	do {
-		if (sm->pending_deinit)
-			break;
-
-		sm->changed = FALSE;
-		sm->wpa_auth->group->changed = FALSE;
-
-		SM_STEP_RUN(WPA_PTK);
-		if (sm->pending_deinit)
-			break;
-		SM_STEP_RUN(WPA_PTK_GROUP);
-		if (sm->pending_deinit)
-			break;
-		wpa_group_sm_step(sm->wpa_auth, sm->group);
-	} while (sm->changed || sm->wpa_auth->group->changed);
-	sm->in_step_loop = 0;
-
-	if (sm->pending_deinit) {
-		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
-			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
-		wpa_free_sta_sm(sm);
-		return 1;
-	}
-	return 0;
-}
-
-
-static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_state_machine *sm = eloop_ctx;
-	wpa_sm_step(sm);
-}
-
-
-void wpa_auth_sm_notify(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return;
-	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
-}
-
-
-void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
-{
-	int tmp, i;
-	struct wpa_group *group;
-
-	if (wpa_auth == NULL)
-		return;
-
-	group = wpa_auth->group;
-
-	for (i = 0; i < 2; i++) {
-		tmp = group->GM;
-		group->GM = group->GN;
-		group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
-		tmp = group->GM_igtk;
-		group->GM_igtk = group->GN_igtk;
-		group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
-		wpa_gtk_update(wpa_auth, group);
-	}
-}
-
-
-static const char * wpa_bool_txt(int bool)
-{
-	return bool ? "TRUE" : "FALSE";
-}
-
-
-static int wpa_cipher_bits(int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_CCMP:
-		return 128;
-	case WPA_CIPHER_TKIP:
-		return 256;
-	case WPA_CIPHER_WEP104:
-		return 104;
-	case WPA_CIPHER_WEP40:
-		return 40;
-	default:
-		return 0;
-	}
-}
-
-
-#define RSN_SUITE "%02x-%02x-%02x-%d"
-#define RSN_SUITE_ARG(s) \
-((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
-
-int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
-{
-	int len = 0, ret;
-	char pmkid_txt[PMKID_LEN * 2 + 1];
-
-	if (wpa_auth == NULL)
-		return len;
-
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot11RSNAOptionImplemented=TRUE\n"
-#ifdef CONFIG_RSN_PREAUTH
-			  "dot11RSNAPreauthenticationImplemented=TRUE\n"
-#else /* CONFIG_RSN_PREAUTH */
-			  "dot11RSNAPreauthenticationImplemented=FALSE\n"
-#endif /* CONFIG_RSN_PREAUTH */
-			  "dot11RSNAEnabled=%s\n"
-			  "dot11RSNAPreauthenticationEnabled=%s\n",
-			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
-			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
-			 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
-
-	ret = os_snprintf(
-		buf + len, buflen - len,
-		"dot11RSNAConfigVersion=%u\n"
-		"dot11RSNAConfigPairwiseKeysSupported=9999\n"
-		/* FIX: dot11RSNAConfigGroupCipher */
-		/* FIX: dot11RSNAConfigGroupRekeyMethod */
-		/* FIX: dot11RSNAConfigGroupRekeyTime */
-		/* FIX: dot11RSNAConfigGroupRekeyPackets */
-		"dot11RSNAConfigGroupRekeyStrict=%u\n"
-		"dot11RSNAConfigGroupUpdateCount=%u\n"
-		"dot11RSNAConfigPairwiseUpdateCount=%u\n"
-		"dot11RSNAConfigGroupCipherSize=%u\n"
-		"dot11RSNAConfigPMKLifetime=%u\n"
-		"dot11RSNAConfigPMKReauthThreshold=%u\n"
-		"dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
-		"dot11RSNAConfigSATimeout=%u\n"
-		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
-		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
-		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
-		"dot11RSNAPMKIDUsed=%s\n"
-		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
-		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
-		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
-		"dot11RSNATKIPCounterMeasuresInvoked=%u\n"
-		"dot11RSNA4WayHandshakeFailures=%u\n"
-		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
-		RSN_VERSION,
-		!!wpa_auth->conf.wpa_strict_rekey,
-		dot11RSNAConfigGroupUpdateCount,
-		dot11RSNAConfigPairwiseUpdateCount,
-		wpa_cipher_bits(wpa_auth->conf.wpa_group),
-		dot11RSNAConfigPMKLifetime,
-		dot11RSNAConfigPMKReauthThreshold,
-		dot11RSNAConfigSATimeout,
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
-		pmkid_txt,
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
-		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
-		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
-		wpa_auth->dot11RSNA4WayHandshakeFailures);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* TODO: dot11RSNAConfigPairwiseCiphersTable */
-	/* TODO: dot11RSNAConfigAuthenticationSuitesTable */
-
-	/* Private MIB */
-	ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
-			  wpa_auth->group->wpa_group_state);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	return len;
-}
-
-
-int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
-{
-	int len = 0, ret;
-	u32 pairwise = 0;
-
-	if (sm == NULL)
-		return 0;
-
-	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
-
-	/* dot11RSNAStatsEntry */
-
-	if (sm->wpa == WPA_VERSION_WPA) {
-		if (sm->pairwise == WPA_CIPHER_CCMP)
-			pairwise = WPA_CIPHER_SUITE_CCMP;
-		else if (sm->pairwise == WPA_CIPHER_TKIP)
-			pairwise = WPA_CIPHER_SUITE_TKIP;
-		else if (sm->pairwise == WPA_CIPHER_WEP104)
-			pairwise = WPA_CIPHER_SUITE_WEP104;
-		else if (sm->pairwise == WPA_CIPHER_WEP40)
-			pairwise = WPA_CIPHER_SUITE_WEP40;
-		else if (sm->pairwise == WPA_CIPHER_NONE)
-			pairwise = WPA_CIPHER_SUITE_NONE;
-	} else if (sm->wpa == WPA_VERSION_WPA2) {
-		if (sm->pairwise == WPA_CIPHER_CCMP)
-			pairwise = RSN_CIPHER_SUITE_CCMP;
-		else if (sm->pairwise == WPA_CIPHER_TKIP)
-			pairwise = RSN_CIPHER_SUITE_TKIP;
-		else if (sm->pairwise == WPA_CIPHER_WEP104)
-			pairwise = RSN_CIPHER_SUITE_WEP104;
-		else if (sm->pairwise == WPA_CIPHER_WEP40)
-			pairwise = RSN_CIPHER_SUITE_WEP40;
-		else if (sm->pairwise == WPA_CIPHER_NONE)
-			pairwise = RSN_CIPHER_SUITE_NONE;
-	} else
-		return 0;
-
-	ret = os_snprintf(
-		buf + len, buflen - len,
-		/* TODO: dot11RSNAStatsIndex */
-		"dot11RSNAStatsSTAAddress=" MACSTR "\n"
-		"dot11RSNAStatsVersion=1\n"
-		"dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
-		/* TODO: dot11RSNAStatsTKIPICVErrors */
-		"dot11RSNAStatsTKIPLocalMICFailures=%u\n"
-		"dot11RSNAStatsTKIPRemoveMICFailures=%u\n"
-		/* TODO: dot11RSNAStatsCCMPReplays */
-		/* TODO: dot11RSNAStatsCCMPDecryptErrors */
-		/* TODO: dot11RSNAStatsTKIPReplays */,
-		MAC2STR(sm->addr),
-		RSN_SUITE_ARG(pairwise),
-		sm->dot11RSNAStatsTKIPLocalMICFailures,
-		sm->dot11RSNAStatsTKIPRemoteMICFailures);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	/* Private MIB */
-	ret = os_snprintf(buf + len, buflen - len,
-			  "hostapdWPAPTKState=%d\n"
-			  "hostapdWPAPTKGroupState=%d\n",
-			  sm->wpa_ptk_state,
-			  sm->wpa_ptk_group_state);
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	return len;
-}
-
-
-void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
-{
-	if (wpa_auth)
-		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
-}
-
-
-int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
-{
-	return sm && sm->pairwise_set;
-}
-
-
-int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
-{
-	return sm->pairwise;
-}
-
-
-int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return -1;
-	return sm->wpa_key_mgmt;
-}
-
-
-int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
-{
-	if (sm == NULL)
-		return 0;
-	return sm->wpa;
-}
-
-
-int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
-			     struct rsn_pmksa_cache_entry *entry)
-{
-	if (sm == NULL || sm->pmksa != entry)
-		return -1;
-	sm->pmksa = NULL;
-	return 0;
-}
-
-
-struct rsn_pmksa_cache_entry *
-wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
-{
-	return sm ? sm->pmksa : NULL;
-}
-
-
-void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
-{
-	if (sm)
-		sm->dot11RSNAStatsTKIPLocalMICFailures++;
-}
-
-
-const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
-{
-	if (wpa_auth == NULL)
-		return NULL;
-	*len = wpa_auth->wpa_ie_len;
-	return wpa_auth->wpa_ie;
-}
-
-
-int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
-		       int session_timeout, struct eapol_state_machine *eapol)
-{
-	if (sm == NULL || sm->wpa != WPA_VERSION_WPA2)
-		return -1;
-
-	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
-				 sm->wpa_auth->addr, sm->addr, session_timeout,
-				 eapol, sm->wpa_key_mgmt))
-		return 0;
-
-	return -1;
-}
-
-
-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)
-{
-	if (wpa_auth == NULL)
-		return -1;
-
-	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
-				 sta_addr, session_timeout, eapol,
-				 WPA_KEY_MGMT_IEEE8021X))
-		return 0;
-
-	return -1;
-}
-
-
-static struct wpa_group *
-wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
-{
-	struct wpa_group *group;
-
-	if (wpa_auth == NULL || wpa_auth->group == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
-		   vlan_id);
-	group = wpa_group_init(wpa_auth, vlan_id);
-	if (group == NULL)
-		return NULL;
-
-	group->next = wpa_auth->group->next;
-	wpa_auth->group->next = group;
-
-	return group;
-}
-
-
-int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
-{
-	struct wpa_group *group;
-
-	if (sm == NULL || sm->wpa_auth == NULL)
-		return 0;
-
-	group = sm->wpa_auth->group;
-	while (group) {
-		if (group->vlan_id == vlan_id)
-			break;
-		group = group->next;
-	}
-
-	if (group == NULL) {
-		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
-		if (group == NULL)
-			return -1;
-	}
-
-	if (sm->group == group)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
-		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
-
-	sm->group = group;
-	return 0;
-}

Copied: vendor/wpa/2.0/src/ap/wpa_auth.c (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3022 @@
+/*
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "utils/state_machine.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+#define STATE_MACHINE_DATA struct wpa_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "WPA"
+#define STATE_MACHINE_ADDR sm->addr
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_sm_step(struct wpa_state_machine *sm);
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group);
+static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group);
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+				       struct wpa_group *group);
+
+static const u32 dot11RSNAConfigGroupUpdateCount = 4;
+static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
+static const u32 eapol_key_timeout_first = 100; /* ms */
+static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
+
+/* TODO: make these configurable */
+static const int dot11RSNAConfigPMKLifetime = 43200;
+static const int dot11RSNAConfigPMKReauthThreshold = 70;
+static const int dot11RSNAConfigSATimeout = 60;
+
+
+static inline int wpa_auth_mic_failure_report(
+	struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	if (wpa_auth->cb.mic_failure_report)
+		return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+	return 0;
+}
+
+
+static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, wpa_eapol_variable var,
+				      int value)
+{
+	if (wpa_auth->cb.set_eapol)
+		wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+}
+
+
+static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
+				     const u8 *addr, wpa_eapol_variable var)
+{
+	if (wpa_auth->cb.get_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+}
+
+
+static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
+					  const u8 *addr, const u8 *prev_psk)
+{
+	if (wpa_auth->cb.get_psk == NULL)
+		return NULL;
+	return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
+}
+
+
+static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
+				   const u8 *addr, u8 *msk, size_t *len)
+{
+	if (wpa_auth->cb.get_msk == NULL)
+		return -1;
+	return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+				   int vlan_id,
+				   enum wpa_alg alg, const u8 *addr, int idx,
+				   u8 *key, size_t key_len)
+{
+	if (wpa_auth->cb.set_key == NULL)
+		return -1;
+	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+				    key, key_len);
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int
+wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		    const u8 *data, size_t data_len, int encrypt)
+{
+	if (wpa_auth->cb.send_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
+				       encrypt);
+}
+
+
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
+			  void *cb_ctx)
+{
+	if (wpa_auth->cb.for_each_sta == NULL)
+		return 0;
+	return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+			   int (*cb)(struct wpa_authenticator *a, void *ctx),
+			   void *cb_ctx)
+{
+	if (wpa_auth->cb.for_each_auth == NULL)
+		return 0;
+	return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		     logger_level level, const char *txt)
+{
+	if (wpa_auth->cb.logger == NULL)
+		return;
+	wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+}
+
+
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		      logger_level level, const char *fmt, ...)
+{
+	char *format;
+	int maxlen;
+	va_list ap;
+
+	if (wpa_auth->cb.logger == NULL)
+		return;
+
+	maxlen = os_strlen(fmt) + 100;
+	format = os_malloc(maxlen);
+	if (!format)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(format, maxlen, fmt, ap);
+	va_end(ap);
+
+	wpa_auth_logger(wpa_auth, addr, level, format);
+
+	os_free(format);
+}
+
+
+static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
+			       const u8 *addr)
+{
+	if (wpa_auth->cb.disconnect == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
+	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
+{
+	int ret = 0;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+		ret = 1;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
+		ret = 1;
+#endif /* CONFIG_IEEE80211W */
+	return ret;
+}
+
+
+static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+	if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+	} else {
+		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
+		wpa_hexdump_key(MSG_DEBUG, "GMK",
+				wpa_auth->group->GMK, WPA_GMK_LEN);
+	}
+
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
+	}
+}
+
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_group *group;
+
+	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
+	for (group = wpa_auth->group; group; group = group->next) {
+		group->GTKReKey = TRUE;
+		do {
+			group->changed = FALSE;
+			wpa_group_sm_step(wpa_auth, group);
+		} while (group->changed);
+	}
+
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
+				       0, wpa_rekey_gtk, wpa_auth, NULL);
+	}
+}
+
+
+static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_state_machine *sm = timeout_ctx;
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+	wpa_request_new_ptk(sm);
+	wpa_sm_step(sm);
+}
+
+
+static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
+{
+	if (sm->pmksa == ctx)
+		sm->pmksa = NULL;
+	return 0;
+}
+
+
+static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+				   void *ctx)
+{
+	struct wpa_authenticator *wpa_auth = ctx;
+	wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
+}
+
+
+static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
+					  struct wpa_group *group)
+{
+	u8 buf[ETH_ALEN + 8 + sizeof(group)];
+	u8 rkey[32];
+
+	if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN);
+
+	/*
+	 * Counter = PRF-256(Random number, "Init Counter",
+	 *                   Local MAC Address || Time)
+	 */
+	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	wpa_get_ntp_timestamp(buf + ETH_ALEN);
+	os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+	if (random_get_bytes(rkey, sizeof(rkey)) < 0)
+		return -1;
+
+	if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
+		     group->Counter, WPA_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "Key Counter",
+			group->Counter, WPA_NONCE_LEN);
+
+	return 0;
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+					 int vlan_id, int delay_init)
+{
+	struct wpa_group *group;
+
+	group = os_zalloc(sizeof(struct wpa_group));
+	if (group == NULL)
+		return NULL;
+
+	group->GTKAuthenticator = TRUE;
+	group->vlan_id = vlan_id;
+	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
+
+	if (random_pool_ready() != 1) {
+		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+			   "for secure operations - update keys later when "
+			   "the first station connects");
+	}
+
+	/*
+	 * Set initial GMK/Counter value here. The actual values that will be
+	 * used in negotiations will be set once the first station tries to
+	 * connect. This allows more time for collecting additional randomness
+	 * on embedded devices.
+	 */
+	if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+		os_free(group);
+		return NULL;
+	}
+
+	group->GInit = TRUE;
+	if (delay_init) {
+		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+			   "until Beacon frames have been configured");
+		/* Initialization is completed in wpa_init_keys(). */
+	} else {
+		wpa_group_sm_step(wpa_auth, group);
+		group->GInit = FALSE;
+		wpa_group_sm_step(wpa_auth, group);
+	}
+
+	return group;
+}
+
+
+/**
+ * wpa_init - Initialize WPA authenticator
+ * @addr: Authenticator address
+ * @conf: Configuration for WPA authenticator
+ * @cb: Callback functions for WPA authenticator
+ * Returns: Pointer to WPA authenticator data or %NULL on failure
+ */
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb)
+{
+	struct wpa_authenticator *wpa_auth;
+
+	wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
+	if (wpa_auth == NULL)
+		return NULL;
+	os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
+	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+
+	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
+	if (wpa_auth->group == NULL) {
+		os_free(wpa_auth->wpa_ie);
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+	wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
+						wpa_auth);
+	if (wpa_auth->pmksa == NULL) {
+		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+		os_free(wpa_auth->wpa_ie);
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
+	if (wpa_auth->ft_pmk_cache == NULL) {
+		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+		os_free(wpa_auth->wpa_ie);
+		pmksa_cache_auth_deinit(wpa_auth->pmksa);
+		os_free(wpa_auth);
+		return NULL;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
+	}
+
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
+				       wpa_rekey_gtk, wpa_auth, NULL);
+	}
+
+	return wpa_auth;
+}
+
+
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+		   "keys");
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+	return 0;
+}
+
+
+/**
+ * wpa_deinit - Deinitialize WPA authenticator
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ */
+void wpa_deinit(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group, *prev;
+
+	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+
+#ifdef CONFIG_PEERKEY
+	while (wpa_auth->stsl_negotiations)
+		wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
+#endif /* CONFIG_PEERKEY */
+
+	pmksa_cache_auth_deinit(wpa_auth->pmksa);
+
+#ifdef CONFIG_IEEE80211R
+	wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
+	wpa_auth->ft_pmk_cache = NULL;
+#endif /* CONFIG_IEEE80211R */
+
+	os_free(wpa_auth->wpa_ie);
+
+	group = wpa_auth->group;
+	while (group) {
+		prev = group;
+		group = group->next;
+		os_free(prev);
+	}
+
+	os_free(wpa_auth);
+}
+
+
+/**
+ * wpa_reconfig - Update WPA authenticator configuration
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ * @conf: Configuration for WPA authenticator
+ */
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf)
+{
+	struct wpa_group *group;
+	if (wpa_auth == NULL)
+		return 0;
+
+	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+		return -1;
+	}
+
+	/*
+	 * Reinitialize GTK to make sure it is suitable for the new
+	 * configuration.
+	 */
+	group = wpa_auth->group;
+	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
+	group->GInit = TRUE;
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+
+	return 0;
+}
+
+
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	struct wpa_state_machine *sm;
+
+	sm = os_zalloc(sizeof(struct wpa_state_machine));
+	if (sm == NULL)
+		return NULL;
+	os_memcpy(sm->addr, addr, ETH_ALEN);
+
+	sm->wpa_auth = wpa_auth;
+	sm->group = wpa_auth->group;
+
+	return sm;
+}
+
+
+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm)
+{
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+		return -1;
+
+#ifdef CONFIG_IEEE80211R
+	if (sm->ft_completed) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"FT authentication already completed - do not "
+				"start 4-way handshake");
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (sm->started) {
+		os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
+		sm->ReAuthenticationRequest = TRUE;
+		return wpa_sm_step(sm);
+	}
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"start authentication");
+	sm->started = 1;
+
+	sm->Init = TRUE;
+	if (wpa_sm_step(sm) == 1)
+		return 1; /* should not really happen */
+	sm->Init = FALSE;
+	sm->AuthenticationRequest = TRUE;
+	return wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
+{
+	/* WPA/RSN was not used - clear WPA state. This is needed if the STA
+	 * reassociates back to the same AP while the previous entry for the
+	 * STA has not yet been removed. */
+	if (sm == NULL)
+		return;
+
+	sm->wpa_key_mgmt = 0;
+}
+
+
+static void wpa_free_sta_sm(struct wpa_state_machine *sm)
+{
+	if (sm->GUpdateStationKeys) {
+		sm->group->GKeyDoneStations--;
+		sm->GUpdateStationKeys = FALSE;
+	}
+#ifdef CONFIG_IEEE80211R
+	os_free(sm->assoc_resp_ftie);
+#endif /* CONFIG_IEEE80211R */
+	os_free(sm->last_rx_eapol_key);
+	os_free(sm->wpa_ie);
+	os_free(sm);
+}
+
+
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"strict rekeying - force GTK rekey since STA "
+				"is leaving");
+		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
+		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
+				       NULL);
+	}
+
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+	sm->pending_1_of_4_timeout = 0;
+	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
+	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+	if (sm->in_step_loop) {
+		/* Must not free state machine while wpa_sm_step() is running.
+		 * Freeing will be completed in the end of wpa_sm_step(). */
+		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		sm->pending_deinit = 1;
+	} else
+		wpa_free_sta_sm(sm);
+}
+
+
+static void wpa_request_new_ptk(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	sm->PTKRequest = TRUE;
+	sm->PTK_valid = 0;
+}
+
+
+static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,
+				    const u8 *replay_counter)
+{
+	int i;
+	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+		if (!ctr[i].valid)
+			break;
+		if (os_memcmp(replay_counter, ctr[i].counter,
+			      WPA_REPLAY_COUNTER_LEN) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
+					    const u8 *replay_counter)
+{
+	int i;
+	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+		if (ctr[i].valid &&
+		    (replay_counter == NULL ||
+		     os_memcmp(replay_counter, ctr[i].counter,
+			       WPA_REPLAY_COUNTER_LEN) == 0))
+			ctr[i].valid = FALSE;
+	}
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
+			       struct wpa_state_machine *sm,
+			       struct wpa_eapol_ie_parse *kde)
+{
+	struct wpa_ie_data ie;
+	struct rsn_mdie *mdie;
+
+	if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
+	    ie.num_pmkid != 1 || ie.pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
+			   "FT 4-way handshake message 2/4");
+		return -1;
+	}
+
+	os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
+		    sm->sup_pmk_r1_name, PMKID_LEN);
+
+	if (!kde->mdie || !kde->ftie) {
+		wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
+			   "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) (kde->mdie + 2);
+	if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
+	    os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
+		return -1;
+	}
+
+	if (sm->assoc_resp_ftie &&
+	    (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
+	     os_memcmp(kde->ftie, sm->assoc_resp_ftie,
+		       2 + sm->assoc_resp_ftie[1]) != 0)) {
+		wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
+			    kde->ftie, kde->ftie_len);
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
+			    sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+				    struct wpa_state_machine *sm, int group)
+{
+	/* Supplicant reported a Michael MIC error */
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "received EAPOL-Key Error Request "
+			 "(STA detected Michael MIC failure (group=%d))",
+			 group);
+
+	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"group cipher is not TKIP");
+	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"pairwise cipher is not TKIP");
+	} else {
+		if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+			return 1; /* STA entry was removed */
+		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+	}
+
+	/*
+	 * Error report is not a request for a new key handshake, but since
+	 * Authenticator may do it, let's change the keys now anyway.
+	 */
+	wpa_request_new_ptk(sm);
+	return 0;
+}
+
+
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
+		 u8 *data, size_t data_len)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info, key_data_length;
+	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
+	       SMK_M1, SMK_M3, SMK_ERROR } msg;
+	char *msgtxt;
+	struct wpa_eapol_ie_parse kde;
+	int ft;
+	const u8 *eapol_key_ie;
+	size_t eapol_key_ie_len;
+
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+		return;
+
+	if (data_len < sizeof(*hdr) + sizeof(*key))
+		return;
+
+	hdr = (struct ieee802_1x_hdr *) data;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	key_info = WPA_GET_BE16(key->key_info);
+	key_data_length = WPA_GET_BE16(key->key_data_length);
+	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+		   " key_info=0x%x type=%u key_data_length=%u",
+		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
+	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
+			   "key_data overflow (%d > %lu)",
+			   key_data_length,
+			   (unsigned long) (data_len - sizeof(*hdr) -
+					    sizeof(*key)));
+		return;
+	}
+
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		if (key->type == EAPOL_KEY_TYPE_WPA) {
+			/*
+			 * Some deployed station implementations seem to send
+			 * msg 4/4 with incorrect type value in WPA2 mode.
+			 */
+			wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
+				   "with unexpected WPA type in RSN mode");
+		} else if (key->type != EAPOL_KEY_TYPE_RSN) {
+			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+				   "unexpected type %d in RSN mode",
+				   key->type);
+			return;
+		}
+	} else {
+		if (key->type != EAPOL_KEY_TYPE_WPA) {
+			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+				   "unexpected type %d in WPA mode",
+				   key->type);
+			return;
+		}
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce,
+		    WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter",
+		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
+	 * are set */
+
+	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
+	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
+		if (key_info & WPA_KEY_INFO_ERROR) {
+			msg = SMK_ERROR;
+			msgtxt = "SMK Error";
+		} else {
+			msg = SMK_M1;
+			msgtxt = "SMK M1";
+		}
+	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+		msg = SMK_M3;
+		msgtxt = "SMK M3";
+	} else if (key_info & WPA_KEY_INFO_REQUEST) {
+		msg = REQUEST;
+		msgtxt = "Request";
+	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+		msg = GROUP_2;
+		msgtxt = "2/2 Group";
+	} else if (key_data_length == 0) {
+		msg = PAIRWISE_4;
+		msgtxt = "4/4 Pairwise";
+	} else {
+		msg = PAIRWISE_2;
+		msgtxt = "2/4 Pairwise";
+	}
+
+	/* TODO: key_info type validation for PeerKey */
+	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
+	    msg == GROUP_2) {
+		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+		if (sm->pairwise == WPA_CIPHER_CCMP ||
+		    sm->pairwise == WPA_CIPHER_GCMP) {
+			if (wpa_use_aes_cmac(sm) &&
+			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+				wpa_auth_logger(wpa_auth, sm->addr,
+						LOGGER_WARNING,
+						"advertised support for "
+						"AES-128-CMAC, but did not "
+						"use it");
+				return;
+			}
+
+			if (!wpa_use_aes_cmac(sm) &&
+			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+				wpa_auth_logger(wpa_auth, sm->addr,
+						LOGGER_WARNING,
+						"did not use HMAC-SHA1-AES "
+						"with CCMP/GCMP");
+				return;
+			}
+		}
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		if (sm->req_replay_counter_used &&
+		    os_memcmp(key->replay_counter, sm->req_replay_counter,
+			      WPA_REPLAY_COUNTER_LEN) <= 0) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+					"received EAPOL-Key request with "
+					"replayed counter");
+			return;
+		}
+	}
+
+	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
+	    !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
+		int i;
+
+		if (msg == PAIRWISE_2 &&
+		    wpa_replay_counter_valid(sm->prev_key_replay,
+					     key->replay_counter) &&
+		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+		    os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0)
+		{
+			/*
+			 * Some supplicant implementations (e.g., Windows XP
+			 * WZC) update SNonce for each EAPOL-Key 2/4. This
+			 * breaks the workaround on accepting any of the
+			 * pending requests, so allow the SNonce to be updated
+			 * even if we have already sent out EAPOL-Key 3/4.
+			 */
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "Process SNonce update from STA "
+					 "based on retransmitted EAPOL-Key "
+					 "1/4");
+			sm->update_snonce = 1;
+			wpa_replay_counter_mark_invalid(sm->prev_key_replay,
+							key->replay_counter);
+			goto continue_processing;
+		}
+
+		if (msg == PAIRWISE_2 &&
+		    wpa_replay_counter_valid(sm->prev_key_replay,
+					     key->replay_counter) &&
+		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "ignore retransmitted EAPOL-Key %s - "
+					 "SNonce did not change", msgtxt);
+		} else {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "received EAPOL-Key %s with "
+					 "unexpected replay counter", msgtxt);
+		}
+		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+			if (!sm->key_replay[i].valid)
+				break;
+			wpa_hexdump(MSG_DEBUG, "pending replay counter",
+				    sm->key_replay[i].counter,
+				    WPA_REPLAY_COUNTER_LEN);
+		}
+		wpa_hexdump(MSG_DEBUG, "received replay counter",
+			    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+		return;
+	}
+
+continue_processing:
+	switch (msg) {
+	case PAIRWISE_2:
+		if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
+		    sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
+		    (!sm->update_snonce ||
+		     sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
+			return;
+		}
+		random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
+		if (sm->group->reject_4way_hs_for_entropy) {
+			/*
+			 * The system did not have enough entropy to generate
+			 * strong random numbers. Reject the first 4-way
+			 * handshake(s) and collect some entropy based on the
+			 * information from it. Once enough entropy is
+			 * available, the next atempt will trigger GMK/Key
+			 * Counter update and the station will be allowed to
+			 * continue.
+			 */
+			wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
+				   "collect more entropy for random number "
+				   "generation");
+			random_mark_pool_ready();
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+		if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
+				      &kde) < 0) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/4 with "
+					 "invalid Key Data contents");
+			return;
+		}
+		if (kde.rsn_ie) {
+			eapol_key_ie = kde.rsn_ie;
+			eapol_key_ie_len = kde.rsn_ie_len;
+		} else {
+			eapol_key_ie = kde.wpa_ie;
+			eapol_key_ie_len = kde.wpa_ie_len;
+		}
+		ft = sm->wpa == WPA_VERSION_WPA2 &&
+			wpa_key_mgmt_ft(sm->wpa_key_mgmt);
+		if (sm->wpa_ie == NULL ||
+		    wpa_compare_rsn_ie(ft,
+				       sm->wpa_ie, sm->wpa_ie_len,
+				       eapol_key_ie, eapol_key_ie_len)) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"WPA IE from (Re)AssocReq did not "
+					"match with msg 2/4");
+			if (sm->wpa_ie) {
+				wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+					    sm->wpa_ie, sm->wpa_ie_len);
+			}
+			wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+				    eapol_key_ie, eapol_key_ie_len);
+			/* MLME-DEAUTHENTICATE.request */
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+#ifdef CONFIG_IEEE80211R
+		if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+#endif /* CONFIG_IEEE80211R */
+		break;
+	case PAIRWISE_4:
+		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
+		    !sm->PTK_valid) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 4/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
+			return;
+		}
+		break;
+	case GROUP_2:
+		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
+		    || !sm->PTK_valid) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/2 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_group_state);
+			return;
+		}
+		break;
+#ifdef CONFIG_PEERKEY
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		if (!wpa_auth->conf.peerkey) {
+			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
+				   "PeerKey use disabled - ignoring message");
+			return;
+		}
+		if (!sm->PTK_valid) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key msg SMK in "
+					"invalid state - dropped");
+			return;
+		}
+		break;
+#else /* CONFIG_PEERKEY */
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		return; /* STSL disabled - ignore SMK messages */
+#endif /* CONFIG_PEERKEY */
+	case REQUEST:
+		break;
+	}
+
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "received EAPOL-Key frame (%s)", msgtxt);
+
+	if (key_info & WPA_KEY_INFO_ACK) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key Ack set");
+		return;
+	}
+
+	if (!(key_info & WPA_KEY_INFO_MIC)) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key MIC not set");
+		return;
+	}
+
+	sm->MICVerified = FALSE;
+	if (sm->PTK_valid && !sm->update_snonce) {
+		if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key with invalid MIC");
+			return;
+		}
+		sm->MICVerified = TRUE;
+		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+		sm->pending_1_of_4_timeout = 0;
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		if (sm->MICVerified) {
+			sm->req_replay_counter_used = 1;
+			os_memcpy(sm->req_replay_counter, key->replay_counter,
+				  WPA_REPLAY_COUNTER_LEN);
+		} else {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key request with "
+					"invalid MIC");
+			return;
+		}
+
+		/*
+		 * TODO: should decrypt key data field if encryption was used;
+		 * even though MAC address KDE is not normally encrypted,
+		 * supplicant is allowed to encrypt it.
+		 */
+		if (msg == SMK_ERROR) {
+#ifdef CONFIG_PEERKEY
+			wpa_smk_error(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+			return;
+		} else if (key_info & WPA_KEY_INFO_ERROR) {
+			if (wpa_receive_error_report(
+				    wpa_auth, sm,
+				    !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+				return; /* STA entry was removed */
+		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for new "
+					"4-Way Handshake");
+			wpa_request_new_ptk(sm);
+#ifdef CONFIG_PEERKEY
+		} else if (msg == SMK_M1) {
+			wpa_smk_m1(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+		} else if (key_data_length > 0 &&
+			   wpa_parse_kde_ies((const u8 *) (key + 1),
+					     key_data_length, &kde) == 0 &&
+			   kde.mac_addr) {
+		} else {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for GTK "
+					"rekeying");
+			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+			wpa_rekey_gtk(wpa_auth, NULL);
+		}
+	} else {
+		/* Do not allow the same key replay counter to be reused. */
+		wpa_replay_counter_mark_invalid(sm->key_replay,
+						key->replay_counter);
+
+		if (msg == PAIRWISE_2) {
+			/*
+			 * Maintain a copy of the pending EAPOL-Key frames in
+			 * case the EAPOL-Key frame was retransmitted. This is
+			 * needed to allow EAPOL-Key msg 2/4 reply to another
+			 * pending msg 1/4 to update the SNonce to work around
+			 * unexpected supplicant behavior.
+			 */
+			os_memcpy(sm->prev_key_replay, sm->key_replay,
+				  sizeof(sm->key_replay));
+		} else {
+			os_memset(sm->prev_key_replay, 0,
+				  sizeof(sm->prev_key_replay));
+		}
+
+		/*
+		 * Make sure old valid counters are not accepted anymore and
+		 * do not get copied again.
+		 */
+		wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (msg == SMK_M3) {
+		wpa_smk_m3(wpa_auth, sm, key);
+		return;
+	}
+#endif /* CONFIG_PEERKEY */
+
+	os_free(sm->last_rx_eapol_key);
+	sm->last_rx_eapol_key = os_malloc(data_len);
+	if (sm->last_rx_eapol_key == NULL)
+		return;
+	os_memcpy(sm->last_rx_eapol_key, data, data_len);
+	sm->last_rx_eapol_key_len = data_len;
+
+	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
+	sm->EAPOLKeyReceived = TRUE;
+	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
+	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
+	os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
+	wpa_sm_step(sm);
+}
+
+
+static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
+			  const u8 *gnonce, u8 *gtk, size_t gtk_len)
+{
+	u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+	u8 *pos;
+	int ret = 0;
+
+	/* GTK = PRF-X(GMK, "Group key expansion",
+	 *	AA || GNonce || Time || random data)
+	 * The example described in the IEEE 802.11 standard uses only AA and
+	 * GNonce as inputs here. Add some more entropy since this derivation
+	 * is done only at the Authenticator and as such, does not need to be
+	 * exactly same.
+	 */
+	os_memcpy(data, addr, ETH_ALEN);
+	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
+	pos = data + ETH_ALEN + WPA_NONCE_LEN;
+	wpa_get_ntp_timestamp(pos);
+	pos += 8;
+	if (random_get_bytes(pos, 16) < 0)
+		ret = -1;
+
+#ifdef CONFIG_IEEE80211W
+	sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
+#else /* CONFIG_IEEE80211W */
+	if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
+	    < 0)
+		ret = -1;
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_state_machine *sm = timeout_ctx;
+
+	sm->pending_1_of_4_timeout = 0;
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
+	sm->TimeoutEvt = TRUE;
+	wpa_sm_step(sm);
+}
+
+
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+		      struct wpa_state_machine *sm, int key_info,
+		      const u8 *key_rsc, const u8 *nonce,
+		      const u8 *kde, size_t kde_len,
+		      int keyidx, int encr, int force_version)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	size_t len;
+	int alg;
+	int key_data_len, pad_len = 0;
+	u8 *buf, *pos;
+	int version, pairwise;
+	int i;
+
+	len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+
+	if (force_version)
+		version = force_version;
+	else if (wpa_use_aes_cmac(sm))
+		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+	else if (sm->pairwise != WPA_CIPHER_TKIP)
+		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+
+	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
+		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
+		   "encr=%d)",
+		   version,
+		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
+		   pairwise, (unsigned long) kde_len, keyidx, encr);
+
+	key_data_len = kde_len;
+
+	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
+		pad_len = key_data_len % 8;
+		if (pad_len)
+			pad_len = 8 - pad_len;
+		key_data_len += pad_len + 8;
+	}
+
+	len += key_data_len;
+
+	hdr = os_zalloc(len);
+	if (hdr == NULL)
+		return;
+	hdr->version = wpa_auth->conf.eapol_version;
+	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+	hdr->length = host_to_be16(len  - sizeof(*hdr));
+	key = (struct wpa_eapol_key *) (hdr + 1);
+
+	key->type = sm->wpa == WPA_VERSION_WPA2 ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info |= version;
+	if (encr && sm->wpa == WPA_VERSION_WPA2)
+		key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+	if (sm->wpa != WPA_VERSION_WPA2)
+		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
+	WPA_PUT_BE16(key->key_info, key_info);
+
+	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+	WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+		WPA_PUT_BE16(key->key_length, 0);
+
+	/* FIX: STSL: what to use as key_replay_counter? */
+	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
+		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
+		os_memcpy(sm->key_replay[i].counter,
+			  sm->key_replay[i - 1].counter,
+			  WPA_REPLAY_COUNTER_LEN);
+	}
+	inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
+	os_memcpy(key->replay_counter, sm->key_replay[0].counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	sm->key_replay[0].valid = TRUE;
+
+	if (nonce)
+		os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
+
+	if (key_rsc)
+		os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
+
+	if (kde && !encr) {
+		os_memcpy(key + 1, kde, kde_len);
+		WPA_PUT_BE16(key->key_data_length, kde_len);
+	} else if (encr && kde) {
+		buf = os_zalloc(key_data_len);
+		if (buf == NULL) {
+			os_free(hdr);
+			return;
+		}
+		pos = buf;
+		os_memcpy(pos, kde, kde_len);
+		pos += kde_len;
+
+		if (pad_len)
+			*pos++ = 0xdd;
+
+		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+				buf, key_data_len);
+		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
+				     (u8 *) (key + 1))) {
+				os_free(hdr);
+				os_free(buf);
+				return;
+			}
+			WPA_PUT_BE16(key->key_data_length, key_data_len);
+		} else {
+			u8 ek[32];
+			os_memcpy(key->key_iv,
+				  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
+			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
+			os_memcpy(ek, key->key_iv, 16);
+			os_memcpy(ek + 16, sm->PTK.kek, 16);
+			os_memcpy(key + 1, buf, key_data_len);
+			rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
+			WPA_PUT_BE16(key->key_data_length, key_data_len);
+		}
+		os_free(buf);
+	}
+
+	if (key_info & WPA_KEY_INFO_MIC) {
+		if (!sm->PTK_valid) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					"PTK not valid when sending EAPOL-Key "
+					"frame");
+			os_free(hdr);
+			return;
+		}
+		wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
+				  key->key_mic);
+	}
+
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
+			   1);
+	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
+			    sm->pairwise_set);
+	os_free(hdr);
+}
+
+
+static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+			   struct wpa_state_machine *sm, int key_info,
+			   const u8 *key_rsc, const u8 *nonce,
+			   const u8 *kde, size_t kde_len,
+			   int keyidx, int encr)
+{
+	int timeout_ms;
+	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+	int ctr;
+
+	if (sm == NULL)
+		return;
+
+	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
+			 keyidx, encr, 0);
+
+	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
+	if (ctr == 1 && wpa_auth->conf.tx_status)
+		timeout_ms = pairwise ? eapol_key_timeout_first :
+			eapol_key_timeout_first_group;
+	else
+		timeout_ms = eapol_key_timeout_subseq;
+	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
+		sm->pending_1_of_4_timeout = 1;
+	wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
+		   "counter %d)", timeout_ms, ctr);
+	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
+			       wpa_send_eapol_timeout, wpa_auth, sm);
+}
+
+
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info;
+	int ret = 0;
+	u8 mic[16];
+
+	if (data_len < sizeof(*hdr) + sizeof(*key))
+		return -1;
+
+	hdr = (struct ieee802_1x_hdr *) data;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	key_info = WPA_GET_BE16(key->key_info);
+	os_memcpy(mic, key->key_mic, 16);
+	os_memset(key->key_mic, 0, 16);
+	if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+			      data, data_len, key->key_mic) ||
+	    os_memcmp(mic, key->key_mic, 16) != 0)
+		ret = -1;
+	os_memcpy(key->key_mic, mic, 16);
+	return ret;
+}
+
+
+void wpa_remove_ptk(struct wpa_state_machine *sm)
+{
+	sm->PTK_valid = FALSE;
+	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+	wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0);
+	sm->pairwise_set = FALSE;
+	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+}
+
+
+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
+{
+	int remove_ptk = 1;
+
+	if (sm == NULL)
+		return -1;
+
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "event %d notification", event);
+
+	switch (event) {
+	case WPA_AUTH:
+	case WPA_ASSOC:
+		break;
+	case WPA_DEAUTH:
+	case WPA_DISASSOC:
+		sm->DeauthenticationRequest = TRUE;
+		break;
+	case WPA_REAUTH:
+	case WPA_REAUTH_EAPOL:
+		if (!sm->started) {
+			/*
+			 * When using WPS, we may end up here if the STA
+			 * manages to re-associate without the previous STA
+			 * entry getting removed. Consequently, we need to make
+			 * sure that the WPA state machines gets initialized
+			 * properly at this point.
+			 */
+			wpa_printf(MSG_DEBUG, "WPA state machine had not been "
+				   "started - initialize now");
+			sm->started = 1;
+			sm->Init = TRUE;
+			if (wpa_sm_step(sm) == 1)
+				return 1; /* should not really happen */
+			sm->Init = FALSE;
+			sm->AuthenticationRequest = TRUE;
+			break;
+		}
+		if (sm->GUpdateStationKeys) {
+			/*
+			 * Reauthentication cancels the pending group key
+			 * update for this STA.
+			 */
+			sm->group->GKeyDoneStations--;
+			sm->GUpdateStationKeys = FALSE;
+			sm->PtkGroupInit = TRUE;
+		}
+		sm->ReAuthenticationRequest = TRUE;
+		break;
+	case WPA_ASSOC_FT:
+#ifdef CONFIG_IEEE80211R
+		wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
+			   "after association");
+		wpa_ft_install_ptk(sm);
+
+		/* Using FT protocol, not WPA auth state machine */
+		sm->ft_completed = 1;
+		return 0;
+#else /* CONFIG_IEEE80211R */
+		break;
+#endif /* CONFIG_IEEE80211R */
+	}
+
+#ifdef CONFIG_IEEE80211R
+	sm->ft_completed = 0;
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_frame_prot && event == WPA_AUTH)
+		remove_ptk = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	if (remove_ptk) {
+		sm->PTK_valid = FALSE;
+		os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+		if (event != WPA_REAUTH_EAPOL)
+			wpa_remove_ptk(sm);
+	}
+
+	return wpa_sm_step(sm);
+}
+
+
+SM_STATE(WPA_PTK, INITIALIZE)
+{
+	SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
+	if (sm->Init) {
+		/* Init flag is not cleared here, so avoid busy
+		 * loop by claiming nothing changed. */
+		sm->changed = FALSE;
+	}
+
+	sm->keycount = 0;
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = FALSE;
+	if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
+	       * Local AA > Remote AA)) */) {
+		sm->Pair = TRUE;
+	}
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
+	wpa_remove_ptk(sm);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
+	sm->TimeoutCtr = 0;
+	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_authorized, 0);
+	}
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECT)
+{
+	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
+	sm->Disconnect = FALSE;
+	wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECTED)
+{
+	SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
+	sm->DeauthenticationRequest = FALSE;
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION)
+{
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
+	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+	sm->PTK_valid = FALSE;
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
+			   1);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
+	sm->AuthenticationRequest = FALSE;
+}
+
+
+static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
+				  struct wpa_group *group)
+{
+	if (group->first_sta_seen)
+		return;
+	/*
+	 * System has run bit further than at the time hostapd was started
+	 * potentially very early during boot up. This provides better chances
+	 * of collecting more randomness on embedded systems. Re-initialize the
+	 * GMK and Counter here to improve their strength if there was not
+	 * enough entropy available immediately after system startup.
+	 */
+	wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
+		   "station");
+	if (random_pool_ready() != 1) {
+		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+			   "to proceed - reject first 4-way handshake");
+		group->reject_4way_hs_for_entropy = TRUE;
+	} else {
+		group->first_sta_seen = TRUE;
+		group->reject_4way_hs_for_entropy = FALSE;
+	}
+
+	wpa_group_init_gmk_and_counter(wpa_auth, group);
+	wpa_gtk_update(wpa_auth, group);
+	wpa_group_config_group_keys(wpa_auth, group);
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION2)
+{
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
+
+	wpa_group_ensure_init(sm->wpa_auth, sm->group);
+
+	/*
+	 * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+	 * ambiguous. The Authenticator state machine uses a counter that is
+	 * incremented by one for each 4-way handshake. However, the security
+	 * analysis of 4-way handshake points out that unpredictable nonces
+	 * help in preventing precomputation attacks. Instead of the state
+	 * machine definition, use an unpredictable nonce value here to provide
+	 * stronger protection against potential precomputation attacks.
+	 */
+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+			   "ANonce.");
+		wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
+		    WPA_NONCE_LEN);
+	sm->ReAuthenticationRequest = FALSE;
+	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
+	 * logical place than INITIALIZE since AUTHENTICATION2 can be
+	 * re-entered on ReAuthenticationRequest without going through
+	 * INITIALIZE. */
+	sm->TimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK, INITPMK)
+{
+	u8 msk[2 * PMK_LEN];
+	size_t len = 2 * PMK_LEN;
+
+	SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
+#ifdef CONFIG_IEEE80211R
+	sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R */
+	if (sm->pmksa) {
+		wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
+		os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
+	} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
+			   "(len=%lu)", (unsigned long) len);
+		os_memcpy(sm->PMK, msk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+		if (len >= 2 * PMK_LEN) {
+			os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+			sm->xxkey_len = PMK_LEN;
+		}
+#endif /* CONFIG_IEEE80211R */
+	} else {
+		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+	}
+
+	sm->req_replay_counter_used = 0;
+	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+	 * will break reauthentication since EAPOL state machines may not be
+	 * get into AUTHENTICATING state that clears keyRun before WPA state
+	 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
+	 * state and takes PMK from the previously used AAA Key. This will
+	 * eventually fail in 4-Way Handshake because Supplicant uses PMK
+	 * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+	 * be good workaround for this issue. */
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+}
+
+
+SM_STATE(WPA_PTK, INITPSK)
+{
+	const u8 *psk;
+	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
+	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
+	if (psk) {
+		os_memcpy(sm->PMK, psk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+		os_memcpy(sm->xxkey, psk, PMK_LEN);
+		sm->xxkey_len = PMK_LEN;
+#endif /* CONFIG_IEEE80211R */
+	}
+	sm->req_replay_counter_used = 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKSTART)
+{
+	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
+	size_t pmkid_len = 0;
+
+	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
+	sm->PTKRequest = FALSE;
+	sm->TimeoutEvt = FALSE;
+
+	sm->TimeoutCtr++;
+	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/4 msg of 4-Way Handshake");
+	/*
+	 * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
+	 * one possible PSK for this STA.
+	 */
+	if (sm->wpa == WPA_VERSION_WPA2 &&
+	    wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
+		pmkid = buf;
+		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
+		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
+		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
+		if (sm->pmksa)
+			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+				  sm->pmksa->pmkid, PMKID_LEN);
+		else {
+			/*
+			 * Calculate PMKID since no PMKSA cache entry was
+			 * available with pre-calculated PMKID.
+			 */
+			rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
+				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+				  wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+		}
+	}
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+		       sm->ANonce, pmkid, pmkid_len, 0, 0);
+}
+
+
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+			  struct wpa_ptk *ptk)
+{
+	size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+		return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
+		       (u8 *) ptk, ptk_len,
+		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+
+	return 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
+{
+	struct wpa_ptk PTK;
+	int ok = 0;
+	const u8 *pmk = NULL;
+
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
+	sm->EAPOLKeyReceived = FALSE;
+	sm->update_snonce = FALSE;
+
+	/* WPA with IEEE 802.1X: use the derived PMK from EAP
+	 * WPA-PSK: iterate through possible PSKs and select the one matching
+	 * the packet */
+	for (;;) {
+		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
+			if (pmk == NULL)
+				break;
+		} else
+			pmk = sm->PMK;
+
+		wpa_derive_ptk(sm, pmk, &PTK);
+
+		if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+				       sm->last_rx_eapol_key_len) == 0) {
+			ok = 1;
+			break;
+		}
+
+		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+			break;
+	}
+
+	if (!ok) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"invalid MIC in msg 2/4 of 4-Way Handshake");
+		return;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		/*
+		 * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
+		 * with the value we derived.
+		 */
+		if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
+			      WPA_PMK_NAME_LEN) != 0) {
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"PMKR1Name mismatch in FT 4-way "
+					"handshake");
+			wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
+				    "Supplicant",
+				    sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
+			wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
+				    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+			return;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	sm->pending_1_of_4_timeout = 0;
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+
+	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+		/* PSK may have changed from the previous choice, so update
+		 * state machine data based on whatever PSK was selected here.
+		 */
+		os_memcpy(sm->PMK, pmk, PMK_LEN);
+	}
+
+	sm->MICVerified = TRUE;
+
+	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+	sm->PTK_valid = TRUE;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
+{
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
+	sm->TimeoutCtr = 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	if (sm->mgmt_frame_prot) {
+		return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+	}
+
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_igtk_kde igtk;
+	struct wpa_group *gsm = sm->group;
+
+	if (!sm->mgmt_frame_prot)
+		return pos;
+
+	igtk.keyid[0] = gsm->GN_igtk;
+	igtk.keyid[1] = 0;
+	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+	if (sm->wpa_auth->conf.disable_gtk) {
+		/*
+		 * Provide unique random IGTK to each STA to prevent use of
+		 * IGTK in the BSS.
+		 */
+		if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+			return pos;
+	}
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
+			  (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+
+	return pos;
+}
+
+#else /* CONFIG_IEEE80211W */
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	return pos;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
+{
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
+	size_t gtk_len, kde_len;
+	struct wpa_group *gsm = sm->group;
+	u8 *wpa_ie;
+	int wpa_ie_len, secure, keyidx, encr = 0;
+
+	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
+	sm->TimeoutEvt = FALSE;
+
+	sm->TimeoutCtr++;
+	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
+	   GTK[GN], IGTK, [FTIE], [TIE * 2])
+	 */
+	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
+	wpa_ie = sm->wpa_auth->wpa_ie;
+	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+	if (sm->wpa == WPA_VERSION_WPA &&
+	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+		/* WPA-only STA, remove RSN IE */
+		wpa_ie = wpa_ie + wpa_ie[1] + 2;
+		wpa_ie_len = wpa_ie[1] + 2;
+	}
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 3/4 msg of 4-Way Handshake");
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		/* WPA2 send GTK in the 4-way handshake */
+		secure = 1;
+		gtk = gsm->GTK[gsm->GN - 1];
+		gtk_len = gsm->GTK_len;
+		if (sm->wpa_auth->conf.disable_gtk) {
+			/*
+			 * Provide unique random GTK to each STA to prevent use
+			 * of GTK in the BSS.
+			 */
+			if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+				return;
+			gtk = dummy_gtk;
+		}
+		keyidx = gsm->GN;
+		_rsc = rsc;
+		encr = 1;
+	} else {
+		/* WPA does not include GTK in msg 3/4 */
+		secure = 0;
+		gtk = NULL;
+		gtk_len = 0;
+		keyidx = 0;
+		_rsc = NULL;
+		if (sm->rx_eapol_key_secure) {
+			/*
+			 * It looks like Windows 7 supplicant tries to use
+			 * Secure bit in msg 2/4 after having reported Michael
+			 * MIC failure and it then rejects the 4-way handshake
+			 * if msg 3/4 does not set Secure bit. Work around this
+			 * by setting the Secure bit here even in the case of
+			 * WPA if the supplicant used it first.
+			 */
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"STA used Secure bit in WPA msg 2/4 - "
+					"set Secure for 3/4 as workaround");
+			secure = 1;
+		}
+	}
+
+	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+	if (gtk)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
+		kde_len += 300; /* FTIE + 2 * TIE */
+	}
+#endif /* CONFIG_IEEE80211R */
+	kde = os_malloc(kde_len);
+	if (kde == NULL)
+		return;
+
+	pos = kde;
+	os_memcpy(pos, wpa_ie, wpa_ie_len);
+	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);
+		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;
+	}
+#endif /* CONFIG_IEEE80211R */
+	if (gtk) {
+		u8 hdr[2];
+		hdr[0] = keyidx & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gtk, gtk_len);
+	}
+	pos = ieee80211w_kde_add(sm, pos);
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		int res;
+		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 (res < 0) {
+			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
+				   "into EAPOL-Key Key Data");
+			os_free(kde);
+			return;
+		}
+		pos += res;
+
+		/* TIE[ReassociationDeadline] (TU) */
+		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+		*pos++ = 5;
+		*pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
+		WPA_PUT_LE32(pos, conf->reassociation_deadline);
+		pos += 4;
+
+		/* TIE[KeyLifetime] (seconds) */
+		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+		*pos++ = 5;
+		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
+		WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+		pos += 4;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+		       WPA_KEY_INFO_KEY_TYPE,
+		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+	os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK, PTKINITDONE)
+{
+	SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
+	sm->EAPOLKeyReceived = FALSE;
+	if (sm->Pair) {
+		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+		int klen = wpa_cipher_key_len(sm->pairwise);
+		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+				     sm->PTK.tk1, klen)) {
+			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+			return;
+		}
+		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+		sm->pairwise_set = TRUE;
+
+		if (sm->wpa_auth->conf.wpa_ptk_rekey) {
+			eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+			eloop_register_timeout(sm->wpa_auth->conf.
+					       wpa_ptk_rekey, 0, wpa_rekey_ptk,
+					       sm->wpa_auth, sm);
+		}
+
+		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_authorized, 1);
+		}
+	}
+
+	if (0 /* IBSS == TRUE */) {
+		sm->keycount++;
+		if (sm->keycount == 2) {
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_portValid, 1);
+		}
+	} else {
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
+				   1);
+	}
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = TRUE;
+	else
+		sm->has_GTK = TRUE;
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "pairwise key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+
+#ifdef CONFIG_IEEE80211R
+	wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+SM_STEP(WPA_PTK)
+{
+	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+	if (sm->Init)
+		SM_ENTER(WPA_PTK, INITIALIZE);
+	else if (sm->Disconnect
+		 /* || FIX: dot11RSNAConfigSALifetime timeout */) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"WPA_PTK: sm->Disconnect");
+		SM_ENTER(WPA_PTK, DISCONNECT);
+	}
+	else if (sm->DeauthenticationRequest)
+		SM_ENTER(WPA_PTK, DISCONNECTED);
+	else if (sm->AuthenticationRequest)
+		SM_ENTER(WPA_PTK, AUTHENTICATION);
+	else if (sm->ReAuthenticationRequest)
+		SM_ENTER(WPA_PTK, AUTHENTICATION2);
+	else if (sm->PTKRequest)
+		SM_ENTER(WPA_PTK, PTKSTART);
+	else switch (sm->wpa_ptk_state) {
+	case WPA_PTK_INITIALIZE:
+		break;
+	case WPA_PTK_DISCONNECT:
+		SM_ENTER(WPA_PTK, DISCONNECTED);
+		break;
+	case WPA_PTK_DISCONNECTED:
+		SM_ENTER(WPA_PTK, INITIALIZE);
+		break;
+	case WPA_PTK_AUTHENTICATION:
+		SM_ENTER(WPA_PTK, AUTHENTICATION2);
+		break;
+	case WPA_PTK_AUTHENTICATION2:
+		if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyRun) > 0)
+			SM_ENTER(WPA_PTK, INITPMK);
+		else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
+			 /* FIX: && 802.1X::keyRun */)
+			SM_ENTER(WPA_PTK, INITPSK);
+		break;
+	case WPA_PTK_INITPMK:
+		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyAvailable) > 0)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		else {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+					"INITPMK - keyAvailable = false");
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		}
+		break;
+	case WPA_PTK_INITPSK:
+		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
+			SM_ENTER(WPA_PTK, PTKSTART);
+		else {
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+					"no PSK configured for the STA");
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		}
+		break;
+	case WPA_PTK_PTKSTART:
+		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+		    sm->EAPOLKeyPairwise)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKSTART: Retry limit %d reached",
+					 dot11RSNAConfigPairwiseUpdateCount);
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		} else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		break;
+	case WPA_PTK_PTKCALCNEGOTIATING:
+		if (sm->MICVerified)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
+		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+			 sm->EAPOLKeyPairwise)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		break;
+	case WPA_PTK_PTKCALCNEGOTIATING2:
+		SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+		break;
+	case WPA_PTK_PTKINITNEGOTIATING:
+		if (sm->update_snonce)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+			 sm->EAPOLKeyPairwise && sm->MICVerified)
+			SM_ENTER(WPA_PTK, PTKINITDONE);
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKINITNEGOTIATING: Retry limit %d "
+					 "reached",
+					 dot11RSNAConfigPairwiseUpdateCount);
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		} else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+		break;
+	case WPA_PTK_PTKINITDONE:
+		break;
+	}
+}
+
+
+SM_STATE(WPA_PTK_GROUP, IDLE)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
+	if (sm->Init) {
+		/* Init flag is not cleared here, so avoid busy
+		 * loop by claiming nothing changed. */
+		sm->changed = FALSE;
+	}
+	sm->GTimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
+{
+	u8 rsc[WPA_KEY_RSC_LEN];
+	struct wpa_group *gsm = sm->group;
+	u8 *kde, *pos, hdr[2];
+	size_t kde_len;
+	u8 *gtk, dummy_gtk[32];
+
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
+
+	sm->GTimeoutCtr++;
+	if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = FALSE;
+	sm->TimeoutEvt = FALSE;
+	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
+	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+	if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
+		wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/2 msg of Group Key Handshake");
+
+	gtk = gsm->GTK[gsm->GN - 1];
+	if (sm->wpa_auth->conf.disable_gtk) {
+		/*
+		 * Provide unique random GTK to each STA to prevent use
+		 * of GTK in the BSS.
+		 */
+		if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+			return;
+		gtk = dummy_gtk;
+	}
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
+			ieee80211w_kde_len(sm);
+		kde = os_malloc(kde_len);
+		if (kde == NULL)
+			return;
+
+		pos = kde;
+		hdr[0] = gsm->GN & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gtk, gsm->GTK_len);
+		pos = ieee80211w_kde_add(sm, pos);
+	} else {
+		kde = gtk;
+		pos = kde + gsm->GTK_len;
+	}
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK |
+		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
+		       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
+	if (sm->wpa == WPA_VERSION_WPA2)
+		os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
+	sm->EAPOLKeyReceived = FALSE;
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	sm->GTimeoutCtr = 0;
+	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "group key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+	sm->has_GTK = TRUE;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, KEYERROR)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	sm->Disconnect = TRUE;
+}
+
+
+SM_STEP(WPA_PTK_GROUP)
+{
+	if (sm->Init || sm->PtkGroupInit) {
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		sm->PtkGroupInit = FALSE;
+	} else switch (sm->wpa_ptk_group_state) {
+	case WPA_PTK_GROUP_IDLE:
+		if (sm->GUpdateStationKeys ||
+		    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
+			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+		break;
+	case WPA_PTK_GROUP_REKEYNEGOTIATING:
+		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+		    !sm->EAPOLKeyPairwise && sm->MICVerified)
+			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
+		else if (sm->GTimeoutCtr >
+			 (int) dot11RSNAConfigGroupUpdateCount)
+			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
+		else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+		break;
+	case WPA_PTK_GROUP_KEYERROR:
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		break;
+	case WPA_PTK_GROUP_REKEYESTABLISHED:
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		break;
+	}
+}
+
+
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group)
+{
+	int ret = 0;
+
+	os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+	inc_byte_array(group->Counter, WPA_NONCE_LEN);
+	if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
+			   wpa_auth->addr, group->GNonce,
+			   group->GTK[group->GN - 1], group->GTK_len) < 0)
+		ret = -1;
+	wpa_hexdump_key(MSG_DEBUG, "GTK",
+			group->GTK[group->GN - 1], group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+		inc_byte_array(group->Counter, WPA_NONCE_LEN);
+		if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
+				   wpa_auth->addr, group->GNonce,
+				   group->IGTK[group->GN_igtk - 4],
+				   WPA_IGTK_LEN) < 0)
+			ret = -1;
+		wpa_hexdump_key(MSG_DEBUG, "IGTK",
+				group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
+			       struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+	group->wpa_group_state = WPA_GROUP_GTK_INIT;
+
+	/* GTK[0..N] = 0 */
+	os_memset(group->GTK, 0, sizeof(group->GTK));
+	group->GN = 1;
+	group->GM = 2;
+#ifdef CONFIG_IEEE80211W
+	group->GN_igtk = 4;
+	group->GM_igtk = 5;
+#endif /* CONFIG_IEEE80211W */
+	/* GTK[GN] = CalcGTK() */
+	wpa_gtk_update(wpa_auth, group);
+}
+
+
+static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
+{
+	if (ctx != NULL && ctx != sm->group)
+		return 0;
+
+	if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"Not in PTKINITDONE; skip Group Key update");
+		sm->GUpdateStationKeys = FALSE;
+		return 0;
+	}
+	if (sm->GUpdateStationKeys) {
+		/*
+		 * This should not really happen, so add a debug log entry.
+		 * Since we clear the GKeyDoneStations before the loop, the
+		 * station needs to be counted here anyway.
+		 */
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"GUpdateStationKeys was already set when "
+				"marking station for GTK rekeying");
+	}
+
+	/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
+	if (sm->is_wnmsleep)
+		return 0;
+
+	sm->group->GKeyDoneStations++;
+	sm->GUpdateStationKeys = TRUE;
+
+	wpa_sm_step(sm);
+	return 0;
+}
+
+
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+	if (sm->is_wnmsleep)
+		return;
+
+	wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+	sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_group *gsm = sm->group;
+	u8 *start = pos;
+
+	/*
+	 * GTK subelement:
+	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+	 * Key[5..32]
+	 */
+	*pos++ = WNM_SLEEP_SUBELEM_GTK;
+	*pos++ = 11 + gsm->GTK_len;
+	/* Key ID in B0-B1 of Key Info */
+	WPA_PUT_LE16(pos, gsm->GN & 0x03);
+	pos += 2;
+	*pos++ = gsm->GTK_len;
+	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
+		return 0;
+	pos += 8;
+	os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+	pos += gsm->GTK_len;
+
+	wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+		   gsm->GN);
+	wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
+			gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+
+	return pos - start;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_group *gsm = sm->group;
+	u8 *start = pos;
+
+	/*
+	 * IGTK subelement:
+	 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+	 */
+	*pos++ = WNM_SLEEP_SUBELEM_IGTK;
+	*pos++ = 2 + 6 + WPA_IGTK_LEN;
+	WPA_PUT_LE16(pos, gsm->GN_igtk);
+	pos += 2;
+	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
+		return 0;
+	pos += 6;
+
+	os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+	pos += WPA_IGTK_LEN;
+
+	wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
+		   gsm->GN_igtk);
+	wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
+			gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+
+	return pos - start;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_WNM */
+
+
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
+{
+	int tmp;
+
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYS;
+	group->GTKReKey = FALSE;
+	tmp = group->GM;
+	group->GM = group->GN;
+	group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+	tmp = group->GM_igtk;
+	group->GM_igtk = group->GN_igtk;
+	group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+	/* "GKeyDoneStations = GNoStations" is done in more robust way by
+	 * counting the STAs that are marked with GUpdateStationKeys instead of
+	 * including all STAs that could be in not-yet-completed state. */
+	wpa_gtk_update(wpa_auth, group);
+
+	if (group->GKeyDoneStations) {
+		wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
+			   "GKeyDoneStations=%d when starting new GTK rekey",
+			   group->GKeyDoneStations);
+		group->GKeyDoneStations = 0;
+	}
+	wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
+	wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
+		   group->GKeyDoneStations);
+}
+
+
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+				       struct wpa_group *group)
+{
+	int ret = 0;
+
+	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
+			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+			     broadcast_ether_addr, group->GN,
+			     group->GTK[group->GN - 1], group->GTK_len) < 0)
+		ret = -1;
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+	    wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
+			     broadcast_ether_addr, group->GN_igtk,
+			     group->IGTK[group->GN_igtk - 4],
+			     WPA_IGTK_LEN) < 0)
+		ret = -1;
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
+				 struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
+
+	if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
+{
+	if (group->GInit) {
+		wpa_group_gtk_init(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
+		   group->GTKAuthenticator) {
+		wpa_group_setkeysdone(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
+		   group->GTKReKey) {
+		wpa_group_setkeys(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
+		if (group->GKeyDoneStations == 0)
+			wpa_group_setkeysdone(wpa_auth, group);
+		else if (group->GTKReKey)
+			wpa_group_setkeys(wpa_auth, group);
+	}
+}
+
+
+static int wpa_sm_step(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+
+	if (sm->in_step_loop) {
+		/* This should not happen, but if it does, make sure we do not
+		 * end up freeing the state machine too early by exiting the
+		 * recursive call. */
+		wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
+		return 0;
+	}
+
+	sm->in_step_loop = 1;
+	do {
+		if (sm->pending_deinit)
+			break;
+
+		sm->changed = FALSE;
+		sm->wpa_auth->group->changed = FALSE;
+
+		SM_STEP_RUN(WPA_PTK);
+		if (sm->pending_deinit)
+			break;
+		SM_STEP_RUN(WPA_PTK_GROUP);
+		if (sm->pending_deinit)
+			break;
+		wpa_group_sm_step(sm->wpa_auth, sm->group);
+	} while (sm->changed || sm->wpa_auth->group->changed);
+	sm->in_step_loop = 0;
+
+	if (sm->pending_deinit) {
+		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		wpa_free_sta_sm(sm);
+		return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_state_machine *sm = eloop_ctx;
+	wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sm_notify(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
+
+
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
+{
+	int tmp, i;
+	struct wpa_group *group;
+
+	if (wpa_auth == NULL)
+		return;
+
+	group = wpa_auth->group;
+
+	for (i = 0; i < 2; i++) {
+		tmp = group->GM;
+		group->GM = group->GN;
+		group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+		tmp = group->GM_igtk;
+		group->GM_igtk = group->GN_igtk;
+		group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+		wpa_gtk_update(wpa_auth, group);
+		wpa_group_config_group_keys(wpa_auth, group);
+	}
+}
+
+
+static const char * wpa_bool_txt(int bool)
+{
+	return bool ? "TRUE" : "FALSE";
+}
+
+
+#define RSN_SUITE "%02x-%02x-%02x-%d"
+#define RSN_SUITE_ARG(s) \
+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	char pmkid_txt[PMKID_LEN * 2 + 1];
+#ifdef CONFIG_RSN_PREAUTH
+	const int preauth = 1;
+#else /* CONFIG_RSN_PREAUTH */
+	const int preauth = 0;
+#endif /* CONFIG_RSN_PREAUTH */
+
+	if (wpa_auth == NULL)
+		return len;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot11RSNAOptionImplemented=TRUE\n"
+			  "dot11RSNAPreauthenticationImplemented=%s\n"
+			  "dot11RSNAEnabled=%s\n"
+			  "dot11RSNAPreauthenticationEnabled=%s\n",
+			  wpa_bool_txt(preauth),
+			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
+			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+			 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		"dot11RSNAConfigVersion=%u\n"
+		"dot11RSNAConfigPairwiseKeysSupported=9999\n"
+		/* FIX: dot11RSNAConfigGroupCipher */
+		/* FIX: dot11RSNAConfigGroupRekeyMethod */
+		/* FIX: dot11RSNAConfigGroupRekeyTime */
+		/* FIX: dot11RSNAConfigGroupRekeyPackets */
+		"dot11RSNAConfigGroupRekeyStrict=%u\n"
+		"dot11RSNAConfigGroupUpdateCount=%u\n"
+		"dot11RSNAConfigPairwiseUpdateCount=%u\n"
+		"dot11RSNAConfigGroupCipherSize=%u\n"
+		"dot11RSNAConfigPMKLifetime=%u\n"
+		"dot11RSNAConfigPMKReauthThreshold=%u\n"
+		"dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
+		"dot11RSNAConfigSATimeout=%u\n"
+		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAPMKIDUsed=%s\n"
+		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNATKIPCounterMeasuresInvoked=%u\n"
+		"dot11RSNA4WayHandshakeFailures=%u\n"
+		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
+		RSN_VERSION,
+		!!wpa_auth->conf.wpa_strict_rekey,
+		dot11RSNAConfigGroupUpdateCount,
+		dot11RSNAConfigPairwiseUpdateCount,
+		wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+		dot11RSNAConfigPMKLifetime,
+		dot11RSNAConfigPMKReauthThreshold,
+		dot11RSNAConfigSATimeout,
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
+		pmkid_txt,
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
+		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
+		wpa_auth->dot11RSNA4WayHandshakeFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* TODO: dot11RSNAConfigPairwiseCiphersTable */
+	/* TODO: dot11RSNAConfigAuthenticationSuitesTable */
+
+	/* Private MIB */
+	ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
+			  wpa_auth->group->wpa_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	u32 pairwise = 0;
+
+	if (sm == NULL)
+		return 0;
+
+	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
+
+	/* dot11RSNAStatsEntry */
+
+	pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+				       WPA_PROTO_RSN : WPA_PROTO_WPA,
+				       sm->pairwise);
+	if (pairwise == 0)
+		return 0;
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		/* TODO: dot11RSNAStatsIndex */
+		"dot11RSNAStatsSTAAddress=" MACSTR "\n"
+		"dot11RSNAStatsVersion=1\n"
+		"dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
+		/* TODO: dot11RSNAStatsTKIPICVErrors */
+		"dot11RSNAStatsTKIPLocalMICFailures=%u\n"
+		"dot11RSNAStatsTKIPRemoteMICFailures=%u\n"
+		/* TODO: dot11RSNAStatsCCMPReplays */
+		/* TODO: dot11RSNAStatsCCMPDecryptErrors */
+		/* TODO: dot11RSNAStatsTKIPReplays */,
+		MAC2STR(sm->addr),
+		RSN_SUITE_ARG(pairwise),
+		sm->dot11RSNAStatsTKIPLocalMICFailures,
+		sm->dot11RSNAStatsTKIPRemoteMICFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* Private MIB */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "hostapdWPAPTKState=%d\n"
+			  "hostapdWPAPTKGroupState=%d\n",
+			  sm->wpa_ptk_state,
+			  sm->wpa_ptk_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
+{
+	if (wpa_auth)
+		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
+}
+
+
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
+{
+	return sm && sm->pairwise_set;
+}
+
+
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
+{
+	return sm->pairwise;
+}
+
+
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return -1;
+	return sm->wpa_key_mgmt;
+}
+
+
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->wpa;
+}
+
+
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry)
+{
+	if (sm == NULL || sm->pmksa != entry)
+		return -1;
+	sm->pmksa = NULL;
+	return 0;
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
+{
+	return sm ? sm->pmksa : NULL;
+}
+
+
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
+{
+	if (sm)
+		sm->dot11RSNAStatsTKIPLocalMICFailures++;
+}
+
+
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
+{
+	if (wpa_auth == NULL)
+		return NULL;
+	*len = wpa_auth->wpa_ie_len;
+	return wpa_auth->wpa_ie;
+}
+
+
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       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,
+				 sm->wpa_auth->addr, sm->addr, session_timeout,
+				 eapol, sm->wpa_key_mgmt))
+		return 0;
+
+	return -1;
+}
+
+
+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)
+{
+	if (wpa_auth == NULL)
+		return -1;
+
+	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+				 sta_addr, session_timeout, eapol,
+				 WPA_KEY_MGMT_IEEE8021X))
+		return 0;
+
+	return -1;
+}
+
+
+static struct wpa_group *
+wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (wpa_auth == NULL || wpa_auth->group == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
+		   vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id, 0);
+	if (group == NULL)
+		return NULL;
+
+	group->next = wpa_auth->group->next;
+	wpa_auth->group->next = group;
+
+	return group;
+}
+
+
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (sm == NULL || sm->wpa_auth == NULL)
+		return 0;
+
+	group = sm->wpa_auth->group;
+	while (group) {
+		if (group->vlan_id == vlan_id)
+			break;
+		group = group->next;
+	}
+
+	if (group == NULL) {
+		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
+		if (group == NULL)
+			return -1;
+	}
+
+	if (sm->group == group)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
+		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+
+	sm->group = group;
+	return 0;
+}
+
+
+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
+				  struct wpa_state_machine *sm, int ack)
+{
+	if (wpa_auth == NULL || sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
+		   " ack=%d", MAC2STR(sm->addr), ack);
+	if (sm->pending_1_of_4_timeout && ack) {
+		/*
+		 * Some deployed supplicant implementations update their SNonce
+		 * for each EAPOL-Key 2/4 message even within the same 4-way
+		 * handshake and then fail to use the first SNonce when
+		 * deriving the PTK. This results in unsuccessful 4-way
+		 * handshake whenever the relatively short initial timeout is
+		 * reached and EAPOL-Key 1/4 is retransmitted. Try to work
+		 * around this by increasing the timeout now that we know that
+		 * the station has received the frame.
+		 */
+		int timeout_ms = eapol_key_timeout_subseq;
+		wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
+			   "timeout by %u ms because of acknowledged frame",
+			   timeout_ms);
+		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+		eloop_register_timeout(timeout_ms / 1000,
+				       (timeout_ms % 1000) * 1000,
+				       wpa_send_eapol_timeout, wpa_auth, sm);
+	}
+}
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}

Deleted: vendor/wpa/2.0/src/ap/wpa_auth.h
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,281 +0,0 @@
-/*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_AUTH_H
-#define WPA_AUTH_H
-
-#include "common/defs.h"
-#include "common/eapol_common.h"
-#include "common/wpa_common.h"
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
- */
-struct ft_rrb_frame {
-	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
-	u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
-	le16 action_length; /* little endian length of action_frame */
-	u8 ap_address[ETH_ALEN];
-	/*
-	 * Followed by action_length bytes of FT Action frame (from Category
-	 * field to the end of Action Frame body.
-	 */
-} STRUCT_PACKED;
-
-#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
-
-#define FT_PACKET_REQUEST 0
-#define FT_PACKET_RESPONSE 1
-/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
-#define FT_PACKET_R0KH_R1KH_PULL 200
-#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
-
-struct ft_r0kh_r1kh_pull_frame {
-	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
-	u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
-	le16 data_length; /* little endian length of data (44) */
-	u8 ap_address[ETH_ALEN];
-
-	u8 nonce[16];
-	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 key_wrap_extra[8];
-} STRUCT_PACKED;
-
-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) */
-	u8 ap_address[ETH_ALEN];
-
-	u8 nonce[16]; /* copied from pull */
-	u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
-	u8 s1kh_id[ETH_ALEN]; /* 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 key_wrap_extra[8];
-} STRUCT_PACKED;
-
-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) */
-	u8 ap_address[ETH_ALEN];
-
-	/* Encrypted with AES key-wrap */
-	u8 timestamp[4]; /* current time in seconds since unix epoch, little
-			  * endian */
-	u8 r1kh_id[FT_R1KH_ID_LEN];
-	u8 s1kh_id[ETH_ALEN];
-	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
-	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 key_wrap_extra[8];
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-/* per STA state machine data */
-
-struct wpa_authenticator;
-struct wpa_state_machine;
-struct rsn_pmksa_cache_entry;
-struct eapol_state_machine;
-
-
-struct ft_remote_r0kh {
-	struct ft_remote_r0kh *next;
-	u8 addr[ETH_ALEN];
-	u8 id[FT_R0KH_ID_MAX_LEN];
-	size_t id_len;
-	u8 key[16];
-};
-
-
-struct ft_remote_r1kh {
-	struct ft_remote_r1kh *next;
-	u8 addr[ETH_ALEN];
-	u8 id[FT_R1KH_ID_LEN];
-	u8 key[16];
-};
-
-
-struct wpa_auth_config {
-	int wpa;
-	int wpa_key_mgmt;
-	int wpa_pairwise;
-	int wpa_group;
-	int wpa_group_rekey;
-	int wpa_strict_rekey;
-	int wpa_gmk_rekey;
-	int wpa_ptk_rekey;
-	int rsn_pairwise;
-	int rsn_preauth;
-	int eapol_version;
-	int peerkey;
-	int wmm_enabled;
-	int wmm_uapsd;
-	int okc;
-#ifdef CONFIG_IEEE80211W
-	enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
-#define SSID_LEN 32
-	u8 ssid[SSID_LEN];
-	size_t ssid_len;
-	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
-	u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
-	size_t r0_key_holder_len;
-	u8 r1_key_holder[FT_R1KH_ID_LEN];
-	u32 r0_key_lifetime;
-	u32 reassociation_deadline;
-	struct ft_remote_r0kh *r0kh_list;
-	struct ft_remote_r1kh *r1kh_list;
-	int pmk_r1_push;
-#endif /* CONFIG_IEEE80211R */
-};
-
-typedef enum {
-	LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
-} logger_level;
-
-typedef enum {
-	WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
-	WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
-	WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
-} wpa_eapol_variable;
-
-struct wpa_auth_callbacks {
-	void *ctx;
-	void (*logger)(void *ctx, const u8 *addr, logger_level level,
-		       const char *txt);
-	void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
-	void (*mic_failure_report)(void *ctx, const u8 *addr);
-	void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
-			  int value);
-	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
-	const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
-	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
-	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
-		       const u8 *addr, int idx, u8 *key, size_t key_len);
-	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
-	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
-			  size_t data_len, int encrypt);
-	int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
-						 void *ctx), void *cb_ctx);
-	int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
-						  void *ctx), void *cb_ctx);
-	int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
-			  size_t data_len);
-#ifdef CONFIG_IEEE80211R
-	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
-	int (*send_ft_action)(void *ctx, const u8 *dst,
-			      const u8 *data, size_t data_len);
-#endif /* CONFIG_IEEE80211R */
-};
-
-struct wpa_authenticator * wpa_init(const u8 *addr,
-				    struct wpa_auth_config *conf,
-				    struct wpa_auth_callbacks *cb);
-void wpa_deinit(struct wpa_authenticator *wpa_auth);
-int wpa_reconfig(struct wpa_authenticator *wpa_auth,
-		 struct wpa_auth_config *conf);
-
-enum {
-	WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
-	WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
-	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
-	WPA_INVALID_MDIE, WPA_INVALID_PROTO
-};
-	
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm,
-			const u8 *wpa_ie, size_t wpa_ie_len,
-			const u8 *mdie, size_t mdie_len);
-int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
-struct wpa_state_machine *
-wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
-int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
-			    struct wpa_state_machine *sm);
-void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
-void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
-void wpa_receive(struct wpa_authenticator *wpa_auth,
-		 struct wpa_state_machine *sm,
-		 u8 *data, size_t data_len);
-typedef enum {
-	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
-	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
-} wpa_event;
-void wpa_remove_ptk(struct wpa_state_machine *sm);
-int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
-void wpa_auth_sm_notify(struct wpa_state_machine *sm);
-void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
-int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
-int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
-void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
-int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
-int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
-int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
-int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
-int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
-			     struct rsn_pmksa_cache_entry *entry);
-struct rsn_pmksa_cache_entry *
-wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
-void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
-const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
-			       size_t *len);
-int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
-		       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_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
-
-#ifdef CONFIG_IEEE80211R
-u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
-				 size_t max_len, int auth_alg,
-				 const u8 *req_ies, size_t req_ies_len);
-void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
-			 u16 auth_transaction, const u8 *ies, size_t ies_len,
-			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
-				    u16 auth_transaction, u16 resp,
-				    const u8 *ies, size_t ies_len),
-			 void *ctx);
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
-			    size_t ies_len);
-int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
-int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
-		  const u8 *data, size_t data_len);
-void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
-#endif /* CONFIG_IEEE80211R */
-
-#endif /* WPA_AUTH_H */

Copied: vendor/wpa/2.0/src/ap/wpa_auth.h (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,292 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_H
+#define WPA_AUTH_H
+
+#include "common/defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
+ */
+struct ft_rrb_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
+	le16 action_length; /* little endian length of action_frame */
+	u8 ap_address[ETH_ALEN];
+	/*
+	 * Followed by action_length bytes of FT Action frame (from Category
+	 * field to the end of Action Frame body.
+	 */
+} STRUCT_PACKED;
+
+#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
+
+#define FT_PACKET_REQUEST 0
+#define FT_PACKET_RESPONSE 1
+/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
+#define FT_PACKET_R0KH_R1KH_PULL 200
+#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
+
+struct ft_r0kh_r1kh_pull_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
+	le16 data_length; /* little endian length of data (44) */
+	u8 ap_address[ETH_ALEN];
+
+	u8 nonce[16];
+	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 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+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) */
+	u8 ap_address[ETH_ALEN];
+
+	u8 nonce[16]; /* copied from pull */
+	u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
+	u8 s1kh_id[ETH_ALEN]; /* 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 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+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) */
+	u8 ap_address[ETH_ALEN];
+
+	/* Encrypted with AES key-wrap */
+	u8 timestamp[4]; /* current time in seconds since unix epoch, little
+			  * endian */
+	u8 r1kh_id[FT_R1KH_ID_LEN];
+	u8 s1kh_id[ETH_ALEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	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 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+/* per STA state machine data */
+
+struct wpa_authenticator;
+struct wpa_state_machine;
+struct rsn_pmksa_cache_entry;
+struct eapol_state_machine;
+
+
+struct ft_remote_r0kh {
+	struct ft_remote_r0kh *next;
+	u8 addr[ETH_ALEN];
+	u8 id[FT_R0KH_ID_MAX_LEN];
+	size_t id_len;
+	u8 key[16];
+};
+
+
+struct ft_remote_r1kh {
+	struct ft_remote_r1kh *next;
+	u8 addr[ETH_ALEN];
+	u8 id[FT_R1KH_ID_LEN];
+	u8 key[16];
+};
+
+
+struct wpa_auth_config {
+	int wpa;
+	int wpa_key_mgmt;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int wpa_ptk_rekey;
+	int rsn_pairwise;
+	int rsn_preauth;
+	int eapol_version;
+	int peerkey;
+	int wmm_enabled;
+	int wmm_uapsd;
+	int disable_pmksa_caching;
+	int okc;
+	int tx_status;
+#ifdef CONFIG_IEEE80211W
+	enum mfp_options ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+#define SSID_LEN 32
+	u8 ssid[SSID_LEN];
+	size_t ssid_len;
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
+	size_t r0_key_holder_len;
+	u8 r1_key_holder[FT_R1KH_ID_LEN];
+	u32 r0_key_lifetime;
+	u32 reassociation_deadline;
+	struct ft_remote_r0kh *r0kh_list;
+	struct ft_remote_r1kh *r1kh_list;
+	int pmk_r1_push;
+	int ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+	int disable_gtk;
+	int ap_mlme;
+};
+
+typedef enum {
+	LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
+} logger_level;
+
+typedef enum {
+	WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
+	WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
+	WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
+} wpa_eapol_variable;
+
+struct wpa_auth_callbacks {
+	void *ctx;
+	void (*logger)(void *ctx, const u8 *addr, logger_level level,
+		       const char *txt);
+	void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
+	int (*mic_failure_report)(void *ctx, const u8 *addr);
+	void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
+			  int value);
+	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
+	const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
+	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
+	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
+		       const u8 *addr, int idx, u8 *key, size_t key_len);
+	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
+	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
+			  size_t data_len, int encrypt);
+	int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+						 void *ctx), void *cb_ctx);
+	int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
+						  void *ctx), void *cb_ctx);
+	int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
+			  size_t data_len);
+#ifdef CONFIG_IEEE80211R
+	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+	int (*send_ft_action)(void *ctx, const u8 *dst,
+			      const u8 *data, size_t data_len);
+	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
+                         size_t tspec_ielen);
+#endif /* CONFIG_IEEE80211R */
+};
+
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
+void wpa_deinit(struct wpa_authenticator *wpa_auth);
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf);
+
+enum {
+	WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
+	WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
+	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
+	WPA_INVALID_MDIE, WPA_INVALID_PROTO
+};
+	
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len,
+			const u8 *mdie, size_t mdie_len);
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm);
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
+		 u8 *data, size_t data_len);
+typedef enum {
+	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
+	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
+} wpa_event;
+void wpa_remove_ptk(struct wpa_state_machine *sm);
+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
+void wpa_auth_sm_notify(struct wpa_state_machine *sm);
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
+			       size_t *len);
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       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_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);
+
+#ifdef CONFIG_IEEE80211R
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+				 size_t max_len, int auth_alg,
+				 const u8 *req_ies, size_t req_ies_len);
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+			 u16 auth_transaction, const u8 *ies, size_t ies_len,
+			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+				    u16 auth_transaction, u16 resp,
+				    const u8 *ies, size_t ies_len),
+			 void *ctx);
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+			    size_t ies_len);
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+		  const u8 *data, size_t data_len);
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
+#endif /* CONFIG_IEEE80211R */
+
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+
+#endif /* WPA_AUTH_H */

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_ft.c
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_ft.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ft.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1776 +0,0 @@
-/*
- * hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "crypto/aes_wrap.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "wmm.h"
-#include "wpa_auth.h"
-#include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
-
-
-#ifdef CONFIG_IEEE80211R
-
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
-static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
-			   const u8 *data, size_t data_len)
-{
-	if (wpa_auth->cb.send_ether == NULL)
-		return -1;
-	wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
-	return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
-				       data, data_len);
-}
-
-
-static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
-			      const u8 *dst, const u8 *data, size_t data_len)
-{
-	if (wpa_auth->cb.send_ft_action == NULL)
-		return -1;
-	return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
-					   data, data_len);
-}
-
-
-static struct wpa_state_machine *
-wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
-{
-	if (wpa_auth->cb.add_sta == NULL)
-		return NULL;
-	return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
-}
-
-
-int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
-{
-	u8 *pos = buf;
-	u8 capab;
-	if (len < 2 + sizeof(struct rsn_mdie))
-		return -1;
-
-	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-	*pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
-	os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
-	pos += MOBILITY_DOMAIN_ID_LEN;
-	capab = RSN_FT_CAPAB_FT_OVER_DS;
-	*pos++ = capab;
-
-	return pos - buf;
-}
-
-
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
-		   size_t r0kh_id_len,
-		   const u8 *anonce, const u8 *snonce,
-		   u8 *buf, size_t len, const u8 *subelem,
-		   size_t subelem_len)
-{
-	u8 *pos = buf, *ielen;
-	struct rsn_ftie *hdr;
-
-	if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
-	    subelem_len)
-		return -1;
-
-	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
-	ielen = pos++;
-
-	hdr = (struct rsn_ftie *) pos;
-	os_memset(hdr, 0, sizeof(*hdr));
-	pos += sizeof(*hdr);
-	WPA_PUT_LE16(hdr->mic_control, 0);
-	if (anonce)
-		os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
-	if (snonce)
-		os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
-
-	/* Optional Parameters */
-	*pos++ = FTIE_SUBELEM_R1KH_ID;
-	*pos++ = FT_R1KH_ID_LEN;
-	os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
-	pos += FT_R1KH_ID_LEN;
-
-	if (r0kh_id) {
-		*pos++ = FTIE_SUBELEM_R0KH_ID;
-		*pos++ = r0kh_id_len;
-		os_memcpy(pos, r0kh_id, r0kh_id_len);
-		pos += r0kh_id_len;
-	}
-
-	if (subelem) {
-		os_memcpy(pos, subelem, subelem_len);
-		pos += subelem_len;
-	}
-
-	*ielen = pos - buf - 2;
-
-	return pos - buf;
-}
-
-
-struct wpa_ft_pmk_r0_sa {
-	struct wpa_ft_pmk_r0_sa *next;
-	u8 pmk_r0[PMK_LEN];
-	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
-	u8 spa[ETH_ALEN];
-	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
-	int pmk_r1_pushed;
-};
-
-struct wpa_ft_pmk_r1_sa {
-	struct wpa_ft_pmk_r1_sa *next;
-	u8 pmk_r1[PMK_LEN];
-	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
-	u8 spa[ETH_ALEN];
-	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
-};
-
-struct wpa_ft_pmk_cache {
-	struct wpa_ft_pmk_r0_sa *pmk_r0;
-	struct wpa_ft_pmk_r1_sa *pmk_r1;
-};
-
-struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
-{
-	struct wpa_ft_pmk_cache *cache;
-
-	cache = os_zalloc(sizeof(*cache));
-
-	return cache;
-}
-
-
-void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
-{
-	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
-	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
-
-	r0 = cache->pmk_r0;
-	while (r0) {
-		r0prev = r0;
-		r0 = r0->next;
-		os_memset(r0prev->pmk_r0, 0, PMK_LEN);
-		os_free(r0prev);
-	}
-
-	r1 = cache->pmk_r1;
-	while (r1) {
-		r1prev = r1;
-		r1 = r1->next;
-		os_memset(r1prev->pmk_r1, 0, PMK_LEN);
-		os_free(r1prev);
-	}
-
-	os_free(cache);
-}
-
-
-static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
-			       const u8 *spa, const u8 *pmk_r0,
-			       const u8 *pmk_r0_name, int pairwise)
-{
-	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
-	struct wpa_ft_pmk_r0_sa *r0;
-
-	/* TODO: add expiration and limit on number of entries in cache */
-
-	r0 = os_zalloc(sizeof(*r0));
-	if (r0 == NULL)
-		return -1;
-
-	os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
-	os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
-	os_memcpy(r0->spa, spa, ETH_ALEN);
-	r0->pairwise = pairwise;
-
-	r0->next = cache->pmk_r0;
-	cache->pmk_r0 = r0;
-
-	return 0;
-}
-
-
-static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
-			       const u8 *spa, const u8 *pmk_r0_name,
-			       u8 *pmk_r0, int *pairwise)
-{
-	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
-	struct wpa_ft_pmk_r0_sa *r0;
-
-	r0 = cache->pmk_r0;
-	while (r0) {
-		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
-		    os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
-		    == 0) {
-			os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
-			if (pairwise)
-				*pairwise = r0->pairwise;
-			return 0;
-		}
-
-		r0 = r0->next;
-	}
-
-	return -1;
-}
-
-
-static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
-			       const u8 *spa, const u8 *pmk_r1,
-			       const u8 *pmk_r1_name, int pairwise)
-{
-	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
-	struct wpa_ft_pmk_r1_sa *r1;
-
-	/* TODO: add expiration and limit on number of entries in cache */
-
-	r1 = os_zalloc(sizeof(*r1));
-	if (r1 == NULL)
-		return -1;
-
-	os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
-	os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
-	os_memcpy(r1->spa, spa, ETH_ALEN);
-	r1->pairwise = pairwise;
-
-	r1->next = cache->pmk_r1;
-	cache->pmk_r1 = r1;
-
-	return 0;
-}
-
-
-static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
-			       const u8 *spa, const u8 *pmk_r1_name,
-			       u8 *pmk_r1, int *pairwise)
-{
-	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
-	struct wpa_ft_pmk_r1_sa *r1;
-
-	r1 = cache->pmk_r1;
-	while (r1) {
-		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
-		    os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
-		    == 0) {
-			os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
-			if (pairwise)
-				*pairwise = r1->pairwise;
-			return 0;
-		}
-
-		r1 = r1->next;
-	}
-
-	return -1;
-}
-
-
-static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
-			      const u8 *s1kh_id, const u8 *r0kh_id,
-			      size_t r0kh_id_len, const u8 *pmk_r0_name)
-{
-	struct ft_remote_r0kh *r0kh;
-	struct ft_r0kh_r1kh_pull_frame frame, f;
-
-	r0kh = wpa_auth->conf.r0kh_list;
-	while (r0kh) {
-		if (r0kh->id_len == r0kh_id_len &&
-		    os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
-			break;
-		r0kh = r0kh->next;
-	}
-	if (r0kh == NULL)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
-		   "address " MACSTR, MAC2STR(r0kh->addr));
-
-	os_memset(&frame, 0, sizeof(frame));
-	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
-	frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
-	frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
-	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
-
-	/* aes_wrap() does not support inplace encryption, so use a temporary
-	 * buffer for the data. */
-	if (os_get_random(f.nonce, sizeof(f.nonce))) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
-			   "nonce");
-		return -1;
-	}
-	os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
-	os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
-	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
-
-	if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
-		     f.nonce, frame.nonce) < 0)
-		return -1;
-
-	wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
-
-	return 0;
-}
-
-
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
-			   struct wpa_ptk *ptk, size_t ptk_len)
-{
-	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
-	u8 pmk_r1[PMK_LEN];
-	u8 ptk_name[WPA_PMK_NAME_LEN];
-	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
-	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
-	size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
-	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
-	const u8 *ssid = sm->wpa_auth->conf.ssid;
-	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
-
-
-	if (sm->xxkey_len == 0) {
-		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
-			   "derivation");
-		return -1;
-	}
-
-	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
-			  r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
-			    sm->pairwise);
-
-	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
-			  pmk_r1, sm->pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
-		    WPA_PMK_NAME_LEN);
-	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
-			    sm->pairwise);
-
-	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
-			  sm->wpa_auth->addr, sm->pmk_r1_name,
-			  (u8 *) ptk, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	return 0;
-}
-
-
-static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
-				      const u8 *addr, int idx, u8 *seq)
-{
-	if (wpa_auth->cb.get_seqnum == NULL)
-		return -1;
-	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
-}
-
-
-static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
-{
-	u8 *subelem;
-	struct wpa_group *gsm = sm->group;
-	size_t subelem_len, pad_len;
-	const u8 *key;
-	size_t key_len;
-	u8 keybuf[32];
-
-	key_len = gsm->GTK_len;
-	if (key_len > sizeof(keybuf))
-		return NULL;
-
-	/*
-	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
-	 * than 16 bytes.
-	 */
-	pad_len = key_len % 8;
-	if (pad_len)
-		pad_len = 8 - pad_len;
-	if (key_len + pad_len < 16)
-		pad_len += 8;
-	if (pad_len) {
-		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
-		os_memset(keybuf + key_len, 0, pad_len);
-		keybuf[key_len] = 0xdd;
-		key_len += pad_len;
-		key = keybuf;
-	} else
-		key = gsm->GTK[gsm->GN - 1];
-
-	/*
-	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
-	 * Key[5..32].
-	 */
-	subelem_len = 13 + key_len + 8;
-	subelem = os_zalloc(subelem_len);
-	if (subelem == NULL)
-		return NULL;
-
-	subelem[0] = FTIE_SUBELEM_GTK;
-	subelem[1] = 11 + key_len + 8;
-	/* Key ID in B0-B1 of Key Info */
-	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
-	subelem[4] = gsm->GTK_len;
-	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
-	if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
-		os_free(subelem);
-		return NULL;
-	}
-
-	*len = subelem_len;
-	return subelem;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
-{
-	u8 *subelem, *pos;
-	struct wpa_group *gsm = sm->group;
-	size_t subelem_len;
-
-	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
-	 * Key[16+8] */
-	subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
-	subelem = os_zalloc(subelem_len);
-	if (subelem == NULL)
-		return NULL;
-
-	pos = subelem;
-	*pos++ = FTIE_SUBELEM_IGTK;
-	*pos++ = subelem_len - 2;
-	WPA_PUT_LE16(pos, gsm->GN_igtk);
-	pos += 2;
-	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
-	pos += 6;
-	*pos++ = WPA_IGTK_LEN;
-	if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
-		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
-		os_free(subelem);
-		return NULL;
-	}
-
-	*len = subelem_len;
-	return subelem;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
-static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
-				const u8 *ies, size_t ies_len)
-{
-	struct ieee802_11_elems parse;
-	struct rsn_rdie *rdie;
-
-	wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
-		   id, descr_count);
-	wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
-		    ies, ies_len);
-
-	if (end - pos < (int) sizeof(*rdie)) {
-		wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
-		return pos;
-	}
-
-	*pos++ = WLAN_EID_RIC_DATA;
-	*pos++ = sizeof(*rdie);
-	rdie = (struct rsn_rdie *) pos;
-	rdie->id = id;
-	rdie->descr_count = 0;
-	rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
-	pos += sizeof(*rdie);
-
-	if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
-	    ParseFailed) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
-		rdie->status_code =
-			host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
-		return pos;
-	}
-
-#ifdef NEED_AP_MLME
-	if (parse.wmm_tspec) {
-		struct wmm_tspec_element *tspec;
-		int res;
-
-		if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
-			wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
-				   "(%d)", (int) parse.wmm_tspec_len);
-			rdie->status_code =
-				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
-			return pos;
-		}
-		if (end - pos < (int) sizeof(*tspec)) {
-			wpa_printf(MSG_ERROR, "FT: Not enough room for "
-				   "response TSPEC");
-			rdie->status_code =
-				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
-			return pos;
-		}
-		tspec = (struct wmm_tspec_element *) pos;
-		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
-		res = wmm_process_tspec(tspec);
-		wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
-		if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
-			rdie->status_code =
-				host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
-		else if (res == WMM_ADDTS_STATUS_REFUSED)
-			rdie->status_code =
-				host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
-		else {
-			/* TSPEC accepted; include updated TSPEC in response */
-			rdie->descr_count = 1;
-			pos += sizeof(*tspec);
-		}
-		return pos;
-	}
-#endif /* NEED_AP_MLME */
-
-	wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
-	rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
-	return pos;
-}
-
-
-static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
-{
-	const u8 *rpos, *start;
-	const struct rsn_rdie *rdie;
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
-
-	rpos = ric;
-	while (rpos + sizeof(*rdie) < ric + ric_len) {
-		if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
-		    rpos + 2 + rpos[1] > ric + ric_len)
-			break;
-		rdie = (const struct rsn_rdie *) (rpos + 2);
-		rpos += 2 + rpos[1];
-		start = rpos;
-
-		while (rpos + 2 <= ric + ric_len &&
-		       rpos + 2 + rpos[1] <= ric + ric_len) {
-			if (rpos[0] == WLAN_EID_RIC_DATA)
-				break;
-			rpos += 2 + rpos[1];
-		}
-		pos = wpa_ft_process_rdie(pos, end, rdie->id,
-					  rdie->descr_count,
-					  start, rpos - start);
-	}
-
-	return pos;
-}
-
-
-u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
-				 size_t max_len, int auth_alg,
-				 const u8 *req_ies, size_t req_ies_len)
-{
-	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
-	size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
-	int res;
-	struct wpa_auth_config *conf;
-	struct rsn_ftie *_ftie;
-	struct wpa_ft_ies parse;
-	u8 *ric_start;
-	u8 *anonce, *snonce;
-
-	if (sm == NULL)
-		return pos;
-
-	conf = &sm->wpa_auth->conf;
-
-	if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
-		return pos;
-
-	end = pos + max_len;
-
-	if (auth_alg == WLAN_AUTH_FT) {
-		/*
-		 * RSN (only present if this is a Reassociation Response and
-		 * part of a fast BSS transition)
-		 */
-		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
-		if (res < 0)
-			return pos;
-		rsnie = pos;
-		rsnie_len = res;
-		pos += res;
-	}
-
-	/* Mobility Domain Information */
-	res = wpa_write_mdie(conf, pos, end - pos);
-	if (res < 0)
-		return pos;
-	mdie = pos;
-	mdie_len = res;
-	pos += res;
-
-	/* Fast BSS Transition Information */
-	if (auth_alg == WLAN_AUTH_FT) {
-		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
-		r0kh_id = sm->r0kh_id;
-		r0kh_id_len = sm->r0kh_id_len;
-		anonce = sm->ANonce;
-		snonce = sm->SNonce;
-#ifdef CONFIG_IEEE80211W
-		if (sm->mgmt_frame_prot) {
-			u8 *igtk;
-			size_t igtk_len;
-			u8 *nbuf;
-			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
-			if (igtk == NULL) {
-				os_free(subelem);
-				return pos;
-			}
-			nbuf = os_realloc(subelem, subelem_len + igtk_len);
-			if (nbuf == NULL) {
-				os_free(subelem);
-				os_free(igtk);
-				return pos;
-			}
-			subelem = nbuf;
-			os_memcpy(subelem + subelem_len, igtk, igtk_len);
-			subelem_len += igtk_len;
-			os_free(igtk);
-		}
-#endif /* CONFIG_IEEE80211W */
-	} else {
-		r0kh_id = conf->r0_key_holder;
-		r0kh_id_len = conf->r0_key_holder_len;
-		anonce = NULL;
-		snonce = NULL;
-	}
-	res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
-			     end - pos, subelem, subelem_len);
-	os_free(subelem);
-	if (res < 0)
-		return pos;
-	ftie = pos;
-	ftie_len = res;
-	pos += res;
-
-	os_free(sm->assoc_resp_ftie);
-	sm->assoc_resp_ftie = os_malloc(ftie_len);
-	if (sm->assoc_resp_ftie)
-		os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
-
-	_ftie = (struct rsn_ftie *) (ftie + 2);
-	if (auth_alg == WLAN_AUTH_FT)
-		_ftie->mic_control[1] = 3; /* Information element count */
-
-	ric_start = pos;
-	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
-		pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
-		if (auth_alg == WLAN_AUTH_FT)
-			_ftie->mic_control[1] +=
-				ieee802_11_ie_count(ric_start,
-						    pos - ric_start);
-	}
-	if (ric_start == pos)
-		ric_start = NULL;
-
-	if (auth_alg == WLAN_AUTH_FT &&
-	    wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
-		       mdie, mdie_len, ftie, ftie_len,
-		       rsnie, rsnie_len,
-		       ric_start, ric_start ? pos - ric_start : 0,
-		       _ftie->mic) < 0)
-		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
-
-	return pos;
-}
-
-
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		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]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			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]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* 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];
-	}
-	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);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
-				   int vlan_id,
-				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
-{
-	if (wpa_auth->cb.set_key == NULL)
-		return -1;
-	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
-				    key, key_len);
-}
-
-
-void wpa_ft_install_ptk(struct wpa_state_machine *sm)
-{
-	enum wpa_alg alg;
-	int klen;
-
-	/* MLME-SETKEYS.request(PTK) */
-	if (sm->pairwise == WPA_CIPHER_TKIP) {
-		alg = WPA_ALG_TKIP;
-		klen = 32;
-	} else if (sm->pairwise == WPA_CIPHER_CCMP) {
-		alg = WPA_ALG_CCMP;
-		klen = 16;
-	} else {
-		wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
-			   "PTK configuration", sm->pairwise);
-		return;
-	}
-
-	/* FIX: add STA entry to kernel/driver here? The set_key will fail
-	 * most likely without this.. At the moment, STA entry is added only
-	 * after association has been completed. This function will be called
-	 * again after association to get the PTK configured, but that could be
-	 * optimized by adding the STA entry earlier.
-	 */
-	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk1, klen))
-		return;
-
-	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
-	sm->pairwise_set = TRUE;
-}
-
-
-static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
-				   const u8 *ies, size_t ies_len,
-				   u8 **resp_ies, size_t *resp_ies_len)
-{
-	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
-	u8 ptk_name[WPA_PMK_NAME_LEN];
-	struct wpa_auth_config *conf;
-	struct wpa_ft_ies parse;
-	size_t buflen, ptk_len;
-	int ret;
-	u8 *pos, *end;
-	int pairwise;
-
-	*resp_ies = NULL;
-	*resp_ies_len = 0;
-
-	sm->pmk_r1_name_valid = 0;
-	conf = &sm->wpa_auth->conf;
-
-	wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
-		    ies, ies_len);
-
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	mdie = (struct rsn_mdie *) parse.mdie;
-	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain,
-		      sm->wpa_auth->conf.mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
-		return WLAN_STATUS_INVALID_MDIE;
-	}
-
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return WLAN_STATUS_INVALID_FTIE;
-	}
-
-	os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
-
-	if (parse.r0kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
-		return WLAN_STATUS_INVALID_FTIE;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
-		    parse.r0kh_id, parse.r0kh_id_len);
-	os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
-	sm->r0kh_id_len = parse.r0kh_id_len;
-
-	if (parse.rsn_pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
-		return WLAN_STATUS_INVALID_PMKID;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
-		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1_name(parse.rsn_pmkid,
-			       sm->wpa_auth->conf.r1_key_holder, sm->addr,
-			       pmk_r1_name);
-	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
-		    pmk_r1_name, WPA_PMK_NAME_LEN);
-
-	if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
-		    &pairwise) < 0) {
-		if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
-				       sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
-			wpa_printf(MSG_DEBUG, "FT: Did not have matching "
-				   "PMK-R1 and unknown R0KH-ID");
-			return WLAN_STATUS_INVALID_PMKID;
-		}
-
-		/*
-		 * TODO: Should return "status pending" (and the caller should
-		 * not send out response now). The real response will be sent
-		 * once the response from R0KH is received.
-		 */
-		return WLAN_STATUS_INVALID_PMKID;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
-	sm->pmk_r1_name_valid = 1;
-	os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
-
-	if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
-			   "ANonce");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-		    sm->SNonce, WPA_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
-		    sm->ANonce, WPA_NONCE_LEN);
-
-	ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48;
-	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
-			  sm->wpa_auth->addr, pmk_r1_name,
-			  (u8 *) &sm->PTK, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
-			(u8 *) &sm->PTK, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	sm->pairwise = pairwise;
-	wpa_ft_install_ptk(sm);
-
-	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
-		2 + FT_R1KH_ID_LEN + 200;
-	*resp_ies = os_zalloc(buflen);
-	if (*resp_ies == NULL) {
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	pos = *resp_ies;
-	end = *resp_ies + buflen;
-
-	ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-	pos += ret;
-
-	ret = wpa_write_mdie(conf, pos, end - pos);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-	pos += ret;
-
-	ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
-			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
-	if (ret < 0) {
-		os_free(*resp_ies);
-		*resp_ies = NULL;
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-	pos += ret;
-
-	*resp_ies_len = pos - *resp_ies;
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
-			 u16 auth_transaction, const u8 *ies, size_t ies_len,
-			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
-				    u16 auth_transaction, u16 status,
-				    const u8 *ies, size_t ies_len),
-			 void *ctx)
-{
-	u16 status;
-	u8 *resp_ies;
-	size_t resp_ies_len;
-
-	if (sm == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
-			   "WPA SM not available");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
-		   " BSSID=" MACSTR " transaction=%d",
-		   MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
-	status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
-					 &resp_ies_len);
-
-	wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
-		   " auth_transaction=%d status=%d",
-		   MAC2STR(sm->addr), auth_transaction + 1, status);
-	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
-	cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
-	   resp_ies, resp_ies_len);
-	os_free(resp_ies);
-}
-
-
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
-			    size_t ies_len)
-{
-	struct wpa_ft_ies parse;
-	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	u8 mic[16];
-	unsigned int count;
-
-	if (sm == NULL)
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-
-	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
-
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	if (parse.rsn == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	if (parse.rsn_pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
-		return WLAN_STATUS_INVALID_PMKID;
-	}
-
-	if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
-	{
-		wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
-			   "with the PMKR1Name derived from auth request");
-		return WLAN_STATUS_INVALID_PMKID;
-	}
-
-	mdie = (struct rsn_mdie *) parse.mdie;
-	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain,
-		      sm->wpa_auth->conf.mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
-		return WLAN_STATUS_INVALID_MDIE;
-	}
-
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return WLAN_STATUS_INVALID_FTIE;
-	}
-
-	if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
-		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
-			    sm->SNonce, WPA_NONCE_LEN);
-		return -1;
-	}
-
-	if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
-		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
-			    ftie->anonce, WPA_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
-			    sm->ANonce, WPA_NONCE_LEN);
-		return -1;
-	}
-
-
-	if (parse.r0kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (parse.r0kh_id_len != sm->r0kh_id_len ||
-	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
-			   "the current R0KH-ID");
-		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
-			    parse.r0kh_id, parse.r0kh_id_len);
-		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
-			    sm->r0kh_id, sm->r0kh_id_len);
-		return -1;
-	}
-
-	if (parse.r1kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
-		      FT_R1KH_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
-			   "ReassocReq");
-		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
-			    parse.r1kh_id, FT_R1KH_ID_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
-			    sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
-		return -1;
-	}
-
-	if (parse.rsn_pmkid == NULL ||
-	    os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
-		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
-			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
-		return -1;
-	}
-
-	count = 3;
-	if (parse.ric)
-		count++;
-	if (ftie->mic_control[1] != count) {
-		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
-			   "Control: received %u expected %u",
-			   ftie->mic_control[1], count);
-		return -1;
-	}
-
-	if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
-		       parse.mdie - 2, parse.mdie_len + 2,
-		       parse.ftie - 2, parse.ftie_len + 2,
-		       parse.rsn - 2, parse.rsn_len + 2,
-		       parse.ric, parse.ric_len,
-		       mic) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
-		return WLAN_STATUS_UNSPECIFIED_FAILURE;
-	}
-
-	if (os_memcmp(mic, ftie->mic, 16) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
-		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
-		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
-		return WLAN_STATUS_INVALID_FTIE;
-	}
-
-	return WLAN_STATUS_SUCCESS;
-}
-
-
-int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
-{
-	const u8 *sta_addr, *target_ap;
-	const u8 *ies;
-	size_t ies_len;
-	u8 action;
-	struct ft_rrb_frame *frame;
-
-	if (sm == NULL)
-		return -1;
-
-	/*
-	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
-	 * FT Request action frame body[variable]
-	 */
-
-	if (len < 14) {
-		wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
-			   "(len=%lu)", (unsigned long) len);
-		return -1;
-	}
-
-	action = data[1];
-	sta_addr = data + 2;
-	target_ap = data + 8;
-	ies = data + 14;
-	ies_len = len - 14;
-
-	wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
-		   " Target AP=" MACSTR " Action=%d)",
-		   MAC2STR(sta_addr), MAC2STR(target_ap), action);
-
-	if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
-			   "STA=" MACSTR " STA-Address=" MACSTR,
-			   MAC2STR(sm->addr), MAC2STR(sta_addr));
-		return -1;
-	}
-
-	/*
-	 * Do some sanity checking on the target AP address (not own and not
-	 * broadcast. This could be extended to filter based on a list of known
-	 * APs in the MD (if such a list were configured).
-	 */
-	if ((target_ap[0] & 0x01) ||
-	    os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
-			   "frame");
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
-
-	/* RRB - Forward action frame to the target AP */
-	frame = os_malloc(sizeof(*frame) + len);
-	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
-	frame->packet_type = FT_PACKET_REQUEST;
-	frame->action_length = host_to_le16(len);
-	os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
-	os_memcpy(frame + 1, data, len);
-
-	wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
-			sizeof(*frame) + len);
-	os_free(frame);
-
-	return 0;
-}
-
-
-static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
-				 const u8 *current_ap, const u8 *sta_addr,
-				 const u8 *body, size_t len)
-{
-	struct wpa_state_machine *sm;
-	u16 status;
-	u8 *resp_ies, *pos;
-	size_t resp_ies_len, rlen;
-	struct ft_rrb_frame *frame;
-
-	sm = wpa_ft_add_sta(wpa_auth, sta_addr);
-	if (sm == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
-			   "RRB Request");
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
-
-	status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
-					 &resp_ies_len);
-
-	wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
-		   " CurrentAP=" MACSTR " status=%d",
-		   MAC2STR(sm->addr), MAC2STR(current_ap), status);
-	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
-
-	/* RRB - Forward action frame response to the Current AP */
-
-	/*
-	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
-	 * Status_Code[2] FT Request action frame body[variable]
-	 */
-	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
-
-	frame = os_malloc(sizeof(*frame) + rlen);
-	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
-	frame->packet_type = FT_PACKET_RESPONSE;
-	frame->action_length = host_to_le16(rlen);
-	os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
-	pos = (u8 *) (frame + 1);
-	*pos++ = WLAN_ACTION_FT;
-	*pos++ = 2; /* Action: Response */
-	os_memcpy(pos, sta_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	WPA_PUT_LE16(pos, status);
-	pos += 2;
-	if (resp_ies) {
-		os_memcpy(pos, resp_ies, resp_ies_len);
-		os_free(resp_ies);
-	}
-
-	wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
-			sizeof(*frame) + rlen);
-	os_free(frame);
-
-	return 0;
-}
-
-
-static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
-			      const u8 *src_addr,
-			      const u8 *data, size_t data_len)
-{
-	struct ft_r0kh_r1kh_pull_frame *frame, f;
-	struct ft_remote_r1kh *r1kh;
-	struct ft_r0kh_r1kh_resp_frame resp, r;
-	u8 pmk_r0[PMK_LEN];
-	int pairwise;
-
-	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
-
-	if (data_len < sizeof(*frame))
-		return -1;
-
-	r1kh = wpa_auth->conf.r1kh_list;
-	while (r1kh) {
-		if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
-			break;
-		r1kh = r1kh->next;
-	}
-	if (r1kh == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
-			   "PMK-R1 pull source address " MACSTR,
-			   MAC2STR(src_addr));
-		return -1;
-	}
-
-	frame = (struct ft_r0kh_r1kh_pull_frame *) data;
-	/* aes_unwrap() does not support inplace decryption, so use a temporary
-	 * buffer for the data. */
-	if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
-		       frame->nonce, f.nonce) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
-			   "request from " MACSTR, MAC2STR(src_addr));
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
-		    f.nonce, sizeof(f.nonce));
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
-		    f.pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
-		   MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
-
-	os_memset(&resp, 0, sizeof(resp));
-	resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
-	resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
-	resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
-	os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
-
-	/* aes_wrap() does not support inplace encryption, so use a temporary
-	 * buffer for the data. */
-	os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
-	os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
-	os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
-	if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
-				&pairwise) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
-			   "PMK-R1 pull");
-		return -1;
-	}
-
-	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
-			  r.pmk_r1, r.pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
-		    WPA_PMK_NAME_LEN);
-	r.pairwise = host_to_le16(pairwise);
-
-	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
-		     r.nonce, resp.nonce) < 0) {
-		os_memset(pmk_r0, 0, PMK_LEN);
-		return -1;
-	}
-
-	os_memset(pmk_r0, 0, PMK_LEN);
-
-	wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
-
-	return 0;
-}
-
-
-static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
-			      const u8 *src_addr,
-			      const u8 *data, size_t data_len)
-{
-	struct ft_r0kh_r1kh_resp_frame *frame, f;
-	struct ft_remote_r0kh *r0kh;
-	int pairwise;
-
-	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
-
-	if (data_len < sizeof(*frame))
-		return -1;
-
-	r0kh = wpa_auth->conf.r0kh_list;
-	while (r0kh) {
-		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
-			break;
-		r0kh = r0kh->next;
-	}
-	if (r0kh == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
-			   "PMK-R0 pull response source address " MACSTR,
-			   MAC2STR(src_addr));
-		return -1;
-	}
-
-	frame = (struct ft_r0kh_r1kh_resp_frame *) data;
-	/* aes_unwrap() does not support inplace decryption, so use a temporary
-	 * buffer for the data. */
-	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
-		       frame->nonce, f.nonce) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
-			   "response from " MACSTR, MAC2STR(src_addr));
-		return -1;
-	}
-
-	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
-	    != 0) {
-		wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
-			   "matching R1KH-ID");
-		return -1;
-	}
-
-	/* TODO: verify that <nonce,s1kh_id> matches with a pending request
-	 * and call this requests callback function to finish request
-	 * processing */
-
-	pairwise = le_to_host16(f.pairwise);
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
-		    f.nonce, sizeof(f.nonce));
-	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
-		   MACSTR " pairwise=0x%x",
-		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
-			f.pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
-			f.pmk_r1_name, WPA_PMK_NAME_LEN);
-
-	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
-			    pairwise);
-	os_memset(f.pmk_r1, 0, PMK_LEN);
-
-	return 0;
-}
-
-
-static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
-			      const u8 *src_addr,
-			      const u8 *data, size_t data_len)
-{
-	struct ft_r0kh_r1kh_push_frame *frame, f;
-	struct ft_remote_r0kh *r0kh;
-	struct os_time now;
-	os_time_t tsend;
-	int pairwise;
-
-	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
-
-	if (data_len < sizeof(*frame))
-		return -1;
-
-	r0kh = wpa_auth->conf.r0kh_list;
-	while (r0kh) {
-		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
-			break;
-		r0kh = r0kh->next;
-	}
-	if (r0kh == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
-			   "PMK-R0 push source address " MACSTR,
-			   MAC2STR(src_addr));
-		return -1;
-	}
-
-	frame = (struct ft_r0kh_r1kh_push_frame *) data;
-	/* aes_unwrap() does not support inplace decryption, so use a temporary
-	 * buffer for the data. */
-	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
-		       frame->timestamp, f.timestamp) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
-			   MACSTR, MAC2STR(src_addr));
-		return -1;
-	}
-
-	os_get_time(&now);
-	tsend = WPA_GET_LE32(f.timestamp);
-	if ((now.sec > tsend && now.sec - tsend > 60) ||
-	    (now.sec < tsend && tsend - now.sec > 60)) {
-		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
-			   "timestamp: sender time %d own time %d\n",
-			   (int) tsend, (int) now.sec);
-		return -1;
-	}
-
-	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
-	    != 0) {
-		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
-			   "R1KH-ID (received " MACSTR " own " MACSTR ")",
-			   MAC2STR(f.r1kh_id),
-			   MAC2STR(wpa_auth->conf.r1_key_holder));
-		return -1;
-	}
-
-	pairwise = le_to_host16(f.pairwise);
-	wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
-		   MACSTR " pairwise=0x%x",
-		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
-			f.pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
-			f.pmk_r1_name, WPA_PMK_NAME_LEN);
-
-	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
-			    pairwise);
-	os_memset(f.pmk_r1, 0, PMK_LEN);
-
-	return 0;
-}
-
-
-int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
-		  const u8 *data, size_t data_len)
-{
-	struct ft_rrb_frame *frame;
-	u16 alen;
-	const u8 *pos, *end, *start;
-	u8 action;
-	const u8 *sta_addr, *target_ap_addr;
-
-	wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
-		   MAC2STR(src_addr));
-
-	if (data_len < sizeof(*frame)) {
-		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
-			   (unsigned long) data_len);
-		return -1;
-	}
-
-	pos = data;
-	frame = (struct ft_rrb_frame *) pos;
-	pos += sizeof(*frame);
-
-	alen = le_to_host16(frame->action_length);
-	wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
-		   "action_length=%d ap_address=" MACSTR,
-		   frame->frame_type, frame->packet_type, alen,
-		   MAC2STR(frame->ap_address));
-
-	if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
-		/* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
-		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
-			   "unrecognized type %d", frame->frame_type);
-		return -1;
-	}
-
-	if (alen > data_len - sizeof(*frame)) {
-		wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
-			   "frame");
-		return -1;
-	}
-
-	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
-		return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
-	if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
-		return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
-	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
-		return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
-
-	if (alen < 1 + 1 + 2 * ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
-			   "room for Action Frame body); alen=%lu",
-			   (unsigned long) alen);
-		return -1;
-	}
-	start = pos;
-	end = pos + alen;
-
-	if (*pos != WLAN_ACTION_FT) {
-		wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
-			   "%d", *pos);
-		return -1;
-	}
-
-	pos++;
-	action = *pos++;
-	sta_addr = pos;
-	pos += ETH_ALEN;
-	target_ap_addr = pos;
-	pos += ETH_ALEN;
-	wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
-		   MACSTR " target_ap_addr=" MACSTR,
-		   action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
-
-	if (frame->packet_type == FT_PACKET_REQUEST) {
-		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
-
-		if (action != 1) {
-			wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
-				   "RRB Request", action);
-			return -1;
-		}
-
-		if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
-			wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
-				   "RRB Request does not match with own "
-				   "address");
-			return -1;
-		}
-
-		if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
-					  sta_addr, pos, end - pos) < 0)
-			return -1;
-	} else if (frame->packet_type == FT_PACKET_RESPONSE) {
-		u16 status_code;
-
-		if (end - pos < 2) {
-			wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
-				   "code in RRB Response");
-			return -1;
-		}
-		status_code = WPA_GET_LE16(pos);
-		pos += 2;
-
-		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
-			   "(status_code=%d)", status_code);
-
-		if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
-			return -1;
-	} else {
-		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
-			   "packet_type %d", frame->packet_type);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
-				   struct wpa_ft_pmk_r0_sa *pmk_r0,
-				   struct ft_remote_r1kh *r1kh,
-				   const u8 *s1kh_id, int pairwise)
-{
-	struct ft_r0kh_r1kh_push_frame frame, f;
-	struct os_time now;
-
-	os_memset(&frame, 0, sizeof(frame));
-	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
-	frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
-	frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
-	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
-
-	/* aes_wrap() does not support inplace encryption, so use a temporary
-	 * buffer for the data. */
-	os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
-	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
-	os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
-			  s1kh_id, f.pmk_r1, f.pmk_r1_name);
-	wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
-		    WPA_PMK_NAME_LEN);
-	os_get_time(&now);
-	WPA_PUT_LE32(f.timestamp, now.sec);
-	f.pairwise = host_to_le16(pairwise);
-	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
-		     f.timestamp, frame.timestamp) < 0)
-		return;
-
-	wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
-}
-
-
-void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
-{
-	struct wpa_ft_pmk_r0_sa *r0;
-	struct ft_remote_r1kh *r1kh;
-
-	if (!wpa_auth->conf.pmk_r1_push)
-		return;
-
-	r0 = wpa_auth->ft_pmk_cache->pmk_r0;
-	while (r0) {
-		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
-			break;
-		r0 = r0->next;
-	}
-
-	if (r0 == NULL || r0->pmk_r1_pushed)
-		return;
-	r0->pmk_r1_pushed = 1;
-
-	wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
-		   "for STA " MACSTR, MAC2STR(addr));
-
-	r1kh = wpa_auth->conf.r1kh_list;
-	while (r1kh) {
-		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
-		r1kh = r1kh->next;
-	}
-}
-
-#endif /* CONFIG_IEEE80211R */

Copied: vendor/wpa/2.0/src/ap/wpa_auth_ft.c (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_ft.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_ft.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ft.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1654 @@
+/*
+ * hostapd - IEEE 802.11r - Fast BSS Transition
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/random.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wmm.h"
+#include "wpa_auth.h"
+#include "wpa_auth_i.h"
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
+			   const u8 *data, size_t data_len)
+{
+	if (wpa_auth->cb.send_ether == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
+	return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
+				       data, data_len);
+}
+
+
+static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
+			      const u8 *dst, const u8 *data, size_t data_len)
+{
+	if (wpa_auth->cb.send_ft_action == NULL)
+		return -1;
+	return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
+					   data, data_len);
+}
+
+
+static struct wpa_state_machine *
+wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+	if (wpa_auth->cb.add_sta == NULL)
+		return NULL;
+	return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
+}
+
+
+static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
+			    const u8 *sta_addr,
+			    u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (wpa_auth->cb.add_tspec == NULL) {
+	        wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+		return -1;
+	}
+	return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
+				      tspec_ielen);
+}
+
+
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+	u8 *pos = buf;
+	u8 capab;
+	if (len < 2 + sizeof(struct rsn_mdie))
+		return -1;
+
+	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+	*pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
+	os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	capab = 0;
+	if (conf->ft_over_ds)
+		capab |= RSN_FT_CAPAB_FT_OVER_DS;
+	*pos++ = capab;
+
+	return pos - buf;
+}
+
+
+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
+		   size_t r0kh_id_len,
+		   const u8 *anonce, const u8 *snonce,
+		   u8 *buf, size_t len, const u8 *subelem,
+		   size_t subelem_len)
+{
+	u8 *pos = buf, *ielen;
+	struct rsn_ftie *hdr;
+
+	if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+	    subelem_len)
+		return -1;
+
+	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
+	ielen = pos++;
+
+	hdr = (struct rsn_ftie *) pos;
+	os_memset(hdr, 0, sizeof(*hdr));
+	pos += sizeof(*hdr);
+	WPA_PUT_LE16(hdr->mic_control, 0);
+	if (anonce)
+		os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+	if (snonce)
+		os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+
+	/* Optional Parameters */
+	*pos++ = FTIE_SUBELEM_R1KH_ID;
+	*pos++ = FT_R1KH_ID_LEN;
+	os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+
+	if (r0kh_id) {
+		*pos++ = FTIE_SUBELEM_R0KH_ID;
+		*pos++ = r0kh_id_len;
+		os_memcpy(pos, r0kh_id, r0kh_id_len);
+		pos += r0kh_id_len;
+	}
+
+	if (subelem) {
+		os_memcpy(pos, subelem, subelem_len);
+		pos += subelem_len;
+	}
+
+	*ielen = pos - buf - 2;
+
+	return pos - buf;
+}
+
+
+struct wpa_ft_pmk_r0_sa {
+	struct wpa_ft_pmk_r0_sa *next;
+	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 spa[ETH_ALEN];
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+	int pmk_r1_pushed;
+};
+
+struct wpa_ft_pmk_r1_sa {
+	struct wpa_ft_pmk_r1_sa *next;
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 spa[ETH_ALEN];
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+};
+
+struct wpa_ft_pmk_cache {
+	struct wpa_ft_pmk_r0_sa *pmk_r0;
+	struct wpa_ft_pmk_r1_sa *pmk_r1;
+};
+
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
+{
+	struct wpa_ft_pmk_cache *cache;
+
+	cache = os_zalloc(sizeof(*cache));
+
+	return cache;
+}
+
+
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
+{
+	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
+	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
+
+	r0 = cache->pmk_r0;
+	while (r0) {
+		r0prev = r0;
+		r0 = r0->next;
+		os_memset(r0prev->pmk_r0, 0, PMK_LEN);
+		os_free(r0prev);
+	}
+
+	r1 = cache->pmk_r1;
+	while (r1) {
+		r1prev = r1;
+		r1 = r1->next;
+		os_memset(r1prev->pmk_r1, 0, PMK_LEN);
+		os_free(r1prev);
+	}
+
+	os_free(cache);
+}
+
+
+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r0,
+			       const u8 *pmk_r0_name, int pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0;
+
+	/* TODO: add expiration and limit on number of entries in cache */
+
+	r0 = os_zalloc(sizeof(*r0));
+	if (r0 == NULL)
+		return -1;
+
+	os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+	os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+	os_memcpy(r0->spa, spa, ETH_ALEN);
+	r0->pairwise = pairwise;
+
+	r0->next = cache->pmk_r0;
+	cache->pmk_r0 = r0;
+
+	return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r0_name,
+			       u8 *pmk_r0, int *pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0;
+
+	r0 = cache->pmk_r0;
+	while (r0) {
+		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
+		    os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
+		    == 0) {
+			os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
+			if (pairwise)
+				*pairwise = r0->pairwise;
+			return 0;
+		}
+
+		r0 = r0->next;
+	}
+
+	return -1;
+}
+
+
+static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r1,
+			       const u8 *pmk_r1_name, int pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r1_sa *r1;
+
+	/* TODO: add expiration and limit on number of entries in cache */
+
+	r1 = os_zalloc(sizeof(*r1));
+	if (r1 == NULL)
+		return -1;
+
+	os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+	os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+	os_memcpy(r1->spa, spa, ETH_ALEN);
+	r1->pairwise = pairwise;
+
+	r1->next = cache->pmk_r1;
+	cache->pmk_r1 = r1;
+
+	return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r1_name,
+			       u8 *pmk_r1, int *pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r1_sa *r1;
+
+	r1 = cache->pmk_r1;
+	while (r1) {
+		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
+		    os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
+		    == 0) {
+			os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+			if (pairwise)
+				*pairwise = r1->pairwise;
+			return 0;
+		}
+
+		r1 = r1->next;
+	}
+
+	return -1;
+}
+
+
+static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
+			      const u8 *s1kh_id, const u8 *r0kh_id,
+			      size_t r0kh_id_len, const u8 *pmk_r0_name)
+{
+	struct ft_remote_r0kh *r0kh;
+	struct ft_r0kh_r1kh_pull_frame frame, f;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (r0kh->id_len == r0kh_id_len &&
+		    os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
+		   "address " MACSTR, MAC2STR(r0kh->addr));
+
+	os_memset(&frame, 0, sizeof(frame));
+	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
+	frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
+	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+			   "nonce");
+		return -1;
+	}
+	os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+	os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+
+	if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+		     f.nonce, frame.nonce) < 0)
+		return -1;
+
+	wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
+
+	return 0;
+}
+
+
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+			   struct wpa_ptk *ptk, size_t ptk_len)
+{
+	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN];
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
+	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
+	size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
+	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
+	const u8 *ssid = sm->wpa_auth->conf.ssid;
+	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+
+
+	if (sm->xxkey_len == 0) {
+		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
+			   "derivation");
+		return -1;
+	}
+
+	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+			  r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
+			    sm->pairwise);
+
+	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+			  pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
+			    sm->pairwise);
+
+	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+			  sm->wpa_auth->addr, sm->pmk_r1_name,
+			  (u8 *) ptk, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	return 0;
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+	u8 *subelem;
+	struct wpa_group *gsm = sm->group;
+	size_t subelem_len, pad_len;
+	const u8 *key;
+	size_t key_len;
+	u8 keybuf[32];
+
+	key_len = gsm->GTK_len;
+	if (key_len > sizeof(keybuf))
+		return NULL;
+
+	/*
+	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+	 * than 16 bytes.
+	 */
+	pad_len = key_len % 8;
+	if (pad_len)
+		pad_len = 8 - pad_len;
+	if (key_len + pad_len < 16)
+		pad_len += 8;
+	if (pad_len) {
+		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+		os_memset(keybuf + key_len, 0, pad_len);
+		keybuf[key_len] = 0xdd;
+		key_len += pad_len;
+		key = keybuf;
+	} else
+		key = gsm->GTK[gsm->GN - 1];
+
+	/*
+	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+	 * Key[5..32].
+	 */
+	subelem_len = 13 + key_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	subelem[0] = FTIE_SUBELEM_GTK;
+	subelem[1] = 11 + key_len + 8;
+	/* Key ID in B0-B1 of Key Info */
+	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
+	subelem[4] = gsm->GTK_len;
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
+	if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+	u8 *subelem, *pos;
+	struct wpa_group *gsm = sm->group;
+	size_t subelem_len;
+
+	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
+	 * Key[16+8] */
+	subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	pos = subelem;
+	*pos++ = FTIE_SUBELEM_IGTK;
+	*pos++ = subelem_len - 2;
+	WPA_PUT_LE16(pos, gsm->GN_igtk);
+	pos += 2;
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
+	pos += 6;
+	*pos++ = WPA_IGTK_LEN;
+	if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
+				u8 *pos, u8 *end, u8 id, u8 descr_count,
+				const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems parse;
+	struct rsn_rdie *rdie;
+
+	wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
+		   id, descr_count);
+	wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
+		    ies, ies_len);
+
+	if (end - pos < (int) sizeof(*rdie)) {
+		wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
+		return pos;
+	}
+
+	*pos++ = WLAN_EID_RIC_DATA;
+	*pos++ = sizeof(*rdie);
+	rdie = (struct rsn_rdie *) pos;
+	rdie->id = id;
+	rdie->descr_count = 0;
+	rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+	pos += sizeof(*rdie);
+
+	if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
+	    ParseFailed) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
+		rdie->status_code =
+			host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+		return pos;
+	}
+
+#ifdef NEED_AP_MLME
+	if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+		struct wmm_tspec_element *tspec;
+		int res;
+
+		if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
+			wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
+				   "(%d)", (int) parse.wmm_tspec_len);
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+			return pos;
+		}
+		if (end - pos < (int) sizeof(*tspec)) {
+			wpa_printf(MSG_ERROR, "FT: Not enough room for "
+				   "response TSPEC");
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+			return pos;
+		}
+		tspec = (struct wmm_tspec_element *) pos;
+		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+		res = wmm_process_tspec(tspec);
+		wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
+		if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
+		else if (res == WMM_ADDTS_STATUS_REFUSED)
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
+		else {
+			/* TSPEC accepted; include updated TSPEC in response */
+			rdie->descr_count = 1;
+			pos += sizeof(*tspec);
+		}
+		return pos;
+	}
+#endif /* NEED_AP_MLME */
+
+	if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
+		struct wmm_tspec_element *tspec;
+		int res;
+
+		tspec = (struct wmm_tspec_element *) pos;
+		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+		res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
+				       sizeof(*tspec));
+		if (res >= 0) {
+			if (res)
+				rdie->status_code = host_to_le16(res);
+			else {
+				/* TSPEC accepted; include updated TSPEC in
+				 * response */
+		                rdie->descr_count = 1;
+	                        pos += sizeof(*tspec);
+			}
+			return pos;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
+	rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+	return pos;
+}
+
+
+static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
+			       const u8 *ric, size_t ric_len)
+{
+	const u8 *rpos, *start;
+	const struct rsn_rdie *rdie;
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
+
+	rpos = ric;
+	while (rpos + sizeof(*rdie) < ric + ric_len) {
+		if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
+		    rpos + 2 + rpos[1] > ric + ric_len)
+			break;
+		rdie = (const struct rsn_rdie *) (rpos + 2);
+		rpos += 2 + rpos[1];
+		start = rpos;
+
+		while (rpos + 2 <= ric + ric_len &&
+		       rpos + 2 + rpos[1] <= ric + ric_len) {
+			if (rpos[0] == WLAN_EID_RIC_DATA)
+				break;
+			rpos += 2 + rpos[1];
+		}
+		pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
+					  rdie->descr_count,
+					  start, rpos - start);
+	}
+
+	return pos;
+}
+
+
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+				 size_t max_len, int auth_alg,
+				 const u8 *req_ies, size_t req_ies_len)
+{
+	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
+	size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+	int res;
+	struct wpa_auth_config *conf;
+	struct rsn_ftie *_ftie;
+	struct wpa_ft_ies parse;
+	u8 *ric_start;
+	u8 *anonce, *snonce;
+
+	if (sm == NULL)
+		return pos;
+
+	conf = &sm->wpa_auth->conf;
+
+	if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	    sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+		return pos;
+
+	end = pos + max_len;
+
+	if (auth_alg == WLAN_AUTH_FT) {
+		/*
+		 * RSN (only present if this is a Reassociation Response and
+		 * part of a fast BSS transition)
+		 */
+		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
+		if (res < 0)
+			return pos;
+		rsnie = pos;
+		rsnie_len = res;
+		pos += res;
+	}
+
+	/* Mobility Domain Information */
+	res = wpa_write_mdie(conf, pos, end - pos);
+	if (res < 0)
+		return pos;
+	mdie = pos;
+	mdie_len = res;
+	pos += res;
+
+	/* Fast BSS Transition Information */
+	if (auth_alg == WLAN_AUTH_FT) {
+		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+		r0kh_id = sm->r0kh_id;
+		r0kh_id_len = sm->r0kh_id_len;
+		anonce = sm->ANonce;
+		snonce = sm->SNonce;
+#ifdef CONFIG_IEEE80211W
+		if (sm->mgmt_frame_prot) {
+			u8 *igtk;
+			size_t igtk_len;
+			u8 *nbuf;
+			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
+			if (igtk == NULL) {
+				os_free(subelem);
+				return pos;
+			}
+			nbuf = os_realloc(subelem, subelem_len + igtk_len);
+			if (nbuf == NULL) {
+				os_free(subelem);
+				os_free(igtk);
+				return pos;
+			}
+			subelem = nbuf;
+			os_memcpy(subelem + subelem_len, igtk, igtk_len);
+			subelem_len += igtk_len;
+			os_free(igtk);
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else {
+		r0kh_id = conf->r0_key_holder;
+		r0kh_id_len = conf->r0_key_holder_len;
+		anonce = NULL;
+		snonce = NULL;
+	}
+	res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
+			     end - pos, subelem, subelem_len);
+	os_free(subelem);
+	if (res < 0)
+		return pos;
+	ftie = pos;
+	ftie_len = res;
+	pos += res;
+
+	os_free(sm->assoc_resp_ftie);
+	sm->assoc_resp_ftie = os_malloc(ftie_len);
+	if (sm->assoc_resp_ftie)
+		os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+
+	_ftie = (struct rsn_ftie *) (ftie + 2);
+	if (auth_alg == WLAN_AUTH_FT)
+		_ftie->mic_control[1] = 3; /* Information element count */
+
+	ric_start = pos;
+	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+		pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
+					 parse.ric_len);
+		if (auth_alg == WLAN_AUTH_FT)
+			_ftie->mic_control[1] +=
+				ieee802_11_ie_count(ric_start,
+						    pos - ric_start);
+	}
+	if (ric_start == pos)
+		ric_start = NULL;
+
+	if (auth_alg == WLAN_AUTH_FT &&
+	    wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+		       mdie, mdie_len, ftie, ftie_len,
+		       rsnie, rsnie_len,
+		       ric_start, ric_start ? pos - ric_start : 0,
+		       _ftie->mic) < 0)
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+
+	return pos;
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+				   int vlan_id,
+				   enum wpa_alg alg, const u8 *addr, int idx,
+				   u8 *key, size_t key_len)
+{
+	if (wpa_auth->cb.set_key == NULL)
+		return -1;
+	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+				    key, key_len);
+}
+
+
+void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+{
+	enum wpa_alg alg;
+	int klen;
+
+	/* MLME-SETKEYS.request(PTK) */
+	alg = wpa_cipher_to_alg(sm->pairwise);
+	klen = wpa_cipher_key_len(sm->pairwise);
+	if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
+			   "PTK configuration", sm->pairwise);
+		return;
+	}
+
+	/* FIX: add STA entry to kernel/driver here? The set_key will fail
+	 * most likely without this.. At the moment, STA entry is added only
+	 * after association has been completed. This function will be called
+	 * again after association to get the PTK configured, but that could be
+	 * optimized by adding the STA entry earlier.
+	 */
+	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+			     sm->PTK.tk1, klen))
+		return;
+
+	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+	sm->pairwise_set = TRUE;
+}
+
+
+static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
+				   const u8 *ies, size_t ies_len,
+				   u8 **resp_ies, size_t *resp_ies_len)
+{
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	struct wpa_auth_config *conf;
+	struct wpa_ft_ies parse;
+	size_t buflen, ptk_len;
+	int ret;
+	u8 *pos, *end;
+	int pairwise;
+
+	*resp_ies = NULL;
+	*resp_ies_len = 0;
+
+	sm->pmk_r1_name_valid = 0;
+	conf = &sm->wpa_auth->conf;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
+		    ies, ies_len);
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain,
+		      sm->wpa_auth->conf.mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return WLAN_STATUS_INVALID_MDIE;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
+		    parse.r0kh_id, parse.r0kh_id_len);
+	os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
+	sm->r0kh_id_len = parse.r0kh_id_len;
+
+	if (parse.rsn_pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
+		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+			       sm->wpa_auth->conf.r1_key_holder, sm->addr,
+			       pmk_r1_name);
+	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
+		    pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
+		    &pairwise) < 0) {
+		if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
+				       sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
+			wpa_printf(MSG_DEBUG, "FT: Did not have matching "
+				   "PMK-R1 and unknown R0KH-ID");
+			return WLAN_STATUS_INVALID_PMKID;
+		}
+
+		/*
+		 * TODO: Should return "status pending" (and the caller should
+		 * not send out response now). The real response will be sent
+		 * once the response from R0KH is received.
+		 */
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+	sm->pmk_r1_name_valid = 1;
+	os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+			   "ANonce");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+		    sm->SNonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
+		    sm->ANonce, WPA_NONCE_LEN);
+
+	ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
+	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+			  sm->wpa_auth->addr, pmk_r1_name,
+			  (u8 *) &sm->PTK, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
+			(u8 *) &sm->PTK, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	sm->pairwise = pairwise;
+	wpa_ft_install_ptk(sm);
+
+	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+		2 + FT_R1KH_ID_LEN + 200;
+	*resp_ies = os_zalloc(buflen);
+	if (*resp_ies == NULL) {
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	pos = *resp_ies;
+	end = *resp_ies + buflen;
+
+	ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	ret = wpa_write_mdie(conf, pos, end - pos);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	*resp_ies_len = pos - *resp_ies;
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+			 u16 auth_transaction, const u8 *ies, size_t ies_len,
+			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+				    u16 auth_transaction, u16 status,
+				    const u8 *ies, size_t ies_len),
+			 void *ctx)
+{
+	u16 status;
+	u8 *resp_ies;
+	size_t resp_ies_len;
+
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
+			   "WPA SM not available");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
+		   " BSSID=" MACSTR " transaction=%d",
+		   MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
+	status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
+					 &resp_ies_len);
+
+	wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
+		   " auth_transaction=%d status=%d",
+		   MAC2STR(sm->addr), auth_transaction + 1, status);
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+	cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
+	   resp_ies, resp_ies_len);
+	os_free(resp_ies);
+}
+
+
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+			    size_t ies_len)
+{
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 mic[16];
+	unsigned int count;
+
+	if (sm == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (parse.rsn == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (parse.rsn_pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
+			   "with the PMKR1Name derived from auth request");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain,
+		      sm->wpa_auth->conf.mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return WLAN_STATUS_INVALID_MDIE;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->SNonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
+			    ftie->anonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
+			    sm->ANonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+		      FT_R1KH_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
+			   "ReassocReq");
+		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
+			    parse.r1kh_id, FT_R1KH_ID_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
+			    sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
+			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
+		return -1;
+	}
+
+	count = 3;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+	if (ftie->mic_control[1] != count) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
+			   "Control: received %u expected %u",
+			   ftie->mic_control[1], count);
+		return -1;
+	}
+
+	if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+		       parse.mdie - 2, parse.mdie_len + 2,
+		       parse.ftie - 2, parse.ftie_len + 2,
+		       parse.rsn - 2, parse.rsn_len + 2,
+		       parse.ric, parse.ric_len,
+		       mic) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (os_memcmp(mic, ftie->mic, 16) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+		wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
+			   MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
+		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
+			    parse.mdie - 2, parse.mdie_len + 2);
+		wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
+			    parse.ftie - 2, parse.ftie_len + 2);
+		wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
+			    parse.rsn - 2, parse.rsn_len + 2);
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
+{
+	const u8 *sta_addr, *target_ap;
+	const u8 *ies;
+	size_t ies_len;
+	u8 action;
+	struct ft_rrb_frame *frame;
+
+	if (sm == NULL)
+		return -1;
+
+	/*
+	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+	 * FT Request action frame body[variable]
+	 */
+
+	if (len < 14) {
+		wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
+			   "(len=%lu)", (unsigned long) len);
+		return -1;
+	}
+
+	action = data[1];
+	sta_addr = data + 2;
+	target_ap = data + 8;
+	ies = data + 14;
+	ies_len = len - 14;
+
+	wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
+		   " Target AP=" MACSTR " Action=%d)",
+		   MAC2STR(sta_addr), MAC2STR(target_ap), action);
+
+	if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
+			   "STA=" MACSTR " STA-Address=" MACSTR,
+			   MAC2STR(sm->addr), MAC2STR(sta_addr));
+		return -1;
+	}
+
+	/*
+	 * Do some sanity checking on the target AP address (not own and not
+	 * broadcast. This could be extended to filter based on a list of known
+	 * APs in the MD (if such a list were configured).
+	 */
+	if ((target_ap[0] & 0x01) ||
+	    os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
+			   "frame");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
+
+	/* RRB - Forward action frame to the target AP */
+	frame = os_malloc(sizeof(*frame) + len);
+	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame->packet_type = FT_PACKET_REQUEST;
+	frame->action_length = host_to_le16(len);
+	os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
+	os_memcpy(frame + 1, data, len);
+
+	wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
+			sizeof(*frame) + len);
+	os_free(frame);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
+				 const u8 *current_ap, const u8 *sta_addr,
+				 const u8 *body, size_t len)
+{
+	struct wpa_state_machine *sm;
+	u16 status;
+	u8 *resp_ies, *pos;
+	size_t resp_ies_len, rlen;
+	struct ft_rrb_frame *frame;
+
+	sm = wpa_ft_add_sta(wpa_auth, sta_addr);
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
+			   "RRB Request");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
+
+	status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
+					 &resp_ies_len);
+
+	wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
+		   " CurrentAP=" MACSTR " status=%d",
+		   MAC2STR(sm->addr), MAC2STR(current_ap), status);
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+
+	/* RRB - Forward action frame response to the Current AP */
+
+	/*
+	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+	 * Status_Code[2] FT Request action frame body[variable]
+	 */
+	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
+
+	frame = os_malloc(sizeof(*frame) + rlen);
+	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame->packet_type = FT_PACKET_RESPONSE;
+	frame->action_length = host_to_le16(rlen);
+	os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
+	pos = (u8 *) (frame + 1);
+	*pos++ = WLAN_ACTION_FT;
+	*pos++ = 2; /* Action: Response */
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	WPA_PUT_LE16(pos, status);
+	pos += 2;
+	if (resp_ies) {
+		os_memcpy(pos, resp_ies, resp_ies_len);
+		os_free(resp_ies);
+	}
+
+	wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
+			sizeof(*frame) + rlen);
+	os_free(frame);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_pull_frame *frame, f;
+	struct ft_remote_r1kh *r1kh;
+	struct ft_r0kh_r1kh_resp_frame resp, r;
+	u8 pmk_r0[PMK_LEN];
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r1kh = wpa_auth->conf.r1kh_list;
+	while (r1kh) {
+		if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r1kh = r1kh->next;
+	}
+	if (r1kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
+			   "PMK-R1 pull source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+		       frame->nonce, f.nonce) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+			   "request from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+		    f.nonce, sizeof(f.nonce));
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
+		    f.pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+		   MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
+	resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
+	os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
+	os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
+	os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
+	if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
+				&pairwise) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
+			   "PMK-R1 pull");
+		return -1;
+	}
+
+	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+			  r.pmk_r1, r.pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	r.pairwise = host_to_le16(pairwise);
+
+	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+		     r.nonce, resp.nonce) < 0) {
+		os_memset(pmk_r0, 0, PMK_LEN);
+		return -1;
+	}
+
+	os_memset(pmk_r0, 0, PMK_LEN);
+
+	wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_resp_frame *frame, f;
+	struct ft_remote_r0kh *r0kh;
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+			   "PMK-R0 pull response source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+		       frame->nonce, f.nonce) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+			   "response from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+	    != 0) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
+			   "matching R1KH-ID");
+		return -1;
+	}
+
+	/* TODO: verify that <nonce,s1kh_id> matches with a pending request
+	 * and call this requests callback function to finish request
+	 * processing */
+
+	pairwise = le_to_host16(f.pairwise);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+		    f.nonce, sizeof(f.nonce));
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+		   MACSTR " pairwise=0x%x",
+		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
+			f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
+			f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
+			    pairwise);
+	os_memset(f.pmk_r1, 0, PMK_LEN);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_push_frame *frame, f;
+	struct ft_remote_r0kh *r0kh;
+	struct os_time now;
+	os_time_t tsend;
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+			   "PMK-R0 push source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_push_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+		       frame->timestamp, f.timestamp) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
+			   MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	os_get_time(&now);
+	tsend = WPA_GET_LE32(f.timestamp);
+	if ((now.sec > tsend && now.sec - tsend > 60) ||
+	    (now.sec < tsend && tsend - now.sec > 60)) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
+			   "timestamp: sender time %d own time %d\n",
+			   (int) tsend, (int) now.sec);
+		return -1;
+	}
+
+	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+	    != 0) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
+			   "R1KH-ID (received " MACSTR " own " MACSTR ")",
+			   MAC2STR(f.r1kh_id),
+			   MAC2STR(wpa_auth->conf.r1_key_holder));
+		return -1;
+	}
+
+	pairwise = le_to_host16(f.pairwise);
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
+		   MACSTR " pairwise=0x%x",
+		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
+			f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
+			f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
+			    pairwise);
+	os_memset(f.pmk_r1, 0, PMK_LEN);
+
+	return 0;
+}
+
+
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+		  const u8 *data, size_t data_len)
+{
+	struct ft_rrb_frame *frame;
+	u16 alen;
+	const u8 *pos, *end, *start;
+	u8 action;
+	const u8 *sta_addr, *target_ap_addr;
+
+	wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
+		   MAC2STR(src_addr));
+
+	if (data_len < sizeof(*frame)) {
+		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
+			   (unsigned long) data_len);
+		return -1;
+	}
+
+	pos = data;
+	frame = (struct ft_rrb_frame *) pos;
+	pos += sizeof(*frame);
+
+	alen = le_to_host16(frame->action_length);
+	wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
+		   "action_length=%d ap_address=" MACSTR,
+		   frame->frame_type, frame->packet_type, alen,
+		   MAC2STR(frame->ap_address));
+
+	if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
+		/* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
+		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
+			   "unrecognized type %d", frame->frame_type);
+		return -1;
+	}
+
+	if (alen > data_len - sizeof(*frame)) {
+		wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
+			   "frame");
+		return -1;
+	}
+
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
+		return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
+		return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
+		return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
+
+	if (alen < 1 + 1 + 2 * ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
+			   "room for Action Frame body); alen=%lu",
+			   (unsigned long) alen);
+		return -1;
+	}
+	start = pos;
+	end = pos + alen;
+
+	if (*pos != WLAN_ACTION_FT) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
+			   "%d", *pos);
+		return -1;
+	}
+
+	pos++;
+	action = *pos++;
+	sta_addr = pos;
+	pos += ETH_ALEN;
+	target_ap_addr = pos;
+	pos += ETH_ALEN;
+	wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
+		   MACSTR " target_ap_addr=" MACSTR,
+		   action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
+
+	if (frame->packet_type == FT_PACKET_REQUEST) {
+		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
+
+		if (action != 1) {
+			wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
+				   "RRB Request", action);
+			return -1;
+		}
+
+		if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
+				   "RRB Request does not match with own "
+				   "address");
+			return -1;
+		}
+
+		if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
+					  sta_addr, pos, end - pos) < 0)
+			return -1;
+	} else if (frame->packet_type == FT_PACKET_RESPONSE) {
+		u16 status_code;
+
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
+				   "code in RRB Response");
+			return -1;
+		}
+		status_code = WPA_GET_LE16(pos);
+		pos += 2;
+
+		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
+			   "(status_code=%d)", status_code);
+
+		if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
+			return -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
+			   "packet_type %d", frame->packet_type);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+				   struct wpa_ft_pmk_r0_sa *pmk_r0,
+				   struct ft_remote_r1kh *r1kh,
+				   const u8 *s1kh_id, int pairwise)
+{
+	struct ft_r0kh_r1kh_push_frame frame, f;
+	struct os_time now;
+
+	os_memset(&frame, 0, sizeof(frame));
+	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
+	frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
+	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
+	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+	os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+			  s1kh_id, f.pmk_r1, f.pmk_r1_name);
+	wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	os_get_time(&now);
+	WPA_PUT_LE32(f.timestamp, now.sec);
+	f.pairwise = host_to_le16(pairwise);
+	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+		     f.timestamp, frame.timestamp) < 0)
+		return;
+
+	wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+}
+
+
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	struct wpa_ft_pmk_r0_sa *r0;
+	struct ft_remote_r1kh *r1kh;
+
+	if (!wpa_auth->conf.pmk_r1_push)
+		return;
+
+	r0 = wpa_auth->ft_pmk_cache->pmk_r0;
+	while (r0) {
+		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+			break;
+		r0 = r0->next;
+	}
+
+	if (r0 == NULL || r0->pmk_r1_pushed)
+		return;
+	r0->pmk_r1_pushed = 1;
+
+	wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
+		   "for STA " MACSTR, MAC2STR(addr));
+
+	r1kh = wpa_auth->conf.r1kh_list;
+	while (r1kh) {
+		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
+		r1kh = r1kh->next;
+	}
+}
+
+#endif /* CONFIG_IEEE80211R */

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_glue.c
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_glue.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_glue.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,545 +0,0 @@
-/*
- * hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "eap_server/eap.h"
-#include "l2_packet/l2_packet.h"
-#include "drivers/driver.h"
-#include "hostapd.h"
-#include "ieee802_1x.h"
-#include "preauth_auth.h"
-#include "sta_info.h"
-#include "tkip_countermeasures.h"
-#include "ap_drv_ops.h"
-#include "ap_config.h"
-#include "wpa_auth.h"
-
-
-#ifdef CONFIG_IEEE80211R
-static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len);
-#endif /* CONFIG_IEEE80211R */
-
-
-static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
-				  struct wpa_auth_config *wconf)
-{
-	wconf->wpa = conf->wpa;
-	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
-	wconf->wpa_pairwise = conf->wpa_pairwise;
-	wconf->wpa_group = conf->wpa_group;
-	wconf->wpa_group_rekey = conf->wpa_group_rekey;
-	wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
-	wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
-	wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
-	wconf->rsn_pairwise = conf->rsn_pairwise;
-	wconf->rsn_preauth = conf->rsn_preauth;
-	wconf->eapol_version = conf->eapol_version;
-	wconf->peerkey = conf->peerkey;
-	wconf->wmm_enabled = conf->wmm_enabled;
-	wconf->wmm_uapsd = conf->wmm_uapsd;
-	wconf->okc = conf->okc;
-#ifdef CONFIG_IEEE80211W
-	wconf->ieee80211w = conf->ieee80211w;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
-	wconf->ssid_len = conf->ssid.ssid_len;
-	if (wconf->ssid_len > SSID_LEN)
-		wconf->ssid_len = SSID_LEN;
-	os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
-	os_memcpy(wconf->mobility_domain, conf->mobility_domain,
-		  MOBILITY_DOMAIN_ID_LEN);
-	if (conf->nas_identifier &&
-	    os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
-		wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
-		os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
-			  wconf->r0_key_holder_len);
-	}
-	os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
-	wconf->r0_key_lifetime = conf->r0_key_lifetime;
-	wconf->reassociation_deadline = conf->reassociation_deadline;
-	wconf->r0kh_list = conf->r0kh_list;
-	wconf->r1kh_list = conf->r1kh_list;
-	wconf->pmk_r1_push = conf->pmk_r1_push;
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
-				    logger_level level, const char *txt)
-{
-#ifndef CONFIG_NO_HOSTAPD_LOGGER
-	struct hostapd_data *hapd = ctx;
-	int hlevel;
-
-	switch (level) {
-	case LOGGER_WARNING:
-		hlevel = HOSTAPD_LEVEL_WARNING;
-		break;
-	case LOGGER_INFO:
-		hlevel = HOSTAPD_LEVEL_INFO;
-		break;
-	case LOGGER_DEBUG:
-	default:
-		hlevel = HOSTAPD_LEVEL_DEBUG;
-		break;
-	}
-
-	hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */
-}
-
-
-static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
-					u16 reason)
-{
-	struct hostapd_data *hapd = ctx;
-	wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
-		   "STA " MACSTR " reason %d",
-		   __func__, MAC2STR(addr), reason);
-	ap_sta_disconnect(hapd, NULL, addr, reason);
-}
-
-
-static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
-{
-	struct hostapd_data *hapd = ctx;
-	michael_mic_failure(hapd, addr, 0);
-}
-
-
-static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
-				       wpa_eapol_variable var, int value)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = ap_get_sta(hapd, addr);
-	if (sta == NULL)
-		return;
-	switch (var) {
-	case WPA_EAPOL_portEnabled:
-		ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
-		break;
-	case WPA_EAPOL_portValid:
-		ieee802_1x_notify_port_valid(sta->eapol_sm, value);
-		break;
-	case WPA_EAPOL_authorized:
-		ieee802_1x_set_sta_authorized(hapd, sta, value);
-		break;
-	case WPA_EAPOL_portControl_Auto:
-		if (sta->eapol_sm)
-			sta->eapol_sm->portControl = Auto;
-		break;
-	case WPA_EAPOL_keyRun:
-		if (sta->eapol_sm)
-			sta->eapol_sm->keyRun = value ? TRUE : FALSE;
-		break;
-	case WPA_EAPOL_keyAvailable:
-		if (sta->eapol_sm)
-			sta->eapol_sm->eap_if->eapKeyAvailable =
-				value ? TRUE : FALSE;
-		break;
-	case WPA_EAPOL_keyDone:
-		if (sta->eapol_sm)
-			sta->eapol_sm->keyDone = value ? TRUE : FALSE;
-		break;
-	case WPA_EAPOL_inc_EapolFramesTx:
-		if (sta->eapol_sm)
-			sta->eapol_sm->dot1xAuthEapolFramesTx++;
-		break;
-	}
-}
-
-
-static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
-				      wpa_eapol_variable var)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta = ap_get_sta(hapd, addr);
-	if (sta == NULL || sta->eapol_sm == NULL)
-		return -1;
-	switch (var) {
-	case WPA_EAPOL_keyRun:
-		return sta->eapol_sm->keyRun;
-	case WPA_EAPOL_keyAvailable:
-		return sta->eapol_sm->eap_if->eapKeyAvailable;
-	default:
-		return -1;
-	}
-}
-
-
-static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
-					   const u8 *prev_psk)
-{
-	struct hostapd_data *hapd = ctx;
-	return hostapd_get_psk(hapd->conf, addr, prev_psk);
-}
-
-
-static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
-				    size_t *len)
-{
-	struct hostapd_data *hapd = ctx;
-	const u8 *key;
-	size_t keylen;
-	struct sta_info *sta;
-
-	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL)
-		return -1;
-
-	key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
-	if (key == NULL)
-		return -1;
-
-	if (keylen > *len)
-		keylen = *len;
-	os_memcpy(msk, key, keylen);
-	*len = keylen;
-
-	return 0;
-}
-
-
-static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-				    const u8 *addr, int idx, u8 *key,
-				    size_t key_len)
-{
-	struct hostapd_data *hapd = ctx;
-	const char *ifname = hapd->conf->iface;
-
-	if (vlan_id > 0) {
-		ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
-		if (ifname == NULL)
-			return -1;
-	}
-
-	return hapd->drv.set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
-				 key, key_len);
-}
-
-
-static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
-				       u8 *seq)
-{
-	struct hostapd_data *hapd = ctx;
-	return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
-}
-
-
-static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
-				       const u8 *data, size_t data_len,
-				       int encrypt)
-{
-	struct hostapd_data *hapd = ctx;
-	return hapd->drv.send_eapol(hapd, addr, data, data_len, encrypt);
-}
-
-
-static int hostapd_wpa_auth_for_each_sta(
-	void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
-	void *cb_ctx)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta;
-
-	for (sta = hapd->sta_list; sta; sta = sta->next) {
-		if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
-			return 1;
-	}
-	return 0;
-}
-
-
-struct wpa_auth_iface_iter_data {
-	int (*cb)(struct wpa_authenticator *sm, void *ctx);
-	void *cb_ctx;
-};
-
-static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx)
-{
-	struct wpa_auth_iface_iter_data *data = ctx;
-	size_t i;
-	for (i = 0; i < iface->num_bss; i++) {
-		if (iface->bss[i]->wpa_auth &&
-		    data->cb(iface->bss[i]->wpa_auth, data->cb_ctx))
-			return 1;
-	}
-	return 0;
-}
-
-
-static int hostapd_wpa_auth_for_each_auth(
-	void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
-	void *cb_ctx)
-{
-	struct hostapd_data *hapd = ctx;
-	struct wpa_auth_iface_iter_data data;
-	if (hapd->iface->for_each_interface == NULL)
-		return -1;
-	data.cb = cb;
-	data.cb_ctx = cb_ctx;
-	return hapd->iface->for_each_interface(hapd->iface->interfaces,
-					       wpa_auth_iface_iter, &data);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-struct wpa_auth_ft_iface_iter_data {
-	struct hostapd_data *src_hapd;
-	const u8 *dst;
-	const u8 *data;
-	size_t data_len;
-};
-
-
-static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
-{
-	struct wpa_auth_ft_iface_iter_data *idata = ctx;
-	struct hostapd_data *hapd;
-	size_t j;
-
-	for (j = 0; j < iface->num_bss; j++) {
-		hapd = iface->bss[j];
-		if (hapd == idata->src_hapd)
-			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 -> "
-				   MACSTR "@%s",
-				   MAC2STR(idata->src_hapd->own_addr),
-				   idata->src_hapd->conf->iface,
-				   MAC2STR(hapd->own_addr), hapd->conf->iface);
-			hostapd_rrb_receive(hapd, idata->src_hapd->own_addr,
-					    idata->data, idata->data_len);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
-				       const u8 *data, size_t data_len)
-{
-	struct hostapd_data *hapd = ctx;
-
-#ifdef CONFIG_IEEE80211R
-	if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
-		int res;
-		struct wpa_auth_ft_iface_iter_data idata;
-		idata.src_hapd = hapd;
-		idata.dst = dst;
-		idata.data = data;
-		idata.data_len = data_len;
-		res = hapd->iface->for_each_interface(hapd->iface->interfaces,
-						      hostapd_wpa_auth_ft_iter,
-						      &idata);
-		if (res == 1)
-			return data_len;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (hapd->driver && hapd->driver->send_ether)
-		return hapd->driver->send_ether(hapd->drv_priv, dst,
-						hapd->own_addr, proto,
-						data, data_len);
-	if (hapd->l2 == NULL)
-		return -1;
-	return l2_packet_send(hapd->l2, dst, proto, data, data_len);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
-					   const u8 *data, size_t data_len)
-{
-	struct hostapd_data *hapd = ctx;
-	int res;
-	struct ieee80211_mgmt *m;
-	size_t mlen;
-	struct sta_info *sta;
-
-	sta = ap_get_sta(hapd, dst);
-	if (sta == NULL || sta->wpa_sm == NULL)
-		return -1;
-
-	m = os_zalloc(sizeof(*m) + data_len);
-	if (m == NULL)
-		return -1;
-	mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
-	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					WLAN_FC_STYPE_ACTION);
-	os_memcpy(m->da, dst, ETH_ALEN);
-	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
-	os_memcpy(&m->u, data, data_len);
-
-	res = hapd->drv.send_mgmt_frame(hapd, (u8 *) m, mlen);
-	os_free(m);
-	return res;
-}
-
-
-static struct wpa_state_machine *
-hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
-{
-	struct hostapd_data *hapd = ctx;
-	struct sta_info *sta;
-
-	sta = ap_sta_add(hapd, sta_addr);
-	if (sta == NULL)
-		return NULL;
-	if (sta->wpa_sm) {
-		sta->auth_alg = WLAN_AUTH_FT;
-		return sta->wpa_sm;
-	}
-
-	sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
-	if (sta->wpa_sm == NULL) {
-		ap_free_sta(hapd, sta);
-		return NULL;
-	}
-	sta->auth_alg = WLAN_AUTH_FT;
-
-	return sta->wpa_sm;
-}
-
-
-static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len)
-{
-	struct hostapd_data *hapd = ctx;
-	wpa_ft_rrb_rx(hapd->wpa_auth, src_addr, buf, len);
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-int hostapd_setup_wpa(struct hostapd_data *hapd)
-{
-	struct wpa_auth_config _conf;
-	struct wpa_auth_callbacks cb;
-	const u8 *wpa_ie;
-	size_t wpa_ie_len;
-
-	hostapd_wpa_auth_conf(hapd->conf, &_conf);
-	os_memset(&cb, 0, sizeof(cb));
-	cb.ctx = hapd;
-	cb.logger = hostapd_wpa_auth_logger;
-	cb.disconnect = hostapd_wpa_auth_disconnect;
-	cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
-	cb.set_eapol = hostapd_wpa_auth_set_eapol;
-	cb.get_eapol = hostapd_wpa_auth_get_eapol;
-	cb.get_psk = hostapd_wpa_auth_get_psk;
-	cb.get_msk = hostapd_wpa_auth_get_msk;
-	cb.set_key = hostapd_wpa_auth_set_key;
-	cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
-	cb.send_eapol = hostapd_wpa_auth_send_eapol;
-	cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
-	cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
-	cb.send_ether = hostapd_wpa_auth_send_ether;
-#ifdef CONFIG_IEEE80211R
-	cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
-	cb.add_sta = hostapd_wpa_auth_add_sta;
-#endif /* CONFIG_IEEE80211R */
-	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
-	if (hapd->wpa_auth == NULL) {
-		wpa_printf(MSG_ERROR, "WPA initialization failed.");
-		return -1;
-	}
-
-	if (hostapd_set_privacy(hapd, 1)) {
-		wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
-			   "for interface %s", hapd->conf->iface);
-		return -1;
-	}
-
-	wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
-	if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
-		wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
-			   "the kernel driver.");
-		return -1;
-	}
-
-	if (rsn_preauth_iface_init(hapd)) {
-		wpa_printf(MSG_ERROR, "Initialization of RSN "
-			   "pre-authentication failed.");
-		return -1;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (!hostapd_drv_none(hapd)) {
-		hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
-					  hapd->conf->bridge :
-					  hapd->conf->iface, NULL, ETH_P_RRB,
-					  hostapd_rrb_receive, hapd, 0);
-		if (hapd->l2 == NULL &&
-		    (hapd->driver == NULL ||
-		     hapd->driver->send_ether == NULL)) {
-			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
-				   "interface");
-			return -1;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	return 0;
-
-}
-
-
-void hostapd_reconfig_wpa(struct hostapd_data *hapd)
-{
-	struct wpa_auth_config wpa_auth_conf;
-	hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
-	wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
-}
-
-
-void hostapd_deinit_wpa(struct hostapd_data *hapd)
-{
-	rsn_preauth_iface_deinit(hapd);
-	if (hapd->wpa_auth) {
-		wpa_deinit(hapd->wpa_auth);
-		hapd->wpa_auth = NULL;
-
-		if (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)) {
-			wpa_printf(MSG_DEBUG, "Could not remove generic "
-				   "information element from interface %s",
-				   hapd->conf->iface);
-		}
-	}
-	ieee802_1x_deinit(hapd);
-
-#ifdef CONFIG_IEEE80211R
-	l2_packet_deinit(hapd->l2);
-#endif /* CONFIG_IEEE80211R */
-}

Copied: vendor/wpa/2.0/src/ap/wpa_auth_glue.c (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_glue.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_glue.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_glue.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,605 @@
+/*
+ * hostapd / WPA authenticator glue code
+ * Copyright (c) 2002-2011, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "eap_server/eap.h"
+#include "l2_packet/l2_packet.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "preauth_auth.h"
+#include "sta_info.h"
+#include "tkip_countermeasures.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "wpa_auth.h"
+#include "wpa_auth_glue.h"
+
+
+static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+				  struct wpa_auth_config *wconf)
+{
+	os_memset(wconf, 0, sizeof(*wconf));
+	wconf->wpa = conf->wpa;
+	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
+	wconf->wpa_pairwise = conf->wpa_pairwise;
+	wconf->wpa_group = conf->wpa_group;
+	wconf->wpa_group_rekey = conf->wpa_group_rekey;
+	wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
+	wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
+	wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+	wconf->rsn_pairwise = conf->rsn_pairwise;
+	wconf->rsn_preauth = conf->rsn_preauth;
+	wconf->eapol_version = conf->eapol_version;
+	wconf->peerkey = conf->peerkey;
+	wconf->wmm_enabled = conf->wmm_enabled;
+	wconf->wmm_uapsd = conf->wmm_uapsd;
+	wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
+	wconf->okc = conf->okc;
+#ifdef CONFIG_IEEE80211W
+	wconf->ieee80211w = conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+	wconf->ssid_len = conf->ssid.ssid_len;
+	if (wconf->ssid_len > SSID_LEN)
+		wconf->ssid_len = SSID_LEN;
+	os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
+	os_memcpy(wconf->mobility_domain, conf->mobility_domain,
+		  MOBILITY_DOMAIN_ID_LEN);
+	if (conf->nas_identifier &&
+	    os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
+		wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
+		os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
+			  wconf->r0_key_holder_len);
+	}
+	os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
+	wconf->r0_key_lifetime = conf->r0_key_lifetime;
+	wconf->reassociation_deadline = conf->reassociation_deadline;
+	wconf->r0kh_list = conf->r0kh_list;
+	wconf->r1kh_list = conf->r1kh_list;
+	wconf->pmk_r1_push = conf->pmk_r1_push;
+	wconf->ft_over_ds = conf->ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_HS20
+	wconf->disable_gtk = conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
+}
+
+
+static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
+				    logger_level level, const char *txt)
+{
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+	struct hostapd_data *hapd = ctx;
+	int hlevel;
+
+	switch (level) {
+	case LOGGER_WARNING:
+		hlevel = HOSTAPD_LEVEL_WARNING;
+		break;
+	case LOGGER_INFO:
+		hlevel = HOSTAPD_LEVEL_INFO;
+		break;
+	case LOGGER_DEBUG:
+	default:
+		hlevel = HOSTAPD_LEVEL_DEBUG;
+		break;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+}
+
+
+static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
+					u16 reason)
+{
+	struct hostapd_data *hapd = ctx;
+	wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
+		   "STA " MACSTR " reason %d",
+		   __func__, MAC2STR(addr), reason);
+	ap_sta_disconnect(hapd, NULL, addr, reason);
+}
+
+
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	return michael_mic_failure(hapd, addr, 0);
+}
+
+
+static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
+				       wpa_eapol_variable var, int value)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return;
+	switch (var) {
+	case WPA_EAPOL_portEnabled:
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_portValid:
+		ieee802_1x_notify_port_valid(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_authorized:
+		ieee802_1x_set_sta_authorized(hapd, sta, value);
+		break;
+	case WPA_EAPOL_portControl_Auto:
+		if (sta->eapol_sm)
+			sta->eapol_sm->portControl = Auto;
+		break;
+	case WPA_EAPOL_keyRun:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyAvailable:
+		if (sta->eapol_sm)
+			sta->eapol_sm->eap_if->eapKeyAvailable =
+				value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyDone:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_inc_EapolFramesTx:
+		if (sta->eapol_sm)
+			sta->eapol_sm->dot1xAuthEapolFramesTx++;
+		break;
+	}
+}
+
+
+static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
+				      wpa_eapol_variable var)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL || sta->eapol_sm == NULL)
+		return -1;
+	switch (var) {
+	case WPA_EAPOL_keyRun:
+		return sta->eapol_sm->keyRun;
+	case WPA_EAPOL_keyAvailable:
+		return sta->eapol_sm->eap_if->eapKeyAvailable;
+	default:
+		return -1;
+	}
+}
+
+
+static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
+					   const u8 *prev_psk)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+	/*
+	 * This is about to iterate over all psks, prev_psk gives the last
+	 * returned psk which should not be returned again.
+	 * logic list (all hostapd_get_psk; all sta->psk)
+	 */
+	if (sta && sta->psk && !psk) {
+		struct hostapd_sta_wpa_psk_short *pos;
+		psk = sta->psk->psk;
+		for (pos = sta->psk; pos; pos = pos->next) {
+			if (pos->psk == prev_psk) {
+				psk = pos->next ? pos->next->psk : NULL;
+				break;
+			}
+		}
+	}
+	return psk;
+}
+
+
+static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
+				    size_t *len)
+{
+	struct hostapd_data *hapd = ctx;
+	const u8 *key;
+	size_t keylen;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
+	if (key == NULL)
+		return -1;
+
+	if (keylen > *len)
+		keylen = *len;
+	os_memcpy(msk, key, keylen);
+	*len = keylen;
+
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+				    const u8 *addr, int idx, u8 *key,
+				    size_t key_len)
+{
+	struct hostapd_data *hapd = ctx;
+	const char *ifname = hapd->conf->iface;
+
+	if (vlan_id > 0) {
+		ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+		if (ifname == NULL)
+			return -1;
+	}
+
+	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
+				   key, key_len);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
+				       u8 *seq)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
+}
+
+
+static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+				       const u8 *data, size_t data_len,
+				       int encrypt)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	u32 flags = 0;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		flags = hostapd_sta_flags_to_drv(sta->flags);
+
+	return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
+					   encrypt, flags);
+}
+
+
+static int hostapd_wpa_auth_for_each_sta(
+	void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
+	void *cb_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
+			return 1;
+	}
+	return 0;
+}
+
+
+struct wpa_auth_iface_iter_data {
+	int (*cb)(struct wpa_authenticator *sm, void *ctx);
+	void *cb_ctx;
+};
+
+static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx)
+{
+	struct wpa_auth_iface_iter_data *data = ctx;
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++) {
+		if (iface->bss[i]->wpa_auth &&
+		    data->cb(iface->bss[i]->wpa_auth, data->cb_ctx))
+			return 1;
+	}
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_for_each_auth(
+	void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
+	void *cb_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct wpa_auth_iface_iter_data data;
+	if (hapd->iface->interfaces == NULL ||
+	    hapd->iface->interfaces->for_each_interface == NULL)
+		return -1;
+	data.cb = cb;
+	data.cb_ctx = cb_ctx;
+	return hapd->iface->interfaces->for_each_interface(
+		hapd->iface->interfaces, wpa_auth_iface_iter, &data);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+struct wpa_auth_ft_iface_iter_data {
+	struct hostapd_data *src_hapd;
+	const u8 *dst;
+	const u8 *data;
+	size_t data_len;
+};
+
+
+static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
+{
+	struct wpa_auth_ft_iface_iter_data *idata = ctx;
+	struct hostapd_data *hapd;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		if (hapd == idata->src_hapd)
+			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 -> "
+				   MACSTR "@%s",
+				   MAC2STR(idata->src_hapd->own_addr),
+				   idata->src_hapd->conf->iface,
+				   MAC2STR(hapd->own_addr), hapd->conf->iface);
+			wpa_ft_rrb_rx(hapd->wpa_auth,
+				      idata->src_hapd->own_addr,
+				      idata->data, idata->data_len);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
+				       const u8 *data, size_t data_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct l2_ethhdr *buf;
+	int ret;
+
+#ifdef CONFIG_IEEE80211R
+	if (proto == ETH_P_RRB && hapd->iface->interfaces &&
+	    hapd->iface->interfaces->for_each_interface) {
+		int res;
+		struct wpa_auth_ft_iface_iter_data idata;
+		idata.src_hapd = hapd;
+		idata.dst = dst;
+		idata.data = data;
+		idata.data_len = data_len;
+		res = hapd->iface->interfaces->for_each_interface(
+			hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
+			&idata);
+		if (res == 1)
+			return data_len;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (hapd->driver && hapd->driver->send_ether)
+		return hapd->driver->send_ether(hapd->drv_priv, dst,
+						hapd->own_addr, proto,
+						data, data_len);
+	if (hapd->l2 == NULL)
+		return -1;
+
+	buf = os_malloc(sizeof(*buf) + data_len);
+	if (buf == NULL)
+		return -1;
+	os_memcpy(buf->h_dest, dst, ETH_ALEN);
+	os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
+	buf->h_proto = host_to_be16(proto);
+	os_memcpy(buf + 1, data, data_len);
+	ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
+			     sizeof(*buf) + data_len);
+	os_free(buf);
+	return ret;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
+					   const u8 *data, size_t data_len)
+{
+	struct hostapd_data *hapd = ctx;
+	int res;
+	struct ieee80211_mgmt *m;
+	size_t mlen;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL || sta->wpa_sm == NULL)
+		return -1;
+
+	m = os_zalloc(sizeof(*m) + data_len);
+	if (m == NULL)
+		return -1;
+	mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
+	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					WLAN_FC_STYPE_ACTION);
+	os_memcpy(m->da, dst, ETH_ALEN);
+	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+	os_memcpy(&m->u, data, data_len);
+
+	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+	os_free(m);
+	return res;
+}
+
+
+static struct wpa_state_machine *
+hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+		return NULL;
+
+	sta = ap_sta_add(hapd, sta_addr);
+	if (sta == NULL)
+		return NULL;
+	if (sta->wpa_sm) {
+		sta->auth_alg = WLAN_AUTH_FT;
+		return sta->wpa_sm;
+	}
+
+	sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+	if (sta->wpa_sm == NULL) {
+		ap_free_sta(hapd, sta);
+		return NULL;
+	}
+	sta->auth_alg = WLAN_AUTH_FT;
+
+	return sta->wpa_sm;
+}
+
+
+static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+				size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct l2_ethhdr *ethhdr;
+	if (len < sizeof(*ethhdr))
+		return;
+	ethhdr = (struct l2_ethhdr *) buf;
+	wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
+		   MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
+	wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
+		      len - sizeof(*ethhdr));
+}
+
+
+static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
+				      u8 *tspec_ie, size_t tspec_ielen)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+int hostapd_setup_wpa(struct hostapd_data *hapd)
+{
+	struct wpa_auth_config _conf;
+	struct wpa_auth_callbacks cb;
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	hostapd_wpa_auth_conf(hapd->conf, &_conf);
+	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
+		_conf.tx_status = 1;
+	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
+		_conf.ap_mlme = 1;
+	os_memset(&cb, 0, sizeof(cb));
+	cb.ctx = hapd;
+	cb.logger = hostapd_wpa_auth_logger;
+	cb.disconnect = hostapd_wpa_auth_disconnect;
+	cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+	cb.set_eapol = hostapd_wpa_auth_set_eapol;
+	cb.get_eapol = hostapd_wpa_auth_get_eapol;
+	cb.get_psk = hostapd_wpa_auth_get_psk;
+	cb.get_msk = hostapd_wpa_auth_get_msk;
+	cb.set_key = hostapd_wpa_auth_set_key;
+	cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
+	cb.send_eapol = hostapd_wpa_auth_send_eapol;
+	cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
+	cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
+	cb.send_ether = hostapd_wpa_auth_send_ether;
+#ifdef CONFIG_IEEE80211R
+	cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
+	cb.add_sta = hostapd_wpa_auth_add_sta;
+	cb.add_tspec = hostapd_wpa_auth_add_tspec;
+#endif /* CONFIG_IEEE80211R */
+	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+	if (hapd->wpa_auth == NULL) {
+		wpa_printf(MSG_ERROR, "WPA initialization failed.");
+		return -1;
+	}
+
+	if (hostapd_set_privacy(hapd, 1)) {
+		wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
+			   "for interface %s", hapd->conf->iface);
+		return -1;
+	}
+
+	wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+	if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
+		wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+			   "the kernel driver.");
+		return -1;
+	}
+
+	if (rsn_preauth_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Initialization of RSN "
+			   "pre-authentication failed.");
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (!hostapd_drv_none(hapd)) {
+		hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
+					  hapd->conf->bridge :
+					  hapd->conf->iface, NULL, ETH_P_RRB,
+					  hostapd_rrb_receive, hapd, 1);
+		if (hapd->l2 == NULL &&
+		    (hapd->driver == NULL ||
+		     hapd->driver->send_ether == NULL)) {
+			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
+				   "interface");
+			return -1;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	return 0;
+
+}
+
+
+void hostapd_reconfig_wpa(struct hostapd_data *hapd)
+{
+	struct wpa_auth_config wpa_auth_conf;
+	hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
+	wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
+}
+
+
+void hostapd_deinit_wpa(struct hostapd_data *hapd)
+{
+	ieee80211_tkip_countermeasures_deinit(hapd);
+	rsn_preauth_iface_deinit(hapd);
+	if (hapd->wpa_auth) {
+		wpa_deinit(hapd->wpa_auth);
+		hapd->wpa_auth = NULL;
+
+		if (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)) {
+			wpa_printf(MSG_DEBUG, "Could not remove generic "
+				   "information element from interface %s",
+				   hapd->conf->iface);
+		}
+	}
+	ieee802_1x_deinit(hapd);
+
+#ifdef CONFIG_IEEE80211R
+	l2_packet_deinit(hapd->l2);
+#endif /* CONFIG_IEEE80211R */
+}

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_glue.h
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_glue.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_glue.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,22 +0,0 @@
-/*
- * hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_AUTH_GLUE_H
-#define WPA_AUTH_GLUE_H
-
-int hostapd_setup_wpa(struct hostapd_data *hapd);
-void hostapd_reconfig_wpa(struct hostapd_data *hapd);
-void hostapd_deinit_wpa(struct hostapd_data *hapd);
-
-#endif /* WPA_AUTH_GLUE_H */

Copied: vendor/wpa/2.0/src/ap/wpa_auth_glue.h (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_glue.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_glue.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_glue.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+/*
+ * hostapd / WPA authenticator glue code
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_GLUE_H
+#define WPA_AUTH_GLUE_H
+
+int hostapd_setup_wpa(struct hostapd_data *hapd);
+void hostapd_reconfig_wpa(struct hostapd_data *hapd);
+void hostapd_deinit_wpa(struct hostapd_data *hapd);
+
+#endif /* WPA_AUTH_GLUE_H */

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_i.h
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,230 +0,0 @@
-/*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_AUTH_I_H
-#define WPA_AUTH_I_H
-
-/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
-#define RSNA_MAX_EAPOL_RETRIES 4
-
-struct wpa_group;
-
-struct wpa_stsl_negotiation {
-	struct wpa_stsl_negotiation *next;
-	u8 initiator[ETH_ALEN];
-	u8 peer[ETH_ALEN];
-};
-
-
-struct wpa_state_machine {
-	struct wpa_authenticator *wpa_auth;
-	struct wpa_group *group;
-
-	u8 addr[ETH_ALEN];
-
-	enum {
-		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
-		WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
-		WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
-		WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
-		WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
-	} wpa_ptk_state;
-
-	enum {
-		WPA_PTK_GROUP_IDLE = 0,
-		WPA_PTK_GROUP_REKEYNEGOTIATING,
-		WPA_PTK_GROUP_REKEYESTABLISHED,
-		WPA_PTK_GROUP_KEYERROR
-	} wpa_ptk_group_state;
-
-	Boolean Init;
-	Boolean DeauthenticationRequest;
-	Boolean AuthenticationRequest;
-	Boolean ReAuthenticationRequest;
-	Boolean Disconnect;
-	int TimeoutCtr;
-	int GTimeoutCtr;
-	Boolean TimeoutEvt;
-	Boolean EAPOLKeyReceived;
-	Boolean EAPOLKeyPairwise;
-	Boolean EAPOLKeyRequest;
-	Boolean MICVerified;
-	Boolean GUpdateStationKeys;
-	u8 ANonce[WPA_NONCE_LEN];
-	u8 SNonce[WPA_NONCE_LEN];
-	u8 PMK[PMK_LEN];
-	struct wpa_ptk PTK;
-	Boolean PTK_valid;
-	Boolean pairwise_set;
-	int keycount;
-	Boolean Pair;
-	struct {
-		u8 counter[WPA_REPLAY_COUNTER_LEN];
-		Boolean valid;
-	} key_replay[RSNA_MAX_EAPOL_RETRIES];
-	Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
-	Boolean PTKRequest; /* not in IEEE 802.11i state machine */
-	Boolean has_GTK;
-	Boolean PtkGroupInit; /* init request for PTK Group state machine */
-
-	u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
-	size_t last_rx_eapol_key_len;
-
-	unsigned int changed:1;
-	unsigned int in_step_loop:1;
-	unsigned int pending_deinit:1;
-	unsigned int started:1;
-	unsigned int mgmt_frame_prot:1;
-#ifdef CONFIG_IEEE80211R
-	unsigned int ft_completed:1;
-	unsigned int pmk_r1_name_valid:1;
-#endif /* CONFIG_IEEE80211R */
-
-	u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
-	int req_replay_counter_used;
-
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
-
-	enum {
-		WPA_VERSION_NO_WPA = 0 /* WPA not used */,
-		WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
-		WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
-	} wpa;
-	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
-	struct rsn_pmksa_cache_entry *pmksa;
-
-	u32 dot11RSNAStatsTKIPLocalMICFailures;
-	u32 dot11RSNAStatsTKIPRemoteMICFailures;
-
-#ifdef CONFIG_IEEE80211R
-	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
-	size_t xxkey_len;
-	u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
-					   * Request */
-	u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
-	size_t r0kh_id_len;
-	u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
-					       * message 2/4 */
-	u8 *assoc_resp_ftie;
-#endif /* CONFIG_IEEE80211R */
-};
-
-
-/* per group key state machine data */
-struct wpa_group {
-	struct wpa_group *next;
-	int vlan_id;
-
-	Boolean GInit;
-	int GKeyDoneStations;
-	Boolean GTKReKey;
-	int GTK_len;
-	int GN, GM;
-	Boolean GTKAuthenticator;
-	u8 Counter[WPA_NONCE_LEN];
-
-	enum {
-		WPA_GROUP_GTK_INIT = 0,
-		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
-	} wpa_group_state;
-
-	u8 GMK[WPA_GMK_LEN];
-	u8 GTK[2][WPA_GTK_MAX_LEN];
-	u8 GNonce[WPA_NONCE_LEN];
-	Boolean changed;
-#ifdef CONFIG_IEEE80211W
-	u8 IGTK[2][WPA_IGTK_LEN];
-	int GN_igtk, GM_igtk;
-#endif /* CONFIG_IEEE80211W */
-};
-
-
-struct wpa_ft_pmk_cache;
-
-/* per authenticator data */
-struct wpa_authenticator {
-	struct wpa_group *group;
-
-	unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
-	u32 dot11RSNAAuthenticationSuiteSelected;
-	u32 dot11RSNAPairwiseCipherSelected;
-	u32 dot11RSNAGroupCipherSelected;
-	u8 dot11RSNAPMKIDUsed[PMKID_LEN];
-	u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
-	u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
-	u32 dot11RSNAGroupCipherRequested; /* FIX: update */
-	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
-	unsigned int dot11RSNA4WayHandshakeFailures;
-
-	struct wpa_stsl_negotiation *stsl_negotiations;
-
-	struct wpa_auth_config conf;
-	struct wpa_auth_callbacks cb;
-
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
-
-	u8 addr[ETH_ALEN];
-
-	struct rsn_pmksa_cache *pmksa;
-	struct wpa_ft_pmk_cache *ft_pmk_cache;
-};
-
-
-int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
-		     const u8 *pmkid);
-void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
-		     logger_level level, const char *txt);
-void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
-		      logger_level level, const char *fmt, ...);
-void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
-		      struct wpa_state_machine *sm, int key_info,
-		      const u8 *key_rsc, const u8 *nonce,
-		      const u8 *kde, size_t kde_len,
-		      int keyidx, int encr, int force_version);
-int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
-			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
-			  void *cb_ctx);
-int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
-			   int (*cb)(struct wpa_authenticator *a, void *ctx),
-			   void *cb_ctx);
-
-#ifdef CONFIG_PEERKEY
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
-		    struct wpa_stsl_negotiation *neg);
-void wpa_smk_error(struct wpa_authenticator *wpa_auth,
-		   struct wpa_state_machine *sm, struct wpa_eapol_key *key);
-void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
-void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211R
-int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
-int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
-		   size_t r0kh_id_len,
-		   const u8 *anonce, const u8 *snonce,
-		   u8 *buf, size_t len, const u8 *subelem,
-		   size_t subelem_len);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
-			   struct wpa_ptk *ptk, size_t ptk_len);
-struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
-void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
-void wpa_ft_install_ptk(struct wpa_state_machine *sm);
-#endif /* CONFIG_IEEE80211R */
-
-#endif /* WPA_AUTH_I_H */

Copied: vendor/wpa/2.0/src/ap/wpa_auth_i.h (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_i.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,232 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_I_H
+#define WPA_AUTH_I_H
+
+/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
+#define RSNA_MAX_EAPOL_RETRIES 4
+
+struct wpa_group;
+
+struct wpa_stsl_negotiation {
+	struct wpa_stsl_negotiation *next;
+	u8 initiator[ETH_ALEN];
+	u8 peer[ETH_ALEN];
+};
+
+
+struct wpa_state_machine {
+	struct wpa_authenticator *wpa_auth;
+	struct wpa_group *group;
+
+	u8 addr[ETH_ALEN];
+
+	enum {
+		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
+		WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
+		WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
+		WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
+		WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
+	} wpa_ptk_state;
+
+	enum {
+		WPA_PTK_GROUP_IDLE = 0,
+		WPA_PTK_GROUP_REKEYNEGOTIATING,
+		WPA_PTK_GROUP_REKEYESTABLISHED,
+		WPA_PTK_GROUP_KEYERROR
+	} wpa_ptk_group_state;
+
+	Boolean Init;
+	Boolean DeauthenticationRequest;
+	Boolean AuthenticationRequest;
+	Boolean ReAuthenticationRequest;
+	Boolean Disconnect;
+	int TimeoutCtr;
+	int GTimeoutCtr;
+	Boolean TimeoutEvt;
+	Boolean EAPOLKeyReceived;
+	Boolean EAPOLKeyPairwise;
+	Boolean EAPOLKeyRequest;
+	Boolean MICVerified;
+	Boolean GUpdateStationKeys;
+	u8 ANonce[WPA_NONCE_LEN];
+	u8 SNonce[WPA_NONCE_LEN];
+	u8 PMK[PMK_LEN];
+	struct wpa_ptk PTK;
+	Boolean PTK_valid;
+	Boolean pairwise_set;
+	int keycount;
+	Boolean Pair;
+	struct wpa_key_replay_counter {
+		u8 counter[WPA_REPLAY_COUNTER_LEN];
+		Boolean valid;
+	} key_replay[RSNA_MAX_EAPOL_RETRIES],
+		prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
+	Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
+	Boolean PTKRequest; /* not in IEEE 802.11i state machine */
+	Boolean has_GTK;
+	Boolean PtkGroupInit; /* init request for PTK Group state machine */
+
+	u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
+	size_t last_rx_eapol_key_len;
+
+	unsigned int changed:1;
+	unsigned int in_step_loop:1;
+	unsigned int pending_deinit:1;
+	unsigned int started:1;
+	unsigned int mgmt_frame_prot:1;
+	unsigned int rx_eapol_key_secure:1;
+	unsigned int update_snonce:1;
+#ifdef CONFIG_IEEE80211R
+	unsigned int ft_completed:1;
+	unsigned int pmk_r1_name_valid:1;
+#endif /* CONFIG_IEEE80211R */
+	unsigned int is_wnmsleep:1;
+
+	u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int req_replay_counter_used;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	enum {
+		WPA_VERSION_NO_WPA = 0 /* WPA not used */,
+		WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
+		WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
+	} wpa;
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	u32 dot11RSNAStatsTKIPLocalMICFailures;
+	u32 dot11RSNAStatsTKIPRemoteMICFailures;
+
+#ifdef CONFIG_IEEE80211R
+	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	size_t xxkey_len;
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
+					   * Request */
+	u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
+	size_t r0kh_id_len;
+	u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
+					       * message 2/4 */
+	u8 *assoc_resp_ftie;
+#endif /* CONFIG_IEEE80211R */
+
+	int pending_1_of_4_timeout;
+};
+
+
+/* per group key state machine data */
+struct wpa_group {
+	struct wpa_group *next;
+	int vlan_id;
+
+	Boolean GInit;
+	int GKeyDoneStations;
+	Boolean GTKReKey;
+	int GTK_len;
+	int GN, GM;
+	Boolean GTKAuthenticator;
+	u8 Counter[WPA_NONCE_LEN];
+
+	enum {
+		WPA_GROUP_GTK_INIT = 0,
+		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+	} wpa_group_state;
+
+	u8 GMK[WPA_GMK_LEN];
+	u8 GTK[2][WPA_GTK_MAX_LEN];
+	u8 GNonce[WPA_NONCE_LEN];
+	Boolean changed;
+	Boolean first_sta_seen;
+	Boolean reject_4way_hs_for_entropy;
+#ifdef CONFIG_IEEE80211W
+	u8 IGTK[2][WPA_IGTK_LEN];
+	int GN_igtk, GM_igtk;
+#endif /* CONFIG_IEEE80211W */
+};
+
+
+struct wpa_ft_pmk_cache;
+
+/* per authenticator data */
+struct wpa_authenticator {
+	struct wpa_group *group;
+
+	unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
+	u32 dot11RSNAAuthenticationSuiteSelected;
+	u32 dot11RSNAPairwiseCipherSelected;
+	u32 dot11RSNAGroupCipherSelected;
+	u8 dot11RSNAPMKIDUsed[PMKID_LEN];
+	u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
+	u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
+	u32 dot11RSNAGroupCipherRequested; /* FIX: update */
+	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
+	unsigned int dot11RSNA4WayHandshakeFailures;
+
+	struct wpa_stsl_negotiation *stsl_negotiations;
+
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	u8 addr[ETH_ALEN];
+
+	struct rsn_pmksa_cache *pmksa;
+	struct wpa_ft_pmk_cache *ft_pmk_cache;
+};
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+		     const u8 *pmkid);
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		     logger_level level, const char *txt);
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		      logger_level level, const char *fmt, ...);
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+		      struct wpa_state_machine *sm, int key_info,
+		      const u8 *key_rsc, const u8 *nonce,
+		      const u8 *kde, size_t kde_len,
+		      int keyidx, int encr, int force_version);
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
+			  void *cb_ctx);
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+			   int (*cb)(struct wpa_authenticator *a, void *ctx),
+			   void *cb_ctx);
+
+#ifdef CONFIG_PEERKEY
+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+		    struct wpa_stsl_negotiation *neg);
+void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+		   struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211R
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
+		   size_t r0kh_id_len,
+		   const u8 *anonce, const u8 *snonce,
+		   u8 *buf, size_t len, const u8 *subelem,
+		   size_t subelem_len);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+			   struct wpa_ptk *ptk, size_t ptk_len);
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm);
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* WPA_AUTH_I_H */

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_ie.c
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_ie.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ie.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,868 +0,0 @@
-/*
- * hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "ap_config.h"
-#include "ieee802_11.h"
-#include "wpa_auth.h"
-#include "pmksa_cache_auth.h"
-#include "wpa_auth_ie.h"
-#include "wpa_auth_i.h"
-
-
-static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
-{
-	struct wpa_ie_hdr *hdr;
-	int num_suites;
-	u8 *pos, *count;
-
-	hdr = (struct wpa_ie_hdr *) buf;
-	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
-	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
-	WPA_PUT_LE16(hdr->version, WPA_VERSION);
-	pos = (u8 *) (hdr + 1);
-
-	if (conf->wpa_group == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
-	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
-	} else {
-		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
-			   conf->wpa_group);
-		return -1;
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	num_suites = 0;
-	count = pos;
-	pos += 2;
-
-	if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-		pos += WPA_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-		pos += WPA_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
-		pos += WPA_SELECTOR_LEN;
-		num_suites++;
-	}
-
-	if (num_suites == 0) {
-		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
-			   conf->wpa_pairwise);
-		return -1;
-	}
-	WPA_PUT_LE16(count, num_suites);
-
-	num_suites = 0;
-	count = pos;
-	pos += 2;
-
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
-		pos += WPA_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
-		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
-		pos += WPA_SELECTOR_LEN;
-		num_suites++;
-	}
-
-	if (num_suites == 0) {
-		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
-			   conf->wpa_key_mgmt);
-		return -1;
-	}
-	WPA_PUT_LE16(count, num_suites);
-
-	/* WPA Capabilities; use defaults, so no need to include it */
-
-	hdr->len = (pos - buf) - 2;
-
-	return pos - buf;
-}
-
-
-int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
-		     const u8 *pmkid)
-{
-	struct rsn_ie_hdr *hdr;
-	int num_suites;
-	u8 *pos, *count;
-	u16 capab;
-
-	hdr = (struct rsn_ie_hdr *) buf;
-	hdr->elem_id = WLAN_EID_RSN;
-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
-	pos = (u8 *) (hdr + 1);
-
-	if (conf->wpa_group == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
-	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
-	} else {
-		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
-			   conf->wpa_group);
-		return -1;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	num_suites = 0;
-	count = pos;
-	pos += 2;
-
-	if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-
-	if (num_suites == 0) {
-		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
-			   conf->rsn_pairwise);
-		return -1;
-	}
-	WPA_PUT_LE16(count, num_suites);
-
-	num_suites = 0;
-	count = pos;
-	pos += 2;
-
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-#ifdef CONFIG_IEEE80211R
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-		pos += RSN_SELECTOR_LEN;
-		num_suites++;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	if (num_suites == 0) {
-		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
-			   conf->wpa_key_mgmt);
-		return -1;
-	}
-	WPA_PUT_LE16(count, num_suites);
-
-	/* RSN Capabilities */
-	capab = 0;
-	if (conf->rsn_preauth)
-		capab |= WPA_CAPABILITY_PREAUTH;
-	if (conf->peerkey)
-		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
-	if (conf->wmm_enabled) {
-		/* 4 PTKSA replay counters when using WMM */
-		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
-	}
-#ifdef CONFIG_IEEE80211W
-	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		capab |= WPA_CAPABILITY_MFPC;
-		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
-			capab |= WPA_CAPABILITY_MFPR;
-	}
-#endif /* CONFIG_IEEE80211W */
-	WPA_PUT_LE16(pos, capab);
-	pos += 2;
-
-	if (pmkid) {
-		if (pos + 2 + PMKID_LEN > buf + len)
-			return -1;
-		/* PMKID Count */
-		WPA_PUT_LE16(pos, 1);
-		pos += 2;
-		os_memcpy(pos, pmkid, PMKID_LEN);
-		pos += PMKID_LEN;
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		if (pos + 2 + 4 > buf + len)
-			return -1;
-		if (pmkid == NULL) {
-			/* PMKID Count */
-			WPA_PUT_LE16(pos, 0);
-			pos += 2;
-		}
-
-		/* Management Group Cipher Suite */
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
-		pos += RSN_SELECTOR_LEN;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	hdr->len = (pos - buf) - 2;
-
-	return pos - buf;
-}
-
-
-int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
-{
-	u8 *pos, buf[128];
-	int res;
-
-	pos = buf;
-
-	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
-		res = wpa_write_rsn_ie(&wpa_auth->conf,
-				       pos, buf + sizeof(buf) - pos, NULL);
-		if (res < 0)
-			return res;
-		pos += res;
-	}
-#ifdef CONFIG_IEEE80211R
-	if (wpa_auth->conf.wpa_key_mgmt &
-	    (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
-		res = wpa_write_mdie(&wpa_auth->conf, pos,
-				     buf + sizeof(buf) - pos);
-		if (res < 0)
-			return res;
-		pos += res;
-	}
-#endif /* CONFIG_IEEE80211R */
-	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
-		res = wpa_write_wpa_ie(&wpa_auth->conf,
-				       pos, buf + sizeof(buf) - pos);
-		if (res < 0)
-			return res;
-		pos += res;
-	}
-
-	os_free(wpa_auth->wpa_ie);
-	wpa_auth->wpa_ie = os_malloc(pos - buf);
-	if (wpa_auth->wpa_ie == NULL)
-		return -1;
-	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
-	wpa_auth->wpa_ie_len = pos - buf;
-
-	return 0;
-}
-
-
-u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
-		 const u8 *data2, size_t data2_len)
-{
-	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
-	RSN_SELECTOR_PUT(pos, kde);
-	pos += RSN_SELECTOR_LEN;
-	os_memcpy(pos, data, data_len);
-	pos += data_len;
-	if (data2) {
-		os_memcpy(pos, data2, data2_len);
-		pos += data2_len;
-	}
-	return pos;
-}
-
-
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-		return WPA_CIPHER_NONE;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-		return WPA_CIPHER_WEP40;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-		return WPA_CIPHER_TKIP;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-		return WPA_CIPHER_CCMP;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-		return WPA_CIPHER_WEP104;
-	return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-		return WPA_KEY_MGMT_IEEE8021X;
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-		return WPA_KEY_MGMT_PSK;
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-		return WPA_KEY_MGMT_WPA_NONE;
-	return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-				struct wpa_ie_data *data)
-{
-	const struct wpa_ie_hdr *hdr;
-	const u8 *pos;
-	int left;
-	int i, count;
-
-	os_memset(data, 0, sizeof(*data));
-	data->pairwise_cipher = WPA_CIPHER_TKIP;
-	data->group_cipher = WPA_CIPHER_TKIP;
-	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	data->mgmt_group_cipher = 0;
-
-	if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
-		return -1;
-
-	hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-	    hdr->len != wpa_ie_len - 2 ||
-	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-		return -2;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	left = wpa_ie_len - sizeof(*hdr);
-
-	if (left >= WPA_SELECTOR_LEN) {
-		data->group_cipher = wpa_selector_to_bitfield(pos);
-		pos += WPA_SELECTOR_LEN;
-		left -= WPA_SELECTOR_LEN;
-	} else if (left > 0)
-		  return -3;
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN)
-			return -4;
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1)
-		return -5;
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN)
-			return -6;
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1)
-		return -7;
-
-	if (left >= 2) {
-		data->capabilities = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left > 0) {
-		return -8;
-	}
-
-	return 0;
-}
-
-
-struct wpa_auth_okc_iter_data {
-	struct rsn_pmksa_cache_entry *pmksa;
-	const u8 *aa;
-	const u8 *spa;
-	const u8 *pmkid;
-};
-
-
-static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
-{
-	struct wpa_auth_okc_iter_data *data = ctx;
-	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
-					  data->pmkid);
-	if (data->pmksa)
-		return 1;
-	return 0;
-}
-
-
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
-			struct wpa_state_machine *sm,
-			const u8 *wpa_ie, size_t wpa_ie_len,
-			const u8 *mdie, size_t mdie_len)
-{
-	struct wpa_ie_data data;
-	int ciphers, key_mgmt, res, version;
-	u32 selector;
-	size_t i;
-	const u8 *pmkid = NULL;
-
-	if (wpa_auth == NULL || sm == NULL)
-		return WPA_NOT_ENABLED;
-
-	if (wpa_ie == NULL || wpa_ie_len < 1)
-		return WPA_INVALID_IE;
-
-	if (wpa_ie[0] == WLAN_EID_RSN)
-		version = WPA_PROTO_RSN;
-	else
-		version = WPA_PROTO_WPA;
-
-	if (!(wpa_auth->conf.wpa & version)) {
-		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
-			   version, MAC2STR(sm->addr));
-		return WPA_INVALID_PROTO;
-	}
-
-	if (version == WPA_PROTO_RSN) {
-		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
-
-		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
-		if (0) {
-		}
-#ifdef CONFIG_IEEE80211R
-		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
-		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
-			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
-		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
-		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
-		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
-			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
-
-		selector = RSN_CIPHER_SUITE_CCMP;
-		if (data.pairwise_cipher & WPA_CIPHER_CCMP)
-			selector = RSN_CIPHER_SUITE_CCMP;
-		else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
-			selector = RSN_CIPHER_SUITE_TKIP;
-		else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
-			selector = RSN_CIPHER_SUITE_WEP104;
-		else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
-			selector = RSN_CIPHER_SUITE_WEP40;
-		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
-			selector = RSN_CIPHER_SUITE_NONE;
-		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
-
-		selector = RSN_CIPHER_SUITE_CCMP;
-		if (data.group_cipher & WPA_CIPHER_CCMP)
-			selector = RSN_CIPHER_SUITE_CCMP;
-		else if (data.group_cipher & WPA_CIPHER_TKIP)
-			selector = RSN_CIPHER_SUITE_TKIP;
-		else if (data.group_cipher & WPA_CIPHER_WEP104)
-			selector = RSN_CIPHER_SUITE_WEP104;
-		else if (data.group_cipher & WPA_CIPHER_WEP40)
-			selector = RSN_CIPHER_SUITE_WEP40;
-		else if (data.group_cipher & WPA_CIPHER_NONE)
-			selector = RSN_CIPHER_SUITE_NONE;
-		wpa_auth->dot11RSNAGroupCipherSelected = selector;
-	} else {
-		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
-
-		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
-		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
-		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
-			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
-
-		selector = WPA_CIPHER_SUITE_TKIP;
-		if (data.pairwise_cipher & WPA_CIPHER_CCMP)
-			selector = WPA_CIPHER_SUITE_CCMP;
-		else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
-			selector = WPA_CIPHER_SUITE_TKIP;
-		else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
-			selector = WPA_CIPHER_SUITE_WEP104;
-		else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
-			selector = WPA_CIPHER_SUITE_WEP40;
-		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
-			selector = WPA_CIPHER_SUITE_NONE;
-		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
-
-		selector = WPA_CIPHER_SUITE_TKIP;
-		if (data.group_cipher & WPA_CIPHER_CCMP)
-			selector = WPA_CIPHER_SUITE_CCMP;
-		else if (data.group_cipher & WPA_CIPHER_TKIP)
-			selector = WPA_CIPHER_SUITE_TKIP;
-		else if (data.group_cipher & WPA_CIPHER_WEP104)
-			selector = WPA_CIPHER_SUITE_WEP104;
-		else if (data.group_cipher & WPA_CIPHER_WEP40)
-			selector = WPA_CIPHER_SUITE_WEP40;
-		else if (data.group_cipher & WPA_CIPHER_NONE)
-			selector = WPA_CIPHER_SUITE_NONE;
-		wpa_auth->dot11RSNAGroupCipherSelected = selector;
-	}
-	if (res) {
-		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
-			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
-		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
-		return WPA_INVALID_IE;
-	}
-
-	if (data.group_cipher != wpa_auth->conf.wpa_group) {
-		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
-			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
-		return WPA_INVALID_GROUP;
-	}
-
-	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
-	if (!key_mgmt) {
-		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
-			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
-		return WPA_INVALID_AKMP;
-	}
-	if (0) {
-	}
-#ifdef CONFIG_IEEE80211R
-	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
-	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
-	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
-	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	else
-		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-
-	if (version == WPA_PROTO_RSN)
-		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
-	else
-		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
-	if (!ciphers) {
-		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
-			   "from " MACSTR,
-			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
-			   data.pairwise_cipher, MAC2STR(sm->addr));
-		return WPA_INVALID_PAIRWISE;
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
-		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
-			wpa_printf(MSG_DEBUG, "Management frame protection "
-				   "required, but client did not enable it");
-			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
-		}
-
-		if (ciphers & WPA_CIPHER_TKIP) {
-			wpa_printf(MSG_DEBUG, "Management frame protection "
-				   "cannot use TKIP");
-			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
-		}
-
-		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
-			wpa_printf(MSG_DEBUG, "Unsupported management group "
-				   "cipher %d", data.mgmt_group_cipher);
-			return WPA_INVALID_MGMT_GROUP_CIPHER;
-		}
-	}
-
-	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
-	    !(data.capabilities & WPA_CAPABILITY_MFPC))
-		sm->mgmt_frame_prot = 0;
-	else
-		sm->mgmt_frame_prot = 1;
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
-		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
-			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
-				   "MDIE not included");
-			return WPA_INVALID_MDIE;
-		}
-		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
-			      MOBILITY_DOMAIN_ID_LEN) != 0) {
-			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
-				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
-			return WPA_INVALID_MDIE;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (ciphers & WPA_CIPHER_CCMP)
-		sm->pairwise = WPA_CIPHER_CCMP;
-	else
-		sm->pairwise = WPA_CIPHER_TKIP;
-
-	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
-	if (wpa_ie[0] == WLAN_EID_RSN)
-		sm->wpa = WPA_VERSION_WPA2;
-	else
-		sm->wpa = WPA_VERSION_WPA;
-
-	sm->pmksa = NULL;
-	for (i = 0; i < data.num_pmkid; i++) {
-		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
-			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
-		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
-						 &data.pmkid[i * PMKID_LEN]);
-		if (sm->pmksa) {
-			pmkid = sm->pmksa->pmkid;
-			break;
-		}
-	}
-	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
-		     i < data.num_pmkid; i++) {
-		struct wpa_auth_okc_iter_data idata;
-		idata.pmksa = NULL;
-		idata.aa = wpa_auth->addr;
-		idata.spa = sm->addr;
-		idata.pmkid = &data.pmkid[i * PMKID_LEN];
-		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
-		if (idata.pmksa) {
-			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-					 "OKC match for PMKID");
-			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
-							idata.pmksa,
-							wpa_auth->addr,
-							idata.pmkid);
-			pmkid = idata.pmkid;
-			break;
-		}
-	}
-	if (sm->pmksa) {
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-				 "PMKID found from PMKSA cache "
-				 "eap_type=%d vlan_id=%d",
-				 sm->pmksa->eap_type_authsrv,
-				 sm->pmksa->vlan_id);
-		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
-	}
-
-	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
-		os_free(sm->wpa_ie);
-		sm->wpa_ie = os_malloc(wpa_ie_len);
-		if (sm->wpa_ie == NULL)
-			return WPA_ALLOC_FAIL;
-	}
-	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
-	sm->wpa_ie_len = wpa_ie_len;
-
-	return WPA_IE_OK;
-}
-
-
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	if (pos[1] == 0)
-		return 1;
-
-	if (pos[1] >= 6 &&
-	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
-	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
-	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
-		ie->wpa_ie = pos;
-		ie->wpa_ie_len = pos[1] + 2;
-		return 0;
-	}
-
-	if (pos + 1 + RSN_SELECTOR_LEN < end &&
-	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
-		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
-		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
-		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
-		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-#ifdef CONFIG_PEERKEY
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
-		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
-		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
-		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
-		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
-		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
-		ie->error = pos + 2 + RSN_SELECTOR_LEN;
-		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211W
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
-		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
-		return 0;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	return 0;
-}
-
-
-/**
- * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
-{
-	const u8 *pos, *end;
-	int ret = 0;
-
-	os_memset(ie, 0, sizeof(*ie));
-	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
-		if (pos[0] == 0xdd &&
-		    ((pos == buf + len - 1) || pos[1] == 0)) {
-			/* Ignore padding */
-			break;
-		}
-		if (pos + 2 + pos[1] > end) {
-			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
-				   "underflow (ie=%d len=%d pos=%d)",
-				   pos[0], pos[1], (int) (pos - buf));
-			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
-					buf, len);
-			ret = -1;
-			break;
-		}
-		if (*pos == WLAN_EID_RSN) {
-			ie->rsn_ie = pos;
-			ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R
-		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
-			ie->mdie = pos;
-			ie->mdie_len = pos[1] + 2;
-		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
-			ie->ftie = pos;
-			ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R */
-		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
-			ret = wpa_parse_generic(pos, end, ie);
-			if (ret < 0)
-				break;
-			if (ret > 0) {
-				ret = 0;
-				break;
-			}
-		} else {
-			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
-				    "Key Data IE", pos, 2 + pos[1]);
-		}
-	}
-
-	return ret;
-}
-
-
-int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
-{
-	return sm ? sm->mgmt_frame_prot : 0;
-}

Copied: vendor/wpa/2.0/src/ap/wpa_auth_ie.c (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_ie.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_ie.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ie.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,778 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
+#include "wpa_auth_ie.h"
+#include "wpa_auth_i.h"
+
+
+#ifdef CONFIG_RSN_TESTING
+int rsn_testing = 0;
+#endif /* CONFIG_RSN_TESTING */
+
+
+static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+	struct wpa_ie_hdr *hdr;
+	int num_suites;
+	u8 *pos, *count;
+	u32 suite;
+
+	hdr = (struct wpa_ie_hdr *) buf;
+	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
+	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
+	WPA_PUT_LE16(hdr->version, WPA_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
+	if (suite == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	count = pos;
+	pos += 2;
+
+	num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->wpa_pairwise);
+		return -1;
+	}
+	pos += num_suites * WPA_SELECTOR_LEN;
+	WPA_PUT_LE16(count, num_suites);
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	/* WPA Capabilities; use defaults, so no need to include it */
+
+	hdr->len = (pos - buf) - 2;
+
+	return pos - buf;
+}
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+		     const u8 *pmkid)
+{
+	struct rsn_ie_hdr *hdr;
+	int num_suites, res;
+	u8 *pos, *count;
+	u16 capab;
+	u32 suite;
+
+	hdr = (struct rsn_ie_hdr *) buf;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+	if (suite == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+	num_suites += res;
+	pos += res * RSN_SELECTOR_LEN;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->rsn_pairwise);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	/* RSN Capabilities */
+	capab = 0;
+	if (conf->rsn_preauth)
+		capab |= WPA_CAPABILITY_PREAUTH;
+	if (conf->peerkey)
+		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
+	if (conf->wmm_enabled) {
+		/* 4 PTKSA replay counters when using WMM */
+		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+	}
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		capab |= WPA_CAPABILITY_MFPC;
+		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+			capab |= WPA_CAPABILITY_MFPR;
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing)
+		capab |= BIT(8) | BIT(14) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	if (pmkid) {
+		if (pos + 2 + PMKID_LEN > buf + len)
+			return -1;
+		/* PMKID Count */
+		WPA_PUT_LE16(pos, 1);
+		pos += 2;
+		os_memcpy(pos, pmkid, PMKID_LEN);
+		pos += PMKID_LEN;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		if (pos + 2 + 4 > buf + len)
+			return -1;
+		if (pmkid == NULL) {
+			/* PMKID Count */
+			WPA_PUT_LE16(pos, 0);
+			pos += 2;
+		}
+
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		/*
+		 * Fill in any defined fields and add extra data to the end of
+		 * the element.
+		 */
+		int pmkid_count_set = pmkid != NULL;
+		if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+			pmkid_count_set = 1;
+		/* PMKID Count */
+		WPA_PUT_LE16(pos, 0);
+		pos += 2;
+		if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+			/* Management Group Cipher Suite */
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+			pos += RSN_SELECTOR_LEN;
+		}
+
+		os_memset(pos, 0x12, 17);
+		pos += 17;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	hdr->len = (pos - buf) - 2;
+
+	return pos - buf;
+}
+
+
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
+{
+	u8 *pos, buf[128];
+	int res;
+
+	pos = buf;
+
+	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
+		res = wpa_write_rsn_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos, NULL);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
+		res = wpa_write_mdie(&wpa_auth->conf, pos,
+				     buf + sizeof(buf) - pos);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+#endif /* CONFIG_IEEE80211R */
+	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
+		res = wpa_write_wpa_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+
+	os_free(wpa_auth->wpa_ie);
+	wpa_auth->wpa_ie = os_malloc(pos - buf);
+	if (wpa_auth->wpa_ie == NULL)
+		return -1;
+	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
+	wpa_auth->wpa_ie_len = pos - buf;
+
+	return 0;
+}
+
+
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+		 const u8 *data2, size_t data2_len)
+{
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
+	RSN_SELECTOR_PUT(pos, kde);
+	pos += RSN_SELECTOR_LEN;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	if (data2) {
+		os_memcpy(pos, data2, data2_len);
+		pos += data2_len;
+	}
+	return pos;
+}
+
+
+struct wpa_auth_okc_iter_data {
+	struct rsn_pmksa_cache_entry *pmksa;
+	const u8 *aa;
+	const u8 *spa;
+	const u8 *pmkid;
+};
+
+
+static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
+{
+	struct wpa_auth_okc_iter_data *data = ctx;
+	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
+					  data->pmkid);
+	if (data->pmksa)
+		return 1;
+	return 0;
+}
+
+
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len,
+			const u8 *mdie, size_t mdie_len)
+{
+	struct wpa_ie_data data;
+	int ciphers, key_mgmt, res, version;
+	u32 selector;
+	size_t i;
+	const u8 *pmkid = NULL;
+
+	if (wpa_auth == NULL || sm == NULL)
+		return WPA_NOT_ENABLED;
+
+	if (wpa_ie == NULL || wpa_ie_len < 1)
+		return WPA_INVALID_IE;
+
+	if (wpa_ie[0] == WLAN_EID_RSN)
+		version = WPA_PROTO_RSN;
+	else
+		version = WPA_PROTO_WPA;
+
+	if (!(wpa_auth->conf.wpa & version)) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
+			   version, MAC2STR(sm->addr));
+		return WPA_INVALID_PROTO;
+	}
+
+	if (version == WPA_PROTO_RSN) {
+		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+
+		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		if (0) {
+		}
+#ifdef CONFIG_IEEE80211R
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
+			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+		else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+			selector = RSN_AUTH_KEY_MGMT_SAE;
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+			selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+					       data.pairwise_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_CCMP;
+		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+					       data.group_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_CCMP;
+		wpa_auth->dot11RSNAGroupCipherSelected = selector;
+	} else {
+		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
+
+		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+					       data.pairwise_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_TKIP;
+		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+					       data.group_cipher);
+		if (!selector)
+			selector = WPA_CIPHER_SUITE_TKIP;
+		wpa_auth->dot11RSNAGroupCipherSelected = selector;
+	}
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
+			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
+		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
+		return WPA_INVALID_IE;
+	}
+
+	if (data.group_cipher != wpa_auth->conf.wpa_group) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
+			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
+		return WPA_INVALID_GROUP;
+	}
+
+	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
+	if (!key_mgmt) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
+			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
+		return WPA_INVALID_AKMP;
+	}
+	if (0) {
+	}
+#ifdef CONFIG_IEEE80211R
+	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	else if (key_mgmt & WPA_KEY_MGMT_SAE)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+	else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	else
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+	if (version == WPA_PROTO_RSN)
+		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
+	else
+		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
+	if (!ciphers) {
+		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
+			   "from " MACSTR,
+			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
+			   data.pairwise_cipher, MAC2STR(sm->addr));
+		return WPA_INVALID_PAIRWISE;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "required, but client did not enable it");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (ciphers & WPA_CIPHER_TKIP) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "cannot use TKIP");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "Unsupported management group "
+				   "cipher %d", data.mgmt_group_cipher);
+			return WPA_INVALID_MGMT_GROUP_CIPHER;
+		}
+	}
+
+	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+	    !(data.capabilities & WPA_CAPABILITY_MFPC))
+		sm->mgmt_frame_prot = 0;
+	else
+		sm->mgmt_frame_prot = 1;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
+			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
+				   "MDIE not included");
+			return WPA_INVALID_MDIE;
+		}
+		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
+			      MOBILITY_DOMAIN_ID_LEN) != 0) {
+			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
+				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
+			return WPA_INVALID_MDIE;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (ciphers & WPA_CIPHER_CCMP)
+		sm->pairwise = WPA_CIPHER_CCMP;
+	else if (ciphers & WPA_CIPHER_GCMP)
+		sm->pairwise = WPA_CIPHER_GCMP;
+	else
+		sm->pairwise = WPA_CIPHER_TKIP;
+
+	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
+	if (wpa_ie[0] == WLAN_EID_RSN)
+		sm->wpa = WPA_VERSION_WPA2;
+	else
+		sm->wpa = WPA_VERSION_WPA;
+
+	sm->pmksa = NULL;
+	for (i = 0; i < data.num_pmkid; i++) {
+		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
+			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
+		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
+						 &data.pmkid[i * PMKID_LEN]);
+		if (sm->pmksa) {
+			pmkid = sm->pmksa->pmkid;
+			break;
+		}
+	}
+	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
+		     i < data.num_pmkid; i++) {
+		struct wpa_auth_okc_iter_data idata;
+		idata.pmksa = NULL;
+		idata.aa = wpa_auth->addr;
+		idata.spa = sm->addr;
+		idata.pmkid = &data.pmkid[i * PMKID_LEN];
+		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
+		if (idata.pmksa) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "OKC match for PMKID");
+			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
+							idata.pmksa,
+							wpa_auth->addr,
+							idata.pmkid);
+			pmkid = idata.pmkid;
+			break;
+		}
+	}
+	if (sm->pmksa) {
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				 "PMKID found from PMKSA cache "
+				 "eap_type=%d vlan_id=%d",
+				 sm->pmksa->eap_type_authsrv,
+				 sm->pmksa->vlan_id);
+		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
+	}
+
+	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
+		os_free(sm->wpa_ie);
+		sm->wpa_ie = os_malloc(wpa_ie_len);
+		if (sm->wpa_ie == NULL)
+			return WPA_ALLOC_FAIL;
+	}
+	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
+	sm->wpa_ie_len = wpa_ie_len;
+
+	return WPA_IE_OK;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		return 0;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < end &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
+		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
+		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
+		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
+		ie->error = pos + 2 + RSN_SELECTOR_LEN;
+		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	os_memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+					buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+#ifdef CONFIG_IEEE80211R
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+			ie->mdie = pos;
+			ie->mdie_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+			ie->ftie = pos;
+			ie->ftie_len = pos[1] + 2;
+#endif /* CONFIG_IEEE80211R */
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+				    "Key Data IE", pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}
+
+
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
+{
+	return sm ? sm->mgmt_frame_prot : 0;
+}

Deleted: vendor/wpa/2.0/src/ap/wpa_auth_ie.h
===================================================================
--- vendor/wpa/dist/src/ap/wpa_auth_ie.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ie.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,56 +0,0 @@
-/*
- * hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_AUTH_IE_H
-#define WPA_AUTH_IE_H
-
-struct wpa_eapol_ie_parse {
-	const u8 *wpa_ie;
-	size_t wpa_ie_len;
-	const u8 *rsn_ie;
-	size_t rsn_ie_len;
-	const u8 *pmkid;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *mac_addr;
-	size_t mac_addr_len;
-#ifdef CONFIG_PEERKEY
-	const u8 *smk;
-	size_t smk_len;
-	const u8 *nonce;
-	size_t nonce_len;
-	const u8 *lifetime;
-	size_t lifetime_len;
-	const u8 *error;
-	size_t error_len;
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211W
-	const u8 *igtk;
-	size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-#endif /* CONFIG_IEEE80211R */
-};
-
-int wpa_parse_kde_ies(const u8 *buf, size_t len,
-		      struct wpa_eapol_ie_parse *ie);
-u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
-		 const u8 *data2, size_t data2_len);
-int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
-
-#endif /* WPA_AUTH_IE_H */

Copied: vendor/wpa/2.0/src/ap/wpa_auth_ie.h (from rev 9639, vendor/wpa/dist/src/ap/wpa_auth_ie.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wpa_auth_ie.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wpa_auth_ie.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,50 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_IE_H
+#define WPA_AUTH_IE_H
+
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+	const u8 *smk;
+	size_t smk_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *lifetime;
+	size_t lifetime_len;
+	const u8 *error;
+	size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+	const u8 *igtk;
+	size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len,
+		      struct wpa_eapol_ie_parse *ie);
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+		 const u8 *data2, size_t data2_len);
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
+
+#endif /* WPA_AUTH_IE_H */

Deleted: vendor/wpa/2.0/src/ap/wps_hostapd.c
===================================================================
--- vendor/wpa/dist/src/ap/wps_hostapd.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wps_hostapd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1020 +0,0 @@
-/*
- * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/uuid.h"
-#include "crypto/dh_groups.h"
-#include "common/wpa_ctrl.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "eapol_auth/eapol_auth_sm.h"
-#include "eapol_auth/eapol_auth_sm_i.h"
-#include "wps/wps.h"
-#include "wps/wps_defs.h"
-#include "wps/wps_dev_attr.h"
-#include "hostapd.h"
-#include "ap_config.h"
-#include "beacon.h"
-#include "sta_info.h"
-#include "wps_hostapd.h"
-
-
-#ifdef CONFIG_WPS_UPNP
-#include "wps/wps_upnp.h"
-static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
-				 struct wps_context *wps);
-static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
-#endif /* CONFIG_WPS_UPNP */
-
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
-				    const u8 *ie, size_t ie_len);
-static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
-
-
-static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
-				  size_t psk_len)
-{
-	struct hostapd_data *hapd = ctx;
-	struct hostapd_wpa_psk *p;
-	struct hostapd_ssid *ssid = &hapd->conf->ssid;
-
-	wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
-		   MACSTR, MAC2STR(mac_addr));
-	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
-
-	if (psk_len != PMK_LEN) {
-		wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
-			   (unsigned long) psk_len);
-		return -1;
-	}
-
-	/* Add the new PSK to runtime PSK list */
-	p = os_zalloc(sizeof(*p));
-	if (p == NULL)
-		return -1;
-	os_memcpy(p->addr, mac_addr, ETH_ALEN);
-	os_memcpy(p->psk, psk, PMK_LEN);
-
-	p->next = ssid->wpa_psk;
-	ssid->wpa_psk = p;
-
-	if (ssid->wpa_psk_file) {
-		FILE *f;
-		char hex[PMK_LEN * 2 + 1];
-		/* Add the new PSK to PSK list file */
-		f = fopen(ssid->wpa_psk_file, "a");
-		if (f == NULL) {
-			wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
-				   "'%s'", ssid->wpa_psk_file);
-			return -1;
-		}
-
-		wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
-		fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
-		fclose(f);
-	}
-
-	return 0;
-}
-
-
-static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
-				 struct wpabuf *probe_resp_ie)
-{
-	struct hostapd_data *hapd = ctx;
-	wpabuf_free(hapd->wps_beacon_ie);
-	hapd->wps_beacon_ie = beacon_ie;
-	wpabuf_free(hapd->wps_probe_resp_ie);
-	hapd->wps_probe_resp_ie = probe_resp_ie;
-	ieee802_11_set_beacon(hapd);
-	return hapd->drv.set_ap_wps_ie(hapd);
-}
-
-
-static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
-				      const struct wps_device_data *dev)
-{
-	struct hostapd_data *hapd = ctx;
-	char uuid[40], txt[400];
-	int len;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
-		return;
-	wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
-	len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
-			  "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
-			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
-			  dev->manufacturer, dev->model_name,
-			  dev->model_number, dev->serial_number,
-			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
-					       sizeof(devtype)));
-	if (len > 0 && len < (int) sizeof(txt))
-		wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
-
-	if (hapd->conf->wps_pin_requests) {
-		FILE *f;
-		struct os_time t;
-		f = fopen(hapd->conf->wps_pin_requests, "a");
-		if (f == NULL)
-			return;
-		os_get_time(&t);
-		fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
-			"\t%s\n",
-			t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
-			dev->manufacturer, dev->model_name, dev->model_number,
-			dev->serial_number,
-			wps_dev_type_bin2str(dev->pri_dev_type, devtype,
-					     sizeof(devtype)));
-		fclose(f);
-	}
-}
-
-
-static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
-				       const u8 *uuid_e)
-{
-	struct hostapd_data *hapd = ctx;
-	char uuid[40];
-	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
-		return;
-	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
-		MAC2STR(mac_addr), uuid);
-	if (hapd->wps_reg_success_cb)
-		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
-					 mac_addr, uuid_e);
-}
-
-
-static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
-					 const u8 *uuid_e,
-					 const u8 *pri_dev_type,
-					 u16 config_methods,
-					 u16 dev_password_id, u8 request_type,
-					 const char *dev_name)
-{
-	struct hostapd_data *hapd = ctx;
-	char uuid[40];
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
-		return;
-	if (dev_name == NULL)
-		dev_name = "";
-	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
-		     " %s %s 0x%x %u %u [%s]",
-		     MAC2STR(addr), uuid,
-		     wps_dev_type_bin2str(pri_dev_type, devtype,
-					  sizeof(devtype)),
-		     config_methods, dev_password_id, request_type, dev_name);
-}
-
-
-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;
-
-	wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
-	if (iface->reload_config(iface) < 0) {
-		wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
-			   "configuration");
-	}
-}
-
-
-static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
-{
-	struct hostapd_data *hapd = ctx;
-	FILE *oconf, *nconf;
-	size_t len, i;
-	char *tmp_fname;
-	char buf[1024];
-	int multi_bss;
-	int wpa;
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
-			cred->cred_attr, cred->cred_attr_len);
-
-	wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
-	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
-		   cred->auth_type);
-	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
-	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
-			cred->key, cred->key_len);
-	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
-		   MAC2STR(cred->mac_addr));
-
-	if ((hapd->conf->wps_cred_processing == 1 ||
-	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
-		size_t blen = cred->cred_attr_len * 2 + 1;
-		char *_buf = os_malloc(blen);
-		if (_buf) {
-			wpa_snprintf_hex(_buf, blen,
-					 cred->cred_attr, cred->cred_attr_len);
-			wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
-				WPS_EVENT_NEW_AP_SETTINGS, _buf);
-			os_free(_buf);
-		}
-	} else
-		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
-
-	if (hapd->conf->wps_cred_processing == 1)
-		return 0;
-
-	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->auth_types = cred->auth_type;
-	if (cred->key_len == 0) {
-		os_free(hapd->wps->network_key);
-		hapd->wps->network_key = NULL;
-		hapd->wps->network_key_len = 0;
-	} else {
-		if (hapd->wps->network_key == NULL ||
-		    hapd->wps->network_key_len < cred->key_len) {
-			hapd->wps->network_key_len = 0;
-			os_free(hapd->wps->network_key);
-			hapd->wps->network_key = os_malloc(cred->key_len);
-			if (hapd->wps->network_key == NULL)
-				return -1;
-		}
-		hapd->wps->network_key_len = cred->key_len;
-		os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
-	}
-	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
-
-	len = os_strlen(hapd->iface->config_fname) + 5;
-	tmp_fname = os_malloc(len);
-	if (tmp_fname == NULL)
-		return -1;
-	os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
-
-	oconf = fopen(hapd->iface->config_fname, "r");
-	if (oconf == NULL) {
-		wpa_printf(MSG_WARNING, "WPS: Could not open current "
-			   "configuration file");
-		os_free(tmp_fname);
-		return -1;
-	}
-
-	nconf = fopen(tmp_fname, "w");
-	if (nconf == NULL) {
-		wpa_printf(MSG_WARNING, "WPS: Could not write updated "
-			   "configuration file");
-		os_free(tmp_fname);
-		fclose(oconf);
-		return -1;
-	}
-
-	fprintf(nconf, "# WPS configuration - START\n");
-
-	fprintf(nconf, "wps_state=2\n");
-
-	fprintf(nconf, "ssid=");
-	for (i = 0; i < cred->ssid_len; i++)
-		fputc(cred->ssid[i], nconf);
-	fprintf(nconf, "\n");
-
-	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
-	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
-		wpa = 3;
-	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
-		wpa = 2;
-	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
-		wpa = 1;
-	else
-		wpa = 0;
-
-	if (wpa) {
-		char *prefix;
-		fprintf(nconf, "wpa=%d\n", wpa);
-
-		fprintf(nconf, "wpa_key_mgmt=");
-		prefix = "";
-		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
-			fprintf(nconf, "WPA-EAP");
-			prefix = " ";
-		}
-		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
-			fprintf(nconf, "%sWPA-PSK", prefix);
-		fprintf(nconf, "\n");
-
-		fprintf(nconf, "wpa_pairwise=");
-		prefix = "";
-		if (cred->encr_type & WPS_ENCR_AES) {
-			fprintf(nconf, "CCMP");
-			prefix = " ";
-		}
-		if (cred->encr_type & WPS_ENCR_TKIP) {
-			fprintf(nconf, "%sTKIP", prefix);
-		}
-		fprintf(nconf, "\n");
-
-		if (cred->key_len >= 8 && cred->key_len < 64) {
-			fprintf(nconf, "wpa_passphrase=");
-			for (i = 0; i < cred->key_len; i++)
-				fputc(cred->key[i], nconf);
-			fprintf(nconf, "\n");
-		} else if (cred->key_len == 64) {
-			fprintf(nconf, "wpa_psk=");
-			for (i = 0; i < cred->key_len; i++)
-				fputc(cred->key[i], nconf);
-			fprintf(nconf, "\n");
-		} else {
-			wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
-				   "for WPA/WPA2",
-				   (unsigned long) cred->key_len);
-		}
-
-		fprintf(nconf, "auth_algs=1\n");
-	} else {
-		if ((cred->auth_type & WPS_AUTH_OPEN) &&
-		    (cred->auth_type & WPS_AUTH_SHARED))
-			fprintf(nconf, "auth_algs=3\n");
-		else if (cred->auth_type & WPS_AUTH_SHARED)
-			fprintf(nconf, "auth_algs=2\n");
-		else
-			fprintf(nconf, "auth_algs=1\n");
-
-		if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
-			int key_idx = cred->key_idx;
-			if (key_idx)
-				key_idx--;
-			fprintf(nconf, "wep_default_key=%d\n", key_idx);
-			fprintf(nconf, "wep_key%d=", key_idx);
-			if (cred->key_len == 10 || cred->key_len == 26) {
-				/* WEP key as a hex string */
-				for (i = 0; i < cred->key_len; i++)
-					fputc(cred->key[i], nconf);
-			} else {
-				/* Raw WEP key; convert to hex */
-				for (i = 0; i < cred->key_len; i++)
-					fprintf(nconf, "%02x", cred->key[i]);
-			}
-			fprintf(nconf, "\n");
-		}
-	}
-
-	fprintf(nconf, "# WPS configuration - END\n");
-
-	multi_bss = 0;
-	while (fgets(buf, sizeof(buf), oconf)) {
-		if (os_strncmp(buf, "bss=", 4) == 0)
-			multi_bss = 1;
-		if (!multi_bss &&
-		    (str_starts(buf, "ssid=") ||
-		     str_starts(buf, "auth_algs=") ||
-		     str_starts(buf, "wps_state=") ||
-		     str_starts(buf, "wpa=") ||
-		     str_starts(buf, "wpa_psk=") ||
-		     str_starts(buf, "wpa_pairwise=") ||
-		     str_starts(buf, "rsn_pairwise=") ||
-		     str_starts(buf, "wpa_key_mgmt=") ||
-		     str_starts(buf, "wpa_passphrase="))) {
-			fprintf(nconf, "#WPS# %s", buf);
-		} else
-			fprintf(nconf, "%s", buf);
-	}
-
-	fclose(nconf);
-	fclose(oconf);
-
-	if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
-		wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
-			   "configuration file: %s", strerror(errno));
-		os_free(tmp_fname);
-		return -1;
-	}
-
-	os_free(tmp_fname);
-
-	/* Schedule configuration reload after short period of time to allow
-	 * EAP-WSC to be finished.
-	 */
-	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
-			       NULL);
-
-	/* TODO: dualband AP may need to update multiple configuration files */
-
-	wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
-
-	return 0;
-}
-
-
-static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
-{
-	struct hostapd_data *hapd = eloop_data;
-
-	if (hapd->conf->ap_setup_locked)
-		return;
-
-	wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
-	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
-	hapd->wps->ap_setup_locked = 0;
-	wps_registrar_update_ie(hapd->wps->registrar);
-}
-
-
-static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
-				  struct wps_event_pwd_auth_fail *data)
-{
-	if (!data->enrollee || hapd->conf->ap_pin == NULL)
-		return;
-
-	/*
-	 * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
-	 * for some time if this happens multiple times to slow down brute
-	 * force attacks.
-	 */
-	hapd->ap_pin_failures++;
-	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
-		   hapd->ap_pin_failures);
-	if (hapd->ap_pin_failures < 3)
-		return;
-
-	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
-	hapd->wps->ap_setup_locked = 1;
-
-	wps_registrar_update_ie(hapd->wps->registrar);
-
-	if (!hapd->conf->ap_setup_locked) {
-		if (hapd->ap_pin_lockout_time == 0)
-			hapd->ap_pin_lockout_time = 60;
-		else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
-			 (hapd->ap_pin_failures % 3) == 0)
-			hapd->ap_pin_lockout_time *= 2;
-
-		wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
-			   hapd->ap_pin_lockout_time);
-		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
-		eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
-				       hostapd_wps_reenable_ap_pin, hapd,
-				       NULL);
-	}
-
-	/* TODO: dualband AP may need to update other interfaces */
-}
-
-
-static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
-				 union wps_event_data *data)
-{
-	struct hostapd_data *hapd = ctx;
-
-	if (event == WPS_EV_PWD_AUTH_FAIL)
-		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
-}
-
-
-static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
-{
-	wpabuf_free(hapd->wps_beacon_ie);
-	hapd->wps_beacon_ie = NULL;
-
-	wpabuf_free(hapd->wps_probe_resp_ie);
-	hapd->wps_probe_resp_ie = NULL;
-
-	hapd->drv.set_ap_wps_ie(hapd);
-}
-
-
-int hostapd_init_wps(struct hostapd_data *hapd,
-		     struct hostapd_bss_config *conf)
-{
-	struct wps_context *wps;
-	struct wps_registrar_config cfg;
-
-	if (conf->wps_state == 0) {
-		hostapd_wps_clear_ies(hapd);
-		return 0;
-	}
-
-	wps = os_zalloc(sizeof(*wps));
-	if (wps == NULL)
-		return -1;
-
-	wps->cred_cb = hostapd_wps_cred_cb;
-	wps->event_cb = hostapd_wps_event_cb;
-	wps->cb_ctx = hapd;
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	wps->wps_state = hapd->conf->wps_state;
-	wps->ap_setup_locked = hapd->conf->ap_setup_locked;
-	if (is_nil_uuid(hapd->conf->uuid)) {
-		uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
-		wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
-			    wps->uuid, UUID_LEN);
-	} else
-		os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
-	wps->ssid_len = hapd->conf->ssid.ssid_len;
-	os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
-	wps->ap = 1;
-	os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
-	wps->dev.device_name = hapd->conf->device_name ?
-		os_strdup(hapd->conf->device_name) : NULL;
-	wps->dev.manufacturer = hapd->conf->manufacturer ?
-		os_strdup(hapd->conf->manufacturer) : NULL;
-	wps->dev.model_name = hapd->conf->model_name ?
-		os_strdup(hapd->conf->model_name) : NULL;
-	wps->dev.model_number = hapd->conf->model_number ?
-		os_strdup(hapd->conf->model_number) : NULL;
-	wps->dev.serial_number = hapd->conf->serial_number ?
-		os_strdup(hapd->conf->serial_number) : NULL;
-	wps->config_methods =
-		wps_config_methods_str2bin(hapd->conf->config_methods);
-	if (hapd->conf->device_type &&
-	    wps_dev_type_str2bin(hapd->conf->device_type,
-				 wps->dev.pri_dev_type) < 0) {
-		wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
-		os_free(wps);
-		return -1;
-	}
-	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
-	wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-		WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
-
-	if (conf->wpa & WPA_PROTO_RSN) {
-		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
-			wps->auth_types |= WPS_AUTH_WPA2PSK;
-		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-			wps->auth_types |= WPS_AUTH_WPA2;
-
-		if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
-			wps->encr_types |= WPS_ENCR_AES;
-		if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
-			wps->encr_types |= WPS_ENCR_TKIP;
-	}
-
-	if (conf->wpa & WPA_PROTO_WPA) {
-		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
-			wps->auth_types |= WPS_AUTH_WPAPSK;
-		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-			wps->auth_types |= WPS_AUTH_WPA;
-
-		if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
-			wps->encr_types |= WPS_ENCR_AES;
-		if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
-			wps->encr_types |= WPS_ENCR_TKIP;
-	}
-
-	if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
-		wps->encr_types |= WPS_ENCR_NONE;
-		wps->auth_types |= WPS_AUTH_OPEN;
-	} else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
-		wps->encr_types |= WPS_ENCR_WEP;
-		if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
-			wps->auth_types |= WPS_AUTH_OPEN;
-		if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
-			wps->auth_types |= WPS_AUTH_SHARED;
-	} else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
-		wps->auth_types |= WPS_AUTH_OPEN;
-		if (conf->default_wep_key_len)
-			wps->encr_types |= WPS_ENCR_WEP;
-		else
-			wps->encr_types |= WPS_ENCR_NONE;
-	}
-
-	if (conf->ssid.wpa_psk_file) {
-		/* Use per-device PSKs */
-	} else if (conf->ssid.wpa_passphrase) {
-		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
-		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
-	} else if (conf->ssid.wpa_psk) {
-		wps->network_key = os_malloc(2 * PMK_LEN + 1);
-		if (wps->network_key == NULL) {
-			os_free(wps);
-			return -1;
-		}
-		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
-				 conf->ssid.wpa_psk->psk, PMK_LEN);
-		wps->network_key_len = 2 * PMK_LEN;
-	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
-		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
-		if (wps->network_key == NULL) {
-			os_free(wps);
-			return -1;
-		}
-		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
-			  conf->ssid.wep.len[0]);
-		wps->network_key_len = conf->ssid.wep.len[0];
-	}
-
-	if (conf->ssid.wpa_psk) {
-		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
-		wps->psk_set = 1;
-	}
-
-	if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
-		/* 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->ap_settings = conf->ap_settings;
-	wps->ap_settings_len = conf->ap_settings_len;
-
-	cfg.new_psk_cb = hostapd_wps_new_psk_cb;
-	cfg.set_ie_cb = hostapd_wps_set_ie_cb;
-	cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
-	cfg.reg_success_cb = hostapd_wps_reg_success_cb;
-	cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
-	cfg.cb_ctx = hapd;
-	cfg.skip_cred_build = conf->skip_cred_build;
-	cfg.extra_cred = conf->extra_cred;
-	cfg.extra_cred_len = conf->extra_cred_len;
-	cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
-		conf->skip_cred_build;
-	if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
-		cfg.static_wep_only = 1;
-
-	wps->registrar = wps_registrar_init(wps, &cfg);
-	if (wps->registrar == NULL) {
-		printf("Failed to initialize WPS Registrar\n");
-		os_free(wps->network_key);
-		os_free(wps);
-		return -1;
-	}
-
-#ifdef CONFIG_WPS_UPNP
-	wps->friendly_name = hapd->conf->friendly_name;
-	wps->manufacturer_url = hapd->conf->manufacturer_url;
-	wps->model_description = hapd->conf->model_description;
-	wps->model_url = hapd->conf->model_url;
-	wps->upc = hapd->conf->upc;
-
-	if (hostapd_wps_upnp_init(hapd, wps) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
-		wps_registrar_deinit(wps->registrar);
-		os_free(wps->network_key);
-		os_free(wps);
-		return -1;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
-
-	hapd->wps = wps;
-
-	return 0;
-}
-
-
-void hostapd_deinit_wps(struct hostapd_data *hapd)
-{
-	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
-	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
-	if (hapd->wps == NULL)
-		return;
-#ifdef CONFIG_WPS_UPNP
-	hostapd_wps_upnp_deinit(hapd);
-#endif /* CONFIG_WPS_UPNP */
-	wps_registrar_deinit(hapd->wps->registrar);
-	os_free(hapd->wps->network_key);
-	wps_device_data_free(&hapd->wps->dev);
-	wpabuf_free(hapd->wps->dh_pubkey);
-	wpabuf_free(hapd->wps->dh_privkey);
-	wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
-	wpabuf_free(hapd->wps->oob_conf.dev_password);
-	wps_free_pending_msgs(hapd->wps->upnp_msgs);
-	os_free(hapd->wps);
-	hapd->wps = NULL;
-	hostapd_wps_clear_ies(hapd);
-}
-
-
-void hostapd_update_wps(struct hostapd_data *hapd)
-{
-	if (hapd->wps == NULL)
-		return;
-	if (hapd->conf->wps_state)
-		wps_registrar_update_ie(hapd->wps->registrar);
-	else
-		hostapd_deinit_wps(hapd);
-}
-
-
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-			const char *pin, int timeout)
-{
-	u8 u[UUID_LEN];
-	int any = 0;
-
-	if (hapd->wps == NULL)
-		return -1;
-	if (os_strcmp(uuid, "any") == 0)
-		any = 1;
-	else if (uuid_str2bin(uuid, u))
-		return -1;
-	return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
-				     (const u8 *) pin, os_strlen(pin),
-				     timeout);
-}
-
-
-int hostapd_wps_button_pushed(struct hostapd_data *hapd)
-{
-	if (hapd->wps == NULL)
-		return -1;
-	return wps_registrar_button_pushed(hapd->wps->registrar);
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
-			  char *path, char *method, char *name)
-{
-	struct wps_context *wps = hapd->wps;
-	struct oob_device_data *oob_dev;
-
-	oob_dev = wps_get_oob_device(device_type);
-	if (oob_dev == NULL)
-		return -1;
-	oob_dev->device_path = path;
-	oob_dev->device_name = name;
-	wps->oob_conf.oob_method = wps_get_oob_method(method);
-
-	if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) {
-		/*
-		 * Use pre-configured DH keys in order to be able to write the
-		 * key hash into the OOB file.
-		 */
-		wpabuf_free(wps->dh_pubkey);
-		wpabuf_free(wps->dh_privkey);
-		wps->dh_privkey = NULL;
-		wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
-					 &wps->dh_privkey);
-		wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-		if (wps->dh_pubkey == NULL) {
-			wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
-				   "Diffie-Hellman handshake");
-			return -1;
-		}
-	}
-
-	if (wps_process_oob(wps, oob_dev, 1) < 0)
-		goto error;
-
-	if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
-	     wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-	    hostapd_wps_add_pin(hapd, "any",
-				wpabuf_head(wps->oob_conf.dev_password), 0) <
-	    0)
-		goto error;
-
-	return 0;
-
-error:
-	wpabuf_free(wps->dh_pubkey);
-	wps->dh_pubkey = NULL;
-	wpabuf_free(wps->dh_privkey);
-	wps->dh_privkey = NULL;
-	return -1;
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
-				    const u8 *ie, size_t ie_len)
-{
-	struct hostapd_data *hapd = ctx;
-	struct wpabuf *wps_ie;
-	struct ieee802_11_elems elems;
-
-	if (hapd->wps == NULL)
-		return 0;
-
-	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
-			   MACSTR, MAC2STR(addr));
-		return 0;
-	}
-
-	if (elems.ssid && elems.ssid_len > 0 &&
-	    (elems.ssid_len != hapd->conf->ssid.ssid_len ||
-	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
-	     0))
-		return 0; /* Not for us */
-
-	wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
-	if (wps_ie == NULL)
-		return 0;
-
-	if (wpabuf_len(wps_ie) > 0) {
-		wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
-#ifdef CONFIG_WPS_UPNP
-		/* FIX: what exactly should be included in the WLANEvent?
-		 * WPS attributes? Full ProbeReq frame? */
-		upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
-						UPNP_WPS_WLANEVENT_TYPE_PROBE,
-						wps_ie);
-#endif /* CONFIG_WPS_UPNP */
-	}
-
-	wpabuf_free(wps_ie);
-
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS_UPNP
-
-static int hostapd_rx_req_put_wlan_response(
-	void *priv, enum upnp_wps_wlanevent_type ev_type,
-	const u8 *mac_addr, const struct wpabuf *msg,
-	enum wps_msg_type msg_type)
-{
-	struct hostapd_data *hapd = priv;
-	struct sta_info *sta;
-	struct upnp_pending_message *p;
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
-		   MACSTR, ev_type, MAC2STR(mac_addr));
-	wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
-		    wpabuf_head(msg), wpabuf_len(msg));
-	if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
-			   "PutWLANResponse WLANEventType %d", ev_type);
-		return -1;
-	}
-
-	/*
-	 * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
-	 * server implementation for delivery to the peer.
-	 */
-
-	sta = ap_get_sta(hapd, mac_addr);
-	if (!sta) {
-		/*
-		 * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
-		 * Pick STA that is in an ongoing WPS registration without
-		 * checking the MAC address.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
-			   "on NewWLANEventMAC; try wildcard match");
-		for (sta = hapd->sta_list; sta; sta = sta->next) {
-			if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
-				break;
-		}
-	}
-
-	if (!sta) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
-		return 0;
-	}
-
-	p = os_zalloc(sizeof(*p));
-	if (p == NULL)
-		return -1;
-	os_memcpy(p->addr, sta->addr, ETH_ALEN);
-	p->msg = wpabuf_dup(msg);
-	p->type = msg_type;
-	p->next = hapd->wps->upnp_msgs;
-	hapd->wps->upnp_msgs = p;
-
-	return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
-}
-
-
-static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
-				 struct wps_context *wps)
-{
-	struct upnp_wps_device_ctx *ctx;
-
-	if (!hapd->conf->upnp_iface)
-		return 0;
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return -1;
-
-	ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
-	if (hapd->conf->ap_pin)
-		ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
-
-	hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd);
-	if (hapd->wps_upnp == NULL) {
-		os_free(ctx);
-		return -1;
-	}
-	wps->wps_upnp = hapd->wps_upnp;
-
-	if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
-		upnp_wps_device_deinit(hapd->wps_upnp);
-		hapd->wps_upnp = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
-{
-	upnp_wps_device_deinit(hapd->wps_upnp);
-}
-
-#endif /* CONFIG_WPS_UPNP */
-
-
-int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
-			    char *buf, size_t buflen)
-{
-	if (hapd->wps == NULL)
-		return 0;
-	return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
-}
-
-
-static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
-{
-	struct hostapd_data *hapd = eloop_data;
-	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
-	hostapd_wps_ap_pin_disable(hapd);
-}
-
-
-static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
-	hapd->ap_pin_failures = 0;
-	hapd->conf->ap_setup_locked = 0;
-	if (hapd->wps->ap_setup_locked) {
-		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
-		hapd->wps->ap_setup_locked = 0;
-		wps_registrar_update_ie(hapd->wps->registrar);
-	}
-	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
-	if (timeout > 0)
-		eloop_register_timeout(timeout, 0,
-				       hostapd_wps_ap_pin_timeout, hapd, NULL);
-}
-
-
-void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
-	os_free(hapd->conf->ap_pin);
-	hapd->conf->ap_pin = NULL;
-#ifdef CONFIG_WPS_UPNP
-	upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
-#endif /* CONFIG_WPS_UPNP */
-	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
-}
-
-
-const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
-{
-	unsigned int pin;
-	char pin_txt[9];
-
-	pin = wps_generate_pin();
-	os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
-	os_free(hapd->conf->ap_pin);
-	hapd->conf->ap_pin = os_strdup(pin_txt);
-#ifdef CONFIG_WPS_UPNP
-	upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
-#endif /* CONFIG_WPS_UPNP */
-	hostapd_wps_ap_pin_enable(hapd, timeout);
-	return hapd->conf->ap_pin;
-}
-
-
-const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
-{
-	return hapd->conf->ap_pin;
-}
-
-
-int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
-			   int timeout)
-{
-	os_free(hapd->conf->ap_pin);
-	hapd->conf->ap_pin = os_strdup(pin);
-	if (hapd->conf->ap_pin == NULL)
-		return -1;
-#ifdef CONFIG_WPS_UPNP
-	upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
-#endif /* CONFIG_WPS_UPNP */
-	hostapd_wps_ap_pin_enable(hapd, timeout);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/ap/wps_hostapd.c (from rev 9639, vendor/wpa/dist/src/ap/wps_hostapd.c)
===================================================================
--- vendor/wpa/2.0/src/ap/wps_hostapd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wps_hostapd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1629 @@
+/*
+ * hostapd / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+#include "wps/wps_dev_attr.h"
+#include "wps/wps_attr_parse.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "sta_info.h"
+#include "wps_hostapd.h"
+
+
+#ifdef CONFIG_WPS_UPNP
+#include "wps/wps_upnp.h"
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+				 struct wps_context *wps);
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
+#endif /* CONFIG_WPS_UPNP */
+
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
+				    const u8 *ie, size_t ie_len,
+				    int ssi_signal);
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+
+
+struct wps_for_each_data {
+	int (*func)(struct hostapd_data *h, void *ctx);
+	void *ctx;
+};
+
+
+static int wps_for_each(struct hostapd_iface *iface, void *ctx)
+{
+	struct wps_for_each_data *data = ctx;
+	size_t j;
+
+	if (iface == NULL)
+		return 0;
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		int ret = data->func(hapd, data->ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_wps_for_each(struct hostapd_data *hapd,
+				int (*func)(struct hostapd_data *h, void *ctx),
+				void *ctx)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct wps_for_each_data data;
+	data.func = func;
+	data.ctx = ctx;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return wps_for_each(iface, &data);
+	return iface->interfaces->for_each_interface(iface->interfaces,
+						     wps_for_each, &data);
+}
+
+
+static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+				  size_t psk_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct hostapd_wpa_psk *p;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+	wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
+		   MACSTR, MAC2STR(mac_addr));
+	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+	if (psk_len != PMK_LEN) {
+		wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
+			   (unsigned long) psk_len);
+		return -1;
+	}
+
+	/* Add the new PSK to runtime PSK list */
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	os_memcpy(p->addr, mac_addr, ETH_ALEN);
+	os_memcpy(p->psk, psk, PMK_LEN);
+
+	p->next = ssid->wpa_psk;
+	ssid->wpa_psk = p;
+
+	if (ssid->wpa_psk_file) {
+		FILE *f;
+		char hex[PMK_LEN * 2 + 1];
+		/* Add the new PSK to PSK list file */
+		f = fopen(ssid->wpa_psk_file, "a");
+		if (f == NULL) {
+			wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
+				   "'%s'", ssid->wpa_psk_file);
+			return -1;
+		}
+
+		wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
+		fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+		fclose(f);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
+				 struct wpabuf *probe_resp_ie)
+{
+	struct hostapd_data *hapd = ctx;
+	wpabuf_free(hapd->wps_beacon_ie);
+	hapd->wps_beacon_ie = beacon_ie;
+	wpabuf_free(hapd->wps_probe_resp_ie);
+	hapd->wps_probe_resp_ie = probe_resp_ie;
+	if (hapd->beacon_set_done)
+		ieee802_11_set_beacon(hapd);
+	return hostapd_set_ap_wps_ie(hapd);
+}
+
+
+static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+				      const struct wps_device_data *dev)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40], txt[400];
+	int len;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
+	len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
+			  "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
+			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			  dev->manufacturer, dev->model_name,
+			  dev->model_number, dev->serial_number,
+			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					       sizeof(devtype)));
+	if (len > 0 && len < (int) sizeof(txt))
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
+
+	if (hapd->conf->wps_pin_requests) {
+		FILE *f;
+		struct os_time t;
+		f = fopen(hapd->conf->wps_pin_requests, "a");
+		if (f == NULL)
+			return;
+		os_get_time(&t);
+		fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
+			"\t%s\n",
+			t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			dev->manufacturer, dev->model_name, dev->model_number,
+			dev->serial_number,
+			wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					     sizeof(devtype)));
+		fclose(f);
+	}
+}
+
+
+struct wps_stop_reg_data {
+	struct hostapd_data *current_hapd;
+	const u8 *uuid_e;
+	const u8 *dev_pw;
+	size_t dev_pw_len;
+};
+
+static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_stop_reg_data *data = ctx;
+	if (hapd != data->current_hapd && hapd->wps != NULL)
+		wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
+				       data->dev_pw, data->dev_pw_len);
+	return 0;
+}
+
+
+static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
+				       const u8 *uuid_e, const u8 *dev_pw,
+				       size_t dev_pw_len)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40];
+	struct wps_stop_reg_data data;
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
+		MAC2STR(mac_addr), uuid);
+	if (hapd->wps_reg_success_cb)
+		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
+					 mac_addr, uuid_e);
+	data.current_hapd = hapd;
+	data.uuid_e = uuid_e;
+	data.dev_pw = dev_pw;
+	data.dev_pw_len = dev_pw_len;
+	hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
+}
+
+
+static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
+					 const u8 *uuid_e,
+					 const u8 *pri_dev_type,
+					 u16 config_methods,
+					 u16 dev_password_id, u8 request_type,
+					 const char *dev_name)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40];
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	if (dev_name == NULL)
+		dev_name = "";
+	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
+		     " %s %s 0x%x %u %u [%s]",
+		     MAC2STR(addr), uuid,
+		     wps_dev_type_bin2str(pri_dev_type, devtype,
+					  sizeof(devtype)),
+		     config_methods, dev_password_id, request_type, dev_name);
+}
+
+
+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;
+
+	wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->reload_config(iface) < 0) {
+		wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
+			   "configuration");
+	}
+}
+
+
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+			      size_t attr_len)
+{
+	size_t blen = attr_len * 2 + 1;
+	char *buf = os_malloc(blen);
+	if (buf) {
+		wpa_snprintf_hex(buf, blen, attr, attr_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+		os_free(buf);
+	}
+}
+
+
+static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
+{
+	const struct wps_credential *cred = ctx;
+	FILE *oconf, *nconf;
+	size_t len, i;
+	char *tmp_fname;
+	char buf[1024];
+	int multi_bss;
+	int wpa;
+
+	if (hapd->wps == NULL)
+		return 0;
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+			cred->cred_attr, cred->cred_attr_len);
+
+	wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
+		   cred->auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+			cred->key, cred->key_len);
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
+		   MAC2STR(cred->mac_addr));
+
+	if ((hapd->conf->wps_cred_processing == 1 ||
+	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
+		hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+	} else if (hapd->conf->wps_cred_processing == 1 ||
+		   hapd->conf->wps_cred_processing == 2) {
+		struct wpabuf *attr;
+		attr = wpabuf_alloc(200);
+		if (attr && wps_build_credential_wrap(attr, cred) == 0)
+			hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+					  wpabuf_len(attr));
+		wpabuf_free(attr);
+	} else
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
+
+	if (hapd->conf->wps_cred_processing == 1)
+		return 0;
+
+	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->auth_types = cred->auth_type;
+	if (cred->key_len == 0) {
+		os_free(hapd->wps->network_key);
+		hapd->wps->network_key = NULL;
+		hapd->wps->network_key_len = 0;
+	} else {
+		if (hapd->wps->network_key == NULL ||
+		    hapd->wps->network_key_len < cred->key_len) {
+			hapd->wps->network_key_len = 0;
+			os_free(hapd->wps->network_key);
+			hapd->wps->network_key = os_malloc(cred->key_len);
+			if (hapd->wps->network_key == NULL)
+				return -1;
+		}
+		hapd->wps->network_key_len = cred->key_len;
+		os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
+	}
+	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
+
+	if (hapd->iface->config_fname == NULL)
+		return 0;
+	len = os_strlen(hapd->iface->config_fname) + 5;
+	tmp_fname = os_malloc(len);
+	if (tmp_fname == NULL)
+		return -1;
+	os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
+
+	oconf = fopen(hapd->iface->config_fname, "r");
+	if (oconf == NULL) {
+		wpa_printf(MSG_WARNING, "WPS: Could not open current "
+			   "configuration file");
+		os_free(tmp_fname);
+		return -1;
+	}
+
+	nconf = fopen(tmp_fname, "w");
+	if (nconf == NULL) {
+		wpa_printf(MSG_WARNING, "WPS: Could not write updated "
+			   "configuration file");
+		os_free(tmp_fname);
+		fclose(oconf);
+		return -1;
+	}
+
+	fprintf(nconf, "# WPS configuration - START\n");
+
+	fprintf(nconf, "wps_state=2\n");
+
+	if (is_hex(cred->ssid, cred->ssid_len)) {
+		fprintf(nconf, "ssid2=");
+		for (i = 0; i < cred->ssid_len; i++)
+			fprintf(nconf, "%02x", cred->ssid[i]);
+		fprintf(nconf, "\n");
+	} else {
+		fprintf(nconf, "ssid=");
+		for (i = 0; i < cred->ssid_len; i++)
+			fputc(cred->ssid[i], nconf);
+		fprintf(nconf, "\n");
+	}
+
+	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+		wpa = 3;
+	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+		wpa = 2;
+	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+		wpa = 1;
+	else
+		wpa = 0;
+
+	if (wpa) {
+		char *prefix;
+		fprintf(nconf, "wpa=%d\n", wpa);
+
+		fprintf(nconf, "wpa_key_mgmt=");
+		prefix = "";
+		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
+			fprintf(nconf, "WPA-EAP");
+			prefix = " ";
+		}
+		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+			fprintf(nconf, "%sWPA-PSK", prefix);
+		fprintf(nconf, "\n");
+
+		fprintf(nconf, "wpa_pairwise=");
+		prefix = "";
+		if (cred->encr_type & WPS_ENCR_AES) {
+			fprintf(nconf, "CCMP");
+			prefix = " ";
+		}
+		if (cred->encr_type & WPS_ENCR_TKIP) {
+			fprintf(nconf, "%sTKIP", prefix);
+		}
+		fprintf(nconf, "\n");
+
+		if (cred->key_len >= 8 && cred->key_len < 64) {
+			fprintf(nconf, "wpa_passphrase=");
+			for (i = 0; i < cred->key_len; i++)
+				fputc(cred->key[i], nconf);
+			fprintf(nconf, "\n");
+		} else if (cred->key_len == 64) {
+			fprintf(nconf, "wpa_psk=");
+			for (i = 0; i < cred->key_len; i++)
+				fputc(cred->key[i], nconf);
+			fprintf(nconf, "\n");
+		} else {
+			wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
+				   "for WPA/WPA2",
+				   (unsigned long) cred->key_len);
+		}
+
+		fprintf(nconf, "auth_algs=1\n");
+	} else {
+		if ((cred->auth_type & WPS_AUTH_OPEN) &&
+		    (cred->auth_type & WPS_AUTH_SHARED))
+			fprintf(nconf, "auth_algs=3\n");
+		else if (cred->auth_type & WPS_AUTH_SHARED)
+			fprintf(nconf, "auth_algs=2\n");
+		else
+			fprintf(nconf, "auth_algs=1\n");
+
+		if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
+			int key_idx = cred->key_idx;
+			if (key_idx)
+				key_idx--;
+			fprintf(nconf, "wep_default_key=%d\n", key_idx);
+			fprintf(nconf, "wep_key%d=", key_idx);
+			if (cred->key_len == 10 || cred->key_len == 26) {
+				/* WEP key as a hex string */
+				for (i = 0; i < cred->key_len; i++)
+					fputc(cred->key[i], nconf);
+			} else {
+				/* Raw WEP key; convert to hex */
+				for (i = 0; i < cred->key_len; i++)
+					fprintf(nconf, "%02x", cred->key[i]);
+			}
+			fprintf(nconf, "\n");
+		}
+	}
+
+	fprintf(nconf, "# WPS configuration - END\n");
+
+	multi_bss = 0;
+	while (fgets(buf, sizeof(buf), oconf)) {
+		if (os_strncmp(buf, "bss=", 4) == 0)
+			multi_bss = 1;
+		if (!multi_bss &&
+		    (str_starts(buf, "ssid=") ||
+		     str_starts(buf, "ssid2=") ||
+		     str_starts(buf, "auth_algs=") ||
+		     str_starts(buf, "wep_default_key=") ||
+		     str_starts(buf, "wep_key") ||
+		     str_starts(buf, "wps_state=") ||
+		     str_starts(buf, "wpa=") ||
+		     str_starts(buf, "wpa_psk=") ||
+		     str_starts(buf, "wpa_pairwise=") ||
+		     str_starts(buf, "rsn_pairwise=") ||
+		     str_starts(buf, "wpa_key_mgmt=") ||
+		     str_starts(buf, "wpa_passphrase="))) {
+			fprintf(nconf, "#WPS# %s", buf);
+		} else
+			fprintf(nconf, "%s", buf);
+	}
+
+	fclose(nconf);
+	fclose(oconf);
+
+	if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
+		wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
+			   "configuration file: %s", strerror(errno));
+		os_free(tmp_fname);
+		return -1;
+	}
+
+	os_free(tmp_fname);
+
+	/* Schedule configuration reload after short period of time to allow
+	 * EAP-WSC to be finished.
+	 */
+	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+			       NULL);
+
+	wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+
+	return 0;
+}
+
+
+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
+}
+
+
+static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_data *hapd = eloop_data;
+
+	if (hapd->conf->ap_setup_locked)
+		return;
+	if (hapd->ap_pin_failures_consecutive >= 10)
+		return;
+
+	wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+	hapd->wps->ap_setup_locked = 0;
+	wps_registrar_update_ie(hapd->wps->registrar);
+}
+
+
+static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_event_pwd_auth_fail *data = ctx;
+
+	if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+		return 0;
+
+	/*
+	 * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
+	 * for some time if this happens multiple times to slow down brute
+	 * force attacks.
+	 */
+	hapd->ap_pin_failures++;
+	hapd->ap_pin_failures_consecutive++;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u "
+		   "(%u consecutive)",
+		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
+	if (hapd->ap_pin_failures < 3)
+		return 0;
+
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
+	hapd->wps->ap_setup_locked = 1;
+
+	wps_registrar_update_ie(hapd->wps->registrar);
+
+	if (!hapd->conf->ap_setup_locked &&
+	    hapd->ap_pin_failures_consecutive >= 10) {
+		/*
+		 * In indefinite lockdown - disable automatic AP PIN
+		 * reenablement.
+		 */
+		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+		wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely");
+	} else if (!hapd->conf->ap_setup_locked) {
+		if (hapd->ap_pin_lockout_time == 0)
+			hapd->ap_pin_lockout_time = 60;
+		else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
+			 (hapd->ap_pin_failures % 3) == 0)
+			hapd->ap_pin_lockout_time *= 2;
+
+		wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
+			   hapd->ap_pin_lockout_time);
+		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+		eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
+				       hostapd_wps_reenable_ap_pin, hapd,
+				       NULL);
+	}
+
+	return 0;
+}
+
+
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+				  struct wps_event_pwd_auth_fail *data)
+{
+	hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
+}
+
+
+static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+		return 0;
+
+	if (hapd->ap_pin_failures_consecutive == 0)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter "
+		   "- total validation failures %u (%u consecutive)",
+		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
+	hapd->ap_pin_failures_consecutive = 0;
+
+	return 0;
+}
+
+
+static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
+{
+	hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL);
+}
+
+
+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
+	"No Error", /* WPS_EI_NO_ERROR */
+	"TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
+	"WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
+};
+
+static void hostapd_wps_event_fail(struct hostapd_data *hapd,
+				   struct wps_event_fail *fail)
+{
+	if (fail->error_indication > 0 &&
+	    fail->error_indication < NUM_WPS_EI_VALUES) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
+			fail->msg, fail->config_error, fail->error_indication,
+			wps_event_fail_reason[fail->error_indication]);
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_FAIL "msg=%d config_error=%d",
+			fail->msg, fail->config_error);
+	}
+}
+
+
+static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
+				 union wps_event_data *data)
+{
+	struct hostapd_data *hapd = ctx;
+
+	switch (event) {
+	case WPS_EV_M2D:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
+		break;
+	case WPS_EV_FAIL:
+		hostapd_wps_event_fail(hapd, &data->fail);
+		break;
+	case WPS_EV_SUCCESS:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
+		break;
+	case WPS_EV_PWD_AUTH_FAIL:
+		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+		break;
+	case WPS_EV_PBC_OVERLAP:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
+		break;
+	case WPS_EV_PBC_TIMEOUT:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
+		break;
+	case WPS_EV_ER_AP_ADD:
+		break;
+	case WPS_EV_ER_AP_REMOVE:
+		break;
+	case WPS_EV_ER_ENROLLEE_ADD:
+		break;
+	case WPS_EV_ER_ENROLLEE_REMOVE:
+		break;
+	case WPS_EV_ER_AP_SETTINGS:
+		break;
+	case WPS_EV_ER_SET_SELECTED_REGISTRAR:
+		break;
+	case WPS_EV_AP_PIN_SUCCESS:
+		hostapd_wps_ap_pin_success(hapd);
+		break;
+	}
+	if (hapd->wps_event_cb)
+		hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
+}
+
+
+static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
+{
+	wpabuf_free(hapd->wps_beacon_ie);
+	hapd->wps_beacon_ie = NULL;
+
+	wpabuf_free(hapd->wps_probe_resp_ie);
+	hapd->wps_probe_resp_ie = NULL;
+
+	hostapd_set_ap_wps_ie(hapd);
+}
+
+
+static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
+{
+	const u8 **uuid = ctx;
+	size_t j;
+
+	if (iface == NULL)
+		return 0;
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+			*uuid = hapd->wps->uuid;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static const u8 * get_own_uuid(struct hostapd_iface *iface)
+{
+	const u8 *uuid;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return NULL;
+	uuid = NULL;
+	iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
+					      &uuid);
+	return uuid;
+}
+
+
+static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
+{
+	int *count= ctx;
+	(*count)++;
+	return 0;
+}
+
+
+static int interface_count(struct hostapd_iface *iface)
+{
+	int count = 0;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return 0;
+	iface->interfaces->for_each_interface(iface->interfaces,
+					      count_interface_cb, &count);
+	return count;
+}
+
+
+static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
+				      struct wps_context *wps)
+{
+	int i;
+
+	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+		wpabuf_free(wps->dev.vendor_ext[i]);
+		wps->dev.vendor_ext[i] = NULL;
+
+		if (hapd->conf->wps_vendor_ext[i] == NULL)
+			continue;
+
+		wps->dev.vendor_ext[i] =
+			wpabuf_dup(hapd->conf->wps_vendor_ext[i]);
+		if (wps->dev.vendor_ext[i] == NULL) {
+			while (--i >= 0)
+				wpabuf_free(wps->dev.vendor_ext[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+		     struct hostapd_bss_config *conf)
+{
+	struct wps_context *wps;
+	struct wps_registrar_config cfg;
+
+	if (conf->wps_state == 0) {
+		hostapd_wps_clear_ies(hapd);
+		return 0;
+	}
+
+	wps = os_zalloc(sizeof(*wps));
+	if (wps == NULL)
+		return -1;
+
+	wps->cred_cb = hostapd_wps_cred_cb;
+	wps->event_cb = hostapd_wps_event_cb;
+	wps->cb_ctx = hapd;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	wps->wps_state = hapd->conf->wps_state;
+	wps->ap_setup_locked = hapd->conf->ap_setup_locked;
+	if (is_nil_uuid(hapd->conf->uuid)) {
+		const u8 *uuid;
+		uuid = get_own_uuid(hapd->iface);
+		if (uuid) {
+			os_memcpy(wps->uuid, uuid, UUID_LEN);
+			wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
+				    "interface", wps->uuid, UUID_LEN);
+		} else {
+			uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
+			wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+				    "address", wps->uuid, UUID_LEN);
+		}
+	} else {
+		os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
+			    wps->uuid, UUID_LEN);
+	}
+	wps->ssid_len = hapd->conf->ssid.ssid_len;
+	os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
+	wps->ap = 1;
+	os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
+	wps->dev.device_name = hapd->conf->device_name ?
+		os_strdup(hapd->conf->device_name) : NULL;
+	wps->dev.manufacturer = hapd->conf->manufacturer ?
+		os_strdup(hapd->conf->manufacturer) : NULL;
+	wps->dev.model_name = hapd->conf->model_name ?
+		os_strdup(hapd->conf->model_name) : NULL;
+	wps->dev.model_number = hapd->conf->model_number ?
+		os_strdup(hapd->conf->model_number) : NULL;
+	wps->dev.serial_number = hapd->conf->serial_number ?
+		os_strdup(hapd->conf->serial_number) : NULL;
+	wps->config_methods =
+		wps_config_methods_str2bin(hapd->conf->config_methods);
+#ifdef CONFIG_WPS2
+	if ((wps->config_methods &
+	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
+	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
+		wpa_printf(MSG_INFO, "WPS: Converting display to "
+			   "virtual_display for WPS 2.0 compliance");
+		wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY;
+	}
+	if ((wps->config_methods &
+	     (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
+	      WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
+		wpa_printf(MSG_INFO, "WPS: Converting push_button to "
+			   "virtual_push_button for WPS 2.0 compliance");
+		wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+	}
+#endif /* CONFIG_WPS2 */
+	os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
+		  WPS_DEV_TYPE_LEN);
+
+	if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
+		os_free(wps);
+		return -1;
+	}
+
+	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
+
+	if (conf->wps_rf_bands) {
+		wps->dev.rf_bands = conf->wps_rf_bands;
+	} else {
+		wps->dev.rf_bands =
+			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+	}
+
+	if (conf->wpa & WPA_PROTO_RSN) {
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+			wps->auth_types |= WPS_AUTH_WPA2PSK;
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			wps->auth_types |= WPS_AUTH_WPA2;
+
+		if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+			wps->encr_types |= WPS_ENCR_AES;
+		if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+			wps->encr_types |= WPS_ENCR_TKIP;
+	}
+
+	if (conf->wpa & WPA_PROTO_WPA) {
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+			wps->auth_types |= WPS_AUTH_WPAPSK;
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			wps->auth_types |= WPS_AUTH_WPA;
+
+		if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+			wps->encr_types |= WPS_ENCR_AES;
+		if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+			wps->encr_types |= WPS_ENCR_TKIP;
+	}
+
+	if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
+		wps->encr_types |= WPS_ENCR_NONE;
+		wps->auth_types |= WPS_AUTH_OPEN;
+	} else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
+		wps->encr_types |= WPS_ENCR_WEP;
+		if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
+			wps->auth_types |= WPS_AUTH_OPEN;
+		if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
+			wps->auth_types |= WPS_AUTH_SHARED;
+	} else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
+		wps->auth_types |= WPS_AUTH_OPEN;
+		if (conf->default_wep_key_len)
+			wps->encr_types |= WPS_ENCR_WEP;
+		else
+			wps->encr_types |= WPS_ENCR_NONE;
+	}
+
+	if (conf->ssid.wpa_psk_file) {
+		/* Use per-device PSKs */
+	} else if (conf->ssid.wpa_passphrase) {
+		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+	} else if (conf->ssid.wpa_psk) {
+		wps->network_key = os_malloc(2 * PMK_LEN + 1);
+		if (wps->network_key == NULL) {
+			os_free(wps);
+			return -1;
+		}
+		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+				 conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->network_key_len = 2 * PMK_LEN;
+	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+		if (wps->network_key == NULL) {
+			os_free(wps);
+			return -1;
+		}
+		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+			  conf->ssid.wep.len[0]);
+		wps->network_key_len = conf->ssid.wep.len[0];
+	}
+
+	if (conf->ssid.wpa_psk) {
+		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->psk_set = 1;
+	}
+
+	if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
+		/* 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->ap_settings = conf->ap_settings;
+	wps->ap_settings_len = conf->ap_settings_len;
+
+	cfg.new_psk_cb = hostapd_wps_new_psk_cb;
+	cfg.set_ie_cb = hostapd_wps_set_ie_cb;
+	cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
+	cfg.reg_success_cb = hostapd_wps_reg_success_cb;
+	cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+	cfg.cb_ctx = hapd;
+	cfg.skip_cred_build = conf->skip_cred_build;
+	cfg.extra_cred = conf->extra_cred;
+	cfg.extra_cred_len = conf->extra_cred_len;
+	cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
+		conf->skip_cred_build;
+	if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
+		cfg.static_wep_only = 1;
+	cfg.dualband = interface_count(hapd->iface) > 1;
+	if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
+	    (WPS_RF_50GHZ | WPS_RF_24GHZ))
+		cfg.dualband = 1;
+	if (cfg.dualband)
+		wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
+
+	wps->registrar = wps_registrar_init(wps, &cfg);
+	if (wps->registrar == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
+		os_free(wps->network_key);
+		os_free(wps);
+		return -1;
+	}
+
+#ifdef CONFIG_WPS_UPNP
+	wps->friendly_name = hapd->conf->friendly_name;
+	wps->manufacturer_url = hapd->conf->manufacturer_url;
+	wps->model_description = hapd->conf->model_description;
+	wps->model_url = hapd->conf->model_url;
+	wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+	hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
+
+	hapd->wps = wps;
+
+	return 0;
+}
+
+
+int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+	struct wps_context *wps = hapd->wps;
+
+	if (wps == NULL)
+		return 0;
+
+#ifdef CONFIG_WPS_UPNP
+	if (hostapd_wps_upnp_init(hapd, wps) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
+		wps_registrar_deinit(wps->registrar);
+		os_free(wps->network_key);
+		os_free(wps);
+		hapd->wps = NULL;
+		return -1;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	return 0;
+}
+
+
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+	wps->ap_nfc_dev_pw_id = 0;
+	wpabuf_free(wps->ap_nfc_dh_pubkey);
+	wps->ap_nfc_dh_pubkey = NULL;
+	wpabuf_free(wps->ap_nfc_dh_privkey);
+	wps->ap_nfc_dh_privkey = NULL;
+	wpabuf_free(wps->ap_nfc_dev_pw);
+	wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
+void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	if (hapd->wps == NULL)
+		return;
+#ifdef CONFIG_WPS_UPNP
+	hostapd_wps_upnp_deinit(hapd);
+#endif /* CONFIG_WPS_UPNP */
+	wps_registrar_deinit(hapd->wps->registrar);
+	os_free(hapd->wps->network_key);
+	wps_device_data_free(&hapd->wps->dev);
+	wpabuf_free(hapd->wps->dh_pubkey);
+	wpabuf_free(hapd->wps->dh_privkey);
+	wps_free_pending_msgs(hapd->wps->upnp_msgs);
+	hostapd_wps_nfc_clear(hapd->wps);
+	os_free(hapd->wps);
+	hapd->wps = NULL;
+	hostapd_wps_clear_ies(hapd);
+}
+
+
+void hostapd_update_wps(struct hostapd_data *hapd)
+{
+	if (hapd->wps == NULL)
+		return;
+
+#ifdef CONFIG_WPS_UPNP
+	hapd->wps->friendly_name = hapd->conf->friendly_name;
+	hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
+	hapd->wps->model_description = hapd->conf->model_description;
+	hapd->wps->model_url = hapd->conf->model_url;
+	hapd->wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+
+	if (hapd->conf->wps_state)
+		wps_registrar_update_ie(hapd->wps->registrar);
+	else
+		hostapd_deinit_wps(hapd);
+}
+
+
+struct wps_add_pin_data {
+	const u8 *addr;
+	const u8 *uuid;
+	const u8 *pin;
+	size_t pin_len;
+	int timeout;
+	int added;
+};
+
+
+static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_add_pin_data *data = ctx;
+	int ret;
+
+	if (hapd->wps == NULL)
+		return 0;
+	ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
+				    data->uuid, data->pin, data->pin_len,
+				    data->timeout);
+	if (ret == 0)
+		data->added++;
+	return ret;
+}
+
+
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+			const char *uuid, const char *pin, int timeout)
+{
+	u8 u[UUID_LEN];
+	struct wps_add_pin_data data;
+
+	data.addr = addr;
+	data.uuid = u;
+	data.pin = (const u8 *) pin;
+	data.pin_len = os_strlen(pin);
+	data.timeout = timeout;
+	data.added = 0;
+
+	if (os_strcmp(uuid, "any") == 0)
+		data.uuid = NULL;
+	else {
+		if (uuid_str2bin(uuid, u))
+			return -1;
+		data.uuid = u;
+	}
+	if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
+		return -1;
+	return data.added ? 0 : -1;
+}
+
+
+static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
+{
+	const u8 *p2p_dev_addr = ctx;
+	if (hapd->wps == NULL)
+		return 0;
+	return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
+}
+
+
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+			      const u8 *p2p_dev_addr)
+{
+	return hostapd_wps_for_each(hapd, wps_button_pushed,
+				    (void *) p2p_dev_addr);
+}
+
+
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->wps == NULL)
+		return 0;
+
+	wps_registrar_wps_cancel(hapd->wps->registrar);
+	ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+
+	return 0;
+}
+
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+	return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+}
+
+
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
+				    const u8 *ie, size_t ie_len,
+				    int ssi_signal)
+{
+	struct hostapd_data *hapd = ctx;
+	struct wpabuf *wps_ie;
+	struct ieee802_11_elems elems;
+
+	if (hapd->wps == NULL)
+		return 0;
+
+	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
+			   MACSTR, MAC2STR(addr));
+		return 0;
+	}
+
+	if (elems.ssid && elems.ssid_len > 0 &&
+	    (elems.ssid_len != hapd->conf->ssid.ssid_len ||
+	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
+	     0))
+		return 0; /* Not for us */
+
+	wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
+	if (wps_ie == NULL)
+		return 0;
+	if (wps_validate_probe_req(wps_ie, addr) < 0) {
+		wpabuf_free(wps_ie);
+		return 0;
+	}
+
+	if (wpabuf_len(wps_ie) > 0) {
+		int p2p_wildcard = 0;
+#ifdef CONFIG_P2P
+		if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+		    os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+			      P2P_WILDCARD_SSID_LEN) == 0)
+			p2p_wildcard = 1;
+#endif /* CONFIG_P2P */
+		wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
+					   p2p_wildcard);
+#ifdef CONFIG_WPS_UPNP
+		/* FIX: what exactly should be included in the WLANEvent?
+		 * WPS attributes? Full ProbeReq frame? */
+		if (!p2p_wildcard)
+			upnp_wps_device_send_wlan_event(
+				hapd->wps_upnp, addr,
+				UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
+#endif /* CONFIG_WPS_UPNP */
+	}
+
+	wpabuf_free(wps_ie);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+
+static int hostapd_rx_req_put_wlan_response(
+	void *priv, enum upnp_wps_wlanevent_type ev_type,
+	const u8 *mac_addr, const struct wpabuf *msg,
+	enum wps_msg_type msg_type)
+{
+	struct hostapd_data *hapd = priv;
+	struct sta_info *sta;
+	struct upnp_pending_message *p;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
+		   MACSTR, ev_type, MAC2STR(mac_addr));
+	wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
+		    wpabuf_head(msg), wpabuf_len(msg));
+	if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
+			   "PutWLANResponse WLANEventType %d", ev_type);
+		return -1;
+	}
+
+	/*
+	 * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
+	 * server implementation for delivery to the peer.
+	 */
+
+	sta = ap_get_sta(hapd, mac_addr);
+#ifndef CONFIG_WPS_STRICT
+	if (!sta) {
+		/*
+		 * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
+		 * Pick STA that is in an ongoing WPS registration without
+		 * checking the MAC address.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
+			   "on NewWLANEventMAC; try wildcard match");
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
+				break;
+		}
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+	if (!sta || !(sta->flags & WLAN_STA_WPS)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
+		return 0;
+	}
+
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	os_memcpy(p->addr, sta->addr, ETH_ALEN);
+	p->msg = wpabuf_dup(msg);
+	p->type = msg_type;
+	p->next = hapd->wps->upnp_msgs;
+	hapd->wps->upnp_msgs = p;
+
+	return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
+}
+
+
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+				 struct wps_context *wps)
+{
+	struct upnp_wps_device_ctx *ctx;
+
+	if (!hapd->conf->upnp_iface)
+		return 0;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return -1;
+
+	ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
+	if (hapd->conf->ap_pin)
+		ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
+
+	hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
+					      hapd->conf->upnp_iface);
+	if (hapd->wps_upnp == NULL)
+		return -1;
+	wps->wps_upnp = hapd->wps_upnp;
+
+	return 0;
+}
+
+
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
+{
+	upnp_wps_device_deinit(hapd->wps_upnp, hapd);
+}
+
+#endif /* CONFIG_WPS_UPNP */
+
+
+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
+			    char *buf, size_t buflen)
+{
+	if (hapd->wps == NULL)
+		return 0;
+	return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
+}
+
+
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_data *hapd = eloop_data;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+	hostapd_wps_ap_pin_disable(hapd);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
+}
+
+
+static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+	hapd->ap_pin_failures = 0;
+	hapd->ap_pin_failures_consecutive = 0;
+	hapd->conf->ap_setup_locked = 0;
+	if (hapd->wps->ap_setup_locked) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+		hapd->wps->ap_setup_locked = 0;
+		wps_registrar_update_ie(hapd->wps->registrar);
+	}
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	if (timeout > 0)
+		eloop_register_timeout(timeout, 0,
+				       hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
+{
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = NULL;
+#ifdef CONFIG_WPS_UPNP
+	upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
+#endif /* CONFIG_WPS_UPNP */
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	return 0;
+}
+
+
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+	hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
+}
+
+
+struct wps_ap_pin_data {
+	char pin_txt[9];
+	int timeout;
+};
+
+
+static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_ap_pin_data *data = ctx;
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = os_strdup(data->pin_txt);
+#ifdef CONFIG_WPS_UPNP
+	upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
+#endif /* CONFIG_WPS_UPNP */
+	hostapd_wps_ap_pin_enable(hapd, data->timeout);
+	return 0;
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+	unsigned int pin;
+	struct wps_ap_pin_data data;
+
+	pin = wps_generate_pin();
+	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
+	data.timeout = timeout;
+	hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
+	return hapd->conf->ap_pin;
+}
+
+
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
+{
+	return hapd->conf->ap_pin;
+}
+
+
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+			   int timeout)
+{
+	struct wps_ap_pin_data data;
+	int ret;
+
+	ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
+	if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
+		return -1;
+	data.timeout = timeout;
+	return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
+}
+
+
+static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->wps)
+		wps_registrar_update_ie(hapd->wps->registrar);
+	return 0;
+}
+
+
+void hostapd_wps_update_ie(struct hostapd_data *hapd)
+{
+	hostapd_wps_for_each(hapd, wps_update_ie, NULL);
+}
+
+
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+			  const char *auth, const char *encr, const char *key)
+{
+	struct wps_credential cred;
+	size_t len;
+
+	os_memset(&cred, 0, sizeof(cred));
+
+	len = os_strlen(ssid);
+	if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
+	    hexstr2bin(ssid, cred.ssid, len / 2))
+		return -1;
+	cred.ssid_len = len / 2;
+
+	if (os_strncmp(auth, "OPEN", 4) == 0)
+		cred.auth_type = WPS_AUTH_OPEN;
+	else if (os_strncmp(auth, "WPAPSK", 6) == 0)
+		cred.auth_type = WPS_AUTH_WPAPSK;
+	else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
+		cred.auth_type = WPS_AUTH_WPA2PSK;
+	else
+		return -1;
+
+	if (encr) {
+		if (os_strncmp(encr, "NONE", 4) == 0)
+			cred.encr_type = WPS_ENCR_NONE;
+		else if (os_strncmp(encr, "WEP", 3) == 0)
+			cred.encr_type = WPS_ENCR_WEP;
+		else if (os_strncmp(encr, "TKIP", 4) == 0)
+			cred.encr_type = WPS_ENCR_TKIP;
+		else if (os_strncmp(encr, "CCMP", 4) == 0)
+			cred.encr_type = WPS_ENCR_AES;
+		else
+			return -1;
+	} else
+		cred.encr_type = WPS_ENCR_NONE;
+
+	if (key) {
+		len = os_strlen(key);
+		if ((len & 1) || len > 2 * sizeof(cred.key) ||
+		    hexstr2bin(key, cred.key, len / 2))
+			return -1;
+		cred.key_len = len / 2;
+	}
+
+	return wps_registrar_config_ap(hapd->wps->registrar, &cred);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_password_token_data {
+	const u8 *oob_dev_pw;
+	size_t oob_dev_pw_len;
+	int added;
+};
+
+
+static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_nfc_password_token_data *data = ctx;
+	int ret;
+
+	if (hapd->wps == NULL)
+		return 0;
+	ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
+						   data->oob_dev_pw,
+						   data->oob_dev_pw_len);
+	if (ret == 0)
+		data->added++;
+	return ret;
+}
+
+
+static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
+					      struct wps_parse_attr *attr)
+{
+	struct wps_nfc_password_token_data data;
+
+	data.oob_dev_pw = attr->oob_dev_password;
+	data.oob_dev_pw_len = attr->oob_dev_password_len;
+	data.added = 0;
+	if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
+		return -1;
+	return data.added ? 0 : -1;
+}
+
+
+static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
+				       const struct wpabuf *wps)
+{
+	struct wps_parse_attr attr;
+
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+	if (wps_parse_msg(wps, &attr)) {
+		wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+		return -1;
+	}
+
+	if (attr.oob_dev_password)
+		return hostapd_wps_add_nfc_password_token(hapd, &attr);
+
+	wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+	return -1;
+}
+
+
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+			     const struct wpabuf *data)
+{
+	const struct wpabuf *wps = data;
+	struct wpabuf *tmp = NULL;
+	int ret;
+
+	if (wpabuf_len(data) < 4)
+		return -1;
+
+	if (*wpabuf_head_u8(data) != 0x10) {
+		/* Assume this contains full NDEF record */
+		tmp = ndef_parse_wifi(data);
+		if (tmp == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+			return -1;
+		}
+		wps = tmp;
+	}
+
+	ret = hostapd_wps_nfc_tag_process(hapd, wps);
+	wpabuf_free(tmp);
+	return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+					     int ndef)
+{
+	struct wpabuf *ret;
+
+	if (hapd->wps == NULL)
+		return NULL;
+
+	ret = wps_get_oob_cred(hapd->wps);
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+	return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+				 &hapd->conf->wps_nfc_dh_pubkey,
+				 &hapd->conf->wps_nfc_dh_privkey,
+				 &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+	struct wps_context *wps = hapd->wps;
+
+	if (wps == NULL)
+		return -1;
+
+	if (!hapd->conf->wps_nfc_dh_pubkey ||
+	    !hapd->conf->wps_nfc_dh_privkey ||
+	    !hapd->conf->wps_nfc_dev_pw ||
+	    !hapd->conf->wps_nfc_dev_pw_id)
+		return -1;
+
+	hostapd_wps_nfc_clear(wps);
+	wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+	wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+	wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+	wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+	if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+	    !wps->ap_nfc_dev_pw) {
+		hostapd_wps_nfc_clear(wps);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+	hostapd_wps_nfc_clear(hapd->wps);
+}
+
+#endif /* CONFIG_WPS_NFC */

Deleted: vendor/wpa/2.0/src/ap/wps_hostapd.h
===================================================================
--- vendor/wpa/dist/src/ap/wps_hostapd.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/ap/wps_hostapd.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,67 +0,0 @@
-/*
- * hostapd / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_HOSTAPD_H
-#define WPS_HOSTAPD_H
-
-#ifdef CONFIG_WPS
-
-int hostapd_init_wps(struct hostapd_data *hapd,
-		     struct hostapd_bss_config *conf);
-void hostapd_deinit_wps(struct hostapd_data *hapd);
-void hostapd_update_wps(struct hostapd_data *hapd);
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-			const char *pin, int timeout);
-int hostapd_wps_button_pushed(struct hostapd_data *hapd);
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
-			  char *path, char *method, char *name);
-int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
-			    char *buf, size_t buflen);
-void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
-const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
-const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
-int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
-			   int timeout);
-
-#else /* CONFIG_WPS */
-
-static inline int hostapd_init_wps(struct hostapd_data *hapd,
-				   struct hostapd_bss_config *conf)
-{
-	return 0;
-}
-
-static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
-{
-}
-
-static inline void hostapd_update_wps(struct hostapd_data *hapd)
-{
-}
-
-static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
-					  const u8 *addr,
-					  char *buf, size_t buflen)
-{
-	return 0;
-}
-
-static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd)
-{
-	return 0;
-}
-
-#endif /* CONFIG_WPS */
-
-#endif /* WPS_HOSTAPD_H */

Copied: vendor/wpa/2.0/src/ap/wps_hostapd.h (from rev 9639, vendor/wpa/dist/src/ap/wps_hostapd.h)
===================================================================
--- vendor/wpa/2.0/src/ap/wps_hostapd.h	                        (rev 0)
+++ vendor/wpa/2.0/src/ap/wps_hostapd.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,83 @@
+/*
+ * hostapd / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_HOSTAPD_H
+#define WPS_HOSTAPD_H
+
+#ifdef CONFIG_WPS
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+		     struct hostapd_bss_config *conf);
+int hostapd_init_wps_complete(struct hostapd_data *hapd);
+void hostapd_deinit_wps(struct hostapd_data *hapd);
+void hostapd_update_wps(struct hostapd_data *hapd);
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+			const char *uuid, const char *pin, int timeout);
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+			      const u8 *p2p_dev_addr);
+int hostapd_wps_cancel(struct hostapd_data *hapd);
+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
+			    char *buf, size_t buflen);
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+			   int timeout);
+void hostapd_wps_update_ie(struct hostapd_data *hapd);
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+			  const char *auth, const char *encr, const char *key);
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+			     const struct wpabuf *data);
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+					     int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
+
+#else /* CONFIG_WPS */
+
+static inline int hostapd_init_wps(struct hostapd_data *hapd,
+				   struct hostapd_bss_config *conf)
+{
+	return 0;
+}
+
+static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+}
+
+static inline int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+    return 0;
+}
+
+static inline void hostapd_update_wps(struct hostapd_data *hapd)
+{
+}
+
+static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
+					  const u8 *addr,
+					  char *buf, size_t buflen)
+{
+	return 0;
+}
+
+static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+					    const u8 *p2p_dev_addr)
+{
+	return 0;
+}
+
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_HOSTAPD_H */

Deleted: vendor/wpa/2.0/src/common/defs.h
===================================================================
--- vendor/wpa/dist/src/common/defs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,255 +0,0 @@
-/*
- * WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DEFS_H
-#define DEFS_H
-
-#ifdef FALSE
-#undef FALSE
-#endif
-#ifdef TRUE
-#undef TRUE
-#endif
-typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-
-
-#define WPA_CIPHER_NONE BIT(0)
-#define WPA_CIPHER_WEP40 BIT(1)
-#define WPA_CIPHER_WEP104 BIT(2)
-#define WPA_CIPHER_TKIP BIT(3)
-#define WPA_CIPHER_CCMP BIT(4)
-#ifdef CONFIG_IEEE80211W
-#define WPA_CIPHER_AES_128_CMAC BIT(5)
-#endif /* CONFIG_IEEE80211W */
-
-#define WPA_KEY_MGMT_IEEE8021X BIT(0)
-#define WPA_KEY_MGMT_PSK BIT(1)
-#define WPA_KEY_MGMT_NONE BIT(2)
-#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
-#define WPA_KEY_MGMT_WPA_NONE BIT(4)
-#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
-#define WPA_KEY_MGMT_FT_PSK BIT(6)
-#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
-#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
-#define WPA_KEY_MGMT_WPS BIT(9)
-
-static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
-{
-	return akm == WPA_KEY_MGMT_IEEE8021X ||
-		akm == WPA_KEY_MGMT_FT_IEEE8021X ||
-		akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
-}
-
-static inline int wpa_key_mgmt_wpa_psk(int akm)
-{
-	return akm == WPA_KEY_MGMT_PSK ||
-		akm == WPA_KEY_MGMT_FT_PSK ||
-		akm == WPA_KEY_MGMT_PSK_SHA256;
-}
-
-static inline int wpa_key_mgmt_ft(int akm)
-{
-	return akm == WPA_KEY_MGMT_FT_PSK ||
-		akm == WPA_KEY_MGMT_FT_IEEE8021X;
-}
-
-static inline int wpa_key_mgmt_sha256(int akm)
-{
-	return akm == WPA_KEY_MGMT_PSK_SHA256 ||
-		akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
-}
-
-
-#define WPA_PROTO_WPA BIT(0)
-#define WPA_PROTO_RSN BIT(1)
-
-#define WPA_AUTH_ALG_OPEN BIT(0)
-#define WPA_AUTH_ALG_SHARED BIT(1)
-#define WPA_AUTH_ALG_LEAP BIT(2)
-#define WPA_AUTH_ALG_FT BIT(3)
-
-
-enum wpa_alg {
-	WPA_ALG_NONE,
-	WPA_ALG_WEP,
-	WPA_ALG_TKIP,
-	WPA_ALG_CCMP,
-	WPA_ALG_IGTK,
-	WPA_ALG_PMK
-};
-
-/**
- * enum wpa_cipher - Cipher suites
- */
-enum wpa_cipher {
-	CIPHER_NONE,
-	CIPHER_WEP40,
-	CIPHER_TKIP,
-	CIPHER_CCMP,
-	CIPHER_WEP104
-};
-
-/**
- * enum wpa_key_mgmt - Key management suites
- */
-enum wpa_key_mgmt {
-	KEY_MGMT_802_1X,
-	KEY_MGMT_PSK,
-	KEY_MGMT_NONE,
-	KEY_MGMT_802_1X_NO_WPA,
-	KEY_MGMT_WPA_NONE,
-	KEY_MGMT_FT_802_1X,
-	KEY_MGMT_FT_PSK,
-	KEY_MGMT_802_1X_SHA256,
-	KEY_MGMT_PSK_SHA256,
-	KEY_MGMT_WPS
-};
-
-/**
- * enum wpa_states - wpa_supplicant state
- *
- * These enumeration values are used to indicate the current wpa_supplicant
- * state (wpa_s->wpa_state). The current state can be retrieved with
- * wpa_supplicant_get_state() function and the state can be changed by calling
- * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
- * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
- * to access the state variable.
- */
-enum wpa_states {
-	/**
-	 * WPA_DISCONNECTED - Disconnected state
-	 *
-	 * This state indicates that client is not associated, but is likely to
-	 * start looking for an access point. This state is entered when a
-	 * connection is lost.
-	 */
-	WPA_DISCONNECTED,
-
-	/**
-	 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
-	 *
-	 * This state is entered if there are no enabled networks in the
-	 * configuration. wpa_supplicant is not trying to associate with a new
-	 * network and external interaction (e.g., ctrl_iface call to add or
-	 * enable a network) is needed to start association.
-	 */
-	WPA_INACTIVE,
-
-	/**
-	 * WPA_SCANNING - Scanning for a network
-	 *
-	 * This state is entered when wpa_supplicant starts scanning for a
-	 * network.
-	 */
-	WPA_SCANNING,
-
-	/**
-	 * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
-	 *
-	 * This state is entered when wpa_supplicant has found a suitable BSS
-	 * to authenticate with and the driver is configured to try to
-	 * authenticate with this BSS. This state is used only with drivers
-	 * that use wpa_supplicant as the SME.
-	 */
-	WPA_AUTHENTICATING,
-
-	/**
-	 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
-	 *
-	 * This state is entered when wpa_supplicant has found a suitable BSS
-	 * to associate with and the driver is configured to try to associate
-	 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
-	 * state is entered when the driver is configured to try to associate
-	 * with a network using the configured SSID and security policy.
-	 */
-	WPA_ASSOCIATING,
-
-	/**
-	 * WPA_ASSOCIATED - Association completed
-	 *
-	 * This state is entered when the driver reports that association has
-	 * been successfully completed with an AP. If IEEE 802.1X is used
-	 * (with or without WPA/WPA2), wpa_supplicant remains in this state
-	 * until the IEEE 802.1X/EAPOL authentication has been completed.
-	 */
-	WPA_ASSOCIATED,
-
-	/**
-	 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
-	 *
-	 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
-	 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
-	 * frame after association. In case of WPA-EAP, this state is entered
-	 * when the IEEE 802.1X/EAPOL authentication has been completed.
-	 */
-	WPA_4WAY_HANDSHAKE,
-
-	/**
-	 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
-	 *
-	 * This state is entered when 4-Way Key Handshake has been completed
-	 * (i.e., when the supplicant sends out message 4/4) and when Group
-	 * Key rekeying is started by the AP (i.e., when supplicant receives
-	 * message 1/2).
-	 */
-	WPA_GROUP_HANDSHAKE,
-
-	/**
-	 * WPA_COMPLETED - All authentication completed
-	 *
-	 * This state is entered when the full authentication process is
-	 * completed. In case of WPA2, this happens when the 4-Way Handshake is
-	 * successfully completed. With WPA, this state is entered after the
-	 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
-	 * completed after dynamic keys are received (or if not used, after
-	 * the EAP authentication has been completed). With static WEP keys and
-	 * plaintext connections, this state is entered when an association
-	 * has been completed.
-	 *
-	 * This state indicates that the supplicant has completed its
-	 * processing for the association phase and that data connection is
-	 * fully configured.
-	 */
-	WPA_COMPLETED
-};
-
-#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
-#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
-#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
-#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
-
-#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
-#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
-
-
-/**
- * enum mfp_options - Management frame protection (IEEE 802.11w) options
- */
-enum mfp_options {
-	NO_MGMT_FRAME_PROTECTION = 0,
-	MGMT_FRAME_PROTECTION_OPTIONAL = 1,
-	MGMT_FRAME_PROTECTION_REQUIRED = 2
-};
-
-/**
- * enum hostapd_hw_mode - Hardware mode
- */
-enum hostapd_hw_mode {
-	HOSTAPD_MODE_IEEE80211B,
-	HOSTAPD_MODE_IEEE80211G,
-	HOSTAPD_MODE_IEEE80211A,
-	NUM_HOSTAPD_MODES
-};
-
-#endif /* DEFS_H */

Copied: vendor/wpa/2.0/src/common/defs.h (from rev 9639, vendor/wpa/dist/src/common/defs.h)
===================================================================
--- vendor/wpa/2.0/src/common/defs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,321 @@
+/*
+ * WPA Supplicant - Common definitions
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+
+#define WPA_CIPHER_NONE BIT(0)
+#define WPA_CIPHER_WEP40 BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP BIT(3)
+#define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+#endif /* CONFIG_IEEE80211W */
+#define WPA_CIPHER_GCMP BIT(6)
+#define WPA_CIPHER_SMS4 BIT(7)
+
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+#define WPA_KEY_MGMT_NONE BIT(2)
+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
+#define WPA_KEY_MGMT_WPA_NONE BIT(4)
+#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
+#define WPA_KEY_MGMT_FT_PSK BIT(6)
+#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
+#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
+#define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
+#define WPA_KEY_MGMT_CCKM BIT(14)
+
+static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_CCKM |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa_psk(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK |
+			 WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_SAE));
+}
+
+static inline int wpa_key_mgmt_ft(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sha256(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa(int akm)
+{
+	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
+		wpa_key_mgmt_wpa_psk(akm);
+}
+
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+	return akm == WPA_KEY_MGMT_CCKM;
+}
+
+
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
+
+#define WPA_AUTH_ALG_OPEN BIT(0)
+#define WPA_AUTH_ALG_SHARED BIT(1)
+#define WPA_AUTH_ALG_LEAP BIT(2)
+#define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
+
+
+enum wpa_alg {
+	WPA_ALG_NONE,
+	WPA_ALG_WEP,
+	WPA_ALG_TKIP,
+	WPA_ALG_CCMP,
+	WPA_ALG_IGTK,
+	WPA_ALG_PMK,
+	WPA_ALG_GCMP,
+	WPA_ALG_SMS4,
+	WPA_ALG_KRK
+};
+
+/**
+ * enum wpa_cipher - Cipher suites
+ */
+enum wpa_cipher {
+	CIPHER_NONE,
+	CIPHER_WEP40,
+	CIPHER_TKIP,
+	CIPHER_CCMP,
+	CIPHER_WEP104,
+	CIPHER_GCMP,
+	CIPHER_SMS4
+};
+
+/**
+ * enum wpa_key_mgmt - Key management suites
+ */
+enum wpa_key_mgmt {
+	KEY_MGMT_802_1X,
+	KEY_MGMT_PSK,
+	KEY_MGMT_NONE,
+	KEY_MGMT_802_1X_NO_WPA,
+	KEY_MGMT_WPA_NONE,
+	KEY_MGMT_FT_802_1X,
+	KEY_MGMT_FT_PSK,
+	KEY_MGMT_802_1X_SHA256,
+	KEY_MGMT_PSK_SHA256,
+	KEY_MGMT_WPS,
+	KEY_MGMT_SAE,
+	KEY_MGMT_FT_SAE,
+	KEY_MGMT_WAPI_PSK,
+	KEY_MGMT_WAPI_CERT,
+	KEY_MGMT_CCKM
+};
+
+/**
+ * enum wpa_states - wpa_supplicant state
+ *
+ * These enumeration values are used to indicate the current wpa_supplicant
+ * state (wpa_s->wpa_state). The current state can be retrieved with
+ * wpa_supplicant_get_state() function and the state can be changed by calling
+ * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
+ * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
+ * to access the state variable.
+ */
+enum wpa_states {
+	/**
+	 * WPA_DISCONNECTED - Disconnected state
+	 *
+	 * This state indicates that client is not associated, but is likely to
+	 * start looking for an access point. This state is entered when a
+	 * connection is lost.
+	 */
+	WPA_DISCONNECTED,
+
+	/**
+	 * WPA_INTERFACE_DISABLED - Interface disabled
+	 *
+	 * This stat eis entered if the network interface is disabled, e.g.,
+	 * due to rfkill. wpa_supplicant refuses any new operations that would
+	 * use the radio until the interface has been enabled.
+	 */
+	WPA_INTERFACE_DISABLED,
+
+	/**
+	 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
+	 *
+	 * This state is entered if there are no enabled networks in the
+	 * configuration. wpa_supplicant is not trying to associate with a new
+	 * network and external interaction (e.g., ctrl_iface call to add or
+	 * enable a network) is needed to start association.
+	 */
+	WPA_INACTIVE,
+
+	/**
+	 * WPA_SCANNING - Scanning for a network
+	 *
+	 * This state is entered when wpa_supplicant starts scanning for a
+	 * network.
+	 */
+	WPA_SCANNING,
+
+	/**
+	 * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to authenticate with and the driver is configured to try to
+	 * authenticate with this BSS. This state is used only with drivers
+	 * that use wpa_supplicant as the SME.
+	 */
+	WPA_AUTHENTICATING,
+
+	/**
+	 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to associate with and the driver is configured to try to associate
+	 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+	 * state is entered when the driver is configured to try to associate
+	 * with a network using the configured SSID and security policy.
+	 */
+	WPA_ASSOCIATING,
+
+	/**
+	 * WPA_ASSOCIATED - Association completed
+	 *
+	 * This state is entered when the driver reports that association has
+	 * been successfully completed with an AP. If IEEE 802.1X is used
+	 * (with or without WPA/WPA2), wpa_supplicant remains in this state
+	 * until the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_ASSOCIATED,
+
+	/**
+	 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+	 *
+	 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+	 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+	 * frame after association. In case of WPA-EAP, this state is entered
+	 * when the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_4WAY_HANDSHAKE,
+
+	/**
+	 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+	 *
+	 * This state is entered when 4-Way Key Handshake has been completed
+	 * (i.e., when the supplicant sends out message 4/4) and when Group
+	 * Key rekeying is started by the AP (i.e., when supplicant receives
+	 * message 1/2).
+	 */
+	WPA_GROUP_HANDSHAKE,
+
+	/**
+	 * WPA_COMPLETED - All authentication completed
+	 *
+	 * This state is entered when the full authentication process is
+	 * completed. In case of WPA2, this happens when the 4-Way Handshake is
+	 * successfully completed. With WPA, this state is entered after the
+	 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+	 * completed after dynamic keys are received (or if not used, after
+	 * the EAP authentication has been completed). With static WEP keys and
+	 * plaintext connections, this state is entered when an association
+	 * has been completed.
+	 *
+	 * This state indicates that the supplicant has completed its
+	 * processing for the association phase and that data connection is
+	 * fully configured.
+	 */
+	WPA_COMPLETED
+};
+
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
+
+/**
+ * enum mfp_options - Management frame protection (IEEE 802.11w) options
+ */
+enum mfp_options {
+	NO_MGMT_FRAME_PROTECTION = 0,
+	MGMT_FRAME_PROTECTION_OPTIONAL = 1,
+	MGMT_FRAME_PROTECTION_REQUIRED = 2,
+};
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
+
+/**
+ * enum hostapd_hw_mode - Hardware mode
+ */
+enum hostapd_hw_mode {
+	HOSTAPD_MODE_IEEE80211B,
+	HOSTAPD_MODE_IEEE80211G,
+	HOSTAPD_MODE_IEEE80211A,
+	HOSTAPD_MODE_IEEE80211AD,
+	NUM_HOSTAPD_MODES
+};
+
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
+#endif /* DEFS_H */

Deleted: vendor/wpa/2.0/src/common/eapol_common.h
===================================================================
--- vendor/wpa/dist/src/common/eapol_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/eapol_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,47 +0,0 @@
-/*
- * EAPOL definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAPOL_COMMON_H
-#define EAPOL_COMMON_H
-
-/* IEEE Std 802.1X-2004 */
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee802_1x_hdr {
-	u8 version;
-	u8 type;
-	be16 length;
-	/* followed by length octets of data */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define EAPOL_VERSION 2
-
-enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
-       IEEE802_1X_TYPE_EAPOL_START = 1,
-       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
-       IEEE802_1X_TYPE_EAPOL_KEY = 3,
-       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
-};
-
-enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
-       EAPOL_KEY_TYPE_WPA = 254 };
-
-#endif /* EAPOL_COMMON_H */

Copied: vendor/wpa/2.0/src/common/eapol_common.h (from rev 9639, vendor/wpa/dist/src/common/eapol_common.h)
===================================================================
--- vendor/wpa/2.0/src/common/eapol_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/eapol_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,81 @@
+/*
+ * EAPOL definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_COMMON_H
+#define EAPOL_COMMON_H
+
+/* IEEE Std 802.1X-2004 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_hdr {
+	u8 version;
+	u8 type;
+	be16 length;
+	/* followed by length octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAPOL_VERSION 2
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+       IEEE802_1X_TYPE_EAPOL_START = 1,
+       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+       IEEE802_1X_TYPE_EAPOL_KEY = 3,
+       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
+       EAPOL_KEY_TYPE_WPA = 254 };
+
+
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_eapol_key {
+	u8 type;
+	/* Note: key_length is unaligned */
+	u8 key_length[2];
+	/* does not repeat within the life of the keying material used to
+	 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+	u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+	u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+	u8 key_index; /* key flag in the most significant bit:
+		       * 0 = broadcast (default key),
+		       * 1 = unicast (key mapping key); key index is in the
+		       * 7 least significant bits */
+	/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+	 * the key */
+	u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+	/* followed by key: if packet body length = 44 + key length, then the
+	 * key field (of key_length bytes) contains the key in encrypted form;
+	 * if packet body length = 44, key field is absent and key_length
+	 * represents the number of least significant octets from
+	 * MS-MPPE-Send-Key attribute to be used as the keying material;
+	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#endif /* EAPOL_COMMON_H */

Copied: vendor/wpa/2.0/src/common/gas.c (from rev 9639, vendor/wpa/dist/src/common/gas.c)
===================================================================
--- vendor/wpa/2.0/src/common/gas.c	                        (rev 0)
+++ vendor/wpa/2.0/src/common/gas.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,273 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+	return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+			     size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+	return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+	       u8 more, u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_le16(buf, status_code);
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+	wpabuf_put_le16(buf, comeback_delay);
+
+	return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+		       size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+			      status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+			u16 comeback_delay, size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+			      status_code, frag_id, more, comeback_delay,
+			      size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+				   u8 pame_bi)
+{
+	/* Advertisement Protocol IE */
+	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+	wpabuf_put_u8(buf, 2); /* Length */
+	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+		      (pame_bi ? 0x80 : 0));
+	/* Advertisement Protocol */
+	wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_req(dialog_token, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0, 0);
+
+	wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+				     4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_comeback_resp(dialog_token, status_code,
+				      frag_id, more, comeback_delay, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, comeback_delay,
+					   payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+	u8 action;
+	size_t offset;
+	u8 *len;
+
+	if (buf == NULL || wpabuf_len(buf) < 2)
+		return;
+
+	action = *(wpabuf_head_u8(buf) + 1);
+	switch (action) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		offset = 3 + 4;
+		break;
+	case WLAN_PA_GAS_INITIAL_RESP:
+		offset = 7 + 4;
+		break;
+	case WLAN_PA_GAS_COMEBACK_RESP:
+		offset = 8 + 4;
+		break;
+	default:
+		return;
+	}
+
+	if (wpabuf_len(buf) < offset + 2)
+		return;
+
+	len = wpabuf_mhead_u8(buf) + offset;
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+	wpabuf_put_le16(buf, info_id);
+	return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}

Copied: vendor/wpa/2.0/src/common/gas.h (from rev 9639, vendor/wpa/dist/src/common/gas.h)
===================================================================
--- vendor/wpa/2.0/src/common/gas.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/gas.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,37 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+				       u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */

Deleted: vendor/wpa/2.0/src/common/ieee802_11_common.c
===================================================================
--- vendor/wpa/dist/src/common/ieee802_11_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/ieee802_11_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,326 +0,0 @@
-/*
- * IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "ieee802_11_defs.h"
-#include "ieee802_11_common.h"
-
-
-static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
-					    struct ieee802_11_elems *elems,
-					    int show_errors)
-{
-	unsigned int oui;
-
-	/* first 3 bytes in vendor specific information element are the IEEE
-	 * OUI of the vendor. The following byte is used a vendor specific
-	 * sub-type. */
-	if (elen < 4) {
-		if (show_errors) {
-			wpa_printf(MSG_MSGDUMP, "short vendor specific "
-				   "information element ignored (len=%lu)",
-				   (unsigned long) elen);
-		}
-		return -1;
-	}
-
-	oui = WPA_GET_BE24(pos);
-	switch (oui) {
-	case OUI_MICROSOFT:
-		/* Microsoft/Wi-Fi information elements are further typed and
-		 * subtyped */
-		switch (pos[3]) {
-		case 1:
-			/* Microsoft OUI (00:50:F2) with OUI Type 1:
-			 * real WPA information element */
-			elems->wpa_ie = pos;
-			elems->wpa_ie_len = elen;
-			break;
-		case WMM_OUI_TYPE:
-			/* WMM information element */
-			if (elen < 5) {
-				wpa_printf(MSG_MSGDUMP, "short WMM "
-					   "information element ignored "
-					   "(len=%lu)",
-					   (unsigned long) elen);
-				return -1;
-			}
-			switch (pos[4]) {
-			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
-			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
-				/*
-				 * Share same pointer since only one of these
-				 * is used and they start with same data.
-				 * Length field can be used to distinguish the
-				 * IEs.
-				 */
-				elems->wmm = pos;
-				elems->wmm_len = elen;
-				break;
-			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
-				elems->wmm_tspec = pos;
-				elems->wmm_tspec_len = elen;
-				break;
-			default:
-				wpa_printf(MSG_MSGDUMP, "unknown WMM "
-					   "information element ignored "
-					   "(subtype=%d len=%lu)",
-					   pos[4], (unsigned long) elen);
-				return -1;
-			}
-			break;
-		case 4:
-			/* Wi-Fi Protected Setup (WPS) IE */
-			elems->wps_ie = pos;
-			elems->wps_ie_len = elen;
-			break;
-		default:
-			wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
-				   "information element ignored "
-				   "(type=%d len=%lu)\n",
-				   pos[3], (unsigned long) elen);
-			return -1;
-		}
-		break;
-
-	case OUI_BROADCOM:
-		switch (pos[3]) {
-		case VENDOR_HT_CAPAB_OUI_TYPE:
-			elems->vendor_ht_cap = pos;
-			elems->vendor_ht_cap_len = elen;
-			break;
-		default:
-			wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
-				   "information element ignored "
-				   "(type=%d len=%lu)\n",
-				   pos[3], (unsigned long) elen);
-			return -1;
-		}
-		break;
-
-	default:
-		wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
-			   "element ignored (vendor OUI %02x:%02x:%02x "
-			   "len=%lu)",
-			   pos[0], pos[1], pos[2], (unsigned long) elen);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * ieee802_11_parse_elems - Parse information elements in management frames
- * @start: Pointer to the start of IEs
- * @len: Length of IE buffer in octets
- * @elems: Data structure for parsed elements
- * @show_errors: Whether to show parsing errors in debug log
- * Returns: Parsing result
- */
-ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
-				struct ieee802_11_elems *elems,
-				int show_errors)
-{
-	size_t left = len;
-	const u8 *pos = start;
-	int unknown = 0;
-
-	os_memset(elems, 0, sizeof(*elems));
-
-	while (left >= 2) {
-		u8 id, elen;
-
-		id = *pos++;
-		elen = *pos++;
-		left -= 2;
-
-		if (elen > left) {
-			if (show_errors) {
-				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
-					   "parse failed (id=%d elen=%d "
-					   "left=%lu)",
-					   id, elen, (unsigned long) left);
-				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
-			}
-			return ParseFailed;
-		}
-
-		switch (id) {
-		case WLAN_EID_SSID:
-			elems->ssid = pos;
-			elems->ssid_len = elen;
-			break;
-		case WLAN_EID_SUPP_RATES:
-			elems->supp_rates = pos;
-			elems->supp_rates_len = elen;
-			break;
-		case WLAN_EID_FH_PARAMS:
-			elems->fh_params = pos;
-			elems->fh_params_len = elen;
-			break;
-		case WLAN_EID_DS_PARAMS:
-			elems->ds_params = pos;
-			elems->ds_params_len = elen;
-			break;
-		case WLAN_EID_CF_PARAMS:
-			elems->cf_params = pos;
-			elems->cf_params_len = elen;
-			break;
-		case WLAN_EID_TIM:
-			elems->tim = pos;
-			elems->tim_len = elen;
-			break;
-		case WLAN_EID_IBSS_PARAMS:
-			elems->ibss_params = pos;
-			elems->ibss_params_len = elen;
-			break;
-		case WLAN_EID_CHALLENGE:
-			elems->challenge = pos;
-			elems->challenge_len = elen;
-			break;
-		case WLAN_EID_ERP_INFO:
-			elems->erp_info = pos;
-			elems->erp_info_len = elen;
-			break;
-		case WLAN_EID_EXT_SUPP_RATES:
-			elems->ext_supp_rates = pos;
-			elems->ext_supp_rates_len = elen;
-			break;
-		case WLAN_EID_VENDOR_SPECIFIC:
-			if (ieee802_11_parse_vendor_specific(pos, elen,
-							     elems,
-							     show_errors))
-				unknown++;
-			break;
-		case WLAN_EID_RSN:
-			elems->rsn_ie = pos;
-			elems->rsn_ie_len = elen;
-			break;
-		case WLAN_EID_PWR_CAPABILITY:
-			elems->power_cap = pos;
-			elems->power_cap_len = elen;
-			break;
-		case WLAN_EID_SUPPORTED_CHANNELS:
-			elems->supp_channels = pos;
-			elems->supp_channels_len = elen;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			elems->mdie = pos;
-			elems->mdie_len = elen;
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			elems->ftie = pos;
-			elems->ftie_len = elen;
-			break;
-		case WLAN_EID_TIMEOUT_INTERVAL:
-			elems->timeout_int = pos;
-			elems->timeout_int_len = elen;
-			break;
-		case WLAN_EID_HT_CAP:
-			elems->ht_capabilities = pos;
-			elems->ht_capabilities_len = elen;
-			break;
-		case WLAN_EID_HT_OPERATION:
-			elems->ht_operation = pos;
-			elems->ht_operation_len = elen;
-			break;
-		default:
-			unknown++;
-			if (!show_errors)
-				break;
-			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
-				   "ignored unknown element (id=%d elen=%d)",
-				   id, elen);
-			break;
-		}
-
-		left -= elen;
-		pos += elen;
-	}
-
-	if (left)
-		return ParseFailed;
-
-	return unknown ? ParseUnknown : ParseOK;
-}
-
-
-int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
-{
-	int count = 0;
-	const u8 *pos, *end;
-
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-
-	while (pos + 2 <= end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		count++;
-		pos += 2 + pos[1];
-	}
-
-	return count;
-}
-
-
-struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
-					    u32 oui_type)
-{
-	struct wpabuf *buf;
-	const u8 *end, *pos, *ie;
-
-	pos = ies;
-	end = ies + ies_len;
-	ie = NULL;
-
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			return NULL;
-		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    WPA_GET_BE32(&pos[2]) == oui_type) {
-			ie = pos;
-			break;
-		}
-		pos += 2 + pos[1];
-	}
-
-	if (ie == NULL)
-		return NULL; /* No specified vendor IE found */
-
-	buf = wpabuf_alloc(ies_len);
-	if (buf == NULL)
-		return NULL;
-
-	/*
-	 * 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)
-			break;
-		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    WPA_GET_BE32(&pos[2]) == oui_type)
-			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
-		pos += 2 + pos[1];
-	}
-
-	return buf;
-}

Copied: vendor/wpa/2.0/src/common/ieee802_11_common.c (from rev 9639, vendor/wpa/dist/src/common/ieee802_11_common.c)
===================================================================
--- vendor/wpa/2.0/src/common/ieee802_11_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/common/ieee802_11_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,488 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2012, Jouni Malinen <j at 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 "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+
+
+static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
+					    struct ieee802_11_elems *elems,
+					    int show_errors)
+{
+	unsigned int oui;
+
+	/* first 3 bytes in vendor specific information element are the IEEE
+	 * OUI of the vendor. The following byte is used a vendor specific
+	 * sub-type. */
+	if (elen < 4) {
+		if (show_errors) {
+			wpa_printf(MSG_MSGDUMP, "short vendor specific "
+				   "information element ignored (len=%lu)",
+				   (unsigned long) elen);
+		}
+		return -1;
+	}
+
+	oui = WPA_GET_BE24(pos);
+	switch (oui) {
+	case OUI_MICROSOFT:
+		/* Microsoft/Wi-Fi information elements are further typed and
+		 * subtyped */
+		switch (pos[3]) {
+		case 1:
+			/* Microsoft OUI (00:50:F2) with OUI Type 1:
+			 * real WPA information element */
+			elems->wpa_ie = pos;
+			elems->wpa_ie_len = elen;
+			break;
+		case WMM_OUI_TYPE:
+			/* WMM information element */
+			if (elen < 5) {
+				wpa_printf(MSG_MSGDUMP, "short WMM "
+					   "information element ignored "
+					   "(len=%lu)",
+					   (unsigned long) elen);
+				return -1;
+			}
+			switch (pos[4]) {
+			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
+			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
+				/*
+				 * Share same pointer since only one of these
+				 * is used and they start with same data.
+				 * Length field can be used to distinguish the
+				 * IEs.
+				 */
+				elems->wmm = pos;
+				elems->wmm_len = elen;
+				break;
+			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
+				elems->wmm_tspec = pos;
+				elems->wmm_tspec_len = elen;
+				break;
+			default:
+				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
+					   "information element ignored "
+					   "(subtype=%d len=%lu)",
+					   pos[4], (unsigned long) elen);
+				return -1;
+			}
+			break;
+		case 4:
+			/* Wi-Fi Protected Setup (WPS) IE */
+			elems->wps_ie = pos;
+			elems->wps_ie_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
+				   "information element ignored "
+				   "(type=%d len=%lu)",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_WFA:
+		switch (pos[3]) {
+		case P2P_OUI_TYPE:
+			/* Wi-Fi Alliance - P2P IE */
+			elems->p2p = pos;
+			elems->p2p_len = elen;
+			break;
+		case WFD_OUI_TYPE:
+			/* Wi-Fi Alliance - WFD IE */
+			elems->wfd = pos;
+			elems->wfd_len = elen;
+			break;
+		case HS20_INDICATION_OUI_TYPE:
+			/* Hotspot 2.0 */
+			elems->hs20 = pos;
+			elems->hs20_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
+				   "information element ignored "
+				   "(type=%d len=%lu)\n",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_BROADCOM:
+		switch (pos[3]) {
+		case VENDOR_HT_CAPAB_OUI_TYPE:
+			elems->vendor_ht_cap = pos;
+			elems->vendor_ht_cap_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
+				   "information element ignored "
+				   "(type=%d len=%lu)",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	default:
+		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
+			   "information element ignored (vendor OUI "
+			   "%02x:%02x:%02x len=%lu)",
+			   pos[0], pos[1], pos[2], (unsigned long) elen);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+				struct ieee802_11_elems *elems,
+				int show_errors)
+{
+	size_t left = len;
+	const u8 *pos = start;
+	int unknown = 0;
+
+	os_memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left) {
+			if (show_errors) {
+				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
+					   "parse failed (id=%d elen=%d "
+					   "left=%lu)",
+					   id, elen, (unsigned long) left);
+				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
+			}
+			return ParseFailed;
+		}
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			elems->fh_params = pos;
+			elems->fh_params_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+			elems->cf_params = pos;
+			elems->cf_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (ieee802_11_parse_vendor_specific(pos, elen,
+							     elems,
+							     show_errors))
+				unknown++;
+			break;
+		case WLAN_EID_RSN:
+			elems->rsn_ie = pos;
+			elems->rsn_ie_len = elen;
+			break;
+		case WLAN_EID_PWR_CAPABILITY:
+			elems->power_cap = pos;
+			elems->power_cap_len = elen;
+			break;
+		case WLAN_EID_SUPPORTED_CHANNELS:
+			elems->supp_channels = pos;
+			elems->supp_channels_len = elen;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			elems->mdie = pos;
+			elems->mdie_len = elen;
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			elems->ftie = pos;
+			elems->ftie_len = elen;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			elems->timeout_int = pos;
+			elems->timeout_int_len = elen;
+			break;
+		case WLAN_EID_HT_CAP:
+			elems->ht_capabilities = pos;
+			elems->ht_capabilities_len = elen;
+			break;
+		case WLAN_EID_HT_OPERATION:
+			elems->ht_operation = pos;
+			elems->ht_operation_len = elen;
+			break;
+		case WLAN_EID_VHT_CAP:
+			elems->vht_capabilities = pos;
+			elems->vht_capabilities_len = elen;
+			break;
+		case WLAN_EID_VHT_OPERATION:
+			elems->vht_operation = pos;
+			elems->vht_operation_len = elen;
+			break;
+		case WLAN_EID_LINK_ID:
+			if (elen < 18)
+				break;
+			elems->link_id = pos;
+			break;
+		case WLAN_EID_INTERWORKING:
+			elems->interworking = pos;
+			elems->interworking_len = elen;
+			break;
+		case WLAN_EID_EXT_CAPAB:
+			elems->ext_capab = pos;
+			elems->ext_capab_len = elen;
+			break;
+		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+			if (elen < 3)
+				break;
+			elems->bss_max_idle_period = pos;
+			break;
+		case WLAN_EID_SSID_LIST:
+			elems->ssid_list = pos;
+			elems->ssid_list_len = elen;
+			break;
+		default:
+			unknown++;
+			if (!show_errors)
+				break;
+			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
+				   "ignored unknown element (id=%d elen=%d)",
+				   id, elen);
+			break;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+
+	if (left)
+		return ParseFailed;
+
+	return unknown ? ParseUnknown : ParseOK;
+}
+
+
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
+{
+	int count = 0;
+	const u8 *pos, *end;
+
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+
+	while (pos + 2 <= end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		count++;
+		pos += 2 + pos[1];
+	}
+
+	return count;
+}
+
+
+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
+					    u32 oui_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos, *ie;
+
+	pos = ies;
+	end = ies + ies_len;
+	ie = NULL;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			return NULL;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    WPA_GET_BE32(&pos[2]) == oui_type) {
+			ie = pos;
+			break;
+		}
+		pos += 2 + pos[1];
+	}
+
+	if (ie == NULL)
+		return NULL; /* No specified vendor IE found */
+
+	buf = wpabuf_alloc(ies_len);
+	if (buf == NULL)
+		return NULL;
+
+	/*
+	 * 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)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    WPA_GET_BE32(&pos[2]) == oui_type)
+			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	return buf;
+}
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc, type, stype;
+
+	/*
+	 * PS-Poll frames are 16 bytes. All other frames are
+	 * 24 bytes or longer.
+	 */
+	if (len < 16)
+		return NULL;
+
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	switch (type) {
+	case WLAN_FC_TYPE_DATA:
+		if (len < 24)
+			return NULL;
+		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+		case WLAN_FC_FROMDS | WLAN_FC_TODS:
+		case WLAN_FC_TODS:
+			return hdr->addr1;
+		case WLAN_FC_FROMDS:
+			return hdr->addr2;
+		default:
+			return NULL;
+		}
+	case WLAN_FC_TYPE_CTRL:
+		if (stype != WLAN_FC_STYPE_PSPOLL)
+			return NULL;
+		return hdr->addr1;
+	case WLAN_FC_TYPE_MGMT:
+		return hdr->addr3;
+	default:
+		return NULL;
+	}
+}
+
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+			  const char *name, const char *val)
+{
+	int num, v;
+	const char *pos;
+	struct hostapd_wmm_ac_params *ac;
+
+	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
+	pos = name + 7;
+	if (os_strncmp(pos, "be_", 3) == 0) {
+		num = 0;
+		pos += 3;
+	} else if (os_strncmp(pos, "bk_", 3) == 0) {
+		num = 1;
+		pos += 3;
+	} else if (os_strncmp(pos, "vi_", 3) == 0) {
+		num = 2;
+		pos += 3;
+	} else if (os_strncmp(pos, "vo_", 3) == 0) {
+		num = 3;
+		pos += 3;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
+		return -1;
+	}
+
+	ac = &wmm_ac_params[num];
+
+	if (os_strcmp(pos, "aifs") == 0) {
+		v = atoi(val);
+		if (v < 1 || v > 255) {
+			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+			return -1;
+		}
+		ac->aifs = v;
+	} else if (os_strcmp(pos, "cwmin") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
+			return -1;
+		}
+		ac->cwmin = v;
+	} else if (os_strcmp(pos, "cwmax") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+			return -1;
+		}
+		ac->cwmax = v;
+	} else if (os_strcmp(pos, "txop_limit") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 0xffff) {
+			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+			return -1;
+		}
+		ac->txop_limit = v;
+	} else if (os_strcmp(pos, "acm") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 1) {
+			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+			return -1;
+		}
+		ac->admission_control_mandatory = v;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/common/ieee802_11_common.h
===================================================================
--- vendor/wpa/dist/src/common/ieee802_11_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/ieee802_11_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,78 +0,0 @@
-/*
- * IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IEEE802_11_COMMON_H
-#define IEEE802_11_COMMON_H
-
-/* Parsed Information Elements */
-struct ieee802_11_elems {
-	const u8 *ssid;
-	const u8 *supp_rates;
-	const u8 *fh_params;
-	const u8 *ds_params;
-	const u8 *cf_params;
-	const u8 *tim;
-	const u8 *ibss_params;
-	const u8 *challenge;
-	const u8 *erp_info;
-	const u8 *ext_supp_rates;
-	const u8 *wpa_ie;
-	const u8 *rsn_ie;
-	const u8 *wmm; /* WMM Information or Parameter Element */
-	const u8 *wmm_tspec;
-	const u8 *wps_ie;
-	const u8 *power_cap;
-	const u8 *supp_channels;
-	const u8 *mdie;
-	const u8 *ftie;
-	const u8 *timeout_int;
-	const u8 *ht_capabilities;
-	const u8 *ht_operation;
-	const u8 *vendor_ht_cap;
-
-	u8 ssid_len;
-	u8 supp_rates_len;
-	u8 fh_params_len;
-	u8 ds_params_len;
-	u8 cf_params_len;
-	u8 tim_len;
-	u8 ibss_params_len;
-	u8 challenge_len;
-	u8 erp_info_len;
-	u8 ext_supp_rates_len;
-	u8 wpa_ie_len;
-	u8 rsn_ie_len;
-	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
-	u8 wmm_tspec_len;
-	u8 wps_ie_len;
-	u8 power_cap_len;
-	u8 supp_channels_len;
-	u8 mdie_len;
-	u8 ftie_len;
-	u8 timeout_int_len;
-	u8 ht_capabilities_len;
-	u8 ht_operation_len;
-	u8 vendor_ht_cap_len;
-};
-
-typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
-
-ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
-				struct ieee802_11_elems *elems,
-				int show_errors);
-int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
-struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
-					    u32 oui_type);
-
-#endif /* IEEE802_11_COMMON_H */

Copied: vendor/wpa/2.0/src/common/ieee802_11_common.h (from rev 9639, vendor/wpa/dist/src/common/ieee802_11_common.h)
===================================================================
--- vendor/wpa/2.0/src/common/ieee802_11_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/ieee802_11_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,103 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_COMMON_H
+#define IEEE802_11_COMMON_H
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	const u8 *ssid;
+	const u8 *supp_rates;
+	const u8 *fh_params;
+	const u8 *ds_params;
+	const u8 *cf_params;
+	const u8 *tim;
+	const u8 *ibss_params;
+	const u8 *challenge;
+	const u8 *erp_info;
+	const u8 *ext_supp_rates;
+	const u8 *wpa_ie;
+	const u8 *rsn_ie;
+	const u8 *wmm; /* WMM Information or Parameter Element */
+	const u8 *wmm_tspec;
+	const u8 *wps_ie;
+	const u8 *power_cap;
+	const u8 *supp_channels;
+	const u8 *mdie;
+	const u8 *ftie;
+	const u8 *timeout_int;
+	const u8 *ht_capabilities;
+	const u8 *ht_operation;
+	const u8 *vht_capabilities;
+	const u8 *vht_operation;
+	const u8 *vendor_ht_cap;
+	const u8 *p2p;
+	const u8 *wfd;
+	const u8 *link_id;
+	const u8 *interworking;
+	const u8 *hs20;
+	const u8 *ext_capab;
+	const u8 *bss_max_idle_period;
+	const u8 *ssid_list;
+
+	u8 ssid_len;
+	u8 supp_rates_len;
+	u8 fh_params_len;
+	u8 ds_params_len;
+	u8 cf_params_len;
+	u8 tim_len;
+	u8 ibss_params_len;
+	u8 challenge_len;
+	u8 erp_info_len;
+	u8 ext_supp_rates_len;
+	u8 wpa_ie_len;
+	u8 rsn_ie_len;
+	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
+	u8 wmm_tspec_len;
+	u8 wps_ie_len;
+	u8 power_cap_len;
+	u8 supp_channels_len;
+	u8 mdie_len;
+	u8 ftie_len;
+	u8 timeout_int_len;
+	u8 ht_capabilities_len;
+	u8 ht_operation_len;
+	u8 vht_capabilities_len;
+	u8 vht_operation_len;
+	u8 vendor_ht_cap_len;
+	u8 p2p_len;
+	u8 wfd_len;
+	u8 interworking_len;
+	u8 hs20_len;
+	u8 ext_capab_len;
+	u8 ssid_list_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+				struct ieee802_11_elems *elems,
+				int show_errors);
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
+					    u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
+
+struct hostapd_wmm_ac_params {
+	int cwmin;
+	int cwmax;
+	int aifs;
+	int txop_limit; /* in units of 32us */
+	int admission_control_mandatory;
+};
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+			  const char *name, const char *val);
+
+#endif /* IEEE802_11_COMMON_H */

Deleted: vendor/wpa/2.0/src/common/ieee802_11_defs.h
===================================================================
--- vendor/wpa/dist/src/common/ieee802_11_defs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/ieee802_11_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,607 +0,0 @@
-/*
- * IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2007-2008 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IEEE802_11_DEFS_H
-#define IEEE802_11_DEFS_H
-
-/* IEEE 802.11 defines */
-
-#define WLAN_FC_PVER		0x0003
-#define WLAN_FC_TODS		0x0100
-#define WLAN_FC_FROMDS		0x0200
-#define WLAN_FC_MOREFRAG	0x0400
-#define WLAN_FC_RETRY		0x0800
-#define WLAN_FC_PWRMGT		0x1000
-#define WLAN_FC_MOREDATA	0x2000
-#define WLAN_FC_ISWEP		0x4000
-#define WLAN_FC_ORDER		0x8000
-
-#define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
-#define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
-#define WLAN_GET_SEQ_SEQ(seq) \
-	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
-
-#define WLAN_FC_TYPE_MGMT		0
-#define WLAN_FC_TYPE_CTRL		1
-#define WLAN_FC_TYPE_DATA		2
-
-/* management */
-#define WLAN_FC_STYPE_ASSOC_REQ		0
-#define WLAN_FC_STYPE_ASSOC_RESP	1
-#define WLAN_FC_STYPE_REASSOC_REQ	2
-#define WLAN_FC_STYPE_REASSOC_RESP	3
-#define WLAN_FC_STYPE_PROBE_REQ		4
-#define WLAN_FC_STYPE_PROBE_RESP	5
-#define WLAN_FC_STYPE_BEACON		8
-#define WLAN_FC_STYPE_ATIM		9
-#define WLAN_FC_STYPE_DISASSOC		10
-#define WLAN_FC_STYPE_AUTH		11
-#define WLAN_FC_STYPE_DEAUTH		12
-#define WLAN_FC_STYPE_ACTION		13
-
-/* control */
-#define WLAN_FC_STYPE_PSPOLL		10
-#define WLAN_FC_STYPE_RTS		11
-#define WLAN_FC_STYPE_CTS		12
-#define WLAN_FC_STYPE_ACK		13
-#define WLAN_FC_STYPE_CFEND		14
-#define WLAN_FC_STYPE_CFENDACK		15
-
-/* data */
-#define WLAN_FC_STYPE_DATA		0
-#define WLAN_FC_STYPE_DATA_CFACK	1
-#define WLAN_FC_STYPE_DATA_CFPOLL	2
-#define WLAN_FC_STYPE_DATA_CFACKPOLL	3
-#define WLAN_FC_STYPE_NULLFUNC		4
-#define WLAN_FC_STYPE_CFACK		5
-#define WLAN_FC_STYPE_CFPOLL		6
-#define WLAN_FC_STYPE_CFACKPOLL		7
-#define WLAN_FC_STYPE_QOS_DATA		8
-
-/* Authentication algorithms */
-#define WLAN_AUTH_OPEN			0
-#define WLAN_AUTH_SHARED_KEY		1
-#define WLAN_AUTH_FT			2
-#define WLAN_AUTH_LEAP			128
-
-#define WLAN_AUTH_CHALLENGE_LEN 128
-
-#define WLAN_CAPABILITY_ESS BIT(0)
-#define WLAN_CAPABILITY_IBSS BIT(1)
-#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
-#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
-#define WLAN_CAPABILITY_PRIVACY BIT(4)
-#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
-#define WLAN_CAPABILITY_PBCC BIT(6)
-#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
-#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
-#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
-#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
-
-/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
-#define WLAN_STATUS_SUCCESS 0
-#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
-#define WLAN_STATUS_CAPS_UNSUPPORTED 10
-#define WLAN_STATUS_REASSOC_NO_ASSOC 11
-#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
-#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
-#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
-#define WLAN_STATUS_CHALLENGE_FAIL 15
-#define WLAN_STATUS_AUTH_TIMEOUT 16
-#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
-#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* IEEE 802.11b */
-#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11h */
-#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
-#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
-#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
-/* IEEE 802.11g */
-#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
-#define WLAN_STATUS_R0KH_UNREACHABLE 28
-/* IEEE 802.11w */
-#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
-#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
-#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
-#define WLAN_STATUS_REQUEST_DECLINED 37
-#define WLAN_STATUS_INVALID_PARAMETERS 38
-/* IEEE 802.11i */
-#define WLAN_STATUS_INVALID_IE 40
-#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
-#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
-#define WLAN_STATUS_AKMP_NOT_VALID 43
-#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
-#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
-#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
-#define WLAN_STATUS_TS_NOT_CREATED 47
-#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
-#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
-#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
-#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
-/* IEEE 802.11r */
-#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
-#define WLAN_STATUS_INVALID_PMKID 53
-#define WLAN_STATUS_INVALID_MDIE 54
-#define WLAN_STATUS_INVALID_FTIE 55
-
-/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
-#define WLAN_REASON_UNSPECIFIED 1
-#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
-#define WLAN_REASON_DEAUTH_LEAVING 3
-#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
-#define WLAN_REASON_DISASSOC_AP_BUSY 5
-#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
-#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
-#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11h */
-#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
-#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
-/* IEEE 802.11i */
-#define WLAN_REASON_INVALID_IE 13
-#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
-#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
-#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
-#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
-#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
-#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
-#define WLAN_REASON_AKMP_NOT_VALID 20
-#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
-#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
-#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
-#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
-
-
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#define WLAN_EID_TIM 5
-#define WLAN_EID_IBSS_PARAMS 6
-#define WLAN_EID_COUNTRY 7
-#define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
-#define WLAN_EID_PWR_CONSTRAINT 32
-#define WLAN_EID_PWR_CAPABILITY 33
-#define WLAN_EID_TPC_REQUEST 34
-#define WLAN_EID_TPC_REPORT 35
-#define WLAN_EID_SUPPORTED_CHANNELS 36
-#define WLAN_EID_CHANNEL_SWITCH 37
-#define WLAN_EID_MEASURE_REQUEST 38
-#define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
-#define WLAN_EID_IBSS_DFS 41
-/* EIDs defined by IEEE 802.11h - END */
-#define WLAN_EID_ERP_INFO 42
-#define WLAN_EID_HT_CAP 45
-#define WLAN_EID_RSN 48
-#define WLAN_EID_EXT_SUPP_RATES 50
-#define WLAN_EID_MOBILITY_DOMAIN 54
-#define WLAN_EID_FAST_BSS_TRANSITION 55
-#define WLAN_EID_TIMEOUT_INTERVAL 56
-#define WLAN_EID_RIC_DATA 57
-#define WLAN_EID_HT_OPERATION 61
-#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
-#define WLAN_EID_20_40_BSS_COEXISTENCE 72
-#define WLAN_EID_20_40_BSS_INTOLERANT 73
-#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
-#define WLAN_EID_MMIE 76
-#define WLAN_EID_VENDOR_SPECIFIC 221
-
-
-/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
-#define WLAN_ACTION_SPECTRUM_MGMT 0
-#define WLAN_ACTION_QOS 1
-#define WLAN_ACTION_DLS 2
-#define WLAN_ACTION_BLOCK_ACK 3
-#define WLAN_ACTION_PUBLIC 4
-#define WLAN_ACTION_RADIO_MEASUREMENT 5
-#define WLAN_ACTION_FT 6
-#define WLAN_ACTION_HT 7
-#define WLAN_ACTION_SA_QUERY 8
-#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
-
-/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
-#define WLAN_SA_QUERY_REQUEST 0
-#define WLAN_SA_QUERY_RESPONSE 1
-
-#define WLAN_SA_QUERY_TR_ID_LEN 2
-
-/* Timeout Interval Type */
-#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
-#define WLAN_TIMEOUT_KEY_LIFETIME 2
-#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
-
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee80211_hdr {
-	le16 frame_control;
-	le16 duration_id;
-	u8 addr1[6];
-	u8 addr2[6];
-	u8 addr3[6];
-	le16 seq_ctrl;
-	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
-	 */
-} STRUCT_PACKED;
-
-#define IEEE80211_DA_FROMDS addr1
-#define IEEE80211_BSSID_FROMDS addr2
-#define IEEE80211_SA_FROMDS addr3
-
-#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
-
-#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
-
-struct ieee80211_mgmt {
-	le16 frame_control;
-	le16 duration;
-	u8 da[6];
-	u8 sa[6];
-	u8 bssid[6];
-	le16 seq_ctrl;
-	union {
-		struct {
-			le16 auth_alg;
-			le16 auth_transaction;
-			le16 status_code;
-			/* possibly followed by Challenge text */
-			u8 variable[0];
-		} STRUCT_PACKED auth;
-		struct {
-			le16 reason_code;
-		} STRUCT_PACKED deauth;
-		struct {
-			le16 capab_info;
-			le16 listen_interval;
-			/* followed by SSID and Supported rates */
-			u8 variable[0];
-		} STRUCT_PACKED assoc_req;
-		struct {
-			le16 capab_info;
-			le16 status_code;
-			le16 aid;
-			/* followed by Supported rates */
-			u8 variable[0];
-		} STRUCT_PACKED assoc_resp, reassoc_resp;
-		struct {
-			le16 capab_info;
-			le16 listen_interval;
-			u8 current_ap[6];
-			/* followed by SSID and Supported rates */
-			u8 variable[0];
-		} STRUCT_PACKED reassoc_req;
-		struct {
-			le16 reason_code;
-		} STRUCT_PACKED disassoc;
-		struct {
-			u8 timestamp[8];
-			le16 beacon_int;
-			le16 capab_info;
-			/* followed by some of SSID, Supported rates,
-			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
-			u8 variable[0];
-		} STRUCT_PACKED beacon;
-		struct {
-			/* only variable items: SSID, Supported rates */
-			u8 variable[0];
-		} STRUCT_PACKED probe_req;
-		struct {
-			u8 timestamp[8];
-			le16 beacon_int;
-			le16 capab_info;
-			/* followed by some of SSID, Supported rates,
-			 * FH Params, DS Params, CF Params, IBSS Params */
-			u8 variable[0];
-		} STRUCT_PACKED probe_resp;
-		struct {
-			u8 category;
-			union {
-				struct {
-					u8 action_code;
-					u8 dialog_token;
-					u8 status_code;
-					u8 variable[0];
-				} STRUCT_PACKED wmm_action;
-				struct{
-					u8 action_code;
-					u8 element_id;
-					u8 length;
-					u8 switch_mode;
-					u8 new_chan;
-					u8 switch_count;
-				} STRUCT_PACKED chan_switch;
-				struct {
-					u8 action;
-					u8 sta_addr[ETH_ALEN];
-					u8 target_ap_addr[ETH_ALEN];
-					u8 variable[0]; /* FT Request */
-				} STRUCT_PACKED ft_action_req;
-				struct {
-					u8 action;
-					u8 sta_addr[ETH_ALEN];
-					u8 target_ap_addr[ETH_ALEN];
-					le16 status_code;
-					u8 variable[0]; /* FT Request */
-				} STRUCT_PACKED ft_action_resp;
-				struct {
-					u8 action;
-					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
-				} STRUCT_PACKED sa_query_req;
-				struct {
-					u8 action; /* */
-					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
-				} STRUCT_PACKED sa_query_resp;
-			} u;
-		} STRUCT_PACKED action;
-	} u;
-} STRUCT_PACKED;
-
-
-struct ieee80211_ht_capabilities {
-	le16 ht_capabilities_info;
-	u8 a_mpdu_params;
-	u8 supported_mcs_set[16];
-	le16 ht_extended_capabilities;
-	le32 tx_bf_capability_info;
-	u8 asel_capabilities;
-} STRUCT_PACKED;
-
-
-struct ieee80211_ht_operation {
-	u8 control_chan;
-	u8 ht_param;
-	le16 operation_mode;
-	le16 stbc_param;
-	u8 basic_set[16];
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define ERP_INFO_NON_ERP_PRESENT BIT(0)
-#define ERP_INFO_USE_PROTECTION BIT(1)
-#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
-
-
-#define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
-#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
-#define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
-#define HT_CAP_INFO_SMPS_STATIC			((u16) 0)
-#define HT_CAP_INFO_SMPS_DYNAMIC		((u16) BIT(2))
-#define HT_CAP_INFO_SMPS_DISABLED		((u16) (BIT(2) | BIT(3)))
-#define HT_CAP_INFO_GREEN_FIELD			((u16) BIT(4))
-#define HT_CAP_INFO_SHORT_GI20MHZ		((u16) BIT(5))
-#define HT_CAP_INFO_SHORT_GI40MHZ		((u16) BIT(6))
-#define HT_CAP_INFO_TX_STBC			((u16) BIT(7))
-#define HT_CAP_INFO_RX_STBC_MASK		((u16) (BIT(8) | BIT(9)))
-#define HT_CAP_INFO_RX_STBC_1			((u16) BIT(8))
-#define HT_CAP_INFO_RX_STBC_12			((u16) BIT(9))
-#define HT_CAP_INFO_RX_STBC_123			((u16) (BIT(8) | BIT(9)))
-#define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
-#define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
-#define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
-#define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
-#define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
-#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
-
-
-#define EXT_HT_CAP_INFO_PCO			((u16) BIT(0))
-#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET	1
-#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET	8
-#define EXT_HT_CAP_INFO_HTC_SUPPORTED		((u16) BIT(10))
-#define EXT_HT_CAP_INFO_RD_RESPONDER		((u16) BIT(11))
-
-
-#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
-#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
-#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
-#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
-#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
-#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
-#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
-#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
-#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
-#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
-#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
-#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
-#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
-#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
-
-
-#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
-#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
-#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
-
-#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
-#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
-#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
-#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
-#define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
-#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
-#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
-
-
-#define OP_MODE_PURE                    0
-#define OP_MODE_MAY_BE_LEGACY_STAS      1
-#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
-#define OP_MODE_MIXED                   3
-
-#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
-		((le16) (0x0001 | 0x0002))
-#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
-#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
-#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
-#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
-
-#define HT_INFO_STBC_PARAM_DUAL_BEACON			((u16) BIT(6))
-#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT		((u16) BIT(7))
-#define HT_INFO_STBC_PARAM_SECONDARY_BCN		((u16) BIT(8))
-#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
-#define HT_INFO_STBC_PARAM_PCO_ACTIVE			((u16) BIT(10))
-#define HT_INFO_STBC_PARAM_PCO_PHASE			((u16) BIT(11))
-
-
-#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
-				* 00:50:F2 */
-#define WPA_IE_VENDOR_TYPE 0x0050f201
-#define WPS_IE_VENDOR_TYPE 0x0050f204
-
-#define WMM_OUI_TYPE 2
-#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
-#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
-#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
-#define WMM_VERSION 1
-
-#define WMM_ACTION_CODE_ADDTS_REQ 0
-#define WMM_ACTION_CODE_ADDTS_RESP 1
-#define WMM_ACTION_CODE_DELTS 2
-
-#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
-#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
-/* 2 - Reserved */
-#define WMM_ADDTS_STATUS_REFUSED 3
-/* 4-255 - Reserved */
-
-/* WMM TSPEC Direction Field Values */
-#define WMM_TSPEC_DIRECTION_UPLINK 0
-#define WMM_TSPEC_DIRECTION_DOWNLINK 1
-/* 2 - Reserved */
-#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
-
-/*
- * WMM Information Element (used in (Re)Association Request frames; may also be
- * used in Beacon frames)
- */
-struct wmm_information_element {
-	/* Element ID: 221 (0xdd); Length: 7 */
-	/* required fields for WMM version 1 */
-	u8 oui[3]; /* 00:50:f2 */
-	u8 oui_type; /* 2 */
-	u8 oui_subtype; /* 0 */
-	u8 version; /* 1 for WMM version 1.0 */
-	u8 qos_info; /* AP/STA specific QoS info */
-
-} STRUCT_PACKED;
-
-#define WMM_AC_AIFSN_MASK 0x0f
-#define WMM_AC_AIFNS_SHIFT 0
-#define WMM_AC_ACM 0x10
-#define WMM_AC_ACI_MASK 0x60
-#define WMM_AC_ACI_SHIFT 5
-
-#define WMM_AC_ECWMIN_MASK 0x0f
-#define WMM_AC_ECWMIN_SHIFT 0
-#define WMM_AC_ECWMAX_MASK 0xf0
-#define WMM_AC_ECWMAX_SHIFT 4
-
-struct wmm_ac_parameter {
-	u8 aci_aifsn; /* AIFSN, ACM, ACI */
-	u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
-	le16 txop_limit;
-}  STRUCT_PACKED;
-
-/*
- * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
- * Response frmaes)
- */
-struct wmm_parameter_element {
-	/* Element ID: 221 (0xdd); Length: 24 */
-	/* required fields for WMM version 1 */
-	u8 oui[3]; /* 00:50:f2 */
-	u8 oui_type; /* 2 */
-	u8 oui_subtype; /* 1 */
-	u8 version; /* 1 for WMM version 1.0 */
-	u8 qos_info; /* AP/STA specif QoS info */
-	u8 reserved; /* 0 */
-	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
-
-} STRUCT_PACKED;
-
-/* WMM TSPEC Element */
-struct wmm_tspec_element {
-	u8 eid; /* 221 = 0xdd */
-	u8 length; /* 6 + 55 = 61 */
-	u8 oui[3]; /* 00:50:f2 */
-	u8 oui_type; /* 2 */
-	u8 oui_subtype; /* 2 */
-	u8 version; /* 1 */
-	/* WMM TSPEC body (55 octets): */
-	u8 ts_info[3];
-	le16 nominal_msdu_size;
-	le16 maximum_msdu_size;
-	le32 minimum_service_interval;
-	le32 maximum_service_interval;
-	le32 inactivity_interval;
-	le32 suspension_interval;
-	le32 service_start_time;
-	le32 minimum_data_rate;
-	le32 mean_data_rate;
-	le32 peak_data_rate;
-	le32 maximum_burst_size;
-	le32 delay_bound;
-	le32 minimum_phy_rate;
-	le16 surplus_bandwidth_allowance;
-	le16 medium_time;
-} STRUCT_PACKED;
-
-
-/* Access Categories / ACI to AC coding */
-enum {
-	WMM_AC_BE = 0 /* Best Effort */,
-	WMM_AC_BK = 1 /* Background */,
-	WMM_AC_VI = 2 /* Video */,
-	WMM_AC_VO = 3 /* Voice */
-};
-
-
-#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
-
-#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
-
-/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
-/* reserved: 				0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
-
-/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X		0x000FAC01
-#define WLAN_AKM_SUITE_PSK		0x000FAC02
-
-#endif /* IEEE802_11_DEFS_H */

Copied: vendor/wpa/2.0/src/common/ieee802_11_defs.h (from rev 9639, vendor/wpa/dist/src/common/ieee802_11_defs.h)
===================================================================
--- vendor/wpa/2.0/src/common/ieee802_11_defs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/ieee802_11_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1085 @@
+/*
+ * IEEE 802.11 Frame type definitions
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2008 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_DEFS_H
+#define IEEE802_11_DEFS_H
+
+/* IEEE 802.11 defines */
+
+#define WLAN_FC_PVER		0x0003
+#define WLAN_FC_TODS		0x0100
+#define WLAN_FC_FROMDS		0x0200
+#define WLAN_FC_MOREFRAG	0x0400
+#define WLAN_FC_RETRY		0x0800
+#define WLAN_FC_PWRMGT		0x1000
+#define WLAN_FC_MOREDATA	0x2000
+#define WLAN_FC_ISWEP		0x4000
+#define WLAN_FC_ORDER		0x8000
+
+#define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
+#define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+#define WLAN_GET_SEQ_SEQ(seq) \
+	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
+
+#define WLAN_FC_TYPE_MGMT		0
+#define WLAN_FC_TYPE_CTRL		1
+#define WLAN_FC_TYPE_DATA		2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ		0
+#define WLAN_FC_STYPE_ASSOC_RESP	1
+#define WLAN_FC_STYPE_REASSOC_REQ	2
+#define WLAN_FC_STYPE_REASSOC_RESP	3
+#define WLAN_FC_STYPE_PROBE_REQ		4
+#define WLAN_FC_STYPE_PROBE_RESP	5
+#define WLAN_FC_STYPE_BEACON		8
+#define WLAN_FC_STYPE_ATIM		9
+#define WLAN_FC_STYPE_DISASSOC		10
+#define WLAN_FC_STYPE_AUTH		11
+#define WLAN_FC_STYPE_DEAUTH		12
+#define WLAN_FC_STYPE_ACTION		13
+
+/* control */
+#define WLAN_FC_STYPE_PSPOLL		10
+#define WLAN_FC_STYPE_RTS		11
+#define WLAN_FC_STYPE_CTS		12
+#define WLAN_FC_STYPE_ACK		13
+#define WLAN_FC_STYPE_CFEND		14
+#define WLAN_FC_STYPE_CFENDACK		15
+
+/* data */
+#define WLAN_FC_STYPE_DATA		0
+#define WLAN_FC_STYPE_DATA_CFACK	1
+#define WLAN_FC_STYPE_DATA_CFPOLL	2
+#define WLAN_FC_STYPE_DATA_CFACKPOLL	3
+#define WLAN_FC_STYPE_NULLFUNC		4
+#define WLAN_FC_STYPE_CFACK		5
+#define WLAN_FC_STYPE_CFPOLL		6
+#define WLAN_FC_STYPE_CFACKPOLL		7
+#define WLAN_FC_STYPE_QOS_DATA		8
+#define WLAN_FC_STYPE_QOS_DATA_CFACK	9
+#define WLAN_FC_STYPE_QOS_DATA_CFPOLL	10
+#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL	11
+#define WLAN_FC_STYPE_QOS_NULL		12
+#define WLAN_FC_STYPE_QOS_CFPOLL	14
+#define WLAN_FC_STYPE_QOS_CFACKPOLL	15
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN			0
+#define WLAN_AUTH_SHARED_KEY		1
+#define WLAN_AUTH_FT			2
+#define WLAN_AUTH_SAE			3
+#define WLAN_AUTH_LEAP			128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS BIT(0)
+#define WLAN_CAPABILITY_IBSS BIT(1)
+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
+#define WLAN_CAPABILITY_PRIVACY BIT(4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
+#define WLAN_CAPABILITY_PBCC BIT(6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+
+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
+#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
+#define WLAN_STATUS_SECURITY_DISABLED 5
+#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
+#define WLAN_STATUS_NOT_IN_SAME_BSS 7
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11g */
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
+#define WLAN_STATUS_R0KH_UNREACHABLE 28
+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
+/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_REQUEST_DECLINED 37
+#define WLAN_STATUS_INVALID_PARAMETERS 38
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
+/* IEEE 802.11r */
+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
+#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+
+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+/* IEEE 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+/* IEEE 802.11i */
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
+#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
+/* IEEE 802.11e */
+#define WLAN_REASON_DISASSOC_LOW_ACK 34
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_MOBILITY_DOMAIN 54
+#define WLAN_EID_FAST_BSS_TRANSITION 55
+#define WLAN_EID_TIMEOUT_INTERVAL 56
+#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_HT_OPERATION 61
+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_WAPI 68
+#define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_20_40_BSS_COEXISTENCE 72
+#define WLAN_EID_20_40_BSS_INTOLERANT 73
+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_MMIE 76
+#define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
+#define WLAN_EID_TFS_REQ 91
+#define WLAN_EID_TFS_RESP 92
+#define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
+#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_CCKM 156
+#define WLAN_EID_VHT_CAP 191
+#define WLAN_EID_VHT_OPERATION 192
+#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_VHT_WIDE_BW_CHSWITCH  194
+#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_VHT_AID 197
+#define WLAN_EID_VHT_QUIET_CHANNEL 198
+#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+
+/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+#define WLAN_ACTION_SPECTRUM_MGMT 0
+#define WLAN_ACTION_QOS 1
+#define WLAN_ACTION_DLS 2
+#define WLAN_ACTION_BLOCK_ACK 3
+#define WLAN_ACTION_PUBLIC 4
+#define WLAN_ACTION_RADIO_MEASUREMENT 5
+#define WLAN_ACTION_FT 6
+#define WLAN_ACTION_HT 7
+#define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
+#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
+#define WLAN_ACTION_VENDOR_SPECIFIC 127
+
+/* Public action codes */
+#define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_VENDOR_SPECIFIC 9
+#define WLAN_PA_GAS_INITIAL_REQ 10
+#define WLAN_PA_GAS_INITIAL_RESP 11
+#define WLAN_PA_GAS_COMEBACK_REQ 12
+#define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
+
+/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
+#define WLAN_SA_QUERY_REQUEST 0
+#define WLAN_SA_QUERY_RESPONSE 1
+
+#define WLAN_SA_QUERY_TR_ID_LEN 2
+
+/* TDLS action codes */
+#define WLAN_TDLS_SETUP_REQUEST 0
+#define WLAN_TDLS_SETUP_RESPONSE 1
+#define WLAN_TDLS_SETUP_CONFIRM 2
+#define WLAN_TDLS_TEARDOWN 3
+#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
+#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
+#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
+#define WLAN_TDLS_PEER_PSM_REQUEST 7
+#define WLAN_TDLS_PEER_PSM_RESPONSE 8
+#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
+#define WLAN_TDLS_DISCOVERY_REQUEST 10
+
+/* Timeout Interval Type */
+#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
+#define WLAN_TIMEOUT_KEY_LIFETIME 2
+#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
+
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+enum adv_proto_id {
+	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
+	MIH_INFO_SERVICE = 1,
+	MIH_CMD_AND_EVENT_DISCOVERY = 2,
+	EMERGENCY_ALERT_SYSTEM = 3,
+	ADV_PROTO_VENDOR_SPECIFIC = 221
+};
+
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+	ANQP_QUERY_LIST = 256,
+	ANQP_CAPABILITY_LIST = 257,
+	ANQP_VENUE_NAME = 258,
+	ANQP_EMERGENCY_CALL_NUMBER = 259,
+	ANQP_NETWORK_AUTH_TYPE = 260,
+	ANQP_ROAMING_CONSORTIUM = 261,
+	ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+	ANQP_NAI_REALM = 263,
+	ANQP_3GPP_CELLULAR_NETWORK = 264,
+	ANQP_AP_GEOSPATIAL_LOCATION = 265,
+	ANQP_AP_CIVIC_LOCATION = 266,
+	ANQP_AP_LOCATION_PUBLIC_URI = 267,
+	ANQP_DOMAIN_NAME = 268,
+	ANQP_EMERGENCY_ALERT_URI = 269,
+	ANQP_EMERGENCY_NAI = 271,
+	ANQP_VENDOR_SPECIFIC = 56797
+};
+
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+	NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+	NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+	NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+	NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+	NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+	NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+	NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+	NAI_REALM_INNER_NON_EAP_PAP = 1,
+	NAI_REALM_INNER_NON_EAP_CHAP = 2,
+	NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+	NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+	NAI_REALM_CRED_TYPE_SIM = 1,
+	NAI_REALM_CRED_TYPE_USIM = 2,
+	NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+	NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+	NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+	NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+	NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+	NAI_REALM_CRED_TYPE_NONE = 8,
+	NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee80211_hdr {
+	le16 frame_control;
+	le16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	le16 seq_ctrl;
+	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
+	 */
+} STRUCT_PACKED;
+
+#define IEEE80211_DA_FROMDS addr1
+#define IEEE80211_BSSID_FROMDS addr2
+#define IEEE80211_SA_FROMDS addr3
+
+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
+
+#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
+
+struct ieee80211_mgmt {
+	le16 frame_control;
+	le16 duration;
+	u8 da[6];
+	u8 sa[6];
+	u8 bssid[6];
+	le16 seq_ctrl;
+	union {
+		struct {
+			le16 auth_alg;
+			le16 auth_transaction;
+			le16 status_code;
+			/* possibly followed by Challenge text */
+			u8 variable[0];
+		} STRUCT_PACKED auth;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED deauth;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_req;
+		struct {
+			le16 capab_info;
+			le16 status_code;
+			le16 aid;
+			/* followed by Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_resp, reassoc_resp;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			u8 current_ap[6];
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED reassoc_req;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED disassoc;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			u8 variable[0];
+		} STRUCT_PACKED beacon;
+		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED probe_req;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		} STRUCT_PACKED probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				} STRUCT_PACKED wmm_action;
+				struct{
+					u8 action_code;
+					u8 element_id;
+					u8 length;
+					u8 switch_mode;
+					u8 new_chan;
+					u8 switch_count;
+				} STRUCT_PACKED chan_switch;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_req;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					le16 status_code;
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_resp;
+				struct {
+					u8 action;
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_req;
+				struct {
+					u8 action; /* */
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_resp;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_req;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					le16 keydata_len;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_resp;
+				struct {
+					u8 action;
+					u8 variable[0];
+				} STRUCT_PACKED public_action;
+				struct {
+					u8 action; /* 9 */
+					u8 oui[3];
+					/* Vendor-specific content */
+					u8 variable[0];
+				} STRUCT_PACKED vs_public_action;
+				struct {
+					u8 action; /* 7 */
+					u8 dialog_token;
+					u8 req_mode;
+					le16 disassoc_timer;
+					u8 validity_interval;
+					/* BSS Termination Duration (optional),
+					 * Session Information URL (optional),
+					 * BSS Transition Candidate List
+					 * Entries */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_req;
+				struct {
+					u8 action; /* 8 */
+					u8 dialog_token;
+					u8 status_code;
+					u8 bss_termination_delay;
+					/* Target BSSID (optional),
+					 * BSS Transition Candidate List
+					 * Entries (optional) */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_resp;
+			} u;
+		} STRUCT_PACKED action;
+	} u;
+} STRUCT_PACKED;
+
+
+/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
+#define IEEE80211_HT_MCS_MASK_LEN 10
+
+struct ieee80211_ht_capabilities {
+	le16 ht_capabilities_info;
+	u8 a_mpdu_params;
+	u8 supported_mcs_set[16];
+	le16 ht_extended_capabilities;
+	le32 tx_bf_capability_info;
+	u8 asel_capabilities;
+} STRUCT_PACKED;
+
+
+struct ieee80211_ht_operation {
+	u8 control_chan;
+	u8 ht_param;
+	le16 operation_mode;
+	le16 stbc_param;
+	u8 basic_set[16];
+} STRUCT_PACKED;
+
+
+struct ieee80211_vht_capabilities {
+	le32 vht_capabilities_info;
+	u8 vht_supported_mcs_set[8];
+} STRUCT_PACKED;
+
+struct ieee80211_vht_operation {
+	u8 vht_op_info_chwidth;
+	u8 vht_op_info_chan_center_freq_seg0_idx;
+	u8 vht_op_info_chan_center_freq_seg1_idx;
+	le16 vht_basic_mcs_set;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define ERP_INFO_USE_PROTECTION BIT(1)
+#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
+
+#define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
+#define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_SMPS_STATIC			((u16) 0)
+#define HT_CAP_INFO_SMPS_DYNAMIC		((u16) BIT(2))
+#define HT_CAP_INFO_SMPS_DISABLED		((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_GREEN_FIELD			((u16) BIT(4))
+#define HT_CAP_INFO_SHORT_GI20MHZ		((u16) BIT(5))
+#define HT_CAP_INFO_SHORT_GI40MHZ		((u16) BIT(6))
+#define HT_CAP_INFO_TX_STBC			((u16) BIT(7))
+#define HT_CAP_INFO_RX_STBC_MASK		((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_RX_STBC_1			((u16) BIT(8))
+#define HT_CAP_INFO_RX_STBC_12			((u16) BIT(9))
+#define HT_CAP_INFO_RX_STBC_123			((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
+#define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
+#define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
+#define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
+#define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
+
+
+#define EXT_HT_CAP_INFO_PCO			((u16) BIT(0))
+#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET	1
+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET	8
+#define EXT_HT_CAP_INFO_HTC_SUPPORTED		((u16) BIT(10))
+#define EXT_HT_CAP_INFO_RD_RESPONDER		((u16) BIT(11))
+
+
+#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
+#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
+#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
+#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
+#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
+#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
+#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
+#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
+#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
+#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
+#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
+#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
+#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
+#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
+
+
+#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
+#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
+#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
+
+
+#define OP_MODE_PURE                    0
+#define OP_MODE_MAY_BE_LEGACY_STAS      1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
+#define OP_MODE_MIXED                   3
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
+		(0x0001 | 0x0002)
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON			((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT		((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BCN		((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE			((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE			((u16) BIT(11))
+
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
+/* VHT Defines */
+#define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
+#define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_RXLDPC                              ((u32) BIT(4))
+#define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
+#define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
+#define VHT_CAP_TXSTBC                              ((u32) BIT(7))
+#define VHT_CAP_RXSTBC_1                            ((u32) BIT(8))
+#define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
+#define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
+#define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
+#define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
+#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
+#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
+#define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
+#define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
+#define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
+#define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
+#define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
+
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+				* 00:50:F2 */
+#define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WPS_IE_VENDOR_TYPE 0x0050f204
+#define OUI_WFA 0x506f9a
+#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define WFD_IE_VENDOR_TYPE 0x506f9a0a
+#define WFD_OUI_TYPE 10
+#define HS20_IE_VENDOR_TYPE 0x506f9a10
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define WMM_ACTION_CODE_ADDTS_REQ 0
+#define WMM_ACTION_CODE_ADDTS_RESP 1
+#define WMM_ACTION_CODE_DELTS 2
+
+#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
+#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
+/* 2 - Reserved */
+#define WMM_ADDTS_STATUS_REFUSED 3
+/* 4-255 - Reserved */
+
+/* WMM TSPEC Direction Field Values */
+#define WMM_TSPEC_DIRECTION_UPLINK 0
+#define WMM_TSPEC_DIRECTION_DOWNLINK 1
+/* 2 - Reserved */
+#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+/*
+ * WMM Information Element (used in (Re)Association Request frames; may also be
+ * used in Beacon frames)
+ */
+struct wmm_information_element {
+	/* Element ID: 221 (0xdd); Length: 7 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 0 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+
+} STRUCT_PACKED;
+
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
+#define WMM_AC_AIFSN_MASK 0x0f
+#define WMM_AC_AIFNS_SHIFT 0
+#define WMM_AC_ACM 0x10
+#define WMM_AC_ACI_MASK 0x60
+#define WMM_AC_ACI_SHIFT 5
+
+#define WMM_AC_ECWMIN_MASK 0x0f
+#define WMM_AC_ECWMIN_SHIFT 0
+#define WMM_AC_ECWMAX_MASK 0xf0
+#define WMM_AC_ECWMAX_SHIFT 4
+
+struct wmm_ac_parameter {
+	u8 aci_aifsn; /* AIFSN, ACM, ACI */
+	u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
+	le16 txop_limit;
+}  STRUCT_PACKED;
+
+/*
+ * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
+ * Response frmaes)
+ */
+struct wmm_parameter_element {
+	/* Element ID: 221 (0xdd); Length: 24 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 1 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+	u8 reserved; /* 0 */
+	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
+
+} STRUCT_PACKED;
+
+/* WMM TSPEC Element */
+struct wmm_tspec_element {
+	u8 eid; /* 221 = 0xdd */
+	u8 length; /* 6 + 55 = 61 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 2 */
+	u8 version; /* 1 */
+	/* WMM TSPEC body (55 octets): */
+	u8 ts_info[3];
+	le16 nominal_msdu_size;
+	le16 maximum_msdu_size;
+	le32 minimum_service_interval;
+	le32 maximum_service_interval;
+	le32 inactivity_interval;
+	le32 suspension_interval;
+	le32 service_start_time;
+	le32 minimum_data_rate;
+	le32 mean_data_rate;
+	le32 peak_data_rate;
+	le32 maximum_burst_size;
+	le32 delay_bound;
+	le32 minimum_phy_rate;
+	le16 surplus_bandwidth_allowance;
+	le16 medium_time;
+} STRUCT_PACKED;
+
+
+/* Access Categories / ACI to AC coding */
+enum {
+	WMM_AC_BE = 0 /* Best Effort */,
+	WMM_AC_BK = 1 /* Background */,
+	WMM_AC_VI = 2 /* Video */,
+	WMM_AC_VO = 3 /* Voice */
+};
+
+
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_ANQP_OUI_TYPE 17
+#define HS20_STYPE_QUERY_LIST 1
+#define HS20_STYPE_CAPABILITY_LIST 2
+#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
+#define HS20_STYPE_WAN_METRICS 4
+#define HS20_STYPE_CONNECTION_CAPABILITY 5
+#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
+#define HS20_STYPE_OPERATING_CLASS 7
+
+/* Wi-Fi Direct (P2P) */
+
+#define P2P_OUI_TYPE 9
+
+enum p2p_attr_id {
+	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_VENDOR_SPECIFIC = 221
+};
+
+#define P2P_MAX_GO_INTENT 15
+
+/* P2P Capability - Device Capability bitmap */
+#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
+#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
+#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
+#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
+#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
+#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
+
+/* P2P Capability - Group Capability bitmap */
+#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
+#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
+#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
+#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
+#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
+#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
+#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+
+/* Invitation Flags */
+#define P2P_INVITATION_FLAGS_TYPE BIT(0)
+
+/* P2P Manageability */
+#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
+#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
+#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
+
+enum p2p_status_code {
+	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,
+};
+
+#define P2P_WILDCARD_SSID "DIRECT-"
+#define P2P_WILDCARD_SSID_LEN 7
+
+/* P2P action frames */
+enum p2p_act_frame_type {
+	P2P_NOA = 0,
+	P2P_PRESENCE_REQ = 1,
+	P2P_PRESENCE_RESP = 2,
+	P2P_GO_DISC_REQ = 3
+};
+
+/* P2P public action frames */
+enum p2p_action_frame_type {
+	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
+};
+
+enum p2p_service_protocol_type {
+	P2P_SERV_ALL_SERVICES = 0,
+	P2P_SERV_BONJOUR = 1,
+	P2P_SERV_UPNP = 2,
+	P2P_SERV_WS_DISCOVERY = 3,
+	P2P_SERV_WIFI_DISPLAY = 4,
+	P2P_SERV_VENDOR_SPECIFIC = 255
+};
+
+enum p2p_sd_status {
+	P2P_SD_SUCCESS = 0,
+	P2P_SD_PROTO_NOT_AVAILABLE = 1,
+	P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
+	P2P_SD_BAD_REQUEST = 3
+};
+
+
+enum wifi_display_subelem {
+	WFD_SUBELEM_DEVICE_INFO = 0,
+	WFD_SUBELEM_ASSOCIATED_BSSID = 1,
+	WFD_SUBELEM_AUDIO_FORMATS = 2,
+	WFD_SUBELEM_VIDEO_FORMATS = 3,
+	WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
+	WFD_SUBELEM_CONTENT_PROTECTION = 5,
+	WFD_SUBELEM_COUPLED_SINK = 6,
+	WFD_SUBELEM_EXT_CAPAB = 7,
+	WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
+	WFD_SUBELEM_SESSION_INFO = 9
+};
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
+/* reserved: 				0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
+#define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
+#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR	0x000FAC07
+#define WLAN_CIPHER_SUITE_GCMP		0x000FAC08
+
+#define WLAN_CIPHER_SUITE_SMS4		0x00147201
+
+#define WLAN_CIPHER_SUITE_CKIP		0x00409600
+#define WLAN_CIPHER_SUITE_CKIP_CMIC	0x00409601
+#define WLAN_CIPHER_SUITE_CMIC		0x00409602
+#define WLAN_CIPHER_SUITE_KRK		0x004096FF /* for nl80211 use only */
+
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X		0x000FAC01
+#define WLAN_AKM_SUITE_PSK		0x000FAC02
+#define WLAN_AKM_SUITE_CCKM		0x00409600
+
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
+/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
+#define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
+#define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
+#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ     BIT(2)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ     BIT(3)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT    BIT(4)
+
+struct ieee80211_2040_bss_coex_ie {
+	u8 element_id;
+	u8 length;
+	u8 coex_param;
+} STRUCT_PACKED;
+
+struct ieee80211_2040_intol_chan_report {
+	u8 element_id;
+	u8 length;
+	u8 op_class;
+	u8 variable[0];	/* Channel List */
+} STRUCT_PACKED;
+
+/* IEEE 802.11v - WNM-Sleep Mode element */
+struct wnm_sleep_element {
+	u8 eid;     /* WLAN_EID_WNMSLEEP */
+	u8 len;
+	u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */
+	u8 status;
+	le16 intval;
+} STRUCT_PACKED;
+
+#define WNM_SLEEP_MODE_ENTER 0
+#define WNM_SLEEP_MODE_EXIT 1
+
+enum wnm_sleep_mode_response_status {
+	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 Mode subelement IDs */
+enum wnm_sleep_mode_subelement_id {
+	WNM_SLEEP_SUBELEM_GTK = 0,
+	WNM_SLEEP_SUBELEM_IGTK = 1
+};
+
+#endif /* IEEE802_11_DEFS_H */

Deleted: vendor/wpa/2.0/src/common/privsep_commands.h
===================================================================
--- vendor/wpa/dist/src/common/privsep_commands.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/privsep_commands.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,75 +0,0 @@
-/*
- * WPA Supplicant - privilege separation commands
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PRIVSEP_COMMANDS_H
-#define PRIVSEP_COMMANDS_H
-
-enum privsep_cmd {
-	PRIVSEP_CMD_REGISTER,
-	PRIVSEP_CMD_UNREGISTER,
-	PRIVSEP_CMD_SCAN,
-	PRIVSEP_CMD_GET_SCAN_RESULTS,
-	PRIVSEP_CMD_ASSOCIATE,
-	PRIVSEP_CMD_GET_BSSID,
-	PRIVSEP_CMD_GET_SSID,
-	PRIVSEP_CMD_SET_KEY,
-	PRIVSEP_CMD_GET_CAPA,
-	PRIVSEP_CMD_L2_REGISTER,
-	PRIVSEP_CMD_L2_UNREGISTER,
-	PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
-	PRIVSEP_CMD_L2_SEND,
-	PRIVSEP_CMD_SET_COUNTRY,
-};
-
-struct privsep_cmd_associate
-{
-	u8 bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
-	int freq;
-	int pairwise_suite;
-	int group_suite;
-	int key_mgmt_suite;
-	int auth_alg;
-	int mode;
-	size_t wpa_ie_len;
-	/* followed by wpa_ie_len bytes of wpa_ie */
-};
-
-struct privsep_cmd_set_key
-{
-	int alg;
-	u8 addr[ETH_ALEN];
-	int key_idx;
-	int set_tx;
-	u8 seq[8];
-	size_t seq_len;
-	u8 key[32];
-	size_t key_len;
-};
-
-enum privsep_event {
-	PRIVSEP_EVENT_SCAN_RESULTS,
-	PRIVSEP_EVENT_ASSOC,
-	PRIVSEP_EVENT_DISASSOC,
-	PRIVSEP_EVENT_ASSOCINFO,
-	PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
-	PRIVSEP_EVENT_INTERFACE_STATUS,
-	PRIVSEP_EVENT_PMKID_CANDIDATE,
-	PRIVSEP_EVENT_STKSTART,
-	PRIVSEP_EVENT_FT_RESPONSE,
-	PRIVSEP_EVENT_RX_EAPOL,
-};
-
-#endif /* PRIVSEP_COMMANDS_H */

Copied: vendor/wpa/2.0/src/common/privsep_commands.h (from rev 9639, vendor/wpa/dist/src/common/privsep_commands.h)
===================================================================
--- vendor/wpa/2.0/src/common/privsep_commands.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/privsep_commands.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,69 @@
+/*
+ * WPA Supplicant - privilege separation commands
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PRIVSEP_COMMANDS_H
+#define PRIVSEP_COMMANDS_H
+
+enum privsep_cmd {
+	PRIVSEP_CMD_REGISTER,
+	PRIVSEP_CMD_UNREGISTER,
+	PRIVSEP_CMD_SCAN,
+	PRIVSEP_CMD_GET_SCAN_RESULTS,
+	PRIVSEP_CMD_ASSOCIATE,
+	PRIVSEP_CMD_GET_BSSID,
+	PRIVSEP_CMD_GET_SSID,
+	PRIVSEP_CMD_SET_KEY,
+	PRIVSEP_CMD_GET_CAPA,
+	PRIVSEP_CMD_L2_REGISTER,
+	PRIVSEP_CMD_L2_UNREGISTER,
+	PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
+	PRIVSEP_CMD_L2_SEND,
+	PRIVSEP_CMD_SET_COUNTRY,
+};
+
+struct privsep_cmd_associate
+{
+	u8 bssid[ETH_ALEN];
+	u8 ssid[32];
+	size_t ssid_len;
+	int freq;
+	int pairwise_suite;
+	int group_suite;
+	int key_mgmt_suite;
+	int auth_alg;
+	int mode;
+	size_t wpa_ie_len;
+	/* followed by wpa_ie_len bytes of wpa_ie */
+};
+
+struct privsep_cmd_set_key
+{
+	int alg;
+	u8 addr[ETH_ALEN];
+	int key_idx;
+	int set_tx;
+	u8 seq[8];
+	size_t seq_len;
+	u8 key[32];
+	size_t key_len;
+};
+
+enum privsep_event {
+	PRIVSEP_EVENT_SCAN_RESULTS,
+	PRIVSEP_EVENT_ASSOC,
+	PRIVSEP_EVENT_DISASSOC,
+	PRIVSEP_EVENT_ASSOCINFO,
+	PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
+	PRIVSEP_EVENT_INTERFACE_STATUS,
+	PRIVSEP_EVENT_PMKID_CANDIDATE,
+	PRIVSEP_EVENT_STKSTART,
+	PRIVSEP_EVENT_FT_RESPONSE,
+	PRIVSEP_EVENT_RX_EAPOL,
+};
+
+#endif /* PRIVSEP_COMMANDS_H */

Deleted: vendor/wpa/2.0/src/common/version.h
===================================================================
--- vendor/wpa/dist/src/common/version.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/version.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,6 +0,0 @@
-#ifndef VERSION_H
-#define VERSION_H
-
-#define VERSION_STR "0.7.3"
-
-#endif /* VERSION_H */

Copied: vendor/wpa/2.0/src/common/version.h (from rev 9639, vendor/wpa/dist/src/common/version.h)
===================================================================
--- vendor/wpa/2.0/src/common/version.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/version.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,10 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#ifndef VERSION_STR_POSTFIX
+#define VERSION_STR_POSTFIX ""
+#endif /* VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.0" VERSION_STR_POSTFIX
+
+#endif /* VERSION_H */

Deleted: vendor/wpa/2.0/src/common/wpa_common.c
===================================================================
--- vendor/wpa/dist/src/common/wpa_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/wpa_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,787 +0,0 @@
-/*
- * WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "ieee802_11_defs.h"
-#include "defs.h"
-#include "wpa_common.h"
-
-
-/**
- * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
- * @key: EAPOL-Key Key Confirmation Key (KCK)
- * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
- * @buf: Pointer to the beginning of the EAPOL header (version field)
- * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
- * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
- * Returns: 0 on success, -1 on failure
- *
- * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
- * to be cleared (all zeroes) when calling this function.
- *
- * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
- * description of the Key MIC calculation. It includes packet data from the
- * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
- * happened during final editing of the standard and the correct behavior is
- * defined in the last draft (IEEE 802.11i/D10).
- */
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
-		      u8 *mic)
-{
-	u8 hash[SHA1_MAC_LEN];
-
-	switch (ver) {
-	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
-		return hmac_md5(key, 16, buf, len, mic);
-	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
-		if (hmac_sha1(key, 16, buf, len, hash))
-			return -1;
-		os_memcpy(mic, hash, MD5_MAC_LEN);
-		break;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
-	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
-		return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
-	default:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
- * @pmk: Pairwise master key
- * @pmk_len: Length of PMK
- * @label: Label to use in derivation
- * @addr1: AA or SA
- * @addr2: SA or AA
- * @nonce1: ANonce or SNonce
- * @nonce2: SNonce or ANonce
- * @ptk: Buffer for pairwise transient key
- * @ptk_len: Length of PTK
- * @use_sha256: Whether to use SHA256-based KDF
- *
- * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
- * PTK = PRF-X(PMK, "Pairwise key expansion",
- *             Min(AA, SA) || Max(AA, SA) ||
- *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
- *
- * STK = PRF-X(SMK, "Peer key expansion",
- *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
- *             Min(INonce, PNonce) || Max(INonce, PNonce))
- */
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
-		    const u8 *addr1, const u8 *addr2,
-		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len, int use_sha256)
-{
-	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
-
-	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
-		os_memcpy(data, addr1, ETH_ALEN);
-		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
-	} else {
-		os_memcpy(data, addr2, ETH_ALEN);
-		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
-	}
-
-	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
-		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
-		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
-			  WPA_NONCE_LEN);
-	} else {
-		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
-		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
-			  WPA_NONCE_LEN);
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (use_sha256)
-		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
-			   ptk, ptk_len);
-	else
-#endif /* CONFIG_IEEE80211W */
-		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
-			 ptk_len);
-
-	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
-		   MAC2STR(addr1), MAC2STR(addr2));
-	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
-	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
-	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
-	       const u8 *ftie, size_t ftie_len,
-	       const u8 *rsnie, size_t rsnie_len,
-	       const u8 *ric, size_t ric_len, u8 *mic)
-{
-	u8 *buf, *pos;
-	size_t buf_len;
-
-	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
-	buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return -1;
-
-	pos = buf;
-	os_memcpy(pos, sta_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, ap_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	*pos++ = transaction_seqnum;
-	if (rsnie) {
-		os_memcpy(pos, rsnie, rsnie_len);
-		pos += rsnie_len;
-	}
-	if (mdie) {
-		os_memcpy(pos, mdie, mdie_len);
-		pos += mdie_len;
-	}
-	if (ftie) {
-		struct rsn_ftie *_ftie;
-		os_memcpy(pos, ftie, ftie_len);
-		if (ftie_len < 2 + sizeof(*_ftie)) {
-			os_free(buf);
-			return -1;
-		}
-		_ftie = (struct rsn_ftie *) (pos + 2);
-		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
-		pos += ftie_len;
-	}
-	if (ric) {
-		os_memcpy(pos, ric, ric_len);
-		pos += ric_len;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
-	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
-		os_free(buf);
-		return -1;
-	}
-
-	os_free(buf);
-
-	return 0;
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifndef CONFIG_NO_WPA2
-static int rsn_selector_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
-		return WPA_CIPHER_NONE;
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
-		return WPA_CIPHER_WEP40;
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
-		return WPA_CIPHER_TKIP;
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
-		return WPA_CIPHER_CCMP;
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
-		return WPA_CIPHER_WEP104;
-#ifdef CONFIG_IEEE80211W
-	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
-		return WPA_CIPHER_AES_128_CMAC;
-#endif /* CONFIG_IEEE80211W */
-	return 0;
-}
-
-
-static int rsn_key_mgmt_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
-		return WPA_KEY_MGMT_IEEE8021X;
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-		return WPA_KEY_MGMT_PSK;
-#ifdef CONFIG_IEEE80211R
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
-		return WPA_KEY_MGMT_FT_IEEE8021X;
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
-		return WPA_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
-		return WPA_KEY_MGMT_IEEE8021X_SHA256;
-	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
-		return WPA_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
-	return 0;
-}
-#endif /* CONFIG_NO_WPA2 */
-
-
-/**
- * wpa_parse_wpa_ie_rsn - Parse RSN IE
- * @rsn_ie: Buffer containing RSN IE
- * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
- * @data: Pointer to structure that will be filled in with parsed data
- * Returns: 0 on success, <0 on failure
- */
-int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
-			 struct wpa_ie_data *data)
-{
-#ifndef CONFIG_NO_WPA2
-	const struct rsn_ie_hdr *hdr;
-	const u8 *pos;
-	int left;
-	int i, count;
-
-	os_memset(data, 0, sizeof(*data));
-	data->proto = WPA_PROTO_RSN;
-	data->pairwise_cipher = WPA_CIPHER_CCMP;
-	data->group_cipher = WPA_CIPHER_CCMP;
-	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	data->capabilities = 0;
-	data->pmkid = NULL;
-	data->num_pmkid = 0;
-#ifdef CONFIG_IEEE80211W
-	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-#else /* CONFIG_IEEE80211W */
-	data->mgmt_group_cipher = 0;
-#endif /* CONFIG_IEEE80211W */
-
-	if (rsn_ie_len == 0) {
-		/* No RSN IE - fail silently */
-		return -1;
-	}
-
-	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
-		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
-			   __func__, (unsigned long) rsn_ie_len);
-		return -1;
-	}
-
-	hdr = (const struct rsn_ie_hdr *) rsn_ie;
-
-	if (hdr->elem_id != WLAN_EID_RSN ||
-	    hdr->len != rsn_ie_len - 2 ||
-	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
-		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-			   __func__);
-		return -2;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	left = rsn_ie_len - sizeof(*hdr);
-
-	if (left >= RSN_SELECTOR_LEN) {
-		data->group_cipher = rsn_selector_to_bitfield(pos);
-#ifdef CONFIG_IEEE80211W
-		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
-			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
-				   "cipher", __func__);
-			return -1;
-		}
-#endif /* CONFIG_IEEE80211W */
-		pos += RSN_SELECTOR_LEN;
-		left -= RSN_SELECTOR_LEN;
-	} else if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
-			   __func__, left);
-		return -3;
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
-				   "count %u left %u", __func__, count, left);
-			return -4;
-		}
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-#ifdef CONFIG_IEEE80211W
-		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
-			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
-				   "pairwise cipher", __func__);
-			return -1;
-		}
-#endif /* CONFIG_IEEE80211W */
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
-			   __func__);
-		return -5;
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
-				   "count %u left %u", __func__, count, left);
-			return -6;
-		}
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
-			   __func__);
-		return -7;
-	}
-
-	if (left >= 2) {
-		data->capabilities = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left >= 2) {
-		data->num_pmkid = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (left < (int) data->num_pmkid * PMKID_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
-				   "(num_pmkid=%lu left=%d)",
-				   __func__, (unsigned long) data->num_pmkid,
-				   left);
-			data->num_pmkid = 0;
-			return -9;
-		} else {
-			data->pmkid = pos;
-			pos += data->num_pmkid * PMKID_LEN;
-			left -= data->num_pmkid * PMKID_LEN;
-		}
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (left >= 4) {
-		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
-		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
-			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
-				   "group cipher 0x%x", __func__,
-				   data->mgmt_group_cipher);
-			return -10;
-		}
-		pos += RSN_SELECTOR_LEN;
-		left -= RSN_SELECTOR_LEN;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
-			   __func__, left);
-	}
-
-	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-/**
- * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
- *
- * IEEE Std 802.11r-2008 - 8.5.1.5.3
- */
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
-		       const u8 *ssid, size_t ssid_len,
-		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
-{
-	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
-	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
-	u8 *pos, r0_key_data[48], hash[32];
-	const u8 *addr[2];
-	size_t len[2];
-
-	/*
-	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
-	 *                       SSIDlength || SSID || MDID || R0KHlength ||
-	 *                       R0KH-ID || S0KH-ID)
-	 * XXKey is either the second 256 bits of MSK or PSK.
-	 * PMK-R0 = L(R0-Key-Data, 0, 256)
-	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
-	 */
-	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
-		return;
-	pos = buf;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-	pos += ssid_len;
-	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
-	pos += MOBILITY_DOMAIN_ID_LEN;
-	*pos++ = r0kh_id_len;
-	os_memcpy(pos, r0kh_id, r0kh_id_len);
-	pos += r0kh_id_len;
-	os_memcpy(pos, s0kh_id, ETH_ALEN);
-	pos += ETH_ALEN;
-
-	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
-		   r0_key_data, sizeof(r0_key_data));
-	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
-
-	/*
-	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
-	 */
-	addr[0] = (const u8 *) "FT-R0N";
-	len[0] = 6;
-	addr[1] = r0_key_data + PMK_LEN;
-	len[1] = 16;
-
-	sha256_vector(2, addr, len, hash);
-	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
-}
-
-
-/**
- * wpa_derive_pmk_r1_name - Derive PMKR1Name
- *
- * IEEE Std 802.11r-2008 - 8.5.1.5.4
- */
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			    const u8 *s1kh_id, u8 *pmk_r1_name)
-{
-	u8 hash[32];
-	const u8 *addr[4];
-	size_t len[4];
-
-	/*
-	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
-	 *                                  R1KH-ID || S1KH-ID))
-	 */
-	addr[0] = (const u8 *) "FT-R1N";
-	len[0] = 6;
-	addr[1] = pmk_r0_name;
-	len[1] = WPA_PMK_NAME_LEN;
-	addr[2] = r1kh_id;
-	len[2] = FT_R1KH_ID_LEN;
-	addr[3] = s1kh_id;
-	len[3] = ETH_ALEN;
-
-	sha256_vector(4, addr, len, hash);
-	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
-}
-
-
-/**
- * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
- *
- * IEEE Std 802.11r-2008 - 8.5.1.5.4
- */
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
-		       const u8 *r1kh_id, const u8 *s1kh_id,
-		       u8 *pmk_r1, u8 *pmk_r1_name)
-{
-	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
-	u8 *pos;
-
-	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
-	pos = buf;
-	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
-	pos += FT_R1KH_ID_LEN;
-	os_memcpy(pos, s1kh_id, ETH_ALEN);
-	pos += ETH_ALEN;
-
-	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
-
-	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
-}
-
-
-/**
- * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
- *
- * IEEE Std 802.11r-2008 - 8.5.1.5.5
- */
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
-		       const u8 *sta_addr, const u8 *bssid,
-		       const u8 *pmk_r1_name,
-		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
-{
-	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
-	u8 *pos, hash[32];
-	const u8 *addr[6];
-	size_t len[6];
-
-	/*
-	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
-	 *                  BSSID || STA-ADDR)
-	 */
-	pos = buf;
-	os_memcpy(pos, snonce, WPA_NONCE_LEN);
-	pos += WPA_NONCE_LEN;
-	os_memcpy(pos, anonce, WPA_NONCE_LEN);
-	pos += WPA_NONCE_LEN;
-	os_memcpy(pos, bssid, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, sta_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-
-	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
-
-	/*
-	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
-	 *                                ANonce || BSSID || STA-ADDR))
-	 */
-	addr[0] = pmk_r1_name;
-	len[0] = WPA_PMK_NAME_LEN;
-	addr[1] = (const u8 *) "FT-PTKN";
-	len[1] = 7;
-	addr[2] = snonce;
-	len[2] = WPA_NONCE_LEN;
-	addr[3] = anonce;
-	len[3] = WPA_NONCE_LEN;
-	addr[4] = bssid;
-	len[4] = ETH_ALEN;
-	addr[5] = sta_addr;
-	len[5] = ETH_ALEN;
-
-	sha256_vector(6, addr, len, hash);
-	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-/**
- * rsn_pmkid - Calculate PMK identifier
- * @pmk: Pairwise master key
- * @pmk_len: Length of pmk in bytes
- * @aa: Authenticator address
- * @spa: Supplicant address
- * @pmkid: Buffer for PMKID
- * @use_sha256: Whether to use SHA256-based KDF
- *
- * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
- * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
- */
-void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
-	       u8 *pmkid, int use_sha256)
-{
-	char *title = "PMK Name";
-	const u8 *addr[3];
-	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
-	unsigned char hash[SHA256_MAC_LEN];
-
-	addr[0] = (u8 *) title;
-	addr[1] = aa;
-	addr[2] = spa;
-
-#ifdef CONFIG_IEEE80211W
-	if (use_sha256)
-		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
-	else
-#endif /* CONFIG_IEEE80211W */
-		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
-	os_memcpy(pmkid, hash, PMKID_LEN);
-}
-
-
-/**
- * wpa_cipher_txt - Convert cipher suite to a text string
- * @cipher: Cipher suite (WPA_CIPHER_* enum)
- * Returns: Pointer to a text string of the cipher suite name
- */
-const char * wpa_cipher_txt(int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_NONE:
-		return "NONE";
-	case WPA_CIPHER_WEP40:
-		return "WEP-40";
-	case WPA_CIPHER_WEP104:
-		return "WEP-104";
-	case WPA_CIPHER_TKIP:
-		return "TKIP";
-	case WPA_CIPHER_CCMP:
-		return "CCMP";
-	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
-		return "CCMP+TKIP";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-/**
- * wpa_key_mgmt_txt - Convert key management suite to a text string
- * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
- * @proto: WPA/WPA2 version (WPA_PROTO_*)
- * Returns: Pointer to a text string of the key management suite name
- */
-const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
-{
-	switch (key_mgmt) {
-	case WPA_KEY_MGMT_IEEE8021X:
-		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
-			return "WPA2+WPA/IEEE 802.1X/EAP";
-		return proto == WPA_PROTO_RSN ?
-			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
-	case WPA_KEY_MGMT_PSK:
-		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
-			return "WPA2-PSK+WPA-PSK";
-		return proto == WPA_PROTO_RSN ?
-			"WPA2-PSK" : "WPA-PSK";
-	case WPA_KEY_MGMT_NONE:
-		return "NONE";
-	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
-		return "IEEE 802.1X (no WPA)";
-#ifdef CONFIG_IEEE80211R
-	case WPA_KEY_MGMT_FT_IEEE8021X:
-		return "FT-EAP";
-	case WPA_KEY_MGMT_FT_PSK:
-		return "FT-PSK";
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	case WPA_KEY_MGMT_IEEE8021X_SHA256:
-		return "WPA2-EAP-SHA256";
-	case WPA_KEY_MGMT_PSK_SHA256:
-		return "WPA2-PSK-SHA256";
-#endif /* CONFIG_IEEE80211W */
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-int wpa_compare_rsn_ie(int ft_initial_assoc,
-		       const u8 *ie1, size_t ie1len,
-		       const u8 *ie2, size_t ie2len)
-{
-	if (ie1 == NULL || ie2 == NULL)
-		return -1;
-
-	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
-		return 0; /* identical IEs */
-
-#ifdef CONFIG_IEEE80211R
-	if (ft_initial_assoc) {
-		struct wpa_ie_data ie1d, ie2d;
-		/*
-		 * The PMKID-List in RSN IE is different between Beacon/Probe
-		 * Response/(Re)Association Request frames and EAPOL-Key
-		 * messages in FT initial mobility domain association. Allow
-		 * for this, but verify that other parts of the RSN IEs are
-		 * identical.
-		 */
-		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
-		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
-			return -1;
-		if (ie1d.proto == ie2d.proto &&
-		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
-		    ie1d.group_cipher == ie2d.group_cipher &&
-		    ie1d.key_mgmt == ie2d.key_mgmt &&
-		    ie1d.capabilities == ie2d.capabilities &&
-		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
-			return 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	return -1;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-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;
-
-	while (start < end) {
-		if (*start == WLAN_EID_RSN)
-			break;
-		start += 2 + start[1];
-	}
-	if (start >= end) {
-		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
-			   "IEs data");
-		return -1;
-	}
-	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
-		    start, 2 + start[1]);
-
-	/* Find start of PMKID-Count */
-	rpos = start + 2;
-	rend = rpos + start[1];
-
-	/* Skip Version and Group Data Cipher Suite */
-	rpos += 2 + 4;
-	/* Skip Pairwise Cipher Suite Count and List */
-	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
-	/* Skip AKM Suite Count and List */
-	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
-
-	if (rpos == rend) {
-		/* Add RSN Capabilities */
-		os_memmove(rpos + 2, rpos, end - rpos);
-		*rpos++ = 0;
-		*rpos++ = 0;
-	} else {
-		/* Skip RSN Capabilities */
-		rpos += 2;
-		if (rpos > rend) {
-			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
-				   "IEs data");
-			return -1;
-		}
-	}
-
-	if (rpos == rend) {
-		/* No PMKID-Count field included; add it */
-		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
-		WPA_PUT_LE16(rpos, 1);
-		rpos += 2;
-		os_memcpy(rpos, pmkid, PMKID_LEN);
-		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");
-			return -1;
-		}
-		WPA_PUT_LE16(rpos, 1);
-		rpos += 2;
-		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
-		os_memcpy(rpos, pmkid, PMKID_LEN);
-		added += PMKID_LEN;
-		start[1] += PMKID_LEN;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
-		    "(PMKID inserted)", start, 2 + start[1]);
-
-	return added;
-}
-#endif /* CONFIG_IEEE80211R */

Copied: vendor/wpa/2.0/src/common/wpa_common.c (from rev 9639, vendor/wpa/dist/src/common/wpa_common.c)
===================================================================
--- vendor/wpa/2.0/src/common/wpa_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/common/wpa_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1216 @@
+/*
+ * WPA/RSN - Shared functions for supplicant and authenticator
+ * Copyright (c) 2002-2008, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "ieee802_11_defs.h"
+#include "defs.h"
+#include "wpa_common.h"
+
+
+/**
+ * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
+ * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
+ * @buf: Pointer to the beginning of the EAPOL header (version field)
+ * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
+ * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: 0 on success, -1 on failure
+ *
+ * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
+ * to be cleared (all zeroes) when calling this function.
+ *
+ * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
+ * description of the Key MIC calculation. It includes packet data from the
+ * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
+ * happened during final editing of the standard and the correct behavior is
+ * defined in the last draft (IEEE 802.11i/D10).
+ */
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic)
+{
+	u8 hash[SHA1_MAC_LEN];
+
+	switch (ver) {
+#ifndef CONFIG_FIPS
+	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
+		return hmac_md5(key, 16, buf, len, mic);
+#endif /* CONFIG_FIPS */
+	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
+		if (hmac_sha1(key, 16, buf, len, hash))
+			return -1;
+		os_memcpy(mic, hash, MD5_MAC_LEN);
+		break;
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
+		return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @label: Label to use in derivation
+ * @addr1: AA or SA
+ * @addr2: SA or AA
+ * @nonce1: ANonce or SNonce
+ * @nonce2: SNonce or ANonce
+ * @ptk: Buffer for pairwise transient key
+ * @ptk_len: Length of PTK
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PTK = PRF-X(PMK, "Pairwise key expansion",
+ *             Min(AA, SA) || Max(AA, SA) ||
+ *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ *
+ * STK = PRF-X(SMK, "Peer key expansion",
+ *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
+ *             Min(INonce, PNonce) || Max(INonce, PNonce))
+ */
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256)
+{
+	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+
+	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
+		os_memcpy(data, addr1, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
+	} else {
+		os_memcpy(data, addr2, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
+	}
+
+	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
+		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
+			  WPA_NONCE_LEN);
+	} else {
+		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
+			  WPA_NONCE_LEN);
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+			   ptk, ptk_len);
+	else
+#endif /* CONFIG_IEEE80211W */
+		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
+			 ptk_len);
+
+	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
+		   MAC2STR(addr1), MAC2STR(addr2));
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	pos = buf;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ap_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	*pos++ = transaction_seqnum;
+	if (rsnie) {
+		os_memcpy(pos, rsnie, rsnie_len);
+		pos += rsnie_len;
+	}
+	if (mdie) {
+		os_memcpy(pos, mdie, mdie_len);
+		pos += mdie_len;
+	}
+	if (ftie) {
+		struct rsn_ftie *_ftie;
+		os_memcpy(pos, ftie, ftie_len);
+		if (ftie_len < 2 + sizeof(*_ftie)) {
+			os_free(buf);
+			return -1;
+		}
+		_ftie = (struct rsn_ftie *) (pos + 2);
+		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
+		pos += ftie_len;
+	}
+	if (ric) {
+		os_memcpy(pos, ric, ric_len);
+		pos += ric_len;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
+	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		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]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			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]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* 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];
+	}
+	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);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifndef CONFIG_NO_WPA2
+static int rsn_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
+		return WPA_CIPHER_AES_128_CMAC;
+#endif /* CONFIG_IEEE80211W */
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
+		return WPA_CIPHER_GCMP;
+	return 0;
+}
+
+
+static int rsn_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_IEEE80211R
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
+		return WPA_KEY_MGMT_FT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
+		return WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
+		return WPA_KEY_MGMT_IEEE8021X_SHA256;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
+		return WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+		return WPA_KEY_MGMT_SAE;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+		return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+	return 0;
+}
+#endif /* CONFIG_NO_WPA2 */
+
+
+/**
+ * wpa_parse_wpa_ie_rsn - Parse RSN IE
+ * @rsn_ie: Buffer containing RSN IE
+ * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
+ * @data: Pointer to structure that will be filled in with parsed data
+ * Returns: 0 on success, <0 on failure
+ */
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data)
+{
+#ifndef CONFIG_NO_WPA2
+	const struct rsn_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_RSN;
+	data->pairwise_cipher = WPA_CIPHER_CCMP;
+	data->group_cipher = WPA_CIPHER_CCMP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+#ifdef CONFIG_IEEE80211W
+	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+#else /* CONFIG_IEEE80211W */
+	data->mgmt_group_cipher = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	if (rsn_ie_len == 0) {
+		/* No RSN IE - fail silently */
+		return -1;
+	}
+
+	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+	if (hdr->elem_id != WLAN_EID_RSN ||
+	    hdr->len != rsn_ie_len - 2 ||
+	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = rsn_ie_len - sizeof(*hdr);
+
+	if (left >= RSN_SELECTOR_LEN) {
+		data->group_cipher = rsn_selector_to_bitfield(pos);
+#ifdef CONFIG_IEEE80211W
+		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
+				   "cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+#ifdef CONFIG_IEEE80211W
+		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
+				   "pairwise cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left >= 2) {
+		data->num_pmkid = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (left < (int) data->num_pmkid * PMKID_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
+				   "(num_pmkid=%lu left=%d)",
+				   __func__, (unsigned long) data->num_pmkid,
+				   left);
+			data->num_pmkid = 0;
+			return -9;
+		} else {
+			data->pmkid = pos;
+			pos += data->num_pmkid * PMKID_LEN;
+			left -= data->num_pmkid * PMKID_LEN;
+		}
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (left >= 4) {
+		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
+		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
+				   "group cipher 0x%x", __func__,
+				   data->mgmt_group_cipher);
+			return -10;
+		}
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int wpa_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+	return 0;
+}
+
+
+static int wpa_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
+		return WPA_KEY_MGMT_WPA_NONE;
+	return 0;
+}
+
+
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data)
+{
+	const struct wpa_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_WPA;
+	data->pairwise_cipher = WPA_CIPHER_TKIP;
+	data->group_cipher = WPA_CIPHER_TKIP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+	data->mgmt_group_cipher = 0;
+
+	if (wpa_ie_len == 0) {
+		/* No WPA IE - fail silently */
+		return -1;
+	}
+
+	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) wpa_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct wpa_ie_hdr *) wpa_ie;
+
+	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
+	    hdr->len != wpa_ie_len - 2 ||
+	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
+	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = wpa_ie_len - sizeof(*hdr);
+
+	if (left >= WPA_SELECTOR_LEN) {
+		data->group_cipher = wpa_selector_to_bitfield(pos);
+		pos += WPA_SELECTOR_LEN;
+		left -= WPA_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+/**
+ * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.3
+ */
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+{
+	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
+	u8 *pos, r0_key_data[48], hash[32];
+	const u8 *addr[2];
+	size_t len[2];
+
+	/*
+	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
+	 *                       SSIDlength || SSID || MDID || R0KHlength ||
+	 *                       R0KH-ID || S0KH-ID)
+	 * XXKey is either the second 256 bits of MSK or PSK.
+	 * PMK-R0 = L(R0-Key-Data, 0, 256)
+	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+	 */
+	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+		return;
+	pos = buf;
+	*pos++ = ssid_len;
+	os_memcpy(pos, ssid, ssid_len);
+	pos += ssid_len;
+	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	*pos++ = r0kh_id_len;
+	os_memcpy(pos, r0kh_id, r0kh_id_len);
+	pos += r0kh_id_len;
+	os_memcpy(pos, s0kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+		   r0_key_data, sizeof(r0_key_data));
+	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+
+	/*
+	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+	 */
+	addr[0] = (const u8 *) "FT-R0N";
+	len[0] = 6;
+	addr[1] = r0_key_data + PMK_LEN;
+	len[1] = 16;
+
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1_name - Derive PMKR1Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name)
+{
+	u8 hash[32];
+	const u8 *addr[4];
+	size_t len[4];
+
+	/*
+	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
+	 *                                  R1KH-ID || S1KH-ID))
+	 */
+	addr[0] = (const u8 *) "FT-R1N";
+	len[0] = 6;
+	addr[1] = pmk_r0_name;
+	len[1] = WPA_PMK_NAME_LEN;
+	addr[2] = r1kh_id;
+	len[2] = FT_R1KH_ID_LEN;
+	addr[3] = s1kh_id;
+	len[3] = ETH_ALEN;
+
+	sha256_vector(4, addr, len, hash);
+	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name)
+{
+	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
+	u8 *pos;
+
+	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+	pos = buf;
+	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+	os_memcpy(pos, s1kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+
+	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+}
+
+
+/**
+ * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.5
+ */
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
+{
+	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
+	u8 *pos, hash[32];
+	const u8 *addr[6];
+	size_t len[6];
+
+	/*
+	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
+	 *                  BSSID || STA-ADDR)
+	 */
+	pos = buf;
+	os_memcpy(pos, snonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, anonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+
+	/*
+	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
+	 *                                ANonce || BSSID || STA-ADDR))
+	 */
+	addr[0] = pmk_r1_name;
+	len[0] = WPA_PMK_NAME_LEN;
+	addr[1] = (const u8 *) "FT-PTKN";
+	len[1] = 7;
+	addr[2] = snonce;
+	len[2] = WPA_NONCE_LEN;
+	addr[3] = anonce;
+	len[3] = WPA_NONCE_LEN;
+	addr[4] = bssid;
+	len[4] = ETH_ALEN;
+	addr[5] = sta_addr;
+	len[5] = ETH_ALEN;
+
+	sha256_vector(6, addr, len, hash);
+	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/**
+ * rsn_pmkid - Calculate PMK identifier
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of pmk in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ */
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+	os_memcpy(pmkid, hash, PMKID_LEN);
+}
+
+
+/**
+ * wpa_cipher_txt - Convert cipher suite to a text string
+ * @cipher: Cipher suite (WPA_CIPHER_* enum)
+ * Returns: Pointer to a text string of the cipher suite name
+ */
+const char * wpa_cipher_txt(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_NONE:
+		return "NONE";
+	case WPA_CIPHER_WEP40:
+		return "WEP-40";
+	case WPA_CIPHER_WEP104:
+		return "WEP-104";
+	case WPA_CIPHER_TKIP:
+		return "TKIP";
+	case WPA_CIPHER_CCMP:
+		return "CCMP";
+	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
+		return "CCMP+TKIP";
+	case WPA_CIPHER_GCMP:
+		return "GCMP";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+/**
+ * wpa_key_mgmt_txt - Convert key management suite to a text string
+ * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
+ * @proto: WPA/WPA2 version (WPA_PROTO_*)
+ * Returns: Pointer to a text string of the key management suite name
+ */
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+	switch (key_mgmt) {
+	case WPA_KEY_MGMT_IEEE8021X:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2+WPA/IEEE 802.1X/EAP";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+	case WPA_KEY_MGMT_PSK:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2-PSK+WPA-PSK";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2-PSK" : "WPA-PSK";
+	case WPA_KEY_MGMT_NONE:
+		return "NONE";
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+		return "IEEE 802.1X (no WPA)";
+#ifdef CONFIG_IEEE80211R
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return "FT-EAP";
+	case WPA_KEY_MGMT_FT_PSK:
+		return "FT-PSK";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return "WPA2-EAP-SHA256";
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return "WPA2-PSK-SHA256";
+#endif /* CONFIG_IEEE80211W */
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int wpa_compare_rsn_ie(int ft_initial_assoc,
+		       const u8 *ie1, size_t ie1len,
+		       const u8 *ie2, size_t ie2len)
+{
+	if (ie1 == NULL || ie2 == NULL)
+		return -1;
+
+	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
+		return 0; /* identical IEs */
+
+#ifdef CONFIG_IEEE80211R
+	if (ft_initial_assoc) {
+		struct wpa_ie_data ie1d, ie2d;
+		/*
+		 * The PMKID-List in RSN IE is different between Beacon/Probe
+		 * Response/(Re)Association Request frames and EAPOL-Key
+		 * messages in FT initial mobility domain association. Allow
+		 * for this, but verify that other parts of the RSN IEs are
+		 * identical.
+		 */
+		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
+		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
+			return -1;
+		if (ie1d.proto == ie2d.proto &&
+		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
+		    ie1d.group_cipher == ie2d.group_cipher &&
+		    ie1d.key_mgmt == ie2d.key_mgmt &&
+		    ie1d.capabilities == ie2d.capabilities &&
+		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
+			return 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	return -1;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+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;
+
+	while (start < end) {
+		if (*start == WLAN_EID_RSN)
+			break;
+		start += 2 + start[1];
+	}
+	if (start >= end) {
+		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
+			   "IEs data");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+		    start, 2 + start[1]);
+
+	/* Find start of PMKID-Count */
+	rpos = start + 2;
+	rend = rpos + start[1];
+
+	/* Skip Version and Group Data Cipher Suite */
+	rpos += 2 + 4;
+	/* Skip Pairwise Cipher Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+	/* Skip AKM Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+
+	if (rpos == rend) {
+		/* Add RSN Capabilities */
+		os_memmove(rpos + 2, rpos, end - rpos);
+		*rpos++ = 0;
+		*rpos++ = 0;
+	} else {
+		/* Skip RSN Capabilities */
+		rpos += 2;
+		if (rpos > rend) {
+			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
+				   "IEs data");
+			return -1;
+		}
+	}
+
+	if (rpos == rend) {
+		/* No PMKID-Count field included; add it */
+		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		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");
+			return -1;
+		}
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += PMKID_LEN;
+		start[1] += PMKID_LEN;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
+		    "(PMKID inserted)", start, 2 + start[1]);
+
+	return added;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+int wpa_cipher_key_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+		return 16;
+	case WPA_CIPHER_TKIP:
+		return 32;
+	case WPA_CIPHER_WEP104:
+		return 13;
+	case WPA_CIPHER_WEP40:
+		return 5;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_rsc_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+	case WPA_CIPHER_TKIP:
+		return 6;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_to_alg(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+		return WPA_ALG_CCMP;
+	case WPA_CIPHER_GCMP:
+		return WPA_ALG_GCMP;
+	case WPA_CIPHER_TKIP:
+		return WPA_ALG_TKIP;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return WPA_ALG_WEP;
+	}
+	return WPA_ALG_NONE;
+}
+
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+	return cipher == WPA_CIPHER_CCMP ||
+		cipher == WPA_CIPHER_GCMP ||
+		cipher == WPA_CIPHER_TKIP;
+}
+
+
+u32 wpa_cipher_to_suite(int proto, int cipher)
+{
+	if (cipher & WPA_CIPHER_CCMP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+	if (cipher & WPA_CIPHER_GCMP)
+		return RSN_CIPHER_SUITE_GCMP;
+	if (cipher & WPA_CIPHER_TKIP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
+	if (cipher & WPA_CIPHER_WEP104)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
+	if (cipher & WPA_CIPHER_WEP40)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
+	if (cipher & WPA_CIPHER_NONE)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+	return 0;
+}
+
+
+int rsn_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_GCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}
+
+
+int wpa_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}

Deleted: vendor/wpa/2.0/src/common/wpa_common.h
===================================================================
--- vendor/wpa/dist/src/common/wpa_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/wpa_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,351 +0,0 @@
-/*
- * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_COMMON_H
-#define WPA_COMMON_H
-
-#define WPA_MAX_SSID_LEN 32
-
-/* IEEE 802.11i */
-#define PMKID_LEN 16
-#define PMK_LEN 32
-#define WPA_REPLAY_COUNTER_LEN 8
-#define WPA_NONCE_LEN 32
-#define WPA_KEY_RSC_LEN 8
-#define WPA_GMK_LEN 32
-#define WPA_GTK_MAX_LEN 32
-
-#define WPA_SELECTOR_LEN 4
-#define WPA_VERSION 1
-#define RSN_SELECTOR_LEN 4
-#define RSN_VERSION 1
-
-#define RSN_SELECTOR(a, b, c, d) \
-	((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
-	 (u32) (d))
-
-#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
-#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
-#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
-#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
-#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
-#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
-#if 0
-#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
-#endif
-#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
-#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
-
-
-#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
-#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
-#ifdef CONFIG_IEEE80211R
-#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
-#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#endif /* CONFIG_IEEE80211R */
-#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-
-#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
-#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
-#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
-#if 0
-#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
-#endif
-#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#ifdef CONFIG_IEEE80211W
-#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-#endif /* CONFIG_IEEE80211W */
-
-/* EAPOL-Key Key Data Encapsulation
- * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
- */
-#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
-#if 0
-#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
-#endif
-#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
-#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#ifdef CONFIG_PEERKEY
-#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
-#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
-#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
-#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211W
-#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
-#endif /* CONFIG_IEEE80211W */
-
-#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
-
-#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
-#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
-
-#define RSN_NUM_REPLAY_COUNTERS_1 0
-#define RSN_NUM_REPLAY_COUNTERS_2 1
-#define RSN_NUM_REPLAY_COUNTERS_4 2
-#define RSN_NUM_REPLAY_COUNTERS_16 3
-
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-#ifdef CONFIG_IEEE80211W
-#define WPA_IGTK_LEN 16
-#endif /* CONFIG_IEEE80211W */
-
-
-/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
-#define WPA_CAPABILITY_PREAUTH BIT(0)
-#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
-/* B2-B3: PTKSA Replay Counter */
-/* B4-B5: GTKSA Replay Counter */
-#define WPA_CAPABILITY_MFPR BIT(6)
-#define WPA_CAPABILITY_MFPC BIT(7)
-#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
-
-
-/* IEEE 802.11r */
-#define MOBILITY_DOMAIN_ID_LEN 2
-#define FT_R0KH_ID_MAX_LEN 48
-#define FT_R1KH_ID_LEN 6
-#define WPA_PMK_NAME_LEN 16
-
-
-/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
-#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
-#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
-#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
-#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
-#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
-/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
-#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
-#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
-#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
-#define WPA_KEY_INFO_TXRX BIT(6) /* group */
-#define WPA_KEY_INFO_ACK BIT(7)
-#define WPA_KEY_INFO_MIC BIT(8)
-#define WPA_KEY_INFO_SECURE BIT(9)
-#define WPA_KEY_INFO_ERROR BIT(10)
-#define WPA_KEY_INFO_REQUEST BIT(11)
-#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
-#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
-
-
-struct wpa_eapol_key {
-	u8 type;
-	/* Note: key_info, key_length, and key_data_length are unaligned */
-	u8 key_info[2]; /* big endian */
-	u8 key_length[2]; /* big endian */
-	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
-	u8 key_nonce[WPA_NONCE_LEN];
-	u8 key_iv[16];
-	u8 key_rsc[WPA_KEY_RSC_LEN];
-	u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
-	u8 key_mic[16];
-	u8 key_data_length[2]; /* big endian */
-	/* followed by key_data_length bytes of key_data */
-} STRUCT_PACKED;
-
-/**
- * struct wpa_ptk - WPA Pairwise Transient Key
- * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
- */
-struct wpa_ptk {
-	u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
-	u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
-	u8 tk1[16]; /* Temporal Key 1 (TK1) */
-	union {
-		u8 tk2[16]; /* Temporal Key 2 (TK2) */
-		struct {
-			u8 tx_mic_key[8];
-			u8 rx_mic_key[8];
-		} auth;
-	} u;
-} STRUCT_PACKED;
-
-
-/* WPA IE version 1
- * 00-50-f2:1 (OUI:OUI type)
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: TKIP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: TKIP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- *    (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- *    (default: unspec 802.1X)
- * WPA Capabilities (2 octets, little endian) (default: 0)
- */
-
-struct wpa_ie_hdr {
-	u8 elem_id;
-	u8 len;
-	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
-	u8 version[2]; /* little endian */
-} STRUCT_PACKED;
-
-
-/* 1/4: PMKID
- * 2/4: RSN IE
- * 3/4: one or two RSN IEs + GTK IE (encrypted)
- * 4/4: empty
- * 1/2: GTK IE (encrypted)
- * 2/2: empty
- */
-
-/* RSN IE version 1
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: CCMP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: CCMP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- *    (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- *    (default: unspec 802.1X)
- * RSN Capabilities (2 octets, little endian) (default: 0)
- * PMKID Count (2 octets) (default: 0)
- * PMKID List (16 * n octets)
- * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
- */
-
-struct rsn_ie_hdr {
-	u8 elem_id; /* WLAN_EID_RSN */
-	u8 len;
-	u8 version[2]; /* little endian */
-} STRUCT_PACKED;
-
-
-#ifdef CONFIG_PEERKEY
-enum {
-	STK_MUI_4WAY_STA_AP = 1,
-	STK_MUI_4WAY_STAT_STA = 2,
-	STK_MUI_GTK = 3,
-	STK_MUI_SMK = 4
-};
-
-enum {
-	STK_ERR_STA_NR = 1,
-	STK_ERR_STA_NRSN = 2,
-	STK_ERR_CPHR_NS = 3,
-	STK_ERR_NO_STSL = 4
-};
-#endif /* CONFIG_PEERKEY */
-
-struct rsn_error_kde {
-	be16 mui;
-	be16 error_type;
-} STRUCT_PACKED;
-
-#ifdef CONFIG_IEEE80211W
-struct wpa_igtk_kde {
-	u8 keyid[2];
-	u8 pn[6];
-	u8 igtk[WPA_IGTK_LEN];
-} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_IEEE80211R
-struct rsn_mdie {
-	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
-	u8 ft_capab;
-} STRUCT_PACKED;
-
-#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
-#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
-
-struct rsn_ftie {
-	u8 mic_control[2];
-	u8 mic[16];
-	u8 anonce[WPA_NONCE_LEN];
-	u8 snonce[WPA_NONCE_LEN];
-	/* followed by optional parameters */
-} STRUCT_PACKED;
-
-#define FTIE_SUBELEM_R1KH_ID 1
-#define FTIE_SUBELEM_GTK 2
-#define FTIE_SUBELEM_R0KH_ID 3
-#define FTIE_SUBELEM_IGTK 4
-
-struct rsn_rdie {
-	u8 id;
-	u8 descr_count;
-	le16 status_code;
-} STRUCT_PACKED;
-
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
-		      u8 *mic);
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
-		    const u8 *addr1, const u8 *addr2,
-		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len, int use_sha256);
-
-#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
-	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
-	       const u8 *ftie, size_t ftie_len,
-	       const u8 *rsnie, size_t rsnie_len,
-	       const u8 *ric, size_t ric_len, u8 *mic);
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
-		       const u8 *ssid, size_t ssid_len,
-		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
-		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
-			    const u8 *s1kh_id, u8 *pmk_r1_name);
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
-		       const u8 *r1kh_id, const u8 *s1kh_id,
-		       u8 *pmk_r1, u8 *pmk_r1_name);
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
-		       const u8 *sta_addr, const u8 *bssid,
-		       const u8 *pmk_r1_name,
-		       u8 *ptk, size_t ptk_len, u8 *ptk_name);
-#endif /* CONFIG_IEEE80211R */
-
-struct wpa_ie_data {
-	int proto;
-	int pairwise_cipher;
-	int group_cipher;
-	int key_mgmt;
-	int capabilities;
-	size_t num_pmkid;
-	const u8 *pmkid;
-	int mgmt_group_cipher;
-};
-
-
-int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
-			 struct wpa_ie_data *data);
-
-void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
-	       u8 *pmkid, int use_sha256);
-
-const char * wpa_cipher_txt(int cipher);
-const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
-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);
-
-#endif /* WPA_COMMON_H */

Copied: vendor/wpa/2.0/src/common/wpa_common.h (from rev 9639, vendor/wpa/dist/src/common/wpa_common.h)
===================================================================
--- vendor/wpa/2.0/src/common/wpa_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/wpa_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,394 @@
+/*
+ * WPA definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_COMMON_H
+#define WPA_COMMON_H
+
+#define WPA_MAX_SSID_LEN 32
+
+/* IEEE 802.11i */
+#define PMKID_LEN 16
+#define PMK_LEN 32
+#define WPA_REPLAY_COUNTER_LEN 8
+#define WPA_NONCE_LEN 32
+#define WPA_KEY_RSC_LEN 8
+#define WPA_GMK_LEN 32
+#define WPA_GTK_MAX_LEN 32
+
+#define WPA_SELECTOR_LEN 4
+#define WPA_VERSION 1
+#define RSN_SELECTOR_LEN 4
+#define RSN_VERSION 1
+
+#define RSN_SELECTOR(a, b, c, d) \
+	((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
+	 (u32) (d))
+
+#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
+#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#if 0
+#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
+#endif
+#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
+#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
+
+
+#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#ifdef CONFIG_IEEE80211R
+#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#endif /* CONFIG_IEEE80211R */
+#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
+
+#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#if 0
+#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#endif
+#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#ifdef CONFIG_IEEE80211W
+#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+
+/* EAPOL-Key Key Data Encapsulation
+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
+ */
+#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#if 0
+#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#endif
+#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#ifdef CONFIG_PEERKEY
+#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+
+#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
+
+#define RSN_NUM_REPLAY_COUNTERS_1 0
+#define RSN_NUM_REPLAY_COUNTERS_2 1
+#define RSN_NUM_REPLAY_COUNTERS_4 2
+#define RSN_NUM_REPLAY_COUNTERS_16 3
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#ifdef CONFIG_IEEE80211W
+#define WPA_IGTK_LEN 16
+#endif /* CONFIG_IEEE80211W */
+
+
+/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
+/* B2-B3: PTKSA Replay Counter */
+/* B4-B5: GTKSA Replay Counter */
+#define WPA_CAPABILITY_MFPR BIT(6)
+#define WPA_CAPABILITY_MFPC BIT(7)
+/* B8: Reserved */
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
+#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
+#define WPA_CAPABILITY_PBAC BIT(12)
+#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
+/* B14-B15: Reserved */
+
+
+/* IEEE 802.11r */
+#define MOBILITY_DOMAIN_ID_LEN 2
+#define FT_R0KH_ID_MAX_LEN 48
+#define FT_R1KH_ID_LEN 6
+#define WPA_PMK_NAME_LEN 16
+
+
+/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
+#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
+#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
+#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
+#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
+#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
+/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
+#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
+#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
+#define WPA_KEY_INFO_TXRX BIT(6) /* group */
+#define WPA_KEY_INFO_ACK BIT(7)
+#define WPA_KEY_INFO_MIC BIT(8)
+#define WPA_KEY_INFO_SECURE BIT(9)
+#define WPA_KEY_INFO_ERROR BIT(10)
+#define WPA_KEY_INFO_REQUEST BIT(11)
+#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
+
+
+struct wpa_eapol_key {
+	u8 type;
+	/* Note: key_info, key_length, and key_data_length are unaligned */
+	u8 key_info[2]; /* big endian */
+	u8 key_length[2]; /* big endian */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	u8 key_nonce[WPA_NONCE_LEN];
+	u8 key_iv[16];
+	u8 key_rsc[WPA_KEY_RSC_LEN];
+	u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+	u8 key_mic[16];
+	u8 key_data_length[2]; /* big endian */
+	/* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+/**
+ * struct wpa_ptk - WPA Pairwise Transient Key
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ */
+struct wpa_ptk {
+	u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
+	u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
+	u8 tk1[16]; /* Temporal Key 1 (TK1) */
+	union {
+		u8 tk2[16]; /* Temporal Key 2 (TK2) */
+		struct {
+			u8 tx_mic_key[8];
+			u8 rx_mic_key[8];
+		} auth;
+	} u;
+} STRUCT_PACKED;
+
+
+/* WPA IE version 1
+ * 00-50-f2:1 (OUI:OUI type)
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: TKIP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: TKIP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * WPA Capabilities (2 octets, little endian) (default: 0)
+ */
+
+struct wpa_ie_hdr {
+	u8 elem_id;
+	u8 len;
+	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+/* 1/4: PMKID
+ * 2/4: RSN IE
+ * 3/4: one or two RSN IEs + GTK IE (encrypted)
+ * 4/4: empty
+ * 1/2: GTK IE (encrypted)
+ * 2/2: empty
+ */
+
+/* RSN IE version 1
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: CCMP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: CCMP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * RSN Capabilities (2 octets, little endian) (default: 0)
+ * PMKID Count (2 octets) (default: 0)
+ * PMKID List (16 * n octets)
+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
+ */
+
+struct rsn_ie_hdr {
+	u8 elem_id; /* WLAN_EID_RSN */
+	u8 len;
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+#ifdef CONFIG_PEERKEY
+enum {
+	STK_MUI_4WAY_STA_AP = 1,
+	STK_MUI_4WAY_STAT_STA = 2,
+	STK_MUI_GTK = 3,
+	STK_MUI_SMK = 4
+};
+
+enum {
+	STK_ERR_STA_NR = 1,
+	STK_ERR_STA_NRSN = 2,
+	STK_ERR_CPHR_NS = 3,
+	STK_ERR_NO_STSL = 4
+};
+#endif /* CONFIG_PEERKEY */
+
+struct rsn_error_kde {
+	be16 mui;
+	be16 error_type;
+} STRUCT_PACKED;
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 igtk[WPA_IGTK_LEN];
+} STRUCT_PACKED;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+struct rsn_mdie {
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 ft_capab;
+} STRUCT_PACKED;
+
+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
+
+struct rsn_ftie {
+	u8 mic_control[2];
+	u8 mic[16];
+	u8 anonce[WPA_NONCE_LEN];
+	u8 snonce[WPA_NONCE_LEN];
+	/* followed by optional parameters */
+} STRUCT_PACKED;
+
+#define FTIE_SUBELEM_R1KH_ID 1
+#define FTIE_SUBELEM_GTK 2
+#define FTIE_SUBELEM_R0KH_ID 3
+#define FTIE_SUBELEM_IGTK 4
+
+struct rsn_rdie {
+	u8 id;
+	u8 descr_count;
+	le16 status_code;
+} STRUCT_PACKED;
+
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic);
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256);
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic);
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name);
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name);
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name);
+#endif /* CONFIG_IEEE80211R */
+
+struct wpa_ie_data {
+	int proto;
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int capabilities;
+	size_t num_pmkid;
+	const u8 *pmkid;
+	int mgmt_group_cipher;
+};
+
+
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data);
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data);
+
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256);
+
+const char * wpa_cipher_txt(int cipher);
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+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);
+
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
+int wpa_cipher_key_len(int cipher);
+int wpa_cipher_rsc_len(int cipher);
+int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_pairwise(int cipher);
+u32 wpa_cipher_to_suite(int proto, int cipher);
+int rsn_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_cipher_put_suites(u8 *pos, int ciphers);
+
+#endif /* WPA_COMMON_H */

Deleted: vendor/wpa/2.0/src/common/wpa_ctrl.c
===================================================================
--- vendor/wpa/dist/src/common/wpa_ctrl.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/wpa_ctrl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,455 +0,0 @@
-/*
- * wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#ifdef CONFIG_CTRL_IFACE
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-#include <sys/un.h>
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
-#include "wpa_ctrl.h"
-#include "common.h"
-
-
-#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
-#define CTRL_IFACE_SOCKET
-#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
-
-
-/**
- * struct wpa_ctrl - Internal structure for control interface library
- *
- * This structure is used by the wpa_supplicant/hostapd control interface
- * library to store internal data. Programs using the library should not touch
- * this data directly. They can only use the pointer to the data structure as
- * an identifier for the control interface connection and use this as one of
- * the arguments for most of the control interface library functions.
- */
-struct wpa_ctrl {
-#ifdef CONFIG_CTRL_IFACE_UDP
-	int s;
-	struct sockaddr_in local;
-	struct sockaddr_in dest;
-	char *cookie;
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#ifdef CONFIG_CTRL_IFACE_UNIX
-	int s;
-	struct sockaddr_un local;
-	struct sockaddr_un dest;
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-	HANDLE pipe;
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-};
-
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-
-struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
-{
-	struct wpa_ctrl *ctrl;
-	static int counter = 0;
-	int ret;
-	size_t res;
-	int tries = 0;
-
-	ctrl = os_malloc(sizeof(*ctrl));
-	if (ctrl == NULL)
-		return NULL;
-	os_memset(ctrl, 0, sizeof(*ctrl));
-
-	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (ctrl->s < 0) {
-		os_free(ctrl);
-		return NULL;
-	}
-
-	ctrl->local.sun_family = AF_UNIX;
-	counter++;
-try_again:
-	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
-			  "/tmp/wpa_ctrl_%d-%d", getpid(), counter);
-	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
-	}
-	tries++;
-	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
-		    sizeof(ctrl->local)) < 0) {
-		if (errno == EADDRINUSE && tries < 2) {
-			/*
-			 * getpid() returns unique identifier for this instance
-			 * of wpa_ctrl, so the existing socket file must have
-			 * been left by unclean termination of an earlier run.
-			 * Remove the file and try again.
-			 */
-			unlink(ctrl->local.sun_path);
-			goto try_again;
-		}
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
-	}
-
-	ctrl->dest.sun_family = AF_UNIX;
-	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
-			 sizeof(ctrl->dest.sun_path));
-	if (res >= sizeof(ctrl->dest.sun_path)) {
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
-	}
-	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
-		    sizeof(ctrl->dest)) < 0) {
-		close(ctrl->s);
-		unlink(ctrl->local.sun_path);
-		os_free(ctrl);
-		return NULL;
-	}
-
-	return ctrl;
-}
-
-
-void wpa_ctrl_close(struct wpa_ctrl *ctrl)
-{
-	unlink(ctrl->local.sun_path);
-	close(ctrl->s);
-	os_free(ctrl);
-}
-
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
-
-#ifdef CONFIG_CTRL_IFACE_UDP
-
-struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
-{
-	struct wpa_ctrl *ctrl;
-	char buf[128];
-	size_t len;
-
-	ctrl = os_malloc(sizeof(*ctrl));
-	if (ctrl == NULL)
-		return NULL;
-	os_memset(ctrl, 0, sizeof(*ctrl));
-
-	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (ctrl->s < 0) {
-		perror("socket");
-		os_free(ctrl);
-		return NULL;
-	}
-
-	ctrl->local.sin_family = AF_INET;
-	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
-	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
-		 sizeof(ctrl->local)) < 0) {
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
-	}
-
-	ctrl->dest.sin_family = AF_INET;
-	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
-	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
-	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
-		    sizeof(ctrl->dest)) < 0) {
-		perror("connect");
-		close(ctrl->s);
-		os_free(ctrl);
-		return NULL;
-	}
-
-	len = sizeof(buf) - 1;
-	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
-		buf[len] = '\0';
-		ctrl->cookie = os_strdup(buf);
-	}
-
-	return ctrl;
-}
-
-
-void wpa_ctrl_close(struct wpa_ctrl *ctrl)
-{
-	close(ctrl->s);
-	os_free(ctrl->cookie);
-	os_free(ctrl);
-}
-
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
-
-#ifdef CTRL_IFACE_SOCKET
-int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
-		     char *reply, size_t *reply_len,
-		     void (*msg_cb)(char *msg, size_t len))
-{
-	struct timeval tv;
-	int res;
-	fd_set rfds;
-	const char *_cmd;
-	char *cmd_buf = NULL;
-	size_t _cmd_len;
-
-#ifdef CONFIG_CTRL_IFACE_UDP
-	if (ctrl->cookie) {
-		char *pos;
-		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
-		cmd_buf = os_malloc(_cmd_len);
-		if (cmd_buf == NULL)
-			return -1;
-		_cmd = cmd_buf;
-		pos = cmd_buf;
-		os_strlcpy(pos, ctrl->cookie, _cmd_len);
-		pos += os_strlen(ctrl->cookie);
-		*pos++ = ' ';
-		os_memcpy(pos, cmd, cmd_len);
-	} else
-#endif /* CONFIG_CTRL_IFACE_UDP */
-	{
-		_cmd = cmd;
-		_cmd_len = cmd_len;
-	}
-
-	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
-		os_free(cmd_buf);
-		return -1;
-	}
-	os_free(cmd_buf);
-
-	for (;;) {
-		tv.tv_sec = 2;
-		tv.tv_usec = 0;
-		FD_ZERO(&rfds);
-		FD_SET(ctrl->s, &rfds);
-		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
-		if (FD_ISSET(ctrl->s, &rfds)) {
-			res = recv(ctrl->s, reply, *reply_len, 0);
-			if (res < 0)
-				return res;
-			if (res > 0 && reply[0] == '<') {
-				/* This is an unsolicited message from
-				 * wpa_supplicant, not the reply to the
-				 * request. Use msg_cb to report this to the
-				 * caller. */
-				if (msg_cb) {
-					/* Make sure the message is nul
-					 * terminated. */
-					if ((size_t) res == *reply_len)
-						res = (*reply_len) - 1;
-					reply[res] = '\0';
-					msg_cb(reply, res);
-				}
-				continue;
-			}
-			*reply_len = res;
-			break;
-		} else {
-			return -2;
-		}
-	}
-	return 0;
-}
-#endif /* CTRL_IFACE_SOCKET */
-
-
-static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
-{
-	char buf[10];
-	int ret;
-	size_t len = 10;
-
-	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
-			       buf, &len, NULL);
-	if (ret < 0)
-		return ret;
-	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
-		return 0;
-	return -1;
-}
-
-
-int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
-{
-	return wpa_ctrl_attach_helper(ctrl, 1);
-}
-
-
-int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
-{
-	return wpa_ctrl_attach_helper(ctrl, 0);
-}
-
-
-#ifdef CTRL_IFACE_SOCKET
-
-int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
-{
-	int res;
-
-	res = recv(ctrl->s, reply, *reply_len, 0);
-	if (res < 0)
-		return res;
-	*reply_len = res;
-	return 0;
-}
-
-
-int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
-{
-	struct timeval tv;
-	fd_set rfds;
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-	FD_ZERO(&rfds);
-	FD_SET(ctrl->s, &rfds);
-	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
-	return FD_ISSET(ctrl->s, &rfds);
-}
-
-
-int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
-{
-	return ctrl->s;
-}
-
-#endif /* CTRL_IFACE_SOCKET */
-
-
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-
-#ifndef WPA_SUPPLICANT_NAMED_PIPE
-#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
-#endif
-#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
-
-struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
-{
-	struct wpa_ctrl *ctrl;
-	DWORD mode;
-	TCHAR name[256];
-	int i, ret;
-
-	ctrl = os_malloc(sizeof(*ctrl));
-	if (ctrl == NULL)
-		return NULL;
-	os_memset(ctrl, 0, sizeof(*ctrl));
-
-#ifdef UNICODE
-	if (ctrl_path == NULL)
-		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
-	else
-		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
-				 ctrl_path);
-#else /* UNICODE */
-	if (ctrl_path == NULL)
-		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
-	else
-		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
-				  ctrl_path);
-#endif /* UNICODE */
-	if (ret < 0 || ret >= 256) {
-		os_free(ctrl);
-		return NULL;
-	}
-
-	for (i = 0; i < 10; i++) {
-		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
-					NULL, OPEN_EXISTING, 0, NULL);
-		/*
-		 * Current named pipe server side in wpa_supplicant is
-		 * re-opening the pipe for new clients only after the previous
-		 * one is taken into use. This leaves a small window for race
-		 * conditions when two connections are being opened at almost
-		 * the same time. Retry if that was the case.
-		 */
-		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
-		    GetLastError() != ERROR_PIPE_BUSY)
-			break;
-		WaitNamedPipe(name, 1000);
-	}
-	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
-		os_free(ctrl);
-		return NULL;
-	}
-
-	mode = PIPE_READMODE_MESSAGE;
-	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
-		CloseHandle(ctrl->pipe);
-		os_free(ctrl);
-		return NULL;
-	}
-
-	return ctrl;
-}
-
-
-void wpa_ctrl_close(struct wpa_ctrl *ctrl)
-{
-	CloseHandle(ctrl->pipe);
-	os_free(ctrl);
-}
-
-
-int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
-		     char *reply, size_t *reply_len,
-		     void (*msg_cb)(char *msg, size_t len))
-{
-	DWORD written;
-	DWORD readlen = *reply_len;
-
-	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
-		return -1;
-
-	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
-		return -1;
-	*reply_len = readlen;
-
-	return 0;
-}
-
-
-int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
-{
-	DWORD len = *reply_len;
-	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
-		return -1;
-	*reply_len = len;
-	return 0;
-}
-
-
-int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
-{
-	DWORD left;
-
-	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
-		return -1;
-	return left ? 1 : 0;
-}
-
-
-int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
-{
-	return -1;
-}
-
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-
-#endif /* CONFIG_CTRL_IFACE */

Copied: vendor/wpa/2.0/src/common/wpa_ctrl.c (from rev 9639, vendor/wpa/dist/src/common/wpa_ctrl.c)
===================================================================
--- vendor/wpa/2.0/src/common/wpa_ctrl.c	                        (rev 0)
+++ vendor/wpa/2.0/src/common/wpa_ctrl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,652 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef ANDROID
+#include <dirent.h>
+#include <cutils/sockets.h>
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
+
+#include "wpa_ctrl.h"
+#include "common.h"
+
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+#define CTRL_IFACE_SOCKET
+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
+
+
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
+struct wpa_ctrl {
+#ifdef CONFIG_CTRL_IFACE_UDP
+	int s;
+	struct sockaddr_in local;
+	struct sockaddr_in dest;
+	char *cookie;
+	char *remote_ifname;
+	char *remote_ip;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+	int s;
+	struct sockaddr_un local;
+	struct sockaddr_un dest;
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	HANDLE pipe;
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+};
+
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+
+#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
+#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
+#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
+#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
+
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	static int counter = 0;
+	int ret;
+	size_t res;
+	int tries = 0;
+	int flags;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sun_family = AF_UNIX;
+	counter++;
+try_again:
+	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+			  (int) getpid(), counter);
+	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	tries++;
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		    sizeof(ctrl->local)) < 0) {
+		if (errno == EADDRINUSE && tries < 2) {
+			/*
+			 * getpid() returns unique identifier for this instance
+			 * of wpa_ctrl, so the existing socket file must have
+			 * been left by unclean termination of an earlier run.
+			 * Remove the file and try again.
+			 */
+			unlink(ctrl->local.sun_path);
+			goto try_again;
+		}
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+#ifdef ANDROID
+	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+	/*
+	 * If the ctrl_path isn't an absolute pathname, assume that
+	 * it's the name of a socket in the Android reserved namespace.
+	 * Otherwise, it's a normal UNIX domain socket appearing in the
+	 * filesystem.
+	 */
+	if (ctrl_path != NULL && *ctrl_path != '/') {
+		char buf[21];
+		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
+		if (socket_local_client_connect(
+			    ctrl->s, buf,
+			    ANDROID_SOCKET_NAMESPACE_RESERVED,
+			    SOCK_DGRAM) < 0) {
+			close(ctrl->s);
+			unlink(ctrl->local.sun_path);
+			os_free(ctrl);
+			return NULL;
+		}
+		return ctrl;
+	}
+#endif /* ANDROID */
+
+	ctrl->dest.sun_family = AF_UNIX;
+	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
+			 sizeof(ctrl->dest.sun_path));
+	if (res >= sizeof(ctrl->dest.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		close(ctrl->s);
+		unlink(ctrl->local.sun_path);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	/*
+	 * Make socket non-blocking so that we don't hang forever if
+	 * target dies unexpectedly.
+	 */
+	flags = fcntl(ctrl->s, F_GETFL);
+	if (flags >= 0) {
+		flags |= O_NONBLOCK;
+		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
+			perror("fcntl(ctrl->s, O_NONBLOCK)");
+			/* Not fatal, continue on.*/
+		}
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	if (ctrl == NULL)
+		return;
+	unlink(ctrl->local.sun_path);
+	if (ctrl->s >= 0)
+		close(ctrl->s);
+	os_free(ctrl);
+}
+
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+	DIR *dir;
+	struct dirent entry;
+	struct dirent *result;
+	size_t dirnamelen;
+	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+	size_t maxcopy;
+	char pathname[PATH_MAX];
+	char *namep;
+
+	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+		return;
+
+	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+					  CONFIG_CTRL_IFACE_CLIENT_DIR);
+	if (dirnamelen >= sizeof(pathname)) {
+		closedir(dir);
+		return;
+	}
+	namep = pathname + dirnamelen;
+	maxcopy = PATH_MAX - dirnamelen;
+	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+			       prefixlen) == 0) {
+			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+				unlink(pathname);
+		}
+	}
+	closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	char buf[128];
+	size_t len;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	struct hostent *h;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		perror("socket");
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	ctrl->local.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		 sizeof(ctrl->local)) < 0) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->dest.sin_family = AF_INET;
+	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	if (ctrl_path) {
+		char *port, *name;
+		int port_id;
+
+		name = os_strdup(ctrl_path);
+		if (name == NULL) {
+			close(ctrl->s);
+			os_free(ctrl);
+			return NULL;
+		}
+		port = os_strchr(name, ':');
+
+		if (port) {
+			port_id = atoi(&port[1]);
+			port[0] = '\0';
+		} else
+			port_id = WPA_CTRL_IFACE_PORT;
+
+		h = gethostbyname(name);
+		ctrl->remote_ip = os_strdup(name);
+		os_free(name);
+		if (h == NULL) {
+			perror("gethostbyname");
+			close(ctrl->s);
+			os_free(ctrl->remote_ip);
+			os_free(ctrl);
+			return NULL;
+		}
+		ctrl->dest.sin_port = htons(port_id);
+		os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
+			  h->h_length);
+	} else
+		ctrl->remote_ip = os_strdup("localhost");
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		perror("connect");
+		close(ctrl->s);
+		os_free(ctrl->remote_ip);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->cookie = os_strdup(buf);
+	}
+
+	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->remote_ifname = os_strdup(buf);
+	}
+
+	return ctrl;
+}
+
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
+{
+#define WPA_CTRL_MAX_PS_NAME 100
+	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
+	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
+		    ctrl->remote_ip, ctrl->remote_ifname);
+	return ps;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	close(ctrl->s);
+	os_free(ctrl->cookie);
+	os_free(ctrl->remote_ifname);
+	os_free(ctrl->remote_ip);
+	os_free(ctrl);
+}
+
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef CTRL_IFACE_SOCKET
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	struct timeval tv;
+	struct os_time started_at;
+	int res;
+	fd_set rfds;
+	const char *_cmd;
+	char *cmd_buf = NULL;
+	size_t _cmd_len;
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+	if (ctrl->cookie) {
+		char *pos;
+		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
+		cmd_buf = os_malloc(_cmd_len);
+		if (cmd_buf == NULL)
+			return -1;
+		_cmd = cmd_buf;
+		pos = cmd_buf;
+		os_strlcpy(pos, ctrl->cookie, _cmd_len);
+		pos += os_strlen(ctrl->cookie);
+		*pos++ = ' ';
+		os_memcpy(pos, cmd, cmd_len);
+	} else
+#endif /* CONFIG_CTRL_IFACE_UDP */
+	{
+		_cmd = cmd;
+		_cmd_len = cmd_len;
+	}
+
+	errno = 0;
+	started_at.sec = 0;
+	started_at.usec = 0;
+retry_send:
+	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
+		{
+			/*
+			 * Must be a non-blocking socket... Try for a bit
+			 * longer before giving up.
+			 */
+			if (started_at.sec == 0)
+				os_get_time(&started_at);
+			else {
+				struct os_time n;
+				os_get_time(&n);
+				/* Try for a few seconds. */
+				if (n.sec > started_at.sec + 5)
+					goto send_err;
+			}
+			os_sleep(1, 0);
+			goto retry_send;
+		}
+	send_err:
+		os_free(cmd_buf);
+		return -1;
+	}
+	os_free(cmd_buf);
+
+	for (;;) {
+		tv.tv_sec = 10;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_SET(ctrl->s, &rfds);
+		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0)
+			return res;
+		if (FD_ISSET(ctrl->s, &rfds)) {
+			res = recv(ctrl->s, reply, *reply_len, 0);
+			if (res < 0)
+				return res;
+			if (res > 0 && reply[0] == '<') {
+				/* This is an unsolicited message from
+				 * wpa_supplicant, not the reply to the
+				 * request. Use msg_cb to report this to the
+				 * caller. */
+				if (msg_cb) {
+					/* Make sure the message is nul
+					 * terminated. */
+					if ((size_t) res == *reply_len)
+						res = (*reply_len) - 1;
+					reply[res] = '\0';
+					msg_cb(reply, res);
+				}
+				continue;
+			}
+			*reply_len = res;
+			break;
+		} else {
+			return -2;
+		}
+	}
+	return 0;
+}
+#endif /* CTRL_IFACE_SOCKET */
+
+
+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
+{
+	char buf[10];
+	int ret;
+	size_t len = 10;
+
+	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+			       buf, &len, NULL);
+	if (ret < 0)
+		return ret;
+	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
+		return 0;
+	return -1;
+}
+
+
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 0);
+}
+
+
+#ifdef CTRL_IFACE_SOCKET
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	int res;
+
+	res = recv(ctrl->s, reply, *reply_len, 0);
+	if (res < 0)
+		return res;
+	*reply_len = res;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	struct timeval tv;
+	fd_set rfds;
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfds);
+	FD_SET(ctrl->s, &rfds);
+	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+	return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return ctrl->s;
+}
+
+#endif /* CTRL_IFACE_SOCKET */
+
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	DWORD mode;
+	TCHAR name[256];
+	int i, ret;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef UNICODE
+	if (ctrl_path == NULL)
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+				 ctrl_path);
+#else /* UNICODE */
+	if (ctrl_path == NULL)
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+				  ctrl_path);
+#endif /* UNICODE */
+	if (ret < 0 || ret >= 256) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	for (i = 0; i < 10; i++) {
+		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
+					NULL, OPEN_EXISTING, 0, NULL);
+		/*
+		 * Current named pipe server side in wpa_supplicant is
+		 * re-opening the pipe for new clients only after the previous
+		 * one is taken into use. This leaves a small window for race
+		 * conditions when two connections are being opened at almost
+		 * the same time. Retry if that was the case.
+		 */
+		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
+		    GetLastError() != ERROR_PIPE_BUSY)
+			break;
+		WaitNamedPipe(name, 1000);
+	}
+	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	mode = PIPE_READMODE_MESSAGE;
+	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
+		CloseHandle(ctrl->pipe);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	CloseHandle(ctrl->pipe);
+	os_free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	DWORD written;
+	DWORD readlen = *reply_len;
+
+	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
+		return -1;
+
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
+		return -1;
+	*reply_len = readlen;
+
+	return 0;
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	DWORD len = *reply_len;
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
+		return -1;
+	*reply_len = len;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	DWORD left;
+
+	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
+		return -1;
+	return left ? 1 : 0;
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return -1;
+}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#endif /* CONFIG_CTRL_IFACE */

Deleted: vendor/wpa/2.0/src/common/wpa_ctrl.h
===================================================================
--- vendor/wpa/dist/src/common/wpa_ctrl.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/common/wpa_ctrl.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,236 +0,0 @@
-/*
- * wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_CTRL_H
-#define WPA_CTRL_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-/* wpa_supplicant control interface - fixed message prefixes */
-
-/** Interactive request for identity/password/pin */
-#define WPA_CTRL_REQ "CTRL-REQ-"
-
-/** Response to identity/password/pin request */
-#define WPA_CTRL_RSP "CTRL-RSP-"
-
-/* Event messages with fixed prefix */
-/** Authentication completed successfully and data connection enabled */
-#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
-/** Disconnected, data connection is not available */
-#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
-/** wpa_supplicant is exiting */
-#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
-/** Password change was completed successfully */
-#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
-/** EAP-Request/Notification received */
-#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
-/** EAP authentication started (EAP-Request/Identity received) */
-#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
-/** EAP method proposed by the server */
-#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
-/** EAP method selected */
-#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
-/** EAP peer certificate from TLS */
-#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
-/** EAP TLS certificate chain validation error */
-#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
-/** EAP authentication completed successfully */
-#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
-/** EAP authentication failed (EAP-Failure received) */
-#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
-/** New scan results available */
-#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
-/** A new BSS entry was added (followed by BSS entry id and BSSID) */
-#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
-/** A BSS entry was removed (followed by BSS entry id and BSSID) */
-#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
-
-/** WPS overlap detected in PBC mode */
-#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
-/** Available WPS AP with active PBC found in scan results */
-#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
-/** Available WPS AP with recently selected PIN registrar found in scan results
- */
-#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
-/** Available WPS AP found in scan results */
-#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
-/** A new credential received */
-#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
-/** M2D received */
-#define WPS_EVENT_M2D "WPS-M2D "
-/** WPS registration failed after M2/M2D */
-#define WPS_EVENT_FAIL "WPS-FAIL "
-/** WPS registration completed successfully */
-#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
-/** WPS enrollment attempt timed out and was terminated */
-#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
-
-#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
-
-/* WPS ER events */
-#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
-#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
-#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
-#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
-
-/* hostapd control interface - fixed message prefixes */
-#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
-#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
-#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
-#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
-#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
-#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
-#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
-#define AP_STA_CONNECTED "AP-STA-CONNECTED "
-#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
-
-
-/* wpa_supplicant/hostapd control interface access */
-
-/**
- * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
- * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
- * Returns: Pointer to abstract control interface data or %NULL on failure
- *
- * This function is used to open a control interface to wpa_supplicant/hostapd.
- * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
- * is configured in wpa_supplicant/hostapd and other programs using the control
- * interface need to use matching path configuration.
- */
-struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
-
-
-/**
- * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
- * @ctrl: Control interface data from wpa_ctrl_open()
- *
- * This function is used to close a control interface.
- */
-void wpa_ctrl_close(struct wpa_ctrl *ctrl);
-
-
-/**
- * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
- * @ctrl: Control interface data from wpa_ctrl_open()
- * @cmd: Command; usually, ASCII text, e.g., "PING"
- * @cmd_len: Length of the cmd in bytes
- * @reply: Buffer for the response
- * @reply_len: Reply buffer length
- * @msg_cb: Callback function for unsolicited messages or %NULL if not used
- * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
- *
- * This function is used to send commands to wpa_supplicant/hostapd. Received
- * response will be written to reply and reply_len is set to the actual length
- * of the reply. This function will block for up to two seconds while waiting
- * for the reply. If unsolicited messages are received, the blocking time may
- * be longer.
- *
- * msg_cb can be used to register a callback function that will be called for
- * unsolicited messages received while waiting for the command response. These
- * messages may be received if wpa_ctrl_request() is called at the same time as
- * wpa_supplicant/hostapd is sending such a message. This can happen only if
- * the program has used wpa_ctrl_attach() to register itself as a monitor for
- * event messages. Alternatively to msg_cb, programs can register two control
- * interface connections and use one of them for commands and the other one for
- * receiving event messages, in other words, call wpa_ctrl_attach() only for
- * the control interface connection that will be used for event messages.
- */
-int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
-		     char *reply, size_t *reply_len,
-		     void (*msg_cb)(char *msg, size_t len));
-
-
-/**
- * wpa_ctrl_attach - Register as an event monitor for the control interface
- * @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: 0 on success, -1 on failure, -2 on timeout
- *
- * This function registers the control interface connection as a monitor for
- * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
- * control interface connection starts receiving event messages that can be
- * read with wpa_ctrl_recv().
- */
-int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
-
-
-/**
- * wpa_ctrl_detach - Unregister event monitor from the control interface
- * @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: 0 on success, -1 on failure, -2 on timeout
- *
- * This function unregisters the control interface connection as a monitor for
- * wpa_supplicant/hostapd events, i.e., cancels the registration done with
- * wpa_ctrl_attach().
- */
-int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
-
-
-/**
- * wpa_ctrl_recv - Receive a pending control interface message
- * @ctrl: Control interface data from wpa_ctrl_open()
- * @reply: Buffer for the message data
- * @reply_len: Length of the reply buffer
- * Returns: 0 on success, -1 on failure
- *
- * This function will receive a pending control interface message. This
- * function will block if no messages are available. The received response will
- * be written to reply and reply_len is set to the actual length of the reply.
- * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
- * must have been used to register the control interface as an event monitor.
- */
-int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
-
-
-/**
- * wpa_ctrl_pending - Check whether there are pending event messages
- * @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: 1 if there are pending messages, 0 if no, or -1 on error
- *
- * This function will check whether there are any pending control interface
- * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
- * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
- * register the control interface as an event monitor.
- */
-int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
-
-
-/**
- * wpa_ctrl_get_fd - Get file descriptor used by the control interface
- * @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: File descriptor used for the connection
- *
- * This function can be used to get the file descriptor that is used for the
- * control interface connection. The returned value can be used, e.g., with
- * select() while waiting for multiple events.
- *
- * The returned file descriptor must not be used directly for sending or
- * receiving packets; instead, the library functions wpa_ctrl_request() and
- * wpa_ctrl_recv() must be used for this.
- */
-int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
-
-#ifdef CONFIG_CTRL_IFACE_UDP
-#define WPA_CTRL_IFACE_PORT 9877
-#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WPA_CTRL_H */

Copied: vendor/wpa/2.0/src/common/wpa_ctrl.h (from rev 9639, vendor/wpa/dist/src/common/wpa_ctrl.h)
===================================================================
--- vendor/wpa/2.0/src/common/wpa_ctrl.h	                        (rev 0)
+++ vendor/wpa/2.0/src/common/wpa_ctrl.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,322 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_CTRL_H
+#define WPA_CTRL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** Association rejected during connection attempt */
+#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method proposed by the server */
+#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP peer certificate from TLS */
+#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP TLS certificate chain validation error */
+#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** Network block temporarily disabled (e.g., due to authentication failure) */
+#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
+/** Temporarily disabled network block re-enabled */
+#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
+/** New scan results available */
+#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** wpa_supplicant state change */
+#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
+/** A new BSS entry was added (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
+/** A BSS entry was removed (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+
+/** WPS overlap detected in PBC mode */
+#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
+/** Available WPS AP with active PBC found in scan results */
+#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with our address as authorized in scan results */
+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
+/** Available WPS AP with recently selected PIN registrar found in scan results
+ */
+#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
+/** Available WPS AP found in scan results */
+#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
+/** A new credential received */
+#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
+/** M2D received */
+#define WPS_EVENT_M2D "WPS-M2D "
+/** WPS registration failed after M2/M2D */
+#define WPS_EVENT_FAIL "WPS-FAIL "
+/** WPS registration completed successfully */
+#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
+/** WPS enrollment attempt timed out and was terminated */
+#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
+
+#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
+
+#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+
+/* WPS ER events */
+#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
+#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
+#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
+#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
+#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
+#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+
+/** P2P device found */
+#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
+
+/** P2P device lost */
+#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
+
+/** A P2P device requested GO negotiation, but we were not ready to start the
+ * negotiation */
+#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
+#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
+#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
+#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
+#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
+#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
+#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
+#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
+#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
+/* parameters: <peer address> <PIN> */
+#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <peer address> <status> */
+#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
+/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
+/* parameters: <src addr> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
+#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
+#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+
+#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+
+/* hostapd control interface - fixed message prefixes */
+#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
+#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
+#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
+#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
+#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
+#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
+#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
+#define AP_STA_CONNECTED "AP-STA-CONNECTED "
+#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+
+
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL		0xFFFFFFFF
+#define WPA_BSS_MASK_ID			BIT(0)
+#define WPA_BSS_MASK_BSSID		BIT(1)
+#define WPA_BSS_MASK_FREQ		BIT(2)
+#define WPA_BSS_MASK_BEACON_INT		BIT(3)
+#define WPA_BSS_MASK_CAPABILITIES	BIT(4)
+#define WPA_BSS_MASK_QUAL		BIT(5)
+#define WPA_BSS_MASK_NOISE		BIT(6)
+#define WPA_BSS_MASK_LEVEL		BIT(7)
+#define WPA_BSS_MASK_TSF		BIT(8)
+#define WPA_BSS_MASK_AGE		BIT(9)
+#define WPA_BSS_MASK_IE			BIT(10)
+#define WPA_BSS_MASK_FLAGS		BIT(11)
+#define WPA_BSS_MASK_SSID		BIT(12)
+#define WPA_BSS_MASK_WPS_SCAN		BIT(13)
+#define WPA_BSS_MASK_P2P_SCAN		BIT(14)
+#define WPA_BSS_MASK_INTERNETW		BIT(15)
+#define WPA_BSS_MASK_WIFI_DISPLAY	BIT(16)
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
+void wpa_ctrl_close(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
+
+
+/**
+ * wpa_ctrl_pending - Check whether there are pending event messages
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+/* Port range for multiple wpa_supplicant instances and multiple VIFs */
+#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WPA_CTRL_H */

Deleted: vendor/wpa/2.0/src/crypto/Makefile
===================================================================
--- vendor/wpa/dist/src/crypto/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,56 +0,0 @@
-all: libcrypto.a
-
-clean:
-	rm -f *~ *.o *.d libcrypto.a
-
-install:
-	@echo Nothing to be made.
-
-
-include ../lib.rules
-
-CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
-CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
-#CFLAGS += -DALL_DH_GROUPS
-
-LIB_OBJS= \
-	aes-cbc.o \
-	aes-ctr.o \
-	aes-eax.o \
-	aes-encblock.o \
-	aes-internal.o \
-	aes-internal-dec.o \
-	aes-internal-enc.o \
-	aes-omac1.o \
-	aes-unwrap.o \
-	aes-wrap.o \
-	des-internal.o \
-	dh_group5.o \
-	dh_groups.o \
-	md4-internal.o \
-	md5.o \
-	md5-internal.o \
-	md5-non-fips.o \
-	milenage.o \
-	ms_funcs.o \
-	rc4.o \
-	sha1.o \
-	sha1-internal.o \
-	sha1-pbkdf2.o \
-	sha1-tlsprf.o \
-	sha1-tprf.o \
-	sha256.o \
-	sha256-internal.o
-
-LIB_OBJS += crypto_internal.o
-LIB_OBJS += crypto_internal-cipher.o
-LIB_OBJS += crypto_internal-modexp.o
-LIB_OBJS += crypto_internal-rsa.o
-LIB_OBJS += tls_internal.o
-LIB_OBJS += fips_prf_internal.o
-
-
-libcrypto.a: $(LIB_OBJS)
-	$(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/src/crypto/Makefile (from rev 9639, vendor/wpa/dist/src/crypto/Makefile)
===================================================================
--- vendor/wpa/2.0/src/crypto/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,62 @@
+all: libcrypto.a
+
+clean:
+	rm -f *~ *.o *.d libcrypto.a
+
+install:
+	@echo Nothing to be made.
+
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+#CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
+
+LIB_OBJS= \
+	aes-cbc.o \
+	aes-ccm.o \
+	aes-ctr.o \
+	aes-eax.o \
+	aes-encblock.o \
+	aes-gcm.o \
+	aes-internal.o \
+	aes-internal-dec.o \
+	aes-internal-enc.o \
+	aes-omac1.o \
+	aes-unwrap.o \
+	aes-wrap.o \
+	des-internal.o \
+	dh_group5.o \
+	dh_groups.o \
+	md4-internal.o \
+	md5.o \
+	md5-internal.o \
+	milenage.o \
+	ms_funcs.o \
+	rc4.o \
+	sha1.o \
+	sha1-internal.o \
+	sha1-pbkdf2.o \
+	sha1-prf.o \
+	sha1-tlsprf.o \
+	sha1-tprf.o \
+	sha256.o \
+	sha256-prf.o \
+	sha256-tlsprf.o \
+	sha256-internal.o
+
+LIB_OBJS += crypto_internal.o
+LIB_OBJS += crypto_internal-cipher.o
+LIB_OBJS += crypto_internal-modexp.o
+LIB_OBJS += crypto_internal-rsa.o
+LIB_OBJS += tls_internal.o
+LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
+
+
+libcrypto.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/src/crypto/aes-cbc.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-cbc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-cbc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,86 +0,0 @@
-/*
- * AES-128 CBC
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_128_cbc_encrypt - AES-128 CBC encryption
- * @key: Encryption key
- * @iv: Encryption IV for CBC mode (16 bytes)
- * @data: Data to encrypt in-place
- * @data_len: Length of data in bytes (must be divisible by 16)
- * Returns: 0 on success, -1 on failure
- */
-int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
-{
-	void *ctx;
-	u8 cbc[AES_BLOCK_SIZE];
-	u8 *pos = data;
-	int i, j, blocks;
-
-	ctx = aes_encrypt_init(key, 16);
-	if (ctx == NULL)
-		return -1;
-	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
-
-	blocks = data_len / AES_BLOCK_SIZE;
-	for (i = 0; i < blocks; i++) {
-		for (j = 0; j < AES_BLOCK_SIZE; j++)
-			cbc[j] ^= pos[j];
-		aes_encrypt(ctx, cbc, cbc);
-		os_memcpy(pos, cbc, AES_BLOCK_SIZE);
-		pos += AES_BLOCK_SIZE;
-	}
-	aes_encrypt_deinit(ctx);
-	return 0;
-}
-
-
-/**
- * aes_128_cbc_decrypt - AES-128 CBC decryption
- * @key: Decryption key
- * @iv: Decryption IV for CBC mode (16 bytes)
- * @data: Data to decrypt in-place
- * @data_len: Length of data in bytes (must be divisible by 16)
- * Returns: 0 on success, -1 on failure
- */
-int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
-{
-	void *ctx;
-	u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
-	u8 *pos = data;
-	int i, j, blocks;
-
-	ctx = aes_decrypt_init(key, 16);
-	if (ctx == NULL)
-		return -1;
-	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
-
-	blocks = data_len / AES_BLOCK_SIZE;
-	for (i = 0; i < blocks; i++) {
-		os_memcpy(tmp, pos, AES_BLOCK_SIZE);
-		aes_decrypt(ctx, pos, pos);
-		for (j = 0; j < AES_BLOCK_SIZE; j++)
-			pos[j] ^= cbc[j];
-		os_memcpy(cbc, tmp, AES_BLOCK_SIZE);
-		pos += AES_BLOCK_SIZE;
-	}
-	aes_decrypt_deinit(ctx);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/aes-cbc.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-cbc.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-cbc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-cbc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,80 @@
+/*
+ * AES-128 CBC
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_cbc_encrypt - AES-128 CBC encryption
+ * @key: Encryption key
+ * @iv: Encryption IV for CBC mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE];
+	u8 *pos = data;
+	int i, j, blocks;
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
+
+	blocks = data_len / AES_BLOCK_SIZE;
+	for (i = 0; i < blocks; i++) {
+		for (j = 0; j < AES_BLOCK_SIZE; j++)
+			cbc[j] ^= pos[j];
+		aes_encrypt(ctx, cbc, cbc);
+		os_memcpy(pos, cbc, AES_BLOCK_SIZE);
+		pos += AES_BLOCK_SIZE;
+	}
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+
+/**
+ * aes_128_cbc_decrypt - AES-128 CBC decryption
+ * @key: Decryption key
+ * @iv: Decryption IV for CBC mode (16 bytes)
+ * @data: Data to decrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
+	u8 *pos = data;
+	int i, j, blocks;
+
+	ctx = aes_decrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
+
+	blocks = data_len / AES_BLOCK_SIZE;
+	for (i = 0; i < blocks; i++) {
+		os_memcpy(tmp, pos, AES_BLOCK_SIZE);
+		aes_decrypt(ctx, pos, pos);
+		for (j = 0; j < AES_BLOCK_SIZE; j++)
+			pos[j] ^= cbc[j];
+		os_memcpy(cbc, tmp, AES_BLOCK_SIZE);
+		pos += AES_BLOCK_SIZE;
+	}
+	aes_decrypt_deinit(ctx);
+	return 0;
+}

Copied: vendor/wpa/2.0/src/crypto/aes-ccm.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-ccm.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-ccm.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-ccm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,212 @@
+/*
+ * Counter with CBC-MAC (CCM) with AES
+ *
+ * Copyright (c) 2010-2012, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+
+static void xor_aes_block(u8 *dst, const u8 *src)
+{
+	u32 *d = (u32 *) dst;
+	u32 *s = (u32 *) src;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+}
+
+
+static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce,
+			       const u8 *aad, size_t aad_len, size_t plain_len,
+			       u8 *x)
+{
+	u8 aad_buf[2 * AES_BLOCK_SIZE];
+	u8 b[AES_BLOCK_SIZE];
+
+	/* Authentication */
+	/* B_0: Flags | Nonce N | l(m) */
+	b[0] = aad_len ? 0x40 : 0 /* Adata */;
+	b[0] |= (((M - 2) / 2) /* M' */ << 3);
+	b[0] |= (L - 1) /* L' */;
+	os_memcpy(&b[1], nonce, 15 - L);
+	WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len);
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM B_0", b, AES_BLOCK_SIZE);
+	aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
+
+	if (!aad_len)
+		return;
+
+	WPA_PUT_BE16(aad_buf, aad_len);
+	os_memcpy(aad_buf + 2, aad, aad_len);
+	os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len);
+
+	xor_aes_block(aad_buf, x);
+	aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */
+
+	if (aad_len > AES_BLOCK_SIZE - 2) {
+		xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x);
+		/* X_3 = E(K, X_2 XOR B_2) */
+		aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x);
+	}
+}
+
+
+static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	for (i = 0; i < len / AES_BLOCK_SIZE; i++) {
+		/* X_i+1 = E(K, X_i XOR B_i) */
+		xor_aes_block(x, data);
+		data += AES_BLOCK_SIZE;
+		aes_encrypt(aes, x, x);
+	}
+	if (last) {
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			x[i] ^= *data++;
+		aes_encrypt(aes, x, x);
+	}
+}
+
+
+static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a)
+{
+	/* A_i = Flags | Nonce N | Counter i */
+	a[0] = L - 1; /* Flags = L' */
+	os_memcpy(&a[1], nonce, 15 - L);
+}
+
+
+static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out,
+			 u8 *a)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	/* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
+	for (i = 1; i <= len / AES_BLOCK_SIZE; i++) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		/* S_i = E(K, A_i) */
+		aes_encrypt(aes, a, out);
+		xor_aes_block(out, in);
+		out += AES_BLOCK_SIZE;
+		in += AES_BLOCK_SIZE;
+	}
+	if (last) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		aes_encrypt(aes, a, out);
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			*out++ ^= *in++;
+	}
+}
+
+
+static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", x, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		auth[i] = x[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M);
+}
+
+
+static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		t[i] = auth[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", t, M);
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *plain, size_t plain_len,
+	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x);
+	aes_ccm_auth(aes, plain, plain_len, x);
+
+	/* Encryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_encr(aes, L, plain, plain_len, crypt, a);
+	aes_ccm_encr_auth(aes, M, x, a, auth);
+
+	aes_encrypt_deinit(aes);
+
+	return 0;
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *crypt, size_t crypt_len,
+	       const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+	u8 t[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	/* Decryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_decr_auth(aes, M, a, auth, t);
+
+	/* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
+	aes_ccm_encr(aes, L, crypt, crypt_len, plain, a);
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x);
+	aes_ccm_auth(aes, plain, crypt_len, x);
+
+	aes_encrypt_deinit(aes);
+
+	if (os_memcmp(x, t, M) != 0) {
+		wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch");
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-ctr.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-ctr.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-ctr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,61 +0,0 @@
-/*
- * AES-128 CTR
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_128_ctr_encrypt - AES-128 CTR mode encryption
- * @key: Key for encryption (16 bytes)
- * @nonce: Nonce for counter mode (16 bytes)
- * @data: Data to encrypt in-place
- * @data_len: Length of data in bytes
- * Returns: 0 on success, -1 on failure
- */
-int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
-			u8 *data, size_t data_len)
-{
-	void *ctx;
-	size_t j, len, left = data_len;
-	int i;
-	u8 *pos = data;
-	u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
-
-	ctx = aes_encrypt_init(key, 16);
-	if (ctx == NULL)
-		return -1;
-	os_memcpy(counter, nonce, AES_BLOCK_SIZE);
-
-	while (left > 0) {
-		aes_encrypt(ctx, counter, buf);
-
-		len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
-		for (j = 0; j < len; j++)
-			pos[j] ^= buf[j];
-		pos += len;
-		left -= len;
-
-		for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
-			counter[i]++;
-			if (counter[i])
-				break;
-		}
-	}
-	aes_encrypt_deinit(ctx);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/aes-ctr.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-ctr.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-ctr.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-ctr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,55 @@
+/*
+ * AES-128 CTR
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+			u8 *data, size_t data_len)
+{
+	void *ctx;
+	size_t j, len, left = data_len;
+	int i;
+	u8 *pos = data;
+	u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(counter, nonce, AES_BLOCK_SIZE);
+
+	while (left > 0) {
+		aes_encrypt(ctx, counter, buf);
+
+		len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
+		for (j = 0; j < len; j++)
+			pos[j] ^= buf[j];
+		pos += len;
+		left -= len;
+
+		for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+			counter[i]++;
+			if (counter[i])
+				break;
+		}
+	}
+	aes_encrypt_deinit(ctx);
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-eax.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-eax.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-eax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,151 +0,0 @@
-/*
- * AES-128 EAX
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_128_eax_encrypt - AES-128 EAX mode encryption
- * @key: Key for encryption (16 bytes)
- * @nonce: Nonce for counter mode
- * @nonce_len: Nonce length in bytes
- * @hdr: Header data to be authenticity protected
- * @hdr_len: Length of the header data bytes
- * @data: Data to encrypt in-place
- * @data_len: Length of data in bytes
- * @tag: 16-byte tag value
- * Returns: 0 on success, -1 on failure
- */
-int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
-			const u8 *hdr, size_t hdr_len,
-			u8 *data, size_t data_len, u8 *tag)
-{
-	u8 *buf;
-	size_t buf_len;
-	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
-		data_mac[AES_BLOCK_SIZE];
-	int i, ret = -1;
-
-	if (nonce_len > data_len)
-		buf_len = nonce_len;
-	else
-		buf_len = data_len;
-	if (hdr_len > buf_len)
-		buf_len = hdr_len;
-	buf_len += 16;
-
-	buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return -1;
-
-	os_memset(buf, 0, 15);
-
-	buf[15] = 0;
-	os_memcpy(buf + 16, nonce, nonce_len);
-	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac))
-		goto fail;
-
-	buf[15] = 1;
-	os_memcpy(buf + 16, hdr, hdr_len);
-	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac))
-		goto fail;
-
-	if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len))
-		goto fail;
-	buf[15] = 2;
-	os_memcpy(buf + 16, data, data_len);
-	if (omac1_aes_128(key, buf, 16 + data_len, data_mac))
-		goto fail;
-
-	for (i = 0; i < AES_BLOCK_SIZE; i++)
-		tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
-
-	ret = 0;
-fail:
-	os_free(buf);
-
-	return ret;
-}
-
-
-/**
- * aes_128_eax_decrypt - AES-128 EAX mode decryption
- * @key: Key for decryption (16 bytes)
- * @nonce: Nonce for counter mode
- * @nonce_len: Nonce length in bytes
- * @hdr: Header data to be authenticity protected
- * @hdr_len: Length of the header data bytes
- * @data: Data to encrypt in-place
- * @data_len: Length of data in bytes
- * @tag: 16-byte tag value
- * Returns: 0 on success, -1 on failure, -2 if tag does not match
- */
-int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
-			const u8 *hdr, size_t hdr_len,
-			u8 *data, size_t data_len, const u8 *tag)
-{
-	u8 *buf;
-	size_t buf_len;
-	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
-		data_mac[AES_BLOCK_SIZE];
-	int i;
-
-	if (nonce_len > data_len)
-		buf_len = nonce_len;
-	else
-		buf_len = data_len;
-	if (hdr_len > buf_len)
-		buf_len = hdr_len;
-	buf_len += 16;
-
-	buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return -1;
-
-	os_memset(buf, 0, 15);
-
-	buf[15] = 0;
-	os_memcpy(buf + 16, nonce, nonce_len);
-	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) {
-		os_free(buf);
-		return -1;
-	}
-
-	buf[15] = 1;
-	os_memcpy(buf + 16, hdr, hdr_len);
-	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) {
-		os_free(buf);
-		return -1;
-	}
-
-	buf[15] = 2;
-	os_memcpy(buf + 16, data, data_len);
-	if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) {
-		os_free(buf);
-		return -1;
-	}
-
-	os_free(buf);
-
-	for (i = 0; i < AES_BLOCK_SIZE; i++) {
-		if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
-			return -2;
-	}
-
-	return aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
-}

Copied: vendor/wpa/2.0/src/crypto/aes-eax.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-eax.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-eax.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-eax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,145 @@
+/*
+ * AES-128 EAX
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_eax_encrypt - AES-128 EAX mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
+			const u8 *hdr, size_t hdr_len,
+			u8 *data, size_t data_len, u8 *tag)
+{
+	u8 *buf;
+	size_t buf_len;
+	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
+		data_mac[AES_BLOCK_SIZE];
+	int i, ret = -1;
+
+	if (nonce_len > data_len)
+		buf_len = nonce_len;
+	else
+		buf_len = data_len;
+	if (hdr_len > buf_len)
+		buf_len = hdr_len;
+	buf_len += 16;
+
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	os_memset(buf, 0, 15);
+
+	buf[15] = 0;
+	os_memcpy(buf + 16, nonce, nonce_len);
+	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac))
+		goto fail;
+
+	buf[15] = 1;
+	os_memcpy(buf + 16, hdr, hdr_len);
+	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac))
+		goto fail;
+
+	if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len))
+		goto fail;
+	buf[15] = 2;
+	os_memcpy(buf + 16, data, data_len);
+	if (omac1_aes_128(key, buf, 16 + data_len, data_mac))
+		goto fail;
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
+
+	ret = 0;
+fail:
+	os_free(buf);
+
+	return ret;
+}
+
+
+/**
+ * aes_128_eax_decrypt - AES-128 EAX mode decryption
+ * @key: Key for decryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure, -2 if tag does not match
+ */
+int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
+			const u8 *hdr, size_t hdr_len,
+			u8 *data, size_t data_len, const u8 *tag)
+{
+	u8 *buf;
+	size_t buf_len;
+	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
+		data_mac[AES_BLOCK_SIZE];
+	int i;
+
+	if (nonce_len > data_len)
+		buf_len = nonce_len;
+	else
+		buf_len = data_len;
+	if (hdr_len > buf_len)
+		buf_len = hdr_len;
+	buf_len += 16;
+
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	os_memset(buf, 0, 15);
+
+	buf[15] = 0;
+	os_memcpy(buf + 16, nonce, nonce_len);
+	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	buf[15] = 1;
+	os_memcpy(buf + 16, hdr, hdr_len);
+	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	buf[15] = 2;
+	os_memcpy(buf + 16, data, data_len);
+	if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++) {
+		if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
+			return -2;
+	}
+
+	return aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-encblock.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-encblock.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-encblock.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,38 +0,0 @@
-/*
- * AES encrypt_block
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_128_encrypt_block - Perform one AES 128-bit block operation
- * @key: Key for AES
- * @in: Input data (16 bytes)
- * @out: Output of the AES block operation (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
-{
-	void *ctx;
-	ctx = aes_encrypt_init(key, 16);
-	if (ctx == NULL)
-		return -1;
-	aes_encrypt(ctx, in, out);
-	aes_encrypt_deinit(ctx);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/aes-encblock.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-encblock.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-encblock.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-encblock.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,32 @@
+/*
+ * AES encrypt_block
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_encrypt_block - Perform one AES 128-bit block operation
+ * @key: Key for AES
+ * @in: Input data (16 bytes)
+ * @out: Output of the AES block operation (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+{
+	void *ctx;
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	aes_encrypt(ctx, in, out);
+	aes_encrypt_deinit(ctx);
+	return 0;
+}

Copied: vendor/wpa/2.0/src/crypto/aes-gcm.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-gcm.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-gcm.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-gcm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,327 @@
+/*
+ * Galois/Counter Mode (GCM) and GMAC with AES
+ *
+ * Copyright (c) 2012, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+static void inc32(u8 *block)
+{
+	u32 val;
+	val = WPA_GET_BE32(block + AES_BLOCK_SIZE - 4);
+	val++;
+	WPA_PUT_BE32(block + AES_BLOCK_SIZE - 4, val);
+}
+
+
+static void xor_block(u8 *dst, const u8 *src)
+{
+	u32 *d = (u32 *) dst;
+	u32 *s = (u32 *) src;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+}
+
+
+static void shift_right_block(u8 *v)
+{
+	u32 val;
+
+	val = WPA_GET_BE32(v + 12);
+	val >>= 1;
+	if (v[11] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 12, val);
+
+	val = WPA_GET_BE32(v + 8);
+	val >>= 1;
+	if (v[7] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 8, val);
+
+	val = WPA_GET_BE32(v + 4);
+	val >>= 1;
+	if (v[3] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 4, val);
+
+	val = WPA_GET_BE32(v);
+	val >>= 1;
+	WPA_PUT_BE32(v, val);
+}
+
+
+/* Multiplication in GF(2^128) */
+static void gf_mult(const u8 *x, const u8 *y, u8 *z)
+{
+	u8 v[16];
+	int i, j;
+
+	os_memset(z, 0, 16); /* Z_0 = 0^128 */
+	os_memcpy(v, y, 16); /* V_0 = Y */
+
+	for (i = 0; i < 16; i++) {
+		for (j = 0; j < 8; j++) {
+			if (x[i] & BIT(7 - j)) {
+				/* Z_(i + 1) = Z_i XOR V_i */
+				xor_block(z, v);
+			} else {
+				/* Z_(i + 1) = Z_i */
+			}
+
+			if (v[15] & 0x01) {
+				/* V_(i + 1) = (V_i >> 1) XOR R */
+				shift_right_block(v);
+				/* R = 11100001 || 0^120 */
+				v[0] ^= 0xe1;
+			} else {
+				/* V_(i + 1) = V_i >> 1 */
+				shift_right_block(v);
+			}
+		}
+	}
+}
+
+
+static void ghash_start(u8 *y)
+{
+	/* Y_0 = 0^128 */
+	os_memset(y, 0, 16);
+}
+
+
+static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
+{
+	size_t m, i;
+	const u8 *xpos = x;
+	u8 tmp[16];
+
+	m = xlen / 16;
+
+	for (i = 0; i < m; i++) {
+		/* Y_i = (Y^(i-1) XOR X_i) dot H */
+		xor_block(y, xpos);
+		xpos += 16;
+
+		/* dot operation:
+		 * multiplication operation for binary Galois (finite) field of
+		 * 2^128 elements */
+		gf_mult(y, h, tmp);
+		os_memcpy(y, tmp, 16);
+	}
+
+	if (x + xlen > xpos) {
+		/* Add zero padded last block */
+		size_t last = x + xlen - xpos;
+		os_memcpy(tmp, xpos, last);
+		os_memset(tmp + last, 0, sizeof(tmp) - last);
+
+		/* Y_i = (Y^(i-1) XOR X_i) dot H */
+		xor_block(y, tmp);
+
+		/* dot operation:
+		 * multiplication operation for binary Galois (finite) field of
+		 * 2^128 elements */
+		gf_mult(y, h, tmp);
+		os_memcpy(y, tmp, 16);
+	}
+
+	/* Return Y_m */
+}
+
+
+static void aes_gctr(void *aes, const u8 *icb, const u8 *x, size_t xlen, u8 *y)
+{
+	size_t i, n, last;
+	u8 cb[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
+	const u8 *xpos = x;
+	u8 *ypos = y;
+
+	if (xlen == 0)
+		return;
+
+	n = xlen / 16;
+
+	os_memcpy(cb, icb, AES_BLOCK_SIZE);
+	/* Full blocks */
+	for (i = 0; i < n; i++) {
+		aes_encrypt(aes, cb, ypos);
+		xor_block(ypos, xpos);
+		xpos += AES_BLOCK_SIZE;
+		ypos += AES_BLOCK_SIZE;
+		inc32(cb);
+	}
+
+	last = x + xlen - xpos;
+	if (last) {
+		/* Last, partial block */
+		aes_encrypt(aes, cb, tmp);
+		for (i = 0; i < last; i++)
+			*ypos++ = *xpos++ ^ tmp[i];
+	}
+}
+
+
+static void * aes_gcm_init_hash_subkey(const u8 *key, size_t key_len, u8 *H)
+{
+	void *aes;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return NULL;
+
+	/* Generate hash subkey H = AES_K(0^128) */
+	os_memset(H, 0, AES_BLOCK_SIZE);
+	aes_encrypt(aes, H, H);
+	wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH",
+			H, AES_BLOCK_SIZE);
+	return aes;
+}
+
+
+static void aes_gcm_prepare_j0(const u8 *iv, size_t iv_len, const u8 *H, u8 *J0)
+{
+	u8 len_buf[16];
+
+	if (iv_len == 12) {
+		/* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
+		os_memcpy(J0, iv, iv_len);
+		os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
+		J0[AES_BLOCK_SIZE - 1] = 0x01;
+	} else {
+		/*
+		 * s = 128 * ceil(len(IV)/128) - len(IV)
+		 * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
+		 */
+		ghash_start(J0);
+		ghash(H, iv, iv_len, J0);
+		WPA_PUT_BE64(len_buf, 0);
+		WPA_PUT_BE64(len_buf + 8, iv_len * 8);
+		ghash(H, len_buf, sizeof(len_buf), J0);
+	}
+}
+
+
+static void aes_gcm_gctr(void *aes, const u8 *J0, const u8 *in, size_t len,
+			 u8 *out)
+{
+	u8 J0inc[AES_BLOCK_SIZE];
+
+	if (len == 0)
+		return;
+
+	os_memcpy(J0inc, J0, AES_BLOCK_SIZE);
+	inc32(J0inc);
+	aes_gctr(aes, J0inc, in, len, out);
+}
+
+
+static void aes_gcm_ghash(const u8 *H, const u8 *aad, size_t aad_len,
+			  const u8 *crypt, size_t crypt_len, u8 *S)
+{
+	u8 len_buf[16];
+
+	/*
+	 * u = 128 * ceil[len(C)/128] - len(C)
+	 * v = 128 * ceil[len(A)/128] - len(A)
+	 * S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
+	 * (i.e., zero padded to block size A || C and lengths of each in bits)
+	 */
+	ghash_start(S);
+	ghash(H, aad, aad_len, S);
+	ghash(H, crypt, crypt_len, S);
+	WPA_PUT_BE64(len_buf, aad_len * 8);
+	WPA_PUT_BE64(len_buf + 8, crypt_len * 8);
+	ghash(H, len_buf, sizeof(len_buf), S);
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
+}
+
+
+/**
+ * aes_gcm_ae - GCM-AE_K(IV, P, A)
+ */
+int aes_gcm_ae(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	       const u8 *plain, size_t plain_len,
+	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag)
+{
+	u8 H[AES_BLOCK_SIZE];
+	u8 J0[AES_BLOCK_SIZE];
+	u8 S[16];
+	void *aes;
+
+	aes = aes_gcm_init_hash_subkey(key, key_len, H);
+	if (aes == NULL)
+		return -1;
+
+	aes_gcm_prepare_j0(iv, iv_len, H, J0);
+
+	/* C = GCTR_K(inc_32(J_0), P) */
+	aes_gcm_gctr(aes, J0, plain, plain_len, crypt);
+
+	aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S);
+
+	/* T = MSB_t(GCTR_K(J_0, S)) */
+	aes_gctr(aes, J0, S, sizeof(S), tag);
+
+	/* Return (C, T) */
+
+	aes_encrypt_deinit(aes);
+
+	return 0;
+}
+
+
+/**
+ * aes_gcm_ad - GCM-AD_K(IV, C, A, T)
+ */
+int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	       const u8 *crypt, size_t crypt_len,
+	       const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
+{
+	u8 H[AES_BLOCK_SIZE];
+	u8 J0[AES_BLOCK_SIZE];
+	u8 S[16], T[16];
+	void *aes;
+
+	aes = aes_gcm_init_hash_subkey(key, key_len, H);
+	if (aes == NULL)
+		return -1;
+
+	aes_gcm_prepare_j0(iv, iv_len, H, J0);
+
+	/* P = GCTR_K(inc_32(J_0), C) */
+	aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);
+
+	aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);
+
+	/* T' = MSB_t(GCTR_K(J_0, S)) */
+	aes_gctr(aes, J0, S, sizeof(S), T);
+
+	aes_encrypt_deinit(aes);
+
+	if (os_memcmp(tag, T, 16) != 0) {
+		wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	     const u8 *aad, size_t aad_len, u8 *tag)
+{
+	return aes_gcm_ae(key, key_len, iv, iv_len, NULL, 0, aad, aad_len, NULL,
+			  tag);
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-internal-dec.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-internal-dec.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-internal-dec.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,151 +0,0 @@
-/*
- * AES (Rijndael) cipher - decrypt
- *
- * Modifications to public domain implementation:
- * - support only 128-bit keys
- * - cleanup
- * - use C pre-processor to make it easier to change S table access
- * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
- *   cost of reduced throughput (quite small difference on Pentium 4,
- *   10-25% when using -O1 or -O2 optimization)
- *
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "aes_i.h"
-
-/**
- * Expand the cipher key into the decryption key schedule.
- *
- * @return	the number of rounds for the given cipher key size.
- */
-void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
-{
-	int Nr = 10, i, j;
-	u32 temp;
-
-	/* expand the cipher key: */
-	rijndaelKeySetupEnc(rk, cipherKey);
-	/* invert the order of the round keys: */
-	for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
-		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
-		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
-		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
-		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
-	}
-	/* apply the inverse MixColumn transform to all round keys but the
-	 * first and the last: */
-	for (i = 1; i < Nr; i++) {
-		rk += 4;
-		for (j = 0; j < 4; j++) {
-			rk[j] = TD0_(TE4((rk[j] >> 24)       )) ^
-				TD1_(TE4((rk[j] >> 16) & 0xff)) ^
-				TD2_(TE4((rk[j] >>  8) & 0xff)) ^
-				TD3_(TE4((rk[j]      ) & 0xff));
-		}
-	}
-}
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	u32 *rk;
-	if (len != 16)
-		return NULL;
-	rk = os_malloc(AES_PRIV_SIZE);
-	if (rk == NULL)
-		return NULL;
-	rijndaelKeySetupDec(rk, key);
-	return rk;
-}
-
-static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
-{
-	u32 s0, s1, s2, s3, t0, t1, t2, t3;
-	const int Nr = 10;
-#ifndef FULL_UNROLL
-	int r;
-#endif /* ?FULL_UNROLL */
-
-	/*
-	 * map byte array block to cipher state
-	 * and add initial round key:
-	 */
-	s0 = GETU32(ct     ) ^ rk[0];
-	s1 = GETU32(ct +  4) ^ rk[1];
-	s2 = GETU32(ct +  8) ^ rk[2];
-	s3 = GETU32(ct + 12) ^ rk[3];
-
-#define ROUND(i,d,s) \
-d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
-d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
-d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
-d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
-
-#ifdef FULL_UNROLL
-
-	ROUND(1,t,s);
-	ROUND(2,s,t);
-	ROUND(3,t,s);
-	ROUND(4,s,t);
-	ROUND(5,t,s);
-	ROUND(6,s,t);
-	ROUND(7,t,s);
-	ROUND(8,s,t);
-	ROUND(9,t,s);
-
-	rk += Nr << 2;
-
-#else  /* !FULL_UNROLL */
-
-	/* Nr - 1 full rounds: */
-	r = Nr >> 1;
-	for (;;) {
-		ROUND(1,t,s);
-		rk += 8;
-		if (--r == 0)
-			break;
-		ROUND(0,s,t);
-	}
-
-#endif /* ?FULL_UNROLL */
-
-#undef ROUND
-
-	/*
-	 * apply last round and
-	 * map cipher state to byte array block:
-	 */
-	s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
-	PUTU32(pt     , s0);
-	s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
-	PUTU32(pt +  4, s1);
-	s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
-	PUTU32(pt +  8, s2);
-	s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
-	PUTU32(pt + 12, s3);
-}
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	rijndaelDecrypt(ctx, crypt, plain);
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	os_memset(ctx, 0, AES_PRIV_SIZE);
-	os_free(ctx);
-}

Copied: vendor/wpa/2.0/src/crypto/aes-internal-dec.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-internal-dec.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-internal-dec.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-internal-dec.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,161 @@
+/*
+ * AES (Rijndael) cipher - decrypt
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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.h"
+#include "aes_i.h"
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits)
+{
+	int Nr, i, j;
+	u32 temp;
+
+	/* expand the cipher key: */
+	Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+	if (Nr < 0)
+		return Nr;
+	/* invert the order of the round keys: */
+	for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+	}
+	/* apply the inverse MixColumn transform to all round keys but the
+	 * first and the last: */
+	for (i = 1; i < Nr; i++) {
+		rk += 4;
+		for (j = 0; j < 4; j++) {
+			rk[j] = TD0_(TE4((rk[j] >> 24)       )) ^
+				TD1_(TE4((rk[j] >> 16) & 0xff)) ^
+				TD2_(TE4((rk[j] >>  8) & 0xff)) ^
+				TD3_(TE4((rk[j]      ) & 0xff));
+		}
+	}
+
+	return Nr;
+}
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	u32 *rk;
+	int res;
+	rk = os_malloc(AES_PRIV_SIZE);
+	if (rk == NULL)
+		return NULL;
+	res = rijndaelKeySetupDec(rk, key, len * 8);
+	if (res < 0) {
+		os_free(rk);
+		return NULL;
+	}
+	rk[AES_PRIV_NR_POS] = res;
+	return rk;
+}
+
+static void rijndaelDecrypt(const u32 rk[/*44*/], int Nr, const u8 ct[16],
+			    u8 pt[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(ct     ) ^ rk[0];
+	s1 = GETU32(ct +  4) ^ rk[1];
+	s2 = GETU32(ct +  8) ^ rk[2];
+	s3 = GETU32(ct + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
+d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
+d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
+d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+	if (Nr > 10) {
+		ROUND(10,s,t);
+		ROUND(11,t,s);
+		if (Nr > 12) {
+			ROUND(12,s,t);
+			ROUND(13,t,s);
+		}
+	}
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
+	PUTU32(pt     , s0);
+	s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
+	PUTU32(pt +  4, s1);
+	s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
+	PUTU32(pt +  8, s2);
+	s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
+	PUTU32(pt + 12, s3);
+}
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	u32 *rk = ctx;
+	rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	os_memset(ctx, 0, AES_PRIV_SIZE);
+	os_free(ctx);
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-internal-enc.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-internal-enc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-internal-enc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,121 +0,0 @@
-/*
- * AES (Rijndael) cipher - encrypt
- *
- * Modifications to public domain implementation:
- * - support only 128-bit keys
- * - cleanup
- * - use C pre-processor to make it easier to change S table access
- * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
- *   cost of reduced throughput (quite small difference on Pentium 4,
- *   10-25% when using -O1 or -O2 optimization)
- *
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "aes_i.h"
-
-void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
-{
-	u32 s0, s1, s2, s3, t0, t1, t2, t3;
-	const int Nr = 10;
-#ifndef FULL_UNROLL
-	int r;
-#endif /* ?FULL_UNROLL */
-
-	/*
-	 * map byte array block to cipher state
-	 * and add initial round key:
-	 */
-	s0 = GETU32(pt     ) ^ rk[0];
-	s1 = GETU32(pt +  4) ^ rk[1];
-	s2 = GETU32(pt +  8) ^ rk[2];
-	s3 = GETU32(pt + 12) ^ rk[3];
-
-#define ROUND(i,d,s) \
-d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
-d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
-d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
-d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
-
-#ifdef FULL_UNROLL
-
-	ROUND(1,t,s);
-	ROUND(2,s,t);
-	ROUND(3,t,s);
-	ROUND(4,s,t);
-	ROUND(5,t,s);
-	ROUND(6,s,t);
-	ROUND(7,t,s);
-	ROUND(8,s,t);
-	ROUND(9,t,s);
-
-	rk += Nr << 2;
-
-#else  /* !FULL_UNROLL */
-
-	/* Nr - 1 full rounds: */
-	r = Nr >> 1;
-	for (;;) {
-		ROUND(1,t,s);
-		rk += 8;
-		if (--r == 0)
-			break;
-		ROUND(0,s,t);
-	}
-
-#endif /* ?FULL_UNROLL */
-
-#undef ROUND
-
-	/*
-	 * apply last round and
-	 * map cipher state to byte array block:
-	 */
-	s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
-	PUTU32(ct     , s0);
-	s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
-	PUTU32(ct +  4, s1);
-	s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
-	PUTU32(ct +  8, s2);
-	s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
-	PUTU32(ct + 12, s3);
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	u32 *rk;
-	if (len != 16)
-		return NULL;
-	rk = os_malloc(AES_PRIV_SIZE);
-	if (rk == NULL)
-		return NULL;
-	rijndaelKeySetupEnc(rk, key);
-	return rk;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	rijndaelEncrypt(ctx, plain, crypt);
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	os_memset(ctx, 0, AES_PRIV_SIZE);
-	os_free(ctx);
-}

Copied: vendor/wpa/2.0/src/crypto/aes-internal-enc.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-internal-enc.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-internal-enc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-internal-enc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,126 @@
+/*
+ * AES (Rijndael) cipher - encrypt
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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.h"
+#include "aes_i.h"
+
+static void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(pt     ) ^ rk[0];
+	s1 = GETU32(pt +  4) ^ rk[1];
+	s2 = GETU32(pt +  8) ^ rk[2];
+	s3 = GETU32(pt + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+	if (Nr > 10) {
+		ROUND(10,s,t);
+		ROUND(11,t,s);
+		if (Nr > 12) {
+			ROUND(12,s,t);
+			ROUND(13,t,s);
+		}
+	}
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
+	PUTU32(ct     , s0);
+	s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
+	PUTU32(ct +  4, s1);
+	s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
+	PUTU32(ct +  8, s2);
+	s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
+	PUTU32(ct + 12, s3);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	u32 *rk;
+	int res;
+	rk = os_malloc(AES_PRIV_SIZE);
+	if (rk == NULL)
+		return NULL;
+	res = rijndaelKeySetupEnc(rk, key, len * 8);
+	if (res < 0) {
+		os_free(rk);
+		return NULL;
+	}
+	rk[AES_PRIV_NR_POS] = res;
+	return rk;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	u32 *rk = ctx;
+	rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	os_memset(ctx, 0, AES_PRIV_SIZE);
+	os_free(ctx);
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,805 +0,0 @@
-/*
- * AES (Rijndael) cipher
- *
- * Modifications to public domain implementation:
- * - support only 128-bit keys
- * - cleanup
- * - use C pre-processor to make it easier to change S table access
- * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
- *   cost of reduced throughput (quite small difference on Pentium 4,
- *   10-25% when using -O1 or -O2 optimization)
- *
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "aes_i.h"
-
-/*
- * rijndael-alg-fst.c
- *
- * @version 3.0 (December 2000)
- *
- * Optimised ANSI C code for the Rijndael cipher (now AES)
- *
- * @author Vincent Rijmen <vincent.rijmen at esat.kuleuven.ac.be>
- * @author Antoon Bosselaers <antoon.bosselaers at esat.kuleuven.ac.be>
- * @author Paulo Barreto <paulo.barreto at terra.com.br>
- *
- * This code is hereby placed in the public domain.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/*
-Te0[x] = S [x].[02, 01, 01, 03];
-Te1[x] = S [x].[03, 02, 01, 01];
-Te2[x] = S [x].[01, 03, 02, 01];
-Te3[x] = S [x].[01, 01, 03, 02];
-Te4[x] = S [x].[01, 01, 01, 01];
-
-Td0[x] = Si[x].[0e, 09, 0d, 0b];
-Td1[x] = Si[x].[0b, 0e, 09, 0d];
-Td2[x] = Si[x].[0d, 0b, 0e, 09];
-Td3[x] = Si[x].[09, 0d, 0b, 0e];
-Td4[x] = Si[x].[01, 01, 01, 01];
-*/
-
-const u32 Te0[256] = {
-    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
-    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
-    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
-    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
-    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
-    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
-    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
-    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
-    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
-    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
-    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
-    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
-    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
-    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
-    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
-    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
-    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
-    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
-    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
-    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
-    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
-    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
-    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
-    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
-    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
-    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
-    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
-    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
-    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
-    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
-    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
-    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
-    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
-    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
-    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
-    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
-    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
-    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
-    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
-    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
-    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
-    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
-    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
-    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
-    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
-    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
-    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
-    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
-    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
-    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
-    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
-    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
-    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
-    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
-    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
-    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
-    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
-    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
-    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
-    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
-    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
-    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
-    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
-    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
-};
-#ifndef AES_SMALL_TABLES
-const u32 Te1[256] = {
-    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
-    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
-    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
-    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
-    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
-    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
-    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
-    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
-    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
-    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
-    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
-    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
-    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
-    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
-    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
-    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
-    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
-    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
-    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
-    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
-    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
-    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
-    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
-    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
-    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
-    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
-    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
-    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
-    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
-    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
-    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
-    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
-    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
-    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
-    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
-    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
-    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
-    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
-    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
-    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
-    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
-    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
-    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
-    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
-    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
-    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
-    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
-    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
-    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
-    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
-    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
-    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
-    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
-    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
-    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
-    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
-    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
-    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
-    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
-    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
-    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
-    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
-    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
-    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
-};
-const u32 Te2[256] = {
-    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
-    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
-    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
-    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
-    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
-    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
-    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
-    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
-    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
-    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
-    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
-    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
-    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
-    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
-    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
-    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
-    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
-    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
-    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
-    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
-    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
-    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
-    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
-    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
-    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
-    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
-    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
-    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
-    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
-    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
-    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
-    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
-    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
-    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
-    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
-    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
-    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
-    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
-    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
-    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
-    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
-    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
-    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
-    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
-    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
-    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
-    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
-    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
-    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
-    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
-    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
-    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
-    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
-    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
-    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
-    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
-    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
-    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
-    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
-    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
-    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
-    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
-    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
-    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
-};
-const u32 Te3[256] = {
-
-    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
-    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
-    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
-    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
-    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
-    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
-    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
-    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
-    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
-    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
-    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
-    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
-    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
-    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
-    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
-    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
-    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
-    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
-    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
-    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
-    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
-    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
-    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
-    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
-    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
-    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
-    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
-    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
-    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
-    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
-    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
-    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
-    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
-    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
-    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
-    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
-    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
-    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
-    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
-    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
-    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
-    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
-    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
-    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
-    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
-    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
-    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
-    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
-    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
-    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
-    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
-    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
-    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
-    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
-    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
-    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
-    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
-    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
-    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
-    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
-    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
-    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
-    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
-    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
-};
-const u32 Te4[256] = {
-    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
-    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
-    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
-    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
-    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
-    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
-    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
-    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
-    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
-    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
-    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
-    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
-    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
-    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
-    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
-    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
-    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
-    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
-    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
-    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
-    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
-    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
-    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
-    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
-    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
-    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
-    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
-    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
-    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
-    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
-    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
-    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
-    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
-    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
-    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
-    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
-    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
-    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
-    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
-    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
-    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
-    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
-    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
-    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
-    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
-    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
-    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
-    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
-    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
-    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
-    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
-    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
-    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
-    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
-    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
-    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
-    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
-    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
-    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
-    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
-    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
-    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
-    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
-    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
-};
-#endif /* AES_SMALL_TABLES */
-const u32 Td0[256] = {
-    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
-    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
-    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
-    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
-    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
-    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
-    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
-    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
-    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
-    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
-    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
-    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
-    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
-    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
-    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
-    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
-    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
-    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
-    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
-    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
-    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
-    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
-    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
-    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
-    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
-    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
-    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
-    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
-    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
-    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
-    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
-    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
-    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
-    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
-    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
-    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
-    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
-    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
-    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
-    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
-    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
-    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
-    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
-    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
-    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
-    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
-    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
-    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
-    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
-    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
-    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
-    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
-    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
-    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
-    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
-    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
-    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
-    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
-    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
-    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
-    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
-    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
-    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
-    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
-};
-#ifndef AES_SMALL_TABLES
-const u32 Td1[256] = {
-    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
-    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
-    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
-    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
-    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
-    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
-    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
-    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
-    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
-    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
-    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
-    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
-    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
-    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
-    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
-    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
-    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
-    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
-    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
-    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
-    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
-    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
-    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
-    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
-    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
-    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
-    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
-    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
-    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
-    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
-    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
-    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
-    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
-    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
-    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
-    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
-    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
-    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
-    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
-    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
-    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
-    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
-    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
-    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
-    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
-    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
-    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
-    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
-    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
-    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
-    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
-    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
-    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
-    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
-    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
-    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
-    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
-    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
-    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
-    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
-    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
-    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
-    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
-    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
-};
-const u32 Td2[256] = {
-    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
-    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
-    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
-    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
-    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
-    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
-    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
-    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
-    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
-    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
-    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
-    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
-    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
-    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
-    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
-    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
-    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
-    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
-    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
-    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
-
-    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
-    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
-    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
-    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
-    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
-    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
-    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
-    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
-    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
-    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
-    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
-    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
-    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
-    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
-    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
-    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
-    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
-    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
-    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
-    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
-    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
-    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
-    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
-    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
-    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
-    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
-    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
-    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
-    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
-    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
-    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
-    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
-    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
-    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
-    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
-    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
-    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
-    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
-    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
-    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
-    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
-    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
-    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
-    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
-};
-const u32 Td3[256] = {
-    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
-    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
-    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
-    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
-    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
-    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
-    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
-    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
-    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
-    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
-    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
-    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
-    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
-    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
-    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
-    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
-    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
-    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
-    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
-    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
-    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
-    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
-    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
-    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
-    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
-    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
-    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
-    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
-    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
-    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
-    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
-    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
-    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
-    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
-    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
-    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
-    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
-    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
-    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
-    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
-    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
-    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
-    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
-    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
-    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
-    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
-    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
-    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
-    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
-    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
-    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
-    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
-    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
-    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
-    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
-    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
-    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
-    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
-    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
-    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
-    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
-    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
-    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
-    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
-};
-const u32 Td4[256] = {
-    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
-    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
-    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
-    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
-    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
-    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
-    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
-    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
-    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
-    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
-    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
-    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
-    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
-    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
-    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
-    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
-    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
-    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
-    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
-    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
-    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
-    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
-    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
-    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
-    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
-    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
-    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
-    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
-    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
-    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
-    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
-    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
-    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
-    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
-    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
-    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
-    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
-    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
-    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
-    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
-    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
-    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
-    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
-    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
-    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
-    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
-    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
-    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
-    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
-    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
-    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
-    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
-    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
-    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
-    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
-    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
-    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
-    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
-    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
-    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
-    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
-    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
-    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
-    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
-};
-const u32 rcon[] = {
-	0x01000000, 0x02000000, 0x04000000, 0x08000000,
-	0x10000000, 0x20000000, 0x40000000, 0x80000000,
-	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
-};
-#else /* AES_SMALL_TABLES */
-const u8 Td4s[256] = {
-    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
-    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
-    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
-    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
-    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
-    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
-    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
-    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
-    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
-    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
-    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
-    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
-    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
-    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
-    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
-    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
-    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
-    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
-    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
-    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
-    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
-    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
-    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
-    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
-    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
-    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
-    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
-    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
-    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
-    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
-    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
-    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
-};
-const u8 rcons[] = {
-	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
-	/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
-};
-#endif /* AES_SMALL_TABLES */
-/**
- * Expand the cipher key into the encryption key schedule.
- *
- * @return	the number of rounds for the given cipher key size.
- */
-void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
-{
-	int i;
-	u32 temp;
-
-	rk[0] = GETU32(cipherKey     );
-	rk[1] = GETU32(cipherKey +  4);
-	rk[2] = GETU32(cipherKey +  8);
-	rk[3] = GETU32(cipherKey + 12);
-	for (i = 0; i < 10; i++) {
-		temp  = rk[3];
-		rk[4] = rk[0] ^
-			TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
-			RCON(i);
-		rk[5] = rk[1] ^ rk[4];
-		rk[6] = rk[2] ^ rk[5];
-		rk[7] = rk[3] ^ rk[6];
-		rk += 4;
-	}
-}

Copied: vendor/wpa/2.0/src/crypto/aes-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,845 @@
+/*
+ * AES (Rijndael) cipher
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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.h"
+#include "aes_i.h"
+
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen at esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers at esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto at terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+#ifndef AES_SMALL_TABLES
+const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+#endif /* AES_SMALL_TABLES */
+const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+#ifndef AES_SMALL_TABLES
+const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#else /* AES_SMALL_TABLES */
+const u8 Td4s[256] = {
+    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+const u8 rcons[] = {
+	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+	/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#endif /* AES_SMALL_TABLES */
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits)
+{
+	int i;
+	u32 temp;
+
+	rk[0] = GETU32(cipherKey     );
+	rk[1] = GETU32(cipherKey +  4);
+	rk[2] = GETU32(cipherKey +  8);
+	rk[3] = GETU32(cipherKey + 12);
+
+	if (keyBits == 128) {
+		for (i = 0; i < 10; i++) {
+			temp  = rk[3];
+			rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[5] = rk[1] ^ rk[4];
+			rk[6] = rk[2] ^ rk[5];
+			rk[7] = rk[3] ^ rk[6];
+			rk += 4;
+		}
+		return 10;
+	}
+
+	rk[4] = GETU32(cipherKey + 16);
+	rk[5] = GETU32(cipherKey + 20);
+
+	if (keyBits == 192) {
+		for (i = 0; i < 8; i++) {
+			temp  = rk[5];
+			rk[6] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[7] = rk[1] ^ rk[6];
+			rk[8] = rk[2] ^ rk[7];
+			rk[9] = rk[3] ^ rk[8];
+			if (i == 7)
+				return 12;
+			rk[10] = rk[4] ^ rk[9];
+			rk[11] = rk[5] ^ rk[10];
+			rk += 6;
+		}
+	}
+
+	rk[6] = GETU32(cipherKey + 24);
+	rk[7] = GETU32(cipherKey + 28);
+
+	if (keyBits == 256) {
+		for (i = 0; i < 7; i++) {
+			temp  = rk[7];
+			rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[9] = rk[1] ^ rk[8];
+			rk[10] = rk[2] ^ rk[9];
+			rk[11] = rk[3] ^ rk[10];
+			if (i == 6)
+				return 14;
+			temp  = rk[11];
+			rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^
+				TE433(temp) ^ TE444(temp);
+			rk[13] = rk[5] ^ rk[12];
+			rk[14] = rk[6] ^ rk[13];
+			rk[15] = rk[7] ^ rk[14];
+			rk += 8;
+		}
+	}
+
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-omac1.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-omac1.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-omac1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,124 +0,0 @@
-/*
- * One-key CBC MAC (OMAC1) hash with AES-128
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-static void gf_mulx(u8 *pad)
-{
-	int i, carry;
-
-	carry = pad[0] & 0x80;
-	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
-		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
-	pad[AES_BLOCK_SIZE - 1] <<= 1;
-	if (carry)
-		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
-}
-
-
-/**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
- * @num_elem: Number of elements in the data vector
- * @addr: Pointers to the data areas
- * @len: Lengths of the data blocks
- * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
- * Returns: 0 on success, -1 on failure
- *
- * This is a mode for using block cipher (AES in this case) for authentication.
- * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
- * (SP) 800-38B.
- */
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
-			 const u8 *addr[], const size_t *len, u8 *mac)
-{
-	void *ctx;
-	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
-	const u8 *pos, *end;
-	size_t i, e, left, total_len;
-
-	ctx = aes_encrypt_init(key, 16);
-	if (ctx == NULL)
-		return -1;
-	os_memset(cbc, 0, AES_BLOCK_SIZE);
-
-	total_len = 0;
-	for (e = 0; e < num_elem; e++)
-		total_len += len[e];
-	left = total_len;
-
-	e = 0;
-	pos = addr[0];
-	end = pos + len[0];
-
-	while (left >= AES_BLOCK_SIZE) {
-		for (i = 0; i < AES_BLOCK_SIZE; i++) {
-			cbc[i] ^= *pos++;
-			if (pos >= end) {
-				e++;
-				pos = addr[e];
-				end = pos + len[e];
-			}
-		}
-		if (left > AES_BLOCK_SIZE)
-			aes_encrypt(ctx, cbc, cbc);
-		left -= AES_BLOCK_SIZE;
-	}
-
-	os_memset(pad, 0, AES_BLOCK_SIZE);
-	aes_encrypt(ctx, pad, pad);
-	gf_mulx(pad);
-
-	if (left || total_len == 0) {
-		for (i = 0; i < left; i++) {
-			cbc[i] ^= *pos++;
-			if (pos >= end) {
-				e++;
-				pos = addr[e];
-				end = pos + len[e];
-			}
-		}
-		cbc[left] ^= 0x80;
-		gf_mulx(pad);
-	}
-
-	for (i = 0; i < AES_BLOCK_SIZE; i++)
-		pad[i] ^= cbc[i];
-	aes_encrypt(ctx, pad, mac);
-	aes_encrypt_deinit(ctx);
-	return 0;
-}
-
-
-/**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
- * @key: 128-bit key for the hash operation
- * @data: Data buffer for which a MAC is determined
- * @data_len: Length of data buffer in bytes
- * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
- * Returns: 0 on success, -1 on failure
- *
- * This is a mode for using block cipher (AES in this case) for authentication.
- * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
- * (SP) 800-38B.
- */
-int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
-{
-	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
-}

Copied: vendor/wpa/2.0/src/crypto/aes-omac1.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-omac1.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-omac1.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-omac1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,118 @@
+/*
+ * One-key CBC MAC (OMAC1) hash with AES-128
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+static void gf_mulx(u8 *pad)
+{
+	int i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
+	const u8 *pos, *end;
+	size_t i, e, left, total_len;
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memset(cbc, 0, AES_BLOCK_SIZE);
+
+	total_len = 0;
+	for (e = 0; e < num_elem; e++)
+		total_len += len[e];
+	left = total_len;
+
+	e = 0;
+	pos = addr[0];
+	end = pos + len[0];
+
+	while (left >= AES_BLOCK_SIZE) {
+		for (i = 0; i < AES_BLOCK_SIZE; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		if (left > AES_BLOCK_SIZE)
+			aes_encrypt(ctx, cbc, cbc);
+		left -= AES_BLOCK_SIZE;
+	}
+
+	os_memset(pad, 0, AES_BLOCK_SIZE);
+	aes_encrypt(ctx, pad, pad);
+	gf_mulx(pad);
+
+	if (left || total_len == 0) {
+		for (i = 0; i < left; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		cbc[left] ^= 0x80;
+		gf_mulx(pad);
+	}
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		pad[i] ^= cbc[i];
+	aes_encrypt(ctx, pad, mac);
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-unwrap.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-unwrap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-unwrap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,79 +0,0 @@
-/*
- * AES key unwrap (128-bit KEK, RFC3394)
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: Key encryption key (KEK)
- * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
- * bytes
- * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
- * @plain: Plaintext key, n * 64 bits
- * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
- */
-int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
-{
-	u8 a[8], *r, b[16];
-	int i, j;
-	void *ctx;
-
-	/* 1) Initialize variables. */
-	os_memcpy(a, cipher, 8);
-	r = plain;
-	os_memcpy(r, cipher + 8, 8 * n);
-
-	ctx = aes_decrypt_init(kek, 16);
-	if (ctx == NULL)
-		return -1;
-
-	/* 2) Compute intermediate values.
-	 * For j = 5 to 0
-	 *     For i = n to 1
-	 *         B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
-	 *         A = MSB(64, B)
-	 *         R[i] = LSB(64, B)
-	 */
-	for (j = 5; j >= 0; j--) {
-		r = plain + (n - 1) * 8;
-		for (i = n; i >= 1; i--) {
-			os_memcpy(b, a, 8);
-			b[7] ^= n * j + i;
-
-			os_memcpy(b + 8, r, 8);
-			aes_decrypt(ctx, b, b);
-			os_memcpy(a, b, 8);
-			os_memcpy(r, b + 8, 8);
-			r -= 8;
-		}
-	}
-	aes_decrypt_deinit(ctx);
-
-	/* 3) Output results.
-	 *
-	 * These are already in @plain due to the location of temporary
-	 * variables. Just verify that the IV matches with the expected value.
-	 */
-	for (i = 0; i < 8; i++) {
-		if (a[i] != 0xa6)
-			return -1;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/aes-unwrap.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-unwrap.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-unwrap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-unwrap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,73 @@
+/*
+ * AES key unwrap (128-bit KEK, RFC3394)
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
+ * @plain: Plaintext key, n * 64 bits
+ * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
+ */
+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
+{
+	u8 a[8], *r, b[16];
+	int i, j;
+	void *ctx;
+
+	/* 1) Initialize variables. */
+	os_memcpy(a, cipher, 8);
+	r = plain;
+	os_memcpy(r, cipher + 8, 8 * n);
+
+	ctx = aes_decrypt_init(kek, 16);
+	if (ctx == NULL)
+		return -1;
+
+	/* 2) Compute intermediate values.
+	 * For j = 5 to 0
+	 *     For i = n to 1
+	 *         B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+	 *         A = MSB(64, B)
+	 *         R[i] = LSB(64, B)
+	 */
+	for (j = 5; j >= 0; j--) {
+		r = plain + (n - 1) * 8;
+		for (i = n; i >= 1; i--) {
+			os_memcpy(b, a, 8);
+			b[7] ^= n * j + i;
+
+			os_memcpy(b + 8, r, 8);
+			aes_decrypt(ctx, b, b);
+			os_memcpy(a, b, 8);
+			os_memcpy(r, b + 8, 8);
+			r -= 8;
+		}
+	}
+	aes_decrypt_deinit(ctx);
+
+	/* 3) Output results.
+	 *
+	 * These are already in @plain due to the location of temporary
+	 * variables. Just verify that the IV matches with the expected value.
+	 */
+	for (i = 0; i < 8; i++) {
+		if (a[i] != 0xa6)
+			return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/aes-wrap.c
===================================================================
--- vendor/wpa/dist/src/crypto/aes-wrap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes-wrap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,76 +0,0 @@
-/*
- * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "aes.h"
-#include "aes_wrap.h"
-
-/**
- * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: 16-octet Key encryption key (KEK)
- * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
- * bytes
- * @plain: Plaintext key to be wrapped, n * 64 bits
- * @cipher: Wrapped key, (n + 1) * 64 bits
- * Returns: 0 on success, -1 on failure
- */
-int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
-{
-	u8 *a, *r, b[16];
-	int i, j;
-	void *ctx;
-
-	a = cipher;
-	r = cipher + 8;
-
-	/* 1) Initialize variables. */
-	os_memset(a, 0xa6, 8);
-	os_memcpy(r, plain, 8 * n);
-
-	ctx = aes_encrypt_init(kek, 16);
-	if (ctx == NULL)
-		return -1;
-
-	/* 2) Calculate intermediate values.
-	 * For j = 0 to 5
-	 *     For i=1 to n
-	 *         B = AES(K, A | R[i])
-	 *         A = MSB(64, B) ^ t where t = (n*j)+i
-	 *         R[i] = LSB(64, B)
-	 */
-	for (j = 0; j <= 5; j++) {
-		r = cipher + 8;
-		for (i = 1; i <= n; i++) {
-			os_memcpy(b, a, 8);
-			os_memcpy(b + 8, r, 8);
-			aes_encrypt(ctx, b, b);
-			os_memcpy(a, b, 8);
-			a[7] ^= n * j + i;
-			os_memcpy(r, b + 8, 8);
-			r += 8;
-		}
-	}
-	aes_encrypt_deinit(ctx);
-
-	/* 3) Output the results.
-	 *
-	 * These are already in @cipher due to the location of temporary
-	 * variables.
-	 */
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/aes-wrap.c (from rev 9639, vendor/wpa/dist/src/crypto/aes-wrap.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes-wrap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes-wrap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,70 @@
+/*
+ * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: 16-octet Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @plain: Plaintext key to be wrapped, n * 64 bits
+ * @cipher: Wrapped key, (n + 1) * 64 bits
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
+{
+	u8 *a, *r, b[16];
+	int i, j;
+	void *ctx;
+
+	a = cipher;
+	r = cipher + 8;
+
+	/* 1) Initialize variables. */
+	os_memset(a, 0xa6, 8);
+	os_memcpy(r, plain, 8 * n);
+
+	ctx = aes_encrypt_init(kek, 16);
+	if (ctx == NULL)
+		return -1;
+
+	/* 2) Calculate intermediate values.
+	 * For j = 0 to 5
+	 *     For i=1 to n
+	 *         B = AES(K, A | R[i])
+	 *         A = MSB(64, B) ^ t where t = (n*j)+i
+	 *         R[i] = LSB(64, B)
+	 */
+	for (j = 0; j <= 5; j++) {
+		r = cipher + 8;
+		for (i = 1; i <= n; i++) {
+			os_memcpy(b, a, 8);
+			os_memcpy(b + 8, r, 8);
+			aes_encrypt(ctx, b, b);
+			os_memcpy(a, b, 8);
+			a[7] ^= n * j + i;
+			os_memcpy(r, b + 8, 8);
+			r += 8;
+		}
+	}
+	aes_encrypt_deinit(ctx);
+
+	/* 3) Output the results.
+	 *
+	 * These are already in @cipher due to the location of temporary
+	 * variables.
+	 */
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/aes.h
===================================================================
--- vendor/wpa/dist/src/crypto/aes.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,27 +0,0 @@
-/*
- * AES functions
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AES_H
-#define AES_H
-
-#define AES_BLOCK_SIZE 16
-
-void * aes_encrypt_init(const u8 *key, size_t len);
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
-void aes_encrypt_deinit(void *ctx);
-void * aes_decrypt_init(const u8 *key, size_t len);
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
-void aes_decrypt_deinit(void *ctx);
-
-#endif /* AES_H */

Copied: vendor/wpa/2.0/src/crypto/aes.h (from rev 9639, vendor/wpa/dist/src/crypto/aes.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,21 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#define AES_BLOCK_SIZE 16
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */

Deleted: vendor/wpa/2.0/src/crypto/aes_i.h
===================================================================
--- vendor/wpa/dist/src/crypto/aes_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,122 +0,0 @@
-/*
- * AES (Rijndael) cipher
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AES_I_H
-#define AES_I_H
-
-#include "aes.h"
-
-/* #define FULL_UNROLL */
-#define AES_SMALL_TABLES
-
-extern const u32 Te0[256];
-extern const u32 Te1[256];
-extern const u32 Te2[256];
-extern const u32 Te3[256];
-extern const u32 Te4[256];
-extern const u32 Td0[256];
-extern const u32 Td1[256];
-extern const u32 Td2[256];
-extern const u32 Td3[256];
-extern const u32 Td4[256];
-extern const u32 rcon[10];
-extern const u8 Td4s[256];
-extern const u8 rcons[10];
-
-#ifndef AES_SMALL_TABLES
-
-#define RCON(i) rcon[(i)]
-
-#define TE0(i) Te0[((i) >> 24) & 0xff]
-#define TE1(i) Te1[((i) >> 16) & 0xff]
-#define TE2(i) Te2[((i) >> 8) & 0xff]
-#define TE3(i) Te3[(i) & 0xff]
-#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
-#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
-#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
-#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
-#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
-#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
-#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
-#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
-#define TE4(i) (Te4[(i)] & 0x000000ff)
-
-#define TD0(i) Td0[((i) >> 24) & 0xff]
-#define TD1(i) Td1[((i) >> 16) & 0xff]
-#define TD2(i) Td2[((i) >> 8) & 0xff]
-#define TD3(i) Td3[(i) & 0xff]
-#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
-#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
-#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
-#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
-#define TD0_(i) Td0[(i) & 0xff]
-#define TD1_(i) Td1[(i) & 0xff]
-#define TD2_(i) Td2[(i) & 0xff]
-#define TD3_(i) Td3[(i) & 0xff]
-
-#else /* AES_SMALL_TABLES */
-
-#define RCON(i) (rcons[(i)] << 24)
-
-static inline u32 rotr(u32 val, int bits)
-{
-	return (val >> bits) | (val << (32 - bits));
-}
-
-#define TE0(i) Te0[((i) >> 24) & 0xff]
-#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
-#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
-#define TE3(i) rotr(Te0[(i) & 0xff], 24)
-#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
-#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
-#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
-#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
-#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
-#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
-#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
-#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
-#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
-
-#define TD0(i) Td0[((i) >> 24) & 0xff]
-#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
-#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
-#define TD3(i) rotr(Td0[(i) & 0xff], 24)
-#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
-#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
-#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
-#define TD44(i) (Td4s[(i) & 0xff])
-#define TD0_(i) Td0[(i) & 0xff]
-#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
-#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
-#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
-
-#endif /* AES_SMALL_TABLES */
-
-#ifdef _MSC_VER
-#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
-#define GETU32(p) SWAP(*((u32 *)(p)))
-#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
-#else
-#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
-((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
-#define PUTU32(ct, st) { \
-(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
-(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
-#endif
-
-#define AES_PRIV_SIZE (4 * 44)
-
-void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]);
-
-#endif /* AES_I_H */

Copied: vendor/wpa/2.0/src/crypto/aes_i.h (from rev 9639, vendor/wpa/dist/src/crypto/aes_i.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,125 @@
+/*
+ * AES (Rijndael) cipher
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_I_H
+#define AES_I_H
+
+#include "aes.h"
+
+/* #define FULL_UNROLL */
+#define AES_SMALL_TABLES
+
+extern const u32 Te0[256];
+extern const u32 Te1[256];
+extern const u32 Te2[256];
+extern const u32 Te3[256];
+extern const u32 Te4[256];
+extern const u32 Td0[256];
+extern const u32 Td1[256];
+extern const u32 Td2[256];
+extern const u32 Td3[256];
+extern const u32 Td4[256];
+extern const u32 rcon[10];
+extern const u8 Td4s[256];
+extern const u8 rcons[10];
+
+#ifndef AES_SMALL_TABLES
+
+#define RCON(i) rcon[(i)]
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) Te1[((i) >> 16) & 0xff]
+#define TE2(i) Te2[((i) >> 8) & 0xff]
+#define TE3(i) Te3[(i) & 0xff]
+#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
+#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
+#define TE411(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE422(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE433(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE444(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE4(i) (Te4[(i)] & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) Td1[((i) >> 16) & 0xff]
+#define TD2(i) Td2[((i) >> 8) & 0xff]
+#define TD3(i) Td3[(i) & 0xff]
+#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
+#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) Td1[(i) & 0xff]
+#define TD2_(i) Td2[(i) & 0xff]
+#define TD3_(i) Td3[(i) & 0xff]
+
+#else /* AES_SMALL_TABLES */
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE411(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE422(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE433(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE444(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#endif /* AES_SMALL_TABLES */
+
+#ifdef _MSC_VER
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+#define AES_PRIV_SIZE (4 * 4 * 15 + 4)
+#define AES_PRIV_NR_POS (4 * 15)
+
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits);
+
+#endif /* AES_I_H */

Deleted: vendor/wpa/2.0/src/crypto/aes_wrap.h
===================================================================
--- vendor/wpa/dist/src/crypto/aes_wrap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/aes_wrap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,48 +0,0 @@
-/*
- * AES-based functions
- *
- * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
- * - AES-128 CTR mode encryption
- * - AES-128 EAX mode encryption/decryption
- * - AES-128 CBC
- *
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AES_WRAP_H
-#define AES_WRAP_H
-
-int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
-int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
-int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
-				      const u8 *addr[], const size_t *len,
-				      u8 *mac);
-int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
-			       u8 *mac);
-int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
-int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
-				     u8 *data, size_t data_len);
-int __must_check aes_128_eax_encrypt(const u8 *key,
-				     const u8 *nonce, size_t nonce_len,
-				     const u8 *hdr, size_t hdr_len,
-				     u8 *data, size_t data_len, u8 *tag);
-int __must_check aes_128_eax_decrypt(const u8 *key,
-				     const u8 *nonce, size_t nonce_len,
-				     const u8 *hdr, size_t hdr_len,
-				     u8 *data, size_t data_len, const u8 *tag);
-int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
-				     size_t data_len);
-int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
-				     size_t data_len);
-
-#endif /* AES_WRAP_H */

Copied: vendor/wpa/2.0/src/crypto/aes_wrap.h (from rev 9639, vendor/wpa/dist/src/crypto/aes_wrap.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/aes_wrap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/aes_wrap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,64 @@
+/*
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ * - AES-GCM
+ * - AES-CCM
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_WRAP_H
+#define AES_WRAP_H
+
+int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
+int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
+				      const u8 *addr[], const size_t *len,
+				      u8 *mac);
+int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
+			       u8 *mac);
+int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+				     u8 *data, size_t data_len);
+int __must_check aes_128_eax_encrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, u8 *tag);
+int __must_check aes_128_eax_decrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, const u8 *tag);
+int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_gcm_ae(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len,
+			    u8 *crypt, u8 *tag);
+int __must_check aes_gcm_ad(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *tag,
+			    u8 *plain);
+int __must_check aes_gmac(const u8 *key, size_t key_len,
+			  const u8 *iv, size_t iv_len,
+			  const u8 *aad, size_t aad_len, u8 *tag);
+int __must_check aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
+int __must_check aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *auth,
+			    u8 *plain);
+
+#endif /* AES_WRAP_H */

Deleted: vendor/wpa/2.0/src/crypto/crypto.h
===================================================================
--- vendor/wpa/dist/src/crypto/crypto.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,469 +0,0 @@
-/*
- * WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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
-
-/**
- * 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);
-
-#ifdef CONFIG_FIPS
-/**
- * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
- * @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_non_fips_allow(size_t num_elem, const u8 *addr[],
-			      const size_t *len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define md5_vector_non_fips_allow md5_vector
-#endif /* CONFIG_FIPS */
-
-
-/**
- * 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);
-
-/**
- * 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
-};
-
-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);
-
-/**
- * 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);
-
-#endif /* CRYPTO_H */

Copied: vendor/wpa/2.0/src/crypto/crypto.h (from rev 9639, vendor/wpa/dist/src/crypto/crypto.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,460 @@
+/*
+ * WPA Supplicant / wrapper functions for crypto libraries
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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
+
+/**
+ * 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);
+
+/**
+ * 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
+};
+
+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);
+
+/**
+ * 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);
+
+#endif /* CRYPTO_H */

Deleted: vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_cryptoapi.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,789 +0,0 @@
-/*
- * Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef MS_ENH_RSA_AES_PROV
-#ifdef UNICODE
-#define MS_ENH_RSA_AES_PROV \
-L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#else
-#define MS_ENH_RSA_AES_PROV \
-"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#endif
-#endif /* MS_ENH_RSA_AES_PROV */
-
-#ifndef CALG_HMAC
-#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
-#endif
-
-#ifdef __MINGW32_VERSION
-/*
- * MinGW does not yet include all the needed definitions for CryptoAPI, so
- * define here whatever extra is needed.
- */
-
-static BOOL WINAPI
-(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
-			    PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
-= NULL; /* to be loaded from crypt32.dll */
-
-
-static int mingw_load_crypto_func(void)
-{
-	HINSTANCE dll;
-
-	/* MinGW does not yet have full CryptoAPI support, so load the needed
-	 * function here. */
-
-	if (CryptImportPublicKeyInfo)
-		return 0;
-
-	dll = LoadLibrary("crypt32");
-	if (dll == NULL) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
-			   "library");
-		return -1;
-	}
-
-	CryptImportPublicKeyInfo = GetProcAddress(
-		dll, "CryptImportPublicKeyInfo");
-	if (CryptImportPublicKeyInfo == NULL) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
-			   "CryptImportPublicKeyInfo() address from "
-			   "crypt32 library");
-		return -1;
-	}
-
-	return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
-	return 0;
-}
-
-#endif /* __MINGW32_VERSION */
-
-
-static void cryptoapi_report_error(const char *msg)
-{
-	char *s, *pos;
-	DWORD err = GetLastError();
-
-	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-			  FORMAT_MESSAGE_FROM_SYSTEM,
-			  NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
-	}
-
-	pos = s;
-	while (*pos) {
-		if (*pos == '\n' || *pos == '\r') {
-			*pos = '\0';
-			break;
-		}
-		pos++;
-	}
-
-	wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
-	LocalFree(s);
-}
-
-
-int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
-			  const u8 *addr[], const size_t *len, u8 *mac)
-{
-	HCRYPTPROV prov;
-	HCRYPTHASH hash;
-	size_t i;
-	DWORD hlen;
-	int ret = 0;
-
-	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		return -1;
-	}
-
-	if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
-		cryptoapi_report_error("CryptCreateHash");
-		CryptReleaseContext(prov, 0);
-		return -1;
-	}
-
-	for (i = 0; i < num_elem; i++) {
-		if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
-			cryptoapi_report_error("CryptHashData");
-			CryptDestroyHash(hash);
-			CryptReleaseContext(prov, 0);
-		}
-	}
-
-	hlen = hash_len;
-	if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
-		cryptoapi_report_error("CryptGetHashParam");
-		ret = -1;
-	}
-
-	CryptDestroyHash(hash);
-	CryptReleaseContext(prov, 0);
-
-	return ret;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	u8 next, tmp;
-	int i;
-	HCRYPTPROV prov;
-	HCRYPTKEY ckey;
-	DWORD dlen;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[8];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_ECB;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.hdr.aiKeyAlg = CALG_DES;
-	key_blob.len = 8;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		key_blob.key[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	key_blob.key[i] = next | 1;
-
-	if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
-				 CRYPT_VERIFYCONTEXT)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
-			   "%d", (int) GetLastError());
-		return;
-	}
-
-	if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
-			    &ckey)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
-			   (int) GetLastError());
-		CryptReleaseContext(prov, 0);
-		return;
-	}
-
-	if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
-			   "failed: %d", (int) GetLastError());
-		CryptDestroyKey(ckey);
-		CryptReleaseContext(prov, 0);
-		return;
-	}
-
-	os_memcpy(cypher, clear, 8);
-	dlen = 8;
-	if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
-			   (int) GetLastError());
-		os_memset(cypher, 0, 8);
-	}
-
-	CryptDestroyKey(ckey);
-	CryptReleaseContext(prov, 0);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
-}
-
-
-struct aes_context {
-	HCRYPTPROV prov;
-	HCRYPTKEY ckey;
-};
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	struct aes_context *akey;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[16];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_ECB;
-
-	if (len != 16)
-		return NULL;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.hdr.aiKeyAlg = CALG_AES_128;
-	key_blob.len = len;
-	os_memcpy(key_blob.key, key, len);
-
-	akey = os_zalloc(sizeof(*akey));
-	if (akey == NULL)
-		return NULL;
-
-	if (!CryptAcquireContext(&akey->prov, NULL,
-				 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
-				 CRYPT_VERIFYCONTEXT)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
-			   "%d", (int) GetLastError());
-		os_free(akey);
-		return NULL;
-	}
-
-	if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
-			    0, 0, &akey->ckey)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
-			   (int) GetLastError());
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-		return NULL;
-	}
-
-	if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
- 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
-			   "failed: %d", (int) GetLastError());
-		CryptDestroyKey(akey->ckey);
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-		return NULL;
-	}
-
-	return akey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	struct aes_context *akey = ctx;
-	DWORD dlen;
-
-	os_memcpy(crypt, plain, 16);
-	dlen = 16;
-	if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
-			   (int) GetLastError());
-		os_memset(crypt, 0, 16);
-	}
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	struct aes_context *akey = ctx;
-	if (akey) {
-		CryptDestroyKey(akey->ckey);
-		CryptReleaseContext(akey->prov, 0);
-		os_free(akey);
-	}
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	return aes_encrypt_init(key, len);
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	struct aes_context *akey = ctx;
-	DWORD dlen;
-
-	os_memcpy(plain, crypt, 16);
-	dlen = 16;
-
-	if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
-			   (int) GetLastError());
-	}
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	aes_encrypt_deinit(ctx);
-}
-
-
-struct crypto_hash {
-	enum crypto_hash_alg alg;
-	int error;
-	HCRYPTPROV prov;
-	HCRYPTHASH hash;
-	HCRYPTKEY key;
-};
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
-				      size_t key_len)
-{
-	struct crypto_hash *ctx;
-	ALG_ID calg;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[32];
-	} key_blob;
-
-	os_memset(&key_blob, 0, sizeof(key_blob));
-	switch (alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		calg = CALG_MD5;
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		calg = CALG_SHA;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		calg = CALG_HMAC;
-		key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-		key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-		key_blob.hdr.reserved = 0;
-		/*
-		 * Note: RC2 is not really used, but that can be used to
-		 * import HMAC keys of up to 16 byte long.
-		 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
-		 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
-		 */
-		key_blob.hdr.aiKeyAlg = CALG_RC2;
-		key_blob.len = key_len;
-		if (key_len > sizeof(key_blob.key))
-			return NULL;
-		os_memcpy(key_blob.key, key, key_len);
-		break;
-	default:
-		return NULL;
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	ctx->alg = alg;
-
-	if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (calg == CALG_HMAC) {
-#ifndef CRYPT_IPSEC_HMAC_KEY
-#define CRYPT_IPSEC_HMAC_KEY 0x00000100
-#endif
-		if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
-				    sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
-				    &ctx->key)) {
-			cryptoapi_report_error("CryptImportKey");
-			CryptReleaseContext(ctx->prov, 0);
-			os_free(ctx);
-			return NULL;
-		}
-	}
-
-	if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
-		cryptoapi_report_error("CryptCreateHash");
-		CryptReleaseContext(ctx->prov, 0);
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (calg == CALG_HMAC) {
-		HMAC_INFO info;
-		os_memset(&info, 0, sizeof(info));
-		switch (alg) {
-		case CRYPTO_HASH_ALG_HMAC_MD5:
-			info.HashAlgid = CALG_MD5;
-			break;
-		case CRYPTO_HASH_ALG_HMAC_SHA1:
-			info.HashAlgid = CALG_SHA;
-			break;
-		default:
-			/* unreachable */
-			break;
-		}
-
-		if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
-				       0)) {
-			cryptoapi_report_error("CryptSetHashParam");
-			CryptDestroyHash(ctx->hash);
-			CryptReleaseContext(ctx->prov, 0);
-			os_free(ctx);
-			return NULL;
-		}
-	}
-
-	return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
-	if (ctx == NULL || ctx->error)
-		return;
-
-	if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
-		cryptoapi_report_error("CryptHashData");
-		ctx->error = 1;
-	}
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
-	int ret = 0;
-	DWORD hlen;
-
-	if (ctx == NULL)
-		return -2;
-
-	if (mac == NULL || len == NULL)
-		goto done;
-
-	if (ctx->error) {
-		ret = -2;
-		goto done;
-	}
-
-	hlen = *len;
-	if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
-		cryptoapi_report_error("CryptGetHashParam");
-		ret = -2;
-	}
-	*len = hlen;
-
-done:
-	if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
-	    ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
-		CryptDestroyKey(ctx->key);
-
-	os_free(ctx);
-
-	return ret;
-}
-
-
-struct crypto_cipher {
-	HCRYPTPROV prov;
-	HCRYPTKEY key;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{	
-	struct crypto_cipher *ctx;
-	struct {
-		BLOBHEADER hdr;
-		DWORD len;
-		BYTE key[32];
-	} key_blob;
-	DWORD mode = CRYPT_MODE_CBC;
-
-	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
-	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
-	key_blob.hdr.reserved = 0;
-	key_blob.len = key_len;
-	if (key_len > sizeof(key_blob.key))
-		return NULL;
-	os_memcpy(key_blob.key, key, key_len);
-
-	switch (alg) {
-	case CRYPTO_CIPHER_ALG_AES:
-		if (key_len == 32)
-			key_blob.hdr.aiKeyAlg = CALG_AES_256;
-		else if (key_len == 24)
-			key_blob.hdr.aiKeyAlg = CALG_AES_192;
-		else
-			key_blob.hdr.aiKeyAlg = CALG_AES_128;
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		key_blob.hdr.aiKeyAlg = CALG_3DES;
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		key_blob.hdr.aiKeyAlg = CALG_DES;
-		break;
-	case CRYPTO_CIPHER_ALG_RC2:
-		key_blob.hdr.aiKeyAlg = CALG_RC2;
-		break;
-	case CRYPTO_CIPHER_ALG_RC4:
-		key_blob.hdr.aiKeyAlg = CALG_RC4;
-		break;
-	default:
-		return NULL;
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
-				 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
-		cryptoapi_report_error("CryptAcquireContext");
-		goto fail1;
-	}
-
-	if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
-			    sizeof(key_blob), 0, 0, &ctx->key)) {
- 		cryptoapi_report_error("CryptImportKey");
-		goto fail2;
-	}
-
-	if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
- 		cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
-		goto fail3;
-	}
-
-	if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
- 		cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
-		goto fail3;
-	}
-
-	return ctx;
-
-fail3:
-	CryptDestroyKey(ctx->key);
-fail2:
-	CryptReleaseContext(ctx->prov, 0);
-fail1:
-	os_free(ctx);
-	return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	DWORD dlen;
-
-	os_memcpy(crypt, plain, len);
-	dlen = len;
-	if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
- 		cryptoapi_report_error("CryptEncrypt");
-		os_memset(crypt, 0, len);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	DWORD dlen;
-
-	os_memcpy(plain, crypt, len);
-	dlen = len;
-	if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
- 		cryptoapi_report_error("CryptDecrypt");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-	CryptDestroyKey(ctx->key);
-	CryptReleaseContext(ctx->prov, 0);
-	os_free(ctx);
-}
-
-
-struct crypto_public_key {
-	HCRYPTPROV prov;
-	HCRYPTKEY rsa;
-};
-
-struct crypto_private_key {
-	HCRYPTPROV prov;
-	HCRYPTKEY rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
-	/* Use crypto_public_key_from_cert() instead. */
-	return NULL;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
-						      size_t len,
-						      const char *passwd)
-{
-	/* TODO */
-	return NULL;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
-						       size_t len)
-{
-	struct crypto_public_key *pk;
-	PCCERT_CONTEXT cc;
-
-	pk = os_zalloc(sizeof(*pk));
-	if (pk == NULL)
-		return NULL;
-
-	cc = CertCreateCertificateContext(X509_ASN_ENCODING |
-					  PKCS_7_ASN_ENCODING, buf, len);
-	if (!cc) {
- 		cryptoapi_report_error("CryptCreateCertificateContext");
-		os_free(pk);
-		return NULL;
-	}
-
-	if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
-				 0)) {
- 		cryptoapi_report_error("CryptAcquireContext");
-		os_free(pk);
-		CertFreeCertificateContext(cc);
-		return NULL;
-	}
-
-	if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
-				      PKCS_7_ASN_ENCODING,
-				      &cc->pCertInfo->SubjectPublicKeyInfo,
-				      &pk->rsa)) {
- 		cryptoapi_report_error("CryptImportPublicKeyInfo");
-		CryptReleaseContext(pk->prov, 0);
-		os_free(pk);
-		CertFreeCertificateContext(cc);
-		return NULL;
-	}
-
-	CertFreeCertificateContext(cc);
-
-	return pk;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
-					const u8 *in, size_t inlen,
-					u8 *out, size_t *outlen)
-{
-	DWORD clen;
-	u8 *tmp;
-	size_t i;
-
-	if (*outlen < inlen)
-		return -1;
-	tmp = malloc(*outlen);
-	if (tmp == NULL)
-		return -1;
-
-	os_memcpy(tmp, in, inlen);
-	clen = inlen;
-	if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
-		wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
-			   "public key: %d", (int) GetLastError());
-		os_free(tmp);
-		return -1;
-	}
-
-	*outlen = clen;
-
-	/* Reverse the output */
-	for (i = 0; i < *outlen; i++)
-		out[i] = tmp[*outlen - 1 - i];
-
-	os_free(tmp);
-
-	return 0;
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen)
-{
-	/* TODO */
-	return -1;
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
-	if (key) {
-		CryptDestroyKey(key->rsa);
-		CryptReleaseContext(key->prov, 0);
-		os_free(key);
-	}
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
-	if (key) {
-		CryptDestroyKey(key->rsa);
-		CryptReleaseContext(key->prov, 0);
-		os_free(key);
-	}
-}
-
-
-int crypto_global_init(void)
-{
-	return mingw_load_crypto_func();
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	/* TODO */
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_cryptoapi.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_cryptoapi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,783 @@
+/*
+ * Crypto wrapper for Microsoft CryptoAPI
+ * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef MS_ENH_RSA_AES_PROV
+#ifdef UNICODE
+#define MS_ENH_RSA_AES_PROV \
+L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#else
+#define MS_ENH_RSA_AES_PROV \
+"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#endif
+#endif /* MS_ENH_RSA_AES_PROV */
+
+#ifndef CALG_HMAC
+#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
+#endif
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+
+static BOOL WINAPI
+(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
+			    PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
+= NULL; /* to be loaded from crypt32.dll */
+
+
+static int mingw_load_crypto_func(void)
+{
+	HINSTANCE dll;
+
+	/* MinGW does not yet have full CryptoAPI support, so load the needed
+	 * function here. */
+
+	if (CryptImportPublicKeyInfo)
+		return 0;
+
+	dll = LoadLibrary("crypt32");
+	if (dll == NULL) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+			   "library");
+		return -1;
+	}
+
+	CryptImportPublicKeyInfo = GetProcAddress(
+		dll, "CryptImportPublicKeyInfo");
+	if (CryptImportPublicKeyInfo == NULL) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+			   "CryptImportPublicKeyInfo() address from "
+			   "crypt32 library");
+		return -1;
+	}
+
+	return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+	return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+
+
+static void cryptoapi_report_error(const char *msg)
+{
+	char *s, *pos;
+	DWORD err = GetLastError();
+
+	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			  FORMAT_MESSAGE_FROM_SYSTEM,
+			  NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
+	}
+
+	pos = s;
+	while (*pos) {
+		if (*pos == '\n' || *pos == '\r') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+
+	wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
+	LocalFree(s);
+}
+
+
+int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
+			  const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HCRYPTPROV prov;
+	HCRYPTHASH hash;
+	size_t i;
+	DWORD hlen;
+	int ret = 0;
+
+	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		return -1;
+	}
+
+	if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
+		cryptoapi_report_error("CryptCreateHash");
+		CryptReleaseContext(prov, 0);
+		return -1;
+	}
+
+	for (i = 0; i < num_elem; i++) {
+		if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
+			cryptoapi_report_error("CryptHashData");
+			CryptDestroyHash(hash);
+			CryptReleaseContext(prov, 0);
+		}
+	}
+
+	hlen = hash_len;
+	if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
+		cryptoapi_report_error("CryptGetHashParam");
+		ret = -1;
+	}
+
+	CryptDestroyHash(hash);
+	CryptReleaseContext(prov, 0);
+
+	return ret;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 next, tmp;
+	int i;
+	HCRYPTPROV prov;
+	HCRYPTKEY ckey;
+	DWORD dlen;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[8];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_ECB;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.hdr.aiKeyAlg = CALG_DES;
+	key_blob.len = 8;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		key_blob.key[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	key_blob.key[i] = next | 1;
+
+	if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
+				 CRYPT_VERIFYCONTEXT)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+			   "%d", (int) GetLastError());
+		return;
+	}
+
+	if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
+			    &ckey)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+			   (int) GetLastError());
+		CryptReleaseContext(prov, 0);
+		return;
+	}
+
+	if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+			   "failed: %d", (int) GetLastError());
+		CryptDestroyKey(ckey);
+		CryptReleaseContext(prov, 0);
+		return;
+	}
+
+	os_memcpy(cypher, clear, 8);
+	dlen = 8;
+	if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+			   (int) GetLastError());
+		os_memset(cypher, 0, 8);
+	}
+
+	CryptDestroyKey(ckey);
+	CryptReleaseContext(prov, 0);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
+}
+
+
+struct aes_context {
+	HCRYPTPROV prov;
+	HCRYPTKEY ckey;
+};
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	struct aes_context *akey;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[16];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_ECB;
+
+	if (len != 16)
+		return NULL;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.hdr.aiKeyAlg = CALG_AES_128;
+	key_blob.len = len;
+	os_memcpy(key_blob.key, key, len);
+
+	akey = os_zalloc(sizeof(*akey));
+	if (akey == NULL)
+		return NULL;
+
+	if (!CryptAcquireContext(&akey->prov, NULL,
+				 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
+				 CRYPT_VERIFYCONTEXT)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+			   "%d", (int) GetLastError());
+		os_free(akey);
+		return NULL;
+	}
+
+	if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
+			    0, 0, &akey->ckey)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+			   (int) GetLastError());
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+		return NULL;
+	}
+
+	if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+			   "failed: %d", (int) GetLastError());
+		CryptDestroyKey(akey->ckey);
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+		return NULL;
+	}
+
+	return akey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	struct aes_context *akey = ctx;
+	DWORD dlen;
+
+	os_memcpy(crypt, plain, 16);
+	dlen = 16;
+	if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+			   (int) GetLastError());
+		os_memset(crypt, 0, 16);
+	}
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	struct aes_context *akey = ctx;
+	if (akey) {
+		CryptDestroyKey(akey->ckey);
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+	}
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	return aes_encrypt_init(key, len);
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	struct aes_context *akey = ctx;
+	DWORD dlen;
+
+	os_memcpy(plain, crypt, 16);
+	dlen = 16;
+
+	if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
+			   (int) GetLastError());
+	}
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	aes_encrypt_deinit(ctx);
+}
+
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	int error;
+	HCRYPTPROV prov;
+	HCRYPTHASH hash;
+	HCRYPTKEY key;
+};
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	ALG_ID calg;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[32];
+	} key_blob;
+
+	os_memset(&key_blob, 0, sizeof(key_blob));
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		calg = CALG_MD5;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		calg = CALG_SHA;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		calg = CALG_HMAC;
+		key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+		key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+		key_blob.hdr.reserved = 0;
+		/*
+		 * Note: RC2 is not really used, but that can be used to
+		 * import HMAC keys of up to 16 byte long.
+		 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
+		 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
+		 */
+		key_blob.hdr.aiKeyAlg = CALG_RC2;
+		key_blob.len = key_len;
+		if (key_len > sizeof(key_blob.key))
+			return NULL;
+		os_memcpy(key_blob.key, key, key_len);
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (calg == CALG_HMAC) {
+#ifndef CRYPT_IPSEC_HMAC_KEY
+#define CRYPT_IPSEC_HMAC_KEY 0x00000100
+#endif
+		if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+				    sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
+				    &ctx->key)) {
+			cryptoapi_report_error("CryptImportKey");
+			CryptReleaseContext(ctx->prov, 0);
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
+		cryptoapi_report_error("CryptCreateHash");
+		CryptReleaseContext(ctx->prov, 0);
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (calg == CALG_HMAC) {
+		HMAC_INFO info;
+		os_memset(&info, 0, sizeof(info));
+		switch (alg) {
+		case CRYPTO_HASH_ALG_HMAC_MD5:
+			info.HashAlgid = CALG_MD5;
+			break;
+		case CRYPTO_HASH_ALG_HMAC_SHA1:
+			info.HashAlgid = CALG_SHA;
+			break;
+		default:
+			/* unreachable */
+			break;
+		}
+
+		if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
+				       0)) {
+			cryptoapi_report_error("CryptSetHashParam");
+			CryptDestroyHash(ctx->hash);
+			CryptReleaseContext(ctx->prov, 0);
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL || ctx->error)
+		return;
+
+	if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
+		cryptoapi_report_error("CryptHashData");
+		ctx->error = 1;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	int ret = 0;
+	DWORD hlen;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL)
+		goto done;
+
+	if (ctx->error) {
+		ret = -2;
+		goto done;
+	}
+
+	hlen = *len;
+	if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
+		cryptoapi_report_error("CryptGetHashParam");
+		ret = -2;
+	}
+	*len = hlen;
+
+done:
+	if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
+	    ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
+		CryptDestroyKey(ctx->key);
+
+	os_free(ctx);
+
+	return ret;
+}
+
+
+struct crypto_cipher {
+	HCRYPTPROV prov;
+	HCRYPTKEY key;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{	
+	struct crypto_cipher *ctx;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[32];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_CBC;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.len = key_len;
+	if (key_len > sizeof(key_blob.key))
+		return NULL;
+	os_memcpy(key_blob.key, key, key_len);
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		if (key_len == 32)
+			key_blob.hdr.aiKeyAlg = CALG_AES_256;
+		else if (key_len == 24)
+			key_blob.hdr.aiKeyAlg = CALG_AES_192;
+		else
+			key_blob.hdr.aiKeyAlg = CALG_AES_128;
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		key_blob.hdr.aiKeyAlg = CALG_3DES;
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		key_blob.hdr.aiKeyAlg = CALG_DES;
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		key_blob.hdr.aiKeyAlg = CALG_RC2;
+		break;
+	case CRYPTO_CIPHER_ALG_RC4:
+		key_blob.hdr.aiKeyAlg = CALG_RC4;
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
+				 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		goto fail1;
+	}
+
+	if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+			    sizeof(key_blob), 0, 0, &ctx->key)) {
+ 		cryptoapi_report_error("CryptImportKey");
+		goto fail2;
+	}
+
+	if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
+ 		cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
+		goto fail3;
+	}
+
+	if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
+ 		cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
+		goto fail3;
+	}
+
+	return ctx;
+
+fail3:
+	CryptDestroyKey(ctx->key);
+fail2:
+	CryptReleaseContext(ctx->prov, 0);
+fail1:
+	os_free(ctx);
+	return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	DWORD dlen;
+
+	os_memcpy(crypt, plain, len);
+	dlen = len;
+	if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
+ 		cryptoapi_report_error("CryptEncrypt");
+		os_memset(crypt, 0, len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	DWORD dlen;
+
+	os_memcpy(plain, crypt, len);
+	dlen = len;
+	if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
+ 		cryptoapi_report_error("CryptDecrypt");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	CryptDestroyKey(ctx->key);
+	CryptReleaseContext(ctx->prov, 0);
+	os_free(ctx);
+}
+
+
+struct crypto_public_key {
+	HCRYPTPROV prov;
+	HCRYPTKEY rsa;
+};
+
+struct crypto_private_key {
+	HCRYPTPROV prov;
+	HCRYPTKEY rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	/* Use crypto_public_key_from_cert() instead. */
+	return NULL;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	/* TODO */
+	return NULL;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	struct crypto_public_key *pk;
+	PCCERT_CONTEXT cc;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	cc = CertCreateCertificateContext(X509_ASN_ENCODING |
+					  PKCS_7_ASN_ENCODING, buf, len);
+	if (!cc) {
+ 		cryptoapi_report_error("CryptCreateCertificateContext");
+		os_free(pk);
+		return NULL;
+	}
+
+	if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+				 0)) {
+ 		cryptoapi_report_error("CryptAcquireContext");
+		os_free(pk);
+		CertFreeCertificateContext(cc);
+		return NULL;
+	}
+
+	if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
+				      PKCS_7_ASN_ENCODING,
+				      &cc->pCertInfo->SubjectPublicKeyInfo,
+				      &pk->rsa)) {
+ 		cryptoapi_report_error("CryptImportPublicKeyInfo");
+		CryptReleaseContext(pk->prov, 0);
+		os_free(pk);
+		CertFreeCertificateContext(cc);
+		return NULL;
+	}
+
+	CertFreeCertificateContext(cc);
+
+	return pk;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	DWORD clen;
+	u8 *tmp;
+	size_t i;
+
+	if (*outlen < inlen)
+		return -1;
+	tmp = malloc(*outlen);
+	if (tmp == NULL)
+		return -1;
+
+	os_memcpy(tmp, in, inlen);
+	clen = inlen;
+	if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
+			   "public key: %d", (int) GetLastError());
+		os_free(tmp);
+		return -1;
+	}
+
+	*outlen = clen;
+
+	/* Reverse the output */
+	for (i = 0; i < *outlen; i++)
+		out[i] = tmp[*outlen - 1 - i];
+
+	os_free(tmp);
+
+	return 0;
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	/* TODO */
+	return -1;
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	if (key) {
+		CryptDestroyKey(key->rsa);
+		CryptReleaseContext(key->prov, 0);
+		os_free(key);
+	}
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	if (key) {
+		CryptDestroyKey(key->rsa);
+		CryptReleaseContext(key->prov, 0);
+		os_free(key);
+	}
+}
+
+
+int crypto_global_init(void)
+{
+	return mingw_load_crypto_func();
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	/* TODO */
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_gnutls.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_gnutls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,305 +0,0 @@
-/*
- * WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <gcrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	gcry_md_hd_t hd;
-	unsigned char *p;
-	size_t i;
-
-	if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
-		return -1;
-	for (i = 0; i < num_elem; i++)
-		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_MD4);
-	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
-	gcry_md_close(hd);
-	return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	gcry_cipher_hd_t hd;
-	u8 pkey[8], next, tmp;
-	int i;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-	gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
-	gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
-	gcry_cipher_close(hd);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	gcry_md_hd_t hd;
-	unsigned char *p;
-	size_t i;
-
-	if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
-		return -1;
-	for (i = 0; i < num_elem; i++)
-		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_MD5);
-	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
-	gcry_md_close(hd);
-	return 0;
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	gcry_md_hd_t hd;
-	unsigned char *p;
-	size_t i;
-
-	if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
-		return -1;
-	for (i = 0; i < num_elem; i++)
-		gcry_md_write(hd, addr[i], len[i]);
-	p = gcry_md_read(hd, GCRY_MD_SHA1);
-	if (p)
-		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
-	gcry_md_close(hd);
-	return 0;
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	gcry_cipher_hd_t hd;
-
-	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
-	    GPG_ERR_NO_ERROR) {
-		printf("cipher open failed\n");
-		return NULL;
-	}
-	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
-		printf("setkey failed\n");
-		gcry_cipher_close(hd);
-		return NULL;
-	}
-
-	return hd;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	gcry_cipher_hd_t hd = ctx;
-	gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	gcry_cipher_hd_t hd = ctx;
-	gcry_cipher_close(hd);
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	gcry_cipher_hd_t hd;
-
-	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
-	    GPG_ERR_NO_ERROR)
-		return NULL;
-	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
-		gcry_cipher_close(hd);
-		return NULL;
-	}
-
-	return hd;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	gcry_cipher_hd_t hd = ctx;
-	gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	gcry_cipher_hd_t hd = ctx;
-	gcry_cipher_close(hd);
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
-		bn_result = NULL;
-	int ret = -1;
-
-	if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
-	    GPG_ERR_NO_ERROR ||
-	    gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
-	    GPG_ERR_NO_ERROR ||
-	    gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
-			  NULL) != GPG_ERR_NO_ERROR)
-		goto error;
-	bn_result = gcry_mpi_new(modulus_len * 8);
-
-	gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
-
-	if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
-			   bn_result) != GPG_ERR_NO_ERROR)
-		goto error;
-
-	ret = 0;
-
-error:
-	gcry_mpi_release(bn_base);
-	gcry_mpi_release(bn_exp);
-	gcry_mpi_release(bn_modulus);
-	gcry_mpi_release(bn_result);
-	return ret;
-}
-
-
-struct crypto_cipher {
-	gcry_cipher_hd_t enc;
-	gcry_cipher_hd_t dec;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{
-	struct crypto_cipher *ctx;
-	gcry_error_t res;
-	enum gcry_cipher_algos a;
-	int ivlen;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	switch (alg) {
-	case CRYPTO_CIPHER_ALG_RC4:
-		a = GCRY_CIPHER_ARCFOUR;
-		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
-				       0);
-		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
-		break;
-	case CRYPTO_CIPHER_ALG_AES:
-		if (key_len == 24)
-			a = GCRY_CIPHER_AES192;
-		else if (key_len == 32)
-			a = GCRY_CIPHER_AES256;
-		else
-			a = GCRY_CIPHER_AES;
-		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
-		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		a = GCRY_CIPHER_3DES;
-		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
-		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		a = GCRY_CIPHER_DES;
-		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
-		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
-		break;
-	case CRYPTO_CIPHER_ALG_RC2:
-		if (key_len == 5)
-			a = GCRY_CIPHER_RFC2268_40;
-		else
-			a = GCRY_CIPHER_RFC2268_128;
-		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
-		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
-		break;
-	default:
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (res != GPG_ERR_NO_ERROR) {
-		os_free(ctx);
-		return NULL;
-	}
-
-	if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
-	    gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
-		gcry_cipher_close(ctx->enc);
-		gcry_cipher_close(ctx->dec);
-		os_free(ctx);
-		return NULL;
-	}
-
-	ivlen = gcry_cipher_get_algo_blklen(a);
-	if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
-	    gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
-		gcry_cipher_close(ctx->enc);
-		gcry_cipher_close(ctx->dec);
-		os_free(ctx);
-		return NULL;
-	}
-
-	return ctx;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
-	    GPG_ERR_NO_ERROR)
-		return -1;
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
-	    GPG_ERR_NO_ERROR)
-		return -1;
-	return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-	gcry_cipher_close(ctx->enc);
-	gcry_cipher_close(ctx->dec);
-	os_free(ctx);
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_gnutls.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_gnutls.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_gnutls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,299 @@
+/*
+ * WPA Supplicant / wrapper functions for libgcrypt
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_MD4);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	gcry_cipher_hd_t hd;
+	u8 pkey[8], next, tmp;
+	int i;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+	gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
+	gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
+	gcry_cipher_close(hd);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_MD5);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_SHA1);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	gcry_cipher_hd_t hd;
+
+	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+	    GPG_ERR_NO_ERROR) {
+		printf("cipher open failed\n");
+		return NULL;
+	}
+	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+		printf("setkey failed\n");
+		gcry_cipher_close(hd);
+		return NULL;
+	}
+
+	return hd;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_close(hd);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	gcry_cipher_hd_t hd;
+
+	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+	    GPG_ERR_NO_ERROR)
+		return NULL;
+	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(hd);
+		return NULL;
+	}
+
+	return hd;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_close(hd);
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
+		bn_result = NULL;
+	int ret = -1;
+
+	if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
+	    GPG_ERR_NO_ERROR ||
+	    gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
+	    GPG_ERR_NO_ERROR ||
+	    gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
+			  NULL) != GPG_ERR_NO_ERROR)
+		goto error;
+	bn_result = gcry_mpi_new(modulus_len * 8);
+
+	gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
+
+	if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
+			   bn_result) != GPG_ERR_NO_ERROR)
+		goto error;
+
+	ret = 0;
+
+error:
+	gcry_mpi_release(bn_base);
+	gcry_mpi_release(bn_exp);
+	gcry_mpi_release(bn_modulus);
+	gcry_mpi_release(bn_result);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	gcry_cipher_hd_t enc;
+	gcry_cipher_hd_t dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+	gcry_error_t res;
+	enum gcry_cipher_algos a;
+	int ivlen;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		a = GCRY_CIPHER_ARCFOUR;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
+				       0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (key_len == 24)
+			a = GCRY_CIPHER_AES192;
+		else if (key_len == 32)
+			a = GCRY_CIPHER_AES256;
+		else
+			a = GCRY_CIPHER_AES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		a = GCRY_CIPHER_3DES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		a = GCRY_CIPHER_DES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		if (key_len == 5)
+			a = GCRY_CIPHER_RFC2268_40;
+		else
+			a = GCRY_CIPHER_RFC2268_128;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (res != GPG_ERR_NO_ERROR) {
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
+	    gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(ctx->enc);
+		gcry_cipher_close(ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	ivlen = gcry_cipher_get_algo_blklen(a);
+	if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
+	    gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(ctx->enc);
+		gcry_cipher_close(ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
+	    GPG_ERR_NO_ERROR)
+		return -1;
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
+	    GPG_ERR_NO_ERROR)
+		return -1;
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	gcry_cipher_close(ctx->enc);
+	gcry_cipher_close(ctx->dec);
+	os_free(ctx);
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_internal-cipher.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,256 +0,0 @@
-/*
- * Crypto wrapper for internal crypto implementation - Cipher wrappers
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "aes.h"
-#include "des_i.h"
-
-
-struct crypto_cipher {
-	enum crypto_cipher_alg alg;
-	union {
-		struct {
-			size_t used_bytes;
-			u8 key[16];
-			size_t keylen;
-		} rc4;
-		struct {
-			u8 cbc[32];
-			size_t block_size;
-			void *ctx_enc;
-			void *ctx_dec;
-		} aes;
-		struct {
-			struct des3_key_s key;
-			u8 cbc[8];
-		} des3;
-		struct {
-			u32 ek[32];
-			u32 dk[32];
-			u8 cbc[8];
-		} des;
-	} u;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{
-	struct crypto_cipher *ctx;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	ctx->alg = alg;
-
-	switch (alg) {
-	case CRYPTO_CIPHER_ALG_RC4:
-		if (key_len > sizeof(ctx->u.rc4.key)) {
-			os_free(ctx);
-			return NULL;
-		}
-		ctx->u.rc4.keylen = key_len;
-		os_memcpy(ctx->u.rc4.key, key, key_len);
-		break;
-	case CRYPTO_CIPHER_ALG_AES:
-		if (key_len > sizeof(ctx->u.aes.cbc)) {
-			os_free(ctx);
-			return NULL;
-		}
-		ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
-		if (ctx->u.aes.ctx_enc == NULL) {
-			os_free(ctx);
-			return NULL;
-		}
-		ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
-		if (ctx->u.aes.ctx_dec == NULL) {
-			aes_encrypt_deinit(ctx->u.aes.ctx_enc);
-			os_free(ctx);
-			return NULL;
-		}
-		ctx->u.aes.block_size = key_len;
-		os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size);
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		if (key_len != 24) {
-			os_free(ctx);
-			return NULL;
-		}
-		des3_key_setup(key, &ctx->u.des3.key);
-		os_memcpy(ctx->u.des3.cbc, iv, 8);
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		if (key_len != 8) {
-			os_free(ctx);
-			return NULL;
-		}
-		des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
-		os_memcpy(ctx->u.des.cbc, iv, 8);
-		break;
-	default:
-		os_free(ctx);
-		return NULL;
-	}
-
-	return ctx;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	size_t i, j, blocks;
-
-	switch (ctx->alg) {
-	case CRYPTO_CIPHER_ALG_RC4:
-		if (plain != crypt)
-			os_memcpy(crypt, plain, len);
-		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
-			 ctx->u.rc4.used_bytes, crypt, len);
-		ctx->u.rc4.used_bytes += len;
-		break;
-	case CRYPTO_CIPHER_ALG_AES:
-		if (len % ctx->u.aes.block_size)
-			return -1;
-		blocks = len / ctx->u.aes.block_size;
-		for (i = 0; i < blocks; i++) {
-			for (j = 0; j < ctx->u.aes.block_size; j++)
-				ctx->u.aes.cbc[j] ^= plain[j];
-			aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
-				    ctx->u.aes.cbc);
-			os_memcpy(crypt, ctx->u.aes.cbc,
-				  ctx->u.aes.block_size);
-			plain += ctx->u.aes.block_size;
-			crypt += ctx->u.aes.block_size;
-		}
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		if (len % 8)
-			return -1;
-		blocks = len / 8;
-		for (i = 0; i < blocks; i++) {
-			for (j = 0; j < 8; j++)
-				ctx->u.des3.cbc[j] ^= plain[j];
-			des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
-				     ctx->u.des3.cbc);
-			os_memcpy(crypt, ctx->u.des3.cbc, 8);
-			plain += 8;
-			crypt += 8;
-		}
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		if (len % 8)
-			return -1;
-		blocks = len / 8;
-		for (i = 0; i < blocks; i++) {
-			for (j = 0; j < 8; j++)
-				ctx->u.des3.cbc[j] ^= plain[j];
-			des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
-					  ctx->u.des.cbc);
-			os_memcpy(crypt, ctx->u.des.cbc, 8);
-			plain += 8;
-			crypt += 8;
-		}
-		break;
-	default:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	size_t i, j, blocks;
-	u8 tmp[32];
-
-	switch (ctx->alg) {
-	case CRYPTO_CIPHER_ALG_RC4:
-		if (plain != crypt)
-			os_memcpy(plain, crypt, len);
-		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
-			 ctx->u.rc4.used_bytes, plain, len);
-		ctx->u.rc4.used_bytes += len;
-		break;
-	case CRYPTO_CIPHER_ALG_AES:
-		if (len % ctx->u.aes.block_size)
-			return -1;
-		blocks = len / ctx->u.aes.block_size;
-		for (i = 0; i < blocks; i++) {
-			os_memcpy(tmp, crypt, ctx->u.aes.block_size);
-			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
-			for (j = 0; j < ctx->u.aes.block_size; j++)
-				plain[j] ^= ctx->u.aes.cbc[j];
-			os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size);
-			plain += ctx->u.aes.block_size;
-			crypt += ctx->u.aes.block_size;
-		}
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		if (len % 8)
-			return -1;
-		blocks = len / 8;
-		for (i = 0; i < blocks; i++) {
-			os_memcpy(tmp, crypt, 8);
-			des3_decrypt(crypt, &ctx->u.des3.key, plain);
-			for (j = 0; j < 8; j++)
-				plain[j] ^= ctx->u.des3.cbc[j];
-			os_memcpy(ctx->u.des3.cbc, tmp, 8);
-			plain += 8;
-			crypt += 8;
-		}
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		if (len % 8)
-			return -1;
-		blocks = len / 8;
-		for (i = 0; i < blocks; i++) {
-			os_memcpy(tmp, crypt, 8);
-			des_block_decrypt(crypt, ctx->u.des.dk, plain);
-			for (j = 0; j < 8; j++)
-				plain[j] ^= ctx->u.des.cbc[j];
-			os_memcpy(ctx->u.des.cbc, tmp, 8);
-			plain += 8;
-			crypt += 8;
-		}
-		break;
-	default:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-	switch (ctx->alg) {
-	case CRYPTO_CIPHER_ALG_AES:
-		aes_encrypt_deinit(ctx->u.aes.ctx_enc);
-		aes_decrypt_deinit(ctx->u.aes.ctx_dec);
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		break;
-	default:
-		break;
-	}
-	os_free(ctx);
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_internal-cipher.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-cipher.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,243 @@
+/*
+ * Crypto wrapper for internal crypto implementation - Cipher wrappers
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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.h"
+#include "aes.h"
+#include "des_i.h"
+
+
+struct crypto_cipher {
+	enum crypto_cipher_alg alg;
+	union {
+		struct {
+			size_t used_bytes;
+			u8 key[16];
+			size_t keylen;
+		} rc4;
+		struct {
+			u8 cbc[32];
+			void *ctx_enc;
+			void *ctx_dec;
+		} aes;
+		struct {
+			struct des3_key_s key;
+			u8 cbc[8];
+		} des3;
+		struct {
+			u32 ek[32];
+			u32 dk[32];
+			u8 cbc[8];
+		} des;
+	} u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (key_len > sizeof(ctx->u.rc4.key)) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.rc4.keylen = key_len;
+		os_memcpy(ctx->u.rc4.key, key, key_len);
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
+		if (ctx->u.aes.ctx_enc == NULL) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
+		if (ctx->u.aes.ctx_dec == NULL) {
+			aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+			os_free(ctx);
+			return NULL;
+		}
+		os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (key_len != 24) {
+			os_free(ctx);
+			return NULL;
+		}
+		des3_key_setup(key, &ctx->u.des3.key);
+		os_memcpy(ctx->u.des3.cbc, iv, 8);
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (key_len != 8) {
+			os_free(ctx);
+			return NULL;
+		}
+		des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
+		os_memcpy(ctx->u.des.cbc, iv, 8);
+		break;
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	size_t i, j, blocks;
+
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (plain != crypt)
+			os_memcpy(crypt, plain, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, crypt, len);
+		ctx->u.rc4.used_bytes += len;
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (len % AES_BLOCK_SIZE)
+			return -1;
+		blocks = len / AES_BLOCK_SIZE;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < AES_BLOCK_SIZE; j++)
+				ctx->u.aes.cbc[j] ^= plain[j];
+			aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
+				    ctx->u.aes.cbc);
+			os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
+			plain += AES_BLOCK_SIZE;
+			crypt += AES_BLOCK_SIZE;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < 8; j++)
+				ctx->u.des3.cbc[j] ^= plain[j];
+			des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
+				     ctx->u.des3.cbc);
+			os_memcpy(crypt, ctx->u.des3.cbc, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < 8; j++)
+				ctx->u.des3.cbc[j] ^= plain[j];
+			des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
+					  ctx->u.des.cbc);
+			os_memcpy(crypt, ctx->u.des.cbc, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	size_t i, j, blocks;
+	u8 tmp[32];
+
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (plain != crypt)
+			os_memcpy(plain, crypt, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, plain, len);
+		ctx->u.rc4.used_bytes += len;
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (len % AES_BLOCK_SIZE)
+			return -1;
+		blocks = len / AES_BLOCK_SIZE;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
+			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
+			for (j = 0; j < AES_BLOCK_SIZE; j++)
+				plain[j] ^= ctx->u.aes.cbc[j];
+			os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
+			plain += AES_BLOCK_SIZE;
+			crypt += AES_BLOCK_SIZE;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, 8);
+			des3_decrypt(crypt, &ctx->u.des3.key, plain);
+			for (j = 0; j < 8; j++)
+				plain[j] ^= ctx->u.des3.cbc[j];
+			os_memcpy(ctx->u.des3.cbc, tmp, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, 8);
+			des_block_decrypt(crypt, ctx->u.des.dk, plain);
+			for (j = 0; j < 8; j++)
+				plain[j] ^= ctx->u.des.cbc[j];
+			os_memcpy(ctx->u.des.cbc, tmp, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+		aes_decrypt_deinit(ctx->u.aes.ctx_dec);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		break;
+	default:
+		break;
+	}
+	os_free(ctx);
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_internal-modexp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,55 +0,0 @@
-/*
- * Crypto wrapper for internal crypto implementation - modexp
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "tls/bignum.h"
-#include "crypto.h"
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
-	int ret = -1;
-
-	bn_base = bignum_init();
-	bn_exp = bignum_init();
-	bn_modulus = bignum_init();
-	bn_result = bignum_init();
-
-	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
-	    bn_result == NULL)
-		goto error;
-
-	if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
-	    bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
-	    bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
-		goto error;
-
-	if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
-		goto error;
-
-	ret = bignum_get_unsigned_bin(bn_result, result, result_len);
-
-error:
-	bignum_deinit(bn_base);
-	bignum_deinit(bn_exp);
-	bignum_deinit(bn_modulus);
-	bignum_deinit(bn_result);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_internal-modexp.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-modexp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,49 @@
+/*
+ * Crypto wrapper for internal crypto implementation - modexp
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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 "tls/bignum.h"
+#include "crypto.h"
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
+	int ret = -1;
+
+	bn_base = bignum_init();
+	bn_exp = bignum_init();
+	bn_modulus = bignum_init();
+	bn_result = bignum_init();
+
+	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+	    bn_result == NULL)
+		goto error;
+
+	if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
+	    bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
+	    bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
+		goto error;
+
+	if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
+		goto error;
+
+	ret = bignum_get_unsigned_bin(bn_result, result, result_len);
+
+error:
+	bignum_deinit(bn_base);
+	bignum_deinit(bn_exp);
+	bignum_deinit(bn_modulus);
+	bignum_deinit(bn_result);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_internal-rsa.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,115 +0,0 @@
-/*
- * Crypto wrapper for internal crypto implementation - RSA parts
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "tls/rsa.h"
-#include "tls/bignum.h"
-#include "tls/pkcs1.h"
-#include "tls/pkcs8.h"
-
-/* Dummy structures; these are just typecast to struct crypto_rsa_key */
-struct crypto_public_key;
-struct crypto_private_key;
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
-	return (struct crypto_public_key *)
-		crypto_rsa_import_public_key(key, len);
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
-						      size_t len,
-						      const char *passwd)
-{
-	struct crypto_private_key *res;
-
-	/* First, check for possible PKCS #8 encoding */
-	res = pkcs8_key_import(key, len);
-	if (res)
-		return res;
-
-	if (passwd) {
-		/* Try to parse as encrypted PKCS #8 */
-		res = pkcs8_enc_key_import(key, len, passwd);
-		if (res)
-			return res;
-	}
-
-	/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
-	wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
-		   "key");
-	return (struct crypto_private_key *)
-		crypto_rsa_import_private_key(key, len);
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
-						       size_t len)
-{
-	/* No X.509 support in crypto_internal.c */
-	return NULL;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
-					const u8 *in, size_t inlen,
-					u8 *out, size_t *outlen)
-{
-	return pkcs1_encrypt(2, (struct crypto_rsa_key *) key,
-			     0, in, inlen, out, outlen);
-}
-
-
-int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
-					 const u8 *in, size_t inlen,
-					 u8 *out, size_t *outlen)
-{
-	return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key,
-					     in, inlen, out, outlen);
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen)
-{
-	return pkcs1_encrypt(1, (struct crypto_rsa_key *) key,
-			     1, in, inlen, out, outlen);
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
-	crypto_rsa_free((struct crypto_rsa_key *) key);
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
-	crypto_rsa_free((struct crypto_rsa_key *) key);
-}
-
-
-int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
-				    const u8 *crypt, size_t crypt_len,
-				    u8 *plain, size_t *plain_len)
-{
-	return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key,
-					crypt, crypt_len, plain, plain_len);
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_internal-rsa.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_internal-rsa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,108 @@
+/*
+ * Crypto wrapper for internal crypto implementation - RSA parts
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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.h"
+#include "tls/rsa.h"
+#include "tls/pkcs1.h"
+#include "tls/pkcs8.h"
+
+/* Dummy structures; these are just typecast to struct crypto_rsa_key */
+struct crypto_public_key;
+struct crypto_private_key;
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	return (struct crypto_public_key *)
+		crypto_rsa_import_public_key(key, len);
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	struct crypto_private_key *res;
+
+	/* First, check for possible PKCS #8 encoding */
+	res = pkcs8_key_import(key, len);
+	if (res)
+		return res;
+
+	if (passwd) {
+		/* Try to parse as encrypted PKCS #8 */
+		res = pkcs8_enc_key_import(key, len, passwd);
+		if (res)
+			return res;
+	}
+
+	/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
+	wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
+		   "key");
+	return (struct crypto_private_key *)
+		crypto_rsa_import_private_key(key, len);
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	/* No X.509 support in crypto_internal.c */
+	return NULL;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	return pkcs1_encrypt(2, (struct crypto_rsa_key *) key,
+			     0, in, inlen, out, outlen);
+}
+
+
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+					 const u8 *in, size_t inlen,
+					 u8 *out, size_t *outlen)
+{
+	return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key,
+					     in, inlen, out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	return pkcs1_encrypt(1, (struct crypto_rsa_key *) key,
+			     1, in, inlen, out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+				    const u8 *crypt, size_t crypt_len,
+				    u8 *plain, size_t *plain_len)
+{
+	return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key,
+					crypt, crypt_len, plain, plain_len);
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,205 +0,0 @@
-/*
- * Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "sha1_i.h"
-#include "md5_i.h"
-
-struct crypto_hash {
-	enum crypto_hash_alg alg;
-	union {
-		struct MD5Context md5;
-		struct SHA1Context sha1;
-	} u;
-	u8 key[64];
-	size_t key_len;
-};
-
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
-				      size_t key_len)
-{
-	struct crypto_hash *ctx;
-	u8 k_pad[64];
-	u8 tk[20];
-	size_t i;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	ctx->alg = alg;
-
-	switch (alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		MD5Init(&ctx->u.md5);
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		SHA1Init(&ctx->u.sha1);
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-		if (key_len > sizeof(k_pad)) {
-			MD5Init(&ctx->u.md5);
-			MD5Update(&ctx->u.md5, key, key_len);
-			MD5Final(tk, &ctx->u.md5);
-			key = tk;
-			key_len = 16;
-		}
-		os_memcpy(ctx->key, key, key_len);
-		ctx->key_len = key_len;
-
-		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
-		for (i = 0; i < sizeof(k_pad); i++)
-			k_pad[i] ^= 0x36;
-		MD5Init(&ctx->u.md5);
-		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
-		break;
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		if (key_len > sizeof(k_pad)) {
-			SHA1Init(&ctx->u.sha1);
-			SHA1Update(&ctx->u.sha1, key, key_len);
-			SHA1Final(tk, &ctx->u.sha1);
-			key = tk;
-			key_len = 20;
-		}
-		os_memcpy(ctx->key, key, key_len);
-		ctx->key_len = key_len;
-
-		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
-		for (i = 0; i < sizeof(k_pad); i++)
-			k_pad[i] ^= 0x36;
-		SHA1Init(&ctx->u.sha1);
-		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
-		break;
-	default:
-		os_free(ctx);
-		return NULL;
-	}
-
-	return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
-	if (ctx == NULL)
-		return;
-
-	switch (ctx->alg) {
-	case CRYPTO_HASH_ALG_MD5:
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-		MD5Update(&ctx->u.md5, data, len);
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		SHA1Update(&ctx->u.sha1, data, len);
-		break;
-	}
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
-	u8 k_pad[64];
-	size_t i;
-
-	if (ctx == NULL)
-		return -2;
-
-	if (mac == NULL || len == NULL) {
-		os_free(ctx);
-		return 0;
-	}
-
-	switch (ctx->alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		if (*len < 16) {
-			*len = 16;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 16;
-		MD5Final(mac, &ctx->u.md5);
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		if (*len < 20) {
-			*len = 20;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 20;
-		SHA1Final(mac, &ctx->u.sha1);
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-		if (*len < 16) {
-			*len = 16;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 16;
-
-		MD5Final(mac, &ctx->u.md5);
-
-		os_memcpy(k_pad, ctx->key, ctx->key_len);
-		os_memset(k_pad + ctx->key_len, 0,
-			  sizeof(k_pad) - ctx->key_len);
-		for (i = 0; i < sizeof(k_pad); i++)
-			k_pad[i] ^= 0x5c;
-		MD5Init(&ctx->u.md5);
-		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
-		MD5Update(&ctx->u.md5, mac, 16);
-		MD5Final(mac, &ctx->u.md5);
-		break;
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		if (*len < 20) {
-			*len = 20;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 20;
-
-		SHA1Final(mac, &ctx->u.sha1);
-
-		os_memcpy(k_pad, ctx->key, ctx->key_len);
-		os_memset(k_pad + ctx->key_len, 0,
-			  sizeof(k_pad) - ctx->key_len);
-		for (i = 0; i < sizeof(k_pad); i++)
-			k_pad[i] ^= 0x5c;
-		SHA1Init(&ctx->u.sha1);
-		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
-		SHA1Update(&ctx->u.sha1, mac, 20);
-		SHA1Final(mac, &ctx->u.sha1);
-		break;
-	}
-
-	os_free(ctx);
-
-	return 0;
-}
-
-
-int crypto_global_init(void)
-{
-	return 0;
-}
-
-
-void crypto_global_deinit(void)
-{
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_internal.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,275 @@
+/*
+ * Crypto wrapper for internal crypto implementation
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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.h"
+#include "sha256_i.h"
+#include "sha1_i.h"
+#include "md5_i.h"
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	union {
+		struct MD5Context md5;
+		struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+		struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
+	} u;
+	u8 key[64];
+	size_t key_len;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	u8 k_pad[64];
+	u8 tk[32];
+	size_t i;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		MD5Init(&ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		SHA1Init(&ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		sha256_init(&ctx->u.sha256);
+		break;
+#endif /* CONFIG_SHA256 */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (key_len > sizeof(k_pad)) {
+			MD5Init(&ctx->u.md5);
+			MD5Update(&ctx->u.md5, key, key_len);
+			MD5Final(tk, &ctx->u.md5);
+			key = tk;
+			key_len = 16;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		MD5Init(&ctx->u.md5);
+		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (key_len > sizeof(k_pad)) {
+			SHA1Init(&ctx->u.sha1);
+			SHA1Update(&ctx->u.sha1, key, key_len);
+			SHA1Final(tk, &ctx->u.sha1);
+			key = tk;
+			key_len = 20;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		SHA1Init(&ctx->u.sha1);
+		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (key_len > sizeof(k_pad)) {
+			sha256_init(&ctx->u.sha256);
+			sha256_process(&ctx->u.sha256, key, key_len);
+			sha256_done(&ctx->u.sha256, tk);
+			key = tk;
+			key_len = 32;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return;
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		MD5Update(&ctx->u.md5, data, len);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		SHA1Update(&ctx->u.sha1, data, len);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		sha256_process(&ctx->u.sha256, data, len);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		break;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	u8 k_pad[64];
+	size_t i;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+		MD5Final(mac, &ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+		SHA1Final(mac, &ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+
+		MD5Final(mac, &ctx->u.md5);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		MD5Init(&ctx->u.md5);
+		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+		MD5Update(&ctx->u.md5, mac, 16);
+		MD5Final(mac, &ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+
+		SHA1Final(mac, &ctx->u.sha1);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		SHA1Init(&ctx->u.sha1);
+		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+		SHA1Update(&ctx->u.sha1, mac, 20);
+		SHA1Final(mac, &ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+
+		sha256_done(&ctx->u.sha256, mac);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		sha256_process(&ctx->u.sha256, mac, 32);
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return -1;
+	}
+
+	os_free(ctx);
+
+	return 0;
+}
+
+
+int crypto_global_init(void)
+{
+	return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_libtomcrypt.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,732 +0,0 @@
-/*
- * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <tomcrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef mp_init_multi
-#define mp_init_multi                ltc_init_multi
-#define mp_clear_multi               ltc_deinit_multi
-#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
-#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
-#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
-#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
-#endif
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	hash_state md;
-	size_t i;
-
-	md4_init(&md);
-	for (i = 0; i < num_elem; i++)
-		md4_process(&md, addr[i], len[i]);
-	md4_done(&md, mac);
-	return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	u8 pkey[8], next, tmp;
-	int i;
-	symmetric_key skey;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	des_setup(pkey, 8, 0, &skey);
-	des_ecb_encrypt(clear, cypher, &skey);
-	des_done(&skey);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	hash_state md;
-	size_t i;
-
-	md5_init(&md);
-	for (i = 0; i < num_elem; i++)
-		md5_process(&md, addr[i], len[i]);
-	md5_done(&md, mac);
-	return 0;
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	hash_state md;
-	size_t i;
-
-	sha1_init(&md);
-	for (i = 0; i < num_elem; i++)
-		sha1_process(&md, addr[i], len[i]);
-	sha1_done(&md, mac);
-	return 0;
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	symmetric_key *skey;
-	skey = os_malloc(sizeof(*skey));
-	if (skey == NULL)
-		return NULL;
-	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
-		os_free(skey);
-		return NULL;
-	}
-	return skey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	symmetric_key *skey = ctx;
-	aes_ecb_encrypt(plain, crypt, skey);
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	symmetric_key *skey = ctx;
-	aes_done(skey);
-	os_free(skey);
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	symmetric_key *skey;
-	skey = os_malloc(sizeof(*skey));
-	if (skey == NULL)
-		return NULL;
-	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
-		os_free(skey);
-		return NULL;
-	}
-	return skey;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	symmetric_key *skey = ctx;
-	aes_ecb_encrypt(plain, (u8 *) crypt, skey);
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	symmetric_key *skey = ctx;
-	aes_done(skey);
-	os_free(skey);
-}
-
-
-struct crypto_hash {
-	enum crypto_hash_alg alg;
-	int error;
-	union {
-		hash_state md;
-		hmac_state hmac;
-	} u;
-};
-
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
-				      size_t key_len)
-{
-	struct crypto_hash *ctx;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	ctx->alg = alg;
-
-	switch (alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		if (md5_init(&ctx->u.md) != CRYPT_OK)
-			goto fail;
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		if (sha1_init(&ctx->u.md) != CRYPT_OK)
-			goto fail;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
-		    CRYPT_OK)
-			goto fail;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
-		    CRYPT_OK)
-			goto fail;
-		break;
-	default:
-		goto fail;
-	}
-
-	return ctx;
-
-fail:
-	os_free(ctx);
-	return NULL;
-}
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
-	if (ctx == NULL || ctx->error)
-		return;
-
-	switch (ctx->alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
-		break;
-	}
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
-	int ret = 0;
-	unsigned long clen;
-
-	if (ctx == NULL)
-		return -2;
-
-	if (mac == NULL || len == NULL) {
-		os_free(ctx);
-		return 0;
-	}
-
-	if (ctx->error) {
-		os_free(ctx);
-		return -2;
-	}
-
-	switch (ctx->alg) {
-	case CRYPTO_HASH_ALG_MD5:
-		if (*len < 16) {
-			*len = 16;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 16;
-		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
-			ret = -2;
-		break;
-	case CRYPTO_HASH_ALG_SHA1:
-		if (*len < 20) {
-			*len = 20;
-			os_free(ctx);
-			return -1;
-		}
-		*len = 20;
-		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
-			ret = -2;
-		break;
-	case CRYPTO_HASH_ALG_HMAC_SHA1:
-		if (*len < 20) {
-			*len = 20;
-			os_free(ctx);
-			return -1;
-		}
-		/* continue */
-	case CRYPTO_HASH_ALG_HMAC_MD5:
-		if (*len < 16) {
-			*len = 16;
-			os_free(ctx);
-			return -1;
-		}
-		clen = *len;
-		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
-			os_free(ctx);
-			return -1;
-		}
-		*len = clen;
-		break;
-	default:
-		ret = -2;
-		break;
-	}
-
-	os_free(ctx);
-
-	return ret;
-}
-
-
-struct crypto_cipher {
-	int rc4;
-	union {
-		symmetric_CBC cbc;
-		struct {
-			size_t used_bytes;
-			u8 key[16];
-			size_t keylen;
-		} rc4;
-	} u;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{	
-	struct crypto_cipher *ctx;
-	int idx, res, rc4 = 0;
-
-	switch (alg) {
-	case CRYPTO_CIPHER_ALG_AES:
-		idx = find_cipher("aes");
-		break;
-	case CRYPTO_CIPHER_ALG_3DES:
-		idx = find_cipher("3des");
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		idx = find_cipher("des");
-		break;
-	case CRYPTO_CIPHER_ALG_RC2:
-		idx = find_cipher("rc2");
-		break;
-	case CRYPTO_CIPHER_ALG_RC4:
-		idx = -1;
-		rc4 = 1;
-		break;
-	default:
-		return NULL;
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	if (rc4) {
-		ctx->rc4 = 1;
-		if (key_len > sizeof(ctx->u.rc4.key)) {
-			os_free(ctx);
-			return NULL;
-		}
-		ctx->u.rc4.keylen = key_len;
-		os_memcpy(ctx->u.rc4.key, key, key_len);
-	} else {
-		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
-		if (res != CRYPT_OK) {
-			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
-				   "failed: %s", error_to_string(res));
-			os_free(ctx);
-			return NULL;
-		}
-	}
-
-	return ctx;
-}
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	int res;
-
-	if (ctx->rc4) {
-		if (plain != crypt)
-			os_memcpy(crypt, plain, len);
-		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
-			 ctx->u.rc4.used_bytes, crypt, len);
-		ctx->u.rc4.used_bytes += len;
-		return 0;
-	}
-
-	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
-			   "failed: %s", error_to_string(res));
-		return -1;
-	}
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	int res;
-
-	if (ctx->rc4) {
-		if (plain != crypt)
-			os_memcpy(plain, crypt, len);
-		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
-			 ctx->u.rc4.used_bytes, plain, len);
-		ctx->u.rc4.used_bytes += len;
-		return 0;
-	}
-
-	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
-			   "failed: %s", error_to_string(res));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-	if (!ctx->rc4)
-		cbc_done(&ctx->u.cbc);
-	os_free(ctx);
-}
-
-
-struct crypto_public_key {
-	rsa_key rsa;
-};
-
-struct crypto_private_key {
-	rsa_key rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
-	int res;
-	struct crypto_public_key *pk;
-
-	pk = os_zalloc(sizeof(*pk));
-	if (pk == NULL)
-		return NULL;
-
-	res = rsa_import(key, len, &pk->rsa);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
-			   "public key (res=%d '%s')",
-			   res, error_to_string(res));
-		os_free(pk);
-		return NULL;
-	}
-
-	if (pk->rsa.type != PK_PUBLIC) {
-		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
-			   "correct type");
-		rsa_free(&pk->rsa);
-		os_free(pk);
-		return NULL;
-	}
-
-	return pk;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
-						      size_t len,
-						      const char *passwd)
-{
-	int res;
-	struct crypto_private_key *pk;
-
-	pk = os_zalloc(sizeof(*pk));
-	if (pk == NULL)
-		return NULL;
-
-	res = rsa_import(key, len, &pk->rsa);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
-			   "private key (res=%d '%s')",
-			   res, error_to_string(res));
-		os_free(pk);
-		return NULL;
-	}
-
-	if (pk->rsa.type != PK_PRIVATE) {
-		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
-			   "correct type");
-		rsa_free(&pk->rsa);
-		os_free(pk);
-		return NULL;
-	}
-
-	return pk;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
-						       size_t len)
-{
-	/* No X.509 support in LibTomCrypt */
-	return NULL;
-}
-
-
-static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
-					   const u8 *in, size_t inlen,
-					   u8 *out, size_t *outlen)
-{
-	size_t ps_len;
-	u8 *pos;
-
-	/*
-	 * PKCS #1 v1.5, 8.1:
-	 *
-	 * EB = 00 || BT || PS || 00 || D
-	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
-	 * PS = k-3-||D||; at least eight octets
-	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
-	 * k = length of modulus in octets (modlen)
-	 */
-
-	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
-		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
-			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
-			   __func__, (unsigned long) modlen,
-			   (unsigned long) *outlen,
-			   (unsigned long) inlen);
-		return -1;
-	}
-
-	pos = out;
-	*pos++ = 0x00;
-	*pos++ = block_type; /* BT */
-	ps_len = modlen - inlen - 3;
-	switch (block_type) {
-	case 0:
-		os_memset(pos, 0x00, ps_len);
-		pos += ps_len;
-		break;
-	case 1:
-		os_memset(pos, 0xff, ps_len);
-		pos += ps_len;
-		break;
-	case 2:
-		if (os_get_random(pos, ps_len) < 0) {
-			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
-				   "random data for PS", __func__);
-			return -1;
-		}
-		while (ps_len--) {
-			if (*pos == 0x00)
-				*pos = 0x01;
-			pos++;
-		}
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
-			   "%d", __func__, block_type);
-		return -1;
-	}
-	*pos++ = 0x00;
-	os_memcpy(pos, in, inlen); /* D */
-
-	return 0;
-}
-
-
-static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
-				    const u8 *in, size_t inlen,
-				    u8 *out, size_t *outlen)
-{
-	unsigned long len, modlen;
-	int res;
-
-	modlen = mp_unsigned_bin_size(key->N);
-
-	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
-					    out, outlen) < 0)
-		return -1;
-
-	len = *outlen;
-	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
-			   error_to_string(res));
-		return -1;
-	}
-	*outlen = len;
-
-	return 0;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
-					const u8 *in, size_t inlen,
-					u8 *out, size_t *outlen)
-{
-	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
-					out, outlen);
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen)
-{
-	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
-					out, outlen);
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
-	if (key) {
-		rsa_free(&key->rsa);
-		os_free(key);
-	}
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
-	if (key) {
-		rsa_free(&key->rsa);
-		os_free(key);
-	}
-}
-
-
-int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
-				    const u8 *crypt, size_t crypt_len,
-				    u8 *plain, size_t *plain_len)
-{
-	int res;
-	unsigned long len;
-	u8 *pos;
-
-	len = *plain_len;
-	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
-			  &key->rsa);
-	if (res != CRYPT_OK) {
-		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
-			   error_to_string(res));
-		return -1;
-	}
-
-	/*
-	 * PKCS #1 v1.5, 8.1:
-	 *
-	 * EB = 00 || BT || PS || 00 || D
-	 * BT = 01
-	 * PS = k-3-||D|| times FF
-	 * k = length of modulus in octets
-	 */
-
-	if (len < 3 + 8 + 16 /* min hash len */ ||
-	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
-		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
-			   "structure");
-		return -1;
-	}
-
-	pos = plain + 3;
-	while (pos < plain + len && *pos == 0xff)
-		pos++;
-	if (pos - plain - 2 < 8) {
-		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
-		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
-			   "padding");
-		return -1;
-	}
-
-	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
-		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
-			   "structure (2)");
-		return -1;
-	}
-	pos++;
-	len -= pos - plain;
-
-	/* Strip PKCS #1 header */
-	os_memmove(plain, pos, len);
-	*plain_len = len;
-
-	return 0;
-}
-
-
-int crypto_global_init(void)
-{
-	ltc_mp = tfm_desc;
-	/* TODO: only register algorithms that are really needed */
-	if (register_hash(&md4_desc) < 0 ||
-	    register_hash(&md5_desc) < 0 ||
-	    register_hash(&sha1_desc) < 0 ||
-	    register_cipher(&aes_desc) < 0 ||
-	    register_cipher(&des_desc) < 0 ||
-	    register_cipher(&des3_desc) < 0) {
-		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
-			   "hash/cipher functions");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-#ifdef CONFIG_MODEXP
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	void *b, *p, *m, *r;
-
-	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
-		return -1;
-
-	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
-	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
-	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
-		goto fail;
-
-	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
-		goto fail;
-
-	*result_len = mp_unsigned_bin_size(r);
-	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
-		goto fail;
-
-	mp_clear_multi(b, p, m, r, NULL);
-	return 0;
-
-fail:
-	mp_clear_multi(b, p, m, r, NULL);
-	return -1;
-}
-
-#endif /* CONFIG_MODEXP */

Copied: vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_libtomcrypt.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_libtomcrypt.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,726 @@
+/*
+ * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <tomcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef mp_init_multi
+#define mp_init_multi                ltc_init_multi
+#define mp_clear_multi               ltc_deinit_multi
+#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
+#endif
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	md4_init(&md);
+	for (i = 0; i < num_elem; i++)
+		md4_process(&md, addr[i], len[i]);
+	md4_done(&md, mac);
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	symmetric_key skey;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	des_setup(pkey, 8, 0, &skey);
+	des_ecb_encrypt(clear, cypher, &skey);
+	des_done(&skey);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	md5_init(&md);
+	for (i = 0; i < num_elem; i++)
+		md5_process(&md, addr[i], len[i]);
+	md5_done(&md, mac);
+	return 0;
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	sha1_init(&md);
+	for (i = 0; i < num_elem; i++)
+		sha1_process(&md, addr[i], len[i]);
+	sha1_done(&md, mac);
+	return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	symmetric_key *skey;
+	skey = os_malloc(sizeof(*skey));
+	if (skey == NULL)
+		return NULL;
+	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+		os_free(skey);
+		return NULL;
+	}
+	return skey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	symmetric_key *skey = ctx;
+	aes_ecb_encrypt(plain, crypt, skey);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	symmetric_key *skey = ctx;
+	aes_done(skey);
+	os_free(skey);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	symmetric_key *skey;
+	skey = os_malloc(sizeof(*skey));
+	if (skey == NULL)
+		return NULL;
+	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+		os_free(skey);
+		return NULL;
+	}
+	return skey;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	symmetric_key *skey = ctx;
+	aes_ecb_encrypt(plain, (u8 *) crypt, skey);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	symmetric_key *skey = ctx;
+	aes_done(skey);
+	os_free(skey);
+}
+
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	int error;
+	union {
+		hash_state md;
+		hmac_state hmac;
+	} u;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (md5_init(&ctx->u.md) != CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (sha1_init(&ctx->u.md) != CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
+		    CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
+		    CRYPT_OK)
+			goto fail;
+		break;
+	default:
+		goto fail;
+	}
+
+	return ctx;
+
+fail:
+	os_free(ctx);
+	return NULL;
+}
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL || ctx->error)
+		return;
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
+		break;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	int ret = 0;
+	unsigned long clen;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	if (ctx->error) {
+		os_free(ctx);
+		return -2;
+	}
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
+			ret = -2;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
+			ret = -2;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		/* continue */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		clen = *len;
+		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
+			os_free(ctx);
+			return -1;
+		}
+		*len = clen;
+		break;
+	default:
+		ret = -2;
+		break;
+	}
+
+	os_free(ctx);
+
+	return ret;
+}
+
+
+struct crypto_cipher {
+	int rc4;
+	union {
+		symmetric_CBC cbc;
+		struct {
+			size_t used_bytes;
+			u8 key[16];
+			size_t keylen;
+		} rc4;
+	} u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{	
+	struct crypto_cipher *ctx;
+	int idx, res, rc4 = 0;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		idx = find_cipher("aes");
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		idx = find_cipher("3des");
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		idx = find_cipher("des");
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		idx = find_cipher("rc2");
+		break;
+	case CRYPTO_CIPHER_ALG_RC4:
+		idx = -1;
+		rc4 = 1;
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	if (rc4) {
+		ctx->rc4 = 1;
+		if (key_len > sizeof(ctx->u.rc4.key)) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.rc4.keylen = key_len;
+		os_memcpy(ctx->u.rc4.key, key, key_len);
+	} else {
+		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
+		if (res != CRYPT_OK) {
+			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
+				   "failed: %s", error_to_string(res));
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	int res;
+
+	if (ctx->rc4) {
+		if (plain != crypt)
+			os_memcpy(crypt, plain, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, crypt, len);
+		ctx->u.rc4.used_bytes += len;
+		return 0;
+	}
+
+	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
+			   "failed: %s", error_to_string(res));
+		return -1;
+	}
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	int res;
+
+	if (ctx->rc4) {
+		if (plain != crypt)
+			os_memcpy(plain, crypt, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, plain, len);
+		ctx->u.rc4.used_bytes += len;
+		return 0;
+	}
+
+	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
+			   "failed: %s", error_to_string(res));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	if (!ctx->rc4)
+		cbc_done(&ctx->u.cbc);
+	os_free(ctx);
+}
+
+
+struct crypto_public_key {
+	rsa_key rsa;
+};
+
+struct crypto_private_key {
+	rsa_key rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	int res;
+	struct crypto_public_key *pk;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	res = rsa_import(key, len, &pk->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+			   "public key (res=%d '%s')",
+			   res, error_to_string(res));
+		os_free(pk);
+		return NULL;
+	}
+
+	if (pk->rsa.type != PK_PUBLIC) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
+			   "correct type");
+		rsa_free(&pk->rsa);
+		os_free(pk);
+		return NULL;
+	}
+
+	return pk;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	int res;
+	struct crypto_private_key *pk;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	res = rsa_import(key, len, &pk->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+			   "private key (res=%d '%s')",
+			   res, error_to_string(res));
+		os_free(pk);
+		return NULL;
+	}
+
+	if (pk->rsa.type != PK_PRIVATE) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
+			   "correct type");
+		rsa_free(&pk->rsa);
+		os_free(pk);
+		return NULL;
+	}
+
+	return pk;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	/* No X.509 support in LibTomCrypt */
+	return NULL;
+}
+
+
+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
+					   const u8 *in, size_t inlen,
+					   u8 *out, size_t *outlen)
+{
+	size_t ps_len;
+	u8 *pos;
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
+	 * PS = k-3-||D||; at least eight octets
+	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
+	 * k = length of modulus in octets (modlen)
+	 */
+
+	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
+			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
+			   __func__, (unsigned long) modlen,
+			   (unsigned long) *outlen,
+			   (unsigned long) inlen);
+		return -1;
+	}
+
+	pos = out;
+	*pos++ = 0x00;
+	*pos++ = block_type; /* BT */
+	ps_len = modlen - inlen - 3;
+	switch (block_type) {
+	case 0:
+		os_memset(pos, 0x00, ps_len);
+		pos += ps_len;
+		break;
+	case 1:
+		os_memset(pos, 0xff, ps_len);
+		pos += ps_len;
+		break;
+	case 2:
+		if (os_get_random(pos, ps_len) < 0) {
+			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
+				   "random data for PS", __func__);
+			return -1;
+		}
+		while (ps_len--) {
+			if (*pos == 0x00)
+				*pos = 0x01;
+			pos++;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
+			   "%d", __func__, block_type);
+		return -1;
+	}
+	*pos++ = 0x00;
+	os_memcpy(pos, in, inlen); /* D */
+
+	return 0;
+}
+
+
+static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
+				    const u8 *in, size_t inlen,
+				    u8 *out, size_t *outlen)
+{
+	unsigned long len, modlen;
+	int res;
+
+	modlen = mp_unsigned_bin_size(key->N);
+
+	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
+					    out, outlen) < 0)
+		return -1;
+
+	len = *outlen;
+	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+			   error_to_string(res));
+		return -1;
+	}
+	*outlen = len;
+
+	return 0;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
+					out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
+					out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	if (key) {
+		rsa_free(&key->rsa);
+		os_free(key);
+	}
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	if (key) {
+		rsa_free(&key->rsa);
+		os_free(key);
+	}
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+				    const u8 *crypt, size_t crypt_len,
+				    u8 *plain, size_t *plain_len)
+{
+	int res;
+	unsigned long len;
+	u8 *pos;
+
+	len = *plain_len;
+	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
+			  &key->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+			   error_to_string(res));
+		return -1;
+	}
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 01
+	 * PS = k-3-||D|| times FF
+	 * k = length of modulus in octets
+	 */
+
+	if (len < 3 + 8 + 16 /* min hash len */ ||
+	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure");
+		return -1;
+	}
+
+	pos = plain + 3;
+	while (pos < plain + len && *pos == 0xff)
+		pos++;
+	if (pos - plain - 2 < 8) {
+		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+			   "padding");
+		return -1;
+	}
+
+	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure (2)");
+		return -1;
+	}
+	pos++;
+	len -= pos - plain;
+
+	/* Strip PKCS #1 header */
+	os_memmove(plain, pos, len);
+	*plain_len = len;
+
+	return 0;
+}
+
+
+int crypto_global_init(void)
+{
+	ltc_mp = tfm_desc;
+	/* TODO: only register algorithms that are really needed */
+	if (register_hash(&md4_desc) < 0 ||
+	    register_hash(&md5_desc) < 0 ||
+	    register_hash(&sha1_desc) < 0 ||
+	    register_cipher(&aes_desc) < 0 ||
+	    register_cipher(&des_desc) < 0 ||
+	    register_cipher(&des3_desc) < 0) {
+		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
+			   "hash/cipher functions");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+#ifdef CONFIG_MODEXP
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	void *b, *p, *m, *r;
+
+	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
+		return -1;
+
+	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
+	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
+	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
+		goto fail;
+
+	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
+		goto fail;
+
+	*result_len = mp_unsigned_bin_size(r);
+	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
+		goto fail;
+
+	mp_clear_multi(b, p, m, r, NULL);
+	return 0;
+
+fail:
+	mp_clear_multi(b, p, m, r, NULL);
+	return -1;
+}
+
+#endif /* CONFIG_MODEXP */

Deleted: vendor/wpa/2.0/src/crypto/crypto_none.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,29 +0,0 @@
-/*
- * WPA Supplicant / Empty template functions for crypto wrapper
- * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_none.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_none.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * WPA Supplicant / Empty template functions for crypto wrapper
+ * Copyright (c) 2005, Jouni Malinen <j at 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.h"
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_nss.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_nss.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,213 +0,0 @@
-/*
- * Crypto wrapper functions for NSS
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prtime.h>
-#include <nspr/prinrval.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nss/sechash.h>
-#include <nss/pk11pub.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-static int nss_hash(HASH_HashType type, unsigned int max_res_len,
-		    size_t num_elem, const u8 *addr[], const size_t *len,
-		    u8 *mac)
-{
-	HASHContext *ctx;
-	size_t i;
-	unsigned int reslen;
-
-	ctx = HASH_Create(type);
-	if (ctx == NULL)
-		return -1;
-
-	HASH_Begin(ctx);
-	for (i = 0; i < num_elem; i++)
-		HASH_Update(ctx, addr[i], len[i]);
-	HASH_End(ctx, mac, &reslen, max_res_len);
-	HASH_Destroy(ctx);
-
-	return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	PK11Context *ctx = NULL;
-	PK11SlotInfo *slot;
-	SECItem *param = NULL;
-	PK11SymKey *symkey = NULL;
-	SECItem item;
-	int olen;
-	u8 pkey[8], next, tmp;
-	int i;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
-	if (slot == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
-		goto out;
-	}
-
-	item.type = siBuffer;
-	item.data = pkey;
-	item.len = 8;
-	symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
-				   CKA_ENCRYPT, &item, NULL);
-	if (symkey == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
-		goto out;
-	}
-
-	param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
-	if (param == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
-		goto out;
-	}
-
-	ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
-					 symkey, param);
-	if (ctx == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
-			   "CKM_DES_ECB) failed");
-		goto out;
-	}
-
-	if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
-	    SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
-		goto out;
-	}
-
-out:
-	if (ctx)
-		PK11_DestroyContext(ctx, PR_TRUE);
-	if (symkey)
-		PK11_FreeSymKey(symkey);
-	if (param)
-		SECITEM_FreeItem(param, PR_TRUE);
-}
-
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
-	     u8 *data, size_t data_len)
-{
-	return -1;
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
-}
-
-
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
-		  u8 *mac)
-{
-	return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	return NULL;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	return NULL;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	return -1;
-}
-
-
-struct crypto_cipher {
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{
-	return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	return -1;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	return -1;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_nss.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_nss.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_nss.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,207 @@
+/*
+ * Crypto wrapper functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prtime.h>
+#include <nspr/prinrval.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nss/sechash.h>
+#include <nss/pk11pub.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static int nss_hash(HASH_HashType type, unsigned int max_res_len,
+		    size_t num_elem, const u8 *addr[], const size_t *len,
+		    u8 *mac)
+{
+	HASHContext *ctx;
+	size_t i;
+	unsigned int reslen;
+
+	ctx = HASH_Create(type);
+	if (ctx == NULL)
+		return -1;
+
+	HASH_Begin(ctx);
+	for (i = 0; i < num_elem; i++)
+		HASH_Update(ctx, addr[i], len[i]);
+	HASH_End(ctx, mac, &reslen, max_res_len);
+	HASH_Destroy(ctx);
+
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	PK11Context *ctx = NULL;
+	PK11SlotInfo *slot;
+	SECItem *param = NULL;
+	PK11SymKey *symkey = NULL;
+	SECItem item;
+	int olen;
+	u8 pkey[8], next, tmp;
+	int i;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
+	if (slot == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
+		goto out;
+	}
+
+	item.type = siBuffer;
+	item.data = pkey;
+	item.len = 8;
+	symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
+				   CKA_ENCRYPT, &item, NULL);
+	if (symkey == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
+		goto out;
+	}
+
+	param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
+	if (param == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
+		goto out;
+	}
+
+	ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
+					 symkey, param);
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
+			   "CKM_DES_ECB) failed");
+		goto out;
+	}
+
+	if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
+	    SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
+		goto out;
+	}
+
+out:
+	if (ctx)
+		PK11_DestroyContext(ctx, PR_TRUE);
+	if (symkey)
+		PK11_FreeSymKey(symkey);
+	if (param)
+		SECITEM_FreeItem(param, PR_TRUE);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+	return -1;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	return NULL;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	return NULL;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	return -1;
+}
+
+
+struct crypto_cipher {
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+}

Deleted: vendor/wpa/2.0/src/crypto/crypto_openssl.c
===================================================================
--- vendor/wpa/dist/src/crypto/crypto_openssl.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/crypto_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,505 +0,0 @@
-/*
- * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
-#include <openssl/des.h>
-#include <openssl/aes.h>
-#include <openssl/bn.h>
-#include <openssl/evp.h>
-#include <openssl/dh.h>
-
-#include "common.h"
-#include "wpabuf.h"
-#include "dh_group5.h"
-#include "crypto.h"
-
-#if OPENSSL_VERSION_NUMBER < 0x00907000
-#define DES_key_schedule des_key_schedule
-#define DES_cblock des_cblock
-#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
-#define DES_ecb_encrypt(input, output, ks, enc) \
-	des_ecb_encrypt((input), (output), *(ks), (enc))
-#endif /* openssl < 0.9.7 */
-
-static BIGNUM * get_group5_prime(void)
-{
-#if OPENSSL_VERSION_NUMBER < 0x00908000
-	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,
-		0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
-		0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
-		0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
-		0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
-		0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
-		0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
-		0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
-		0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
-		0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
-		0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
-		0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
-		0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
-		0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
-		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 < 0.9.8 */
-	return get_rfc3526_prime_1536(NULL);
-#endif /* openssl < 0.9.8 */
-}
-
-#if OPENSSL_VERSION_NUMBER < 0x00908000
-#ifndef OPENSSL_NO_SHA256
-#ifndef OPENSSL_FIPS
-#define NO_SHA256_WRAPPER
-#endif
-#endif
-
-#endif /* openssl < 0.9.8 */
-
-#ifdef OPENSSL_NO_SHA256
-#define NO_SHA256_WRAPPER
-#endif
-
-static int openssl_digest_vector(const EVP_MD *type, int non_fips,
-				 size_t num_elem, const u8 *addr[],
-				 const size_t *len, u8 *mac)
-{
-	EVP_MD_CTX ctx;
-	size_t i;
-	unsigned int mac_len;
-
-	EVP_MD_CTX_init(&ctx);
-#ifdef CONFIG_FIPS
-#ifdef OPENSSL_FIPS
-	if (non_fips)
-		EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif /* OPENSSL_FIPS */
-#endif /* CONFIG_FIPS */
-	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
-		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		return -1;
-	}
-	for (i = 0; i < num_elem; 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));
-			return -1;
-		}
-	}
-	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
-		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
-			   ERR_error_string(ERR_get_error(), NULL));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	u8 pkey[8], next, tmp;
-	int i;
-	DES_key_schedule ks;
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	DES_set_key(&pkey, &ks);
-	DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
-			DES_ENCRYPT);
-}
-
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
-	     u8 *data, size_t data_len)
-{
-#ifdef OPENSSL_NO_RC4
-	return -1;
-#else /* OPENSSL_NO_RC4 */
-	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))
-		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))
-			goto out;
-		skip -= len;
-	}
-
-	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
-		res = 0;
-
-out:
-	EVP_CIPHER_CTX_cleanup(&ctx);
-	return res;
-#endif /* OPENSSL_NO_RC4 */
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
-}
-
-
-#ifdef CONFIG_FIPS
-int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
-			      const size_t *len, u8 *mac)
-{
-	return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
-}
-#endif /* CONFIG_FIPS */
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
-}
-
-
-#ifndef NO_SHA256_WRAPPER
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
-		  u8 *mac)
-{
-	return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
-				     mac);
-}
-#endif /* NO_SHA256_WRAPPER */
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
-	AES_KEY *ak;
-	ak = os_malloc(sizeof(*ak));
-	if (ak == NULL)
-		return NULL;
-	if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
-		os_free(ak);
-		return NULL;
-	}
-	return ak;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-	AES_encrypt(plain, crypt, ctx);
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-	os_free(ctx);
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
-	AES_KEY *ak;
-	ak = os_malloc(sizeof(*ak));
-	if (ak == NULL)
-		return NULL;
-	if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
-		os_free(ak);
-		return NULL;
-	}
-	return ak;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-	AES_decrypt(crypt, plain, ctx);
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-	os_free(ctx);
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
-		   const u8 *power, size_t power_len,
-		   const u8 *modulus, size_t modulus_len,
-		   u8 *result, size_t *result_len)
-{
-	BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
-	int ret = -1;
-	BN_CTX *ctx;
-
-	ctx = BN_CTX_new();
-	if (ctx == NULL)
-		return -1;
-
-	bn_base = BN_bin2bn(base, base_len, NULL);
-	bn_exp = BN_bin2bn(power, power_len, NULL);
-	bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
-	bn_result = BN_new();
-
-	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
-	    bn_result == NULL)
-		goto error;
-
-	if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
-		goto error;
-
-	*result_len = BN_bn2bin(bn_result, result);
-	ret = 0;
-
-error:
-	BN_free(bn_base);
-	BN_free(bn_exp);
-	BN_free(bn_modulus);
-	BN_free(bn_result);
-	BN_CTX_free(ctx);
-	return ret;
-}
-
-
-struct crypto_cipher {
-	EVP_CIPHER_CTX enc;
-	EVP_CIPHER_CTX dec;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
-					  const u8 *iv, const u8 *key,
-					  size_t key_len)
-{
-	struct crypto_cipher *ctx;
-	const EVP_CIPHER *cipher;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return NULL;
-
-	switch (alg) {
-#ifndef OPENSSL_NO_RC4
-	case CRYPTO_CIPHER_ALG_RC4:
-		cipher = EVP_rc4();
-		break;
-#endif /* OPENSSL_NO_RC4 */
-#ifndef OPENSSL_NO_AES
-	case CRYPTO_CIPHER_ALG_AES:
-		switch (key_len) {
-		case 16:
-			cipher = EVP_aes_128_cbc();
-			break;
-		case 24:
-			cipher = EVP_aes_192_cbc();
-			break;
-		case 32:
-			cipher = EVP_aes_256_cbc();
-			break;
-		default:
-			os_free(ctx);
-			return NULL;
-		}
-		break;
-#endif /* OPENSSL_NO_AES */
-#ifndef OPENSSL_NO_DES
-	case CRYPTO_CIPHER_ALG_3DES:
-		cipher = EVP_des_ede3_cbc();
-		break;
-	case CRYPTO_CIPHER_ALG_DES:
-		cipher = EVP_des_cbc();
-		break;
-#endif /* OPENSSL_NO_DES */
-#ifndef OPENSSL_NO_RC2
-	case CRYPTO_CIPHER_ALG_RC2:
-		cipher = EVP_rc2_ecb();
-		break;
-#endif /* OPENSSL_NO_RC2 */
-	default:
-		os_free(ctx);
-		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);
-		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);
-		os_free(ctx);
-		return NULL;
-	}
-
-	return ctx;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
-			  u8 *crypt, size_t len)
-{
-	int outl;
-	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
-		return -1;
-	return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
-			  u8 *plain, size_t len)
-{
-	int outl;
-	outl = 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);
-	os_free(ctx);
-}
-
-
-void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
-{
-	DH *dh;
-	struct wpabuf *pubkey = NULL, *privkey = NULL;
-	size_t publen, privlen;
-
-	*priv = NULL;
-	*publ = NULL;
-
-	dh = DH_new();
-	if (dh == NULL)
-		return NULL;
-
-	dh->g = BN_new();
-	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
-		goto err;
-
-	dh->p = get_group5_prime();
-	if (dh->p == NULL)
-		goto err;
-
-	if (DH_generate_key(dh) != 1)
-		goto err;
-
-	publen = BN_num_bytes(dh->pub_key);
-	pubkey = wpabuf_alloc(publen);
-	if (pubkey == NULL)
-		goto err;
-	privlen = BN_num_bytes(dh->priv_key);
-	privkey = wpabuf_alloc(privlen);
-	if (privkey == NULL)
-		goto err;
-
-	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
-	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
-
-	*priv = privkey;
-	*publ = pubkey;
-	return dh;
-
-err:
-	wpabuf_free(pubkey);
-	wpabuf_free(privkey);
-	DH_free(dh);
-	return NULL;
-}
-
-
-struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
-				  const struct wpabuf *own_private)
-{
-	BIGNUM *pub_key;
-	struct wpabuf *res = NULL;
-	size_t rlen;
-	DH *dh = ctx;
-	int keylen;
-
-	if (ctx == NULL)
-		return NULL;
-
-	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
-			    NULL);
-	if (pub_key == NULL)
-		return NULL;
-
-	rlen = DH_size(dh);
-	res = wpabuf_alloc(rlen);
-	if (res == NULL)
-		goto err;
-
-	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
-	if (keylen < 0)
-		goto err;
-	wpabuf_put(res, keylen);
-	BN_free(pub_key);
-
-	return res;
-
-err:
-	BN_free(pub_key);
-	wpabuf_free(res);
-	return NULL;
-}
-
-
-void dh5_free(void *ctx)
-{
-	DH *dh;
-	if (ctx == NULL)
-		return;
-	dh = ctx;
-	DH_free(dh);
-}

Copied: vendor/wpa/2.0/src/crypto/crypto_openssl.c (from rev 9639, vendor/wpa/dist/src/crypto/crypto_openssl.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/crypto_openssl.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/crypto_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant / wrapper functions for libcrypto
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/des.h>
+#include <openssl/aes.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#ifdef CONFIG_OPENSSL_CMAC
+#include <openssl/cmac.h>
+#endif /* CONFIG_OPENSSL_CMAC */
+
+#include "common.h"
+#include "wpabuf.h"
+#include "dh_group5.h"
+#include "crypto.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
+#define DES_ecb_encrypt(input, output, ks, enc) \
+	des_ecb_encrypt((input), (output), *(ks), (enc))
+#endif /* openssl < 0.9.7 */
+
+static BIGNUM * get_group5_prime(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	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,
+		0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+		0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+		0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+		0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+		0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+		0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+		0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+		0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+		0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+		0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+		0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+		0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+		0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+		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 < 0.9.8 */
+	return get_rfc3526_prime_1536(NULL);
+#endif /* openssl < 0.9.8 */
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+#ifndef OPENSSL_NO_SHA256
+#ifndef OPENSSL_FIPS
+#define NO_SHA256_WRAPPER
+#endif
+#endif
+
+#endif /* openssl < 0.9.8 */
+
+#ifdef OPENSSL_NO_SHA256
+#define NO_SHA256_WRAPPER
+#endif
+
+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;
+	size_t i;
+	unsigned int mac_len;
+
+	EVP_MD_CTX_init(&ctx);
+	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	for (i = 0; i < num_elem; 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));
+			return -1;
+		}
+	}
+	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	DES_key_schedule ks;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	DES_set_key(&pkey, &ks);
+	DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
+			DES_ENCRYPT);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+#ifdef OPENSSL_NO_RC4
+	return -1;
+#else /* OPENSSL_NO_RC4 */
+	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))
+		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))
+			goto out;
+		skip -= len;
+	}
+
+	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+		res = 0;
+
+out:
+	EVP_CIPHER_CTX_cleanup(&ctx);
+	return res;
+#endif /* OPENSSL_NO_RC4 */
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
+{
+	switch (keylen) {
+	case 16:
+		return EVP_aes_128_ecb();
+	case 24:
+		return EVP_aes_192_ecb();
+	case 32:
+		return EVP_aes_256_ecb();
+	}
+
+	return NULL;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	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;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int clen = 16;
+	if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES encrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(c);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	EVP_CIPHER_CTX_init(ctx);
+	if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int plen = 16;
+	if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES decrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(ctx);
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
+	int ret = -1;
+	BN_CTX *ctx;
+
+	ctx = BN_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	bn_base = BN_bin2bn(base, base_len, NULL);
+	bn_exp = BN_bin2bn(power, power_len, NULL);
+	bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
+	bn_result = BN_new();
+
+	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+	    bn_result == NULL)
+		goto error;
+
+	if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+		goto error;
+
+	*result_len = BN_bn2bin(bn_result, result);
+	ret = 0;
+
+error:
+	BN_free(bn_base);
+	BN_free(bn_exp);
+	BN_free(bn_modulus);
+	BN_free(bn_result);
+	BN_CTX_free(ctx);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	EVP_CIPHER_CTX enc;
+	EVP_CIPHER_CTX dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+	const EVP_CIPHER *cipher;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		cipher = EVP_rc4();
+		break;
+#endif /* OPENSSL_NO_RC4 */
+#ifndef OPENSSL_NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		switch (key_len) {
+		case 16:
+			cipher = EVP_aes_128_cbc();
+			break;
+		case 24:
+			cipher = EVP_aes_192_cbc();
+			break;
+		case 32:
+			cipher = EVP_aes_256_cbc();
+			break;
+		default:
+			os_free(ctx);
+			return NULL;
+		}
+		break;
+#endif /* OPENSSL_NO_AES */
+#ifndef OPENSSL_NO_DES
+	case CRYPTO_CIPHER_ALG_3DES:
+		cipher = EVP_des_ede3_cbc();
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		cipher = EVP_des_cbc();
+		break;
+#endif /* OPENSSL_NO_DES */
+#ifndef OPENSSL_NO_RC2
+	case CRYPTO_CIPHER_ALG_RC2:
+		cipher = EVP_rc2_ecb();
+		break;
+#endif /* OPENSSL_NO_RC2 */
+	default:
+		os_free(ctx);
+		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);
+		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);
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	int outl;
+	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+		return -1;
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	int outl;
+	outl = 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);
+	os_free(ctx);
+}
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	DH *dh;
+	struct wpabuf *pubkey = NULL, *privkey = NULL;
+	size_t publen, privlen;
+
+	*priv = NULL;
+	*publ = NULL;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	publen = BN_num_bytes(dh->pub_key);
+	pubkey = wpabuf_alloc(publen);
+	if (pubkey == NULL)
+		goto err;
+	privlen = BN_num_bytes(dh->priv_key);
+	privkey = wpabuf_alloc(privlen);
+	if (privkey == NULL)
+		goto err;
+
+	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
+	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
+
+	*priv = privkey;
+	*publ = pubkey;
+	return dh;
+
+err:
+	wpabuf_free(pubkey);
+	wpabuf_free(privkey);
+	DH_free(dh);
+	return NULL;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	DH *dh;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+	if (dh->priv_key == NULL)
+		goto err;
+
+	dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+	if (dh->pub_key == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	return dh;
+
+err:
+	DH_free(dh);
+	return NULL;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	BIGNUM *pub_key;
+	struct wpabuf *res = NULL;
+	size_t rlen;
+	DH *dh = ctx;
+	int keylen;
+
+	if (ctx == NULL)
+		return NULL;
+
+	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			    NULL);
+	if (pub_key == NULL)
+		return NULL;
+
+	rlen = DH_size(dh);
+	res = wpabuf_alloc(rlen);
+	if (res == NULL)
+		goto err;
+
+	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
+	if (keylen < 0)
+		goto err;
+	wpabuf_put(res, keylen);
+	BN_free(pub_key);
+
+	return res;
+
+err:
+	BN_free(pub_key);
+	wpabuf_free(res);
+	return NULL;
+}
+
+
+void dh5_free(void *ctx)
+{
+	DH *dh;
+	if (ctx == NULL)
+		return;
+	dh = ctx;
+	DH_free(dh);
+}
+
+
+struct crypto_hash {
+	HMAC_CTX ctx;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	const EVP_MD *md;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_MD5
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		md = EVP_md5();
+		break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		md = EVP_sha1();
+		break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		md = EVP_sha256();
+		break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	HMAC_CTX_init(&ctx->ctx);
+
+#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) {
+		os_free(ctx);
+		return NULL;
+	}
+#endif /* openssl < 0.9.9 */
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return;
+	HMAC_Update(&ctx->ctx, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	unsigned int mdlen;
+	int res;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(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);
+	os_free(ctx);
+
+	if (res == 1) {
+		*len = mdlen;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
+				   (unsigned char *) ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#else /* openssl < 0.9.8 */
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#endif /* openssl < 0.9.8 */
+	return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 20;
+#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);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 32;
+#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);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+int crypto_get_random(void *buf, size_t len)
+{
+	if (RAND_bytes(buf, len) != 1)
+		return -1;
+	return 0;
+}
+
+
+#ifdef CONFIG_OPENSSL_CMAC
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	CMAC_CTX *ctx;
+	int ret = -1;
+	size_t outlen, i;
+
+	ctx = CMAC_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+		goto fail;
+	for (i = 0; i < num_elem; i++) {
+		if (!CMAC_Update(ctx, addr[i], len[i]))
+			goto fail;
+	}
+	if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
+		goto fail;
+
+	ret = 0;
+fail:
+	CMAC_CTX_free(ctx);
+	return ret;
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+#endif /* CONFIG_OPENSSL_CMAC */

Deleted: vendor/wpa/2.0/src/crypto/des-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/des-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/des-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,499 +0,0 @@
-/*
- * DES and 3DES-EDE ciphers
- *
- * Modifications to LibTomCrypt implementation:
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "des_i.h"
-
-/*
- * This implementation is based on a DES implementation included in
- * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
- * coding style.
- */
-
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis at gmail.com, http://libtomcrypt.com
- */
-
-/**
-  DES code submitted by Dobes Vandermeer
-*/
-
-#define ROLc(x, y) \
-	((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
-	  (((unsigned long) (x) & 0xFFFFFFFFUL) >> \
-	   (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
-#define RORc(x, y) \
-	(((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
-	   (unsigned long) ((y) & 31)) | \
-	  ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
-	 0xFFFFFFFFUL)
-
-
-static const u32 bytebit[8] =
-{
-	0200, 0100, 040, 020, 010, 04, 02, 01 
-};
-
-static const u32 bigbyte[24] =
-{
-	0x800000UL,  0x400000UL,  0x200000UL,  0x100000UL,
-	0x80000UL,   0x40000UL,   0x20000UL,   0x10000UL,
-	0x8000UL,    0x4000UL,    0x2000UL,    0x1000UL,
-	0x800UL,     0x400UL,     0x200UL,     0x100UL,
-	0x80UL,      0x40UL,      0x20UL,      0x10UL,
-	0x8UL,       0x4UL,       0x2UL,       0x1L 
-};
-
-/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
-
-static const u8 pc1[56] = {
-	56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  
-	 9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 
-	62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
-	13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3 
-};
-
-static const u8 totrot[16] = {
-	1,   2,  4,  6,
-	8,  10, 12, 14, 
-	15, 17, 19, 21, 
-	23, 25, 27, 28
-};
-
-static const u8 pc2[48] = {
-	13, 16, 10, 23,  0,  4,      2, 27, 14,  5, 20,  9,
-	22, 18, 11,  3, 25,  7,     15,  6, 26, 19, 12,  1,
-	40, 51, 30, 36, 46, 54,     29, 39, 50, 44, 32, 47,
-	43, 48, 38, 55, 33, 52,     45, 41, 49, 35, 28, 31
-};
-
-
-static const u32 SP1[64] =
-{
-	0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
-	0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
-	0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
-	0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
-	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
-	0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
-	0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
-	0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
-	0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
-	0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
-	0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
-	0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
-	0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
-	0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
-	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
-	0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
-};
-
-static const u32 SP2[64] =
-{
-	0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
-	0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
-	0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
-	0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
-	0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
-	0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
-	0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
-	0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
-	0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
-	0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
-	0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
-	0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
-	0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
-	0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
-	0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
-	0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
-};
-
-static const u32 SP3[64] =
-{
-	0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
-	0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
-	0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
-	0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
-	0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
-	0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
-	0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
-	0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
-	0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
-	0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
-	0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
-	0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
-	0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
-	0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
-	0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
-	0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
-};
-
-static const u32 SP4[64] =
-{
-	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
-	0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
-	0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
-	0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
-	0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
-	0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
-	0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
-	0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
-	0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
-	0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
-	0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
-	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
-	0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
-	0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
-	0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
-	0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
-};
-
-static const u32 SP5[64] =
-{
-	0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
-	0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
-	0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
-	0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
-	0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
-	0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
-	0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
-	0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
-	0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
-	0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
-	0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
-	0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
-	0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
-	0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
-	0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
-	0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
-};
-
-static const u32 SP6[64] =
-{
-	0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
-	0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
-	0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
-	0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
-	0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
-	0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
-	0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
-	0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
-	0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
-	0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
-	0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
-	0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
-	0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
-	0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
-	0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
-	0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
-};
-
-static const u32 SP7[64] =
-{
-	0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
-	0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
-	0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
-	0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
-	0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
-	0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
-	0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
-	0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
-	0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
-	0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
-	0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
-	0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
-	0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
-	0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
-	0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
-	0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
-};
-
-static const u32 SP8[64] =
-{
-	0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
-	0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
-	0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
-	0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
-	0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
-	0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
-	0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
-	0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
-	0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
-	0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
-	0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
-	0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
-	0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
-	0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
-	0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
-	0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
-};
-
-
-static void cookey(const u32 *raw1, u32 *keyout)
-{
-	u32 *cook;
-	const u32 *raw0;
-	u32 dough[32];
-	int i;
-
-	cook = dough;
-	for (i = 0; i < 16; i++, raw1++) {
-		raw0 = raw1++;
-		*cook    = (*raw0 & 0x00fc0000L) << 6;
-		*cook   |= (*raw0 & 0x00000fc0L) << 10;
-		*cook   |= (*raw1 & 0x00fc0000L) >> 10;
-		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
-		*cook    = (*raw0 & 0x0003f000L) << 12;
-		*cook   |= (*raw0 & 0x0000003fL) << 16;
-		*cook   |= (*raw1 & 0x0003f000L) >> 4;
-		*cook++ |= (*raw1 & 0x0000003fL);
-	}
-
-	os_memcpy(keyout, dough, sizeof(dough));
-}
-
-
-static void deskey(const u8 *key, int decrypt, u32 *keyout)
-{
-	u32 i, j, l, m, n, kn[32];
-	u8 pc1m[56], pcr[56];
-
-	for (j = 0; j < 56; j++) {
-		l = (u32) pc1[j];
-		m = l & 7;
-		pc1m[j] = (u8)
-			((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
-	}
-
-	for (i = 0; i < 16; i++) {
-		if (decrypt)
-			m = (15 - i) << 1;
-		else
-			m = i << 1;
-		n = m + 1;
-		kn[m] = kn[n] = 0L;
-		for (j = 0; j < 28; j++) {
-			l = j + (u32) totrot[i];
-			if (l < 28)
-				pcr[j] = pc1m[l];
-			else
-				pcr[j] = pc1m[l - 28];
-		}
-		for (/* j = 28 */; j < 56; j++) {
-			l = j + (u32) totrot[i];
-			if (l < 56)
-				pcr[j] = pc1m[l];
-			else
-				pcr[j] = pc1m[l - 28];
-		}
-		for (j = 0; j < 24; j++) {
-			if ((int) pcr[(int) pc2[j]] != 0)
-				kn[m] |= bigbyte[j];
-			if ((int) pcr[(int) pc2[j + 24]] != 0)
-				kn[n] |= bigbyte[j];
-		}
-	}
-
-	cookey(kn, keyout);
-}
-
-
-static void desfunc(u32 *block, const u32 *keys)
-{
-	u32 work, right, leftt;
-	int cur_round;
-
-	leftt = block[0];
-	right = block[1];
-
-	work = ((leftt >> 4)  ^ right) & 0x0f0f0f0fL;
-	right ^= work;
-	leftt ^= (work << 4);
-
-	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
-	right ^= work;
-	leftt ^= (work << 16);
-
-	work = ((right >> 2)  ^ leftt) & 0x33333333L;
-	leftt ^= work;
-	right ^= (work << 2);
-
-	work = ((right >> 8)  ^ leftt) & 0x00ff00ffL;
-	leftt ^= work;
-	right ^= (work << 8);
-
-	right = ROLc(right, 1);
-	work = (leftt ^ right) & 0xaaaaaaaaL;
-
-	leftt ^= work;
-	right ^= work;
-	leftt = ROLc(leftt, 1);
-
-	for (cur_round = 0; cur_round < 8; cur_round++) {
-		work  = RORc(right, 4) ^ *keys++;
-		leftt ^= SP7[work        & 0x3fL]
-			^ SP5[(work >>  8) & 0x3fL]
-			^ SP3[(work >> 16) & 0x3fL]
-			^ SP1[(work >> 24) & 0x3fL];
-		work  = right ^ *keys++;
-		leftt ^= SP8[ work        & 0x3fL]
-			^  SP6[(work >>  8) & 0x3fL]
-			^  SP4[(work >> 16) & 0x3fL]
-			^  SP2[(work >> 24) & 0x3fL];
-
-		work = RORc(leftt, 4) ^ *keys++;
-		right ^= SP7[ work        & 0x3fL]
-			^  SP5[(work >>  8) & 0x3fL]
-			^  SP3[(work >> 16) & 0x3fL]
-			^  SP1[(work >> 24) & 0x3fL];
-		work  = leftt ^ *keys++;
-		right ^= SP8[ work        & 0x3fL]
-			^  SP6[(work >>  8) & 0x3fL]
-			^  SP4[(work >> 16) & 0x3fL]
-			^  SP2[(work >> 24) & 0x3fL];
-	}
-
-	right = RORc(right, 1);
-	work = (leftt ^ right) & 0xaaaaaaaaL;
-	leftt ^= work;
-	right ^= work;
-	leftt = RORc(leftt, 1);
-	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
-	right ^= work;
-	leftt ^= (work << 8);
-	/* -- */
-	work = ((leftt >> 2) ^ right) & 0x33333333L;
-	right ^= work;
-	leftt ^= (work << 2);
-	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
-	leftt ^= work;
-	right ^= (work << 16);
-	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
-	leftt ^= work;
-	right ^= (work << 4);
-
-	block[0] = right;
-	block[1] = leftt;
-}
-
-
-/* wpa_supplicant/hostapd specific wrapper */
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
-	u8 pkey[8], next, tmp;
-	int i;
-	u32 ek[32], work[2];
-
-	/* Add parity bits to the key */
-	next = 0;
-	for (i = 0; i < 7; i++) {
-		tmp = key[i];
-		pkey[i] = (tmp >> i) | next | 1;
-		next = tmp << (7 - i);
-	}
-	pkey[i] = next | 1;
-
-	deskey(pkey, 0, ek);
-
-	work[0] = WPA_GET_BE32(clear);
-	work[1] = WPA_GET_BE32(clear + 4);
-	desfunc(work, ek);
-	WPA_PUT_BE32(cypher, work[0]);
-	WPA_PUT_BE32(cypher + 4, work[1]);
-
-	os_memset(pkey, 0, sizeof(pkey));
-	os_memset(ek, 0, sizeof(ek));
-}
-
-
-void des_key_setup(const u8 *key, u32 *ek, u32 *dk)
-{
-	deskey(key, 0, ek);
-	deskey(key, 1, dk);
-}
-
-
-void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt)
-{
-	u32 work[2];
-	work[0] = WPA_GET_BE32(plain);
-	work[1] = WPA_GET_BE32(plain + 4);
-	desfunc(work, ek);
-	WPA_PUT_BE32(crypt, work[0]);
-	WPA_PUT_BE32(crypt + 4, work[1]);
-}
-
-
-void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain)
-{
-	u32 work[2];
-	work[0] = WPA_GET_BE32(crypt);
-	work[1] = WPA_GET_BE32(crypt + 4);
-	desfunc(work, dk);
-	WPA_PUT_BE32(plain, work[0]);
-	WPA_PUT_BE32(plain + 4, work[1]);
-}
-
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
-{
-	deskey(key, 0, dkey->ek[0]);
-	deskey(key + 8, 1, dkey->ek[1]);
-	deskey(key + 16, 0, dkey->ek[2]);
-
-	deskey(key, 1, dkey->dk[2]);
-	deskey(key + 8, 0, dkey->dk[1]);
-	deskey(key + 16, 1, dkey->dk[0]);
-}
-
-
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
-{
-	u32 work[2];
-
-	work[0] = WPA_GET_BE32(plain);
-	work[1] = WPA_GET_BE32(plain + 4);
-	desfunc(work, key->ek[0]);
-	desfunc(work, key->ek[1]);
-	desfunc(work, key->ek[2]);
-	WPA_PUT_BE32(crypt, work[0]);
-	WPA_PUT_BE32(crypt + 4, work[1]);
-}
-
-
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
-{
-	u32 work[2];
-
-	work[0] = WPA_GET_BE32(crypt);
-	work[1] = WPA_GET_BE32(crypt + 4);
-	desfunc(work, key->dk[0]);
-	desfunc(work, key->dk[1]);
-	desfunc(work, key->dk[2]);
-	WPA_PUT_BE32(plain, work[0]);
-	WPA_PUT_BE32(plain + 4, work[1]);
-}

Copied: vendor/wpa/2.0/src/crypto/des-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/des-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/des-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/des-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,493 @@
+/*
+ * DES and 3DES-EDE ciphers
+ *
+ * Modifications to LibTomCrypt implementation:
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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.h"
+#include "des_i.h"
+
+/*
+ * This implementation is based on a DES implementation included in
+ * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
+ * coding style.
+ */
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis at gmail.com, http://libtomcrypt.com
+ */
+
+/**
+  DES code submitted by Dobes Vandermeer
+*/
+
+#define ROLc(x, y) \
+	((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
+	  (((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+	   (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) \
+	(((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+	   (unsigned long) ((y) & 31)) | \
+	  ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
+	 0xFFFFFFFFUL)
+
+
+static const u32 bytebit[8] =
+{
+	0200, 0100, 040, 020, 010, 04, 02, 01 
+};
+
+static const u32 bigbyte[24] =
+{
+	0x800000UL,  0x400000UL,  0x200000UL,  0x100000UL,
+	0x80000UL,   0x40000UL,   0x20000UL,   0x10000UL,
+	0x8000UL,    0x4000UL,    0x2000UL,    0x1000UL,
+	0x800UL,     0x400UL,     0x200UL,     0x100UL,
+	0x80UL,      0x40UL,      0x20UL,      0x10UL,
+	0x8UL,       0x4UL,       0x2UL,       0x1L 
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const u8 pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  
+	 9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 
+	62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3 
+};
+
+static const u8 totrot[16] = {
+	1,   2,  4,  6,
+	8,  10, 12, 14, 
+	15, 17, 19, 21, 
+	23, 25, 27, 28
+};
+
+static const u8 pc2[48] = {
+	13, 16, 10, 23,  0,  4,      2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7,     15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54,     29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52,     45, 41, 49, 35, 28, 31
+};
+
+
+static const u32 SP1[64] =
+{
+	0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+	0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+	0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+	0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+	0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+	0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+	0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+	0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+	0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+	0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+	0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+	0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+	0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+	0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const u32 SP2[64] =
+{
+	0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+	0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+	0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+	0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+	0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+	0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+	0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+	0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+	0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+	0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+	0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+	0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+	0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+	0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+	0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+	0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const u32 SP3[64] =
+{
+	0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+	0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+	0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+	0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+	0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+	0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+	0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+	0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+	0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+	0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+	0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+	0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+	0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+	0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+	0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+	0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const u32 SP4[64] =
+{
+	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+	0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+	0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+	0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+	0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+	0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+	0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+	0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+	0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+	0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+	0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+	0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+	0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+	0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+	0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const u32 SP5[64] =
+{
+	0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+	0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+	0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+	0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+	0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+	0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+	0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+	0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+	0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+	0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+	0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+	0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+	0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+	0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+	0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+	0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const u32 SP6[64] =
+{
+	0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+	0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+	0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+	0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+	0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+	0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+	0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+	0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+	0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+	0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+	0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+	0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+	0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+	0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+	0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+	0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const u32 SP7[64] =
+{
+	0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+	0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+	0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+	0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+	0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+	0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+	0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+	0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+	0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+	0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+	0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+	0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+	0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+	0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+	0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+	0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const u32 SP8[64] =
+{
+	0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+	0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+	0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+	0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+	0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+	0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+	0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+	0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+	0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+	0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+	0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+	0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+	0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+	0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+	0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+	0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
+};
+
+
+static void cookey(const u32 *raw1, u32 *keyout)
+{
+	u32 *cook;
+	const u32 *raw0;
+	u32 dough[32];
+	int i;
+
+	cook = dough;
+	for (i = 0; i < 16; i++, raw1++) {
+		raw0 = raw1++;
+		*cook    = (*raw0 & 0x00fc0000L) << 6;
+		*cook   |= (*raw0 & 0x00000fc0L) << 10;
+		*cook   |= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook    = (*raw0 & 0x0003f000L) << 12;
+		*cook   |= (*raw0 & 0x0000003fL) << 16;
+		*cook   |= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+	}
+
+	os_memcpy(keyout, dough, sizeof(dough));
+}
+
+
+static void deskey(const u8 *key, int decrypt, u32 *keyout)
+{
+	u32 i, j, l, m, n, kn[32];
+	u8 pc1m[56], pcr[56];
+
+	for (j = 0; j < 56; j++) {
+		l = (u32) pc1[j];
+		m = l & 7;
+		pc1m[j] = (u8)
+			((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (decrypt)
+			m = (15 - i) << 1;
+		else
+			m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for (j = 0; j < 28; j++) {
+			l = j + (u32) totrot[i];
+			if (l < 28)
+				pcr[j] = pc1m[l];
+			else
+				pcr[j] = pc1m[l - 28];
+		}
+		for (/* j = 28 */; j < 56; j++) {
+			l = j + (u32) totrot[i];
+			if (l < 56)
+				pcr[j] = pc1m[l];
+			else
+				pcr[j] = pc1m[l - 28];
+		}
+		for (j = 0; j < 24; j++) {
+			if ((int) pcr[(int) pc2[j]] != 0)
+				kn[m] |= bigbyte[j];
+			if ((int) pcr[(int) pc2[j + 24]] != 0)
+				kn[n] |= bigbyte[j];
+		}
+	}
+
+	cookey(kn, keyout);
+}
+
+
+static void desfunc(u32 *block, const u32 *keys)
+{
+	u32 work, right, leftt;
+	int cur_round;
+
+	leftt = block[0];
+	right = block[1];
+
+	work = ((leftt >> 4)  ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+
+	work = ((right >> 2)  ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+
+	work = ((right >> 8)  ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+
+	right = ROLc(right, 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+
+	leftt ^= work;
+	right ^= work;
+	leftt = ROLc(leftt, 1);
+
+	for (cur_round = 0; cur_round < 8; cur_round++) {
+		work  = RORc(right, 4) ^ *keys++;
+		leftt ^= SP7[work        & 0x3fL]
+			^ SP5[(work >>  8) & 0x3fL]
+			^ SP3[(work >> 16) & 0x3fL]
+			^ SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		leftt ^= SP8[ work        & 0x3fL]
+			^  SP6[(work >>  8) & 0x3fL]
+			^  SP4[(work >> 16) & 0x3fL]
+			^  SP2[(work >> 24) & 0x3fL];
+
+		work = RORc(leftt, 4) ^ *keys++;
+		right ^= SP7[ work        & 0x3fL]
+			^  SP5[(work >>  8) & 0x3fL]
+			^  SP3[(work >> 16) & 0x3fL]
+			^  SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		right ^= SP8[ work        & 0x3fL]
+			^  SP6[(work >>  8) & 0x3fL]
+			^  SP4[(work >> 16) & 0x3fL]
+			^  SP2[(work >> 24) & 0x3fL];
+	}
+
+	right = RORc(right, 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = RORc(leftt, 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	/* -- */
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+
+	block[0] = right;
+	block[1] = leftt;
+}
+
+
+/* wpa_supplicant/hostapd specific wrapper */
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	u32 ek[32], work[2];
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	deskey(pkey, 0, ek);
+
+	work[0] = WPA_GET_BE32(clear);
+	work[1] = WPA_GET_BE32(clear + 4);
+	desfunc(work, ek);
+	WPA_PUT_BE32(cypher, work[0]);
+	WPA_PUT_BE32(cypher + 4, work[1]);
+
+	os_memset(pkey, 0, sizeof(pkey));
+	os_memset(ek, 0, sizeof(ek));
+}
+
+
+void des_key_setup(const u8 *key, u32 *ek, u32 *dk)
+{
+	deskey(key, 0, ek);
+	deskey(key, 1, dk);
+}
+
+
+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt)
+{
+	u32 work[2];
+	work[0] = WPA_GET_BE32(plain);
+	work[1] = WPA_GET_BE32(plain + 4);
+	desfunc(work, ek);
+	WPA_PUT_BE32(crypt, work[0]);
+	WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain)
+{
+	u32 work[2];
+	work[0] = WPA_GET_BE32(crypt);
+	work[1] = WPA_GET_BE32(crypt + 4);
+	desfunc(work, dk);
+	WPA_PUT_BE32(plain, work[0]);
+	WPA_PUT_BE32(plain + 4, work[1]);
+}
+
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
+{
+	deskey(key, 0, dkey->ek[0]);
+	deskey(key + 8, 1, dkey->ek[1]);
+	deskey(key + 16, 0, dkey->ek[2]);
+
+	deskey(key, 1, dkey->dk[2]);
+	deskey(key + 8, 0, dkey->dk[1]);
+	deskey(key + 16, 1, dkey->dk[0]);
+}
+
+
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
+{
+	u32 work[2];
+
+	work[0] = WPA_GET_BE32(plain);
+	work[1] = WPA_GET_BE32(plain + 4);
+	desfunc(work, key->ek[0]);
+	desfunc(work, key->ek[1]);
+	desfunc(work, key->ek[2]);
+	WPA_PUT_BE32(crypt, work[0]);
+	WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
+{
+	u32 work[2];
+
+	work[0] = WPA_GET_BE32(crypt);
+	work[1] = WPA_GET_BE32(crypt + 4);
+	desfunc(work, key->dk[0]);
+	desfunc(work, key->dk[1]);
+	desfunc(work, key->dk[2]);
+	WPA_PUT_BE32(plain, work[0]);
+	WPA_PUT_BE32(plain + 4, work[1]);
+}

Deleted: vendor/wpa/2.0/src/crypto/des_i.h
===================================================================
--- vendor/wpa/dist/src/crypto/des_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/des_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,31 +0,0 @@
-/*
- * DES and 3DES-EDE ciphers
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DES_I_H
-#define DES_I_H
-
-struct des3_key_s {
-	u32 ek[3][32];
-	u32 dk[3][32];
-};
-
-void des_key_setup(const u8 *key, u32 *ek, u32 *dk);
-void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt);
-void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain);
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
-
-#endif /* DES_I_H */

Copied: vendor/wpa/2.0/src/crypto/des_i.h (from rev 9639, vendor/wpa/dist/src/crypto/des_i.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/des_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/des_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,25 @@
+/*
+ * DES and 3DES-EDE ciphers
+ * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DES_I_H
+#define DES_I_H
+
+struct des3_key_s {
+	u32 ek[3][32];
+	u32 dk[3][32];
+};
+
+void des_key_setup(const u8 *key, u32 *ek, u32 *dk);
+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt);
+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain);
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
+
+#endif /* DES_I_H */

Deleted: vendor/wpa/2.0/src/crypto/dh_group5.c
===================================================================
--- vendor/wpa/dist/src/crypto/dh_group5.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/dh_group5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,40 +0,0 @@
-/*
- * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "dh_groups.h"
-#include "dh_group5.h"
-
-
-void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
-{
-	*publ = dh_init(dh_groups_get(5), priv);
-	if (*publ == 0)
-		return NULL;
-	return (void *) 1;
-}
-
-
-struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
-				  const struct wpabuf *own_private)
-{
-	return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
-}
-
-
-void dh5_free(void *ctx)
-{
-}

Copied: vendor/wpa/2.0/src/crypto/dh_group5.c (from rev 9639, vendor/wpa/dist/src/crypto/dh_group5.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/dh_group5.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/dh_group5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,40 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, 2012, Jouni Malinen <j at 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 "dh_groups.h"
+#include "dh_group5.h"
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	*publ = dh_init(dh_groups_get(5), priv);
+	if (*publ == NULL)
+		return NULL;
+	return (void *) 1;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	return (void *) 1;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
+}
+
+
+void dh5_free(void *ctx)
+{
+}

Deleted: vendor/wpa/2.0/src/crypto/dh_group5.h
===================================================================
--- vendor/wpa/dist/src/crypto/dh_group5.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/dh_group5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,23 +0,0 @@
-/*
- * Diffie-Hellman group 5 operations
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DH_GROUP5_H
-#define DH_GROUP5_H
-
-void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
-struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
-				  const struct wpabuf *own_private);
-void dh5_free(void *ctx);
-
-#endif /* DH_GROUP5_H */

Copied: vendor/wpa/2.0/src/crypto/dh_group5.h (from rev 9639, vendor/wpa/dist/src/crypto/dh_group5.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/dh_group5.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/dh_group5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,18 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DH_GROUP5_H
+#define DH_GROUP5_H
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ);
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private);
+void dh5_free(void *ctx);
+
+#endif /* DH_GROUP5_H */

Deleted: vendor/wpa/2.0/src/crypto/dh_groups.c
===================================================================
--- vendor/wpa/dist/src/crypto/dh_groups.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/dh_groups.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,631 +0,0 @@
-/*
- * Diffie-Hellman groups
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-#include "dh_groups.h"
-
-
-#ifdef ALL_DH_GROUPS
-
-/* RFC 4306, B.1. Group 1 - 768 Bit MODP
- * Generator: 2
- * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
- */
-static const u8 dh_group1_generator[1] = { 0x02 };
-static const u8 dh_group1_prime[96] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
- * Generator: 2
- * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
- */
-static const u8 dh_group2_generator[1] = { 0x02 };
-static const u8 dh_group2_prime[128] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-#endif /* ALL_DH_GROUPS */
-
-/* RFC 3526, 2. Group 5 - 1536 Bit MODP
- * Generator: 2
- * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
- */
-static const u8 dh_group5_generator[1] = { 0x02 };
-static const u8 dh_group5_prime[192] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-#ifdef ALL_DH_GROUPS
-
-/* RFC 3526, 3. Group 14 - 2048 Bit MODP
- * Generator: 2
- * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
- */
-static const u8 dh_group14_generator[1] = { 0x02 };
-static const u8 dh_group14_prime[256] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
-	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
-	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
-	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
-	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
-	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
-	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
-	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
-	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* RFC 3526, 4. Group 15 - 3072 Bit MODP
- * Generator: 2
- * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
- */
-static const u8 dh_group15_generator[1] = { 0x02 };
-static const u8 dh_group15_prime[384] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
-	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
-	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
-	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
-	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
-	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
-	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
-	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
-	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
-	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
-	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
-	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
-	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
-	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
-	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
-	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
-	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
-	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
-	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
-	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
-	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
-	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
-	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
-	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
-	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* RFC 3526, 5. Group 16 - 4096 Bit MODP
- * Generator: 2
- * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
- */
-static const u8 dh_group16_generator[1] = { 0x02 };
-static const u8 dh_group16_prime[512] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
-	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
-	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
-	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
-	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
-	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
-	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
-	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
-	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
-	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
-	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
-	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
-	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
-	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
-	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
-	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
-	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
-	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
-	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
-	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
-	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
-	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
-	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
-	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
-	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
-	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
-	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
-	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
-	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
-	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
-	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
-	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
-	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
-	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
-	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
-	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
-	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
-	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
-	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
-	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
-	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* RFC 3526, 6. Group 17 - 6144 Bit MODP
- * Generator: 2
- * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
- */
-static const u8 dh_group17_generator[1] = { 0x02 };
-static const u8 dh_group17_prime[768] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
-	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
-	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
-	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
-	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
-	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
-	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
-	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
-	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
-	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
-	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
-	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
-	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
-	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
-	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
-	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
-	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
-	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
-	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
-	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
-	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
-	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
-	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
-	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
-	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
-	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
-	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
-	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
-	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
-	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
-	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
-	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
-	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
-	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
-	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
-	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
-	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
-	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
-	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
-	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
-	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
-	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
-	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
-	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
-	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
-	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
-	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
-	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
-	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
-	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
-	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
-	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
-	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
-	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
-	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
-	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
-	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
-	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
-	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
-	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
-	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
-	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
-	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
-	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
-	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
-	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
-	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
-	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
-	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
-	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
-	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
-	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
-	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-/* RFC 3526, 7. Group 18 - 8192 Bit MODP
- * Generator: 2
- * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
- */
-static const u8 dh_group18_generator[1] = { 0x02 };
-static const u8 dh_group18_prime[1024] = {
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
-	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
-	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
-	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
-	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
-	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
-	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
-	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
-	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
-	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
-	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
-	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
-	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
-	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
-	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
-	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
-	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
-	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
-	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
-	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
-	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
-	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
-	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
-	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
-	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
-	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
-	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
-	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
-	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
-	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
-	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
-	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
-	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
-	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
-	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
-	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
-	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
-	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
-	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
-	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
-	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
-	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
-	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
-	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
-	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
-	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
-	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
-	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
-	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
-	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
-	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
-	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
-	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
-	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
-	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
-	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
-	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
-	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
-	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
-	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
-	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
-	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
-	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
-	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
-	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
-	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
-	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
-	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
-	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
-	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
-	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
-	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
-	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
-	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
-	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
-	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
-	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
-	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
-	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
-	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
-	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
-	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
-	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
-	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
-	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
-	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
-	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
-	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
-	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
-	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
-	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
-	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
-	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
-	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
-	0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
-	0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
-	0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
-	0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
-	0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
-	0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
-	0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
-	0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
-	0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
-	0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
-	0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
-	0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
-	0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
-	0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
-	0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
-	0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
-	0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
-	0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
-	0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
-	0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
-	0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
-	0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
-	0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
-	0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
-	0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
-	0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
-	0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
-	0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
-	0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
-	0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
-	0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
-	0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-#endif /* ALL_DH_GROUPS */
-
-
-#define DH_GROUP(id) \
-{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
-dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
-		
-
-static struct dh_group dh_groups[] = {
-	DH_GROUP(5),
-#ifdef ALL_DH_GROUPS
-	DH_GROUP(1),
-	DH_GROUP(2),
-	DH_GROUP(14),
-	DH_GROUP(15),
-	DH_GROUP(16),
-	DH_GROUP(17),
-	DH_GROUP(18)
-#endif /* ALL_DH_GROUPS */
-};
-
-#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
-
-
-const struct dh_group * dh_groups_get(int id)
-{
-	size_t i;
-
-	for (i = 0; i < NUM_DH_GROUPS; i++) {
-		if (dh_groups[i].id == id)
-			return &dh_groups[i];
-	}
-	return NULL;
-}
-
-
-/**
- * dh_init - Initialize Diffie-Hellman handshake
- * @dh: Selected Diffie-Hellman group
- * @priv: Pointer for returning Diffie-Hellman private key
- * Returns: Diffie-Hellman public value
- */
-struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
-{
-	struct wpabuf *pv;
-	size_t pv_len;
-
-	if (dh == NULL)
-		return NULL;
-
-	wpabuf_free(*priv);
-	*priv = wpabuf_alloc(dh->prime_len);
-	if (*priv == NULL)
-		return NULL;
-
-	if (os_get_random(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) {
-		wpabuf_free(*priv);
-		*priv = NULL;
-		return NULL;
-	}
-
-	if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
-		/* Make sure private value is smaller than prime */
-		*(wpabuf_mhead_u8(*priv)) = 0;
-	}
-	wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
-
-	pv_len = dh->prime_len;
-	pv = wpabuf_alloc(pv_len);
-	if (pv == 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_free(pv);
-		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
-		return NULL;
-	}
-	wpabuf_put(pv, pv_len);
-	wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
-
-	return pv;
-}
-
-
-/**
- * dh_derive_shared - Derive shared Diffie-Hellman key
- * @peer_public: Diffie-Hellman public value from peer
- * @own_private: Diffie-Hellman private key from dh_init()
- * @dh: Selected Diffie-Hellman group
- * Returns: Diffie-Hellman shared key
- */
-struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
-				 const struct wpabuf *own_private,
-				 const struct dh_group *dh)
-{
-	struct wpabuf *shared;
-	size_t shared_len;
-
-	if (dh == NULL || peer_public == NULL || own_private == NULL)
-		return NULL;
-
-	shared_len = dh->prime_len;
-	shared = wpabuf_alloc(shared_len);
-	if (shared == NULL)
-		return NULL;
-	if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
-			   wpabuf_head(own_private), wpabuf_len(own_private),
-			   dh->prime, dh->prime_len,
-			   wpabuf_mhead(shared), &shared_len) < 0) {
-		wpabuf_free(shared);
-		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
-		return NULL;
-	}
-	wpabuf_put(shared, shared_len);
-	wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
-
-	return shared;
-}

Copied: vendor/wpa/2.0/src/crypto/dh_groups.c (from rev 9639, vendor/wpa/dist/src/crypto/dh_groups.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/dh_groups.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/dh_groups.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,627 @@
+/*
+ * Diffie-Hellman groups
+ * Copyright (c) 2007, Jouni Malinen <j at 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.h"
+#include "random.h"
+#include "dh_groups.h"
+
+
+#ifdef ALL_DH_GROUPS
+
+/* RFC 4306, B.1. Group 1 - 768 Bit MODP
+ * Generator: 2
+ * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+ */
+static const u8 dh_group1_generator[1] = { 0x02 };
+static const u8 dh_group1_prime[96] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
+ * Generator: 2
+ * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
+ */
+static const u8 dh_group2_generator[1] = { 0x02 };
+static const u8 dh_group2_prime[128] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#endif /* ALL_DH_GROUPS */
+
+/* RFC 3526, 2. Group 5 - 1536 Bit MODP
+ * Generator: 2
+ * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
+ */
+static const u8 dh_group5_generator[1] = { 0x02 };
+static const u8 dh_group5_prime[192] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#ifdef ALL_DH_GROUPS
+
+/* RFC 3526, 3. Group 14 - 2048 Bit MODP
+ * Generator: 2
+ * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+ */
+static const u8 dh_group14_generator[1] = { 0x02 };
+static const u8 dh_group14_prime[256] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 4. Group 15 - 3072 Bit MODP
+ * Generator: 2
+ * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
+ */
+static const u8 dh_group15_generator[1] = { 0x02 };
+static const u8 dh_group15_prime[384] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 5. Group 16 - 4096 Bit MODP
+ * Generator: 2
+ * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
+ */
+static const u8 dh_group16_generator[1] = { 0x02 };
+static const u8 dh_group16_prime[512] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 6. Group 17 - 6144 Bit MODP
+ * Generator: 2
+ * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
+ */
+static const u8 dh_group17_generator[1] = { 0x02 };
+static const u8 dh_group17_prime[768] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
+	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
+	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
+	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
+	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
+	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
+	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
+	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
+	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
+	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
+	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
+	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
+	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
+	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
+	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
+	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
+	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
+	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
+	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
+	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
+	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
+	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
+	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
+	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
+	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
+	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
+	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
+	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
+	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
+	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
+	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
+	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
+	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 7. Group 18 - 8192 Bit MODP
+ * Generator: 2
+ * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
+ */
+static const u8 dh_group18_generator[1] = { 0x02 };
+static const u8 dh_group18_prime[1024] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
+	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
+	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
+	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
+	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
+	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
+	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
+	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
+	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
+	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
+	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
+	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
+	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
+	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
+	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
+	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
+	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
+	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
+	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
+	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
+	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
+	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
+	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
+	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
+	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
+	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
+	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
+	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
+	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
+	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
+	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
+	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
+	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
+	0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
+	0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
+	0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
+	0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
+	0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
+	0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
+	0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
+	0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
+	0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
+	0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
+	0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
+	0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
+	0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
+	0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
+	0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
+	0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
+	0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
+	0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
+	0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
+	0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
+	0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
+	0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
+	0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
+	0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
+	0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
+	0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
+	0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
+	0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
+	0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
+	0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
+	0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
+	0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#endif /* ALL_DH_GROUPS */
+
+
+#define DH_GROUP(id) \
+{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
+		
+
+static struct dh_group dh_groups[] = {
+	DH_GROUP(5),
+#ifdef ALL_DH_GROUPS
+	DH_GROUP(1),
+	DH_GROUP(2),
+	DH_GROUP(14),
+	DH_GROUP(15),
+	DH_GROUP(16),
+	DH_GROUP(17),
+	DH_GROUP(18)
+#endif /* ALL_DH_GROUPS */
+};
+
+#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+
+
+const struct dh_group * dh_groups_get(int id)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_DH_GROUPS; i++) {
+		if (dh_groups[i].id == id)
+			return &dh_groups[i];
+	}
+	return NULL;
+}
+
+
+/**
+ * dh_init - Initialize Diffie-Hellman handshake
+ * @dh: Selected Diffie-Hellman group
+ * @priv: Pointer for returning Diffie-Hellman private key
+ * Returns: Diffie-Hellman public value
+ */
+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
+{
+	struct wpabuf *pv;
+	size_t pv_len;
+
+	if (dh == NULL)
+		return NULL;
+
+	wpabuf_free(*priv);
+	*priv = wpabuf_alloc(dh->prime_len);
+	if (*priv == NULL)
+		return NULL;
+
+	if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
+	{
+		wpabuf_free(*priv);
+		*priv = NULL;
+		return NULL;
+	}
+
+	if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		*(wpabuf_mhead_u8(*priv)) = 0;
+	}
+	wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
+
+	pv_len = dh->prime_len;
+	pv = wpabuf_alloc(pv_len);
+	if (pv == 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_free(pv);
+		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		return NULL;
+	}
+	wpabuf_put(pv, pv_len);
+	wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
+
+	return pv;
+}
+
+
+/**
+ * dh_derive_shared - Derive shared Diffie-Hellman key
+ * @peer_public: Diffie-Hellman public value from peer
+ * @own_private: Diffie-Hellman private key from dh_init()
+ * @dh: Selected Diffie-Hellman group
+ * Returns: Diffie-Hellman shared key
+ */
+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
+				 const struct wpabuf *own_private,
+				 const struct dh_group *dh)
+{
+	struct wpabuf *shared;
+	size_t shared_len;
+
+	if (dh == NULL || peer_public == NULL || own_private == NULL)
+		return NULL;
+
+	shared_len = dh->prime_len;
+	shared = wpabuf_alloc(shared_len);
+	if (shared == NULL)
+		return NULL;
+	if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			   wpabuf_head(own_private), wpabuf_len(own_private),
+			   dh->prime, dh->prime_len,
+			   wpabuf_mhead(shared), &shared_len) < 0) {
+		wpabuf_free(shared);
+		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		return NULL;
+	}
+	wpabuf_put(shared, shared_len);
+	wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
+
+	return shared;
+}

Deleted: vendor/wpa/2.0/src/crypto/dh_groups.h
===================================================================
--- vendor/wpa/dist/src/crypto/dh_groups.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/dh_groups.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,32 +0,0 @@
-/*
- * Diffie-Hellman groups
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DH_GROUPS_H
-#define DH_GROUPS_H
-
-struct dh_group {
-	int id;
-	const u8 *generator;
-	size_t generator_len;
-	const u8 *prime;
-	size_t prime_len;
-};
-
-const struct dh_group * dh_groups_get(int id);
-struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv);
-struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
-				 const struct wpabuf *own_private,
-				 const struct dh_group *dh);
-
-#endif /* DH_GROUPS_H */

Copied: vendor/wpa/2.0/src/crypto/dh_groups.h (from rev 9639, vendor/wpa/dist/src/crypto/dh_groups.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/dh_groups.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/dh_groups.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,26 @@
+/*
+ * Diffie-Hellman groups
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DH_GROUPS_H
+#define DH_GROUPS_H
+
+struct dh_group {
+	int id;
+	const u8 *generator;
+	size_t generator_len;
+	const u8 *prime;
+	size_t prime_len;
+};
+
+const struct dh_group * dh_groups_get(int id);
+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv);
+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
+				 const struct wpabuf *own_private,
+				 const struct dh_group *dh);
+
+#endif /* DH_GROUPS_H */

Deleted: vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c
===================================================================
--- vendor/wpa/dist/src/crypto/fips_prf_cryptoapi.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,25 +0,0 @@
-/*
- * FIPS 186-2 PRF for Microsoft CryptoAPI
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
-	/* FIX: how to do this with CryptoAPI? */
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c (from rev 9639, vendor/wpa/dist/src/crypto/fips_prf_cryptoapi.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/fips_prf_cryptoapi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,19 @@
+/*
+ * FIPS 186-2 PRF for Microsoft CryptoAPI
+ * Copyright (c) 2009, Jouni Malinen <j at 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.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	/* FIX: how to do this with CryptoAPI? */
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c
===================================================================
--- vendor/wpa/dist/src/crypto/fips_prf_gnutls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,26 +0,0 @@
-/*
- * FIPS 186-2 PRF for libgcrypt
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <gcrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
-	/* FIX: how to do this with libgcrypt? */
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c (from rev 9639, vendor/wpa/dist/src/crypto/fips_prf_gnutls.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/fips_prf_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,20 @@
+/*
+ * FIPS 186-2 PRF for libgcrypt
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	/* FIX: how to do this with libgcrypt? */
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/fips_prf_internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/fips_prf_internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/fips_prf_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,74 +0,0 @@
-/*
- * FIPS 186-2 PRF for internal crypto implementation
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "sha1_i.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
-	u8 xkey[64];
-	u32 t[5], _t[5];
-	int i, j, m, k;
-	u8 *xpos = x;
-	u32 carry;
-
-	if (seed_len > sizeof(xkey))
-		seed_len = sizeof(xkey);
-
-	/* FIPS 186-2 + change notice 1 */
-
-	os_memcpy(xkey, seed, seed_len);
-	os_memset(xkey + seed_len, 0, 64 - seed_len);
-	t[0] = 0x67452301;
-	t[1] = 0xEFCDAB89;
-	t[2] = 0x98BADCFE;
-	t[3] = 0x10325476;
-	t[4] = 0xC3D2E1F0;
-
-	m = xlen / 40;
-	for (j = 0; j < m; j++) {
-		/* XSEED_j = 0 */
-		for (i = 0; i < 2; i++) {
-			/* XVAL = (XKEY + XSEED_j) mod 2^b */
-
-			/* w_i = G(t, XVAL) */
-			os_memcpy(_t, t, 20);
-			SHA1Transform(_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);
-
-			/* XKEY = (1 + XKEY + w_i) mod 2^b */
-			carry = 1;
-			for (k = 19; k >= 0; k--) {
-				carry += xkey[k] + xpos[k];
-				xkey[k] = carry & 0xff;
-				carry >>= 8;
-			}
-
-			xpos += SHA1_MAC_LEN;
-		}
-		/* x_j = w_0|w_1 */
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/fips_prf_internal.c (from rev 9639, vendor/wpa/dist/src/crypto/fips_prf_internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/fips_prf_internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/fips_prf_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,69 @@
+/*
+ * FIPS 186-2 PRF for internal crypto implementation
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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 "sha1.h"
+#include "sha1_i.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			SHA1Transform(_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);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += SHA1_MAC_LEN;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/fips_prf_nss.c
===================================================================
--- vendor/wpa/dist/src/crypto/fips_prf_nss.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/fips_prf_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,25 +0,0 @@
-/*
- * FIPS 186-2 PRF for NSS
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <openssl/sha.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/fips_prf_nss.c (from rev 9639, vendor/wpa/dist/src/crypto/fips_prf_nss.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/fips_prf_nss.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/fips_prf_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,19 @@
+/*
+ * FIPS 186-2 PRF for NSS
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/fips_prf_openssl.c
===================================================================
--- vendor/wpa/dist/src/crypto/fips_prf_openssl.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/fips_prf_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,83 +0,0 @@
-/*
- * FIPS 186-2 PRF for libcrypto
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <openssl/sha.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-static void sha1_transform(u8 *state, const u8 data[64])
-{
-	SHA_CTX context;
-	os_memset(&context, 0, sizeof(context));
-	os_memcpy(&context.h0, state, 5 * 4);
-	SHA1_Transform(&context, data);
-	os_memcpy(state, &context.h0, 5 * 4);
-}
-
-
-int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
-{
-	u8 xkey[64];
-	u32 t[5], _t[5];
-	int i, j, m, k;
-	u8 *xpos = x;
-	u32 carry;
-
-	if (seed_len > sizeof(xkey))
-		seed_len = sizeof(xkey);
-
-	/* FIPS 186-2 + change notice 1 */
-
-	os_memcpy(xkey, seed, seed_len);
-	os_memset(xkey + seed_len, 0, 64 - seed_len);
-	t[0] = 0x67452301;
-	t[1] = 0xEFCDAB89;
-	t[2] = 0x98BADCFE;
-	t[3] = 0x10325476;
-	t[4] = 0xC3D2E1F0;
-
-	m = xlen / 40;
-	for (j = 0; j < m; j++) {
-		/* XSEED_j = 0 */
-		for (i = 0; i < 2; i++) {
-			/* XVAL = (XKEY + XSEED_j) mod 2^b */
-
-			/* w_i = G(t, XVAL) */
-			os_memcpy(_t, t, 20);
-			sha1_transform((u8 *) _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);
-
-			/* XKEY = (1 + XKEY + w_i) mod 2^b */
-			carry = 1;
-			for (k = 19; k >= 0; k--) {
-				carry += xkey[k] + xpos[k];
-				xkey[k] = carry & 0xff;
-				carry >>= 8;
-			}
-
-			xpos += 20;
-		}
-		/* x_j = w_0|w_1 */
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/fips_prf_openssl.c (from rev 9639, vendor/wpa/dist/src/crypto/fips_prf_openssl.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/fips_prf_openssl.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/fips_prf_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,78 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u8 *state, const u8 data[64])
+{
+	SHA_CTX context;
+	os_memset(&context, 0, sizeof(context));
+	os_memcpy(&context.h0, state, 5 * 4);
+	SHA1_Transform(&context, data);
+	os_memcpy(state, &context.h0, 5 * 4);
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			sha1_transform((u8 *) _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);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += 20;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/md4-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/md4-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md4-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,278 +0,0 @@
-/*
- * MD4 hash implementation
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-
-#define	MD4_BLOCK_LENGTH		64
-#define	MD4_DIGEST_LENGTH		16
-
-typedef struct MD4Context {
-	u32 state[4];			/* state */
-	u64 count;			/* number of bits, mod 2^64 */
-	u8 buffer[MD4_BLOCK_LENGTH];	/* input buffer */
-} MD4_CTX;
-
-
-static void MD4Init(MD4_CTX *ctx);
-static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
-static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	MD4_CTX ctx;
-	size_t i;
-
-	MD4Init(&ctx);
-	for (i = 0; i < num_elem; i++)
-		MD4Update(&ctx, addr[i], len[i]);
-	MD4Final(mac, &ctx);
-	return 0;
-}
-
-
-/* ===== start - public domain MD4 implementation ===== */
-/*	$OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $	*/
-
-/*
- * This code implements the MD4 message-digest algorithm.
- * The algorithm is due to Ron Rivest.	This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD4Context structure, pass it to MD4Init, call MD4Update as
- * needed on buffers full of bytes, and then call MD4Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-#define	MD4_DIGEST_STRING_LENGTH	(MD4_DIGEST_LENGTH * 2 + 1)
-
-
-static void
-MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
-
-#define PUT_64BIT_LE(cp, value) do {					\
-	(cp)[7] = (value) >> 56;					\
-	(cp)[6] = (value) >> 48;					\
-	(cp)[5] = (value) >> 40;					\
-	(cp)[4] = (value) >> 32;					\
-	(cp)[3] = (value) >> 24;					\
-	(cp)[2] = (value) >> 16;					\
-	(cp)[1] = (value) >> 8;						\
-	(cp)[0] = (value); } while (0)
-
-#define PUT_32BIT_LE(cp, value) do {					\
-	(cp)[3] = (value) >> 24;					\
-	(cp)[2] = (value) >> 16;					\
-	(cp)[1] = (value) >> 8;						\
-	(cp)[0] = (value); } while (0)
-
-static u8 PADDING[MD4_BLOCK_LENGTH] = {
-	0x80, 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, 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
-};
-
-/*
- * Start MD4 accumulation.
- * Set bit count to 0 and buffer to mysterious initialization constants.
- */
-static void MD4Init(MD4_CTX *ctx)
-{
-	ctx->count = 0;
-	ctx->state[0] = 0x67452301;
-	ctx->state[1] = 0xefcdab89;
-	ctx->state[2] = 0x98badcfe;
-	ctx->state[3] = 0x10325476;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
-{
-	size_t have, need;
-
-	/* Check how many bytes we already have and how many more we need. */
-	have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
-	need = MD4_BLOCK_LENGTH - have;
-
-	/* Update bitcount */
-	ctx->count += (u64)len << 3;
-
-	if (len >= need) {
-		if (have != 0) {
-			os_memcpy(ctx->buffer + have, input, need);
-			MD4Transform(ctx->state, ctx->buffer);
-			input += need;
-			len -= need;
-			have = 0;
-		}
-
-		/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
-		while (len >= MD4_BLOCK_LENGTH) {
-			MD4Transform(ctx->state, input);
-			input += MD4_BLOCK_LENGTH;
-			len -= MD4_BLOCK_LENGTH;
-		}
-	}
-
-	/* Handle any remaining bytes of data. */
-	if (len != 0)
-		os_memcpy(ctx->buffer + have, input, len);
-}
-
-/*
- * Pad pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-static void MD4Pad(MD4_CTX *ctx)
-{
-	u8 count[8];
-	size_t padlen;
-
-	/* Convert count to 8 bytes in little endian order. */
-	PUT_64BIT_LE(count, ctx->count);
-
-	/* Pad out to 56 mod 64. */
-	padlen = MD4_BLOCK_LENGTH -
-	    ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
-	if (padlen < 1 + 8)
-		padlen += MD4_BLOCK_LENGTH;
-	MD4Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
-	MD4Update(ctx, count, 8);
-}
-
-/*
- * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
- */
-static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
-{
-	int i;
-
-	MD4Pad(ctx);
-	if (digest != NULL) {
-		for (i = 0; i < 4; i++)
-			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
-		os_memset(ctx, 0, sizeof(*ctx));
-	}
-}
-
-
-/* The three core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
-#define F3(x, y, z) (x ^ y ^ z)
-
-/* This is the central step in the MD4 algorithm. */
-#define MD4STEP(f, w, x, y, z, data, s) \
-	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s) )
-
-/*
- * The core of the MD4 algorithm, this alters an existing MD4 hash to
- * reflect the addition of 16 longwords of new data.  MD4Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void
-MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
-{
-	u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-	os_memcpy(in, block, sizeof(in));
-#else
-	for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
-		in[a] = (u32)(
-		    (u32)(block[a * 4 + 0]) |
-		    (u32)(block[a * 4 + 1]) <<  8 |
-		    (u32)(block[a * 4 + 2]) << 16 |
-		    (u32)(block[a * 4 + 3]) << 24);
-	}
-#endif
-
-	a = state[0];
-	b = state[1];
-	c = state[2];
-	d = state[3];
-
-	MD4STEP(F1, a, b, c, d, in[ 0],  3);
-	MD4STEP(F1, d, a, b, c, in[ 1],  7);
-	MD4STEP(F1, c, d, a, b, in[ 2], 11);
-	MD4STEP(F1, b, c, d, a, in[ 3], 19);
-	MD4STEP(F1, a, b, c, d, in[ 4],  3);
-	MD4STEP(F1, d, a, b, c, in[ 5],  7);
-	MD4STEP(F1, c, d, a, b, in[ 6], 11);
-	MD4STEP(F1, b, c, d, a, in[ 7], 19);
-	MD4STEP(F1, a, b, c, d, in[ 8],  3);
-	MD4STEP(F1, d, a, b, c, in[ 9],  7);
-	MD4STEP(F1, c, d, a, b, in[10], 11);
-	MD4STEP(F1, b, c, d, a, in[11], 19);
-	MD4STEP(F1, a, b, c, d, in[12],  3);
-	MD4STEP(F1, d, a, b, c, in[13],  7);
-	MD4STEP(F1, c, d, a, b, in[14], 11);
-	MD4STEP(F1, b, c, d, a, in[15], 19);
-
-	MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
-	MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
-	MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
-	MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
-	MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
-	MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
-	MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
-	MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
-	MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
-	MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
-	MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999,  9);
-	MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
-	MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
-	MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
-	MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999,  9);
-	MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
-
-	MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
-	MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
-	MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
-	MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
-	MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
-	MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
-	MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
-	MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
-	MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
-	MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
-	MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
-	MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
-	MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
-	MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
-	MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
-	MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
-
-	state[0] += a;
-	state[1] += b;
-	state[2] += c;
-	state[3] += d;
-}
-/* ===== end - public domain MD4 implementation ===== */

Copied: vendor/wpa/2.0/src/crypto/md4-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/md4-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/md4-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/md4-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,272 @@
+/*
+ * MD4 hash implementation
+ * Copyright (c) 2006, Jouni Malinen <j at 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.h"
+
+#define	MD4_BLOCK_LENGTH		64
+#define	MD4_DIGEST_LENGTH		16
+
+typedef struct MD4Context {
+	u32 state[4];			/* state */
+	u64 count;			/* number of bits, mod 2^64 */
+	u8 buffer[MD4_BLOCK_LENGTH];	/* input buffer */
+} MD4_CTX;
+
+
+static void MD4Init(MD4_CTX *ctx);
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	MD4_CTX ctx;
+	size_t i;
+
+	MD4Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		MD4Update(&ctx, addr[i], len[i]);
+	MD4Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain MD4 implementation ===== */
+/*	$OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $	*/
+
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4Context structure, pass it to MD4Init, call MD4Update as
+ * needed on buffers full of bytes, and then call MD4Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#define	MD4_DIGEST_STRING_LENGTH	(MD4_DIGEST_LENGTH * 2 + 1)
+
+
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
+
+#define PUT_64BIT_LE(cp, value) do {					\
+	(cp)[7] = (value) >> 56;					\
+	(cp)[6] = (value) >> 48;					\
+	(cp)[5] = (value) >> 40;					\
+	(cp)[4] = (value) >> 32;					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+static u8 PADDING[MD4_BLOCK_LENGTH] = {
+	0x80, 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, 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
+};
+
+/*
+ * Start MD4 accumulation.
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ */
+static void MD4Init(MD4_CTX *ctx)
+{
+	ctx->count = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	need = MD4_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+	ctx->count += (u64)len << 3;
+
+	if (len >= need) {
+		if (have != 0) {
+			os_memcpy(ctx->buffer + have, input, need);
+			MD4Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD4_BLOCK_LENGTH) {
+			MD4Transform(ctx->state, input);
+			input += MD4_BLOCK_LENGTH;
+			len -= MD4_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		os_memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD4Pad(MD4_CTX *ctx)
+{
+	u8 count[8];
+	size_t padlen;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD4_BLOCK_LENGTH -
+	    ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD4_BLOCK_LENGTH;
+	MD4Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
+	MD4Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
+ */
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
+{
+	int i;
+
+	MD4Pad(ctx);
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+		os_memset(ctx, 0, sizeof(*ctx));
+	}
+}
+
+
+/* The three core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F3(x, y, z) (x ^ y ^ z)
+
+/* This is the central step in the MD4 algorithm. */
+#define MD4STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s) )
+
+/*
+ * The core of the MD4 algorithm, this alters an existing MD4 hash to
+ * reflect the addition of 16 longwords of new data.  MD4Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
+{
+	u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	os_memcpy(in, block, sizeof(in));
+#else
+	for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
+		in[a] = (u32)(
+		    (u32)(block[a * 4 + 0]) |
+		    (u32)(block[a * 4 + 1]) <<  8 |
+		    (u32)(block[a * 4 + 2]) << 16 |
+		    (u32)(block[a * 4 + 3]) << 24);
+	}
+#endif
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD4STEP(F1, a, b, c, d, in[ 0],  3);
+	MD4STEP(F1, d, a, b, c, in[ 1],  7);
+	MD4STEP(F1, c, d, a, b, in[ 2], 11);
+	MD4STEP(F1, b, c, d, a, in[ 3], 19);
+	MD4STEP(F1, a, b, c, d, in[ 4],  3);
+	MD4STEP(F1, d, a, b, c, in[ 5],  7);
+	MD4STEP(F1, c, d, a, b, in[ 6], 11);
+	MD4STEP(F1, b, c, d, a, in[ 7], 19);
+	MD4STEP(F1, a, b, c, d, in[ 8],  3);
+	MD4STEP(F1, d, a, b, c, in[ 9],  7);
+	MD4STEP(F1, c, d, a, b, in[10], 11);
+	MD4STEP(F1, b, c, d, a, in[11], 19);
+	MD4STEP(F1, a, b, c, d, in[12],  3);
+	MD4STEP(F1, d, a, b, c, in[13],  7);
+	MD4STEP(F1, c, d, a, b, in[14], 11);
+	MD4STEP(F1, b, c, d, a, in[15], 19);
+
+	MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
+
+	MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
+/* ===== end - public domain MD4 implementation ===== */

Deleted: vendor/wpa/2.0/src/crypto/md5-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/md5-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md5-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,293 +0,0 @@
-/*
- * MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "md5.h"
-#include "md5_i.h"
-#include "crypto.h"
-
-
-static void MD5Transform(u32 buf[4], u32 const in[16]);
-
-
-typedef struct MD5Context MD5_CTX;
-
-
-/**
- * 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 of failure
- */
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	MD5_CTX ctx;
-	size_t i;
-
-	MD5Init(&ctx);
-	for (i = 0; i < num_elem; i++)
-		MD5Update(&ctx, addr[i], len[i]);
-	MD5Final(mac, &ctx);
-	return 0;
-}
-
-
-/* ===== start - public domain MD5 implementation ===== */
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-#ifndef WORDS_BIGENDIAN
-#define byteReverse(buf, len)	/* Nothing */
-#else
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void byteReverse(unsigned char *buf, unsigned longs)
-{
-    u32 t;
-    do {
-	t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-	    ((unsigned) buf[1] << 8 | buf[0]);
-	*(u32 *) buf = t;
-	buf += 4;
-    } while (--longs);
-}
-#endif
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void MD5Init(struct MD5Context *ctx)
-{
-    ctx->buf[0] = 0x67452301;
-    ctx->buf[1] = 0xefcdab89;
-    ctx->buf[2] = 0x98badcfe;
-    ctx->buf[3] = 0x10325476;
-
-    ctx->bits[0] = 0;
-    ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
-{
-    u32 t;
-
-    /* Update bitcount */
-
-    t = ctx->bits[0];
-    if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
-	ctx->bits[1]++;		/* Carry from low to high */
-    ctx->bits[1] += len >> 29;
-
-    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
-
-    /* Handle any leading odd-sized chunks */
-
-    if (t) {
-	unsigned char *p = (unsigned char *) ctx->in + t;
-
-	t = 64 - t;
-	if (len < t) {
-	    os_memcpy(p, buf, len);
-	    return;
-	}
-	os_memcpy(p, buf, t);
-	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (u32 *) ctx->in);
-	buf += t;
-	len -= t;
-    }
-    /* Process data in 64-byte chunks */
-
-    while (len >= 64) {
-	os_memcpy(ctx->in, buf, 64);
-	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (u32 *) ctx->in);
-	buf += 64;
-	len -= 64;
-    }
-
-    /* Handle any remaining bytes of data. */
-
-    os_memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
-{
-    unsigned count;
-    unsigned char *p;
-
-    /* Compute number of bytes mod 64 */
-    count = (ctx->bits[0] >> 3) & 0x3F;
-
-    /* Set the first char of padding to 0x80.  This is safe since there is
-       always at least one byte free */
-    p = ctx->in + count;
-    *p++ = 0x80;
-
-    /* Bytes of padding needed to make 64 bytes */
-    count = 64 - 1 - count;
-
-    /* Pad out to 56 mod 64 */
-    if (count < 8) {
-	/* Two lots of padding:  Pad the first block to 64 bytes */
-	os_memset(p, 0, count);
-	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (u32 *) ctx->in);
-
-	/* Now fill the next block with 56 bytes */
-	os_memset(ctx->in, 0, 56);
-    } else {
-	/* Pad block to 56 bytes */
-	os_memset(p, 0, count - 8);
-    }
-    byteReverse(ctx->in, 14);
-
-    /* Append length in bits and transform */
-    ((u32 *) ctx->in)[14] = ctx->bits[0];
-    ((u32 *) ctx->in)[15] = ctx->bits[1];
-
-    MD5Transform(ctx->buf, (u32 *) ctx->in);
-    byteReverse((unsigned char *) ctx->buf, 4);
-    os_memcpy(digest, ctx->buf, 16);
-    os_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
-}
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(u32 buf[4], u32 const in[16])
-{
-    register u32 a, b, c, d;
-
-    a = buf[0];
-    b = buf[1];
-    c = buf[2];
-    d = buf[3];
-
-    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-    buf[0] += a;
-    buf[1] += b;
-    buf[2] += c;
-    buf[3] += d;
-}
-/* ===== end - public domain MD5 implementation ===== */

Copied: vendor/wpa/2.0/src/crypto/md5-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/md5-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/md5-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/md5-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,287 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "md5.h"
+#include "md5_i.h"
+#include "crypto.h"
+
+
+static void MD5Transform(u32 buf[4], u32 const in[16]);
+
+
+typedef struct MD5Context MD5_CTX;
+
+
+/**
+ * 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 of failure
+ */
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	MD5_CTX ctx;
+	size_t i;
+
+	MD5Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		MD5Update(&ctx, addr[i], len[i]);
+	MD5Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain MD5 implementation ===== */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)	/* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    u32 t;
+    do {
+	t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(u32 *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    u32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    os_memcpy(p, buf, len);
+	    return;
+	}
+	os_memcpy(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	os_memcpy(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    os_memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	os_memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	os_memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	os_memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[14] = ctx->bits[0];
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    os_memcpy(digest, ctx->buf, 16);
+    os_memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(u32 buf[4], u32 const in[16])
+{
+    register u32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+/* ===== end - public domain MD5 implementation ===== */

Deleted: vendor/wpa/2.0/src/crypto/md5-non-fips.c
===================================================================
--- vendor/wpa/dist/src/crypto/md5-non-fips.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md5-non-fips.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,113 +0,0 @@
-/*
- * MD5 hash implementation and interface functions (non-FIPS allowed cases)
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "md5.h"
-#include "crypto.h"
-
-
-/**
- * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @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 (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
-				   size_t num_elem, const u8 *addr[],
-				   const size_t *len, u8 *mac)
-{
-	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
-	u8 tk[16];
-	const u8 *_addr[6];
-	size_t i, _len[6];
-
-	if (num_elem > 5) {
-		/*
-		 * Fixed limit on the number of fragments to avoid having to
-		 * allocate memory (which could fail).
-		 */
-		return -1;
-	}
-
-        /* if key is longer than 64 bytes reset it to key = MD5(key) */
-        if (key_len > 64) {
-		if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
-			return -1;
-		key = tk;
-		key_len = 16;
-        }
-
-	/* the HMAC_MD5 transform looks like:
-	 *
-	 * MD5(K XOR opad, MD5(K XOR ipad, text))
-	 *
-	 * where K is an n byte key
-	 * ipad is the byte 0x36 repeated 64 times
-	 * opad is the byte 0x5c repeated 64 times
-	 * and text is the data being protected */
-
-	/* start out by storing key in ipad */
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-
-	/* XOR key with ipad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x36;
-
-	/* perform inner MD5 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	for (i = 0; i < num_elem; i++) {
-		_addr[i + 1] = addr[i];
-		_len[i + 1] = len[i];
-	}
-	if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
-		return -1;
-
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with opad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x5c;
-
-	/* perform outer MD5 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	_addr[1] = mac;
-	_len[1] = MD5_MAC_LEN;
-	return md5_vector_non_fips_allow(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
-			    size_t data_len, u8 *mac)
-{
-	return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
-					      &data_len, mac);
-}

Deleted: vendor/wpa/2.0/src/crypto/md5.c
===================================================================
--- vendor/wpa/dist/src/crypto/md5.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,111 +0,0 @@
-/*
- * MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "md5.h"
-#include "crypto.h"
-
-
-/**
- * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @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 (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
-		    const u8 *addr[], const size_t *len, u8 *mac)
-{
-	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
-	u8 tk[16];
-	const u8 *_addr[6];
-	size_t i, _len[6];
-
-	if (num_elem > 5) {
-		/*
-		 * Fixed limit on the number of fragments to avoid having to
-		 * allocate memory (which could fail).
-		 */
-		return -1;
-	}
-
-        /* if key is longer than 64 bytes reset it to key = MD5(key) */
-        if (key_len > 64) {
-		if (md5_vector(1, &key, &key_len, tk))
-			return -1;
-		key = tk;
-		key_len = 16;
-        }
-
-	/* the HMAC_MD5 transform looks like:
-	 *
-	 * MD5(K XOR opad, MD5(K XOR ipad, text))
-	 *
-	 * where K is an n byte key
-	 * ipad is the byte 0x36 repeated 64 times
-	 * opad is the byte 0x5c repeated 64 times
-	 * and text is the data being protected */
-
-	/* start out by storing key in ipad */
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-
-	/* XOR key with ipad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x36;
-
-	/* perform inner MD5 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	for (i = 0; i < num_elem; i++) {
-		_addr[i + 1] = addr[i];
-		_len[i + 1] = len[i];
-	}
-	if (md5_vector(1 + num_elem, _addr, _len, mac))
-		return -1;
-
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with opad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x5c;
-
-	/* perform outer MD5 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	_addr[1] = mac;
-	_len[1] = MD5_MAC_LEN;
-	return md5_vector(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
-	      u8 *mac)
-{
-	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
-}

Copied: vendor/wpa/2.0/src/crypto/md5.c (from rev 9639, vendor/wpa/dist/src/crypto/md5.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/md5.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,105 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "md5.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @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 (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
+	size_t i, _len[6];
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = MD5(key) */
+        if (key_len > 64) {
+		if (md5_vector(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 16;
+        }
+
+	/* the HMAC_MD5 transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (md5_vector(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = MD5_MAC_LEN;
+	return md5_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}

Deleted: vendor/wpa/2.0/src/crypto/md5.h
===================================================================
--- vendor/wpa/dist/src/crypto/md5.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,35 +0,0 @@
-/*
- * MD5 hash implementation and interface functions
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MD5_H
-#define MD5_H
-
-#define MD5_MAC_LEN 16
-
-int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
-		    const u8 *addr[], const size_t *len, u8 *mac);
-int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
-	     u8 *mac);
-#ifdef CONFIG_FIPS
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
-				   size_t num_elem, const u8 *addr[],
-				   const size_t *len, u8 *mac);
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
-			    size_t data_len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define hmac_md5_vector_non_fips_allow hmac_md5_vector
-#define hmac_md5_non_fips_allow hmac_md5
-#endif /* CONFIG_FIPS */
-
-#endif /* MD5_H */

Copied: vendor/wpa/2.0/src/crypto/md5.h (from rev 9639, vendor/wpa/dist/src/crypto/md5.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/md5.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/md5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,19 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define MD5_MAC_LEN 16
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac);
+
+#endif /* MD5_H */

Deleted: vendor/wpa/2.0/src/crypto/md5_i.h
===================================================================
--- vendor/wpa/dist/src/crypto/md5_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/md5_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,29 +0,0 @@
-/*
- * MD5 internal definitions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MD5_I_H
-#define MD5_I_H
-
-struct MD5Context {
-	u32 buf[4];
-	u32 bits[2];
-	u8 in[64];
-};
-
-void MD5Init(struct MD5Context *context);
-void MD5Update(struct MD5Context *context, unsigned char const *buf,
-	       unsigned len);
-void MD5Final(unsigned char digest[16], struct MD5Context *context);
-
-#endif /* MD5_I_H */

Copied: vendor/wpa/2.0/src/crypto/md5_i.h (from rev 9639, vendor/wpa/dist/src/crypto/md5_i.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/md5_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/md5_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * MD5 internal definitions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MD5_I_H
+#define MD5_I_H
+
+struct MD5Context {
+	u32 buf[4];
+	u32 bits[2];
+	u8 in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif /* MD5_I_H */

Deleted: vendor/wpa/2.0/src/crypto/milenage.c
===================================================================
--- vendor/wpa/dist/src/crypto/milenage.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/milenage.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,329 +0,0 @@
-/*
- * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
- * Copyright (c) 2006-2007 <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements an example authentication algorithm defined for 3GPP
- * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
- * EAP-AKA to be tested properly with real USIM cards.
- *
- * This implementations assumes that the r1..r5 and c1..c5 constants defined in
- * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
- * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
- * be AES (Rijndael).
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "milenage.h"
-
-
-/**
- * milenage_f1 - Milenage f1 and f1* algorithms
- * @opc: OPc = 128-bit value derived from OP and K
- * @k: K = 128-bit subscriber key
- * @_rand: RAND = 128-bit random challenge
- * @sqn: SQN = 48-bit sequence number
- * @amf: AMF = 16-bit authentication management field
- * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
- * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
- * Returns: 0 on success, -1 on failure
- */
-int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
-		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
-{
-	u8 tmp1[16], tmp2[16], tmp3[16];
-	int i;
-
-	/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
-	for (i = 0; i < 16; i++)
-		tmp1[i] = _rand[i] ^ opc[i];
-	if (aes_128_encrypt_block(k, tmp1, tmp1))
-		return -1;
-
-	/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
-	os_memcpy(tmp2, sqn, 6);
-	os_memcpy(tmp2 + 6, amf, 2);
-	os_memcpy(tmp2 + 8, tmp2, 8);
-
-	/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
-
-	/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
-	for (i = 0; i < 16; i++)
-		tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
-	/* XOR with TEMP = E_K(RAND XOR OP_C) */
-	for (i = 0; i < 16; i++)
-		tmp3[i] ^= tmp1[i];
-	/* XOR with c1 (= ..00, i.e., NOP) */
-
-	/* f1 || f1* = E_K(tmp3) XOR OP_c */
-	if (aes_128_encrypt_block(k, tmp3, tmp1))
-		return -1;
-	for (i = 0; i < 16; i++)
-		tmp1[i] ^= opc[i];
-	if (mac_a)
-		os_memcpy(mac_a, tmp1, 8); /* f1 */
-	if (mac_s)
-		os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
-	return 0;
-}
-
-
-/**
- * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
- * @opc: OPc = 128-bit value derived from OP and K
- * @k: K = 128-bit subscriber key
- * @_rand: RAND = 128-bit random challenge
- * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
- * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
- * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
- * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
- * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
- * Returns: 0 on success, -1 on failure
- */
-int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
-		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
-{
-	u8 tmp1[16], tmp2[16], tmp3[16];
-	int i;
-
-	/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
-	for (i = 0; i < 16; i++)
-		tmp1[i] = _rand[i] ^ opc[i];
-	if (aes_128_encrypt_block(k, tmp1, tmp2))
-		return -1;
-
-	/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
-	/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
-	/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
-	/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
-
-	/* f2 and f5 */
-	/* rotate by r2 (= 0, i.e., NOP) */
-	for (i = 0; i < 16; i++)
-		tmp1[i] = tmp2[i] ^ opc[i];
-	tmp1[15] ^= 1; /* XOR c2 (= ..01) */
-	/* f5 || f2 = E_K(tmp1) XOR OP_c */
-	if (aes_128_encrypt_block(k, tmp1, tmp3))
-		return -1;
-	for (i = 0; i < 16; i++)
-		tmp3[i] ^= opc[i];
-	if (res)
-		os_memcpy(res, tmp3 + 8, 8); /* f2 */
-	if (ak)
-		os_memcpy(ak, tmp3, 6); /* f5 */
-
-	/* f3 */
-	if (ck) {
-		/* rotate by r3 = 0x20 = 4 bytes */
-		for (i = 0; i < 16; i++)
-			tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
-		tmp1[15] ^= 2; /* XOR c3 (= ..02) */
-		if (aes_128_encrypt_block(k, tmp1, ck))
-			return -1;
-		for (i = 0; i < 16; i++)
-			ck[i] ^= opc[i];
-	}
-
-	/* f4 */
-	if (ik) {
-		/* rotate by r4 = 0x40 = 8 bytes */
-		for (i = 0; i < 16; i++)
-			tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
-		tmp1[15] ^= 4; /* XOR c4 (= ..04) */
-		if (aes_128_encrypt_block(k, tmp1, ik))
-			return -1;
-		for (i = 0; i < 16; i++)
-			ik[i] ^= opc[i];
-	}
-
-	/* f5* */
-	if (akstar) {
-		/* rotate by r5 = 0x60 = 12 bytes */
-		for (i = 0; i < 16; i++)
-			tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
-		tmp1[15] ^= 8; /* XOR c5 (= ..08) */
-		if (aes_128_encrypt_block(k, tmp1, tmp1))
-			return -1;
-		for (i = 0; i < 6; i++)
-			akstar[i] = tmp1[i] ^ opc[i];
-	}
-
-	return 0;
-}
-
-
-/**
- * milenage_generate - Generate AKA AUTN,IK,CK,RES
- * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
- * @amf: AMF = 16-bit authentication management field
- * @k: K = 128-bit subscriber key
- * @sqn: SQN = 48-bit sequence number
- * @_rand: RAND = 128-bit random challenge
- * @autn: Buffer for AUTN = 128-bit authentication token
- * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
- * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
- * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
- * @res_len: Max length for res; set to used length or 0 on failure
- */
-void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
-		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
-		       u8 *ck, u8 *res, size_t *res_len)
-{
-	int i;
-	u8 mac_a[8], ak[6];
-
-	if (*res_len < 8) {
-		*res_len = 0;
-		return;
-	}
-	if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
-	    milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
-		*res_len = 0;
-		return;
-	}
-	*res_len = 8;
-
-	/* AUTN = (SQN ^ AK) || AMF || MAC */
-	for (i = 0; i < 6; i++)
-		autn[i] = sqn[i] ^ ak[i];
-	os_memcpy(autn + 6, amf, 2);
-	os_memcpy(autn + 8, mac_a, 8);
-}
-
-
-/**
- * milenage_auts - Milenage AUTS validation
- * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
- * @k: K = 128-bit subscriber key
- * @_rand: RAND = 128-bit random challenge
- * @auts: AUTS = 112-bit authentication token from client
- * @sqn: Buffer for SQN = 48-bit sequence number
- * Returns: 0 = success (sqn filled), -1 on failure
- */
-int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
-		  u8 *sqn)
-{
-	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
-	u8 ak[6], mac_s[8];
-	int i;
-
-	if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
-		return -1;
-	for (i = 0; i < 6; i++)
-		sqn[i] = auts[i] ^ ak[i];
-	if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
-	    memcmp(mac_s, auts + 6, 8) != 0)
-		return -1;
-	return 0;
-}
-
-
-/**
- * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
- * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
- * @k: K = 128-bit subscriber key
- * @_rand: RAND = 128-bit random challenge
- * @sres: Buffer for SRES = 32-bit SRES
- * @kc: Buffer for Kc = 64-bit Kc
- * Returns: 0 on success, -1 on failure
- */
-int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
-{
-	u8 res[8], ck[16], ik[16];
-	int i;
-
-	if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
-		return -1;
-
-	for (i = 0; i < 8; i++)
-		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
-
-#ifdef GSM_MILENAGE_ALT_SRES
-	os_memcpy(sres, res, 4);
-#else /* GSM_MILENAGE_ALT_SRES */
-	for (i = 0; i < 4; i++)
-		sres[i] = res[i] ^ res[i + 4];
-#endif /* GSM_MILENAGE_ALT_SRES */
-	return 0;
-}
-
-
-/**
- * milenage_generate - Generate AKA AUTN,IK,CK,RES
- * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
- * @k: K = 128-bit subscriber key
- * @sqn: SQN = 48-bit sequence number
- * @_rand: RAND = 128-bit random challenge
- * @autn: AUTN = 128-bit authentication token
- * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
- * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
- * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
- * @res_len: Variable that will be set to RES length
- * @auts: 112-bit buffer for AUTS
- * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
- */
-int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
-		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
-		   u8 *auts)
-{
-	int i;
-	u8 mac_a[8], ak[6], rx_sqn[6];
-	const u8 *amf;
-
-	wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
-	wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
-
-	if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
-		return -1;
-
-	*res_len = 8;
-	wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
-	wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
-	wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
-	wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
-
-	/* AUTN = (SQN ^ AK) || AMF || MAC */
-	for (i = 0; i < 6; i++)
-		rx_sqn[i] = autn[i] ^ ak[i];
-	wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
-
-	if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
-		u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
-		if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
-			return -1;
-		wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
-		for (i = 0; i < 6; i++)
-			auts[i] = sqn[i] ^ ak[i];
-		if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
-			return -1;
-		wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
-		return -2;
-	}
-
-	amf = autn + 6;
-	wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
-	if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
-
-	if (os_memcmp(mac_a, autn + 8, 8) != 0) {
-		wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
-		wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
-			    autn + 8, 8);
-		return -1;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/milenage.c (from rev 9639, vendor/wpa/dist/src/crypto/milenage.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/milenage.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/milenage.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,323 @@
+/*
+ * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006-2007 <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements an example authentication algorithm defined for 3GPP
+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
+ * EAP-AKA to be tested properly with real USIM cards.
+ *
+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in
+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
+ * be AES (Rijndael).
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "milenage.h"
+
+
+/**
+ * milenage_f1 - Milenage f1 and f1* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sqn: SQN = 48-bit sequence number
+ * @amf: AMF = 16-bit authentication management field
+ * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
+ * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
+ * Returns: 0 on success, -1 on failure
+ */
+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
+		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	if (aes_128_encrypt_block(k, tmp1, tmp1))
+		return -1;
+
+	/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
+	os_memcpy(tmp2, sqn, 6);
+	os_memcpy(tmp2 + 6, amf, 2);
+	os_memcpy(tmp2 + 8, tmp2, 8);
+
+	/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
+
+	/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
+	for (i = 0; i < 16; i++)
+		tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
+	/* XOR with TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= tmp1[i];
+	/* XOR with c1 (= ..00, i.e., NOP) */
+
+	/* f1 || f1* = E_K(tmp3) XOR OP_c */
+	if (aes_128_encrypt_block(k, tmp3, tmp1))
+		return -1;
+	for (i = 0; i < 16; i++)
+		tmp1[i] ^= opc[i];
+	if (mac_a)
+		os_memcpy(mac_a, tmp1, 8); /* f1 */
+	if (mac_s)
+		os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
+	return 0;
+}
+
+
+/**
+ * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
+ * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
+ * Returns: 0 on success, -1 on failure
+ */
+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
+		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	if (aes_128_encrypt_block(k, tmp1, tmp2))
+		return -1;
+
+	/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
+	/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
+	/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
+	/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
+
+	/* f2 and f5 */
+	/* rotate by r2 (= 0, i.e., NOP) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = tmp2[i] ^ opc[i];
+	tmp1[15] ^= 1; /* XOR c2 (= ..01) */
+	/* f5 || f2 = E_K(tmp1) XOR OP_c */
+	if (aes_128_encrypt_block(k, tmp1, tmp3))
+		return -1;
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= opc[i];
+	if (res)
+		os_memcpy(res, tmp3 + 8, 8); /* f2 */
+	if (ak)
+		os_memcpy(ak, tmp3, 6); /* f5 */
+
+	/* f3 */
+	if (ck) {
+		/* rotate by r3 = 0x20 = 4 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 2; /* XOR c3 (= ..02) */
+		if (aes_128_encrypt_block(k, tmp1, ck))
+			return -1;
+		for (i = 0; i < 16; i++)
+			ck[i] ^= opc[i];
+	}
+
+	/* f4 */
+	if (ik) {
+		/* rotate by r4 = 0x40 = 8 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 4; /* XOR c4 (= ..04) */
+		if (aes_128_encrypt_block(k, tmp1, ik))
+			return -1;
+		for (i = 0; i < 16; i++)
+			ik[i] ^= opc[i];
+	}
+
+	/* f5* */
+	if (akstar) {
+		/* rotate by r5 = 0x60 = 12 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 8; /* XOR c5 (= ..08) */
+		if (aes_128_encrypt_block(k, tmp1, tmp1))
+			return -1;
+		for (i = 0; i < 6; i++)
+			akstar[i] = tmp1[i] ^ opc[i];
+	}
+
+	return 0;
+}
+
+
+/**
+ * milenage_generate - Generate AKA AUTN,IK,CK,RES
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @amf: AMF = 16-bit authentication management field
+ * @k: K = 128-bit subscriber key
+ * @sqn: SQN = 48-bit sequence number
+ * @_rand: RAND = 128-bit random challenge
+ * @autn: Buffer for AUTN = 128-bit authentication token
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @res_len: Max length for res; set to used length or 0 on failure
+ */
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len)
+{
+	int i;
+	u8 mac_a[8], ak[6];
+
+	if (*res_len < 8) {
+		*res_len = 0;
+		return;
+	}
+	if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
+	    milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
+		*res_len = 0;
+		return;
+	}
+	*res_len = 8;
+
+	/* AUTN = (SQN ^ AK) || AMF || MAC */
+	for (i = 0; i < 6; i++)
+		autn[i] = sqn[i] ^ ak[i];
+	os_memcpy(autn + 6, amf, 2);
+	os_memcpy(autn + 8, mac_a, 8);
+}
+
+
+/**
+ * milenage_auts - Milenage AUTS validation
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @auts: AUTS = 112-bit authentication token from client
+ * @sqn: Buffer for SQN = 48-bit sequence number
+ * Returns: 0 = success (sqn filled), -1 on failure
+ */
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn)
+{
+	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+	u8 ak[6], mac_s[8];
+	int i;
+
+	if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
+		return -1;
+	for (i = 0; i < 6; i++)
+		sqn[i] = auts[i] ^ ak[i];
+	if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
+	    memcmp(mac_s, auts + 6, 8) != 0)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sres: Buffer for SRES = 32-bit SRES
+ * @kc: Buffer for Kc = 64-bit Kc
+ * Returns: 0 on success, -1 on failure
+ */
+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
+{
+	u8 res[8], ck[16], ik[16];
+	int i;
+
+	if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
+		return -1;
+
+	for (i = 0; i < 8; i++)
+		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
+
+#ifdef GSM_MILENAGE_ALT_SRES
+	os_memcpy(sres, res, 4);
+#else /* GSM_MILENAGE_ALT_SRES */
+	for (i = 0; i < 4; i++)
+		sres[i] = res[i] ^ res[i + 4];
+#endif /* GSM_MILENAGE_ALT_SRES */
+	return 0;
+}
+
+
+/**
+ * milenage_generate - Generate AKA AUTN,IK,CK,RES
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @sqn: SQN = 48-bit sequence number
+ * @_rand: RAND = 128-bit random challenge
+ * @autn: AUTN = 128-bit authentication token
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @res_len: Variable that will be set to RES length
+ * @auts: 112-bit buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
+ */
+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
+		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
+		   u8 *auts)
+{
+	int i;
+	u8 mac_a[8], ak[6], rx_sqn[6];
+	const u8 *amf;
+
+	wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
+	wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
+
+	if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
+		return -1;
+
+	*res_len = 8;
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
+
+	/* AUTN = (SQN ^ AK) || AMF || MAC */
+	for (i = 0; i < 6; i++)
+		rx_sqn[i] = autn[i] ^ ak[i];
+	wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
+
+	if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
+		u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+		if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
+			return -1;
+		wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
+		for (i = 0; i < 6; i++)
+			auts[i] = sqn[i] ^ ak[i];
+		if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
+			return -1;
+		wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
+		return -2;
+	}
+
+	amf = autn + 6;
+	wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
+	if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
+
+	if (os_memcmp(mac_a, autn + 8, 8) != 0) {
+		wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
+		wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
+			    autn + 8, 8);
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/milenage.h
===================================================================
--- vendor/wpa/dist/src/crypto/milenage.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/milenage.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,33 +0,0 @@
-/*
- * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
- * Copyright (c) 2006-2007 <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MILENAGE_H
-#define MILENAGE_H
-
-void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
-		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
-		       u8 *ck, u8 *res, size_t *res_len);
-int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
-		  u8 *sqn);
-int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
-		 u8 *kc);
-int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
-		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
-		   u8 *auts);
-int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
-		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s);
-int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
-		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar);
-
-#endif /* MILENAGE_H */

Copied: vendor/wpa/2.0/src/crypto/milenage.h (from rev 9639, vendor/wpa/dist/src/crypto/milenage.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/milenage.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/milenage.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,27 @@
+/*
+ * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006-2007 <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MILENAGE_H
+#define MILENAGE_H
+
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len);
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn);
+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
+		 u8 *kc);
+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
+		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
+		   u8 *auts);
+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
+		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s);
+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
+		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar);
+
+#endif /* MILENAGE_H */

Deleted: vendor/wpa/2.0/src/crypto/ms_funcs.c
===================================================================
--- vendor/wpa/dist/src/crypto/ms_funcs.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/ms_funcs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,476 +0,0 @@
-/*
- * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "ms_funcs.h"
-#include "crypto.h"
-
-
-/**
- * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
- * @peer_challenge: 16-octet PeerChallenge (IN)
- * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @username: 0-to-256-char UserName (IN)
- * @username_len: Length of username
- * @challenge: 8-octet Challenge (OUT)
- * Returns: 0 on success, -1 on failure
- */
-static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
-			  const u8 *username, size_t username_len,
-			  u8 *challenge)
-{
-	u8 hash[SHA1_MAC_LEN];
-	const unsigned char *addr[3];
-	size_t len[3];
-
-	addr[0] = peer_challenge;
-	len[0] = 16;
-	addr[1] = auth_challenge;
-	len[1] = 16;
-	addr[2] = username;
-	len[2] = username_len;
-
-	if (sha1_vector(3, addr, len, hash))
-		return -1;
-	os_memcpy(challenge, hash, 8);
-	return 0;
-}
-
-
-/**
- * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
- * @password_len: Length of password
- * @password_hash: 16-octet PasswordHash (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int nt_password_hash(const u8 *password, size_t password_len,
-		      u8 *password_hash)
-{
-	u8 buf[512], *pos;
-	size_t i, len;
-
-	if (password_len > 256)
-		password_len = 256;
-
-	/* Convert password into unicode */
-	for (i = 0; i < password_len; i++) {
-		buf[2 * i] = password[i];
-		buf[2 * i + 1] = 0;
-	}
-
-	len = password_len * 2;
-	pos = buf;
-	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
-}
-
-
-/**
- * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
- * @password_hash: 16-octet PasswordHash (IN)
- * @password_hash_hash: 16-octet PasswordHashHash (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
-{
-	size_t len = 16;
-	return md4_vector(1, &password_hash, &len, password_hash_hash);
-}
-
-
-/**
- * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
- * @challenge: 8-octet Challenge (IN)
- * @password_hash: 16-octet PasswordHash (IN)
- * @response: 24-octet Response (OUT)
- */
-void challenge_response(const u8 *challenge, const u8 *password_hash,
-			u8 *response)
-{
-	u8 zpwd[7];
-	des_encrypt(challenge, password_hash, response);
-	des_encrypt(challenge, password_hash + 7, response + 8);
-	zpwd[0] = password_hash[14];
-	zpwd[1] = password_hash[15];
-	os_memset(zpwd + 2, 0, 5);
-	des_encrypt(challenge, zpwd, response + 16);
-}
-
-
-/**
- * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
- * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @peer_challenge: 16-octet PeerChallenge (IN)
- * @username: 0-to-256-char UserName (IN)
- * @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
- * @password_len: Length of password
- * @response: 24-octet Response (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
-			 const u8 *username, size_t username_len,
-			 const u8 *password, size_t password_len,
-			 u8 *response)
-{
-	u8 challenge[8];
-	u8 password_hash[16];
-
-	challenge_hash(peer_challenge, auth_challenge, username, username_len,
-		       challenge);
-	if (nt_password_hash(password, password_len, password_hash))
-		return -1;
-	challenge_response(challenge, password_hash, response);
-	return 0;
-}
-
-
-/**
- * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
- * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @peer_challenge: 16-octet PeerChallenge (IN)
- * @username: 0-to-256-char UserName (IN)
- * @username_len: Length of username
- * @password_hash: 16-octet PasswordHash (IN)
- * @response: 24-octet Response (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int generate_nt_response_pwhash(const u8 *auth_challenge,
-				const u8 *peer_challenge,
-				const u8 *username, size_t username_len,
-				const u8 *password_hash,
-				u8 *response)
-{
-	u8 challenge[8];
-
-	if (challenge_hash(peer_challenge, auth_challenge,
-			   username, username_len,
-			   challenge))
-		return -1;
-	challenge_response(challenge, password_hash, response);
-	return 0;
-}
-
-
-/**
- * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password_hash: 16-octet PasswordHash (IN)
- * @nt_response: 24-octet NT-Response (IN)
- * @peer_challenge: 16-octet PeerChallenge (IN)
- * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @username: 0-to-256-char UserName (IN)
- * @username_len: Length of username
- * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
- * encoded as a 42-octet ASCII string (S=hexdump_of_response)
- * Returns: 0 on success, -1 on failure
- */
-int generate_authenticator_response_pwhash(
-	const u8 *password_hash,
-	const u8 *peer_challenge, const u8 *auth_challenge,
-	const u8 *username, size_t username_len,
-	const u8 *nt_response, u8 *response)
-{
-	static const u8 magic1[39] = {
-		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
-		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
-		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
-		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
-	};
-	static const u8 magic2[41] = {
-		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
-		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
-		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
-		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
-		0x6E
-	};
-
-	u8 password_hash_hash[16], challenge[8];
-	const unsigned char *addr1[3];
-	const size_t len1[3] = { 16, 24, sizeof(magic1) };
-	const unsigned char *addr2[3];
-	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
-
-	addr1[0] = password_hash_hash;
-	addr1[1] = nt_response;
-	addr1[2] = magic1;
-
-	addr2[0] = response;
-	addr2[1] = challenge;
-	addr2[2] = magic2;
-
-	if (hash_nt_password_hash(password_hash, password_hash_hash))
-		return -1;
-	if (sha1_vector(3, addr1, len1, response))
-		return -1;
-
-	challenge_hash(peer_challenge, auth_challenge, username, username_len,
-		       challenge);
-	return sha1_vector(3, addr2, len2, response);
-}
-
-
-/**
- * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
- * @password_len: Length of password
- * @nt_response: 24-octet NT-Response (IN)
- * @peer_challenge: 16-octet PeerChallenge (IN)
- * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @username: 0-to-256-char UserName (IN)
- * @username_len: Length of username
- * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
- * encoded as a 42-octet ASCII string (S=hexdump_of_response)
- * Returns: 0 on success, -1 on failure
- */
-int generate_authenticator_response(const u8 *password, size_t password_len,
-				    const u8 *peer_challenge,
-				    const u8 *auth_challenge,
-				    const u8 *username, size_t username_len,
-				    const u8 *nt_response, u8 *response)
-{
-	u8 password_hash[16];
-	if (nt_password_hash(password, password_len, password_hash))
-		return -1;
-	return generate_authenticator_response_pwhash(
-		password_hash, peer_challenge, auth_challenge,
-		username, username_len, nt_response, response);
-}
-
-
-/**
- * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
- * @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
- * @password_len: Length of password
- * @response: 24-octet Response (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int nt_challenge_response(const u8 *challenge, const u8 *password,
-			  size_t password_len, u8 *response)
-{
-	u8 password_hash[16];
-	if (nt_password_hash(password, password_len, password_hash))
-		return -1;
-	challenge_response(challenge, password_hash, response);
-	return 0;
-}
-
-
-/**
- * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
- * @password_hash_hash: 16-octet PasswordHashHash (IN)
- * @nt_response: 24-octet NTResponse (IN)
- * @master_key: 16-octet MasterKey (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
-		   u8 *master_key)
-{
-	static const u8 magic1[27] = {
-		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
-		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
-		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
-	};
-	const unsigned char *addr[3];
-	const size_t len[3] = { 16, 24, sizeof(magic1) };
-	u8 hash[SHA1_MAC_LEN];
-
-	addr[0] = password_hash_hash;
-	addr[1] = nt_response;
-	addr[2] = magic1;
-
-	if (sha1_vector(3, addr, len, hash))
-		return -1;
-	os_memcpy(master_key, hash, 16);
-	return 0;
-}
-
-
-/**
- * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
- * @master_key: 16-octet MasterKey (IN)
- * @session_key: 8-to-16 octet SessionKey (OUT)
- * @session_key_len: SessionKeyLength (Length of session_key) (IN)
- * @is_send: IsSend (IN, BOOLEAN)
- * @is_server: IsServer (IN, BOOLEAN)
- * Returns: 0 on success, -1 on failure
- */
-int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
-			    size_t session_key_len, int is_send,
-			    int is_server)
-{
-	static const u8 magic2[84] = {
-		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
-		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
-		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
-		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
-		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
-		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
-		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
-		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
-		0x6b, 0x65, 0x79, 0x2e
-	};
-	static const u8 magic3[84] = {
-		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
-		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
-		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
-		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
-		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
-		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
-		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
-		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
-		0x6b, 0x65, 0x79, 0x2e
-	};
-	static const u8 shs_pad1[40] = {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
-
-	static const u8 shs_pad2[40] = {
-		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
-		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
-	};
-	u8 digest[SHA1_MAC_LEN];
-	const unsigned char *addr[4];
-	const size_t len[4] = { 16, 40, 84, 40 };
-
-	addr[0] = master_key;
-	addr[1] = shs_pad1;
-	if (is_send) {
-		addr[2] = is_server ? magic3 : magic2;
-	} else {
-		addr[2] = is_server ? magic2 : magic3;
-	}
-	addr[3] = shs_pad2;
-
-	if (sha1_vector(4, addr, len, digest))
-		return -1;
-
-	if (session_key_len > SHA1_MAC_LEN)
-		session_key_len = SHA1_MAC_LEN;
-	os_memcpy(session_key, digest, session_key_len);
-	return 0;
-}
-
-
-#define PWBLOCK_LEN 516
-
-/**
- * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
- * @password_len: Length of password
- * @password_hash: 16-octet PasswordHash (IN)
- * @pw_block: 516-byte PwBlock (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int encrypt_pw_block_with_password_hash(
-	const u8 *password, size_t password_len,
-	const u8 *password_hash, u8 *pw_block)
-{
-	size_t i, offset;
-	u8 *pos;
-
-	if (password_len > 256)
-		return -1;
-
-	os_memset(pw_block, 0, PWBLOCK_LEN);
-	offset = (256 - password_len) * 2;
-	if (os_get_random(pw_block, offset) < 0)
-		return -1;
-	for (i = 0; i < password_len; i++)
-		pw_block[offset + i * 2] = password[i];
-	/*
-	 * PasswordLength is 4 octets, but since the maximum password length is
-	 * 256, only first two (in little endian byte order) can be non-zero.
-	 */
-	pos = &pw_block[2 * 256];
-	WPA_PUT_LE16(pos, password_len * 2);
-	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
-	return 0;
-}
-
-
-/**
- * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
- * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
- * @old_password_len: Length of old_password
- * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int new_password_encrypted_with_old_nt_password_hash(
-	const u8 *new_password, size_t new_password_len,
-	const u8 *old_password, size_t old_password_len,
-	u8 *encrypted_pw_block)
-{
-	u8 password_hash[16];
-
-	if (nt_password_hash(old_password, old_password_len, password_hash))
-		return -1;
-	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
-						password_hash,
-						encrypted_pw_block))
-		return -1;
-	return 0;
-}
-
-
-/**
- * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
- * @password_hash: 16-octer PasswordHash (IN)
- * @block: 16-octet Block (IN)
- * @cypher: 16-octer Cypher (OUT)
- */
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
-					   const u8 *block, u8 *cypher)
-{
-	des_encrypt(password_hash, block, cypher);
-	des_encrypt(password_hash + 8, block + 7, cypher + 8);
-}
-
-
-/**
- * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
- * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
- * @old_password_len: Length of old_password
- * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
- * Returns: 0 on success, -1 on failure
- */
-int old_nt_password_hash_encrypted_with_new_nt_password_hash(
-	const u8 *new_password, size_t new_password_len,
-	const u8 *old_password, size_t old_password_len,
-	u8 *encrypted_password_hash)
-{
-	u8 old_password_hash[16], new_password_hash[16];
-
-	if (nt_password_hash(old_password, old_password_len,
-			     old_password_hash) ||
-	    nt_password_hash(new_password, new_password_len,
-			     new_password_hash))
-		return -1;
-	nt_password_hash_encrypted_with_block(old_password_hash,
-					      new_password_hash,
-					      encrypted_password_hash);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/ms_funcs.c (from rev 9639, vendor/wpa/dist/src/crypto/ms_funcs.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/ms_funcs.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/ms_funcs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,526 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "sha1.h"
+#include "ms_funcs.h"
+#include "crypto.h"
+
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+	size_t i, j;
+
+	for (i = 0, j = 0; i < utf8_string_len; i++) {
+		u8 c = utf8_string[i];
+		if (j >= ucs2_buffer_size) {
+			/* input too long */
+			return -1;
+		}
+		if (c <= 0x7F) {
+			WPA_PUT_LE16(ucs2_buffer + j, c);
+			j += 2;
+		} else if (i == utf8_string_len - 1 ||
+			   j >= ucs2_buffer_size - 1) {
+			/* incomplete surrogate */
+			return -1;
+		} else {
+			u8 c2 = utf8_string[++i];
+			if ((c & 0xE0) == 0xC0) {
+				/* two-byte encoding */
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0x1F) << 6) | (c2 & 0x3F));
+				j += 2;
+			} else if (i == utf8_string_len ||
+				   j >= ucs2_buffer_size - 1) {
+				/* incomplete surrogate */
+				return -1;
+			} else {
+				/* three-byte encoding */
+				u8 c3 = utf8_string[++i];
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0xF) << 12) |
+					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+			}
+		}
+	}
+
+	if (ucs2_string_size)
+		*ucs2_string_size = j / 2;
+	return 0;
+}
+
+
+/**
+ * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @challenge: 8-octet Challenge (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+			  const u8 *username, size_t username_len,
+			  u8 *challenge)
+{
+	u8 hash[SHA1_MAC_LEN];
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = peer_challenge;
+	len[0] = 16;
+	addr[1] = auth_challenge;
+	len[1] = 16;
+	addr[2] = username;
+	len[2] = username_len;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(challenge, hash, 8);
+	return 0;
+}
+
+
+/**
+ * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_password_hash(const u8 *password, size_t password_len,
+		      u8 *password_hash)
+{
+	u8 buf[512], *pos;
+	size_t len, max_len;
+
+	max_len = sizeof(buf);
+	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+		return -1;
+
+	len *= 2;
+	pos = buf;
+	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
+}
+
+
+/**
+ * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @password_hash_hash: 16-octet PasswordHashHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
+{
+	size_t len = 16;
+	return md4_vector(1, &password_hash, &len, password_hash_hash);
+}
+
+
+/**
+ * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response)
+{
+	u8 zpwd[7];
+	des_encrypt(challenge, password_hash, response);
+	des_encrypt(challenge, password_hash + 7, response + 8);
+	zpwd[0] = password_hash[14];
+	zpwd[1] = password_hash[15];
+	os_memset(zpwd + 2, 0, 5);
+	des_encrypt(challenge, zpwd, response + 16);
+}
+
+
+/**
+ * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response)
+{
+	u8 challenge[8];
+	u8 password_hash[16];
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response)
+{
+	u8 challenge[8];
+
+	if (challenge_hash(peer_challenge, auth_challenge,
+			   username, username_len,
+			   challenge))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response)
+{
+	static const u8 magic1[39] = {
+		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
+	};
+	static const u8 magic2[41] = {
+		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+		0x6E
+	};
+
+	u8 password_hash_hash[16], challenge[8];
+	const unsigned char *addr1[3];
+	const size_t len1[3] = { 16, 24, sizeof(magic1) };
+	const unsigned char *addr2[3];
+	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
+
+	addr1[0] = password_hash_hash;
+	addr1[1] = nt_response;
+	addr1[2] = magic1;
+
+	addr2[0] = response;
+	addr2[1] = challenge;
+	addr2[2] = magic2;
+
+	if (hash_nt_password_hash(password_hash, password_hash_hash))
+		return -1;
+	if (sha1_vector(3, addr1, len1, response))
+		return -1;
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	return sha1_vector(3, addr2, len2, response);
+}
+
+
+/**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	return generate_authenticator_response_pwhash(
+		password_hash, peer_challenge, auth_challenge,
+		username, username_len, nt_response, response);
+}
+
+
+/**
+ * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
+ * @password_hash_hash: 16-octet PasswordHashHash (IN)
+ * @nt_response: 24-octet NTResponse (IN)
+ * @master_key: 16-octet MasterKey (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key)
+{
+	static const u8 magic1[27] = {
+		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
+	};
+	const unsigned char *addr[3];
+	const size_t len[3] = { 16, 24, sizeof(magic1) };
+	u8 hash[SHA1_MAC_LEN];
+
+	addr[0] = password_hash_hash;
+	addr[1] = nt_response;
+	addr[2] = magic1;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(master_key, hash, 16);
+	return 0;
+}
+
+
+/**
+ * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
+ * @master_key: 16-octet MasterKey (IN)
+ * @session_key: 8-to-16 octet SessionKey (OUT)
+ * @session_key_len: SessionKeyLength (Length of session_key) (IN)
+ * @is_send: IsSend (IN, BOOLEAN)
+ * @is_server: IsServer (IN, BOOLEAN)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server)
+{
+	static const u8 magic2[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 magic3[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 shs_pad1[40] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	static const u8 shs_pad2[40] = {
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
+	};
+	u8 digest[SHA1_MAC_LEN];
+	const unsigned char *addr[4];
+	const size_t len[4] = { 16, 40, 84, 40 };
+
+	addr[0] = master_key;
+	addr[1] = shs_pad1;
+	if (is_send) {
+		addr[2] = is_server ? magic3 : magic2;
+	} else {
+		addr[2] = is_server ? magic2 : magic3;
+	}
+	addr[3] = shs_pad2;
+
+	if (sha1_vector(4, addr, len, digest))
+		return -1;
+
+	if (session_key_len > SHA1_MAC_LEN)
+		session_key_len = SHA1_MAC_LEN;
+	os_memcpy(session_key, digest, session_key_len);
+	return 0;
+}
+
+
+#define PWBLOCK_LEN 516
+
+/**
+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @pw_block: 516-byte PwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block)
+{
+	size_t ucs2_len, offset;
+	u8 *pos;
+
+	os_memset(pw_block, 0, PWBLOCK_LEN);
+
+	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
+		return -1;
+
+	if (ucs2_len > 256)
+		return -1;
+
+	offset = (256 - ucs2_len) * 2;
+	if (offset != 0) {
+		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+		if (os_get_random(pw_block, offset) < 0)
+			return -1;
+	}
+	/*
+	 * PasswordLength is 4 octets, but since the maximum password length is
+	 * 256, only first two (in little endian byte order) can be non-zero.
+	 */
+	pos = &pw_block[2 * 256];
+	WPA_PUT_LE16(pos, password_len * 2);
+	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
+	return 0;
+}
+
+
+/**
+ * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block)
+{
+	u8 password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len, password_hash))
+		return -1;
+	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
+						password_hash,
+						encrypted_pw_block))
+		return -1;
+	return 0;
+}
+
+
+/**
+ * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
+ * @password_hash: 16-octer PasswordHash (IN)
+ * @block: 16-octet Block (IN)
+ * @cypher: 16-octer Cypher (OUT)
+ */
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher)
+{
+	des_encrypt(password_hash, block, cypher);
+	des_encrypt(password_hash + 8, block + 7, cypher + 8);
+}
+
+
+/**
+ * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash)
+{
+	u8 old_password_hash[16], new_password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len,
+			     old_password_hash) ||
+	    nt_password_hash(new_password, new_password_len,
+			     new_password_hash))
+		return -1;
+	nt_password_hash_encrypted_with_block(old_password_hash,
+					      new_password_hash,
+					      encrypted_password_hash);
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/ms_funcs.h
===================================================================
--- vendor/wpa/dist/src/crypto/ms_funcs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/ms_funcs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,64 +0,0 @@
-/*
- * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MS_FUNCS_H
-#define MS_FUNCS_H
-
-int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
-			 const u8 *username, size_t username_len,
-			 const u8 *password, size_t password_len,
-			 u8 *response);
-int generate_nt_response_pwhash(const u8 *auth_challenge,
-				const u8 *peer_challenge,
-				const u8 *username, size_t username_len,
-				const u8 *password_hash,
-				u8 *response);
-int generate_authenticator_response(const u8 *password, size_t password_len,
-				    const u8 *peer_challenge,
-				    const u8 *auth_challenge,
-				    const u8 *username, size_t username_len,
-				    const u8 *nt_response, u8 *response);
-int generate_authenticator_response_pwhash(
-	const u8 *password_hash,
-	const u8 *peer_challenge, const u8 *auth_challenge,
-	const u8 *username, size_t username_len,
-	const u8 *nt_response, u8 *response);
-int nt_challenge_response(const u8 *challenge, const u8 *password,
-			  size_t password_len, u8 *response);
-
-void challenge_response(const u8 *challenge, const u8 *password_hash,
-			u8 *response);
-int nt_password_hash(const u8 *password, size_t password_len,
-		     u8 *password_hash);
-int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
-int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
-		   u8 *master_key);
-int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
-			    size_t session_key_len, int is_send,
-			    int is_server);
-int __must_check encrypt_pw_block_with_password_hash(
-	const u8 *password, size_t password_len,
-	const u8 *password_hash, u8 *pw_block);
-int __must_check new_password_encrypted_with_old_nt_password_hash(
-	const u8 *new_password, size_t new_password_len,
-	const u8 *old_password, size_t old_password_len,
-	u8 *encrypted_pw_block);
-void nt_password_hash_encrypted_with_block(const u8 *password_hash,
-					   const u8 *block, u8 *cypher);
-int old_nt_password_hash_encrypted_with_new_nt_password_hash(
-	const u8 *new_password, size_t new_password_len,
-	const u8 *old_password, size_t old_password_len,
-	u8 *encrypted_password_hash);
-
-#endif /* MS_FUNCS_H */

Copied: vendor/wpa/2.0/src/crypto/ms_funcs.h (from rev 9639, vendor/wpa/dist/src/crypto/ms_funcs.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/ms_funcs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/ms_funcs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,58 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MS_FUNCS_H
+#define MS_FUNCS_H
+
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response);
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response);
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response);
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response);
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response);
+
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response);
+int nt_password_hash(const u8 *password, size_t password_len,
+		     u8 *password_hash);
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key);
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server);
+int __must_check encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block);
+int __must_check new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block);
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher);
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash);
+
+#endif /* MS_FUNCS_H */

Copied: vendor/wpa/2.0/src/crypto/random.c (from rev 9639, vendor/wpa/dist/src/crypto/random.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/random.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/random.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,446 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This random number generator is used to provide additional entropy to the
+ * one provided by the operating system (os_get_random()) for session key
+ * generation. The os_get_random() output is expected to be secure and the
+ * implementation here is expected to provide only limited protection against
+ * cases where os_get_random() cannot provide strong randomness. This
+ * implementation shall not be assumed to be secure as the sole source of
+ * randomness. The random_get_bytes() function mixes in randomness from
+ * os_get_random() and as such, calls to os_get_random() can be replaced with
+ * calls to random_get_bytes() without reducing security.
+ *
+ * The design here follows partially the design used in the Linux
+ * drivers/char/random.c, but the implementation here is simpler and not as
+ * strong. This is a compromise to reduce duplicated CPU effort and to avoid
+ * extra code/memory size. As pointed out above, os_get_random() needs to be
+ * guaranteed to be secure for any of the security assumptions to hold.
+ */
+
+#include "utils/includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "sha1.h"
+#include "random.h"
+
+#define POOL_WORDS 32
+#define POOL_WORDS_MASK (POOL_WORDS - 1)
+#define POOL_TAP1 26
+#define POOL_TAP2 20
+#define POOL_TAP3 14
+#define POOL_TAP4 7
+#define POOL_TAP5 1
+#define EXTRACT_LEN 16
+#define MIN_READY_MARK 2
+
+static u32 pool[POOL_WORDS];
+static unsigned int input_rotate = 0;
+static unsigned int pool_pos = 0;
+static u8 dummy_key[20];
+#ifdef __linux__
+static size_t dummy_key_avail = 0;
+static int random_fd = -1;
+#endif /* __linux__ */
+static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
+
+#define MIN_COLLECT_ENTROPY 1000
+static unsigned int entropy = 0;
+static unsigned int total_collected = 0;
+
+
+static void random_write_entropy(void);
+
+
+static u32 __ROL32(u32 x, u32 y)
+{
+	return (x << (y & 31)) | (x >> (32 - (y & 31)));
+}
+
+
+static void random_mix_pool(const void *buf, size_t len)
+{
+	static const u32 twist[8] = {
+		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
+	};
+	const u8 *pos = buf;
+	u32 w;
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len);
+
+	while (len--) {
+		w = __ROL32(*pos++, input_rotate & 31);
+		input_rotate += pool_pos ? 7 : 14;
+		pool_pos = (pool_pos - 1) & POOL_WORDS_MASK;
+		w ^= pool[pool_pos];
+		w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK];
+		pool[pool_pos] = (w >> 3) ^ twist[w & 7];
+	}
+}
+
+
+static void random_extract(u8 *out)
+{
+	unsigned int i;
+	u8 hash[SHA1_MAC_LEN];
+	u32 *hash_ptr;
+	u32 buf[POOL_WORDS / 2];
+
+	/* First, add hash back to pool to make backtracking more difficult. */
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
+		  sizeof(pool), hash);
+	random_mix_pool(hash, sizeof(hash));
+	/* Hash half the pool to extra data */
+	for (i = 0; i < POOL_WORDS / 2; i++)
+		buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
+		  sizeof(buf), hash);
+	/*
+	 * Fold the hash to further reduce any potential output pattern.
+	 * Though, compromise this to reduce CPU use for the most common output
+	 * length (32) and return 16 bytes from instead of only half.
+	 */
+	hash_ptr = (u32 *) hash;
+	hash_ptr[0] ^= hash_ptr[4];
+	os_memcpy(out, hash, EXTRACT_LEN);
+}
+
+
+void random_add_randomness(const void *buf, size_t len)
+{
+	struct os_time t;
+	static unsigned int count = 0;
+
+	count++;
+	if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
+		/*
+		 * No need to add more entropy at this point, so save CPU and
+		 * skip the update.
+		 */
+		return;
+	}
+	wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+		   count, entropy);
+
+	os_get_time(&t);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	random_mix_pool(&t, sizeof(t));
+	random_mix_pool(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	entropy++;
+	total_collected++;
+}
+
+
+int random_get_bytes(void *buf, size_t len)
+{
+	int ret;
+	u8 *bytes = buf;
+	size_t left;
+
+	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
+		   (unsigned int) len, entropy);
+
+	/* Start with assumed strong randomness from OS */
+	ret = os_get_random(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
+			buf, len);
+
+	/* Mix in additional entropy extracted from the internal pool */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		random_extract(tmp);
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+
+#ifdef CONFIG_FIPS
+	/* Mix in additional entropy from the crypto module */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
+			wpa_printf(MSG_ERROR, "random: No entropy available "
+				   "for generating strong random bytes");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+#endif /* CONFIG_FIPS */
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
+
+	if (entropy < len)
+		entropy = 0;
+	else
+		entropy -= len;
+
+	return ret;
+}
+
+
+int random_pool_ready(void)
+{
+#ifdef __linux__
+	int fd;
+	ssize_t res;
+
+	/*
+	 * Make sure that there is reasonable entropy available before allowing
+	 * some key derivation operations to proceed.
+	 */
+
+	if (dummy_key_avail == sizeof(dummy_key))
+		return 1; /* Already initialized - good to continue */
+
+	/*
+	 * Try to fetch some more data from the kernel high quality
+	 * /dev/random. There may not be enough data available at this point,
+	 * so use non-blocking read to avoid blocking the application
+	 * completely.
+	 */
+	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return -1;
+	}
+
+	res = read(fd, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		res = 0;
+	}
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
+		   "/dev/random", (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+	close(fd);
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
+		   "random data available from /dev/random",
+		   (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+
+	if (own_pool_ready >= MIN_READY_MARK ||
+	    total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+		wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+			   "based on internal entropy");
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
+		   "secure operations");
+	return 0;
+#else /* __linux__ */
+	/* TODO: could do similar checks on non-Linux platforms */
+	return 1;
+#endif /* __linux__ */
+}
+
+
+void random_mark_pool_ready(void)
+{
+	own_pool_ready++;
+	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+	random_write_entropy();
+}
+
+
+#ifdef __linux__
+
+static void random_close_fd(void)
+{
+	if (random_fd >= 0) {
+		eloop_unregister_read_sock(random_fd);
+		close(random_fd);
+		random_fd = -1;
+	}
+}
+
+
+static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	ssize_t res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		return;
+	}
+
+	res = read(sock, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
+		   (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+	}
+}
+
+#endif /* __linux__ */
+
+
+static void random_read_entropy(void)
+{
+	char *buf;
+	size_t len;
+
+	if (!random_entropy_file)
+		return;
+
+	buf = os_readfile(random_entropy_file, &len);
+	if (buf == NULL)
+		return; /* entropy file not yet available */
+
+	if (len != 1 + RANDOM_ENTROPY_SIZE) {
+		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+			   random_entropy_file);
+		os_free(buf);
+		return;
+	}
+
+	own_pool_ready = (u8) buf[0];
+	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+	random_entropy_file_read = 1;
+	os_free(buf);
+	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+	char buf[RANDOM_ENTROPY_SIZE];
+	FILE *f;
+	u8 opr;
+	int fail = 0;
+
+	if (!random_entropy_file)
+		return;
+
+	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+		return;
+
+	f = fopen(random_entropy_file, "wb");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+			   "for writing", random_entropy_file);
+		return;
+	}
+
+	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+	if (fwrite(&opr, 1, 1, f) != 1 ||
+	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+		fail = 1;
+	fclose(f);
+	if (fail) {
+		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+			   "to %s", random_entropy_file);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+	os_free(random_entropy_file);
+	if (entropy_file)
+		random_entropy_file = os_strdup(entropy_file);
+	else
+		random_entropy_file = NULL;
+	random_read_entropy();
+
+#ifdef __linux__
+	if (random_fd >= 0)
+		return;
+
+	random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (random_fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
+		   "/dev/random");
+
+	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
+#endif /* __linux__ */
+
+	random_write_entropy();
+}
+
+
+void random_deinit(void)
+{
+#ifdef __linux__
+	random_close_fd();
+#endif /* __linux__ */
+	random_write_entropy();
+	os_free(random_entropy_file);
+	random_entropy_file = NULL;
+}

Copied: vendor/wpa/2.0/src/crypto/random.h (from rev 9639, vendor/wpa/dist/src/crypto/random.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/random.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/random.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#ifdef CONFIG_NO_RANDOM_POOL
+#define random_init(e) do { } while (0)
+#define random_deinit() do { } while (0)
+#define random_add_randomness(b, l) do { } while (0)
+#define random_get_bytes(b, l) os_get_random((b), (l))
+#define random_pool_ready() 1
+#define random_mark_pool_ready() do { } while (0)
+#else /* CONFIG_NO_RANDOM_POOL */
+void random_init(const char *entropy_file);
+void random_deinit(void);
+void random_add_randomness(const void *buf, size_t len);
+int random_get_bytes(void *buf, size_t len);
+int random_pool_ready(void);
+void random_mark_pool_ready(void);
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#endif /* RANDOM_H */

Deleted: vendor/wpa/2.0/src/crypto/rc4.c
===================================================================
--- vendor/wpa/dist/src/crypto/rc4.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/rc4.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,60 +0,0 @@
-/*
- * RC4 stream cipher
- * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto.h"
-
-#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
-	     u8 *data, size_t data_len)
-{
-	u32 i, j, k;
-	u8 S[256], *pos;
-	size_t kpos;
-
-	/* Setup RC4 state */
-	for (i = 0; i < 256; i++)
-		S[i] = i;
-	j = 0;
-	kpos = 0;
-	for (i = 0; i < 256; i++) {
-		j = (j + S[i] + key[kpos]) & 0xff;
-		kpos++;
-		if (kpos >= keylen)
-			kpos = 0;
-		S_SWAP(i, j);
-	}
-
-	/* Skip the start of the stream */
-	i = j = 0;
-	for (k = 0; k < skip; k++) {
-		i = (i + 1) & 0xff;
-		j = (j + S[i]) & 0xff;
-		S_SWAP(i, j);
-	}
-
-	/* Apply RC4 to data */
-	pos = data;
-	for (k = 0; k < data_len; k++) {
-		i = (i + 1) & 0xff;
-		j = (j + S[i]) & 0xff;
-		S_SWAP(i, j);
-		*pos++ ^= S[(S[i] + S[j]) & 0xff];
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/rc4.c (from rev 9639, vendor/wpa/dist/src/crypto/rc4.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/rc4.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/rc4.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,54 @@
+/*
+ * RC4 stream cipher
+ * Copyright (c) 2002-2005, Jouni Malinen <j at 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.h"
+
+#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+	u32 i, j, k;
+	u8 S[256], *pos;
+	size_t kpos;
+
+	/* Setup RC4 state */
+	for (i = 0; i < 256; i++)
+		S[i] = i;
+	j = 0;
+	kpos = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + S[i] + key[kpos]) & 0xff;
+		kpos++;
+		if (kpos >= keylen)
+			kpos = 0;
+		S_SWAP(i, j);
+	}
+
+	/* Skip the start of the stream */
+	i = j = 0;
+	for (k = 0; k < skip; k++) {
+		i = (i + 1) & 0xff;
+		j = (j + S[i]) & 0xff;
+		S_SWAP(i, j);
+	}
+
+	/* Apply RC4 to data */
+	pos = data;
+	for (k = 0; k < data_len; k++) {
+		i = (i + 1) & 0xff;
+		j = (j + S[i]) & 0xff;
+		S_SWAP(i, j);
+		*pos++ ^= S[(S[i] + S[j]) & 0xff];
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/sha1-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha1-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,308 +0,0 @@
-/*
- * SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "sha1_i.h"
-#include "md5.h"
-#include "crypto.h"
-
-typedef struct SHA1Context SHA1_CTX;
-
-void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
-
-
-/**
- * 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 of failure
- */
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
-	SHA1_CTX ctx;
-	size_t i;
-
-	SHA1Init(&ctx);
-	for (i = 0; i < num_elem; i++)
-		SHA1Update(&ctx, addr[i], len[i]);
-	SHA1Final(mac, &ctx);
-	return 0;
-}
-
-
-/* ===== start - public domain SHA1 implementation ===== */
-
-/*
-SHA-1 in C
-By Steve Reid <sreid at sea-to-sky.net>
-100% Public Domain
-
------------------
-Modified 7/98 
-By James H. Brown <jbrown at burgoyne.com>
-Still 100% Public Domain
-
-Corrected a problem which generated improper hash values on 16 bit machines
-Routine SHA1Update changed from
-	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
-len)
-to
-	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
-long len)
-
-The 'len' parameter was declared an int which works fine on 32 bit machines.
-However, on 16 bit machines an int is too small for the shifts being done
-against
-it.  This caused the hash function to generate incorrect values if len was
-greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
-
-Since the file IO in main() reads 16K at a time, any file 8K or larger would
-be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
-"a"s).
-
-I also changed the declaration of variables i & j in SHA1Update to 
-unsigned long from unsigned int for the same reason.
-
-These changes should make no difference to any 32 bit implementations since
-an
-int and a long are the same size in those environments.
-
---
-I also corrected a few compiler warnings generated by Borland C.
-1. Added #include <process.h> for exit() prototype
-2. Removed unused variable 'j' in SHA1Final
-3. Changed exit(0) to return(0) at end of main.
-
-ALL changes I made can be located by searching for comments containing 'JHB'
------------------
-Modified 8/98
-By Steve Reid <sreid at sea-to-sky.net>
-Still 100% public domain
-
-1- Removed #include <process.h> and used return() instead of exit()
-2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
-3- Changed email address from steve at edmweb.com to sreid at sea-to-sky.net
-
------------------
-Modified 4/01
-By Saul Kravitz <Saul.Kravitz at celera.com>
-Still 100% PD
-Modified to run on Compaq Alpha hardware.  
-
------------------
-Modified 4/01
-By Jouni Malinen <j at w1.fi>
-Minor changes to match the coding style used in Dynamics.
-
-Modified September 24, 2004
-By Jouni Malinen <j at w1.fi>
-Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
-
-*/
-
-/*
-Test Vectors (from FIPS PUB 180-1)
-"abc"
-  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
-"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
-A million repetitions of "a"
-  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
-*/
-
-#define SHA1HANDSOFF
-
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-#ifndef WORDS_BIGENDIAN
-#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \
-	(rol(block->l[i], 8) & 0x00FF00FF))
-#else
-#define blk0(i) block->l[i]
-#endif
-#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \
-	block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) \
-	z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
-	w = rol(w, 30);
-#define R1(v,w,x,y,z,i) \
-	z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
-	w = rol(w, 30);
-#define R2(v,w,x,y,z,i) \
-	z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
-#define R3(v,w,x,y,z,i) \
-	z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
-	w = rol(w, 30);
-#define R4(v,w,x,y,z,i) \
-	z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
-	w=rol(w, 30);
-
-
-#ifdef VERBOSE  /* SAK */
-void SHAPrintContext(SHA1_CTX *context, char *msg)
-{
-	printf("%s (%d,%d) %x %x %x %x %x\n",
-	       msg,
-	       context->count[0], context->count[1], 
-	       context->state[0],
-	       context->state[1],
-	       context->state[2],
-	       context->state[3],
-	       context->state[4]);
-}
-#endif
-
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-
-void SHA1Transform(u32 state[5], const unsigned char buffer[64])
-{
-	u32 a, b, c, d, e;
-	typedef union {
-		unsigned char c[64];
-		u32 l[16];
-	} CHAR64LONG16;
-	CHAR64LONG16* block;
-#ifdef SHA1HANDSOFF
-	CHAR64LONG16 workspace;
-	block = &workspace;
-	os_memcpy(block, buffer, 64);
-#else
-	block = (CHAR64LONG16 *) buffer;
-#endif
-	/* Copy context->state[] to working vars */
-	a = state[0];
-	b = state[1];
-	c = state[2];
-	d = state[3];
-	e = state[4];
-	/* 4 rounds of 20 operations each. Loop unrolled. */
-	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
-	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
-	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
-	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
-	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
-	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
-	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
-	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
-	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
-	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
-	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
-	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
-	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
-	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
-	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
-	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
-	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
-	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
-	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
-	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
-	/* Add the working vars back into context.state[] */
-	state[0] += a;
-	state[1] += b;
-	state[2] += c;
-	state[3] += d;
-	state[4] += e;
-	/* Wipe variables */
-	a = b = c = d = e = 0;
-#ifdef SHA1HANDSOFF
-	os_memset(block, 0, 64);
-#endif
-}
-
-
-/* SHA1Init - Initialize new context */
-
-void SHA1Init(SHA1_CTX* context)
-{
-	/* SHA1 initialization constants */
-	context->state[0] = 0x67452301;
-	context->state[1] = 0xEFCDAB89;
-	context->state[2] = 0x98BADCFE;
-	context->state[3] = 0x10325476;
-	context->state[4] = 0xC3D2E1F0;
-	context->count[0] = context->count[1] = 0;
-}
-
-
-/* Run your data through this. */
-
-void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
-{
-	u32 i, j;
-	const unsigned char *data = _data;
-
-#ifdef VERBOSE
-	SHAPrintContext(context, "before");
-#endif
-	j = (context->count[0] >> 3) & 63;
-	if ((context->count[0] += len << 3) < (len << 3))
-		context->count[1]++;
-	context->count[1] += (len >> 29);
-	if ((j + len) > 63) {
-		os_memcpy(&context->buffer[j], data, (i = 64-j));
-		SHA1Transform(context->state, context->buffer);
-		for ( ; i + 63 < len; i += 64) {
-			SHA1Transform(context->state, &data[i]);
-		}
-		j = 0;
-	}
-	else i = 0;
-	os_memcpy(&context->buffer[j], &data[i], len - i);
-#ifdef VERBOSE
-	SHAPrintContext(context, "after ");
-#endif
-}
-
-
-/* Add padding and return the message digest. */
-
-void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
-{
-	u32 i;
-	unsigned char finalcount[8];
-
-	for (i = 0; i < 8; i++) {
-		finalcount[i] = (unsigned char)
-			((context->count[(i >= 4 ? 0 : 1)] >>
-			  ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
-	}
-	SHA1Update(context, (unsigned char *) "\200", 1);
-	while ((context->count[0] & 504) != 448) {
-		SHA1Update(context, (unsigned char *) "\0", 1);
-	}
-	SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform()
-					      */
-	for (i = 0; i < 20; i++) {
-		digest[i] = (unsigned char)
-			((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) &
-			 255);
-	}
-	/* Wipe variables */
-	i = 0;
-	os_memset(context->buffer, 0, 64);
-	os_memset(context->state, 0, 20);
-	os_memset(context->count, 0, 8);
-	os_memset(finalcount, 0, 8);
-}
-
-/* ===== end - public domain SHA1 implementation ===== */

Copied: vendor/wpa/2.0/src/crypto/sha1-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,302 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+#include "sha1_i.h"
+#include "md5.h"
+#include "crypto.h"
+
+typedef struct SHA1Context SHA1_CTX;
+
+void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+
+
+/**
+ * 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 of failure
+ */
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	SHA1_CTX ctx;
+	size_t i;
+
+	SHA1Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		SHA1Update(&ctx, addr[i], len[i]);
+	SHA1Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain SHA1 implementation ===== */
+
+/*
+SHA-1 in C
+By Steve Reid <sreid at sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98 
+By James H. Brown <jbrown at burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to 
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid at sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve at edmweb.com to sreid at sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz at celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.  
+
+-----------------
+Modified 4/01
+By Jouni Malinen <j at w1.fi>
+Minor changes to match the coding style used in Dynamics.
+
+Modified September 24, 2004
+By Jouni Malinen <j at w1.fi>
+Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define SHA1HANDSOFF
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifndef WORDS_BIGENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \
+	(rol(block->l[i], 8) & 0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \
+	block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) \
+	z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
+	w = rol(w, 30);
+#define R1(v,w,x,y,z,i) \
+	z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+	w = rol(w, 30);
+#define R2(v,w,x,y,z,i) \
+	z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
+#define R3(v,w,x,y,z,i) \
+	z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+	w = rol(w, 30);
+#define R4(v,w,x,y,z,i) \
+	z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+	w=rol(w, 30);
+
+
+#ifdef VERBOSE  /* SAK */
+void SHAPrintContext(SHA1_CTX *context, char *msg)
+{
+	printf("%s (%d,%d) %x %x %x %x %x\n",
+	       msg,
+	       context->count[0], context->count[1], 
+	       context->state[0],
+	       context->state[1],
+	       context->state[2],
+	       context->state[3],
+	       context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(u32 state[5], const unsigned char buffer[64])
+{
+	u32 a, b, c, d, e;
+	typedef union {
+		unsigned char c[64];
+		u32 l[16];
+	} CHAR64LONG16;
+	CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+	CHAR64LONG16 workspace;
+	block = &workspace;
+	os_memcpy(block, buffer, 64);
+#else
+	block = (CHAR64LONG16 *) buffer;
+#endif
+	/* Copy context->state[] to working vars */
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+	e = state[4];
+	/* 4 rounds of 20 operations each. Loop unrolled. */
+	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+	/* Add the working vars back into context.state[] */
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+	/* Wipe variables */
+	a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+	os_memset(block, 0, 64);
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+	/* SHA1 initialization constants */
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xEFCDAB89;
+	context->state[2] = 0x98BADCFE;
+	context->state[3] = 0x10325476;
+	context->state[4] = 0xC3D2E1F0;
+	context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
+{
+	u32 i, j;
+	const unsigned char *data = _data;
+
+#ifdef VERBOSE
+	SHAPrintContext(context, "before");
+#endif
+	j = (context->count[0] >> 3) & 63;
+	if ((context->count[0] += len << 3) < (len << 3))
+		context->count[1]++;
+	context->count[1] += (len >> 29);
+	if ((j + len) > 63) {
+		os_memcpy(&context->buffer[j], data, (i = 64-j));
+		SHA1Transform(context->state, context->buffer);
+		for ( ; i + 63 < len; i += 64) {
+			SHA1Transform(context->state, &data[i]);
+		}
+		j = 0;
+	}
+	else i = 0;
+	os_memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+	SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+	u32 i;
+	unsigned char finalcount[8];
+
+	for (i = 0; i < 8; i++) {
+		finalcount[i] = (unsigned char)
+			((context->count[(i >= 4 ? 0 : 1)] >>
+			  ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+	}
+	SHA1Update(context, (unsigned char *) "\200", 1);
+	while ((context->count[0] & 504) != 448) {
+		SHA1Update(context, (unsigned char *) "\0", 1);
+	}
+	SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform()
+					      */
+	for (i = 0; i < 20; i++) {
+		digest[i] = (unsigned char)
+			((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) &
+			 255);
+	}
+	/* Wipe variables */
+	i = 0;
+	os_memset(context->buffer, 0, 64);
+	os_memset(context->state, 0, 20);
+	os_memset(context->count, 0, 8);
+	os_memset(finalcount, 0, 8);
+}
+
+/* ===== end - public domain SHA1 implementation ===== */

Deleted: vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha1-pbkdf2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,100 +0,0 @@
-/*
- * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
-
-static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
-			 size_t ssid_len, int iterations, unsigned int count,
-			 u8 *digest)
-{
-	unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
-	int i, j;
-	unsigned char count_buf[4];
-	const u8 *addr[2];
-	size_t len[2];
-	size_t passphrase_len = os_strlen(passphrase);
-
-	addr[0] = (u8 *) ssid;
-	len[0] = ssid_len;
-	addr[1] = count_buf;
-	len[1] = 4;
-
-	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
-	 * U1 = PRF(P, S || i)
-	 * U2 = PRF(P, U1)
-	 * Uc = PRF(P, Uc-1)
-	 */
-
-	count_buf[0] = (count >> 24) & 0xff;
-	count_buf[1] = (count >> 16) & 0xff;
-	count_buf[2] = (count >> 8) & 0xff;
-	count_buf[3] = count & 0xff;
-	if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
-			     tmp))
-		return -1;
-	os_memcpy(digest, tmp, SHA1_MAC_LEN);
-
-	for (i = 1; i < iterations; i++) {
-		if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp,
-			      SHA1_MAC_LEN, tmp2))
-			return -1;
-		os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
-		for (j = 0; j < SHA1_MAC_LEN; j++)
-			digest[j] ^= tmp2[j];
-	}
-
-	return 0;
-}
-
-
-/**
- * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
- * @passphrase: ASCII passphrase
- * @ssid: SSID
- * @ssid_len: SSID length in bytes
- * @iterations: Number of iterations to run
- * @buf: Buffer for the generated key
- * @buflen: Length of the buffer in bytes
- * Returns: 0 on success, -1 of failure
- *
- * This function is used to derive PSK for WPA-PSK. For this protocol,
- * iterations is set to 4096 and buflen to 32. This function is described in
- * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
- */
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
-		int iterations, u8 *buf, size_t buflen)
-{
-	unsigned int count = 0;
-	unsigned char *pos = buf;
-	size_t left = buflen, plen;
-	unsigned char digest[SHA1_MAC_LEN];
-
-	while (left > 0) {
-		count++;
-		if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations,
-				  count, digest))
-			return -1;
-		plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
-		os_memcpy(pos, digest, plen);
-		pos += plen;
-		left -= plen;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1-pbkdf2.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1-pbkdf2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,92 @@
+/*
+ * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+
+static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid,
+			 size_t ssid_len, int iterations, unsigned int count,
+			 u8 *digest)
+{
+	unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
+	int i, j;
+	unsigned char count_buf[4];
+	const u8 *addr[2];
+	size_t len[2];
+	size_t passphrase_len = os_strlen(passphrase);
+
+	addr[0] = ssid;
+	len[0] = ssid_len;
+	addr[1] = count_buf;
+	len[1] = 4;
+
+	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
+	 * U1 = PRF(P, S || i)
+	 * U2 = PRF(P, U1)
+	 * Uc = PRF(P, Uc-1)
+	 */
+
+	count_buf[0] = (count >> 24) & 0xff;
+	count_buf[1] = (count >> 16) & 0xff;
+	count_buf[2] = (count >> 8) & 0xff;
+	count_buf[3] = count & 0xff;
+	if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
+			     tmp))
+		return -1;
+	os_memcpy(digest, tmp, SHA1_MAC_LEN);
+
+	for (i = 1; i < iterations; i++) {
+		if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp,
+			      SHA1_MAC_LEN, tmp2))
+			return -1;
+		os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
+		for (j = 0; j < SHA1_MAC_LEN; j++)
+			digest[j] ^= tmp2[j];
+	}
+
+	return 0;
+}
+
+
+/**
+ * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
+ * @passphrase: ASCII passphrase
+ * @ssid: SSID
+ * @ssid_len: SSID length in bytes
+ * @iterations: Number of iterations to run
+ * @buf: Buffer for the generated key
+ * @buflen: Length of the buffer in bytes
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive PSK for WPA-PSK. For this protocol,
+ * iterations is set to 4096 and buflen to 32. This function is described in
+ * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
+ */
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+	unsigned int count = 0;
+	unsigned char *pos = buf;
+	size_t left = buflen, plen;
+	unsigned char digest[SHA1_MAC_LEN];
+
+	while (left > 0) {
+		count++;
+		if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations,
+				  count, digest))
+			return -1;
+		plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
+		os_memcpy(pos, digest, plen);
+		pos += plen;
+		left -= plen;
+	}
+
+	return 0;
+}

Copied: vendor/wpa/2.0/src/crypto/sha1-prf.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1-prf.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1-prf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1-prf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., PMK in IEEE 802.11i).
+ */
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	u8 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label) + 1;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = (u8 *) label;
+	len[0] = label_len;
+	addr[1] = data;
+	len[1] = data_len;
+	addr[2] = &counter;
+	len[2] = 1;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		if (plen >= SHA1_MAC_LEN) {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     &buf[pos]))
+				return -1;
+			pos += SHA1_MAC_LEN;
+		} else {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     hash))
+				return -1;
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/sha1-tlsprf.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha1-tlsprf.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1-tlsprf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,109 +0,0 @@
-/*
- * TLS PRF (SHA1 + MD5)
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
-
-
-/**
- * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
- * @secret: Key for PRF
- * @secret_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @seed: Seed value to bind into the key
- * @seed_len: Length of the seed
- * @out: Buffer for the generated pseudo-random key
- * @outlen: Number of bytes of key to generate
- * Returns: 0 on success, -1 on failure.
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
- */
-int tls_prf(const u8 *secret, size_t secret_len, const char *label,
-	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
-{
-	size_t L_S1, L_S2, i;
-	const u8 *S1, *S2;
-	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
-	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
-	int MD5_pos, SHA1_pos;
-	const u8 *MD5_addr[3];
-	size_t MD5_len[3];
-	const unsigned char *SHA1_addr[3];
-	size_t SHA1_len[3];
-
-	if (secret_len & 1)
-		return -1;
-
-	MD5_addr[0] = A_MD5;
-	MD5_len[0] = MD5_MAC_LEN;
-	MD5_addr[1] = (unsigned char *) label;
-	MD5_len[1] = os_strlen(label);
-	MD5_addr[2] = seed;
-	MD5_len[2] = seed_len;
-
-	SHA1_addr[0] = A_SHA1;
-	SHA1_len[0] = SHA1_MAC_LEN;
-	SHA1_addr[1] = (unsigned char *) label;
-	SHA1_len[1] = os_strlen(label);
-	SHA1_addr[2] = seed;
-	SHA1_len[2] = seed_len;
-
-	/* RFC 2246, Chapter 5
-	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
-	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
-	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
-	 */
-
-	L_S1 = L_S2 = (secret_len + 1) / 2;
-	S1 = secret;
-	S2 = secret + L_S1;
-	if (secret_len & 1) {
-		/* The last byte of S1 will be shared with S2 */
-		S2--;
-	}
-
-	hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
-				       A_MD5);
-	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
-
-	MD5_pos = MD5_MAC_LEN;
-	SHA1_pos = SHA1_MAC_LEN;
-	for (i = 0; i < outlen; i++) {
-		if (MD5_pos == MD5_MAC_LEN) {
-			hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
-						       MD5_len, P_MD5);
-			MD5_pos = 0;
-			hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
-						A_MD5);
-		}
-		if (SHA1_pos == SHA1_MAC_LEN) {
-			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
-					 P_SHA1);
-			SHA1_pos = 0;
-			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
-		}
-
-		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
-
-		MD5_pos++;
-		SHA1_pos++;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/sha1-tlsprf.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1-tlsprf.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1-tlsprf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1-tlsprf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,99 @@
+/*
+ * TLS PRF (SHA1 + MD5)
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+#include "md5.h"
+
+
+/**
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t L_S1, L_S2, i;
+	const u8 *S1, *S2;
+	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
+	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
+	int MD5_pos, SHA1_pos;
+	const u8 *MD5_addr[3];
+	size_t MD5_len[3];
+	const unsigned char *SHA1_addr[3];
+	size_t SHA1_len[3];
+
+	if (secret_len & 1)
+		return -1;
+
+	MD5_addr[0] = A_MD5;
+	MD5_len[0] = MD5_MAC_LEN;
+	MD5_addr[1] = (unsigned char *) label;
+	MD5_len[1] = os_strlen(label);
+	MD5_addr[2] = seed;
+	MD5_len[2] = seed_len;
+
+	SHA1_addr[0] = A_SHA1;
+	SHA1_len[0] = SHA1_MAC_LEN;
+	SHA1_addr[1] = (unsigned char *) label;
+	SHA1_len[1] = os_strlen(label);
+	SHA1_addr[2] = seed;
+	SHA1_len[2] = seed_len;
+
+	/* RFC 2246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
+	 */
+
+	L_S1 = L_S2 = (secret_len + 1) / 2;
+	S1 = secret;
+	S2 = secret + L_S1;
+	if (secret_len & 1) {
+		/* The last byte of S1 will be shared with S2 */
+		S2--;
+	}
+
+	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
+	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
+
+	MD5_pos = MD5_MAC_LEN;
+	SHA1_pos = SHA1_MAC_LEN;
+	for (i = 0; i < outlen; i++) {
+		if (MD5_pos == MD5_MAC_LEN) {
+			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
+			MD5_pos = 0;
+			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
+		}
+		if (SHA1_pos == SHA1_MAC_LEN) {
+			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
+					 P_SHA1);
+			SHA1_pos = 0;
+			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
+		}
+
+		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
+
+		MD5_pos++;
+		SHA1_pos++;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/sha1-tprf.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha1-tprf.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1-tprf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,76 +0,0 @@
-/*
- * SHA1 T-PRF for EAP-FAST
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "crypto.h"
-
-/**
- * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @seed: Seed value to bind into the key
- * @seed_len: Length of the seed
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- * Returns: 0 on success, -1 of failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5.
- */
-int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
-	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
-{
-	unsigned char counter = 0;
-	size_t pos, plen;
-	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = os_strlen(label);
-	u8 output_len[2];
-	const unsigned char *addr[5];
-	size_t len[5];
-
-	addr[0] = hash;
-	len[0] = 0;
-	addr[1] = (unsigned char *) label;
-	len[1] = label_len + 1;
-	addr[2] = seed;
-	len[2] = seed_len;
-	addr[3] = output_len;
-	len[3] = 2;
-	addr[4] = &counter;
-	len[4] = 1;
-
-	output_len[0] = (buf_len >> 8) & 0xff;
-	output_len[1] = buf_len & 0xff;
-	pos = 0;
-	while (pos < buf_len) {
-		counter++;
-		plen = buf_len - pos;
-		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
-			return -1;
-		if (plen >= SHA1_MAC_LEN) {
-			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
-			pos += SHA1_MAC_LEN;
-		} else {
-			os_memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		len[0] = SHA1_MAC_LEN;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/sha1-tprf.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1-tprf.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1-tprf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1-tprf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,70 @@
+/*
+ * SHA1 T-PRF for EAP-FAST
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+#include "crypto.h"
+
+/**
+ * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5.
+ */
+int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
+{
+	unsigned char counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label);
+	u8 output_len[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (unsigned char *) label;
+	len[1] = label_len + 1;
+	addr[2] = seed;
+	len[2] = seed_len;
+	addr[3] = output_len;
+	len[3] = 2;
+	addr[4] = &counter;
+	len[4] = 1;
+
+	output_len[0] = (buf_len >> 8) & 0xff;
+	output_len[1] = buf_len & 0xff;
+	pos = 0;
+	while (pos < buf_len) {
+		counter++;
+		plen = buf_len - pos;
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
+			return -1;
+		if (plen >= SHA1_MAC_LEN) {
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			pos += SHA1_MAC_LEN;
+		} else {
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		len[0] = SHA1_MAC_LEN;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/sha1.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha1.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,163 +0,0 @@
-/*
- * SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha1.h"
-#include "crypto.h"
-
-
-/**
- * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @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 (20 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
-		     const u8 *addr[], const size_t *len, u8 *mac)
-{
-	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
-	unsigned char tk[20];
-	const u8 *_addr[6];
-	size_t _len[6], i;
-
-	if (num_elem > 5) {
-		/*
-		 * Fixed limit on the number of fragments to avoid having to
-		 * allocate memory (which could fail).
-		 */
-		return -1;
-	}
-
-        /* if key is longer than 64 bytes reset it to key = SHA1(key) */
-        if (key_len > 64) {
-		if (sha1_vector(1, &key, &key_len, tk))
-			return -1;
-		key = tk;
-		key_len = 20;
-        }
-
-	/* the HMAC_SHA1 transform looks like:
-	 *
-	 * SHA1(K XOR opad, SHA1(K XOR ipad, text))
-	 *
-	 * where K is an n byte key
-	 * ipad is the byte 0x36 repeated 64 times
-	 * opad is the byte 0x5c repeated 64 times
-	 * and text is the data being protected */
-
-	/* start out by storing key in ipad */
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with ipad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x36;
-
-	/* perform inner SHA1 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	for (i = 0; i < num_elem; i++) {
-		_addr[i + 1] = addr[i];
-		_len[i + 1] = len[i];
-	}
-	if (sha1_vector(1 + num_elem, _addr, _len, mac))
-		return -1;
-
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with opad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x5c;
-
-	/* perform outer SHA1 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	_addr[1] = mac;
-	_len[1] = SHA1_MAC_LEN;
-	return sha1_vector(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (20 bytes)
- * Returns: 0 on success, -1 of failure
- */
-int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
-	       u8 *mac)
-{
-	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
-}
-
-
-/**
- * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- * Returns: 0 on success, -1 of failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key (e.g., PMK in IEEE 802.11i).
- */
-int sha1_prf(const u8 *key, size_t key_len, const char *label,
-	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
-{
-	u8 counter = 0;
-	size_t pos, plen;
-	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = os_strlen(label) + 1;
-	const unsigned char *addr[3];
-	size_t len[3];
-
-	addr[0] = (u8 *) label;
-	len[0] = label_len;
-	addr[1] = data;
-	len[1] = data_len;
-	addr[2] = &counter;
-	len[2] = 1;
-
-	pos = 0;
-	while (pos < buf_len) {
-		plen = buf_len - pos;
-		if (plen >= SHA1_MAC_LEN) {
-			if (hmac_sha1_vector(key, key_len, 3, addr, len,
-					     &buf[pos]))
-				return -1;
-			pos += SHA1_MAC_LEN;
-		} else {
-			if (hmac_sha1_vector(key, key_len, 3, addr, len,
-					     hash))
-				return -1;
-			os_memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		counter++;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/crypto/sha1.c (from rev 9639, vendor/wpa/dist/src/crypto/sha1.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,104 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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 "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @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 (20 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[20];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = SHA1(key) */
+        if (key_len > 64) {
+		if (sha1_vector(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 20;
+        }
+
+	/* the HMAC_SHA1 transform looks like:
+	 *
+	 * SHA1(K XOR opad, SHA1(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA1 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (sha1_vector(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA1 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = SHA1_MAC_LEN;
+	return sha1_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (20 bytes)
+ * Returns: 0 on success, -1 of failure
+ */
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}

Deleted: vendor/wpa/2.0/src/crypto/sha1.h
===================================================================
--- vendor/wpa/dist/src/crypto/sha1.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,33 +0,0 @@
-/*
- * SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef SHA1_H
-#define SHA1_H
-
-#define SHA1_MAC_LEN 20
-
-int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
-		     const u8 *addr[], const size_t *len, u8 *mac);
-int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
-	       u8 *mac);
-int sha1_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 sha1_t_prf(const u8 *key, size_t key_len, const char *label,
-	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
-int __must_check tls_prf(const u8 *secret, size_t secret_len,
-			 const char *label, const u8 *seed, size_t seed_len,
-			 u8 *out, size_t outlen);
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
-		int iterations, u8 *buf, size_t buflen);
-#endif /* SHA1_H */

Copied: vendor/wpa/2.0/src/crypto/sha1.h (from rev 9639, vendor/wpa/dist/src/crypto/sha1.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,27 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#define SHA1_MAC_LEN 20
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac);
+int sha1_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 sha1_t_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+				  const char *label, const u8 *seed,
+				  size_t seed_len, u8 *out, size_t outlen);
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen);
+#endif /* SHA1_H */

Deleted: vendor/wpa/2.0/src/crypto/sha1_i.h
===================================================================
--- vendor/wpa/dist/src/crypto/sha1_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha1_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,29 +0,0 @@
-/*
- * SHA1 internal definitions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef SHA1_I_H
-#define SHA1_I_H
-
-struct SHA1Context {
-	u32 state[5];
-	u32 count[2];
-	unsigned char buffer[64];
-};
-
-void SHA1Init(struct SHA1Context *context);
-void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
-void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
-void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
-
-#endif /* SHA1_I_H */

Copied: vendor/wpa/2.0/src/crypto/sha1_i.h (from rev 9639, vendor/wpa/dist/src/crypto/sha1_i.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha1_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha1_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * SHA1 internal definitions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA1_I_H
+#define SHA1_I_H
+
+struct SHA1Context {
+	u32 state[5];
+	u32 count[2];
+	unsigned char buffer[64];
+};
+
+void SHA1Init(struct SHA1Context *context);
+void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+
+#endif /* SHA1_I_H */

Deleted: vendor/wpa/2.0/src/crypto/sha256-internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha256-internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha256-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,243 +0,0 @@
-/*
- * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha256.h"
-#include "crypto.h"
-
-struct sha256_state {
-	u64 length;
-	u32 state[8], curlen;
-	u8 buf[64];
-};
-
-static void sha256_init(struct sha256_state *md);
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen);
-static int sha256_done(struct sha256_state *md, unsigned char *out);
-
-
-/**
- * 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 of failure
- */
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
-		  u8 *mac)
-{
-	struct sha256_state ctx;
-	size_t i;
-
-	sha256_init(&ctx);
-	for (i = 0; i < num_elem; i++)
-		if (sha256_process(&ctx, addr[i], len[i]))
-			return -1;
-	if (sha256_done(&ctx, mac))
-		return -1;
-	return 0;
-}
-
-
-/* ===== start - public domain SHA256 implementation ===== */
-
-/* This is based on SHA256 implementation in LibTomCrypt that was released into
- * public domain by Tom St Denis. */
-
-/* the K array */
-static const unsigned long K[64] = {
-	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
-	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
-	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
-	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
-	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
-	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
-	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
-	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
-	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
-	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
-	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
-	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
-	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
-};
-
-
-/* Various logical functions */
-#define RORc(x, y) \
-( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
-   ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
-#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
-#define Maj(x,y,z)      (((x | y) & z) | (x & y)) 
-#define S(x, n)         RORc((x), (n))
-#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
-#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
-#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
-#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
-#ifndef MIN
-#define MIN(x, y) (((x) < (y)) ? (x) : (y))
-#endif
-
-/* compress 512-bits */
-static int sha256_compress(struct sha256_state *md, unsigned char *buf)
-{
-	u32 S[8], W[64], t0, t1;
-	u32 t;
-	int i;
-
-	/* copy state into S */
-	for (i = 0; i < 8; i++) {
-		S[i] = md->state[i];
-	}
-
-	/* copy the state into 512-bits into W[0..15] */
-	for (i = 0; i < 16; i++)
-		W[i] = WPA_GET_BE32(buf + (4 * i));
-
-	/* fill W[16..63] */
-	for (i = 16; i < 64; i++) {
-		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
-			W[i - 16];
-	}        
-
-	/* Compress */
-#define RND(a,b,c,d,e,f,g,h,i)                          \
-	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
-	t1 = Sigma0(a) + Maj(a, b, c);			\
-	d += t0;					\
-	h  = t0 + t1;
-
-	for (i = 0; i < 64; ++i) {
-		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
-		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; 
-		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
-	}
-
-	/* feedback */
-	for (i = 0; i < 8; i++) {
-		md->state[i] = md->state[i] + S[i];
-	}
-	return 0;
-}
-
-
-/* Initialize the hash state */
-static void sha256_init(struct sha256_state *md)
-{
-	md->curlen = 0;
-	md->length = 0;
-	md->state[0] = 0x6A09E667UL;
-	md->state[1] = 0xBB67AE85UL;
-	md->state[2] = 0x3C6EF372UL;
-	md->state[3] = 0xA54FF53AUL;
-	md->state[4] = 0x510E527FUL;
-	md->state[5] = 0x9B05688CUL;
-	md->state[6] = 0x1F83D9ABUL;
-	md->state[7] = 0x5BE0CD19UL;
-}
-
-/**
-   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
-*/
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen)
-{
-	unsigned long n;
-#define block_size 64
-
-	if (md->curlen > sizeof(md->buf))
-		return -1;
-
-	while (inlen > 0) {
-		if (md->curlen == 0 && inlen >= block_size) {
-			if (sha256_compress(md, (unsigned char *) in) < 0)
-				return -1;
-			md->length += block_size * 8;
-			in += block_size;
-			inlen -= block_size;
-		} else {
-			n = MIN(inlen, (block_size - md->curlen));
-			os_memcpy(md->buf + md->curlen, in, n);
-			md->curlen += n;
-			in += n;
-			inlen -= n;
-			if (md->curlen == block_size) {
-				if (sha256_compress(md, md->buf) < 0)
-					return -1;
-				md->length += 8 * 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 (32 bytes)
-   @return CRYPT_OK if successful
-*/
-static int sha256_done(struct sha256_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 * 8;
-
-	/* append the '1' bit */
-	md->buf[md->curlen++] = (unsigned char) 0x80;
-
-	/* if the length is currently above 56 bytes we append zeros
-	 * then compress.  Then we can fall back to padding zeros and length
-	 * encoding like normal.
-	 */
-	if (md->curlen > 56) {
-		while (md->curlen < 64) {
-			md->buf[md->curlen++] = (unsigned char) 0;
-		}
-		sha256_compress(md, md->buf);
-		md->curlen = 0;
-	}
-
-	/* pad upto 56 bytes of zeroes */
-	while (md->curlen < 56) {
-		md->buf[md->curlen++] = (unsigned char) 0;
-	}
-
-	/* store length */
-	WPA_PUT_BE64(md->buf + 56, md->length);
-	sha256_compress(md, md->buf);
-
-	/* copy output */
-	for (i = 0; i < 8; i++)
-		WPA_PUT_BE32(out + (4 * i), md->state[i]);
-
-	return 0;
-}
-
-/* ===== end - public domain SHA256 implementation ===== */

Copied: vendor/wpa/2.0/src/crypto/sha256-internal.c (from rev 9639, vendor/wpa/dist/src/crypto/sha256-internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256-internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256-internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,226 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j at 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 "sha256.h"
+#include "sha256_i.h"
+#include "crypto.h"
+
+
+/**
+ * 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 of failure
+ */
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	struct sha256_state ctx;
+	size_t i;
+
+	sha256_init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		if (sha256_process(&ctx, addr[i], len[i]))
+			return -1;
+	if (sha256_done(&ctx, mac))
+		return -1;
+	return 0;
+}
+
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+
+/* Various logical functions */
+#define RORc(x, y) \
+( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
+   ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y)) 
+#define S(x, n)         RORc((x), (n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md, unsigned char *buf)
+{
+	u32 S[8], W[64], t0, t1;
+	u32 t;
+	int i;
+
+	/* copy state into S */
+	for (i = 0; i < 8; i++) {
+		S[i] = md->state[i];
+	}
+
+	/* copy the state into 512-bits into W[0..15] */
+	for (i = 0; i < 16; i++)
+		W[i] = WPA_GET_BE32(buf + (4 * i));
+
+	/* fill W[16..63] */
+	for (i = 16; i < 64; i++) {
+		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+			W[i - 16];
+	}        
+
+	/* Compress */
+#define RND(a,b,c,d,e,f,g,h,i)                          \
+	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
+	t1 = Sigma0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+	for (i = 0; i < 64; ++i) {
+		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; 
+		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+	}
+
+	/* feedback */
+	for (i = 0; i < 8; i++) {
+		md->state[i] = md->state[i] + S[i];
+	}
+	return 0;
+}
+
+
+/* Initialize the hash state */
+void sha256_init(struct sha256_state *md)
+{
+	md->curlen = 0;
+	md->length = 0;
+	md->state[0] = 0x6A09E667UL;
+	md->state[1] = 0xBB67AE85UL;
+	md->state[2] = 0x3C6EF372UL;
+	md->state[3] = 0xA54FF53AUL;
+	md->state[4] = 0x510E527FUL;
+	md->state[5] = 0x9B05688CUL;
+	md->state[6] = 0x1F83D9ABUL;
+	md->state[7] = 0x5BE0CD19UL;
+}
+
+/**
+   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 sha256_process(struct sha256_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 >= SHA256_BLOCK_SIZE) {
+			if (sha256_compress(md, (unsigned char *) in) < 0)
+				return -1;
+			md->length += SHA256_BLOCK_SIZE * 8;
+			in += SHA256_BLOCK_SIZE;
+			inlen -= SHA256_BLOCK_SIZE;
+		} else {
+			n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
+			os_memcpy(md->buf + md->curlen, in, n);
+			md->curlen += n;
+			in += n;
+			inlen -= n;
+			if (md->curlen == SHA256_BLOCK_SIZE) {
+				if (sha256_compress(md, md->buf) < 0)
+					return -1;
+				md->length += 8 * SHA256_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 (32 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha256_done(struct sha256_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 * 8;
+
+	/* append the '1' bit */
+	md->buf[md->curlen++] = (unsigned char) 0x80;
+
+	/* if the length is currently above 56 bytes we append zeros
+	 * then compress.  Then we can fall back to padding zeros and length
+	 * encoding like normal.
+	 */
+	if (md->curlen > 56) {
+		while (md->curlen < SHA256_BLOCK_SIZE) {
+			md->buf[md->curlen++] = (unsigned char) 0;
+		}
+		sha256_compress(md, md->buf);
+		md->curlen = 0;
+	}
+
+	/* pad up to 56 bytes of zeroes */
+	while (md->curlen < 56) {
+		md->buf[md->curlen++] = (unsigned char) 0;
+	}
+
+	/* store length */
+	WPA_PUT_BE64(md->buf + 56, md->length);
+	sha256_compress(md, md->buf);
+
+	/* copy output */
+	for (i = 0; i < 8; i++)
+		WPA_PUT_BE32(out + (4 * i), md->state[i]);
+
+	return 0;
+}
+
+/* ===== end - public domain SHA256 implementation ===== */

Copied: vendor/wpa/2.0/src/crypto/sha256-prf.c (from rev 9639, vendor/wpa/dist/src/crypto/sha256-prf.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256-prf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256-prf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,64 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2007, Jouni Malinen <j at 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 "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void 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)
+{
+	u16 counter = 1;
+	size_t pos, plen;
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+	u8 counter_le[2], length_le[2];
+
+	addr[0] = counter_le;
+	len[0] = 2;
+	addr[1] = (u8 *) label;
+	len[1] = os_strlen(label);
+	addr[2] = data;
+	len[2] = data_len;
+	addr[3] = length_le;
+	len[3] = sizeof(length_le);
+
+	WPA_PUT_LE16(length_le, buf_len * 8);
+	pos = 0;
+	while (pos < buf_len) {
+		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]);
+			pos += SHA256_MAC_LEN;
+		} else {
+			hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+}

Copied: vendor/wpa/2.0/src/crypto/sha256-tlsprf.c (from rev 9639, vendor/wpa/dist/src/crypto/sha256-tlsprf.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256-tlsprf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256-tlsprf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,66 @@
+/*
+ * TLS PRF P_SHA256
+ * Copyright (c) 2011, Jouni Malinen <j at 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 "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+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)
+{
+	size_t clen;
+	u8 A[SHA256_MAC_LEN];
+	u8 P[SHA256_MAC_LEN];
+	size_t pos;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = A;
+	len[0] = SHA256_MAC_LEN;
+	addr[1] = (unsigned char *) label;
+	len[1] = os_strlen(label);
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	/*
+	 * RFC 5246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+	 */
+
+	hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+	pos = 0;
+	while (pos < outlen) {
+		hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+		hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+		clen = outlen - pos;
+		if (clen > SHA256_MAC_LEN)
+			clen = SHA256_MAC_LEN;
+		os_memcpy(out + pos, P, clen);
+		pos += clen;
+	}
+}

Deleted: vendor/wpa/2.0/src/crypto/sha256.c
===================================================================
--- vendor/wpa/dist/src/crypto/sha256.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha256.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,157 +0,0 @@
-/*
- * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "sha256.h"
-#include "crypto.h"
-
-
-/**
- * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @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 (32 bytes)
- */
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
-			const u8 *addr[], const size_t *len, u8 *mac)
-{
-	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
-	unsigned char tk[32];
-	const u8 *_addr[6];
-	size_t _len[6], i;
-
-	if (num_elem > 5) {
-		/*
-		 * Fixed limit on the number of fragments to avoid having to
-		 * allocate memory (which could fail).
-		 */
-		return;
-	}
-
-        /* if key is longer than 64 bytes reset it to key = SHA256(key) */
-        if (key_len > 64) {
-		sha256_vector(1, &key, &key_len, tk);
-		key = tk;
-		key_len = 32;
-        }
-
-	/* the HMAC_SHA256 transform looks like:
-	 *
-	 * SHA256(K XOR opad, SHA256(K XOR ipad, text))
-	 *
-	 * where K is an n byte key
-	 * ipad is the byte 0x36 repeated 64 times
-	 * opad is the byte 0x5c repeated 64 times
-	 * and text is the data being protected */
-
-	/* start out by storing key in ipad */
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with ipad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x36;
-
-	/* perform inner SHA256 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	for (i = 0; i < num_elem; i++) {
-		_addr[i + 1] = addr[i];
-		_len[i + 1] = len[i];
-	}
-	sha256_vector(1 + num_elem, _addr, _len, mac);
-
-	os_memset(k_pad, 0, sizeof(k_pad));
-	os_memcpy(k_pad, key, key_len);
-	/* XOR key with opad values */
-	for (i = 0; i < 64; i++)
-		k_pad[i] ^= 0x5c;
-
-	/* perform outer SHA256 */
-	_addr[0] = k_pad;
-	_len[0] = 64;
-	_addr[1] = mac;
-	_len[1] = SHA256_MAC_LEN;
-	sha256_vector(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (20 bytes)
- */
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
-		 size_t data_len, u8 *mac)
-{
-	hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
-}
-
-
-/**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
- * @key: Key for PRF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the PRF
- * @data: Extra data to bind into the key
- * @data_len: Length of the data
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key.
- */
-void 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)
-{
-	u16 counter = 1;
-	size_t pos, plen;
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-	u8 counter_le[2], length_le[2];
-
-	addr[0] = counter_le;
-	len[0] = 2;
-	addr[1] = (u8 *) label;
-	len[1] = os_strlen(label);
-	addr[2] = data;
-	len[2] = data_len;
-	addr[3] = length_le;
-	len[3] = sizeof(length_le);
-
-	WPA_PUT_LE16(length_le, buf_len * 8);
-	pos = 0;
-	while (pos < buf_len) {
-		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]);
-			pos += SHA256_MAC_LEN;
-		} else {
-			hmac_sha256_vector(key, key_len, 4, addr, len, hash);
-			os_memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		counter++;
-	}
-}

Copied: vendor/wpa/2.0/src/crypto/sha256.c (from rev 9639, vendor/wpa/dist/src/crypto/sha256.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,104 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @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 (32 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[32];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = SHA256(key) */
+        if (key_len > 64) {
+		if (sha256_vector(1, &key, &key_len, tk) < 0)
+			return -1;
+		key = tk;
+		key_len = 32;
+        }
+
+	/* the HMAC_SHA256 transform looks like:
+	 *
+	 * SHA256(K XOR opad, SHA256(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0)
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = SHA256_MAC_LEN;
+	return sha256_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}

Deleted: vendor/wpa/2.0/src/crypto/sha256.h
===================================================================
--- vendor/wpa/dist/src/crypto/sha256.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/sha256.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,27 +0,0 @@
-/*
- * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef SHA256_H
-#define SHA256_H
-
-#define SHA256_MAC_LEN 32
-
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
-		      const u8 *addr[], const size_t *len, u8 *mac);
-void 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);
-
-#endif /* SHA256_H */

Copied: vendor/wpa/2.0/src/crypto/sha256.h (from rev 9639, vendor/wpa/dist/src/crypto/sha256.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,24 @@
+/*
+ * SHA256 hash implementation and interface functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#define SHA256_MAC_LEN 32
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac);
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void 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);
+
+#endif /* SHA256_H */

Copied: vendor/wpa/2.0/src/crypto/sha256_i.h (from rev 9639, vendor/wpa/dist/src/crypto/sha256_i.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/sha256_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/sha256_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,25 @@
+/*
+ * SHA-256 internal definitions
+ * Copyright (c) 2003-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */

Deleted: vendor/wpa/2.0/src/crypto/tls.h
===================================================================
--- vendor/wpa/dist/src/crypto/tls.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,569 +0,0 @@
-/*
- * SSL/TLS interface definition
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLS_H
-#define TLS_H
-
-struct tls_connection;
-
-struct tls_keys {
-	const u8 *master_key; /* TLS master secret */
-	size_t master_key_len;
-	const u8 *client_random;
-	size_t client_random_len;
-	const u8 *server_random;
-	size_t server_random_len;
-	const u8 *inner_secret; /* TLS/IA inner secret */
-	size_t inner_secret_len;
-};
-
-enum tls_event {
-	TLS_CERT_CHAIN_FAILURE,
-	TLS_PEER_CERTIFICATE
-};
-
-/*
- * 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
-};
-
-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;
-	} peer_cert;
-};
-
-struct tls_config {
-	const char *opensc_engine_path;
-	const char *pkcs11_engine_path;
-	const char *pkcs11_module_path;
-	int fips_mode;
-
-	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)
-
-/**
- * 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
- * @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
- * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
- * @flags: Parameter options (TLS_CONN_*)
- *
- * 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 *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;
-	int tls_ia;
-
-	/* 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;
-
-	unsigned int flags;
-};
-
-
-/**
- * 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_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 possible PIN 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.
- */
-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 possible PIN 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.
- */
-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
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_set_verify(void *tls_ctx,
-					   struct tls_connection *conn,
-					   int verify_peer);
-
-/**
- * tls_connection_set_ia - Set TLS/IA parameters
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @tls_ia: 1 = enable TLS/IA
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to configure TLS/IA in server mode where
- * tls_connection_set_params() is not used.
- */
-int __must_check tls_connection_set_ia(void *tls_ctx,
-				       struct tls_connection *conn,
-				       int tls_ia);
-
-/**
- * tls_connection_get_keys - Get master key and random data from TLS connection
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @keys: Structure of key/random data (filled on success)
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_get_keys(void *tls_ctx,
-					 struct tls_connection *conn,
-					 struct tls_keys *keys);
-
-/**
- * tls_connection_prf - Use TLS-PRF to derive keying material
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @out: Buffer for output data from TLS-PRF
- * @out_len: Length of the output buffer
- * Returns: 0 on success, -1 on failure
- *
- * This function is optional to implement if tls_connection_get_keys() provides
- * access to master secret and server/client random values. If these values are
- * not exported from the TLS library, tls_connection_prf() is required so that
- * further keying material can be derived from the master secret. If not
- * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf() function
- * when it is called with seed set to client_random|server_random (or
- * server_random|client_random).
- */
-int __must_check  tls_connection_prf(void *tls_ctx,
-				     struct tls_connection *conn,
-				     const char *label,
-				     int server_random_first,
-				     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);
-
-/**
- * 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);
-
-/**
- * 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_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_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);
-
-/**
- * tls_connection_get_keyblock_size - Get TLS key_block size
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn);
-
-#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
-/**
- * tls_capabilities - Get supported TLS capabilities
- * @tls_ctx: TLS context data from tls_init()
- * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
- */
-unsigned int tls_capabilities(void *tls_ctx);
-
-/**
- * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
- * Returns: Encrypted TLS/IA data, %NULL on failure
- *
- * This function is used to send the TLS/IA end phase message, e.g., when the
- * EAP server completes EAP-TTLSv1.
- */
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-
-/**
- * tls_connection_ia_final_phase_finished - Has final phase been completed
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
- * on failure
- */
-int __must_check tls_connection_ia_final_phase_finished(
-	void *tls_ctx, struct tls_connection *conn);
-
-/**
- * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: Session key material (session_key vectors with 2-octet length), or
- * %NULL if no session key was generating in the current phase
- * @key_len: Length of session key material
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_ia_permute_inner_secret(
-	void *tls_ctx, struct tls_connection *conn,
-	const u8 *key, size_t key_len);
-
-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);
-
-#endif /* TLS_H */

Copied: vendor/wpa/2.0/src/crypto/tls.h (from rev 9639, vendor/wpa/dist/src/crypto/tls.h)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls.h	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,529 @@
+/*
+ * SSL/TLS interface definition
+ * Copyright (c) 2004-2010, Jouni Malinen <j at 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
+
+struct tls_connection;
+
+struct tls_keys {
+	const u8 *master_key; /* TLS master secret */
+	size_t master_key_len;
+	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
+};
+
+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;
+	} 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;
+
+	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)
+
+/**
+ * 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
+ * @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
+ * @flags: Parameter options (TLS_CONN_*)
+ *
+ * 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 *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;
+
+	unsigned int flags;
+};
+
+
+/**
+ * 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_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 possible PIN 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.
+ */
+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 possible PIN 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.
+ */
+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
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_set_verify(void *tls_ctx,
+					   struct tls_connection *conn,
+					   int verify_peer);
+
+/**
+ * tls_connection_get_keys - Get master key and random data from TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_get_keys(void *tls_ctx,
+					 struct tls_connection *conn,
+					 struct tls_keys *keys);
+
+/**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int __must_check  tls_connection_prf(void *tls_ctx,
+				     struct tls_connection *conn,
+				     const char *label,
+				     int server_random_first,
+				     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_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_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);
+
+/**
+ * tls_connection_get_keyblock_size - Get TLS key_block size
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn);
+
+/**
+ * tls_capabilities - Get supported TLS capabilities
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
+ */
+unsigned int tls_capabilities(void *tls_ctx);
+
+typedef int (*tls_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+int __must_check  tls_connection_set_session_ticket_cb(
+	void *tls_ctx, struct tls_connection *conn,
+	tls_session_ticket_cb cb, void *ctx);
+
+#endif /* TLS_H */

Deleted: vendor/wpa/2.0/src/crypto/tls_gnutls.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_gnutls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1457 +0,0 @@
-/*
- * SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#ifdef PKCS12_FUNCS
-#include <gnutls/pkcs12.h>
-#endif /* PKCS12_FUNCS */
-
-#ifdef CONFIG_GNUTLS_EXTRA
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-#define GNUTLS_IA
-#include <gnutls/extra.h>
-#if LIBGNUTLS_VERSION_NUMBER == 0x010302
-/* This function is not included in the current gnutls/extra.h even though it
- * should be, so define it here as a workaround for the time being. */
-int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
-#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* CONFIG_GNUTLS_EXTRA */
-
-#include "common.h"
-#include "tls.h"
-
-
-#ifndef TLS_RANDOM_SIZE
-#define TLS_RANDOM_SIZE 32
-#endif
-#ifndef TLS_MASTER_SIZE
-#define TLS_MASTER_SIZE 48
-#endif
-
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x010302
-/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
- * use of internal structures to get the master_secret and
- * {server,client}_random.
- */
-#define GNUTLS_INTERNAL_STRUCTURE_HACK
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-/*
- * It looks like gnutls does not provide access to client/server_random and
- * master_key. This is somewhat unfortunate since these are needed for key
- * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
- * hack that copies the gnutls_session_int definition from gnutls_int.h so that
- * we can get the needed information.
- */
-
-typedef u8 uint8;
-typedef unsigned char opaque;
-typedef struct {
-    uint8 suite[2];
-} cipher_suite_st;
-
-typedef struct {
-	gnutls_connection_end_t entity;
-	gnutls_kx_algorithm_t kx_algorithm;
-	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
-	gnutls_mac_algorithm_t read_mac_algorithm;
-	gnutls_compression_method_t read_compression_algorithm;
-	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
-	gnutls_mac_algorithm_t write_mac_algorithm;
-	gnutls_compression_method_t write_compression_algorithm;
-	cipher_suite_st current_cipher_suite;
-	opaque master_secret[TLS_MASTER_SIZE];
-	opaque client_random[TLS_RANDOM_SIZE];
-	opaque server_random[TLS_RANDOM_SIZE];
-	/* followed by stuff we are not interested in */
-} security_parameters_st;
-
-struct gnutls_session_int {
-	security_parameters_st security_parameters;
-	/* followed by things we are not interested in */
-};
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
-static int tls_gnutls_ref_count = 0;
-
-struct tls_global {
-	/* Data for session resumption */
-	void *session_data;
-	size_t session_data_size;
-
-	int server;
-
-	int params_set;
-	gnutls_certificate_credentials_t xcred;
-};
-
-struct tls_connection {
-	gnutls_session session;
-	char *subject_match, *altsubject_match;
-	int read_alerts, write_alerts, failed;
-
-	u8 *pre_shared_secret;
-	size_t pre_shared_secret_len;
-	int established;
-	int verify_peer;
-
-	struct wpabuf *push_buf;
-	struct wpabuf *pull_buf;
-	const u8 *pull_buf_offset;
-
-	int params_set;
-	gnutls_certificate_credentials_t xcred;
-
-	int tls_ia;
-	int final_phase_finished;
-
-#ifdef GNUTLS_IA
-	gnutls_ia_server_credentials_t iacred_srv;
-	gnutls_ia_client_credentials_t iacred_cli;
-
-	/* Session keys generated in the current phase for inner secret
-	 * permutation before generating/verifying PhaseFinished. */
-	u8 *session_keys;
-	size_t session_keys_len;
-
-	u8 inner_secret[TLS_MASTER_SIZE];
-#endif /* GNUTLS_IA */
-};
-
-
-static void tls_log_func(int level, const char *msg)
-{
-	char *s, *pos;
-	if (level == 6 || level == 7) {
-		/* These levels seem to be mostly I/O debug and msg dumps */
-		return;
-	}
-
-	s = os_strdup(msg);
-	if (s == NULL)
-		return;
-
-	pos = s;
-	while (*pos != '\0') {
-		if (*pos == '\n') {
-			*pos = '\0';
-			break;
-		}
-		pos++;
-	}
-	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
-		   "gnutls<%d> %s", level, s);
-	os_free(s);
-}
-
-
-extern int wpa_debug_show_keys;
-
-void * tls_init(const struct tls_config *conf)
-{
-	struct tls_global *global;
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	/* Because of the horrible hack to get master_secret and client/server
-	 * random, we need to make sure that the gnutls version is something
-	 * that is expected to have same structure definition for the session
-	 * data.. */
-	const char *ver;
-	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
-				 "1.3.2",
-				 NULL };
-	int i;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
-	global = os_zalloc(sizeof(*global));
-	if (global == NULL)
-		return NULL;
-
-	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
-		os_free(global);
-		return NULL;
-	}
-	tls_gnutls_ref_count++;
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	ver = gnutls_check_version(NULL);
-	if (ver == NULL) {
-		tls_deinit(global);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
-	for (i = 0; ok_ver[i]; i++) {
-		if (strcmp(ok_ver[i], ver) == 0)
-			break;
-	}
-	if (ok_ver[i] == NULL) {
-		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
-			   "to be tested and enabled in tls_gnutls.c", ver);
-		tls_deinit(global);
-		return NULL;
-	}
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
-	gnutls_global_set_log_function(tls_log_func);
-	if (wpa_debug_show_keys)
-		gnutls_global_set_log_level(11);
-	return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
-	struct tls_global *global = ssl_ctx;
-	if (global) {
-		if (global->params_set)
-			gnutls_certificate_free_credentials(global->xcred);
-		os_free(global->session_data);
-		os_free(global);
-	}
-
-	tls_gnutls_ref_count--;
-	if (tls_gnutls_ref_count == 0)
-		gnutls_global_deinit();
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
-	return 0;
-}
-
-
-static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
-			     size_t len)
-{
-	struct tls_connection *conn = (struct tls_connection *) ptr;
-	const u8 *end;
-	if (conn->pull_buf == NULL) {
-		errno = EWOULDBLOCK;
-		return -1;
-	}
-
-	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
-	if ((size_t) (end - conn->pull_buf_offset) < len)
-		len = end - conn->pull_buf_offset;
-	os_memcpy(buf, conn->pull_buf_offset, len);
-	conn->pull_buf_offset += len;
-	if (conn->pull_buf_offset == end) {
-		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
-		wpabuf_free(conn->pull_buf);
-		conn->pull_buf = NULL;
-		conn->pull_buf_offset = NULL;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
-			   __func__,
-			   (unsigned long) (end - conn->pull_buf_offset));
-	}
-	return len;
-}
-
-
-static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
-			     size_t len)
-{
-	struct tls_connection *conn = (struct tls_connection *) ptr;
-
-	if (wpabuf_resize(&conn->push_buf, len) < 0) {
-		errno = ENOMEM;
-		return -1;
-	}
-	wpabuf_put_data(conn->push_buf, buf, len);
-
-	return len;
-}
-
-
-static int tls_gnutls_init_session(struct tls_global *global,
-				   struct tls_connection *conn)
-{
-	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
-	const int protos[2] = { GNUTLS_TLS1, 0 };
-	int ret;
-
-	ret = gnutls_init(&conn->session,
-			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
-	if (ret < 0) {
-		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
-			   "connection: %s", gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_set_default_priority(conn->session);
-	if (ret < 0)
-		goto fail;
-
-	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
-	if (ret < 0)
-		goto fail;
-
-	ret = gnutls_protocol_set_priority(conn->session, protos);
-	if (ret < 0)
-		goto fail;
-
-	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
-	gnutls_transport_set_push_function(conn->session, tls_push_func);
-	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
-
-	return 0;
-
-fail:
-	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
-		   gnutls_strerror(ret));
-	gnutls_deinit(conn->session);
-	return -1;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
-	struct tls_global *global = ssl_ctx;
-	struct tls_connection *conn;
-	int ret;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-	if (tls_gnutls_init_session(global, conn)) {
-		os_free(conn);
-		return NULL;
-	}
-
-	if (global->params_set) {
-		ret = gnutls_credentials_set(conn->session,
-					     GNUTLS_CRD_CERTIFICATE,
-					     global->xcred);
-		if (ret < 0) {
-			wpa_printf(MSG_INFO, "Failed to configure "
-				   "credentials: %s", gnutls_strerror(ret));
-			os_free(conn);
-			return NULL;
-		}
-	}
-
-	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
-		os_free(conn);
-		return NULL;
-	}
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return;
-
-#ifdef GNUTLS_IA
-	if (conn->iacred_srv)
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-#endif /* GNUTLS_IA */
-
-	gnutls_certificate_free_credentials(conn->xcred);
-	gnutls_deinit(conn->session);
-	os_free(conn->pre_shared_secret);
-	os_free(conn->subject_match);
-	os_free(conn->altsubject_match);
-	wpabuf_free(conn->push_buf);
-	wpabuf_free(conn->pull_buf);
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
-	return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
-	struct tls_global *global = ssl_ctx;
-	int ret;
-
-	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. */
-	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
-	wpabuf_free(conn->push_buf);
-	conn->push_buf = NULL;
-	conn->established = 0;
-	conn->final_phase_finished = 0;
-#ifdef GNUTLS_IA
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-#endif /* GNUTLS_IA */
-
-	gnutls_deinit(conn->session);
-	if (tls_gnutls_init_session(global, conn)) {
-		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
-			   "for session resumption use");
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
-				     conn->params_set ? conn->xcred :
-				     global->xcred);
-	if (ret < 0) {
-		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
-			   "for session resumption: %s", gnutls_strerror(ret));
-		return -1;
-	}
-
-	if (global->session_data) {
-		ret = gnutls_session_set_data(conn->session,
-					      global->session_data,
-					      global->session_data_size);
-		if (ret < 0) {
-			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
-				   "data: %s", gnutls_strerror(ret));
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-#if 0
-static int tls_match_altsubject(X509 *cert, const char *match)
-{
-	GENERAL_NAME *gen;
-	char *field, *tmp;
-	void *ext;
-	int i, found = 0;
-	size_t len;
-
-	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);
-		switch (gen->type) {
-		case GEN_EMAIL:
-			field = "EMAIL";
-			break;
-		case GEN_DNS:
-			field = "DNS";
-			break;
-		case GEN_URI:
-			field = "URI";
-			break;
-		default:
-			field = NULL;
-			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
-				   "unsupported type=%d", gen->type);
-			break;
-		}
-
-		if (!field)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
-			   field, gen->d.ia5->data);
-		len = os_strlen(field) + 1 +
-			strlen((char *) gen->d.ia5->data) + 1;
-		tmp = os_malloc(len);
-		if (tmp == NULL)
-			continue;
-		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
-		if (strstr(tmp, match))
-			found++;
-		os_free(tmp);
-	}
-
-	return found;
-}
-#endif
-
-
-#if 0
-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;
-	char *match, *altmatch;
-
-	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
-	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);
-	match = conn ? conn->subject_match : NULL;
-	altmatch = conn ? conn->altsubject_match : NULL;
-
-	if (!preverify_ok) {
-		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
-			   " error %d (%s) depth %d for '%s'", err,
-			   X509_verify_cert_error_string(err), depth, buf);
-	} else {
-		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
-			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
-			   preverify_ok, err,
-			   X509_verify_cert_error_string(err), depth, buf);
-		if (depth == 0 && match && strstr(buf, match) == NULL) {
-			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
-				   "match with '%s'", buf, match);
-			preverify_ok = 0;
-		} else if (depth == 0 && altmatch &&
-			   !tls_match_altsubject(err_cert, altmatch)) {
-			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
-				   "'%s' not found", altmatch);
-			preverify_ok = 0;
-		}
-	}
-
-	return preverify_ok;
-}
-#endif
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	int ret;
-
-	if (conn == NULL || params == NULL)
-		return -1;
-
-	os_free(conn->subject_match);
-	conn->subject_match = NULL;
-	if (params->subject_match) {
-		conn->subject_match = os_strdup(params->subject_match);
-		if (conn->subject_match == NULL)
-			return -1;
-	}
-
-	os_free(conn->altsubject_match);
-	conn->altsubject_match = NULL;
-	if (params->altsubject_match) {
-		conn->altsubject_match = os_strdup(params->altsubject_match);
-		if (conn->altsubject_match == NULL)
-			return -1;
-	}
-
-	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
-	 * to force peer validation(?) */
-
-	if (params->ca_cert) {
-		conn->verify_peer = 1;
-		ret = gnutls_certificate_set_x509_trust_file(
-			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
-		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
-				   "in PEM format: %s", params->ca_cert,
-				   gnutls_strerror(ret));
-			ret = gnutls_certificate_set_x509_trust_file(
-				conn->xcred, params->ca_cert,
-				GNUTLS_X509_FMT_DER);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
-					   "'%s' in DER format: %s",
-					   params->ca_cert,
-					   gnutls_strerror(ret));
-				return -1;
-			}
-		}
-
-		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
-			gnutls_certificate_set_verify_flags(
-				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
-		}
-
-		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
-			gnutls_certificate_set_verify_flags(
-				conn->xcred,
-				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
-		}
-	}
-
-	if (params->client_cert && params->private_key) {
-		/* TODO: private_key_passwd? */
-		ret = gnutls_certificate_set_x509_key_file(
-			conn->xcred, params->client_cert, params->private_key,
-			GNUTLS_X509_FMT_PEM);
-		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
-				   "in PEM format: %s", gnutls_strerror(ret));
-			ret = gnutls_certificate_set_x509_key_file(
-				conn->xcred, params->client_cert,
-				params->private_key, GNUTLS_X509_FMT_DER);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "Failed to read client "
-					   "cert/key in DER format: %s",
-					   gnutls_strerror(ret));
-				return ret;
-			}
-		}
-	} else if (params->private_key) {
-		int pkcs12_ok = 0;
-#ifdef PKCS12_FUNCS
-		/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
-			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
-			params->private_key_passwd);
-		if (ret != 0) {
-			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
-				   "PKCS#12 format: %s", gnutls_strerror(ret));
-			return -1;
-		} else
-			pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* PKCS12_FUNCS */
-
-		if (!pkcs12_ok) {
-			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
-				   "included");
-			return -1;
-		}
-	}
-
-	conn->tls_ia = params->tls_ia;
-	conn->params_set = 1;
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
-				     conn->xcred);
-	if (ret < 0) {
-		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
-			   gnutls_strerror(ret));
-	}
-
-#ifdef GNUTLS_IA
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-
-	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-		conn->iacred_cli = NULL;
-		return -1;
-	}
-#endif /* GNUTLS_IE */
-
-	return ret;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	struct tls_global *global = tls_ctx;
-	int ret;
-
-	/* Currently, global parameters are only set when running in server
-	 * mode. */
-	global->server = 1;
-
-	if (global->params_set) {
-		gnutls_certificate_free_credentials(global->xcred);
-		global->params_set = 0;
-	}
-
-	ret = gnutls_certificate_allocate_credentials(&global->xcred);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
-			   "%s", gnutls_strerror(ret));
-		return -1;
-	}
-
-	if (params->ca_cert) {
-		ret = gnutls_certificate_set_x509_trust_file(
-			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
-		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
-				   "in PEM format: %s", params->ca_cert,
-				   gnutls_strerror(ret));
-			ret = gnutls_certificate_set_x509_trust_file(
-				global->xcred, params->ca_cert,
-				GNUTLS_X509_FMT_DER);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
-					   "'%s' in DER format: %s",
-					   params->ca_cert,
-					   gnutls_strerror(ret));
-				goto fail;
-			}
-		}
-
-		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
-			gnutls_certificate_set_verify_flags(
-				global->xcred,
-				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
-		}
-
-		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
-			gnutls_certificate_set_verify_flags(
-				global->xcred,
-				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
-		}
-	}
-
-	if (params->client_cert && params->private_key) {
-		/* TODO: private_key_passwd? */
-		ret = gnutls_certificate_set_x509_key_file(
-			global->xcred, params->client_cert,
-			params->private_key, GNUTLS_X509_FMT_PEM);
-		if (ret < 0) {
-			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
-				   "in PEM format: %s", gnutls_strerror(ret));
-			ret = gnutls_certificate_set_x509_key_file(
-				global->xcred, params->client_cert,
-				params->private_key, GNUTLS_X509_FMT_DER);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "Failed to read client "
-					   "cert/key in DER format: %s",
-					   gnutls_strerror(ret));
-				goto fail;
-			}
-		}
-	} else if (params->private_key) {
-		int pkcs12_ok = 0;
-#ifdef PKCS12_FUNCS
-		/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
-			global->xcred, params->private_key,
-			GNUTLS_X509_FMT_DER, params->private_key_passwd);
-		if (ret != 0) {
-			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
-				   "PKCS#12 format: %s", gnutls_strerror(ret));
-			goto fail;
-		} else
-			pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* PKCS12_FUNCS */
-
-		if (!pkcs12_ok) {
-			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
-				   "included");
-			goto fail;
-		}
-	}
-
-	global->params_set = 1;
-
-	return 0;
-
-fail:
-	gnutls_certificate_free_credentials(global->xcred);
-	return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
-	/* TODO */
-	return 0;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	if (conn == NULL || conn->session == NULL)
-		return -1;
-
-	conn->verify_peer = verify_peer;
-	gnutls_certificate_server_set_request(conn->session,
-					      verify_peer ? GNUTLS_CERT_REQUIRE
-					      : GNUTLS_CERT_REQUEST);
-
-	return 0;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	security_parameters_st *sec;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
-	if (conn == NULL || conn->session == NULL || keys == NULL)
-		return -1;
-
-	os_memset(keys, 0, sizeof(*keys));
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-	sec = &conn->session->security_parameters;
-	keys->master_key = sec->master_secret;
-	keys->master_key_len = TLS_MASTER_SIZE;
-	keys->client_random = sec->client_random;
-	keys->server_random = sec->server_random;
-#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-	keys->client_random =
-		(u8 *) gnutls_session_get_client_random(conn->session);
-	keys->server_random =
-		(u8 *) gnutls_session_get_server_random(conn->session);
-	/* No access to master_secret */
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
-#ifdef GNUTLS_IA
-	gnutls_ia_extract_inner_secret(conn->session,
-				       (char *) conn->inner_secret);
-	keys->inner_secret = conn->inner_secret;
-	keys->inner_secret_len = TLS_MASTER_SIZE;
-#endif /* GNUTLS_IA */
-
-	keys->client_random_len = TLS_RANDOM_SIZE;
-	keys->server_random_len = TLS_RANDOM_SIZE;
-
-	return 0;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-	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);
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-	return -1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-}
-
-
-static int tls_connection_verify_peer(struct tls_connection *conn,
-				      gnutls_alert_description_t *err)
-{
-	unsigned int status, num_certs, i;
-	struct os_time now;
-	const gnutls_datum_t *certs;
-	gnutls_x509_crt_t cert;
-
-	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
-		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
-			   "certificate chain");
-		*err = GNUTLS_A_INTERNAL_ERROR;
-		return -1;
-	}
-
-	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
-		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
-		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
-			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
-				   "algorithm");
-			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
-		}
-		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
-			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
-				   "activated");
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
-		}
-		if (status & GNUTLS_CERT_EXPIRED) {
-			wpa_printf(MSG_INFO, "TLS: Certificate expired");
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
-		}
-		return -1;
-	}
-
-	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
-		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
-			   "known issuer");
-		*err = GNUTLS_A_UNKNOWN_CA;
-		return -1;
-	}
-
-	if (status & GNUTLS_CERT_REVOKED) {
-		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
-		*err = GNUTLS_A_CERTIFICATE_REVOKED;
-		return -1;
-	}
-
-	os_get_time(&now);
-
-	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
-	if (certs == NULL) {
-		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
-			   "received");
-		*err = GNUTLS_A_UNKNOWN_CA;
-		return -1;
-	}
-
-	for (i = 0; i < num_certs; i++) {
-		char *buf;
-		size_t len;
-		if (gnutls_x509_crt_init(&cert) < 0) {
-			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
-				   "failed");
-			*err = GNUTLS_A_BAD_CERTIFICATE;
-			return -1;
-		}
-
-		if (gnutls_x509_crt_import(cert, &certs[i],
-					   GNUTLS_X509_FMT_DER) < 0) {
-			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
-				   "certificate %d/%d", i + 1, num_certs);
-			gnutls_x509_crt_deinit(cert);
-			*err = GNUTLS_A_BAD_CERTIFICATE;
-			return -1;
-		}
-
-		gnutls_x509_crt_get_dn(cert, NULL, &len);
-		len++;
-		buf = os_malloc(len + 1);
-		if (buf) {
-			buf[0] = buf[len] = '\0';
-			gnutls_x509_crt_get_dn(cert, buf, &len);
-		}
-		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
-			   i + 1, num_certs, buf);
-
-		if (i == 0) {
-			/* TODO: validate subject_match and altsubject_match */
-		}
-
-		os_free(buf);
-
-		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
-		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
-			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
-				   "not valid at this time",
-				   i + 1, num_certs);
-			gnutls_x509_crt_deinit(cert);
-			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
-			return -1;
-		}
-
-		gnutls_x509_crt_deinit(cert);
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
-{
-	int res;
-	struct wpabuf *ad;
-	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
-	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
-	if (ad == NULL)
-		return NULL;
-
-	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
-				 wpabuf_size(ad));
-	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
-			   "(%s)", __func__, (int) res,
-			   gnutls_strerror(res));
-		wpabuf_free(ad);
-		return NULL;
-	}
-
-	wpabuf_put(ad, res);
-	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
-		   res);
-	return ad;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	struct tls_global *global = tls_ctx;
-	struct wpabuf *out_data;
-	int ret;
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	if (in_data && wpabuf_len(in_data) > 0) {
-		if (conn->pull_buf) {
-			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-				   "pull_buf", __func__,
-				   (unsigned long) wpabuf_len(conn->pull_buf));
-			wpabuf_free(conn->pull_buf);
-		}
-		conn->pull_buf = wpabuf_dup(in_data);
-		if (conn->pull_buf == NULL)
-			return NULL;
-		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
-	}
-
-	ret = gnutls_handshake(conn->session);
-	if (ret < 0) {
-		switch (ret) {
-		case GNUTLS_E_AGAIN:
-			if (global->server && conn->established &&
-			    conn->push_buf == NULL) {
-				/* Need to return something to trigger
-				 * completion of EAP-TLS. */
-				conn->push_buf = wpabuf_alloc(0);
-			}
-			break;
-		case GNUTLS_E_FATAL_ALERT_RECEIVED:
-			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
-				   __func__, gnutls_alert_get_name(
-					   gnutls_alert_get(conn->session)));
-			conn->read_alerts++;
-			/* continue */
-		default:
-			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
-				   "-> %s", __func__, gnutls_strerror(ret));
-			conn->failed++;
-		}
-	} else {
-		size_t size;
-		gnutls_alert_description_t err;
-
-		if (conn->verify_peer &&
-		    tls_connection_verify_peer(conn, &err)) {
-			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
-				   "failed validation");
-			conn->failed++;
-			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
-			goto out;
-		}
-
-#ifdef CONFIG_GNUTLS_EXTRA
-		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
-			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
-			conn->failed++;
-			return NULL;
-		}
-#endif /* CONFIG_GNUTLS_EXTRA */
-
-		if (conn->tls_ia)
-			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
-		else {
-			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
-				   "successfully");
-		}
-		conn->established = 1;
-		if (conn->push_buf == NULL) {
-			/* Need to return something to get final TLS ACK. */
-			conn->push_buf = wpabuf_alloc(0);
-		}
-
-		gnutls_session_get_data(conn->session, NULL, &size);
-		if (global->session_data == NULL ||
-		    global->session_data_size < size) {
-			os_free(global->session_data);
-			global->session_data = os_malloc(size);
-		}
-		if (global->session_data) {
-			global->session_data_size = size;
-			gnutls_session_get_data(conn->session,
-						global->session_data,
-						&global->session_data_size);
-		}
-
-		if (conn->pull_buf && appl_data)
-			*appl_data = gnutls_get_appl_data(conn);
-	}
-
-out:
-	out_data = conn->push_buf;
-	conn->push_buf = NULL;
-	return out_data;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	ssize_t res;
-	struct wpabuf *buf;
-
-#ifdef GNUTLS_IA
-	if (conn->tls_ia)
-		res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
-				     wpabuf_len(in_data));
-	else
-#endif /* GNUTLS_IA */
-	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
-				 wpabuf_len(in_data));
-	if (res < 0) {
-		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
-			   __func__, gnutls_strerror(res));
-		return NULL;
-	}
-
-	buf = conn->push_buf;
-	conn->push_buf = NULL;
-	return buf;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	ssize_t res;
-	struct wpabuf *out;
-
-	if (conn->pull_buf) {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-			   "pull_buf", __func__,
-			   (unsigned long) wpabuf_len(conn->pull_buf));
-		wpabuf_free(conn->pull_buf);
-	}
-	conn->pull_buf = wpabuf_dup(in_data);
-	if (conn->pull_buf == NULL)
-		return NULL;
-	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
-
-	/*
-	 * 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.
-	 */
-	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-	if (out == NULL)
-		return NULL;
-
-#ifdef GNUTLS_IA
-	if (conn->tls_ia) {
-		res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
-				     wpabuf_size(out));
-		if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-		    res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
-			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
-			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
-				   __func__, final ? "Final" : "Intermediate");
-
-			res = gnutls_ia_permute_inner_secret(
-				conn->session, conn->session_keys_len,
-				(char *) conn->session_keys);
-			if (conn->session_keys) {
-				os_memset(conn->session_keys, 0,
-					  conn->session_keys_len);
-				os_free(conn->session_keys);
-			}
-			conn->session_keys = NULL;
-			conn->session_keys_len = 0;
-			if (res) {
-				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
-					   "inner secret: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			res = gnutls_ia_verify_endphase(conn->session,
-							wpabuf_head(out));
-			if (res == 0) {
-				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
-					   "checksum", __func__);
-			} else {
-				wpa_printf(MSG_INFO, "%s: Endphase "
-					   "verification failed: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			if (final)
-				conn->final_phase_finished = 1;
-
-			return out;
-		}
-
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
-				   "(%s)", __func__, (int) res,
-				   gnutls_strerror(res));
-			wpabuf_free(out);
-			return NULL;
-		}
-		wpabuf_put(out, res);
-		return out;
-	}
-#endif /* GNUTLS_IA */
-
-	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
-				 wpabuf_size(out));
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
-			   "(%s)", __func__, (int) res, gnutls_strerror(res));
-		wpabuf_free(out);
-		return NULL;
-	}
-	wpabuf_put(out, res);
-
-	return out;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return 0;
-	return gnutls_session_is_resumed(conn->session);
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	/* TODO */
-	return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	/* TODO */
-	buf[0] = '\0';
-	return 0;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
-				     struct tls_connection *conn)
-{
-	gnutls_record_disable_padding(conn->session);
-	return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	/* TODO */
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->write_alerts;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	/* TODO */
-	return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	unsigned int capa = 0;
-
-#ifdef GNUTLS_IA
-	capa |= TLS_CAPABILITY_IA;
-#endif /* GNUTLS_IA */
-
-	return capa;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-#ifdef GNUTLS_IA
-	int ret;
-
-	if (conn == NULL)
-		return -1;
-
-	conn->tls_ia = tls_ia;
-	if (!tls_ia)
-		return 0;
-
-	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-		conn->iacred_srv = NULL;
-		return -1;
-	}
-
-	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-#ifdef GNUTLS_IA
-	int ret;
-	struct wpabuf *buf;
-
-	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
-		return NULL;
-
-	ret = gnutls_ia_permute_inner_secret(conn->session,
-					     conn->session_keys_len,
-					     (char *) conn->session_keys);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys = NULL;
-	conn->session_keys_len = 0;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	ret = gnutls_ia_endphase_send(conn->session, final);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	buf = conn->push_buf;
-	conn->push_buf = NULL;
-	return buf;
-#else /* GNUTLS_IA */
-	return NULL;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-
-	return conn->final_phase_finished;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-#ifdef GNUTLS_IA
-	if (conn == NULL || !conn->tls_ia)
-		return -1;
-
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-
-	if (key) {
-		conn->session_keys = os_malloc(key_len);
-		if (conn->session_keys == NULL)
-			return -1;
-		os_memcpy(conn->session_keys, key, key_len);
-		conn->session_keys_len = key_len;
-	} else {
-		conn->session_keys = NULL;
-		conn->session_keys_len = 0;
-	}
-
-	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
-					 struct tls_connection *conn,
-					 tls_session_ticket_cb cb, void *ctx)
-{
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/tls_gnutls.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_gnutls.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_gnutls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_gnutls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1192 @@
+/*
+ * SSL/TLS interface functions for GnuTLS
+ * Copyright (c) 2004-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#ifdef PKCS12_FUNCS
+#include <gnutls/pkcs12.h>
+#endif /* PKCS12_FUNCS */
+
+#include "common.h"
+#include "tls.h"
+
+
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
+
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x010302
+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
+ * use of internal structures to get the master_secret and
+ * {server,client}_random.
+ */
+#define GNUTLS_INTERNAL_STRUCTURE_HACK
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+/*
+ * It looks like gnutls does not provide access to client/server_random and
+ * master_key. This is somewhat unfortunate since these are needed for key
+ * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
+ * hack that copies the gnutls_session_int definition from gnutls_int.h so that
+ * we can get the needed information.
+ */
+
+typedef u8 uint8;
+typedef unsigned char opaque;
+typedef struct {
+    uint8 suite[2];
+} cipher_suite_st;
+
+typedef struct {
+	gnutls_connection_end_t entity;
+	gnutls_kx_algorithm_t kx_algorithm;
+	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t read_mac_algorithm;
+	gnutls_compression_method_t read_compression_algorithm;
+	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t write_mac_algorithm;
+	gnutls_compression_method_t write_compression_algorithm;
+	cipher_suite_st current_cipher_suite;
+	opaque master_secret[WPA_TLS_MASTER_SIZE];
+	opaque client_random[WPA_TLS_RANDOM_SIZE];
+	opaque server_random[WPA_TLS_RANDOM_SIZE];
+	/* followed by stuff we are not interested in */
+} security_parameters_st;
+
+struct gnutls_session_int {
+	security_parameters_st security_parameters;
+	/* followed by things we are not interested in */
+};
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+static int tls_gnutls_ref_count = 0;
+
+struct tls_global {
+	/* Data for session resumption */
+	void *session_data;
+	size_t session_data_size;
+
+	int server;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+};
+
+struct tls_connection {
+	gnutls_session session;
+	char *subject_match, *altsubject_match;
+	int read_alerts, write_alerts, failed;
+
+	u8 *pre_shared_secret;
+	size_t pre_shared_secret_len;
+	int established;
+	int verify_peer;
+
+	struct wpabuf *push_buf;
+	struct wpabuf *pull_buf;
+	const u8 *pull_buf_offset;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+};
+
+
+static void tls_log_func(int level, const char *msg)
+{
+	char *s, *pos;
+	if (level == 6 || level == 7) {
+		/* These levels seem to be mostly I/O debug and msg dumps */
+		return;
+	}
+
+	s = os_strdup(msg);
+	if (s == NULL)
+		return;
+
+	pos = s;
+	while (*pos != '\0') {
+		if (*pos == '\n') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
+		   "gnutls<%d> %s", level, s);
+	os_free(s);
+}
+
+
+extern int wpa_debug_show_keys;
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	/* Because of the horrible hack to get master_secret and client/server
+	 * random, we need to make sure that the gnutls version is something
+	 * that is expected to have same structure definition for the session
+	 * data.. */
+	const char *ver;
+	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
+				 "1.3.2",
+				 NULL };
+	int i;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
+		os_free(global);
+		return NULL;
+	}
+	tls_gnutls_ref_count++;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	ver = gnutls_check_version(NULL);
+	if (ver == NULL) {
+		tls_deinit(global);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
+	for (i = 0; ok_ver[i]; i++) {
+		if (strcmp(ok_ver[i], ver) == 0)
+			break;
+	}
+	if (ok_ver[i] == NULL) {
+		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
+			   "to be tested and enabled in tls_gnutls.c", ver);
+		tls_deinit(global);
+		return NULL;
+	}
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	gnutls_global_set_log_function(tls_log_func);
+	if (wpa_debug_show_keys)
+		gnutls_global_set_log_level(11);
+	return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	if (global) {
+		if (global->params_set)
+			gnutls_certificate_free_credentials(global->xcred);
+		os_free(global->session_data);
+		os_free(global);
+	}
+
+	tls_gnutls_ref_count--;
+	if (tls_gnutls_ref_count == 0)
+		gnutls_global_deinit();
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	return 0;
+}
+
+
+static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+	const u8 *end;
+	if (conn->pull_buf == NULL) {
+		errno = EWOULDBLOCK;
+		return -1;
+	}
+
+	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
+	if ((size_t) (end - conn->pull_buf_offset) < len)
+		len = end - conn->pull_buf_offset;
+	os_memcpy(buf, conn->pull_buf_offset, len);
+	conn->pull_buf_offset += len;
+	if (conn->pull_buf_offset == end) {
+		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+		wpabuf_free(conn->pull_buf);
+		conn->pull_buf = NULL;
+		conn->pull_buf_offset = NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+			   __func__,
+			   (unsigned long) (end - conn->pull_buf_offset));
+	}
+	return len;
+}
+
+
+static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+
+	if (wpabuf_resize(&conn->push_buf, len) < 0) {
+		errno = ENOMEM;
+		return -1;
+	}
+	wpabuf_put_data(conn->push_buf, buf, len);
+
+	return len;
+}
+
+
+static int tls_gnutls_init_session(struct tls_global *global,
+				   struct tls_connection *conn)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
+	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
+	const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
+	int ret;
+
+	ret = gnutls_init(&conn->session,
+			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
+			   "connection: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_set_default_priority(conn->session);
+	if (ret < 0)
+		goto fail;
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+					 &err);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+			   "'%s'", err);
+		goto fail;
+	}
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
+	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
+	if (ret < 0)
+		goto fail;
+
+	ret = gnutls_protocol_set_priority(conn->session, protos);
+	if (ret < 0)
+		goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
+
+	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
+	gnutls_transport_set_push_function(conn->session, tls_push_func);
+	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
+		   gnutls_strerror(ret));
+	gnutls_deinit(conn->session);
+	return -1;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	struct tls_connection *conn;
+	int ret;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	if (tls_gnutls_init_session(global, conn)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	if (global->params_set) {
+		ret = gnutls_credentials_set(conn->session,
+					     GNUTLS_CRD_CERTIFICATE,
+					     global->xcred);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "Failed to configure "
+				   "credentials: %s", gnutls_strerror(ret));
+			os_free(conn);
+			return NULL;
+		}
+	}
+
+	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+
+	gnutls_certificate_free_credentials(conn->xcred);
+	gnutls_deinit(conn->session);
+	os_free(conn->pre_shared_secret);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	wpabuf_free(conn->push_buf);
+	wpabuf_free(conn->pull_buf);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	struct tls_global *global = ssl_ctx;
+	int ret;
+
+	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. */
+	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+	wpabuf_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->established = 0;
+
+	gnutls_deinit(conn->session);
+	if (tls_gnutls_init_session(global, conn)) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
+			   "for session resumption use");
+		return -1;
+	}
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->params_set ? conn->xcred :
+				     global->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
+			   "for session resumption: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (global->session_data) {
+		ret = gnutls_session_set_data(conn->session,
+					      global->session_data,
+					      global->session_data_size);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
+				   "data: %s", gnutls_strerror(ret));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+#if 0
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	GENERAL_NAME *gen;
+	char *field, *tmp;
+	void *ext;
+	int i, found = 0;
+	size_t len;
+
+	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);
+		switch (gen->type) {
+		case GEN_EMAIL:
+			field = "EMAIL";
+			break;
+		case GEN_DNS:
+			field = "DNS";
+			break;
+		case GEN_URI:
+			field = "URI";
+			break;
+		default:
+			field = NULL;
+			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
+				   "unsupported type=%d", gen->type);
+			break;
+		}
+
+		if (!field)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
+			   field, gen->d.ia5->data);
+		len = os_strlen(field) + 1 +
+			strlen((char *) gen->d.ia5->data) + 1;
+		tmp = os_malloc(len);
+		if (tmp == NULL)
+			continue;
+		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+		if (strstr(tmp, match))
+			found++;
+		os_free(tmp);
+	}
+
+	return found;
+}
+#endif
+
+
+#if 0
+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;
+	char *match, *altmatch;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	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);
+	match = conn ? conn->subject_match : NULL;
+	altmatch = conn ? conn->altsubject_match : NULL;
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'", err,
+			   X509_verify_cert_error_string(err), depth, buf);
+	} else {
+		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
+			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
+			   preverify_ok, err,
+			   X509_verify_cert_error_string(err), depth, buf);
+		if (depth == 0 && match && strstr(buf, match) == NULL) {
+			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+				   "match with '%s'", buf, match);
+			preverify_ok = 0;
+		} else if (depth == 0 && altmatch &&
+			   !tls_match_altsubject(err_cert, altmatch)) {
+			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+				   "'%s' not found", altmatch);
+			preverify_ok = 0;
+		}
+	}
+
+	return preverify_ok;
+}
+#endif
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+
+	if (conn == NULL || params == NULL)
+		return -1;
+
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (params->subject_match) {
+		conn->subject_match = os_strdup(params->subject_match);
+		if (conn->subject_match == NULL)
+			return -1;
+	}
+
+	os_free(conn->altsubject_match);
+	conn->altsubject_match = NULL;
+	if (params->altsubject_match) {
+		conn->altsubject_match = os_strdup(params->altsubject_match);
+		if (conn->altsubject_match == NULL)
+			return -1;
+	}
+
+	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
+	 * to force peer validation(?) */
+
+	if (params->ca_cert) {
+		conn->verify_peer = 1;
+		ret = gnutls_certificate_set_x509_trust_file(
+			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				conn->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				return -1;
+			}
+		}
+
+		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+			gnutls_certificate_set_verify_flags(
+				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+		}
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+			gnutls_certificate_set_verify_flags(
+				conn->xcred,
+				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			conn->xcred, params->client_cert, params->private_key,
+			GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				conn->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				return ret;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
+			params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			return -1;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			return -1;
+		}
+	}
+
+	conn->params_set = 1;
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
+			   gnutls_strerror(ret));
+	}
+
+	return ret;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	struct tls_global *global = tls_ctx;
+	int ret;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+
+	if (global->params_set) {
+		gnutls_certificate_free_credentials(global->xcred);
+		global->params_set = 0;
+	}
+
+	ret = gnutls_certificate_allocate_credentials(&global->xcred);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
+			   "%s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (params->ca_cert) {
+		ret = gnutls_certificate_set_x509_trust_file(
+			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				global->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+
+		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+			gnutls_certificate_set_verify_flags(
+				global->xcred,
+				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+		}
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+			gnutls_certificate_set_verify_flags(
+				global->xcred,
+				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			global->xcred, params->client_cert,
+			params->private_key, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				global->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			global->xcred, params->private_key,
+			GNUTLS_X509_FMT_DER, params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			goto fail;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			goto fail;
+		}
+	}
+
+	global->params_set = 1;
+
+	return 0;
+
+fail:
+	gnutls_certificate_free_credentials(global->xcred);
+	return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	if (conn == NULL || conn->session == NULL)
+		return -1;
+
+	conn->verify_peer = verify_peer;
+	gnutls_certificate_server_set_request(conn->session,
+					      verify_peer ? GNUTLS_CERT_REQUIRE
+					      : GNUTLS_CERT_REQUEST);
+
+	return 0;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	security_parameters_st *sec;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	if (conn == NULL || conn->session == NULL || keys == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	sec = &conn->session->security_parameters;
+	keys->master_key = sec->master_secret;
+	keys->master_key_len = WPA_TLS_MASTER_SIZE;
+	keys->client_random = sec->client_random;
+	keys->server_random = sec->server_random;
+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+	keys->client_random =
+		(u8 *) gnutls_session_get_client_random(conn->session);
+	keys->server_random =
+		(u8 *) gnutls_session_get_server_random(conn->session);
+	/* No access to master_secret */
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+
+	return 0;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+	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);
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+	return -1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
+static int tls_connection_verify_peer(struct tls_connection *conn,
+				      gnutls_alert_description_t *err)
+{
+	unsigned int status, num_certs, i;
+	struct os_time now;
+	const gnutls_datum_t *certs;
+	gnutls_x509_crt_t cert;
+
+	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
+			   "certificate chain");
+		*err = GNUTLS_A_INTERNAL_ERROR;
+		return -1;
+	}
+
+	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+		*err = GNUTLS_A_INTERNAL_ERROR;
+		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
+			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
+				   "algorithm");
+			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
+		}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
+			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
+				   "activated");
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+		}
+		if (status & GNUTLS_CERT_EXPIRED) {
+			wpa_printf(MSG_INFO, "TLS: Certificate expired");
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
+			   "known issuer");
+		*err = GNUTLS_A_UNKNOWN_CA;
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_REVOKED) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
+		*err = GNUTLS_A_CERTIFICATE_REVOKED;
+		return -1;
+	}
+
+	os_get_time(&now);
+
+	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
+	if (certs == NULL) {
+		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
+			   "received");
+		*err = GNUTLS_A_UNKNOWN_CA;
+		return -1;
+	}
+
+	for (i = 0; i < num_certs; i++) {
+		char *buf;
+		size_t len;
+		if (gnutls_x509_crt_init(&cert) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
+				   "failed");
+			*err = GNUTLS_A_BAD_CERTIFICATE;
+			return -1;
+		}
+
+		if (gnutls_x509_crt_import(cert, &certs[i],
+					   GNUTLS_X509_FMT_DER) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
+				   "certificate %d/%d", i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			*err = GNUTLS_A_BAD_CERTIFICATE;
+			return -1;
+		}
+
+		gnutls_x509_crt_get_dn(cert, NULL, &len);
+		len++;
+		buf = os_malloc(len + 1);
+		if (buf) {
+			buf[0] = buf[len] = '\0';
+			gnutls_x509_crt_get_dn(cert, buf, &len);
+		}
+		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
+			   i + 1, num_certs, buf);
+
+		if (i == 0) {
+			/* TODO: validate subject_match and altsubject_match */
+		}
+
+		os_free(buf);
+
+		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+				   "not valid at this time",
+				   i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			return -1;
+		}
+
+		gnutls_x509_crt_deinit(cert);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
+{
+	int res;
+	struct wpabuf *ad;
+	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
+	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
+	if (ad == NULL)
+		return NULL;
+
+	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
+				 wpabuf_size(ad));
+	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+			   "(%s)", __func__, (int) res,
+			   gnutls_strerror(res));
+		wpabuf_free(ad);
+		return NULL;
+	}
+
+	wpabuf_put(ad, res);
+	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
+		   res);
+	return ad;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct tls_global *global = tls_ctx;
+	struct wpabuf *out_data;
+	int ret;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (in_data && wpabuf_len(in_data) > 0) {
+		if (conn->pull_buf) {
+			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+				   "pull_buf", __func__,
+				   (unsigned long) wpabuf_len(conn->pull_buf));
+			wpabuf_free(conn->pull_buf);
+		}
+		conn->pull_buf = wpabuf_dup(in_data);
+		if (conn->pull_buf == NULL)
+			return NULL;
+		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
+	}
+
+	ret = gnutls_handshake(conn->session);
+	if (ret < 0) {
+		switch (ret) {
+		case GNUTLS_E_AGAIN:
+			if (global->server && conn->established &&
+			    conn->push_buf == NULL) {
+				/* Need to return something to trigger
+				 * completion of EAP-TLS. */
+				conn->push_buf = wpabuf_alloc(0);
+			}
+			break;
+		case GNUTLS_E_FATAL_ALERT_RECEIVED:
+			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
+				   __func__, gnutls_alert_get_name(
+					   gnutls_alert_get(conn->session)));
+			conn->read_alerts++;
+			/* continue */
+		default:
+			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
+				   "-> %s", __func__, gnutls_strerror(ret));
+			conn->failed++;
+		}
+	} else {
+		size_t size;
+		gnutls_alert_description_t err;
+
+		if (conn->verify_peer &&
+		    tls_connection_verify_peer(conn, &err)) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
+				   "failed validation");
+			conn->failed++;
+			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
+			goto out;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+		conn->established = 1;
+		if (conn->push_buf == NULL) {
+			/* Need to return something to get final TLS ACK. */
+			conn->push_buf = wpabuf_alloc(0);
+		}
+
+		gnutls_session_get_data(conn->session, NULL, &size);
+		if (global->session_data == NULL ||
+		    global->session_data_size < size) {
+			os_free(global->session_data);
+			global->session_data = os_malloc(size);
+		}
+		if (global->session_data) {
+			global->session_data_size = size;
+			gnutls_session_get_data(conn->session,
+						global->session_data,
+						&global->session_data_size);
+		}
+
+		if (conn->pull_buf && appl_data)
+			*appl_data = gnutls_get_appl_data(conn);
+	}
+
+out:
+	out_data = conn->push_buf;
+	conn->push_buf = NULL;
+	return out_data;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	ssize_t res;
+	struct wpabuf *buf;
+
+	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
+				 wpabuf_len(in_data));
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
+			   __func__, gnutls_strerror(res));
+		return NULL;
+	}
+
+	buf = conn->push_buf;
+	conn->push_buf = NULL;
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	ssize_t res;
+	struct wpabuf *out;
+
+	if (conn->pull_buf) {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+			   "pull_buf", __func__,
+			   (unsigned long) wpabuf_len(conn->pull_buf));
+		wpabuf_free(conn->pull_buf);
+	}
+	conn->pull_buf = wpabuf_dup(in_data);
+	if (conn->pull_buf == NULL)
+		return NULL;
+	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
+
+	/*
+	 * 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.
+	 */
+	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (out == NULL)
+		return NULL;
+
+	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
+				 wpabuf_size(out));
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+			   "(%s)", __func__, (int) res, gnutls_strerror(res));
+		wpabuf_free(out);
+		return NULL;
+	}
+	wpabuf_put(out, res);
+
+	return out;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return 0;
+	return gnutls_session_is_resumed(conn->session);
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	/* TODO */
+	buf[0] = '\0';
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	gnutls_record_disable_padding(conn->session);
+	return 0;
+}
+
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	/* TODO */
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb, void *ctx)
+{
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/tls_internal.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,651 +0,0 @@
-/*
- * TLS interface functions and an internal TLS implementation
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file interface functions for hostapd/wpa_supplicant to use the
- * integrated TLSv1 implementation.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "tls.h"
-#include "tls/tlsv1_client.h"
-#include "tls/tlsv1_server.h"
-
-
-static int tls_ref_count = 0;
-
-struct tls_global {
-	int server;
-	struct tlsv1_credentials *server_cred;
-	int check_crl;
-};
-
-struct tls_connection {
-	struct tlsv1_client *client;
-	struct tlsv1_server *server;
-};
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	struct tls_global *global;
-
-	if (tls_ref_count == 0) {
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-		if (tlsv1_client_global_init())
-			return NULL;
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-		if (tlsv1_server_global_init())
-			return NULL;
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	}
-	tls_ref_count++;
-
-	global = os_zalloc(sizeof(*global));
-	if (global == NULL)
-		return NULL;
-
-	return global;
-}
-
-void tls_deinit(void *ssl_ctx)
-{
-	struct tls_global *global = ssl_ctx;
-	tls_ref_count--;
-	if (tls_ref_count == 0) {
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-		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 */
-	}
-	os_free(global);
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
-	return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
-	struct tls_connection *conn;
-	struct tls_global *global = tls_ctx;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (!global->server) {
-		conn->client = tlsv1_client_init();
-		if (conn->client == NULL) {
-			os_free(conn);
-			return NULL;
-		}
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (global->server) {
-		conn->server = tlsv1_server_init(global->server_cred);
-		if (conn->server == NULL) {
-			os_free(conn);
-			return NULL;
-		}
-	}
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return;
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		tlsv1_client_deinit(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		tlsv1_server_deinit(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_established(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_established(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return 0;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_shutdown(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_shutdown(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	struct tlsv1_credentials *cred;
-
-	if (conn->client == NULL)
-		return -1;
-
-	cred = tlsv1_cred_alloc();
-	if (cred == NULL)
-		return -1;
-
-	if (tlsv1_set_ca_cert(cred, params->ca_cert,
-			      params->ca_cert_blob, params->ca_cert_blob_len,
-			      params->ca_path)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
-			   "certificates");
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
-	if (tlsv1_set_cert(cred, params->client_cert,
-			   params->client_cert_blob,
-			   params->client_cert_blob_len)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to configure client "
-			   "certificate");
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
-	if (tlsv1_set_private_key(cred, 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");
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
-	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
-			       params->dh_blob_len)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
-	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
-		tlsv1_cred_free(cred);
-		return -1;
-	}
-
-	return 0;
-#else /* CONFIG_TLS_INTERNAL_CLIENT */
-	return -1;
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	struct tls_global *global = tls_ctx;
-	struct tlsv1_credentials *cred;
-
-	/* Currently, global parameters are only set when running in server
-	 * mode. */
-	global->server = 1;
-	tlsv1_cred_free(global->server_cred);
-	global->server_cred = cred = tlsv1_cred_alloc();
-	if (cred == NULL)
-		return -1;
-
-	if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
-			      params->ca_cert_blob_len, params->ca_path)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
-			   "certificates");
-		return -1;
-	}
-
-	if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
-			   params->client_cert_blob_len)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to configure server "
-			   "certificate");
-		return -1;
-	}
-
-	if (tlsv1_set_private_key(cred, 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");
-		return -1;
-	}
-
-	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
-			       params->dh_blob_len)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
-		return -1;
-	}
-
-	return 0;
-#else /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
-	struct tls_global *global = tls_ctx;
-	global->check_crl = check_crl;
-	return 0;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_set_verify(conn->server, verify_peer);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_get_keys(conn->client, keys);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_get_keys(conn->server, keys);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client) {
-		return tlsv1_client_prf(conn->client, label,
-					server_random_first,
-					out, out_len);
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server) {
-		return tlsv1_server_prf(conn->server, label,
-					server_random_first,
-					out, out_len);
-	}
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	u8 *res, *ad;
-	size_t res_len, ad_len;
-	struct wpabuf *out;
-
-	if (conn->client == NULL)
-		return NULL;
-
-	ad = NULL;
-	res = tlsv1_client_handshake(conn->client,
-				     in_data ? wpabuf_head(in_data) : NULL,
-				     in_data ? wpabuf_len(in_data) : 0,
-				     &res_len, &ad, &ad_len);
-	if (res == NULL)
-		return NULL;
-	out = wpabuf_alloc_ext_data(res, res_len);
-	if (out == NULL) {
-		os_free(res);
-		os_free(ad);
-		return NULL;
-	}
-	if (appl_data) {
-		if (ad) {
-			*appl_data = wpabuf_alloc_ext_data(ad, ad_len);
-			if (*appl_data == NULL)
-				os_free(ad);
-		} else
-			*appl_data = NULL;
-	} else
-		os_free(ad);
-
-	return out;
-#else /* CONFIG_TLS_INTERNAL_CLIENT */
-	return NULL;
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	u8 *res;
-	size_t res_len;
-	struct wpabuf *out;
-
-	if (conn->server == NULL)
-		return NULL;
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
-				     wpabuf_len(in_data), &res_len);
-	if (res == NULL && tlsv1_server_established(conn->server))
-		return wpabuf_alloc(0);
-	if (res == NULL)
-		return NULL;
-	out = wpabuf_alloc_ext_data(res, res_len);
-	if (out == NULL) {
-		os_free(res);
-		return NULL;
-	}
-
-	return out;
-#else /* CONFIG_TLS_INTERNAL_SERVER */
-	return NULL;
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
-	}
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
-	}
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return NULL;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_resumed(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_resumed(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_set_cipher_list(conn->client, ciphers);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_set_cipher_list(conn->server, ciphers);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	if (conn == NULL)
-		return -1;
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_get_cipher(conn->client, buf, buflen);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_get_cipher(conn->server, buf, buflen);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client) {
-		return tlsv1_client_hello_ext(conn->client, ext_type,
-					      data, data_len);
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
-				    struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client)
-		return tlsv1_client_get_keyblock_size(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server)
-		return tlsv1_server_get_keyblock_size(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
-					 struct tls_connection *conn,
-					 tls_session_ticket_cb cb,
-					 void *ctx)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
-	if (conn->client) {
-		tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
-		return 0;
-	}
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
-	if (conn->server) {
-		tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
-		return 0;
-	}
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/tls_internal.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_internal.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,630 @@
+/*
+ * TLS interface functions and an internal TLS implementation
+ * Copyright (c) 2004-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file interface functions for hostapd/wpa_supplicant to use the
+ * integrated TLSv1 implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls.h"
+#include "tls/tlsv1_client.h"
+#include "tls/tlsv1_server.h"
+
+
+static int tls_ref_count = 0;
+
+struct tls_global {
+	int server;
+	struct tlsv1_credentials *server_cred;
+	int check_crl;
+};
+
+struct tls_connection {
+	struct tlsv1_client *client;
+	struct tlsv1_server *server;
+};
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+		if (tlsv1_client_global_init())
+			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+		if (tlsv1_server_global_init())
+			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	}
+	tls_ref_count++;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	return global;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	tls_ref_count--;
+	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+		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 */
+	}
+	os_free(global);
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	struct tls_connection *conn;
+	struct tls_global *global = tls_ctx;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (!global->server) {
+		conn->client = tlsv1_client_init();
+		if (conn->client == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (global->server) {
+		conn->server = tlsv1_server_init(global->server_cred);
+		if (conn->server == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		tlsv1_client_deinit(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		tlsv1_server_deinit(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_established(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_established(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return 0;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_shutdown(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_shutdown(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	struct tlsv1_credentials *cred;
+
+	if (conn->client == NULL)
+		return -1;
+
+	cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert,
+			      params->ca_cert_blob, params->ca_cert_blob_len,
+			      params->ca_path)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+			   "certificates");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert,
+			   params->client_cert_blob,
+			   params->client_cert_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure client "
+			   "certificate");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, 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");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	tlsv1_client_set_time_checks(
+		conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	struct tls_global *global = tls_ctx;
+	struct tlsv1_credentials *cred;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+	tlsv1_cred_free(global->server_cred);
+	global->server_cred = cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
+			      params->ca_cert_blob_len, params->ca_path)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+			   "certificates");
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
+			   params->client_cert_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure server "
+			   "certificate");
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, 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");
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		return -1;
+	}
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	struct tls_global *global = tls_ctx;
+	global->check_crl = check_crl;
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_verify(conn->server, verify_peer);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keys(conn->client, keys);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keys(conn->server, keys);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_prf(conn->client, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		return tlsv1_server_prf(conn->server, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+					 NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *need_more_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	u8 *res, *ad;
+	size_t res_len, ad_len;
+	struct wpabuf *out;
+
+	if (conn->client == NULL)
+		return NULL;
+
+	ad = NULL;
+	res = tlsv1_client_handshake(conn->client,
+				     in_data ? wpabuf_head(in_data) : NULL,
+				     in_data ? wpabuf_len(in_data) : 0,
+				     &res_len, &ad, &ad_len, need_more_data);
+	if (res == NULL)
+		return NULL;
+	out = wpabuf_alloc_ext_data(res, res_len);
+	if (out == NULL) {
+		os_free(res);
+		os_free(ad);
+		return NULL;
+	}
+	if (appl_data) {
+		if (ad) {
+			*appl_data = wpabuf_alloc_ext_data(ad, ad_len);
+			if (*appl_data == NULL)
+				os_free(ad);
+		} else
+			*appl_data = NULL;
+	} else
+		os_free(ad);
+
+	return out;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	u8 *res;
+	size_t res_len;
+	struct wpabuf *out;
+
+	if (conn->server == NULL)
+		return NULL;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
+				     wpabuf_len(in_data), &res_len);
+	if (res == NULL && tlsv1_server_established(conn->server))
+		return wpabuf_alloc(0);
+	if (res == NULL)
+		return NULL;
+	out = wpabuf_alloc_ext_data(res, res_len);
+	if (out == NULL) {
+		os_free(res);
+		return NULL;
+	}
+
+	return out;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *need_more_data)
+{
+	if (need_more_data)
+		*need_more_data = 0;
+
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+					    wpabuf_len(in_data),
+					    need_more_data);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_resumed(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_resumed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_cipher_list(conn->server, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	if (conn == NULL)
+		return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_cipher(conn->server, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_hello_ext(conn->client, ext_type,
+					      data, data_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/tls_none.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,229 +0,0 @@
-/*
- * SSL/TLS interface functions for no TLS case
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "tls.h"
-
-void * tls_init(const struct tls_config *conf)
-{
-	return (void *) 1;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
-	return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
-	return NULL;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
-	return -1;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	return -1;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	return NULL;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
-				    struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/tls_none.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_none.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,194 @@
+/*
+ * SSL/TLS interface functions for no TLS case
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "tls.h"
+
+void * tls_init(const struct tls_config *conf)
+{
+	return (void *) 1;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	return NULL;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	return -1;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/crypto/tls_nss.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_nss.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,680 +0,0 @@
-/*
- * SSL/TLS interface functions for NSS
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prio.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nspr/prinit.h>
-#include <nspr/prerror.h>
-#include <nspr/prmem.h>
-#include <nss/nss.h>
-#include <nss/nssilckt.h>
-#include <nss/ssl.h>
-#include <nss/pk11func.h>
-#include <nss/secerr.h>
-
-#include "common.h"
-#include "tls.h"
-
-static int tls_nss_ref_count = 0;
-
-static PRDescIdentity nss_layer_id;
-
-
-struct tls_connection {
-	PRFileDesc *fd;
-
-	int established;
-	int verify_peer;
-	u8 *push_buf, *pull_buf, *pull_buf_offset;
-	size_t push_buf_len, pull_buf_len;
-};
-
-
-static PRStatus nss_io_close(PRFileDesc *fd)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O close");
-	return PR_SUCCESS;
-}
-
-
-static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
-			     PRInt32 iov_size, PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
-			   PRIntn flags, PRIntervalTime timeout)
-{
-	struct tls_connection *conn = (struct tls_connection *) fd->secret;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
-
-	if (conn->pull_buf == NULL) {
-		wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
-		return PR_FAILURE;
-	}
-
-	end = conn->pull_buf + conn->pull_buf_len;
-	if (end - conn->pull_buf_offset < amount)
-		amount = end - conn->pull_buf_offset;
-	os_memcpy(buf, conn->pull_buf_offset, amount);
-	conn->pull_buf_offset += amount;
-	if (conn->pull_buf_offset == end) {
-		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
-		os_free(conn->pull_buf);
-		conn->pull_buf = conn->pull_buf_offset = NULL;
-		conn->pull_buf_len = 0;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
-			   __func__,
-			   (unsigned long) (end - conn->pull_buf_offset));
-	}
-	return amount;
-}
-
-
-static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
-			   PRIntn flags, PRIntervalTime timeout)
-{
-	struct tls_connection *conn = (struct tls_connection *) fd->secret;
-	u8 *nbuf;
-
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
-
-	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
-	if (nbuf == NULL) {
-		wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
-			   "data to be sent");
-		return PR_FAILURE;
-	}
-	os_memcpy(nbuf + conn->push_buf_len, buf, amount);
-	conn->push_buf = nbuf;
-	conn->push_buf_len += amount;
-
-	return amount;
-}
-
-
-static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
-			       PRIntn flags, PRNetAddr *addr,
-			       PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
-			     PRIntn flags, const PRNetAddr *addr,
-			     PRIntervalTime timeout)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
-	return PR_FAILURE;
-}
-
-
-static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
-{
-	wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
-
-	/*
-	 * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
-	 * fake IPv4 address to work around this even though we are not really
-	 * using TCP.
-	 */
-	os_memset(addr, 0, sizeof(*addr));
-	addr->inet.family = PR_AF_INET;
-
-	return PR_SUCCESS;
-}
-
-
-static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
-				       PRSocketOptionData *data)
-{
-	switch (data->option) {
-	case PR_SockOpt_Nonblocking:
-		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
-		data->value.non_blocking = PR_TRUE;
-		return PR_SUCCESS;
-	default:
-		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
-			   data->option);
-		return PR_FAILURE;
-	}
-}
-
-
-static const PRIOMethods nss_io = {
-	PR_DESC_LAYERED,
-	nss_io_close,
-	nss_io_read,
-	nss_io_write,
-	NULL /* available */,
-	NULL /* available64 */,
-	NULL /* fsync */,
-	NULL /* fseek */,
-	NULL /* fseek64 */,
-	NULL /* fileinfo */,
-	NULL /* fileinfo64 */,
-	nss_io_writev,
-	NULL /* connect */,
-	NULL /* accept */,
-	NULL /* bind */,
-	NULL /* listen */,
-	NULL /* shutdown */,
-	nss_io_recv,
-	nss_io_send,
-	nss_io_recvfrom,
-	nss_io_sendto,
-	NULL /* poll */,
-	NULL /* acceptread */,
-	NULL /* transmitfile */,
-	NULL /* getsockname */,
-	nss_io_getpeername,
-	NULL /* reserved_fn_6 */,
-	NULL /* reserved_fn_5 */,
-	nss_io_getsocketoption,
-	NULL /* setsocketoption */,
-	NULL /* sendfile */,
-	NULL /* connectcontinue */,
-	NULL /* reserved_fn_3 */,
-	NULL /* reserved_fn_2 */,
-	NULL /* reserved_fn_1 */,
-	NULL /* reserved_fn_0 */
-};
-
-
-static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
-{
-	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
-	return NULL;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	char *dir;
-
-	tls_nss_ref_count++;
-	if (tls_nss_ref_count > 1)
-		return (void *) 1;
-
-	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
-
-	nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
-
-	PK11_SetPasswordFunc(nss_password_cb);
-
-	dir = getenv("SSL_DIR");
-	if (dir) {
-		if (NSS_Init(dir) != SECSuccess) {
-			wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
-				   "failed", dir);
-			return NULL;
-		}
-	} else {
-		if (NSS_NoDB_Init(NULL) != SECSuccess) {
-			wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
-				   "failed");
-			return NULL;
-		}
-	}
-
-	if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
-	    SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
-	    SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
-		return NULL;
-	}
-
-	if (NSS_SetDomesticPolicy() != SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
-		return NULL;
-	}
-
-	return (void *) 1;
-}
-
-void tls_deinit(void *ssl_ctx)
-{
-	tls_nss_ref_count--;
-	if (tls_nss_ref_count == 0) {
-		if (NSS_Shutdown() != SECSuccess)
-			wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
-	}
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
-	return 0;
-}
-
-
-static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
-{
-	struct tls_connection *conn = arg;
-	SECStatus res = SECSuccess;
-	PRErrorCode err;
-	CERTCertificate *cert;
-	char *subject, *issuer;
-
-	err = PR_GetError();
-	if (IS_SEC_ERROR(err))
-		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
-			   "%d)", err - SEC_ERROR_BASE);
-	else
-		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
-			   err);
-	cert = SSL_PeerCertificate(fd);
-	subject = CERT_NameToAscii(&cert->subject);
-	issuer = CERT_NameToAscii(&cert->issuer);
-	wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
-		   subject, issuer);
-	CERT_DestroyCertificate(cert);
-	PR_Free(subject);
-	PR_Free(issuer);
-	if (conn->verify_peer)
-		res = SECFailure;
-
-	return res;
-}
-
-
-static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
-{
-	struct tls_connection *conn = client_data;
-	wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
-	conn->established = 1;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
-	struct tls_connection *conn;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-	conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
-	if (conn->fd == NULL) {
-		os_free(conn);
-		return NULL;
-	}
-	conn->fd->secret = (void *) conn;
-
-	conn->fd = SSL_ImportFD(NULL, conn->fd);
-	if (conn->fd == NULL) {
-		os_free(conn);
-		return NULL;
-	}
-
-	if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
-	    SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
-	    SECSuccess ||
-	    SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
-	    SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
-	    SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
-	    SECSuccess) {
-		wpa_printf(MSG_ERROR, "NSS: Failed to set options");
-		PR_Close(conn->fd);
-		os_free(conn);
-		return NULL;
-	}
-
-	SSL_ResetHandshake(conn->fd, PR_FALSE);
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
-	PR_Close(conn->fd);
-	os_free(conn->push_buf);
-	os_free(conn->pull_buf);
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
-	return conn->established;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
-	return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
-	return -1;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	conn->verify_peer = verify_peer;
-	return 0;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	/* NSS does not export master secret or client/server random. */
-	return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-	if (conn == NULL || server_random_first) {
-		wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
-			   "(server_random_first=%d)",
-			   server_random_first);
-		return -1;
-	}
-
-	if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
-	    SECSuccess) {
-		wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
-			   "(label='%s' out_len=%d", label, (int) out_len);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	struct wpabuf *out_data;
-
-	wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
-		   in_data ? (unsigned int) wpabuf_len(in_data) : 0);
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	if (in_data && wpabuf_len(in_data) > 0) {
-		if (conn->pull_buf) {
-			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-				   "pull_buf", __func__,
-				   (unsigned long) conn->pull_buf_len);
-			os_free(conn->pull_buf);
-		}
-		conn->pull_buf = os_malloc(wpabuf_len(in_data));
-		if (conn->pull_buf == NULL)
-			return NULL;
-		os_memcpy(conn->pull_buf, wpabuf_head(in_data),
-			  wpabuf_len(in_data));
-		conn->pull_buf_offset = conn->pull_buf;
-		conn->pull_buf_len = wpabuf_len(in_data);
-	}
-
-	SSL_ForceHandshake(conn->fd);
-
-	if (conn->established && conn->push_buf == NULL) {
-		/* Need to return something to get final TLS ACK. */
-		conn->push_buf = os_malloc(1);
-	}
-
-	if (conn->push_buf == NULL)
-		return NULL;
-	out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
-	if (out_data == NULL)
-		os_free(conn->push_buf);
-	conn->push_buf = NULL;
-	conn->push_buf_len = 0;
-	return out_data;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	PRInt32 res;
-	struct wpabuf *buf;
-
-	wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
-		   (int) wpabuf_len(in_data));
-	res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
-		      0);
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "NSS: Encryption failed");
-		return NULL;
-	}
-	if (conn->push_buf == NULL)
-		return NULL;
-	buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
-	if (buf == NULL)
-		os_free(conn->push_buf);
-	conn->push_buf = NULL;
-	conn->push_buf_len = 0;
-	return buf;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	PRInt32 res;
-	struct wpabuf *out;
-
-	wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
-		   (int) wpabuf_len(in_data));
-	if (conn->pull_buf) {
-		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
-			   "pull_buf", __func__,
-			   (unsigned long) conn->pull_buf_len);
-		os_free(conn->pull_buf);
-	}
-	conn->pull_buf = os_malloc(wpabuf_len(in_data));
-	if (conn->pull_buf == NULL)
-		return NULL;
-	os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
-	conn->pull_buf_offset = conn->pull_buf;
-	conn->pull_buf_len = wpabuf_len(in_data);
-
-	/*
-	 * 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.
-	 */
-	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-	if (out == NULL)
-		return NULL;
-
-	res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
-	wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
-	if (res < 0) {
-		wpabuf_free(out);
-		return NULL;
-	}
-	wpabuf_put(out, res);
-
-	return out;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
-				    struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
-					 struct tls_connection *conn,
-					 tls_session_ticket_cb cb,
-					 void *ctx)
-{
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/tls_nss.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_nss.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_nss.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_nss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,645 @@
+/*
+ * SSL/TLS interface functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prio.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nspr/prinit.h>
+#include <nspr/prerror.h>
+#include <nspr/prmem.h>
+#include <nss/nss.h>
+#include <nss/nssilckt.h>
+#include <nss/ssl.h>
+#include <nss/pk11func.h>
+#include <nss/secerr.h>
+
+#include "common.h"
+#include "tls.h"
+
+static int tls_nss_ref_count = 0;
+
+static PRDescIdentity nss_layer_id;
+
+
+struct tls_connection {
+	PRFileDesc *fd;
+
+	int established;
+	int verify_peer;
+	u8 *push_buf, *pull_buf, *pull_buf_offset;
+	size_t push_buf_len, pull_buf_len;
+};
+
+
+static PRStatus nss_io_close(PRFileDesc *fd)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O close");
+	return PR_SUCCESS;
+}
+
+
+static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
+			     PRInt32 iov_size, PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+			   PRIntn flags, PRIntervalTime timeout)
+{
+	struct tls_connection *conn = (struct tls_connection *) fd->secret;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
+
+	if (conn->pull_buf == NULL) {
+		wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
+		return PR_FAILURE;
+	}
+
+	end = conn->pull_buf + conn->pull_buf_len;
+	if (end - conn->pull_buf_offset < amount)
+		amount = end - conn->pull_buf_offset;
+	os_memcpy(buf, conn->pull_buf_offset, amount);
+	conn->pull_buf_offset += amount;
+	if (conn->pull_buf_offset == end) {
+		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+		os_free(conn->pull_buf);
+		conn->pull_buf = conn->pull_buf_offset = NULL;
+		conn->pull_buf_len = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+			   __func__,
+			   (unsigned long) (end - conn->pull_buf_offset));
+	}
+	return amount;
+}
+
+
+static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+			   PRIntn flags, PRIntervalTime timeout)
+{
+	struct tls_connection *conn = (struct tls_connection *) fd->secret;
+	u8 *nbuf;
+
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
+
+	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
+	if (nbuf == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
+			   "data to be sent");
+		return PR_FAILURE;
+	}
+	os_memcpy(nbuf + conn->push_buf_len, buf, amount);
+	conn->push_buf = nbuf;
+	conn->push_buf_len += amount;
+
+	return amount;
+}
+
+
+static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+			       PRIntn flags, PRNetAddr *addr,
+			       PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
+			     PRIntn flags, const PRNetAddr *addr,
+			     PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	return PR_FAILURE;
+}
+
+
+static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
+
+	/*
+	 * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
+	 * fake IPv4 address to work around this even though we are not really
+	 * using TCP.
+	 */
+	os_memset(addr, 0, sizeof(*addr));
+	addr->inet.family = PR_AF_INET;
+
+	return PR_SUCCESS;
+}
+
+
+static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
+				       PRSocketOptionData *data)
+{
+	switch (data->option) {
+	case PR_SockOpt_Nonblocking:
+		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
+		data->value.non_blocking = PR_TRUE;
+		return PR_SUCCESS;
+	default:
+		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
+			   data->option);
+		return PR_FAILURE;
+	}
+}
+
+
+static const PRIOMethods nss_io = {
+	PR_DESC_LAYERED,
+	nss_io_close,
+	nss_io_read,
+	nss_io_write,
+	NULL /* available */,
+	NULL /* available64 */,
+	NULL /* fsync */,
+	NULL /* fseek */,
+	NULL /* fseek64 */,
+	NULL /* fileinfo */,
+	NULL /* fileinfo64 */,
+	nss_io_writev,
+	NULL /* connect */,
+	NULL /* accept */,
+	NULL /* bind */,
+	NULL /* listen */,
+	NULL /* shutdown */,
+	nss_io_recv,
+	nss_io_send,
+	nss_io_recvfrom,
+	nss_io_sendto,
+	NULL /* poll */,
+	NULL /* acceptread */,
+	NULL /* transmitfile */,
+	NULL /* getsockname */,
+	nss_io_getpeername,
+	NULL /* reserved_fn_6 */,
+	NULL /* reserved_fn_5 */,
+	nss_io_getsocketoption,
+	NULL /* setsocketoption */,
+	NULL /* sendfile */,
+	NULL /* connectcontinue */,
+	NULL /* reserved_fn_3 */,
+	NULL /* reserved_fn_2 */,
+	NULL /* reserved_fn_1 */,
+	NULL /* reserved_fn_0 */
+};
+
+
+static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+	return NULL;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	char *dir;
+
+	tls_nss_ref_count++;
+	if (tls_nss_ref_count > 1)
+		return (void *) 1;
+
+	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+	nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
+
+	PK11_SetPasswordFunc(nss_password_cb);
+
+	dir = getenv("SSL_DIR");
+	if (dir) {
+		if (NSS_Init(dir) != SECSuccess) {
+			wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
+				   "failed", dir);
+			return NULL;
+		}
+	} else {
+		if (NSS_NoDB_Init(NULL) != SECSuccess) {
+			wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
+				   "failed");
+			return NULL;
+		}
+	}
+
+	if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
+	    SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
+		return NULL;
+	}
+
+	if (NSS_SetDomesticPolicy() != SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
+		return NULL;
+	}
+
+	return (void *) 1;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+	tls_nss_ref_count--;
+	if (tls_nss_ref_count == 0) {
+		if (NSS_Shutdown() != SECSuccess)
+			wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
+	}
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
+{
+	struct tls_connection *conn = arg;
+	SECStatus res = SECSuccess;
+	PRErrorCode err;
+	CERTCertificate *cert;
+	char *subject, *issuer;
+
+	err = PR_GetError();
+	if (IS_SEC_ERROR(err))
+		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
+			   "%d)", err - SEC_ERROR_BASE);
+	else
+		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
+			   err);
+	cert = SSL_PeerCertificate(fd);
+	subject = CERT_NameToAscii(&cert->subject);
+	issuer = CERT_NameToAscii(&cert->issuer);
+	wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
+		   subject, issuer);
+	CERT_DestroyCertificate(cert);
+	PR_Free(subject);
+	PR_Free(issuer);
+	if (conn->verify_peer)
+		res = SECFailure;
+
+	return res;
+}
+
+
+static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
+{
+	struct tls_connection *conn = client_data;
+	wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
+	conn->established = 1;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	struct tls_connection *conn;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
+	if (conn->fd == NULL) {
+		os_free(conn);
+		return NULL;
+	}
+	conn->fd->secret = (void *) conn;
+
+	conn->fd = SSL_ImportFD(NULL, conn->fd);
+	if (conn->fd == NULL) {
+		os_free(conn);
+		return NULL;
+	}
+
+	if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
+	    SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
+	    SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
+	    SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
+	    SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
+	    SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: Failed to set options");
+		PR_Close(conn->fd);
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_ResetHandshake(conn->fd, PR_FALSE);
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	PR_Close(conn->fd);
+	os_free(conn->push_buf);
+	os_free(conn->pull_buf);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return conn->established;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	conn->verify_peer = verify_peer;
+	return 0;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	/* NSS does not export master secret or client/server random. */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	if (conn == NULL || server_random_first) {
+		wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
+			   "(server_random_first=%d)",
+			   server_random_first);
+		return -1;
+	}
+
+	if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
+	    SECSuccess) {
+		wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
+			   "(label='%s' out_len=%d", label, (int) out_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct wpabuf *out_data;
+
+	wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
+		   in_data ? (unsigned int) wpabuf_len(in_data) : 0);
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (in_data && wpabuf_len(in_data) > 0) {
+		if (conn->pull_buf) {
+			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+				   "pull_buf", __func__,
+				   (unsigned long) conn->pull_buf_len);
+			os_free(conn->pull_buf);
+		}
+		conn->pull_buf = os_malloc(wpabuf_len(in_data));
+		if (conn->pull_buf == NULL)
+			return NULL;
+		os_memcpy(conn->pull_buf, wpabuf_head(in_data),
+			  wpabuf_len(in_data));
+		conn->pull_buf_offset = conn->pull_buf;
+		conn->pull_buf_len = wpabuf_len(in_data);
+	}
+
+	SSL_ForceHandshake(conn->fd);
+
+	if (conn->established && conn->push_buf == NULL) {
+		/* Need to return something to get final TLS ACK. */
+		conn->push_buf = os_malloc(1);
+	}
+
+	if (conn->push_buf == NULL)
+		return NULL;
+	out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
+	if (out_data == NULL)
+		os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return out_data;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	PRInt32 res;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
+		   (int) wpabuf_len(in_data));
+	res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
+		      0);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "NSS: Encryption failed");
+		return NULL;
+	}
+	if (conn->push_buf == NULL)
+		return NULL;
+	buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
+	if (buf == NULL)
+		os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	PRInt32 res;
+	struct wpabuf *out;
+
+	wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
+		   (int) wpabuf_len(in_data));
+	if (conn->pull_buf) {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+			   "pull_buf", __func__,
+			   (unsigned long) conn->pull_buf_len);
+		os_free(conn->pull_buf);
+	}
+	conn->pull_buf = os_malloc(wpabuf_len(in_data));
+	if (conn->pull_buf == NULL)
+		return NULL;
+	os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
+	conn->pull_buf_offset = conn->pull_buf;
+	conn->pull_buf_len = wpabuf_len(in_data);
+
+	/*
+	 * 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.
+	 */
+	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (out == NULL)
+		return NULL;
+
+	res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
+	wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
+	if (res < 0) {
+		wpabuf_free(out);
+		return NULL;
+	}
+	wpabuf_put(out, res);
+
+	return out;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/crypto/tls_openssl.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_openssl.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2925 +0,0 @@
-/*
- * SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#ifndef CONFIG_SMARTCARD
-#ifndef OPENSSL_NO_ENGINE
-#define OPENSSL_NO_ENGINE
-#endif
-#endif
-
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/pkcs12.h>
-#include <openssl/x509v3.h>
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif /* OPENSSL_NO_ENGINE */
-
-#include "common.h"
-#include "crypto.h"
-#include "tls.h"
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
-#define OPENSSL_d2i_TYPE const unsigned char **
-#else
-#define OPENSSL_d2i_TYPE unsigned char **
-#endif
-
-#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
-#ifdef SSL_OP_NO_TICKET
-/*
- * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
- * 2008-11-15. This version uses a bit different API compared to the old patch.
- */
-#define CONFIG_OPENSSL_TICKET_OVERRIDE
-#endif
-#endif
-
-static int tls_openssl_ref_count = 0;
-
-struct tls_global {
-	void (*event_cb)(void *ctx, enum tls_event ev,
-			 union tls_event_data *data);
-	void *cb_ctx;
-};
-
-static struct tls_global *tls_global = NULL;
-
-
-struct tls_connection {
-	SSL *ssl;
-	BIO *ssl_in, *ssl_out;
-#ifndef 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;
-	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;
-
-	u8 srv_cert_hash[32];
-};
-
-
-#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, (OPENSSL_d2i_TYPE) &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, (OPENSSL_d2i_TYPE) &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);
-
-		if (!X509_STORE_add_cert(ssl_ctx->cert_store, 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) {
-		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) {
-			struct tls_connection *conn =
-				SSL_get_app_data((SSL *) ssl);
-			if (where & SSL_CB_READ)
-				conn->read_alerts++;
-			else
-				conn->write_alerts++;
-		}
-	} 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) {
-		ENGINE_free(engine);
-		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
-			   "available", id);
-		return 0;
-	}
-	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;
-	}
-
-	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 || !pkcs11_module_path)
-		return 0;
-
-	pre_cmd[1] = pkcs11_so_path;
-	pre_cmd[3] = engine_id;
-	post_cmd[1] = pkcs11_module_path;
-
-	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 */
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	SSL_CTX *ssl;
-
-	if (tls_openssl_ref_count == 0) {
-		tls_global = os_zalloc(sizeof(*tls_global));
-		if (tls_global == NULL)
-			return NULL;
-		if (conf) {
-			tls_global->event_cb = conf->event_cb;
-			tls_global->cb_ctx = conf->cb_ctx;
-		}
-
-#ifdef CONFIG_FIPS
-#ifdef OPENSSL_FIPS
-		if (conf && conf->fips_mode) {
-			if (!FIPS_mode_set(1)) {
-				wpa_printf(MSG_ERROR, "Failed to enable FIPS "
-					   "mode");
-				ERR_load_crypto_strings();
-				ERR_print_errors_fp(stderr);
-				return NULL;
-			} else
-				wpa_printf(MSG_INFO, "Running in FIPS mode");
-		}
-#else /* OPENSSL_FIPS */
-		if (conf && conf->fips_mode) {
-			wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
-				   "supported");
-			return NULL;
-		}
-#endif /* OPENSSL_FIPS */
-#endif /* CONFIG_FIPS */
-		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 */
-	}
-	tls_openssl_ref_count++;
-
-	ssl = SSL_CTX_new(TLSv1_method());
-	if (ssl == NULL)
-		return NULL;
-
-	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
-
-#ifndef OPENSSL_NO_ENGINE
-	if (conf &&
-	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
-	     conf->pkcs11_module_path)) {
-		wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
-		ERR_load_ENGINE_strings();
-		ENGINE_load_dynamic();
-
-		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
-		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
-						   conf->pkcs11_module_path)) {
-			tls_deinit(ssl);
-			return NULL;
-		}
-	}
-#endif /* OPENSSL_NO_ENGINE */
-
-	return ssl;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
-	SSL_CTX *ssl = ssl_ctx;
-	SSL_CTX_free(ssl);
-
-	tls_openssl_ref_count--;
-	if (tls_openssl_ref_count == 0) {
-#ifndef OPENSSL_NO_ENGINE
-		ENGINE_cleanup();
-#endif /* OPENSSL_NO_ENGINE */
-		CRYPTO_cleanup_all_ex_data();
-		ERR_remove_state(0);
-		ERR_free_strings();
-		EVP_cleanup();
-		os_free(tls_global);
-		tls_global = NULL;
-	}
-}
-
-
-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)
-{
-#ifndef OPENSSL_NO_ENGINE
-	int ret = -1;
-	if (engine_id == NULL) {
-		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
-		return -1;
-	}
-	if (pin == NULL) {
-		wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
-		return -1;
-	}
-	if (key_id == NULL) {
-		wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
-		return -1;
-	}
-
-	ERR_clear_error();
-	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");
-
-	if (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;
-	}
-	/* load private key first in-case PIN is required for cert */
-	conn->private_key = ENGINE_load_private_key(conn->engine,
-						    key_id, NULL, NULL);
-	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));
-		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)
-{
-#ifndef 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) {
-		ENGINE_finish(conn->engine);
-		conn->engine = NULL;
-	}
-#endif /* 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;
-}
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
-	SSL_CTX *ssl = ssl_ctx;
-	struct tls_connection *conn;
-	long options;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-	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;
-	}
-
-	SSL_set_app_data(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;
-	SSL_free(conn->ssl);
-	tls_engine_deinit(conn);
-	os_free(conn->subject_match);
-	os_free(conn->altsubject_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 0;
-}
-
-
-static int tls_match_altsubject_component(X509 *cert, int type,
-					  const char *value, size_t len)
-{
-	GENERAL_NAME *gen;
-	void *ext;
-	int i, found = 0;
-
-	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++;
-	}
-
-	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;
-}
-
-
-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;
-
-	if (tls_global->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;
-	tls_global->event_cb(tls_global->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;
-#ifdef CONFIG_SHA256
-	u8 hash[32];
-#endif /* CONFIG_SHA256 */
-
-	if (tls_global->event_cb == NULL)
-		return;
-
-	os_memset(&ev, 0, sizeof(ev));
-	if (conn->cert_probe) {
-		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;
-	tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
-	wpabuf_free(cert);
-}
-
-
-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;
-	char *match, *altmatch;
-	const char *err_str;
-
-	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
-	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);
-	match = conn ? conn->subject_match : NULL;
-	altmatch = conn ? conn->altsubject_match : NULL;
-
-	if (!preverify_ok && !conn->ca_cert_verify)
-		preverify_ok = 1;
-	if (!preverify_ok && depth > 0 && conn->server_cert_only)
-		preverify_ok = 1;
-
-	err_str = X509_verify_cert_error_string(err);
-
-#ifdef CONFIG_SHA256
-	if (preverify_ok && depth == 0 && conn->server_cert_only) {
-		struct wpabuf *cert;
-		cert = get_x509_cert(err_cert);
-		if (!cert) {
-			wpa_printf(MSG_DEBUG, "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;
-			}
-			wpabuf_free(cert);
-		}
-	}
-#endif /* CONFIG_SHA256 */
-
-	if (!preverify_ok) {
-		wpa_printf(MSG_WARNING, "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 - 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: 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: 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
-		openssl_tls_cert_event(conn, err_cert, depth, buf);
-
-	if (conn->cert_probe && preverify_ok && depth == 0) {
-		wpa_printf(MSG_DEBUG, "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);
-	}
-
-	return preverify_ok;
-}
-
-
-#ifndef OPENSSL_NO_STDIO
-static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
-{
-	SSL_CTX *ssl_ctx = _ssl_ctx;
-	X509_LOOKUP *lookup;
-	int ret = 0;
-
-	lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
-				       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(void *_ssl_ctx, struct tls_connection *conn,
-				  const char *ca_cert, const u8 *ca_cert_blob,
-				  size_t ca_cert_blob_len, const char *ca_path)
-{
-	SSL_CTX *ssl_ctx = _ssl_ctx;
-
-	/*
-	 * Remove previously configured trusted CA certificates before adding
-	 * new ones.
-	 */
-	X509_STORE_free(ssl_ctx->cert_store);
-	ssl_ctx->cert_store = X509_STORE_new();
-	if (ssl_ctx->cert_store == NULL) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
-			   "certificate store", __func__);
-		return -1;
-	}
-
-	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
-	conn->ca_cert_verify = 1;
-
-	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
-			   "chain");
-		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, (OPENSSL_d2i_TYPE) &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->cert_store, 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 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(ssl_ctx, 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(ssl_ctx);
-		}
-#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 */
-		conn->ca_cert_verify = 0;
-	}
-
-	return 0;
-}
-
-
-static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
-{
-	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) {
-		X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
-		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)
-{
-	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;
-	}
-
-	return 0;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	static int counter = 0;
-
-	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 {
-		conn->ca_cert_verify = 0;
-		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
-	}
-
-	SSL_set_accept_state(conn->ssl);
-
-	/*
-	 * Set session id context in order to avoid fatal errors when client
-	 * tries to resume a session. However, set the context to a unique
-	 * value in order to effectively disable session resumption for now
-	 * since not all areas of the server code are ready for it (e.g.,
-	 * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
-	 * handshake).
-	 */
-	counter++;
-	SSL_set_session_id_context(conn->ssl,
-				   (const unsigned char *) &counter,
-				   sizeof(counter));
-
-	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;
-
-	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;
-
-#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;
-	} else {
-		tls_show_errors(MSG_DEBUG, __func__,
-				"SSL_use_certificate_file (DER) failed");
-	}
-
-	if (SSL_use_certificate_file(conn->ssl, client_cert,
-				     SSL_FILETYPE_PEM) == 1) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
-			   " --> OK");
-		return 0;
-	} else {
-		tls_show_errors(MSG_DEBUG, __func__,
-				"SSL_use_certificate_file (PEM) 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(SSL_CTX *ssl_ctx, const char *client_cert)
-{
-#ifndef OPENSSL_NO_STDIO
-	if (client_cert == NULL)
-		return 0;
-
-	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
-					 SSL_FILETYPE_ASN1) != 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(SSL_CTX *ssl_ctx, 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 (!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(ssl_ctx, 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(ssl_ctx, pkey) != 1)
-				res = -1;
-		}
-		EVP_PKEY_free(pkey);
-	}
-
-	if (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(ssl_ctx, cert) != 1) {
-				res = -1;
-				break;
-			}
-		}
-		sk_X509_free(certs);
-	}
-
-	PKCS12_free(p12);
-
-	if (res < 0)
-		tls_get_errors(ssl_ctx);
-
-	return res;
-}
-#endif  /* PKCS12_FUNCS */
-
-
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, 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(ssl_ctx, 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(SSL_CTX *ssl_ctx, SSL *ssl,
-				const u8 *blob, size_t len, const char *passwd)
-{
-#ifdef PKCS12_FUNCS
-	PKCS12 *p12;
-
-	p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
-	if (p12 == NULL) {
-		tls_show_errors(MSG_INFO, __func__,
-				"Failed to use PKCS#12 blob");
-		return -1;
-	}
-
-	return tls_parse_pkcs12(ssl_ctx, 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)) {
-		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
-			   " '%s' [%s]", cert_id,
-			   ERR_error_string(ERR_get_error(), NULL));
-		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(void *_ssl_ctx,
-					 struct tls_connection *conn,
-					 const char *ca_cert_id)
-{
-#ifndef OPENSSL_NO_ENGINE
-	X509 *cert;
-	SSL_CTX *ssl_ctx = _ssl_ctx;
-
-	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
-		return -1;
-
-	/* start off the same as tls_connection_ca_cert */
-	X509_STORE_free(ssl_ctx->cert_store);
-	ssl_ctx->cert_store = X509_STORE_new();
-	if (ssl_ctx->cert_store == NULL) {
-		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
-			   "certificate store", __func__);
-		X509_free(cert);
-		return -1;
-	}
-	if (!X509_STORE_add_cert(ssl_ctx->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);
-	return 0;
-
-#else /* OPENSSL_NO_ENGINE */
-	return -1;
-#endif /* OPENSSL_NO_ENGINE */
-}
-
-
-static int tls_connection_engine_private_key(struct tls_connection *conn)
-{
-#ifndef 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(void *_ssl_ctx,
-				      struct tls_connection *conn,
-				      const char *private_key,
-				      const char *private_key_passwd,
-				      const u8 *private_key_blob,
-				      size_t private_key_blob_len)
-{
-	SSL_CTX *ssl_ctx = _ssl_ctx;
-	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;
-		} else {
-			tls_show_errors(MSG_DEBUG, __func__,
-					"SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
-					" failed");
-		}
-
-		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;
-		} else {
-			tls_show_errors(MSG_DEBUG, __func__,
-					"SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
-					" failed");
-		}
-
-		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;
-		} else {
-			tls_show_errors(MSG_DEBUG, __func__,
-					"SSL_use_RSAPrivateKey_ASN1 failed");
-		}
-
-		if (tls_read_pkcs12_blob(ssl_ctx, 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;
-		} else {
-			tls_show_errors(MSG_DEBUG, __func__,
-					"SSL_use_PrivateKey_File (DER) "
-					"failed");
-		}
-
-		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 {
-			tls_show_errors(MSG_DEBUG, __func__,
-					"SSL_use_PrivateKey_File (PEM) "
-					"failed");
-		}
-#else /* OPENSSL_NO_STDIO */
-		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
-			   __func__);
-#endif /* OPENSSL_NO_STDIO */
-
-		if (tls_read_pkcs12(ssl_ctx, 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) {
-		wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
-		os_free(passwd);
-		ERR_clear_error();
-		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(SSL_CTX *ssl_ctx, const char *private_key,
-				  const char *private_key_passwd)
-{
-	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(ssl_ctx, 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(SSL_CTX *ssl_ctx, 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 (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_keys(void *ssl_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	SSL *ssl;
-
-	if (conn == NULL || keys == NULL)
-		return -1;
-	ssl = conn->ssl;
-	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
-		return -1;
-
-	os_memset(keys, 0, sizeof(*keys));
-	keys->master_key = ssl->session->master_key;
-	keys->master_key_len = ssl->session->master_key_length;
-	keys->client_random = ssl->s3->client_random;
-	keys->client_random_len = SSL3_RANDOM_SIZE;
-	keys->server_random = ssl->s3->server_random;
-	keys->server_random_len = SSL3_RANDOM_SIZE;
-
-	return 0;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-	return -1;
-}
-
-
-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 &&
-	    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 (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
-		*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
-
-	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);
-
-	return buf;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
-	return conn ? conn->ssl->hit : 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	char buf[100], *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;
-		default:
-			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
-				   "cipher selection: %d", *c);
-			return -1;
-		}
-		ret = os_snprintf(pos, end - pos, ":%s", suite);
-		if (ret < 0 || ret >= end - pos)
-			break;
-		pos += ret;
-
-		c++;
-	}
-
-	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
-
-	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_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;
-
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
-	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
-				       data_len) != 1)
-		return -1;
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-	if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
-				    data_len) != 1)
-		return -1;
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-
-	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;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	int ret;
-	unsigned long err;
-
-	if (conn == NULL)
-		return -1;
-
-	while ((err = ERR_get_error())) {
-		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
-			   __func__, ERR_error_string(err, NULL));
-	}
-
-	if (params->engine) {
-		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
-		ret = tls_engine_init(conn, params->engine_id, params->pin,
-				      params->key_id, params->cert_id,
-				      params->ca_cert_id);
-		if (ret)
-			return ret;
-	}
-	if (tls_connection_set_subject_match(conn,
-					     params->subject_match,
-					     params->altsubject_match))
-		return -1;
-
-	if (params->engine && params->ca_cert_id) {
-		if (tls_connection_engine_ca_cert(tls_ctx, conn,
-						  params->ca_cert_id))
-			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
-					  params->ca_cert_blob,
-					  params->ca_cert_blob_len,
-					  params->ca_path))
-		return -1;
-
-	if (params->engine && params->cert_id) {
-		if (tls_connection_engine_client_cert(conn, params->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 (params->engine && params->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(tls_ctx, 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;
-	}
-
-	tls_get_errors(tls_ctx);
-
-	return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	SSL_CTX *ssl_ctx = tls_ctx;
-	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(ssl_ctx, params->ca_cert))
-		return -1;
-
-	if (tls_global_client_cert(ssl_ctx, params->client_cert))
-		return -1;
-
-	if (tls_global_private_key(ssl_ctx, params->private_key,
-				   params->private_key_passwd))
-		return -1;
-
-	if (tls_global_dh(ssl_ctx, params->dh_file)) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
-			   params->dh_file);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
-				     struct tls_connection *conn)
-{
-	const EVP_CIPHER *c;
-	const EVP_MD *h;
-
-	if (conn == NULL || conn->ssl == NULL ||
-	    conn->ssl->enc_read_ctx == NULL ||
-	    conn->ssl->enc_read_ctx->cipher == NULL ||
-	    conn->ssl->read_hash == NULL)
-		return -1;
-
-	c = conn->ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-	h = EVP_MD_CTX_md(conn->ssl->read_hash);
-#else
-	h = conn->ssl->read_hash;
-#endif
-
-	return 2 * (EVP_CIPHER_key_length(c) +
-		    EVP_MD_size(h) +
-		    EVP_CIPHER_iv_length(c));
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
-#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. */
-
-static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
-			   STACK_OF(SSL_CIPHER) *peer_ciphers,
-			   SSL_CIPHER **cipher, void *arg)
-{
-	struct tls_connection *conn = arg;
-	int ret;
-
-	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);
-	os_free(conn->session_ticket);
-	conn->session_ticket = NULL;
-
-	if (ret <= 0)
-		return 0;
-
-	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
-	return 1;
-}
-
-
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
-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;
-}
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-static void tls_hello_ext_cb(SSL *s, int client_server, int type,
-			     unsigned char *data, int len, void *arg)
-{
-	struct tls_connection *conn = arg;
-
-	if (conn == NULL || conn->session_ticket_cb == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-		   type, len);
-
-	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
-		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;
-
-		os_memcpy(conn->session_ticket, data, len);
-		conn->session_ticket_len = len;
-	}
-}
-#else /* SSL_OP_NO_TICKET */
-static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
-{
-	struct tls_connection *conn = arg;
-
-	if (conn == NULL || conn->session_ticket_cb == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-		   ext->type, ext->length);
-
-	os_free(conn->session_ticket);
-	conn->session_ticket = NULL;
-
-	if (ext->type == 35) {
-		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
-			    "extension", ext->data, ext->length);
-		conn->session_ticket = os_malloc(ext->length);
-		if (conn->session_ticket == NULL)
-			return SSL_AD_INTERNAL_ERROR;
-
-		os_memcpy(conn->session_ticket, ext->data, ext->length);
-		conn->session_ticket_len = ext->length;
-	}
-
-	return 0;
-}
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#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;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
-		SSL_set_session_ticket_ext_cb(conn->ssl,
-					      tls_session_ticket_ext_cb, conn);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
-		SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
-		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
-					       conn) != 1)
-			return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-	} else {
-		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
-			return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
-		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
-		SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
-		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
-			return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-	}
-
-	return 0;
-#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
-	return -1;
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
-}

Copied: vendor/wpa/2.0/src/crypto/tls_openssl.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_openssl.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_openssl.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_openssl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3035 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2011, Jouni Malinen <j at 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
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
+
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include "keystore_get.h"
+#endif /* ANDROID */
+
+#include "common.h"
+#include "crypto.h"
+#include "tls.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#define OPENSSL_d2i_TYPE const unsigned char **
+#else
+#define OPENSSL_d2i_TYPE unsigned char **
+#endif
+
+#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
+#ifdef SSL_OP_NO_TICKET
+/*
+ * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
+ * 2008-11-15. This version uses a bit different API compared to the old patch.
+ */
+#define CONFIG_OPENSSL_TICKET_OVERRIDE
+#endif
+#endif
+
+static int tls_openssl_ref_count = 0;
+
+struct tls_global {
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
+};
+
+static struct tls_global *tls_global = NULL;
+
+
+struct tls_connection {
+	SSL *ssl;
+	BIO *ssl_in, *ssl_out;
+#ifndef 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;
+	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;
+
+	u8 srv_cert_hash[32];
+
+	unsigned int flags;
+};
+
+
+#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, (OPENSSL_d2i_TYPE) &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, (OPENSSL_d2i_TYPE) &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);
+
+		if (!X509_STORE_add_cert(ssl_ctx->cert_store, 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) {
+		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) {
+			struct tls_connection *conn =
+				SSL_get_app_data((SSL *) ssl);
+			if (where & SSL_CB_READ)
+				conn->read_alerts++;
+			else
+				conn->write_alerts++;
+		}
+		if (tls_global->event_cb != NULL) {
+			union tls_event_data ev;
+			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);
+			tls_global->event_cb(tls_global->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) {
+		ENGINE_free(engine);
+		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
+			   "available", id);
+		return 0;
+	}
+	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;
+	}
+
+	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 || !pkcs11_module_path)
+		return 0;
+
+	pre_cmd[1] = pkcs11_so_path;
+	pre_cmd[3] = engine_id;
+	post_cmd[1] = pkcs11_module_path;
+
+	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 */
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	SSL_CTX *ssl;
+
+	if (tls_openssl_ref_count == 0) {
+		tls_global = os_zalloc(sizeof(*tls_global));
+		if (tls_global == NULL)
+			return NULL;
+		if (conf) {
+			tls_global->event_cb = conf->event_cb;
+			tls_global->cb_ctx = conf->cb_ctx;
+			tls_global->cert_in_cb = conf->cert_in_cb;
+		}
+
+#ifdef CONFIG_FIPS
+#ifdef OPENSSL_FIPS
+		if (conf && conf->fips_mode) {
+			if (!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");
+		}
+#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 */
+		SSL_load_error_strings();
+		SSL_library_init();
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(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 */
+	}
+	tls_openssl_ref_count++;
+
+	ssl = SSL_CTX_new(TLSv1_method());
+	if (ssl == NULL)
+		return NULL;
+
+	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+
+#ifndef OPENSSL_NO_ENGINE
+	if (conf &&
+	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
+	     conf->pkcs11_module_path)) {
+		wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+		ERR_load_ENGINE_strings();
+		ENGINE_load_dynamic();
+
+		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
+		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
+						   conf->pkcs11_module_path)) {
+			tls_deinit(ssl);
+			return NULL;
+		}
+	}
+#endif /* OPENSSL_NO_ENGINE */
+
+	return ssl;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	SSL_CTX_free(ssl);
+
+	tls_openssl_ref_count--;
+	if (tls_openssl_ref_count == 0) {
+#ifndef OPENSSL_NO_ENGINE
+		ENGINE_cleanup();
+#endif /* OPENSSL_NO_ENGINE */
+		CRYPTO_cleanup_all_ex_data();
+		ERR_remove_state(0);
+		ERR_free_strings();
+		EVP_cleanup();
+		os_free(tls_global);
+		tls_global = NULL;
+	}
+}
+
+
+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)
+{
+#ifndef OPENSSL_NO_ENGINE
+	int ret = -1;
+	if (engine_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
+		return -1;
+	}
+	if (pin == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
+		return -1;
+	}
+	if (key_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
+		return -1;
+	}
+
+	ERR_clear_error();
+	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");
+
+	if (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;
+	}
+	/* load private key first in-case PIN is required for cert */
+	conn->private_key = ENGINE_load_private_key(conn->engine,
+						    key_id, NULL, NULL);
+	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));
+		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)
+{
+#ifndef 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) {
+		ENGINE_finish(conn->engine);
+		conn->engine = NULL;
+	}
+#endif /* 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;
+}
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	struct tls_connection *conn;
+	long options;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+	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;
+	}
+
+	SSL_set_app_data(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;
+	SSL_free(conn->ssl);
+	tls_engine_deinit(conn);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_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 0;
+}
+
+
+static int tls_match_altsubject_component(X509 *cert, int type,
+					  const char *value, size_t len)
+{
+	GENERAL_NAME *gen;
+	void *ext;
+	int i, found = 0;
+
+	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++;
+	}
+
+	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;
+}
+
+
+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;
+
+	if (tls_global->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;
+	tls_global->event_cb(tls_global->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;
+#ifdef CONFIG_SHA256
+	u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+	if (tls_global->event_cb == NULL)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	if (conn->cert_probe || tls_global->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;
+	tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	wpabuf_free(cert);
+}
+
+
+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;
+	char *match, *altmatch;
+	const char *err_str;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	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;
+	match = conn->subject_match;
+	altmatch = conn->altsubject_match;
+
+	if (!preverify_ok && !conn->ca_cert_verify)
+		preverify_ok = 1;
+	if (!preverify_ok && depth > 0 && conn->server_cert_only)
+		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, "OpenSSL: Ignore certificate validity "
+			   "time mismatch");
+		preverify_ok = 1;
+	}
+
+	err_str = X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+	if (preverify_ok && depth == 0 && conn->server_cert_only) {
+		struct wpabuf *cert;
+		cert = get_x509_cert(err_cert);
+		if (!cert) {
+			wpa_printf(MSG_DEBUG, "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;
+			}
+			wpabuf_free(cert);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "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 - 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: 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: 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
+		openssl_tls_cert_event(conn, err_cert, depth, buf);
+
+	if (conn->cert_probe && preverify_ok && depth == 0) {
+		wpa_printf(MSG_DEBUG, "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);
+	}
+
+	if (preverify_ok && tls_global->event_cb != NULL)
+		tls_global->event_cb(tls_global->cb_ctx,
+				     TLS_CERT_CHAIN_SUCCESS, NULL);
+
+	return preverify_ok;
+}
+
+
+#ifndef OPENSSL_NO_STDIO
+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	X509_LOOKUP *lookup;
+	int ret = 0;
+
+	lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+				       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 */
+
+
+#ifdef ANDROID
+static BIO * BIO_from_keystore(const char *key)
+{
+	BIO *bio = NULL;
+	char value[KEYSTORE_MESSAGE_SIZE];
+	int length = keystore_get(key, strlen(key), value);
+	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+		BIO_write(bio, value, length);
+	return bio;
+}
+#endif /* ANDROID */
+
+
+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+				  const char *ca_cert, const u8 *ca_cert_blob,
+				  size_t ca_cert_blob_len, const char *ca_path)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	/*
+	 * Remove previously configured trusted CA certificates before adding
+	 * new ones.
+	 */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		return -1;
+	}
+
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
+			   "chain");
+		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, (OPENSSL_d2i_TYPE) &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->cert_store, 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
+	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&ca_cert[11]);
+		STACK_OF(X509_INFO) *stack = NULL;
+		int i;
+
+		if (bio) {
+			stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (!stack)
+			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(ssl_ctx->cert_store,
+						    info->x509);
+			}
+			if (info->crl) {
+				X509_STORE_add_crl(ssl_ctx->cert_store,
+						   info->crl);
+			}
+		}
+		sk_X509_INFO_pop_free(stack, X509_INFO_free);
+		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(ssl_ctx, 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(ssl_ctx);
+		}
+#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 */
+		conn->ca_cert_verify = 0;
+	}
+
+	return 0;
+}
+
+
+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+{
+	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) {
+		X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+		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)
+{
+	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;
+	}
+
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	static int counter = 0;
+
+	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 {
+		conn->ca_cert_verify = 0;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+	}
+
+	SSL_set_accept_state(conn->ssl);
+
+	/*
+	 * Set session id context in order to avoid fatal errors when client
+	 * tries to resume a session. However, set the context to a unique
+	 * value in order to effectively disable session resumption for now
+	 * since not all areas of the server code are ready for it (e.g.,
+	 * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
+	 * handshake).
+	 */
+	counter++;
+	SSL_set_session_id_context(conn->ssl,
+				   (const unsigned char *) &counter,
+				   sizeof(counter));
+
+	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;
+
+	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(SSL_CTX *ssl_ctx, const char *client_cert)
+{
+#ifndef OPENSSL_NO_STDIO
+	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(SSL_CTX *ssl_ctx, 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 (!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(ssl_ctx, 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(ssl_ctx, pkey) != 1)
+				res = -1;
+		}
+		EVP_PKEY_free(pkey);
+	}
+
+	if (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(ssl_ctx, cert) != 1) {
+				res = -1;
+				break;
+			}
+		}
+		sk_X509_free(certs);
+	}
+
+	PKCS12_free(p12);
+
+	if (res < 0)
+		tls_get_errors(ssl_ctx);
+
+	return res;
+}
+#endif  /* PKCS12_FUNCS */
+
+
+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, 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(ssl_ctx, 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(SSL_CTX *ssl_ctx, SSL *ssl,
+				const u8 *blob, size_t len, const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+	PKCS12 *p12;
+
+	p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+	if (p12 == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to use PKCS#12 blob");
+		return -1;
+	}
+
+	return tls_parse_pkcs12(ssl_ctx, 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)) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
+			   " '%s' [%s]", cert_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		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(void *_ssl_ctx,
+					 struct tls_connection *conn,
+					 const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+		return -1;
+
+	/* start off the same as tls_connection_ca_cert */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		X509_free(cert);
+		return -1;
+	}
+	if (!X509_STORE_add_cert(ssl_ctx->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)
+{
+#ifndef 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(void *_ssl_ctx,
+				      struct tls_connection *conn,
+				      const char *private_key,
+				      const char *private_key_passwd,
+				      const u8 *private_key_blob,
+				      size_t private_key_blob_len)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	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(ssl_ctx, 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;
+	}
+
+#ifdef ANDROID
+	if (!ok && private_key &&
+	    os_strncmp("keystore://", private_key, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&private_key[11]);
+		EVP_PKEY *pkey = NULL;
+		if (bio) {
+			pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (pkey) {
+			if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: Private key "
+					   "from keystore");
+				ok = 1;
+			}
+			EVP_PKEY_free(pkey);
+		}
+	}
+#endif /* ANDROID */
+
+	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(ssl_ctx, 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(SSL_CTX *ssl_ctx, const char *private_key,
+				  const char *private_key_passwd)
+{
+	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(ssl_ctx, 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(SSL_CTX *ssl_ctx, 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 (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_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef CONFIG_FIPS
+	wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+		   "mode");
+	return -1;
+#else /* CONFIG_FIPS */
+	SSL *ssl;
+
+	if (conn == NULL || keys == NULL)
+		return -1;
+	ssl = conn->ssl;
+	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+	keys->master_key = ssl->session->master_key;
+	keys->master_key_len = ssl->session->master_key_length;
+	keys->client_random = ssl->s3->client_random;
+	keys->client_random_len = SSL3_RANDOM_SIZE;
+	keys->server_random = ssl->s3->server_random;
+	keys->server_random_len = SSL3_RANDOM_SIZE;
+
+	return 0;
+#endif /* CONFIG_FIPS */
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+	SSL *ssl;
+	if (conn == NULL)
+		return -1;
+	if (server_random_first)
+		return -1;
+	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 -1;
+}
+
+
+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 &&
+	    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 (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
+		*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+
+	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);
+
+	return buf;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->ssl->hit : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	char buf[100], *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;
+		default:
+			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
+				   "cipher selection: %d", *c);
+			return -1;
+		}
+		ret = os_snprintf(pos, end - pos, ":%s", suite);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		c++;
+	}
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+
+	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_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;
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
+				       data_len) != 1)
+		return -1;
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
+				    data_len) != 1)
+		return -1;
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+
+	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;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+	unsigned long err;
+
+	if (conn == NULL)
+		return -1;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (params->engine) {
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		ret = tls_engine_init(conn, params->engine_id, params->pin,
+				      params->key_id, params->cert_id,
+				      params->ca_cert_id);
+		if (ret)
+			return ret;
+	}
+	if (tls_connection_set_subject_match(conn,
+					     params->subject_match,
+					     params->altsubject_match))
+		return -1;
+
+	if (params->engine && params->ca_cert_id) {
+		if (tls_connection_engine_ca_cert(tls_ctx, conn,
+						  params->ca_cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+					  params->ca_cert_blob,
+					  params->ca_cert_blob_len,
+					  params->ca_path))
+		return -1;
+
+	if (params->engine && params->cert_id) {
+		if (tls_connection_engine_client_cert(conn, params->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 (params->engine && params->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(tls_ctx, 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;
+	}
+
+#ifdef SSL_OP_NO_TICKET
+	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+	else
+		SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	conn->flags = params->flags;
+
+	tls_get_errors(tls_ctx);
+
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	SSL_CTX *ssl_ctx = tls_ctx;
+	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(ssl_ctx, params->ca_cert))
+		return -1;
+
+	if (tls_global_client_cert(ssl_ctx, params->client_cert))
+		return -1;
+
+	if (tls_global_private_key(ssl_ctx, params->private_key,
+				   params->private_key_passwd))
+		return -1;
+
+	if (tls_global_dh(ssl_ctx, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		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);
+	else
+		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	const EVP_CIPHER *c;
+	const EVP_MD *h;
+	int md_size;
+
+	if (conn == NULL || conn->ssl == NULL ||
+	    conn->ssl->enc_read_ctx == NULL ||
+	    conn->ssl->enc_read_ctx->cipher == NULL ||
+	    conn->ssl->read_hash == NULL)
+		return -1;
+
+	c = conn->ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+	h = EVP_MD_CTX_md(conn->ssl->read_hash);
+#else
+	h = conn->ssl->read_hash;
+#endif
+	if (h)
+		md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+	else if (conn->ssl->s3)
+		md_size = conn->ssl->s3->tmp.new_mac_secret_size;
+#endif
+	else
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+		   "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+		   EVP_CIPHER_iv_length(c));
+	return 2 * (EVP_CIPHER_key_length(c) +
+		    md_size +
+		    EVP_CIPHER_iv_length(c));
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+			   STACK_OF(SSL_CIPHER) *peer_ciphers,
+			   SSL_CIPHER **cipher, void *arg)
+{
+	struct tls_connection *conn = arg;
+	int ret;
+
+	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);
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ret <= 0)
+		return 0;
+
+	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+	return 1;
+}
+
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+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;
+}
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+static void tls_hello_ext_cb(SSL *s, int client_server, int type,
+			     unsigned char *data, int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   type, len);
+
+	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
+		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;
+
+		os_memcpy(conn->session_ticket, data, len);
+		conn->session_ticket_len = len;
+	}
+}
+#else /* SSL_OP_NO_TICKET */
+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   ext->type, ext->length);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ext->type == 35) {
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", ext->data, ext->length);
+		conn->session_ticket = os_malloc(ext->length);
+		if (conn->session_ticket == NULL)
+			return SSL_AD_INTERNAL_ERROR;
+
+		os_memcpy(conn->session_ticket, ext->data, ext->length);
+		conn->session_ticket_len = ext->length;
+	}
+
+	return 0;
+}
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#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;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl,
+					      tls_session_ticket_ext_cb, conn);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
+					       conn) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	} else {
+		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	}
+
+	return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+	return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}

Deleted: vendor/wpa/2.0/src/crypto/tls_schannel.c
===================================================================
--- vendor/wpa/dist/src/crypto/tls_schannel.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/crypto/tls_schannel.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,767 +0,0 @@
-/*
- * SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-/*
- * FIX: Go through all SSPI functions and verify what needs to be freed
- * FIX: session resumption
- * TODO: add support for server cert chain validation
- * TODO: add support for CA cert validation
- * TODO: add support for EAP-TLS (client cert/key conf)
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-#include <schannel.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <sspi.h>
-
-#include "common.h"
-#include "tls.h"
-
-
-struct tls_global {
-	HMODULE hsecurity;
-	PSecurityFunctionTable sspi;
-	HCERTSTORE my_cert_store;
-};
-
-struct tls_connection {
-	int established, start;
-	int failed, read_alerts, write_alerts;
-
-	SCHANNEL_CRED schannel_cred;
-	CredHandle creds;
-	CtxtHandle context;
-
-	u8 eap_tls_prf[128];
-	int eap_tls_prf_set;
-};
-
-
-static int schannel_load_lib(struct tls_global *global)
-{
-	INIT_SECURITY_INTERFACE pInitSecurityInterface;
-
-	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
-	if (global->hsecurity == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		return -1;
-	}
-
-	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
-		global->hsecurity, "InitSecurityInterfaceA");
-	if (pInitSecurityInterface == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not find "
-			   "InitSecurityInterfaceA from Secur32.dll",
-			   __func__);
-		FreeLibrary(global->hsecurity);
-		global->hsecurity = NULL;
-		return -1;
-	}
-
-	global->sspi = pInitSecurityInterface();
-	if (global->sspi == NULL) {
-		wpa_printf(MSG_ERROR, "%s: Could not read security "
-			   "interface - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		FreeLibrary(global->hsecurity);
-		global->hsecurity = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
-	struct tls_global *global;
-
-	global = os_zalloc(sizeof(*global));
-	if (global == NULL)
-		return NULL;
-	if (schannel_load_lib(global)) {
-		os_free(global);
-		return NULL;
-	}
-	return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
-	struct tls_global *global = ssl_ctx;
-
-	if (global->my_cert_store)
-		CertCloseStore(global->my_cert_store, 0);
-	FreeLibrary(global->hsecurity);
-	os_free(global);
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
-	return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
-	struct tls_connection *conn;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-	conn->start = 1;
-
-	return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return;
-
-	os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
-	return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
-	struct tls_global *global = ssl_ctx;
-	if (conn == NULL)
-		return -1;
-
-	conn->eap_tls_prf_set = 0;
-	conn->established = conn->failed = 0;
-	conn->read_alerts = conn->write_alerts = 0;
-	global->sspi->DeleteSecurityContext(&conn->context);
-	/* FIX: what else needs to be reseted? */
-
-	return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
-			  const struct tls_connection_params *params)
-{
-	return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
-	return -1;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-			      int verify_peer)
-{
-	return -1;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
-			    struct tls_keys *keys)
-{
-	/* Schannel does not export master secret or client/server random. */
-	return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-		       const char *label, int server_random_first,
-		       u8 *out, size_t out_len)
-{
-	/*
-	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
-	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
-	 * EAP-TTLS cannot use this, though, since they are using different
-	 * labels. The only option could be to implement TLSv1 completely here
-	 * and just use Schannel or CryptoAPI for low-level crypto
-	 * functionality..
-	 */
-
-	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
-	    os_strcmp(label, "client EAP encryption") != 0 ||
-	    out_len > sizeof(conn->eap_tls_prf))
-		return -1;
-
-	os_memcpy(out, conn->eap_tls_prf, out_len);
-
-	return 0;
-}
-
-
-static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
-					       struct tls_connection *conn)
-{
-	DWORD sspi_flags, sspi_flags_out;
-	SecBufferDesc outbuf;
-	SecBuffer outbufs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-
-	sspi_flags = ISC_REQ_REPLAY_DETECT |
-		ISC_REQ_CONFIDENTIALITY |
-		ISC_RET_EXTENDED_ERROR |
-		ISC_REQ_ALLOCATE_MEMORY |
-		ISC_REQ_MANUAL_CRED_VALIDATION;
-
-	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
-
-	outbufs[0].pvBuffer = NULL;
-	outbufs[0].BufferType = SECBUFFER_TOKEN;
-	outbufs[0].cbBuffer = 0;
-
-	outbuf.cBuffers = 1;
-	outbuf.pBuffers = outbufs;
-	outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
-	status = global->sspi->InitializeSecurityContextW(
-		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->InitializeSecurityContextA(
-		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-	if (status != SEC_I_CONTINUE_NEEDED) {
-		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
-			   "failed - 0x%x",
-			   __func__, (unsigned int) status);
-		return NULL;
-	}
-
-	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
-		struct wpabuf *buf;
-		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
-			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
-		conn->start = 0;
-		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
-					outbufs[0].cbBuffer);
-		if (buf == NULL)
-			return NULL;
-		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
-		return buf;
-	}
-
-	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
-
-	return NULL;
-}
-
-
-#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
-#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
-
-typedef struct _SecPkgContext_EapKeyBlock {
-	BYTE rgbKeys[128];
-	BYTE rgbIVs[64];
-} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
-#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
-
-static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
-{
-	SECURITY_STATUS status;
-	SecPkgContext_EapKeyBlock kb;
-
-	/* Note: Windows NT and Windows Me/98/95 do not support getting
-	 * EapKeyBlock */
-
-	status = global->sspi->QueryContextAttributes(
-		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
-			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
-			   __func__, (int) status);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
-			kb.rgbKeys, sizeof(kb.rgbKeys));
-	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
-			kb.rgbIVs, sizeof(kb.rgbIVs));
-
-	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
-	conn->eap_tls_prf_set = 1;
-	return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
-					 struct tls_connection *conn,
-					 const struct wpabuf *in_data,
-					 struct wpabuf **appl_data)
-{
-	struct tls_global *global = tls_ctx;
-	DWORD sspi_flags, sspi_flags_out;
-	SecBufferDesc inbuf, outbuf;
-	SecBuffer inbufs[2], outbufs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-	struct wpabuf *out_buf = NULL;
-
-	if (appl_data)
-		*appl_data = NULL;
-
-	if (conn->start)
-		return tls_conn_hs_clienthello(global, conn);
-
-	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
-		   (int) wpabuf_len(in_data));
-
-	sspi_flags = ISC_REQ_REPLAY_DETECT |
-		ISC_REQ_CONFIDENTIALITY |
-		ISC_RET_EXTENDED_ERROR |
-		ISC_REQ_ALLOCATE_MEMORY |
-		ISC_REQ_MANUAL_CRED_VALIDATION;
-
-	/* Input buffer for Schannel */
-	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
-	inbufs[0].cbBuffer = wpabuf_len(in_data);
-	inbufs[0].BufferType = SECBUFFER_TOKEN;
-
-	/* Place for leftover data from Schannel */
-	inbufs[1].pvBuffer = NULL;
-	inbufs[1].cbBuffer = 0;
-	inbufs[1].BufferType = SECBUFFER_EMPTY;
-
-	inbuf.cBuffers = 2;
-	inbuf.pBuffers = inbufs;
-	inbuf.ulVersion = SECBUFFER_VERSION;
-
-	/* Output buffer for Schannel */
-	outbufs[0].pvBuffer = NULL;
-	outbufs[0].cbBuffer = 0;
-	outbufs[0].BufferType = SECBUFFER_TOKEN;
-
-	outbuf.cBuffers = 1;
-	outbuf.pBuffers = outbufs;
-	outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
-	status = global->sspi->InitializeSecurityContextW(
-		&conn->creds, &conn->context, NULL, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->InitializeSecurityContextA(
-		&conn->creds, &conn->context, NULL, sspi_flags, 0,
-		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
-		&outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-
-	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
-		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
-		   "intype[1]=%d outlen[0]=%d",
-		   (int) status, (int) inbufs[0].cbBuffer,
-		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
-		   (int) inbufs[1].BufferType,
-		   (int) outbufs[0].cbBuffer);
-	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
-	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
-		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
-			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
-				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
-			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
-						    outbufs[0].cbBuffer);
-			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
-			outbufs[0].pvBuffer = NULL;
-			if (out_buf == NULL)
-				return NULL;
-		}
-	}
-
-	switch (status) {
-	case SEC_E_INCOMPLETE_MESSAGE:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
-		break;
-	case SEC_I_CONTINUE_NEEDED:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
-		break;
-	case SEC_E_OK:
-		/* TODO: verify server certificate chain */
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
-			   "completed successfully");
-		conn->established = 1;
-		tls_get_eap(global, conn);
-
-		/* Need to return something to get final TLS ACK. */
-		if (out_buf == NULL)
-			out_buf = wpabuf_alloc(0);
-
-		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
-			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
-				    "application data",
-				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
-			if (appl_data) {
-				*appl_data = wpabuf_alloc_copy(
-					outbufs[1].pvBuffer,
-					outbufs[1].cbBuffer);
-			}
-			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
-			inbufs[1].pvBuffer = NULL;
-		}
-		break;
-	case SEC_I_INCOMPLETE_CREDENTIALS:
-		wpa_printf(MSG_DEBUG,
-			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
-		break;
-	case SEC_E_WRONG_PRINCIPAL:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
-		break;
-	case SEC_E_INTERNAL_ERROR:
-		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
-		break;
-	}
-
-	if (FAILED(status)) {
-		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
-			   "(out_buf=%p)", out_buf);
-		conn->failed++;
-		global->sspi->DeleteSecurityContext(&conn->context);
-		return out_buf;
-	}
-
-	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
-		/* TODO: Can this happen? What to do with this data? */
-		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
-			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
-		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
-		inbufs[1].pvBuffer = NULL;
-	}
-
-	return out_buf;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
-						struct tls_connection *conn,
-						const struct wpabuf *in_data,
-						struct wpabuf **appl_data)
-{
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	struct tls_global *global = tls_ctx;
-	SECURITY_STATUS status;
-	SecBufferDesc buf;
-	SecBuffer bufs[4];
-	SecPkgContext_StreamSizes sizes;
-	int i;
-	struct wpabuf *out;
-
-	status = global->sspi->QueryContextAttributes(&conn->context,
-						      SECPKG_ATTR_STREAM_SIZES,
-						      &sizes);
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
-			   __func__);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
-		   __func__,
-		   (unsigned int) sizes.cbHeader,
-		   (unsigned int) sizes.cbTrailer);
-
-	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
-			   sizes.cbTrailer);
-
-	os_memset(&bufs, 0, sizeof(bufs));
-	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
-	bufs[0].cbBuffer = sizes.cbHeader;
-	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
-
-	bufs[1].pvBuffer = wpabuf_put(out, 0);
-	wpabuf_put_buf(out, in_data);
-	bufs[1].cbBuffer = wpabuf_len(in_data);
-	bufs[1].BufferType = SECBUFFER_DATA;
-
-	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
-	bufs[2].cbBuffer = sizes.cbTrailer;
-	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-
-	buf.ulVersion = SECBUFFER_VERSION;
-	buf.cBuffers = 3;
-	buf.pBuffers = bufs;
-
-	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
-
-	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
-		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
-		   "len[2]=%d type[2]=%d",
-		   (int) status,
-		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
-		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
-		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
-	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
-		   "out_data=%p bufs %p %p %p",
-		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
-		   bufs[2].pvBuffer);
-
-	for (i = 0; i < 3; i++) {
-		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
-		{
-			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
-				    bufs[i].pvBuffer, bufs[i].cbBuffer);
-		}
-	}
-
-	if (status == SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
-		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
-				    "from EncryptMessage", out);
-		return out;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
-		   __func__, (int) status);
-	wpabuf_free(out);
-	return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
-				       struct tls_connection *conn,
-				       const struct wpabuf *in_data)
-{
-	struct tls_global *global = tls_ctx;
-	SECURITY_STATUS status;
-	SecBufferDesc buf;
-	SecBuffer bufs[4];
-	int i;
-	struct wpabuf *out, *tmp;
-
-	wpa_hexdump_buf(MSG_MSGDUMP,
-			"Schannel: Encrypted data to DecryptMessage", in_data);
-	os_memset(&bufs, 0, sizeof(bufs));
-	tmp = wpabuf_dup(in_data);
-	if (tmp == NULL)
-		return NULL;
-	bufs[0].pvBuffer = wpabuf_mhead(tmp);
-	bufs[0].cbBuffer = wpabuf_len(in_data);
-	bufs[0].BufferType = SECBUFFER_DATA;
-
-	bufs[1].BufferType = SECBUFFER_EMPTY;
-	bufs[2].BufferType = SECBUFFER_EMPTY;
-	bufs[3].BufferType = SECBUFFER_EMPTY;
-
-	buf.ulVersion = SECBUFFER_VERSION;
-	buf.cBuffers = 4;
-	buf.pBuffers = bufs;
-
-	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
-						    NULL);
-	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
-		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
-		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
-		   (int) status,
-		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
-		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
-		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
-		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
-	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
-		   "out_data=%p bufs %p %p %p %p",
-		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
-		   bufs[2].pvBuffer, bufs[3].pvBuffer);
-
-	switch (status) {
-	case SEC_E_INCOMPLETE_MESSAGE:
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
-			   __func__);
-		break;
-	case SEC_E_OK:
-		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
-		for (i = 0; i < 4; i++) {
-			if (bufs[i].BufferType == SECBUFFER_DATA)
-				break;
-		}
-		if (i == 4) {
-			wpa_printf(MSG_DEBUG, "%s: No output data from "
-				   "DecryptMessage", __func__);
-			wpabuf_free(tmp);
-			return NULL;
-		}
-		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
-				"DecryptMessage",
-				bufs[i].pvBuffer, bufs[i].cbBuffer);
-		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
-		wpabuf_free(tmp);
-		return out;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
-		   __func__, (int) status);
-	wpabuf_free(tmp);
-	return NULL;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
-				   u8 *ciphers)
-{
-	return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
-		   char *buf, size_t buflen)
-{
-	return -1;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
-				     struct tls_connection *conn)
-{
-	return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
-				    int ext_type, const u8 *data,
-				    size_t data_len)
-{
-	return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-	return conn->write_alerts;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
-			      const struct tls_connection_params *params)
-{
-	struct tls_global *global = tls_ctx;
-	ALG_ID algs[1];
-	SECURITY_STATUS status;
-	TimeStamp ts_expiry;
-
-	if (conn == NULL)
-		return -1;
-
-	if (global->my_cert_store == NULL &&
-	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
-	    NULL) {
-		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
-			   __func__, (unsigned int) GetLastError());
-		return -1;
-	}
-
-	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
-	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
-	algs[0] = CALG_RSA_KEYX;
-	conn->schannel_cred.cSupportedAlgs = 1;
-	conn->schannel_cred.palgSupportedAlgs = algs;
-	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-#ifdef UNICODE
-	status = global->sspi->AcquireCredentialsHandleW(
-		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
-		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#else /* UNICODE */
-	status = global->sspi->AcquireCredentialsHandleA(
-		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
-		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#endif /* UNICODE */
-	if (status != SEC_E_OK) {
-		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
-			   "0x%x", __func__, (unsigned int) status);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
-	return 0;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}

Copied: vendor/wpa/2.0/src/crypto/tls_schannel.c (from rev 9639, vendor/wpa/dist/src/crypto/tls_schannel.c)
===================================================================
--- vendor/wpa/2.0/src/crypto/tls_schannel.c	                        (rev 0)
+++ vendor/wpa/2.0/src/crypto/tls_schannel.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,732 @@
+/*
+ * SSL/TLS interface functions for Microsoft Schannel
+ * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+/*
+ * FIX: Go through all SSPI functions and verify what needs to be freed
+ * FIX: session resumption
+ * TODO: add support for server cert chain validation
+ * TODO: add support for CA cert validation
+ * TODO: add support for EAP-TLS (client cert/key conf)
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+#include <schannel.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <sspi.h>
+
+#include "common.h"
+#include "tls.h"
+
+
+struct tls_global {
+	HMODULE hsecurity;
+	PSecurityFunctionTable sspi;
+	HCERTSTORE my_cert_store;
+};
+
+struct tls_connection {
+	int established, start;
+	int failed, read_alerts, write_alerts;
+
+	SCHANNEL_CRED schannel_cred;
+	CredHandle creds;
+	CtxtHandle context;
+
+	u8 eap_tls_prf[128];
+	int eap_tls_prf_set;
+};
+
+
+static int schannel_load_lib(struct tls_global *global)
+{
+	INIT_SECURITY_INTERFACE pInitSecurityInterface;
+
+	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
+	if (global->hsecurity == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		return -1;
+	}
+
+	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
+		global->hsecurity, "InitSecurityInterfaceA");
+	if (pInitSecurityInterface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not find "
+			   "InitSecurityInterfaceA from Secur32.dll",
+			   __func__);
+		FreeLibrary(global->hsecurity);
+		global->hsecurity = NULL;
+		return -1;
+	}
+
+	global->sspi = pInitSecurityInterface();
+	if (global->sspi == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not read security "
+			   "interface - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		FreeLibrary(global->hsecurity);
+		global->hsecurity = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+	if (schannel_load_lib(global)) {
+		os_free(global);
+		return NULL;
+	}
+	return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+
+	if (global->my_cert_store)
+		CertCloseStore(global->my_cert_store, 0);
+	FreeLibrary(global->hsecurity);
+	os_free(global);
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	struct tls_connection *conn;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+	conn->start = 1;
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	struct tls_global *global = ssl_ctx;
+	if (conn == NULL)
+		return -1;
+
+	conn->eap_tls_prf_set = 0;
+	conn->established = conn->failed = 0;
+	conn->read_alerts = conn->write_alerts = 0;
+	global->sspi->DeleteSecurityContext(&conn->context);
+	/* FIX: what else needs to be reseted? */
+
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	/* Schannel does not export master secret or client/server random. */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	/*
+	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
+	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
+	 * EAP-TTLS cannot use this, though, since they are using different
+	 * labels. The only option could be to implement TLSv1 completely here
+	 * and just use Schannel or CryptoAPI for low-level crypto
+	 * functionality..
+	 */
+
+	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
+	    os_strcmp(label, "client EAP encryption") != 0 ||
+	    out_len > sizeof(conn->eap_tls_prf))
+		return -1;
+
+	os_memcpy(out, conn->eap_tls_prf, out_len);
+
+	return 0;
+}
+
+
+static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
+					       struct tls_connection *conn)
+{
+	DWORD sspi_flags, sspi_flags_out;
+	SecBufferDesc outbuf;
+	SecBuffer outbufs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+
+	sspi_flags = ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+
+	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
+
+	outbufs[0].pvBuffer = NULL;
+	outbufs[0].BufferType = SECBUFFER_TOKEN;
+	outbufs[0].cbBuffer = 0;
+
+	outbuf.cBuffers = 1;
+	outbuf.pBuffers = outbufs;
+	outbuf.ulVersion = SECBUFFER_VERSION;
+
+#ifdef UNICODE
+	status = global->sspi->InitializeSecurityContextW(
+		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->InitializeSecurityContextA(
+		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
+	if (status != SEC_I_CONTINUE_NEEDED) {
+		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
+			   "failed - 0x%x",
+			   __func__, (unsigned int) status);
+		return NULL;
+	}
+
+	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+		struct wpabuf *buf;
+		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
+			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
+		conn->start = 0;
+		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
+					outbufs[0].cbBuffer);
+		if (buf == NULL)
+			return NULL;
+		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+		return buf;
+	}
+
+	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
+
+	return NULL;
+}
+
+
+#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
+#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
+
+typedef struct _SecPkgContext_EapKeyBlock {
+	BYTE rgbKeys[128];
+	BYTE rgbIVs[64];
+} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
+#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
+
+static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
+{
+	SECURITY_STATUS status;
+	SecPkgContext_EapKeyBlock kb;
+
+	/* Note: Windows NT and Windows Me/98/95 do not support getting
+	 * EapKeyBlock */
+
+	status = global->sspi->QueryContextAttributes(
+		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
+			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
+			   __func__, (int) status);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
+			kb.rgbKeys, sizeof(kb.rgbKeys));
+	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
+			kb.rgbIVs, sizeof(kb.rgbIVs));
+
+	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
+	conn->eap_tls_prf_set = 1;
+	return 0;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct tls_global *global = tls_ctx;
+	DWORD sspi_flags, sspi_flags_out;
+	SecBufferDesc inbuf, outbuf;
+	SecBuffer inbufs[2], outbufs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+	struct wpabuf *out_buf = NULL;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (conn->start)
+		return tls_conn_hs_clienthello(global, conn);
+
+	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
+		   (int) wpabuf_len(in_data));
+
+	sspi_flags = ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+
+	/* Input buffer for Schannel */
+	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
+	inbufs[0].cbBuffer = wpabuf_len(in_data);
+	inbufs[0].BufferType = SECBUFFER_TOKEN;
+
+	/* Place for leftover data from Schannel */
+	inbufs[1].pvBuffer = NULL;
+	inbufs[1].cbBuffer = 0;
+	inbufs[1].BufferType = SECBUFFER_EMPTY;
+
+	inbuf.cBuffers = 2;
+	inbuf.pBuffers = inbufs;
+	inbuf.ulVersion = SECBUFFER_VERSION;
+
+	/* Output buffer for Schannel */
+	outbufs[0].pvBuffer = NULL;
+	outbufs[0].cbBuffer = 0;
+	outbufs[0].BufferType = SECBUFFER_TOKEN;
+
+	outbuf.cBuffers = 1;
+	outbuf.pBuffers = outbufs;
+	outbuf.ulVersion = SECBUFFER_VERSION;
+
+#ifdef UNICODE
+	status = global->sspi->InitializeSecurityContextW(
+		&conn->creds, &conn->context, NULL, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->InitializeSecurityContextA(
+		&conn->creds, &conn->context, NULL, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
+
+	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
+		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
+		   "intype[1]=%d outlen[0]=%d",
+		   (int) status, (int) inbufs[0].cbBuffer,
+		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
+		   (int) inbufs[1].BufferType,
+		   (int) outbufs[0].cbBuffer);
+	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
+	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
+		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
+				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
+			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
+						    outbufs[0].cbBuffer);
+			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+			outbufs[0].pvBuffer = NULL;
+			if (out_buf == NULL)
+				return NULL;
+		}
+	}
+
+	switch (status) {
+	case SEC_E_INCOMPLETE_MESSAGE:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
+		break;
+	case SEC_I_CONTINUE_NEEDED:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
+		break;
+	case SEC_E_OK:
+		/* TODO: verify server certificate chain */
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
+			   "completed successfully");
+		conn->established = 1;
+		tls_get_eap(global, conn);
+
+		/* Need to return something to get final TLS ACK. */
+		if (out_buf == NULL)
+			out_buf = wpabuf_alloc(0);
+
+		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
+			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
+				    "application data",
+				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
+			if (appl_data) {
+				*appl_data = wpabuf_alloc_copy(
+					outbufs[1].pvBuffer,
+					outbufs[1].cbBuffer);
+			}
+			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+			inbufs[1].pvBuffer = NULL;
+		}
+		break;
+	case SEC_I_INCOMPLETE_CREDENTIALS:
+		wpa_printf(MSG_DEBUG,
+			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
+		break;
+	case SEC_E_WRONG_PRINCIPAL:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
+		break;
+	case SEC_E_INTERNAL_ERROR:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
+		break;
+	}
+
+	if (FAILED(status)) {
+		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
+			   "(out_buf=%p)", out_buf);
+		conn->failed++;
+		global->sspi->DeleteSecurityContext(&conn->context);
+		return out_buf;
+	}
+
+	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
+		/* TODO: Can this happen? What to do with this data? */
+		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
+			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
+		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+		inbufs[1].pvBuffer = NULL;
+	}
+
+	return out_buf;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	struct tls_global *global = tls_ctx;
+	SECURITY_STATUS status;
+	SecBufferDesc buf;
+	SecBuffer bufs[4];
+	SecPkgContext_StreamSizes sizes;
+	int i;
+	struct wpabuf *out;
+
+	status = global->sspi->QueryContextAttributes(&conn->context,
+						      SECPKG_ATTR_STREAM_SIZES,
+						      &sizes);
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
+			   __func__);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
+		   __func__,
+		   (unsigned int) sizes.cbHeader,
+		   (unsigned int) sizes.cbTrailer);
+
+	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
+			   sizes.cbTrailer);
+
+	os_memset(&bufs, 0, sizeof(bufs));
+	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
+	bufs[0].cbBuffer = sizes.cbHeader;
+	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+	bufs[1].pvBuffer = wpabuf_put(out, 0);
+	wpabuf_put_buf(out, in_data);
+	bufs[1].cbBuffer = wpabuf_len(in_data);
+	bufs[1].BufferType = SECBUFFER_DATA;
+
+	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
+	bufs[2].cbBuffer = sizes.cbTrailer;
+	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+	buf.ulVersion = SECBUFFER_VERSION;
+	buf.cBuffers = 3;
+	buf.pBuffers = bufs;
+
+	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
+
+	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
+		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+		   "len[2]=%d type[2]=%d",
+		   (int) status,
+		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
+	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
+		   "out_data=%p bufs %p %p %p",
+		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
+		   bufs[2].pvBuffer);
+
+	for (i = 0; i < 3; i++) {
+		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
+		{
+			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
+				    bufs[i].pvBuffer, bufs[i].cbBuffer);
+		}
+	}
+
+	if (status == SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
+				    "from EncryptMessage", out);
+		return out;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+		   __func__, (int) status);
+	wpabuf_free(out);
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	struct tls_global *global = tls_ctx;
+	SECURITY_STATUS status;
+	SecBufferDesc buf;
+	SecBuffer bufs[4];
+	int i;
+	struct wpabuf *out, *tmp;
+
+	wpa_hexdump_buf(MSG_MSGDUMP,
+			"Schannel: Encrypted data to DecryptMessage", in_data);
+	os_memset(&bufs, 0, sizeof(bufs));
+	tmp = wpabuf_dup(in_data);
+	if (tmp == NULL)
+		return NULL;
+	bufs[0].pvBuffer = wpabuf_mhead(tmp);
+	bufs[0].cbBuffer = wpabuf_len(in_data);
+	bufs[0].BufferType = SECBUFFER_DATA;
+
+	bufs[1].BufferType = SECBUFFER_EMPTY;
+	bufs[2].BufferType = SECBUFFER_EMPTY;
+	bufs[3].BufferType = SECBUFFER_EMPTY;
+
+	buf.ulVersion = SECBUFFER_VERSION;
+	buf.cBuffers = 4;
+	buf.pBuffers = bufs;
+
+	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
+						    NULL);
+	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
+		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
+		   (int) status,
+		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
+		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
+	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
+		   "out_data=%p bufs %p %p %p %p",
+		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
+		   bufs[2].pvBuffer, bufs[3].pvBuffer);
+
+	switch (status) {
+	case SEC_E_INCOMPLETE_MESSAGE:
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
+			   __func__);
+		break;
+	case SEC_E_OK:
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+		for (i = 0; i < 4; i++) {
+			if (bufs[i].BufferType == SECBUFFER_DATA)
+				break;
+		}
+		if (i == 4) {
+			wpa_printf(MSG_DEBUG, "%s: No output data from "
+				   "DecryptMessage", __func__);
+			wpabuf_free(tmp);
+			return NULL;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
+				"DecryptMessage",
+				bufs[i].pvBuffer, bufs[i].cbBuffer);
+		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
+		wpabuf_free(tmp);
+		return out;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+		   __func__, (int) status);
+	wpabuf_free(tmp);
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	struct tls_global *global = tls_ctx;
+	ALG_ID algs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+
+	if (conn == NULL)
+		return -1;
+
+	if (global->my_cert_store == NULL &&
+	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
+	    NULL) {
+		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		return -1;
+	}
+
+	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
+	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
+	algs[0] = CALG_RSA_KEYX;
+	conn->schannel_cred.cSupportedAlgs = 1;
+	conn->schannel_cred.palgSupportedAlgs = algs;
+	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+#ifdef UNICODE
+	status = global->sspi->AcquireCredentialsHandleW(
+		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
+		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->AcquireCredentialsHandleA(
+		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
+		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#endif /* UNICODE */
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
+			   "0x%x", __func__, (unsigned int) status);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/drivers/Apple80211.h
===================================================================
--- vendor/wpa/dist/src/drivers/Apple80211.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/Apple80211.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,156 +0,0 @@
-#ifndef APPLE80211_H
-#define APPLE80211_H
-
-/*
- * Apple80211 framework definitions
- * This is an undocumented interface and the definitions here are based on
- * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
- * whatever related information can be found with google and experiments ;-).
- */
-
-typedef struct __WirelessRef *WirelessRef;
-typedef SInt32 WirelessError;
-#define errWirelessNoError 0
-
-typedef struct WirelessInfo {
-	UInt16 link_qual;
-	UInt16 comms_qual;
-	UInt16 signal;
-	UInt16 noise;
-	UInt16 port_stat;
-	UInt16 client_mode;
-	UInt16 res1;
-	UInt16 power;
-	UInt16 res2;
-	UInt8 bssID[6];
-	UInt8 ssid[34];
-} WirelessInfo;
-
-typedef struct WirelessInfo2 {
-	/* TODO - these are probably not in correct order or complete */
-	WirelessInfo info1;
-	UInt8 macAddress[6];
-} WirelessInfo2;
-
-typedef struct WirelessNetworkInfo {
-	UInt16 channel;
-	UInt16 noise;
-	UInt16 signal;
-	UInt8 bssid[6];
-	UInt16 beacon_int;
-	UInt16 capability;
-	UInt16 ssid_len;
-	UInt8 ssid[32];
-} WirelessNetworkInfo;
-
-typedef int wirelessKeyType; /* TODO */
-
-int WirelessIsAvailable(void);
-WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
-WirelessError WirelessDetach(WirelessRef ref);
-WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
-			      void *out_ptr, int out_bytes);
-WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
-WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
-WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
-WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
-WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
-WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
-WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
-			   UInt32 strip_dups);
-WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
-				CFArrayRef *ibss_results, UInt32 strip_dups);
-WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
-				   UInt32 strip_dups, CFStringRef ssid);
-WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
-				    UInt32 strip_dups, CFArrayRef *results);
-WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
-WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
-			      CFStringRef passwd);
-WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
-/*
- * Set WEP key
- * ref: wireless reference from WirelessAttach()
- * type: ?
- * key_idx: 0..3
- * key_len: 13 for WEP-104 or 0 for clearing the key
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
-			     int key_idx, int key_len,
-			     const unsigned char *key);
-/*
- * Set WPA key (e.g., PMK for 4-way handshake)
- * ref: wireless reference from WirelessAttach()
- * type: 0..4; 1 = PMK
- * key_len: 16, 32, or 0
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
-				int key_len, const unsigned char *key);
-WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
-				CFStringRef key);
-WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
-				 CFStringRef key);
-WirelessError WirelessDisassociate(WirelessRef ref);
-
-/*
- * Get a copy of scan results for the given SSID
- * The returned dictionary includes following entries:
- * beaconInterval: CFNumber(kCFNumberSInt32Type)
- * SSID: CFData buffer of the SSID
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
- * name: Name of the network (SSID string)
- * BSSID: CFData buffer of the BSSID
- * channel: CFNumber(kCFNumberSInt32Type)
- * signal: CFNumber(kCFNumberSInt32Type)
- * appleIE: CFData
- * WPSNOPINRequired: CFBoolean
- * noise: CFNumber(kCFNumberSInt32Type)
- * capability: CFNumber(kCFNumberSInt32Type)
- * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
- * appleIE_Version: CFNumber(kCFNumberSInt32Type)
- * appleIE_Robust: CFBoolean
- * WPSConfigured: CFBoolean
- * scanWasDirected: CFBoolean
- * appleIE_Product: CFNumber(kCFNumberSInt32Type)
- * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
- * multiCipher: CFNumber(kCFNumberSInt32Type)
- */
-CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
-
-/*
- * Get information about the current association
- * The returned dictionary includes following entries:
- * keyData: CFData buffer of the key (e.g., 32-octet PSK)
- * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
- * channel: CFNumber(kCFNumberSInt32Type)
- * isIBSS: CFBoolean
- * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
- *	129 = WPA2-Enterprise
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
- * SSID: CFData buffer of the SSID
- * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
- */
-CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
-
-WirelessError WirelessConfigure(WirelessRef ref);
-
-/*
- * Get ASP information
- * The returned dictionary includes following entries:
- * Version: version number (e.g., 3.0)
- * Channel: channel (e.g., 1)
- * Vendor: vendor (e.g., 2)
- */
-CFDictionaryRef WirelessGetInfoASP(void);
-
-/*
- * Get a copy of the interface dictionary
- * The returned dictionary has a key,value pairs for wireless interfaces.
- * The key is the interface name and the value is the driver identifier, e.g.,
- * en1: com.apple.driver.AirPort.Atheros
- */
-CFDictionaryRef WirelessCopyInterfaceDict(void);
-
-#endif /* APPLE80211_H */

Deleted: vendor/wpa/2.0/src/drivers/MobileApple80211.c
===================================================================
--- vendor/wpa/dist/src/drivers/MobileApple80211.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/MobileApple80211.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,189 +0,0 @@
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include "MobileApple80211.h"
-
-/*
- * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
- * having to link with full Preferences.framework.
- */
-
-static void *aeropuerto = NULL;
-
-
-int _Apple80211Initialized(void)
-{
-	return aeropuerto ? 1 : 0;
-}
-
-
-static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
-
-int Apple80211Open(Apple80211Ref *ctx)
-{
-	return __Apple80211Open(ctx);
-}
-
-
-static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
-
-int Apple80211Close(Apple80211Ref ctx)
-{
-	return __Apple80211Close(ctx);
-}
-
-
-static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
-	= NULL;
-
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
-{
-	return __Apple80211GetIfListCopy(handle, list);
-}
-
-
-static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
-					  CFStringRef interface) = NULL;
-
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface)
-{
-	return __Apple80211BindToInterface(handle, interface);
-}
-
-
-static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
-					       CFStringRef *name) = NULL;
-
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name)
-{
-	return __Apple80211GetInterfaceNameCopy(handle, name);
-}
-
-
-static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
-				      CFDictionaryRef *info) = NULL;
-
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info)
-{
-	return __Apple80211GetInfoCopy(handle, info);
-}
-
-
-static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
-
-int Apple80211GetPower(Apple80211Ref handle, char *pwr)
-{
-	return __Apple80211GetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
-
-int Apple80211SetPower(Apple80211Ref handle, char pwr)
-{
-	return __Apple80211SetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
-			       CFDictionaryRef parameters) = NULL;
-
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters)
-{
-	return __Apple80211Scan(handle, list, parameters);
-}
-
-
-static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
-				    CFStringRef password) = NULL;
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password)
-{
-	return __Apple80211Associate(handle, bss, password);
-}
-
-
-static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
-					       CFDictionaryRef bss,
-					       CFStringRef password,
-					       CFDictionaryRef *info) =
-	NULL;
-
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password, CFDictionaryRef *info)
-{
-	return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
-}
-
-
-static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
-				    CFDictionaryRef arg2, void *value) = NULL;
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value)
-{
-	return __Apple80211CopyValue(handle, field, arg2, value);
-}
-
-
-#define DLSYM(s) \
-do { \
-	__ ## s = dlsym(aeropuerto, #s); \
-	if (__ ## s == NULL) { \
-		wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
-			   "symbol '" #s "' (%s)", dlerror()); \
-		err = 1; \
-	} \
-} while (0)
-
-
-__attribute__ ((constructor))
-void _Apple80211_constructor(void)
-{
-	const char *fname = "/System/Library/SystemConfiguration/"
-		"Aeropuerto.bundle/Aeropuerto";
-	int err = 0;
-
-	aeropuerto = dlopen(fname, RTLD_LAZY);
-	if (!aeropuerto) {
-		wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
-			   "for symbols", fname);
-		return;
-	}
-
-	DLSYM(Apple80211Open);
-	DLSYM(Apple80211Close);
-	DLSYM(Apple80211GetIfListCopy);
-	DLSYM(Apple80211BindToInterface);
-	DLSYM(Apple80211GetInterfaceNameCopy);
-	DLSYM(Apple80211GetInfoCopy);
-	DLSYM(Apple80211GetPower);
-	DLSYM(Apple80211SetPower);
-	DLSYM(Apple80211Scan);
-	DLSYM(Apple80211Associate);
-	DLSYM(Apple80211AssociateAndCopyInfo);
-	DLSYM(Apple80211CopyValue);
-
-	if (err) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}
-
-
-__attribute__ ((destructor))
-void _Apple80211_destructor(void)
-{
-	if (aeropuerto) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}

Deleted: vendor/wpa/2.0/src/drivers/MobileApple80211.h
===================================================================
--- vendor/wpa/dist/src/drivers/MobileApple80211.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/MobileApple80211.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,43 +0,0 @@
-#ifndef MOBILEAPPLE80211_H
-#define MOBILEAPPLE80211_H
-
-/*
- * MobileApple80211 interface for iPhone/iPod touch
- * These functions are available from Aeropuerto.
- */
-
-struct Apple80211;
-typedef struct Apple80211 *Apple80211Ref;
-
-int Apple80211Open(Apple80211Ref *ctx);
-int Apple80211Close(Apple80211Ref ctx);
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface);
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name);
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info);
-int Apple80211GetPower(Apple80211Ref handle, char *pwr);
-int Apple80211SetPower(Apple80211Ref handle, char pwr);
-
-/* parameters can be NULL; returns scan results in CFArrayRef *list;
- * caller will need to free with CFRelease() */
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters);
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password);
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password,
-				   CFDictionaryRef *info);
-
-enum {
-	APPLE80211_VALUE_SSID = 1,
-	APPLE80211_VALUE_BSSID = 9
-};
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value);
-
-#endif /* MOBILEAPPLE80211_H */

Copied: vendor/wpa/2.0/src/drivers/android_drv.h (from rev 9639, vendor/wpa/dist/src/drivers/android_drv.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/android_drv.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/android_drv.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,60 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE		248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS	4
+
+#define WEXT_PNOSETUP_HEADER		"PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE	9
+#define WEXT_PNO_TLV_PREFIX		'S'
+#define WEXT_PNO_TLV_VERSION		'1'
+#define WEXT_PNO_TLV_SUBVERSION		'2'
+#define WEXT_PNO_TLV_RESERVED		'0'
+#define WEXT_PNO_VERSION_SIZE		4
+#define WEXT_PNO_AMOUNT			16
+#define WEXT_PNO_SSID_SECTION		'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE	2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION	'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH	2
+#define WEXT_PNO_SCAN_INTERVAL		30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE	(1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION		'R'
+#define WEXT_PNO_REPEAT_LENGTH		1
+#define WEXT_PNO_REPEAT			4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE		(1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION	'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH	1
+#define WEXT_PNO_MAX_REPEAT		3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE	(1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+	(WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+	 + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+	 + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */

Deleted: vendor/wpa/2.0/src/drivers/driver.h
===================================================================
--- vendor/wpa/dist/src/drivers/driver.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2491 +0,0 @@
-/*
- * Driver interface definition
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file defines a driver interface used by both %wpa_supplicant and
- * hostapd. The first part of the file defines data structures used in various
- * driver operations. This is followed by the struct wpa_driver_ops that each
- * driver wrapper will beed to define with callback functions for requesting
- * driver operations. After this, there are definitions for driver event
- * reporting with wpa_supplicant_event() and some convenience helper functions
- * that can be used to report events.
- */
-
-#ifndef DRIVER_H
-#define DRIVER_H
-
-#define WPA_SUPPLICANT_DRIVER_VERSION 4
-
-#include "common/defs.h"
-
-#define HOSTAPD_CHAN_DISABLED 0x00000001
-#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
-#define HOSTAPD_CHAN_NO_IBSS 0x00000004
-#define HOSTAPD_CHAN_RADAR 0x00000008
-
-/**
- * struct hostapd_channel_data - Channel information
- */
-struct hostapd_channel_data {
-	/**
-	 * chan - Channel number (IEEE 802.11)
-	 */
-	short chan;
-
-	/**
-	 * freq - Frequency in MHz
-	 */
-	short freq;
-
-	/**
-	 * flag - Channel flags (HOSTAPD_CHAN_*)
-	 */
-	int flag;
-
-	/**
-	 * max_tx_power - maximum transmit power in dBm
-	 */
-	u8 max_tx_power;
-};
-
-/**
- * struct hostapd_hw_modes - Supported hardware mode information
- */
-struct hostapd_hw_modes {
-	/**
-	 * mode - Hardware mode
-	 */
-	enum hostapd_hw_mode mode;
-
-	/**
-	 * num_channels - Number of entries in the channels array
-	 */
-	int num_channels;
-
-	/**
-	 * channels - Array of supported channels
-	 */
-	struct hostapd_channel_data *channels;
-
-	/**
-	 * num_rates - Number of entries in the rates array
-	 */
-	int num_rates;
-
-	/**
-	 * rates - Array of supported rates in 100 kbps units
-	 */
-	int *rates;
-
-	/**
-	 * ht_capab - HT (IEEE 802.11n) capabilities
-	 */
-	u16 ht_capab;
-
-	/**
-	 * mcs_set - MCS (IEEE 802.11n) rate parameters
-	 */
-	u8 mcs_set[16];
-
-	/**
-	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
-	 */
-	u8 a_mpdu_params;
-};
-
-
-#define IEEE80211_MODE_INFRA	0
-#define IEEE80211_MODE_IBSS	1
-#define IEEE80211_MODE_AP	2
-
-#define IEEE80211_CAP_ESS	0x0001
-#define IEEE80211_CAP_IBSS	0x0002
-#define IEEE80211_CAP_PRIVACY	0x0010
-
-#define WPA_SCAN_QUAL_INVALID		BIT(0)
-#define WPA_SCAN_NOISE_INVALID		BIT(1)
-#define WPA_SCAN_LEVEL_INVALID		BIT(2)
-#define WPA_SCAN_LEVEL_DBM		BIT(3)
-#define WPA_SCAN_AUTHENTICATED		BIT(4)
-#define WPA_SCAN_ASSOCIATED		BIT(5)
-
-/**
- * struct wpa_scan_res - Scan result for an BSS/IBSS
- * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
- * @bssid: BSSID
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @beacon_int: beacon interval in TUs (host byte order)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @tsf: Timestamp
- * @age: Age of the information in milliseconds (i.e., how many milliseconds
- * ago the last Beacon or Probe Response frame was received)
- * @ie_len: length of the following IE field in octets
- * @beacon_ie_len: length of the following Beacon IE field in octets
- *
- * This structure is used as a generic format for scan results from the
- * driver. Each driver interface implementation is responsible for converting
- * the driver or OS specific scan results into this format.
- *
- * If the driver does not support reporting all IEs, the IE data structure is
- * constructed of the IEs that are available. This field will also need to
- * include SSID in IE format. All drivers are encouraged to be extended to
- * report all IEs to make it easier to support future additions.
- */
-struct wpa_scan_res {
-	unsigned int flags;
-	u8 bssid[ETH_ALEN];
-	int freq;
-	u16 beacon_int;
-	u16 caps;
-	int qual;
-	int noise;
-	int level;
-	u64 tsf;
-	unsigned int age;
-	size_t ie_len;
-	size_t beacon_ie_len;
-	/*
-	 * Followed by ie_len octets of IEs from Probe Response frame (or if
-	 * the driver does not indicate source of IEs, these may also be from
-	 * Beacon frame). After the first set of IEs, another set of IEs may
-	 * follow (with beacon_ie_len octets of data) if the driver provides
-	 * both IE sets.
-	 */
-};
-
-/**
- * struct wpa_scan_results - Scan results
- * @res: Array of pointers to allocated variable length scan result entries
- * @num: Number of entries in the scan result array
- */
-struct wpa_scan_results {
-	struct wpa_scan_res **res;
-	size_t num;
-};
-
-/**
- * struct wpa_interface_info - Network interface information
- * @next: Pointer to the next interface or NULL if this is the last one
- * @ifname: Interface name that can be used with init() or init2()
- * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
- *	not available
- * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
- *	is not an allocated copy, i.e., get_interfaces() caller will not free
- *	this)
- */
-struct wpa_interface_info {
-	struct wpa_interface_info *next;
-	char *ifname;
-	char *desc;
-	const char *drv_name;
-};
-
-#define WPAS_MAX_SCAN_SSIDS 4
-
-/**
- * struct wpa_driver_scan_params - Scan parameters
- * Data for struct wpa_driver_ops::scan2().
- */
-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];
-
-	/**
-	 * num_ssids - Number of entries in ssids array
-	 * Zero indicates a request for a passive scan.
-	 */
-	size_t num_ssids;
-
-	/**
-	 * extra_ies - Extra IE(s) to add into Probe Request or %NULL
-	 */
-	const u8 *extra_ies;
-
-	/**
-	 * extra_ies_len - Length of extra_ies in octets
-	 */
-	size_t extra_ies_len;
-
-	/**
-	 * freqs - Array of frequencies to scan or %NULL for all frequencies
-	 *
-	 * The frequency is set in MHz. The array is zero-terminated.
-	 */
-	int *freqs;
-
-	/**
-	 * filter_ssids - Filter for reporting SSIDs
-	 *
-	 * This optional parameter can be used to request the driver wrapper to
-	 * filter scan results to include only the specified SSIDs. %NULL
-	 * indicates that no filtering is to be done. This can be used to
-	 * reduce memory needs for scan results in environments that have large
-	 * number of APs with different SSIDs.
-	 *
-	 * The driver wrapper is allowed to take this allocated buffer into its
-	 * own use by setting the pointer to %NULL. In that case, the driver
-	 * wrapper is responsible for freeing the buffer with os_free() once it
-	 * is not needed anymore.
-	 */
-	struct wpa_driver_scan_filter {
-		u8 ssid[32];
-		size_t ssid_len;
-	} *filter_ssids;
-
-	/**
-	 * num_filter_ssids - Number of entries in filter_ssids array
-	 */
-	size_t num_filter_ssids;
-};
-
-/**
- * struct wpa_driver_auth_params - Authentication parameters
- * Data for struct wpa_driver_ops::authenticate().
- */
-struct wpa_driver_auth_params {
-	int freq;
-	const u8 *bssid;
-	const u8 *ssid;
-	size_t ssid_len;
-	int auth_alg;
-	const u8 *ie;
-	size_t ie_len;
-	const u8 *wep_key[4];
-	size_t wep_key_len[4];
-	int wep_tx_keyidx;
-	int local_state_change;
-};
-
-/**
- * struct wpa_driver_associate_params - Association parameters
- * Data for struct wpa_driver_ops::associate().
- */
-struct wpa_driver_associate_params {
-	/**
-	 * bssid - BSSID of the selected AP
-	 * This can be %NULL, if ap_scan=2 mode is used and the driver is
-	 * responsible for selecting with which BSS to associate. */
-	const u8 *bssid;
-
-	/**
-	 * ssid - The selected SSID
-	 */
-	const u8 *ssid;
-
-	/**
-	 * ssid_len - Length of the SSID (1..32)
-	 */
-	size_t ssid_len;
-
-	/**
-	 * freq - Frequency of the channel the selected AP is using
-	 * Frequency that the selected AP is using (in MHz as
-	 * reported in the scan results)
-	 */
-	int freq;
-
-	/**
-	 * wpa_ie - WPA information element for (Re)Association Request
-	 * WPA information element to be included in (Re)Association
-	 * Request (including information element id and length). Use
-	 * of this WPA IE is optional. If the driver generates the WPA
-	 * IE, it can use pairwise_suite, group_suite, and
-	 * key_mgmt_suite to select proper algorithms. In this case,
-	 * the driver has to notify wpa_supplicant about the used WPA
-	 * IE by generating an event that the interface code will
-	 * convert into EVENT_ASSOCINFO data (see below).
-	 *
-	 * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
-	 * instead. The driver can determine which version is used by
-	 * looking at the first byte of the IE (0xdd for WPA, 0x30 for
-	 * WPA2/RSN).
-	 *
-	 * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
-	 */
-	const u8 *wpa_ie;
-
-	/**
-	 * wpa_ie_len - length of the wpa_ie
-	 */
-	size_t wpa_ie_len;
-
-	/**
-	 * pairwise_suite - Selected pairwise cipher suite
-	 *
-	 * This is usually ignored if @wpa_ie is used.
-	 */
-	enum wpa_cipher pairwise_suite;
-
-	/**
-	 * group_suite - Selected group cipher suite
-	 *
-	 * This is usually ignored if @wpa_ie is used.
-	 */
-	enum wpa_cipher group_suite;
-
-	/**
-	 * key_mgmt_suite - Selected key management suite
-	 *
-	 * This is usually ignored if @wpa_ie is used.
-	 */
-	enum wpa_key_mgmt key_mgmt_suite;
-
-	/**
-	 * auth_alg - Allowed authentication algorithms
-	 * Bit field of WPA_AUTH_ALG_*
-	 */
-	int auth_alg;
-
-	/**
-	 * mode - Operation mode (infra/ibss) IEEE80211_MODE_*
-	 */
-	int mode;
-
-	/**
-	 * wep_key - WEP keys for static WEP configuration
-	 */
-	const u8 *wep_key[4];
-
-	/**
-	 * wep_key_len - WEP key length for static WEP configuration
-	 */
-	size_t wep_key_len[4];
-
-	/**
-	 * wep_tx_keyidx - WEP TX key index for static WEP configuration
-	 */
-	int wep_tx_keyidx;
-
-	/**
-	 * mgmt_frame_protection - IEEE 802.11w management frame protection
-	 */
-	enum mfp_options mgmt_frame_protection;
-
-	/**
-	 * ft_ies - IEEE 802.11r / FT information elements
-	 * If the supplicant is using IEEE 802.11r (FT) and has the needed keys
-	 * for fast transition, this parameter is set to include the IEs that
-	 * are to be sent in the next FT Authentication Request message.
-	 * update_ft_ies() handler is called to update the IEs for further
-	 * FT messages in the sequence.
-	 *
-	 * The driver should use these IEs only if the target AP is advertising
-	 * the same mobility domain as the one included in the MDIE here.
-	 *
-	 * In ap_scan=2 mode, the driver can use these IEs when moving to a new
-	 * AP after the initial association. These IEs can only be used if the
-	 * target AP is advertising support for FT and is using the same MDIE
-	 * and SSID as the current AP.
-	 *
-	 * The driver is responsible for reporting the FT IEs received from the
-	 * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE
-	 * type. update_ft_ies() handler will then be called with the FT IEs to
-	 * include in the next frame in the authentication sequence.
-	 */
-	const u8 *ft_ies;
-
-	/**
-	 * ft_ies_len - Length of ft_ies in bytes
-	 */
-	size_t ft_ies_len;
-
-	/**
-	 * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies)
-	 *
-	 * This value is provided to allow the driver interface easier access
-	 * to the current mobility domain. This value is set to %NULL if no
-	 * mobility domain is currently active.
-	 */
-	const u8 *ft_md;
-
-	/**
-	 * passphrase - RSN passphrase for PSK
-	 *
-	 * This value is made available only for WPA/WPA2-Personal (PSK) and
-	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
-	 * the 8..63 character ASCII passphrase, if available. Please note that
-	 * this can be %NULL if passphrase was not used to generate the PSK. In
-	 * that case, the psk field must be used to fetch the PSK.
-	 */
-	const char *passphrase;
-
-	/**
-	 * psk - RSN PSK (alternative for passphrase for PSK)
-	 *
-	 * This value is made available only for WPA/WPA2-Personal (PSK) and
-	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
-	 * the 32-octet (256-bit) PSK, if available. The driver wrapper should
-	 * be prepared to handle %NULL value as an error.
-	 */
-	const u8 *psk;
-
-	/**
-	 * drop_unencrypted - Enable/disable unencrypted frame filtering
-	 *
-	 * Configure the driver to drop all non-EAPOL frames (both receive and
-	 * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
-	 * still be allowed for key negotiation.
-	 */
-	int drop_unencrypted;
-
-	/**
-	 * prev_bssid - Previously used BSSID in this ESS
-	 *
-	 * When not %NULL, this is a request to use reassociation instead of
-	 * association.
-	 */
-	const u8 *prev_bssid;
-};
-
-/**
- * struct wpa_driver_capa - Driver capability information
- */
-struct wpa_driver_capa {
-#define WPA_DRIVER_CAPA_KEY_MGMT_WPA		0x00000001
-#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2		0x00000002
-#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK	0x00000004
-#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK	0x00000008
-#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE	0x00000010
-#define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
-#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
-	unsigned int key_mgmt;
-
-#define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
-#define WPA_DRIVER_CAPA_ENC_WEP104	0x00000002
-#define WPA_DRIVER_CAPA_ENC_TKIP	0x00000004
-#define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
-	unsigned int enc;
-
-#define WPA_DRIVER_AUTH_OPEN		0x00000001
-#define WPA_DRIVER_AUTH_SHARED		0x00000002
-#define WPA_DRIVER_AUTH_LEAP		0x00000004
-	unsigned int auth;
-
-/* Driver generated WPA/RSN IE */
-#define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
-/* Driver needs static WEP key setup after association command */
-#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
- * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
-#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
-#define WPA_DRIVER_FLAGS_WIRED		0x00000010
-/* Driver provides separate commands for authentication and association (SME in
- * wpa_supplicant). */
-#define WPA_DRIVER_FLAGS_SME		0x00000020
-/* Driver supports AP mode */
-#define WPA_DRIVER_FLAGS_AP		0x00000040
-/* Driver needs static WEP key setup after association has been completed */
-#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
-	unsigned int flags;
-
-	int max_scan_ssids;
-
-	/**
-	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
-	 */
-	unsigned int max_remain_on_chan;
-};
-
-
-struct hostapd_data;
-
-struct hostap_sta_driver_data {
-	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
-	unsigned long current_tx_rate;
-	unsigned long inactive_msec;
-	unsigned long flags;
-	unsigned long num_ps_buf_frames;
-	unsigned long tx_retry_failed;
-	unsigned long tx_retry_count;
-	int last_rssi;
-	int last_ack_rssi;
-};
-
-struct hostapd_sta_add_params {
-	const u8 *addr;
-	u16 aid;
-	u16 capability;
-	const u8 *supp_rates;
-	size_t supp_rates_len;
-	u16 listen_interval;
-	const struct ieee80211_ht_capabilities *ht_capabilities;
-};
-
-struct hostapd_freq_params {
-	int mode;
-	int freq;
-	int channel;
-	int ht_enabled;
-	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
-				 * secondary channel below primary, 1 = HT40
-				 * enabled, secondary channel above primary */
-};
-
-enum wpa_driver_if_type {
-	/**
-	 * WPA_IF_STATION - Station mode interface
-	 */
-	WPA_IF_STATION,
-
-	/**
-	 * WPA_IF_AP_VLAN - AP mode VLAN interface
-	 *
-	 * This interface shares its address and Beacon frame with the main
-	 * BSS.
-	 */
-	WPA_IF_AP_VLAN,
-
-	/**
-	 * WPA_IF_AP_BSS - AP mode BSS interface
-	 *
-	 * This interface has its own address and Beacon frame.
-	 */
-	WPA_IF_AP_BSS,
-};
-
-struct wpa_init_params {
-	const u8 *bssid;
-	const char *ifname;
-	const u8 *ssid;
-	size_t ssid_len;
-	const char *test_socket;
-	int use_pae_group_addr;
-	char **bridge;
-	size_t num_bridge;
-
-	u8 *own_addr; /* buffer for writing own MAC address */
-};
-
-
-struct wpa_bss_params {
-	/** Interface name (for multi-SSID/VLAN support) */
-	const char *ifname;
-	/** Whether IEEE 802.1X or WPA/WPA2 is enabled */
-	int enabled;
-
-	int wpa;
-	int ieee802_1x;
-	int wpa_group;
-	int wpa_pairwise;
-	int wpa_key_mgmt;
-	int rsn_preauth;
-};
-
-#define WPA_STA_AUTHORIZED BIT(0)
-#define WPA_STA_WMM BIT(1)
-#define WPA_STA_SHORT_PREAMBLE BIT(2)
-#define WPA_STA_MFP BIT(3)
-
-/**
- * struct wpa_driver_ops - Driver interface API definition
- *
- * This structure defines the API that each driver interface needs to implement
- * for core wpa_supplicant code. All driver specific functionality is captured
- * in this wrapper.
- */
-struct wpa_driver_ops {
-	/** Name of the driver interface */
-	const char *name;
-	/** One line description of the driver interface */
-	const char *desc;
-
-	/**
-	 * get_bssid - Get the current BSSID
-	 * @priv: private driver interface data
-	 * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Query kernel driver for the current BSSID and copy it to bssid.
-	 * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
-	 * associated.
-	 */
-	int (*get_bssid)(void *priv, u8 *bssid);
-
-	/**
-	 * get_ssid - Get the current SSID
-	 * @priv: private driver interface data
-	 * @ssid: buffer for SSID (at least 32 bytes)
-	 *
-	 * Returns: Length of the SSID on success, -1 on failure
-	 *
-	 * Query kernel driver for the current SSID and copy it to ssid.
-	 * Returning zero is recommended if the STA is not associated.
-	 *
-	 * Note: SSID is an array of octets, i.e., it is not nul terminated and
-	 * can, at least in theory, contain control characters (including nul)
-	 * and as such, should be processed as binary data, not a printable
-	 * string.
-	 */
-	int (*get_ssid)(void *priv, u8 *ssid);
-
-	/**
-	 * set_key - Configure encryption key
-	 * @ifname: Interface name (for multi-SSID/VLAN support)
-	 * @priv: private driver interface data
-	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
-	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
-	 *	%WPA_ALG_NONE clears the key.
-	 * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
-	 *	broadcast/default keys
-	 * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
-	 *	IGTK
-	 * @set_tx: configure this key as the default Tx key (only used when
-	 *	driver does not support separate unicast/individual key
-	 * @seq: sequence number/packet number, seq_len octets, the next
-	 *	packet number to be used for in replay protection; configured
-	 *	for Rx keys (in most cases, this is only used with broadcast
-	 *	keys and set to zero for unicast keys)
-	 * @seq_len: length of the seq, depends on the algorithm:
-	 *	TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
-	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
-	 *	8-byte Rx Mic Key
-	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
-	 *	TKIP: 32, CCMP: 16, IGTK: 16)
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Configure the given key for the kernel driver. If the driver
-	 * supports separate individual keys (4 default keys + 1 individual),
-	 * addr can be used to determine whether the key is default or
-	 * individual. If only 4 keys are supported, the default key with key
-	 * index 0 is used as the individual key. STA must be configured to use
-	 * it as the default Tx key (set_tx is set) and accept Rx for all the
-	 * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
-	 * broadcast keys, so key index 0 is available for this kind of
-	 * configuration.
-	 *
-	 * Please note that TKIP keys include separate TX and RX MIC keys and
-	 * some drivers may expect them in different order than wpa_supplicant
-	 * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
-	 * will tricker Michael MIC errors. This can be fixed by changing the
-	 * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
-	 * in driver_*.c set_key() implementation, see driver_ndis.c for an
-	 * example on how this can be done.
-	 */
-	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
-		       const u8 *addr, int key_idx, int set_tx,
-		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
-
-	/**
-	 * init - Initialize driver interface
-	 * @ctx: context to be used when calling wpa_supplicant functions,
-	 * e.g., wpa_supplicant_event()
-	 * @ifname: interface name, e.g., wlan0
-	 *
-	 * Returns: Pointer to private data, %NULL on failure
-	 *
-	 * Initialize driver interface, including event processing for kernel
-	 * driver events (e.g., associated, scan results, Michael MIC failure).
-	 * This function can allocate a private configuration data area for
-	 * @ctx, file descriptor, interface name, etc. information that may be
-	 * needed in future driver operations. If this is not used, non-NULL
-	 * value will need to be returned because %NULL is used to indicate
-	 * failure. The returned value will be used as 'void *priv' data for
-	 * all other driver_ops functions.
-	 *
-	 * The main event loop (eloop.c) of wpa_supplicant can be used to
-	 * register callback for read sockets (eloop_register_read_sock()).
-	 *
-	 * See below for more information about events and
-	 * wpa_supplicant_event() function.
-	 */
-	void * (*init)(void *ctx, const char *ifname);
-
-	/**
-	 * deinit - Deinitialize driver interface
-	 * @priv: private driver interface data from init()
-	 *
-	 * Shut down driver interface and processing of driver events. Free
-	 * private data buffer if one was allocated in init() handler.
-	 */
-	void (*deinit)(void *priv);
-
-	/**
-	 * set_param - Set driver configuration parameters
-	 * @priv: private driver interface data from init()
-	 * @param: driver specific configuration parameters
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Optional handler for notifying driver interface about configuration
-	 * parameters (driver_param).
-	 */
-	int (*set_param)(void *priv, const char *param);
-
-	/**
-	 * set_countermeasures - Enable/disable TKIP countermeasures
-	 * @priv: private driver interface data
-	 * @enabled: 1 = countermeasures enabled, 0 = disabled
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Configure TKIP countermeasures. When these are enabled, the driver
-	 * should drop all received and queued frames that are using TKIP.
-	 */
-	int (*set_countermeasures)(void *priv, int enabled);
-
-	/**
-	 * deauthenticate - Request driver to deauthenticate
-	 * @priv: private driver interface data
-	 * @addr: peer address (BSSID of the AP)
-	 * @reason_code: 16-bit reason code to be sent in the deauthentication
-	 *	frame
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
-
-	/**
-	 * disassociate - Request driver to disassociate
-	 * @priv: private driver interface data
-	 * @addr: peer address (BSSID of the AP)
-	 * @reason_code: 16-bit reason code to be sent in the disassociation
-	 *	frame
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*disassociate)(void *priv, const u8 *addr, int reason_code);
-
-	/**
-	 * associate - Request driver to associate
-	 * @priv: private driver interface data
-	 * @params: association parameters
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*associate)(void *priv,
-			 struct wpa_driver_associate_params *params);
-
-	/**
-	 * add_pmkid - Add PMKSA cache entry to the driver
-	 * @priv: private driver interface data
-	 * @bssid: BSSID for the PMKSA cache entry
-	 * @pmkid: PMKID for the PMKSA cache entry
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is called when a new PMK is received, as a result of
-	 * either normal authentication or RSN pre-authentication.
-	 *
-	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
-	 * associate(), add_pmkid() can be used to add new PMKSA cache entries
-	 * in the driver. If the driver uses wpa_ie from wpa_supplicant, this
-	 * driver_ops function does not need to be implemented. Likewise, if
-	 * the driver does not support WPA, this function is not needed.
-	 */
-	int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
-
-	/**
-	 * remove_pmkid - Remove PMKSA cache entry to the driver
-	 * @priv: private driver interface data
-	 * @bssid: BSSID for the PMKSA cache entry
-	 * @pmkid: PMKID for the PMKSA cache entry
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is called when the supplicant drops a PMKSA cache
-	 * entry for any reason.
-	 *
-	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
-	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
-	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
-	 * from wpa_supplicant, this driver_ops function does not need to be
-	 * implemented. Likewise, if the driver does not support WPA, this
-	 * function is not needed.
-	 */
-	int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
-
-	/**
-	 * flush_pmkid - Flush PMKSA cache
-	 * @priv: private driver interface data
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is called when the supplicant drops all PMKSA cache
-	 * entries for any reason.
-	 *
-	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
-	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
-	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
-	 * from wpa_supplicant, this driver_ops function does not need to be
-	 * implemented. Likewise, if the driver does not support WPA, this
-	 * function is not needed.
-	 */
-	int (*flush_pmkid)(void *priv);
-
-	/**
-	 * get_capa - Get driver capabilities
-	 * @priv: private driver interface data
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Get driver/firmware/hardware capabilities.
-	 */
-	int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
-
-	/**
-	 * poll - Poll driver for association information
-	 * @priv: private driver interface data
-	 *
-	 * This is an option callback that can be used when the driver does not
-	 * provide event mechanism for association events. This is called when
-	 * receiving WPA EAPOL-Key messages that require association
-	 * information. The driver interface is supposed to generate associnfo
-	 * event before returning from this callback function. In addition, the
-	 * driver interface should generate an association event after having
-	 * sent out associnfo.
-	 */
-	void (*poll)(void *priv);
-
-	/**
-	 * get_ifname - Get interface name
-	 * @priv: private driver interface data
-	 *
-	 * Returns: Pointer to the interface name. This can differ from the
-	 * interface name used in init() call. Init() is called first.
-	 *
-	 * This optional function can be used to allow the driver interface to
-	 * replace the interface name with something else, e.g., based on an
-	 * interface mapping from a more descriptive name.
-	 */
-	const char * (*get_ifname)(void *priv);
-
-	/**
-	 * get_mac_addr - Get own MAC address
-	 * @priv: private driver interface data
-	 *
-	 * Returns: Pointer to own MAC address or %NULL on failure
-	 *
-	 * This optional function can be used to get the own MAC address of the
-	 * device from the driver interface code. This is only needed if the
-	 * l2_packet implementation for the OS does not provide easy access to
-	 * a MAC address. */
-	const u8 * (*get_mac_addr)(void *priv);
-
-	/**
-	 * send_eapol - Optional function for sending EAPOL packets
-	 * @priv: private driver interface data
-	 * @dest: Destination MAC address
-	 * @proto: Ethertype
-	 * @data: EAPOL packet starting with IEEE 802.1X header
-	 * @data_len: Size of the EAPOL packet
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This optional function can be used to override l2_packet operations
-	 * with driver specific functionality. If this function pointer is set,
-	 * l2_packet module is not used at all and the driver interface code is
-	 * responsible for receiving and sending all EAPOL packets. The
-	 * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
-	 * event. The driver interface is required to implement get_mac_addr()
-	 * handler if send_eapol() is used.
-	 */
-	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
-			  const u8 *data, size_t data_len);
-
-	/**
-	 * set_operstate - Sets device operating state to DORMANT or UP
-	 * @priv: private driver interface data
-	 * @state: 0 = dormant, 1 = up
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function that can be used on operating systems
-	 * that support a concept of controlling network device state from user
-	 * space applications. This function, if set, gets called with
-	 * state = 1 when authentication has been completed and with state = 0
-	 * when connection is lost.
-	 */
-	int (*set_operstate)(void *priv, int state);
-
-	/**
-	 * mlme_setprotection - MLME-SETPROTECTION.request primitive
-	 * @priv: Private driver interface data
-	 * @addr: Address of the station for which to set protection (may be
-	 * %NULL for group keys)
-	 * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
-	 * @key_type: MLME_SETPROTECTION_KEY_TYPE_*
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function that can be used to set the driver to
-	 * require protection for Tx and/or Rx frames. This uses the layer
-	 * interface defined in IEEE 802.11i-2004 clause 10.3.22.1
-	 * (MLME-SETPROTECTION.request). Many drivers do not use explicit
-	 * set protection operation; instead, they set protection implicitly
-	 * based on configured keys.
-	 */
-	int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type,
-				  int key_type);
-
-	/**
-	 * get_hw_feature_data - Get hardware support data (channels and rates)
-	 * @priv: Private driver interface data
-	 * @num_modes: Variable for returning the number of returned modes
-	 * flags: Variable for returning hardware feature flags
-	 * Returns: Pointer to allocated hardware data on success or %NULL on
-	 * failure. Caller is responsible for freeing this.
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to %wpa_supplicant or hostapd.
-	 */
-	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
-							 u16 *num_modes,
-							 u16 *flags);
-
-	/**
-	 * set_channel - Set channel
-	 * @priv: Private driver interface data
-	 * @phymode: HOSTAPD_MODE_IEEE80211B, ..
-	 * @chan: IEEE 802.11 channel number
-	 * @freq: Frequency of the channel in MHz
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
-			   int freq);
-
-	/**
-	 * set_ssid - Set SSID
-	 * @priv: Private driver interface data
-	 * @ssid: SSID
-	 * @ssid_len: SSID length
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
-
-	/**
-	 * set_bssid - Set BSSID
-	 * @priv: Private driver interface data
-	 * @bssid: BSSID
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_bssid)(void *priv, const u8 *bssid);
-
-	/**
-	 * send_mlme - Send management frame from MLME
-	 * @priv: Private driver interface data
-	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
-	 * @data_len: Size of the management frame
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
-
-	/**
-	 * mlme_add_sta - Add a STA entry into the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
-	 * format (one octet per rate, 1 = 0.5 Mbps)
-	 * @supp_rates_len: Number of entries in supp_rates
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant. When the MLME code
-	 * completes association with an AP, this function is called to
-	 * configure the driver/netstack with a STA entry for data frame
-	 * processing (TX rate control, encryption/decryption).
-	 */
-	int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
-			    size_t supp_rates_len);
-
-	/**
-	 * mlme_remove_sta - Remove a STA entry from the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*mlme_remove_sta)(void *priv, const u8 *addr);
-
-	/**
-	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
-	 * @priv: Private driver interface data
-	 * @md: Mobility domain (2 octets) (also included inside ies)
-	 * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs
-	 * @ies_len: Length of FT IEs in bytes
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * The supplicant uses this callback to let the driver know that keying
-	 * material for FT is available and that the driver can use the
-	 * provided IEs in the next message in FT authentication sequence.
-	 *
-	 * This function is only needed for driver that support IEEE 802.11r
-	 * (Fast BSS Transition).
-	 */
-	int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies,
-			     size_t ies_len);
-
-	/**
-	 * send_ft_action - Send FT Action frame (IEEE 802.11r)
-	 * @priv: Private driver interface data
-	 * @action: Action field value
-	 * @target_ap: Target AP address
-	 * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
-	 * @ies_len: Length of FT IEs in bytes
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * The supplicant uses this callback to request the driver to transmit
-	 * an FT Action frame (action category 6) for over-the-DS fast BSS
-	 * transition.
-	 */
-	int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
-			      const u8 *ies, size_t ies_len);
-
-	/**
-	 * get_scan_results2 - Fetch the latest scan results
-	 * @priv: private driver interface data
-	 *
-	 * Returns: Allocated buffer of scan results (caller is responsible for
-	 * freeing the data structure) on success, NULL on failure
-	 */
-	 struct wpa_scan_results * (*get_scan_results2)(void *priv);
-
-	/**
-	 * set_country - Set country
-	 * @priv: Private driver interface data
-	 * @alpha2: country to which to switch to
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is for drivers which support some form
-	 * of setting a regulatory domain.
-	 */
-	int (*set_country)(void *priv, const char *alpha2);
-
-	/**
-	 * global_init - Global driver initialization
-	 * Returns: Pointer to private data (global), %NULL on failure
-	 *
-	 * This optional function is called to initialize the driver wrapper
-	 * for global data, i.e., data that applies to all interfaces. If this
-	 * function is implemented, global_deinit() will also need to be
-	 * implemented to free the private data. The driver will also likely
-	 * use init2() function instead of init() to get the pointer to global
-	 * data available to per-interface initializer.
-	 */
-	void * (*global_init)(void);
-
-	/**
-	 * global_deinit - Global driver deinitialization
-	 * @priv: private driver global data from global_init()
-	 *
-	 * Terminate any global driver related functionality and free the
-	 * global data structure.
-	 */
-	void (*global_deinit)(void *priv);
-
-	/**
-	 * init2 - Initialize driver interface (with global data)
-	 * @ctx: context to be used when calling wpa_supplicant functions,
-	 * e.g., wpa_supplicant_event()
-	 * @ifname: interface name, e.g., wlan0
-	 * @global_priv: private driver global data from global_init()
-	 * Returns: Pointer to private data, %NULL on failure
-	 *
-	 * This function can be used instead of init() if the driver wrapper
-	 * uses global data.
-	 */
-	void * (*init2)(void *ctx, const char *ifname, void *global_priv);
-
-	/**
-	 * get_interfaces - Get information about available interfaces
-	 * @global_priv: private driver global data from global_init()
-	 * Returns: Allocated buffer of interface information (caller is
-	 * responsible for freeing the data structure) on success, NULL on
-	 * failure
-	 */
-	struct wpa_interface_info * (*get_interfaces)(void *global_priv);
-
-	/**
-	 * scan2 - Request the driver to initiate scan
-	 * @priv: private driver interface data
-	 * @params: Scan parameters
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * Once the scan results are ready, the driver should report scan
-	 * results event for wpa_supplicant which will eventually request the
-	 * results with wpa_driver_get_scan_results2().
-	 */
-	int (*scan2)(void *priv, struct wpa_driver_scan_params *params);
-
-	/**
-	 * authenticate - Request driver to authenticate
-	 * @priv: private driver interface data
-	 * @params: authentication parameters
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function that can be used with drivers that
-	 * support separate authentication and association steps, i.e., when
-	 * wpa_supplicant can act as the SME. If not implemented, associate()
-	 * function is expected to take care of IEEE 802.11 authentication,
-	 * too.
-	 */
-	int (*authenticate)(void *priv,
-			    struct wpa_driver_auth_params *params);
-
-	/**
-	 * set_beacon - Set Beacon frame template
-	 * @priv: Private driver interface data
-	 * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE
-	 * @head_len: Length of the head buffer in octets
-	 * @tail: Beacon tail following TIM IE
-	 * @tail_len: Length of the tail buffer in octets
-	 * @dtim_period: DTIM period
-	 * @beacon_int: Beacon interval
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is used to configure Beacon template for the driver in
-	 * AP mode. The driver is responsible for building the full Beacon
-	 * frame by concatenating the head part with TIM IE generated by the
-	 * driver/firmware and finishing with the tail part.
-	 */
-	int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
-			  const u8 *tail, size_t tail_len, int dtim_period,
-			  int beacon_int);
-
-	/**
-	 * hapd_init - Initialize driver interface (hostapd only)
-	 * @hapd: Pointer to hostapd context
-	 * @params: Configuration for the driver wrapper
-	 * Returns: Pointer to private data, %NULL on failure
-	 *
-	 * This function is used instead of init() or init2() when the driver
-	 * wrapper is used withh hostapd.
-	 */
-	void * (*hapd_init)(struct hostapd_data *hapd,
-			    struct wpa_init_params *params);
-
-	/**
-	 * hapd_deinit - Deinitialize driver interface (hostapd only)
-	 * @priv: Private driver interface data from hapd_init()
-	 */
-	void (*hapd_deinit)(void *priv);
-
-	/**
-	 * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
-	 * @priv: Private driver interface data
-	 * @params: BSS parameters
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function to configure the kernel driver to
-	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
-	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
-	 * always enabled and the driver uses set_beacon() to set WPA/RSN IE
-	 * for Beacon frames.
-	 */
-	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
-
-	/**
-	 * set_privacy - Enable/disable privacy (AP only)
-	 * @priv: Private driver interface data
-	 * @enabled: 1 = privacy enabled, 0 = disabled
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function to configure privacy field in the
-	 * kernel driver for Beacon frames. This can be left undefined (set to
-	 * %NULL) if the driver uses the Beacon template from set_beacon().
-	 */
-	int (*set_privacy)(void *priv, int enabled);
-
-	/**
-	 * get_seqnum - Fetch the current TSC/packet number (AP only)
-	 * @ifname: The interface name (main or virtual)
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the station or %NULL for group keys
-	 * @idx: Key index
-	 * @seq: Buffer for returning the latest used TSC/packet number
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is used to fetch the last used TSC/packet number for
-	 * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so
-	 * there is no strict requirement on implementing support for unicast
-	 * keys (i.e., addr != %NULL).
-	 */
-	int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
-			  int idx, u8 *seq);
-
-	/**
-	 * flush - Flush all association stations (AP only)
-	 * @priv: Private driver interface data
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function requests the driver to disassociate all associated
-	 * stations. This function does not need to be implemented if the
-	 * driver does not process association frames internally.
-	 */
-	int (*flush)(void *priv);
-
-	/**
-	 * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP)
-	 * @priv: Private driver interface data
-	 * @elem: Information elements
-	 * @elem_len: Length of the elem buffer in octets
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function to add information elements in the
-	 * kernel driver for Beacon and Probe Response frames. This can be left
-	 * undefined (set to %NULL) if the driver uses the Beacon template from
-	 * set_beacon().
-	 */
-	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
-
-	/**
-	 * read_sta_data - Fetch station data (AP only)
-	 * @priv: Private driver interface data
-	 * @data: Buffer for returning station information
-	 * @addr: MAC address of the station
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
-			     const u8 *addr);
-
-	/**
-	 * hapd_send_eapol - Send an EAPOL packet (AP only)
-	 * @priv: private driver interface data
-	 * @addr: Destination MAC address
-	 * @data: EAPOL packet starting with IEEE 802.1X header
-	 * @data_len: Length of the EAPOL packet in octets
-	 * @encrypt: Whether the frame should be encrypted
-	 * @own_addr: Source MAC address
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
-			       size_t data_len, int encrypt,
-			       const u8 *own_addr);
-
-	/**
-	 * sta_deauth - Deauthenticate a station (AP only)
-	 * @priv: Private driver interface data
-	 * @own_addr: Source address and BSSID for the Deauthentication frame
-	 * @addr: MAC address of the station to deauthenticate
-	 * @reason: Reason code for the Deauthentiation frame
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function requests a specific station to be deauthenticated and
-	 * a Deauthentication frame to be sent to it.
-	 */
-	int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
-			  int reason);
-
-	/**
-	 * sta_disassoc - Disassociate a station (AP only)
-	 * @priv: Private driver interface data
-	 * @own_addr: Source address and BSSID for the Disassociation frame
-	 * @addr: MAC address of the station to disassociate
-	 * @reason: Reason code for the Disassociation frame
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function requests a specific station to be disassociated and
-	 * a Disassociation frame to be sent to it.
-	 */
-	int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
-			    int reason);
-
-	/**
-	 * sta_remove - Remove a station entry (AP only)
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the station to be removed
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*sta_remove)(void *priv, const u8 *addr);
-
-	/**
-	 * hapd_get_ssid - Get the current SSID (AP only)
-	 * @priv: Private driver interface data
-	 * @buf: Buffer for returning the SSID
-	 * @len: Maximum length of the buffer
-	 * Returns: Length of the SSID on success, -1 on failure
-	 *
-	 * This function need not be implemented if the driver uses Beacon
-	 * template from set_beacon() and does not reply to Probe Request
-	 * frames.
-	 */
-	int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
-
-	/**
-	 * hapd_set_ssid - Set SSID (AP only)
-	 * @priv: Private driver interface data
-	 * @buf: SSID
-	 * @len: Length of the SSID in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
-
-	/**
-	 * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP)
-	 * @priv: Private driver interface data
-	 * @enabled: 1 = countermeasures enabled, 0 = disabled
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This need not be implemented if the driver does not take care of
-	 * association processing.
-	 */
-	int (*hapd_set_countermeasures)(void *priv, int enabled);
-
-	/**
-	 * sta_add - Add a station entry
-	 * @priv: Private driver interface data
-	 * @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
-	 * does not take care of association processing.
-	 */
-	int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
-
-	/**
-	 * get_inact_sec - Get station inactivity duration (AP only)
-	 * @priv: Private driver interface data
-	 * @addr: Station address
-	 * Returns: Number of seconds station has been inactive, -1 on failure
-	 */
-	int (*get_inact_sec)(void *priv, const u8 *addr);
-
-	/**
-	 * sta_clear_stats - Clear station statistics (AP only)
-	 * @priv: Private driver interface data
-	 * @addr: Station address
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*sta_clear_stats)(void *priv, const u8 *addr);
-
-	/**
-	 * set_freq - Set channel/frequency (AP only)
-	 * @priv: Private driver interface data
-	 * @freq: Channel parameters
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_freq)(void *priv, struct hostapd_freq_params *freq);
-
-	/**
-	 * set_rts - Set RTS threshold
-	 * @priv: Private driver interface data
-	 * @rts: RTS threshold in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_rts)(void *priv, int rts);
-
-	/**
-	 * set_frag - Set fragmentation threshold
-	 * @priv: Private driver interface data
-	 * @frag: Fragmentation threshold in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_frag)(void *priv, int frag);
-
-	/**
-	 * sta_set_flags - Set station flags (AP only)
-	 * @priv: Private driver interface data
-	 * @addr: Station address
-	 * @total_flags: Bitmap of all WPA_STA_* flags currently set
-	 * @flags_or: Bitmap of WPA_STA_* flags to add
-	 * @flags_and: Bitmap of WPA_STA_* flags to us as a mask
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*sta_set_flags)(void *priv, const u8 *addr,
-			     int total_flags, int flags_or, int flags_and);
-
-	/**
-	 * set_rate_sets - Set supported and basic rate sets (AP only)
-	 * @priv: Private driver interface data
-	 * @supp_rates: -1 terminated array of supported rates in 100 kbps
-	 * @basic_rates: -1 terminated array of basic rates in 100 kbps
-	 * @mode: hardware mode (HOSTAPD_MODE_*)
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
-			     int mode);
-
-	/**
-	 * set_cts_protect - Set CTS protection mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether CTS protection is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_cts_protect)(void *priv, int value);
-
-	/**
-	 * set_preamble - Set preamble mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short preamble is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_preamble)(void *priv, int value);
-
-	/**
-	 * set_short_slot_time - Set short slot time (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short slot time is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_short_slot_time)(void *priv, int value);
-
-	/**
-	 * set_tx_queue_params - Set TX queue parameters
-	 * @priv: Private driver interface data
-	 * @queue: Queue number
-	 * @aifs: AIFS
-	 * @cw_min: cwMin
-	 * @cw_max: cwMax
-	 * @burst_time: Maximum length for bursting in 0.1 msec units
-	 */
-	int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
-				   int cw_max, int burst_time);
-
-	/**
-	 * valid_bss_mask - Validate BSSID mask
-	 * @priv: Private driver interface data
-	 * @addr: Address
-	 * @mask: Mask
-	 * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can
-	 * be used, but the main interface address must be the first address in
-	 * the block if mask is applied
-	 */
-	int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
-
-	/**
-	 * if_add - Add a virtual interface
-	 * @priv: Private driver interface data
-	 * @type: Interface type
-	 * @ifname: Interface name for the new virtual interface
-	 * @addr: Local address to use for the interface or %NULL to use the
-	 *	parent interface address
-	 * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
-	 * @drv_priv: Pointer for overwriting the driver context or %NULL if
-	 *	not allowed (applies only to %WPA_IF_AP_BSS type)
-	 * @force_ifname: Buffer for returning an interface name that the
-	 *	driver ended up using if it differs from the requested ifname
-	 * @if_addr: Buffer for returning the allocated interface address
-	 *	(this may differ from the requested addr if the driver cannot
-	 *	change interface address)
-	 * 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);
-
-	/**
-	 * if_remove - Remove a virtual interface
-	 * @priv: Private driver interface data
-	 * @type: Interface type
-	 * @ifname: Interface name of the virtual interface to be removed
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*if_remove)(void *priv, enum wpa_driver_if_type type,
-			 const char *ifname);
-
-	/**
-	 * set_sta_vlan - Bind a station into a specific interface (AP only)
-	 * @priv: Private driver interface data
-	 * @ifname: Interface (main or virtual BSS or VLAN)
-	 * @addr: MAC address of the associated station
-	 * @vlan_id: VLAN ID
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is used to bind a station to a specific virtual
-	 * interface. It is only used if when virtual interfaces are supported,
-	 * e.g., to assign stations to different VLAN interfaces based on
-	 * information from a RADIUS server. This allows separate broadcast
-	 * domains to be used with a single BSS.
-	 */
-	int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
-			    int vlan_id);
-
-	/**
-	 * commit - Optional commit changes handler (AP only)
-	 * @priv: driver private data
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This optional handler function can be registered if the driver
-	 * interface implementation needs to commit changes (e.g., by setting
-	 * network interface up) at the end of initial configuration. If set,
-	 * this handler will be called after initial setup has been completed.
-	 */
-	int (*commit)(void *priv);
-
-	/**
-	 * send_ether - Send an ethernet packet (AP only)
-	 * @priv: private driver interface data
-	 * @dst: Destination MAC address
-	 * @src: Source MAC address
-	 * @proto: Ethertype
-	 * @data: EAPOL packet starting with IEEE 802.1X header
-	 * @data_len: Length of the EAPOL packet in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
-			  const u8 *data, size_t data_len);
-
-	/**
-	 * set_radius_acl_auth - Notification of RADIUS ACL change
-	 * @priv: Private driver interface data
-	 * @mac: MAC address of the station
-	 * @accepted: Whether the station was accepted
-	 * @session_timeout: Session timeout for the station
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, 
-				   u32 session_timeout);
-
-	/**
-	 * set_radius_acl_expire - Notification of RADIUS ACL expiration
-	 * @priv: Private driver interface data
-	 * @mac: MAC address of the station
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_radius_acl_expire)(void *priv, const u8 *mac);
-
-	/**
-	 * set_ht_params - Set HT parameters (AP only)
-	 * @priv: Private driver interface data
-	 * @ht_capab: HT Capabilities IE
-	 * @ht_capab_len: Length of ht_capab in octets
-	 * @ht_oper: HT Operation IE
-	 * @ht_oper_len: Length of ht_oper in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_ht_params)(void *priv,
-			     const u8 *ht_capab, size_t ht_capab_len,
-			     const u8 *ht_oper, size_t ht_oper_len);
-
-	/**
-	 * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
-	 * @priv: Private driver interface data
-	 * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
-	 * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove
-	 *	extra IE(s)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is an optional function to add WPS IE in the kernel driver for
-	 * Beacon and Probe Response frames. This can be left undefined (set
-	 * to %NULL) if the driver uses the Beacon template from set_beacon()
-	 * and does not process Probe Request frames.
-	 */
-	int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
-			     const struct wpabuf *proberesp);
-
-	/**
-	 * set_supp_port - Set IEEE 802.1X Supplicant Port status
-	 * @priv: Private driver interface data
-	 * @authorized: Whether the port is authorized
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_supp_port)(void *priv, int authorized);
-
-	/**
-	 * set_wds_sta - Bind a station into a 4-address WDS (AP only)
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the associated station
-	 * @aid: Association ID
-	 * @val: 1 = bind to 4-address WDS; 0 = unbind
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val);
-
-	/**
-	 * send_action - Transmit an Action frame
-	 * @priv: Private driver interface data
-	 * @freq: Frequency (in MHz) of the channel
-	 * @dst: Destination MAC address (Address 1)
-	 * @src: Source MAC address (Address 2)
-	 * @bssid: BSSID (Address 3)
-	 * @data: Frame body
-	 * @data_len: data length in octets
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This command can be used to request the driver to transmit an action
-	 * frame to the specified destination. If a remain-on-channel duration
-	 * is in progress, the frame is transmitted on that channel. Otherwise,
-	 * the frame is transmitted on the current operational channel if in
-	 * associated state in station mode or if operating as an AP. If none
-	 * of these conditions is in effect, send_action() cannot be used.
-	 */
-	int (*send_action)(void *priv, unsigned int freq,
-			   const u8 *dst, const u8 *src, const u8 *bssid,
-			   const u8 *data, size_t data_len);
-
-	/**
-	 * remain_on_channel - Remain awake on a channel
-	 * @priv: Private driver interface data
-	 * @freq: Frequency (in MHz) of the channel
-	 * @duration: Duration in milliseconds
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This command is used to request the driver to remain awake on the
-	 * specified channel for the specified duration and report received
-	 * Action frames with EVENT_RX_ACTION events. Optionally, received
-	 * Probe Request frames may also be requested to be reported by calling
-	 * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
-	 *
-	 * The driver may not be at the requested channel when this function
-	 * returns, i.e., the return code is only indicating whether the
-	 * request was accepted. The caller will need to wait until the
-	 * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has
-	 * completed the channel change. This may take some time due to other
-	 * need for the radio and the caller should be prepared to timing out
-	 * its wait since there are no guarantees on when this request can be
-	 * executed.
-	 */
-	int (*remain_on_channel)(void *priv, unsigned int freq,
-				 unsigned int duration);
-
-	/**
-	 * cancel_remain_on_channel - Cancel remain-on-channel operation
-	 * @priv: Private driver interface data
-	 *
-	 * This command can be used to cancel a remain-on-channel operation
-	 * before its originally requested duration has passed. This could be
-	 * used, e.g., when remain_on_channel() is used to request extra time
-	 * to receive a response to an Action frame and the response is
-	 * received when there is still unneeded time remaining on the
-	 * remain-on-channel operation.
-	 */
-	int (*cancel_remain_on_channel)(void *priv);
-
-	/**
-	 * probe_req_report - Request Probe Request frames to be indicated
-	 * @priv: Private driver interface data
-	 * @report: Whether to report received Probe Request frames
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This command can be used to request the driver to indicate when
-	 * Probe Request frames are received with EVENT_RX_PROBE_REQ events.
-	 * Since this operation may require extra resources, e.g., due to less
-	 * optimal hardware/firmware RX filtering, many drivers may disable
-	 * Probe Request reporting at least in station mode. This command is
-	 * used to notify the driver when the Probe Request frames need to be
-	 * reported, e.g., during remain-on-channel operations.
-	 */
-	int (*probe_req_report)(void *priv, int report);
-
-	/**
-	 * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX
-	 * @priv: Private driver interface data
-	 * @disabled: Whether IEEE 802.11b rates are disabled
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and
-	 * 11 Mbps) as TX rates for data and management frames. This can be
-	 * used to optimize channel use when there is no need to support IEEE
-	 * 802.11b-only devices.
-	 */
-	int (*disable_11b_rates)(void *priv, int disabled);
-
-	/**
-	 * deinit_ap - Deinitialize AP mode
-	 * @priv: Private driver interface data
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This optional function can be used to disable AP mode related
-	 * configuration and change the driver mode to station mode to allow
-	 * normal station operations like scanning to be completed.
-	 */
-	int (*deinit_ap)(void *priv);
-
-	/**
-	 * suspend - Notification on system suspend/hibernate event
-	 * @priv: Private driver interface data
-	 */
-	void (*suspend)(void *priv);
-
-	/**
-	 * resume - Notification on system resume/thaw event
-	 * @priv: Private driver interface data
-	 */
-	void (*resume)(void *priv);
-
-	/**
-	 * signal_monitor - Set signal monitoring parameters
-	 * @priv: Private driver interface data
-	 * @threshold: Threshold value for signal change events; 0 = disabled
-	 * @hysteresis: Minimum change in signal strength before indicating a
-	 *	new event
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This function can be used to configure monitoring of signal strength
-	 * with the current AP. Whenever signal strength drops below the
-	 * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event
-	 * should be generated assuming the signal strength has changed at
-	 * least %hysteresis from the previously indicated signal change event.
-	 */
-	int (*signal_monitor)(void *priv, int threshold, int hysteresis);
-
-	/**
-	 * send_frame - Send IEEE 802.11 frame (testing use only)
-	 * @priv: Private driver interface data
-	 * @data: IEEE 802.11 frame with IEEE 802.11 header
-	 * @data_len: Size of the frame
-	 * @encrypt: Whether to encrypt the frame (if keys are set)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only used for debugging purposes and is not
-	 * required to be implemented for normal operations.
-	 */
-	int (*send_frame)(void *priv, const u8 *data, size_t data_len,
-			  int encrypt);
-};
-
-
-/**
- * enum wpa_event_type - Event type for wpa_supplicant_event() calls
- */
-enum wpa_event_type {
-	/**
-	 * EVENT_ASSOC - Association completed
-	 *
-	 * This event needs to be delivered when the driver completes IEEE
-	 * 802.11 association or reassociation successfully.
-	 * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
-	 * after this event has been generated. In addition, optional
-	 * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
-	 * more information about the association. If the driver interface gets
-	 * both of these events at the same time, it can also include the
-	 * assoc_info data in EVENT_ASSOC call.
-	 */
-	EVENT_ASSOC,
-
-	/**
-	 * EVENT_DISASSOC - Association lost
-	 *
-	 * This event should be called when association is lost either due to
-	 * receiving deauthenticate or disassociate frame from the AP or when
-	 * sending either of these frames to the current AP. If the driver
-	 * supports separate deauthentication event, EVENT_DISASSOC should only
-	 * be used for disassociation and EVENT_DEAUTH for deauthentication.
-	 * In AP mode, union wpa_event_data::disassoc_info is required.
-	 */
-	EVENT_DISASSOC,
-
-	/**
-	 * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected
-	 *
-	 * This event must be delivered when a Michael MIC error is detected by
-	 * the local driver. Additional data for event processing is
-	 * provided with union wpa_event_data::michael_mic_failure. This
-	 * information is used to request new encyption key and to initiate
-	 * TKIP countermeasures if needed.
-	 */
-	EVENT_MICHAEL_MIC_FAILURE,
-
-	/**
-	 * EVENT_SCAN_RESULTS - Scan results available
-	 *
-	 * This event must be called whenever scan results are available to be
-	 * fetched with struct wpa_driver_ops::get_scan_results(). This event
-	 * is expected to be used some time after struct wpa_driver_ops::scan()
-	 * is called. If the driver provides an unsolicited event when the scan
-	 * has been completed, this event can be used to trigger
-	 * EVENT_SCAN_RESULTS call. If such event is not available from the
-	 * driver, the driver wrapper code is expected to use a registered
-	 * timeout to generate EVENT_SCAN_RESULTS call after the time that the
-	 * scan is expected to be completed. Optional information about
-	 * completed scan can be provided with union wpa_event_data::scan_info.
-	 */
-	EVENT_SCAN_RESULTS,
-
-	/**
-	 * EVENT_ASSOCINFO - Report optional extra information for association
-	 *
-	 * This event can be used to report extra association information for
-	 * EVENT_ASSOC processing. This extra information includes IEs from
-	 * association frames and Beacon/Probe Response frames in union
-	 * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before
-	 * EVENT_ASSOC. Alternatively, the driver interface can include
-	 * assoc_info data in the EVENT_ASSOC call if it has all the
-	 * information available at the same point.
-	 */
-	EVENT_ASSOCINFO,
-
-	/**
-	 * EVENT_INTERFACE_STATUS - Report interface status changes
-	 *
-	 * This optional event can be used to report changes in interface
-	 * status (interface added/removed) using union
-	 * wpa_event_data::interface_status. This can be used to trigger
-	 * wpa_supplicant to stop and re-start processing for the interface,
-	 * e.g., when a cardbus card is ejected/inserted.
-	 */
-	EVENT_INTERFACE_STATUS,
-
-	/**
-	 * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication
-	 *
-	 * This event can be used to inform wpa_supplicant about candidates for
-	 * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible
-	 * for scan request (ap_scan=2 mode), this event is required for
-	 * pre-authentication. If wpa_supplicant is performing scan request
-	 * (ap_scan=1), this event is optional since scan results can be used
-	 * to add pre-authentication candidates. union
-	 * wpa_event_data::pmkid_candidate is used to report the BSSID of the
-	 * candidate and priority of the candidate, e.g., based on the signal
-	 * strength, in order to try to pre-authenticate first with candidates
-	 * that are most likely targets for re-association.
-	 *
-	 * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates
-	 * on the candidate list. In addition, it can be called for the current
-	 * AP and APs that have existing PMKSA cache entries. wpa_supplicant
-	 * will automatically skip pre-authentication in cases where a valid
-	 * PMKSA exists. When more than one candidate exists, this event should
-	 * be generated once for each candidate.
-	 *
-	 * Driver will be notified about successful pre-authentication with
-	 * struct wpa_driver_ops::add_pmkid() calls.
-	 */
-	EVENT_PMKID_CANDIDATE,
-
-	/**
-	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
-	 *
-	 * This event can be used to inform wpa_supplicant about desire to set
-	 * up secure direct link connection between two stations as defined in
-	 * IEEE 802.11e with a new PeerKey mechanism that replaced the original
-	 * STAKey negotiation. The caller will need to set peer address for the
-	 * event.
-	 */
-	EVENT_STKSTART,
-
-	/**
-	 * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs
-	 *
-	 * The driver is expected to report the received FT IEs from
-	 * FT authentication sequence from the AP. The FT IEs are included in
-	 * the extra information in union wpa_event_data::ft_ies.
-	 */
-	EVENT_FT_RESPONSE,
-
-	/**
-	 * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS
-	 *
-	 * The driver can use this event to inform wpa_supplicant about a STA
-	 * in an IBSS with which protected frames could be exchanged. This
-	 * event starts RSN authentication with the other STA to authenticate
-	 * the STA and set up encryption keys with it.
-	 */
-	EVENT_IBSS_RSN_START,
-
-	/**
-	 * EVENT_AUTH - Authentication result
-	 *
-	 * This event should be called when authentication attempt has been
-	 * completed. This is only used if the driver supports separate
-	 * authentication step (struct wpa_driver_ops::authenticate).
-	 * Information about authentication result is included in
-	 * union wpa_event_data::auth.
-	 */
-	EVENT_AUTH,
-
-	/**
-	 * EVENT_DEAUTH - Authentication lost
-	 *
-	 * This event should be called when authentication is lost either due
-	 * to receiving deauthenticate frame from the AP or when sending that
-	 * frame to the current AP.
-	 * In AP mode, union wpa_event_data::deauth_info is required.
-	 */
-	EVENT_DEAUTH,
-
-	/**
-	 * EVENT_ASSOC_REJECT - Association rejected
-	 *
-	 * This event should be called when (re)association attempt has been
-	 * rejected by the AP. Information about authentication result is
-	 * included in union wpa_event_data::assoc_reject.
-	 */
-	EVENT_ASSOC_REJECT,
-
-	/**
-	 * EVENT_AUTH_TIMED_OUT - Authentication timed out
-	 */
-	EVENT_AUTH_TIMED_OUT,
-
-	/**
-	 * EVENT_ASSOC_TIMED_OUT - Association timed out
-	 */
-	EVENT_ASSOC_TIMED_OUT,
-
-	/**
-	 * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
-	 */
-	EVENT_FT_RRB_RX,
-
-	/**
-	 * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
-	 */
-	EVENT_WPS_BUTTON_PUSHED,
-
-	/**
-	 * EVENT_TX_STATUS - Report TX status
-	 */
-	EVENT_TX_STATUS,
-
-	/**
-	 * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA
-	 */
-	EVENT_RX_FROM_UNKNOWN,
-
-	/**
-	 * EVENT_RX_MGMT - Report RX of a management frame
-	 */
-	EVENT_RX_MGMT,
-
-	/**
-	 * EVENT_RX_ACTION - Action frame received
-	 *
-	 * This event is used to indicate when an Action frame has been
-	 * received. Information about the received frame is included in
-	 * union wpa_event_data::rx_action.
-	 */
-	EVENT_RX_ACTION,
-
-	/**
-	 * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
-	 *
-	 * This event is used to indicate when the driver has started the
-	 * requested remain-on-channel duration. Information about the
-	 * operation is included in union wpa_event_data::remain_on_channel.
-	 */
-	EVENT_REMAIN_ON_CHANNEL,
-
-	/**
-	 * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out
-	 *
-	 * This event is used to indicate when the driver has completed
-	 * remain-on-channel duration, i.e., may noot be available on the
-	 * requested channel anymore. Information about the
-	 * operation is included in union wpa_event_data::remain_on_channel.
-	 */
-	EVENT_CANCEL_REMAIN_ON_CHANNEL,
-
-	/**
-	 * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
-	 *
-	 * This event is used only by driver_test.c and userspace MLME.
-	 */
-	EVENT_MLME_RX,
-
-	/**
-	 * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
-	 *
-	 * This event is used to indicate when a Probe Request frame has been
-	 * received. Information about the received frame is included in
-	 * union wpa_event_data::rx_probe_req. The driver is required to report
-	 * these events only after successfully completed probe_req_report()
-	 * commands to request the events (i.e., report parameter is non-zero)
-	 * in station mode. In AP mode, Probe Request frames should always be
-	 * reported.
-	 */
-	EVENT_RX_PROBE_REQ,
-
-	/**
-	 * EVENT_NEW_STA - New wired device noticed
-	 *
-	 * This event is used to indicate that a new device has been detected
-	 * in a network that does not use association-like functionality (i.e.,
-	 * mainly wired Ethernet). This can be used to start EAPOL
-	 * authenticator when receiving a frame from a device. The address of
-	 * the device is included in union wpa_event_data::new_sta.
-	 */
-	EVENT_NEW_STA,
-
-	/**
-	 * EVENT_EAPOL_RX - Report received EAPOL frame
-	 *
-	 * When in AP mode with hostapd, this event is required to be used to
-	 * deliver the receive EAPOL frames from the driver. With
-	 * %wpa_supplicant, this event is used only if the send_eapol() handler
-	 * is used to override the use of l2_packet for EAPOL frame TX.
-	 */
-	EVENT_EAPOL_RX,
-
-	/**
-	 * EVENT_SIGNAL_CHANGE - Indicate change in signal strength
-	 *
-	 * This event is used to indicate changes in the signal strength
-	 * observed in frames received from the current AP if signal strength
-	 * monitoring has been enabled with signal_monitor().
-	 */
-	EVENT_SIGNAL_CHANGE
-};
-
-
-/**
- * union wpa_event_data - Additional data for wpa_supplicant_event() calls
- */
-union wpa_event_data {
-	/**
-	 * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events
-	 *
-	 * This structure is optional for EVENT_ASSOC calls and required for
-	 * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the
-	 * driver interface does not need to generate separate EVENT_ASSOCINFO
-	 * calls.
-	 */
-	struct assoc_info {
-		/**
-		 * req_ies - (Re)Association Request IEs
-		 *
-		 * If the driver generates WPA/RSN IE, this event data must be
-		 * returned for WPA handshake to have needed information. If
-		 * wpa_supplicant-generated WPA/RSN IE is used, this
-		 * information event is optional.
-		 *
-		 * This should start with the first IE (fixed fields before IEs
-		 * are not included).
-		 */
-		const u8 *req_ies;
-
-		/**
-		 * req_ies_len - Length of req_ies in bytes
-		 */
-		size_t req_ies_len;
-
-		/**
-		 * resp_ies - (Re)Association Response IEs
-		 *
-		 * Optional association data from the driver. This data is not
-		 * required WPA, but may be useful for some protocols and as
-		 * such, should be reported if this is available to the driver
-		 * interface.
-		 *
-		 * This should start with the first IE (fixed fields before IEs
-		 * are not included).
-		 */
-		const u8 *resp_ies;
-
-		/**
-		 * resp_ies_len - Length of resp_ies in bytes
-		 */
-		size_t resp_ies_len;
-
-		/**
-		 * beacon_ies - Beacon or Probe Response IEs
-		 *
-		 * Optional Beacon/ProbeResp data: IEs included in Beacon or
-		 * Probe Response frames from the current AP (i.e., the one
-		 * that the client just associated with). This information is
-		 * used to update WPA/RSN IE for the AP. If this field is not
-		 * set, the results from previous scan will be used. If no
-		 * data for the new AP is found, scan results will be requested
-		 * again (without scan request). At this point, the driver is
-		 * expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is
-		 * used).
-		 *
-		 * This should start with the first IE (fixed fields before IEs
-		 * are not included).
-		 */
-		const u8 *beacon_ies;
-
-		/**
-		 * beacon_ies_len - Length of beacon_ies */
-		size_t beacon_ies_len;
-
-		/**
-		 * freq - Frequency of the operational channel in MHz
-		 */
-		unsigned int freq;
-
-		/**
-		 * addr - Station address (for AP mode)
-		 */
-		const u8 *addr;
-	} assoc_info;
-
-	/**
-	 * struct disassoc_info - Data for EVENT_DISASSOC events
-	 */
-	struct disassoc_info {
-		/**
-		 * addr - Station address (for AP mode)
-		 */
-		const u8 *addr;
-
-		/**
-		 * reason_code - Reason Code (host byte order) used in
-		 *	Deauthentication frame
-		 */
-		u16 reason_code;
-	} disassoc_info;
-
-	/**
-	 * struct deauth_info - Data for EVENT_DEAUTH events
-	 */
-	struct deauth_info {
-		/**
-		 * addr - Station address (for AP mode)
-		 */
-		const u8 *addr;
-
-		/**
-		 * reason_code - Reason Code (host byte order) used in
-		 *	Deauthentication frame
-		 */
-		u16 reason_code;
-	} deauth_info;
-
-	/**
-	 * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE
-	 */
-	struct michael_mic_failure {
-		int unicast;
-		const u8 *src;
-	} michael_mic_failure;
-
-	/**
-	 * struct interface_status - Data for EVENT_INTERFACE_STATUS
-	 */
-	struct interface_status {
-		char ifname[100];
-		enum {
-			EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
-		} ievent;
-	} interface_status;
-
-	/**
-	 * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE
-	 */
-	struct pmkid_candidate {
-		/** BSSID of the PMKID candidate */
-		u8 bssid[ETH_ALEN];
-		/** Smaller the index, higher the priority */
-		int index;
-		/** Whether RSN IE includes pre-authenticate flag */
-		int preauth;
-	} pmkid_candidate;
-
-	/**
-	 * struct stkstart - Data for EVENT_STKSTART
-	 */
-	struct stkstart {
-		u8 peer[ETH_ALEN];
-	} stkstart;
-
-	/**
-	 * struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
-	 *
-	 * During FT (IEEE 802.11r) authentication sequence, the driver is
-	 * expected to use this event to report received FT IEs (MDIE, FTIE,
-	 * RSN IE, TIE, possible resource request) to the supplicant. The FT
-	 * IEs for the next message will be delivered through the
-	 * struct wpa_driver_ops::update_ft_ies() callback.
-	 */
-	struct ft_ies {
-		const u8 *ies;
-		size_t ies_len;
-		int ft_action;
-		u8 target_ap[ETH_ALEN];
-		/** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */
-		const u8 *ric_ies;
-		/** Length of ric_ies buffer in octets */
-		size_t ric_ies_len;
-	} ft_ies;
-
-	/**
-	 * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START
-	 */
-	struct ibss_rsn_start {
-		u8 peer[ETH_ALEN];
-	} ibss_rsn_start;
-
-	/**
-	 * struct auth_info - Data for EVENT_AUTH events
-	 */
-	struct auth_info {
-		u8 peer[ETH_ALEN];
-		u16 auth_type;
-		u16 status_code;
-		const u8 *ies;
-		size_t ies_len;
-	} auth;
-
-	/**
-	 * struct assoc_reject - Data for EVENT_ASSOC_REJECT events
-	 */
-	struct assoc_reject {
-		/**
-		 * resp_ies - (Re)Association Response IEs
-		 *
-		 * Optional association data from the driver. This data is not
-		 * required WPA, but may be useful for some protocols and as
-		 * such, should be reported if this is available to the driver
-		 * interface.
-		 *
-		 * This should start with the first IE (fixed fields before IEs
-		 * are not included).
-		 */
-		u8 *resp_ies;
-
-		/**
-		 * resp_ies_len - Length of resp_ies in bytes
-		 */
-		size_t resp_ies_len;
-
-		/**
-		 * status_code - Status Code from (Re)association Response
-		 */
-		u16 status_code;
-	} assoc_reject;
-
-	struct timeout_event {
-		u8 addr[ETH_ALEN];
-	} timeout_event;
-
-	/**
-	 * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
-	 */
-	struct ft_rrb_rx {
-		const u8 *src;
-		const u8 *data;
-		size_t data_len;
-	} ft_rrb_rx;
-
-	/**
-	 * struct tx_status - Data for EVENT_TX_STATUS events
-	 */
-	struct tx_status {
-		u16 type;
-		u16 stype;
-		const u8 *dst;
-		const u8 *data;
-		size_t data_len;
-		int ack;
-	} tx_status;
-
-	/**
-	 * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
-	 */
-	struct rx_from_unknown {
-		const u8 *frame;
-		size_t len;
-	} rx_from_unknown;
-
-	/**
-	 * struct rx_mgmt - Data for EVENT_RX_MGMT events
-	 */
-	struct rx_mgmt {
-		const u8 *frame;
-		size_t frame_len;
-		u32 datarate;
-		u32 ssi_signal;
-	} rx_mgmt;
-
-	/**
-	 * struct rx_action - Data for EVENT_RX_ACTION events
-	 */
-	struct rx_action {
-		/**
-		 * da - Destination address of the received Action frame
-		 */
-		const u8 *da;
-
-		/**
-		 * sa - Source address of the received Action frame
-		 */
-		const u8 *sa;
-
-		/**
-		 * bssid - Address 3 of the received Action frame
-		 */
-		const u8 *bssid;
-
-		/**
-		 * category - Action frame category
-		 */
-		u8 category;
-
-		/**
-		 * data - Action frame body after category field
-		 */
-		const u8 *data;
-
-		/**
-		 * len - Length of data in octets
-		 */
-		size_t len;
-
-		/**
-		 * freq - Frequency (in MHz) on which the frame was received
-		 */
-		int freq;
-	} rx_action;
-
-	/**
-	 * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
-	 *
-	 * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events.
-	 */
-	struct remain_on_channel {
-		/**
-		 * freq - Channel frequency in MHz
-		 */
-		unsigned int freq;
-
-		/**
-		 * duration - Duration to remain on the channel in milliseconds
-		 */
-		unsigned int duration;
-	} remain_on_channel;
-
-	/**
-	 * struct scan_info - Optional data for EVENT_SCAN_RESULTS events
-	 * @aborted: Whether the scan was aborted
-	 * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
-	 * @num_freqs: Number of entries in freqs array
-	 * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
-	 *	SSID)
-	 * @num_ssids: Number of entries in ssids array
-	 */
-	struct scan_info {
-		int aborted;
-		const int *freqs;
-		size_t num_freqs;
-		struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
-		size_t num_ssids;
-	} scan_info;
-
-	/**
-	 * struct mlme_rx - Data for EVENT_MLME_RX events
-	 */
-	struct mlme_rx {
-		const u8 *buf;
-		size_t len;
-		int freq;
-		int channel;
-		int ssi;
-	} mlme_rx;
-
-	/**
-	 * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
-	 */
-	struct rx_probe_req {
-		/**
-		 * sa - Source address of the received Probe Request frame
-		 */
-		const u8 *sa;
-
-		/**
-		 * ie - IEs from the Probe Request body
-		 */
-		const u8 *ie;
-
-		/**
-		 * ie_len - Length of ie buffer in octets
-		 */
-		size_t ie_len;
-	} rx_probe_req;
-
-	/**
-	 * struct new_sta - Data for EVENT_NEW_STA events
-	 */
-	struct new_sta {
-		const u8 *addr;
-	} new_sta;
-
-	/**
-	 * struct eapol_rx - Data for EVENT_EAPOL_RX events
-	 */
-	struct eapol_rx {
-		const u8 *src;
-		const u8 *data;
-		size_t data_len;
-	} eapol_rx;
-
-	/**
-	 * struct signal_change - Data for EVENT_SIGNAL_CHANGE events
-	 */
-	struct signal_change {
-		int above_threshold;
-	} signal_change;
-};
-
-/**
- * wpa_supplicant_event - 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
- *
- * Driver wrapper code should call this function whenever an event is received
- * from the driver.
- */
-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
-			  union wpa_event_data *data);
-
-
-/*
- * The following inline functions are provided for convenience to simplify
- * event indication for some of the common events.
- */
-
-static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie,
-				   size_t ielen)
-{
-	union wpa_event_data event;
-	os_memset(&event, 0, sizeof(event));
-	event.assoc_info.req_ies = ie;
-	event.assoc_info.req_ies_len = ielen;
-	event.assoc_info.addr = addr;
-	wpa_supplicant_event(ctx, EVENT_ASSOC, &event);
-}
-
-static inline void drv_event_disassoc(void *ctx, const u8 *addr)
-{
-	union wpa_event_data event;
-	os_memset(&event, 0, sizeof(event));
-	event.disassoc_info.addr = addr;
-	wpa_supplicant_event(ctx, EVENT_DISASSOC, &event);
-}
-
-static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
-				      size_t data_len)
-{
-	union wpa_event_data event;
-	os_memset(&event, 0, sizeof(event));
-	event.eapol_rx.src = src;
-	event.eapol_rx.data = data;
-	event.eapol_rx.data_len = data_len;
-	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
-}
-
-#endif /* DRIVER_H */

Copied: vendor/wpa/2.0/src/drivers/driver.h (from rev 9639, vendor/wpa/dist/src/drivers/driver.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3732 @@
+/*
+ * Driver interface definition
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines a driver interface used by both %wpa_supplicant and
+ * hostapd. The first part of the file defines data structures used in various
+ * driver operations. This is followed by the struct wpa_driver_ops that each
+ * driver wrapper will beed to define with callback functions for requesting
+ * driver operations. After this, there are definitions for driver event
+ * reporting with wpa_supplicant_event() and some convenience helper functions
+ * that can be used to report events.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#define WPA_SUPPLICANT_DRIVER_VERSION 4
+
+#include "common/defs.h"
+
+#define HOSTAPD_CHAN_DISABLED 0x00000001
+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_RADAR 0x00000008
+#define HOSTAPD_CHAN_HT40PLUS 0x00000010
+#define HOSTAPD_CHAN_HT40MINUS 0x00000020
+#define HOSTAPD_CHAN_HT40 0x00000040
+
+/**
+ * struct hostapd_channel_data - Channel information
+ */
+struct hostapd_channel_data {
+	/**
+	 * chan - Channel number (IEEE 802.11)
+	 */
+	short chan;
+
+	/**
+	 * freq - Frequency in MHz
+	 */
+	int freq;
+
+	/**
+	 * flag - Channel flags (HOSTAPD_CHAN_*)
+	 */
+	int flag;
+
+	/**
+	 * max_tx_power - maximum transmit power in dBm
+	 */
+	u8 max_tx_power;
+};
+
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
+/**
+ * struct hostapd_hw_modes - Supported hardware mode information
+ */
+struct hostapd_hw_modes {
+	/**
+	 * mode - Hardware mode
+	 */
+	enum hostapd_hw_mode mode;
+
+	/**
+	 * num_channels - Number of entries in the channels array
+	 */
+	int num_channels;
+
+	/**
+	 * channels - Array of supported channels
+	 */
+	struct hostapd_channel_data *channels;
+
+	/**
+	 * num_rates - Number of entries in the rates array
+	 */
+	int num_rates;
+
+	/**
+	 * rates - Array of supported rates in 100 kbps units
+	 */
+	int *rates;
+
+	/**
+	 * ht_capab - HT (IEEE 802.11n) capabilities
+	 */
+	u16 ht_capab;
+
+	/**
+	 * mcs_set - MCS (IEEE 802.11n) rate parameters
+	 */
+	u8 mcs_set[16];
+
+	/**
+	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
+	 */
+	u8 a_mpdu_params;
+
+	/**
+	 * vht_capab - VHT (IEEE 802.11ac) capabilities
+	 */
+	u32 vht_capab;
+
+	/**
+	 * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters
+	 */
+	u8 vht_mcs_set[8];
+
+	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+};
+
+
+#define IEEE80211_MODE_INFRA	0
+#define IEEE80211_MODE_IBSS	1
+#define IEEE80211_MODE_AP	2
+
+#define IEEE80211_CAP_ESS	0x0001
+#define IEEE80211_CAP_IBSS	0x0002
+#define IEEE80211_CAP_PRIVACY	0x0010
+
+#define WPA_SCAN_QUAL_INVALID		BIT(0)
+#define WPA_SCAN_NOISE_INVALID		BIT(1)
+#define WPA_SCAN_LEVEL_INVALID		BIT(2)
+#define WPA_SCAN_LEVEL_DBM		BIT(3)
+#define WPA_SCAN_AUTHENTICATED		BIT(4)
+#define WPA_SCAN_ASSOCIATED		BIT(5)
+
+/**
+ * struct wpa_scan_res - Scan result for an BSS/IBSS
+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
+ * @bssid: BSSID
+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @beacon_int: beacon interval in TUs (host byte order)
+ * @caps: capability information field in host byte order
+ * @qual: signal quality
+ * @noise: noise level
+ * @level: signal level
+ * @tsf: Timestamp
+ * @age: Age of the information in milliseconds (i.e., how many milliseconds
+ * ago the last Beacon or Probe Response frame was received)
+ * @ie_len: length of the following IE field in octets
+ * @beacon_ie_len: length of the following Beacon IE field in octets
+ *
+ * This structure is used as a generic format for scan results from the
+ * driver. Each driver interface implementation is responsible for converting
+ * the driver or OS specific scan results into this format.
+ *
+ * If the driver does not support reporting all IEs, the IE data structure is
+ * constructed of the IEs that are available. This field will also need to
+ * include SSID in IE format. All drivers are encouraged to be extended to
+ * report all IEs to make it easier to support future additions.
+ */
+struct wpa_scan_res {
+	unsigned int flags;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	u16 beacon_int;
+	u16 caps;
+	int qual;
+	int noise;
+	int level;
+	u64 tsf;
+	unsigned int age;
+	size_t ie_len;
+	size_t beacon_ie_len;
+	/*
+	 * Followed by ie_len octets of IEs from Probe Response frame (or if
+	 * the driver does not indicate source of IEs, these may also be from
+	 * Beacon frame). After the first set of IEs, another set of IEs may
+	 * follow (with beacon_ie_len octets of data) if the driver provides
+	 * both IE sets.
+	 */
+};
+
+/**
+ * struct wpa_scan_results - Scan results
+ * @res: Array of pointers to allocated variable length scan result entries
+ * @num: Number of entries in the scan result array
+ */
+struct wpa_scan_results {
+	struct wpa_scan_res **res;
+	size_t num;
+};
+
+/**
+ * struct wpa_interface_info - Network interface information
+ * @next: Pointer to the next interface or NULL if this is the last one
+ * @ifname: Interface name that can be used with init() or init2()
+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
+ *	not available
+ * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
+ *	is not an allocated copy, i.e., get_interfaces() caller will not free
+ *	this)
+ */
+struct wpa_interface_info {
+	struct wpa_interface_info *next;
+	char *ifname;
+	char *desc;
+	const char *drv_name;
+};
+
+#define WPAS_MAX_SCAN_SSIDS 16
+
+/**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+ */
+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];
+
+	/**
+	 * num_ssids - Number of entries in ssids array
+	 * Zero indicates a request for a passive scan.
+	 */
+	size_t num_ssids;
+
+	/**
+	 * extra_ies - Extra IE(s) to add into Probe Request or %NULL
+	 */
+	const u8 *extra_ies;
+
+	/**
+	 * extra_ies_len - Length of extra_ies in octets
+	 */
+	size_t extra_ies_len;
+
+	/**
+	 * freqs - Array of frequencies to scan or %NULL for all frequencies
+	 *
+	 * The frequency is set in MHz. The array is zero-terminated.
+	 */
+	int *freqs;
+
+	/**
+	 * filter_ssids - Filter for reporting SSIDs
+	 *
+	 * This optional parameter can be used to request the driver wrapper to
+	 * filter scan results to include only the specified SSIDs. %NULL
+	 * indicates that no filtering is to be done. This can be used to
+	 * reduce memory needs for scan results in environments that have large
+	 * number of APs with different SSIDs.
+	 *
+	 * The driver wrapper is allowed to take this allocated buffer into its
+	 * own use by setting the pointer to %NULL. In that case, the driver
+	 * wrapper is responsible for freeing the buffer with os_free() once it
+	 * is not needed anymore.
+	 */
+	struct wpa_driver_scan_filter {
+		u8 ssid[32];
+		size_t ssid_len;
+	} *filter_ssids;
+
+	/**
+	 * num_filter_ssids - Number of entries in filter_ssids array
+	 */
+	size_t num_filter_ssids;
+
+	/**
+	 * filter_rssi - Filter by RSSI
+	 *
+	 * The driver may filter scan results in firmware to reduce host
+	 * wakeups and thereby save power. Specify the RSSI threshold in s32
+	 * dBm.
+	 */
+	s32 filter_rssi;
+
+	/**
+	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+	 *
+	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+	 * Mbps from the support rates element(s) in the Probe Request frames
+	 * and not to transmit the frames at any of those rates.
+	 */
+	u8 p2p_probe;
+};
+
+/**
+ * struct wpa_driver_auth_params - Authentication parameters
+ * Data for struct wpa_driver_ops::authenticate().
+ */
+struct wpa_driver_auth_params {
+	int freq;
+	const u8 *bssid;
+	const u8 *ssid;
+	size_t ssid_len;
+	int auth_alg;
+	const u8 *ie;
+	size_t ie_len;
+	const u8 *wep_key[4];
+	size_t wep_key_len[4];
+	int wep_tx_keyidx;
+	int local_state_change;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	const u8 *sae_data;
+	size_t sae_data_len;
+
+};
+
+enum wps_mode {
+	WPS_MODE_NONE /* no WPS provisioning being used */,
+	WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
+	WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
+			  */
+};
+
+/**
+ * struct wpa_driver_associate_params - Association parameters
+ * Data for struct wpa_driver_ops::associate().
+ */
+struct wpa_driver_associate_params {
+	/**
+	 * bssid - BSSID of the selected AP
+	 * This can be %NULL, if ap_scan=2 mode is used and the driver is
+	 * responsible for selecting with which BSS to associate. */
+	const u8 *bssid;
+
+	/**
+	 * ssid - The selected SSID
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * freq - Frequency of the channel the selected AP is using
+	 * Frequency that the selected AP is using (in MHz as
+	 * reported in the scan results)
+	 */
+	int freq;
+
+	/**
+	 * bg_scan_period - Background scan period in seconds, 0 to disable
+	 * background scan, or -1 to indicate no change to default driver
+	 * configuration
+	 */
+	int bg_scan_period;
+
+	/**
+	 * wpa_ie - WPA information element for (Re)Association Request
+	 * WPA information element to be included in (Re)Association
+	 * Request (including information element id and length). Use
+	 * of this WPA IE is optional. If the driver generates the WPA
+	 * IE, it can use pairwise_suite, group_suite, and
+	 * key_mgmt_suite to select proper algorithms. In this case,
+	 * the driver has to notify wpa_supplicant about the used WPA
+	 * IE by generating an event that the interface code will
+	 * convert into EVENT_ASSOCINFO data (see below).
+	 *
+	 * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
+	 * instead. The driver can determine which version is used by
+	 * looking at the first byte of the IE (0xdd for WPA, 0x30 for
+	 * WPA2/RSN).
+	 *
+	 * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
+	 */
+	const u8 *wpa_ie;
+
+	/**
+	 * wpa_ie_len - length of the wpa_ie
+	 */
+	size_t wpa_ie_len;
+
+	/**
+	 * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+	 */
+	unsigned int wpa_proto;
+
+	/**
+	 * pairwise_suite - Selected pairwise cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher pairwise_suite;
+
+	/**
+	 * group_suite - Selected group cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher group_suite;
+
+	/**
+	 * key_mgmt_suite - Selected key management suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_key_mgmt key_mgmt_suite;
+
+	/**
+	 * auth_alg - Allowed authentication algorithms
+	 * Bit field of WPA_AUTH_ALG_*
+	 */
+	int auth_alg;
+
+	/**
+	 * mode - Operation mode (infra/ibss) IEEE80211_MODE_*
+	 */
+	int mode;
+
+	/**
+	 * wep_key - WEP keys for static WEP configuration
+	 */
+	const u8 *wep_key[4];
+
+	/**
+	 * wep_key_len - WEP key length for static WEP configuration
+	 */
+	size_t wep_key_len[4];
+
+	/**
+	 * wep_tx_keyidx - WEP TX key index for static WEP configuration
+	 */
+	int wep_tx_keyidx;
+
+	/**
+	 * mgmt_frame_protection - IEEE 802.11w management frame protection
+	 */
+	enum mfp_options mgmt_frame_protection;
+
+	/**
+	 * ft_ies - IEEE 802.11r / FT information elements
+	 * If the supplicant is using IEEE 802.11r (FT) and has the needed keys
+	 * for fast transition, this parameter is set to include the IEs that
+	 * are to be sent in the next FT Authentication Request message.
+	 * update_ft_ies() handler is called to update the IEs for further
+	 * FT messages in the sequence.
+	 *
+	 * The driver should use these IEs only if the target AP is advertising
+	 * the same mobility domain as the one included in the MDIE here.
+	 *
+	 * In ap_scan=2 mode, the driver can use these IEs when moving to a new
+	 * AP after the initial association. These IEs can only be used if the
+	 * target AP is advertising support for FT and is using the same MDIE
+	 * and SSID as the current AP.
+	 *
+	 * The driver is responsible for reporting the FT IEs received from the
+	 * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE
+	 * type. update_ft_ies() handler will then be called with the FT IEs to
+	 * include in the next frame in the authentication sequence.
+	 */
+	const u8 *ft_ies;
+
+	/**
+	 * ft_ies_len - Length of ft_ies in bytes
+	 */
+	size_t ft_ies_len;
+
+	/**
+	 * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies)
+	 *
+	 * This value is provided to allow the driver interface easier access
+	 * to the current mobility domain. This value is set to %NULL if no
+	 * mobility domain is currently active.
+	 */
+	const u8 *ft_md;
+
+	/**
+	 * passphrase - RSN passphrase for PSK
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 8..63 character ASCII passphrase, if available. Please note that
+	 * this can be %NULL if passphrase was not used to generate the PSK. In
+	 * that case, the psk field must be used to fetch the PSK.
+	 */
+	const char *passphrase;
+
+	/**
+	 * psk - RSN PSK (alternative for passphrase for PSK)
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 32-octet (256-bit) PSK, if available. The driver wrapper should
+	 * be prepared to handle %NULL value as an error.
+	 */
+	const u8 *psk;
+
+	/**
+	 * drop_unencrypted - Enable/disable unencrypted frame filtering
+	 *
+	 * Configure the driver to drop all non-EAPOL frames (both receive and
+	 * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
+	 * still be allowed for key negotiation.
+	 */
+	int drop_unencrypted;
+
+	/**
+	 * prev_bssid - Previously used BSSID in this ESS
+	 *
+	 * When not %NULL, this is a request to use reassociation instead of
+	 * association.
+	 */
+	const u8 *prev_bssid;
+
+	/**
+	 * wps - WPS mode
+	 *
+	 * If the driver needs to do special configuration for WPS association,
+	 * this variable provides more information on what type of association
+	 * is being requested. Most drivers should not need ot use this.
+	 */
+	enum wps_mode wps;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	/**
+	 * uapsd - UAPSD parameters for the network
+	 * -1 = do not change defaults
+	 * AP mode: 1 = enabled, 0 = disabled
+	 * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE
+	 */
+	int uapsd;
+
+	/**
+	 * fixed_bssid - Whether to force this BSSID in IBSS mode
+	 * 1 = Fix this BSSID and prevent merges.
+	 * 0 = Do not fix BSSID.
+	 */
+	int fixed_bssid;
+
+	/**
+	 * disable_ht - Disable HT (IEEE 802.11n) for this connection
+	 */
+	int disable_ht;
+
+	/**
+	 * HT Capabilities over-rides. Only bits set in the mask will be used,
+	 * and not all values are used by the kernel anyway. Currently, MCS,
+	 * MPDU and MSDU fields are used.
+	 */
+	const u8 *htcaps;       /* struct ieee80211_ht_capabilities * */
+	const u8 *htcaps_mask;  /* struct ieee80211_ht_capabilities * */
+};
+
+enum hide_ssid {
+	NO_SSID_HIDING,
+	HIDDEN_SSID_ZERO_LEN,
+	HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+	/**
+	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+	 */
+	const u8 *head;
+
+	/**
+	 * head_len - Length of the head buffer in octets
+	 */
+	size_t head_len;
+
+	/**
+	 * tail - Beacon tail following TIM IE
+	 */
+	const u8 *tail;
+
+	/**
+	 * tail_len - Length of the tail buffer in octets
+	 */
+	size_t tail_len;
+
+	/**
+	 * dtim_period - DTIM period
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Beacon interval
+	 */
+	int beacon_int;
+
+	/**
+	 * basic_rates: -1 terminated array of basic rates in 100 kbps
+	 *
+	 * This parameter can be used to set a specific basic rate set for the
+	 * BSS. If %NULL, default basic rate set is used.
+	 */
+	int *basic_rates;
+
+	/**
+	 * proberesp - Probe Response template
+	 *
+	 * This is used by drivers that reply to Probe Requests internally in
+	 * AP mode and require the full Probe Response template.
+	 */
+	const u8 *proberesp;
+
+	/**
+	 * proberesp_len - Length of the proberesp buffer in octets
+	 */
+	size_t proberesp_len;
+
+	/**
+	 * ssid - The SSID to use in Beacon/Probe Response frames
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * hide_ssid - Whether to hide the SSID
+	 */
+	enum hide_ssid hide_ssid;
+
+	/**
+	 * pairwise_ciphers - WPA_CIPHER_* bitfield
+	 */
+	unsigned int pairwise_ciphers;
+
+	/**
+	 * group_cipher - WPA_CIPHER_*
+	 */
+	unsigned int group_cipher;
+
+	/**
+	 * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+	 */
+	unsigned int key_mgmt_suites;
+
+	/**
+	 * auth_algs - WPA_AUTH_ALG_* bitfield
+	 */
+	unsigned int auth_algs;
+
+	/**
+	 * wpa_version - WPA_PROTO_* bitfield
+	 */
+	unsigned int wpa_version;
+
+	/**
+	 * privacy - Whether privacy is used in the BSS
+	 */
+	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do
+	 * not use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 *
+	 * This is used to add IEs like WPS IE by drivers that reply to
+	 * (Re)Association Request frames internally.
+	 */
+	const struct wpabuf *assocresp_ies;
+
+	/**
+	 * isolate - Whether to isolate frames between associated stations
+	 *
+	 * If this is non-zero, the AP is requested to disable forwarding of
+	 * frames between associated stations.
+	 */
+	int isolate;
+
+	/**
+	 * cts_protect - Whether CTS protection is enabled
+	 */
+	int cts_protect;
+
+	/**
+	 * preamble - Whether short preamble is enabled
+	 */
+	int preamble;
+
+	/**
+	 * short_slot_time - Whether short slot time is enabled
+	 *
+	 * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+	 * not set (e.g., when 802.11g mode is not in use)
+	 */
+	int short_slot_time;
+
+	/**
+	 * ht_opmode - HT operation mode or -1 if HT not in use
+	 */
+	int ht_opmode;
+
+	/**
+	 * interworking - Whether Interworking is enabled
+	 */
+	int interworking;
+
+	/**
+	 * hessid - Homogeneous ESS identifier or %NULL if not set
+	 */
+	const u8 *hessid;
+
+	/**
+	 * access_network_type - Access Network Type (0..15)
+	 *
+	 * This is used for filtering Probe Request frames when Interworking is
+	 * enabled.
+	 */
+	u8 access_network_type;
+
+	/**
+	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+	 *
+	 * This is used by driver which advertises this capability.
+	 */
+	int ap_max_inactivity;
+
+	/**
+	 * disable_dgaf - Whether group-addressed frames are disabled
+	 */
+	int disable_dgaf;
+};
+
+/**
+ * struct wpa_driver_capa - Driver capability information
+ */
+struct wpa_driver_capa {
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA		0x00000001
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2		0x00000002
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK	0x00000004
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK	0x00000008
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE	0x00000010
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
+#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
+	unsigned int key_mgmt;
+
+#define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
+#define WPA_DRIVER_CAPA_ENC_WEP104	0x00000002
+#define WPA_DRIVER_CAPA_ENC_TKIP	0x00000004
+#define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
+#define WPA_DRIVER_CAPA_ENC_WEP128	0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP	0x00000020
+	unsigned int enc;
+
+#define WPA_DRIVER_AUTH_OPEN		0x00000001
+#define WPA_DRIVER_AUTH_SHARED		0x00000002
+#define WPA_DRIVER_AUTH_LEAP		0x00000004
+	unsigned int auth;
+
+/* Driver generated WPA/RSN IE */
+#define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
+/* Driver needs static WEP key setup after association command */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
+/* unused: 0x00000004 */
+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_WIRED		0x00000010
+/* Driver provides separate commands for authentication and association (SME in
+ * wpa_supplicant). */
+#define WPA_DRIVER_FLAGS_SME		0x00000020
+/* Driver supports AP mode */
+#define WPA_DRIVER_FLAGS_AP		0x00000040
+/* Driver needs static WEP key setup after association has been completed */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
+/* Driver takes care of P2P management operations */
+#define WPA_DRIVER_FLAGS_P2P_MGMT	0x00000100
+/* Driver supports concurrent P2P operations */
+#define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
+/*
+ * Driver uses the initial interface as a dedicated management interface, i.e.,
+ * it cannot be used for P2P group operations or non-P2P purposes.
+ */
+#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
+/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+#define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
+/* Driver supports concurrent operations on multiple channels */
+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
+/*
+ * Driver uses the initial interface for P2P management interface and non-P2P
+ * purposes (e.g., connect to infra AP), but this interface cannot be used for
+ * P2P group operations.
+ */
+#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
+/*
+ * Driver is known to use sane error codes, i.e., when it indicates that
+ * something (e.g., association) fails, there was indeed a failure and the
+ * operation does not end up getting completed successfully later.
+ */
+#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
+/* Driver indicates TX status events for EAPOL Data frames */
+#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
+/* Driver supports inactivity timer in AP mode */
+#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE				0x02000000
+/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+#define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
+	unsigned int flags;
+
+	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	int max_match_sets;
+
+	/**
+	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
+	 */
+	unsigned int max_remain_on_chan;
+
+	/**
+	 * max_stations - Maximum number of associated stations the driver
+	 * supports in AP mode
+	 */
+	unsigned int max_stations;
+
+	/**
+	 * probe_resp_offloads - Bitmap of supported protocols by the driver
+	 * for Probe Response offloading.
+	 */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
+	unsigned int probe_resp_offloads;
+};
+
+
+struct hostapd_data;
+
+struct hostap_sta_driver_data {
+	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+	unsigned long current_tx_rate;
+	unsigned long inactive_msec;
+	unsigned long flags;
+	unsigned long num_ps_buf_frames;
+	unsigned long tx_retry_failed;
+	unsigned long tx_retry_count;
+	int last_rssi;
+	int last_ack_rssi;
+};
+
+struct hostapd_sta_add_params {
+	const u8 *addr;
+	u16 aid;
+	u16 capability;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	u16 listen_interval;
+	const struct ieee80211_ht_capabilities *ht_capabilities;
+	u32 flags; /* bitmask of WPA_STA_* flags */
+	int set; /* Set STA parameters instead of add */
+	u8 qosinfo;
+};
+
+struct hostapd_freq_params {
+	int mode;
+	int freq;
+	int channel;
+	int ht_enabled;
+	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+				 * secondary channel below primary, 1 = HT40
+				 * enabled, secondary channel above primary */
+};
+
+enum wpa_driver_if_type {
+	/**
+	 * WPA_IF_STATION - Station mode interface
+	 */
+	WPA_IF_STATION,
+
+	/**
+	 * WPA_IF_AP_VLAN - AP mode VLAN interface
+	 *
+	 * This interface shares its address and Beacon frame with the main
+	 * BSS.
+	 */
+	WPA_IF_AP_VLAN,
+
+	/**
+	 * WPA_IF_AP_BSS - AP mode BSS interface
+	 *
+	 * This interface has its own address and Beacon frame.
+	 */
+	WPA_IF_AP_BSS,
+
+	/**
+	 * WPA_IF_P2P_GO - P2P Group Owner
+	 */
+	WPA_IF_P2P_GO,
+
+	/**
+	 * WPA_IF_P2P_CLIENT - P2P Client
+	 */
+	WPA_IF_P2P_CLIENT,
+
+	/**
+	 * WPA_IF_P2P_GROUP - P2P Group interface (will become either
+	 * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
+	 */
+	WPA_IF_P2P_GROUP
+};
+
+struct wpa_init_params {
+	void *global_priv;
+	const u8 *bssid;
+	const char *ifname;
+	const u8 *ssid;
+	size_t ssid_len;
+	const char *test_socket;
+	int use_pae_group_addr;
+	char **bridge;
+	size_t num_bridge;
+
+	u8 *own_addr; /* buffer for writing own MAC address */
+};
+
+
+struct wpa_bss_params {
+	/** Interface name (for multi-SSID/VLAN support) */
+	const char *ifname;
+	/** Whether IEEE 802.1X or WPA/WPA2 is enabled */
+	int enabled;
+
+	int wpa;
+	int ieee802_1x;
+	int wpa_group;
+	int wpa_pairwise;
+	int wpa_key_mgmt;
+	int rsn_preauth;
+	enum mfp_options ieee80211w;
+};
+
+#define WPA_STA_AUTHORIZED BIT(0)
+#define WPA_STA_WMM BIT(1)
+#define WPA_STA_SHORT_PREAMBLE BIT(2)
+#define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
+
+/**
+ * struct p2p_params - P2P parameters for driver-based P2P management
+ */
+struct p2p_params {
+	const char *dev_name;
+	u8 pri_dev_type[8];
+#define DRV_MAX_SEC_DEV_TYPES 5
+	u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
+	size_t num_sec_dev_types;
+};
+
+enum tdls_oper {
+	TDLS_DISCOVERY_REQ,
+	TDLS_SETUP,
+	TDLS_TEARDOWN,
+	TDLS_ENABLE_LINK,
+	TDLS_DISABLE_LINK,
+	TDLS_ENABLE,
+	TDLS_DISABLE
+};
+
+enum wnm_oper {
+	WNM_SLEEP_ENTER_CONFIRM,
+	WNM_SLEEP_ENTER_FAIL,
+	WNM_SLEEP_EXIT_CONFIRM,
+	WNM_SLEEP_EXIT_FAIL,
+	WNM_SLEEP_TFS_REQ_IE_ADD,   /* STA requests driver to add TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_NONE,  /* STA requests empty TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_SET,   /* AP requests driver to set TFS req IE for
+				     * a STA */
+	WNM_SLEEP_TFS_RESP_IE_ADD,  /* AP requests driver to add TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+	WNM_SLEEP_TFS_RESP_IE_SET,  /* AP requests driver to set TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
+};
+
+/**
+ * struct wpa_signal_info - Information about channel signal quality
+ */
+struct wpa_signal_info {
+	u32 frequency;
+	int above_threshold;
+	int current_signal;
+	int current_noise;
+	int current_txrate;
+};
+
+/**
+ * struct wpa_driver_ops - Driver interface API definition
+ *
+ * This structure defines the API that each driver interface needs to implement
+ * for core wpa_supplicant code. All driver specific functionality is captured
+ * in this wrapper.
+ */
+struct wpa_driver_ops {
+	/** Name of the driver interface */
+	const char *name;
+	/** One line description of the driver interface */
+	const char *desc;
+
+	/**
+	 * get_bssid - Get the current BSSID
+	 * @priv: private driver interface data
+	 * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Query kernel driver for the current BSSID and copy it to bssid.
+	 * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
+	 * associated.
+	 */
+	int (*get_bssid)(void *priv, u8 *bssid);
+
+	/**
+	 * get_ssid - Get the current SSID
+	 * @priv: private driver interface data
+	 * @ssid: buffer for SSID (at least 32 bytes)
+	 *
+	 * Returns: Length of the SSID on success, -1 on failure
+	 *
+	 * Query kernel driver for the current SSID and copy it to ssid.
+	 * Returning zero is recommended if the STA is not associated.
+	 *
+	 * Note: SSID is an array of octets, i.e., it is not nul terminated and
+	 * can, at least in theory, contain control characters (including nul)
+	 * and as such, should be processed as binary data, not a printable
+	 * string.
+	 */
+	int (*get_ssid)(void *priv, u8 *ssid);
+
+	/**
+	 * set_key - Configure encryption key
+	 * @ifname: Interface name (for multi-SSID/VLAN support)
+	 * @priv: private driver interface data
+	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+	 *	%WPA_ALG_GCMP);
+	 *	%WPA_ALG_NONE clears the key.
+	 * @addr: Address of the peer STA (BSSID of the current AP when setting
+	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
+	 *	broadcast keys, %NULL for default keys that are used both for
+	 *	broadcast and unicast; when clearing keys, %NULL is used to
+	 *	indicate that both the broadcast-only and default key of the
+	 *	specified key index is to be cleared
+	 * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
+	 *	IGTK
+	 * @set_tx: configure this key as the default Tx key (only used when
+	 *	driver does not support separate unicast/individual key
+	 * @seq: sequence number/packet number, seq_len octets, the next
+	 *	packet number to be used for in replay protection; configured
+	 *	for Rx keys (in most cases, this is only used with broadcast
+	 *	keys and set to zero for unicast keys); %NULL if not set
+	 * @seq_len: length of the seq, depends on the algorithm:
+	 *	TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
+	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+	 *	8-byte Rx Mic Key
+	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
+	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure the given key for the kernel driver. If the driver
+	 * supports separate individual keys (4 default keys + 1 individual),
+	 * addr can be used to determine whether the key is default or
+	 * individual. If only 4 keys are supported, the default key with key
+	 * index 0 is used as the individual key. STA must be configured to use
+	 * it as the default Tx key (set_tx is set) and accept Rx for all the
+	 * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
+	 * broadcast keys, so key index 0 is available for this kind of
+	 * configuration.
+	 *
+	 * Please note that TKIP keys include separate TX and RX MIC keys and
+	 * some drivers may expect them in different order than wpa_supplicant
+	 * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
+	 * will trigger Michael MIC errors. This can be fixed by changing the
+	 * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+	 * in driver_*.c set_key() implementation, see driver_ndis.c for an
+	 * example on how this can be done.
+	 */
+	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
+		       const u8 *addr, int key_idx, int set_tx,
+		       const u8 *seq, size_t seq_len,
+		       const u8 *key, size_t key_len);
+
+	/**
+	 * init - Initialize driver interface
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 *
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * Initialize driver interface, including event processing for kernel
+	 * driver events (e.g., associated, scan results, Michael MIC failure).
+	 * This function can allocate a private configuration data area for
+	 * @ctx, file descriptor, interface name, etc. information that may be
+	 * needed in future driver operations. If this is not used, non-NULL
+	 * value will need to be returned because %NULL is used to indicate
+	 * failure. The returned value will be used as 'void *priv' data for
+	 * all other driver_ops functions.
+	 *
+	 * The main event loop (eloop.c) of wpa_supplicant can be used to
+	 * register callback for read sockets (eloop_register_read_sock()).
+	 *
+	 * See below for more information about events and
+	 * wpa_supplicant_event() function.
+	 */
+	void * (*init)(void *ctx, const char *ifname);
+
+	/**
+	 * deinit - Deinitialize driver interface
+	 * @priv: private driver interface data from init()
+	 *
+	 * Shut down driver interface and processing of driver events. Free
+	 * private data buffer if one was allocated in init() handler.
+	 */
+	void (*deinit)(void *priv);
+
+	/**
+	 * set_param - Set driver configuration parameters
+	 * @priv: private driver interface data from init()
+	 * @param: driver specific configuration parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Optional handler for notifying driver interface about configuration
+	 * parameters (driver_param).
+	 */
+	int (*set_param)(void *priv, const char *param);
+
+	/**
+	 * set_countermeasures - Enable/disable TKIP countermeasures
+	 * @priv: private driver interface data
+	 * @enabled: 1 = countermeasures enabled, 0 = disabled
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure TKIP countermeasures. When these are enabled, the driver
+	 * should drop all received and queued frames that are using TKIP.
+	 */
+	int (*set_countermeasures)(void *priv, int enabled);
+
+	/**
+	 * deauthenticate - Request driver to deauthenticate
+	 * @priv: private driver interface data
+	 * @addr: peer address (BSSID of the AP)
+	 * @reason_code: 16-bit reason code to be sent in the deauthentication
+	 *	frame
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
+
+	/**
+	 * associate - Request driver to associate
+	 * @priv: private driver interface data
+	 * @params: association parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*associate)(void *priv,
+			 struct wpa_driver_associate_params *params);
+
+	/**
+	 * add_pmkid - Add PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when a new PMK is received, as a result of
+	 * either normal authentication or RSN pre-authentication.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), add_pmkid() can be used to add new PMKSA cache entries
+	 * in the driver. If the driver uses wpa_ie from wpa_supplicant, this
+	 * driver_ops function does not need to be implemented. Likewise, if
+	 * the driver does not support WPA, this function is not needed.
+	 */
+	int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * remove_pmkid - Remove PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops a PMKSA cache
+	 * entry for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * flush_pmkid - Flush PMKSA cache
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops all PMKSA cache
+	 * entries for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*flush_pmkid)(void *priv);
+
+	/**
+	 * get_capa - Get driver capabilities
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Get driver/firmware/hardware capabilities.
+	 */
+	int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
+
+	/**
+	 * poll - Poll driver for association information
+	 * @priv: private driver interface data
+	 *
+	 * This is an option callback that can be used when the driver does not
+	 * provide event mechanism for association events. This is called when
+	 * receiving WPA EAPOL-Key messages that require association
+	 * information. The driver interface is supposed to generate associnfo
+	 * event before returning from this callback function. In addition, the
+	 * driver interface should generate an association event after having
+	 * sent out associnfo.
+	 */
+	void (*poll)(void *priv);
+
+	/**
+	 * get_ifname - Get interface name
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to the interface name. This can differ from the
+	 * interface name used in init() call. Init() is called first.
+	 *
+	 * This optional function can be used to allow the driver interface to
+	 * replace the interface name with something else, e.g., based on an
+	 * interface mapping from a more descriptive name.
+	 */
+	const char * (*get_ifname)(void *priv);
+
+	/**
+	 * get_mac_addr - Get own MAC address
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to own MAC address or %NULL on failure
+	 *
+	 * This optional function can be used to get the own MAC address of the
+	 * device from the driver interface code. This is only needed if the
+	 * l2_packet implementation for the OS does not provide easy access to
+	 * a MAC address. */
+	const u8 * (*get_mac_addr)(void *priv);
+
+	/**
+	 * send_eapol - Optional function for sending EAPOL packets
+	 * @priv: private driver interface data
+	 * @dest: Destination MAC address
+	 * @proto: Ethertype
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Size of the EAPOL packet
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional function can be used to override l2_packet operations
+	 * with driver specific functionality. If this function pointer is set,
+	 * l2_packet module is not used at all and the driver interface code is
+	 * responsible for receiving and sending all EAPOL packets. The
+	 * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
+	 * event. The driver interface is required to implement get_mac_addr()
+	 * handler if send_eapol() is used.
+	 */
+	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
+			  const u8 *data, size_t data_len);
+
+	/**
+	 * set_operstate - Sets device operating state to DORMANT or UP
+	 * @priv: private driver interface data
+	 * @state: 0 = dormant, 1 = up
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used on operating systems
+	 * that support a concept of controlling network device state from user
+	 * space applications. This function, if set, gets called with
+	 * state = 1 when authentication has been completed and with state = 0
+	 * when connection is lost.
+	 */
+	int (*set_operstate)(void *priv, int state);
+
+	/**
+	 * mlme_setprotection - MLME-SETPROTECTION.request primitive
+	 * @priv: Private driver interface data
+	 * @addr: Address of the station for which to set protection (may be
+	 * %NULL for group keys)
+	 * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
+	 * @key_type: MLME_SETPROTECTION_KEY_TYPE_*
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used to set the driver to
+	 * require protection for Tx and/or Rx frames. This uses the layer
+	 * interface defined in IEEE 802.11i-2004 clause 10.3.22.1
+	 * (MLME-SETPROTECTION.request). Many drivers do not use explicit
+	 * set protection operation; instead, they set protection implicitly
+	 * based on configured keys.
+	 */
+	int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type,
+				  int key_type);
+
+	/**
+	 * get_hw_feature_data - Get hardware support data (channels and rates)
+	 * @priv: Private driver interface data
+	 * @num_modes: Variable for returning the number of returned modes
+	 * flags: Variable for returning hardware feature flags
+	 * Returns: Pointer to allocated hardware data on success or %NULL on
+	 * failure. Caller is responsible for freeing this.
+	 */
+	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+							 u16 *num_modes,
+							 u16 *flags);
+
+	/**
+	 * send_mlme - Send management frame from MLME
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
+	 * @data_len: Size of the management frame
+	 * @noack: Do not wait for this frame to be acked (disable retries)
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+			 int noack);
+
+	/**
+	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
+	 * @priv: Private driver interface data
+	 * @md: Mobility domain (2 octets) (also included inside ies)
+	 * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to let the driver know that keying
+	 * material for FT is available and that the driver can use the
+	 * provided IEs in the next message in FT authentication sequence.
+	 *
+	 * This function is only needed for driver that support IEEE 802.11r
+	 * (Fast BSS Transition).
+	 */
+	int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies,
+			     size_t ies_len);
+
+	/**
+	 * send_ft_action - Send FT Action frame (IEEE 802.11r)
+	 * @priv: Private driver interface data
+	 * @action: Action field value
+	 * @target_ap: Target AP address
+	 * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to request the driver to transmit
+	 * an FT Action frame (action category 6) for over-the-DS fast BSS
+	 * transition.
+	 */
+	int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
+			      const u8 *ies, size_t ies_len);
+
+	/**
+	 * get_scan_results2 - Fetch the latest scan results
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Allocated buffer of scan results (caller is responsible for
+	 * freeing the data structure) on success, NULL on failure
+	 */
+	 struct wpa_scan_results * (*get_scan_results2)(void *priv);
+
+	/**
+	 * set_country - Set country
+	 * @priv: Private driver interface data
+	 * @alpha2: country to which to switch to
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is for drivers which support some form
+	 * of setting a regulatory domain.
+	 */
+	int (*set_country)(void *priv, const char *alpha2);
+
+	/**
+	 * global_init - Global driver initialization
+	 * Returns: Pointer to private data (global), %NULL on failure
+	 *
+	 * This optional function is called to initialize the driver wrapper
+	 * for global data, i.e., data that applies to all interfaces. If this
+	 * function is implemented, global_deinit() will also need to be
+	 * implemented to free the private data. The driver will also likely
+	 * use init2() function instead of init() to get the pointer to global
+	 * data available to per-interface initializer.
+	 */
+	void * (*global_init)(void);
+
+	/**
+	 * global_deinit - Global driver deinitialization
+	 * @priv: private driver global data from global_init()
+	 *
+	 * Terminate any global driver related functionality and free the
+	 * global data structure.
+	 */
+	void (*global_deinit)(void *priv);
+
+	/**
+	 * init2 - Initialize driver interface (with global data)
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function can be used instead of init() if the driver wrapper
+	 * uses global data.
+	 */
+	void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+
+	/**
+	 * get_interfaces - Get information about available interfaces
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Allocated buffer of interface information (caller is
+	 * responsible for freeing the data structure) on success, NULL on
+	 * failure
+	 */
+	struct wpa_interface_info * (*get_interfaces)(void *global_priv);
+
+	/**
+	 * scan2 - Request the driver to initiate scan
+	 * @priv: private driver interface data
+	 * @params: Scan parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Once the scan results are ready, the driver should report scan
+	 * results event for wpa_supplicant which will eventually request the
+	 * results with wpa_driver_get_scan_results2().
+	 */
+	int (*scan2)(void *priv, struct wpa_driver_scan_params *params);
+
+	/**
+	 * authenticate - Request driver to authenticate
+	 * @priv: private driver interface data
+	 * @params: authentication parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used with drivers that
+	 * support separate authentication and association steps, i.e., when
+	 * wpa_supplicant can act as the SME. If not implemented, associate()
+	 * function is expected to take care of IEEE 802.11 authentication,
+	 * too.
+	 */
+	int (*authenticate)(void *priv,
+			    struct wpa_driver_auth_params *params);
+
+	/**
+	 * set_ap - Set Beacon and Probe Response information for AP mode
+	 * @priv: Private driver interface data
+	 * @params: Parameters to use in AP mode
+	 *
+	 * This function is used to configure Beacon template and/or extra IEs
+	 * to add for Beacon and Probe Response frames for the driver in
+	 * AP mode. The driver is responsible for building the full Beacon
+	 * frame by concatenating the head part with TIM IE generated by the
+	 * driver/firmware and finishing with the tail part. Depending on the
+	 * driver architectue, this can be done either by using the full
+	 * template or the set of additional IEs (e.g., WPS and P2P IE).
+	 * Similarly, Probe Response processing depends on the driver design.
+	 * If the driver (or firmware) takes care of replying to Probe Request
+	 * frames, the extra IEs provided here needs to be added to the Probe
+	 * Response frames.
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
+
+	/**
+	 * hapd_init - Initialize driver interface (hostapd only)
+	 * @hapd: Pointer to hostapd context
+	 * @params: Configuration for the driver wrapper
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function is used instead of init() or init2() when the driver
+	 * wrapper is used with hostapd.
+	 */
+	void * (*hapd_init)(struct hostapd_data *hapd,
+			    struct wpa_init_params *params);
+
+	/**
+	 * hapd_deinit - Deinitialize driver interface (hostapd only)
+	 * @priv: Private driver interface data from hapd_init()
+	 */
+	void (*hapd_deinit)(void *priv);
+
+	/**
+	 * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
+	 * @priv: Private driver interface data
+	 * @params: BSS parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure the kernel driver to
+	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
+	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
+	 * always enabled and the driver uses set_ap() to set WPA/RSN IE
+	 * for Beacon frames.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
+
+	/**
+	 * set_privacy - Enable/disable privacy (AP only)
+	 * @priv: Private driver interface data
+	 * @enabled: 1 = privacy enabled, 0 = disabled
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure privacy field in the
+	 * kernel driver for Beacon frames. This can be left undefined (set to
+	 * %NULL) if the driver uses the Beacon template from set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_privacy)(void *priv, int enabled);
+
+	/**
+	 * get_seqnum - Fetch the current TSC/packet number (AP only)
+	 * @ifname: The interface name (main or virtual)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station or %NULL for group keys
+	 * @idx: Key index
+	 * @seq: Buffer for returning the latest used TSC/packet number
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to fetch the last used TSC/packet number for
+	 * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group
+	 * keys, so there is no strict requirement on implementing support for
+	 * unicast keys (i.e., addr != %NULL).
+	 */
+	int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+			  int idx, u8 *seq);
+
+	/**
+	 * flush - Flush all association stations (AP only)
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests the driver to disassociate all associated
+	 * stations. This function does not need to be implemented if the
+	 * driver does not process association frames internally.
+	 */
+	int (*flush)(void *priv);
+
+	/**
+	 * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP)
+	 * @priv: Private driver interface data
+	 * @elem: Information elements
+	 * @elem_len: Length of the elem buffer in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to add information elements in the
+	 * kernel driver for Beacon and Probe Response frames. This can be left
+	 * undefined (set to %NULL) if the driver uses the Beacon template from
+	 * set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+
+	/**
+	 * read_sta_data - Fetch station data
+	 * @priv: Private driver interface data
+	 * @data: Buffer for returning station information
+	 * @addr: MAC address of the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
+			     const u8 *addr);
+
+	/**
+	 * hapd_send_eapol - Send an EAPOL packet (AP only)
+	 * @priv: private driver interface data
+	 * @addr: Destination MAC address
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Length of the EAPOL packet in octets
+	 * @encrypt: Whether the frame should be encrypted
+	 * @own_addr: Source MAC address
+	 * @flags: WPA_STA_* flags for the destination station
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
+			       size_t data_len, int encrypt,
+			       const u8 *own_addr, u32 flags);
+
+	/**
+	 * sta_deauth - Deauthenticate a station (AP only)
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for the Deauthentication frame
+	 * @addr: MAC address of the station to deauthenticate
+	 * @reason: Reason code for the Deauthentiation frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests a specific station to be deauthenticated and
+	 * a Deauthentication frame to be sent to it.
+	 */
+	int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reason);
+
+	/**
+	 * sta_disassoc - Disassociate a station (AP only)
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for the Disassociation frame
+	 * @addr: MAC address of the station to disassociate
+	 * @reason: Reason code for the Disassociation frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests a specific station to be disassociated and
+	 * a Disassociation frame to be sent to it.
+	 */
+	int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			    int reason);
+
+	/**
+	 * sta_remove - Remove a station entry (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to be removed
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_remove)(void *priv, const u8 *addr);
+
+	/**
+	 * hapd_get_ssid - Get the current SSID (AP only)
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for returning the SSID
+	 * @len: Maximum length of the buffer
+	 * Returns: Length of the SSID on success, -1 on failure
+	 *
+	 * This function need not be implemented if the driver uses Beacon
+	 * template from set_ap() and does not reply to Probe Request frames.
+	 */
+	int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
+
+	/**
+	 * hapd_set_ssid - Set SSID (AP only)
+	 * @priv: Private driver interface data
+	 * @buf: SSID
+	 * @len: Length of the SSID in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
+
+	/**
+	 * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP)
+	 * @priv: Private driver interface data
+	 * @enabled: 1 = countermeasures enabled, 0 = disabled
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This need not be implemented if the driver does not take care of
+	 * association processing.
+	 */
+	int (*hapd_set_countermeasures)(void *priv, int enabled);
+
+	/**
+	 * sta_add - Add a station entry
+	 * @priv: Private driver interface data
+	 * @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
+	 * does not take care of association processing.
+	 *
+	 * With TDLS, this function is also used to add or set (params->set 1)
+	 * TDLS peer entries.
+	 */
+	int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
+
+	/**
+	 * get_inact_sec - Get station inactivity duration (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * Returns: Number of seconds station has been inactive, -1 on failure
+	 */
+	int (*get_inact_sec)(void *priv, const u8 *addr);
+
+	/**
+	 * sta_clear_stats - Clear station statistics (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+	/**
+	 * set_freq - Set channel/frequency (AP only)
+	 * @priv: Private driver interface data
+	 * @freq: Channel parameters
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_freq)(void *priv, struct hostapd_freq_params *freq);
+
+	/**
+	 * set_rts - Set RTS threshold
+	 * @priv: Private driver interface data
+	 * @rts: RTS threshold in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_rts)(void *priv, int rts);
+
+	/**
+	 * set_frag - Set fragmentation threshold
+	 * @priv: Private driver interface data
+	 * @frag: Fragmentation threshold in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_frag)(void *priv, int frag);
+
+	/**
+	 * sta_set_flags - Set station flags (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * @total_flags: Bitmap of all WPA_STA_* flags currently set
+	 * @flags_or: Bitmap of WPA_STA_* flags to add
+	 * @flags_and: Bitmap of WPA_STA_* flags to us as a mask
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_set_flags)(void *priv, const u8 *addr,
+			     int total_flags, int flags_or, int flags_and);
+
+	/**
+	 * set_tx_queue_params - Set TX queue parameters
+	 * @priv: Private driver interface data
+	 * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
+	 * @aifs: AIFS
+	 * @cw_min: cwMin
+	 * @cw_max: cwMax
+	 * @burst_time: Maximum length for bursting in 0.1 msec units
+	 */
+	int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+				   int cw_max, int burst_time);
+
+	/**
+	 * if_add - Add a virtual interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type
+	 * @ifname: Interface name for the new virtual interface
+	 * @addr: Local address to use for the interface or %NULL to use the
+	 *	parent interface address
+	 * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
+	 * @drv_priv: Pointer for overwriting the driver context or %NULL if
+	 *	not allowed (applies only to %WPA_IF_AP_BSS type)
+	 * @force_ifname: Buffer for returning an interface name that the
+	 *	driver ended up using if it differs from the requested ifname
+	 * @if_addr: Buffer for returning the allocated interface address
+	 *	(this may differ from the requested addr if the driver cannot
+	 *	change interface address)
+	 * @bridge: Bridge interface to use or %NULL if no bridge configured
+	 * 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);
+
+	/**
+	 * if_remove - Remove a virtual interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type
+	 * @ifname: Interface name of the virtual interface to be removed
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*if_remove)(void *priv, enum wpa_driver_if_type type,
+			 const char *ifname);
+
+	/**
+	 * set_sta_vlan - Bind a station into a specific interface (AP only)
+	 * @priv: Private driver interface data
+	 * @ifname: Interface (main or virtual BSS or VLAN)
+	 * @addr: MAC address of the associated station
+	 * @vlan_id: VLAN ID
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to bind a station to a specific virtual
+	 * interface. It is only used if when virtual interfaces are supported,
+	 * e.g., to assign stations to different VLAN interfaces based on
+	 * information from a RADIUS server. This allows separate broadcast
+	 * domains to be used with a single BSS.
+	 */
+	int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+			    int vlan_id);
+
+	/**
+	 * commit - Optional commit changes handler (AP only)
+	 * @priv: driver private data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional handler function can be registered if the driver
+	 * interface implementation needs to commit changes (e.g., by setting
+	 * network interface up) at the end of initial configuration. If set,
+	 * this handler will be called after initial setup has been completed.
+	 */
+	int (*commit)(void *priv);
+
+	/**
+	 * send_ether - Send an ethernet packet (AP only)
+	 * @priv: private driver interface data
+	 * @dst: Destination MAC address
+	 * @src: Source MAC address
+	 * @proto: Ethertype
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Length of the EAPOL packet in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
+			  const u8 *data, size_t data_len);
+
+	/**
+	 * set_radius_acl_auth - Notification of RADIUS ACL change
+	 * @priv: Private driver interface data
+	 * @mac: MAC address of the station
+	 * @accepted: Whether the station was accepted
+	 * @session_timeout: Session timeout for the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, 
+				   u32 session_timeout);
+
+	/**
+	 * set_radius_acl_expire - Notification of RADIUS ACL expiration
+	 * @priv: Private driver interface data
+	 * @mac: MAC address of the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_radius_acl_expire)(void *priv, const u8 *mac);
+
+	/**
+	 * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
+	 * @priv: Private driver interface data
+	 * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
+	 * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove
+	 *	extra IE(s)
+	 * @assocresp: WPS IE(s) for (Re)Association Response frames or %NULL
+	 *	to remove extra IE(s)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to add WPS IE in the kernel driver for
+	 * Beacon and Probe Response frames. This can be left undefined (set
+	 * to %NULL) if the driver uses the Beacon template from set_ap()
+	 * and does not process Probe Request frames. If the driver takes care
+	 * of (Re)Association frame processing, the assocresp buffer includes
+	 * WPS IE(s) that need to be added to (Re)Association Response frames
+	 * whenever a (Re)Association Request frame indicated use of WPS.
+	 *
+	 * This will also be used to add P2P IE(s) into Beacon/Probe Response
+	 * frames when operating as a GO. The driver is responsible for adding
+	 * timing related attributes (e.g., NoA) in addition to the IEs
+	 * included here by appending them after these buffers. This call is
+	 * also used to provide Probe Response IEs for P2P Listen state
+	 * operations for drivers that generate the Probe Response frames
+	 * internally.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
+			     const struct wpabuf *proberesp,
+			     const struct wpabuf *assocresp);
+
+	/**
+	 * set_supp_port - Set IEEE 802.1X Supplicant Port status
+	 * @priv: Private driver interface data
+	 * @authorized: Whether the port is authorized
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_supp_port)(void *priv, int authorized);
+
+	/**
+	 * set_wds_sta - Bind a station into a 4-address WDS (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the associated station
+	 * @aid: Association ID
+	 * @val: 1 = bind to 4-address WDS; 0 = unbind
+	 * @bridge_ifname: Bridge interface to use for the WDS station or %NULL
+	 *	to indicate that bridge is not to be used
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
+	                   const char *bridge_ifname);
+
+	/**
+	 * send_action - Transmit an Action frame
+	 * @priv: Private driver interface data
+	 * @freq: Frequency (in MHz) of the channel
+	 * @wait: Time to wait off-channel for a response (in ms), or zero
+	 * @dst: Destination MAC address (Address 1)
+	 * @src: Source MAC address (Address 2)
+	 * @bssid: BSSID (Address 3)
+	 * @data: Frame body
+	 * @data_len: data length in octets
+	 @ @no_cck: Whether CCK rates must not be used to transmit this frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This command can be used to request the driver to transmit an action
+	 * frame to the specified destination.
+	 *
+	 * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
+	 * be transmitted on the given channel and the device will wait for a
+	 * response on that channel for the given wait time.
+	 *
+	 * If the flag is not set, the wait time will be ignored. In this case,
+	 * if a remain-on-channel duration is in progress, the frame must be
+	 * transmitted on that channel; alternatively the frame may be sent on
+	 * the current operational channel (if in associated state in station
+	 * mode or while operating as an AP.)
+	 */
+	int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *data, size_t data_len, int no_cck);
+
+	/**
+	 * send_action_cancel_wait - Cancel action frame TX wait
+	 * @priv: Private driver interface data
+	 *
+	 * This command cancels the wait time associated with sending an action
+	 * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is
+	 * set in the driver flags.
+	 */
+	void (*send_action_cancel_wait)(void *priv);
+
+	/**
+	 * remain_on_channel - Remain awake on a channel
+	 * @priv: Private driver interface data
+	 * @freq: Frequency (in MHz) of the channel
+	 * @duration: Duration in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This command is used to request the driver to remain awake on the
+	 * specified channel for the specified duration and report received
+	 * Action frames with EVENT_RX_ACTION events. Optionally, received
+	 * Probe Request frames may also be requested to be reported by calling
+	 * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
+	 *
+	 * The driver may not be at the requested channel when this function
+	 * returns, i.e., the return code is only indicating whether the
+	 * request was accepted. The caller will need to wait until the
+	 * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has
+	 * completed the channel change. This may take some time due to other
+	 * need for the radio and the caller should be prepared to timing out
+	 * its wait since there are no guarantees on when this request can be
+	 * executed.
+	 */
+	int (*remain_on_channel)(void *priv, unsigned int freq,
+				 unsigned int duration);
+
+	/**
+	 * cancel_remain_on_channel - Cancel remain-on-channel operation
+	 * @priv: Private driver interface data
+	 *
+	 * This command can be used to cancel a remain-on-channel operation
+	 * before its originally requested duration has passed. This could be
+	 * used, e.g., when remain_on_channel() is used to request extra time
+	 * to receive a response to an Action frame and the response is
+	 * received when there is still unneeded time remaining on the
+	 * remain-on-channel operation.
+	 */
+	int (*cancel_remain_on_channel)(void *priv);
+
+	/**
+	 * probe_req_report - Request Probe Request frames to be indicated
+	 * @priv: Private driver interface data
+	 * @report: Whether to report received Probe Request frames
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This command can be used to request the driver to indicate when
+	 * Probe Request frames are received with EVENT_RX_PROBE_REQ events.
+	 * Since this operation may require extra resources, e.g., due to less
+	 * optimal hardware/firmware RX filtering, many drivers may disable
+	 * Probe Request reporting at least in station mode. This command is
+	 * used to notify the driver when the Probe Request frames need to be
+	 * reported, e.g., during remain-on-channel operations.
+	 */
+	int (*probe_req_report)(void *priv, int report);
+
+	/**
+	 * deinit_ap - Deinitialize AP mode
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This optional function can be used to disable AP mode related
+	 * configuration and change the driver mode to station mode to allow
+	 * normal station operations like scanning to be completed.
+	 */
+	int (*deinit_ap)(void *priv);
+
+	/**
+	 * deinit_p2p_cli - Deinitialize P2P client mode
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This optional function can be used to disable P2P client mode. It
+	 * can be used to change the interface type back to station mode.
+	 */
+	int (*deinit_p2p_cli)(void *priv);
+
+	/**
+	 * suspend - Notification on system suspend/hibernate event
+	 * @priv: Private driver interface data
+	 */
+	void (*suspend)(void *priv);
+
+	/**
+	 * resume - Notification on system resume/thaw event
+	 * @priv: Private driver interface data
+	 */
+	void (*resume)(void *priv);
+
+	/**
+	 * signal_monitor - Set signal monitoring parameters
+	 * @priv: Private driver interface data
+	 * @threshold: Threshold value for signal change events; 0 = disabled
+	 * @hysteresis: Minimum change in signal strength before indicating a
+	 *	new event
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This function can be used to configure monitoring of signal strength
+	 * with the current AP. Whenever signal strength drops below the
+	 * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event
+	 * should be generated assuming the signal strength has changed at
+	 * least %hysteresis from the previously indicated signal change event.
+	 */
+	int (*signal_monitor)(void *priv, int threshold, int hysteresis);
+
+	/**
+	 * send_frame - Send IEEE 802.11 frame (testing use only)
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 frame with IEEE 802.11 header
+	 * @data_len: Size of the frame
+	 * @encrypt: Whether to encrypt the frame (if keys are set)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used for debugging purposes and is not
+	 * required to be implemented for normal operations.
+	 */
+	int (*send_frame)(void *priv, const u8 *data, size_t data_len,
+			  int encrypt);
+
+	/**
+	 * shared_freq - Get operating frequency of shared interface(s)
+	 * @priv: Private driver interface data
+	 * Returns: Operating frequency in MHz, 0 if no shared operation in
+	 * use, or -1 on failure
+	 *
+	 * This command can be used to request the current operating frequency
+	 * of any virtual interface that shares the same radio to provide
+	 * information for channel selection for other virtual interfaces.
+	 */
+	int (*shared_freq)(void *priv);
+
+	/**
+	 * get_noa - Get current Notice of Absence attribute payload
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for returning NoA
+	 * @buf_len: Buffer length in octets
+	 * Returns: Number of octets used in buf, 0 to indicate no NoA is being
+	 * advertized, or -1 on failure
+	 *
+	 * This function is used to fetch the current Notice of Absence
+	 * attribute value from GO.
+	 */
+	int (*get_noa)(void *priv, u8 *buf, size_t buf_len);
+
+	/**
+	 * set_noa - Set Notice of Absence parameters for GO (testing)
+	 * @priv: Private driver interface data
+	 * @count: Count
+	 * @start: Start time in ms from next TBTT
+	 * @duration: Duration in ms
+	 * Returns: 0 on success or -1 on failure
+	 *
+	 * This function is used to set Notice of Absence parameters for GO. It
+	 * is used only for testing. To disable NoA, all parameters are set to
+	 * 0.
+	 */
+	int (*set_noa)(void *priv, u8 count, int start, int duration);
+
+	/**
+	 * set_p2p_powersave - Set P2P power save options
+	 * @priv: Private driver interface data
+	 * @legacy_ps: 0 = disable, 1 = enable, 2 = maximum PS, -1 = no change
+	 * @opp_ps: 0 = disable, 1 = enable, -1 = no change
+	 * @ctwindow: 0.. = change (msec), -1 = no change
+	 * Returns: 0 on success or -1 on failure
+	 */
+	int (*set_p2p_powersave)(void *priv, int legacy_ps, int opp_ps,
+				 int ctwindow);
+
+	/**
+	 * ampdu - Enable/disable aggregation
+	 * @priv: Private driver interface data
+	 * @ampdu: 1/0 = enable/disable A-MPDU aggregation
+	 * Returns: 0 on success or -1 on failure
+	 */
+	int (*ampdu)(void *priv, int ampdu);
+
+	/**
+	 * get_radio_name - Get physical radio name for the device
+	 * @priv: Private driver interface data
+	 * Returns: Radio name or %NULL if not known
+	 *
+	 * The returned data must not be modified by the caller. It is assumed
+	 * that any interface that has the same radio name as another is
+	 * sharing the same physical radio. This information can be used to
+	 * share scan results etc. information between the virtual interfaces
+	 * to speed up various operations.
+	 */
+	const char * (*get_radio_name)(void *priv);
+
+	/**
+	 * p2p_find - Start P2P Device Discovery
+	 * @priv: Private driver interface data
+	 * @timeout: Timeout for find operation in seconds or 0 for no timeout
+	 * @type: Device Discovery type (enum p2p_discovery_type)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_find)(void *priv, unsigned int timeout, int type);
+
+	/**
+	 * p2p_stop_find - Stop P2P Device Discovery
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_stop_find)(void *priv);
+
+	/**
+	 * p2p_listen - Start P2P Listen state for specified duration
+	 * @priv: Private driver interface data
+	 * @timeout: Listen state duration in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to request the P2P module to keep the
+	 * device discoverable on the listen channel for an extended set of
+	 * time. At least in its current form, this is mainly used for testing
+	 * purposes and may not be of much use for normal P2P operations.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_listen)(void *priv, unsigned int timeout);
+
+	/**
+	 * p2p_connect - Start P2P group formation (GO negotiation)
+	 * @priv: Private driver interface data
+	 * @peer_addr: MAC address of the peer P2P client
+	 * @wps_method: enum p2p_wps_method value indicating config method
+	 * @go_intent: Local GO intent value (1..15)
+	 * @own_interface_addr: Intended interface address to use with the
+	 *	group
+	 * @force_freq: The only allowed channel frequency in MHz or 0
+	 * @persistent_group: Whether to create persistent group
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method,
+			   int go_intent, const u8 *own_interface_addr,
+			   unsigned int force_freq, int persistent_group);
+
+	/**
+	 * wps_success_cb - Report successfully completed WPS provisioning
+	 * @priv: Private driver interface data
+	 * @peer_addr: Peer address
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to report successfully completed WPS
+	 * provisioning during group formation in both GO/Registrar and
+	 * client/Enrollee roles.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*wps_success_cb)(void *priv, const u8 *peer_addr);
+
+	/**
+	 * p2p_group_formation_failed - Report failed WPS provisioning
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to report failed group formation. This can
+	 * happen either due to failed WPS provisioning or due to 15 second
+	 * timeout during the provisioning phase.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_group_formation_failed)(void *priv);
+
+	/**
+	 * p2p_set_params - Set P2P parameters
+	 * @priv: Private driver interface data
+	 * @params: P2P parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_set_params)(void *priv, const struct p2p_params *params);
+
+	/**
+	 * p2p_prov_disc_req - Send Provision Discovery Request
+	 * @priv: Private driver interface data
+	 * @peer_addr: MAC address of the peer P2P client
+	 * @config_methods: WPS Config Methods value (only one bit set)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to request a discovered P2P peer to
+	 * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared
+	 * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The
+	 * Provision Discovery Request frame is transmitted once immediately
+	 * and if no response is received, the frame will be sent again
+	 * whenever the target device is discovered during device dsicovery
+	 * (start with a p2p_find() call). Response from the peer is indicated
+	 * with the EVENT_P2P_PROV_DISC_RESPONSE event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
+				 u16 config_methods, int join);
+
+	/**
+	 * p2p_sd_request - Schedule a service discovery query
+	 * @priv: Private driver interface data
+	 * @dst: Destination peer or %NULL to apply for all peers
+	 * @tlvs: P2P Service Query TLV(s)
+	 * Returns: Reference to the query or 0 on failure
+	 *
+	 * Response to the query is indicated with the
+	 * EVENT_P2P_SD_RESPONSE driver event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	u64 (*p2p_sd_request)(void *priv, const u8 *dst,
+			      const struct wpabuf *tlvs);
+
+	/**
+	 * p2p_sd_cancel_request - Cancel a pending service discovery query
+	 * @priv: Private driver interface data
+	 * @req: Query reference from p2p_sd_request()
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_sd_cancel_request)(void *priv, u64 req);
+
+	/**
+	 * p2p_sd_response - Send response to a service discovery query
+	 * @priv: Private driver interface data
+	 * @freq: Frequency from EVENT_P2P_SD_REQUEST event
+	 * @dst: Destination address from EVENT_P2P_SD_REQUEST event
+	 * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event
+	 * @resp_tlvs: P2P Service Response TLV(s)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called as a response to the request indicated with
+	 * the EVENT_P2P_SD_REQUEST driver event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_sd_response)(void *priv, int freq, const u8 *dst,
+			       u8 dialog_token,
+			       const struct wpabuf *resp_tlvs);
+
+	/**
+	 * p2p_service_update - Indicate a change in local services
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function needs to be called whenever there is a change in
+	 * availability of the local services. This will increment the
+	 * Service Update Indicator value which will be used in SD Request and
+	 * Response frames.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_service_update)(void *priv);
+
+	/**
+	 * p2p_reject - Reject peer device (explicitly block connections)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the peer
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*p2p_reject)(void *priv, const u8 *addr);
+
+	/**
+	 * p2p_invite - Invite a P2P Device into a group
+	 * @priv: Private driver interface data
+	 * @peer: Device Address of the peer P2P Device
+	 * @role: Local role in the group
+	 * @bssid: Group BSSID or %NULL if not known
+	 * @ssid: Group SSID
+	 * @ssid_len: Length of ssid in octets
+	 * @go_dev_addr: Forced GO Device Address or %NULL if none
+	 * @persistent_group: Whether this is to reinvoke a persistent group
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*p2p_invite)(void *priv, const u8 *peer, int role,
+			  const u8 *bssid, const u8 *ssid, size_t ssid_len,
+			  const u8 *go_dev_addr, int persistent_group);
+
+	/**
+	 * send_tdls_mgmt - for sending TDLS management packets
+	 * @priv: private driver interface data
+	 * @dst: Destination (peer) MAC address
+	 * @action_code: TDLS action code for the mssage
+	 * @dialog_token: Dialog Token to use in the message (if needed)
+	 * @status_code: Status Code or Reason Code to use (if needed)
+	 * @buf: TDLS IEs to add to the message
+	 * @len: Length of buf in octets
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send packet to driver which is
+	 * responsible for receiving and sending all TDLS packets.
+	 */
+	int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
+			      u8 dialog_token, u16 status_code,
+			      const u8 *buf, size_t len);
+
+	/**
+	 * tdls_oper - Ask the driver to perform high-level TDLS operations
+	 * @priv: Private driver interface data
+	 * @oper: TDLS high-level operation. See %enum tdls_oper
+	 * @peer: Destination (peer) MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send high-level TDLS commands
+	 * to the driver.
+	 */
+	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
+
+	/**
+	 * wnm_oper - Notify driver of the WNM frame reception
+	 * @priv: Private driver interface data
+	 * @oper: WNM operation. See %enum wnm_oper
+	 * @peer: Destination (peer) MAC address
+	 * @buf: Buffer for the driver to fill in (for getting IE)
+	 * @buf_len: Return the len of buf
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer,
+			u8 *buf, u16 *buf_len);
+
+	/**
+	 * signal_poll - Get current connection information
+	 * @priv: Private driver interface data
+	 * @signal_info: Connection info structure
+         */
+	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
+
+	/**
+	 * set_authmode - Set authentication algorithm(s) for static WEP
+	 * @priv: Private driver interface data
+	 * @authmode: 1=Open System, 2=Shared Key, 3=both
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to set authentication algorithms for AP
+	 * mode when static WEP is used. If the driver uses user space MLME/SME
+	 * implementation, there is no need to implement this function.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_authmode)(void *priv, int authmode);
+
+	/**
+	 * set_rekey_info - Set rekey information
+	 * @priv: Private driver interface data
+	 * @kek: Current KEK
+	 * @kck: Current KCK
+	 * @replay_ctr: Current EAPOL-Key Replay Counter
+	 *
+	 * This optional function can be used to provide information for the
+	 * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+	 * while the host (including wpa_supplicant) is sleeping.
+	 */
+	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+			       const u8 *replay_ctr);
+
+	/**
+	 * sta_assoc - Station association indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for association frame
+	 * @addr: MAC address of the station to associate
+	 * @reassoc: flag to indicate re-association
+	 * @status: association response status code
+	 * @ie: assoc response ie buffer
+	 * @len: ie buffer length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates the driver to send (Re)Association
+	 * Response frame to the station.
+	 */
+	 int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reassoc, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * sta_auth - Station authentication indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for authentication frame
+	 * @addr: MAC address of the station to associate
+	 * @seq: authentication sequence number
+	 * @status: authentication response status code
+	 * @ie: authentication frame ie buffer
+	 * @len: ie buffer length
+	 *
+	 * This function indicates the driver to send Authentication frame
+	 * to the station.
+	 */
+	 int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+			 u16 seq, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * add_tspec - Add traffic stream
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to associate
+	 * @tspec_ie: tspec ie buffer
+	 * @tspec_ielen: tspec ie length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the traffic steam for the station
+	 * and fills the medium_time in tspec_ie.
+	 */
+	 int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+			  size_t tspec_ielen);
+
+	/**
+	 * add_sta_node - Add a station node in the driver
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to add
+	 * @auth_alg: authentication algorithm used by the station
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the station node in the driver, when
+	 * the station gets added by FT-over-DS.
+	 */
+	int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+	/**
+	 * 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
+	 * the hardware. Every time scan results are available, the
+	 * driver should report scan results event for wpa_supplicant
+	 * which will eventually request the results with
+	 * wpa_driver_get_scan_results2(). This operation is optional
+	 * 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);
+
+	/**
+	 * stop_sched_scan - Request the driver to stop a scheduled scan
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This should cause the scheduled scan to be stopped and
+	 * results should stop being sent. Must be supported if
+	 * sched_scan is supported.
+	 */
+	int (*stop_sched_scan)(void *priv);
+
+	/**
+	 * poll_client - Probe (null data or such) the given station
+	 * @priv: Private driver interface data
+	 * @own_addr: MAC address of sending interface
+	 * @addr: MAC address of the station to probe
+	 * @qos: Indicates whether station is QoS station
+	 *
+	 * This function is used to verify whether an associated station is
+	 * still present. This function does not need to be implemented if the
+	 * driver provides such inactivity polling mechanism.
+	 */
+	void (*poll_client)(void *priv, const u8 *own_addr,
+			    const u8 *addr, int qos);
+
+	/**
+	 * radio_disable - Disable/enable radio
+	 * @priv: Private driver interface data
+	 * @disabled: 1=disable 0=enable radio
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional command is for testing purposes. It can be used to
+	 * disable the radio on a testbed device to simulate out-of-radio-range
+	 * conditions.
+	 */
+	int (*radio_disable)(void *priv, int disabled);
+
+	/**
+	 * switch_channel - Announce channel switch and migrate the GO to the
+	 * given frequency
+	 * @priv: Private driver interface data
+	 * @freq: Frequency in MHz
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to move the GO to the legacy STA channel to
+	 * avoid frequency conflict in single channel concurrency.
+	 */
+	int (*switch_channel)(void *priv, unsigned int freq);
+};
+
+
+/**
+ * enum wpa_event_type - Event type for wpa_supplicant_event() calls
+ */
+enum wpa_event_type {
+	/**
+	 * EVENT_ASSOC - Association completed
+	 *
+	 * This event needs to be delivered when the driver completes IEEE
+	 * 802.11 association or reassociation successfully.
+	 * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
+	 * after this event has been generated. In addition, optional
+	 * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
+	 * more information about the association. If the driver interface gets
+	 * both of these events at the same time, it can also include the
+	 * assoc_info data in EVENT_ASSOC call.
+	 */
+	EVENT_ASSOC,
+
+	/**
+	 * EVENT_DISASSOC - Association lost
+	 *
+	 * This event should be called when association is lost either due to
+	 * receiving deauthenticate or disassociate frame from the AP or when
+	 * sending either of these frames to the current AP. If the driver
+	 * supports separate deauthentication event, EVENT_DISASSOC should only
+	 * be used for disassociation and EVENT_DEAUTH for deauthentication.
+	 * In AP mode, union wpa_event_data::disassoc_info is required.
+	 */
+	EVENT_DISASSOC,
+
+	/**
+	 * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected
+	 *
+	 * This event must be delivered when a Michael MIC error is detected by
+	 * the local driver. Additional data for event processing is
+	 * provided with union wpa_event_data::michael_mic_failure. This
+	 * information is used to request new encyption key and to initiate
+	 * TKIP countermeasures if needed.
+	 */
+	EVENT_MICHAEL_MIC_FAILURE,
+
+	/**
+	 * EVENT_SCAN_RESULTS - Scan results available
+	 *
+	 * This event must be called whenever scan results are available to be
+	 * fetched with struct wpa_driver_ops::get_scan_results(). This event
+	 * is expected to be used some time after struct wpa_driver_ops::scan()
+	 * is called. If the driver provides an unsolicited event when the scan
+	 * has been completed, this event can be used to trigger
+	 * EVENT_SCAN_RESULTS call. If such event is not available from the
+	 * driver, the driver wrapper code is expected to use a registered
+	 * timeout to generate EVENT_SCAN_RESULTS call after the time that the
+	 * scan is expected to be completed. Optional information about
+	 * completed scan can be provided with union wpa_event_data::scan_info.
+	 */
+	EVENT_SCAN_RESULTS,
+
+	/**
+	 * EVENT_ASSOCINFO - Report optional extra information for association
+	 *
+	 * This event can be used to report extra association information for
+	 * EVENT_ASSOC processing. This extra information includes IEs from
+	 * association frames and Beacon/Probe Response frames in union
+	 * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before
+	 * EVENT_ASSOC. Alternatively, the driver interface can include
+	 * assoc_info data in the EVENT_ASSOC call if it has all the
+	 * information available at the same point.
+	 */
+	EVENT_ASSOCINFO,
+
+	/**
+	 * EVENT_INTERFACE_STATUS - Report interface status changes
+	 *
+	 * This optional event can be used to report changes in interface
+	 * status (interface added/removed) using union
+	 * wpa_event_data::interface_status. This can be used to trigger
+	 * wpa_supplicant to stop and re-start processing for the interface,
+	 * e.g., when a cardbus card is ejected/inserted.
+	 */
+	EVENT_INTERFACE_STATUS,
+
+	/**
+	 * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication
+	 *
+	 * This event can be used to inform wpa_supplicant about candidates for
+	 * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible
+	 * for scan request (ap_scan=2 mode), this event is required for
+	 * pre-authentication. If wpa_supplicant is performing scan request
+	 * (ap_scan=1), this event is optional since scan results can be used
+	 * to add pre-authentication candidates. union
+	 * wpa_event_data::pmkid_candidate is used to report the BSSID of the
+	 * candidate and priority of the candidate, e.g., based on the signal
+	 * strength, in order to try to pre-authenticate first with candidates
+	 * that are most likely targets for re-association.
+	 *
+	 * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates
+	 * on the candidate list. In addition, it can be called for the current
+	 * AP and APs that have existing PMKSA cache entries. wpa_supplicant
+	 * will automatically skip pre-authentication in cases where a valid
+	 * PMKSA exists. When more than one candidate exists, this event should
+	 * be generated once for each candidate.
+	 *
+	 * Driver will be notified about successful pre-authentication with
+	 * struct wpa_driver_ops::add_pmkid() calls.
+	 */
+	EVENT_PMKID_CANDIDATE,
+
+	/**
+	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
+	 *
+	 * This event can be used to inform wpa_supplicant about desire to set
+	 * up secure direct link connection between two stations as defined in
+	 * IEEE 802.11e with a new PeerKey mechanism that replaced the original
+	 * STAKey negotiation. The caller will need to set peer address for the
+	 * event.
+	 */
+	EVENT_STKSTART,
+
+	/**
+	 * EVENT_TDLS - Request TDLS operation
+	 *
+	 * This event can be used to request a TDLS operation to be performed.
+	 */
+	EVENT_TDLS,
+
+	/**
+	 * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs
+	 *
+	 * The driver is expected to report the received FT IEs from
+	 * FT authentication sequence from the AP. The FT IEs are included in
+	 * the extra information in union wpa_event_data::ft_ies.
+	 */
+	EVENT_FT_RESPONSE,
+
+	/**
+	 * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS
+	 *
+	 * The driver can use this event to inform wpa_supplicant about a STA
+	 * in an IBSS with which protected frames could be exchanged. This
+	 * event starts RSN authentication with the other STA to authenticate
+	 * the STA and set up encryption keys with it.
+	 */
+	EVENT_IBSS_RSN_START,
+
+	/**
+	 * EVENT_AUTH - Authentication result
+	 *
+	 * This event should be called when authentication attempt has been
+	 * completed. This is only used if the driver supports separate
+	 * authentication step (struct wpa_driver_ops::authenticate).
+	 * Information about authentication result is included in
+	 * union wpa_event_data::auth.
+	 */
+	EVENT_AUTH,
+
+	/**
+	 * EVENT_DEAUTH - Authentication lost
+	 *
+	 * This event should be called when authentication is lost either due
+	 * to receiving deauthenticate frame from the AP or when sending that
+	 * frame to the current AP.
+	 * In AP mode, union wpa_event_data::deauth_info is required.
+	 */
+	EVENT_DEAUTH,
+
+	/**
+	 * EVENT_ASSOC_REJECT - Association rejected
+	 *
+	 * This event should be called when (re)association attempt has been
+	 * rejected by the AP. Information about the association response is
+	 * included in union wpa_event_data::assoc_reject.
+	 */
+	EVENT_ASSOC_REJECT,
+
+	/**
+	 * EVENT_AUTH_TIMED_OUT - Authentication timed out
+	 */
+	EVENT_AUTH_TIMED_OUT,
+
+	/**
+	 * EVENT_ASSOC_TIMED_OUT - Association timed out
+	 */
+	EVENT_ASSOC_TIMED_OUT,
+
+	/**
+	 * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
+	 */
+	EVENT_FT_RRB_RX,
+
+	/**
+	 * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
+	 */
+	EVENT_WPS_BUTTON_PUSHED,
+
+	/**
+	 * EVENT_TX_STATUS - Report TX status
+	 */
+	EVENT_TX_STATUS,
+
+	/**
+	 * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA
+	 */
+	EVENT_RX_FROM_UNKNOWN,
+
+	/**
+	 * EVENT_RX_MGMT - Report RX of a management frame
+	 */
+	EVENT_RX_MGMT,
+
+	/**
+	 * EVENT_RX_ACTION - Action frame received
+	 *
+	 * This event is used to indicate when an Action frame has been
+	 * received. Information about the received frame is included in
+	 * union wpa_event_data::rx_action.
+	 */
+	EVENT_RX_ACTION,
+
+	/**
+	 * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
+	 *
+	 * This event is used to indicate when the driver has started the
+	 * requested remain-on-channel duration. Information about the
+	 * operation is included in union wpa_event_data::remain_on_channel.
+	 */
+	EVENT_REMAIN_ON_CHANNEL,
+
+	/**
+	 * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out
+	 *
+	 * This event is used to indicate when the driver has completed
+	 * remain-on-channel duration, i.e., may noot be available on the
+	 * requested channel anymore. Information about the
+	 * operation is included in union wpa_event_data::remain_on_channel.
+	 */
+	EVENT_CANCEL_REMAIN_ON_CHANNEL,
+
+	/**
+	 * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
+	 *
+	 * This event is used only by driver_test.c and userspace MLME.
+	 */
+	EVENT_MLME_RX,
+
+	/**
+	 * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
+	 *
+	 * This event is used to indicate when a Probe Request frame has been
+	 * received. Information about the received frame is included in
+	 * union wpa_event_data::rx_probe_req. The driver is required to report
+	 * these events only after successfully completed probe_req_report()
+	 * commands to request the events (i.e., report parameter is non-zero)
+	 * in station mode. In AP mode, Probe Request frames should always be
+	 * reported.
+	 */
+	EVENT_RX_PROBE_REQ,
+
+	/**
+	 * EVENT_NEW_STA - New wired device noticed
+	 *
+	 * This event is used to indicate that a new device has been detected
+	 * in a network that does not use association-like functionality (i.e.,
+	 * mainly wired Ethernet). This can be used to start EAPOL
+	 * authenticator when receiving a frame from a device. The address of
+	 * the device is included in union wpa_event_data::new_sta.
+	 */
+	EVENT_NEW_STA,
+
+	/**
+	 * EVENT_EAPOL_RX - Report received EAPOL frame
+	 *
+	 * When in AP mode with hostapd, this event is required to be used to
+	 * deliver the receive EAPOL frames from the driver. With
+	 * %wpa_supplicant, this event is used only if the send_eapol() handler
+	 * is used to override the use of l2_packet for EAPOL frame TX.
+	 */
+	EVENT_EAPOL_RX,
+
+	/**
+	 * EVENT_SIGNAL_CHANGE - Indicate change in signal strength
+	 *
+	 * This event is used to indicate changes in the signal strength
+	 * observed in frames received from the current AP if signal strength
+	 * monitoring has been enabled with signal_monitor().
+	 */
+	EVENT_SIGNAL_CHANGE,
+
+	/**
+	 * EVENT_INTERFACE_ENABLED - Notify that interface was enabled
+	 *
+	 * This event is used to indicate that the interface was enabled after
+	 * having been previously disabled, e.g., due to rfkill.
+	 */
+	EVENT_INTERFACE_ENABLED,
+
+	/**
+	 * EVENT_INTERFACE_DISABLED - Notify that interface was disabled
+	 *
+	 * This event is used to indicate that the interface was disabled,
+	 * e.g., due to rfkill.
+	 */
+	EVENT_INTERFACE_DISABLED,
+
+	/**
+	 * EVENT_CHANNEL_LIST_CHANGED - Channel list changed
+	 *
+	 * This event is used to indicate that the channel list has changed,
+	 * e.g., because of a regulatory domain change triggered by scan
+	 * results including an AP advertising a country code.
+	 */
+	EVENT_CHANNEL_LIST_CHANGED,
+
+	/**
+	 * EVENT_INTERFACE_UNAVAILABLE - Notify that interface is unavailable
+	 *
+	 * This event is used to indicate that the driver cannot maintain this
+	 * interface in its operation mode anymore. The most likely use for
+	 * this is to indicate that AP mode operation is not available due to
+	 * operating channel would need to be changed to a DFS channel when
+	 * the driver does not support radar detection and another virtual
+	 * interfaces caused the operating channel to change. Other similar
+	 * resource conflicts could also trigger this for station mode
+	 * interfaces.
+	 */
+	EVENT_INTERFACE_UNAVAILABLE,
+
+	/**
+	 * EVENT_BEST_CHANNEL
+	 *
+	 * Driver generates this event whenever it detects a better channel
+	 * (e.g., based on RSSI or channel use). This information can be used
+	 * to improve channel selection for a new AP/P2P group.
+	 */
+	EVENT_BEST_CHANNEL,
+
+	/**
+	 * EVENT_UNPROT_DEAUTH - Unprotected Deauthentication frame received
+	 *
+	 * This event should be called when a Deauthentication frame is dropped
+	 * due to it not being protected (MFP/IEEE 802.11w).
+	 * union wpa_event_data::unprot_deauth is required to provide more
+	 * details of the frame.
+	 */
+	EVENT_UNPROT_DEAUTH,
+
+	/**
+	 * EVENT_UNPROT_DISASSOC - Unprotected Disassociation frame received
+	 *
+	 * This event should be called when a Disassociation frame is dropped
+	 * due to it not being protected (MFP/IEEE 802.11w).
+	 * union wpa_event_data::unprot_disassoc is required to provide more
+	 * details of the frame.
+	 */
+	EVENT_UNPROT_DISASSOC,
+
+	/**
+	 * EVENT_STATION_LOW_ACK
+	 *
+	 * Driver generates this event whenever it detected that a particular
+	 * station was lost. Detection can be through massive transmission
+	 * failures for example.
+	 */
+	EVENT_STATION_LOW_ACK,
+
+	/**
+	 * EVENT_P2P_DEV_FOUND - Report a discovered P2P device
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_dev_found.
+	 */
+	EVENT_P2P_DEV_FOUND,
+
+	/**
+	 * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_go_neg_req_rx.
+	 */
+	EVENT_P2P_GO_NEG_REQ_RX,
+
+	/**
+	 * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_go_neg_completed.
+	 */
+	EVENT_P2P_GO_NEG_COMPLETED,
+
+	EVENT_P2P_PROV_DISC_REQUEST,
+	EVENT_P2P_PROV_DISC_RESPONSE,
+	EVENT_P2P_SD_REQUEST,
+	EVENT_P2P_SD_RESPONSE,
+
+	/**
+	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
+	 */
+	EVENT_IBSS_PEER_LOST,
+
+	/**
+	 * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+	 *
+	 * This event carries the new replay counter to notify wpa_supplicant
+	 * of the current EAPOL-Key Replay Counter in case the driver/firmware
+	 * completed Group Key Handshake while the host (including
+	 * wpa_supplicant was sleeping).
+	 */
+	EVENT_DRIVER_GTK_REKEY,
+
+	/**
+	 * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+	 */
+	EVENT_SCHED_SCAN_STOPPED,
+
+	/**
+	 * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+	 *
+	 * This event indicates that the station responded to the poll
+	 * initiated with @poll_client.
+	 */
+	EVENT_DRIVER_CLIENT_POLL_OK,
+
+	/**
+	 * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+	 */
+	EVENT_EAPOL_TX_STATUS,
+
+	/**
+	 * EVENT_CH_SWITCH - AP or GO decided to switch channels
+	 *
+	 * Described in wpa_event_data.ch_switch
+	 * */
+	EVENT_CH_SWITCH,
+
+	/**
+	 * EVENT_WNM - Request WNM operation
+	 *
+	 * This event can be used to request a WNM operation to be performed.
+	 */
+	EVENT_WNM
+};
+
+
+/**
+ * union wpa_event_data - Additional data for wpa_supplicant_event() calls
+ */
+union wpa_event_data {
+	/**
+	 * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events
+	 *
+	 * This structure is optional for EVENT_ASSOC calls and required for
+	 * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the
+	 * driver interface does not need to generate separate EVENT_ASSOCINFO
+	 * calls.
+	 */
+	struct assoc_info {
+		/**
+		 * reassoc - Flag to indicate association or reassociation
+		 */
+		int reassoc;
+
+		/**
+		 * req_ies - (Re)Association Request IEs
+		 *
+		 * If the driver generates WPA/RSN IE, this event data must be
+		 * returned for WPA handshake to have needed information. If
+		 * wpa_supplicant-generated WPA/RSN IE is used, this
+		 * information event is optional.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *req_ies;
+
+		/**
+		 * req_ies_len - Length of req_ies in bytes
+		 */
+		size_t req_ies_len;
+
+		/**
+		 * resp_ies - (Re)Association Response IEs
+		 *
+		 * Optional association data from the driver. This data is not
+		 * required WPA, but may be useful for some protocols and as
+		 * such, should be reported if this is available to the driver
+		 * interface.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *resp_ies;
+
+		/**
+		 * resp_ies_len - Length of resp_ies in bytes
+		 */
+		size_t resp_ies_len;
+
+		/**
+		 * beacon_ies - Beacon or Probe Response IEs
+		 *
+		 * Optional Beacon/ProbeResp data: IEs included in Beacon or
+		 * Probe Response frames from the current AP (i.e., the one
+		 * that the client just associated with). This information is
+		 * used to update WPA/RSN IE for the AP. If this field is not
+		 * set, the results from previous scan will be used. If no
+		 * data for the new AP is found, scan results will be requested
+		 * again (without scan request). At this point, the driver is
+		 * expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is
+		 * used).
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *beacon_ies;
+
+		/**
+		 * beacon_ies_len - Length of beacon_ies */
+		size_t beacon_ies_len;
+
+		/**
+		 * freq - Frequency of the operational channel in MHz
+		 */
+		unsigned int freq;
+
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+	} assoc_info;
+
+	/**
+	 * struct disassoc_info - Data for EVENT_DISASSOC events
+	 */
+	struct disassoc_info {
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+
+		/**
+		 * reason_code - Reason Code (host byte order) used in
+		 *	Deauthentication frame
+		 */
+		u16 reason_code;
+
+		/**
+		 * ie - Optional IE(s) in Disassociation frame
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * locally_generated - Whether the frame was locally generated
+		 */
+		int locally_generated;
+	} disassoc_info;
+
+	/**
+	 * struct deauth_info - Data for EVENT_DEAUTH events
+	 */
+	struct deauth_info {
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+
+		/**
+		 * reason_code - Reason Code (host byte order) used in
+		 *	Deauthentication frame
+		 */
+		u16 reason_code;
+
+		/**
+		 * ie - Optional IE(s) in Deauthentication frame
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * locally_generated - Whether the frame was locally generated
+		 */
+		int locally_generated;
+	} deauth_info;
+
+	/**
+	 * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE
+	 */
+	struct michael_mic_failure {
+		int unicast;
+		const u8 *src;
+	} michael_mic_failure;
+
+	/**
+	 * struct interface_status - Data for EVENT_INTERFACE_STATUS
+	 */
+	struct interface_status {
+		char ifname[100];
+		enum {
+			EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
+		} ievent;
+	} interface_status;
+
+	/**
+	 * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE
+	 */
+	struct pmkid_candidate {
+		/** BSSID of the PMKID candidate */
+		u8 bssid[ETH_ALEN];
+		/** Smaller the index, higher the priority */
+		int index;
+		/** Whether RSN IE includes pre-authenticate flag */
+		int preauth;
+	} pmkid_candidate;
+
+	/**
+	 * struct stkstart - Data for EVENT_STKSTART
+	 */
+	struct stkstart {
+		u8 peer[ETH_ALEN];
+	} stkstart;
+
+	/**
+	 * struct tdls - Data for EVENT_TDLS
+	 */
+	struct tdls {
+		u8 peer[ETH_ALEN];
+		enum {
+			TDLS_REQUEST_SETUP,
+			TDLS_REQUEST_TEARDOWN
+		} oper;
+		u16 reason_code; /* for teardown */
+	} tdls;
+
+	/**
+	 * struct wnm - Data for EVENT_WNM
+	 */
+	struct wnm {
+		u8 addr[ETH_ALEN];
+		enum {
+			WNM_OPER_SLEEP,
+		} oper;
+		enum {
+			WNM_SLEEP_ENTER,
+			WNM_SLEEP_EXIT
+		} sleep_action;
+		int sleep_intval;
+		u16 reason_code;
+		u8 *buf;
+		u16 buf_len;
+	} wnm;
+
+	/**
+	 * struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
+	 *
+	 * During FT (IEEE 802.11r) authentication sequence, the driver is
+	 * expected to use this event to report received FT IEs (MDIE, FTIE,
+	 * RSN IE, TIE, possible resource request) to the supplicant. The FT
+	 * IEs for the next message will be delivered through the
+	 * struct wpa_driver_ops::update_ft_ies() callback.
+	 */
+	struct ft_ies {
+		const u8 *ies;
+		size_t ies_len;
+		int ft_action;
+		u8 target_ap[ETH_ALEN];
+		/** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */
+		const u8 *ric_ies;
+		/** Length of ric_ies buffer in octets */
+		size_t ric_ies_len;
+	} ft_ies;
+
+	/**
+	 * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START
+	 */
+	struct ibss_rsn_start {
+		u8 peer[ETH_ALEN];
+	} ibss_rsn_start;
+
+	/**
+	 * struct auth_info - Data for EVENT_AUTH events
+	 */
+	struct auth_info {
+		u8 peer[ETH_ALEN];
+		u8 bssid[ETH_ALEN];
+		u16 auth_type;
+		u16 auth_transaction;
+		u16 status_code;
+		const u8 *ies;
+		size_t ies_len;
+	} auth;
+
+	/**
+	 * struct assoc_reject - Data for EVENT_ASSOC_REJECT events
+	 */
+	struct assoc_reject {
+		/**
+		 * bssid - BSSID of the AP that rejected association
+		 */
+		const u8 *bssid;
+
+		/**
+		 * resp_ies - (Re)Association Response IEs
+		 *
+		 * Optional association data from the driver. This data is not
+		 * required WPA, but may be useful for some protocols and as
+		 * such, should be reported if this is available to the driver
+		 * interface.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *resp_ies;
+
+		/**
+		 * resp_ies_len - Length of resp_ies in bytes
+		 */
+		size_t resp_ies_len;
+
+		/**
+		 * status_code - Status Code from (Re)association Response
+		 */
+		u16 status_code;
+	} assoc_reject;
+
+	struct timeout_event {
+		u8 addr[ETH_ALEN];
+	} timeout_event;
+
+	/**
+	 * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
+	 */
+	struct ft_rrb_rx {
+		const u8 *src;
+		const u8 *data;
+		size_t data_len;
+	} ft_rrb_rx;
+
+	/**
+	 * struct tx_status - Data for EVENT_TX_STATUS events
+	 */
+	struct tx_status {
+		u16 type;
+		u16 stype;
+		const u8 *dst;
+		const u8 *data;
+		size_t data_len;
+		int ack;
+	} tx_status;
+
+	/**
+	 * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
+	 */
+	struct rx_from_unknown {
+		const u8 *bssid;
+		const u8 *addr;
+		int wds;
+	} rx_from_unknown;
+
+	/**
+	 * struct rx_mgmt - Data for EVENT_RX_MGMT events
+	 */
+	struct rx_mgmt {
+		const u8 *frame;
+		size_t frame_len;
+		u32 datarate;
+		int ssi_signal; /* dBm */
+	} rx_mgmt;
+
+	/**
+	 * struct rx_action - Data for EVENT_RX_ACTION events
+	 */
+	struct rx_action {
+		/**
+		 * da - Destination address of the received Action frame
+		 */
+		const u8 *da;
+
+		/**
+		 * sa - Source address of the received Action frame
+		 */
+		const u8 *sa;
+
+		/**
+		 * bssid - Address 3 of the received Action frame
+		 */
+		const u8 *bssid;
+
+		/**
+		 * category - Action frame category
+		 */
+		u8 category;
+
+		/**
+		 * data - Action frame body after category field
+		 */
+		const u8 *data;
+
+		/**
+		 * len - Length of data in octets
+		 */
+		size_t len;
+
+		/**
+		 * freq - Frequency (in MHz) on which the frame was received
+		 */
+		int freq;
+	} rx_action;
+
+	/**
+	 * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
+	 *
+	 * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events.
+	 */
+	struct remain_on_channel {
+		/**
+		 * freq - Channel frequency in MHz
+		 */
+		unsigned int freq;
+
+		/**
+		 * duration - Duration to remain on the channel in milliseconds
+		 */
+		unsigned int duration;
+	} remain_on_channel;
+
+	/**
+	 * struct scan_info - Optional data for EVENT_SCAN_RESULTS events
+	 * @aborted: Whether the scan was aborted
+	 * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
+	 * @num_freqs: Number of entries in freqs array
+	 * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
+	 *	SSID)
+	 * @num_ssids: Number of entries in ssids array
+	 */
+	struct scan_info {
+		int aborted;
+		const int *freqs;
+		size_t num_freqs;
+		struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+		size_t num_ssids;
+	} scan_info;
+
+	/**
+	 * struct mlme_rx - Data for EVENT_MLME_RX events
+	 */
+	struct mlme_rx {
+		const u8 *buf;
+		size_t len;
+		int freq;
+		int channel;
+		int ssi;
+	} mlme_rx;
+
+	/**
+	 * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
+	 */
+	struct rx_probe_req {
+		/**
+		 * sa - Source address of the received Probe Request frame
+		 */
+		const u8 *sa;
+
+		/**
+		 * da - Destination address of the received Probe Request frame
+		 *	or %NULL if not available
+		 */
+		const u8 *da;
+
+		/**
+		 * bssid - BSSID of the received Probe Request frame or %NULL
+		 *	if not available
+		 */
+		const u8 *bssid;
+
+		/**
+		 * ie - IEs from the Probe Request body
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * signal - signal strength in dBm (or 0 if not available)
+		 */
+		int ssi_signal;
+	} rx_probe_req;
+
+	/**
+	 * struct new_sta - Data for EVENT_NEW_STA events
+	 */
+	struct new_sta {
+		const u8 *addr;
+	} new_sta;
+
+	/**
+	 * struct eapol_rx - Data for EVENT_EAPOL_RX events
+	 */
+	struct eapol_rx {
+		const u8 *src;
+		const u8 *data;
+		size_t data_len;
+	} eapol_rx;
+
+	/**
+	 * signal_change - Data for EVENT_SIGNAL_CHANGE events
+	 */
+	struct wpa_signal_info signal_change;
+
+	/**
+	 * struct best_channel - Data for EVENT_BEST_CHANNEL events
+	 * @freq_24: Best 2.4 GHz band channel frequency in MHz
+	 * @freq_5: Best 5 GHz band channel frequency in MHz
+	 * @freq_overall: Best channel frequency in MHz
+	 *
+	 * 0 can be used to indicate no preference in either band.
+	 */
+	struct best_channel {
+		int freq_24;
+		int freq_5;
+		int freq_overall;
+	} best_chan;
+
+	struct unprot_deauth {
+		const u8 *sa;
+		const u8 *da;
+		u16 reason_code;
+	} unprot_deauth;
+
+	struct unprot_disassoc {
+		const u8 *sa;
+		const u8 *da;
+		u16 reason_code;
+	} unprot_disassoc;
+
+	/**
+	 * struct low_ack - Data for EVENT_STATION_LOW_ACK events
+	 * @addr: station address
+	 */
+	struct low_ack {
+		u8 addr[ETH_ALEN];
+	} low_ack;
+
+	/**
+	 * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND
+	 */
+	struct p2p_dev_found {
+		const u8 *addr;
+		const u8 *dev_addr;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		u16 config_methods;
+		u8 dev_capab;
+		u8 group_capab;
+	} p2p_dev_found;
+
+	/**
+	 * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX
+	 */
+	struct p2p_go_neg_req_rx {
+		const u8 *src;
+		u16 dev_passwd_id;
+	} p2p_go_neg_req_rx;
+
+	/**
+	 * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED
+	 */
+	struct p2p_go_neg_completed {
+		struct p2p_go_neg_results *res;
+	} p2p_go_neg_completed;
+
+	struct p2p_prov_disc_req {
+		const u8 *peer;
+		u16 config_methods;
+		const u8 *dev_addr;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		u16 supp_config_methods;
+		u8 dev_capab;
+		u8 group_capab;
+	} p2p_prov_disc_req;
+
+	struct p2p_prov_disc_resp {
+		const u8 *peer;
+		u16 config_methods;
+	} p2p_prov_disc_resp;
+
+	struct p2p_sd_req {
+		int freq;
+		const u8 *sa;
+		u8 dialog_token;
+		u16 update_indic;
+		const u8 *tlvs;
+		size_t tlvs_len;
+	} p2p_sd_req;
+
+	struct p2p_sd_resp {
+		const u8 *sa;
+		u16 update_indic;
+		const u8 *tlvs;
+		size_t tlvs_len;
+	} p2p_sd_resp;
+
+	/**
+	 * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST
+	 */
+	struct ibss_peer_lost {
+		u8 peer[ETH_ALEN];
+	} ibss_peer_lost;
+
+	/**
+	 * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+	 */
+	struct driver_gtk_rekey {
+		const u8 *bssid;
+		const u8 *replay_ctr;
+	} driver_gtk_rekey;
+
+	/**
+	 * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+	 * @addr: station address
+	 */
+	struct client_poll {
+		u8 addr[ETH_ALEN];
+	} client_poll;
+
+	/**
+	 * struct eapol_tx_status
+	 * @dst: Original destination
+	 * @data: Data starting with IEEE 802.1X header (!)
+	 * @data_len: Length of data
+	 * @ack: Indicates ack or lost frame
+	 *
+	 * This corresponds to hapd_send_eapol if the frame sent
+	 * there isn't just reported as EVENT_TX_STATUS.
+	 */
+	struct eapol_tx_status {
+		const u8 *dst;
+		const u8 *data;
+		int data_len;
+		int ack;
+	} eapol_tx_status;
+
+	/**
+	 * struct ch_switch
+	 * @freq: Frequency of new channel in MHz
+	 * @ht_enabled: Whether this is an HT channel
+	 * @ch_offset: Secondary channel offset
+	 */
+	struct ch_switch {
+		int freq;
+		int ht_enabled;
+		int ch_offset;
+	} ch_switch;
+};
+
+/**
+ * wpa_supplicant_event - 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
+ *
+ * Driver wrapper code should call this function whenever an event is received
+ * from the driver.
+ */
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data);
+
+
+/*
+ * The following inline functions are provided for convenience to simplify
+ * event indication for some of the common events.
+ */
+
+static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie,
+				   size_t ielen, int reassoc)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.assoc_info.reassoc = reassoc;
+	event.assoc_info.req_ies = ie;
+	event.assoc_info.req_ies_len = ielen;
+	event.assoc_info.addr = addr;
+	wpa_supplicant_event(ctx, EVENT_ASSOC, &event);
+}
+
+static inline void drv_event_disassoc(void *ctx, const u8 *addr)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.disassoc_info.addr = addr;
+	wpa_supplicant_event(ctx, EVENT_DISASSOC, &event);
+}
+
+static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
+				      size_t data_len)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.eapol_rx.src = src;
+	event.eapol_rx.data = data;
+	event.eapol_rx.data_len = data_len;
+	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
+}
+
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
+#endif /* DRIVER_H */

Deleted: vendor/wpa/2.0/src/drivers/driver_atheros.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_atheros.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_atheros.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1298 +0,0 @@
-/*
- * hostapd / Driver interaction with Atheros driver
- * Copyright (c) 2004, Sam Leffler <sam at errno.com>
- * Copyright (c) 2004, Video54 Technologies
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2009, Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include "common.h"
-#ifndef _BYTE_ORDER
-#ifdef WORDS_BIGENDIAN
-#define _BYTE_ORDER _BIG_ENDIAN
-#else
-#define _BYTE_ORDER _LITTLE_ENDIAN
-#endif
-#endif /* _BYTE_ORDER */
-
-/*
- * Note, the ATH_WPS_IE setting must match with the driver build.. If the
- * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
- */
-#define ATH_WPS_IE
-
-#include "os/linux/include/ieee80211_external.h"
-
-
-#ifdef CONFIG_WPS
-#include <netpacket/packet.h>
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW 0x0019
-#endif
-#endif /* CONFIG_WPS */
-
-#include "wireless_copy.h"
-
-#include "driver.h"
-#include "eloop.h"
-#include "priv_netlink.h"
-#include "l2_packet/l2_packet.h"
-#include "common/ieee802_11_defs.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-
-
-struct madwifi_driver_data {
-	struct hostapd_data *hapd;		/* back pointer */
-
-	char	iface[IFNAMSIZ + 1];
-	int     ifindex;
-	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */
-	struct l2_packet_data *sock_recv;	/* raw packet recv socket */
-	int	ioctl_sock;			/* socket for ioctl() use */
-	struct netlink_data *netlink;
-	int	we_version;
-	u8	acct_mac[ETH_ALEN];
-	struct hostap_sta_driver_data acct_data;
-
-	struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
-};
-
-static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			      int reason_code);
-static int madwifi_set_privacy(void *priv, int enabled);
-
-static const char * athr_get_ioctl_name(int op)
-{
-	switch (op) {
-	case IEEE80211_IOCTL_SETPARAM:
-		return "SETPARAM";
-	case IEEE80211_IOCTL_GETPARAM:
-		return "GETPARAM";
-	case IEEE80211_IOCTL_SETKEY:
-		return "SETKEY";
-	case IEEE80211_IOCTL_SETWMMPARAMS:
-		return "SETWMMPARAMS";
-	case IEEE80211_IOCTL_DELKEY:
-		return "DELKEY";
-	case IEEE80211_IOCTL_GETWMMPARAMS:
-		return "GETWMMPARAMS";
-	case IEEE80211_IOCTL_SETMLME:
-		return "SETMLME";
-	case IEEE80211_IOCTL_GETCHANINFO:
-		return "GETCHANINFO";
-	case IEEE80211_IOCTL_SETOPTIE:
-		return "SETOPTIE";
-	case IEEE80211_IOCTL_GETOPTIE:
-		return "GETOPTIE";
-	case IEEE80211_IOCTL_ADDMAC:
-		return "ADDMAC";
-	case IEEE80211_IOCTL_DELMAC:
-		return "DELMAC";
-	case IEEE80211_IOCTL_GETCHANLIST:
-		return "GETCHANLIST";
-	case IEEE80211_IOCTL_SETCHANLIST:
-		return "SETCHANLIST";
-	case IEEE80211_IOCTL_KICKMAC:
-		return "KICKMAC";
-	case IEEE80211_IOCTL_CHANSWITCH:
-		return "CHANSWITCH";
-	case IEEE80211_IOCTL_GETMODE:
-		return "GETMODE";
-	case IEEE80211_IOCTL_SETMODE:
-		return "SETMODE";
-	case IEEE80211_IOCTL_GET_APPIEBUF:
-		return "GET_APPIEBUF";
-	case IEEE80211_IOCTL_SET_APPIEBUF:
-		return "SET_APPIEBUF";
-	case IEEE80211_IOCTL_SET_ACPARAMS:
-		return "SET_ACPARAMS";
-	case IEEE80211_IOCTL_FILTERFRAME:
-		return "FILTERFRAME";
-	case IEEE80211_IOCTL_SET_RTPARAMS:
-		return "SET_RTPARAMS";
-	case IEEE80211_IOCTL_SENDADDBA:
-		return "SENDADDBA";
-	case IEEE80211_IOCTL_GETADDBASTATUS:
-		return "GETADDBASTATUS";
-	case IEEE80211_IOCTL_SENDDELBA:
-		return "SENDDELBA";
-	case IEEE80211_IOCTL_SET_MEDENYENTRY:
-		return "SET_MEDENYENTRY";
-	case IEEE80211_IOCTL_SET_ADDBARESP:
-		return "SET_ADDBARESP";
-	case IEEE80211_IOCTL_GET_MACADDR:
-		return "GET_MACADDR";
-	case IEEE80211_IOCTL_SET_HBRPARAMS:
-		return "SET_HBRPARAMS";
-	case IEEE80211_IOCTL_SET_RXTIMEOUT:
-		return "SET_RXTIMEOUT";
-	case IEEE80211_IOCTL_STA_STATS:
-		return "STA_STATS";
-	case IEEE80211_IOCTL_GETWPAIE:
-		return "GETWPAIE";
-	default:
-		return "??";
-	}
-}
-
-
-static const char * athr_get_param_name(int op)
-{
-	switch (op) {
-	case IEEE80211_IOC_MCASTCIPHER:
-		return "MCASTCIPHER";
-	case IEEE80211_PARAM_MCASTKEYLEN:
-		return "MCASTKEYLEN";
-	case IEEE80211_PARAM_UCASTCIPHERS:
-		return "UCASTCIPHERS";
-	case IEEE80211_PARAM_KEYMGTALGS:
-		return "KEYMGTALGS";
-	case IEEE80211_PARAM_RSNCAPS:
-		return "RSNCAPS";
-	case IEEE80211_PARAM_WPA:
-		return "WPA";
-	case IEEE80211_PARAM_AUTHMODE:
-		return "AUTHMODE";
-	case IEEE80211_PARAM_PRIVACY:
-		return "PRIVACY";
-	case IEEE80211_PARAM_COUNTERMEASURES:
-		return "COUNTERMEASURES";
-	default:
-		return "??";
-	}
-}
-
-
-static int
-set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
-{
-	struct iwreq iwr;
-	int do_inline = len < IFNAMSIZ;
-
-	/* Certain ioctls must use the non-inlined method */
-	if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
-	    op == IEEE80211_IOCTL_FILTERFRAME)
-		do_inline = 0;
-
-	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);
-	} else {
-		/*
-		 * Argument data too big for inline transfer; setup a
-		 * parameter block instead; the kernel will transfer
-		 * the data for the driver.
-		 */
-		iwr.u.data.pointer = data;
-		iwr.u.data.length = len;
-	}
-
-	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
-			   "(%s) len=%d failed: %d (%s)",
-			   __func__, drv->iface, op,
-			   athr_get_ioctl_name(op),
-			   len, errno, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct madwifi_driver_data *drv, int op, int arg)
-{
-	struct iwreq iwr;
-
-	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));
-
-	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
-			   "(%s) arg %d)", __func__, drv->iface, op,
-			   athr_get_param_name(op), arg);
-		return -1;
-	}
-	return 0;
-}
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char *
-ether_sprintf(const u8 *addr)
-{
-	static char buf[sizeof(MACSTR)];
-
-	if (addr != NULL)
-		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	else
-		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
-	return buf;
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-/*
- * Configure WPA parameters.
- */
-static int
-madwifi_configure_wpa(struct madwifi_driver_data *drv,
-		      struct wpa_bss_params *params)
-{
-	int v;
-
-	switch (params->wpa_group) {
-	case WPA_CIPHER_CCMP:
-		v = IEEE80211_CIPHER_AES_CCM;
-		break;
-	case WPA_CIPHER_TKIP:
-		v = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_NONE:
-		v = IEEE80211_CIPHER_NONE;
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
-			   params->wpa_group);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u\n", v);
-		return -1;
-	}
-	if (v == IEEE80211_CIPHER_WEP) {
-		/* key length is done only for specific ciphers */
-		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
-		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
-			return -1;
-		}
-	}
-
-	v = 0;
-	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
-		v |= 1<<IEEE80211_CIPHER_AES_CCM;
-	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
-		v |= 1<<IEEE80211_CIPHER_TKIP;
-	if (params->wpa_pairwise & WPA_CIPHER_NONE)
-		v |= 1<<IEEE80211_CIPHER_NONE;
-	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
-		   __func__, params->wpa_key_mgmt);
-	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
-			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
-		return -1;
-	}
-
-	v = 0;
-	if (params->rsn_preauth)
-		v |= BIT(0);
-	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
-		   __func__, params->rsn_preauth);
-	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
-	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
-
-	if (!params->enabled) {
-		/* XXX restore state */
-		if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-				  IEEE80211_AUTH_AUTO) < 0)
-			return -1;
-		/* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
-		return madwifi_set_privacy(drv, 0);
-	}
-	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
-		return -1;
-	}
-	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
-		return -1;
-	}
-	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
-madwifi_set_privacy(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-
-	return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
-}
-
-static int
-madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
-		   __func__, ether_sprintf(addr), authorized);
-
-	if (authorized)
-		mlme.im_op = IEEE80211_MLME_AUTHORIZE;
-	else
-		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
-	mlme.im_reason = 0;
-	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,
-			   __func__, authorized ? "" : "un", MAC2STR(addr));
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_set_flags(void *priv, const u8 *addr,
-		      int total_flags, int flags_or, int flags_and)
-{
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		return madwifi_set_sta_authorized(priv, addr, 1);
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		return madwifi_set_sta_authorized(priv, addr, 0);
-	return 0;
-}
-
-static int
-madwifi_del_key(void *priv, const u8 *addr, int key_idx)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_del_key wk;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
-		   __func__, ether_sprintf(addr), key_idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr != NULL) {
-		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
-	} else {
-		wk.idk_keyix = key_idx;
-	}
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
-			   " key_idx %d)", __func__, ether_sprintf(addr),
-			   key_idx);
-	}
-
-	return ret;
-}
-
-static int
-madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-		const u8 *addr, int key_idx, int set_tx, const u8 *seq,
-		size_t seq_len, const u8 *key, size_t key_len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-	u_int8_t cipher;
-	int ret;
-
-	if (alg == WPA_ALG_NONE)
-		return madwifi_del_key(drv, addr, key_idx);
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
-		   __func__, alg, ether_sprintf(addr), key_idx);
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		cipher = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		cipher = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		cipher = IEEE80211_CIPHER_AES_CCM;
-		break;
-	default:
-		printf("%s: unknown/unsupported algorithm %d\n",
-			__func__, alg);
-		return -1;
-	}
-
-	if (key_len > sizeof(wk.ik_keydata)) {
-		printf("%s: key length %lu too big\n", __func__,
-		       (unsigned long) key_len);
-		return -3;
-	}
-
-	memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
-	if (addr == NULL) {
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-		wk.ik_keyix = key_idx;
-		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
-	} else {
-		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);
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
-			   " key_idx %d alg %d key_len %lu set_tx %d)",
-			   __func__, ether_sprintf(wk.ik_macaddr), key_idx,
-			   alg, (unsigned long) key_len, set_tx);
-	}
-
-	return ret;
-}
-
-
-static int
-madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
-		   u8 *seq)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
-		   __func__, ether_sprintf(addr), idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr == NULL)
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-	else
-		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = idx;
-
-	if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
-			   "(addr " MACSTR " key_idx %d)",
-			   __func__, MAC2STR(wk.ik_macaddr), idx);
-		return -1;
-	}
-
-#ifdef WORDS_BIGENDIAN
-	{
-		/*
-		 * wk.ik_keytsc is in host byte order (big endian), need to
-		 * swap it to match with the byte order used in WPA.
-		 */
-		int i;
-#ifndef WPA_KEY_RSC_LEN
-#define WPA_KEY_RSC_LEN 8
-#endif
-		u8 tmp[WPA_KEY_RSC_LEN];
-		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));
-#endif /* WORDS_BIGENDIAN */
-	return 0;
-}
-
-
-static int
-madwifi_flush(void *priv)
-{
-	u8 allsta[IEEE80211_ADDR_LEN];
-	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
-	return madwifi_sta_deauth(priv, NULL, allsta,
-				  IEEE80211_REASON_AUTH_LEAVE);
-}
-
-
-static int
-madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
-			     const u8 *addr)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_sta_stats stats;
-
-	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);
-	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));
-			return 0;
-		}
-
-		printf("Failed to get station stats information element.\n");
-		return -1;
-	}
-
-	data->rx_packets = stats.is_stats.ns_rx_data;
-	data->rx_bytes = stats.is_stats.ns_rx_bytes;
-	data->tx_packets = stats.is_stats.ns_tx_data;
-	data->tx_bytes = stats.is_stats.ns_tx_bytes;
-	return 0;
-}
-
-
-static int
-madwifi_sta_clear_stats(void *priv, const u8 *addr)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	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);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-			   sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
-			   MACSTR ")", __func__, MAC2STR(addr));
-	}
-
-	return ret;
-}
-
-
-static int
-madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
-{
-	/*
-	 * Do nothing; we setup parameters at startup that define the
-	 * contents of the beacon information element.
-	 */
-	return 0;
-}
-
-static int
-madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-		   int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	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
-			   " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-		     int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	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 "
-			   MACSTR " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	union wpa_event_data event;
-
-	/* Send Probe Request information to WPS processing */
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
-	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_probe_req.sa = mgmt->sa;
-	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-	event.rx_probe_req.ie_len =
-		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* CONFIG_WPS */
-
-static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
-{
-	int ret = 0;
-#ifdef CONFIG_WPS
-	struct ieee80211req_set_filter filt;
-
-	wpa_printf(MSG_DEBUG, "%s Enter", __func__);
-	filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
-			   sizeof(struct ieee80211req_set_filter));
-	if (ret)
-		return ret;
-
-	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
-				       madwifi_raw_receive, drv, 1);
-	if (drv->sock_raw == NULL)
-		return -1;
-#endif /* CONFIG_WPS */
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-static int
-madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
-{
-	struct madwifi_driver_data *drv = priv;
-	u8 buf[256];
-	struct ieee80211req_getset_appiebuf *beac_ie;
-
-	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-		   (unsigned long) len);
-
-	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
-	beac_ie->app_frmtype = frametype;
-	beac_ie->app_buflen = len;
-	memcpy(&(beac_ie->app_buf[0]), ie, len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
-			    sizeof(struct ieee80211req_getset_appiebuf) + len);
-}
-
-static int
-madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-		      const struct wpabuf *proberesp)
-{
-	if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
-			       beacon ? wpabuf_len(beacon) : 0,
-			       IEEE80211_APPIE_FRAME_BEACON))
-		return -1;
-	return madwifi_set_wps_ie(priv,
-				  proberesp ? wpabuf_head(proberesp) : NULL,
-				  proberesp ? wpabuf_len(proberesp): 0,
-				  IEEE80211_APPIE_FRAME_PROBE_RESP);
-}
-#else /* CONFIG_WPS */
-#define madwifi_set_ap_wps_ie NULL
-#endif /* CONFIG_WPS */
-
-static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
-{
-	struct hostapd_data *hapd = drv->hapd;
-	struct ieee80211req_wpaie ie;
-	int ielen = 0;
-	u8 *iebuf = NULL;
-
-	/*
-	 * Fetch negotiated WPA/RSN parameters from the system.
-	 */
-	memset(&ie, 0, sizeof(ie));
-	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
-		 * possible cause for the failure..
-		 */
-		wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
-			   __func__, strerror(errno));
-		goto no_ie;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
-		    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
-		    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
-	iebuf = ie.wpa_ie;
-	/* madwifi seems to return some random data if WPA/RSN IE is not set.
-	 * Assume the IE was not included if the IE type is unknown. */
-	if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
-		iebuf[1] = 0;
-	if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
-		/* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
-		 * set. This is needed for WPA2. */
-		iebuf = ie.rsn_ie;
-		if (iebuf[0] != WLAN_EID_RSN)
-			iebuf[1] = 0;
-	}
-
-	ielen = iebuf[1];
-	if (ielen == 0)
-		iebuf = NULL;
-	else
-		ielen += 2;
-
-no_ie:
-	drv_event_assoc(hapd, addr, iebuf, ielen);
-
-	if (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));
-	}
-}
-
-static void
-madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
-				       char *custom, char *end)
-{
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		char *pos;
-		u8 addr[ETH_ALEN];
-		pos = strstr(custom, "addr=");
-		if (pos == NULL) {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "without sender address ignored");
-			return;
-		}
-		pos += 5;
-		if (hwaddr_aton(pos, addr) == 0) {
-			union wpa_event_data data;
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = addr;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "with invalid MAC address");
-		}
-	} else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
-		char *key, *value;
-		u32 val;
-		key = custom;
-		while ((key = strchr(key, '\n')) != NULL) {
-			key++;
-			value = strchr(key, '=');
-			if (value == NULL)
-				continue;
-			*value++ = '\0';
-			val = strtoul(value, NULL, 10);
-			if (strcmp(key, "mac") == 0)
-				hwaddr_aton(value, drv->acct_mac);
-			else if (strcmp(key, "rx_packets") == 0)
-				drv->acct_data.rx_packets = val;
-			else if (strcmp(key, "tx_packets") == 0)
-				drv->acct_data.tx_packets = val;
-			else if (strcmp(key, "rx_bytes") == 0)
-				drv->acct_data.rx_bytes = val;
-			else if (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) {
-		/* 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) {
-		/*
-		 * Atheros driver uses a hack to pass Probe Request frames as a
-		 * binary data in the custom wireless event. The old way (using
-		 * packet sniffing) didn't work when bridging.
-		 * Format: "Manage.prob_req <frame len>" | zero padding | frame
-		 */
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
-		int len = atoi(custom + 16);
-		if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
-			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
-				   "length %d", len);
-			return;
-		}
-		madwifi_raw_receive(drv, NULL,
-				    (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS */
-	}
-}
-
-static void
-madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
-				char *data, 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) {
-		/* Event data may be unaligned, so make a local, aligned copy
-		 * before processing. */
-		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)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (drv->we_version > 18 &&
-		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
-		     iwe->cmd == IWEVASSOCREQIE ||
-		     iwe->cmd == IWEVCUSTOM)) {
-			/* 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);
-		} else {
-			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVEXPIRED:
-			drv_event_disassoc(drv->hapd,
-					   (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVREGISTERED:
-			madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVASSOCREQIE:
-			/* Driver hack.. Use IWEVASSOCREQIE to bypass
-			 * IWEVCUSTOM size limitations. Need to handle this
-			 * just like IWEVCUSTOM.
-			 */
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;		/* XXX */
-			memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-			madwifi_wireless_event_wireless_custom(
-				drv, buf, buf + iwe->u.data.length);
-			free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-
-static void
-madwifi_wireless_event_rtm_newlink(void *ctx,
-				   struct ifinfomsg *ifi, u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	if (ifi->ifi_index != drv->ifindex)
-		return;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_WIRELESS) {
-			madwifi_wireless_event_wireless(
-				drv, ((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-static int
-madwifi_get_we_version(struct madwifi_driver_data *drv)
-{
-	struct iw_range *range;
-	struct iwreq iwr;
-	int minlen;
-	size_t buflen;
-
-	drv->we_version = 0;
-
-	/*
-	 * Use larger buffer than struct iw_range in order to allow the
-	 * structure to grow in the future.
-	 */
-	buflen = sizeof(struct iw_range) + 500;
-	range = os_zalloc(buflen);
-	if (range == NULL)
-		return -1;
-
-	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;
-
-	minlen = ((char *) &range->enc_capa) - (char *) range +
-		sizeof(range->enc_capa);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
-		return -1;
-	} else if (iwr.u.data.length >= minlen &&
-		   range->we_version_compiled >= 18) {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
-			   "WE(source)=%d enc_capa=0x%x",
-			   range->we_version_compiled,
-			   range->we_version_source,
-			   range->enc_capa);
-		drv->we_version = range->we_version_compiled;
-	}
-
-	free(range);
-	return 0;
-}
-
-
-static int
-madwifi_wireless_event_init(struct madwifi_driver_data *drv)
-{
-	struct netlink_config *cfg;
-
-	madwifi_get_we_version(drv);
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		return -1;
-	cfg->ctx = drv;
-	cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int
-madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-		   int encrypt, const u8 *own_addr)
-{
-	struct madwifi_driver_data *drv = priv;
-	unsigned char buf[3000];
-	unsigned char *bp = buf;
-	struct l2_ethhdr *eth;
-	size_t len;
-	int status;
-
-	/*
-	 * Prepend the Ethernet header.  If the caller left us
-	 * space at the front we could just insert it but since
-	 * we don't know we copy to a local buffer.  Given the frequency
-	 * and size of frames this probably doesn't matter.
-	 */
-	len = data_len + sizeof(struct l2_ethhdr);
-	if (len > sizeof(buf)) {
-		bp = malloc(len);
-		if (bp == NULL) {
-			printf("EAPOL frame discarded, cannot malloc temp "
-			       "buffer of size %lu!\n", (unsigned long) len);
-			return -1;
-		}
-	}
-	eth = (struct l2_ethhdr *) bp;
-	memcpy(eth->h_dest, addr, ETH_ALEN);
-	memcpy(eth->h_source, own_addr, ETH_ALEN);
-	eth->h_proto = host_to_be16(ETH_P_EAPOL);
-	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);
-	return status;
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
-			   len - sizeof(struct l2_ethhdr));
-}
-
-static void *
-madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
-{
-	struct madwifi_driver_data *drv;
-	struct ifreq ifr;
-	struct iwreq iwr;
-	char brname[IFNAMSIZ];
-
-	drv = os_zalloc(sizeof(struct madwifi_driver_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for madwifi driver data\n");
-		return NULL;
-	}
-
-	drv->hapd = hapd;
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		goto bad;
-	}
-	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
-
-	memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
-	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		goto bad;
-	}
-	drv->ifindex = ifr.ifr_ifindex;
-
-	drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
-					handle_read, drv, 1);
-	if (drv->sock_xmit == NULL)
-		goto bad;
-	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
-		goto bad;
-	if (params->bridge[0]) {
-		wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
-			   params->bridge[0]);
-		drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
-						ETH_P_EAPOL, handle_read, drv,
-						1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else if (linux_br_get(brname, drv->iface) == 0) {
-		wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
-			   "EAPOL receive", brname);
-		drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
-						handle_read, drv, 1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else
-		drv->sock_recv = drv->sock_xmit;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-
-	iwr.u.mode = IW_MODE_MASTER;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMODE]");
-		printf("Could not set interface to master mode!\n");
-		goto bad;
-	}
-
-	/* mark down during setup */
-	linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	madwifi_set_privacy(drv, 0); /* default to no privacy */
-
-	madwifi_receive_probe_req(drv);
-
-	if (madwifi_wireless_event_init(drv))
-		goto bad;
-
-	return drv;
-bad:
-	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
-		l2_packet_deinit(drv->sock_recv);
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv != NULL)
-		free(drv);
-	return NULL;
-}
-
-
-static void
-madwifi_deinit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	netlink_deinit(drv->netlink);
-	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
-		l2_packet_deinit(drv->sock_recv);
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock_raw)
-		l2_packet_deinit(drv->sock_raw);
-	free(drv);
-}
-
-static int
-madwifi_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	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;
-	iwr.u.essid.length = len + 1;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_get_ssid(void *priv, u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	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;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	return ret;
-}
-
-static int
-madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
-}
-
-static int
-madwifi_commit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
-}
-
-const struct wpa_driver_ops wpa_driver_atheros_ops = {
-	.name			= "atheros",
-	.hapd_init		= madwifi_init,
-	.hapd_deinit		= madwifi_deinit,
-	.set_ieee8021x		= madwifi_set_ieee8021x,
-	.set_privacy		= madwifi_set_privacy,
-	.set_key		= madwifi_set_key,
-	.get_seqnum		= madwifi_get_seqnum,
-	.flush			= madwifi_flush,
-	.set_generic_elem	= madwifi_set_opt_ie,
-	.sta_set_flags		= madwifi_sta_set_flags,
-	.read_sta_data		= madwifi_read_sta_driver_data,
-	.hapd_send_eapol	= madwifi_send_eapol,
-	.sta_disassoc		= madwifi_sta_disassoc,
-	.sta_deauth		= madwifi_sta_deauth,
-	.hapd_set_ssid		= madwifi_set_ssid,
-	.hapd_get_ssid		= madwifi_get_ssid,
-	.set_countermeasures	= madwifi_set_countermeasures,
-	.sta_clear_stats	= madwifi_sta_clear_stats,
-	.commit			= madwifi_commit,
-	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_atheros.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_atheros.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_atheros.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_atheros.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2156 @@
+/*
+ * hostapd / Driver interaction with Atheros driver
+ * Copyright (c) 2004, Sam Leffler <sam at errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+
+#include "common.h"
+#ifndef _BYTE_ORDER
+#ifdef WORDS_BIGENDIAN
+#define _BYTE_ORDER _BIG_ENDIAN
+#else
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#endif
+#endif /* _BYTE_ORDER */
+
+/*
+ * Note, the ATH_WPS_IE setting must match with the driver build.. If the
+ * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
+ */
+#define ATH_WPS_IE
+
+#include "ieee80211_external.h"
+
+
+#ifdef CONFIG_WPS
+#include <netpacket/packet.h>
+#endif /* CONFIG_WPS */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+
+#include "linux_wext.h"
+
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "l2_packet/l2_packet.h"
+#include "common/ieee802_11_defs.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+
+
+struct atheros_driver_data {
+	struct hostapd_data *hapd;		/* back pointer */
+
+	char	iface[IFNAMSIZ + 1];
+	int     ifindex;
+	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */
+	struct l2_packet_data *sock_recv;	/* raw packet recv socket */
+	int	ioctl_sock;			/* socket for ioctl() use */
+	struct netlink_data *netlink;
+	int	we_version;
+	u8	acct_mac[ETH_ALEN];
+	struct hostap_sta_driver_data acct_data;
+
+	struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+	struct wpabuf *wpa_ie;
+	struct wpabuf *wps_beacon_ie;
+	struct wpabuf *wps_probe_resp_ie;
+	u8	own_addr[ETH_ALEN];
+};
+
+static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+			      int reason_code);
+static int atheros_set_privacy(void *priv, int enabled);
+
+static const char * athr_get_ioctl_name(int op)
+{
+	switch (op) {
+	case IEEE80211_IOCTL_SETPARAM:
+		return "SETPARAM";
+	case IEEE80211_IOCTL_GETPARAM:
+		return "GETPARAM";
+	case IEEE80211_IOCTL_SETKEY:
+		return "SETKEY";
+	case IEEE80211_IOCTL_SETWMMPARAMS:
+		return "SETWMMPARAMS";
+	case IEEE80211_IOCTL_DELKEY:
+		return "DELKEY";
+	case IEEE80211_IOCTL_GETWMMPARAMS:
+		return "GETWMMPARAMS";
+	case IEEE80211_IOCTL_SETMLME:
+		return "SETMLME";
+	case IEEE80211_IOCTL_GETCHANINFO:
+		return "GETCHANINFO";
+	case IEEE80211_IOCTL_SETOPTIE:
+		return "SETOPTIE";
+	case IEEE80211_IOCTL_GETOPTIE:
+		return "GETOPTIE";
+	case IEEE80211_IOCTL_ADDMAC:
+		return "ADDMAC";
+	case IEEE80211_IOCTL_DELMAC:
+		return "DELMAC";
+	case IEEE80211_IOCTL_GETCHANLIST:
+		return "GETCHANLIST";
+	case IEEE80211_IOCTL_SETCHANLIST:
+		return "SETCHANLIST";
+	case IEEE80211_IOCTL_KICKMAC:
+		return "KICKMAC";
+	case IEEE80211_IOCTL_CHANSWITCH:
+		return "CHANSWITCH";
+	case IEEE80211_IOCTL_GETMODE:
+		return "GETMODE";
+	case IEEE80211_IOCTL_SETMODE:
+		return "SETMODE";
+	case IEEE80211_IOCTL_GET_APPIEBUF:
+		return "GET_APPIEBUF";
+	case IEEE80211_IOCTL_SET_APPIEBUF:
+		return "SET_APPIEBUF";
+	case IEEE80211_IOCTL_SET_ACPARAMS:
+		return "SET_ACPARAMS";
+	case IEEE80211_IOCTL_FILTERFRAME:
+		return "FILTERFRAME";
+	case IEEE80211_IOCTL_SET_RTPARAMS:
+		return "SET_RTPARAMS";
+	case IEEE80211_IOCTL_SET_MEDENYENTRY:
+		return "SET_MEDENYENTRY";
+	case IEEE80211_IOCTL_GET_MACADDR:
+		return "GET_MACADDR";
+	case IEEE80211_IOCTL_SET_HBRPARAMS:
+		return "SET_HBRPARAMS";
+	case IEEE80211_IOCTL_SET_RXTIMEOUT:
+		return "SET_RXTIMEOUT";
+	case IEEE80211_IOCTL_STA_STATS:
+		return "STA_STATS";
+	case IEEE80211_IOCTL_GETWPAIE:
+		return "GETWPAIE";
+	default:
+		return "??";
+	}
+}
+
+
+static const char * athr_get_param_name(int op)
+{
+	switch (op) {
+	case IEEE80211_IOC_MCASTCIPHER:
+		return "MCASTCIPHER";
+	case IEEE80211_PARAM_MCASTKEYLEN:
+		return "MCASTKEYLEN";
+	case IEEE80211_PARAM_UCASTCIPHERS:
+		return "UCASTCIPHERS";
+	case IEEE80211_PARAM_KEYMGTALGS:
+		return "KEYMGTALGS";
+	case IEEE80211_PARAM_RSNCAPS:
+		return "RSNCAPS";
+	case IEEE80211_PARAM_WPA:
+		return "WPA";
+	case IEEE80211_PARAM_AUTHMODE:
+		return "AUTHMODE";
+	case IEEE80211_PARAM_PRIVACY:
+		return "PRIVACY";
+	case IEEE80211_PARAM_COUNTERMEASURES:
+		return "COUNTERMEASURES";
+	default:
+		return "??";
+	}
+}
+
+
+static int
+set80211priv(struct atheros_driver_data *drv, int op, void *data, int len)
+{
+	struct iwreq iwr;
+	int do_inline = len < IFNAMSIZ;
+
+	/* Certain ioctls must use the non-inlined method */
+	if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
+	    op == IEEE80211_IOCTL_FILTERFRAME)
+		do_inline = 0;
+
+	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);
+	} else {
+		/*
+		 * Argument data too big for inline transfer; setup a
+		 * parameter block instead; the kernel will transfer
+		 * the data for the driver.
+		 */
+		iwr.u.data.pointer = data;
+		iwr.u.data.length = len;
+	}
+
+	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
+		wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
+			   "(%s) len=%d failed: %d (%s)",
+			   __func__, drv->iface, op,
+			   athr_get_ioctl_name(op),
+			   len, errno, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+set80211param(struct atheros_driver_data *drv, int op, int arg)
+{
+	struct iwreq iwr;
+
+	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));
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
+			   "(%s) arg %d)", __func__, drv->iface, op,
+			   athr_get_param_name(op), arg);
+		return -1;
+	}
+	return 0;
+}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char *
+ether_sprintf(const u8 *addr)
+{
+	static char buf[sizeof(MACSTR)];
+
+	if (addr != NULL)
+		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	else
+		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+	return buf;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+atheros_configure_wpa(struct atheros_driver_data *drv,
+		      struct wpa_bss_params *params)
+{
+	int v;
+
+	switch (params->wpa_group) {
+	case WPA_CIPHER_CCMP:
+		v = IEEE80211_CIPHER_AES_CCM;
+		break;
+	case WPA_CIPHER_TKIP:
+		v = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_CIPHER_WEP104:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_WEP40:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_NONE:
+		v = IEEE80211_CIPHER_NONE;
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+			   params->wpa_group);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+		printf("Unable to set group key cipher to %u\n", v);
+		return -1;
+	}
+	if (v == IEEE80211_CIPHER_WEP) {
+		/* key length is done only for specific ciphers */
+		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+			printf("Unable to set group key length to %u\n", v);
+			return -1;
+		}
+	}
+
+	v = 0;
+	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+		v |= 1<<IEEE80211_CIPHER_AES_CCM;
+	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+		v |= 1<<IEEE80211_CIPHER_TKIP;
+	if (params->wpa_pairwise & WPA_CIPHER_NONE)
+		v |= 1<<IEEE80211_CIPHER_NONE;
+	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+		   __func__, params->wpa_key_mgmt);
+	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
+			  params->wpa_key_mgmt)) {
+		printf("Unable to set key management algorithms to 0x%x\n",
+			params->wpa_key_mgmt);
+		return -1;
+	}
+
+	v = 0;
+	if (params->rsn_preauth)
+		v |= BIT(0);
+#ifdef CONFIG_IEEE80211W
+	if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		v |= BIT(7);
+		if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+			v |= BIT(6);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
+	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+		printf("Unable to set RSN capabilities to 0x%x\n", v);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
+	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
+		printf("Unable to set WPA to %u\n", params->wpa);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+	struct atheros_driver_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+	if (!params->enabled) {
+		/* XXX restore state */
+		if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+				  IEEE80211_AUTH_AUTO) < 0)
+			return -1;
+		/* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
+		return atheros_set_privacy(drv, 0);
+	}
+	if (!params->wpa && !params->ieee802_1x) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		return -1;
+	}
+	if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		return -1;
+	}
+	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+atheros_set_privacy(void *priv, int enabled)
+{
+	struct atheros_driver_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+	return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+		   __func__, ether_sprintf(addr), authorized);
+
+	if (authorized)
+		mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+	else
+		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+	mlme.im_reason = 0;
+	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,
+			   __func__, authorized ? "" : "un", MAC2STR(addr));
+	}
+
+	return ret;
+}
+
+static int
+atheros_sta_set_flags(void *priv, const u8 *addr,
+		      int total_flags, int flags_or, int flags_and)
+{
+	/* For now, only support setting Authorized flag */
+	if (flags_or & WPA_STA_AUTHORIZED)
+		return atheros_set_sta_authorized(priv, addr, 1);
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		return atheros_set_sta_authorized(priv, addr, 0);
+	return 0;
+}
+
+static int
+atheros_del_key(void *priv, const u8 *addr, int key_idx)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_del_key wk;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+		   __func__, ether_sprintf(addr), key_idx);
+
+	memset(&wk, 0, sizeof(wk));
+	if (addr != NULL) {
+		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+	} else {
+		wk.idk_keyix = key_idx;
+	}
+
+	ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+			   " key_idx %d)", __func__, ether_sprintf(addr),
+			   key_idx);
+	}
+
+	return ret;
+}
+
+static int
+atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+		const u8 *addr, int key_idx, int set_tx, const u8 *seq,
+		size_t seq_len, const u8 *key, size_t key_len)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_key wk;
+	u_int8_t cipher;
+	int ret;
+
+	if (alg == WPA_ALG_NONE)
+		return atheros_del_key(drv, addr, key_idx);
+
+	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
+		   __func__, alg, ether_sprintf(addr), key_idx);
+
+	switch (alg) {
+	case WPA_ALG_WEP:
+		cipher = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_ALG_TKIP:
+		cipher = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_ALG_CCMP:
+		cipher = IEEE80211_CIPHER_AES_CCM;
+		break;
+#ifdef CONFIG_IEEE80211W
+	case WPA_ALG_IGTK:
+		cipher = IEEE80211_CIPHER_AES_CMAC;
+		break;
+#endif /* CONFIG_IEEE80211W */
+	default:
+		printf("%s: unknown/unsupported algorithm %d\n",
+			__func__, alg);
+		return -1;
+	}
+
+	if (key_len > sizeof(wk.ik_keydata)) {
+		printf("%s: key length %lu too big\n", __func__,
+		       (unsigned long) key_len);
+		return -3;
+	}
+
+	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);
+		wk.ik_keyix = key_idx;
+		if (set_tx)
+			wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+	} else {
+		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);
+
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+			   " key_idx %d alg %d key_len %lu set_tx %d)",
+			   __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+			   alg, (unsigned long) key_len, set_tx);
+	}
+
+	return ret;
+}
+
+
+static int
+atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+		   u8 *seq)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_key wk;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+		   __func__, ether_sprintf(addr), idx);
+
+	memset(&wk, 0, sizeof(wk));
+	if (addr == NULL)
+		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+	else
+		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+	wk.ik_keyix = idx;
+
+	if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+			   "(addr " MACSTR " key_idx %d)",
+			   __func__, MAC2STR(wk.ik_macaddr), idx);
+		return -1;
+	}
+
+#ifdef WORDS_BIGENDIAN
+	{
+		/*
+		 * wk.ik_keytsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+#ifndef WPA_KEY_RSC_LEN
+#define WPA_KEY_RSC_LEN 8
+#endif
+		u8 tmp[WPA_KEY_RSC_LEN];
+		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));
+#endif /* WORDS_BIGENDIAN */
+	return 0;
+}
+
+
+static int
+atheros_flush(void *priv)
+{
+	u8 allsta[IEEE80211_ADDR_LEN];
+	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+	return atheros_sta_deauth(priv, NULL, allsta,
+				  IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+			     const u8 *addr)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_sta_stats stats;
+
+	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);
+	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));
+			return 0;
+		}
+
+		printf("Failed to get station stats information element.\n");
+		return -1;
+	}
+
+	data->rx_packets = stats.is_stats.ns_rx_data;
+	data->rx_bytes = stats.is_stats.ns_rx_bytes;
+	data->tx_packets = stats.is_stats.ns_tx_data;
+	data->tx_bytes = stats.is_stats.ns_tx_bytes;
+	return 0;
+}
+
+
+static int
+atheros_sta_clear_stats(void *priv, const u8 *addr)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	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);
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+			   sizeof(mlme));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+			   MACSTR ")", __func__, MAC2STR(addr));
+	}
+
+	return ret;
+}
+
+
+static int
+atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+	struct atheros_driver_data *drv = priv;
+	u8 buf[512];
+	struct ieee80211req_getset_appiebuf *app_ie;
+
+	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+		   (unsigned long) ie_len);
+	wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
+
+	wpabuf_free(drv->wpa_ie);
+	drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
+
+	app_ie = (struct ieee80211req_getset_appiebuf *) buf;
+	os_memcpy(&(app_ie->app_buf[0]), ie, ie_len);
+	app_ie->app_buflen = ie_len;
+
+	app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON;
+
+	/* append WPS IE for Beacon */
+	if (drv->wps_beacon_ie != NULL) {
+		os_memcpy(&(app_ie->app_buf[ie_len]),
+			  wpabuf_head(drv->wps_beacon_ie),
+			  wpabuf_len(drv->wps_beacon_ie));
+		app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
+	}
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
+		    app_ie->app_buf, app_ie->app_buflen);
+	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
+		     sizeof(struct ieee80211req_getset_appiebuf) +
+		     app_ie->app_buflen);
+
+	/* append WPS IE for Probe Response */
+	app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP;
+	if (drv->wps_probe_resp_ie != NULL) {
+		os_memcpy(&(app_ie->app_buf[ie_len]),
+			  wpabuf_head(drv->wps_probe_resp_ie),
+			  wpabuf_len(drv->wps_probe_resp_ie));
+		app_ie->app_buflen = ie_len +
+			wpabuf_len(drv->wps_probe_resp_ie);
+	} else
+		app_ie->app_buflen = ie_len;
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
+		    app_ie->app_buf, app_ie->app_buflen);
+	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
+		     sizeof(struct ieee80211req_getset_appiebuf) +
+		     app_ie->app_buflen);
+	return 0;
+}
+
+static int
+atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+		   int reason_code)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+		   __func__, ether_sprintf(addr), reason_code);
+
+	mlme.im_op = IEEE80211_MLME_DEAUTH;
+	mlme.im_reason = reason_code;
+	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
+			   " reason %d)",
+			   __func__, MAC2STR(addr), reason_code);
+	}
+
+	return ret;
+}
+
+static int
+atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+		     int reason_code)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+		   __func__, ether_sprintf(addr), reason_code);
+
+	mlme.im_op = IEEE80211_MLME_DISASSOC;
+	mlme.im_reason = reason_code;
+	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 "
+			   MACSTR " reason %d)",
+			   __func__, MAC2STR(addr), reason_code);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_WPS
+static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	union wpa_event_data event;
+
+	/* Send Probe Request information to WPS processing */
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+		return;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+		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));
+	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_IEEE80211R
+static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	u16 stype;
+	int ielen;
+	const u8 *iebuf;
+
+	/* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
+	if (len < IEEE80211_HDRLEN)
+		return;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+		return;
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+		   (int) len);
+
+	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+			   __func__);
+		return;
+	}
+	switch (stype) {
+	case WLAN_FC_STYPE_ASSOC_REQ:
+		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
+			break;
+		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+		iebuf = mgmt->u.assoc_req.variable;
+		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+		break;
+	case WLAN_FC_STYPE_REASSOC_REQ:
+		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
+			break;
+		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+		iebuf = mgmt->u.reassoc_req.variable;
+		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
+		break;
+	case WLAN_FC_STYPE_ACTION:
+		if (&mgmt->u.action.category > buf + len)
+			break;
+		os_memset(&event, 0, sizeof(event));
+		event.rx_action.da = mgmt->da;
+		event.rx_action.sa = mgmt->sa;
+		event.rx_action.bssid = mgmt->bssid;
+		event.rx_action.category = mgmt->u.action.category;
+		event.rx_action.data = &mgmt->u.action.category;
+		event.rx_action.len = buf + len - event.rx_action.data;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+		break;
+	case WLAN_FC_STYPE_AUTH:
+		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
+			break;
+		os_memset(&event, 0, sizeof(event));
+		os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+		os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
+		event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+		event.auth.status_code =
+			le_to_host16(mgmt->u.auth.status_code);
+		event.auth.auth_transaction =
+			le_to_host16(mgmt->u.auth.auth_transaction);
+		event.auth.ies = mgmt->u.auth.variable;
+		event.auth.ies_len = len - IEEE80211_HDRLEN -
+			sizeof(mgmt->u.auth);
+		wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+		break;
+	default:
+		break;
+	}
+}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_HS20
+static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	union wpa_event_data event;
+
+	/* Send the Action frame for HS20 processing */
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
+	    sizeof(mgmt->u.action.u.public_action))
+		return;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
+	    mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+		return;
+
+	wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_mgmt.frame = (const u8 *) mgmt;
+	event.rx_mgmt.frame_len = len;
+	wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+}
+#endif /* CONFIG_HS20 */
+
+#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
+static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
+				 size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	u16 stype;
+
+	/* Do 11R processing for WNM ACTION frames */
+	if (len < IEEE80211_HDRLEN)
+		return;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+		return;
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+		   (int) len);
+
+	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+			   __func__);
+		return;
+	}
+
+	switch (stype) {
+	case WLAN_FC_STYPE_ACTION:
+		if (&mgmt->u.action.category > buf + len)
+			break;
+		os_memset(&event, 0, sizeof(event));
+		event.rx_action.da = mgmt->da;
+		event.rx_action.sa = mgmt->sa;
+		event.rx_action.bssid = mgmt->bssid;
+		event.rx_action.category = mgmt->u.action.category;
+		event.rx_action.data = &mgmt->u.action.category;
+		event.rx_action.len = buf + len - event.rx_action.data;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+		break;
+	default:
+		break;
+	}
+}
+#endif /* CONFIG_WNM */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+				size_t len)
+{
+#ifdef CONFIG_WPS
+	atheros_raw_recv_wps(ctx, src_addr, buf, len);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+	atheros_raw_recv_11r(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211R */
+#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
+	atheros_raw_recv_11v(ctx, src_addr, buf, len);
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_HS20
+	atheros_raw_recv_hs20(ctx, src_addr, buf, len);
+#endif /* CONFIG_HS20 */
+}
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+
+static int atheros_receive_pkt(struct atheros_driver_data *drv)
+{
+	int ret = 0;
+	struct ieee80211req_set_filter filt;
+
+	wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+	filt.app_filterype = 0;
+#ifdef CONFIG_WPS
+	filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+	filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
+			       IEEE80211_FILTER_TYPE_AUTH |
+			       IEEE80211_FILTER_TYPE_ACTION);
+#endif
+#ifdef CONFIG_WNM
+	filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_HS20
+	filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_HS20 */
+	if (filt.app_filterype) {
+		ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+				   sizeof(struct ieee80211req_set_filter));
+		if (ret)
+			return ret;
+	}
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+				       atheros_raw_receive, drv, 1);
+	if (drv->sock_raw == NULL)
+		return -1;
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+	return ret;
+}
+
+static int atheros_reset_appfilter(struct atheros_driver_data *drv)
+{
+	struct ieee80211req_set_filter filt;
+	filt.app_filterype = 0;
+	return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+			    sizeof(struct ieee80211req_set_filter));
+}
+
+#ifdef CONFIG_WPS
+static int
+atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+	struct atheros_driver_data *drv = priv;
+	u8 buf[512];
+	struct ieee80211req_getset_appiebuf *beac_ie;
+
+	wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
+		   (unsigned long) len, frametype);
+	wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
+
+	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+	beac_ie->app_frmtype = frametype;
+	beac_ie->app_buflen = len;
+	os_memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+	/* append the WPA/RSN IE if it is set already */
+	if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
+	     (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
+	    (drv->wpa_ie != NULL)) {
+		wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
+				drv->wpa_ie);
+		os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
+			  wpabuf_len(drv->wpa_ie));
+		beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
+		    beac_ie->app_buf, beac_ie->app_buflen);
+	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+			    sizeof(struct ieee80211req_getset_appiebuf) +
+			    beac_ie->app_buflen);
+}
+
+static int
+atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+		      const struct wpabuf *proberesp,
+		      const struct wpabuf *assocresp)
+{
+	struct atheros_driver_data *drv = priv;
+
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
+			proberesp);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
+			assocresp);
+	wpabuf_free(drv->wps_beacon_ie);
+	drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
+	wpabuf_free(drv->wps_probe_resp_ie);
+	drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL;
+
+	atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL,
+			   assocresp ? wpabuf_len(assocresp) : 0,
+			   IEEE80211_APPIE_FRAME_ASSOC_RESP);
+	if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+			       beacon ? wpabuf_len(beacon) : 0,
+			       IEEE80211_APPIE_FRAME_BEACON))
+		return -1;
+	return atheros_set_wps_ie(priv,
+				  proberesp ? wpabuf_head(proberesp) : NULL,
+				  proberesp ? wpabuf_len(proberesp): 0,
+				  IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define atheros_set_ap_wps_ie NULL
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_IEEE80211R
+static int
+atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
+		 u16 status_code, const u8 *ie, size_t len)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
+		   __func__, ether_sprintf(addr), status_code);
+
+	mlme.im_op = IEEE80211_MLME_AUTH;
+	mlme.im_reason = status_code;
+	mlme.im_seq = seq;
+	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+	mlme.im_optie_len = len;
+	if (len) {
+		if (len < IEEE80211_MAX_OPT_IE) {
+			os_memcpy(mlme.im_optie, ie, len);
+		} else {
+			wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+				   "opt_ie STA (addr " MACSTR " reason %d, "
+				   "ie_len %d)",
+				   __func__, MAC2STR(addr), status_code,
+				   (int) len);
+			return -1;
+		}
+	}
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
+			   " reason %d)",
+			   __func__, MAC2STR(addr), status_code);
+	}
+	return ret;
+}
+
+static int
+atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
+		  int reassoc, u16 status_code, const u8 *ie, size_t len)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d",
+		   __func__, ether_sprintf(addr), status_code, reassoc);
+
+	if (reassoc)
+		mlme.im_op = IEEE80211_MLME_REASSOC;
+	else
+		mlme.im_op = IEEE80211_MLME_ASSOC;
+	mlme.im_reason = status_code;
+	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+	mlme.im_optie_len = len;
+	if (len) {
+		if (len < IEEE80211_MAX_OPT_IE) {
+			os_memcpy(mlme.im_optie, ie, len);
+		} else {
+			wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
+				   "opt_ie STA (addr " MACSTR " reason %d, "
+				   "ie_len %d)",
+				   __func__, MAC2STR(addr), status_code,
+				   (int) len);
+			return -1;
+		}
+	}
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR
+			   " reason %d)",
+			   __func__, MAC2STR(addr), status_code);
+	}
+	return ret;
+}
+#endif /* CONFIG_IEEE80211R */
+
+static void
+atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+	struct hostapd_data *hapd = drv->hapd;
+	struct ieee80211req_wpaie ie;
+	int ielen = 0;
+	u8 *iebuf = NULL;
+
+	/*
+	 * Fetch negotiated WPA/RSN parameters from the system.
+	 */
+	memset(&ie, 0, sizeof(ie));
+	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
+		 * possible cause for the failure..
+		 */
+		wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
+			   __func__, strerror(errno));
+		goto no_ie;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE",
+		    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+	wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE",
+		    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+#ifdef ATH_WPS_IE
+	wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE",
+		    ie.wps_ie, IEEE80211_MAX_OPT_IE);
+#endif /* ATH_WPS_IE */
+	iebuf = ie.wpa_ie;
+	/* atheros seems to return some random data if WPA/RSN IE is not set.
+	 * Assume the IE was not included if the IE type is unknown. */
+	if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+		iebuf[1] = 0;
+	if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+		/* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+		 * set. This is needed for WPA2. */
+		iebuf = ie.rsn_ie;
+		if (iebuf[0] != WLAN_EID_RSN)
+			iebuf[1] = 0;
+	}
+
+	ielen = iebuf[1];
+
+#ifdef ATH_WPS_IE
+	/* if WPS IE is present, preference is given to WPS */
+	if (ie.wps_ie &&
+	    (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) {
+		iebuf = ie.wps_ie;
+		ielen = ie.wps_ie[1];
+	}
+#endif /* ATH_WPS_IE */
+
+	if (ielen == 0)
+		iebuf = NULL;
+	else
+		ielen += 2;
+
+no_ie:
+	drv_event_assoc(hapd, addr, iebuf, ielen, 0);
+
+	if (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));
+	}
+}
+
+static void
+atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
+				       char *custom, char *end)
+{
+	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+		char *pos;
+		u8 addr[ETH_ALEN];
+		pos = strstr(custom, "addr=");
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "without sender address ignored");
+			return;
+		}
+		pos += 5;
+		if (hwaddr_aton(pos, addr) == 0) {
+			union wpa_event_data data;
+			os_memset(&data, 0, sizeof(data));
+			data.michael_mic_failure.unicast = 1;
+			data.michael_mic_failure.src = addr;
+			wpa_supplicant_event(drv->hapd,
+					     EVENT_MICHAEL_MIC_FAILURE, &data);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "with invalid MAC address");
+		}
+	} else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+		char *key, *value;
+		u32 val;
+		key = custom;
+		while ((key = strchr(key, '\n')) != NULL) {
+			key++;
+			value = strchr(key, '=');
+			if (value == NULL)
+				continue;
+			*value++ = '\0';
+			val = strtoul(value, NULL, 10);
+			if (strcmp(key, "mac") == 0)
+				hwaddr_aton(value, drv->acct_mac);
+			else if (strcmp(key, "rx_packets") == 0)
+				drv->acct_data.rx_packets = val;
+			else if (strcmp(key, "tx_packets") == 0)
+				drv->acct_data.tx_packets = val;
+			else if (strcmp(key, "rx_bytes") == 0)
+				drv->acct_data.rx_bytes = val;
+			else if (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) {
+		/* 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);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+	} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
+		/*
+		 * Atheros driver uses a hack to pass Probe Request frames as a
+		 * binary data in the custom wireless event. The old way (using
+		 * packet sniffing) didn't work when bridging.
+		 * Format: "Manage.prob_req <frame len>" | zero padding | frame
+		 */
+		int len = atoi(custom + 16);
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
+				   "length %d", len);
+			return;
+		}
+		atheros_raw_receive(drv, NULL,
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+	} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
+		/* Format: "Manage.assoc_req <frame len>" | zero padding |
+		 * frame */
+		int len = atoi(custom + 17);
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+				   "assoc_req/auth event length %d", len);
+			return;
+		}
+		atheros_raw_receive(drv, NULL,
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+	} else if (strncmp(custom, "Manage.action ", 14) == 0) {
+		/* Format: "Manage.assoc_req <frame len>" | zero padding |
+		 * frame */
+		int len = atoi(custom + 14);
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+				   "assoc_req/auth event length %d", len);
+			return;
+		}
+		atheros_raw_receive(drv, NULL,
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+	} else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+		/* Format: "Manage.auth <frame len>" | zero padding | frame
+		 */
+		int len = atoi(custom + 12);
+		if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
+			wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
+				   "assoc_req/auth event length %d", len);
+			return;
+		}
+		atheros_raw_receive(drv, NULL,
+				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
+	}
+}
+
+/*
+* Handle size of data problem. WEXT only allows data of 256 bytes for custom
+* events, and p2p data can be much bigger. So the athr driver sends a small
+* event telling me to collect the big data with an ioctl.
+* On the first event, send all pending events to supplicant.
+*/
+static void fetch_pending_big_events(struct atheros_driver_data *drv)
+{
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
+	u16 fc, stype;
+	struct iwreq iwr;
+	size_t data_len;
+	u32 freq, frame_type;
+
+	while (1) {
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+		iwr.u.data.pointer = (void *) tbuf;
+		iwr.u.data.length = sizeof(tbuf);
+		iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
+
+		if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
+		    < 0) {
+			if (errno == ENOSPC) {
+				wpa_printf(MSG_DEBUG, "%s:%d exit",
+					   __func__, __LINE__);
+				return;
+			}
+			wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
+				   "P2P_FETCH_FRAME] failed: %s",
+				   __func__, strerror(errno));
+			return;
+		}
+		data_len = iwr.u.data.length;
+		wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
+			    (u8 *) tbuf, data_len);
+		if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
+			wpa_printf(MSG_DEBUG, "athr: frame too short");
+			continue;
+		}
+		os_memcpy(&freq, tbuf, sizeof(freq));
+		os_memcpy(&frame_type, &tbuf[sizeof(freq)],
+			  sizeof(frame_type));
+		mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
+		data_len -= sizeof(freq) + sizeof(frame_type);
+
+		if (frame_type == IEEE80211_EV_RX_MGMT) {
+			fc = le_to_host16(mgmt->frame_control);
+			stype = WLAN_FC_GET_STYPE(fc);
+
+			wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
+				"freq=%u len=%u", stype, freq, (int) data_len);
+
+			if (stype == WLAN_FC_STYPE_ACTION) {
+				os_memset(&event, 0, sizeof(event));
+				event.rx_mgmt.frame = (const u8 *) mgmt;
+				event.rx_mgmt.frame_len = data_len;
+				wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
+						     &event);
+				continue;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
+				   __func__, frame_type);
+			continue;
+		}
+	}
+}
+
+static void
+atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
+				      int opcode, char *buf, int len)
+{
+	switch (opcode) {
+	case IEEE80211_EV_RX_MGMT:
+		wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
+		fetch_pending_big_events(drv);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+atheros_wireless_event_wireless(struct atheros_driver_data *drv,
+				char *data, 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) {
+		/* Event data may be unaligned, so make a local, aligned copy
+		 * before processing. */
+		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)
+			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVASSOCREQIE ||
+		     iwe->cmd == IWEVCUSTOM)) {
+			/* 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);
+		} else {
+			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case IWEVEXPIRED:
+			drv_event_disassoc(drv->hapd,
+					   (u8 *) iwe->u.addr.sa_data);
+			break;
+		case IWEVREGISTERED:
+			atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+			break;
+		case IWEVASSOCREQIE:
+			/* Driver hack.. Use IWEVASSOCREQIE to bypass
+			 * IWEVCUSTOM size limitations. Need to handle this
+			 * just like IWEVCUSTOM.
+			 */
+		case IWEVCUSTOM:
+			if (custom + iwe->u.data.length > end)
+				return;
+			buf = malloc(iwe->u.data.length + 1);
+			if (buf == NULL)
+				return;		/* XXX */
+			memcpy(buf, custom, iwe->u.data.length);
+			buf[iwe->u.data.length] = '\0';
+
+			if (iwe->u.data.flags != 0) {
+				atheros_wireless_event_atheros_custom(
+					drv, (int) iwe->u.data.flags,
+					buf, len);
+			} else {
+				atheros_wireless_event_wireless_custom(
+					drv, buf, buf + iwe->u.data.length);
+			}
+			free(buf);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+
+static void
+atheros_wireless_event_rtm_newlink(void *ctx,
+				   struct ifinfomsg *ifi, u8 *buf, size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	if (ifi->ifi_index != drv->ifindex)
+		return;
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			atheros_wireless_event_wireless(
+				drv, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static int
+atheros_get_we_version(struct atheros_driver_data *drv)
+{
+	struct iw_range *range;
+	struct iwreq iwr;
+	int minlen;
+	size_t buflen;
+
+	drv->we_version = 0;
+
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
+	buflen = sizeof(struct iw_range) + 500;
+	range = os_zalloc(buflen);
+	if (range == NULL)
+		return -1;
+
+	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;
+
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWRANGE]");
+		free(range);
+		return -1;
+	} else if (iwr.u.data.length >= minlen &&
+		   range->we_version_compiled >= 18) {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+			   "WE(source)=%d enc_capa=0x%x",
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
+		drv->we_version = range->we_version_compiled;
+	}
+
+	os_free(range);
+	return 0;
+}
+
+
+static int
+atheros_wireless_event_init(struct atheros_driver_data *drv)
+{
+	struct netlink_config *cfg;
+
+	atheros_get_we_version(drv);
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		return -1;
+	cfg->ctx = drv;
+	cfg->newlink_cb = atheros_wireless_event_rtm_newlink;
+	drv->netlink = netlink_init(cfg);
+	if (drv->netlink == NULL) {
+		os_free(cfg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+		   int encrypt, const u8 *own_addr, u32 flags)
+{
+	struct atheros_driver_data *drv = priv;
+	unsigned char buf[3000];
+	unsigned char *bp = buf;
+	struct l2_ethhdr *eth;
+	size_t len;
+	int status;
+
+	/*
+	 * Prepend the Ethernet header.  If the caller left us
+	 * space at the front we could just insert it but since
+	 * we don't know we copy to a local buffer.  Given the frequency
+	 * and size of frames this probably doesn't matter.
+	 */
+	len = data_len + sizeof(struct l2_ethhdr);
+	if (len > sizeof(buf)) {
+		bp = malloc(len);
+		if (bp == NULL) {
+			printf("EAPOL frame discarded, cannot malloc temp "
+			       "buffer of size %lu!\n", (unsigned long) len);
+			return -1;
+		}
+	}
+	eth = (struct l2_ethhdr *) bp;
+	memcpy(eth->h_dest, addr, ETH_ALEN);
+	memcpy(eth->h_source, own_addr, ETH_ALEN);
+	eth->h_proto = host_to_be16(ETH_P_EAPOL);
+	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);
+	return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+	struct atheros_driver_data *drv = ctx;
+	drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+			   len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+	struct atheros_driver_data *drv;
+	struct ifreq ifr;
+	struct iwreq iwr;
+	char brname[IFNAMSIZ];
+
+	drv = os_zalloc(sizeof(struct atheros_driver_data));
+	if (drv == NULL) {
+		printf("Could not allocate memory for atheros driver data\n");
+		return NULL;
+	}
+
+	drv->hapd = hapd;
+	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->ioctl_sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		goto bad;
+	}
+	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+	memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		goto bad;
+	}
+	drv->ifindex = ifr.ifr_ifindex;
+
+	drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+					handle_read, drv, 1);
+	if (drv->sock_xmit == NULL)
+		goto bad;
+	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+		goto bad;
+	os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN);
+	if (params->bridge[0]) {
+		wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+			   params->bridge[0]);
+		drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
+						ETH_P_EAPOL, handle_read, drv,
+						1);
+		if (drv->sock_recv == NULL)
+			goto bad;
+	} else if (linux_br_get(brname, drv->iface) == 0) {
+		wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
+			   "EAPOL receive", brname);
+		drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
+						handle_read, drv, 1);
+		if (drv->sock_recv == NULL)
+			goto bad;
+	} else
+		drv->sock_recv = drv->sock_xmit;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+	iwr.u.mode = IW_MODE_MASTER;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWMODE]");
+		printf("Could not set interface to master mode!\n");
+		goto bad;
+	}
+
+	/* mark down during setup */
+	linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+	atheros_set_privacy(drv, 0); /* default to no privacy */
+
+	if (atheros_receive_pkt(drv))
+		goto bad;
+
+	if (atheros_wireless_event_init(drv))
+		goto bad;
+
+	return drv;
+bad:
+	atheros_reset_appfilter(drv);
+	if (drv->sock_raw)
+		l2_packet_deinit(drv->sock_raw);
+	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+		l2_packet_deinit(drv->sock_recv);
+	if (drv->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	if (drv->ioctl_sock >= 0)
+		close(drv->ioctl_sock);
+	if (drv != NULL)
+		free(drv);
+	return NULL;
+}
+
+
+static void
+atheros_deinit(void *priv)
+{
+	struct atheros_driver_data *drv = priv;
+
+	atheros_reset_appfilter(drv);
+	netlink_deinit(drv->netlink);
+	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+	if (drv->ioctl_sock >= 0)
+		close(drv->ioctl_sock);
+	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+		l2_packet_deinit(drv->sock_recv);
+	if (drv->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	if (drv->sock_raw)
+		l2_packet_deinit(drv->sock_raw);
+	wpabuf_free(drv->wpa_ie);
+	wpabuf_free(drv->wps_beacon_ie);
+	wpabuf_free(drv->wps_probe_resp_ie);
+	free(drv);
+}
+
+static int
+atheros_set_ssid(void *priv, const u8 *buf, int len)
+{
+	struct atheros_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.essid.flags = 1; /* SSID active */
+	iwr.u.essid.pointer = (caddr_t) buf;
+	iwr.u.essid.length = len + 1;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCSIWESSID]");
+		printf("len=%d\n", len);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+atheros_get_ssid(void *priv, u8 *buf, int len)
+{
+	struct atheros_driver_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	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) ?
+		IW_ESSID_MAX_SIZE : len;
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCGIWESSID]");
+		ret = -1;
+	} else
+		ret = iwr.u.essid.length;
+
+	return ret;
+}
+
+static int
+atheros_set_countermeasures(void *priv, int enabled)
+{
+	struct atheros_driver_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+atheros_commit(void *priv)
+{
+	struct atheros_driver_data *drv = priv;
+	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
+}
+
+static int atheros_set_authmode(void *priv, int auth_algs)
+{
+	int authmode;
+
+	if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
+	    (auth_algs & WPA_AUTH_ALG_SHARED))
+		authmode = IEEE80211_AUTH_AUTO;
+	else if (auth_algs & WPA_AUTH_ALG_OPEN)
+		authmode = IEEE80211_AUTH_OPEN;
+	else if (auth_algs & WPA_AUTH_ALG_SHARED)
+		authmode = IEEE80211_AUTH_SHARED;
+	else
+		return -1;
+
+	return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
+}
+
+static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
+{
+	/*
+	 * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
+	 * set_generic_elem, and hapd_set_ssid.
+	 */
+
+	wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
+		   "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
+		   "wpa_version=0x%x privacy=%d interworking=%d",
+		   params->pairwise_ciphers, params->group_cipher,
+		   params->key_mgmt_suites, params->auth_algs,
+		   params->wpa_version, params->privacy, params->interworking);
+	wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
+			  params->ssid, params->ssid_len);
+	if (params->hessid)
+		wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
+			   MAC2STR(params->hessid));
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
+			params->beacon_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
+			params->proberesp_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
+			params->assocresp_ies);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
+			     int noack)
+{
+	struct atheros_driver_data *drv = priv;
+	u8 buf[1510];
+	const struct ieee80211_mgmt *mgmt;
+	struct ieee80211req_mgmtbuf *mgmt_frm;
+
+	mgmt = (const struct ieee80211_mgmt *) frm;
+	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);
+	mgmt_frm->buflen = data_len;
+	if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
+		wpa_printf(MSG_INFO, "atheros: Too long frame for "
+			   "atheros_send_mgmt (%u)", (unsigned int) data_len);
+		return -1;
+	}
+	os_memcpy(&mgmt_frm->buf[0], frm, data_len);
+	return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
+			    sizeof(struct ieee80211req_mgmtbuf) + data_len);
+}
+
+
+static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
+			     size_t tspec_ielen)
+{
+	struct atheros_driver_data *drv = priv;
+	int retv;
+	struct ieee80211req_res req;
+	struct ieee80211req_res_addts *addts = &req.u.addts;
+
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	req.type = IEEE80211_RESREQ_ADDTS;
+	os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+	os_memcpy(addts->tspecie, tspec_ie, tspec_ielen);
+	retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+			    sizeof(struct ieee80211req_res));
+	if (retv < 0) {
+		wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED "
+			   "retv = %d", __func__, retv);
+		return -1;
+	}
+	os_memcpy(tspec_ie, addts->tspecie, tspec_ielen);
+	return addts->status;
+}
+
+
+static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211req_res req;
+	struct ieee80211req_res_addnode *addnode = &req.u.addnode;
+
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	req.type = IEEE80211_RESREQ_ADDNODE;
+	os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
+	addnode->auth_alg = auth_alg;
+	return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
+			    sizeof(struct ieee80211req_res));
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/* Use only to set a big param, get will not work. */
+static int
+set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
+{
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+	iwr.u.data.pointer = (void *) data;
+	iwr.u.data.length = len;
+	iwr.u.data.flags = op;
+	wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
+		   __func__, op, op, athr_get_param_name(op), len);
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
+			   "value=0x%x,0x%x failed: %d (%s)",
+			   __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
+			   iwr.u.mode, iwr.u.data.length,
+			   iwr.u.data.flags, errno, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+
+static int atheros_send_action(void *priv, unsigned int freq,
+			       unsigned int wait,
+			       const u8 *dst, const u8 *src,
+			       const u8 *bssid,
+			       const u8 *data, size_t data_len, int no_cck)
+{
+	struct atheros_driver_data *drv = priv;
+	struct ieee80211_p2p_send_action *act;
+	int res;
+
+	act = os_zalloc(sizeof(*act) + data_len);
+	if (act == NULL)
+		return -1;
+	act->freq = freq;
+	os_memcpy(act->dst_addr, dst, ETH_ALEN);
+	os_memcpy(act->src_addr, src, ETH_ALEN);
+	os_memcpy(act->bssid, bssid, ETH_ALEN);
+	os_memcpy(act + 1, data, data_len);
+	wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
+		   MACSTR ", bssid=" MACSTR,
+		   __func__, act->freq, wait, MAC2STR(act->dst_addr),
+		   MAC2STR(act->src_addr), MAC2STR(act->bssid));
+	wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
+	wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
+
+	res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
+			  act, sizeof(*act) + data_len);
+	os_free(act);
+	return res;
+}
+
+
+#ifdef CONFIG_WNM
+static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
+			u8 *ie, u16 *len, enum wnm_oper oper)
+{
+#define IEEE80211_APPIE_MAX    1024 /* max appie buffer size */
+	u8 buf[IEEE80211_APPIE_MAX];
+	struct ieee80211req_getset_appiebuf *tfs_ie;
+	u16 val;
+
+	wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
+		   drv->iface, oper, MAC2STR(peer));
+
+	switch (oper) {
+	case WNM_SLEEP_TFS_REQ_IE_SET:
+		if (*len > IEEE80211_APPIE_MAX -
+		    sizeof(struct ieee80211req_getset_appiebuf)) {
+			wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
+			return -1;
+		}
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
+
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = *len;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		/* copy the ie */
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+		break;
+	case WNM_SLEEP_TFS_RESP_IE_ADD:
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+			sizeof(struct ieee80211req_getset_appiebuf);
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = 0;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+
+		*len = tfs_ie->app_buflen;
+		os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
+		wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
+			   *len);
+		break;
+	case WNM_SLEEP_TFS_RESP_IE_NONE:
+		*len = 0;
+		break;
+	case WNM_SLEEP_TFS_IE_DEL:
+		tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+		tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+		tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+			sizeof(struct ieee80211req_getset_appiebuf);
+		/* Command header for driver */
+		os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+		val = oper;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+		val = 0;
+		os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+		if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+				 IEEE80211_APPIE_MAX)) {
+			wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+				   "%s", __func__, strerror(errno));
+			return -1;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int atheros_wnm_sleep(struct atheros_driver_data *drv,
+			     const u8 *peer, enum wnm_oper oper)
+{
+	u8 *data, *pos;
+	size_t dlen;
+	int ret;
+	u16 val;
+
+	wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
+		   oper, MAC2STR(peer));
+
+	dlen = ETH_ALEN + 2 + 2;
+	data = os_malloc(dlen);
+	if (data == NULL)
+		return -1;
+
+	/* Command header for driver */
+	pos = data;
+	os_memcpy(pos, peer, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	val = oper;
+	os_memcpy(pos, &val, 2);
+	pos += 2;
+
+	val = 0;
+	os_memcpy(pos, &val, 2);
+
+	ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
+
+	os_free(data);
+
+	return ret;
+}
+
+
+static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
+			    u8 *buf, u16 *buf_len)
+{
+	struct atheros_driver_data *drv = priv;
+
+	switch (oper) {
+	case WNM_SLEEP_ENTER_CONFIRM:
+	case WNM_SLEEP_ENTER_FAIL:
+	case WNM_SLEEP_EXIT_CONFIRM:
+	case WNM_SLEEP_EXIT_FAIL:
+		return atheros_wnm_sleep(drv, peer, oper);
+	case WNM_SLEEP_TFS_REQ_IE_SET:
+	case WNM_SLEEP_TFS_RESP_IE_ADD:
+	case WNM_SLEEP_TFS_RESP_IE_NONE:
+	case WNM_SLEEP_TFS_IE_DEL:
+		return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
+	default:
+		wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
+			   oper);
+		return -1;
+	}
+}
+#endif /* CONFIG_WNM */
+
+
+const struct wpa_driver_ops wpa_driver_atheros_ops = {
+	.name			= "atheros",
+	.hapd_init		= atheros_init,
+	.hapd_deinit		= atheros_deinit,
+	.set_ieee8021x		= atheros_set_ieee8021x,
+	.set_privacy		= atheros_set_privacy,
+	.set_key		= atheros_set_key,
+	.get_seqnum		= atheros_get_seqnum,
+	.flush			= atheros_flush,
+	.set_generic_elem	= atheros_set_opt_ie,
+	.sta_set_flags		= atheros_sta_set_flags,
+	.read_sta_data		= atheros_read_sta_driver_data,
+	.hapd_send_eapol	= atheros_send_eapol,
+	.sta_disassoc		= atheros_sta_disassoc,
+	.sta_deauth		= atheros_sta_deauth,
+	.hapd_set_ssid		= atheros_set_ssid,
+	.hapd_get_ssid		= atheros_get_ssid,
+	.set_countermeasures	= atheros_set_countermeasures,
+	.sta_clear_stats	= atheros_sta_clear_stats,
+	.commit			= atheros_commit,
+	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
+	.set_authmode		= atheros_set_authmode,
+	.set_ap			= atheros_set_ap,
+#ifdef CONFIG_IEEE80211R
+	.sta_assoc              = atheros_sta_assoc,
+	.sta_auth               = atheros_sta_auth,
+	.send_mlme       	= atheros_send_mgmt,
+	.add_tspec      	= atheros_add_tspec,
+	.add_sta_node    	= atheros_add_sta_node,
+#endif /* CONFIG_IEEE80211R */
+	.send_action		= atheros_send_action,
+#ifdef CONFIG_WNM
+	.wnm_oper		= atheros_wnm_oper,
+#endif /* CONFIG_WNM */
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_atmel.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_atmel.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_atmel.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,499 +0,0 @@
-/*
- * WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
- * Copyright (c) 2000-2005, ATMEL Corporation
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-/******************************************************************************
-	Copyright 2000-2001 ATMEL Corporation.
-	
-    WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
-    
-    This is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with Atmel wireless lan drivers; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-******************************************************************************/
-
-/*
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_atmel_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-
-#define ATMEL_WPA_IOCTL                (SIOCIWFIRSTPRIV + 2)
-#define ATMEL_WPA_IOCTL_PARAM          (SIOCIWFIRSTPRIV + 3)
-#define ATMEL_WPA_IOCTL_GET_PARAM      (SIOCIWFIRSTPRIV + 4)
-
-
-/* ATMEL_WPA_IOCTL ioctl() cmd: */
-enum {
-    SET_WPA_ENCRYPTION  = 1,
-    SET_CIPHER_SUITES   = 2,
-    MLME_STA_DEAUTH     = 3,
-    MLME_STA_DISASSOC   = 4
-};
-
-/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
-enum {
-            ATMEL_PARAM_WPA = 1,
-            ATMEL_PARAM_PRIVACY_INVOKED = 2,
-            ATMEL_PARAM_WPA_TYPE = 3
-};
-
-#define MAX_KEY_LENGTH      40
-
-struct atmel_param{
-    unsigned char sta_addr[6];
-        int     cmd;
-        u8      alg;
-        u8      key_idx;
-        u8      set_tx;
-        u8      seq[8];
-        u8      seq_len;
-        u16     key_len;
-        u8      key[MAX_KEY_LENGTH];
-    struct{
-        int     reason_code;
-        u8      state;
-    }mlme;
-    u8          pairwise_suite;
-    u8          group_suite;
-    u8          key_mgmt_suite;
-};
-
-    
-    
-static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
-		       struct atmel_param *param,
-		       int len, int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
-		int ret;
-		ret = errno;
-		if (show_err) 
-			perror("ioctl[ATMEL_WPA_IOCTL]");
-		return ret;
-	}
-
-	return 0;
-}
-
-
-static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = param;
-	*i++ = value;
-
-	if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
-		perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
-		ret = -1;
-	}
-	return ret;
-}
-
-
-#if 0
-static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
-				       const char *wpa_ie, size_t wpa_ie_len)
-{
-	struct atmel_param *param;
-	int res;
-	size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-	if (blen < sizeof(*param))
-		blen = sizeof(*param);
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = ATMEL_SET_GENERIC_ELEMENT;
-	param->u.generic_elem.len = wpa_ie_len;
-	os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-	res = atmel_ioctl(drv, param, blen, 1);
-
-	os_free(param);
-
-	return res;
-}
-#endif
-
-
-static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-        int ret = 0;
-	
-        printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-#if 0
-	if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
-		ret = -1;
-#endif
-	if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
-		ret = -1;
-	if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static int wpa_driver_atmel_set_key(const char *ifname, void *priv,
-				    enum wpa_alg alg, const u8 *addr,
-				    int key_idx, int set_tx,
-				    const u8 *seq, size_t seq_len,
-				    const u8 *key, size_t key_len)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	int ret = 0;
-        struct atmel_param *param;
-	u8 *buf;
-        u8 alg_type;
-        
-	size_t blen;
-	char *alg_name;
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		alg_name = "none";
-                alg_type = 0;
-		break;
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		alg_type = 1;
-                break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		alg_type = 2;
-                break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		alg_type = 3;
-                break;
-	default:
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > 8)
-		return -2;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct atmel_param *) buf;
-        
-        param->cmd = SET_WPA_ENCRYPTION; 
-        
-        if (addr == NULL)
-		os_memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		os_memcpy(param->sta_addr, addr, ETH_ALEN);
-        
-        param->alg = alg_type;
-        param->key_idx = key_idx;
-        param->set_tx = set_tx;
-        os_memcpy(param->seq, seq, seq_len);
-        param->seq_len = seq_len;
-        param->key_len = key_len;
-	os_memcpy((u8 *)param->key, key, key_len);
-	
-        if (atmel_ioctl(drv, param, blen, 1)) {
-		wpa_printf(MSG_WARNING, "Failed to set encryption.");
-		/* TODO: show key error*/
-		ret = -1;
-	}
-	os_free(buf);
-
-	return ret;
-}
-
-
-static int wpa_driver_atmel_set_countermeasures(void *priv,
-						 int enabled)
-{
-	/* FIX */
-	printf("wpa_driver_atmel_set_countermeasures - not yet "
-	       "implemented\n");
-	return 0;
-}
-
-
-static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
-				 int reason_code)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	struct atmel_param param;
-	int ret;
-        int mgmt_error = 0xaa;
-        
-	os_memset(&param, 0, sizeof(param));
-	os_memcpy(param.sta_addr, addr, ETH_ALEN);
-	param.cmd = cmd;
-	param.mlme.reason_code = reason_code;
-        param.mlme.state = mgmt_error;
-	ret = atmel_ioctl(drv, &param, sizeof(param), 1);
-	return ret;
-}
-
-
-#if 0
-static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
-				       u8 pairwise_suite, u8 group_suite,
-				       u8 key_mgmt_suite)
-{
-	struct atmel_param param;
-	int ret;
-        
-	os_memset(&param, 0, sizeof(param));
-        param.cmd = SET_CIPHER_SUITES;
-        param.pairwise_suite = pairwise_suite;
-        param.group_suite = group_suite;
-        param.key_mgmt_suite = key_mgmt_suite;
-	        
-	ret = atmel_ioctl(drv, &param, sizeof(param), 1);
-	return ret;
-}
-#endif
-
-
-static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
-					   int reason_code)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	printf("wpa_driver_atmel_deauthenticate\n");
-        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
-				     reason_code);
-
-}
-
-
-static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
-					 int reason_code)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	printf("wpa_driver_atmel_disassociate\n");
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
-				     reason_code);
-
-}
-
-
-#if 0
-/* Atmel driver uses specific values for each cipher suite */
-static int convertSuiteToDriver(enum wpa_cipher suite)
-{
-    u8 suite_type;
-    
-    switch(suite) {
-        case CIPHER_NONE:
-                suite_type =  0;
-                break;
-        case CIPHER_WEP40:
-                suite_type =  1;
-                break;
-        case CIPHER_TKIP:
-                suite_type = 2;
-                break;
-        case CIPHER_WEP104:
-                suite_type = 5;
-                break;
-        case CIPHER_CCMP:
-                suite_type = 3;
-                break;
-        default:
-                suite_type = 2;
-    }
-    
-    return suite_type;
-
-}
-#endif
-    
-static int
-wpa_driver_atmel_associate(void *priv,
-			   struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	int ret = 0;
-#if 0
-        u8 pairwise_suite_driver;
-        u8 group_suite_driver;
-        u8 key_mgmt_suite_driver;
-
-        pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
-        group_suite_driver    = convertSuiteToDriver(params->group_suite);
-        key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
-
-        if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
-					group_suite_driver,
-					key_mgmt_suite_driver) < 0){
-		printf("wpa_driver_atmel_set_suites.\n");
-                ret = -1;
-        }
-        if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
-	        printf("wpa_driver_atmel_set_freq.\n");
-		ret = -1;
-        }
-#endif
-	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-	    < 0) {
-	        printf("FAILED : wpa_driver_atmel_set_ssid.\n");
-		ret = -1;
-        }
-	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
-	        printf("FAILED : wpa_driver_atmel_set_bssid.\n");
-		ret = -1;
-        }
-
-	return ret;
-}
-
-
-static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_driver_atmel_scan(void *priv,
-				 struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_atmel_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_atmel_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	wpa_driver_atmel_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_driver_atmel_deinit(void *priv)
-{
-	struct wpa_driver_atmel_data *drv = priv;
-	wpa_driver_atmel_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_atmel_ops = {
-	.name = "atmel",
-	.desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
-	.get_bssid = wpa_driver_atmel_get_bssid,
-	.get_ssid = wpa_driver_atmel_get_ssid,
-	.set_key = wpa_driver_atmel_set_key,
-	.init = wpa_driver_atmel_init,
-	.deinit = wpa_driver_atmel_deinit,
-	.set_countermeasures = wpa_driver_atmel_set_countermeasures,
-	.scan2 = wpa_driver_atmel_scan,
-	.get_scan_results2 = wpa_driver_atmel_get_scan_results,
-	.deauthenticate = wpa_driver_atmel_deauthenticate,
-	.disassociate = wpa_driver_atmel_disassociate,
-	.associate = wpa_driver_atmel_associate,
-	.set_operstate = wpa_driver_atmel_set_operstate,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_broadcom.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_broadcom.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_broadcom.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,599 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki at gattaca.ru>
- * Copyright (c) 2004, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
-
-#include "includes.h"
-
-#include <sys/ioctl.h>
-
-#include "common.h"
-
-#if 0
-#include <netpacket/packet.h>
-#include <net/ethernet.h>     /* the L2 protocols */
-#else
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>   /* The L2 protocols */
-#endif
-#include <net/if.h>
-#include <typedefs.h>
-
-/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
-#include <wlioctl.h>
-
-#include "driver.h"
-#include "eloop.h"
-
-struct wpa_driver_broadcom_data {
-	void *ctx;
-	int ioctl_sock;
-	int event_sock;
-	char ifname[IFNAMSIZ + 1];
-};
-
-
-#ifndef WLC_DEAUTHENTICATE
-#define WLC_DEAUTHENTICATE 143
-#endif
-#ifndef WLC_DEAUTHENTICATE_WITH_REASON
-#define WLC_DEAUTHENTICATE_WITH_REASON 201
-#endif
-#ifndef WLC_SET_TKIP_COUNTERMEASURES
-#define WLC_SET_TKIP_COUNTERMEASURES 202
-#endif
-
-#if !defined(PSK_ENABLED) /* NEW driver interface */
-#define WL_VERSION 360130
-/* wireless authentication bit vector */
-#define WPA_ENABLED 1
-#define PSK_ENABLED 2
-                                                                                
-#define WAUTH_WPA_ENABLED(wauth)  ((wauth) & WPA_ENABLED)
-#define WAUTH_PSK_ENABLED(wauth)  ((wauth) & PSK_ENABLED)
-#define WAUTH_ENABLED(wauth)    ((wauth) & (WPA_ENABLED | PSK_ENABLED))
-
-#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
-
-typedef wl_wsec_key_t wsec_key_t;
-#endif
-
-typedef struct {
-	uint32 val;
-	struct ether_addr ea;
-	uint16 res;
-} wlc_deauth_t;
-
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-					     void *timeout_ctx);
-
-static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
-			  void *buf, int len)
-{
-	struct ifreq ifr;
-	wl_ioctl_t ioc;
-	int ret = 0;
-
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
-		   drv->ifname, cmd, len, buf);
-	/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
-
-	ioc.cmd = cmd;
-	ioc.buf = buf;
-	ioc.len = len;
-	os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
-	ifr.ifr_data = (caddr_t) &ioc;
-	if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
-		if (cmd != WLC_GET_MAGIC)
-			perror(ifr.ifr_name);
-		wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
-			   cmd, ret);
-	}
-
-	return ret;
-}
-
-static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
-		return 0;
-	
-	os_memset(bssid, 0, ETH_ALEN);
-	return -1;
-}
-
-static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	
-	if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
-		return -1;
-
-	os_memcpy(ssid, s.SSID, s.SSID_len);
-	return s.SSID_len;
-}
-
-static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	unsigned int wauth, wsec;
-	struct ether_addr ea;
-
-	os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
-	if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	if (enable) {
-		wauth = PSK_ENABLED;
-		wsec = TKIP_ENABLED;
-	} else {
-		wauth = 255;
-		wsec &= ~(TKIP_ENABLED | AES_ENABLED);
-	}
-
-	if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	/* FIX: magic number / error handling? */
-	broadcom_ioctl(drv, 122, &ea, sizeof(ea));
-
-	return 0;
-}
-
-static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
-				       enum wpa_alg alg,
-				       const u8 *addr, int key_idx, int set_tx,
-				       const u8 *seq, size_t seq_len,
-				       const u8 *key, size_t key_len)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	int ret;
-	wsec_key_t wkt;
-
-	os_memset(&wkt, 0, sizeof wkt);
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
-		   set_tx ? "PRIMARY " : "", key_idx, alg);
-	if (key && key_len > 0)
-		wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		wkt.algo = CRYPTO_ALGO_OFF;
-		break;
-	case WPA_ALG_WEP:
-		wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
-		break;
-	case WPA_ALG_TKIP:
-		wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
-		break;
-	case WPA_ALG_CCMP:
-		wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
-			       * AES_OCB_MSDU, AES_OCB_MPDU? */
-		break;
-	default:
-		wkt.algo = CRYPTO_ALGO_NALG;
-		break;
-	}
-
-	if (seq && seq_len > 0)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
-
-	if (addr)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
-
-	wkt.index = key_idx;
-	wkt.len = key_len;
-	if (key && key_len > 0) {
-		os_memcpy(wkt.data, key, key_len);
-		if (key_len == 32) {
-			/* hack hack hack XXX */
-			os_memcpy(&wkt.data[16], &key[24], 8);
-			os_memcpy(&wkt.data[24], &key[16], 8);
-		}
-	}
-	/* wkt.algo = CRYPTO_ALGO_...; */
-	wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
-	if (addr && set_tx)
-		os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
-	ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
-	if (addr && set_tx) {
-		/* FIX: magic number / error handling? */
-		broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
-	}
-	return ret;
-}
-
-
-static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
-					      void *sock_ctx)
-{
-	char buf[8192];
-	int left;
-	wl_wpa_header_t *wwh;
-	union wpa_event_data data;
-	u8 *resp_ies = NULL;
-
-	if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
-		return;
-
-	wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
-
-	if ((size_t) left < sizeof(wl_wpa_header_t))
-		return;
-
-	wwh = (wl_wpa_header_t *) buf;
-
-	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
-		return;
-	if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-
-	switch (wwh->type) {
-	case WLC_ASSOC_MSG:
-		left -= WL_WPA_HEADER_LEN;
-		wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
-			   left);
-		if (left > 0) {
-			resp_ies = os_malloc(left);
-			if (resp_ies == NULL)
-				return;
-			os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = left;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
-		os_free(resp_ies);
-		break;
-	case WLC_DISASSOC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
-		wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
-		break;
-	case WLC_PTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 1;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	case WLC_GTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 0;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
-			   wwh->type);
-		break;
-	}
-}	
-
-static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct sockaddr_ll ll;
-	struct wpa_driver_broadcom_data *drv;
-	struct ifreq ifr;
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-
-	s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
-	if (s < 0) {
-		perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	os_memset(&ll, 0, sizeof(ll));
-	ll.sll_family = AF_PACKET;
-	ll.sll_protocol = ntohs(ETH_P_802_2);
-	ll.sll_ifindex = ifr.ifr_ifindex;
-	ll.sll_hatype = 0;
-	ll.sll_pkttype = PACKET_HOST;
-	ll.sll_halen = 0;
-
-	if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("bind(netlink)");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
-				 NULL);
-	drv->event_sock = s;
-	wpa_driver_broadcom_set_wpa(drv, 1);
-
-	return drv;
-}
-
-static void wpa_driver_broadcom_deinit(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wpa_driver_broadcom_set_wpa(drv, 0);
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_unregister_read_sock(drv->event_sock);
-	close(drv->event_sock);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static int wpa_driver_broadcom_set_countermeasures(void *priv,
-						   int enabled)
-{
-#if 0
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* FIX: ? */
-	return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
-			      sizeof(enabled));
-#else
-	return 0;
-#endif
-}
-
-static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
-	int _restrict = (enabled ? 1 : 0);
-	
-	if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, 
-			   &_restrict, sizeof(_restrict)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
-			   &_restrict, sizeof(_restrict)) < 0)
-		return -1;
-
-	return 0;
-}
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-					     void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-static int wpa_driver_broadcom_scan(void *priv,
-				    struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t wst = { 0, "" };
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
-		wst.SSID_len = ssid_len;
-		os_memcpy(wst.SSID, ssid, ssid_len);
-	}
-	
-	if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
-		return -1;
-
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static const int frequency_list[] = { 
-	2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484 
-};
-
-struct bss_ie_hdr {
-	u8 elem_id;
-	u8 len;
-	u8 oui[3];
-	/* u8 oui_type; */
-	/* u16 version; */
-} __attribute__ ((packed));
-
-static struct wpa_scan_results *
-wpa_driver_broadcom_get_scan_results(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	char *buf;
-	wl_scan_results_t *wsr;
-	wl_bss_info_t *wbi;
-	size_t ap_num;
-	struct wpa_scan_results *res;
-
-	buf = os_malloc(WLC_IOCTL_MAXLEN);
-	if (buf == NULL)
-		return NULL;
-
-	wsr = (wl_scan_results_t *) buf;
-
-	wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
-	wsr->version = 107;
-	wsr->count = 0;
-
-	if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
-		struct wpa_scan_res *r;
-		r = os_malloc(sizeof(*r) + wbi->ie_length);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
-		r->freq = frequency_list[wbi->channel - 1];
-		/* get ie's */
-		os_memcpy(r + 1, wbi + 1, wbi->ie_length);
-		r->ie_len = wbi->ie_length;
-
-		wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
-	}
-
-	wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
-		   "BSSes)",
-		   wsr->buflen, (unsigned long) ap_num);
-	
-	os_free(buf);
-	return res;
-	}
-
-static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
-					      int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_deauth_t wdt;
-	wdt.val = reason_code;
-	os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
-	wdt.res = 0x7fff;
-	return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
-			      sizeof(wdt));
-}
-
-static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
-}
-
-static int
-wpa_driver_broadcom_associate(void *priv,
-			      struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	int infra = 1;
-	int auth = 0;
-	int wsec = 4;
-	int dummy;
-	int wpa_auth;
-	int ret;
-
-	ret = wpa_driver_broadcom_set_drop_unencrypted(
-		drv, params->drop_unencrypted);
-
-	s.SSID_len = params->ssid_len;
-	os_memcpy(s.SSID, params->ssid, params->ssid_len);
-
-	switch (params->pairwise_suite) {
-	case CIPHER_WEP40:
-	case CIPHER_WEP104:
-		wsec = 1;
-		break;
-
-	case CIPHER_TKIP:
-		wsec = 2;
-		break;
-
-	case CIPHER_CCMP:
-		wsec = 4;
-		break;
-
-	default:
-		wsec = 0;
-		break;
-	}
-
-	switch (params->key_mgmt_suite) {
-	case KEY_MGMT_802_1X:
-		wpa_auth = 1;
-		break;
-
-	case KEY_MGMT_PSK:
-		wpa_auth = 2;
-		break;
-
-	default:
-		wpa_auth = 255;
-		break;
-	}
-
-	/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
-	 * group_suite, key_mgmt_suite);
-	 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
-	 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
-
-	if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
-			   sizeof(wpa_auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
-		return -1;
-
-	return ret;
-}
-
-const struct wpa_driver_ops wpa_driver_broadcom_ops = {
-	.name = "broadcom",
-	.desc = "Broadcom wl.o driver",
-	.get_bssid = wpa_driver_broadcom_get_bssid,
-	.get_ssid = wpa_driver_broadcom_get_ssid,
-	.set_key = wpa_driver_broadcom_set_key,
-	.init = wpa_driver_broadcom_init,
-	.deinit = wpa_driver_broadcom_deinit,
-	.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
-	.scan2 = wpa_driver_broadcom_scan,
-	.get_scan_results2 = wpa_driver_broadcom_get_scan_results,
-	.deauthenticate = wpa_driver_broadcom_deauthenticate,
-	.disassociate = wpa_driver_broadcom_disassociate,
-	.associate = wpa_driver_broadcom_associate,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_bsd.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_bsd.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_bsd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1542 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with BSD net80211 layer
- * Copyright (c) 2004, Sam Leffler <sam at errno.com>
- * Copyright (c) 2004, 2Wire, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include <net/if.h>
-#include <net/if_media.h>
-
-#ifdef __NetBSD__
-#include <net/if_ether.h>
-#else
-#include <net/ethernet.h>
-#endif
-#include <net/route.h>
-
-#ifdef __DragonFly__
-#include <netproto/802_11/ieee80211_ioctl.h>
-#include <netproto/802_11/ieee80211_dragonfly.h>
-#else /* __DragonFly__ */
-#ifdef __GLIBC__
-#include <netinet/ether.h>
-#endif /* __GLIBC__ */
-#include <net80211/ieee80211.h>
-#include <net80211/ieee80211_ioctl.h>
-#include <net80211/ieee80211_crypto.h>
-#endif /* __DragonFly__ || __GLIBC__ */
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <net80211/ieee80211_freebsd.h>
-#endif
-#if __NetBSD__
-#include <net80211/ieee80211_netbsd.h>
-#endif
-
-#include "l2_packet/l2_packet.h"
-
-struct bsd_driver_data {
-	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 */
-	unsigned int ifindex;		/* interface index */
-	void	*ctx;
-	struct wpa_driver_capa capa;	/* driver capability */
-	int	is_ap;			/* Access point mode */
-	int	prev_roaming;	/* roaming state to restore on deinit */
-	int	prev_privacy;	/* privacy state to restore on deinit */
-	int	prev_wpa;	/* wpa state to restore on deinit */
-};
-
-/* Generic functions for hostapd and wpa_supplicant */
-
-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;
-
-	os_memset(&ireq, 0, sizeof(ireq));
-	os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
-	ireq.i_type = op;
-	ireq.i_val = val;
-	ireq.i_data = (void *) arg;
-	ireq.i_len = arg_len;
-
-	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
-			   "arg_len=%u]: %s", op, val, arg_len,
-			   strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-static int
-bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
-	     int arg_len)
-{
-	struct bsd_driver_data *drv = priv;
-
-	os_memset(ireq, 0, sizeof(*ireq));
-	os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name));
-	ireq->i_type = op;
-	ireq->i_len = arg_len;
-	ireq->i_data = arg;
-
-	if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
-			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-static int
-get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
-{
-	struct ieee80211req ireq;
-
-	if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0)
-		return -1;
-	return ireq.i_len;
-}
-
-static int
-set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
-{
-	return bsd_set80211(drv, op, 0, arg, arg_len);
-}
-
-static int
-set80211param(struct bsd_driver_data *drv, int op, int arg)
-{
-	return bsd_set80211(drv, op, arg, NULL, 0);
-}
-
-static int
-bsd_get_ssid(void *priv, u8 *ssid, int len)
-{
-	struct bsd_driver_data *drv = priv;
-#ifdef SIOCG80211NWID
-	struct ieee80211_nwid nwid;
-	struct ifreq ifr;
-
-	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 ||
-	    nwid.i_len > IEEE80211_NWID_LEN)
-		return -1;
-	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
-	return nwid.i_len;
-#else
-	return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN);
-#endif
-}
-
-static int
-bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
-{
-	struct bsd_driver_data *drv = priv;
-#ifdef SIOCS80211NWID
-	struct ieee80211_nwid nwid;
-	struct ifreq ifr;
-
-	os_memcpy(nwid.i_nwid, ssid, ssid_len);
-	nwid.i_len = ssid_len;
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-	ifr.ifr_data = (void *)&nwid;
-	return ioctl(drv->sock, SIOCS80211NWID, &ifr);
-#else
-	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
-#endif
-}
-
-static int
-bsd_get_if_media(void *priv)
-{
-	struct bsd_driver_data *drv = priv;
-	struct ifmediareq ifmr;
-
-	os_memset(&ifmr, 0, sizeof(ifmr));
-	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
-
-	if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
-		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
-			   strerror(errno));
-		return -1;
-	}
-
-	return ifmr.ifm_current;
-}
-
-static int
-bsd_set_if_media(void *priv, int media)
-{
-	struct bsd_driver_data *drv = priv;
-	struct ifreq ifr;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-	ifr.ifr_media = media;
-
-	if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
-		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
-			   strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
-bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode)
-{
-	int media = bsd_get_if_media(priv);
-
-	if (media < 0)
-		return -1;
-	media &= ~mask;
-	media |= mode;
-	if (bsd_set_if_media(priv, media) < 0)
-		return -1;
-	return 0;
-}
-
-static int
-bsd_del_key(void *priv, const u8 *addr, int key_idx)
-{
-	struct ieee80211req_del_key wk;
-
-	os_memset(&wk, 0, sizeof(wk));
-	if (addr == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx);
-		wk.idk_keyix = key_idx;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__,
-			   MAC2STR(addr));
-		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-		wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE;	/* XXX */
-	}
-
-	return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
-}
-
-static int
-bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
-{
-	struct ieee80211req_mlme mlme;
-
-	os_memset(&mlme, 0, sizeof(mlme));
-	mlme.im_op = op;
-	mlme.im_reason = reason;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
-}
-
-static int
-bsd_ctrl_iface(void *priv, int enable)
-{
-	struct bsd_driver_data *drv = priv;
-	struct ifreq ifr;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-
-	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
-		perror("ioctl[SIOCGIFFLAGS]");
-		return -1;
-	}
-
-	if (enable)
-		ifr.ifr_flags |= IFF_UP;
-	else
-		ifr.ifr_flags &= ~IFF_UP;
-
-	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
-		perror("ioctl[SIOCSIFFLAGS]");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
-bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
-{
-	struct ieee80211req_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
-		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
-		   set_tx, seq_len, key_len);
-
-	if (alg == WPA_ALG_NONE) {
-#ifndef HOSTAPD
-		if (addr == NULL ||
-		    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-			      IEEE80211_ADDR_LEN) == 0)
-			return bsd_del_key(priv, NULL, key_idx);
-		else
-#endif /* HOSTAPD */
-			return bsd_del_key(priv, addr, key_idx);
-	}
-
-	os_memset(&wk, 0, sizeof(wk));
-	switch (alg) {
-	case WPA_ALG_WEP:
-		wk.ik_type = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		wk.ik_type = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg);
-		return -1;
-	}
-
-	wk.ik_flags = IEEE80211_KEY_RECV;
-	if (set_tx)
-		wk.ik_flags |= IEEE80211_KEY_XMIT;
-
-	if (addr == NULL) {
-		os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-		wk.ik_keyix = key_idx;
-	} else {
-		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-		/*
-		 * Deduce whether group/global or unicast key by checking
-		 * the address (yech).  Note also that we can only mark global
-		 * keys default; doing this for a unicast key is an error.
-		 */
-		if (os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-			      IEEE80211_ADDR_LEN) == 0) {
-			wk.ik_flags |= IEEE80211_KEY_GROUP;
-			wk.ik_keyix = key_idx;
-		} else {
-			wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE :
-				key_idx;
-		}
-	}
-	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
-		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
-	wk.ik_keylen = key_len;
-	os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-	os_memcpy(wk.ik_keydata, key, key_len);
-
-	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
-}
-
-static int
-bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
-{
-#ifndef IEEE80211_IOC_APPIE
-	static const char *ciphernames[] =
-		{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
-	int v;
-
-	switch (params->wpa_group) {
-	case WPA_CIPHER_CCMP:
-		v = IEEE80211_CIPHER_AES_CCM;
-		break;
-	case WPA_CIPHER_TKIP:
-		v = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_NONE:
-		v = IEEE80211_CIPHER_NONE;
-		break;
-	default:
-		printf("Unknown group key cipher %u\n",
-			params->wpa_group);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
-		   __func__, ciphernames[v], v);
-	if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u (%s)\n",
-			v, ciphernames[v]);
-		return -1;
-	}
-	if (v == IEEE80211_CIPHER_WEP) {
-		/* key length is done only for specific ciphers */
-		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
-		if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
-			return -1;
-		}
-	}
-
-	v = 0;
-	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
-		v |= 1<<IEEE80211_CIPHER_AES_CCM;
-	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
-		v |= 1<<IEEE80211_CIPHER_TKIP;
-	if (params->wpa_pairwise & WPA_CIPHER_NONE)
-		v |= 1<<IEEE80211_CIPHER_NONE;
-	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
-	if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
-		   __func__, params->wpa_key_mgmt);
-	if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
-			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
-		return -1;
-	}
-
-	v = 0;
-	if (params->rsn_preauth)
-		v |= BIT(0);
-	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
-		   __func__, params->rsn_preauth);
-	if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
-		return -1;
-	}
-#endif /* IEEE80211_IOC_APPIE */
-
-	wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
-	if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
-
-	if (!params->enabled) {
-		/* XXX restore state */
-		return set80211param(priv, IEEE80211_IOC_AUTHMODE,
-				     IEEE80211_AUTH_AUTO);
-	}
-	if (!params->wpa && !params->ieee802_1x) {
-		wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled",
-			   __func__);
-		return -1;
-	}
-	if (params->wpa && bsd_configure_wpa(priv, params) != 0) {
-		wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state",
-			   __func__);
-		return -1;
-	}
-	if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
-		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X",
-			   __func__);
-		return -1;
-	}
-	return bsd_ctrl_iface(priv, 1);
-}
-
-static int
-bsd_set_sta_authorized(void *priv, const u8 *addr,
-		       int total_flags, int flags_or, int flags_and)
-{
-	int authorized = -1;
-
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		authorized = 1;
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		authorized = 0;
-
-	if (authorized < 0)
-		return 0;
-
-	return bsd_send_mlme_param(priv, authorized ?
-				   IEEE80211_MLME_AUTHORIZE :
-				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
-}
-
-static void
-bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
-{
-	struct ieee80211req_wpaie ie;
-	int ielen = 0;
-	u8 *iebuf = NULL;
-
-	/*
-	 * Fetch and validate any negotiated WPA/RSN parameters.
-	 */
-	memset(&ie, 0, sizeof(ie));
-	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
-	if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
-		printf("Failed to get WPA/RSN information element.\n");
-		goto no_ie;
-	}
-	iebuf = ie.wpa_ie;
-	ielen = ie.wpa_ie[1];
-	if (ielen == 0)
-		iebuf = NULL;
-	else
-		ielen += 2;
-
-no_ie:
-	drv_event_assoc(ctx, addr, iebuf, ielen);
-}
-
-static int
-bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-	       int encrypt, const u8 *own_addr)
-{
-	struct bsd_driver_data *drv = priv;
-
-	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len);
-
-	return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data,
-			      data_len);
-}
-
-static int
-bsd_set_freq(void *priv, u16 channel)
-{
-	struct bsd_driver_data *drv = priv;
-#ifdef SIOCS80211CHANNEL
-	struct ieee80211chanreq creq;
-#endif /* SIOCS80211CHANNEL */
-	u32 mode;
-
-	if (channel < 14)
-		mode = IFM_IEEE80211_11G;
-	else if (channel == 14)
-		mode = IFM_IEEE80211_11B;
-	else
-		mode = IFM_IEEE80211_11A;
-	if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
-			   __func__);
-		return -1;
-	}
-
-#ifdef SIOCS80211CHANNEL
-	os_memset(&creq, 0, sizeof(creq));
-	os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name));
-	creq.i_channel = channel;
-	return ioctl(drv->sock, SIOCS80211CHANNEL, &creq);
-#else /* SIOCS80211CHANNEL */
-	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
-#endif /* SIOCS80211CHANNEL */
-}
-
-static int
-bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
-{
-#ifdef IEEE80211_IOC_APPIE
-	wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__,
-		   (unsigned long)ie_len);
-	return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA,
-			    ie, ie_len);
-#endif /* IEEE80211_IOC_APPIE */
-	return 0;
-}
-
-
-#ifdef HOSTAPD
-
-/*
- * Avoid conflicts with hostapd definitions by undefining couple of defines
- * from net80211 header files.
- */
-#undef RSN_VERSION
-#undef WPA_VERSION
-#undef WPA_OUI_TYPE
-
-static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			  int reason_code);
-
-static const char *
-ether_sprintf(const u8 *addr)
-{
-	static char buf[sizeof(MACSTR)];
-
-	if (addr != NULL)
-		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	else
-		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
-	return buf;
-}
-
-static int
-bsd_set_privacy(void *priv, int enabled)
-{
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-
-	return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled);
-}
-
-static int
-bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
-	       u8 *seq)
-{
-	struct ieee80211req_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
-		   __func__, ether_sprintf(addr), idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr == NULL)
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-	else
-		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = idx;
-
-	if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
-		printf("Failed to get encryption.\n");
-		return -1;
-	}
-
-#ifdef WORDS_BIGENDIAN
-	{
-		/*
-		 * wk.ik_keytsc is in host byte order (big endian), need to
-		 * swap it to match with the byte order used in WPA.
-		 */
-		int i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		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));
-#endif /* WORDS_BIGENDIAN */
-	return 0;
-}
-
-
-static int 
-bsd_flush(void *priv)
-{
-	u8 allsta[IEEE80211_ADDR_LEN];
-
-	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
-	return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE);
-}
-
-
-static int
-bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
-			 const u8 *addr)
-{
-	struct ieee80211req_sta_stats stats;
-
-	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
-	if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats))
-	    > 0) {
-		/* XXX? do packets counts include non-data frames? */
-		data->rx_packets = stats.is_stats.ns_rx_data;
-		data->rx_bytes = stats.is_stats.ns_rx_bytes;
-		data->tx_packets = stats.is_stats.ns_tx_data;
-		data->tx_bytes = stats.is_stats.ns_tx_bytes;
-	}
-	return 0;
-}
-
-static int
-bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
-{
-	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
-				   addr);
-}
-
-static int
-bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-		 int reason_code)
-{
-	return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
-				   addr);
-}
-
-static void
-bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
-{
-	struct bsd_driver_data *drv = ctx;
-	char buf[2048];
-	struct if_announcemsghdr *ifan;
-	struct rt_msghdr *rtm;
-	struct ieee80211_michael_event *mic;
-	struct ieee80211_join_event *join;
-	struct ieee80211_leave_event *leave;
-	int n;
-	union wpa_event_data data;
-
-	n = read(sock, buf, sizeof(buf));
-	if (n < 0) {
-		if (errno != EINTR && errno != EAGAIN)
-			perror("read(PF_ROUTE)");
-		return;
-	}
-
-	rtm = (struct rt_msghdr *) buf;
-	if (rtm->rtm_version != RTM_VERSION) {
-		wpa_printf(MSG_DEBUG, "Routing message version %d not "
-			"understood\n", rtm->rtm_version);
-		return;
-	}
-	ifan = (struct if_announcemsghdr *) rtm;
-	switch (rtm->rtm_type) {
-	case RTM_IEEE80211:
-		switch (ifan->ifan_what) {
-		case RTM_IEEE80211_ASSOC:
-		case RTM_IEEE80211_REASSOC:
-		case RTM_IEEE80211_DISASSOC:
-		case RTM_IEEE80211_SCAN:
-			break;
-		case RTM_IEEE80211_LEAVE:
-			leave = (struct ieee80211_leave_event *) &ifan[1];
-			drv_event_disassoc(drv->hapd, leave->iev_addr);
-			break;
-		case RTM_IEEE80211_JOIN:
-#ifdef RTM_IEEE80211_REJOIN
-		case RTM_IEEE80211_REJOIN:
-#endif
-			join = (struct ieee80211_join_event *) &ifan[1];
-			bsd_new_sta(drv, drv->hapd, join->iev_addr);
-			break;
-		case RTM_IEEE80211_REPLAY:
-			/* ignore */
-			break;
-		case RTM_IEEE80211_MICHAEL:
-			mic = (struct ieee80211_michael_event *) &ifan[1];
-			wpa_printf(MSG_DEBUG,
-				"Michael MIC failure wireless event: "
-				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
-				MAC2STR(mic->iev_src));
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = mic->iev_src;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-			break;
-		}
-		break;
-	}
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
-	struct bsd_driver_data *drv = ctx;
-	drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
-}
-
-static int
-hostapd_bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-	return bsd_set_freq(priv, freq->channel);
-}
-
-static void *
-bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
-{
-	struct bsd_driver_data *drv;
-
-	drv = os_zalloc(sizeof(struct bsd_driver_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for bsd driver data\n");
-		goto bad;
-	}
-
-	drv->hapd = hapd;
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		goto bad;
-	}
-	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
-
-	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
-					handle_read, drv, 0);
-	if (drv->sock_xmit == NULL)
-		goto bad;
-	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
-		goto bad;
-
-	/* mark down during setup */
-	if (bsd_ctrl_iface(drv, 0) < 0)
-		goto bad;
-
-	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
-	if (drv->route < 0) {
-		perror("socket(PF_ROUTE,SOCK_RAW)");
-		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;
-	}
-
-	return drv;
-bad:
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock >= 0)
-		close(drv->sock);
-	if (drv != NULL)
-		os_free(drv);
-	return NULL;
-}
-
-
-static void
-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->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	os_free(drv);
-}
-
-#else /* HOSTAPD */
-
-static int
-get80211param(struct bsd_driver_data *drv, int op)
-{
-	struct ieee80211req ireq;
-
-	if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0)
-		return -1;
-	return ireq.i_val;
-}
-
-static int
-wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
-{
-	struct bsd_driver_data *drv = priv;
-#ifdef SIOCG80211BSSID
-	struct ieee80211_bssid bs;
-
-	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
-	if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
-		return -1;
-	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
-	return 0;
-#else
-	return get80211var(drv, IEEE80211_IOC_BSSID,
-		bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
-#endif
-}
-
-static int
-wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
-{
-	struct bsd_driver_data *drv = priv;
-	return bsd_get_ssid(drv, ssid, 0);
-}
-
-static int
-wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie,
-			  size_t wpa_ie_len)
-{
-#ifdef IEEE80211_IOC_APPIE
-	return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len);
-#else /* IEEE80211_IOC_APPIE */
-	return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
-#endif /* IEEE80211_IOC_APPIE */
-}
-
-static int
-wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
-{
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
-		__FUNCTION__, wpa, privacy);
-
-	if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
-		ret = -1;
-	if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0)
-		ret = -1;
-	if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-static int
-wpa_driver_bsd_set_wpa(void *priv, int enabled)
-{
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
-}
-
-static int
-wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
-{
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-	return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled);
-}
-
-
-static int
-wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
-{
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-	return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
-}
-
-static int
-wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
-	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
-				   addr);
-}
-
-static int
-wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-	return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
-				   addr);
-}
-
-static int
-wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
-{
-	int authmode;
-
-	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
-	    (auth_alg & WPA_AUTH_ALG_SHARED))
-		authmode = IEEE80211_AUTH_AUTO;
-	else if (auth_alg & WPA_AUTH_ALG_SHARED)
-		authmode = IEEE80211_AUTH_SHARED;
-	else
-		authmode = IEEE80211_AUTH_OPEN;
-
-	return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode);
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
-	struct bsd_driver_data *drv = ctx;
-
-	drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
-}
-
-static int
-wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
-{
-	struct bsd_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	u32 mode;
-	u16 channel;
-	int privacy;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG,
-		"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
-		, __func__
-		   , (unsigned int) params->ssid_len, params->ssid
-		, (unsigned int) params->wpa_ie_len
-		, params->pairwise_suite
-		, params->group_suite
-		, params->key_mgmt_suite
-	);
-
-	switch (params->mode) {
-	case IEEE80211_MODE_INFRA:
-		mode = 0 /* STA */;
-		break;
-	case IEEE80211_MODE_IBSS:
-		mode = IFM_IEEE80211_IBSS;
-		break;
-	case IEEE80211_MODE_AP:
-		mode = IFM_IEEE80211_HOSTAP;
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__);
-		return -1;
-	}
-	if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
-			   __func__);
-		return -1;
-	}
-
-	if (params->mode == IEEE80211_MODE_AP) {
-		if (params->freq >= 2412 && params->freq <= 2472)
-			channel = (params->freq - 2407) / 5;
-		else if (params->freq == 2484)
-			channel = 14;
-		else if ((params->freq >= 5180 && params->freq <= 5240) ||
-			 (params->freq >= 5745 && params->freq <= 5825))
-			channel = (params->freq - 5000) / 5;
-		else
-			channel = 0;
-		if (bsd_set_freq(drv, channel) < 0)
-			return -1;
-
-		drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
-						handle_read, drv, 0);
-		if (drv->sock_xmit == NULL)
-			return -1;
-		drv->is_ap = 1;
-		return 0;
-	}
-
-	if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted)
-	    < 0)
-		ret = -1;
-	if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	/* XXX error handling is wrong but unclear what to do... */
-	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
-		return -1;
-
-	privacy = !(params->pairwise_suite == CIPHER_NONE &&
-	    params->group_suite == CIPHER_NONE &&
-	    params->key_mgmt_suite == KEY_MGMT_NONE &&
-	    params->wpa_ie_len == 0);
-	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
-
-	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
-		return -1;
-
-	if (params->wpa_ie_len &&
-	    set80211param(drv, IEEE80211_IOC_WPA,
-			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
-		return -1;
-
-	os_memset(&mlme, 0, sizeof(mlme));
-	mlme.im_op = IEEE80211_MLME_ASSOC;
-	if (params->ssid != NULL)
-		os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
-	mlme.im_ssid_len = params->ssid_len;
-	if (params->bssid != NULL)
-		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
-	if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
-		return -1;
-	return ret;
-}
-
-static int
-wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct bsd_driver_data *drv = priv;
-#ifdef IEEE80211_IOC_SCAN_MAX_SSID
-	struct ieee80211_scan_req sr;
-	int i;
-#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
-
-	if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
-			   __func__);
-		return -1;
-	}
-
-	if (set80211param(drv, IEEE80211_IOC_ROAMING,
-			  IEEE80211_ROAMING_MANUAL) < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to set "
-			   "wpa_supplicant-based roaming: %s", __func__,
-			   strerror(errno));
-		return -1;
-	}
-
-	if (wpa_driver_bsd_set_wpa(drv, 1) < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__,
-			   strerror(errno));
-		return -1;
-	}
-
-	/* NB: interface must be marked UP to do a scan */
-	if (bsd_ctrl_iface(drv, 1) < 0)
-		return -1;
-
-#ifdef IEEE80211_IOC_SCAN_MAX_SSID
-	os_memset(&sr, 0, sizeof(sr));
-	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE |
-		IEEE80211_IOC_SCAN_NOJOIN;
-	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
-	if (params->num_ssids > 0) {
-		sr.sr_nssid = params->num_ssids;
-#if 0
-		/* Boundary check is done by upper layer */
-		if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID)
-			sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID;
-#endif
-
-		/* NB: check scan cache first */
-		sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK;
-	}
-	for (i = 0; i < sr.sr_nssid; i++) {
-		sr.sr_ssid[i].len = params->ssids[i].ssid_len;
-		os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid,
-			  sr.sr_ssid[i].len);
-	}
-
-	/* NB: net80211 delivers a scan complete event so no need to poll */
-	return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr));
-#else /* IEEE80211_IOC_SCAN_MAX_SSID */
-	/* set desired ssid before scan */
-	if (bsd_set_ssid(drv, params->ssids[0].ssid,
-			 params->ssids[0].ssid_len) < 0)
-		return -1;
-
-	/* NB: net80211 delivers a scan complete event so no need to poll */
-	return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
-#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
-}
-
-static void
-wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
-{
-	struct bsd_driver_data *drv = sock_ctx;
-	char buf[2048];
-	struct if_announcemsghdr *ifan;
-	struct if_msghdr *ifm;
-	struct rt_msghdr *rtm;
-	union wpa_event_data event;
-	struct ieee80211_michael_event *mic;
-	struct ieee80211_leave_event *leave;
-	struct ieee80211_join_event *join;
-	int n;
-
-	n = read(sock, buf, sizeof(buf));
-	if (n < 0) {
-		if (errno != EINTR && errno != EAGAIN)
-			perror("read(PF_ROUTE)");
-		return;
-	}
-
-	rtm = (struct rt_msghdr *) buf;
-	if (rtm->rtm_version != RTM_VERSION) {
-		wpa_printf(MSG_DEBUG, "Routing message version %d not "
-			"understood\n", rtm->rtm_version);
-		return;
-	}
-	os_memset(&event, 0, sizeof(event));
-	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:
-			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-		default:
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
-			   event.interface_status.ifname,
-			   ifan->ifan_what == IFAN_DEPARTURE ?
-				"removed" : "added");
-		wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
-		break;
-	case RTM_IEEE80211:
-		ifan = (struct if_announcemsghdr *) rtm;
-		if (ifan->ifan_index != drv->ifindex)
-			break;
-		switch (ifan->ifan_what) {
-		case RTM_IEEE80211_ASSOC:
-		case RTM_IEEE80211_REASSOC:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
-			break;
-		case RTM_IEEE80211_DISASSOC:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
-			break;
-		case RTM_IEEE80211_SCAN:
-			if (drv->is_ap)
-				break;
-			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
-			break;
-		case RTM_IEEE80211_LEAVE:
-			leave = (struct ieee80211_leave_event *) &ifan[1];
-			drv_event_disassoc(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);
-			break;
-		case RTM_IEEE80211_REPLAY:
-			/* ignore */
-			break;
-		case RTM_IEEE80211_MICHAEL:
-			mic = (struct ieee80211_michael_event *) &ifan[1];
-			wpa_printf(MSG_DEBUG,
-				"Michael MIC failure wireless event: "
-				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
-				MAC2STR(mic->iev_src));
-
-			os_memset(&event, 0, sizeof(event));
-			event.michael_mic_failure.unicast =
-				!IEEE80211_IS_MULTICAST(mic->iev_dst);
-			wpa_supplicant_event(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;
-			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
-				   event.interface_status.ifname);
-			wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
-		}
-		break;
-	}
-}
-
-static void
-wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
-			      struct ieee80211req_scan_result *sr)
-{
-	struct wpa_scan_res *result, **tmp;
-	size_t extra_len;
-	u8 *pos;
-
-	extra_len = 2 + sr->isr_ssid_len;
-	extra_len += 2 + sr->isr_nrates;
-	extra_len += 3; /* ERP IE */
-	extra_len += sr->isr_ie_len;
-
-	result = os_zalloc(sizeof(*result) + extra_len);
-	if (result == NULL)
-		return;
-	os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
-	result->freq = sr->isr_freq;
-	result->beacon_int = sr->isr_intval;
-	result->caps = sr->isr_capinfo;
-	result->qual = sr->isr_rssi;
-	result->noise = sr->isr_noise;
-
-	pos = (u8 *)(result + 1);
-
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = sr->isr_ssid_len;
-	os_memcpy(pos, sr + 1, sr->isr_ssid_len);
-	pos += sr->isr_ssid_len;
-
-	/*
-	 * Deal all rates as supported rate.
-	 * Because net80211 doesn't report extended supported rate or not.
-	 */
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = sr->isr_nrates;
-	os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
-	pos += sr->isr_nrates;
-
-	*pos++ = WLAN_EID_ERP_INFO;
-	*pos++ = 1;
-	*pos++ = sr->isr_erp;
-
-	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
-	pos += sr->isr_ie_len;
-
-	result->ie_len = pos - (u8 *)(result + 1);
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(result);
-		return;
-	}
-	tmp[res->num++] = result;
-	res->res = tmp;
-}
-
-struct wpa_scan_results *
-wpa_driver_bsd_get_scan_results2(void *priv)
-{
-	struct ieee80211req_scan_result *sr;
-	struct wpa_scan_results *res;
-	int len, rest;
-	uint8_t buf[24*1024], *pos;
-
-	len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
-	if (len < 0)
-		return NULL;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	pos = buf;
-	rest = len;
-	while (rest >= sizeof(struct ieee80211req_scan_result)) {
-		sr = (struct ieee80211req_scan_result *)pos;
-		wpa_driver_bsd_add_scan_entry(res, sr);
-		pos += sr->isr_len;
-		rest -= sr->isr_len;
-	}
-
-	wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
-		   len, (unsigned long)res->num);
-
-	return res;
-}
-
-static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
-{
-#ifdef IEEE80211_IOC_DEVCAPS
-/* kernel definitions copied from net80211/ieee80211_var.h */
-#define IEEE80211_CIPHER_WEP            0
-#define IEEE80211_CIPHER_TKIP           1
-#define IEEE80211_CIPHER_AES_CCM        3
-#define IEEE80211_CRYPTO_WEP            (1<<IEEE80211_CIPHER_WEP)
-#define IEEE80211_CRYPTO_TKIP           (1<<IEEE80211_CIPHER_TKIP)
-#define IEEE80211_CRYPTO_AES_CCM        (1<<IEEE80211_CIPHER_AES_CCM)
-#define IEEE80211_C_HOSTAP      0x00000400      /* CAPABILITY: HOSTAP avail */
-#define IEEE80211_C_WPA1        0x00800000      /* CAPABILITY: WPA1 avail */
-#define IEEE80211_C_WPA2        0x01000000      /* CAPABILITY: WPA2 avail */
-	struct ieee80211_devcaps_req devcaps;
-
-	if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps,
-			sizeof(devcaps)) < 0) {
-		wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s",
-			   strerror(errno));
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x",
-		   __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps);
-
-	if (devcaps.dc_drivercaps & IEEE80211_C_WPA1)
-		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-			WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
-	if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
-		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-			WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-
-	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
-			WPA_DRIVER_CAPA_ENC_WEP104;
-	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP)
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-
-	if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
-#undef IEEE80211_CIPHER_WEP
-#undef IEEE80211_CIPHER_TKIP
-#undef IEEE80211_CIPHER_AES_CCM
-#undef IEEE80211_CRYPTO_WEP
-#undef IEEE80211_CRYPTO_TKIP
-#undef IEEE80211_CRYPTO_AES_CCM
-#undef IEEE80211_C_HOSTAP
-#undef IEEE80211_C_WPA1
-#undef IEEE80211_C_WPA2
-#else /* IEEE80211_IOC_DEVCAPS */
-	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
-	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-		WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP |
-		WPA_DRIVER_CAPA_ENC_CCMP;
-	drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
-#endif /* IEEE80211_IOC_DEVCAPS */
-#ifdef IEEE80211_IOC_SCAN_MAX_SSID
-	drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID;
-#else /* IEEE80211_IOC_SCAN_MAX_SSID */
-	drv->capa.max_scan_ssids = 1;
-#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
-	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
-		WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	return 0;
-}
-
-static void *
-wpa_driver_bsd_init(void *ctx, const char *ifname)
-{
-#define	GETPARAM(drv, param, v) \
-	(((v) = get80211param(drv, param)) != -1)
-	struct bsd_driver_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	/*
-	 * NB: We require the interface name be mappable to an index.
-	 *     This implies we do not support having wpa_supplicant
-	 *     wait for an interface to appear.  This seems ok; that
-	 *     doesn't belong here; it's really the job of devd.
-	 */
-	drv->ifindex = if_nametoindex(ifname);
-	if (drv->ifindex == 0) {
-		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
-			   __func__, ifname);
-		goto fail1;
-	}
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail1;
-	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;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-
-	/* Down interface during setup. */
-	if (bsd_ctrl_iface(drv, 0) < 0)
-		goto fail;
-
-	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
-		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
-			__func__, strerror(errno));
-		goto fail;
-	}
-	if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
-		wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
-			__func__, strerror(errno));
-		goto fail;
-	}
-	if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
-		wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
-			__func__, strerror(errno));
-		goto fail;
-	}
-
-	if (wpa_driver_bsd_capa(drv))
-		goto fail;
-
-	return drv;
-fail:
-	close(drv->sock);
-fail1:
-	os_free(drv);
-	return NULL;
-#undef GETPARAM
-}
-
-static void
-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);
-
-	/* 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__);
-
-	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);
-}
-
-static int
-wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	struct bsd_driver_data *drv = priv;
-
-	os_memcpy(capa, &drv->capa, sizeof(*capa));
-	return 0;
-}
-#endif /* HOSTAPD */
-
-
-const struct wpa_driver_ops wpa_driver_bsd_ops = {
-	.name			= "bsd",
-	.desc			= "BSD 802.11 support",
-#ifdef HOSTAPD
-	.hapd_init		= bsd_init,
-	.hapd_deinit		= bsd_deinit,
-	.set_privacy		= bsd_set_privacy,
-	.get_seqnum		= bsd_get_seqnum,
-	.flush			= bsd_flush,
-	.read_sta_data		= bsd_read_sta_driver_data,
-	.sta_disassoc		= bsd_sta_disassoc,
-	.sta_deauth		= bsd_sta_deauth,
-	.set_freq		= hostapd_bsd_set_freq,
-#else /* HOSTAPD */
-	.init			= wpa_driver_bsd_init,
-	.deinit			= wpa_driver_bsd_deinit,
-	.get_bssid		= wpa_driver_bsd_get_bssid,
-	.get_ssid		= wpa_driver_bsd_get_ssid,
-	.set_countermeasures	= wpa_driver_bsd_set_countermeasures,
-	.scan2			= wpa_driver_bsd_scan,
-	.get_scan_results2	= wpa_driver_bsd_get_scan_results2,
-	.deauthenticate		= wpa_driver_bsd_deauthenticate,
-	.disassociate		= wpa_driver_bsd_disassociate,
-	.associate		= wpa_driver_bsd_associate,
-	.get_capa		= wpa_driver_bsd_get_capa,
-#endif /* HOSTAPD */
-	.set_key		= bsd_set_key,
-	.set_ieee8021x		= bsd_set_ieee8021x,
-	.hapd_set_ssid		= bsd_set_ssid,
-	.hapd_get_ssid		= bsd_get_ssid,
-	.hapd_send_eapol	= bsd_send_eapol,
-	.sta_set_flags		= bsd_set_sta_authorized,
-	.set_generic_elem	= bsd_set_opt_ie,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_bsd.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_bsd.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_bsd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_bsd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1571 @@
+/*
+ * WPA Supplicant - driver interaction with BSD net80211 layer
+ * Copyright (c) 2004, Sam Leffler <sam at errno.com>
+ * Copyright (c) 2004, 2Wire, Inc
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#else
+#include <net/ethernet.h>
+#endif
+#include <net/route.h>
+
+#ifdef __DragonFly__
+#include <netproto/802_11/ieee80211_ioctl.h>
+#include <netproto/802_11/ieee80211_dragonfly.h>
+#else /* __DragonFly__ */
+#ifdef __GLIBC__
+#include <netinet/ether.h>
+#endif /* __GLIBC__ */
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_crypto.h>
+#endif /* __DragonFly__ || __GLIBC__ */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <net80211/ieee80211_freebsd.h>
+#endif
+#if __NetBSD__
+#include <net80211/ieee80211_netbsd.h>
+#endif
+
+#include "l2_packet/l2_packet.h"
+
+struct bsd_driver_data {
+	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 */
+	unsigned int ifindex;		/* interface index */
+	void	*ctx;
+	struct wpa_driver_capa capa;	/* driver capability */
+	int	is_ap;			/* Access point mode */
+	int	prev_roaming;	/* roaming state to restore on deinit */
+	int	prev_privacy;	/* privacy state to restore on deinit */
+	int	prev_wpa;	/* wpa state to restore on deinit */
+};
+
+/* Generic functions for hostapd and wpa_supplicant */
+
+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;
+
+	os_memset(&ireq, 0, sizeof(ireq));
+	os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name));
+	ireq.i_type = op;
+	ireq.i_val = val;
+	ireq.i_data = (void *) arg;
+	ireq.i_len = arg_len;
+
+	if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, "
+			   "arg_len=%u]: %s", op, val, arg_len,
+			   strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
+	     int arg_len)
+{
+	struct bsd_driver_data *drv = priv;
+
+	os_memset(ireq, 0, sizeof(*ireq));
+	os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name));
+	ireq->i_type = op;
+	ireq->i_len = arg_len;
+	ireq->i_data = arg;
+
+	if (ioctl(drv->sock, SIOCG80211, ireq) < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
+			   "arg_len=%u]: %s", op, arg_len, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
+{
+	struct ieee80211req ireq;
+
+	if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0)
+		return -1;
+	return ireq.i_len;
+}
+
+static int
+set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
+{
+	return bsd_set80211(drv, op, 0, arg, arg_len);
+}
+
+static int
+set80211param(struct bsd_driver_data *drv, int op, int arg)
+{
+	return bsd_set80211(drv, op, arg, NULL, 0);
+}
+
+static int
+bsd_get_ssid(void *priv, u8 *ssid, int len)
+{
+	struct bsd_driver_data *drv = priv;
+#ifdef SIOCG80211NWID
+	struct ieee80211_nwid nwid;
+	struct ifreq ifr;
+
+	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 ||
+	    nwid.i_len > IEEE80211_NWID_LEN)
+		return -1;
+	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+	return nwid.i_len;
+#else
+	return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN);
+#endif
+}
+
+static int
+bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len)
+{
+	struct bsd_driver_data *drv = priv;
+#ifdef SIOCS80211NWID
+	struct ieee80211_nwid nwid;
+	struct ifreq ifr;
+
+	os_memcpy(nwid.i_nwid, ssid, ssid_len);
+	nwid.i_len = ssid_len;
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (void *)&nwid;
+	return ioctl(drv->sock, SIOCS80211NWID, &ifr);
+#else
+	return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+#endif
+}
+
+static int
+bsd_get_if_media(void *priv)
+{
+	struct bsd_driver_data *drv = priv;
+	struct ifmediareq ifmr;
+
+	os_memset(&ifmr, 0, sizeof(ifmr));
+	os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+
+	if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) {
+		wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__,
+			   strerror(errno));
+		return -1;
+	}
+
+	return ifmr.ifm_current;
+}
+
+static int
+bsd_set_if_media(void *priv, int media)
+{
+	struct bsd_driver_data *drv = priv;
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+	ifr.ifr_media = media;
+
+	if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) {
+		wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__,
+			   strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode)
+{
+	int media = bsd_get_if_media(priv);
+
+	if (media < 0)
+		return -1;
+	media &= ~mask;
+	media |= mode;
+	if (bsd_set_if_media(priv, media) < 0)
+		return -1;
+	return 0;
+}
+
+static int
+bsd_del_key(void *priv, const u8 *addr, int key_idx)
+{
+	struct ieee80211req_del_key wk;
+
+	os_memset(&wk, 0, sizeof(wk));
+	if (addr == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx);
+		wk.idk_keyix = key_idx;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__,
+			   MAC2STR(addr));
+		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+		wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE;	/* XXX */
+	}
+
+	return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+}
+
+static int
+bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr)
+{
+	struct ieee80211req_mlme mlme;
+
+	os_memset(&mlme, 0, sizeof(mlme));
+	mlme.im_op = op;
+	mlme.im_reason = reason;
+	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+	return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_ctrl_iface(void *priv, int enable)
+{
+	struct bsd_driver_data *drv = priv;
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+
+	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
+		perror("ioctl[SIOCGIFFLAGS]");
+		return -1;
+	}
+
+	if (enable)
+		ifr.ifr_flags |= IFF_UP;
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
+		perror("ioctl[SIOCSIFFLAGS]");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+	    size_t seq_len, const u8 *key, size_t key_len)
+{
+	struct ieee80211req_key wk;
+
+	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
+		   set_tx, seq_len, key_len);
+
+	if (alg == WPA_ALG_NONE) {
+#ifndef HOSTAPD
+		if (addr == NULL || is_broadcast_ether_addr(addr))
+			return bsd_del_key(priv, NULL, key_idx);
+		else
+#endif /* HOSTAPD */
+			return bsd_del_key(priv, addr, key_idx);
+	}
+
+	os_memset(&wk, 0, sizeof(wk));
+	switch (alg) {
+	case WPA_ALG_WEP:
+		wk.ik_type = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_ALG_TKIP:
+		wk.ik_type = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_ALG_CCMP:
+		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg);
+		return -1;
+	}
+
+	wk.ik_flags = IEEE80211_KEY_RECV;
+	if (set_tx)
+		wk.ik_flags |= IEEE80211_KEY_XMIT;
+
+	if (addr == NULL) {
+		os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+		wk.ik_keyix = key_idx;
+	} else {
+		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+		/*
+		 * Deduce whether group/global or unicast key by checking
+		 * the address (yech).  Note also that we can only mark global
+		 * keys default; doing this for a unicast key is an error.
+		 */
+		if (is_broadcast_ether_addr(addr)) {
+			wk.ik_flags |= IEEE80211_KEY_GROUP;
+			wk.ik_keyix = key_idx;
+		} else {
+			wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE :
+				key_idx;
+		}
+	}
+	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
+		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+	wk.ik_keylen = key_len;
+	if (seq) {
+#ifdef WORDS_BIGENDIAN
+		/*
+		 * wk.ik_keyrsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+		u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
+		for (i = 0; i < seq_len; i++)
+			keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+#else /* WORDS_BIGENDIAN */
+		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+	}
+	os_memcpy(wk.ik_keydata, key, key_len);
+
+	return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+}
+
+static int
+bsd_configure_wpa(void *priv, struct wpa_bss_params *params)
+{
+#ifndef IEEE80211_IOC_APPIE
+	static const char *ciphernames[] =
+		{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
+	int v;
+
+	switch (params->wpa_group) {
+	case WPA_CIPHER_CCMP:
+		v = IEEE80211_CIPHER_AES_CCM;
+		break;
+	case WPA_CIPHER_TKIP:
+		v = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_CIPHER_WEP104:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_WEP40:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_NONE:
+		v = IEEE80211_CIPHER_NONE;
+		break;
+	default:
+		printf("Unknown group key cipher %u\n",
+			params->wpa_group);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
+		   __func__, ciphernames[v], v);
+	if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
+		printf("Unable to set group key cipher to %u (%s)\n",
+			v, ciphernames[v]);
+		return -1;
+	}
+	if (v == IEEE80211_CIPHER_WEP) {
+		/* key length is done only for specific ciphers */
+		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+		if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
+			printf("Unable to set group key length to %u\n", v);
+			return -1;
+		}
+	}
+
+	v = 0;
+	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+		v |= 1<<IEEE80211_CIPHER_AES_CCM;
+	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+		v |= 1<<IEEE80211_CIPHER_TKIP;
+	if (params->wpa_pairwise & WPA_CIPHER_NONE)
+		v |= 1<<IEEE80211_CIPHER_NONE;
+	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+	if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
+		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+		   __func__, params->wpa_key_mgmt);
+	if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
+			  params->wpa_key_mgmt)) {
+		printf("Unable to set key management algorithms to 0x%x\n",
+			params->wpa_key_mgmt);
+		return -1;
+	}
+
+	v = 0;
+	if (params->rsn_preauth)
+		v |= BIT(0);
+	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+		   __func__, params->rsn_preauth);
+	if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
+		printf("Unable to set RSN capabilities to 0x%x\n", v);
+		return -1;
+	}
+#endif /* IEEE80211_IOC_APPIE */
+
+	wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
+	if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
+		printf("Unable to set WPA to %u\n", params->wpa);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+	if (!params->enabled) {
+		/* XXX restore state */
+		return set80211param(priv, IEEE80211_IOC_AUTHMODE,
+				     IEEE80211_AUTH_AUTO);
+	}
+	if (!params->wpa && !params->ieee802_1x) {
+		wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled",
+			   __func__);
+		return -1;
+	}
+	if (params->wpa && bsd_configure_wpa(priv, params) != 0) {
+		wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state",
+			   __func__);
+		return -1;
+	}
+	if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
+		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+		wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X",
+			   __func__);
+		return -1;
+	}
+	return bsd_ctrl_iface(priv, 1);
+}
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr,
+		       int total_flags, int flags_or, int flags_and)
+{
+	int authorized = -1;
+
+	/* For now, only support setting Authorized flag */
+	if (flags_or & WPA_STA_AUTHORIZED)
+		authorized = 1;
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		authorized = 0;
+
+	if (authorized < 0)
+		return 0;
+
+	return bsd_send_mlme_param(priv, authorized ?
+				   IEEE80211_MLME_AUTHORIZE :
+				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
+}
+
+static void
+bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
+{
+	struct ieee80211req_wpaie ie;
+	int ielen = 0;
+	u8 *iebuf = NULL;
+
+	/*
+	 * Fetch and validate any negotiated WPA/RSN parameters.
+	 */
+	memset(&ie, 0, sizeof(ie));
+	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+	if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
+		printf("Failed to get WPA/RSN information element.\n");
+		goto no_ie;
+	}
+	iebuf = ie.wpa_ie;
+	ielen = ie.wpa_ie[1];
+	if (ielen == 0)
+		iebuf = NULL;
+	else
+		ielen += 2;
+
+no_ie:
+	drv_event_assoc(ctx, addr, iebuf, ielen, 0);
+}
+
+static int
+bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+	       int encrypt, const u8 *own_addr, u32 flags)
+{
+	struct bsd_driver_data *drv = priv;
+
+	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len);
+
+	return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data,
+			      data_len);
+}
+
+static int
+bsd_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct bsd_driver_data *drv = priv;
+#ifdef SIOCS80211CHANNEL
+	struct ieee80211chanreq creq;
+#endif /* SIOCS80211CHANNEL */
+	u32 mode;
+	int channel = freq->channel;
+
+	if (channel < 14) {
+		mode =
+#ifdef CONFIG_IEEE80211N
+			freq->ht_enabled ? IFM_IEEE80211_11NG :
+#endif /* CONFIG_IEEE80211N */
+		        IFM_IEEE80211_11G;
+	} else if (channel == 14) {
+		mode = IFM_IEEE80211_11B;
+	} else {
+		mode =
+#ifdef CONFIG_IEEE80211N
+			freq->ht_enabled ? IFM_IEEE80211_11NA :
+#endif /* CONFIG_IEEE80211N */
+			IFM_IEEE80211_11A;
+	}
+	if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to set modulation mode",
+			   __func__);
+		return -1;
+	}
+
+#ifdef SIOCS80211CHANNEL
+	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);
+#else /* SIOCS80211CHANNEL */
+	return set80211param(priv, IEEE80211_IOC_CHANNEL, channel);
+#endif /* SIOCS80211CHANNEL */
+}
+
+static int
+bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+#ifdef IEEE80211_IOC_APPIE
+	wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__,
+		   (unsigned long)ie_len);
+	return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA,
+			    ie, ie_len);
+#endif /* IEEE80211_IOC_APPIE */
+	return 0;
+}
+
+static int
+rtbuf_len(void)
+{
+	size_t len;
+
+	int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
+		wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+			   strerror(errno));
+		len = 2048;
+	}
+
+	return len;
+}
+
+#ifdef HOSTAPD
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from net80211 header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+
+static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reason_code);
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+	static char buf[sizeof(MACSTR)];
+
+	if (addr != NULL)
+		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	else
+		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+	return buf;
+}
+
+static int
+bsd_set_privacy(void *priv, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+	return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled);
+}
+
+static int
+bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+	       u8 *seq)
+{
+	struct ieee80211req_key wk;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+		   __func__, ether_sprintf(addr), idx);
+
+	memset(&wk, 0, sizeof(wk));
+	if (addr == NULL)
+		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+	else
+		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+	wk.ik_keyix = idx;
+
+	if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
+		printf("Failed to get encryption.\n");
+		return -1;
+	}
+
+#ifdef WORDS_BIGENDIAN
+	{
+		/*
+		 * wk.ik_keytsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+		u8 tmp[WPA_KEY_RSC_LEN];
+		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));
+#endif /* WORDS_BIGENDIAN */
+	return 0;
+}
+
+
+static int 
+bsd_flush(void *priv)
+{
+	u8 allsta[IEEE80211_ADDR_LEN];
+
+	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+	return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+			 const u8 *addr)
+{
+	struct ieee80211req_sta_stats stats;
+
+	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+	if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats))
+	    > 0) {
+		/* XXX? do packets counts include non-data frames? */
+		data->rx_packets = stats.is_stats.ns_rx_data;
+		data->rx_bytes = stats.is_stats.ns_rx_bytes;
+		data->tx_packets = stats.is_stats.ns_tx_data;
+		data->tx_bytes = stats.is_stats.ns_tx_bytes;
+	}
+	return 0;
+}
+
+static int
+bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
+{
+	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
+				   addr);
+}
+
+static int
+bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+		 int reason_code)
+{
+	return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
+				   addr);
+}
+
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+	struct bsd_driver_data *drv = ctx;
+	char *buf;
+	struct if_announcemsghdr *ifan;
+	struct rt_msghdr *rtm;
+	struct ieee80211_michael_event *mic;
+	struct ieee80211_join_event *join;
+	struct ieee80211_leave_event *leave;
+	int n, len;
+	union wpa_event_data data;
+
+	len = rtbuf_len();
+
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
+		return;
+	}
+
+	n = read(sock, buf, len);
+	if (n < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+				   __func__, strerror(errno));
+		os_free(buf);
+		return;
+	}
+
+	rtm = (struct rt_msghdr *) buf;
+	if (rtm->rtm_version != RTM_VERSION) {
+		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+			   rtm->rtm_version);
+		os_free(buf);
+		return;
+	}
+	ifan = (struct if_announcemsghdr *) rtm;
+	switch (rtm->rtm_type) {
+	case RTM_IEEE80211:
+		switch (ifan->ifan_what) {
+		case RTM_IEEE80211_ASSOC:
+		case RTM_IEEE80211_REASSOC:
+		case RTM_IEEE80211_DISASSOC:
+		case RTM_IEEE80211_SCAN:
+			break;
+		case RTM_IEEE80211_LEAVE:
+			leave = (struct ieee80211_leave_event *) &ifan[1];
+			drv_event_disassoc(drv->hapd, leave->iev_addr);
+			break;
+		case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+		case RTM_IEEE80211_REJOIN:
+#endif
+			join = (struct ieee80211_join_event *) &ifan[1];
+			bsd_new_sta(drv, drv->hapd, join->iev_addr);
+			break;
+		case RTM_IEEE80211_REPLAY:
+			/* ignore */
+			break;
+		case RTM_IEEE80211_MICHAEL:
+			mic = (struct ieee80211_michael_event *) &ifan[1];
+			wpa_printf(MSG_DEBUG,
+				"Michael MIC failure wireless event: "
+				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+				MAC2STR(mic->iev_src));
+			os_memset(&data, 0, sizeof(data));
+			data.michael_mic_failure.unicast = 1;
+			data.michael_mic_failure.src = mic->iev_src;
+			wpa_supplicant_event(drv->hapd,
+					     EVENT_MICHAEL_MIC_FAILURE, &data);
+			break;
+		}
+		break;
+	}
+	os_free(buf);
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+	struct bsd_driver_data *drv = ctx;
+	drv_event_eapol_rx(drv->hapd, src_addr, buf, len);
+}
+
+static void *
+bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+	struct bsd_driver_data *drv;
+
+	drv = os_zalloc(sizeof(struct bsd_driver_data));
+	if (drv == NULL) {
+		printf("Could not allocate memory for bsd driver data\n");
+		goto bad;
+	}
+
+	drv->hapd = hapd;
+	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		goto bad;
+	}
+	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+
+	drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
+					handle_read, drv, 0);
+	if (drv->sock_xmit == NULL)
+		goto bad;
+	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+		goto bad;
+
+	/* mark down during setup */
+	if (bsd_ctrl_iface(drv, 0) < 0)
+		goto bad;
+
+	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (drv->route < 0) {
+		perror("socket(PF_ROUTE,SOCK_RAW)");
+		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;
+	}
+
+	return drv;
+bad:
+	if (drv->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	if (drv->sock >= 0)
+		close(drv->sock);
+	if (drv != NULL)
+		os_free(drv);
+	return NULL;
+}
+
+
+static void
+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->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	os_free(drv);
+}
+
+#else /* HOSTAPD */
+
+static int
+get80211param(struct bsd_driver_data *drv, int op)
+{
+	struct ieee80211req ireq;
+
+	if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0)
+		return -1;
+	return ireq.i_val;
+}
+
+static int
+wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
+{
+	struct bsd_driver_data *drv = priv;
+#ifdef SIOCG80211BSSID
+	struct ieee80211_bssid bs;
+
+	os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name));
+	if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0)
+		return -1;
+	os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid));
+	return 0;
+#else
+	return get80211var(drv, IEEE80211_IOC_BSSID,
+		bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
+#endif
+}
+
+static int
+wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
+{
+	struct bsd_driver_data *drv = priv;
+	return bsd_get_ssid(drv, ssid, 0);
+}
+
+static int
+wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie,
+			  size_t wpa_ie_len)
+{
+#ifdef IEEE80211_IOC_APPIE
+	return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len);
+#else /* IEEE80211_IOC_APPIE */
+	return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
+#endif /* IEEE80211_IOC_APPIE */
+}
+
+static int
+wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
+{
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
+		__FUNCTION__, wpa, privacy);
+
+	if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0)
+		ret = -1;
+	if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+		ret = -1;
+	if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0)
+		ret = -1;
+
+	return ret;
+}
+
+static int
+wpa_driver_bsd_set_wpa(void *priv, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+	return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
+}
+
+static int
+wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+	return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled);
+}
+
+
+static int
+wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+	return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+}
+
+static int
+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+	return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
+				   addr);
+}
+
+static int
+wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
+{
+	int authmode;
+
+	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
+	    (auth_alg & WPA_AUTH_ALG_SHARED))
+		authmode = IEEE80211_AUTH_AUTO;
+	else if (auth_alg & WPA_AUTH_ALG_SHARED)
+		authmode = IEEE80211_AUTH_SHARED;
+	else
+		authmode = IEEE80211_AUTH_OPEN;
+
+	return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode);
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+	struct bsd_driver_data *drv = ctx;
+
+	drv_event_eapol_rx(drv->ctx, src_addr, buf, len);
+}
+
+static int
+wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
+{
+	struct bsd_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	u32 mode;
+	int privacy;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG,
+		"%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
+		, __func__
+		   , (unsigned int) params->ssid_len, params->ssid
+		, (unsigned int) params->wpa_ie_len
+		, params->pairwise_suite
+		, params->group_suite
+		, params->key_mgmt_suite
+	);
+
+	switch (params->mode) {
+	case IEEE80211_MODE_INFRA:
+		mode = 0 /* STA */;
+		break;
+	case IEEE80211_MODE_IBSS:
+		mode = IFM_IEEE80211_IBSS;
+		break;
+	case IEEE80211_MODE_AP:
+		mode = IFM_IEEE80211_HOSTAP;
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__);
+		return -1;
+	}
+	if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
+			   __func__);
+		return -1;
+	}
+
+	if (params->mode == IEEE80211_MODE_AP) {
+		drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL,
+						handle_read, drv, 0);
+		if (drv->sock_xmit == NULL)
+			return -1;
+		drv->is_ap = 1;
+		return 0;
+	}
+
+	if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted)
+	    < 0)
+		ret = -1;
+	if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0)
+		ret = -1;
+	/* XXX error handling is wrong but unclear what to do... */
+	if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
+		return -1;
+
+	privacy = !(params->pairwise_suite == CIPHER_NONE &&
+	    params->group_suite == CIPHER_NONE &&
+	    params->key_mgmt_suite == KEY_MGMT_NONE &&
+	    params->wpa_ie_len == 0);
+	wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
+
+	if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+		return -1;
+
+	if (params->wpa_ie_len &&
+	    set80211param(drv, IEEE80211_IOC_WPA,
+			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
+		return -1;
+
+	os_memset(&mlme, 0, sizeof(mlme));
+	mlme.im_op = IEEE80211_MLME_ASSOC;
+	if (params->ssid != NULL)
+		os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
+	mlme.im_ssid_len = params->ssid_len;
+	if (params->bssid != NULL)
+		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
+	if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
+		return -1;
+	return ret;
+}
+
+static int
+wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params)
+{
+	struct bsd_driver_data *drv = priv;
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+	struct ieee80211_scan_req sr;
+	int i;
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
+
+	if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to set operation mode",
+			   __func__);
+		return -1;
+	}
+
+	if (set80211param(drv, IEEE80211_IOC_ROAMING,
+			  IEEE80211_ROAMING_MANUAL) < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to set "
+			   "wpa_supplicant-based roaming: %s", __func__,
+			   strerror(errno));
+		return -1;
+	}
+
+	if (wpa_driver_bsd_set_wpa(drv, 1) < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__,
+			   strerror(errno));
+		return -1;
+	}
+
+	/* NB: interface must be marked UP to do a scan */
+	if (bsd_ctrl_iface(drv, 1) < 0)
+		return -1;
+
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+	os_memset(&sr, 0, sizeof(sr));
+	sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE |
+		IEEE80211_IOC_SCAN_NOJOIN;
+	sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+	if (params->num_ssids > 0) {
+		sr.sr_nssid = params->num_ssids;
+#if 0
+		/* Boundary check is done by upper layer */
+		if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID)
+			sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID;
+#endif
+
+		/* NB: check scan cache first */
+		sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK;
+	}
+	for (i = 0; i < sr.sr_nssid; i++) {
+		sr.sr_ssid[i].len = params->ssids[i].ssid_len;
+		os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid,
+			  sr.sr_ssid[i].len);
+	}
+
+	/* NB: net80211 delivers a scan complete event so no need to poll */
+	return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr));
+#else /* IEEE80211_IOC_SCAN_MAX_SSID */
+	/* set desired ssid before scan */
+	if (bsd_set_ssid(drv, params->ssids[0].ssid,
+			 params->ssids[0].ssid_len) < 0)
+		return -1;
+
+	/* NB: net80211 delivers a scan complete event so no need to poll */
+	return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
+}
+
+static void
+wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+	struct bsd_driver_data *drv = sock_ctx;
+	char *buf;
+	struct if_announcemsghdr *ifan;
+	struct if_msghdr *ifm;
+	struct rt_msghdr *rtm;
+	union wpa_event_data event;
+	struct ieee80211_michael_event *mic;
+	struct ieee80211_leave_event *leave;
+	struct ieee80211_join_event *join;
+	int n, len;
+
+	len = rtbuf_len();
+
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__);
+		return;
+	}
+
+	n = read(sock, buf, len);
+	if (n < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+				   __func__, strerror(errno));
+		os_free(buf);
+		return;
+	}
+
+	rtm = (struct rt_msghdr *) buf;
+	if (rtm->rtm_version != RTM_VERSION) {
+		wpa_printf(MSG_DEBUG, "Invalid routing message version=%d",
+			   rtm->rtm_version);
+		os_free(buf);
+		return;
+	}
+	os_memset(&event, 0, sizeof(event));
+	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:
+			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+		default:
+			os_free(buf);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+			   event.interface_status.ifname,
+			   ifan->ifan_what == IFAN_DEPARTURE ?
+				"removed" : "added");
+		wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+		break;
+	case RTM_IEEE80211:
+		ifan = (struct if_announcemsghdr *) rtm;
+		if (ifan->ifan_index != drv->ifindex)
+			break;
+		switch (ifan->ifan_what) {
+		case RTM_IEEE80211_ASSOC:
+		case RTM_IEEE80211_REASSOC:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+			break;
+		case RTM_IEEE80211_DISASSOC:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+			break;
+		case RTM_IEEE80211_SCAN:
+			if (drv->is_ap)
+				break;
+			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+			break;
+		case RTM_IEEE80211_LEAVE:
+			leave = (struct ieee80211_leave_event *) &ifan[1];
+			drv_event_disassoc(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);
+			break;
+		case RTM_IEEE80211_REPLAY:
+			/* ignore */
+			break;
+		case RTM_IEEE80211_MICHAEL:
+			mic = (struct ieee80211_michael_event *) &ifan[1];
+			wpa_printf(MSG_DEBUG,
+				"Michael MIC failure wireless event: "
+				"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+				MAC2STR(mic->iev_src));
+
+			os_memset(&event, 0, sizeof(event));
+			event.michael_mic_failure.unicast =
+				!IEEE80211_IS_MULTICAST(mic->iev_dst);
+			wpa_supplicant_event(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;
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+				   event.interface_status.ifname);
+			wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+		}
+		break;
+	}
+	os_free(buf);
+}
+
+static void
+wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res,
+			      struct ieee80211req_scan_result *sr)
+{
+	struct wpa_scan_res *result, **tmp;
+	size_t extra_len;
+	u8 *pos;
+
+	extra_len = 2 + sr->isr_ssid_len;
+	extra_len += 2 + sr->isr_nrates;
+	extra_len += 3; /* ERP IE */
+	extra_len += sr->isr_ie_len;
+
+	result = os_zalloc(sizeof(*result) + extra_len);
+	if (result == NULL)
+		return;
+	os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN);
+	result->freq = sr->isr_freq;
+	result->beacon_int = sr->isr_intval;
+	result->caps = sr->isr_capinfo;
+	result->qual = sr->isr_rssi;
+	result->noise = sr->isr_noise;
+
+	pos = (u8 *)(result + 1);
+
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = sr->isr_ssid_len;
+	os_memcpy(pos, sr + 1, sr->isr_ssid_len);
+	pos += sr->isr_ssid_len;
+
+	/*
+	 * Deal all rates as supported rate.
+	 * Because net80211 doesn't report extended supported rate or not.
+	 */
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = sr->isr_nrates;
+	os_memcpy(pos, sr->isr_rates, sr->isr_nrates);
+	pos += sr->isr_nrates;
+
+	*pos++ = WLAN_EID_ERP_INFO;
+	*pos++ = 1;
+	*pos++ = sr->isr_erp;
+
+	os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+	pos += sr->isr_ie_len;
+
+	result->ie_len = pos - (u8 *)(result + 1);
+
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(result);
+		return;
+	}
+	tmp[res->num++] = result;
+	res->res = tmp;
+}
+
+struct wpa_scan_results *
+wpa_driver_bsd_get_scan_results2(void *priv)
+{
+	struct ieee80211req_scan_result *sr;
+	struct wpa_scan_results *res;
+	int len, rest;
+	uint8_t buf[24*1024], *pos;
+
+	len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024);
+	if (len < 0)
+		return NULL;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL)
+		return NULL;
+
+	pos = buf;
+	rest = len;
+	while (rest >= sizeof(struct ieee80211req_scan_result)) {
+		sr = (struct ieee80211req_scan_result *)pos;
+		wpa_driver_bsd_add_scan_entry(res, sr);
+		pos += sr->isr_len;
+		rest -= sr->isr_len;
+	}
+
+	wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)",
+		   len, (unsigned long)res->num);
+
+	return res;
+}
+
+static int wpa_driver_bsd_capa(struct bsd_driver_data *drv)
+{
+#ifdef IEEE80211_IOC_DEVCAPS
+/* kernel definitions copied from net80211/ieee80211_var.h */
+#define IEEE80211_CIPHER_WEP            0
+#define IEEE80211_CIPHER_TKIP           1
+#define IEEE80211_CIPHER_AES_CCM        3
+#define IEEE80211_CRYPTO_WEP            (1<<IEEE80211_CIPHER_WEP)
+#define IEEE80211_CRYPTO_TKIP           (1<<IEEE80211_CIPHER_TKIP)
+#define IEEE80211_CRYPTO_AES_CCM        (1<<IEEE80211_CIPHER_AES_CCM)
+#define IEEE80211_C_HOSTAP      0x00000400      /* CAPABILITY: HOSTAP avail */
+#define IEEE80211_C_WPA1        0x00800000      /* CAPABILITY: WPA1 avail */
+#define IEEE80211_C_WPA2        0x01000000      /* CAPABILITY: WPA2 avail */
+	struct ieee80211_devcaps_req devcaps;
+
+	if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps,
+			sizeof(devcaps)) < 0) {
+		wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x",
+		   __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps);
+
+	if (devcaps.dc_drivercaps & IEEE80211_C_WPA1)
+		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+	if (devcaps.dc_drivercaps & IEEE80211_C_WPA2)
+		drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+			WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+
+	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP)
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+			WPA_DRIVER_CAPA_ENC_WEP104;
+	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP)
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+	if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM)
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+
+	if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+#undef IEEE80211_CIPHER_WEP
+#undef IEEE80211_CIPHER_TKIP
+#undef IEEE80211_CIPHER_AES_CCM
+#undef IEEE80211_CRYPTO_WEP
+#undef IEEE80211_CRYPTO_TKIP
+#undef IEEE80211_CRYPTO_AES_CCM
+#undef IEEE80211_C_HOSTAP
+#undef IEEE80211_C_WPA1
+#undef IEEE80211_C_WPA2
+#else /* IEEE80211_IOC_DEVCAPS */
+	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
+	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+		WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP |
+		WPA_DRIVER_CAPA_ENC_CCMP;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+#endif /* IEEE80211_IOC_DEVCAPS */
+#ifdef IEEE80211_IOC_SCAN_MAX_SSID
+	drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID;
+#else /* IEEE80211_IOC_SCAN_MAX_SSID */
+	drv->capa.max_scan_ssids = 1;
+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */
+	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+		WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+	return 0;
+}
+
+static void *
+wpa_driver_bsd_init(void *ctx, const char *ifname)
+{
+#define	GETPARAM(drv, param, v) \
+	(((v) = get80211param(drv, param)) != -1)
+	struct bsd_driver_data *drv;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	/*
+	 * NB: We require the interface name be mappable to an index.
+	 *     This implies we do not support having wpa_supplicant
+	 *     wait for an interface to appear.  This seems ok; that
+	 *     doesn't belong here; it's really the job of devd.
+	 */
+	drv->ifindex = if_nametoindex(ifname);
+	if (drv->ifindex == 0) {
+		wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+			   __func__, ifname);
+		goto fail1;
+	}
+	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->sock < 0)
+		goto fail1;
+	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;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	/* Down interface during setup. */
+	if (bsd_ctrl_iface(drv, 0) < 0)
+		goto fail;
+
+	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
+		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
+			__func__, strerror(errno));
+		goto fail;
+	}
+	if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
+		wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
+			__func__, strerror(errno));
+		goto fail;
+	}
+	if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
+		wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
+			__func__, strerror(errno));
+		goto fail;
+	}
+
+	if (wpa_driver_bsd_capa(drv))
+		goto fail;
+
+	return drv;
+fail:
+	close(drv->sock);
+fail1:
+	os_free(drv);
+	return NULL;
+#undef GETPARAM
+}
+
+static void
+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);
+
+	/* 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__);
+
+	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);
+}
+
+static int
+wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	struct bsd_driver_data *drv = priv;
+
+	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	return 0;
+}
+#endif /* HOSTAPD */
+
+
+const struct wpa_driver_ops wpa_driver_bsd_ops = {
+	.name			= "bsd",
+	.desc			= "BSD 802.11 support",
+#ifdef HOSTAPD
+	.hapd_init		= bsd_init,
+	.hapd_deinit		= bsd_deinit,
+	.set_privacy		= bsd_set_privacy,
+	.get_seqnum		= bsd_get_seqnum,
+	.flush			= bsd_flush,
+	.read_sta_data		= bsd_read_sta_driver_data,
+	.sta_disassoc		= bsd_sta_disassoc,
+	.sta_deauth		= bsd_sta_deauth,
+#else /* HOSTAPD */
+	.init			= wpa_driver_bsd_init,
+	.deinit			= wpa_driver_bsd_deinit,
+	.get_bssid		= wpa_driver_bsd_get_bssid,
+	.get_ssid		= wpa_driver_bsd_get_ssid,
+	.set_countermeasures	= wpa_driver_bsd_set_countermeasures,
+	.scan2			= wpa_driver_bsd_scan,
+	.get_scan_results2	= wpa_driver_bsd_get_scan_results2,
+	.deauthenticate		= wpa_driver_bsd_deauthenticate,
+	.associate		= wpa_driver_bsd_associate,
+	.get_capa		= wpa_driver_bsd_get_capa,
+#endif /* HOSTAPD */
+	.set_freq		= bsd_set_freq,
+	.set_key		= bsd_set_key,
+	.set_ieee8021x		= bsd_set_ieee8021x,
+	.hapd_set_ssid		= bsd_set_ssid,
+	.hapd_get_ssid		= bsd_get_ssid,
+	.hapd_send_eapol	= bsd_send_eapol,
+	.sta_set_flags		= bsd_set_sta_authorized,
+	.set_generic_elem	= bsd_set_opt_ie,
+};

Copied: vendor/wpa/2.0/src/drivers/driver_common.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_common.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,86 @@
+/*
+ * Common driver-related functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j at 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 "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+	size_t i;
+
+	if (res == NULL)
+		return;
+
+	for (i = 0; i < res->num; i++)
+		os_free(res->res[i]);
+	os_free(res->res);
+	os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+	switch (event) {
+	E2S(ASSOC);
+	E2S(DISASSOC);
+	E2S(MICHAEL_MIC_FAILURE);
+	E2S(SCAN_RESULTS);
+	E2S(ASSOCINFO);
+	E2S(INTERFACE_STATUS);
+	E2S(PMKID_CANDIDATE);
+	E2S(STKSTART);
+	E2S(TDLS);
+	E2S(FT_RESPONSE);
+	E2S(IBSS_RSN_START);
+	E2S(AUTH);
+	E2S(DEAUTH);
+	E2S(ASSOC_REJECT);
+	E2S(AUTH_TIMED_OUT);
+	E2S(ASSOC_TIMED_OUT);
+	E2S(FT_RRB_RX);
+	E2S(WPS_BUTTON_PUSHED);
+	E2S(TX_STATUS);
+	E2S(RX_FROM_UNKNOWN);
+	E2S(RX_MGMT);
+	E2S(RX_ACTION);
+	E2S(REMAIN_ON_CHANNEL);
+	E2S(CANCEL_REMAIN_ON_CHANNEL);
+	E2S(MLME_RX);
+	E2S(RX_PROBE_REQ);
+	E2S(NEW_STA);
+	E2S(EAPOL_RX);
+	E2S(SIGNAL_CHANGE);
+	E2S(INTERFACE_ENABLED);
+	E2S(INTERFACE_DISABLED);
+	E2S(CHANNEL_LIST_CHANGED);
+	E2S(INTERFACE_UNAVAILABLE);
+	E2S(BEST_CHANNEL);
+	E2S(UNPROT_DEAUTH);
+	E2S(UNPROT_DISASSOC);
+	E2S(STATION_LOW_ACK);
+	E2S(P2P_DEV_FOUND);
+	E2S(P2P_GO_NEG_REQ_RX);
+	E2S(P2P_GO_NEG_COMPLETED);
+	E2S(P2P_PROV_DISC_REQUEST);
+	E2S(P2P_PROV_DISC_RESPONSE);
+	E2S(P2P_SD_REQUEST);
+	E2S(P2P_SD_RESPONSE);
+	E2S(IBSS_PEER_LOST);
+	E2S(DRIVER_GTK_REKEY);
+	E2S(SCHED_SCAN_STOPPED);
+	E2S(DRIVER_CLIENT_POLL_OK);
+	E2S(EAPOL_TX_STATUS);
+	E2S(CH_SWITCH);
+	E2S(WNM);
+	}
+
+	return "UNKNOWN";
+#undef E2S
+}

Deleted: vendor/wpa/2.0/src/drivers/driver_hostap.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_hostap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_hostap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1635 +0,0 @@
-/*
- * Driver interaction with Linux Host AP driver
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "eloop.h"
-#include "driver_hostap.h"
-
-
-#ifdef HOSTAPD
-
-#include <net/if_arp.h>
-#include <netpacket/packet.h>
-
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "common/ieee802_11_defs.h"
-
-
-/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
- * frames that might be longer than normal default MTU and they are not
- * fragmented */
-#define HOSTAPD_MTU 2290
-
-static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-struct hostap_driver_data {
-	struct hostapd_data *hapd;
-
-	char iface[IFNAMSIZ + 1];
-	int sock; /* raw packet socket for driver access */
-	int ioctl_sock; /* socket for ioctl() use */
-	struct netlink_data *netlink;
-
-	int we_version;
-
-	u8 *generic_ie;
-	size_t generic_ie_len;
-	u8 *wps_ie;
-	size_t wps_ie_len;
-};
-
-
-static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
-			 int len);
-static int hostap_set_iface_flags(void *priv, int dev_up);
-
-static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
-			u16 stype)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc, ethertype;
-	u8 *pos, *sa;
-	size_t left;
-	union wpa_event_data event;
-
-	if (len < sizeof(struct ieee80211_hdr))
-		return;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
-		printf("Not ToDS data frame (fc=0x%04x)\n", fc);
-		return;
-	}
-
-	sa = hdr->addr2;
-	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.frame = buf;
-	event.rx_from_unknown.len = len;
-	wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
-
-	pos = (u8 *) (hdr + 1);
-	left = len - sizeof(*hdr);
-
-	if (left < sizeof(rfc1042_header)) {
-		printf("Too short data frame\n");
-		return;
-	}
-
-	if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
-		printf("Data frame with no RFC1042 header\n");
-		return;
-	}
-	pos += sizeof(rfc1042_header);
-	left -= sizeof(rfc1042_header);
-
-	if (left < 2) {
-		printf("No ethertype in data frame\n");
-		return;
-	}
-
-	ethertype = WPA_GET_BE16(pos);
-	pos += 2;
-	left -= 2;
-	switch (ethertype) {
-	case ETH_P_PAE:
-		drv_event_eapol_rx(drv->hapd, sa, pos, left);
-		break;
-
-	default:
-		printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
-		break;
-	}
-}
-
-
-static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
-			       size_t len, int ok)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = buf;
-	event.tx_status.data_len = len;
-	event.tx_status.ack = ok;
-	wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
-}
-
-
-static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc, extra_len, type, stype;
-	unsigned char *extra = NULL;
-	size_t data_len = len;
-	int ver;
-	union wpa_event_data event;
-
-	/* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
-	 * these to user space */
-	if (len < 24) {
-		wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)",
-			   (unsigned long) len);
-		return;
-	}
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-	type = WLAN_FC_GET_TYPE(fc);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) {
-		wpa_hexdump(MSG_MSGDUMP, "Received management frame",
-			    buf, len);
-	}
-
-	ver = fc & WLAN_FC_PVER;
-
-	/* protocol version 3 is reserved for indicating extra data after the
-	 * payload, version 2 for indicating ACKed frame (TX callbacks), and
-	 * version 1 for indicating failed frame (no ACK, TX callbacks) */
-	if (ver == 3) {
-		u8 *pos = buf + len - 2;
-		extra_len = WPA_GET_LE16(pos);
-		printf("extra data in frame (elen=%d)\n", extra_len);
-		if ((size_t) extra_len + 2 > len) {
-			printf("  extra data overflow\n");
-			return;
-		}
-		len -= extra_len + 2;
-		extra = buf + len;
-	} else if (ver == 1 || ver == 2) {
-		handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
-		return;
-	} else if (ver != 0) {
-		printf("unknown protocol version %d\n", ver);
-		return;
-	}
-
-	switch (type) {
-	case WLAN_FC_TYPE_MGMT:
-		os_memset(&event, 0, sizeof(event));
-		event.rx_mgmt.frame = buf;
-		event.rx_mgmt.frame_len = data_len;
-		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-		break;
-	case WLAN_FC_TYPE_CTRL:
-		wpa_printf(MSG_DEBUG, "CTRL");
-		break;
-	case WLAN_FC_TYPE_DATA:
-		wpa_printf(MSG_DEBUG, "DATA");
-		handle_data(drv, buf, data_len, stype);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
-		break;
-	}
-}
-
-
-static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct hostap_driver_data *drv = eloop_ctx;
-	int len;
-	unsigned char buf[3000];
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	handle_frame(drv, buf, len);
-}
-
-
-static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
-{
-	struct ifreq ifr;
-	struct sockaddr_ll addr;
-
-	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (drv->sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
-		return -1;
-	}
-
-	if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
-		printf("Could not register read socket\n");
-		return -1;
-	}
-
-        memset(&ifr, 0, sizeof(ifr));
-        snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
-        if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		return -1;
-        }
-
-	if (hostap_set_iface_flags(drv, 1)) {
-		return -1;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sll_family = AF_PACKET;
-	addr.sll_ifindex = ifr.ifr_ifindex;
-	wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
-		   addr.sll_ifindex);
-
-	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
-		return -1;
-	}
-
-	return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr);
-}
-
-
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
-{
-	struct hostap_driver_data *drv = priv;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
-	int res;
-
-	/* Request TX callback */
-	hdr->frame_control |= host_to_le16(BIT(1));
-	res = send(drv->sock, msg, len, 0);
-	hdr->frame_control &= ~host_to_le16(BIT(1));
-
-	return res;
-}
-
-
-static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
-			     size_t data_len, int encrypt, const u8 *own_addr)
-{
-	struct hostap_driver_data *drv = priv;
-	struct ieee80211_hdr *hdr;
-	size_t len;
-	u8 *pos;
-	int res;
-
-	len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len;
-	hdr = os_zalloc(len);
-	if (hdr == NULL) {
-		printf("malloc() failed for hostapd_send_data(len=%lu)\n",
-		       (unsigned long) len);
-		return -1;
-	}
-
-	hdr->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
-	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
-	if (encrypt)
-		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
-	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
-	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
-
-	pos = (u8 *) (hdr + 1);
-	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
-	pos += sizeof(rfc1042_header);
-	*((u16 *) pos) = htons(ETH_P_PAE);
-	pos += 2;
-	memcpy(pos, data, data_len);
-
-	res = hostap_send_mlme(drv, (u8 *) hdr, len);
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
-			   "failed: %d (%s)",
-			   (unsigned long) len, errno, strerror(errno));
-	}
-	free(hdr);
-
-	return res;
-}
-
-
-static int hostap_sta_set_flags(void *priv, const u8 *addr,
-				int total_flags, int flags_or, int flags_and)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-
-	if (flags_or & WPA_STA_AUTHORIZED)
-		flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		flags_and = ~BIT(5);
-	else
-		flags_and = ~0;
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
-	memcpy(param.sta_addr, addr, ETH_ALEN);
-	param.u.set_flags_sta.flags_or = flags_or;
-	param.u.set_flags_sta.flags_and = flags_and;
-	return hostapd_ioctl(drv, &param, sizeof(param));
-}
-
-
-static int hostap_set_iface_flags(void *priv, int dev_up)
-{
-	struct hostap_driver_data *drv = priv;
-	struct ifreq ifr;
-	char ifname[IFNAMSIZ];
-
-	os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface);
-	if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0)
-		return -1;
-
-	if (dev_up) {
-		memset(&ifr, 0, sizeof(ifr));
-		os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-		ifr.ifr_mtu = HOSTAPD_MTU;
-		if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
-			perror("ioctl[SIOCSIFMTU]");
-			printf("Setting MTU failed - trying to survive with "
-			       "current value\n");
-		}
-	}
-
-	return 0;
-}
-
-
-static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
-			 int len)
-{
-	struct hostap_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct prism2_hostapd_param *) buf;
-	param->cmd = PRISM2_SET_ENCRYPTION;
-	if (addr == NULL)
-		memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		memcpy(param->sta_addr, addr, ETH_ALEN);
-	switch (alg) {
-	case WPA_ALG_NONE:
-		os_strlcpy((char *) param->u.crypt.alg, "NONE",
-			   HOSTAP_CRYPT_ALG_NAME_LEN);
-		break;
-	case WPA_ALG_WEP:
-		os_strlcpy((char *) param->u.crypt.alg, "WEP",
-			   HOSTAP_CRYPT_ALG_NAME_LEN);
-		break;
-	case WPA_ALG_TKIP:
-		os_strlcpy((char *) param->u.crypt.alg, "TKIP",
-			   HOSTAP_CRYPT_ALG_NAME_LEN);
-		break;
-	case WPA_ALG_CCMP:
-		os_strlcpy((char *) param->u.crypt.alg, "CCMP",
-			   HOSTAP_CRYPT_ALG_NAME_LEN);
-		break;
-	default:
-		os_free(buf);
-		return -1;
-	}
-	param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
-	param->u.crypt.idx = key_idx;
-	param->u.crypt.key_len = key_len;
-	memcpy((u8 *) (param + 1), key, key_len);
-
-	if (hostapd_ioctl(drv, param, blen)) {
-		printf("Failed to set encryption.\n");
-		ret = -1;
-	}
-	free(buf);
-
-	return ret;
-}
-
-
-static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
-			     int idx, u8 *seq)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-
-	blen = sizeof(*param) + 32;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct prism2_hostapd_param *) buf;
-	param->cmd = PRISM2_GET_ENCRYPTION;
-	if (addr == NULL)
-		memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		memcpy(param->sta_addr, addr, ETH_ALEN);
-	param->u.crypt.idx = idx;
-
-	if (hostapd_ioctl(drv, param, blen)) {
-		printf("Failed to get encryption.\n");
-		ret = -1;
-	} else {
-		memcpy(seq, param->u.crypt.seq, 8);
-	}
-	free(buf);
-
-	return ret;
-}
-
-
-static int hostap_ioctl_prism2param(void *priv, int param, int value)
-{
-	struct hostap_driver_data *drv = priv;
-	struct iwreq iwr;
-	int *i;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = param;
-	*i++ = value;
-
-	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
-	struct hostap_driver_data *drv = priv;
-	int enabled = params->enabled;
-
-	/* enable kernel driver support for IEEE 802.1X */
-	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) {
-		printf("Could not setup IEEE 802.1X support in kernel driver."
-		       "\n");
-		return -1;
-	}
-
-	if (!enabled)
-		return 0;
-
-	/* use host driver implementation of encryption to allow
-	 * individual keys and passing plaintext EAPOL frames */
-	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) ||
-	    hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) {
-		printf("Could not setup host-based encryption in kernel "
-		       "driver.\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int hostap_set_privacy(void *priv, int enabled)
-{
-	struct hostap_drvier_data *drv = priv;
-
-	return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
-					enabled);
-}
-
-
-static int hostap_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct hostap_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	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;
-	iwr.u.essid.length = len + 1;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int hostap_flush(void *priv)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_FLUSH;
-	return hostapd_ioctl(drv, &param, sizeof(param));
-}
-
-
-static int hostap_read_sta_data(void *priv,
-				struct hostap_sta_driver_data *data,
-				const u8 *addr)
-{
-	struct hostap_driver_data *drv = priv;
-	char buf[1024], line[128], *pos;
-	FILE *f;
-	unsigned long val;
-
-	memset(data, 0, sizeof(*data));
-	snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
-		 drv->iface, MAC2STR(addr));
-
-	f = fopen(buf, "r");
-	if (!f)
-		return -1;
-	/* Need to read proc file with in one piece, so use large enough
-	 * buffer. */
-	setbuffer(f, buf, sizeof(buf));
-
-	while (fgets(line, sizeof(line), f)) {
-		pos = strchr(line, '=');
-		if (!pos)
-			continue;
-		*pos++ = '\0';
-		val = strtoul(pos, NULL, 10);
-		if (strcmp(line, "rx_packets") == 0)
-			data->rx_packets = val;
-		else if (strcmp(line, "tx_packets") == 0)
-			data->tx_packets = val;
-		else if (strcmp(line, "rx_bytes") == 0)
-			data->rx_bytes = val;
-		else if (strcmp(line, "tx_bytes") == 0)
-			data->tx_bytes = val;
-	}
-
-	fclose(f);
-
-	return 0;
-}
-
-
-static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-	int tx_supp_rates = 0;
-	size_t i;
-
-#define WLAN_RATE_1M BIT(0)
-#define WLAN_RATE_2M BIT(1)
-#define WLAN_RATE_5M5 BIT(2)
-#define WLAN_RATE_11M BIT(3)
-
-	for (i = 0; i < params->supp_rates_len; i++) {
-		if ((params->supp_rates[i] & 0x7f) == 2)
-			tx_supp_rates |= WLAN_RATE_1M;
-		if ((params->supp_rates[i] & 0x7f) == 4)
-			tx_supp_rates |= WLAN_RATE_2M;
-		if ((params->supp_rates[i] & 0x7f) == 11)
-			tx_supp_rates |= WLAN_RATE_5M5;
-		if ((params->supp_rates[i] & 0x7f) == 22)
-			tx_supp_rates |= WLAN_RATE_11M;
-	}
-
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_ADD_STA;
-	memcpy(param.sta_addr, params->addr, ETH_ALEN);
-	param.u.add_sta.aid = params->aid;
-	param.u.add_sta.capability = params->capability;
-	param.u.add_sta.tx_supp_rates = tx_supp_rates;
-	return hostapd_ioctl(drv, &param, sizeof(param));
-}
-
-
-static int hostap_sta_remove(void *priv, const u8 *addr)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-
-	hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED);
-
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
-	memcpy(param.sta_addr, addr, ETH_ALEN);
-	if (hostapd_ioctl(drv, &param, sizeof(param))) {
-		printf("Could not remove station from kernel driver.\n");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int hostap_get_inact_sec(void *priv, const u8 *addr)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
-	memcpy(param.sta_addr, addr, ETH_ALEN);
-	if (hostapd_ioctl(drv, &param, sizeof(param))) {
-		return -1;
-	}
-
-	return param.u.get_info_sta.inactive_sec;
-}
-
-
-static int hostap_sta_clear_stats(void *priv, const u8 *addr)
-{
-	struct hostap_driver_data *drv = priv;
-	struct prism2_hostapd_param param;
-
-	memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS;
-	memcpy(param.sta_addr, addr, ETH_ALEN);
-	if (hostapd_ioctl(drv, &param, sizeof(param))) {
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
-{
-	struct prism2_hostapd_param *param;
-	int res;
-	size_t blen, elem_len;
-
-	elem_len = drv->generic_ie_len + drv->wps_ie_len;
-	blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len;
-	if (blen < sizeof(*param))
-		blen = sizeof(*param);
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
-	param->u.generic_elem.len = elem_len;
-	if (drv->generic_ie) {
-		os_memcpy(param->u.generic_elem.data, drv->generic_ie,
-			  drv->generic_ie_len);
-	}
-	if (drv->wps_ie) {
-		os_memcpy(&param->u.generic_elem.data[drv->generic_ie_len],
-			  drv->wps_ie, drv->wps_ie_len);
-	}
-	wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
-		    param->u.generic_elem.data, elem_len);
-	res = hostapd_ioctl(drv, param, blen);
-
-	os_free(param);
-
-	return res;
-}
-
-
-static int hostap_set_generic_elem(void *priv,
-				   const u8 *elem, size_t elem_len)
-{
-	struct hostap_driver_data *drv = priv;
-
-	os_free(drv->generic_ie);
-	drv->generic_ie = NULL;
-	drv->generic_ie_len = 0;
-	if (elem) {
-		drv->generic_ie = os_malloc(elem_len);
-		if (drv->generic_ie == NULL)
-			return -1;
-		os_memcpy(drv->generic_ie, elem, elem_len);
-		drv->generic_ie_len = elem_len;
-	}
-
-	return hostapd_ioctl_set_generic_elem(drv);
-}
-
-
-static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-				const struct wpabuf *proberesp)
-{
-	struct hostap_driver_data *drv = priv;
-
-	/*
-	 * Host AP driver supports only one set of extra IEs, so we need to
-	 * use the Probe Response IEs also for Beacon frames since they include
-	 * more information.
-	 */
-
-	os_free(drv->wps_ie);
-	drv->wps_ie = NULL;
-	drv->wps_ie_len = 0;
-	if (proberesp) {
-		drv->wps_ie = os_malloc(wpabuf_len(proberesp));
-		if (drv->wps_ie == NULL)
-			return -1;
-		os_memcpy(drv->wps_ie, wpabuf_head(proberesp),
-			  wpabuf_len(proberesp));
-		drv->wps_ie_len = wpabuf_len(proberesp);
-	}
-
-	return hostapd_ioctl_set_generic_elem(drv);
-}
-
-
-static void
-hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
-				       char *custom)
-{
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		char *pos;
-		u8 addr[ETH_ALEN];
-		pos = strstr(custom, "addr=");
-		if (pos == NULL) {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "without sender address ignored");
-			return;
-		}
-		pos += 5;
-		if (hwaddr_aton(pos, addr) == 0) {
-			union wpa_event_data data;
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = addr;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "with invalid MAC address");
-		}
-	}
-}
-
-
-static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
-					    char *data, 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) {
-		/* 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)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (drv->we_version > 18 &&
-		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
-		     iwe->cmd == IWEVCUSTOM)) {
-			/* 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);
-		} else {
-			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;
-			memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-			hostapd_wireless_event_wireless_custom(drv, buf);
-			free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-
-static void hostapd_wireless_event_rtm_newlink(void *ctx,
-					       struct ifinfomsg *ifi,
-					       u8 *buf, size_t len)
-{
-	struct hostap_driver_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	/* TODO: use ifi->ifi_index to filter out wireless events from other
-	 * interfaces */
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_WIRELESS) {
-			hostapd_wireless_event_wireless(
-				drv, ((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-static int hostap_get_we_version(struct hostap_driver_data *drv)
-{
-	struct iw_range *range;
-	struct iwreq iwr;
-	int minlen;
-	size_t buflen;
-
-	drv->we_version = 0;
-
-	/*
-	 * Use larger buffer than struct iw_range in order to allow the
-	 * structure to grow in the future.
-	 */
-	buflen = sizeof(struct iw_range) + 500;
-	range = os_zalloc(buflen);
-	if (range == NULL)
-		return -1;
-
-	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;
-
-	minlen = ((char *) &range->enc_capa) - (char *) range +
-		sizeof(range->enc_capa);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
-		return -1;
-	} else if (iwr.u.data.length >= minlen &&
-		   range->we_version_compiled >= 18) {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
-			   "WE(source)=%d enc_capa=0x%x",
-			   range->we_version_compiled,
-			   range->we_version_source,
-			   range->enc_capa);
-		drv->we_version = range->we_version_compiled;
-	}
-
-	free(range);
-	return 0;
-}
-
-
-static int hostap_wireless_event_init(struct hostap_driver_data *drv)
-{
-	struct netlink_config *cfg;
-
-	hostap_get_we_version(drv);
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		return -1;
-	cfg->ctx = drv;
-	cfg->newlink_cb = hostapd_wireless_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void * hostap_init(struct hostapd_data *hapd,
-			  struct wpa_init_params *params)
-{
-	struct hostap_driver_data *drv;
-
-	drv = os_zalloc(sizeof(struct hostap_driver_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for hostapd driver data\n");
-		return NULL;
-	}
-
-	drv->hapd = hapd;
-	drv->ioctl_sock = drv->sock = -1;
-	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
-
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		free(drv);
-		return NULL;
-	}
-
-	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
-		printf("Could not enable hostapd mode for interface %s\n",
-		       drv->iface);
-		close(drv->ioctl_sock);
-		free(drv);
-		return NULL;
-	}
-
-	if (hostap_init_sockets(drv, params->own_addr) ||
-	    hostap_wireless_event_init(drv)) {
-		close(drv->ioctl_sock);
-		free(drv);
-		return NULL;
-	}
-
-	return drv;
-}
-
-
-static void hostap_driver_deinit(void *priv)
-{
-	struct hostap_driver_data *drv = priv;
-
-	netlink_deinit(drv->netlink);
-	(void) hostap_set_iface_flags(drv, 0);
-	(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
-	(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
-
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	if (drv->sock >= 0)
-		close(drv->sock);
-
-	os_free(drv->generic_ie);
-	os_free(drv->wps_ie);
-
-	free(drv);
-}
-
-
-static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			     int reason)
-{
-	struct hostap_driver_data *drv = priv;
-	struct ieee80211_mgmt mgmt;
-
-	memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_DEAUTH);
-	memcpy(mgmt.da, addr, ETH_ALEN);
-	memcpy(mgmt.sa, own_addr, ETH_ALEN);
-	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
-	mgmt.u.deauth.reason_code = host_to_le16(reason);
-	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				sizeof(mgmt.u.deauth));
-}
-
-
-static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-			       int reason)
-{
-	struct hostap_driver_data *drv = priv;
-	struct ieee80211_mgmt mgmt;
-
-	memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_DISASSOC);
-	memcpy(mgmt.da, addr, ETH_ALEN);
-	memcpy(mgmt.sa, own_addr, ETH_ALEN);
-	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
-	mgmt.u.disassoc.reason_code = host_to_le16(reason);
-	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				 sizeof(mgmt.u.disassoc));
-}
-
-
-static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
-							    u16 *num_modes,
-							    u16 *flags)
-{
-	struct hostapd_hw_modes *mode;
-	int i, clen, rlen;
-	const short chan2freq[14] = {
-		2412, 2417, 2422, 2427, 2432, 2437, 2442,
-		2447, 2452, 2457, 2462, 2467, 2472, 2484
-	};
-
-	mode = os_zalloc(sizeof(struct hostapd_hw_modes));
-	if (mode == NULL)
-		return NULL;
-
-	*num_modes = 1;
-	*flags = 0;
-
-	mode->mode = HOSTAPD_MODE_IEEE80211B;
-	mode->num_channels = 14;
-	mode->num_rates = 4;
-
-	clen = mode->num_channels * sizeof(struct hostapd_channel_data);
-	rlen = mode->num_rates * sizeof(int);
-
-	mode->channels = os_zalloc(clen);
-	mode->rates = os_zalloc(rlen);
-	if (mode->channels == NULL || mode->rates == NULL) {
-		os_free(mode->channels);
-		os_free(mode->rates);
-		os_free(mode);
-		return NULL;
-	}
-
-	for (i = 0; i < 14; i++) {
-		mode->channels[i].chan = i + 1;
-		mode->channels[i].freq = chan2freq[i];
-		/* TODO: Get allowed channel list from the driver */
-		if (i >= 11)
-			mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
-	}
-
-	mode->rates[0] = 10;
-	mode->rates[1] = 20;
-	mode->rates[2] = 55;
-	mode->rates[3] = 110;
-
-	return mode;
-}
-
-#else /* HOSTAPD */
-
-struct wpa_driver_hostap_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-	int current_mode; /* infra/adhoc */
-};
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg);
-
-
-static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
-			 struct prism2_hostapd_param *param,
-			 int len, int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-		int ret = errno;
-		if (show_err)
-			perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
-		return ret;
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
-					const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct prism2_hostapd_param *param;
-	int res;
-	size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-	if (blen < sizeof(*param))
-		blen = sizeof(*param);
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
-	param->u.generic_elem.len = wpa_ie_len;
-	os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-	res = hostapd_ioctl(drv, param, blen, 1);
-
-	os_free(param);
-
-	return res;
-}
-
-
-static int prism2param(struct wpa_driver_hostap_data *drv, int param,
-		       int value)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = param;
-	*i++ = value;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
-		ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-	if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
-	switch (param->u.crypt.err) {
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
-		wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-			   param->u.crypt.alg);
-		wpa_printf(MSG_INFO, "You may need to load kernel module to "
-			   "register that algorithm.");
-		wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
-			   "WEP.");
-		break;
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
-		wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-			   MAC2STR(param->sta_addr));
-		break;
-	case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
-		wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "Key setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "TX key index setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
-		wpa_printf(MSG_INFO, "Card configuration failed.");
-		break;
-	}
-}
-
-
-static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-	char *alg_name;
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		alg_name = "none";
-		break;
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		break;
-	default:
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > 8)
-		return -2;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct prism2_hostapd_param *) buf;
-	param->cmd = PRISM2_SET_ENCRYPTION;
-	/* TODO: In theory, STA in client mode can use five keys; four default
-	 * keys for receiving (with keyidx 0..3) and one individual key for
-	 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
-	 * keyidx 0 is reserved for this unicast use and default keys can only
-	 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
-	 * This should be fine for more or less all cases, but for completeness
-	 * sake, the driver could be enhanced to support the missing key. */
-#if 0
-	if (addr == NULL)
-		os_memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
-	os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
-	os_strlcpy((char *) param->u.crypt.alg, alg_name,
-		   HOSTAP_CRYPT_ALG_NAME_LEN);
-	param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
-	param->u.crypt.idx = key_idx;
-	os_memcpy(param->u.crypt.seq, seq, seq_len);
-	param->u.crypt.key_len = key_len;
-	os_memcpy((u8 *) (param + 1), key, key_len);
-
-	if (hostapd_ioctl(drv, param, blen, 1)) {
-		wpa_printf(MSG_WARNING, "Failed to set encryption.");
-		show_set_key_error(param);
-		ret = -1;
-	}
-	os_free(buf);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
-}
-
-
-static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
-				   int type)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = type;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
-	        perror("ioctl[PRISM2_IOCTL_RESET]");
-	        ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
-				  const u8 *addr, int cmd, int reason_code)
-{
-	struct prism2_hostapd_param param;
-	int ret;
-
-	/* There does not seem to be a better way of deauthenticating or
-	 * disassociating with Prism2/2.5/3 than sending the management frame
-	 * and then resetting the Port0 to make sure both the AP and the STA
-	 * end up in disconnected state. */
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_MLME;
-	os_memcpy(param.sta_addr, addr, ETH_ALEN);
-	param.u.mlme.cmd = cmd;
-	param.u.mlme.reason_code = reason_code;
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-	if (ret == 0) {
-		os_sleep(0, 100000);
-		ret = wpa_driver_hostap_reset(drv, 2);
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
-				      reason_code);
-}
-
-
-static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
-				      reason_code);
-}
-
-
-static int
-wpa_driver_hostap_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-	int allow_unencrypted_eapol;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED,
-			params->drop_unencrypted) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	if (params->mode != drv->current_mode) {
-		/* At the moment, Host AP driver requires host_roaming=2 for
-		 * infrastructure mode and host_roaming=0 for adhoc. */
-		if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
-				params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
-				   __func__);
-		}
-		drv->current_mode = params->mode;
-	}
-
-	if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
-			params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
-					 params->wpa_ie_len) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
-		ret = -1;
-	if (params->freq &&
-	    wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-	    < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-		ret = -1;
-
-	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
-	 * not using WPA. IEEE 802.1X specifies that these frames are not
-	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
-		allow_unencrypted_eapol = 0;
-	else
-		allow_unencrypted_eapol = 1;
-	
-	if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
-			allow_unencrypted_eapol) < 0) {
-		wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
-			   "ieee_802_1x param");
-		/* Ignore this error.. driver_hostap.c can also be used with
-		 * other drivers that do not support this prism2_param. */
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param param;
-	int ret;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid == NULL) {
-		/* Use standard Linux Wireless Extensions ioctl if possible
-		 * because some drivers using hostap code in wpa_supplicant
-		 * might not support Host AP specific scan request (with SSID
-		 * info). */
-		return wpa_driver_wext_scan(drv->wext, params);
-	}
-
-	if (ssid_len > 32)
-		ssid_len = 32;
-
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
-	param.u.scan_req.ssid_len = ssid_len;
-	os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int algs = 0;
-
-	if (auth_alg & WPA_AUTH_ALG_OPEN)
-		algs |= 1;
-	if (auth_alg & WPA_AUTH_ALG_SHARED)
-		algs |= 2;
-	if (auth_alg & WPA_AUTH_ALG_LEAP)
-		algs |= 4;
-	if (algs == 0)
-		algs = 1; /* at least one algorithm should be set */
-
-	return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_hostap_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_hostap_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		perror("socket");
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (os_strncmp(ifname, "wlan", 4) == 0) {
-		/*
-		 * Host AP driver may use both wlan# and wifi# interface in
-		 * wireless events.
-		 */
-		char ifname2[IFNAMSIZ + 1];
-		os_strlcpy(ifname2, ifname, sizeof(ifname2));
-		os_memcpy(ifname2, "wifi", 4);
-		wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
-	}
-
-	wpa_driver_hostap_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_driver_hostap_deinit(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_driver_hostap_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
-
-const struct wpa_driver_ops wpa_driver_hostap_ops = {
-	.name = "hostap",
-	.desc = "Host AP driver (Intersil Prism2/2.5/3)",
-	.set_key = wpa_driver_hostap_set_key,
-#ifdef HOSTAPD
-	.hapd_init = hostap_init,
-	.hapd_deinit = hostap_driver_deinit,
-	.set_ieee8021x = hostap_set_ieee8021x,
-	.set_privacy = hostap_set_privacy,
-	.get_seqnum = hostap_get_seqnum,
-	.flush = hostap_flush,
-	.set_generic_elem = hostap_set_generic_elem,
-	.read_sta_data = hostap_read_sta_data,
-	.hapd_send_eapol = hostap_send_eapol,
-	.sta_set_flags = hostap_sta_set_flags,
-	.sta_deauth = hostap_sta_deauth,
-	.sta_disassoc = hostap_sta_disassoc,
-	.sta_remove = hostap_sta_remove,
-	.hapd_set_ssid = hostap_set_ssid,
-	.send_mlme = hostap_send_mlme,
-	.sta_add = hostap_sta_add,
-	.get_inact_sec = hostap_get_inact_sec,
-	.sta_clear_stats = hostap_sta_clear_stats,
-	.get_hw_feature_data = hostap_get_hw_feature_data,
-	.set_ap_wps_ie = hostap_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid = wpa_driver_hostap_get_bssid,
-	.get_ssid = wpa_driver_hostap_get_ssid,
-	.set_countermeasures = wpa_driver_hostap_set_countermeasures,
-	.scan2 = wpa_driver_hostap_scan,
-	.get_scan_results2 = wpa_driver_hostap_get_scan_results,
-	.deauthenticate = wpa_driver_hostap_deauthenticate,
-	.disassociate = wpa_driver_hostap_disassociate,
-	.associate = wpa_driver_hostap_associate,
-	.init = wpa_driver_hostap_init,
-	.deinit = wpa_driver_hostap_deinit,
-	.set_operstate = wpa_driver_hostap_set_operstate,
-#endif /* HOSTAPD */
-};

Copied: vendor/wpa/2.0/src/drivers/driver_hostap.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_hostap.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_hostap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_hostap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1193 @@
+/*
+ * Driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "linux_wext.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "driver_hostap.h"
+
+
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+
+
+/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
+ * frames that might be longer than normal default MTU and they are not
+ * fragmented */
+#define HOSTAPD_MTU 2290
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+struct hostap_driver_data {
+	struct hostapd_data *hapd;
+
+	char iface[IFNAMSIZ + 1];
+	int sock; /* raw packet socket for driver access */
+	int ioctl_sock; /* socket for ioctl() use */
+	struct netlink_data *netlink;
+
+	int we_version;
+
+	u8 *generic_ie;
+	size_t generic_ie_len;
+	u8 *wps_ie;
+	size_t wps_ie_len;
+};
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+			 int len);
+static int hostap_set_iface_flags(void *priv, int dev_up);
+
+static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
+			u16 stype)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc, ethertype;
+	u8 *pos, *sa;
+	size_t left;
+	union wpa_event_data event;
+
+	if (len < sizeof(struct ieee80211_hdr))
+		return;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
+		printf("Not ToDS data frame (fc=0x%04x)\n", fc);
+		return;
+	}
+
+	sa = hdr->addr2;
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = sa;
+	wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
+
+	pos = (u8 *) (hdr + 1);
+	left = len - sizeof(*hdr);
+
+	if (left < sizeof(rfc1042_header)) {
+		printf("Too short data frame\n");
+		return;
+	}
+
+	if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
+		printf("Data frame with no RFC1042 header\n");
+		return;
+	}
+	pos += sizeof(rfc1042_header);
+	left -= sizeof(rfc1042_header);
+
+	if (left < 2) {
+		printf("No ethertype in data frame\n");
+		return;
+	}
+
+	ethertype = WPA_GET_BE16(pos);
+	pos += 2;
+	left -= 2;
+	switch (ethertype) {
+	case ETH_P_PAE:
+		drv_event_eapol_rx(drv->hapd, sa, pos, left);
+		break;
+
+	default:
+		printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
+		break;
+	}
+}
+
+
+static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
+			       size_t len, int ok)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = buf;
+	event.tx_status.data_len = len;
+	event.tx_status.ack = ok;
+	wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
+}
+
+
+static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc, extra_len, type, stype;
+	size_t data_len = len;
+	int ver;
+	union wpa_event_data event;
+
+	/* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
+	 * these to user space */
+	if (len < 24) {
+		wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) {
+		wpa_hexdump(MSG_MSGDUMP, "Received management frame",
+			    buf, len);
+	}
+
+	ver = fc & WLAN_FC_PVER;
+
+	/* protocol version 3 is reserved for indicating extra data after the
+	 * payload, version 2 for indicating ACKed frame (TX callbacks), and
+	 * version 1 for indicating failed frame (no ACK, TX callbacks) */
+	if (ver == 3) {
+		u8 *pos = buf + len - 2;
+		extra_len = WPA_GET_LE16(pos);
+		printf("extra data in frame (elen=%d)\n", extra_len);
+		if ((size_t) extra_len + 2 > len) {
+			printf("  extra data overflow\n");
+			return;
+		}
+		len -= extra_len + 2;
+	} else if (ver == 1 || ver == 2) {
+		handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
+		return;
+	} else if (ver != 0) {
+		printf("unknown protocol version %d\n", ver);
+		return;
+	}
+
+	switch (type) {
+	case WLAN_FC_TYPE_MGMT:
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = data_len;
+		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+		break;
+	case WLAN_FC_TYPE_CTRL:
+		wpa_printf(MSG_DEBUG, "CTRL");
+		break;
+	case WLAN_FC_TYPE_DATA:
+		wpa_printf(MSG_DEBUG, "DATA");
+		handle_data(drv, buf, data_len, stype);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
+		break;
+	}
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct hostap_driver_data *drv = eloop_ctx;
+	int len;
+	unsigned char buf[3000];
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	handle_frame(drv, buf, len);
+}
+
+
+static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
+{
+	struct ifreq ifr;
+	struct sockaddr_ll addr;
+
+	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (drv->sock < 0) {
+		perror("socket[PF_PACKET,SOCK_RAW]");
+		return -1;
+	}
+
+	if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
+		printf("Could not register read socket\n");
+		return -1;
+	}
+
+        memset(&ifr, 0, sizeof(ifr));
+        snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+        if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		return -1;
+        }
+
+	if (hostap_set_iface_flags(drv, 1)) {
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_ifindex = ifr.ifr_ifindex;
+	wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+		   addr.sll_ifindex);
+
+	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		return -1;
+	}
+
+	return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr);
+}
+
+
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
+{
+	struct hostap_driver_data *drv = priv;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
+	int res;
+
+	/* Request TX callback */
+	hdr->frame_control |= host_to_le16(BIT(1));
+	res = send(drv->sock, msg, len, 0);
+	hdr->frame_control &= ~host_to_le16(BIT(1));
+
+	return res;
+}
+
+
+static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
+			     size_t data_len, int encrypt, const u8 *own_addr,
+			     u32 flags)
+{
+	struct hostap_driver_data *drv = priv;
+	struct ieee80211_hdr *hdr;
+	size_t len;
+	u8 *pos;
+	int res;
+
+	len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len;
+	hdr = os_zalloc(len);
+	if (hdr == NULL) {
+		printf("malloc() failed for hostapd_send_data(len=%lu)\n",
+		       (unsigned long) len);
+		return -1;
+	}
+
+	hdr->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+	if (encrypt)
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	pos = (u8 *) (hdr + 1);
+	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+	pos += sizeof(rfc1042_header);
+	*((u16 *) pos) = htons(ETH_P_PAE);
+	pos += 2;
+	memcpy(pos, data, data_len);
+
+	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
+			   "failed: %d (%s)",
+			   (unsigned long) len, errno, strerror(errno));
+	}
+	free(hdr);
+
+	return res;
+}
+
+
+static int hostap_sta_set_flags(void *priv, const u8 *addr,
+				int total_flags, int flags_or, int flags_and)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+
+	if (flags_or & WPA_STA_AUTHORIZED)
+		flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		flags_and = ~BIT(5);
+	else
+		flags_and = ~0;
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+	param.u.set_flags_sta.flags_or = flags_or;
+	param.u.set_flags_sta.flags_and = flags_and;
+	return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_set_iface_flags(void *priv, int dev_up)
+{
+	struct hostap_driver_data *drv = priv;
+	struct ifreq ifr;
+	char ifname[IFNAMSIZ];
+
+	os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface);
+	if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0)
+		return -1;
+
+	if (dev_up) {
+		memset(&ifr, 0, sizeof(ifr));
+		os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+		ifr.ifr_mtu = HOSTAPD_MTU;
+		if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+			perror("ioctl[SIOCSIFMTU]");
+			printf("Setting MTU failed - trying to survive with "
+			       "current value\n");
+		}
+	}
+
+	return 0;
+}
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+			 int len)
+{
+	struct hostap_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.data.pointer = (caddr_t) param;
+	iwr.u.data.length = len;
+
+	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+		perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
+				     enum wpa_alg alg, const u8 *addr,
+				     int key_idx, int set_tx,
+				     const u8 *seq, size_t seq_len,
+				     const u8 *key, size_t key_len)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param *param;
+	u8 *buf;
+	size_t blen;
+	int ret = 0;
+
+	blen = sizeof(*param) + key_len;
+	buf = os_zalloc(blen);
+	if (buf == NULL)
+		return -1;
+
+	param = (struct prism2_hostapd_param *) buf;
+	param->cmd = PRISM2_SET_ENCRYPTION;
+	if (addr == NULL)
+		memset(param->sta_addr, 0xff, ETH_ALEN);
+	else
+		memcpy(param->sta_addr, addr, ETH_ALEN);
+	switch (alg) {
+	case WPA_ALG_NONE:
+		os_strlcpy((char *) param->u.crypt.alg, "NONE",
+			   HOSTAP_CRYPT_ALG_NAME_LEN);
+		break;
+	case WPA_ALG_WEP:
+		os_strlcpy((char *) param->u.crypt.alg, "WEP",
+			   HOSTAP_CRYPT_ALG_NAME_LEN);
+		break;
+	case WPA_ALG_TKIP:
+		os_strlcpy((char *) param->u.crypt.alg, "TKIP",
+			   HOSTAP_CRYPT_ALG_NAME_LEN);
+		break;
+	case WPA_ALG_CCMP:
+		os_strlcpy((char *) param->u.crypt.alg, "CCMP",
+			   HOSTAP_CRYPT_ALG_NAME_LEN);
+		break;
+	default:
+		os_free(buf);
+		return -1;
+	}
+	param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+	param->u.crypt.idx = key_idx;
+	param->u.crypt.key_len = key_len;
+	memcpy((u8 *) (param + 1), key, key_len);
+
+	if (hostapd_ioctl(drv, param, blen)) {
+		printf("Failed to set encryption.\n");
+		ret = -1;
+	}
+	free(buf);
+
+	return ret;
+}
+
+
+static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
+			     int idx, u8 *seq)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param *param;
+	u8 *buf;
+	size_t blen;
+	int ret = 0;
+
+	blen = sizeof(*param) + 32;
+	buf = os_zalloc(blen);
+	if (buf == NULL)
+		return -1;
+
+	param = (struct prism2_hostapd_param *) buf;
+	param->cmd = PRISM2_GET_ENCRYPTION;
+	if (addr == NULL)
+		memset(param->sta_addr, 0xff, ETH_ALEN);
+	else
+		memcpy(param->sta_addr, addr, ETH_ALEN);
+	param->u.crypt.idx = idx;
+
+	if (hostapd_ioctl(drv, param, blen)) {
+		printf("Failed to get encryption.\n");
+		ret = -1;
+	} else {
+		memcpy(seq, param->u.crypt.seq, 8);
+	}
+	free(buf);
+
+	return ret;
+}
+
+
+static int hostap_ioctl_prism2param(void *priv, int param, int value)
+{
+	struct hostap_driver_data *drv = priv;
+	struct iwreq iwr;
+	int *i;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	i = (int *) iwr.u.name;
+	*i++ = param;
+	*i++ = value;
+
+	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+	struct hostap_driver_data *drv = priv;
+	int enabled = params->enabled;
+
+	/* enable kernel driver support for IEEE 802.1X */
+	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) {
+		printf("Could not setup IEEE 802.1X support in kernel driver."
+		       "\n");
+		return -1;
+	}
+
+	if (!enabled)
+		return 0;
+
+	/* use host driver implementation of encryption to allow
+	 * individual keys and passing plaintext EAPOL frames */
+	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) ||
+	    hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) {
+		printf("Could not setup host-based encryption in kernel "
+		       "driver.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostap_set_privacy(void *priv, int enabled)
+{
+	struct hostap_drvier_data *drv = priv;
+
+	return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+					enabled);
+}
+
+
+static int hostap_set_ssid(void *priv, const u8 *buf, int len)
+{
+	struct hostap_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	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;
+	iwr.u.essid.length = len + 1;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCSIWESSID]");
+		printf("len=%d\n", len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostap_flush(void *priv)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_FLUSH;
+	return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_read_sta_data(void *priv,
+				struct hostap_sta_driver_data *data,
+				const u8 *addr)
+{
+	struct hostap_driver_data *drv = priv;
+	char buf[1024], line[128], *pos;
+	FILE *f;
+	unsigned long val;
+
+	memset(data, 0, sizeof(*data));
+	snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
+		 drv->iface, MAC2STR(addr));
+
+	f = fopen(buf, "r");
+	if (!f)
+		return -1;
+	/* Need to read proc file with in one piece, so use large enough
+	 * buffer. */
+	setbuffer(f, buf, sizeof(buf));
+
+	while (fgets(line, sizeof(line), f)) {
+		pos = strchr(line, '=');
+		if (!pos)
+			continue;
+		*pos++ = '\0';
+		val = strtoul(pos, NULL, 10);
+		if (strcmp(line, "rx_packets") == 0)
+			data->rx_packets = val;
+		else if (strcmp(line, "tx_packets") == 0)
+			data->tx_packets = val;
+		else if (strcmp(line, "rx_bytes") == 0)
+			data->rx_bytes = val;
+		else if (strcmp(line, "tx_bytes") == 0)
+			data->tx_bytes = val;
+	}
+
+	fclose(f);
+
+	return 0;
+}
+
+
+static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+	int tx_supp_rates = 0;
+	size_t i;
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+
+	for (i = 0; i < params->supp_rates_len; i++) {
+		if ((params->supp_rates[i] & 0x7f) == 2)
+			tx_supp_rates |= WLAN_RATE_1M;
+		if ((params->supp_rates[i] & 0x7f) == 4)
+			tx_supp_rates |= WLAN_RATE_2M;
+		if ((params->supp_rates[i] & 0x7f) == 11)
+			tx_supp_rates |= WLAN_RATE_5M5;
+		if ((params->supp_rates[i] & 0x7f) == 22)
+			tx_supp_rates |= WLAN_RATE_11M;
+	}
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_ADD_STA;
+	memcpy(param.sta_addr, params->addr, ETH_ALEN);
+	param.u.add_sta.aid = params->aid;
+	param.u.add_sta.capability = params->capability;
+	param.u.add_sta.tx_supp_rates = tx_supp_rates;
+	return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_sta_remove(void *priv, const u8 *addr)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+
+	hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED);
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+	if (hostapd_ioctl(drv, &param, sizeof(param))) {
+		printf("Could not remove station from kernel driver.\n");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostap_get_inact_sec(void *priv, const u8 *addr)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+	if (hostapd_ioctl(drv, &param, sizeof(param))) {
+		return -1;
+	}
+
+	return param.u.get_info_sta.inactive_sec;
+}
+
+
+static int hostap_sta_clear_stats(void *priv, const u8 *addr)
+{
+	struct hostap_driver_data *drv = priv;
+	struct prism2_hostapd_param param;
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS;
+	memcpy(param.sta_addr, addr, ETH_ALEN);
+	if (hostapd_ioctl(drv, &param, sizeof(param))) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
+{
+	struct prism2_hostapd_param *param;
+	int res;
+	size_t blen, elem_len;
+
+	elem_len = drv->generic_ie_len + drv->wps_ie_len;
+	blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len;
+	if (blen < sizeof(*param))
+		blen = sizeof(*param);
+
+	param = os_zalloc(blen);
+	if (param == NULL)
+		return -1;
+
+	param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+	param->u.generic_elem.len = elem_len;
+	if (drv->generic_ie) {
+		os_memcpy(param->u.generic_elem.data, drv->generic_ie,
+			  drv->generic_ie_len);
+	}
+	if (drv->wps_ie) {
+		os_memcpy(&param->u.generic_elem.data[drv->generic_ie_len],
+			  drv->wps_ie, drv->wps_ie_len);
+	}
+	wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
+		    param->u.generic_elem.data, elem_len);
+	res = hostapd_ioctl(drv, param, blen);
+
+	os_free(param);
+
+	return res;
+}
+
+
+static int hostap_set_generic_elem(void *priv,
+				   const u8 *elem, size_t elem_len)
+{
+	struct hostap_driver_data *drv = priv;
+
+	os_free(drv->generic_ie);
+	drv->generic_ie = NULL;
+	drv->generic_ie_len = 0;
+	if (elem) {
+		drv->generic_ie = os_malloc(elem_len);
+		if (drv->generic_ie == NULL)
+			return -1;
+		os_memcpy(drv->generic_ie, elem, elem_len);
+		drv->generic_ie_len = elem_len;
+	}
+
+	return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+				const struct wpabuf *proberesp,
+				const struct wpabuf *assocresp)
+{
+	struct hostap_driver_data *drv = priv;
+
+	/*
+	 * Host AP driver supports only one set of extra IEs, so we need to
+	 * use the Probe Response IEs also for Beacon frames since they include
+	 * more information.
+	 */
+
+	os_free(drv->wps_ie);
+	drv->wps_ie = NULL;
+	drv->wps_ie_len = 0;
+	if (proberesp) {
+		drv->wps_ie = os_malloc(wpabuf_len(proberesp));
+		if (drv->wps_ie == NULL)
+			return -1;
+		os_memcpy(drv->wps_ie, wpabuf_head(proberesp),
+			  wpabuf_len(proberesp));
+		drv->wps_ie_len = wpabuf_len(proberesp);
+	}
+
+	return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
+				       char *custom)
+{
+	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+		char *pos;
+		u8 addr[ETH_ALEN];
+		pos = strstr(custom, "addr=");
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "without sender address ignored");
+			return;
+		}
+		pos += 5;
+		if (hwaddr_aton(pos, addr) == 0) {
+			union wpa_event_data data;
+			os_memset(&data, 0, sizeof(data));
+			data.michael_mic_failure.unicast = 1;
+			data.michael_mic_failure.src = addr;
+			wpa_supplicant_event(drv->hapd,
+					     EVENT_MICHAEL_MIC_FAILURE, &data);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "with invalid MAC address");
+		}
+	}
+}
+
+
+static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
+					    char *data, 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) {
+		/* 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)
+			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVCUSTOM)) {
+			/* 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);
+		} else {
+			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case IWEVCUSTOM:
+			if (custom + iwe->u.data.length > end)
+				return;
+			buf = malloc(iwe->u.data.length + 1);
+			if (buf == NULL)
+				return;
+			memcpy(buf, custom, iwe->u.data.length);
+			buf[iwe->u.data.length] = '\0';
+			hostapd_wireless_event_wireless_custom(drv, buf);
+			free(buf);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(void *ctx,
+					       struct ifinfomsg *ifi,
+					       u8 *buf, size_t len)
+{
+	struct hostap_driver_data *drv = ctx;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	/* TODO: use ifi->ifi_index to filter out wireless events from other
+	 * interfaces */
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			hostapd_wireless_event_wireless(
+				drv, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static int hostap_get_we_version(struct hostap_driver_data *drv)
+{
+	struct iw_range *range;
+	struct iwreq iwr;
+	int minlen;
+	size_t buflen;
+
+	drv->we_version = 0;
+
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
+	buflen = sizeof(struct iw_range) + 500;
+	range = os_zalloc(buflen);
+	if (range == NULL)
+		return -1;
+
+	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;
+
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWRANGE]");
+		free(range);
+		return -1;
+	} else if (iwr.u.data.length >= minlen &&
+		   range->we_version_compiled >= 18) {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+			   "WE(source)=%d enc_capa=0x%x",
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
+		drv->we_version = range->we_version_compiled;
+	}
+
+	free(range);
+	return 0;
+}
+
+
+static int hostap_wireless_event_init(struct hostap_driver_data *drv)
+{
+	struct netlink_config *cfg;
+
+	hostap_get_we_version(drv);
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		return -1;
+	cfg->ctx = drv;
+	cfg->newlink_cb = hostapd_wireless_event_rtm_newlink;
+	drv->netlink = netlink_init(cfg);
+	if (drv->netlink == NULL) {
+		os_free(cfg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void * hostap_init(struct hostapd_data *hapd,
+			  struct wpa_init_params *params)
+{
+	struct hostap_driver_data *drv;
+
+	drv = os_zalloc(sizeof(struct hostap_driver_data));
+	if (drv == NULL) {
+		printf("Could not allocate memory for hostapd driver data\n");
+		return NULL;
+	}
+
+	drv->hapd = hapd;
+	drv->ioctl_sock = drv->sock = -1;
+	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->ioctl_sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		free(drv);
+		return NULL;
+	}
+
+	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
+		printf("Could not enable hostapd mode for interface %s\n",
+		       drv->iface);
+		close(drv->ioctl_sock);
+		free(drv);
+		return NULL;
+	}
+
+	if (hostap_init_sockets(drv, params->own_addr) ||
+	    hostap_wireless_event_init(drv)) {
+		close(drv->ioctl_sock);
+		free(drv);
+		return NULL;
+	}
+
+	return drv;
+}
+
+
+static void hostap_driver_deinit(void *priv)
+{
+	struct hostap_driver_data *drv = priv;
+
+	netlink_deinit(drv->netlink);
+	(void) hostap_set_iface_flags(drv, 0);
+	(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
+	(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
+
+	if (drv->ioctl_sock >= 0)
+		close(drv->ioctl_sock);
+
+	if (drv->sock >= 0)
+		close(drv->sock);
+
+	os_free(drv->generic_ie);
+	os_free(drv->wps_ie);
+
+	free(drv);
+}
+
+
+static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+			     int reason)
+{
+	struct hostap_driver_data *drv = priv;
+	struct ieee80211_mgmt mgmt;
+
+	if (is_broadcast_ether_addr(addr)) {
+		/*
+		 * New Prism2.5/3 STA firmware versions seem to have issues
+		 * with this broadcast deauth frame. This gets the firmware in
+		 * odd state where nothing works correctly, so let's skip
+		 * sending this for the hostap driver.
+		 */
+		return 0;
+	}
+
+	memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_DEAUTH);
+	memcpy(mgmt.da, addr, ETH_ALEN);
+	memcpy(mgmt.sa, own_addr, ETH_ALEN);
+	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+	mgmt.u.deauth.reason_code = host_to_le16(reason);
+	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
+				sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct hostap_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.freq.m = freq->channel;
+	iwr.u.freq.e = 0;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+			       int reason)
+{
+	struct hostap_driver_data *drv = priv;
+	struct ieee80211_mgmt mgmt;
+
+	memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_DISASSOC);
+	memcpy(mgmt.da, addr, ETH_ALEN);
+	memcpy(mgmt.sa, own_addr, ETH_ALEN);
+	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+	mgmt.u.disassoc.reason_code = host_to_le16(reason);
+	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
+				 sizeof(mgmt.u.disassoc), 0);
+}
+
+
+static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
+							    u16 *num_modes,
+							    u16 *flags)
+{
+	struct hostapd_hw_modes *mode;
+	int i, clen, rlen;
+	const short chan2freq[14] = {
+		2412, 2417, 2422, 2427, 2432, 2437, 2442,
+		2447, 2452, 2457, 2462, 2467, 2472, 2484
+	};
+
+	mode = os_zalloc(sizeof(struct hostapd_hw_modes));
+	if (mode == NULL)
+		return NULL;
+
+	*num_modes = 1;
+	*flags = 0;
+
+	mode->mode = HOSTAPD_MODE_IEEE80211B;
+	mode->num_channels = 14;
+	mode->num_rates = 4;
+
+	clen = mode->num_channels * sizeof(struct hostapd_channel_data);
+	rlen = mode->num_rates * sizeof(int);
+
+	mode->channels = os_zalloc(clen);
+	mode->rates = os_zalloc(rlen);
+	if (mode->channels == NULL || mode->rates == NULL) {
+		os_free(mode->channels);
+		os_free(mode->rates);
+		os_free(mode);
+		return NULL;
+	}
+
+	for (i = 0; i < 14; i++) {
+		mode->channels[i].chan = i + 1;
+		mode->channels[i].freq = chan2freq[i];
+		/* TODO: Get allowed channel list from the driver */
+		if (i >= 11)
+			mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
+	}
+
+	mode->rates[0] = 10;
+	mode->rates[1] = 20;
+	mode->rates[2] = 55;
+	mode->rates[3] = 110;
+
+	return mode;
+}
+
+
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+					  const u8 *addr, int qos)
+{
+	struct ieee80211_hdr hdr;
+
+	os_memset(&hdr, 0, sizeof(hdr));
+
+	/*
+	 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+	 * but it is apparently not retried so TX Exc events
+	 * are not received for it.
+	 * This is the reason the driver overrides the default
+	 * handling.
+	 */
+	hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+					 WLAN_FC_STYPE_DATA);
+
+	hdr.frame_control |=
+		host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	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);
+}
+
+
+const struct wpa_driver_ops wpa_driver_hostap_ops = {
+	.name = "hostap",
+	.desc = "Host AP driver (Intersil Prism2/2.5/3)",
+	.set_key = wpa_driver_hostap_set_key,
+	.hapd_init = hostap_init,
+	.hapd_deinit = hostap_driver_deinit,
+	.set_ieee8021x = hostap_set_ieee8021x,
+	.set_privacy = hostap_set_privacy,
+	.get_seqnum = hostap_get_seqnum,
+	.flush = hostap_flush,
+	.set_generic_elem = hostap_set_generic_elem,
+	.read_sta_data = hostap_read_sta_data,
+	.hapd_send_eapol = hostap_send_eapol,
+	.sta_set_flags = hostap_sta_set_flags,
+	.sta_deauth = hostap_sta_deauth,
+	.sta_disassoc = hostap_sta_disassoc,
+	.sta_remove = hostap_sta_remove,
+	.hapd_set_ssid = hostap_set_ssid,
+	.send_mlme = hostap_send_mlme,
+	.sta_add = hostap_sta_add,
+	.get_inact_sec = hostap_get_inact_sec,
+	.sta_clear_stats = hostap_sta_clear_stats,
+	.get_hw_feature_data = hostap_get_hw_feature_data,
+	.set_ap_wps_ie = hostap_set_ap_wps_ie,
+	.set_freq = hostap_set_freq,
+	.poll_client = wpa_driver_hostap_poll_client,
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_hostap.h
===================================================================
--- vendor/wpa/dist/src/drivers/driver_hostap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_hostap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,216 +0,0 @@
-/*
- * Driver interaction with Linux Host AP driver
- * Copyright (c) 2002-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HOSTAP_DRIVER_H
-#define HOSTAP_DRIVER_H
-
-/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
-
-/* New wireless extensions API - SET/GET convention (even ioctl numbers are
- * root only)
- */
-#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
-#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
-#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
-#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
-#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
-#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
-#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
-#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
-#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
-#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
-#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
-#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
-
-/* following are not in SIOCGIWPRIV list; check permission in the driver code
- */
-#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
-#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
-
-
-/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
-enum {
-	/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
-	PRISM2_PARAM_TXRATECTRL = 2,
-	PRISM2_PARAM_BEACON_INT = 3,
-	PRISM2_PARAM_PSEUDO_IBSS = 4,
-	PRISM2_PARAM_ALC = 5,
-	/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
-	PRISM2_PARAM_DUMP = 7,
-	PRISM2_PARAM_OTHER_AP_POLICY = 8,
-	PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
-	PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
-	PRISM2_PARAM_DTIM_PERIOD = 11,
-	PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
-	PRISM2_PARAM_MAX_WDS = 13,
-	PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
-	PRISM2_PARAM_AP_AUTH_ALGS = 15,
-	PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
-	PRISM2_PARAM_HOST_ENCRYPT = 17,
-	PRISM2_PARAM_HOST_DECRYPT = 18,
-	PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
-	PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
-	PRISM2_PARAM_HOST_ROAMING = 21,
-	PRISM2_PARAM_BCRX_STA_KEY = 22,
-	PRISM2_PARAM_IEEE_802_1X = 23,
-	PRISM2_PARAM_ANTSEL_TX = 24,
-	PRISM2_PARAM_ANTSEL_RX = 25,
-	PRISM2_PARAM_MONITOR_TYPE = 26,
-	PRISM2_PARAM_WDS_TYPE = 27,
-	PRISM2_PARAM_HOSTSCAN = 28,
-	PRISM2_PARAM_AP_SCAN = 29,
-	PRISM2_PARAM_ENH_SEC = 30,
-	PRISM2_PARAM_IO_DEBUG = 31,
-	PRISM2_PARAM_BASIC_RATES = 32,
-	PRISM2_PARAM_OPER_RATES = 33,
-	PRISM2_PARAM_HOSTAPD = 34,
-	PRISM2_PARAM_HOSTAPD_STA = 35,
-	PRISM2_PARAM_WPA = 36,
-	PRISM2_PARAM_PRIVACY_INVOKED = 37,
-	PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
-	PRISM2_PARAM_DROP_UNENCRYPTED = 39,
-	PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
-};
-
-enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
-       HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
-
-
-/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
-enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
-       AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
-       AP_MAC_CMD_KICKALL = 4 };
-
-
-/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
-enum {
-	PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
-	/* Note! Old versions of prism2_srec have a fatal error in CRC-16
-	 * calculation, which will corrupt all non-volatile downloads.
-	 * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
-	 * prevent use of old versions of prism2_srec for non-volatile
-	 * download. */
-	PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
-	PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
-	/* Persistent versions of volatile download commands (keep firmware
-	 * data in memory and automatically re-download after hw_reset */
-	PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
-	PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
-};
-
-struct prism2_download_param {
-	u32 dl_cmd;
-	u32 start_addr;
-	u32 num_areas;
-	struct prism2_download_area {
-		u32 addr; /* wlan card address */
-		u32 len;
-		caddr_t ptr; /* pointer to data in user space */
-	} data[0];
-};
-
-#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
-#define PRISM2_MAX_DOWNLOAD_LEN 262144
-
-
-/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
-enum {
-	PRISM2_HOSTAPD_FLUSH = 1,
-	PRISM2_HOSTAPD_ADD_STA = 2,
-	PRISM2_HOSTAPD_REMOVE_STA = 3,
-	PRISM2_HOSTAPD_GET_INFO_STA = 4,
-	/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
-	PRISM2_SET_ENCRYPTION = 6,
-	PRISM2_GET_ENCRYPTION = 7,
-	PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
-	PRISM2_HOSTAPD_GET_RID = 9,
-	PRISM2_HOSTAPD_SET_RID = 10,
-	PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
-	PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
-	PRISM2_HOSTAPD_MLME = 13,
-	PRISM2_HOSTAPD_SCAN_REQ = 14,
-	PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
-};
-
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
-#define PRISM2_HOSTAPD_RID_HDR_LEN \
-((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
-#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
-
-/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
- */
-#define HOSTAP_CRYPT_ALG_NAME_LEN 16
-
-
-struct prism2_hostapd_param {
-	u32 cmd;
-	u8 sta_addr[ETH_ALEN];
-	union {
-		struct {
-			u16 aid;
-			u16 capability;
-			u8 tx_supp_rates;
-		} add_sta;
-		struct {
-			u32 inactive_sec;
-		} get_info_sta;
-		struct {
-			u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
-			u32 flags;
-			u32 err;
-			u8 idx;
-			u8 seq[8]; /* sequence counter (set: RX, get: TX) */
-			u16 key_len;
-			u8 key[0];
-		} crypt;
-		struct {
-			u32 flags_and;
-			u32 flags_or;
-		} set_flags_sta;
-		struct {
-			u16 rid;
-			u16 len;
-			u8 data[0];
-		} rid;
-		struct {
-			u8 len;
-			u8 data[0];
-		} generic_elem;
-		struct {
-#define MLME_STA_DEAUTH 0
-#define MLME_STA_DISASSOC 1
-			u16 cmd;
-			u16 reason_code;
-		} mlme;
-		struct {
-			u8 ssid_len;
-			u8 ssid[32];
-		} scan_req;
-	} u;
-};
-
-#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
-#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
-
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
-#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
-#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
-#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
-#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
-
-#endif /* HOSTAP_DRIVER_H */

Copied: vendor/wpa/2.0/src/drivers/driver_hostap.h (from rev 9639, vendor/wpa/dist/src/drivers/driver_hostap.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_hostap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_hostap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,210 @@
+/*
+ * Driver interaction with Linux Host AP driver
+ * Copyright (c) 2002-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAP_DRIVER_H
+#define HOSTAP_DRIVER_H
+
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+	/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+	PRISM2_PARAM_TXRATECTRL = 2,
+	PRISM2_PARAM_BEACON_INT = 3,
+	PRISM2_PARAM_PSEUDO_IBSS = 4,
+	PRISM2_PARAM_ALC = 5,
+	/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+	PRISM2_PARAM_DUMP = 7,
+	PRISM2_PARAM_OTHER_AP_POLICY = 8,
+	PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+	PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+	PRISM2_PARAM_DTIM_PERIOD = 11,
+	PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+	PRISM2_PARAM_MAX_WDS = 13,
+	PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+	PRISM2_PARAM_AP_AUTH_ALGS = 15,
+	PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+	PRISM2_PARAM_HOST_ENCRYPT = 17,
+	PRISM2_PARAM_HOST_DECRYPT = 18,
+	PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+	PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+	PRISM2_PARAM_HOST_ROAMING = 21,
+	PRISM2_PARAM_BCRX_STA_KEY = 22,
+	PRISM2_PARAM_IEEE_802_1X = 23,
+	PRISM2_PARAM_ANTSEL_TX = 24,
+	PRISM2_PARAM_ANTSEL_RX = 25,
+	PRISM2_PARAM_MONITOR_TYPE = 26,
+	PRISM2_PARAM_WDS_TYPE = 27,
+	PRISM2_PARAM_HOSTSCAN = 28,
+	PRISM2_PARAM_AP_SCAN = 29,
+	PRISM2_PARAM_ENH_SEC = 30,
+	PRISM2_PARAM_IO_DEBUG = 31,
+	PRISM2_PARAM_BASIC_RATES = 32,
+	PRISM2_PARAM_OPER_RATES = 33,
+	PRISM2_PARAM_HOSTAPD = 34,
+	PRISM2_PARAM_HOSTAPD_STA = 35,
+	PRISM2_PARAM_WPA = 36,
+	PRISM2_PARAM_PRIVACY_INVOKED = 37,
+	PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+	PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+	PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+       HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+       AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+       AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+	PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+	/* Note! Old versions of prism2_srec have a fatal error in CRC-16
+	 * calculation, which will corrupt all non-volatile downloads.
+	 * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+	 * prevent use of old versions of prism2_srec for non-volatile
+	 * download. */
+	PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+	PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+	/* Persistent versions of volatile download commands (keep firmware
+	 * data in memory and automatically re-download after hw_reset */
+	PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+	PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+	u32 dl_cmd;
+	u32 start_addr;
+	u32 num_areas;
+	struct prism2_download_area {
+		u32 addr; /* wlan card address */
+		u32 len;
+		caddr_t ptr; /* pointer to data in user space */
+	} data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+	PRISM2_HOSTAPD_FLUSH = 1,
+	PRISM2_HOSTAPD_ADD_STA = 2,
+	PRISM2_HOSTAPD_REMOVE_STA = 3,
+	PRISM2_HOSTAPD_GET_INFO_STA = 4,
+	/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+	PRISM2_SET_ENCRYPTION = 6,
+	PRISM2_GET_ENCRYPTION = 7,
+	PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+	PRISM2_HOSTAPD_GET_RID = 9,
+	PRISM2_HOSTAPD_SET_RID = 10,
+	PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+	PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+	PRISM2_HOSTAPD_MLME = 13,
+	PRISM2_HOSTAPD_SCAN_REQ = 14,
+	PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+	u32 cmd;
+	u8 sta_addr[ETH_ALEN];
+	union {
+		struct {
+			u16 aid;
+			u16 capability;
+			u8 tx_supp_rates;
+		} add_sta;
+		struct {
+			u32 inactive_sec;
+		} get_info_sta;
+		struct {
+			u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+			u32 flags;
+			u32 err;
+			u8 idx;
+			u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+			u16 key_len;
+			u8 key[0];
+		} crypt;
+		struct {
+			u32 flags_and;
+			u32 flags_or;
+		} set_flags_sta;
+		struct {
+			u16 rid;
+			u16 len;
+			u8 data[0];
+		} rid;
+		struct {
+			u8 len;
+			u8 data[0];
+		} generic_elem;
+		struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+			u16 cmd;
+			u16 reason_code;
+		} mlme;
+		struct {
+			u8 ssid_len;
+			u8 ssid[32];
+		} scan_req;
+	} u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#endif /* HOSTAP_DRIVER_H */

Deleted: vendor/wpa/2.0/src/drivers/driver_iphone.m
===================================================================
--- vendor/wpa/dist/src/drivers/driver_iphone.m	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_iphone.m	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,466 +0,0 @@
-/*
- * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "MobileApple80211.h"
-
-struct wpa_driver_iphone_data {
-	void *ctx;
-	Apple80211Ref wireless_ctx;
-	CFArrayRef scan_results;
-	int ctrl_power;
-};
-
-
-static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
-{
-	const void *res;
-	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
-						    kCFStringEncodingMacRoman);
-	if (str == NULL)
-		return NULL;
-
-	res = CFDictionaryGetValue(dict, str);
-	CFRelease(str);
-	return res;
-}
-
-
-static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFDataRef data;
-	int err, len;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	len = CFDataGetLength(data);
-	if (len > 32) {
-		CFRelease(data);
-		return -1;
-	}
-	os_memcpy(ssid, CFDataGetBytePtr(data), len);
-	CFRelease(data);
-
-	return len;
-}
-
-
-static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFStringRef data;
-	int err;
-	int a1, a2, a3, a4, a5, a6;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
-	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
-	bssid[0] = a1;
-	bssid[1] = a2;
-	bssid[2] = a3;
-	bssid[3] = a4;
-	bssid[4] = a5;
-	bssid[5] = a6;
-
-	CFRelease(data);
-
-	return 0;
-}
-
-
-static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
-			   err);
-		return -1;
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static int wpa_driver_iphone_get_scan_results(void *priv,
-					      struct wpa_scan_result *results,
-					      size_t max_size)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-	if (num > max_size)
-		num = max_size;
-	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
-
-	for (i = 0; i < num; i++) {
-		struct wpa_scan_result *res = &results[i];
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-		CFStringRef str;
-		CFNumberRef num;
-		int val;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data) {
-			res->ssid_len = CFDataGetLength(data);
-			if (res->ssid_len > 32)
-				res->ssid_len = 32;
-			os_memcpy(res->ssid, CFDataGetBytePtr(data),
-				  res->ssid_len);
-		}
-
-		str = cfdict_get_key_str(dict, "BSSID");
-		if (str) {
-			int a1, a2, a3, a4, a5, a6;
-			sscanf(CFStringGetCStringPtr(
-				       str, kCFStringEncodingMacRoman),
-			       "%x:%x:%x:%x:%x:%x",
-			       &a1, &a2, &a3, &a4, &a5, &a6);
-			res->bssid[0] = a1;
-			res->bssid[1] = a2;
-			res->bssid[2] = a3;
-			res->bssid[3] = a4;
-			res->bssid[4] = a5;
-			res->bssid[5] = a6;
-		}
-
-		num = cfdict_get_key_str(dict, "CAPABILITIES");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->caps = val;
-		}
-
-		num = cfdict_get_key_str(dict, "CHANNEL");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->freq = 2407 + val * 5;
-		}
-
-		num = cfdict_get_key_str(dict, "RSSI");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->level = val;
-		}
-
-		num = cfdict_get_key_str(dict, "NOISE");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->noise = val;
-		}
-
-		data = cfdict_get_key_str(dict, "IE");
-		if (data) {
-			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
-			int len = CFDataGetLength(data);
-			u8 *pos = ptr, *end = ptr + len;
-
-			while (pos + 2 < end) {
-				if (pos + 2 + pos[1] > end)
-					break;
-				if (pos[0] == WLAN_EID_RSN &&
-				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
-					os_memcpy(res->rsn_ie, pos,
-						  2 + pos[1]);
-					res->rsn_ie_len = 2 + pos[1];
-				}
-				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
-				    pos[1] > 4 && pos[2] == 0x00 &&
-				    pos[3] == 0x50 && pos[4] == 0xf2 &&
-				    pos[5] == 0x01) {
-					os_memcpy(res->wpa_ie, pos,
-						  2 + pos[1]);
-					res->wpa_ie_len = 2 + pos[1];
-				}
-
-				pos = pos + 2 + pos[1];
-			}
-		}
-	}
-
-	return num;
-}
-
-
-static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_iphone_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-
-	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_iphone_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int i, num, err;
-	size_t ssid_len;
-	CFDictionaryRef bss = NULL;
-
-	/*
-	 * TODO: Consider generating parameters instead of just using an entry
-	 * from scan results in order to support ap_scan=2.
-	 */
-
-	if (drv->scan_results == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
-			   "associate");
-		return -1;
-	}
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	for (i = 0; i < num; i++) {
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data == NULL)
-			continue;
-
-		ssid_len = CFDataGetLength(data);
-		if (ssid_len != params->ssid_len ||
-		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
-		    != 0)
-			continue;
-
-		bss = dict;
-		break;
-	}
-
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
-			   "results - cannot associate");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
-		   "from scan results");
-
-	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
-			   "%d", err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx, const u8 *seq,
-				     size_t seq_len, const u8 *key,
-				     size_t key_len)
-{
-	/*
-	 * TODO: Need to either support configuring PMK for 4-way handshake or
-	 * PTK for TKIP/CCMP.
-	 */
-	return -1;
-}
-
-
-static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_iphone_data *drv;
-	int err;
-	char power;
-	CFStringRef name;
-	CFDictionaryRef dict;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = Apple80211Open(&drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
-			   err);
-		os_free(drv);
-		return NULL;
-	}
-
-	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
-					 kCFStringEncodingISOLatin1);
-	if (name == NULL) {
-		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211BindToInterface(drv->wireless_ctx, name);
-	CFRelease(name);
-
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
-			   "failed: %d", err);
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211GetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
-			   err);
-
-	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
-
-	if (!power) {
-		drv->ctrl_power = 1;
-		err = Apple80211SetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
-				   "failed: %d", err);
-			Apple80211Close(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
-	if (err == 0) {
-		CFShow(dict);
-		CFRelease(dict);
-	} else {
-		printf("Apple80211GetInfoCopy: %d\n", err);
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_iphone_deinit(void *priv)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-
-	if (drv->ctrl_power) {
-		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
-		err = Apple80211SetPower(drv->wireless_ctx, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
-				   "failed: %d", err);
-		}
-	}
-
-	err = Apple80211Close(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
-			   err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_iphone_ops = {
-	.name = "iphone",
-	.desc = "iPhone/iPod touch Apple80211 driver",
-	.get_ssid = wpa_driver_iphone_get_ssid,
-	.get_bssid = wpa_driver_iphone_get_bssid,
-	.init = wpa_driver_iphone_init,
-	.deinit = wpa_driver_iphone_deinit,
-	.scan = wpa_driver_iphone_scan,
-	.get_scan_results = wpa_driver_iphone_get_scan_results,
-	.associate = wpa_driver_iphone_associate,
-	.set_key = wpa_driver_iphone_set_key,
-	.get_capa = wpa_driver_iphone_get_capa,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_ipw.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ipw.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ipw.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,472 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
- * Copyright (c) 2005 Zhu Yi <yi.zhu at intel.com>
- * Copyright (c) 2004 Lubomir Gelo <lgelo at cnc.sk>
- * Copyright (c) 2003-2004, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that ipw2100/2200 drivers change to use generic Linux wireless
- * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
- * or newer). driver_wext.c should be used in those cases.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_ipw_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
-
-#define IPW_IOCTL_WPA_SUPPLICANT		SIOCIWFIRSTPRIV+30
-
-#define IPW_CMD_SET_WPA_PARAM			1
-#define	IPW_CMD_SET_WPA_IE			2
-#define IPW_CMD_SET_ENCRYPTION			3
-#define IPW_CMD_MLME				4
-
-#define IPW_PARAM_WPA_ENABLED			1
-#define IPW_PARAM_TKIP_COUNTERMEASURES		2
-#define IPW_PARAM_DROP_UNENCRYPTED		3
-#define IPW_PARAM_PRIVACY_INVOKED		4
-#define IPW_PARAM_AUTH_ALGS			5
-#define IPW_PARAM_IEEE_802_1X			6
-
-#define IPW_MLME_STA_DEAUTH			1
-#define IPW_MLME_STA_DISASSOC			2
-
-#define IPW_CRYPT_ERR_UNKNOWN_ALG		2
-#define IPW_CRYPT_ERR_UNKNOWN_ADDR		3
-#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED		4
-#define IPW_CRYPT_ERR_KEY_SET_FAILED		5
-#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED		6
-#define IPW_CRYPT_ERR_CARD_CONF_FAILED		7
-
-#define	IPW_CRYPT_ALG_NAME_LEN			16
-
-struct ipw_param {
-	u32 cmd;
-	u8 sta_addr[ETH_ALEN];
-        union {
-		struct {
-			u8 name;
-			u32 value;
-		} wpa_param;
-		struct {
-			u32 len;
-			u8 reserved[32];
-			u8 data[0];
-		} wpa_ie;
-	        struct{
-			u32 command;
-    			u32 reason_code;
-		} mlme;
-		struct {
-			u8 alg[IPW_CRYPT_ALG_NAME_LEN];
-			u8 set_tx;
-			u32 err;
-			u8 idx;
-			u8 seq[8];
-			u16 key_len;
-			u8 key[0];
-		} crypt;
-
-	} u;
-};
-
-/* end of ipw2100.c and ipw2200.c code */
-
-static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg);
-
-static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
-		     struct ipw_param *param, int len, int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
-		int ret = errno;
-		if (show_err) 
-			perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
-		return ret;
-	}
-
-	return 0;
-}
-
-
-static void ipw_show_set_key_error(struct ipw_param *param)
-{
-	switch (param->u.crypt.err) {
-	case IPW_CRYPT_ERR_UNKNOWN_ALG:
-		wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-			   param->u.crypt.alg);
-		wpa_printf(MSG_INFO, "You may need to load kernel module to "
-			   "register that algorithm.");
-		wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
-			   " WEP.");
-		break;
-	case IPW_CRYPT_ERR_UNKNOWN_ADDR:
-		wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-			   MAC2STR(param->sta_addr));
-		break;
-	case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
-		wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-		break;
-	case IPW_CRYPT_ERR_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "Key setting failed.");
-		break;
-	case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "TX key index setting failed.");
-		break;
-	case IPW_CRYPT_ERR_CARD_CONF_FAILED:
-		wpa_printf(MSG_INFO, "Card configuration failed.");
-		break;
-	}
-}
-
-
-static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
-			  const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct ipw_param *param;
-	int ret;
-	size_t blen = sizeof(*param) + wpa_ie_len;
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = IPW_CMD_SET_WPA_IE;
-	param->u.wpa_ie.len = wpa_ie_len;
-	os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
-	
-	ret = ipw_ioctl(drv, param, blen, 1);
-
-	os_free(param);
-	return ret;
-}
-
-
-static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
-			     u32 value)
-{
-	struct ipw_param param;
-
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = IPW_CMD_SET_WPA_PARAM;
-	param.u.wpa_param.name = name;
-	param.u.wpa_param.value = value;
-
-	return ipw_ioctl(drv, &param, sizeof(param), 1);
-}
-
-
-static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
-		    int cmd, int reason)
-{
-	struct ipw_param param;
-
-	os_memset(&param, 0, sizeof(param));
-	os_memcpy(param.sta_addr, addr, ETH_ALEN);	
-	param.cmd = IPW_CMD_MLME;
-	param.u.mlme.command = cmd;
-	param.u.mlme.reason_code = reason;
-
-	return ipw_ioctl(drv, &param, sizeof(param), 1);
-}
-
-
-static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-	if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
-		ret = -1;
-
-	if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static int wpa_driver_ipw_set_key(const char *ifname, void *priv,
-				  enum wpa_alg alg, const u8 *addr,
-				  int key_idx, int set_tx,
-				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	struct ipw_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-	char *alg_name;
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		alg_name = "none";
-		break;
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		break;
-	default:
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > 8)
-		return -2;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct ipw_param *) buf;
-	param->cmd = IPW_CMD_SET_ENCRYPTION;
-	os_memset(param->sta_addr, 0xff, ETH_ALEN);
-	os_strlcpy((char *) param->u.crypt.alg, alg_name,
-		   IPW_CRYPT_ALG_NAME_LEN);
-	param->u.crypt.set_tx = set_tx ? 1 : 0;
-	param->u.crypt.idx = key_idx;
-	os_memcpy(param->u.crypt.seq, seq, seq_len);
-	param->u.crypt.key_len = key_len;
-	os_memcpy((u8 *) (param + 1), key, key_len);
-
-	if (ipw_ioctl(drv, param, blen, 1)) {
-		wpa_printf(MSG_WARNING, "Failed to set encryption.");
-		ipw_show_set_key_error(param);
-		ret = -1;
-	}
-	os_free(buf);
-
-	return ret;
-}
-
-
-static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
-				     enabled);
-
-}
-
-
-static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
-				     enabled);
-}
-
-
-static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
-					 int reason_code)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
-}
-
-
-static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
-				       int reason_code)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
-}
-
-
-static int
-wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	int ret = 0;
-	int unencrypted_eapol;
-
-	if (wpa_driver_ipw_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	if (wpa_driver_ipw_set_drop_unencrypted(drv, params->drop_unencrypted)
-	    < 0)
-		ret = -1;
-	if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-				     params->ssid_len) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-		ret = -1;
-
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
-		unencrypted_eapol = 0;
-	else
-		unencrypted_eapol = 1;
-	
-	if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
-			      unencrypted_eapol) < 0) {
-		wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
-			   "ieee_802_1x param");
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	int algs = 0;
-
-	if (auth_alg & WPA_AUTH_ALG_OPEN)
-		algs |= 1;
-	if (auth_alg & WPA_AUTH_ALG_SHARED)
-		algs |= 2;
-	if (auth_alg & WPA_AUTH_ALG_LEAP)
-		algs |= 4;
-	if (algs == 0)
-		algs = 1; /* at least one algorithm should be set */
-
-	wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
-	return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_driver_ipw_scan(void *priv,
-			       struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_ipw_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_ipw_data *drv;
-	int ver;
-
-	wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	ver = wpa_driver_wext_get_version(drv->wext);
-	if (ver >= 18) {
-		wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
-			   "detected.", ver);
-		wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
-			   "(-Dwext) instead of driver_ipw.");
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	wpa_driver_ipw_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_driver_ipw_deinit(void *priv)
-{
-	struct wpa_driver_ipw_data *drv = priv;
-	wpa_driver_ipw_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_ipw_ops = {
-	.name = "ipw",
-	.desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
-	"or newer)",
-	.get_bssid = wpa_driver_ipw_get_bssid,
-	.get_ssid = wpa_driver_ipw_get_ssid,
-	.set_key = wpa_driver_ipw_set_key,
-	.set_countermeasures = wpa_driver_ipw_set_countermeasures,
-	.scan2 = wpa_driver_ipw_scan,
-	.get_scan_results2 = wpa_driver_ipw_get_scan_results,
-	.deauthenticate = wpa_driver_ipw_deauthenticate,
-	.disassociate = wpa_driver_ipw_disassociate,
-	.associate = wpa_driver_ipw_associate,
-	.init = wpa_driver_ipw_init,
-	.deinit = wpa_driver_ipw_deinit,
-	.set_operstate = wpa_driver_ipw_set_operstate,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_madwifi.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_madwifi.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_madwifi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1854 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
- * Copyright (c) 2004, Sam Leffler <sam at errno.com>
- * Copyright (c) 2004, Video54 Technologies
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * While this driver wrapper supports both AP (hostapd) and station
- * (wpa_supplicant) operations, the station side is deprecated and
- * driver_wext.c should be used instead. This driver wrapper should only be
- * used with hostapd for AP mode functionality.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "wireless_copy.h"
-
-/*
- * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
- */
-#undef WME_OUI_TYPE
-
-#include <include/compat.h>
-#include <net80211/ieee80211.h>
-#ifdef WME_NUM_AC
-/* Assume this is built against BSD branch of madwifi driver. */
-#define MADWIFI_BSD
-#include <net80211/_ieee80211.h>
-#endif /* WME_NUM_AC */
-#include <net80211/ieee80211_crypto.h>
-#include <net80211/ieee80211_ioctl.h>
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-#include <netpacket/packet.h>
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW 0x0019
-#endif
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-/*
- * Avoid conflicts with hostapd definitions by undefining couple of defines
- * from madwifi header files.
- */
-#undef RSN_VERSION
-#undef WPA_VERSION
-#undef WPA_OUI_TYPE
-#undef WME_OUI_TYPE
-
-
-#ifdef IEEE80211_IOCTL_SETWMMPARAMS
-/* Assume this is built against madwifi-ng */
-#define MADWIFI_NG
-#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
-
-
-#ifdef HOSTAPD
-
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "l2_packet/l2_packet.h"
-
-
-struct madwifi_driver_data {
-	struct hostapd_data *hapd;		/* back pointer */
-
-	char	iface[IFNAMSIZ + 1];
-	int     ifindex;
-	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */
-	struct l2_packet_data *sock_recv;	/* raw packet recv socket */
-	int	ioctl_sock;			/* socket for ioctl() use */
-	struct netlink_data *netlink;
-	int	we_version;
-	u8	acct_mac[ETH_ALEN];
-	struct hostap_sta_driver_data acct_data;
-
-	struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
-};
-
-static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			      int reason_code);
-
-static int
-set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
-{
-	struct iwreq iwr;
-	int do_inline = len < IFNAMSIZ;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-	/* FILTERFRAME must be NOT inline, regardless of size. */
-	if (op == IEEE80211_IOCTL_FILTERFRAME)
-		do_inline = 0;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-	if (op == IEEE80211_IOCTL_SET_APPIEBUF)
-		do_inline = 0;
-	if (do_inline) {
-		/*
-		 * Argument data fits inline; put it there.
-		 */
-		memcpy(iwr.u.name, data, len);
-	} else {
-		/*
-		 * Argument data too big for inline transfer; setup a
-		 * parameter block instead; the kernel will transfer
-		 * the data for the driver.
-		 */
-		iwr.u.data.pointer = data;
-		iwr.u.data.length = len;
-	}
-
-	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
-#ifdef MADWIFI_NG
-		int first = IEEE80211_IOCTL_SETPARAM;
-		static const char *opnames[] = {
-			"ioctl[IEEE80211_IOCTL_SETPARAM]",
-			"ioctl[IEEE80211_IOCTL_GETPARAM]",
-			"ioctl[IEEE80211_IOCTL_SETMODE]",
-			"ioctl[IEEE80211_IOCTL_GETMODE]",
-			"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
-			"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
-			"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
-			"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
-			"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
-			"ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
-			"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-			"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-			"ioctl[IEEE80211_IOCTL_FILTERFRAME]",
-			"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
-			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_SETMLME]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_SETKEY]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_DELKEY]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_ADDMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_DELMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_WDSMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_KICKMAC]",
-		};
-#else /* MADWIFI_NG */
-		int first = IEEE80211_IOCTL_SETPARAM;
-		static const char *opnames[] = {
-			"ioctl[IEEE80211_IOCTL_SETPARAM]",
-			"ioctl[IEEE80211_IOCTL_GETPARAM]",
-			"ioctl[IEEE80211_IOCTL_SETKEY]",
-			"ioctl[SIOCIWFIRSTPRIV+3]",
-			"ioctl[IEEE80211_IOCTL_DELKEY]",
-			"ioctl[SIOCIWFIRSTPRIV+5]",
-			"ioctl[IEEE80211_IOCTL_SETMLME]",
-			"ioctl[SIOCIWFIRSTPRIV+7]",
-			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_ADDMAC]",
-			"ioctl[SIOCIWFIRSTPRIV+11]",
-			"ioctl[IEEE80211_IOCTL_DELMAC]",
-			"ioctl[SIOCIWFIRSTPRIV+13]",
-			"ioctl[IEEE80211_IOCTL_CHANLIST]",
-			"ioctl[SIOCIWFIRSTPRIV+15]",
-			"ioctl[IEEE80211_IOCTL_GETRSN]",
-			"ioctl[SIOCIWFIRSTPRIV+17]",
-			"ioctl[IEEE80211_IOCTL_GETKEY]",
-		};
-#endif /* MADWIFI_NG */
-		int idx = op - first;
-		if (first <= op &&
-		    idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
-		    opnames[idx])
-			perror(opnames[idx]);
-		else
-			perror("ioctl[unknown???]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct madwifi_driver_data *drv, int op, int arg)
-{
-	struct iwreq iwr;
-
-	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));
-
-	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
-			   "arg %d)", __func__, op, arg);
-		return -1;
-	}
-	return 0;
-}
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char *
-ether_sprintf(const u8 *addr)
-{
-	static char buf[sizeof(MACSTR)];
-
-	if (addr != NULL)
-		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	else
-		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
-	return buf;
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-/*
- * Configure WPA parameters.
- */
-static int
-madwifi_configure_wpa(struct madwifi_driver_data *drv,
-		      struct wpa_bss_params *params)
-{
-	int v;
-
-	switch (params->wpa_group) {
-	case WPA_CIPHER_CCMP:
-		v = IEEE80211_CIPHER_AES_CCM;
-		break;
-	case WPA_CIPHER_TKIP:
-		v = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_NONE:
-		v = IEEE80211_CIPHER_NONE;
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
-			   params->wpa_group);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u\n", v);
-		return -1;
-	}
-	if (v == IEEE80211_CIPHER_WEP) {
-		/* key length is done only for specific ciphers */
-		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
-		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
-			return -1;
-		}
-	}
-
-	v = 0;
-	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
-		v |= 1<<IEEE80211_CIPHER_AES_CCM;
-	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
-		v |= 1<<IEEE80211_CIPHER_TKIP;
-	if (params->wpa_pairwise & WPA_CIPHER_NONE)
-		v |= 1<<IEEE80211_CIPHER_NONE;
-	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
-		   __func__, params->wpa_key_mgmt);
-	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
-			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
-		return -1;
-	}
-
-	v = 0;
-	if (params->rsn_preauth)
-		v |= BIT(0);
-	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
-		   __func__, params->rsn_preauth);
-	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
-	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
-
-	if (!params->enabled) {
-		/* XXX restore state */
-		return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-			IEEE80211_AUTH_AUTO);
-	}
-	if (!params->wpa && !params->ieee802_1x) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
-		return -1;
-	}
-	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
-		return -1;
-	}
-	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
-			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
-madwifi_set_privacy(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-
-	return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
-}
-
-static int
-madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
-		   __func__, ether_sprintf(addr), authorized);
-
-	if (authorized)
-		mlme.im_op = IEEE80211_MLME_AUTHORIZE;
-	else
-		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
-	mlme.im_reason = 0;
-	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,
-			   __func__, authorized ? "" : "un", MAC2STR(addr));
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_set_flags(void *priv, const u8 *addr,
-		      int total_flags, int flags_or, int flags_and)
-{
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		return madwifi_set_sta_authorized(priv, addr, 1);
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		return madwifi_set_sta_authorized(priv, addr, 0);
-	return 0;
-}
-
-static int
-madwifi_del_key(void *priv, const u8 *addr, int key_idx)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_del_key wk;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
-		   __func__, ether_sprintf(addr), key_idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr != NULL) {
-		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
-	} else {
-		wk.idk_keyix = key_idx;
-	}
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
-			   " key_idx %d)", __func__, ether_sprintf(addr),
-			   key_idx);
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			   const u8 *addr, int key_idx, int set_tx,
-			   const u8 *seq, size_t seq_len,
-			   const u8 *key, size_t key_len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-	u_int8_t cipher;
-	int ret;
-
-	if (alg == WPA_ALG_NONE)
-		return madwifi_del_key(drv, addr, key_idx);
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
-		   __func__, alg, ether_sprintf(addr), key_idx);
-
-	if (alg == WPA_ALG_WEP)
-		cipher = IEEE80211_CIPHER_WEP;
-	else if (alg == WPA_ALG_TKIP)
-		cipher = IEEE80211_CIPHER_TKIP;
-	else if (alg == WPA_ALG_CCMP)
-		cipher = IEEE80211_CIPHER_AES_CCM;
-	else {
-		printf("%s: unknown/unsupported algorithm %d\n",
-			__func__, alg);
-		return -1;
-	}
-
-	if (key_len > sizeof(wk.ik_keydata)) {
-		printf("%s: key length %lu too big\n", __func__,
-		       (unsigned long) key_len);
-		return -3;
-	}
-
-	memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
-	if (addr == NULL) {
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-		wk.ik_keyix = key_idx;
-		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
-	} else {
-		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);
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
-			   " key_idx %d alg %d key_len %lu set_tx %d)",
-			   __func__, ether_sprintf(wk.ik_macaddr), key_idx,
-			   alg, (unsigned long) key_len, set_tx);
-	}
-
-	return ret;
-}
-
-
-static int
-madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
-		   u8 *seq)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
-		   __func__, ether_sprintf(addr), idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr == NULL)
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-	else
-		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = idx;
-
-	if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
-			   "(addr " MACSTR " key_idx %d)",
-			   __func__, MAC2STR(wk.ik_macaddr), idx);
-		return -1;
-	}
-
-#ifdef WORDS_BIGENDIAN
-	{
-		/*
-		 * wk.ik_keytsc is in host byte order (big endian), need to
-		 * swap it to match with the byte order used in WPA.
-		 */
-		int i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		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));
-#endif /* WORDS_BIGENDIAN */
-	return 0;
-}
-
-
-static int 
-madwifi_flush(void *priv)
-{
-#ifdef MADWIFI_BSD
-	u8 allsta[IEEE80211_ADDR_LEN];
-	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
-	return madwifi_sta_deauth(priv, NULL, allsta,
-				  IEEE80211_REASON_AUTH_LEAVE);
-#else /* MADWIFI_BSD */
-	return 0;		/* XXX */
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
-			     const u8 *addr)
-{
-	struct madwifi_driver_data *drv = priv;
-
-#ifdef MADWIFI_BSD
-	struct ieee80211req_sta_stats stats;
-
-	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);
-	if (set80211priv(drv,
-#ifdef MADWIFI_NG
-			 IEEE80211_IOCTL_STA_STATS,
-#else /* MADWIFI_NG */
-			 IEEE80211_IOCTL_GETSTASTATS,
-#endif /* MADWIFI_NG */
-			 &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));
-			return 0;
-		}
-
-		printf("Failed to get station stats information element.\n");
-		return -1;
-	}
-
-	data->rx_packets = stats.is_stats.ns_rx_data;
-	data->rx_bytes = stats.is_stats.ns_rx_bytes;
-	data->tx_packets = stats.is_stats.ns_tx_data;
-	data->tx_bytes = stats.is_stats.ns_tx_bytes;
-	return 0;
-
-#else /* MADWIFI_BSD */
-
-	char buf[1024], line[128], *pos;
-	FILE *f;
-	unsigned long val;
-
-	memset(data, 0, sizeof(*data));
-	snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
-		 drv->iface, MAC2STR(addr));
-
-	f = fopen(buf, "r");
-	if (!f) {
-		if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
-			return -1;
-		memcpy(data, &drv->acct_data, sizeof(*data));
-		return 0;
-	}
-	/* Need to read proc file with in one piece, so use large enough
-	 * buffer. */
-	setbuffer(f, buf, sizeof(buf));
-
-	while (fgets(line, sizeof(line), f)) {
-		pos = strchr(line, '=');
-		if (!pos)
-			continue;
-		*pos++ = '\0';
-		val = strtoul(pos, NULL, 10);
-		if (strcmp(line, "rx_packets") == 0)
-			data->rx_packets = val;
-		else if (strcmp(line, "tx_packets") == 0)
-			data->tx_packets = val;
-		else if (strcmp(line, "rx_bytes") == 0)
-			data->rx_bytes = val;
-		else if (strcmp(line, "tx_bytes") == 0)
-			data->tx_bytes = val;
-	}
-
-	fclose(f);
-
-	return 0;
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_sta_clear_stats(void *priv, const u8 *addr)
-{
-#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	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);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-			   sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
-			   MACSTR ")", __func__, MAC2STR(addr));
-	}
-
-	return ret;
-#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
-	return 0; /* FIX */
-#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
-}
-
-
-static int
-madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
-{
-	/*
-	 * Do nothing; we setup parameters at startup that define the
-	 * contents of the beacon information element.
-	 */
-	return 0;
-}
-
-static int
-madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-		   int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	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
-			   " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-		     int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	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 "
-			   MACSTR " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	union wpa_event_data event;
-
-	/* Send Probe Request information to WPS processing */
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
-	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_probe_req.sa = mgmt->sa;
-	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-	event.rx_probe_req.ie_len =
-		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
-{
-	int ret = 0;
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-	struct ieee80211req_set_filter filt;
-
-	wpa_printf(MSG_DEBUG, "%s Enter", __func__);
-	filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
-			   sizeof(struct ieee80211req_set_filter));
-	if (ret)
-		return ret;
-
-	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
-				       madwifi_raw_receive, drv, 1);
-	if (drv->sock_raw == NULL)
-		return -1;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-static int
-madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
-{
-	struct madwifi_driver_data *drv = priv;
-	u8 buf[256];
-	struct ieee80211req_getset_appiebuf *beac_ie;
-
-	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-		   (unsigned long) len);
-
-	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
-	beac_ie->app_frmtype = frametype;
-	beac_ie->app_buflen = len;
-	memcpy(&(beac_ie->app_buf[0]), ie, len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
-			    sizeof(struct ieee80211req_getset_appiebuf) + len);
-}
-
-static int
-madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-		      const struct wpabuf *proberesp)
-{
-	if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
-			       beacon ? wpabuf_len(beacon) : 0,
-			       IEEE80211_APPIE_FRAME_BEACON) < 0)
-		return -1;
-	return madwifi_set_wps_ie(priv,
-				  proberesp ? wpabuf_head(proberesp) : NULL,
-				  proberesp ? wpabuf_len(proberesp) : 0,
-				  IEEE80211_APPIE_FRAME_PROBE_RESP);
-}
-#else /* CONFIG_WPS */
-#define madwifi_set_ap_wps_ie NULL
-#endif /* CONFIG_WPS */
-
-static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
-{
-	struct hostapd_data *hapd = drv->hapd;
-	struct ieee80211req_wpaie ie;
-	int ielen = 0;
-	u8 *iebuf = NULL;
-
-	/*
-	 * Fetch negotiated WPA/RSN parameters from the system.
-	 */
-	memset(&ie, 0, sizeof(ie));
-	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
-	if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE",
-			   __func__);
-		goto no_ie;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
-		    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
-	iebuf = ie.wpa_ie;
-	/* madwifi seems to return some random data if WPA/RSN IE is not set.
-	 * Assume the IE was not included if the IE type is unknown. */
-	if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
-		iebuf[1] = 0;
-#ifdef MADWIFI_NG
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
-		    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
-	if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
-		/* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
-		 * set. This is needed for WPA2. */
-		iebuf = ie.rsn_ie;
-		if (iebuf[0] != WLAN_EID_RSN)
-			iebuf[1] = 0;
-	}
-#endif /* MADWIFI_NG */
-
-	ielen = iebuf[1];
-	if (ielen == 0)
-		iebuf = NULL;
-	else
-		ielen += 2;
-
-no_ie:
-	drv_event_assoc(hapd, addr, iebuf, ielen);
-
-	if (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));
-	}
-}
-
-static void
-madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
-				       char *custom)
-{
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		char *pos;
-		u8 addr[ETH_ALEN];
-		pos = strstr(custom, "addr=");
-		if (pos == NULL) {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "without sender address ignored");
-			return;
-		}
-		pos += 5;
-		if (hwaddr_aton(pos, addr) == 0) {
-			union wpa_event_data data;
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = addr;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "with invalid MAC address");
-		}
-	} else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
-		char *key, *value;
-		u32 val;
-		key = custom;
-		while ((key = strchr(key, '\n')) != NULL) {
-			key++;
-			value = strchr(key, '=');
-			if (value == NULL)
-				continue;
-			*value++ = '\0';
-			val = strtoul(value, NULL, 10);
-			if (strcmp(key, "mac") == 0)
-				hwaddr_aton(value, drv->acct_mac);
-			else if (strcmp(key, "rx_packets") == 0)
-				drv->acct_data.rx_packets = val;
-			else if (strcmp(key, "tx_packets") == 0)
-				drv->acct_data.tx_packets = val;
-			else if (strcmp(key, "rx_bytes") == 0)
-				drv->acct_data.rx_bytes = val;
-			else if (strcmp(key, "tx_bytes") == 0)
-				drv->acct_data.tx_bytes = val;
-			key = value;
-		}
-	}
-}
-
-static void
-madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
-					    char *data, 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) {
-		/* Event data may be unaligned, so make a local, aligned copy
-		 * before processing. */
-		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)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (drv->we_version > 18 &&
-		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
-		     iwe->cmd == IWEVCUSTOM)) {
-			/* 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);
-		} else {
-			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVEXPIRED:
-			drv_event_disassoc(drv->hapd,
-					   (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVREGISTERED:
-			madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;		/* XXX */
-			memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-			madwifi_wireless_event_wireless_custom(drv, buf);
-			free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-
-static void
-madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
-				   u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	if (ifi->ifi_index != drv->ifindex)
-		return;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_WIRELESS) {
-			madwifi_wireless_event_wireless(
-				drv, ((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-static int
-madwifi_get_we_version(struct madwifi_driver_data *drv)
-{
-	struct iw_range *range;
-	struct iwreq iwr;
-	int minlen;
-	size_t buflen;
-
-	drv->we_version = 0;
-
-	/*
-	 * Use larger buffer than struct iw_range in order to allow the
-	 * structure to grow in the future.
-	 */
-	buflen = sizeof(struct iw_range) + 500;
-	range = os_zalloc(buflen);
-	if (range == NULL)
-		return -1;
-
-	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;
-
-	minlen = ((char *) &range->enc_capa) - (char *) range +
-		sizeof(range->enc_capa);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
-		return -1;
-	} else if (iwr.u.data.length >= minlen &&
-		   range->we_version_compiled >= 18) {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
-			   "WE(source)=%d enc_capa=0x%x",
-			   range->we_version_compiled,
-			   range->we_version_source,
-			   range->enc_capa);
-		drv->we_version = range->we_version_compiled;
-	}
-
-	free(range);
-	return 0;
-}
-
-
-static int
-madwifi_wireless_event_init(struct madwifi_driver_data *drv)
-{
-	struct netlink_config *cfg;
-
-	madwifi_get_we_version(drv);
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		return -1;
-	cfg->ctx = drv;
-	cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int
-madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-		   int encrypt, const u8 *own_addr)
-{
-	struct madwifi_driver_data *drv = priv;
-	unsigned char buf[3000];
-	unsigned char *bp = buf;
-	struct l2_ethhdr *eth;
-	size_t len;
-	int status;
-
-	/*
-	 * Prepend the Ethernet header.  If the caller left us
-	 * space at the front we could just insert it but since
-	 * we don't know we copy to a local buffer.  Given the frequency
-	 * and size of frames this probably doesn't matter.
-	 */
-	len = data_len + sizeof(struct l2_ethhdr);
-	if (len > sizeof(buf)) {
-		bp = malloc(len);
-		if (bp == NULL) {
-			printf("EAPOL frame discarded, cannot malloc temp "
-			       "buffer of size %lu!\n", (unsigned long) len);
-			return -1;
-		}
-	}
-	eth = (struct l2_ethhdr *) bp;
-	memcpy(eth->h_dest, addr, ETH_ALEN);
-	memcpy(eth->h_source, own_addr, ETH_ALEN);
-	eth->h_proto = host_to_be16(ETH_P_EAPOL);
-	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);
-	return status;
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
-			   len - sizeof(struct l2_ethhdr));
-}
-
-static void *
-madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
-{
-	struct madwifi_driver_data *drv;
-	struct ifreq ifr;
-	struct iwreq iwr;
-	char brname[IFNAMSIZ];
-
-	drv = os_zalloc(sizeof(struct madwifi_driver_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for madwifi driver data\n");
-		return NULL;
-	}
-
-	drv->hapd = hapd;
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		goto bad;
-	}
-	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
-
-	memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
-	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		goto bad;
-	}
-	drv->ifindex = ifr.ifr_ifindex;
-
-	drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
-					handle_read, drv, 1);
-	if (drv->sock_xmit == NULL)
-		goto bad;
-	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
-		goto bad;
-	if (params->bridge[0]) {
-		wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
-			   params->bridge[0]);
-		drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
-						ETH_P_EAPOL, handle_read, drv,
-						1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else if (linux_br_get(brname, drv->iface) == 0) {
-		wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
-			   "EAPOL receive", brname);
-		drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
-						handle_read, drv, 1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else
-		drv->sock_recv = drv->sock_xmit;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-
-	iwr.u.mode = IW_MODE_MASTER;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMODE]");
-		printf("Could not set interface to master mode!\n");
-		goto bad;
-	}
-
-	/* mark down during setup */
-	linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	madwifi_set_privacy(drv, 0); /* default to no privacy */
-
-	madwifi_receive_probe_req(drv);
-
-	if (madwifi_wireless_event_init(drv))
-		goto bad;
-
-	return drv;
-bad:
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv != NULL)
-		free(drv);
-	return NULL;
-}
-
-
-static void
-madwifi_deinit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	netlink_deinit(drv->netlink);
-	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
-		l2_packet_deinit(drv->sock_recv);
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock_raw)
-		l2_packet_deinit(drv->sock_raw);
-	free(drv);
-}
-
-static int
-madwifi_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	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;
-	iwr.u.essid.length = len + 1;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_get_ssid(void *priv, u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	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;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	return ret;
-}
-
-static int
-madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
-}
-
-static int
-madwifi_commit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
-}
-
-#else /* HOSTAPD */
-
-struct wpa_driver_madwifi_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg);
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len);
-
-
-static int
-set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
-	     int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	if (len < IFNAMSIZ &&
-	    op != IEEE80211_IOCTL_SET_APPIEBUF) {
-		/*
-		 * Argument data fits inline; put it there.
-		 */
-		os_memcpy(iwr.u.name, data, len);
-	} else {
-		/*
-		 * Argument data too big for inline transfer; setup a
-		 * parameter block instead; the kernel will transfer
-		 * the data for the driver.
-		 */
-		iwr.u.data.pointer = data;
-		iwr.u.data.length = len;
-	}
-
-	if (ioctl(drv->sock, op, &iwr) < 0) {
-		if (show_err) {
-#ifdef MADWIFI_NG
-			int first = IEEE80211_IOCTL_SETPARAM;
-			int last = IEEE80211_IOCTL_KICKMAC;
-			static const char *opnames[] = {
-				"ioctl[IEEE80211_IOCTL_SETPARAM]",
-				"ioctl[IEEE80211_IOCTL_GETPARAM]",
-				"ioctl[IEEE80211_IOCTL_SETMODE]",
-				"ioctl[IEEE80211_IOCTL_GETMODE]",
-				"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
-				"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
-				"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
-				"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
-				"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-				"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
-				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_SETMLME]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_ADDMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_WDSMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_KICKMAC]",
-			};
-#else /* MADWIFI_NG */
-			int first = IEEE80211_IOCTL_SETPARAM;
-			int last = IEEE80211_IOCTL_CHANLIST;
-			static const char *opnames[] = {
-				"ioctl[IEEE80211_IOCTL_SETPARAM]",
-				"ioctl[IEEE80211_IOCTL_GETPARAM]",
-				"ioctl[IEEE80211_IOCTL_SETKEY]",
-				"ioctl[IEEE80211_IOCTL_GETKEY]",
-				"ioctl[IEEE80211_IOCTL_DELKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETMLME]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_ADDMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_CHANLIST]",
-			};
-#endif /* MADWIFI_NG */
-			int idx = op - first;
-			if (first <= op && op <= last &&
-			    idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
-			    && opnames[idx])
-				perror(opnames[idx]);
-			else
-				perror("ioctl[unknown???]");
-		}
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
-	      int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.mode = op;
-	os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		if (show_err) 
-			perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
-			      const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	/* NB: SETOPTIE is not fixed-size so must not be inlined */
-	iwr.u.data.pointer = (void *) wpa_ie;
-	iwr.u.data.length = wpa_ie_len;
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
-			   const u8 *addr)
-{
-	struct ieee80211req_del_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
-	os_memset(&wk, 0, sizeof(wk));
-	wk.idk_keyix = key_idx;
-	if (addr != NULL)
-		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-
-	return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			   const u8 *addr, int key_idx, int set_tx,
-			   const u8 *seq, size_t seq_len,
-			   const u8 *key, size_t key_len)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_key wk;
-	char *alg_name;
-	u_int8_t cipher;
-
-	if (alg == WPA_ALG_NONE)
-		return wpa_driver_madwifi_del_key(drv, key_idx, addr);
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-					      ETH_ALEN) == 0) {
-			/*
-			 * madwifi did not seem to like static WEP key
-			 * configuration with IEEE80211_IOCTL_SETKEY, so use
-			 * Linux wireless extensions ioctl for this.
-			 */
-			return wpa_driver_wext_set_key(ifname, drv->wext, alg,
-						       addr, key_idx, set_tx,
-						       seq, seq_len,
-						       key, key_len);
-		}
-		alg_name = "WEP";
-		cipher = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		cipher = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		cipher = IEEE80211_CIPHER_AES_CCM;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
-			__FUNCTION__, alg);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > sizeof(u_int64_t)) {
-		wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
-			   __FUNCTION__, (unsigned long) seq_len);
-		return -2;
-	}
-	if (key_len > sizeof(wk.ik_keydata)) {
-		wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
-			   __FUNCTION__, (unsigned long) key_len);
-		return -3;
-	}
-
-	os_memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV;
-	if (addr == NULL ||
-	    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
-		wk.ik_flags |= IEEE80211_KEY_GROUP;
-	if (set_tx) {
-		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
-		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	} else
-		os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = key_idx;
-	wk.ik_keylen = key_len;
-#ifdef WORDS_BIGENDIAN
-#define WPA_KEY_RSC_LEN 8
-	{
-		size_t i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		os_memset(tmp, 0, sizeof(tmp));
-		for (i = 0; i < seq_len; i++)
-			tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
-		os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
-	}
-#else /* WORDS_BIGENDIAN */
-	os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-#endif /* WORDS_BIGENDIAN */
-	os_memcpy(wk.ik_keydata, key, key_len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
-}
-
-static int
-wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_associate(void *priv,
-			     struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret = 0, privacy = 1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED,
-			  params->drop_unencrypted, 1) < 0)
-		ret = -1;
-	if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-
-	/*
-	 * NB: Don't need to set the freq or cipher-related state as
-	 *     this is implied by the bssid which is used to locate
-	 *     the scanned node state which holds it.  The ssid is
-	 *     needed to disambiguate an AP that broadcasts multiple
-	 *     ssid's but uses the same bssid.
-	 */
-	/* XXX error handling is wrong but unclear what to do... */
-	if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
-					  params->wpa_ie_len) < 0)
-		ret = -1;
-
-	if (params->pairwise_suite == CIPHER_NONE &&
-	    params->group_suite == CIPHER_NONE &&
-	    params->key_mgmt_suite == KEY_MGMT_NONE &&
-	    params->wpa_ie_len == 0)
-		privacy = 0;
-
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
-		ret = -1;
-
-	if (params->wpa_ie_len &&
-	    set80211param(drv, IEEE80211_PARAM_WPA,
-			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
-		ret = -1;
-
-	if (params->bssid == NULL) {
-		/* ap_scan=2 mode - driver takes care of AP selection and
-		 * roaming */
-		/* FIX: this does not seem to work; would probably need to
-		 * change something in the driver */
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
-			ret = -1;
-
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-	} else {
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
-			ret = -1;
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-		os_memset(&mlme, 0, sizeof(mlme));
-		mlme.im_op = IEEE80211_MLME_ASSOC;
-		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
-		if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-				 sizeof(mlme), 1) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
-				   __func__);
-			ret = -1;
-		}
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	int authmode;
-
-	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
-	    (auth_alg & WPA_AUTH_ALG_SHARED))
-		authmode = IEEE80211_AUTH_AUTO;
-	else if (auth_alg & WPA_AUTH_ALG_SHARED)
-		authmode = IEEE80211_AUTH_SHARED;
-	else
-		authmode = IEEE80211_AUTH_OPEN;
-
-	return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
-}
-
-static int
-wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies,
-					    params->extra_ies_len);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	/* set desired ssid before scan */
-	/* FIX: scan should not break the current association, so using
-	 * set_ssid may not be the best way of doing this.. */
-	if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
-		ret = -1;
-
-	if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/*
-	 * madwifi delivers a scan complete event so no need to poll, but
-	 * register a backup timeout anyway to make sure that we recover even
-	 * if the driver does not send this event for any reason. This timeout
-	 * will only be used if the event is not delivered (event handler will
-	 * cancel the timeout).
-	 */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_madwifi_get_scan_results(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_madwifi_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len)
-{
-	struct ieee80211req_getset_appiebuf *probe_req_ie;
-	int ret;
-
-	probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
-	if (probe_req_ie == NULL)
-		return -1;
-
-	probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
-	probe_req_ie->app_buflen = ies_len;
-	os_memcpy(probe_req_ie->app_buf, ies, ies_len);
-
-	ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
-			   sizeof(struct ieee80211req_getset_appiebuf) +
-			   ies_len, 1);
-
-	os_free(probe_req_ie);
-
-	return ret;
-}
-
-
-static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_madwifi_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL)
-		goto fail;
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail2;
-
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
-			   "roaming", __FUNCTION__);
-		goto fail3;
-	}
-
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
-			   __FUNCTION__);
-		goto fail3;
-	}
-
-	return drv;
-
-fail3:
-	close(drv->sock);
-fail2:
-	wpa_driver_wext_deinit(drv->wext);
-fail:
-	os_free(drv);
-	return NULL;
-}
-
-
-static void wpa_driver_madwifi_deinit(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-
-	if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
-			   __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
-			   "roaming", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
-			   "flag", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
-			   __FUNCTION__);
-	}
-
-	wpa_driver_wext_deinit(drv->wext);
-
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
-
-const struct wpa_driver_ops wpa_driver_madwifi_ops = {
-	.name			= "madwifi",
-	.desc			= "MADWIFI 802.11 support (Atheros, etc.)",
-	.set_key		= wpa_driver_madwifi_set_key,
-#ifdef HOSTAPD
-	.hapd_init		= madwifi_init,
-	.hapd_deinit		= madwifi_deinit,
-	.set_ieee8021x		= madwifi_set_ieee8021x,
-	.set_privacy		= madwifi_set_privacy,
-	.get_seqnum		= madwifi_get_seqnum,
-	.flush			= madwifi_flush,
-	.set_generic_elem	= madwifi_set_opt_ie,
-	.sta_set_flags		= madwifi_sta_set_flags,
-	.read_sta_data		= madwifi_read_sta_driver_data,
-	.hapd_send_eapol	= madwifi_send_eapol,
-	.sta_disassoc		= madwifi_sta_disassoc,
-	.sta_deauth		= madwifi_sta_deauth,
-	.hapd_set_ssid		= madwifi_set_ssid,
-	.hapd_get_ssid		= madwifi_get_ssid,
-	.hapd_set_countermeasures	= madwifi_set_countermeasures,
-	.sta_clear_stats        = madwifi_sta_clear_stats,
-	.commit			= madwifi_commit,
-	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid		= wpa_driver_madwifi_get_bssid,
-	.get_ssid		= wpa_driver_madwifi_get_ssid,
-	.init			= wpa_driver_madwifi_init,
-	.deinit			= wpa_driver_madwifi_deinit,
-	.set_countermeasures	= wpa_driver_madwifi_set_countermeasures,
-	.scan2			= wpa_driver_madwifi_scan,
-	.get_scan_results2	= wpa_driver_madwifi_get_scan_results,
-	.deauthenticate		= wpa_driver_madwifi_deauthenticate,
-	.disassociate		= wpa_driver_madwifi_disassociate,
-	.associate		= wpa_driver_madwifi_associate,
-	.set_operstate		= wpa_driver_madwifi_set_operstate,
-#endif /* HOSTAPD */
-};

Copied: vendor/wpa/2.0/src/drivers/driver_madwifi.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_madwifi.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_madwifi.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_madwifi.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1313 @@
+/*
+ * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
+ * Copyright (c) 2004, Sam Leffler <sam at errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * While this driver wrapper supports both AP (hostapd) and station
+ * (wpa_supplicant) operations, the station side is deprecated and
+ * driver_wext.c should be used instead. This driver wrapper should only be
+ * used with hostapd for AP mode functionality.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "linux_wext.h"
+
+/*
+ * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
+ */
+#undef WME_OUI_TYPE
+
+#include <include/compat.h>
+#include <net80211/ieee80211.h>
+#ifdef WME_NUM_AC
+/* Assume this is built against BSD branch of madwifi driver. */
+#define MADWIFI_BSD
+#include <net80211/_ieee80211.h>
+#endif /* WME_NUM_AC */
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+#include <netpacket/packet.h>
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from madwifi header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+#undef WME_OUI_TYPE
+
+
+#ifdef IEEE80211_IOCTL_SETWMMPARAMS
+/* Assume this is built against madwifi-ng */
+#define MADWIFI_NG
+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+#define WPA_KEY_RSC_LEN 8
+
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "l2_packet/l2_packet.h"
+
+
+struct madwifi_driver_data {
+	struct hostapd_data *hapd;		/* back pointer */
+
+	char	iface[IFNAMSIZ + 1];
+	int     ifindex;
+	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */
+	struct l2_packet_data *sock_recv;	/* raw packet recv socket */
+	int	ioctl_sock;			/* socket for ioctl() use */
+	struct netlink_data *netlink;
+	int	we_version;
+	u8	acct_mac[ETH_ALEN];
+	struct hostap_sta_driver_data acct_data;
+
+	struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+			      int reason_code);
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+	struct iwreq iwr;
+	int do_inline = len < IFNAMSIZ;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+	/* FILTERFRAME must be NOT inline, regardless of size. */
+	if (op == IEEE80211_IOCTL_FILTERFRAME)
+		do_inline = 0;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+	if (op == IEEE80211_IOCTL_SET_APPIEBUF)
+		do_inline = 0;
+	if (do_inline) {
+		/*
+		 * Argument data fits inline; put it there.
+		 */
+		memcpy(iwr.u.name, data, len);
+	} else {
+		/*
+		 * Argument data too big for inline transfer; setup a
+		 * parameter block instead; the kernel will transfer
+		 * the data for the driver.
+		 */
+		iwr.u.data.pointer = data;
+		iwr.u.data.length = len;
+	}
+
+	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
+#ifdef MADWIFI_NG
+		int first = IEEE80211_IOCTL_SETPARAM;
+		static const char *opnames[] = {
+			"ioctl[IEEE80211_IOCTL_SETPARAM]",
+			"ioctl[IEEE80211_IOCTL_GETPARAM]",
+			"ioctl[IEEE80211_IOCTL_SETMODE]",
+			"ioctl[IEEE80211_IOCTL_GETMODE]",
+			"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+			"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+			"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+			"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+			"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+			"ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
+			"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+			"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+			"ioctl[IEEE80211_IOCTL_FILTERFRAME]",
+			"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
+			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
+			"ioctl[IEEE80211_IOCTL_SETMLME]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_SETKEY]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_DELKEY]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_ADDMAC]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_DELMAC]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_WDSMAC]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
+			NULL,
+			"ioctl[IEEE80211_IOCTL_KICKMAC]",
+		};
+#else /* MADWIFI_NG */
+		int first = IEEE80211_IOCTL_SETPARAM;
+		static const char *opnames[] = {
+			"ioctl[IEEE80211_IOCTL_SETPARAM]",
+			"ioctl[IEEE80211_IOCTL_GETPARAM]",
+			"ioctl[IEEE80211_IOCTL_SETKEY]",
+			"ioctl[SIOCIWFIRSTPRIV+3]",
+			"ioctl[IEEE80211_IOCTL_DELKEY]",
+			"ioctl[SIOCIWFIRSTPRIV+5]",
+			"ioctl[IEEE80211_IOCTL_SETMLME]",
+			"ioctl[SIOCIWFIRSTPRIV+7]",
+			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
+			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
+			"ioctl[IEEE80211_IOCTL_ADDMAC]",
+			"ioctl[SIOCIWFIRSTPRIV+11]",
+			"ioctl[IEEE80211_IOCTL_DELMAC]",
+			"ioctl[SIOCIWFIRSTPRIV+13]",
+			"ioctl[IEEE80211_IOCTL_CHANLIST]",
+			"ioctl[SIOCIWFIRSTPRIV+15]",
+			"ioctl[IEEE80211_IOCTL_GETRSN]",
+			"ioctl[SIOCIWFIRSTPRIV+17]",
+			"ioctl[IEEE80211_IOCTL_GETKEY]",
+		};
+#endif /* MADWIFI_NG */
+		int idx = op - first;
+		if (first <= op &&
+		    idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+		    opnames[idx])
+			perror(opnames[idx]);
+		else
+			perror("ioctl[unknown???]");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+	struct iwreq iwr;
+
+	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));
+
+	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+		wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
+			   "arg %d)", __func__, op, arg);
+		return -1;
+	}
+	return 0;
+}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char *
+ether_sprintf(const u8 *addr)
+{
+	static char buf[sizeof(MACSTR)];
+
+	if (addr != NULL)
+		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	else
+		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+	return buf;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv,
+		      struct wpa_bss_params *params)
+{
+	int v;
+
+	switch (params->wpa_group) {
+	case WPA_CIPHER_CCMP:
+		v = IEEE80211_CIPHER_AES_CCM;
+		break;
+	case WPA_CIPHER_TKIP:
+		v = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_CIPHER_WEP104:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_WEP40:
+		v = IEEE80211_CIPHER_WEP;
+		break;
+	case WPA_CIPHER_NONE:
+		v = IEEE80211_CIPHER_NONE;
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+			   params->wpa_group);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+		printf("Unable to set group key cipher to %u\n", v);
+		return -1;
+	}
+	if (v == IEEE80211_CIPHER_WEP) {
+		/* key length is done only for specific ciphers */
+		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+			printf("Unable to set group key length to %u\n", v);
+			return -1;
+		}
+	}
+
+	v = 0;
+	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
+		v |= 1<<IEEE80211_CIPHER_AES_CCM;
+	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
+		v |= 1<<IEEE80211_CIPHER_TKIP;
+	if (params->wpa_pairwise & WPA_CIPHER_NONE)
+		v |= 1<<IEEE80211_CIPHER_NONE;
+	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+		   __func__, params->wpa_key_mgmt);
+	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
+			  params->wpa_key_mgmt)) {
+		printf("Unable to set key management algorithms to 0x%x\n",
+			params->wpa_key_mgmt);
+		return -1;
+	}
+
+	v = 0;
+	if (params->rsn_preauth)
+		v |= BIT(0);
+	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+		   __func__, params->rsn_preauth);
+	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+		printf("Unable to set RSN capabilities to 0x%x\n", v);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
+	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
+		printf("Unable to set WPA to %u\n", params->wpa);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
+{
+	struct madwifi_driver_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
+
+	if (!params->enabled) {
+		/* XXX restore state */
+		return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+			IEEE80211_AUTH_AUTO);
+	}
+	if (!params->wpa && !params->ieee802_1x) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+		return -1;
+	}
+	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+		return -1;
+	}
+	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+		hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
+			HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+madwifi_set_privacy(void *priv, int enabled)
+{
+	struct madwifi_driver_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+	return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+		   __func__, ether_sprintf(addr), authorized);
+
+	if (authorized)
+		mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+	else
+		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+	mlme.im_reason = 0;
+	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,
+			   __func__, authorized ? "" : "un", MAC2STR(addr));
+	}
+
+	return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr,
+		      int total_flags, int flags_or, int flags_and)
+{
+	/* For now, only support setting Authorized flag */
+	if (flags_or & WPA_STA_AUTHORIZED)
+		return madwifi_set_sta_authorized(priv, addr, 1);
+	if (!(flags_and & WPA_STA_AUTHORIZED))
+		return madwifi_set_sta_authorized(priv, addr, 0);
+	return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_del_key wk;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+		   __func__, ether_sprintf(addr), key_idx);
+
+	memset(&wk, 0, sizeof(wk));
+	if (addr != NULL) {
+		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+	} else {
+		wk.idk_keyix = key_idx;
+	}
+
+	ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+			   " key_idx %d)", __func__, ether_sprintf(addr),
+			   key_idx);
+	}
+
+	return ret;
+}
+
+static int
+wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+			   const u8 *addr, int key_idx, int set_tx,
+			   const u8 *seq, size_t seq_len,
+			   const u8 *key, size_t key_len)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_key wk;
+	u_int8_t cipher;
+	int ret;
+
+	if (alg == WPA_ALG_NONE)
+		return madwifi_del_key(drv, addr, key_idx);
+
+	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
+		   __func__, alg, ether_sprintf(addr), key_idx);
+
+	if (alg == WPA_ALG_WEP)
+		cipher = IEEE80211_CIPHER_WEP;
+	else if (alg == WPA_ALG_TKIP)
+		cipher = IEEE80211_CIPHER_TKIP;
+	else if (alg == WPA_ALG_CCMP)
+		cipher = IEEE80211_CIPHER_AES_CCM;
+	else {
+		printf("%s: unknown/unsupported algorithm %d\n",
+			__func__, alg);
+		return -1;
+	}
+
+	if (key_len > sizeof(wk.ik_keydata)) {
+		printf("%s: key length %lu too big\n", __func__,
+		       (unsigned long) key_len);
+		return -3;
+	}
+
+	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);
+		wk.ik_keyix = key_idx;
+		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+	} else {
+		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);
+
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+			   " key_idx %d alg %d key_len %lu set_tx %d)",
+			   __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+			   alg, (unsigned long) key_len, set_tx);
+	}
+
+	return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+		   u8 *seq)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_key wk;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+		   __func__, ether_sprintf(addr), idx);
+
+	memset(&wk, 0, sizeof(wk));
+	if (addr == NULL)
+		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+	else
+		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+	wk.ik_keyix = idx;
+
+	if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+			   "(addr " MACSTR " key_idx %d)",
+			   __func__, MAC2STR(wk.ik_macaddr), idx);
+		return -1;
+	}
+
+#ifdef WORDS_BIGENDIAN
+	{
+		/*
+		 * wk.ik_keytsc is in host byte order (big endian), need to
+		 * swap it to match with the byte order used in WPA.
+		 */
+		int i;
+		u8 tmp[WPA_KEY_RSC_LEN];
+		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));
+#endif /* WORDS_BIGENDIAN */
+	return 0;
+}
+
+
+static int 
+madwifi_flush(void *priv)
+{
+#ifdef MADWIFI_BSD
+	u8 allsta[IEEE80211_ADDR_LEN];
+	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+	return madwifi_sta_deauth(priv, NULL, allsta,
+				  IEEE80211_REASON_AUTH_LEAVE);
+#else /* MADWIFI_BSD */
+	return 0;		/* XXX */
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+			     const u8 *addr)
+{
+	struct madwifi_driver_data *drv = priv;
+
+#ifdef MADWIFI_BSD
+	struct ieee80211req_sta_stats stats;
+
+	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);
+	if (set80211priv(drv,
+#ifdef MADWIFI_NG
+			 IEEE80211_IOCTL_STA_STATS,
+#else /* MADWIFI_NG */
+			 IEEE80211_IOCTL_GETSTASTATS,
+#endif /* MADWIFI_NG */
+			 &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));
+			return 0;
+		}
+
+		printf("Failed to get station stats information element.\n");
+		return -1;
+	}
+
+	data->rx_packets = stats.is_stats.ns_rx_data;
+	data->rx_bytes = stats.is_stats.ns_rx_bytes;
+	data->tx_packets = stats.is_stats.ns_tx_data;
+	data->tx_bytes = stats.is_stats.ns_tx_bytes;
+	return 0;
+
+#else /* MADWIFI_BSD */
+
+	char buf[1024], line[128], *pos;
+	FILE *f;
+	unsigned long val;
+
+	memset(data, 0, sizeof(*data));
+	snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
+		 drv->iface, MAC2STR(addr));
+
+	f = fopen(buf, "r");
+	if (!f) {
+		if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
+			return -1;
+		memcpy(data, &drv->acct_data, sizeof(*data));
+		return 0;
+	}
+	/* Need to read proc file with in one piece, so use large enough
+	 * buffer. */
+	setbuffer(f, buf, sizeof(buf));
+
+	while (fgets(line, sizeof(line), f)) {
+		pos = strchr(line, '=');
+		if (!pos)
+			continue;
+		*pos++ = '\0';
+		val = strtoul(pos, NULL, 10);
+		if (strcmp(line, "rx_packets") == 0)
+			data->rx_packets = val;
+		else if (strcmp(line, "tx_packets") == 0)
+			data->tx_packets = val;
+		else if (strcmp(line, "rx_bytes") == 0)
+			data->rx_bytes = val;
+		else if (strcmp(line, "tx_bytes") == 0)
+			data->tx_bytes = val;
+	}
+
+	fclose(f);
+
+	return 0;
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	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);
+	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+			   sizeof(mlme));
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+			   MACSTR ")", __func__, MAC2STR(addr));
+	}
+
+	return ret;
+#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+	return 0; /* FIX */
+#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+}
+
+
+static int
+madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
+{
+	/*
+	 * Do nothing; we setup parameters at startup that define the
+	 * contents of the beacon information element.
+	 */
+	return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+		   int reason_code)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+		   __func__, ether_sprintf(addr), reason_code);
+
+	mlme.im_op = IEEE80211_MLME_DEAUTH;
+	mlme.im_reason = reason_code;
+	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
+			   " reason %d)",
+			   __func__, MAC2STR(addr), reason_code);
+	}
+
+	return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+		     int reason_code)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct ieee80211req_mlme mlme;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+		   __func__, ether_sprintf(addr), reason_code);
+
+	mlme.im_op = IEEE80211_MLME_DISASSOC;
+	mlme.im_reason = reason_code;
+	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 "
+			   MACSTR " reason %d)",
+			   __func__, MAC2STR(addr), reason_code);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+				size_t len)
+{
+	struct madwifi_driver_data *drv = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	union wpa_event_data event;
+
+	/* Send Probe Request information to WPS processing */
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+		return;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	fc = le_to_host16(mgmt->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+		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));
+	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+}
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+{
+	int ret = 0;
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+	struct ieee80211req_set_filter filt;
+
+	wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+	filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+
+	ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+			   sizeof(struct ieee80211req_set_filter));
+	if (ret)
+		return ret;
+
+	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+				       madwifi_raw_receive, drv, 1);
+	if (drv->sock_raw == NULL)
+		return -1;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+	return ret;
+}
+
+#ifdef CONFIG_WPS
+static int
+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+	struct madwifi_driver_data *drv = priv;
+	u8 buf[256];
+	struct ieee80211req_getset_appiebuf *beac_ie;
+
+	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+		   (unsigned long) len);
+
+	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+	beac_ie->app_frmtype = frametype;
+	beac_ie->app_buflen = len;
+	memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+			    sizeof(struct ieee80211req_getset_appiebuf) + len);
+}
+
+static int
+madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+		      const struct wpabuf *proberesp,
+		      const struct wpabuf *assocresp)
+{
+	if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+			       beacon ? wpabuf_len(beacon) : 0,
+			       IEEE80211_APPIE_FRAME_BEACON) < 0)
+		return -1;
+	return madwifi_set_wps_ie(priv,
+				  proberesp ? wpabuf_head(proberesp) : NULL,
+				  proberesp ? wpabuf_len(proberesp) : 0,
+				  IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define madwifi_set_ap_wps_ie NULL
+#endif /* CONFIG_WPS */
+
+static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+	iwr.u.freq.m = freq->channel;
+	iwr.u.freq.e = 0;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+	struct hostapd_data *hapd = drv->hapd;
+	struct ieee80211req_wpaie ie;
+	int ielen = 0;
+	u8 *iebuf = NULL;
+
+	/*
+	 * Fetch negotiated WPA/RSN parameters from the system.
+	 */
+	memset(&ie, 0, sizeof(ie));
+	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+	if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE",
+			   __func__);
+		goto no_ie;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+		    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+	iebuf = ie.wpa_ie;
+	/* madwifi seems to return some random data if WPA/RSN IE is not set.
+	 * Assume the IE was not included if the IE type is unknown. */
+	if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+		iebuf[1] = 0;
+#ifdef MADWIFI_NG
+	wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+		    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+	if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+		/* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+		 * set. This is needed for WPA2. */
+		iebuf = ie.rsn_ie;
+		if (iebuf[0] != WLAN_EID_RSN)
+			iebuf[1] = 0;
+	}
+#endif /* MADWIFI_NG */
+
+	ielen = iebuf[1];
+	if (ielen == 0)
+		iebuf = NULL;
+	else
+		ielen += 2;
+
+no_ie:
+	drv_event_assoc(hapd, addr, iebuf, ielen, 0);
+
+	if (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));
+	}
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+				       char *custom)
+{
+	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+		char *pos;
+		u8 addr[ETH_ALEN];
+		pos = strstr(custom, "addr=");
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "without sender address ignored");
+			return;
+		}
+		pos += 5;
+		if (hwaddr_aton(pos, addr) == 0) {
+			union wpa_event_data data;
+			os_memset(&data, 0, sizeof(data));
+			data.michael_mic_failure.unicast = 1;
+			data.michael_mic_failure.src = addr;
+			wpa_supplicant_event(drv->hapd,
+					     EVENT_MICHAEL_MIC_FAILURE, &data);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "with invalid MAC address");
+		}
+	} else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+		char *key, *value;
+		u32 val;
+		key = custom;
+		while ((key = strchr(key, '\n')) != NULL) {
+			key++;
+			value = strchr(key, '=');
+			if (value == NULL)
+				continue;
+			*value++ = '\0';
+			val = strtoul(value, NULL, 10);
+			if (strcmp(key, "mac") == 0)
+				hwaddr_aton(value, drv->acct_mac);
+			else if (strcmp(key, "rx_packets") == 0)
+				drv->acct_data.rx_packets = val;
+			else if (strcmp(key, "tx_packets") == 0)
+				drv->acct_data.tx_packets = val;
+			else if (strcmp(key, "rx_bytes") == 0)
+				drv->acct_data.rx_bytes = val;
+			else if (strcmp(key, "tx_bytes") == 0)
+				drv->acct_data.tx_bytes = val;
+			key = value;
+		}
+	}
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+					    char *data, 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) {
+		/* Event data may be unaligned, so make a local, aligned copy
+		 * before processing. */
+		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)
+			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVCUSTOM)) {
+			/* 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);
+		} else {
+			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case IWEVEXPIRED:
+			drv_event_disassoc(drv->hapd,
+					   (u8 *) iwe->u.addr.sa_data);
+			break;
+		case IWEVREGISTERED:
+			madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+			break;
+		case IWEVCUSTOM:
+			if (custom + iwe->u.data.length > end)
+				return;
+			buf = malloc(iwe->u.data.length + 1);
+			if (buf == NULL)
+				return;		/* XXX */
+			memcpy(buf, custom, iwe->u.data.length);
+			buf[iwe->u.data.length] = '\0';
+			madwifi_wireless_event_wireless_custom(drv, buf);
+			free(buf);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+				   u8 *buf, size_t len)
+{
+	struct madwifi_driver_data *drv = ctx;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	if (ifi->ifi_index != drv->ifindex)
+		return;
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			madwifi_wireless_event_wireless(
+				drv, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+	struct iw_range *range;
+	struct iwreq iwr;
+	int minlen;
+	size_t buflen;
+
+	drv->we_version = 0;
+
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
+	buflen = sizeof(struct iw_range) + 500;
+	range = os_zalloc(buflen);
+	if (range == NULL)
+		return -1;
+
+	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;
+
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWRANGE]");
+		free(range);
+		return -1;
+	} else if (iwr.u.data.length >= minlen &&
+		   range->we_version_compiled >= 18) {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+			   "WE(source)=%d enc_capa=0x%x",
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
+		drv->we_version = range->we_version_compiled;
+	}
+
+	free(range);
+	return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(struct madwifi_driver_data *drv)
+{
+	struct netlink_config *cfg;
+
+	madwifi_get_we_version(drv);
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		return -1;
+	cfg->ctx = drv;
+	cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
+	drv->netlink = netlink_init(cfg);
+	if (drv->netlink == NULL) {
+		os_free(cfg);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+		   int encrypt, const u8 *own_addr, u32 flags)
+{
+	struct madwifi_driver_data *drv = priv;
+	unsigned char buf[3000];
+	unsigned char *bp = buf;
+	struct l2_ethhdr *eth;
+	size_t len;
+	int status;
+
+	/*
+	 * Prepend the Ethernet header.  If the caller left us
+	 * space at the front we could just insert it but since
+	 * we don't know we copy to a local buffer.  Given the frequency
+	 * and size of frames this probably doesn't matter.
+	 */
+	len = data_len + sizeof(struct l2_ethhdr);
+	if (len > sizeof(buf)) {
+		bp = malloc(len);
+		if (bp == NULL) {
+			printf("EAPOL frame discarded, cannot malloc temp "
+			       "buffer of size %lu!\n", (unsigned long) len);
+			return -1;
+		}
+	}
+	eth = (struct l2_ethhdr *) bp;
+	memcpy(eth->h_dest, addr, ETH_ALEN);
+	memcpy(eth->h_source, own_addr, ETH_ALEN);
+	eth->h_proto = host_to_be16(ETH_P_EAPOL);
+	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);
+	return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+	struct madwifi_driver_data *drv = ctx;
+	drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+			   len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+{
+	struct madwifi_driver_data *drv;
+	struct ifreq ifr;
+	struct iwreq iwr;
+	char brname[IFNAMSIZ];
+
+	drv = os_zalloc(sizeof(struct madwifi_driver_data));
+	if (drv == NULL) {
+		printf("Could not allocate memory for madwifi driver data\n");
+		return NULL;
+	}
+
+	drv->hapd = hapd;
+	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->ioctl_sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		goto bad;
+	}
+	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
+
+	memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		goto bad;
+	}
+	drv->ifindex = ifr.ifr_ifindex;
+
+	drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+					handle_read, drv, 1);
+	if (drv->sock_xmit == NULL)
+		goto bad;
+	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
+		goto bad;
+	if (params->bridge[0]) {
+		wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+			   params->bridge[0]);
+		drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
+						ETH_P_EAPOL, handle_read, drv,
+						1);
+		if (drv->sock_recv == NULL)
+			goto bad;
+	} else if (linux_br_get(brname, drv->iface) == 0) {
+		wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
+			   "EAPOL receive", brname);
+		drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
+						handle_read, drv, 1);
+		if (drv->sock_recv == NULL)
+			goto bad;
+	} else
+		drv->sock_recv = drv->sock_xmit;
+
+	memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+	iwr.u.mode = IW_MODE_MASTER;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWMODE]");
+		printf("Could not set interface to master mode!\n");
+		goto bad;
+	}
+
+	/* mark down during setup */
+	linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+	madwifi_set_privacy(drv, 0); /* default to no privacy */
+
+	madwifi_receive_probe_req(drv);
+
+	if (madwifi_wireless_event_init(drv))
+		goto bad;
+
+	return drv;
+bad:
+	if (drv->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	if (drv->ioctl_sock >= 0)
+		close(drv->ioctl_sock);
+	if (drv != NULL)
+		free(drv);
+	return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+	struct madwifi_driver_data *drv = priv;
+
+	netlink_deinit(drv->netlink);
+	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+	if (drv->ioctl_sock >= 0)
+		close(drv->ioctl_sock);
+	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+		l2_packet_deinit(drv->sock_recv);
+	if (drv->sock_xmit != NULL)
+		l2_packet_deinit(drv->sock_xmit);
+	if (drv->sock_raw)
+		l2_packet_deinit(drv->sock_raw);
+	free(drv);
+}
+
+static int
+madwifi_set_ssid(void *priv, const u8 *buf, int len)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct iwreq iwr;
+
+	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;
+	iwr.u.essid.length = len + 1;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCSIWESSID]");
+		printf("len=%d\n", len);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+madwifi_get_ssid(void *priv, u8 *buf, int len)
+{
+	struct madwifi_driver_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	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;
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCGIWESSID]");
+		ret = -1;
+	} else
+		ret = iwr.u.essid.length;
+
+	return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+	struct madwifi_driver_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+	struct madwifi_driver_data *drv = priv;
+	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
+}
+
+
+const struct wpa_driver_ops wpa_driver_madwifi_ops = {
+	.name			= "madwifi",
+	.desc			= "MADWIFI 802.11 support (Atheros, etc.)",
+	.set_key		= wpa_driver_madwifi_set_key,
+	.hapd_init		= madwifi_init,
+	.hapd_deinit		= madwifi_deinit,
+	.set_ieee8021x		= madwifi_set_ieee8021x,
+	.set_privacy		= madwifi_set_privacy,
+	.get_seqnum		= madwifi_get_seqnum,
+	.flush			= madwifi_flush,
+	.set_generic_elem	= madwifi_set_opt_ie,
+	.sta_set_flags		= madwifi_sta_set_flags,
+	.read_sta_data		= madwifi_read_sta_driver_data,
+	.hapd_send_eapol	= madwifi_send_eapol,
+	.sta_disassoc		= madwifi_sta_disassoc,
+	.sta_deauth		= madwifi_sta_deauth,
+	.hapd_set_ssid		= madwifi_set_ssid,
+	.hapd_get_ssid		= madwifi_get_ssid,
+	.hapd_set_countermeasures	= madwifi_set_countermeasures,
+	.sta_clear_stats        = madwifi_sta_clear_stats,
+	.commit			= madwifi_commit,
+	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
+	.set_freq		= madwifi_set_freq,
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_ndis.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ndis.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ndis.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,3278 +0,0 @@
-/*
- * WPA Supplicant - Windows/NDIS driver interface
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifdef __CYGWIN__
-/* Avoid some header file conflicts by not including standard headers for
- * cygwin builds when Packet32.h is included. */
-#include "build_config.h"
-int close(int fd);
-#else /* __CYGWIN__ */
-#include "includes.h"
-#endif /* __CYGWIN__ */
-#ifdef CONFIG_USE_NDISUIO
-#include <winsock2.h>
-#else /* CONFIG_USE_NDISUIO */
-#include <Packet32.h>
-#endif /* CONFIG_USE_NDISUIO */
-#ifdef __MINGW32_VERSION
-#include <ddk/ntddndis.h>
-#else /* __MINGW32_VERSION */
-#include <ntddndis.h>
-#endif /* __MINGW32_VERSION */
-
-#ifdef _WIN32_WCE
-#include <winioctl.h>
-#include <nuiouser.h>
-#include <devload.h>
-#endif /* _WIN32_WCE */
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "driver_ndis.h"
-
-int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
-#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data);
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-
-static void wpa_driver_ndis_deinit(void *priv);
-static void wpa_driver_ndis_poll(void *drv);
-static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx);
-static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv);
-static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
-static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
-
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-
-/* FIX: to be removed once this can be compiled with the complete NDIS
- * header files */
-#ifndef OID_802_11_BSSID
-#define OID_802_11_BSSID 			0x0d010101
-#define OID_802_11_SSID 			0x0d010102
-#define OID_802_11_INFRASTRUCTURE_MODE		0x0d010108
-#define OID_802_11_ADD_WEP			0x0D010113
-#define OID_802_11_REMOVE_WEP			0x0D010114
-#define OID_802_11_DISASSOCIATE			0x0D010115
-#define OID_802_11_BSSID_LIST 			0x0d010217
-#define OID_802_11_AUTHENTICATION_MODE		0x0d010118
-#define OID_802_11_PRIVACY_FILTER		0x0d010119
-#define OID_802_11_BSSID_LIST_SCAN 		0x0d01011A
-#define OID_802_11_WEP_STATUS	 		0x0d01011B
-#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
-#define OID_802_11_ADD_KEY 			0x0d01011D
-#define OID_802_11_REMOVE_KEY 			0x0d01011E
-#define OID_802_11_ASSOCIATION_INFORMATION	0x0d01011F
-#define OID_802_11_TEST 			0x0d010120
-#define OID_802_11_CAPABILITY 			0x0d010122
-#define OID_802_11_PMKID 			0x0d010123
-
-#define NDIS_802_11_LENGTH_SSID 32
-#define NDIS_802_11_LENGTH_RATES 8
-#define NDIS_802_11_LENGTH_RATES_EX 16
-
-typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
-
-typedef struct NDIS_802_11_SSID {
-	ULONG SsidLength;
-	UCHAR Ssid[NDIS_802_11_LENGTH_SSID];
-} NDIS_802_11_SSID;
-
-typedef LONG NDIS_802_11_RSSI;
-
-typedef enum NDIS_802_11_NETWORK_TYPE {
-	Ndis802_11FH,
-	Ndis802_11DS,
-	Ndis802_11OFDM5,
-	Ndis802_11OFDM24,
-	Ndis802_11NetworkTypeMax
-} NDIS_802_11_NETWORK_TYPE;
-
-typedef struct NDIS_802_11_CONFIGURATION_FH {
-	ULONG Length;
-	ULONG HopPattern;
-	ULONG HopSet;
-	ULONG DwellTime;
-} NDIS_802_11_CONFIGURATION_FH;
-
-typedef struct NDIS_802_11_CONFIGURATION {
-	ULONG Length;
-	ULONG BeaconPeriod;
-	ULONG ATIMWindow;
-	ULONG DSConfig;
-	NDIS_802_11_CONFIGURATION_FH FHConfig;
-} NDIS_802_11_CONFIGURATION;
-
-typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
-	Ndis802_11IBSS,
-	Ndis802_11Infrastructure,
-	Ndis802_11AutoUnknown,
-	Ndis802_11InfrastructureMax
-} NDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-typedef enum NDIS_802_11_AUTHENTICATION_MODE {
-	Ndis802_11AuthModeOpen,
-	Ndis802_11AuthModeShared,
-	Ndis802_11AuthModeAutoSwitch,
-	Ndis802_11AuthModeWPA,
-	Ndis802_11AuthModeWPAPSK,
-	Ndis802_11AuthModeWPANone,
-	Ndis802_11AuthModeWPA2,
-	Ndis802_11AuthModeWPA2PSK,
-	Ndis802_11AuthModeMax
-} NDIS_802_11_AUTHENTICATION_MODE;
-
-typedef enum NDIS_802_11_WEP_STATUS {
-	Ndis802_11WEPEnabled,
-	Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
-	Ndis802_11WEPDisabled,
-	Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
-	Ndis802_11WEPKeyAbsent,
-	Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
-	Ndis802_11WEPNotSupported,
-	Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
-	Ndis802_11Encryption2Enabled,
-	Ndis802_11Encryption2KeyAbsent,
-	Ndis802_11Encryption3Enabled,
-	Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum NDIS_802_11_PRIVACY_FILTER {
-	Ndis802_11PrivFilterAcceptAll,
-	Ndis802_11PrivFilter8021xWEP
-} NDIS_802_11_PRIVACY_FILTER;
-
-typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];
-typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
-
-typedef struct NDIS_WLAN_BSSID_EX {
-	ULONG Length;
-	NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */
-	UCHAR Reserved[2];
-	NDIS_802_11_SSID Ssid;
-	ULONG Privacy;
-	NDIS_802_11_RSSI Rssi;
-	NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
-	NDIS_802_11_CONFIGURATION Configuration;
-	NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
-	NDIS_802_11_RATES_EX SupportedRates;
-	ULONG IELength;
-	UCHAR IEs[1];
-} NDIS_WLAN_BSSID_EX;
-
-typedef struct NDIS_802_11_BSSID_LIST_EX {
-	ULONG NumberOfItems;
-	NDIS_WLAN_BSSID_EX Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX;
-
-typedef struct NDIS_802_11_FIXED_IEs {
-	UCHAR Timestamp[8];
-	USHORT BeaconInterval;
-	USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs;
-
-typedef struct NDIS_802_11_WEP {
-	ULONG Length;
-	ULONG KeyIndex;
-	ULONG KeyLength;
-	UCHAR KeyMaterial[1];
-} NDIS_802_11_WEP;
-
-typedef ULONG NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG NDIS_802_11_KEY_RSC;
-
-typedef struct NDIS_802_11_KEY {
-	ULONG Length;
-	ULONG KeyIndex;
-	ULONG KeyLength;
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_KEY_RSC KeyRSC;
-	UCHAR KeyMaterial[1];
-} NDIS_802_11_KEY;
-
-typedef struct NDIS_802_11_REMOVE_KEY {
-	ULONG Length;
-	ULONG KeyIndex;
-	NDIS_802_11_MAC_ADDRESS BSSID;
-} NDIS_802_11_REMOVE_KEY;
-
-typedef struct NDIS_802_11_AI_REQFI {
-	USHORT Capabilities;
-	USHORT ListenInterval;
-	NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
-} NDIS_802_11_AI_REQFI;
-
-typedef struct NDIS_802_11_AI_RESFI {
-	USHORT Capabilities;
-	USHORT StatusCode;
-	USHORT AssociationId;
-} NDIS_802_11_AI_RESFI;
-
-typedef struct NDIS_802_11_ASSOCIATION_INFORMATION {
-	ULONG Length;
-	USHORT AvailableRequestFixedIEs;
-	NDIS_802_11_AI_REQFI RequestFixedIEs;
-	ULONG RequestIELength;
-	ULONG OffsetRequestIEs;
-	USHORT AvailableResponseFixedIEs;
-	NDIS_802_11_AI_RESFI ResponseFixedIEs;
-	ULONG ResponseIELength;
-	ULONG OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION;
-
-typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
-	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
-	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
-} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
-
-typedef struct NDIS_802_11_CAPABILITY {
-	ULONG Length;
-	ULONG Version;
-	ULONG NoOfPMKIDs;
-	ULONG NoOfAuthEncryptPairsSupported;
-	NDIS_802_11_AUTHENTICATION_ENCRYPTION
-		AuthenticationEncryptionSupported[1];
-} NDIS_802_11_CAPABILITY;
-
-typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct BSSID_INFO {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO;
-
-typedef struct NDIS_802_11_PMKID {
-	ULONG Length;
-	ULONG BSSIDInfoCount;
-	BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID;
-
-typedef enum NDIS_802_11_STATUS_TYPE {
-	Ndis802_11StatusType_Authentication,
-	Ndis802_11StatusType_PMKID_CandidateList = 2,
-	Ndis802_11StatusTypeMax
-} NDIS_802_11_STATUS_TYPE;
-
-typedef struct NDIS_802_11_STATUS_INDICATION {
-	NDIS_802_11_STATUS_TYPE StatusType;
-} NDIS_802_11_STATUS_INDICATION;
-
-typedef struct PMKID_CANDIDATE {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	ULONG Flags;
-} PMKID_CANDIDATE;
-
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
-
-typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
-	ULONG Version;
-	ULONG NumCandidates;
-	PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST;
-
-typedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
-	ULONG Length;
-	NDIS_802_11_MAC_ADDRESS Bssid;
-	ULONG Flags;
-} NDIS_802_11_AUTHENTICATION_REQUEST;
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH			0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE		0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR		0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR		0x0E
-
-#endif /* OID_802_11_BSSID */
-
-
-#ifndef OID_802_11_PMKID
-/* Platform SDK for XP did not include WPA2, so add needed definitions */
-
-#define OID_802_11_CAPABILITY 			0x0d010122
-#define OID_802_11_PMKID 			0x0d010123
-
-#define Ndis802_11AuthModeWPA2 6
-#define Ndis802_11AuthModeWPA2PSK 7
-
-#define Ndis802_11StatusType_PMKID_CandidateList 2
-
-typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
-	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
-	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
-} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
-
-typedef struct NDIS_802_11_CAPABILITY {
-	ULONG Length;
-	ULONG Version;
-	ULONG NoOfPMKIDs;
-	ULONG NoOfAuthEncryptPairsSupported;
-	NDIS_802_11_AUTHENTICATION_ENCRYPTION
-		AuthenticationEncryptionSupported[1];
-} NDIS_802_11_CAPABILITY;
-
-typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct BSSID_INFO {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO;
-
-typedef struct NDIS_802_11_PMKID {
-	ULONG Length;
-	ULONG BSSIDInfoCount;
-	BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID;
-
-typedef struct PMKID_CANDIDATE {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	ULONG Flags;
-} PMKID_CANDIDATE;
-
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
-
-typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
-	ULONG Version;
-	ULONG NumCandidates;
-	PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST;
-
-#endif /* OID_802_11_CAPABILITY */
-
-
-#ifndef OID_DOT11_CURRENT_OPERATION_MODE
-/* Native 802.11 OIDs */
-#define OID_DOT11_NDIS_START 0x0D010300
-#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8)
-#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11)
-
-typedef enum _DOT11_BSS_TYPE {
-	dot11_BSS_type_infrastructure = 1,
-	dot11_BSS_type_independent = 2,
-	dot11_BSS_type_any = 3
-} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE;
-
-typedef UCHAR DOT11_MAC_ADDRESS[6];
-typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS;
-
-typedef enum _DOT11_SCAN_TYPE {
-	dot11_scan_type_active = 1,
-	dot11_scan_type_passive = 2,
-	dot11_scan_type_auto = 3,
-	dot11_scan_type_forced = 0x80000000
-} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE;
-
-typedef struct _DOT11_SCAN_REQUEST_V2 {
-	DOT11_BSS_TYPE dot11BSSType;
-	DOT11_MAC_ADDRESS dot11BSSID;
-	DOT11_SCAN_TYPE dot11ScanType;
-	BOOLEAN bRestrictedScan;
-	ULONG udot11SSIDsOffset;
-	ULONG uNumOfdot11SSIDs;
-	BOOLEAN bUseRequestIE;
-	ULONG uRequestIDsOffset;
-	ULONG uNumOfRequestIDs;
-	ULONG uPhyTypeInfosOffset;
-	ULONG uNumOfPhyTypeInfos;
-	ULONG uIEsOffset;
-	ULONG uIEsLength;
-	UCHAR ucBuffer[1];
-} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2;
-
-#endif /* OID_DOT11_CURRENT_OPERATION_MODE */
-
-#ifdef CONFIG_USE_NDISUIO
-#ifndef _WIN32_WCE
-#ifdef __MINGW32_VERSION
-typedef ULONG NDIS_OID;
-#endif /* __MINGW32_VERSION */
-/* from nuiouser.h */
-#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
-
-#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
-	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
-
-#define IOCTL_NDISUIO_OPEN_DEVICE \
-	_NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_QUERY_OID_VALUE \
-	_NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_SET_OID_VALUE \
-	_NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_SET_ETHER_TYPE \
-	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_QUERY_BINDING \
-	_NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_BIND_WAIT \
-	_NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-typedef struct _NDISUIO_QUERY_OID
-{
-    NDIS_OID Oid;
-    UCHAR Data[sizeof(ULONG)];
-} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
-
-typedef struct _NDISUIO_SET_OID
-{
-    NDIS_OID Oid;
-    UCHAR Data[sizeof(ULONG)];
-} NDISUIO_SET_OID, *PNDISUIO_SET_OID;
-
-typedef struct _NDISUIO_QUERY_BINDING
-{
-	ULONG BindingIndex;
-	ULONG DeviceNameOffset;
-	ULONG DeviceNameLength;
-	ULONG DeviceDescrOffset;
-	ULONG DeviceDescrLength;
-} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
-#endif /* _WIN32_WCE */
-#endif /* CONFIG_USE_NDISUIO */
-
-
-static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
-			char *data, size_t len)
-{
-#ifdef CONFIG_USE_NDISUIO
-	NDISUIO_QUERY_OID *o;
-	size_t buflen = sizeof(*o) + len;
-	DWORD written;
-	int ret;
-	size_t hdrlen;
-
-	o = os_zalloc(buflen);
-	if (o == NULL)
-		return -1;
-	o->Oid = oid;
-#ifdef _WIN32_WCE
-	o->ptcDeviceName = drv->adapter_name;
-#endif /* _WIN32_WCE */
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE,
-			     o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written,
-			     NULL)) {
-		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE "
-			   "failed (oid=%08x): %d", oid, (int) GetLastError());
-		os_free(o);
-		return -1;
-	}
-	hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data);
-	if (written < hdrlen) {
-		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); "
-			   "too short", oid, (unsigned int) written);
-		os_free(o);
-		return -1;
-	}
-	written -= hdrlen;
-	if (written > len) {
-		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > "
-			   "len (%d)",oid, (unsigned int) written, len);
-		os_free(o);
-		return -1;
-	}
-	os_memcpy(data, o->Data, written);
-	ret = written;
-	os_free(o);
-	return ret;
-#else /* CONFIG_USE_NDISUIO */
-	char *buf;
-	PACKET_OID_DATA *o;
-	int ret;
-
-	buf = os_zalloc(sizeof(*o) + len);
-	if (buf == NULL)
-		return -1;
-	o = (PACKET_OID_DATA *) buf;
-	o->Oid = oid;
-	o->Length = len;
-
-	if (!PacketRequest(drv->adapter, FALSE, o)) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-			   __func__, oid, len);
-		os_free(buf);
-		return -1;
-	}
-	if (o->Length > len) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
-			   __func__, oid, (unsigned int) o->Length, len);
-		os_free(buf);
-		return -1;
-	}
-	os_memcpy(data, o->Data, o->Length);
-	ret = o->Length;
-	os_free(buf);
-	return ret;
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
-			const char *data, size_t len)
-{
-#ifdef CONFIG_USE_NDISUIO
-	NDISUIO_SET_OID *o;
-	size_t buflen, reallen;
-	DWORD written;
-	char txt[50];
-
-	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
-	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
-
-	buflen = sizeof(*o) + len;
-	reallen = buflen - sizeof(o->Data);
-	o = os_zalloc(buflen);
-	if (o == NULL)
-		return -1;
-	o->Oid = oid;
-#ifdef _WIN32_WCE
-	o->ptcDeviceName = drv->adapter_name;
-#endif /* _WIN32_WCE */
-	if (data)
-		os_memcpy(o->Data, data, len);
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE,
-			     o, reallen, NULL, 0, &written, NULL)) {
-		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE "
-			   "(oid=%08x) failed: %d", oid, (int) GetLastError());
-		os_free(o);
-		return -1;
-	}
-	os_free(o);
-	return 0;
-#else /* CONFIG_USE_NDISUIO */
-	char *buf;
-	PACKET_OID_DATA *o;
-	char txt[50];
-
-	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
-	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
-
-	buf = os_zalloc(sizeof(*o) + len);
-	if (buf == NULL)
-		return -1;
-	o = (PACKET_OID_DATA *) buf;
-	o->Oid = oid;
-	o->Length = len;
-	if (data)
-		os_memcpy(o->Data, data, len);
-
-	if (!PacketRequest(drv->adapter, TRUE, o)) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-			   __func__, oid, len);
-		os_free(buf);
-		return -1;
-	}
-	os_free(buf);
-	return 0;
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode)
-{
-	u32 auth_mode = mode;
-	if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-			 (char *) &auth_mode, sizeof(auth_mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
-			   "OID_802_11_AUTHENTICATION_MODE (%d)",
-			   (int) auth_mode);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv)
-{
-	u32 auth_mode;
-	int res;
-	res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-			   (char *) &auth_mode, sizeof(auth_mode));
-	if (res != sizeof(auth_mode)) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
-			   "OID_802_11_AUTHENTICATION_MODE");
-		return -1;
-	}
-	return auth_mode;
-}
-
-
-static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr)
-{
-	u32 encr_status = encr;
-	if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS,
-			 (char *) &encr_status, sizeof(encr_status)) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
-			   "OID_802_11_ENCRYPTION_STATUS (%d)", encr);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv)
-{
-	u32 encr;
-	int res;
-	res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS,
-			   (char *) &encr, sizeof(encr));
-	if (res != sizeof(encr)) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
-			   "OID_802_11_ENCRYPTION_STATUS");
-		return -1;
-	}
-	return encr;
-}
-
-
-static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-
-	if (drv->wired) {
-		/*
-		 * Report PAE group address as the "BSSID" for wired
-		 * connection.
-		 */
-		os_memcpy(bssid, pae_group_addr, ETH_ALEN);
-		return 0;
-	}
-
-	return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) <
-		0 ? -1 : 0;
-}
-
-
-static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	NDIS_802_11_SSID buf;
-	int res;
-
-	res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
-	if (res < 4) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
-		if (drv->wired) {
-			wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
-				   "with a wired interface");
-			return 0;
-		}
-		return -1;
-	}
-	os_memcpy(ssid, buf.Ssid, buf.SsidLength);
-	return buf.SsidLength;
-}
-
-
-static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
-				    const u8 *ssid, size_t ssid_len)
-{
-	NDIS_802_11_SSID buf;
-
-	os_memset(&buf, 0, sizeof(buf));
-	buf.SsidLength = ssid_len;
-	os_memcpy(buf.Ssid, ssid, ssid_len);
-	/*
-	 * Make sure radio is marked enabled here so that scan request will not
-	 * force SSID to be changed to a random one in order to enable radio at
-	 * that point.
-	 */
-	drv->radio_enabled = 1;
-	return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
-}
-
-
-/* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off.
- */
-static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
-{
-	drv->radio_enabled = 0;
-	return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4);
-}
-
-
-/* Disconnect by setting SSID to random (i.e., likely not used). */
-static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
-{
-	char ssid[32];
-	int i;
-	for (i = 0; i < 32; i++)
-		ssid[i] = rand() & 0xff;
-	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
-}
-
-
-static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	return wpa_driver_ndis_disconnect(drv);
-}
-
-
-static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	return wpa_driver_ndis_disconnect(drv);
-}
-
-
-static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_ndis_scan_native80211(
-	struct wpa_driver_ndis_data *drv,
-	struct wpa_driver_scan_params *params)
-{
-	DOT11_SCAN_REQUEST_V2 req;
-	int res;
-
-	os_memset(&req, 0, sizeof(req));
-	req.dot11BSSType = dot11_BSS_type_any;
-	os_memset(req.dot11BSSID, 0xff, ETH_ALEN);
-	req.dot11ScanType = dot11_scan_type_auto;
-	res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req,
-			   sizeof(req));
-	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
-			       drv->ctx);
-	return res;
-}
-
-
-static int wpa_driver_ndis_scan(void *priv,
-				struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	int res;
-
-	if (drv->native80211)
-		return wpa_driver_ndis_scan_native80211(drv, params);
-
-	if (!drv->radio_enabled) {
-		wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
-			   " scan");
-		if (wpa_driver_ndis_disconnect(drv) < 0) {
-			wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio");
-		}
-		drv->radio_enabled = 1;
-	}
-
-	res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, "    ", 4);
-	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
-			       drv->ctx);
-	return res;
-}
-
-
-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;
-}
-
-
-static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
-	struct wpa_scan_res *r, NDIS_802_11_SSID *ssid)
-{
-	struct wpa_scan_res *nr;
-	u8 *pos;
-
-	if (wpa_scan_get_ie(r, WLAN_EID_SSID))
-		return r; /* SSID IE already present */
-
-	if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
-		return r; /* No valid SSID inside scan data */
-
-	nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
-	if (nr == NULL)
-		return r;
-
-	pos = ((u8 *) (nr + 1)) + nr->ie_len;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid->SsidLength;
-	os_memcpy(pos, ssid->Ssid, ssid->SsidLength);
-	nr->ie_len += 2 + ssid->SsidLength;
-
-	return nr;
-}
-
-
-static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	NDIS_802_11_BSSID_LIST_EX *b;
-	size_t blen, count, i;
-	int len;
-	char *pos;
-	struct wpa_scan_results *results;
-	struct wpa_scan_res *r;
-
-	blen = 65535;
-	b = os_zalloc(blen);
-	if (b == NULL)
-		return NULL;
-	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
-	if (len < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
-		os_free(b);
-		return NULL;
-	}
-	count = b->NumberOfItems;
-
-	results = os_zalloc(sizeof(*results));
-	if (results == NULL) {
-		os_free(b);
-		return NULL;
-	}
-	results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
-	if (results->res == NULL) {
-		os_free(results);
-		os_free(b);
-		return NULL;
-	}
-
-	pos = (char *) &b->Bssid[0];
-	for (i = 0; i < count; i++) {
-		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
-		NDIS_802_11_FIXED_IEs *fixed;
-
-		if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) {
-			wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d",
-				   (int) bss->IELength);
-			break;
-		}
-		if (((char *) bss->IEs) + bss->IELength  > (char *) b + blen) {
-			/*
-			 * Some NDIS drivers have been reported to include an
-			 * entry with an invalid IELength in scan results and
-			 * this has crashed wpa_supplicant, so validate the
-			 * returned value before using it.
-			 */
-			wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan "
-				   "result IE (BSSID=" MACSTR ") IELength=%d",
-				   MAC2STR(bss->MacAddress),
-				   (int) bss->IELength);
-			break;
-		}
-
-		r = os_zalloc(sizeof(*r) + bss->IELength -
-			      sizeof(NDIS_802_11_FIXED_IEs));
-		if (r == NULL)
-			break;
-
-		os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN);
-		r->level = (int) bss->Rssi;
-		r->freq = bss->Configuration.DSConfig / 1000;
-		fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs;
-		r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval);
-		r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities);
-		r->tsf = WPA_GET_LE64(fixed->Timestamp);
-		os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs),
-			  bss->IELength - sizeof(NDIS_802_11_FIXED_IEs));
-		r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-		r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid);
-
-		results->res[results->num++] = r;
-
-		pos += bss->Length;
-		if (pos > (char *) b + blen)
-			break;
-	}
-
-	os_free(b);
-
-	return results;
-}
-
-
-static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
-				      int key_idx, const u8 *addr,
-				      const u8 *bssid, int pairwise)
-{
-	NDIS_802_11_REMOVE_KEY rkey;
-	NDIS_802_11_KEY_INDEX index;
-	int res, res2;
-
-	os_memset(&rkey, 0, sizeof(rkey));
-
-	rkey.Length = sizeof(rkey);
-	rkey.KeyIndex = key_idx;
-	if (pairwise)
-		rkey.KeyIndex |= 1 << 30;
-	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
-	res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
-			   sizeof(rkey));
-	if (!pairwise) {
-		index = key_idx;
-		res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
-				    (char *) &index, sizeof(index));
-	} else
-		res2 = 0;
-
-	if (res < 0 && res2 < 0)
-		return -1;
-	return 0;
-}
-
-
-static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
-				   int pairwise, int key_idx, int set_tx,
-				   const u8 *key, size_t key_len)
-{
-	NDIS_802_11_WEP *wep;
-	size_t len;
-	int res;
-
-	len = 12 + key_len;
-	wep = os_zalloc(len);
-	if (wep == NULL)
-		return -1;
-	wep->Length = len;
-	wep->KeyIndex = key_idx;
-	if (set_tx)
-		wep->KeyIndex |= 1 << 31;
-#if 0 /* Setting bit30 does not seem to work with some NDIS drivers */
-	if (pairwise)
-		wep->KeyIndex |= 1 << 30;
-#endif
-	wep->KeyLength = key_len;
-	os_memcpy(wep->KeyMaterial, key, key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
-			(u8 *) wep, len);
-	res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
-	os_free(wep);
-
-	return res;
-}
-
-
-static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
-				   enum wpa_alg alg, const u8 *addr,
-				   int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	size_t len, i;
-	NDIS_802_11_KEY *nkey;
-	int res, pairwise;
-	u8 bssid[ETH_ALEN];
-
-	if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-				      ETH_ALEN) == 0) {
-		/* Group Key */
-		pairwise = 0;
-		if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
-			os_memset(bssid, 0xff, ETH_ALEN);
-	} else {
-		/* Pairwise Key */
-		pairwise = 1;
-		os_memcpy(bssid, addr, ETH_ALEN);
-	}
-
-	if (alg == WPA_ALG_NONE || key_len == 0) {
-		return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid,
-						  pairwise);
-	}
-
-	if (alg == WPA_ALG_WEP) {
-		return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
-					       key, key_len);
-	}
-
-	len = 12 + 6 + 6 + 8 + key_len;
-
-	nkey = os_zalloc(len);
-	if (nkey == NULL)
-		return -1;
-
-	nkey->Length = len;
-	nkey->KeyIndex = key_idx;
-	if (set_tx)
-		nkey->KeyIndex |= 1 << 31;
-	if (pairwise)
-		nkey->KeyIndex |= 1 << 30;
-	if (seq && seq_len)
-		nkey->KeyIndex |= 1 << 29;
-	nkey->KeyLength = key_len;
-	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-	if (seq && seq_len) {
-		for (i = 0; i < seq_len; i++)
-			nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8);
-	}
-	if (alg == WPA_ALG_TKIP && key_len == 32) {
-		os_memcpy(nkey->KeyMaterial, key, 16);
-		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
-		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
-	} else {
-		os_memcpy(nkey->KeyMaterial, key, key_len);
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
-			(u8 *) nkey, len);
-	res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
-	os_free(nkey);
-
-	return res;
-}
-
-
-static int
-wpa_driver_ndis_associate(void *priv,
-			  struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	u32 auth_mode, encr, priv_mode, mode;
-
-	drv->mode = params->mode;
-
-	/* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
-	 * so static WEP keys needs to be set again after this. */
-	if (params->mode == IEEE80211_MODE_IBSS) {
-		mode = Ndis802_11IBSS;
-		/* Need to make sure that BSSID polling is enabled for
-		 * IBSS mode. */
-		eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
-		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
-				       drv, NULL);
-	} else
-		mode = Ndis802_11Infrastructure;
-	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-			 (char *) &mode, sizeof(mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
-			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-			   (int) mode);
-		/* Try to continue anyway */
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_NONE ||
-	    params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
-		/* Re-set WEP keys if static WEP configuration is used. */
-		u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-		int i;
-		for (i = 0; i < 4; i++) {
-			if (!params->wep_key[i])
-				continue;
-			wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
-				   "key %d", i);
-			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
-						bcast, i,
-						i == params->wep_tx_keyidx,
-						NULL, 0, params->wep_key[i],
-						params->wep_key_len[i]);
-		}
-	}
-
-	if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-		if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
-			if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-				auth_mode = Ndis802_11AuthModeAutoSwitch;
-			else
-				auth_mode = Ndis802_11AuthModeShared;
-		} else
-			auth_mode = Ndis802_11AuthModeOpen;
-		priv_mode = Ndis802_11PrivFilterAcceptAll;
-	} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-		priv_mode = Ndis802_11PrivFilter8021xWEP;
-		if (params->key_mgmt_suite == KEY_MGMT_PSK)
-			auth_mode = Ndis802_11AuthModeWPA2PSK;
-		else
-			auth_mode = Ndis802_11AuthModeWPA2;
-#ifdef CONFIG_WPS
-	} else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
-		auth_mode = Ndis802_11AuthModeOpen;
-		priv_mode = Ndis802_11PrivFilterAcceptAll;
-#endif /* CONFIG_WPS */
-	} else {
-		priv_mode = Ndis802_11PrivFilter8021xWEP;
-		if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-			auth_mode = Ndis802_11AuthModeWPANone;
-		else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-			auth_mode = Ndis802_11AuthModeWPAPSK;
-		else
-			auth_mode = Ndis802_11AuthModeWPA;
-	}
-
-	switch (params->pairwise_suite) {
-	case CIPHER_CCMP:
-		encr = Ndis802_11Encryption3Enabled;
-		break;
-	case CIPHER_TKIP:
-		encr = Ndis802_11Encryption2Enabled;
-		break;
-	case CIPHER_WEP40:
-	case CIPHER_WEP104:
-		encr = Ndis802_11Encryption1Enabled;
-		break;
-	case CIPHER_NONE:
-		if (params->group_suite == CIPHER_CCMP)
-			encr = Ndis802_11Encryption3Enabled;
-		else if (params->group_suite == CIPHER_TKIP)
-			encr = Ndis802_11Encryption2Enabled;
-		else
-			encr = Ndis802_11EncryptionDisabled;
-		break;
-	default:
-		encr = Ndis802_11EncryptionDisabled;
-	};
-
-	if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
-			 (char *) &priv_mode, sizeof(priv_mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
-			   "OID_802_11_PRIVACY_FILTER (%d)",
-			   (int) priv_mode);
-		/* Try to continue anyway */
-	}
-
-	ndis_set_auth_mode(drv, auth_mode);
-	ndis_set_encr_status(drv, encr);
-
-	if (params->bssid) {
-		ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid,
-			     ETH_ALEN);
-		drv->oid_bssid_set = 1;
-	} else if (drv->oid_bssid_set) {
-		ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
-			     ETH_ALEN);
-		drv->oid_bssid_set = 0;
-	}
-
-	return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-
-static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
-{
-	int len, count, i, ret;
-	struct ndis_pmkid_entry *entry;
-	NDIS_802_11_PMKID *p;
-
-	count = 0;
-	entry = drv->pmkid;
-	while (entry) {
-		count++;
-		if (count >= drv->no_of_pmkid)
-			break;
-		entry = entry->next;
-	}
-	len = 8 + count * sizeof(BSSID_INFO);
-	p = os_zalloc(len);
-	if (p == NULL)
-		return -1;
-
-	p->Length = len;
-	p->BSSIDInfoCount = count;
-	entry = drv->pmkid;
-	for (i = 0; i < count; i++) {
-		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
-		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
-		entry = entry->next;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len);
-	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
-	os_free(p);
-	return ret;
-}
-
-
-static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
-				     const u8 *pmkid)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	prev = NULL;
-	entry = drv->pmkid;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		prev = entry;
-		entry = entry->next;
-	}
-
-	if (entry) {
-		/* Replace existing entry for this BSSID and move it into the
-		 * beginning of the list. */
-		os_memcpy(entry->pmkid, pmkid, 16);
-		if (prev) {
-			prev->next = entry->next;
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	} else {
-		entry = os_malloc(sizeof(*entry));
-		if (entry) {
-			os_memcpy(entry->bssid, bssid, ETH_ALEN);
-			os_memcpy(entry->pmkid, pmkid, 16);
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	}
-
-	return wpa_driver_ndis_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
-		 			const u8 *pmkid)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	entry = drv->pmkid;
-	prev = NULL;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
-		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				drv->pmkid = entry->next;
-			os_free(entry);
-			break;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-	return wpa_driver_ndis_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ndis_flush_pmkid(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	NDIS_802_11_PMKID p;
-	struct ndis_pmkid_entry *pmkid, *prev;
-	int prev_authmode, ret;
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	pmkid = drv->pmkid;
-	drv->pmkid = NULL;
-	while (pmkid) {
-		prev = pmkid;
-		pmkid = pmkid->next;
-		os_free(prev);
-	}
-
-	/*
-	 * Some drivers may refuse OID_802_11_PMKID if authMode is not set to
-	 * WPA2, so change authMode temporarily, if needed.
-	 */
-	prev_authmode = ndis_get_auth_mode(drv);
-	if (prev_authmode != Ndis802_11AuthModeWPA2)
-		ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2);
-
-	os_memset(&p, 0, sizeof(p));
-	p.Length = 8;
-	p.BSSIDInfoCount = 0;
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-		    (u8 *) &p, 8);
-	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-
-	if (prev_authmode != Ndis802_11AuthModeWPA2)
-		ndis_set_auth_mode(drv, prev_authmode);
-
-	return ret;
-}
-
-
-static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
-{
-	char buf[512], *pos;
-	NDIS_802_11_ASSOCIATION_INFORMATION *ai;
-	int len;
-	union wpa_event_data data;
-	NDIS_802_11_BSSID_LIST_EX *b;
-	size_t blen, i;
-
-	len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
-			   sizeof(buf));
-	if (len < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: failed to get association "
-			   "information");
-		return -1;
-	}
-	if (len > sizeof(buf)) {
-		/* Some drivers seem to be producing incorrect length for this
-		 * data. Limit the length to the current buffer size to avoid
-		 * crashing in hexdump. The data seems to be otherwise valid,
-		 * so better try to use it. */
-		wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association "
-			   "information length %d", len);
-		len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION,
-				   buf, sizeof(buf));
-		if (len < -1) {
-			wpa_printf(MSG_DEBUG, "NDIS: re-reading association "
-				   "information failed");
-			return -1;
-		}
-		if (len > sizeof(buf)) {
-			wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association"
-				   " information length %d (re-read)", len);
-			len = sizeof(buf);
-		}
-	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: association information",
-		    (u8 *) buf, len);
-	if (len < sizeof(*ai)) {
-		wpa_printf(MSG_DEBUG, "NDIS: too short association "
-			   "information");
-		return -1;
-	}
-	ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf;
-	wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d "
-		   "off_resp=%d len_req=%d len_resp=%d",
-		   ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs,
-		   (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
-		   (int) ai->RequestIELength, (int) ai->ResponseIELength);
-
-	if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len ||
-	    ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) {
-		wpa_printf(MSG_DEBUG, "NDIS: association information - "
-			   "IE overflow");
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
-		    (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength);
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
-		    (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength);
-
-	os_memset(&data, 0, sizeof(data));
-	data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs;
-	data.assoc_info.req_ies_len = ai->RequestIELength;
-	data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs;
-	data.assoc_info.resp_ies_len = ai->ResponseIELength;
-
-	blen = 65535;
-	b = os_zalloc(blen);
-	if (b == NULL)
-		goto skip_scan_results;
-	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
-	if (len < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
-		os_free(b);
-		b = NULL;
-		goto skip_scan_results;
-	}
-	wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
-		   (unsigned int) b->NumberOfItems);
-
-	pos = (char *) &b->Bssid[0];
-	for (i = 0; i < b->NumberOfItems; i++) {
-		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
-		if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
-		    bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
-			data.assoc_info.beacon_ies =
-				((u8 *) bss->IEs) +
-				sizeof(NDIS_802_11_FIXED_IEs);
-			data.assoc_info.beacon_ies_len =
-				bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-			wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
-				    data.assoc_info.beacon_ies,
-				    data.assoc_info.beacon_ies_len);
-			break;
-		}
-		pos += bss->Length;
-		if (pos > (char *) b + blen)
-			break;
-	}
-
-skip_scan_results:
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
-
-	os_free(b);
-
-	return 0;
-}
-
-
-static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_ndis_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-	int poll;
-
-	if (drv->wired)
-		return;
-
-	if (wpa_driver_ndis_get_bssid(drv, bssid)) {
-		/* Disconnected */
-		if (!is_zero_ether_addr(drv->bssid)) {
-			os_memset(drv->bssid, 0, ETH_ALEN);
-			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-		}
-	} else {
-		/* Connected */
-		if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
-			os_memcpy(drv->bssid, bssid, ETH_ALEN);
-			wpa_driver_ndis_get_associnfo(drv);
-			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-		}
-	}
-
-	/* When using integrated NDIS event receiver, we can skip BSSID
-	 * polling when using infrastructure network. However, when using
-	 * IBSS mode, many driver do not seem to generate connection event,
-	 * so we need to enable BSSID polling to figure out when IBSS network
-	 * has been formed.
-	 */
-	poll = drv->mode == IEEE80211_MODE_IBSS;
-#ifndef CONFIG_NDIS_EVENTS_INTEGRATED
-#ifndef _WIN32_WCE
-	poll = 1;
-#endif /* _WIN32_WCE */
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-
-	if (poll) {
-		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
-					drv, NULL);
-	}
-}
-
-
-static void wpa_driver_ndis_poll(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
-	wpa_driver_ndis_poll_timeout(drv, NULL);
-}
-
-
-/* Called when driver generates Media Connect Event by calling
- * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */
-void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
-{
-	wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event");
-	if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) {
-		wpa_driver_ndis_get_associnfo(drv);
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-	}
-}
-
-
-/* Called when driver generates Media Disconnect Event by calling
- * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */
-void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
-{
-	wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
-	os_memset(drv->bssid, 0, ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-}
-
-
-static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
-				       const u8 *data, size_t data_len)
-{
-	NDIS_802_11_AUTHENTICATION_REQUEST *req;
-	int pairwise = 0, group = 0;
-	union wpa_event_data event;
-
-	if (data_len < sizeof(*req)) {
-		wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
-			   "Event (len=%d)", data_len);
-		return;
-	}
-	req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: "
-		   "Bssid " MACSTR " Flags 0x%x",
-		   MAC2STR(req->Bssid), (int) req->Flags);
-
-	if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) ==
-	    NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR)
-		pairwise = 1;
-	else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) ==
-	    NDIS_802_11_AUTH_REQUEST_GROUP_ERROR)
-		group = 1;
-
-	if (pairwise || group) {
-		os_memset(&event, 0, sizeof(event));
-		event.michael_mic_failure.unicast = pairwise;
-		wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
-				     &event);
-	}
-}
-
-
-static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
-					const u8 *data, size_t data_len)
-{
-	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
-	size_t i;
-	union wpa_event_data event;
-
-	if (data_len < 8) {
-		wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
-			   "Event (len=%d)", data_len);
-		return;
-	}
-	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
-	wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d "
-		   "NumCandidates %d",
-		   (int) pmkid->Version, (int) pmkid->NumCandidates);
-
-	if (pmkid->Version != 1) {
-		wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List "
-			   "Version %d", (int) pmkid->Version);
-		return;
-	}
-
-	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
-		wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow");
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	for (i = 0; i < pmkid->NumCandidates; i++) {
-		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-		wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
-			   i, MAC2STR(p->BSSID), (int) p->Flags);
-		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
-		event.pmkid_candidate.index = i;
-		event.pmkid_candidate.preauth =
-			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
-		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
-				     &event);
-	}
-}
-
-
-/* Called when driver calls NdisMIndicateStatus() with
- * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */
-void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
-					  const u8 *data, size_t data_len)
-{
-	NDIS_802_11_STATUS_INDICATION *status;
-
-	if (data == NULL || data_len < sizeof(*status))
-		return;
-
-	wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication",
-		    data, data_len);
-
-	status = (NDIS_802_11_STATUS_INDICATION *) data;
-	data += sizeof(status);
-	data_len -= sizeof(status);
-
-	switch (status->StatusType) {
-	case Ndis802_11StatusType_Authentication:
-		wpa_driver_ndis_event_auth(drv, data, data_len);
-		break;
-	case Ndis802_11StatusType_PMKID_CandidateList:
-		wpa_driver_ndis_event_pmkid(drv, data, data_len);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d",
-			   (int) status->StatusType);
-		break;
-	}
-}
-
-
-/* Called when an adapter is added */
-void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv)
-{
-	union wpa_event_data event;
-	int i;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival");
-
-	for (i = 0; i < 30; i++) {
-		/* Re-open Packet32/NDISUIO connection */
-		wpa_driver_ndis_adapter_close(drv);
-		if (wpa_driver_ndis_adapter_init(drv) < 0 ||
-		    wpa_driver_ndis_adapter_open(drv) < 0) {
-			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization "
-				   "(%d) failed", i);
-			os_sleep(1, 0);
-		} else {
-			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized");
-			break;
-		}
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	os_strlcpy(event.interface_status.ifname, drv->ifname,
-		   sizeof(event.interface_status.ifname));
-	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-}
-
-
-/* Called when an adapter is removed */
-void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv)
-{
-	union wpa_event_data event;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal");
-	os_memset(&event, 0, sizeof(event));
-	os_strlcpy(event.interface_status.ifname, drv->ifname,
-		   sizeof(event.interface_status.ifname));
-	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-}
-
-
-static void
-wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
-{
-	wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability");
-
-	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 &&
-	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) {
-		wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported");
-		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
-	}
-
-	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 &&
-	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) {
-		wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management "
-			   "supported");
-		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
-	}
-
-	if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 &&
-	    ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) {
-		wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported");
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-	}
-
-	if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 &&
-	    ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) {
-		wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported");
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-	}
-
-	if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 &&
-	    ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) {
-		wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported");
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
-			WPA_DRIVER_CAPA_ENC_WEP104;
-	}
-
-	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 &&
-	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) {
-		drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
-	}
-
-	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 &&
-	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) {
-		drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
-	}
-
-	ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled);
-
-	/* Could also verify OID_802_11_ADD_KEY error reporting and
-	 * support for OID_802_11_ASSOCIATION_INFORMATION. */
-
-	if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA &&
-	    drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP |
-			     WPA_DRIVER_CAPA_ENC_CCMP)) {
-		wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA");
-		drv->has_capability = 1;
-	} else {
-		wpa_printf(MSG_DEBUG, "NDIS: no WPA support found");
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
-		   "enc 0x%x auth 0x%x",
-		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
-}
-
-
-static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
-{
-	char buf[512];
-	int len;
-	size_t i;
-	NDIS_802_11_CAPABILITY *c;
-
-	drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE;
-
-	len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
-	if (len < 0) {
-		wpa_driver_ndis_get_wpa_capability(drv);
-		return;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len);
-	c = (NDIS_802_11_CAPABILITY *) buf;
-	if (len < sizeof(*c) || c->Version != 2) {
-		wpa_printf(MSG_DEBUG, "NDIS: unsupported "
-			   "OID_802_11_CAPABILITY data");
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
-		   "NoOfPMKIDs %d NoOfAuthEncrPairs %d",
-		   (int) c->NoOfPMKIDs,
-		   (int) c->NoOfAuthEncryptPairsSupported);
-	drv->has_capability = 1;
-	drv->no_of_pmkid = c->NoOfPMKIDs;
-	for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) {
-		NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
-		ae = &c->AuthenticationEncryptionSupported[i];
-		if ((char *) (ae + 1) > buf + len) {
-			wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list "
-				   "overflow");
-			break;
-		}
-		wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
-			   i, (int) ae->AuthModeSupported,
-			   (int) ae->EncryptStatusSupported);
-		switch (ae->AuthModeSupported) {
-		case Ndis802_11AuthModeOpen:
-			drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
-			break;
-		case Ndis802_11AuthModeShared:
-			drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
-			break;
-		case Ndis802_11AuthModeWPA:
-			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
-			break;
-		case Ndis802_11AuthModeWPAPSK:
-			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
-			break;
-		case Ndis802_11AuthModeWPA2:
-			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
-			break;
-		case Ndis802_11AuthModeWPA2PSK:
-			drv->capa.key_mgmt |=
-				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-			break;
-		case Ndis802_11AuthModeWPANone:
-			drv->capa.key_mgmt |=
-				WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE;
-			break;
-		default:
-			break;
-		}
-		switch (ae->EncryptStatusSupported) {
-		case Ndis802_11Encryption1Enabled:
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40;
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104;
-			break;
-		case Ndis802_11Encryption2Enabled:
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-			break;
-		case Ndis802_11Encryption3Enabled:
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-			break;
-		default:
-			break;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
-		   "enc 0x%x auth 0x%x",
-		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
-}
-
-
-static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	if (!drv->has_capability)
-		return -1;
-	os_memcpy(capa, &drv->capa, sizeof(*capa));
-	return 0;
-}
-
-
-static const char * wpa_driver_ndis_get_ifname(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	return drv->ifname;
-}
-
-
-static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-	return drv->own_addr;
-}
-
-
-#ifdef _WIN32_WCE
-
-#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512)
-
-static void ndisuio_notification_receive(void *eloop_data, void *user_ctx)
-{
-	struct wpa_driver_ndis_data *drv = eloop_data;
-	NDISUIO_DEVICE_NOTIFICATION *hdr;
-	u8 buf[NDISUIO_MSG_SIZE];
-	DWORD len, flags;
-
-	if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0,
-			  &flags)) {
-		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
-			   "ReadMsgQueue failed: %d", (int) GetLastError());
-		return;
-	}
-
-	if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) {
-		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
-			   "Too short message (len=%d)", (int) len);
-		return;
-	}
-
-	hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf;
-	wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x",
-		   (int) len, hdr->dwNotificationType);
-
-	switch (hdr->dwNotificationType) {
-#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
-	case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL:
-		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL");
-		wpa_driver_ndis_event_adapter_arrival(drv);
-		break;
-#endif
-#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
-	case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL:
-		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL");
-		wpa_driver_ndis_event_adapter_removal(drv);
-		break;
-#endif
-	case NDISUIO_NOTIFICATION_MEDIA_CONNECT:
-		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT");
-		SetEvent(drv->connected_event);
-		wpa_driver_ndis_event_connect(drv);
-		break;
-	case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT:
-		ResetEvent(drv->connected_event);
-		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT");
-		wpa_driver_ndis_event_disconnect(drv);
-		break;
-	case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION:
-		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION");
-#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
-		wpa_driver_ndis_event_media_specific(
-			drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize);
-#else
-		wpa_driver_ndis_event_media_specific(
-			drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer,
-			(size_t) hdr->uiStatusBufferSize);
-#endif
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x",
-			   hdr->dwNotificationType);
-		break;
-	}
-}
-
-
-static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv)
-{
-	NDISUIO_REQUEST_NOTIFICATION req;
-
-	memset(&req, 0, sizeof(req));
-	req.hMsgQueue = drv->event_queue;
-	req.dwNotificationTypes = 0;
-
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
-			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
-		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
-			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
-			   (int) GetLastError());
-	}
-
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION,
-			     NULL, 0, NULL, 0, NULL, NULL)) {
-		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
-			   "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d",
-			   (int) GetLastError());
-	}
-
-	if (drv->event_queue) {
-		eloop_unregister_event(drv->event_queue,
-				       sizeof(drv->event_queue));
-		CloseHandle(drv->event_queue);
-		drv->event_queue = NULL;
-	}
-
-	if (drv->connected_event) {
-		CloseHandle(drv->connected_event);
-		drv->connected_event = NULL;
-	}
-}
-
-
-static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv)
-{
-	MSGQUEUEOPTIONS opt;
-	NDISUIO_REQUEST_NOTIFICATION req;
-
-	drv->connected_event =
-		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
-	if (drv->connected_event == NULL) {
-		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
-			   "CreateEvent failed: %d",
-			   (int) GetLastError());
-		return -1;
-	}
-
-	memset(&opt, 0, sizeof(opt));
-	opt.dwSize = sizeof(opt);
-	opt.dwMaxMessages = 5;
-	opt.cbMaxMessage = NDISUIO_MSG_SIZE;
-	opt.bReadAccess = TRUE;
-
-	drv->event_queue = CreateMsgQueue(NULL, &opt);
-	if (drv->event_queue == NULL) {
-		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
-			   "CreateMsgQueue failed: %d",
-			   (int) GetLastError());
-		ndisuio_notification_deinit(drv);
-		return -1;
-	}
-
-	memset(&req, 0, sizeof(req));
-	req.hMsgQueue = drv->event_queue;
-	req.dwNotificationTypes =
-#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
-		NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL |
-#endif
-#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
-		NDISUIO_NOTIFICATION_ADAPTER_REMOVAL |
-#endif
-		NDISUIO_NOTIFICATION_MEDIA_CONNECT |
-		NDISUIO_NOTIFICATION_MEDIA_DISCONNECT |
-		NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION;
-
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
-			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
-		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
-			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
-			   (int) GetLastError());
-		ndisuio_notification_deinit(drv);
-		return -1;
-	}
-
-	eloop_register_event(drv->event_queue, sizeof(drv->event_queue),
-			     ndisuio_notification_receive, drv, NULL);
-
-	return 0;
-}
-#endif /* _WIN32_WCE */
-
-
-static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
-{
-#ifdef CONFIG_USE_NDISUIO
-	NDISUIO_QUERY_BINDING *b;
-	size_t blen = sizeof(*b) + 1024;
-	int i, error, found = 0;
-	DWORD written;
-	char name[256], desc[256], *dpos;
-	WCHAR *pos;
-	size_t j, len, dlen;
-
-	b = os_malloc(blen);
-	if (b == NULL)
-		return -1;
-
-	for (i = 0; ; i++) {
-		os_memset(b, 0, blen);
-		b->BindingIndex = i;
-		if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
-				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
-				     &written, NULL)) {
-			error = (int) GetLastError();
-			if (error == ERROR_NO_MORE_ITEMS)
-				break;
-			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
-				   "failed: %d", error);
-			break;
-		}
-
-		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
-		len = b->DeviceNameLength;
-		if (len >= sizeof(name))
-			len = sizeof(name) - 1;
-		for (j = 0; j < len; j++)
-			name[j] = (char) pos[j];
-		name[len] = '\0';
-
-		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
-		len = b->DeviceDescrLength;
-		if (len >= sizeof(desc))
-			len = sizeof(desc) - 1;
-		for (j = 0; j < len; j++)
-			desc[j] = (char) pos[j];
-		desc[len] = '\0';
-
-		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
-
-		if (os_strstr(name, drv->ifname)) {
-			wpa_printf(MSG_DEBUG, "NDIS: Interface name match");
-			found = 1;
-			break;
-		}
-
-		if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0)
-		{
-			wpa_printf(MSG_DEBUG, "NDIS: Interface description "
-				   "match");
-			found = 1;
-			break;
-		}
-	}
-
-	if (!found) {
-		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
-			   drv->ifname);
-		os_free(b);
-		return -1;
-	}
-
-	os_strlcpy(drv->ifname,
-		   os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name,
-		   sizeof(drv->ifname));
-#ifdef _WIN32_WCE
-	drv->adapter_name = wpa_strdup_tchar(drv->ifname);
-	if (drv->adapter_name == NULL) {
-		wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for "
-			   "adapter name");
-		os_free(b);
-		return -1;
-	}
-#endif /* _WIN32_WCE */
-
-	dpos = os_strstr(desc, " - ");
-	if (dpos)
-		dlen = dpos - desc;
-	else
-		dlen = os_strlen(desc);
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc, dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
-	os_free(b);
-
-	if (drv->adapter_desc == NULL)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
-		   drv->adapter_desc);
-
-	return 0;
-#else /* CONFIG_USE_NDISUIO */
-	PTSTR _names;
-	char *names, *pos, *pos2;
-	ULONG len;
-	BOOLEAN res;
-#define MAX_ADAPTERS 32
-	char *name[MAX_ADAPTERS];
-	char *desc[MAX_ADAPTERS];
-	int num_name, num_desc, i, found_name, found_desc;
-	size_t dlen;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
-		   PacketGetVersion());
-
-	len = 8192;
-	_names = os_zalloc(len);
-	if (_names == NULL)
-		return -1;
-
-	res = PacketGetAdapterNames(_names, &len);
-	if (!res && len > 8192) {
-		os_free(_names);
-		_names = os_zalloc(len);
-		if (_names == NULL)
-			return -1;
-		res = PacketGetAdapterNames(_names, &len);
-	}
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
-			   "(PacketGetAdapterNames)");
-		os_free(_names);
-		return -1;
-	}
-
-	names = (char *) _names;
-	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
-		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
-			   "UNICODE");
-		/* Convert to ASCII */
-		pos2 = pos = names;
-		while (pos2 < names + len) {
-			if (pos2[0] == '\0' && pos2[1] == '\0' &&
-			    pos2[2] == '\0' && pos2[3] == '\0') {
-				pos2 += 4;
-				break;
-			}
-			*pos++ = pos2[0];
-			pos2 += 2;
-		}
-		os_memcpy(pos + 2, names, pos - names);
-		pos += 2;
-	} else
-		pos = names;
-
-	num_name = 0;
-	while (pos < names + len) {
-		name[num_name] = pos;
-		while (*pos && pos < names + len)
-			pos++;
-		if (pos + 1 >= names + len) {
-			os_free(names);
-			return -1;
-		}
-		pos++;
-		num_name++;
-		if (num_name >= MAX_ADAPTERS) {
-			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
-			os_free(names);
-			return -1;
-		}
-		if (*pos == '\0') {
-			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
-				   num_name);
-			pos++;
-			break;
-		}
-	}
-
-	num_desc = 0;
-	while (pos < names + len) {
-		desc[num_desc] = pos;
-		while (*pos && pos < names + len)
-			pos++;
-		if (pos + 1 >= names + len) {
-			os_free(names);
-			return -1;
-		}
-		pos++;
-		num_desc++;
-		if (num_desc >= MAX_ADAPTERS) {
-			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
-				   "descriptions");
-			os_free(names);
-			return -1;
-		}
-		if (*pos == '\0') {
-			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
-				   "found", num_name);
-			pos++;
-			break;
-		}
-	}
-
-	/*
-	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
-	 * descriptions. Fill in dummy descriptors to work around this.
-	 */
-	while (num_desc < num_name)
-		desc[num_desc++] = "dummy description";
-
-	if (num_name != num_desc) {
-		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
-			   "description counts (%d != %d)",
-			   num_name, num_desc);
-		os_free(names);
-		return -1;
-	}
-
-	found_name = found_desc = -1;
-	for (i = 0; i < num_name; i++) {
-		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
-			   i, name[i], desc[i]);
-		if (found_name == -1 && os_strstr(name[i], drv->ifname))
-			found_name = i;
-		if (found_desc == -1 &&
-		    os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) ==
-		    0)
-			found_desc = i;
-	}
-
-	if (found_name < 0 && found_desc >= 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on "
-			   "description '%s'",
-			   name[found_desc], desc[found_desc]);
-		found_name = found_desc;
-		os_strlcpy(drv->ifname,
-			   os_strncmp(name[found_desc], "\\Device\\NPF_", 12)
-			   == 0 ? name[found_desc] + 12 : name[found_desc],
-			   sizeof(drv->ifname));
-	}
-
-	if (found_name < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
-			   drv->ifname);
-		os_free(names);
-		return -1;
-	}
-
-	i = found_name;
-	pos = os_strrchr(desc[i], '(');
-	if (pos) {
-		dlen = pos - desc[i];
-		pos--;
-		if (pos > desc[i] && *pos == ' ')
-			dlen--;
-	} else {
-		dlen = os_strlen(desc[i]);
-	}
-	drv->adapter_desc = os_malloc(dlen + 1);
-	if (drv->adapter_desc) {
-		os_memcpy(drv->adapter_desc, desc[i], dlen);
-		drv->adapter_desc[dlen] = '\0';
-	}
-
-	os_free(names);
-
-	if (drv->adapter_desc == NULL)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
-		   drv->adapter_desc);
-
-	return 0;
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__)
-#ifndef _WIN32_WCE
-/*
- * These structures are undocumented for WinXP; only WinCE version is
- * documented. These would be included wzcsapi.h if it were available. Some
- * changes here have been needed to make the structures match with WinXP SP2.
- * It is unclear whether these work with any other version.
- */
-
-typedef struct {
-	LPWSTR wszGuid;
-} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY;
-
-typedef struct {
-	DWORD dwNumIntfs;
-	PINTF_KEY_ENTRY pIntfs;
-} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE;
-
-typedef struct {
-	DWORD dwDataLen;
-	LPBYTE pData;
-} RAW_DATA, *PRAW_DATA;
-
-typedef struct {
-	LPWSTR wszGuid;
-	LPWSTR wszDescr;
-	ULONG ulMediaState;
-	ULONG ulMediaType;
-	ULONG ulPhysicalMediaType;
-	INT nInfraMode;
-	INT nAuthMode;
-	INT nWepStatus;
-#ifndef _WIN32_WCE
-	u8 pad[2]; /* why is this needed? */
-#endif /* _WIN32_WCE */
-	DWORD dwCtlFlags;
-	DWORD dwCapabilities; /* something added for WinXP SP2(?) */
-	RAW_DATA rdSSID;
-	RAW_DATA rdBSSID;
-	RAW_DATA rdBSSIDList;
-	RAW_DATA rdStSSIDList;
-	RAW_DATA rdCtrlData;
-#ifdef UNDER_CE
-	BOOL bInitialized;
-#endif
-	DWORD nWPAMCastCipher;
-	/* add some extra buffer for later additions since this interface is
-	 * far from stable */
-	u8 later_additions[100];
-} INTF_ENTRY, *PINTF_ENTRY;
-
-#define INTF_ALL 0xffffffff
-#define INTF_ALL_FLAGS 0x0000ffff
-#define INTF_CTLFLAGS 0x00000010
-#define INTFCTL_ENABLED 0x8000
-#endif /* _WIN32_WCE */
-
-
-#ifdef _WIN32_WCE
-static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv)
-{
-	HANDLE ndis;
-	TCHAR multi[100];
-	int len;
-
-	len = _tcslen(drv->adapter_name);
-	if (len > 80)
-		return -1;
-
-	ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
-			  0, NULL, OPEN_EXISTING, 0, NULL);
-	if (ndis == INVALID_HANDLE_VALUE) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS "
-			   "device: %d", (int) GetLastError());
-		return -1;
-	}
-
-	len++;
-	memcpy(multi, drv->adapter_name, len * sizeof(TCHAR));
-	memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR));
-	len += 9;
-
-	if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER,
-			     multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL))
-	{
-		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER "
-			   "failed: 0x%x", (int) GetLastError());
-		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz",
-				  (u8 *) multi, len * sizeof(TCHAR));
-		CloseHandle(ndis);
-		return -1;
-	}
-
-	CloseHandle(ndis);
-
-	wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO "
-		   "protocol");
-
-	return 0;
-}
-#endif /* _WIN32_WCE */
-
-
-static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
-				   int enable)
-{
-#ifdef _WIN32_WCE
-	HKEY hk, hk2;
-	LONG ret;
-	DWORD i, hnd, len;
-	TCHAR keyname[256], devname[256];
-
-#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig")
-
-	if (enable) {
-		HANDLE h;
-		h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL);
-		if (h == INVALID_HANDLE_VALUE || h == 0) {
-			wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC "
-				   "- ActivateDeviceEx failed: %d",
-				   (int) GetLastError());
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled");
-		return wpa_driver_ndis_rebind_adapter(drv);
-	}
-
-	/*
-	 * Unfortunately, just disabling the WZC for an interface is not enough
-	 * to free NDISUIO for us, so need to disable and unload WZC completely
-	 * for now when using WinCE with NDISUIO. In addition, must request
-	 * NDISUIO protocol to be rebound to the adapter in order to free the
-	 * NDISUIO binding that WZC hold before us.
-	 */
-
-	/* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */
-	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) "
-			   "failed: %d %d", (int) ret, (int) GetLastError());
-		return -1;
-	}
-
-	for (i = 0; ; i++) {
-		len = sizeof(keyname);
-		ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL,
-				   NULL);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "NDIS: Could not find active "
-				   "WZC - assuming it is not running.");
-			RegCloseKey(hk);
-			return -1;
-		}
-
-		ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) "
-				   "failed: %d %d",
-				   (int) ret, (int) GetLastError());
-			continue;
-		}
-
-		len = sizeof(devname);
-		ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL,
-				      (LPBYTE) devname, &len);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx("
-				   "DEVKEY_VALNAME) failed: %d %d",
-				   (int) ret, (int) GetLastError());
-			RegCloseKey(hk2);
-			continue;
-		}
-
-		if (_tcscmp(devname, WZC_DRIVER) == 0)
-			break;
-
-		RegCloseKey(hk2);
-	}
-
-	RegCloseKey(hk);
-
-	/* Found WZC - get handle to it. */
-	len = sizeof(hnd);
-	ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL,
-			      (PUCHAR) &hnd, &len);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) "
-			   "failed: %d %d", (int) ret, (int) GetLastError());
-		RegCloseKey(hk2);
-		return -1;
-	}
-
-	RegCloseKey(hk2);
-
-	/* Deactivate WZC */
-	if (!DeactivateDevice((HANDLE) hnd)) {
-		wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d",
-			   (int) GetLastError());
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily");
-	drv->wzc_disabled = 1;
-	return wpa_driver_ndis_rebind_adapter(drv);
-
-#else /* _WIN32_WCE */
-
-	HMODULE hm;
-	DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr,
-					PINTFS_KEY_TABLE pIntfs);
-	DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
-					 PINTF_ENTRY pIntf,
-					 LPDWORD pdwOutFlags);
-	DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
-				       PINTF_ENTRY pIntf, LPDWORD pdwOutFlags);
-	int ret = -1, j;
-	DWORD res;
-	INTFS_KEY_TABLE guids;
-	INTF_ENTRY intf;
-	char guid[128];
-	WCHAR *pos;
-	DWORD flags, i;
-
-	hm = LoadLibrary(TEXT("wzcsapi.dll"));
-	if (hm == NULL) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) "
-			   "- WZC probably not running",
-			   (unsigned int) GetLastError());
-		return -1;
-	}
-
-#ifdef _WIN32_WCE
-	wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces");
-	wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface");
-	wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface");
-#else /* _WIN32_WCE */
-	wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces");
-	wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface");
-	wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface");
-#endif /* _WIN32_WCE */
-
-	if (wzc_enum_interf == NULL || wzc_query_interf == NULL ||
-	    wzc_set_interf == NULL) {
-		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, "
-			   "WZCQueryInterface, or WZCSetInterface not found "
-			   "in wzcsapi.dll");
-		goto fail;
-	}
-
-	os_memset(&guids, 0, sizeof(guids));
-	res = wzc_enum_interf(NULL, &guids);
-	if (res != 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; "
-			   "WZC service is apparently not running",
-			   (int) res);
-		goto fail;
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces",
-		   (int) guids.dwNumIntfs);
-
-	for (i = 0; i < guids.dwNumIntfs; i++) {
-		pos = guids.pIntfs[i].wszGuid;
-		for (j = 0; j < sizeof(guid); j++) {
-			guid[j] = (char) *pos;
-			if (*pos == 0)
-				break;
-			pos++;
-		}
-		guid[sizeof(guid) - 1] = '\0';
-		wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'",
-			   (int) i, guid);
-		if (os_strstr(drv->ifname, guid) == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "NDIS: Current interface found from "
-			   "WZC");
-		break;
-	}
-
-	if (i >= guids.dwNumIntfs) {
-		wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from "
-			   "WZC");
-		goto fail;
-	}
-
-	os_memset(&intf, 0, sizeof(intf));
-	intf.wszGuid = guids.pIntfs[i].wszGuid;
-	/* Set flags to verify that the structure has not changed. */
-	intf.dwCtlFlags = -1;
-	flags = 0;
-	res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags);
-	if (res != 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the "
-			   "WZC interface: %d (0x%x)",
-			   (int) res, (int) res);
-		wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
-			   (unsigned int) GetLastError());
-		goto fail;
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x",
-		   (int) flags, (int) intf.dwCtlFlags);
-
-	if (intf.dwCtlFlags == -1) {
-		wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed "
-			   "again - could not disable WZC");
-		wpa_hexdump(MSG_MSGDUMP, "NDIS: intf",
-			    (u8 *) &intf, sizeof(intf));
-		goto fail;
-	}
-
-	if (enable) {
-		if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) {
-			wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this "
-				   "interface");
-			intf.dwCtlFlags |= INTFCTL_ENABLED;
-			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
-					     &flags);
-			if (res != 0) {
-				wpa_printf(MSG_DEBUG, "NDIS: Failed to enable "
-					   "WZC: %d (0x%x)",
-					   (int) res, (int) res);
-				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
-					   (unsigned int) GetLastError());
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this "
-				   "interface");
-			drv->wzc_disabled = 0;
-		}
-	} else {
-		if (intf.dwCtlFlags & INTFCTL_ENABLED) {
-			wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this "
-				   "interface");
-			intf.dwCtlFlags &= ~INTFCTL_ENABLED;
-			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
-					     &flags);
-			if (res != 0) {
-				wpa_printf(MSG_DEBUG, "NDIS: Failed to "
-					   "disable WZC: %d (0x%x)",
-					   (int) res, (int) res);
-				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
-					   (unsigned int) GetLastError());
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily "
-				   "for this interface");
-			drv->wzc_disabled = 1;
-		} else {
-			wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for "
-				   "this interface");
-		}
-	}
-
-	ret = 0;
-
-fail:
-	FreeLibrary(hm);
-
-	return ret;
-#endif /* _WIN32_WCE */
-}
-
-#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
-
-static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
-				   int enable)
-{
-	return 0;
-}
-
-#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
-
-
-#ifdef CONFIG_USE_NDISUIO
-/*
- * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able
- * to export this handle. This is somewhat ugly, but there is no better
- * mechanism available to pass data from driver interface to l2_packet wrapper.
- */
-static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
-
-HANDLE driver_ndis_get_ndisuio_handle(void)
-{
-	return driver_ndis_ndisuio_handle;
-}
-#endif /* CONFIG_USE_NDISUIO */
-
-
-static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv)
-{
-#ifdef CONFIG_USE_NDISUIO
-#ifndef _WIN32_WCE
-#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio")
-	DWORD written;
-#endif /* _WIN32_WCE */
-	drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
-				  GENERIC_READ | GENERIC_WRITE, 0, NULL,
-				  OPEN_EXISTING,
-				  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
-				  INVALID_HANDLE_VALUE);
-	if (drv->ndisuio == INVALID_HANDLE_VALUE) {
-		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
-			   "NDISUIO: %d", (int) GetLastError());
-		return -1;
-	}
-	driver_ndis_ndisuio_handle = drv->ndisuio;
-
-#ifndef _WIN32_WCE
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
-			     NULL, 0, &written, NULL)) {
-		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
-			   "%d", (int) GetLastError());
-		CloseHandle(drv->ndisuio);
-		drv->ndisuio = INVALID_HANDLE_VALUE;
-		return -1;
-	}
-#endif /* _WIN32_WCE */
-
-	return 0;
-#else /* CONFIG_USE_NDISUIO */
-	return 0;
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv)
-{
-#ifdef CONFIG_USE_NDISUIO
-	DWORD written;
-#define MAX_NDIS_DEVICE_NAME_LEN 256
-	WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN];
-	size_t len, i, pos;
-	const char *prefix = "\\DEVICE\\";
-
-#ifdef _WIN32_WCE
-	pos = 0;
-#else /* _WIN32_WCE */
-	pos = 8;
-#endif /* _WIN32_WCE */
-	len = pos + os_strlen(drv->ifname);
-	if (len >= MAX_NDIS_DEVICE_NAME_LEN)
-		return -1;
-	for (i = 0; i < pos; i++)
-		ifname[i] = (WCHAR) prefix[i];
-	for (i = pos; i < len; i++)
-		ifname[i] = (WCHAR) drv->ifname[i - pos];
-	ifname[i] = L'\0';
-
-	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE,
-			     ifname, len * sizeof(WCHAR), NULL, 0, &written,
-			     NULL)) {
-		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE "
-			   "failed: %d", (int) GetLastError());
-		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname",
-				  (const u8 *) ifname, len * sizeof(WCHAR));
-		CloseHandle(drv->ndisuio);
-		drv->ndisuio = INVALID_HANDLE_VALUE;
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully");
-
-	return 0;
-#else /* CONFIG_USE_NDISUIO */
-	char ifname[128];
-	os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname);
-	drv->adapter = PacketOpenAdapter(ifname);
-	if (drv->adapter == NULL) {
-		wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
-			   "'%s'", ifname);
-		return -1;
-	}
-	return 0;
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
-{
-#ifdef CONFIG_USE_NDISUIO
-	driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
-	if (drv->ndisuio != INVALID_HANDLE_VALUE)
-		CloseHandle(drv->ndisuio);
-#else /* CONFIG_USE_NDISUIO */
-	if (drv->adapter)
-		PacketCloseAdapter(drv->adapter);
-#endif /* CONFIG_USE_NDISUIO */
-}
-
-
-static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
-{
-	if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
-			 (const char *) pae_group_addr, ETH_ALEN) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
-			   "to the multicast list");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_ndis_data *drv;
-	u32 mode;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	/*
-	 * Compatibility code to strip possible prefix from the GUID. Previous
-	 * versions include \Device\NPF_ prefix for all names, but the internal
-	 * interface name is now only the GUI. Both Packet32 and NDISUIO
-	 * prefixes are supported.
-	 */
-	if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
-		ifname += 12;
-	else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0)
-		ifname += 8;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-
-	if (wpa_driver_ndis_adapter_init(drv) < 0) {
-		os_free(drv);
-		return NULL;
-	}
-
-	if (wpa_driver_ndis_get_names(drv) < 0) {
-		wpa_driver_ndis_adapter_close(drv);
-		os_free(drv);
-		return NULL;
-	}
-
-	wpa_driver_ndis_set_wzc(drv, 0);
-
-	if (wpa_driver_ndis_adapter_open(drv) < 0) {
-		wpa_driver_ndis_adapter_close(drv);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
-			 (char *) drv->own_addr, ETH_ALEN) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
-			   "failed");
-		wpa_driver_ndis_adapter_close(drv);
-		os_free(drv);
-		return NULL;
-	}
-	wpa_driver_ndis_get_capability(drv);
-
-	/* Make sure that the driver does not have any obsolete PMKID entries.
-	 */
-	wpa_driver_ndis_flush_pmkid(drv);
-
-	/*
-	 * Disconnect to make sure that driver re-associates if it was
-	 * connected.
-	 */
-	wpa_driver_ndis_disconnect(drv);
-
-	eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
-
-#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-	drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail,
-				       drv->ifname, drv->adapter_desc);
-	if (drv->events == NULL) {
-		wpa_driver_ndis_deinit(drv);
-		return NULL;
-	}
-	eloop_register_event(drv->event_avail, sizeof(drv->event_avail),
-			     wpa_driver_ndis_event_pipe_cb, drv, NULL);
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-
-#ifdef _WIN32_WCE
-	if (ndisuio_notification_init(drv) < 0) {
-		wpa_driver_ndis_deinit(drv);
-		return NULL;
-	}
-#endif /* _WIN32_WCE */
-
-	/* Set mode here in case card was configured for ad-hoc mode
-	 * previously. */
-	mode = Ndis802_11Infrastructure;
-	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-			 (char *) &mode, sizeof(mode)) < 0) {
-		char buf[8];
-		int res;
-		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
-			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-			   (int) mode);
-		/* Try to continue anyway */
-
-		res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf,
-				   sizeof(buf));
-		if (res > 0) {
-			wpa_printf(MSG_INFO, "NDIS: The driver seems to use "
-				   "Native 802.11 OIDs. These are not yet "
-				   "fully supported.");
-			drv->native80211 = 1;
-		} else if (!drv->has_capability || drv->capa.enc == 0) {
-			/*
-			 * Note: This will also happen with NDIS 6 drivers with
-			 * Vista.
-			 */
-			wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
-				   "any wireless capabilities - assume it is "
-				   "a wired interface");
-			drv->wired = 1;
-			drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED;
-			drv->has_capability = 1;
-			ndis_add_multicast(drv);
-		}
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_ndis_deinit(void *priv)
-{
-	struct wpa_driver_ndis_data *drv = priv;
-
-#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-	if (drv->events) {
-		eloop_unregister_event(drv->event_avail,
-				       sizeof(drv->event_avail));
-		ndis_events_deinit(drv->events);
-	}
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-
-#ifdef _WIN32_WCE
-	ndisuio_notification_deinit(drv);
-#endif /* _WIN32_WCE */
-
-	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
-	wpa_driver_ndis_flush_pmkid(drv);
-	wpa_driver_ndis_disconnect(drv);
-	if (wpa_driver_ndis_radio_off(drv) < 0) {
-		wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
-			   "radio off");
-	}
-
-	wpa_driver_ndis_adapter_close(drv);
-
-	if (drv->wzc_disabled)
-		wpa_driver_ndis_set_wzc(drv, 1);
-
-#ifdef _WIN32_WCE
-	os_free(drv->adapter_name);
-#endif /* _WIN32_WCE */
-	os_free(drv->adapter_desc);
-	os_free(drv);
-}
-
-
-static struct wpa_interface_info *
-wpa_driver_ndis_get_interfaces(void *global_priv)
-{
-	struct wpa_interface_info *iface = NULL, *niface;
-
-#ifdef CONFIG_USE_NDISUIO
-	NDISUIO_QUERY_BINDING *b;
-	size_t blen = sizeof(*b) + 1024;
-	int i, error;
-	DWORD written;
-	char name[256], desc[256];
-	WCHAR *pos;
-	size_t j, len;
-	HANDLE ndisuio;
-
-	ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
-			     GENERIC_READ | GENERIC_WRITE, 0, NULL,
-			     OPEN_EXISTING,
-			     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
-			     INVALID_HANDLE_VALUE);
-	if (ndisuio == INVALID_HANDLE_VALUE) {
-		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
-			   "NDISUIO: %d", (int) GetLastError());
-		return NULL;
-	}
-
-#ifndef _WIN32_WCE
-	if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
-			     NULL, 0, &written, NULL)) {
-		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
-			   "%d", (int) GetLastError());
-		CloseHandle(ndisuio);
-		return NULL;
-	}
-#endif /* _WIN32_WCE */
-
-	b = os_malloc(blen);
-	if (b == NULL) {
-		CloseHandle(ndisuio);
-		return NULL;
-	}
-
-	for (i = 0; ; i++) {
-		os_memset(b, 0, blen);
-		b->BindingIndex = i;
-		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
-				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
-				     &written, NULL)) {
-			error = (int) GetLastError();
-			if (error == ERROR_NO_MORE_ITEMS)
-				break;
-			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
-				   "failed: %d", error);
-			break;
-		}
-
-		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
-		len = b->DeviceNameLength;
-		if (len >= sizeof(name))
-			len = sizeof(name) - 1;
-		for (j = 0; j < len; j++)
-			name[j] = (char) pos[j];
-		name[len] = '\0';
-
-		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
-		len = b->DeviceDescrLength;
-		if (len >= sizeof(desc))
-			len = sizeof(desc) - 1;
-		for (j = 0; j < len; j++)
-			desc[j] = (char) pos[j];
-		desc[len] = '\0';
-
-		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
-
-		niface = os_zalloc(sizeof(*niface));
-		if (niface == NULL)
-			break;
-		niface->drv_name = "ndis";
-		if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
-			niface->ifname = os_strdup(name + 8);
-		else
-			niface->ifname = os_strdup(name);
-		if (niface->ifname == NULL) {
-			os_free(niface);
-			break;
-		}
-		niface->desc = os_strdup(desc);
-		niface->next = iface;
-		iface = niface;
-	}
-
-	os_free(b);
-	CloseHandle(ndisuio);
-#else /* CONFIG_USE_NDISUIO */
-	PTSTR _names;
-	char *names, *pos, *pos2;
-	ULONG len;
-	BOOLEAN res;
-	char *name[MAX_ADAPTERS];
-	char *desc[MAX_ADAPTERS];
-	int num_name, num_desc, i;
-
-	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
-		   PacketGetVersion());
-
-	len = 8192;
-	_names = os_zalloc(len);
-	if (_names == NULL)
-		return NULL;
-
-	res = PacketGetAdapterNames(_names, &len);
-	if (!res && len > 8192) {
-		os_free(_names);
-		_names = os_zalloc(len);
-		if (_names == NULL)
-			return NULL;
-		res = PacketGetAdapterNames(_names, &len);
-	}
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
-			   "(PacketGetAdapterNames)");
-		os_free(_names);
-		return NULL;
-	}
-
-	names = (char *) _names;
-	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
-		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
-			   "UNICODE");
-		/* Convert to ASCII */
-		pos2 = pos = names;
-		while (pos2 < names + len) {
-			if (pos2[0] == '\0' && pos2[1] == '\0' &&
-			    pos2[2] == '\0' && pos2[3] == '\0') {
-				pos2 += 4;
-				break;
-			}
-			*pos++ = pos2[0];
-			pos2 += 2;
-		}
-		os_memcpy(pos + 2, names, pos - names);
-		pos += 2;
-	} else
-		pos = names;
-
-	num_name = 0;
-	while (pos < names + len) {
-		name[num_name] = pos;
-		while (*pos && pos < names + len)
-			pos++;
-		if (pos + 1 >= names + len) {
-			os_free(names);
-			return NULL;
-		}
-		pos++;
-		num_name++;
-		if (num_name >= MAX_ADAPTERS) {
-			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
-			os_free(names);
-			return NULL;
-		}
-		if (*pos == '\0') {
-			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
-				   num_name);
-			pos++;
-			break;
-		}
-	}
-
-	num_desc = 0;
-	while (pos < names + len) {
-		desc[num_desc] = pos;
-		while (*pos && pos < names + len)
-			pos++;
-		if (pos + 1 >= names + len) {
-			os_free(names);
-			return NULL;
-		}
-		pos++;
-		num_desc++;
-		if (num_desc >= MAX_ADAPTERS) {
-			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
-				   "descriptions");
-			os_free(names);
-			return NULL;
-		}
-		if (*pos == '\0') {
-			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
-				   "found", num_name);
-			pos++;
-			break;
-		}
-	}
-
-	/*
-	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
-	 * descriptions. Fill in dummy descriptors to work around this.
-	 */
-	while (num_desc < num_name)
-		desc[num_desc++] = "dummy description";
-
-	if (num_name != num_desc) {
-		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
-			   "description counts (%d != %d)",
-			   num_name, num_desc);
-		os_free(names);
-		return NULL;
-	}
-
-	for (i = 0; i < num_name; i++) {
-		niface = os_zalloc(sizeof(*niface));
-		if (niface == NULL)
-			break;
-		niface->drv_name = "ndis";
-		if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
-			niface->ifname = os_strdup(name[i] + 12);
-		else
-			niface->ifname = os_strdup(name[i]);
-		if (niface->ifname == NULL) {
-			os_free(niface);
-			break;
-		}
-		niface->desc = os_strdup(desc[i]);
-		niface->next = iface;
-		iface = niface;
-	}
-
-#endif /* CONFIG_USE_NDISUIO */
-
-	return iface;
-}
-
-
-const struct wpa_driver_ops wpa_driver_ndis_ops = {
-	"ndis",
-	"Windows NDIS driver",
-	wpa_driver_ndis_get_bssid,
-	wpa_driver_ndis_get_ssid,
-	wpa_driver_ndis_set_key,
-	wpa_driver_ndis_init,
-	wpa_driver_ndis_deinit,
-	NULL /* set_param */,
-	NULL /* set_countermeasures */,
-	wpa_driver_ndis_deauthenticate,
-	wpa_driver_ndis_disassociate,
-	wpa_driver_ndis_associate,
-	wpa_driver_ndis_add_pmkid,
-	wpa_driver_ndis_remove_pmkid,
-	wpa_driver_ndis_flush_pmkid,
-	wpa_driver_ndis_get_capa,
-	wpa_driver_ndis_poll,
-	wpa_driver_ndis_get_ifname,
-	wpa_driver_ndis_get_mac_addr,
-	NULL /* send_eapol */,
-	NULL /* set_operstate */,
-	NULL /* mlme_setprotection */,
-	NULL /* get_hw_feature_data */,
-	NULL /* set_channel */,
-	NULL /* set_ssid */,
-	NULL /* set_bssid */,
-	NULL /* send_mlme */,
-	NULL /* mlme_add_sta */,
-	NULL /* mlme_remove_sta */,
-	NULL /* update_ft_ies */,
-	NULL /* send_ft_action */,
-	wpa_driver_ndis_get_scan_results,
-	NULL /* set_country */,
-	NULL /* global_init */,
-	NULL /* global_deinit */,
-	NULL /* init2 */,
-	wpa_driver_ndis_get_interfaces,
-	wpa_driver_ndis_scan,
-	NULL /* authenticate */,
-	NULL /* set_beacon */,
-	NULL /* hapd_init */,
-	NULL /* hapd_deinit */,
-	NULL /* set_ieee8021x */,
-	NULL /* set_privacy */,
-	NULL /* get_seqnum */,
-	NULL /* flush */,
-	NULL /* set_generic_elem */,
-	NULL /* read_sta_data */,
-	NULL /* hapd_send_eapol */,
-	NULL /* sta_deauth */,
-	NULL /* sta_disassoc */,
-	NULL /* sta_remove */,
-	NULL /* hapd_get_ssid */,
-	NULL /* hapd_set_ssid */,
-	NULL /* hapd_set_countermeasures */,
-	NULL /* sta_add */,
-	NULL /* get_inact_sec */,
-	NULL /* sta_clear_stats */,
-	NULL /* set_freq */,
-	NULL /* set_rts */,
-	NULL /* set_frag */,
-	NULL /* sta_set_flags */,
-	NULL /* set_rate_sets */,
-	NULL /* set_cts_protect */,
-	NULL /* set_preamble */,
-	NULL /* set_short_slot_time */,
-	NULL /* set_tx_queue_params */,
-	NULL /* valid_bss_mask */,
-	NULL /* if_add */,
-	NULL /* if_remove */,
-	NULL /* set_sta_vlan */,
-	NULL /* commit */,
-	NULL /* send_ether */,
-	NULL /* set_radius_acl_auth */,
-	NULL /* set_radius_acl_expire */,
-	NULL /* set_ht_params */,
-	NULL /* set_ap_wps_ie */,
-	NULL /* set_supp_port */,
-	NULL /* set_wds_sta */,
-	NULL /* send_action */,
-	NULL /* remain_on_channel */,
-	NULL /* cancel_remain_on_channel */,
-	NULL /* probe_req_report */,
-	NULL /* disable_11b_rates */,
-	NULL /* deinit_ap */,
-	NULL /* suspend */,
-	NULL /* resume */,
-	NULL /* signal_monitor */,
-	NULL /* send_frame */
-};

Copied: vendor/wpa/2.0/src/drivers/driver_ndis.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_ndis.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_ndis.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_ndis.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3230 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifdef __CYGWIN__
+/* Avoid some header file conflicts by not including standard headers for
+ * cygwin builds when Packet32.h is included. */
+#include "build_config.h"
+int close(int fd);
+#else /* __CYGWIN__ */
+#include "includes.h"
+#endif /* __CYGWIN__ */
+#ifdef CONFIG_USE_NDISUIO
+#include <winsock2.h>
+#else /* CONFIG_USE_NDISUIO */
+#include <Packet32.h>
+#endif /* CONFIG_USE_NDISUIO */
+#ifdef __MINGW32_VERSION
+#include <ddk/ntddndis.h>
+#else /* __MINGW32_VERSION */
+#include <ntddndis.h>
+#endif /* __MINGW32_VERSION */
+
+#ifdef _WIN32_WCE
+#include <winioctl.h>
+#include <nuiouser.h>
+#include <devload.h>
+#endif /* _WIN32_WCE */
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "driver_ndis.h"
+
+int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data);
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+static void wpa_driver_ndis_deinit(void *priv);
+static void wpa_driver_ndis_poll(void *drv);
+static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv);
+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+/* FIX: to be removed once this can be compiled with the complete NDIS
+ * header files */
+#ifndef OID_802_11_BSSID
+#define OID_802_11_BSSID 			0x0d010101
+#define OID_802_11_SSID 			0x0d010102
+#define OID_802_11_INFRASTRUCTURE_MODE		0x0d010108
+#define OID_802_11_ADD_WEP			0x0D010113
+#define OID_802_11_REMOVE_WEP			0x0D010114
+#define OID_802_11_DISASSOCIATE			0x0D010115
+#define OID_802_11_BSSID_LIST 			0x0d010217
+#define OID_802_11_AUTHENTICATION_MODE		0x0d010118
+#define OID_802_11_PRIVACY_FILTER		0x0d010119
+#define OID_802_11_BSSID_LIST_SCAN 		0x0d01011A
+#define OID_802_11_WEP_STATUS	 		0x0d01011B
+#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS
+#define OID_802_11_ADD_KEY 			0x0d01011D
+#define OID_802_11_REMOVE_KEY 			0x0d01011E
+#define OID_802_11_ASSOCIATION_INFORMATION	0x0d01011F
+#define OID_802_11_TEST 			0x0d010120
+#define OID_802_11_CAPABILITY 			0x0d010122
+#define OID_802_11_PMKID 			0x0d010123
+
+#define NDIS_802_11_LENGTH_SSID 32
+#define NDIS_802_11_LENGTH_RATES 8
+#define NDIS_802_11_LENGTH_RATES_EX 16
+
+typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
+
+typedef struct NDIS_802_11_SSID {
+	ULONG SsidLength;
+	UCHAR Ssid[NDIS_802_11_LENGTH_SSID];
+} NDIS_802_11_SSID;
+
+typedef LONG NDIS_802_11_RSSI;
+
+typedef enum NDIS_802_11_NETWORK_TYPE {
+	Ndis802_11FH,
+	Ndis802_11DS,
+	Ndis802_11OFDM5,
+	Ndis802_11OFDM24,
+	Ndis802_11NetworkTypeMax
+} NDIS_802_11_NETWORK_TYPE;
+
+typedef struct NDIS_802_11_CONFIGURATION_FH {
+	ULONG Length;
+	ULONG HopPattern;
+	ULONG HopSet;
+	ULONG DwellTime;
+} NDIS_802_11_CONFIGURATION_FH;
+
+typedef struct NDIS_802_11_CONFIGURATION {
+	ULONG Length;
+	ULONG BeaconPeriod;
+	ULONG ATIMWindow;
+	ULONG DSConfig;
+	NDIS_802_11_CONFIGURATION_FH FHConfig;
+} NDIS_802_11_CONFIGURATION;
+
+typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
+	Ndis802_11IBSS,
+	Ndis802_11Infrastructure,
+	Ndis802_11AutoUnknown,
+	Ndis802_11InfrastructureMax
+} NDIS_802_11_NETWORK_INFRASTRUCTURE;
+
+typedef enum NDIS_802_11_AUTHENTICATION_MODE {
+	Ndis802_11AuthModeOpen,
+	Ndis802_11AuthModeShared,
+	Ndis802_11AuthModeAutoSwitch,
+	Ndis802_11AuthModeWPA,
+	Ndis802_11AuthModeWPAPSK,
+	Ndis802_11AuthModeWPANone,
+	Ndis802_11AuthModeWPA2,
+	Ndis802_11AuthModeWPA2PSK,
+	Ndis802_11AuthModeMax
+} NDIS_802_11_AUTHENTICATION_MODE;
+
+typedef enum NDIS_802_11_WEP_STATUS {
+	Ndis802_11WEPEnabled,
+	Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+	Ndis802_11WEPDisabled,
+	Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+	Ndis802_11WEPKeyAbsent,
+	Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+	Ndis802_11WEPNotSupported,
+	Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+	Ndis802_11Encryption2Enabled,
+	Ndis802_11Encryption2KeyAbsent,
+	Ndis802_11Encryption3Enabled,
+	Ndis802_11Encryption3KeyAbsent
+} NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS;
+
+typedef enum NDIS_802_11_PRIVACY_FILTER {
+	Ndis802_11PrivFilterAcceptAll,
+	Ndis802_11PrivFilter8021xWEP
+} NDIS_802_11_PRIVACY_FILTER;
+
+typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];
+typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
+
+typedef struct NDIS_WLAN_BSSID_EX {
+	ULONG Length;
+	NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */
+	UCHAR Reserved[2];
+	NDIS_802_11_SSID Ssid;
+	ULONG Privacy;
+	NDIS_802_11_RSSI Rssi;
+	NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+	NDIS_802_11_CONFIGURATION Configuration;
+	NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+	NDIS_802_11_RATES_EX SupportedRates;
+	ULONG IELength;
+	UCHAR IEs[1];
+} NDIS_WLAN_BSSID_EX;
+
+typedef struct NDIS_802_11_BSSID_LIST_EX {
+	ULONG NumberOfItems;
+	NDIS_WLAN_BSSID_EX Bssid[1];
+} NDIS_802_11_BSSID_LIST_EX;
+
+typedef struct NDIS_802_11_FIXED_IEs {
+	UCHAR Timestamp[8];
+	USHORT BeaconInterval;
+	USHORT Capabilities;
+} NDIS_802_11_FIXED_IEs;
+
+typedef struct NDIS_802_11_WEP {
+	ULONG Length;
+	ULONG KeyIndex;
+	ULONG KeyLength;
+	UCHAR KeyMaterial[1];
+} NDIS_802_11_WEP;
+
+typedef ULONG NDIS_802_11_KEY_INDEX;
+typedef ULONGLONG NDIS_802_11_KEY_RSC;
+
+typedef struct NDIS_802_11_KEY {
+	ULONG Length;
+	ULONG KeyIndex;
+	ULONG KeyLength;
+	NDIS_802_11_MAC_ADDRESS BSSID;
+	NDIS_802_11_KEY_RSC KeyRSC;
+	UCHAR KeyMaterial[1];
+} NDIS_802_11_KEY;
+
+typedef struct NDIS_802_11_REMOVE_KEY {
+	ULONG Length;
+	ULONG KeyIndex;
+	NDIS_802_11_MAC_ADDRESS BSSID;
+} NDIS_802_11_REMOVE_KEY;
+
+typedef struct NDIS_802_11_AI_REQFI {
+	USHORT Capabilities;
+	USHORT ListenInterval;
+	NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
+} NDIS_802_11_AI_REQFI;
+
+typedef struct NDIS_802_11_AI_RESFI {
+	USHORT Capabilities;
+	USHORT StatusCode;
+	USHORT AssociationId;
+} NDIS_802_11_AI_RESFI;
+
+typedef struct NDIS_802_11_ASSOCIATION_INFORMATION {
+	ULONG Length;
+	USHORT AvailableRequestFixedIEs;
+	NDIS_802_11_AI_REQFI RequestFixedIEs;
+	ULONG RequestIELength;
+	ULONG OffsetRequestIEs;
+	USHORT AvailableResponseFixedIEs;
+	NDIS_802_11_AI_RESFI ResponseFixedIEs;
+	ULONG ResponseIELength;
+	ULONG OffsetResponseIEs;
+} NDIS_802_11_ASSOCIATION_INFORMATION;
+
+typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
+	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
+	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
+} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
+
+typedef struct NDIS_802_11_CAPABILITY {
+	ULONG Length;
+	ULONG Version;
+	ULONG NoOfPMKIDs;
+	ULONG NoOfAuthEncryptPairsSupported;
+	NDIS_802_11_AUTHENTICATION_ENCRYPTION
+		AuthenticationEncryptionSupported[1];
+} NDIS_802_11_CAPABILITY;
+
+typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+
+typedef struct BSSID_INFO {
+	NDIS_802_11_MAC_ADDRESS BSSID;
+	NDIS_802_11_PMKID_VALUE PMKID;
+} BSSID_INFO;
+
+typedef struct NDIS_802_11_PMKID {
+	ULONG Length;
+	ULONG BSSIDInfoCount;
+	BSSID_INFO BSSIDInfo[1];
+} NDIS_802_11_PMKID;
+
+typedef enum NDIS_802_11_STATUS_TYPE {
+	Ndis802_11StatusType_Authentication,
+	Ndis802_11StatusType_PMKID_CandidateList = 2,
+	Ndis802_11StatusTypeMax
+} NDIS_802_11_STATUS_TYPE;
+
+typedef struct NDIS_802_11_STATUS_INDICATION {
+	NDIS_802_11_STATUS_TYPE StatusType;
+} NDIS_802_11_STATUS_INDICATION;
+
+typedef struct PMKID_CANDIDATE {
+	NDIS_802_11_MAC_ADDRESS BSSID;
+	ULONG Flags;
+} PMKID_CANDIDATE;
+
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
+
+typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
+	ULONG Version;
+	ULONG NumCandidates;
+	PMKID_CANDIDATE CandidateList[1];
+} NDIS_802_11_PMKID_CANDIDATE_LIST;
+
+typedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
+	ULONG Length;
+	NDIS_802_11_MAC_ADDRESS Bssid;
+	ULONG Flags;
+} NDIS_802_11_AUTHENTICATION_REQUEST;
+
+#define NDIS_802_11_AUTH_REQUEST_REAUTH			0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE		0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR		0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR		0x0E
+
+#endif /* OID_802_11_BSSID */
+
+
+#ifndef OID_802_11_PMKID
+/* Platform SDK for XP did not include WPA2, so add needed definitions */
+
+#define OID_802_11_CAPABILITY 			0x0d010122
+#define OID_802_11_PMKID 			0x0d010123
+
+#define Ndis802_11AuthModeWPA2 6
+#define Ndis802_11AuthModeWPA2PSK 7
+
+#define Ndis802_11StatusType_PMKID_CandidateList 2
+
+typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
+	NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
+	NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
+} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
+
+typedef struct NDIS_802_11_CAPABILITY {
+	ULONG Length;
+	ULONG Version;
+	ULONG NoOfPMKIDs;
+	ULONG NoOfAuthEncryptPairsSupported;
+	NDIS_802_11_AUTHENTICATION_ENCRYPTION
+		AuthenticationEncryptionSupported[1];
+} NDIS_802_11_CAPABILITY;
+
+typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+
+typedef struct BSSID_INFO {
+	NDIS_802_11_MAC_ADDRESS BSSID;
+	NDIS_802_11_PMKID_VALUE PMKID;
+} BSSID_INFO;
+
+typedef struct NDIS_802_11_PMKID {
+	ULONG Length;
+	ULONG BSSIDInfoCount;
+	BSSID_INFO BSSIDInfo[1];
+} NDIS_802_11_PMKID;
+
+typedef struct PMKID_CANDIDATE {
+	NDIS_802_11_MAC_ADDRESS BSSID;
+	ULONG Flags;
+} PMKID_CANDIDATE;
+
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
+
+typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
+	ULONG Version;
+	ULONG NumCandidates;
+	PMKID_CANDIDATE CandidateList[1];
+} NDIS_802_11_PMKID_CANDIDATE_LIST;
+
+#endif /* OID_802_11_CAPABILITY */
+
+
+#ifndef OID_DOT11_CURRENT_OPERATION_MODE
+/* Native 802.11 OIDs */
+#define OID_DOT11_NDIS_START 0x0D010300
+#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8)
+#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11)
+
+typedef enum _DOT11_BSS_TYPE {
+	dot11_BSS_type_infrastructure = 1,
+	dot11_BSS_type_independent = 2,
+	dot11_BSS_type_any = 3
+} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE;
+
+typedef UCHAR DOT11_MAC_ADDRESS[6];
+typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS;
+
+typedef enum _DOT11_SCAN_TYPE {
+	dot11_scan_type_active = 1,
+	dot11_scan_type_passive = 2,
+	dot11_scan_type_auto = 3,
+	dot11_scan_type_forced = 0x80000000
+} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE;
+
+typedef struct _DOT11_SCAN_REQUEST_V2 {
+	DOT11_BSS_TYPE dot11BSSType;
+	DOT11_MAC_ADDRESS dot11BSSID;
+	DOT11_SCAN_TYPE dot11ScanType;
+	BOOLEAN bRestrictedScan;
+	ULONG udot11SSIDsOffset;
+	ULONG uNumOfdot11SSIDs;
+	BOOLEAN bUseRequestIE;
+	ULONG uRequestIDsOffset;
+	ULONG uNumOfRequestIDs;
+	ULONG uPhyTypeInfosOffset;
+	ULONG uNumOfPhyTypeInfos;
+	ULONG uIEsOffset;
+	ULONG uIEsLength;
+	UCHAR ucBuffer[1];
+} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2;
+
+#endif /* OID_DOT11_CURRENT_OPERATION_MODE */
+
+#ifdef CONFIG_USE_NDISUIO
+#ifndef _WIN32_WCE
+#ifdef __MINGW32_VERSION
+typedef ULONG NDIS_OID;
+#endif /* __MINGW32_VERSION */
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
+
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISUIO_OPEN_DEVICE \
+	_NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_QUERY_OID_VALUE \
+	_NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_SET_OID_VALUE \
+	_NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_SET_ETHER_TYPE \
+	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_QUERY_BINDING \
+	_NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_BIND_WAIT \
+	_NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _NDISUIO_QUERY_OID
+{
+    NDIS_OID Oid;
+    UCHAR Data[sizeof(ULONG)];
+} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
+
+typedef struct _NDISUIO_SET_OID
+{
+    NDIS_OID Oid;
+    UCHAR Data[sizeof(ULONG)];
+} NDISUIO_SET_OID, *PNDISUIO_SET_OID;
+
+typedef struct _NDISUIO_QUERY_BINDING
+{
+	ULONG BindingIndex;
+	ULONG DeviceNameOffset;
+	ULONG DeviceNameLength;
+	ULONG DeviceDescrOffset;
+	ULONG DeviceDescrLength;
+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
+#endif /* _WIN32_WCE */
+#endif /* CONFIG_USE_NDISUIO */
+
+
+static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
+			char *data, size_t len)
+{
+#ifdef CONFIG_USE_NDISUIO
+	NDISUIO_QUERY_OID *o;
+	size_t buflen = sizeof(*o) + len;
+	DWORD written;
+	int ret;
+	size_t hdrlen;
+
+	o = os_zalloc(buflen);
+	if (o == NULL)
+		return -1;
+	o->Oid = oid;
+#ifdef _WIN32_WCE
+	o->ptcDeviceName = drv->adapter_name;
+#endif /* _WIN32_WCE */
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE,
+			     o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written,
+			     NULL)) {
+		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE "
+			   "failed (oid=%08x): %d", oid, (int) GetLastError());
+		os_free(o);
+		return -1;
+	}
+	hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data);
+	if (written < hdrlen) {
+		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); "
+			   "too short", oid, (unsigned int) written);
+		os_free(o);
+		return -1;
+	}
+	written -= hdrlen;
+	if (written > len) {
+		wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > "
+			   "len (%d)",oid, (unsigned int) written, len);
+		os_free(o);
+		return -1;
+	}
+	os_memcpy(data, o->Data, written);
+	ret = written;
+	os_free(o);
+	return ret;
+#else /* CONFIG_USE_NDISUIO */
+	char *buf;
+	PACKET_OID_DATA *o;
+	int ret;
+
+	buf = os_zalloc(sizeof(*o) + len);
+	if (buf == NULL)
+		return -1;
+	o = (PACKET_OID_DATA *) buf;
+	o->Oid = oid;
+	o->Length = len;
+
+	if (!PacketRequest(drv->adapter, FALSE, o)) {
+		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+			   __func__, oid, len);
+		os_free(buf);
+		return -1;
+	}
+	if (o->Length > len) {
+		wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
+			   __func__, oid, (unsigned int) o->Length, len);
+		os_free(buf);
+		return -1;
+	}
+	os_memcpy(data, o->Data, o->Length);
+	ret = o->Length;
+	os_free(buf);
+	return ret;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
+			const char *data, size_t len)
+{
+#ifdef CONFIG_USE_NDISUIO
+	NDISUIO_SET_OID *o;
+	size_t buflen, reallen;
+	DWORD written;
+	char txt[50];
+
+	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
+	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
+
+	buflen = sizeof(*o) + len;
+	reallen = buflen - sizeof(o->Data);
+	o = os_zalloc(buflen);
+	if (o == NULL)
+		return -1;
+	o->Oid = oid;
+#ifdef _WIN32_WCE
+	o->ptcDeviceName = drv->adapter_name;
+#endif /* _WIN32_WCE */
+	if (data)
+		os_memcpy(o->Data, data, len);
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE,
+			     o, reallen, NULL, 0, &written, NULL)) {
+		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE "
+			   "(oid=%08x) failed: %d", oid, (int) GetLastError());
+		os_free(o);
+		return -1;
+	}
+	os_free(o);
+	return 0;
+#else /* CONFIG_USE_NDISUIO */
+	char *buf;
+	PACKET_OID_DATA *o;
+	char txt[50];
+
+	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
+	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
+
+	buf = os_zalloc(sizeof(*o) + len);
+	if (buf == NULL)
+		return -1;
+	o = (PACKET_OID_DATA *) buf;
+	o->Oid = oid;
+	o->Length = len;
+	if (data)
+		os_memcpy(o->Data, data, len);
+
+	if (!PacketRequest(drv->adapter, TRUE, o)) {
+		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+			   __func__, oid, len);
+		os_free(buf);
+		return -1;
+	}
+	os_free(buf);
+	return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode)
+{
+	u32 auth_mode = mode;
+	if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
+			 (char *) &auth_mode, sizeof(auth_mode)) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
+			   "OID_802_11_AUTHENTICATION_MODE (%d)",
+			   (int) auth_mode);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv)
+{
+	u32 auth_mode;
+	int res;
+	res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE,
+			   (char *) &auth_mode, sizeof(auth_mode));
+	if (res != sizeof(auth_mode)) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
+			   "OID_802_11_AUTHENTICATION_MODE");
+		return -1;
+	}
+	return auth_mode;
+}
+
+
+static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr)
+{
+	u32 encr_status = encr;
+	if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS,
+			 (char *) &encr_status, sizeof(encr_status)) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
+			   "OID_802_11_ENCRYPTION_STATUS (%d)", encr);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv)
+{
+	u32 encr;
+	int res;
+	res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS,
+			   (char *) &encr, sizeof(encr));
+	if (res != sizeof(encr)) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to get "
+			   "OID_802_11_ENCRYPTION_STATUS");
+		return -1;
+	}
+	return encr;
+}
+
+
+static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+
+	if (drv->wired) {
+		/*
+		 * Report PAE group address as the "BSSID" for wired
+		 * connection.
+		 */
+		os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+		return 0;
+	}
+
+	return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) <
+		0 ? -1 : 0;
+}
+
+
+static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	NDIS_802_11_SSID buf;
+	int res;
+
+	res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
+	if (res < 4) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
+		if (drv->wired) {
+			wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
+				   "with a wired interface");
+			return 0;
+		}
+		return -1;
+	}
+	os_memcpy(ssid, buf.Ssid, buf.SsidLength);
+	return buf.SsidLength;
+}
+
+
+static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
+				    const u8 *ssid, size_t ssid_len)
+{
+	NDIS_802_11_SSID buf;
+
+	os_memset(&buf, 0, sizeof(buf));
+	buf.SsidLength = ssid_len;
+	os_memcpy(buf.Ssid, ssid, ssid_len);
+	/*
+	 * Make sure radio is marked enabled here so that scan request will not
+	 * force SSID to be changed to a random one in order to enable radio at
+	 * that point.
+	 */
+	drv->radio_enabled = 1;
+	return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
+}
+
+
+/* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off.
+ */
+static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
+{
+	drv->radio_enabled = 0;
+	return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4);
+}
+
+
+/* Disconnect by setting SSID to random (i.e., likely not used). */
+static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
+{
+	char ssid[32];
+	int i;
+	for (i = 0; i < 32; i++)
+		ssid[i] = rand() & 0xff;
+	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
+}
+
+
+static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
+					  int reason_code)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	return wpa_driver_ndis_disconnect(drv);
+}
+
+
+static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_ndis_scan_native80211(
+	struct wpa_driver_ndis_data *drv,
+	struct wpa_driver_scan_params *params)
+{
+	DOT11_SCAN_REQUEST_V2 req;
+	int res;
+
+	os_memset(&req, 0, sizeof(req));
+	req.dot11BSSType = dot11_BSS_type_any;
+	os_memset(req.dot11BSSID, 0xff, ETH_ALEN);
+	req.dot11ScanType = dot11_scan_type_auto;
+	res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req,
+			   sizeof(req));
+	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
+			       drv->ctx);
+	return res;
+}
+
+
+static int wpa_driver_ndis_scan(void *priv,
+				struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	int res;
+
+	if (drv->native80211)
+		return wpa_driver_ndis_scan_native80211(drv, params);
+
+	if (!drv->radio_enabled) {
+		wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first"
+			   " scan");
+		if (wpa_driver_ndis_disconnect(drv) < 0) {
+			wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio");
+		}
+		drv->radio_enabled = 1;
+	}
+
+	res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, "    ", 4);
+	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
+			       drv->ctx);
+	return res;
+}
+
+
+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;
+}
+
+
+static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
+	struct wpa_scan_res *r, NDIS_802_11_SSID *ssid)
+{
+	struct wpa_scan_res *nr;
+	u8 *pos;
+
+	if (wpa_scan_get_ie(r, WLAN_EID_SSID))
+		return r; /* SSID IE already present */
+
+	if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
+		return r; /* No valid SSID inside scan data */
+
+	nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
+	if (nr == NULL)
+		return r;
+
+	pos = ((u8 *) (nr + 1)) + nr->ie_len;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid->SsidLength;
+	os_memcpy(pos, ssid->Ssid, ssid->SsidLength);
+	nr->ie_len += 2 + ssid->SsidLength;
+
+	return nr;
+}
+
+
+static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	NDIS_802_11_BSSID_LIST_EX *b;
+	size_t blen, count, i;
+	int len;
+	char *pos;
+	struct wpa_scan_results *results;
+	struct wpa_scan_res *r;
+
+	blen = 65535;
+	b = os_zalloc(blen);
+	if (b == NULL)
+		return NULL;
+	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
+	if (len < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
+		os_free(b);
+		return NULL;
+	}
+	count = b->NumberOfItems;
+
+	results = os_zalloc(sizeof(*results));
+	if (results == NULL) {
+		os_free(b);
+		return NULL;
+	}
+	results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
+	if (results->res == NULL) {
+		os_free(results);
+		os_free(b);
+		return NULL;
+	}
+
+	pos = (char *) &b->Bssid[0];
+	for (i = 0; i < count; i++) {
+		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
+		NDIS_802_11_FIXED_IEs *fixed;
+
+		if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) {
+			wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d",
+				   (int) bss->IELength);
+			break;
+		}
+		if (((char *) bss->IEs) + bss->IELength  > (char *) b + blen) {
+			/*
+			 * Some NDIS drivers have been reported to include an
+			 * entry with an invalid IELength in scan results and
+			 * this has crashed wpa_supplicant, so validate the
+			 * returned value before using it.
+			 */
+			wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan "
+				   "result IE (BSSID=" MACSTR ") IELength=%d",
+				   MAC2STR(bss->MacAddress),
+				   (int) bss->IELength);
+			break;
+		}
+
+		r = os_zalloc(sizeof(*r) + bss->IELength -
+			      sizeof(NDIS_802_11_FIXED_IEs));
+		if (r == NULL)
+			break;
+
+		os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN);
+		r->level = (int) bss->Rssi;
+		r->freq = bss->Configuration.DSConfig / 1000;
+		fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs;
+		r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval);
+		r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities);
+		r->tsf = WPA_GET_LE64(fixed->Timestamp);
+		os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs),
+			  bss->IELength - sizeof(NDIS_802_11_FIXED_IEs));
+		r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
+		r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid);
+
+		results->res[results->num++] = r;
+
+		pos += bss->Length;
+		if (pos > (char *) b + blen)
+			break;
+	}
+
+	os_free(b);
+
+	return results;
+}
+
+
+static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
+				      int key_idx, const u8 *addr,
+				      const u8 *bssid, int pairwise)
+{
+	NDIS_802_11_REMOVE_KEY rkey;
+	NDIS_802_11_KEY_INDEX index;
+	int res, res2;
+
+	os_memset(&rkey, 0, sizeof(rkey));
+
+	rkey.Length = sizeof(rkey);
+	rkey.KeyIndex = key_idx;
+	if (pairwise)
+		rkey.KeyIndex |= 1 << 30;
+	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
+
+	res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
+			   sizeof(rkey));
+	if (!pairwise) {
+		index = key_idx;
+		res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
+				    (char *) &index, sizeof(index));
+	} else
+		res2 = 0;
+
+	if (res < 0 && res2 < 0)
+		return -1;
+	return 0;
+}
+
+
+static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
+				   int pairwise, int key_idx, int set_tx,
+				   const u8 *key, size_t key_len)
+{
+	NDIS_802_11_WEP *wep;
+	size_t len;
+	int res;
+
+	len = 12 + key_len;
+	wep = os_zalloc(len);
+	if (wep == NULL)
+		return -1;
+	wep->Length = len;
+	wep->KeyIndex = key_idx;
+	if (set_tx)
+		wep->KeyIndex |= 1 << 31;
+#if 0 /* Setting bit30 does not seem to work with some NDIS drivers */
+	if (pairwise)
+		wep->KeyIndex |= 1 << 30;
+#endif
+	wep->KeyLength = key_len;
+	os_memcpy(wep->KeyMaterial, key, key_len);
+
+	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
+			(u8 *) wep, len);
+	res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
+
+	os_free(wep);
+
+	return res;
+}
+
+
+static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
+				   enum wpa_alg alg, const u8 *addr,
+				   int key_idx, int set_tx,
+				   const u8 *seq, size_t seq_len,
+				   const u8 *key, size_t key_len)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	size_t len, i;
+	NDIS_802_11_KEY *nkey;
+	int res, pairwise;
+	u8 bssid[ETH_ALEN];
+
+	if (addr == NULL || is_broadcast_ether_addr(addr)) {
+		/* Group Key */
+		pairwise = 0;
+		if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
+			os_memset(bssid, 0xff, ETH_ALEN);
+	} else {
+		/* Pairwise Key */
+		pairwise = 1;
+		os_memcpy(bssid, addr, ETH_ALEN);
+	}
+
+	if (alg == WPA_ALG_NONE || key_len == 0) {
+		return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid,
+						  pairwise);
+	}
+
+	if (alg == WPA_ALG_WEP) {
+		return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
+					       key, key_len);
+	}
+
+	len = 12 + 6 + 6 + 8 + key_len;
+
+	nkey = os_zalloc(len);
+	if (nkey == NULL)
+		return -1;
+
+	nkey->Length = len;
+	nkey->KeyIndex = key_idx;
+	if (set_tx)
+		nkey->KeyIndex |= 1 << 31;
+	if (pairwise)
+		nkey->KeyIndex |= 1 << 30;
+	if (seq && seq_len)
+		nkey->KeyIndex |= 1 << 29;
+	nkey->KeyLength = key_len;
+	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
+	if (seq && seq_len) {
+		for (i = 0; i < seq_len; i++)
+			nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8);
+	}
+	if (alg == WPA_ALG_TKIP && key_len == 32) {
+		os_memcpy(nkey->KeyMaterial, key, 16);
+		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
+		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
+	} else {
+		os_memcpy(nkey->KeyMaterial, key, key_len);
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
+			(u8 *) nkey, len);
+	res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
+	os_free(nkey);
+
+	return res;
+}
+
+
+static int
+wpa_driver_ndis_associate(void *priv,
+			  struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	u32 auth_mode, encr, priv_mode, mode;
+	u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	drv->mode = params->mode;
+
+	/* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
+	 * so static WEP keys needs to be set again after this. */
+	if (params->mode == IEEE80211_MODE_IBSS) {
+		mode = Ndis802_11IBSS;
+		/* Need to make sure that BSSID polling is enabled for
+		 * IBSS mode. */
+		eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
+		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
+				       drv, NULL);
+	} else
+		mode = Ndis802_11Infrastructure;
+	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
+			 (char *) &mode, sizeof(mode)) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
+			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
+			   (int) mode);
+		/* Try to continue anyway */
+	}
+
+	if (params->key_mgmt_suite == KEY_MGMT_NONE ||
+	    params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
+		/* Re-set WEP keys if static WEP configuration is used. */
+		int i;
+		for (i = 0; i < 4; i++) {
+			if (!params->wep_key[i])
+				continue;
+			wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
+				   "key %d", i);
+			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
+						bcast, i,
+						i == params->wep_tx_keyidx,
+						NULL, 0, params->wep_key[i],
+						params->wep_key_len[i]);
+		}
+	}
+
+	if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
+		if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
+			if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+				auth_mode = Ndis802_11AuthModeAutoSwitch;
+			else
+				auth_mode = Ndis802_11AuthModeShared;
+		} else
+			auth_mode = Ndis802_11AuthModeOpen;
+		priv_mode = Ndis802_11PrivFilterAcceptAll;
+	} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
+		priv_mode = Ndis802_11PrivFilter8021xWEP;
+		if (params->key_mgmt_suite == KEY_MGMT_PSK)
+			auth_mode = Ndis802_11AuthModeWPA2PSK;
+		else
+			auth_mode = Ndis802_11AuthModeWPA2;
+#ifdef CONFIG_WPS
+	} else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
+		auth_mode = Ndis802_11AuthModeOpen;
+		priv_mode = Ndis802_11PrivFilterAcceptAll;
+		if (params->wps == WPS_MODE_PRIVACY) {
+			u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
+			/*
+			 * Some NDIS drivers refuse to associate in open mode
+			 * configuration due to Privacy field mismatch, so use
+			 * a workaround to make the configuration look like
+			 * matching one for WPS provisioning.
+			 */
+			wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a "
+				   "workaround to allow driver to associate "
+				   "for WPS");
+			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
+						bcast, 0, 1,
+						NULL, 0, dummy_key,
+						sizeof(dummy_key));
+		}
+#endif /* CONFIG_WPS */
+	} else {
+		priv_mode = Ndis802_11PrivFilter8021xWEP;
+		if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+			auth_mode = Ndis802_11AuthModeWPANone;
+		else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+			auth_mode = Ndis802_11AuthModeWPAPSK;
+		else
+			auth_mode = Ndis802_11AuthModeWPA;
+	}
+
+	switch (params->pairwise_suite) {
+	case CIPHER_CCMP:
+		encr = Ndis802_11Encryption3Enabled;
+		break;
+	case CIPHER_TKIP:
+		encr = Ndis802_11Encryption2Enabled;
+		break;
+	case CIPHER_WEP40:
+	case CIPHER_WEP104:
+		encr = Ndis802_11Encryption1Enabled;
+		break;
+	case CIPHER_NONE:
+#ifdef CONFIG_WPS
+		if (params->wps == WPS_MODE_PRIVACY) {
+			encr = Ndis802_11Encryption1Enabled;
+			break;
+		}
+#endif /* CONFIG_WPS */
+		if (params->group_suite == CIPHER_CCMP)
+			encr = Ndis802_11Encryption3Enabled;
+		else if (params->group_suite == CIPHER_TKIP)
+			encr = Ndis802_11Encryption2Enabled;
+		else
+			encr = Ndis802_11EncryptionDisabled;
+		break;
+	default:
+#ifdef CONFIG_WPS
+		if (params->wps == WPS_MODE_PRIVACY) {
+			encr = Ndis802_11Encryption1Enabled;
+			break;
+		}
+#endif /* CONFIG_WPS */
+		encr = Ndis802_11EncryptionDisabled;
+		break;
+	};
+
+	if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER,
+			 (char *) &priv_mode, sizeof(priv_mode)) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
+			   "OID_802_11_PRIVACY_FILTER (%d)",
+			   (int) priv_mode);
+		/* Try to continue anyway */
+	}
+
+	ndis_set_auth_mode(drv, auth_mode);
+	ndis_set_encr_status(drv, encr);
+
+	if (params->bssid) {
+		ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid,
+			     ETH_ALEN);
+		drv->oid_bssid_set = 1;
+	} else if (drv->oid_bssid_set) {
+		ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
+			     ETH_ALEN);
+		drv->oid_bssid_set = 0;
+	}
+
+	return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
+}
+
+
+static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
+{
+	int len, count, i, ret;
+	struct ndis_pmkid_entry *entry;
+	NDIS_802_11_PMKID *p;
+
+	count = 0;
+	entry = drv->pmkid;
+	while (entry) {
+		count++;
+		if (count >= drv->no_of_pmkid)
+			break;
+		entry = entry->next;
+	}
+	len = 8 + count * sizeof(BSSID_INFO);
+	p = os_zalloc(len);
+	if (p == NULL)
+		return -1;
+
+	p->Length = len;
+	p->BSSIDInfoCount = count;
+	entry = drv->pmkid;
+	for (i = 0; i < count; i++) {
+		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
+		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
+		entry = entry->next;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len);
+	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
+	os_free(p);
+	return ret;
+}
+
+
+static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
+				     const u8 *pmkid)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	struct ndis_pmkid_entry *entry, *prev;
+
+	if (drv->no_of_pmkid == 0)
+		return 0;
+
+	prev = NULL;
+	entry = drv->pmkid;
+	while (entry) {
+		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
+			break;
+		prev = entry;
+		entry = entry->next;
+	}
+
+	if (entry) {
+		/* Replace existing entry for this BSSID and move it into the
+		 * beginning of the list. */
+		os_memcpy(entry->pmkid, pmkid, 16);
+		if (prev) {
+			prev->next = entry->next;
+			entry->next = drv->pmkid;
+			drv->pmkid = entry;
+		}
+	} else {
+		entry = os_malloc(sizeof(*entry));
+		if (entry) {
+			os_memcpy(entry->bssid, bssid, ETH_ALEN);
+			os_memcpy(entry->pmkid, pmkid, 16);
+			entry->next = drv->pmkid;
+			drv->pmkid = entry;
+		}
+	}
+
+	return wpa_driver_ndis_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
+		 			const u8 *pmkid)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	struct ndis_pmkid_entry *entry, *prev;
+
+	if (drv->no_of_pmkid == 0)
+		return 0;
+
+	entry = drv->pmkid;
+	prev = NULL;
+	while (entry) {
+		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
+		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				drv->pmkid = entry->next;
+			os_free(entry);
+			break;
+		}
+		prev = entry;
+		entry = entry->next;
+	}
+	return wpa_driver_ndis_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ndis_flush_pmkid(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	NDIS_802_11_PMKID p;
+	struct ndis_pmkid_entry *pmkid, *prev;
+	int prev_authmode, ret;
+
+	if (drv->no_of_pmkid == 0)
+		return 0;
+
+	pmkid = drv->pmkid;
+	drv->pmkid = NULL;
+	while (pmkid) {
+		prev = pmkid;
+		pmkid = pmkid->next;
+		os_free(prev);
+	}
+
+	/*
+	 * Some drivers may refuse OID_802_11_PMKID if authMode is not set to
+	 * WPA2, so change authMode temporarily, if needed.
+	 */
+	prev_authmode = ndis_get_auth_mode(drv);
+	if (prev_authmode != Ndis802_11AuthModeWPA2)
+		ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2);
+
+	os_memset(&p, 0, sizeof(p));
+	p.Length = 8;
+	p.BSSIDInfoCount = 0;
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
+		    (u8 *) &p, 8);
+	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
+
+	if (prev_authmode != Ndis802_11AuthModeWPA2)
+		ndis_set_auth_mode(drv, prev_authmode);
+
+	return ret;
+}
+
+
+static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
+{
+	char buf[512], *pos;
+	NDIS_802_11_ASSOCIATION_INFORMATION *ai;
+	int len;
+	union wpa_event_data data;
+	NDIS_802_11_BSSID_LIST_EX *b;
+	size_t blen, i;
+
+	len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
+			   sizeof(buf));
+	if (len < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: failed to get association "
+			   "information");
+		return -1;
+	}
+	if (len > sizeof(buf)) {
+		/* Some drivers seem to be producing incorrect length for this
+		 * data. Limit the length to the current buffer size to avoid
+		 * crashing in hexdump. The data seems to be otherwise valid,
+		 * so better try to use it. */
+		wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association "
+			   "information length %d", len);
+		len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION,
+				   buf, sizeof(buf));
+		if (len < -1) {
+			wpa_printf(MSG_DEBUG, "NDIS: re-reading association "
+				   "information failed");
+			return -1;
+		}
+		if (len > sizeof(buf)) {
+			wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association"
+				   " information length %d (re-read)", len);
+			len = sizeof(buf);
+		}
+	}
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: association information",
+		    (u8 *) buf, len);
+	if (len < sizeof(*ai)) {
+		wpa_printf(MSG_DEBUG, "NDIS: too short association "
+			   "information");
+		return -1;
+	}
+	ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf;
+	wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d "
+		   "off_resp=%d len_req=%d len_resp=%d",
+		   ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs,
+		   (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
+		   (int) ai->RequestIELength, (int) ai->ResponseIELength);
+
+	if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len ||
+	    ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) {
+		wpa_printf(MSG_DEBUG, "NDIS: association information - "
+			   "IE overflow");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
+		    (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength);
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
+		    (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength);
+
+	os_memset(&data, 0, sizeof(data));
+	data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs;
+	data.assoc_info.req_ies_len = ai->RequestIELength;
+	data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs;
+	data.assoc_info.resp_ies_len = ai->ResponseIELength;
+
+	blen = 65535;
+	b = os_zalloc(blen);
+	if (b == NULL)
+		goto skip_scan_results;
+	len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
+	if (len < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
+		os_free(b);
+		b = NULL;
+		goto skip_scan_results;
+	}
+	wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
+		   (unsigned int) b->NumberOfItems);
+
+	pos = (char *) &b->Bssid[0];
+	for (i = 0; i < b->NumberOfItems; i++) {
+		NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
+		if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
+		    bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
+			data.assoc_info.beacon_ies =
+				((u8 *) bss->IEs) +
+				sizeof(NDIS_802_11_FIXED_IEs);
+			data.assoc_info.beacon_ies_len =
+				bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
+			wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
+				    data.assoc_info.beacon_ies,
+				    data.assoc_info.beacon_ies_len);
+			break;
+		}
+		pos += bss->Length;
+		if (pos > (char *) b + blen)
+			break;
+	}
+
+skip_scan_results:
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+	os_free(b);
+
+	return 0;
+}
+
+
+static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_ndis_data *drv = eloop_ctx;
+	u8 bssid[ETH_ALEN];
+	int poll;
+
+	if (drv->wired)
+		return;
+
+	if (wpa_driver_ndis_get_bssid(drv, bssid)) {
+		/* Disconnected */
+		if (!is_zero_ether_addr(drv->bssid)) {
+			os_memset(drv->bssid, 0, ETH_ALEN);
+			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+		}
+	} else {
+		/* Connected */
+		if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
+			os_memcpy(drv->bssid, bssid, ETH_ALEN);
+			wpa_driver_ndis_get_associnfo(drv);
+			wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+		}
+	}
+
+	/* When using integrated NDIS event receiver, we can skip BSSID
+	 * polling when using infrastructure network. However, when using
+	 * IBSS mode, many driver do not seem to generate connection event,
+	 * so we need to enable BSSID polling to figure out when IBSS network
+	 * has been formed.
+	 */
+	poll = drv->mode == IEEE80211_MODE_IBSS;
+#ifndef CONFIG_NDIS_EVENTS_INTEGRATED
+#ifndef _WIN32_WCE
+	poll = 1;
+#endif /* _WIN32_WCE */
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+	if (poll) {
+		eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
+					drv, NULL);
+	}
+}
+
+
+static void wpa_driver_ndis_poll(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
+	wpa_driver_ndis_poll_timeout(drv, NULL);
+}
+
+
+/* Called when driver generates Media Connect Event by calling
+ * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */
+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
+{
+	wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event");
+	if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) {
+		wpa_driver_ndis_get_associnfo(drv);
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+	}
+}
+
+
+/* Called when driver generates Media Disconnect Event by calling
+ * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */
+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
+{
+	wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
+	os_memset(drv->bssid, 0, ETH_ALEN);
+	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+}
+
+
+static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
+				       const u8 *data, size_t data_len)
+{
+	NDIS_802_11_AUTHENTICATION_REQUEST *req;
+	int pairwise = 0, group = 0;
+	union wpa_event_data event;
+
+	if (data_len < sizeof(*req)) {
+		wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request "
+			   "Event (len=%d)", data_len);
+		return;
+	}
+	req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: "
+		   "Bssid " MACSTR " Flags 0x%x",
+		   MAC2STR(req->Bssid), (int) req->Flags);
+
+	if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) ==
+	    NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR)
+		pairwise = 1;
+	else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) ==
+	    NDIS_802_11_AUTH_REQUEST_GROUP_ERROR)
+		group = 1;
+
+	if (pairwise || group) {
+		os_memset(&event, 0, sizeof(event));
+		event.michael_mic_failure.unicast = pairwise;
+		wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
+				     &event);
+	}
+}
+
+
+static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
+					const u8 *data, size_t data_len)
+{
+	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
+	size_t i;
+	union wpa_event_data event;
+
+	if (data_len < 8) {
+		wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List "
+			   "Event (len=%d)", data_len);
+		return;
+	}
+	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
+	wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d "
+		   "NumCandidates %d",
+		   (int) pmkid->Version, (int) pmkid->NumCandidates);
+
+	if (pmkid->Version != 1) {
+		wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List "
+			   "Version %d", (int) pmkid->Version);
+		return;
+	}
+
+	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
+		wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow");
+		return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	for (i = 0; i < pmkid->NumCandidates; i++) {
+		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
+		wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
+			   i, MAC2STR(p->BSSID), (int) p->Flags);
+		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
+		event.pmkid_candidate.index = i;
+		event.pmkid_candidate.preauth =
+			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
+				     &event);
+	}
+}
+
+
+/* Called when driver calls NdisMIndicateStatus() with
+ * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */
+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
+					  const u8 *data, size_t data_len)
+{
+	NDIS_802_11_STATUS_INDICATION *status;
+
+	if (data == NULL || data_len < sizeof(*status))
+		return;
+
+	wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication",
+		    data, data_len);
+
+	status = (NDIS_802_11_STATUS_INDICATION *) data;
+	data += sizeof(status);
+	data_len -= sizeof(status);
+
+	switch (status->StatusType) {
+	case Ndis802_11StatusType_Authentication:
+		wpa_driver_ndis_event_auth(drv, data, data_len);
+		break;
+	case Ndis802_11StatusType_PMKID_CandidateList:
+		wpa_driver_ndis_event_pmkid(drv, data, data_len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d",
+			   (int) status->StatusType);
+		break;
+	}
+}
+
+
+/* Called when an adapter is added */
+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv)
+{
+	union wpa_event_data event;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival");
+
+	for (i = 0; i < 30; i++) {
+		/* Re-open Packet32/NDISUIO connection */
+		wpa_driver_ndis_adapter_close(drv);
+		if (wpa_driver_ndis_adapter_init(drv) < 0 ||
+		    wpa_driver_ndis_adapter_open(drv) < 0) {
+			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization "
+				   "(%d) failed", i);
+			os_sleep(1, 0);
+		} else {
+			wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized");
+			break;
+		}
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	os_strlcpy(event.interface_status.ifname, drv->ifname,
+		   sizeof(event.interface_status.ifname));
+	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+/* Called when an adapter is removed */
+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv)
+{
+	union wpa_event_data event;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal");
+	os_memset(&event, 0, sizeof(event));
+	os_strlcpy(event.interface_status.ifname, drv->ifname,
+		   sizeof(event.interface_status.ifname));
+	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static void
+wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
+{
+	wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability");
+
+	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 &&
+	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) {
+		wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported");
+		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
+	}
+
+	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 &&
+	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) {
+		wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management "
+			   "supported");
+		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+	}
+
+	if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 &&
+	    ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) {
+		wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported");
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+	}
+
+	if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 &&
+	    ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) {
+		wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported");
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+	}
+
+	if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 &&
+	    ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) {
+		wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported");
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+			WPA_DRIVER_CAPA_ENC_WEP104;
+	}
+
+	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 &&
+	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) {
+		drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
+	}
+
+	if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 &&
+	    ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) {
+		drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
+	}
+
+	ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled);
+
+	/* Could also verify OID_802_11_ADD_KEY error reporting and
+	 * support for OID_802_11_ASSOCIATION_INFORMATION. */
+
+	if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA &&
+	    drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP |
+			     WPA_DRIVER_CAPA_ENC_CCMP)) {
+		wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA");
+		drv->has_capability = 1;
+	} else {
+		wpa_printf(MSG_DEBUG, "NDIS: no WPA support found");
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
+		   "enc 0x%x auth 0x%x",
+		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
+}
+
+
+static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
+{
+	char buf[512];
+	int len;
+	size_t i;
+	NDIS_802_11_CAPABILITY *c;
+
+	drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE;
+
+	len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
+	if (len < 0) {
+		wpa_driver_ndis_get_wpa_capability(drv);
+		return;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len);
+	c = (NDIS_802_11_CAPABILITY *) buf;
+	if (len < sizeof(*c) || c->Version != 2) {
+		wpa_printf(MSG_DEBUG, "NDIS: unsupported "
+			   "OID_802_11_CAPABILITY data");
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
+		   "NoOfPMKIDs %d NoOfAuthEncrPairs %d",
+		   (int) c->NoOfPMKIDs,
+		   (int) c->NoOfAuthEncryptPairsSupported);
+	drv->has_capability = 1;
+	drv->no_of_pmkid = c->NoOfPMKIDs;
+	for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) {
+		NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
+		ae = &c->AuthenticationEncryptionSupported[i];
+		if ((char *) (ae + 1) > buf + len) {
+			wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list "
+				   "overflow");
+			break;
+		}
+		wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d",
+			   i, (int) ae->AuthModeSupported,
+			   (int) ae->EncryptStatusSupported);
+		switch (ae->AuthModeSupported) {
+		case Ndis802_11AuthModeOpen:
+			drv->capa.auth |= WPA_DRIVER_AUTH_OPEN;
+			break;
+		case Ndis802_11AuthModeShared:
+			drv->capa.auth |= WPA_DRIVER_AUTH_SHARED;
+			break;
+		case Ndis802_11AuthModeWPA:
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA;
+			break;
+		case Ndis802_11AuthModeWPAPSK:
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+			break;
+		case Ndis802_11AuthModeWPA2:
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
+			break;
+		case Ndis802_11AuthModeWPA2PSK:
+			drv->capa.key_mgmt |=
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+			break;
+		case Ndis802_11AuthModeWPANone:
+			drv->capa.key_mgmt |=
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE;
+			break;
+		default:
+			break;
+		}
+		switch (ae->EncryptStatusSupported) {
+		case Ndis802_11Encryption1Enabled:
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+			break;
+		case Ndis802_11Encryption2Enabled:
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+			break;
+		case Ndis802_11Encryption3Enabled:
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+			break;
+		default:
+			break;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x "
+		   "enc 0x%x auth 0x%x",
+		   drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth);
+}
+
+
+static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	if (!drv->has_capability)
+		return -1;
+	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	return 0;
+}
+
+
+static const char * wpa_driver_ndis_get_ifname(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	return drv->ifname;
+}
+
+
+static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+	return drv->own_addr;
+}
+
+
+#ifdef _WIN32_WCE
+
+#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512)
+
+static void ndisuio_notification_receive(void *eloop_data, void *user_ctx)
+{
+	struct wpa_driver_ndis_data *drv = eloop_data;
+	NDISUIO_DEVICE_NOTIFICATION *hdr;
+	u8 buf[NDISUIO_MSG_SIZE];
+	DWORD len, flags;
+
+	if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0,
+			  &flags)) {
+		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
+			   "ReadMsgQueue failed: %d", (int) GetLastError());
+		return;
+	}
+
+	if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) {
+		wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
+			   "Too short message (len=%d)", (int) len);
+		return;
+	}
+
+	hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf;
+	wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x",
+		   (int) len, hdr->dwNotificationType);
+
+	switch (hdr->dwNotificationType) {
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
+	case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL:
+		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL");
+		wpa_driver_ndis_event_adapter_arrival(drv);
+		break;
+#endif
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
+	case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL:
+		wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL");
+		wpa_driver_ndis_event_adapter_removal(drv);
+		break;
+#endif
+	case NDISUIO_NOTIFICATION_MEDIA_CONNECT:
+		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT");
+		SetEvent(drv->connected_event);
+		wpa_driver_ndis_event_connect(drv);
+		break;
+	case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT:
+		ResetEvent(drv->connected_event);
+		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT");
+		wpa_driver_ndis_event_disconnect(drv);
+		break;
+	case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION:
+		wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION");
+#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
+		wpa_driver_ndis_event_media_specific(
+			drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize);
+#else
+		wpa_driver_ndis_event_media_specific(
+			drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer,
+			(size_t) hdr->uiStatusBufferSize);
+#endif
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x",
+			   hdr->dwNotificationType);
+		break;
+	}
+}
+
+
+static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv)
+{
+	NDISUIO_REQUEST_NOTIFICATION req;
+
+	memset(&req, 0, sizeof(req));
+	req.hMsgQueue = drv->event_queue;
+	req.dwNotificationTypes = 0;
+
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
+			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
+		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
+			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
+			   (int) GetLastError());
+	}
+
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION,
+			     NULL, 0, NULL, 0, NULL, NULL)) {
+		wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
+			   "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d",
+			   (int) GetLastError());
+	}
+
+	if (drv->event_queue) {
+		eloop_unregister_event(drv->event_queue,
+				       sizeof(drv->event_queue));
+		CloseHandle(drv->event_queue);
+		drv->event_queue = NULL;
+	}
+
+	if (drv->connected_event) {
+		CloseHandle(drv->connected_event);
+		drv->connected_event = NULL;
+	}
+}
+
+
+static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv)
+{
+	MSGQUEUEOPTIONS opt;
+	NDISUIO_REQUEST_NOTIFICATION req;
+
+	drv->connected_event =
+		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
+	if (drv->connected_event == NULL) {
+		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+			   "CreateEvent failed: %d",
+			   (int) GetLastError());
+		return -1;
+	}
+
+	memset(&opt, 0, sizeof(opt));
+	opt.dwSize = sizeof(opt);
+	opt.dwMaxMessages = 5;
+	opt.cbMaxMessage = NDISUIO_MSG_SIZE;
+	opt.bReadAccess = TRUE;
+
+	drv->event_queue = CreateMsgQueue(NULL, &opt);
+	if (drv->event_queue == NULL) {
+		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+			   "CreateMsgQueue failed: %d",
+			   (int) GetLastError());
+		ndisuio_notification_deinit(drv);
+		return -1;
+	}
+
+	memset(&req, 0, sizeof(req));
+	req.hMsgQueue = drv->event_queue;
+	req.dwNotificationTypes =
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
+		NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL |
+#endif
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
+		NDISUIO_NOTIFICATION_ADAPTER_REMOVAL |
+#endif
+		NDISUIO_NOTIFICATION_MEDIA_CONNECT |
+		NDISUIO_NOTIFICATION_MEDIA_DISCONNECT |
+		NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION;
+
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
+			     &req, sizeof(req), NULL, 0, NULL, NULL)) {
+		wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+			   "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
+			   (int) GetLastError());
+		ndisuio_notification_deinit(drv);
+		return -1;
+	}
+
+	eloop_register_event(drv->event_queue, sizeof(drv->event_queue),
+			     ndisuio_notification_receive, drv, NULL);
+
+	return 0;
+}
+#endif /* _WIN32_WCE */
+
+
+static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+	NDISUIO_QUERY_BINDING *b;
+	size_t blen = sizeof(*b) + 1024;
+	int i, error, found = 0;
+	DWORD written;
+	char name[256], desc[256], *dpos;
+	WCHAR *pos;
+	size_t j, len, dlen;
+
+	b = os_malloc(blen);
+	if (b == NULL)
+		return -1;
+
+	for (i = 0; ; i++) {
+		os_memset(b, 0, blen);
+		b->BindingIndex = i;
+		if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
+				     &written, NULL)) {
+			error = (int) GetLastError();
+			if (error == ERROR_NO_MORE_ITEMS)
+				break;
+			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
+				   "failed: %d", error);
+			break;
+		}
+
+		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+		len = b->DeviceNameLength;
+		if (len >= sizeof(name))
+			len = sizeof(name) - 1;
+		for (j = 0; j < len; j++)
+			name[j] = (char) pos[j];
+		name[len] = '\0';
+
+		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+		len = b->DeviceDescrLength;
+		if (len >= sizeof(desc))
+			len = sizeof(desc) - 1;
+		for (j = 0; j < len; j++)
+			desc[j] = (char) pos[j];
+		desc[len] = '\0';
+
+		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
+
+		if (os_strstr(name, drv->ifname)) {
+			wpa_printf(MSG_DEBUG, "NDIS: Interface name match");
+			found = 1;
+			break;
+		}
+
+		if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "NDIS: Interface description "
+				   "match");
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
+			   drv->ifname);
+		os_free(b);
+		return -1;
+	}
+
+	os_strlcpy(drv->ifname,
+		   os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name,
+		   sizeof(drv->ifname));
+#ifdef _WIN32_WCE
+	drv->adapter_name = wpa_strdup_tchar(drv->ifname);
+	if (drv->adapter_name == NULL) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for "
+			   "adapter name");
+		os_free(b);
+		return -1;
+	}
+#endif /* _WIN32_WCE */
+
+	dpos = os_strstr(desc, " - ");
+	if (dpos)
+		dlen = dpos - desc;
+	else
+		dlen = os_strlen(desc);
+	drv->adapter_desc = os_malloc(dlen + 1);
+	if (drv->adapter_desc) {
+		os_memcpy(drv->adapter_desc, desc, dlen);
+		drv->adapter_desc[dlen] = '\0';
+	}
+
+	os_free(b);
+
+	if (drv->adapter_desc == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
+		   drv->adapter_desc);
+
+	return 0;
+#else /* CONFIG_USE_NDISUIO */
+	PTSTR _names;
+	char *names, *pos, *pos2;
+	ULONG len;
+	BOOLEAN res;
+#define MAX_ADAPTERS 32
+	char *name[MAX_ADAPTERS];
+	char *desc[MAX_ADAPTERS];
+	int num_name, num_desc, i, found_name, found_desc;
+	size_t dlen;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
+		   PacketGetVersion());
+
+	len = 8192;
+	_names = os_zalloc(len);
+	if (_names == NULL)
+		return -1;
+
+	res = PacketGetAdapterNames(_names, &len);
+	if (!res && len > 8192) {
+		os_free(_names);
+		_names = os_zalloc(len);
+		if (_names == NULL)
+			return -1;
+		res = PacketGetAdapterNames(_names, &len);
+	}
+
+	if (!res) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
+			   "(PacketGetAdapterNames)");
+		os_free(_names);
+		return -1;
+	}
+
+	names = (char *) _names;
+	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
+		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
+			   "UNICODE");
+		/* Convert to ASCII */
+		pos2 = pos = names;
+		while (pos2 < names + len) {
+			if (pos2[0] == '\0' && pos2[1] == '\0' &&
+			    pos2[2] == '\0' && pos2[3] == '\0') {
+				pos2 += 4;
+				break;
+			}
+			*pos++ = pos2[0];
+			pos2 += 2;
+		}
+		os_memcpy(pos + 2, names, pos - names);
+		pos += 2;
+	} else
+		pos = names;
+
+	num_name = 0;
+	while (pos < names + len) {
+		name[num_name] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return -1;
+		}
+		pos++;
+		num_name++;
+		if (num_name >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
+			os_free(names);
+			return -1;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
+				   num_name);
+			pos++;
+			break;
+		}
+	}
+
+	num_desc = 0;
+	while (pos < names + len) {
+		desc[num_desc] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return -1;
+		}
+		pos++;
+		num_desc++;
+		if (num_desc >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
+				   "descriptions");
+			os_free(names);
+			return -1;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
+				   "found", num_name);
+			pos++;
+			break;
+		}
+	}
+
+	/*
+	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
+	 * descriptions. Fill in dummy descriptors to work around this.
+	 */
+	while (num_desc < num_name)
+		desc[num_desc++] = "dummy description";
+
+	if (num_name != num_desc) {
+		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
+			   "description counts (%d != %d)",
+			   num_name, num_desc);
+		os_free(names);
+		return -1;
+	}
+
+	found_name = found_desc = -1;
+	for (i = 0; i < num_name; i++) {
+		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
+			   i, name[i], desc[i]);
+		if (found_name == -1 && os_strstr(name[i], drv->ifname))
+			found_name = i;
+		if (found_desc == -1 &&
+		    os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) ==
+		    0)
+			found_desc = i;
+	}
+
+	if (found_name < 0 && found_desc >= 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on "
+			   "description '%s'",
+			   name[found_desc], desc[found_desc]);
+		found_name = found_desc;
+		os_strlcpy(drv->ifname,
+			   os_strncmp(name[found_desc], "\\Device\\NPF_", 12)
+			   == 0 ? name[found_desc] + 12 : name[found_desc],
+			   sizeof(drv->ifname));
+	}
+
+	if (found_name < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
+			   drv->ifname);
+		os_free(names);
+		return -1;
+	}
+
+	i = found_name;
+	pos = os_strrchr(desc[i], '(');
+	if (pos) {
+		dlen = pos - desc[i];
+		pos--;
+		if (pos > desc[i] && *pos == ' ')
+			dlen--;
+	} else {
+		dlen = os_strlen(desc[i]);
+	}
+	drv->adapter_desc = os_malloc(dlen + 1);
+	if (drv->adapter_desc) {
+		os_memcpy(drv->adapter_desc, desc[i], dlen);
+		drv->adapter_desc[dlen] = '\0';
+	}
+
+	os_free(names);
+
+	if (drv->adapter_desc == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
+		   drv->adapter_desc);
+
+	return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__)
+#ifndef _WIN32_WCE
+/*
+ * These structures are undocumented for WinXP; only WinCE version is
+ * documented. These would be included wzcsapi.h if it were available. Some
+ * changes here have been needed to make the structures match with WinXP SP2.
+ * It is unclear whether these work with any other version.
+ */
+
+typedef struct {
+	LPWSTR wszGuid;
+} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY;
+
+typedef struct {
+	DWORD dwNumIntfs;
+	PINTF_KEY_ENTRY pIntfs;
+} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE;
+
+typedef struct {
+	DWORD dwDataLen;
+	LPBYTE pData;
+} RAW_DATA, *PRAW_DATA;
+
+typedef struct {
+	LPWSTR wszGuid;
+	LPWSTR wszDescr;
+	ULONG ulMediaState;
+	ULONG ulMediaType;
+	ULONG ulPhysicalMediaType;
+	INT nInfraMode;
+	INT nAuthMode;
+	INT nWepStatus;
+#ifndef _WIN32_WCE
+	u8 pad[2]; /* why is this needed? */
+#endif /* _WIN32_WCE */
+	DWORD dwCtlFlags;
+	DWORD dwCapabilities; /* something added for WinXP SP2(?) */
+	RAW_DATA rdSSID;
+	RAW_DATA rdBSSID;
+	RAW_DATA rdBSSIDList;
+	RAW_DATA rdStSSIDList;
+	RAW_DATA rdCtrlData;
+#ifdef UNDER_CE
+	BOOL bInitialized;
+#endif
+	DWORD nWPAMCastCipher;
+	/* add some extra buffer for later additions since this interface is
+	 * far from stable */
+	u8 later_additions[100];
+} INTF_ENTRY, *PINTF_ENTRY;
+
+#define INTF_ALL 0xffffffff
+#define INTF_ALL_FLAGS 0x0000ffff
+#define INTF_CTLFLAGS 0x00000010
+#define INTFCTL_ENABLED 0x8000
+#endif /* _WIN32_WCE */
+
+
+#ifdef _WIN32_WCE
+static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv)
+{
+	HANDLE ndis;
+	TCHAR multi[100];
+	int len;
+
+	len = _tcslen(drv->adapter_name);
+	if (len > 80)
+		return -1;
+
+	ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
+			  0, NULL, OPEN_EXISTING, 0, NULL);
+	if (ndis == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS "
+			   "device: %d", (int) GetLastError());
+		return -1;
+	}
+
+	len++;
+	memcpy(multi, drv->adapter_name, len * sizeof(TCHAR));
+	memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR));
+	len += 9;
+
+	if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER,
+			     multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL))
+	{
+		wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER "
+			   "failed: 0x%x", (int) GetLastError());
+		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz",
+				  (u8 *) multi, len * sizeof(TCHAR));
+		CloseHandle(ndis);
+		return -1;
+	}
+
+	CloseHandle(ndis);
+
+	wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO "
+		   "protocol");
+
+	return 0;
+}
+#endif /* _WIN32_WCE */
+
+
+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
+				   int enable)
+{
+#ifdef _WIN32_WCE
+	HKEY hk, hk2;
+	LONG ret;
+	DWORD i, hnd, len;
+	TCHAR keyname[256], devname[256];
+
+#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig")
+
+	if (enable) {
+		HANDLE h;
+		h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL);
+		if (h == INVALID_HANDLE_VALUE || h == 0) {
+			wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC "
+				   "- ActivateDeviceEx failed: %d",
+				   (int) GetLastError());
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled");
+		return wpa_driver_ndis_rebind_adapter(drv);
+	}
+
+	/*
+	 * Unfortunately, just disabling the WZC for an interface is not enough
+	 * to free NDISUIO for us, so need to disable and unload WZC completely
+	 * for now when using WinCE with NDISUIO. In addition, must request
+	 * NDISUIO protocol to be rebound to the adapter in order to free the
+	 * NDISUIO binding that WZC hold before us.
+	 */
+
+	/* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */
+	ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) "
+			   "failed: %d %d", (int) ret, (int) GetLastError());
+		return -1;
+	}
+
+	for (i = 0; ; i++) {
+		len = sizeof(keyname);
+		ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL,
+				   NULL);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Could not find active "
+				   "WZC - assuming it is not running.");
+			RegCloseKey(hk);
+			return -1;
+		}
+
+		ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) "
+				   "failed: %d %d",
+				   (int) ret, (int) GetLastError());
+			continue;
+		}
+
+		len = sizeof(devname);
+		ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL,
+				      (LPBYTE) devname, &len);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx("
+				   "DEVKEY_VALNAME) failed: %d %d",
+				   (int) ret, (int) GetLastError());
+			RegCloseKey(hk2);
+			continue;
+		}
+
+		if (_tcscmp(devname, WZC_DRIVER) == 0)
+			break;
+
+		RegCloseKey(hk2);
+	}
+
+	RegCloseKey(hk);
+
+	/* Found WZC - get handle to it. */
+	len = sizeof(hnd);
+	ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL,
+			      (PUCHAR) &hnd, &len);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) "
+			   "failed: %d %d", (int) ret, (int) GetLastError());
+		RegCloseKey(hk2);
+		return -1;
+	}
+
+	RegCloseKey(hk2);
+
+	/* Deactivate WZC */
+	if (!DeactivateDevice((HANDLE) hnd)) {
+		wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d",
+			   (int) GetLastError());
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily");
+	drv->wzc_disabled = 1;
+	return wpa_driver_ndis_rebind_adapter(drv);
+
+#else /* _WIN32_WCE */
+
+	HMODULE hm;
+	DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr,
+					PINTFS_KEY_TABLE pIntfs);
+	DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
+					 PINTF_ENTRY pIntf,
+					 LPDWORD pdwOutFlags);
+	DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
+				       PINTF_ENTRY pIntf, LPDWORD pdwOutFlags);
+	int ret = -1, j;
+	DWORD res;
+	INTFS_KEY_TABLE guids;
+	INTF_ENTRY intf;
+	char guid[128];
+	WCHAR *pos;
+	DWORD flags, i;
+
+	hm = LoadLibrary(TEXT("wzcsapi.dll"));
+	if (hm == NULL) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) "
+			   "- WZC probably not running",
+			   (unsigned int) GetLastError());
+		return -1;
+	}
+
+#ifdef _WIN32_WCE
+	wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces");
+	wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface");
+	wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface");
+#else /* _WIN32_WCE */
+	wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces");
+	wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface");
+	wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface");
+#endif /* _WIN32_WCE */
+
+	if (wzc_enum_interf == NULL || wzc_query_interf == NULL ||
+	    wzc_set_interf == NULL) {
+		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, "
+			   "WZCQueryInterface, or WZCSetInterface not found "
+			   "in wzcsapi.dll");
+		goto fail;
+	}
+
+	os_memset(&guids, 0, sizeof(guids));
+	res = wzc_enum_interf(NULL, &guids);
+	if (res != 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; "
+			   "WZC service is apparently not running",
+			   (int) res);
+		goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces",
+		   (int) guids.dwNumIntfs);
+
+	for (i = 0; i < guids.dwNumIntfs; i++) {
+		pos = guids.pIntfs[i].wszGuid;
+		for (j = 0; j < sizeof(guid); j++) {
+			guid[j] = (char) *pos;
+			if (*pos == 0)
+				break;
+			pos++;
+		}
+		guid[sizeof(guid) - 1] = '\0';
+		wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'",
+			   (int) i, guid);
+		if (os_strstr(drv->ifname, guid) == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "NDIS: Current interface found from "
+			   "WZC");
+		break;
+	}
+
+	if (i >= guids.dwNumIntfs) {
+		wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from "
+			   "WZC");
+		goto fail;
+	}
+
+	os_memset(&intf, 0, sizeof(intf));
+	intf.wszGuid = guids.pIntfs[i].wszGuid;
+	/* Set flags to verify that the structure has not changed. */
+	intf.dwCtlFlags = -1;
+	flags = 0;
+	res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags);
+	if (res != 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the "
+			   "WZC interface: %d (0x%x)",
+			   (int) res, (int) res);
+		wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+			   (unsigned int) GetLastError());
+		goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x",
+		   (int) flags, (int) intf.dwCtlFlags);
+
+	if (intf.dwCtlFlags == -1) {
+		wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed "
+			   "again - could not disable WZC");
+		wpa_hexdump(MSG_MSGDUMP, "NDIS: intf",
+			    (u8 *) &intf, sizeof(intf));
+		goto fail;
+	}
+
+	if (enable) {
+		if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) {
+			wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this "
+				   "interface");
+			intf.dwCtlFlags |= INTFCTL_ENABLED;
+			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
+					     &flags);
+			if (res != 0) {
+				wpa_printf(MSG_DEBUG, "NDIS: Failed to enable "
+					   "WZC: %d (0x%x)",
+					   (int) res, (int) res);
+				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+					   (unsigned int) GetLastError());
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this "
+				   "interface");
+			drv->wzc_disabled = 0;
+		}
+	} else {
+		if (intf.dwCtlFlags & INTFCTL_ENABLED) {
+			wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this "
+				   "interface");
+			intf.dwCtlFlags &= ~INTFCTL_ENABLED;
+			res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
+					     &flags);
+			if (res != 0) {
+				wpa_printf(MSG_DEBUG, "NDIS: Failed to "
+					   "disable WZC: %d (0x%x)",
+					   (int) res, (int) res);
+				wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+					   (unsigned int) GetLastError());
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily "
+				   "for this interface");
+			drv->wzc_disabled = 1;
+		} else {
+			wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for "
+				   "this interface");
+		}
+	}
+
+	ret = 0;
+
+fail:
+	FreeLibrary(hm);
+
+	return ret;
+#endif /* _WIN32_WCE */
+}
+
+#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
+
+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
+				   int enable)
+{
+	return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
+
+
+#ifdef CONFIG_USE_NDISUIO
+/*
+ * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able
+ * to export this handle. This is somewhat ugly, but there is no better
+ * mechanism available to pass data from driver interface to l2_packet wrapper.
+ */
+static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
+
+HANDLE driver_ndis_get_ndisuio_handle(void)
+{
+	return driver_ndis_ndisuio_handle;
+}
+#endif /* CONFIG_USE_NDISUIO */
+
+
+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+#ifndef _WIN32_WCE
+#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio")
+	DWORD written;
+#endif /* _WIN32_WCE */
+	drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
+				  GENERIC_READ | GENERIC_WRITE, 0, NULL,
+				  OPEN_EXISTING,
+				  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+				  INVALID_HANDLE_VALUE);
+	if (drv->ndisuio == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
+			   "NDISUIO: %d", (int) GetLastError());
+		return -1;
+	}
+	driver_ndis_ndisuio_handle = drv->ndisuio;
+
+#ifndef _WIN32_WCE
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
+			     NULL, 0, &written, NULL)) {
+		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
+			   "%d", (int) GetLastError());
+		CloseHandle(drv->ndisuio);
+		drv->ndisuio = INVALID_HANDLE_VALUE;
+		return -1;
+	}
+#endif /* _WIN32_WCE */
+
+	return 0;
+#else /* CONFIG_USE_NDISUIO */
+	return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+	DWORD written;
+#define MAX_NDIS_DEVICE_NAME_LEN 256
+	WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN];
+	size_t len, i, pos;
+	const char *prefix = "\\DEVICE\\";
+
+#ifdef _WIN32_WCE
+	pos = 0;
+#else /* _WIN32_WCE */
+	pos = 8;
+#endif /* _WIN32_WCE */
+	len = pos + os_strlen(drv->ifname);
+	if (len >= MAX_NDIS_DEVICE_NAME_LEN)
+		return -1;
+	for (i = 0; i < pos; i++)
+		ifname[i] = (WCHAR) prefix[i];
+	for (i = pos; i < len; i++)
+		ifname[i] = (WCHAR) drv->ifname[i - pos];
+	ifname[i] = L'\0';
+
+	if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE,
+			     ifname, len * sizeof(WCHAR), NULL, 0, &written,
+			     NULL)) {
+		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE "
+			   "failed: %d", (int) GetLastError());
+		wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname",
+				  (const u8 *) ifname, len * sizeof(WCHAR));
+		CloseHandle(drv->ndisuio);
+		drv->ndisuio = INVALID_HANDLE_VALUE;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully");
+
+	return 0;
+#else /* CONFIG_USE_NDISUIO */
+	char ifname[128];
+	os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname);
+	drv->adapter = PacketOpenAdapter(ifname);
+	if (drv->adapter == NULL) {
+		wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
+			   "'%s'", ifname);
+		return -1;
+	}
+	return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+	driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
+	if (drv->ndisuio != INVALID_HANDLE_VALUE)
+		CloseHandle(drv->ndisuio);
+#else /* CONFIG_USE_NDISUIO */
+	if (drv->adapter)
+		PacketCloseAdapter(drv->adapter);
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
+{
+	if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
+			 (const char *) pae_group_addr, ETH_ALEN) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
+			   "to the multicast list");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_ndis_data *drv;
+	u32 mode;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	/*
+	 * Compatibility code to strip possible prefix from the GUID. Previous
+	 * versions include \Device\NPF_ prefix for all names, but the internal
+	 * interface name is now only the GUI. Both Packet32 and NDISUIO
+	 * prefixes are supported.
+	 */
+	if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
+		ifname += 12;
+	else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0)
+		ifname += 8;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	if (wpa_driver_ndis_adapter_init(drv) < 0) {
+		os_free(drv);
+		return NULL;
+	}
+
+	if (wpa_driver_ndis_get_names(drv) < 0) {
+		wpa_driver_ndis_adapter_close(drv);
+		os_free(drv);
+		return NULL;
+	}
+
+	wpa_driver_ndis_set_wzc(drv, 0);
+
+	if (wpa_driver_ndis_adapter_open(drv) < 0) {
+		wpa_driver_ndis_adapter_close(drv);
+		os_free(drv);
+		return NULL;
+	}
+
+	if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
+			 (char *) drv->own_addr, ETH_ALEN) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
+			   "failed");
+		wpa_driver_ndis_adapter_close(drv);
+		os_free(drv);
+		return NULL;
+	}
+	wpa_driver_ndis_get_capability(drv);
+
+	/* Make sure that the driver does not have any obsolete PMKID entries.
+	 */
+	wpa_driver_ndis_flush_pmkid(drv);
+
+	/*
+	 * Disconnect to make sure that driver re-associates if it was
+	 * connected.
+	 */
+	wpa_driver_ndis_disconnect(drv);
+
+	eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
+
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+	drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail,
+				       drv->ifname, drv->adapter_desc);
+	if (drv->events == NULL) {
+		wpa_driver_ndis_deinit(drv);
+		return NULL;
+	}
+	eloop_register_event(drv->event_avail, sizeof(drv->event_avail),
+			     wpa_driver_ndis_event_pipe_cb, drv, NULL);
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+#ifdef _WIN32_WCE
+	if (ndisuio_notification_init(drv) < 0) {
+		wpa_driver_ndis_deinit(drv);
+		return NULL;
+	}
+#endif /* _WIN32_WCE */
+
+	/* Set mode here in case card was configured for ad-hoc mode
+	 * previously. */
+	mode = Ndis802_11Infrastructure;
+	if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
+			 (char *) &mode, sizeof(mode)) < 0) {
+		char buf[8];
+		int res;
+		wpa_printf(MSG_DEBUG, "NDIS: Failed to set "
+			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
+			   (int) mode);
+		/* Try to continue anyway */
+
+		res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf,
+				   sizeof(buf));
+		if (res > 0) {
+			wpa_printf(MSG_INFO, "NDIS: The driver seems to use "
+				   "Native 802.11 OIDs. These are not yet "
+				   "fully supported.");
+			drv->native80211 = 1;
+		} else if (!drv->has_capability || drv->capa.enc == 0) {
+			/*
+			 * Note: This will also happen with NDIS 6 drivers with
+			 * Vista.
+			 */
+			wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
+				   "any wireless capabilities - assume it is "
+				   "a wired interface");
+			drv->wired = 1;
+			drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED;
+			drv->has_capability = 1;
+			ndis_add_multicast(drv);
+		}
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_ndis_deinit(void *priv)
+{
+	struct wpa_driver_ndis_data *drv = priv;
+
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+	if (drv->events) {
+		eloop_unregister_event(drv->event_avail,
+				       sizeof(drv->event_avail));
+		ndis_events_deinit(drv->events);
+	}
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+#ifdef _WIN32_WCE
+	ndisuio_notification_deinit(drv);
+#endif /* _WIN32_WCE */
+
+	eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
+	eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
+	wpa_driver_ndis_flush_pmkid(drv);
+	wpa_driver_ndis_disconnect(drv);
+	if (wpa_driver_ndis_radio_off(drv) < 0) {
+		wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
+			   "radio off");
+	}
+
+	wpa_driver_ndis_adapter_close(drv);
+
+	if (drv->wzc_disabled)
+		wpa_driver_ndis_set_wzc(drv, 1);
+
+#ifdef _WIN32_WCE
+	os_free(drv->adapter_name);
+#endif /* _WIN32_WCE */
+	os_free(drv->adapter_desc);
+	os_free(drv);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_ndis_get_interfaces(void *global_priv)
+{
+	struct wpa_interface_info *iface = NULL, *niface;
+
+#ifdef CONFIG_USE_NDISUIO
+	NDISUIO_QUERY_BINDING *b;
+	size_t blen = sizeof(*b) + 1024;
+	int i, error;
+	DWORD written;
+	char name[256], desc[256];
+	WCHAR *pos;
+	size_t j, len;
+	HANDLE ndisuio;
+
+	ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
+			     GENERIC_READ | GENERIC_WRITE, 0, NULL,
+			     OPEN_EXISTING,
+			     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+			     INVALID_HANDLE_VALUE);
+	if (ndisuio == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
+			   "NDISUIO: %d", (int) GetLastError());
+		return NULL;
+	}
+
+#ifndef _WIN32_WCE
+	if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
+			     NULL, 0, &written, NULL)) {
+		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
+			   "%d", (int) GetLastError());
+		CloseHandle(ndisuio);
+		return NULL;
+	}
+#endif /* _WIN32_WCE */
+
+	b = os_malloc(blen);
+	if (b == NULL) {
+		CloseHandle(ndisuio);
+		return NULL;
+	}
+
+	for (i = 0; ; i++) {
+		os_memset(b, 0, blen);
+		b->BindingIndex = i;
+		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
+				     &written, NULL)) {
+			error = (int) GetLastError();
+			if (error == ERROR_NO_MORE_ITEMS)
+				break;
+			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
+				   "failed: %d", error);
+			break;
+		}
+
+		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+		len = b->DeviceNameLength;
+		if (len >= sizeof(name))
+			len = sizeof(name) - 1;
+		for (j = 0; j < len; j++)
+			name[j] = (char) pos[j];
+		name[len] = '\0';
+
+		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+		len = b->DeviceDescrLength;
+		if (len >= sizeof(desc))
+			len = sizeof(desc) - 1;
+		for (j = 0; j < len; j++)
+			desc[j] = (char) pos[j];
+		desc[len] = '\0';
+
+		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
+
+		niface = os_zalloc(sizeof(*niface));
+		if (niface == NULL)
+			break;
+		niface->drv_name = "ndis";
+		if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
+			niface->ifname = os_strdup(name + 8);
+		else
+			niface->ifname = os_strdup(name);
+		if (niface->ifname == NULL) {
+			os_free(niface);
+			break;
+		}
+		niface->desc = os_strdup(desc);
+		niface->next = iface;
+		iface = niface;
+	}
+
+	os_free(b);
+	CloseHandle(ndisuio);
+#else /* CONFIG_USE_NDISUIO */
+	PTSTR _names;
+	char *names, *pos, *pos2;
+	ULONG len;
+	BOOLEAN res;
+	char *name[MAX_ADAPTERS];
+	char *desc[MAX_ADAPTERS];
+	int num_name, num_desc, i;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
+		   PacketGetVersion());
+
+	len = 8192;
+	_names = os_zalloc(len);
+	if (_names == NULL)
+		return NULL;
+
+	res = PacketGetAdapterNames(_names, &len);
+	if (!res && len > 8192) {
+		os_free(_names);
+		_names = os_zalloc(len);
+		if (_names == NULL)
+			return NULL;
+		res = PacketGetAdapterNames(_names, &len);
+	}
+
+	if (!res) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
+			   "(PacketGetAdapterNames)");
+		os_free(_names);
+		return NULL;
+	}
+
+	names = (char *) _names;
+	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
+		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
+			   "UNICODE");
+		/* Convert to ASCII */
+		pos2 = pos = names;
+		while (pos2 < names + len) {
+			if (pos2[0] == '\0' && pos2[1] == '\0' &&
+			    pos2[2] == '\0' && pos2[3] == '\0') {
+				pos2 += 4;
+				break;
+			}
+			*pos++ = pos2[0];
+			pos2 += 2;
+		}
+		os_memcpy(pos + 2, names, pos - names);
+		pos += 2;
+	} else
+		pos = names;
+
+	num_name = 0;
+	while (pos < names + len) {
+		name[num_name] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return NULL;
+		}
+		pos++;
+		num_name++;
+		if (num_name >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
+			os_free(names);
+			return NULL;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
+				   num_name);
+			pos++;
+			break;
+		}
+	}
+
+	num_desc = 0;
+	while (pos < names + len) {
+		desc[num_desc] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return NULL;
+		}
+		pos++;
+		num_desc++;
+		if (num_desc >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
+				   "descriptions");
+			os_free(names);
+			return NULL;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
+				   "found", num_name);
+			pos++;
+			break;
+		}
+	}
+
+	/*
+	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
+	 * descriptions. Fill in dummy descriptors to work around this.
+	 */
+	while (num_desc < num_name)
+		desc[num_desc++] = "dummy description";
+
+	if (num_name != num_desc) {
+		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
+			   "description counts (%d != %d)",
+			   num_name, num_desc);
+		os_free(names);
+		return NULL;
+	}
+
+	for (i = 0; i < num_name; i++) {
+		niface = os_zalloc(sizeof(*niface));
+		if (niface == NULL)
+			break;
+		niface->drv_name = "ndis";
+		if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
+			niface->ifname = os_strdup(name[i] + 12);
+		else
+			niface->ifname = os_strdup(name[i]);
+		if (niface->ifname == NULL) {
+			os_free(niface);
+			break;
+		}
+		niface->desc = os_strdup(desc[i]);
+		niface->next = iface;
+		iface = niface;
+	}
+
+#endif /* CONFIG_USE_NDISUIO */
+
+	return iface;
+}
+
+
+static const char *ndis_drv_name = "ndis";
+static const char *ndis_drv_desc = "Windows NDIS driver";
+
+struct wpa_driver_ops wpa_driver_ndis_ops;
+
+void driver_ndis_init_ops(void)
+{
+	os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
+	wpa_driver_ndis_ops.name = ndis_drv_name;
+	wpa_driver_ndis_ops.desc = ndis_drv_desc;
+	wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
+	wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
+	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+	wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
+	wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
+	wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
+	wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
+	wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
+	wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
+	wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
+	wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
+	wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
+	wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
+	wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
+	wpa_driver_ndis_ops.get_scan_results2 =
+		wpa_driver_ndis_get_scan_results;
+	wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
+	wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
+}

Deleted: vendor/wpa/2.0/src/drivers/driver_ndis.h
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ndis.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ndis.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,65 +0,0 @@
-/*
- * WPA Supplicant - Windows/NDIS driver interface
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DRIVER_NDIS_H
-#define DRIVER_NDIS_H
-
-#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-struct ndis_events_data;
-struct ndis_events_data * ndis_events_init(HANDLE *read_pipe, HANDLE *event,
-					   const char *ifname,
-					   const char *desc);
-void ndis_events_deinit(struct ndis_events_data *events);
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-
-struct ndis_pmkid_entry {
-	struct ndis_pmkid_entry *next;
-	u8 bssid[ETH_ALEN];
-	u8 pmkid[16];
-};
-
-struct wpa_driver_ndis_data {
-	void *ctx;
-	char ifname[100]; /* GUID: {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D} */
-#ifdef _WIN32_WCE
-	TCHAR *adapter_name;
-	HANDLE event_queue; /* NDISUIO notifier MsgQueue */
-	HANDLE connected_event; /* WpaSupplicantConnected event */
-#endif /* _WIN32_WCE */
-	u8 own_addr[ETH_ALEN];
-#ifdef CONFIG_USE_NDISUIO
-	HANDLE ndisuio;
-#else /* CONFIG_USE_NDISUIO */
-	LPADAPTER adapter;
-#endif /* CONFIG_USE_NDISUIO */
-	u8 bssid[ETH_ALEN];
-
-	int has_capability;
-	int no_of_pmkid;
-	int radio_enabled;
-	struct wpa_driver_capa capa;
-	struct ndis_pmkid_entry *pmkid;
-	char *adapter_desc;
-	int wired;
-	int native80211;
-	int mode;
-	int wzc_disabled;
-	int oid_bssid_set;
-#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-	HANDLE events_pipe, event_avail;
-	struct ndis_events_data *events;
-#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
-};
-
-#endif /* DRIVER_NDIS_H */

Copied: vendor/wpa/2.0/src/drivers/driver_ndis.h (from rev 9639, vendor/wpa/dist/src/drivers/driver_ndis.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_ndis.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_ndis.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_NDIS_H
+#define DRIVER_NDIS_H
+
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+struct ndis_events_data;
+struct ndis_events_data * ndis_events_init(HANDLE *read_pipe, HANDLE *event,
+					   const char *ifname,
+					   const char *desc);
+void ndis_events_deinit(struct ndis_events_data *events);
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+struct ndis_pmkid_entry {
+	struct ndis_pmkid_entry *next;
+	u8 bssid[ETH_ALEN];
+	u8 pmkid[16];
+};
+
+struct wpa_driver_ndis_data {
+	void *ctx;
+	char ifname[100]; /* GUID: {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D} */
+#ifdef _WIN32_WCE
+	TCHAR *adapter_name;
+	HANDLE event_queue; /* NDISUIO notifier MsgQueue */
+	HANDLE connected_event; /* WpaSupplicantConnected event */
+#endif /* _WIN32_WCE */
+	u8 own_addr[ETH_ALEN];
+#ifdef CONFIG_USE_NDISUIO
+	HANDLE ndisuio;
+#else /* CONFIG_USE_NDISUIO */
+	LPADAPTER adapter;
+#endif /* CONFIG_USE_NDISUIO */
+	u8 bssid[ETH_ALEN];
+
+	int has_capability;
+	int no_of_pmkid;
+	int radio_enabled;
+	struct wpa_driver_capa capa;
+	struct ndis_pmkid_entry *pmkid;
+	char *adapter_desc;
+	int wired;
+	int native80211;
+	int mode;
+	int wzc_disabled;
+	int oid_bssid_set;
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+	HANDLE events_pipe, event_avail;
+	struct ndis_events_data *events;
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+};
+
+#endif /* DRIVER_NDIS_H */

Deleted: vendor/wpa/2.0/src/drivers/driver_ndis_.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ndis_.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ndis_.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,105 +0,0 @@
-/*
- * WPA Supplicant - Windows/NDIS driver interface - event processing
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-
-/* Keep this event processing in a separate file and without WinPcap headers to
- * avoid conflicts with some of the header files. */
-struct _ADAPTER;
-typedef struct _ADAPTER * LPADAPTER;
-#include "driver_ndis.h"
-
-
-void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv);
-void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv);
-void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
-					  const u8 *data, size_t data_len);
-void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv);
-void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv);
-
-
-enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
-		   EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
-		   EVENT_ADAPTER_REMOVAL };
-
-/* Event data:
- * enum event_types (as int, i.e., 4 octets)
- * data length (2 octets (big endian), optional)
- * data (variable len, optional)
- */
-
-
-static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv,
-					  u8 *buf, size_t len)
-{
-	u8 *pos, *data = NULL;
-	enum event_types type;
-	size_t data_len = 0;
-
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len);
-	if (len < sizeof(int))
-		return;
-	type = *((int *) buf);
-	pos = buf + sizeof(int);
-	wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type);
-
-	if (buf + len - pos > 2) {
-		data_len = (int) *pos++ << 8;
-		data_len += *pos++;
-		if (data_len > (size_t) (buf + len - pos)) {
-			wpa_printf(MSG_DEBUG, "NDIS: event data overflow");
-			return;
-		}
-		data = pos;
-		wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len);
-	}
-
-	switch (type) {
-	case EVENT_CONNECT:
-		wpa_driver_ndis_event_connect(drv);
-		break;
-	case EVENT_DISCONNECT:
-		wpa_driver_ndis_event_disconnect(drv);
-		break;
-	case EVENT_MEDIA_SPECIFIC:
-		wpa_driver_ndis_event_media_specific(drv, data, data_len);
-		break;
-	case EVENT_ADAPTER_ARRIVAL:
-		wpa_driver_ndis_event_adapter_arrival(drv);
-		break;
-	case EVENT_ADAPTER_REMOVAL:
-		wpa_driver_ndis_event_adapter_removal(drv);
-		break;
-	}
-}
-
-
-void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data)
-{
-	struct wpa_driver_ndis_data *drv = eloop_data;
-	u8 buf[512];
-	DWORD len;
-
-	ResetEvent(drv->event_avail);
-	if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL))
-		wpa_driver_ndis_event_process(drv, buf, len);
-	else {
-		wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__,
-			   (int) GetLastError());
-	}
-}

Copied: vendor/wpa/2.0/src/drivers/driver_ndis_.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_ndis_.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_ndis_.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_ndis_.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,99 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface - event processing
+ * Copyright (c) 2004-2005, Jouni Malinen <j at 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 "driver.h"
+#include "eloop.h"
+
+/* Keep this event processing in a separate file and without WinPcap headers to
+ * avoid conflicts with some of the header files. */
+struct _ADAPTER;
+typedef struct _ADAPTER * LPADAPTER;
+#include "driver_ndis.h"
+
+
+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
+					  const u8 *data, size_t data_len);
+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv);
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
+		   EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
+		   EVENT_ADAPTER_REMOVAL };
+
+/* Event data:
+ * enum event_types (as int, i.e., 4 octets)
+ * data length (2 octets (big endian), optional)
+ * data (variable len, optional)
+ */
+
+
+static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv,
+					  u8 *buf, size_t len)
+{
+	u8 *pos, *data = NULL;
+	enum event_types type;
+	size_t data_len = 0;
+
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len);
+	if (len < sizeof(int))
+		return;
+	type = *((int *) buf);
+	pos = buf + sizeof(int);
+	wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type);
+
+	if (buf + len - pos > 2) {
+		data_len = (int) *pos++ << 8;
+		data_len += *pos++;
+		if (data_len > (size_t) (buf + len - pos)) {
+			wpa_printf(MSG_DEBUG, "NDIS: event data overflow");
+			return;
+		}
+		data = pos;
+		wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len);
+	}
+
+	switch (type) {
+	case EVENT_CONNECT:
+		wpa_driver_ndis_event_connect(drv);
+		break;
+	case EVENT_DISCONNECT:
+		wpa_driver_ndis_event_disconnect(drv);
+		break;
+	case EVENT_MEDIA_SPECIFIC:
+		wpa_driver_ndis_event_media_specific(drv, data, data_len);
+		break;
+	case EVENT_ADAPTER_ARRIVAL:
+		wpa_driver_ndis_event_adapter_arrival(drv);
+		break;
+	case EVENT_ADAPTER_REMOVAL:
+		wpa_driver_ndis_event_adapter_removal(drv);
+		break;
+	}
+}
+
+
+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data)
+{
+	struct wpa_driver_ndis_data *drv = eloop_data;
+	u8 buf[512];
+	DWORD len;
+
+	ResetEvent(drv->event_avail);
+	if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL))
+		wpa_driver_ndis_event_process(drv, buf, len);
+	else {
+		wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__,
+			   (int) GetLastError());
+	}
+}

Deleted: vendor/wpa/2.0/src/drivers/driver_ndiswrapper.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ndiswrapper.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ndiswrapper.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,378 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Linux ndiswrapper
- * Copyright (c) 2004-2006, Giridhar Pemmasani <giri at lmc.cs.sunysb.edu>
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that ndiswrapper supports WPA configuration via Linux wireless
- * extensions and if the kernel includes support for this, driver_wext.c should
- * be used instead of this driver wrapper.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-struct wpa_driver_ndiswrapper_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-
-struct wpa_key {
-	enum wpa_alg alg;
-	const u8 *addr;
-	int key_index;
-	int set_tx;
-	const u8 *seq;
-	size_t seq_len;
-	const u8 *key;
-	size_t key_len;
-};
-
-struct wpa_assoc_info {
-	const u8 *bssid;
-	const u8 *ssid;
-	size_t ssid_len;
-	int freq;
-	const u8 *wpa_ie;
-	size_t wpa_ie_len;
-	enum wpa_cipher pairwise_suite;
-	enum wpa_cipher group_suite;
-	enum wpa_key_mgmt key_mgmt_suite;
-	int auth_alg;
-	int mode;
-};
-
-#define PRIV_RESET	 		SIOCIWFIRSTPRIV+0
-#define WPA_SET_WPA 			SIOCIWFIRSTPRIV+1
-#define WPA_SET_KEY 			SIOCIWFIRSTPRIV+2
-#define WPA_ASSOCIATE		 	SIOCIWFIRSTPRIV+3
-#define WPA_DISASSOCIATE 		SIOCIWFIRSTPRIV+4
-#define WPA_DROP_UNENCRYPTED 		SIOCIWFIRSTPRIV+5
-#define WPA_SET_COUNTERMEASURES 	SIOCIWFIRSTPRIV+6
-#define WPA_DEAUTHENTICATE	 	SIOCIWFIRSTPRIV+7
-#define WPA_SET_AUTH_ALG	 	SIOCIWFIRSTPRIV+8
-#define WPA_INIT			SIOCIWFIRSTPRIV+9
-#define WPA_DEINIT			SIOCIWFIRSTPRIV+10
-#define WPA_GET_CAPA		 	SIOCIWFIRSTPRIV+11
-
-static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg);
-
-static int get_socket(void)
-{
-	static const int families[] = {
-		AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
-	};
-	unsigned int i;
-	int sock;
-
-	for (i = 0; i < sizeof(families) / sizeof(int); ++i) {
-		sock = socket(families[i], SOCK_DGRAM, 0);
-		if (sock >= 0)
-			return sock;
-	}
-
-	return -1;
-}
-
-static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request,
-		      struct iwreq *pwrq)
-{
-	os_strlcpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ);
-	return ioctl(drv->sock, request, pwrq);
-}
-
-static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	struct iwreq priv_req;
-	int ret = 0;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.data.flags = enabled;
-	if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int wpa_ndiswrapper_set_key(const char *ifname, void *priv,
-				   enum wpa_alg alg, const u8 *addr,
-				   int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	struct wpa_key wpa_key;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	wpa_key.alg = alg;
-	wpa_key.addr = addr;
-	wpa_key.key_index = key_idx;
-	wpa_key.set_tx = set_tx;
-	wpa_key.seq = seq;
-	wpa_key.seq_len = seq_len;
-	wpa_key.key = key;
-	wpa_key.key_len = key_len;
-
-	priv_req.u.data.pointer = (void *)&wpa_key;
-	priv_req.u.data.length = sizeof(wpa_key);
-
-	if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0)
-		ret = -1;
-
-	if (alg == WPA_ALG_NONE) {
-		/*
-		 * ndiswrapper did not seem to be clearing keys properly in
-		 * some cases with WPA_SET_KEY. For example, roaming from WPA
-		 * enabled AP to plaintext one seemed to fail since the driver
-		 * did not associate. Try to make sure the keys are cleared so
-		 * that plaintext APs can be used in all cases.
-		 */
-		wpa_driver_wext_set_key(ifname, drv->wext, alg, addr, key_idx,
-					set_tx, seq, seq_len, key, key_len);
-	}
-
-	return ret;
-}
-
-static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.param.value = enabled;
-	if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-static int wpa_ndiswrapper_set_drop_unencrypted(void *priv,
-						int enabled)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.param.value = enabled;
-	if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.param.value = reason_code;
-	os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
-	if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
-	if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int
-wpa_ndiswrapper_associate(void *priv,
-			  struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct wpa_assoc_info wpa_assoc_info;
-	struct iwreq priv_req;
-
-	if (wpa_ndiswrapper_set_drop_unencrypted(drv,
-						 params->drop_unencrypted) < 0)
-		ret = -1;
-	if (wpa_ndiswrapper_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-	os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
-
-	wpa_assoc_info.bssid = params->bssid;
-	wpa_assoc_info.ssid = params->ssid;
-	wpa_assoc_info.ssid_len = params->ssid_len;
-	wpa_assoc_info.freq = params->freq;
-	wpa_assoc_info.wpa_ie = params->wpa_ie;
-	wpa_assoc_info.wpa_ie_len = params->wpa_ie_len;
-	wpa_assoc_info.pairwise_suite = params->pairwise_suite;
-	wpa_assoc_info.group_suite = params->group_suite;
-	wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite;
-	wpa_assoc_info.auth_alg = params->auth_alg;
-	wpa_assoc_info.mode = params->mode;
-
-	priv_req.u.data.pointer = (void *)&wpa_assoc_info;
-	priv_req.u.data.length = sizeof(wpa_assoc_info);
-
-	if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.param.value = auth_alg;
-	if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0)
-		ret = -1;
-	return ret;
-}
-
-static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static int wpa_ndiswrapper_scan(void *priv,
-				struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	return wpa_driver_wext_scan(drv->wext, params);
-}
-
-
-static struct wpa_scan_results * wpa_ndiswrapper_get_scan_results(void *priv)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	int ret = 0;
-	struct iwreq priv_req;
-
-	os_memset(&priv_req, 0, sizeof(priv_req));
-
-	priv_req.u.data.pointer = (void *) capa;
-	priv_req.u.data.length = sizeof(*capa);
-	if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0)
-		ret = -1;
-	return ret;
-	
-}
-
-
-static int wpa_ndiswrapper_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_ndiswrapper_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = get_socket();
-	if (drv->sock < 0) {
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	wpa_ndiswrapper_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_ndiswrapper_deinit(void *priv)
-{
-	struct wpa_driver_ndiswrapper_data *drv = priv;
-	wpa_ndiswrapper_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
-	.name = "ndiswrapper",
-	.desc = "Linux ndiswrapper (deprecated; use wext)",
-	.set_key = wpa_ndiswrapper_set_key,
-	.set_countermeasures = wpa_ndiswrapper_set_countermeasures,
-	.deauthenticate = wpa_ndiswrapper_deauthenticate,
-	.disassociate = wpa_ndiswrapper_disassociate,
-	.associate = wpa_ndiswrapper_associate,
-
-	.get_bssid = wpa_ndiswrapper_get_bssid,
-	.get_ssid = wpa_ndiswrapper_get_ssid,
-	.scan2 = wpa_ndiswrapper_scan,
-	.get_scan_results2 = wpa_ndiswrapper_get_scan_results,
-	.init = wpa_ndiswrapper_init,
-	.deinit = wpa_ndiswrapper_deinit,
-	.get_capa = wpa_ndiswrapper_get_capa,
-	.set_operstate = wpa_ndiswrapper_set_operstate,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_nl80211.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_nl80211.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_nl80211.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,5390 +0,0 @@
-/*
- * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2003-2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2007, Johannes Berg <johannes at sipsolutions.net>
- * Copyright (c) 2009-2010, Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-#include <netpacket/packet.h>
-#include <linux/filter.h>
-#include "nl80211_copy.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "radiotap.h"
-#include "radiotap_iter.h"
-#include "driver.h"
-
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl_handle_alloc_cb nl_socket_alloc_cb
-#define nl_handle_destroy nl_socket_free
-#endif /* CONFIG_LIBNL20 */
-
-
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
-#endif
-#ifndef IFF_DORMANT
-#define IFF_DORMANT    0x20000         /* driver signals dormant       */
-#endif
-
-#ifndef IF_OPER_DORMANT
-#define IF_OPER_DORMANT 5
-#endif
-#ifndef IF_OPER_UP
-#define IF_OPER_UP 6
-#endif
-
-struct i802_bss {
-	struct wpa_driver_nl80211_data *drv;
-	struct i802_bss *next;
-	int ifindex;
-	char ifname[IFNAMSIZ + 1];
-	unsigned int beacon_set:1;
-};
-
-struct wpa_driver_nl80211_data {
-	void *ctx;
-	struct netlink_data *netlink;
-	int ioctl_sock; /* socket for ioctl() use */
-	char brname[IFNAMSIZ];
-	int ifindex;
-	int if_removed;
-	struct wpa_driver_capa capa;
-	int has_capability;
-
-	int operstate;
-
-	int scan_complete_events;
-
-	struct nl_handle *nl_handle;
-	struct nl_handle *nl_handle_event;
-	struct nl_cache *nl_cache;
-	struct nl_cache *nl_cache_event;
-	struct nl_cb *nl_cb;
-	struct genl_family *nl80211;
-
-	u8 auth_bssid[ETH_ALEN];
-	u8 bssid[ETH_ALEN];
-	int associated;
-	u8 ssid[32];
-	size_t ssid_len;
-	int nlmode;
-	int ap_scan_as_station;
-	unsigned int assoc_freq;
-
-	int monitor_sock;
-	int monitor_ifidx;
-	int probe_req_report;
-	int disable_11b_rates;
-
-	unsigned int pending_remain_on_chan:1;
-	unsigned int added_bridge:1;
-	unsigned int added_if_into_bridge:1;
-
-	u64 remain_on_chan_cookie;
-	u64 send_action_cookie;
-
-	struct wpa_driver_scan_filter *filter_ssids;
-	size_t num_filter_ssids;
-
-	struct i802_bss first_bss;
-
-#ifdef HOSTAPD
-	int eapol_sock; /* socket for EAPOL frames */
-
-	int default_if_indices[16];
-	int *if_indices;
-	int num_if_indices;
-
-	int last_freq;
-	int last_freq_ht;
-#endif /* HOSTAPD */
-};
-
-
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
-					    void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
-static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-				   const u8 *addr, int cmd, u16 reason_code,
-				   int local_state_change);
-static void nl80211_remove_monitor_interface(
-	struct wpa_driver_nl80211_data *drv);
-
-#ifdef HOSTAPD
-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);
-static int wpa_driver_nl80211_if_remove(void *priv,
-					enum wpa_driver_if_type type,
-					const char *ifname);
-#else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	return 0;
-}
-#endif /* HOSTAPD */
-
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
-static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
-							void *timeout_ctx);
-static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
-				     int ifindex, int disabled);
-
-
-/* nl80211 code */
-static int ack_handler(struct nl_msg *msg, void *arg)
-{
-	int *err = arg;
-	*err = 0;
-	return NL_STOP;
-}
-
-static int finish_handler(struct nl_msg *msg, void *arg)
-{
-	int *ret = arg;
-	*ret = 0;
-	return NL_SKIP;
-}
-
-static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
-			 void *arg)
-{
-	int *ret = arg;
-	*ret = err->error;
-	return NL_SKIP;
-}
-
-
-static int no_seq_check(struct nl_msg *msg, void *arg)
-{
-	return NL_OK;
-}
-
-
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
-			 struct nl_handle *nl_handle, struct nl_msg *msg,
-			 int (*valid_handler)(struct nl_msg *, void *),
-			 void *valid_data)
-{
-	struct nl_cb *cb;
-	int err = -ENOMEM;
-
-	cb = nl_cb_clone(drv->nl_cb);
-	if (!cb)
-		goto out;
-
-	err = nl_send_auto_complete(nl_handle, msg);
-	if (err < 0)
-		goto out;
-
-	err = 1;
-
-	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
-	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
-	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
-
-	if (valid_handler)
-		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
-			  valid_handler, valid_data);
-
-	while (err > 0)
-		nl_recvmsgs(nl_handle, cb);
- out:
-	nl_cb_put(cb);
-	nlmsg_free(msg);
-	return err;
-}
-
-
-static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
-			      struct nl_msg *msg,
-			      int (*valid_handler)(struct nl_msg *, void *),
-			      void *valid_data)
-{
-	return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
-			     valid_data);
-}
-
-
-struct family_data {
-	const char *group;
-	int id;
-};
-
-
-static int family_handler(struct nl_msg *msg, void *arg)
-{
-	struct family_data *res = arg;
-	struct nlattr *tb[CTRL_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *mcgrp;
-	int i;
-
-	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-	if (!tb[CTRL_ATTR_MCAST_GROUPS])
-		return NL_SKIP;
-
-	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
-		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
-		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
-			  nla_len(mcgrp), NULL);
-		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
-		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
-		    os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
-			       res->group,
-			       nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
-			continue;
-		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
-		break;
-	};
-
-	return NL_SKIP;
-}
-
-
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
-			       const char *family, const char *group)
-{
-	struct nl_msg *msg;
-	int ret = -1;
-	struct family_data res = { group, -ENOENT };
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
-		    0, 0, CTRL_CMD_GETFAMILY, 0);
-	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
-
-	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
-	msg = NULL;
-	if (ret == 0)
-		ret = res.id;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (!drv->associated)
-		return -1;
-	os_memcpy(bssid, drv->bssid, ETH_ALEN);
-	return 0;
-}
-
-
-static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (!drv->associated)
-		return -1;
-	os_memcpy(ssid, drv->ssid, drv->ssid_len);
-	return drv->ssid_len;
-}
-
-
-static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
-					  char *buf, size_t len, int del)
-{
-	union wpa_event_data event;
-
-	os_memset(&event, 0, sizeof(event));
-	if (len > sizeof(event.interface_status.ifname))
-		len = sizeof(event.interface_status.ifname) - 1;
-	os_memcpy(event.interface_status.ifname, buf, len);
-	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
-		EVENT_INTERFACE_ADDED;
-
-	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
-		   del ? "DEL" : "NEW",
-		   event.interface_status.ifname,
-		   del ? "removed" : "added");
-
-	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
-		if (del)
-			drv->if_removed = 1;
-		else
-			drv->if_removed = 0;
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-}
-
-
-static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
-					 u8 *buf, size_t len)
-{
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
-			    == 0)
-				return 1;
-			else
-				break;
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
-					  int ifindex, u8 *buf, size_t len)
-{
-	if (drv->ifindex == ifindex)
-		return 1;
-
-	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
-		drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
-		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
-			   "interface");
-		wpa_driver_nl80211_finish_drv_init(drv);
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
-						 struct ifinfomsg *ifi,
-						 u8 *buf, size_t len)
-{
-	struct wpa_driver_nl80211_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-	u32 brid = 0;
-
-	if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-	    !have_ifidx(drv, ifi->ifi_index)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
-			   "ifindex %d", ifi->ifi_index);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
-		   "(%s%s%s%s)",
-		   drv->operstate, ifi->ifi_flags,
-		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
-		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
-		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
-		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
-	/*
-	 * Some drivers send the association event before the operup event--in
-	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
-	 * fails. This will hit us when wpa_supplicant does not need to do
-	 * IEEE 802.1X authentication
-	 */
-	if (drv->operstate == 1 &&
-	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
-	    !(ifi->ifi_flags & IFF_RUNNING))
-		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
-				       -1, IF_OPER_UP);
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_nl80211_event_link(
-				drv,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len, 0);
-		} else if (attr->rta_type == IFLA_MASTER)
-			brid = nla_get_u32((struct nlattr *) attr);
-		attr = RTA_NEXT(attr, attrlen);
-	}
-
-#ifdef HOSTAPD
-	if (ifi->ifi_family == AF_BRIDGE && brid) {
-		/* device has been added to bridge */
-		char namebuf[IFNAMSIZ];
-		if_indextoname(brid, namebuf);
-		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
-			   brid, namebuf);
-		add_ifidx(drv, brid);
-	}
-#endif /* HOSTAPD */
-}
-
-
-static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
-						 struct ifinfomsg *ifi,
-						 u8 *buf, size_t len)
-{
-	struct wpa_driver_nl80211_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-	u32 brid = 0;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_nl80211_event_link(
-				drv,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len, 1);
-		} else if (attr->rta_type == IFLA_MASTER)
-			brid = nla_get_u32((struct nlattr *) attr);
-		attr = RTA_NEXT(attr, attrlen);
-	}
-
-#ifdef HOSTAPD
-	if (ifi->ifi_family == AF_BRIDGE && brid) {
-		/* device has been removed from bridge */
-		char namebuf[IFNAMSIZ];
-		if_indextoname(brid, namebuf);
-		wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
-			   "%s", brid, namebuf);
-		del_ifidx(drv, brid);
-	}
-#endif /* HOSTAPD */
-}
-
-
-static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
-			    const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24 + sizeof(mgmt->u.auth)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
-			   "frame");
-		return;
-	}
-
-	os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
-	os_memset(&event, 0, sizeof(event));
-	os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
-	event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
-	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
-	if (len > 24 + sizeof(mgmt->u.auth)) {
-		event.auth.ies = mgmt->u.auth.variable;
-		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
-}
-
-
-static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
-			    const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	u16 status;
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
-			   "frame");
-		return;
-	}
-
-	status = le_to_host16(mgmt->u.assoc_resp.status_code);
-	if (status != WLAN_STATUS_SUCCESS) {
-		os_memset(&event, 0, sizeof(event));
-		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
-			event.assoc_reject.resp_ies =
-				(u8 *) mgmt->u.assoc_resp.variable;
-			event.assoc_reject.resp_ies_len =
-				len - 24 - sizeof(mgmt->u.assoc_resp);
-		}
-		event.assoc_reject.status_code = status;
-
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
-		return;
-	}
-
-	drv->associated = 1;
-	os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
-
-	os_memset(&event, 0, sizeof(event));
-	if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
-		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
-		event.assoc_info.resp_ies_len =
-			len - 24 - sizeof(mgmt->u.assoc_resp);
-	}
-
-	event.assoc_info.freq = drv->assoc_freq;
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
-			       enum nl80211_commands cmd, struct nlattr *status,
-			       struct nlattr *addr, struct nlattr *req_ie,
-			       struct nlattr *resp_ie)
-{
-	union wpa_event_data event;
-
-	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-		/*
-		 * Avoid reporting two association events that would confuse
-		 * the core code.
-		 */
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
-			   "when using userspace SME", cmd);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	if (cmd == NL80211_CMD_CONNECT &&
-	    nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
-		if (resp_ie) {
-			event.assoc_reject.resp_ies = nla_data(resp_ie);
-			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
-		}
-		event.assoc_reject.status_code = nla_get_u16(status);
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
-		return;
-	}
-
-	drv->associated = 1;
-	if (addr)
-		os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
-
-	if (req_ie) {
-		event.assoc_info.req_ies = nla_data(req_ie);
-		event.assoc_info.req_ies_len = nla_len(req_ie);
-	}
-	if (resp_ie) {
-		event.assoc_info.resp_ies = nla_data(resp_ie);
-		event.assoc_info.resp_ies_len = nla_len(resp_ie);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
-			       enum nl80211_commands cmd, struct nlattr *addr)
-{
-	union wpa_event_data event;
-	enum wpa_event_type ev;
-
-	if (nla_len(addr) != ETH_ALEN)
-		return;
-
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
-		   cmd, MAC2STR((u8 *) nla_data(addr)));
-
-	if (cmd == NL80211_CMD_AUTHENTICATE)
-		ev = EVENT_AUTH_TIMED_OUT;
-	else if (cmd == NL80211_CMD_ASSOCIATE)
-		ev = EVENT_ASSOC_TIMED_OUT;
-	else
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, ev, &event);
-}
-
-
-static void mlme_event_action(struct wpa_driver_nl80211_data *drv,
-			      struct nlattr *freq, const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	u16 fc, stype;
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
-		return;
-	}
-
-	fc = le_to_host16(mgmt->frame_control);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_action.da = mgmt->da;
-	event.rx_action.sa = mgmt->sa;
-	event.rx_action.bssid = mgmt->bssid;
-	event.rx_action.category = mgmt->u.action.category;
-	event.rx_action.data = &mgmt->u.action.category + 1;
-	event.rx_action.len = frame + len - event.rx_action.data;
-	if (freq)
-		event.rx_action.freq = nla_get_u32(freq);
-	wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
-}
-
-
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
-					struct nlattr *cookie, const u8 *frame,
-					size_t len, struct nlattr *ack)
-{
-	union wpa_event_data event;
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
-	u64 cookie_val;
-
-	if (!cookie)
-		return;
-
-	cookie_val = nla_get_u64(cookie);
-	wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s",
-		   (long long unsigned int) cookie_val,
-		   cookie_val == drv->send_action_cookie ?
-		   " (match)" : " (unknown)");
-	if (cookie_val != drv->send_action_cookie)
-		return;
-
-	hdr = (const struct ieee80211_hdr *) frame;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = frame;
-	event.tx_status.data_len = len;
-	event.tx_status.ack = ack != NULL;
-	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
-				       enum wpa_event_type type,
-				       const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	const u8 *bssid = NULL;
-	u16 reason_code = 0;
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len >= 24) {
-		bssid = mgmt->bssid;
-
-		if (drv->associated != 0 &&
-		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
-		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
-			/*
-			 * We have presumably received this deauth as a
-			 * response to a clear_state_mismatch() outgoing
-			 * deauth.  Don't let it take us offline!
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
-				   "from Unknown BSSID " MACSTR " -- ignoring",
-				   MAC2STR(bssid));
-			return;
-		}
-	}
-
-	drv->associated = 0;
-	os_memset(&event, 0, sizeof(event));
-
-	/* Note: Same offset for Reason Code in both frame subtypes */
-	if (len >= 24 + sizeof(mgmt->u.deauth))
-		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-	if (type == EVENT_DISASSOC) {
-		event.disassoc_info.addr = bssid;
-		event.disassoc_info.reason_code = reason_code;
-	} else {
-		event.deauth_info.addr = bssid;
-		event.deauth_info.reason_code = reason_code;
-	}
-
-	wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event(struct wpa_driver_nl80211_data *drv,
-		       enum nl80211_commands cmd, struct nlattr *frame,
-		       struct nlattr *addr, struct nlattr *timed_out,
-		       struct nlattr *freq, struct nlattr *ack,
-		       struct nlattr *cookie)
-{
-	if (timed_out && addr) {
-		mlme_timeout_event(drv, cmd, addr);
-		return;
-	}
-
-	if (frame == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
-			   "data", cmd);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
-	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
-		    nla_data(frame), nla_len(frame));
-
-	switch (cmd) {
-	case NL80211_CMD_AUTHENTICATE:
-		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_ASSOCIATE:
-		mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_DEAUTHENTICATE:
-		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
-					   nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_DISASSOCIATE:
-		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
-					   nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_ACTION:
-		mlme_event_action(drv, freq, nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_ACTION_TX_STATUS:
-		mlme_event_action_tx_status(drv, cookie, nla_data(frame),
-					    nla_len(frame), ack);
-		break;
-	default:
-		break;
-	}
-}
-
-
-static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
-					   struct nlattr *tb[])
-{
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
-	os_memset(&data, 0, sizeof(data));
-	if (tb[NL80211_ATTR_MAC]) {
-		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
-			    nla_data(tb[NL80211_ATTR_MAC]),
-			    nla_len(tb[NL80211_ATTR_MAC]));
-		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
-	}
-	if (tb[NL80211_ATTR_KEY_SEQ]) {
-		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
-			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
-			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
-	}
-	if (tb[NL80211_ATTR_KEY_TYPE]) {
-		enum nl80211_key_type key_type =
-			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
-		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
-		if (key_type == NL80211_KEYTYPE_PAIRWISE)
-			data.michael_mic_failure.unicast = 1;
-	} else
-		data.michael_mic_failure.unicast = 1;
-
-	if (tb[NL80211_ATTR_KEY_IDX]) {
-		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
-		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-}
-
-
-static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr *tb[])
-{
-	if (tb[NL80211_ATTR_MAC] == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
-			   "event");
-		return;
-	}
-	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-	drv->associated = 1;
-	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
-		   MAC2STR(drv->bssid));
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
-					 int cancel_event, struct nlattr *tb[])
-{
-	unsigned int freq, chan_type, duration;
-	union wpa_event_data data;
-	u64 cookie;
-
-	if (tb[NL80211_ATTR_WIPHY_FREQ])
-		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
-	else
-		freq = 0;
-
-	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
-		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
-	else
-		chan_type = 0;
-
-	if (tb[NL80211_ATTR_DURATION])
-		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
-	else
-		duration = 0;
-
-	if (tb[NL80211_ATTR_COOKIE])
-		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
-	else
-		cookie = 0;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
-		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
-		   cancel_event, freq, chan_type, duration,
-		   (long long unsigned int) cookie,
-		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
-
-	if (cookie != drv->remain_on_chan_cookie)
-		return; /* not for us */
-
-	drv->pending_remain_on_chan = !cancel_event;
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = freq;
-	data.remain_on_channel.duration = duration;
-	wpa_supplicant_event(drv->ctx, cancel_event ?
-			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
-			     EVENT_REMAIN_ON_CHANNEL, &data);
-}
-
-
-static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
-			    struct nlattr *tb[])
-{
-	union wpa_event_data event;
-	struct nlattr *nl;
-	int rem;
-	struct scan_info *info;
-#define MAX_REPORT_FREQS 50
-	int freqs[MAX_REPORT_FREQS];
-	int num_freqs = 0;
-
-	os_memset(&event, 0, sizeof(event));
-	info = &event.scan_info;
-	info->aborted = aborted;
-
-	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
-		nla_for_each_nested(nl, tb[NL80211_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);
-			info->num_ssids++;
-			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
-				break;
-		}
-	}
-	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
-		{
-			freqs[num_freqs] = nla_get_u32(nl);
-			num_freqs++;
-			if (num_freqs == MAX_REPORT_FREQS - 1)
-				break;
-		}
-		info->freqs = freqs;
-		info->num_freqs = num_freqs;
-	}
-	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
-}
-
-
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
-			      struct nlattr *tb[])
-{
-	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
-		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
-		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
-	};
-	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
-	enum nl80211_cqm_rssi_threshold_event event;
-	union wpa_event_data ed;
-
-	if (tb[NL80211_ATTR_CQM] == NULL ||
-	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
-			     cqm_policy)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
-		return;
-	}
-
-	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
-		return;
-	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
-
-	os_memset(&ed, 0, sizeof(ed));
-
-	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
-		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
-			   "event: RSSI high");
-		ed.signal_change.above_threshold = 1;
-	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
-		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
-			   "event: RSSI low");
-		ed.signal_change.above_threshold = 0;
-	} else
-		return;
-
-	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
-}
-
-
-static int process_event(struct nl_msg *msg, void *arg)
-{
-	struct wpa_driver_nl80211_data *drv = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	union wpa_event_data data;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb[NL80211_ATTR_IFINDEX]) {
-		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-				   " for foreign interface (ifindex %d)",
-				   gnlh->cmd, ifindex);
-			return NL_SKIP;
-		}
-	}
-
-	if (drv->ap_scan_as_station &&
-	    (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-	     gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
-	}
-
-	switch (gnlh->cmd) {
-	case NL80211_CMD_TRIGGER_SCAN:
-		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
-		break;
-	case NL80211_CMD_NEW_SCAN_RESULTS:
-		wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
-		drv->scan_complete_events = 1;
-		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
-				     drv->ctx);
-		send_scan_event(drv, 0, tb);
-		break;
-	case NL80211_CMD_SCAN_ABORTED:
-		wpa_printf(MSG_DEBUG, "nl80211: 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);
-		break;
-	case NL80211_CMD_AUTHENTICATE:
-	case NL80211_CMD_ASSOCIATE:
-	case NL80211_CMD_DEAUTHENTICATE:
-	case NL80211_CMD_DISASSOCIATE:
-	case NL80211_CMD_ACTION:
-	case NL80211_CMD_ACTION_TX_STATUS:
-		mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
-			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
-			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
-			   tb[NL80211_ATTR_COOKIE]);
-		break;
-	case NL80211_CMD_CONNECT:
-	case NL80211_CMD_ROAM:
-		mlme_event_connect(drv, gnlh->cmd,
-				   tb[NL80211_ATTR_STATUS_CODE],
-				   tb[NL80211_ATTR_MAC],
-				   tb[NL80211_ATTR_REQ_IE],
-				   tb[NL80211_ATTR_RESP_IE]);
-		break;
-	case NL80211_CMD_DISCONNECT:
-		if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-			/*
-			 * Avoid reporting two disassociation events that could
-			 * confuse the core code.
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
-				   "event when using userspace SME");
-			break;
-		}
-		drv->associated = 0;
-		os_memset(&data, 0, sizeof(data));
-		if (tb[NL80211_ATTR_REASON_CODE])
-			data.disassoc_info.reason_code =
-				nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
-		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
-		break;
-	case NL80211_CMD_MICHAEL_MIC_FAILURE:
-		mlme_event_michael_mic_failure(drv, tb);
-		break;
-	case NL80211_CMD_JOIN_IBSS:
-		mlme_event_join_ibss(drv, tb);
-		break;
-	case NL80211_CMD_REMAIN_ON_CHANNEL:
-		mlme_event_remain_on_channel(drv, 0, tb);
-		break;
-	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
-		mlme_event_remain_on_channel(drv, 1, tb);
-		break;
-	case NL80211_CMD_NOTIFY_CQM:
-		nl80211_cqm_event(drv, tb);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
-			   "(cmd=%d)", gnlh->cmd);
-		break;
-	}
-
-	return NL_SKIP;
-}
-
-
-static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
-					     void *sock_ctx)
-{
-	struct nl_cb *cb;
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
-
-	cb = nl_cb_clone(drv->nl_cb);
-	if (!cb)
-		return;
-	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
-	nl_recvmsgs(drv->nl_handle_event, cb);
-	nl_cb_put(cb);
-}
-
-
-/**
- * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
- * @priv: driver_nl80211 private data
- * @alpha2_arg: country to which to switch to
- * Returns: 0 on success, -1 on failure
- *
- * This asks nl80211 to set the regulatory domain for given
- * country ISO / IEC alpha2.
- */
-static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	char alpha2[3];
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	alpha2[0] = alpha2_arg[0];
-	alpha2[1] = alpha2_arg[1];
-	alpha2[2] = '\0';
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_REQ_SET_REG, 0);
-
-	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
-	if (send_and_recv_msgs(drv, msg, NULL, NULL))
-		return -EINVAL;
-	return 0;
-nla_put_failure:
-	return -EINVAL;
-}
-
-
-#ifndef HOSTAPD
-struct wiphy_info_data {
-	int max_scan_ssids;
-	int ap_supported;
-	int auth_supported;
-	int connect_supported;
-};
-
-
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct wiphy_info_data *info = arg;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
-		info->max_scan_ssids =
-			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
-
-	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
-		struct nlattr *nl_mode;
-		int i;
-		nla_for_each_nested(nl_mode,
-				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
-			if (nl_mode->nla_type == NL80211_IFTYPE_AP) {
-				info->ap_supported = 1;
-				break;
-			}
-		}
-	}
-
-	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
-		struct nlattr *nl_cmd;
-		int i;
-
-		nla_for_each_nested(nl_cmd,
-				    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-			u32 cmd = nla_get_u32(nl_cmd);
-			if (cmd == NL80211_CMD_AUTHENTICATE)
-				info->auth_supported = 1;
-			else if (cmd == NL80211_CMD_CONNECT)
-				info->connect_supported = 1;
-		}
-	}
-
-	return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
-				       struct wiphy_info_data *info)
-{
-	struct nl_msg *msg;
-
-	os_memset(info, 0, sizeof(*info));
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
-
-	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
-		return 0;
-	msg = NULL;
-nla_put_failure:
-	nlmsg_free(msg);
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
-{
-	struct wiphy_info_data info;
-	if (wpa_driver_nl80211_get_info(drv, &info))
-		return -1;
-	drv->has_capability = 1;
-	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
-	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-		WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP |
-		WPA_DRIVER_CAPA_ENC_CCMP;
-	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
-		WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-
-	drv->capa.max_scan_ssids = info.max_scan_ssids;
-	if (info.ap_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
-
-	if (info.auth_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-	else if (!info.connect_supported) {
-		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
-			   "authentication/association or connect commands");
-		return -1;
-	}
-
-	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
-	drv->capa.max_remain_on_chan = 5000;
-
-	return 0;
-}
-#endif /* HOSTAPD */
-
-
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv,
-				      void *ctx)
-{
-	int ret;
-
-	/* Initialize generic netlink and nl80211 */
-
-	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (drv->nl_cb == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks");
-		goto err1;
-	}
-
-	drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
-	if (drv->nl_handle == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks");
-		goto err2;
-	}
-
-	drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb);
-	if (drv->nl_handle_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks (event)");
-		goto err2b;
-	}
-
-	if (genl_connect(drv->nl_handle)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink");
-		goto err3;
-	}
-
-	if (genl_connect(drv->nl_handle_event)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink (event)");
-		goto err3;
-	}
-
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
-	    0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
-	if (drv->nl_cache == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
-	if (drv->nl_cache_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
-	if (drv->nl80211 == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
-			   "found");
-		goto err4;
-	}
-
-	ret = nl_get_multicast_id(drv, "nl80211", "scan");
-	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
-			   "membership for scan events: %d (%s)",
-			   ret, strerror(-ret));
-		goto err4;
-	}
-
-	ret = nl_get_multicast_id(drv, "nl80211", "mlme");
-	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
-			   "membership for mlme events: %d (%s)",
-			   ret, strerror(-ret));
-		goto err4;
-	}
-
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
-				 wpa_driver_nl80211_event_receive, drv, ctx);
-
-	return 0;
-
-err4:
-	nl_cache_free(drv->nl_cache_event);
-err3b:
-	nl_cache_free(drv->nl_cache);
-err3:
-	nl_handle_destroy(drv->nl_handle_event);
-err2b:
-	nl_handle_destroy(drv->nl_handle);
-err2:
-	nl_cb_put(drv->nl_cb);
-err1:
-	return -1;
-}
-
-
-/**
- * wpa_driver_nl80211_init - Initialize nl80211 driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * Returns: Pointer to private data, %NULL on failure
- */
-static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_nl80211_data *drv;
-	struct netlink_config *cfg;
-	struct i802_bss *bss;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	bss = &drv->first_bss;
-	bss->drv = drv;
-	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
-	drv->monitor_ifidx = -1;
-	drv->monitor_sock = -1;
-	drv->ioctl_sock = -1;
-
-	if (wpa_driver_nl80211_init_nl(drv, ctx)) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
-		goto failed;
-	}
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		goto failed;
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		goto failed;
-	}
-	if (wpa_driver_nl80211_finish_drv_init(drv))
-		goto failed;
-
-	return bss;
-
-failed:
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
-	return NULL;
-}
-
-
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
-					 const u8 *match, size_t match_len)
-{
-	struct nl_msg *msg;
-	int ret = -1;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REGISTER_ACTION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
-
-	ret = send_and_recv(drv, drv->nl_handle_event, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Register Action command "
-			   "failed: ret=%d (%s)", ret, strerror(-ret));
-		wpa_hexdump(MSG_DEBUG, "nl80211: Register Action match",
-			    match, match_len);
-		goto nla_put_failure;
-	}
-	ret = 0;
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
-{
-	/* FT Action frames */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
-		return -1;
-	else
-		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
-			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
-
-	return 0;
-}
-
-
-static int
-wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
-{
-	struct i802_bss *bss = &drv->first_bss;
-
-	drv->ifindex = if_nametoindex(bss->ifname);
-	drv->first_bss.ifindex = drv->ifindex;
-
-#ifndef HOSTAPD
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
-			   "use managed mode");
-	}
-
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
-		wpa_printf(MSG_ERROR, "Could not set interface '%s' UP",
-			   bss->ifname);
-		return -1;
-	}
-
-	if (wpa_driver_nl80211_capa(drv))
-		return -1;
-
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
-			       1, IF_OPER_DORMANT);
-#endif /* HOSTAPD */
-
-	if (nl80211_register_action_frames(drv) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
-			   "frame processing - ignore for now");
-		/*
-		 * Older kernel versions did not support this, so ignore the
-		 * error for now. Some functionality may not be available
-		 * because of this.
-		 */
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
-{
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_BEACON, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-/**
- * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
- *
- * Shut down driver interface and processing of driver events. Free
- * private data buffer if one was allocated in wpa_driver_nl80211_init().
- */
-static void wpa_driver_nl80211_deinit(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-
-	if (drv->added_if_into_bridge) {
-		if (linux_br_del_if(drv->ioctl_sock, drv->brname, bss->ifname)
-		    < 0)
-			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
-				   "interface %s from bridge %s: %s",
-				   bss->ifname, drv->brname, strerror(errno));
-	}
-	if (drv->added_bridge) {
-		if (linux_br_del(drv->ioctl_sock, drv->brname) < 0)
-			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
-				   "bridge %s: %s",
-				   drv->brname, strerror(errno));
-	}
-
-	nl80211_remove_monitor_interface(drv);
-
-	if (drv->nlmode == NL80211_IFTYPE_AP)
-		wpa_driver_nl80211_del_beacon(drv);
-
-#ifdef HOSTAPD
-	if (drv->last_freq_ht) {
-		/* Clear HT flags from the driver */
-		struct hostapd_freq_params freq;
-		os_memset(&freq, 0, sizeof(freq));
-		freq.freq = drv->last_freq;
-		i802_set_freq(priv, &freq);
-	}
-
-	if (drv->eapol_sock >= 0) {
-		eloop_unregister_read_sock(drv->eapol_sock);
-		close(drv->eapol_sock);
-	}
-
-	if (drv->if_indices != drv->default_if_indices)
-		os_free(drv->if_indices);
-#endif /* HOSTAPD */
-
-	if (drv->disable_11b_rates)
-		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
-
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-	netlink_deinit(drv->netlink);
-
-	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
-
-	(void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
-	wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
-
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl_cache_free(drv->nl_cache_event);
-	nl_handle_destroy(drv->nl_handle);
-	nl_handle_destroy(drv->nl_handle_event);
-	nl_cb_put(drv->nl_cb);
-
-	eloop_cancel_timeout(wpa_driver_nl80211_probe_req_report_timeout,
-			     drv, NULL);
-
-	os_free(drv->filter_ssids);
-
-	os_free(drv);
-}
-
-
-/**
- * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Driver private data
- * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
- *
- * This function can be used as registered timeout when starting a scan to
- * generate a scan completed event if the driver does not report this.
- */
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	if (drv->ap_scan_as_station) {
-		wpa_driver_nl80211_set_mode(&drv->first_bss,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
-	}
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(void *priv,
-				   struct wpa_driver_scan_params *params)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = 0, timeout;
-	struct nl_msg *msg, *ssids, *freqs;
-	size_t i;
-
-	msg = nlmsg_alloc();
-	ssids = nlmsg_alloc();
-	freqs = nlmsg_alloc();
-	if (!msg || !ssids || !freqs) {
-		nlmsg_free(msg);
-		nlmsg_free(ssids);
-		nlmsg_free(freqs);
-		return -1;
-	}
-
-	os_free(drv->filter_ssids);
-	drv->filter_ssids = params->filter_ssids;
-	params->filter_ssids = NULL;
-	drv->num_filter_ssids = params->num_filter_ssids;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_TRIGGER_SCAN, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	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);
-		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
-			params->ssids[i].ssid);
-	}
-	if (params->num_ssids)
-		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
-	if (params->extra_ies) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-				  params->extra_ies, params->extra_ies_len);
-		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
-			params->extra_ies);
-	}
-
-	if (params->freqs) {
-		for (i = 0; params->freqs[i]; i++) {
-			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
-				   "MHz", params->freqs[i]);
-			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
-		}
-		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-#ifdef HOSTAPD
-		if (drv->nlmode == NL80211_IFTYPE_AP) {
-			/*
-			 * mac80211 does not allow scan requests in AP mode, so
-			 * try to do this in station mode.
-			 */
-			if (wpa_driver_nl80211_set_mode(bss,
-							IEEE80211_MODE_INFRA))
-				goto nla_put_failure;
-
-			if (wpa_driver_nl80211_scan(drv, params)) {
-				wpa_driver_nl80211_set_mode(bss,
-							    IEEE80211_MODE_AP);
-				goto nla_put_failure;
-			}
-
-			/* Restore AP mode when processing scan results */
-			drv->ap_scan_as_station = 1;
-			ret = 0;
-		} else
-			goto nla_put_failure;
-#else /* HOSTAPD */
-		goto nla_put_failure;
-#endif /* HOSTAPD */
-	}
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	timeout = 10;
-	if (drv->scan_complete_events) {
-		/*
-		 * The driver seems to deliver events to notify when scan is
-		 * complete, so use longer timeout to avoid race conditions
-		 * with scanning and following association request.
-		 */
-		timeout = 30;
-	}
-	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
-		   "seconds", ret, timeout);
-	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
-			       drv, drv->ctx);
-
-nla_put_failure:
-	nlmsg_free(ssids);
-	nlmsg_free(msg);
-	nlmsg_free(freqs);
-	return ret;
-}
-
-
-static 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)
-{
-	const u8 *ssid;
-	size_t i;
-
-	if (drv->filter_ssids == NULL)
-		return 0;
-
-	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
-	if (ssid == NULL)
-		return 1;
-
-	for (i = 0; i < drv->num_filter_ssids; i++) {
-		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
-		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
-		    0)
-			return 0;
-	}
-
-	return 1;
-}
-
-
-struct nl80211_bss_info_arg {
-	struct wpa_driver_nl80211_data *drv;
-	struct wpa_scan_results *res;
-};
-
-static int bss_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *bss[NL80211_BSS_MAX + 1];
-	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
-		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
-		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
-		[NL80211_BSS_TSF] = { .type = NLA_U64 },
-		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
-		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
-		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
-		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
-		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
-		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
-		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
-		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
-	};
-	struct nl80211_bss_info_arg *_arg = arg;
-	struct wpa_scan_results *res = _arg->res;
-	struct wpa_scan_res **tmp;
-	struct wpa_scan_res *r;
-	const u8 *ie, *beacon_ie;
-	size_t ie_len, beacon_ie_len;
-	u8 *pos;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-	if (!tb[NL80211_ATTR_BSS])
-		return NL_SKIP;
-	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
-			     bss_policy))
-		return NL_SKIP;
-	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
-		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-	} else {
-		ie = NULL;
-		ie_len = 0;
-	}
-	if (bss[NL80211_BSS_BEACON_IES]) {
-		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
-		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
-	} else {
-		beacon_ie = NULL;
-		beacon_ie_len = 0;
-	}
-
-	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
-				  ie ? ie_len : beacon_ie_len))
-		return NL_SKIP;
-
-	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
-	if (r == NULL)
-		return NL_SKIP;
-	if (bss[NL80211_BSS_BSSID])
-		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
-			  ETH_ALEN);
-	if (bss[NL80211_BSS_FREQUENCY])
-		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-	if (bss[NL80211_BSS_BEACON_INTERVAL])
-		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
-	if (bss[NL80211_BSS_CAPABILITY])
-		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
-	r->flags |= WPA_SCAN_NOISE_INVALID;
-	if (bss[NL80211_BSS_SIGNAL_MBM]) {
-		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
-		r->level /= 100; /* mBm to dBm */
-		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
-	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
-		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-		r->flags |= WPA_SCAN_LEVEL_INVALID;
-	} else
-		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
-	if (bss[NL80211_BSS_TSF])
-		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
-	if (bss[NL80211_BSS_SEEN_MS_AGO])
-		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
-	r->ie_len = ie_len;
-	pos = (u8 *) (r + 1);
-	if (ie) {
-		os_memcpy(pos, ie, ie_len);
-		pos += ie_len;
-	}
-	r->beacon_ie_len = beacon_ie_len;
-	if (beacon_ie)
-		os_memcpy(pos, beacon_ie, beacon_ie_len);
-
-	if (bss[NL80211_BSS_STATUS]) {
-		enum nl80211_bss_status status;
-		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-		switch (status) {
-		case NL80211_BSS_STATUS_AUTHENTICATED:
-			r->flags |= WPA_SCAN_AUTHENTICATED;
-			break;
-		case NL80211_BSS_STATUS_ASSOCIATED:
-			r->flags |= WPA_SCAN_ASSOCIATED;
-			break;
-		default:
-			break;
-		}
-	}
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(r);
-		return NL_SKIP;
-	}
-	tmp[res->num++] = r;
-	res->res = tmp;
-
-	return NL_SKIP;
-}
-
-
-static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
-				 const u8 *addr)
-{
-	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
-			   "mismatch (" MACSTR ")", MAC2STR(addr));
-		wpa_driver_nl80211_mlme(drv, addr,
-					NL80211_CMD_DEAUTHENTICATE,
-					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
-	}
-}
-
-
-static void wpa_driver_nl80211_check_bss_status(
-	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
-{
-	size_t i;
-
-	for (i = 0; i < res->num; i++) {
-		struct wpa_scan_res *r = res->res[i];
-		if (r->flags & WPA_SCAN_AUTHENTICATED) {
-			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-				   "indicates BSS status with " MACSTR
-				   " as authenticated",
-				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
-			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
-			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
-			    0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
-					   " in local state (auth=" MACSTR
-					   " assoc=" MACSTR ")",
-					   MAC2STR(drv->auth_bssid),
-					   MAC2STR(drv->bssid));
-				clear_state_mismatch(drv, r->bssid);
-			}
-		}
-
-		if (r->flags & WPA_SCAN_ASSOCIATED) {
-			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-				   "indicate BSS status with " MACSTR
-				   " as associated",
-				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
-			    !drv->associated) {
-				wpa_printf(MSG_DEBUG, "nl80211: Local state "
-					   "(not associated) does not match "
-					   "with BSS state");
-				clear_state_mismatch(drv, r->bssid);
-			} else if (drv->nlmode == NL80211_IFTYPE_STATION &&
-				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
-				   0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Local state "
-					   "(associated with " MACSTR ") does "
-					   "not match with BSS state",
-					   MAC2STR(drv->bssid));
-				clear_state_mismatch(drv, r->bssid);
-				clear_state_mismatch(drv, drv->bssid);
-			}
-		}
-	}
-}
-
-
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
-static struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
-{
-	struct nl_msg *msg;
-	struct wpa_scan_results *res;
-	int ret;
-	struct nl80211_bss_info_arg arg;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-		    NL80211_CMD_GET_SCAN, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	arg.drv = drv;
-	arg.res = res;
-	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-	msg = NULL;
-	if (ret == 0) {
-		wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-			   (unsigned long) res->num);
-		return res;
-	}
-	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
-		   "(%s)", ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
-	wpa_scan_results_free(res);
-	return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * Returns: Scan results on success, -1 on failure
- */
-static struct wpa_scan_results *
-wpa_driver_nl80211_get_scan_results(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct wpa_scan_results *res;
-
-	res = nl80211_get_scan_results(drv);
-	if (res)
-		wpa_driver_nl80211_check_bss_status(drv, res);
-	return res;
-}
-
-
-static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
-{
-	struct wpa_scan_results *res;
-	size_t i;
-
-	res = nl80211_get_scan_results(drv);
-	if (res == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
-	for (i = 0; i < res->num; i++) {
-		struct wpa_scan_res *r = res->res[i];
-		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
-			   (int) i, (int) res->num, MAC2STR(r->bssid),
-			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
-			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
-	}
-
-	wpa_scan_results_free(res);
-}
-
-
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
-				      enum wpa_alg alg, const u8 *addr,
-				      int key_idx, int set_tx,
-				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ifindex = if_nametoindex(ifname);
-	struct nl_msg *msg;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
-		   "set_tx=%d seq_len=%lu key_len=%lu",
-		   __func__, ifindex, alg, addr, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	if (alg == WPA_ALG_NONE) {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_DEL_KEY, 0);
-	} else {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_NEW_KEY, 0);
-		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
-		switch (alg) {
-		case WPA_ALG_WEP:
-			if (key_len == 5)
-				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-					    WLAN_CIPHER_SUITE_WEP40);
-			else
-				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-					    WLAN_CIPHER_SUITE_WEP104);
-			break;
-		case WPA_ALG_TKIP:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_TKIP);
-			break;
-		case WPA_ALG_CCMP:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_CCMP);
-			break;
-		case WPA_ALG_IGTK:
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_AES_CMAC);
-			break;
-		default:
-			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
-				   "algorithm %d", __func__, alg);
-			nlmsg_free(msg);
-			return -1;
-		}
-	}
-
-	if (seq && seq_len)
-		NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
-
-	if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-	{
-		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	}
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
-		ret = 0;
-	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
-			   ret, strerror(-ret));
-
-	/*
-	 * If we failed or don't need to set the default TX key (below),
-	 * we're done here.
-	 */
-	if (ret || !set_tx || alg == WPA_ALG_NONE)
-		return ret;
-#ifdef HOSTAPD
-	if (addr)
-		return ret;
-#else /* HOSTAPD */
-	if (drv->nlmode == NL80211_IFTYPE_AP && addr)
-		return ret;
-#endif /* HOSTAPD */
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_KEY, 0);
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-	if (alg == WPA_ALG_IGTK)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
-	else
-		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == -ENOENT)
-		ret = 0;
-	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
-			   "err=%d %s)", ret, strerror(-ret));
-	return ret;
-
-nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
-		      int key_idx, int defkey,
-		      const u8 *seq, size_t seq_len,
-		      const u8 *key, size_t key_len)
-{
-	struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
-	if (!key_attr)
-		return -1;
-
-	if (defkey && alg == WPA_ALG_IGTK)
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
-	else if (defkey)
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
-
-	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		if (key_len == 5)
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP40);
-		else
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP104);
-		break;
-	case WPA_ALG_TKIP:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
-		break;
-	case WPA_ALG_CCMP:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
-		break;
-	case WPA_ALG_IGTK:
-		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-			    WLAN_CIPHER_SUITE_AES_CMAC);
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
-			   "algorithm %d", __func__, alg);
-		return -1;
-	}
-
-	if (seq && seq_len)
-		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
-
-	NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
-
-	nla_nest_end(msg, key_attr);
-
-	return 0;
- nla_put_failure:
-	return -1;
-}
-
-
-static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
-				 struct nl_msg *msg)
-{
-	int i, privacy = 0;
-	struct nlattr *nl_keys, *nl_key;
-
-	for (i = 0; i < 4; i++) {
-		if (!params->wep_key[i])
-			continue;
-		privacy = 1;
-		break;
-	}
-	if (!privacy)
-		return 0;
-
-	NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
-
-	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
-	if (!nl_keys)
-		goto nla_put_failure;
-
-	for (i = 0; i < 4; i++) {
-		if (!params->wep_key[i])
-			continue;
-
-		nl_key = nla_nest_start(msg, i);
-		if (!nl_key)
-			goto nla_put_failure;
-
-		NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
-			params->wep_key[i]);
-		if (params->wep_key_len[i] == 5)
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP40);
-		else
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP104);
-
-		NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
-
-		if (i == params->wep_tx_keyidx)
-			NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
-
-		nla_nest_end(msg, nl_key);
-	}
-	nla_nest_end(msg, nl_keys);
-
-	return 0;
-
-nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-				   const u8 *addr, int cmd, u16 reason_code,
-				   int local_state_change)
-{
-	int ret = -1;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	if (local_state_change)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-	ret = 0;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
-					 const u8 *addr, int reason_code)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	drv->associated = 0;
-	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
-				       reason_code, 0);
-}
-
-
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
-					     int reason_code)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-		return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	drv->associated = 0;
-	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
-				       reason_code, 0);
-}
-
-
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
-					   int reason_code)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
-		return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	drv->associated = 0;
-	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
-				       reason_code, 0);
-}
-
-
-static int wpa_driver_nl80211_authenticate(
-	void *priv, struct wpa_driver_auth_params *params)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1, i;
-	struct nl_msg *msg;
-	enum nl80211_auth_type type;
-	int count = 0;
-
-	drv->associated = 0;
-	os_memset(drv->auth_bssid, 0, ETH_ALEN);
-	/* FIX: IBSS mode */
-	if (drv->nlmode != NL80211_IFTYPE_STATION)
-		wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
-
-	if (wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
-		return -1;
-
-retry:
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
-		   drv->ifindex);
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_AUTHENTICATE, 0);
-
-	for (i = 0; i < 4; i++) {
-		if (!params->wep_key[i])
-			continue;
-		wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
-					   NULL, i,
-					   i == params->wep_tx_keyidx, NULL, 0,
-					   params->wep_key[i],
-					   params->wep_key_len[i]);
-		if (params->wep_tx_keyidx != i)
-			continue;
-		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
-			       params->wep_key[i], params->wep_key_len[i])) {
-			nlmsg_free(msg);
-			return -1;
-		}
-	}
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
-	}
-	if (params->freq) {
-		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-	}
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
-	}
-	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
-	if (params->ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
-	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
-		type = NL80211_AUTHTYPE_SHARED_KEY;
-	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
-		type = NL80211_AUTHTYPE_NETWORK_EAP;
-	else if (params->auth_alg & WPA_AUTH_ALG_FT)
-		type = NL80211_AUTHTYPE_FT;
-	else
-		goto nla_put_failure;
-	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
-	if (params->local_state_change) {
-		wpa_printf(MSG_DEBUG, "  * Local state change only");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		count++;
-		if (ret == -EALREADY && count == 1 && params->bssid &&
-		    !params->local_state_change) {
-			/*
-			 * mac80211 does not currently accept new
-			 * authentication if we are already authenticated. As a
-			 * workaround, force deauthentication and try again.
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
-				   "after forced deauthentication");
-			wpa_driver_nl80211_deauthenticate(
-				bss, params->bssid,
-				WLAN_REASON_PREV_AUTH_NOT_VALID);
-			nlmsg_free(msg);
-			goto retry;
-		}
-		goto nla_put_failure;
-	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
-		   "successfully");
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-struct phy_info_arg {
-	u16 *num_modes;
-	struct hostapd_hw_modes *modes;
-};
-
-static int phy_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct phy_info_arg *phy_info = arg;
-
-	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
-
-	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
-	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
-		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
-		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
-	};
-
-	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
-	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
-		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
-		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
-	};
-
-	struct nlattr *nl_band;
-	struct nlattr *nl_freq;
-	struct nlattr *nl_rate;
-	int rem_band, rem_freq, rem_rate;
-	struct hostapd_hw_modes *mode;
-	int idx, mode_is_set;
-
-	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
-		return NL_SKIP;
-
-	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
-		mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
-		if (!mode)
-			return NL_SKIP;
-		phy_info->modes = mode;
-
-		mode_is_set = 0;
-
-		mode = &phy_info->modes[*(phy_info->num_modes)];
-		memset(mode, 0, sizeof(*mode));
-		*(phy_info->num_modes) += 1;
-
-		nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
-			  nla_len(nl_band), NULL);
-
-		if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
-			mode->ht_capab = nla_get_u16(
-				tb_band[NL80211_BAND_ATTR_HT_CAPA]);
-		}
-
-		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
-			mode->a_mpdu_params |= nla_get_u8(
-				tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
-				0x03;
-		}
-
-		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
-			mode->a_mpdu_params |= nla_get_u8(
-				tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
-				2;
-		}
-
-		if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
-		    nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
-			u8 *mcs;
-			mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
-			os_memcpy(mode->mcs_set, mcs, 16);
-		}
-
-		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
-			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
-				  nla_len(nl_freq), freq_policy);
-			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-				continue;
-			mode->num_channels++;
-		}
-
-		mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
-		if (!mode->channels)
-			return NL_SKIP;
-
-		idx = 0;
-
-		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
-			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
-				  nla_len(nl_freq), freq_policy);
-			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-				continue;
-
-			mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
-			mode->channels[idx].flag = 0;
-
-			if (!mode_is_set) {
-				/* crude heuristic */
-				if (mode->channels[idx].freq < 4000)
-					mode->mode = HOSTAPD_MODE_IEEE80211B;
-				else
-					mode->mode = HOSTAPD_MODE_IEEE80211A;
-				mode_is_set = 1;
-			}
-
-			/* crude heuristic */
-			if (mode->channels[idx].freq < 4000)
-				if (mode->channels[idx].freq == 2484)
-					mode->channels[idx].chan = 14;
-				else
-					mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
-			else
-				mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
-
-			if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-				mode->channels[idx].flag |=
-					HOSTAPD_CHAN_DISABLED;
-			if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
-				mode->channels[idx].flag |=
-					HOSTAPD_CHAN_PASSIVE_SCAN;
-			if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
-				mode->channels[idx].flag |=
-					HOSTAPD_CHAN_NO_IBSS;
-			if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
-				mode->channels[idx].flag |=
-					HOSTAPD_CHAN_RADAR;
-
-			if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
-			    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
-				mode->channels[idx].max_tx_power =
-					nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
-
-			idx++;
-		}
-
-		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
-			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
-				  nla_len(nl_rate), rate_policy);
-			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-				continue;
-			mode->num_rates++;
-		}
-
-		mode->rates = os_zalloc(mode->num_rates * sizeof(int));
-		if (!mode->rates)
-			return NL_SKIP;
-
-		idx = 0;
-
-		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
-			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
-				  nla_len(nl_rate), rate_policy);
-			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-				continue;
-			mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
-
-			/* crude heuristic */
-			if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
-			    mode->rates[idx] > 200)
-				mode->mode = HOSTAPD_MODE_IEEE80211G;
-
-			idx++;
-		}
-	}
-
-	return NL_SKIP;
-}
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
-{
-	u16 m;
-	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
-	int i, mode11g_idx = -1;
-
-	/* If only 802.11g mode is included, use it to construct matching
-	 * 802.11b mode data. */
-
-	for (m = 0; m < *num_modes; m++) {
-		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
-			return modes; /* 802.11b already included */
-		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
-			mode11g_idx = m;
-	}
-
-	if (mode11g_idx < 0)
-		return modes; /* 2.4 GHz band not supported at all */
-
-	nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
-	if (nmodes == NULL)
-		return modes; /* Could not add 802.11b mode */
-
-	mode = &nmodes[*num_modes];
-	os_memset(mode, 0, sizeof(*mode));
-	(*num_modes)++;
-	modes = nmodes;
-
-	mode->mode = HOSTAPD_MODE_IEEE80211B;
-
-	mode11g = &modes[mode11g_idx];
-	mode->num_channels = mode11g->num_channels;
-	mode->channels = os_malloc(mode11g->num_channels *
-				   sizeof(struct hostapd_channel_data));
-	if (mode->channels == NULL) {
-		(*num_modes)--;
-		return modes; /* Could not add 802.11b mode */
-	}
-	os_memcpy(mode->channels, mode11g->channels,
-		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
-
-	mode->num_rates = 0;
-	mode->rates = os_malloc(4 * sizeof(int));
-	if (mode->rates == NULL) {
-		os_free(mode->channels);
-		(*num_modes)--;
-		return modes; /* Could not add 802.11b mode */
-	}
-
-	for (i = 0; i < mode11g->num_rates; i++) {
-		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
-		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
-			continue;
-		mode->rates[mode->num_rates] = mode11g->rates[i];
-		mode->num_rates++;
-		if (mode->num_rates == 4)
-			break;
-	}
-
-	if (mode->num_rates == 0) {
-		os_free(mode->channels);
-		os_free(mode->rates);
-		(*num_modes)--;
-		return modes; /* No 802.11b rates */
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
-		   "information");
-
-	return modes;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	struct phy_info_arg result = {
-		.num_modes = num_modes,
-		.modes = NULL,
-	};
-
-	*num_modes = 0;
-	*flags = 0;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return NULL;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
-		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
- nla_put_failure:
-	return NULL;
-}
-
-
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
-					 const void *data, size_t len,
-					 int encrypt)
-{
-	__u8 rtap_hdr[] = {
-		0x00, 0x00, /* radiotap version */
-		0x0e, 0x00, /* radiotap length */
-		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
-		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
-		0x00,       /* padding */
-		0x00, 0x00, /* RX and TX flags to indicate that */
-		0x00, 0x00, /* this is the injected frame directly */
-	};
-	struct iovec iov[2] = {
-		{
-			.iov_base = &rtap_hdr,
-			.iov_len = sizeof(rtap_hdr),
-		},
-		{
-			.iov_base = (void *) data,
-			.iov_len = len,
-		}
-	};
-	struct msghdr msg = {
-		.msg_name = NULL,
-		.msg_namelen = 0,
-		.msg_iov = iov,
-		.msg_iovlen = 2,
-		.msg_control = NULL,
-		.msg_controllen = 0,
-		.msg_flags = 0,
-	};
-
-	if (encrypt)
-		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
-
-	return sendmsg(drv->monitor_sock, &msg, 0);
-}
-
-
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-					size_t data_len)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct ieee80211_mgmt *mgmt;
-	int encrypt = 1;
-	u16 fc;
-
-	mgmt = (struct ieee80211_mgmt *) data;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
-		/*
-		 * Only one of the authentication frame types is encrypted.
-		 * In order for static WEP encryption to work properly (i.e.,
-		 * to not encrypt the frame), we need to tell mac80211 about
-		 * the frames that must not be encrypted.
-		 */
-		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
-		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
-		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
-			encrypt = 0;
-	}
-
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
-}
-
-
-static int wpa_driver_nl80211_set_beacon(void *priv,
-					 const u8 *head, size_t head_len,
-					 const u8 *tail, size_t tail_len,
-					 int dtim_period, int beacon_int)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	u8 cmd = NL80211_CMD_NEW_BEACON;
-	int ret;
-	int beacon_set;
-	int ifindex = if_nametoindex(bss->ifname);
-
-	beacon_set = bss->beacon_set;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
-		   beacon_set);
-	if (beacon_set)
-		cmd = NL80211_CMD_SET_BEACON;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, cmd, 0);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
-	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
-			   ret, strerror(-ret));
-	} else {
-		bss->beacon_set = 1;
-	}
-	return ret;
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
-				       int freq, int ht_enabled,
-				       int sec_channel_offset)
-{
-	struct nl_msg *msg;
-	int ret;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_WIPHY, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-	if (ht_enabled) {
-		switch (sec_channel_offset) {
-		case -1:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT40MINUS);
-			break;
-		case 1:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT40PLUS);
-			break;
-		default:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT20);
-			break;
-		}
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == 0)
-		return 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
-		   "%d (%s)", freq, ret, strerror(-ret));
-nla_put_failure:
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_sta_add(void *priv,
-				      struct hostapd_sta_add_params *params)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_STATION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
-	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
-		params->supp_rates);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-		    params->listen_interval);
-	if (params->ht_capabilities) {
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
-			sizeof(*params->ht_capabilities),
-			params->ht_capabilities);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-			   "result: %d (%s)", ret, strerror(-ret));
-	if (ret == -EEXIST)
-		ret = 0;
- nla_put_failure:
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == -ENOENT)
-		return 0;
-	return ret;
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
-				 int ifidx)
-{
-	struct nl_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
-
-#ifdef HOSTAPD
-	/* stop listening for EAPOL on this interface */
-	del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_INTERFACE, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
-
-	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-		return;
- nla_put_failure:
-	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
-}
-
-
-static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
-				     const char *ifname,
-				     enum nl80211_iftype iftype,
-				     const u8 *addr, int wds)
-{
-	struct nl_msg *msg, *flags = NULL;
-	int ifidx;
-	int ret = -ENOBUFS;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_INTERFACE, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
-
-	if (iftype == NL80211_IFTYPE_MONITOR) {
-		int err;
-
-		flags = nlmsg_alloc();
-		if (!flags)
-			goto nla_put_failure;
-
-		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
-
-		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-		nlmsg_free(flags);
-
-		if (err)
-			goto nla_put_failure;
-	} else if (wds) {
-		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret) {
- nla_put_failure:
-		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
-			   ifname, ret, strerror(-ret));
-		return ret;
-	}
-
-	ifidx = if_nametoindex(ifname);
-	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
-		   ifname, ifidx);
-
-	if (ifidx <= 0)
-		return -1;
-
-#ifdef HOSTAPD
-	/* start listening for EAPOL on this interface */
-	add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
-
-	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
-	    linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
-		nl80211_remove_iface(drv, ifidx);
-		return -1;
-	}
-
-	return ifidx;
-}
-
-
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
-				const char *ifname, enum nl80211_iftype iftype,
-				const u8 *addr, int wds)
-{
-	int ret;
-
-	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
-
-	/* if error occured and interface exists already */
-	if (ret == -ENFILE && if_nametoindex(ifname)) {
-		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
-
-		/* Try to remove the interface that was already there. */
-		nl80211_remove_iface(drv, if_nametoindex(ifname));
-
-		/* Try to create the interface again */
-		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
-						wds);
-	}
-
-	if (ret >= 0 && drv->disable_11b_rates)
-		nl80211_disable_11b_rates(drv, ret, 1);
-
-	return ret;
-}
-
-
-static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = buf;
-	event.tx_status.data_len = len;
-	event.tx_status.ack = ok;
-	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
-			     u8 *buf, size_t len)
-{
-	union wpa_event_data event;
-	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.frame = buf;
-	event.rx_from_unknown.len = len;
-	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void handle_frame(struct wpa_driver_nl80211_data *drv,
-			 u8 *buf, size_t len, int datarate, int ssi_signal)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	switch (WLAN_FC_GET_TYPE(fc)) {
-	case WLAN_FC_TYPE_MGMT:
-		os_memset(&event, 0, sizeof(event));
-		event.rx_mgmt.frame = buf;
-		event.rx_mgmt.frame_len = len;
-		event.rx_mgmt.datarate = datarate;
-		event.rx_mgmt.ssi_signal = ssi_signal;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-		break;
-	case WLAN_FC_TYPE_CTRL:
-		/* can only get here with PS-Poll frames */
-		wpa_printf(MSG_DEBUG, "CTRL");
-		from_unknown_sta(drv, buf, len);
-		break;
-	case WLAN_FC_TYPE_DATA:
-		from_unknown_sta(drv, buf, len);
-		break;
-	}
-}
-
-
-static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	int len;
-	unsigned char buf[3000];
-	struct ieee80211_radiotap_iterator iter;
-	int ret;
-	int datarate = 0, ssi_signal = 0;
-	int injected = 0, failed = 0, rxflags = 0;
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	if (drv->nlmode == NL80211_IFTYPE_STATION && !drv->probe_req_report) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore monitor interface "
-			   "frame since Probe Request reporting is disabled");
-		return;
-	}
-
-	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
-		printf("received invalid radiotap frame\n");
-		return;
-	}
-
-	while (1) {
-		ret = ieee80211_radiotap_iterator_next(&iter);
-		if (ret == -ENOENT)
-			break;
-		if (ret) {
-			printf("received invalid radiotap frame (%d)\n", ret);
-			return;
-		}
-		switch (iter.this_arg_index) {
-		case IEEE80211_RADIOTAP_FLAGS:
-			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
-				len -= 4;
-			break;
-		case IEEE80211_RADIOTAP_RX_FLAGS:
-			rxflags = 1;
-			break;
-		case IEEE80211_RADIOTAP_TX_FLAGS:
-			injected = 1;
-			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
-					IEEE80211_RADIOTAP_F_TX_FAIL;
-			break;
-		case IEEE80211_RADIOTAP_DATA_RETRIES:
-			break;
-		case IEEE80211_RADIOTAP_CHANNEL:
-			/* TODO: convert from freq/flags to channel number */
-			break;
-		case IEEE80211_RADIOTAP_RATE:
-			datarate = *iter.this_arg * 5;
-			break;
-		case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
-			ssi_signal = *iter.this_arg;
-			break;
-		}
-	}
-
-	if (rxflags && injected)
-		return;
-
-	if (!injected)
-		handle_frame(drv, buf + iter.max_length,
-			     len - iter.max_length, datarate, ssi_signal);
-	else
-		handle_tx_callback(drv->ctx, buf + iter.max_length,
-				   len - iter.max_length, !failed);
-}
-
-
-/*
- * we post-process the filter code later and rewrite
- * this to the offset to the last instruction
- */
-#define PASS	0xFF
-#define FAIL	0xFE
-
-static struct sock_filter msock_filter_insns[] = {
-	/*
-	 * do a little-endian load of the radiotap length field
-	 */
-	/* load lower byte into A */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
-	/* put it into X (== index register) */
-	BPF_STMT(BPF_MISC| BPF_TAX, 0),
-	/* load upper byte into A */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
-	/* left-shift it by 8 */
-	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
-	/* or with X */
-	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
-	/* put result into X */
-	BPF_STMT(BPF_MISC| BPF_TAX, 0),
-
-	/*
-	 * Allow management frames through, this also gives us those
-	 * management frames that we sent ourselves with status
-	 */
-	/* load the lower byte of the IEEE 802.11 frame control field */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
-	/* mask off frame type and version */
-	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
-	/* accept frame if it's both 0, fall through otherwise */
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
-
-	/*
-	 * TODO: add a bit to radiotap RX flags that indicates
-	 * that the sending station is not associated, then
-	 * add a filter here that filters on our DA and that flag
-	 * to allow us to deauth frames to that bad station.
-	 *
-	 * Not a regression -- we didn't do it before either.
-	 */
-
-#if 0
-	/*
-	 * drop non-data frames
-	 */
-	/* load the lower byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
-	/* mask off QoS bit */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
-	/* drop non-data frames */
-	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
-#endif
-	/* load the upper byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
-	/* mask off toDS/fromDS */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
-	/* accept WDS frames */
-	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
-
-	/*
-	 * add header length to index
-	 */
-	/* load the lower byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
-	/* mask off QoS bit */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
-	/* right shift it by 6 to give 0 or 2 */
-	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
-	/* add data frame header length */
-	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
-	/* add index, was start of 802.11 header */
-	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
-	/* move to index, now start of LL header */
-	BPF_STMT(BPF_MISC | BPF_TAX, 0),
-
-	/*
-	 * Accept empty data frames, we use those for
-	 * polling activity.
-	 */
-	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
-
-	/*
-	 * Accept EAPOL frames
-	 */
-	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
-	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
-
-	/* keep these last two statements or change the code below */
-	/* return 0 == "DROP" */
-	BPF_STMT(BPF_RET | BPF_K, 0),
-	/* return ~0 == "keep all" */
-	BPF_STMT(BPF_RET | BPF_K, ~0),
-};
-
-static struct sock_fprog msock_filter = {
-	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
-	.filter = msock_filter_insns,
-};
-
-
-static int add_monitor_filter(int s)
-{
-	int idx;
-
-	/* rewrite all PASS/FAIL jump offsets */
-	for (idx = 0; idx < msock_filter.len; idx++) {
-		struct sock_filter *insn = &msock_filter_insns[idx];
-
-		if (BPF_CLASS(insn->code) == BPF_JMP) {
-			if (insn->code == (BPF_JMP|BPF_JA)) {
-				if (insn->k == PASS)
-					insn->k = msock_filter.len - idx - 2;
-				else if (insn->k == FAIL)
-					insn->k = msock_filter.len - idx - 3;
-			}
-
-			if (insn->jt == PASS)
-				insn->jt = msock_filter.len - idx - 2;
-			else if (insn->jt == FAIL)
-				insn->jt = msock_filter.len - idx - 3;
-
-			if (insn->jf == PASS)
-				insn->jf = msock_filter.len - idx - 2;
-			else if (insn->jf == FAIL)
-				insn->jf = msock_filter.len - idx - 3;
-		}
-	}
-
-	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
-		       &msock_filter, sizeof(msock_filter))) {
-		perror("SO_ATTACH_FILTER");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void nl80211_remove_monitor_interface(
-	struct wpa_driver_nl80211_data *drv)
-{
-	if (drv->monitor_ifidx >= 0) {
-		nl80211_remove_iface(drv, drv->monitor_ifidx);
-		drv->monitor_ifidx = -1;
-	}
-	if (drv->monitor_sock >= 0) {
-		eloop_unregister_read_sock(drv->monitor_sock);
-		close(drv->monitor_sock);
-		drv->monitor_sock = -1;
-	}
-}
-
-
-static int
-nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
-{
-	char buf[IFNAMSIZ];
-	struct sockaddr_ll ll;
-	int optval;
-	socklen_t optlen;
-
-	snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
-	buf[IFNAMSIZ - 1] = '\0';
-
-	drv->monitor_ifidx =
-		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0);
-
-	if (drv->monitor_ifidx < 0)
-		return -1;
-
-	if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
-		goto error;
-
-	memset(&ll, 0, sizeof(ll));
-	ll.sll_family = AF_PACKET;
-	ll.sll_ifindex = drv->monitor_ifidx;
-	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (drv->monitor_sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
-		goto error;
-	}
-
-	if (add_monitor_filter(drv->monitor_sock)) {
-		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
-			   "interface; do filtering in user space");
-		/* This works, but will cost in performance. */
-	}
-
-	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("monitor socket bind");
-		goto error;
-	}
-
-	optlen = sizeof(optval);
-	optval = 20;
-	if (setsockopt
-	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
-		perror("Failed to set socket priority");
-		goto error;
-	}
-
-	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
-				     drv, NULL)) {
-		printf("Could not register monitor read socket\n");
-		goto error;
-	}
-
-	return 0;
- error:
-	nl80211_remove_monitor_interface(drv);
-	return -1;
-}
-
-
-static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-static int wpa_driver_nl80211_hapd_send_eapol(
-	void *priv, const u8 *addr, const u8 *data,
-	size_t data_len, int encrypt, const u8 *own_addr)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct ieee80211_hdr *hdr;
-	size_t len;
-	u8 *pos;
-	int res;
-#if 0 /* FIX */
-	int qos = sta->flags & WPA_STA_WMM;
-#else
-	int qos = 0;
-#endif
-
-	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
-		data_len;
-	hdr = os_zalloc(len);
-	if (hdr == NULL) {
-		printf("malloc() failed for i802_send_data(len=%lu)\n",
-		       (unsigned long) len);
-		return -1;
-	}
-
-	hdr->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
-	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
-	if (encrypt)
-		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-#if 0 /* To be enabled if qos determination is added above */
-	if (qos) {
-		hdr->frame_control |=
-			host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
-	}
-#endif
-
-	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
-	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
-	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
-	pos = (u8 *) (hdr + 1);
-
-#if 0 /* To be enabled if qos determination is added above */
-	if (qos) {
-		/* add an empty QoS header if needed */
-		pos[0] = 0;
-		pos[1] = 0;
-		pos += 2;
-	}
-#endif
-
-	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
-	pos += sizeof(rfc1042_header);
-	WPA_PUT_BE16(pos, ETH_P_PAE);
-	pos += 2;
-	memcpy(pos, data, data_len);
-
-	res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
-			   "failed: %d (%s)",
-			   (unsigned long) len, errno, strerror(errno));
-	}
-	os_free(hdr);
-
-	return res;
-}
-
-
-static u32 sta_flags_nl80211(int flags)
-{
-	u32 f = 0;
-
-	if (flags & WPA_STA_AUTHORIZED)
-		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
-	if (flags & WPA_STA_WMM)
-		f |= BIT(NL80211_STA_FLAG_WME);
-	if (flags & WPA_STA_SHORT_PREAMBLE)
-		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-	if (flags & WPA_STA_MFP)
-		f |= BIT(NL80211_STA_FLAG_MFP);
-
-	return f;
-}
-
-
-static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
-					    int total_flags,
-					    int flags_or, int flags_and)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *flags = NULL;
-	struct nl80211_sta_flag_update upd;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	flags = nlmsg_alloc();
-	if (!flags) {
-		nlmsg_free(msg);
-		return -ENOMEM;
-	}
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-
-	/*
-	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
-	 * can be removed eventually.
-	 */
-	if (total_flags & WPA_STA_AUTHORIZED)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
-
-	if (total_flags & WPA_STA_WMM)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
-
-	if (total_flags & WPA_STA_SHORT_PREAMBLE)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
-
-	if (total_flags & WPA_STA_MFP)
-		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
-
-	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-		goto nla_put_failure;
-
-	os_memset(&upd, 0, sizeof(upd));
-	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
-	upd.set = sta_flags_nl80211(flags_or);
-	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
-
-	nlmsg_free(flags);
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	nlmsg_free(flags);
-	return -ENOBUFS;
-}
-
-
-static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
-				 struct wpa_driver_associate_params *params)
-{
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
-	    wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
-		nl80211_remove_monitor_interface(drv);
-		return -1;
-	}
-
-	/* TODO: setup monitor interface (and add code somewhere to remove this
-	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
-
-	return 0;
-}
-
-
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
-{
-	struct nl_msg *msg;
-	int ret = -1;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_LEAVE_IBSS, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
-				   struct wpa_driver_associate_params *params)
-{
-	struct nl_msg *msg;
-	int ret = -1;
-	int count = 0;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
-
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
-		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
-			   "IBSS mode");
-		return -1;
-	}
-
-retry:
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_JOIN_IBSS, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
-		goto nla_put_failure;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-			  params->ssid, params->ssid_len);
-	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-		params->ssid);
-	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
-	drv->ssid_len = params->ssid_len;
-
-	wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-
-	ret = nl80211_set_conn_keys(params, msg);
-	if (ret)
-		goto nla_put_failure;
-
-	if (params->wpa_ie) {
-		wpa_hexdump(MSG_DEBUG,
-			    "  * Extra IEs for Beacon/Probe Response frames",
-			    params->wpa_ie, params->wpa_ie_len);
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
-			   ret, strerror(-ret));
-		count++;
-		if (ret == -EALREADY && count == 1) {
-			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
-				   "forced leave");
-			nl80211_leave_ibss(drv);
-			nlmsg_free(msg);
-			goto retry;
-		}
-
-		goto nla_put_failure;
-	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_connect(
-	struct wpa_driver_nl80211_data *drv,
-	struct wpa_driver_associate_params *params)
-{
-	struct nl_msg *msg;
-	enum nl80211_auth_type type;
-	int ret = 0;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CONNECT, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
-	}
-	if (params->freq) {
-		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-	}
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
-		if (params->ssid_len > sizeof(drv->ssid))
-			goto nla_put_failure;
-		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
-		drv->ssid_len = params->ssid_len;
-	}
-	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
-	if (params->wpa_ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
-
-	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
-	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
-		type = NL80211_AUTHTYPE_SHARED_KEY;
-	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
-		type = NL80211_AUTHTYPE_NETWORK_EAP;
-	else if (params->auth_alg & WPA_AUTH_ALG_FT)
-		type = NL80211_AUTHTYPE_FT;
-	else
-		goto nla_put_failure;
-
-	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
-
-	if (params->wpa_ie && params->wpa_ie_len) {
-		enum nl80211_wpa_versions ver;
-
-		if (params->wpa_ie[0] == WLAN_EID_RSN)
-			ver = NL80211_WPA_VERSION_2;
-		else
-			ver = NL80211_WPA_VERSION_1;
-
-		wpa_printf(MSG_DEBUG, "  * WPA Version %d", ver);
-		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
-	}
-
-	if (params->pairwise_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->pairwise_suite) {
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
-	}
-
-	if (params->group_suite != CIPHER_NONE) {
-		int cipher;
-
-		switch (params->group_suite) {
-		case CIPHER_WEP40:
-			cipher = WLAN_CIPHER_SUITE_WEP40;
-			break;
-		case CIPHER_WEP104:
-			cipher = WLAN_CIPHER_SUITE_WEP104;
-			break;
-		case CIPHER_CCMP:
-			cipher = WLAN_CIPHER_SUITE_CCMP;
-			break;
-		case CIPHER_TKIP:
-		default:
-			cipher = WLAN_CIPHER_SUITE_TKIP;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK) {
-		int mgmt = WLAN_AKM_SUITE_PSK;
-
-		switch (params->key_mgmt_suite) {
-		case KEY_MGMT_802_1X:
-			mgmt = WLAN_AKM_SUITE_8021X;
-			break;
-		case KEY_MGMT_PSK:
-		default:
-			mgmt = WLAN_AKM_SUITE_PSK;
-			break;
-		}
-		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
-	}
-
-	ret = nl80211_set_conn_keys(params, msg);
-	if (ret)
-		goto nla_put_failure;
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-
-}
-
-
-static int wpa_driver_nl80211_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1;
-	struct nl_msg *msg;
-
-	if (params->mode == IEEE80211_MODE_AP)
-		return wpa_driver_nl80211_ap(drv, params);
-
-	if (params->mode == IEEE80211_MODE_IBSS)
-		return wpa_driver_nl80211_ibss(drv, params);
-
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-		if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
-			return -1;
-		return wpa_driver_nl80211_connect(drv, params);
-	}
-
-	drv->associated = 0;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
-		   drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_ASSOCIATE, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
-	}
-	if (params->freq) {
-		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-		drv->assoc_freq = params->freq;
-	} else
-		drv->assoc_freq = 0;
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
-		if (params->ssid_len > sizeof(drv->ssid))
-			goto nla_put_failure;
-		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
-		drv->ssid_len = params->ssid_len;
-	}
-	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
-	if (params->wpa_ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
-
-#ifdef CONFIG_IEEE80211W
-	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
-		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
-#endif /* CONFIG_IEEE80211W */
-
-	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
-
-	if (params->prev_bssid) {
-		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
-			   MAC2STR(params->prev_bssid));
-		NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
-			params->prev_bssid);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		nl80211_dump_scan(drv);
-		goto nla_put_failure;
-	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Association request send "
-		   "successfully");
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
-			    int ifindex, int mode)
-{
-	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_INTERFACE, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (!ret)
-		return 0;
-nla_put_failure:
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
-		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1;
-	int nlmode;
-
-	switch (mode) {
-	case 0:
-		nlmode = NL80211_IFTYPE_STATION;
-		break;
-	case 1:
-		nlmode = NL80211_IFTYPE_ADHOC;
-		break;
-	case 2:
-		nlmode = NL80211_IFTYPE_AP;
-		break;
-	default:
-		return -1;
-	}
-
-	if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
-		drv->nlmode = nlmode;
-		ret = 0;
-		goto done;
-	}
-
-	if (nlmode == drv->nlmode) {
-		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
-			   "requested mode - ignore error");
-		ret = 0;
-		goto done; /* Already in the requested mode */
-	}
-
-	/* mac80211 doesn't allow mode changes while the device is up, so
-	 * take the device down, try to set the mode again, and bring the
-	 * device back up.
-	 */
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == 0) {
-		/* Try to set the mode again while the interface is down */
-		ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
-		if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
-			ret = -1;
-	}
-
-	if (!ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
-			   "interface is down");
-		drv->nlmode = nlmode;
-	}
-
-done:
-	if (!ret && nlmode == NL80211_IFTYPE_AP) {
-		/* Setup additional AP mode functionality if needed */
-		if (drv->monitor_ifidx < 0 &&
-		    nl80211_create_monitor_interface(drv))
-			return -1;
-	} else if (!ret && nlmode != NL80211_IFTYPE_AP) {
-		/* Remove additional AP mode functionality */
-		nl80211_remove_monitor_interface(drv);
-		bss->beacon_set = 0;
-	}
-
-	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
-			   "from %d failed", nlmode, drv->nlmode);
-
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_get_capa(void *priv,
-				       struct wpa_driver_capa *capa)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (!drv->has_capability)
-		return -1;
-	os_memcpy(capa, &drv->capa, sizeof(*capa));
-	return 0;
-}
-
-
-static int wpa_driver_nl80211_set_operstate(void *priv, int state)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-
-	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
-		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
-	drv->operstate = state;
-	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
-				      state ? IF_OPER_UP : IF_OPER_DORMANT);
-}
-
-
-static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	struct nl80211_sta_flag_update upd;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
-
-	os_memset(&upd, 0, sizeof(upd));
-	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
-	if (authorized)
-		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
-	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-#ifdef HOSTAPD
-
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-	int *old;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
-		   ifidx);
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == 0) {
-			drv->if_indices[i] = ifidx;
-			return;
-		}
-	}
-
-	if (drv->if_indices != drv->default_if_indices)
-		old = drv->if_indices;
-	else
-		old = NULL;
-
-	drv->if_indices = os_realloc(old,
-				     sizeof(int) * (drv->num_if_indices + 1));
-	if (!drv->if_indices) {
-		if (!old)
-			drv->if_indices = drv->default_if_indices;
-		else
-			drv->if_indices = old;
-		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
-			   "interfaces");
-		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
-		return;
-	} else if (!old)
-		os_memcpy(drv->if_indices, drv->default_if_indices,
-			  sizeof(drv->default_if_indices));
-	drv->if_indices[drv->num_if_indices] = ifidx;
-	drv->num_if_indices++;
-}
-
-
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++) {
-		if (drv->if_indices[i] == ifidx) {
-			drv->if_indices[i] = 0;
-			break;
-		}
-	}
-}
-
-
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
-	int i;
-
-	for (i = 0; i < drv->num_if_indices; i++)
-		if (drv->if_indices[i] == ifidx)
-			return 1;
-
-	return 0;
-}
-
-
-static inline int min_int(int a, int b)
-{
-	if (a < b)
-		return a;
-	return b;
-}
-
-
-static int get_key_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	/*
-	 * TODO: validate the key index and mac address!
-	 * Otherwise, there's a race condition as soon as
-	 * the kernel starts sending key notifications.
-	 */
-
-	if (tb[NL80211_ATTR_KEY_SEQ])
-		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
-		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
-	return NL_SKIP;
-}
-
-
-static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
-			   int idx, u8 *seq)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_KEY, 0);
-
-	if (addr)
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
-
-	memset(seq, 0, 6);
-
-	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
-			      int mode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	u8 rates[NL80211_MAX_SUPP_RATES];
-	u8 rates_len = 0;
-	int i;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
-		rates[rates_len++] = basic_rates[i] / 5;
-
-	NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-#endif /* HOSTAPD */
-
-
-/* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
-					   freq->sec_channel_offset);
-}
-
-
-#ifdef HOSTAPD
-
-static int i802_set_rts(void *priv, int rts)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-	u32 val;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	if (rts >= 2347)
-		val = (u32) -1;
-	else
-		val = rts;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (!ret)
-		return 0;
-nla_put_failure:
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
-		   "%d (%s)", rts, ret, strerror(-ret));
-	return ret;
-}
-
-
-static int i802_set_frag(void *priv, int frag)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-	u32 val;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	if (frag >= 2346)
-		val = (u32) -1;
-	else
-		val = frag;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (!ret)
-		return 0;
-nla_put_failure:
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
-		   "%d: %d (%s)", frag, ret, strerror(-ret));
-	return ret;
-}
-
-
-static int i802_flush(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
-
-	/*
-	 * XXX: FIX! this needs to flush all VLANs too
-	 */
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int get_sta_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct hostap_sta_driver_data *data = arg;
-	struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
-	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
-		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
-		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
-	};
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	/*
-	 * TODO: validate the interface and mac address!
-	 * Otherwise, there's a race condition as soon as
-	 * the kernel starts sending station notifications.
-	 */
-
-	if (!tb[NL80211_ATTR_STA_INFO]) {
-		wpa_printf(MSG_DEBUG, "sta stats missing!");
-		return NL_SKIP;
-	}
-	if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
-			     tb[NL80211_ATTR_STA_INFO],
-			     stats_policy)) {
-		wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
-		return NL_SKIP;
-	}
-
-	if (stats[NL80211_STA_INFO_INACTIVE_TIME])
-		data->inactive_msec =
-			nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
-	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_PACKETS])
-		data->rx_packets =
-			nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
-	if (stats[NL80211_STA_INFO_TX_PACKETS])
-		data->tx_packets =
-			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
-
-	return NL_SKIP;
-}
-
-static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
-			      const u8 *addr)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	os_memset(data, 0, sizeof(*data));
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_STATION, 0);
-
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
-				    int cw_min, int cw_max, int burst_time)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	struct nlattr *txq, *params;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
-	if (!txq)
-		goto nla_put_failure;
-
-	/* We are only sending parameters for a single TXQ at a time */
-	params = nla_nest_start(msg, 1);
-	if (!params)
-		goto nla_put_failure;
-
-	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue);
-	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
-	 * 32 usec, so need to convert the value here. */
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
-	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
-
-	nla_nest_end(msg, params);
-
-	nla_nest_end(msg, txq);
-
-	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-		return 0;
- nla_put_failure:
-	return -1;
-}
-
-
-static int i802_set_bss(void *priv, int cts, int preamble, int slot)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	if (cts >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
-	if (preamble >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
-	if (slot >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_cts_protect(void *priv, int value)
-{
-	return i802_set_bss(priv, value, -1, -1);
-}
-
-
-static int i802_set_preamble(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, value, -1);
-}
-
-
-static int i802_set_short_slot_time(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, -1, value);
-}
-
-
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
-			     const char *ifname, int vlan_id)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
-		    if_nametoindex(ifname));
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
-			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
-			   MAC2STR(addr), ifname, vlan_id, ret,
-			   strerror(-ret));
-	}
- nla_put_failure:
-	return ret;
-}
-
-
-static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	char name[IFNAMSIZ + 1];
-
-	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
-	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
-		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
-	if (val) {
-		if (nl80211_create_iface(drv, name, NL80211_IFTYPE_AP_VLAN,
-					 NULL, 1) < 0)
-			return -1;
-		linux_set_iface_flags(drv->ioctl_sock, name, 1);
-		return i802_set_sta_vlan(priv, addr, name, 0);
-	} else {
-		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
-		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
-						    name);
-	}
-}
-
-
-static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	struct sockaddr_ll lladdr;
-	unsigned char buf[3000];
-	int len;
-	socklen_t fromlen = sizeof(lladdr);
-
-	len = recvfrom(sock, buf, sizeof(buf), 0,
-		       (struct sockaddr *)&lladdr, &fromlen);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	if (have_ifidx(drv, lladdr.sll_ifindex))
-		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
-}
-
-
-static int i802_get_inact_sec(void *priv, const u8 *addr)
-{
-	struct hostap_sta_driver_data data;
-	int ret;
-
-	data.inactive_msec = (unsigned long) -1;
-	ret = i802_read_sta_data(priv, &data, addr);
-	if (ret || data.inactive_msec == (unsigned long) -1)
-		return -1;
-	return data.inactive_msec / 1000;
-}
-
-
-static int i802_sta_clear_stats(void *priv, const u8 *addr)
-{
-#if 0
-	/* TODO */
-#endif
-	return 0;
-}
-
-
-static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			   int reason)
-{
-	struct i802_bss *bss = priv;
-	struct ieee80211_mgmt mgmt;
-
-	memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_DEAUTH);
-	memcpy(mgmt.da, addr, ETH_ALEN);
-	memcpy(mgmt.sa, own_addr, ETH_ALEN);
-	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
-	mgmt.u.deauth.reason_code = host_to_le16(reason);
-	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
-					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.deauth));
-}
-
-
-static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-			     int reason)
-{
-	struct i802_bss *bss = priv;
-	struct ieee80211_mgmt mgmt;
-
-	memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_DISASSOC);
-	memcpy(mgmt.da, addr, ETH_ALEN);
-	memcpy(mgmt.sa, own_addr, ETH_ALEN);
-	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
-	mgmt.u.disassoc.reason_code = host_to_le16(reason);
-	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
-					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.disassoc));
-}
-
-
-static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
-			     const char *brname, const char *ifname)
-{
-	int ifindex;
-	char in_br[IFNAMSIZ];
-
-	os_strlcpy(drv->brname, brname, IFNAMSIZ);
-	ifindex = if_nametoindex(brname);
-	if (ifindex == 0) {
-		/*
-		 * Bridge was configured, but the bridge device does
-		 * not exist. Try to add it now.
-		 */
-		if (linux_br_add(drv->ioctl_sock, brname) < 0) {
-			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
-				   "bridge interface %s: %s",
-				   brname, strerror(errno));
-			return -1;
-		}
-		drv->added_bridge = 1;
-		add_ifidx(drv, if_nametoindex(brname));
-	}
-
-	if (linux_br_get(in_br, ifname) == 0) {
-		if (os_strcmp(in_br, brname) == 0)
-			return 0; /* already in the bridge */
-
-		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
-			   "bridge %s", ifname, in_br);
-		if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
-			wpa_printf(MSG_ERROR, "nl80211: Failed to "
-				   "remove interface %s from bridge "
-				   "%s: %s",
-				   ifname, brname, strerror(errno));
-			return -1;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
-		   ifname, brname);
-	if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
-			   "into bridge %s: %s",
-			   ifname, brname, strerror(errno));
-		return -1;
-	}
-	drv->added_if_into_bridge = 1;
-
-	return 0;
-}
-
-
-static void *i802_init(struct hostapd_data *hapd,
-		       struct wpa_init_params *params)
-{
-	struct wpa_driver_nl80211_data *drv;
-	struct i802_bss *bss;
-	size_t i;
-	char brname[IFNAMSIZ];
-	int ifindex, br_ifindex;
-	int br_added = 0;
-
-	bss = wpa_driver_nl80211_init(hapd, params->ifname);
-	if (bss == NULL)
-		return NULL;
-
-	drv = bss->drv;
-	if (linux_br_get(brname, params->ifname) == 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
-			   params->ifname, brname);
-		br_ifindex = if_nametoindex(brname);
-	} else {
-		brname[0] = '\0';
-		br_ifindex = 0;
-	}
-
-	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
-	drv->if_indices = drv->default_if_indices;
-	for (i = 0; i < params->num_bridge; i++) {
-		if (params->bridge[i]) {
-			ifindex = if_nametoindex(params->bridge[i]);
-			if (ifindex)
-				add_ifidx(drv, ifindex);
-			if (ifindex == br_ifindex)
-				br_added = 1;
-		}
-	}
-	if (!br_added && br_ifindex &&
-	    (params->num_bridge == 0 || !params->bridge[0]))
-		add_ifidx(drv, br_ifindex);
-
-	/* start listening for EAPOL on the default AP interface */
-	add_ifidx(drv, drv->ifindex);
-
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
-		goto failed;
-
-	if (params->bssid) {
-		if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
-				       params->bssid))
-			goto failed;
-	}
-
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
-			   "into AP mode", bss->ifname);
-		goto failed;
-	}
-
-	if (params->num_bridge && params->bridge[0] &&
-	    i802_check_bridge(drv, params->bridge[0], params->ifname) < 0)
-		goto failed;
-
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
-		goto failed;
-
-	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
-	if (drv->eapol_sock < 0) {
-		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
-		goto failed;
-	}
-
-	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
-	{
-		printf("Could not register read socket for eapol\n");
-		goto failed;
-	}
-
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
-		goto failed;
-
-	return bss;
-
-failed:
-	nl80211_remove_monitor_interface(drv);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-
-	os_free(drv);
-	return NULL;
-}
-
-
-static void i802_deinit(void *priv)
-{
-	wpa_driver_nl80211_deinit(priv);
-}
-
-#endif /* HOSTAPD */
-
-
-static enum nl80211_iftype wpa_driver_nl80211_if_type(
-	enum wpa_driver_if_type type)
-{
-	switch (type) {
-	case WPA_IF_STATION:
-		return NL80211_IFTYPE_STATION;
-	case WPA_IF_AP_VLAN:
-		return NL80211_IFTYPE_AP_VLAN;
-	case WPA_IF_AP_BSS:
-		return NL80211_IFTYPE_AP;
-	}
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
-				     const char *ifname, const u8 *addr,
-				     void *bss_ctx, void **drv_priv,
-				     char *force_ifname, u8 *if_addr)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ifidx;
-#ifdef HOSTAPD
-	struct i802_bss *new_bss = NULL;
-
-	if (type == WPA_IF_AP_BSS) {
-		new_bss = os_zalloc(sizeof(*new_bss));
-		if (new_bss == NULL)
-			return -1;
-	}
-#endif /* HOSTAPD */
-
-	if (addr)
-		os_memcpy(if_addr, addr, ETH_ALEN);
-	ifidx = nl80211_create_iface(drv, ifname,
-				     wpa_driver_nl80211_if_type(type), addr,
-				     0);
-	if (ifidx < 0) {
-#ifdef HOSTAPD
-		os_free(new_bss);
-#endif /* HOSTAPD */
-		return -1;
-	}
-
-	if (!addr &&
-	    linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0)
-		return -1;
-
-#ifdef HOSTAPD
-	if (type == WPA_IF_AP_BSS) {
-		if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
-			nl80211_remove_iface(drv, ifidx);
-			os_free(new_bss);
-			return -1;
-		}
-		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
-		new_bss->ifindex = ifidx;
-		new_bss->drv = drv;
-		new_bss->next = drv->first_bss.next;
-		drv->first_bss.next = new_bss;
-		if (drv_priv)
-			*drv_priv = new_bss;
-	}
-#endif /* HOSTAPD */
-
-	return 0;
-}
-
-
-static int wpa_driver_nl80211_if_remove(void *priv,
-					enum wpa_driver_if_type type,
-					const char *ifname)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ifindex = if_nametoindex(ifname);
-
-	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
-		   __func__, type, ifname, ifindex);
-	if (ifindex <= 0)
-		return -1;
-	nl80211_remove_iface(drv, ifindex);
-
-#ifdef HOSTAPD
-	if (type != WPA_IF_AP_BSS)
-		return 0;
-
-	if (bss != &drv->first_bss) {
-		struct i802_bss *tbss = &drv->first_bss;
-
-		while (tbss) {
-			if (tbss->next != bss)
-				continue;
-
-			tbss->next = bss->next;
-			os_free(bss);
-			break;
-		}
-	}
-#endif /* HOSTAPD */
-
-	return 0;
-}
-
-
-static int cookie_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	u64 *cookie = arg;
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-	if (tb[NL80211_ATTR_COOKIE])
-		*cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
-	return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
-					  const u8 *dst, const u8 *src,
-					  const u8 *bssid,
-					  const u8 *data, size_t data_len)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1;
-	struct nl_msg *msg;
-	u8 *buf;
-	struct ieee80211_hdr *hdr;
-	u64 cookie;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)",
-		   drv->ifindex);
-
-	buf = os_zalloc(24 + data_len);
-	if (buf == NULL)
-		return ret;
-	os_memcpy(buf + 24, data, data_len);
-	hdr = (struct ieee80211_hdr *) buf;
-	hdr->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
-	os_memcpy(hdr->addr1, dst, ETH_ALEN);
-	os_memcpy(hdr->addr2, src, ETH_ALEN);
-	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
-
-	if (drv->nlmode == NL80211_IFTYPE_AP) {
-		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
-		os_free(buf);
-		return ret;
-	}
-
-	msg = nlmsg_alloc();
-	if (!msg) {
-		os_free(buf);
-		return -1;
-	}
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_ACTION, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-	NLA_PUT(msg, NL80211_ATTR_FRAME, 24 + data_len, buf);
-	os_free(buf);
-	buf = NULL;
-
-	cookie = 0;
-	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Action command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-	wpa_printf(MSG_DEBUG, "nl80211: Action TX command accepted; "
-		   "cookie 0x%llx", (long long unsigned int) cookie);
-	drv->send_action_cookie = cookie;
-	ret = 0;
-
-nla_put_failure:
-	os_free(buf);
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
-						unsigned int duration)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret;
-	u64 cookie;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REMAIN_ON_CHANNEL, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
-
-	cookie = 0;
-	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
-	if (ret == 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
-			   "0x%llx for freq=%u MHz duration=%u",
-			   (long long unsigned int) cookie, freq, duration);
-		drv->remain_on_chan_cookie = cookie;
-		return 0;
-	}
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
-		   "(freq=%d): %d (%s)", freq, ret, strerror(-ret));
-nla_put_failure:
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int ret;
-
-	if (!drv->pending_remain_on_chan) {
-		wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
-			   "to cancel");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
-		   "0x%llx",
-		   (long long unsigned int) drv->remain_on_chan_cookie);
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == 0)
-		return 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
-		   "%d (%s)", ret, strerror(-ret));
-nla_put_failure:
-	return -1;
-}
-
-
-static void wpa_driver_nl80211_probe_req_report_timeout(void *eloop_ctx,
-							void *timeout_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	if (drv->monitor_ifidx < 0)
-		return; /* monitor interface already removed */
-
-	if (drv->nlmode != NL80211_IFTYPE_STATION)
-		return; /* not in station mode anymore */
-
-	if (drv->probe_req_report)
-		return; /* reporting enabled */
-
-	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface due to no "
-		   "Probe Request reporting needed anymore");
-	nl80211_remove_monitor_interface(drv);
-}
-
-
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-
-	if (drv->nlmode != NL80211_IFTYPE_STATION) {
-		wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
-			   "allowed in station mode (iftype=%d)",
-			   drv->nlmode);
-		return -1;
-	}
-	drv->probe_req_report = report;
-
-	if (report) {
-		eloop_cancel_timeout(
-			wpa_driver_nl80211_probe_req_report_timeout,
-			drv, NULL);
-		if (drv->monitor_ifidx < 0 &&
-		    nl80211_create_monitor_interface(drv))
-			return -1;
-	} else {
-		/*
-		 * It takes a while to remove the monitor interface, so try to
-		 * avoid doing this if it is needed again shortly. Instead,
-		 * schedule the interface to be removed later if no need for it
-		 * is seen.
-		 */
-		wpa_printf(MSG_DEBUG, "nl80211: Scheduling monitor interface "
-			   "to be removed after 10 seconds of no use");
-		eloop_register_timeout(
-			10, 0, wpa_driver_nl80211_probe_req_report_timeout,
-			drv, NULL);
-	}
-
-	return 0;
-}
-
-
-static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
-				     int ifindex, int disabled)
-{
-	struct nl_msg *msg;
-	struct nlattr *bands, *band;
-	int ret;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_TX_BITRATE_MASK, 0);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-
-	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
-	if (!bands)
-		goto nla_put_failure;
-
-	/*
-	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
-	 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
-	 * rates. All 5 GHz rates are left enabled.
-	 */
-	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
-	if (!band)
-		goto nla_put_failure;
-	NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-		"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-	nla_nest_end(msg, band);
-
-	nla_nest_end(msg, bands);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-	}
-
-	return ret;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	drv->disable_11b_rates = disabled;
-	return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
-static int wpa_driver_nl80211_deinit_ap(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (drv->nlmode != NL80211_IFTYPE_AP)
-		return -1;
-	wpa_driver_nl80211_del_beacon(drv);
-	return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
-}
-
-
-static void wpa_driver_nl80211_resume(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
-			   "resume event");
-	}
-}
-
-
-static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
-				  const u8 *ies, size_t ies_len)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret;
-	u8 *data, *pos;
-	size_t data_len;
-	u8 own_addr[ETH_ALEN];
-
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
-		return -1;
-
-	if (action != 1) {
-		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
-			   "action %d", action);
-		return -1;
-	}
-
-	/*
-	 * Action frame payload:
-	 * Category[1] = 6 (Fast BSS Transition)
-	 * Action[1] = 1 (Fast BSS Transition Request)
-	 * STA Address
-	 * Target AP Address
-	 * FT IEs
-	 */
-
-	data_len = 2 + 2 * ETH_ALEN + ies_len;
-	data = os_malloc(data_len);
-	if (data == NULL)
-		return -1;
-	pos = data;
-	*pos++ = 0x06; /* FT Action category */
-	*pos++ = action;
-	os_memcpy(pos, own_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, target_ap, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, ies, ies_len);
-
-	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
-					     own_addr, drv->bssid,
-					     data, data_len);
-	os_free(data);
-
-	return ret;
-}
-
-
-static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg, *cqm = NULL;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
-		   "hysteresis=%d", threshold, hysteresis);
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_CQM, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
-	cqm = nlmsg_alloc();
-	if (cqm == NULL)
-		return -1;
-
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-	nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
-
-	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
-		return 0;
-	msg = NULL;
-
-nla_put_failure:
-	if (cqm)
-		nlmsg_free(cqm);
-	nlmsg_free(msg);
-	return -1;
-}
-
-
-static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
-			      int encrypt)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
-}
-
-
-const struct wpa_driver_ops wpa_driver_nl80211_ops = {
-	.name = "nl80211",
-	.desc = "Linux nl80211/cfg80211",
-	.get_bssid = wpa_driver_nl80211_get_bssid,
-	.get_ssid = wpa_driver_nl80211_get_ssid,
-	.set_key = wpa_driver_nl80211_set_key,
-	.scan2 = wpa_driver_nl80211_scan,
-	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
-	.deauthenticate = wpa_driver_nl80211_deauthenticate,
-	.disassociate = wpa_driver_nl80211_disassociate,
-	.authenticate = wpa_driver_nl80211_authenticate,
-	.associate = wpa_driver_nl80211_associate,
-	.init = wpa_driver_nl80211_init,
-	.deinit = wpa_driver_nl80211_deinit,
-	.get_capa = wpa_driver_nl80211_get_capa,
-	.set_operstate = wpa_driver_nl80211_set_operstate,
-	.set_supp_port = wpa_driver_nl80211_set_supp_port,
-	.set_country = wpa_driver_nl80211_set_country,
-	.set_beacon = wpa_driver_nl80211_set_beacon,
-	.if_add = wpa_driver_nl80211_if_add,
-	.if_remove = wpa_driver_nl80211_if_remove,
-	.send_mlme = wpa_driver_nl80211_send_mlme,
-	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
-	.sta_add = wpa_driver_nl80211_sta_add,
-	.sta_remove = wpa_driver_nl80211_sta_remove,
-	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
-	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
-#ifdef HOSTAPD
-	.hapd_init = i802_init,
-	.hapd_deinit = i802_deinit,
-	.get_seqnum = i802_get_seqnum,
-	.flush = i802_flush,
-	.read_sta_data = i802_read_sta_data,
-	.sta_deauth = i802_sta_deauth,
-	.sta_disassoc = i802_sta_disassoc,
-	.get_inact_sec = i802_get_inact_sec,
-	.sta_clear_stats = i802_sta_clear_stats,
-	.set_rts = i802_set_rts,
-	.set_frag = i802_set_frag,
-	.set_rate_sets = i802_set_rate_sets,
-	.set_cts_protect = i802_set_cts_protect,
-	.set_preamble = i802_set_preamble,
-	.set_short_slot_time = i802_set_short_slot_time,
-	.set_tx_queue_params = i802_set_tx_queue_params,
-	.set_sta_vlan = i802_set_sta_vlan,
-	.set_wds_sta = i802_set_wds_sta,
-#endif /* HOSTAPD */
-	.set_freq = i802_set_freq,
-	.send_action = wpa_driver_nl80211_send_action,
-	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
-	.cancel_remain_on_channel =
-	wpa_driver_nl80211_cancel_remain_on_channel,
-	.probe_req_report = wpa_driver_nl80211_probe_req_report,
-	.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
-	.deinit_ap = wpa_driver_nl80211_deinit_ap,
-	.resume = wpa_driver_nl80211_resume,
-	.send_ft_action = nl80211_send_ft_action,
-	.signal_monitor = nl80211_signal_monitor,
-	.send_frame = nl80211_send_frame,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_nl80211.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_nl80211.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_nl80211.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_nl80211.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,9313 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2012, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes at sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include "nl80211_copy.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "utils/list.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#include "rfkill.h"
+#include "driver.h"
+
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+#  define SO_WIFI_STATUS	0x0025
+# elif defined(__parisc__)
+#  define SO_WIFI_STATUS	0x4022
+# else
+#  define SO_WIFI_STATUS	41
+# endif
+
+# define SCM_WIFI_STATUS	SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS	4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP	16
+#endif
+
+#ifdef ANDROID
+#include "android_drv.h"
+
+/* system/core/libnl_2 in AOSP does not include nla_put_u32() */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+#endif /* ANDROID */
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#else
+/*
+ * libnl 1.1 has a bug, it tries to allocate socket numbers densely
+ * but when you free a socket again it will mess up its bitmap and
+ * and use the wrong number the next time it needs a socket ID.
+ * Therefore, we wrap the handle alloc/destroy and add our own pid
+ * accounting.
+ */
+static uint32_t port_bitmap[32] = { 0 };
+
+static struct nl_handle *nl80211_handle_alloc(void *cb)
+{
+	struct nl_handle *handle;
+	uint32_t pid = getpid() & 0x3FFFFF;
+	int i;
+
+	handle = nl_handle_alloc_cb(cb);
+
+	for (i = 0; i < 1024; i++) {
+		if (port_bitmap[i / 32] & (1 << (i % 32)))
+			continue;
+		port_bitmap[i / 32] |= 1 << (i % 32);
+		pid += i << 22;
+		break;
+	}
+
+	nl_socket_set_local_port(handle, pid);
+
+	return handle;
+}
+
+static void nl80211_handle_destroy(struct nl_handle *handle)
+{
+	uint32_t port = nl_socket_get_local_port(handle);
+
+	port >>= 22;
+	port_bitmap[port / 32] &= ~(1 << (port % 32));
+
+	nl_handle_destroy(handle);
+}
+#endif /* CONFIG_LIBNL20 */
+
+
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+	struct nl_handle *handle;
+
+	handle = nl80211_handle_alloc(cb);
+	if (handle == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks (%s)", dbg);
+		return NULL;
+	}
+
+	if (genl_connect(handle)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+			   "netlink (%s)", dbg);
+		nl80211_handle_destroy(handle);
+		return NULL;
+	}
+
+	return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_handle **handle)
+{
+	if (*handle == NULL)
+		return;
+	nl80211_handle_destroy(*handle);
+	*handle = NULL;
+}
+
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+struct nl80211_global {
+	struct dl_list interfaces;
+	int if_add_ifindex;
+	struct netlink_data *netlink;
+	struct nl_cb *nl_cb;
+	struct nl_handle *nl;
+	int nl80211_id;
+	int ioctl_sock; /* socket for ioctl() use */
+
+	struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+	struct dl_list list;
+	struct dl_list bsss;
+	struct dl_list drvs;
+
+	struct nl_handle *nl_beacons;
+	struct nl_cb *nl_cb;
+
+	int wiphy_idx;
+};
+
+static void nl80211_global_deinit(void *priv);
+static void wpa_driver_nl80211_deinit(void *priv);
+
+struct i802_bss {
+	struct wpa_driver_nl80211_data *drv;
+	struct i802_bss *next;
+	int ifindex;
+	char ifname[IFNAMSIZ + 1];
+	char brname[IFNAMSIZ];
+	unsigned int beacon_set:1;
+	unsigned int added_if_into_bridge:1;
+	unsigned int added_bridge:1;
+	unsigned int in_deinit:1;
+
+	u8 addr[ETH_ALEN];
+
+	int freq;
+
+	void *ctx;
+	struct nl_handle *nl_preq, *nl_mgmt;
+	struct nl_cb *nl_cb;
+
+	struct nl80211_wiphy_data *wiphy_data;
+	struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+	struct nl80211_global *global;
+	struct dl_list list;
+	struct dl_list wiphy_list;
+	char phyname[32];
+	void *ctx;
+	int ifindex;
+	int if_removed;
+	int if_disabled;
+	int ignore_if_down_event;
+	struct rfkill_data *rfkill;
+	struct wpa_driver_capa capa;
+	int has_capability;
+
+	int operstate;
+
+	int scan_complete_events;
+
+	struct nl_cb *nl_cb;
+
+	u8 auth_bssid[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+	int associated;
+	u8 ssid[32];
+	size_t ssid_len;
+	enum nl80211_iftype nlmode;
+	enum nl80211_iftype ap_scan_as_station;
+	unsigned int assoc_freq;
+
+	int monitor_sock;
+	int monitor_ifidx;
+	int monitor_refcount;
+
+	unsigned int disabled_11b_rates:1;
+	unsigned int pending_remain_on_chan:1;
+	unsigned int in_interface_list:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int scan_for_auth:1;
+	unsigned int retry_auth:1;
+	unsigned int use_monitor:1;
+	unsigned int ignore_next_local_disconnect:1;
+
+	u64 remain_on_chan_cookie;
+	u64 send_action_cookie;
+
+	unsigned int last_mgmt_freq;
+
+	struct wpa_driver_scan_filter *filter_ssids;
+	size_t num_filter_ssids;
+
+	struct i802_bss first_bss;
+
+	int eapol_tx_sock;
+
+#ifdef HOSTAPD
+	int eapol_sock; /* socket for EAPOL frames */
+
+	int default_if_indices[16];
+	int *if_indices;
+	int num_if_indices;
+
+	int last_freq;
+	int last_freq_ht;
+#endif /* HOSTAPD */
+
+	/* From failed authentication command */
+	int auth_freq;
+	u8 auth_bssid_[ETH_ALEN];
+	u8 auth_ssid[32];
+	size_t auth_ssid_len;
+	int auth_alg;
+	u8 *auth_ie;
+	size_t auth_ie_len;
+	u8 auth_wep_key[4][16];
+	size_t auth_wep_key_len[4];
+	int auth_wep_tx_keyidx;
+	int auth_local_state_change;
+	int auth_p2p;
+};
+
+
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
+					    void *timeout_ctx);
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode);
+static int
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+				   const u8 *addr, int cmd, u16 reason_code,
+				   int local_state_change);
+static void nl80211_remove_monitor_interface(
+	struct wpa_driver_nl80211_data *drv);
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+				  unsigned int freq, unsigned int wait,
+				  const u8 *buf, size_t buf_len, u64 *cookie,
+				  int no_cck, int no_ack, int offchanok);
+static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
+#ifdef ANDROID
+static int android_pno_start(struct i802_bss *bss,
+			     struct wpa_driver_scan_params *params);
+static int android_pno_stop(struct i802_bss *bss);
+#endif /* ANDROID */
+
+#ifdef HOSTAPD
+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);
+static int wpa_driver_nl80211_if_remove(void *priv,
+					enum wpa_driver_if_type type,
+					const char *ifname);
+#else /* HOSTAPD */
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	return 0;
+}
+#endif /* HOSTAPD */
+
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+				     int ifindex, int disabled);
+
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
+static int wpa_driver_nl80211_authenticate_retry(
+	struct wpa_driver_nl80211_data *drv);
+
+
+static int is_ap_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_AP ||
+		nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+static int is_sta_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_STATION ||
+		nlmode == NL80211_IFTYPE_P2P_CLIENT);
+}
+
+
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+		nlmode == NL80211_IFTYPE_P2P_GO);
+}
+
+
+struct nl80211_bss_info_arg {
+	struct wpa_driver_nl80211_data *drv;
+	struct wpa_scan_results *res;
+	unsigned int assoc_freq;
+	u8 assoc_bssid[ETH_ALEN];
+};
+
+static int bss_info_handler(struct nl_msg *msg, void *arg);
+
+
+/* nl80211 code */
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+	int *err = arg;
+	*err = 0;
+	return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+	int *ret = arg;
+	*ret = 0;
+	return NL_SKIP;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+			 void *arg)
+{
+	int *ret = arg;
+	*ret = err->error;
+	return NL_SKIP;
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+
+static int send_and_recv(struct nl80211_global *global,
+			 struct nl_handle *nl_handle, struct nl_msg *msg,
+			 int (*valid_handler)(struct nl_msg *, void *),
+			 void *valid_data)
+{
+	struct nl_cb *cb;
+	int err = -ENOMEM;
+
+	cb = nl_cb_clone(global->nl_cb);
+	if (!cb)
+		goto out;
+
+	err = nl_send_auto_complete(nl_handle, msg);
+	if (err < 0)
+		goto out;
+
+	err = 1;
+
+	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+	if (valid_handler)
+		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+			  valid_handler, valid_data);
+
+	while (err > 0)
+		nl_recvmsgs(nl_handle, cb);
+ out:
+	nl_cb_put(cb);
+	nlmsg_free(msg);
+	return err;
+}
+
+
+static int send_and_recv_msgs_global(struct nl80211_global *global,
+				     struct nl_msg *msg,
+				     int (*valid_handler)(struct nl_msg *, void *),
+				     void *valid_data)
+{
+	return send_and_recv(global, global->nl, msg, valid_handler,
+			     valid_data);
+}
+
+
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+			      struct nl_msg *msg,
+			      int (*valid_handler)(struct nl_msg *, void *),
+			      void *valid_data)
+{
+	return send_and_recv(drv->global, drv->global->nl, msg,
+			     valid_handler, valid_data);
+}
+
+
+struct family_data {
+	const char *group;
+	int id;
+};
+
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+	struct family_data *res = arg;
+	struct nlattr *tb[CTRL_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *mcgrp;
+	int i;
+
+	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[CTRL_ATTR_MCAST_GROUPS])
+		return NL_SKIP;
+
+	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
+			  nla_len(mcgrp), NULL);
+		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
+		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
+		    os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
+			       res->group,
+			       nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
+			continue;
+		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+		break;
+	};
+
+	return NL_SKIP;
+}
+
+
+static int nl_get_multicast_id(struct nl80211_global *global,
+			       const char *family, const char *group)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+	struct family_data res = { group, -ENOENT };
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+		    0, 0, CTRL_CMD_GETFAMILY, 0);
+	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+
+	ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
+	msg = NULL;
+	if (ret == 0)
+		ret = res.id;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+			  struct nl_msg *msg, int flags, uint8_t cmd)
+{
+	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
+			   0, flags, cmd, 0);
+}
+
+
+struct wiphy_idx_data {
+	int wiphy_idx;
+};
+
+
+static int netdev_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wiphy_idx_data *info = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_WIPHY])
+		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.wiphy_idx = -1,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
+		return data.wiphy_idx;
+	msg = NULL;
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+				    struct nl80211_wiphy_data *w)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+
+	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
+			   "failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+	struct nl80211_wiphy_data *w = eloop_ctx;
+
+	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
+
+	nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_wiphy_data *w = arg;
+	struct wpa_driver_nl80211_data *drv;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	union wpa_event_data event;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (gnlh->cmd != NL80211_CMD_FRAME) {
+		wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+			   gnlh->cmd);
+		return NL_SKIP;
+	}
+
+	if (!tb[NL80211_ATTR_FRAME])
+		return NL_SKIP;
+
+	dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+			 wiphy_list) {
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+		event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+	}
+
+	return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+	static DEFINE_DL_LIST(nl80211_wiphys);
+	struct nl80211_wiphy_data *w;
+	int wiphy_idx, found = 0;
+	struct i802_bss *tmp_bss;
+
+	if (bss->wiphy_data != NULL)
+		return bss->wiphy_data;
+
+	wiphy_idx = nl80211_get_wiphy_index(bss);
+
+	dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+		if (w->wiphy_idx == wiphy_idx)
+			goto add;
+	}
+
+	/* alloc new one */
+	w = os_zalloc(sizeof(*w));
+	if (w == NULL)
+		return NULL;
+	w->wiphy_idx = wiphy_idx;
+	dl_list_init(&w->bsss);
+	dl_list_init(&w->drvs);
+
+	w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!w->nl_cb) {
+		os_free(w);
+		return NULL;
+	}
+	nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+	nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+		  w);
+
+	w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+					 "wiphy beacons");
+	if (w->nl_beacons == NULL) {
+		os_free(w);
+		return NULL;
+	}
+
+	if (nl80211_register_beacons(bss->drv, w)) {
+		nl_destroy_handles(&w->nl_beacons);
+		os_free(w);
+		return NULL;
+	}
+
+	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+				 nl80211_recv_beacons, w, w->nl_beacons);
+
+	dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+	/* drv entry for this bss already there? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not add it */
+	if (!found)
+		dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+	dl_list_add(&w->bsss, &bss->wiphy_list);
+	bss->wiphy_data = w;
+	return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+	struct nl80211_wiphy_data *w = bss->wiphy_data;
+	struct i802_bss *tmp_bss;
+	int found = 0;
+
+	if (w == NULL)
+		return;
+	bss->wiphy_data = NULL;
+	dl_list_del(&bss->wiphy_list);
+
+	/* still any for this drv present? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not remove it */
+	if (!found)
+		dl_list_del(&bss->drv->wiphy_list);
+
+	if (!dl_list_empty(&w->bsss))
+		return;
+
+	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+	nl_cb_put(w->nl_cb);
+	nl_destroy_handles(&w->nl_beacons);
+	dl_list_del(&w->list);
+	os_free(w);
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!drv->associated)
+		return -1;
+	os_memcpy(bssid, drv->bssid, ETH_ALEN);
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!drv->associated)
+		return -1;
+	os_memcpy(ssid, drv->ssid, drv->ssid_len);
+	return drv->ssid_len;
+}
+
+
+static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
+					  char *buf, size_t len, int del)
+{
+	union wpa_event_data event;
+
+	os_memset(&event, 0, sizeof(event));
+	if (len > sizeof(event.interface_status.ifname))
+		len = sizeof(event.interface_status.ifname) - 1;
+	os_memcpy(event.interface_status.ifname, buf, len);
+	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+		EVENT_INTERFACE_ADDED;
+
+	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+		   del ? "DEL" : "NEW",
+		   event.interface_status.ifname,
+		   del ? "removed" : "added");
+
+	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
+		if (del) {
+			if (drv->if_removed) {
+				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+					   "already set - ignore event");
+				return;
+			}
+			drv->if_removed = 1;
+		} else {
+			if (if_nametoindex(drv->first_bss.ifname) == 0) {
+				wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
+					   "does not exist - ignore "
+					   "RTM_NEWLINK",
+					   drv->first_bss.ifname);
+				return;
+			}
+			if (!drv->if_removed) {
+				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
+					   "already cleared - ignore event");
+				return;
+			}
+			drv->if_removed = 0;
+		}
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
+					 u8 *buf, size_t len)
+{
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
+			    == 0)
+				return 1;
+			else
+				break;
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
+					  int ifindex, u8 *buf, size_t len)
+{
+	if (drv->ifindex == ifindex)
+		return 1;
+
+	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+		drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
+		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
+			   "interface");
+		wpa_driver_nl80211_finish_drv_init(drv);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+	struct wpa_driver_nl80211_data *drv;
+	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))
+			return drv;
+	}
+	return NULL;
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
+						 struct ifinfomsg *ifi,
+						 u8 *buf, size_t len)
+{
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+	u32 brid = 0;
+	char namebuf[IFNAMSIZ];
+
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
+			   "ifindex %d", ifi->ifi_index);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+		   "(%s%s%s%s)",
+		   drv->operstate, ifi->ifi_flags,
+		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) > 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event since interface %s is up", namebuf);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
+		if (drv->ignore_if_down_event) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event generated by mode change");
+			drv->ignore_if_down_event = 0;
+		} else {
+			drv->if_disabled = 1;
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_DISABLED, NULL);
+		}
+	}
+
+	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+				   "event since interface %s is down",
+				   namebuf);
+		} else if (if_nametoindex(drv->first_bss.ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+				   "event since interface %s does not exist",
+				   drv->first_bss.ifname);
+		} else if (drv->if_removed) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+				   "event since interface %s is marked "
+				   "removed", drv->first_bss.ifname);
+		} else {
+			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+			drv->if_disabled = 0;
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
+	}
+
+	/*
+	 * Some drivers send the association event before the operup event--in
+	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+	 * fails. This will hit us when wpa_supplicant does not need to do
+	 * IEEE 802.1X authentication
+	 */
+	if (drv->operstate == 1 &&
+	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+	    !(ifi->ifi_flags & IFF_RUNNING))
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+				       -1, IF_OPER_UP);
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_nl80211_event_link(
+				drv,
+				((char *) attr) + rta_len,
+				attr->rta_len - rta_len, 0);
+		} else if (attr->rta_type == IFLA_MASTER)
+			brid = nla_get_u32((struct nlattr *) attr);
+		attr = RTA_NEXT(attr, attrlen);
+	}
+
+	if (ifi->ifi_family == AF_BRIDGE && brid) {
+		/* device has been added to bridge */
+		if_indextoname(brid, namebuf);
+		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
+			   brid, namebuf);
+		add_ifidx(drv, brid);
+	}
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
+						 struct ifinfomsg *ifi,
+						 u8 *buf, size_t len)
+{
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+	u32 brid = 0;
+
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+			   "foreign ifindex %d", ifi->ifi_index);
+		return;
+	}
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_nl80211_event_link(
+				drv,
+				((char *) attr) + rta_len,
+				attr->rta_len - rta_len, 1);
+		} else if (attr->rta_type == IFLA_MASTER)
+			brid = nla_get_u32((struct nlattr *) attr);
+		attr = RTA_NEXT(attr, attrlen);
+	}
+
+	if (ifi->ifi_family == AF_BRIDGE && brid) {
+		/* device has been removed from bridge */
+		char namebuf[IFNAMSIZ];
+		if_indextoname(brid, namebuf);
+		wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
+			   "%s", brid, namebuf);
+		del_ifidx(drv, brid);
+	}
+}
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+			    const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24 + sizeof(mgmt->u.auth)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+			   "frame");
+		return;
+	}
+
+	os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+	os_memset(&event, 0, sizeof(event));
+	os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+	event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+	event.auth.auth_transaction =
+		le_to_host16(mgmt->u.auth.auth_transaction);
+	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+	if (len > 24 + sizeof(mgmt->u.auth)) {
+		event.auth.ies = mgmt->u.auth.variable;
+		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	int ret;
+	struct nl80211_bss_info_arg arg;
+
+	os_memset(&arg, 0, sizeof(arg));
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto nla_put_failure;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	arg.drv = drv;
+	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+	msg = NULL;
+	if (ret == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
+			   "associated BSS from scan results: %u MHz",
+			   arg.assoc_freq);
+		return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+		   "(%s)", ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	return drv->assoc_freq;
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+			    const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 status;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+			   "frame");
+		return;
+	}
+
+	status = le_to_host16(mgmt->u.assoc_resp.status_code);
+	if (status != WLAN_STATUS_SUCCESS) {
+		os_memset(&event, 0, sizeof(event));
+		event.assoc_reject.bssid = mgmt->bssid;
+		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+			event.assoc_reject.resp_ies =
+				(u8 *) mgmt->u.assoc_resp.variable;
+			event.assoc_reject.resp_ies_len =
+				len - 24 - sizeof(mgmt->u.assoc_resp);
+		}
+		event.assoc_reject.status_code = status;
+
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+		return;
+	}
+
+	drv->associated = 1;
+	os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+
+	os_memset(&event, 0, sizeof(event));
+	if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+		event.assoc_info.resp_ies_len =
+			len - 24 - sizeof(mgmt->u.assoc_resp);
+	}
+
+	event.assoc_info.freq = drv->assoc_freq;
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+			       enum nl80211_commands cmd, struct nlattr *status,
+			       struct nlattr *addr, struct nlattr *req_ie,
+			       struct nlattr *resp_ie)
+{
+	union wpa_event_data event;
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		/*
+		 * Avoid reporting two association events that would confuse
+		 * the core code.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+			   "when using userspace SME", cmd);
+		return;
+	}
+
+	if (cmd == NL80211_CMD_CONNECT)
+		wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+	else if (cmd == NL80211_CMD_ROAM)
+		wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
+	os_memset(&event, 0, sizeof(event));
+	if (cmd == NL80211_CMD_CONNECT &&
+	    nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+		if (addr)
+			event.assoc_reject.bssid = nla_data(addr);
+		if (resp_ie) {
+			event.assoc_reject.resp_ies = nla_data(resp_ie);
+			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+		}
+		event.assoc_reject.status_code = nla_get_u16(status);
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+		return;
+	}
+
+	drv->associated = 1;
+	if (addr)
+		os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+
+	if (req_ie) {
+		event.assoc_info.req_ies = nla_data(req_ie);
+		event.assoc_info.req_ies_len = nla_len(req_ie);
+	}
+	if (resp_ie) {
+		event.assoc_info.resp_ies = nla_data(resp_ie);
+		event.assoc_info.resp_ies_len = nla_len(resp_ie);
+	}
+
+	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+				  struct nlattr *reason, struct nlattr *addr,
+				  struct nlattr *by_ap)
+{
+	union wpa_event_data data;
+	unsigned int locally_generated = by_ap == NULL;
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		/*
+		 * Avoid reporting two disassociation events that could
+		 * confuse the core code.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+			   "event when using userspace SME");
+		return;
+	}
+
+	if (drv->ignore_next_local_disconnect) {
+		drv->ignore_next_local_disconnect = 0;
+		if (locally_generated) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+				   "event triggered during reassociation");
+			return;
+		}
+		wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+			   "disconnect but got another disconnect "
+			   "event first");
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+	drv->associated = 0;
+	os_memset(&data, 0, sizeof(data));
+	if (reason)
+		data.deauth_info.reason_code = nla_get_u16(reason);
+	data.deauth_info.locally_generated = by_ap == NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr *freq, struct nlattr *type)
+{
+	union wpa_event_data data;
+	int ht_enabled = 1;
+	int chan_offset = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+	if (!freq || !type)
+		return;
+
+	switch (nla_get_u32(type)) {
+	case NL80211_CHAN_NO_HT:
+		ht_enabled = 0;
+		break;
+	case NL80211_CHAN_HT20:
+		break;
+	case NL80211_CHAN_HT40PLUS:
+		chan_offset = 1;
+		break;
+	case NL80211_CHAN_HT40MINUS:
+		chan_offset = -1;
+		break;
+	}
+
+	data.ch_switch.freq = nla_get_u32(freq);
+	data.ch_switch.ht_enabled = ht_enabled;
+	data.ch_switch.ch_offset = chan_offset;
+
+	wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+			       enum nl80211_commands cmd, struct nlattr *addr)
+{
+	union wpa_event_data event;
+	enum wpa_event_type ev;
+
+	if (nla_len(addr) != ETH_ALEN)
+		return;
+
+	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+		   cmd, MAC2STR((u8 *) nla_data(addr)));
+
+	if (cmd == NL80211_CMD_AUTHENTICATE)
+		ev = EVENT_AUTH_TIMED_OUT;
+	else if (cmd == NL80211_CMD_ASSOCIATE)
+		ev = EVENT_ASSOC_TIMED_OUT;
+	else
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+	wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
+static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
+			    struct nlattr *freq, struct nlattr *sig,
+			    const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 fc, stype;
+	int ssi_signal = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Frame event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
+		return;
+	}
+
+	fc = le_to_host16(mgmt->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	if (sig)
+		ssi_signal = (s32) nla_get_u32(sig);
+
+	os_memset(&event, 0, sizeof(event));
+	if (freq) {
+		event.rx_action.freq = nla_get_u32(freq);
+		drv->last_mgmt_freq = event.rx_action.freq;
+	}
+	if (stype == WLAN_FC_STYPE_ACTION) {
+		event.rx_action.da = mgmt->da;
+		event.rx_action.sa = mgmt->sa;
+		event.rx_action.bssid = mgmt->bssid;
+		event.rx_action.category = mgmt->u.action.category;
+		event.rx_action.data = &mgmt->u.action.category + 1;
+		event.rx_action.len = frame + len - event.rx_action.data;
+		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
+	} else {
+		event.rx_mgmt.frame = frame;
+		event.rx_mgmt.frame_len = len;
+		event.rx_mgmt.ssi_signal = ssi_signal;
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+	}
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr *cookie, const u8 *frame,
+				      size_t len, struct nlattr *ack)
+{
+	union wpa_event_data event;
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+	if (!is_ap_interface(drv->nlmode)) {
+		u64 cookie_val;
+
+		if (!cookie)
+			return;
+
+		cookie_val = nla_get_u64(cookie);
+		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+			   " cookie=0%llx%s (ack=%d)",
+			   (long long unsigned int) cookie_val,
+			   cookie_val == drv->send_action_cookie ?
+			   " (match)" : " (unknown)", ack != NULL);
+		if (cookie_val != drv->send_action_cookie)
+			return;
+	}
+
+	hdr = (const struct ieee80211_hdr *) frame;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = frame;
+	event.tx_status.data_len = len;
+	event.tx_status.ack = ack != NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+				       enum wpa_event_type type,
+				       const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	const u8 *bssid = NULL;
+	u16 reason_code = 0;
+
+	if (type == EVENT_DEAUTH)
+		wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+	else
+		wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len >= 24) {
+		bssid = mgmt->bssid;
+
+		if (drv->associated != 0 &&
+		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
+		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+			/*
+			 * We have presumably received this deauth as a
+			 * response to a clear_state_mismatch() outgoing
+			 * deauth.  Don't let it take us offline!
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+				   "from Unknown BSSID " MACSTR " -- ignoring",
+				   MAC2STR(bssid));
+			return;
+		}
+	}
+
+	drv->associated = 0;
+	os_memset(&event, 0, sizeof(event));
+
+	/* Note: Same offset for Reason Code in both frame subtypes */
+	if (len >= 24 + sizeof(mgmt->u.deauth))
+		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+	if (type == EVENT_DISASSOC) {
+		event.disassoc_info.locally_generated =
+			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+		event.disassoc_info.addr = bssid;
+		event.disassoc_info.reason_code = reason_code;
+		if (frame + len > mgmt->u.disassoc.variable) {
+			event.disassoc_info.ie = mgmt->u.disassoc.variable;
+			event.disassoc_info.ie_len = frame + len -
+				mgmt->u.disassoc.variable;
+		}
+	} else {
+		event.deauth_info.locally_generated =
+			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
+		event.deauth_info.addr = bssid;
+		event.deauth_info.reason_code = reason_code;
+		if (frame + len > mgmt->u.deauth.variable) {
+			event.deauth_info.ie = mgmt->u.deauth.variable;
+			event.deauth_info.ie_len = frame + len -
+				mgmt->u.deauth.variable;
+		}
+	}
+
+	wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+					 enum wpa_event_type type,
+					 const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 reason_code = 0;
+
+	if (type == EVENT_UNPROT_DEAUTH)
+		wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+	else
+		wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+	if (len < 24)
+		return;
+
+	mgmt = (const struct ieee80211_mgmt *) frame;
+
+	os_memset(&event, 0, sizeof(event));
+	/* Note: Same offset for Reason Code in both frame subtypes */
+	if (len >= 24 + sizeof(mgmt->u.deauth))
+		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+	if (type == EVENT_UNPROT_DISASSOC) {
+		event.unprot_disassoc.sa = mgmt->sa;
+		event.unprot_disassoc.da = mgmt->da;
+		event.unprot_disassoc.reason_code = reason_code;
+	} else {
+		event.unprot_deauth.sa = mgmt->sa;
+		event.unprot_deauth.da = mgmt->da;
+		event.unprot_deauth.reason_code = reason_code;
+	}
+
+	wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event(struct wpa_driver_nl80211_data *drv,
+		       enum nl80211_commands cmd, struct nlattr *frame,
+		       struct nlattr *addr, struct nlattr *timed_out,
+		       struct nlattr *freq, struct nlattr *ack,
+		       struct nlattr *cookie, struct nlattr *sig)
+{
+	if (timed_out && addr) {
+		mlme_timeout_event(drv, cmd, addr);
+		return;
+	}
+
+	if (frame == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
+			   "data", cmd);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
+	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+		    nla_data(frame), nla_len(frame));
+
+	switch (cmd) {
+	case NL80211_CMD_AUTHENTICATE:
+		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_ASSOCIATE:
+		mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_DEAUTHENTICATE:
+		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+					   nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_DISASSOCIATE:
+		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+					   nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_FRAME:
+		mlme_event_mgmt(drv, freq, sig, nla_data(frame),
+				nla_len(frame));
+		break;
+	case NL80211_CMD_FRAME_TX_STATUS:
+		mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+					  nla_len(frame), ack);
+		break;
+	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+					     nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_UNPROT_DISASSOCIATE:
+		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+					     nla_data(frame), nla_len(frame));
+		break;
+	default:
+		break;
+	}
+}
+
+
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
+					   struct nlattr *tb[])
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+	os_memset(&data, 0, sizeof(data));
+	if (tb[NL80211_ATTR_MAC]) {
+		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+			    nla_data(tb[NL80211_ATTR_MAC]),
+			    nla_len(tb[NL80211_ATTR_MAC]));
+		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
+	}
+	if (tb[NL80211_ATTR_KEY_SEQ]) {
+		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+	}
+	if (tb[NL80211_ATTR_KEY_TYPE]) {
+		enum nl80211_key_type key_type =
+			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+		if (key_type == NL80211_KEYTYPE_PAIRWISE)
+			data.michael_mic_failure.unicast = 1;
+	} else
+		data.michael_mic_failure.unicast = 1;
+
+	if (tb[NL80211_ATTR_KEY_IDX]) {
+		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
+	}
+
+	wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr *tb[])
+{
+	if (tb[NL80211_ATTR_MAC] == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
+			   "event");
+		return;
+	}
+	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+	drv->associated = 1;
+	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
+		   MAC2STR(drv->bssid));
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+					 int cancel_event, struct nlattr *tb[])
+{
+	unsigned int freq, chan_type, duration;
+	union wpa_event_data data;
+	u64 cookie;
+
+	if (tb[NL80211_ATTR_WIPHY_FREQ])
+		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	else
+		freq = 0;
+
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+	else
+		chan_type = 0;
+
+	if (tb[NL80211_ATTR_DURATION])
+		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+	else
+		duration = 0;
+
+	if (tb[NL80211_ATTR_COOKIE])
+		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+	else
+		cookie = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
+		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
+		   cancel_event, freq, chan_type, duration,
+		   (long long unsigned int) cookie,
+		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
+
+	if (cookie != drv->remain_on_chan_cookie)
+		return; /* not for us */
+
+	if (cancel_event)
+		drv->pending_remain_on_chan = 0;
+
+	os_memset(&data, 0, sizeof(data));
+	data.remain_on_channel.freq = freq;
+	data.remain_on_channel.duration = duration;
+	wpa_supplicant_event(drv->ctx, cancel_event ?
+			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
+			     EVENT_REMAIN_ON_CHANNEL, &data);
+}
+
+
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+			    struct nlattr *tb[])
+{
+	union wpa_event_data event;
+	struct nlattr *nl;
+	int rem;
+	struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+	int freqs[MAX_REPORT_FREQS];
+	int num_freqs = 0;
+
+	if (drv->scan_for_auth) {
+		drv->scan_for_auth = 0;
+		wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+			   "cfg80211 BSS entry");
+		wpa_driver_nl80211_authenticate_retry(drv);
+		return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	info = &event.scan_info;
+	info->aborted = aborted;
+
+	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+		nla_for_each_nested(nl, tb[NL80211_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);
+			info->num_ssids++;
+			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+				break;
+		}
+	}
+	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+		{
+			freqs[num_freqs] = nla_get_u32(nl);
+			num_freqs++;
+			if (num_freqs == MAX_REPORT_FREQS - 1)
+				break;
+		}
+		info->freqs = freqs;
+		info->num_freqs = num_freqs;
+	}
+	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static int get_link_signal(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
+	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
+		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
+	};
+	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
+	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
+		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
+		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
+		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
+		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
+	};
+	struct wpa_signal_info *sig_change = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[NL80211_ATTR_STA_INFO] ||
+	    nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
+			     tb[NL80211_ATTR_STA_INFO], policy))
+		return NL_SKIP;
+	if (!sinfo[NL80211_STA_INFO_SIGNAL])
+		return NL_SKIP;
+
+	sig_change->current_signal =
+		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
+
+	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
+		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
+				     sinfo[NL80211_STA_INFO_TX_BITRATE],
+				     rate_policy)) {
+			sig_change->current_txrate = 0;
+		} else {
+			if (rinfo[NL80211_RATE_INFO_BITRATE]) {
+				sig_change->current_txrate =
+					nla_get_u16(rinfo[
+					     NL80211_RATE_INFO_BITRATE]) * 100;
+			}
+		}
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+				   struct wpa_signal_info *sig)
+{
+	struct nl_msg *msg;
+
+	sig->current_signal = -9999;
+	sig->current_txrate = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+
+	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int get_link_noise(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+	};
+	struct wpa_signal_info *sig_change = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+		wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
+		return NL_SKIP;
+	}
+
+	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+			     tb[NL80211_ATTR_SURVEY_INFO],
+			     survey_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
+			   "attributes!");
+		return NL_SKIP;
+	}
+
+	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+		return NL_SKIP;
+
+	if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+	    sig_change->frequency)
+		return NL_SKIP;
+
+	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+		return NL_SKIP;
+
+	sig_change->current_noise =
+		(s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+				  struct wpa_signal_info *sig_change)
+{
+	struct nl_msg *msg;
+
+	sig_change->current_noise = 9999;
+	sig_change->frequency = drv->assoc_freq;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+	};
+	struct wpa_scan_results *scan_results = arg;
+	struct wpa_scan_res *scan_res;
+	size_t i;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+		return NL_SKIP;
+	}
+
+	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+			     tb[NL80211_ATTR_SURVEY_INFO],
+			     survey_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+			   "attributes");
+		return NL_SKIP;
+	}
+
+	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+		return NL_SKIP;
+
+	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+		return NL_SKIP;
+
+	for (i = 0; i < scan_results->num; ++i) {
+		scan_res = scan_results->res[i];
+		if (!scan_res)
+			continue;
+		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+		    scan_res->freq)
+			continue;
+		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+			continue;
+		scan_res->noise = (s8)
+			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_scan_results *scan_res)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+				  scan_res);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+			      struct nlattr *tb[])
+{
+	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+	};
+	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+	enum nl80211_cqm_rssi_threshold_event event;
+	union wpa_event_data ed;
+	struct wpa_signal_info sig;
+	int res;
+
+	if (tb[NL80211_ATTR_CQM] == NULL ||
+	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+			     cqm_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
+		return;
+	}
+
+	os_memset(&ed, 0, sizeof(ed));
+
+	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+		if (!tb[NL80211_ATTR_MAC])
+			return;
+		os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+		return;
+	}
+
+	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+		return;
+	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
+		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+			   "event: RSSI high");
+		ed.signal_change.above_threshold = 1;
+	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
+		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+			   "event: RSSI low");
+		ed.signal_change.above_threshold = 0;
+	} else
+		return;
+
+	res = nl80211_get_link_signal(drv, &sig);
+	if (res == 0) {
+		ed.signal_change.current_signal = sig.current_signal;
+		ed.signal_change.current_txrate = sig.current_txrate;
+		wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
+			   sig.current_signal, sig.current_txrate);
+	}
+
+	res = nl80211_get_link_noise(drv, &sig);
+	if (res == 0) {
+		ed.signal_change.current_noise = sig.current_noise;
+		wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+			   sig.current_noise);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
+}
+
+
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr **tb)
+{
+	u8 *addr;
+	union wpa_event_data data;
+
+	if (tb[NL80211_ATTR_MAC] == NULL)
+		return;
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+		u8 *ies = NULL;
+		size_t ies_len = 0;
+		if (tb[NL80211_ATTR_IE]) {
+			ies = nla_data(tb[NL80211_ATTR_IE]);
+			ies_len = nla_len(tb[NL80211_ATTR_IE]);
+		}
+		wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+		drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
+		return;
+	}
+
+	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+	wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr **tb)
+{
+	u8 *addr;
+	union wpa_event_data data;
+
+	if (tb[NL80211_ATTR_MAC] == NULL)
+		return;
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+		   MAC2STR(addr));
+
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+		drv_event_disassoc(drv->ctx, addr);
+		return;
+	}
+
+	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+		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);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+					struct nlattr **tb)
+{
+	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+		[NL80211_REKEY_DATA_KEK] = {
+			.minlen = NL80211_KEK_LEN,
+			.maxlen = NL80211_KEK_LEN,
+		},
+		[NL80211_REKEY_DATA_KCK] = {
+			.minlen = NL80211_KCK_LEN,
+			.maxlen = NL80211_KCK_LEN,
+		},
+		[NL80211_REKEY_DATA_REPLAY_CTR] = {
+			.minlen = NL80211_REPLAY_CTR_LEN,
+			.maxlen = NL80211_REPLAY_CTR_LEN,
+		},
+	};
+	union wpa_event_data data;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+	if (!tb[NL80211_ATTR_REKEY_DATA])
+		return;
+	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+		return;
+	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+		   MAC2STR(data.driver_gtk_rekey.bssid));
+	data.driver_gtk_rekey.replay_ctr =
+		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+		    data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+					  struct nlattr **tb)
+{
+	struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+	static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+		[NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+		[NL80211_PMKSA_CANDIDATE_BSSID] = {
+			.minlen = ETH_ALEN,
+			.maxlen = ETH_ALEN,
+		},
+		[NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+	};
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
+	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+		return;
+	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+		return;
+	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.pmkid_candidate.bssid,
+		  nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+	data.pmkid_candidate.index =
+		nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+	data.pmkid_candidate.preauth =
+		cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+				       struct nlattr **tb)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.client_poll.addr,
+		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+				    struct nlattr **tb)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+	switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+	case NL80211_TDLS_SETUP:
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+			   MACSTR, MAC2STR(data.tdls.peer));
+		data.tdls.oper = TDLS_REQUEST_SETUP;
+		break;
+	case NL80211_TDLS_TEARDOWN:
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+			   MACSTR, MAC2STR(data.tdls.peer));
+		data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+			   "event");
+		return;
+	}
+	if (tb[NL80211_ATTR_REASON_CODE]) {
+		data.tdls.reason_code =
+			nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+				   int wds)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data event;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = bss->addr;
+	event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+	event.rx_from_unknown.wds = wds;
+
+	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+				 struct nlattr **tb)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+	     cmd == NL80211_CMD_SCAN_ABORTED)) {
+		wpa_driver_nl80211_set_mode(&drv->first_bss,
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+	}
+
+	switch (cmd) {
+	case NL80211_CMD_TRIGGER_SCAN:
+		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+		break;
+	case NL80211_CMD_START_SCHED_SCAN:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+		break;
+	case NL80211_CMD_SCHED_SCAN_STOPPED:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+		break;
+	case NL80211_CMD_NEW_SCAN_RESULTS:
+		wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+		drv->scan_complete_events = 1;
+		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+				     drv->ctx);
+		send_scan_event(drv, 0, tb);
+		break;
+	case NL80211_CMD_SCHED_SCAN_RESULTS:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: New sched scan results available");
+		send_scan_event(drv, 0, tb);
+		break;
+	case NL80211_CMD_SCAN_ABORTED:
+		wpa_printf(MSG_DEBUG, "nl80211: 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);
+		break;
+	case NL80211_CMD_AUTHENTICATE:
+	case NL80211_CMD_ASSOCIATE:
+	case NL80211_CMD_DEAUTHENTICATE:
+	case NL80211_CMD_DISASSOCIATE:
+	case NL80211_CMD_FRAME_TX_STATUS:
+	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+	case NL80211_CMD_UNPROT_DISASSOCIATE:
+		mlme_event(drv, cmd, tb[NL80211_ATTR_FRAME],
+			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_COOKIE],
+			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
+		break;
+	case NL80211_CMD_CONNECT:
+	case NL80211_CMD_ROAM:
+		mlme_event_connect(drv, cmd,
+				   tb[NL80211_ATTR_STATUS_CODE],
+				   tb[NL80211_ATTR_MAC],
+				   tb[NL80211_ATTR_REQ_IE],
+				   tb[NL80211_ATTR_RESP_IE]);
+		break;
+	case NL80211_CMD_CH_SWITCH_NOTIFY:
+		mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+		break;
+	case NL80211_CMD_DISCONNECT:
+		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+				      tb[NL80211_ATTR_MAC],
+				      tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
+		break;
+	case NL80211_CMD_MICHAEL_MIC_FAILURE:
+		mlme_event_michael_mic_failure(bss, tb);
+		break;
+	case NL80211_CMD_JOIN_IBSS:
+		mlme_event_join_ibss(drv, tb);
+		break;
+	case NL80211_CMD_REMAIN_ON_CHANNEL:
+		mlme_event_remain_on_channel(drv, 0, tb);
+		break;
+	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+		mlme_event_remain_on_channel(drv, 1, tb);
+		break;
+	case NL80211_CMD_NOTIFY_CQM:
+		nl80211_cqm_event(drv, tb);
+		break;
+	case NL80211_CMD_REG_CHANGE:
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+				     NULL);
+		break;
+	case NL80211_CMD_REG_BEACON_HINT:
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+				     NULL);
+		break;
+	case NL80211_CMD_NEW_STATION:
+		nl80211_new_station_event(drv, tb);
+		break;
+	case NL80211_CMD_DEL_STATION:
+		nl80211_del_station_event(drv, tb);
+		break;
+	case NL80211_CMD_SET_REKEY_OFFLOAD:
+		nl80211_rekey_offload_event(drv, tb);
+		break;
+	case NL80211_CMD_PMKSA_CANDIDATE:
+		nl80211_pmksa_candidate_event(drv, tb);
+		break;
+	case NL80211_CMD_PROBE_CLIENT:
+		nl80211_client_probe_event(drv, tb);
+		break;
+	case NL80211_CMD_TDLS_OPER:
+		nl80211_tdls_oper_event(drv, tb);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+			   "(cmd=%d)", cmd);
+		break;
+	}
+}
+
+
+static int process_drv_event(struct nl_msg *msg, void *arg)
+{
+	struct wpa_driver_nl80211_data *drv = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct i802_bss *bss;
+	int ifidx = -1;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX])
+		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+	for (bss = &drv->first_bss; bss; bss = bss->next) {
+		if (ifidx == -1 || ifidx == bss->ifindex) {
+			do_process_drv_event(bss, gnlh->cmd, tb);
+			return NL_SKIP;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
+		   "interface (ifindex %d)", gnlh->cmd, ifidx);
+
+	return NL_SKIP;
+}
+
+
+static int process_global_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_global *global = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct wpa_driver_nl80211_data *drv, *tmp;
+	int ifidx = -1;
+	struct i802_bss *bss;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX])
+		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+	dl_list_for_each_safe(drv, tmp, &global->interfaces,
+			      struct wpa_driver_nl80211_data, list) {
+		for (bss = &drv->first_bss; bss; bss = bss->next) {
+			if (ifidx == -1 || ifidx == bss->ifindex) {
+				do_process_drv_event(bss, gnlh->cmd, tb);
+				return NL_SKIP;
+			}
+		}
+	}
+
+	return NL_SKIP;
+}
+
+
+static int process_bss_event(struct nl_msg *msg, void *arg)
+{
+	struct i802_bss *bss = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	switch (gnlh->cmd) {
+	case NL80211_CMD_FRAME:
+	case NL80211_CMD_FRAME_TX_STATUS:
+		mlme_event(bss->drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+			   tb[NL80211_ATTR_COOKIE],
+			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
+		break;
+	case NL80211_CMD_UNEXPECTED_FRAME:
+		nl80211_spurious_frame(bss, tb, 0);
+		break;
+	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+		nl80211_spurious_frame(bss, tb, 1);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+			   "(cmd=%d)", gnlh->cmd);
+		break;
+	}
+
+	return NL_SKIP;
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+					     void *handle)
+{
+	struct nl_cb *cb = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+
+	nl_recvmsgs(handle, cb);
+}
+
+
+/**
+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
+ * @priv: driver_nl80211 private data
+ * @alpha2_arg: country to which to switch to
+ * Returns: 0 on success, -1 on failure
+ *
+ * This asks nl80211 to set the regulatory domain for given
+ * country ISO / IEC alpha2.
+ */
+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	char alpha2[3];
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	alpha2[0] = alpha2_arg[0];
+	alpha2[1] = alpha2_arg[1];
+	alpha2[2] = '\0';
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
+
+	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+	if (send_and_recv_msgs(drv, msg, NULL, NULL))
+		return -EINVAL;
+	return 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return -EINVAL;
+}
+
+
+struct wiphy_info_data {
+	struct wpa_driver_capa *capa;
+
+	unsigned int error:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int monitor_supported:1;
+};
+
+
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+	unsigned int prot = 0;
+
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+	return prot;
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wiphy_info_data *info = arg;
+	int p2p_go_supported = 0, p2p_client_supported = 0;
+	int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
+	int auth_supported = 0, connect_supported = 0;
+	struct wpa_driver_capa *capa = info->capa;
+	static struct nla_policy
+	iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+		[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+		[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+		[NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+		[NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+	},
+	iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+		[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+	};
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+		capa->max_scan_ssids =
+			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+		capa->max_sched_scan_ssids =
+			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+		capa->max_match_sets =
+			nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
+		struct nlattr *nl_mode;
+		int i;
+		nla_for_each_nested(nl_mode,
+				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
+			switch (nla_type(nl_mode)) {
+			case NL80211_IFTYPE_AP:
+				capa->flags |= WPA_DRIVER_FLAGS_AP;
+				break;
+			case NL80211_IFTYPE_P2P_GO:
+				p2p_go_supported = 1;
+				break;
+			case NL80211_IFTYPE_P2P_CLIENT:
+				p2p_client_supported = 1;
+				break;
+			case NL80211_IFTYPE_MONITOR:
+				info->monitor_supported = 1;
+				break;
+			}
+		}
+	}
+
+	if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+		struct nlattr *nl_combi;
+		int rem_combi;
+
+		nla_for_each_nested(nl_combi,
+				    tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
+				    rem_combi) {
+			struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+			struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+			struct nlattr *nl_limit, *nl_mode;
+			int err, rem_limit, rem_mode;
+			int combination_has_p2p = 0, combination_has_mgd = 0;
+
+			err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+					       nl_combi,
+					       iface_combination_policy);
+			if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+			    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+			    !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+				goto broken_combination;
+
+			nla_for_each_nested(nl_limit,
+					    tb_comb[NL80211_IFACE_COMB_LIMITS],
+					    rem_limit) {
+				err = nla_parse_nested(tb_limit,
+						       MAX_NL80211_IFACE_LIMIT,
+						       nl_limit,
+						       iface_limit_policy);
+				if (err ||
+				    !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+					goto broken_combination;
+
+				nla_for_each_nested(
+					nl_mode,
+					tb_limit[NL80211_IFACE_LIMIT_TYPES],
+					rem_mode) {
+					int ift = nla_type(nl_mode);
+					if (ift == NL80211_IFTYPE_P2P_GO ||
+					    ift == NL80211_IFTYPE_P2P_CLIENT)
+						combination_has_p2p = 1;
+					if (ift == NL80211_IFTYPE_STATION)
+						combination_has_mgd = 1;
+				}
+				if (combination_has_p2p && combination_has_mgd)
+					break;
+			}
+
+			if (combination_has_p2p && combination_has_mgd) {
+				p2p_concurrent = 1;
+				if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+					p2p_multichan_concurrent = 1;
+				break;
+			}
+
+broken_combination:
+			;
+		}
+	}
+
+	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+		struct nlattr *nl_cmd;
+		int i;
+
+		nla_for_each_nested(nl_cmd,
+				    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
+			switch (nla_get_u32(nl_cmd)) {
+			case NL80211_CMD_AUTHENTICATE:
+				auth_supported = 1;
+				break;
+			case NL80211_CMD_CONNECT:
+				connect_supported = 1;
+				break;
+			case NL80211_CMD_START_SCHED_SCAN:
+				capa->sched_scan_supported = 1;
+				break;
+			case NL80211_CMD_PROBE_CLIENT:
+				info->poll_command_supported = 1;
+				break;
+			}
+		}
+	}
+
+	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+			   "off-channel TX");
+		capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+	}
+
+	if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+		capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+	}
+
+	/* default to 5000 since early versions of mac80211 don't set it */
+	capa->max_remain_on_chan = 5000;
+
+	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+	if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
+		capa->max_remain_on_chan =
+			nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+	if (auth_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_SME;
+	else if (!connect_supported) {
+		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+			   "authentication/association or connect commands");
+		info->error = 1;
+	}
+
+	if (p2p_go_supported && p2p_client_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+	if (p2p_concurrent) {
+		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+			   "interface (driver advertised support)");
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+
+		if (p2p_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+				   "concurrent (driver advertised support)");
+			capa->flags |=
+				WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+		}
+	}
+
+	if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+		if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+			wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+			capa->flags |=
+				WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+		}
+	}
+
+	if (tb[NL80211_ATTR_DEVICE_AP_SME])
+		info->device_ap_sme = 1;
+
+	if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+		u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+		if (flags & NL80211_FEATURE_SK_TX_STATUS)
+			info->data_tx_status = 1;
+
+		if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+			capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+		if (flags & NL80211_FEATURE_SAE)
+			capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+		if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+			capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+	}
+
+	if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+		int protocols =
+			nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+		wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response "
+			   "offload in AP mode");
+		capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+		capa->probe_resp_offloads =
+			probe_resp_offload_support(protocols);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+				       struct wiphy_info_data *info)
+{
+	struct nl_msg *msg;
+
+	os_memset(info, 0, sizeof(*info));
+	info->capa = &drv->capa;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
+
+	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
+		return 0;
+	msg = NULL;
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+{
+	struct wiphy_info_data info;
+	if (wpa_driver_nl80211_get_info(drv, &info))
+		return -1;
+
+	if (info.error)
+		return -1;
+
+	drv->has_capability = 1;
+	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
+	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+		WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP |
+		WPA_DRIVER_CAPA_ENC_CCMP;
+	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+		WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+
+	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+	if (!info.device_ap_sme) {
+		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+		/*
+		 * No AP SME is currently assumed to also indicate no AP MLME
+		 * in the driver/firmware.
+		 */
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+	}
+
+	drv->device_ap_sme = info.device_ap_sme;
+	drv->poll_command_supported = info.poll_command_supported;
+	drv->data_tx_status = info.data_tx_status;
+
+	/*
+	 * 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;
+		}
+	}
+
+	/*
+	 * If we aren't going to use monitor interfaces, but the
+	 * driver doesn't support data TX status, we won't get TX
+	 * status for EAPOL frames.
+	 */
+	if (!drv->use_monitor && !info.data_tx_status)
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+	return 0;
+}
+
+
+#ifdef ANDROID
+static int android_genl_ctrl_resolve(struct nl_handle *handle,
+				     const char *name)
+{
+	/*
+	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+	 * need to work around that.
+	 */
+	struct nl_cache *cache = NULL;
+	struct genl_family *nl80211 = NULL;
+	int id = -1;
+
+	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+			   "netlink cache");
+		goto fail;
+	}
+
+	nl80211 = genl_ctrl_search_by_name(cache, name);
+	if (nl80211 == NULL)
+		goto fail;
+
+	id = genl_family_get_id(nl80211);
+
+fail:
+	if (nl80211)
+		genl_family_put(nl80211);
+	if (cache)
+		nl_cache_free(cache);
+
+	return id;
+}
+#define genl_ctrl_resolve android_genl_ctrl_resolve
+#endif /* ANDROID */
+
+
+static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
+{
+	int ret;
+
+	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (global->nl_cb == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks");
+		return -1;
+	}
+
+	global->nl = nl_create_handle(global->nl_cb, "nl");
+	if (global->nl == NULL)
+		goto err;
+
+	global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+	if (global->nl80211_id < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+			   "found");
+		goto err;
+	}
+
+	global->nl_event = nl_create_handle(global->nl_cb, "event");
+	if (global->nl_event == NULL)
+		goto err;
+
+	ret = nl_get_multicast_id(global, "nl80211", "scan");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_event, ret);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+			   "membership for scan events: %d (%s)",
+			   ret, strerror(-ret));
+		goto err;
+	}
+
+	ret = nl_get_multicast_id(global, "nl80211", "mlme");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_event, ret);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+			   "membership for mlme events: %d (%s)",
+			   ret, strerror(-ret));
+		goto err;
+	}
+
+	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
+	if (ret >= 0)
+		ret = nl_socket_add_membership(global->nl_event, ret);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
+			   "membership for regulatory events: %d (%s)",
+			   ret, strerror(-ret));
+		/* Continue without regulatory events */
+	}
+
+	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_global_event, global);
+
+	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
+				 wpa_driver_nl80211_event_receive,
+				 global->nl_cb, global->nl_event);
+
+	return 0;
+
+err:
+	nl_destroy_handles(&global->nl_event);
+	nl_destroy_handles(&global->nl);
+	nl_cb_put(global->nl_cb);
+	global->nl_cb = NULL;
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+{
+	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!drv->nl_cb) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
+		return -1;
+	}
+
+	nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_drv_event, drv);
+
+	return 0;
+}
+
+
+static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
+	/*
+	 * This may be for any interface; use ifdown event to disable
+	 * interface.
+	 */
+}
+
+
+static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
+{
+	struct wpa_driver_nl80211_data *drv = ctx;
+	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
+	if (linux_set_iface_flags(drv->global->ioctl_sock,
+				  drv->first_bss.ifname, 1)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
+			   "after rfkill unblock");
+		return;
+	}
+	/* rtnetlink ifup handler will report interface as enabled */
+}
+
+
+static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
+{
+	/* Find phy (radio) to which this interface belongs */
+	char buf[90], *pos;
+	int f, rv;
+
+	drv->phyname[0] = '\0';
+	snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+		 drv->first_bss.ifname);
+	f = open(buf, O_RDONLY);
+	if (f < 0) {
+		wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+			   buf, strerror(errno));
+		return;
+	}
+
+	rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+	close(f);
+	if (rv < 0) {
+		wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+			   buf, strerror(errno));
+		return;
+	}
+
+	drv->phyname[rv] = '\0';
+	pos = os_strchr(drv->phyname, '\n');
+	if (pos)
+		*pos = '\0';
+	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+		   drv->first_bss.ifname, drv->phyname);
+}
+
+
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+						      void *eloop_ctx,
+						      void *handle)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	u8 data[2048];
+	struct msghdr msg;
+	struct iovec entry;
+	u8 control[512];
+	struct cmsghdr *cmsg;
+	int res, found_ee = 0, found_wifi = 0, acked = 0;
+	union wpa_event_data event;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &entry;
+	msg.msg_iovlen = 1;
+	entry.iov_base = data;
+	entry.iov_len = sizeof(data);
+	msg.msg_control = &control;
+	msg.msg_controllen = sizeof(control);
+
+	res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+	/* if error or not fitting 802.3 header, return */
+	if (res < 14)
+		return;
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+	{
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_WIFI_STATUS) {
+			int *ack;
+
+			found_wifi = 1;
+			ack = (void *)CMSG_DATA(cmsg);
+			acked = *ack;
+		}
+
+		if (cmsg->cmsg_level == SOL_PACKET &&
+		    cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+			struct sock_extended_err *err =
+				(struct sock_extended_err *)CMSG_DATA(cmsg);
+
+			if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+				found_ee = 1;
+		}
+	}
+
+	if (!found_ee || !found_wifi)
+		return;
+
+	memset(&event, 0, sizeof(event));
+	event.eapol_tx_status.dst = data;
+	event.eapol_tx_status.data = data + 14;
+	event.eapol_tx_status.data_len = res - 14;
+	event.eapol_tx_status.ack = acked;
+	wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+	bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!bss->nl_cb)
+		return -1;
+
+	nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_bss_event, bss);
+
+	return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+	nl_cb_put(bss->nl_cb);
+	bss->nl_cb = NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * @global_priv: private driver global data from global_init()
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
+				      void *global_priv)
+{
+	struct wpa_driver_nl80211_data *drv;
+	struct rfkill_config *rcfg;
+	struct i802_bss *bss;
+
+	if (global_priv == NULL)
+		return NULL;
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->global = global_priv;
+	drv->ctx = ctx;
+	bss = &drv->first_bss;
+	bss->drv = drv;
+	bss->ctx = ctx;
+
+	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
+	drv->monitor_ifidx = -1;
+	drv->monitor_sock = -1;
+	drv->eapol_tx_sock = -1;
+	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+
+	if (wpa_driver_nl80211_init_nl(drv)) {
+		os_free(drv);
+		return NULL;
+	}
+
+	if (nl80211_init_bss(bss))
+		goto failed;
+
+	nl80211_get_phy_name(drv);
+
+	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 (wpa_driver_nl80211_finish_drv_init(drv))
+		goto failed;
+
+	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+	if (drv->eapol_tx_sock < 0)
+		goto failed;
+
+	if (drv->data_tx_status) {
+		int enabled = 1;
+
+		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+			       &enabled, sizeof(enabled)) < 0) {
+			wpa_printf(MSG_DEBUG,
+				"nl80211: wifi status sockopt failed\n");
+			drv->data_tx_status = 0;
+			if (!drv->use_monitor)
+				drv->capa.flags &=
+					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+		} else {
+			eloop_register_read_sock(drv->eapol_tx_sock,
+				wpa_driver_nl80211_handle_eapol_tx_status,
+				drv, NULL);
+		}
+	}
+
+	if (drv->global) {
+		dl_list_add(&drv->global->interfaces, &drv->list);
+		drv->in_interface_list = 1;
+	}
+
+	return bss;
+
+failed:
+	wpa_driver_nl80211_deinit(bss);
+	return NULL;
+}
+
+
+static int nl80211_register_frame(struct i802_bss *bss,
+				  struct nl_handle *nl_handle,
+				  u16 type, const u8 *match, size_t match_len)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
+		   type, nl_handle);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+		    match, match_len);
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
+	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
+
+	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
+			   "failed (type=%u): ret=%d (%s)",
+			   type, ret, strerror(-ret));
+		wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+			    match, match_len);
+		goto nla_put_failure;
+	}
+	ret = 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (bss->nl_mgmt) {
+		wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
+			   "already on! (nl_mgmt=%p)", bss->nl_mgmt);
+		return -1;
+	}
+
+	bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+	if (bss->nl_mgmt == NULL)
+		return -1;
+
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_mgmt);
+
+	return 0;
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
+					 const u8 *match, size_t match_len)
+{
+	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
+	return nl80211_register_frame(bss, bss->nl_mgmt,
+				      type, match, match_len);
+}
+
+
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+		   "handle %p", bss->nl_mgmt);
+
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
+	/* GAS Initial Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
+		return -1;
+	/* GAS Initial Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
+		return -1;
+	/* GAS Comeback Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
+		return -1;
+	/* GAS Comeback Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
+		return -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
+	/* P2P Public Action */
+	if (nl80211_register_action_frame(bss,
+					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
+					  6) < 0)
+		return -1;
+	/* P2P Action */
+	if (nl80211_register_action_frame(bss,
+					  (u8 *) "\x7f\x50\x6f\x9a\x09",
+					  5) < 0)
+		return -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_IEEE80211W
+	/* SA Query Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
+		return -1;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+		/* TDLS Discovery Response */
+		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+		    0)
+			return -1;
+	}
+#endif /* CONFIG_TDLS */
+
+	/* FT Action frames */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
+		return -1;
+	else
+		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
+			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+
+	/* WNM - BSS Transition Management Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+		return -1;
+	/* WNM-Sleep Mode Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int nl80211_register_spurious_class3(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
+			   "failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+	static const int stypes[] = {
+		WLAN_FC_STYPE_AUTH,
+		WLAN_FC_STYPE_ASSOC_REQ,
+		WLAN_FC_STYPE_REASSOC_REQ,
+		WLAN_FC_STYPE_DISASSOC,
+		WLAN_FC_STYPE_DEAUTH,
+		WLAN_FC_STYPE_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
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+//		WLAN_FC_STYPE_BEACON,
+	};
+	unsigned int i;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p", bss->nl_mgmt);
+
+	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+		if (nl80211_register_frame(bss, bss->nl_mgmt,
+					   (WLAN_FC_TYPE_MGMT << 2) |
+					   (stypes[i] << 4),
+					   NULL, 0) < 0) {
+			goto out_err;
+		}
+	}
+
+	if (nl80211_register_spurious_class3(bss))
+		goto out_err;
+
+	if (nl80211_get_wiphy_data_ap(bss) == NULL)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p (device SME)", bss->nl_mgmt);
+
+	if (nl80211_register_frame(bss, bss->nl_mgmt,
+				   (WLAN_FC_TYPE_MGMT << 2) |
+				   (WLAN_FC_STYPE_ACTION << 4),
+				   NULL, 0) < 0)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+	if (bss->nl_mgmt == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
+		   "(%s)", bss->nl_mgmt, reason);
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+
+	nl80211_put_wiphy_data_ap(bss);
+}
+
+
+static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
+static int
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+{
+	struct i802_bss *bss = &drv->first_bss;
+	int send_rfkill_event = 0;
+
+	drv->ifindex = if_nametoindex(bss->ifname);
+	drv->first_bss.ifindex = drv->ifindex;
+
+#ifndef HOSTAPD
+	/*
+	 * Make sure the interface starts up in station mode unless this is a
+	 * dynamically added interface (e.g., P2P) that was already configured
+	 * with proper iftype.
+	 */
+	if (drv->ifindex != drv->global->if_add_ifindex &&
+	    wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
+			   "use managed mode");
+		return -1;
+	}
+
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
+		if (rfkill_is_blocked(drv->rfkill)) {
+			wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
+				   "interface '%s' due to rfkill",
+				   bss->ifname);
+			drv->if_disabled = 1;
+			send_rfkill_event = 1;
+		} else {
+			wpa_printf(MSG_ERROR, "nl80211: Could not set "
+				   "interface '%s' UP", bss->ifname);
+			return -1;
+		}
+	}
+
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
+			       1, IF_OPER_DORMANT);
+#endif /* HOSTAPD */
+
+	if (wpa_driver_nl80211_capa(drv))
+		return -1;
+
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       bss->addr))
+		return -1;
+
+	if (send_rfkill_event) {
+		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
+				       drv, drv->ctx);
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+ * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+static void wpa_driver_nl80211_deinit(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	bss->in_deinit = 1;
+	if (drv->data_tx_status)
+		eloop_unregister_read_sock(drv->eapol_tx_sock);
+	if (drv->eapol_tx_sock >= 0)
+		close(drv->eapol_tx_sock);
+
+	if (bss->nl_preq)
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+	if (bss->added_if_into_bridge) {
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
+			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+				   "interface %s from bridge %s: %s",
+				   bss->ifname, bss->brname, strerror(errno));
+	}
+	if (bss->added_bridge) {
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
+			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+				   "bridge %s: %s",
+				   bss->brname, strerror(errno));
+	}
+
+	nl80211_remove_monitor_interface(drv);
+
+	if (is_ap_interface(drv->nlmode))
+		wpa_driver_nl80211_del_beacon(drv);
+
+#ifdef HOSTAPD
+	if (drv->last_freq_ht) {
+		/* Clear HT flags from the driver */
+		struct hostapd_freq_params freq;
+		os_memset(&freq, 0, sizeof(freq));
+		freq.freq = drv->last_freq;
+		i802_set_freq(priv, &freq);
+	}
+
+	if (drv->eapol_sock >= 0) {
+		eloop_unregister_read_sock(drv->eapol_sock);
+		close(drv->eapol_sock);
+	}
+
+	if (drv->if_indices != drv->default_if_indices)
+		os_free(drv->if_indices);
+#endif /* HOSTAPD */
+
+	if (drv->disabled_11b_rates)
+		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+			       IF_OPER_UP);
+	rfkill_deinit(drv->rfkill);
+
+	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+	(void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+	wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+	nl80211_mgmt_unsubscribe(bss, "deinit");
+
+	nl_cb_put(drv->nl_cb);
+
+	nl80211_destroy_bss(&drv->first_bss);
+
+	os_free(drv->filter_ssids);
+
+	os_free(drv->auth_ie);
+
+	if (drv->in_interface_list)
+		dl_list_del(&drv->list);
+
+	os_free(drv);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Driver private data
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	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_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+		    struct wpa_driver_scan_params *params)
+{
+	struct nl_msg *msg;
+	int err;
+	size_t i;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NULL;
+
+	nl80211_cmd(drv, msg, 0, cmd);
+
+	if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
+		goto fail;
+
+	if (params->num_ssids) {
+		struct nl_msg *ssids = nlmsg_alloc();
+		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(ssids, i + 1, params->ssids[i].ssid_len,
+				    params->ssids[i].ssid) < 0) {
+				nlmsg_free(ssids);
+				goto fail;
+			}
+		}
+		err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+		nlmsg_free(ssids);
+		if (err < 0)
+			goto fail;
+	}
+
+	if (params->extra_ies) {
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+			    params->extra_ies, params->extra_ies_len);
+		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+			    params->extra_ies) < 0)
+			goto fail;
+	}
+
+	if (params->freqs) {
+		struct nl_msg *freqs = nlmsg_alloc();
+		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(freqs, i + 1, params->freqs[i]) < 0) {
+				nlmsg_free(freqs);
+				goto fail;
+			}
+		}
+		err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
+				     freqs);
+		nlmsg_free(freqs);
+		if (err < 0)
+			goto fail;
+	}
+
+	os_free(drv->filter_ssids);
+	drv->filter_ssids = params->filter_ssids;
+	params->filter_ssids = NULL;
+	drv->num_filter_ssids = params->num_filter_ssids;
+
+	return msg;
+
+fail:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv,
+				   struct wpa_driver_scan_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1, timeout;
+	struct nl_msg *msg, *rates = NULL;
+
+	drv->scan_for_auth = 0;
+
+	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+	if (!msg)
+		return -1;
+
+	if (params->p2p_probe) {
+		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+		rates = nlmsg_alloc();
+		if (rates == NULL)
+			goto nla_put_failure;
+
+		/*
+		 * 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.
+		 */
+		NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+		if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
+		    0)
+			goto nla_put_failure;
+
+		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+#ifdef HOSTAPD
+		if (is_ap_interface(drv->nlmode)) {
+			/*
+			 * mac80211 does not allow scan requests in AP mode, so
+			 * try to do this in station mode.
+			 */
+			if (wpa_driver_nl80211_set_mode(
+				    bss, NL80211_IFTYPE_STATION))
+				goto nla_put_failure;
+
+			if (wpa_driver_nl80211_scan(drv, params)) {
+				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
+				goto nla_put_failure;
+			}
+
+			/* Restore AP mode when processing scan results */
+			drv->ap_scan_as_station = drv->nlmode;
+			ret = 0;
+		} else
+			goto nla_put_failure;
+#else /* HOSTAPD */
+		goto nla_put_failure;
+#endif /* HOSTAPD */
+	}
+
+	/* Not all drivers generate "scan completed" wireless event, so try to
+	 * read results after a timeout. */
+	timeout = 10;
+	if (drv->scan_complete_events) {
+		/*
+		 * The driver seems to deliver events to notify when scan is
+		 * complete, so use longer timeout to avoid race conditions
+		 * with scanning and following association request.
+		 */
+		timeout = 30;
+	}
+	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+		   "seconds", ret, timeout);
+	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+			       drv, drv->ctx);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	nlmsg_free(rates);
+	return ret;
+}
+
+
+/**
+ * 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
+ */
+static int wpa_driver_nl80211_sched_scan(void *priv,
+					 struct wpa_driver_scan_params *params,
+					 u32 interval)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1;
+	struct nl_msg *msg;
+	struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
+	struct nl_msg *match_set_rssi = NULL;
+	size_t i;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+	if (!msg)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
+
+	if ((drv->num_filter_ssids &&
+	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+	    params->filter_rssi) {
+		match_sets = nlmsg_alloc();
+		if (match_sets == NULL)
+			goto nla_put_failure;
+
+		for (i = 0; i < drv->num_filter_ssids; i++) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "nl80211: Sched scan filter SSID",
+					  drv->filter_ssids[i].ssid,
+					  drv->filter_ssids[i].ssid_len);
+
+			match_set_ssid = nlmsg_alloc();
+			if (match_set_ssid == NULL)
+				goto nla_put_failure;
+			NLA_PUT(match_set_ssid,
+				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+				drv->filter_ssids[i].ssid_len,
+				drv->filter_ssids[i].ssid);
+
+			if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
+			    0)
+				goto nla_put_failure;
+		}
+
+		if (params->filter_rssi) {
+			match_set_rssi = nlmsg_alloc();
+			if (match_set_rssi == NULL)
+				goto nla_put_failure;
+			NLA_PUT_U32(match_set_rssi,
+				    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+				    params->filter_rssi);
+			wpa_printf(MSG_MSGDUMP,
+				   "nl80211: Sched scan RSSI filter %d dBm",
+				   params->filter_rssi);
+			if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
+				goto nla_put_failure;
+		}
+
+		if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+				   match_sets) < 0)
+			goto nla_put_failure;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+	/* TODO: if we get an error here, we should fall back to normal scan */
+
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+			   "ret=%d (%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+		   "scan interval %d msec", ret, interval);
+
+nla_put_failure:
+	nlmsg_free(match_set_ssid);
+	nlmsg_free(match_sets);
+	nlmsg_free(match_set_rssi);
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+static int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = 0;
+	struct nl_msg *msg;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_stop(bss);
+#endif /* ANDROID */
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
+			   "ret=%d (%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static 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)
+{
+	const u8 *ssid;
+	size_t i;
+
+	if (drv->filter_ssids == NULL)
+		return 0;
+
+	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+	if (ssid == NULL)
+		return 1;
+
+	for (i = 0; i < drv->num_filter_ssids; i++) {
+		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+		    0)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *bss[NL80211_BSS_MAX + 1];
+	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_BSS_TSF] = { .type = NLA_U64 },
+		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
+		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+	};
+	struct nl80211_bss_info_arg *_arg = arg;
+	struct wpa_scan_results *res = _arg->res;
+	struct wpa_scan_res **tmp;
+	struct wpa_scan_res *r;
+	const u8 *ie, *beacon_ie;
+	size_t ie_len, beacon_ie_len;
+	u8 *pos;
+	size_t i;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[NL80211_ATTR_BSS])
+		return NL_SKIP;
+	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+			     bss_policy))
+		return NL_SKIP;
+	if (bss[NL80211_BSS_STATUS]) {
+		enum nl80211_bss_status status;
+		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+		    bss[NL80211_BSS_FREQUENCY]) {
+			_arg->assoc_freq =
+				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+				   _arg->assoc_freq);
+		}
+		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+		    bss[NL80211_BSS_BSSID]) {
+			os_memcpy(_arg->assoc_bssid,
+				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+				   MACSTR, MAC2STR(_arg->assoc_bssid));
+		}
+	}
+	if (!res)
+		return NL_SKIP;
+	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+	} else {
+		ie = NULL;
+		ie_len = 0;
+	}
+	if (bss[NL80211_BSS_BEACON_IES]) {
+		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
+		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
+	} else {
+		beacon_ie = NULL;
+		beacon_ie_len = 0;
+	}
+
+	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+				  ie ? ie_len : beacon_ie_len))
+		return NL_SKIP;
+
+	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
+	if (r == NULL)
+		return NL_SKIP;
+	if (bss[NL80211_BSS_BSSID])
+		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+			  ETH_ALEN);
+	if (bss[NL80211_BSS_FREQUENCY])
+		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+	if (bss[NL80211_BSS_BEACON_INTERVAL])
+		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+	if (bss[NL80211_BSS_CAPABILITY])
+		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+	r->flags |= WPA_SCAN_NOISE_INVALID;
+	if (bss[NL80211_BSS_SIGNAL_MBM]) {
+		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+		r->level /= 100; /* mBm to dBm */
+		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
+	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
+		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+		r->flags |= WPA_SCAN_QUAL_INVALID;
+	} else
+		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
+	if (bss[NL80211_BSS_TSF])
+		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+	if (bss[NL80211_BSS_SEEN_MS_AGO])
+		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
+	r->ie_len = ie_len;
+	pos = (u8 *) (r + 1);
+	if (ie) {
+		os_memcpy(pos, ie, ie_len);
+		pos += ie_len;
+	}
+	r->beacon_ie_len = beacon_ie_len;
+	if (beacon_ie)
+		os_memcpy(pos, beacon_ie, beacon_ie_len);
+
+	if (bss[NL80211_BSS_STATUS]) {
+		enum nl80211_bss_status status;
+		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+		switch (status) {
+		case NL80211_BSS_STATUS_AUTHENTICATED:
+			r->flags |= WPA_SCAN_AUTHENTICATED;
+			break;
+		case NL80211_BSS_STATUS_ASSOCIATED:
+			r->flags |= WPA_SCAN_ASSOCIATED;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * cfg80211 maintains separate BSS table entries for APs if the same
+	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+	 * not use frequency as a separate key in the BSS table, so filter out
+	 * duplicated entries. Prefer associated BSS entry in such a case in
+	 * order to get the correct frequency into the BSS table.
+	 */
+	for (i = 0; i < res->num; i++) {
+		const u8 *s1, *s2;
+		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);
+		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
+			continue;
+
+		/* Same BSSID,SSID was already included in scan results */
+		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+			   "for " MACSTR, MAC2STR(r->bssid));
+
+		if ((r->flags & WPA_SCAN_ASSOCIATED) &&
+		    !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
+			os_free(res->res[i]);
+			res->res[i] = r;
+		} else
+			os_free(r);
+		return NL_SKIP;
+	}
+
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(r);
+		return NL_SKIP;
+	}
+	tmp[res->num++] = r;
+	res->res = tmp;
+
+	return NL_SKIP;
+}
+
+
+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
+				 const u8 *addr)
+{
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
+			   "mismatch (" MACSTR ")", MAC2STR(addr));
+		wpa_driver_nl80211_mlme(drv, addr,
+					NL80211_CMD_DEAUTHENTICATE,
+					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+	}
+}
+
+
+static void wpa_driver_nl80211_check_bss_status(
+	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
+{
+	size_t i;
+
+	for (i = 0; i < res->num; i++) {
+		struct wpa_scan_res *r = res->res[i];
+		if (r->flags & WPA_SCAN_AUTHENTICATED) {
+			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+				   "indicates BSS status with " MACSTR
+				   " as authenticated",
+				   MAC2STR(r->bssid));
+			if (is_sta_interface(drv->nlmode) &&
+			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
+			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
+			    0) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
+					   " in local state (auth=" MACSTR
+					   " assoc=" MACSTR ")",
+					   MAC2STR(drv->auth_bssid),
+					   MAC2STR(drv->bssid));
+				clear_state_mismatch(drv, r->bssid);
+			}
+		}
+
+		if (r->flags & WPA_SCAN_ASSOCIATED) {
+			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+				   "indicate BSS status with " MACSTR
+				   " as associated",
+				   MAC2STR(r->bssid));
+			if (is_sta_interface(drv->nlmode) &&
+			    !drv->associated) {
+				wpa_printf(MSG_DEBUG, "nl80211: Local state "
+					   "(not associated) does not match "
+					   "with BSS state");
+				clear_state_mismatch(drv, r->bssid);
+			} else if (is_sta_interface(drv->nlmode) &&
+				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
+				   0) {
+				wpa_printf(MSG_DEBUG, "nl80211: Local state "
+					   "(associated with " MACSTR ") does "
+					   "not match with BSS state",
+					   MAC2STR(drv->bssid));
+				clear_state_mismatch(drv, r->bssid);
+				clear_state_mismatch(drv, drv->bssid);
+			}
+		}
+	}
+}
+
+
+static struct wpa_scan_results *
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	struct wpa_scan_results *res;
+	int ret;
+	struct nl80211_bss_info_arg arg;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL)
+		return NULL;
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto nla_put_failure;
+
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	arg.drv = drv;
+	arg.res = res;
+	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+	msg = NULL;
+	if (ret == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+			   "BSSes)", (unsigned long) res->num);
+		nl80211_get_noise_for_scan_results(drv, res);
+		return res;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+		   "(%s)", ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	wpa_scan_results_free(res);
+	return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+static struct wpa_scan_results *
+wpa_driver_nl80211_get_scan_results(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct wpa_scan_results *res;
+
+	res = nl80211_get_scan_results(drv);
+	if (res)
+		wpa_driver_nl80211_check_bss_status(drv, res);
+	return res;
+}
+
+
+static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+	struct wpa_scan_results *res;
+	size_t i;
+
+	res = nl80211_get_scan_results(drv);
+	if (res == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+	for (i = 0; i < res->num; i++) {
+		struct wpa_scan_res *r = res->res[i];
+		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
+			   (int) i, (int) res->num, MAC2STR(r->bssid),
+			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
+			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+	}
+
+	wpa_scan_results_free(res);
+}
+
+
+static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+				      enum wpa_alg alg, const u8 *addr,
+				      int key_idx, int set_tx,
+				      const u8 *seq, size_t seq_len,
+				      const u8 *key, size_t key_len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ifindex = if_nametoindex(ifname);
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
+		   "set_tx=%d seq_len=%lu key_len=%lu",
+		   __func__, ifindex, alg, addr, key_idx, set_tx,
+		   (unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+	if (key_idx == -1)
+		key_idx = 0;
+#endif /* CONFIG_TDLS */
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	if (alg == WPA_ALG_NONE) {
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
+	} else {
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
+		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+		switch (alg) {
+		case WPA_ALG_WEP:
+			if (key_len == 5)
+				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+					    WLAN_CIPHER_SUITE_WEP40);
+			else
+				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+					    WLAN_CIPHER_SUITE_WEP104);
+			break;
+		case WPA_ALG_TKIP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_TKIP);
+			break;
+		case WPA_ALG_CCMP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_CCMP);
+			break;
+		case WPA_ALG_GCMP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_GCMP);
+			break;
+		case WPA_ALG_IGTK:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_AES_CMAC);
+			break;
+		case WPA_ALG_SMS4:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_SMS4);
+			break;
+		case WPA_ALG_KRK:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_KRK);
+			break;
+		default:
+			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+				   "algorithm %d", __func__, alg);
+			nlmsg_free(msg);
+			return -1;
+		}
+	}
+
+	if (seq && seq_len)
+		NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+
+	if (addr && !is_broadcast_ether_addr(addr)) {
+		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
+			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
+				    NL80211_KEYTYPE_GROUP);
+		}
+	} else if (addr && is_broadcast_ether_addr(addr)) {
+		struct nl_msg *types;
+		int err;
+		wpa_printf(MSG_DEBUG, "   broadcast key");
+		types = nlmsg_alloc();
+		if (!types)
+			goto nla_put_failure;
+		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+				     types);
+		nlmsg_free(types);
+		if (err)
+			goto nla_put_failure;
+	}
+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
+		ret = 0;
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
+			   ret, strerror(-ret));
+
+	/*
+	 * If we failed or don't need to set the default TX key (below),
+	 * we're done here.
+	 */
+	if (ret || !set_tx || alg == WPA_ALG_NONE)
+		return ret;
+	if (is_ap_interface(drv->nlmode) && addr &&
+	    !is_broadcast_ether_addr(addr))
+		return ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	if (alg == WPA_ALG_IGTK)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+	else
+		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+	if (addr && is_broadcast_ether_addr(addr)) {
+		struct nl_msg *types;
+		int err;
+		types = nlmsg_alloc();
+		if (!types)
+			goto nla_put_failure;
+		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+				     types);
+		nlmsg_free(types);
+		if (err)
+			goto nla_put_failure;
+	} else if (addr) {
+		struct nl_msg *types;
+		int err;
+		types = nlmsg_alloc();
+		if (!types)
+			goto nla_put_failure;
+		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
+				     types);
+		nlmsg_free(types);
+		if (err)
+			goto nla_put_failure;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret == -ENOENT)
+		ret = 0;
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
+			   "err=%d %s)", ret, strerror(-ret));
+	return ret;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
+		      int key_idx, int defkey,
+		      const u8 *seq, size_t seq_len,
+		      const u8 *key, size_t key_len)
+{
+	struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+	if (!key_attr)
+		return -1;
+
+	if (defkey && alg == WPA_ALG_IGTK)
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
+	else if (defkey)
+		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+
+	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
+
+	switch (alg) {
+	case WPA_ALG_WEP:
+		if (key_len == 5)
+			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_WEP40);
+		else
+			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_WEP104);
+		break;
+	case WPA_ALG_TKIP:
+		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
+		break;
+	case WPA_ALG_CCMP:
+		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
+		break;
+	case WPA_ALG_GCMP:
+		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+		break;
+	case WPA_ALG_IGTK:
+		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+			    WLAN_CIPHER_SUITE_AES_CMAC);
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+			   "algorithm %d", __func__, alg);
+		return -1;
+	}
+
+	if (seq && seq_len)
+		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
+
+	NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+
+	nla_nest_end(msg, key_attr);
+
+	return 0;
+ nla_put_failure:
+	return -1;
+}
+
+
+static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
+				 struct nl_msg *msg)
+{
+	int i, privacy = 0;
+	struct nlattr *nl_keys, *nl_key;
+
+	for (i = 0; i < 4; i++) {
+		if (!params->wep_key[i])
+			continue;
+		privacy = 1;
+		break;
+	}
+	if (params->wps == WPS_MODE_PRIVACY)
+		privacy = 1;
+	if (params->pairwise_suite &&
+	    params->pairwise_suite != WPA_CIPHER_NONE)
+		privacy = 1;
+
+	if (!privacy)
+		return 0;
+
+	NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+
+	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
+	if (!nl_keys)
+		goto nla_put_failure;
+
+	for (i = 0; i < 4; i++) {
+		if (!params->wep_key[i])
+			continue;
+
+		nl_key = nla_nest_start(msg, i);
+		if (!nl_key)
+			goto nla_put_failure;
+
+		NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+			params->wep_key[i]);
+		if (params->wep_key_len[i] == 5)
+			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_WEP40);
+		else
+			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+				    WLAN_CIPHER_SUITE_WEP104);
+
+		NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
+
+		if (i == params->wep_tx_keyidx)
+			NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+
+		nla_nest_end(msg, nl_key);
+	}
+	nla_nest_end(msg, nl_keys);
+
+	return 0;
+
+nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+				   const u8 *addr, int cmd, u16 reason_code,
+				   int local_state_change)
+{
+	int ret = -1;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, cmd);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
+	if (addr)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	if (local_state_change)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
+			reason_code, ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+					 int reason_code)
+{
+	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
+	drv->associated = 0;
+	drv->ignore_next_local_disconnect = 0;
+	/* Disconnect command doesn't need BSSID - it uses cached value */
+	return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+				       reason_code, 0);
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+					     int reason_code)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+		return wpa_driver_nl80211_disconnect(drv, reason_code);
+	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
+		   __func__, MAC2STR(addr), reason_code);
+	drv->associated = 0;
+	if (drv->nlmode == NL80211_IFTYPE_ADHOC)
+		return nl80211_leave_ibss(drv);
+	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
+				       reason_code, 0);
+}
+
+
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+				     struct wpa_driver_auth_params *params)
+{
+	int i;
+
+	drv->auth_freq = params->freq;
+	drv->auth_alg = params->auth_alg;
+	drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+	drv->auth_local_state_change = params->local_state_change;
+	drv->auth_p2p = params->p2p;
+
+	if (params->bssid)
+		os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+	else
+		os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+	if (params->ssid) {
+		os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+		drv->auth_ssid_len = params->ssid_len;
+	} else
+		drv->auth_ssid_len = 0;
+
+
+	os_free(drv->auth_ie);
+	drv->auth_ie = NULL;
+	drv->auth_ie_len = 0;
+	if (params->ie) {
+		drv->auth_ie = os_malloc(params->ie_len);
+		if (drv->auth_ie) {
+			os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+			drv->auth_ie_len = params->ie_len;
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (params->wep_key[i] && params->wep_key_len[i] &&
+		    params->wep_key_len[i] <= 16) {
+			os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+				  params->wep_key_len[i]);
+			drv->auth_wep_key_len[i] = params->wep_key_len[i];
+		} else
+			drv->auth_wep_key_len[i] = 0;
+	}
+}
+
+
+static int wpa_driver_nl80211_authenticate(
+	void *priv, struct wpa_driver_auth_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1, i;
+	struct nl_msg *msg;
+	enum nl80211_auth_type type;
+	enum nl80211_iftype nlmode;
+	int count = 0;
+	int is_retry;
+
+	is_retry = drv->retry_auth;
+	drv->retry_auth = 0;
+
+	drv->associated = 0;
+	os_memset(drv->auth_bssid, 0, ETH_ALEN);
+	/* FIX: IBSS mode */
+	nlmode = params->p2p ?
+		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+	if (drv->nlmode != nlmode &&
+	    wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+		return -1;
+
+retry:
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
+		   drv->ifindex);
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
+
+	for (i = 0; i < 4; i++) {
+		if (!params->wep_key[i])
+			continue;
+		wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+					   NULL, i,
+					   i == params->wep_tx_keyidx, NULL, 0,
+					   params->wep_key[i],
+					   params->wep_key_len[i]);
+		if (params->wep_tx_keyidx != i)
+			continue;
+		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
+			       params->wep_key[i], params->wep_key_len[i])) {
+			nlmsg_free(msg);
+			return -1;
+		}
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (params->bssid) {
+		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
+			   MAC2STR(params->bssid));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+	}
+	if (params->freq) {
+		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+	}
+	if (params->ssid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+				  params->ssid, params->ssid_len);
+		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+			params->ssid);
+	}
+	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
+	if (params->ie)
+		NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+	if (params->sae_data) {
+		wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
+			    params->sae_data_len);
+		NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+			params->sae_data);
+	}
+	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+		type = NL80211_AUTHTYPE_SHARED_KEY;
+	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+		type = NL80211_AUTHTYPE_NETWORK_EAP;
+	else if (params->auth_alg & WPA_AUTH_ALG_FT)
+		type = NL80211_AUTHTYPE_FT;
+	else if (params->auth_alg & WPA_AUTH_ALG_SAE)
+		type = NL80211_AUTHTYPE_SAE;
+	else
+		goto nla_put_failure;
+	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
+	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+	if (params->local_state_change) {
+		wpa_printf(MSG_DEBUG, "  * Local state change only");
+		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (auth): ret=%d (%s)",
+			ret, strerror(-ret));
+		count++;
+		if (ret == -EALREADY && count == 1 && params->bssid &&
+		    !params->local_state_change) {
+			/*
+			 * mac80211 does not currently accept new
+			 * authentication if we are already authenticated. As a
+			 * workaround, force deauthentication and try again.
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
+				   "after forced deauthentication");
+			wpa_driver_nl80211_deauthenticate(
+				bss, params->bssid,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
+			nlmsg_free(msg);
+			goto retry;
+		}
+
+		if (ret == -ENOENT && params->freq && !is_retry) {
+			/*
+			 * cfg80211 has likely expired the BSS entry even
+			 * though it was previously available in our internal
+			 * BSS table. To recover quickly, start a single
+			 * channel scan on the specified channel.
+			 */
+			struct wpa_driver_scan_params scan;
+			int freqs[2];
+
+			os_memset(&scan, 0, sizeof(scan));
+			scan.num_ssids = 1;
+			if (params->ssid) {
+				scan.ssids[0].ssid = params->ssid;
+				scan.ssids[0].ssid_len = params->ssid_len;
+			}
+			freqs[0] = params->freq;
+			freqs[1] = 0;
+			scan.freqs = freqs;
+			wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+				   "channel scan to refresh cfg80211 BSS "
+				   "entry");
+			ret = wpa_driver_nl80211_scan(bss, &scan);
+			if (ret == 0) {
+				nl80211_copy_auth_params(drv, params);
+				drv->scan_for_auth = 1;
+			}
+		} else if (is_retry) {
+			/*
+			 * Need to indicate this with an event since the return
+			 * value from the retry is not delivered to core code.
+			 */
+			union wpa_event_data event;
+			wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+				   "failed");
+			os_memset(&event, 0, sizeof(event));
+			os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+				  ETH_ALEN);
+			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+					     &event);
+		}
+
+		goto nla_put_failure;
+	}
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
+		   "successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_authenticate_retry(
+	struct wpa_driver_nl80211_data *drv)
+{
+	struct wpa_driver_auth_params params;
+	struct i802_bss *bss = &drv->first_bss;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+	os_memset(&params, 0, sizeof(params));
+	params.freq = drv->auth_freq;
+	params.auth_alg = drv->auth_alg;
+	params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+	params.local_state_change = drv->auth_local_state_change;
+	params.p2p = drv->auth_p2p;
+
+	if (!is_zero_ether_addr(drv->auth_bssid_))
+		params.bssid = drv->auth_bssid_;
+
+	if (drv->auth_ssid_len) {
+		params.ssid = drv->auth_ssid;
+		params.ssid_len = drv->auth_ssid_len;
+	}
+
+	params.ie = drv->auth_ie;
+	params.ie_len = drv->auth_ie_len;
+
+	for (i = 0; i < 4; i++) {
+		if (drv->auth_wep_key_len[i]) {
+			params.wep_key[i] = drv->auth_wep_key[i];
+			params.wep_key_len[i] = drv->auth_wep_key_len[i];
+		}
+	}
+
+	drv->retry_auth = 1;
+	return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
+struct phy_info_arg {
+	u16 *num_modes;
+	struct hostapd_hw_modes *modes;
+};
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct phy_info_arg *phy_info = arg;
+
+	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+	};
+
+	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
+	};
+
+	struct nlattr *nl_band;
+	struct nlattr *nl_freq;
+	struct nlattr *nl_rate;
+	int rem_band, rem_freq, rem_rate;
+	struct hostapd_hw_modes *mode;
+	int idx, mode_is_set;
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+		return NL_SKIP;
+
+	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+		mode = os_realloc_array(phy_info->modes,
+					*phy_info->num_modes + 1,
+					sizeof(*mode));
+		if (!mode)
+			return NL_SKIP;
+		phy_info->modes = mode;
+
+		mode_is_set = 0;
+
+		mode = &phy_info->modes[*(phy_info->num_modes)];
+		memset(mode, 0, sizeof(*mode));
+		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
+		*(phy_info->num_modes) += 1;
+
+		nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+			  nla_len(nl_band), NULL);
+
+		if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
+			mode->ht_capab = nla_get_u16(
+				tb_band[NL80211_BAND_ATTR_HT_CAPA]);
+		}
+
+		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
+			mode->a_mpdu_params |= nla_get_u8(
+				tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
+				0x03;
+		}
+
+		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
+			mode->a_mpdu_params |= nla_get_u8(
+				tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
+				2;
+		}
+
+		if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
+		    nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
+			u8 *mcs;
+			mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+			os_memcpy(mode->mcs_set, mcs, 16);
+		}
+
+		if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
+			mode->vht_capab = nla_get_u32(
+				tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+		}
+
+		if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
+		    nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
+			u8 *mcs;
+			mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+			os_memcpy(mode->vht_mcs_set, mcs, 8);
+		}
+
+		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+				  nla_len(nl_freq), freq_policy);
+			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+				continue;
+			mode->num_channels++;
+		}
+
+		mode->channels = os_calloc(mode->num_channels,
+					   sizeof(struct hostapd_channel_data));
+		if (!mode->channels)
+			return NL_SKIP;
+
+		idx = 0;
+
+		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+				  nla_len(nl_freq), freq_policy);
+			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+				continue;
+
+			mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+			mode->channels[idx].flag = 0;
+
+			if (!mode_is_set) {
+				/* crude heuristic */
+				if (mode->channels[idx].freq < 4000)
+					mode->mode = HOSTAPD_MODE_IEEE80211B;
+				else if (mode->channels[idx].freq > 50000)
+					mode->mode = HOSTAPD_MODE_IEEE80211AD;
+				else
+					mode->mode = HOSTAPD_MODE_IEEE80211A;
+				mode_is_set = 1;
+			}
+
+			switch (mode->mode) {
+			case HOSTAPD_MODE_IEEE80211AD:
+				mode->channels[idx].chan =
+					(mode->channels[idx].freq - 56160) /
+					2160;
+				break;
+			case HOSTAPD_MODE_IEEE80211A:
+				mode->channels[idx].chan =
+					mode->channels[idx].freq / 5 - 1000;
+				break;
+			case HOSTAPD_MODE_IEEE80211B:
+			case HOSTAPD_MODE_IEEE80211G:
+				if (mode->channels[idx].freq == 2484)
+					mode->channels[idx].chan = 14;
+				else
+					mode->channels[idx].chan =
+						(mode->channels[idx].freq -
+						 2407) / 5;
+				break;
+			default:
+				break;
+			}
+
+			if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+				mode->channels[idx].flag |=
+					HOSTAPD_CHAN_DISABLED;
+			if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+				mode->channels[idx].flag |=
+					HOSTAPD_CHAN_PASSIVE_SCAN;
+			if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+				mode->channels[idx].flag |=
+					HOSTAPD_CHAN_NO_IBSS;
+			if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+				mode->channels[idx].flag |=
+					HOSTAPD_CHAN_RADAR;
+
+			if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+			    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+				mode->channels[idx].max_tx_power =
+					nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+
+			idx++;
+		}
+
+		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+				  nla_len(nl_rate), rate_policy);
+			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+				continue;
+			mode->num_rates++;
+		}
+
+		mode->rates = os_calloc(mode->num_rates, sizeof(int));
+		if (!mode->rates)
+			return NL_SKIP;
+
+		idx = 0;
+
+		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+				  nla_len(nl_rate), rate_policy);
+			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+				continue;
+			mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
+
+			/* crude heuristic */
+			if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
+			    mode->rates[idx] > 200)
+				mode->mode = HOSTAPD_MODE_IEEE80211G;
+
+			idx++;
+		}
+	}
+
+	return NL_SKIP;
+}
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
+{
+	u16 m;
+	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+	int i, mode11g_idx = -1;
+
+	/* If only 802.11g mode is included, use it to construct matching
+	 * 802.11b mode data. */
+
+	for (m = 0; m < *num_modes; m++) {
+		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+			return modes; /* 802.11b already included */
+		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+			mode11g_idx = m;
+	}
+
+	if (mode11g_idx < 0)
+		return modes; /* 2.4 GHz band not supported at all */
+
+	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
+	if (nmodes == NULL)
+		return modes; /* Could not add 802.11b mode */
+
+	mode = &nmodes[*num_modes];
+	os_memset(mode, 0, sizeof(*mode));
+	(*num_modes)++;
+	modes = nmodes;
+
+	mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+	mode11g = &modes[mode11g_idx];
+	mode->num_channels = mode11g->num_channels;
+	mode->channels = os_malloc(mode11g->num_channels *
+				   sizeof(struct hostapd_channel_data));
+	if (mode->channels == NULL) {
+		(*num_modes)--;
+		return modes; /* Could not add 802.11b mode */
+	}
+	os_memcpy(mode->channels, mode11g->channels,
+		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+	mode->num_rates = 0;
+	mode->rates = os_malloc(4 * sizeof(int));
+	if (mode->rates == NULL) {
+		os_free(mode->channels);
+		(*num_modes)--;
+		return modes; /* Could not add 802.11b mode */
+	}
+
+	for (i = 0; i < mode11g->num_rates; i++) {
+		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
+		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
+			continue;
+		mode->rates[mode->num_rates] = mode11g->rates[i];
+		mode->num_rates++;
+		if (mode->num_rates == 4)
+			break;
+	}
+
+	if (mode->num_rates == 0) {
+		os_free(mode->channels);
+		os_free(mode->rates);
+		(*num_modes)--;
+		return modes; /* No 802.11b rates */
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+		   "information");
+
+	return modes;
+}
+
+
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+				  int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40;
+	}
+}
+
+
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+				      int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (!(chan->flag & HOSTAPD_CHAN_HT40))
+			continue;
+		if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+		if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+	}
+}
+
+
+static void nl80211_reg_rule_ht40(struct nlattr *tb[],
+				  struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
+		   start, end, max_bw);
+	if (max_bw < 40)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		nl80211_set_ht40_mode(&results->modes[m], start, end);
+	}
+}
+
+
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+				 struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	if (max_bw < 20)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+	}
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+	struct phy_info_arg *results = arg;
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *nl_rule;
+	struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+	int rem_rule;
+	static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+		[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+		[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+		[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+	};
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+	    !tb_msg[NL80211_ATTR_REG_RULES]) {
+		wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+			   "available");
+		return NL_SKIP;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+		   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_ht40(tb_rule, results);
+	}
+
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_sec(tb_rule, results);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
+				  struct phy_info_arg *results)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct phy_info_arg result = {
+		.num_modes = num_modes,
+		.modes = NULL,
+	};
+
+	*num_modes = 0;
+	*flags = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NULL;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+		nl80211_set_ht40_flags(drv, &result);
+		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+	}
+	msg = NULL;
+ nla_put_failure:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+
+static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
+					const void *data, size_t len,
+					int encrypt, int noack)
+{
+	__u8 rtap_hdr[] = {
+		0x00, 0x00, /* radiotap version */
+		0x0e, 0x00, /* radiotap length */
+		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+		0x00,       /* padding */
+		0x00, 0x00, /* RX and TX flags to indicate that */
+		0x00, 0x00, /* this is the injected frame directly */
+	};
+	struct iovec iov[2] = {
+		{
+			.iov_base = &rtap_hdr,
+			.iov_len = sizeof(rtap_hdr),
+		},
+		{
+			.iov_base = (void *) data,
+			.iov_len = len,
+		}
+	};
+	struct msghdr msg = {
+		.msg_name = NULL,
+		.msg_namelen = 0,
+		.msg_iov = iov,
+		.msg_iovlen = 2,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_flags = 0,
+	};
+	int res;
+	u16 txflags = 0;
+
+	if (encrypt)
+		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+	if (drv->monitor_sock < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+			   "for %s", __func__);
+		return -1;
+	}
+
+	if (noack)
+		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+	WPA_PUT_LE16(&rtap_hdr[12], txflags);
+
+	res = sendmsg(drv->monitor_sock, &msg, 0);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+					 const void *data, size_t len,
+					 int encrypt, int noack,
+					 unsigned int freq, int no_cck,
+					 int offchanok, unsigned int wait_time)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	u64 cookie;
+
+	if (freq == 0)
+		freq = bss->freq;
+
+	if (drv->use_monitor)
+		return wpa_driver_nl80211_send_mntr(drv, data, len,
+						    encrypt, noack);
+
+	return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+				      &cookie, no_cck, noack, offchanok);
+}
+
+
+static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
+					     const u8 *data,
+					     size_t data_len, int noack,
+					     unsigned int freq, int no_cck,
+					     int offchanok,
+					     unsigned int wait_time)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ieee80211_mgmt *mgmt;
+	int encrypt = 1;
+	u16 fc;
+
+	mgmt = (struct ieee80211_mgmt *) data;
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (is_sta_interface(drv->nlmode) &&
+	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
+		/*
+		 * The use of last_mgmt_freq is a bit of a hack,
+		 * but it works due to the single-threaded nature
+		 * of wpa_supplicant.
+		 */
+		if (freq == 0)
+			freq = drv->last_mgmt_freq;
+		return nl80211_send_frame_cmd(bss, freq, 0,
+					      data, data_len, NULL, 1, noack,
+					      1);
+	}
+
+	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+		if (freq == 0)
+			freq = bss->freq;
+		return nl80211_send_frame_cmd(bss, freq,
+					      (int) freq == bss->freq ? 0 :
+					      wait_time,
+					      data, data_len,
+					      &drv->send_action_cookie,
+					      no_cck, noack, offchanok);
+	}
+
+	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+		/*
+		 * Only one of the authentication frame types is encrypted.
+		 * In order for static WEP encryption to work properly (i.e.,
+		 * to not encrypt the frame), we need to tell mac80211 about
+		 * the frames that must not be encrypted.
+		 */
+		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
+		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
+			encrypt = 0;
+	}
+
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+					     noack, freq, no_cck, offchanok,
+					     wait_time);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+					size_t data_len, int noack)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
+						 0, 0, 0, 0);
+}
+
+
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+			   int slot, int ht_opmode, int ap_isolate,
+			   int *basic_rates)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
+
+	if (cts >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
+	if (preamble >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
+	if (slot >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
+	if (ht_opmode >= 0)
+		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
+	if (ap_isolate >= 0)
+		NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+
+	if (basic_rates) {
+		u8 rates[NL80211_MAX_SUPP_RATES];
+		u8 rates_len = 0;
+		int i;
+
+		for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+		     i++)
+			rates[rates_len++] = basic_rates[i] / 5;
+
+		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_ap(void *priv,
+				     struct wpa_driver_ap_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	u8 cmd = NL80211_CMD_NEW_BEACON;
+	int ret;
+	int beacon_set;
+	int ifindex = if_nametoindex(bss->ifname);
+	int num_suites;
+	u32 suites[10];
+	u32 ver;
+
+	beacon_set = bss->beacon_set;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
+		   beacon_set);
+	if (beacon_set)
+		cmd = NL80211_CMD_SET_BEACON;
+
+	nl80211_cmd(drv, msg, 0, cmd);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
+	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
+	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+		params->ssid);
+	if (params->proberesp && params->proberesp_len)
+		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+			params->proberesp);
+	switch (params->hide_ssid) {
+	case NO_SSID_HIDING:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_NOT_IN_USE);
+		break;
+	case HIDDEN_SSID_ZERO_LEN:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_LEN);
+		break;
+	case HIDDEN_SSID_ZERO_CONTENTS:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+		break;
+	}
+	if (params->privacy)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
+	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
+		/* Leave out the attribute */
+	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
+		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+			    NL80211_AUTHTYPE_SHARED_KEY);
+	else
+		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
+			    NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+	ver = 0;
+	if (params->wpa_version & WPA_PROTO_WPA)
+		ver |= NL80211_WPA_VERSION_1;
+	if (params->wpa_version & WPA_PROTO_RSN)
+		ver |= NL80211_WPA_VERSION_2;
+	if (ver)
+		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+
+	num_suites = 0;
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
+		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
+		suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+	if (num_suites) {
+		NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
+			num_suites * sizeof(u32), suites);
+	}
+
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
+	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
+		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+
+	num_suites = 0;
+	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+	if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
+	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+	if (num_suites) {
+		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+			num_suites * sizeof(u32), suites);
+	}
+
+	switch (params->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_CCMP);
+		break;
+	case WPA_CIPHER_GCMP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_GCMP);
+		break;
+	case WPA_CIPHER_TKIP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_TKIP);
+		break;
+	case WPA_CIPHER_WEP104:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP104);
+		break;
+	case WPA_CIPHER_WEP40:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP40);
+		break;
+	}
+
+	if (params->beacon_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+			wpabuf_head(params->beacon_ies));
+	}
+	if (params->proberesp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			wpabuf_len(params->proberesp_ies),
+			wpabuf_head(params->proberesp_ies));
+	}
+	if (params->assocresp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+			wpabuf_len(params->assocresp_ies),
+			wpabuf_head(params->assocresp_ies));
+	}
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
+		NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+			    params->ap_max_inactivity);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
+			   ret, strerror(-ret));
+	} else {
+		bss->beacon_set = 1;
+		nl80211_set_bss(bss, params->cts_protect, params->preamble,
+				params->short_slot_time, params->ht_opmode,
+				params->isolate, params->basic_rates);
+	}
+	return ret;
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+				       int freq, int ht_enabled,
+				       int sec_channel_offset)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
+		   "sec_channel_offset=%d)",
+		   freq, ht_enabled, sec_channel_offset);
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	if (ht_enabled) {
+		switch (sec_channel_offset) {
+		case -1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40MINUS);
+			break;
+		case 1:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT40PLUS);
+			break;
+		default:
+			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+				    NL80211_CHAN_HT20);
+			break;
+		}
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret == 0) {
+		bss->freq = freq;
+		return 0;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
+		   "%d (%s)", freq, ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static u32 sta_flags_nl80211(int flags)
+{
+	u32 f = 0;
+
+	if (flags & WPA_STA_AUTHORIZED)
+		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+	if (flags & WPA_STA_WMM)
+		f |= BIT(NL80211_STA_FLAG_WME);
+	if (flags & WPA_STA_SHORT_PREAMBLE)
+		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+	if (flags & WPA_STA_MFP)
+		f |= BIT(NL80211_STA_FLAG_MFP);
+	if (flags & WPA_STA_TDLS_PEER)
+		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+	return f;
+}
+
+
+static int wpa_driver_nl80211_sta_add(void *priv,
+				      struct hostapd_sta_add_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg, *wme = NULL;
+	struct nl80211_sta_flag_update upd;
+	int ret = -ENOBUFS;
+
+	if ((params->flags & WPA_STA_TDLS_PEER) &&
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+		    NL80211_CMD_NEW_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
+	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
+		params->supp_rates);
+	if (!params->set) {
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+			    params->listen_interval);
+	}
+	if (params->ht_capabilities) {
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
+			sizeof(*params->ht_capabilities),
+			params->ht_capabilities);
+	}
+
+	os_memset(&upd, 0, sizeof(upd));
+	upd.mask = sta_flags_nl80211(params->flags);
+	upd.set = upd.mask;
+	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	if (params->flags & WPA_STA_WMM) {
+		wme = nlmsg_alloc();
+		if (!wme)
+			goto nla_put_failure;
+
+		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+				(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+				WMM_QOSINFO_STA_SP_MASK);
+		if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
+			goto nla_put_failure;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+			   "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+			   strerror(-ret));
+	if (ret == -EEXIST)
+		ret = 0;
+ nla_put_failure:
+	nlmsg_free(wme);
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+		    if_nametoindex(bss->ifname));
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret == -ENOENT)
+		return 0;
+	return ret;
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+				 int ifidx)
+{
+	struct nl_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
+
+	/* stop listening for EAPOL on this interface */
+	del_ifidx(drv, ifidx);
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto nla_put_failure;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+
+	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+		return;
+	msg = NULL;
+ nla_put_failure:
+	nlmsg_free(msg);
+	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
+}
+
+
+static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+	switch (mode) {
+	case NL80211_IFTYPE_ADHOC:
+		return "ADHOC";
+	case NL80211_IFTYPE_STATION:
+		return "STATION";
+	case NL80211_IFTYPE_AP:
+		return "AP";
+	case NL80211_IFTYPE_MONITOR:
+		return "MONITOR";
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return "P2P_CLIENT";
+	case NL80211_IFTYPE_P2P_GO:
+		return "P2P_GO";
+	default:
+		return "unknown";
+	}
+}
+
+
+static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
+				     const char *ifname,
+				     enum nl80211_iftype iftype,
+				     const u8 *addr, int wds)
+{
+	struct nl_msg *msg, *flags = NULL;
+	int ifidx;
+	int ret = -ENOBUFS;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+		   iftype, nl80211_iftype_str(iftype));
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+	if (iftype == NL80211_IFTYPE_MONITOR) {
+		int err;
+
+		flags = nlmsg_alloc();
+		if (!flags)
+			goto nla_put_failure;
+
+		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+		nlmsg_free(flags);
+
+		if (err)
+			goto nla_put_failure;
+	} else if (wds) {
+		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+ nla_put_failure:
+		nlmsg_free(msg);
+		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
+			   ifname, ret, strerror(-ret));
+		return ret;
+	}
+
+	ifidx = if_nametoindex(ifname);
+	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
+		   ifname, ifidx);
+
+	if (ifidx <= 0)
+		return -1;
+
+	/* start listening for EAPOL on this interface */
+	add_ifidx(drv, ifidx);
+
+	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
+	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
+		nl80211_remove_iface(drv, ifidx);
+		return -1;
+	}
+
+	return ifidx;
+}
+
+
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+				const char *ifname, enum nl80211_iftype iftype,
+				const u8 *addr, int wds)
+{
+	int ret;
+
+	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
+
+	/* if error occurred and interface exists already */
+	if (ret == -ENFILE && if_nametoindex(ifname)) {
+		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
+
+		/* Try to remove the interface that was already there. */
+		nl80211_remove_iface(drv, if_nametoindex(ifname));
+
+		/* Try to create the interface again */
+		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
+						wds);
+	}
+
+	if (ret >= 0 && is_p2p_interface(iftype))
+		nl80211_disable_11b_rates(drv, ret, 1);
+
+	return ret;
+}
+
+
+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = buf;
+	event.tx_status.data_len = len;
+	event.tx_status.ack = ok;
+	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+			     u8 *buf, size_t len)
+{
+	struct ieee80211_hdr *hdr = (void *)buf;
+	u16 fc;
+	union wpa_event_data event;
+
+	if (len < sizeof(*hdr))
+		return;
+
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = hdr->addr2;
+	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+		(WLAN_FC_FROMDS | WLAN_FC_TODS);
+	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+			 u8 *buf, size_t len, int datarate, int ssi_signal)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	switch (WLAN_FC_GET_TYPE(fc)) {
+	case WLAN_FC_TYPE_MGMT:
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = len;
+		event.rx_mgmt.datarate = datarate;
+		event.rx_mgmt.ssi_signal = ssi_signal;
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+		break;
+	case WLAN_FC_TYPE_CTRL:
+		/* can only get here with PS-Poll frames */
+		wpa_printf(MSG_DEBUG, "CTRL");
+		from_unknown_sta(drv, buf, len);
+		break;
+	case WLAN_FC_TYPE_DATA:
+		from_unknown_sta(drv, buf, len);
+		break;
+	}
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	int len;
+	unsigned char buf[3000];
+	struct ieee80211_radiotap_iterator iter;
+	int ret;
+	int datarate = 0, ssi_signal = 0;
+	int injected = 0, failed = 0, rxflags = 0;
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+		printf("received invalid radiotap frame\n");
+		return;
+	}
+
+	while (1) {
+		ret = ieee80211_radiotap_iterator_next(&iter);
+		if (ret == -ENOENT)
+			break;
+		if (ret) {
+			printf("received invalid radiotap frame (%d)\n", ret);
+			return;
+		}
+		switch (iter.this_arg_index) {
+		case IEEE80211_RADIOTAP_FLAGS:
+			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+				len -= 4;
+			break;
+		case IEEE80211_RADIOTAP_RX_FLAGS:
+			rxflags = 1;
+			break;
+		case IEEE80211_RADIOTAP_TX_FLAGS:
+			injected = 1;
+			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+					IEEE80211_RADIOTAP_F_TX_FAIL;
+			break;
+		case IEEE80211_RADIOTAP_DATA_RETRIES:
+			break;
+		case IEEE80211_RADIOTAP_CHANNEL:
+			/* TODO: convert from freq/flags to channel number */
+			break;
+		case IEEE80211_RADIOTAP_RATE:
+			datarate = *iter.this_arg * 5;
+			break;
+		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+			ssi_signal = (s8) *iter.this_arg;
+			break;
+		}
+	}
+
+	if (rxflags && injected)
+		return;
+
+	if (!injected)
+		handle_frame(drv, buf + iter.max_length,
+			     len - iter.max_length, datarate, ssi_signal);
+	else
+		handle_tx_callback(drv->ctx, buf + iter.max_length,
+				   len - iter.max_length, !failed);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS	0xFF
+#define FAIL	0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+	/*
+	 * do a little-endian load of the radiotap length field
+	 */
+	/* load lower byte into A */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
+	/* put it into X (== index register) */
+	BPF_STMT(BPF_MISC| BPF_TAX, 0),
+	/* load upper byte into A */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
+	/* left-shift it by 8 */
+	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+	/* or with X */
+	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+	/* put result into X */
+	BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+	/*
+	 * Allow management frames through, this also gives us those
+	 * management frames that we sent ourselves with status
+	 */
+	/* load the lower byte of the IEEE 802.11 frame control field */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
+	/* mask off frame type and version */
+	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+	/* accept frame if it's both 0, fall through otherwise */
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+	/*
+	 * TODO: add a bit to radiotap RX flags that indicates
+	 * that the sending station is not associated, then
+	 * add a filter here that filters on our DA and that flag
+	 * to allow us to deauth frames to that bad station.
+	 *
+	 * For now allow all To DS data frames through.
+	 */
+	/* load the IEEE 802.11 frame control field */
+	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
+	/* mask off frame type, version and DS status */
+	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+	/* accept frame if version 0, type 2 and To DS, fall through otherwise
+	 */
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
+
+#if 0
+	/*
+	 * drop non-data frames
+	 */
+	/* load the lower byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
+	/* mask off QoS bit */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
+	/* drop non-data frames */
+	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
+	/* load the upper byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
+	/* mask off toDS/fromDS */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
+	/* accept WDS frames */
+	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
+
+	/*
+	 * add header length to index
+	 */
+	/* load the lower byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
+	/* mask off QoS bit */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
+	/* right shift it by 6 to give 0 or 2 */
+	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
+	/* add data frame header length */
+	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
+	/* add index, was start of 802.11 header */
+	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
+	/* move to index, now start of LL header */
+	BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+	/*
+	 * Accept empty data frames, we use those for
+	 * polling activity.
+	 */
+	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+	/*
+	 * Accept EAPOL frames
+	 */
+	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+	/* keep these last two statements or change the code below */
+	/* return 0 == "DROP" */
+	BPF_STMT(BPF_RET | BPF_K, 0),
+	/* return ~0 == "keep all" */
+	BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+	.filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+	int idx;
+
+	/* rewrite all PASS/FAIL jump offsets */
+	for (idx = 0; idx < msock_filter.len; idx++) {
+		struct sock_filter *insn = &msock_filter_insns[idx];
+
+		if (BPF_CLASS(insn->code) == BPF_JMP) {
+			if (insn->code == (BPF_JMP|BPF_JA)) {
+				if (insn->k == PASS)
+					insn->k = msock_filter.len - idx - 2;
+				else if (insn->k == FAIL)
+					insn->k = msock_filter.len - idx - 3;
+			}
+
+			if (insn->jt == PASS)
+				insn->jt = msock_filter.len - idx - 2;
+			else if (insn->jt == FAIL)
+				insn->jt = msock_filter.len - idx - 3;
+
+			if (insn->jf == PASS)
+				insn->jf = msock_filter.len - idx - 2;
+			else if (insn->jf == FAIL)
+				insn->jf = msock_filter.len - idx - 3;
+		}
+	}
+
+	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+		       &msock_filter, sizeof(msock_filter))) {
+		perror("SO_ATTACH_FILTER");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void nl80211_remove_monitor_interface(
+	struct wpa_driver_nl80211_data *drv)
+{
+	drv->monitor_refcount--;
+	if (drv->monitor_refcount > 0)
+		return;
+
+	if (drv->monitor_ifidx >= 0) {
+		nl80211_remove_iface(drv, drv->monitor_ifidx);
+		drv->monitor_ifidx = -1;
+	}
+	if (drv->monitor_sock >= 0) {
+		eloop_unregister_read_sock(drv->monitor_sock);
+		close(drv->monitor_sock);
+		drv->monitor_sock = -1;
+	}
+}
+
+
+static int
+nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+	char buf[IFNAMSIZ];
+	struct sockaddr_ll ll;
+	int optval;
+	socklen_t optlen;
+
+	if (drv->monitor_ifidx >= 0) {
+		drv->monitor_refcount++;
+		return 0;
+	}
+
+	if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
+		/*
+		 * P2P interface name is of the format p2p-%s-%d. For monitor
+		 * interface name corresponding to P2P GO, replace "p2p-" with
+		 * "mon-" to retain the same interface name length and to
+		 * indicate that it is a monitor interface.
+		 */
+		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
+	} else {
+		/* Non-P2P interface with AP functionality. */
+		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
+	}
+
+	buf[IFNAMSIZ - 1] = '\0';
+
+	drv->monitor_ifidx =
+		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+				     0);
+
+	if (drv->monitor_ifidx == -EOPNOTSUPP) {
+		/*
+		 * This is backward compatibility for a few versions of
+		 * the kernel only that didn't advertise the right
+		 * attributes for the only driver that then supported
+		 * AP mode w/o monitor -- ath6kl.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+			   "monitor interface type - try to run without it");
+		drv->device_ap_sme = 1;
+	}
+
+	if (drv->monitor_ifidx < 0)
+		return -1;
+
+	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
+		goto error;
+
+	memset(&ll, 0, sizeof(ll));
+	ll.sll_family = AF_PACKET;
+	ll.sll_ifindex = drv->monitor_ifidx;
+	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (drv->monitor_sock < 0) {
+		perror("socket[PF_PACKET,SOCK_RAW]");
+		goto error;
+	}
+
+	if (add_monitor_filter(drv->monitor_sock)) {
+		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+			   "interface; do filtering in user space");
+		/* This works, but will cost in performance. */
+	}
+
+	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		perror("monitor socket bind");
+		goto error;
+	}
+
+	optlen = sizeof(optval);
+	optval = 20;
+	if (setsockopt
+	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+		perror("Failed to set socket priority");
+		goto error;
+	}
+
+	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+				     drv, NULL)) {
+		printf("Could not register monitor read socket\n");
+		goto error;
+	}
+
+	return 0;
+ error:
+	nl80211_remove_monitor_interface(drv);
+	return -1;
+}
+
+
+static int nl80211_setup_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
+		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+
+	/*
+	 * Disable Probe Request reporting unless we need it in this way for
+	 * devices that include the AP SME, in the other case (unless using
+	 * monitor iface) we'll get it through the nl_mgmt socket instead.
+	 */
+	if (!drv->device_ap_sme)
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+
+	if (!drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap(bss))
+			return -1;
+
+	if (drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+			return -1;
+
+	if (!drv->device_ap_sme && drv->use_monitor &&
+	    nl80211_create_monitor_interface(drv) &&
+	    !drv->device_ap_sme)
+		return -1;
+
+	if (drv->device_ap_sme &&
+	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+			   "Probe Request frame reporting in AP mode");
+		/* Try to survive without this */
+	}
+
+	return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->device_ap_sme) {
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+		if (!drv->use_monitor)
+			nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+	} else if (drv->use_monitor)
+		nl80211_remove_monitor_interface(drv);
+	else
+		nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+	bss->beacon_set = 0;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+				   const u8 *addr, const u8 *data,
+				   size_t data_len)
+{
+	struct sockaddr_ll ll;
+	int ret;
+
+	if (bss->drv->eapol_tx_sock < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+		return -1;
+	}
+
+	os_memset(&ll, 0, sizeof(ll));
+	ll.sll_family = AF_PACKET;
+	ll.sll_ifindex = bss->ifindex;
+	ll.sll_protocol = htons(ETH_P_PAE);
+	ll.sll_halen = ETH_ALEN;
+	os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+	ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+		     (struct sockaddr *) &ll, sizeof(ll));
+	if (ret < 0)
+		wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+			   strerror(errno));
+
+	return ret;
+}
+
+
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+static int wpa_driver_nl80211_hapd_send_eapol(
+	void *priv, const u8 *addr, const u8 *data,
+	size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ieee80211_hdr *hdr;
+	size_t len;
+	u8 *pos;
+	int res;
+	int qos = flags & WPA_STA_WMM;
+
+	if (drv->device_ap_sme || !drv->use_monitor)
+		return nl80211_send_eapol_data(bss, addr, data, data_len);
+
+	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+		data_len;
+	hdr = os_zalloc(len);
+	if (hdr == NULL) {
+		printf("malloc() failed for i802_send_data(len=%lu)\n",
+		       (unsigned long) len);
+		return -1;
+	}
+
+	hdr->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+	if (encrypt)
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	if (qos) {
+		hdr->frame_control |=
+			host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
+	}
+
+	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+	pos = (u8 *) (hdr + 1);
+
+	if (qos) {
+		/* Set highest priority in QoS header */
+		pos[0] = 7;
+		pos[1] = 0;
+		pos += 2;
+	}
+
+	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+	pos += sizeof(rfc1042_header);
+	WPA_PUT_BE16(pos, ETH_P_PAE);
+	pos += 2;
+	memcpy(pos, data, data_len);
+
+	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
+					    0, 0, 0, 0);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
+			   "failed: %d (%s)",
+			   (unsigned long) len, errno, strerror(errno));
+	}
+	os_free(hdr);
+
+	return res;
+}
+
+
+static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
+					    int total_flags,
+					    int flags_or, int flags_and)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg, *flags = NULL;
+	struct nl80211_sta_flag_update upd;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	flags = nlmsg_alloc();
+	if (!flags) {
+		nlmsg_free(msg);
+		return -ENOMEM;
+	}
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+		    if_nametoindex(bss->ifname));
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+	/*
+	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
+	 * can be removed eventually.
+	 */
+	if (total_flags & WPA_STA_AUTHORIZED)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+	if (total_flags & WPA_STA_WMM)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+
+	if (total_flags & WPA_STA_SHORT_PREAMBLE)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+
+	if (total_flags & WPA_STA_MFP)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+
+	if (total_flags & WPA_STA_TDLS_PEER)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
+	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+		goto nla_put_failure;
+
+	os_memset(&upd, 0, sizeof(upd));
+	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
+	upd.set = sta_flags_nl80211(flags_or);
+	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	nlmsg_free(flags);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	nlmsg_free(flags);
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
+				 struct wpa_driver_associate_params *params)
+{
+	enum nl80211_iftype nlmode, old_mode;
+
+	if (params->p2p) {
+		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
+			   "group (GO)");
+		nlmode = NL80211_IFTYPE_P2P_GO;
+	} else
+		nlmode = NL80211_IFTYPE_AP;
+
+	old_mode = drv->nlmode;
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+		nl80211_remove_monitor_interface(drv);
+		return -1;
+	}
+
+	if (wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
+		if (old_mode != nlmode)
+			wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
+		nl80211_remove_monitor_interface(drv);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
+				   struct wpa_driver_associate_params *params)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+	int count = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
+
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+					NL80211_IFTYPE_ADHOC)) {
+		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
+			   "IBSS mode");
+		return -1;
+	}
+
+retry:
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+		goto nla_put_failure;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+			  params->ssid, params->ssid_len);
+	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+		params->ssid);
+	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+	drv->ssid_len = params->ssid_len;
+
+	wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+
+	ret = nl80211_set_conn_keys(params, msg);
+	if (ret)
+		goto nla_put_failure;
+
+	if (params->bssid && params->fixed_bssid) {
+		wpa_printf(MSG_DEBUG, "  * BSSID=" MACSTR,
+			   MAC2STR(params->bssid));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+	}
+
+	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+	    params->key_mgmt_suite == KEY_MGMT_PSK ||
+	    params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
+	    params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
+		wpa_printf(MSG_DEBUG, "  * control port");
+		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+	}
+
+	if (params->wpa_ie) {
+		wpa_hexdump(MSG_DEBUG,
+			    "  * Extra IEs for Beacon/Probe Response frames",
+			    params->wpa_ie, params->wpa_ie_len);
+		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+			params->wpa_ie);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		count++;
+		if (ret == -EALREADY && count == 1) {
+			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
+				   "forced leave");
+			nl80211_leave_ibss(drv);
+			nlmsg_free(msg);
+			goto retry;
+		}
+
+		goto nla_put_failure;
+	}
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_try_connect(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_driver_associate_params *params)
+{
+	struct nl_msg *msg;
+	enum nl80211_auth_type type;
+	int ret = 0;
+	int algs;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (params->bssid) {
+		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
+			   MAC2STR(params->bssid));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+	}
+	if (params->freq) {
+		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+	}
+	if (params->bg_scan_period >= 0) {
+		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
+			   params->bg_scan_period);
+		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+			    params->bg_scan_period);
+	}
+	if (params->ssid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+				  params->ssid, params->ssid_len);
+		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+			params->ssid);
+		if (params->ssid_len > sizeof(drv->ssid))
+			goto nla_put_failure;
+		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+		drv->ssid_len = params->ssid_len;
+	}
+	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
+	if (params->wpa_ie)
+		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+			params->wpa_ie);
+
+	algs = 0;
+	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+		algs++;
+	if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+		algs++;
+	if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+		algs++;
+	if (algs > 1) {
+		wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
+			   "selection");
+		goto skip_auth_type;
+	}
+
+	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+		type = NL80211_AUTHTYPE_SHARED_KEY;
+	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
+		type = NL80211_AUTHTYPE_NETWORK_EAP;
+	else if (params->auth_alg & WPA_AUTH_ALG_FT)
+		type = NL80211_AUTHTYPE_FT;
+	else
+		goto nla_put_failure;
+
+	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
+	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+
+skip_auth_type:
+	if (params->wpa_proto) {
+		enum nl80211_wpa_versions ver = 0;
+
+		if (params->wpa_proto & WPA_PROTO_WPA)
+			ver |= NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_RSN)
+			ver |= NL80211_WPA_VERSION_2;
+
+		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
+		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+	}
+
+	if (params->pairwise_suite != CIPHER_NONE) {
+		int cipher;
+
+		switch (params->pairwise_suite) {
+		case CIPHER_SMS4:
+			cipher = WLAN_CIPHER_SUITE_SMS4;
+			break;
+		case CIPHER_WEP40:
+			cipher = WLAN_CIPHER_SUITE_WEP40;
+			break;
+		case CIPHER_WEP104:
+			cipher = WLAN_CIPHER_SUITE_WEP104;
+			break;
+		case CIPHER_CCMP:
+			cipher = WLAN_CIPHER_SUITE_CCMP;
+			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
+		case CIPHER_TKIP:
+		default:
+			cipher = WLAN_CIPHER_SUITE_TKIP;
+			break;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+	}
+
+	if (params->group_suite != CIPHER_NONE) {
+		int cipher;
+
+		switch (params->group_suite) {
+		case CIPHER_SMS4:
+			cipher = WLAN_CIPHER_SUITE_SMS4;
+			break;
+		case CIPHER_WEP40:
+			cipher = WLAN_CIPHER_SUITE_WEP40;
+			break;
+		case CIPHER_WEP104:
+			cipher = WLAN_CIPHER_SUITE_WEP104;
+			break;
+		case CIPHER_CCMP:
+			cipher = WLAN_CIPHER_SUITE_CCMP;
+			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
+		case CIPHER_TKIP:
+		default:
+			cipher = WLAN_CIPHER_SUITE_TKIP;
+			break;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+	}
+
+	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+	    params->key_mgmt_suite == KEY_MGMT_PSK ||
+	    params->key_mgmt_suite == KEY_MGMT_CCKM) {
+		int mgmt = WLAN_AKM_SUITE_PSK;
+
+		switch (params->key_mgmt_suite) {
+		case KEY_MGMT_CCKM:
+			mgmt = WLAN_AKM_SUITE_CCKM;
+			break;
+		case KEY_MGMT_802_1X:
+			mgmt = WLAN_AKM_SUITE_8021X;
+			break;
+		case KEY_MGMT_PSK:
+		default:
+			mgmt = WLAN_AKM_SUITE_PSK;
+			break;
+		}
+		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+	}
+
+	if (params->disable_ht)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+	if (params->htcaps && params->htcaps_mask) {
+		int sz = sizeof(struct ieee80211_ht_capabilities);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+			params->htcaps_mask);
+	}
+
+	ret = nl80211_set_conn_keys(params, msg);
+	if (ret)
+		goto nla_put_failure;
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+		goto nla_put_failure;
+	}
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+
+}
+
+
+static int wpa_driver_nl80211_connect(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_driver_associate_params *params)
+{
+	int ret = wpa_driver_nl80211_try_connect(drv, params);
+	if (ret == -EALREADY) {
+		/*
+		 * cfg80211 does not currently accept new connections if
+		 * we are already connected. As a workaround, force
+		 * disconnection and try again.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+			   "disconnecting before reassociation "
+			   "attempt");
+		if (wpa_driver_nl80211_disconnect(
+			    drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+			return -1;
+		/* Ignore the next local disconnect message. */
+		drv->ignore_next_local_disconnect = 1;
+		ret = wpa_driver_nl80211_try_connect(drv, params);
+	}
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1;
+	struct nl_msg *msg;
+
+	if (params->mode == IEEE80211_MODE_AP)
+		return wpa_driver_nl80211_ap(drv, params);
+
+	if (params->mode == IEEE80211_MODE_IBSS)
+		return wpa_driver_nl80211_ibss(drv, params);
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+		enum nl80211_iftype nlmode = params->p2p ?
+			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+			return -1;
+		return wpa_driver_nl80211_connect(drv, params);
+	}
+
+	drv->associated = 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
+		   drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (params->bssid) {
+		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
+			   MAC2STR(params->bssid));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+	}
+	if (params->freq) {
+		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+		drv->assoc_freq = params->freq;
+	} else
+		drv->assoc_freq = 0;
+	if (params->bg_scan_period >= 0) {
+		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
+			   params->bg_scan_period);
+		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+			    params->bg_scan_period);
+	}
+	if (params->ssid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+				  params->ssid, params->ssid_len);
+		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+			params->ssid);
+		if (params->ssid_len > sizeof(drv->ssid))
+			goto nla_put_failure;
+		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+		drv->ssid_len = params->ssid_len;
+	}
+	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
+	if (params->wpa_ie)
+		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+			params->wpa_ie);
+
+	if (params->pairwise_suite != CIPHER_NONE) {
+		int cipher;
+
+		switch (params->pairwise_suite) {
+		case CIPHER_WEP40:
+			cipher = WLAN_CIPHER_SUITE_WEP40;
+			break;
+		case CIPHER_WEP104:
+			cipher = WLAN_CIPHER_SUITE_WEP104;
+			break;
+		case CIPHER_CCMP:
+			cipher = WLAN_CIPHER_SUITE_CCMP;
+			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
+		case CIPHER_TKIP:
+		default:
+			cipher = WLAN_CIPHER_SUITE_TKIP;
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+	}
+
+	if (params->group_suite != CIPHER_NONE) {
+		int cipher;
+
+		switch (params->group_suite) {
+		case CIPHER_WEP40:
+			cipher = WLAN_CIPHER_SUITE_WEP40;
+			break;
+		case CIPHER_WEP104:
+			cipher = WLAN_CIPHER_SUITE_WEP104;
+			break;
+		case CIPHER_CCMP:
+			cipher = WLAN_CIPHER_SUITE_CCMP;
+			break;
+		case CIPHER_GCMP:
+			cipher = WLAN_CIPHER_SUITE_GCMP;
+			break;
+		case CIPHER_TKIP:
+		default:
+			cipher = WLAN_CIPHER_SUITE_TKIP;
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
+	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+
+	if (params->prev_bssid) {
+		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
+			   MAC2STR(params->prev_bssid));
+		NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+			params->prev_bssid);
+	}
+
+	if (params->disable_ht)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+
+	if (params->htcaps && params->htcaps_mask) {
+		int sz = sizeof(struct ieee80211_ht_capabilities);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
+		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+			params->htcaps_mask);
+	}
+
+	if (params->p2p)
+		wpa_printf(MSG_DEBUG, "  * P2P group");
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (assoc): ret=%d (%s)",
+			ret, strerror(-ret));
+		nl80211_dump_scan(drv);
+		goto nla_put_failure;
+	}
+	ret = 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Association request send "
+		   "successfully");
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
+			    int ifindex, enum nl80211_iftype mode)
+{
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
+		   ifindex, mode, nl80211_iftype_str(mode));
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (!ret)
+		return 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
+		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1;
+	int i;
+	int was_ap = is_ap_interface(drv->nlmode);
+	int res;
+
+	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+	if (res == 0) {
+		drv->nlmode = nlmode;
+		ret = 0;
+		goto done;
+	}
+
+	if (res == -ENODEV)
+		return -1;
+
+	if (nlmode == drv->nlmode) {
+		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
+			   "requested mode - ignore error");
+		ret = 0;
+		goto done; /* Already in the requested mode */
+	}
+
+	/* mac80211 doesn't allow mode changes while the device is up, so
+	 * take the device down, try to set the mode again, and bring the
+	 * device back up.
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
+		   "interface down");
+	for (i = 0; i < 10; i++) {
+		res = linux_set_iface_flags(drv->global->ioctl_sock,
+					    bss->ifname, 0);
+		if (res == -EACCES || res == -ENODEV)
+			break;
+		if (res == 0) {
+			/* Try to set the mode again while the interface is
+			 * down */
+			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
+			if (ret == -EACCES)
+				break;
+			res = linux_set_iface_flags(drv->global->ioctl_sock,
+						    bss->ifname, 1);
+			if (res && !ret)
+				ret = -1;
+			else if (ret != -EBUSY)
+				break;
+		} else
+			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
+				   "interface down");
+		os_sleep(0, 100000);
+	}
+
+	if (!ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
+			   "interface is down");
+		drv->nlmode = nlmode;
+		drv->ignore_if_down_event = 1;
+	}
+
+done:
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+			   "from %d failed", nlmode, drv->nlmode);
+		return ret;
+	}
+
+	if (is_p2p_interface(nlmode))
+		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+	else if (drv->disabled_11b_rates)
+		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
+	if (is_ap_interface(nlmode)) {
+		nl80211_mgmt_unsubscribe(bss, "start AP");
+		/* Setup additional AP mode functionality if needed */
+		if (nl80211_setup_ap(bss))
+			return -1;
+	} else if (was_ap) {
+		/* Remove additional AP mode functionality */
+		nl80211_teardown_ap(bss);
+	} else {
+		nl80211_mgmt_unsubscribe(bss, "mode change");
+	}
+
+	if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+			   "frame processing - ignore for now");
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+				       struct wpa_driver_capa *capa)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!drv->has_capability)
+		return -1;
+	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+	drv->operstate = state;
+	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
+				      state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nl80211_sta_flag_update upd;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+		    if_nametoindex(bss->ifname));
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+
+	os_memset(&upd, 0, sizeof(upd));
+	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
+	if (authorized)
+		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
+	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
+					   freq->sec_channel_offset);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+
+static inline int min_int(int a, int b)
+{
+	if (a < b)
+		return a;
+	return b;
+}
+
+
+static int get_key_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	/*
+	 * TODO: validate the key index and mac address!
+	 * Otherwise, there's a race condition as soon as
+	 * the kernel starts sending key notifications.
+	 */
+
+	if (tb[NL80211_ATTR_KEY_SEQ])
+		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+	return NL_SKIP;
+}
+
+
+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+			   int idx, u8 *seq)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
+
+	if (addr)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+	memset(seq, 0, 6);
+
+	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int i802_set_rts(void *priv, int rts)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+	u32 val;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	if (rts >= 2347)
+		val = (u32) -1;
+	else
+		val = rts;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (!ret)
+		return 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
+		   "%d (%s)", rts, ret, strerror(-ret));
+	return ret;
+}
+
+
+static int i802_set_frag(void *priv, int frag)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+	u32 val;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	if (frag >= 2346)
+		val = (u32) -1;
+	else
+		val = frag;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (!ret)
+		return 0;
+nla_put_failure:
+	nlmsg_free(msg);
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
+		   "%d: %d (%s)", frag, ret, strerror(-ret));
+	return ret;
+}
+
+
+static int i802_flush(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int res;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
+
+	/*
+	 * XXX: FIX! this needs to flush all VLANs too
+	 */
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+		    if_nametoindex(bss->ifname));
+
+	res = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
+			   "(%s)", res, strerror(-res));
+	}
+	return res;
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int get_sta_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct hostap_sta_driver_data *data = arg;
+	struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
+	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+		[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
+	};
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	/*
+	 * TODO: validate the interface and mac address!
+	 * Otherwise, there's a race condition as soon as
+	 * the kernel starts sending station notifications.
+	 */
+
+	if (!tb[NL80211_ATTR_STA_INFO]) {
+		wpa_printf(MSG_DEBUG, "sta stats missing!");
+		return NL_SKIP;
+	}
+	if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
+			     tb[NL80211_ATTR_STA_INFO],
+			     stats_policy)) {
+		wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
+		return NL_SKIP;
+	}
+
+	if (stats[NL80211_STA_INFO_INACTIVE_TIME])
+		data->inactive_msec =
+			nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
+	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_PACKETS])
+		data->rx_packets =
+			nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
+	if (stats[NL80211_STA_INFO_TX_PACKETS])
+		data->tx_packets =
+			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+	if (stats[NL80211_STA_INFO_TX_FAILED])
+		data->tx_retry_failed =
+			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
+
+	return NL_SKIP;
+}
+
+static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+			      const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	os_memset(data, 0, sizeof(*data));
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+
+static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
+				    int cw_min, int cw_max, int burst_time)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *txq, *params;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
+	if (!txq)
+		goto nla_put_failure;
+
+	/* We are only sending parameters for a single TXQ at a time */
+	params = nla_nest_start(msg, 1);
+	if (!params)
+		goto nla_put_failure;
+
+	switch (queue) {
+	case 0:
+		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
+		break;
+	case 1:
+		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
+		break;
+	case 2:
+		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
+		break;
+	case 3:
+		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
+		break;
+	}
+	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
+	 * 32 usec, so need to convert the value here. */
+	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
+	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
+	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
+	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
+
+	nla_nest_end(msg, params);
+
+	nla_nest_end(msg, txq);
+
+	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+		return 0;
+	msg = NULL;
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int i802_set_sta_vlan(void *priv, const u8 *addr,
+			     const char *ifname, int vlan_id)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+		    if_nametoindex(bss->ifname));
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
+		    if_nametoindex(ifname));
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
+			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
+			   MAC2STR(addr), ifname, vlan_id, ret,
+			   strerror(-ret));
+	}
+ nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int i802_get_inact_sec(void *priv, const u8 *addr)
+{
+	struct hostap_sta_driver_data data;
+	int ret;
+
+	data.inactive_msec = (unsigned long) -1;
+	ret = i802_read_sta_data(priv, &data, addr);
+	if (ret || data.inactive_msec == (unsigned long) -1)
+		return -1;
+	return data.inactive_msec / 1000;
+}
+
+
+static int i802_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if 0
+	/* TODO */
+#endif
+	return 0;
+}
+
+
+static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
+			   int reason)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ieee80211_mgmt mgmt;
+
+	if (drv->device_ap_sme)
+		return wpa_driver_nl80211_sta_remove(bss, addr);
+
+	memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_DEAUTH);
+	memcpy(mgmt.da, addr, ETH_ALEN);
+	memcpy(mgmt.sa, own_addr, ETH_ALEN);
+	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+	mgmt.u.deauth.reason_code = host_to_le16(reason);
+	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+					    IEEE80211_HDRLEN +
+					    sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+			     int reason)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ieee80211_mgmt mgmt;
+
+	if (drv->device_ap_sme)
+		return wpa_driver_nl80211_sta_remove(bss, addr);
+
+	memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_DISASSOC);
+	memcpy(mgmt.da, addr, ETH_ALEN);
+	memcpy(mgmt.sa, own_addr, ETH_ALEN);
+	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
+	mgmt.u.disassoc.reason_code = host_to_le16(reason);
+	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
+					    IEEE80211_HDRLEN +
+					    sizeof(mgmt.u.disassoc), 0);
+}
+
+#endif /* HOSTAPD || CONFIG_AP */
+
+#ifdef HOSTAPD
+
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+	int *old;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+		   ifidx);
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == 0) {
+			drv->if_indices[i] = ifidx;
+			return;
+		}
+	}
+
+	if (drv->if_indices != drv->default_if_indices)
+		old = drv->if_indices;
+	else
+		old = NULL;
+
+	drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+					   sizeof(int));
+	if (!drv->if_indices) {
+		if (!old)
+			drv->if_indices = drv->default_if_indices;
+		else
+			drv->if_indices = old;
+		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+			   "interfaces");
+		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+		return;
+	} else if (!old)
+		os_memcpy(drv->if_indices, drv->default_if_indices,
+			  sizeof(drv->default_if_indices));
+	drv->if_indices[drv->num_if_indices] = ifidx;
+	drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++) {
+		if (drv->if_indices[i] == ifidx) {
+			drv->if_indices[i] = 0;
+			break;
+		}
+	}
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+	int i;
+
+	for (i = 0; i < drv->num_if_indices; i++)
+		if (drv->if_indices[i] == ifidx)
+			return 1;
+
+	return 0;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+                            const char *bridge_ifname)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	char name[IFNAMSIZ + 1];
+
+	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+	if (val) {
+		if (!if_nametoindex(name)) {
+			if (nl80211_create_iface(drv, name,
+						 NL80211_IFTYPE_AP_VLAN,
+						 NULL, 1) < 0)
+				return -1;
+			if (bridge_ifname &&
+			    linux_br_add_if(drv->global->ioctl_sock,
+					    bridge_ifname, name) < 0)
+				return -1;
+		}
+		if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+				   "interface %s up", name);
+		}
+		return i802_set_sta_vlan(priv, addr, name, 0);
+	} else {
+		if (bridge_ifname)
+			linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+					name);
+
+		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+						    name);
+	}
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct sockaddr_ll lladdr;
+	unsigned char buf[3000];
+	int len;
+	socklen_t fromlen = sizeof(lladdr);
+
+	len = recvfrom(sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *)&lladdr, &fromlen);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	if (have_ifidx(drv, lladdr.sll_ifindex))
+		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
+static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
+			     struct i802_bss *bss,
+			     const char *brname, const char *ifname)
+{
+	int ifindex;
+	char in_br[IFNAMSIZ];
+
+	os_strlcpy(bss->brname, brname, IFNAMSIZ);
+	ifindex = if_nametoindex(brname);
+	if (ifindex == 0) {
+		/*
+		 * Bridge was configured, but the bridge device does
+		 * not exist. Try to add it now.
+		 */
+		if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
+				   "bridge interface %s: %s",
+				   brname, strerror(errno));
+			return -1;
+		}
+		bss->added_bridge = 1;
+		add_ifidx(drv, if_nametoindex(brname));
+	}
+
+	if (linux_br_get(in_br, ifname) == 0) {
+		if (os_strcmp(in_br, brname) == 0)
+			return 0; /* already in the bridge */
+
+		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
+			   "bridge %s", ifname, in_br);
+		if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+		    0) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to "
+				   "remove interface %s from bridge "
+				   "%s: %s",
+				   ifname, brname, strerror(errno));
+			return -1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
+		   ifname, brname);
+	if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
+			   "into bridge %s: %s",
+			   ifname, brname, strerror(errno));
+		return -1;
+	}
+	bss->added_if_into_bridge = 1;
+
+	return 0;
+}
+
+
+static void *i802_init(struct hostapd_data *hapd,
+		       struct wpa_init_params *params)
+{
+	struct wpa_driver_nl80211_data *drv;
+	struct i802_bss *bss;
+	size_t i;
+	char brname[IFNAMSIZ];
+	int ifindex, br_ifindex;
+	int br_added = 0;
+
+	bss = wpa_driver_nl80211_init(hapd, params->ifname,
+				      params->global_priv);
+	if (bss == NULL)
+		return NULL;
+
+	drv = bss->drv;
+	drv->nlmode = NL80211_IFTYPE_AP;
+	drv->eapol_sock = -1;
+
+	if (linux_br_get(brname, params->ifname) == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
+			   params->ifname, brname);
+		br_ifindex = if_nametoindex(brname);
+	} else {
+		brname[0] = '\0';
+		br_ifindex = 0;
+	}
+
+	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+	drv->if_indices = drv->default_if_indices;
+	for (i = 0; i < params->num_bridge; i++) {
+		if (params->bridge[i]) {
+			ifindex = if_nametoindex(params->bridge[i]);
+			if (ifindex)
+				add_ifidx(drv, ifindex);
+			if (ifindex == br_ifindex)
+				br_added = 1;
+		}
+	}
+	if (!br_added && br_ifindex &&
+	    (params->num_bridge == 0 || !params->bridge[0]))
+		add_ifidx(drv, br_ifindex);
+
+	/* start listening for EAPOL on the default AP interface */
+	add_ifidx(drv, drv->ifindex);
+
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
+		goto failed;
+
+	if (params->bssid) {
+		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				       params->bssid))
+			goto failed;
+	}
+
+	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
+			   "into AP mode", bss->ifname);
+		goto failed;
+	}
+
+	if (params->num_bridge && params->bridge[0] &&
+	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
+		goto failed;
+
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
+		goto failed;
+
+	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
+	if (drv->eapol_sock < 0) {
+		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+		goto failed;
+	}
+
+	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
+	{
+		printf("Could not register read socket for eapol\n");
+		goto failed;
+	}
+
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       params->own_addr))
+		goto failed;
+
+	memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
+	return bss;
+
+failed:
+	wpa_driver_nl80211_deinit(bss);
+	return NULL;
+}
+
+
+static void i802_deinit(void *priv)
+{
+	wpa_driver_nl80211_deinit(priv);
+}
+
+#endif /* HOSTAPD */
+
+
+static enum nl80211_iftype wpa_driver_nl80211_if_type(
+	enum wpa_driver_if_type type)
+{
+	switch (type) {
+	case WPA_IF_STATION:
+		return NL80211_IFTYPE_STATION;
+	case WPA_IF_P2P_CLIENT:
+	case WPA_IF_P2P_GROUP:
+		return NL80211_IFTYPE_P2P_CLIENT;
+	case WPA_IF_AP_VLAN:
+		return NL80211_IFTYPE_AP_VLAN;
+	case WPA_IF_AP_BSS:
+		return NL80211_IFTYPE_AP;
+	case WPA_IF_P2P_GO:
+		return NL80211_IFTYPE_P2P_GO;
+	}
+	return -1;
+}
+
+
+#ifdef CONFIG_P2P
+
+static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
+{
+	struct wpa_driver_nl80211_data *drv;
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
+static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
+				      u8 *new_addr)
+{
+	unsigned int idx;
+
+	if (!drv->global)
+		return -1;
+
+	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
+	for (idx = 0; idx < 64; idx++) {
+		new_addr[0] = drv->first_bss.addr[0] | 0x02;
+		new_addr[0] ^= idx << 2;
+		if (!nl80211_addr_in_use(drv->global, new_addr))
+			break;
+	}
+	if (idx == 64)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+		   MACSTR, MAC2STR(new_addr));
+
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
+				     const char *ifname, const u8 *addr,
+				     void *bss_ctx, void **drv_priv,
+				     char *force_ifname, u8 *if_addr,
+				     const char *bridge)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ifidx;
+#ifdef HOSTAPD
+	struct i802_bss *new_bss = NULL;
+
+	if (type == WPA_IF_AP_BSS) {
+		new_bss = os_zalloc(sizeof(*new_bss));
+		if (new_bss == NULL)
+			return -1;
+	}
+#endif /* HOSTAPD */
+
+	if (addr)
+		os_memcpy(if_addr, addr, ETH_ALEN);
+	ifidx = nl80211_create_iface(drv, ifname,
+				     wpa_driver_nl80211_if_type(type), addr,
+				     0);
+	if (ifidx < 0) {
+#ifdef HOSTAPD
+		os_free(new_bss);
+#endif /* HOSTAPD */
+		return -1;
+	}
+
+	if (!addr &&
+	    linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       if_addr) < 0) {
+		nl80211_remove_iface(drv, ifidx);
+		return -1;
+	}
+
+#ifdef CONFIG_P2P
+	if (!addr &&
+	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
+	     type == WPA_IF_P2P_GO)) {
+		/* Enforce unique P2P Interface Address */
+		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
+
+		if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				       own_addr) < 0 ||
+		    linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+				       new_addr) < 0) {
+			nl80211_remove_iface(drv, ifidx);
+			return -1;
+		}
+		if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
+				   "for P2P group interface");
+			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
+				nl80211_remove_iface(drv, ifidx);
+				return -1;
+			}
+			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
+					       new_addr) < 0) {
+				nl80211_remove_iface(drv, ifidx);
+				return -1;
+			}
+		}
+		os_memcpy(if_addr, new_addr, ETH_ALEN);
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef HOSTAPD
+	if (bridge &&
+	    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+			   "interface %s to a bridge %s", ifname, bridge);
+		nl80211_remove_iface(drv, ifidx);
+		os_free(new_bss);
+		return -1;
+	}
+
+	if (type == WPA_IF_AP_BSS) {
+		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+		{
+			nl80211_remove_iface(drv, ifidx);
+			os_free(new_bss);
+			return -1;
+		}
+		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
+		new_bss->ifindex = ifidx;
+		new_bss->drv = drv;
+		new_bss->next = drv->first_bss.next;
+		new_bss->freq = drv->first_bss.freq;
+		new_bss->ctx = bss_ctx;
+		drv->first_bss.next = new_bss;
+		if (drv_priv)
+			*drv_priv = new_bss;
+		nl80211_init_bss(new_bss);
+
+		/* Subscribe management frames for this WPA_IF_AP_BSS */
+		if (nl80211_setup_ap(new_bss))
+			return -1;
+	}
+#endif /* HOSTAPD */
+
+	if (drv->global)
+		drv->global->if_add_ifindex = ifidx;
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_if_remove(void *priv,
+					enum wpa_driver_if_type type,
+					const char *ifname)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ifindex = if_nametoindex(ifname);
+
+	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
+		   __func__, type, ifname, ifindex);
+	if (ifindex <= 0)
+		return -1;
+
+	nl80211_remove_iface(drv, ifindex);
+
+#ifdef HOSTAPD
+	if (type != WPA_IF_AP_BSS)
+		return 0;
+
+	if (bss->added_if_into_bridge) {
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
+			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+				   "interface %s from bridge %s: %s",
+				   bss->ifname, bss->brname, strerror(errno));
+	}
+	if (bss->added_bridge) {
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
+			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+				   "bridge %s: %s",
+				   bss->brname, strerror(errno));
+	}
+
+	if (bss != &drv->first_bss) {
+		struct i802_bss *tbss;
+
+		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
+			if (tbss->next == bss) {
+				tbss->next = bss->next;
+				/* Unsubscribe management frames */
+				nl80211_teardown_ap(bss);
+				nl80211_destroy_bss(bss);
+				os_free(bss);
+				bss = NULL;
+				break;
+			}
+		}
+		if (bss)
+			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
+				   "BSS %p in the list", __func__, bss);
+	}
+#endif /* HOSTAPD */
+
+	return 0;
+}
+
+
+static int cookie_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	u64 *cookie = arg;
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (tb[NL80211_ATTR_COOKIE])
+		*cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+	return NL_SKIP;
+}
+
+
+static int nl80211_send_frame_cmd(struct i802_bss *bss,
+				  unsigned int freq, unsigned int wait,
+				  const u8 *buf, size_t buf_len,
+				  u64 *cookie_out, int no_cck, int no_ack,
+				  int offchanok)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	u64 cookie;
+	int ret = -1;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
+		   "no_ack=%d offchanok=%d",
+		   freq, wait, no_cck, no_ack, offchanok);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	if (wait)
+		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
+	if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
+		NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+	if (no_cck)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
+	if (no_ack)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
+
+	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
+
+	cookie = 0;
+	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
+			   "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
+			   freq, wait);
+		goto nla_put_failure;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+		   (long long unsigned int) cookie);
+
+	if (cookie_out)
+		*cookie_out = no_ack ? (u64) -1 : cookie;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+					  unsigned int wait_time,
+					  const u8 *dst, const u8 *src,
+					  const u8 *bssid,
+					  const u8 *data, size_t data_len,
+					  int no_cck)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
+		   "freq=%u MHz wait=%d ms no_cck=%d)",
+		   drv->ifindex, freq, wait_time, no_cck);
+
+	buf = os_zalloc(24 + data_len);
+	if (buf == NULL)
+		return ret;
+	os_memcpy(buf + 24, data, data_len);
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+	os_memcpy(hdr->addr1, dst, ETH_ALEN);
+	os_memcpy(hdr->addr2, src, ETH_ALEN);
+	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+
+	if (is_ap_interface(drv->nlmode))
+		ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
+							24 + data_len,
+							0, freq, no_cck, 1,
+							wait_time);
+	else
+		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
+					     24 + data_len,
+					     &drv->send_action_cookie,
+					     no_cck, 0, 1);
+
+	os_free(buf);
+	return ret;
+}
+
+
+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
+						unsigned int duration)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+	u64 cookie;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+
+	cookie = 0;
+	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
+	msg = NULL;
+	if (ret == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
+			   "0x%llx for freq=%u MHz duration=%u",
+			   (long long unsigned int) cookie, freq, duration);
+		drv->remain_on_chan_cookie = cookie;
+		drv->pending_remain_on_chan = 1;
+		return 0;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
+		   "(freq=%d duration=%u): %d (%s)",
+		   freq, duration, ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	if (!drv->pending_remain_on_chan) {
+		wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
+			   "to cancel");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
+		   "0x%llx",
+		   (long long unsigned int) drv->remain_on_chan_cookie);
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret == 0)
+		return 0;
+	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
+		   "%d (%s)", ret, strerror(-ret));
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (!report) {
+		if (bss->nl_preq && drv->device_ap_sme &&
+		    is_ap_interface(drv->nlmode)) {
+			/*
+			 * Do not disable Probe Request reporting that was
+			 * enabled in nl80211_setup_ap().
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+				   "Probe Request reporting nl_preq=%p while "
+				   "in AP mode", bss->nl_preq);
+		} else if (bss->nl_preq) {
+			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
+				   "reporting nl_preq=%p", bss->nl_preq);
+			eloop_unregister_read_sock(
+				nl_socket_get_fd(bss->nl_preq));
+			nl_destroy_handles(&bss->nl_preq);
+		}
+		return 0;
+	}
+
+	if (bss->nl_preq) {
+		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
+			   "already on! nl_preq=%p", bss->nl_preq);
+		return 0;
+	}
+
+	bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+	if (bss->nl_preq == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+		   "reporting nl_preq=%p", bss->nl_preq);
+
+	if (nl80211_register_frame(bss, bss->nl_preq,
+				   (WLAN_FC_TYPE_MGMT << 2) |
+				   (WLAN_FC_STYPE_PROBE_REQ << 4),
+				   NULL, 0) < 0)
+		goto out_err;
+
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_preq);
+
+	return 0;
+
+ out_err:
+	nl_destroy_handles(&bss->nl_preq);
+	return -1;
+}
+
+
+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
+				     int ifindex, int disabled)
+{
+	struct nl_msg *msg;
+	struct nlattr *bands, *band;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+
+	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+	if (!bands)
+		goto nla_put_failure;
+
+	/*
+	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
+	 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
+	 * rates. All 5 GHz rates are left enabled.
+	 */
+	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+	if (!band)
+		goto nla_put_failure;
+	if (disabled) {
+		NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+	}
+	nla_nest_end(msg, band);
+
+	nla_nest_end(msg, bands);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+	} else
+		drv->disabled_11b_rates = disabled;
+
+	return ret;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+}
+
+
+static int wpa_driver_nl80211_deinit_ap(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (!is_ap_interface(drv->nlmode))
+		return -1;
+	wpa_driver_nl80211_del_beacon(drv);
+	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
+static int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
+		return -1;
+	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
+}
+
+
+static void wpa_driver_nl80211_resume(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
+			   "resume event");
+	}
+}
+
+
+static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
+				  const u8 *ies, size_t ies_len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret;
+	u8 *data, *pos;
+	size_t data_len;
+	const u8 *own_addr = bss->addr;
+
+	if (action != 1) {
+		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
+			   "action %d", action);
+		return -1;
+	}
+
+	/*
+	 * Action frame payload:
+	 * Category[1] = 6 (Fast BSS Transition)
+	 * Action[1] = 1 (Fast BSS Transition Request)
+	 * STA Address
+	 * Target AP Address
+	 * FT IEs
+	 */
+
+	data_len = 2 + 2 * ETH_ALEN + ies_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	*pos++ = 0x06; /* FT Action category */
+	*pos++ = action;
+	os_memcpy(pos, own_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, target_ap, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ies, ies_len);
+
+	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
+					     drv->bssid, own_addr, drv->bssid,
+					     data, data_len, 0);
+	os_free(data);
+
+	return ret;
+}
+
+
+static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg, *cqm = NULL;
+	int ret = -1;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
+		   "hysteresis=%d", threshold, hysteresis);
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	cqm = nlmsg_alloc();
+	if (cqm == NULL)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+	if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
+		goto nla_put_failure;
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+
+nla_put_failure:
+	nlmsg_free(cqm);
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int res;
+
+	os_memset(si, 0, sizeof(*si));
+	res = nl80211_get_link_signal(drv, si);
+	if (res != 0)
+		return res;
+
+	return nl80211_get_link_noise(drv, si);
+}
+
+
+static int wpa_driver_nl80211_shared_freq(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct wpa_driver_nl80211_data *driver;
+	int freq = 0;
+
+	/*
+	 * If the same PHY is in connected state with some other interface,
+	 * then retrieve the assoc freq.
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+		   drv->phyname);
+
+	dl_list_for_each(driver, &drv->global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (drv == driver ||
+		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
+		    !driver->associated)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+			   MACSTR,
+			   driver->phyname, driver->first_bss.ifname,
+			   MAC2STR(driver->first_bss.addr));
+		if (is_ap_interface(driver->nlmode))
+			freq = driver->first_bss.freq;
+		else
+			freq = nl80211_get_assoc_freq(driver);
+		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+			   drv->phyname, freq);
+	}
+
+	if (!freq)
+		wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+			   "PHY (%s) in associated state", drv->phyname);
+
+	return freq;
+}
+
+
+static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
+			      int encrypt)
+{
+	struct i802_bss *bss = priv;
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
+					     0, 0, 0, 0);
+}
+
+
+static int nl80211_set_param(void *priv, const char *param)
+{
+	wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
+	if (param == NULL)
+		return 0;
+
+#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;
+		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+	}
+#endif /* CONFIG_P2P */
+
+	return 0;
+}
+
+
+static void * nl80211_global_init(void)
+{
+	struct nl80211_global *global;
+	struct netlink_config *cfg;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+	global->ioctl_sock = -1;
+	dl_list_init(&global->interfaces);
+	global->if_add_ifindex = -1;
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		goto err;
+
+	cfg->ctx = global;
+	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+	global->netlink = netlink_init(cfg);
+	if (global->netlink == NULL) {
+		os_free(cfg);
+		goto err;
+	}
+
+	if (wpa_driver_nl80211_init_nl_global(global) < 0)
+		goto err;
+
+	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (global->ioctl_sock < 0) {
+		perror("socket(PF_INET,SOCK_DGRAM)");
+		goto err;
+	}
+
+	return global;
+
+err:
+	nl80211_global_deinit(global);
+	return NULL;
+}
+
+
+static void nl80211_global_deinit(void *priv)
+{
+	struct nl80211_global *global = priv;
+	if (global == NULL)
+		return;
+	if (!dl_list_empty(&global->interfaces)) {
+		wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
+			   "nl80211_global_deinit",
+			   dl_list_len(&global->interfaces));
+	}
+
+	if (global->netlink)
+		netlink_deinit(global->netlink);
+
+	nl_destroy_handles(&global->nl);
+
+	if (global->nl_event) {
+		eloop_unregister_read_sock(
+			nl_socket_get_fd(global->nl_event));
+		nl_destroy_handles(&global->nl_event);
+	}
+
+	nl_cb_put(global->nl_cb);
+
+	if (global->ioctl_sock >= 0)
+		close(global->ioctl_sock);
+
+	os_free(global);
+}
+
+
+static const char * nl80211_get_radio_name(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	return drv->phyname;
+}
+
+
+static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
+			 const u8 *pmkid)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(bss->drv, msg, 0, cmd);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+	if (pmkid)
+		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
+	if (bssid)
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+		   MAC2STR(bssid));
+	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+	struct i802_bss *bss = priv;
+	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+				   const u8 *replay_ctr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *replay_nested;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+	if (!replay_nested)
+		goto nla_put_failure;
+
+	NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+	NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+		replay_ctr);
+
+	nla_nest_end(msg, replay_nested);
+
+	send_and_recv_msgs(drv, msg, NULL, NULL);
+	return;
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+				    const u8 *addr, int qos)
+{
+	/* send data frame to poll STA and check whether
+	 * this frame is ACKed */
+	struct {
+		struct ieee80211_hdr hdr;
+		u16 qos_ctl;
+	} STRUCT_PACKED nulldata;
+	size_t size;
+
+	/* Send data frame to poll STA and check whether this frame is ACKed */
+
+	os_memset(&nulldata, 0, sizeof(nulldata));
+
+	if (qos) {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_QOS_NULL);
+		size = sizeof(nulldata);
+	} else {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_NULLFUNC);
+		size = sizeof(struct ieee80211_hdr);
+	}
+
+	nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+			   "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+				int qos)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!drv->poll_command_supported) {
+		nl80211_send_null_frame(bss, own_addr, addr, qos);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+	send_and_recv_msgs(drv, msg, NULL, NULL);
+	return;
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
+		    enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+				     int ctwindow)
+{
+	struct i802_bss *bss = priv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+	if (opp_ps != -1 || ctwindow != -1)
+		return -1; /* Not yet supported */
+
+	if (legacy_ps == -1)
+		return 0;
+	if (legacy_ps != 0 && legacy_ps != 1)
+		return -1; /* Not yet supported */
+
+	return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+				  u8 dialog_token, u16 status_code,
+				  const u8 *buf, size_t len)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	if (!dst)
+		return -EINVAL;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
+	NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	enum nl80211_tdls_operation nl80211_oper;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	switch (oper) {
+	case TDLS_DISCOVERY_REQ:
+		nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+		break;
+	case TDLS_SETUP:
+		nl80211_oper = NL80211_TDLS_SETUP;
+		break;
+	case TDLS_TEARDOWN:
+		nl80211_oper = NL80211_TDLS_TEARDOWN;
+		break;
+	case TDLS_ENABLE_LINK:
+		nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+		break;
+	case TDLS_DISABLE_LINK:
+		nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+		break;
+	case TDLS_ENABLE:
+		return 0;
+	case TDLS_DISABLE:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
+	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+#endif /* CONFIG TDLS */
+
+
+#ifdef ANDROID
+
+typedef struct android_wifi_priv_cmd {
+	char *buf;
+	int used_len;
+	int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+	drv_errors++;
+	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+		drv_errors = 0;
+		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+	}
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = sizeof(buf);
+	priv_cmd.total_len = sizeof(buf);
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+			   __func__);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+	return 0;
+}
+
+
+static int android_pno_start(struct i802_bss *bss,
+			     struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/* Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	memset(&ifr, 0, sizeof(ifr));
+	memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = bp;
+	priv_cmd.total_len = bp;
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+
+	return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+static int android_pno_stop(struct i802_bss *bss)
+{
+	return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+	.name = "nl80211",
+	.desc = "Linux nl80211/cfg80211",
+	.get_bssid = wpa_driver_nl80211_get_bssid,
+	.get_ssid = wpa_driver_nl80211_get_ssid,
+	.set_key = wpa_driver_nl80211_set_key,
+	.scan2 = wpa_driver_nl80211_scan,
+	.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,
+	.deauthenticate = wpa_driver_nl80211_deauthenticate,
+	.authenticate = wpa_driver_nl80211_authenticate,
+	.associate = wpa_driver_nl80211_associate,
+	.global_init = nl80211_global_init,
+	.global_deinit = nl80211_global_deinit,
+	.init2 = wpa_driver_nl80211_init,
+	.deinit = wpa_driver_nl80211_deinit,
+	.get_capa = wpa_driver_nl80211_get_capa,
+	.set_operstate = wpa_driver_nl80211_set_operstate,
+	.set_supp_port = wpa_driver_nl80211_set_supp_port,
+	.set_country = wpa_driver_nl80211_set_country,
+	.set_ap = wpa_driver_nl80211_set_ap,
+	.if_add = wpa_driver_nl80211_if_add,
+	.if_remove = wpa_driver_nl80211_if_remove,
+	.send_mlme = wpa_driver_nl80211_send_mlme,
+	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+	.sta_add = wpa_driver_nl80211_sta_add,
+	.sta_remove = wpa_driver_nl80211_sta_remove,
+	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
+	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
+#ifdef HOSTAPD
+	.hapd_init = i802_init,
+	.hapd_deinit = i802_deinit,
+	.set_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+	.get_seqnum = i802_get_seqnum,
+	.flush = i802_flush,
+	.get_inact_sec = i802_get_inact_sec,
+	.sta_clear_stats = i802_sta_clear_stats,
+	.set_rts = i802_set_rts,
+	.set_frag = i802_set_frag,
+	.set_tx_queue_params = i802_set_tx_queue_params,
+	.set_sta_vlan = i802_set_sta_vlan,
+	.sta_deauth = i802_sta_deauth,
+	.sta_disassoc = i802_sta_disassoc,
+#endif /* HOSTAPD || CONFIG_AP */
+	.read_sta_data = i802_read_sta_data,
+	.set_freq = i802_set_freq,
+	.send_action = wpa_driver_nl80211_send_action,
+	.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
+	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
+	.cancel_remain_on_channel =
+	wpa_driver_nl80211_cancel_remain_on_channel,
+	.probe_req_report = wpa_driver_nl80211_probe_req_report,
+	.deinit_ap = wpa_driver_nl80211_deinit_ap,
+	.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
+	.resume = wpa_driver_nl80211_resume,
+	.send_ft_action = nl80211_send_ft_action,
+	.signal_monitor = nl80211_signal_monitor,
+	.signal_poll = nl80211_signal_poll,
+	.send_frame = nl80211_send_frame,
+	.shared_freq = wpa_driver_nl80211_shared_freq,
+	.set_param = nl80211_set_param,
+	.get_radio_name = nl80211_get_radio_name,
+	.add_pmkid = nl80211_add_pmkid,
+	.remove_pmkid = nl80211_remove_pmkid,
+	.flush_pmkid = nl80211_flush_pmkid,
+	.set_rekey_info = nl80211_set_rekey_info,
+	.poll_client = nl80211_poll_client,
+	.set_p2p_powersave = nl80211_set_p2p_powersave,
+#ifdef CONFIG_TDLS
+	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
+	.tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_none.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,99 +0,0 @@
-/*
- * Driver interface for RADIUS server or WPS ER only (no driver)
- * Copyright (c) 2008, Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "driver.h"
-
-
-struct none_driver_data {
-	struct hostapd_data *hapd;
-	void *ctx;
-};
-
-
-static void * none_driver_hapd_init(struct hostapd_data *hapd,
-				    struct wpa_init_params *params)
-{
-	struct none_driver_data *drv;
-
-	drv = os_zalloc(sizeof(struct none_driver_data));
-	if (drv == NULL) {
-		wpa_printf(MSG_ERROR, "Could not allocate memory for none "
-			   "driver data");
-		return NULL;
-	}
-	drv->hapd = hapd;
-
-	return drv;
-}
-
-
-static void none_driver_hapd_deinit(void *priv)
-{
-	struct none_driver_data *drv = priv;
-
-	os_free(drv);
-}
-
-
-static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
-				  u16 proto, const u8 *data, size_t data_len)
-{
-	return 0;
-}
-
-
-static void * none_driver_init(void *ctx, const char *ifname)
-{
-	struct none_driver_data *drv;
-
-	drv = os_zalloc(sizeof(struct none_driver_data));
-	if (drv == NULL) {
-		wpa_printf(MSG_ERROR, "Could not allocate memory for none "
-			   "driver data");
-		return NULL;
-	}
-	drv->ctx = ctx;
-
-	return drv;
-}
-
-
-static void none_driver_deinit(void *priv)
-{
-	struct none_driver_data *drv = priv;
-
-	os_free(drv);
-}
-
-
-static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto,
-				  const u8 *data, size_t data_len)
-{
-	return -1;
-}
-
-
-const struct wpa_driver_ops wpa_driver_none_ops = {
-	.name = "none",
-	.desc = "no driver (RADIUS server/WPS ER)",
-	.hapd_init = none_driver_hapd_init,
-	.hapd_deinit = none_driver_hapd_deinit,
-	.send_ether = none_driver_send_ether,
-	.init = none_driver_init,
-	.deinit = none_driver_deinit,
-	.send_eapol = none_driver_send_eapol,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_none.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_none.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,93 @@
+/*
+ * Driver interface for RADIUS server or WPS ER only (no driver)
+ * Copyright (c) 2008, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "driver.h"
+
+
+struct none_driver_data {
+	struct hostapd_data *hapd;
+	void *ctx;
+};
+
+
+static void * none_driver_hapd_init(struct hostapd_data *hapd,
+				    struct wpa_init_params *params)
+{
+	struct none_driver_data *drv;
+
+	drv = os_zalloc(sizeof(struct none_driver_data));
+	if (drv == NULL) {
+		wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+			   "driver data");
+		return NULL;
+	}
+	drv->hapd = hapd;
+
+	return drv;
+}
+
+
+static void none_driver_hapd_deinit(void *priv)
+{
+	struct none_driver_data *drv = priv;
+
+	os_free(drv);
+}
+
+
+static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+				  u16 proto, const u8 *data, size_t data_len)
+{
+	return 0;
+}
+
+
+static void * none_driver_init(void *ctx, const char *ifname)
+{
+	struct none_driver_data *drv;
+
+	drv = os_zalloc(sizeof(struct none_driver_data));
+	if (drv == NULL) {
+		wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+			   "driver data");
+		return NULL;
+	}
+	drv->ctx = ctx;
+
+	return drv;
+}
+
+
+static void none_driver_deinit(void *priv)
+{
+	struct none_driver_data *drv = priv;
+
+	os_free(drv);
+}
+
+
+static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto,
+				  const u8 *data, size_t data_len)
+{
+	return -1;
+}
+
+
+const struct wpa_driver_ops wpa_driver_none_ops = {
+	.name = "none",
+	.desc = "no driver (RADIUS server/WPS ER)",
+	.hapd_init = none_driver_hapd_init,
+	.hapd_deinit = none_driver_hapd_deinit,
+	.send_ether = none_driver_send_ether,
+	.init = none_driver_init,
+	.deinit = none_driver_deinit,
+	.send_eapol = none_driver_send_eapol,
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_osx.m
===================================================================
--- vendor/wpa/dist/src/drivers/driver_osx.m	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_osx.m	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,459 +0,0 @@
-/*
- * WPA Supplicant - Mac OS X Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "Apple80211.h"
-
-struct wpa_driver_osx_data {
-	void *ctx;
-	WirelessRef wireless_ctx;
-	CFArrayRef scan_results;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern int wpa_debug_level;
-
-static void dump_dict_cb(const void *key, const void *value, void *context)
-{
-        if (MSG_DEBUG < wpa_debug_level)
-                return;
-
-	wpa_printf(MSG_DEBUG, "Key:");
-	CFShow(key);
-	wpa_printf(MSG_DEBUG, "Value:");
-	CFShow(value);
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
-		   title, (unsigned int) CFDictionaryGetCount(dict));
-	CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-	int len;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	for (len = 0; len < 32; len++)
-		if (info.ssid[len] == 0)
-			break;
-
-	os_memcpy(ssid, info.ssid, len);
-	return len;
-}
-
-
-static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	os_memcpy(bssid, info.bssID, ETH_ALEN);
-	return 0;
-}
-
-
-static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	if (ssid) {
-		CFStringRef data;
-		data = CFStringCreateWithBytes(kCFAllocatorDefault,
-					       ssid, ssid_len,
-					       kCFStringEncodingISOLatin1,
-					       FALSE);
-		if (data == NULL) {
-			wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
-				   "failed");
-			return -1;
-		}
-
-		err = WirelessDirectedScan(drv->wireless_ctx,
-					   &drv->scan_results, 0, data);
-		CFRelease(data);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
-				   "failed: 0x%08x", (unsigned int) err);
-			return -1;
-		}
-	} else {
-		err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
-					  WirelessNetworkInfo *info)
-{
-	struct wpa_scan_res *result, **tmp;
-	size_t extra_len;
-	u8 *pos;
-
-	extra_len = 2 + info->ssid_len;
-
-	result = os_zalloc(sizeof(*result) + extra_len);
-	if (result == NULL)
-		return;
-	os_memcpy(result->bssid, info->bssid, ETH_ALEN);
-	result->freq = 2407 + info->channel * 5;
-	//result->beacon_int =;
-	result->caps = info->capability;
-	//result->qual = info->signal;
-	result->noise = info->noise;
-
-	pos = (u8 *)(result + 1);
-
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = info->ssid_len;
-	os_memcpy(pos, info->ssid, info->ssid_len);
-	pos += info->ssid_len;
-
-	result->ie_len = pos - (u8 *)(result + 1);
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(result);
-		return;
-	}
-	tmp[res->num++] = result;
-	res->res = tmp;
-}
-
-
-static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	struct wpa_scan_results *res;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	for (i = 0; i < num; i++)
-		wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
-			CFDataGetBytePtr(CFArrayGetValueAtIndex(
-				drv->scan_results, i)));
-
-	return res;
-}
-
-
-static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_osx_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-	CFDictionaryRef ai;
-
-	if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	ai = WirelessGetAssociationInfo(drv->wireless_ctx);
-	if (ai) {
-		wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
-		CFRelease(ai);
-	} else {
-		wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_osx_associate(void *priv,
-				    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	CFDataRef ssid;
-	CFStringRef key;
-	int assoc_type;
-
-	ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
-			    params->ssid_len);
-	if (ssid == NULL)
-		return -1;
-
-	/* TODO: support for WEP */
-	if (params->key_mgmt_suite == KEY_MGMT_PSK) {
-		if (params->passphrase == NULL)
-			return -1;
-		key = CFStringCreateWithCString(kCFAllocatorDefault,
-						params->passphrase,
-						kCFStringEncodingISOLatin1);
-		if (key == NULL) {
-			CFRelease(ssid);
-			return -1;
-		}
-	} else
-		key = NULL;
-
-	if (params->key_mgmt_suite == KEY_MGMT_NONE)
-		assoc_type = 0;
-	else
-		assoc_type = 4;
-
-	wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
-		   assoc_type, key);
-	err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
-	CFRelease(ssid);
-	if (key)
-		CFRelease(key);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
-			   (unsigned int) err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_osx_set_key(const char *ifname, void *priv,
-				  enum wpa_alg alg, const u8 *addr,
-				  int key_idx, int set_tx, const u8 *seq,
-				  size_t seq_len, const u8 *key,
-				  size_t key_len)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	if (alg == WPA_ALG_WEP) {
-		err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
-				     key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-
-		return 0;
-	}
-
-	if (alg == WPA_ALG_PMK) {
-		err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
-	return -1;
-}
-
-
-static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_osx_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_osx_data *drv;
-	WirelessError err;
-	u8 enabled, power;
-
-	if (!WirelessIsAvailable()) {
-		wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = WirelessAttach(&drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
-			   (int) err);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
-			   (unsigned int) err);
-	err = WirelessGetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
-			   (unsigned int) err);
-
-	wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
-
-	if (!enabled) {
-		err = WirelessSetEnabled(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
-				   " 0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	if (!power) {
-		err = WirelessSetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
-				   "0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_osx_deinit(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-
-	err = WirelessSetPower(drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
-			   "0x%08x", (unsigned int) err);
-	}
-
-	err = WirelessDetach(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
-			   (unsigned int) err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_osx_ops = {
-	.name = "osx",
-	.desc = "Mac OS X Apple80211 driver",
-	.get_ssid = wpa_driver_osx_get_ssid,
-	.get_bssid = wpa_driver_osx_get_bssid,
-	.init = wpa_driver_osx_init,
-	.deinit = wpa_driver_osx_deinit,
-	.scan2 = wpa_driver_osx_scan,
-	.get_scan_results2 = wpa_driver_osx_get_scan_results,
-	.associate = wpa_driver_osx_associate,
-	.set_key = wpa_driver_osx_set_key,
-	.get_capa = wpa_driver_osx_get_capa,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_privsep.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_privsep.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_privsep.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,758 +0,0 @@
-/*
- * WPA Supplicant - privilege separated driver interface
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/un.h>
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/privsep_commands.h"
-
-
-struct wpa_driver_privsep_data {
-	void *ctx;
-	u8 own_addr[ETH_ALEN];
-	int priv_socket;
-	char *own_socket_path;
-	int cmd_socket;
-	char *own_cmd_path;
-	struct sockaddr_un priv_addr;
-	char ifname[16];
-};
-
-
-static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
-{
-	int res;
-
-	res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
-		     (struct sockaddr *) &drv->priv_addr,
-		     sizeof(drv->priv_addr));
-	if (res < 0)
-		perror("sendto");
-	return res < 0 ? -1 : 0;
-}
-
-
-static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
-			const void *data, size_t data_len,
-			void *reply, size_t *reply_len)
-{
-	struct msghdr msg;
-	struct iovec io[2];
-
-	io[0].iov_base = &cmd;
-	io[0].iov_len = sizeof(cmd);
-	io[1].iov_base = (u8 *) data;
-	io[1].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = data ? 2 : 1;
-	msg.msg_name = &drv->priv_addr;
-	msg.msg_namelen = sizeof(drv->priv_addr);
-
-	if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
-		perror("sendmsg(cmd_socket)");
-		return -1;
-	}
-
-	if (reply) {
-		fd_set rfds;
-		struct timeval tv;
-		int res;
-
-		FD_ZERO(&rfds);
-		FD_SET(drv->cmd_socket, &rfds);
-		tv.tv_sec = 5;
-		tv.tv_usec = 0;
-		res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
-		if (res < 0 && errno != EINTR) {
-			perror("select");
-			return -1;
-		}
-
-		if (FD_ISSET(drv->cmd_socket, &rfds)) {
-			res = recv(drv->cmd_socket, reply, *reply_len, 0);
-			if (res < 0) {
-				perror("recv");
-				return -1;
-			}
-			*reply_len = res;
-		} else {
-			wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
-				   "for reply (cmd=%d)", cmd);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-			     
-static int wpa_driver_privsep_scan(void *priv,
-				   struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
-	return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
-			    NULL, NULL);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_privsep_get_scan_results2(void *priv)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	int res, num;
-	u8 *buf, *pos, *end;
-	size_t reply_len = 60000;
-	struct wpa_scan_results *results;
-	struct wpa_scan_res *r;
-
-	buf = os_malloc(reply_len);
-	if (buf == NULL)
-		return NULL;
-	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
-			   NULL, 0, buf, &reply_len);
-	if (res < 0) {
-		os_free(buf);
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
-		   (unsigned long) reply_len);
-	if (reply_len < sizeof(int)) {
-		wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
-			   (unsigned long) reply_len);
-		os_free(buf);
-		return NULL;
-	}
-
-	pos = buf;
-	end = buf + reply_len;
-	os_memcpy(&num, pos, sizeof(int));
-	if (num < 0 || num > 1000) {
-		os_free(buf);
-		return NULL;
-	}
-	pos += sizeof(int);
-
-	results = os_zalloc(sizeof(*results));
-	if (results == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
-	if (results->res == NULL) {
-		os_free(results);
-		os_free(buf);
-		return NULL;
-	}
-
-	while (results->num < (size_t) num && pos + sizeof(int) < end) {
-		int len;
-		os_memcpy(&len, pos, sizeof(int));
-		pos += sizeof(int);
-		if (len < 0 || len > 10000 || pos + len > end)
-			break;
-
-		r = os_malloc(len);
-		if (r == NULL)
-			break;
-		os_memcpy(r, pos, len);
-		pos += len;
-		if (sizeof(*r) + r->ie_len > (size_t) len) {
-			os_free(r);
-			break;
-		}
-
-		results->res[results->num++] = r;
-	}
-
-	os_free(buf);
-	return results;
-}
-
-
-static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
-				      enum wpa_alg alg, const u8 *addr,
-				      int key_idx, int set_tx,
-				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	struct privsep_cmd_set_key cmd;
-
-	wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
-		   __func__, priv, alg, key_idx, set_tx);
-
-	os_memset(&cmd, 0, sizeof(cmd));
-	cmd.alg = alg;
-	if (addr)
-		os_memcpy(cmd.addr, addr, ETH_ALEN);
-	else
-		os_memset(cmd.addr, 0xff, ETH_ALEN);
-	cmd.key_idx = key_idx;
-	cmd.set_tx = set_tx;
-	if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
-		os_memcpy(cmd.seq, seq, seq_len);
-		cmd.seq_len = seq_len;
-	}
-	if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
-		os_memcpy(cmd.key, key, key_len);
-		cmd.key_len = key_len;
-	}
-
-	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
-			    NULL, NULL);
-}
-
-
-static int wpa_driver_privsep_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	struct privsep_cmd_associate *data;
-	int res;
-	size_t buflen;
-
-	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
-		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
-		   __func__, priv, params->freq, params->pairwise_suite,
-		   params->group_suite, params->key_mgmt_suite,
-		   params->auth_alg, params->mode);
-
-	buflen = sizeof(*data) + params->wpa_ie_len;
-	data = os_zalloc(buflen);
-	if (data == NULL)
-		return -1;
-
-	if (params->bssid)
-		os_memcpy(data->bssid, params->bssid, ETH_ALEN);
-	os_memcpy(data->ssid, params->ssid, params->ssid_len);
-	data->ssid_len = params->ssid_len;
-	data->freq = params->freq;
-	data->pairwise_suite = params->pairwise_suite;
-	data->group_suite = params->group_suite;
-	data->key_mgmt_suite = params->key_mgmt_suite;
-	data->auth_alg = params->auth_alg;
-	data->mode = params->mode;
-	data->wpa_ie_len = params->wpa_ie_len;
-	if (params->wpa_ie)
-		os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
-	/* TODO: add support for other assoc parameters */
-
-	res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
-			   NULL, NULL);
-	os_free(data);
-
-	return res;
-}
-
-
-static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	int res;
-	size_t len = ETH_ALEN;
-
-	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
-	if (res < 0 || len != ETH_ALEN)
-		return -1;
-	return 0;
-}
-
-
-static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	int res, ssid_len;
-	u8 reply[sizeof(int) + 32];
-	size_t len = sizeof(reply);
-
-	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
-	if (res < 0 || len < sizeof(int))
-		return -1;
-	os_memcpy(&ssid_len, reply, sizeof(int));
-	if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
-		wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
-		return -1;
-	}
-	os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
-	return ssid_len;
-}
-
-
-static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	//struct wpa_driver_privsep_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-		   __func__, MAC2STR(addr), reason_code);
-	wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
-	return 0;
-}
-
-
-static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	//struct wpa_driver_privsep_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-		   __func__, MAC2STR(addr), reason_code);
-	wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
-	return 0;
-}
-
-
-static void wpa_driver_privsep_event_assoc(void *ctx,
-					   enum wpa_event_type event,
-					   u8 *buf, size_t len)
-{
-	union wpa_event_data data;
-	int inc_data = 0;
-	u8 *pos, *end;
-	int ie_len;
-
-	os_memset(&data, 0, sizeof(data));
-
-	pos = buf;
-	end = buf + len;
-
-	if (end - pos < (int) sizeof(int))
-		return;
-	os_memcpy(&ie_len, pos, sizeof(int));
-	pos += sizeof(int);
-	if (ie_len < 0 || ie_len > end - pos)
-		return;
-	if (ie_len) {
-		data.assoc_info.req_ies = pos;
-		data.assoc_info.req_ies_len = ie_len;
-		pos += ie_len;
-		inc_data = 1;
-	}
-
-	wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
-}
-
-
-static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
-						      size_t len)
-{
-	union wpa_event_data data;
-	int ievent;
-
-	if (len < sizeof(int) ||
-	    len - sizeof(int) > sizeof(data.interface_status.ifname))
-		return;
-
-	os_memcpy(&ievent, buf, sizeof(int));
-
-	os_memset(&data, 0, sizeof(data));
-	data.interface_status.ievent = ievent;
-	os_memcpy(data.interface_status.ifname, buf + sizeof(int),
-		  len - sizeof(int));
-	wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
-}
-
-
-static void wpa_driver_privsep_event_michael_mic_failure(
-	void *ctx, u8 *buf, size_t len)
-{
-	union wpa_event_data data;
-
-	if (len != sizeof(int))
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
-	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-}
-
-
-static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
-						     size_t len)
-{
-	union wpa_event_data data;
-
-	if (len != sizeof(struct pmkid_candidate))
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(&data.pmkid_candidate, buf, len);
-	wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
-}
-
-
-static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
-{
-	union wpa_event_data data;
-
-	if (len != ETH_ALEN)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
-	wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
-}
-
-
-static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
-						 size_t len)
-{
-	union wpa_event_data data;
-
-	if (len < sizeof(int) + ETH_ALEN)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
-	os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
-	data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
-	data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
-	wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
-}
-
-
-static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
-{
-	if (len < ETH_ALEN)
-		return;
-	drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
-}
-
-
-static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
-				       void *sock_ctx)
-{
-	struct wpa_driver_privsep_data *drv = eloop_ctx;
-	u8 *buf, *event_buf;
-	size_t event_len;
-	int res, event;
-	enum privsep_event e;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-	const size_t buflen = 2000;
-
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-	res = recvfrom(sock, buf, buflen, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(priv_socket)");
-		os_free(buf);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
-
-	if (res < (int) sizeof(int)) {
-		wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
-		return;
-	}
-
-	os_memcpy(&event, buf, sizeof(int));
-	event_buf = &buf[sizeof(int)];
-	event_len = res - sizeof(int);
-	wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
-		   event, (unsigned long) event_len);
-
-	e = event;
-	switch (e) {
-	case PRIVSEP_EVENT_SCAN_RESULTS:
-		wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
-		break;
-	case PRIVSEP_EVENT_ASSOC:
-		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
-					       event_buf, event_len);
-		break;
-	case PRIVSEP_EVENT_DISASSOC:
-		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-		break;
-	case PRIVSEP_EVENT_ASSOCINFO:
-		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
-					       event_buf, event_len);
-		break;
-	case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
-		wpa_driver_privsep_event_michael_mic_failure(
-			drv->ctx, event_buf, event_len);
-		break;
-	case PRIVSEP_EVENT_INTERFACE_STATUS:
-		wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
-							  event_len);
-		break;
-	case PRIVSEP_EVENT_PMKID_CANDIDATE:
-		wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
-							 event_len);
-		break;
-	case PRIVSEP_EVENT_STKSTART:
-		wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
-						  event_len);
-		break;
-	case PRIVSEP_EVENT_FT_RESPONSE:
-		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
-						     event_len);
-		break;
-	case PRIVSEP_EVENT_RX_EAPOL:
-		wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
-						  event_len);
-		break;
-	}
-
-	os_free(buf);
-}
-
-
-static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_privsep_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	drv->priv_socket = -1;
-	drv->cmd_socket = -1;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-
-	return drv;
-}
-
-
-static void wpa_driver_privsep_deinit(void *priv)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-
-	if (drv->priv_socket >= 0) {
-		wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
-		eloop_unregister_read_sock(drv->priv_socket);
-		close(drv->priv_socket);
-	}
-
-	if (drv->own_socket_path) {
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-	}
-
-	if (drv->cmd_socket >= 0) {
-		eloop_unregister_read_sock(drv->cmd_socket);
-		close(drv->cmd_socket);
-	}
-
-	if (drv->own_cmd_path) {
-		unlink(drv->own_cmd_path);
-		os_free(drv->own_cmd_path);
-	}
-
-	os_free(drv);
-}
-
-
-static int wpa_driver_privsep_set_param(void *priv, const char *param)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	const char *pos;
-	char *own_dir, *priv_dir;
-	static unsigned int counter = 0;
-	size_t len;
-	struct sockaddr_un addr;
-
-	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
-	if (param == NULL)
-		pos = NULL;
-	else
-		pos = os_strstr(param, "own_dir=");
-	if (pos) {
-		char *end;
-		own_dir = os_strdup(pos + 8);
-		if (own_dir == NULL)
-			return -1;
-		end = os_strchr(own_dir, ' ');
-		if (end)
-			*end = '\0';
-	} else {
-		own_dir = os_strdup("/tmp");
-		if (own_dir == NULL)
-			return -1;
-	}
-
-	if (param == NULL)
-		pos = NULL;
-	else
-		pos = os_strstr(param, "priv_dir=");
-	if (pos) {
-		char *end;
-		priv_dir = os_strdup(pos + 9);
-		if (priv_dir == NULL) {
-			os_free(own_dir);
-			return -1;
-		}
-		end = os_strchr(priv_dir, ' ');
-		if (end)
-			*end = '\0';
-	} else {
-		priv_dir = os_strdup("/var/run/wpa_priv");
-		if (priv_dir == NULL) {
-			os_free(own_dir);
-			return -1;
-		}
-	}
-
-	len = os_strlen(own_dir) + 50;
-	drv->own_socket_path = os_malloc(len);
-	if (drv->own_socket_path == NULL) {
-		os_free(priv_dir);
-		os_free(own_dir);
-		return -1;
-	}
-	os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
-		    own_dir, getpid(), counter++);
-
-	len = os_strlen(own_dir) + 50;
-	drv->own_cmd_path = os_malloc(len);
-	if (drv->own_cmd_path == NULL) {
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		os_free(priv_dir);
-		os_free(own_dir);
-		return -1;
-	}
-	os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
-		    own_dir, getpid(), counter++);
-
-	os_free(own_dir);
-
-	drv->priv_addr.sun_family = AF_UNIX;
-	os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
-		    "%s/%s", priv_dir, drv->ifname);
-	os_free(priv_dir);
-
-	drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (drv->priv_socket < 0) {
-		perror("socket(PF_UNIX)");
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
-	if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
-	    0) {
-		perror("bind(PF_UNIX)");
-		close(drv->priv_socket);
-		drv->priv_socket = -1;
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
-				 drv, NULL);
-
-	drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (drv->cmd_socket < 0) {
-		perror("socket(PF_UNIX)");
-		os_free(drv->own_cmd_path);
-		drv->own_cmd_path = NULL;
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
-	if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
-	{
-		perror("bind(PF_UNIX)");
-		close(drv->cmd_socket);
-		drv->cmd_socket = -1;
-		unlink(drv->own_cmd_path);
-		os_free(drv->own_cmd_path);
-		drv->own_cmd_path = NULL;
-		return -1;
-	}
-
-	if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_privsep_get_capa(void *priv,
-				       struct wpa_driver_capa *capa)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	int res;
-	size_t len = sizeof(*capa);
-
-	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
-	if (res < 0 || len != sizeof(*capa))
-		return -1;
-	return 0;
-}
-
-
-static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return drv->own_addr;
-}
-
-
-static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
-{
-	struct wpa_driver_privsep_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
-	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
-			    os_strlen(alpha2), NULL, NULL);
-}
-
-
-struct wpa_driver_ops wpa_driver_privsep_ops = {
-	"privsep",
-	"wpa_supplicant privilege separated driver",
-	.get_bssid = wpa_driver_privsep_get_bssid,
-	.get_ssid = wpa_driver_privsep_get_ssid,
-	.set_key = wpa_driver_privsep_set_key,
-	.init = wpa_driver_privsep_init,
-	.deinit = wpa_driver_privsep_deinit,
-	.set_param = wpa_driver_privsep_set_param,
-	.scan2 = wpa_driver_privsep_scan,
-	.deauthenticate = wpa_driver_privsep_deauthenticate,
-	.disassociate = wpa_driver_privsep_disassociate,
-	.associate = wpa_driver_privsep_associate,
-	.get_capa = wpa_driver_privsep_get_capa,
-	.get_mac_addr = wpa_driver_privsep_get_mac_addr,
-	.get_scan_results2 = wpa_driver_privsep_get_scan_results2,
-	.set_country = wpa_driver_privsep_set_country,
-};
-
-
-struct wpa_driver_ops *wpa_drivers[] =
-{
-	&wpa_driver_privsep_ops,
-	NULL
-};

Copied: vendor/wpa/2.0/src/drivers/driver_privsep.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_privsep.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_privsep.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_privsep.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,740 @@
+/*
+ * WPA Supplicant - privilege separated driver interface
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "common/privsep_commands.h"
+
+
+struct wpa_driver_privsep_data {
+	void *ctx;
+	u8 own_addr[ETH_ALEN];
+	int priv_socket;
+	char *own_socket_path;
+	int cmd_socket;
+	char *own_cmd_path;
+	struct sockaddr_un priv_addr;
+	char ifname[16];
+};
+
+
+static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
+{
+	int res;
+
+	res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
+		     (struct sockaddr *) &drv->priv_addr,
+		     sizeof(drv->priv_addr));
+	if (res < 0)
+		perror("sendto");
+	return res < 0 ? -1 : 0;
+}
+
+
+static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
+			const void *data, size_t data_len,
+			void *reply, size_t *reply_len)
+{
+	struct msghdr msg;
+	struct iovec io[2];
+
+	io[0].iov_base = &cmd;
+	io[0].iov_len = sizeof(cmd);
+	io[1].iov_base = (u8 *) data;
+	io[1].iov_len = data_len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = data ? 2 : 1;
+	msg.msg_name = &drv->priv_addr;
+	msg.msg_namelen = sizeof(drv->priv_addr);
+
+	if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
+		perror("sendmsg(cmd_socket)");
+		return -1;
+	}
+
+	if (reply) {
+		fd_set rfds;
+		struct timeval tv;
+		int res;
+
+		FD_ZERO(&rfds);
+		FD_SET(drv->cmd_socket, &rfds);
+		tv.tv_sec = 5;
+		tv.tv_usec = 0;
+		res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0 && errno != EINTR) {
+			perror("select");
+			return -1;
+		}
+
+		if (FD_ISSET(drv->cmd_socket, &rfds)) {
+			res = recv(drv->cmd_socket, reply, *reply_len, 0);
+			if (res < 0) {
+				perror("recv");
+				return -1;
+			}
+			*reply_len = res;
+		} else {
+			wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
+				   "for reply (cmd=%d)", cmd);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+			     
+static int wpa_driver_privsep_scan(void *priv,
+				   struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	const u8 *ssid = params->ssids[0].ssid;
+	size_t ssid_len = params->ssids[0].ssid_len;
+	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+	return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+			    NULL, NULL);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_privsep_get_scan_results2(void *priv)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	int res, num;
+	u8 *buf, *pos, *end;
+	size_t reply_len = 60000;
+	struct wpa_scan_results *results;
+	struct wpa_scan_res *r;
+
+	buf = os_malloc(reply_len);
+	if (buf == NULL)
+		return NULL;
+	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
+			   NULL, 0, buf, &reply_len);
+	if (res < 0) {
+		os_free(buf);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
+		   (unsigned long) reply_len);
+	if (reply_len < sizeof(int)) {
+		wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
+			   (unsigned long) reply_len);
+		os_free(buf);
+		return NULL;
+	}
+
+	pos = buf;
+	end = buf + reply_len;
+	os_memcpy(&num, pos, sizeof(int));
+	if (num < 0 || num > 1000) {
+		os_free(buf);
+		return NULL;
+	}
+	pos += sizeof(int);
+
+	results = os_zalloc(sizeof(*results));
+	if (results == NULL) {
+		os_free(buf);
+		return NULL;
+	}
+
+	results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
+	if (results->res == NULL) {
+		os_free(results);
+		os_free(buf);
+		return NULL;
+	}
+
+	while (results->num < (size_t) num && pos + sizeof(int) < end) {
+		int len;
+		os_memcpy(&len, pos, sizeof(int));
+		pos += sizeof(int);
+		if (len < 0 || len > 10000 || pos + len > end)
+			break;
+
+		r = os_malloc(len);
+		if (r == NULL)
+			break;
+		os_memcpy(r, pos, len);
+		pos += len;
+		if (sizeof(*r) + r->ie_len > (size_t) len) {
+			os_free(r);
+			break;
+		}
+
+		results->res[results->num++] = r;
+	}
+
+	os_free(buf);
+	return results;
+}
+
+
+static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
+				      enum wpa_alg alg, const u8 *addr,
+				      int key_idx, int set_tx,
+				      const u8 *seq, size_t seq_len,
+				      const u8 *key, size_t key_len)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	struct privsep_cmd_set_key cmd;
+
+	wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
+		   __func__, priv, alg, key_idx, set_tx);
+
+	os_memset(&cmd, 0, sizeof(cmd));
+	cmd.alg = alg;
+	if (addr)
+		os_memcpy(cmd.addr, addr, ETH_ALEN);
+	else
+		os_memset(cmd.addr, 0xff, ETH_ALEN);
+	cmd.key_idx = key_idx;
+	cmd.set_tx = set_tx;
+	if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
+		os_memcpy(cmd.seq, seq, seq_len);
+		cmd.seq_len = seq_len;
+	}
+	if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
+		os_memcpy(cmd.key, key, key_len);
+		cmd.key_len = key_len;
+	}
+
+	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
+			    NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	struct privsep_cmd_associate *data;
+	int res;
+	size_t buflen;
+
+	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+		   __func__, priv, params->freq, params->pairwise_suite,
+		   params->group_suite, params->key_mgmt_suite,
+		   params->auth_alg, params->mode);
+
+	buflen = sizeof(*data) + params->wpa_ie_len;
+	data = os_zalloc(buflen);
+	if (data == NULL)
+		return -1;
+
+	if (params->bssid)
+		os_memcpy(data->bssid, params->bssid, ETH_ALEN);
+	os_memcpy(data->ssid, params->ssid, params->ssid_len);
+	data->ssid_len = params->ssid_len;
+	data->freq = params->freq;
+	data->pairwise_suite = params->pairwise_suite;
+	data->group_suite = params->group_suite;
+	data->key_mgmt_suite = params->key_mgmt_suite;
+	data->auth_alg = params->auth_alg;
+	data->mode = params->mode;
+	data->wpa_ie_len = params->wpa_ie_len;
+	if (params->wpa_ie)
+		os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
+	/* TODO: add support for other assoc parameters */
+
+	res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
+			   NULL, NULL);
+	os_free(data);
+
+	return res;
+}
+
+
+static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	int res;
+	size_t len = ETH_ALEN;
+
+	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
+	if (res < 0 || len != ETH_ALEN)
+		return -1;
+	return 0;
+}
+
+
+static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	int res, ssid_len;
+	u8 reply[sizeof(int) + 32];
+	size_t len = sizeof(reply);
+
+	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
+	if (res < 0 || len < sizeof(int))
+		return -1;
+	os_memcpy(&ssid_len, reply, sizeof(int));
+	if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+		wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
+		return -1;
+	}
+	os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
+	return ssid_len;
+}
+
+
+static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
+					  int reason_code)
+{
+	//struct wpa_driver_privsep_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+		   __func__, MAC2STR(addr), reason_code);
+	wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
+	return 0;
+}
+
+
+static void wpa_driver_privsep_event_assoc(void *ctx,
+					   enum wpa_event_type event,
+					   u8 *buf, size_t len)
+{
+	union wpa_event_data data;
+	int inc_data = 0;
+	u8 *pos, *end;
+	int ie_len;
+
+	os_memset(&data, 0, sizeof(data));
+
+	pos = buf;
+	end = buf + len;
+
+	if (end - pos < (int) sizeof(int))
+		return;
+	os_memcpy(&ie_len, pos, sizeof(int));
+	pos += sizeof(int);
+	if (ie_len < 0 || ie_len > end - pos)
+		return;
+	if (ie_len) {
+		data.assoc_info.req_ies = pos;
+		data.assoc_info.req_ies_len = ie_len;
+		pos += ie_len;
+		inc_data = 1;
+	}
+
+	wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
+}
+
+
+static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
+						      size_t len)
+{
+	union wpa_event_data data;
+	int ievent;
+
+	if (len < sizeof(int) ||
+	    len - sizeof(int) > sizeof(data.interface_status.ifname))
+		return;
+
+	os_memcpy(&ievent, buf, sizeof(int));
+
+	os_memset(&data, 0, sizeof(data));
+	data.interface_status.ievent = ievent;
+	os_memcpy(data.interface_status.ifname, buf + sizeof(int),
+		  len - sizeof(int));
+	wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
+}
+
+
+static void wpa_driver_privsep_event_michael_mic_failure(
+	void *ctx, u8 *buf, size_t len)
+{
+	union wpa_event_data data;
+
+	if (len != sizeof(int))
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
+	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
+						     size_t len)
+{
+	union wpa_event_data data;
+
+	if (len != sizeof(struct pmkid_candidate))
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(&data.pmkid_candidate, buf, len);
+	wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
+{
+	union wpa_event_data data;
+
+	if (len != ETH_ALEN)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
+	wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+}
+
+
+static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
+						 size_t len)
+{
+	union wpa_event_data data;
+
+	if (len < sizeof(int) + ETH_ALEN)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
+	os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
+	data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
+	data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
+	wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
+{
+	if (len < ETH_ALEN)
+		return;
+	drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
+}
+
+
+static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
+				       void *sock_ctx)
+{
+	struct wpa_driver_privsep_data *drv = eloop_ctx;
+	u8 *buf, *event_buf;
+	size_t event_len;
+	int res, event;
+	enum privsep_event e;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	const size_t buflen = 2000;
+
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	res = recvfrom(sock, buf, buflen, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(priv_socket)");
+		os_free(buf);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
+
+	if (res < (int) sizeof(int)) {
+		wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
+		return;
+	}
+
+	os_memcpy(&event, buf, sizeof(int));
+	event_buf = &buf[sizeof(int)];
+	event_len = res - sizeof(int);
+	wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
+		   event, (unsigned long) event_len);
+
+	e = event;
+	switch (e) {
+	case PRIVSEP_EVENT_SCAN_RESULTS:
+		wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+		break;
+	case PRIVSEP_EVENT_ASSOC:
+		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
+					       event_buf, event_len);
+		break;
+	case PRIVSEP_EVENT_DISASSOC:
+		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+		break;
+	case PRIVSEP_EVENT_ASSOCINFO:
+		wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
+					       event_buf, event_len);
+		break;
+	case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
+		wpa_driver_privsep_event_michael_mic_failure(
+			drv->ctx, event_buf, event_len);
+		break;
+	case PRIVSEP_EVENT_INTERFACE_STATUS:
+		wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
+							  event_len);
+		break;
+	case PRIVSEP_EVENT_PMKID_CANDIDATE:
+		wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
+							 event_len);
+		break;
+	case PRIVSEP_EVENT_STKSTART:
+		wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
+						  event_len);
+		break;
+	case PRIVSEP_EVENT_FT_RESPONSE:
+		wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
+						     event_len);
+		break;
+	case PRIVSEP_EVENT_RX_EAPOL:
+		wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
+						  event_len);
+		break;
+	}
+
+	os_free(buf);
+}
+
+
+static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_privsep_data *drv;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	drv->priv_socket = -1;
+	drv->cmd_socket = -1;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	return drv;
+}
+
+
+static void wpa_driver_privsep_deinit(void *priv)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+
+	if (drv->priv_socket >= 0) {
+		wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
+		eloop_unregister_read_sock(drv->priv_socket);
+		close(drv->priv_socket);
+	}
+
+	if (drv->own_socket_path) {
+		unlink(drv->own_socket_path);
+		os_free(drv->own_socket_path);
+	}
+
+	if (drv->cmd_socket >= 0) {
+		eloop_unregister_read_sock(drv->cmd_socket);
+		close(drv->cmd_socket);
+	}
+
+	if (drv->own_cmd_path) {
+		unlink(drv->own_cmd_path);
+		os_free(drv->own_cmd_path);
+	}
+
+	os_free(drv);
+}
+
+
+static int wpa_driver_privsep_set_param(void *priv, const char *param)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	const char *pos;
+	char *own_dir, *priv_dir;
+	static unsigned int counter = 0;
+	size_t len;
+	struct sockaddr_un addr;
+
+	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+	if (param == NULL)
+		pos = NULL;
+	else
+		pos = os_strstr(param, "own_dir=");
+	if (pos) {
+		char *end;
+		own_dir = os_strdup(pos + 8);
+		if (own_dir == NULL)
+			return -1;
+		end = os_strchr(own_dir, ' ');
+		if (end)
+			*end = '\0';
+	} else {
+		own_dir = os_strdup("/tmp");
+		if (own_dir == NULL)
+			return -1;
+	}
+
+	if (param == NULL)
+		pos = NULL;
+	else
+		pos = os_strstr(param, "priv_dir=");
+	if (pos) {
+		char *end;
+		priv_dir = os_strdup(pos + 9);
+		if (priv_dir == NULL) {
+			os_free(own_dir);
+			return -1;
+		}
+		end = os_strchr(priv_dir, ' ');
+		if (end)
+			*end = '\0';
+	} else {
+		priv_dir = os_strdup("/var/run/wpa_priv");
+		if (priv_dir == NULL) {
+			os_free(own_dir);
+			return -1;
+		}
+	}
+
+	len = os_strlen(own_dir) + 50;
+	drv->own_socket_path = os_malloc(len);
+	if (drv->own_socket_path == NULL) {
+		os_free(priv_dir);
+		os_free(own_dir);
+		return -1;
+	}
+	os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
+		    own_dir, getpid(), counter++);
+
+	len = os_strlen(own_dir) + 50;
+	drv->own_cmd_path = os_malloc(len);
+	if (drv->own_cmd_path == NULL) {
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+		os_free(priv_dir);
+		os_free(own_dir);
+		return -1;
+	}
+	os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
+		    own_dir, getpid(), counter++);
+
+	os_free(own_dir);
+
+	drv->priv_addr.sun_family = AF_UNIX;
+	os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
+		    "%s/%s", priv_dir, drv->ifname);
+	os_free(priv_dir);
+
+	drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (drv->priv_socket < 0) {
+		perror("socket(PF_UNIX)");
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+	if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
+	    0) {
+		perror("privsep-set-params priv-sock: bind(PF_UNIX)");
+		close(drv->priv_socket);
+		drv->priv_socket = -1;
+		unlink(drv->own_socket_path);
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+		return -1;
+	}
+
+	eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
+				 drv, NULL);
+
+	drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (drv->cmd_socket < 0) {
+		perror("socket(PF_UNIX)");
+		os_free(drv->own_cmd_path);
+		drv->own_cmd_path = NULL;
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
+	if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+	{
+		perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
+		close(drv->cmd_socket);
+		drv->cmd_socket = -1;
+		unlink(drv->own_cmd_path);
+		os_free(drv->own_cmd_path);
+		drv->own_cmd_path = NULL;
+		return -1;
+	}
+
+	if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_privsep_get_capa(void *priv,
+				       struct wpa_driver_capa *capa)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	int res;
+	size_t len = sizeof(*capa);
+
+	res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
+	if (res < 0 || len != sizeof(*capa))
+		return -1;
+	return 0;
+}
+
+
+static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	return drv->own_addr;
+}
+
+
+static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
+{
+	struct wpa_driver_privsep_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
+	return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
+			    os_strlen(alpha2), NULL, NULL);
+}
+
+
+struct wpa_driver_ops wpa_driver_privsep_ops = {
+	"privsep",
+	"wpa_supplicant privilege separated driver",
+	.get_bssid = wpa_driver_privsep_get_bssid,
+	.get_ssid = wpa_driver_privsep_get_ssid,
+	.set_key = wpa_driver_privsep_set_key,
+	.init = wpa_driver_privsep_init,
+	.deinit = wpa_driver_privsep_deinit,
+	.set_param = wpa_driver_privsep_set_param,
+	.scan2 = wpa_driver_privsep_scan,
+	.deauthenticate = wpa_driver_privsep_deauthenticate,
+	.associate = wpa_driver_privsep_associate,
+	.get_capa = wpa_driver_privsep_get_capa,
+	.get_mac_addr = wpa_driver_privsep_get_mac_addr,
+	.get_scan_results2 = wpa_driver_privsep_get_scan_results2,
+	.set_country = wpa_driver_privsep_set_country,
+};
+
+
+struct wpa_driver_ops *wpa_drivers[] =
+{
+	&wpa_driver_privsep_ops,
+	NULL
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_ralink.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ralink.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ralink.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1499 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Ralink Wireless Client
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee at ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver_ralink.h"
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-#define MAX_SSID_LEN 32
-
-struct wpa_driver_ralink_data {
-	void *ctx;
-	int ioctl_sock;
-	struct netlink_data *netlink;
-	char ifname[IFNAMSIZ + 1];
-	u8 *assoc_req_ies;
-	size_t assoc_req_ies_len;
-	u8 *assoc_resp_ies;
-	size_t assoc_resp_ies_len;
-	int no_of_pmkid;
-	struct ndis_pmkid_entry *pmkid;
-	int we_version_compiled;
-	int ap_scan;
-	int scanning_done;
-	u8 g_driver_down;
-	BOOLEAN	bAddWepKey;
-};
-
-static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
-			  unsigned short oid, char *data, int len)
-{
-	char *buf;
-	struct iwreq iwr;
-
-	buf = os_zalloc(len);
-	if (buf == NULL)
-		return -1;
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.flags = oid;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-
-	if (data)
-		os_memcpy(buf, data, len);
-
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-			   __func__, oid, len);
-		os_free(buf);
-		return -1;
-	}
-	os_free(buf);
-	return 0;
-}
-
-static int
-ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UCHAR enabled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (UCHAR*) &enabled;
-	iwr.u.data.flags = RT_OID_NEW_DRIVER;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return 0;
-	}
-
-	return (enabled == 1) ? 1 : 0;
-}
-
-static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCGIWAP]");
-		ret = -1;
-	}
-	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
-	return ret;
-}
-
-static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-#if 0
-	struct wpa_supplicant *wpa_s = drv->ctx;
-	struct wpa_ssid *entry;
-#endif
-	int ssid_len;
-	u8 bssid[ETH_ALEN];
-	u8 ssid_str[MAX_SSID_LEN];
-	struct iwreq iwr;
-#if 0
-	int result = 0;
-#endif
-	int ret = 0;
-#if 0
-	BOOLEAN	ieee8021x_mode = FALSE;
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.essid.pointer = (caddr_t) ssid;
-	iwr.u.essid.length = 32;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	if (ret <= 0)
-		return ret;
-
-	ssid_len = ret;
-	os_memset(ssid_str, 0, MAX_SSID_LEN);
-	os_memcpy(ssid_str, ssid, ssid_len);
-
-	if (drv->ap_scan == 0) {
-		/* Read BSSID form driver */
-		if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
-			wpa_printf(MSG_WARNING, "Could not read BSSID from "
-				   "driver.");
-			return ret;
-		}
-
-#if 0
-		entry = wpa_s->conf->ssid;
-		while (entry) {
-			if (!entry->disabled && ssid_len == entry->ssid_len &&
-			    os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
-			    (!entry->bssid_set ||
-			     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
-				/* match the config of driver */
-				result = 1;
-				break;
-			}
-			entry = entry->next;
-		}
-
-		if (result) {
-			wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
-				   "ieee_required_keys parameters to driver");
-
-			/* set 802.1x mode and ieee_required_keys parameter */
-			if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-				if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
-						ieee8021x_required_key = TRUE;
-				ieee8021x_mode = TRUE;
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
-																								entry->eapol_flags);
-			}
-		}
-#endif
-	}
-
-	return ret;
-}
-
-static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
-				      const u8 *ssid, size_t ssid_len)
-{
-	NDIS_802_11_SSID *buf;
-	int ret = 0;
-	struct iwreq iwr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	buf = os_zalloc(sizeof(NDIS_802_11_SSID));
-	if (buf == NULL)
-		return -1;
-	os_memset(buf, 0, sizeof(buf));
-	buf->SsidLength = ssid_len;
-	os_memcpy(buf->Ssid, ssid, ssid_len);
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	iwr.u.data.flags = OID_802_11_SSID;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = sizeof(NDIS_802_11_SSID);
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
-		ret = -1;
-	}
-	os_free(buf);
-	return ret;
-}
-
-static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
-					  const u8 *data, size_t data_len)
-{
-	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
-	size_t i;
-	union wpa_event_data event;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (data_len < 8) {
-		wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
-			   "Event (len=%lu)", (unsigned long) data_len);
-		return;
-	}
-	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
-	wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
-		   " NumCandidates %d",
-		   (int) pmkid->Version, (int) pmkid->NumCandidates);
-
-	if (pmkid->Version != 1) {
-		wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
-			   "List Version %d", (int) pmkid->Version);
-		return;
-	}
-
-	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
-		wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
-			   "underflow");
-
-		return;
-	}
-
-
-
-	os_memset(&event, 0, sizeof(event));
-	for (i = 0; i < pmkid->NumCandidates; i++) {
-		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-		wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
-			   (unsigned long) i, MAC2STR(p->BSSID),
-			   (int) p->Flags);
-		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
-		event.pmkid_candidate.index = i;
-		event.pmkid_candidate.preauth =
-			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
-		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
-				     &event);
-	}
-}
-
-static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
-{
-	int len, count, i, ret;
-	struct ndis_pmkid_entry *entry;
-	NDIS_802_11_PMKID *p;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	count = 0;
-	entry = drv->pmkid;
-	while (entry) {
-		count++;
-		if (count >= drv->no_of_pmkid)
-			break;
-		entry = entry->next;
-	}
-	len = 8 + count * sizeof(BSSID_INFO);
-	p = os_zalloc(len);
-	if (p == NULL)
-		return -1;
-	p->Length = len;
-	p->BSSIDInfoCount = count;
-	entry = drv->pmkid;
-	for (i = 0; i < count; i++) {
-		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
-		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
-		entry = entry->next;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
-		    (const u8 *) p, len);
-	ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
-	os_free(p);
-	return ret;
-}
-
-static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
-				       const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	prev = NULL;
-	entry = drv->pmkid;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		prev = entry;
-		entry = entry->next;
-	}
-
-	if (entry) {
-		/* Replace existing entry for this BSSID and move it into the
-		 * beginning of the list. */
-		os_memcpy(entry->pmkid, pmkid, 16);
-		if (prev) {
-			prev->next = entry->next;
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	} else {
-		entry = os_malloc(sizeof(*entry));
-		if (entry) {
-			os_memcpy(entry->bssid, bssid, ETH_ALEN);
-			os_memcpy(entry->pmkid, pmkid, 16);
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	}
-
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
-					  const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	entry = drv->pmkid;
-	prev = NULL;
-	drv->pmkid = NULL;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
-		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				drv->pmkid = entry->next;
-			os_free(entry);
-			break;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_flush_pmkid(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	NDIS_802_11_PMKID p;
-	struct ndis_pmkid_entry *pmkid, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	pmkid = drv->pmkid;
-	drv->pmkid = NULL;
-	while (pmkid) {
-		prev = pmkid;
-		pmkid = pmkid->next;
-		os_free(prev);
-	}
-
-	os_memset(&p, 0, sizeof(p));
-	p.Length = 8;
-	p.BSSIDInfoCount = 0;
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-		    (const u8 *) &p, 8);
-	return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-}
-
-static void
-wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
-					void *ctx, char *custom)
-{
-	union wpa_event_data data;
-	u8 *req_ies = NULL, *resp_ies = NULL;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	os_memset(&data, 0, sizeof(data));
-	/* Host AP driver */
-	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		/* receive a MICFAILURE report */
-		data.michael_mic_failure.unicast =
-			os_strstr(custom, " unicast") != NULL;
-		/* TODO: parse parameters(?) */
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-	} else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
-		/* receive assoc. req. IEs */
-		char *spos;
-		int bytes;
-
-		spos = custom + 17;
-		/*get IE's length */
-		/*
-		 * bytes = strlen(spos); ==> bug, bytes may less than original
-		 * size by using this way to get size. snowpin 20070312
-		 * if (!bytes)
-		 *	return;
-		 */
-		bytes = drv->assoc_req_ies_len;
-
-		req_ies = os_malloc(bytes);
-		if (req_ies == NULL)
-			return;
-		os_memcpy(req_ies, spos, bytes);
-		data.assoc_info.req_ies = req_ies;
-		data.assoc_info.req_ies_len = bytes;
-
-		/* skip the '\0' byte */
-		spos += bytes + 1;
-
-		data.assoc_info.resp_ies = NULL;
-		data.assoc_info.resp_ies_len = 0;
-
-		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
-			/* receive assoc. resp. IEs */
-			spos += 9;
-			/* get IE's length */
-			bytes = os_strlen(spos);
-			if (!bytes)
-				goto done;
-
-			resp_ies = os_malloc(bytes);
-			if (resp_ies == NULL)
-				goto done;
-			os_memcpy(resp_ies, spos, bytes);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = bytes;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
-	done:
-		/* free allocated memory */
-		os_free(resp_ies);
-		os_free(req_ies);
-	}
-}
-
-static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
-{
-	union wpa_event_data event;
-	int enable_wpa_supplicant = 0;
-	drv->g_driver_down = 0;
-	os_memset(&event, 0, sizeof(event));
-	os_snprintf(event.interface_status.ifname,
-		    sizeof(event.interface_status.ifname), "%s", drv->ifname);
-
-	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_INFO, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "ralink. Driver does not support "
-			   "wpa_supplicant");
-	}
-}
-
-static void
-wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
-				 void *ctx, char *data, int len)
-{
-	struct iw_event iwe_buf, *iwe = &iwe_buf;
-	char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
-#if 0
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	assoc_info_buf = info_pos = NULL;
-	pos = data;
-	end = data + len;
-
-	while (pos + IW_EV_LCP_LEN <= end) {
-		/* 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)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-
-		if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
-			/* WE-19 removed the pointer from struct iw_point */
-			char *dpos = (char *) &iwe_buf.u.data.length;
-			int dlen = dpos - (char *) &iwe_buf;
-			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-				  sizeof(struct iw_event) - dlen);
-		} else {
-			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = os_malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-
-			if (drv->ap_scan == 1) {
-				if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_REQIE_EVENT_FLAG) ||
-				    (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_ASSOCINFO_EVENT_FLAG)) {
-					if (drv->scanning_done == 0) {
-						os_free(buf);
-						return;
-					}
-				}
-			}
-
-			if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
-				wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCIATED_EVENT !!!");
-			} else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ReqIEs !!!");
-				drv->assoc_req_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_req_ies == NULL) {
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_req_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_req_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive RespIEs !!!");
-				drv->assoc_resp_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_resp_ies == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_resp_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_resp_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags ==
-				   RT_ASSOCINFO_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCINFO_EVENT !!!");
-
-				assoc_info_buf =
-					os_zalloc(drv->assoc_req_ies_len +
-						  drv->assoc_resp_ies_len + 1);
-
-				if (assoc_info_buf == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(drv->assoc_resp_ies);
-					drv->assoc_resp_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				if (drv->assoc_req_ies) {
-					os_memcpy(assoc_info_buf,
-						  drv->assoc_req_ies,
-						  drv->assoc_req_ies_len);
-				}
-				info_pos = assoc_info_buf +
-					drv->assoc_req_ies_len;
-				if (drv->assoc_resp_ies) {
-					os_memcpy(info_pos,
-						  drv->assoc_resp_ies,
-						  drv->assoc_resp_ies_len);
-				}
-				assoc_info_buf[drv->assoc_req_ies_len +
-					       drv->assoc_resp_ies_len] = '\0';
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, assoc_info_buf);
-				os_free(drv->assoc_req_ies);
-				drv->assoc_req_ies = NULL;
-				os_free(drv->assoc_resp_ies);
-				drv->assoc_resp_ies = NULL;
-				os_free(assoc_info_buf);
-			} else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
-			{
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive DISASSOCIATED_EVENT !!!");
-				wpa_supplicant_event(ctx, EVENT_DISASSOC,
-						     NULL);
-			} else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive PMKIDCAND_EVENT !!!");
-				wpa_driver_ralink_event_pmkid(
-					drv, (const u8 *) custom,
-					iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
-				drv->g_driver_down = 1;
-				eloop_terminate();
-			} else if (iwe->u.data.flags == RT_INTERFACE_UP) {
-				ralink_interface_up(drv);
-			} else {
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, buf);
-			}
-			os_free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-static void
-wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 
-				    u8 *buf, size_t len)
-{
-	struct wpa_driver_ralink_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
-
-	attrlen = len;
-	wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
-	attr = (struct rtattr *) buf;
-	wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
-	while (RTA_OK(attr, attrlen)) {
-		wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
-		if (attr->rta_type == IFLA_WIRELESS) {
-			wpa_driver_ralink_event_wireless(
-				drv, ctx,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-		wpa_hexdump(MSG_DEBUG, "attr3: ",
-			    (u8 *) attr, sizeof(struct rtattr));
-	}
-}
-
-static int
-ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UINT we_version_compiled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) &we_version_compiled;
-	iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return -1;
-	}
-
-	drv->we_version_compiled = we_version_compiled;
-
-	return 0;
-}
-
-static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct wpa_driver_ralink_data *drv;
-	struct ifreq ifr;
-	UCHAR enable_wpa_supplicant = 0;
-	struct netlink_config *cfg;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-
-	drv->scanning_done = 1;
-	drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-	drv->g_driver_down = 0;
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL) {
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
-
-	linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
-	ralink_get_we_version_compiled(drv);
-	wpa_driver_ralink_flush_pmkid(drv);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
-			   "wpa_supplicant");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (drv->ap_scan == 1)
-		drv->scanning_done = 0;
-
-	return drv;
-}
-
-static void wpa_driver_ralink_deinit(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR enable_wpa_supplicant;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	enable_wpa_supplicant = 0;
-
-	if (drv->g_driver_down == 0) {
-		/* trigger driver disable wpa_supplicant support */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (char *) &enable_wpa_supplicant,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_flush_pmkid(drv);
-
-		sleep(1);
-		/* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
-	}
-
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	netlink_deinit(drv->netlink);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_ralink_data *drv = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-
-	drv->scanning_done = 1;
-
-}
-
-static int wpa_driver_ralink_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-#if 0
-	if (ssid_len > IW_ESSID_MAX_SIZE) {
-		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
-			   __FUNCTION__, (unsigned long) ssid_len);
-		return -1;
-	}
-
-	/* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
-#endif
-
-	if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
-			   (char *) params->extra_ies, params->extra_ies_len) <
-	    0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPS_PROBE_REQ_IE");
-	}
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
-			       drv->ctx);
-
-	drv->scanning_done = 0;
-
-	return ret;
-}
-
-static struct wpa_scan_results *
-wpa_driver_ralink_get_scan_results(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR *buf = NULL;
-	size_t buf_len;
-	NDIS_802_11_BSSID_LIST_EX *wsr;
-	NDIS_WLAN_BSSID_EX *wbi;
-	struct iwreq iwr;
-	size_t ap_num;
-	u8 *pos;
-	struct wpa_scan_results *res;
-
-	if (drv->g_driver_down == 1)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->we_version_compiled >= 17)
-		buf_len = 8192;
-	else
-		buf_len = 4096;
-
-	for (;;) {
-		buf = os_zalloc(buf_len);
-		iwr.u.data.length = buf_len;
-		if (buf == NULL)
-			return NULL;
-
-		wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
-
-		wsr->NumberOfItems = 0;
-		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-		iwr.u.data.pointer = (void *) buf;
-		iwr.u.data.flags = OID_802_11_BSSID_LIST;
-
-		if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
-			break;
-
-		if (errno == E2BIG && buf_len < 65535) {
-			os_free(buf);
-			buf = NULL;
-			buf_len *= 2;
-			if (buf_len > 65535)
-				buf_len = 65535; /* 16-bit length field */
-			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
-				   "trying larger buffer (%lu bytes)",
-				   (unsigned long) buf_len);
-		} else {
-			perror("ioctl[RT_PRIV_IOCTL]");
-			os_free(buf);
-			return NULL;
-		}
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->NumberOfItems *
-			     sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
-	     ++ap_num) {
-		struct wpa_scan_res *r = NULL;
-		size_t extra_len = 0, var_ie_len = 0;
-		u8 *pos2;
-
-		/* SSID data element */
-		extra_len += 2 + wbi->Ssid.SsidLength;
-		var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-		r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
-		/* get ie's */
-		wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
-			    (u8 *) &wbi->IEs[0], wbi->IELength);
-
-		os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
-
-		extra_len += (2 + wbi->Ssid.SsidLength);
-		r->ie_len = extra_len + var_ie_len;
-		pos2 = (u8 *) (r + 1);
-
-		/*
-		 * Generate a fake SSID IE since the driver did not report
-		 * a full IE list.
-		 */
-		*pos2++ = WLAN_EID_SSID;
-		*pos2++ = wbi->Ssid.SsidLength;
-		os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
-		pos2 += wbi->Ssid.SsidLength;
-
-		r->freq = (wbi->Configuration.DSConfig / 1000);
-
-		pos = (u8 *) wbi + sizeof(*wbi) - 1;
-
-		pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
-		os_memcpy(&(r->caps), pos, 2);
-		pos += 2;
-
-		if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
-			os_memcpy(pos2, pos, var_ie_len);
-
-		wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
-	}
-
-	os_free(buf);
-	return res;
-}
-
-static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_AUTHENTICATION_MODE mode)
-{
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-			   (char *) &auth_mode, sizeof(auth_mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_AUTHENTICATION_MODE (%d)",
-			   (int) auth_mode);
-		return -1;
-	}
-	return 0;
-}
-
-static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_WEP_STATUS encr_type)
-{
-	NDIS_802_11_WEP_STATUS wep_status = encr_type;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
-			   (char *) &wep_status, sizeof(wep_status)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_WEP_STATUS (%d)",
-			   (int) wep_status);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
-					int key_idx, const u8 *addr,
-					const u8 *bssid, int pairwise)
-{
-	NDIS_802_11_REMOVE_KEY rkey;
-	NDIS_802_11_KEY_INDEX _index;
-	int res, res2;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&rkey, 0, sizeof(rkey));
-
-	rkey.Length = sizeof(rkey);
-	rkey.KeyIndex = key_idx;
-
-	if (pairwise)
-		rkey.KeyIndex |= 1 << 30;
-
-	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
-	res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
-			     sizeof(rkey));
-
-	/* AlbertY at 20060210 removed it */
-	if (0 /* !pairwise */) {
-		res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
-				      (char *) &_index, sizeof(_index));
-	} else
-		res2 = 0;
-
-	if (res < 0 && res2 < 0)
-		return res;
-	return 0;
-}
-
-static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
-				     int pairwise, int key_idx, int set_tx,
-				     const u8 *key, size_t key_len)
-{
-	NDIS_802_11_WEP *wep;
-	size_t len;
-	int res;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	len = 12 + key_len;
-	wep = os_zalloc(len);
-	if (wep == NULL)
-		return -1;
-
-	wep->Length = len;
-	wep->KeyIndex = key_idx;
-
-	if (set_tx)
-		wep->KeyIndex |= 0x80000000;
-
-	wep->KeyLength = key_len;
-	os_memcpy(wep->KeyMaterial, key, key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
-			(const u8 *) wep, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
-	os_free(wep);
-
-	return res;
-}
-
-static int wpa_driver_ralink_set_key(const char *ifname, void *priv,
-				     enum wpa_alg alg, const u8 *addr,
-				     int key_idx, int set_tx,
-				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	size_t len, i;
-	NDIS_802_11_KEY *nkey;
-	int res, pairwise;
-	u8 bssid[ETH_ALEN];
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	drv->bAddWepKey = FALSE;
-
-	if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-				      ETH_ALEN) == 0) {
-		/* Group Key */
-		pairwise = 0;
-		wpa_driver_ralink_get_bssid(drv, bssid);
-	} else {
-		/* Pairwise Key */
-		pairwise = 1;
-		os_memcpy(bssid, addr, ETH_ALEN);
-	}
-
-	if (alg == WPA_ALG_NONE || key_len == 0) {
-		return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
-						    pairwise);
-	}
-
-	if (alg == WPA_ALG_WEP) {
-		drv->bAddWepKey = TRUE;
-		return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
-						 set_tx, key, key_len);
-	}
-
-	len = 12 + 6 + 6 + 8 + key_len;
-
-	nkey = os_zalloc(len);
-	if (nkey == NULL)
-		return -1;
-
-	nkey->Length = len;
-	nkey->KeyIndex = key_idx;
-
-	if (set_tx)
-		nkey->KeyIndex |= 1 << 31;
-
-	if (pairwise)
-		nkey->KeyIndex |= 1 << 30;
-
-	if (seq && seq_len)
-		nkey->KeyIndex |= 1 << 29;
-
-	nkey->KeyLength = key_len;
-	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-
-	if (seq && seq_len) {
-		for (i = 0; i < seq_len; i++)
-			nkey->KeyRSC |= seq[i] << (i * 8);
-	}
-	if (alg == WPA_ALG_TKIP && key_len == 32) {
-		os_memcpy(nkey->KeyMaterial, key, 16);
-		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
-		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
-	} else {
-		os_memcpy(nkey->KeyMaterial, key, key_len);
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
-			(const u8 *) nkey, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
-	os_free(nkey);
-
-	return res;
-}
-
-static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_DISASSOCIATE");
-	}
-
-	return 0;
-}
-
-static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_get_new_driver_flag(drv) == 0) {
-		return wpa_driver_ralink_disassociate(priv, addr, reason_code);
-	} else {
-		MLME_DEAUTH_REQ_STRUCT mlme;
-		os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
-		mlme.Reason = reason_code;
-		os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
-		return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
-				      (char *) &mlme,
-				      sizeof(MLME_DEAUTH_REQ_STRUCT));
-	}
-}
-
-static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
-					size_t ie_len)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) ie;
-	iwr.u.data.length = ie_len;
-
-	wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
-		    (u8 *) ie, ie_len);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWGENIE]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_ralink_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode;
-	NDIS_802_11_WEP_STATUS encr;
-	BOOLEAN		ieee8021xMode;
-	BOOLEAN 	ieee8021x_required_key = TRUE;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (params->mode == IEEE80211_MODE_IBSS)
-		mode = Ndis802_11IBSS;
-	else
-		mode = Ndis802_11Infrastructure;
-
-	if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-			 (char *) &mode, sizeof(mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-			   (int) mode);
-		/* Try to continue anyway */
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_WPS) {
-		UCHAR enable_wps = 0x80;
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_INFO, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wps);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
-					     params->wpa_ie_len);
-
-		ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
-
-		ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
-	} else {
-#ifdef CONFIG_WPS
-		UCHAR enable_wpa_supplicant;
-
-		if (drv->ap_scan == 1)
-			enable_wpa_supplicant = 0x01;
-		else
-			enable_wpa_supplicant = 0x02;
-
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wpa_supplicant,
-				   sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
-#endif /* CONFIG_WPS */
-
-		if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-			if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
-				if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-					auth_mode = Ndis802_11AuthModeAutoSwitch;
-				else
-					auth_mode = Ndis802_11AuthModeShared;
-			} else
-				auth_mode = Ndis802_11AuthModeOpen;
-		} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-			if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPA2PSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA2;
-		} else {
-			if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-				auth_mode = Ndis802_11AuthModeWPANone;
-			else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPAPSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA;
-		}
-
-		switch (params->pairwise_suite) {
-		case CIPHER_CCMP:
-			encr = Ndis802_11Encryption3Enabled;
-			break;
-		case CIPHER_TKIP:
-			encr = Ndis802_11Encryption2Enabled;
-			break;
-		case CIPHER_WEP40:
-		case CIPHER_WEP104:
-			encr = Ndis802_11Encryption1Enabled;
-			break;
-		case CIPHER_NONE:
-			if (params->group_suite == CIPHER_CCMP)
-				encr = Ndis802_11Encryption3Enabled;
-			else if (params->group_suite == CIPHER_TKIP)
-				encr = Ndis802_11Encryption2Enabled;
-			else
-				encr = Ndis802_11EncryptionDisabled;
-			break;
-		default:
-			encr = Ndis802_11EncryptionDisabled;
-			break;
-		}
-
-		ralink_set_auth_mode(drv, auth_mode);
-
-		/* notify driver that IEEE8021x mode is enabled */
-		if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
-			ieee8021xMode = TRUE;
-			if (drv->bAddWepKey)
-				ieee8021x_required_key = FALSE;
-		} else
-			ieee8021xMode = FALSE;
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
-				   (char *) &ieee8021x_required_key,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
-				   "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
-				   (int) ieee8021x_required_key);
-		} else {
-			wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
-				   ieee8021x_required_key ? "TRUE" : "FALSE");
-		}
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
-				   (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "OID_802_11_SET_IEEE8021X(%d)",
-				   (int) ieee8021xMode);
-		}
-
-		ralink_set_encr_type(drv, encr);
-
-		if ((ieee8021xMode == FALSE) &&
-		    (encr == Ndis802_11Encryption1Enabled)) {
-			/* static WEP */
-			int enabled = 0;
-			if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
-					   (char *) &enabled, sizeof(enabled))
-			    < 0) {
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-					   "OID_802_11_DROP_UNENCRYPTED(%d)",
-					   (int) encr);
-			}
-		}
-	}
-
-	return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-static int
-wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
-			      sizeof(int));
-}
-
-const struct wpa_driver_ops wpa_driver_ralink_ops = {
-	.name = "ralink",
-	.desc = "Ralink Wireless Client driver",
-	.get_bssid = wpa_driver_ralink_get_bssid,
-	.get_ssid = wpa_driver_ralink_get_ssid,
-	.set_key = wpa_driver_ralink_set_key,
-	.init = wpa_driver_ralink_init,
-	.deinit = wpa_driver_ralink_deinit,
-	.set_countermeasures	= wpa_driver_ralink_set_countermeasures,
-	.scan2 = wpa_driver_ralink_scan,
-	.get_scan_results2 = wpa_driver_ralink_get_scan_results,
-	.deauthenticate = wpa_driver_ralink_deauthenticate,
-	.disassociate = wpa_driver_ralink_disassociate,
-	.associate = wpa_driver_ralink_associate,
-	.add_pmkid = wpa_driver_ralink_add_pmkid,
-	.remove_pmkid = wpa_driver_ralink_remove_pmkid,
-	.flush_pmkid = wpa_driver_ralink_flush_pmkid,
-};

Deleted: vendor/wpa/2.0/src/drivers/driver_ralink.h
===================================================================
--- vendor/wpa/dist/src/drivers/driver_ralink.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_ralink.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,383 +0,0 @@
-/*
- * WPA Supplicant - driver_ralink exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee at ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-// Ralink defined OIDs
-#if WIRELESS_EXT <= 11
-#ifndef SIOCDEVPRIVATE
-#define SIOCDEVPRIVATE                              0x8BE0
-#endif
-#define SIOCIWFIRSTPRIV								SIOCDEVPRIVATE
-#endif
-
-#define RT_PRIV_IOCTL								(SIOCIWFIRSTPRIV + 0x0E)  
-#define RTPRIV_IOCTL_SET							(SIOCIWFIRSTPRIV + 0x02)
-
-// IEEE 802.11 OIDs  &  Ralink defined OIDs  ******
-
-// (RaConfig Set/QueryInform) ==>
-#define OID_GET_SET_TOGGLE							0x8000
-
-#define OID_802_11_ADD_WEP                          0x0112
-#define OID_802_11_REMOVE_WEP                       0x0113
-#define OID_802_11_DISASSOCIATE                     0x0114
-#define OID_802_11_PRIVACY_FILTER                   0x0118
-#define OID_802_11_ASSOCIATION_INFORMATION          0x011E
-#define OID_802_11_BSSID_LIST_SCAN                  0x0508
-#define OID_802_11_SSID                             0x0509
-#define OID_802_11_BSSID                            0x050A
-#define OID_802_11_WEP_STATUS                       0x0510
-#define OID_802_11_AUTHENTICATION_MODE              0x0511
-#define OID_802_11_INFRASTRUCTURE_MODE              0x0512
-#define OID_802_11_TX_POWER_LEVEL                   0x0517
-#define OID_802_11_REMOVE_KEY                       0x0519
-#define OID_802_11_ADD_KEY                          0x0520
-#define OID_802_11_DEAUTHENTICATION                 0x0526
-#define OID_802_11_DROP_UNENCRYPTED                 0x0527
-#define OID_802_11_BSSID_LIST                       0x0609
-#define OID_802_3_CURRENT_ADDRESS                   0x060A
-#define OID_SET_COUNTERMEASURES                     0x0616
-#define OID_802_11_SET_IEEE8021X                    0x0617	// For IEEE8021x mode 
-#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY        0x0618  // For DynamicWEP in IEEE802.1x mode
-#define OID_802_11_PMKID                            0x0620
-#define RT_OID_WPA_SUPPLICANT_SUPPORT               0x0621  // for trigger driver enable/disable wpa_supplicant support 
-#define RT_OID_WE_VERSION_COMPILED                  0x0622
-#define RT_OID_NEW_DRIVER                           0x0623
-#define RT_OID_WPS_PROBE_REQ_IE						0x0625
-
-#define PACKED  __attribute__ ((packed))
-
-//wpa_supplicant event flags
-#define	RT_ASSOC_EVENT_FLAG                         0x0101
-#define	RT_DISASSOC_EVENT_FLAG                      0x0102
-#define	RT_REQIE_EVENT_FLAG                         0x0103
-#define	RT_RESPIE_EVENT_FLAG                        0x0104
-#define	RT_ASSOCINFO_EVENT_FLAG                     0x0105
-#define RT_PMKIDCAND_FLAG                           0x0106
-#define RT_INTERFACE_DOWN                           0x0107
-#define RT_INTERFACE_UP                           	0x0108
-
-//
-// IEEE 802.11 Structures and definitions
-//
-// new types for Media Specific Indications
-
-#ifndef ULONG
-#define CHAR            char
-#define INT             int
-#define SHORT           int
-#define UINT            u32
-#undef  ULONG           
-//#define ULONG           u32
-#define ULONG           unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
-#define USHORT          unsigned short
-#define UCHAR           unsigned char
-
-#define uint32		u32
-#define uint8		u8
-
-
-#define BOOLEAN         u8
-//#define LARGE_INTEGER s64
-#define VOID            void
-#define LONG            long
-#define LONGLONG        s64
-#define ULONGLONG       u64
-typedef VOID            *PVOID;
-typedef CHAR            *PCHAR;
-typedef UCHAR           *PUCHAR;
-typedef USHORT          *PUSHORT;
-typedef LONG            *PLONG;
-typedef ULONG           *PULONG;
-
-typedef union _LARGE_INTEGER {
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    }vv;
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    } u;
-    s64 QuadPart;
-} LARGE_INTEGER;
-
-#endif
-
-#define NDIS_802_11_LENGTH_SSID         32
-#define NDIS_802_11_LENGTH_RATES        8
-#define NDIS_802_11_LENGTH_RATES_EX     16
-#define MAX_LEN_OF_SSID                 32
-#define MAC_ADDR_LEN                    6
-
-typedef UCHAR   NDIS_802_11_MAC_ADDRESS[6];
-
-// mask for authentication/integrity fields
-#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        0x0f
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH             0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE          0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR     0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR        0x0E
-
-// Added new types for OFDM 5G and 2.4G
-typedef enum _NDIS_802_11_NETWORK_TYPE
-{
-    Ndis802_11FH, 
-    Ndis802_11DS, 
-    Ndis802_11OFDM5,
-    Ndis802_11OFDM24,
-    Ndis802_11Automode,
-    Ndis802_11NetworkTypeMax    // not a real type, defined as an upper bound
-} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
-//
-// Received Signal Strength Indication
-//
-typedef LONG    NDIS_802_11_RSSI;           // in dBm
-
-typedef struct _NDIS_802_11_CONFIGURATION_FH
-{
-   ULONG           Length;            // Length of structure
-   ULONG           HopPattern;        // As defined by 802.11, MSB set 
-   ULONG           HopSet;            // to one if non-802.11
-   ULONG           DwellTime;         // units are Kusec
-} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
-
-typedef struct _NDIS_802_11_CONFIGURATION
-{
-   ULONG                           Length;             // Length of structure
-   ULONG                           BeaconPeriod;       // units are Kusec
-   ULONG                           ATIMWindow;         // units are Kusec
-   ULONG                           DSConfig;           // Frequency, units are kHz
-   NDIS_802_11_CONFIGURATION_FH    FHConfig;
-} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
-
-typedef  ULONG  NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG   NDIS_802_11_KEY_RSC;
-
-// Key mapping keys require a BSSID
-typedef struct _NDIS_802_11_KEY
-{
-    UINT           Length;             // Length of this structure
-    UINT           KeyIndex;           
-    UINT           KeyLength;          // length of key in bytes
-    NDIS_802_11_MAC_ADDRESS BSSID;
-    NDIS_802_11_KEY_RSC KeyRSC;
-    UCHAR           KeyMaterial[1];     // variable length depending on above field
-} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
-
-typedef struct _NDIS_802_11_REMOVE_KEY
-{
-    UINT                   Length;        // Length of this structure
-    UINT                   KeyIndex;           
-    NDIS_802_11_MAC_ADDRESS BSSID;      
-} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
-
-typedef struct PACKED _NDIS_802_11_WEP
-{
-   UINT     Length;        // Length of this structure
-   UINT           KeyIndex;           // 0 is the per-client key, 1-N are the
-                                        // global keys
-   UINT     KeyLength;     // length of key in bytes
-   UCHAR     KeyMaterial[1];// variable length depending on above field
-} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
-
-
-typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
-{
-   Ndis802_11IBSS,
-   Ndis802_11Infrastructure,
-   Ndis802_11AutoUnknown,
-   Ndis802_11InfrastructureMax     // Not a real value, defined as upper bound
-} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-// PMKID Structures
-typedef UCHAR   NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct _BSSID_INFO
-{
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO, *PBSSID_INFO;
-
-typedef struct _NDIS_802_11_PMKID
-{
-	ULONG Length;
-	ULONG BSSIDInfoCount;
-	BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
-
-//Added new types for PMKID Candidate lists.
-typedef struct _PMKID_CANDIDATE {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	ULONG Flags;
-} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
-typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
-{
-	ULONG Version;       // Version of the structure
-	ULONG NumCandidates; // No. of pmkid candidates
-	PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
-
-//Flags for PMKID Candidate list structure
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED	0x01
-
-// Add new authentication modes
-typedef enum _NDIS_802_11_AUTHENTICATION_MODE
-{
-   Ndis802_11AuthModeOpen,
-   Ndis802_11AuthModeShared,
-   Ndis802_11AuthModeAutoSwitch,
-   Ndis802_11AuthModeWPA,
-   Ndis802_11AuthModeWPAPSK,
-   Ndis802_11AuthModeWPANone,
-   Ndis802_11AuthModeWPA2,
-   Ndis802_11AuthModeWPA2PSK,    
-   Ndis802_11AuthModeMax           // Not a real mode, defined as upper bound
-} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
-
-typedef UCHAR  NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];        // Set of 8 data rates
-typedef UCHAR  NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];  // Set of 16 data rates
-
-typedef struct PACKED _NDIS_802_11_SSID 
-{
-    INT   SsidLength;         // length of SSID field below, in bytes;
-                                // this can be zero.
-    UCHAR   Ssid[NDIS_802_11_LENGTH_SSID];           // SSID information field
-} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
-
-
-typedef struct PACKED _NDIS_WLAN_BSSID
-{
-   ULONG                               Length;     // Length of this structure
-   NDIS_802_11_MAC_ADDRESS             MacAddress; // BSSID
-   UCHAR                               Reserved[2];
-   NDIS_802_11_SSID                    Ssid;       // SSID
-   ULONG                               Privacy;    // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-   NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-   NDIS_802_11_CONFIGURATION           Configuration;
-   NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-   NDIS_802_11_RATES                   SupportedRates;
-} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST
-{
-   UINT             NumberOfItems;      // in list below, at least 1
-   NDIS_WLAN_BSSID Bssid[1];
-} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
-
-// Added Capabilities, IELength and IEs for each BSSID
-typedef struct PACKED _NDIS_WLAN_BSSID_EX
-{
-    ULONG                               Length;             // Length of this structure
-    NDIS_802_11_MAC_ADDRESS             MacAddress;         // BSSID
-    UCHAR                               Reserved[2];
-    NDIS_802_11_SSID                    Ssid;               // SSID
-    UINT                                Privacy;            // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-    NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-    NDIS_802_11_CONFIGURATION           Configuration;
-    NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-    NDIS_802_11_RATES_EX                SupportedRates;
-    ULONG                               IELength;
-    UCHAR                               IEs[1];
-} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
-{
-    UINT                   NumberOfItems;      // in list below, at least 1
-    NDIS_WLAN_BSSID_EX      Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
-
-typedef struct PACKED _NDIS_802_11_FIXED_IEs 
-{
-    UCHAR Timestamp[8];
-    USHORT BeaconInterval;
-    USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
-
-// Added new encryption types
-// Also aliased typedef to new name
-typedef enum _NDIS_802_11_WEP_STATUS
-{
-   Ndis802_11WEPEnabled,
-   Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
-   Ndis802_11WEPDisabled,
-   Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
-   Ndis802_11WEPKeyAbsent,
-   Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
-   Ndis802_11WEPNotSupported,
-   Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
-   Ndis802_11Encryption2Enabled,
-   Ndis802_11Encryption2KeyAbsent,
-   Ndis802_11Encryption3Enabled,
-   Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
-  NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum _NDIS_802_11_RELOAD_DEFAULTS
-{
-   Ndis802_11ReloadWEPKeys
-} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
-
-#define NDIS_802_11_AI_REQFI_CAPABILITIES      1
-#define NDIS_802_11_AI_REQFI_LISTENINTERVAL    2
-#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS  4
-
-#define NDIS_802_11_AI_RESFI_CAPABILITIES      1
-#define NDIS_802_11_AI_RESFI_STATUSCODE        2
-#define NDIS_802_11_AI_RESFI_ASSOCIATIONID     4
-
-typedef struct _NDIS_802_11_AI_REQFI
-{
-    USHORT Capabilities;
-    USHORT ListenInterval;
-    NDIS_802_11_MAC_ADDRESS  CurrentAPAddress;
-} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
-
-typedef struct _NDIS_802_11_AI_RESFI
-{
-    USHORT Capabilities;
-    USHORT StatusCode;
-    USHORT AssociationId;
-} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
-
-typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
-{
-    ULONG                   Length;
-    USHORT                  AvailableRequestFixedIEs;
-    NDIS_802_11_AI_REQFI    RequestFixedIEs;
-    ULONG                   RequestIELength;
-    ULONG                   OffsetRequestIEs;
-    USHORT                  AvailableResponseFixedIEs;
-    NDIS_802_11_AI_RESFI    ResponseFixedIEs;
-    ULONG                   ResponseIELength;
-    ULONG                   OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-struct ndis_pmkid_entry {
-	struct ndis_pmkid_entry *next;
-	u8 bssid[ETH_ALEN];
-	u8 pmkid[16];
-};
-
-typedef struct _MLME_DEAUTH_REQ_STRUCT {
-    UCHAR        Addr[MAC_ADDR_LEN];
-    USHORT       Reason;
-} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;

Deleted: vendor/wpa/2.0/src/drivers/driver_roboswitch.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_roboswitch.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_roboswitch.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,480 +0,0 @@
-/*
- * WPA Supplicant - roboswitch driver interface
- * Copyright (c) 2008-2009 Jouke Witteveen
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#include <linux/if.h>
-#include <linux/sockios.h>
-#include <linux/if_ether.h>
-#include <linux/mii.h>
-
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-
-#define ROBO_PHY_ADDR		0x1e	/* RoboSwitch PHY address */
-
-/* MII access registers */
-#define ROBO_MII_PAGE		0x10	/* MII page register */
-#define ROBO_MII_ADDR		0x11	/* MII address register */
-#define ROBO_MII_DATA_OFFSET	0x18	/* Start of MII data registers */
-
-#define ROBO_MII_PAGE_ENABLE	0x01	/* MII page op code */
-#define ROBO_MII_ADDR_WRITE	0x01	/* MII address write op code */
-#define ROBO_MII_ADDR_READ	0x02	/* MII address read op code */
-#define ROBO_MII_DATA_MAX	   4	/* Consecutive MII data registers */
-#define ROBO_MII_RETRY_MAX	  10	/* Read attempts before giving up */
-
-/* Page numbers */
-#define ROBO_ARLCTRL_PAGE	0x04	/* ARL control page */
-#define ROBO_VLAN_PAGE		0x34	/* VLAN page */
-
-/* ARL control page registers */
-#define ROBO_ARLCTRL_CONF	0x00	/* ARL configuration register */
-#define ROBO_ARLCTRL_ADDR_1	0x10	/* Multiport address 1 */
-#define ROBO_ARLCTRL_VEC_1	0x16	/* Multiport vector 1 */
-#define ROBO_ARLCTRL_ADDR_2	0x20	/* Multiport address 2 */
-#define ROBO_ARLCTRL_VEC_2	0x26	/* Multiport vector 2 */
-
-/* VLAN page registers */
-#define ROBO_VLAN_ACCESS	0x08	/* VLAN table access register */
-#define ROBO_VLAN_ACCESS_5350	0x06	/* VLAN table access register (5350) */
-#define ROBO_VLAN_READ		0x0c	/* VLAN read register */
-#define ROBO_VLAN_MAX		0xff	/* Maximum number of VLANs */
-
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-
-struct wpa_driver_roboswitch_data {
-	void *ctx;
-	struct l2_packet_data *l2;
-	char ifname[IFNAMSIZ + 1];
-	u8 own_addr[ETH_ALEN];
-	struct ifreq ifr;
-	int fd, is_5350;
-	u16 ports;
-};
-
-
-/* Copied from the kernel-only part of mii.h. */
-static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
-{
-	return (struct mii_ioctl_data *) &rq->ifr_ifru;
-}
-
-
-/*
- * RoboSwitch uses 16-bit Big Endian addresses.
- * The ordering of the words is reversed in the MII registers.
- */
-static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
-{
-	int i;
-	for (i = 0; i < ETH_ALEN; i += 2)
-		be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
-}
-
-
-static u16 wpa_driver_roboswitch_mdio_read(
-	struct wpa_driver_roboswitch_data *drv, u8 reg)
-{
-	struct mii_ioctl_data *mii = if_mii(&drv->ifr);
-
-	mii->phy_id = ROBO_PHY_ADDR;
-	mii->reg_num = reg;
-
-	if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
-		perror("ioctl[SIOCGMIIREG]");
-		return 0x00;
-	}
-	return mii->val_out;
-}
-
-
-static void wpa_driver_roboswitch_mdio_write(
-	struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
-{
-	struct mii_ioctl_data *mii = if_mii(&drv->ifr);
-
-	mii->phy_id = ROBO_PHY_ADDR;
-	mii->reg_num = reg;
-	mii->val_in = val;
-
-	if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
-		perror("ioctl[SIOCSMIIREG");
-	}
-}
-
-
-static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
-				     u8 page, u8 reg, u8 op)
-{
-	int i;
-
-	/* set page number */
-	wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
-					 (page << 8) | ROBO_MII_PAGE_ENABLE);
-	/* set register address */
-	wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
-
-	/* check if operation completed */
-	for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
-		if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
-		    == 0)
-			return 0;
-	}
-	/* timeout */
-	return -1;
-}
-
-
-static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
-				      u8 page, u8 reg, u16 *val, int len)
-{
-	int i;
-
-	if (len > ROBO_MII_DATA_MAX ||
-	    wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
-		return -1;
-
-	for (i = 0; i < len; ++i) {
-		val[i] = wpa_driver_roboswitch_mdio_read(
-			drv, ROBO_MII_DATA_OFFSET + i);
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
-				       u8 page, u8 reg, u16 *val, int len)
-{
-	int i;
-
-	if (len > ROBO_MII_DATA_MAX) return -1;
-	for (i = 0; i < len; ++i) {
-		wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
-						 val[i]);
-	}
-	return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
-}
-
-
-static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
-					  const u8 *buf, size_t len)
-{
-	struct wpa_driver_roboswitch_data *drv = priv;
-
-	if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
-	    os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0)
-		drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14);
-}
-
-
-static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
-{
-	ssid[0] = 0;
-	return 0;
-}
-
-
-static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
-{
-	/* Report PAE group address as the "BSSID" for wired connection. */
-	os_memcpy(bssid, pae_group_addr, ETH_ALEN);
-	return 0;
-}
-
-
-static int wpa_driver_roboswitch_get_capa(void *priv,
-					  struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-	capa->flags = WPA_DRIVER_FLAGS_WIRED;
-	return 0;
-}
-
-
-static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
-{
-	struct wpa_driver_roboswitch_data *drv = priv;
-	char *sep;
-
-	if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
-		sep = drv->ifname + os_strlen(drv->ifname);
-		*sep = '.';
-		drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
-					 wpa_driver_roboswitch_receive, drv,
-					 1);
-		if (drv->l2 == NULL) {
-			wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
-				   __func__, drv->ifname);
-			return -1;
-		}
-		*sep = '\0';
-		l2_packet_get_own_addr(drv->l2, drv->own_addr);
-	} else {
-		wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
-		drv->l2 = NULL;
-	}
-	return 0;
-}
-
-
-static const char * wpa_driver_roboswitch_get_ifname(void *priv)
-{
-	struct wpa_driver_roboswitch_data *drv = priv;
-	return drv->ifname;
-}
-
-
-static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
-				      u16 ports, const u8 *addr)
-{
-	u16 read1[3], read2[3], addr_be16[3];
-
-	wpa_driver_roboswitch_addr_be16(addr, addr_be16);
-
-	if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-				       ROBO_ARLCTRL_CONF, read1, 1) < 0)
-		return -1;
-	if (!(read1[0] & (1 << 4))) {
-		/* multiport addresses are not yet enabled */
-		read1[0] |= 1 << 4;
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_VEC_1, &ports, 1);
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_VEC_2, &ports, 1);
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_CONF, read1, 1);
-	} else {
-		/* if both multiport addresses are the same we can add */
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_ADDR_1, read1, 3);
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_ADDR_2, read2, 3);
-		if (os_memcmp(read1, read2, 6) != 0)
-			return -1;
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_VEC_1, read1, 1);
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_VEC_2, read2, 1);
-		if (read1[0] != read2[0])
-			return -1;
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
-		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-					    ROBO_ARLCTRL_VEC_1, &ports, 1);
-	}
-	return 0;
-}
-
-
-static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
-				       u16 ports, const u8 *addr)
-{
-	u16 _read, addr_be16[3], addr_read[3], ports_read;
-
-	wpa_driver_roboswitch_addr_be16(addr, addr_be16);
-
-	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
-				   &_read, 1);
-	/* If ARL control is disabled, there is nothing to leave. */
-	if (!(_read & (1 << 4))) return -1;
-
-	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-				   ROBO_ARLCTRL_ADDR_1, addr_read, 3);
-	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
-				   &ports_read, 1);
-	/* check if we occupy multiport address 1 */
-	if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_ADDR_2, addr_read, 3);
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_VEC_2, &ports_read, 1);
-		/* and multiport address 2 */
-		if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
-		    ports_read == ports) {
-			_read &= ~(1 << 4);
-			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-						    ROBO_ARLCTRL_CONF, &_read,
-						    1);
-		} else {
-			wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-						   ROBO_ARLCTRL_ADDR_1,
-						   addr_read, 3);
-			wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-						   ROBO_ARLCTRL_VEC_1,
-						   &ports_read, 1);
-			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-						    ROBO_ARLCTRL_ADDR_2,
-						    addr_read, 3);
-			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-						    ROBO_ARLCTRL_VEC_2,
-						    &ports_read, 1);
-		}
-	} else {
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_ADDR_2, addr_read, 3);
-		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
-					   ROBO_ARLCTRL_VEC_2, &ports_read, 1);
-		/* or multiport address 2 */
-		if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
-		    ports_read == ports) {
-			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-						    ROBO_ARLCTRL_ADDR_1,
-						    addr_read, 3);
-			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
-						    ROBO_ARLCTRL_VEC_1,
-						    &ports_read, 1);
-		} else return -1;
-	}
-	return 0;
-}
-
-
-static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_roboswitch_data *drv;
-	char *sep;
-	u16 vlan = 0, _read[2];
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL) return NULL;
-	drv->ctx = ctx;
-	drv->own_addr[0] = '\0';
-
-	/* copy ifname and take a pointer to the second to last character */
-	sep = drv->ifname +
-	      os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
-	/* find the '.' seperating <interface> and <vlan> */
-	while (sep > drv->ifname && *sep != '.') sep--;
-	if (sep <= drv->ifname) {
-		wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
-			   "interface name %s", __func__, drv->ifname);
-		os_free(drv);
-		return NULL;
-	}
-	*sep = '\0';
-	while (*++sep) {
-		if (*sep < '0' || *sep > '9') {
-			wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
-				   "in interface name %s", __func__, ifname);
-			os_free(drv);
-			return NULL;
-		}
-		vlan *= 10;
-		vlan += *sep - '0';
-		if (vlan > ROBO_VLAN_MAX) {
-			wpa_printf(MSG_INFO, "%s: VLAN out of range in "
-				   "interface name %s", __func__, ifname);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->fd < 0) {
-		wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
-		os_free(drv);
-		return NULL;
-	}
-
-	os_memset(&drv->ifr, 0, sizeof(drv->ifr));
-	os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
-	if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
-		perror("ioctl[SIOCGMIIPHY]");
-		os_free(drv);
-		return NULL;
-	}
-	if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
-		wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
-			   "RoboSwitch?)", __func__);
-		os_free(drv);
-		return NULL;
-	}
-
-	/* set and read back to see if the register can be used */
-	_read[0] = ROBO_VLAN_MAX;
-	wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
-				    _read, 1);
-	wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
-				   _read + 1, 1);
-	drv->is_5350 = _read[0] == _read[1];
-
-	/* set the read bit */
-	vlan |= 1 << 13;
-	wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
-				    drv->is_5350 ? ROBO_VLAN_ACCESS_5350
-						 : ROBO_VLAN_ACCESS,
-				    &vlan, 1);
-	wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
-				   drv->is_5350 ? 2 : 1);
-	if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
-		wpa_printf(MSG_INFO, "%s: Could not get port information for "
-				     "VLAN %d", __func__, vlan & ~(1 << 13));
-		os_free(drv);
-		return NULL;
-	}
-	drv->ports = _read[0] & 0x001F;
-	/* add the MII port */
-	drv->ports |= 1 << 8;
-	if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
-		wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
-		os_free(drv);
-		return NULL;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
-			   "RoboSwitch ARL", __func__);
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_roboswitch_deinit(void *priv)
-{
-	struct wpa_driver_roboswitch_data *drv = priv;
-
-	if (drv->l2) {
-		l2_packet_deinit(drv->l2);
-		drv->l2 = NULL;
-	}
-	if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
-			   __func__);
-	}
-
-	close(drv->fd);
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
-	.name = "roboswitch",
-	.desc = "wpa_supplicant roboswitch driver",
-	.get_ssid = wpa_driver_roboswitch_get_ssid,
-	.get_bssid = wpa_driver_roboswitch_get_bssid,
-	.get_capa = wpa_driver_roboswitch_get_capa,
-	.init = wpa_driver_roboswitch_init,
-	.deinit = wpa_driver_roboswitch_deinit,
-	.set_param = wpa_driver_roboswitch_set_param,
-	.get_ifname = wpa_driver_roboswitch_get_ifname,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_roboswitch.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_roboswitch.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_roboswitch.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_roboswitch.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,474 @@
+/*
+ * WPA Supplicant - roboswitch driver interface
+ * Copyright (c) 2008-2009 Jouke Witteveen
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_ether.h>
+#include <linux/mii.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+
+#define ROBO_PHY_ADDR		0x1e	/* RoboSwitch PHY address */
+
+/* MII access registers */
+#define ROBO_MII_PAGE		0x10	/* MII page register */
+#define ROBO_MII_ADDR		0x11	/* MII address register */
+#define ROBO_MII_DATA_OFFSET	0x18	/* Start of MII data registers */
+
+#define ROBO_MII_PAGE_ENABLE	0x01	/* MII page op code */
+#define ROBO_MII_ADDR_WRITE	0x01	/* MII address write op code */
+#define ROBO_MII_ADDR_READ	0x02	/* MII address read op code */
+#define ROBO_MII_DATA_MAX	   4	/* Consecutive MII data registers */
+#define ROBO_MII_RETRY_MAX	  10	/* Read attempts before giving up */
+
+/* Page numbers */
+#define ROBO_ARLCTRL_PAGE	0x04	/* ARL control page */
+#define ROBO_VLAN_PAGE		0x34	/* VLAN page */
+
+/* ARL control page registers */
+#define ROBO_ARLCTRL_CONF	0x00	/* ARL configuration register */
+#define ROBO_ARLCTRL_ADDR_1	0x10	/* Multiport address 1 */
+#define ROBO_ARLCTRL_VEC_1	0x16	/* Multiport vector 1 */
+#define ROBO_ARLCTRL_ADDR_2	0x20	/* Multiport address 2 */
+#define ROBO_ARLCTRL_VEC_2	0x26	/* Multiport vector 2 */
+
+/* VLAN page registers */
+#define ROBO_VLAN_ACCESS	0x08	/* VLAN table access register */
+#define ROBO_VLAN_ACCESS_5350	0x06	/* VLAN table access register (5350) */
+#define ROBO_VLAN_READ		0x0c	/* VLAN read register */
+#define ROBO_VLAN_MAX		0xff	/* Maximum number of VLANs */
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_roboswitch_data {
+	void *ctx;
+	struct l2_packet_data *l2;
+	char ifname[IFNAMSIZ + 1];
+	u8 own_addr[ETH_ALEN];
+	struct ifreq ifr;
+	int fd, is_5350;
+	u16 ports;
+};
+
+
+/* Copied from the kernel-only part of mii.h. */
+static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
+{
+	return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+
+
+/*
+ * RoboSwitch uses 16-bit Big Endian addresses.
+ * The ordering of the words is reversed in the MII registers.
+ */
+static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
+{
+	int i;
+	for (i = 0; i < ETH_ALEN; i += 2)
+		be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
+}
+
+
+static u16 wpa_driver_roboswitch_mdio_read(
+	struct wpa_driver_roboswitch_data *drv, u8 reg)
+{
+	struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+	mii->phy_id = ROBO_PHY_ADDR;
+	mii->reg_num = reg;
+
+	if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
+		perror("ioctl[SIOCGMIIREG]");
+		return 0x00;
+	}
+	return mii->val_out;
+}
+
+
+static void wpa_driver_roboswitch_mdio_write(
+	struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
+{
+	struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+	mii->phy_id = ROBO_PHY_ADDR;
+	mii->reg_num = reg;
+	mii->val_in = val;
+
+	if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
+		perror("ioctl[SIOCSMIIREG");
+	}
+}
+
+
+static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
+				     u8 page, u8 reg, u8 op)
+{
+	int i;
+
+	/* set page number */
+	wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
+					 (page << 8) | ROBO_MII_PAGE_ENABLE);
+	/* set register address */
+	wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
+
+	/* check if operation completed */
+	for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
+		if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
+		    == 0)
+			return 0;
+	}
+	/* timeout */
+	return -1;
+}
+
+
+static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
+				      u8 page, u8 reg, u16 *val, int len)
+{
+	int i;
+
+	if (len > ROBO_MII_DATA_MAX ||
+	    wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
+		return -1;
+
+	for (i = 0; i < len; ++i) {
+		val[i] = wpa_driver_roboswitch_mdio_read(
+			drv, ROBO_MII_DATA_OFFSET + i);
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
+				       u8 page, u8 reg, u16 *val, int len)
+{
+	int i;
+
+	if (len > ROBO_MII_DATA_MAX) return -1;
+	for (i = 0; i < len; ++i) {
+		wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
+						 val[i]);
+	}
+	return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
+}
+
+
+static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
+					  const u8 *buf, size_t len)
+{
+	struct wpa_driver_roboswitch_data *drv = priv;
+
+	if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
+	    os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0)
+		drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14);
+}
+
+
+static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
+{
+	ssid[0] = 0;
+	return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
+{
+	/* Report PAE group address as the "BSSID" for wired connection. */
+	os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_capa(void *priv,
+					  struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+	capa->flags = WPA_DRIVER_FLAGS_WIRED;
+	return 0;
+}
+
+
+static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
+{
+	struct wpa_driver_roboswitch_data *drv = priv;
+	char *sep;
+
+	if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
+		sep = drv->ifname + os_strlen(drv->ifname);
+		*sep = '.';
+		drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
+					 wpa_driver_roboswitch_receive, drv,
+					 1);
+		if (drv->l2 == NULL) {
+			wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
+				   __func__, drv->ifname);
+			return -1;
+		}
+		*sep = '\0';
+		l2_packet_get_own_addr(drv->l2, drv->own_addr);
+	} else {
+		wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
+		drv->l2 = NULL;
+	}
+	return 0;
+}
+
+
+static const char * wpa_driver_roboswitch_get_ifname(void *priv)
+{
+	struct wpa_driver_roboswitch_data *drv = priv;
+	return drv->ifname;
+}
+
+
+static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
+				      u16 ports, const u8 *addr)
+{
+	u16 read1[3], read2[3], addr_be16[3];
+
+	wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+	if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+				       ROBO_ARLCTRL_CONF, read1, 1) < 0)
+		return -1;
+	if (!(read1[0] & (1 << 4))) {
+		/* multiport addresses are not yet enabled */
+		read1[0] |= 1 << 4;
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_VEC_1, &ports, 1);
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_VEC_2, &ports, 1);
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_CONF, read1, 1);
+	} else {
+		/* if both multiport addresses are the same we can add */
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_ADDR_1, read1, 3);
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_ADDR_2, read2, 3);
+		if (os_memcmp(read1, read2, 6) != 0)
+			return -1;
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_VEC_1, read1, 1);
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_VEC_2, read2, 1);
+		if (read1[0] != read2[0])
+			return -1;
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+		wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+					    ROBO_ARLCTRL_VEC_1, &ports, 1);
+	}
+	return 0;
+}
+
+
+static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
+				       u16 ports, const u8 *addr)
+{
+	u16 _read, addr_be16[3], addr_read[3], ports_read;
+
+	wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
+				   &_read, 1);
+	/* If ARL control is disabled, there is nothing to leave. */
+	if (!(_read & (1 << 4))) return -1;
+
+	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+				   ROBO_ARLCTRL_ADDR_1, addr_read, 3);
+	wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
+				   &ports_read, 1);
+	/* check if we occupy multiport address 1 */
+	if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+		/* and multiport address 2 */
+		if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+		    ports_read == ports) {
+			_read &= ~(1 << 4);
+			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+						    ROBO_ARLCTRL_CONF, &_read,
+						    1);
+		} else {
+			wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+						   ROBO_ARLCTRL_ADDR_1,
+						   addr_read, 3);
+			wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+						   ROBO_ARLCTRL_VEC_1,
+						   &ports_read, 1);
+			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+						    ROBO_ARLCTRL_ADDR_2,
+						    addr_read, 3);
+			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+						    ROBO_ARLCTRL_VEC_2,
+						    &ports_read, 1);
+		}
+	} else {
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+		wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+					   ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+		/* or multiport address 2 */
+		if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+		    ports_read == ports) {
+			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+						    ROBO_ARLCTRL_ADDR_1,
+						    addr_read, 3);
+			wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+						    ROBO_ARLCTRL_VEC_1,
+						    &ports_read, 1);
+		} else return -1;
+	}
+	return 0;
+}
+
+
+static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_roboswitch_data *drv;
+	char *sep;
+	u16 vlan = 0, _read[2];
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL) return NULL;
+	drv->ctx = ctx;
+	drv->own_addr[0] = '\0';
+
+	/* copy ifname and take a pointer to the second to last character */
+	sep = drv->ifname +
+	      os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
+	/* find the '.' separating <interface> and <vlan> */
+	while (sep > drv->ifname && *sep != '.') sep--;
+	if (sep <= drv->ifname) {
+		wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
+			   "interface name %s", __func__, drv->ifname);
+		os_free(drv);
+		return NULL;
+	}
+	*sep = '\0';
+	while (*++sep) {
+		if (*sep < '0' || *sep > '9') {
+			wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
+				   "in interface name %s", __func__, ifname);
+			os_free(drv);
+			return NULL;
+		}
+		vlan *= 10;
+		vlan += *sep - '0';
+		if (vlan > ROBO_VLAN_MAX) {
+			wpa_printf(MSG_INFO, "%s: VLAN out of range in "
+				   "interface name %s", __func__, ifname);
+			os_free(drv);
+			return NULL;
+		}
+	}
+
+	drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->fd < 0) {
+		wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
+		os_free(drv);
+		return NULL;
+	}
+
+	os_memset(&drv->ifr, 0, sizeof(drv->ifr));
+	os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
+	if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
+		perror("ioctl[SIOCGMIIPHY]");
+		os_free(drv);
+		return NULL;
+	}
+	if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+		wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
+			   "RoboSwitch?)", __func__);
+		os_free(drv);
+		return NULL;
+	}
+
+	/* set and read back to see if the register can be used */
+	_read[0] = ROBO_VLAN_MAX;
+	wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+				    _read, 1);
+	wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+				   _read + 1, 1);
+	drv->is_5350 = _read[0] == _read[1];
+
+	/* set the read bit */
+	vlan |= 1 << 13;
+	wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+				    drv->is_5350 ? ROBO_VLAN_ACCESS_5350
+						 : ROBO_VLAN_ACCESS,
+				    &vlan, 1);
+	wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
+				   drv->is_5350 ? 2 : 1);
+	if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
+		wpa_printf(MSG_INFO, "%s: Could not get port information for "
+				     "VLAN %d", __func__, vlan & ~(1 << 13));
+		os_free(drv);
+		return NULL;
+	}
+	drv->ports = _read[0] & 0x001F;
+	/* add the MII port */
+	drv->ports |= 1 << 8;
+	if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
+		wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
+		os_free(drv);
+		return NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
+			   "RoboSwitch ARL", __func__);
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_roboswitch_deinit(void *priv)
+{
+	struct wpa_driver_roboswitch_data *drv = priv;
+
+	if (drv->l2) {
+		l2_packet_deinit(drv->l2);
+		drv->l2 = NULL;
+	}
+	if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
+			   __func__);
+	}
+
+	close(drv->fd);
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
+	.name = "roboswitch",
+	.desc = "wpa_supplicant roboswitch driver",
+	.get_ssid = wpa_driver_roboswitch_get_ssid,
+	.get_bssid = wpa_driver_roboswitch_get_bssid,
+	.get_capa = wpa_driver_roboswitch_get_capa,
+	.init = wpa_driver_roboswitch_init,
+	.deinit = wpa_driver_roboswitch_deinit,
+	.set_param = wpa_driver_roboswitch_set_param,
+	.get_ifname = wpa_driver_roboswitch_get_ifname,
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_test.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_test.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2753 +0,0 @@
-/*
- * Testing driver interface for a simulated network driver
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */
-#include "build_config.h"
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/un.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#define DRIVER_TEST_UNIX
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/list.h"
-#include "utils/trace.h"
-#include "common/ieee802_11_defs.h"
-#include "crypto/sha1.h"
-#include "l2_packet/l2_packet.h"
-#include "driver.h"
-
-
-struct test_client_socket {
-	struct test_client_socket *next;
-	u8 addr[ETH_ALEN];
-	struct sockaddr_un un;
-	socklen_t unlen;
-	struct test_driver_bss *bss;
-};
-
-struct test_driver_bss {
-	struct wpa_driver_test_data *drv;
-	struct dl_list list;
-	void *bss_ctx;
-	char ifname[IFNAMSIZ];
-	u8 bssid[ETH_ALEN];
-	u8 *ie;
-	size_t ielen;
-	u8 *wps_beacon_ie;
-	size_t wps_beacon_ie_len;
-	u8 *wps_probe_resp_ie;
-	size_t wps_probe_resp_ie_len;
-	u8 ssid[32];
-	size_t ssid_len;
-	int privacy;
-};
-
-struct wpa_driver_test_global {
-	int bss_add_used;
-	u8 req_addr[ETH_ALEN];
-};
-
-struct wpa_driver_test_data {
-	struct wpa_driver_test_global *global;
-	void *ctx;
-	WPA_TRACE_REF(ctx);
-	u8 own_addr[ETH_ALEN];
-	int test_socket;
-#ifdef DRIVER_TEST_UNIX
-	struct sockaddr_un hostapd_addr;
-#endif /* DRIVER_TEST_UNIX */
-	int hostapd_addr_set;
-	struct sockaddr_in hostapd_addr_udp;
-	int hostapd_addr_udp_set;
-	char *own_socket_path;
-	char *test_dir;
-#define MAX_SCAN_RESULTS 30
-	struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
-	size_t num_scanres;
-	int use_associnfo;
-	u8 assoc_wpa_ie[80];
-	size_t assoc_wpa_ie_len;
-	int use_mlme;
-	int associated;
-	u8 *probe_req_ie;
-	size_t probe_req_ie_len;
-	u8 probe_req_ssid[32];
-	size_t probe_req_ssid_len;
-	int ibss;
-	int ap;
-
-	struct test_client_socket *cli;
-	struct dl_list bss;
-	int udp_port;
-
-	int alloc_iface_idx;
-
-	int probe_req_report;
-	unsigned int remain_on_channel_freq;
-	unsigned int remain_on_channel_duration;
-
-	int current_freq;
-};
-
-
-static void wpa_driver_test_deinit(void *priv);
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
-				  const char *dir, int ap);
-static void wpa_driver_test_close_test_socket(
-	struct wpa_driver_test_data *drv);
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
-
-
-static void test_driver_free_bss(struct test_driver_bss *bss)
-{
-	os_free(bss->ie);
-	os_free(bss->wps_beacon_ie);
-	os_free(bss->wps_probe_resp_ie);
-	os_free(bss);
-}
-
-
-static void test_driver_free_bsses(struct wpa_driver_test_data *drv)
-{
-	struct test_driver_bss *bss, *tmp;
-
-	dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss,
-			      list) {
-		dl_list_del(&bss->list);
-		test_driver_free_bss(bss);
-	}
-}
-
-
-static struct test_client_socket *
-test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
-		    socklen_t fromlen)
-{
-	struct test_client_socket *cli = drv->cli;
-
-	while (cli) {
-		if (cli->unlen == fromlen &&
-		    strncmp(cli->un.sun_path, from->sun_path,
-			    fromlen - sizeof(cli->un.sun_family)) == 0)
-			return cli;
-		cli = cli->next;
-	}
-
-	return NULL;
-}
-
-
-static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
-				  size_t data_len, int encrypt,
-				  const u8 *own_addr)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-	struct msghdr msg;
-	struct iovec io[3];
-	struct l2_ethhdr eth;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli) {
-		wpa_printf(MSG_DEBUG, "%s: no destination client entry",
-			   __func__);
-		return -1;
-	}
-
-	memcpy(eth.h_dest, addr, ETH_ALEN);
-	memcpy(eth.h_source, own_addr, ETH_ALEN);
-	eth.h_proto = host_to_be16(ETH_P_EAPOL);
-
-	io[0].iov_base = "EAPOL ";
-	io[0].iov_len = 6;
-	io[1].iov_base = ð
-	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = (u8 *) data;
-	io[2].iov_len = data_len;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
-	msg.msg_name = &cli->un;
-	msg.msg_namelen = cli->unlen;
-	return sendmsg(drv->test_socket, &msg, 0);
-}
-
-
-static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
-				  u16 proto, const u8 *data, size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct msghdr msg;
-	struct iovec io[3];
-	struct l2_ethhdr eth;
-	char desttxt[30];
-	struct sockaddr_un addr;
-	struct dirent *dent;
-	DIR *dir;
-	int ret = 0, broadcast = 0, count = 0;
-
-	if (drv->test_socket < 0 || drv->test_dir == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
-			   "test_dir=%p)",
-			   __func__, drv->test_socket, drv->test_dir);
-		return -1;
-	}
-
-	broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
-	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
-
-	memcpy(eth.h_dest, dst, ETH_ALEN);
-	memcpy(eth.h_source, src, ETH_ALEN);
-	eth.h_proto = host_to_be16(proto);
-
-	io[0].iov_base = "ETHER ";
-	io[0].iov_len = 6;
-	io[1].iov_base = ð
-	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = (u8 *) data;
-	io[2].iov_len = data_len;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
-
-	dir = opendir(drv->test_dir);
-	if (dir == NULL) {
-		perror("test_driver: opendir");
-		return -1;
-	}
-	while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-		/* Skip the file if it is not a socket. Also accept
-		 * DT_UNKNOWN (0) in case the C library or underlying file
-		 * system does not support d_type. */
-		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
-			continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-		if (strcmp(dent->d_name, ".") == 0 ||
-		    strcmp(dent->d_name, "..") == 0)
-			continue;
-
-		memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			 drv->test_dir, dent->d_name);
-
-		if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
-			continue;
-		if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
-			   __func__, dent->d_name);
-
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-		ret = sendmsg(drv->test_socket, &msg, 0);
-		if (ret < 0)
-			perror("driver_test: sendmsg");
-		count++;
-	}
-	closedir(dir);
-
-	if (!broadcast && count == 0) {
-		wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
-			   __func__, MAC2STR(dst));
-		return -1;
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
-				     size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct msghdr msg;
-	struct iovec io[2];
-	const u8 *dest;
-	struct sockaddr_un addr;
-	struct dirent *dent;
-	DIR *dir;
-	int broadcast;
-	int ret = 0;
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	char cmd[50];
-	int freq;
-#ifdef HOSTAPD
-	char desttxt[30];
-#endif /* HOSTAPD */
-	union wpa_event_data event;
-
-	wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
-	if (drv->test_socket < 0 || data_len < 10) {
-		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
-			   " test_dir=%p)",
-			   __func__, drv->test_socket,
-			   (unsigned long) data_len,
-			   drv->test_dir);
-		return -1;
-	}
-
-	dest = data + 4;
-	broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
-
-#ifdef HOSTAPD
-	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
-#endif /* HOSTAPD */
-
-	if (drv->remain_on_channel_freq)
-		freq = drv->remain_on_channel_freq;
-	else
-		freq = drv->current_freq;
-	wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
-		   dbss->ifname, freq);
-	os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
-	io[0].iov_base = cmd;
-	io[0].iov_len = os_strlen(cmd);
-	io[1].iov_base = (void *) data;
-	io[1].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
-
-#ifdef HOSTAPD
-	if (drv->test_dir == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__);
-		return -1;
-	}
-
-	dir = opendir(drv->test_dir);
-	if (dir == NULL) {
-		perror("test_driver: opendir");
-		return -1;
-	}
-	while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-		/* Skip the file if it is not a socket. Also accept
-		 * DT_UNKNOWN (0) in case the C library or underlying file
-		 * system does not support d_type. */
-		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
-			continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-		if (os_strcmp(dent->d_name, ".") == 0 ||
-		    os_strcmp(dent->d_name, "..") == 0)
-			continue;
-
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			    drv->test_dir, dent->d_name);
-
-		if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0)
-			continue;
-		if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
-			   __func__, dent->d_name);
-
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-		ret = sendmsg(drv->test_socket, &msg, 0);
-		if (ret < 0)
-			perror("driver_test: sendmsg(test_socket)");
-	}
-	closedir(dir);
-#else /* HOSTAPD */
-
-	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
-	    drv->test_dir == NULL) {
-		if (drv->hostapd_addr_udp_set) {
-			msg.msg_name = &drv->hostapd_addr_udp;
-			msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
-		} else {
-#ifdef DRIVER_TEST_UNIX
-			msg.msg_name = &drv->hostapd_addr;
-			msg.msg_namelen = sizeof(drv->hostapd_addr);
-#endif /* DRIVER_TEST_UNIX */
-		}
-	} else if (broadcast) {
-		dir = opendir(drv->test_dir);
-		if (dir == NULL)
-			return -1;
-		while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-			/* Skip the file if it is not a socket.
-			 * Also accept DT_UNKNOWN (0) in case
-			 * the C library or underlying file
-			 * system does not support d_type. */
-			if (dent->d_type != DT_SOCK &&
-			    dent->d_type != DT_UNKNOWN)
-				continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-			if (os_strcmp(dent->d_name, ".") == 0 ||
-			    os_strcmp(dent->d_name, "..") == 0)
-				continue;
-			wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
-				   __func__, dent->d_name);
-			os_memset(&addr, 0, sizeof(addr));
-			addr.sun_family = AF_UNIX;
-			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-				    "%s/%s", drv->test_dir, dent->d_name);
-
-			msg.msg_name = &addr;
-			msg.msg_namelen = sizeof(addr);
-
-			ret = sendmsg(drv->test_socket, &msg, 0);
-			if (ret < 0)
-				perror("driver_test: sendmsg(test_socket)");
-		}
-		closedir(dir);
-		return ret;
-	} else {
-		struct stat st;
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-			    "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
-		if (stat(addr.sun_path, &st) < 0) {
-			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-				    "%s/STA-" MACSTR,
-				    drv->test_dir, MAC2STR(dest));
-		}
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-	}
-
-	if (sendmsg(drv->test_socket, &msg, 0) < 0) {
-		perror("sendmsg(test_socket)");
-		return -1;
-	}
-#endif /* HOSTAPD */
-
-	hdr = (struct ieee80211_hdr *) data;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = data;
-	event.tx_status.data_len = data_len;
-	event.tx_status.ack = ret >= 0;
-	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-
-	return ret;
-}
-
-
-static void test_driver_scan(struct wpa_driver_test_data *drv,
-			     struct sockaddr_un *from, socklen_t fromlen,
-			     char *data)
-{
-	char buf[512], *pos, *end;
-	int ret;
-	struct test_driver_bss *bss;
-	u8 sa[ETH_ALEN];
-	u8 ie[512];
-	size_t ielen;
-	union wpa_event_data event;
-
-	/* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
-
-	wpa_printf(MSG_DEBUG, "test_driver: SCAN");
-
-	if (*data) {
-		if (*data != ' ' ||
-		    hwaddr_aton(data + 1, sa)) {
-			wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
-				   "command format");
-			return;
-		}
-
-		data += 18;
-		while (*data == ' ')
-			data++;
-		ielen = os_strlen(data) / 2;
-		if (ielen > sizeof(ie))
-			ielen = sizeof(ie);
-		if (hexstr2bin(data, ie, ielen) < 0)
-			ielen = 0;
-
-		wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
-			   MAC2STR(sa));
-		wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
-
-		os_memset(&event, 0, sizeof(event));
-		event.rx_probe_req.sa = sa;
-		event.rx_probe_req.ie = ie;
-		event.rx_probe_req.ie_len = ielen;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
-	}
-
-	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
-		pos = buf;
-		end = buf + sizeof(buf);
-
-		/* reply: SCANRESP BSSID SSID IEs */
-		ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-			       MAC2STR(bss->bssid));
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos,
-					bss->ssid, bss->ssid_len);
-		ret = snprintf(pos, end - pos, " ");
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
-		pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
-					bss->wps_probe_resp_ie_len);
-
-		if (bss->privacy) {
-			ret = snprintf(pos, end - pos, " PRIVACY");
-			if (ret < 0 || ret >= end - pos)
-				return;
-			pos += ret;
-		}
-
-		sendto(drv->test_socket, buf, pos - buf, 0,
-		       (struct sockaddr *) from, fromlen);
-	}
-}
-
-
-static void test_driver_assoc(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      char *data)
-{
-	struct test_client_socket *cli;
-	u8 ie[256], ssid[32];
-	size_t ielen, ssid_len = 0;
-	char *pos, *pos2, cmd[50];
-	struct test_driver_bss *bss, *tmp;
-
-	/* data: STA-addr SSID(hex) IEs(hex) */
-
-	cli = os_zalloc(sizeof(*cli));
-	if (cli == NULL)
-		return;
-
-	if (hwaddr_aton(data, cli->addr)) {
-		printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
-		       data);
-		os_free(cli);
-		return;
-	}
-	pos = data + 17;
-	while (*pos == ' ')
-		pos++;
-	pos2 = strchr(pos, ' ');
-	ielen = 0;
-	if (pos2) {
-		ssid_len = (pos2 - pos) / 2;
-		if (hexstr2bin(pos, ssid, ssid_len) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
-			os_free(cli);
-			return;
-		}
-		wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
-				  ssid, ssid_len);
-
-		pos = pos2 + 1;
-		ielen = strlen(pos) / 2;
-		if (ielen > sizeof(ie))
-			ielen = sizeof(ie);
-		if (hexstr2bin(pos, ie, ielen) < 0)
-			ielen = 0;
-	}
-
-	bss = NULL;
-	dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) {
-		if (tmp->ssid_len == ssid_len &&
-		    os_memcmp(tmp->ssid, ssid, ssid_len) == 0) {
-			bss = tmp;
-			break;
-		}
-	}
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
-			   "configured BSSes", __func__);
-		os_free(cli);
-		return;
-	}
-
-	cli->bss = bss;
-	memcpy(&cli->un, from, sizeof(cli->un));
-	cli->unlen = fromlen;
-	cli->next = drv->cli;
-	drv->cli = cli;
-	wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
-			  (const u8 *) cli->un.sun_path,
-			  cli->unlen - sizeof(cli->un.sun_family));
-
-	snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
-		 MAC2STR(bss->bssid));
-	sendto(drv->test_socket, cmd, strlen(cmd), 0,
-	       (struct sockaddr *) from, fromlen);
-
-	drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen);
-}
-
-
-static void test_driver_disassoc(struct wpa_driver_test_data *drv,
-				 struct sockaddr_un *from, socklen_t fromlen)
-{
-	struct test_client_socket *cli;
-
-	cli = test_driver_get_cli(drv, from, fromlen);
-	if (!cli)
-		return;
-
-	drv_event_disassoc(drv->ctx, cli->addr);
-}
-
-
-static void test_driver_eapol(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      u8 *data, size_t datalen)
-{
-#ifdef HOSTAPD
-	struct test_client_socket *cli;
-#endif /* HOSTAPD */
-	const u8 *src = NULL;
-
-	if (datalen > 14) {
-		/* Skip Ethernet header */
-		src = data + ETH_ALEN;
-		wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
-			   MACSTR " proto=%04x",
-			   MAC2STR(data), MAC2STR(src),
-			   WPA_GET_BE16(data + 2 * ETH_ALEN));
-		data += 14;
-		datalen -= 14;
-	}
-
-#ifdef HOSTAPD
-	cli = test_driver_get_cli(drv, from, fromlen);
-	if (cli) {
-		drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data,
-				   datalen);
-	} else {
-		wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
-			   "client");
-	}
-#else /* HOSTAPD */
-	if (src)
-		drv_event_eapol_rx(drv->ctx, src, data, datalen);
-#endif /* HOSTAPD */
-}
-
-
-static void test_driver_ether(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      u8 *data, size_t datalen)
-{
-	struct l2_ethhdr *eth;
-
-	if (datalen < sizeof(*eth))
-		return;
-
-	eth = (struct l2_ethhdr *) data;
-	wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
-		   MACSTR " proto=%04x",
-		   MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
-		   be_to_host16(eth->h_proto));
-
-#ifdef CONFIG_IEEE80211R
-	if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
-		union wpa_event_data ev;
-		os_memset(&ev, 0, sizeof(ev));
-		ev.ft_rrb_rx.src = eth->h_source;
-		ev.ft_rrb_rx.data = data + sizeof(*eth);
-		ev.ft_rrb_rx.data_len = datalen - sizeof(*eth);
-	}
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-static void test_driver_mlme(struct wpa_driver_test_data *drv,
-			     struct sockaddr_un *from, socklen_t fromlen,
-			     u8 *data, size_t datalen)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-	int freq = 0, own_freq;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
-		size_t pos;
-		for (pos = 5; pos < datalen; pos++) {
-			if (data[pos] == ' ')
-				break;
-		}
-		if (pos < datalen) {
-			freq = atoi((const char *) &data[5]);
-			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
-				   "freq %d MHz", bss->ifname, freq);
-			pos++;
-			data += pos;
-			datalen -= pos;
-		}
-	}
-
-	if (drv->remain_on_channel_freq)
-		own_freq = drv->remain_on_channel_freq;
-	else
-		own_freq = drv->current_freq;
-
-	if (freq && own_freq && freq != own_freq) {
-		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
-			   "another frequency %d MHz (own %d MHz)",
-			   bss->ifname, freq, own_freq);
-		return;
-	}
-
-	hdr = (struct ieee80211_hdr *) data;
-
-	if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
-		struct test_client_socket *cli;
-		cli = os_zalloc(sizeof(*cli));
-		if (cli == NULL)
-			return;
-		wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
-			   MAC2STR(hdr->addr2));
-		memcpy(cli->addr, hdr->addr2, ETH_ALEN);
-		memcpy(&cli->un, from, sizeof(cli->un));
-		cli->unlen = fromlen;
-		cli->next = drv->cli;
-		drv->cli = cli;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
-		    data, datalen);
-	fc = le_to_host16(hdr->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
-		wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
-			   __func__);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_mgmt.frame = data;
-	event.rx_mgmt.frame_len = datalen;
-	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	char buf[2000];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(test_socket)");
-		return;
-	}
-	buf[res] = '\0';
-
-	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
-	if (strncmp(buf, "SCAN", 4) == 0) {
-		test_driver_scan(drv, &from, fromlen, buf + 4);
-	} else if (strncmp(buf, "ASSOC ", 6) == 0) {
-		test_driver_assoc(drv, &from, fromlen, buf + 6);
-	} else if (strcmp(buf, "DISASSOC") == 0) {
-		test_driver_disassoc(drv, &from, fromlen);
-	} else if (strncmp(buf, "EAPOL ", 6) == 0) {
-		test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
-				  res - 6);
-	} else if (strncmp(buf, "ETHER ", 6) == 0) {
-		test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
-				  res - 6);
-	} else if (strncmp(buf, "MLME ", 5) == 0) {
-		test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
-	} else {
-		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
-				  (u8 *) buf, res);
-	}
-}
-
-
-static int test_driver_set_generic_elem(void *priv,
-					const u8 *elem, size_t elem_len)
-{
-	struct test_driver_bss *bss = priv;
-
-	os_free(bss->ie);
-
-	if (elem == NULL) {
-		bss->ie = NULL;
-		bss->ielen = 0;
-		return 0;
-	}
-
-	bss->ie = os_malloc(elem_len);
-	if (bss->ie == NULL) {
-		bss->ielen = 0;
-		return -1;
-	}
-
-	memcpy(bss->ie, elem, elem_len);
-	bss->ielen = elem_len;
-	return 0;
-}
-
-
-static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-				     const struct wpabuf *proberesp)
-{
-	struct test_driver_bss *bss = priv;
-
-	if (beacon == NULL)
-		wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
-	else
-		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
-				beacon);
-
-	os_free(bss->wps_beacon_ie);
-
-	if (beacon == NULL) {
-		bss->wps_beacon_ie = NULL;
-		bss->wps_beacon_ie_len = 0;
-	} else {
-		bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
-		if (bss->wps_beacon_ie == NULL) {
-			bss->wps_beacon_ie_len = 0;
-			return -1;
-		}
-
-		os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
-			  wpabuf_len(beacon));
-		bss->wps_beacon_ie_len = wpabuf_len(beacon);
-	}
-
-	if (proberesp == NULL)
-		wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
-			   "IE");
-	else
-		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
-				"IE", proberesp);
-
-	os_free(bss->wps_probe_resp_ie);
-
-	if (proberesp == NULL) {
-		bss->wps_probe_resp_ie = NULL;
-		bss->wps_probe_resp_ie_len = 0;
-	} else {
-		bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
-		if (bss->wps_probe_resp_ie == NULL) {
-			bss->wps_probe_resp_ie_len = 0;
-			return -1;
-		}
-
-		os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
-			  wpabuf_len(proberesp));
-		bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
-	}
-
-	return 0;
-}
-
-
-static int test_driver_sta_deauth(void *priv, const u8 *own_addr,
-				  const u8 *addr, int reason)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli)
-		return -1;
-
-	return sendto(drv->test_socket, "DEAUTH", 6, 0,
-		      (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_sta_disassoc(void *priv, const u8 *own_addr,
-				    const u8 *addr, int reason)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli)
-		return -1;
-
-	return sendto(drv->test_socket, "DISASSOC", 8, 0,
-		      (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
-			       void *bss_ctx, void **drv_priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_driver_bss *bss;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
-		   __func__, ifname, MAC2STR(bssid));
-
-	bss = os_zalloc(sizeof(*bss));
-	if (bss == NULL)
-		return -1;
-
-	bss->bss_ctx = bss_ctx;
-	bss->drv = drv;
-	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
-	os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
-	dl_list_add(&drv->bss, &bss->list);
-	if (drv->global) {
-		drv->global->bss_add_used = 1;
-		os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
-	}
-
-	if (drv_priv)
-		*drv_priv = bss;
-
-	return 0;
-}
-
-
-static int test_driver_bss_remove(void *priv, const char *ifname)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_driver_bss *bss;
-	struct test_client_socket *cli, *prev_c;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
-
-	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
-		if (strcmp(bss->ifname, ifname) != 0)
-			continue;
-
-		for (prev_c = NULL, cli = drv->cli; cli;
-		     prev_c = cli, cli = cli->next) {
-			if (cli->bss != bss)
-				continue;
-			if (prev_c)
-				prev_c->next = cli->next;
-			else
-				drv->cli = cli->next;
-			os_free(cli);
-			break;
-		}
-
-		dl_list_del(&bss->list);
-		test_driver_free_bss(bss);
-		return 0;
-	}
-
-	return -1;
-}
-
-
-static int test_driver_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)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-
-	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)",
-		   __func__, type, ifname, bss_ctx);
-	if (addr)
-		os_memcpy(if_addr, addr, ETH_ALEN);
-	else {
-		drv->alloc_iface_idx++;
-		if_addr[0] = 0x02; /* locally administered */
-		sha1_prf(drv->own_addr, ETH_ALEN,
-			 "hostapd test addr generation",
-			 (const u8 *) &drv->alloc_iface_idx,
-			 sizeof(drv->alloc_iface_idx),
-			 if_addr + 1, ETH_ALEN - 1);
-	}
-	if (type == WPA_IF_AP_BSS)
-		return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
-					   drv_priv);
-	return 0;
-}
-
-
-static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
-				 const char *ifname)
-{
-	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
-	if (type == WPA_IF_AP_BSS)
-		return test_driver_bss_remove(priv, ifname);
-	return 0;
-}
-
-
-static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
-				      const u8 *mask)
-{
-	return 0;
-}
-
-
-static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct test_driver_bss *bss = priv;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
-	wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
-
-	if (len < 0 || (size_t) len > sizeof(bss->ssid))
-		return -1;
-
-	os_memcpy(bss->ssid, buf, len);
-	bss->ssid_len = len;
-
-	return 0;
-}
-
-
-static int test_driver_set_privacy(void *priv, int enabled)
-{
-	struct test_driver_bss *dbss = priv;
-
-	wpa_printf(MSG_DEBUG, "%s(enabled=%d)",  __func__, enabled);
-	dbss->privacy = enabled;
-
-	return 0;
-}
-
-
-static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
-				    const char *ifname, int vlan_id)
-{
-	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
-		   __func__, MAC2STR(addr), ifname, vlan_id);
-	return 0;
-}
-
-
-static int test_driver_sta_add(void *priv,
-			       struct hostapd_sta_add_params *params)
-{
-	struct test_driver_bss *bss = priv;
-	struct wpa_driver_test_data *drv = bss->drv;
-	struct test_client_socket *cli;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
-		   "capability=0x%x listen_interval=%d)",
-		   __func__, bss->ifname, MAC2STR(params->addr), params->aid,
-		   params->capability, params->listen_interval);
-	wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
-		    params->supp_rates, params->supp_rates_len);
-
-	cli = drv->cli;
-	while (cli) {
-		if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-	if (!cli) {
-		wpa_printf(MSG_DEBUG, "%s: no matching client entry",
-			   __func__);
-		return -1;
-	}
-
-	cli->bss = bss;
-
-	return 0;
-}
-
-
-static struct wpa_driver_test_data * test_alloc_data(void *ctx,
-						     const char *ifname)
-{
-	struct wpa_driver_test_data *drv;
-	struct test_driver_bss *bss;
-
-	drv = os_zalloc(sizeof(struct wpa_driver_test_data));
-	if (drv == NULL) {
-		wpa_printf(MSG_ERROR, "Could not allocate memory for test "
-			   "driver data");
-		return NULL;
-	}
-
-	bss = os_zalloc(sizeof(struct test_driver_bss));
-	if (bss == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	wpa_trace_add_ref(drv, ctx, ctx);
-	dl_list_init(&drv->bss);
-	dl_list_add(&drv->bss, &bss->list);
-	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
-	bss->bss_ctx = ctx;
-	bss->drv = drv;
-
-	/* Generate a MAC address to help testing with multiple STAs */
-	drv->own_addr[0] = 0x02; /* locally administered */
-	sha1_prf((const u8 *) ifname, os_strlen(ifname),
-		 "test mac addr generation",
-		 NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
-
-	return drv;
-}
-
-
-static void * test_driver_init(struct hostapd_data *hapd,
-			       struct wpa_init_params *params)
-{
-	struct wpa_driver_test_data *drv;
-	struct sockaddr_un addr_un;
-	struct sockaddr_in addr_in;
-	struct sockaddr *addr;
-	socklen_t alen;
-	struct test_driver_bss *bss;
-
-	drv = test_alloc_data(hapd, params->ifname);
-	if (drv == NULL)
-		return NULL;
-	drv->ap = 1;
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	bss->bss_ctx = hapd;
-	os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
-	os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
-
-	if (params->test_socket) {
-		if (os_strlen(params->test_socket) >=
-		    sizeof(addr_un.sun_path)) {
-			printf("Too long test_socket path\n");
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-		if (strncmp(params->test_socket, "DIR:", 4) == 0) {
-			size_t len = strlen(params->test_socket) + 30;
-			drv->test_dir = os_strdup(params->test_socket + 4);
-			drv->own_socket_path = os_malloc(len);
-			if (drv->own_socket_path) {
-				snprintf(drv->own_socket_path, len,
-					 "%s/AP-" MACSTR,
-					 params->test_socket + 4,
-					 MAC2STR(params->own_addr));
-			}
-		} else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
-			drv->udp_port = atoi(params->test_socket + 4);
-		} else {
-			drv->own_socket_path = os_strdup(params->test_socket);
-		}
-		if (drv->own_socket_path == NULL && drv->udp_port == 0) {
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-
-		drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
-					  SOCK_DGRAM, 0);
-		if (drv->test_socket < 0) {
-			perror("socket");
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-
-		if (drv->udp_port) {
-			os_memset(&addr_in, 0, sizeof(addr_in));
-			addr_in.sin_family = AF_INET;
-			addr_in.sin_port = htons(drv->udp_port);
-			addr = (struct sockaddr *) &addr_in;
-			alen = sizeof(addr_in);
-		} else {
-			os_memset(&addr_un, 0, sizeof(addr_un));
-			addr_un.sun_family = AF_UNIX;
-			os_strlcpy(addr_un.sun_path, drv->own_socket_path,
-				   sizeof(addr_un.sun_path));
-			addr = (struct sockaddr *) &addr_un;
-			alen = sizeof(addr_un);
-		}
-		if (bind(drv->test_socket, addr, alen) < 0) {
-			perror("bind(PF_UNIX)");
-			close(drv->test_socket);
-			if (drv->own_socket_path)
-				unlink(drv->own_socket_path);
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-		eloop_register_read_sock(drv->test_socket,
-					 test_driver_receive_unix, drv, NULL);
-	} else
-		drv->test_socket = -1;
-
-	return bss;
-}
-
-
-static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->associated && drv->hostapd_addr_set) {
-		struct stat st;
-		if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
-				   __func__, strerror(errno));
-			drv->associated = 0;
-			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-		}
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-}
-
-
-static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-#ifdef DRIVER_TEST_UNIX
-static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
-				const char *path)
-{
-	struct dirent *dent;
-	DIR *dir;
-	struct sockaddr_un addr;
-	char cmd[512], *pos, *end;
-	int ret;
-
-	dir = opendir(path);
-	if (dir == NULL)
-		return;
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
-			  MAC2STR(drv->own_addr));
-	if (ret >= 0 && ret < end - pos)
-		pos += ret;
-	if (drv->probe_req_ie) {
-		ret = os_snprintf(pos, end - pos, " ");
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
-					drv->probe_req_ie_len);
-	}
-	if (drv->probe_req_ssid_len) {
-		/* Add SSID IE */
-		ret = os_snprintf(pos, end - pos, "%02x%02x",
-				  WLAN_EID_SSID,
-				  (unsigned int) drv->probe_req_ssid_len);
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid,
-					drv->probe_req_ssid_len);
-	}
-	end[-1] = '\0';
-
-	while ((dent = readdir(dir))) {
-		if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
-		    os_strncmp(dent->d_name, "STA-", 4) != 0)
-			continue;
-		if (drv->own_socket_path) {
-			size_t olen, dlen;
-			olen = os_strlen(drv->own_socket_path);
-			dlen = os_strlen(dent->d_name);
-			if (olen >= dlen &&
-			    os_strcmp(dent->d_name,
-				      drv->own_socket_path + olen - dlen) == 0)
-				continue;
-		}
-		wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
-
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			    path, dent->d_name);
-
-		if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-			perror("sendto(test_socket)");
-		}
-	}
-	closedir(dir);
-}
-#endif /* DRIVER_TEST_UNIX */
-
-
-static int wpa_driver_test_scan(void *priv,
-				struct wpa_driver_scan_params *params)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	size_t i;
-
-	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
-
-	os_free(drv->probe_req_ie);
-	if (params->extra_ies) {
-		drv->probe_req_ie = os_malloc(params->extra_ies_len);
-		if (drv->probe_req_ie == NULL) {
-			drv->probe_req_ie_len = 0;
-			return -1;
-		}
-		os_memcpy(drv->probe_req_ie, params->extra_ies,
-			  params->extra_ies_len);
-		drv->probe_req_ie_len = params->extra_ies_len;
-	} else {
-		drv->probe_req_ie = NULL;
-		drv->probe_req_ie_len = 0;
-	}
-
-	for (i = 0; i < params->num_ssids; i++)
-		wpa_hexdump(MSG_DEBUG, "Scan SSID",
-			    params->ssids[i].ssid, params->ssids[i].ssid_len);
-	drv->probe_req_ssid_len = 0;
-	if (params->num_ssids) {
-		os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid,
-			  params->ssids[0].ssid_len);
-		drv->probe_req_ssid_len = params->ssids[0].ssid_len;
-	}
-	wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
-		    params->extra_ies, params->extra_ies_len);
-
-	drv->num_scanres = 0;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_socket >= 0 && drv->test_dir)
-		wpa_driver_scan_dir(drv, drv->test_dir);
-
-	if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
-	    sendto(drv->test_socket, "SCAN", 4, 0,
-		   (struct sockaddr *) &drv->hostapd_addr,
-		   sizeof(drv->hostapd_addr)) < 0) {
-		perror("sendto(test_socket)");
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
-	    sendto(drv->test_socket, "SCAN", 4, 0,
-		   (struct sockaddr *) &drv->hostapd_addr_udp,
-		   sizeof(drv->hostapd_addr_udp)) < 0) {
-		perror("sendto(test_socket)");
-	}
-
-	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct wpa_scan_results *res;
-	size_t i;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		return NULL;
-	}
-
-	for (i = 0; i < drv->num_scanres; i++) {
-		struct wpa_scan_res *r;
-		if (drv->scanres[i] == NULL)
-			continue;
-		r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
-		if (r == NULL)
-			break;
-		os_memcpy(r, drv->scanres[i],
-			  sizeof(*r) + drv->scanres[i]->ie_len);
-		res->res[res->num++] = r;
-	}
-
-	return res;
-}
-
-
-static int wpa_driver_test_set_key(const char *ifname, void *priv,
-				   enum wpa_alg alg, const u8 *addr,
-				   int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
-{
-	wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d "
-		   "set_tx=%d",
-		   __func__, ifname, priv, alg, key_idx, set_tx);
-	if (addr)
-		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
-	if (seq)
-		wpa_hexdump(MSG_DEBUG, "   seq", seq, seq_len);
-	if (key)
-		wpa_hexdump_key(MSG_DEBUG, "   key", key, key_len);
-	return 0;
-}
-
-
-static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap)
-{
-	if (ap && !drv->ap) {
-		wpa_driver_test_close_test_socket(drv);
-		wpa_driver_test_attach(drv, drv->test_dir, 1);
-		drv->ap = 1;
-	} else if (!ap && drv->ap) {
-		wpa_driver_test_close_test_socket(drv);
-		wpa_driver_test_attach(drv, drv->test_dir, 0);
-		drv->ap = 0;
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_test_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
-		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
-		   __func__, priv, params->freq, params->pairwise_suite,
-		   params->group_suite, params->key_mgmt_suite,
-		   params->auth_alg, params->mode);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "   bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-	}
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "   ssid",
-				  params->ssid, params->ssid_len);
-	}
-	if (params->wpa_ie) {
-		wpa_hexdump(MSG_DEBUG, "   wpa_ie",
-			    params->wpa_ie, params->wpa_ie_len);
-		drv->assoc_wpa_ie_len = params->wpa_ie_len;
-		if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
-			drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
-		os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
-			  drv->assoc_wpa_ie_len);
-	} else
-		drv->assoc_wpa_ie_len = 0;
-
-	wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
-
-	drv->ibss = params->mode == IEEE80211_MODE_IBSS;
-	dbss->privacy = params->key_mgmt_suite &
-		(WPA_KEY_MGMT_IEEE8021X |
-		 WPA_KEY_MGMT_PSK |
-		 WPA_KEY_MGMT_WPA_NONE |
-		 WPA_KEY_MGMT_FT_IEEE8021X |
-		 WPA_KEY_MGMT_FT_PSK |
-		 WPA_KEY_MGMT_IEEE8021X_SHA256 |
-		 WPA_KEY_MGMT_PSK_SHA256);
-	if (params->wep_key_len[params->wep_tx_keyidx])
-		dbss->privacy = 1;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_dir && params->bssid &&
-	    params->mode != IEEE80211_MODE_IBSS) {
-		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
-		drv->hostapd_addr.sun_family = AF_UNIX;
-		os_snprintf(drv->hostapd_addr.sun_path,
-			    sizeof(drv->hostapd_addr.sun_path),
-			    "%s/AP-" MACSTR,
-			    drv->test_dir, MAC2STR(params->bssid));
-		drv->hostapd_addr_set = 1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	if (params->mode == IEEE80211_MODE_AP) {
-		os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
-		dbss->ssid_len = params->ssid_len;
-		os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN);
-		if (params->wpa_ie && params->wpa_ie_len) {
-			dbss->ie = os_malloc(params->wpa_ie_len);
-			if (dbss->ie) {
-				os_memcpy(dbss->ie, params->wpa_ie,
-					  params->wpa_ie_len);
-				dbss->ielen = params->wpa_ie_len;
-			}
-		}
-	} else if (drv->test_socket >= 0 &&
-		   (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
-		char cmd[200], *pos, *end;
-		int ret;
-		end = cmd + sizeof(cmd);
-		pos = cmd;
-		ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
-				  MAC2STR(drv->own_addr));
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
-					params->ssid_len);
-		ret = os_snprintf(pos, end - pos, " ");
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
-					params->wpa_ie_len);
-		end[-1] = '\0';
-#ifdef DRIVER_TEST_UNIX
-		if (drv->hostapd_addr_set &&
-		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &drv->hostapd_addr,
-			   sizeof(drv->hostapd_addr)) < 0) {
-			perror("sendto(test_socket)");
-			return -1;
-		}
-#endif /* DRIVER_TEST_UNIX */
-		if (drv->hostapd_addr_udp_set &&
-		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &drv->hostapd_addr_udp,
-			   sizeof(drv->hostapd_addr_udp)) < 0) {
-			perror("sendto(test_socket)");
-			return -1;
-		}
-
-		os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
-		dbss->ssid_len = params->ssid_len;
-	} else {
-		drv->associated = 1;
-		if (params->mode == IEEE80211_MODE_IBSS) {
-			os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
-			dbss->ssid_len = params->ssid_len;
-			if (params->bssid)
-				os_memcpy(dbss->bssid, params->bssid,
-					  ETH_ALEN);
-			else {
-				os_get_random(dbss->bssid, ETH_ALEN);
-				dbss->bssid[0] &= ~0x01;
-				dbss->bssid[0] |= 0x02;
-			}
-		}
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
-{
-	struct test_driver_bss *dbss = priv;
-	os_memcpy(bssid, dbss->bssid, ETH_ALEN);
-	return 0;
-}
-
-
-static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
-{
-	struct test_driver_bss *dbss = priv;
-	os_memcpy(ssid, dbss->ssid, 32);
-	return dbss->ssid_len;
-}
-
-
-static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
-{
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_socket >= 0 &&
-	    sendto(drv->test_socket, "DISASSOC", 8, 0,
-		   (struct sockaddr *) &drv->hostapd_addr,
-		   sizeof(drv->hostapd_addr)) < 0) {
-		perror("sendto(test_socket)");
-		return -1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
-	    sendto(drv->test_socket, "DISASSOC", 8, 0,
-		   (struct sockaddr *) &drv->hostapd_addr_udp,
-		   sizeof(drv->hostapd_addr_udp)) < 0) {
-		perror("sendto(test_socket)");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-		   __func__, MAC2STR(addr), reason_code);
-	os_memset(dbss->bssid, 0, ETH_ALEN);
-	drv->associated = 0;
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-	return wpa_driver_test_send_disassoc(drv);
-}
-
-
-static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-		   __func__, MAC2STR(addr), reason_code);
-	os_memset(dbss->bssid, 0, ETH_ALEN);
-	drv->associated = 0;
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-	return wpa_driver_test_send_disassoc(drv);
-}
-
-
-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;
-}
-
-
-static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen,
-				     const char *data)
-{
-	struct wpa_scan_res *res;
-	const char *pos, *pos2;
-	size_t len;
-	u8 *ie_pos, *ie_start, *ie_end;
-#define MAX_IE_LEN 1000
-	const u8 *ds_params;
-
-	wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
-	if (drv->num_scanres >= MAX_SCAN_RESULTS) {
-		wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
-			   "result");
-		return;
-	}
-
-	/* SCANRESP BSSID SSID IEs */
-
-	res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
-	if (res == NULL)
-		return;
-	ie_start = ie_pos = (u8 *) (res + 1);
-	ie_end = ie_pos + MAX_IE_LEN;
-
-	if (hwaddr_aton(data, res->bssid)) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
-		os_free(res);
-		return;
-	}
-
-	pos = data + 17;
-	while (*pos == ' ')
-		pos++;
-	pos2 = os_strchr(pos, ' ');
-	if (pos2 == NULL) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
-			   "in scanres");
-		os_free(res);
-		return;
-	}
-	len = (pos2 - pos) / 2;
-	if (len > 32)
-		len = 32;
-	/*
-	 * Generate SSID IE from the SSID field since this IE is not included
-	 * in the main IE field.
-	 */
-	*ie_pos++ = WLAN_EID_SSID;
-	*ie_pos++ = len;
-	if (hexstr2bin(pos, ie_pos, len) < 0) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
-		os_free(res);
-		return;
-	}
-	ie_pos += len;
-
-	pos = pos2 + 1;
-	pos2 = os_strchr(pos, ' ');
-	if (pos2 == NULL)
-		len = os_strlen(pos) / 2;
-	else
-		len = (pos2 - pos) / 2;
-	if ((int) len > ie_end - ie_pos)
-		len = ie_end - ie_pos;
-	if (hexstr2bin(pos, ie_pos, len) < 0) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
-		os_free(res);
-		return;
-	}
-	ie_pos += len;
-	res->ie_len = ie_pos - ie_start;
-
-	if (pos2) {
-		pos = pos2 + 1;
-		while (*pos == ' ')
-			pos++;
-		if (os_strstr(pos, "PRIVACY"))
-			res->caps |= IEEE80211_CAP_PRIVACY;
-		if (os_strstr(pos, "IBSS"))
-			res->caps |= IEEE80211_CAP_IBSS;
-	}
-
-	ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS);
-	if (ds_params && ds_params[1] > 0) {
-		if (ds_params[2] >= 1 && ds_params[2] <= 13)
-			res->freq = 2407 + ds_params[2] * 5;
-	}
-
-	os_free(drv->scanres[drv->num_scanres]);
-	drv->scanres[drv->num_scanres++] = res;
-}
-
-
-static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
-				      struct sockaddr *from,
-				      socklen_t fromlen,
-				      const char *data)
-{
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	/* ASSOCRESP BSSID <res> */
-	if (hwaddr_aton(data, bss->bssid)) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
-			   "assocresp");
-	}
-	if (drv->use_associnfo) {
-		union wpa_event_data event;
-		os_memset(&event, 0, sizeof(event));
-		event.assoc_info.req_ies = drv->assoc_wpa_ie;
-		event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
-	}
-	drv->associated = 1;
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen)
-{
-	drv->associated = 0;
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-}
-
-
-static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
-				  struct sockaddr *from,
-				  socklen_t fromlen,
-				  const u8 *data, size_t data_len)
-{
-	const u8 *src;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	if (data_len > 14) {
-		/* Skip Ethernet header */
-		src = data + ETH_ALEN;
-		data += 14;
-		data_len -= 14;
-	} else
-		src = bss->bssid;
-
-	drv_event_eapol_rx(drv->ctx, src, data, data_len);
-}
-
-
-static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
-				 struct sockaddr *from,
-				 socklen_t fromlen,
-				 const u8 *data, size_t data_len)
-{
-	int freq = 0, own_freq;
-	union wpa_event_data event;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-	if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
-		size_t pos;
-		for (pos = 5; pos < data_len; pos++) {
-			if (data[pos] == ' ')
-				break;
-		}
-		if (pos < data_len) {
-			freq = atoi((const char *) &data[5]);
-			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
-				   "freq %d MHz", bss->ifname, freq);
-			pos++;
-			data += pos;
-			data_len -= pos;
-		}
-	}
-
-	if (drv->remain_on_channel_freq)
-		own_freq = drv->remain_on_channel_freq;
-	else
-		own_freq = drv->current_freq;
-
-	if (freq && own_freq && freq != own_freq) {
-		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
-			   "another frequency %d MHz (own %d MHz)",
-			   bss->ifname, freq, own_freq);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	event.mlme_rx.buf = data;
-	event.mlme_rx.len = data_len;
-	event.mlme_rx.freq = freq;
-	wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
-
-	if (drv->probe_req_report && data_len >= 24) {
-		const struct ieee80211_mgmt *mgmt;
-		u16 fc;
-
-		mgmt = (const struct ieee80211_mgmt *) data;
-		fc = le_to_host16(mgmt->frame_control);
-		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
-			os_memset(&event, 0, sizeof(event));
-			event.rx_probe_req.sa = mgmt->sa;
-			event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-			event.rx_probe_req.ie_len =
-				data_len - (mgmt->u.probe_req.variable - data);
-			wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
-					     &event);
-		}
-	}
-}
-
-
-static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen,
-				     const u8 *data, size_t data_len)
-{
-	char buf[512], *pos, *end;
-	int ret;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
-
-	if (!drv->ibss)
-		return;
-
-	pos = buf;
-	end = buf + sizeof(buf);
-
-	/* reply: SCANRESP BSSID SSID IEs */
-	ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-		       MAC2STR(bss->bssid));
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos,
-				bss->ssid, bss->ssid_len);
-	ret = snprintf(pos, end - pos, " ");
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
-				drv->assoc_wpa_ie_len);
-
-	if (bss->privacy) {
-		ret = snprintf(pos, end - pos, " PRIVACY");
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-	}
-
-	ret = snprintf(pos, end - pos, " IBSS");
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-
-	sendto(drv->test_socket, buf, pos - buf, 0,
-	       (struct sockaddr *) from, fromlen);
-}
-
-
-static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
-					 void *sock_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	char *buf;
-	int res;
-	struct sockaddr_storage from;
-	socklen_t fromlen = sizeof(from);
-	const size_t buflen = 2000;
-
-	if (drv->ap) {
-		test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
-		return;
-	}
-
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-	res = recvfrom(sock, buf, buflen - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(test_socket)");
-		os_free(buf);
-		return;
-	}
-	buf[res] = '\0';
-
-	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
-	if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
-		wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
-					 fromlen, buf + 9);
-	} else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
-		wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
-					  fromlen, buf + 10);
-	} else if (os_strcmp(buf, "DISASSOC") == 0) {
-		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
-					 fromlen);
-	} else if (os_strcmp(buf, "DEAUTH") == 0) {
-		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
-					 fromlen);
-	} else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
-		wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
-				      (const u8 *) buf + 6, res - 6);
-	} else if (os_strncmp(buf, "MLME ", 5) == 0) {
-		wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
-				     (const u8 *) buf + 5, res - 5);
-	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
-		wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
-					 fromlen,
-					 (const u8 *) buf + 5, res - 5);
-	} else {
-		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
-				  (u8 *) buf, res);
-	}
-	os_free(buf);
-}
-
-
-static void * wpa_driver_test_init2(void *ctx, const char *ifname,
-				    void *global_priv)
-{
-	struct wpa_driver_test_data *drv;
-	struct wpa_driver_test_global *global = global_priv;
-	struct test_driver_bss *bss;
-
-	drv = test_alloc_data(ctx, ifname);
-	if (drv == NULL)
-		return NULL;
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-	drv->global = global_priv;
-	drv->test_socket = -1;
-
-	/* Set dummy BSSID and SSID for testing. */
-	bss->bssid[0] = 0x02;
-	bss->bssid[1] = 0x00;
-	bss->bssid[2] = 0x00;
-	bss->bssid[3] = 0x00;
-	bss->bssid[4] = 0x00;
-	bss->bssid[5] = 0x01;
-	os_memcpy(bss->ssid, "test", 5);
-	bss->ssid_len = 4;
-
-	if (global->bss_add_used) {
-		os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
-		global->bss_add_used = 0;
-	}
-
-	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-
-	return bss;
-}
-
-
-static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
-{
-	if (drv->test_socket >= 0) {
-		eloop_unregister_read_sock(drv->test_socket);
-		close(drv->test_socket);
-		drv->test_socket = -1;
-	}
-
-	if (drv->own_socket_path) {
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-	}
-}
-
-
-static void wpa_driver_test_deinit(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli, *prev;
-	int i;
-
-	cli = drv->cli;
-	while (cli) {
-		prev = cli;
-		cli = cli->next;
-		os_free(prev);
-	}
-
-#ifdef HOSTAPD
-	/* There should be only one BSS remaining at this point. */
-	if (dl_list_len(&drv->bss) != 1)
-		wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries",
-			   __func__, dl_list_len(&drv->bss));
-#endif /* HOSTAPD */
-
-	test_driver_free_bsses(drv);
-
-	wpa_driver_test_close_test_socket(drv);
-	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	os_free(drv->test_dir);
-	for (i = 0; i < MAX_SCAN_RESULTS; i++)
-		os_free(drv->scanres[i]);
-	os_free(drv->probe_req_ie);
-	wpa_trace_remove_ref(drv, ctx, drv->ctx);
-	os_free(drv);
-}
-
-
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
-				  const char *dir, int ap)
-{
-#ifdef DRIVER_TEST_UNIX
-	static unsigned int counter = 0;
-	struct sockaddr_un addr;
-	size_t len;
-
-	os_free(drv->own_socket_path);
-	if (dir) {
-		len = os_strlen(dir) + 30;
-		drv->own_socket_path = os_malloc(len);
-		if (drv->own_socket_path == NULL)
-			return -1;
-		os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
-			    dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
-	} else {
-		drv->own_socket_path = os_malloc(100);
-		if (drv->own_socket_path == NULL)
-			return -1;
-		os_snprintf(drv->own_socket_path, 100,
-			    "/tmp/wpa_supplicant_test-%d-%d",
-			    getpid(), counter++);
-	}
-
-	drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (drv->test_socket < 0) {
-		perror("socket(PF_UNIX)");
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
-	if (bind(drv->test_socket, (struct sockaddr *) &addr,
-		 sizeof(addr)) < 0) {
-		perror("bind(PF_UNIX)");
-		close(drv->test_socket);
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	eloop_register_read_sock(drv->test_socket,
-				 wpa_driver_test_receive_unix, drv, NULL);
-
-	return 0;
-#else /* DRIVER_TEST_UNIX */
-	return -1;
-#endif /* DRIVER_TEST_UNIX */
-}
-
-
-static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
-				      char *dst)
-{
-	char *pos;
-
-	pos = os_strchr(dst, ':');
-	if (pos == NULL)
-		return -1;
-	*pos++ = '\0';
-	wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
-
-	drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->test_socket < 0) {
-		perror("socket(PF_INET)");
-		return -1;
-	}
-
-	os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
-	drv->hostapd_addr_udp.sin_family = AF_INET;
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
-	{
-		int a[4];
-		u8 *pos;
-		sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
-		pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
-		*pos++ = a[0];
-		*pos++ = a[1];
-		*pos++ = a[2];
-		*pos++ = a[3];
-	}
-#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
-#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
-
-	drv->hostapd_addr_udp_set = 1;
-
-	eloop_register_read_sock(drv->test_socket,
-				 wpa_driver_test_receive_unix, drv, NULL);
-
-	return 0;
-}
-
-
-static int wpa_driver_test_set_param(void *priv, const char *param)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	const char *pos;
-
-	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
-	if (param == NULL)
-		return 0;
-
-	wpa_driver_test_close_test_socket(drv);
-
-#ifdef DRIVER_TEST_UNIX
-	pos = os_strstr(param, "test_socket=");
-	if (pos) {
-		const char *pos2;
-		size_t len;
-
-		pos += 12;
-		pos2 = os_strchr(pos, ' ');
-		if (pos2)
-			len = pos2 - pos;
-		else
-			len = os_strlen(pos);
-		if (len > sizeof(drv->hostapd_addr.sun_path))
-			return -1;
-		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
-		drv->hostapd_addr.sun_family = AF_UNIX;
-		os_memcpy(drv->hostapd_addr.sun_path, pos, len);
-		drv->hostapd_addr_set = 1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	pos = os_strstr(param, "test_dir=");
-	if (pos) {
-		char *end;
-		os_free(drv->test_dir);
-		drv->test_dir = os_strdup(pos + 9);
-		if (drv->test_dir == NULL)
-			return -1;
-		end = os_strchr(drv->test_dir, ' ');
-		if (end)
-			*end = '\0';
-		if (wpa_driver_test_attach(drv, drv->test_dir, 0))
-			return -1;
-	} else {
-		pos = os_strstr(param, "test_udp=");
-		if (pos) {
-			char *dst, *epos;
-			dst = os_strdup(pos + 9);
-			if (dst == NULL)
-				return -1;
-			epos = os_strchr(dst, ' ');
-			if (epos)
-				*epos = '\0';
-			if (wpa_driver_test_attach_udp(drv, dst))
-				return -1;
-			os_free(dst);
-		} else if (wpa_driver_test_attach(drv, NULL, 0))
-			return -1;
-	}
-
-	if (os_strstr(param, "use_associnfo=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
-		drv->use_associnfo = 1;
-	}
-
-#ifdef CONFIG_CLIENT_MLME
-	if (os_strstr(param, "use_mlme=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
-		drv->use_mlme = 1;
-	}
-#endif /* CONFIG_CLIENT_MLME */
-
-	return 0;
-}
-
-
-static const u8 * wpa_driver_test_get_mac_addr(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return drv->own_addr;
-}
-
-
-static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
-				      const u8 *data, size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	char *msg;
-	size_t msg_len;
-	struct l2_ethhdr eth;
-	struct sockaddr *addr;
-	socklen_t alen;
-#ifdef DRIVER_TEST_UNIX
-	struct sockaddr_un addr_un;
-#endif /* DRIVER_TEST_UNIX */
-
-	wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
-
-	os_memset(&eth, 0, sizeof(eth));
-	os_memcpy(eth.h_dest, dest, ETH_ALEN);
-	os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
-	eth.h_proto = host_to_be16(proto);
-
-	msg_len = 6 + sizeof(eth) + data_len;
-	msg = os_malloc(msg_len);
-	if (msg == NULL)
-		return -1;
-	os_memcpy(msg, "EAPOL ", 6);
-	os_memcpy(msg + 6, &eth, sizeof(eth));
-	os_memcpy(msg + 6 + sizeof(eth), data, data_len);
-
-	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
-	    drv->test_dir == NULL) {
-		if (drv->hostapd_addr_udp_set) {
-			addr = (struct sockaddr *) &drv->hostapd_addr_udp;
-			alen = sizeof(drv->hostapd_addr_udp);
-		} else {
-#ifdef DRIVER_TEST_UNIX
-			addr = (struct sockaddr *) &drv->hostapd_addr;
-			alen = sizeof(drv->hostapd_addr);
-#else /* DRIVER_TEST_UNIX */
-			os_free(msg);
-			return -1;
-#endif /* DRIVER_TEST_UNIX */
-		}
-	} else {
-#ifdef DRIVER_TEST_UNIX
-		struct stat st;
-		os_memset(&addr_un, 0, sizeof(addr_un));
-		addr_un.sun_family = AF_UNIX;
-		os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
-			    "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
-		if (stat(addr_un.sun_path, &st) < 0) {
-			os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
-				    "%s/AP-" MACSTR,
-				    drv->test_dir, MAC2STR(dest));
-		}
-		addr = (struct sockaddr *) &addr_un;
-		alen = sizeof(addr_un);
-#else /* DRIVER_TEST_UNIX */
-		os_free(msg);
-		return -1;
-#endif /* DRIVER_TEST_UNIX */
-	}
-
-	if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
-		perror("sendmsg(test_socket)");
-		os_free(msg);
-		return -1;
-	}
-
-	os_free(msg);
-	return 0;
-}
-
-
-static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	os_memset(capa, 0, sizeof(*capa));
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
-		WPA_DRIVER_CAPA_KEY_MGMT_FT |
-		WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-		WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP |
-		WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN |
-		WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	if (drv->use_mlme)
-		capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
-	capa->flags |= WPA_DRIVER_FLAGS_AP;
-	capa->max_scan_ssids = 2;
-	capa->max_remain_on_chan = 60000;
-
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
-					      int protect_type,
-					      int key_type)
-{
-	wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
-		   __func__, protect_type, key_type);
-
-	if (addr) {
-		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
-			   __func__, MAC2STR(addr));
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_test_set_channel(void *priv,
-				       enum hostapd_hw_mode phymode,
-				       int chan, int freq)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
-		   __func__, phymode, chan, freq);
-	drv->current_freq = freq;
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
-					const u8 *supp_rates,
-					size_t supp_rates_len)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
-				    size_t ssid_len)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return 0;
-}
-
-
-static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
-{
-	wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
-	return 0;
-}
-
-
-static void * wpa_driver_test_global_init(void)
-{
-	struct wpa_driver_test_global *global;
-
-	global = os_zalloc(sizeof(*global));
-	return global;
-}
-
-
-static void wpa_driver_test_global_deinit(void *priv)
-{
-	struct wpa_driver_test_global *global = priv;
-	os_free(global);
-}
-
-
-static struct wpa_interface_info *
-wpa_driver_test_get_interfaces(void *global_priv)
-{
-	/* struct wpa_driver_test_global *global = priv; */
-	struct wpa_interface_info *iface;
-
-	iface = os_zalloc(sizeof(*iface));
-	if (iface == NULL)
-		return iface;
-	iface->ifname = os_strdup("sta0");
-	iface->desc = os_strdup("test interface 0");
-	iface->drv_name = "test";
-	iface->next = os_zalloc(sizeof(*iface));
-	if (iface->next) {
-		iface->next->ifname = os_strdup("sta1");
-		iface->next->desc = os_strdup("test interface 1");
-		iface->next->drv_name = "test";
-	}
-
-	return iface;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
-	struct hostapd_hw_modes *modes;
-	size_t i;
-
-	*num_modes = 3;
-	*flags = 0;
-	modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
-	if (modes == NULL)
-		return NULL;
-	modes[0].mode = HOSTAPD_MODE_IEEE80211G;
-	modes[0].num_channels = 11;
-	modes[0].num_rates = 12;
-	modes[0].channels =
-		os_zalloc(11 * sizeof(struct hostapd_channel_data));
-	modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
-	if (modes[0].channels == NULL || modes[0].rates == NULL)
-		goto fail;
-	for (i = 0; i < 11; i++) {
-		modes[0].channels[i].chan = i + 1;
-		modes[0].channels[i].freq = 2412 + 5 * i;
-		modes[0].channels[i].flag = 0;
-	}
-	modes[0].rates[0] = 10;
-	modes[0].rates[1] = 20;
-	modes[0].rates[2] = 55;
-	modes[0].rates[3] = 110;
-	modes[0].rates[4] = 60;
-	modes[0].rates[5] = 90;
-	modes[0].rates[6] = 120;
-	modes[0].rates[7] = 180;
-	modes[0].rates[8] = 240;
-	modes[0].rates[9] = 360;
-	modes[0].rates[10] = 480;
-	modes[0].rates[11] = 540;
-
-	modes[1].mode = HOSTAPD_MODE_IEEE80211B;
-	modes[1].num_channels = 11;
-	modes[1].num_rates = 4;
-	modes[1].channels =
-		os_zalloc(11 * sizeof(struct hostapd_channel_data));
-	modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
-	if (modes[1].channels == NULL || modes[1].rates == NULL)
-		goto fail;
-	for (i = 0; i < 11; i++) {
-		modes[1].channels[i].chan = i + 1;
-		modes[1].channels[i].freq = 2412 + 5 * i;
-		modes[1].channels[i].flag = 0;
-	}
-	modes[1].rates[0] = 10;
-	modes[1].rates[1] = 20;
-	modes[1].rates[2] = 55;
-	modes[1].rates[3] = 110;
-
-	modes[2].mode = HOSTAPD_MODE_IEEE80211A;
-	modes[2].num_channels = 1;
-	modes[2].num_rates = 8;
-	modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
-	modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
-	if (modes[2].channels == NULL || modes[2].rates == NULL)
-		goto fail;
-	modes[2].channels[0].chan = 60;
-	modes[2].channels[0].freq = 5300;
-	modes[2].channels[0].flag = 0;
-	modes[2].rates[0] = 60;
-	modes[2].rates[1] = 90;
-	modes[2].rates[2] = 120;
-	modes[2].rates[3] = 180;
-	modes[2].rates[4] = 240;
-	modes[2].rates[5] = 360;
-	modes[2].rates[6] = 480;
-	modes[2].rates[7] = 540;
-
-	return modes;
-
-fail:
-	if (modes) {
-		for (i = 0; i < *num_modes; i++) {
-			os_free(modes[i].channels);
-			os_free(modes[i].rates);
-		}
-		os_free(modes);
-	}
-	return NULL;
-}
-
-
-static int wpa_driver_test_set_freq(void *priv,
-				    struct hostapd_freq_params *freq)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
-	drv->current_freq = freq->freq;
-	return 0;
-}
-
-
-static int wpa_driver_test_send_action(void *priv, unsigned int freq,
-				       const u8 *dst, const u8 *src,
-				       const u8 *bssid,
-				       const u8 *data, size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	int ret = -1;
-	u8 *buf;
-	struct ieee80211_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "test: Send Action frame");
-
-	if ((drv->remain_on_channel_freq &&
-	     freq != drv->remain_on_channel_freq) ||
-	    (drv->remain_on_channel_freq == 0 &&
-	     freq != (unsigned int) drv->current_freq)) {
-		wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
-			   "unexpected channel: freq=%u MHz (current_freq=%u "
-			   "MHz, remain-on-channel freq=%u MHz)",
-			   freq, drv->current_freq,
-			   drv->remain_on_channel_freq);
-		return -1;
-	}
-
-	buf = os_zalloc(24 + data_len);
-	if (buf == NULL)
-		return ret;
-	os_memcpy(buf + 24, data, data_len);
-	hdr = (struct ieee80211_hdr *) buf;
-	hdr->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
-	os_memcpy(hdr->addr1, dst, ETH_ALEN);
-	os_memcpy(hdr->addr2, src, ETH_ALEN);
-	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
-
-	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len);
-	os_free(buf);
-	return ret;
-}
-
-
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = drv->remain_on_channel_freq;
-	data.remain_on_channel.duration = drv->remain_on_channel_duration;
-	wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
-
-	drv->remain_on_channel_freq = 0;
-}
-
-
-static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
-					     unsigned int duration)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
-		   __func__, freq, duration);
-	if (drv->remain_on_channel_freq &&
-	    drv->remain_on_channel_freq != freq) {
-		wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
-			   "remain_on_channel request");
-		return -1;
-	}
-
-	drv->remain_on_channel_freq = freq;
-	drv->remain_on_channel_duration = duration;
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
-			       test_remain_on_channel_timeout, drv, NULL);
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = freq;
-	data.remain_on_channel.duration = duration;
-	wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
-
-	return 0;
-}
-
-
-static int wpa_driver_test_cancel_remain_on_channel(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	if (!drv->remain_on_channel_freq)
-		return -1;
-	drv->remain_on_channel_freq = 0;
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	return 0;
-}
-
-
-static int wpa_driver_test_probe_req_report(void *priv, int report)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
-	drv->probe_req_report = report;
-	return 0;
-}
-
-
-const struct wpa_driver_ops wpa_driver_test_ops = {
-	"test",
-	"wpa_supplicant test driver",
-	.hapd_init = test_driver_init,
-	.hapd_deinit = wpa_driver_test_deinit,
-	.hapd_send_eapol = test_driver_send_eapol,
-	.send_mlme = wpa_driver_test_send_mlme,
-	.set_generic_elem = test_driver_set_generic_elem,
-	.sta_deauth = test_driver_sta_deauth,
-	.sta_disassoc = test_driver_sta_disassoc,
-	.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
-	.if_add = test_driver_if_add,
-	.if_remove = test_driver_if_remove,
-	.valid_bss_mask = test_driver_valid_bss_mask,
-	.hapd_set_ssid = test_driver_set_ssid,
-	.set_privacy = test_driver_set_privacy,
-	.set_sta_vlan = test_driver_set_sta_vlan,
-	.sta_add = test_driver_sta_add,
-	.send_ether = test_driver_send_ether,
-	.set_ap_wps_ie = test_driver_set_ap_wps_ie,
-	.get_bssid = wpa_driver_test_get_bssid,
-	.get_ssid = wpa_driver_test_get_ssid,
-	.set_key = wpa_driver_test_set_key,
-	.deinit = wpa_driver_test_deinit,
-	.set_param = wpa_driver_test_set_param,
-	.deauthenticate = wpa_driver_test_deauthenticate,
-	.disassociate = wpa_driver_test_disassociate,
-	.associate = wpa_driver_test_associate,
-	.get_capa = wpa_driver_test_get_capa,
-	.get_mac_addr = wpa_driver_test_get_mac_addr,
-	.send_eapol = wpa_driver_test_send_eapol,
-	.mlme_setprotection = wpa_driver_test_mlme_setprotection,
-	.set_channel = wpa_driver_test_set_channel,
-	.set_ssid = wpa_driver_test_set_ssid,
-	.set_bssid = wpa_driver_test_set_bssid,
-	.mlme_add_sta = wpa_driver_test_mlme_add_sta,
-	.mlme_remove_sta = wpa_driver_test_mlme_remove_sta,
-	.get_scan_results2 = wpa_driver_test_get_scan_results2,
-	.global_init = wpa_driver_test_global_init,
-	.global_deinit = wpa_driver_test_global_deinit,
-	.init2 = wpa_driver_test_init2,
-	.get_interfaces = wpa_driver_test_get_interfaces,
-	.scan2 = wpa_driver_test_scan,
-	.set_freq = wpa_driver_test_set_freq,
-	.send_action = wpa_driver_test_send_action,
-	.remain_on_channel = wpa_driver_test_remain_on_channel,
-	.cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
-	.probe_req_report = wpa_driver_test_probe_req_report,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_test.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_test.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_test.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3315 @@
+/*
+ * Testing driver interface for a simulated network driver
+ * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */
+#include "build_config.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock2.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/un.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#define DRIVER_TEST_UNIX
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
+#include "utils/trace.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/sha1.h"
+#include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+#include "driver.h"
+
+
+struct test_client_socket {
+	struct test_client_socket *next;
+	u8 addr[ETH_ALEN];
+	struct sockaddr_un un;
+	socklen_t unlen;
+	struct test_driver_bss *bss;
+};
+
+struct test_driver_bss {
+	struct wpa_driver_test_data *drv;
+	struct dl_list list;
+	void *bss_ctx;
+	char ifname[IFNAMSIZ];
+	u8 bssid[ETH_ALEN];
+	u8 *ie;
+	size_t ielen;
+	u8 *wps_beacon_ie;
+	size_t wps_beacon_ie_len;
+	u8 *wps_probe_resp_ie;
+	size_t wps_probe_resp_ie_len;
+	u8 ssid[32];
+	size_t ssid_len;
+	int privacy;
+};
+
+struct wpa_driver_test_global {
+	int bss_add_used;
+	u8 req_addr[ETH_ALEN];
+};
+
+struct wpa_driver_test_data {
+	struct wpa_driver_test_global *global;
+	void *ctx;
+	WPA_TRACE_REF(ctx);
+	u8 own_addr[ETH_ALEN];
+	int test_socket;
+#ifdef DRIVER_TEST_UNIX
+	struct sockaddr_un hostapd_addr;
+#endif /* DRIVER_TEST_UNIX */
+	int hostapd_addr_set;
+	struct sockaddr_in hostapd_addr_udp;
+	int hostapd_addr_udp_set;
+	char *own_socket_path;
+	char *test_dir;
+#define MAX_SCAN_RESULTS 30
+	struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
+	size_t num_scanres;
+	int use_associnfo;
+	u8 assoc_wpa_ie[80];
+	size_t assoc_wpa_ie_len;
+	int associated;
+	u8 *probe_req_ie;
+	size_t probe_req_ie_len;
+	u8 probe_req_ssid[32];
+	size_t probe_req_ssid_len;
+	int ibss;
+	int ap;
+
+	struct test_client_socket *cli;
+	struct dl_list bss;
+	int udp_port;
+
+	int alloc_iface_idx;
+
+	int probe_req_report;
+	unsigned int remain_on_channel_freq;
+	unsigned int remain_on_channel_duration;
+
+	int current_freq;
+
+	struct p2p_data *p2p;
+	unsigned int off_channel_freq;
+	struct wpabuf *pending_action_tx;
+	u8 pending_action_src[ETH_ALEN];
+	u8 pending_action_dst[ETH_ALEN];
+	u8 pending_action_bssid[ETH_ALEN];
+	unsigned int pending_action_freq;
+	unsigned int pending_action_no_cck;
+	unsigned int pending_listen_freq;
+	unsigned int pending_listen_duration;
+	int pending_p2p_scan;
+	struct sockaddr *probe_from;
+	socklen_t probe_from_len;
+};
+
+
+static void wpa_driver_test_deinit(void *priv);
+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
+				  const char *dir, int ap);
+static void wpa_driver_test_close_test_socket(
+	struct wpa_driver_test_data *drv);
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv);
+
+
+static void test_driver_free_bss(struct test_driver_bss *bss)
+{
+	os_free(bss->ie);
+	os_free(bss->wps_beacon_ie);
+	os_free(bss->wps_probe_resp_ie);
+	os_free(bss);
+}
+
+
+static void test_driver_free_bsses(struct wpa_driver_test_data *drv)
+{
+	struct test_driver_bss *bss, *tmp;
+
+	dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss,
+			      list) {
+		dl_list_del(&bss->list);
+		test_driver_free_bss(bss);
+	}
+}
+
+
+static struct test_client_socket *
+test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
+		    socklen_t fromlen)
+{
+	struct test_client_socket *cli = drv->cli;
+
+	while (cli) {
+		if (cli->unlen == fromlen &&
+		    strncmp(cli->un.sun_path, from->sun_path,
+			    fromlen - sizeof(cli->un.sun_family)) == 0)
+			return cli;
+		cli = cli->next;
+	}
+
+	return NULL;
+}
+
+
+static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
+				  size_t data_len, int encrypt,
+				  const u8 *own_addr, u32 flags)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_client_socket *cli;
+	struct msghdr msg;
+	struct iovec io[3];
+	struct l2_ethhdr eth;
+
+	if (drv->test_socket < 0)
+		return -1;
+
+	cli = drv->cli;
+	while (cli) {
+		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+			break;
+		cli = cli->next;
+	}
+
+	if (!cli) {
+		wpa_printf(MSG_DEBUG, "%s: no destination client entry",
+			   __func__);
+		return -1;
+	}
+
+	memcpy(eth.h_dest, addr, ETH_ALEN);
+	memcpy(eth.h_source, own_addr, ETH_ALEN);
+	eth.h_proto = host_to_be16(ETH_P_EAPOL);
+
+	io[0].iov_base = "EAPOL ";
+	io[0].iov_len = 6;
+	io[1].iov_base = ð
+	io[1].iov_len = sizeof(eth);
+	io[2].iov_base = (u8 *) data;
+	io[2].iov_len = data_len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 3;
+	msg.msg_name = &cli->un;
+	msg.msg_namelen = cli->unlen;
+	return sendmsg(drv->test_socket, &msg, 0);
+}
+
+
+static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+				  u16 proto, const u8 *data, size_t data_len)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct msghdr msg;
+	struct iovec io[3];
+	struct l2_ethhdr eth;
+	char desttxt[30];
+	struct sockaddr_un addr;
+	struct dirent *dent;
+	DIR *dir;
+	int ret = 0, broadcast = 0, count = 0;
+
+	if (drv->test_socket < 0 || drv->test_dir == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
+			   "test_dir=%p)",
+			   __func__, drv->test_socket, drv->test_dir);
+		return -1;
+	}
+
+	broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
+
+	memcpy(eth.h_dest, dst, ETH_ALEN);
+	memcpy(eth.h_source, src, ETH_ALEN);
+	eth.h_proto = host_to_be16(proto);
+
+	io[0].iov_base = "ETHER ";
+	io[0].iov_len = 6;
+	io[1].iov_base = ð
+	io[1].iov_len = sizeof(eth);
+	io[2].iov_base = (u8 *) data;
+	io[2].iov_len = data_len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 3;
+
+	dir = opendir(drv->test_dir);
+	if (dir == NULL) {
+		perror("test_driver: opendir");
+		return -1;
+	}
+	while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		/* Skip the file if it is not a socket. Also accept
+		 * DT_UNKNOWN (0) in case the C library or underlying file
+		 * system does not support d_type. */
+		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+			continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+
+		memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_UNIX;
+		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+			 drv->test_dir, dent->d_name);
+
+		if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
+			continue;
+		if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
+			   __func__, dent->d_name);
+
+		msg.msg_name = &addr;
+		msg.msg_namelen = sizeof(addr);
+		ret = sendmsg(drv->test_socket, &msg, 0);
+		if (ret < 0)
+			perror("driver_test: sendmsg");
+		count++;
+	}
+	closedir(dir);
+
+	if (!broadcast && count == 0) {
+		wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
+			   __func__, MAC2STR(dst));
+		return -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
+				     size_t data_len, int noack)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct msghdr msg;
+	struct iovec io[2];
+	const u8 *dest;
+	struct sockaddr_un addr;
+	struct dirent *dent;
+	DIR *dir;
+	int broadcast;
+	int ret = 0;
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	char cmd[50];
+	int freq;
+#ifdef HOSTAPD
+	char desttxt[30];
+#endif /* HOSTAPD */
+	union wpa_event_data event;
+
+	wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
+	if (drv->test_socket < 0 || data_len < 10) {
+		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
+			   " test_dir=%p)",
+			   __func__, drv->test_socket,
+			   (unsigned long) data_len,
+			   drv->test_dir);
+		return -1;
+	}
+
+	dest = data + 4;
+	broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+
+#ifdef HOSTAPD
+	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
+#endif /* HOSTAPD */
+
+	if (drv->remain_on_channel_freq)
+		freq = drv->remain_on_channel_freq;
+	else
+		freq = drv->current_freq;
+	wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
+		   dbss->ifname, freq);
+	os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
+	io[0].iov_base = cmd;
+	io[0].iov_len = os_strlen(cmd);
+	io[1].iov_base = (void *) data;
+	io[1].iov_len = data_len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+#ifdef HOSTAPD
+	if (drv->test_dir == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__);
+		return -1;
+	}
+
+	dir = opendir(drv->test_dir);
+	if (dir == NULL) {
+		perror("test_driver: opendir");
+		return -1;
+	}
+	while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		/* Skip the file if it is not a socket. Also accept
+		 * DT_UNKNOWN (0) in case the C library or underlying file
+		 * system does not support d_type. */
+		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+			continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+		if (os_strcmp(dent->d_name, ".") == 0 ||
+		    os_strcmp(dent->d_name, "..") == 0)
+			continue;
+
+		os_memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_UNIX;
+		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+			    drv->test_dir, dent->d_name);
+
+		if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0)
+			continue;
+		if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
+			   __func__, dent->d_name);
+
+		msg.msg_name = &addr;
+		msg.msg_namelen = sizeof(addr);
+		ret = sendmsg(drv->test_socket, &msg, 0);
+		if (ret < 0)
+			perror("driver_test: sendmsg(test_socket)");
+	}
+	closedir(dir);
+#else /* HOSTAPD */
+
+	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
+	    drv->test_dir == NULL) {
+		if (drv->hostapd_addr_udp_set) {
+			msg.msg_name = &drv->hostapd_addr_udp;
+			msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+		} else {
+#ifdef DRIVER_TEST_UNIX
+			msg.msg_name = &drv->hostapd_addr;
+			msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+		}
+	} else if (broadcast) {
+		dir = opendir(drv->test_dir);
+		if (dir == NULL)
+			return -1;
+		while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+			/* Skip the file if it is not a socket.
+			 * Also accept DT_UNKNOWN (0) in case
+			 * the C library or underlying file
+			 * system does not support d_type. */
+			if (dent->d_type != DT_SOCK &&
+			    dent->d_type != DT_UNKNOWN)
+				continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+			if (os_strcmp(dent->d_name, ".") == 0 ||
+			    os_strcmp(dent->d_name, "..") == 0)
+				continue;
+			wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
+				   __func__, dent->d_name);
+			os_memset(&addr, 0, sizeof(addr));
+			addr.sun_family = AF_UNIX;
+			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+				    "%s/%s", drv->test_dir, dent->d_name);
+
+			msg.msg_name = &addr;
+			msg.msg_namelen = sizeof(addr);
+
+			ret = sendmsg(drv->test_socket, &msg, 0);
+			if (ret < 0)
+				perror("driver_test: sendmsg(test_socket)");
+		}
+		closedir(dir);
+		return ret;
+	} else {
+		struct stat st;
+		os_memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_UNIX;
+		os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+			    "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
+		if (stat(addr.sun_path, &st) < 0) {
+			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+				    "%s/STA-" MACSTR,
+				    drv->test_dir, MAC2STR(dest));
+		}
+		msg.msg_name = &addr;
+		msg.msg_namelen = sizeof(addr);
+	}
+
+	if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+		perror("sendmsg(test_socket)");
+		return -1;
+	}
+#endif /* HOSTAPD */
+
+	hdr = (struct ieee80211_hdr *) data;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = data;
+	event.tx_status.data_len = data_len;
+	event.tx_status.ack = ret >= 0;
+	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+
+#ifdef CONFIG_P2P
+	if (drv->p2p &&
+	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+		if (drv->pending_action_tx == NULL) {
+			wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
+				   "no pending operation");
+			return ret;
+		}
+
+		if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) !=
+		    0) {
+			wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - "
+				   "unknown destination address");
+			return ret;
+		}
+
+		wpabuf_free(drv->pending_action_tx);
+		drv->pending_action_tx = NULL;
+
+		p2p_send_action_cb(drv->p2p, drv->pending_action_freq,
+				   drv->pending_action_dst,
+				   drv->pending_action_src,
+				   drv->pending_action_bssid,
+				   ret >= 0);
+	}
+#endif /* CONFIG_P2P */
+
+	return ret;
+}
+
+
+static void test_driver_scan(struct wpa_driver_test_data *drv,
+			     struct sockaddr_un *from, socklen_t fromlen,
+			     char *data)
+{
+	char buf[512], *pos, *end;
+	int ret;
+	struct test_driver_bss *bss;
+	u8 sa[ETH_ALEN];
+	u8 ie[512];
+	size_t ielen;
+	union wpa_event_data event;
+
+	/* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
+
+	wpa_printf(MSG_DEBUG, "test_driver: SCAN");
+
+	if (*data) {
+		if (*data != ' ' ||
+		    hwaddr_aton(data + 1, sa)) {
+			wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
+				   "command format");
+			return;
+		}
+
+		data += 18;
+		while (*data == ' ')
+			data++;
+		ielen = os_strlen(data) / 2;
+		if (ielen > sizeof(ie))
+			ielen = sizeof(ie);
+		if (hexstr2bin(data, ie, ielen) < 0)
+			ielen = 0;
+
+		wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
+			   MAC2STR(sa));
+		wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
+
+		os_memset(&event, 0, sizeof(event));
+		event.rx_probe_req.sa = sa;
+		event.rx_probe_req.ie = ie;
+		event.rx_probe_req.ie_len = ielen;
+		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
+#ifdef CONFIG_P2P
+		if (drv->p2p)
+			p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
+#endif /* CONFIG_P2P */
+	}
+
+	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
+		pos = buf;
+		end = buf + sizeof(buf);
+
+		/* reply: SCANRESP BSSID SSID IEs */
+		ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+			       MAC2STR(bss->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos,
+					bss->ssid, bss->ssid_len);
+		ret = snprintf(pos, end - pos, " ");
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
+		pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
+					bss->wps_probe_resp_ie_len);
+
+		if (bss->privacy) {
+			ret = snprintf(pos, end - pos, " PRIVACY");
+			if (ret < 0 || ret >= end - pos)
+				return;
+			pos += ret;
+		}
+
+		sendto(drv->test_socket, buf, pos - buf, 0,
+		       (struct sockaddr *) from, fromlen);
+	}
+}
+
+
+static void test_driver_assoc(struct wpa_driver_test_data *drv,
+			      struct sockaddr_un *from, socklen_t fromlen,
+			      char *data)
+{
+	struct test_client_socket *cli;
+	u8 ie[256], ssid[32];
+	size_t ielen, ssid_len = 0;
+	char *pos, *pos2, cmd[50];
+	struct test_driver_bss *bss, *tmp;
+
+	/* data: STA-addr SSID(hex) IEs(hex) */
+
+	cli = os_zalloc(sizeof(*cli));
+	if (cli == NULL)
+		return;
+
+	if (hwaddr_aton(data, cli->addr)) {
+		printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
+		       data);
+		os_free(cli);
+		return;
+	}
+	pos = data + 17;
+	while (*pos == ' ')
+		pos++;
+	pos2 = strchr(pos, ' ');
+	ielen = 0;
+	if (pos2) {
+		ssid_len = (pos2 - pos) / 2;
+		if (hexstr2bin(pos, ssid, ssid_len) < 0) {
+			wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
+			os_free(cli);
+			return;
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
+				  ssid, ssid_len);
+
+		pos = pos2 + 1;
+		ielen = strlen(pos) / 2;
+		if (ielen > sizeof(ie))
+			ielen = sizeof(ie);
+		if (hexstr2bin(pos, ie, ielen) < 0)
+			ielen = 0;
+	}
+
+	bss = NULL;
+	dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) {
+		if (tmp->ssid_len == ssid_len &&
+		    os_memcmp(tmp->ssid, ssid, ssid_len) == 0) {
+			bss = tmp;
+			break;
+		}
+	}
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
+			   "configured BSSes", __func__);
+		os_free(cli);
+		return;
+	}
+
+	cli->bss = bss;
+	memcpy(&cli->un, from, sizeof(cli->un));
+	cli->unlen = fromlen;
+	cli->next = drv->cli;
+	drv->cli = cli;
+	wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
+			  (const u8 *) cli->un.sun_path,
+			  cli->unlen - sizeof(cli->un.sun_family));
+
+	snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
+		 MAC2STR(bss->bssid));
+	sendto(drv->test_socket, cmd, strlen(cmd), 0,
+	       (struct sockaddr *) from, fromlen);
+
+	drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0);
+}
+
+
+static void test_driver_disassoc(struct wpa_driver_test_data *drv,
+				 struct sockaddr_un *from, socklen_t fromlen)
+{
+	struct test_client_socket *cli;
+
+	cli = test_driver_get_cli(drv, from, fromlen);
+	if (!cli)
+		return;
+
+	drv_event_disassoc(drv->ctx, cli->addr);
+}
+
+
+static void test_driver_eapol(struct wpa_driver_test_data *drv,
+			      struct sockaddr_un *from, socklen_t fromlen,
+			      u8 *data, size_t datalen)
+{
+#ifdef HOSTAPD
+	struct test_client_socket *cli;
+#endif /* HOSTAPD */
+	const u8 *src = NULL;
+
+	if (datalen > 14) {
+		/* Skip Ethernet header */
+		src = data + ETH_ALEN;
+		wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
+			   MACSTR " proto=%04x",
+			   MAC2STR(data), MAC2STR(src),
+			   WPA_GET_BE16(data + 2 * ETH_ALEN));
+		data += 14;
+		datalen -= 14;
+	}
+
+#ifdef HOSTAPD
+	cli = test_driver_get_cli(drv, from, fromlen);
+	if (cli) {
+		drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data,
+				   datalen);
+	} else {
+		wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
+			   "client");
+	}
+#else /* HOSTAPD */
+	if (src)
+		drv_event_eapol_rx(drv->ctx, src, data, datalen);
+#endif /* HOSTAPD */
+}
+
+
+static void test_driver_ether(struct wpa_driver_test_data *drv,
+			      struct sockaddr_un *from, socklen_t fromlen,
+			      u8 *data, size_t datalen)
+{
+	struct l2_ethhdr *eth;
+
+	if (datalen < sizeof(*eth))
+		return;
+
+	eth = (struct l2_ethhdr *) data;
+	wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
+		   MACSTR " proto=%04x",
+		   MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
+		   be_to_host16(eth->h_proto));
+
+#ifdef CONFIG_IEEE80211R
+	if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
+		union wpa_event_data ev;
+		os_memset(&ev, 0, sizeof(ev));
+		ev.ft_rrb_rx.src = eth->h_source;
+		ev.ft_rrb_rx.data = data + sizeof(*eth);
+		ev.ft_rrb_rx.data_len = datalen - sizeof(*eth);
+	}
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+static void test_driver_mlme(struct wpa_driver_test_data *drv,
+			     struct sockaddr_un *from, socklen_t fromlen,
+			     u8 *data, size_t datalen)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+	int freq = 0, own_freq;
+	struct test_driver_bss *bss;
+
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+	if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
+		size_t pos;
+		for (pos = 5; pos < datalen; pos++) {
+			if (data[pos] == ' ')
+				break;
+		}
+		if (pos < datalen) {
+			freq = atoi((const char *) &data[5]);
+			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+				   "freq %d MHz", bss->ifname, freq);
+			pos++;
+			data += pos;
+			datalen -= pos;
+		}
+	}
+
+	if (drv->remain_on_channel_freq)
+		own_freq = drv->remain_on_channel_freq;
+	else
+		own_freq = drv->current_freq;
+
+	if (freq && own_freq && freq != own_freq) {
+		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+			   "another frequency %d MHz (own %d MHz)",
+			   bss->ifname, freq, own_freq);
+		return;
+	}
+
+	hdr = (struct ieee80211_hdr *) data;
+
+	if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
+		struct test_client_socket *cli;
+		cli = os_zalloc(sizeof(*cli));
+		if (cli == NULL)
+			return;
+		wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
+			   MAC2STR(hdr->addr2));
+		memcpy(cli->addr, hdr->addr2, ETH_ALEN);
+		memcpy(&cli->un, from, sizeof(cli->un));
+		cli->unlen = fromlen;
+		cli->next = drv->cli;
+		drv->cli = cli;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
+		    data, datalen);
+	fc = le_to_host16(hdr->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
+		wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
+			   __func__);
+		return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_mgmt.frame = data;
+	event.rx_mgmt.frame_len = datalen;
+	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+	char buf[2000];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(test_socket)");
+		return;
+	}
+	buf[res] = '\0';
+
+	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+	if (strncmp(buf, "SCAN", 4) == 0) {
+		test_driver_scan(drv, &from, fromlen, buf + 4);
+	} else if (strncmp(buf, "ASSOC ", 6) == 0) {
+		test_driver_assoc(drv, &from, fromlen, buf + 6);
+	} else if (strcmp(buf, "DISASSOC") == 0) {
+		test_driver_disassoc(drv, &from, fromlen);
+	} else if (strncmp(buf, "EAPOL ", 6) == 0) {
+		test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
+				  res - 6);
+	} else if (strncmp(buf, "ETHER ", 6) == 0) {
+		test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
+				  res - 6);
+	} else if (strncmp(buf, "MLME ", 5) == 0) {
+		test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
+	} else {
+		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+				  (u8 *) buf, res);
+	}
+}
+
+
+static int test_driver_set_generic_elem(void *priv,
+					const u8 *elem, size_t elem_len)
+{
+	struct test_driver_bss *bss = priv;
+
+	os_free(bss->ie);
+
+	if (elem == NULL) {
+		bss->ie = NULL;
+		bss->ielen = 0;
+		return 0;
+	}
+
+	bss->ie = os_malloc(elem_len);
+	if (bss->ie == NULL) {
+		bss->ielen = 0;
+		return -1;
+	}
+
+	memcpy(bss->ie, elem, elem_len);
+	bss->ielen = elem_len;
+	return 0;
+}
+
+
+static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+				     const struct wpabuf *proberesp,
+				     const struct wpabuf *assocresp)
+{
+	struct test_driver_bss *bss = priv;
+
+	if (beacon == NULL)
+		wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
+	else
+		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
+				beacon);
+
+	os_free(bss->wps_beacon_ie);
+
+	if (beacon == NULL) {
+		bss->wps_beacon_ie = NULL;
+		bss->wps_beacon_ie_len = 0;
+	} else {
+		bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
+		if (bss->wps_beacon_ie == NULL) {
+			bss->wps_beacon_ie_len = 0;
+			return -1;
+		}
+
+		os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
+			  wpabuf_len(beacon));
+		bss->wps_beacon_ie_len = wpabuf_len(beacon);
+	}
+
+	if (proberesp == NULL)
+		wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
+			   "IE");
+	else
+		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
+				"IE", proberesp);
+
+	os_free(bss->wps_probe_resp_ie);
+
+	if (proberesp == NULL) {
+		bss->wps_probe_resp_ie = NULL;
+		bss->wps_probe_resp_ie_len = 0;
+	} else {
+		bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
+		if (bss->wps_probe_resp_ie == NULL) {
+			bss->wps_probe_resp_ie_len = 0;
+			return -1;
+		}
+
+		os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
+			  wpabuf_len(proberesp));
+		bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
+	}
+
+	return 0;
+}
+
+
+static int test_driver_sta_deauth(void *priv, const u8 *own_addr,
+				  const u8 *addr, int reason)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_client_socket *cli;
+
+	if (drv->test_socket < 0)
+		return -1;
+
+	cli = drv->cli;
+	while (cli) {
+		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+			break;
+		cli = cli->next;
+	}
+
+	if (!cli)
+		return -1;
+
+	return sendto(drv->test_socket, "DEAUTH", 6, 0,
+		      (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static int test_driver_sta_disassoc(void *priv, const u8 *own_addr,
+				    const u8 *addr, int reason)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_client_socket *cli;
+
+	if (drv->test_socket < 0)
+		return -1;
+
+	cli = drv->cli;
+	while (cli) {
+		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+			break;
+		cli = cli->next;
+	}
+
+	if (!cli)
+		return -1;
+
+	return sendto(drv->test_socket, "DISASSOC", 8, 0,
+		      (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
+			       void *bss_ctx, void **drv_priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_driver_bss *bss;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
+		   __func__, ifname, MAC2STR(bssid));
+
+	bss = os_zalloc(sizeof(*bss));
+	if (bss == NULL)
+		return -1;
+
+	bss->bss_ctx = bss_ctx;
+	bss->drv = drv;
+	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
+	os_memcpy(bss->bssid, bssid, ETH_ALEN);
+
+	dl_list_add(&drv->bss, &bss->list);
+	if (drv->global) {
+		drv->global->bss_add_used = 1;
+		os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
+	}
+
+	if (drv_priv)
+		*drv_priv = bss;
+
+	return 0;
+}
+
+
+static int test_driver_bss_remove(void *priv, const char *ifname)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_driver_bss *bss;
+	struct test_client_socket *cli, *prev_c;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+
+	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
+		if (strcmp(bss->ifname, ifname) != 0)
+			continue;
+
+		for (prev_c = NULL, cli = drv->cli; cli;
+		     prev_c = cli, cli = cli->next) {
+			if (cli->bss != bss)
+				continue;
+			if (prev_c)
+				prev_c->next = cli->next;
+			else
+				drv->cli = cli->next;
+			os_free(cli);
+			break;
+		}
+
+		dl_list_del(&bss->list);
+		test_driver_free_bss(bss);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static int test_driver_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)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+
+	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)",
+		   __func__, type, ifname, bss_ctx);
+	if (addr)
+		os_memcpy(if_addr, addr, ETH_ALEN);
+	else {
+		drv->alloc_iface_idx++;
+		if_addr[0] = 0x02; /* locally administered */
+		sha1_prf(drv->own_addr, ETH_ALEN,
+			 "hostapd test addr generation",
+			 (const u8 *) &drv->alloc_iface_idx,
+			 sizeof(drv->alloc_iface_idx),
+			 if_addr + 1, ETH_ALEN - 1);
+	}
+	if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
+	    type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
+		return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
+					   drv_priv);
+	return 0;
+}
+
+
+static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
+				 const char *ifname)
+{
+	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+	if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
+	    type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
+		return test_driver_bss_remove(priv, ifname);
+	return 0;
+}
+
+
+static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
+{
+	struct test_driver_bss *bss = priv;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
+	if (len < 0)
+		return -1;
+	wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
+
+	if ((size_t) len > sizeof(bss->ssid))
+		return -1;
+
+	os_memcpy(bss->ssid, buf, len);
+	bss->ssid_len = len;
+
+	return 0;
+}
+
+
+static int test_driver_set_privacy(void *priv, int enabled)
+{
+	struct test_driver_bss *dbss = priv;
+
+	wpa_printf(MSG_DEBUG, "%s(enabled=%d)",  __func__, enabled);
+	dbss->privacy = enabled;
+
+	return 0;
+}
+
+
+static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
+				    const char *ifname, int vlan_id)
+{
+	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
+		   __func__, MAC2STR(addr), ifname, vlan_id);
+	return 0;
+}
+
+
+static int test_driver_sta_add(void *priv,
+			       struct hostapd_sta_add_params *params)
+{
+	struct test_driver_bss *bss = priv;
+	struct wpa_driver_test_data *drv = bss->drv;
+	struct test_client_socket *cli;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
+		   "capability=0x%x listen_interval=%d)",
+		   __func__, bss->ifname, MAC2STR(params->addr), params->aid,
+		   params->capability, params->listen_interval);
+	wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
+		    params->supp_rates, params->supp_rates_len);
+
+	cli = drv->cli;
+	while (cli) {
+		if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0)
+			break;
+		cli = cli->next;
+	}
+	if (!cli) {
+		wpa_printf(MSG_DEBUG, "%s: no matching client entry",
+			   __func__);
+		return -1;
+	}
+
+	cli->bss = bss;
+
+	return 0;
+}
+
+
+static struct wpa_driver_test_data * test_alloc_data(void *ctx,
+						     const char *ifname)
+{
+	struct wpa_driver_test_data *drv;
+	struct test_driver_bss *bss;
+
+	drv = os_zalloc(sizeof(struct wpa_driver_test_data));
+	if (drv == NULL) {
+		wpa_printf(MSG_ERROR, "Could not allocate memory for test "
+			   "driver data");
+		return NULL;
+	}
+
+	bss = os_zalloc(sizeof(struct test_driver_bss));
+	if (bss == NULL) {
+		os_free(drv);
+		return NULL;
+	}
+
+	drv->ctx = ctx;
+	wpa_trace_add_ref(drv, ctx, ctx);
+	dl_list_init(&drv->bss);
+	dl_list_add(&drv->bss, &bss->list);
+	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
+	bss->bss_ctx = ctx;
+	bss->drv = drv;
+
+	/* Generate a MAC address to help testing with multiple STAs */
+	drv->own_addr[0] = 0x02; /* locally administered */
+	sha1_prf((const u8 *) ifname, os_strlen(ifname),
+		 "test mac addr generation",
+		 NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+
+	return drv;
+}
+
+
+static void * test_driver_init(struct hostapd_data *hapd,
+			       struct wpa_init_params *params)
+{
+	struct wpa_driver_test_data *drv;
+	struct sockaddr_un addr_un;
+	struct sockaddr_in addr_in;
+	struct sockaddr *addr;
+	socklen_t alen;
+	struct test_driver_bss *bss;
+
+	drv = test_alloc_data(hapd, params->ifname);
+	if (drv == NULL)
+		return NULL;
+	drv->ap = 1;
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+	drv->global = params->global_priv;
+
+	bss->bss_ctx = hapd;
+	os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
+	os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
+
+	if (params->test_socket) {
+		if (os_strlen(params->test_socket) >=
+		    sizeof(addr_un.sun_path)) {
+			printf("Too long test_socket path\n");
+			wpa_driver_test_deinit(bss);
+			return NULL;
+		}
+		if (strncmp(params->test_socket, "DIR:", 4) == 0) {
+			size_t len = strlen(params->test_socket) + 30;
+			drv->test_dir = os_strdup(params->test_socket + 4);
+			drv->own_socket_path = os_malloc(len);
+			if (drv->own_socket_path) {
+				snprintf(drv->own_socket_path, len,
+					 "%s/AP-" MACSTR,
+					 params->test_socket + 4,
+					 MAC2STR(params->own_addr));
+			}
+		} else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
+			drv->udp_port = atoi(params->test_socket + 4);
+		} else {
+			drv->own_socket_path = os_strdup(params->test_socket);
+		}
+		if (drv->own_socket_path == NULL && drv->udp_port == 0) {
+			wpa_driver_test_deinit(bss);
+			return NULL;
+		}
+
+		drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
+					  SOCK_DGRAM, 0);
+		if (drv->test_socket < 0) {
+			perror("socket");
+			wpa_driver_test_deinit(bss);
+			return NULL;
+		}
+
+		if (drv->udp_port) {
+			os_memset(&addr_in, 0, sizeof(addr_in));
+			addr_in.sin_family = AF_INET;
+			addr_in.sin_port = htons(drv->udp_port);
+			addr = (struct sockaddr *) &addr_in;
+			alen = sizeof(addr_in);
+		} else {
+			os_memset(&addr_un, 0, sizeof(addr_un));
+			addr_un.sun_family = AF_UNIX;
+			os_strlcpy(addr_un.sun_path, drv->own_socket_path,
+				   sizeof(addr_un.sun_path));
+			addr = (struct sockaddr *) &addr_un;
+			alen = sizeof(addr_un);
+		}
+		if (bind(drv->test_socket, addr, alen) < 0) {
+			perror("test-driver-init: bind(PF_UNIX)");
+			close(drv->test_socket);
+			if (drv->own_socket_path)
+				unlink(drv->own_socket_path);
+			wpa_driver_test_deinit(bss);
+			return NULL;
+		}
+		eloop_register_read_sock(drv->test_socket,
+					 test_driver_receive_unix, drv, NULL);
+	} else
+		drv->test_socket = -1;
+
+	return bss;
+}
+
+
+static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+
+#ifdef DRIVER_TEST_UNIX
+	if (drv->associated && drv->hostapd_addr_set) {
+		struct stat st;
+		if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
+			wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
+				   __func__, strerror(errno));
+			drv->associated = 0;
+			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+		}
+	}
+#endif /* DRIVER_TEST_UNIX */
+
+	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+}
+
+
+static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+	if (drv->pending_p2p_scan && drv->p2p) {
+#ifdef CONFIG_P2P
+		size_t i;
+		for (i = 0; i < drv->num_scanres; i++) {
+			struct wpa_scan_res *bss = drv->scanres[i];
+			if (p2p_scan_res_handler(drv->p2p, bss->bssid,
+						 bss->freq, bss->age,
+						 bss->level,
+						 (const u8 *) (bss + 1),
+						 bss->ie_len) > 0)
+				return;
+		}
+		p2p_scan_res_handled(drv->p2p);
+#endif /* CONFIG_P2P */
+		return;
+	}
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+#ifdef DRIVER_TEST_UNIX
+static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
+				const char *path)
+{
+	struct dirent *dent;
+	DIR *dir;
+	struct sockaddr_un addr;
+	char cmd[512], *pos, *end;
+	int ret;
+
+	dir = opendir(path);
+	if (dir == NULL)
+		return;
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
+			  MAC2STR(drv->own_addr));
+	if (ret >= 0 && ret < end - pos)
+		pos += ret;
+	if (drv->probe_req_ie) {
+		ret = os_snprintf(pos, end - pos, " ");
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
+					drv->probe_req_ie_len);
+	}
+	if (drv->probe_req_ssid_len) {
+		/* Add SSID IE */
+		ret = os_snprintf(pos, end - pos, "%02x%02x",
+				  WLAN_EID_SSID,
+				  (unsigned int) drv->probe_req_ssid_len);
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid,
+					drv->probe_req_ssid_len);
+	}
+	end[-1] = '\0';
+
+	while ((dent = readdir(dir))) {
+		if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
+		    os_strncmp(dent->d_name, "STA-", 4) != 0)
+			continue;
+		if (drv->own_socket_path) {
+			size_t olen, dlen;
+			olen = os_strlen(drv->own_socket_path);
+			dlen = os_strlen(dent->d_name);
+			if (olen >= dlen &&
+			    os_strcmp(dent->d_name,
+				      drv->own_socket_path + olen - dlen) == 0)
+				continue;
+		}
+		wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
+
+		os_memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_UNIX;
+		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+			    path, dent->d_name);
+
+		if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+			   (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			perror("sendto(test_socket)");
+		}
+	}
+	closedir(dir);
+}
+#endif /* DRIVER_TEST_UNIX */
+
+
+static int wpa_driver_test_scan(void *priv,
+				struct wpa_driver_scan_params *params)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	size_t i;
+
+	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+
+	os_free(drv->probe_req_ie);
+	if (params->extra_ies) {
+		drv->probe_req_ie = os_malloc(params->extra_ies_len);
+		if (drv->probe_req_ie == NULL) {
+			drv->probe_req_ie_len = 0;
+			return -1;
+		}
+		os_memcpy(drv->probe_req_ie, params->extra_ies,
+			  params->extra_ies_len);
+		drv->probe_req_ie_len = params->extra_ies_len;
+	} else {
+		drv->probe_req_ie = NULL;
+		drv->probe_req_ie_len = 0;
+	}
+
+	for (i = 0; i < params->num_ssids; i++)
+		wpa_hexdump(MSG_DEBUG, "Scan SSID",
+			    params->ssids[i].ssid, params->ssids[i].ssid_len);
+	drv->probe_req_ssid_len = 0;
+	if (params->num_ssids) {
+		os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid,
+			  params->ssids[0].ssid_len);
+		drv->probe_req_ssid_len = params->ssids[0].ssid_len;
+	}
+	wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
+		    params->extra_ies, params->extra_ies_len);
+
+	drv->num_scanres = 0;
+
+#ifdef DRIVER_TEST_UNIX
+	if (drv->test_socket >= 0 && drv->test_dir)
+		wpa_driver_scan_dir(drv, drv->test_dir);
+
+	if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
+	    sendto(drv->test_socket, "SCAN", 4, 0,
+		   (struct sockaddr *) &drv->hostapd_addr,
+		   sizeof(drv->hostapd_addr)) < 0) {
+		perror("sendto(test_socket)");
+	}
+#endif /* DRIVER_TEST_UNIX */
+
+	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+	    sendto(drv->test_socket, "SCAN", 4, 0,
+		   (struct sockaddr *) &drv->hostapd_addr_udp,
+		   sizeof(drv->hostapd_addr_udp)) < 0) {
+		perror("sendto(test_socket)");
+	}
+
+	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
+			       drv->ctx);
+	return 0;
+}
+
+
+static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct wpa_scan_results *res;
+	size_t i;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL)
+		return NULL;
+
+	res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
+	if (res->res == NULL) {
+		os_free(res);
+		return NULL;
+	}
+
+	for (i = 0; i < drv->num_scanres; i++) {
+		struct wpa_scan_res *r;
+		if (drv->scanres[i] == NULL)
+			continue;
+		r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
+		if (r == NULL)
+			break;
+		os_memcpy(r, drv->scanres[i],
+			  sizeof(*r) + drv->scanres[i]->ie_len);
+		res->res[res->num++] = r;
+	}
+
+	return res;
+}
+
+
+static int wpa_driver_test_set_key(const char *ifname, void *priv,
+				   enum wpa_alg alg, const u8 *addr,
+				   int key_idx, int set_tx,
+				   const u8 *seq, size_t seq_len,
+				   const u8 *key, size_t key_len)
+{
+	wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d "
+		   "set_tx=%d",
+		   __func__, ifname, priv, alg, key_idx, set_tx);
+	if (addr)
+		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
+	if (seq)
+		wpa_hexdump(MSG_DEBUG, "   seq", seq, seq_len);
+	if (key)
+		wpa_hexdump_key(MSG_DEBUG, "   key", key, key_len);
+	return 0;
+}
+
+
+static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap)
+{
+	if (ap && !drv->ap) {
+		wpa_driver_test_close_test_socket(drv);
+		wpa_driver_test_attach(drv, drv->test_dir, 1);
+		drv->ap = 1;
+	} else if (!ap && drv->ap) {
+		wpa_driver_test_close_test_socket(drv);
+		wpa_driver_test_attach(drv, drv->test_dir, 0);
+		drv->ap = 0;
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_test_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+		   __func__, priv, params->freq, params->pairwise_suite,
+		   params->group_suite, params->key_mgmt_suite,
+		   params->auth_alg, params->mode);
+	wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
+	if (params->bssid) {
+		wpa_printf(MSG_DEBUG, "   bssid=" MACSTR,
+			   MAC2STR(params->bssid));
+	}
+	if (params->ssid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "   ssid",
+				  params->ssid, params->ssid_len);
+	}
+	if (params->wpa_ie) {
+		wpa_hexdump(MSG_DEBUG, "   wpa_ie",
+			    params->wpa_ie, params->wpa_ie_len);
+		drv->assoc_wpa_ie_len = params->wpa_ie_len;
+		if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
+			drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
+		os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
+			  drv->assoc_wpa_ie_len);
+	} else
+		drv->assoc_wpa_ie_len = 0;
+
+	wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
+
+	drv->ibss = params->mode == IEEE80211_MODE_IBSS;
+	dbss->privacy = params->key_mgmt_suite &
+		(WPA_KEY_MGMT_IEEE8021X |
+		 WPA_KEY_MGMT_PSK |
+		 WPA_KEY_MGMT_WPA_NONE |
+		 WPA_KEY_MGMT_FT_IEEE8021X |
+		 WPA_KEY_MGMT_FT_PSK |
+		 WPA_KEY_MGMT_IEEE8021X_SHA256 |
+		 WPA_KEY_MGMT_PSK_SHA256);
+	if (params->wep_key_len[params->wep_tx_keyidx])
+		dbss->privacy = 1;
+
+#ifdef DRIVER_TEST_UNIX
+	if (drv->test_dir && params->bssid &&
+	    params->mode != IEEE80211_MODE_IBSS) {
+		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+		drv->hostapd_addr.sun_family = AF_UNIX;
+		os_snprintf(drv->hostapd_addr.sun_path,
+			    sizeof(drv->hostapd_addr.sun_path),
+			    "%s/AP-" MACSTR,
+			    drv->test_dir, MAC2STR(params->bssid));
+		drv->hostapd_addr_set = 1;
+	}
+#endif /* DRIVER_TEST_UNIX */
+
+	if (params->mode == IEEE80211_MODE_AP) {
+		os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+		dbss->ssid_len = params->ssid_len;
+		os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN);
+		if (params->wpa_ie && params->wpa_ie_len) {
+			dbss->ie = os_malloc(params->wpa_ie_len);
+			if (dbss->ie) {
+				os_memcpy(dbss->ie, params->wpa_ie,
+					  params->wpa_ie_len);
+				dbss->ielen = params->wpa_ie_len;
+			}
+		}
+	} else if (drv->test_socket >= 0 &&
+		   (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
+		char cmd[200], *pos, *end;
+		int ret;
+		end = cmd + sizeof(cmd);
+		pos = cmd;
+		ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
+				  MAC2STR(drv->own_addr));
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
+					params->ssid_len);
+		ret = os_snprintf(pos, end - pos, " ");
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
+					params->wpa_ie_len);
+		end[-1] = '\0';
+#ifdef DRIVER_TEST_UNIX
+		if (drv->hostapd_addr_set &&
+		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+			   (struct sockaddr *) &drv->hostapd_addr,
+			   sizeof(drv->hostapd_addr)) < 0) {
+			perror("sendto(test_socket)");
+			return -1;
+		}
+#endif /* DRIVER_TEST_UNIX */
+		if (drv->hostapd_addr_udp_set &&
+		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+			   (struct sockaddr *) &drv->hostapd_addr_udp,
+			   sizeof(drv->hostapd_addr_udp)) < 0) {
+			perror("sendto(test_socket)");
+			return -1;
+		}
+
+		os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+		dbss->ssid_len = params->ssid_len;
+	} else {
+		drv->associated = 1;
+		if (params->mode == IEEE80211_MODE_IBSS) {
+			os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
+			dbss->ssid_len = params->ssid_len;
+			if (params->bssid)
+				os_memcpy(dbss->bssid, params->bssid,
+					  ETH_ALEN);
+			else {
+				os_get_random(dbss->bssid, ETH_ALEN);
+				dbss->bssid[0] &= ~0x01;
+				dbss->bssid[0] |= 0x02;
+			}
+		}
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
+{
+	struct test_driver_bss *dbss = priv;
+	os_memcpy(bssid, dbss->bssid, ETH_ALEN);
+	return 0;
+}
+
+
+static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
+{
+	struct test_driver_bss *dbss = priv;
+	os_memcpy(ssid, dbss->ssid, 32);
+	return dbss->ssid_len;
+}
+
+
+static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
+{
+#ifdef DRIVER_TEST_UNIX
+	if (drv->test_socket >= 0 &&
+	    sendto(drv->test_socket, "DISASSOC", 8, 0,
+		   (struct sockaddr *) &drv->hostapd_addr,
+		   sizeof(drv->hostapd_addr)) < 0) {
+		perror("sendto(test_socket)");
+		return -1;
+	}
+#endif /* DRIVER_TEST_UNIX */
+	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+	    sendto(drv->test_socket, "DISASSOC", 8, 0,
+		   (struct sockaddr *) &drv->hostapd_addr_udp,
+		   sizeof(drv->hostapd_addr_udp)) < 0) {
+		perror("sendto(test_socket)");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
+					  int reason_code)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+		   __func__, MAC2STR(addr), reason_code);
+	os_memset(dbss->bssid, 0, ETH_ALEN);
+	drv->associated = 0;
+	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+	return wpa_driver_test_send_disassoc(drv);
+}
+
+
+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;
+}
+
+
+static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
+				     struct sockaddr *from,
+				     socklen_t fromlen,
+				     const char *data)
+{
+	struct wpa_scan_res *res;
+	const char *pos, *pos2;
+	size_t len;
+	u8 *ie_pos, *ie_start, *ie_end;
+#define MAX_IE_LEN 1000
+	const u8 *ds_params;
+
+	wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
+	if (drv->num_scanres >= MAX_SCAN_RESULTS) {
+		wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
+			   "result");
+		return;
+	}
+
+	/* SCANRESP BSSID SSID IEs */
+
+	res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
+	if (res == NULL)
+		return;
+	ie_start = ie_pos = (u8 *) (res + 1);
+	ie_end = ie_pos + MAX_IE_LEN;
+
+	if (hwaddr_aton(data, res->bssid)) {
+		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
+		os_free(res);
+		return;
+	}
+
+	pos = data + 17;
+	while (*pos == ' ')
+		pos++;
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL) {
+		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
+			   "in scanres");
+		os_free(res);
+		return;
+	}
+	len = (pos2 - pos) / 2;
+	if (len > 32)
+		len = 32;
+	/*
+	 * Generate SSID IE from the SSID field since this IE is not included
+	 * in the main IE field.
+	 */
+	*ie_pos++ = WLAN_EID_SSID;
+	*ie_pos++ = len;
+	if (hexstr2bin(pos, ie_pos, len) < 0) {
+		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
+		os_free(res);
+		return;
+	}
+	ie_pos += len;
+
+	pos = pos2 + 1;
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL)
+		len = os_strlen(pos) / 2;
+	else
+		len = (pos2 - pos) / 2;
+	if ((int) len > ie_end - ie_pos)
+		len = ie_end - ie_pos;
+	if (hexstr2bin(pos, ie_pos, len) < 0) {
+		wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
+		os_free(res);
+		return;
+	}
+	ie_pos += len;
+	res->ie_len = ie_pos - ie_start;
+
+	if (pos2) {
+		pos = pos2 + 1;
+		while (*pos == ' ')
+			pos++;
+		if (os_strstr(pos, "PRIVACY"))
+			res->caps |= IEEE80211_CAP_PRIVACY;
+		if (os_strstr(pos, "IBSS"))
+			res->caps |= IEEE80211_CAP_IBSS;
+	}
+
+	ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS);
+	if (ds_params && ds_params[1] > 0) {
+		if (ds_params[2] >= 1 && ds_params[2] <= 13)
+			res->freq = 2407 + ds_params[2] * 5;
+	}
+
+	os_free(drv->scanres[drv->num_scanres]);
+	drv->scanres[drv->num_scanres++] = res;
+}
+
+
+static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
+				      struct sockaddr *from,
+				      socklen_t fromlen,
+				      const char *data)
+{
+	struct test_driver_bss *bss;
+
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+	/* ASSOCRESP BSSID <res> */
+	if (hwaddr_aton(data, bss->bssid)) {
+		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
+			   "assocresp");
+	}
+	if (drv->use_associnfo) {
+		union wpa_event_data event;
+		os_memset(&event, 0, sizeof(event));
+		event.assoc_info.req_ies = drv->assoc_wpa_ie;
+		event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
+	}
+	drv->associated = 1;
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
+				     struct sockaddr *from,
+				     socklen_t fromlen)
+{
+	drv->associated = 0;
+	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+}
+
+
+static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
+				  struct sockaddr *from,
+				  socklen_t fromlen,
+				  const u8 *data, size_t data_len)
+{
+	const u8 *src;
+	struct test_driver_bss *bss;
+
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+	if (data_len > 14) {
+		/* Skip Ethernet header */
+		src = data + ETH_ALEN;
+		data += 14;
+		data_len -= 14;
+	} else
+		src = bss->bssid;
+
+	drv_event_eapol_rx(drv->ctx, src, data, data_len);
+}
+
+
+static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
+				 struct sockaddr *from,
+				 socklen_t fromlen,
+				 const u8 *data, size_t data_len)
+{
+	int freq = 0, own_freq;
+	union wpa_event_data event;
+	const struct ieee80211_mgmt *mgmt;
+	u16 fc;
+	struct test_driver_bss *bss;
+
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+	if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
+		size_t pos;
+		for (pos = 5; pos < data_len; pos++) {
+			if (data[pos] == ' ')
+				break;
+		}
+		if (pos < data_len) {
+			freq = atoi((const char *) &data[5]);
+			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+				   "freq %d MHz", bss->ifname, freq);
+			pos++;
+			data += pos;
+			data_len -= pos;
+		}
+	}
+
+	if (drv->remain_on_channel_freq)
+		own_freq = drv->remain_on_channel_freq;
+	else
+		own_freq = drv->current_freq;
+
+	if (freq && own_freq && freq != own_freq) {
+		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+			   "another frequency %d MHz (own %d MHz)",
+			   bss->ifname, freq, own_freq);
+		return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	event.mlme_rx.buf = data;
+	event.mlme_rx.len = data_len;
+	event.mlme_rx.freq = freq;
+	wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
+
+	mgmt = (const struct ieee80211_mgmt *) data;
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (drv->probe_req_report && data_len >= 24) {
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
+			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 =
+				data_len - (mgmt->u.probe_req.variable - data);
+			wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
+					     &event);
+#ifdef CONFIG_P2P
+			if (drv->p2p)
+				p2p_probe_req_rx(drv->p2p, mgmt->sa,
+						 mgmt->da, mgmt->bssid,
+						 event.rx_probe_req.ie,
+						 event.rx_probe_req.ie_len);
+#endif /* CONFIG_P2P */
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if (drv->p2p &&
+	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+		size_t hdr_len;
+		hdr_len = (const u8 *)
+			&mgmt->u.action.u.vs_public_action.action - data;
+		p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
+			      mgmt->u.action.category,
+			      &mgmt->u.action.u.vs_public_action.action,
+			      data_len - hdr_len, freq);
+	}
+#endif /* CONFIG_P2P */
+
+}
+
+
+static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
+				     struct sockaddr *from,
+				     socklen_t fromlen,
+				     const u8 *data, size_t data_len)
+{
+	char buf[512], *pos, *end;
+	int ret;
+	struct test_driver_bss *bss;
+
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+
+	/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
+#ifdef CONFIG_P2P
+	if (drv->probe_req_report && drv->p2p && data_len) {
+		const char *d = (const char *) data;
+		u8 sa[ETH_ALEN];
+		u8 ie[512];
+		size_t ielen;
+
+		if (hwaddr_aton(d, sa))
+			return;
+		d += 18;
+		while (*d == ' ')
+			d++;
+		ielen = os_strlen(d) / 2;
+		if (ielen > sizeof(ie))
+			ielen = sizeof(ie);
+		if (hexstr2bin(d, ie, ielen) < 0)
+			ielen = 0;
+		drv->probe_from = from;
+		drv->probe_from_len = fromlen;
+		p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
+		drv->probe_from = NULL;
+	}
+#endif /* CONFIG_P2P */
+
+	if (!drv->ibss)
+		return;
+
+	pos = buf;
+	end = buf + sizeof(buf);
+
+	/* reply: SCANRESP BSSID SSID IEs */
+	ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+		       MAC2STR(bss->bssid));
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+	pos += wpa_snprintf_hex(pos, end - pos,
+				bss->ssid, bss->ssid_len);
+	ret = snprintf(pos, end - pos, " ");
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+	pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
+				drv->assoc_wpa_ie_len);
+
+	if (bss->privacy) {
+		ret = snprintf(pos, end - pos, " PRIVACY");
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+	}
+
+	ret = snprintf(pos, end - pos, " IBSS");
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+
+	sendto(drv->test_socket, buf, pos - buf, 0,
+	       (struct sockaddr *) from, fromlen);
+}
+
+
+static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
+					 void *sock_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+	char *buf;
+	int res;
+	struct sockaddr_storage from;
+	socklen_t fromlen = sizeof(from);
+	const size_t buflen = 2000;
+
+	if (drv->ap) {
+		test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
+		return;
+	}
+
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	res = recvfrom(sock, buf, buflen - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(test_socket)");
+		os_free(buf);
+		return;
+	}
+	buf[res] = '\0';
+
+	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+	if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
+		wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
+					 fromlen, buf + 9);
+	} else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
+		wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
+					  fromlen, buf + 10);
+	} else if (os_strcmp(buf, "DISASSOC") == 0) {
+		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+					 fromlen);
+	} else if (os_strcmp(buf, "DEAUTH") == 0) {
+		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+					 fromlen);
+	} else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
+		wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
+				      (const u8 *) buf + 6, res - 6);
+	} else if (os_strncmp(buf, "MLME ", 5) == 0) {
+		wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
+				     (const u8 *) buf + 5, res - 5);
+	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
+		wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
+					 fromlen,
+					 (const u8 *) buf + 5, res - 5);
+	} else {
+		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+				  (u8 *) buf, res);
+	}
+	os_free(buf);
+}
+
+
+static void * wpa_driver_test_init2(void *ctx, const char *ifname,
+				    void *global_priv)
+{
+	struct wpa_driver_test_data *drv;
+	struct wpa_driver_test_global *global = global_priv;
+	struct test_driver_bss *bss;
+
+	drv = test_alloc_data(ctx, ifname);
+	if (drv == NULL)
+		return NULL;
+	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
+	drv->global = global_priv;
+	drv->test_socket = -1;
+
+	/* Set dummy BSSID and SSID for testing. */
+	bss->bssid[0] = 0x02;
+	bss->bssid[1] = 0x00;
+	bss->bssid[2] = 0x00;
+	bss->bssid[3] = 0x00;
+	bss->bssid[4] = 0x00;
+	bss->bssid[5] = 0x01;
+	os_memcpy(bss->ssid, "test", 5);
+	bss->ssid_len = 4;
+
+	if (global->bss_add_used) {
+		os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
+		global->bss_add_used = 0;
+	}
+
+	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+
+	return bss;
+}
+
+
+static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
+{
+	if (drv->test_socket >= 0) {
+		eloop_unregister_read_sock(drv->test_socket);
+		close(drv->test_socket);
+		drv->test_socket = -1;
+	}
+
+	if (drv->own_socket_path) {
+		unlink(drv->own_socket_path);
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+	}
+}
+
+
+static void wpa_driver_test_deinit(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	struct test_client_socket *cli, *prev;
+	int i;
+
+#ifdef CONFIG_P2P
+	if (drv->p2p)
+		p2p_deinit(drv->p2p);
+	wpabuf_free(drv->pending_action_tx);
+#endif /* CONFIG_P2P */
+
+	cli = drv->cli;
+	while (cli) {
+		prev = cli;
+		cli = cli->next;
+		os_free(prev);
+	}
+
+#ifdef HOSTAPD
+	/* There should be only one BSS remaining at this point. */
+	if (dl_list_len(&drv->bss) != 1)
+		wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries",
+			   __func__, dl_list_len(&drv->bss));
+#endif /* HOSTAPD */
+
+	test_driver_free_bsses(drv);
+
+	wpa_driver_test_close_test_socket(drv);
+	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+	eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
+	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+	os_free(drv->test_dir);
+	for (i = 0; i < MAX_SCAN_RESULTS; i++)
+		os_free(drv->scanres[i]);
+	os_free(drv->probe_req_ie);
+	wpa_trace_remove_ref(drv, ctx, drv->ctx);
+	os_free(drv);
+}
+
+
+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
+				  const char *dir, int ap)
+{
+#ifdef DRIVER_TEST_UNIX
+	static unsigned int counter = 0;
+	struct sockaddr_un addr;
+	size_t len;
+
+	os_free(drv->own_socket_path);
+	if (dir) {
+		len = os_strlen(dir) + 30;
+		drv->own_socket_path = os_malloc(len);
+		if (drv->own_socket_path == NULL)
+			return -1;
+		os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
+			    dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
+	} else {
+		drv->own_socket_path = os_malloc(100);
+		if (drv->own_socket_path == NULL)
+			return -1;
+		os_snprintf(drv->own_socket_path, 100,
+			    "/tmp/wpa_supplicant_test-%d-%d",
+			    getpid(), counter++);
+	}
+
+	drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (drv->test_socket < 0) {
+		perror("socket(PF_UNIX)");
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+	if (bind(drv->test_socket, (struct sockaddr *) &addr,
+		 sizeof(addr)) < 0) {
+		perror("test-driver-attach: bind(PF_UNIX)");
+		close(drv->test_socket);
+		unlink(drv->own_socket_path);
+		os_free(drv->own_socket_path);
+		drv->own_socket_path = NULL;
+		return -1;
+	}
+
+	eloop_register_read_sock(drv->test_socket,
+				 wpa_driver_test_receive_unix, drv, NULL);
+
+	return 0;
+#else /* DRIVER_TEST_UNIX */
+	return -1;
+#endif /* DRIVER_TEST_UNIX */
+}
+
+
+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
+				      char *dst)
+{
+	char *pos;
+
+	pos = os_strchr(dst, ':');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
+
+	drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->test_socket < 0) {
+		perror("socket(PF_INET)");
+		return -1;
+	}
+
+	os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
+	drv->hostapd_addr_udp.sin_family = AF_INET;
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+	{
+		int a[4];
+		u8 *pos;
+		sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+		pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
+		*pos++ = a[0];
+		*pos++ = a[1];
+		*pos++ = a[2];
+		*pos++ = a[3];
+	}
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
+
+	drv->hostapd_addr_udp_set = 1;
+
+	eloop_register_read_sock(drv->test_socket,
+				 wpa_driver_test_receive_unix, drv, NULL);
+
+	return 0;
+}
+
+
+static int wpa_driver_test_set_param(void *priv, const char *param)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	const char *pos;
+
+	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+	if (param == NULL)
+		return 0;
+
+	wpa_driver_test_close_test_socket(drv);
+
+#ifdef DRIVER_TEST_UNIX
+	pos = os_strstr(param, "test_socket=");
+	if (pos) {
+		const char *pos2;
+		size_t len;
+
+		pos += 12;
+		pos2 = os_strchr(pos, ' ');
+		if (pos2)
+			len = pos2 - pos;
+		else
+			len = os_strlen(pos);
+		if (len > sizeof(drv->hostapd_addr.sun_path))
+			return -1;
+		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+		drv->hostapd_addr.sun_family = AF_UNIX;
+		os_memcpy(drv->hostapd_addr.sun_path, pos, len);
+		drv->hostapd_addr_set = 1;
+	}
+#endif /* DRIVER_TEST_UNIX */
+
+	pos = os_strstr(param, "test_dir=");
+	if (pos) {
+		char *end;
+		os_free(drv->test_dir);
+		drv->test_dir = os_strdup(pos + 9);
+		if (drv->test_dir == NULL)
+			return -1;
+		end = os_strchr(drv->test_dir, ' ');
+		if (end)
+			*end = '\0';
+		if (wpa_driver_test_attach(drv, drv->test_dir, 0))
+			return -1;
+	} else {
+		pos = os_strstr(param, "test_udp=");
+		if (pos) {
+			char *dst, *epos;
+			dst = os_strdup(pos + 9);
+			if (dst == NULL)
+				return -1;
+			epos = os_strchr(dst, ' ');
+			if (epos)
+				*epos = '\0';
+			if (wpa_driver_test_attach_udp(drv, dst))
+				return -1;
+			os_free(dst);
+		} else if (wpa_driver_test_attach(drv, NULL, 0))
+			return -1;
+	}
+
+	if (os_strstr(param, "use_associnfo=1")) {
+		wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
+		drv->use_associnfo = 1;
+	}
+
+	if (os_strstr(param, "p2p_mgmt=1")) {
+		wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
+			   "management");
+		if (wpa_driver_test_init_p2p(drv) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static const u8 * wpa_driver_test_get_mac_addr(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	return drv->own_addr;
+}
+
+
+static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
+				      const u8 *data, size_t data_len)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	char *msg;
+	size_t msg_len;
+	struct l2_ethhdr eth;
+	struct sockaddr *addr;
+	socklen_t alen;
+#ifdef DRIVER_TEST_UNIX
+	struct sockaddr_un addr_un;
+#endif /* DRIVER_TEST_UNIX */
+
+	wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
+
+	os_memset(&eth, 0, sizeof(eth));
+	os_memcpy(eth.h_dest, dest, ETH_ALEN);
+	os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
+	eth.h_proto = host_to_be16(proto);
+
+	msg_len = 6 + sizeof(eth) + data_len;
+	msg = os_malloc(msg_len);
+	if (msg == NULL)
+		return -1;
+	os_memcpy(msg, "EAPOL ", 6);
+	os_memcpy(msg + 6, &eth, sizeof(eth));
+	os_memcpy(msg + 6 + sizeof(eth), data, data_len);
+
+	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
+	    drv->test_dir == NULL) {
+		if (drv->hostapd_addr_udp_set) {
+			addr = (struct sockaddr *) &drv->hostapd_addr_udp;
+			alen = sizeof(drv->hostapd_addr_udp);
+		} else {
+#ifdef DRIVER_TEST_UNIX
+			addr = (struct sockaddr *) &drv->hostapd_addr;
+			alen = sizeof(drv->hostapd_addr);
+#else /* DRIVER_TEST_UNIX */
+			os_free(msg);
+			return -1;
+#endif /* DRIVER_TEST_UNIX */
+		}
+	} else {
+#ifdef DRIVER_TEST_UNIX
+		struct stat st;
+		os_memset(&addr_un, 0, sizeof(addr_un));
+		addr_un.sun_family = AF_UNIX;
+		os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+			    "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
+		if (stat(addr_un.sun_path, &st) < 0) {
+			os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+				    "%s/AP-" MACSTR,
+				    drv->test_dir, MAC2STR(dest));
+		}
+		addr = (struct sockaddr *) &addr_un;
+		alen = sizeof(addr_un);
+#else /* DRIVER_TEST_UNIX */
+		os_free(msg);
+		return -1;
+#endif /* DRIVER_TEST_UNIX */
+	}
+
+	if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
+		perror("sendmsg(test_socket)");
+		os_free(msg);
+		return -1;
+	}
+
+	os_free(msg);
+	return 0;
+}
+
+
+static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	os_memset(capa, 0, sizeof(*capa));
+	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
+		WPA_DRIVER_CAPA_KEY_MGMT_FT |
+		WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+		WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP |
+		WPA_DRIVER_CAPA_ENC_CCMP;
+	capa->auth = WPA_DRIVER_AUTH_OPEN |
+		WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+	if (drv->p2p)
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
+	capa->flags |= WPA_DRIVER_FLAGS_AP;
+	capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+	capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
+	capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+	capa->max_scan_ssids = 2;
+	capa->max_remain_on_chan = 60000;
+
+	return 0;
+}
+
+
+static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
+					      int protect_type,
+					      int key_type)
+{
+	wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
+		   __func__, protect_type, key_type);
+
+	if (addr) {
+		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
+			   __func__, MAC2STR(addr));
+	}
+
+	return 0;
+}
+
+
+static void * wpa_driver_test_global_init(void)
+{
+	struct wpa_driver_test_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	return global;
+}
+
+
+static void wpa_driver_test_global_deinit(void *priv)
+{
+	struct wpa_driver_test_global *global = priv;
+	os_free(global);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+	/* struct wpa_driver_test_global *global = priv; */
+	struct wpa_interface_info *iface;
+
+	iface = os_zalloc(sizeof(*iface));
+	if (iface == NULL)
+		return iface;
+	iface->ifname = os_strdup("sta0");
+	iface->desc = os_strdup("test interface 0");
+	iface->drv_name = "test";
+	iface->next = os_zalloc(sizeof(*iface));
+	if (iface->next) {
+		iface->next->ifname = os_strdup("sta1");
+		iface->next->desc = os_strdup("test interface 1");
+		iface->next->drv_name = "test";
+	}
+
+	return iface;
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+	struct hostapd_hw_modes *modes;
+	size_t i;
+
+	*num_modes = 3;
+	*flags = 0;
+	modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
+	if (modes == NULL)
+		return NULL;
+	modes[0].mode = HOSTAPD_MODE_IEEE80211G;
+	modes[0].num_channels = 11;
+	modes[0].num_rates = 12;
+	modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+	modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
+	if (modes[0].channels == NULL || modes[0].rates == NULL)
+		goto fail;
+	for (i = 0; i < 11; i++) {
+		modes[0].channels[i].chan = i + 1;
+		modes[0].channels[i].freq = 2412 + 5 * i;
+		modes[0].channels[i].flag = 0;
+	}
+	modes[0].rates[0] = 10;
+	modes[0].rates[1] = 20;
+	modes[0].rates[2] = 55;
+	modes[0].rates[3] = 110;
+	modes[0].rates[4] = 60;
+	modes[0].rates[5] = 90;
+	modes[0].rates[6] = 120;
+	modes[0].rates[7] = 180;
+	modes[0].rates[8] = 240;
+	modes[0].rates[9] = 360;
+	modes[0].rates[10] = 480;
+	modes[0].rates[11] = 540;
+
+	modes[1].mode = HOSTAPD_MODE_IEEE80211B;
+	modes[1].num_channels = 11;
+	modes[1].num_rates = 4;
+	modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+	modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
+	if (modes[1].channels == NULL || modes[1].rates == NULL)
+		goto fail;
+	for (i = 0; i < 11; i++) {
+		modes[1].channels[i].chan = i + 1;
+		modes[1].channels[i].freq = 2412 + 5 * i;
+		modes[1].channels[i].flag = 0;
+	}
+	modes[1].rates[0] = 10;
+	modes[1].rates[1] = 20;
+	modes[1].rates[2] = 55;
+	modes[1].rates[3] = 110;
+
+	modes[2].mode = HOSTAPD_MODE_IEEE80211A;
+	modes[2].num_channels = 1;
+	modes[2].num_rates = 8;
+	modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
+	modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
+	if (modes[2].channels == NULL || modes[2].rates == NULL)
+		goto fail;
+	modes[2].channels[0].chan = 60;
+	modes[2].channels[0].freq = 5300;
+	modes[2].channels[0].flag = 0;
+	modes[2].rates[0] = 60;
+	modes[2].rates[1] = 90;
+	modes[2].rates[2] = 120;
+	modes[2].rates[3] = 180;
+	modes[2].rates[4] = 240;
+	modes[2].rates[5] = 360;
+	modes[2].rates[6] = 480;
+	modes[2].rates[7] = 540;
+
+	return modes;
+
+fail:
+	if (modes) {
+		for (i = 0; i < *num_modes; i++) {
+			os_free(modes[i].channels);
+			os_free(modes[i].rates);
+		}
+		os_free(modes);
+	}
+	return NULL;
+}
+
+
+static int wpa_driver_test_set_freq(void *priv,
+				    struct hostapd_freq_params *freq)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
+	drv->current_freq = freq->freq;
+	return 0;
+}
+
+
+static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+				       unsigned int wait,
+				       const u8 *dst, const u8 *src,
+				       const u8 *bssid,
+				       const u8 *data, size_t data_len,
+				       int no_cck)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	int ret = -1;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "test: Send Action frame");
+
+	if ((drv->remain_on_channel_freq &&
+	     freq != drv->remain_on_channel_freq) ||
+	    (drv->remain_on_channel_freq == 0 &&
+	     freq != (unsigned int) drv->current_freq)) {
+		wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
+			   "unexpected channel: freq=%u MHz (current_freq=%u "
+			   "MHz, remain-on-channel freq=%u MHz)",
+			   freq, drv->current_freq,
+			   drv->remain_on_channel_freq);
+		return -1;
+	}
+
+	buf = os_zalloc(24 + data_len);
+	if (buf == NULL)
+		return ret;
+	os_memcpy(buf + 24, data, data_len);
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+	os_memcpy(hdr->addr1, dst, ETH_ALEN);
+	os_memcpy(hdr->addr2, src, ETH_ALEN);
+	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+
+	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
+	os_free(buf);
+	return ret;
+}
+
+
+#ifdef CONFIG_P2P
+static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+
+	if (drv->pending_action_tx == NULL)
+		return;
+
+	if (drv->off_channel_freq != drv->pending_action_freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
+			   "waiting for another freq=%u",
+			   drv->pending_action_freq);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
+		   MACSTR, MAC2STR(drv->pending_action_dst));
+	wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
+				    drv->pending_action_dst,
+				    drv->pending_action_src,
+				    drv->pending_action_bssid,
+				    wpabuf_head(drv->pending_action_tx),
+				    wpabuf_len(drv->pending_action_tx),
+				    drv->pending_action_no_cck);
+}
+#endif /* CONFIG_P2P */
+
+
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_test_data *drv = eloop_ctx;
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
+
+	os_memset(&data, 0, sizeof(data));
+	data.remain_on_channel.freq = drv->remain_on_channel_freq;
+	data.remain_on_channel.duration = drv->remain_on_channel_duration;
+
+	if (drv->p2p)
+		drv->off_channel_freq = 0;
+
+	drv->remain_on_channel_freq = 0;
+
+	wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
+}
+
+
+static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
+					     unsigned int duration)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
+		   __func__, freq, duration);
+	if (drv->remain_on_channel_freq &&
+	    drv->remain_on_channel_freq != freq) {
+		wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
+			   "remain_on_channel request");
+		return -1;
+	}
+
+	drv->remain_on_channel_freq = freq;
+	drv->remain_on_channel_duration = duration;
+	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+	eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
+			       test_remain_on_channel_timeout, drv, NULL);
+
+	os_memset(&data, 0, sizeof(data));
+	data.remain_on_channel.freq = freq;
+	data.remain_on_channel.duration = duration;
+	wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
+
+#ifdef CONFIG_P2P
+	if (drv->p2p) {
+		drv->off_channel_freq = drv->remain_on_channel_freq;
+		test_send_action_cb(drv, NULL);
+		if (drv->off_channel_freq == drv->pending_listen_freq) {
+			p2p_listen_cb(drv->p2p, drv->pending_listen_freq,
+				      drv->pending_listen_duration);
+			drv->pending_listen_freq = 0;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	return 0;
+}
+
+
+static int wpa_driver_test_cancel_remain_on_channel(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if (!drv->remain_on_channel_freq)
+		return -1;
+	drv->remain_on_channel_freq = 0;
+	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+	return 0;
+}
+
+
+static int wpa_driver_test_probe_req_report(void *priv, int report)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
+	drv->probe_req_report = report;
+	return 0;
+}
+
+
+#ifdef CONFIG_P2P
+
+static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
+	if (!drv->p2p)
+		return -1;
+	return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
+}
+
+
+static int wpa_driver_test_p2p_stop_find(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if (!drv->p2p)
+		return -1;
+	p2p_stop_find(drv->p2p);
+	return 0;
+}
+
+
+static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
+	if (!drv->p2p)
+		return -1;
+	return p2p_listen(drv->p2p, timeout);
+}
+
+
+static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr,
+				       int wps_method, int go_intent,
+				       const u8 *own_interface_addr,
+				       unsigned int force_freq,
+				       int persistent_group)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
+		   "go_intent=%d "
+		   "own_interface_addr=" MACSTR " force_freq=%u "
+		   "persistent_group=%d)",
+		   __func__, MAC2STR(peer_addr), wps_method, go_intent,
+		   MAC2STR(own_interface_addr), force_freq, persistent_group);
+	if (!drv->p2p)
+		return -1;
+	return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
+			   own_interface_addr, force_freq, persistent_group,
+			   NULL, 0, 0, 0);
+}
+
+
+static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
+		   __func__, MAC2STR(peer_addr));
+	if (!drv->p2p)
+		return -1;
+	p2p_wps_success_cb(drv->p2p, peer_addr);
+	return 0;
+}
+
+
+static int wpa_driver_test_p2p_group_formation_failed(void *priv)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if (!drv->p2p)
+		return -1;
+	p2p_group_formation_failed(drv->p2p);
+	return 0;
+}
+
+
+static int wpa_driver_test_p2p_set_params(void *priv,
+					  const struct p2p_params *params)
+{
+	struct test_driver_bss *dbss = priv;
+	struct wpa_driver_test_data *drv = dbss->drv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if (!drv->p2p)
+		return -1;
+	if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 ||
+	    p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 ||
+	    p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type,
+				  params->num_sec_dev_types) < 0)
+		return -1;
+	return 0;
+}
+
+
+static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+			 unsigned int num_req_dev_types,
+			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
+{
+	struct wpa_driver_test_data *drv = ctx;
+	struct wpa_driver_scan_params params;
+	int ret;
+	struct wpabuf *wps_ie, *ies;
+	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+	size_t ielen;
+
+	wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
+		   __func__, type, freq);
+
+	os_memset(&params, 0, sizeof(params));
+
+	/* P2P Wildcard SSID */
+	params.num_ssids = 1;
+	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+#if 0 /* TODO: WPS IE */
+	wpa_s->wps->dev.p2p = 1;
+	wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+					wpa_s->wps->uuid, WPS_REQ_ENROLLEE);
+#else
+	wps_ie = wpabuf_alloc(1);
+#endif
+	if (wps_ie == NULL)
+		return -1;
+
+	ielen = p2p_scan_ie_buf_len(drv->p2p);
+	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
+	if (ies == NULL) {
+		wpabuf_free(wps_ie);
+		return -1;
+	}
+	wpabuf_put_buf(ies, wps_ie);
+	wpabuf_free(wps_ie);
+
+	p2p_scan_ie(drv->p2p, ies, dev_id);
+
+	params.extra_ies = wpabuf_head(ies);
+	params.extra_ies_len = wpabuf_len(ies);
+
+	switch (type) {
+	case P2P_SCAN_SOCIAL:
+		params.freqs = social_channels;
+		break;
+	case P2P_SCAN_FULL:
+		break;
+	case P2P_SCAN_SOCIAL_PLUS_ONE:
+		social_channels[3] = freq;
+		params.freqs = social_channels;
+		break;
+	}
+
+	drv->pending_p2p_scan = 1;
+	ret = wpa_driver_test_scan(drv, &params);
+
+	wpabuf_free(ies);
+
+	return ret;
+}
+
+
+static int test_send_action(void *ctx, unsigned int freq, const u8 *dst,
+			    const u8 *src, const u8 *bssid, const u8 *buf,
+			    size_t len, unsigned int wait_time)
+{
+	struct wpa_driver_test_data *drv = ctx;
+
+	wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR
+		   " bssid=" MACSTR " len=%d",
+		   __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+		   (int) len);
+	if (freq <= 0) {
+		wpa_printf(MSG_WARNING, "P2P: No frequency specified for "
+			   "action frame TX");
+		return -1;
+	}
+
+	if (drv->pending_action_tx) {
+		wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
+			   "to " MACSTR, MAC2STR(drv->pending_action_dst));
+		wpabuf_free(drv->pending_action_tx);
+	}
+	drv->pending_action_tx = wpabuf_alloc(len);
+	if (drv->pending_action_tx == NULL)
+		return -1;
+	wpabuf_put_data(drv->pending_action_tx, buf, len);
+	os_memcpy(drv->pending_action_src, src, ETH_ALEN);
+	os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
+	os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
+	drv->pending_action_freq = freq;
+	drv->pending_action_no_cck = 1;
+
+	if (drv->off_channel_freq == freq) {
+		/* Already on requested channel; send immediately */
+		/* TODO: Would there ever be need to extend the current
+		 * duration on the channel? */
+		eloop_cancel_timeout(test_send_action_cb, drv, NULL);
+		eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
+		   "once the driver gets to the requested channel");
+	if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
+			   "to remain on channel (%u MHz) for Action "
+			   "Frame TX", freq);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void test_send_action_done(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	/* TODO */
+}
+
+
+static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+{
+	struct wpa_driver_test_data *drv = ctx;
+	union wpa_event_data event;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	os_memset(&event, 0, sizeof(event));
+	event.p2p_go_neg_completed.res = res;
+	wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event);
+}
+
+
+static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+{
+	struct wpa_driver_test_data *drv = ctx;
+	union wpa_event_data event;
+	wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src));
+	os_memset(&event, 0, sizeof(event));
+	event.p2p_go_neg_req_rx.src = src;
+	event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id;
+	wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event);
+}
+
+
+static void test_dev_found(void *ctx, const u8 *addr,
+			   const struct p2p_peer_info *info, int new_device)
+{
+	struct wpa_driver_test_data *drv = ctx;
+	union wpa_event_data event;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR
+		   " pri_dev_type=%s name='%s' config_methods=0x%x "
+		   "dev_capab=0x%x group_capab=0x%x)",
+		   __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+		   wps_dev_type_bin2str(info->pri_dev_type, devtype,
+					sizeof(devtype)),
+		   info->device_name, info->config_methods, info->dev_capab,
+		   info->group_capab);
+
+	os_memset(&event, 0, sizeof(event));
+	event.p2p_dev_found.addr = addr;
+	event.p2p_dev_found.dev_addr = info->p2p_device_addr;
+	event.p2p_dev_found.pri_dev_type = info->pri_dev_type;
+	event.p2p_dev_found.dev_name = info->device_name;
+	event.p2p_dev_found.config_methods = info->config_methods;
+	event.p2p_dev_found.dev_capab = info->dev_capab;
+	event.p2p_dev_found.group_capab = info->group_capab;
+	wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event);
+}
+
+
+static int test_start_listen(void *ctx, unsigned int freq,
+			     unsigned int duration,
+			     const struct wpabuf *probe_resp_ie)
+{
+	struct wpa_driver_test_data *drv = ctx;
+
+	wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)",
+		   __func__, freq, duration);
+
+	if (wpa_driver_test_probe_req_report(drv, 1) < 0)
+		return -1;
+
+	drv->pending_listen_freq = freq;
+	drv->pending_listen_duration = duration;
+
+	if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) {
+		drv->pending_listen_freq = 0;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void test_stop_listen(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	/* TODO */
+}
+
+
+static int test_send_probe_resp(void *ctx, const struct wpabuf *buf)
+{
+	struct wpa_driver_test_data *drv = ctx;
+	char resp[512], *pos, *end;
+	int ret;
+	const struct ieee80211_mgmt *mgmt;
+	const u8 *ie, *ie_end;
+
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf);
+	if (wpabuf_len(buf) < 24)
+		return -1;
+	if (!drv->probe_from) {
+		wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__);
+		return -1;
+	}
+
+	pos = resp;
+	end = resp + sizeof(resp);
+
+	mgmt = wpabuf_head(buf);
+
+	/* reply: SCANRESP BSSID SSID IEs */
+	ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+			  MAC2STR(mgmt->bssid));
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+
+	ie = mgmt->u.probe_resp.variable;
+	ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf);
+	if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID ||
+	    ie + 2 + ie[1] > ie_end)
+		return -1;
+	pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]);
+
+	ret = os_snprintf(pos, end - pos, " ");
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+	pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie);
+
+	sendto(drv->test_socket, resp, pos - resp, 0,
+	       drv->probe_from, drv->probe_from_len);
+
+	return 0;
+}
+
+
+static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+			    u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+{
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	/* TODO */
+}
+
+
+static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+			     const u8 *tlvs, size_t tlvs_len)
+{
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	/* TODO */
+}
+
+
+static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+			       const u8 *dev_addr, const u8 *pri_dev_type,
+			       const char *dev_name, u16 supp_config_methods,
+			       u8 dev_capab, u8 group_capab,
+			       const u8 *group_id, size_t group_id_len)
+{
+	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
+		   __func__, MAC2STR(peer), config_methods);
+	/* TODO */
+}
+
+
+static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+{
+	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
+		   __func__, MAC2STR(peer), config_methods);
+	/* TODO */
+}
+
+#endif /* CONFIG_P2P */
+
+
+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv)
+{
+#ifdef CONFIG_P2P
+	struct p2p_config p2p;
+	unsigned int r;
+	int i;
+
+	os_memset(&p2p, 0, sizeof(p2p));
+	p2p.msg_ctx = drv->ctx;
+	p2p.cb_ctx = drv;
+	p2p.p2p_scan = test_p2p_scan;
+	p2p.send_action = test_send_action;
+	p2p.send_action_done = test_send_action_done;
+	p2p.go_neg_completed = test_go_neg_completed;
+	p2p.go_neg_req_rx = test_go_neg_req_rx;
+	p2p.dev_found = test_dev_found;
+	p2p.start_listen = test_start_listen;
+	p2p.stop_listen = test_stop_listen;
+	p2p.send_probe_resp = test_send_probe_resp;
+	p2p.sd_request = test_sd_request;
+	p2p.sd_response = test_sd_response;
+	p2p.prov_disc_req = test_prov_disc_req;
+	p2p.prov_disc_resp = test_prov_disc_resp;
+
+	os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN);
+
+	p2p.reg_class = 12; /* TODO: change depending on location */
+	/*
+	 * Pick one of the social channels randomly as the listen
+	 * channel.
+	 */
+	os_get_random((u8 *) &r, sizeof(r));
+	p2p.channel = 1 + (r % 3) * 5;
+
+	/* TODO: change depending on location */
+	p2p.op_reg_class = 12;
+	/*
+	 * For initial tests, pick the operation channel randomly.
+	 * TODO: Use scan results (etc.) to select the best channel.
+	 */
+	p2p.op_channel = 1 + r % 11;
+
+	os_memcpy(p2p.country, "US ", 3);
+
+	/* FIX: fetch available channels from the driver */
+	p2p.channels.reg_classes = 1;
+	p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */
+	p2p.channels.reg_class[0].channels = 11;
+	for (i = 0; i < 11; i++)
+		p2p.channels.reg_class[0].channel[i] = i + 1;
+
+	p2p.max_peers = 100;
+
+	drv->p2p = p2p_init(&p2p);
+	if (drv->p2p == NULL)
+		return -1;
+	return 0;
+#else /* CONFIG_P2P */
+	wpa_printf(MSG_INFO, "driver_test: P2P support not included");
+	return -1;
+#endif /* CONFIG_P2P */
+}
+
+
+const struct wpa_driver_ops wpa_driver_test_ops = {
+	"test",
+	"wpa_supplicant test driver",
+	.hapd_init = test_driver_init,
+	.hapd_deinit = wpa_driver_test_deinit,
+	.hapd_send_eapol = test_driver_send_eapol,
+	.send_mlme = wpa_driver_test_send_mlme,
+	.set_generic_elem = test_driver_set_generic_elem,
+	.sta_deauth = test_driver_sta_deauth,
+	.sta_disassoc = test_driver_sta_disassoc,
+	.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
+	.if_add = test_driver_if_add,
+	.if_remove = test_driver_if_remove,
+	.hapd_set_ssid = test_driver_set_ssid,
+	.set_privacy = test_driver_set_privacy,
+	.set_sta_vlan = test_driver_set_sta_vlan,
+	.sta_add = test_driver_sta_add,
+	.send_ether = test_driver_send_ether,
+	.set_ap_wps_ie = test_driver_set_ap_wps_ie,
+	.get_bssid = wpa_driver_test_get_bssid,
+	.get_ssid = wpa_driver_test_get_ssid,
+	.set_key = wpa_driver_test_set_key,
+	.deinit = wpa_driver_test_deinit,
+	.set_param = wpa_driver_test_set_param,
+	.deauthenticate = wpa_driver_test_deauthenticate,
+	.associate = wpa_driver_test_associate,
+	.get_capa = wpa_driver_test_get_capa,
+	.get_mac_addr = wpa_driver_test_get_mac_addr,
+	.send_eapol = wpa_driver_test_send_eapol,
+	.mlme_setprotection = wpa_driver_test_mlme_setprotection,
+	.get_scan_results2 = wpa_driver_test_get_scan_results2,
+	.global_init = wpa_driver_test_global_init,
+	.global_deinit = wpa_driver_test_global_deinit,
+	.init2 = wpa_driver_test_init2,
+	.get_interfaces = wpa_driver_test_get_interfaces,
+	.scan2 = wpa_driver_test_scan,
+	.set_freq = wpa_driver_test_set_freq,
+	.send_action = wpa_driver_test_send_action,
+	.remain_on_channel = wpa_driver_test_remain_on_channel,
+	.cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
+	.probe_req_report = wpa_driver_test_probe_req_report,
+#ifdef CONFIG_P2P
+	.p2p_find = wpa_driver_test_p2p_find,
+	.p2p_stop_find = wpa_driver_test_p2p_stop_find,
+	.p2p_listen = wpa_driver_test_p2p_listen,
+	.p2p_connect = wpa_driver_test_p2p_connect,
+	.wps_success_cb = wpa_driver_test_wps_success_cb,
+	.p2p_group_formation_failed =
+	wpa_driver_test_p2p_group_formation_failed,
+	.p2p_set_params = wpa_driver_test_p2p_set_params,
+#endif /* CONFIG_P2P */
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_wext.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_wext.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_wext.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2189 +0,0 @@
-/*
- * Driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements a driver interface for the Linux Wireless Extensions.
- * When used with WE-18 or newer, this interface can be used as-is with number
- * of drivers. In addition to this, some of the common functions in this file
- * can be used by other driver interface implementations that use generic WE
- * ioctls, but require private ioctls for some of the functionality.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <net/if_arp.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "common/wpa_common.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver.h"
-#include "driver_wext.h"
-
-
-static int wpa_driver_wext_flush_pmkid(void *priv);
-static int wpa_driver_wext_get_range(void *priv);
-static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
-static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
-static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
-
-
-int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
-				   int idx, u32 value)
-{
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.param.flags = idx & IW_AUTH_INDEX;
-	iwr.u.param.value = value;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
-		if (errno != EOPNOTSUPP) {
-			wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
-				   "value 0x%x) failed: %s)",
-				   idx, value, strerror(errno));
-		}
-		ret = errno == EOPNOTSUPP ? -2 : -1;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @bssid: Buffer for BSSID
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCGIWAP]");
-		ret = -1;
-	}
-	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @bssid: BSSID
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
-	if (bssid)
-		os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
-	else
-		os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCSIWAP]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @ssid: Buffer for the SSID; must be at least 32 bytes long
- * Returns: SSID length on success, -1 on failure
- */
-int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.essid.pointer = (caddr_t) ssid;
-	iwr.u.essid.length = 32;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else {
-		ret = iwr.u.essid.length;
-		if (ret > 32)
-			ret = 32;
-		/* Some drivers include nul termination in the SSID, so let's
-		 * remove it here before further processing. WE-21 changes this
-		 * to explicitly require the length _not_ to include nul
-		 * termination. */
-		if (ret > 0 && ssid[ret - 1] == '\0' &&
-		    drv->we_version_compiled < 21)
-			ret--;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @ssid: SSID
- * @ssid_len: Length of SSID (0..32)
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-	char buf[33];
-
-	if (ssid_len > 32)
-		return -1;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	/* flags: 1 = ESSID is active, 0 = not (promiscuous) */
-	iwr.u.essid.flags = (ssid_len != 0);
-	os_memset(buf, 0, sizeof(buf));
-	os_memcpy(buf, ssid, ssid_len);
-	iwr.u.essid.pointer = (caddr_t) buf;
-	if (drv->we_version_compiled < 21) {
-		/* For historic reasons, set SSID length to include one extra
-		 * character, C string nul termination, even though SSID is
-		 * really an octet string that should not be presented as a C
-		 * string. Some Linux drivers decrement the length by one and
-		 * can thus end up missing the last octet of the SSID if the
-		 * length is not incremented here. WE-21 changes this to
-		 * explicitly require the length _not_ to include nul
-		 * termination. */
-		if (ssid_len)
-			ssid_len++;
-	}
-	iwr.u.essid.length = ssid_len;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @freq: Frequency in MHz
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_freq(void *priv, int freq)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.freq.m = freq * 100000;
-	iwr.u.freq.e = 1;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
-		perror("ioctl[SIOCSIWFREQ]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-static void
-wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
-{
-	union wpa_event_data data;
-
-	wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
-		   custom);
-
-	os_memset(&data, 0, sizeof(data));
-	/* Host AP driver */
-	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		data.michael_mic_failure.unicast =
-			os_strstr(custom, " unicast ") != NULL;
-		/* TODO: parse parameters(?) */
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-	} else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
-		char *spos;
-		int bytes;
-		u8 *req_ies = NULL, *resp_ies = NULL;
-
-		spos = custom + 17;
-
-		bytes = strspn(spos, "0123456789abcdefABCDEF");
-		if (!bytes || (bytes & 1))
-			return;
-		bytes /= 2;
-
-		req_ies = os_malloc(bytes);
-		if (req_ies == NULL ||
-		    hexstr2bin(spos, req_ies, bytes) < 0)
-			goto done;
-		data.assoc_info.req_ies = req_ies;
-		data.assoc_info.req_ies_len = bytes;
-
-		spos += bytes * 2;
-
-		data.assoc_info.resp_ies = NULL;
-		data.assoc_info.resp_ies_len = 0;
-
-		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
-			spos += 9;
-
-			bytes = strspn(spos, "0123456789abcdefABCDEF");
-			if (!bytes || (bytes & 1))
-				goto done;
-			bytes /= 2;
-
-			resp_ies = os_malloc(bytes);
-			if (resp_ies == NULL ||
-			    hexstr2bin(spos, resp_ies, bytes) < 0)
-				goto done;
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = bytes;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
-	done:
-		os_free(resp_ies);
-		os_free(req_ies);
-#ifdef CONFIG_PEERKEY
-	} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
-		if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
-			wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
-				   "STKSTART.request '%s'", custom + 17);
-			return;
-		}
-		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
-#endif /* CONFIG_PEERKEY */
-	}
-}
-
-
-static int wpa_driver_wext_event_wireless_michaelmicfailure(
-	void *ctx, const char *ev, size_t len)
-{
-	const struct iw_michaelmicfailure *mic;
-	union wpa_event_data data;
-
-	if (len < sizeof(*mic))
-		return -1;
-
-	mic = (const struct iw_michaelmicfailure *) ev;
-
-	wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
-		   "flags=0x%x src_addr=" MACSTR, mic->flags,
-		   MAC2STR(mic->src_addr.sa_data));
-
-	os_memset(&data, 0, sizeof(data));
-	data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
-	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-
-	return 0;
-}
-
-
-static int wpa_driver_wext_event_wireless_pmkidcand(
-	struct wpa_driver_wext_data *drv, const char *ev, size_t len)
-{
-	const struct iw_pmkid_cand *cand;
-	union wpa_event_data data;
-	const u8 *addr;
-
-	if (len < sizeof(*cand))
-		return -1;
-
-	cand = (const struct iw_pmkid_cand *) ev;
-	addr = (const u8 *) cand->bssid.sa_data;
-
-	wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
-		   "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
-		   cand->index, MAC2STR(addr));
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
-	data.pmkid_candidate.index = cand->index;
-	data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
-	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
-
-	return 0;
-}
-
-
-static int wpa_driver_wext_event_wireless_assocreqie(
-	struct wpa_driver_wext_data *drv, const char *ev, int len)
-{
-	if (len < 0)
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
-		    len);
-	os_free(drv->assoc_req_ies);
-	drv->assoc_req_ies = os_malloc(len);
-	if (drv->assoc_req_ies == NULL) {
-		drv->assoc_req_ies_len = 0;
-		return -1;
-	}
-	os_memcpy(drv->assoc_req_ies, ev, len);
-	drv->assoc_req_ies_len = len;
-
-	return 0;
-}
-
-
-static int wpa_driver_wext_event_wireless_assocrespie(
-	struct wpa_driver_wext_data *drv, const char *ev, int len)
-{
-	if (len < 0)
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
-		    len);
-	os_free(drv->assoc_resp_ies);
-	drv->assoc_resp_ies = os_malloc(len);
-	if (drv->assoc_resp_ies == NULL) {
-		drv->assoc_resp_ies_len = 0;
-		return -1;
-	}
-	os_memcpy(drv->assoc_resp_ies, ev, len);
-	drv->assoc_resp_ies_len = len;
-
-	return 0;
-}
-
-
-static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
-{
-	union wpa_event_data data;
-
-	if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	if (drv->assoc_req_ies) {
-		data.assoc_info.req_ies = drv->assoc_req_ies;
-		data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
-	}
-	if (drv->assoc_resp_ies) {
-		data.assoc_info.resp_ies = drv->assoc_resp_ies;
-		data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
-
-	os_free(drv->assoc_req_ies);
-	drv->assoc_req_ies = NULL;
-	os_free(drv->assoc_resp_ies);
-	drv->assoc_resp_ies = NULL;
-}
-
-
-static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
-					   char *data, 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) {
-		/* 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)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (drv->we_version_compiled > 18 &&
-		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
-		     iwe->cmd == IWEVCUSTOM ||
-		     iwe->cmd == IWEVASSOCREQIE ||
-		     iwe->cmd == IWEVASSOCRESPIE ||
-		     iwe->cmd == IWEVPMKIDCAND)) {
-			/* WE-19 removed the pointer from struct iw_point */
-			char *dpos = (char *) &iwe_buf.u.data.length;
-			int dlen = dpos - (char *) &iwe_buf;
-			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-				  sizeof(struct iw_event) - dlen);
-		} else {
-			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case SIOCGIWAP:
-			wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
-				   MACSTR,
-				   MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
-			if (is_zero_ether_addr(
-				    (const u8 *) iwe->u.ap_addr.sa_data) ||
-			    os_memcmp(iwe->u.ap_addr.sa_data,
-				      "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
-			    0) {
-				os_free(drv->assoc_req_ies);
-				drv->assoc_req_ies = NULL;
-				os_free(drv->assoc_resp_ies);
-				drv->assoc_resp_ies = NULL;
-				wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
-						     NULL);
-			
-			} else {
-				wpa_driver_wext_event_assoc_ies(drv);
-				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
-						     NULL);
-			}
-			break;
-		case IWEVMICHAELMICFAILURE:
-			if (custom + iwe->u.data.length > end) {
-				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
-					   "IWEVMICHAELMICFAILURE length");
-				return;
-			}
-			wpa_driver_wext_event_wireless_michaelmicfailure(
-				drv->ctx, custom, iwe->u.data.length);
-			break;
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end) {
-				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
-					   "IWEVCUSTOM length");
-				return;
-			}
-			buf = os_malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-			wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
-			os_free(buf);
-			break;
-		case SIOCGIWSCAN:
-			drv->scan_complete_events = 1;
-			eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
-					     drv, drv->ctx);
-			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
-					     NULL);
-			break;
-		case IWEVASSOCREQIE:
-			if (custom + iwe->u.data.length > end) {
-				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
-					   "IWEVASSOCREQIE length");
-				return;
-			}
-			wpa_driver_wext_event_wireless_assocreqie(
-				drv, custom, iwe->u.data.length);
-			break;
-		case IWEVASSOCRESPIE:
-			if (custom + iwe->u.data.length > end) {
-				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
-					   "IWEVASSOCRESPIE length");
-				return;
-			}
-			wpa_driver_wext_event_wireless_assocrespie(
-				drv, custom, iwe->u.data.length);
-			break;
-		case IWEVPMKIDCAND:
-			if (custom + iwe->u.data.length > end) {
-				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
-					   "IWEVPMKIDCAND length");
-				return;
-			}
-			wpa_driver_wext_event_wireless_pmkidcand(
-				drv, custom, iwe->u.data.length);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-
-static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
-				       char *buf, size_t len, int del)
-{
-	union wpa_event_data event;
-
-	os_memset(&event, 0, sizeof(event));
-	if (len > sizeof(event.interface_status.ifname))
-		len = sizeof(event.interface_status.ifname) - 1;
-	os_memcpy(event.interface_status.ifname, buf, len);
-	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
-		EVENT_INTERFACE_ADDED;
-
-	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
-		   del ? "DEL" : "NEW",
-		   event.interface_status.ifname,
-		   del ? "removed" : "added");
-
-	if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
-		if (del)
-			drv->if_removed = 1;
-		else
-			drv->if_removed = 0;
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-}
-
-
-static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
-				      u8 *buf, size_t len)
-{
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
-			    == 0)
-				return 1;
-			else
-				break;
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
-				       int ifindex, u8 *buf, size_t len)
-{
-	if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
-		return 1;
-
-	if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
-		drv->ifindex = if_nametoindex(drv->ifname);
-		wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
-			   "interface");
-		wpa_driver_wext_finish_drv_init(drv);
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
-					      u8 *buf, size_t len)
-{
-	struct wpa_driver_wext_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
-		wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
-			   ifi->ifi_index);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
-		   "(%s%s%s%s)",
-		   drv->operstate, ifi->ifi_flags,
-		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
-		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
-		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
-		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
-	/*
-	 * Some drivers send the association event before the operup event--in
-	 * this case, lifting operstate in wpa_driver_wext_set_operstate()
-	 * fails. This will hit us when wpa_supplicant does not need to do
-	 * IEEE 802.1X authentication
-	 */
-	if (drv->operstate == 1 &&
-	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
-	    !(ifi->ifi_flags & IFF_RUNNING))
-		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
-				       -1, IF_OPER_UP);
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_WIRELESS) {
-			wpa_driver_wext_event_wireless(
-				drv, ((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		} else if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_wext_event_link(drv,
-						   ((char *) attr) + rta_len,
-						   attr->rta_len - rta_len, 0);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
-					      u8 *buf, size_t len)
-{
-	struct wpa_driver_wext_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_IFNAME) {
-			wpa_driver_wext_event_link(drv,
-						   ((char *) attr) + rta_len,
-						   attr->rta_len - rta_len, 1);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-/**
- * wpa_driver_wext_init - Initialize WE driver interface
- * @ctx: context to be used when calling wpa_supplicant functions,
- * e.g., wpa_supplicant_event()
- * @ifname: interface name, e.g., wlan0
- * Returns: Pointer to private data, %NULL on failure
- */
-void * wpa_driver_wext_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_wext_data *drv;
-	struct netlink_config *cfg;
-	char path[128];
-	struct stat buf;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-
-	os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
-	if (stat(path, &buf) == 0) {
-		wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
-		drv->cfg80211 = 1;
-	}
-
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
-		goto err1;
-	}
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		goto err1;
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
-	cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		goto err2;
-	}
-
-	drv->mlme_sock = -1;
-
-	if (wpa_driver_wext_finish_drv_init(drv) < 0)
-		goto err3;
-
-	wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
-
-	return drv;
-
-err3:
-	netlink_deinit(drv->netlink);
-err2:
-	close(drv->ioctl_sock);
-err1:
-	os_free(drv);
-	return NULL;
-}
-
-
-static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
-{
-	if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0)
-		return -1;
-
-	/*
-	 * Make sure that the driver does not have any obsolete PMKID entries.
-	 */
-	wpa_driver_wext_flush_pmkid(drv);
-
-	if (wpa_driver_wext_set_mode(drv, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "Could not configure driver to use "
-			   "managed mode");
-		/* Try to use it anyway */
-	}
-
-	wpa_driver_wext_get_range(drv);
-
-	/*
-	 * Unlock the driver's BSSID and force to a random SSID to clear any
-	 * previous association the driver might have when the supplicant
-	 * starts up.
-	 */
-	wpa_driver_wext_disconnect(drv);
-
-	drv->ifindex = if_nametoindex(drv->ifname);
-
-	if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
-		/*
-		 * Host AP driver may use both wlan# and wifi# interface in
-		 * wireless events. Since some of the versions included WE-18
-		 * support, let's add the alternative ifindex also from
-		 * driver_wext.c for the time being. This may be removed at
-		 * some point once it is believed that old versions of the
-		 * driver are not in use anymore.
-		 */
-		char ifname2[IFNAMSIZ + 1];
-		os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
-		os_memcpy(ifname2, "wifi", 4);
-		wpa_driver_wext_alternative_ifindex(drv, ifname2);
-	}
-
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
-			       1, IF_OPER_DORMANT);
-
-	return 0;
-}
-
-
-/**
- * wpa_driver_wext_deinit - Deinitialize WE driver interface
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- *
- * Shut down driver interface and processing of driver events. Free
- * private data buffer if one was allocated in wpa_driver_wext_init().
- */
-void wpa_driver_wext_deinit(void *priv)
-{
-	struct wpa_driver_wext_data *drv = priv;
-
-	wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
-
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
-
-	/*
-	 * Clear possibly configured driver parameters in order to make it
-	 * easier to use the driver after wpa_supplicant has been terminated.
-	 */
-	wpa_driver_wext_disconnect(drv);
-
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-	netlink_deinit(drv->netlink);
-
-	if (drv->mlme_sock >= 0)
-		eloop_unregister_read_sock(drv->mlme_sock);
-
-	(void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
-
-	close(drv->ioctl_sock);
-	if (drv->mlme_sock >= 0)
-		close(drv->mlme_sock);
-	os_free(drv->assoc_req_ies);
-	os_free(drv->assoc_resp_ies);
-	os_free(drv);
-}
-
-
-/**
- * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Unused
- * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
- *
- * This function can be used as registered timeout when starting a scan to
- * generate a scan completed event if the driver does not report this.
- */
-void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-/**
- * wpa_driver_wext_scan - Request the driver to initiate scan
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0, timeout;
-	struct iw_scan_req req;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid_len > IW_ESSID_MAX_SIZE) {
-		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
-			   __FUNCTION__, (unsigned long) ssid_len);
-		return -1;
-	}
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ssid && ssid_len) {
-		os_memset(&req, 0, sizeof(req));
-		req.essid_len = ssid_len;
-		req.bssid.sa_family = ARPHRD_ETHER;
-		os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
-		os_memcpy(req.essid, ssid, ssid_len);
-		iwr.u.data.pointer = (caddr_t) &req;
-		iwr.u.data.length = sizeof(req);
-		iwr.u.data.flags = IW_SCAN_THIS_ESSID;
-	}
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	timeout = 5;
-	if (drv->scan_complete_events) {
-		/*
-		 * The driver seems to deliver SIOCGIWSCAN events to notify
-		 * when scan is complete, so use longer timeout to avoid race
-		 * conditions with scanning and following association request.
-		 */
-		timeout = 30;
-	}
-	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
-		   "seconds", ret, timeout);
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
-			       drv->ctx);
-
-	return ret;
-}
-
-
-static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
-				    size_t *len)
-{
-	struct iwreq iwr;
-	u8 *res_buf;
-	size_t res_buf_len;
-
-	res_buf_len = IW_SCAN_MAX_DATA;
-	for (;;) {
-		res_buf = os_malloc(res_buf_len);
-		if (res_buf == NULL)
-			return NULL;
-		os_memset(&iwr, 0, sizeof(iwr));
-		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-		iwr.u.data.pointer = res_buf;
-		iwr.u.data.length = res_buf_len;
-
-		if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
-			break;
-
-		if (errno == E2BIG && res_buf_len < 65535) {
-			os_free(res_buf);
-			res_buf = NULL;
-			res_buf_len *= 2;
-			if (res_buf_len > 65535)
-				res_buf_len = 65535; /* 16-bit length field */
-			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
-				   "trying larger buffer (%lu bytes)",
-				   (unsigned long) res_buf_len);
-		} else {
-			perror("ioctl[SIOCGIWSCAN]");
-			os_free(res_buf);
-			return NULL;
-		}
-	}
-
-	if (iwr.u.data.length > res_buf_len) {
-		os_free(res_buf);
-		return NULL;
-	}
-	*len = iwr.u.data.length;
-
-	return res_buf;
-}
-
-
-/*
- * Data structure for collecting WEXT scan results. This is needed to allow
- * the various methods of reporting IEs to be combined into a single IE buffer.
- */
-struct wext_scan_data {
-	struct wpa_scan_res res;
-	u8 *ie;
-	size_t ie_len;
-	u8 ssid[32];
-	size_t ssid_len;
-	int maxrate;
-};
-
-
-static void wext_get_scan_mode(struct iw_event *iwe,
-			       struct wext_scan_data *res)
-{
-	if (iwe->u.mode == IW_MODE_ADHOC)
-		res->res.caps |= IEEE80211_CAP_IBSS;
-	else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
-		res->res.caps |= IEEE80211_CAP_ESS;
-}
-
-
-static void wext_get_scan_ssid(struct iw_event *iwe,
-			       struct wext_scan_data *res, char *custom,
-			       char *end)
-{
-	int ssid_len = iwe->u.essid.length;
-	if (custom + ssid_len > end)
-		return;
-	if (iwe->u.essid.flags &&
-	    ssid_len > 0 &&
-	    ssid_len <= IW_ESSID_MAX_SIZE) {
-		os_memcpy(res->ssid, custom, ssid_len);
-		res->ssid_len = ssid_len;
-	}
-}
-
-
-static void wext_get_scan_freq(struct iw_event *iwe,
-			       struct wext_scan_data *res)
-{
-	int divi = 1000000, i;
-
-	if (iwe->u.freq.e == 0) {
-		/*
-		 * Some drivers do not report frequency, but a channel.
-		 * Try to map this to frequency by assuming they are using
-		 * IEEE 802.11b/g.  But don't overwrite a previously parsed
-		 * frequency if the driver sends both frequency and channel,
-		 * since the driver may be sending an A-band channel that we
-		 * don't handle here.
-		 */
-
-		if (res->res.freq)
-			return;
-
-		if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
-			res->res.freq = 2407 + 5 * iwe->u.freq.m;
-			return;
-		} else if (iwe->u.freq.m == 14) {
-			res->res.freq = 2484;
-			return;
-		}
-	}
-
-	if (iwe->u.freq.e > 6) {
-		wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
-			   MACSTR " m=%d e=%d)",
-			   MAC2STR(res->res.bssid), iwe->u.freq.m,
-			   iwe->u.freq.e);
-		return;
-	}
-
-	for (i = 0; i < iwe->u.freq.e; i++)
-		divi /= 10;
-	res->res.freq = iwe->u.freq.m / divi;
-}
-
-
-static void wext_get_scan_qual(struct iw_event *iwe,
-			       struct wext_scan_data *res)
-{
-	res->res.qual = iwe->u.qual.qual;
-	res->res.noise = iwe->u.qual.noise;
-	res->res.level = iwe->u.qual.level;
-	if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
-		res->res.flags |= WPA_SCAN_QUAL_INVALID;
-	if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
-		res->res.flags |= WPA_SCAN_LEVEL_INVALID;
-	if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
-		res->res.flags |= WPA_SCAN_NOISE_INVALID;
-	if (iwe->u.qual.updated & IW_QUAL_DBM)
-		res->res.flags |= WPA_SCAN_LEVEL_DBM;
-}
-
-
-static void wext_get_scan_encode(struct iw_event *iwe,
-				 struct wext_scan_data *res)
-{
-	if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
-		res->res.caps |= IEEE80211_CAP_PRIVACY;
-}
-
-
-static void wext_get_scan_rate(struct iw_event *iwe,
-			       struct wext_scan_data *res, char *pos,
-			       char *end)
-{
-	int maxrate;
-	char *custom = pos + IW_EV_LCP_LEN;
-	struct iw_param p;
-	size_t clen;
-
-	clen = iwe->len;
-	if (custom + clen > end)
-		return;
-	maxrate = 0;
-	while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
-		/* Note: may be misaligned, make a local, aligned copy */
-		os_memcpy(&p, custom, sizeof(struct iw_param));
-		if (p.value > maxrate)
-			maxrate = p.value;
-		clen -= sizeof(struct iw_param);
-		custom += sizeof(struct iw_param);
-	}
-
-	/* Convert the maxrate from WE-style (b/s units) to
-	 * 802.11 rates (500000 b/s units).
-	 */
-	res->maxrate = maxrate / 500000;
-}
-
-
-static void wext_get_scan_iwevgenie(struct iw_event *iwe,
-				    struct wext_scan_data *res, char *custom,
-				    char *end)
-{
-	char *genie, *gpos, *gend;
-	u8 *tmp;
-
-	if (iwe->u.data.length == 0)
-		return;
-
-	gpos = genie = custom;
-	gend = genie + iwe->u.data.length;
-	if (gend > end) {
-		wpa_printf(MSG_INFO, "IWEVGENIE overflow");
-		return;
-	}
-
-	tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
-	if (tmp == NULL)
-		return;
-	os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
-	res->ie = tmp;
-	res->ie_len += gend - gpos;
-}
-
-
-static void wext_get_scan_custom(struct iw_event *iwe,
-				 struct wext_scan_data *res, char *custom,
-				 char *end)
-{
-	size_t clen;
-	u8 *tmp;
-
-	clen = iwe->u.data.length;
-	if (custom + clen > end)
-		return;
-
-	if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
-		char *spos;
-		int bytes;
-		spos = custom + 7;
-		bytes = custom + clen - spos;
-		if (bytes & 1 || bytes == 0)
-			return;
-		bytes /= 2;
-		tmp = os_realloc(res->ie, res->ie_len + bytes);
-		if (tmp == NULL)
-			return;
-		res->ie = tmp;
-		if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
-			return;
-		res->ie_len += bytes;
-	} else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
-		char *spos;
-		int bytes;
-		spos = custom + 7;
-		bytes = custom + clen - spos;
-		if (bytes & 1 || bytes == 0)
-			return;
-		bytes /= 2;
-		tmp = os_realloc(res->ie, res->ie_len + bytes);
-		if (tmp == NULL)
-			return;
-		res->ie = tmp;
-		if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
-			return;
-		res->ie_len += bytes;
-	} else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
-		char *spos;
-		int bytes;
-		u8 bin[8];
-		spos = custom + 4;
-		bytes = custom + clen - spos;
-		if (bytes != 16) {
-			wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
-			return;
-		}
-		bytes /= 2;
-		if (hexstr2bin(spos, bin, bytes) < 0) {
-			wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
-			return;
-		}
-		res->res.tsf += WPA_GET_BE64(bin);
-	}
-}
-
-
-static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
-{
-	return drv->we_version_compiled > 18 &&
-		(cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
-		 cmd == IWEVGENIE || cmd == IWEVCUSTOM);
-}
-
-
-static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
-					   struct wext_scan_data *data)
-{
-	struct wpa_scan_res **tmp;
-	struct wpa_scan_res *r;
-	size_t extra_len;
-	u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
-
-	/* Figure out whether we need to fake any IEs */
-	pos = data->ie;
-	end = pos + data->ie_len;
-	while (pos && pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		if (pos[0] == WLAN_EID_SSID)
-			ssid_ie = pos;
-		else if (pos[0] == WLAN_EID_SUPP_RATES)
-			rate_ie = pos;
-		else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
-			rate_ie = pos;
-		pos += 2 + pos[1];
-	}
-
-	extra_len = 0;
-	if (ssid_ie == NULL)
-		extra_len += 2 + data->ssid_len;
-	if (rate_ie == NULL && data->maxrate)
-		extra_len += 3;
-
-	r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
-	if (r == NULL)
-		return;
-	os_memcpy(r, &data->res, sizeof(*r));
-	r->ie_len = extra_len + data->ie_len;
-	pos = (u8 *) (r + 1);
-	if (ssid_ie == NULL) {
-		/*
-		 * Generate a fake SSID IE since the driver did not report
-		 * a full IE list.
-		 */
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = data->ssid_len;
-		os_memcpy(pos, data->ssid, data->ssid_len);
-		pos += data->ssid_len;
-	}
-	if (rate_ie == NULL && data->maxrate) {
-		/*
-		 * Generate a fake Supported Rates IE since the driver did not
-		 * report a full IE list.
-		 */
-		*pos++ = WLAN_EID_SUPP_RATES;
-		*pos++ = 1;
-		*pos++ = data->maxrate;
-	}
-	if (data->ie)
-		os_memcpy(pos, data->ie, data->ie_len);
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(r);
-		return;
-	}
-	tmp[res->num++] = r;
-	res->res = tmp;
-}
-				      
-
-/**
- * wpa_driver_wext_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * Returns: Scan results on success, -1 on failure
- */
-struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	size_t ap_num = 0, len;
-	int first;
-	u8 *res_buf;
-	struct iw_event iwe_buf, *iwe = &iwe_buf;
-	char *pos, *end, *custom;
-	struct wpa_scan_results *res;
-	struct wext_scan_data data;
-
-	res_buf = wpa_driver_wext_giwscan(drv, &len);
-	if (res_buf == NULL)
-		return NULL;
-
-	ap_num = 0;
-	first = 1;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(res_buf);
-		return NULL;
-	}
-
-	pos = (char *) res_buf;
-	end = (char *) res_buf + len;
-	os_memset(&data, 0, sizeof(data));
-
-	while (pos + IW_EV_LCP_LEN <= end) {
-		/* 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)
-			break;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (wext_19_iw_point(drv, iwe->cmd)) {
-			/* WE-19 removed the pointer from struct iw_point */
-			char *dpos = (char *) &iwe_buf.u.data.length;
-			int dlen = dpos - (char *) &iwe_buf;
-			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-				  sizeof(struct iw_event) - dlen);
-		} else {
-			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case SIOCGIWAP:
-			if (!first)
-				wpa_driver_wext_add_scan_entry(res, &data);
-			first = 0;
-			os_free(data.ie);
-			os_memset(&data, 0, sizeof(data));
-			os_memcpy(data.res.bssid,
-				  iwe->u.ap_addr.sa_data, ETH_ALEN);
-			break;
-		case SIOCGIWMODE:
-			wext_get_scan_mode(iwe, &data);
-			break;
-		case SIOCGIWESSID:
-			wext_get_scan_ssid(iwe, &data, custom, end);
-			break;
-		case SIOCGIWFREQ:
-			wext_get_scan_freq(iwe, &data);
-			break;
-		case IWEVQUAL:
-			wext_get_scan_qual(iwe, &data);
-			break;
-		case SIOCGIWENCODE:
-			wext_get_scan_encode(iwe, &data);
-			break;
-		case SIOCGIWRATE:
-			wext_get_scan_rate(iwe, &data, pos, end);
-			break;
-		case IWEVGENIE:
-			wext_get_scan_iwevgenie(iwe, &data, custom, end);
-			break;
-		case IWEVCUSTOM:
-			wext_get_scan_custom(iwe, &data, custom, end);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-	os_free(res_buf);
-	res_buf = NULL;
-	if (!first)
-		wpa_driver_wext_add_scan_entry(res, &data);
-	os_free(data.ie);
-
-	wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
-		   (unsigned long) len, (unsigned long) res->num);
-
-	return res;
-}
-
-
-static int wpa_driver_wext_get_range(void *priv)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iw_range *range;
-	struct iwreq iwr;
-	int minlen;
-	size_t buflen;
-
-	/*
-	 * Use larger buffer than struct iw_range in order to allow the
-	 * structure to grow in the future.
-	 */
-	buflen = sizeof(struct iw_range) + 500;
-	range = os_zalloc(buflen);
-	if (range == NULL)
-		return -1;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) range;
-	iwr.u.data.length = buflen;
-
-	minlen = ((char *) &range->enc_capa) - (char *) range +
-		sizeof(range->enc_capa);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		os_free(range);
-		return -1;
-	} else if (iwr.u.data.length >= minlen &&
-		   range->we_version_compiled >= 18) {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
-			   "WE(source)=%d enc_capa=0x%x",
-			   range->we_version_compiled,
-			   range->we_version_source,
-			   range->enc_capa);
-		drv->has_capability = 1;
-		drv->we_version_compiled = range->we_version_compiled;
-		if (range->enc_capa & IW_ENC_CAPA_WPA) {
-			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
-		}
-		if (range->enc_capa & IW_ENC_CAPA_WPA2) {
-			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-		}
-		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
-			WPA_DRIVER_CAPA_ENC_WEP104;
-		if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-		if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
-			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-		if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
-			drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
-		drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
-			WPA_DRIVER_AUTH_SHARED |
-			WPA_DRIVER_AUTH_LEAP;
-		drv->capa.max_scan_ssids = 1;
-
-		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
-			   "flags 0x%x",
-			   drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
-	} else {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
-			   "assuming WPA is not supported");
-	}
-
-	os_free(range);
-	return 0;
-}
-
-
-static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
-				   const u8 *psk)
-{
-	struct iw_encode_ext *ext;
-	struct iwreq iwr;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
-		return 0;
-
-	if (!psk)
-		return 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	ext = os_zalloc(sizeof(*ext) + PMK_LEN);
-	if (ext == NULL)
-		return -1;
-
-	iwr.u.encoding.pointer = (caddr_t) ext;
-	iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
-	ext->key_len = PMK_LEN;
-	os_memcpy(&ext->key, psk, ext->key_len);
-	ext->alg = IW_ENCODE_ALG_PMK;
-
-	ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
-	if (ret < 0)
-		perror("ioctl[SIOCSIWENCODEEXT] PMK");
-	os_free(ext);
-
-	return ret;
-}
-
-
-static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
-				       const u8 *addr, int key_idx,
-				       int set_tx, const u8 *seq,
-				       size_t seq_len,
-				       const u8 *key, size_t key_len)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-	struct iw_encode_ext *ext;
-
-	if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
-		wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
-			   __FUNCTION__, (unsigned long) seq_len);
-		return -1;
-	}
-
-	ext = os_zalloc(sizeof(*ext) + key_len);
-	if (ext == NULL)
-		return -1;
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.encoding.flags = key_idx + 1;
-	iwr.u.encoding.flags |= IW_ENCODE_TEMP;
-	if (alg == WPA_ALG_NONE)
-		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
-	iwr.u.encoding.pointer = (caddr_t) ext;
-	iwr.u.encoding.length = sizeof(*ext) + key_len;
-
-	if (addr == NULL ||
-	    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
-		ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
-	if (set_tx)
-		ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
-
-	ext->addr.sa_family = ARPHRD_ETHER;
-	if (addr)
-		os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
-	else
-		os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
-	if (key && key_len) {
-		os_memcpy(ext + 1, key, key_len);
-		ext->key_len = key_len;
-	}
-	switch (alg) {
-	case WPA_ALG_NONE:
-		ext->alg = IW_ENCODE_ALG_NONE;
-		break;
-	case WPA_ALG_WEP:
-		ext->alg = IW_ENCODE_ALG_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		ext->alg = IW_ENCODE_ALG_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		ext->alg = IW_ENCODE_ALG_CCMP;
-		break;
-	case WPA_ALG_PMK:
-		ext->alg = IW_ENCODE_ALG_PMK;
-		break;
-#ifdef CONFIG_IEEE80211W
-	case WPA_ALG_IGTK:
-		ext->alg = IW_ENCODE_ALG_AES_CMAC;
-		break;
-#endif /* CONFIG_IEEE80211W */
-	default:
-		wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
-			   __FUNCTION__, alg);
-		os_free(ext);
-		return -1;
-	}
-
-	if (seq && seq_len) {
-		ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
-		os_memcpy(ext->rx_seq, seq, seq_len);
-	}
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
-		ret = errno == EOPNOTSUPP ? -2 : -1;
-		if (errno == ENODEV) {
-			/*
-			 * ndiswrapper seems to be returning incorrect error
-			 * code.. */
-			ret = -2;
-		}
-
-		perror("ioctl[SIOCSIWENCODEEXT]");
-	}
-
-	os_free(ext);
-	return ret;
-}
-
-
-/**
- * wpa_driver_wext_set_key - Configure encryption key
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @priv: Private driver interface data
- * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- *	%WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
- * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
- *	broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys
- * @set_tx: Configure this key as the default Tx key (only used when
- *	driver does not support separate unicast/individual key
- * @seq: Sequence number/packet number, seq_len octets, the next
- *	packet number to be used for in replay protection; configured
- *	for Rx keys (in most cases, this is only used with broadcast
- *	keys and set to zero for unicast keys)
- * @seq_len: Length of the seq, depends on the algorithm:
- *	TKIP: 6 octets, CCMP: 6 octets
- * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- *	8-byte Rx Mic Key
- * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
- *	TKIP: 32, CCMP: 16)
- * Returns: 0 on success, -1 on failure
- *
- * This function uses SIOCSIWENCODEEXT by default, but tries to use
- * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
- */
-int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			    const u8 *addr, int key_idx,
-			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu",
-		   __FUNCTION__, alg, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
-					  seq, seq_len, key, key_len);
-	if (ret == 0)
-		return 0;
-
-	if (ret == -2 &&
-	    (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
-		wpa_printf(MSG_DEBUG, "Driver did not support "
-			   "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
-		ret = 0;
-	} else {
-		wpa_printf(MSG_DEBUG, "Driver did not support "
-			   "SIOCSIWENCODEEXT");
-		return ret;
-	}
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.encoding.flags = key_idx + 1;
-	iwr.u.encoding.flags |= IW_ENCODE_TEMP;
-	if (alg == WPA_ALG_NONE)
-		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
-	iwr.u.encoding.pointer = (caddr_t) key;
-	iwr.u.encoding.length = key_len;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWENCODE]");
-		ret = -1;
-	}
-
-	if (set_tx && alg != WPA_ALG_NONE) {
-		os_memset(&iwr, 0, sizeof(iwr));
-		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-		iwr.u.encoding.flags = key_idx + 1;
-		iwr.u.encoding.flags |= IW_ENCODE_TEMP;
-		iwr.u.encoding.pointer = (caddr_t) NULL;
-		iwr.u.encoding.length = 0;
-		if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-			perror("ioctl[SIOCSIWENCODE] (set_tx)");
-			ret = -1;
-		}
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_wext_set_countermeasures(void *priv,
-					       int enabled)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_wext_set_auth_param(drv,
-					      IW_AUTH_TKIP_COUNTERMEASURES,
-					      enabled);
-}
-
-
-static int wpa_driver_wext_set_drop_unencrypted(void *priv,
-						int enabled)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	drv->use_crypt = enabled;
-	return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
-					      enabled);
-}
-
-
-static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
-				const u8 *addr, int cmd, int reason_code)
-{
-	struct iwreq iwr;
-	struct iw_mlme mlme;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	os_memset(&mlme, 0, sizeof(mlme));
-	mlme.cmd = cmd;
-	mlme.reason_code = reason_code;
-	mlme.addr.sa_family = ARPHRD_ETHER;
-	os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
-	iwr.u.data.pointer = (caddr_t) &mlme;
-	iwr.u.data.length = sizeof(mlme);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMLME]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
-{
-	struct iwreq iwr;
-	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-	u8 ssid[32];
-	int i;
-
-	/*
-	 * Only force-disconnect when the card is in infrastructure mode,
-	 * otherwise the driver might interpret the cleared BSSID and random
-	 * SSID as an attempt to create a new ad-hoc network.
-	 */
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWMODE]");
-		iwr.u.mode = IW_MODE_INFRA;
-	}
-
-	if (iwr.u.mode == IW_MODE_INFRA) {
-		if (drv->cfg80211) {
-			/*
-			 * cfg80211 supports SIOCSIWMLME commands, so there is
-			 * no need for the random SSID hack, but clear the
-			 * BSSID and SSID.
-			 */
-			if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-			    wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
-				wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
-					   "to disconnect");
-			}
-			return;
-		}
-		/*
-		 * Clear the BSSID selection and set a random SSID to make sure
-		 * the driver will not be trying to associate with something
-		 * even if it does not understand SIOCSIWMLME commands (or
-		 * tries to associate automatically after deauth/disassoc).
-		 */
-		for (i = 0; i < 32; i++)
-			ssid[i] = rand() & 0xFF;
-		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-		    wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
-			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
-				   "BSSID/SSID to disconnect");
-		}
-	}
-}
-
-
-static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	int ret;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
-	wpa_driver_wext_disconnect(drv);
-	return ret;
-}
-
-
-static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	int ret;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
-	wpa_driver_wext_disconnect(drv);
-	return ret;
-}
-
-
-static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
-				      size_t ie_len)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) ie;
-	iwr.u.data.length = ie_len;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWGENIE]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-int wpa_driver_wext_cipher2wext(int cipher)
-{
-	switch (cipher) {
-	case CIPHER_NONE:
-		return IW_AUTH_CIPHER_NONE;
-	case CIPHER_WEP40:
-		return IW_AUTH_CIPHER_WEP40;
-	case CIPHER_TKIP:
-		return IW_AUTH_CIPHER_TKIP;
-	case CIPHER_CCMP:
-		return IW_AUTH_CIPHER_CCMP;
-	case CIPHER_WEP104:
-		return IW_AUTH_CIPHER_WEP104;
-	default:
-		return 0;
-	}
-}
-
-
-int wpa_driver_wext_keymgmt2wext(int keymgmt)
-{
-	switch (keymgmt) {
-	case KEY_MGMT_802_1X:
-	case KEY_MGMT_802_1X_NO_WPA:
-		return IW_AUTH_KEY_MGMT_802_1X;
-	case KEY_MGMT_PSK:
-		return IW_AUTH_KEY_MGMT_PSK;
-	default:
-		return 0;
-	}
-}
-
-
-static int
-wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
-				  struct wpa_driver_associate_params *params)
-{
-	struct iwreq iwr;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
-		   "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	/* Just changing mode, not actual keys */
-	iwr.u.encoding.flags = 0;
-	iwr.u.encoding.pointer = (caddr_t) NULL;
-	iwr.u.encoding.length = 0;
-
-	/*
-	 * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
-	 * different things. Here they are used to indicate Open System vs.
-	 * Shared Key authentication algorithm. However, some drivers may use
-	 * them to select between open/restricted WEP encrypted (open = allow
-	 * both unencrypted and encrypted frames; restricted = only allow
-	 * encrypted frames).
-	 */
-
-	if (!drv->use_crypt) {
-		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
-	} else {
-		if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-			iwr.u.encoding.flags |= IW_ENCODE_OPEN;
-		if (params->auth_alg & WPA_AUTH_ALG_SHARED)
-			iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
-	}
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWENCODE]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-int wpa_driver_wext_associate(void *priv,
-			      struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	int ret = 0;
-	int allow_unencrypted_eapol;
-	int value;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->cfg80211) {
-		/*
-		 * Stop cfg80211 from trying to associate before we are done
-		 * with all parameters.
-		 */
-		wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
-	}
-
-	if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
-	    < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
-		ret = -1;
-
-	/*
-	 * If the driver did not support SIOCSIWAUTH, fallback to
-	 * SIOCSIWENCODE here.
-	 */
-	if (drv->auth_alg_fallback &&
-	    wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
-		ret = -1;
-
-	if (!params->bssid &&
-	    wpa_driver_wext_set_bssid(drv, NULL) < 0)
-		ret = -1;
-
-	/* TODO: should consider getting wpa version and cipher/key_mgmt suites
-	 * from configuration, not from here, where only the selected suite is
-	 * available */
-	if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
-	    < 0)
-		ret = -1;
-	if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
-		value = IW_AUTH_WPA_VERSION_DISABLED;
-	else if (params->wpa_ie[0] == WLAN_EID_RSN)
-		value = IW_AUTH_WPA_VERSION_WPA2;
-	else
-		value = IW_AUTH_WPA_VERSION_WPA;
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_WPA_VERSION, value) < 0)
-		ret = -1;
-	value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_CIPHER_PAIRWISE, value) < 0)
-		ret = -1;
-	value = wpa_driver_wext_cipher2wext(params->group_suite);
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_CIPHER_GROUP, value) < 0)
-		ret = -1;
-	value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_KEY_MGMT, value) < 0)
-		ret = -1;
-	value = params->key_mgmt_suite != KEY_MGMT_NONE ||
-		params->pairwise_suite != CIPHER_NONE ||
-		params->group_suite != CIPHER_NONE ||
-		params->wpa_ie_len;
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_PRIVACY_INVOKED, value) < 0)
-		ret = -1;
-
-	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
-	 * not using WPA. IEEE 802.1X specifies that these frames are not
-	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
-		allow_unencrypted_eapol = 0;
-	else
-		allow_unencrypted_eapol = 1;
-
-	if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_auth_param(drv,
-					   IW_AUTH_RX_UNENCRYPTED_EAPOL,
-					   allow_unencrypted_eapol) < 0)
-		ret = -1;
-#ifdef CONFIG_IEEE80211W
-	switch (params->mgmt_frame_protection) {
-	case NO_MGMT_FRAME_PROTECTION:
-		value = IW_AUTH_MFP_DISABLED;
-		break;
-	case MGMT_FRAME_PROTECTION_OPTIONAL:
-		value = IW_AUTH_MFP_OPTIONAL;
-		break;
-	case MGMT_FRAME_PROTECTION_REQUIRED:
-		value = IW_AUTH_MFP_REQUIRED;
-		break;
-	};
-	if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
-		ret = -1;
-#endif /* CONFIG_IEEE80211W */
-	if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
-		ret = -1;
-	if (!drv->cfg80211 &&
-	    wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
-		ret = -1;
-	if (params->bssid &&
-	    wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
-		ret = -1;
-	if (drv->cfg80211 &&
-	    wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	int algs = 0, res;
-
-	if (auth_alg & WPA_AUTH_ALG_OPEN)
-		algs |= IW_AUTH_ALG_OPEN_SYSTEM;
-	if (auth_alg & WPA_AUTH_ALG_SHARED)
-		algs |= IW_AUTH_ALG_SHARED_KEY;
-	if (auth_alg & WPA_AUTH_ALG_LEAP)
-		algs |= IW_AUTH_ALG_LEAP;
-	if (algs == 0) {
-		/* at least one algorithm should be set */
-		algs = IW_AUTH_ALG_OPEN_SYSTEM;
-	}
-
-	res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
-					     algs);
-	drv->auth_alg_fallback = res == -2;
-	return res;
-}
-
-
-/**
- * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
- * @priv: Pointer to private wext data from wpa_driver_wext_init()
- * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
- * Returns: 0 on success, -1 on failure
- */
-int wpa_driver_wext_set_mode(void *priv, int mode)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	struct iwreq iwr;
-	int ret = -1;
-	unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.mode = new_mode;
-	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
-		ret = 0;
-		goto done;
-	}
-
-	if (errno != EBUSY) {
-		perror("ioctl[SIOCSIWMODE]");
-		goto done;
-	}
-
-	/* mac80211 doesn't allow mode changes while the device is up, so if
-	 * the device isn't in the mode we're about to change to, take device
-	 * down, try to set the mode again, and bring it back up.
-	 */
-	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWMODE]");
-		goto done;
-	}
-
-	if (iwr.u.mode == new_mode) {
-		ret = 0;
-		goto done;
-	}
-
-	if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
-		/* Try to set the mode again while the interface is down */
-		iwr.u.mode = new_mode;
-		if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
-			perror("ioctl[SIOCSIWMODE]");
-		else
-			ret = 0;
-
-		(void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
-	}
-
-done:
-	return ret;
-}
-
-
-static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
-				 u32 cmd, const u8 *bssid, const u8 *pmkid)
-{
-	struct iwreq iwr;
-	struct iw_pmksa pmksa;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	os_memset(&pmksa, 0, sizeof(pmksa));
-	pmksa.cmd = cmd;
-	pmksa.bssid.sa_family = ARPHRD_ETHER;
-	if (bssid)
-		os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
-	if (pmkid)
-		os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
-	iwr.u.data.pointer = (caddr_t) &pmksa;
-	iwr.u.data.length = sizeof(pmksa);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
-		if (errno != EOPNOTSUPP)
-			perror("ioctl[SIOCSIWPMKSA]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
-				     const u8 *pmkid)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
-}
-
-
-static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
-		 			const u8 *pmkid)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
-}
-
-
-static int wpa_driver_wext_flush_pmkid(void *priv)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
-}
-
-
-int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	struct wpa_driver_wext_data *drv = priv;
-	if (!drv->has_capability)
-		return -1;
-	os_memcpy(capa, &drv->capa, sizeof(*capa));
-	return 0;
-}
-
-
-int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
-					const char *ifname)
-{
-	if (ifname == NULL) {
-		drv->ifindex2 = -1;
-		return 0;
-	}
-
-	drv->ifindex2 = if_nametoindex(ifname);
-	if (drv->ifindex2 <= 0)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
-		   "wireless events", drv->ifindex2, ifname);
-
-	return 0;
-}
-
-
-int wpa_driver_wext_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_wext_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
-		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
-	drv->operstate = state;
-	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
-				      state ? IF_OPER_UP : IF_OPER_DORMANT);
-}
-
-
-int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
-{
-	return drv->we_version_compiled;
-}
-
-
-const struct wpa_driver_ops wpa_driver_wext_ops = {
-	.name = "wext",
-	.desc = "Linux wireless extensions (generic)",
-	.get_bssid = wpa_driver_wext_get_bssid,
-	.get_ssid = wpa_driver_wext_get_ssid,
-	.set_key = wpa_driver_wext_set_key,
-	.set_countermeasures = wpa_driver_wext_set_countermeasures,
-	.scan2 = wpa_driver_wext_scan,
-	.get_scan_results2 = wpa_driver_wext_get_scan_results,
-	.deauthenticate = wpa_driver_wext_deauthenticate,
-	.disassociate = wpa_driver_wext_disassociate,
-	.associate = wpa_driver_wext_associate,
-	.init = wpa_driver_wext_init,
-	.deinit = wpa_driver_wext_deinit,
-	.add_pmkid = wpa_driver_wext_add_pmkid,
-	.remove_pmkid = wpa_driver_wext_remove_pmkid,
-	.flush_pmkid = wpa_driver_wext_flush_pmkid,
-	.get_capa = wpa_driver_wext_get_capa,
-	.set_operstate = wpa_driver_wext_set_operstate,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_wext.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_wext.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_wext.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_wext.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2489 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements a driver interface for the Linux Wireless Extensions.
+ * When used with WE-18 or newer, this interface can be used as-is with number
+ * of drivers. In addition to this, some of the common functions in this file
+ * can be used by other driver interface implementations that use generic WE
+ * ioctls, but require private ioctls for some of the functionality.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+
+#include "linux_wext.h"
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
+#include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "rfkill.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
+
+static int wpa_driver_wext_flush_pmkid(void *priv);
+static int wpa_driver_wext_get_range(void *priv);
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
+
+
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+				   int idx, u32 value)
+{
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.param.flags = idx & IW_AUTH_INDEX;
+	iwr.u.param.value = value;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+		if (errno != EOPNOTSUPP) {
+			wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+				   "value 0x%x) failed: %s)",
+				   idx, value, strerror(errno));
+		}
+		ret = errno == EOPNOTSUPP ? -2 : -1;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: Buffer for BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+		perror("ioctl[SIOCGIWAP]");
+		ret = -1;
+	}
+	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+	if (bssid)
+		os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+	else
+		os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+		perror("ioctl[SIOCSIWAP]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Buffer for the SSID; must be at least 32 bytes long
+ * Returns: SSID length on success, -1 on failure
+ */
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.essid.pointer = (caddr_t) ssid;
+	iwr.u.essid.length = 32;
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCGIWESSID]");
+		ret = -1;
+	} else {
+		ret = iwr.u.essid.length;
+		if (ret > 32)
+			ret = 32;
+		/* Some drivers include nul termination in the SSID, so let's
+		 * remove it here before further processing. WE-21 changes this
+		 * to explicitly require the length _not_ to include nul
+		 * termination. */
+		if (ret > 0 && ssid[ret - 1] == '\0' &&
+		    drv->we_version_compiled < 21)
+			ret--;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: SSID
+ * @ssid_len: Length of SSID (0..32)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+	char buf[33];
+
+	if (ssid_len > 32)
+		return -1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	/* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+	iwr.u.essid.flags = (ssid_len != 0);
+	os_memset(buf, 0, sizeof(buf));
+	os_memcpy(buf, ssid, ssid_len);
+	iwr.u.essid.pointer = (caddr_t) buf;
+	if (drv->we_version_compiled < 21) {
+		/* For historic reasons, set SSID length to include one extra
+		 * character, C string nul termination, even though SSID is
+		 * really an octet string that should not be presented as a C
+		 * string. Some Linux drivers decrement the length by one and
+		 * can thus end up missing the last octet of the SSID if the
+		 * length is not incremented here. WE-21 changes this to
+		 * explicitly require the length _not_ to include nul
+		 * termination. */
+		if (ssid_len)
+			ssid_len++;
+	}
+	iwr.u.essid.length = ssid_len;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCSIWESSID]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @freq: Frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_freq(void *priv, int freq)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.freq.m = freq * 100000;
+	iwr.u.freq.e = 1;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static void
+wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+		   custom);
+
+	os_memset(&data, 0, sizeof(data));
+	/* Host AP driver */
+	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+		data.michael_mic_failure.unicast =
+			os_strstr(custom, " unicast ") != NULL;
+		/* TODO: parse parameters(?) */
+		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+	} else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+		char *spos;
+		int bytes;
+		u8 *req_ies = NULL, *resp_ies = NULL;
+
+		spos = custom + 17;
+
+		bytes = strspn(spos, "0123456789abcdefABCDEF");
+		if (!bytes || (bytes & 1))
+			return;
+		bytes /= 2;
+
+		req_ies = os_malloc(bytes);
+		if (req_ies == NULL ||
+		    hexstr2bin(spos, req_ies, bytes) < 0)
+			goto done;
+		data.assoc_info.req_ies = req_ies;
+		data.assoc_info.req_ies_len = bytes;
+
+		spos += bytes * 2;
+
+		data.assoc_info.resp_ies = NULL;
+		data.assoc_info.resp_ies_len = 0;
+
+		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+			spos += 9;
+
+			bytes = strspn(spos, "0123456789abcdefABCDEF");
+			if (!bytes || (bytes & 1))
+				goto done;
+			bytes /= 2;
+
+			resp_ies = os_malloc(bytes);
+			if (resp_ies == NULL ||
+			    hexstr2bin(spos, resp_ies, bytes) < 0)
+				goto done;
+			data.assoc_info.resp_ies = resp_ies;
+			data.assoc_info.resp_ies_len = bytes;
+		}
+
+		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+	done:
+		os_free(resp_ies);
+		os_free(req_ies);
+#ifdef CONFIG_PEERKEY
+	} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+		if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+			wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+				   "STKSTART.request '%s'", custom + 17);
+			return;
+		}
+		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+#ifdef ANDROID
+	} else if (os_strncmp(custom, "STOP", 4) == 0) {
+		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+	} else if (os_strncmp(custom, "START", 5) == 0) {
+		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+	} else if (os_strncmp(custom, "HANG", 4) == 0) {
+		wpa_msg(ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+#endif /* ANDROID */
+	}
+}
+
+
+static int wpa_driver_wext_event_wireless_michaelmicfailure(
+	void *ctx, const char *ev, size_t len)
+{
+	const struct iw_michaelmicfailure *mic;
+	union wpa_event_data data;
+
+	if (len < sizeof(*mic))
+		return -1;
+
+	mic = (const struct iw_michaelmicfailure *) ev;
+
+	wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+		   "flags=0x%x src_addr=" MACSTR, mic->flags,
+		   MAC2STR(mic->src_addr.sa_data));
+
+	os_memset(&data, 0, sizeof(data));
+	data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+	return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_pmkidcand(
+	struct wpa_driver_wext_data *drv, const char *ev, size_t len)
+{
+	const struct iw_pmkid_cand *cand;
+	union wpa_event_data data;
+	const u8 *addr;
+
+	if (len < sizeof(*cand))
+		return -1;
+
+	cand = (const struct iw_pmkid_cand *) ev;
+	addr = (const u8 *) cand->bssid.sa_data;
+
+	wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+		   "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+		   cand->index, MAC2STR(addr));
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+	data.pmkid_candidate.index = cand->index;
+	data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+	return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocreqie(
+	struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+	if (len < 0)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+		    len);
+	os_free(drv->assoc_req_ies);
+	drv->assoc_req_ies = os_malloc(len);
+	if (drv->assoc_req_ies == NULL) {
+		drv->assoc_req_ies_len = 0;
+		return -1;
+	}
+	os_memcpy(drv->assoc_req_ies, ev, len);
+	drv->assoc_req_ies_len = len;
+
+	return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocrespie(
+	struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+	if (len < 0)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+		    len);
+	os_free(drv->assoc_resp_ies);
+	drv->assoc_resp_ies = os_malloc(len);
+	if (drv->assoc_resp_ies == NULL) {
+		drv->assoc_resp_ies_len = 0;
+		return -1;
+	}
+	os_memcpy(drv->assoc_resp_ies, ev, len);
+	drv->assoc_resp_ies_len = len;
+
+	return 0;
+}
+
+
+static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
+{
+	union wpa_event_data data;
+
+	if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	if (drv->assoc_req_ies) {
+		data.assoc_info.req_ies = drv->assoc_req_ies;
+		data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+	}
+	if (drv->assoc_resp_ies) {
+		data.assoc_info.resp_ies = drv->assoc_resp_ies;
+		data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+	os_free(drv->assoc_req_ies);
+	drv->assoc_req_ies = NULL;
+	os_free(drv->assoc_resp_ies);
+	drv->assoc_resp_ies = NULL;
+}
+
+
+static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
+					   char *data, 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) {
+		/* 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)
+			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version_compiled > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVCUSTOM ||
+		     iwe->cmd == IWEVASSOCREQIE ||
+		     iwe->cmd == IWEVASSOCRESPIE ||
+		     iwe->cmd == IWEVPMKIDCAND)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+				  sizeof(struct iw_event) - dlen);
+		} else {
+			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case SIOCGIWAP:
+			wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+				   MACSTR,
+				   MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+			if (is_zero_ether_addr(
+				    (const u8 *) iwe->u.ap_addr.sa_data) ||
+			    os_memcmp(iwe->u.ap_addr.sa_data,
+				      "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+			    0) {
+				os_free(drv->assoc_req_ies);
+				drv->assoc_req_ies = NULL;
+				os_free(drv->assoc_resp_ies);
+				drv->assoc_resp_ies = NULL;
+				wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
+						     NULL);
+			
+			} else {
+				wpa_driver_wext_event_assoc_ies(drv);
+				wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
+						     NULL);
+			}
+			break;
+		case IWEVMICHAELMICFAILURE:
+			if (custom + iwe->u.data.length > end) {
+				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+					   "IWEVMICHAELMICFAILURE length");
+				return;
+			}
+			wpa_driver_wext_event_wireless_michaelmicfailure(
+				drv->ctx, custom, iwe->u.data.length);
+			break;
+		case IWEVCUSTOM:
+			if (custom + iwe->u.data.length > end) {
+				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+					   "IWEVCUSTOM length");
+				return;
+			}
+			buf = os_malloc(iwe->u.data.length + 1);
+			if (buf == NULL)
+				return;
+			os_memcpy(buf, custom, iwe->u.data.length);
+			buf[iwe->u.data.length] = '\0';
+			wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
+			os_free(buf);
+			break;
+		case SIOCGIWSCAN:
+			drv->scan_complete_events = 1;
+			eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
+					     drv, drv->ctx);
+			wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
+					     NULL);
+			break;
+		case IWEVASSOCREQIE:
+			if (custom + iwe->u.data.length > end) {
+				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+					   "IWEVASSOCREQIE length");
+				return;
+			}
+			wpa_driver_wext_event_wireless_assocreqie(
+				drv, custom, iwe->u.data.length);
+			break;
+		case IWEVASSOCRESPIE:
+			if (custom + iwe->u.data.length > end) {
+				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+					   "IWEVASSOCRESPIE length");
+				return;
+			}
+			wpa_driver_wext_event_wireless_assocrespie(
+				drv, custom, iwe->u.data.length);
+			break;
+		case IWEVPMKIDCAND:
+			if (custom + iwe->u.data.length > end) {
+				wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+					   "IWEVPMKIDCAND length");
+				return;
+			}
+			wpa_driver_wext_event_wireless_pmkidcand(
+				drv, custom, iwe->u.data.length);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+
+static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
+				       char *buf, size_t len, int del)
+{
+	union wpa_event_data event;
+
+	os_memset(&event, 0, sizeof(event));
+	if (len > sizeof(event.interface_status.ifname))
+		len = sizeof(event.interface_status.ifname) - 1;
+	os_memcpy(event.interface_status.ifname, buf, len);
+	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+		EVENT_INTERFACE_ADDED;
+
+	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+		   del ? "DEL" : "NEW",
+		   event.interface_status.ifname,
+		   del ? "removed" : "added");
+
+	if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+		if (del) {
+			if (drv->if_removed) {
+				wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+					   "already set - ignore event");
+				return;
+			}
+			drv->if_removed = 1;
+		} else {
+			if (if_nametoindex(drv->ifname) == 0) {
+				wpa_printf(MSG_DEBUG, "WEXT: Interface %s "
+					   "does not exist - ignore "
+					   "RTM_NEWLINK",
+					   drv->ifname);
+				return;
+			}
+			if (!drv->if_removed) {
+				wpa_printf(MSG_DEBUG, "WEXT: if_removed "
+					   "already cleared - ignore event");
+				return;
+			}
+			drv->if_removed = 0;
+		}
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
+				      u8 *buf, size_t len)
+{
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+			    == 0)
+				return 1;
+			else
+				break;
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+
+	return 0;
+}
+
+
+static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
+				       int ifindex, u8 *buf, size_t len)
+{
+	if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
+		return 1;
+
+	if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
+		drv->ifindex = if_nametoindex(drv->ifname);
+		wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
+			   "interface");
+		wpa_driver_wext_finish_drv_init(drv);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
+					      u8 *buf, size_t len)
+{
+	struct wpa_driver_wext_data *drv = ctx;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+	char namebuf[IFNAMSIZ];
+
+	if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
+		wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+			   ifi->ifi_index);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+		   "(%s%s%s%s)",
+		   drv->operstate, ifi->ifi_flags,
+		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+		wpa_printf(MSG_DEBUG, "WEXT: Interface down");
+		drv->if_disabled = 1;
+		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+	}
+
+	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+				   "event since interface %s is down",
+				   namebuf);
+		} else if (if_nametoindex(drv->ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+				   "event since interface %s does not exist",
+				   drv->ifname);
+		} else if (drv->if_removed) {
+			wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up "
+				   "event since interface %s is marked "
+				   "removed", drv->ifname);
+		} else {
+			wpa_printf(MSG_DEBUG, "WEXT: Interface up");
+			drv->if_disabled = 0;
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
+	}
+
+	/*
+	 * Some drivers send the association event before the operup event--in
+	 * this case, lifting operstate in wpa_driver_wext_set_operstate()
+	 * fails. This will hit us when wpa_supplicant does not need to do
+	 * IEEE 802.1X authentication
+	 */
+	if (drv->operstate == 1 &&
+	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+	    !(ifi->ifi_flags & IFF_RUNNING))
+		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+				       -1, IF_OPER_UP);
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			wpa_driver_wext_event_wireless(
+				drv, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		} else if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_wext_event_link(drv,
+						   ((char *) attr) + rta_len,
+						   attr->rta_len - rta_len, 0);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
+					      u8 *buf, size_t len)
+{
+	struct wpa_driver_wext_data *drv = ctx;
+	int attrlen, rta_len;
+	struct rtattr *attr;
+
+	attrlen = len;
+	attr = (struct rtattr *) buf;
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_wext_event_link(drv,
+						   ((char *) attr) + rta_len,
+						   attr->rta_len - rta_len, 1);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void wpa_driver_wext_rfkill_blocked(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked");
+	/*
+	 * This may be for any interface; use ifdown event to disable
+	 * interface.
+	 */
+}
+
+
+static void wpa_driver_wext_rfkill_unblocked(void *ctx)
+{
+	struct wpa_driver_wext_data *drv = ctx;
+	wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked");
+	if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
+		wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP "
+			   "after rfkill unblock");
+		return;
+	}
+	/* rtnetlink ifup handler will report interface as enabled */
+}
+
+
+static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
+{
+	/* Find phy (radio) to which this interface belongs */
+	char buf[90], *pos;
+	int f, rv;
+
+	drv->phyname[0] = '\0';
+	snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+		 drv->ifname);
+	f = open(buf, O_RDONLY);
+	if (f < 0) {
+		wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+			   buf, strerror(errno));
+		return;
+	}
+
+	rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+	close(f);
+	if (rv < 0) {
+		wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+			   buf, strerror(errno));
+		return;
+	}
+
+	drv->phyname[rv] = '\0';
+	pos = os_strchr(drv->phyname, '\n');
+	if (pos)
+		*pos = '\0';
+	wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
+		   drv->ifname, drv->phyname);
+}
+
+
+/**
+ * wpa_driver_wext_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_wext_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_wext_data *drv;
+	struct netlink_config *cfg;
+	struct rfkill_config *rcfg;
+	char path[128];
+	struct stat buf;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
+	if (stat(path, &buf) == 0) {
+		wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
+		drv->cfg80211 = 1;
+		wext_get_phy_name(drv);
+	}
+
+	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->ioctl_sock < 0) {
+		perror("socket(PF_INET,SOCK_DGRAM)");
+		goto err1;
+	}
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		goto err1;
+	cfg->ctx = drv;
+	cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
+	cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
+	drv->netlink = netlink_init(cfg);
+	if (drv->netlink == NULL) {
+		os_free(cfg);
+		goto err2;
+	}
+
+	rcfg = os_zalloc(sizeof(*rcfg));
+	if (rcfg == NULL)
+		goto err3;
+	rcfg->ctx = drv;
+	os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
+	rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
+	rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
+	drv->rfkill = rfkill_init(rcfg);
+	if (drv->rfkill == NULL) {
+		wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
+		os_free(rcfg);
+	}
+
+	drv->mlme_sock = -1;
+
+#ifdef ANDROID
+	drv->errors = 0;
+	drv->driver_is_started = TRUE;
+	drv->bgscan_enabled = 0;
+#endif /* ANDROID */
+
+	if (wpa_driver_wext_finish_drv_init(drv) < 0)
+		goto err3;
+
+	wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
+
+	return drv;
+
+err3:
+	rfkill_deinit(drv->rfkill);
+	netlink_deinit(drv->netlink);
+err2:
+	close(drv->ioctl_sock);
+err1:
+	os_free(drv);
+	return NULL;
+}
+
+
+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
+}
+
+
+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+{
+	int send_rfkill_event = 0;
+
+	if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) {
+		if (rfkill_is_blocked(drv->rfkill)) {
+			wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable "
+				   "interface '%s' due to rfkill",
+				   drv->ifname);
+			drv->if_disabled = 1;
+			send_rfkill_event = 1;
+		} else {
+			wpa_printf(MSG_ERROR, "WEXT: Could not set "
+				   "interface '%s' UP", drv->ifname);
+			return -1;
+		}
+	}
+
+	/*
+	 * Make sure that the driver does not have any obsolete PMKID entries.
+	 */
+	wpa_driver_wext_flush_pmkid(drv);
+
+	if (wpa_driver_wext_set_mode(drv, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Could not configure driver to use "
+			   "managed mode");
+		/* Try to use it anyway */
+	}
+
+	wpa_driver_wext_get_range(drv);
+
+	/*
+	 * Unlock the driver's BSSID and force to a random SSID to clear any
+	 * previous association the driver might have when the supplicant
+	 * starts up.
+	 */
+	wpa_driver_wext_disconnect(drv);
+
+	drv->ifindex = if_nametoindex(drv->ifname);
+
+	if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+		/*
+		 * Host AP driver may use both wlan# and wifi# interface in
+		 * wireless events. Since some of the versions included WE-18
+		 * support, let's add the alternative ifindex also from
+		 * driver_wext.c for the time being. This may be removed at
+		 * some point once it is believed that old versions of the
+		 * driver are not in use anymore.
+		 */
+		char ifname2[IFNAMSIZ + 1];
+		os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+		os_memcpy(ifname2, "wifi", 4);
+		wpa_driver_wext_alternative_ifindex(drv, ifname2);
+	}
+
+	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+			       1, IF_OPER_DORMANT);
+
+	if (send_rfkill_event) {
+		eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill,
+				       drv, drv->ctx);
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_driver_wext_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_wext_init().
+ */
+void wpa_driver_wext_deinit(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+
+	wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
+
+	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+
+	/*
+	 * Clear possibly configured driver parameters in order to make it
+	 * easier to use the driver after wpa_supplicant has been terminated.
+	 */
+	wpa_driver_wext_disconnect(drv);
+
+	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
+	netlink_deinit(drv->netlink);
+	rfkill_deinit(drv->rfkill);
+
+	if (drv->mlme_sock >= 0)
+		eloop_unregister_read_sock(drv->mlme_sock);
+
+	(void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
+
+	close(drv->ioctl_sock);
+	if (drv->mlme_sock >= 0)
+		close(drv->mlme_sock);
+	os_free(drv->assoc_req_ies);
+	os_free(drv->assoc_resp_ies);
+	os_free(drv);
+}
+
+
+/**
+ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_wext_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0, timeout;
+	struct iw_scan_req req;
+	const u8 *ssid = params->ssids[0].ssid;
+	size_t ssid_len = params->ssids[0].ssid_len;
+
+	if (ssid_len > IW_ESSID_MAX_SIZE) {
+		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+			   __FUNCTION__, (unsigned long) ssid_len);
+		return -1;
+	}
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	if (ssid && ssid_len) {
+		os_memset(&req, 0, sizeof(req));
+		req.essid_len = ssid_len;
+		req.bssid.sa_family = ARPHRD_ETHER;
+		os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+		os_memcpy(req.essid, ssid, ssid_len);
+		iwr.u.data.pointer = (caddr_t) &req;
+		iwr.u.data.length = sizeof(req);
+		iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+	}
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+		perror("ioctl[SIOCSIWSCAN]");
+		ret = -1;
+	}
+
+	/* Not all drivers generate "scan completed" wireless event, so try to
+	 * read results after a timeout. */
+	timeout = 10;
+	if (drv->scan_complete_events) {
+		/*
+		 * The driver seems to deliver SIOCGIWSCAN events to notify
+		 * when scan is complete, so use longer timeout to avoid race
+		 * conditions with scanning and following association request.
+		 */
+		timeout = 30;
+	}
+	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+		   "seconds", ret, timeout);
+	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
+			       drv->ctx);
+
+	return ret;
+}
+
+
+static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
+				    size_t *len)
+{
+	struct iwreq iwr;
+	u8 *res_buf;
+	size_t res_buf_len;
+
+	res_buf_len = IW_SCAN_MAX_DATA;
+	for (;;) {
+		res_buf = os_malloc(res_buf_len);
+		if (res_buf == NULL)
+			return NULL;
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+		iwr.u.data.pointer = res_buf;
+		iwr.u.data.length = res_buf_len;
+
+		if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+			break;
+
+		if (errno == E2BIG && res_buf_len < 65535) {
+			os_free(res_buf);
+			res_buf = NULL;
+			res_buf_len *= 2;
+			if (res_buf_len > 65535)
+				res_buf_len = 65535; /* 16-bit length field */
+			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+				   "trying larger buffer (%lu bytes)",
+				   (unsigned long) res_buf_len);
+		} else {
+			perror("ioctl[SIOCGIWSCAN]");
+			os_free(res_buf);
+			return NULL;
+		}
+	}
+
+	if (iwr.u.data.length > res_buf_len) {
+		os_free(res_buf);
+		return NULL;
+	}
+	*len = iwr.u.data.length;
+
+	return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+	struct wpa_scan_res res;
+	u8 *ie;
+	size_t ie_len;
+	u8 ssid[32];
+	size_t ssid_len;
+	int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	if (iwe->u.mode == IW_MODE_ADHOC)
+		res->res.caps |= IEEE80211_CAP_IBSS;
+	else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+		res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+			       struct wext_scan_data *res, char *custom,
+			       char *end)
+{
+	int ssid_len = iwe->u.essid.length;
+	if (custom + ssid_len > end)
+		return;
+	if (iwe->u.essid.flags &&
+	    ssid_len > 0 &&
+	    ssid_len <= IW_ESSID_MAX_SIZE) {
+		os_memcpy(res->ssid, custom, ssid_len);
+		res->ssid_len = ssid_len;
+	}
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	int divi = 1000000, i;
+
+	if (iwe->u.freq.e == 0) {
+		/*
+		 * Some drivers do not report frequency, but a channel.
+		 * Try to map this to frequency by assuming they are using
+		 * IEEE 802.11b/g.  But don't overwrite a previously parsed
+		 * frequency if the driver sends both frequency and channel,
+		 * since the driver may be sending an A-band channel that we
+		 * don't handle here.
+		 */
+
+		if (res->res.freq)
+			return;
+
+		if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+			res->res.freq = 2407 + 5 * iwe->u.freq.m;
+			return;
+		} else if (iwe->u.freq.m == 14) {
+			res->res.freq = 2484;
+			return;
+		}
+	}
+
+	if (iwe->u.freq.e > 6) {
+		wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+			   MACSTR " m=%d e=%d)",
+			   MAC2STR(res->res.bssid), iwe->u.freq.m,
+			   iwe->u.freq.e);
+		return;
+	}
+
+	for (i = 0; i < iwe->u.freq.e; i++)
+		divi /= 10;
+	res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv,
+			       struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	res->res.qual = iwe->u.qual.qual;
+	res->res.noise = iwe->u.qual.noise;
+	res->res.level = iwe->u.qual.level;
+	if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
+		res->res.flags |= WPA_SCAN_QUAL_INVALID;
+	if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
+		res->res.flags |= WPA_SCAN_LEVEL_INVALID;
+	if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
+		res->res.flags |= WPA_SCAN_NOISE_INVALID;
+	if (iwe->u.qual.updated & IW_QUAL_DBM)
+		res->res.flags |= WPA_SCAN_LEVEL_DBM;
+	if ((iwe->u.qual.updated & IW_QUAL_DBM) ||
+	    ((iwe->u.qual.level != 0) &&
+	     (iwe->u.qual.level > drv->max_level))) {
+		if (iwe->u.qual.level >= 64)
+			res->res.level -= 0x100;
+		if (iwe->u.qual.noise >= 64)
+			res->res.noise -= 0x100;
+	}
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+				 struct wext_scan_data *res)
+{
+	if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+		res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+			       struct wext_scan_data *res, char *pos,
+			       char *end)
+{
+	int maxrate;
+	char *custom = pos + IW_EV_LCP_LEN;
+	struct iw_param p;
+	size_t clen;
+
+	clen = iwe->len;
+	if (custom + clen > end)
+		return;
+	maxrate = 0;
+	while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+		/* Note: may be misaligned, make a local, aligned copy */
+		os_memcpy(&p, custom, sizeof(struct iw_param));
+		if (p.value > maxrate)
+			maxrate = p.value;
+		clen -= sizeof(struct iw_param);
+		custom += sizeof(struct iw_param);
+	}
+
+	/* Convert the maxrate from WE-style (b/s units) to
+	 * 802.11 rates (500000 b/s units).
+	 */
+	res->maxrate = maxrate / 500000;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+				    struct wext_scan_data *res, char *custom,
+				    char *end)
+{
+	char *genie, *gpos, *gend;
+	u8 *tmp;
+
+	if (iwe->u.data.length == 0)
+		return;
+
+	gpos = genie = custom;
+	gend = genie + iwe->u.data.length;
+	if (gend > end) {
+		wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+		return;
+	}
+
+	tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+	if (tmp == NULL)
+		return;
+	os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+	res->ie = tmp;
+	res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+				 struct wext_scan_data *res, char *custom,
+				 char *end)
+{
+	size_t clen;
+	u8 *tmp;
+
+	clen = iwe->u.data.length;
+	if (custom + clen > end)
+		return;
+
+	if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+		char *spos;
+		int bytes;
+		spos = custom + 7;
+		bytes = custom + clen - spos;
+		if (bytes & 1 || bytes == 0)
+			return;
+		bytes /= 2;
+		tmp = os_realloc(res->ie, res->ie_len + bytes);
+		if (tmp == NULL)
+			return;
+		res->ie = tmp;
+		if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+			return;
+		res->ie_len += bytes;
+	} else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+		char *spos;
+		int bytes;
+		spos = custom + 7;
+		bytes = custom + clen - spos;
+		if (bytes & 1 || bytes == 0)
+			return;
+		bytes /= 2;
+		tmp = os_realloc(res->ie, res->ie_len + bytes);
+		if (tmp == NULL)
+			return;
+		res->ie = tmp;
+		if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
+			return;
+		res->ie_len += bytes;
+	} else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+		char *spos;
+		int bytes;
+		u8 bin[8];
+		spos = custom + 4;
+		bytes = custom + clen - spos;
+		if (bytes != 16) {
+			wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+			return;
+		}
+		bytes /= 2;
+		if (hexstr2bin(spos, bin, bytes) < 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
+			return;
+		}
+		res->res.tsf += WPA_GET_BE64(bin);
+	}
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
+{
+	return drv->we_version_compiled > 18 &&
+		(cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+		 cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
+					   struct wext_scan_data *data)
+{
+	struct wpa_scan_res **tmp;
+	struct wpa_scan_res *r;
+	size_t extra_len;
+	u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+	/* Figure out whether we need to fake any IEs */
+	pos = data->ie;
+	end = pos + data->ie_len;
+	while (pos && pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_SSID)
+			ssid_ie = pos;
+		else if (pos[0] == WLAN_EID_SUPP_RATES)
+			rate_ie = pos;
+		else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+			rate_ie = pos;
+		pos += 2 + pos[1];
+	}
+
+	extra_len = 0;
+	if (ssid_ie == NULL)
+		extra_len += 2 + data->ssid_len;
+	if (rate_ie == NULL && data->maxrate)
+		extra_len += 3;
+
+	r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+	if (r == NULL)
+		return;
+	os_memcpy(r, &data->res, sizeof(*r));
+	r->ie_len = extra_len + data->ie_len;
+	pos = (u8 *) (r + 1);
+	if (ssid_ie == NULL) {
+		/*
+		 * Generate a fake SSID IE since the driver did not report
+		 * a full IE list.
+		 */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = data->ssid_len;
+		os_memcpy(pos, data->ssid, data->ssid_len);
+		pos += data->ssid_len;
+	}
+	if (rate_ie == NULL && data->maxrate) {
+		/*
+		 * Generate a fake Supported Rates IE since the driver did not
+		 * report a full IE list.
+		 */
+		*pos++ = WLAN_EID_SUPP_RATES;
+		*pos++ = 1;
+		*pos++ = data->maxrate;
+	}
+	if (data->ie)
+		os_memcpy(pos, data->ie, data->ie_len);
+
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(r);
+		return;
+	}
+	tmp[res->num++] = r;
+	res->res = tmp;
+}
+
+
+/**
+ * wpa_driver_wext_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	size_t len;
+	int first;
+	u8 *res_buf;
+	struct iw_event iwe_buf, *iwe = &iwe_buf;
+	char *pos, *end, *custom;
+	struct wpa_scan_results *res;
+	struct wext_scan_data data;
+
+	res_buf = wpa_driver_wext_giwscan(drv, &len);
+	if (res_buf == NULL)
+		return NULL;
+
+	first = 1;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL) {
+		os_free(res_buf);
+		return NULL;
+	}
+
+	pos = (char *) res_buf;
+	end = (char *) res_buf + len;
+	os_memset(&data, 0, sizeof(data));
+
+	while (pos + IW_EV_LCP_LEN <= end) {
+		/* 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)
+			break;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (wext_19_iw_point(drv, iwe->cmd)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+				  sizeof(struct iw_event) - dlen);
+		} else {
+			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case SIOCGIWAP:
+			if (!first)
+				wpa_driver_wext_add_scan_entry(res, &data);
+			first = 0;
+			os_free(data.ie);
+			os_memset(&data, 0, sizeof(data));
+			os_memcpy(data.res.bssid,
+				  iwe->u.ap_addr.sa_data, ETH_ALEN);
+			break;
+		case SIOCGIWMODE:
+			wext_get_scan_mode(iwe, &data);
+			break;
+		case SIOCGIWESSID:
+			wext_get_scan_ssid(iwe, &data, custom, end);
+			break;
+		case SIOCGIWFREQ:
+			wext_get_scan_freq(iwe, &data);
+			break;
+		case IWEVQUAL:
+			wext_get_scan_qual(drv, iwe, &data);
+			break;
+		case SIOCGIWENCODE:
+			wext_get_scan_encode(iwe, &data);
+			break;
+		case SIOCGIWRATE:
+			wext_get_scan_rate(iwe, &data, pos, end);
+			break;
+		case IWEVGENIE:
+			wext_get_scan_iwevgenie(iwe, &data, custom, end);
+			break;
+		case IWEVCUSTOM:
+			wext_get_scan_custom(iwe, &data, custom, end);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+	os_free(res_buf);
+	res_buf = NULL;
+	if (!first)
+		wpa_driver_wext_add_scan_entry(res, &data);
+	os_free(data.ie);
+
+	wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+		   (unsigned long) len, (unsigned long) res->num);
+
+	return res;
+}
+
+
+static int wpa_driver_wext_get_range(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iw_range *range;
+	struct iwreq iwr;
+	int minlen;
+	size_t buflen;
+
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
+	buflen = sizeof(struct iw_range) + 500;
+	range = os_zalloc(buflen);
+	if (range == NULL)
+		return -1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = (caddr_t) range;
+	iwr.u.data.length = buflen;
+
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWRANGE]");
+		os_free(range);
+		return -1;
+	} else if (iwr.u.data.length >= minlen &&
+		   range->we_version_compiled >= 18) {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+			   "WE(source)=%d enc_capa=0x%x",
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
+		drv->has_capability = 1;
+		drv->we_version_compiled = range->we_version_compiled;
+		if (range->enc_capa & IW_ENC_CAPA_WPA) {
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+		}
+		if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+		}
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+			WPA_DRIVER_CAPA_ENC_WEP104;
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128;
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+		if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
+			drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+		drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+			WPA_DRIVER_AUTH_SHARED |
+			WPA_DRIVER_AUTH_LEAP;
+		drv->capa.max_scan_ssids = 1;
+
+		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
+			   "flags 0x%x",
+			   drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+	} else {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+			   "assuming WPA is not supported");
+	}
+
+	drv->max_level = range->max_qual.level;
+
+	os_free(range);
+	return 0;
+}
+
+
+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
+				   const u8 *psk)
+{
+	struct iw_encode_ext *ext;
+	struct iwreq iwr;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		return 0;
+
+	if (!psk)
+		return 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	ext = os_zalloc(sizeof(*ext) + PMK_LEN);
+	if (ext == NULL)
+		return -1;
+
+	iwr.u.encoding.pointer = (caddr_t) ext;
+	iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
+	ext->key_len = PMK_LEN;
+	os_memcpy(&ext->key, psk, ext->key_len);
+	ext->alg = IW_ENCODE_ALG_PMK;
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
+	if (ret < 0)
+		perror("ioctl[SIOCSIWENCODEEXT] PMK");
+	os_free(ext);
+
+	return ret;
+}
+
+
+static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
+				       const u8 *addr, int key_idx,
+				       int set_tx, const u8 *seq,
+				       size_t seq_len,
+				       const u8 *key, size_t key_len)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+	struct iw_encode_ext *ext;
+
+	if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
+		wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
+			   __FUNCTION__, (unsigned long) seq_len);
+		return -1;
+	}
+
+	ext = os_zalloc(sizeof(*ext) + key_len);
+	if (ext == NULL)
+		return -1;
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.encoding.flags = key_idx + 1;
+	iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+	if (alg == WPA_ALG_NONE)
+		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+	iwr.u.encoding.pointer = (caddr_t) ext;
+	iwr.u.encoding.length = sizeof(*ext) + key_len;
+
+	if (addr == NULL || is_broadcast_ether_addr(addr))
+		ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
+	if (set_tx)
+		ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
+
+	ext->addr.sa_family = ARPHRD_ETHER;
+	if (addr)
+		os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
+	else
+		os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
+	if (key && key_len) {
+		os_memcpy(ext + 1, key, key_len);
+		ext->key_len = key_len;
+	}
+	switch (alg) {
+	case WPA_ALG_NONE:
+		ext->alg = IW_ENCODE_ALG_NONE;
+		break;
+	case WPA_ALG_WEP:
+		ext->alg = IW_ENCODE_ALG_WEP;
+		break;
+	case WPA_ALG_TKIP:
+		ext->alg = IW_ENCODE_ALG_TKIP;
+		break;
+	case WPA_ALG_CCMP:
+		ext->alg = IW_ENCODE_ALG_CCMP;
+		break;
+	case WPA_ALG_PMK:
+		ext->alg = IW_ENCODE_ALG_PMK;
+		break;
+#ifdef CONFIG_IEEE80211W
+	case WPA_ALG_IGTK:
+		ext->alg = IW_ENCODE_ALG_AES_CMAC;
+		break;
+#endif /* CONFIG_IEEE80211W */
+	default:
+		wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+			   __FUNCTION__, alg);
+		os_free(ext);
+		return -1;
+	}
+
+	if (seq && seq_len) {
+		ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
+		os_memcpy(ext->rx_seq, seq, seq_len);
+	}
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
+		ret = errno == EOPNOTSUPP ? -2 : -1;
+		if (errno == ENODEV) {
+			/*
+			 * ndiswrapper seems to be returning incorrect error
+			 * code.. */
+			ret = -2;
+		}
+
+		perror("ioctl[SIOCSIWENCODEEXT]");
+	}
+
+	os_free(ext);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_key - Configure encryption key
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @priv: Private driver interface data
+ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+ *	%WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
+ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
+ *	broadcast/default keys
+ * @key_idx: key index (0..3), usually 0 for unicast keys
+ * @set_tx: Configure this key as the default Tx key (only used when
+ *	driver does not support separate unicast/individual key
+ * @seq: Sequence number/packet number, seq_len octets, the next
+ *	packet number to be used for in replay protection; configured
+ *	for Rx keys (in most cases, this is only used with broadcast
+ *	keys and set to zero for unicast keys)
+ * @seq_len: Length of the seq, depends on the algorithm:
+ *	TKIP: 6 octets, CCMP: 6 octets
+ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+ *	8-byte Rx Mic Key
+ * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
+ *	TKIP: 32, CCMP: 16)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function uses SIOCSIWENCODEEXT by default, but tries to use
+ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
+ */
+int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+			    const u8 *addr, int key_idx,
+			    int set_tx, const u8 *seq, size_t seq_len,
+			    const u8 *key, size_t key_len)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+		   "key_len=%lu",
+		   __FUNCTION__, alg, key_idx, set_tx,
+		   (unsigned long) seq_len, (unsigned long) key_len);
+
+	ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
+					  seq, seq_len, key, key_len);
+	if (ret == 0)
+		return 0;
+
+	if (ret == -2 &&
+	    (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
+		wpa_printf(MSG_DEBUG, "Driver did not support "
+			   "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
+		ret = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "Driver did not support "
+			   "SIOCSIWENCODEEXT");
+		return ret;
+	}
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.encoding.flags = key_idx + 1;
+	iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+	if (alg == WPA_ALG_NONE)
+		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+	iwr.u.encoding.pointer = (caddr_t) key;
+	iwr.u.encoding.length = key_len;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWENCODE]");
+		ret = -1;
+	}
+
+	if (set_tx && alg != WPA_ALG_NONE) {
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+		iwr.u.encoding.flags = key_idx + 1;
+		iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+		iwr.u.encoding.pointer = (caddr_t) NULL;
+		iwr.u.encoding.length = 0;
+		if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+			perror("ioctl[SIOCSIWENCODE] (set_tx)");
+			ret = -1;
+		}
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_wext_set_countermeasures(void *priv,
+					       int enabled)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	return wpa_driver_wext_set_auth_param(drv,
+					      IW_AUTH_TKIP_COUNTERMEASURES,
+					      enabled);
+}
+
+
+static int wpa_driver_wext_set_drop_unencrypted(void *priv,
+						int enabled)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	drv->use_crypt = enabled;
+	return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+					      enabled);
+}
+
+
+static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
+				const u8 *addr, int cmd, int reason_code)
+{
+	struct iwreq iwr;
+	struct iw_mlme mlme;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_memset(&mlme, 0, sizeof(mlme));
+	mlme.cmd = cmd;
+	mlme.reason_code = reason_code;
+	mlme.addr.sa_family = ARPHRD_ETHER;
+	os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+	iwr.u.data.pointer = (caddr_t) &mlme;
+	iwr.u.data.length = sizeof(mlme);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+		perror("ioctl[SIOCSIWMLME]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
+{
+	struct iwreq iwr;
+	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+#ifndef ANDROID
+	u8 ssid[32];
+	int i;
+#endif /* ANDROID */
+
+	/*
+	 * Only force-disconnect when the card is in infrastructure mode,
+	 * otherwise the driver might interpret the cleared BSSID and random
+	 * SSID as an attempt to create a new ad-hoc network.
+	 */
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWMODE]");
+		iwr.u.mode = IW_MODE_INFRA;
+	}
+
+	if (iwr.u.mode == IW_MODE_INFRA) {
+		/* Clear the BSSID selection */
+		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+				   "selection on disconnect");
+		}
+
+#ifndef ANDROID
+		if (drv->cfg80211) {
+			/*
+			 * cfg80211 supports SIOCSIWMLME commands, so there is
+			 * no need for the random SSID hack, but clear the
+			 * SSID.
+			 */
+			if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+				wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
+					   "SSID on disconnect");
+			}
+			return;
+		}
+
+		/*
+		 * Set a random SSID to make sure the driver will not be trying
+		 * to associate with something even if it does not understand
+		 * SIOCSIWMLME commands (or tries to associate automatically
+		 * after deauth/disassoc).
+		 */
+		for (i = 0; i < 32; i++)
+			ssid[i] = rand() & 0xFF;
+		if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
+				   "SSID to disconnect");
+		}
+#endif /* ANDROID */
+	}
+}
+
+
+static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
+					  int reason_code)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	int ret;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+	wpa_driver_wext_disconnect(drv);
+	return ret;
+}
+
+
+static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
+				      size_t ie_len)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = (caddr_t) ie;
+	iwr.u.data.length = ie_len;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWGENIE]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+int wpa_driver_wext_cipher2wext(int cipher)
+{
+	switch (cipher) {
+	case CIPHER_NONE:
+		return IW_AUTH_CIPHER_NONE;
+	case CIPHER_WEP40:
+		return IW_AUTH_CIPHER_WEP40;
+	case CIPHER_TKIP:
+		return IW_AUTH_CIPHER_TKIP;
+	case CIPHER_CCMP:
+		return IW_AUTH_CIPHER_CCMP;
+	case CIPHER_WEP104:
+		return IW_AUTH_CIPHER_WEP104;
+	default:
+		return 0;
+	}
+}
+
+
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
+{
+	switch (keymgmt) {
+	case KEY_MGMT_802_1X:
+	case KEY_MGMT_802_1X_NO_WPA:
+		return IW_AUTH_KEY_MGMT_802_1X;
+	case KEY_MGMT_PSK:
+		return IW_AUTH_KEY_MGMT_PSK;
+	default:
+		return 0;
+	}
+}
+
+
+static int
+wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
+				  struct wpa_driver_associate_params *params)
+{
+	struct iwreq iwr;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+		   "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	/* Just changing mode, not actual keys */
+	iwr.u.encoding.flags = 0;
+	iwr.u.encoding.pointer = (caddr_t) NULL;
+	iwr.u.encoding.length = 0;
+
+	/*
+	 * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+	 * different things. Here they are used to indicate Open System vs.
+	 * Shared Key authentication algorithm. However, some drivers may use
+	 * them to select between open/restricted WEP encrypted (open = allow
+	 * both unencrypted and encrypted frames; restricted = only allow
+	 * encrypted frames).
+	 */
+
+	if (!drv->use_crypt) {
+		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+	} else {
+		if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+			iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+		if (params->auth_alg & WPA_AUTH_ALG_SHARED)
+			iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+	}
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWENCODE]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+int wpa_driver_wext_associate(void *priv,
+			      struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	int ret = 0;
+	int allow_unencrypted_eapol;
+	int value;
+
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+	if (drv->cfg80211) {
+		/*
+		 * Stop cfg80211 from trying to associate before we are done
+		 * with all parameters.
+		 */
+		wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
+	}
+
+	if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
+	    < 0)
+		ret = -1;
+	if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
+		ret = -1;
+	if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+		ret = -1;
+
+	/*
+	 * If the driver did not support SIOCSIWAUTH, fallback to
+	 * SIOCSIWENCODE here.
+	 */
+	if (drv->auth_alg_fallback &&
+	    wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
+		ret = -1;
+
+	if (!params->bssid &&
+	    wpa_driver_wext_set_bssid(drv, NULL) < 0)
+		ret = -1;
+
+	/* TODO: should consider getting wpa version and cipher/key_mgmt suites
+	 * from configuration, not from here, where only the selected suite is
+	 * available */
+	if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+	    < 0)
+		ret = -1;
+	if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+		value = IW_AUTH_WPA_VERSION_DISABLED;
+	else if (params->wpa_ie[0] == WLAN_EID_RSN)
+		value = IW_AUTH_WPA_VERSION_WPA2;
+	else
+		value = IW_AUTH_WPA_VERSION_WPA;
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_WPA_VERSION, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_cipher2wext(params->group_suite);
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_CIPHER_GROUP, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_KEY_MGMT, value) < 0)
+		ret = -1;
+	value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+		params->pairwise_suite != CIPHER_NONE ||
+		params->group_suite != CIPHER_NONE ||
+		params->wpa_ie_len;
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_PRIVACY_INVOKED, value) < 0)
+		ret = -1;
+
+	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
+	 * not using WPA. IEEE 802.1X specifies that these frames are not
+	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
+	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+	    params->key_mgmt_suite == KEY_MGMT_PSK)
+		allow_unencrypted_eapol = 0;
+	else
+		allow_unencrypted_eapol = 1;
+
+	if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
+		ret = -1;
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_RX_UNENCRYPTED_EAPOL,
+					   allow_unencrypted_eapol) < 0)
+		ret = -1;
+#ifdef CONFIG_IEEE80211W
+	switch (params->mgmt_frame_protection) {
+	case NO_MGMT_FRAME_PROTECTION:
+		value = IW_AUTH_MFP_DISABLED;
+		break;
+	case MGMT_FRAME_PROTECTION_OPTIONAL:
+		value = IW_AUTH_MFP_OPTIONAL;
+		break;
+	case MGMT_FRAME_PROTECTION_REQUIRED:
+		value = IW_AUTH_MFP_REQUIRED;
+		break;
+	};
+	if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
+		ret = -1;
+#endif /* CONFIG_IEEE80211W */
+	if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
+		ret = -1;
+	if (!drv->cfg80211 &&
+	    wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+		ret = -1;
+	if (params->bssid &&
+	    wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+		ret = -1;
+	if (drv->cfg80211 &&
+	    wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+		ret = -1;
+
+	return ret;
+}
+
+
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	int algs = 0, res;
+
+	if (auth_alg & WPA_AUTH_ALG_OPEN)
+		algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+	if (auth_alg & WPA_AUTH_ALG_SHARED)
+		algs |= IW_AUTH_ALG_SHARED_KEY;
+	if (auth_alg & WPA_AUTH_ALG_LEAP)
+		algs |= IW_AUTH_ALG_LEAP;
+	if (algs == 0) {
+		/* at least one algorithm should be set */
+		algs = IW_AUTH_ALG_OPEN_SYSTEM;
+	}
+
+	res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+					     algs);
+	drv->auth_alg_fallback = res == -2;
+	return res;
+}
+
+
+/**
+ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_mode(void *priv, int mode)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = -1;
+	unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.mode = new_mode;
+	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+		ret = 0;
+		goto done;
+	}
+
+	if (errno != EBUSY) {
+		perror("ioctl[SIOCSIWMODE]");
+		goto done;
+	}
+
+	/* mac80211 doesn't allow mode changes while the device is up, so if
+	 * the device isn't in the mode we're about to change to, take device
+	 * down, try to set the mode again, and bring it back up.
+	 */
+	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWMODE]");
+		goto done;
+	}
+
+	if (iwr.u.mode == new_mode) {
+		ret = 0;
+		goto done;
+	}
+
+	if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
+		/* Try to set the mode again while the interface is down */
+		iwr.u.mode = new_mode;
+		if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+			perror("ioctl[SIOCSIWMODE]");
+		else
+			ret = 0;
+
+		(void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
+	}
+
+done:
+	return ret;
+}
+
+
+static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
+				 u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+	struct iwreq iwr;
+	struct iw_pmksa pmksa;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_memset(&pmksa, 0, sizeof(pmksa));
+	pmksa.cmd = cmd;
+	pmksa.bssid.sa_family = ARPHRD_ETHER;
+	if (bssid)
+		os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+	if (pmkid)
+		os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+	iwr.u.data.pointer = (caddr_t) &pmksa;
+	iwr.u.data.length = sizeof(pmksa);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+		if (errno != EOPNOTSUPP)
+			perror("ioctl[SIOCSIWPMKSA]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
+				     const u8 *pmkid)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
+		 			const u8 *pmkid)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	if (!drv->has_capability)
+		return -1;
+	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	return 0;
+}
+
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+					const char *ifname)
+{
+	if (ifname == NULL) {
+		drv->ifindex2 = -1;
+		return 0;
+	}
+
+	drv->ifindex2 = if_nametoindex(ifname);
+	if (drv->ifindex2 <= 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
+		   "wireless events", drv->ifindex2, ifname);
+
+	return 0;
+}
+
+
+int wpa_driver_wext_set_operstate(void *priv, int state)
+{
+	struct wpa_driver_wext_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+	drv->operstate = state;
+	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+				      state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
+{
+	return drv->we_version_compiled;
+}
+
+
+static const char * wext_get_radio_name(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	return drv->phyname;
+}
+
+
+#ifdef ANDROID
+
+static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
+{
+	struct iwreq iwr;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = sizeof(buf);
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
+			   cmd);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
+				"HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	return 0;
+}
+
+
+static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
+			   u32 interval)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/*
+		 * Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination.
+		 */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	/* TODO: consider using interval parameter (interval in msec) instead
+	 * of hardcoded value here */
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = bp;
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO,
+				WPA_EVENT_DRIVER_STATE "HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	drv->bgscan_enabled = 1;
+
+	return android_wext_cmd(drv, "PNOFORCE 1");
+}
+
+
+static int wext_stop_sched_scan(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	drv->bgscan_enabled = 0;
+	return android_wext_cmd(drv, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
+const struct wpa_driver_ops wpa_driver_wext_ops = {
+	.name = "wext",
+	.desc = "Linux wireless extensions (generic)",
+	.get_bssid = wpa_driver_wext_get_bssid,
+	.get_ssid = wpa_driver_wext_get_ssid,
+	.set_key = wpa_driver_wext_set_key,
+	.set_countermeasures = wpa_driver_wext_set_countermeasures,
+	.scan2 = wpa_driver_wext_scan,
+	.get_scan_results2 = wpa_driver_wext_get_scan_results,
+	.deauthenticate = wpa_driver_wext_deauthenticate,
+	.associate = wpa_driver_wext_associate,
+	.init = wpa_driver_wext_init,
+	.deinit = wpa_driver_wext_deinit,
+	.add_pmkid = wpa_driver_wext_add_pmkid,
+	.remove_pmkid = wpa_driver_wext_remove_pmkid,
+	.flush_pmkid = wpa_driver_wext_flush_pmkid,
+	.get_capa = wpa_driver_wext_get_capa,
+	.set_operstate = wpa_driver_wext_set_operstate,
+	.get_radio_name = wext_get_radio_name,
+#ifdef ANDROID
+	.sched_scan = wext_sched_scan,
+	.stop_sched_scan = wext_stop_sched_scan,
+#endif /* ANDROID */
+};

Deleted: vendor/wpa/2.0/src/drivers/driver_wext.h
===================================================================
--- vendor/wpa/dist/src/drivers/driver_wext.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_wext.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,82 +0,0 @@
-/*
- * WPA Supplicant - driver_wext exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DRIVER_WEXT_H
-#define DRIVER_WEXT_H
-
-#include <net/if.h>
-
-struct wpa_driver_wext_data {
-	void *ctx;
-	struct netlink_data *netlink;
-	int ioctl_sock;
-	int mlme_sock;
-	char ifname[IFNAMSIZ + 1];
-	int ifindex;
-	int ifindex2;
-	int if_removed;
-	u8 *assoc_req_ies;
-	size_t assoc_req_ies_len;
-	u8 *assoc_resp_ies;
-	size_t assoc_resp_ies_len;
-	struct wpa_driver_capa capa;
-	int has_capability;
-	int we_version_compiled;
-
-	/* for set_auth_alg fallback */
-	int use_crypt;
-	int auth_alg_fallback;
-
-	int operstate;
-
-	char mlmedev[IFNAMSIZ + 1];
-
-	int scan_complete_events;
-
-	int cfg80211; /* whether driver is using cfg80211 */
-};
-
-int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
-int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
-int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
-int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
-int wpa_driver_wext_set_freq(void *priv, int freq);
-int wpa_driver_wext_set_mode(void *priv, int mode);
-int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			    const u8 *addr, int key_idx,
-			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len);
-int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
-struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
-
-void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
-					const char *ifname);
-
-void * wpa_driver_wext_init(void *ctx, const char *ifname);
-void wpa_driver_wext_deinit(void *priv);
-
-int wpa_driver_wext_set_operstate(void *priv, int state);
-int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
-
-int wpa_driver_wext_associate(void *priv,
-			      struct wpa_driver_associate_params *params);
-int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
-int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
-				   int idx, u32 value);
-int wpa_driver_wext_cipher2wext(int cipher);
-int wpa_driver_wext_keymgmt2wext(int keymgmt);
-
-#endif /* DRIVER_WEXT_H */

Copied: vendor/wpa/2.0/src/drivers/driver_wext.h (from rev 9639, vendor/wpa/dist/src/drivers/driver_wext.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_wext.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_wext.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,87 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_WEXT_H
+#define DRIVER_WEXT_H
+
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+	void *ctx;
+	struct netlink_data *netlink;
+	int ioctl_sock;
+	int mlme_sock;
+	char ifname[IFNAMSIZ + 1];
+	char phyname[32];
+	int ifindex;
+	int ifindex2;
+	int if_removed;
+	int if_disabled;
+	struct rfkill_data *rfkill;
+	u8 *assoc_req_ies;
+	size_t assoc_req_ies_len;
+	u8 *assoc_resp_ies;
+	size_t assoc_resp_ies_len;
+	struct wpa_driver_capa capa;
+	int has_capability;
+	int we_version_compiled;
+
+	/* for set_auth_alg fallback */
+	int use_crypt;
+	int auth_alg_fallback;
+
+	int operstate;
+
+	char mlmedev[IFNAMSIZ + 1];
+
+	int scan_complete_events;
+
+	int cfg80211; /* whether driver is using cfg80211 */
+
+	u8 max_level;
+
+#ifdef ANDROID
+	int errors;
+	int driver_is_started;
+	int bgscan_enabled;
+#endif /* ANDROID */
+};
+
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_wext_set_freq(void *priv, int freq);
+int wpa_driver_wext_set_mode(void *priv, int mode);
+int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+			    const u8 *addr, int key_idx,
+			    int set_tx, const u8 *seq, size_t seq_len,
+			    const u8 *key, size_t key_len);
+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
+
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+					const char *ifname);
+
+void * wpa_driver_wext_init(void *ctx, const char *ifname);
+void wpa_driver_wext_deinit(void *priv);
+
+int wpa_driver_wext_set_operstate(void *priv, int state);
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
+
+int wpa_driver_wext_associate(void *priv,
+			      struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+				   int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
+#endif /* DRIVER_WEXT_H */

Deleted: vendor/wpa/2.0/src/drivers/driver_wired.c
===================================================================
--- vendor/wpa/dist/src/drivers/driver_wired.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/driver_wired.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,622 +0,0 @@
-/*
- * Wired Ethernet driver interface
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2004, Gunter Burchardt <tira at isx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#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>
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
-
-#include "common.h"
-#include "eloop.h"
-#include "driver.h"
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee8023_hdr {
-	u8 dest[6];
-	u8 src[6];
-	u16 ethertype;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-
-struct wpa_driver_wired_data {
-	char ifname[IFNAMSIZ + 1];
-	void *ctx;
-
-	int sock; /* raw packet socket for driver access */
-	int dhcp_sock; /* socket for dhcp packets */
-	int use_pae_group_addr;
-
-	int pf_sock;
-	int membership, multi, iff_allmulti, iff_up;
-};
-
-
-/* TODO: detecting new devices should eventually be changed from using DHCP
- * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
- * based on ebtables, etc. */
-
-struct dhcp_message {
-	u_int8_t op;
-	u_int8_t htype;
-	u_int8_t hlen;
-	u_int8_t hops;
-	u_int32_t xid;
-	u_int16_t secs;
-	u_int16_t flags;
-	u_int32_t ciaddr;
-	u_int32_t yiaddr;
-	u_int32_t siaddr;
-	u_int32_t giaddr;
-	u_int8_t chaddr[16];
-	u_int8_t sname[64];
-	u_int8_t file[128];
-	u_int32_t cookie;
-	u_int8_t options[308]; /* 312 - cookie */
-};
-
-
-static int wired_multicast_membership(int sock, int ifindex,
-				      const u8 *addr, int add)
-{
-#ifdef __linux__
-	struct packet_mreq mreq;
-
-	if (sock < 0)
-		return -1;
-
-	os_memset(&mreq, 0, sizeof(mreq));
-	mreq.mr_ifindex = ifindex;
-	mreq.mr_type = PACKET_MR_MULTICAST;
-	mreq.mr_alen = ETH_ALEN;
-	os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
-	if (setsockopt(sock, SOL_PACKET,
-		       add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
-		       &mreq, sizeof(mreq)) < 0) {
-		perror("setsockopt");
-		return -1;
-	}
-	return 0;
-#else /* __linux__ */
-	return -1;
-#endif /* __linux__ */
-}
-
-
-#ifdef __linux__
-static void handle_data(void *ctx, unsigned char *buf, size_t len)
-{
-#ifdef HOSTAPD
-	struct ieee8023_hdr *hdr;
-	u8 *pos, *sa;
-	size_t left;
-	union wpa_event_data event;
-
-	/* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
-	 * 2 byte ethertype */
-	if (len < 14) {
-		wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
-			   (unsigned long) len);
-		return;
-	}
-
-	hdr = (struct ieee8023_hdr *) buf;
-
-	switch (ntohs(hdr->ethertype)) {
-		case ETH_P_PAE:
-			wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
-			sa = hdr->src;
-			os_memset(&event, 0, sizeof(event));
-			event.new_sta.addr = sa;
-			wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
-
-			pos = (u8 *) (hdr + 1);
-			left = len - sizeof(*hdr);
-			drv_event_eapol_rx(ctx, sa, pos, left);
-		break;
-
-	default:
-		wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
-			   ntohs(hdr->ethertype));
-		break;
-	}
-#endif /* HOSTAPD */
-}
-
-
-static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	int len;
-	unsigned char buf[3000];
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	handle_data(eloop_ctx, buf, len);
-}
-
-
-static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	int len;
-	unsigned char buf[3000];
-	struct dhcp_message *msg;
-	u8 *mac_address;
-	union wpa_event_data event;
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		perror("recv");
-		return;
-	}
-
-	/* must contain at least dhcp_message->chaddr */
-	if (len < 44) {
-		wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
-		return;
-	}
-
-	msg = (struct dhcp_message *) buf;
-	mac_address = (u8 *) &(msg->chaddr);
-
-	wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
-		   MAC2STR(mac_address));
-
-	os_memset(&event, 0, sizeof(event));
-	event.new_sta.addr = mac_address;
-	wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event);
-}
-#endif /* __linux__ */
-
-
-static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
-{
-#ifdef __linux__
-	struct ifreq ifr;
-	struct sockaddr_ll addr;
-	struct sockaddr_in addr2;
-	int n = 1;
-
-	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
-	if (drv->sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
-		return -1;
-	}
-
-	if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
-		printf("Could not register read socket\n");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-	if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sll_family = AF_PACKET;
-	addr.sll_ifindex = ifr.ifr_ifindex;
-	wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
-		   addr.sll_ifindex);
-
-	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
-		return -1;
-	}
-
-	/* filter multicast address */
-	if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
-				       pae_group_addr, 1) < 0) {
-		wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
-			   "membership");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
-	if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFHWADDR)");
-		return -1;
-	}
-
-	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-		printf("Invalid HW-addr family 0x%04x\n",
-		       ifr.ifr_hwaddr.sa_family);
-		return -1;
-	}
-	os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-
-	/* setup dhcp listen socket for sta detection */
-	if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-		perror("socket call failed for dhcp");
-		return -1;
-	}
-
-	if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
-				     NULL)) {
-		printf("Could not register read socket\n");
-		return -1;
-	}
-
-	os_memset(&addr2, 0, sizeof(addr2));
-	addr2.sin_family = AF_INET;
-	addr2.sin_port = htons(67);
-	addr2.sin_addr.s_addr = INADDR_ANY;
-
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
-		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
-		return -1;
-	}
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
-		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
-	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
-		       (char *) &ifr, sizeof(ifr)) < 0) {
-		perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
-		return -1;
-	}
-
-	if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
-		 sizeof(struct sockaddr)) == -1) {
-		perror("bind");
-		return -1;
-	}
-
-	return 0;
-#else /* __linux__ */
-	return -1;
-#endif /* __linux__ */
-}
-
-
-static int wired_send_eapol(void *priv, const u8 *addr,
-			    const u8 *data, size_t data_len, int encrypt,
-			    const u8 *own_addr)
-{
-	struct wpa_driver_wired_data *drv = priv;
-	struct ieee8023_hdr *hdr;
-	size_t len;
-	u8 *pos;
-	int res;
-
-	len = sizeof(*hdr) + data_len;
-	hdr = os_zalloc(len);
-	if (hdr == NULL) {
-		printf("malloc() failed for wired_send_eapol(len=%lu)\n",
-		       (unsigned long) len);
-		return -1;
-	}
-
-	os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
-		  ETH_ALEN);
-	os_memcpy(hdr->src, own_addr, ETH_ALEN);
-	hdr->ethertype = htons(ETH_P_PAE);
-
-	pos = (u8 *) (hdr + 1);
-	os_memcpy(pos, data, data_len);
-
-	res = send(drv->sock, (u8 *) hdr, len, 0);
-	os_free(hdr);
-
-	if (res < 0) {
-		perror("wired_send_eapol: send");
-		printf("wired_send_eapol - packet len: %lu - failed\n",
-		       (unsigned long) len);
-	}
-
-	return res;
-}
-
-
-static void * wired_driver_hapd_init(struct hostapd_data *hapd,
-				     struct wpa_init_params *params)
-{
-	struct wpa_driver_wired_data *drv;
-
-	drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for wired driver data\n");
-		return NULL;
-	}
-
-	drv->ctx = hapd;
-	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
-	drv->use_pae_group_addr = params->use_pae_group_addr;
-
-	if (wired_init_sockets(drv, params->own_addr)) {
-		os_free(drv);
-		return NULL;
-	}
-
-	return drv;
-}
-
-
-static void wired_driver_hapd_deinit(void *priv)
-{
-	struct wpa_driver_wired_data *drv = priv;
-
-	if (drv->sock >= 0)
-		close(drv->sock);
-
-	if (drv->dhcp_sock >= 0)
-		close(drv->dhcp_sock);
-
-	os_free(drv);
-}
-
-
-static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
-{
-	ssid[0] = 0;
-	return 0;
-}
-
-
-static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
-{
-	/* Report PAE group address as the "BSSID" for wired connection. */
-	os_memcpy(bssid, pae_group_addr, ETH_ALEN);
-	return 0;
-}
-
-
-static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-	capa->flags = WPA_DRIVER_FLAGS_WIRED;
-	return 0;
-}
-
-
-static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
-{
-	struct ifreq ifr;
-	int s;
-
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCGIFFLAGS]");
-		close(s);
-		return -1;
-	}
-	close(s);
-	*flags = ifr.ifr_flags & 0xffff;
-	return 0;
-}
-
-
-static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
-{
-	struct ifreq ifr;
-	int s;
-
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	ifr.ifr_flags = flags & 0xffff;
-	if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCSIFFLAGS]");
-		close(s);
-		return -1;
-	}
-	close(s);
-	return 0;
-}
-
-
-static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
-{
-	struct ifreq ifr;
-	int s;
-
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket");
-		return -1;
-	}
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
-	ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
-	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-	{
-		struct sockaddr_dl *dlp;
-		dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
-		dlp->sdl_len = sizeof(struct sockaddr_dl);
-		dlp->sdl_family = AF_LINK;
-		dlp->sdl_index = 0;
-		dlp->sdl_nlen = 0;
-		dlp->sdl_alen = ETH_ALEN;
-		dlp->sdl_slen = 0;
-		os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
-	}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
-	{
-		struct sockaddr *sap;
-		sap = (struct sockaddr *) &ifr.ifr_addr;
-		sap->sa_len = sizeof(struct sockaddr);
-		sap->sa_family = AF_UNSPEC;
-		os_memcpy(sap->sa_data, addr, ETH_ALEN);
-	}
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
-	if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOC{ADD/DEL}MULTI]");
-		close(s);
-		return -1;
-	}
-	close(s);
-	return 0;
-}
-
-
-static void * wpa_driver_wired_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_wired_data *drv;
-	int flags;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ctx = ctx;
-
-#ifdef __linux__
-	drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
-	if (drv->pf_sock < 0)
-		perror("socket(PF_PACKET)");
-#else /* __linux__ */
-	drv->pf_sock = -1;
-#endif /* __linux__ */
-
-	if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
-	    !(flags & IFF_UP) &&
-	    wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
-		drv->iff_up = 1;
-	}
-
-	if (wired_multicast_membership(drv->pf_sock,
-				       if_nametoindex(drv->ifname),
-				       pae_group_addr, 1) == 0) {
-		wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
-			   "packet socket", __func__);
-		drv->membership = 1;
-	} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
-		wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
-			   "SIOCADDMULTI", __func__);
-		drv->multi = 1;
-	} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
-		wpa_printf(MSG_INFO, "%s: Could not get interface "
-			   "flags", __func__);
-		os_free(drv);
-		return NULL;
-	} else if (flags & IFF_ALLMULTI) {
-		wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
-			   "for multicast", __func__);
-	} else if (wpa_driver_wired_set_ifflags(ifname,
-						flags | IFF_ALLMULTI) < 0) {
-		wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
-			   __func__);
-		os_free(drv);
-		return NULL;
-	} else {
-		wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
-			   __func__);
-		drv->iff_allmulti = 1;
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_wired_deinit(void *priv)
-{
-	struct wpa_driver_wired_data *drv = priv;
-	int flags;
-
-	if (drv->membership &&
-	    wired_multicast_membership(drv->pf_sock,
-				       if_nametoindex(drv->ifname),
-				       pae_group_addr, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
-			   "group (PACKET)", __func__);
-	}
-
-	if (drv->multi &&
-	    wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
-			   "group (SIOCDELMULTI)", __func__);
-	}
-
-	if (drv->iff_allmulti &&
-	    (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
-	     wpa_driver_wired_set_ifflags(drv->ifname,
-					  flags & ~IFF_ALLMULTI) < 0)) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
-			   __func__);
-	}
-
-	if (drv->iff_up &&
-	    wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
-	    (flags & IFF_UP) &&
-	    wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
-			   __func__);
-	}
-
-	if (drv->pf_sock != -1)
-		close(drv->pf_sock);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_wired_ops = {
-	.name = "wired",
-	.desc = "Wired Ethernet driver",
-	.hapd_init = wired_driver_hapd_init,
-	.hapd_deinit = wired_driver_hapd_deinit,
-	.hapd_send_eapol = wired_send_eapol,
-	.get_ssid = wpa_driver_wired_get_ssid,
-	.get_bssid = wpa_driver_wired_get_bssid,
-	.get_capa = wpa_driver_wired_get_capa,
-	.init = wpa_driver_wired_init,
-	.deinit = wpa_driver_wired_deinit,
-};

Copied: vendor/wpa/2.0/src/drivers/driver_wired.c (from rev 9639, vendor/wpa/dist/src/drivers/driver_wired.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/driver_wired.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/driver_wired.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,623 @@
+/*
+ * Wired Ethernet driver interface
+ * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira at isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <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>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
+#ifdef __sun__
+#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 */
+
+struct ieee8023_hdr {
+	u8 dest[6];
+	u8 src[6];
+	u16 ethertype;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_wired_data {
+	char ifname[IFNAMSIZ + 1];
+	void *ctx;
+
+	int sock; /* raw packet socket for driver access */
+	int dhcp_sock; /* socket for dhcp packets */
+	int use_pae_group_addr;
+
+	int pf_sock;
+	int membership, multi, iff_allmulti, iff_up;
+};
+
+
+/* TODO: detecting new devices should eventually be changed from using DHCP
+ * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
+ * based on ebtables, etc. */
+
+struct dhcp_message {
+	u_int8_t op;
+	u_int8_t htype;
+	u_int8_t hlen;
+	u_int8_t hops;
+	u_int32_t xid;
+	u_int16_t secs;
+	u_int16_t flags;
+	u_int32_t ciaddr;
+	u_int32_t yiaddr;
+	u_int32_t siaddr;
+	u_int32_t giaddr;
+	u_int8_t chaddr[16];
+	u_int8_t sname[64];
+	u_int8_t file[128];
+	u_int32_t cookie;
+	u_int8_t options[308]; /* 312 - cookie */
+};
+
+
+static int wired_multicast_membership(int sock, int ifindex,
+				      const u8 *addr, int add)
+{
+#ifdef __linux__
+	struct packet_mreq mreq;
+
+	if (sock < 0)
+		return -1;
+
+	os_memset(&mreq, 0, sizeof(mreq));
+	mreq.mr_ifindex = ifindex;
+	mreq.mr_type = PACKET_MR_MULTICAST;
+	mreq.mr_alen = ETH_ALEN;
+	os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+	if (setsockopt(sock, SOL_PACKET,
+		       add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+		       &mreq, sizeof(mreq)) < 0) {
+		perror("setsockopt");
+		return -1;
+	}
+	return 0;
+#else /* __linux__ */
+	return -1;
+#endif /* __linux__ */
+}
+
+
+#ifdef __linux__
+static void handle_data(void *ctx, unsigned char *buf, size_t len)
+{
+#ifdef HOSTAPD
+	struct ieee8023_hdr *hdr;
+	u8 *pos, *sa;
+	size_t left;
+	union wpa_event_data event;
+
+	/* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
+	 * 2 byte ethertype */
+	if (len < 14) {
+		wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	hdr = (struct ieee8023_hdr *) buf;
+
+	switch (ntohs(hdr->ethertype)) {
+		case ETH_P_PAE:
+			wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+			sa = hdr->src;
+			os_memset(&event, 0, sizeof(event));
+			event.new_sta.addr = sa;
+			wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
+
+			pos = (u8 *) (hdr + 1);
+			left = len - sizeof(*hdr);
+			drv_event_eapol_rx(ctx, sa, pos, left);
+		break;
+
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
+			   ntohs(hdr->ethertype));
+		break;
+	}
+#endif /* HOSTAPD */
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	int len;
+	unsigned char buf[3000];
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	handle_data(eloop_ctx, buf, len);
+}
+
+
+static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	int len;
+	unsigned char buf[3000];
+	struct dhcp_message *msg;
+	u8 *mac_address;
+	union wpa_event_data event;
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+
+	/* must contain at least dhcp_message->chaddr */
+	if (len < 44) {
+		wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
+		return;
+	}
+
+	msg = (struct dhcp_message *) buf;
+	mac_address = (u8 *) &(msg->chaddr);
+
+	wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
+		   MAC2STR(mac_address));
+
+	os_memset(&event, 0, sizeof(event));
+	event.new_sta.addr = mac_address;
+	wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event);
+}
+#endif /* __linux__ */
+
+
+static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
+{
+#ifdef __linux__
+	struct ifreq ifr;
+	struct sockaddr_ll addr;
+	struct sockaddr_in addr2;
+	int n = 1;
+
+	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+	if (drv->sock < 0) {
+		perror("socket[PF_PACKET,SOCK_RAW]");
+		return -1;
+	}
+
+	if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
+		printf("Could not register read socket\n");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+	if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_ifindex = ifr.ifr_ifindex;
+	wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+		   addr.sll_ifindex);
+
+	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		return -1;
+	}
+
+	/* filter multicast address */
+	if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
+				       pae_group_addr, 1) < 0) {
+		wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
+			   "membership");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+	if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+		perror("ioctl(SIOCGIFHWADDR)");
+		return -1;
+	}
+
+	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+		printf("Invalid HW-addr family 0x%04x\n",
+		       ifr.ifr_hwaddr.sa_family);
+		return -1;
+	}
+	os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	/* setup dhcp listen socket for sta detection */
+	if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+		perror("socket call failed for dhcp");
+		return -1;
+	}
+
+	if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
+				     NULL)) {
+		printf("Could not register read socket\n");
+		return -1;
+	}
+
+	os_memset(&addr2, 0, sizeof(addr2));
+	addr2.sin_family = AF_INET;
+	addr2.sin_port = htons(67);
+	addr2.sin_addr.s_addr = INADDR_ANY;
+
+	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
+		       sizeof(n)) == -1) {
+		perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+		return -1;
+	}
+	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
+		       sizeof(n)) == -1) {
+		perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
+	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
+		       (char *) &ifr, sizeof(ifr)) < 0) {
+		perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+		return -1;
+	}
+
+	if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
+		 sizeof(struct sockaddr)) == -1) {
+		perror("bind");
+		return -1;
+	}
+
+	return 0;
+#else /* __linux__ */
+	return -1;
+#endif /* __linux__ */
+}
+
+
+static int wired_send_eapol(void *priv, const u8 *addr,
+			    const u8 *data, size_t data_len, int encrypt,
+			    const u8 *own_addr, u32 flags)
+{
+	struct wpa_driver_wired_data *drv = priv;
+	struct ieee8023_hdr *hdr;
+	size_t len;
+	u8 *pos;
+	int res;
+
+	len = sizeof(*hdr) + data_len;
+	hdr = os_zalloc(len);
+	if (hdr == NULL) {
+		printf("malloc() failed for wired_send_eapol(len=%lu)\n",
+		       (unsigned long) len);
+		return -1;
+	}
+
+	os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
+		  ETH_ALEN);
+	os_memcpy(hdr->src, own_addr, ETH_ALEN);
+	hdr->ethertype = htons(ETH_P_PAE);
+
+	pos = (u8 *) (hdr + 1);
+	os_memcpy(pos, data, data_len);
+
+	res = send(drv->sock, (u8 *) hdr, len, 0);
+	os_free(hdr);
+
+	if (res < 0) {
+		perror("wired_send_eapol: send");
+		printf("wired_send_eapol - packet len: %lu - failed\n",
+		       (unsigned long) len);
+	}
+
+	return res;
+}
+
+
+static void * wired_driver_hapd_init(struct hostapd_data *hapd,
+				     struct wpa_init_params *params)
+{
+	struct wpa_driver_wired_data *drv;
+
+	drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
+	if (drv == NULL) {
+		printf("Could not allocate memory for wired driver data\n");
+		return NULL;
+	}
+
+	drv->ctx = hapd;
+	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+	drv->use_pae_group_addr = params->use_pae_group_addr;
+
+	if (wired_init_sockets(drv, params->own_addr)) {
+		os_free(drv);
+		return NULL;
+	}
+
+	return drv;
+}
+
+
+static void wired_driver_hapd_deinit(void *priv)
+{
+	struct wpa_driver_wired_data *drv = priv;
+
+	if (drv->sock >= 0)
+		close(drv->sock);
+
+	if (drv->dhcp_sock >= 0)
+		close(drv->dhcp_sock);
+
+	os_free(drv);
+}
+
+
+static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+	ssid[0] = 0;
+	return 0;
+}
+
+
+static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+	/* Report PAE group address as the "BSSID" for wired connection. */
+	os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+	capa->flags = WPA_DRIVER_FLAGS_WIRED;
+	return 0;
+}
+
+
+static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+	struct ifreq ifr;
+	int s;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+		perror("ioctl[SIOCGIFFLAGS]");
+		close(s);
+		return -1;
+	}
+	close(s);
+	*flags = ifr.ifr_flags & 0xffff;
+	return 0;
+}
+
+
+static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
+{
+	struct ifreq ifr;
+	int s;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	ifr.ifr_flags = flags & 0xffff;
+	if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+		perror("ioctl[SIOCSIFFLAGS]");
+		close(s);
+		return -1;
+	}
+	close(s);
+	return 0;
+}
+
+
+static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+	struct ifreq ifr;
+	int s;
+
+#ifdef __sun__
+	return -1;
+#endif /* __sun__ */
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+	ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+	{
+		struct sockaddr_dl *dlp;
+		dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+		dlp->sdl_len = sizeof(struct sockaddr_dl);
+		dlp->sdl_family = AF_LINK;
+		dlp->sdl_index = 0;
+		dlp->sdl_nlen = 0;
+		dlp->sdl_alen = ETH_ALEN;
+		dlp->sdl_slen = 0;
+		os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+	}
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+	{
+		struct sockaddr *sap;
+		sap = (struct sockaddr *) &ifr.ifr_addr;
+		sap->sa_len = sizeof(struct sockaddr);
+		sap->sa_family = AF_UNSPEC;
+		os_memcpy(sap->sa_data, addr, ETH_ALEN);
+	}
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+	if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+		perror("ioctl[SIOC{ADD/DEL}MULTI]");
+		close(s);
+		return -1;
+	}
+	close(s);
+	return 0;
+}
+
+
+static void * wpa_driver_wired_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_wired_data *drv;
+	int flags;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+	drv->ctx = ctx;
+
+#ifdef __linux__
+	drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+	if (drv->pf_sock < 0)
+		perror("socket(PF_PACKET)");
+#else /* __linux__ */
+	drv->pf_sock = -1;
+#endif /* __linux__ */
+
+	if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
+	    !(flags & IFF_UP) &&
+	    wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
+		drv->iff_up = 1;
+	}
+
+	if (wired_multicast_membership(drv->pf_sock,
+				       if_nametoindex(drv->ifname),
+				       pae_group_addr, 1) == 0) {
+		wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+			   "packet socket", __func__);
+		drv->membership = 1;
+	} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+		wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+			   "SIOCADDMULTI", __func__);
+		drv->multi = 1;
+	} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
+		wpa_printf(MSG_INFO, "%s: Could not get interface "
+			   "flags", __func__);
+		os_free(drv);
+		return NULL;
+	} else if (flags & IFF_ALLMULTI) {
+		wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
+			   "for multicast", __func__);
+	} else if (wpa_driver_wired_set_ifflags(ifname,
+						flags | IFF_ALLMULTI) < 0) {
+		wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
+			   __func__);
+		os_free(drv);
+		return NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
+			   __func__);
+		drv->iff_allmulti = 1;
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_wired_deinit(void *priv)
+{
+	struct wpa_driver_wired_data *drv = priv;
+	int flags;
+
+	if (drv->membership &&
+	    wired_multicast_membership(drv->pf_sock,
+				       if_nametoindex(drv->ifname),
+				       pae_group_addr, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+			   "group (PACKET)", __func__);
+	}
+
+	if (drv->multi &&
+	    wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+			   "group (SIOCDELMULTI)", __func__);
+	}
+
+	if (drv->iff_allmulti &&
+	    (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
+	     wpa_driver_wired_set_ifflags(drv->ifname,
+					  flags & ~IFF_ALLMULTI) < 0)) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+			   __func__);
+	}
+
+	if (drv->iff_up &&
+	    wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
+	    (flags & IFF_UP) &&
+	    wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+			   __func__);
+	}
+
+	if (drv->pf_sock != -1)
+		close(drv->pf_sock);
+
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_wired_ops = {
+	.name = "wired",
+	.desc = "Wired Ethernet driver",
+	.hapd_init = wired_driver_hapd_init,
+	.hapd_deinit = wired_driver_hapd_deinit,
+	.hapd_send_eapol = wired_send_eapol,
+	.get_ssid = wpa_driver_wired_get_ssid,
+	.get_bssid = wpa_driver_wired_get_bssid,
+	.get_capa = wpa_driver_wired_get_capa,
+	.init = wpa_driver_wired_init,
+	.deinit = wpa_driver_wired_deinit,
+};

Deleted: vendor/wpa/2.0/src/drivers/drivers.c
===================================================================
--- vendor/wpa/dist/src/drivers/drivers.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/drivers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,139 +0,0 @@
-/*
- * Driver interface list
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.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_HERMES
-extern struct wpa_driver_ops wpa_driver_hermes_ops; /* driver_hermes.c */
-#endif /* CONFIG_DRIVER_HERMES */
-#ifdef CONFIG_DRIVER_MADWIFI
-extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
-#endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_ATMEL
-extern struct wpa_driver_ops wpa_driver_atmel_ops; /* driver_atmel.c */
-#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_NDISWRAPPER
-/* driver_ndiswrapper.c */
-extern struct wpa_driver_ops wpa_driver_ndiswrapper_ops;
-#endif /* CONFIG_DRIVER_NDISWRAPPER */
-#ifdef CONFIG_DRIVER_BROADCOM
-extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
-#endif /* CONFIG_DRIVER_BROADCOM */
-#ifdef CONFIG_DRIVER_IPW
-extern struct wpa_driver_ops wpa_driver_ipw_ops; /* driver_ipw.c */
-#endif /* CONFIG_DRIVER_IPW */
-#ifdef CONFIG_DRIVER_BSD
-extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
-#endif /* CONFIG_DRIVER_BSD */
-#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_TEST
-extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
-#endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
-#endif /* CONFIG_DRIVER_IPHONE */
-#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 */
-
-
-struct wpa_driver_ops *wpa_drivers[] =
-{
-#ifdef CONFIG_DRIVER_WEXT
-	&wpa_driver_wext_ops,
-#endif /* CONFIG_DRIVER_WEXT */
-#ifdef CONFIG_DRIVER_NL80211
-	&wpa_driver_nl80211_ops,
-#endif /* CONFIG_DRIVER_NL80211 */
-#ifdef CONFIG_DRIVER_HOSTAP
-	&wpa_driver_hostap_ops,
-#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_HERMES
-	&wpa_driver_hermes_ops,
-#endif /* CONFIG_DRIVER_HERMES */
-#ifdef CONFIG_DRIVER_MADWIFI
-	&wpa_driver_madwifi_ops,
-#endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_ATMEL
-	&wpa_driver_atmel_ops,
-#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_NDISWRAPPER
-	&wpa_driver_ndiswrapper_ops,
-#endif /* CONFIG_DRIVER_NDISWRAPPER */
-#ifdef CONFIG_DRIVER_BROADCOM
-	&wpa_driver_broadcom_ops,
-#endif /* CONFIG_DRIVER_BROADCOM */
-#ifdef CONFIG_DRIVER_IPW
-	&wpa_driver_ipw_ops,
-#endif /* CONFIG_DRIVER_IPW */
-#ifdef CONFIG_DRIVER_BSD
-	&wpa_driver_bsd_ops,
-#endif /* CONFIG_DRIVER_BSD */
-#ifdef CONFIG_DRIVER_NDIS
-	&wpa_driver_ndis_ops,
-#endif /* CONFIG_DRIVER_NDIS */
-#ifdef CONFIG_DRIVER_WIRED
-	&wpa_driver_wired_ops,
-#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_TEST
-	&wpa_driver_test_ops,
-#endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-	&wpa_driver_ralink_ops,
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-	&wpa_driver_osx_ops,
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-	&wpa_driver_iphone_ops,
-#endif /* CONFIG_DRIVER_IPHONE */
-#ifdef CONFIG_DRIVER_ROBOSWITCH
-	&wpa_driver_roboswitch_ops,
-#endif /* CONFIG_DRIVER_ROBOSWITCH */
-#ifdef CONFIG_DRIVER_ATHEROS
-	&wpa_driver_atheros_ops,
-#endif /* CONFIG_DRIVER_ATHEROS */
-#ifdef CONFIG_DRIVER_NONE
-	&wpa_driver_none_ops,
-#endif /* CONFIG_DRIVER_NONE */
-	NULL
-};

Copied: vendor/wpa/2.0/src/drivers/drivers.c (from rev 9639, vendor/wpa/dist/src/drivers/drivers.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/drivers.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/drivers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,84 @@
+/*
+ * Driver interface list
+ * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.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_MADWIFI
+extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_BSD
+extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#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_TEST
+extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
+#endif /* CONFIG_DRIVER_TEST */
+#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 */
+
+
+struct wpa_driver_ops *wpa_drivers[] =
+{
+#ifdef CONFIG_DRIVER_WEXT
+	&wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+	&wpa_driver_nl80211_ops,
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+	&wpa_driver_hostap_ops,
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_MADWIFI
+	&wpa_driver_madwifi_ops,
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_BSD
+	&wpa_driver_bsd_ops,
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_NDIS
+	&wpa_driver_ndis_ops,
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+	&wpa_driver_wired_ops,
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_TEST
+	&wpa_driver_test_ops,
+#endif /* CONFIG_DRIVER_TEST */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+	&wpa_driver_roboswitch_ops,
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+	&wpa_driver_atheros_ops,
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+	&wpa_driver_none_ops,
+#endif /* CONFIG_DRIVER_NONE */
+	NULL
+};

Deleted: vendor/wpa/2.0/src/drivers/drivers.mak
===================================================================
--- vendor/wpa/dist/src/drivers/drivers.mak	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/drivers.mak	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,181 +0,0 @@
-##### COMMON DRIVERS
-
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += ../src/drivers/driver_hostap.o
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_WIRED
-DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
-DRV_OBJS += ../src/drivers/driver_wired.o
-endif
-
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_NL80211
-DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
-DRV_OBJS += ../src/drivers/driver_nl80211.o
-DRV_OBJS += ../src/utils/radiotap.o
-NEED_SME=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-DRV_LIBS += -lnl
-
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
-endif
-endif
-
-ifdef CONFIG_DRIVER_BSD
-ifndef CONFIG_L2_PACKET
-CONFIG_L2_PACKET=freebsd
-endif
-DRV_CFLAGS += -DCONFIG_DRIVER_BSD
-DRV_OBJS += ../src/drivers/driver_bsd.o
-CONFIG_L2_FREEBSD=y
-CONFIG_DNET_PCAP=y
-endif
-
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += ../src/drivers/driver_test.o
-NEED_AP_MLME=y
-endif
-
-ifdef CONFIG_DRIVER_NONE
-DRV_CFLAGS += -DCONFIG_DRIVER_NONE
-DRV_OBJS += ../src/drivers/driver_none.o
-endif
-
-##### PURE AP DRIVERS
-
-ifdef CONFIG_DRIVER_ATHEROS
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
-DRV_AP_OBJS += ../src/drivers/driver_atheros.o
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-##### PURE CLIENT DRIVERS
-
-ifdef CONFIG_DRIVER_WEXT
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
-CONFIG_WIRELESS_EXTENSION=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_HERMES
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_HERMES
-DRV_WPA_OBJS += ../src/drivers/driver_hermes.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_ATMEL
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ATMEL
-DRV_WPA_OBJS += ../src/drivers/driver_atmel.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_NDISWRAPPER
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
-DRV_WPA_OBJS += ../src/drivers/driver_ndiswrapper.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += ../src/drivers/driver_ralink.o
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o
-endif
-
-ifdef CONFIG_DRIVER_IPW
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPW
-DRV_WPA_OBJS += ../src/drivers/driver_ipw.o
-CONFIG_WIRELESS_EXTENSION=y
-endif
-
-ifdef CONFIG_DRIVER_NDIS
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
-DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
-ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o
-endif
-ifndef CONFIG_L2_PACKET
-CONFIG_L2_PACKET=pcap
-endif
-CONFIG_WINPCAP=y
-ifdef CONFIG_USE_NDISUIO
-DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
-endif
-endif
-
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += ../src/drivers/driver_osx.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += ../src/drivers/driver_iphone.o
-DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
-ifdef CONFIG_DRIVER_ROBOSWITCH
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
-DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
-endif
-
-ifdef CONFIG_WIRELESS_EXTENSION
-DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
-DRV_WPA_OBJS += ../src/drivers/driver_wext.o
-endif
-
-ifdef NEED_NETLINK
-DRV_OBJS += ../src/drivers/netlink.o
-endif
-
-ifdef NEED_LINUX_IOCTL
-DRV_OBJS += ../src/drivers/linux_ioctl.o
-endif
-
-
-##### COMMON VARS
-DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
-DRV_WPA_CFLAGS += $(DRV_CFLAGS)
-DRV_AP_CFLAGS += $(DRV_CFLAGS)
-
-DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
-DRV_WPA_LIBS += $(DRV_LIBS)
-DRV_AP_LIBS += $(DRV_LIBS)
-
-DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
-DRV_WPA_OBJS += $(DRV_OBJS)
-DRV_AP_OBJS += $(DRV_OBJS)
-
-DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
-DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
-DRV_AP_LDFLAGS += $(DRV_LDFLAGS)

Copied: vendor/wpa/2.0/src/drivers/drivers.mak (from rev 9639, vendor/wpa/dist/src/drivers/drivers.mak)
===================================================================
--- vendor/wpa/2.0/src/drivers/drivers.mak	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/drivers.mak	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,183 @@
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
+
+##### COMMON DRIVERS
+
+ifdef CONFIG_DRIVER_WIRED
+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
+DRV_OBJS += ../src/drivers/driver_wired.o
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
+DRV_OBJS += ../src/drivers/driver_nl80211.o
+DRV_OBJS += ../src/utils/radiotap.o
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += ../src/drivers/driver_bsd.o
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+DRV_CFLAGS += -DCONFIG_DRIVER_TEST
+DRV_OBJS += ../src/drivers/driver_test.o
+NEED_AP_MLME=y
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += ../src/drivers/driver_none.o
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += ../src/drivers/driver_atheros.o
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += ../src/drivers/driver_wext.o
+NEED_RFKILL=y
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += ../src/drivers/netlink.o
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += ../src/drivers/linux_ioctl.o
+endif
+
+ifdef NEED_RFKILL
+DRV_OBJS += ../src/drivers/rfkill.o
+endif
+
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+endif
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)

Copied: vendor/wpa/2.0/src/drivers/drivers.mk (from rev 9639, vendor/wpa/dist/src/drivers/drivers.mk)
===================================================================
--- vendor/wpa/2.0/src/drivers/drivers.mk	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/drivers.mk	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,187 @@
+##### CLEAR VARS
+
+DRV_CFLAGS =
+DRV_WPA_CFLAGS =
+DRV_AP_CFLAGS =
+DRV_OBJS =
+DRV_WPA_OBJS =
+DRV_AP_OBJS =
+DRV_LIBS =
+DRV_WPA_LIBS =
+DRV_AP_LIBS =
+
+##### COMMON DRIVERS
+
+ifdef CONFIG_DRIVER_WIRED
+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
+DRV_OBJS += src/drivers/driver_wired.c
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
+DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/utils/radiotap.c
+NEED_SME=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+
+ifdef CONFIG_DRIVER_BSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_BSD
+DRV_OBJS += src/drivers/driver_bsd.c
+CONFIG_L2_FREEBSD=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+DRV_CFLAGS += -DCONFIG_DRIVER_TEST
+DRV_OBJS += src/drivers/driver_test.c
+NEED_AP_MLME=y
+endif
+
+ifdef CONFIG_DRIVER_NONE
+DRV_CFLAGS += -DCONFIG_DRIVER_NONE
+DRV_OBJS += src/drivers/driver_none.c
+endif
+
+##### PURE AP DRIVERS
+
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
+DRV_AP_OBJS += src/drivers/driver_madwifi.c
+CONFIG_WIRELESS_EXTENSION=y
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
+DRV_AP_OBJS += src/drivers/driver_atheros.c
+CONFIG_L2_PACKET=linux
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+endif
+
+##### PURE CLIENT DRIVERS
+
+ifdef CONFIG_DRIVER_WEXT
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+NEED_NETLINK=y
+NEED_LINUX_IOCTL=y
+NEED_RFKILL=y
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
+DRV_WPA_OBJS += src/drivers/driver_ndis.c
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+DRV_WPA_OBJS += src/drivers/driver_ndis_.c
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION
+DRV_WPA_OBJS += src/drivers/driver_wext.c
+NEED_RFKILL=y
+endif
+
+ifdef NEED_NETLINK
+DRV_OBJS += src/drivers/netlink.c
+endif
+
+ifdef NEED_LINUX_IOCTL
+DRV_OBJS += src/drivers/linux_ioctl.c
+endif
+
+ifdef NEED_RFKILL
+DRV_OBJS += src/drivers/rfkill.c
+endif
+
+ifdef CONFIG_DRIVER_CUSTOM
+DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
+endif
+
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_LIBS += -lnl-route-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_LIBS += -lnl-route
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
+endif
+endif
+endif
+
+##### COMMON VARS
+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
+DRV_WPA_CFLAGS += $(DRV_CFLAGS)
+DRV_AP_CFLAGS += $(DRV_CFLAGS)
+
+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS)
+DRV_WPA_LIBS += $(DRV_LIBS)
+DRV_AP_LIBS += $(DRV_LIBS)
+
+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS)
+DRV_WPA_OBJS += $(DRV_OBJS)
+DRV_AP_OBJS += $(DRV_OBJS)
+
+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS)
+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS)
+DRV_AP_LDFLAGS += $(DRV_LDFLAGS)

Deleted: vendor/wpa/2.0/src/drivers/linux_ioctl.c
===================================================================
--- vendor/wpa/dist/src/drivers/linux_ioctl.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/linux_ioctl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,198 +0,0 @@
-/*
- * Linux ioctl helper functions for driver wrappers
- * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-
-#include "utils/common.h"
-#include "linux_ioctl.h"
-
-
-int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
-{
-	struct ifreq ifr;
-
-	if (sock < 0)
-		return -1;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
-	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
-		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
-			   ifname, strerror(errno));
-		return -1;
-	}
-
-	if (dev_up) {
-		if (ifr.ifr_flags & IFF_UP)
-			return 0;
-		ifr.ifr_flags |= IFF_UP;
-	} else {
-		if (!(ifr.ifr_flags & IFF_UP))
-			return 0;
-		ifr.ifr_flags &= ~IFF_UP;
-	}
-
-	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
-		wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
-			   ifname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
-{
-	struct ifreq ifr;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
-		wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
-			   ifname, strerror(errno));
-		return -1;
-	}
-
-	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-		wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
-			   ifname, ifr.ifr_hwaddr.sa_family);
-		return -1;
-	}
-	os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-
-	return 0;
-}
-
-
-int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
-{
-	struct ifreq ifr;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
-
-	if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
-		wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
-			   ifname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifndef SIOCBRADDBR
-#define SIOCBRADDBR 0x89a0
-#endif
-#ifndef SIOCBRDELBR
-#define SIOCBRDELBR 0x89a1
-#endif
-#ifndef SIOCBRADDIF
-#define SIOCBRADDIF 0x89a2
-#endif
-#ifndef SIOCBRDELIF
-#define SIOCBRDELIF 0x89a3
-#endif
-
-
-int linux_br_add(int sock, const char *brname)
-{
-	if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
-		wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
-			   brname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int linux_br_del(int sock, const char *brname)
-{
-	if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
-		wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
-			   brname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int linux_br_add_if(int sock, const char *brname, const char *ifname)
-{
-	struct ifreq ifr;
-	int ifindex;
-
-	ifindex = if_nametoindex(ifname);
-	if (ifindex == 0)
-		return -1;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
-	ifr.ifr_ifindex = ifindex;
-	if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
-		wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
-			   "%s: %s", ifname, brname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int linux_br_del_if(int sock, const char *brname, const char *ifname)
-{
-	struct ifreq ifr;
-	int ifindex;
-
-	ifindex = if_nametoindex(ifname);
-	if (ifindex == 0)
-		return -1;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
-	ifr.ifr_ifindex = ifindex;
-	if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
-		wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
-			   "bridge %s: %s", ifname, brname, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int linux_br_get(char *brname, const char *ifname)
-{
-	char path[128], brlink[128], *pos;
-	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
-		    ifname);
-	os_memset(brlink, 0, sizeof(brlink));
-	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
-		return -1;
-	pos = os_strrchr(brlink, '/');
-	if (pos == NULL)
-		return -1;
-	pos++;
-	os_strlcpy(brname, pos, IFNAMSIZ);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/drivers/linux_ioctl.c (from rev 9639, vendor/wpa/dist/src/drivers/linux_ioctl.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/linux_ioctl.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/linux_ioctl.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,218 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include "utils/common.h"
+#include "linux_ioctl.h"
+
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
+{
+	struct ifreq ifr;
+	int ret;
+
+	if (sock < 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
+		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+			   ifname, strerror(errno));
+		return ret;
+	}
+
+	if (dev_up) {
+		if (ifr.ifr_flags & IFF_UP)
+			return 0;
+		ifr.ifr_flags |= IFF_UP;
+	} else {
+		if (!(ifr.ifr_flags & IFF_UP))
+			return 0;
+		ifr.ifr_flags &= ~IFF_UP;
+	}
+
+	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
+		wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+			   "%s",
+			   ifname, dev_up ? "UP" : "DOWN", strerror(errno));
+		return ret;
+	}
+
+	return 0;
+}
+
+
+int linux_iface_up(int sock, const char *ifname)
+{
+	struct ifreq ifr;
+	int ret;
+
+	if (sock < 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
+		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+			   ifname, strerror(errno));
+		return ret;
+	}
+
+	return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
+{
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
+		wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
+			   ifname, strerror(errno));
+		return -1;
+	}
+
+	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+		wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
+			   ifname, ifr.ifr_hwaddr.sa_family);
+		return -1;
+	}
+	os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	return 0;
+}
+
+
+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
+{
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+	if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
+		wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
+			   ifname, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifndef SIOCBRADDBR
+#define SIOCBRADDBR 0x89a0
+#endif
+#ifndef SIOCBRDELBR
+#define SIOCBRDELBR 0x89a1
+#endif
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2
+#endif
+#ifndef SIOCBRDELIF
+#define SIOCBRDELIF 0x89a3
+#endif
+
+
+int linux_br_add(int sock, const char *brname)
+{
+	if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
+		wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
+			   brname, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int linux_br_del(int sock, const char *brname)
+{
+	if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
+		wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
+			   brname, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int linux_br_add_if(int sock, const char *brname, const char *ifname)
+{
+	struct ifreq ifr;
+	int ifindex;
+
+	ifindex = if_nametoindex(ifname);
+	if (ifindex == 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+	ifr.ifr_ifindex = ifindex;
+	if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
+		wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
+			   "%s: %s", ifname, brname, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int linux_br_del_if(int sock, const char *brname, const char *ifname)
+{
+	struct ifreq ifr;
+	int ifindex;
+
+	ifindex = if_nametoindex(ifname);
+	if (ifindex == 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
+	ifr.ifr_ifindex = ifindex;
+	if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
+		wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
+			   "bridge %s: %s", ifname, brname, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int linux_br_get(char *brname, const char *ifname)
+{
+	char path[128], brlink[128], *pos;
+	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
+		    ifname);
+	os_memset(brlink, 0, sizeof(brlink));
+	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
+		return -1;
+	pos = os_strrchr(brlink, '/');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	os_strlcpy(brname, pos, IFNAMSIZ);
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/drivers/linux_ioctl.h
===================================================================
--- vendor/wpa/dist/src/drivers/linux_ioctl.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/linux_ioctl.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,27 +0,0 @@
-/*
- * Linux ioctl helper functions for driver wrappers
- * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef LINUX_IOCTL_H
-#define LINUX_IOCTL_H
-
-int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
-int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
-int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
-int linux_br_add(int sock, const char *brname);
-int linux_br_del(int sock, const char *brname);
-int linux_br_add_if(int sock, const char *brname, const char *ifname);
-int linux_br_del_if(int sock, const char *brname, const char *ifname);
-int linux_br_get(char *brname, const char *ifname);
-
-#endif /* LINUX_IOCTL_H */

Copied: vendor/wpa/2.0/src/drivers/linux_ioctl.h (from rev 9639, vendor/wpa/dist/src/drivers/linux_ioctl.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/linux_ioctl.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/linux_ioctl.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,22 @@
+/*
+ * Linux ioctl helper functions for driver wrappers
+ * Copyright (c) 2002-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_IOCTL_H
+#define LINUX_IOCTL_H
+
+int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
+int linux_br_add(int sock, const char *brname);
+int linux_br_del(int sock, const char *brname);
+int linux_br_add_if(int sock, const char *brname, const char *ifname);
+int linux_br_del_if(int sock, const char *brname, const char *ifname);
+int linux_br_get(char *brname, const char *ifname);
+
+#endif /* LINUX_IOCTL_H */

Copied: vendor/wpa/2.0/src/drivers/linux_wext.h (from rev 9639, vendor/wpa/dist/src/drivers/linux_wext.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/linux_wext.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/linux_wext.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,45 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <sys/types.h>
+#include <net/if.h>
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */

Deleted: vendor/wpa/2.0/src/drivers/ndis_events.c
===================================================================
--- vendor/wpa/dist/src/drivers/ndis_events.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/ndis_events.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,808 +0,0 @@
-/*
- * ndis_events - Receive NdisMIndicateStatus() events using WMI
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#define _WIN32_WINNT    0x0400
-
-#include "includes.h"
-
-#ifndef COBJMACROS
-#define COBJMACROS
-#endif /* COBJMACROS */
-#include <wbemidl.h>
-
-#include "common.h"
-
-
-static int wmi_refcnt = 0;
-static int wmi_first = 1;
-
-struct ndis_events_data {
-	IWbemObjectSink sink;
-	IWbemObjectSinkVtbl sink_vtbl;
-
-	IWbemServices *pSvc;
-	IWbemLocator *pLoc;
-
-	HANDLE read_pipe, write_pipe, event_avail;
-	UINT ref;
-	int terminating;
-	char *ifname; /* {GUID..} */
-	WCHAR *adapter_desc;
-};
-
-#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
-#define BstrFree(x) if (x) SysFreeString(x)
-
-/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
- * BSTRs */
-HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
-	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
-	long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
-{
-	BSTR bsQueryLanguage, bsQuery;
-	HRESULT hr;
-
-	bsQueryLanguage = BstrAlloc(strQueryLanguage);
-	bsQuery = BstrAlloc(strQuery);
-
-	hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
-				     pCtx, ppEnum);
-
-	BstrFree(bsQueryLanguage);
-	BstrFree(bsQuery);
-
-	return hr;
-}
-
-
-HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
-	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
-	long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
-{
-	BSTR bsQueryLanguage, bsQuery;
-	HRESULT hr;
-
-	bsQueryLanguage = BstrAlloc(strQueryLanguage);
-	bsQuery = BstrAlloc(strQuery);
-
-	hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
-						      bsQuery, lFlags, pCtx,
-						      pResponseHandler);
-
-	BstrFree(bsQueryLanguage);
-	BstrFree(bsQuery);
-
-	return hr;
-}
-
-
-HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
-	IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
-	LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
-	LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
-{
-	BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
-	HRESULT hr;
-
-	bsNetworkResource = BstrAlloc(strNetworkResource);
-	bsUser = BstrAlloc(strUser);
-	bsPassword = BstrAlloc(strPassword);
-	bsLocale = BstrAlloc(strLocale);
-	bsAuthority = BstrAlloc(strAuthority);
-
-	hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
-					bsPassword, bsLocale, lSecurityFlags,
-					bsAuthority, pCtx, ppNamespace);
-
-	BstrFree(bsNetworkResource);
-	BstrFree(bsUser);
-	BstrFree(bsPassword);
-	BstrFree(bsLocale);
-	BstrFree(bsAuthority);
-
-	return hr;
-}
-
-
-enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
-		   EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
-
-static int ndis_events_get_adapter(struct ndis_events_data *events,
-				   const char *ifname, const char *desc);
-
-
-static int ndis_events_constructor(struct ndis_events_data *events)
-{
-	events->ref = 1;
-
-	if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
-		wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
-			   (int) GetLastError());
-		return -1;
-	}
-	events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
-	if (events->event_avail == NULL) {
-		wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
-			   (int) GetLastError());
-		CloseHandle(events->read_pipe);
-		CloseHandle(events->write_pipe);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void ndis_events_destructor(struct ndis_events_data *events)
-{
-	CloseHandle(events->read_pipe);
-	CloseHandle(events->write_pipe);
-	CloseHandle(events->event_avail);
-	IWbemServices_Release(events->pSvc);
-	IWbemLocator_Release(events->pLoc);
-	if (--wmi_refcnt == 0)
-		CoUninitialize();
-}
-
-
-static HRESULT STDMETHODCALLTYPE
-ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
-{
-	*obj = NULL;
-
-	if (IsEqualIID(riid, &IID_IUnknown) ||
-	    IsEqualIID(riid, &IID_IWbemObjectSink)) {
-		*obj = this;
-		IWbemObjectSink_AddRef(this);
-		return NOERROR;
-	}
-
-	return E_NOINTERFACE;
-}
-
-
-static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
-{
-	struct ndis_events_data *events = (struct ndis_events_data *) this;
-	return ++events->ref;
-}
-
-
-static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
-{
-	struct ndis_events_data *events = (struct ndis_events_data *) this;
-
-	if (--events->ref != 0)
-		return events->ref;
-
-	ndis_events_destructor(events);
-	wpa_printf(MSG_DEBUG, "ndis_events: terminated");
-	os_free(events->adapter_desc);
-	os_free(events->ifname);
-	os_free(events);
-	return 0;
-}
-
-
-static int ndis_events_send_event(struct ndis_events_data *events,
-				  enum event_types type,
-				  char *data, size_t data_len)
-{
-	char buf[512], *pos, *end;
-	int _type;
-	DWORD written;
-
-	end = buf + sizeof(buf);
-	_type = (int) type;
-	os_memcpy(buf, &_type, sizeof(_type));
-	pos = buf + sizeof(_type);
-
-	if (data) {
-		if (2 + data_len > (size_t) (end - pos)) {
-			wpa_printf(MSG_DEBUG, "Not enough room for send_event "
-				   "data (%d)", data_len);
-			return -1;
-		}
-		*pos++ = data_len >> 8;
-		*pos++ = data_len & 0xff;
-		os_memcpy(pos, data, data_len);
-		pos += data_len;
-	}
-
-	if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
-		SetEvent(events->event_avail);
-		return 0;
-	}
-	wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
-	return -1;
-}
-
-
-static void ndis_events_media_connect(struct ndis_events_data *events)
-{
-	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
-	ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
-}
-
-
-static void ndis_events_media_disconnect(struct ndis_events_data *events)
-{
-	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
-	ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
-}
-
-
-static void ndis_events_media_specific(struct ndis_events_data *events,
-				       IWbemClassObject *pObj)
-{
-	VARIANT vt;
-	HRESULT hr;
-	LONG lower, upper, k;
-	UCHAR ch;
-	char *data, *pos;
-	size_t data_len;
-
-	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
-
-	/* This is the StatusBuffer from NdisMIndicateStatus() call */
-	hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
-				  0, &vt, NULL, NULL);
-	if (FAILED(hr)) {
-		wpa_printf(MSG_DEBUG, "Could not get "
-			   "NdisStatusMediaSpecificIndication from "
-			   "the object?!");
-		return;
-	}
-
-	SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
-	SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
-	data_len = upper - lower + 1;
-	data = os_malloc(data_len);
-	if (data == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
-			   "data");
-		VariantClear(&vt);
-		return;
-	}
-
-	pos = data;
-	for (k = lower; k <= upper; k++) {
-		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
-		*pos++ = ch;
-	}
-	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
-
-	VariantClear(&vt);
-
-	ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
-
-	os_free(data);
-}
-
-
-static void ndis_events_adapter_arrival(struct ndis_events_data *events)
-{
-	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
-	ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
-}
-
-
-static void ndis_events_adapter_removal(struct ndis_events_data *events)
-{
-	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
-	ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
-}
-
-
-static HRESULT STDMETHODCALLTYPE
-ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
-		     IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
-{
-	struct ndis_events_data *events = (struct ndis_events_data *) this;
-	long i;
-
-	if (events->terminating) {
-		wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
-			   "indication - terminating");
-		return WBEM_NO_ERROR;
-	}
-	/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
-	   lObjectCount); */
-
-	for (i = 0; i < lObjectCount; i++) {
-		IWbemClassObject *pObj = ppObjArray[i];
-		HRESULT hr;
-		VARIANT vtClass, vt;
-
-		hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
-					  NULL);
-		if (FAILED(hr)) {
-			wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
-				   "event.");
-			break;
-		}
-		/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
-
-		hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
-					  NULL);
-		if (FAILED(hr)) {
-			wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
-				   "from event.");
-			VariantClear(&vtClass);
-			break;
-		}
-
-		if (wcscmp(vtClass.bstrVal,
-			   L"MSNdis_NotifyAdapterArrival") == 0) {
-			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
-				   "update adapter description since it may "
-				   "have changed with new adapter instance");
-			ndis_events_get_adapter(events, events->ifname, NULL);
-		}
-
-		if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
-			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
-				   "indication for foreign adapter: "
-				   "InstanceName: '%S' __CLASS: '%S'",
-				   vt.bstrVal, vtClass.bstrVal);
-			VariantClear(&vtClass);
-			VariantClear(&vt);
-			continue;
-		}
-		VariantClear(&vt);
-
-		if (wcscmp(vtClass.bstrVal,
-			   L"MSNdis_StatusMediaSpecificIndication") == 0) {
-			ndis_events_media_specific(events, pObj);
-		} else if (wcscmp(vtClass.bstrVal,
-				  L"MSNdis_StatusMediaConnect") == 0) {
-			ndis_events_media_connect(events);
-		} else if (wcscmp(vtClass.bstrVal,
-				  L"MSNdis_StatusMediaDisconnect") == 0) {
-			ndis_events_media_disconnect(events);
-		} else if (wcscmp(vtClass.bstrVal,
-				  L"MSNdis_NotifyAdapterArrival") == 0) {
-			ndis_events_adapter_arrival(events);
-		} else if (wcscmp(vtClass.bstrVal,
-				  L"MSNdis_NotifyAdapterRemoval") == 0) {
-			ndis_events_adapter_removal(events);
-		} else {
-			wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
-				   "'%S'", vtClass.bstrVal);
-		}
-
-		VariantClear(&vtClass);
-	}
-
-	return WBEM_NO_ERROR;
-}
-
-
-static HRESULT STDMETHODCALLTYPE
-ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
-		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
-{
-	return WBEM_NO_ERROR;
-}
-
-
-static int notification_query(IWbemObjectSink *pDestSink,
-			      IWbemServices *pSvc, const char *class_name)
-{
-	HRESULT hr;
-	WCHAR query[256];
-
-	_snwprintf(query, 256,
-		  L"SELECT * FROM %S", class_name);
-	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
-	hr = call_IWbemServices_ExecNotificationQueryAsync(
-		pSvc, L"WQL", query, 0, 0, pDestSink);
-	if (FAILED(hr)) {
-		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
-			   "failed with hresult of 0x%x",
-			   class_name, (int) hr);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int register_async_notification(IWbemObjectSink *pDestSink,
-				       IWbemServices *pSvc)
-{
-	int i;
-	const char *class_list[] = {
-		"MSNdis_StatusMediaConnect",
-		"MSNdis_StatusMediaDisconnect",
-		"MSNdis_StatusMediaSpecificIndication",
-		"MSNdis_NotifyAdapterArrival",
-		"MSNdis_NotifyAdapterRemoval",
-		NULL
-	};
-
-	for (i = 0; class_list[i]; i++) {
-		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-
-void ndis_events_deinit(struct ndis_events_data *events)
-{
-	events->terminating = 1;
-	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
-	IWbemObjectSink_Release(&events->sink);
-	/*
-	 * Rest of deinitialization is done in ndis_events_destructor() once
-	 * all reference count drops to zero.
-	 */
-}
-
-
-static int ndis_events_use_desc(struct ndis_events_data *events,
-				const char *desc)
-{
-	char *tmp, *pos;
-	size_t len;
-
-	if (desc == NULL) {
-		if (events->adapter_desc == NULL)
-			return -1;
-		/* Continue using old description */
-		return 0;
-	}
-
-	tmp = os_strdup(desc);
-	if (tmp == NULL)
-		return -1;
-
-	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
-	if (pos)
-		*pos = '\0';
-
-	len = os_strlen(tmp);
-	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
-	if (events->adapter_desc == NULL) {
-		os_free(tmp);
-		return -1;
-	}
-	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
-	os_free(tmp);
-	return 0;
-}
-
-
-static int ndis_events_get_adapter(struct ndis_events_data *events,
-				   const char *ifname, const char *desc)
-{
-	HRESULT hr;
-	IWbemServices *pSvc;
-#define MAX_QUERY_LEN 256
-	WCHAR query[MAX_QUERY_LEN];
-	IEnumWbemClassObject *pEnumerator;
-	IWbemClassObject *pObj;
-	ULONG uReturned;
-	VARIANT vt;
-	int len, pos;
-
-	/*
-	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
-	 * to have better probability of matching with InstanceName from
-	 * MSNdis events. If this fails, use the provided description.
-	 */
-
-	os_free(events->adapter_desc);
-	events->adapter_desc = NULL;
-
-	hr = call_IWbemLocator_ConnectServer(
-		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
-	if (FAILED(hr)) {
-		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
-			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
-		return ndis_events_use_desc(events, desc);
-	}
-	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
-
-	_snwprintf(query, MAX_QUERY_LEN,
-		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
-		  L"WHERE SettingID='%S'", ifname);
-	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
-
-	hr = call_IWbemServices_ExecQuery(
-		pSvc, L"WQL", query,
-		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
-		NULL, &pEnumerator);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
-			   "GUID from Win32_NetworkAdapterConfiguration: "
-			   "0x%x", (int) hr);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-
-	uReturned = 0;
-	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
-				       &pObj, &uReturned);
-	if (!SUCCEEDED(hr) || uReturned == 0) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
-			   "GUID from Win32_NetworkAdapterConfiguration: "
-			   "0x%x", (int) hr);
-		IEnumWbemClassObject_Release(pEnumerator);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-	IEnumWbemClassObject_Release(pEnumerator);
-
-	VariantInit(&vt);
-	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
-			   "Win32_NetworkAdapterConfiguration: 0x%x",
-			   (int) hr);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-
-	_snwprintf(query, MAX_QUERY_LEN,
-		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
-		  L"Index=%d",
-		  vt.uintVal);
-	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
-	VariantClear(&vt);
-	IWbemClassObject_Release(pObj);
-
-	hr = call_IWbemServices_ExecQuery(
-		pSvc, L"WQL", query,
-		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
-		NULL, &pEnumerator);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
-			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-
-	uReturned = 0;
-	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
-				       &pObj, &uReturned);
-	if (!SUCCEEDED(hr) || uReturned == 0) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
-			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
-		IEnumWbemClassObject_Release(pEnumerator);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-	IEnumWbemClassObject_Release(pEnumerator);
-
-	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
-			   "Win32_NetworkAdapter: 0x%x", (int) hr);
-		IWbemClassObject_Release(pObj);
-		IWbemServices_Release(pSvc);
-		return ndis_events_use_desc(events, desc);
-	}
-
-	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
-		   vt.bstrVal);
-	events->adapter_desc = _wcsdup(vt.bstrVal);
-	VariantClear(&vt);
-
-	/*
-	 * Try to get even better candidate for matching with InstanceName
-	 * from Win32_PnPEntity. This is needed at least for some USB cards
-	 * that can change the InstanceName whenever being unplugged and
-	 * plugged again.
-	 */
-
-	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
-			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
-		IWbemClassObject_Release(pObj);
-		IWbemServices_Release(pSvc);
-		if (events->adapter_desc == NULL)
-			return ndis_events_use_desc(events, desc);
-		return 0; /* use Win32_NetworkAdapter::Name */
-	}
-
-	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
-		   "'%S'", vt.bstrVal);
-
-	len = _snwprintf(query, MAX_QUERY_LEN,
-			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
-	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
-		VariantClear(&vt);
-		IWbemClassObject_Release(pObj);
-		IWbemServices_Release(pSvc);
-		if (events->adapter_desc == NULL)
-			return ndis_events_use_desc(events, desc);
-		return 0; /* use Win32_NetworkAdapter::Name */
-	}
-
-	/* Escape \ as \\ */
-	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
-		if (vt.bstrVal[pos] == '\\') {
-			if (len >= MAX_QUERY_LEN - 3)
-				break;
-			query[len++] = '\\';
-		}
-		query[len++] = vt.bstrVal[pos];
-	}
-	query[len++] = L'\'';
-	query[len] = L'\0';
-	VariantClear(&vt);
-	IWbemClassObject_Release(pObj);
-	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
-
-	hr = call_IWbemServices_ExecQuery(
-		pSvc, L"WQL", query,
-		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
-		NULL, &pEnumerator);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
-			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
-		IWbemServices_Release(pSvc);
-		if (events->adapter_desc == NULL)
-			return ndis_events_use_desc(events, desc);
-		return 0; /* use Win32_NetworkAdapter::Name */
-	}
-
-	uReturned = 0;
-	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
-				       &pObj, &uReturned);
-	if (!SUCCEEDED(hr) || uReturned == 0) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
-			   "from Win32_PnPEntity: 0x%x", (int) hr);
-		IEnumWbemClassObject_Release(pEnumerator);
-		IWbemServices_Release(pSvc);
-		if (events->adapter_desc == NULL)
-			return ndis_events_use_desc(events, desc);
-		return 0; /* use Win32_NetworkAdapter::Name */
-	}
-	IEnumWbemClassObject_Release(pEnumerator);
-
-	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
-	if (!SUCCEEDED(hr)) {
-		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
-			   "Win32_PnPEntity: 0x%x", (int) hr);
-		IWbemClassObject_Release(pObj);
-		IWbemServices_Release(pSvc);
-		if (events->adapter_desc == NULL)
-			return ndis_events_use_desc(events, desc);
-		return 0; /* use Win32_NetworkAdapter::Name */
-	}
-
-	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
-		   vt.bstrVal);
-	os_free(events->adapter_desc);
-	events->adapter_desc = _wcsdup(vt.bstrVal);
-	VariantClear(&vt);
-
-	IWbemClassObject_Release(pObj);
-
-	IWbemServices_Release(pSvc);
-
-	if (events->adapter_desc == NULL)
-		return ndis_events_use_desc(events, desc);
-
-	return 0;
-}
-
-
-struct ndis_events_data *
-ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
-		 const char *ifname, const char *desc)
-{
-	HRESULT hr;
-	IWbemObjectSink *pSink;
-	struct ndis_events_data *events;
-
-	events = os_zalloc(sizeof(*events));
-	if (events == NULL) {
-		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
-		return NULL;
-	}
-	events->ifname = os_strdup(ifname);
-	if (events->ifname == NULL) {
-		os_free(events);
-		return NULL;
-	}
-
-	if (wmi_refcnt++ == 0) {
-		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
-		if (FAILED(hr)) {
-			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
-				   "returned 0x%x", (int) hr);
-			os_free(events);
-			return NULL;
-		}
-	}
-
-	if (wmi_first) {
-		/* CoInitializeSecurity() must be called once and only once
-		 * per process, so let's use wmi_first flag to protect against
-		 * multiple calls. */
-		wmi_first = 0;
-
-		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
-					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
-					  RPC_C_IMP_LEVEL_IMPERSONATE,
-					  NULL, EOAC_SECURE_REFS, NULL);
-		if (FAILED(hr)) {
-			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
-				   "- returned 0x%x", (int) hr);
-			os_free(events);
-			return NULL;
-		}
-	}
-
-	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
-			      &IID_IWbemLocator,
-			      (LPVOID *) (void *) &events->pLoc);
-	if (FAILED(hr)) {
-		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
-			   "0x%x", (int) hr);
-		CoUninitialize();
-		os_free(events);
-		return NULL;
-	}
-
-	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
-		CoUninitialize();
-		os_free(events);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
-		   events->adapter_desc);
-
-	hr = call_IWbemLocator_ConnectServer(
-		events->pLoc, L"ROOT\\WMI", NULL, NULL,
-		0, 0, 0, 0, &events->pSvc);
-	if (FAILED(hr)) {
-		wpa_printf(MSG_ERROR, "Could not connect to server - error "
-			   "0x%x", (int) hr);
-		CoUninitialize();
-		os_free(events->adapter_desc);
-		os_free(events);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
-
-	ndis_events_constructor(events);
-	pSink = &events->sink;
-	pSink->lpVtbl = &events->sink_vtbl;
-	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
-	events->sink_vtbl.AddRef = ndis_events_add_ref;
-	events->sink_vtbl.Release = ndis_events_release;
-	events->sink_vtbl.Indicate = ndis_events_indicate;
-	events->sink_vtbl.SetStatus = ndis_events_set_status;
-
-	if (register_async_notification(pSink, events->pSvc) < 0) {
-		wpa_printf(MSG_DEBUG, "Failed to register async "
-			   "notifications");
-		ndis_events_destructor(events);
-		os_free(events->adapter_desc);
-		os_free(events);
-		return NULL;
-	}
-
-	*read_pipe = events->read_pipe;
-	*event_avail = events->event_avail;
-
-	return events;
-}

Copied: vendor/wpa/2.0/src/drivers/ndis_events.c (from rev 9639, vendor/wpa/dist/src/drivers/ndis_events.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/ndis_events.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/ndis_events.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,802 @@
+/*
+ * ndis_events - Receive NdisMIndicateStatus() events using WMI
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#define _WIN32_WINNT    0x0400
+
+#include "includes.h"
+
+#ifndef COBJMACROS
+#define COBJMACROS
+#endif /* COBJMACROS */
+#include <wbemidl.h>
+
+#include "common.h"
+
+
+static int wmi_refcnt = 0;
+static int wmi_first = 1;
+
+struct ndis_events_data {
+	IWbemObjectSink sink;
+	IWbemObjectSinkVtbl sink_vtbl;
+
+	IWbemServices *pSvc;
+	IWbemLocator *pLoc;
+
+	HANDLE read_pipe, write_pipe, event_avail;
+	UINT ref;
+	int terminating;
+	char *ifname; /* {GUID..} */
+	WCHAR *adapter_desc;
+};
+
+#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
+#define BstrFree(x) if (x) SysFreeString(x)
+
+/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
+ * BSTRs */
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
+	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+	long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
+{
+	BSTR bsQueryLanguage, bsQuery;
+	HRESULT hr;
+
+	bsQueryLanguage = BstrAlloc(strQueryLanguage);
+	bsQuery = BstrAlloc(strQuery);
+
+	hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
+				     pCtx, ppEnum);
+
+	BstrFree(bsQueryLanguage);
+	BstrFree(bsQuery);
+
+	return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
+	IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+	long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
+{
+	BSTR bsQueryLanguage, bsQuery;
+	HRESULT hr;
+
+	bsQueryLanguage = BstrAlloc(strQueryLanguage);
+	bsQuery = BstrAlloc(strQuery);
+
+	hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
+						      bsQuery, lFlags, pCtx,
+						      pResponseHandler);
+
+	BstrFree(bsQueryLanguage);
+	BstrFree(bsQuery);
+
+	return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
+	IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
+	LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
+	LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
+{
+	BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
+	HRESULT hr;
+
+	bsNetworkResource = BstrAlloc(strNetworkResource);
+	bsUser = BstrAlloc(strUser);
+	bsPassword = BstrAlloc(strPassword);
+	bsLocale = BstrAlloc(strLocale);
+	bsAuthority = BstrAlloc(strAuthority);
+
+	hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
+					bsPassword, bsLocale, lSecurityFlags,
+					bsAuthority, pCtx, ppNamespace);
+
+	BstrFree(bsNetworkResource);
+	BstrFree(bsUser);
+	BstrFree(bsPassword);
+	BstrFree(bsLocale);
+	BstrFree(bsAuthority);
+
+	return hr;
+}
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
+		   EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+				   const char *ifname, const char *desc);
+
+
+static int ndis_events_constructor(struct ndis_events_data *events)
+{
+	events->ref = 1;
+
+	if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
+		wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
+			   (int) GetLastError());
+		return -1;
+	}
+	events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (events->event_avail == NULL) {
+		wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
+			   (int) GetLastError());
+		CloseHandle(events->read_pipe);
+		CloseHandle(events->write_pipe);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void ndis_events_destructor(struct ndis_events_data *events)
+{
+	CloseHandle(events->read_pipe);
+	CloseHandle(events->write_pipe);
+	CloseHandle(events->event_avail);
+	IWbemServices_Release(events->pSvc);
+	IWbemLocator_Release(events->pLoc);
+	if (--wmi_refcnt == 0)
+		CoUninitialize();
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
+{
+	*obj = NULL;
+
+	if (IsEqualIID(riid, &IID_IUnknown) ||
+	    IsEqualIID(riid, &IID_IWbemObjectSink)) {
+		*obj = this;
+		IWbemObjectSink_AddRef(this);
+		return NOERROR;
+	}
+
+	return E_NOINTERFACE;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
+{
+	struct ndis_events_data *events = (struct ndis_events_data *) this;
+	return ++events->ref;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
+{
+	struct ndis_events_data *events = (struct ndis_events_data *) this;
+
+	if (--events->ref != 0)
+		return events->ref;
+
+	ndis_events_destructor(events);
+	wpa_printf(MSG_DEBUG, "ndis_events: terminated");
+	os_free(events->adapter_desc);
+	os_free(events->ifname);
+	os_free(events);
+	return 0;
+}
+
+
+static int ndis_events_send_event(struct ndis_events_data *events,
+				  enum event_types type,
+				  char *data, size_t data_len)
+{
+	char buf[512], *pos, *end;
+	int _type;
+	DWORD written;
+
+	end = buf + sizeof(buf);
+	_type = (int) type;
+	os_memcpy(buf, &_type, sizeof(_type));
+	pos = buf + sizeof(_type);
+
+	if (data) {
+		if (2 + data_len > (size_t) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "Not enough room for send_event "
+				   "data (%d)", data_len);
+			return -1;
+		}
+		*pos++ = data_len >> 8;
+		*pos++ = data_len & 0xff;
+		os_memcpy(pos, data, data_len);
+		pos += data_len;
+	}
+
+	if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
+		SetEvent(events->event_avail);
+		return 0;
+	}
+	wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
+	return -1;
+}
+
+
+static void ndis_events_media_connect(struct ndis_events_data *events)
+{
+	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
+	ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_disconnect(struct ndis_events_data *events)
+{
+	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
+	ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_specific(struct ndis_events_data *events,
+				       IWbemClassObject *pObj)
+{
+	VARIANT vt;
+	HRESULT hr;
+	LONG lower, upper, k;
+	UCHAR ch;
+	char *data, *pos;
+	size_t data_len;
+
+	wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
+
+	/* This is the StatusBuffer from NdisMIndicateStatus() call */
+	hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
+				  0, &vt, NULL, NULL);
+	if (FAILED(hr)) {
+		wpa_printf(MSG_DEBUG, "Could not get "
+			   "NdisStatusMediaSpecificIndication from "
+			   "the object?!");
+		return;
+	}
+
+	SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
+	SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
+	data_len = upper - lower + 1;
+	data = os_malloc(data_len);
+	if (data == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
+			   "data");
+		VariantClear(&vt);
+		return;
+	}
+
+	pos = data;
+	for (k = lower; k <= upper; k++) {
+		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
+		*pos++ = ch;
+	}
+	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
+
+	VariantClear(&vt);
+
+	ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
+
+	os_free(data);
+}
+
+
+static void ndis_events_adapter_arrival(struct ndis_events_data *events)
+{
+	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
+	ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
+}
+
+
+static void ndis_events_adapter_removal(struct ndis_events_data *events)
+{
+	wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
+	ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
+		     IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
+{
+	struct ndis_events_data *events = (struct ndis_events_data *) this;
+	long i;
+
+	if (events->terminating) {
+		wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+			   "indication - terminating");
+		return WBEM_NO_ERROR;
+	}
+	/* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
+	   lObjectCount); */
+
+	for (i = 0; i < lObjectCount; i++) {
+		IWbemClassObject *pObj = ppObjArray[i];
+		HRESULT hr;
+		VARIANT vtClass, vt;
+
+		hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
+					  NULL);
+		if (FAILED(hr)) {
+			wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
+				   "event.");
+			break;
+		}
+		/* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
+
+		hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
+					  NULL);
+		if (FAILED(hr)) {
+			wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
+				   "from event.");
+			VariantClear(&vtClass);
+			break;
+		}
+
+		if (wcscmp(vtClass.bstrVal,
+			   L"MSNdis_NotifyAdapterArrival") == 0) {
+			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
+				   "update adapter description since it may "
+				   "have changed with new adapter instance");
+			ndis_events_get_adapter(events, events->ifname, NULL);
+		}
+
+		if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
+			wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+				   "indication for foreign adapter: "
+				   "InstanceName: '%S' __CLASS: '%S'",
+				   vt.bstrVal, vtClass.bstrVal);
+			VariantClear(&vtClass);
+			VariantClear(&vt);
+			continue;
+		}
+		VariantClear(&vt);
+
+		if (wcscmp(vtClass.bstrVal,
+			   L"MSNdis_StatusMediaSpecificIndication") == 0) {
+			ndis_events_media_specific(events, pObj);
+		} else if (wcscmp(vtClass.bstrVal,
+				  L"MSNdis_StatusMediaConnect") == 0) {
+			ndis_events_media_connect(events);
+		} else if (wcscmp(vtClass.bstrVal,
+				  L"MSNdis_StatusMediaDisconnect") == 0) {
+			ndis_events_media_disconnect(events);
+		} else if (wcscmp(vtClass.bstrVal,
+				  L"MSNdis_NotifyAdapterArrival") == 0) {
+			ndis_events_adapter_arrival(events);
+		} else if (wcscmp(vtClass.bstrVal,
+				  L"MSNdis_NotifyAdapterRemoval") == 0) {
+			ndis_events_adapter_removal(events);
+		} else {
+			wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
+				   "'%S'", vtClass.bstrVal);
+		}
+
+		VariantClear(&vtClass);
+	}
+
+	return WBEM_NO_ERROR;
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
+		       BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
+{
+	return WBEM_NO_ERROR;
+}
+
+
+static int notification_query(IWbemObjectSink *pDestSink,
+			      IWbemServices *pSvc, const char *class_name)
+{
+	HRESULT hr;
+	WCHAR query[256];
+
+	_snwprintf(query, 256,
+		  L"SELECT * FROM %S", class_name);
+	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+	hr = call_IWbemServices_ExecNotificationQueryAsync(
+		pSvc, L"WQL", query, 0, 0, pDestSink);
+	if (FAILED(hr)) {
+		wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
+			   "failed with hresult of 0x%x",
+			   class_name, (int) hr);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int register_async_notification(IWbemObjectSink *pDestSink,
+				       IWbemServices *pSvc)
+{
+	int i;
+	const char *class_list[] = {
+		"MSNdis_StatusMediaConnect",
+		"MSNdis_StatusMediaDisconnect",
+		"MSNdis_StatusMediaSpecificIndication",
+		"MSNdis_NotifyAdapterArrival",
+		"MSNdis_NotifyAdapterRemoval",
+		NULL
+	};
+
+	for (i = 0; class_list[i]; i++) {
+		if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void ndis_events_deinit(struct ndis_events_data *events)
+{
+	events->terminating = 1;
+	IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
+	IWbemObjectSink_Release(&events->sink);
+	/*
+	 * Rest of deinitialization is done in ndis_events_destructor() once
+	 * all reference count drops to zero.
+	 */
+}
+
+
+static int ndis_events_use_desc(struct ndis_events_data *events,
+				const char *desc)
+{
+	char *tmp, *pos;
+	size_t len;
+
+	if (desc == NULL) {
+		if (events->adapter_desc == NULL)
+			return -1;
+		/* Continue using old description */
+		return 0;
+	}
+
+	tmp = os_strdup(desc);
+	if (tmp == NULL)
+		return -1;
+
+	pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
+	if (pos)
+		*pos = '\0';
+
+	len = os_strlen(tmp);
+	events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
+	if (events->adapter_desc == NULL) {
+		os_free(tmp);
+		return -1;
+	}
+	_snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
+	os_free(tmp);
+	return 0;
+}
+
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+				   const char *ifname, const char *desc)
+{
+	HRESULT hr;
+	IWbemServices *pSvc;
+#define MAX_QUERY_LEN 256
+	WCHAR query[MAX_QUERY_LEN];
+	IEnumWbemClassObject *pEnumerator;
+	IWbemClassObject *pObj;
+	ULONG uReturned;
+	VARIANT vt;
+	int len, pos;
+
+	/*
+	 * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
+	 * to have better probability of matching with InstanceName from
+	 * MSNdis events. If this fails, use the provided description.
+	 */
+
+	os_free(events->adapter_desc);
+	events->adapter_desc = NULL;
+
+	hr = call_IWbemLocator_ConnectServer(
+		events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
+	if (FAILED(hr)) {
+		wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
+			   "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
+		return ndis_events_use_desc(events, desc);
+	}
+	wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
+
+	_snwprintf(query, MAX_QUERY_LEN,
+		  L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
+		  L"WHERE SettingID='%S'", ifname);
+	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+	hr = call_IWbemServices_ExecQuery(
+		pSvc, L"WQL", query,
+		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+		NULL, &pEnumerator);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+			   "GUID from Win32_NetworkAdapterConfiguration: "
+			   "0x%x", (int) hr);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+
+	uReturned = 0;
+	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+				       &pObj, &uReturned);
+	if (!SUCCEEDED(hr) || uReturned == 0) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+			   "GUID from Win32_NetworkAdapterConfiguration: "
+			   "0x%x", (int) hr);
+		IEnumWbemClassObject_Release(pEnumerator);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+	IEnumWbemClassObject_Release(pEnumerator);
+
+	VariantInit(&vt);
+	hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
+			   "Win32_NetworkAdapterConfiguration: 0x%x",
+			   (int) hr);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+
+	_snwprintf(query, MAX_QUERY_LEN,
+		  L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
+		  L"Index=%d",
+		  vt.uintVal);
+	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+	VariantClear(&vt);
+	IWbemClassObject_Release(pObj);
+
+	hr = call_IWbemServices_ExecQuery(
+		pSvc, L"WQL", query,
+		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+		NULL, &pEnumerator);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+
+	uReturned = 0;
+	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+				       &pObj, &uReturned);
+	if (!SUCCEEDED(hr) || uReturned == 0) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
+		IEnumWbemClassObject_Release(pEnumerator);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+	IEnumWbemClassObject_Release(pEnumerator);
+
+	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+			   "Win32_NetworkAdapter: 0x%x", (int) hr);
+		IWbemClassObject_Release(pObj);
+		IWbemServices_Release(pSvc);
+		return ndis_events_use_desc(events, desc);
+	}
+
+	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
+		   vt.bstrVal);
+	events->adapter_desc = _wcsdup(vt.bstrVal);
+	VariantClear(&vt);
+
+	/*
+	 * Try to get even better candidate for matching with InstanceName
+	 * from Win32_PnPEntity. This is needed at least for some USB cards
+	 * that can change the InstanceName whenever being unplugged and
+	 * plugged again.
+	 */
+
+	hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
+			   "from Win32_NetworkAdapter: 0x%x", (int) hr);
+		IWbemClassObject_Release(pObj);
+		IWbemServices_Release(pSvc);
+		if (events->adapter_desc == NULL)
+			return ndis_events_use_desc(events, desc);
+		return 0; /* use Win32_NetworkAdapter::Name */
+	}
+
+	wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
+		   "'%S'", vt.bstrVal);
+
+	len = _snwprintf(query, MAX_QUERY_LEN,
+			L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
+	if (len < 0 || len >= MAX_QUERY_LEN - 1) {
+		VariantClear(&vt);
+		IWbemClassObject_Release(pObj);
+		IWbemServices_Release(pSvc);
+		if (events->adapter_desc == NULL)
+			return ndis_events_use_desc(events, desc);
+		return 0; /* use Win32_NetworkAdapter::Name */
+	}
+
+	/* Escape \ as \\ */
+	for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
+		if (vt.bstrVal[pos] == '\\') {
+			if (len >= MAX_QUERY_LEN - 3)
+				break;
+			query[len++] = '\\';
+		}
+		query[len++] = vt.bstrVal[pos];
+	}
+	query[len++] = L'\'';
+	query[len] = L'\0';
+	VariantClear(&vt);
+	IWbemClassObject_Release(pObj);
+	wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+	hr = call_IWbemServices_ExecQuery(
+		pSvc, L"WQL", query,
+		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+		NULL, &pEnumerator);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+			   "Name from Win32_PnPEntity: 0x%x", (int) hr);
+		IWbemServices_Release(pSvc);
+		if (events->adapter_desc == NULL)
+			return ndis_events_use_desc(events, desc);
+		return 0; /* use Win32_NetworkAdapter::Name */
+	}
+
+	uReturned = 0;
+	hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+				       &pObj, &uReturned);
+	if (!SUCCEEDED(hr) || uReturned == 0) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+			   "from Win32_PnPEntity: 0x%x", (int) hr);
+		IEnumWbemClassObject_Release(pEnumerator);
+		IWbemServices_Release(pSvc);
+		if (events->adapter_desc == NULL)
+			return ndis_events_use_desc(events, desc);
+		return 0; /* use Win32_NetworkAdapter::Name */
+	}
+	IEnumWbemClassObject_Release(pEnumerator);
+
+	hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+	if (!SUCCEEDED(hr)) {
+		wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+			   "Win32_PnPEntity: 0x%x", (int) hr);
+		IWbemClassObject_Release(pObj);
+		IWbemServices_Release(pSvc);
+		if (events->adapter_desc == NULL)
+			return ndis_events_use_desc(events, desc);
+		return 0; /* use Win32_NetworkAdapter::Name */
+	}
+
+	wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
+		   vt.bstrVal);
+	os_free(events->adapter_desc);
+	events->adapter_desc = _wcsdup(vt.bstrVal);
+	VariantClear(&vt);
+
+	IWbemClassObject_Release(pObj);
+
+	IWbemServices_Release(pSvc);
+
+	if (events->adapter_desc == NULL)
+		return ndis_events_use_desc(events, desc);
+
+	return 0;
+}
+
+
+struct ndis_events_data *
+ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
+		 const char *ifname, const char *desc)
+{
+	HRESULT hr;
+	IWbemObjectSink *pSink;
+	struct ndis_events_data *events;
+
+	events = os_zalloc(sizeof(*events));
+	if (events == NULL) {
+		wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
+		return NULL;
+	}
+	events->ifname = os_strdup(ifname);
+	if (events->ifname == NULL) {
+		os_free(events);
+		return NULL;
+	}
+
+	if (wmi_refcnt++ == 0) {
+		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+		if (FAILED(hr)) {
+			wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
+				   "returned 0x%x", (int) hr);
+			os_free(events);
+			return NULL;
+		}
+	}
+
+	if (wmi_first) {
+		/* CoInitializeSecurity() must be called once and only once
+		 * per process, so let's use wmi_first flag to protect against
+		 * multiple calls. */
+		wmi_first = 0;
+
+		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
+					  RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+					  RPC_C_IMP_LEVEL_IMPERSONATE,
+					  NULL, EOAC_SECURE_REFS, NULL);
+		if (FAILED(hr)) {
+			wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
+				   "- returned 0x%x", (int) hr);
+			os_free(events);
+			return NULL;
+		}
+	}
+
+	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+			      &IID_IWbemLocator,
+			      (LPVOID *) (void *) &events->pLoc);
+	if (FAILED(hr)) {
+		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
+			   "0x%x", (int) hr);
+		CoUninitialize();
+		os_free(events);
+		return NULL;
+	}
+
+	if (ndis_events_get_adapter(events, ifname, desc) < 0) {
+		CoUninitialize();
+		os_free(events);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
+		   events->adapter_desc);
+
+	hr = call_IWbemLocator_ConnectServer(
+		events->pLoc, L"ROOT\\WMI", NULL, NULL,
+		0, 0, 0, 0, &events->pSvc);
+	if (FAILED(hr)) {
+		wpa_printf(MSG_ERROR, "Could not connect to server - error "
+			   "0x%x", (int) hr);
+		CoUninitialize();
+		os_free(events->adapter_desc);
+		os_free(events);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
+
+	ndis_events_constructor(events);
+	pSink = &events->sink;
+	pSink->lpVtbl = &events->sink_vtbl;
+	events->sink_vtbl.QueryInterface = ndis_events_query_interface;
+	events->sink_vtbl.AddRef = ndis_events_add_ref;
+	events->sink_vtbl.Release = ndis_events_release;
+	events->sink_vtbl.Indicate = ndis_events_indicate;
+	events->sink_vtbl.SetStatus = ndis_events_set_status;
+
+	if (register_async_notification(pSink, events->pSvc) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to register async "
+			   "notifications");
+		ndis_events_destructor(events);
+		os_free(events->adapter_desc);
+		os_free(events);
+		return NULL;
+	}
+
+	*read_pipe = events->read_pipe;
+	*event_avail = events->event_avail;
+
+	return events;
+}

Deleted: vendor/wpa/2.0/src/drivers/netlink.c
===================================================================
--- vendor/wpa/dist/src/drivers/netlink.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/netlink.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,204 +0,0 @@
-/*
- * Netlink helper functions for driver wrappers
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-
-
-struct netlink_data {
-	struct netlink_config *cfg;
-	int sock;
-};
-
-
-static void netlink_receive_link(struct netlink_data *netlink,
-				 void (*cb)(void *ctx, struct ifinfomsg *ifi,
-					    u8 *buf, size_t len),
-				 struct nlmsghdr *h)
-{
-	if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
-		return;
-	cb(netlink->cfg->ctx, NLMSG_DATA(h),
-	   NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
-	   NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
-}
-
-
-static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct netlink_data *netlink = eloop_ctx;
-	char buf[8192];
-	int left;
-	struct sockaddr_nl from;
-	socklen_t fromlen;
-	struct nlmsghdr *h;
-	int max_events = 10;
-
-try_again:
-	fromlen = sizeof(from);
-	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
-			(struct sockaddr *) &from, &fromlen);
-	if (left < 0) {
-		if (errno != EINTR && errno != EAGAIN)
-			wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
-				   strerror(errno));
-		return;
-	}
-
-	h = (struct nlmsghdr *) buf;
-	while (NLMSG_OK(h, left)) {
-		switch (h->nlmsg_type) {
-		case RTM_NEWLINK:
-			netlink_receive_link(netlink, netlink->cfg->newlink_cb,
-					     h);
-			break;
-		case RTM_DELLINK:
-			netlink_receive_link(netlink, netlink->cfg->dellink_cb,
-					     h);
-			break;
-		}
-
-		h = NLMSG_NEXT(h, left);
-	}
-
-	if (left > 0) {
-		wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
-			   "netlink message", left);
-	}
-
-	if (--max_events > 0) {
-		/*
-		 * Try to receive all events in one eloop call in order to
-		 * limit race condition on cases where AssocInfo event, Assoc
-		 * event, and EAPOL frames are received more or less at the
-		 * same time. We want to process the event messages first
-		 * before starting EAPOL processing.
-		 */
-		goto try_again;
-	}
-}
-
-
-struct netlink_data * netlink_init(struct netlink_config *cfg)
-{
-	struct netlink_data *netlink;
-	struct sockaddr_nl local;
-
-	netlink = os_zalloc(sizeof(*netlink));
-	if (netlink == NULL)
-		return NULL;
-
-	netlink->cfg = cfg;
-
-	netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-	if (netlink->sock < 0) {
-		wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
-			   "socket: %s", strerror(errno));
-		netlink_deinit(netlink);
-		return NULL;
-	}
-
-	os_memset(&local, 0, sizeof(local));
-	local.nl_family = AF_NETLINK;
-	local.nl_groups = RTMGRP_LINK;
-	if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
-	{
-		wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
-			   "socket: %s", strerror(errno));
-		netlink_deinit(netlink);
-		return NULL;
-	}
-
-	eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
-				 NULL);
-
-	return netlink;
-}
-
-
-void netlink_deinit(struct netlink_data *netlink)
-{
-	if (netlink == NULL)
-		return;
-	if (netlink->sock >= 0) {
-		eloop_unregister_read_sock(netlink->sock);
-		close(netlink->sock);
-	}
-	os_free(netlink->cfg);
-	os_free(netlink);
-}
-
-int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
-			   int linkmode, int operstate)
-{
-	struct {
-		struct nlmsghdr hdr;
-		struct ifinfomsg ifinfo;
-		char opts[16];
-	} req;
-	struct rtattr *rta;
-	static int nl_seq;
-	ssize_t ret;
-
-	os_memset(&req, 0, sizeof(req));
-
-	req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-	req.hdr.nlmsg_type = RTM_SETLINK;
-	req.hdr.nlmsg_flags = NLM_F_REQUEST;
-	req.hdr.nlmsg_seq = ++nl_seq;
-	req.hdr.nlmsg_pid = 0;
-
-	req.ifinfo.ifi_family = AF_UNSPEC;
-	req.ifinfo.ifi_type = 0;
-	req.ifinfo.ifi_index = ifindex;
-	req.ifinfo.ifi_flags = 0;
-	req.ifinfo.ifi_change = 0;
-
-	if (linkmode != -1) {
-		rta = aliasing_hide_typecast(
-			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
-			struct rtattr);
-		rta->rta_type = IFLA_LINKMODE;
-		rta->rta_len = RTA_LENGTH(sizeof(char));
-		*((char *) RTA_DATA(rta)) = linkmode;
-		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
-			RTA_LENGTH(sizeof(char));
-	}
-	if (operstate != -1) {
-		rta = aliasing_hide_typecast(
-			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
-			struct rtattr);
-		rta->rta_type = IFLA_OPERSTATE;
-		rta->rta_len = RTA_LENGTH(sizeof(char));
-		*((char *) RTA_DATA(rta)) = operstate;
-		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
-			RTA_LENGTH(sizeof(char));
-	}
-
-	wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
-		   linkmode, operstate);
-
-	ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
-			   "failed: %s (assume operstate is not supported)",
-			   strerror(errno));
-	}
-
-	return ret < 0 ? -1 : 0;
-}

Copied: vendor/wpa/2.0/src/drivers/netlink.c (from rev 9639, vendor/wpa/dist/src/drivers/netlink.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/netlink.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/netlink.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,198 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "netlink.h"
+
+
+struct netlink_data {
+	struct netlink_config *cfg;
+	int sock;
+};
+
+
+static void netlink_receive_link(struct netlink_data *netlink,
+				 void (*cb)(void *ctx, struct ifinfomsg *ifi,
+					    u8 *buf, size_t len),
+				 struct nlmsghdr *h)
+{
+	if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
+		return;
+	cb(netlink->cfg->ctx, NLMSG_DATA(h),
+	   (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+	   NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
+}
+
+
+static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct netlink_data *netlink = eloop_ctx;
+	char buf[8192];
+	int left;
+	struct sockaddr_nl from;
+	socklen_t fromlen;
+	struct nlmsghdr *h;
+	int max_events = 10;
+
+try_again:
+	fromlen = sizeof(from);
+	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+			(struct sockaddr *) &from, &fromlen);
+	if (left < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",
+				   strerror(errno));
+		return;
+	}
+
+	h = (struct nlmsghdr *) buf;
+	while (NLMSG_OK(h, left)) {
+		switch (h->nlmsg_type) {
+		case RTM_NEWLINK:
+			netlink_receive_link(netlink, netlink->cfg->newlink_cb,
+					     h);
+			break;
+		case RTM_DELLINK:
+			netlink_receive_link(netlink, netlink->cfg->dellink_cb,
+					     h);
+			break;
+		}
+
+		h = NLMSG_NEXT(h, left);
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "
+			   "netlink message", left);
+	}
+
+	if (--max_events > 0) {
+		/*
+		 * Try to receive all events in one eloop call in order to
+		 * limit race condition on cases where AssocInfo event, Assoc
+		 * event, and EAPOL frames are received more or less at the
+		 * same time. We want to process the event messages first
+		 * before starting EAPOL processing.
+		 */
+		goto try_again;
+	}
+}
+
+
+struct netlink_data * netlink_init(struct netlink_config *cfg)
+{
+	struct netlink_data *netlink;
+	struct sockaddr_nl local;
+
+	netlink = os_zalloc(sizeof(*netlink));
+	if (netlink == NULL)
+		return NULL;
+
+	netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (netlink->sock < 0) {
+		wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
+			   "socket: %s", strerror(errno));
+		netlink_deinit(netlink);
+		return NULL;
+	}
+
+	os_memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+	local.nl_groups = RTMGRP_LINK;
+	if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)
+	{
+		wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "
+			   "socket: %s", strerror(errno));
+		netlink_deinit(netlink);
+		return NULL;
+	}
+
+	eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
+				 NULL);
+
+	netlink->cfg = cfg;
+
+	return netlink;
+}
+
+
+void netlink_deinit(struct netlink_data *netlink)
+{
+	if (netlink == NULL)
+		return;
+	if (netlink->sock >= 0) {
+		eloop_unregister_read_sock(netlink->sock);
+		close(netlink->sock);
+	}
+	os_free(netlink->cfg);
+	os_free(netlink);
+}
+
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+			   int linkmode, int operstate)
+{
+	struct {
+		struct nlmsghdr hdr;
+		struct ifinfomsg ifinfo;
+		char opts[16];
+	} req;
+	struct rtattr *rta;
+	static int nl_seq;
+	ssize_t ret;
+
+	os_memset(&req, 0, sizeof(req));
+
+	req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.hdr.nlmsg_type = RTM_SETLINK;
+	req.hdr.nlmsg_flags = NLM_F_REQUEST;
+	req.hdr.nlmsg_seq = ++nl_seq;
+	req.hdr.nlmsg_pid = 0;
+
+	req.ifinfo.ifi_family = AF_UNSPEC;
+	req.ifinfo.ifi_type = 0;
+	req.ifinfo.ifi_index = ifindex;
+	req.ifinfo.ifi_flags = 0;
+	req.ifinfo.ifi_change = 0;
+
+	if (linkmode != -1) {
+		rta = aliasing_hide_typecast(
+			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+			struct rtattr);
+		rta->rta_type = IFLA_LINKMODE;
+		rta->rta_len = RTA_LENGTH(sizeof(char));
+		*((char *) RTA_DATA(rta)) = linkmode;
+		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+			RTA_LENGTH(sizeof(char));
+	}
+	if (operstate != -1) {
+		rta = aliasing_hide_typecast(
+			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+			struct rtattr);
+		rta->rta_type = IFLA_OPERSTATE;
+		rta->rta_len = RTA_LENGTH(sizeof(char));
+		*((char *) RTA_DATA(rta)) = operstate;
+		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+			RTA_LENGTH(sizeof(char));
+	}
+
+	wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d",
+		   linkmode, operstate);
+
+	ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA "
+			   "failed: %s (assume operstate is not supported)",
+			   strerror(errno));
+	}
+
+	return ret < 0 ? -1 : 0;
+}

Deleted: vendor/wpa/2.0/src/drivers/netlink.h
===================================================================
--- vendor/wpa/dist/src/drivers/netlink.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/netlink.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,33 +0,0 @@
-/*
- * Netlink helper functions for driver wrappers
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef NETLINK_H
-#define NETLINK_H
-
-struct netlink_data;
-
-struct netlink_config {
-	void *ctx;
-	void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
-			   size_t len);
-	void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
-			   size_t len);
-};
-
-struct netlink_data * netlink_init(struct netlink_config *cfg);
-void netlink_deinit(struct netlink_data *netlink);
-int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
-			   int linkmode, int operstate);
-
-#endif /* NETLINK_H */

Copied: vendor/wpa/2.0/src/drivers/netlink.h (from rev 9639, vendor/wpa/dist/src/drivers/netlink.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/netlink.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/netlink.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * Netlink helper functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NETLINK_H
+#define NETLINK_H
+
+struct netlink_data;
+struct ifinfomsg;
+
+struct netlink_config {
+	void *ctx;
+	void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+			   size_t len);
+	void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf,
+			   size_t len);
+};
+
+struct netlink_data * netlink_init(struct netlink_config *cfg);
+void netlink_deinit(struct netlink_data *netlink);
+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex,
+			   int linkmode, int operstate);
+
+#endif /* NETLINK_H */

Deleted: vendor/wpa/2.0/src/drivers/nl80211_copy.h
===================================================================
--- vendor/wpa/dist/src/drivers/nl80211_copy.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/nl80211_copy.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1644 +0,0 @@
-#ifndef __LINUX_NL80211_H
-#define __LINUX_NL80211_H
-/*
- * 802.11 netlink interface public header
- *
- * Copyright 2006-2010 Johannes Berg <johannes at sipsolutions.net>
- * Copyright 2008 Michael Wu <flamingice at sourmilk.net>
- * Copyright 2008 Luis Carlos Cobo <luisca at cozybit.com>
- * Copyright 2008 Michael Buesch <mb at bu3sch.de>
- * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez at atheros.com>
- * Copyright 2008 Jouni Malinen <jouni.malinen at atheros.com>
- * Copyright 2008 Colin McCabe <colin at cozybit.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-#include <linux/types.h>
-
-/**
- * DOC: Station handling
- *
- * Stations are added per interface, but a special case exists with VLAN
- * interfaces. When a station is bound to an AP interface, it may be moved
- * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
- * The station is still assumed to belong to the AP interface it was added
- * to.
- *
- * TODO: need more info?
- */
-
-/**
- * enum nl80211_commands - supported nl80211 commands
- *
- * @NL80211_CMD_UNSPEC: unspecified command to catch errors
- *
- * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
- *	to get a list of all present wiphys.
- * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
- *	%NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
- *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
- *	%NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- *	and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
- * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
- *	or rename notification. Has attributes %NL80211_ATTR_WIPHY and
- *	%NL80211_ATTR_WIPHY_NAME.
- * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
- *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
- *
- * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
- *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
- *	on an %NL80211_ATTR_IFINDEX is supported.
- * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
- *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
- * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
- *	to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
- *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
- *	be sent from userspace to request creation of a new virtual interface,
- *	then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
- *	%NL80211_ATTR_IFNAME.
- * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
- *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
- *	userspace to request deletion of a virtual interface, then requires
- *	attribute %NL80211_ATTR_IFINDEX.
- *
- * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
- *	by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
- * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
- *	%NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
- * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
- *	%NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
- *	and %NL80211_ATTR_KEY_SEQ attributes.
- * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
- *	or %NL80211_ATTR_MAC.
- *
- * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
- *	%NL80222_CMD_NEW_BEACON message)
- * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
- *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
- *	%NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
- * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
- *	parameters are like for %NL80211_CMD_SET_BEACON.
- * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
- *
- * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
- *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
- *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
- *	the interface identified by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
- *	or, if no MAC address given, all stations, on the interface identified
- *	by %NL80211_ATTR_IFINDEX.
- *
- * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
- * 	destination %NL80211_ATTR_MAC on the interface identified by
- * 	%NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
- * 	destination %NL80211_ATTR_MAC on the interface identified by
- * 	%NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
- *	the interface identified by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
- *	or, if no MAC address given, all mesh paths, on the interface identified
- *	by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
- *	%NL80211_ATTR_IFINDEX.
- *
- * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
- * 	regulatory domain.
- * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
- *	after being queried by the kernel. CRDA replies by sending a regulatory
- *	domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
- *	current alpha2 if it found a match. It also provides
- * 	NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
- * 	regulatory rule is a nested set of attributes  given by
- * 	%NL80211_ATTR_REG_RULE_FREQ_[START|END] and
- * 	%NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
- * 	%NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
- * 	%NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
- * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- * 	to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
- * 	store this as a valid request and then query userspace for it.
- *
- * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
- *	interface identified by %NL80211_ATTR_IFINDEX
- *
- * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
- *      interface identified by %NL80211_ATTR_IFINDEX
- *
- * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
- *	interface is identified with %NL80211_ATTR_IFINDEX and the management
- *	frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
- *	added to the end of the specified management frame is specified with
- *	%NL80211_ATTR_IE. If the command succeeds, the requested data will be
- *	added to all specified management frames generated by
- *	kernel/firmware/driver.
- *	Note: This command has been removed and it is only reserved at this
- *	point to avoid re-using existing command number. The functionality this
- *	command was planned for has been provided with cleaner design with the
- *	option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
- *	NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
- *	NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
- *
- * @NL80211_CMD_GET_SCAN: get scan results
- * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
- * @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_GET_SURVEY: get survey resuls, e.g. channel occupation
- *      or noise level
- * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
- *	NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
- *
- * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
- * 	has been changed and provides details of the request information
- * 	that caused the change such as who initiated the regulatory request
- * 	(%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
- * 	(%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
- * 	the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
- * 	%NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
- * 	set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
- * 	%NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
- * 	to (%NL80211_ATTR_REG_ALPHA2).
- * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
- * 	has been found while world roaming thus enabling active scan or
- * 	any mode of operation that initiates TX (beacons) on a channel
- * 	where we would not have been able to do either before. As an example
- * 	if you are world roaming (regulatory domain set to world or if your
- * 	driver is using a custom world roaming regulatory domain) and while
- * 	doing a passive scan on the 5 GHz band you find an AP there (if not
- * 	on a DFS channel) you will now be able to actively scan for that AP
- * 	or use AP mode on your card on that same channel. Note that this will
- * 	never be used for channels 1-11 on the 2 GHz band as they are always
- * 	enabled world wide. This beacon hint is only sent if your device had
- * 	either disabled active scanning or beaconing on a channel. We send to
- * 	userspace the wiphy on which we removed a restriction from
- * 	(%NL80211_ATTR_WIPHY) and the channel on which this occurred
- * 	before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
- * 	the beacon hint was processed.
- *
- * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
- *	This command is used both as a command (request to authenticate) and
- *	as an event on the "mlme" multicast group indicating completion of the
- *	authentication process.
- *	When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
- *	interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
- *	BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
- *	the SSID (mainly for association, but is included in authentication
- *	request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
- *	to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
- *	is used to specify the authentication type. %NL80211_ATTR_IE is used to
- *	define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
- *	to be added to the frame.
- *	When used as an event, this reports reception of an Authentication
- *	frame in station and IBSS modes when the local MLME processed the
- *	frame, i.e., it was for the local STA and was received in correct
- *	state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
- *	MLME SAP interface (kernel providing MLME, userspace SME). The
- *	included %NL80211_ATTR_FRAME attribute contains the management frame
- *	(including both the header and frame body, but not FCS). This event is
- *	also used to indicate if the authentication attempt timed out. In that
- *	case the %NL80211_ATTR_FRAME attribute is replaced with a
- *	%NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
- *	pending authentication timed out).
- * @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).
- * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
- *	NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
- *	MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
- *	primitives).
- * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
- *	NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
- *	MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
- *
- * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
- *	MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
- *	event includes %NL80211_ATTR_MAC to describe the source MAC address of
- *	the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
- *	type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
- *	%NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
- *	event matches with MLME-MICHAELMICFAILURE.indication() primitive
- *
- * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
- *	FREQ attribute (for the initial frequency if no peer can be found)
- *	and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
- *	should be fixed rather than automatically determined. Can only be
- *	executed on a network interface that is UP, and fixed BSSID/FREQ
- *	may be rejected. Another optional parameter is the beacon interval,
- *	given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
- *	given defaults to 100 TU (102.4ms).
- * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
- *	determined by the network interface.
- *
- * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
- *	to identify the device, and the TESTDATA blob attribute to pass through
- *	to the driver.
- *
- * @NL80211_CMD_CONNECT: connection request and notification; this command
- *	requests to connect to a specified network but without separating
- *	auth and assoc steps. For this, you need to specify the SSID in a
- *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
- *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- *	%NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
- *	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.
- * @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
- *	userspace that a connection was dropped by the AP or due to other
- *	reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
- *	%NL80211_ATTR_REASON_CODE attributes are used.
- *
- * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
- *	associated with this wiphy must be down and will follow.
- *
- * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
- *	channel for the specified amount of time. This can be used to do
- *	off-channel operations like transmit a Public Action frame and wait for
- *	a response while being associated to an AP on another channel.
- *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
- *	radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
- *	frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
- *	optionally used to specify additional channel parameters.
- *	%NL80211_ATTR_DURATION is used to specify the duration in milliseconds
- *	to remain on the channel. This command is also used as an event to
- *	notify when the requested duration starts (it may take a while for the
- *	driver to schedule this time due to other concurrent needs for the
- *	radio).
- *	When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
- *	that will be included with any events pertaining to this request;
- *	the cookie is also used to cancel the request.
- * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
- *	pending remain-on-channel duration if the desired operation has been
- *	completed prior to expiration of the originally requested duration.
- *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
- *	radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
- *	uniquely identify the request.
- *	This command is also used as an event to notify when a requested
- *	remain-on-channel duration has expired.
- *
- * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
- *	rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
- *	and @NL80211_ATTR_TX_RATES the set of allowed rates.
- *
- * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
- *	(via @NL80211_CMD_ACTION) for processing in userspace. This command
- *	requires an interface index and a match attribute containing the first
- *	few bytes of the frame that should match, e.g. a single byte for only
- *	a category match or four bytes for vendor frames including the OUI.
- *	The registration cannot be dropped, but is removed automatically
- *	when the netlink socket is closed. Multiple registrations can be made.
- * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
- *	command is used both as a request to transmit an Action frame and as an
- *	event indicating reception of an Action frame that was not processed in
- *	kernel code, but is for us (i.e., which may need to be processed in a
- *	user space application). %NL80211_ATTR_FRAME is used to specify the
- *	frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
- *	optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- *	which channel the frame is to be transmitted or was received. This
- *	channel has to be the current channel (remain-on-channel or the
- *	operational channel). When called, this operation returns a cookie
- *	(%NL80211_ATTR_COOKIE) that will be included with the TX status event
- *	pertaining to the TX request.
- * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
- *	transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
- *	the TX command and %NL80211_ATTR_FRAME includes the contents of the
- *	frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
- *	the frame.
- * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
- *	is used to configure connection quality monitoring notification trigger
- *	levels.
- * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
- *	command is used as an event to indicate the that a trigger level was
- *	reached.
- *
- * @NL80211_CMD_MAX: highest used command number
- * @__NL80211_CMD_AFTER_LAST: internal use
- */
-enum nl80211_commands {
-/* don't change the order or add anything inbetween, this is ABI! */
-	NL80211_CMD_UNSPEC,
-
-	NL80211_CMD_GET_WIPHY,		/* can dump */
-	NL80211_CMD_SET_WIPHY,
-	NL80211_CMD_NEW_WIPHY,
-	NL80211_CMD_DEL_WIPHY,
-
-	NL80211_CMD_GET_INTERFACE,	/* can dump */
-	NL80211_CMD_SET_INTERFACE,
-	NL80211_CMD_NEW_INTERFACE,
-	NL80211_CMD_DEL_INTERFACE,
-
-	NL80211_CMD_GET_KEY,
-	NL80211_CMD_SET_KEY,
-	NL80211_CMD_NEW_KEY,
-	NL80211_CMD_DEL_KEY,
-
-	NL80211_CMD_GET_BEACON,
-	NL80211_CMD_SET_BEACON,
-	NL80211_CMD_NEW_BEACON,
-	NL80211_CMD_DEL_BEACON,
-
-	NL80211_CMD_GET_STATION,
-	NL80211_CMD_SET_STATION,
-	NL80211_CMD_NEW_STATION,
-	NL80211_CMD_DEL_STATION,
-
-	NL80211_CMD_GET_MPATH,
-	NL80211_CMD_SET_MPATH,
-	NL80211_CMD_NEW_MPATH,
-	NL80211_CMD_DEL_MPATH,
-
-	NL80211_CMD_SET_BSS,
-
-	NL80211_CMD_SET_REG,
-	NL80211_CMD_REQ_SET_REG,
-
-	NL80211_CMD_GET_MESH_PARAMS,
-	NL80211_CMD_SET_MESH_PARAMS,
-
-	NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
-
-	NL80211_CMD_GET_REG,
-
-	NL80211_CMD_GET_SCAN,
-	NL80211_CMD_TRIGGER_SCAN,
-	NL80211_CMD_NEW_SCAN_RESULTS,
-	NL80211_CMD_SCAN_ABORTED,
-
-	NL80211_CMD_REG_CHANGE,
-
-	NL80211_CMD_AUTHENTICATE,
-	NL80211_CMD_ASSOCIATE,
-	NL80211_CMD_DEAUTHENTICATE,
-	NL80211_CMD_DISASSOCIATE,
-
-	NL80211_CMD_MICHAEL_MIC_FAILURE,
-
-	NL80211_CMD_REG_BEACON_HINT,
-
-	NL80211_CMD_JOIN_IBSS,
-	NL80211_CMD_LEAVE_IBSS,
-
-	NL80211_CMD_TESTMODE,
-
-	NL80211_CMD_CONNECT,
-	NL80211_CMD_ROAM,
-	NL80211_CMD_DISCONNECT,
-
-	NL80211_CMD_SET_WIPHY_NETNS,
-
-	NL80211_CMD_GET_SURVEY,
-	NL80211_CMD_NEW_SURVEY_RESULTS,
-
-	NL80211_CMD_SET_PMKSA,
-	NL80211_CMD_DEL_PMKSA,
-	NL80211_CMD_FLUSH_PMKSA,
-
-	NL80211_CMD_REMAIN_ON_CHANNEL,
-	NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
-
-	NL80211_CMD_SET_TX_BITRATE_MASK,
-
-	NL80211_CMD_REGISTER_ACTION,
-	NL80211_CMD_ACTION,
-	NL80211_CMD_ACTION_TX_STATUS,
-
-	NL80211_CMD_SET_POWER_SAVE,
-	NL80211_CMD_GET_POWER_SAVE,
-
-	NL80211_CMD_SET_CQM,
-	NL80211_CMD_NOTIFY_CQM,
-
-	/* add new commands above here */
-
-	/* used to define NL80211_CMD_MAX below */
-	__NL80211_CMD_AFTER_LAST,
-	NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
-};
-
-/*
- * Allow user space programs to use #ifdef on new commands by defining them
- * here
- */
-#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
-#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
-#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
-#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
-#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
-#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
-#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
-#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
-
-/**
- * enum nl80211_attrs - nl80211 netlink attributes
- *
- * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
- *
- * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
- *	/sys/class/ieee80211/<phyname>/index
- * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
- * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
- * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
- * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
- *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
- *	NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
- *		this attribute)
- *	NL80211_CHAN_HT20 = HT20 only
- *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
- *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
- * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
- *	less than or equal to the RTS threshold; allowed range: 1..255;
- *	dot11ShortRetryLimit; u8
- * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
- *	greater than the RTS threshold; allowed range: 1..255;
- *	dot11ShortLongLimit; u8
- * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
- *	length in octets for frames; allowed range: 256..8000, disable
- *	fragmentation with (u32)-1; dot11FragmentationThreshold; u32
- * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
- *	larger than or equal to this use RTS/CTS handshake); allowed range:
- *	0..65536, disable with (u32)-1; dot11RTSThreshold; u32
- * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
- *	section 7.3.2.9; dot11CoverageClass; u8
- *
- * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
- * @NL80211_ATTR_IFNAME: network interface name
- * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
- *
- * @NL80211_ATTR_MAC: MAC address (various uses)
- *
- * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
- *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
- *	keys
- * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
- * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
- *	section 7.3.2.25.1, e.g. 0x000FAC04)
- * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
- *	CCMP keys, each six bytes in little endian
- *
- * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
- * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
- * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
- * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
- *
- * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
- * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
- *	&enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
- * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
- *	IEEE 802.11 7.3.1.6 (u16).
- * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
- *	rates as defined by IEEE 802.11 7.3.2.2 but without the length
- *	restriction (at most %NL80211_MAX_SUPP_RATES).
- * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
- *	to, or the AP interface the station was originally added to to.
- * @NL80211_ATTR_STA_INFO: information about a station, part of station info
- *	given for %NL80211_CMD_GET_STATION, nested attribute containing
- *	info as possible, see &enum nl80211_sta_info.
- *
- * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
- *	consisting of a nested array.
- *
- * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
- * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
- * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
- * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
- *	&enum nl80211_mpath_info.
- *
- * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
- *      &enum nl80211_mntr_flags.
- *
- * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
- * 	current regulatory domain should be set to or is already set to.
- * 	For example, 'CR', for Costa Rica. This attribute is used by the kernel
- * 	to query the CRDA to retrieve one regulatory domain. This attribute can
- * 	also be used by userspace to query the kernel for the currently set
- * 	regulatory domain. We chose an alpha2 as that is also used by the
- * 	IEEE-802.11d country information element to identify a country.
- * 	Users can also simply ask the wireless core to set regulatory domain
- * 	to a specific alpha2.
- * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
- *	rules.
- *
- * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
- * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
- *	(u8, 0 or 1)
- * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
- *	(u8, 0 or 1)
- * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
- *	rates in format defined by IEEE 802.11 7.3.2.2 but without the length
- *	restriction (at most %NL80211_MAX_SUPP_RATES).
- *
- * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
- *	association request when used with NL80211_CMD_NEW_STATION)
- *
- * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
- *	supported interface types, each a flag attribute with the number
- *	of the interface mode.
- *
- * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
- *	%NL80211_CMD_SET_MGMT_EXTRA_IE.
- *
- * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
- *	%NL80211_CMD_SET_MGMT_EXTRA_IE).
- *
- * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
- *	a single scan request, a wiphy attribute.
- * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
- *	that can be added to a scan request
- *
- * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
- * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
- *	scanning and include a zero-length SSID (wildcard) for wildcard scan
- * @NL80211_ATTR_BSS: scan result BSS
- *
- * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
- * 	currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
- * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
- * 	set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
- *
- * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
- *	an array of command numbers (i.e. a mapping index to command number)
- *	that the driver for the given wiphy supports.
- *
- * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
- *	and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
- *	NL80211_CMD_ASSOCIATE events
- * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
- * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
- *	represented as a u32
- * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
- *	%NL80211_CMD_DISASSOCIATE, u16
- *
- * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
- *	a u32
- *
- * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
- * 	due to considerations from a beacon hint. This attribute reflects
- * 	the state of the channel _before_ the beacon hint processing. This
- * 	attributes consists of a nested attribute containing
- * 	NL80211_FREQUENCY_ATTR_*
- * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
- * 	due to considerations from a beacon hint. This attribute reflects
- * 	the state of the channel _after_ the beacon hint processing. This
- * 	attributes consists of a nested attribute containing
- * 	NL80211_FREQUENCY_ATTR_*
- *
- * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
- *	cipher suites
- *
- * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
- *	for other networks on different channels
- *
- * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
- *	is used, e.g., with %NL80211_CMD_AUTHENTICATE event
- *
- * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
- *	used for the association (&enum nl80211_mfp, represented as a u32);
- *	this attribute can be used
- *	with %NL80211_CMD_ASSOCIATE request
- *
- * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
- *	&struct nl80211_sta_flag_update.
- *
- * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
- *	IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
- *	station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
- *	request, the driver will assume that the port is unauthorized until
- *	authorized by user space. Otherwise, port is marked authorized by
- *	default in station mode.
- *
- * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
- *	We recommend using nested, driver-specific attributes within this.
- *
- * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
- *	event was due to the AP disconnecting the station, and not due to
- *	a local disconnect request.
- * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
- *	event (u16)
- * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- *	that protected APs should be used.
- *
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- *	indicate which unicast key ciphers will be used with the connection
- *	(an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- *	which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- *	which WPA version(s) the AP we want to associate with is using
- *	(a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- *	which key management algorithm(s) to use (an array of u32).
- *
- * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
- *	sent out by the card, for ROAM and successful CONNECT events.
- * @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_KEY: key information in a nested attribute with
- *	%NL80211_KEY_* sub-attributes
- * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
- *	and join_ibss(), key information is in a nested attribute each
- *	with %NL80211_KEY_* sub-attributes
- *
- * @NL80211_ATTR_PID: Process ID of a network namespace.
- *
- * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
- *	dumps. This number increases whenever the object list being
- *	dumped changes, and as such userspace can verify that it has
- *	obtained a complete and consistent snapshot by verifying that
- *	all dump messages contain the same generation number. If it
- *	changed then the list changed and the dump should be repeated
- *	completely from scratch.
- *
- * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
- *
- * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
- *      the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
- *      containing info as possible, see &enum survey_info.
- *
- * @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
- * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
- *	cache, a wiphy attribute.
- *
- * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
- *
- * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
- *
- * @NL80211_ATTR_TX_RATES: Nested set of attributes
- *	(enum nl80211_tx_rate_attributes) describing TX rates per band. The
- *	enum nl80211_band value is used as the index (nla_type() of the nested
- *	data. If a band is not included, it will be configured to allow all
- *	rates based on negotiated supported rates information. This attribute
- *	is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
- *
- * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
- *	at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
- *
- * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
- *	acknowledged by the recipient.
- *
- * @NL80211_ATTR_CQM: connection quality monitor configuration in a
- *	nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
- *
- * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
- *	is requesting a local authentication/association state change without
- *	invoking actual management frame exchange. This can be used with
- *	NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
- *	NL80211_CMD_DISASSOCIATE.
- *
- * @NL80211_ATTR_MAX: highest attribute number currently defined
- * @__NL80211_ATTR_AFTER_LAST: internal use
- */
-enum nl80211_attrs {
-/* don't change the order or add anything inbetween, this is ABI! */
-	NL80211_ATTR_UNSPEC,
-
-	NL80211_ATTR_WIPHY,
-	NL80211_ATTR_WIPHY_NAME,
-
-	NL80211_ATTR_IFINDEX,
-	NL80211_ATTR_IFNAME,
-	NL80211_ATTR_IFTYPE,
-
-	NL80211_ATTR_MAC,
-
-	NL80211_ATTR_KEY_DATA,
-	NL80211_ATTR_KEY_IDX,
-	NL80211_ATTR_KEY_CIPHER,
-	NL80211_ATTR_KEY_SEQ,
-	NL80211_ATTR_KEY_DEFAULT,
-
-	NL80211_ATTR_BEACON_INTERVAL,
-	NL80211_ATTR_DTIM_PERIOD,
-	NL80211_ATTR_BEACON_HEAD,
-	NL80211_ATTR_BEACON_TAIL,
-
-	NL80211_ATTR_STA_AID,
-	NL80211_ATTR_STA_FLAGS,
-	NL80211_ATTR_STA_LISTEN_INTERVAL,
-	NL80211_ATTR_STA_SUPPORTED_RATES,
-	NL80211_ATTR_STA_VLAN,
-	NL80211_ATTR_STA_INFO,
-
-	NL80211_ATTR_WIPHY_BANDS,
-
-	NL80211_ATTR_MNTR_FLAGS,
-
-	NL80211_ATTR_MESH_ID,
-	NL80211_ATTR_STA_PLINK_ACTION,
-	NL80211_ATTR_MPATH_NEXT_HOP,
-	NL80211_ATTR_MPATH_INFO,
-
-	NL80211_ATTR_BSS_CTS_PROT,
-	NL80211_ATTR_BSS_SHORT_PREAMBLE,
-	NL80211_ATTR_BSS_SHORT_SLOT_TIME,
-
-	NL80211_ATTR_HT_CAPABILITY,
-
-	NL80211_ATTR_SUPPORTED_IFTYPES,
-
-	NL80211_ATTR_REG_ALPHA2,
-	NL80211_ATTR_REG_RULES,
-
-	NL80211_ATTR_MESH_PARAMS,
-
-	NL80211_ATTR_BSS_BASIC_RATES,
-
-	NL80211_ATTR_WIPHY_TXQ_PARAMS,
-	NL80211_ATTR_WIPHY_FREQ,
-	NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-
-	NL80211_ATTR_KEY_DEFAULT_MGMT,
-
-	NL80211_ATTR_MGMT_SUBTYPE,
-	NL80211_ATTR_IE,
-
-	NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
-
-	NL80211_ATTR_SCAN_FREQUENCIES,
-	NL80211_ATTR_SCAN_SSIDS,
-	NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
-	NL80211_ATTR_BSS,
-
-	NL80211_ATTR_REG_INITIATOR,
-	NL80211_ATTR_REG_TYPE,
-
-	NL80211_ATTR_SUPPORTED_COMMANDS,
-
-	NL80211_ATTR_FRAME,
-	NL80211_ATTR_SSID,
-	NL80211_ATTR_AUTH_TYPE,
-	NL80211_ATTR_REASON_CODE,
-
-	NL80211_ATTR_KEY_TYPE,
-
-	NL80211_ATTR_MAX_SCAN_IE_LEN,
-	NL80211_ATTR_CIPHER_SUITES,
-
-	NL80211_ATTR_FREQ_BEFORE,
-	NL80211_ATTR_FREQ_AFTER,
-
-	NL80211_ATTR_FREQ_FIXED,
-
-
-	NL80211_ATTR_WIPHY_RETRY_SHORT,
-	NL80211_ATTR_WIPHY_RETRY_LONG,
-	NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
-	NL80211_ATTR_WIPHY_RTS_THRESHOLD,
-
-	NL80211_ATTR_TIMED_OUT,
-
-	NL80211_ATTR_USE_MFP,
-
-	NL80211_ATTR_STA_FLAGS2,
-
-	NL80211_ATTR_CONTROL_PORT,
-
-	NL80211_ATTR_TESTDATA,
-
-	NL80211_ATTR_PRIVACY,
-
-	NL80211_ATTR_DISCONNECTED_BY_AP,
-	NL80211_ATTR_STATUS_CODE,
-
-	NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
-	NL80211_ATTR_CIPHER_SUITE_GROUP,
-	NL80211_ATTR_WPA_VERSIONS,
-	NL80211_ATTR_AKM_SUITES,
-
-	NL80211_ATTR_REQ_IE,
-	NL80211_ATTR_RESP_IE,
-
-	NL80211_ATTR_PREV_BSSID,
-
-	NL80211_ATTR_KEY,
-	NL80211_ATTR_KEYS,
-
-	NL80211_ATTR_PID,
-
-	NL80211_ATTR_4ADDR,
-
-	NL80211_ATTR_SURVEY_INFO,
-
-	NL80211_ATTR_PMKID,
-	NL80211_ATTR_MAX_NUM_PMKIDS,
-
-	NL80211_ATTR_DURATION,
-
-	NL80211_ATTR_COOKIE,
-
-	NL80211_ATTR_WIPHY_COVERAGE_CLASS,
-
-	NL80211_ATTR_TX_RATES,
-
-	NL80211_ATTR_FRAME_MATCH,
-
-	NL80211_ATTR_ACK,
-
-	NL80211_ATTR_PS_STATE,
-
-	NL80211_ATTR_CQM,
-
-	NL80211_ATTR_LOCAL_STATE_CHANGE,
-
-	/* add attributes here, update the policy in nl80211.c */
-
-	__NL80211_ATTR_AFTER_LAST,
-	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
-};
-
-/* source-level API compatibility */
-#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
-
-/*
- * Allow user space programs to use #ifdef on new attributes by defining them
- * here
- */
-#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
-#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
-#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
-#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
-#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
-#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
-#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
-#define NL80211_ATTR_IE NL80211_ATTR_IE
-#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
-#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
-#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
-#define NL80211_ATTR_SSID NL80211_ATTR_SSID
-#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
-#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
-#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
-#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
-#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
-#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
-#define NL80211_ATTR_KEY NL80211_ATTR_KEY
-#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
-
-#define NL80211_MAX_SUPP_RATES			32
-#define NL80211_MAX_SUPP_REG_RULES		32
-#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY	0
-#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY	16
-#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
-#define NL80211_HT_CAPABILITY_LEN		26
-
-#define NL80211_MAX_NR_CIPHER_SUITES		5
-#define NL80211_MAX_NR_AKM_SUITES		2
-
-/**
- * enum nl80211_iftype - (virtual) interface types
- *
- * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
- * @NL80211_IFTYPE_ADHOC: independent BSS member
- * @NL80211_IFTYPE_STATION: managed BSS member
- * @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
- * @NL80211_IFTYPE_WDS: wireless distribution interface
- * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
- * @NL80211_IFTYPE_MESH_POINT: mesh point
- * @NL80211_IFTYPE_MAX: highest interface type number currently defined
- * @__NL80211_IFTYPE_AFTER_LAST: internal use
- *
- * These values are used with the %NL80211_ATTR_IFTYPE
- * to set the type of an interface.
- *
- */
-enum nl80211_iftype {
-	NL80211_IFTYPE_UNSPECIFIED,
-	NL80211_IFTYPE_ADHOC,
-	NL80211_IFTYPE_STATION,
-	NL80211_IFTYPE_AP,
-	NL80211_IFTYPE_AP_VLAN,
-	NL80211_IFTYPE_WDS,
-	NL80211_IFTYPE_MONITOR,
-	NL80211_IFTYPE_MESH_POINT,
-
-	/* keep last */
-	__NL80211_IFTYPE_AFTER_LAST,
-	NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_sta_flags - station flags
- *
- * Station flags. When a station is added to an AP interface, it is
- * assumed to be already associated (and hence authenticated.)
- *
- * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
- * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
- *	with short barker preamble
- * @NL80211_STA_FLAG_WME: station is WME/QoS capable
- * @NL80211_STA_FLAG_MFP: station uses management frame protection
- */
-enum nl80211_sta_flags {
-	__NL80211_STA_FLAG_INVALID,
-	NL80211_STA_FLAG_AUTHORIZED,
-	NL80211_STA_FLAG_SHORT_PREAMBLE,
-	NL80211_STA_FLAG_WME,
-	NL80211_STA_FLAG_MFP,
-
-	/* keep last */
-	__NL80211_STA_FLAG_AFTER_LAST,
-	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
-};
-
-/**
- * struct nl80211_sta_flag_update - station flags mask/set
- * @mask: mask of station flags to set
- * @set: which values to set them to
- *
- * Both mask and set contain bits as per &enum nl80211_sta_flags.
- */
-struct nl80211_sta_flag_update {
-	__u32 mask;
-	__u32 set;
-} __attribute__((packed));
-
-/**
- * enum nl80211_rate_info - bitrate information
- *
- * These attribute types are used with %NL80211_STA_INFO_TXRATE
- * when getting information about the bitrate of a station.
- *
- * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
- * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
- * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
- * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
- * @__NL80211_RATE_INFO_AFTER_LAST: internal use
- */
-enum nl80211_rate_info {
-	__NL80211_RATE_INFO_INVALID,
-	NL80211_RATE_INFO_BITRATE,
-	NL80211_RATE_INFO_MCS,
-	NL80211_RATE_INFO_40_MHZ_WIDTH,
-	NL80211_RATE_INFO_SHORT_GI,
-
-	/* keep last */
-	__NL80211_RATE_INFO_AFTER_LAST,
-	NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_sta_info - station information
- *
- * These attribute types are used with %NL80211_ATTR_STA_INFO
- * when getting information about a station.
- *
- * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
- * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
- * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * 	containing info as possible, see &enum nl80211_sta_info_txrate.
- * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
- * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
- *	station)
- */
-enum nl80211_sta_info {
-	__NL80211_STA_INFO_INVALID,
-	NL80211_STA_INFO_INACTIVE_TIME,
-	NL80211_STA_INFO_RX_BYTES,
-	NL80211_STA_INFO_TX_BYTES,
-	NL80211_STA_INFO_LLID,
-	NL80211_STA_INFO_PLID,
-	NL80211_STA_INFO_PLINK_STATE,
-	NL80211_STA_INFO_SIGNAL,
-	NL80211_STA_INFO_TX_BITRATE,
-	NL80211_STA_INFO_RX_PACKETS,
-	NL80211_STA_INFO_TX_PACKETS,
-
-	/* keep last */
-	__NL80211_STA_INFO_AFTER_LAST,
-	NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_mpath_flags - nl80211 mesh path flags
- *
- * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
- * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
- * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
- * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
- * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
- */
-enum nl80211_mpath_flags {
-	NL80211_MPATH_FLAG_ACTIVE =	1<<0,
-	NL80211_MPATH_FLAG_RESOLVING =	1<<1,
-	NL80211_MPATH_FLAG_SN_VALID =	1<<2,
-	NL80211_MPATH_FLAG_FIXED =	1<<3,
-	NL80211_MPATH_FLAG_RESOLVED =	1<<4,
-};
-
-/**
- * enum nl80211_mpath_info - mesh path information
- *
- * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
- * information about a mesh path.
- *
- * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
- * @NL80211_ATTR_MPATH_SN: destination sequence number
- * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
- * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
- * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
- * 	&enum nl80211_mpath_flags;
- * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
- * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
- */
-enum nl80211_mpath_info {
-	__NL80211_MPATH_INFO_INVALID,
-	NL80211_MPATH_INFO_FRAME_QLEN,
-	NL80211_MPATH_INFO_SN,
-	NL80211_MPATH_INFO_METRIC,
-	NL80211_MPATH_INFO_EXPTIME,
-	NL80211_MPATH_INFO_FLAGS,
-	NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
-	NL80211_MPATH_INFO_DISCOVERY_RETRIES,
-
-	/* keep last */
-	__NL80211_MPATH_INFO_AFTER_LAST,
-	NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_band_attr - band attributes
- * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
- * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
- *	an array of nested frequency attributes
- * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
- *	an array of nested bitrate attributes
- * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
- *	defined in 802.11n
- * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
- * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
- * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
- */
-enum nl80211_band_attr {
-	__NL80211_BAND_ATTR_INVALID,
-	NL80211_BAND_ATTR_FREQS,
-	NL80211_BAND_ATTR_RATES,
-
-	NL80211_BAND_ATTR_HT_MCS_SET,
-	NL80211_BAND_ATTR_HT_CAPA,
-	NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
-	NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
-
-	/* keep last */
-	__NL80211_BAND_ATTR_AFTER_LAST,
-	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
-};
-
-#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
-
-/**
- * enum nl80211_frequency_attr - frequency attributes
- * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
- * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
- *	regulatory domain.
- * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
- *	permitted on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
- *	on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
- *	on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
- *	(100 * dBm).
- */
-enum nl80211_frequency_attr {
-	__NL80211_FREQUENCY_ATTR_INVALID,
-	NL80211_FREQUENCY_ATTR_FREQ,
-	NL80211_FREQUENCY_ATTR_DISABLED,
-	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
-	NL80211_FREQUENCY_ATTR_NO_IBSS,
-	NL80211_FREQUENCY_ATTR_RADAR,
-	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
-
-	/* keep last */
-	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
-	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
-};
-
-#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
-
-/**
- * enum nl80211_bitrate_attr - bitrate attributes
- * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
- * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
- *	in 2.4 GHz band.
- */
-enum nl80211_bitrate_attr {
-	__NL80211_BITRATE_ATTR_INVALID,
-	NL80211_BITRATE_ATTR_RATE,
-	NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
-
-	/* keep last */
-	__NL80211_BITRATE_ATTR_AFTER_LAST,
-	NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_initiator - Indicates the initiator of a reg domain request
- * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
- * 	regulatory domain.
- * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
- * 	regulatory domain.
- * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
- * 	wireless core it thinks its knows the regulatory domain we should be in.
- * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
- * 	802.11 country information element with regulatory information it
- * 	thinks we should consider.
- */
-enum nl80211_reg_initiator {
-	NL80211_REGDOM_SET_BY_CORE,
-	NL80211_REGDOM_SET_BY_USER,
-	NL80211_REGDOM_SET_BY_DRIVER,
-	NL80211_REGDOM_SET_BY_COUNTRY_IE,
-};
-
-/**
- * enum nl80211_reg_type - specifies the type of regulatory domain
- * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
- *	to a specific country. When this is set you can count on the
- *	ISO / IEC 3166 alpha2 country code being valid.
- * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
- * 	domain.
- * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
- * 	driver specific world regulatory domain. These do not apply system-wide
- * 	and are only applicable to the individual devices which have requested
- * 	them to be applied.
- * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
- *	of an intersection between two regulatory domains -- the previously
- *	set regulatory domain on the system and the last accepted regulatory
- *	domain request to be processed.
- */
-enum nl80211_reg_type {
-	NL80211_REGDOM_TYPE_COUNTRY,
-	NL80211_REGDOM_TYPE_WORLD,
-	NL80211_REGDOM_TYPE_CUSTOM_WORLD,
-	NL80211_REGDOM_TYPE_INTERSECTION,
-};
-
-/**
- * enum nl80211_reg_rule_attr - regulatory rule attributes
- * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
- * 	considerations for a given frequency range. These are the
- * 	&enum nl80211_reg_rule_flags.
- * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
- * 	rule in KHz. This is not a center of frequency but an actual regulatory
- * 	band edge.
- * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
- * 	in KHz. This is not a center a frequency but an actual regulatory
- * 	band edge.
- * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
- * 	frequency range, in KHz.
- * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
- * 	for a given frequency range. The value is in mBi (100 * dBi).
- * 	If you don't have one then don't send this.
- * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
- * 	a given frequency range. The value is in mBm (100 * dBm).
- */
-enum nl80211_reg_rule_attr {
-	__NL80211_REG_RULE_ATTR_INVALID,
-	NL80211_ATTR_REG_RULE_FLAGS,
-
-	NL80211_ATTR_FREQ_RANGE_START,
-	NL80211_ATTR_FREQ_RANGE_END,
-	NL80211_ATTR_FREQ_RANGE_MAX_BW,
-
-	NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
-	NL80211_ATTR_POWER_RULE_MAX_EIRP,
-
-	/* keep last */
-	__NL80211_REG_RULE_ATTR_AFTER_LAST,
-	NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_reg_rule_flags - regulatory rule flags
- *
- * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
- * @NL80211_RRF_NO_CCK: CCK modulation not allowed
- * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
- * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
- * @NL80211_RRF_DFS: DFS support is required to be used
- * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
- * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
- * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
- * @NL80211_RRF_NO_IBSS: no IBSS is allowed
- */
-enum nl80211_reg_rule_flags {
-	NL80211_RRF_NO_OFDM		= 1<<0,
-	NL80211_RRF_NO_CCK		= 1<<1,
-	NL80211_RRF_NO_INDOOR		= 1<<2,
-	NL80211_RRF_NO_OUTDOOR		= 1<<3,
-	NL80211_RRF_DFS			= 1<<4,
-	NL80211_RRF_PTP_ONLY		= 1<<5,
-	NL80211_RRF_PTMP_ONLY		= 1<<6,
-	NL80211_RRF_PASSIVE_SCAN	= 1<<7,
-	NL80211_RRF_NO_IBSS		= 1<<8,
-};
-
-/**
- * enum nl80211_survey_info - survey information
- *
- * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
- * when getting information about a survey.
- *
- * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
- * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
- */
-enum nl80211_survey_info {
-	__NL80211_SURVEY_INFO_INVALID,
-	NL80211_SURVEY_INFO_FREQUENCY,
-	NL80211_SURVEY_INFO_NOISE,
-
-	/* keep last */
-	__NL80211_SURVEY_INFO_AFTER_LAST,
-	NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_mntr_flags - monitor configuration flags
- *
- * Monitor configuration flags.
- *
- * @__NL80211_MNTR_FLAG_INVALID: reserved
- *
- * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
- * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
- * @NL80211_MNTR_FLAG_CONTROL: pass control frames
- * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
- * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
- *	overrides all other flags.
- *
- * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
- * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
- */
-enum nl80211_mntr_flags {
-	__NL80211_MNTR_FLAG_INVALID,
-	NL80211_MNTR_FLAG_FCSFAIL,
-	NL80211_MNTR_FLAG_PLCPFAIL,
-	NL80211_MNTR_FLAG_CONTROL,
-	NL80211_MNTR_FLAG_OTHER_BSS,
-	NL80211_MNTR_FLAG_COOK_FRAMES,
-
-	/* keep last */
-	__NL80211_MNTR_FLAG_AFTER_LAST,
-	NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_meshconf_params - mesh configuration parameters
- *
- * Mesh configuration parameters
- *
- * @__NL80211_MESHCONF_INVALID: internal use
- *
- * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
- * millisecond units, used by the Peer Link Open message
- *
- * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
- * millisecond units, used by the peer link management to close a peer link
- *
- * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
- * millisecond units
- *
- * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
- * on this mesh interface
- *
- * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
- * open retries that can be sent to establish a new peer link instance in a
- * mesh
- *
- * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
- * point.
- *
- * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
- *
- * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
- * containing a PREQ that an MP can send to a particular destination (path
- * target)
- *
- * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
- * (in milliseconds)
- *
- * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
- * until giving up on a path discovery (in milliseconds)
- *
- * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
- * points receiving a PREQ shall consider the forwarding information from the
- * root to be valid. (TU = time unit)
- *
- * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
- * TUs) during which an MP can send only one action frame containing a PREQ
- * reference element
- *
- * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
- * that it takes for an HWMP information element to propagate across the mesh
- *
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
- *
- * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
- *
- * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
- */
-enum nl80211_meshconf_params {
-	__NL80211_MESHCONF_INVALID,
-	NL80211_MESHCONF_RETRY_TIMEOUT,
-	NL80211_MESHCONF_CONFIRM_TIMEOUT,
-	NL80211_MESHCONF_HOLDING_TIMEOUT,
-	NL80211_MESHCONF_MAX_PEER_LINKS,
-	NL80211_MESHCONF_MAX_RETRIES,
-	NL80211_MESHCONF_TTL,
-	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
-	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
-	NL80211_MESHCONF_PATH_REFRESH_TIME,
-	NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
-	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
-	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
-	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
-	NL80211_MESHCONF_HWMP_ROOTMODE,
-
-	/* keep last */
-	__NL80211_MESHCONF_ATTR_AFTER_LAST,
-	NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_txq_attr - TX queue parameter attributes
- * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
- * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
- * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
- *	disabled
- * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
- *	2^n-1 in the range 1..32767]
- * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
- *	2^n-1 in the range 1..32767]
- * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
- * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
- * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
- */
-enum nl80211_txq_attr {
-	__NL80211_TXQ_ATTR_INVALID,
-	NL80211_TXQ_ATTR_QUEUE,
-	NL80211_TXQ_ATTR_TXOP,
-	NL80211_TXQ_ATTR_CWMIN,
-	NL80211_TXQ_ATTR_CWMAX,
-	NL80211_TXQ_ATTR_AIFS,
-
-	/* keep last */
-	__NL80211_TXQ_ATTR_AFTER_LAST,
-	NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
-};
-
-enum nl80211_txq_q {
-	NL80211_TXQ_Q_VO,
-	NL80211_TXQ_Q_VI,
-	NL80211_TXQ_Q_BE,
-	NL80211_TXQ_Q_BK
-};
-
-enum nl80211_channel_type {
-	NL80211_CHAN_NO_HT,
-	NL80211_CHAN_HT20,
-	NL80211_CHAN_HT40MINUS,
-	NL80211_CHAN_HT40PLUS
-};
-
-/**
- * enum nl80211_bss - netlink attributes for a BSS
- *
- * @__NL80211_BSS_INVALID: invalid
- * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
- * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
- * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
- * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
- * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
- *	raw information elements from the probe response/beacon (bin);
- *	if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- *	from a Probe Response frame; otherwise they are from a Beacon frame.
- *	However, if the driver does not indicate the source of the IEs, these
- *	IEs may be from either frame subtype.
- * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
- *	in mBm (100 * dBm) (s32)
- * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
- *	in unspecified units, scaled to 0..100 (u8)
- * @NL80211_BSS_STATUS: status, if this BSS is "used"
- * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
- * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
- *	elements from a Beacon frame (bin); not present if no Beacon frame has
- *	yet been received
- * @__NL80211_BSS_AFTER_LAST: internal
- * @NL80211_BSS_MAX: highest BSS attribute
- */
-enum nl80211_bss {
-	__NL80211_BSS_INVALID,
-	NL80211_BSS_BSSID,
-	NL80211_BSS_FREQUENCY,
-	NL80211_BSS_TSF,
-	NL80211_BSS_BEACON_INTERVAL,
-	NL80211_BSS_CAPABILITY,
-	NL80211_BSS_INFORMATION_ELEMENTS,
-	NL80211_BSS_SIGNAL_MBM,
-	NL80211_BSS_SIGNAL_UNSPEC,
-	NL80211_BSS_STATUS,
-	NL80211_BSS_SEEN_MS_AGO,
-	NL80211_BSS_BEACON_IES,
-
-	/* keep last */
-	__NL80211_BSS_AFTER_LAST,
-	NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_bss_status - BSS "status"
- */
-enum nl80211_bss_status {
-	NL80211_BSS_STATUS_AUTHENTICATED,
-	NL80211_BSS_STATUS_ASSOCIATED,
-	NL80211_BSS_STATUS_IBSS_JOINED,
-};
-
-/**
- * enum nl80211_auth_type - AuthenticationType
- *
- * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
- * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
- * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
- * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
- * @__NL80211_AUTHTYPE_NUM: internal
- * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
- * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
- *	trying multiple times); this is invalid in netlink -- leave out
- *	the attribute for this on CONNECT commands.
- */
-enum nl80211_auth_type {
-	NL80211_AUTHTYPE_OPEN_SYSTEM,
-	NL80211_AUTHTYPE_SHARED_KEY,
-	NL80211_AUTHTYPE_FT,
-	NL80211_AUTHTYPE_NETWORK_EAP,
-
-	/* keep last */
-	__NL80211_AUTHTYPE_NUM,
-	NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
-	NL80211_AUTHTYPE_AUTOMATIC
-};
-
-/**
- * enum nl80211_key_type - Key Type
- * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
- * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
- * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
- */
-enum nl80211_key_type {
-	NL80211_KEYTYPE_GROUP,
-	NL80211_KEYTYPE_PAIRWISE,
-	NL80211_KEYTYPE_PEERKEY,
-};
-
-/**
- * enum nl80211_mfp - Management frame protection state
- * @NL80211_MFP_NO: Management frame protection not used
- * @NL80211_MFP_REQUIRED: Management frame protection required
- */
-enum nl80211_mfp {
-	NL80211_MFP_NO,
-	NL80211_MFP_REQUIRED,
-};
-
-enum nl80211_wpa_versions {
-	NL80211_WPA_VERSION_1 = 1 << 0,
-	NL80211_WPA_VERSION_2 = 1 << 1,
-};
-
-/**
- * enum nl80211_key_attributes - key attributes
- * @__NL80211_KEY_INVALID: invalid
- * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
- *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
- *	keys
- * @NL80211_KEY_IDX: key ID (u8, 0-3)
- * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
- *	section 7.3.2.25.1, e.g. 0x000FAC04)
- * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
- *	CCMP keys, each six bytes in little endian
- * @NL80211_KEY_DEFAULT: flag indicating default key
- * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
- * @__NL80211_KEY_AFTER_LAST: internal
- * @NL80211_KEY_MAX: highest key attribute
- */
-enum nl80211_key_attributes {
-	__NL80211_KEY_INVALID,
-	NL80211_KEY_DATA,
-	NL80211_KEY_IDX,
-	NL80211_KEY_CIPHER,
-	NL80211_KEY_SEQ,
-	NL80211_KEY_DEFAULT,
-	NL80211_KEY_DEFAULT_MGMT,
-
-	/* keep last */
-	__NL80211_KEY_AFTER_LAST,
-	NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_tx_rate_attributes - TX rate set attributes
- * @__NL80211_TXRATE_INVALID: invalid
- * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
- *	in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
- *	1 = 500 kbps) but without the IE length restriction (at most
- *	%NL80211_MAX_SUPP_RATES in a single array).
- * @__NL80211_TXRATE_AFTER_LAST: internal
- * @NL80211_TXRATE_MAX: highest TX rate attribute
- */
-enum nl80211_tx_rate_attributes {
-	__NL80211_TXRATE_INVALID,
-	NL80211_TXRATE_LEGACY,
-
-	/* keep last */
-	__NL80211_TXRATE_AFTER_LAST,
-	NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_band - Frequency band
- * @NL80211_BAND_2GHZ - 2.4 GHz ISM band
- * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
- */
-enum nl80211_band {
-	NL80211_BAND_2GHZ,
-	NL80211_BAND_5GHZ,
-};
-
-enum nl80211_ps_state {
-	NL80211_PS_DISABLED,
-	NL80211_PS_ENABLED,
-};
-
-/**
- * enum nl80211_attr_cqm - connection quality monitor attributes
- * @__NL80211_ATTR_CQM_INVALID: invalid
- * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
- *	the threshold for the RSSI level at which an event will be sent. Zero
- *	to disable.
- * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
- *	the minimum amount the RSSI level must change after an event before a
- *	new event may be issued (to reduce effects of RSSI oscillation).
- * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
- * @__NL80211_ATTR_CQM_AFTER_LAST: internal
- * @NL80211_ATTR_CQM_MAX: highest key attribute
- */
-enum nl80211_attr_cqm {
-	__NL80211_ATTR_CQM_INVALID,
-	NL80211_ATTR_CQM_RSSI_THOLD,
-	NL80211_ATTR_CQM_RSSI_HYST,
-	NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
-
-	/* keep last */
-	__NL80211_ATTR_CQM_AFTER_LAST,
-	NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
-};
-
-/**
- * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
- *      configured threshold
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
- *      configured threshold
- */
-enum nl80211_cqm_rssi_threshold_event {
-	NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-	NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-};
-
-#endif /* __LINUX_NL80211_H */

Copied: vendor/wpa/2.0/src/drivers/nl80211_copy.h (from rev 9639, vendor/wpa/dist/src/drivers/nl80211_copy.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/nl80211_copy.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/nl80211_copy.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3137 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006-2010 Johannes Berg <johannes at sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice at sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca at cozybit.com>
+ * Copyright 2008 Michael Buesch <m at bues.ch>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez at atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen at atheros.com>
+ * Copyright 2008 Colin McCabe <colin at cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ *       these registrations are ignored until the interface type is
+ *       changed again. This means that changing the interface type can
+ *       lead to a situation that couldn't otherwise be produced, but
+ *       any such registrations will be dormant in the sense that they
+ *       will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ *	to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ *	%NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ *	%NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ *	and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ *	However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
+ *	instead, the support here is for backward compatibility only.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ *	or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ *	%NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ *	on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ *	to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ *	be sent from userspace to request creation of a new virtual interface,
+ *	then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ *	%NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ *	userspace to request deletion of a virtual interface, then requires
+ *	attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ *	by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ *	%NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ *	%NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ *	and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ *	or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: (not used)
+ * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
+ *	using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
+ *	attributes. For drivers that generate the beacon and probe responses
+ *	internally, the following attributes must be provided: %NL80211_ATTR_IE,
+ *	%NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
+ * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
+ *	are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
+ *	do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
+ *	%NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
+ *	%NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ *	%NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ *	The channel to use can be set on the interface or be given using the
+ *	%NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
+ * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
+ * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ *	the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ *	or, if no MAC address given, all stations, on the interface identified
+ *	by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * 	destination %NL80211_ATTR_MAC on the interface identified by
+ * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
+ * 	destination %NL80211_ATTR_MAC on the interface identified by
+ * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ *	%NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ *	%NL80211_ATTR_MAC.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ *	the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ *	or, if no MAC address given, all mesh paths, on the interface identified
+ *	by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ *	%NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * 	regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ *	after being queried by the kernel. CRDA replies by sending a regulatory
+ *	domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ *	current alpha2 if it found a match. It also provides
+ * 	NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * 	regulatory rule is a nested set of attributes  given by
+ * 	%NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * 	%NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * 	to the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * 	store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
+ *	interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
+ *      interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ *	interface is identified with %NL80211_ATTR_IFINDEX and the management
+ *	frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ *	added to the end of the specified management frame is specified with
+ *	%NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ *	added to all specified management frames generated by
+ *	kernel/firmware/driver.
+ *	Note: This command has been removed and it is only reserved at this
+ *	point to avoid re-using existing command number. The functionality this
+ *	command was planned for has been provided with cleaner design with the
+ *	option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ *	NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ *	NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @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.
+ * @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.
+ *	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
+ *	string).  If no SSID is passed, no probe requests are sent and
+ *	a passive scan is performed.  %NL80211_ATTR_SCAN_FREQUENCIES,
+ *	if passed, define which channels should be scanned; if not
+ *	passed, all channels allowed for the current regulatory domain
+ *	are used.  Extra IEs can also be passed from the userspace by
+ *	using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
+ *	if scheduled scan is not running.
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ *	results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ *	stopped.  The driver may issue this event at any time during a
+ *	scheduled scan.  One reason for stopping the scan is if the hardware
+ *	does not support starting an association or a normal scan while running
+ *	a scheduled scan.  This event is also sent when the
+ *	%NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ *	is brought down while a scheduled scan was running.
+ *
+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ *      or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ *	NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *	(for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
+ *	(for the BSSID) and %NL80211_ATTR_PMKID.
+ * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ * 	has been changed and provides details of the request information
+ * 	that caused the change such as who initiated the regulatory request
+ * 	(%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * 	(%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * 	the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * 	%NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * 	set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * 	%NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * 	to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * 	has been found while world roaming thus enabling active scan or
+ * 	any mode of operation that initiates TX (beacons) on a channel
+ * 	where we would not have been able to do either before. As an example
+ * 	if you are world roaming (regulatory domain set to world or if your
+ * 	driver is using a custom world roaming regulatory domain) and while
+ * 	doing a passive scan on the 5 GHz band you find an AP there (if not
+ * 	on a DFS channel) you will now be able to actively scan for that AP
+ * 	or use AP mode on your card on that same channel. Note that this will
+ * 	never be used for channels 1-11 on the 2 GHz band as they are always
+ * 	enabled world wide. This beacon hint is only sent if your device had
+ * 	either disabled active scanning or beaconing on a channel. We send to
+ * 	userspace the wiphy on which we removed a restriction from
+ * 	(%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * 	before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * 	the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ *	This command is used both as a command (request to authenticate) and
+ *	as an event on the "mlme" multicast group indicating completion of the
+ *	authentication process.
+ *	When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ *	interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ *	BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ *	the SSID (mainly for association, but is included in authentication
+ *	request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ *	to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ *	is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ *	define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ *	to be added to the frame.
+ *	When used as an event, this reports reception of an Authentication
+ *	frame in station and IBSS modes when the local MLME processed the
+ *	frame, i.e., it was for the local STA and was received in correct
+ *	state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ *	MLME SAP interface (kernel providing MLME, userspace SME). The
+ *	included %NL80211_ATTR_FRAME attribute contains the management frame
+ *	(including both the header and frame body, but not FCS). This event is
+ *	also used to indicate if the authentication attempt timed out. In that
+ *	case the %NL80211_ATTR_FRAME attribute is replaced with a
+ *	%NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ *	pending authentication timed out).
+ * @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).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ *	NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ *	MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ *	primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ *	NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ *	MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ *	MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ *	event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ *	the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ *	type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ *	%NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ *	event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ *	FREQ attribute (for the initial frequency if no peer can be found)
+ *	and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ *	should be fixed rather than automatically determined. Can only be
+ *	executed on a network interface that is UP, and fixed BSSID/FREQ
+ *	may be rejected. Another optional parameter is the beacon interval,
+ *	given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ *	given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ *	determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ *	to identify the device, and the TESTDATA blob attribute to pass through
+ *	to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ *	requests to connect to a specified network but without separating
+ *	auth and assoc steps. For this, you need to specify the SSID in a
+ *	%NL80211_ATTR_SSID attribute, and can optionally specify the association
+ *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ *	%NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *	Background scan period can optionally be
+ *	specified in %NL80211_ATTR_BG_SCAN_PERIOD,
+ *	if not specified default background scan configuration
+ *	in driver is used and if period value is 0, bg scan will be disabled.
+ *	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.
+ * @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
+ *	userspace that a connection was dropped by the AP or due to other
+ *	reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ *	%NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ *	associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ *	channel for the specified amount of time. This can be used to do
+ *	off-channel operations like transmit a Public Action frame and wait for
+ *	a response while being associated to an AP on another channel.
+ *	%NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ *	radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *	frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ *	optionally used to specify additional channel parameters.
+ *	%NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ *	to remain on the channel. This command is also used as an event to
+ *	notify when the requested duration starts (it may take a while for the
+ *	driver to schedule this time due to other concurrent needs for the
+ *	radio).
+ *	When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ *	that will be included with any events pertaining to this request;
+ *	the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ *	pending remain-on-channel duration if the desired operation has been
+ *	completed prior to expiration of the originally requested duration.
+ *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ *	radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ *	uniquely identify the request.
+ *	This command is also used as an event to notify when a requested
+ *	remain-on-channel duration has expired.
+ *
+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
+ *	rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
+ *	and @NL80211_ATTR_TX_RATES the set of allowed rates.
+ *
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ *	(via @NL80211_CMD_FRAME) for processing in userspace. This command
+ *	requires an interface index, a frame type attribute (optional for
+ *	backward compatibility reasons, if not given assumes action frames)
+ *	and a match attribute containing the first few bytes of the frame
+ *	that should match, e.g. a single byte for only a category match or
+ *	four bytes for vendor frames including the OUI. The registration
+ *	cannot be dropped, but is removed automatically when the netlink
+ *	socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ *	backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ *	command is used both as a request to transmit a management frame and
+ *	as an event indicating reception of a frame that was not processed in
+ *	kernel code, but is for us (i.e., which may need to be processed in a
+ *	user space application). %NL80211_ATTR_FRAME is used to specify the
+ *	frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
+ *	optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
+ *	which channel the frame is to be transmitted or was received. If this
+ *	channel is not the current channel (remain-on-channel or the
+ *	operational channel) the device will switch to the given channel and
+ *	transmit the frame, optionally waiting for a response for the time
+ *	specified using %NL80211_ATTR_DURATION. When called, this operation
+ *	returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
+ *	TX status event pertaining to the TX request.
+ *	%NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *	management frames at CCK rate or not in 2GHz band.
+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
+ *	command may be used with the corresponding cookie to cancel the wait
+ *	time if it is known that it is no longer necessary.
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ *	transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
+ *	the TX command and %NL80211_ATTR_FRAME includes the contents of the
+ *	frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
+ *	the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ *	backward compatibility.
+ *
+ * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
+ * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
+ *
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
+ *	is used to configure connection quality monitoring notification trigger
+ *	levels.
+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
+ *	command is used as an event to indicate the that a trigger level was
+ *	reached.
+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
+ *	and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
+ *	by %NL80211_ATTR_IFINDEX) shall operate on.
+ *	In case multiple channels are supported by the device, the mechanism
+ *	with which it switches channels is implementation-defined.
+ *	When a monitor interface is given, it can only switch channel while
+ *	no other interfaces are operating to avoid disturbing the operation
+ *	of any other interfaces, and other interfaces will again take
+ *	precedence when they are used.
+ *
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
+ *	mesh config parameters may be given.
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ *	network is determined by the network interface.
+ *
+ * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame
+ *	notification. This event is used to indicate that an unprotected
+ *	deauthentication frame was dropped when MFP is in use.
+ * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame
+ *	notification. This event is used to indicate that an unprotected
+ *	disassociation frame was dropped when MFP is in use.
+ *
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ *      beacon or probe response from a compatible mesh peer.  This is only
+ *      sent while no station information (sta_info) exists for the new peer
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
+ *      reception of this notification, userspace may decide to create a new
+ *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      reoccurring, the userspace authentication daemon may want to create the
+ *      new station with the AUTHENTICATED flag unset and maybe change it later
+ *      depending on the authentication result.
+ *
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ *	Since wireless is more complex than wired ethernet, it supports
+ *	various triggers. These triggers can be configured through this
+ *	command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ *	more background information, see
+ *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *	the necessary information for supporting GTK rekey offload. This
+ *	feature is typically used during WoWLAN. The configuration data
+ *	is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *	contains the data in sub-attributes). After rekeying happened,
+ *	this command may also be sent by the driver as an MLME event to
+ *	inform userspace of the new replay counter.
+ *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ *	of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ *	In addition, this can be used as an event to request userspace to take
+ *	actions on TDLS links (set up a new link or tear down an existing one).
+ *	In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested
+ *	operation, %NL80211_ATTR_MAC contains the peer MAC address, and
+ *	%NL80211_ATTR_REASON_CODE the reason code to be used (only with
+ *	%NL80211_TDLS_TEARDOWN).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *	(or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *	implement sending deauth to stations that send unexpected class 3
+ *	frames. Also used as the event sent by the kernel when such a frame
+ *	is received.
+ *	For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *	other attributes like the interface index are present.
+ *	If used as the command it must have an interface index and you can
+ *	only unsubscribe from the event by closing the socket. Subscription
+ *	is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *	associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *	and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *	to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *	by sending a null data frame to it and reporting when the frame is
+ *	acknowleged. This is used to allow timing out inactive clients. Uses
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *	direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *	up the event with the request. The event includes the same data and
+ *	has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *	other BSSes when any interfaces are in AP mode. This helps implement
+ *	OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *	messages. Note that per PHY only one application may register.
+ *
+ * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
+ *      No Acknowledgement Policy should be applied.
+ *
+ * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
+ *	independently of the userspace SME, send this event indicating
+ *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
+ *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ *
+ * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
+ *	its %NL80211_ATTR_WDEV identifier. It must have been created with
+ *	%NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
+ *	P2P Device can be used for P2P operations, e.g. remain-on-channel and
+ *	public action frame TX.
+ * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
+ *	its %NL80211_ATTR_WDEV identifier.
+ *
+ * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to
+ *	notify userspace that AP has rejected the connection request from a
+ *	station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
+ *	is used for this.
+ *
+ * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
+ *	for IBSS or MESH vif.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything between, this is ABI! */
+	NL80211_CMD_UNSPEC,
+
+	NL80211_CMD_GET_WIPHY,		/* can dump */
+	NL80211_CMD_SET_WIPHY,
+	NL80211_CMD_NEW_WIPHY,
+	NL80211_CMD_DEL_WIPHY,
+
+	NL80211_CMD_GET_INTERFACE,	/* can dump */
+	NL80211_CMD_SET_INTERFACE,
+	NL80211_CMD_NEW_INTERFACE,
+	NL80211_CMD_DEL_INTERFACE,
+
+	NL80211_CMD_GET_KEY,
+	NL80211_CMD_SET_KEY,
+	NL80211_CMD_NEW_KEY,
+	NL80211_CMD_DEL_KEY,
+
+	NL80211_CMD_GET_BEACON,
+	NL80211_CMD_SET_BEACON,
+	NL80211_CMD_START_AP,
+	NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
+	NL80211_CMD_STOP_AP,
+	NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,
+
+	NL80211_CMD_GET_STATION,
+	NL80211_CMD_SET_STATION,
+	NL80211_CMD_NEW_STATION,
+	NL80211_CMD_DEL_STATION,
+
+	NL80211_CMD_GET_MPATH,
+	NL80211_CMD_SET_MPATH,
+	NL80211_CMD_NEW_MPATH,
+	NL80211_CMD_DEL_MPATH,
+
+	NL80211_CMD_SET_BSS,
+
+	NL80211_CMD_SET_REG,
+	NL80211_CMD_REQ_SET_REG,
+
+	NL80211_CMD_GET_MESH_CONFIG,
+	NL80211_CMD_SET_MESH_CONFIG,
+
+	NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+	NL80211_CMD_GET_REG,
+
+	NL80211_CMD_GET_SCAN,
+	NL80211_CMD_TRIGGER_SCAN,
+	NL80211_CMD_NEW_SCAN_RESULTS,
+	NL80211_CMD_SCAN_ABORTED,
+
+	NL80211_CMD_REG_CHANGE,
+
+	NL80211_CMD_AUTHENTICATE,
+	NL80211_CMD_ASSOCIATE,
+	NL80211_CMD_DEAUTHENTICATE,
+	NL80211_CMD_DISASSOCIATE,
+
+	NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+	NL80211_CMD_REG_BEACON_HINT,
+
+	NL80211_CMD_JOIN_IBSS,
+	NL80211_CMD_LEAVE_IBSS,
+
+	NL80211_CMD_TESTMODE,
+
+	NL80211_CMD_CONNECT,
+	NL80211_CMD_ROAM,
+	NL80211_CMD_DISCONNECT,
+
+	NL80211_CMD_SET_WIPHY_NETNS,
+
+	NL80211_CMD_GET_SURVEY,
+	NL80211_CMD_NEW_SURVEY_RESULTS,
+
+	NL80211_CMD_SET_PMKSA,
+	NL80211_CMD_DEL_PMKSA,
+	NL80211_CMD_FLUSH_PMKSA,
+
+	NL80211_CMD_REMAIN_ON_CHANNEL,
+	NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
+	NL80211_CMD_SET_TX_BITRATE_MASK,
+
+	NL80211_CMD_REGISTER_FRAME,
+	NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+	NL80211_CMD_FRAME,
+	NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+	NL80211_CMD_FRAME_TX_STATUS,
+	NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
+
+	NL80211_CMD_SET_POWER_SAVE,
+	NL80211_CMD_GET_POWER_SAVE,
+
+	NL80211_CMD_SET_CQM,
+	NL80211_CMD_NOTIFY_CQM,
+
+	NL80211_CMD_SET_CHANNEL,
+	NL80211_CMD_SET_WDS_PEER,
+
+	NL80211_CMD_FRAME_WAIT_CANCEL,
+
+	NL80211_CMD_JOIN_MESH,
+	NL80211_CMD_LEAVE_MESH,
+
+	NL80211_CMD_UNPROT_DEAUTHENTICATE,
+	NL80211_CMD_UNPROT_DISASSOCIATE,
+
+	NL80211_CMD_NEW_PEER_CANDIDATE,
+
+	NL80211_CMD_GET_WOWLAN,
+	NL80211_CMD_SET_WOWLAN,
+
+	NL80211_CMD_START_SCHED_SCAN,
+	NL80211_CMD_STOP_SCHED_SCAN,
+	NL80211_CMD_SCHED_SCAN_RESULTS,
+	NL80211_CMD_SCHED_SCAN_STOPPED,
+
+	NL80211_CMD_SET_REKEY_OFFLOAD,
+
+	NL80211_CMD_PMKSA_CANDIDATE,
+
+	NL80211_CMD_TDLS_OPER,
+	NL80211_CMD_TDLS_MGMT,
+
+	NL80211_CMD_UNEXPECTED_FRAME,
+
+	NL80211_CMD_PROBE_CLIENT,
+
+	NL80211_CMD_REGISTER_BEACONS,
+
+	NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
+	NL80211_CMD_SET_NOACK_MAP,
+
+	NL80211_CMD_CH_SWITCH_NOTIFY,
+
+	NL80211_CMD_START_P2P_DEVICE,
+	NL80211_CMD_STOP_P2P_DEVICE,
+
+	NL80211_CMD_CONN_FAILED,
+
+	NL80211_CMD_SET_MCAST_RATE,
+
+	/* add new commands above here */
+
+	/* used to define NL80211_CMD_MAX below */
+	__NL80211_CMD_AFTER_LAST,
+	NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+/* source-level API compatibility */
+#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
+#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ *	/sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *	NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ *		this attribute)
+ *	NL80211_CHAN_HT20 = HT20 only
+ *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ *	less than or equal to the RTS threshold; allowed range: 1..255;
+ *	dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ *	greater than the RTS threshold; allowed range: 1..255;
+ *	dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ *	length in octets for frames; allowed range: 256..8000, disable
+ *	fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ *	larger than or equal to this use RTS/CTS handshake); allowed range:
+ *	0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
+ *	section 7.3.2.9; dot11CoverageClass; u8
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices
+ *	that don't have a netdev (u64)
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key
+ * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the
+ *	default management key
+ * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or
+ *	other commands, indicates which pairwise cipher suites are used
+ * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or
+ *	other commands, indicates which group cipher suite is used
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *	&enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ *	IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ *	rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ *	to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ *	given for %NL80211_CMD_GET_STATION, nested attribute containing
+ *	info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ *	consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ *	&enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * 	current regulatory domain should be set to or is already set to.
+ * 	For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * 	to query the CRDA to retrieve one regulatory domain. This attribute can
+ * 	also be used by userspace to query the kernel for the currently set
+ * 	regulatory domain. We chose an alpha2 as that is also used by the
+ * 	IEEE-802.11d country information element to identify a country.
+ * 	Users can also simply ask the wireless core to set regulatory domain
+ * 	to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ *	rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ *	rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ *	association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *	supported interface types, each a flag attribute with the number
+ *	of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ *	%NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ *	%NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ *	a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ *	scan with a single scheduled scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ *	that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ *	elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ *	used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ *	scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ * 	currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ * 	set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ *	an array of command numbers (i.e. a mapping index to command number)
+ *	that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ *	and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ *	NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ *	represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ *	%NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ *	a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * 	due to considerations from a beacon hint. This attribute reflects
+ * 	the state of the channel _before_ the beacon hint processing. This
+ * 	attributes consists of a nested attribute containing
+ * 	NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * 	due to considerations from a beacon hint. This attribute reflects
+ * 	the state of the channel _after_ the beacon hint processing. This
+ * 	attributes consists of a nested attribute containing
+ * 	NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ *	cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ *	for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ *	is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ *	used for the association (&enum nl80211_mfp, represented as a u32);
+ *	this attribute can be used
+ *	with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ *	&struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ *	IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ *	station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ *	request, the driver will assume that the port is unauthorized until
+ *	authorized by user space. Otherwise, port is marked authorized by
+ *	default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *	ethertype that will be used for key negotiation. It can be
+ *	specified with the associate and connect commands. If it is not
+ *	specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *	attribute is also used as a flag in the wiphy information to
+ *	indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *	ethertype frames used for key negotiation must not be encrypted.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ *	We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ *	event was due to the AP disconnecting the station, and not due to
+ *	a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ *	event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ *	that protected APs should be used. This is also used with NEW_BEACON to
+ *	indicate that the BSS is to use protection.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ *	to indicate which unicast key ciphers will be used with the connection
+ *	(an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which group key cipher will be used with the connection (a
+ *	u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which WPA version(s) the AP we want to associate with is using
+ *	(a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ *	sent out by the card, for ROAM and successful CONNECT events.
+ * @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_KEY: key information in a nested attribute with
+ *	%NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *	and join_ibss(), key information is in a nested attribute each
+ *	with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ *	dumps. This number increases whenever the object list being
+ *	dumped changes, and as such userspace can verify that it has
+ *	obtained a complete and consistent snapshot by verifying that
+ *	all dump messages contain the same generation number. If it
+ *	changed then the list changed and the dump should be repeated
+ *	completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ *      the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ *      containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
+ * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
+ *	cache, a wiphy attribute.
+ *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that
+ *	specifies the maximum duration that can be requested with the
+ *	remain-on-channel operation, in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
+ * @NL80211_ATTR_TX_RATES: Nested set of attributes
+ *	(enum nl80211_tx_rate_attributes) describing TX rates per band. The
+ *	enum nl80211_band value is used as the index (nla_type() of the nested
+ *	data. If a band is not included, it will be configured to allow all
+ *	rates based on negotiated supported rates information. This attribute
+ *	is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ *
+ * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
+ *	at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ *	@NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ *	nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *	information about which frame types can be transmitted with
+ *	%NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ *	nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *	information about which frame types can be registered for RX.
+ *
+ * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
+ *	acknowledged by the recipient.
+ *
+ * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
+ *
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ *	nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ *	is requesting a local authentication/association state change without
+ *	invoking actual management frame exchange. This can be used with
+ *	NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ *	NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ *	connected to this BSS.
+ *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ *      &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ *      for non-automatic settings.
+ *
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ *	means support for per-station GTKs.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting.
+ *	This can be used to mask out antennas which are not attached or should
+ *	not be used for transmitting. If an antenna is not selected in this
+ *	bitmap the hardware is not allowed to transmit on this antenna.
+ *
+ *	Each bit represents one antenna, starting with antenna 1 at the first
+ *	bit. Depending on which antennas are selected in the bitmap, 802.11n
+ *	drivers can derive which chainmasks to use (if all antennas belonging to
+ *	a particular chain are disabled this chain should be disabled) and if
+ *	a chain has diversity antennas wether diversity should be used or not.
+ *	HT capabilities (STBC, TX Beamforming, Antenna selection) can be
+ *	derived from the available chains after applying the antenna mask.
+ *	Non-802.11n drivers can derive wether to use diversity or not.
+ *	Drivers may reject configurations or RX/TX mask combinations they cannot
+ *	support by returning -EINVAL.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving.
+ *	This can be used to mask out antennas which are not attached or should
+ *	not be used for receiving. If an antenna is not selected in this bitmap
+ *	the hardware should not be configured to receive on this antenna.
+ *	For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available
+ *	for configuration as TX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
+ *	for configuration as RX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
+ *
+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
+ *	transmitted on another channel when the channel given doesn't match
+ *	the current channel. If the current channel doesn't match and this
+ *	flag isn't set, the frame will be rejected. This is also used as an
+ *	nl80211 capability flag.
+ *
+ * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16)
+ *
+ * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
+ *	attributes, specifying what a key should be set as default as.
+ *	See &enum nl80211_key_default_types.
+ *
+ * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters.  These cannot be
+ *	changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ *	containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ *	allows auth frames in a mesh to be passed to userspace for processing via
+ *	the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ *	defined in &enum nl80211_plink_state. Used when userspace is
+ *	driving the peer link management state machine.
+ *	@NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
+ *	capabilities, the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ *	indicate which WoW triggers should be enabled. This is also
+ *	used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ *	triggers.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ *	cycles, in msecs.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ *	sets of attributes to match during scheduled scans.  Only BSSs
+ *	that match any of the sets will be reported.  These are
+ *	pass-thru filter rules.
+ *	For a match to succeed, the BSS must match all attributes of a
+ *	set.  Since not every hardware supports matching all types of
+ *	attributes, there is no guarantee that the reported BSSs are
+ *	fully complying with the match sets and userspace needs to be
+ *	able to ignore them by itself.
+ *	Thus, the implementation is somewhat hardware-dependent, but
+ *	this is only an optimization and the userspace application
+ *	needs to handle all the non-filtered results anyway.
+ *	If the match attributes don't make sense when combined with
+ *	the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ *	is included in the probe request, but the match attributes
+ *	will never let it go through), -EINVAL may be returned.
+ *	If ommited, no filtering is done.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ *	interface combinations. In each nested item, it contains attributes
+ *	defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ *	%NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ *	are managed in software: interfaces of these types aren't subject to
+ *	any restrictions in their number or combinations.
+ *
+ * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
+ *	nested array attribute containing an entry for each band, with the entry
+ *	being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
+ *	without the length restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ *	and Probe Response (when response to wildcard Probe Request); see
+ *	&enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ *	This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ *	provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ *	driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ *	Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ *	(Re)Association Response frames when the driver (or firmware) replies to
+ *	(Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *	of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ *	as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ *	roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *	candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *	for management frames transmission. In order to avoid p2p probe/action
+ *	frames are being transmitted at CCK rate in 2GHz band, the user space
+ *	applications use this attribute.
+ *	This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *	%NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *	request, link setup confirm, link teardown, etc.). Values are
+ *	described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *	TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *	&enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *	as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *	procedures should be performed by sending TDLS packets via
+ *	%NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *	used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *	that have AP support to indicate that they have the AP SME integrated
+ *	with support for the features listed in this attribute, see
+ *	&enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *	the driver to not wait for an acknowledgement. Note that due to this,
+ *	it will also not give a status callback nor return a cookie. This is
+ *	mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *	&enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *	requests while operating in AP-mode.
+ *	This attribute holds a bitmap of the supported protocols for
+ *	offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *	probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *	to be filled by the FW.
+ * @NL80211_ATTR_DISABLE_HT:  Force HT capable interfaces to disable
+ *      this feature.  Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
+ *      ATTR_HT_CAPABILITY to which attention should be paid.
+ *      Currently, only mac80211 NICs support this feature.
+ *      The values that may be configured are:
+ *       MCS rates, MAX-AMSDU, HT-20-40 and HT_CAP_SGI_40
+ *       AMPDU density and AMPDU factor.
+ *      All values are treated as suggestions and may be ignored
+ *      by the driver as required.  The actual values may be seen in
+ *      the station debugfs ht_caps file.
+ *
+ * @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country
+ *    abides to when initiating radiation on DFS channels. A country maps
+ *    to one DFS region.
+ *
+ * @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
+ *      up to 16 TIDs.
+ *
+ * @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
+ *	used by the drivers which has MLME in firmware and does not have support
+ *	to report per station tx/rx activity to free up the staion entry from
+ *	the list. This needs to be used when the driver advertises the
+ *	capability to timeout the stations.
+ *
+ * @NL80211_ATTR_RX_SIGNAL_DBM: signal strength in dBm (as a 32-bit int);
+ *	this attribute is (depending on the driver capabilities) added to
+ *	received frames indicated with %NL80211_CMD_FRAME.
+ *
+ * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
+ *      or 0 to disable background scan.
+ *
+ * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from
+ *	userspace. If unset it is assumed the hint comes directly from
+ *	a user. If set code could specify exactly what type of source
+ *	was used to provide the hint. For the different types of
+ *	allowed user regulatory hints see nl80211_user_reg_hint_type.
+ *
+ * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected
+ *	the connection request from a station. nl80211_connect_failed_reason
+ *	enum has different reasons of connection failure.
+ *
+ * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
+ *	with the Authentication transaction sequence number field.
+ *
+ * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
+ *	association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything between, this is ABI! */
+	NL80211_ATTR_UNSPEC,
+
+	NL80211_ATTR_WIPHY,
+	NL80211_ATTR_WIPHY_NAME,
+
+	NL80211_ATTR_IFINDEX,
+	NL80211_ATTR_IFNAME,
+	NL80211_ATTR_IFTYPE,
+
+	NL80211_ATTR_MAC,
+
+	NL80211_ATTR_KEY_DATA,
+	NL80211_ATTR_KEY_IDX,
+	NL80211_ATTR_KEY_CIPHER,
+	NL80211_ATTR_KEY_SEQ,
+	NL80211_ATTR_KEY_DEFAULT,
+
+	NL80211_ATTR_BEACON_INTERVAL,
+	NL80211_ATTR_DTIM_PERIOD,
+	NL80211_ATTR_BEACON_HEAD,
+	NL80211_ATTR_BEACON_TAIL,
+
+	NL80211_ATTR_STA_AID,
+	NL80211_ATTR_STA_FLAGS,
+	NL80211_ATTR_STA_LISTEN_INTERVAL,
+	NL80211_ATTR_STA_SUPPORTED_RATES,
+	NL80211_ATTR_STA_VLAN,
+	NL80211_ATTR_STA_INFO,
+
+	NL80211_ATTR_WIPHY_BANDS,
+
+	NL80211_ATTR_MNTR_FLAGS,
+
+	NL80211_ATTR_MESH_ID,
+	NL80211_ATTR_STA_PLINK_ACTION,
+	NL80211_ATTR_MPATH_NEXT_HOP,
+	NL80211_ATTR_MPATH_INFO,
+
+	NL80211_ATTR_BSS_CTS_PROT,
+	NL80211_ATTR_BSS_SHORT_PREAMBLE,
+	NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+	NL80211_ATTR_HT_CAPABILITY,
+
+	NL80211_ATTR_SUPPORTED_IFTYPES,
+
+	NL80211_ATTR_REG_ALPHA2,
+	NL80211_ATTR_REG_RULES,
+
+	NL80211_ATTR_MESH_CONFIG,
+
+	NL80211_ATTR_BSS_BASIC_RATES,
+
+	NL80211_ATTR_WIPHY_TXQ_PARAMS,
+	NL80211_ATTR_WIPHY_FREQ,
+	NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+	NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+	NL80211_ATTR_MGMT_SUBTYPE,
+	NL80211_ATTR_IE,
+
+	NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+	NL80211_ATTR_SCAN_FREQUENCIES,
+	NL80211_ATTR_SCAN_SSIDS,
+	NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+	NL80211_ATTR_BSS,
+
+	NL80211_ATTR_REG_INITIATOR,
+	NL80211_ATTR_REG_TYPE,
+
+	NL80211_ATTR_SUPPORTED_COMMANDS,
+
+	NL80211_ATTR_FRAME,
+	NL80211_ATTR_SSID,
+	NL80211_ATTR_AUTH_TYPE,
+	NL80211_ATTR_REASON_CODE,
+
+	NL80211_ATTR_KEY_TYPE,
+
+	NL80211_ATTR_MAX_SCAN_IE_LEN,
+	NL80211_ATTR_CIPHER_SUITES,
+
+	NL80211_ATTR_FREQ_BEFORE,
+	NL80211_ATTR_FREQ_AFTER,
+
+	NL80211_ATTR_FREQ_FIXED,
+
+
+	NL80211_ATTR_WIPHY_RETRY_SHORT,
+	NL80211_ATTR_WIPHY_RETRY_LONG,
+	NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+	NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+	NL80211_ATTR_TIMED_OUT,
+
+	NL80211_ATTR_USE_MFP,
+
+	NL80211_ATTR_STA_FLAGS2,
+
+	NL80211_ATTR_CONTROL_PORT,
+
+	NL80211_ATTR_TESTDATA,
+
+	NL80211_ATTR_PRIVACY,
+
+	NL80211_ATTR_DISCONNECTED_BY_AP,
+	NL80211_ATTR_STATUS_CODE,
+
+	NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+	NL80211_ATTR_CIPHER_SUITE_GROUP,
+	NL80211_ATTR_WPA_VERSIONS,
+	NL80211_ATTR_AKM_SUITES,
+
+	NL80211_ATTR_REQ_IE,
+	NL80211_ATTR_RESP_IE,
+
+	NL80211_ATTR_PREV_BSSID,
+
+	NL80211_ATTR_KEY,
+	NL80211_ATTR_KEYS,
+
+	NL80211_ATTR_PID,
+
+	NL80211_ATTR_4ADDR,
+
+	NL80211_ATTR_SURVEY_INFO,
+
+	NL80211_ATTR_PMKID,
+	NL80211_ATTR_MAX_NUM_PMKIDS,
+
+	NL80211_ATTR_DURATION,
+
+	NL80211_ATTR_COOKIE,
+
+	NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+
+	NL80211_ATTR_TX_RATES,
+
+	NL80211_ATTR_FRAME_MATCH,
+
+	NL80211_ATTR_ACK,
+
+	NL80211_ATTR_PS_STATE,
+
+	NL80211_ATTR_CQM,
+
+	NL80211_ATTR_LOCAL_STATE_CHANGE,
+
+	NL80211_ATTR_AP_ISOLATE,
+
+	NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+	NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
+	NL80211_ATTR_TX_FRAME_TYPES,
+	NL80211_ATTR_RX_FRAME_TYPES,
+	NL80211_ATTR_FRAME_TYPE,
+
+	NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+	NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
+	NL80211_ATTR_SUPPORT_IBSS_RSN,
+
+	NL80211_ATTR_WIPHY_ANTENNA_TX,
+	NL80211_ATTR_WIPHY_ANTENNA_RX,
+
+	NL80211_ATTR_MCAST_RATE,
+
+	NL80211_ATTR_OFFCHANNEL_TX_OK,
+
+	NL80211_ATTR_BSS_HT_OPMODE,
+
+	NL80211_ATTR_KEY_DEFAULT_TYPES,
+
+	NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+
+	NL80211_ATTR_MESH_SETUP,
+
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+
+	NL80211_ATTR_SUPPORT_MESH_AUTH,
+	NL80211_ATTR_STA_PLINK_STATE,
+
+	NL80211_ATTR_WOWLAN_TRIGGERS,
+	NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+	NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+	NL80211_ATTR_INTERFACE_COMBINATIONS,
+	NL80211_ATTR_SOFTWARE_IFTYPES,
+
+	NL80211_ATTR_REKEY_DATA,
+
+	NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+	NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+	NL80211_ATTR_SCAN_SUPP_RATES,
+
+	NL80211_ATTR_HIDDEN_SSID,
+
+	NL80211_ATTR_IE_PROBE_RESP,
+	NL80211_ATTR_IE_ASSOC_RESP,
+
+	NL80211_ATTR_STA_WME,
+	NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+	NL80211_ATTR_ROAM_SUPPORT,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH,
+	NL80211_ATTR_MAX_MATCH_SETS,
+
+	NL80211_ATTR_PMKSA_CANDIDATE,
+
+	NL80211_ATTR_TX_NO_CCK_RATE,
+
+	NL80211_ATTR_TDLS_ACTION,
+	NL80211_ATTR_TDLS_DIALOG_TOKEN,
+	NL80211_ATTR_TDLS_OPERATION,
+	NL80211_ATTR_TDLS_SUPPORT,
+	NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
+	NL80211_ATTR_DEVICE_AP_SME,
+
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+	NL80211_ATTR_FEATURE_FLAGS,
+
+	NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+	NL80211_ATTR_PROBE_RESP,
+
+	NL80211_ATTR_DFS_REGION,
+
+	NL80211_ATTR_DISABLE_HT,
+	NL80211_ATTR_HT_CAPABILITY_MASK,
+
+	NL80211_ATTR_NOACK_MAP,
+
+	NL80211_ATTR_INACTIVITY_TIMEOUT,
+
+	NL80211_ATTR_RX_SIGNAL_DBM,
+
+	NL80211_ATTR_BG_SCAN_PERIOD,
+
+	NL80211_ATTR_WDEV,
+
+	NL80211_ATTR_USER_REG_HINT_TYPE,
+
+	NL80211_ATTR_CONN_FAILED_REASON,
+
+	NL80211_ATTR_SAE_DATA,
+
+	NL80211_ATTR_VHT_CAPABILITY,
+
+	NL80211_ATTR_SCAN_FLAGS,
+
+	/* add attributes here, update the policy in nl80211.c */
+
+	__NL80211_ATTR_AFTER_LAST,
+	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+#define	NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+#define NL80211_MAX_SUPP_RATES			32
+#define NL80211_MAX_SUPP_HT_RATES		77
+#define NL80211_MAX_SUPP_REG_RULES		32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY	0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY	16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
+#define NL80211_HT_CAPABILITY_LEN		26
+#define NL80211_VHT_CAPABILITY_LEN		12
+
+#define NL80211_MAX_NR_CIPHER_SUITES		5
+#define NL80211_MAX_NR_AKM_SUITES		2
+
+#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME	10
+
+/* default RSSI threshold for scan results if none specified. */
+#define NL80211_SCAN_RSSI_THOLD_OFF		-300
+
+#define NL80211_CQM_TXE_MAX_INTVL		1800
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ *	are a bit special in that they must always be tied to a pre-existing
+ *	AP type interface.
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client
+ * @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
+ *	and therefore can't be created in the normal ways, use the
+ *	%NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
+ *	commands to create and destroy one
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @NUM_NL80211_IFTYPES: number of defined interface types
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+	NL80211_IFTYPE_UNSPECIFIED,
+	NL80211_IFTYPE_ADHOC,
+	NL80211_IFTYPE_STATION,
+	NL80211_IFTYPE_AP,
+	NL80211_IFTYPE_AP_VLAN,
+	NL80211_IFTYPE_WDS,
+	NL80211_IFTYPE_MONITOR,
+	NL80211_IFTYPE_MESH_POINT,
+	NL80211_IFTYPE_P2P_CLIENT,
+	NL80211_IFTYPE_P2P_GO,
+	NL80211_IFTYPE_P2P_DEVICE,
+
+	/* keep last */
+	NUM_NL80211_IFTYPES,
+	NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *	with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer -- this flag should
+ *	only be used in managed mode (even in the flags mask). Note that the
+ *	flag can't be changed, it is only valid while adding a station, and
+ *	attempts to change it will silently be ignored (rather than rejected
+ *	as errors.)
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
+ */
+enum nl80211_sta_flags {
+	__NL80211_STA_FLAG_INVALID,
+	NL80211_STA_FLAG_AUTHORIZED,
+	NL80211_STA_FLAG_SHORT_PREAMBLE,
+	NL80211_STA_FLAG_WME,
+	NL80211_STA_FLAG_MFP,
+	NL80211_STA_FLAG_AUTHENTICATED,
+	NL80211_STA_FLAG_TDLS_PEER,
+
+	/* keep last */
+	__NL80211_STA_FLAG_AFTER_LAST,
+	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+#define NL80211_STA_FLAG_MAX_OLD_API	NL80211_STA_FLAG_TDLS_PEER
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+	__u32 mask;
+	__u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ * There are 2 attributes for bitrate, a legacy one that represents
+ * a 16-bit value, and new one that represents a 32-bit value.
+ * If the rate value fits into 16 bit, both attributes are reported
+ * with the same value. If the rate is too high to fit into 16 bits
+ * (>6.5535Gbps) only 32-bit attribute is included.
+ * User space tools encouraged to use the 32-bit attribute and fall
+ * back to the 16-bit one for compatibility with older kernels.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+	__NL80211_RATE_INFO_INVALID,
+	NL80211_RATE_INFO_BITRATE,
+	NL80211_RATE_INFO_MCS,
+	NL80211_RATE_INFO_40_MHZ_WIDTH,
+	NL80211_RATE_INFO_SHORT_GI,
+	NL80211_RATE_INFO_BITRATE32,
+
+	/* keep last */
+	__NL80211_RATE_INFO_AFTER_LAST,
+	NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE:  whether short preamble is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME:  whether short slot time is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+	__NL80211_STA_BSS_PARAM_INVALID,
+	NL80211_STA_BSS_PARAM_CTS_PROT,
+	NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+	NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+	NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+	NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+	/* keep last */
+	__NL80211_STA_BSS_PARAM_AFTER_LAST,
+	NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * 	containing info as possible, see &enum nl80211_rate_info
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ *	station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ *	(see %enum nl80211_plink_state)
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
+ *	attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_bss_param
+ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
+ * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+enum nl80211_sta_info {
+	__NL80211_STA_INFO_INVALID,
+	NL80211_STA_INFO_INACTIVE_TIME,
+	NL80211_STA_INFO_RX_BYTES,
+	NL80211_STA_INFO_TX_BYTES,
+	NL80211_STA_INFO_LLID,
+	NL80211_STA_INFO_PLID,
+	NL80211_STA_INFO_PLINK_STATE,
+	NL80211_STA_INFO_SIGNAL,
+	NL80211_STA_INFO_TX_BITRATE,
+	NL80211_STA_INFO_RX_PACKETS,
+	NL80211_STA_INFO_TX_PACKETS,
+	NL80211_STA_INFO_TX_RETRIES,
+	NL80211_STA_INFO_TX_FAILED,
+	NL80211_STA_INFO_SIGNAL_AVG,
+	NL80211_STA_INFO_RX_BITRATE,
+	NL80211_STA_INFO_BSS_PARAM,
+	NL80211_STA_INFO_CONNECTED_TIME,
+	NL80211_STA_INFO_STA_FLAGS,
+	NL80211_STA_INFO_BEACON_LOSS,
+	NL80211_STA_INFO_T_OFFSET,
+
+	/* keep last */
+	__NL80211_STA_INFO_AFTER_LAST,
+	NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+	NL80211_MPATH_FLAG_ACTIVE =	1<<0,
+	NL80211_MPATH_FLAG_RESOLVING =	1<<1,
+	NL80211_MPATH_FLAG_SN_VALID =	1<<2,
+	NL80211_MPATH_FLAG_FIXED =	1<<3,
+	NL80211_MPATH_FLAG_RESOLVED =	1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
+ * 	&enum nl80211_mpath_flags;
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ *	currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_mpath_info {
+	__NL80211_MPATH_INFO_INVALID,
+	NL80211_MPATH_INFO_FRAME_QLEN,
+	NL80211_MPATH_INFO_SN,
+	NL80211_MPATH_INFO_METRIC,
+	NL80211_MPATH_INFO_EXPTIME,
+	NL80211_MPATH_INFO_FLAGS,
+	NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+	NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+	/* keep last */
+	__NL80211_MPATH_INFO_AFTER_LAST,
+	NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ *	an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ *	an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ *	defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
+ *	defined in 802.11ac
+ * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_attr {
+	__NL80211_BAND_ATTR_INVALID,
+	NL80211_BAND_ATTR_FREQS,
+	NL80211_BAND_ATTR_RATES,
+
+	NL80211_BAND_ATTR_HT_MCS_SET,
+	NL80211_BAND_ATTR_HT_CAPA,
+	NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+	NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+	NL80211_BAND_ATTR_VHT_MCS_SET,
+	NL80211_BAND_ATTR_VHT_CAPA,
+
+	/* keep last */
+	__NL80211_BAND_ATTR_AFTER_LAST,
+	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ *	regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ *	permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ *	(100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ *	currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_frequency_attr {
+	__NL80211_FREQUENCY_ATTR_INVALID,
+	NL80211_FREQUENCY_ATTR_FREQ,
+	NL80211_FREQUENCY_ATTR_DISABLED,
+	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+	NL80211_FREQUENCY_ATTR_NO_IBSS,
+	NL80211_FREQUENCY_ATTR_RADAR,
+	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+	/* keep last */
+	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
+	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ *	in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ *	currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_bitrate_attr {
+	__NL80211_BITRATE_ATTR_INVALID,
+	NL80211_BITRATE_ATTR_RATE,
+	NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+	/* keep last */
+	__NL80211_BITRATE_ATTR_AFTER_LAST,
+	NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ * 	regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * 	regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ * 	wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ * 	802.11 country information element with regulatory information it
+ * 	thinks we should consider. cfg80211 only processes the country
+ *	code from the IE, and relies on the regulatory domain information
+ *	structure passed by userspace (CRDA) from our wireless-regdb.
+ *	If a channel is enabled but the country code indicates it should
+ *	be disabled we disable the channel and re-enable it upon disassociation.
+ */
+enum nl80211_reg_initiator {
+	NL80211_REGDOM_SET_BY_CORE,
+	NL80211_REGDOM_SET_BY_USER,
+	NL80211_REGDOM_SET_BY_DRIVER,
+	NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ *	to a specific country. When this is set you can count on the
+ *	ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ * 	domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ * 	driver specific world regulatory domain. These do not apply system-wide
+ * 	and are only applicable to the individual devices which have requested
+ * 	them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ *	of an intersection between two regulatory domains -- the previously
+ *	set regulatory domain on the system and the last accepted regulatory
+ *	domain request to be processed.
+ */
+enum nl80211_reg_type {
+	NL80211_REGDOM_TYPE_COUNTRY,
+	NL80211_REGDOM_TYPE_WORLD,
+	NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+	NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * 	considerations for a given frequency range. These are the
+ * 	&enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * 	rule in KHz. This is not a center of frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * 	in KHz. This is not a center a frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * 	frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * 	for a given frequency range. The value is in mBi (100 * dBi).
+ * 	If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * 	a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ *	currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_reg_rule_attr {
+	__NL80211_REG_RULE_ATTR_INVALID,
+	NL80211_ATTR_REG_RULE_FLAGS,
+
+	NL80211_ATTR_FREQ_RANGE_START,
+	NL80211_ATTR_FREQ_RANGE_END,
+	NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+	NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+	NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+	/* keep last */
+	__NL80211_REG_RULE_ATTR_AFTER_LAST,
+	NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
+ *	BSS in scan results. Filtering is turned off if not specified.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ *	attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+	__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+	NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+	NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+
+	/* keep last */
+	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+	NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+		__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/* only for backward compatibility */
+#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+	NL80211_RRF_NO_OFDM		= 1<<0,
+	NL80211_RRF_NO_CCK		= 1<<1,
+	NL80211_RRF_NO_INDOOR		= 1<<2,
+	NL80211_RRF_NO_OUTDOOR		= 1<<3,
+	NL80211_RRF_DFS			= 1<<4,
+	NL80211_RRF_PTP_ONLY		= 1<<5,
+	NL80211_RRF_PTMP_ONLY		= 1<<6,
+	NL80211_RRF_PASSIVE_SCAN	= 1<<7,
+	NL80211_RRF_NO_IBSS		= 1<<8,
+};
+
+/**
+ * enum nl80211_dfs_regions - regulatory DFS regions
+ *
+ * @NL80211_DFS_UNSET: Country has no DFS master region specified
+ * @NL80211_DFS_FCC: Country follows DFS master rules from FCC
+ * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI
+ * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec
+ */
+enum nl80211_dfs_regions {
+	NL80211_DFS_UNSET	= 0,
+	NL80211_DFS_FCC		= 1,
+	NL80211_DFS_ETSI	= 2,
+	NL80211_DFS_JP		= 3,
+};
+
+/**
+ * enum nl80211_user_reg_hint_type - type of user regulatory hint
+ *
+ * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always
+ *	assumed if the attribute is not set.
+ * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular
+ *	base station. Device drivers that have been tested to work
+ *	properly to support this type of hint can enable these hints
+ *	by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature
+ *	capability on the struct wiphy. The wireless core will
+ *	ignore all cell base station hints until at least one device
+ *	present has been registered with the wireless core that
+ *	has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
+ *	supported feature.
+ */
+enum nl80211_user_reg_hint_type {
+	NL80211_USER_REG_HINT_USER	= 0,
+	NL80211_USER_REG_HINT_CELL_BASE = 1,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
+ *	spent on this channel
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ *	channel was sensed busy (either due to activity or energy detect)
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ *	channel was sensed busy
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
+ *	receiving data
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
+ *	transmitting data
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ *	currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_survey_info {
+	__NL80211_SURVEY_INFO_INVALID,
+	NL80211_SURVEY_INFO_FREQUENCY,
+	NL80211_SURVEY_INFO_NOISE,
+	NL80211_SURVEY_INFO_IN_USE,
+	NL80211_SURVEY_INFO_CHANNEL_TIME,
+	NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+	NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+	NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+	NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+
+	/* keep last */
+	__NL80211_SURVEY_INFO_AFTER_LAST,
+	NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *	overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+	__NL80211_MNTR_FLAG_INVALID,
+	NL80211_MNTR_FLAG_FCSFAIL,
+	NL80211_MNTR_FLAG_PLCPFAIL,
+	NL80211_MNTR_FLAG_CONTROL,
+	NL80211_MNTR_FLAG_OTHER_BSS,
+	NL80211_MNTR_FLAG_COOK_FRAMES,
+
+	/* keep last */
+	__NL80211_MNTR_FLAG_AFTER_LAST,
+	NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters. These can be changed while the mesh is
+ * active.
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ *	millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
+ *	millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ *	millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ *	on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ *	open retries that can be sent to establish a new peer link instance in a
+ *	mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ *	point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ *	open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ *	containing a PREQ that an MP can send to a particular destination (path
+ *	target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ *	(in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ *	until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ *	points receiving a PREQ shall consider the forwarding information from
+ *	the root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ *	TUs) during which an MP can send only one action frame containing a PREQ
+ *	reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ *	that it takes for an HWMP information element to propagate across the
+ *	mesh
+ *
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ *	source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
+ *	root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ *	access to a broader network beyond the MBSS.  This is done via Root
+ *	Announcement frames.
+ *
+ * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in
+ *	TUs) during which a mesh STA can send only one Action frame containing a
+ *	PERR element.
+ *
+ * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding
+ *	or forwarding entity (default is TRUE - forwarding entity)
+ *
+ * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the
+ *	threshold for average signal strength of candidate station to establish
+ *	a peer link.
+ *
+ * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors
+ *	to synchronize to for 11s default synchronization method
+ *	(see 11C.12.2.2)
+ *
+ * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode.
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for
+ *	which mesh STAs receiving a proactive PREQ shall consider the forwarding
+ *	information to the root mesh STA to be valid.
+ *
+ * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between
+ *	proactive PREQs are transmitted.
+ *
+ * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time
+ *	(in TUs) during which a mesh STA can send only one Action frame
+ *	containing a PREQ element for root path confirmation.
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+	__NL80211_MESHCONF_INVALID,
+	NL80211_MESHCONF_RETRY_TIMEOUT,
+	NL80211_MESHCONF_CONFIRM_TIMEOUT,
+	NL80211_MESHCONF_HOLDING_TIMEOUT,
+	NL80211_MESHCONF_MAX_PEER_LINKS,
+	NL80211_MESHCONF_MAX_RETRIES,
+	NL80211_MESHCONF_TTL,
+	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+	NL80211_MESHCONF_PATH_REFRESH_TIME,
+	NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+	NL80211_MESHCONF_HWMP_ROOTMODE,
+	NL80211_MESHCONF_ELEMENT_TTL,
+	NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+	NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+	NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
+	NL80211_MESHCONF_FORWARDING,
+	NL80211_MESHCONF_RSSI_THRESHOLD,
+	NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
+	NL80211_MESHCONF_HT_OPMODE,
+	NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
+	NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
+	NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+
+	/* keep last */
+	__NL80211_MESHCONF_ATTR_AFTER_LAST,
+	NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mesh_setup_params - mesh setup parameters
+ *
+ * Mesh setup parameters.  These are used to start/join a mesh and cannot be
+ * changed while the mesh is active.
+ *
+ * @__NL80211_MESH_SETUP_INVALID: Internal use
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
+ *	vendor specific path selection algorithm or disable it to use the
+ *	default HWMP.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
+ *	vendor specific path metric or disable it to use the default Airtime
+ *	metric.
+ *
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ *	robust security network ie, or a vendor specific information element
+ *	that vendors will use to identify the path selection methods and
+ *	metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ *	daemon will be authenticating mesh candidates.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ *	daemon will be securing peer link frames.  AMPE is a secured version of
+ *	Mesh Peering Management (MPM) and is implemented with the assistance of
+ *	a userspace daemon.  When this flag is set, the kernel will send peer
+ *	management frames to a userspace daemon that will implement AMPE
+ *	functionality (security capabilities selection, key confirmation, and
+ *	key management).  When the flag is unset (default), the kernel can
+ *	autonomously complete (unsecured) mesh peering without the need of a
+ *	userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a
+ *	vendor specific synchronization method or disable it to use the default
+ *	neighbor offset synchronization
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ *
+ * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
+ */
+enum nl80211_mesh_setup_params {
+	__NL80211_MESH_SETUP_INVALID,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
+	NL80211_MESH_SETUP_IE,
+	NL80211_MESH_SETUP_USERSPACE_AUTH,
+	NL80211_MESH_SETUP_USERSPACE_AMPE,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
+
+	/* keep last */
+	__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
+	NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_AC: AC identifier (NL80211_AC_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ *	disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+	__NL80211_TXQ_ATTR_INVALID,
+	NL80211_TXQ_ATTR_AC,
+	NL80211_TXQ_ATTR_TXOP,
+	NL80211_TXQ_ATTR_CWMIN,
+	NL80211_TXQ_ATTR_CWMAX,
+	NL80211_TXQ_ATTR_AIFS,
+
+	/* keep last */
+	__NL80211_TXQ_ATTR_AFTER_LAST,
+	NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_ac {
+	NL80211_AC_VO,
+	NL80211_AC_VI,
+	NL80211_AC_BE,
+	NL80211_AC_BK,
+	NL80211_NUM_ACS
+};
+
+/* backward compat */
+#define NL80211_TXQ_ATTR_QUEUE	NL80211_TXQ_ATTR_AC
+#define NL80211_TXQ_Q_VO	NL80211_AC_VO
+#define NL80211_TXQ_Q_VI	NL80211_AC_VI
+#define NL80211_TXQ_Q_BE	NL80211_AC_BE
+#define NL80211_TXQ_Q_BK	NL80211_AC_BK
+
+enum nl80211_channel_type {
+	NL80211_CHAN_NO_HT,
+	NL80211_CHAN_HT20,
+	NL80211_CHAN_HT40MINUS,
+	NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ *	raw information elements from the probe response/beacon (bin);
+ *	if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
+ *	from a Probe Response frame; otherwise they are from a Beacon frame.
+ *	However, if the driver does not indicate the source of the IEs, these
+ *	IEs may be from either frame subtype.
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ *	in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ *	in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
+ *	elements from a Beacon frame (bin); not present if no Beacon frame has
+ *	yet been received
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+	__NL80211_BSS_INVALID,
+	NL80211_BSS_BSSID,
+	NL80211_BSS_FREQUENCY,
+	NL80211_BSS_TSF,
+	NL80211_BSS_BEACON_INTERVAL,
+	NL80211_BSS_CAPABILITY,
+	NL80211_BSS_INFORMATION_ELEMENTS,
+	NL80211_BSS_SIGNAL_MBM,
+	NL80211_BSS_SIGNAL_UNSPEC,
+	NL80211_BSS_STATUS,
+	NL80211_BSS_SEEN_MS_AGO,
+	NL80211_BSS_BEACON_IES,
+
+	/* keep last */
+	__NL80211_BSS_AFTER_LAST,
+	NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
+ */
+enum nl80211_bss_status {
+	NL80211_BSS_STATUS_AUTHENTICATED,
+	NL80211_BSS_STATUS_ASSOCIATED,
+	NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ *	trying multiple times); this is invalid in netlink -- leave out
+ *	the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+	NL80211_AUTHTYPE_OPEN_SYSTEM,
+	NL80211_AUTHTYPE_SHARED_KEY,
+	NL80211_AUTHTYPE_FT,
+	NL80211_AUTHTYPE_NETWORK_EAP,
+	NL80211_AUTHTYPE_SAE,
+
+	/* keep last */
+	__NL80211_AUTHTYPE_NUM,
+	NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+	NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
+ */
+enum nl80211_key_type {
+	NL80211_KEYTYPE_GROUP,
+	NL80211_KEYTYPE_PAIRWISE,
+	NL80211_KEYTYPE_PEERKEY,
+
+	NUM_NL80211_KEYTYPES
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+	NL80211_MFP_NO,
+	NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+	NL80211_WPA_VERSION_1 = 1 << 0,
+	NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_default_types - key default types
+ * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid
+ * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default
+ *	unicast key
+ * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default
+ *	multicast key
+ * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types
+ */
+enum nl80211_key_default_types {
+	__NL80211_KEY_DEFAULT_TYPE_INVALID,
+	NL80211_KEY_DEFAULT_TYPE_UNICAST,
+	NL80211_KEY_DEFAULT_TYPE_MULTICAST,
+
+	NUM_NL80211_KEY_DEFAULT_TYPES
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ *	specified the default depends on whether a MAC address was
+ *	given with the command using the key or not (u32)
+ * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
+ *	attributes, specifying what a key should be set as default as.
+ *	See &enum nl80211_key_default_types.
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+	__NL80211_KEY_INVALID,
+	NL80211_KEY_DATA,
+	NL80211_KEY_IDX,
+	NL80211_KEY_CIPHER,
+	NL80211_KEY_SEQ,
+	NL80211_KEY_DEFAULT,
+	NL80211_KEY_DEFAULT_MGMT,
+	NL80211_KEY_TYPE,
+	NL80211_KEY_DEFAULT_TYPES,
+
+	/* keep last */
+	__NL80211_KEY_AFTER_LAST,
+	NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_tx_rate_attributes - TX rate set attributes
+ * @__NL80211_TXRATE_INVALID: invalid
+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
+ *	in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
+ *	1 = 500 kbps) but without the IE length restriction (at most
+ *	%NL80211_MAX_SUPP_RATES in a single array).
+ * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection
+ *	in an array of MCS numbers.
+ * @__NL80211_TXRATE_AFTER_LAST: internal
+ * @NL80211_TXRATE_MAX: highest TX rate attribute
+ */
+enum nl80211_tx_rate_attributes {
+	__NL80211_TXRATE_INVALID,
+	NL80211_TXRATE_LEGACY,
+	NL80211_TXRATE_MCS,
+
+	/* keep last */
+	__NL80211_TXRATE_AFTER_LAST,
+	NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band - Frequency band
+ * @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)
+ */
+enum nl80211_band {
+	NL80211_BAND_2GHZ,
+	NL80211_BAND_5GHZ,
+	NL80211_BAND_60GHZ,
+};
+
+/**
+ * enum nl80211_ps_state - powersave state
+ * @NL80211_PS_DISABLED: powersave is disabled
+ * @NL80211_PS_ENABLED: powersave is enabled
+ */
+enum nl80211_ps_state {
+	NL80211_PS_DISABLED,
+	NL80211_PS_ENABLED,
+};
+
+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ *	the threshold for the RSSI level at which an event will be sent. Zero
+ *	to disable.
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ *	the minimum amount the RSSI level must change after an event before a
+ *	new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
+ *	consecutive packets were not acknowledged by the peer
+ * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures
+ *	during the given %NL80211_ATTR_CQM_TXE_INTVL before an
+ *	%NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and
+ *	%NL80211_ATTR_CQM_TXE_PKTS is generated.
+ * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given
+ *	%NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is
+ *	checked.
+ * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic
+ *	interval in which %NL80211_ATTR_CQM_TXE_PKTS and
+ *	%NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
+ *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+	__NL80211_ATTR_CQM_INVALID,
+	NL80211_ATTR_CQM_RSSI_THOLD,
+	NL80211_ATTR_CQM_RSSI_HYST,
+	NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+	NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+	NL80211_ATTR_CQM_TXE_RATE,
+	NL80211_ATTR_CQM_TXE_PKTS,
+	NL80211_ATTR_CQM_TXE_INTVL,
+
+	/* keep last */
+	__NL80211_ATTR_CQM_AFTER_LAST,
+	NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
+ *      configured threshold
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
+ *      configured threshold
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
+ *	(Note that deauth/disassoc will still follow if the AP is not
+ *	available. This event might get used as roaming event, etc.)
+ */
+enum nl80211_cqm_rssi_threshold_event {
+	NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+	NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+	NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+};
+
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+	NL80211_TX_POWER_AUTOMATIC,
+	NL80211_TX_POWER_LIMITED,
+	NL80211_TX_POWER_FIXED,
+};
+
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ *	a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ *	a bit for each byte in the pattern. The lowest-order bit corresponds
+ *	to the first byte of the pattern, but the bytes of the pattern are
+ *	in a little-endian-like format, i.e. the 9th byte of the pattern
+ *	corresponds to the lowest-order bit in the second byte of the mask.
+ *	For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ *	xx indicates "don't care") would be represented by a pattern of
+ *	twelve zero bytes, and a mask of "0xed,0x07".
+ *	Note that the pattern matching is done as though frames were not
+ *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ *	first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+	__NL80211_WOWLAN_PKTPAT_INVALID,
+	NL80211_WOWLAN_PKTPAT_MASK,
+	NL80211_WOWLAN_PKTPAT_PATTERN,
+
+	NUM_NL80211_WOWLAN_PKTPAT,
+	MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+	__u32 max_patterns;
+	__u32 min_pattern_len;
+	__u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ *	the chip into a special state -- works best with chips that have
+ *	support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ *	is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ *	by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ *	which are passed in an array of nested attributes, each nested attribute
+ *	defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ *	Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ *	i.e. as though the packet was an 802.3 packet, so the pattern matching
+ *	is done after the packet is converted to the MSDU.
+ *
+ *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ *	carrying a &struct nl80211_wowlan_pattern_support.
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
+ *	used when setting, used only to indicate that GTK rekeying is supported
+ *	by the device (flag)
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if
+ *	done by the device) (flag)
+ * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request
+ *	packet (flag)
+ * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
+ * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
+ *	(on devices that have rfkill in the device) (flag)
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+	__NL80211_WOWLAN_TRIG_INVALID,
+	NL80211_WOWLAN_TRIG_ANY,
+	NL80211_WOWLAN_TRIG_DISCONNECT,
+	NL80211_WOWLAN_TRIG_MAGIC_PKT,
+	NL80211_WOWLAN_TRIG_PKT_PATTERN,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE,
+	NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
+	NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
+	NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+
+	/* keep last */
+	NUM_NL80211_WOWLAN_TRIG,
+	MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ *	can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ *	flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+	NL80211_IFACE_LIMIT_UNSPEC,
+	NL80211_IFACE_LIMIT_MAX,
+	NL80211_IFACE_LIMIT_TYPES,
+
+	/* keep last */
+	NUM_NL80211_IFACE_LIMIT,
+	MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ *	for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ *	interfaces that can be created in this group. This number doesn't
+ *	apply to interfaces purely managed in software, which are listed
+ *	in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ *	beacon intervals within this group must be all the same even for
+ *	infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ *	the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ *	different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ *	limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ *	=> allows an AP and a STA that must match BIs
+ *
+ *	numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ *	=> allows 8 of AP/GO
+ *
+ *	numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ *	=> allows two STAs on different channels
+ *
+ *	numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ *	=> allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ *	numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+	NL80211_IFACE_COMB_UNSPEC,
+	NL80211_IFACE_COMB_LIMITS,
+	NL80211_IFACE_COMB_MAXNUM,
+	NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+	NL80211_IFACE_COMB_NUM_CHANNELS,
+
+	/* keep last */
+	NUM_NL80211_IFACE_COMB,
+	MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ *	state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ *	this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ *	from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ *	received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ *	plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+	NL80211_PLINK_LISTEN,
+	NL80211_PLINK_OPN_SNT,
+	NL80211_PLINK_OPN_RCVD,
+	NL80211_PLINK_CNF_RCVD,
+	NL80211_PLINK_ESTAB,
+	NL80211_PLINK_HOLDING,
+	NL80211_PLINK_BLOCKED,
+
+	/* keep last */
+	NUM_NL80211_PLINK_STATES,
+	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
+#define NL80211_KCK_LEN			16
+#define NL80211_KEK_LEN			16
+#define NL80211_REPLAY_CTR_LEN		8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+	__NL80211_REKEY_DATA_INVALID,
+	NL80211_REKEY_DATA_KEK,
+	NL80211_REKEY_DATA_KCK,
+	NL80211_REKEY_DATA_REPLAY_CTR,
+
+	/* keep last */
+	NUM_NL80211_REKEY_DATA,
+	MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ *	Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ *	in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ *	element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+	NL80211_HIDDEN_SSID_NOT_IN_USE,
+	NL80211_HIDDEN_SSID_ZERO_LEN,
+	NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ *	is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ *	as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+	__NL80211_STA_WME_INVALID,
+	NL80211_STA_WME_UAPSD_QUEUES,
+	NL80211_STA_WME_MAX_SP,
+
+	/* keep last */
+	__NL80211_STA_WME_AFTER_LAST,
+	NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ *	priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ *	(internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ *	(internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+	__NL80211_PMKSA_CANDIDATE_INVALID,
+	NL80211_PMKSA_CANDIDATE_INDEX,
+	NL80211_PMKSA_CANDIDATE_BSSID,
+	NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+	/* keep last */
+	NUM_NL80211_PMKSA_CANDIDATE,
+	MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+	NL80211_TDLS_DISCOVERY_REQ,
+	NL80211_TDLS_SETUP,
+	NL80211_TDLS_TEARDOWN,
+	NL80211_TDLS_ENABLE_LINK,
+	NL80211_TDLS_DISABLE_LINK,
+};
+
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *	TX status to the socket error queue when requested with the
+ *	socket option.
+ * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
+ * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
+ *	the connected inactive stations in AP mode.
+ * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
+ *	to work properly to suppport receiving regulatory hints from
+ *	cellular base stations.
+ * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
+ *	P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
+ *	in the interface combinations, even when it's only used for scan
+ *	and remain-on-channel. This could be due to, for example, the
+ *	remain-on-channel implementation requiring a channel context.
+ * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
+ *	equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
+ *	mode
+ * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
+ * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
+ * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
+ * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting
+ * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform
+ *	OBSS scans and generate 20/40 BSS coex reports. This flag is used only
+ *	for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied.
+ */
+enum nl80211_feature_flags {
+	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
+	NL80211_FEATURE_HT_IBSS				= 1 << 1,
+	NL80211_FEATURE_INACTIVITY_TIMER		= 1 << 2,
+	NL80211_FEATURE_CELL_BASE_REG_HINTS		= 1 << 3,
+	NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL	= 1 << 4,
+	NL80211_FEATURE_SAE				= 1 << 5,
+	NL80211_FEATURE_LOW_PRIORITY_SCAN		= 1 << 6,
+	NL80211_FEATURE_SCAN_FLUSH			= 1 << 7,
+	NL80211_FEATURE_AP_SCAN				= 1 << 8,
+	NL80211_FEATURE_VIF_TXPOWER			= 1 << 9,
+	NL80211_FEATURE_NEED_OBSS_SCAN			= 1 << 10,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *	protocols for probe-response offloading by the driver/FW.
+ *	To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *	Each enum value represents a bit in the bitmap of supported
+ *	protocols. Typically a subset of probe-requests belonging to a
+ *	supported protocol will be excluded from offload and uploaded
+ *	to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =	1<<0,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =	1<<1,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =	1<<2,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =	1<<3,
+};
+
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ *	handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist.
+ */
+enum nl80211_connect_failed_reason {
+	NL80211_CONN_FAIL_MAX_CLIENTS,
+	NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_scan_flags -  scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
+ * requests.
+ *
+ * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
+ * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
+ * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
+ *	as AP and the beaconing has already been configured. This attribute is
+ *	dangerous because will destroy stations performance as a lot of frames
+ *	will be lost while scanning off-channel, therefore it must be used only
+ *	when really needed
+ */
+enum nl80211_scan_flags {
+	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
+	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
+	NL80211_SCAN_FLAG_AP				= 1<<2,
+};
+
+#endif /* __LINUX_NL80211_H */

Deleted: vendor/wpa/2.0/src/drivers/priv_netlink.h
===================================================================
--- vendor/wpa/dist/src/drivers/priv_netlink.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/priv_netlink.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,113 +0,0 @@
-/*
- * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PRIV_NETLINK_H
-#define PRIV_NETLINK_H
-
-/*
- * This should be replaced with user space header once one is available with C
- * library, etc..
- */
-
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
-#endif
-#ifndef IFF_DORMANT
-#define IFF_DORMANT    0x20000         /* driver signals dormant       */
-#endif
-
-#ifndef IFLA_IFNAME
-#define IFLA_IFNAME 3
-#endif
-#ifndef IFLA_WIRELESS
-#define IFLA_WIRELESS 11
-#endif
-#ifndef IFLA_OPERSTATE
-#define IFLA_OPERSTATE 16
-#endif
-#ifndef IFLA_LINKMODE
-#define IFLA_LINKMODE 17
-#define IF_OPER_DORMANT 5
-#define IF_OPER_UP 6
-#endif
-
-#define NLM_F_REQUEST 1
-
-#define NETLINK_ROUTE 0
-#define RTMGRP_LINK 1
-#define RTM_BASE 0x10
-#define RTM_NEWLINK (RTM_BASE + 0)
-#define RTM_DELLINK (RTM_BASE + 1)
-#define RTM_SETLINK (RTM_BASE + 3)
-
-#define NLMSG_ALIGNTO 4
-#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
-#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
-#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
-#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
-			     (struct nlmsghdr *) \
-			     (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
-#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \
-			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
-			   (int) (nlh)->nlmsg_len <= (len))
-#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
-
-#define RTA_ALIGNTO 4
-#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
-#define RTA_OK(rta,len) \
-((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
-(rta)->rta_len <= (len))
-#define RTA_NEXT(rta,attrlen) \
-((attrlen) -= RTA_ALIGN((rta)->rta_len), \
-(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
-#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
-#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
-
-
-struct sockaddr_nl
-{
-	sa_family_t nl_family;
-	unsigned short nl_pad;
-	u32 nl_pid;
-	u32 nl_groups;
-};
-
-struct nlmsghdr
-{
-	u32 nlmsg_len;
-	u16 nlmsg_type;
-	u16 nlmsg_flags;
-	u32 nlmsg_seq;
-	u32 nlmsg_pid;
-};
-
-struct ifinfomsg
-{
-	unsigned char ifi_family;
-	unsigned char __ifi_pad;
-	unsigned short ifi_type;
-	int ifi_index;
-	unsigned ifi_flags;
-	unsigned ifi_change;
-};
-
-struct rtattr
-{
-	unsigned short rta_len;
-	unsigned short rta_type;
-};
-
-#endif /* PRIV_NETLINK_H */

Copied: vendor/wpa/2.0/src/drivers/priv_netlink.h (from rev 9639, vendor/wpa/dist/src/drivers/priv_netlink.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/priv_netlink.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/priv_netlink.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,107 @@
+/*
+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/*
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+#endif
+
+#ifndef IFLA_IFNAME
+#define IFLA_IFNAME 3
+#endif
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+#ifndef IFLA_OPERSTATE
+#define IFLA_OPERSTATE 16
+#endif
+#ifndef IFLA_LINKMODE
+#define IFLA_LINKMODE 17
+#define IF_OPER_DORMANT 5
+#define IF_OPER_UP 6
+#endif
+
+#define NLM_F_REQUEST 1
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+#define RTM_DELLINK (RTM_BASE + 1)
+#define RTM_SETLINK (RTM_BASE + 3)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+			     (struct nlmsghdr *) \
+			     (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \
+			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+			   (int) (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
+
+
+struct sockaddr_nl
+{
+	sa_family_t nl_family;
+	unsigned short nl_pad;
+	u32 nl_pid;
+	u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+	u32 nlmsg_len;
+	u16 nlmsg_type;
+	u16 nlmsg_flags;
+	u32 nlmsg_seq;
+	u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+	unsigned char ifi_family;
+	unsigned char __ifi_pad;
+	unsigned short ifi_type;
+	int ifi_index;
+	unsigned ifi_flags;
+	unsigned ifi_change;
+};
+
+struct rtattr
+{
+	unsigned short rta_len;
+	unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */

Copied: vendor/wpa/2.0/src/drivers/rfkill.c (from rev 9639, vendor/wpa/dist/src/drivers/rfkill.c)
===================================================================
--- vendor/wpa/2.0/src/drivers/rfkill.c	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/rfkill.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,188 @@
+/*
+ * Linux rfkill helper functions for driver wrappers
+ * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "rfkill.h"
+
+#define RFKILL_EVENT_SIZE_V1 8
+
+struct rfkill_event {
+	u32 idx;
+	u8 type;
+	u8 op;
+	u8 soft;
+	u8 hard;
+} STRUCT_PACKED;
+
+enum rfkill_operation {
+	RFKILL_OP_ADD = 0,
+	RFKILL_OP_DEL,
+	RFKILL_OP_CHANGE,
+	RFKILL_OP_CHANGE_ALL,
+};
+
+enum rfkill_type {
+	RFKILL_TYPE_ALL = 0,
+	RFKILL_TYPE_WLAN,
+	RFKILL_TYPE_BLUETOOTH,
+	RFKILL_TYPE_UWB,
+	RFKILL_TYPE_WIMAX,
+	RFKILL_TYPE_WWAN,
+	RFKILL_TYPE_GPS,
+	RFKILL_TYPE_FM,
+	NUM_RFKILL_TYPES,
+};
+
+
+struct rfkill_data {
+	struct rfkill_config *cfg;
+	int fd;
+	int blocked;
+};
+
+
+static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct rfkill_data *rfkill = eloop_ctx;
+	struct rfkill_event event;
+	ssize_t len;
+	int new_blocked;
+
+	len = read(rfkill->fd, &event, sizeof(event));
+	if (len < 0) {
+		wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+			   strerror(errno));
+		return;
+	}
+	if (len != RFKILL_EVENT_SIZE_V1) {
+		wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+			   "%d (expected %d)",
+			   (int) len, RFKILL_EVENT_SIZE_V1);
+		return;
+	}
+	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");
+		new_blocked = 1;
+	} else if (event.soft) {
+		wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+		new_blocked = 1;
+	} else {
+		wpa_printf(MSG_INFO, "rfkill: WLAN unblocked");
+		new_blocked = 0;
+	}
+
+	if (new_blocked != rfkill->blocked) {
+		rfkill->blocked = new_blocked;
+		if (new_blocked)
+			rfkill->cfg->blocked_cb(rfkill->cfg->ctx);
+		else
+			rfkill->cfg->unblocked_cb(rfkill->cfg->ctx);
+	}
+}
+
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
+{
+	struct rfkill_data *rfkill;
+	struct rfkill_event event;
+	ssize_t len;
+
+	rfkill = os_zalloc(sizeof(*rfkill));
+	if (rfkill == NULL)
+		return NULL;
+
+	rfkill->cfg = cfg;
+	rfkill->fd = open("/dev/rfkill", O_RDONLY);
+	if (rfkill->fd < 0) {
+		wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
+			   "device");
+		goto fail;
+	}
+
+	if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) {
+		wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: "
+			   "%s", strerror(errno));
+		goto fail2;
+	}
+
+	for (;;) {
+		len = read(rfkill->fd, &event, sizeof(event));
+		if (len < 0) {
+			if (errno == EAGAIN)
+				break; /* No more entries */
+			wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s",
+				   strerror(errno));
+			break;
+		}
+		if (len != RFKILL_EVENT_SIZE_V1) {
+			wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size "
+				   "%d (expected %d)",
+				   (int) len, RFKILL_EVENT_SIZE_V1);
+			continue;
+		}
+		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;
+		if (event.hard) {
+			wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked");
+			rfkill->blocked = 1;
+		} else if (event.soft) {
+			wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked");
+			rfkill->blocked = 1;
+		}
+	}
+
+	eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL);
+
+	return rfkill;
+
+fail2:
+	close(rfkill->fd);
+fail:
+	os_free(rfkill);
+	return NULL;
+}
+
+
+void rfkill_deinit(struct rfkill_data *rfkill)
+{
+	if (rfkill == NULL)
+		return;
+
+	if (rfkill->fd >= 0) {
+		eloop_unregister_read_sock(rfkill->fd);
+		close(rfkill->fd);
+	}
+
+	os_free(rfkill->cfg);
+	os_free(rfkill);
+}
+
+
+int rfkill_is_blocked(struct rfkill_data *rfkill)
+{
+	if (rfkill == NULL)
+		return 0;
+
+	return rfkill->blocked;
+}

Copied: vendor/wpa/2.0/src/drivers/rfkill.h (from rev 9639, vendor/wpa/dist/src/drivers/rfkill.h)
===================================================================
--- vendor/wpa/2.0/src/drivers/rfkill.h	                        (rev 0)
+++ vendor/wpa/2.0/src/drivers/rfkill.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,25 @@
+/*
+ * Linux rfkill helper functions for driver wrappers
+ * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RFKILL_H
+#define RFKILL_H
+
+struct rfkill_data;
+
+struct rfkill_config {
+	void *ctx;
+	char ifname[IFNAMSIZ];
+	void (*blocked_cb)(void *ctx);
+	void (*unblocked_cb)(void *ctx);
+};
+
+struct rfkill_data * rfkill_init(struct rfkill_config *cfg);
+void rfkill_deinit(struct rfkill_data *rfkill);
+int rfkill_is_blocked(struct rfkill_data *rfkill);
+
+#endif /* RFKILL_H */

Deleted: vendor/wpa/2.0/src/drivers/wireless_copy.h
===================================================================
--- vendor/wpa/dist/src/drivers/wireless_copy.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/drivers/wireless_copy.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1099 +0,0 @@
-/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 18.
- * I have just removed kernel related headers and added some typedefs etc. to
- * make this easier to include into user space programs.
- * Jouni Malinen, 2005-03-12.
- */
-
-
-/*
- * This file define a set of standard wireless extensions
- *
- * Version :	19	18.3.05
- *
- * Authors :	Jean Tourrilhes - HPL - <jt at hpl.hp.com>
- * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
- */
-
-#ifndef _LINUX_WIRELESS_H
-#define _LINUX_WIRELESS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * Initial APIs (1996 -> onward) :
- * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
- * The entry /proc/net/wireless give statistics and information on the
- * driver.
- * This is better than having each driver having its entry because
- * its centralised and we may remove the driver module safely.
- *
- * Ioctl are used to configure the driver and issue commands.  This is
- * better than command line options of insmod because we may want to
- * change dynamically (while the driver is running) some parameters.
- *
- * The ioctl mechanimsm are copied from standard devices ioctl.
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
- *	# net/core/dev.c (two place + add include)
- *	# net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
- *	# net/core/dev.c (two other places)
- *	# include/linux/netdevice.h (one place)
- *	# include/linux/proc_fs.h (one place)
- *
- * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
- *	# include/net/iw_handler.h
- *
- * Note as well that /proc/net/wireless implementation has now moved in :
- *	# net/core/wireless.c
- *
- * Wireless Events (2002 -> onward) :
- * --------------------------------
- * Events are defined at the end of this file, and implemented in :
- *	# net/core/wireless.c
- *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
- *
- * These wireless extensions are not magic : each driver has to provide
- * support for them...
- *
- * IMPORTANT NOTE : As everything in the kernel, this is very much a
- * work in progress. Contact me if you have ideas of improvements...
- */
-
-/***************************** INCLUDES *****************************/
-
- /* jkm - replaced linux headers with C library headers, added typedefs */
-#if 0
-/* To minimise problems in user space, I might remove those headers
- * at some point. Jean II */
-#include <linux/types.h>		/* for "caddr_t" et al		*/
-#include <linux/socket.h>		/* for "struct sockaddr" et al	*/
-#include <linux/if.h>			/* for IFNAMSIZ and co... */
-#else
-#include <sys/types.h>
-#include <net/if.h>
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
-#ifndef __user
-#define __user
-#endif /* __user */
-#endif
-
-/***************************** VERSION *****************************/
-/*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
-#define WIRELESS_EXT	19
-
-/*
- * Changes :
- *
- * V2 to V3
- * --------
- *	Alan Cox start some incompatibles changes. I've integrated a bit more.
- *	- Encryption renamed to Encode to avoid US regulation problems
- *	- Frequency changed from float to struct to avoid problems on old 386
- *
- * V3 to V4
- * --------
- *	- Add sensitivity
- *
- * V4 to V5
- * --------
- *	- Missing encoding definitions in range
- *	- Access points stuff
- *
- * V5 to V6
- * --------
- *	- 802.11 support (ESSID ioctls)
- *
- * V6 to V7
- * --------
- *	- define IW_ESSID_MAX_SIZE and IW_MAX_AP
- *
- * V7 to V8
- * --------
- *	- Changed my e-mail address
- *	- More 802.11 support (nickname, rate, rts, frag)
- *	- List index in frequencies
- *
- * V8 to V9
- * --------
- *	- Support for 'mode of operation' (ad-hoc, managed...)
- *	- Support for unicast and multicast power saving
- *	- Change encoding to support larger tokens (>64 bits)
- *	- Updated iw_params (disable, flags) and use it for NWID
- *	- Extracted iw_point from iwreq for clarity
- *
- * V9 to V10
- * ---------
- *	- Add PM capability to range structure
- *	- Add PM modifier : MAX/MIN/RELATIVE
- *	- Add encoding option : IW_ENCODE_NOKEY
- *	- Add TxPower ioctls (work like TxRate)
- *
- * V10 to V11
- * ----------
- *	- Add WE version in range (help backward/forward compatibility)
- *	- Add retry ioctls (work like PM)
- *
- * V11 to V12
- * ----------
- *	- Add SIOCSIWSTATS to get /proc/net/wireless programatically
- *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- *	- Add new statistics (frag, retry, beacon)
- *	- Add average quality (for user space calibration)
- *
- * V12 to V13
- * ----------
- *	- Document creation of new driver API.
- *	- Extract union iwreq_data from struct iwreq (for new driver API).
- *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
- *
- * V13 to V14
- * ----------
- *	- Wireless Events support : define struct iw_event
- *	- Define additional specific event numbers
- *	- Add "addr" and "param" fields in union iwreq_data
- *	- AP scanning stuff (SIOCSIWSCAN and friends)
- *
- * V14 to V15
- * ----------
- *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
- *	- Make struct iw_freq signed (both m & e), add explicit padding
- *	- Add IWEVCUSTOM for driver specific event/scanning token
- *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
- *	- Add IW_TXPOW_RANGE for range of Tx Powers
- *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- *	- Add IW_MODE_MONITOR for passive monitor
- *
- * V15 to V16
- * ----------
- *	- Increase the number of bitrates in iw_range to 32 (for 802.11g)
- *	- Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
- *	- Reshuffle struct iw_range for increases, add filler
- *	- Increase IW_MAX_AP to 64 for driver returning a lot of addresses
- *	- Remove IW_MAX_GET_SPY because conflict with enhanced spy support
- *	- Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
- *	- Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- *
- * V16 to V17
- * ----------
- *	- Add flags to frequency -> auto/fixed
- *	- Document (struct iw_quality *)->updated, add new flags (INVALID)
- *	- Wireless Event capability in struct iw_range
- *	- Add support for relative TxPower (yick !)
- *
- * V17 to V18 (From Jouni Malinen <j at w1.fi>)
- * ----------
- *	- Add support for WPA/WPA2
- *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
- *	  SIOCGIWENCODEEXT)
- *	- Add SIOCSIWGENIE/SIOCGIWGENIE
- *	- Add SIOCSIWMLME
- *	- Add SIOCSIWPMKSA
- *	- Add struct iw_range bit field for supported encoding capabilities
- *	- Add optional scan request parameters for SIOCSIWSCAN
- *	- Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
- *	  related parameters (extensible up to 4096 parameter values)
- *	- Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
- *	  IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
- *
- * V18 to V19
- * ----------
- *	- Remove (struct iw_point *)->pointer from events and streams
- *	- Remove header includes to help user space
- *	- Increase IW_ENCODING_TOKEN_MAX from 32 to 64
- *	- Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
- *	- Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
- *	- Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
- */
-
-/**************************** CONSTANTS ****************************/
-
-/* -------------------------- IOCTL LIST -------------------------- */
-
-/* Wireless Identification */
-#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
-#define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
- * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
- * Don't put the name of your driver there, it's useless. */
-
-/* Basic operations */
-#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
-#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
-#define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
-#define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
-#define SIOCSIWMODE	0x8B06		/* set operation mode */
-#define SIOCGIWMODE	0x8B07		/* get operation mode */
-#define SIOCSIWSENS	0x8B08		/* set sensitivity (dBm) */
-#define SIOCGIWSENS	0x8B09		/* get sensitivity (dBm) */
-
-/* Informative stuff */
-#define SIOCSIWRANGE	0x8B0A		/* Unused */
-#define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
-#define SIOCSIWPRIV	0x8B0C		/* Unused */
-#define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
-#define SIOCSIWSTATS	0x8B0E		/* Unused */
-#define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
-/* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
-/* Spy support (statistics per MAC address - used for Mobile IP support) */
-#define SIOCSIWSPY	0x8B10		/* set spy addresses */
-#define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
-#define SIOCSIWTHRSPY	0x8B12		/* set spy threshold (spy event) */
-#define SIOCGIWTHRSPY	0x8B13		/* get spy threshold */
-
-/* Access Point manipulation */
-#define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
-#define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
-#define SIOCGIWSCAN	0x8B19		/* get scanning results */
-
-/* 802.11 specific support */
-#define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
-#define SIOCGIWESSID	0x8B1B		/* get ESSID */
-#define SIOCSIWNICKN	0x8B1C		/* set node name/nickname */
-#define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
-/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
- * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE... */
-
-/* Other parameters useful in 802.11 and some other devices */
-#define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
-#define SIOCGIWRATE	0x8B21		/* get default bit rate (bps) */
-#define SIOCSIWRTS	0x8B22		/* set RTS/CTS threshold (bytes) */
-#define SIOCGIWRTS	0x8B23		/* get RTS/CTS threshold (bytes) */
-#define SIOCSIWFRAG	0x8B24		/* set fragmentation thr (bytes) */
-#define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
-#define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
-#define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
-#define SIOCSIWRETRY	0x8B28		/* set retry limits and lifetime */
-#define SIOCGIWRETRY	0x8B29		/* get retry limits and lifetime */
-
-/* Encoding stuff (scrambling, hardware security, WEP...) */
-#define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
-#define SIOCGIWENCODE	0x8B2B		/* get encoding token & mode */
-/* Power saving stuff (power management, unicast and multicast) */
-#define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
-#define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
-
-/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
- * This ioctl uses struct iw_point and data buffer that includes IE id and len
- * fields. More than one IE may be included in the request. Setting the generic
- * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
- * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
- * are required to report the used IE as a wireless event, e.g., when
- * associating with an AP. */
-#define SIOCSIWGENIE	0x8B30		/* set generic IE */
-#define SIOCGIWGENIE	0x8B31		/* get generic IE */
-
-/* WPA : IEEE 802.11 MLME requests */
-#define SIOCSIWMLME	0x8B16		/* request MLME operation; uses
-					 * struct iw_mlme */
-/* WPA : Authentication mode parameters */
-#define SIOCSIWAUTH	0x8B32		/* set authentication mode params */
-#define SIOCGIWAUTH	0x8B33		/* get authentication mode params */
-
-/* WPA : Extended version of encoding configuration */
-#define SIOCSIWENCODEEXT 0x8B34		/* set encoding token & mode */
-#define SIOCGIWENCODEEXT 0x8B35		/* get encoding token & mode */
-
-/* WPA2 : PMKSA cache management */
-#define SIOCSIWPMKSA	0x8B36		/* PMKSA cache operation */
-
-/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
-
-/* These 32 ioctl are wireless device private, for 16 commands.
- * Each driver is free to use them for whatever purpose it chooses,
- * however the driver *must* export the description of those ioctls
- * with SIOCGIWPRIV and *must* use arguments as defined below.
- * If you don't follow those rules, DaveM is going to hate you (reason :
- * it make mixed 32/64bit operation impossible).
- */
-#define SIOCIWFIRSTPRIV	0x8BE0
-#define SIOCIWLASTPRIV	0x8BFF
-/* Previously, we were using SIOCDEVPRIVATE, but we now have our
- * separate range because of collisions with other tools such as
- * 'mii-tool'.
- * We now have 32 commands, so a bit more space ;-).
- * Also, all 'odd' commands are only usable by root and don't return the
- * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command). More details in iwpriv.c.
- * And I repeat : you are not forced to use them with iwpriv, but you
- * must be compliant with it.
- */
-
-/* ------------------------- IOCTL STUFF ------------------------- */
-
-/* The first and the last (range) */
-#define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	SIOCIWLASTPRIV		/* 0x8BFF */
-#define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
-
-/* Even : get (world access), odd : set (root access) */
-#define IW_IS_SET(cmd)	(!((cmd) & 0x1))
-#define IW_IS_GET(cmd)	((cmd) & 0x1)
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/* Those are *NOT* ioctls, do not issue request on them !!! */
-/* Most events use the same identifier as ioctl requests */
-
-#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
-#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
-#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
-#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
-#define IWEVGENIE	0x8C05		/* Generic IE (WPA, RSN, WMM, ..)
-					 * (scan results); This includes id and
-					 * length fields. One IWEVGENIE may
-					 * contain more than one IE. Scan
-					 * results may contain one or more
-					 * IWEVGENIE events. */
-#define IWEVMICHAELMICFAILURE 0x8C06	/* Michael MIC failure
-					 * (struct iw_michaelmicfailure)
-					 */
-#define IWEVASSOCREQIE	0x8C07		/* IEs used in (Re)Association Request.
-					 * The data includes id and length
-					 * fields and may contain more than one
-					 * IE. This event is required in
-					 * Managed mode if the driver
-					 * generates its own WPA/RSN IE. This
-					 * should be sent just before
-					 * IWEVREGISTERED event for the
-					 * association. */
-#define IWEVASSOCRESPIE	0x8C08		/* IEs used in (Re)Association
-					 * Response. The data includes id and
-					 * length fields and may contain more
-					 * than one IE. This may be sent
-					 * between IWEVASSOCREQIE and
-					 * IWEVREGISTERED events for the
-					 * association. */
-#define IWEVPMKIDCAND	0x8C09		/* PMKID candidate for RSN
-					 * pre-authentication
-					 * (struct iw_pmkid_cand) */
-
-#define IWEVFIRST	0x8C00
-#define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
-
-/* ------------------------- PRIVATE INFO ------------------------- */
-/*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
- * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
- */
-
-#define IW_PRIV_TYPE_MASK	0x7000	/* Type of arguments */
-#define IW_PRIV_TYPE_NONE	0x0000
-#define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
-#define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
-#define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
-#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
-
-#define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed number of args */
-
-#define IW_PRIV_SIZE_MASK	0x07FF	/* Max number of those args */
-
-/*
- * Note : if the number of args is fixed and the size < 16 octets,
- * instead of passing a pointer we will put args in the iwreq struct...
- */
-
-/* ----------------------- OTHER CONSTANTS ----------------------- */
-
-/* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES	32
-/* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
-/* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES		32
-
-/* Maximum tx powers in the range struct */
-#define IW_MAX_TXPOWER		8
-/* Note : if you more than 8 TXPowers, just set the max and min or
- * a few of them in the struct iw_range. */
-
-/* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
-
-/* Maximum of address that you may get in the
-   list of access points in range */
-#define IW_MAX_AP		64
-
-/* Maximum size of the ESSID and NICKN strings */
-#define IW_ESSID_MAX_SIZE	32
-
-/* Modes of operation */
-#define IW_MODE_AUTO	0	/* Let the driver decides */
-#define IW_MODE_ADHOC	1	/* Single cell network */
-#define IW_MODE_INFRA	2	/* Multi cell network, roaming, ... */
-#define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
-#define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
-#define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
-#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
-
-/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED	0x01	/* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED	0x02
-#define IW_QUAL_NOISE_UPDATED	0x04
-#define IW_QUAL_ALL_UPDATED	0x07
-#define IW_QUAL_DBM		0x08	/* Level + Noise are dBm */
-#define IW_QUAL_QUAL_INVALID	0x10	/* Driver doesn't provide value */
-#define IW_QUAL_LEVEL_INVALID	0x20
-#define IW_QUAL_NOISE_INVALID	0x40
-#define IW_QUAL_ALL_INVALID	0x70
-
-/* Frequency flags */
-#define IW_FREQ_AUTO		0x00	/* Let the driver decides */
-#define IW_FREQ_FIXED		0x01	/* Force a specific value */
-
-/* Maximum number of size of encoding token available
- * they are listed in the range structure */
-#define IW_MAX_ENCODING_SIZES	8
-
-/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX	64	/* 512 bits (for now) */
-
-/* Flags for encoding (along with the token) */
-#define IW_ENCODE_INDEX		0x00FF	/* Token index (if needed) */
-#define IW_ENCODE_FLAGS		0xFF00	/* Flags defined below */
-#define IW_ENCODE_MODE		0xF000	/* Modes defined below */
-#define IW_ENCODE_DISABLED	0x8000	/* Encoding disabled */
-#define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
-#define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
-#define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY		0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_TEMP		0x0400  /* Temporary key */
-
-/* Power management flags available (along with the value, if any) */
-#define IW_POWER_ON		0x0000	/* No details... */
-#define IW_POWER_TYPE		0xF000	/* Type of parameter */
-#define IW_POWER_PERIOD		0x1000	/* Value is a period/duration of  */
-#define IW_POWER_TIMEOUT	0x2000	/* Value is a timeout (to go asleep) */
-#define IW_POWER_MODE		0x0F00	/* Power Management mode */
-#define IW_POWER_UNICAST_R	0x0100	/* Receive only unicast messages */
-#define IW_POWER_MULTICAST_R	0x0200	/* Receive only multicast messages */
-#define IW_POWER_ALL_R		0x0300	/* Receive all messages though PM */
-#define IW_POWER_FORCE_S	0x0400	/* Force PM procedure for sending unicast */
-#define IW_POWER_REPEATER	0x0800	/* Repeat broadcast messages in PM period */
-#define IW_POWER_MODIFIER	0x000F	/* Modify a parameter */
-#define IW_POWER_MIN		0x0001	/* Value is a minimum  */
-#define IW_POWER_MAX		0x0002	/* Value is a maximum */
-#define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-
-/* Transmit Power flags available */
-#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
-#define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
-#define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
-#define IW_TXPOW_RELATIVE	0x0002	/* Value is in arbitrary units */
-#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
-
-/* Retry limits and lifetime flags available */
-#define IW_RETRY_ON		0x0000	/* No details... */
-#define IW_RETRY_TYPE		0xF000	/* Type of parameter */
-#define IW_RETRY_LIMIT		0x1000	/* Maximum number of retries*/
-#define IW_RETRY_LIFETIME	0x2000	/* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER	0x000F	/* Modify a parameter */
-#define IW_RETRY_MIN		0x0001	/* Value is a minimum  */
-#define IW_RETRY_MAX		0x0002	/* Value is a maximum */
-#define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-
-/* Scanning request flags */
-#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
-#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
-#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
-#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
-#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
-#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
-#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
-#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
-#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
-/* struct iw_scan_req scan_type */
-#define IW_SCAN_TYPE_ACTIVE 0
-#define IW_SCAN_TYPE_PASSIVE 1
-/* Maximum size of returned data */
-#define IW_SCAN_MAX_DATA	4096	/* In bytes */
-
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX		256	/* In bytes */
-
-/* Generic information element */
-#define IW_GENERIC_IE_MAX	1024
-
-/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
-#define IW_MLME_DEAUTH		0
-#define IW_MLME_DISASSOC	1
-
-/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
-#define IW_AUTH_INDEX		0x0FFF
-#define IW_AUTH_FLAGS		0xF000
-/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
- * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
- * parameter that is being set/get to; value will be read/written to
- * struct iw_param value field) */
-#define IW_AUTH_WPA_VERSION		0
-#define IW_AUTH_CIPHER_PAIRWISE		1
-#define IW_AUTH_CIPHER_GROUP		2
-#define IW_AUTH_KEY_MGMT		3
-#define IW_AUTH_TKIP_COUNTERMEASURES	4
-#define IW_AUTH_DROP_UNENCRYPTED	5
-#define IW_AUTH_80211_AUTH_ALG		6
-#define IW_AUTH_WPA_ENABLED		7
-#define IW_AUTH_RX_UNENCRYPTED_EAPOL	8
-#define IW_AUTH_ROAMING_CONTROL		9
-#define IW_AUTH_PRIVACY_INVOKED		10
-#define IW_AUTH_CIPHER_GROUP_MGMT	11
-#define IW_AUTH_MFP			12
-
-/* IW_AUTH_WPA_VERSION values (bit field) */
-#define IW_AUTH_WPA_VERSION_DISABLED	0x00000001
-#define IW_AUTH_WPA_VERSION_WPA		0x00000002
-#define IW_AUTH_WPA_VERSION_WPA2	0x00000004
-
-/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
-#define IW_AUTH_CIPHER_NONE	0x00000001
-#define IW_AUTH_CIPHER_WEP40	0x00000002
-#define IW_AUTH_CIPHER_TKIP	0x00000004
-#define IW_AUTH_CIPHER_CCMP	0x00000008
-#define IW_AUTH_CIPHER_WEP104	0x00000010
-
-/* IW_AUTH_KEY_MGMT values (bit field) */
-#define IW_AUTH_KEY_MGMT_802_1X	1
-#define IW_AUTH_KEY_MGMT_PSK	2
-
-/* IW_AUTH_80211_AUTH_ALG values (bit field) */
-#define IW_AUTH_ALG_OPEN_SYSTEM	0x00000001
-#define IW_AUTH_ALG_SHARED_KEY	0x00000002
-#define IW_AUTH_ALG_LEAP	0x00000004
-
-/* IW_AUTH_ROAMING_CONTROL values */
-#define IW_AUTH_ROAMING_ENABLE	0	/* driver/firmware based roaming */
-#define IW_AUTH_ROAMING_DISABLE	1	/* user space program used for roaming
-					 * control */
-
-/* IW_AUTH_MFP (management frame protection) values */
-#define IW_AUTH_MFP_DISABLED	0	/* MFP disabled */
-#define IW_AUTH_MFP_OPTIONAL	1	/* MFP optional */
-#define IW_AUTH_MFP_REQUIRED	2	/* MFP required */
-
-/* SIOCSIWENCODEEXT definitions */
-#define IW_ENCODE_SEQ_MAX_SIZE	8
-/* struct iw_encode_ext ->alg */
-#define IW_ENCODE_ALG_NONE	0
-#define IW_ENCODE_ALG_WEP	1
-#define IW_ENCODE_ALG_TKIP	2
-#define IW_ENCODE_ALG_CCMP	3
-#define IW_ENCODE_ALG_PMK	4
-#define IW_ENCODE_ALG_AES_CMAC	5
-/* struct iw_encode_ext ->ext_flags */
-#define IW_ENCODE_EXT_TX_SEQ_VALID	0x00000001
-#define IW_ENCODE_EXT_RX_SEQ_VALID	0x00000002
-#define IW_ENCODE_EXT_GROUP_KEY		0x00000004
-#define IW_ENCODE_EXT_SET_TX_KEY	0x00000008
-
-/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
-#define IW_MICFAILURE_KEY_ID	0x00000003 /* Key ID 0..3 */
-#define IW_MICFAILURE_GROUP	0x00000004
-#define IW_MICFAILURE_PAIRWISE	0x00000008
-#define IW_MICFAILURE_STAKEY	0x00000010
-#define IW_MICFAILURE_COUNT	0x00000060 /* 1 or 2 (0 = count not supported)
-					    */
-
-/* Bit field values for enc_capa in struct iw_range */
-#define IW_ENC_CAPA_WPA		0x00000001
-#define IW_ENC_CAPA_WPA2	0x00000002
-#define IW_ENC_CAPA_CIPHER_TKIP	0x00000004
-#define IW_ENC_CAPA_CIPHER_CCMP	0x00000008
-#define IW_ENC_CAPA_4WAY_HANDSHAKE	0x00000010
-
-/* Event capability macros - in (struct iw_range *)->event_capa
- * Because we have more than 32 possible events, we use an array of
- * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
-#define IW_EVENT_CAPA_BASE(cmd)		((cmd >= SIOCIWFIRSTPRIV) ? \
-					 (cmd - SIOCIWFIRSTPRIV + 0x60) : \
-					 (cmd - SIOCSIWCOMMIT))
-#define IW_EVENT_CAPA_INDEX(cmd)	(IW_EVENT_CAPA_BASE(cmd) >> 5)
-#define IW_EVENT_CAPA_MASK(cmd)		(1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
-/* Event capability constants - event autogenerated by the kernel
- * This list is valid for most 802.11 devices, customise as needed... */
-#define IW_EVENT_CAPA_K_0	(IW_EVENT_CAPA_MASK(0x8B04) | \
-				 IW_EVENT_CAPA_MASK(0x8B06) | \
-				 IW_EVENT_CAPA_MASK(0x8B1A))
-#define IW_EVENT_CAPA_K_1	(IW_EVENT_CAPA_MASK(0x8B2A))
-/* "Easy" macro to set events in iw_range (less efficient) */
-#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
-#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
-
-
-/****************************** TYPES ******************************/
-
-/* --------------------------- SUBTYPES --------------------------- */
-/*
- *	Generic format for most parameters that fit in an int
- */
-struct	iw_param
-{
-  __s32		value;		/* The value of the parameter itself */
-  __u8		fixed;		/* Hardware should not use auto select */
-  __u8		disabled;	/* Disable the feature */
-  __u16		flags;		/* Various specifc flags (if any) */
-};
-
-/*
- *	For all data larger than 16 octets, we need to use a
- *	pointer to memory allocated in user space.
- */
-struct	iw_point
-{
-  void __user	*pointer;	/* Pointer to the data  (in user space) */
-  __u16		length;		/* number of fields or size in bytes */
-  __u16		flags;		/* Optional params */
-};
-
-/*
- *	A frequency
- *	For numbers lower than 10^9, we encode the number in 'm' and
- *	set 'e' to 0
- *	For number greater than 10^9, we divide it by the lowest power
- *	of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
- *	The power of 10 is in 'e', the result of the division is in 'm'.
- */
-struct	iw_freq
-{
-	__s32		m;		/* Mantissa */
-	__s16		e;		/* Exponent */
-	__u8		i;		/* List index (when in range struct) */
-	__u8		flags;		/* Flags (fixed/auto) */
-};
-
-/*
- *	Quality of the link
- */
-struct	iw_quality
-{
-	__u8		qual;		/* link quality (%retries, SNR,
-					   %missed beacons or better...) */
-	__u8		level;		/* signal level (dBm) */
-	__u8		noise;		/* noise level (dBm) */
-	__u8		updated;	/* Flags to know if updated */
-};
-
-/*
- *	Packet discarded in the wireless adapter due to
- *	"wireless" specific problems...
- *	Note : the list of counter and statistics in net_device_stats
- *	is already pretty exhaustive, and you should use that first.
- *	This is only additional stats...
- */
-struct	iw_discarded
-{
-	__u32		nwid;		/* Rx : Wrong nwid/essid */
-	__u32		code;		/* Rx : Unable to code/decode (WEP) */
-	__u32		fragment;	/* Rx : Can't perform MAC reassembly */
-	__u32		retries;	/* Tx : Max MAC retries num reached */
-	__u32		misc;		/* Others cases */
-};
-
-/*
- *	Packet/Time period missed in the wireless adapter due to
- *	"wireless" specific problems...
- */
-struct	iw_missed
-{
-	__u32		beacon;		/* Missed beacons/superframe */
-};
-
-/*
- *	Quality range (for spy threshold)
- */
-struct	iw_thrspy
-{
-	struct sockaddr		addr;		/* Source address (hw/mac) */
-	struct iw_quality	qual;		/* Quality of the link */
-	struct iw_quality	low;		/* Low threshold */
-	struct iw_quality	high;		/* High threshold */
-};
-
-/*
- *	Optional data for scan request
- *
- *	Note: these optional parameters are controlling parameters for the
- *	scanning behavior, these do not apply to getting scan results
- *	(SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
- *	provide a merged results with all BSSes even if the previous scan
- *	request limited scanning to a subset, e.g., by specifying an SSID.
- *	Especially, scan results are required to include an entry for the
- *	current BSS if the driver is in Managed mode and associated with an AP.
- */
-struct	iw_scan_req
-{
-	__u8		scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
-	__u8		essid_len;
-	__u8		num_channels; /* num entries in channel_list;
-				       * 0 = scan all allowed channels */
-	__u8		flags; /* reserved as padding; use zero, this may
-				* be used in the future for adding flags
-				* to request different scan behavior */
-	struct sockaddr	bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
-				* individual address of a specific BSS */
-
-	/*
-	 * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
-	 * the current ESSID. This allows scan requests for specific ESSID
-	 * without having to change the current ESSID and potentially breaking
-	 * the current association.
-	 */
-	__u8		essid[IW_ESSID_MAX_SIZE];
-
-	/*
-	 * Optional parameters for changing the default scanning behavior.
-	 * These are based on the MLME-SCAN.request from IEEE Std 802.11.
-	 * TU is 1.024 ms. If these are set to 0, driver is expected to use
-	 * reasonable default values. min_channel_time defines the time that
-	 * will be used to wait for the first reply on each channel. If no
-	 * replies are received, next channel will be scanned after this. If
-	 * replies are received, total time waited on the channel is defined by
-	 * max_channel_time.
-	 */
-	__u32		min_channel_time; /* in TU */
-	__u32		max_channel_time; /* in TU */
-
-	struct iw_freq	channel_list[IW_MAX_FREQUENCIES];
-};
-
-/* ------------------------- WPA SUPPORT ------------------------- */
-
-/*
- *	Extended data structure for get/set encoding (this is used with
- *	SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
- *	flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
- *	only the data contents changes (key data -> this structure, including
- *	key data).
- *
- *	If the new key is the first group key, it will be set as the default
- *	TX key. Otherwise, default TX key index is only changed if
- *	IW_ENCODE_EXT_SET_TX_KEY flag is set.
- *
- *	Key will be changed with SIOCSIWENCODEEXT in all cases except for
- *	special "change TX key index" operation which is indicated by setting
- *	key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
- *
- *	tx_seq/rx_seq are only used when respective
- *	IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
- *	TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
- *	TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
- *	used only by an Authenticator (AP or an IBSS station) to get the
- *	current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
- *	RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
- *	debugging/testing.
- */
-struct	iw_encode_ext
-{
-	__u32		ext_flags; /* IW_ENCODE_EXT_* */
-	__u8		tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	__u8		rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	struct sockaddr	addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
-			       * (group) keys or unicast address for
-			       * individual keys */
-	__u16		alg; /* IW_ENCODE_ALG_* */
-	__u16		key_len;
-	__u8		key[0];
-};
-
-/* SIOCSIWMLME data */
-struct	iw_mlme
-{
-	__u16		cmd; /* IW_MLME_* */
-	__u16		reason_code;
-	struct sockaddr	addr;
-};
-
-/* SIOCSIWPMKSA data */
-#define IW_PMKSA_ADD		1
-#define IW_PMKSA_REMOVE		2
-#define IW_PMKSA_FLUSH		3
-
-#define IW_PMKID_LEN	16
-
-struct	iw_pmksa
-{
-	__u32		cmd; /* IW_PMKSA_* */
-	struct sockaddr	bssid;
-	__u8		pmkid[IW_PMKID_LEN];
-};
-
-/* IWEVMICHAELMICFAILURE data */
-struct	iw_michaelmicfailure
-{
-	__u32		flags;
-	struct sockaddr	src_addr;
-	__u8		tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-};
-
-/* IWEVPMKIDCAND data */
-#define IW_PMKID_CAND_PREAUTH	0x00000001 /* RNS pre-authentication enabled */
-struct	iw_pmkid_cand
-{
-	__u32		flags; /* IW_PMKID_CAND_* */
-	__u32		index; /* the smaller the index, the higher the
-				* priority */
-	struct sockaddr	bssid;
-};
-
-/* ------------------------ WIRELESS STATS ------------------------ */
-/*
- * Wireless statistics (used for /proc/net/wireless)
- */
-struct	iw_statistics
-{
-	__u16		status;		/* Status
-					 * - device dependent for now */
-
-	struct iw_quality	qual;		/* Quality of the link
-						 * (instant/mean/max) */
-	struct iw_discarded	discard;	/* Packet discarded counts */
-	struct iw_missed	miss;		/* Packet missed counts */
-};
-
-/* ------------------------ IOCTL REQUEST ------------------------ */
-/*
- * This structure defines the payload of an ioctl, and is used 
- * below.
- *
- * Note that this structure should fit on the memory footprint
- * of iwreq (which is the same as ifreq), which mean a max size of
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
- * You should check this when increasing the structures defined
- * above in this file...
- */
-union	iwreq_data
-{
-	/* Config - generic */
-	char		name[IFNAMSIZ];
-	/* Name : used to verify the presence of  wireless extensions.
-	 * Name of the protocol/provider... */
-
-	struct iw_point	essid;		/* Extended network name */
-	struct iw_param	nwid;		/* network id (or domain - the cell) */
-	struct iw_freq	freq;		/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-	struct iw_param	sens;		/* signal level threshold */
-	struct iw_param	bitrate;	/* default bit rate */
-	struct iw_param	txpower;	/* default transmit power */
-	struct iw_param	rts;		/* RTS threshold threshold */
-	struct iw_param	frag;		/* Fragmentation threshold */
-	__u32		mode;		/* Operation mode */
-	struct iw_param	retry;		/* Retry limits & lifetime */
-
-	struct iw_point	encoding;	/* Encoding stuff : tokens */
-	struct iw_param	power;		/* PM duration/timeout */
-	struct iw_quality qual;		/* Quality part of statistics */
-
-	struct sockaddr	ap_addr;	/* Access point address */
-	struct sockaddr	addr;		/* Destination address (hw/mac) */
-
-	struct iw_param	param;		/* Other small parameters */
-	struct iw_point	data;		/* Other large parameters */
-};
-
-/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
- * Do I need to remind you about structure size (32 octets) ?
- */
-struct	iwreq 
-{
-	union
-	{
-		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
-	} ifr_ifrn;
-
-	/* Data part (defined just above) */
-	union	iwreq_data	u;
-};
-
-/* -------------------------- IOCTL DATA -------------------------- */
-/*
- *	For those ioctl which want to exchange mode data that what could
- *	fit in the above structure...
- */
-
-/*
- *	Range of parameters
- */
-
-struct	iw_range
-{
-	/* Informative stuff (to choose between different interface) */
-	__u32		throughput;	/* To give an idea... */
-	/* In theory this value should be the maximum benchmarked
-	 * TCP/IP throughput, because with most of these devices the
-	 * bit rate is meaningless (overhead an co) to estimate how
-	 * fast the connection will go and pick the fastest one.
-	 * I suggest people to play with Netperf or any benchmark...
-	 */
-
-	/* NWID (or domain id) */
-	__u32		min_nwid;	/* Minimal NWID we are able to set */
-	__u32		max_nwid;	/* Maximal NWID we are able to set */
-
-	/* Old Frequency (backward compat - moved lower ) */
-	__u16		old_num_channels;
-	__u8		old_num_frequency;
-
-	/* Wireless event capability bitmasks */
-	__u32		event_capa[6];
-
-	/* signal level threshold range */
-	__s32		sensitivity;
-
-	/* Quality of link & SNR stuff */
-	/* Quality range (link, level, noise)
-	 * If the quality is absolute, it will be in the range [0 ; max_qual],
-	 * if the quality is dBm, it will be in the range [max_qual ; 0].
-	 * Don't forget that we use 8 bit arithmetics... */
-	struct iw_quality	max_qual;	/* Quality of the link */
-	/* This should contain the average/typical values of the quality
-	 * indicator. This should be the threshold between a "good" and
-	 * a "bad" link (example : monitor going from green to orange).
-	 * Currently, user space apps like quality monitors don't have any
-	 * way to calibrate the measurement. With this, they can split
-	 * the range between 0 and max_qual in different quality level
-	 * (using a geometric subdivision centered on the average).
-	 * I expect that people doing the user space apps will feedback
-	 * us on which value we need to put in each driver... */
-	struct iw_quality	avg_qual;	/* Quality of the link */
-
-	/* Rates */
-	__u8		num_bitrates;	/* Number of entries in the list */
-	__s32		bitrate[IW_MAX_BITRATES];	/* list, in bps */
-
-	/* RTS threshold */
-	__s32		min_rts;	/* Minimal RTS threshold */
-	__s32		max_rts;	/* Maximal RTS threshold */
-
-	/* Frag threshold */
-	__s32		min_frag;	/* Minimal frag threshold */
-	__s32		max_frag;	/* Maximal frag threshold */
-
-	/* Power Management duration & timeout */
-	__s32		min_pmp;	/* Minimal PM period */
-	__s32		max_pmp;	/* Maximal PM period */
-	__s32		min_pmt;	/* Minimal PM timeout */
-	__s32		max_pmt;	/* Maximal PM timeout */
-	__u16		pmp_flags;	/* How to decode max/min PM period */
-	__u16		pmt_flags;	/* How to decode max/min PM timeout */
-	__u16		pm_capa;	/* What PM options are supported */
-
-	/* Encoder stuff */
-	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
-	__u8	num_encoding_sizes;	/* Number of entry in the list */
-	__u8	max_encoding_tokens;	/* Max number of tokens */
-	/* For drivers that need a "login/passwd" form */
-	__u8	encoding_login_index;	/* token index for login token */
-
-	/* Transmit power */
-	__u16		txpower_capa;	/* What options are supported */
-	__u8		num_txpower;	/* Number of entries in the list */
-	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
-
-	/* Wireless Extension version info */
-	__u8		we_version_compiled;	/* Must be WIRELESS_EXT */
-	__u8		we_version_source;	/* Last update of source */
-
-	/* Retry limits and lifetime */
-	__u16		retry_capa;	/* What retry options are supported */
-	__u16		retry_flags;	/* How to decode max/min retry limit */
-	__u16		r_time_flags;	/* How to decode max/min retry life */
-	__s32		min_retry;	/* Minimal number of retries */
-	__s32		max_retry;	/* Maximal number of retries */
-	__s32		min_r_time;	/* Minimal retry lifetime */
-	__s32		max_r_time;	/* Maximal retry lifetime */
-
-	/* Frequency */
-	__u16		num_channels;	/* Number of channels [0; num - 1] */
-	__u8		num_frequency;	/* Number of entry in the list */
-	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
-	/* Note : this frequency list doesn't need to fit channel numbers,
-	 * because each entry contain its channel index */
-
-	__u32		enc_capa; /* IW_ENC_CAPA_* bit field */
-};
-
-/*
- * Private ioctl interface information
- */
- 
-struct	iw_priv_args
-{
-	__u32		cmd;		/* Number of the ioctl to issue */
-	__u16		set_args;	/* Type and number of args */
-	__u16		get_args;	/* Type and number of args */
-	char		name[IFNAMSIZ];	/* Name of the extension */
-};
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Wireless events are carried through the rtnetlink socket to user
- * space. They are encapsulated in the IFLA_WIRELESS field of
- * a RTM_NEWLINK message.
- */
-
-/*
- * A Wireless Event. Contains basically the same data as the ioctl...
- */
-struct iw_event
-{
-	__u16		len;			/* Real lenght of this stuff */
-	__u16		cmd;			/* Wireless IOCTL */
-	union iwreq_data	u;		/* IOCTL fixed payload */
-};
-
-/* Size of the Event prefix (including padding and alignement junk) */
-#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
-/* Size of the various events */
-#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
-#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
-#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
-
-/* iw_point events are special. First, the payload (extra data) come at
- * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
- * we omit the pointer, so start at an offset. */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
-			  (char *) NULL)
-#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point) - \
-			 IW_EV_POINT_OFF)
-
-#endif	/* _LINUX_WIRELESS_H */

Deleted: vendor/wpa/2.0/src/eap_common/chap.c
===================================================================
--- vendor/wpa/dist/src/eap_common/chap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/chap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,34 +0,0 @@
-/*
- * CHAP-MD5 (RFC 1994)
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/crypto.h"
-#include "chap.h"
-
-int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
-	      size_t challenge_len, u8 *response)
-{
-	const u8 *addr[3];
-	size_t len[3];
-
-	addr[0] = &id;
-	len[0] = 1;
-	addr[1] = secret;
-	len[1] = secret_len;
-	addr[2] = challenge;
-	len[2] = challenge_len;
-	return md5_vector(3, addr, len, response);
-}

Copied: vendor/wpa/2.0/src/eap_common/chap.c (from rev 9639, vendor/wpa/dist/src/eap_common/chap.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/chap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/chap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * CHAP-MD5 (RFC 1994)
+ * Copyright (c) 2007-2009, Jouni Malinen <j at 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/crypto.h"
+#include "chap.h"
+
+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
+	      size_t challenge_len, u8 *response)
+{
+	const u8 *addr[3];
+	size_t len[3];
+
+	addr[0] = &id;
+	len[0] = 1;
+	addr[1] = secret;
+	len[1] = secret_len;
+	addr[2] = challenge;
+	len[2] = challenge_len;
+	return md5_vector(3, addr, len, response);
+}

Deleted: vendor/wpa/2.0/src/eap_common/chap.h
===================================================================
--- vendor/wpa/dist/src/eap_common/chap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/chap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,23 +0,0 @@
-/*
- * CHAP-MD5 (RFC 1994)
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CHAP_H
-#define CHAP_H
-
-#define CHAP_MD5_LEN 16
-
-int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
-	     size_t challenge_len, u8 *response);
-
-#endif /* CHAP_H */

Copied: vendor/wpa/2.0/src/eap_common/chap.h (from rev 9639, vendor/wpa/dist/src/eap_common/chap.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/chap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/chap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,17 @@
+/*
+ * CHAP-MD5 (RFC 1994)
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CHAP_H
+#define CHAP_H
+
+#define CHAP_MD5_LEN 16
+
+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
+	     size_t challenge_len, u8 *response);
+
+#endif /* CHAP_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,184 +0,0 @@
-/*
- * EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_defs.h"
-#include "eap_common.h"
-
-/**
- * eap_hdr_validate - Validate EAP header
- * @vendor: Expected EAP Vendor-Id (0 = IETF)
- * @eap_type: Expected EAP type number
- * @msg: EAP frame (starting with EAP header)
- * @plen: Pointer to variable to contain the returned payload length
- * Returns: Pointer to EAP payload (after type field), or %NULL on failure
- *
- * This is a helper function for EAP method implementations. This is usually
- * called in the beginning of struct eap_method::process() function to verify
- * that the received EAP request packet has a valid header. This function is
- * able to process both legacy and expanded EAP headers and in most cases, the
- * caller can just use the returned payload pointer (into *plen) for processing
- * the payload regardless of whether the packet used the expanded EAP header or
- * not.
- */
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
-			    const struct wpabuf *msg, size_t *plen)
-{
-	const struct eap_hdr *hdr;
-	const u8 *pos;
-	size_t len;
-
-	hdr = wpabuf_head(msg);
-
-	if (wpabuf_len(msg) < sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
-		return NULL;
-	}
-
-	len = be_to_host16(hdr->length);
-	if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) {
-		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
-		return NULL;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-
-	if (*pos == EAP_TYPE_EXPANDED) {
-		int exp_vendor;
-		u32 exp_type;
-		if (len < sizeof(*hdr) + 8) {
-			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
-				   "length");
-			return NULL;
-		}
-		pos++;
-		exp_vendor = WPA_GET_BE24(pos);
-		pos += 3;
-		exp_type = WPA_GET_BE32(pos);
-		pos += 4;
-		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
-			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
-				   "type");
-			return NULL;
-		}
-
-		*plen = len - sizeof(*hdr) - 8;
-		return pos;
-	} else {
-		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
-			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
-			return NULL;
-		}
-		*plen = len - sizeof(*hdr) - 1;
-		return pos + 1;
-	}
-}
-
-
-/**
- * eap_msg_alloc - Allocate a buffer for an EAP message
- * @vendor: Vendor-Id (0 = IETF)
- * @type: EAP type
- * @payload_len: Payload length in bytes (data after Type)
- * @code: Message Code (EAP_CODE_*)
- * @identifier: Identifier
- * Returns: Pointer to the allocated message buffer or %NULL on error
- *
- * This function can be used to allocate a buffer for an EAP message and fill
- * in the EAP header. This function is automatically using expanded EAP header
- * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
- * not need to separately select which header type to use when using this
- * function to allocate the message buffers. The returned buffer has room for
- * payload_len bytes and has the EAP header and Type field already filled in.
- */
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
-			      u8 code, u8 identifier)
-{
-	struct wpabuf *buf;
-	struct eap_hdr *hdr;
-	size_t len;
-
-	len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
-		payload_len;
-	buf = wpabuf_alloc(len);
-	if (buf == NULL)
-		return NULL;
-
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	hdr->code = code;
-	hdr->identifier = identifier;
-	hdr->length = host_to_be16(len);
-
-	if (vendor == EAP_VENDOR_IETF) {
-		wpabuf_put_u8(buf, type);
-	} else {
-		wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
-		wpabuf_put_be24(buf, vendor);
-		wpabuf_put_be32(buf, type);
-	}
-
-	return buf;
-}
-
-
-/**
- * eap_update_len - Update EAP header length
- * @msg: EAP message from eap_msg_alloc
- *
- * This function updates the length field in the EAP header to match with the
- * current length for the buffer. This allows eap_msg_alloc() to be used to
- * allocate a larger buffer than the exact message length (e.g., if exact
- * message length is not yet known).
- */
-void eap_update_len(struct wpabuf *msg)
-{
-	struct eap_hdr *hdr;
-	hdr = wpabuf_mhead(msg);
-	if (wpabuf_len(msg) < sizeof(*hdr))
-		return;
-	hdr->length = host_to_be16(wpabuf_len(msg));
-}
-
-
-/**
- * eap_get_id - Get EAP Identifier from wpabuf
- * @msg: Buffer starting with an EAP header
- * Returns: The Identifier field from the EAP header
- */
-u8 eap_get_id(const struct wpabuf *msg)
-{
-	const struct eap_hdr *eap;
-
-	if (wpabuf_len(msg) < sizeof(*eap))
-		return 0;
-
-	eap = wpabuf_head(msg);
-	return eap->identifier;
-}
-
-
-/**
- * eap_get_id - Get EAP Type from wpabuf
- * @msg: Buffer starting with an EAP header
- * Returns: The EAP Type after the EAP header
- */
-EapType eap_get_type(const struct wpabuf *msg)
-{
-	if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
-		return EAP_TYPE_NONE;
-
-	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,205 @@
+/*
+ * EAP common peer/server definitions
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "eap_defs.h"
+#include "eap_common.h"
+
+/**
+ * eap_hdr_len_valid - Validate EAP header length field
+ * @msg: EAP frame (starting with EAP header)
+ * @min_payload: Minimum payload length needed
+ * Returns: 1 for valid header, 0 for invalid
+ *
+ * This is a helper function that does minimal validation of EAP messages. The
+ * length field is verified to be large enough to include the header and not
+ * too large to go beyond the end of the buffer.
+ */
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
+{
+	const struct eap_hdr *hdr;
+	size_t len;
+
+	if (msg == NULL)
+		return 0;
+
+	hdr = wpabuf_head(msg);
+
+	if (wpabuf_len(msg) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+		return 0;
+	}
+
+	len = be_to_host16(hdr->length);
+	if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
+		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @vendor: Expected EAP Vendor-Id (0 = IETF)
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @plen: Pointer to variable to contain the returned payload length
+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure
+ *
+ * This is a helper function for EAP method implementations. This is usually
+ * called in the beginning of struct eap_method::process() function to verify
+ * that the received EAP request packet has a valid header. This function is
+ * able to process both legacy and expanded EAP headers and in most cases, the
+ * caller can just use the returned payload pointer (into *plen) for processing
+ * the payload regardless of whether the packet used the expanded EAP header or
+ * not.
+ */
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const struct wpabuf *msg, size_t *plen)
+{
+	const struct eap_hdr *hdr;
+	const u8 *pos;
+	size_t len;
+
+	if (!eap_hdr_len_valid(msg, 1))
+		return NULL;
+
+	hdr = wpabuf_head(msg);
+	len = be_to_host16(hdr->length);
+	pos = (const u8 *) (hdr + 1);
+
+	if (*pos == EAP_TYPE_EXPANDED) {
+		int exp_vendor;
+		u32 exp_type;
+		if (len < sizeof(*hdr) + 8) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
+				   "length");
+			return NULL;
+		}
+		pos++;
+		exp_vendor = WPA_GET_BE24(pos);
+		pos += 3;
+		exp_type = WPA_GET_BE32(pos);
+		pos += 4;
+		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
+				   "type");
+			return NULL;
+		}
+
+		*plen = len - sizeof(*hdr) - 8;
+		return pos;
+	} else {
+		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+			return NULL;
+		}
+		*plen = len - sizeof(*hdr) - 1;
+		return pos + 1;
+	}
+}
+
+
+/**
+ * eap_msg_alloc - Allocate a buffer for an EAP message
+ * @vendor: Vendor-Id (0 = IETF)
+ * @type: EAP type
+ * @payload_len: Payload length in bytes (data after Type)
+ * @code: Message Code (EAP_CODE_*)
+ * @identifier: Identifier
+ * Returns: Pointer to the allocated message buffer or %NULL on error
+ *
+ * This function can be used to allocate a buffer for an EAP message and fill
+ * in the EAP header. This function is automatically using expanded EAP header
+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
+ * not need to separately select which header type to use when using this
+ * function to allocate the message buffers. The returned buffer has room for
+ * payload_len bytes and has the EAP header and Type field already filled in.
+ */
+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
+			      u8 code, u8 identifier)
+{
+	struct wpabuf *buf;
+	struct eap_hdr *hdr;
+	size_t len;
+
+	len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
+		payload_len;
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	hdr = wpabuf_put(buf, sizeof(*hdr));
+	hdr->code = code;
+	hdr->identifier = identifier;
+	hdr->length = host_to_be16(len);
+
+	if (vendor == EAP_VENDOR_IETF) {
+		wpabuf_put_u8(buf, type);
+	} else {
+		wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
+		wpabuf_put_be24(buf, vendor);
+		wpabuf_put_be32(buf, type);
+	}
+
+	return buf;
+}
+
+
+/**
+ * eap_update_len - Update EAP header length
+ * @msg: EAP message from eap_msg_alloc
+ *
+ * This function updates the length field in the EAP header to match with the
+ * current length for the buffer. This allows eap_msg_alloc() to be used to
+ * allocate a larger buffer than the exact message length (e.g., if exact
+ * message length is not yet known).
+ */
+void eap_update_len(struct wpabuf *msg)
+{
+	struct eap_hdr *hdr;
+	hdr = wpabuf_mhead(msg);
+	if (wpabuf_len(msg) < sizeof(*hdr))
+		return;
+	hdr->length = host_to_be16(wpabuf_len(msg));
+}
+
+
+/**
+ * eap_get_id - Get EAP Identifier from wpabuf
+ * @msg: Buffer starting with an EAP header
+ * Returns: The Identifier field from the EAP header
+ */
+u8 eap_get_id(const struct wpabuf *msg)
+{
+	const struct eap_hdr *eap;
+
+	if (wpabuf_len(msg) < sizeof(*eap))
+		return 0;
+
+	eap = wpabuf_head(msg);
+	return eap->identifier;
+}
+
+
+/**
+ * eap_get_id - Get EAP Type from wpabuf
+ * @msg: Buffer starting with an EAP header
+ * Returns: The EAP Type after the EAP header
+ */
+EapType eap_get_type(const struct wpabuf *msg)
+{
+	if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
+		return EAP_TYPE_NONE;
+
+	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,28 +0,0 @@
-/*
- * EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_COMMON_H
-#define EAP_COMMON_H
-
-#include "wpabuf.h"
-
-const u8 * eap_hdr_validate(int vendor, EapType eap_type,
-			    const struct wpabuf *msg, size_t *plen);
-struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
-			      u8 code, u8 identifier);
-void eap_update_len(struct wpabuf *msg);
-u8 eap_get_id(const struct wpabuf *msg);
-EapType eap_get_type(const struct wpabuf *msg);
-
-#endif /* EAP_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * EAP common peer/server definitions
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_COMMON_H
+#define EAP_COMMON_H
+
+#include "wpabuf.h"
+
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const struct wpabuf *msg, size_t *plen);
+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
+			      u8 code, u8 identifier);
+void eap_update_len(struct wpabuf *msg);
+u8 eap_get_id(const struct wpabuf *msg);
+EapType eap_get_type(const struct wpabuf *msg);
+
+#endif /* EAP_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_defs.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_defs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,85 +0,0 @@
-/*
- * EAP server/peer: Shared EAP definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_DEFS_H
-#define EAP_DEFS_H
-
-/* RFC 3748 - Extensible Authentication Protocol (EAP) */
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_hdr {
-	u8 code;
-	u8 identifier;
-	be16 length; /* including code and identifier; network byte order */
-	/* followed by length-4 octets of data */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
-       EAP_CODE_FAILURE = 4 };
-
-/* EAP Request and Response data begins with one octet Type. Success and
- * Failure do not have additional data. */
-
-/*
- * EAP Method Types as allocated by IANA:
- * http://www.iana.org/assignments/eap-numbers
- */
-typedef enum {
-	EAP_TYPE_NONE = 0,
-	EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
-	EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
-	EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
-	EAP_TYPE_MD5 = 4, /* RFC 3748 */
-	EAP_TYPE_OTP = 5 /* RFC 3748 */,
-	EAP_TYPE_GTC = 6, /* RFC 3748 */
-	EAP_TYPE_TLS = 13 /* RFC 2716 */,
-	EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
-	EAP_TYPE_SIM = 18 /* RFC 4186 */,
-	EAP_TYPE_TTLS = 21 /* RFC 5281 */,
-	EAP_TYPE_AKA = 23 /* RFC 4187 */,
-	EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
-	EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
-	EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
-	EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment;
-			   * type 38 has previously been allocated for
-			   * EAP-HTTP Digest, (funk.com) */,
-	EAP_TYPE_FAST = 43 /* RFC 4851 */,
-	EAP_TYPE_PAX = 46 /* RFC 4746 */,
-	EAP_TYPE_PSK = 47 /* RFC 4764 */,
-	EAP_TYPE_SAKE = 48 /* RFC 4763 */,
-	EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
-	EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
-	EAP_TYPE_GPSK = 51 /* RFC 5433 */,
-	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
-} EapType;
-
-
-/* SMI Network Management Private Enterprise Code for vendor specific types */
-enum {
-	EAP_VENDOR_IETF = 0,
-	EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
-	EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
-};
-
-#define EAP_MSK_LEN 64
-#define EAP_EMSK_LEN 64
-
-#endif /* EAP_DEFS_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_defs.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_defs.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_defs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,84 @@
+/*
+ * EAP server/peer: Shared EAP definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_DEFS_H
+#define EAP_DEFS_H
+
+/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_hdr {
+	u8 code;
+	u8 identifier;
+	be16 length; /* including code and identifier; network byte order */
+	/* followed by length-4 octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
+       EAP_CODE_FAILURE = 4 };
+
+/* EAP Request and Response data begins with one octet Type. Success and
+ * Failure do not have additional data. */
+
+/*
+ * EAP Method Types as allocated by IANA:
+ * http://www.iana.org/assignments/eap-numbers
+ */
+typedef enum {
+	EAP_TYPE_NONE = 0,
+	EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
+	EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
+	EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
+	EAP_TYPE_MD5 = 4, /* RFC 3748 */
+	EAP_TYPE_OTP = 5 /* RFC 3748 */,
+	EAP_TYPE_GTC = 6, /* RFC 3748 */
+	EAP_TYPE_TLS = 13 /* RFC 2716 */,
+	EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
+	EAP_TYPE_SIM = 18 /* RFC 4186 */,
+	EAP_TYPE_TTLS = 21 /* RFC 5281 */,
+	EAP_TYPE_AKA = 23 /* RFC 4187 */,
+	EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
+	EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
+	EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
+	EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment;
+			   * type 38 has previously been allocated for
+			   * EAP-HTTP Digest, (funk.com) */,
+	EAP_TYPE_FAST = 43 /* RFC 4851 */,
+	EAP_TYPE_PAX = 46 /* RFC 4746 */,
+	EAP_TYPE_PSK = 47 /* RFC 4764 */,
+	EAP_TYPE_SAKE = 48 /* RFC 4763 */,
+	EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
+	EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
+	EAP_TYPE_GPSK = 51 /* RFC 5433 */,
+	EAP_TYPE_PWD = 52 /* RFC 5931 */,
+	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
+} EapType;
+
+
+/* SMI Network Management Private Enterprise Code for vendor specific types */
+enum {
+	EAP_VENDOR_IETF = 0,
+	EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
+	EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */,
+	EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */
+};
+
+#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
+
+#define EAP_MSK_LEN 64
+#define EAP_EMSK_LEN 64
+
+#endif /* EAP_DEFS_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_fast_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_fast_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_fast_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,304 +0,0 @@
-/*
- * EAP-FAST common helper functions (RFC 4851)
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "eap_defs.h"
-#include "eap_tlv_common.h"
-#include "eap_fast_common.h"
-
-
-void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
-{
-	struct pac_tlv_hdr hdr;
-	hdr.type = host_to_be16(type);
-	hdr.len = host_to_be16(len);
-	wpabuf_put_data(buf, &hdr, sizeof(hdr));
-}
-
-
-void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
-			     u16 len)
-{
-	eap_fast_put_tlv_hdr(buf, type, len);
-	wpabuf_put_data(buf, data, len);
-}
-
-
-void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
-				 const struct wpabuf *data)
-{
-	eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
-	wpabuf_put_buf(buf, data);
-}
-
-
-struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	eap_fast_put_tlv_buf(e,
-			     EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
-			     buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
-void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
-				   const u8 *client_random, u8 *master_secret)
-{
-#define TLS_RANDOM_LEN 32
-#define TLS_MASTER_SECRET_LEN 48
-	u8 seed[2 * TLS_RANDOM_LEN];
-
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
-		    client_random, TLS_RANDOM_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
-		    server_random, TLS_RANDOM_LEN);
-
-	/*
-	 * RFC 4851, Section 5.1:
-	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
-	 *                       server_random + client_random, 48)
-	 */
-	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
-	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
-	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
-		   "PAC to master secret label hash",
-		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
-			master_secret, TLS_MASTER_SECRET_LEN);
-}
-
-
-u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
-			 const char *label, size_t len)
-{
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-	int block_size;
-
-	block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
-	if (block_size < 0)
-		return NULL;
-
-	out = os_malloc(block_size + len);
-	if (out == NULL)
-		return NULL;
-
-	if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
-	    == 0) {
-		os_memmove(out, out + block_size, len);
-		return out;
-	}
-
-	if (tls_connection_get_keys(ssl_ctx, conn, &keys))
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
-			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, block_size + len))
-		goto fail;
-	os_free(rnd);
-	os_memmove(out, out + block_size, len);
-	return out;
-
-fail:
-	os_free(rnd);
-	os_free(out);
-	return NULL;
-}
-
-
-void 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);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
-			msk, EAP_FAST_KEY_LEN);
-}
-
-
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
-{
-	/*
-	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
-	 * EMSK = T-PRF(S-IMCK[j],
-	 *        "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);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
-			emsk, EAP_EMSK_LEN);
-}
-
-
-int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
-		       int tlv_type, u8 *pos, int len)
-{
-	switch (tlv_type) {
-	case EAP_TLV_EAP_PAYLOAD_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
-			    pos, len);
-		if (tlv->eap_payload_tlv) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "EAP-Payload TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->eap_payload_tlv = pos;
-		tlv->eap_payload_tlv_len = len;
-		break;
-	case EAP_TLV_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
-		if (tlv->result) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Result TLV in the message");
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Result TLV");
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->result = WPA_GET_BE16(pos);
-		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->result != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
-				   tlv->result);
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
-			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
-			    pos, len);
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Intermediate-Result TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		if (tlv->iresult) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Intermediate-Result TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->iresult = WPA_GET_BE16(pos);
-		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
-				   "Result %d", tlv->iresult);
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
-			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_CRYPTO_BINDING_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
-			    pos, len);
-		if (tlv->crypto_binding) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Crypto-Binding TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
-		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Crypto-Binding TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
-			(pos - sizeof(struct eap_tlv_hdr));
-		break;
-	case EAP_TLV_REQUEST_ACTION_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
-			    pos, len);
-		if (tlv->request_action) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Request-Action TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Request-Action TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->request_action = WPA_GET_BE16(pos);
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
-			   tlv->request_action);
-		break;
-	case EAP_TLV_PAC_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
-		if (tlv->pac) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "PAC TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->pac = pos;
-		tlv->pac_len = len;
-		break;
-	default:
-		/* Unknown TLV */
-		return -1;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_fast_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_fast_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_fast_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_fast_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,298 @@
+/*
+ * EAP-FAST common helper functions (RFC 4851)
+ * Copyright (c) 2008, Jouni Malinen <j at 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_defs.h"
+#include "eap_tlv_common.h"
+#include "eap_fast_common.h"
+
+
+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
+{
+	struct pac_tlv_hdr hdr;
+	hdr.type = host_to_be16(type);
+	hdr.len = host_to_be16(len);
+	wpabuf_put_data(buf, &hdr, sizeof(hdr));
+}
+
+
+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
+			     u16 len)
+{
+	eap_fast_put_tlv_hdr(buf, type, len);
+	wpabuf_put_data(buf, data, len);
+}
+
+
+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
+				 const struct wpabuf *data)
+{
+	eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
+	wpabuf_put_buf(buf, data);
+}
+
+
+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
+{
+	struct wpabuf *e;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
+	e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
+	if (e == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+			   "for TLV encapsulation");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	eap_fast_put_tlv_buf(e,
+			     EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
+			     buf);
+	wpabuf_free(buf);
+	return e;
+}
+
+
+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
+				   const u8 *client_random, u8 *master_secret)
+{
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+		    client_random, TLS_RANDOM_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+		    server_random, TLS_RANDOM_LEN);
+
+	/*
+	 * RFC 4851, Section 5.1:
+	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
+	 *                       server_random + client_random, 48)
+	 */
+	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
+		   "PAC to master secret label hash",
+		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+			master_secret, TLS_MASTER_SECRET_LEN);
+}
+
+
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
+			 const char *label, size_t len)
+{
+	struct tls_keys keys;
+	u8 *rnd = NULL, *out;
+	int block_size;
+
+	block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
+	if (block_size < 0)
+		return NULL;
+
+	out = os_malloc(block_size + len);
+	if (out == NULL)
+		return NULL;
+
+	if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
+	    == 0) {
+		os_memmove(out, out + block_size, len);
+		return out;
+	}
+
+	if (tls_connection_get_keys(ssl_ctx, conn, &keys))
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+
+	os_memcpy(rnd, keys.server_random, keys.server_random_len);
+	os_memcpy(rnd + keys.server_random_len, keys.client_random,
+		  keys.client_random_len);
+
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
+			"expansion", keys.master_key, keys.master_key_len);
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, block_size + len))
+		goto fail;
+	os_free(rnd);
+	os_memmove(out, out + block_size, len);
+	return out;
+
+fail:
+	os_free(rnd);
+	os_free(out);
+	return NULL;
+}
+
+
+void 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);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+			msk, EAP_FAST_KEY_LEN);
+}
+
+
+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+{
+	/*
+	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+	 * EMSK = T-PRF(S-IMCK[j],
+	 *        "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);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+			emsk, EAP_EMSK_LEN);
+}
+
+
+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+		       int tlv_type, u8 *pos, int len)
+{
+	switch (tlv_type) {
+	case EAP_TLV_EAP_PAYLOAD_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
+			    pos, len);
+		if (tlv->eap_payload_tlv) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "EAP-Payload TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->eap_payload_tlv = pos;
+		tlv->eap_payload_tlv_len = len;
+		break;
+	case EAP_TLV_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
+		if (tlv->result) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Result TLV in the message");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Result TLV");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->result = WPA_GET_BE16(pos);
+		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->result != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
+				   tlv->result);
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
+			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
+			    pos, len);
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Intermediate-Result TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		if (tlv->iresult) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Intermediate-Result TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->iresult = WPA_GET_BE16(pos);
+		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
+				   "Result %d", tlv->iresult);
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
+			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_CRYPTO_BINDING_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
+			    pos, len);
+		if (tlv->crypto_binding) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Crypto-Binding TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
+		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Crypto-Binding TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
+			(pos - sizeof(struct eap_tlv_hdr));
+		break;
+	case EAP_TLV_REQUEST_ACTION_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
+			    pos, len);
+		if (tlv->request_action) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Request-Action TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Request-Action TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->request_action = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
+			   tlv->request_action);
+		break;
+	case EAP_TLV_PAC_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
+		if (tlv->pac) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "PAC TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->pac = pos;
+		tlv->pac_len = len;
+		break;
+	default:
+		/* Unknown TLV */
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_fast_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_fast_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_fast_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,113 +0,0 @@
-/*
- * EAP-FAST definitions (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_FAST_H
-#define EAP_FAST_H
-
-#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,
-			 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);
-int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
-		       int tlv_type, u8 *pos, int len);
-
-#endif /* EAP_FAST_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_fast_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_fast_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_fast_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_fast_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,107 @@
+/*
+ * EAP-FAST definitions (RFC 4851)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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
+
+#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,
+			 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);
+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+		       int tlv_type, u8 *pos, int len);
+
+#endif /* EAP_FAST_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_gpsk_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,423 +0,0 @@
-/*
- * EAP server/peer: EAP-GPSK shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/sha256.h"
-#include "eap_defs.h"
-#include "eap_gpsk_common.h"
-
-
-/**
- * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
- * @vendor: CSuite/Vendor
- * @specifier: CSuite/Specifier
- * Returns: 1 if ciphersuite is support, or 0 if not
- */
-int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
-{
-	if (vendor == EAP_GPSK_VENDOR_IETF &&
-	    specifier == EAP_GPSK_CIPHER_AES)
-		return 1;
-#ifdef EAP_GPSK_SHA256
-	if (vendor == EAP_GPSK_VENDOR_IETF &&
-	    specifier == EAP_GPSK_CIPHER_SHA256)
-		return 1;
-#endif /* EAP_GPSK_SHA256 */
-	return 0;
-}
-
-
-static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */,
-			      const u8 *data /* Z */, size_t data_len,
-			      u8 *buf, size_t len /* X */)
-{
-	u8 *opos;
-	size_t i, n, hashlen, left, clen;
-	u8 ibuf[2], hash[16];
-	const u8 *addr[2];
-	size_t vlen[2];
-
-	hashlen = sizeof(hash);
-	/* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */
-	addr[0] = ibuf;
-	vlen[0] = sizeof(ibuf);
-	addr[1] = data;
-	vlen[1] = data_len;
-
-	opos = buf;
-	left = len;
-	n = (len + hashlen - 1) / hashlen;
-	for (i = 1; i <= n; i++) {
-		WPA_PUT_BE16(ibuf, i);
-		if (omac1_aes_128_vector(psk, 2, addr, vlen, hash))
-			return -1;
-		clen = left > hashlen ? hashlen : left;
-		os_memcpy(opos, hash, clen);
-		opos += clen;
-		left -= clen;
-	}
-
-	return 0;
-}
-
-
-#ifdef EAP_GPSK_SHA256
-static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
-				const u8 *data /* Z */, size_t data_len,
-				u8 *buf, size_t len /* X */)
-{
-	u8 *opos;
-	size_t i, n, hashlen, left, clen;
-	u8 ibuf[2], hash[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t vlen[2];
-
-	hashlen = SHA256_MAC_LEN;
-	/* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */
-	addr[0] = ibuf;
-	vlen[0] = sizeof(ibuf);
-	addr[1] = data;
-	vlen[1] = data_len;
-
-	opos = buf;
-	left = len;
-	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);
-		clen = left > hashlen ? hashlen : left;
-		os_memcpy(opos, hash, clen);
-		opos += clen;
-		left -= clen;
-	}
-
-	return 0;
-}
-#endif /* EAP_GPSK_SHA256 */
-
-
-static int eap_gpsk_derive_keys_helper(u32 csuite_specifier,
-				       u8 *kdf_out, size_t kdf_out_len,
-				       const u8 *psk, size_t psk_len,
-				       const u8 *seed, size_t seed_len,
-				       u8 *msk, u8 *emsk,
-				       u8 *sk, size_t sk_len,
-				       u8 *pk, size_t pk_len)
-{
-	u8 mk[32], *pos, *data;
-	size_t data_len, mk_len;
-	int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
-		    u8 *buf, size_t len);
-
-	gkdf = NULL;
-	switch (csuite_specifier) {
-	case EAP_GPSK_CIPHER_AES:
-		gkdf = eap_gpsk_gkdf_cmac;
-		mk_len = 16;
-		break;
-#ifdef EAP_GPSK_SHA256
-	case EAP_GPSK_CIPHER_SHA256:
-		gkdf = eap_gpsk_gkdf_sha256;
-		mk_len = SHA256_MAC_LEN;
-		break;
-#endif /* EAP_GPSK_SHA256 */
-	default:
-		return -1;
-	}
-
-	if (psk_len < mk_len)
-		return -1;
-
-	data_len = 2 + psk_len + 6 + seed_len;
-	data = os_malloc(data_len);
-	if (data == NULL)
-		return -1;
-	pos = data;
-	WPA_PUT_BE16(pos, psk_len);
-	pos += 2;
-	os_memcpy(pos, psk, psk_len);
-	pos += psk_len;
-	WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
-	pos += 4;
-	WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
-	pos += 2;
-	os_memcpy(pos, seed, seed_len); /* inputString */
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation",
-			data, data_len);
-
-	if (gkdf(psk, data, data_len, mk, mk_len) < 0) {
-		os_free(data);
-		return -1;
-	}
-	os_free(data);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len);
-
-	if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0)
-		return -1;
-
-	pos = kdf_out;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
-	os_memcpy(msk, pos, EAP_MSK_LEN);
-	pos += EAP_MSK_LEN;
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
-	os_memcpy(emsk, pos, EAP_EMSK_LEN);
-	pos += EAP_EMSK_LEN;
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len);
-	os_memcpy(sk, pos, sk_len);
-	pos += sk_len;
-
-	if (pk) {
-		wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len);
-		os_memcpy(pk, pos, pk_len);
-	}
-
-	return 0;
-}
-
-
-static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
-				    const u8 *seed, size_t seed_len,
-				    u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
-				    u8 *pk, size_t *pk_len)
-{
-#define EAP_GPSK_SK_LEN_AES 16
-#define EAP_GPSK_PK_LEN_AES 16
-	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
-		   EAP_GPSK_PK_LEN_AES];
-
-	/*
-	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
-	 *            (= seed)
-	 * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001
-	 * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString)
-	 * MSK = GKDF-160 (MK, inputString)[0..63]
-	 * EMSK = GKDF-160 (MK, inputString)[64..127]
-	 * SK = GKDF-160 (MK, inputString)[128..143]
-	 * PK = GKDF-160 (MK, inputString)[144..159]
-	 * zero = 0x00 || 0x00 || ... || 0x00 (16 times)
-	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
-	 *                      CSuite_Sel || inputString)
-	 */
-
-	*sk_len = EAP_GPSK_SK_LEN_AES;
-	*pk_len = EAP_GPSK_PK_LEN_AES;
-
-	return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES,
-					   kdf_out, sizeof(kdf_out),
-					   psk, psk_len, seed, seed_len,
-					   msk, emsk, sk, *sk_len,
-					   pk, *pk_len);
-}
-
-
-#ifdef EAP_GPSK_SHA256
-static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
-				       const u8 *seed, size_t seed_len,
-				       u8 *msk, u8 *emsk,
-				       u8 *sk, size_t *sk_len)
-{
-#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
-#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
-	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
-		   EAP_GPSK_PK_LEN_SHA256];
-
-	/*
-	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
-	 *            (= seed)
-	 * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002
-	 * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString)
-	 * MSK = GKDF-160 (MK, inputString)[0..63]
-	 * EMSK = GKDF-160 (MK, inputString)[64..127]
-	 * SK = GKDF-160 (MK, inputString)[128..159]
-	 * zero = 0x00 || 0x00 || ... || 0x00 (32 times)
-	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
-	 *                      CSuite_Sel || inputString)
-	 */
-
-	*sk_len = EAP_GPSK_SK_LEN_SHA256;
-
-	return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256,
-					   kdf_out, sizeof(kdf_out),
-					   psk, psk_len, seed, seed_len,
-					   msk, emsk, sk, *sk_len,
-					   NULL, 0);
-}
-#endif /* EAP_GPSK_SHA256 */
-
-
-/**
- * eap_gpsk_derive_keys - Derive EAP-GPSK keys
- * @psk: Pre-shared key
- * @psk_len: Length of psk in bytes
- * @vendor: CSuite/Vendor
- * @specifier: CSuite/Specifier
- * @rand_peer: 32-byte RAND_Peer
- * @rand_server: 32-byte RAND_Server
- * @id_peer: ID_Peer
- * @id_peer_len: Length of ID_Peer
- * @id_server: ID_Server
- * @id_server_len: Length of ID_Server
- * @msk: Buffer for 64-byte MSK
- * @emsk: Buffer for 64-byte EMSK
- * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
- * @sk_len: Buffer for returning length of SK
- * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes)
- * @pk_len: Buffer for returning length of PK
- * Returns: 0 on success, -1 on failure
- */
-int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
-			 int specifier,
-			 const u8 *rand_peer, const u8 *rand_server,
-			 const u8 *id_peer, size_t id_peer_len,
-			 const u8 *id_server, size_t id_server_len,
-			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
-			 u8 *pk, size_t *pk_len)
-{
-	u8 *seed, *pos;
-	size_t seed_len;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
-		   vendor, specifier);
-
-	if (vendor != EAP_GPSK_VENDOR_IETF)
-		return -1;
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
-
-	/* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */
-	seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
-	seed = os_malloc(seed_len);
-	if (seed == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
-			   "for key derivation");
-		return -1;
-	}
-
-	pos = seed;
-	os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
-	pos += EAP_GPSK_RAND_LEN;
-	os_memcpy(pos, id_peer, id_peer_len);
-	pos += id_peer_len;
-	os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
-	pos += EAP_GPSK_RAND_LEN;
-	os_memcpy(pos, id_server, id_server_len);
-	pos += id_server_len;
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
-
-	switch (specifier) {
-	case EAP_GPSK_CIPHER_AES:
-		ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
-					       msk, emsk, sk, sk_len,
-					       pk, pk_len);
-		break;
-#ifdef EAP_GPSK_SHA256
-	case EAP_GPSK_CIPHER_SHA256:
-		ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
-						  msk, emsk, sk, sk_len);
-		break;
-#endif /* EAP_GPSK_SHA256 */
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
-			   "key derivation", vendor, specifier);
-		ret = -1;
-		break;
-	}
-
-	os_free(seed);
-
-	return ret;
-}
-
-
-/**
- * eap_gpsk_mic_len - Get the length of the MIC
- * @vendor: CSuite/Vendor
- * @specifier: CSuite/Specifier
- * Returns: MIC length in bytes
- */
-size_t eap_gpsk_mic_len(int vendor, int specifier)
-{
-	if (vendor != EAP_GPSK_VENDOR_IETF)
-		return 0;
-
-	switch (specifier) {
-	case EAP_GPSK_CIPHER_AES:
-		return 16;
-#ifdef EAP_GPSK_SHA256
-	case EAP_GPSK_CIPHER_SHA256:
-		return 32;
-#endif /* EAP_GPSK_SHA256 */
-	default:
-		return 0;
-	}
-}
-
-
-static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
-				    const u8 *data, size_t len, u8 *mic)
-{
-	if (sk_len != 16) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for "
-			   "AES-CMAC MIC", (unsigned long) sk_len);
-		return -1;
-	}
-
-	return omac1_aes_128(sk, data, len, mic);
-}
-
-
-/**
- * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
- * @sk: Session key SK from eap_gpsk_derive_keys()
- * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
- * @vendor: CSuite/Vendor
- * @specifier: CSuite/Specifier
- * @data: Input data to MIC
- * @len: Input data length in bytes
- * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
- * Returns: 0 on success, -1 on failure
- */
-int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
-			 int specifier, const u8 *data, size_t len, u8 *mic)
-{
-	int ret;
-
-	if (vendor != EAP_GPSK_VENDOR_IETF)
-		return -1;
-
-	switch (specifier) {
-	case EAP_GPSK_CIPHER_AES:
-		ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
-		break;
-#ifdef EAP_GPSK_SHA256
-	case EAP_GPSK_CIPHER_SHA256:
-		hmac_sha256(sk, sk_len, data, len, mic);
-		ret = 0;
-		break;
-#endif /* EAP_GPSK_SHA256 */
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
-			   "MIC computation", vendor, specifier);
-		ret = -1;
-		break;
-	}
-
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_gpsk_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_gpsk_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,417 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/sha256.h"
+#include "eap_defs.h"
+#include "eap_gpsk_common.h"
+
+
+/**
+ * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: 1 if ciphersuite is support, or 0 if not
+ */
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
+{
+	if (vendor == EAP_GPSK_VENDOR_IETF &&
+	    specifier == EAP_GPSK_CIPHER_AES)
+		return 1;
+#ifdef EAP_GPSK_SHA256
+	if (vendor == EAP_GPSK_VENDOR_IETF &&
+	    specifier == EAP_GPSK_CIPHER_SHA256)
+		return 1;
+#endif /* EAP_GPSK_SHA256 */
+	return 0;
+}
+
+
+static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */,
+			      const u8 *data /* Z */, size_t data_len,
+			      u8 *buf, size_t len /* X */)
+{
+	u8 *opos;
+	size_t i, n, hashlen, left, clen;
+	u8 ibuf[2], hash[16];
+	const u8 *addr[2];
+	size_t vlen[2];
+
+	hashlen = sizeof(hash);
+	/* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */
+	addr[0] = ibuf;
+	vlen[0] = sizeof(ibuf);
+	addr[1] = data;
+	vlen[1] = data_len;
+
+	opos = buf;
+	left = len;
+	n = (len + hashlen - 1) / hashlen;
+	for (i = 1; i <= n; i++) {
+		WPA_PUT_BE16(ibuf, i);
+		if (omac1_aes_128_vector(psk, 2, addr, vlen, hash))
+			return -1;
+		clen = left > hashlen ? hashlen : left;
+		os_memcpy(opos, hash, clen);
+		opos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+
+
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
+				const u8 *data /* Z */, size_t data_len,
+				u8 *buf, size_t len /* X */)
+{
+	u8 *opos;
+	size_t i, n, hashlen, left, clen;
+	u8 ibuf[2], hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t vlen[2];
+
+	hashlen = SHA256_MAC_LEN;
+	/* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */
+	addr[0] = ibuf;
+	vlen[0] = sizeof(ibuf);
+	addr[1] = data;
+	vlen[1] = data_len;
+
+	opos = buf;
+	left = len;
+	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);
+		clen = left > hashlen ? hashlen : left;
+		os_memcpy(opos, hash, clen);
+		opos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+static int eap_gpsk_derive_keys_helper(u32 csuite_specifier,
+				       u8 *kdf_out, size_t kdf_out_len,
+				       const u8 *psk, size_t psk_len,
+				       const u8 *seed, size_t seed_len,
+				       u8 *msk, u8 *emsk,
+				       u8 *sk, size_t sk_len,
+				       u8 *pk, size_t pk_len)
+{
+	u8 mk[32], *pos, *data;
+	size_t data_len, mk_len;
+	int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
+		    u8 *buf, size_t len);
+
+	gkdf = NULL;
+	switch (csuite_specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		gkdf = eap_gpsk_gkdf_cmac;
+		mk_len = 16;
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		gkdf = eap_gpsk_gkdf_sha256;
+		mk_len = SHA256_MAC_LEN;
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		return -1;
+	}
+
+	if (psk_len < mk_len)
+		return -1;
+
+	data_len = 2 + psk_len + 6 + seed_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	WPA_PUT_BE16(pos, psk_len);
+	pos += 2;
+	os_memcpy(pos, psk, psk_len);
+	pos += psk_len;
+	WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+	pos += 4;
+	WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+	pos += 2;
+	os_memcpy(pos, seed, seed_len); /* inputString */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation",
+			data, data_len);
+
+	if (gkdf(psk, data, data_len, mk, mk_len) < 0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len);
+
+	if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0)
+		return -1;
+
+	pos = kdf_out;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	pos += EAP_EMSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len);
+	os_memcpy(sk, pos, sk_len);
+	pos += sk_len;
+
+	if (pk) {
+		wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len);
+		os_memcpy(pk, pos, pk_len);
+	}
+
+	return 0;
+}
+
+
+static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
+				    const u8 *seed, size_t seed_len,
+				    u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+				    u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_AES 16
+#define EAP_GPSK_PK_LEN_AES 16
+	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
+		   EAP_GPSK_PK_LEN_AES];
+
+	/*
+	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+	 *            (= seed)
+	 * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001
+	 * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString)
+	 * MSK = GKDF-160 (MK, inputString)[0..63]
+	 * EMSK = GKDF-160 (MK, inputString)[64..127]
+	 * SK = GKDF-160 (MK, inputString)[128..143]
+	 * PK = GKDF-160 (MK, inputString)[144..159]
+	 * zero = 0x00 || 0x00 || ... || 0x00 (16 times)
+	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+	 *                      CSuite_Sel || inputString)
+	 */
+
+	*sk_len = EAP_GPSK_SK_LEN_AES;
+	*pk_len = EAP_GPSK_PK_LEN_AES;
+
+	return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES,
+					   kdf_out, sizeof(kdf_out),
+					   psk, psk_len, seed, seed_len,
+					   msk, emsk, sk, *sk_len,
+					   pk, *pk_len);
+}
+
+
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
+				       const u8 *seed, size_t seed_len,
+				       u8 *msk, u8 *emsk,
+				       u8 *sk, size_t *sk_len)
+{
+#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
+#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
+	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
+		   EAP_GPSK_PK_LEN_SHA256];
+
+	/*
+	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+	 *            (= seed)
+	 * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002
+	 * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString)
+	 * MSK = GKDF-160 (MK, inputString)[0..63]
+	 * EMSK = GKDF-160 (MK, inputString)[64..127]
+	 * SK = GKDF-160 (MK, inputString)[128..159]
+	 * zero = 0x00 || 0x00 || ... || 0x00 (32 times)
+	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+	 *                      CSuite_Sel || inputString)
+	 */
+
+	*sk_len = EAP_GPSK_SK_LEN_SHA256;
+
+	return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256,
+					   kdf_out, sizeof(kdf_out),
+					   psk, psk_len, seed, seed_len,
+					   msk, emsk, sk, *sk_len,
+					   NULL, 0);
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+/**
+ * eap_gpsk_derive_keys - Derive EAP-GPSK keys
+ * @psk: Pre-shared key
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_peer: 32-byte RAND_Peer
+ * @rand_server: 32-byte RAND_Server
+ * @id_peer: ID_Peer
+ * @id_peer_len: Length of ID_Peer
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
+ * @sk_len: Buffer for returning length of SK
+ * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes)
+ * @pk_len: Buffer for returning length of PK
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+			 int specifier,
+			 const u8 *rand_peer, const u8 *rand_server,
+			 const u8 *id_peer, size_t id_peer_len,
+			 const u8 *id_server, size_t id_server_len,
+			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+			 u8 *pk, size_t *pk_len)
+{
+	u8 *seed, *pos;
+	size_t seed_len;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
+		   vendor, specifier);
+
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return -1;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+	/* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */
+	seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
+	seed = os_malloc(seed_len);
+	if (seed == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+			   "for key derivation");
+		return -1;
+	}
+
+	pos = seed;
+	os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	os_memcpy(pos, id_peer, id_peer_len);
+	pos += id_peer_len;
+	os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	os_memcpy(pos, id_server, id_server_len);
+	pos += id_server_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+					       msk, emsk, sk, sk_len,
+					       pk, pk_len);
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+						  msk, emsk, sk, sk_len);
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+			   "key derivation", vendor, specifier);
+		ret = -1;
+		break;
+	}
+
+	os_free(seed);
+
+	return ret;
+}
+
+
+/**
+ * eap_gpsk_mic_len - Get the length of the MIC
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: MIC length in bytes
+ */
+size_t eap_gpsk_mic_len(int vendor, int specifier)
+{
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return 0;
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		return 16;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		return 32;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		return 0;
+	}
+}
+
+
+static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
+				    const u8 *data, size_t len, u8 *mic)
+{
+	if (sk_len != 16) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for "
+			   "AES-CMAC MIC", (unsigned long) sk_len);
+		return -1;
+	}
+
+	return omac1_aes_128(sk, data, len, mic);
+}
+
+
+/**
+ * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
+ * @sk: Session key SK from eap_gpsk_derive_keys()
+ * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @data: Input data to MIC
+ * @len: Input data length in bytes
+ * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+			 int specifier, const u8 *data, size_t len, u8 *mic)
+{
+	int ret;
+
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return -1;
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		hmac_sha256(sk, sk_len, data, len, mic);
+		ret = 0;
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+			   "MIC computation", vendor, specifier);
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_gpsk_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,66 +0,0 @@
-/*
- * EAP server/peer: EAP-GPSK shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_GPSK_COMMON_H
-#define EAP_GPSK_COMMON_H
-
-#define EAP_GPSK_OPCODE_GPSK_1 1
-#define EAP_GPSK_OPCODE_GPSK_2 2
-#define EAP_GPSK_OPCODE_GPSK_3 3
-#define EAP_GPSK_OPCODE_GPSK_4 4
-#define EAP_GPSK_OPCODE_FAIL 5
-#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6
-
-/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */
-#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001
-#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002
-#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003
-
-#define EAP_GPSK_RAND_LEN 32
-#define EAP_GPSK_MAX_SK_LEN 32
-#define EAP_GPSK_MAX_PK_LEN 32
-#define EAP_GPSK_MAX_MIC_LEN 32
-
-#define EAP_GPSK_VENDOR_IETF		0x00000000
-#define EAP_GPSK_CIPHER_RESERVED	0x000000
-#define EAP_GPSK_CIPHER_AES		0x000001
-#define EAP_GPSK_CIPHER_SHA256		0x000002
-
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_gpsk_csuite {
-	u8 vendor[4];
-	u8 specifier[2];
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-int eap_gpsk_supported_ciphersuite(int vendor, int specifier);
-int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
-			 int specifier,
-			 const u8 *rand_client, const u8 *rand_server,
-			 const u8 *id_client, size_t id_client_len,
-			 const u8 *id_server, size_t id_server_len,
-			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
-			 u8 *pk, size_t *pk_len);
-size_t eap_gpsk_mic_len(int vendor, int specifier);
-int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
-			 int specifier, const u8 *data, size_t len, u8 *mic);
-
-#endif /* EAP_GPSK_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_gpsk_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_gpsk_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,60 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_GPSK_COMMON_H
+#define EAP_GPSK_COMMON_H
+
+#define EAP_GPSK_OPCODE_GPSK_1 1
+#define EAP_GPSK_OPCODE_GPSK_2 2
+#define EAP_GPSK_OPCODE_GPSK_3 3
+#define EAP_GPSK_OPCODE_GPSK_4 4
+#define EAP_GPSK_OPCODE_FAIL 5
+#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6
+
+/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */
+#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001
+#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002
+#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003
+
+#define EAP_GPSK_RAND_LEN 32
+#define EAP_GPSK_MAX_SK_LEN 32
+#define EAP_GPSK_MAX_PK_LEN 32
+#define EAP_GPSK_MAX_MIC_LEN 32
+
+#define EAP_GPSK_VENDOR_IETF		0x00000000
+#define EAP_GPSK_CIPHER_RESERVED	0x000000
+#define EAP_GPSK_CIPHER_AES		0x000001
+#define EAP_GPSK_CIPHER_SHA256		0x000002
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_gpsk_csuite {
+	u8 vendor[4];
+	u8 specifier[2];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier);
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+			 int specifier,
+			 const u8 *rand_client, const u8 *rand_server,
+			 const u8 *id_client, size_t id_client_len,
+			 const u8 *id_server, size_t id_server_len,
+			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+			 u8 *pk, size_t *pk_len);
+size_t eap_gpsk_mic_len(int vendor, int specifier);
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+			 int specifier, const u8 *data, size_t len, u8 *mic);
+
+#endif /* EAP_GPSK_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_ikev2_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,132 +0,0 @@
-/*
- * EAP-IKEv2 common routines
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_defs.h"
-#include "eap_common.h"
-#include "ikev2_common.h"
-#include "eap_ikev2_common.h"
-
-
-int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
-			    const u8 *i_nonce, size_t i_nonce_len,
-			    const u8 *r_nonce, size_t r_nonce_len,
-			    u8 *keymat)
-{
-	u8 *nonces;
-	size_t nlen;
-
-	/* KEYMAT = prf+(SK_d, Ni | Nr) */
-	if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
-		return -1;
-
-	nlen = i_nonce_len + r_nonce_len;
-	nonces = os_malloc(nlen);
-	if (nonces == NULL)
-		return -1;
-	os_memcpy(nonces, i_nonce, i_nonce_len);
-	os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
-
-	if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
-			   keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
-		os_free(nonces);
-		return -1;
-	}
-	os_free(nonces);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
-			keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
-
-	return 0;
-}
-
-
-struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
-{
-	struct wpabuf *msg;
-
-#ifdef CCNS_PL
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
-			   "for fragment ack");
-		return NULL;
-	}
-	wpabuf_put_u8(msg, 0); /* Flags */
-#else /* CCNS_PL */
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
-			   "for fragment ack");
-		return NULL;
-	}
-#endif /* CCNS_PL */
-
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
-
-	return msg;
-}
-
-
-int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
-			   int initiator, const struct wpabuf *msg,
-			   const u8 *pos, const u8 *end)
-{
-	const struct ikev2_integ_alg *integ;
-	size_t icv_len;
-	u8 icv[IKEV2_MAX_HASH_LEN];
-	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
-
-	integ = ikev2_get_integ(integ_alg);
-	if (integ == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
-			   "transform / cannot validate ICV");
-		return -1;
-	}
-	icv_len = integ->hash_len;
-
-	if (end - pos < (int) icv_len) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
-			   "message for Integrity Checksum Data");
-		return -1;
-	}
-
-	if (SK_a == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
-		return -1;
-	}
-
-	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
-			     wpabuf_head(msg),
-			     wpabuf_len(msg) - icv_len, icv) < 0) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
-		return -1;
-	}
-
-	if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
-		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
-			    icv, icv_len);
-		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
-			    end - icv_len, icv_len);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
-		   "the received message");
-
-	return icv_len;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_ikev2_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_ikev2_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,126 @@
+/*
+ * EAP-IKEv2 common routines
+ * Copyright (c) 2007, Jouni Malinen <j at 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 "eap_defs.h"
+#include "eap_common.h"
+#include "ikev2_common.h"
+#include "eap_ikev2_common.h"
+
+
+int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
+			    const u8 *i_nonce, size_t i_nonce_len,
+			    const u8 *r_nonce, size_t r_nonce_len,
+			    u8 *keymat)
+{
+	u8 *nonces;
+	size_t nlen;
+
+	/* KEYMAT = prf+(SK_d, Ni | Nr) */
+	if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL)
+		return -1;
+
+	nlen = i_nonce_len + r_nonce_len;
+	nonces = os_malloc(nlen);
+	if (nonces == NULL)
+		return -1;
+	os_memcpy(nonces, i_nonce, i_nonce_len);
+	os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len);
+
+	if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen,
+			   keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) {
+		os_free(nonces);
+		return -1;
+	}
+	os_free(nonces);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT",
+			keymat, EAP_MSK_LEN + EAP_EMSK_LEN);
+
+	return 0;
+}
+
+
+struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+#ifdef CCNS_PL
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+	wpabuf_put_u8(msg, 0); /* Flags */
+#else /* CCNS_PL */
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+#endif /* CCNS_PL */
+
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
+
+	return msg;
+}
+
+
+int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
+			   int initiator, const struct wpabuf *msg,
+			   const u8 *pos, const u8 *end)
+{
+	const struct ikev2_integ_alg *integ;
+	size_t icv_len;
+	u8 icv[IKEV2_MAX_HASH_LEN];
+	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
+
+	integ = ikev2_get_integ(integ_alg);
+	if (integ == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
+			   "transform / cannot validate ICV");
+		return -1;
+	}
+	icv_len = integ->hash_len;
+
+	if (end - pos < (int) icv_len) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the "
+			   "message for Integrity Checksum Data");
+		return -1;
+	}
+
+	if (SK_a == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation");
+		return -1;
+	}
+
+	if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len,
+			     wpabuf_head(msg),
+			     wpabuf_len(msg) - icv_len, icv) < 0) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV");
+		return -1;
+	}
+
+	if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
+		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
+			    icv, icv_len);
+		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV",
+			    end - icv_len, icv_len);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in "
+		   "the received message");
+
+	return icv_len;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_ikev2_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,42 +0,0 @@
-/*
- * EAP-IKEv2 definitions
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_IKEV2_COMMON_H
-#define EAP_IKEV2_COMMON_H
-
-#ifdef CCNS_PL
-/* incorrect bit order */
-#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
-#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
-#define IKEV2_FLAGS_ICV_INCLUDED 0x04
-#else /* CCNS_PL */
-#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
-#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
-#define IKEV2_FLAGS_ICV_INCLUDED 0x20
-#endif /* CCNS_PL */
-
-#define IKEV2_FRAGMENT_SIZE 1400
-
-struct ikev2_keys;
-
-int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
-			    const u8 *i_nonce, size_t i_nonce_len,
-			    const u8 *r_nonce, size_t r_nonce_len,
-			    u8 *keymat);
-struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code);
-int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
-			   int initiator, const struct wpabuf *msg,
-			   const u8 *pos, const u8 *end);
-
-#endif /* EAP_IKEV2_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_ikev2_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_ikev2_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,36 @@
+/*
+ * EAP-IKEv2 definitions
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_IKEV2_COMMON_H
+#define EAP_IKEV2_COMMON_H
+
+#ifdef CCNS_PL
+/* incorrect bit order */
+#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
+#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
+#define IKEV2_FLAGS_ICV_INCLUDED 0x04
+#else /* CCNS_PL */
+#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
+#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
+#define IKEV2_FLAGS_ICV_INCLUDED 0x20
+#endif /* CCNS_PL */
+
+#define IKEV2_FRAGMENT_SIZE 1400
+
+struct ikev2_keys;
+
+int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
+			    const u8 *i_nonce, size_t i_nonce_len,
+			    const u8 *r_nonce, size_t r_nonce_len,
+			    u8 *keymat);
+struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code);
+int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
+			   int initiator, const struct wpabuf *msg,
+			   const u8 *pos, const u8 *end);
+
+#endif /* EAP_IKEV2_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_pax_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_pax_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_pax_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,150 +0,0 @@
-/*
- * EAP server/peer: EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "eap_pax_common.h"
-
-
-/**
- * eap_pax_kdf - PAX Key Derivation Function
- * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
- * @key: Secret key (X)
- * @key_len: Length of the secret key in bytes
- * @identifier: Public identifier for the key (Y)
- * @entropy: Exchanged entropy to seed the KDF (Z)
- * @entropy_len: Length of the entropy in bytes
- * @output_len: Output len in bytes (W)
- * @output: Buffer for the derived key
- * Returns: 0 on success, -1 failed
- *
- * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
- */
-int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
-		const char *identifier,
-		const u8 *entropy, size_t entropy_len,
-		size_t output_len, u8 *output)
-{
-	u8 mac[SHA1_MAC_LEN];
-	u8 counter, *pos;
-	const u8 *addr[3];
-	size_t len[3];
-	size_t num_blocks, left;
-
-	num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN;
-	if (identifier == NULL || num_blocks >= 255)
-		return -1;
-
-	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
-	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
-		return -1;
-
-	addr[0] = (const u8 *) identifier;
-	len[0] = os_strlen(identifier);
-	addr[1] = entropy;
-	len[1] = entropy_len;
-	addr[2] = &counter;
-	len[2] = 1;
-
-	pos = output;
-	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);
-		os_memcpy(pos, mac, clen);
-		pos += clen;
-		left -= clen;
-	}
-
-	return 0;
-}
-
-
-/**
- * eap_pax_mac - EAP-PAX MAC
- * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
- * @key: Secret key
- * @key_len: Length of the secret key in bytes
- * @data1: Optional data, first block; %NULL if not used
- * @data1_len: Length of data1 in bytes
- * @data2: Optional data, second block; %NULL if not used
- * @data2_len: Length of data2 in bytes
- * @data3: Optional data, third block; %NULL if not used
- * @data3_len: Length of data3 in bytes
- * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes)
- * Returns: 0 on success, -1 on failure
- *
- * Wrapper function to calculate EAP-PAX MAC.
- */
-int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
-		const u8 *data1, size_t data1_len,
-		const u8 *data2, size_t data2_len,
-		const u8 *data3, size_t data3_len,
-		u8 *mac)
-{
-	u8 hash[SHA1_MAC_LEN];
-	const u8 *addr[3];
-	size_t len[3];
-	size_t count;
-
-	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
-	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
-		return -1;
-
-	addr[0] = data1;
-	len[0] = data1_len;
-	addr[1] = data2;
-	len[1] = data2_len;
-	addr[2] = data3;
-	len[2] = data3_len;
-
-	count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
-	hmac_sha1_vector(key, key_len, count, addr, len, hash);
-	os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
-
-	return 0;
-}
-
-
-/**
- * eap_pax_initial_key_derivation - EAP-PAX initial key derivation
- * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
- * @ak: Authentication Key
- * @e: Entropy
- * @mk: Buffer for the derived Master Key
- * @ck: Buffer for the derived Confirmation Key
- * @ick: Buffer for the derived Integrity Check Key
- * Returns: 0 on success, -1 on failure
- */
-int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
-				   u8 *mk, u8 *ck, u8 *ick)
-{
-	wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
-	if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
-			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) ||
-	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
-			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
-	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
-			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
-		return -1;
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_pax_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_pax_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_pax_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_pax_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,144 @@
+/*
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005, Jouni Malinen <j at 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 "eap_pax_common.h"
+
+
+/**
+ * eap_pax_kdf - PAX Key Derivation Function
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @key: Secret key (X)
+ * @key_len: Length of the secret key in bytes
+ * @identifier: Public identifier for the key (Y)
+ * @entropy: Exchanged entropy to seed the KDF (Z)
+ * @entropy_len: Length of the entropy in bytes
+ * @output_len: Output len in bytes (W)
+ * @output: Buffer for the derived key
+ * Returns: 0 on success, -1 failed
+ *
+ * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
+ */
+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
+		const char *identifier,
+		const u8 *entropy, size_t entropy_len,
+		size_t output_len, u8 *output)
+{
+	u8 mac[SHA1_MAC_LEN];
+	u8 counter, *pos;
+	const u8 *addr[3];
+	size_t len[3];
+	size_t num_blocks, left;
+
+	num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN;
+	if (identifier == NULL || num_blocks >= 255)
+		return -1;
+
+	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
+	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
+		return -1;
+
+	addr[0] = (const u8 *) identifier;
+	len[0] = os_strlen(identifier);
+	addr[1] = entropy;
+	len[1] = entropy_len;
+	addr[2] = &counter;
+	len[2] = 1;
+
+	pos = output;
+	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);
+		os_memcpy(pos, mac, clen);
+		pos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_pax_mac - EAP-PAX MAC
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @key: Secret key
+ * @key_len: Length of the secret key in bytes
+ * @data1: Optional data, first block; %NULL if not used
+ * @data1_len: Length of data1 in bytes
+ * @data2: Optional data, second block; %NULL if not used
+ * @data2_len: Length of data2 in bytes
+ * @data3: Optional data, third block; %NULL if not used
+ * @data3_len: Length of data3 in bytes
+ * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Wrapper function to calculate EAP-PAX MAC.
+ */
+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
+		const u8 *data1, size_t data1_len,
+		const u8 *data2, size_t data2_len,
+		const u8 *data3, size_t data3_len,
+		u8 *mac)
+{
+	u8 hash[SHA1_MAC_LEN];
+	const u8 *addr[3];
+	size_t len[3];
+	size_t count;
+
+	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
+	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
+		return -1;
+
+	addr[0] = data1;
+	len[0] = data1_len;
+	addr[1] = data2;
+	len[1] = data2_len;
+	addr[2] = data3;
+	len[2] = data3_len;
+
+	count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
+	hmac_sha1_vector(key, key_len, count, addr, len, hash);
+	os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
+
+	return 0;
+}
+
+
+/**
+ * eap_pax_initial_key_derivation - EAP-PAX initial key derivation
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @ak: Authentication Key
+ * @e: Entropy
+ * @mk: Buffer for the derived Master Key
+ * @ck: Buffer for the derived Confirmation Key
+ * @ick: Buffer for the derived Integrity Check Key
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
+				   u8 *mk, u8 *ck, u8 *ick)
+{
+	wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
+	if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
+			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) ||
+	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
+			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
+	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
+			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
+		return -1;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_pax_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_pax_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_pax_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,97 +0,0 @@
-/*
- * EAP server/peer: EAP-PAX shared routines
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_PAX_COMMON_H
-#define EAP_PAX_COMMON_H
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_pax_hdr {
-	u8 op_code;
-	u8 flags;
-	u8 mac_id;
-	u8 dh_group_id;
-	u8 public_key_id;
-	/* Followed by variable length payload and ICV */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-/* op_code: */
-enum {
-	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
-};
-
-/* flags: */
-#define EAP_PAX_FLAGS_MF			0x01
-#define EAP_PAX_FLAGS_CE			0x02
-#define EAP_PAX_FLAGS_AI			0x04
-
-/* mac_id: */
-#define EAP_PAX_MAC_HMAC_SHA1_128		0x01
-#define EAP_PAX_HMAC_SHA256_128			0x02
-
-/* dh_group_id: */
-#define EAP_PAX_DH_GROUP_NONE			0x00
-#define EAP_PAX_DH_GROUP_2048_MODP		0x01
-#define EAP_PAX_DH_GROUP_3072_MODP		0x02
-#define EAP_PAX_DH_GROUP_NIST_ECC_P_256		0x03
-
-/* public_key_id: */
-#define EAP_PAX_PUBLIC_KEY_NONE			0x00
-#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP		0x01
-#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5	0x02
-#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC	0x03
-
-/* ADE type: */
-#define EAP_PAX_ADE_VENDOR_SPECIFIC		0x01
-#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING	0x02
-#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING	0x03
-
-
-#define EAP_PAX_RAND_LEN 32
-#define EAP_PAX_MAC_LEN 16
-#define EAP_PAX_ICV_LEN 16
-#define EAP_PAX_AK_LEN 16
-#define EAP_PAX_MK_LEN 16
-#define EAP_PAX_CK_LEN 16
-#define EAP_PAX_ICK_LEN 16
-
-
-int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
-		const char *identifier,
-		const u8 *entropy, size_t entropy_len,
-		size_t output_len, u8 *output);
-int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
-		const u8 *data1, size_t data1_len,
-		const u8 *data2, size_t data2_len,
-		const u8 *data3, size_t data3_len,
-		u8 *mac);
-int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
-				   u8 *mk, u8 *ck, u8 *ick);
-
-#endif /* EAP_PAX_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_pax_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_pax_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_pax_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_pax_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,91 @@
+/*
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PAX_COMMON_H
+#define EAP_PAX_COMMON_H
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_pax_hdr {
+	u8 op_code;
+	u8 flags;
+	u8 mac_id;
+	u8 dh_group_id;
+	u8 public_key_id;
+	/* Followed by variable length payload and ICV */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+/* op_code: */
+enum {
+	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
+};
+
+/* flags: */
+#define EAP_PAX_FLAGS_MF			0x01
+#define EAP_PAX_FLAGS_CE			0x02
+#define EAP_PAX_FLAGS_AI			0x04
+
+/* mac_id: */
+#define EAP_PAX_MAC_HMAC_SHA1_128		0x01
+#define EAP_PAX_HMAC_SHA256_128			0x02
+
+/* dh_group_id: */
+#define EAP_PAX_DH_GROUP_NONE			0x00
+#define EAP_PAX_DH_GROUP_2048_MODP		0x01
+#define EAP_PAX_DH_GROUP_3072_MODP		0x02
+#define EAP_PAX_DH_GROUP_NIST_ECC_P_256		0x03
+
+/* public_key_id: */
+#define EAP_PAX_PUBLIC_KEY_NONE			0x00
+#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP		0x01
+#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5	0x02
+#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC	0x03
+
+/* ADE type: */
+#define EAP_PAX_ADE_VENDOR_SPECIFIC		0x01
+#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING	0x02
+#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING	0x03
+
+
+#define EAP_PAX_RAND_LEN 32
+#define EAP_PAX_MAC_LEN 16
+#define EAP_PAX_ICV_LEN 16
+#define EAP_PAX_AK_LEN 16
+#define EAP_PAX_MK_LEN 16
+#define EAP_PAX_CK_LEN 16
+#define EAP_PAX_ICK_LEN 16
+
+
+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
+		const char *identifier,
+		const u8 *entropy, size_t entropy_len,
+		size_t output_len, u8 *output);
+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
+		const u8 *data1, size_t data1_len,
+		const u8 *data2, size_t data2_len,
+		const u8 *data3, size_t data3_len,
+		u8 *mac);
+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
+				   u8 *mk, u8 *ck, u8 *ick);
+
+#endif /* EAP_PAX_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_peap_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_peap_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_peap_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,88 +0,0 @@
-/*
- * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "eap_peap_common.h"
-
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len)
-{
-	unsigned char counter = 0;
-	size_t pos, plen;
-	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = os_strlen(label);
-	u8 extra[2];
-	const unsigned char *addr[5];
-	size_t len[5];
-
-	addr[0] = hash;
-	len[0] = 0;
-	addr[1] = (unsigned char *) label;
-	len[1] = label_len;
-	addr[2] = seed;
-	len[2] = seed_len;
-
-	if (version == 0) {
-		/*
-		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
-		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
-		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
-		 * ...
-		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
-		 */
-
-		extra[0] = 0;
-		extra[1] = 0;
-
-		addr[3] = &counter;
-		len[3] = 1;
-		addr[4] = extra;
-		len[4] = 2;
-	} else {
-		/*
-		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
-		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
-		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
-		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
-		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
-		 *   ...
-		 */
-
-		extra[0] = buf_len & 0xff;
-
-		addr[3] = extra;
-		len[3] = 1;
-		addr[4] = &counter;
-		len[4] = 1;
-	}
-
-	pos = 0;
-	while (pos < buf_len) {
-		counter++;
-		plen = buf_len - pos;
-		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
-		if (plen >= SHA1_MAC_LEN) {
-			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
-			pos += SHA1_MAC_LEN;
-		} else {
-			os_memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		len[0] = SHA1_MAC_LEN;
-	}
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_peap_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_peap_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_peap_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_peap_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,85 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008-2011, Jouni Malinen <j at 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 "eap_peap_common.h"
+
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len)
+{
+	unsigned char counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label);
+	u8 extra[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (unsigned char *) label;
+	len[1] = label_len;
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	if (version == 0) {
+		/*
+		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
+		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
+		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
+		 * ...
+		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
+		 */
+
+		extra[0] = 0;
+		extra[1] = 0;
+
+		addr[3] = &counter;
+		len[3] = 1;
+		addr[4] = extra;
+		len[4] = 2;
+	} else {
+		/*
+		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
+		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
+		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
+		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
+		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
+		 *   ...
+		 */
+
+		extra[0] = buf_len & 0xff;
+
+		addr[3] = extra;
+		len[3] = 1;
+		addr[4] = &counter;
+		len[4] = 1;
+	}
+
+	pos = 0;
+	while (pos < buf_len) {
+		counter++;
+		plen = buf_len - pos;
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+			return -1;
+		if (plen >= SHA1_MAC_LEN) {
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			pos += SHA1_MAC_LEN;
+		} else {
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		len[0] = SHA1_MAC_LEN;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_peap_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_peap_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_peap_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,22 +0,0 @@
-/*
- * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_PEAP_COMMON_H
-#define EAP_PEAP_COMMON_H
-
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len);
-
-#endif /* EAP_PEAP_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_peap_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_peap_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_peap_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_peap_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PEAP_COMMON_H
+#define EAP_PEAP_COMMON_H
+
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len);
+
+#endif /* EAP_PEAP_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_psk_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_psk_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_psk_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,74 +0,0 @@
-/*
- * EAP server/peer: EAP-PSK shared routines
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "eap_defs.h"
-#include "eap_psk_common.h"
-
-#define aes_block_size 16
-
-
-int eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
-{
-	os_memset(ak, 0, aes_block_size);
-	if (aes_128_encrypt_block(psk, ak, ak))
-		return -1;
-	os_memcpy(kdk, ak, aes_block_size);
-	ak[aes_block_size - 1] ^= 0x01;
-	kdk[aes_block_size - 1] ^= 0x02;
-	if (aes_128_encrypt_block(psk, ak, ak) ||
-	    aes_128_encrypt_block(psk, kdk, kdk))
-		return -1;
-	return 0;
-}
-
-
-int eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
-			u8 *emsk)
-{
-	u8 hash[aes_block_size];
-	u8 counter = 1;
-	int i;
-
-	if (aes_128_encrypt_block(kdk, rand_p, hash))
-		return -1;
-
-	hash[aes_block_size - 1] ^= counter;
-	if (aes_128_encrypt_block(kdk, hash, tek))
-		return -1;
-	hash[aes_block_size - 1] ^= counter;
-	counter++;
-
-	for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) {
-		hash[aes_block_size - 1] ^= counter;
-		if (aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]))
-			return -1;
-		hash[aes_block_size - 1] ^= counter;
-		counter++;
-	}
-
-	for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) {
-		hash[aes_block_size - 1] ^= counter;
-		if (aes_128_encrypt_block(kdk, hash,
-					  &emsk[i * aes_block_size]))
-			return -1;
-		hash[aes_block_size - 1] ^= counter;
-		counter++;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_psk_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_psk_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_psk_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_psk_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,68 @@
+/*
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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/aes_wrap.h"
+#include "eap_defs.h"
+#include "eap_psk_common.h"
+
+#define aes_block_size 16
+
+
+int eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
+{
+	os_memset(ak, 0, aes_block_size);
+	if (aes_128_encrypt_block(psk, ak, ak))
+		return -1;
+	os_memcpy(kdk, ak, aes_block_size);
+	ak[aes_block_size - 1] ^= 0x01;
+	kdk[aes_block_size - 1] ^= 0x02;
+	if (aes_128_encrypt_block(psk, ak, ak) ||
+	    aes_128_encrypt_block(psk, kdk, kdk))
+		return -1;
+	return 0;
+}
+
+
+int eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+			u8 *emsk)
+{
+	u8 hash[aes_block_size];
+	u8 counter = 1;
+	int i;
+
+	if (aes_128_encrypt_block(kdk, rand_p, hash))
+		return -1;
+
+	hash[aes_block_size - 1] ^= counter;
+	if (aes_128_encrypt_block(kdk, hash, tek))
+		return -1;
+	hash[aes_block_size - 1] ^= counter;
+	counter++;
+
+	for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) {
+		hash[aes_block_size - 1] ^= counter;
+		if (aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]))
+			return -1;
+		hash[aes_block_size - 1] ^= counter;
+		counter++;
+	}
+
+	for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) {
+		hash[aes_block_size - 1] ^= counter;
+		if (aes_128_encrypt_block(kdk, hash,
+					  &emsk[i * aes_block_size]))
+			return -1;
+		hash[aes_block_size - 1] ^= counter;
+		counter++;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_psk_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_psk_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_psk_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,78 +0,0 @@
-/*
- * EAP server/peer: EAP-PSK shared routines
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_PSK_COMMON_H
-#define EAP_PSK_COMMON_H
-
-
-#define EAP_PSK_RAND_LEN 16
-#define EAP_PSK_MAC_LEN 16
-#define EAP_PSK_TEK_LEN 16
-#define EAP_PSK_PSK_LEN 16
-#define EAP_PSK_AK_LEN 16
-#define EAP_PSK_KDK_LEN 16
-
-#define EAP_PSK_R_FLAG_CONT 1
-#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
-#define EAP_PSK_R_FLAG_DONE_FAILURE 3
-#define EAP_PSK_E_FLAG 0x20
-
-#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6)
-#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6)
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-/* EAP-PSK First Message (AS -> Supplicant) */
-struct eap_psk_hdr_1 {
-	u8 flags;
-	u8 rand_s[EAP_PSK_RAND_LEN];
-	/* Followed by variable length ID_S */
-} STRUCT_PACKED;
-
-/* EAP-PSK Second Message (Supplicant -> AS) */
-struct eap_psk_hdr_2 {
-	u8 flags;
-	u8 rand_s[EAP_PSK_RAND_LEN];
-	u8 rand_p[EAP_PSK_RAND_LEN];
-	u8 mac_p[EAP_PSK_MAC_LEN];
-	/* Followed by variable length ID_P */
-} STRUCT_PACKED;
-
-/* EAP-PSK Third Message (AS -> Supplicant) */
-struct eap_psk_hdr_3 {
-	u8 flags;
-	u8 rand_s[EAP_PSK_RAND_LEN];
-	u8 mac_s[EAP_PSK_MAC_LEN];
-	/* Followed by variable length PCHANNEL */
-} STRUCT_PACKED;
-
-/* EAP-PSK Fourth Message (Supplicant -> AS) */
-struct eap_psk_hdr_4 {
-	u8 flags;
-	u8 rand_s[EAP_PSK_RAND_LEN];
-	/* Followed by variable length PCHANNEL */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
-int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek,
-				     u8 *msk, u8 *emsk);
-
-#endif /* EAP_PSK_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_psk_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_psk_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_psk_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_psk_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,72 @@
+/*
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PSK_COMMON_H
+#define EAP_PSK_COMMON_H
+
+
+#define EAP_PSK_RAND_LEN 16
+#define EAP_PSK_MAC_LEN 16
+#define EAP_PSK_TEK_LEN 16
+#define EAP_PSK_PSK_LEN 16
+#define EAP_PSK_AK_LEN 16
+#define EAP_PSK_KDK_LEN 16
+
+#define EAP_PSK_R_FLAG_CONT 1
+#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
+#define EAP_PSK_R_FLAG_DONE_FAILURE 3
+#define EAP_PSK_E_FLAG 0x20
+
+#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6)
+#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+/* EAP-PSK First Message (AS -> Supplicant) */
+struct eap_psk_hdr_1 {
+	u8 flags;
+	u8 rand_s[EAP_PSK_RAND_LEN];
+	/* Followed by variable length ID_S */
+} STRUCT_PACKED;
+
+/* EAP-PSK Second Message (Supplicant -> AS) */
+struct eap_psk_hdr_2 {
+	u8 flags;
+	u8 rand_s[EAP_PSK_RAND_LEN];
+	u8 rand_p[EAP_PSK_RAND_LEN];
+	u8 mac_p[EAP_PSK_MAC_LEN];
+	/* Followed by variable length ID_P */
+} STRUCT_PACKED;
+
+/* EAP-PSK Third Message (AS -> Supplicant) */
+struct eap_psk_hdr_3 {
+	u8 flags;
+	u8 rand_s[EAP_PSK_RAND_LEN];
+	u8 mac_s[EAP_PSK_MAC_LEN];
+	/* Followed by variable length PCHANNEL */
+} STRUCT_PACKED;
+
+/* EAP-PSK Fourth Message (Supplicant -> AS) */
+struct eap_psk_hdr_4 {
+	u8 flags;
+	u8 rand_s[EAP_PSK_RAND_LEN];
+	/* Followed by variable length PCHANNEL */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
+int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek,
+				     u8 *msk, u8 *emsk);
+
+#endif /* EAP_PSK_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_pwd_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_pwd_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_pwd_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_pwd_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,345 @@
+/*
+ * EAP server/peer: EAP-pwd shared routines
+ * Copyright (c) 2010, Dan Harkins <dharkins at lounge.org>
+ *
+ * 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/sha256.h"
+#include "crypto/crypto.h"
+#include "eap_defs.h"
+#include "eap_pwd_common.h"
+
+/* The random function H(x) = HMAC-SHA256(0^32, x) */
+struct crypto_hash * eap_pwd_h_init(void)
+{
+	u8 allzero[SHA256_MAC_LEN];
+	os_memset(allzero, 0, SHA256_MAC_LEN);
+	return crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256, allzero,
+				SHA256_MAC_LEN);
+}
+
+
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len)
+{
+	crypto_hash_update(hash, data, len);
+}
+
+
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest)
+{
+	size_t len = SHA256_MAC_LEN;
+	crypto_hash_finish(hash, digest, &len);
+}
+
+
+/* a counter-based KDF based on NIST SP800-108 */
+static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
+		       size_t labellen, u8 *result, size_t resultbitlen)
+{
+	struct crypto_hash *hash;
+	u8 digest[SHA256_MAC_LEN];
+	u16 i, ctr, L;
+	size_t resultbytelen, len = 0, mdlen;
+
+	resultbytelen = (resultbitlen + 7) / 8;
+	ctr = 0;
+	L = htons(resultbitlen);
+	while (len < resultbytelen) {
+		ctr++;
+		i = htons(ctr);
+		hash = crypto_hash_init(CRYPTO_HASH_ALG_HMAC_SHA256,
+					key, keylen);
+		if (hash == NULL)
+			return -1;
+		if (ctr > 1)
+			crypto_hash_update(hash, digest, SHA256_MAC_LEN);
+		crypto_hash_update(hash, (u8 *) &i, sizeof(u16));
+		crypto_hash_update(hash, label, labellen);
+		crypto_hash_update(hash, (u8 *) &L, sizeof(u16));
+		mdlen = SHA256_MAC_LEN;
+		if (crypto_hash_finish(hash, digest, &mdlen) < 0)
+			return -1;
+		if ((len + mdlen) > resultbytelen)
+			os_memcpy(result + len, digest, resultbytelen - len);
+		else
+			os_memcpy(result + len, digest, mdlen);
+		len += mdlen;
+	}
+
+	/* since we're expanding to a bit length, mask off the excess */
+	if (resultbitlen % 8) {
+		u8 mask = 0xff;
+		mask <<= (8 - (resultbitlen % 8));
+		result[resultbytelen - 1] &= mask;
+	}
+
+	return 0;
+}
+
+
+/*
+ * compute a "random" secret point on an elliptic curve based
+ * on the password and identities.
+ */
+int compute_password_element(EAP_PWD_group *grp, u16 num,
+			     u8 *password, int password_len,
+			     u8 *id_server, int id_server_len,
+			     u8 *id_peer, int id_peer_len, u8 *token)
+{
+	BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
+	struct crypto_hash *hash;
+	unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
+	int nid, is_odd, ret = 0;
+	size_t primebytelen, primebitlen;
+
+	switch (num) { /* from IANA registry for IKE D-H groups */
+        case 19:
+		nid = NID_X9_62_prime256v1;
+		break;
+        case 20:
+		nid = NID_secp384r1;
+		break;
+        case 21:
+		nid = NID_secp521r1;
+		break;
+        case 25:
+		nid = NID_X9_62_prime192v1;
+		break;
+        case 26:
+		nid = NID_secp224r1;
+		break;
+        default:
+		wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
+		return -1;
+	}
+
+	grp->pwe = NULL;
+	grp->order = NULL;
+	grp->prime = NULL;
+
+	if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
+		goto fail;
+	}
+
+	if (((rnd = BN_new()) == NULL) ||
+	    ((cofactor = BN_new()) == NULL) ||
+	    ((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
+	    ((grp->order = BN_new()) == NULL) ||
+	    ((grp->prime = BN_new()) == NULL) ||
+	    ((x_candidate = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
+		goto fail;
+	}
+
+	if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
+	{
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
+			   "curve");
+		goto fail;
+	}
+	if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
+		goto fail;
+	}
+	if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
+			   "curve");
+		goto fail;
+	}
+	primebitlen = BN_num_bits(grp->prime);
+	primebytelen = BN_num_bytes(grp->prime);
+	if ((prfbuf = os_malloc(primebytelen)) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
+			   "buffer");
+		goto fail;
+	}
+	os_memset(prfbuf, 0, primebytelen);
+	ctr = 0;
+	while (1) {
+		if (ctr > 30) {
+			wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
+				   "point on curve for group %d, something's "
+				   "fishy", num);
+			goto fail;
+		}
+		ctr++;
+
+		/*
+		 * compute counter-mode password value and stretch to prime
+		 *    pwd-seed = H(token | peer-id | server-id | password |
+		 *		   counter)
+		 */
+		hash = eap_pwd_h_init();
+		if (hash == NULL)
+			goto fail;
+		eap_pwd_h_update(hash, token, sizeof(u32));
+		eap_pwd_h_update(hash, id_peer, id_peer_len);
+		eap_pwd_h_update(hash, id_server, id_server_len);
+		eap_pwd_h_update(hash, password, password_len);
+		eap_pwd_h_update(hash, &ctr, sizeof(ctr));
+		eap_pwd_h_final(hash, pwe_digest);
+
+		BN_bin2bn(pwe_digest, SHA256_MAC_LEN, rnd);
+
+		if (eap_pwd_kdf(pwe_digest, SHA256_MAC_LEN,
+				(u8 *) "EAP-pwd Hunting And Pecking",
+				os_strlen("EAP-pwd Hunting And Pecking"),
+				prfbuf, primebitlen) < 0)
+			goto fail;
+
+		BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+		/*
+		 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+		 * BN_bin2bn will treat that string of bits as a big endian
+		 * number. If the primebitlen is not an even multiple of 8
+		 * then excessive bits-- those _after_ primebitlen-- so now
+		 * we have to shift right the amount we masked off.
+		 */
+		if (primebitlen % 8)
+			BN_rshift(x_candidate, x_candidate,
+				  (8 - (primebitlen % 8)));
+
+		if (BN_ucmp(x_candidate, grp->prime) >= 0)
+			continue;
+
+		wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
+			    prfbuf, primebytelen);
+
+		/*
+		 * need to unambiguously identify the solution, if there is
+		 * one...
+		 */
+		if (BN_is_odd(rnd))
+			is_odd = 1;
+		else
+			is_odd = 0;
+
+		/*
+		 * solve the quadratic equation, if it's not solvable then we
+		 * don't have a point
+		 */
+		if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
+							     grp->pwe,
+							     x_candidate,
+							     is_odd, NULL))
+			continue;
+		/*
+		 * If there's a solution to the equation then the point must be
+		 * on the curve so why check again explicitly? OpenSSL code
+		 * says this is required by X9.62. We're not X9.62 but it can't
+		 * hurt just to be sure.
+		 */
+		if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
+			wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
+			continue;
+		}
+
+		if (BN_cmp(cofactor, BN_value_one())) {
+			/* make sure the point is not in a small sub-group */
+			if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
+					  cofactor, NULL)) {
+				wpa_printf(MSG_INFO, "EAP-pwd: cannot "
+					   "multiply generator by order");
+				continue;
+			}
+			if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
+				wpa_printf(MSG_INFO, "EAP-pwd: point is at "
+					   "infinity");
+				continue;
+			}
+		}
+		/* if we got here then we have a new generator. */
+		break;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
+	grp->group_num = num;
+	if (0) {
+ fail:
+		EC_GROUP_free(grp->group);
+		grp->group = NULL;
+		EC_POINT_free(grp->pwe);
+		grp->pwe = NULL;
+		BN_free(grp->order);
+		grp->order = NULL;
+		BN_free(grp->prime);
+		grp->prime = NULL;
+		ret = 1;
+	}
+	/* cleanliness and order.... */
+	BN_free(cofactor);
+	BN_free(x_candidate);
+	BN_free(rnd);
+	os_free(prfbuf);
+
+	return ret;
+}
+
+
+int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
+		 BIGNUM *peer_scalar, BIGNUM *server_scalar,
+		 u8 *confirm_peer, u8 *confirm_server,
+		 u32 *ciphersuite, u8 *msk, u8 *emsk)
+{
+	struct crypto_hash *hash;
+	u8 mk[SHA256_MAC_LEN], *cruft;
+	u8 session_id[SHA256_MAC_LEN + 1];
+	u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
+	int offset;
+
+	if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
+		return -1;
+
+	/*
+	 * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
+	 *	scal_s)
+	 */
+	session_id[0] = EAP_TYPE_PWD;
+	hash = eap_pwd_h_init();
+	if (hash == NULL) {
+		os_free(cruft);
+		return -1;
+	}
+	eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32));
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(peer_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(server_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->order));
+	eap_pwd_h_final(hash, &session_id[1]);
+
+	/* then compute MK = H(k | confirm-peer | confirm-server) */
+	hash = eap_pwd_h_init();
+	if (hash == NULL) {
+		os_free(cruft);
+		return -1;
+	}
+	offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(k, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(grp->prime));
+	os_free(cruft);
+	eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN);
+	eap_pwd_h_update(hash, confirm_server, SHA256_MAC_LEN);
+	eap_pwd_h_final(hash, mk);
+
+	/* stretch the mk with the session-id to get MSK | EMSK */
+	if (eap_pwd_kdf(mk, SHA256_MAC_LEN,
+			session_id, SHA256_MAC_LEN + 1,
+			msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8) < 0) {
+		return -1;
+	}
+
+	os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
+	os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
+
+	return 1;
+}

Copied: vendor/wpa/2.0/src/eap_common/eap_pwd_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_pwd_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_pwd_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_pwd_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,67 @@
+/*
+ * EAP server/peer: EAP-pwd shared definitions
+ * Copyright (c) 2009, Dan Harkins <dharkins at lounge.org>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PWD_COMMON_H
+#define EAP_PWD_COMMON_H
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+/*
+ * definition of a finite cyclic group
+ * TODO: support one based on a prime field
+ */
+typedef struct group_definition_ {
+	u16 group_num;
+	EC_GROUP *group;
+	EC_POINT *pwe;
+	BIGNUM *order;
+	BIGNUM *prime;
+} EAP_PWD_group;
+
+/*
+ * EAP-pwd header, included on all payloads
+ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
+ */
+#define EAP_PWD_HDR_SIZE                1
+
+#define EAP_PWD_OPCODE_ID_EXCH          1
+#define EAP_PWD_OPCODE_COMMIT_EXCH      2
+#define EAP_PWD_OPCODE_CONFIRM_EXCH     3
+#define EAP_PWD_GET_LENGTH_BIT(x)       ((x) & 0x80)
+#define EAP_PWD_SET_LENGTH_BIT(x)       ((x) |= 0x80)
+#define EAP_PWD_GET_MORE_BIT(x)         ((x) & 0x40)
+#define EAP_PWD_SET_MORE_BIT(x)         ((x) |= 0x40)
+#define EAP_PWD_GET_EXCHANGE(x)         ((x) & 0x3f)
+#define EAP_PWD_SET_EXCHANGE(x,y)       ((x) |= (y))
+
+/* EAP-pwd-ID payload */
+struct eap_pwd_id {
+	be16 group_num;
+	u8 random_function;
+#define EAP_PWD_DEFAULT_RAND_FUNC       1
+	u8 prf;
+#define EAP_PWD_DEFAULT_PRF             1
+	u8 token[4];
+	u8 prep;
+#define EAP_PWD_PREP_NONE               0
+#define EAP_PWD_PREP_MS                 1
+	u8 identity[0];     /* length inferred from payload */
+} STRUCT_PACKED;
+
+/* common routines */
+int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
+			     int, u8 *);
+int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
+		 u8 *, u8 *, u32 *, u8 *, u8 *);
+struct crypto_hash * eap_pwd_h_init(void);
+void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
+void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
+
+#endif  /* EAP_PWD_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_sake_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_sake_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_sake_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,393 +0,0 @@
-/*
- * EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpabuf.h"
-#include "crypto/sha1.h"
-#include "eap_defs.h"
-#include "eap_sake_common.h"
-
-
-static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
-				   const u8 *pos)
-{
-	size_t i;
-
-	switch (pos[0]) {
-	case EAP_SAKE_AT_RAND_S:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
-		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
-				   "invalid length %d", pos[1]);
-			return -1;
-		}
-		attr->rand_s = pos + 2;
-		break;
-	case EAP_SAKE_AT_RAND_P:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
-		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
-				   "invalid length %d", pos[1]);
-			return -1;
-		}
-		attr->rand_p = pos + 2;
-		break;
-	case EAP_SAKE_AT_MIC_S:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
-		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
-				   "invalid length %d", pos[1]);
-			return -1;
-		}
-		attr->mic_s = pos + 2;
-		break;
-	case EAP_SAKE_AT_MIC_P:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
-		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
-				   "invalid length %d", pos[1]);
-			return -1;
-		}
-		attr->mic_p = pos + 2;
-		break;
-	case EAP_SAKE_AT_SERVERID:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
-		attr->serverid = pos + 2;
-		attr->serverid_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_PEERID:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
-		attr->peerid = pos + 2;
-		attr->peerid_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_SPI_S:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
-		attr->spi_s = pos + 2;
-		attr->spi_s_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_SPI_P:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
-		attr->spi_p = pos + 2;
-		attr->spi_p_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_ANY_ID_REQ:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
-		if (pos[1] != 4) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
-				   " length %d", pos[1]);
-			return -1;
-		}
-		attr->any_id_req = pos + 2;
-		break;
-	case EAP_SAKE_AT_PERM_ID_REQ:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
-		if (pos[1] != 4) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
-				   "AT_PERM_ID_REQ length %d", pos[1]);
-			return -1;
-		}
-		attr->perm_id_req = pos + 2;
-		break;
-	case EAP_SAKE_AT_ENCR_DATA:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
-		attr->encr_data = pos + 2;
-		attr->encr_data_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_IV:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
-		attr->iv = pos + 2;
-		attr->iv_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_PADDING:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
-		for (i = 2; i < pos[1]; i++) {
-			if (pos[i]) {
-				wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
-					   "with non-zero pad byte");
-				return -1;
-			}
-		}
-		break;
-	case EAP_SAKE_AT_NEXT_TMPID:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
-		attr->next_tmpid = pos + 2;
-		attr->next_tmpid_len = pos[1] - 2;
-		break;
-	case EAP_SAKE_AT_MSK_LIFE:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
-		if (pos[1] != 6) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
-				   "AT_MSK_LIFE length %d", pos[1]);
-			return -1;
-		}
-		attr->msk_life = pos + 2;
-		break;
-	default:
-		if (pos[0] < 128) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
-				   " attribute %d", pos[0]);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
-			   "attribute %d", pos[0]);
-		break;
-	}
-
-	if (attr->iv && !attr->encr_data) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
-			   "AT_ENCR_DATA");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * eap_sake_parse_attributes - Parse EAP-SAKE attributes
- * @buf: Packet payload (starting with the first attribute)
- * @len: Payload length
- * @attr: Structure to be filled with found attributes
- * Returns: 0 on success or -1 on failure
- */
-int eap_sake_parse_attributes(const u8 *buf, size_t len,
-			      struct eap_sake_parse_attr *attr)
-{
-	const u8 *pos = buf, *end = buf + len;
-
-	os_memset(attr, 0, sizeof(*attr));
-	while (pos < end) {
-		if (end - pos < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
-			return -1;
-		}
-
-		if (pos[1] < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
-				   "length (%d)", pos[1]);
-			return -1;
-		}
-
-		if (pos + pos[1] > end) {
-			wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
-			return -1;
-		}
-
-		if (eap_sake_parse_add_attr(attr, pos))
-			return -1;
-
-		pos += pos[1];
-	}
-
-	return 0;
-}
-
-
-/**
- * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
- * @key: Key for KDF
- * @key_len: Length of the key in bytes
- * @label: A unique label for each purpose of the KDF
- * @data: Extra data (start) to bind into the key
- * @data_len: Length of the data
- * @data2: Extra data (end) to bind into the key
- * @data2_len: Length of the data2
- * @buf: Buffer for the generated pseudo-random key
- * @buf_len: Number of bytes of key to generate
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
- */
-static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
-			 const u8 *data, size_t data_len,
-			 const u8 *data2, size_t data2_len,
-			 u8 *buf, size_t buf_len)
-{
-	u8 counter = 0;
-	size_t pos, plen;
-	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = os_strlen(label) + 1;
-	const unsigned char *addr[4];
-	size_t len[4];
-
-	addr[0] = (u8 *) label; /* Label | Y */
-	len[0] = label_len;
-	addr[1] = data; /* Msg[start] */
-	len[1] = data_len;
-	addr[2] = data2; /* Msg[end] */
-	len[2] = data2_len;
-	addr[3] = &counter; /* Length */
-	len[3] = 1;
-
-	pos = 0;
-	while (pos < buf_len) {
-		plen = buf_len - pos;
-		if (plen >= SHA1_MAC_LEN) {
-			hmac_sha1_vector(key, key_len, 4, addr, len,
-					 &buf[pos]);
-			pos += SHA1_MAC_LEN;
-		} else {
-			hmac_sha1_vector(key, key_len, 4, addr, len,
-					 hash);
-			os_memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		counter++;
-	}
-}
-
-
-/**
- * eap_sake_derive_keys - Derive EAP-SAKE keys
- * @root_secret_a: 16-byte Root-Secret-A
- * @root_secret_b: 16-byte Root-Secret-B
- * @rand_s: 16-byte RAND_S
- * @rand_p: 16-byte RAND_P
- * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
- * @msk: Buffer for 64-byte MSK
- * @emsk: Buffer for 64-byte EMSK
- *
- * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
- */
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
-			  const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
-			  u8 *emsk)
-{
-	u8 sms_a[EAP_SAKE_SMS_LEN];
-	u8 sms_b[EAP_SAKE_SMS_LEN];
-	u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
-			root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
-	eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
-		     "SAKE Master Secret A",
-		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
-		     sms_a, EAP_SAKE_SMS_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
-	eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
-		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
-		     tek, EAP_SAKE_TEK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
-			tek, EAP_SAKE_TEK_AUTH_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
-			tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
-			root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
-	eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
-		     "SAKE Master Secret B",
-		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
-		     sms_b, EAP_SAKE_SMS_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
-	eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
-		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
-		     key_buf, sizeof(key_buf));
-	os_memcpy(msk, key_buf, EAP_MSK_LEN);
-	os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
-}
-
-
-/**
- * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
- * @tek_auth: 16-byte TEK-Auth
- * @rand_s: 16-byte RAND_S
- * @rand_p: 16-byte RAND_P
- * @serverid: SERVERID
- * @serverid_len: SERVERID length
- * @peerid: PEERID
- * @peerid_len: PEERID length
- * @peer: MIC calculation for 0 = Server, 1 = Peer message
- * @eap: EAP packet
- * @eap_len: EAP packet length
- * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
- * @mic: Buffer for the computed 16-byte MIC
- */
-int eap_sake_compute_mic(const u8 *tek_auth,
-			 const u8 *rand_s, const u8 *rand_p,
-			 const u8 *serverid, size_t serverid_len,
-			 const u8 *peerid, size_t peerid_len,
-			 int peer, const u8 *eap, size_t eap_len,
-			 const u8 *mic_pos, u8 *mic)
-{
-	u8 _rand[2 * EAP_SAKE_RAND_LEN];
-	u8 *tmp, *pos;
-	size_t tmplen;
-
-	tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
-	tmp = os_malloc(tmplen);
-	if (tmp == NULL)
-		return -1;
-	pos = tmp;
-	if (peer) {
-		if (peerid) {
-			os_memcpy(pos, peerid, peerid_len);
-			pos += peerid_len;
-		}
-		*pos++ = 0x00;
-		if (serverid) {
-			os_memcpy(pos, serverid, serverid_len);
-			pos += serverid_len;
-		}
-		*pos++ = 0x00;
-
-		os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
-		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
-			  EAP_SAKE_RAND_LEN);
-	} else {
-		if (serverid) {
-			os_memcpy(pos, serverid, serverid_len);
-			pos += serverid_len;
-		}
-		*pos++ = 0x00;
-		if (peerid) {
-			os_memcpy(pos, peerid, peerid_len);
-			pos += peerid_len;
-		}
-		*pos++ = 0x00;
-
-		os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
-		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
-			  EAP_SAKE_RAND_LEN);
-	}
-
-	os_memcpy(pos, eap, eap_len);
-	os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
-
-	eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
-		     peer ? "Peer MIC" : "Server MIC",
-		     _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
-		     mic, EAP_SAKE_MIC_LEN);
-
-	os_free(tmp);
-
-	return 0;
-}
-
-
-void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
-		       size_t len)
-{
-	wpabuf_put_u8(buf, type);
-	wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */
-	if (data)
-		wpabuf_put_data(buf, data, len);
-	else
-		os_memset(wpabuf_put(buf, len), 0, len);
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_sake_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_sake_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_sake_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_sake_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,387 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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 "wpabuf.h"
+#include "crypto/sha1.h"
+#include "eap_defs.h"
+#include "eap_sake_common.h"
+
+
+static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
+				   const u8 *pos)
+{
+	size_t i;
+
+	switch (pos[0]) {
+	case EAP_SAKE_AT_RAND_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
+		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->rand_s = pos + 2;
+		break;
+	case EAP_SAKE_AT_RAND_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
+		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->rand_p = pos + 2;
+		break;
+	case EAP_SAKE_AT_MIC_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
+		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->mic_s = pos + 2;
+		break;
+	case EAP_SAKE_AT_MIC_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
+		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->mic_p = pos + 2;
+		break;
+	case EAP_SAKE_AT_SERVERID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
+		attr->serverid = pos + 2;
+		attr->serverid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_PEERID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
+		attr->peerid = pos + 2;
+		attr->peerid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_SPI_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
+		attr->spi_s = pos + 2;
+		attr->spi_s_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_SPI_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
+		attr->spi_p = pos + 2;
+		attr->spi_p_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_ANY_ID_REQ:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
+		if (pos[1] != 4) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
+				   " length %d", pos[1]);
+			return -1;
+		}
+		attr->any_id_req = pos + 2;
+		break;
+	case EAP_SAKE_AT_PERM_ID_REQ:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
+		if (pos[1] != 4) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+				   "AT_PERM_ID_REQ length %d", pos[1]);
+			return -1;
+		}
+		attr->perm_id_req = pos + 2;
+		break;
+	case EAP_SAKE_AT_ENCR_DATA:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
+		attr->encr_data = pos + 2;
+		attr->encr_data_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_IV:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+		attr->iv = pos + 2;
+		attr->iv_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_PADDING:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
+		for (i = 2; i < pos[1]; i++) {
+			if (pos[i]) {
+				wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
+					   "with non-zero pad byte");
+				return -1;
+			}
+		}
+		break;
+	case EAP_SAKE_AT_NEXT_TMPID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
+		attr->next_tmpid = pos + 2;
+		attr->next_tmpid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_MSK_LIFE:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+		if (pos[1] != 6) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+				   "AT_MSK_LIFE length %d", pos[1]);
+			return -1;
+		}
+		attr->msk_life = pos + 2;
+		break;
+	default:
+		if (pos[0] < 128) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
+				   " attribute %d", pos[0]);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
+			   "attribute %d", pos[0]);
+		break;
+	}
+
+	if (attr->iv && !attr->encr_data) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_sake_parse_attributes - Parse EAP-SAKE attributes
+ * @buf: Packet payload (starting with the first attribute)
+ * @len: Payload length
+ * @attr: Structure to be filled with found attributes
+ * Returns: 0 on success or -1 on failure
+ */
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+			      struct eap_sake_parse_attr *attr)
+{
+	const u8 *pos = buf, *end = buf + len;
+
+	os_memset(attr, 0, sizeof(*attr));
+	while (pos < end) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
+			return -1;
+		}
+
+		if (pos[1] < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
+				   "length (%d)", pos[1]);
+			return -1;
+		}
+
+		if (pos + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
+			return -1;
+		}
+
+		if (eap_sake_parse_add_attr(attr, pos))
+			return -1;
+
+		pos += pos[1];
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @data: Extra data (start) to bind into the key
+ * @data_len: Length of the data
+ * @data2: Extra data (end) to bind into the key
+ * @data2_len: Length of the data2
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
+ */
+static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+			 const u8 *data, size_t data_len,
+			 const u8 *data2, size_t data2_len,
+			 u8 *buf, size_t buf_len)
+{
+	u8 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label) + 1;
+	const unsigned char *addr[4];
+	size_t len[4];
+
+	addr[0] = (u8 *) label; /* Label | Y */
+	len[0] = label_len;
+	addr[1] = data; /* Msg[start] */
+	len[1] = data_len;
+	addr[2] = data2; /* Msg[end] */
+	len[2] = data2_len;
+	addr[3] = &counter; /* Length */
+	len[3] = 1;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		if (plen >= SHA1_MAC_LEN) {
+			hmac_sha1_vector(key, key_len, 4, addr, len,
+					 &buf[pos]);
+			pos += SHA1_MAC_LEN;
+		} else {
+			hmac_sha1_vector(key, key_len, 4, addr, len,
+					 hash);
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+}
+
+
+/**
+ * eap_sake_derive_keys - Derive EAP-SAKE keys
+ * @root_secret_a: 16-byte Root-Secret-A
+ * @root_secret_b: 16-byte Root-Secret-B
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ *
+ * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
+ */
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+			  const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
+			  u8 *emsk)
+{
+	u8 sms_a[EAP_SAKE_SMS_LEN];
+	u8 sms_b[EAP_SAKE_SMS_LEN];
+	u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
+			root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
+	eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+		     "SAKE Master Secret A",
+		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+		     sms_a, EAP_SAKE_SMS_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
+	eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+		     tek, EAP_SAKE_TEK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
+			tek, EAP_SAKE_TEK_AUTH_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
+			tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
+			root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
+	eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+		     "SAKE Master Secret B",
+		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+		     sms_b, EAP_SAKE_SMS_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
+	eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+		     key_buf, sizeof(key_buf));
+	os_memcpy(msk, key_buf, EAP_MSK_LEN);
+	os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+/**
+ * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
+ * @tek_auth: 16-byte TEK-Auth
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @serverid: SERVERID
+ * @serverid_len: SERVERID length
+ * @peerid: PEERID
+ * @peerid_len: PEERID length
+ * @peer: MIC calculation for 0 = Server, 1 = Peer message
+ * @eap: EAP packet
+ * @eap_len: EAP packet length
+ * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
+ * @mic: Buffer for the computed 16-byte MIC
+ */
+int eap_sake_compute_mic(const u8 *tek_auth,
+			 const u8 *rand_s, const u8 *rand_p,
+			 const u8 *serverid, size_t serverid_len,
+			 const u8 *peerid, size_t peerid_len,
+			 int peer, const u8 *eap, size_t eap_len,
+			 const u8 *mic_pos, u8 *mic)
+{
+	u8 _rand[2 * EAP_SAKE_RAND_LEN];
+	u8 *tmp, *pos;
+	size_t tmplen;
+
+	tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
+	tmp = os_malloc(tmplen);
+	if (tmp == NULL)
+		return -1;
+	pos = tmp;
+	if (peer) {
+		if (peerid) {
+			os_memcpy(pos, peerid, peerid_len);
+			pos += peerid_len;
+		}
+		*pos++ = 0x00;
+		if (serverid) {
+			os_memcpy(pos, serverid, serverid_len);
+			pos += serverid_len;
+		}
+		*pos++ = 0x00;
+
+		os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
+		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
+			  EAP_SAKE_RAND_LEN);
+	} else {
+		if (serverid) {
+			os_memcpy(pos, serverid, serverid_len);
+			pos += serverid_len;
+		}
+		*pos++ = 0x00;
+		if (peerid) {
+			os_memcpy(pos, peerid, peerid_len);
+			pos += peerid_len;
+		}
+		*pos++ = 0x00;
+
+		os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
+		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
+			  EAP_SAKE_RAND_LEN);
+	}
+
+	os_memcpy(pos, eap, eap_len);
+	os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
+
+	eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+		     peer ? "Peer MIC" : "Server MIC",
+		     _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+		     mic, EAP_SAKE_MIC_LEN);
+
+	os_free(tmp);
+
+	return 0;
+}
+
+
+void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
+		       size_t len)
+{
+	wpabuf_put_u8(buf, type);
+	wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */
+	if (data)
+		wpabuf_put_data(buf, data, len);
+	else
+		os_memset(wpabuf_put(buf, len), 0, len);
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_sake_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_sake_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_sake_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,102 +0,0 @@
-/*
- * EAP server/peer: EAP-SAKE shared routines
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_SAKE_COMMON_H
-#define EAP_SAKE_COMMON_H
-
-#define EAP_SAKE_VERSION 2
-
-#define EAP_SAKE_SUBTYPE_CHALLENGE 1
-#define EAP_SAKE_SUBTYPE_CONFIRM 2
-#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3
-#define EAP_SAKE_SUBTYPE_IDENTITY 4
-
-#define EAP_SAKE_AT_RAND_S 1
-#define EAP_SAKE_AT_RAND_P 2
-#define EAP_SAKE_AT_MIC_S 3
-#define EAP_SAKE_AT_MIC_P 4
-#define EAP_SAKE_AT_SERVERID 5
-#define EAP_SAKE_AT_PEERID 6
-#define EAP_SAKE_AT_SPI_S 7
-#define EAP_SAKE_AT_SPI_P 8
-#define EAP_SAKE_AT_ANY_ID_REQ 9
-#define EAP_SAKE_AT_PERM_ID_REQ 10
-#define EAP_SAKE_AT_ENCR_DATA 128
-#define EAP_SAKE_AT_IV 129
-#define EAP_SAKE_AT_PADDING 130
-#define EAP_SAKE_AT_NEXT_TMPID 131
-#define EAP_SAKE_AT_MSK_LIFE 132
-
-#define EAP_SAKE_RAND_LEN 16
-#define EAP_SAKE_MIC_LEN 16
-#define EAP_SAKE_ROOT_SECRET_LEN 16
-#define EAP_SAKE_SMS_LEN 16
-#define EAP_SAKE_TEK_AUTH_LEN 16
-#define EAP_SAKE_TEK_CIPHER_LEN 16
-#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN)
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_sake_hdr {
-	u8 version; /* EAP_SAKE_VERSION */
-	u8 session_id;
-	u8 subtype;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-struct eap_sake_parse_attr {
-	const u8 *rand_s;
-	const u8 *rand_p;
-	const u8 *mic_s;
-	const u8 *mic_p;
-	const u8 *serverid;
-	size_t serverid_len;
-	const u8 *peerid;
-	size_t peerid_len;
-	const u8 *spi_s;
-	size_t spi_s_len;
-	const u8 *spi_p;
-	size_t spi_p_len;
-	const u8 *any_id_req;
-	const u8 *perm_id_req;
-	const u8 *encr_data;
-	size_t encr_data_len;
-	const u8 *iv;
-	size_t iv_len;
-	const u8 *next_tmpid;
-	size_t next_tmpid_len;
-	const u8 *msk_life;
-};
-
-int eap_sake_parse_attributes(const u8 *buf, size_t len,
-			      struct eap_sake_parse_attr *attr);
-void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
-			  const u8 *rand_s, const u8 *rand_p,
-			  u8 *tek, u8 *msk, u8 *emsk);
-int eap_sake_compute_mic(const u8 *tek_auth,
-			 const u8 *rand_s, const u8 *rand_p,
-			 const u8 *serverid, size_t serverid_len,
-			 const u8 *peerid, size_t peerid_len,
-			 int peer, const u8 *eap, size_t eap_len,
-			 const u8 *mic_pos, u8 *mic);
-void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
-		       size_t len);
-
-#endif /* EAP_SAKE_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_sake_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_sake_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_sake_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_sake_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,96 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_SAKE_COMMON_H
+#define EAP_SAKE_COMMON_H
+
+#define EAP_SAKE_VERSION 2
+
+#define EAP_SAKE_SUBTYPE_CHALLENGE 1
+#define EAP_SAKE_SUBTYPE_CONFIRM 2
+#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3
+#define EAP_SAKE_SUBTYPE_IDENTITY 4
+
+#define EAP_SAKE_AT_RAND_S 1
+#define EAP_SAKE_AT_RAND_P 2
+#define EAP_SAKE_AT_MIC_S 3
+#define EAP_SAKE_AT_MIC_P 4
+#define EAP_SAKE_AT_SERVERID 5
+#define EAP_SAKE_AT_PEERID 6
+#define EAP_SAKE_AT_SPI_S 7
+#define EAP_SAKE_AT_SPI_P 8
+#define EAP_SAKE_AT_ANY_ID_REQ 9
+#define EAP_SAKE_AT_PERM_ID_REQ 10
+#define EAP_SAKE_AT_ENCR_DATA 128
+#define EAP_SAKE_AT_IV 129
+#define EAP_SAKE_AT_PADDING 130
+#define EAP_SAKE_AT_NEXT_TMPID 131
+#define EAP_SAKE_AT_MSK_LIFE 132
+
+#define EAP_SAKE_RAND_LEN 16
+#define EAP_SAKE_MIC_LEN 16
+#define EAP_SAKE_ROOT_SECRET_LEN 16
+#define EAP_SAKE_SMS_LEN 16
+#define EAP_SAKE_TEK_AUTH_LEN 16
+#define EAP_SAKE_TEK_CIPHER_LEN 16
+#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_sake_hdr {
+	u8 version; /* EAP_SAKE_VERSION */
+	u8 session_id;
+	u8 subtype;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+struct eap_sake_parse_attr {
+	const u8 *rand_s;
+	const u8 *rand_p;
+	const u8 *mic_s;
+	const u8 *mic_p;
+	const u8 *serverid;
+	size_t serverid_len;
+	const u8 *peerid;
+	size_t peerid_len;
+	const u8 *spi_s;
+	size_t spi_s_len;
+	const u8 *spi_p;
+	size_t spi_p_len;
+	const u8 *any_id_req;
+	const u8 *perm_id_req;
+	const u8 *encr_data;
+	size_t encr_data_len;
+	const u8 *iv;
+	size_t iv_len;
+	const u8 *next_tmpid;
+	size_t next_tmpid_len;
+	const u8 *msk_life;
+};
+
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+			      struct eap_sake_parse_attr *attr);
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+			  const u8 *rand_s, const u8 *rand_p,
+			  u8 *tek, u8 *msk, u8 *emsk);
+int eap_sake_compute_mic(const u8 *tek_auth,
+			 const u8 *rand_s, const u8 *rand_p,
+			 const u8 *serverid, size_t serverid_len,
+			 const u8 *peerid, size_t peerid_len,
+			 int peer, const u8 *eap, size_t eap_len,
+			 const u8 *mic_pos, u8 *mic);
+void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
+		       size_t len);
+
+#endif /* EAP_SAKE_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_sim_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_sim_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_sim_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1214 +0,0 @@
-/*
- * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpabuf.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "eap_common/eap_defs.h"
-#include "eap_common/eap_sim_common.h"
-
-
-static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
-{
-	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
-}
-
-
-void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
-		       const u8 *nonce_mt, u16 selected_version,
-		       const u8 *ver_list, size_t ver_list_len,
-		       int num_chal, const u8 *kc, u8 *mk)
-{
-	u8 sel_ver[2];
-	const unsigned char *addr[5];
-	size_t len[5];
-
-	addr[0] = identity;
-	len[0] = identity_len;
-	addr[1] = kc;
-	len[1] = num_chal * EAP_SIM_KC_LEN;
-	addr[2] = nonce_mt;
-	len[2] = EAP_SIM_NONCE_MT_LEN;
-	addr[3] = ver_list;
-	len[3] = ver_list_len;
-	addr[4] = sel_ver;
-	len[4] = 2;
-
-	WPA_PUT_BE16(sel_ver, selected_version);
-
-	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
-	sha1_vector(5, addr, len, mk);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
-}
-
-
-void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
-		       const u8 *ik, const u8 *ck, u8 *mk)
-{
-	const u8 *addr[3];
-	size_t len[3];
-
-	addr[0] = identity;
-	len[0] = identity_len;
-	addr[1] = ik;
-	len[1] = EAP_AKA_IK_LEN;
-	addr[2] = ck;
-	len[2] = EAP_AKA_CK_LEN;
-
-	/* MK = SHA1(Identity|IK|CK) */
-	sha1_vector(3, addr, len, mk);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
-}
-
-
-int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
-{
-	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
-	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
-	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
-		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
-		return -1;
-	}
-	pos = buf;
-	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
-	pos += EAP_SIM_K_ENCR_LEN;
-	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
-	pos += EAP_SIM_K_AUT_LEN;
-	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
-	pos += EAP_SIM_KEYING_DATA_LEN;
-	os_memcpy(emsk, pos, EAP_EMSK_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
-			k_encr, EAP_SIM_K_ENCR_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
-			k_aut, EAP_SIM_K_AUT_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
-			msk, EAP_SIM_KEYING_DATA_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
-	os_memset(buf, 0, sizeof(buf));
-
-	return 0;
-}
-
-
-int eap_sim_derive_keys_reauth(u16 _counter,
-			       const u8 *identity, size_t identity_len,
-			       const u8 *nonce_s, const u8 *mk, u8 *msk,
-			       u8 *emsk)
-{
-	u8 xkey[SHA1_MAC_LEN];
-	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
-	u8 counter[2];
-	const u8 *addr[4];
-	size_t len[4];
-
-	while (identity_len > 0 && identity[identity_len - 1] == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
-			   "character from the end of identity");
-		identity_len--;
-	}
-	addr[0] = identity;
-	len[0] = identity_len;
-	addr[1] = counter;
-	len[1] = 2;
-	addr[2] = nonce_s;
-	len[2] = EAP_SIM_NONCE_S_LEN;
-	addr[3] = mk;
-	len[3] = EAP_SIM_MK_LEN;
-
-	WPA_PUT_BE16(counter, _counter);
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
-			  identity, identity_len);
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
-		    EAP_SIM_NONCE_S_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
-
-	/* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
-	sha1_vector(4, addr, len, xkey);
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
-
-	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
-		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
-		return -1;
-	}
-	if (msk) {
-		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
-			    msk, EAP_SIM_KEYING_DATA_LEN);
-	}
-	if (emsk) {
-		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
-	}
-	os_memset(buf, 0, sizeof(buf));
-
-	return 0;
-}
-
-
-int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
-		       const u8 *mac, const u8 *extra, size_t extra_len)
-{
-	unsigned char hmac[SHA1_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-	u8 *tmp;
-
-	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
-	    mac < wpabuf_head_u8(req) ||
-	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
-		return -1;
-
-	tmp = os_malloc(wpabuf_len(req));
-	if (tmp == NULL)
-		return -1;
-
-	addr[0] = tmp;
-	len[0] = wpabuf_len(req);
-	addr[1] = extra;
-	len[1] = extra_len;
-
-	/* HMAC-SHA1-128 */
-	os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
-	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
-		    tmp, wpabuf_len(req));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
-		    extra, extra_len);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
-			k_aut, EAP_SIM_K_AUT_LEN);
-	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
-		    hmac, EAP_SIM_MAC_LEN);
-	os_free(tmp);
-
-	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
-}
-
-
-void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
-		     const u8 *extra, size_t extra_len)
-{
-	unsigned char hmac[SHA1_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	addr[0] = msg;
-	len[0] = msg_len;
-	addr[1] = extra;
-	len[1] = extra_len;
-
-	/* HMAC-SHA1-128 */
-	os_memset(mac, 0, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
-		    extra, extra_len);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
-			k_aut, EAP_SIM_K_AUT_LEN);
-	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
-	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
-		    mac, EAP_SIM_MAC_LEN);
-}
-
-
-#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
-static void prf_prime(const u8 *k, const char *seed1,
-		      const u8 *seed2, size_t seed2_len,
-		      const u8 *seed3, size_t seed3_len,
-		      u8 *res, size_t res_len)
-{
-	const u8 *addr[5];
-	size_t len[5];
-	u8 hash[SHA256_MAC_LEN];
-	u8 iter;
-
-	/*
-	 * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
-	 * T1 = HMAC-SHA-256 (K, S | 0x01)
-	 * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
-	 * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
-	 * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
-	 * ...
-	 */
-
-	addr[0] = hash;
-	len[0] = 0;
-	addr[1] = (const u8 *) seed1;
-	len[1] = os_strlen(seed1);
-	addr[2] = seed2;
-	len[2] = seed2_len;
-	addr[3] = seed3;
-	len[3] = seed3_len;
-	addr[4] = &iter;
-	len[4] = 1;
-
-	iter = 0;
-	while (res_len) {
-		size_t hlen;
-		iter++;
-		hmac_sha256_vector(k, 32, 5, addr, len, hash);
-		len[0] = SHA256_MAC_LEN;
-		hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
-		os_memcpy(res, hash, hlen);
-		res += hlen;
-		res_len -= hlen;
-	}
-}
-
-
-void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
-			       const u8 *ik, const u8 *ck, u8 *k_encr,
-			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
-{
-	u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
-	u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
-		EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
-	u8 *pos;
-
-	/*
-	 * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
-	 * K_encr = MK[0..127]
-	 * K_aut  = MK[128..383]
-	 * K_re   = MK[384..639]
-	 * MSK    = MK[640..1151]
-	 * EMSK   = MK[1152..1663]
-	 */
-
-	os_memcpy(key, ik, EAP_AKA_IK_LEN);
-	os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
-
-	prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
-		  keys, sizeof(keys));
-
-	pos = keys;
-	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
-			k_encr, EAP_SIM_K_ENCR_LEN);
-	pos += EAP_SIM_K_ENCR_LEN;
-
-	os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
-			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
-	pos += EAP_AKA_PRIME_K_AUT_LEN;
-
-	os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
-			k_re, EAP_AKA_PRIME_K_RE_LEN);
-	pos += EAP_AKA_PRIME_K_RE_LEN;
-
-	os_memcpy(msk, pos, EAP_MSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
-	pos += EAP_MSK_LEN;
-
-	os_memcpy(emsk, pos, EAP_EMSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
-}
-
-
-int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
-				     const u8 *identity, size_t identity_len,
-				     const u8 *nonce_s, u8 *msk, u8 *emsk)
-{
-	u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
-	u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
-	u8 *pos;
-
-	/*
-	 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
-	 * MSK  = MK[0..511]
-	 * EMSK = MK[512..1023]
-	 */
-
-	WPA_PUT_BE16(seed3, counter);
-	os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
-
-	prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
-		  seed3, sizeof(seed3),
-		  keys, sizeof(keys));
-
-	pos = keys;
-	os_memcpy(msk, pos, EAP_MSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
-	pos += EAP_MSK_LEN;
-
-	os_memcpy(emsk, pos, EAP_EMSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
-
-	os_memset(keys, 0, sizeof(keys));
-
-	return 0;
-}
-
-
-int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
-			      const u8 *mac, const u8 *extra, size_t extra_len)
-{
-	unsigned char hmac[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-	u8 *tmp;
-
-	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
-	    mac < wpabuf_head_u8(req) ||
-	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
-		return -1;
-
-	tmp = os_malloc(wpabuf_len(req));
-	if (tmp == NULL)
-		return -1;
-
-	addr[0] = tmp;
-	len[0] = wpabuf_len(req);
-	addr[1] = extra;
-	len[1] = extra_len;
-
-	/* HMAC-SHA-256-128 */
-	os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
-	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
-		    tmp, wpabuf_len(req));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
-		    extra, extra_len);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
-			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
-	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
-		    hmac, EAP_SIM_MAC_LEN);
-	os_free(tmp);
-
-	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
-}
-
-
-void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
-			    u8 *mac, const u8 *extra, size_t extra_len)
-{
-	unsigned char hmac[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	addr[0] = msg;
-	len[0] = msg_len;
-	addr[1] = extra;
-	len[1] = extra_len;
-
-	/* HMAC-SHA-256-128 */
-	os_memset(mac, 0, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
-		    extra, extra_len);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
-			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
-	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
-	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
-		    mac, EAP_SIM_MAC_LEN);
-}
-
-
-void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
-				      const u8 *network_name,
-				      size_t network_name_len)
-{
-	u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN];
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[5];
-	size_t len[5];
-	u8 fc;
-	u8 l0[2], l1[2];
-
-	/* 3GPP TS 33.402 V8.0.0
-	 * (CK', IK') = F(CK, IK, <access network identity>)
-	 */
-	/* TODO: CK', IK' generation should really be moved into the actual
-	 * AKA procedure with network name passed in there and option to use
-	 * AMF separation bit = 1 (3GPP TS 33.401). */
-
-	/* Change Request 33.402 CR 0033 to version 8.1.1 from
-	 * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
-	 *
-	 * CK' || IK' = HMAC-SHA-256(Key, S)
-	 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
-	 * Key = CK || IK
-	 * FC = 0x20
-	 * P0 = access network identity (3GPP TS 24.302)
-	 * L0 = length of acceess network identity (2 octets, big endian)
-	 * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0
-	 * L1 = 0x00 0x06
-	 */
-
-	fc = 0x20;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
-	wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
-			  network_name, network_name_len);
-	wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
-
-	os_memcpy(key, ck, EAP_AKA_CK_LEN);
-	os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
-			key, sizeof(key));
-
-	addr[0] = &fc;
-	len[0] = 1;
-	addr[1] = network_name;
-	len[1] = network_name_len;
-	WPA_PUT_BE16(l0, network_name_len);
-	addr[2] = l0;
-	len[2] = 2;
-	addr[3] = sqn_ak;
-	len[3] = 6;
-	WPA_PUT_BE16(l1, 6);
-	addr[4] = l1;
-	len[4] = 2;
-
-	hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
-			hash, sizeof(hash));
-
-	os_memcpy(ck, hash, EAP_AKA_CK_LEN);
-	os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
-}
-#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
-
-
-int eap_sim_parse_attr(const u8 *start, const u8 *end,
-		       struct eap_sim_attrs *attr, int aka, int encr)
-{
-	const u8 *pos = start, *apos;
-	size_t alen, plen, i, list_len;
-
-	os_memset(attr, 0, sizeof(*attr));
-	attr->id_req = NO_ID_REQ;
-	attr->notification = -1;
-	attr->counter = -1;
-	attr->selected_version = -1;
-	attr->client_error_code = -1;
-
-	while (pos < end) {
-		if (pos + 2 > end) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
-			return -1;
-		}
-		wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
-			   pos[0], pos[1] * 4);
-		if (pos + pos[1] * 4 > end) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
-				   "(pos=%p len=%d end=%p)",
-				   pos, pos[1] * 4, end);
-			return -1;
-		}
-		if (pos[1] == 0) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
-			return -1;
-		}
-		apos = pos + 2;
-		alen = pos[1] * 4 - 2;
-		wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
-			    apos, alen);
-
-		switch (pos[0]) {
-		case EAP_SIM_AT_RAND:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
-			apos += 2;
-			alen -= 2;
-			if ((!aka && (alen % GSM_RAND_LEN)) ||
-			    (aka && alen != EAP_AKA_RAND_LEN)) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
-					   " (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->rand = apos;
-			attr->num_chal = alen / GSM_RAND_LEN;
-			break;
-		case EAP_SIM_AT_AUTN:
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
-			if (!aka) {
-				wpa_printf(MSG_DEBUG, "EAP-SIM: "
-					   "Unexpected AT_AUTN");
-				return -1;
-			}
-			apos += 2;
-			alen -= 2;
-			if (alen != EAP_AKA_AUTN_LEN) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
-					   " (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->autn = apos;
-			break;
-		case EAP_SIM_AT_PADDING:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_PADDING");
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
-			for (i = 2; i < alen; i++) {
-				if (apos[i] != 0) {
-					wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
-						   "AT_PADDING used a non-zero"
-						   " padding byte");
-					wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
-						    "(encr) padding bytes",
-						    apos + 2, alen - 2);
-					return -1;
-				}
-			}
-			break;
-		case EAP_SIM_AT_NONCE_MT:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
-			if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_NONCE_MT length");
-				return -1;
-			}
-			attr->nonce_mt = apos + 2;
-			break;
-		case EAP_SIM_AT_PERMANENT_ID_REQ:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
-			attr->id_req = PERMANENT_ID;
-			break;
-		case EAP_SIM_AT_MAC:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
-			if (alen != 2 + EAP_SIM_MAC_LEN) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
-					   "length");
-				return -1;
-			}
-			attr->mac = apos + 2;
-			break;
-		case EAP_SIM_AT_NOTIFICATION:
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_NOTIFICATION length %lu",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->notification = apos[0] * 256 + apos[1];
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
-				   attr->notification);
-			break;
-		case EAP_SIM_AT_ANY_ID_REQ:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
-			attr->id_req = ANY_ID;
-			break;
-		case EAP_SIM_AT_IDENTITY:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
-			plen = WPA_GET_BE16(apos);
-			apos += 2;
-			alen -= 2;
-			if (plen > alen) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_IDENTITY (Actual Length %lu, "
-					   "remaining length %lu)",
-					   (unsigned long) plen,
-					   (unsigned long) alen);
-				return -1;
-			}
-
-			attr->identity = apos;
-			attr->identity_len = plen;
-			break;
-		case EAP_SIM_AT_VERSION_LIST:
-			if (aka) {
-				wpa_printf(MSG_DEBUG, "EAP-AKA: "
-					   "Unexpected AT_VERSION_LIST");
-				return -1;
-			}
-			list_len = apos[0] * 256 + apos[1];
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
-			if (list_len < 2 || list_len > alen - 2) {
-				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
-					   "AT_VERSION_LIST (list_len=%lu "
-					   "attr_len=%lu)",
-					   (unsigned long) list_len,
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->version_list = apos + 2;
-			attr->version_list_len = list_len;
-			break;
-		case EAP_SIM_AT_SELECTED_VERSION:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_SELECTED_VERSION length %lu",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->selected_version = apos[0] * 256 + apos[1];
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
-				   "%d", attr->selected_version);
-			break;
-		case EAP_SIM_AT_FULLAUTH_ID_REQ:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
-			attr->id_req = FULLAUTH_ID;
-			break;
-		case EAP_SIM_AT_COUNTER:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_COUNTER");
-				return -1;
-			}
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
-					   "AT_COUNTER (alen=%lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->counter = apos[0] * 256 + apos[1];
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
-				   attr->counter);
-			break;
-		case EAP_SIM_AT_COUNTER_TOO_SMALL:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_COUNTER_TOO_SMALL");
-				return -1;
-			}
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
-					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
-				   "AT_COUNTER_TOO_SMALL");
-			attr->counter_too_small = 1;
-			break;
-		case EAP_SIM_AT_NONCE_S:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_NONCE_S");
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
-				   "AT_NONCE_S");
-			if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
-				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
-					   "AT_NONCE_S (alen=%lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->nonce_s = apos + 2;
-			break;
-		case EAP_SIM_AT_CLIENT_ERROR_CODE:
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_CLIENT_ERROR_CODE length %lu",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->client_error_code = apos[0] * 256 + apos[1];
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
-				   "%d", attr->client_error_code);
-			break;
-		case EAP_SIM_AT_IV:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
-			if (alen != 2 + EAP_SIM_MAC_LEN) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
-					   "length %lu", (unsigned long) alen);
-				return -1;
-			}
-			attr->iv = apos + 2;
-			break;
-		case EAP_SIM_AT_ENCR_DATA:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
-			attr->encr_data = apos + 2;
-			attr->encr_data_len = alen - 2;
-			if (attr->encr_data_len % 16) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_ENCR_DATA length %lu",
-					   (unsigned long)
-					   attr->encr_data_len);
-				return -1;
-			}
-			break;
-		case EAP_SIM_AT_NEXT_PSEUDONYM:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_NEXT_PSEUDONYM");
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
-				   "AT_NEXT_PSEUDONYM");
-			plen = apos[0] * 256 + apos[1];
-			if (plen > alen - 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
-					   " AT_NEXT_PSEUDONYM (actual"
-					   " len %lu, attr len %lu)",
-					   (unsigned long) plen,
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->next_pseudonym = pos + 4;
-			attr->next_pseudonym_len = plen;
-			break;
-		case EAP_SIM_AT_NEXT_REAUTH_ID:
-			if (!encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
-					   "AT_NEXT_REAUTH_ID");
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
-				   "AT_NEXT_REAUTH_ID");
-			plen = apos[0] * 256 + apos[1];
-			if (plen > alen - 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
-					   " AT_NEXT_REAUTH_ID (actual"
-					   " len %lu, attr len %lu)",
-					   (unsigned long) plen,
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->next_reauth_id = pos + 4;
-			attr->next_reauth_id_len = plen;
-			break;
-		case EAP_SIM_AT_RES:
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
-			attr->res_len_bits = WPA_GET_BE16(apos);
-			apos += 2;
-			alen -= 2;
-			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
-			    alen > EAP_AKA_MAX_RES_LEN) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
-					   "(len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->res = apos;
-			attr->res_len = alen;
-			break;
-		case EAP_SIM_AT_AUTS:
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
-			if (!aka) {
-				wpa_printf(MSG_DEBUG, "EAP-SIM: "
-					   "Unexpected AT_AUTS");
-				return -1;
-			}
-			if (alen != EAP_AKA_AUTS_LEN) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
-					   " (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->auts = apos;
-			break;
-		case EAP_SIM_AT_CHECKCODE:
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
-			if (!aka) {
-				wpa_printf(MSG_DEBUG, "EAP-SIM: "
-					   "Unexpected AT_CHECKCODE");
-				return -1;
-			}
-			apos += 2;
-			alen -= 2;
-			if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
-			    alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
-					   "AT_CHECKCODE (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->checkcode = apos;
-			attr->checkcode_len = alen;
-			break;
-		case EAP_SIM_AT_RESULT_IND:
-			if (encr) {
-				wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
-					   "AT_RESULT_IND");
-				return -1;
-			}
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
-					   "AT_RESULT_IND (alen=%lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
-			attr->result_ind = 1;
-			break;
-#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
-		case EAP_SIM_AT_KDF_INPUT:
-			if (aka != 2) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
-					   "AT_KDF_INPUT");
-				return -1;
-			}
-
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
-			plen = WPA_GET_BE16(apos);
-			apos += 2;
-			alen -= 2;
-			if (plen > alen) {
-				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
-					   "AT_KDF_INPUT (Actual Length %lu, "
-					   "remaining length %lu)",
-					   (unsigned long) plen,
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->kdf_input = apos;
-			attr->kdf_input_len = plen;
-			break;
-		case EAP_SIM_AT_KDF:
-			if (aka != 2) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
-					   "AT_KDF");
-				return -1;
-			}
-
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
-					   "AT_KDF (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
-				wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
-					   "AT_KDF attributes - ignore this");
-				continue;
-			}
-			attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
-			attr->kdf_count++;
-			break;
-		case EAP_SIM_AT_BIDDING:
-			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
-			if (alen != 2) {
-				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
-					   "AT_BIDDING (len %lu)",
-					   (unsigned long) alen);
-				return -1;
-			}
-			attr->bidding = apos;
-			break;
-#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
-		default:
-			if (pos[0] < 128) {
-				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
-					   "non-skippable attribute %d",
-					   pos[0]);
-				return -1;
-			}
-
-			wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
-				   " attribute %d ignored", pos[0]);
-			break;
-		}
-
-		pos += pos[1] * 4;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
-		   "(aka=%d encr=%d)", aka, encr);
-
-	return 0;
-}
-
-
-u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
-			size_t encr_data_len, const u8 *iv,
-			struct eap_sim_attrs *attr, int aka)
-{
-	u8 *decrypted;
-
-	if (!iv) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
-		return NULL;
-	}
-
-	decrypted = os_malloc(encr_data_len);
-	if (decrypted == NULL)
-		return NULL;
-	os_memcpy(decrypted, encr_data, encr_data_len);
-
-	if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
-		os_free(decrypted);
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
-		    decrypted, encr_data_len);
-
-	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
-			       aka, 1)) {
-		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
-			   "decrypted AT_ENCR_DATA");
-		os_free(decrypted);
-		return NULL;
-	}
-
-	return decrypted;
-}
-
-
-#define EAP_SIM_INIT_LEN 128
-
-struct eap_sim_msg {
-	struct wpabuf *buf;
-	size_t mac, iv, encr; /* index from buf */
-	int type;
-};
-
-
-struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
-{
-	struct eap_sim_msg *msg;
-	struct eap_hdr *eap;
-	u8 *pos;
-
-	msg = os_zalloc(sizeof(*msg));
-	if (msg == NULL)
-		return NULL;
-
-	msg->type = type;
-	msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
-	if (msg->buf == NULL) {
-		os_free(msg);
-		return NULL;
-	}
-	eap = wpabuf_put(msg->buf, sizeof(*eap));
-	eap->code = code;
-	eap->identifier = id;
-
-	pos = wpabuf_put(msg->buf, 4);
-	*pos++ = type;
-	*pos++ = subtype;
-	*pos++ = 0; /* Reserved */
-	*pos++ = 0; /* Reserved */
-
-	return msg;
-}
-
-
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
-				   const u8 *extra, size_t extra_len)
-{
-	struct eap_hdr *eap;
-	struct wpabuf *buf;
-
-	if (msg == NULL)
-		return NULL;
-
-	eap = wpabuf_mhead(msg->buf);
-	eap->length = host_to_be16(wpabuf_len(msg->buf));
-
-#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
-	if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
-		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
-				       wpabuf_len(msg->buf),
-				       (u8 *) wpabuf_mhead(msg->buf) +
-				       msg->mac, extra, extra_len);
-	} else
-#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
-	if (k_aut && msg->mac) {
-		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
-				wpabuf_len(msg->buf),
-				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
-				extra, extra_len);
-	}
-
-	buf = msg->buf;
-	os_free(msg);
-	return buf;
-}
-
-
-void eap_sim_msg_free(struct eap_sim_msg *msg)
-{
-	if (msg) {
-		wpabuf_free(msg->buf);
-		os_free(msg);
-	}
-}
-
-
-u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
-			  const u8 *data, size_t len)
-{
-	int attr_len = 2 + len;
-	int pad_len;
-	u8 *start;
-
-	if (msg == NULL)
-		return NULL;
-
-	pad_len = (4 - attr_len % 4) % 4;
-	attr_len += pad_len;
-	if (wpabuf_resize(&msg->buf, attr_len))
-		return NULL;
-	start = wpabuf_put(msg->buf, 0);
-	wpabuf_put_u8(msg->buf, attr);
-	wpabuf_put_u8(msg->buf, attr_len / 4);
-	wpabuf_put_data(msg->buf, data, len);
-	if (pad_len)
-		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
-	return start;
-}
-
-
-u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
-		     const u8 *data, size_t len)
-{
-	int attr_len = 4 + len;
-	int pad_len;
-	u8 *start;
-
-	if (msg == NULL)
-		return NULL;
-
-	pad_len = (4 - attr_len % 4) % 4;
-	attr_len += pad_len;
-	if (wpabuf_resize(&msg->buf, attr_len))
-		return NULL;
-	start = wpabuf_put(msg->buf, 0);
-	wpabuf_put_u8(msg->buf, attr);
-	wpabuf_put_u8(msg->buf, attr_len / 4);
-	wpabuf_put_be16(msg->buf, value);
-	if (data)
-		wpabuf_put_data(msg->buf, data, len);
-	else
-		wpabuf_put(msg->buf, len);
-	if (pad_len)
-		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
-	return start;
-}
-
-
-u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
-{
-	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
-	if (pos)
-		msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
-	return pos;
-}
-
-
-int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
-			       u8 attr_encr)
-{
-	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
-	if (pos == NULL)
-		return -1;
-	msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
-	if (os_get_random(wpabuf_mhead_u8(msg->buf) + msg->iv,
-			  EAP_SIM_IV_LEN)) {
-		msg->iv = 0;
-		return -1;
-	}
-
-	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
-	if (pos == NULL) {
-		msg->iv = 0;
-		return -1;
-	}
-	msg->encr = pos - wpabuf_head_u8(msg->buf);
-
-	return 0;
-}
-
-
-int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
-{
-	size_t encr_len;
-
-	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
-		return -1;
-
-	encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
-	if (encr_len % 16) {
-		u8 *pos;
-		int pad_len = 16 - (encr_len % 16);
-		if (pad_len < 4) {
-			wpa_printf(MSG_WARNING, "EAP-SIM: "
-				   "eap_sim_msg_add_encr_end - invalid pad_len"
-				   " %d", pad_len);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
-		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
-		if (pos == NULL)
-			return -1;
-		os_memset(pos + 4, 0, pad_len - 4);
-		encr_len += pad_len;
-	}
-	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
-		   (unsigned long) encr_len);
-	wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
-	return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
-				   wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
-				   encr_len);
-}
-
-
-void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	const char *type = aka ? "AKA" : "SIM";
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-	switch (notification) {
-	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
-		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
-			   "notification (after authentication)", type);
-		break;
-	case EAP_SIM_TEMPORARILY_DENIED:
-		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
-			   "User has been temporarily denied access to the "
-			   "requested service", type);
-		break;
-	case EAP_SIM_NOT_SUBSCRIBED:
-		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
-			   "User has not subscribed to the requested service",
-			   type);
-		break;
-	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
-		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
-			   "notification (before authentication)", type);
-		break;
-	case EAP_SIM_SUCCESS:
-		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
-			   "notification", type);
-		break;
-	default:
-		if (notification >= 32768) {
-			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
-				   "non-failure notification %d",
-				   type, notification);
-		} else {
-			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
-				   "failure notification %d",
-				   type, notification);
-		}
-	}
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_sim_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_sim_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_sim_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_sim_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1209 @@
+/*
+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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 "wpabuf.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "eap_common/eap_defs.h"
+#include "eap_common/eap_sim_common.h"
+
+
+static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+{
+	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
+}
+
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *nonce_mt, u16 selected_version,
+		       const u8 *ver_list, size_t ver_list_len,
+		       int num_chal, const u8 *kc, u8 *mk)
+{
+	u8 sel_ver[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = identity;
+	len[0] = identity_len;
+	addr[1] = kc;
+	len[1] = num_chal * EAP_SIM_KC_LEN;
+	addr[2] = nonce_mt;
+	len[2] = EAP_SIM_NONCE_MT_LEN;
+	addr[3] = ver_list;
+	len[3] = ver_list_len;
+	addr[4] = sel_ver;
+	len[4] = 2;
+
+	WPA_PUT_BE16(sel_ver, selected_version);
+
+	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+	sha1_vector(5, addr, len, mk);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+}
+
+
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *ik, const u8 *ck, u8 *mk)
+{
+	const u8 *addr[3];
+	size_t len[3];
+
+	addr[0] = identity;
+	len[0] = identity_len;
+	addr[1] = ik;
+	len[1] = EAP_AKA_IK_LEN;
+	addr[2] = ck;
+	len[2] = EAP_AKA_CK_LEN;
+
+	/* MK = SHA1(Identity|IK|CK) */
+	sha1_vector(3, addr, len, mk);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
+}
+
+
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
+{
+	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
+	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
+	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
+		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+		return -1;
+	}
+	pos = buf;
+	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+	pos += EAP_SIM_K_ENCR_LEN;
+	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+	pos += EAP_SIM_K_AUT_LEN;
+	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+	pos += EAP_SIM_KEYING_DATA_LEN;
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
+			k_encr, EAP_SIM_K_ENCR_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
+			k_aut, EAP_SIM_K_AUT_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
+			msk, EAP_SIM_KEYING_DATA_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+	os_memset(buf, 0, sizeof(buf));
+
+	return 0;
+}
+
+
+int eap_sim_derive_keys_reauth(u16 _counter,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *nonce_s, const u8 *mk, u8 *msk,
+			       u8 *emsk)
+{
+	u8 xkey[SHA1_MAC_LEN];
+	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
+	u8 counter[2];
+	const u8 *addr[4];
+	size_t len[4];
+
+	while (identity_len > 0 && identity[identity_len - 1] == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null "
+			   "character from the end of identity");
+		identity_len--;
+	}
+	addr[0] = identity;
+	len[0] = identity_len;
+	addr[1] = counter;
+	len[1] = 2;
+	addr[2] = nonce_s;
+	len[2] = EAP_SIM_NONCE_S_LEN;
+	addr[3] = mk;
+	len[3] = EAP_SIM_MK_LEN;
+
+	WPA_PUT_BE16(counter, _counter);
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
+			  identity, identity_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
+		    EAP_SIM_NONCE_S_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+
+	/* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
+	sha1_vector(4, addr, len, xkey);
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
+
+	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
+		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+		return -1;
+	}
+	if (msk) {
+		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
+			    msk, EAP_SIM_KEYING_DATA_LEN);
+	}
+	if (emsk) {
+		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+	}
+	os_memset(buf, 0, sizeof(buf));
+
+	return 0;
+}
+
+
+int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
+		       const u8 *mac, const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA1_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *tmp;
+
+	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
+	    mac < wpabuf_head_u8(req) ||
+	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
+		return -1;
+
+	tmp = os_malloc(wpabuf_len(req));
+	if (tmp == NULL)
+		return -1;
+
+	addr[0] = tmp;
+	len[0] = wpabuf_len(req);
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA1-128 */
+	os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
+	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg",
+		    tmp, wpabuf_len(req));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
+			k_aut, EAP_SIM_K_AUT_LEN);
+	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
+		    hmac, EAP_SIM_MAC_LEN);
+	os_free(tmp);
+
+	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+}
+
+
+void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
+		     const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA1_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	addr[0] = msg;
+	len[0] = msg_len;
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA1-128 */
+	os_memset(mac, 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
+			k_aut, EAP_SIM_K_AUT_LEN);
+	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
+		    mac, EAP_SIM_MAC_LEN);
+}
+
+
+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
+static void prf_prime(const u8 *k, const char *seed1,
+		      const u8 *seed2, size_t seed2_len,
+		      const u8 *seed3, size_t seed3_len,
+		      u8 *res, size_t res_len)
+{
+	const u8 *addr[5];
+	size_t len[5];
+	u8 hash[SHA256_MAC_LEN];
+	u8 iter;
+
+	/*
+	 * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
+	 * T1 = HMAC-SHA-256 (K, S | 0x01)
+	 * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
+	 * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
+	 * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
+	 * ...
+	 */
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (const u8 *) seed1;
+	len[1] = os_strlen(seed1);
+	addr[2] = seed2;
+	len[2] = seed2_len;
+	addr[3] = seed3;
+	len[3] = seed3_len;
+	addr[4] = &iter;
+	len[4] = 1;
+
+	iter = 0;
+	while (res_len) {
+		size_t hlen;
+		iter++;
+		hmac_sha256_vector(k, 32, 5, addr, len, hash);
+		len[0] = SHA256_MAC_LEN;
+		hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
+		os_memcpy(res, hash, hlen);
+		res += hlen;
+		res_len -= hlen;
+	}
+}
+
+
+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
+			       const u8 *ik, const u8 *ck, u8 *k_encr,
+			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
+{
+	u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
+	u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
+		EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
+	u8 *pos;
+
+	/*
+	 * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
+	 * K_encr = MK[0..127]
+	 * K_aut  = MK[128..383]
+	 * K_re   = MK[384..639]
+	 * MSK    = MK[640..1151]
+	 * EMSK   = MK[1152..1663]
+	 */
+
+	os_memcpy(key, ik, EAP_AKA_IK_LEN);
+	os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
+
+	prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
+		  keys, sizeof(keys));
+
+	pos = keys;
+	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
+			k_encr, EAP_SIM_K_ENCR_LEN);
+	pos += EAP_SIM_K_ENCR_LEN;
+
+	os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	pos += EAP_AKA_PRIME_K_AUT_LEN;
+
+	os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
+			k_re, EAP_AKA_PRIME_K_RE_LEN);
+	pos += EAP_AKA_PRIME_K_RE_LEN;
+
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+				     const u8 *identity, size_t identity_len,
+				     const u8 *nonce_s, u8 *msk, u8 *emsk)
+{
+	u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
+	u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
+	u8 *pos;
+
+	/*
+	 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
+	 * MSK  = MK[0..511]
+	 * EMSK = MK[512..1023]
+	 */
+
+	WPA_PUT_BE16(seed3, counter);
+	os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
+		  seed3, sizeof(seed3),
+		  keys, sizeof(keys));
+
+	pos = keys;
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
+
+	os_memset(keys, 0, sizeof(keys));
+
+	return 0;
+}
+
+
+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *tmp;
+
+	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
+	    mac < wpabuf_head_u8(req) ||
+	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
+		return -1;
+
+	tmp = os_malloc(wpabuf_len(req));
+	if (tmp == NULL)
+		return -1;
+
+	addr[0] = tmp;
+	len[0] = wpabuf_len(req);
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA-256-128 */
+	os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
+	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
+		    tmp, wpabuf_len(req));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
+		    hmac, EAP_SIM_MAC_LEN);
+	os_free(tmp);
+
+	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+}
+
+
+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
+			    u8 *mac, const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	addr[0] = msg;
+	len[0] = msg_len;
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA-256-128 */
+	os_memset(mac, 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
+	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
+		    mac, EAP_SIM_MAC_LEN);
+}
+
+
+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
+				      const u8 *network_name,
+				      size_t network_name_len)
+{
+	u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN];
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[5];
+	size_t len[5];
+	u8 fc;
+	u8 l0[2], l1[2];
+
+	/* 3GPP TS 33.402 V8.0.0
+	 * (CK', IK') = F(CK, IK, <access network identity>)
+	 */
+	/* TODO: CK', IK' generation should really be moved into the actual
+	 * AKA procedure with network name passed in there and option to use
+	 * AMF separation bit = 1 (3GPP TS 33.401). */
+
+	/* Change Request 33.402 CR 0033 to version 8.1.1 from
+	 * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
+	 *
+	 * CK' || IK' = HMAC-SHA-256(Key, S)
+	 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
+	 * Key = CK || IK
+	 * FC = 0x20
+	 * P0 = access network identity (3GPP TS 24.302)
+	 * L0 = length of acceess network identity (2 octets, big endian)
+	 * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0
+	 * L1 = 0x00 0x06
+	 */
+
+	fc = 0x20;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
+	wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
+			  network_name, network_name_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
+
+	os_memcpy(key, ck, EAP_AKA_CK_LEN);
+	os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
+			key, sizeof(key));
+
+	addr[0] = &fc;
+	len[0] = 1;
+	addr[1] = network_name;
+	len[1] = network_name_len;
+	WPA_PUT_BE16(l0, network_name_len);
+	addr[2] = l0;
+	len[2] = 2;
+	addr[3] = sqn_ak;
+	len[3] = 6;
+	WPA_PUT_BE16(l1, 6);
+	addr[4] = l1;
+	len[4] = 2;
+
+	hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
+			hash, sizeof(hash));
+
+	os_memcpy(ck, hash, EAP_AKA_CK_LEN);
+	os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
+}
+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
+
+
+int eap_sim_parse_attr(const u8 *start, const u8 *end,
+		       struct eap_sim_attrs *attr, int aka, int encr)
+{
+	const u8 *pos = start, *apos;
+	size_t alen, plen, i, list_len;
+
+	os_memset(attr, 0, sizeof(*attr));
+	attr->id_req = NO_ID_REQ;
+	attr->notification = -1;
+	attr->counter = -1;
+	attr->selected_version = -1;
+	attr->client_error_code = -1;
+
+	while (pos < end) {
+		if (pos + 2 > end) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
+			return -1;
+		}
+		wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
+			   pos[0], pos[1] * 4);
+		if (pos + pos[1] * 4 > end) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
+				   "(pos=%p len=%d end=%p)",
+				   pos, pos[1] * 4, end);
+			return -1;
+		}
+		if (pos[1] == 0) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow");
+			return -1;
+		}
+		apos = pos + 2;
+		alen = pos[1] * 4 - 2;
+		wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
+			    apos, alen);
+
+		switch (pos[0]) {
+		case EAP_SIM_AT_RAND:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
+			apos += 2;
+			alen -= 2;
+			if ((!aka && (alen % GSM_RAND_LEN)) ||
+			    (aka && alen != EAP_AKA_RAND_LEN)) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
+					   " (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->rand = apos;
+			attr->num_chal = alen / GSM_RAND_LEN;
+			break;
+		case EAP_SIM_AT_AUTN:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
+			if (!aka) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: "
+					   "Unexpected AT_AUTN");
+				return -1;
+			}
+			apos += 2;
+			alen -= 2;
+			if (alen != EAP_AKA_AUTN_LEN) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
+					   " (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->autn = apos;
+			break;
+		case EAP_SIM_AT_PADDING:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_PADDING");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
+			for (i = 2; i < alen; i++) {
+				if (apos[i] != 0) {
+					wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
+						   "AT_PADDING used a non-zero"
+						   " padding byte");
+					wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
+						    "(encr) padding bytes",
+						    apos + 2, alen - 2);
+					return -1;
+				}
+			}
+			break;
+		case EAP_SIM_AT_NONCE_MT:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
+			if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_NONCE_MT length");
+				return -1;
+			}
+			attr->nonce_mt = apos + 2;
+			break;
+		case EAP_SIM_AT_PERMANENT_ID_REQ:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
+			attr->id_req = PERMANENT_ID;
+			break;
+		case EAP_SIM_AT_MAC:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
+			if (alen != 2 + EAP_SIM_MAC_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
+					   "length");
+				return -1;
+			}
+			attr->mac = apos + 2;
+			break;
+		case EAP_SIM_AT_NOTIFICATION:
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_NOTIFICATION length %lu",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->notification = apos[0] * 256 + apos[1];
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
+				   attr->notification);
+			break;
+		case EAP_SIM_AT_ANY_ID_REQ:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
+			attr->id_req = ANY_ID;
+			break;
+		case EAP_SIM_AT_IDENTITY:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
+			plen = WPA_GET_BE16(apos);
+			apos += 2;
+			alen -= 2;
+			if (plen > alen) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_IDENTITY (Actual Length %lu, "
+					   "remaining length %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+
+			attr->identity = apos;
+			attr->identity_len = plen;
+			break;
+		case EAP_SIM_AT_VERSION_LIST:
+			if (aka) {
+				wpa_printf(MSG_DEBUG, "EAP-AKA: "
+					   "Unexpected AT_VERSION_LIST");
+				return -1;
+			}
+			list_len = apos[0] * 256 + apos[1];
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
+			if (list_len < 2 || list_len > alen - 2) {
+				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
+					   "AT_VERSION_LIST (list_len=%lu "
+					   "attr_len=%lu)",
+					   (unsigned long) list_len,
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->version_list = apos + 2;
+			attr->version_list_len = list_len;
+			break;
+		case EAP_SIM_AT_SELECTED_VERSION:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_SELECTED_VERSION length %lu",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->selected_version = apos[0] * 256 + apos[1];
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
+				   "%d", attr->selected_version);
+			break;
+		case EAP_SIM_AT_FULLAUTH_ID_REQ:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
+			attr->id_req = FULLAUTH_ID;
+			break;
+		case EAP_SIM_AT_COUNTER:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_COUNTER");
+				return -1;
+			}
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+					   "AT_COUNTER (alen=%lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->counter = apos[0] * 256 + apos[1];
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
+				   attr->counter);
+			break;
+		case EAP_SIM_AT_COUNTER_TOO_SMALL:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_COUNTER_TOO_SMALL");
+				return -1;
+			}
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+				   "AT_COUNTER_TOO_SMALL");
+			attr->counter_too_small = 1;
+			break;
+		case EAP_SIM_AT_NONCE_S:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_NONCE_S");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+				   "AT_NONCE_S");
+			if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+					   "AT_NONCE_S (alen=%lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->nonce_s = apos + 2;
+			break;
+		case EAP_SIM_AT_CLIENT_ERROR_CODE:
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_CLIENT_ERROR_CODE length %lu",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->client_error_code = apos[0] * 256 + apos[1];
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
+				   "%d", attr->client_error_code);
+			break;
+		case EAP_SIM_AT_IV:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
+			if (alen != 2 + EAP_SIM_MAC_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
+					   "length %lu", (unsigned long) alen);
+				return -1;
+			}
+			attr->iv = apos + 2;
+			break;
+		case EAP_SIM_AT_ENCR_DATA:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
+			attr->encr_data = apos + 2;
+			attr->encr_data_len = alen - 2;
+			if (attr->encr_data_len % 16) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_ENCR_DATA length %lu",
+					   (unsigned long)
+					   attr->encr_data_len);
+				return -1;
+			}
+			break;
+		case EAP_SIM_AT_NEXT_PSEUDONYM:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_NEXT_PSEUDONYM");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+				   "AT_NEXT_PSEUDONYM");
+			plen = apos[0] * 256 + apos[1];
+			if (plen > alen - 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+					   " AT_NEXT_PSEUDONYM (actual"
+					   " len %lu, attr len %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->next_pseudonym = pos + 4;
+			attr->next_pseudonym_len = plen;
+			break;
+		case EAP_SIM_AT_NEXT_REAUTH_ID:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_NEXT_REAUTH_ID");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+				   "AT_NEXT_REAUTH_ID");
+			plen = apos[0] * 256 + apos[1];
+			if (plen > alen - 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+					   " AT_NEXT_REAUTH_ID (actual"
+					   " len %lu, attr len %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->next_reauth_id = pos + 4;
+			attr->next_reauth_id_len = plen;
+			break;
+		case EAP_SIM_AT_RES:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
+			attr->res_len_bits = WPA_GET_BE16(apos);
+			apos += 2;
+			alen -= 2;
+			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
+			    alen > EAP_AKA_MAX_RES_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
+					   "(len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->res = apos;
+			attr->res_len = alen;
+			break;
+		case EAP_SIM_AT_AUTS:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
+			if (!aka) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: "
+					   "Unexpected AT_AUTS");
+				return -1;
+			}
+			if (alen != EAP_AKA_AUTS_LEN) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
+					   " (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->auts = apos;
+			break;
+		case EAP_SIM_AT_CHECKCODE:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE");
+			if (!aka) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: "
+					   "Unexpected AT_CHECKCODE");
+				return -1;
+			}
+			apos += 2;
+			alen -= 2;
+			if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
+			    alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
+					   "AT_CHECKCODE (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->checkcode = apos;
+			attr->checkcode_len = alen;
+			break;
+		case EAP_SIM_AT_RESULT_IND:
+			if (encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted "
+					   "AT_RESULT_IND");
+				return -1;
+			}
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_RESULT_IND (alen=%lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
+			attr->result_ind = 1;
+			break;
+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
+		case EAP_SIM_AT_KDF_INPUT:
+			if (aka != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
+					   "AT_KDF_INPUT");
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
+			plen = WPA_GET_BE16(apos);
+			apos += 2;
+			alen -= 2;
+			if (plen > alen) {
+				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
+					   "AT_KDF_INPUT (Actual Length %lu, "
+					   "remaining length %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->kdf_input = apos;
+			attr->kdf_input_len = plen;
+			break;
+		case EAP_SIM_AT_KDF:
+			if (aka != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
+					   "AT_KDF");
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
+					   "AT_KDF (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
+				wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
+					   "AT_KDF attributes - ignore this");
+				continue;
+			}
+			attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
+			attr->kdf_count++;
+			break;
+		case EAP_SIM_AT_BIDDING:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
+					   "AT_BIDDING (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->bidding = apos;
+			break;
+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
+		default:
+			if (pos[0] < 128) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
+					   "non-skippable attribute %d",
+					   pos[0]);
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
+				   " attribute %d ignored", pos[0]);
+			break;
+		}
+
+		pos += pos[1] * 4;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
+		   "(aka=%d encr=%d)", aka, encr);
+
+	return 0;
+}
+
+
+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
+			size_t encr_data_len, const u8 *iv,
+			struct eap_sim_attrs *attr, int aka)
+{
+	u8 *decrypted;
+
+	if (!iv) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
+		return NULL;
+	}
+
+	decrypted = os_malloc(encr_data_len);
+	if (decrypted == NULL)
+		return NULL;
+	os_memcpy(decrypted, encr_data, encr_data_len);
+
+	if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
+		os_free(decrypted);
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
+		    decrypted, encr_data_len);
+
+	if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
+			       aka, 1)) {
+		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
+			   "decrypted AT_ENCR_DATA");
+		os_free(decrypted);
+		return NULL;
+	}
+
+	return decrypted;
+}
+
+
+#define EAP_SIM_INIT_LEN 128
+
+struct eap_sim_msg {
+	struct wpabuf *buf;
+	size_t mac, iv, encr; /* index from buf */
+	int type;
+};
+
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
+{
+	struct eap_sim_msg *msg;
+	struct eap_hdr *eap;
+	u8 *pos;
+
+	msg = os_zalloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	msg->type = type;
+	msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
+	if (msg->buf == NULL) {
+		os_free(msg);
+		return NULL;
+	}
+	eap = wpabuf_put(msg->buf, sizeof(*eap));
+	eap->code = code;
+	eap->identifier = id;
+
+	pos = wpabuf_put(msg->buf, 4);
+	*pos++ = type;
+	*pos++ = subtype;
+	*pos++ = 0; /* Reserved */
+	*pos++ = 0; /* Reserved */
+
+	return msg;
+}
+
+
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+				   const u8 *extra, size_t extra_len)
+{
+	struct eap_hdr *eap;
+	struct wpabuf *buf;
+
+	if (msg == NULL)
+		return NULL;
+
+	eap = wpabuf_mhead(msg->buf);
+	eap->length = host_to_be16(wpabuf_len(msg->buf));
+
+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
+	if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
+		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
+				       wpabuf_len(msg->buf),
+				       (u8 *) wpabuf_mhead(msg->buf) +
+				       msg->mac, extra, extra_len);
+	} else
+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
+	if (k_aut && msg->mac) {
+		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
+				wpabuf_len(msg->buf),
+				(u8 *) wpabuf_mhead(msg->buf) + msg->mac,
+				extra, extra_len);
+	}
+
+	buf = msg->buf;
+	os_free(msg);
+	return buf;
+}
+
+
+void eap_sim_msg_free(struct eap_sim_msg *msg)
+{
+	if (msg) {
+		wpabuf_free(msg->buf);
+		os_free(msg);
+	}
+}
+
+
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+			  const u8 *data, size_t len)
+{
+	int attr_len = 2 + len;
+	int pad_len;
+	u8 *start;
+
+	if (msg == NULL)
+		return NULL;
+
+	pad_len = (4 - attr_len % 4) % 4;
+	attr_len += pad_len;
+	if (wpabuf_resize(&msg->buf, attr_len))
+		return NULL;
+	start = wpabuf_put(msg->buf, 0);
+	wpabuf_put_u8(msg->buf, attr);
+	wpabuf_put_u8(msg->buf, attr_len / 4);
+	wpabuf_put_data(msg->buf, data, len);
+	if (pad_len)
+		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
+	return start;
+}
+
+
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
+		     const u8 *data, size_t len)
+{
+	int attr_len = 4 + len;
+	int pad_len;
+	u8 *start;
+
+	if (msg == NULL)
+		return NULL;
+
+	pad_len = (4 - attr_len % 4) % 4;
+	attr_len += pad_len;
+	if (wpabuf_resize(&msg->buf, attr_len))
+		return NULL;
+	start = wpabuf_put(msg->buf, 0);
+	wpabuf_put_u8(msg->buf, attr);
+	wpabuf_put_u8(msg->buf, attr_len / 4);
+	wpabuf_put_be16(msg->buf, value);
+	if (data)
+		wpabuf_put_data(msg->buf, data, len);
+	else
+		wpabuf_put(msg->buf, len);
+	if (pad_len)
+		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
+	return start;
+}
+
+
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
+{
+	u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
+	if (pos)
+		msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4;
+	return pos;
+}
+
+
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+			       u8 attr_encr)
+{
+	u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
+	if (pos == NULL)
+		return -1;
+	msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4;
+	if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv,
+			     EAP_SIM_IV_LEN)) {
+		msg->iv = 0;
+		return -1;
+	}
+
+	pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
+	if (pos == NULL) {
+		msg->iv = 0;
+		return -1;
+	}
+	msg->encr = pos - wpabuf_head_u8(msg->buf);
+
+	return 0;
+}
+
+
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
+{
+	size_t encr_len;
+
+	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+		return -1;
+
+	encr_len = wpabuf_len(msg->buf) - msg->encr - 4;
+	if (encr_len % 16) {
+		u8 *pos;
+		int pad_len = 16 - (encr_len % 16);
+		if (pad_len < 4) {
+			wpa_printf(MSG_WARNING, "EAP-SIM: "
+				   "eap_sim_msg_add_encr_end - invalid pad_len"
+				   " %d", pad_len);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "   *AT_PADDING");
+		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
+		if (pos == NULL)
+			return -1;
+		os_memset(pos + 4, 0, pad_len - 4);
+		encr_len += pad_len;
+	}
+	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
+		   (unsigned long) encr_len);
+	wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1;
+	return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv,
+				   wpabuf_mhead_u8(msg->buf) + msg->encr + 4,
+				   encr_len);
+}
+
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	const char *type = aka ? "AKA" : "SIM";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	switch (notification) {
+	case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
+		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+			   "notification (after authentication)", type);
+		break;
+	case EAP_SIM_TEMPORARILY_DENIED:
+		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+			   "User has been temporarily denied access to the "
+			   "requested service", type);
+		break;
+	case EAP_SIM_NOT_SUBSCRIBED:
+		wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+			   "User has not subscribed to the requested service",
+			   type);
+		break;
+	case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
+		wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+			   "notification (before authentication)", type);
+		break;
+	case EAP_SIM_SUCCESS:
+		wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
+			   "notification", type);
+		break;
+	default:
+		if (notification >= 32768) {
+			wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
+				   "non-failure notification %d",
+				   type, notification);
+		} else {
+			wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
+				   "failure notification %d",
+				   type, notification);
+		}
+	}
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_sim_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_sim_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_sim_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,235 +0,0 @@
-/*
- * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_SIM_COMMON_H
-#define EAP_SIM_COMMON_H
-
-#define EAP_SIM_NONCE_S_LEN 16
-#define EAP_SIM_NONCE_MT_LEN 16
-#define EAP_SIM_MAC_LEN 16
-#define EAP_SIM_MK_LEN 20
-#define EAP_SIM_K_AUT_LEN 16
-#define EAP_SIM_K_ENCR_LEN 16
-#define EAP_SIM_KEYING_DATA_LEN 64
-#define EAP_SIM_IV_LEN 16
-#define EAP_SIM_KC_LEN 8
-#define EAP_SIM_SRES_LEN 4
-
-#define GSM_RAND_LEN 16
-
-#define EAP_SIM_VERSION 1
-
-/* EAP-SIM Subtypes */
-#define EAP_SIM_SUBTYPE_START 10
-#define EAP_SIM_SUBTYPE_CHALLENGE 11
-#define EAP_SIM_SUBTYPE_NOTIFICATION 12
-#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
-#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
-
-/* AT_CLIENT_ERROR_CODE error codes */
-#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
-#define EAP_SIM_UNSUPPORTED_VERSION 1
-#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
-#define EAP_SIM_RAND_NOT_FRESH 3
-
-#define EAP_SIM_MAX_FAST_REAUTHS 1000
-
-#define EAP_SIM_MAX_CHAL 3
-
-
-/* EAP-AKA Subtypes */
-#define EAP_AKA_SUBTYPE_CHALLENGE 1
-#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
-#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
-#define EAP_AKA_SUBTYPE_IDENTITY 5
-#define EAP_AKA_SUBTYPE_NOTIFICATION 12
-#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
-#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
-
-/* AT_CLIENT_ERROR_CODE error codes */
-#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
-
-#define EAP_AKA_RAND_LEN 16
-#define EAP_AKA_AUTN_LEN 16
-#define EAP_AKA_AUTS_LEN 14
-#define EAP_AKA_RES_MAX_LEN 16
-#define EAP_AKA_IK_LEN 16
-#define EAP_AKA_CK_LEN 16
-#define EAP_AKA_MAX_FAST_REAUTHS 1000
-#define EAP_AKA_MIN_RES_LEN 4
-#define EAP_AKA_MAX_RES_LEN 16
-#define EAP_AKA_CHECKCODE_LEN 20
-
-#define EAP_AKA_PRIME_K_AUT_LEN 32
-#define EAP_AKA_PRIME_CHECKCODE_LEN 32
-#define EAP_AKA_PRIME_K_RE_LEN 32
-
-struct wpabuf;
-
-void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
-		       const u8 *nonce_mt, u16 selected_version,
-		       const u8 *ver_list, size_t ver_list_len,
-		       int num_chal, const u8 *kc, u8 *mk);
-void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
-		       const u8 *ik, const u8 *ck, u8 *mk);
-int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk,
-			u8 *emsk);
-int eap_sim_derive_keys_reauth(u16 _counter,
-			       const u8 *identity, size_t identity_len,
-			       const u8 *nonce_s, const u8 *mk, u8 *msk,
-			       u8 *emsk);
-int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
-		       const u8 *mac, const u8 *extra, size_t extra_len);
-void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
-		     const u8 *extra, size_t extra_len);
-
-#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
-void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
-			       const u8 *ik, const u8 *ck, u8 *k_encr,
-			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk);
-int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
-				     const u8 *identity, size_t identity_len,
-				     const u8 *nonce_s, u8 *msk, u8 *emsk);
-int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
-			      const u8 *mac, const u8 *extra,
-			      size_t extra_len);
-void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
-			    u8 *mac, const u8 *extra, size_t extra_len);
-
-void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
-				      const u8 *network_name,
-				      size_t network_name_len);
-#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
-static inline void eap_aka_prime_derive_keys(const u8 *identity,
-					     size_t identity_len,
-					     const u8 *ik, const u8 *ck,
-					     u8 *k_encr, u8 *k_aut, u8 *k_re,
-					     u8 *msk, u8 *emsk)
-{
-}
-
-static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
-						   const u8 *identity,
-						   size_t identity_len,
-						   const u8 *nonce_s, u8 *msk,
-						   u8 *emsk)
-{
-	return -1;
-}
-
-static inline int eap_sim_verify_mac_sha256(const u8 *k_aut,
-					    const struct wpabuf *req,
-					    const u8 *mac, const u8 *extra,
-					    size_t extra_len)
-{
-	return -1;
-}
-#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
-
-
-/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
-#define EAP_SIM_AT_RAND 1
-#define EAP_SIM_AT_AUTN 2 /* only AKA */
-#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */
-#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */
-#define EAP_SIM_AT_PADDING 6 /* only encrypted */
-#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
-#define EAP_SIM_AT_PERMANENT_ID_REQ 10
-#define EAP_SIM_AT_MAC 11
-#define EAP_SIM_AT_NOTIFICATION 12
-#define EAP_SIM_AT_ANY_ID_REQ 13
-#define EAP_SIM_AT_IDENTITY 14 /* only send */
-#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */
-#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */
-#define EAP_SIM_AT_FULLAUTH_ID_REQ 17
-#define EAP_SIM_AT_COUNTER 19 /* only encrypted */
-#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
-#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
-#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
-#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */
-#define EAP_SIM_AT_KDF 24 /* only AKA' */
-#define EAP_SIM_AT_IV 129
-#define EAP_SIM_AT_ENCR_DATA 130
-#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
-#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
-#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
-#define EAP_SIM_AT_RESULT_IND 135
-#define EAP_SIM_AT_BIDDING 136
-
-/* AT_NOTIFICATION notification code values */
-#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
-#define EAP_SIM_TEMPORARILY_DENIED 1026
-#define EAP_SIM_NOT_SUBSCRIBED 1031
-#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
-#define EAP_SIM_SUCCESS 32768
-
-/* EAP-AKA' AT_KDF Key Derivation Function values */
-#define EAP_AKA_PRIME_KDF 1
-
-/* AT_BIDDING flags */
-#define EAP_AKA_BIDDING_FLAG_D 0x8000
-
-
-enum eap_sim_id_req {
-	NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
-};
-
-
-struct eap_sim_attrs {
-	const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
-	const u8 *next_pseudonym, *next_reauth_id;
-	const u8 *nonce_mt, *identity, *res, *auts;
-	const u8 *checkcode;
-	const u8 *kdf_input;
-	const u8 *bidding;
-	size_t num_chal, version_list_len, encr_data_len;
-	size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
-	size_t res_len_bits;
-	size_t checkcode_len;
-	size_t kdf_input_len;
-	enum eap_sim_id_req id_req;
-	int notification, counter, selected_version, client_error_code;
-	int counter_too_small;
-	int result_ind;
-#define EAP_AKA_PRIME_KDF_MAX 10
-	u16 kdf[EAP_AKA_PRIME_KDF_MAX];
-	size_t kdf_count;
-};
-
-int eap_sim_parse_attr(const u8 *start, const u8 *end,
-		       struct eap_sim_attrs *attr, int aka, int encr);
-u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
-			size_t encr_data_len, const u8 *iv,
-			struct eap_sim_attrs *attr, int aka);
-
-
-struct eap_sim_msg;
-
-struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
-				   const u8 *extra, size_t extra_len);
-void eap_sim_msg_free(struct eap_sim_msg *msg);
-u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
-			  const u8 *data, size_t len);
-u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr,
-		     u16 value, const u8 *data, size_t len);
-u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr);
-int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
-			       u8 attr_encr);
-int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
-			     int attr_pad);
-
-void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
-
-#endif /* EAP_SIM_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_sim_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_sim_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_sim_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_sim_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,229 @@
+/*
+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_SIM_COMMON_H
+#define EAP_SIM_COMMON_H
+
+#define EAP_SIM_NONCE_S_LEN 16
+#define EAP_SIM_NONCE_MT_LEN 16
+#define EAP_SIM_MAC_LEN 16
+#define EAP_SIM_MK_LEN 20
+#define EAP_SIM_K_AUT_LEN 16
+#define EAP_SIM_K_ENCR_LEN 16
+#define EAP_SIM_KEYING_DATA_LEN 64
+#define EAP_SIM_IV_LEN 16
+#define EAP_SIM_KC_LEN 8
+#define EAP_SIM_SRES_LEN 4
+
+#define GSM_RAND_LEN 16
+
+#define EAP_SIM_VERSION 1
+
+/* EAP-SIM Subtypes */
+#define EAP_SIM_SUBTYPE_START 10
+#define EAP_SIM_SUBTYPE_CHALLENGE 11
+#define EAP_SIM_SUBTYPE_NOTIFICATION 12
+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
+#define EAP_SIM_UNSUPPORTED_VERSION 1
+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
+#define EAP_SIM_RAND_NOT_FRESH 3
+
+#define EAP_SIM_MAX_FAST_REAUTHS 1000
+
+#define EAP_SIM_MAX_CHAL 3
+
+
+/* EAP-AKA Subtypes */
+#define EAP_AKA_SUBTYPE_CHALLENGE 1
+#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
+#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
+#define EAP_AKA_SUBTYPE_IDENTITY 5
+#define EAP_AKA_SUBTYPE_NOTIFICATION 12
+#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
+#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+#define EAP_AKA_MAX_FAST_REAUTHS 1000
+#define EAP_AKA_MIN_RES_LEN 4
+#define EAP_AKA_MAX_RES_LEN 16
+#define EAP_AKA_CHECKCODE_LEN 20
+
+#define EAP_AKA_PRIME_K_AUT_LEN 32
+#define EAP_AKA_PRIME_CHECKCODE_LEN 32
+#define EAP_AKA_PRIME_K_RE_LEN 32
+
+struct wpabuf;
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *nonce_mt, u16 selected_version,
+		       const u8 *ver_list, size_t ver_list_len,
+		       int num_chal, const u8 *kc, u8 *mk);
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *ik, const u8 *ck, u8 *mk);
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk,
+			u8 *emsk);
+int eap_sim_derive_keys_reauth(u16 _counter,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *nonce_s, const u8 *mk, u8 *msk,
+			       u8 *emsk);
+int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
+		       const u8 *mac, const u8 *extra, size_t extra_len);
+void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
+		     const u8 *extra, size_t extra_len);
+
+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
+			       const u8 *ik, const u8 *ck, u8 *k_encr,
+			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk);
+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+				     const u8 *identity, size_t identity_len,
+				     const u8 *nonce_s, u8 *msk, u8 *emsk);
+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len);
+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
+			    u8 *mac, const u8 *extra, size_t extra_len);
+
+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
+				      const u8 *network_name,
+				      size_t network_name_len);
+#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
+static inline void eap_aka_prime_derive_keys(const u8 *identity,
+					     size_t identity_len,
+					     const u8 *ik, const u8 *ck,
+					     u8 *k_encr, u8 *k_aut, u8 *k_re,
+					     u8 *msk, u8 *emsk)
+{
+}
+
+static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+						   const u8 *identity,
+						   size_t identity_len,
+						   const u8 *nonce_s, u8 *msk,
+						   u8 *emsk)
+{
+	return -1;
+}
+
+static inline int eap_sim_verify_mac_sha256(const u8 *k_aut,
+					    const struct wpabuf *req,
+					    const u8 *mac, const u8 *extra,
+					    size_t extra_len)
+{
+	return -1;
+}
+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
+
+
+/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
+#define EAP_SIM_AT_RAND 1
+#define EAP_SIM_AT_AUTN 2 /* only AKA */
+#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */
+#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */
+#define EAP_SIM_AT_PADDING 6 /* only encrypted */
+#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
+#define EAP_SIM_AT_PERMANENT_ID_REQ 10
+#define EAP_SIM_AT_MAC 11
+#define EAP_SIM_AT_NOTIFICATION 12
+#define EAP_SIM_AT_ANY_ID_REQ 13
+#define EAP_SIM_AT_IDENTITY 14 /* only send */
+#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */
+#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */
+#define EAP_SIM_AT_FULLAUTH_ID_REQ 17
+#define EAP_SIM_AT_COUNTER 19 /* only encrypted */
+#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
+#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
+#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
+#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */
+#define EAP_SIM_AT_KDF 24 /* only AKA' */
+#define EAP_SIM_AT_IV 129
+#define EAP_SIM_AT_ENCR_DATA 130
+#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
+#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
+#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
+#define EAP_SIM_AT_RESULT_IND 135
+#define EAP_SIM_AT_BIDDING 136
+
+/* AT_NOTIFICATION notification code values */
+#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
+#define EAP_SIM_TEMPORARILY_DENIED 1026
+#define EAP_SIM_NOT_SUBSCRIBED 1031
+#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
+#define EAP_SIM_SUCCESS 32768
+
+/* EAP-AKA' AT_KDF Key Derivation Function values */
+#define EAP_AKA_PRIME_KDF 1
+
+/* AT_BIDDING flags */
+#define EAP_AKA_BIDDING_FLAG_D 0x8000
+
+
+enum eap_sim_id_req {
+	NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
+};
+
+
+struct eap_sim_attrs {
+	const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
+	const u8 *next_pseudonym, *next_reauth_id;
+	const u8 *nonce_mt, *identity, *res, *auts;
+	const u8 *checkcode;
+	const u8 *kdf_input;
+	const u8 *bidding;
+	size_t num_chal, version_list_len, encr_data_len;
+	size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
+	size_t res_len_bits;
+	size_t checkcode_len;
+	size_t kdf_input_len;
+	enum eap_sim_id_req id_req;
+	int notification, counter, selected_version, client_error_code;
+	int counter_too_small;
+	int result_ind;
+#define EAP_AKA_PRIME_KDF_MAX 10
+	u16 kdf[EAP_AKA_PRIME_KDF_MAX];
+	size_t kdf_count;
+};
+
+int eap_sim_parse_attr(const u8 *start, const u8 *end,
+		       struct eap_sim_attrs *attr, int aka, int encr);
+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
+			size_t encr_data_len, const u8 *iv,
+			struct eap_sim_attrs *attr, int aka);
+
+
+struct eap_sim_msg;
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+				   const u8 *extra, size_t extra_len);
+void eap_sim_msg_free(struct eap_sim_msg *msg);
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+			  const u8 *data, size_t len);
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr,
+		     u16 value, const u8 *data, size_t len);
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr);
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+			       u8 attr_encr);
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
+			     int attr_pad);
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
+
+#endif /* EAP_SIM_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_tlv_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_tlv_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_tlv_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,118 +0,0 @@
-/*
- * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_TLV_COMMON_H
-#define EAP_TLV_COMMON_H
-
-/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */
-#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
-#define EAP_TLV_NAK_TLV 4
-#define EAP_TLV_ERROR_CODE_TLV 5
-#define EAP_TLV_CONNECTION_BINDING_TLV 6
-#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
-#define EAP_TLV_URI_TLV 8
-#define EAP_TLV_EAP_PAYLOAD_TLV 9
-#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
-#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
-#define EAP_TLV_CRYPTO_BINDING_TLV 12
-#define EAP_TLV_CALLING_STATION_ID_TLV 13
-#define EAP_TLV_CALLED_STATION_ID_TLV 14
-#define EAP_TLV_NAS_PORT_TYPE_TLV 15
-#define EAP_TLV_SERVER_IDENTIFIER_TLV 16
-#define EAP_TLV_IDENTITY_TYPE_TLV 17
-#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
-#define EAP_TLV_REQUEST_ACTION_TLV 19
-#define EAP_TLV_PKCS7_TLV 20
-
-#define EAP_TLV_RESULT_SUCCESS 1
-#define EAP_TLV_RESULT_FAILURE 2
-
-#define EAP_TLV_TYPE_MANDATORY 0x8000
-#define EAP_TLV_TYPE_MASK 0x3fff
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_tlv_hdr {
-	be16 tlv_type;
-	be16 length;
-} STRUCT_PACKED;
-
-struct eap_tlv_nak_tlv {
-	be16 tlv_type;
-	be16 length;
-	be32 vendor_id;
-	be16 nak_type;
-} STRUCT_PACKED;
-
-struct eap_tlv_result_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 status;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
-struct eap_tlv_intermediate_result_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 status;
-	/* Followed by optional TLVs */
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
-struct eap_tlv_crypto_binding_tlv {
-	be16 tlv_type;
-	be16 length;
-	u8 reserved;
-	u8 version;
-	u8 received_version;
-	u8 subtype;
-	u8 nonce[32];
-	u8 compound_mac[20];
-} STRUCT_PACKED;
-
-struct eap_tlv_pac_ack_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 pac_type;
-	be16 pac_len;
-	be16 result;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.9 - Request-Action TLV */
-struct eap_tlv_request_action_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 action;
-} STRUCT_PACKED;
-
-/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
-struct eap_tlv_pac_type_tlv {
-	be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
-	be16 length;
-	be16 pac_type;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
-
-#define EAP_TLV_ACTION_PROCESS_TLV 1
-#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
-
-#endif /* EAP_TLV_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_tlv_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_tlv_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_tlv_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_tlv_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,112 @@
+/*
+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TLV_COMMON_H
+#define EAP_TLV_COMMON_H
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+#define EAP_TLV_ERROR_CODE_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
+#define EAP_TLV_CRYPTO_BINDING_TLV 12
+#define EAP_TLV_CALLING_STATION_ID_TLV 13
+#define EAP_TLV_CALLED_STATION_ID_TLV 14
+#define EAP_TLV_NAS_PORT_TYPE_TLV 15
+#define EAP_TLV_SERVER_IDENTIFIER_TLV 16
+#define EAP_TLV_IDENTITY_TYPE_TLV 17
+#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
+#define EAP_TLV_REQUEST_ACTION_TLV 19
+#define EAP_TLV_PKCS7_TLV 20
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+#define EAP_TLV_TYPE_MANDATORY 0x8000
+#define EAP_TLV_TYPE_MASK 0x3fff
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_tlv_hdr {
+	be16 tlv_type;
+	be16 length;
+} STRUCT_PACKED;
+
+struct eap_tlv_nak_tlv {
+	be16 tlv_type;
+	be16 length;
+	be32 vendor_id;
+	be16 nak_type;
+} STRUCT_PACKED;
+
+struct eap_tlv_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
+struct eap_tlv_intermediate_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+	/* Followed by optional TLVs */
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+struct eap_tlv_crypto_binding_tlv {
+	be16 tlv_type;
+	be16 length;
+	u8 reserved;
+	u8 version;
+	u8 received_version;
+	u8 subtype;
+	u8 nonce[32];
+	u8 compound_mac[20];
+} STRUCT_PACKED;
+
+struct eap_tlv_pac_ack_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 pac_type;
+	be16 pac_len;
+	be16 result;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.9 - Request-Action TLV */
+struct eap_tlv_request_action_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 action;
+} STRUCT_PACKED;
+
+/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
+struct eap_tlv_pac_type_tlv {
+	be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
+	be16 length;
+	be16 pac_type;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+#define EAP_TLV_ACTION_PROCESS_TLV 1
+#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
+
+#endif /* EAP_TLV_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_ttls.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_ttls.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_ttls.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,71 +0,0 @@
-/*
- * EAP server/peer: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_TTLS_H
-#define EAP_TTLS_H
-
-struct ttls_avp {
-	be32 avp_code;
-	be32 avp_length; /* 8-bit flags, 24-bit length;
-			  * length includes AVP header */
-	/* optional 32-bit Vendor-ID */
-	/* Data */
-};
-
-struct ttls_avp_vendor {
-	be32 avp_code;
-	be32 avp_length; /* 8-bit flags, 24-bit length;
-			  * length includes AVP header */
-	be32 vendor_id;
-	/* Data */
-};
-
-#define AVP_FLAGS_VENDOR 0x80
-#define AVP_FLAGS_MANDATORY 0x40
-
-#define AVP_PAD(start, pos) \
-do { \
-	int __pad; \
-	__pad = (4 - (((pos) - (start)) & 3)) & 3; \
-	os_memset((pos), 0, __pad); \
-	pos += __pad; \
-} while (0)
-
-
-/* RFC 2865 */
-#define RADIUS_ATTR_USER_NAME 1
-#define RADIUS_ATTR_USER_PASSWORD 2
-#define RADIUS_ATTR_CHAP_PASSWORD 3
-#define RADIUS_ATTR_REPLY_MESSAGE 18
-#define RADIUS_ATTR_CHAP_CHALLENGE 60
-#define RADIUS_ATTR_EAP_MESSAGE 79
-
-/* RFC 2548 */
-#define RADIUS_VENDOR_ID_MICROSOFT 311
-#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
-#define RADIUS_ATTR_MS_CHAP_ERROR 2
-#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
-#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
-#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
-#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
-#define RADIUS_ATTR_MS_CHAP2_CPW 27
-
-#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
-#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
-#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
-#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
-#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
-#define EAP_TTLS_CHAP_PASSWORD_LEN 16
-
-#endif /* EAP_TTLS_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_ttls.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_ttls.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_ttls.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_ttls.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,65 @@
+/*
+ * EAP server/peer: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TTLS_H
+#define EAP_TTLS_H
+
+struct ttls_avp {
+	be32 avp_code;
+	be32 avp_length; /* 8-bit flags, 24-bit length;
+			  * length includes AVP header */
+	/* optional 32-bit Vendor-ID */
+	/* Data */
+};
+
+struct ttls_avp_vendor {
+	be32 avp_code;
+	be32 avp_length; /* 8-bit flags, 24-bit length;
+			  * length includes AVP header */
+	be32 vendor_id;
+	/* Data */
+};
+
+#define AVP_FLAGS_VENDOR 0x80
+#define AVP_FLAGS_MANDATORY 0x40
+
+#define AVP_PAD(start, pos) \
+do { \
+	int __pad; \
+	__pad = (4 - (((pos) - (start)) & 3)) & 3; \
+	os_memset((pos), 0, __pad); \
+	pos += __pad; \
+} while (0)
+
+
+/* RFC 2865 */
+#define RADIUS_ATTR_USER_NAME 1
+#define RADIUS_ATTR_USER_PASSWORD 2
+#define RADIUS_ATTR_CHAP_PASSWORD 3
+#define RADIUS_ATTR_REPLY_MESSAGE 18
+#define RADIUS_ATTR_CHAP_CHALLENGE 60
+#define RADIUS_ATTR_EAP_MESSAGE 79
+
+/* RFC 2548 */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
+#define RADIUS_ATTR_MS_CHAP_ERROR 2
+#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
+#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
+#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
+#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
+#define RADIUS_ATTR_MS_CHAP2_CPW 27
+
+#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
+#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
+#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
+#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
+#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
+#define EAP_TTLS_CHAP_PASSWORD_LEN 16
+
+#endif /* EAP_TTLS_H */

Deleted: vendor/wpa/2.0/src/eap_common/eap_wsc_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_wsc_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_wsc_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,39 +0,0 @@
-/*
- * EAP-WSC common routines for Wi-Fi Protected Setup
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_defs.h"
-#include "eap_common.h"
-#include "wps/wps.h"
-#include "eap_wsc_common.h"
-
-struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code)
-{
-	struct wpabuf *msg;
-
-	msg = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
-			   "FRAG_ACK");
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK");
-	wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */
-	wpabuf_put_u8(msg, 0); /* Flags */
-
-	return msg;
-}

Copied: vendor/wpa/2.0/src/eap_common/eap_wsc_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/eap_wsc_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_wsc_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_wsc_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,33 @@
+/*
+ * EAP-WSC common routines for Wi-Fi Protected Setup
+ * Copyright (c) 2007, Jouni Malinen <j at 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 "eap_defs.h"
+#include "eap_common.h"
+#include "wps/wps.h"
+#include "eap_wsc_common.h"
+
+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "FRAG_ACK");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK");
+	wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */
+	wpabuf_put_u8(msg, 0); /* Flags */
+
+	return msg;
+}

Deleted: vendor/wpa/2.0/src/eap_common/eap_wsc_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/eap_wsc_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/eap_wsc_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,33 +0,0 @@
-/*
- * EAP-WSC definitions for Wi-Fi Protected Setup
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_WSC_COMMON_H
-#define EAP_WSC_COMMON_H
-
-#define EAP_VENDOR_TYPE_WSC 1
-
-#define WSC_FLAGS_MF 0x01
-#define WSC_FLAGS_LF 0x02
-
-#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0"
-#define WSC_ID_REGISTRAR_LEN 30
-#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0"
-#define WSC_ID_ENROLLEE_LEN 29
-
-#define WSC_FRAGMENT_SIZE 1400
-
-
-struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code);
-
-#endif /* EAP_WSC_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/eap_wsc_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/eap_wsc_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/eap_wsc_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/eap_wsc_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,27 @@
+/*
+ * EAP-WSC definitions for Wi-Fi Protected Setup
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_WSC_COMMON_H
+#define EAP_WSC_COMMON_H
+
+#define EAP_VENDOR_TYPE_WSC 1
+
+#define WSC_FLAGS_MF 0x01
+#define WSC_FLAGS_LF 0x02
+
+#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0"
+#define WSC_ID_REGISTRAR_LEN 30
+#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0"
+#define WSC_ID_ENROLLEE_LEN 29
+
+#define WSC_FRAGMENT_SIZE 1400
+
+
+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code);
+
+#endif /* EAP_WSC_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_common/ikev2_common.c
===================================================================
--- vendor/wpa/dist/src/eap_common/ikev2_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/ikev2_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,796 +0,0 @@
-/*
- * IKEv2 common routines for initiator and responder
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/crypto.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "ikev2_common.h"
-
-
-static struct ikev2_integ_alg ikev2_integ_algs[] = {
-	{ AUTH_HMAC_SHA1_96, 20, 12 },
-	{ AUTH_HMAC_MD5_96, 16, 12 }
-};
-
-#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
-
-
-static struct ikev2_prf_alg ikev2_prf_algs[] = {
-	{ PRF_HMAC_SHA1, 20, 20 },
-	{ PRF_HMAC_MD5, 16, 16 }
-};
-
-#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
-
-
-static struct ikev2_encr_alg ikev2_encr_algs[] = {
-	{ ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */
-	{ ENCR_3DES, 24, 8 }
-};
-
-#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
-
-
-const struct ikev2_integ_alg * ikev2_get_integ(int id)
-{
-	size_t i;
-
-	for (i = 0; i < NUM_INTEG_ALGS; i++) {
-		if (ikev2_integ_algs[i].id == id)
-			return &ikev2_integ_algs[i];
-	}
-
-	return NULL;
-}
-
-
-int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
-		     size_t data_len, u8 *hash)
-{
-	u8 tmphash[IKEV2_MAX_HASH_LEN];
-
-	switch (alg) {
-	case AUTH_HMAC_SHA1_96:
-		if (key_len != 20)
-			return -1;
-		hmac_sha1(key, key_len, data, data_len, tmphash);
-		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);
-		os_memcpy(hash, tmphash, 12);
-		break;
-	default:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-const struct ikev2_prf_alg * ikev2_get_prf(int id)
-{
-	size_t i;
-
-	for (i = 0; i < NUM_PRF_ALGS; i++) {
-		if (ikev2_prf_algs[i].id == id)
-			return &ikev2_prf_algs[i];
-	}
-
-	return NULL;
-}
-
-
-int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
-		   size_t num_elem, const u8 *addr[], const size_t *len,
-		   u8 *hash)
-{
-	switch (alg) {
-	case PRF_HMAC_SHA1:
-		hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
-		break;
-	case PRF_HMAC_MD5:
-		hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
-		break;
-	default:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
-		   const u8 *data, size_t data_len,
-		   u8 *out, size_t out_len)
-{
-	u8 hash[IKEV2_MAX_HASH_LEN];
-	size_t hash_len;
-	u8 iter, *pos, *end;
-	const u8 *addr[3];
-	size_t len[3];
-	const struct ikev2_prf_alg *prf;
-	int res;
-
-	prf = ikev2_get_prf(alg);
-	if (prf == NULL)
-		return -1;
-	hash_len = prf->hash_len;
-
-	addr[0] = hash;
-	len[0] = hash_len;
-	addr[1] = data;
-	len[1] = data_len;
-	addr[2] = &iter;
-	len[2] = 1;
-
-	pos = out;
-	end = out + out_len;
-	iter = 1;
-	while (pos < end) {
-		size_t clen;
-		if (iter == 1)
-			res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1],
-					     &len[1], hash);
-		else
-			res = ikev2_prf_hash(alg, key, key_len, 3, addr, len,
-					     hash);
-		if (res < 0)
-			return -1;
-		clen = hash_len;
-		if ((int) clen > end - pos)
-			clen = end - pos;
-		os_memcpy(pos, hash, clen);
-		pos += clen;
-		iter++;
-	}
-
-	return 0;
-}
-
-
-const struct ikev2_encr_alg * ikev2_get_encr(int id)
-{
-	size_t i;
-
-	for (i = 0; i < NUM_ENCR_ALGS; i++) {
-		if (ikev2_encr_algs[i].id == id)
-			return &ikev2_encr_algs[i];
-	}
-
-	return NULL;
-}
-
-
-#ifdef CCNS_PL
-/* from des.c */
-struct des3_key_s {
-	u32 ek[3][32];
-	u32 dk[3][32];
-};
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
-#endif /* CCNS_PL */
-
-
-int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
-		       const u8 *plain, u8 *crypt, size_t len)
-{
-	struct crypto_cipher *cipher;
-	int encr_alg;
-
-#ifdef CCNS_PL
-	if (alg == ENCR_3DES) {
-		struct des3_key_s des3key;
-		size_t i, blocks;
-		u8 *pos;
-
-		/* ECB mode is used incorrectly for 3DES!? */
-		if (key_len != 24) {
-			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
-			return -1;
-		}
-		des3_key_setup(key, &des3key);
-
-		blocks = len / 8;
-		pos = crypt;
-		for (i = 0; i < blocks; i++) {
-			des3_encrypt(pos, &des3key, pos);
-			pos += 8;
-		}
-	} else {
-#endif /* CCNS_PL */
-	switch (alg) {
-	case ENCR_3DES:
-		encr_alg = CRYPTO_CIPHER_ALG_3DES;
-		break;
-	case ENCR_AES_CBC:
-		encr_alg = CRYPTO_CIPHER_ALG_AES;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
-		return -1;
-	}
-
-	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
-	if (cipher == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
-		return -1;
-	}
-
-	if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Encryption failed");
-		crypto_cipher_deinit(cipher);
-		return -1;
-	}
-	crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
-	}
-#endif /* CCNS_PL */
-
-	return 0;
-}
-
-
-int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
-		       const u8 *crypt, u8 *plain, size_t len)
-{
-	struct crypto_cipher *cipher;
-	int encr_alg;
-
-#ifdef CCNS_PL
-	if (alg == ENCR_3DES) {
-		struct des3_key_s des3key;
-		size_t i, blocks;
-
-		/* ECB mode is used incorrectly for 3DES!? */
-		if (key_len != 24) {
-			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
-			return -1;
-		}
-		des3_key_setup(key, &des3key);
-
-		if (len % 8) {
-			wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
-				   "length");
-			return -1;
-		}
-		blocks = len / 8;
-		for (i = 0; i < blocks; i++) {
-			des3_decrypt(crypt, &des3key, plain);
-			plain += 8;
-			crypt += 8;
-		}
-	} else {
-#endif /* CCNS_PL */
-	switch (alg) {
-	case ENCR_3DES:
-		encr_alg = CRYPTO_CIPHER_ALG_3DES;
-		break;
-	case ENCR_AES_CBC:
-		encr_alg = CRYPTO_CIPHER_ALG_AES;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
-		return -1;
-	}
-
-	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
-	if (cipher == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
-		return -1;
-	}
-
-	if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Decryption failed");
-		crypto_cipher_deinit(cipher);
-		return -1;
-	}
-	crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
-	}
-#endif /* CCNS_PL */
-
-	return 0;
-}
-
-
-int ikev2_parse_payloads(struct ikev2_payloads *payloads,
-			 u8 next_payload, const u8 *pos, const u8 *end)
-{
-	const struct ikev2_payload_hdr *phdr;
-
-	os_memset(payloads, 0, sizeof(*payloads));
-
-	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
-		int plen, pdatalen;
-		const u8 *pdata;
-		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
-			   next_payload);
-		if (end - pos < (int) sizeof(*phdr)) {
-			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
-				   "payload header (left=%ld)",
-				   (long) (end - pos));
-		}
-		phdr = (const struct ikev2_payload_hdr *) pos;
-		plen = WPA_GET_BE16(phdr->payload_length);
-		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
-			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
-				   "length %d", plen);
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
-			   "  Payload Length: %d",
-			   phdr->next_payload, phdr->flags, plen);
-
-		pdata = (const u8 *) (phdr + 1);
-		pdatalen = plen - sizeof(*phdr);
-
-		switch (next_payload) {
-		case IKEV2_PAYLOAD_SA:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
-				   "Association");
-			payloads->sa = pdata;
-			payloads->sa_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_KEY_EXCHANGE:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
-				   "Exchange");
-			payloads->ke = pdata;
-			payloads->ke_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_IDi:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
-			payloads->idi = pdata;
-			payloads->idi_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_IDr:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
-			payloads->idr = pdata;
-			payloads->idr_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_CERTIFICATE:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
-			payloads->cert = pdata;
-			payloads->cert_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_AUTHENTICATION:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
-				   "Authentication");
-			payloads->auth = pdata;
-			payloads->auth_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_NONCE:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
-			payloads->nonce = pdata;
-			payloads->nonce_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_ENCRYPTED:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
-			payloads->encrypted = pdata;
-			payloads->encrypted_len = pdatalen;
-			break;
-		case IKEV2_PAYLOAD_NOTIFICATION:
-			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
-				   "Notification");
-			payloads->notification = pdata;
-			payloads->notification_len = pdatalen;
-			break;
-		default:
-			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
-				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
-					   "critical payload %u - reject the "
-					   "entire message", next_payload);
-				return -1;
-			} else {
-				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
-					   "unsupported payload %u",
-					   next_payload);
-			}
-		}
-
-		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
-		    pos + plen == end) {
-			/*
-			 * Next Payload in the case of Encrypted Payload is
-			 * actually the payload type for the first embedded
-			 * payload.
-			 */
-			payloads->encr_next_payload = phdr->next_payload;
-			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
-		} else
-			next_payload = phdr->next_payload;
-
-		pos += plen;
-	}
-
-	if (pos != end) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
-			   "payloads");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
-			   const u8 *ID, size_t ID_len, u8 ID_type,
-			   struct ikev2_keys *keys, int initiator,
-			   const u8 *shared_secret, size_t shared_secret_len,
-			   const u8 *nonce, size_t nonce_len,
-			   const u8 *key_pad, size_t key_pad_len,
-			   u8 *auth_data)
-{
-	size_t sign_len, buf_len;
-	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
-	const struct ikev2_prf_alg *prf;
-	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
-
-	prf = ikev2_get_prf(prf_alg);
-	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
-	    shared_secret == NULL || nonce == NULL || prf == NULL)
-		return -1;
-
-	/* prf(SK_pi/r,IDi/r') */
-	buf_len = 4 + ID_len;
-	buf = os_zalloc(buf_len);
-	if (buf == NULL)
-		return -1;
-	buf[0] = ID_type;
-	os_memcpy(buf + 4, ID, ID_len);
-	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
-			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
-		os_free(buf);
-		return -1;
-	}
-	os_free(buf);
-
-	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
-	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
-	sign_data = os_malloc(sign_len);
-	if (sign_data == NULL)
-		return -1;
-	pos = sign_data;
-	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
-	pos += wpabuf_len(sign_msg);
-	os_memcpy(pos, nonce, nonce_len);
-	pos += nonce_len;
-	os_memcpy(pos, hash, prf->hash_len);
-
-	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
-	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
-			   &key_pad, &key_pad_len, hash) < 0 ||
-	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
-			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
-	{
-		os_free(sign_data);
-		return -1;
-	}
-	os_free(sign_data);
-
-	return 0;
-}
-
-
-u8 * ikev2_decrypt_payload(int encr_id, int integ_id,
-			   struct ikev2_keys *keys, int initiator,
-			   const struct ikev2_hdr *hdr,
-			   const u8 *encrypted, size_t encrypted_len,
-			   size_t *res_len)
-{
-	size_t iv_len;
-	const u8 *pos, *end, *iv, *integ;
-	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
-	size_t decrypted_len, pad_len;
-	const struct ikev2_integ_alg *integ_alg;
-	const struct ikev2_encr_alg *encr_alg;
-	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
-	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
-
-	if (encrypted == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
-		return NULL;
-	}
-
-	encr_alg = ikev2_get_encr(encr_id);
-	if (encr_alg == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
-		return NULL;
-	}
-	iv_len = encr_alg->block_size;
-
-	integ_alg = ikev2_get_integ(integ_id);
-	if (integ_alg == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
-		return NULL;
-	}
-
-	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
-		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
-			  "Checksum");
-		return NULL;
-	}
-
-	iv = encrypted;
-	pos = iv + iv_len;
-	end = encrypted + encrypted_len;
-	integ = end - integ_alg->hash_len;
-
-	if (SK_a == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
-		return NULL;
-	}
-	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
-			     (const u8 *) hdr,
-			     integ - (const u8 *) hdr, hash) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
-			   "hash");
-		return NULL;
-	}
-	if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
-			   "Data");
-		return NULL;
-	}
-
-	if (SK_e == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
-		return NULL;
-	}
-
-	decrypted_len = integ - pos;
-	decrypted = os_malloc(decrypted_len);
-	if (decrypted == NULL)
-		return NULL;
-
-	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
-			       decrypted, decrypted_len) < 0) {
-		os_free(decrypted);
-		return NULL;
-	}
-
-	pad_len = decrypted[decrypted_len - 1];
-	if (decrypted_len < pad_len + 1) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
-			   "payload");
-		os_free(decrypted);
-		return NULL;
-	}
-
-	decrypted_len -= pad_len + 1;
-
-	*res_len = decrypted_len;
-	return decrypted;
-}
-
-
-void ikev2_update_hdr(struct wpabuf *msg)
-{
-	struct ikev2_hdr *hdr;
-
-	/* Update lenth field in HDR */
-	hdr = wpabuf_mhead(msg);
-	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
-}
-
-
-int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
-			  int initiator, struct wpabuf *msg,
-			  struct wpabuf *plain, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	size_t iv_len, pad_len;
-	u8 *icv, *iv;
-	const struct ikev2_integ_alg *integ_alg;
-	const struct ikev2_encr_alg *encr_alg;
-	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
-	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
-
-	/* Encr - RFC 4306, Sect. 3.14 */
-
-	encr_alg = ikev2_get_encr(encr_id);
-	if (encr_alg == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
-		return -1;
-	}
-	iv_len = encr_alg->block_size;
-
-	integ_alg = ikev2_get_integ(integ_id);
-	if (integ_alg == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
-		return -1;
-	}
-
-	if (SK_e == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
-		return -1;
-	}
-
-	if (SK_a == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
-		return -1;
-	}
-
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-
-	iv = wpabuf_put(msg, iv_len);
-	if (os_get_random(iv, iv_len)) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
-		return -1;
-	}
-
-	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
-	if (pad_len == iv_len)
-		pad_len = 0;
-	wpabuf_put(plain, pad_len);
-	wpabuf_put_u8(plain, pad_len);
-
-	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
-			       wpabuf_head(plain), wpabuf_mhead(plain),
-			       wpabuf_len(plain)) < 0)
-		return -1;
-
-	wpabuf_put_buf(msg, plain);
-
-	/* Need to update all headers (Length fields) prior to hash func */
-	icv = wpabuf_put(msg, integ_alg->hash_len);
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-
-	ikev2_update_hdr(msg);
-
-	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
-				wpabuf_head(msg),
-				wpabuf_len(msg) - integ_alg->hash_len, icv);
-
-	return 0;
-}
-
-
-int ikev2_keys_set(struct ikev2_keys *keys)
-{
-	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
-		keys->SK_er && keys->SK_pi && keys->SK_pr;
-}
-
-
-void ikev2_free_keys(struct ikev2_keys *keys)
-{
-	os_free(keys->SK_d);
-	os_free(keys->SK_ai);
-	os_free(keys->SK_ar);
-	os_free(keys->SK_ei);
-	os_free(keys->SK_er);
-	os_free(keys->SK_pi);
-	os_free(keys->SK_pr);
-	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
-		keys->SK_pi = keys->SK_pr = NULL;
-}
-
-
-int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
-			 const struct ikev2_integ_alg *integ,
-			 const struct ikev2_encr_alg *encr,
-			 const u8 *skeyseed, const u8 *data, size_t data_len,
-			 struct ikev2_keys *keys)
-{
-	u8 *keybuf, *pos;
-	size_t keybuf_len;
-
-	/*
-	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
-	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
-	 */
-	ikev2_free_keys(keys);
-	keys->SK_d_len = prf->key_len;
-	keys->SK_integ_len = integ->key_len;
-	keys->SK_encr_len = encr->key_len;
-	keys->SK_prf_len = prf->key_len;
-#ifdef CCNS_PL
-	/* Uses encryption key length for SK_d; should be PRF length */
-	keys->SK_d_len = keys->SK_encr_len;
-#endif /* CCNS_PL */
-
-	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
-		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
-	keybuf = os_malloc(keybuf_len);
-	if (keybuf == NULL)
-		return -1;
-
-	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
-			   data, data_len, keybuf, keybuf_len)) {
-		os_free(keybuf);
-		return -1;
-	}
-
-	pos = keybuf;
-
-	keys->SK_d = os_malloc(keys->SK_d_len);
-	if (keys->SK_d) {
-		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
-				keys->SK_d, keys->SK_d_len);
-	}
-	pos += keys->SK_d_len;
-
-	keys->SK_ai = os_malloc(keys->SK_integ_len);
-	if (keys->SK_ai) {
-		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
-				keys->SK_ai, keys->SK_integ_len);
-	}
-	pos += keys->SK_integ_len;
-
-	keys->SK_ar = os_malloc(keys->SK_integ_len);
-	if (keys->SK_ar) {
-		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
-				keys->SK_ar, keys->SK_integ_len);
-	}
-	pos += keys->SK_integ_len;
-
-	keys->SK_ei = os_malloc(keys->SK_encr_len);
-	if (keys->SK_ei) {
-		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
-				keys->SK_ei, keys->SK_encr_len);
-	}
-	pos += keys->SK_encr_len;
-
-	keys->SK_er = os_malloc(keys->SK_encr_len);
-	if (keys->SK_er) {
-		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
-				keys->SK_er, keys->SK_encr_len);
-	}
-	pos += keys->SK_encr_len;
-
-	keys->SK_pi = os_malloc(keys->SK_prf_len);
-	if (keys->SK_pi) {
-		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
-				keys->SK_pi, keys->SK_prf_len);
-	}
-	pos += keys->SK_prf_len;
-
-	keys->SK_pr = os_malloc(keys->SK_prf_len);
-	if (keys->SK_pr) {
-		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
-		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
-				keys->SK_pr, keys->SK_prf_len);
-	}
-
-	os_free(keybuf);
-
-	if (!ikev2_keys_set(keys)) {
-		ikev2_free_keys(keys);
-		return -1;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_common/ikev2_common.c (from rev 9639, vendor/wpa/dist/src/eap_common/ikev2_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_common/ikev2_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/ikev2_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,791 @@
+/*
+ * IKEv2 common routines for initiator and responder
+ * Copyright (c) 2007, Jouni Malinen <j at 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/crypto.h"
+#include "crypto/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/random.h"
+#include "ikev2_common.h"
+
+
+static struct ikev2_integ_alg ikev2_integ_algs[] = {
+	{ AUTH_HMAC_SHA1_96, 20, 12 },
+	{ AUTH_HMAC_MD5_96, 16, 12 }
+};
+
+#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
+
+
+static struct ikev2_prf_alg ikev2_prf_algs[] = {
+	{ PRF_HMAC_SHA1, 20, 20 },
+	{ PRF_HMAC_MD5, 16, 16 }
+};
+
+#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
+
+
+static struct ikev2_encr_alg ikev2_encr_algs[] = {
+	{ ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */
+	{ ENCR_3DES, 24, 8 }
+};
+
+#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
+
+
+const struct ikev2_integ_alg * ikev2_get_integ(int id)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_INTEG_ALGS; i++) {
+		if (ikev2_integ_algs[i].id == id)
+			return &ikev2_integ_algs[i];
+	}
+
+	return NULL;
+}
+
+
+int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
+		     size_t data_len, u8 *hash)
+{
+	u8 tmphash[IKEV2_MAX_HASH_LEN];
+
+	switch (alg) {
+	case AUTH_HMAC_SHA1_96:
+		if (key_len != 20)
+			return -1;
+		hmac_sha1(key, key_len, data, data_len, tmphash);
+		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);
+		os_memcpy(hash, tmphash, 12);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+const struct ikev2_prf_alg * ikev2_get_prf(int id)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_PRF_ALGS; i++) {
+		if (ikev2_prf_algs[i].id == id)
+			return &ikev2_prf_algs[i];
+	}
+
+	return NULL;
+}
+
+
+int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
+		   size_t num_elem, const u8 *addr[], const size_t *len,
+		   u8 *hash)
+{
+	switch (alg) {
+	case PRF_HMAC_SHA1:
+		hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
+		break;
+	case PRF_HMAC_MD5:
+		hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
+		   const u8 *data, size_t data_len,
+		   u8 *out, size_t out_len)
+{
+	u8 hash[IKEV2_MAX_HASH_LEN];
+	size_t hash_len;
+	u8 iter, *pos, *end;
+	const u8 *addr[3];
+	size_t len[3];
+	const struct ikev2_prf_alg *prf;
+	int res;
+
+	prf = ikev2_get_prf(alg);
+	if (prf == NULL)
+		return -1;
+	hash_len = prf->hash_len;
+
+	addr[0] = hash;
+	len[0] = hash_len;
+	addr[1] = data;
+	len[1] = data_len;
+	addr[2] = &iter;
+	len[2] = 1;
+
+	pos = out;
+	end = out + out_len;
+	iter = 1;
+	while (pos < end) {
+		size_t clen;
+		if (iter == 1)
+			res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1],
+					     &len[1], hash);
+		else
+			res = ikev2_prf_hash(alg, key, key_len, 3, addr, len,
+					     hash);
+		if (res < 0)
+			return -1;
+		clen = hash_len;
+		if ((int) clen > end - pos)
+			clen = end - pos;
+		os_memcpy(pos, hash, clen);
+		pos += clen;
+		iter++;
+	}
+
+	return 0;
+}
+
+
+const struct ikev2_encr_alg * ikev2_get_encr(int id)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_ENCR_ALGS; i++) {
+		if (ikev2_encr_algs[i].id == id)
+			return &ikev2_encr_algs[i];
+	}
+
+	return NULL;
+}
+
+
+#ifdef CCNS_PL
+/* from des.c */
+struct des3_key_s {
+	u32 ek[3][32];
+	u32 dk[3][32];
+};
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
+#endif /* CCNS_PL */
+
+
+int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
+		       const u8 *plain, u8 *crypt, size_t len)
+{
+	struct crypto_cipher *cipher;
+	int encr_alg;
+
+#ifdef CCNS_PL
+	if (alg == ENCR_3DES) {
+		struct des3_key_s des3key;
+		size_t i, blocks;
+		u8 *pos;
+
+		/* ECB mode is used incorrectly for 3DES!? */
+		if (key_len != 24) {
+			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
+			return -1;
+		}
+		des3_key_setup(key, &des3key);
+
+		blocks = len / 8;
+		pos = crypt;
+		for (i = 0; i < blocks; i++) {
+			des3_encrypt(pos, &des3key, pos);
+			pos += 8;
+		}
+	} else {
+#endif /* CCNS_PL */
+	switch (alg) {
+	case ENCR_3DES:
+		encr_alg = CRYPTO_CIPHER_ALG_3DES;
+		break;
+	case ENCR_AES_CBC:
+		encr_alg = CRYPTO_CIPHER_ALG_AES;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
+		return -1;
+	}
+
+	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
+	if (cipher == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
+		return -1;
+	}
+
+	if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Encryption failed");
+		crypto_cipher_deinit(cipher);
+		return -1;
+	}
+	crypto_cipher_deinit(cipher);
+#ifdef CCNS_PL
+	}
+#endif /* CCNS_PL */
+
+	return 0;
+}
+
+
+int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
+		       const u8 *crypt, u8 *plain, size_t len)
+{
+	struct crypto_cipher *cipher;
+	int encr_alg;
+
+#ifdef CCNS_PL
+	if (alg == ENCR_3DES) {
+		struct des3_key_s des3key;
+		size_t i, blocks;
+
+		/* ECB mode is used incorrectly for 3DES!? */
+		if (key_len != 24) {
+			wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
+			return -1;
+		}
+		des3_key_setup(key, &des3key);
+
+		if (len % 8) {
+			wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
+				   "length");
+			return -1;
+		}
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			des3_decrypt(crypt, &des3key, plain);
+			plain += 8;
+			crypt += 8;
+		}
+	} else {
+#endif /* CCNS_PL */
+	switch (alg) {
+	case ENCR_3DES:
+		encr_alg = CRYPTO_CIPHER_ALG_3DES;
+		break;
+	case ENCR_AES_CBC:
+		encr_alg = CRYPTO_CIPHER_ALG_AES;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg);
+		return -1;
+	}
+
+	cipher = crypto_cipher_init(encr_alg, iv, key, key_len);
+	if (cipher == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher");
+		return -1;
+	}
+
+	if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Decryption failed");
+		crypto_cipher_deinit(cipher);
+		return -1;
+	}
+	crypto_cipher_deinit(cipher);
+#ifdef CCNS_PL
+	}
+#endif /* CCNS_PL */
+
+	return 0;
+}
+
+
+int ikev2_parse_payloads(struct ikev2_payloads *payloads,
+			 u8 next_payload, const u8 *pos, const u8 *end)
+{
+	const struct ikev2_payload_hdr *phdr;
+
+	os_memset(payloads, 0, sizeof(*payloads));
+
+	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
+		int plen, pdatalen;
+		const u8 *pdata;
+		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
+			   next_payload);
+		if (end - pos < (int) sizeof(*phdr)) {
+			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
+				   "payload header (left=%ld)",
+				   (long) (end - pos));
+		}
+		phdr = (const struct ikev2_payload_hdr *) pos;
+		plen = WPA_GET_BE16(phdr->payload_length);
+		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
+			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
+				   "length %d", plen);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
+			   "  Payload Length: %d",
+			   phdr->next_payload, phdr->flags, plen);
+
+		pdata = (const u8 *) (phdr + 1);
+		pdatalen = plen - sizeof(*phdr);
+
+		switch (next_payload) {
+		case IKEV2_PAYLOAD_SA:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Security "
+				   "Association");
+			payloads->sa = pdata;
+			payloads->sa_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_KEY_EXCHANGE:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Key "
+				   "Exchange");
+			payloads->ke = pdata;
+			payloads->ke_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_IDi:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDi");
+			payloads->idi = pdata;
+			payloads->idi_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_IDr:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: IDr");
+			payloads->idr = pdata;
+			payloads->idr_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_CERTIFICATE:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Certificate");
+			payloads->cert = pdata;
+			payloads->cert_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_AUTHENTICATION:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
+				   "Authentication");
+			payloads->auth = pdata;
+			payloads->auth_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_NONCE:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Nonce");
+			payloads->nonce = pdata;
+			payloads->nonce_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_ENCRYPTED:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: Encrypted");
+			payloads->encrypted = pdata;
+			payloads->encrypted_len = pdatalen;
+			break;
+		case IKEV2_PAYLOAD_NOTIFICATION:
+			wpa_printf(MSG_DEBUG, "IKEV2:   Payload: "
+				   "Notification");
+			payloads->notification = pdata;
+			payloads->notification_len = pdatalen;
+			break;
+		default:
+			if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) {
+				wpa_printf(MSG_INFO, "IKEV2:   Unsupported "
+					   "critical payload %u - reject the "
+					   "entire message", next_payload);
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "IKEV2:   Skipped "
+					   "unsupported payload %u",
+					   next_payload);
+			}
+		}
+
+		if (next_payload == IKEV2_PAYLOAD_ENCRYPTED &&
+		    pos + plen == end) {
+			/*
+			 * Next Payload in the case of Encrypted Payload is
+			 * actually the payload type for the first embedded
+			 * payload.
+			 */
+			payloads->encr_next_payload = phdr->next_payload;
+			next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD;
+		} else
+			next_payload = phdr->next_payload;
+
+		pos += plen;
+	}
+
+	if (pos != end) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after "
+			   "payloads");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
+			   const u8 *ID, size_t ID_len, u8 ID_type,
+			   struct ikev2_keys *keys, int initiator,
+			   const u8 *shared_secret, size_t shared_secret_len,
+			   const u8 *nonce, size_t nonce_len,
+			   const u8 *key_pad, size_t key_pad_len,
+			   u8 *auth_data)
+{
+	size_t sign_len, buf_len;
+	u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN];
+	const struct ikev2_prf_alg *prf;
+	const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr;
+
+	prf = ikev2_get_prf(prf_alg);
+	if (sign_msg == NULL || ID == NULL || SK_p == NULL ||
+	    shared_secret == NULL || nonce == NULL || prf == NULL)
+		return -1;
+
+	/* prf(SK_pi/r,IDi/r') */
+	buf_len = 4 + ID_len;
+	buf = os_zalloc(buf_len);
+	if (buf == NULL)
+		return -1;
+	buf[0] = ID_type;
+	os_memcpy(buf + 4, ID, ID_len);
+	if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len,
+			   1, (const u8 **) &buf, &buf_len, hash) < 0) {
+		os_free(buf);
+		return -1;
+	}
+	os_free(buf);
+
+	/* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */
+	sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len;
+	sign_data = os_malloc(sign_len);
+	if (sign_data == NULL)
+		return -1;
+	pos = sign_data;
+	os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg));
+	pos += wpabuf_len(sign_msg);
+	os_memcpy(pos, nonce, nonce_len);
+	pos += nonce_len;
+	os_memcpy(pos, hash, prf->hash_len);
+
+	/* AUTH = prf(prf(Shared Secret, key pad, sign_data) */
+	if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1,
+			   &key_pad, &key_pad_len, hash) < 0 ||
+	    ikev2_prf_hash(prf->id, hash, prf->hash_len, 1,
+			   (const u8 **) &sign_data, &sign_len, auth_data) < 0)
+	{
+		os_free(sign_data);
+		return -1;
+	}
+	os_free(sign_data);
+
+	return 0;
+}
+
+
+u8 * ikev2_decrypt_payload(int encr_id, int integ_id,
+			   struct ikev2_keys *keys, int initiator,
+			   const struct ikev2_hdr *hdr,
+			   const u8 *encrypted, size_t encrypted_len,
+			   size_t *res_len)
+{
+	size_t iv_len;
+	const u8 *pos, *end, *iv, *integ;
+	u8 hash[IKEV2_MAX_HASH_LEN], *decrypted;
+	size_t decrypted_len, pad_len;
+	const struct ikev2_integ_alg *integ_alg;
+	const struct ikev2_encr_alg *encr_alg;
+	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
+	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
+
+	if (encrypted == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH");
+		return NULL;
+	}
+
+	encr_alg = ikev2_get_encr(encr_id);
+	if (encr_alg == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
+		return NULL;
+	}
+	iv_len = encr_alg->block_size;
+
+	integ_alg = ikev2_get_integ(integ_id);
+	if (integ_alg == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
+		return NULL;
+	}
+
+	if (encrypted_len < iv_len + 1 + integ_alg->hash_len) {
+		wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity "
+			  "Checksum");
+		return NULL;
+	}
+
+	iv = encrypted;
+	pos = iv + iv_len;
+	end = encrypted + encrypted_len;
+	integ = end - integ_alg->hash_len;
+
+	if (SK_a == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
+		return NULL;
+	}
+	if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
+			     (const u8 *) hdr,
+			     integ - (const u8 *) hdr, hash) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity "
+			   "hash");
+		return NULL;
+	}
+	if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
+			   "Data");
+		return NULL;
+	}
+
+	if (SK_e == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
+		return NULL;
+	}
+
+	decrypted_len = integ - pos;
+	decrypted = os_malloc(decrypted_len);
+	if (decrypted == NULL)
+		return NULL;
+
+	if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos,
+			       decrypted, decrypted_len) < 0) {
+		os_free(decrypted);
+		return NULL;
+	}
+
+	pad_len = decrypted[decrypted_len - 1];
+	if (decrypted_len < pad_len + 1) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted "
+			   "payload");
+		os_free(decrypted);
+		return NULL;
+	}
+
+	decrypted_len -= pad_len + 1;
+
+	*res_len = decrypted_len;
+	return decrypted;
+}
+
+
+void ikev2_update_hdr(struct wpabuf *msg)
+{
+	struct ikev2_hdr *hdr;
+
+	/* Update lenth field in HDR */
+	hdr = wpabuf_mhead(msg);
+	WPA_PUT_BE32(hdr->length, wpabuf_len(msg));
+}
+
+
+int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
+			  int initiator, struct wpabuf *msg,
+			  struct wpabuf *plain, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	size_t iv_len, pad_len;
+	u8 *icv, *iv;
+	const struct ikev2_integ_alg *integ_alg;
+	const struct ikev2_encr_alg *encr_alg;
+	const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er;
+	const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload");
+
+	/* Encr - RFC 4306, Sect. 3.14 */
+
+	encr_alg = ikev2_get_encr(encr_id);
+	if (encr_alg == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type");
+		return -1;
+	}
+	iv_len = encr_alg->block_size;
+
+	integ_alg = ikev2_get_integ(integ_id);
+	if (integ_alg == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type");
+		return -1;
+	}
+
+	if (SK_e == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No SK_e available");
+		return -1;
+	}
+
+	if (SK_a == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No SK_a available");
+		return -1;
+	}
+
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+
+	iv = wpabuf_put(msg, iv_len);
+	if (random_get_bytes(iv, iv_len)) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not generate IV");
+		return -1;
+	}
+
+	pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len;
+	if (pad_len == iv_len)
+		pad_len = 0;
+	wpabuf_put(plain, pad_len);
+	wpabuf_put_u8(plain, pad_len);
+
+	if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv,
+			       wpabuf_head(plain), wpabuf_mhead(plain),
+			       wpabuf_len(plain)) < 0)
+		return -1;
+
+	wpabuf_put_buf(msg, plain);
+
+	/* Need to update all headers (Length fields) prior to hash func */
+	icv = wpabuf_put(msg, integ_alg->hash_len);
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+
+	ikev2_update_hdr(msg);
+
+	return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len,
+				wpabuf_head(msg),
+				wpabuf_len(msg) - integ_alg->hash_len, icv);
+
+	return 0;
+}
+
+
+int ikev2_keys_set(struct ikev2_keys *keys)
+{
+	return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei &&
+		keys->SK_er && keys->SK_pi && keys->SK_pr;
+}
+
+
+void ikev2_free_keys(struct ikev2_keys *keys)
+{
+	os_free(keys->SK_d);
+	os_free(keys->SK_ai);
+	os_free(keys->SK_ar);
+	os_free(keys->SK_ei);
+	os_free(keys->SK_er);
+	os_free(keys->SK_pi);
+	os_free(keys->SK_pr);
+	keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er =
+		keys->SK_pi = keys->SK_pr = NULL;
+}
+
+
+int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
+			 const struct ikev2_integ_alg *integ,
+			 const struct ikev2_encr_alg *encr,
+			 const u8 *skeyseed, const u8 *data, size_t data_len,
+			 struct ikev2_keys *keys)
+{
+	u8 *keybuf, *pos;
+	size_t keybuf_len;
+
+	/*
+	 * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } =
+	 *	prf+(SKEYSEED, Ni | Nr | SPIi | SPIr )
+	 */
+	ikev2_free_keys(keys);
+	keys->SK_d_len = prf->key_len;
+	keys->SK_integ_len = integ->key_len;
+	keys->SK_encr_len = encr->key_len;
+	keys->SK_prf_len = prf->key_len;
+#ifdef CCNS_PL
+	/* Uses encryption key length for SK_d; should be PRF length */
+	keys->SK_d_len = keys->SK_encr_len;
+#endif /* CCNS_PL */
+
+	keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
+		2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
+	keybuf = os_malloc(keybuf_len);
+	if (keybuf == NULL)
+		return -1;
+
+	if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len,
+			   data, data_len, keybuf, keybuf_len)) {
+		os_free(keybuf);
+		return -1;
+	}
+
+	pos = keybuf;
+
+	keys->SK_d = os_malloc(keys->SK_d_len);
+	if (keys->SK_d) {
+		os_memcpy(keys->SK_d, pos, keys->SK_d_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d",
+				keys->SK_d, keys->SK_d_len);
+	}
+	pos += keys->SK_d_len;
+
+	keys->SK_ai = os_malloc(keys->SK_integ_len);
+	if (keys->SK_ai) {
+		os_memcpy(keys->SK_ai, pos, keys->SK_integ_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai",
+				keys->SK_ai, keys->SK_integ_len);
+	}
+	pos += keys->SK_integ_len;
+
+	keys->SK_ar = os_malloc(keys->SK_integ_len);
+	if (keys->SK_ar) {
+		os_memcpy(keys->SK_ar, pos, keys->SK_integ_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar",
+				keys->SK_ar, keys->SK_integ_len);
+	}
+	pos += keys->SK_integ_len;
+
+	keys->SK_ei = os_malloc(keys->SK_encr_len);
+	if (keys->SK_ei) {
+		os_memcpy(keys->SK_ei, pos, keys->SK_encr_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei",
+				keys->SK_ei, keys->SK_encr_len);
+	}
+	pos += keys->SK_encr_len;
+
+	keys->SK_er = os_malloc(keys->SK_encr_len);
+	if (keys->SK_er) {
+		os_memcpy(keys->SK_er, pos, keys->SK_encr_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er",
+				keys->SK_er, keys->SK_encr_len);
+	}
+	pos += keys->SK_encr_len;
+
+	keys->SK_pi = os_malloc(keys->SK_prf_len);
+	if (keys->SK_pi) {
+		os_memcpy(keys->SK_pi, pos, keys->SK_prf_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi",
+				keys->SK_pi, keys->SK_prf_len);
+	}
+	pos += keys->SK_prf_len;
+
+	keys->SK_pr = os_malloc(keys->SK_prf_len);
+	if (keys->SK_pr) {
+		os_memcpy(keys->SK_pr, pos, keys->SK_prf_len);
+		wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr",
+				keys->SK_pr, keys->SK_prf_len);
+	}
+
+	os_free(keybuf);
+
+	if (!ikev2_keys_set(keys)) {
+		ikev2_free_keys(keys);
+		return -1;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_common/ikev2_common.h
===================================================================
--- vendor/wpa/dist/src/eap_common/ikev2_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_common/ikev2_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,344 +0,0 @@
-/*
- * IKEv2 definitions
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IKEV2_COMMON_H
-#define IKEV2_COMMON_H
-
-/*
- * Nonce length must be at least 16 octets. It must also be at least half the
- * key size of the negotiated PRF.
- */
-#define IKEV2_NONCE_MIN_LEN 16
-#define IKEV2_NONCE_MAX_LEN 256
-
-/* IKE Header - RFC 4306, Sect. 3.1 */
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-#define IKEV2_SPI_LEN 8
-
-struct ikev2_hdr {
-	u8 i_spi[IKEV2_SPI_LEN]; /* IKE_SA Initiator's SPI */
-	u8 r_spi[IKEV2_SPI_LEN]; /* IKE_SA Responder's SPI */
-	u8 next_payload;
-	u8 version; /* MjVer | MnVer */
-	u8 exchange_type;
-	u8 flags;
-	u8 message_id[4];
-	u8 length[4]; /* total length of HDR + payloads */
-} STRUCT_PACKED;
-
-struct ikev2_payload_hdr {
-	u8 next_payload;
-	u8 flags;
-	u8 payload_length[2]; /* this payload, including the payload header */
-} STRUCT_PACKED;
-
-struct ikev2_proposal {
-	u8 type; /* 0 (last) or 2 (more) */
-	u8 reserved;
-	u8 proposal_length[2]; /* including all transform and attributes */
-	u8 proposal_num;
-	u8 protocol_id; /* IKEV2_PROTOCOL_* */
-	u8 spi_size;
-	u8 num_transforms;
-	/* SPI of spi_size octets */
-	/* Transforms */
-} STRUCT_PACKED;
-
-struct ikev2_transform {
-	u8 type; /* 0 (last) or 3 (more) */
-	u8 reserved;
-	u8 transform_length[2]; /* including Header and Attributes */
-	u8 transform_type;
-	u8 reserved2;
-	u8 transform_id[2];
-	/* Transform Attributes */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-/* Current IKEv2 version from RFC 4306 */
-#define IKEV2_MjVer 2
-#define IKEV2_MnVer 0
-#ifdef CCNS_PL
-#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4))
-#else /* CCNS_PL */
-#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer))
-#endif /* CCNS_PL */
-
-/* IKEv2 Exchange Types */
-enum {
-	/* 0-33 RESERVED */
-	IKE_SA_INIT = 34,
-	IKE_SA_AUTH = 35,
-	CREATE_CHILD_SA = 36,
-	INFORMATION = 37
-	/* 38-239 RESERVED TO IANA */
-	/* 240-255 Reserved for private use */
-};
-
-/* IKEv2 Flags */
-#define IKEV2_HDR_INITIATOR	0x08
-#define IKEV2_HDR_VERSION	0x10
-#define IKEV2_HDR_RESPONSE	0x20
-
-/* Payload Header Flags */
-#define IKEV2_PAYLOAD_FLAGS_CRITICAL 0x01
-
-
-/* EAP-IKEv2 Payload Types (in Next Payload Type field)
- * http://www.iana.org/assignments/eap-ikev2-payloads */
-enum {
-	IKEV2_PAYLOAD_NO_NEXT_PAYLOAD = 0,
-	IKEV2_PAYLOAD_SA = 33,
-	IKEV2_PAYLOAD_KEY_EXCHANGE = 34,
-	IKEV2_PAYLOAD_IDi = 35,
-	IKEV2_PAYLOAD_IDr = 36,
-	IKEV2_PAYLOAD_CERTIFICATE = 37,
-	IKEV2_PAYLOAD_CERT_REQ = 38,
-	IKEV2_PAYLOAD_AUTHENTICATION = 39,
-	IKEV2_PAYLOAD_NONCE = 40,
-	IKEV2_PAYLOAD_NOTIFICATION = 41,
-	IKEV2_PAYLOAD_VENDOD_ID = 43,
-	IKEV2_PAYLOAD_ENCRYPTED = 46,
-	IKEV2_PAYLOAD_NEXT_FAST_ID = 121
-};
-
-
-/* IKEv2 Proposal - Protocol ID */
-enum {
-	IKEV2_PROTOCOL_RESERVED = 0,
-	IKEV2_PROTOCOL_IKE = 1, /* IKE is the only one allowed for EAP-IKEv2 */
-	IKEV2_PROTOCOL_AH = 2,
-	IKEV2_PROTOCOL_ESP = 3
-};
-
-
-/* IKEv2 Transform Types */
-enum {
-	IKEV2_TRANSFORM_ENCR = 1,
-	IKEV2_TRANSFORM_PRF = 2,
-	IKEV2_TRANSFORM_INTEG = 3,
-	IKEV2_TRANSFORM_DH = 4,
-	IKEV2_TRANSFORM_ESN = 5
-};
-
-/* IKEv2 Tranform Type 1 (Encryption Algorithm) */
-enum {
-	ENCR_DES_IV64 = 1,
-	ENCR_DES = 2,
-	ENCR_3DES = 3,
-	ENCR_RC5 = 4,
-	ENCR_IDEA = 5,
-	ENCR_CAST = 6,
-	ENCR_BLOWFISH = 7,
-	ENCR_3IDEA = 8,
-	ENCR_DES_IV32 = 9,
-	ENCR_NULL = 11,
-	ENCR_AES_CBC = 12,
-	ENCR_AES_CTR = 13
-};
-
-/* IKEv2 Transform Type 2 (Pseudo-random Function) */
-enum {
-	PRF_HMAC_MD5 = 1,
-	PRF_HMAC_SHA1 = 2,
-	PRF_HMAC_TIGER = 3,
-	PRF_AES128_XCBC = 4
-};
-
-/* IKEv2 Transform Type 3 (Integrity Algorithm) */
-enum {
-	AUTH_HMAC_MD5_96 = 1,
-	AUTH_HMAC_SHA1_96 = 2,
-	AUTH_DES_MAC = 3,
-	AUTH_KPDK_MD5 = 4,
-	AUTH_AES_XCBC_96 = 5
-};
-
-/* IKEv2 Transform Type 4 (Diffie-Hellman Group) */
-enum {
-	DH_GROUP1_768BIT_MODP = 1, /* RFC 4306 */
-	DH_GROUP2_1024BIT_MODP = 2, /* RFC 4306 */
-	DH_GROUP5_1536BIT_MODP = 5, /* RFC 3526 */
-	DH_GROUP5_2048BIT_MODP = 14, /* RFC 3526 */
-	DH_GROUP5_3072BIT_MODP = 15, /* RFC 3526 */
-	DH_GROUP5_4096BIT_MODP = 16, /* RFC 3526 */
-	DH_GROUP5_6144BIT_MODP = 17, /* RFC 3526 */
-	DH_GROUP5_8192BIT_MODP = 18 /* RFC 3526 */
-};
-
-
-/* Identification Data Types (RFC 4306, Sect. 3.5) */
-enum {
-	ID_IPV4_ADDR = 1,
-	ID_FQDN = 2,
-	ID_RFC822_ADDR = 3,
-	ID_IPV6_ADDR = 5,
-	ID_DER_ASN1_DN = 9,
-	ID_DER_ASN1_GN= 10,
-	ID_KEY_ID = 11
-};
-
-
-/* Certificate Encoding (RFC 4306, Sect. 3.6) */
-enum {
-	CERT_ENCODING_PKCS7_X509 = 1,
-	CERT_ENCODING_PGP_CERT = 2,
-	CERT_ENCODING_DNS_SIGNED_KEY = 3,
-	/* X.509 Certificate - Signature: DER encoded X.509 certificate whose
-	 * public key is used to validate the sender's AUTH payload */
-	CERT_ENCODING_X509_CERT_SIGN = 4,
-	CERT_ENCODING_KERBEROS_TOKEN = 6,
-	/* DER encoded X.509 certificate revocation list */
-	CERT_ENCODING_CRL = 7,
-	CERT_ENCODING_ARL = 8,
-	CERT_ENCODING_SPKI_CERT = 9,
-	CERT_ENCODING_X509_CERT_ATTR = 10,
-	/* PKCS #1 encoded RSA key */
-	CERT_ENCODING_RAW_RSA_KEY = 11,
-	CERT_ENCODING_HASH_AND_URL_X509_CERT = 12,
-	CERT_ENCODING_HASH_AND_URL_X509_BUNDLE = 13
-};
-
-
-/* Authentication Method (RFC 4306, Sect. 3.8) */
-enum {
-	AUTH_RSA_SIGN = 1,
-	AUTH_SHARED_KEY_MIC = 2,
-	AUTH_DSS_SIGN = 3
-};
-
-
-/* Notify Message Types (RFC 4306, Sect. 3.10.1) */
-enum {
-	UNSUPPORTED_CRITICAL_PAYLOAD = 1,
-	INVALID_IKE_SPI = 4,
-	INVALID_MAJOR_VERSION = 5,
-	INVALID_SYNTAX = 7,
-	INVALID_MESSAGE_ID = 9,
-	INVALID_SPI = 11,
-	NO_PROPOSAL_CHOSEN = 14,
-	INVALID_KE_PAYLOAD = 17,
-	AUTHENTICATION_FAILED = 24,
-	SINGLE_PAIR_REQUIRED = 34,
-	NO_ADDITIONAL_SAS = 35,
-	INTERNAL_ADDRESS_FAILURE = 36,
-	FAILED_CP_REQUIRED = 37,
-	TS_UNACCEPTABLE = 38,
-	INVALID_SELECTORS = 39
-};
-
-
-struct ikev2_keys {
-	u8 *SK_d, *SK_ai, *SK_ar, *SK_ei, *SK_er, *SK_pi, *SK_pr;
-	size_t SK_d_len, SK_integ_len, SK_encr_len, SK_prf_len;
-};
-
-
-int ikev2_keys_set(struct ikev2_keys *keys);
-void ikev2_free_keys(struct ikev2_keys *keys);
-
-
-/* Maximum hash length for supported hash algorithms */
-#define IKEV2_MAX_HASH_LEN 20
-
-struct ikev2_integ_alg {
-	int id;
-	size_t key_len;
-	size_t hash_len;
-};
-
-struct ikev2_prf_alg {
-	int id;
-	size_t key_len;
-	size_t hash_len;
-};
-
-struct ikev2_encr_alg {
-	int id;
-	size_t key_len;
-	size_t block_size;
-};
-
-const struct ikev2_integ_alg * ikev2_get_integ(int id);
-int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
-		     size_t data_len, u8 *hash);
-const struct ikev2_prf_alg * ikev2_get_prf(int id);
-int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
-		   size_t num_elem, const u8 *addr[], const size_t *len,
-		   u8 *hash);
-int ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
-		   const u8 *data, size_t data_len,
-		   u8 *out, size_t out_len);
-const struct ikev2_encr_alg * ikev2_get_encr(int id);
-int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
-		       const u8 *plain, u8 *crypt, size_t len);
-int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
-		       const u8 *crypt, u8 *plain, size_t len);
-
-int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
-			   const u8 *ID, size_t ID_len, u8 ID_type,
-			   struct ikev2_keys *keys, int initiator,
-			   const u8 *shared_secret, size_t shared_secret_len,
-			   const u8 *nonce, size_t nonce_len,
-			   const u8 *key_pad, size_t key_pad_len,
-			   u8 *auth_data);
-
-
-struct ikev2_payloads {
-	const u8 *sa;
-	size_t sa_len;
-	const u8 *ke;
-	size_t ke_len;
-	const u8 *idi;
-	size_t idi_len;
-	const u8 *idr;
-	size_t idr_len;
-	const u8 *cert;
-	size_t cert_len;
-	const u8 *auth;
-	size_t auth_len;
-	const u8 *nonce;
-	size_t nonce_len;
-	const u8 *encrypted;
-	size_t encrypted_len;
-	u8 encr_next_payload;
-	const u8 *notification;
-	size_t notification_len;
-};
-
-int ikev2_parse_payloads(struct ikev2_payloads *payloads,
-			 u8 next_payload, const u8 *pos, const u8 *end);
-
-u8 * ikev2_decrypt_payload(int encr_id, int integ_id, struct ikev2_keys *keys,
-			   int initiator, const struct ikev2_hdr *hdr,
-			   const u8 *encrypted, size_t encrypted_len,
-			   size_t *res_len);
-void ikev2_update_hdr(struct wpabuf *msg);
-int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
-			  int initiator, struct wpabuf *msg,
-			  struct wpabuf *plain, u8 next_payload);
-int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
-			 const struct ikev2_integ_alg *integ,
-			 const struct ikev2_encr_alg *encr,
-			 const u8 *skeyseed, const u8 *data, size_t data_len,
-			 struct ikev2_keys *keys);
-
-#endif /* IKEV2_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_common/ikev2_common.h (from rev 9639, vendor/wpa/dist/src/eap_common/ikev2_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_common/ikev2_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_common/ikev2_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,338 @@
+/*
+ * IKEv2 definitions
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IKEV2_COMMON_H
+#define IKEV2_COMMON_H
+
+/*
+ * Nonce length must be at least 16 octets. It must also be at least half the
+ * key size of the negotiated PRF.
+ */
+#define IKEV2_NONCE_MIN_LEN 16
+#define IKEV2_NONCE_MAX_LEN 256
+
+/* IKE Header - RFC 4306, Sect. 3.1 */
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#define IKEV2_SPI_LEN 8
+
+struct ikev2_hdr {
+	u8 i_spi[IKEV2_SPI_LEN]; /* IKE_SA Initiator's SPI */
+	u8 r_spi[IKEV2_SPI_LEN]; /* IKE_SA Responder's SPI */
+	u8 next_payload;
+	u8 version; /* MjVer | MnVer */
+	u8 exchange_type;
+	u8 flags;
+	u8 message_id[4];
+	u8 length[4]; /* total length of HDR + payloads */
+} STRUCT_PACKED;
+
+struct ikev2_payload_hdr {
+	u8 next_payload;
+	u8 flags;
+	u8 payload_length[2]; /* this payload, including the payload header */
+} STRUCT_PACKED;
+
+struct ikev2_proposal {
+	u8 type; /* 0 (last) or 2 (more) */
+	u8 reserved;
+	u8 proposal_length[2]; /* including all transform and attributes */
+	u8 proposal_num;
+	u8 protocol_id; /* IKEV2_PROTOCOL_* */
+	u8 spi_size;
+	u8 num_transforms;
+	/* SPI of spi_size octets */
+	/* Transforms */
+} STRUCT_PACKED;
+
+struct ikev2_transform {
+	u8 type; /* 0 (last) or 3 (more) */
+	u8 reserved;
+	u8 transform_length[2]; /* including Header and Attributes */
+	u8 transform_type;
+	u8 reserved2;
+	u8 transform_id[2];
+	/* Transform Attributes */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+/* Current IKEv2 version from RFC 4306 */
+#define IKEV2_MjVer 2
+#define IKEV2_MnVer 0
+#ifdef CCNS_PL
+#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4))
+#else /* CCNS_PL */
+#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer))
+#endif /* CCNS_PL */
+
+/* IKEv2 Exchange Types */
+enum {
+	/* 0-33 RESERVED */
+	IKE_SA_INIT = 34,
+	IKE_SA_AUTH = 35,
+	CREATE_CHILD_SA = 36,
+	INFORMATION = 37
+	/* 38-239 RESERVED TO IANA */
+	/* 240-255 Reserved for private use */
+};
+
+/* IKEv2 Flags */
+#define IKEV2_HDR_INITIATOR	0x08
+#define IKEV2_HDR_VERSION	0x10
+#define IKEV2_HDR_RESPONSE	0x20
+
+/* Payload Header Flags */
+#define IKEV2_PAYLOAD_FLAGS_CRITICAL 0x01
+
+
+/* EAP-IKEv2 Payload Types (in Next Payload Type field)
+ * http://www.iana.org/assignments/eap-ikev2-payloads */
+enum {
+	IKEV2_PAYLOAD_NO_NEXT_PAYLOAD = 0,
+	IKEV2_PAYLOAD_SA = 33,
+	IKEV2_PAYLOAD_KEY_EXCHANGE = 34,
+	IKEV2_PAYLOAD_IDi = 35,
+	IKEV2_PAYLOAD_IDr = 36,
+	IKEV2_PAYLOAD_CERTIFICATE = 37,
+	IKEV2_PAYLOAD_CERT_REQ = 38,
+	IKEV2_PAYLOAD_AUTHENTICATION = 39,
+	IKEV2_PAYLOAD_NONCE = 40,
+	IKEV2_PAYLOAD_NOTIFICATION = 41,
+	IKEV2_PAYLOAD_VENDOD_ID = 43,
+	IKEV2_PAYLOAD_ENCRYPTED = 46,
+	IKEV2_PAYLOAD_NEXT_FAST_ID = 121
+};
+
+
+/* IKEv2 Proposal - Protocol ID */
+enum {
+	IKEV2_PROTOCOL_RESERVED = 0,
+	IKEV2_PROTOCOL_IKE = 1, /* IKE is the only one allowed for EAP-IKEv2 */
+	IKEV2_PROTOCOL_AH = 2,
+	IKEV2_PROTOCOL_ESP = 3
+};
+
+
+/* IKEv2 Transform Types */
+enum {
+	IKEV2_TRANSFORM_ENCR = 1,
+	IKEV2_TRANSFORM_PRF = 2,
+	IKEV2_TRANSFORM_INTEG = 3,
+	IKEV2_TRANSFORM_DH = 4,
+	IKEV2_TRANSFORM_ESN = 5
+};
+
+/* IKEv2 Transform Type 1 (Encryption Algorithm) */
+enum {
+	ENCR_DES_IV64 = 1,
+	ENCR_DES = 2,
+	ENCR_3DES = 3,
+	ENCR_RC5 = 4,
+	ENCR_IDEA = 5,
+	ENCR_CAST = 6,
+	ENCR_BLOWFISH = 7,
+	ENCR_3IDEA = 8,
+	ENCR_DES_IV32 = 9,
+	ENCR_NULL = 11,
+	ENCR_AES_CBC = 12,
+	ENCR_AES_CTR = 13
+};
+
+/* IKEv2 Transform Type 2 (Pseudo-random Function) */
+enum {
+	PRF_HMAC_MD5 = 1,
+	PRF_HMAC_SHA1 = 2,
+	PRF_HMAC_TIGER = 3,
+	PRF_AES128_XCBC = 4
+};
+
+/* IKEv2 Transform Type 3 (Integrity Algorithm) */
+enum {
+	AUTH_HMAC_MD5_96 = 1,
+	AUTH_HMAC_SHA1_96 = 2,
+	AUTH_DES_MAC = 3,
+	AUTH_KPDK_MD5 = 4,
+	AUTH_AES_XCBC_96 = 5
+};
+
+/* IKEv2 Transform Type 4 (Diffie-Hellman Group) */
+enum {
+	DH_GROUP1_768BIT_MODP = 1, /* RFC 4306 */
+	DH_GROUP2_1024BIT_MODP = 2, /* RFC 4306 */
+	DH_GROUP5_1536BIT_MODP = 5, /* RFC 3526 */
+	DH_GROUP5_2048BIT_MODP = 14, /* RFC 3526 */
+	DH_GROUP5_3072BIT_MODP = 15, /* RFC 3526 */
+	DH_GROUP5_4096BIT_MODP = 16, /* RFC 3526 */
+	DH_GROUP5_6144BIT_MODP = 17, /* RFC 3526 */
+	DH_GROUP5_8192BIT_MODP = 18 /* RFC 3526 */
+};
+
+
+/* Identification Data Types (RFC 4306, Sect. 3.5) */
+enum {
+	ID_IPV4_ADDR = 1,
+	ID_FQDN = 2,
+	ID_RFC822_ADDR = 3,
+	ID_IPV6_ADDR = 5,
+	ID_DER_ASN1_DN = 9,
+	ID_DER_ASN1_GN= 10,
+	ID_KEY_ID = 11
+};
+
+
+/* Certificate Encoding (RFC 4306, Sect. 3.6) */
+enum {
+	CERT_ENCODING_PKCS7_X509 = 1,
+	CERT_ENCODING_PGP_CERT = 2,
+	CERT_ENCODING_DNS_SIGNED_KEY = 3,
+	/* X.509 Certificate - Signature: DER encoded X.509 certificate whose
+	 * public key is used to validate the sender's AUTH payload */
+	CERT_ENCODING_X509_CERT_SIGN = 4,
+	CERT_ENCODING_KERBEROS_TOKEN = 6,
+	/* DER encoded X.509 certificate revocation list */
+	CERT_ENCODING_CRL = 7,
+	CERT_ENCODING_ARL = 8,
+	CERT_ENCODING_SPKI_CERT = 9,
+	CERT_ENCODING_X509_CERT_ATTR = 10,
+	/* PKCS #1 encoded RSA key */
+	CERT_ENCODING_RAW_RSA_KEY = 11,
+	CERT_ENCODING_HASH_AND_URL_X509_CERT = 12,
+	CERT_ENCODING_HASH_AND_URL_X509_BUNDLE = 13
+};
+
+
+/* Authentication Method (RFC 4306, Sect. 3.8) */
+enum {
+	AUTH_RSA_SIGN = 1,
+	AUTH_SHARED_KEY_MIC = 2,
+	AUTH_DSS_SIGN = 3
+};
+
+
+/* Notify Message Types (RFC 4306, Sect. 3.10.1) */
+enum {
+	UNSUPPORTED_CRITICAL_PAYLOAD = 1,
+	INVALID_IKE_SPI = 4,
+	INVALID_MAJOR_VERSION = 5,
+	INVALID_SYNTAX = 7,
+	INVALID_MESSAGE_ID = 9,
+	INVALID_SPI = 11,
+	NO_PROPOSAL_CHOSEN = 14,
+	INVALID_KE_PAYLOAD = 17,
+	AUTHENTICATION_FAILED = 24,
+	SINGLE_PAIR_REQUIRED = 34,
+	NO_ADDITIONAL_SAS = 35,
+	INTERNAL_ADDRESS_FAILURE = 36,
+	FAILED_CP_REQUIRED = 37,
+	TS_UNACCEPTABLE = 38,
+	INVALID_SELECTORS = 39
+};
+
+
+struct ikev2_keys {
+	u8 *SK_d, *SK_ai, *SK_ar, *SK_ei, *SK_er, *SK_pi, *SK_pr;
+	size_t SK_d_len, SK_integ_len, SK_encr_len, SK_prf_len;
+};
+
+
+int ikev2_keys_set(struct ikev2_keys *keys);
+void ikev2_free_keys(struct ikev2_keys *keys);
+
+
+/* Maximum hash length for supported hash algorithms */
+#define IKEV2_MAX_HASH_LEN 20
+
+struct ikev2_integ_alg {
+	int id;
+	size_t key_len;
+	size_t hash_len;
+};
+
+struct ikev2_prf_alg {
+	int id;
+	size_t key_len;
+	size_t hash_len;
+};
+
+struct ikev2_encr_alg {
+	int id;
+	size_t key_len;
+	size_t block_size;
+};
+
+const struct ikev2_integ_alg * ikev2_get_integ(int id);
+int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
+		     size_t data_len, u8 *hash);
+const struct ikev2_prf_alg * ikev2_get_prf(int id);
+int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
+		   size_t num_elem, const u8 *addr[], const size_t *len,
+		   u8 *hash);
+int ikev2_prf_plus(int alg, const u8 *key, size_t key_len,
+		   const u8 *data, size_t data_len,
+		   u8 *out, size_t out_len);
+const struct ikev2_encr_alg * ikev2_get_encr(int id);
+int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
+		       const u8 *plain, u8 *crypt, size_t len);
+int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
+		       const u8 *crypt, u8 *plain, size_t len);
+
+int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg,
+			   const u8 *ID, size_t ID_len, u8 ID_type,
+			   struct ikev2_keys *keys, int initiator,
+			   const u8 *shared_secret, size_t shared_secret_len,
+			   const u8 *nonce, size_t nonce_len,
+			   const u8 *key_pad, size_t key_pad_len,
+			   u8 *auth_data);
+
+
+struct ikev2_payloads {
+	const u8 *sa;
+	size_t sa_len;
+	const u8 *ke;
+	size_t ke_len;
+	const u8 *idi;
+	size_t idi_len;
+	const u8 *idr;
+	size_t idr_len;
+	const u8 *cert;
+	size_t cert_len;
+	const u8 *auth;
+	size_t auth_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *encrypted;
+	size_t encrypted_len;
+	u8 encr_next_payload;
+	const u8 *notification;
+	size_t notification_len;
+};
+
+int ikev2_parse_payloads(struct ikev2_payloads *payloads,
+			 u8 next_payload, const u8 *pos, const u8 *end);
+
+u8 * ikev2_decrypt_payload(int encr_id, int integ_id, struct ikev2_keys *keys,
+			   int initiator, const struct ikev2_hdr *hdr,
+			   const u8 *encrypted, size_t encrypted_len,
+			   size_t *res_len);
+void ikev2_update_hdr(struct wpabuf *msg);
+int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys,
+			  int initiator, struct wpabuf *msg,
+			  struct wpabuf *plain, u8 next_payload);
+int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
+			 const struct ikev2_integ_alg *integ,
+			 const struct ikev2_encr_alg *encr,
+			 const u8 *skeyseed, const u8 *data, size_t data_len,
+			 struct ikev2_keys *keys);
+
+#endif /* IKEV2_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2140 +0,0 @@
-/*
- * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements the Peer State Machine as defined in RFC 4137. The used
- * states and state transitions match mostly with the RFC. However, there are
- * couple of additional transitions for working around small issues noticed
- * during testing. These exceptions are explained in comments within the
- * functions in this file. The method functions, m.func(), are similar to the
- * ones used in RFC 4137, but some small changes have used here to optimize
- * operations and to add functionality needed for fast re-authentication
- * (session resumption).
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "pcsc_funcs.h"
-#include "state_machine.h"
-#include "crypto/crypto.h"
-#include "crypto/tls.h"
-#include "common/wpa_ctrl.h"
-#include "eap_common/eap_wsc_common.h"
-#include "eap_i.h"
-#include "eap_config.h"
-
-#define STATE_MACHINE_DATA struct eap_sm
-#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-
-#define EAP_MAX_AUTH_ROUNDS 50
-
-
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
-				  EapType method);
-static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
-static void eap_sm_processIdentity(struct eap_sm *sm,
-				   const struct wpabuf *req);
-static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
-static struct wpabuf * eap_sm_buildNotify(int id);
-static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-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 Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
-{
-	return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
-}
-
-
-static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
-			   Boolean value)
-{
-	sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
-}
-
-
-static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
-{
-	return sm->eapol_cb->get_int(sm->eapol_ctx, var);
-}
-
-
-static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
-			  unsigned int value)
-{
-	sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
-}
-
-
-static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
-{
-	return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
-}
-
-
-static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
-{
-	if (sm->m == NULL || sm->eap_method_priv == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
-		   "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
-	sm->m->deinit(sm, sm->eap_method_priv);
-	sm->eap_method_priv = NULL;
-	sm->m = NULL;
-}
-
-
-/**
- * eap_allowed_method - Check whether EAP method is allowed
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
- * @method: EAP type
- * Returns: 1 = allowed EAP method, 0 = not allowed
- */
-int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	int i;
-	struct eap_method_type *m;
-
-	if (config == NULL || config->eap_methods == NULL)
-		return 1;
-
-	m = config->eap_methods;
-	for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
-		     m[i].method != EAP_TYPE_NONE; i++) {
-		if (m[i].vendor == vendor && m[i].method == method)
-			return 1;
-	}
-	return 0;
-}
-
-
-/*
- * This state initializes state machine variables when the machine is
- * activated (portEnabled = TRUE). This is also used when re-starting
- * authentication (eapRestart == TRUE).
- */
-SM_STATE(EAP, INITIALIZE)
-{
-	SM_ENTRY(EAP, INITIALIZE);
-	if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
-	    sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
-	    !sm->prev_failure) {
-		wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
-			   "fast reauthentication");
-		sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
-	} else {
-		eap_deinit_prev_method(sm, "INITIALIZE");
-	}
-	sm->selectedMethod = EAP_TYPE_NONE;
-	sm->methodState = METHOD_NONE;
-	sm->allowNotifications = TRUE;
-	sm->decision = DECISION_FAIL;
-	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
-	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
-	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
-	os_free(sm->eapKeyData);
-	sm->eapKeyData = NULL;
-	sm->eapKeyAvailable = FALSE;
-	eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
-	sm->lastId = -1; /* new session - make sure this does not match with
-			  * the first EAP-Packet */
-	/*
-	 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
-	 * seemed to be able to trigger cases where both were set and if EAPOL
-	 * state machine uses eapNoResp first, it may end up not sending a real
-	 * reply correctly. This occurred when the workaround in FAIL state set
-	 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
-	 * something else(?)
-	 */
-	eapol_set_bool(sm, EAPOL_eapResp, FALSE);
-	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
-	sm->num_rounds = 0;
-	sm->prev_failure = 0;
-}
-
-
-/*
- * This state is reached whenever service from the lower layer is interrupted
- * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
- * occurs when the port becomes enabled.
- */
-SM_STATE(EAP, DISABLED)
-{
-	SM_ENTRY(EAP, DISABLED);
-	sm->num_rounds = 0;
-}
-
-
-/*
- * The state machine spends most of its time here, waiting for something to
- * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
- * SEND_RESPONSE states.
- */
-SM_STATE(EAP, IDLE)
-{
-	SM_ENTRY(EAP, IDLE);
-}
-
-
-/*
- * This state is entered when an EAP packet is received (eapReq == TRUE) to
- * parse the packet header.
- */
-SM_STATE(EAP, RECEIVED)
-{
-	const struct wpabuf *eapReqData;
-
-	SM_ENTRY(EAP, RECEIVED);
-	eapReqData = eapol_get_eapReqData(sm);
-	/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
-	eap_sm_parseEapReq(sm, eapReqData);
-	sm->num_rounds++;
-}
-
-
-/*
- * This state is entered when a request for a new type comes in. Either the
- * correct method is started, or a Nak response is built.
- */
-SM_STATE(EAP, GET_METHOD)
-{
-	int reinit;
-	EapType method;
-
-	SM_ENTRY(EAP, GET_METHOD);
-
-	if (sm->reqMethod == EAP_TYPE_EXPANDED)
-		method = sm->reqVendorMethod;
-	else
-		method = sm->reqMethod;
-
-	if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
-		wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
-			   sm->reqVendor, method);
-		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
-			"vendor=%u method=%u -> NAK",
-			sm->reqVendor, method);
-		goto nak;
-	}
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
-		"vendor=%u method=%u", sm->reqVendor, method);
-
-	/*
-	 * RFC 4137 does not define specific operation for fast
-	 * re-authentication (session resumption). The design here is to allow
-	 * the previously used method data to be maintained for
-	 * re-authentication if the method support session resumption.
-	 * Otherwise, the previously used method data is freed and a new method
-	 * is allocated here.
-	 */
-	if (sm->fast_reauth &&
-	    sm->m && sm->m->vendor == sm->reqVendor &&
-	    sm->m->method == method &&
-	    sm->m->has_reauth_data &&
-	    sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
-		wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
-			   " for fast re-authentication");
-		reinit = 1;
-	} else {
-		eap_deinit_prev_method(sm, "GET_METHOD");
-		reinit = 0;
-	}
-
-	sm->selectedMethod = sm->reqMethod;
-	if (sm->m == NULL)
-		sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
-	if (!sm->m) {
-		wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
-			   "vendor %d method %d",
-			   sm->reqVendor, method);
-		goto nak;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
-		   "vendor %u method %u (%s)",
-		   sm->reqVendor, method, sm->m->name);
-	if (reinit)
-		sm->eap_method_priv = sm->m->init_for_reauth(
-			sm, sm->eap_method_priv);
-	else
-		sm->eap_method_priv = sm->m->init(sm);
-
-	if (sm->eap_method_priv == NULL) {
-		struct eap_peer_config *config = eap_get_config(sm);
-		wpa_msg(sm->msg_ctx, MSG_INFO,
-			"EAP: Failed to initialize EAP method: vendor %u "
-			"method %u (%s)",
-			sm->reqVendor, method, sm->m->name);
-		sm->m = NULL;
-		sm->methodState = METHOD_NONE;
-		sm->selectedMethod = EAP_TYPE_NONE;
-		if (sm->reqMethod == EAP_TYPE_TLS && config &&
-		    (config->pending_req_pin ||
-		     config->pending_req_passphrase)) {
-			/*
-			 * Return without generating Nak in order to allow
-			 * entering of PIN code or passphrase to retry the
-			 * current EAP packet.
-			 */
-			wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
-				   "request - skip Nak");
-			return;
-		}
-
-		goto nak;
-	}
-
-	sm->methodState = METHOD_INIT;
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
-		"EAP vendor %u method %u (%s) selected",
-		sm->reqVendor, method, sm->m->name);
-	return;
-
-nak:
-	wpabuf_free(sm->eapRespData);
-	sm->eapRespData = NULL;
-	sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
-}
-
-
-/*
- * The method processing happens here. The request from the authenticator is
- * processed, and an appropriate response packet is built.
- */
-SM_STATE(EAP, METHOD)
-{
-	struct wpabuf *eapReqData;
-	struct eap_method_ret ret;
-
-	SM_ENTRY(EAP, METHOD);
-	if (sm->m == NULL) {
-		wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
-		return;
-	}
-
-	eapReqData = eapol_get_eapReqData(sm);
-
-	/*
-	 * Get ignore, methodState, decision, allowNotifications, and
-	 * eapRespData. RFC 4137 uses three separate method procedure (check,
-	 * process, and buildResp) in this state. These have been combined into
-	 * a single function call to m->process() in order to optimize EAP
-	 * method implementation interface a bit. These procedures are only
-	 * used from within this METHOD state, so there is no need to keep
-	 * these as separate C functions.
-	 *
-	 * The RFC 4137 procedures return values as follows:
-	 * ignore = m.check(eapReqData)
-	 * (methodState, decision, allowNotifications) = m.process(eapReqData)
-	 * eapRespData = m.buildResp(reqId)
-	 */
-	os_memset(&ret, 0, sizeof(ret));
-	ret.ignore = sm->ignore;
-	ret.methodState = sm->methodState;
-	ret.decision = sm->decision;
-	ret.allowNotifications = sm->allowNotifications;
-	wpabuf_free(sm->eapRespData);
-	sm->eapRespData = NULL;
-	sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
-					 eapReqData);
-	wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
-		   "methodState=%s decision=%s",
-		   ret.ignore ? "TRUE" : "FALSE",
-		   eap_sm_method_state_txt(ret.methodState),
-		   eap_sm_decision_txt(ret.decision));
-
-	sm->ignore = ret.ignore;
-	if (sm->ignore)
-		return;
-	sm->methodState = ret.methodState;
-	sm->decision = ret.decision;
-	sm->allowNotifications = ret.allowNotifications;
-
-	if (sm->m->isKeyAvailable && sm->m->getKey &&
-	    sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
-		os_free(sm->eapKeyData);
-		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
-					       &sm->eapKeyDataLen);
-	}
-}
-
-
-/*
- * This state signals the lower layer that a response packet is ready to be
- * sent.
- */
-SM_STATE(EAP, SEND_RESPONSE)
-{
-	SM_ENTRY(EAP, SEND_RESPONSE);
-	wpabuf_free(sm->lastRespData);
-	if (sm->eapRespData) {
-		if (sm->workaround)
-			os_memcpy(sm->last_md5, sm->req_md5, 16);
-		sm->lastId = sm->reqId;
-		sm->lastRespData = wpabuf_dup(sm->eapRespData);
-		eapol_set_bool(sm, EAPOL_eapResp, TRUE);
-	} else
-		sm->lastRespData = NULL;
-	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
-	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
-}
-
-
-/*
- * This state signals the lower layer that the request was discarded, and no
- * response packet will be sent at this time.
- */
-SM_STATE(EAP, DISCARD)
-{
-	SM_ENTRY(EAP, DISCARD);
-	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
-	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
-}
-
-
-/*
- * Handles requests for Identity method and builds a response.
- */
-SM_STATE(EAP, IDENTITY)
-{
-	const struct wpabuf *eapReqData;
-
-	SM_ENTRY(EAP, IDENTITY);
-	eapReqData = eapol_get_eapReqData(sm);
-	eap_sm_processIdentity(sm, eapReqData);
-	wpabuf_free(sm->eapRespData);
-	sm->eapRespData = NULL;
-	sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
-}
-
-
-/*
- * Handles requests for Notification method and builds a response.
- */
-SM_STATE(EAP, NOTIFICATION)
-{
-	const struct wpabuf *eapReqData;
-
-	SM_ENTRY(EAP, NOTIFICATION);
-	eapReqData = eapol_get_eapReqData(sm);
-	eap_sm_processNotify(sm, eapReqData);
-	wpabuf_free(sm->eapRespData);
-	sm->eapRespData = NULL;
-	sm->eapRespData = eap_sm_buildNotify(sm->reqId);
-}
-
-
-/*
- * This state retransmits the previous response packet.
- */
-SM_STATE(EAP, RETRANSMIT)
-{
-	SM_ENTRY(EAP, RETRANSMIT);
-	wpabuf_free(sm->eapRespData);
-	if (sm->lastRespData)
-		sm->eapRespData = wpabuf_dup(sm->lastRespData);
-	else
-		sm->eapRespData = NULL;
-}
-
-
-/*
- * This state is entered in case of a successful completion of authentication
- * and state machine waits here until port is disabled or EAP authentication is
- * restarted.
- */
-SM_STATE(EAP, SUCCESS)
-{
-	SM_ENTRY(EAP, SUCCESS);
-	if (sm->eapKeyData != NULL)
-		sm->eapKeyAvailable = TRUE;
-	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
-
-	/*
-	 * RFC 4137 does not clear eapReq here, but this seems to be required
-	 * to avoid processing the same request twice when state machine is
-	 * initialized.
-	 */
-	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
-
-	/*
-	 * RFC 4137 does not set eapNoResp here, but this seems to be required
-	 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
-	 * addition, either eapResp or eapNoResp is required to be set after
-	 * processing the received EAP frame.
-	 */
-	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
-		"EAP authentication completed successfully");
-}
-
-
-/*
- * This state is entered in case of a failure and state machine waits here
- * until port is disabled or EAP authentication is restarted.
- */
-SM_STATE(EAP, FAILURE)
-{
-	SM_ENTRY(EAP, FAILURE);
-	eapol_set_bool(sm, EAPOL_eapFail, TRUE);
-
-	/*
-	 * RFC 4137 does not clear eapReq here, but this seems to be required
-	 * to avoid processing the same request twice when state machine is
-	 * initialized.
-	 */
-	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
-
-	/*
-	 * RFC 4137 does not set eapNoResp here. However, either eapResp or
-	 * eapNoResp is required to be set after processing the received EAP
-	 * frame.
-	 */
-	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
-		"EAP authentication failed");
-
-	sm->prev_failure = 1;
-}
-
-
-static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
-{
-	/*
-	 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
-	 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
-	 * RFC 4137 require that reqId == lastId. In addition, it looks like
-	 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
-	 *
-	 * Accept this kind of Id if EAP workarounds are enabled. These are
-	 * unauthenticated plaintext messages, so this should have minimal
-	 * security implications (bit easier to fake EAP-Success/Failure).
-	 */
-	if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
-			       reqId == ((lastId + 2) & 0xff))) {
-		wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
-			   "identifier field in EAP Success: "
-			   "reqId=%d lastId=%d (these are supposed to be "
-			   "same)", reqId, lastId);
-		return 1;
-	}
-	wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
-		   "lastId=%d", reqId, lastId);
-	return 0;
-}
-
-
-/*
- * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
- */
-
-static void eap_peer_sm_step_idle(struct eap_sm *sm)
-{
-	/*
-	 * The first three transitions are from RFC 4137. The last two are
-	 * local additions to handle special cases with LEAP and PEAP server
-	 * not sending EAP-Success in some cases.
-	 */
-	if (eapol_get_bool(sm, EAPOL_eapReq))
-		SM_ENTER(EAP, RECEIVED);
-	else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
-		  sm->decision != DECISION_FAIL) ||
-		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
-		  sm->decision == DECISION_UNCOND_SUCC))
-		SM_ENTER(EAP, SUCCESS);
-	else if (eapol_get_bool(sm, EAPOL_altReject) ||
-		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
-		  sm->decision != DECISION_UNCOND_SUCC) ||
-		 (eapol_get_bool(sm, EAPOL_altAccept) &&
-		  sm->methodState != METHOD_CONT &&
-		  sm->decision == DECISION_FAIL))
-		SM_ENTER(EAP, FAILURE);
-	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
-		 sm->leap_done && sm->decision != DECISION_FAIL &&
-		 sm->methodState == METHOD_DONE)
-		SM_ENTER(EAP, SUCCESS);
-	else if (sm->selectedMethod == EAP_TYPE_PEAP &&
-		 sm->peap_done && sm->decision != DECISION_FAIL &&
-		 sm->methodState == METHOD_DONE)
-		SM_ENTER(EAP, SUCCESS);
-}
-
-
-static int eap_peer_req_is_duplicate(struct eap_sm *sm)
-{
-	int duplicate;
-
-	duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
-	if (sm->workaround && duplicate &&
-	    os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
-		/*
-		 * RFC 4137 uses (reqId == lastId) as the only verification for
-		 * duplicate EAP requests. However, this misses cases where the
-		 * AS is incorrectly using the same id again; and
-		 * unfortunately, such implementations exist. Use MD5 hash as
-		 * an extra verification for the packets being duplicate to
-		 * workaround these issues.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
-			   "EAP packets were not identical");
-		wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
-			   "duplicate packet");
-		duplicate = 0;
-	}
-
-	return duplicate;
-}
-
-
-static void eap_peer_sm_step_received(struct eap_sm *sm)
-{
-	int duplicate = eap_peer_req_is_duplicate(sm);
-
-	/*
-	 * Two special cases below for LEAP are local additions to work around
-	 * odd LEAP behavior (EAP-Success in the middle of authentication and
-	 * then swapped roles). Other transitions are based on RFC 4137.
-	 */
-	if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
-	    (sm->reqId == sm->lastId ||
-	     eap_success_workaround(sm, sm->reqId, sm->lastId)))
-		SM_ENTER(EAP, SUCCESS);
-	else if (sm->methodState != METHOD_CONT &&
-		 ((sm->rxFailure &&
-		   sm->decision != DECISION_UNCOND_SUCC) ||
-		  (sm->rxSuccess && sm->decision == DECISION_FAIL &&
-		   (sm->selectedMethod != EAP_TYPE_LEAP ||
-		    sm->methodState != METHOD_MAY_CONT))) &&
-		 (sm->reqId == sm->lastId ||
-		  eap_success_workaround(sm, sm->reqId, sm->lastId)))
-		SM_ENTER(EAP, FAILURE);
-	else if (sm->rxReq && duplicate)
-		SM_ENTER(EAP, RETRANSMIT);
-	else if (sm->rxReq && !duplicate &&
-		 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
-		 sm->allowNotifications)
-		SM_ENTER(EAP, NOTIFICATION);
-	else if (sm->rxReq && !duplicate &&
-		 sm->selectedMethod == EAP_TYPE_NONE &&
-		 sm->reqMethod == EAP_TYPE_IDENTITY)
-		SM_ENTER(EAP, IDENTITY);
-	else if (sm->rxReq && !duplicate &&
-		 sm->selectedMethod == EAP_TYPE_NONE &&
-		 sm->reqMethod != EAP_TYPE_IDENTITY &&
-		 sm->reqMethod != EAP_TYPE_NOTIFICATION)
-		SM_ENTER(EAP, GET_METHOD);
-	else if (sm->rxReq && !duplicate &&
-		 sm->reqMethod == sm->selectedMethod &&
-		 sm->methodState != METHOD_DONE)
-		SM_ENTER(EAP, METHOD);
-	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
-		 (sm->rxSuccess || sm->rxResp))
-		SM_ENTER(EAP, METHOD);
-	else
-		SM_ENTER(EAP, DISCARD);
-}
-
-
-static void eap_peer_sm_step_local(struct eap_sm *sm)
-{
-	switch (sm->EAP_state) {
-	case EAP_INITIALIZE:
-		SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_DISABLED:
-		if (eapol_get_bool(sm, EAPOL_portEnabled) &&
-		    !sm->force_disabled)
-			SM_ENTER(EAP, INITIALIZE);
-		break;
-	case EAP_IDLE:
-		eap_peer_sm_step_idle(sm);
-		break;
-	case EAP_RECEIVED:
-		eap_peer_sm_step_received(sm);
-		break;
-	case EAP_GET_METHOD:
-		if (sm->selectedMethod == sm->reqMethod)
-			SM_ENTER(EAP, METHOD);
-		else
-			SM_ENTER(EAP, SEND_RESPONSE);
-		break;
-	case EAP_METHOD:
-		if (sm->ignore)
-			SM_ENTER(EAP, DISCARD);
-		else
-			SM_ENTER(EAP, SEND_RESPONSE);
-		break;
-	case EAP_SEND_RESPONSE:
-		SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_DISCARD:
-		SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_IDENTITY:
-		SM_ENTER(EAP, SEND_RESPONSE);
-		break;
-	case EAP_NOTIFICATION:
-		SM_ENTER(EAP, SEND_RESPONSE);
-		break;
-	case EAP_RETRANSMIT:
-		SM_ENTER(EAP, SEND_RESPONSE);
-		break;
-	case EAP_SUCCESS:
-		break;
-	case EAP_FAILURE:
-		break;
-	}
-}
-
-
-SM_STEP(EAP)
-{
-	/* Global transitions */
-	if (eapol_get_bool(sm, EAPOL_eapRestart) &&
-	    eapol_get_bool(sm, EAPOL_portEnabled))
-		SM_ENTER_GLOBAL(EAP, INITIALIZE);
-	else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
-		SM_ENTER_GLOBAL(EAP, DISABLED);
-	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
-		/* RFC 4137 does not place any limit on number of EAP messages
-		 * in an authentication session. However, some error cases have
-		 * ended up in a state were EAP messages were sent between the
-		 * peer and server in a loop (e.g., TLS ACK frame in both
-		 * direction). Since this is quite undesired outcome, limit the
-		 * total number of EAP round-trips and abort authentication if
-		 * this limit is exceeded.
-		 */
-		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
-			wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
-				"authentication rounds - abort",
-				EAP_MAX_AUTH_ROUNDS);
-			sm->num_rounds++;
-			SM_ENTER_GLOBAL(EAP, FAILURE);
-		}
-	} else {
-		/* Local transitions */
-		eap_peer_sm_step_local(sm);
-	}
-}
-
-
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
-				  EapType method)
-{
-	if (!eap_allowed_method(sm, vendor, method)) {
-		wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
-			   "vendor %u method %u", vendor, method);
-		return FALSE;
-	}
-	if (eap_peer_get_eap_method(vendor, method))
-		return TRUE;
-	wpa_printf(MSG_DEBUG, "EAP: not included in build: "
-		   "vendor %u method %u", vendor, method);
-	return FALSE;
-}
-
-
-static struct wpabuf * eap_sm_build_expanded_nak(
-	struct eap_sm *sm, int id, const struct eap_method *methods,
-	size_t count)
-{
-	struct wpabuf *resp;
-	int found = 0;
-	const struct eap_method *m;
-
-	wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
-
-	/* RFC 3748 - 5.3.2: Expanded Nak */
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
-			     8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_be24(resp, EAP_VENDOR_IETF);
-	wpabuf_put_be32(resp, EAP_TYPE_NAK);
-
-	for (m = methods; m; m = m->next) {
-		if (sm->reqVendor == m->vendor &&
-		    sm->reqVendorMethod == m->method)
-			continue; /* do not allow the current method again */
-		if (eap_allowed_method(sm, m->vendor, m->method)) {
-			wpa_printf(MSG_DEBUG, "EAP: allowed type: "
-				   "vendor=%u method=%u",
-				   m->vendor, m->method);
-			wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
-			wpabuf_put_be24(resp, m->vendor);
-			wpabuf_put_be32(resp, m->method);
-
-			found++;
-		}
-	}
-	if (!found) {
-		wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
-		wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
-		wpabuf_put_be24(resp, EAP_VENDOR_IETF);
-		wpabuf_put_be32(resp, EAP_TYPE_NONE);
-	}
-
-	eap_update_len(resp);
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
-{
-	struct wpabuf *resp;
-	u8 *start;
-	int found = 0, expanded_found = 0;
-	size_t count;
-	const struct eap_method *methods, *m;
-
-	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
-		   "vendor=%u method=%u not allowed)", sm->reqMethod,
-		   sm->reqVendor, sm->reqVendorMethod);
-	methods = eap_peer_get_methods(&count);
-	if (methods == NULL)
-		return NULL;
-	if (sm->reqMethod == EAP_TYPE_EXPANDED)
-		return eap_sm_build_expanded_nak(sm, id, methods, count);
-
-	/* RFC 3748 - 5.3.1: Legacy Nak */
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
-			     sizeof(struct eap_hdr) + 1 + count + 1,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	start = wpabuf_put(resp, 0);
-	for (m = methods; m; m = m->next) {
-		if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
-			continue; /* do not allow the current method again */
-		if (eap_allowed_method(sm, m->vendor, m->method)) {
-			if (m->vendor != EAP_VENDOR_IETF) {
-				if (expanded_found)
-					continue;
-				expanded_found = 1;
-				wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
-			} else
-				wpabuf_put_u8(resp, m->method);
-			found++;
-		}
-	}
-	if (!found)
-		wpabuf_put_u8(resp, EAP_TYPE_NONE);
-	wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
-
-	eap_update_len(resp);
-
-	return resp;
-}
-
-
-static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
-{
-	const struct eap_hdr *hdr = wpabuf_head(req);
-	const u8 *pos = (const u8 *) (hdr + 1);
-	pos++;
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
-		"EAP authentication started");
-
-	/*
-	 * RFC 3748 - 5.1: Identity
-	 * Data field may contain a displayable message in UTF-8. If this
-	 * includes NUL-character, only the data before that should be
-	 * displayed. Some EAP implementasitons may piggy-back additional
-	 * options after the NUL.
-	 */
-	/* TODO: could save displayable message so that it can be shown to the
-	 * user in case of interaction is required */
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
-			  pos, be_to_host16(hdr->length) - 5);
-}
-
-
-#ifdef PCSC_FUNCS
-static int eap_sm_imsi_identity(struct eap_sm *sm,
-				struct eap_peer_config *conf)
-{
-	int aka = 0;
-	char imsi[100];
-	size_t imsi_len;
-	struct eap_method_type *m = conf->eap_methods;
-	int i;
-
-	imsi_len = sizeof(imsi);
-	if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
-		wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
-
-	for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
-			  m[i].method != EAP_TYPE_NONE); i++) {
-		if (m[i].vendor == EAP_VENDOR_IETF &&
-		    m[i].method == EAP_TYPE_AKA) {
-			aka = 1;
-			break;
-		}
-	}
-
-	os_free(conf->identity);
-	conf->identity = os_malloc(1 + imsi_len);
-	if (conf->identity == NULL) {
-		wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
-			   "IMSI-based identity");
-		return -1;
-	}
-
-	conf->identity[0] = aka ? '0' : '1';
-	os_memcpy(conf->identity + 1, imsi, imsi_len);
-	conf->identity_len = 1 + imsi_len;
-
-	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
-		 * blocking SIM.
-		 */
-		os_free(conf->pin);
-		conf->pin = NULL;
-
-		wpa_printf(MSG_WARNING, "PIN validation failed");
-		eap_sm_request_pin(sm);
-		return -1;
-	}
-	return 0;
-#else /* PCSC_FUNCS */
-	return -1;
-#endif /* PCSC_FUNCS */
-}
-
-static int eap_sm_get_scard_identity(struct eap_sm *sm,
-				     struct eap_peer_config *conf)
-{
-#ifdef PCSC_FUNCS
-	if (eap_sm_set_scard_pin(sm, conf))
-		return -1;
-
-	return eap_sm_imsi_identity(sm, conf);
-#else /* PCSC_FUNCS */
-	return -1;
-#endif /* PCSC_FUNCS */
-}
-
-
-/**
- * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @id: EAP identifier for the packet
- * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
- * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
- * failure
- *
- * This function allocates and builds an EAP-Identity/Response packet for the
- * current network. The caller is responsible for freeing the returned data.
- */
-struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	struct wpabuf *resp;
-	const u8 *identity;
-	size_t identity_len;
-
-	if (config == NULL) {
-		wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
-			   "was not available");
-		return NULL;
-	}
-
-	if (sm->m && sm->m->get_identity &&
-	    (identity = sm->m->get_identity(sm, sm->eap_method_priv,
-					    &identity_len)) != NULL) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
-				  "identity", identity, identity_len);
-	} else if (!encrypted && config->anonymous_identity) {
-		identity = config->anonymous_identity;
-		identity_len = config->anonymous_identity_len;
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
-				  identity, identity_len);
-	} else {
-		identity = config->identity;
-		identity_len = config->identity_len;
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
-				  identity, identity_len);
-	}
-
-	if (identity == NULL) {
-		wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
-			   "configuration was not available");
-		if (config->pcsc) {
-			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);
-			return NULL;
-		}
-	} else if (config->pcsc) {
-		if (eap_sm_set_scard_pin(sm, config) < 0)
-			return NULL;
-	}
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_data(resp, identity, identity_len);
-
-	return resp;
-}
-
-
-static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
-{
-	const u8 *pos;
-	char *msg;
-	size_t i, msg_len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
-			       &msg_len);
-	if (pos == NULL)
-		return;
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
-			  pos, msg_len);
-
-	msg = os_malloc(msg_len + 1);
-	if (msg == NULL)
-		return;
-	for (i = 0; i < msg_len; i++)
-		msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
-	msg[msg_len] = '\0';
-	wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
-		WPA_EVENT_EAP_NOTIFICATION, msg);
-	os_free(msg);
-}
-
-
-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;
-}
-
-
-static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
-{
-	const struct eap_hdr *hdr;
-	size_t plen;
-	const u8 *pos;
-
-	sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
-	sm->reqId = 0;
-	sm->reqMethod = EAP_TYPE_NONE;
-	sm->reqVendor = EAP_VENDOR_IETF;
-	sm->reqVendorMethod = EAP_TYPE_NONE;
-
-	if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
-		return;
-
-	hdr = wpabuf_head(req);
-	plen = be_to_host16(hdr->length);
-	if (plen > wpabuf_len(req)) {
-		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
-			   "(len=%lu plen=%lu)",
-			   (unsigned long) wpabuf_len(req),
-			   (unsigned long) plen);
-		return;
-	}
-
-	sm->reqId = hdr->identifier;
-
-	if (sm->workaround) {
-		const u8 *addr[1];
-		addr[0] = wpabuf_head(req);
-		md5_vector(1, addr, &plen, sm->req_md5);
-	}
-
-	switch (hdr->code) {
-	case EAP_CODE_REQUEST:
-		if (plen < sizeof(*hdr) + 1) {
-			wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
-				   "no Type field");
-			return;
-		}
-		sm->rxReq = TRUE;
-		pos = (const u8 *) (hdr + 1);
-		sm->reqMethod = *pos++;
-		if (sm->reqMethod == EAP_TYPE_EXPANDED) {
-			if (plen < sizeof(*hdr) + 8) {
-				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
-					   "expanded EAP-Packet (plen=%lu)",
-					   (unsigned long) plen);
-				return;
-			}
-			sm->reqVendor = WPA_GET_BE24(pos);
-			pos += 3;
-			sm->reqVendorMethod = WPA_GET_BE32(pos);
-		}
-		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
-			   "method=%u vendor=%u vendorMethod=%u",
-			   sm->reqId, sm->reqMethod, sm->reqVendor,
-			   sm->reqVendorMethod);
-		break;
-	case EAP_CODE_RESPONSE:
-		if (sm->selectedMethod == EAP_TYPE_LEAP) {
-			/*
-			 * LEAP differs from RFC 4137 by using reversed roles
-			 * for mutual authentication and because of this, we
-			 * need to accept EAP-Response frames if LEAP is used.
-			 */
-			if (plen < sizeof(*hdr) + 1) {
-				wpa_printf(MSG_DEBUG, "EAP: Too short "
-					   "EAP-Response - no Type field");
-				return;
-			}
-			sm->rxResp = TRUE;
-			pos = (const u8 *) (hdr + 1);
-			sm->reqMethod = *pos;
-			wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
-				   "LEAP method=%d id=%d",
-				   sm->reqMethod, sm->reqId);
-			break;
-		}
-		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
-		break;
-	case EAP_CODE_SUCCESS:
-		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
-		sm->rxSuccess = TRUE;
-		break;
-	case EAP_CODE_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
-		sm->rxFailure = TRUE;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
-			   "code %d", hdr->code);
-		break;
-	}
-}
-
-
-static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
-				  union tls_event_data *data)
-{
-	struct eap_sm *sm = ctx;
-	char *hash_hex = NULL;
-	char *cert_hex = NULL;
-
-	switch (ev) {
-	case TLS_CERT_CHAIN_FAILURE:
-		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
-			"reason=%d depth=%d subject='%s' err='%s'",
-			data->cert_fail.reason,
-			data->cert_fail.depth,
-			data->cert_fail.subject,
-			data->cert_fail.reason_txt);
-		break;
-	case TLS_PEER_CERTIFICATE:
-		if (data->peer_cert.hash) {
-			size_t len = data->peer_cert.hash_len * 2 + 1;
-			hash_hex = os_malloc(len);
-			if (hash_hex) {
-				wpa_snprintf_hex(hash_hex, len,
-						 data->peer_cert.hash,
-						 data->peer_cert.hash_len);
-			}
-		}
-		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
-			"depth=%d subject='%s'%s%s",
-			data->peer_cert.depth, data->peer_cert.subject,
-			hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
-
-		if (data->peer_cert.cert) {
-			size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
-			cert_hex = os_malloc(len);
-			if (cert_hex == NULL)
-				break;
-			wpa_snprintf_hex(cert_hex, len,
-					 wpabuf_head(data->peer_cert.cert),
-					 wpabuf_len(data->peer_cert.cert));
-			wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
-				     WPA_EVENT_EAP_PEER_CERT
-				     "depth=%d subject='%s' cert=%s",
-				     data->peer_cert.depth,
-				     data->peer_cert.subject,
-				     cert_hex);
-		}
-		break;
-	}
-
-	os_free(hash_hex);
-	os_free(cert_hex);
-}
-
-
-/**
- * eap_peer_sm_init - Allocate and initialize EAP peer state machine
- * @eapol_ctx: Context data to be used with eapol_cb calls
- * @eapol_cb: Pointer to EAPOL callback functions
- * @msg_ctx: Context data for wpa_msg() calls
- * @conf: EAP configuration
- * Returns: Pointer to the allocated EAP state machine or %NULL on failure
- *
- * This function allocates and initializes an EAP state machine. In addition,
- * this initializes TLS library for the new EAP state machine. eapol_cb pointer
- * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
- * state machine. Consequently, the caller must make sure that this data
- * structure remains alive while the EAP state machine is active.
- */
-struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
-				 struct eapol_callbacks *eapol_cb,
-				 void *msg_ctx, struct eap_config *conf)
-{
-	struct eap_sm *sm;
-	struct tls_config tlsconf;
-
-	sm = os_zalloc(sizeof(*sm));
-	if (sm == NULL)
-		return NULL;
-	sm->eapol_ctx = eapol_ctx;
-	sm->eapol_cb = eapol_cb;
-	sm->msg_ctx = msg_ctx;
-	sm->ClientTimeout = 60;
-	sm->wps = conf->wps;
-
-	os_memset(&tlsconf, 0, sizeof(tlsconf));
-	tlsconf.opensc_engine_path = conf->opensc_engine_path;
-	tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
-	tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
-#ifdef CONFIG_FIPS
-	tlsconf.fips_mode = 1;
-#endif /* CONFIG_FIPS */
-	tlsconf.event_cb = eap_peer_sm_tls_event;
-	tlsconf.cb_ctx = sm;
-	sm->ssl_ctx = tls_init(&tlsconf);
-	if (sm->ssl_ctx == NULL) {
-		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
-			   "context.");
-		os_free(sm);
-		return NULL;
-	}
-
-	return sm;
-}
-
-
-/**
- * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * This function deinitializes EAP state machine and frees all allocated
- * resources.
- */
-void eap_peer_sm_deinit(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	eap_deinit_prev_method(sm, "EAP deinit");
-	eap_sm_abort(sm);
-	tls_deinit(sm->ssl_ctx);
-	os_free(sm);
-}
-
-
-/**
- * eap_peer_sm_step - Step EAP peer state machine
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: 1 if EAP state was changed or 0 if not
- *
- * This function advances EAP state machine to a new state to match with the
- * current variables. This should be called whenever variables used by the EAP
- * state machine have changed.
- */
-int eap_peer_sm_step(struct eap_sm *sm)
-{
-	int res = 0;
-	do {
-		sm->changed = FALSE;
-		SM_STEP_RUN(EAP);
-		if (sm->changed)
-			res = 1;
-	} while (sm->changed);
-	return res;
-}
-
-
-/**
- * eap_sm_abort - Abort EAP authentication
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * Release system resources that have been allocated for the authentication
- * session without fully deinitializing the EAP state machine.
- */
-void eap_sm_abort(struct eap_sm *sm)
-{
-	wpabuf_free(sm->lastRespData);
-	sm->lastRespData = NULL;
-	wpabuf_free(sm->eapRespData);
-	sm->eapRespData = NULL;
-	os_free(sm->eapKeyData);
-	sm->eapKeyData = NULL;
-
-	/* This is not clearly specified in the EAP statemachines draft, but
-	 * it seems necessary to make sure that some of the EAPOL variables get
-	 * cleared for the next authentication. */
-	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
-}
-
-
-#ifdef CONFIG_CTRL_IFACE
-static const char * eap_sm_state_txt(int state)
-{
-	switch (state) {
-	case EAP_INITIALIZE:
-		return "INITIALIZE";
-	case EAP_DISABLED:
-		return "DISABLED";
-	case EAP_IDLE:
-		return "IDLE";
-	case EAP_RECEIVED:
-		return "RECEIVED";
-	case EAP_GET_METHOD:
-		return "GET_METHOD";
-	case EAP_METHOD:
-		return "METHOD";
-	case EAP_SEND_RESPONSE:
-		return "SEND_RESPONSE";
-	case EAP_DISCARD:
-		return "DISCARD";
-	case EAP_IDENTITY:
-		return "IDENTITY";
-	case EAP_NOTIFICATION:
-		return "NOTIFICATION";
-	case EAP_RETRANSMIT:
-		return "RETRANSMIT";
-	case EAP_SUCCESS:
-		return "SUCCESS";
-	case EAP_FAILURE:
-		return "FAILURE";
-	default:
-		return "UNKNOWN";
-	}
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static const char * eap_sm_method_state_txt(EapMethodState state)
-{
-	switch (state) {
-	case METHOD_NONE:
-		return "NONE";
-	case METHOD_INIT:
-		return "INIT";
-	case METHOD_CONT:
-		return "CONT";
-	case METHOD_MAY_CONT:
-		return "MAY_CONT";
-	case METHOD_DONE:
-		return "DONE";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-static const char * eap_sm_decision_txt(EapDecision decision)
-{
-	switch (decision) {
-	case DECISION_FAIL:
-		return "FAIL";
-	case DECISION_COND_SUCC:
-		return "COND_SUCC";
-	case DECISION_UNCOND_SUCC:
-		return "UNCOND_SUCC";
-	default:
-		return "UNKNOWN";
-	}
-}
-#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-
-
-#ifdef CONFIG_CTRL_IFACE
-
-/**
- * eap_sm_get_status - Get EAP state machine status
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_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 state machine for status information. This function fills in a
- * text area with current status information from the EAPOL state machine. If
- * the buffer (buf) is not large enough, status information will be truncated
- * to fit the buffer.
- */
-int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
-{
-	int len, ret;
-
-	if (sm == NULL)
-		return 0;
-
-	len = os_snprintf(buf, buflen,
-			  "EAP state=%s\n",
-			  eap_sm_state_txt(sm->EAP_state));
-	if (len < 0 || (size_t) len >= buflen)
-		return 0;
-
-	if (sm->selectedMethod != EAP_TYPE_NONE) {
-		const char *name;
-		if (sm->m) {
-			name = sm->m->name;
-		} else {
-			const struct eap_method *m =
-				eap_peer_get_eap_method(EAP_VENDOR_IETF,
-							sm->selectedMethod);
-			if (m)
-				name = m->name;
-			else
-				name = "?";
-		}
-		ret = os_snprintf(buf + len, buflen - len,
-				  "selectedMethod=%d (EAP-%s)\n",
-				  sm->selectedMethod, name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			return len;
-		len += ret;
-
-		if (sm->m && sm->m->get_status) {
-			len += sm->m->get_status(sm, sm->eap_method_priv,
-						 buf + len, buflen - len,
-						 verbose);
-		}
-	}
-
-	if (verbose) {
-		ret = os_snprintf(buf + len, buflen - len,
-				  "reqMethod=%d\n"
-				  "methodState=%s\n"
-				  "decision=%s\n"
-				  "ClientTimeout=%d\n",
-				  sm->reqMethod,
-				  eap_sm_method_state_txt(sm->methodState),
-				  eap_sm_decision_txt(sm->decision),
-				  sm->ClientTimeout);
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			return len;
-		len += ret;
-	}
-
-	return len;
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-typedef enum {
-	TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
-	TYPE_PASSPHRASE
-} eap_ctrl_req_type;
-
-static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
-			   const char *msg, size_t msglen)
-{
-	struct eap_peer_config *config;
-	char *field, *txt, *tmp;
-
-	if (sm == NULL)
-		return;
-	config = eap_get_config(sm);
-	if (config == NULL)
-		return;
-
-	switch (type) {
-	case TYPE_IDENTITY:
-		field = "IDENTITY";
-		txt = "Identity";
-		config->pending_req_identity++;
-		break;
-	case TYPE_PASSWORD:
-		field = "PASSWORD";
-		txt = "Password";
-		config->pending_req_password++;
-		break;
-	case TYPE_NEW_PASSWORD:
-		field = "NEW_PASSWORD";
-		txt = "New Password";
-		config->pending_req_new_password++;
-		break;
-	case TYPE_PIN:
-		field = "PIN";
-		txt = "PIN";
-		config->pending_req_pin++;
-		break;
-	case TYPE_OTP:
-		field = "OTP";
-		if (msg) {
-			tmp = os_malloc(msglen + 3);
-			if (tmp == NULL)
-				return;
-			tmp[0] = '[';
-			os_memcpy(tmp + 1, msg, msglen);
-			tmp[msglen + 1] = ']';
-			tmp[msglen + 2] = '\0';
-			txt = tmp;
-			os_free(config->pending_req_otp);
-			config->pending_req_otp = tmp;
-			config->pending_req_otp_len = msglen + 3;
-		} else {
-			if (config->pending_req_otp == NULL)
-				return;
-			txt = config->pending_req_otp;
-		}
-		break;
-	case TYPE_PASSPHRASE:
-		field = "PASSPHRASE";
-		txt = "Private key passphrase";
-		config->pending_req_passphrase++;
-		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 */
-
-
-/**
- * eap_sm_request_identity - Request identity from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * EAP methods can call this function to request identity information for the
- * current network. This is normally called when the identity is not included
- * in the network configuration. The request will be sent to monitor programs
- * through the control interface.
- */
-void eap_sm_request_identity(struct eap_sm *sm)
-{
-	eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
-}
-
-
-/**
- * eap_sm_request_password - Request password from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * EAP methods can call this function to request password information for the
- * current network. This is normally called when the password is not included
- * in the network configuration. The request will be sent to monitor programs
- * through the control interface.
- */
-void eap_sm_request_password(struct eap_sm *sm)
-{
-	eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
-}
-
-
-/**
- * eap_sm_request_new_password - Request new password from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * EAP methods can call this function to request new password information for
- * the current network. This is normally called when the EAP method indicates
- * that the current password has expired and password change is required. The
- * request will be sent to monitor programs through the control interface.
- */
-void eap_sm_request_new_password(struct eap_sm *sm)
-{
-	eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
-}
-
-
-/**
- * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * EAP methods can call this function to request SIM or smart card PIN
- * information for the current network. This is normally called when the PIN is
- * not included in the network configuration. The request will be sent to
- * monitor programs through the control interface.
- */
-void eap_sm_request_pin(struct eap_sm *sm)
-{
-	eap_sm_request(sm, TYPE_PIN, NULL, 0);
-}
-
-
-/**
- * eap_sm_request_otp - Request one time password from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @msg: Message to be displayed to the user when asking for OTP
- * @msg_len: Length of the user displayable message
- *
- * EAP methods can call this function to request open time password (OTP) for
- * the current network. The request will be sent to monitor programs through
- * the control interface.
- */
-void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
-{
-	eap_sm_request(sm, TYPE_OTP, msg, msg_len);
-}
-
-
-/**
- * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * EAP methods can call this function to request passphrase for a private key
- * for the current network. This is normally called when the passphrase is not
- * included in the network configuration. The request will be sent to monitor
- * programs through the control interface.
- */
-void eap_sm_request_passphrase(struct eap_sm *sm)
-{
-	eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
-}
-
-
-/**
- * eap_sm_notify_ctrl_attached - Notification of attached monitor
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * Notify EAP state machines that a monitor was attached to the control
- * interface to trigger re-sending of pending requests for user input.
- */
-void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	if (config == NULL)
-		return;
-
-	/* Re-send any pending requests for user data since a new control
-	 * interface was added. This handles cases where the EAP authentication
-	 * starts immediately after system startup when the user interface is
-	 * not yet running. */
-	if (config->pending_req_identity)
-		eap_sm_request_identity(sm);
-	if (config->pending_req_password)
-		eap_sm_request_password(sm);
-	if (config->pending_req_new_password)
-		eap_sm_request_new_password(sm);
-	if (config->pending_req_otp)
-		eap_sm_request_otp(sm, NULL, 0);
-	if (config->pending_req_pin)
-		eap_sm_request_pin(sm);
-	if (config->pending_req_passphrase)
-		eap_sm_request_passphrase(sm);
-}
-
-
-static int eap_allowed_phase2_type(int vendor, int type)
-{
-	if (vendor != EAP_VENDOR_IETF)
-		return 0;
-	return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
-		type != EAP_TYPE_FAST;
-}
-
-
-/**
- * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
- * @name: EAP method name, e.g., MD5
- * @vendor: Buffer for returning EAP Vendor-Id
- * Returns: EAP method type or %EAP_TYPE_NONE if not found
- *
- * This function maps EAP type names into EAP type numbers that are allowed for
- * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
- * EAP-PEAP, EAP-TTLS, and EAP-FAST.
- */
-u32 eap_get_phase2_type(const char *name, int *vendor)
-{
-	int v;
-	u8 type = eap_peer_get_type(name, &v);
-	if (eap_allowed_phase2_type(v, type)) {
-		*vendor = v;
-		return type;
-	}
-	*vendor = EAP_VENDOR_IETF;
-	return EAP_TYPE_NONE;
-}
-
-
-/**
- * eap_get_phase2_types - Get list of allowed EAP phase 2 types
- * @config: Pointer to a network configuration
- * @count: Pointer to a variable to be filled with number of returned EAP types
- * Returns: Pointer to allocated type list or %NULL on failure
- *
- * This function generates an array of allowed EAP phase 2 (tunneled) types for
- * the given network configuration.
- */
-struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
-					      size_t *count)
-{
-	struct eap_method_type *buf;
-	u32 method;
-	int vendor;
-	size_t mcount;
-	const struct eap_method *methods, *m;
-
-	methods = eap_peer_get_methods(&mcount);
-	if (methods == NULL)
-		return NULL;
-	*count = 0;
-	buf = os_malloc(mcount * sizeof(struct eap_method_type));
-	if (buf == NULL)
-		return NULL;
-
-	for (m = methods; m; m = m->next) {
-		vendor = m->vendor;
-		method = m->method;
-		if (eap_allowed_phase2_type(vendor, method)) {
-			if (vendor == EAP_VENDOR_IETF &&
-			    method == EAP_TYPE_TLS && config &&
-			    config->private_key2 == NULL)
-				continue;
-			buf[*count].vendor = vendor;
-			buf[*count].method = method;
-			(*count)++;
-		}
-	}
-
-	return buf;
-}
-
-
-/**
- * eap_set_fast_reauth - Update fast_reauth setting
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
- */
-void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
-{
-	sm->fast_reauth = enabled;
-}
-
-
-/**
- * eap_set_workaround - Update EAP workarounds setting
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
- */
-void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
-{
-	sm->workaround = workaround;
-}
-
-
-/**
- * eap_get_config - Get current network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: Pointer to the current network configuration or %NULL if not found
- *
- * EAP peer methods should avoid using this function if they can use other
- * access functions, like eap_get_config_identity() and
- * eap_get_config_password(), that do not require direct access to
- * struct eap_peer_config.
- */
-struct eap_peer_config * eap_get_config(struct eap_sm *sm)
-{
-	return sm->eapol_cb->get_config(sm->eapol_ctx);
-}
-
-
-/**
- * eap_get_config_identity - Get identity from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Buffer for the length of the identity
- * Returns: Pointer to the identity or %NULL if not found
- */
-const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	*len = config->identity_len;
-	return config->identity;
-}
-
-
-/**
- * eap_get_config_password - Get password from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Buffer for the length of the password
- * Returns: Pointer to the password or %NULL if not found
- */
-const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	*len = config->password_len;
-	return config->password;
-}
-
-
-/**
- * eap_get_config_password2 - Get password from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Buffer for the length of the password
- * @hash: Buffer for returning whether the password is stored as a
- * NtPasswordHash instead of plaintext password; can be %NULL if this
- * information is not needed
- * Returns: Pointer to the password or %NULL if not found
- */
-const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	*len = config->password_len;
-	if (hash)
-		*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
-	return config->password;
-}
-
-
-/**
- * eap_get_config_new_password - Get new password from network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Buffer for the length of the new password
- * Returns: Pointer to the new password or %NULL if not found
- */
-const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	*len = config->new_password_len;
-	return config->new_password;
-}
-
-
-/**
- * eap_get_config_otp - Get one-time password from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Buffer for the length of the one-time password
- * Returns: Pointer to the one-time password or %NULL if not found
- */
-const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	*len = config->otp_len;
-	return config->otp;
-}
-
-
-/**
- * eap_clear_config_otp - Clear used one-time password
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * This function clears a used one-time password (OTP) from the current network
- * configuration. This should be called when the OTP has been used and is not
- * needed anymore.
- */
-void eap_clear_config_otp(struct eap_sm *sm)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return;
-	os_memset(config->otp, 0, config->otp_len);
-	os_free(config->otp);
-	config->otp = NULL;
-	config->otp_len = 0;
-}
-
-
-/**
- * eap_get_config_phase1 - Get phase1 data from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: Pointer to the phase1 data or %NULL if not found
- */
-const char * eap_get_config_phase1(struct eap_sm *sm)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	return config->phase1;
-}
-
-
-/**
- * eap_get_config_phase2 - Get phase2 data from the network configuration
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: Pointer to the phase1 data or %NULL if not found
- */
-const char * eap_get_config_phase2(struct eap_sm *sm)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL)
-		return NULL;
-	return config->phase2;
-}
-
-
-/**
- * eap_key_available - Get key availability (eapKeyAvailable variable)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: 1 if EAP keying material is available, 0 if not
- */
-int eap_key_available(struct eap_sm *sm)
-{
-	return sm ? sm->eapKeyAvailable : 0;
-}
-
-
-/**
- * eap_notify_success - Notify EAP state machine about external success trigger
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * This function is called when external event, e.g., successful completion of
- * WPA-PSK key handshake, is indicating that EAP state machine should move to
- * success state. This is mainly used with security modes that do not use EAP
- * state machine (e.g., WPA-PSK).
- */
-void eap_notify_success(struct eap_sm *sm)
-{
-	if (sm) {
-		sm->decision = DECISION_COND_SUCC;
-		sm->EAP_state = EAP_SUCCESS;
-	}
-}
-
-
-/**
- * eap_notify_lower_layer_success - Notification of lower layer success
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * Notify EAP state machines that a lower layer has detected a successful
- * authentication. This is used to recover from dropped EAP-Success messages.
- */
-void eap_notify_lower_layer_success(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return;
-
-	if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
-	    sm->decision == DECISION_FAIL ||
-	    (sm->methodState != METHOD_MAY_CONT &&
-	     sm->methodState != METHOD_DONE))
-		return;
-
-	if (sm->eapKeyData != NULL)
-		sm->eapKeyAvailable = TRUE;
-	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
-		"EAP authentication completed successfully (based on lower "
-		"layer success)");
-}
-
-
-/**
- * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @len: Pointer to variable that will be set to number of bytes in the key
- * Returns: Pointer to the EAP keying data or %NULL on failure
- *
- * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
- * key is available only after a successful authentication. EAP state machine
- * continues to manage the key data and the caller must not change or free the
- * returned data.
- */
-const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
-{
-	if (sm == NULL || sm->eapKeyData == NULL) {
-		*len = 0;
-		return NULL;
-	}
-
-	*len = sm->eapKeyDataLen;
-	return sm->eapKeyData;
-}
-
-
-/**
- * eap_get_eapKeyData - Get EAP response data
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
- *
- * Fetch EAP response (eapRespData) from the EAP state machine. This data is
- * available when EAP state machine has processed an incoming EAP request. The
- * EAP state machine does not maintain a reference to the response after this
- * function is called and the caller is responsible for freeing the data.
- */
-struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
-{
-	struct wpabuf *resp;
-
-	if (sm == NULL || sm->eapRespData == NULL)
-		return NULL;
-
-	resp = sm->eapRespData;
-	sm->eapRespData = NULL;
-
-	return resp;
-}
-
-
-/**
- * eap_sm_register_scard_ctx - Notification of smart card context
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @ctx: Context data for smart card operations
- *
- * Notify EAP state machines of context data for smart card operations. This
- * context data will be used as a parameter for scard_*() functions.
- */
-void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
-{
-	if (sm)
-		sm->scard_ctx = ctx;
-}
-
-
-/**
- * eap_set_config_blob - Set or add a named configuration blob
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @blob: New value for the blob
- *
- * Adds a new configuration blob or replaces the current value of an existing
- * blob.
- */
-void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
-{
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-}
-
-
-/**
- * eap_get_config_blob - Get a named configuration blob
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @name: Name of the blob
- * Returns: Pointer to blob data or %NULL if not found
- */
-const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
-						   const char *name)
-{
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
-#else /* CONFIG_NO_CONFIG_BLOBS */
-	return NULL;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-}
-
-
-/**
- * eap_set_force_disabled - Set force_disabled flag
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @disabled: 1 = EAP disabled, 0 = EAP enabled
- *
- * This function is used to force EAP state machine to be disabled when it is
- * not in use (e.g., with WPA-PSK or plaintext connections).
- */
-void eap_set_force_disabled(struct eap_sm *sm, int disabled)
-{
-	sm->force_disabled = disabled;
-}
-
-
- /**
- * eap_notify_pending - Notify that EAP method is ready to re-process a request
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- *
- * An EAP method can perform a pending operation (e.g., to get a response from
- * an external process). Once the response is available, this function can be
- * used to request EAPOL state machine to retry delivering the previously
- * received (and still unanswered) EAP request to EAP state machine.
- */
-void eap_notify_pending(struct eap_sm *sm)
-{
-	sm->eapol_cb->notify_pending(sm->eapol_ctx);
-}
-
-
-/**
- * eap_invalidate_cached_session - Mark cached session data invalid
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- */
-void eap_invalidate_cached_session(struct eap_sm *sm)
-{
-	if (sm)
-		eap_deinit_prev_method(sm, "invalidate");
-}
-
-
-int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
-{
-	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
-	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
-		return 0; /* Not a WPS Enrollee */
-
-	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
-		return 0; /* Not using PBC */
-
-	return 1;
-}
-
-
-int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
-{
-	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
-	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
-		return 0; /* Not a WPS Enrollee */
-
-	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
-		return 0; /* Not using PIN */
-
-	return 1;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2339 @@
+/*
+ * EAP peer state machines (RFC 4137)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements the Peer State Machine as defined in RFC 4137. The used
+ * states and state transitions match mostly with the RFC. However, there are
+ * couple of additional transitions for working around small issues noticed
+ * during testing. These exceptions are explained in comments within the
+ * functions in this file. The method functions, m.func(), are similar to the
+ * ones used in RFC 4137, but some small changes have used here to optimize
+ * operations and to add functionality needed for fast re-authentication
+ * (session resumption).
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "pcsc_funcs.h"
+#include "state_machine.h"
+#include "ext_password.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+#include "common/wpa_ctrl.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_i.h"
+#include "eap_config.h"
+
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
+
+#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_CLIENT_TIMEOUT_DEFAULT 60
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+				  EapType method);
+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
+static void eap_sm_processIdentity(struct eap_sm *sm,
+				   const struct wpabuf *req);
+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
+static struct wpabuf * eap_sm_buildNotify(int id);
+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+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 Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+{
+	return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
+			   Boolean value)
+{
+	sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
+}
+
+
+static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
+{
+	return sm->eapol_cb->get_int(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
+			  unsigned int value)
+{
+	sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
+}
+
+
+static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
+{
+	return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
+}
+
+
+static void eap_notify_status(struct eap_sm *sm, const char *status,
+				      const char *parameter)
+{
+	wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
+		   status, parameter);
+	if (sm->eapol_cb->notify_status)
+		sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
+}
+
+
+static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
+{
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = NULL;
+
+	if (sm->m == NULL || sm->eap_method_priv == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
+		   "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
+	sm->m->deinit(sm, sm->eap_method_priv);
+	sm->eap_method_priv = NULL;
+	sm->m = NULL;
+}
+
+
+/**
+ * eap_allowed_method - Check whether EAP method is allowed
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
+ * @method: EAP type
+ * Returns: 1 = allowed EAP method, 0 = not allowed
+ */
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	int i;
+	struct eap_method_type *m;
+
+	if (config == NULL || config->eap_methods == NULL)
+		return 1;
+
+	m = config->eap_methods;
+	for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
+		     m[i].method != EAP_TYPE_NONE; i++) {
+		if (m[i].vendor == vendor && m[i].method == method)
+			return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * This state initializes state machine variables when the machine is
+ * activated (portEnabled = TRUE). This is also used when re-starting
+ * authentication (eapRestart == TRUE).
+ */
+SM_STATE(EAP, INITIALIZE)
+{
+	SM_ENTRY(EAP, INITIALIZE);
+	if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
+	    sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
+	    !sm->prev_failure) {
+		wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
+			   "fast reauthentication");
+		sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
+	} else {
+		eap_deinit_prev_method(sm, "INITIALIZE");
+	}
+	sm->selectedMethod = EAP_TYPE_NONE;
+	sm->methodState = METHOD_NONE;
+	sm->allowNotifications = TRUE;
+	sm->decision = DECISION_FAIL;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+	os_free(sm->eapKeyData);
+	sm->eapKeyData = NULL;
+	sm->eapKeyAvailable = FALSE;
+	eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+	sm->lastId = -1; /* new session - make sure this does not match with
+			  * the first EAP-Packet */
+	/*
+	 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
+	 * seemed to be able to trigger cases where both were set and if EAPOL
+	 * state machine uses eapNoResp first, it may end up not sending a real
+	 * reply correctly. This occurred when the workaround in FAIL state set
+	 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+	 * something else(?)
+	 */
+	eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+	sm->num_rounds = 0;
+	sm->prev_failure = 0;
+}
+
+
+/*
+ * This state is reached whenever service from the lower layer is interrupted
+ * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
+ * occurs when the port becomes enabled.
+ */
+SM_STATE(EAP, DISABLED)
+{
+	SM_ENTRY(EAP, DISABLED);
+	sm->num_rounds = 0;
+	/*
+	 * RFC 4137 does not describe clearing of idleWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when EAP is not in
+	 * use.
+	 */
+	eapol_set_int(sm, EAPOL_idleWhile, 0);
+}
+
+
+/*
+ * The state machine spends most of its time here, waiting for something to
+ * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
+ * SEND_RESPONSE states.
+ */
+SM_STATE(EAP, IDLE)
+{
+	SM_ENTRY(EAP, IDLE);
+}
+
+
+/*
+ * This state is entered when an EAP packet is received (eapReq == TRUE) to
+ * parse the packet header.
+ */
+SM_STATE(EAP, RECEIVED)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, RECEIVED);
+	eapReqData = eapol_get_eapReqData(sm);
+	/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
+	eap_sm_parseEapReq(sm, eapReqData);
+	sm->num_rounds++;
+}
+
+
+/*
+ * This state is entered when a request for a new type comes in. Either the
+ * correct method is started, or a Nak response is built.
+ */
+SM_STATE(EAP, GET_METHOD)
+{
+	int reinit;
+	EapType method;
+	const struct eap_method *eap_method;
+
+	SM_ENTRY(EAP, GET_METHOD);
+
+	if (sm->reqMethod == EAP_TYPE_EXPANDED)
+		method = sm->reqVendorMethod;
+	else
+		method = sm->reqMethod;
+
+	eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
+
+	if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
+		wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
+			   sm->reqVendor, method);
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+			"vendor=%u method=%u -> NAK",
+			sm->reqVendor, method);
+		eap_notify_status(sm, "refuse proposed method",
+				  eap_method ?  eap_method->name : "unknown");
+		goto nak;
+	}
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+		"vendor=%u method=%u", sm->reqVendor, method);
+
+	eap_notify_status(sm, "accept proposed method",
+			  eap_method ?  eap_method->name : "unknown");
+	/*
+	 * RFC 4137 does not define specific operation for fast
+	 * re-authentication (session resumption). The design here is to allow
+	 * the previously used method data to be maintained for
+	 * re-authentication if the method support session resumption.
+	 * Otherwise, the previously used method data is freed and a new method
+	 * is allocated here.
+	 */
+	if (sm->fast_reauth &&
+	    sm->m && sm->m->vendor == sm->reqVendor &&
+	    sm->m->method == method &&
+	    sm->m->has_reauth_data &&
+	    sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
+			   " for fast re-authentication");
+		reinit = 1;
+	} else {
+		eap_deinit_prev_method(sm, "GET_METHOD");
+		reinit = 0;
+	}
+
+	sm->selectedMethod = sm->reqMethod;
+	if (sm->m == NULL)
+		sm->m = eap_method;
+	if (!sm->m) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
+			   "vendor %d method %d",
+			   sm->reqVendor, method);
+		goto nak;
+	}
+
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+
+	wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
+		   "vendor %u method %u (%s)",
+		   sm->reqVendor, method, sm->m->name);
+	if (reinit)
+		sm->eap_method_priv = sm->m->init_for_reauth(
+			sm, sm->eap_method_priv);
+	else
+		sm->eap_method_priv = sm->m->init(sm);
+
+	if (sm->eap_method_priv == NULL) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		wpa_msg(sm->msg_ctx, MSG_INFO,
+			"EAP: Failed to initialize EAP method: vendor %u "
+			"method %u (%s)",
+			sm->reqVendor, method, sm->m->name);
+		sm->m = NULL;
+		sm->methodState = METHOD_NONE;
+		sm->selectedMethod = EAP_TYPE_NONE;
+		if (sm->reqMethod == EAP_TYPE_TLS && config &&
+		    (config->pending_req_pin ||
+		     config->pending_req_passphrase)) {
+			/*
+			 * Return without generating Nak in order to allow
+			 * entering of PIN code or passphrase to retry the
+			 * current EAP packet.
+			 */
+			wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
+				   "request - skip Nak");
+			return;
+		}
+
+		goto nak;
+	}
+
+	sm->methodState = METHOD_INIT;
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
+		"EAP vendor %u method %u (%s) selected",
+		sm->reqVendor, method, sm->m->name);
+	return;
+
+nak:
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
+}
+
+
+/*
+ * The method processing happens here. The request from the authenticator is
+ * processed, and an appropriate response packet is built.
+ */
+SM_STATE(EAP, METHOD)
+{
+	struct wpabuf *eapReqData;
+	struct eap_method_ret ret;
+	int min_len = 1;
+
+	SM_ENTRY(EAP, METHOD);
+	if (sm->m == NULL) {
+		wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
+		return;
+	}
+
+	eapReqData = eapol_get_eapReqData(sm);
+	if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP)
+		min_len = 0; /* LEAP uses EAP-Success without payload */
+	if (!eap_hdr_len_valid(eapReqData, min_len))
+		return;
+
+	/*
+	 * Get ignore, methodState, decision, allowNotifications, and
+	 * eapRespData. RFC 4137 uses three separate method procedure (check,
+	 * process, and buildResp) in this state. These have been combined into
+	 * a single function call to m->process() in order to optimize EAP
+	 * method implementation interface a bit. These procedures are only
+	 * used from within this METHOD state, so there is no need to keep
+	 * these as separate C functions.
+	 *
+	 * The RFC 4137 procedures return values as follows:
+	 * ignore = m.check(eapReqData)
+	 * (methodState, decision, allowNotifications) = m.process(eapReqData)
+	 * eapRespData = m.buildResp(reqId)
+	 */
+	os_memset(&ret, 0, sizeof(ret));
+	ret.ignore = sm->ignore;
+	ret.methodState = sm->methodState;
+	ret.decision = sm->decision;
+	ret.allowNotifications = sm->allowNotifications;
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
+					 eapReqData);
+	wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
+		   "methodState=%s decision=%s",
+		   ret.ignore ? "TRUE" : "FALSE",
+		   eap_sm_method_state_txt(ret.methodState),
+		   eap_sm_decision_txt(ret.decision));
+
+	sm->ignore = ret.ignore;
+	if (sm->ignore)
+		return;
+	sm->methodState = ret.methodState;
+	sm->decision = ret.decision;
+	sm->allowNotifications = ret.allowNotifications;
+
+	if (sm->m->isKeyAvailable && sm->m->getKey &&
+	    sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
+		os_free(sm->eapKeyData);
+		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
+					       &sm->eapKeyDataLen);
+	}
+}
+
+
+/*
+ * This state signals the lower layer that a response packet is ready to be
+ * sent.
+ */
+SM_STATE(EAP, SEND_RESPONSE)
+{
+	SM_ENTRY(EAP, SEND_RESPONSE);
+	wpabuf_free(sm->lastRespData);
+	if (sm->eapRespData) {
+		if (sm->workaround)
+			os_memcpy(sm->last_md5, sm->req_md5, 16);
+		sm->lastId = sm->reqId;
+		sm->lastRespData = wpabuf_dup(sm->eapRespData);
+		eapol_set_bool(sm, EAPOL_eapResp, TRUE);
+	} else
+		sm->lastRespData = NULL;
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+}
+
+
+/*
+ * This state signals the lower layer that the request was discarded, and no
+ * response packet will be sent at this time.
+ */
+SM_STATE(EAP, DISCARD)
+{
+	SM_ENTRY(EAP, DISCARD);
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+}
+
+
+/*
+ * Handles requests for Identity method and builds a response.
+ */
+SM_STATE(EAP, IDENTITY)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, IDENTITY);
+	eapReqData = eapol_get_eapReqData(sm);
+	if (!eap_hdr_len_valid(eapReqData, 1))
+		return;
+	eap_sm_processIdentity(sm, eapReqData);
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
+}
+
+
+/*
+ * Handles requests for Notification method and builds a response.
+ */
+SM_STATE(EAP, NOTIFICATION)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, NOTIFICATION);
+	eapReqData = eapol_get_eapReqData(sm);
+	if (!eap_hdr_len_valid(eapReqData, 1))
+		return;
+	eap_sm_processNotify(sm, eapReqData);
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildNotify(sm->reqId);
+}
+
+
+/*
+ * This state retransmits the previous response packet.
+ */
+SM_STATE(EAP, RETRANSMIT)
+{
+	SM_ENTRY(EAP, RETRANSMIT);
+	wpabuf_free(sm->eapRespData);
+	if (sm->lastRespData)
+		sm->eapRespData = wpabuf_dup(sm->lastRespData);
+	else
+		sm->eapRespData = NULL;
+}
+
+
+/*
+ * This state is entered in case of a successful completion of authentication
+ * and state machine waits here until port is disabled or EAP authentication is
+ * restarted.
+ */
+SM_STATE(EAP, SUCCESS)
+{
+	SM_ENTRY(EAP, SUCCESS);
+	if (sm->eapKeyData != NULL)
+		sm->eapKeyAvailable = TRUE;
+	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+
+	/*
+	 * RFC 4137 does not clear eapReq here, but this seems to be required
+	 * to avoid processing the same request twice when state machine is
+	 * initialized.
+	 */
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+
+	/*
+	 * RFC 4137 does not set eapNoResp here, but this seems to be required
+	 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
+	 * addition, either eapResp or eapNoResp is required to be set after
+	 * processing the received EAP frame.
+	 */
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		"EAP authentication completed successfully");
+}
+
+
+/*
+ * This state is entered in case of a failure and state machine waits here
+ * until port is disabled or EAP authentication is restarted.
+ */
+SM_STATE(EAP, FAILURE)
+{
+	SM_ENTRY(EAP, FAILURE);
+	eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+
+	/*
+	 * RFC 4137 does not clear eapReq here, but this seems to be required
+	 * to avoid processing the same request twice when state machine is
+	 * initialized.
+	 */
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+
+	/*
+	 * RFC 4137 does not set eapNoResp here. However, either eapResp or
+	 * eapNoResp is required to be set after processing the received EAP
+	 * frame.
+	 */
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+		"EAP authentication failed");
+
+	sm->prev_failure = 1;
+}
+
+
+static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
+{
+	/*
+	 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
+	 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
+	 * RFC 4137 require that reqId == lastId. In addition, it looks like
+	 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
+	 *
+	 * Accept this kind of Id if EAP workarounds are enabled. These are
+	 * unauthenticated plaintext messages, so this should have minimal
+	 * security implications (bit easier to fake EAP-Success/Failure).
+	 */
+	if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
+			       reqId == ((lastId + 2) & 0xff))) {
+		wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
+			   "identifier field in EAP Success: "
+			   "reqId=%d lastId=%d (these are supposed to be "
+			   "same)", reqId, lastId);
+		return 1;
+	}
+	wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
+		   "lastId=%d", reqId, lastId);
+	return 0;
+}
+
+
+/*
+ * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
+ */
+
+static void eap_peer_sm_step_idle(struct eap_sm *sm)
+{
+	/*
+	 * The first three transitions are from RFC 4137. The last two are
+	 * local additions to handle special cases with LEAP and PEAP server
+	 * not sending EAP-Success in some cases.
+	 */
+	if (eapol_get_bool(sm, EAPOL_eapReq))
+		SM_ENTER(EAP, RECEIVED);
+	else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
+		  sm->decision != DECISION_FAIL) ||
+		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+		  sm->decision == DECISION_UNCOND_SUCC))
+		SM_ENTER(EAP, SUCCESS);
+	else if (eapol_get_bool(sm, EAPOL_altReject) ||
+		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+		  sm->decision != DECISION_UNCOND_SUCC) ||
+		 (eapol_get_bool(sm, EAPOL_altAccept) &&
+		  sm->methodState != METHOD_CONT &&
+		  sm->decision == DECISION_FAIL))
+		SM_ENTER(EAP, FAILURE);
+	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+		 sm->leap_done && sm->decision != DECISION_FAIL &&
+		 sm->methodState == METHOD_DONE)
+		SM_ENTER(EAP, SUCCESS);
+	else if (sm->selectedMethod == EAP_TYPE_PEAP &&
+		 sm->peap_done && sm->decision != DECISION_FAIL &&
+		 sm->methodState == METHOD_DONE)
+		SM_ENTER(EAP, SUCCESS);
+}
+
+
+static int eap_peer_req_is_duplicate(struct eap_sm *sm)
+{
+	int duplicate;
+
+	duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
+	if (sm->workaround && duplicate &&
+	    os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
+		/*
+		 * RFC 4137 uses (reqId == lastId) as the only verification for
+		 * duplicate EAP requests. However, this misses cases where the
+		 * AS is incorrectly using the same id again; and
+		 * unfortunately, such implementations exist. Use MD5 hash as
+		 * an extra verification for the packets being duplicate to
+		 * workaround these issues.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
+			   "EAP packets were not identical");
+		wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
+			   "duplicate packet");
+		duplicate = 0;
+	}
+
+	return duplicate;
+}
+
+
+static void eap_peer_sm_step_received(struct eap_sm *sm)
+{
+	int duplicate = eap_peer_req_is_duplicate(sm);
+
+	/*
+	 * Two special cases below for LEAP are local additions to work around
+	 * odd LEAP behavior (EAP-Success in the middle of authentication and
+	 * then swapped roles). Other transitions are based on RFC 4137.
+	 */
+	if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
+	    (sm->reqId == sm->lastId ||
+	     eap_success_workaround(sm, sm->reqId, sm->lastId)))
+		SM_ENTER(EAP, SUCCESS);
+	else if (sm->methodState != METHOD_CONT &&
+		 ((sm->rxFailure &&
+		   sm->decision != DECISION_UNCOND_SUCC) ||
+		  (sm->rxSuccess && sm->decision == DECISION_FAIL &&
+		   (sm->selectedMethod != EAP_TYPE_LEAP ||
+		    sm->methodState != METHOD_MAY_CONT))) &&
+		 (sm->reqId == sm->lastId ||
+		  eap_success_workaround(sm, sm->reqId, sm->lastId)))
+		SM_ENTER(EAP, FAILURE);
+	else if (sm->rxReq && duplicate)
+		SM_ENTER(EAP, RETRANSMIT);
+	else if (sm->rxReq && !duplicate &&
+		 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
+		 sm->allowNotifications)
+		SM_ENTER(EAP, NOTIFICATION);
+	else if (sm->rxReq && !duplicate &&
+		 sm->selectedMethod == EAP_TYPE_NONE &&
+		 sm->reqMethod == EAP_TYPE_IDENTITY)
+		SM_ENTER(EAP, IDENTITY);
+	else if (sm->rxReq && !duplicate &&
+		 sm->selectedMethod == EAP_TYPE_NONE &&
+		 sm->reqMethod != EAP_TYPE_IDENTITY &&
+		 sm->reqMethod != EAP_TYPE_NOTIFICATION)
+		SM_ENTER(EAP, GET_METHOD);
+	else if (sm->rxReq && !duplicate &&
+		 sm->reqMethod == sm->selectedMethod &&
+		 sm->methodState != METHOD_DONE)
+		SM_ENTER(EAP, METHOD);
+	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+		 (sm->rxSuccess || sm->rxResp))
+		SM_ENTER(EAP, METHOD);
+	else
+		SM_ENTER(EAP, DISCARD);
+}
+
+
+static void eap_peer_sm_step_local(struct eap_sm *sm)
+{
+	switch (sm->EAP_state) {
+	case EAP_INITIALIZE:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_DISABLED:
+		if (eapol_get_bool(sm, EAPOL_portEnabled) &&
+		    !sm->force_disabled)
+			SM_ENTER(EAP, INITIALIZE);
+		break;
+	case EAP_IDLE:
+		eap_peer_sm_step_idle(sm);
+		break;
+	case EAP_RECEIVED:
+		eap_peer_sm_step_received(sm);
+		break;
+	case EAP_GET_METHOD:
+		if (sm->selectedMethod == sm->reqMethod)
+			SM_ENTER(EAP, METHOD);
+		else
+			SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_METHOD:
+		if (sm->ignore)
+			SM_ENTER(EAP, DISCARD);
+		else
+			SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_SEND_RESPONSE:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_DISCARD:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_IDENTITY:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_NOTIFICATION:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_RETRANSMIT:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_SUCCESS:
+		break;
+	case EAP_FAILURE:
+		break;
+	}
+}
+
+
+SM_STEP(EAP)
+{
+	/* Global transitions */
+	if (eapol_get_bool(sm, EAPOL_eapRestart) &&
+	    eapol_get_bool(sm, EAPOL_portEnabled))
+		SM_ENTER_GLOBAL(EAP, INITIALIZE);
+	else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
+		SM_ENTER_GLOBAL(EAP, DISABLED);
+	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
+		/* RFC 4137 does not place any limit on number of EAP messages
+		 * in an authentication session. However, some error cases have
+		 * ended up in a state were EAP messages were sent between the
+		 * peer and server in a loop (e.g., TLS ACK frame in both
+		 * direction). Since this is quite undesired outcome, limit the
+		 * total number of EAP round-trips and abort authentication if
+		 * this limit is exceeded.
+		 */
+		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+			wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
+				"authentication rounds - abort",
+				EAP_MAX_AUTH_ROUNDS);
+			sm->num_rounds++;
+			SM_ENTER_GLOBAL(EAP, FAILURE);
+		}
+	} else {
+		/* Local transitions */
+		eap_peer_sm_step_local(sm);
+	}
+}
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+				  EapType method)
+{
+	if (!eap_allowed_method(sm, vendor, method)) {
+		wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
+			   "vendor %u method %u", vendor, method);
+		return FALSE;
+	}
+	if (eap_peer_get_eap_method(vendor, method))
+		return TRUE;
+	wpa_printf(MSG_DEBUG, "EAP: not included in build: "
+		   "vendor %u method %u", vendor, method);
+	return FALSE;
+}
+
+
+static struct wpabuf * eap_sm_build_expanded_nak(
+	struct eap_sm *sm, int id, const struct eap_method *methods,
+	size_t count)
+{
+	struct wpabuf *resp;
+	int found = 0;
+	const struct eap_method *m;
+
+	wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
+
+	/* RFC 3748 - 5.3.2: Expanded Nak */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
+			     8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_be24(resp, EAP_VENDOR_IETF);
+	wpabuf_put_be32(resp, EAP_TYPE_NAK);
+
+	for (m = methods; m; m = m->next) {
+		if (sm->reqVendor == m->vendor &&
+		    sm->reqVendorMethod == m->method)
+			continue; /* do not allow the current method again */
+		if (eap_allowed_method(sm, m->vendor, m->method)) {
+			wpa_printf(MSG_DEBUG, "EAP: allowed type: "
+				   "vendor=%u method=%u",
+				   m->vendor, m->method);
+			wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+			wpabuf_put_be24(resp, m->vendor);
+			wpabuf_put_be32(resp, m->method);
+
+			found++;
+		}
+	}
+	if (!found) {
+		wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
+		wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+		wpabuf_put_be24(resp, EAP_VENDOR_IETF);
+		wpabuf_put_be32(resp, EAP_TYPE_NONE);
+	}
+
+	eap_update_len(resp);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
+{
+	struct wpabuf *resp;
+	u8 *start;
+	int found = 0, expanded_found = 0;
+	size_t count;
+	const struct eap_method *methods, *m;
+
+	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
+		   "vendor=%u method=%u not allowed)", sm->reqMethod,
+		   sm->reqVendor, sm->reqVendorMethod);
+	methods = eap_peer_get_methods(&count);
+	if (methods == NULL)
+		return NULL;
+	if (sm->reqMethod == EAP_TYPE_EXPANDED)
+		return eap_sm_build_expanded_nak(sm, id, methods, count);
+
+	/* RFC 3748 - 5.3.1: Legacy Nak */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
+			     sizeof(struct eap_hdr) + 1 + count + 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	start = wpabuf_put(resp, 0);
+	for (m = methods; m; m = m->next) {
+		if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
+			continue; /* do not allow the current method again */
+		if (eap_allowed_method(sm, m->vendor, m->method)) {
+			if (m->vendor != EAP_VENDOR_IETF) {
+				if (expanded_found)
+					continue;
+				expanded_found = 1;
+				wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+			} else
+				wpabuf_put_u8(resp, m->method);
+			found++;
+		}
+	}
+	if (!found)
+		wpabuf_put_u8(resp, EAP_TYPE_NONE);
+	wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
+
+	eap_update_len(resp);
+
+	return resp;
+}
+
+
+static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const u8 *pos;
+	size_t msg_len;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+		"EAP authentication started");
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
+			       &msg_len);
+	if (pos == NULL)
+		return;
+
+	/*
+	 * RFC 3748 - 5.1: Identity
+	 * Data field may contain a displayable message in UTF-8. If this
+	 * includes NUL-character, only the data before that should be
+	 * displayed. Some EAP implementasitons may piggy-back additional
+	 * options after the NUL.
+	 */
+	/* TODO: could save displayable message so that it can be shown to the
+	 * user in case of interaction is required */
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
+			  pos, msg_len);
+}
+
+
+#ifdef PCSC_FUNCS
+
+/*
+ * Rules for figuring out MNC length based on IMSI for SIM cards that do not
+ * include MNC length field.
+ */
+static int mnc_len_from_imsi(const char *imsi)
+{
+	char mcc_str[4];
+	unsigned int mcc;
+
+	os_memcpy(mcc_str, imsi, 3);
+	mcc_str[3] = '\0';
+	mcc = atoi(mcc_str);
+
+	if (mcc == 244)
+		return 2; /* Networks in Finland use 2-digit MNC */
+
+	return -1;
+}
+
+
+static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
+				    size_t max_len, size_t *imsi_len)
+{
+	int mnc_len;
+	char *pos, mnc[4];
+
+	if (*imsi_len + 36 > max_len) {
+		wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
+		return -1;
+	}
+
+	/* MNC (2 or 3 digits) */
+	mnc_len = scard_get_mnc_len(sm->scard_ctx);
+	if (mnc_len < 0)
+		mnc_len = mnc_len_from_imsi(imsi);
+	if (mnc_len < 0) {
+		wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
+			   "assuming 3");
+		mnc_len = 3;
+	}
+
+	if (mnc_len == 2) {
+		mnc[0] = '0';
+		mnc[1] = imsi[3];
+		mnc[2] = imsi[4];
+	} else if (mnc_len == 3) {
+		mnc[0] = imsi[3];
+		mnc[1] = imsi[4];
+		mnc[2] = imsi[5];
+	}
+	mnc[3] = '\0';
+
+	pos = imsi + *imsi_len;
+	pos += os_snprintf(pos, imsi + max_len - pos,
+			   "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
+			   mnc, imsi[0], imsi[1], imsi[2]);
+	*imsi_len = pos - imsi;
+
+	return 0;
+}
+
+
+static int eap_sm_imsi_identity(struct eap_sm *sm,
+				struct eap_peer_config *conf)
+{
+	enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
+	char imsi[100];
+	size_t imsi_len;
+	struct eap_method_type *m = conf->eap_methods;
+	int i;
+
+	imsi_len = sizeof(imsi);
+	if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
+		wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
+
+	if (imsi_len < 7) {
+		wpa_printf(MSG_WARNING, "Too short IMSI for SIM identity");
+		return -1;
+	}
+
+	if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len) < 0) {
+		wpa_printf(MSG_WARNING, "Could not add realm to SIM identity");
+		return -1;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "IMSI + realm", (u8 *) imsi, imsi_len);
+
+	for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
+			  m[i].method != EAP_TYPE_NONE); i++) {
+		if (m[i].vendor == EAP_VENDOR_IETF &&
+		    m[i].method == EAP_TYPE_AKA_PRIME) {
+			method = EAP_SM_AKA_PRIME;
+			break;
+		}
+
+		if (m[i].vendor == EAP_VENDOR_IETF &&
+		    m[i].method == EAP_TYPE_AKA) {
+			method = EAP_SM_AKA;
+			break;
+		}
+	}
+
+	os_free(conf->identity);
+	conf->identity = os_malloc(1 + imsi_len);
+	if (conf->identity == NULL) {
+		wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
+			   "IMSI-based identity");
+		return -1;
+	}
+
+	switch (method) {
+	case EAP_SM_SIM:
+		conf->identity[0] = '1';
+		break;
+	case EAP_SM_AKA:
+		conf->identity[0] = '0';
+		break;
+	case EAP_SM_AKA_PRIME:
+		conf->identity[0] = '6';
+		break;
+	}
+	os_memcpy(conf->identity + 1, imsi, imsi_len);
+	conf->identity_len = 1 + imsi_len;
+
+	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
+		 * blocking SIM.
+		 */
+		os_free(conf->pin);
+		conf->pin = NULL;
+
+		wpa_printf(MSG_WARNING, "PIN validation failed");
+		eap_sm_request_pin(sm);
+		return -1;
+	}
+	return 0;
+#else /* PCSC_FUNCS */
+	return -1;
+#endif /* PCSC_FUNCS */
+}
+
+static int eap_sm_get_scard_identity(struct eap_sm *sm,
+				     struct eap_peer_config *conf)
+{
+#ifdef PCSC_FUNCS
+	if (eap_sm_set_scard_pin(sm, conf))
+		return -1;
+
+	return eap_sm_imsi_identity(sm, conf);
+#else /* PCSC_FUNCS */
+	return -1;
+#endif /* PCSC_FUNCS */
+}
+
+
+/**
+ * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: EAP identifier for the packet
+ * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
+ * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
+ * failure
+ *
+ * This function allocates and builds an EAP-Identity/Response packet for the
+ * current network. The caller is responsible for freeing the returned data.
+ */
+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	struct wpabuf *resp;
+	const u8 *identity;
+	size_t identity_len;
+
+	if (config == NULL) {
+		wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
+			   "was not available");
+		return NULL;
+	}
+
+	if (sm->m && sm->m->get_identity &&
+	    (identity = sm->m->get_identity(sm, sm->eap_method_priv,
+					    &identity_len)) != NULL) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
+				  "identity", identity, identity_len);
+	} else if (!encrypted && config->anonymous_identity) {
+		identity = config->anonymous_identity;
+		identity_len = config->anonymous_identity_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
+				  identity, identity_len);
+	} else {
+		identity = config->identity;
+		identity_len = config->identity_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
+				  identity, identity_len);
+	}
+
+	if (identity == NULL) {
+		wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
+			   "configuration was not available");
+		if (config->pcsc) {
+			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);
+			return NULL;
+		}
+	} else if (config->pcsc) {
+		if (eap_sm_set_scard_pin(sm, config) < 0)
+			return NULL;
+	}
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_data(resp, identity, identity_len);
+
+	return resp;
+}
+
+
+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const u8 *pos;
+	char *msg;
+	size_t i, msg_len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
+			       &msg_len);
+	if (pos == NULL)
+		return;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
+			  pos, msg_len);
+
+	msg = os_malloc(msg_len + 1);
+	if (msg == NULL)
+		return;
+	for (i = 0; i < msg_len; i++)
+		msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
+	msg[msg_len] = '\0';
+	wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
+		WPA_EVENT_EAP_NOTIFICATION, msg);
+	os_free(msg);
+}
+
+
+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;
+}
+
+
+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const struct eap_hdr *hdr;
+	size_t plen;
+	const u8 *pos;
+
+	sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
+	sm->reqId = 0;
+	sm->reqMethod = EAP_TYPE_NONE;
+	sm->reqVendor = EAP_VENDOR_IETF;
+	sm->reqVendorMethod = EAP_TYPE_NONE;
+
+	if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
+		return;
+
+	hdr = wpabuf_head(req);
+	plen = be_to_host16(hdr->length);
+	if (plen > wpabuf_len(req)) {
+		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
+			   "(len=%lu plen=%lu)",
+			   (unsigned long) wpabuf_len(req),
+			   (unsigned long) plen);
+		return;
+	}
+
+	sm->reqId = hdr->identifier;
+
+	if (sm->workaround) {
+		const u8 *addr[1];
+		addr[0] = wpabuf_head(req);
+		md5_vector(1, addr, &plen, sm->req_md5);
+	}
+
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (plen < sizeof(*hdr) + 1) {
+			wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
+				   "no Type field");
+			return;
+		}
+		sm->rxReq = TRUE;
+		pos = (const u8 *) (hdr + 1);
+		sm->reqMethod = *pos++;
+		if (sm->reqMethod == EAP_TYPE_EXPANDED) {
+			if (plen < sizeof(*hdr) + 8) {
+				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+					   "expanded EAP-Packet (plen=%lu)",
+					   (unsigned long) plen);
+				return;
+			}
+			sm->reqVendor = WPA_GET_BE24(pos);
+			pos += 3;
+			sm->reqVendorMethod = WPA_GET_BE32(pos);
+		}
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
+			   "method=%u vendor=%u vendorMethod=%u",
+			   sm->reqId, sm->reqMethod, sm->reqVendor,
+			   sm->reqVendorMethod);
+		break;
+	case EAP_CODE_RESPONSE:
+		if (sm->selectedMethod == EAP_TYPE_LEAP) {
+			/*
+			 * LEAP differs from RFC 4137 by using reversed roles
+			 * for mutual authentication and because of this, we
+			 * need to accept EAP-Response frames if LEAP is used.
+			 */
+			if (plen < sizeof(*hdr) + 1) {
+				wpa_printf(MSG_DEBUG, "EAP: Too short "
+					   "EAP-Response - no Type field");
+				return;
+			}
+			sm->rxResp = TRUE;
+			pos = (const u8 *) (hdr + 1);
+			sm->reqMethod = *pos;
+			wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
+				   "LEAP method=%d id=%d",
+				   sm->reqMethod, sm->reqId);
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+		eap_notify_status(sm, "completion", "success");
+		sm->rxSuccess = TRUE;
+		break;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+		eap_notify_status(sm, "completion", "failure");
+		sm->rxFailure = TRUE;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
+			   "code %d", hdr->code);
+		break;
+	}
+}
+
+
+static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
+				  union tls_event_data *data)
+{
+	struct eap_sm *sm = ctx;
+	char *hash_hex = NULL;
+
+	switch (ev) {
+	case TLS_CERT_CHAIN_SUCCESS:
+		eap_notify_status(sm, "remote certificate verification",
+				  "success");
+		break;
+	case TLS_CERT_CHAIN_FAILURE:
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
+			"reason=%d depth=%d subject='%s' err='%s'",
+			data->cert_fail.reason,
+			data->cert_fail.depth,
+			data->cert_fail.subject,
+			data->cert_fail.reason_txt);
+		eap_notify_status(sm, "remote certificate verification",
+				  data->cert_fail.reason_txt);
+		break;
+	case TLS_PEER_CERTIFICATE:
+		if (!sm->eapol_cb->notify_cert)
+			break;
+
+		if (data->peer_cert.hash) {
+			size_t len = data->peer_cert.hash_len * 2 + 1;
+			hash_hex = os_malloc(len);
+			if (hash_hex) {
+				wpa_snprintf_hex(hash_hex, len,
+						 data->peer_cert.hash,
+						 data->peer_cert.hash_len);
+			}
+		}
+
+		sm->eapol_cb->notify_cert(sm->eapol_ctx,
+					  data->peer_cert.depth,
+					  data->peer_cert.subject,
+					  hash_hex, data->peer_cert.cert);
+		break;
+	case TLS_ALERT:
+		if (data->alert.is_local)
+			eap_notify_status(sm, "local TLS alert",
+					  data->alert.description);
+		else
+			eap_notify_status(sm, "remote TLS alert",
+					  data->alert.description);
+		break;
+	}
+
+	os_free(hash_hex);
+}
+
+
+/**
+ * eap_peer_sm_init - Allocate and initialize EAP peer state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @msg_ctx: Context data for wpa_msg() calls
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine. In addition,
+ * this initializes TLS library for the new EAP state machine. eapol_cb pointer
+ * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
+ * state machine. Consequently, the caller must make sure that this data
+ * structure remains alive while the EAP state machine is active.
+ */
+struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
+				 struct eapol_callbacks *eapol_cb,
+				 void *msg_ctx, struct eap_config *conf)
+{
+	struct eap_sm *sm;
+	struct tls_config tlsconf;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	sm->eapol_ctx = eapol_ctx;
+	sm->eapol_cb = eapol_cb;
+	sm->msg_ctx = msg_ctx;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+	sm->wps = conf->wps;
+
+	os_memset(&tlsconf, 0, sizeof(tlsconf));
+	tlsconf.opensc_engine_path = conf->opensc_engine_path;
+	tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
+	tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+#ifdef CONFIG_FIPS
+	tlsconf.fips_mode = 1;
+#endif /* CONFIG_FIPS */
+	tlsconf.event_cb = eap_peer_sm_tls_event;
+	tlsconf.cb_ctx = sm;
+	tlsconf.cert_in_cb = conf->cert_in_cb;
+	sm->ssl_ctx = tls_init(&tlsconf);
+	if (sm->ssl_ctx == NULL) {
+		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
+			   "context.");
+		os_free(sm);
+		return NULL;
+	}
+
+	sm->ssl_ctx2 = tls_init(&tlsconf);
+	if (sm->ssl_ctx2 == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
+			   "context (2).");
+		/* Run without separate TLS context within TLS tunnel */
+	}
+
+	return sm;
+}
+
+
+/**
+ * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
+void eap_peer_sm_deinit(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eap_deinit_prev_method(sm, "EAP deinit");
+	eap_sm_abort(sm);
+	if (sm->ssl_ctx2)
+		tls_deinit(sm->ssl_ctx2);
+	tls_deinit(sm->ssl_ctx);
+	os_free(sm);
+}
+
+
+/**
+ * eap_peer_sm_step - Step EAP peer state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
+int eap_peer_sm_step(struct eap_sm *sm)
+{
+	int res = 0;
+	do {
+		sm->changed = FALSE;
+		SM_STEP_RUN(EAP);
+		if (sm->changed)
+			res = 1;
+	} while (sm->changed);
+	return res;
+}
+
+
+/**
+ * eap_sm_abort - Abort EAP authentication
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Release system resources that have been allocated for the authentication
+ * session without fully deinitializing the EAP state machine.
+ */
+void eap_sm_abort(struct eap_sm *sm)
+{
+	wpabuf_free(sm->lastRespData);
+	sm->lastRespData = NULL;
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	os_free(sm->eapKeyData);
+	sm->eapKeyData = NULL;
+
+	/* This is not clearly specified in the EAP statemachines draft, but
+	 * it seems necessary to make sure that some of the EAPOL variables get
+	 * cleared for the next authentication. */
+	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static const char * eap_sm_state_txt(int state)
+{
+	switch (state) {
+	case EAP_INITIALIZE:
+		return "INITIALIZE";
+	case EAP_DISABLED:
+		return "DISABLED";
+	case EAP_IDLE:
+		return "IDLE";
+	case EAP_RECEIVED:
+		return "RECEIVED";
+	case EAP_GET_METHOD:
+		return "GET_METHOD";
+	case EAP_METHOD:
+		return "METHOD";
+	case EAP_SEND_RESPONSE:
+		return "SEND_RESPONSE";
+	case EAP_DISCARD:
+		return "DISCARD";
+	case EAP_IDENTITY:
+		return "IDENTITY";
+	case EAP_NOTIFICATION:
+		return "NOTIFICATION";
+	case EAP_RETRANSMIT:
+		return "RETRANSMIT";
+	case EAP_SUCCESS:
+		return "SUCCESS";
+	case EAP_FAILURE:
+		return "FAILURE";
+	default:
+		return "UNKNOWN";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eap_sm_method_state_txt(EapMethodState state)
+{
+	switch (state) {
+	case METHOD_NONE:
+		return "NONE";
+	case METHOD_INIT:
+		return "INIT";
+	case METHOD_CONT:
+		return "CONT";
+	case METHOD_MAY_CONT:
+		return "MAY_CONT";
+	case METHOD_DONE:
+		return "DONE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char * eap_sm_decision_txt(EapDecision decision)
+{
+	switch (decision) {
+	case DECISION_FAIL:
+		return "FAIL";
+	case DECISION_COND_SUCC:
+		return "COND_SUCC";
+	case DECISION_UNCOND_SUCC:
+		return "UNCOND_SUCC";
+	default:
+		return "UNKNOWN";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_CTRL_IFACE
+
+/**
+ * eap_sm_get_status - Get EAP state machine status
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_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 state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
+{
+	int len, ret;
+
+	if (sm == NULL)
+		return 0;
+
+	len = os_snprintf(buf, buflen,
+			  "EAP state=%s\n",
+			  eap_sm_state_txt(sm->EAP_state));
+	if (len < 0 || (size_t) len >= buflen)
+		return 0;
+
+	if (sm->selectedMethod != EAP_TYPE_NONE) {
+		const char *name;
+		if (sm->m) {
+			name = sm->m->name;
+		} else {
+			const struct eap_method *m =
+				eap_peer_get_eap_method(EAP_VENDOR_IETF,
+							sm->selectedMethod);
+			if (m)
+				name = m->name;
+			else
+				name = "?";
+		}
+		ret = os_snprintf(buf + len, buflen - len,
+				  "selectedMethod=%d (EAP-%s)\n",
+				  sm->selectedMethod, name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+
+		if (sm->m && sm->m->get_status) {
+			len += sm->m->get_status(sm, sm->eap_method_priv,
+						 buf + len, buflen - len,
+						 verbose);
+		}
+	}
+
+	if (verbose) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "reqMethod=%d\n"
+				  "methodState=%s\n"
+				  "decision=%s\n"
+				  "ClientTimeout=%d\n",
+				  sm->reqMethod,
+				  eap_sm_method_state_txt(sm->methodState),
+				  eap_sm_decision_txt(sm->decision),
+				  sm->ClientTimeout);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
+#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)
+{
+	struct eap_peer_config *config;
+	char *txt = NULL, *tmp;
+
+	if (sm == NULL)
+		return;
+	config = eap_get_config(sm);
+	if (config == NULL)
+		return;
+
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		config->pending_req_identity++;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		config->pending_req_password++;
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		config->pending_req_new_password++;
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		config->pending_req_pin++;
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		if (msg) {
+			tmp = os_malloc(msglen + 3);
+			if (tmp == NULL)
+				return;
+			tmp[0] = '[';
+			os_memcpy(tmp + 1, msg, msglen);
+			tmp[msglen + 1] = ']';
+			tmp[msglen + 2] = '\0';
+			txt = tmp;
+			os_free(config->pending_req_otp);
+			config->pending_req_otp = tmp;
+			config->pending_req_otp_len = msglen + 3;
+		} else {
+			if (config->pending_req_otp == NULL)
+				return;
+			txt = config->pending_req_otp;
+		}
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		config->pending_req_passphrase++;
+		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)
+{
+	if (sm->m == NULL)
+		return "UNKNOWN";
+	return sm->m->name;
+}
+
+
+/**
+ * eap_sm_request_identity - Request identity from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request identity information for the
+ * current network. This is normally called when the identity is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
+void eap_sm_request_identity(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_password - Request password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request password information for the
+ * current network. This is normally called when the password is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
+void eap_sm_request_password(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_new_password - Request new password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request new password information for
+ * the current network. This is normally called when the EAP method indicates
+ * that the current password has expired and password change is required. The
+ * request will be sent to monitor programs through the control interface.
+ */
+void eap_sm_request_new_password(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request SIM or smart card PIN
+ * information for the current network. This is normally called when the PIN is
+ * not included in the network configuration. The request will be sent to
+ * monitor programs through the control interface.
+ */
+void eap_sm_request_pin(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_otp - Request one time password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @msg: Message to be displayed to the user when asking for OTP
+ * @msg_len: Length of the user displayable message
+ *
+ * EAP methods can call this function to request open time password (OTP) for
+ * the current network. The request will be sent to monitor programs through
+ * the control interface.
+ */
+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
+}
+
+
+/**
+ * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request passphrase for a private key
+ * for the current network. This is normally called when the passphrase is not
+ * included in the network configuration. The request will be sent to monitor
+ * programs through the control interface.
+ */
+void eap_sm_request_passphrase(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
+}
+
+
+/**
+ * eap_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Notify EAP state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	if (config == NULL)
+		return;
+
+	/* Re-send any pending requests for user data since a new control
+	 * interface was added. This handles cases where the EAP authentication
+	 * starts immediately after system startup when the user interface is
+	 * not yet running. */
+	if (config->pending_req_identity)
+		eap_sm_request_identity(sm);
+	if (config->pending_req_password)
+		eap_sm_request_password(sm);
+	if (config->pending_req_new_password)
+		eap_sm_request_new_password(sm);
+	if (config->pending_req_otp)
+		eap_sm_request_otp(sm, NULL, 0);
+	if (config->pending_req_pin)
+		eap_sm_request_pin(sm);
+	if (config->pending_req_passphrase)
+		eap_sm_request_passphrase(sm);
+}
+
+
+static int eap_allowed_phase2_type(int vendor, int type)
+{
+	if (vendor != EAP_VENDOR_IETF)
+		return 0;
+	return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
+		type != EAP_TYPE_FAST;
+}
+
+
+/**
+ * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
+ * @name: EAP method name, e.g., MD5
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers that are allowed for
+ * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
+ * EAP-PEAP, EAP-TTLS, and EAP-FAST.
+ */
+u32 eap_get_phase2_type(const char *name, int *vendor)
+{
+	int v;
+	u8 type = eap_peer_get_type(name, &v);
+	if (eap_allowed_phase2_type(v, type)) {
+		*vendor = v;
+		return type;
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_get_phase2_types - Get list of allowed EAP phase 2 types
+ * @config: Pointer to a network configuration
+ * @count: Pointer to a variable to be filled with number of returned EAP types
+ * Returns: Pointer to allocated type list or %NULL on failure
+ *
+ * This function generates an array of allowed EAP phase 2 (tunneled) types for
+ * the given network configuration.
+ */
+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
+					      size_t *count)
+{
+	struct eap_method_type *buf;
+	u32 method;
+	int vendor;
+	size_t mcount;
+	const struct eap_method *methods, *m;
+
+	methods = eap_peer_get_methods(&mcount);
+	if (methods == NULL)
+		return NULL;
+	*count = 0;
+	buf = os_malloc(mcount * sizeof(struct eap_method_type));
+	if (buf == NULL)
+		return NULL;
+
+	for (m = methods; m; m = m->next) {
+		vendor = m->vendor;
+		method = m->method;
+		if (eap_allowed_phase2_type(vendor, method)) {
+			if (vendor == EAP_VENDOR_IETF &&
+			    method == EAP_TYPE_TLS && config &&
+			    config->private_key2 == NULL)
+				continue;
+			buf[*count].vendor = vendor;
+			buf[*count].method = method;
+			(*count)++;
+		}
+	}
+
+	return buf;
+}
+
+
+/**
+ * eap_set_fast_reauth - Update fast_reauth setting
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
+ */
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
+{
+	sm->fast_reauth = enabled;
+}
+
+
+/**
+ * eap_set_workaround - Update EAP workarounds setting
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
+ */
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
+{
+	sm->workaround = workaround;
+}
+
+
+/**
+ * eap_get_config - Get current network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the current network configuration or %NULL if not found
+ *
+ * EAP peer methods should avoid using this function if they can use other
+ * access functions, like eap_get_config_identity() and
+ * eap_get_config_password(), that do not require direct access to
+ * struct eap_peer_config.
+ */
+struct eap_peer_config * eap_get_config(struct eap_sm *sm)
+{
+	return sm->eapol_cb->get_config(sm->eapol_ctx);
+}
+
+
+/**
+ * eap_get_config_identity - Get identity from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the identity
+ * Returns: Pointer to the identity or %NULL if not found
+ */
+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->identity_len;
+	return config->identity;
+}
+
+
+static int eap_get_ext_password(struct eap_sm *sm,
+				struct eap_peer_config *config)
+{
+	char *name;
+
+	if (config->password == NULL)
+		return -1;
+
+	name = os_zalloc(config->password_len + 1);
+	if (name == NULL)
+		return -1;
+	os_memcpy(name, config->password, config->password_len);
+
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
+	os_free(name);
+
+	return sm->ext_pw_buf == NULL ? -1 : 0;
+}
+
+
+/**
+ * eap_get_config_password - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+
+	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		if (eap_get_ext_password(sm, config) < 0)
+			return NULL;
+		*len = wpabuf_len(sm->ext_pw_buf);
+		return wpabuf_head(sm->ext_pw_buf);
+	}
+
+	*len = config->password_len;
+	return config->password;
+}
+
+
+/**
+ * eap_get_config_password2 - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * @hash: Buffer for returning whether the password is stored as a
+ * NtPasswordHash instead of plaintext password; can be %NULL if this
+ * information is not needed
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+
+	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		if (eap_get_ext_password(sm, config) < 0)
+			return NULL;
+		*len = wpabuf_len(sm->ext_pw_buf);
+		return wpabuf_head(sm->ext_pw_buf);
+	}
+
+	*len = config->password_len;
+	if (hash)
+		*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
+	return config->password;
+}
+
+
+/**
+ * eap_get_config_new_password - Get new password from network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the new password
+ * Returns: Pointer to the new password or %NULL if not found
+ */
+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->new_password_len;
+	return config->new_password;
+}
+
+
+/**
+ * eap_get_config_otp - Get one-time password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the one-time password
+ * Returns: Pointer to the one-time password or %NULL if not found
+ */
+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->otp_len;
+	return config->otp;
+}
+
+
+/**
+ * eap_clear_config_otp - Clear used one-time password
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function clears a used one-time password (OTP) from the current network
+ * configuration. This should be called when the OTP has been used and is not
+ * needed anymore.
+ */
+void eap_clear_config_otp(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return;
+	os_memset(config->otp, 0, config->otp_len);
+	os_free(config->otp);
+	config->otp = NULL;
+	config->otp_len = 0;
+}
+
+
+/**
+ * eap_get_config_phase1 - Get phase1 data from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the phase1 data or %NULL if not found
+ */
+const char * eap_get_config_phase1(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	return config->phase1;
+}
+
+
+/**
+ * eap_get_config_phase2 - Get phase2 data from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the phase1 data or %NULL if not found
+ */
+const char * eap_get_config_phase2(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	return config->phase2;
+}
+
+
+int eap_get_config_fragment_size(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return -1;
+	return config->fragment_size;
+}
+
+
+/**
+ * eap_key_available - Get key availability (eapKeyAvailable variable)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: 1 if EAP keying material is available, 0 if not
+ */
+int eap_key_available(struct eap_sm *sm)
+{
+	return sm ? sm->eapKeyAvailable : 0;
+}
+
+
+/**
+ * eap_notify_success - Notify EAP state machine about external success trigger
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function is called when external event, e.g., successful completion of
+ * WPA-PSK key handshake, is indicating that EAP state machine should move to
+ * success state. This is mainly used with security modes that do not use EAP
+ * state machine (e.g., WPA-PSK).
+ */
+void eap_notify_success(struct eap_sm *sm)
+{
+	if (sm) {
+		sm->decision = DECISION_COND_SUCC;
+		sm->EAP_state = EAP_SUCCESS;
+	}
+}
+
+
+/**
+ * eap_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Notify EAP state machines that a lower layer has detected a successful
+ * authentication. This is used to recover from dropped EAP-Success messages.
+ */
+void eap_notify_lower_layer_success(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
+	    sm->decision == DECISION_FAIL ||
+	    (sm->methodState != METHOD_MAY_CONT &&
+	     sm->methodState != METHOD_DONE))
+		return;
+
+	if (sm->eapKeyData != NULL)
+		sm->eapKeyAvailable = TRUE;
+	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		"EAP authentication completed successfully (based on lower "
+		"layer success)");
+}
+
+
+/**
+ * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the key
+ * Returns: Pointer to the EAP keying data or %NULL on failure
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
+ * key is available only after a successful authentication. EAP state machine
+ * continues to manage the key data and the caller must not change or free the
+ * returned data.
+ */
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
+{
+	if (sm == NULL || sm->eapKeyData == NULL) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = sm->eapKeyDataLen;
+	return sm->eapKeyData;
+}
+
+
+/**
+ * eap_get_eapKeyData - Get EAP response data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
+ *
+ * Fetch EAP response (eapRespData) from the EAP state machine. This data is
+ * available when EAP state machine has processed an incoming EAP request. The
+ * EAP state machine does not maintain a reference to the response after this
+ * function is called and the caller is responsible for freeing the data.
+ */
+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
+{
+	struct wpabuf *resp;
+
+	if (sm == NULL || sm->eapRespData == NULL)
+		return NULL;
+
+	resp = sm->eapRespData;
+	sm->eapRespData = NULL;
+
+	return resp;
+}
+
+
+/**
+ * eap_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ctx: Context data for smart card operations
+ *
+ * Notify EAP state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
+{
+	if (sm)
+		sm->scard_ctx = ctx;
+}
+
+
+/**
+ * eap_set_config_blob - Set or add a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+/**
+ * eap_get_config_blob - Get a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
+						   const char *name)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
+#else /* CONFIG_NO_CONFIG_BLOBS */
+	return NULL;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+/**
+ * eap_set_force_disabled - Set force_disabled flag
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @disabled: 1 = EAP disabled, 0 = EAP enabled
+ *
+ * This function is used to force EAP state machine to be disabled when it is
+ * not in use (e.g., with WPA-PSK or plaintext connections).
+ */
+void eap_set_force_disabled(struct eap_sm *sm, int disabled)
+{
+	sm->force_disabled = disabled;
+}
+
+
+ /**
+ * eap_notify_pending - Notify that EAP method is ready to re-process a request
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * An EAP method can perform a pending operation (e.g., to get a response from
+ * an external process). Once the response is available, this function can be
+ * used to request EAPOL state machine to retry delivering the previously
+ * received (and still unanswered) EAP request to EAP state machine.
+ */
+void eap_notify_pending(struct eap_sm *sm)
+{
+	sm->eapol_cb->notify_pending(sm->eapol_ctx);
+}
+
+
+/**
+ * eap_invalidate_cached_session - Mark cached session data invalid
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ */
+void eap_invalidate_cached_session(struct eap_sm *sm)
+{
+	if (sm)
+		eap_deinit_prev_method(sm, "invalidate");
+}
+
+
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
+		return 0; /* Not using PBC */
+
+	return 1;
+}
+
+
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
+		return 0; /* Not using PIN */
+
+	return 1;
+}
+
+
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
+{
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = NULL;
+	sm->ext_pw = ext;
+}
+
+
+/**
+ * eap_set_anon_id - Set or add anonymous identity
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
+{
+	if (sm->eapol_cb->set_anon_id)
+		sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,291 +0,0 @@
-/*
- * EAP peer state machine functions (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_H
-#define EAP_H
-
-#include "common/defs.h"
-#include "eap_common/eap_defs.h"
-#include "eap_peer/eap_methods.h"
-
-struct eap_sm;
-struct wpa_config_blob;
-struct wpabuf;
-
-struct eap_method_type {
-	int vendor;
-	u32 method;
-};
-
-#ifdef IEEE8021X_EAPOL
-
-/**
- * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
- *
- * These variables are used in the interface between EAP peer state machine and
- * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
- * expected to maintain these variables and register a callback functions for
- * EAP state machine to get and set the variables.
- */
-enum eapol_bool_var {
-	/**
-	 * EAPOL_eapSuccess - EAP SUCCESS state reached
-	 *
-	 * EAP state machine reads and writes this value.
-	 */
-	EAPOL_eapSuccess,
-
-	/**
-	 * EAPOL_eapRestart - Lower layer request to restart authentication
-	 *
-	 * Set to TRUE in lower layer, FALSE in EAP state machine.
-	 */
-	EAPOL_eapRestart,
-
-	/**
-	 * EAPOL_eapFail - EAP FAILURE state reached
-	 *
-	 * EAP state machine writes this value.
-	 */
-	EAPOL_eapFail,
-
-	/**
-	 * EAPOL_eapResp - Response to send
-	 *
-	 * Set to TRUE in EAP state machine, FALSE in lower layer.
-	 */
-	EAPOL_eapResp,
-
-	/**
-	 * EAPOL_eapNoResp - Request has been process; no response to send
-	 *
-	 * Set to TRUE in EAP state machine, FALSE in lower layer.
-	 */
-	EAPOL_eapNoResp,
-
-	/**
-	 * EAPOL_eapReq - EAP request available from lower layer
-	 *
-	 * Set to TRUE in lower layer, FALSE in EAP state machine.
-	 */
-	EAPOL_eapReq,
-
-	/**
-	 * EAPOL_portEnabled - Lower layer is ready for communication
-	 *
-	 * EAP state machines reads this value.
-	 */
-	EAPOL_portEnabled,
-
-	/**
-	 * EAPOL_altAccept - Alternate indication of success (RFC3748)
-	 *
-	 * EAP state machines reads this value.
-	 */
-	EAPOL_altAccept,
-
-	/**
-	 * EAPOL_altReject - Alternate indication of failure (RFC3748)
-	 *
-	 * EAP state machines reads this value.
-	 */
-	EAPOL_altReject
-};
-
-/**
- * enum eapol_int_var - EAPOL integer state variables for EAP state machine
- *
- * These variables are used in the interface between EAP peer state machine and
- * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
- * expected to maintain these variables and register a callback functions for
- * EAP state machine to get and set the variables.
- */
-enum eapol_int_var {
-	/**
-	 * EAPOL_idleWhile - Outside time for EAP peer timeout
-	 *
-	 * This integer variable is used to provide an outside timer that the
-	 * external (to EAP state machine) code must decrement by one every
-	 * second until the value reaches zero. This is used in the same way as
-	 * EAPOL state machine timers. EAP state machine reads and writes this
-	 * value.
-	 */
-	EAPOL_idleWhile
-};
-
-/**
- * struct eapol_callbacks - Callback functions from EAP to lower layer
- *
- * This structure defines the callback functions that EAP state machine
- * requires from the lower layer (usually EAPOL state machine) for updating
- * state variables and requesting information. eapol_ctx from
- * eap_peer_sm_init() call will be used as the ctx parameter for these
- * callback functions.
- */
-struct eapol_callbacks {
-	/**
-	 * get_config - Get pointer to the current network configuration
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 */
-	struct eap_peer_config * (*get_config)(void *ctx);
-
-	/**
-	 * get_bool - Get a boolean EAPOL state variable
-	 * @variable: EAPOL boolean variable to get
-	 * Returns: Value of the EAPOL variable
-	 */
-	Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
-
-	/**
-	 * set_bool - Set a boolean EAPOL state variable
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @variable: EAPOL boolean variable to set
-	 * @value: Value for the EAPOL variable
-	 */
-	void (*set_bool)(void *ctx, enum eapol_bool_var variable,
-			 Boolean value);
-
-	/**
-	 * get_int - Get an integer EAPOL state variable
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @variable: EAPOL integer variable to get
-	 * Returns: Value of the EAPOL variable
-	 */
-	unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
-
-	/**
-	 * set_int - Set an integer EAPOL state variable
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @variable: EAPOL integer variable to set
-	 * @value: Value for the EAPOL variable
-	 */
-	void (*set_int)(void *ctx, enum eapol_int_var variable,
-			unsigned int value);
-
-	/**
-	 * get_eapReqData - Get EAP-Request data
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @len: Pointer to variable that will be set to eapReqDataLen
-	 * Returns: Reference to eapReqData (EAP state machine will not free
-	 * this) or %NULL if eapReqData not available.
-	 */
-	struct wpabuf * (*get_eapReqData)(void *ctx);
-
-	/**
-	 * set_config_blob - Set named configuration blob
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @blob: New value for the blob
-	 *
-	 * Adds a new configuration blob or replaces the current value of an
-	 * existing blob.
-	 */
-	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
-
-	/**
-	 * get_config_blob - Get a named configuration blob
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @name: Name of the blob
-	 * Returns: Pointer to blob data or %NULL if not found
-	 */
-	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
-							  const char *name);
-
-	/**
-	 * notify_pending - Notify that a pending request can be retried
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 *
-	 * An EAP method can perform a pending operation (e.g., to get a
-	 * response from an external process). Once the response is available,
-	 * this callback function can be used to request EAPOL state machine to
-	 * retry delivering the previously received (and still unanswered) EAP
-	 * request to EAP state machine.
-	 */
-	void (*notify_pending)(void *ctx);
-
-	/**
-	 * eap_param_needed - Notify that EAP parameter is needed
-	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @field: Field name (e.g., "IDENTITY")
-	 * @txt: User readable text describing the required parameter
-	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
-				 const char *txt);
-};
-
-/**
- * struct eap_config - Configuration for EAP state machine
- */
-struct eap_config {
-	/**
-	 * opensc_engine_path - OpenSC engine for OpenSSL engine support
-	 *
-	 * Usually, path to engine_opensc.so.
-	 */
-	const char *opensc_engine_path;
-	/**
-	 * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
-	 *
-	 * Usually, path to engine_pkcs11.so.
-	 */
-	const char *pkcs11_engine_path;
-	/**
-	 * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
-	 *
-	 * Usually, path to opensc-pkcs11.so.
-	 */
-	const char *pkcs11_module_path;
-	/**
-	 * wps - WPS context data
-	 *
-	 * This is only used by EAP-WSC and can be left %NULL if not available.
-	 */
-	struct wps_context *wps;
-};
-
-struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
-				 struct eapol_callbacks *eapol_cb,
-				 void *msg_ctx, struct eap_config *conf);
-void eap_peer_sm_deinit(struct eap_sm *sm);
-int eap_peer_sm_step(struct eap_sm *sm);
-void eap_sm_abort(struct eap_sm *sm);
-int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
-		      int verbose);
-struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
-void eap_sm_request_identity(struct eap_sm *sm);
-void eap_sm_request_password(struct eap_sm *sm);
-void eap_sm_request_new_password(struct eap_sm *sm);
-void eap_sm_request_pin(struct eap_sm *sm);
-void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
-void eap_sm_request_passphrase(struct eap_sm *sm);
-void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
-u32 eap_get_phase2_type(const char *name, int *vendor);
-struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
-					      size_t *count);
-void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
-void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
-void eap_set_force_disabled(struct eap_sm *sm, int disabled);
-int eap_key_available(struct eap_sm *sm);
-void eap_notify_success(struct eap_sm *sm);
-void eap_notify_lower_layer_success(struct eap_sm *sm);
-const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
-struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
-void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
-void eap_invalidate_cached_session(struct eap_sm *sm);
-
-int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
-int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
-
-#endif /* IEEE8021X_EAPOL */
-
-#endif /* EAP_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,323 @@
+/*
+ * EAP peer state machine functions (RFC 4137)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_H
+#define EAP_H
+
+#include "common/defs.h"
+#include "eap_common/eap_defs.h"
+#include "eap_peer/eap_methods.h"
+
+struct eap_sm;
+struct wpa_config_blob;
+struct wpabuf;
+
+struct eap_method_type {
+	int vendor;
+	u32 method;
+};
+
+#ifdef IEEE8021X_EAPOL
+
+/**
+ * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
+enum eapol_bool_var {
+	/**
+	 * EAPOL_eapSuccess - EAP SUCCESS state reached
+	 *
+	 * EAP state machine reads and writes this value.
+	 */
+	EAPOL_eapSuccess,
+
+	/**
+	 * EAPOL_eapRestart - Lower layer request to restart authentication
+	 *
+	 * Set to TRUE in lower layer, FALSE in EAP state machine.
+	 */
+	EAPOL_eapRestart,
+
+	/**
+	 * EAPOL_eapFail - EAP FAILURE state reached
+	 *
+	 * EAP state machine writes this value.
+	 */
+	EAPOL_eapFail,
+
+	/**
+	 * EAPOL_eapResp - Response to send
+	 *
+	 * Set to TRUE in EAP state machine, FALSE in lower layer.
+	 */
+	EAPOL_eapResp,
+
+	/**
+	 * EAPOL_eapNoResp - Request has been process; no response to send
+	 *
+	 * Set to TRUE in EAP state machine, FALSE in lower layer.
+	 */
+	EAPOL_eapNoResp,
+
+	/**
+	 * EAPOL_eapReq - EAP request available from lower layer
+	 *
+	 * Set to TRUE in lower layer, FALSE in EAP state machine.
+	 */
+	EAPOL_eapReq,
+
+	/**
+	 * EAPOL_portEnabled - Lower layer is ready for communication
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_portEnabled,
+
+	/**
+	 * EAPOL_altAccept - Alternate indication of success (RFC3748)
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_altAccept,
+
+	/**
+	 * EAPOL_altReject - Alternate indication of failure (RFC3748)
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_altReject
+};
+
+/**
+ * enum eapol_int_var - EAPOL integer state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
+enum eapol_int_var {
+	/**
+	 * EAPOL_idleWhile - Outside time for EAP peer timeout
+	 *
+	 * This integer variable is used to provide an outside timer that the
+	 * external (to EAP state machine) code must decrement by one every
+	 * second until the value reaches zero. This is used in the same way as
+	 * EAPOL state machine timers. EAP state machine reads and writes this
+	 * value.
+	 */
+	EAPOL_idleWhile
+};
+
+/**
+ * struct eapol_callbacks - Callback functions from EAP to lower layer
+ *
+ * This structure defines the callback functions that EAP state machine
+ * requires from the lower layer (usually EAPOL state machine) for updating
+ * state variables and requesting information. eapol_ctx from
+ * eap_peer_sm_init() call will be used as the ctx parameter for these
+ * callback functions.
+ */
+struct eapol_callbacks {
+	/**
+	 * get_config - Get pointer to the current network configuration
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 */
+	struct eap_peer_config * (*get_config)(void *ctx);
+
+	/**
+	 * get_bool - Get a boolean EAPOL state variable
+	 * @variable: EAPOL boolean variable to get
+	 * Returns: Value of the EAPOL variable
+	 */
+	Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+
+	/**
+	 * set_bool - Set a boolean EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL boolean variable to set
+	 * @value: Value for the EAPOL variable
+	 */
+	void (*set_bool)(void *ctx, enum eapol_bool_var variable,
+			 Boolean value);
+
+	/**
+	 * get_int - Get an integer EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL integer variable to get
+	 * Returns: Value of the EAPOL variable
+	 */
+	unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
+
+	/**
+	 * set_int - Set an integer EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL integer variable to set
+	 * @value: Value for the EAPOL variable
+	 */
+	void (*set_int)(void *ctx, enum eapol_int_var variable,
+			unsigned int value);
+
+	/**
+	 * get_eapReqData - Get EAP-Request data
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @len: Pointer to variable that will be set to eapReqDataLen
+	 * Returns: Reference to eapReqData (EAP state machine will not free
+	 * this) or %NULL if eapReqData not available.
+	 */
+	struct wpabuf * (*get_eapReqData)(void *ctx);
+
+	/**
+	 * set_config_blob - Set named configuration blob
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @blob: New value for the blob
+	 *
+	 * Adds a new configuration blob or replaces the current value of an
+	 * existing blob.
+	 */
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+	/**
+	 * get_config_blob - Get a named configuration blob
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @name: Name of the blob
+	 * Returns: Pointer to blob data or %NULL if not found
+	 */
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+
+	/**
+	 * notify_pending - Notify that a pending request can be retried
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 *
+	 * An EAP method can perform a pending operation (e.g., to get a
+	 * response from an external process). Once the response is available,
+	 * this callback function can be used to request EAPOL state machine to
+	 * retry delivering the previously received (and still unanswered) EAP
+	 * request to EAP state machine.
+	 */
+	void (*notify_pending)(void *ctx);
+
+	/**
+	 * eap_param_needed - Notify that EAP parameter is needed
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
+	 * @txt: User readable text describing the required parameter
+	 */
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
+				 const char *txt);
+
+	/**
+	 * notify_cert - Notification of a peer certificate
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @depth: Depth in certificate chain (0 = server)
+	 * @subject: Subject of the peer certificate
+	 * @cert_hash: SHA-256 hash of the certificate
+	 * @cert: Peer certificate
+	 */
+	void (*notify_cert)(void *ctx, int depth, const char *subject,
+			    const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * notify_status - Notification of the current EAP state
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @status: Step in the process of EAP authentication
+	 * @parameter: Step-specific parameter, e.g., EAP method name
+	 */
+	void (*notify_status)(void *ctx, const char *status,
+			      const char *parameter);
+
+	/**
+	 * set_anon_id - Set or add anonymous identity
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+	 * @len: Length of anonymous identity in octets
+	 */
+	void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+};
+
+/**
+ * struct eap_config - Configuration for EAP state machine
+ */
+struct eap_config {
+	/**
+	 * opensc_engine_path - OpenSC engine for OpenSSL engine support
+	 *
+	 * Usually, path to engine_opensc.so.
+	 */
+	const char *opensc_engine_path;
+	/**
+	 * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
+	 *
+	 * Usually, path to engine_pkcs11.so.
+	 */
+	const char *pkcs11_engine_path;
+	/**
+	 * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
+	 *
+	 * Usually, path to opensc-pkcs11.so.
+	 */
+	const char *pkcs11_module_path;
+	/**
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
+};
+
+struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
+				 struct eapol_callbacks *eapol_cb,
+				 void *msg_ctx, struct eap_config *conf);
+void eap_peer_sm_deinit(struct eap_sm *sm);
+int eap_peer_sm_step(struct eap_sm *sm);
+void eap_sm_abort(struct eap_sm *sm);
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
+		      int verbose);
+const char * eap_sm_get_method_name(struct eap_sm *sm);
+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
+void eap_sm_request_identity(struct eap_sm *sm);
+void eap_sm_request_password(struct eap_sm *sm);
+void eap_sm_request_new_password(struct eap_sm *sm);
+void eap_sm_request_pin(struct eap_sm *sm);
+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
+void eap_sm_request_passphrase(struct eap_sm *sm);
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
+u32 eap_get_phase2_type(const char *name, int *vendor);
+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
+					      size_t *count);
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
+void eap_set_force_disabled(struct eap_sm *sm, int disabled);
+int eap_key_available(struct eap_sm *sm);
+void eap_notify_success(struct eap_sm *sm);
+void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
+void eap_invalidate_cached_session(struct eap_sm *sm);
+
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
+
+struct ext_password_data;
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* EAP_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_aka.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_aka.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_aka.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1389 +0,0 @@
-/*
- * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "pcsc_funcs.h"
-#include "crypto/crypto.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/milenage.h"
-#include "eap_common/eap_sim_common.h"
-#include "eap_config.h"
-#include "eap_i.h"
-
-
-struct eap_aka_data {
-	u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
-	size_t res_len;
-	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
-	u8 mk[EAP_SIM_MK_LEN];
-	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
-	u8 k_encr[EAP_SIM_K_ENCR_LEN];
-	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
-	u8 msk[EAP_SIM_KEYING_DATA_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
-	u8 auts[EAP_AKA_AUTS_LEN];
-
-	int num_id_req, num_notification;
-	u8 *pseudonym;
-	size_t pseudonym_len;
-	u8 *reauth_id;
-	size_t reauth_id_len;
-	int reauth;
-	unsigned int counter, counter_too_small;
-	u8 *last_eap_identity;
-	size_t last_eap_identity_len;
-	enum {
-		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
-	} state;
-
-	struct wpabuf *id_msgs;
-	int prev_id;
-	int result_ind, use_result_ind;
-	u8 eap_method;
-	u8 *network_name;
-	size_t network_name_len;
-	u16 kdf;
-	int kdf_negotiation;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char * eap_aka_state_txt(int state)
-{
-	switch (state) {
-	case CONTINUE:
-		return "CONTINUE";
-	case RESULT_SUCCESS:
-		return "RESULT_SUCCESS";
-	case RESULT_FAILURE:
-		return "RESULT_FAILURE";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void eap_aka_state(struct eap_aka_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
-		   eap_aka_state_txt(data->state),
-		   eap_aka_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_aka_init(struct eap_sm *sm)
-{
-	struct eap_aka_data *data;
-	const char *phase1 = eap_get_config_phase1(sm);
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	data->eap_method = EAP_TYPE_AKA;
-
-	eap_aka_state(data, CONTINUE);
-	data->prev_id = -1;
-
-	data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
-
-	return data;
-}
-
-
-#ifdef EAP_AKA_PRIME
-static void * eap_aka_prime_init(struct eap_sm *sm)
-{
-	struct eap_aka_data *data = eap_aka_init(sm);
-	if (data == NULL)
-		return NULL;
-	data->eap_method = EAP_TYPE_AKA_PRIME;
-	return data;
-}
-#endif /* EAP_AKA_PRIME */
-
-
-static void eap_aka_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	if (data) {
-		os_free(data->pseudonym);
-		os_free(data->reauth_id);
-		os_free(data->last_eap_identity);
-		wpabuf_free(data->id_msgs);
-		os_free(data->network_name);
-		os_free(data);
-	}
-}
-
-
-static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
-{
-	struct eap_peer_config *conf;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
-
-	conf = eap_get_config(sm);
-	if (conf == NULL)
-		return -1;
-	if (conf->pcsc) {
-		return scard_umts_auth(sm->scard_ctx, data->rand,
-				       data->autn, data->res, &data->res_len,
-				       data->ik, data->ck, data->auts);
-	}
-
-#ifdef CONFIG_USIM_SIMULATOR
-	if (conf->password) {
-		u8 opc[16], k[16], sqn[6];
-		const char *pos;
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
-			   "implementation for UMTS authentication");
-		if (conf->password_len < 78) {
-			wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
-				   "password");
-			return -1;
-		}
-		pos = (const char *) conf->password;
-		if (hexstr2bin(pos, k, 16))
-			return -1;
-		pos += 32;
-		if (*pos != ':')
-			return -1;
-		pos++;
-
-		if (hexstr2bin(pos, opc, 16))
-			return -1;
-		pos += 32;
-		if (*pos != ':')
-			return -1;
-		pos++;
-
-		if (hexstr2bin(pos, sqn, 6))
-			return -1;
-
-		return milenage_check(opc, k, sqn, data->rand, data->autn,
-				      data->ik, data->ck,
-				      data->res, &data->res_len, data->auts);
-	}
-#endif /* CONFIG_USIM_SIMULATOR */
-
-#ifdef CONFIG_USIM_HARDCODED
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
-		   "testing");
-
-	/* These hardcoded Kc and SRES values are used for testing.
-	 * Could consider making them configurable. */
-	os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
-	data->res_len = EAP_AKA_RES_MAX_LEN;
-	os_memset(data->ik, '3', EAP_AKA_IK_LEN);
-	os_memset(data->ck, '4', EAP_AKA_CK_LEN);
-	{
-		u8 autn[EAP_AKA_AUTN_LEN];
-		os_memset(autn, '1', EAP_AKA_AUTN_LEN);
-		if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
-			wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
-				   "with expected value");
-			return -1;
-		}
-	}
-#if 0
-	{
-		static int test_resync = 1;
-		if (test_resync) {
-			/* Test Resynchronization */
-			test_resync = 0;
-			return -2;
-		}
-	}
-#endif
-	return 0;
-
-#else /* CONFIG_USIM_HARDCODED */
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
-		   "enabled");
-	return -1;
-
-#endif /* CONFIG_USIM_HARDCODED */
-}
-
-
-#define CLEAR_PSEUDONYM	0x01
-#define CLEAR_REAUTH_ID	0x02
-#define CLEAR_EAP_ID	0x04
-
-static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
-	if (id & CLEAR_PSEUDONYM) {
-		os_free(data->pseudonym);
-		data->pseudonym = NULL;
-		data->pseudonym_len = 0;
-	}
-	if (id & CLEAR_REAUTH_ID) {
-		os_free(data->reauth_id);
-		data->reauth_id = NULL;
-		data->reauth_id_len = 0;
-	}
-	if (id & CLEAR_EAP_ID) {
-		os_free(data->last_eap_identity);
-		data->last_eap_identity = NULL;
-		data->last_eap_identity_len = 0;
-	}
-}
-
-
-static int eap_aka_learn_ids(struct eap_aka_data *data,
-			     struct eap_sim_attrs *attr)
-{
-	if (attr->next_pseudonym) {
-		os_free(data->pseudonym);
-		data->pseudonym = os_malloc(attr->next_pseudonym_len);
-		if (data->pseudonym == NULL) {
-			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
-				   "next pseudonym");
-			return -1;
-		}
-		os_memcpy(data->pseudonym, attr->next_pseudonym,
-			  attr->next_pseudonym_len);
-		data->pseudonym_len = attr->next_pseudonym_len;
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
-				  data->pseudonym,
-				  data->pseudonym_len);
-	}
-
-	if (attr->next_reauth_id) {
-		os_free(data->reauth_id);
-		data->reauth_id = os_malloc(attr->next_reauth_id_len);
-		if (data->reauth_id == NULL) {
-			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
-				   "next reauth_id");
-			return -1;
-		}
-		os_memcpy(data->reauth_id, attr->next_reauth_id,
-			  attr->next_reauth_id_len);
-		data->reauth_id_len = attr->next_reauth_id_len;
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
-				  data->reauth_id,
-				  data->reauth_id_len);
-	}
-
-	return 0;
-}
-
-
-static int eap_aka_add_id_msg(struct eap_aka_data *data,
-			      const struct wpabuf *msg)
-{
-	if (msg == NULL)
-		return -1;
-
-	if (data->id_msgs == NULL) {
-		data->id_msgs = wpabuf_dup(msg);
-		return data->id_msgs == NULL ? -1 : 0;
-	}
-
-	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
-		return -1;
-	wpabuf_put_buf(data->id_msgs, msg);
-
-	return 0;
-}
-
-
-static void eap_aka_add_checkcode(struct eap_aka_data *data,
-				  struct eap_sim_msg *msg)
-{
-	const u8 *addr;
-	size_t len;
-	u8 hash[SHA256_MAC_LEN];
-
-	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
-
-	if (data->id_msgs == NULL) {
-		/*
-		 * No EAP-AKA/Identity packets were exchanged - send empty
-		 * checkcode.
-		 */
-		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
-		return;
-	}
-
-	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
-	addr = wpabuf_head(data->id_msgs);
-	len = wpabuf_len(data->id_msgs);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
-#ifdef EAP_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		sha256_vector(1, &addr, &len, hash);
-	else
-#endif /* EAP_AKA_PRIME */
-		sha1_vector(1, &addr, &len, hash);
-
-	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
-			data->eap_method == EAP_TYPE_AKA_PRIME ?
-			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
-}
-
-
-static int eap_aka_verify_checkcode(struct eap_aka_data *data,
-				    const u8 *checkcode, size_t checkcode_len)
-{
-	const u8 *addr;
-	size_t len;
-	u8 hash[SHA256_MAC_LEN];
-	size_t hash_len;
-
-	if (checkcode == NULL)
-		return -1;
-
-	if (data->id_msgs == NULL) {
-		if (checkcode_len != 0) {
-			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
-				   "indicates that AKA/Identity messages were "
-				   "used, but they were not");
-			return -1;
-		}
-		return 0;
-	}
-
-	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
-		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
-
-	if (checkcode_len != hash_len) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
-			   "indicates that AKA/Identity message were not "
-			   "used, but they were");
-		return -1;
-	}
-
-	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
-	addr = wpabuf_head(data->id_msgs);
-	len = wpabuf_len(data->id_msgs);
-#ifdef EAP_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		sha256_vector(1, &addr, &len, hash);
-	else
-#endif /* EAP_AKA_PRIME */
-		sha1_vector(1, &addr, &len, hash);
-
-	if (os_memcmp(hash, checkcode, hash_len) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
-					    int err)
-{
-	struct eap_sim_msg *msg;
-
-	eap_aka_state(data, FAILURE);
-	data->num_id_req = 0;
-	data->num_notification = 0;
-
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_CLIENT_ERROR);
-	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
-						     u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	eap_aka_state(data, FAILURE);
-	data->num_id_req = 0;
-	data->num_notification = 0;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
-		   "(id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_synchronization_failure(
-	struct eap_aka_data *data, u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	data->num_id_req = 0;
-	data->num_notification = 0;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
-		   "(id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
-	wpa_printf(MSG_DEBUG, "   AT_AUTS");
-	eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
-			     EAP_AKA_AUTS_LEN);
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
-						 struct eap_aka_data *data,
-						 u8 id,
-						 enum eap_sim_id_req id_req)
-{
-	const u8 *identity = NULL;
-	size_t identity_len = 0;
-	struct eap_sim_msg *msg;
-
-	data->reauth = 0;
-	if (id_req == ANY_ID && data->reauth_id) {
-		identity = data->reauth_id;
-		identity_len = data->reauth_id_len;
-		data->reauth = 1;
-	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
-		   data->pseudonym) {
-		identity = data->pseudonym;
-		identity_len = data->pseudonym_len;
-		eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
-	} else if (id_req != NO_ID_REQ) {
-		identity = eap_get_config_identity(sm, &identity_len);
-		if (identity) {
-			eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
-						 CLEAR_REAUTH_ID);
-		}
-	}
-	if (id_req != NO_ID_REQ)
-		eap_aka_clear_identities(data, CLEAR_EAP_ID);
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_IDENTITY);
-
-	if (identity) {
-		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
-				  identity, identity_len);
-		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
-				identity, identity_len);
-	}
-
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
-						  u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_CHALLENGE);
-	wpa_printf(MSG_DEBUG, "   AT_RES");
-	eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
-			data->res, data->res_len);
-	eap_aka_add_checkcode(data, msg);
-	if (data->use_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
-}
-
-
-static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
-					       u8 id, int counter_too_small,
-					       const u8 *nonce_s)
-{
-	struct eap_sim_msg *msg;
-	unsigned int counter;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
-		   id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
-	wpa_printf(MSG_DEBUG, "   AT_IV");
-	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
-
-	if (counter_too_small) {
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
-		counter = data->counter_too_small;
-	} else
-		counter = data->counter;
-
-	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
-	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
-
-	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
-			   "AT_ENCR_DATA");
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-	eap_aka_add_checkcode(data, msg);
-	if (data->use_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
-				  EAP_SIM_NONCE_S_LEN);
-}
-
-
-static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
-						     u8 id, u16 notification)
-{
-	struct eap_sim_msg *msg;
-	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_NOTIFICATION);
-	if (k_aut && data->reauth) {
-		wpa_printf(MSG_DEBUG, "   AT_IV");
-		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
-					   EAP_SIM_AT_ENCR_DATA);
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
-				NULL, 0);
-		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
-					     EAP_SIM_AT_PADDING)) {
-			wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
-				   "AT_ENCR_DATA");
-			eap_sim_msg_free(msg);
-			return NULL;
-		}
-	}
-	if (k_aut) {
-		wpa_printf(MSG_DEBUG, "   AT_MAC");
-		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	}
-	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
-}
-
-
-static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
-						struct eap_aka_data *data,
-						u8 id,
-						const struct wpabuf *reqData,
-						struct eap_sim_attrs *attr)
-{
-	int id_error;
-	struct wpabuf *buf;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
-
-	id_error = 0;
-	switch (attr->id_req) {
-	case NO_ID_REQ:
-		break;
-	case ANY_ID:
-		if (data->num_id_req > 0)
-			id_error++;
-		data->num_id_req++;
-		break;
-	case FULLAUTH_ID:
-		if (data->num_id_req > 1)
-			id_error++;
-		data->num_id_req++;
-		break;
-	case PERMANENT_ID:
-		if (data->num_id_req > 2)
-			id_error++;
-		data->num_id_req++;
-		break;
-	}
-	if (id_error) {
-		wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
-			   "used within one authentication");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	buf = eap_aka_response_identity(sm, data, id, attr->id_req);
-
-	if (data->prev_id != id) {
-		eap_aka_add_id_msg(data, reqData);
-		eap_aka_add_id_msg(data, buf);
-		data->prev_id = id;
-	}
-
-	return buf;
-}
-
-
-static int eap_aka_verify_mac(struct eap_aka_data *data,
-			      const struct wpabuf *req,
-			      const u8 *mac, const u8 *extra,
-			      size_t extra_len)
-{
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
-						 extra_len);
-	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
-}
-
-
-#ifdef EAP_AKA_PRIME
-static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
-						u8 id, u16 kdf)
-{
-	struct eap_sim_msg *msg;
-
-	data->kdf_negotiation = 1;
-	data->kdf = kdf;
-	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
-		   "select)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_CHALLENGE);
-	wpa_printf(MSG_DEBUG, "   AT_KDF");
-	eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
-					     u8 id, struct eap_sim_attrs *attr)
-{
-	size_t i;
-
-	for (i = 0; i < attr->kdf_count; i++) {
-		if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
-			return eap_aka_prime_kdf_select(data, id,
-							EAP_AKA_PRIME_KDF);
-	}
-
-	/* No matching KDF found - fail authentication as if AUTN had been
-	 * incorrect */
-	return eap_aka_authentication_reject(data, id);
-}
-
-
-static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
-				   struct eap_sim_attrs *attr)
-{
-	size_t i, j;
-
-	if (attr->kdf_count == 0)
-		return 0;
-
-	/* The only allowed (and required) duplication of a KDF is the addition
-	 * of the selected KDF into the beginning of the list. */
-
-	if (data->kdf_negotiation) {
-		if (attr->kdf[0] != data->kdf) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
-				   "accept the selected KDF");
-			return 0;
-		}
-
-		for (i = 1; i < attr->kdf_count; i++) {
-			if (attr->kdf[i] == data->kdf)
-				break;
-		}
-		if (i == attr->kdf_count &&
-		    attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
-				   "duplicate the selected KDF");
-			return 0;
-		}
-
-		/* TODO: should check that the list is identical to the one
-		 * used in the previous Challenge message apart from the added
-		 * entry in the beginning. */
-	}
-
-	for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
-		for (j = i + 1; j < attr->kdf_count; j++) {
-			if (attr->kdf[i] == attr->kdf[j]) {
-				wpa_printf(MSG_WARNING, "EAP-AKA': The server "
-					   "included a duplicated KDF");
-				return 0;
-			}
-		}
-	}
-
-	return 1;
-}
-#endif /* EAP_AKA_PRIME */
-
-
-static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
-						 struct eap_aka_data *data,
-						 u8 id,
-						 const struct wpabuf *reqData,
-						 struct eap_sim_attrs *attr)
-{
-	const u8 *identity;
-	size_t identity_len;
-	int res;
-	struct eap_sim_attrs eattr;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
-
-	if (attr->checkcode &&
-	    eap_aka_verify_checkcode(data, attr->checkcode,
-				     attr->checkcode_len)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
-			   "message");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-#ifdef EAP_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		if (!attr->kdf_input || attr->kdf_input_len == 0) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
-				   "did not include non-empty AT_KDF_INPUT");
-			/* Fail authentication as if AUTN had been incorrect */
-			return eap_aka_authentication_reject(data, id);
-		}
-		os_free(data->network_name);
-		data->network_name = os_malloc(attr->kdf_input_len);
-		if (data->network_name == NULL) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
-				   "storing Network Name");
-			return eap_aka_authentication_reject(data, id);
-		}
-		os_memcpy(data->network_name, attr->kdf_input,
-			  attr->kdf_input_len);
-		data->network_name_len = attr->kdf_input_len;
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
-				  "(AT_KDF_INPUT)",
-				  data->network_name, data->network_name_len);
-		/* TODO: check Network Name per 3GPP.33.402 */
-
-		if (!eap_aka_prime_kdf_valid(data, attr))
-			return eap_aka_authentication_reject(data, id);
-
-		if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
-			return eap_aka_prime_kdf_neg(data, id, attr);
-
-		data->kdf = EAP_AKA_PRIME_KDF;
-		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
-	}
-
-	if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
-		u16 flags = WPA_GET_BE16(attr->bidding);
-		if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
-		    eap_allowed_method(sm, EAP_VENDOR_IETF,
-				       EAP_TYPE_AKA_PRIME)) {
-			wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
-				   "AKA' to AKA detected");
-			/* Fail authentication as if AUTN had been incorrect */
-			return eap_aka_authentication_reject(data, id);
-		}
-	}
-#endif /* EAP_AKA_PRIME */
-
-	data->reauth = 0;
-	if (!attr->mac || !attr->rand || !attr->autn) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
-			   "did not include%s%s%s",
-			   !attr->mac ? " AT_MAC" : "",
-			   !attr->rand ? " AT_RAND" : "",
-			   !attr->autn ? " AT_AUTN" : "");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-	os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
-	os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
-
-	res = eap_aka_umts_auth(sm, data);
-	if (res == -1) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
-			   "failed (AUTN)");
-		return eap_aka_authentication_reject(data, id);
-	} else if (res == -2) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
-			   "failed (AUTN seq# -> AUTS)");
-		return eap_aka_synchronization_failure(data, id);
-	} else if (res) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-#ifdef EAP_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
-		 * needed 6-octet SQN ^ AK for CK',IK' derivation */
-		u16 amf = WPA_GET_BE16(data->autn + 6);
-		if (!(amf & 0x8000)) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
-				   "not set (AMF=0x%4x)", amf);
-			return eap_aka_authentication_reject(data, id);
-		}
-		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
-						 data->autn,
-						 data->network_name,
-						 data->network_name_len);
-	}
-#endif /* EAP_AKA_PRIME */
-	if (data->last_eap_identity) {
-		identity = data->last_eap_identity;
-		identity_len = data->last_eap_identity_len;
-	} else if (data->pseudonym) {
-		identity = data->pseudonym;
-		identity_len = data->pseudonym_len;
-	} else
-		identity = eap_get_config_identity(sm, &identity_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
-			  "derivation", identity, identity_len);
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
-					  data->ck, data->k_encr, data->k_aut,
-					  data->k_re, data->msk, data->emsk);
-	} else {
-		eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
-				  data->mk);
-		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
-				    data->msk, data->emsk);
-	}
-	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
-			   "used invalid AT_MAC");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
-
-	if (attr->encr_data) {
-		u8 *decrypted;
-		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-					       attr->encr_data_len, attr->iv,
-					       &eattr, 0);
-		if (decrypted == NULL) {
-			return eap_aka_client_error(
-				data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-		}
-		eap_aka_learn_ids(data, &eattr);
-		os_free(decrypted);
-	}
-
-	if (data->result_ind && attr->result_ind)
-		data->use_result_ind = 1;
-
-	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
-		eap_aka_state(data, data->use_result_ind ?
-			      RESULT_SUCCESS : SUCCESS);
-	}
-
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	/* RFC 4187 specifies that counter is initialized to one after
-	 * fullauth, but initializing it to zero makes it easier to implement
-	 * reauth verification. */
-	data->counter = 0;
-	return eap_aka_response_challenge(data, id);
-}
-
-
-static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
-					       struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted;
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
-			   "reauth did not include encrypted data");
-		return -1;
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
-			   "data from notification message");
-		return -1;
-	}
-
-	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
-			   "message does not match with counter in reauth "
-			   "message");
-		os_free(decrypted);
-		return -1;
-	}
-
-	os_free(decrypted);
-	return 0;
-}
-
-
-static int eap_aka_process_notification_auth(struct eap_aka_data *data,
-					     const struct wpabuf *reqData,
-					     struct eap_sim_attrs *attr)
-{
-	if (attr->mac == NULL) {
-		wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
-			   "Notification message");
-		return -1;
-	}
-
-	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
-			   "used invalid AT_MAC");
-		return -1;
-	}
-
-	if (data->reauth &&
-	    eap_aka_process_notification_reauth(data, attr)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
-			   "message after reauth");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_aka_process_notification(
-	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
-	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
-	if (data->num_notification > 0) {
-		wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
-			   "rounds (only one allowed)");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-	data->num_notification++;
-	if (attr->notification == -1) {
-		wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
-			   "Notification message");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if ((attr->notification & 0x4000) == 0 &&
-	    eap_aka_process_notification_auth(data, reqData, attr)) {
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
-	if (attr->notification >= 0 && attr->notification < 32768) {
-		eap_aka_state(data, FAILURE);
-	} else if (attr->notification == EAP_SIM_SUCCESS &&
-		   data->state == RESULT_SUCCESS)
-		eap_aka_state(data, SUCCESS);
-	return eap_aka_response_notification(data, id, attr->notification);
-}
-
-
-static struct wpabuf * eap_aka_process_reauthentication(
-	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
-	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
-
-	if (attr->checkcode &&
-	    eap_aka_verify_checkcode(data, attr->checkcode,
-				     attr->checkcode_len)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
-			   "message");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (data->reauth_id == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
-			   "reauthentication, but no reauth_id available");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	data->reauth = 1;
-	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
-			   "did not have valid AT_MAC");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
-			   "message did not include encrypted data");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
-			   "data from reauthentication message");
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (eattr.nonce_s == NULL || eattr.counter < 0) {
-		wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
-			   !eattr.nonce_s ? " AT_NONCE_S" : "",
-			   eattr.counter < 0 ? " AT_COUNTER" : "");
-		os_free(decrypted);
-		return eap_aka_client_error(data, id,
-					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
-		struct wpabuf *res;
-		wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
-			   "(%d <= %d)", eattr.counter, data->counter);
-		data->counter_too_small = eattr.counter;
-
-		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
-		 * reauth_id must not be used to start a new reauthentication.
-		 * However, since it was used in the last EAP-Response-Identity
-		 * packet, it has to saved for the following fullauth to be
-		 * used in MK derivation. */
-		os_free(data->last_eap_identity);
-		data->last_eap_identity = data->reauth_id;
-		data->last_eap_identity_len = data->reauth_id_len;
-		data->reauth_id = NULL;
-		data->reauth_id_len = 0;
-
-		res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
-		os_free(decrypted);
-
-		return res;
-	}
-	data->counter = eattr.counter;
-
-	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
-		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
-
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
-						 data->reauth_id,
-						 data->reauth_id_len,
-						 data->nonce_s,
-						 data->msk, data->emsk);
-	} else {
-		eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
-					   data->reauth_id_len,
-					   data->nonce_s, data->mk,
-					   data->msk, data->emsk);
-	}
-	eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
-	eap_aka_learn_ids(data, &eattr);
-
-	if (data->result_ind && attr->result_ind)
-		data->use_result_ind = 1;
-
-	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
-		eap_aka_state(data, data->use_result_ind ?
-			      RESULT_SUCCESS : SUCCESS);
-	}
-
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
-			   "fast reauths performed - force fullauth");
-		eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
-	}
-	os_free(decrypted);
-	return eap_aka_response_reauth(data, id, 0, data->nonce_s);
-}
-
-
-static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_aka_data *data = priv;
-	const struct eap_hdr *req;
-	u8 subtype, id;
-	struct wpabuf *res;
-	const u8 *pos;
-	struct eap_sim_attrs attr;
-	size_t len;
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
-	if (eap_get_config_identity(sm, &len) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
-		eap_sm_request_identity(sm);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
-			       &len);
-	if (pos == NULL || len < 1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	req = wpabuf_head(reqData);
-	id = req->identifier;
-	len = be_to_host16(req->length);
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	subtype = *pos++;
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
-	pos += 2; /* Reserved */
-
-	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
-			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
-			       0)) {
-		res = eap_aka_client_error(data, id,
-					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-		goto done;
-	}
-
-	switch (subtype) {
-	case EAP_AKA_SUBTYPE_IDENTITY:
-		res = eap_aka_process_identity(sm, data, id, reqData, &attr);
-		break;
-	case EAP_AKA_SUBTYPE_CHALLENGE:
-		res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
-		break;
-	case EAP_AKA_SUBTYPE_NOTIFICATION:
-		res = eap_aka_process_notification(sm, data, id, reqData,
-						   &attr);
-		break;
-	case EAP_AKA_SUBTYPE_REAUTHENTICATION:
-		res = eap_aka_process_reauthentication(sm, data, id, reqData,
-						       &attr);
-		break;
-	case EAP_AKA_SUBTYPE_CLIENT_ERROR:
-		wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
-		res = eap_aka_client_error(data, id,
-					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
-		res = eap_aka_client_error(data, id,
-					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
-		break;
-	}
-
-done:
-	if (data->state == FAILURE) {
-		ret->decision = DECISION_FAIL;
-		ret->methodState = METHOD_DONE;
-	} else if (data->state == SUCCESS) {
-		ret->decision = data->use_result_ind ?
-			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
-		/*
-		 * It is possible for the server to reply with AKA
-		 * Notification, so we must allow the method to continue and
-		 * not only accept EAP-Success at this point.
-		 */
-		ret->methodState = data->use_result_ind ?
-			METHOD_DONE : METHOD_MAY_CONT;
-	} else if (data->state == RESULT_FAILURE)
-		ret->methodState = METHOD_CONT;
-	else if (data->state == RESULT_SUCCESS)
-		ret->methodState = METHOD_CONT;
-
-	if (ret->methodState == METHOD_DONE) {
-		ret->allowNotifications = FALSE;
-	}
-
-	return res;
-}
-
-
-static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	return data->pseudonym || data->reauth_id;
-}
-
-
-static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	eap_aka_clear_identities(data, CLEAR_EAP_ID);
-	data->prev_id = -1;
-	wpabuf_free(data->id_msgs);
-	data->id_msgs = NULL;
-	data->use_result_ind = 0;
-	data->kdf_negotiation = 0;
-}
-
-
-static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	eap_aka_state(data, CONTINUE);
-	return priv;
-}
-
-
-static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
-				       size_t *len)
-{
-	struct eap_aka_data *data = priv;
-
-	if (data->reauth_id) {
-		*len = data->reauth_id_len;
-		return data->reauth_id;
-	}
-
-	if (data->pseudonym) {
-		*len = data->pseudonym_len;
-		return data->pseudonym;
-	}
-
-	return NULL;
-}
-
-
-static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_aka_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_SIM_KEYING_DATA_LEN;
-	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
-
-	return key;
-}
-
-
-static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_aka_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_EMSK_LEN;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_aka_init;
-	eap->deinit = eap_aka_deinit;
-	eap->process = eap_aka_process;
-	eap->isKeyAvailable = eap_aka_isKeyAvailable;
-	eap->getKey = eap_aka_getKey;
-	eap->has_reauth_data = eap_aka_has_reauth_data;
-	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
-	eap->init_for_reauth = eap_aka_init_for_reauth;
-	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;
-}
-
-
-#ifdef EAP_AKA_PRIME
-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,
-				    "AKA'");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_aka_prime_init;
-	eap->deinit = eap_aka_deinit;
-	eap->process = eap_aka_process;
-	eap->isKeyAvailable = eap_aka_isKeyAvailable;
-	eap->getKey = eap_aka_getKey;
-	eap->has_reauth_data = eap_aka_has_reauth_data;
-	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
-	eap->init_for_reauth = eap_aka_init_for_reauth;
-	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;
-}
-#endif /* EAP_AKA_PRIME */

Copied: vendor/wpa/2.0/src/eap_peer/eap_aka.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_aka.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_aka.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_aka.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1419 @@
+/*
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "pcsc_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/milenage.h"
+#include "eap_common/eap_sim_common.h"
+#include "eap_config.h"
+#include "eap_i.h"
+
+
+struct eap_aka_data {
+	u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
+	u8 mk[EAP_SIM_MK_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
+	u8 msk[EAP_SIM_KEYING_DATA_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
+	u8 auts[EAP_AKA_AUTS_LEN];
+
+	int num_id_req, num_notification;
+	u8 *pseudonym;
+	size_t pseudonym_len;
+	u8 *reauth_id;
+	size_t reauth_id_len;
+	int reauth;
+	unsigned int counter, counter_too_small;
+	u8 *last_eap_identity;
+	size_t last_eap_identity_len;
+	enum {
+		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+	} state;
+
+	struct wpabuf *id_msgs;
+	int prev_id;
+	int result_ind, use_result_ind;
+	u8 eap_method;
+	u8 *network_name;
+	size_t network_name_len;
+	u16 kdf;
+	int kdf_negotiation;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_aka_state_txt(int state)
+{
+	switch (state) {
+	case CONTINUE:
+		return "CONTINUE";
+	case RESULT_SUCCESS:
+		return "RESULT_SUCCESS";
+	case RESULT_FAILURE:
+		return "RESULT_FAILURE";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_aka_state(struct eap_aka_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
+		   eap_aka_state_txt(data->state),
+		   eap_aka_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_aka_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data;
+	const char *phase1 = eap_get_config_phase1(sm);
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->eap_method = EAP_TYPE_AKA;
+
+	eap_aka_state(data, CONTINUE);
+	data->prev_id = -1;
+
+	data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
+
+	if (config && config->anonymous_identity) {
+		data->pseudonym = os_malloc(config->anonymous_identity_len);
+		if (data->pseudonym) {
+			os_memcpy(data->pseudonym, config->anonymous_identity,
+				  config->anonymous_identity_len);
+			data->pseudonym_len = config->anonymous_identity_len;
+		}
+	}
+
+	return data;
+}
+
+
+#ifdef EAP_AKA_PRIME
+static void * eap_aka_prime_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data = eap_aka_init(sm);
+	if (data == NULL)
+		return NULL;
+	data->eap_method = EAP_TYPE_AKA_PRIME;
+	return data;
+}
+#endif /* EAP_AKA_PRIME */
+
+
+static void eap_aka_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	if (data) {
+		os_free(data->pseudonym);
+		os_free(data->reauth_id);
+		os_free(data->last_eap_identity);
+		wpabuf_free(data->id_msgs);
+		os_free(data->network_name);
+		os_free(data);
+	}
+}
+
+
+static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
+{
+	struct eap_peer_config *conf;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm");
+
+	conf = eap_get_config(sm);
+	if (conf == NULL)
+		return -1;
+	if (conf->pcsc) {
+		return scard_umts_auth(sm->scard_ctx, data->rand,
+				       data->autn, data->res, &data->res_len,
+				       data->ik, data->ck, data->auts);
+	}
+
+#ifdef CONFIG_USIM_SIMULATOR
+	if (conf->password) {
+		u8 opc[16], k[16], sqn[6];
+		const char *pos;
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage "
+			   "implementation for UMTS authentication");
+		if (conf->password_len < 78) {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage "
+				   "password");
+			return -1;
+		}
+		pos = (const char *) conf->password;
+		if (hexstr2bin(pos, k, 16))
+			return -1;
+		pos += 32;
+		if (*pos != ':')
+			return -1;
+		pos++;
+
+		if (hexstr2bin(pos, opc, 16))
+			return -1;
+		pos += 32;
+		if (*pos != ':')
+			return -1;
+		pos++;
+
+		if (hexstr2bin(pos, sqn, 6))
+			return -1;
+
+		return milenage_check(opc, k, sqn, data->rand, data->autn,
+				      data->ik, data->ck,
+				      data->res, &data->res_len, data->auts);
+	}
+#endif /* CONFIG_USIM_SIMULATOR */
+
+#ifdef CONFIG_USIM_HARDCODED
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for "
+		   "testing");
+
+	/* These hardcoded Kc and SRES values are used for testing.
+	 * Could consider making them configurable. */
+	os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
+	data->res_len = EAP_AKA_RES_MAX_LEN;
+	os_memset(data->ik, '3', EAP_AKA_IK_LEN);
+	os_memset(data->ck, '4', EAP_AKA_CK_LEN);
+	{
+		u8 autn[EAP_AKA_AUTN_LEN];
+		os_memset(autn, '1', EAP_AKA_AUTN_LEN);
+		if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
+			wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
+				   "with expected value");
+			return -1;
+		}
+	}
+#if 0
+	{
+		static int test_resync = 1;
+		if (test_resync) {
+			/* Test Resynchronization */
+			test_resync = 0;
+			return -2;
+		}
+	}
+#endif
+	return 0;
+
+#else /* CONFIG_USIM_HARDCODED */
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith "
+		   "enabled");
+	return -1;
+
+#endif /* CONFIG_USIM_HARDCODED */
+}
+
+
+#define CLEAR_PSEUDONYM	0x01
+#define CLEAR_REAUTH_ID	0x02
+#define CLEAR_EAP_ID	0x04
+
+static void eap_aka_clear_identities(struct eap_sm *sm,
+				     struct eap_aka_data *data, int id)
+{
+	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
+		os_free(data->pseudonym);
+		data->pseudonym = NULL;
+		data->pseudonym_len = 0;
+		eap_set_anon_id(sm, NULL, 0);
+	}
+	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
+		os_free(data->reauth_id);
+		data->reauth_id = NULL;
+		data->reauth_id_len = 0;
+	}
+	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
+		os_free(data->last_eap_identity);
+		data->last_eap_identity = NULL;
+		data->last_eap_identity_len = 0;
+	}
+}
+
+
+static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
+			     struct eap_sim_attrs *attr)
+{
+	if (attr->next_pseudonym) {
+		const u8 *identity = NULL;
+		size_t identity_len = 0;
+		const u8 *realm = NULL;
+		size_t realm_len = 0;
+
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
+				  attr->next_pseudonym,
+				  attr->next_pseudonym_len);
+		os_free(data->pseudonym);
+		/* Look for the realm of the permanent identity */
+		identity = eap_get_config_identity(sm, &identity_len);
+		if (identity) {
+			for (realm = identity, realm_len = identity_len;
+			     realm_len > 0; realm_len--, realm++) {
+				if (*realm == '@')
+					break;
+			}
+		}
+		data->pseudonym = os_malloc(attr->next_pseudonym_len +
+					    realm_len);
+		if (data->pseudonym == NULL) {
+			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
+				   "next pseudonym");
+			data->pseudonym_len = 0;
+			return -1;
+		}
+		os_memcpy(data->pseudonym, attr->next_pseudonym,
+			  attr->next_pseudonym_len);
+		if (realm_len) {
+			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
+				  realm, realm_len);
+		}
+		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+		eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+	}
+
+	if (attr->next_reauth_id) {
+		os_free(data->reauth_id);
+		data->reauth_id = os_malloc(attr->next_reauth_id_len);
+		if (data->reauth_id == NULL) {
+			wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
+				   "next reauth_id");
+			data->reauth_id_len = 0;
+			return -1;
+		}
+		os_memcpy(data->reauth_id, attr->next_reauth_id,
+			  attr->next_reauth_id_len);
+		data->reauth_id_len = attr->next_reauth_id_len;
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
+				  data->reauth_id,
+				  data->reauth_id_len);
+	}
+
+	return 0;
+}
+
+
+static int eap_aka_add_id_msg(struct eap_aka_data *data,
+			      const struct wpabuf *msg)
+{
+	if (msg == NULL)
+		return -1;
+
+	if (data->id_msgs == NULL) {
+		data->id_msgs = wpabuf_dup(msg);
+		return data->id_msgs == NULL ? -1 : 0;
+	}
+
+	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
+		return -1;
+	wpabuf_put_buf(data->id_msgs, msg);
+
+	return 0;
+}
+
+
+static void eap_aka_add_checkcode(struct eap_aka_data *data,
+				  struct eap_sim_msg *msg)
+{
+	const u8 *addr;
+	size_t len;
+	u8 hash[SHA256_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
+
+	if (data->id_msgs == NULL) {
+		/*
+		 * No EAP-AKA/Identity packets were exchanged - send empty
+		 * checkcode.
+		 */
+		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
+		return;
+	}
+
+	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
+	addr = wpabuf_head(data->id_msgs);
+	len = wpabuf_len(data->id_msgs);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+#endif /* EAP_AKA_PRIME */
+		sha1_vector(1, &addr, &len, hash);
+
+	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
+			data->eap_method == EAP_TYPE_AKA_PRIME ?
+			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
+}
+
+
+static int eap_aka_verify_checkcode(struct eap_aka_data *data,
+				    const u8 *checkcode, size_t checkcode_len)
+{
+	const u8 *addr;
+	size_t len;
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
+
+	if (checkcode == NULL)
+		return -1;
+
+	if (data->id_msgs == NULL) {
+		if (checkcode_len != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
+				   "indicates that AKA/Identity messages were "
+				   "used, but they were not");
+			return -1;
+		}
+		return 0;
+	}
+
+	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
+		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
+
+	if (checkcode_len != hash_len) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
+			   "indicates that AKA/Identity message were not "
+			   "used, but they were");
+		return -1;
+	}
+
+	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
+	addr = wpabuf_head(data->id_msgs);
+	len = wpabuf_len(data->id_msgs);
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+#endif /* EAP_AKA_PRIME */
+		sha1_vector(1, &addr, &len, hash);
+
+	if (os_memcmp(hash, checkcode, hash_len) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
+					    int err)
+{
+	struct eap_sim_msg *msg;
+
+	eap_aka_state(data, FAILURE);
+	data->num_id_req = 0;
+	data->num_notification = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)",
+		   err);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_CLIENT_ERROR);
+	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
+						     u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	eap_aka_state(data, FAILURE);
+	data->num_id_req = 0;
+	data->num_notification = 0;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
+		   "(id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_synchronization_failure(
+	struct eap_aka_data *data, u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	data->num_id_req = 0;
+	data->num_notification = 0;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
+		   "(id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
+	wpa_printf(MSG_DEBUG, "   AT_AUTS");
+	eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
+			     EAP_AKA_AUTS_LEN);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
+						 struct eap_aka_data *data,
+						 u8 id,
+						 enum eap_sim_id_req id_req)
+{
+	const u8 *identity = NULL;
+	size_t identity_len = 0;
+	struct eap_sim_msg *msg;
+
+	data->reauth = 0;
+	if (id_req == ANY_ID && data->reauth_id) {
+		identity = data->reauth_id;
+		identity_len = data->reauth_id_len;
+		data->reauth = 1;
+	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
+		   data->pseudonym) {
+		identity = data->pseudonym;
+		identity_len = data->pseudonym_len;
+		eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
+	} else if (id_req != NO_ID_REQ) {
+		identity = eap_get_config_identity(sm, &identity_len);
+		if (identity) {
+			eap_aka_clear_identities(sm, data, CLEAR_PSEUDONYM |
+						 CLEAR_REAUTH_ID);
+		}
+	}
+	if (id_req != NO_ID_REQ)
+		eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_IDENTITY);
+
+	if (identity) {
+		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
+				  identity, identity_len);
+		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+				identity, identity_len);
+	}
+
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
+						  u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_RES");
+	eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
+			data->res, data->res_len);
+	eap_aka_add_checkcode(data, msg);
+	if (data->use_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
+}
+
+
+static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
+					       u8 id, int counter_too_small,
+					       const u8 *nonce_s)
+{
+	struct eap_sim_msg *msg;
+	unsigned int counter;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
+		   id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter_too_small) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
+		counter = data->counter_too_small;
+	} else
+		counter = data->counter;
+
+	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
+	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+	eap_aka_add_checkcode(data, msg);
+	if (data->use_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+				  EAP_SIM_NONCE_S_LEN);
+}
+
+
+static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
+						     u8 id, u16 notification)
+{
+	struct eap_sim_msg *msg;
+	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_NOTIFICATION);
+	if (k_aut && data->reauth) {
+		wpa_printf(MSG_DEBUG, "   AT_IV");
+		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+					   EAP_SIM_AT_ENCR_DATA);
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+				NULL, 0);
+		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+					     EAP_SIM_AT_PADDING)) {
+			wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+				   "AT_ENCR_DATA");
+			eap_sim_msg_free(msg);
+			return NULL;
+		}
+	}
+	if (k_aut) {
+		wpa_printf(MSG_DEBUG, "   AT_MAC");
+		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	}
+	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+}
+
+
+static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
+						struct eap_aka_data *data,
+						u8 id,
+						const struct wpabuf *reqData,
+						struct eap_sim_attrs *attr)
+{
+	int id_error;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity");
+
+	id_error = 0;
+	switch (attr->id_req) {
+	case NO_ID_REQ:
+		break;
+	case ANY_ID:
+		if (data->num_id_req > 0)
+			id_error++;
+		data->num_id_req++;
+		break;
+	case FULLAUTH_ID:
+		if (data->num_id_req > 1)
+			id_error++;
+		data->num_id_req++;
+		break;
+	case PERMANENT_ID:
+		if (data->num_id_req > 2)
+			id_error++;
+		data->num_id_req++;
+		break;
+	}
+	if (id_error) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
+			   "used within one authentication");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	buf = eap_aka_response_identity(sm, data, id, attr->id_req);
+
+	if (data->prev_id != id) {
+		eap_aka_add_id_msg(data, reqData);
+		eap_aka_add_id_msg(data, buf);
+		data->prev_id = id;
+	}
+
+	return buf;
+}
+
+
+static int eap_aka_verify_mac(struct eap_aka_data *data,
+			      const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len)
+{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
+						 extra_len);
+	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
+}
+
+
+#ifdef EAP_AKA_PRIME
+static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
+						u8 id, u16 kdf)
+{
+	struct eap_sim_msg *msg;
+
+	data->kdf_negotiation = 1;
+	data->kdf = kdf;
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
+		   "select)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_KDF");
+	eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
+					     u8 id, struct eap_sim_attrs *attr)
+{
+	size_t i;
+
+	for (i = 0; i < attr->kdf_count; i++) {
+		if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
+			return eap_aka_prime_kdf_select(data, id,
+							EAP_AKA_PRIME_KDF);
+	}
+
+	/* No matching KDF found - fail authentication as if AUTN had been
+	 * incorrect */
+	return eap_aka_authentication_reject(data, id);
+}
+
+
+static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
+				   struct eap_sim_attrs *attr)
+{
+	size_t i, j;
+
+	if (attr->kdf_count == 0)
+		return 0;
+
+	/* The only allowed (and required) duplication of a KDF is the addition
+	 * of the selected KDF into the beginning of the list. */
+
+	if (data->kdf_negotiation) {
+		if (attr->kdf[0] != data->kdf) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
+				   "accept the selected KDF");
+			return 0;
+		}
+
+		for (i = 1; i < attr->kdf_count; i++) {
+			if (attr->kdf[i] == data->kdf)
+				break;
+		}
+		if (i == attr->kdf_count &&
+		    attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
+				   "duplicate the selected KDF");
+			return 0;
+		}
+
+		/* TODO: should check that the list is identical to the one
+		 * used in the previous Challenge message apart from the added
+		 * entry in the beginning. */
+	}
+
+	for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
+		for (j = i + 1; j < attr->kdf_count; j++) {
+			if (attr->kdf[i] == attr->kdf[j]) {
+				wpa_printf(MSG_WARNING, "EAP-AKA': The server "
+					   "included a duplicated KDF");
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+#endif /* EAP_AKA_PRIME */
+
+
+static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
+						 struct eap_aka_data *data,
+						 u8 id,
+						 const struct wpabuf *reqData,
+						 struct eap_sim_attrs *attr)
+{
+	const u8 *identity;
+	size_t identity_len;
+	int res;
+	struct eap_sim_attrs eattr;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge");
+
+	if (attr->checkcode &&
+	    eap_aka_verify_checkcode(data, attr->checkcode,
+				     attr->checkcode_len)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
+			   "message");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		if (!attr->kdf_input || attr->kdf_input_len == 0) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
+				   "did not include non-empty AT_KDF_INPUT");
+			/* Fail authentication as if AUTN had been incorrect */
+			return eap_aka_authentication_reject(data, id);
+		}
+		os_free(data->network_name);
+		data->network_name = os_malloc(attr->kdf_input_len);
+		if (data->network_name == NULL) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
+				   "storing Network Name");
+			return eap_aka_authentication_reject(data, id);
+		}
+		os_memcpy(data->network_name, attr->kdf_input,
+			  attr->kdf_input_len);
+		data->network_name_len = attr->kdf_input_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
+				  "(AT_KDF_INPUT)",
+				  data->network_name, data->network_name_len);
+		/* TODO: check Network Name per 3GPP.33.402 */
+
+		if (!eap_aka_prime_kdf_valid(data, attr))
+			return eap_aka_authentication_reject(data, id);
+
+		if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
+			return eap_aka_prime_kdf_neg(data, id, attr);
+
+		data->kdf = EAP_AKA_PRIME_KDF;
+		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
+	}
+
+	if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
+		u16 flags = WPA_GET_BE16(attr->bidding);
+		if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
+		    eap_allowed_method(sm, EAP_VENDOR_IETF,
+				       EAP_TYPE_AKA_PRIME)) {
+			wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
+				   "AKA' to AKA detected");
+			/* Fail authentication as if AUTN had been incorrect */
+			return eap_aka_authentication_reject(data, id);
+		}
+	}
+#endif /* EAP_AKA_PRIME */
+
+	data->reauth = 0;
+	if (!attr->mac || !attr->rand || !attr->autn) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+			   "did not include%s%s%s",
+			   !attr->mac ? " AT_MAC" : "",
+			   !attr->rand ? " AT_RAND" : "",
+			   !attr->autn ? " AT_AUTN" : "");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+	os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
+	os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
+
+	res = eap_aka_umts_auth(sm, data);
+	if (res == -1) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
+			   "failed (AUTN)");
+		return eap_aka_authentication_reject(data, id);
+	} else if (res == -2) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
+			   "failed (AUTN seq# -> AUTS)");
+		return eap_aka_synchronization_failure(data, id);
+	} else if (res) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
+		 * needed 6-octet SQN ^ AK for CK',IK' derivation */
+		u16 amf = WPA_GET_BE16(data->autn + 6);
+		if (!(amf & 0x8000)) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit "
+				   "not set (AMF=0x%4x)", amf);
+			return eap_aka_authentication_reject(data, id);
+		}
+		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
+						 data->autn,
+						 data->network_name,
+						 data->network_name_len);
+	}
+#endif /* EAP_AKA_PRIME */
+	if (data->last_eap_identity) {
+		identity = data->last_eap_identity;
+		identity_len = data->last_eap_identity_len;
+	} else if (data->pseudonym) {
+		identity = data->pseudonym;
+		identity_len = data->pseudonym_len;
+	} else
+		identity = eap_get_config_identity(sm, &identity_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
+			  "derivation", identity, identity_len);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+					  data->ck, data->k_encr, data->k_aut,
+					  data->k_re, data->msk, data->emsk);
+	} else {
+		eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
+				  data->mk);
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+	}
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+			   "used invalid AT_MAC");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new identities are received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+
+	if (attr->encr_data) {
+		u8 *decrypted;
+		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+					       attr->encr_data_len, attr->iv,
+					       &eattr, 0);
+		if (decrypted == NULL) {
+			return eap_aka_client_error(
+				data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		}
+		eap_aka_learn_ids(sm, data, &eattr);
+		os_free(decrypted);
+	}
+
+	if (data->result_ind && attr->result_ind)
+		data->use_result_ind = 1;
+
+	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+		eap_aka_state(data, data->use_result_ind ?
+			      RESULT_SUCCESS : SUCCESS);
+	}
+
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	/* RFC 4187 specifies that counter is initialized to one after
+	 * fullauth, but initializing it to zero makes it easier to implement
+	 * reauth verification. */
+	data->counter = 0;
+	return eap_aka_response_challenge(data, id);
+}
+
+
+static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
+					       struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted;
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
+			   "reauth did not include encrypted data");
+		return -1;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+			   "data from notification message");
+		return -1;
+	}
+
+	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
+			   "message does not match with counter in reauth "
+			   "message");
+		os_free(decrypted);
+		return -1;
+	}
+
+	os_free(decrypted);
+	return 0;
+}
+
+
+static int eap_aka_process_notification_auth(struct eap_aka_data *data,
+					     const struct wpabuf *reqData,
+					     struct eap_sim_attrs *attr)
+{
+	if (attr->mac == NULL) {
+		wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth "
+			   "Notification message");
+		return -1;
+	}
+
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
+			   "used invalid AT_MAC");
+		return -1;
+	}
+
+	if (data->reauth &&
+	    eap_aka_process_notification_reauth(data, attr)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
+			   "message after reauth");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_aka_process_notification(
+	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
+	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification");
+	if (data->num_notification > 0) {
+		wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
+			   "rounds (only one allowed)");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+	data->num_notification++;
+	if (attr->notification == -1) {
+		wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
+			   "Notification message");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if ((attr->notification & 0x4000) == 0 &&
+	    eap_aka_process_notification_auth(data, reqData, attr)) {
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
+	if (attr->notification >= 0 && attr->notification < 32768) {
+		eap_aka_state(data, FAILURE);
+	} else if (attr->notification == EAP_SIM_SUCCESS &&
+		   data->state == RESULT_SUCCESS)
+		eap_aka_state(data, SUCCESS);
+	return eap_aka_response_notification(data, id, attr->notification);
+}
+
+
+static struct wpabuf * eap_aka_process_reauthentication(
+	struct eap_sm *sm, struct eap_aka_data *data, u8 id,
+	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
+
+	if (attr->checkcode &&
+	    eap_aka_verify_checkcode(data, attr->checkcode,
+				     attr->checkcode_len)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
+			   "message");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (data->reauth_id == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
+			   "reauthentication, but no reauth_id available");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	data->reauth = 1;
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+			   "did not have valid AT_MAC");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+			   "message did not include encrypted data");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+			   "data from reauthentication message");
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (eattr.nonce_s == NULL || eattr.counter < 0) {
+		wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
+			   !eattr.nonce_s ? " AT_NONCE_S" : "",
+			   eattr.counter < 0 ? " AT_COUNTER" : "");
+		os_free(decrypted);
+		return eap_aka_client_error(data, id,
+					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
+		struct wpabuf *res;
+		wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
+			   "(%d <= %d)", eattr.counter, data->counter);
+		data->counter_too_small = eattr.counter;
+
+		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
+		 * reauth_id must not be used to start a new reauthentication.
+		 * However, since it was used in the last EAP-Response-Identity
+		 * packet, it has to saved for the following fullauth to be
+		 * used in MK derivation. */
+		os_free(data->last_eap_identity);
+		data->last_eap_identity = data->reauth_id;
+		data->last_eap_identity_len = data->reauth_id_len;
+		data->reauth_id = NULL;
+		data->reauth_id_len = 0;
+
+		res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s);
+		os_free(decrypted);
+
+		return res;
+	}
+	data->counter = eattr.counter;
+
+	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
+		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
+						 data->reauth_id,
+						 data->reauth_id_len,
+						 data->nonce_s,
+						 data->msk, data->emsk);
+	} else {
+		eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
+					   data->reauth_id_len,
+					   data->nonce_s, data->mk,
+					   data->msk, data->emsk);
+	}
+	eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+	eap_aka_learn_ids(sm, data, &eattr);
+
+	if (data->result_ind && attr->result_ind)
+		data->use_result_ind = 1;
+
+	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+		eap_aka_state(data, data->use_result_ind ?
+			      RESULT_SUCCESS : SUCCESS);
+	}
+
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
+			   "fast reauths performed - force fullauth");
+		eap_aka_clear_identities(sm, data,
+					 CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+	}
+	os_free(decrypted);
+	return eap_aka_response_reauth(data, id, 0, data->nonce_s);
+}
+
+
+static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_aka_data *data = priv;
+	const struct eap_hdr *req;
+	u8 subtype, id;
+	struct wpabuf *res;
+	const u8 *pos;
+	struct eap_sim_attrs attr;
+	size_t len;
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData);
+	if (eap_get_config_identity(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
+		eap_sm_request_identity(sm);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
+			       &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	req = wpabuf_head(reqData);
+	id = req->identifier;
+	len = be_to_host16(req->length);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	subtype = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
+	pos += 2; /* Reserved */
+
+	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
+			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
+			       0)) {
+		res = eap_aka_client_error(data, id,
+					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		goto done;
+	}
+
+	switch (subtype) {
+	case EAP_AKA_SUBTYPE_IDENTITY:
+		res = eap_aka_process_identity(sm, data, id, reqData, &attr);
+		break;
+	case EAP_AKA_SUBTYPE_CHALLENGE:
+		res = eap_aka_process_challenge(sm, data, id, reqData, &attr);
+		break;
+	case EAP_AKA_SUBTYPE_NOTIFICATION:
+		res = eap_aka_process_notification(sm, data, id, reqData,
+						   &attr);
+		break;
+	case EAP_AKA_SUBTYPE_REAUTHENTICATION:
+		res = eap_aka_process_reauthentication(sm, data, id, reqData,
+						       &attr);
+		break;
+	case EAP_AKA_SUBTYPE_CLIENT_ERROR:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
+		res = eap_aka_client_error(data, id,
+					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
+		res = eap_aka_client_error(data, id,
+					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		break;
+	}
+
+done:
+	if (data->state == FAILURE) {
+		ret->decision = DECISION_FAIL;
+		ret->methodState = METHOD_DONE;
+	} else if (data->state == SUCCESS) {
+		ret->decision = data->use_result_ind ?
+			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
+		/*
+		 * It is possible for the server to reply with AKA
+		 * Notification, so we must allow the method to continue and
+		 * not only accept EAP-Success at this point.
+		 */
+		ret->methodState = data->use_result_ind ?
+			METHOD_DONE : METHOD_MAY_CONT;
+	} else if (data->state == RESULT_FAILURE)
+		ret->methodState = METHOD_CONT;
+	else if (data->state == RESULT_SUCCESS)
+		ret->methodState = METHOD_CONT;
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	return res;
+}
+
+
+static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->pseudonym || data->reauth_id;
+}
+
+
+static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
+	data->prev_id = -1;
+	wpabuf_free(data->id_msgs);
+	data->id_msgs = NULL;
+	data->use_result_ind = 0;
+	data->kdf_negotiation = 0;
+}
+
+
+static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	eap_aka_state(data, CONTINUE);
+	return priv;
+}
+
+
+static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv,
+				       size_t *len)
+{
+	struct eap_aka_data *data = priv;
+
+	if (data->reauth_id) {
+		*len = data->reauth_id_len;
+		return data->reauth_id;
+	}
+
+	if (data->pseudonym) {
+		*len = data->pseudonym_len;
+		return data->pseudonym;
+	}
+
+	return NULL;
+}
+
+
+static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_SIM_KEYING_DATA_LEN;
+	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+
+	return key;
+}
+
+
+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_init;
+	eap->deinit = eap_aka_deinit;
+	eap->process = eap_aka_process;
+	eap->isKeyAvailable = eap_aka_isKeyAvailable;
+	eap->getKey = eap_aka_getKey;
+	eap->has_reauth_data = eap_aka_has_reauth_data;
+	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
+	eap->init_for_reauth = eap_aka_init_for_reauth;
+	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;
+}
+
+
+#ifdef EAP_AKA_PRIME
+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,
+				    "AKA'");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_prime_init;
+	eap->deinit = eap_aka_deinit;
+	eap->process = eap_aka_process;
+	eap->isKeyAvailable = eap_aka_isKeyAvailable;
+	eap->getKey = eap_aka_getKey;
+	eap->has_reauth_data = eap_aka_has_reauth_data;
+	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
+	eap->init_for_reauth = eap_aka_init_for_reauth;
+	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;
+}
+#endif /* EAP_AKA_PRIME */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_config.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_config.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,669 +0,0 @@
-/*
- * EAP peer configuration data
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_CONFIG_H
-#define EAP_CONFIG_H
-
-/**
- * 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.
-	 */
-	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.
-	 */
-	u8 *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
-	 * server certificate. If this string is set, the server sertificate 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 at n.example.com
-	 */
-	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 this string is set, the server sertificate 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 at example.com
-	 * Example: DNS:server.example.com;DNS:server2.example.com
-	 *
-	 * Following types are supported: EMAIL, DNS, URI
-	 */
-	u8 *altsubject_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.
-	 */
-	u8 *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;
-
-	/**
-	 * 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
-	 */
-	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.
-	 */
-	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;
-
-#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
-	/**
-	 * 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
-	 */
-	u32 flags;
-};
-
-
-/**
- * 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;
-};
-
-#endif /* EAP_CONFIG_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap_config.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_config.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_config.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,669 @@
+/*
+ * EAP peer configuration data
+ * Copyright (c) 2003-2008, Jouni Malinen <j at 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
+
+/**
+ * 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.
+	 */
+	u8 *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
+	 * server certificate. If this string is set, the server sertificate 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 at n.example.com
+	 */
+	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 this string is set, the server sertificate 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 at example.com
+	 * Example: DNS:server.example.com;DNS:server2.example.com
+	 *
+	 * Following types are supported: EMAIL, DNS, URI
+	 */
+	u8 *altsubject_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.
+	 */
+	u8 *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;
+
+	/**
+	 * 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
+	 */
+	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.
+	 */
+	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;
+
+#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;
+};
+
+
+/**
+ * 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;
+};
+
+#endif /* EAP_CONFIG_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_fast.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_fast.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1712 +0,0 @@
-/*
- * EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/tls.h"
-#include "crypto/sha1.h"
-#include "eap_common/eap_tlv_common.h"
-#include "eap_i.h"
-#include "eap_tls_common.h"
-#include "eap_config.h"
-#include "eap_fast_pac.h"
-
-#ifdef EAP_FAST_DYNAMIC
-#include "eap_fast_pac.c"
-#endif /* EAP_FAST_DYNAMIC */
-
-/* TODO:
- * - test session resumption and enable it if it interoperates
- * - password change (pending mschapv2 packet; replay decrypted packet)
- */
-
-
-static void eap_fast_deinit(struct eap_sm *sm, void *priv);
-
-
-struct eap_fast_data {
-	struct eap_ssl_data ssl;
-
-	int fast_version;
-
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int phase2_success;
-
-	struct eap_method_type phase2_type;
-	struct eap_method_type *phase2_types;
-	size_t num_phase2_types;
-	int resuming; /* starting a resumed session */
-	struct eap_fast_key_block_provisioning *key_block_p;
-#define EAP_FAST_PROV_UNAUTH 1
-#define EAP_FAST_PROV_AUTH 2
-	int provisioning_allowed; /* Allowed PAC provisioning modes */
-	int provisioning; /* doing PAC provisioning (not the normal auth) */
-	int anon_provisioning; /* doing anonymous (unauthenticated)
-				* provisioning */
-	int session_ticket_used;
-
-	u8 key_data[EAP_FAST_KEY_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	int success;
-
-	struct eap_fast_pac *pac;
-	struct eap_fast_pac *current_pac;
-	size_t max_pac_list_len;
-	int use_pac_binary_format;
-
-	u8 simck[EAP_FAST_SIMCK_LEN];
-	int simck_idx;
-
-	struct wpabuf *pending_phase2_req;
-};
-
-
-static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
-				      const u8 *client_random,
-				      const u8 *server_random,
-				      u8 *master_secret)
-{
-	struct eap_fast_data *data = ctx;
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
-
-	if (client_random == NULL || server_random == NULL ||
-	    master_secret == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "
-			   "back to full TLS handshake");
-		data->session_ticket_used = 0;
-		if (data->provisioning_allowed) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "
-				   "new PAC-Key");
-			data->provisioning = 1;
-			data->current_pac = NULL;
-		}
-		return 0;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
-
-	if (data->current_pac == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
-			   "using SessionTicket");
-		data->session_ticket_used = 0;
-		return 0;
-	}
-
-	eap_fast_derive_master_secret(data->current_pac->pac_key,
-				      server_random, client_random,
-				      master_secret);
-
-	data->session_ticket_used = 1;
-
-	return 1;
-}
-
-
-static int eap_fast_parse_phase1(struct eap_fast_data *data,
-				 const char *phase1)
-{
-	const char *pos;
-
-	pos = os_strstr(phase1, "fast_provisioning=");
-	if (pos) {
-		data->provisioning_allowed = atoi(pos + 18);
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning "
-			   "mode: %d", data->provisioning_allowed);
-	}
-
-	pos = os_strstr(phase1, "fast_max_pac_list_len=");
-	if (pos) {
-		data->max_pac_list_len = atoi(pos + 22);
-		if (data->max_pac_list_len == 0)
-			data->max_pac_list_len = 1;
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu",
-			   (unsigned long) data->max_pac_list_len);
-	}
-
-	pos = os_strstr(phase1, "fast_pac_format=binary");
-	if (pos) {
-		data->use_pac_binary_format = 1;
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
-			   "list");
-	}
-
-	return 0;
-}
-
-
-static void * eap_fast_init(struct eap_sm *sm)
-{
-	struct eap_fast_data *data;
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->fast_version = EAP_FAST_VERSION;
-	data->max_pac_list_len = 10;
-
-	if (config && config->phase1 &&
-	    eap_fast_parse_phase1(data, config->phase1) < 0) {
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	if (eap_peer_select_phase2_methods(config, "auth=",
-					   &data->phase2_types,
-					   &data->num_phase2_types) < 0) {
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	data->phase2_type.vendor = EAP_VENDOR_IETF;
-	data->phase2_type.method = EAP_TYPE_NONE;
-
-	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
-						 eap_fast_session_ticket_cb,
-						 data) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
-			   "callback");
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	/*
-	 * The local RADIUS server in a Cisco AP does not seem to like empty
-	 * fragments before data, so disable that workaround for CBC.
-	 * TODO: consider making this configurable
-	 */
-	if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS "
-			   "workarounds");
-	}
-
-	if (data->use_pac_binary_format &&
-	    eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	if (!data->use_pac_binary_format &&
-	    eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
-
-	if (data->pac == NULL && !data->provisioning_allowed) {
-		wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
-			   "provisioning disabled");
-		eap_fast_deinit(sm, data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_fast_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	struct eap_fast_pac *pac, *prev;
-
-	if (data == NULL)
-		return;
-	if (data->phase2_priv && data->phase2_method)
-		data->phase2_method->deinit(sm, data->phase2_priv);
-	os_free(data->phase2_types);
-	os_free(data->key_block_p);
-	eap_peer_tls_ssl_deinit(sm, &data->ssl);
-
-	pac = data->pac;
-	prev = NULL;
-	while (pac) {
-		prev = pac;
-		pac = pac->next;
-		eap_fast_free_pac(prev);
-	}
-	wpabuf_free(data->pending_phase2_req);
-	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);
-	data->success = 1;
-	return 0;
-}
-
-
-static void eap_fast_derive_key_auth(struct eap_sm *sm,
-				     struct eap_fast_data *data)
-{
-	u8 *sks;
-
-	/* RFC 4851, Section 5.1:
-	 * Extra key material after TLS key_block: session_key_seed[40]
-	 */
-
-	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
-				  EAP_FAST_SKS_LEN);
-	if (sks == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
-			   "session_key_seed");
-		return;
-	}
-
-	/*
-	 * RFC 4851, Section 5.2:
-	 * S-IMCK[0] = session_key_seed
-	 */
-	wpa_hexdump_key(MSG_DEBUG,
-			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
-			sks, EAP_FAST_SKS_LEN);
-	data->simck_idx = 0;
-	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
-	os_free(sks);
-}
-
-
-static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
-					     struct eap_fast_data *data)
-{
-	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");
-		return;
-	}
-	/*
-	 * RFC 4851, Section 5.2:
-	 * S-IMCK[0] = session_key_seed
-	 */
-	wpa_hexdump_key(MSG_DEBUG,
-			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
-			data->key_block_p->session_key_seed,
-			sizeof(data->key_block_p->session_key_seed));
-	data->simck_idx = 0;
-	os_memcpy(data->simck, data->key_block_p->session_key_seed,
-		  EAP_FAST_SIMCK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
-			data->key_block_p->server_challenge,
-			sizeof(data->key_block_p->server_challenge));
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
-			data->key_block_p->client_challenge,
-			sizeof(data->key_block_p->client_challenge));
-}
-
-
-static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
-{
-	if (data->anon_provisioning)
-		eap_fast_derive_key_provisioning(sm, data);
-	else
-		eap_fast_derive_key_auth(sm, data);
-}
-
-
-static int eap_fast_init_phase2_method(struct eap_sm *sm,
-				       struct eap_fast_data *data)
-{
-	data->phase2_method =
-		eap_peer_get_eap_method(data->phase2_type.vendor,
-					data->phase2_type.method);
-	if (data->phase2_method == NULL)
-		return -1;
-
-	if (data->key_block_p) {
-		sm->auth_challenge = data->key_block_p->server_challenge;
-		sm->peer_challenge = data->key_block_p->client_challenge;
-	}
-	sm->init_phase2 = 1;
-	data->phase2_priv = data->phase2_method->init(sm);
-	sm->init_phase2 = 0;
-	sm->auth_challenge = NULL;
-	sm->peer_challenge = NULL;
-
-	return data->phase2_priv == NULL ? -1 : 0;
-}
-
-
-static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
-{
-	size_t i;
-
-	/* TODO: TNC with anonymous provisioning; need to require both
-	 * completed MSCHAPv2 and TNC */
-
-	if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
-			   "during unauthenticated provisioning; reject phase2"
-			   " type %d", type);
-		return -1;
-	}
-
-#ifdef EAP_TNC
-	if (type == EAP_TYPE_TNC) {
-		data->phase2_type.vendor = EAP_VENDOR_IETF;
-		data->phase2_type.method = EAP_TYPE_TNC;
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
-			   "vendor %d method %d for TNC",
-			   data->phase2_type.vendor,
-			   data->phase2_type.method);
-		return 0;
-	}
-#endif /* EAP_TNC */
-
-	for (i = 0; i < data->num_phase2_types; i++) {
-		if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
-		    data->phase2_types[i].method != type)
-			continue;
-
-		data->phase2_type.vendor = data->phase2_types[i].vendor;
-		data->phase2_type.method = data->phase2_types[i].method;
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
-			   "vendor %d method %d",
-			   data->phase2_type.vendor,
-			   data->phase2_type.method);
-		break;
-	}
-
-	if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
-		return -1;
-
-	return 0;
-}
-
-
-static int eap_fast_phase2_request(struct eap_sm *sm,
-				   struct eap_fast_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_method_ret iret;
-	struct eap_peer_config *config = eap_get_config(sm);
-	struct wpabuf msg;
-
-	if (len <= sizeof(struct eap_hdr)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: too short "
-			   "Phase 2 request (len=%lu)", (unsigned long) len);
-		return -1;
-	}
-	pos = (u8 *) (hdr + 1);
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
-	if (*pos == EAP_TYPE_IDENTITY) {
-		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
-		return 0;
-	}
-
-	if (data->phase2_priv && data->phase2_method &&
-	    *pos != data->phase2_type.method) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
-			   "deinitialize previous method");
-		data->phase2_method->deinit(sm, data->phase2_priv);
-		data->phase2_method = NULL;
-		data->phase2_priv = NULL;
-		data->phase2_type.vendor = EAP_VENDOR_IETF;
-		data->phase2_type.method = EAP_TYPE_NONE;
-	}
-
-	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
-	    data->phase2_type.method == EAP_TYPE_NONE &&
-	    eap_fast_select_phase2_method(data, *pos) < 0) {
-		if (eap_peer_tls_phase2_nak(data->phase2_types,
-					    data->num_phase2_types,
-					    hdr, resp))
-			return -1;
-		return 0;
-	}
-
-	if (data->phase2_priv == NULL &&
-	    eap_fast_init_phase2_method(sm, data) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
-			   "Phase 2 EAP method %d", *pos);
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return -1;
-	}
-
-	os_memset(&iret, 0, sizeof(iret));
-	wpabuf_set(&msg, hdr, len);
-	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
-					     &msg);
-	if (*resp == NULL ||
-	    (iret.methodState == METHOD_DONE &&
-	     iret.decision == DECISION_FAIL)) {
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-	} else if ((iret.methodState == METHOD_DONE ||
-		    iret.methodState == METHOD_MAY_CONT) &&
-		   (iret.decision == DECISION_UNCOND_SUCC ||
-		    iret.decision == DECISION_COND_SUCC)) {
-		data->phase2_success = 1;
-	}
-
-	if (*resp == NULL && config &&
-	    (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_alloc_copy(hdr, len);
-	} else if (*resp == NULL)
-		return -1;
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type)
-{
-	struct wpabuf *buf;
-	struct eap_tlv_nak_tlv *nak;
-	buf = wpabuf_alloc(sizeof(*nak));
-	if (buf == NULL)
-		return NULL;
-	nak = wpabuf_put(buf, sizeof(*nak));
-	nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
-	nak->length = host_to_be16(6);
-	nak->vendor_id = host_to_be32(vendor_id);
-	nak->nak_type = host_to_be16(tlv_type);
-	return buf;
-}
-
-
-static struct wpabuf * eap_fast_tlv_result(int status, int intermediate)
-{
-	struct wpabuf *buf;
-	struct eap_tlv_intermediate_result_tlv *result;
-	buf = wpabuf_alloc(sizeof(*result));
-	if (buf == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)",
-		   intermediate ? "Intermediate " : "", status);
-	result = wpabuf_put(buf, sizeof(*result));
-	result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-					(intermediate ?
-					 EAP_TLV_INTERMEDIATE_RESULT_TLV :
-					 EAP_TLV_RESULT_TLV));
-	result->length = host_to_be16(2);
-	result->status = host_to_be16(status);
-	return buf;
-}
-
-
-static struct wpabuf * eap_fast_tlv_pac_ack(void)
-{
-	struct wpabuf *buf;
-	struct eap_tlv_result_tlv *res;
-	struct eap_tlv_pac_ack_tlv *ack;
-
-	buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
-	if (buf == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)");
-	ack = wpabuf_put(buf, sizeof(*ack));
-	ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
-				     EAP_TLV_TYPE_MANDATORY);
-	ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
-	ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
-	ack->pac_len = host_to_be16(2);
-	ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
-
-	return buf;
-}
-
-
-static struct wpabuf * eap_fast_process_eap_payload_tlv(
-	struct eap_sm *sm, struct eap_fast_data *data,
-	struct eap_method_ret *ret, const struct eap_hdr *req,
-	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
-{
-	struct eap_hdr *hdr;
-	struct wpabuf *resp = NULL;
-
-	if (eap_payload_tlv_len < sizeof(*hdr)) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
-			   "Payload TLV (len=%lu)",
-			   (unsigned long) eap_payload_tlv_len);
-		return NULL;
-	}
-
-	hdr = (struct eap_hdr *) eap_payload_tlv;
-	if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in "
-			   "EAP Payload TLV");
-		return NULL;
-	}
-
-	if (hdr->code != EAP_CODE_REQUEST) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
-			   "Phase 2 EAP header", hdr->code);
-		return NULL;
-	}
-
-	if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing "
-			   "failed");
-		return NULL;
-	}
-
-	return eap_fast_tlv_eap_payload(resp);
-}
-
-
-static int eap_fast_validate_crypto_binding(
-	struct eap_tlv_crypto_binding_tlv *_bind)
-{
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
-		   "Received Version %d SubType %d",
-		   _bind->version, _bind->received_version, _bind->subtype);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
-		    _bind->nonce, sizeof(_bind->nonce));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
-		    _bind->compound_mac, sizeof(_bind->compound_mac));
-
-	if (_bind->version != EAP_FAST_VERSION ||
-	    _bind->received_version != EAP_FAST_VERSION ||
-	    _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
-			   "Crypto-Binding TLV: Version %d "
-			   "Received Version %d SubType %d",
-			   _bind->version, _bind->received_version,
-			   _bind->subtype);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void eap_fast_write_crypto_binding(
-	struct eap_tlv_crypto_binding_tlv *rbind,
-	struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk)
-{
-	rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				       EAP_TLV_CRYPTO_BINDING_TLV);
-	rbind->length = host_to_be16(sizeof(*rbind) -
-				     sizeof(struct eap_tlv_hdr));
-	rbind->version = EAP_FAST_VERSION;
-	rbind->received_version = _bind->version;
-	rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
-	os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
-	inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
-	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind),
-		  rbind->compound_mac);
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
-		   "Received Version %d SubType %d",
-		   rbind->version, rbind->received_version, rbind->subtype);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
-		    rbind->nonce, sizeof(rbind->nonce));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
-		    rbind->compound_mac, sizeof(rbind->compound_mac));
-}
-
-
-static int eap_fast_get_phase2_key(struct eap_sm *sm,
-				   struct eap_fast_data *data,
-				   u8 *isk, size_t isk_len)
-{
-	u8 *key;
-	size_t key_len;
-
-	os_memset(isk, 0, isk_len);
-
-	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
-			   "available");
-		return -1;
-	}
-
-	if (data->phase2_method->isKeyAvailable == NULL ||
-	    data->phase2_method->getKey == NULL)
-		return 0;
-
-	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
-	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
-					       &key_len)) == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
-			   "from Phase 2");
-		return -1;
-	}
-
-	if (key_len > isk_len)
-		key_len = isk_len;
-	if (key_len == 32 &&
-	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
-	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
-		/*
-		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
-		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
-		 * ISK for EAP-FAST cryptobinding.
-		 */
-		os_memcpy(isk, key + 16, 16);
-		os_memcpy(isk + 16, key, 16);
-	} else
-		os_memcpy(isk, key, key_len);
-	os_free(key);
-
-	return 0;
-}
-
-
-static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
-			    u8 *cmk)
-{
-	u8 isk[32], imck[60];
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
-		   "calculation", data->simck_idx + 1);
-
-	/*
-	 * RFC 4851, Section 5.2:
-	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
-	 *                 MSK[j], 60)
-	 * S-IMCK[j] = first 40 octets of IMCK[j]
-	 * CMK[j] = last 20 octets of IMCK[j]
-	 */
-
-	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));
-	data->simck_idx++;
-	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
-			data->simck, EAP_FAST_SIMCK_LEN);
-	os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
-			cmk, EAP_FAST_CMK_LEN);
-
-	return 0;
-}
-
-
-static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type)
-{
-	struct eap_tlv_hdr *pac;
-	struct eap_tlv_request_action_tlv *act;
-	struct eap_tlv_pac_type_tlv *type;
-
-	act = (struct eap_tlv_request_action_tlv *) pos;
-	act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV);
-	act->length = host_to_be16(2);
-	act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV);
-
-	pac = (struct eap_tlv_hdr *) (act + 1);
-	pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV);
-	pac->length = host_to_be16(sizeof(*type));
-
-	type = (struct eap_tlv_pac_type_tlv *) (pac + 1);
-	type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE);
-	type->length = host_to_be16(2);
-	type->pac_type = host_to_be16(pac_type);
-
-	return (u8 *) (type + 1);
-}
-
-
-static struct wpabuf * eap_fast_process_crypto_binding(
-	struct eap_sm *sm, struct eap_fast_data *data,
-	struct eap_method_ret *ret,
-	struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len)
-{
-	struct wpabuf *resp;
-	u8 *pos;
-	u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN];
-	int res;
-	size_t len;
-
-	if (eap_fast_validate_crypto_binding(_bind) < 0)
-		return NULL;
-
-	if (eap_fast_get_cmk(sm, data, cmk) < 0)
-		return NULL;
-
-	/* Validate received Compound MAC */
-	os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
-	os_memset(_bind->compound_mac, 0, sizeof(cmac));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
-		    "MAC calculation", (u8 *) _bind, bind_len);
-	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
-		  _bind->compound_mac);
-	res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
-		    cmac, sizeof(cmac));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
-		    _bind->compound_mac, sizeof(cmac));
-	if (res != 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
-		os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
-		return NULL;
-	}
-
-	/*
-	 * Compound MAC was valid, so authentication succeeded. Reply with
-	 * crypto binding to allow server to complete authentication.
-	 */
-
-	len = sizeof(struct eap_tlv_crypto_binding_tlv);
-	resp = wpabuf_alloc(len);
-	if (resp == NULL)
-		return NULL;
-
-	if (!data->anon_provisioning && data->phase2_success &&
-	    eap_fast_derive_msk(data) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		data->phase2_success = 0;
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
-	eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
-				      pos, _bind, cmk);
-
-	return resp;
-}
-
-
-static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type,
-				   u8 *pos, size_t len, int *pac_key_found)
-{
-	switch (type & 0x7fff) {
-	case PAC_TYPE_PAC_KEY:
-		wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len);
-		if (len != EAP_FAST_PAC_KEY_LEN) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key "
-				   "length %lu", (unsigned long) len);
-			break;
-		}
-		*pac_key_found = 1;
-		os_memcpy(entry->pac_key, pos, len);
-		break;
-	case PAC_TYPE_PAC_OPAQUE:
-		wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len);
-		entry->pac_opaque = pos;
-		entry->pac_opaque_len = len;
-		break;
-	case PAC_TYPE_PAC_INFO:
-		wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len);
-		entry->pac_info = pos;
-		entry->pac_info_len = len;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d",
-			   type);
-		break;
-	}
-}
-
-
-static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry,
-				    u8 *pac, size_t pac_len)
-{
-	struct pac_tlv_hdr *hdr;
-	u8 *pos;
-	size_t left, len;
-	int type, pac_key_found = 0;
-
-	pos = pac;
-	left = pac_len;
-
-	while (left > sizeof(*hdr)) {
-		hdr = (struct pac_tlv_hdr *) pos;
-		type = be_to_host16(hdr->type);
-		len = be_to_host16(hdr->len);
-		pos += sizeof(*hdr);
-		left -= sizeof(*hdr);
-		if (len > left) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
-				   "(type=%d len=%lu left=%lu)",
-				   type, (unsigned long) len,
-				   (unsigned long) left);
-			return -1;
-		}
-
-		eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
-
-		pos += len;
-		left -= len;
-	}
-
-	if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
-			   "all the required fields");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
-				   u8 *pos, size_t len)
-{
-	u16 pac_type;
-	u32 lifetime;
-	struct os_time now;
-
-	switch (type & 0x7fff) {
-	case PAC_TYPE_CRED_LIFETIME:
-		if (len != 4) {
-			wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - "
-				    "Invalid CRED_LIFETIME length - ignored",
-				    pos, len);
-			return 0;
-		}
-
-		/*
-		 * This is not currently saved separately in PAC files since
-		 * the server can automatically initiate PAC update when
-		 * needed. Anyway, the information is available from PAC-Info
-		 * dump if it is needed for something in the future.
-		 */
-		lifetime = WPA_GET_BE32(pos);
-		os_get_time(&now);
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d "
-			   "(%d days)",
-			   lifetime, (lifetime - (u32) now.sec) / 86400);
-		break;
-	case PAC_TYPE_A_ID:
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID",
-				  pos, len);
-		entry->a_id = pos;
-		entry->a_id_len = len;
-		break;
-	case PAC_TYPE_I_ID:
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID",
-				  pos, len);
-		entry->i_id = pos;
-		entry->i_id_len = len;
-		break;
-	case PAC_TYPE_A_ID_INFO:
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info",
-				  pos, len);
-		entry->a_id_info = pos;
-		entry->a_id_info_len = len;
-		break;
-	case PAC_TYPE_PAC_TYPE:
-		/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
-		if (len != 2) {
-			wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
-				   "length %lu (expected 2)",
-				   (unsigned long) len);
-			wpa_hexdump_ascii(MSG_DEBUG,
-					  "EAP-FAST: PAC-Info - PAC-Type",
-					  pos, len);
-			return -1;
-		}
-		pac_type = WPA_GET_BE16(pos);
-		if (pac_type != PAC_TYPE_TUNNEL_PAC &&
-		    pac_type != PAC_TYPE_USER_AUTHORIZATION &&
-		    pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) {
-			wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type "
-				   "%d", pac_type);
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d",
-			   pac_type);
-		entry->pac_type = pac_type;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info "
-			   "type %d", type);
-		break;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
-{
-	struct pac_tlv_hdr *hdr;
-	u8 *pos;
-	size_t left, len;
-	int type;
-
-	/* RFC 5422, Section 4.2.4 */
-
-	/* PAC-Type defaults to Tunnel PAC (Type 1) */
-	entry->pac_type = PAC_TYPE_TUNNEL_PAC;
-
-	pos = entry->pac_info;
-	left = entry->pac_info_len;
-	while (left > sizeof(*hdr)) {
-		hdr = (struct pac_tlv_hdr *) pos;
-		type = be_to_host16(hdr->type);
-		len = be_to_host16(hdr->len);
-		pos += sizeof(*hdr);
-		left -= sizeof(*hdr);
-		if (len > left) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
-				   "(type=%d len=%lu left=%lu)",
-				   type, (unsigned long) len,
-				   (unsigned long) left);
-			return -1;
-		}
-
-		if (eap_fast_parse_pac_info(entry, type, pos, len) < 0)
-			return -1;
-
-		pos += len;
-		left -= len;
-	}
-
-	if (entry->a_id == NULL || entry->a_id_info == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
-			   "all the required fields");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
-					    struct eap_fast_data *data,
-					    struct eap_method_ret *ret,
-					    u8 *pac, size_t pac_len)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	struct eap_fast_pac entry;
-
-	os_memset(&entry, 0, sizeof(entry));
-	if (eap_fast_process_pac_tlv(&entry, pac, pac_len) ||
-	    eap_fast_process_pac_info(&entry))
-		return NULL;
-
-	eap_fast_add_pac(&data->pac, &data->current_pac, &entry);
-	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
-	if (data->use_pac_binary_format)
-		eap_fast_save_pac_bin(sm, data->pac, config->pac_file);
-	else
-		eap_fast_save_pac(sm, data->pac, config->pac_file);
-
-	if (data->provisioning) {
-		if (data->anon_provisioning) {
-			/*
-			 * Unauthenticated provisioning does not provide keying
-			 * material and must end with an EAP-Failure.
-			 * Authentication will be done separately after this.
-			 */
-			data->success = 0;
-			ret->decision = DECISION_FAIL;
-		} else {
-			/*
-			 * Server may or may not allow authenticated
-			 * provisioning also for key generation.
-			 */
-			ret->decision = DECISION_COND_SUCC;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
-			   "- Provisioning completed successfully");
-	} else {
-		/*
-		 * This is PAC refreshing, i.e., normal authentication that is
-		 * expected to be completed with an EAP-Success.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
-			   "- PAC refreshing completed successfully");
-		ret->decision = DECISION_UNCOND_SUCC;
-	}
-	ret->methodState = METHOD_DONE;
-	return eap_fast_tlv_pac_ack();
-}
-
-
-static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
-				    struct eap_fast_tlv_parse *tlv,
-				    struct wpabuf **resp)
-{
-	int mandatory, tlv_type, len, res;
-	u8 *pos, *end;
-
-	os_memset(tlv, 0, sizeof(*tlv));
-
-	/* Parse TLVs from the decrypted Phase 2 data */
-	pos = wpabuf_mhead(decrypted);
-	end = pos + wpabuf_len(decrypted);
-	while (pos + 4 < end) {
-		mandatory = pos[0] & 0x80;
-		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
-		pos += 2;
-		len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + len > end) {
-			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
-			   "TLV type %d length %d%s",
-			   tlv_type, len, mandatory ? " (mandatory)" : "");
-
-		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
-		if (res == -2)
-			break;
-		if (res < 0) {
-			if (mandatory) {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
-					   "mandatory TLV type %d", tlv_type);
-				*resp = eap_fast_tlv_nak(0, tlv_type);
-				break;
-			} else {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
-					   "unknown optional TLV type %d",
-					   tlv_type);
-			}
-		}
-
-		pos += len;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_encrypt_response(struct eap_sm *sm,
-				     struct eap_fast_data *data,
-				     struct wpabuf *resp,
-				     u8 identifier, struct wpabuf **out_data)
-{
-	if (resp == NULL)
-		return 0;
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
-			resp);
-	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
-				 data->fast_version, identifier,
-				 resp, out_data)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
-			   "frame");
-	}
-	wpabuf_free(resp);
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_pac_request(void)
-{
-	struct wpabuf *tmp;
-	u8 *pos, *pos2;
-
-	tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) +
-			   sizeof(struct eap_tlv_request_action_tlv) +
-			   sizeof(struct eap_tlv_pac_type_tlv));
-	if (tmp == NULL)
-		return NULL;
-
-	pos = wpabuf_put(tmp, 0);
-	pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
-	wpabuf_put(tmp, pos2 - pos);
-	return tmp;
-}
-
-
-static int eap_fast_process_decrypted(struct eap_sm *sm,
-				      struct eap_fast_data *data,
-				      struct eap_method_ret *ret,
-				      const struct eap_hdr *req,
-				      struct wpabuf *decrypted,
-				      struct wpabuf **out_data)
-{
-	struct wpabuf *resp = NULL, *tmp;
-	struct eap_fast_tlv_parse tlv;
-	int failed = 0;
-
-	if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0)
-		return 0;
-	if (resp)
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-
-	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
-		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-	}
-
-	if (tlv.iresult == EAP_TLV_RESULT_FAILURE) {
-		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-	}
-
-	if (tlv.crypto_binding) {
-		tmp = eap_fast_process_crypto_binding(sm, data, ret,
-						      tlv.crypto_binding,
-						      tlv.crypto_binding_len);
-		if (tmp == NULL)
-			failed = 1;
-		else
-			resp = wpabuf_concat(resp, tmp);
-	}
-
-	if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) {
-		tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE :
-					  EAP_TLV_RESULT_SUCCESS, 1);
-		resp = wpabuf_concat(resp, tmp);
-	}
-
-	if (tlv.eap_payload_tlv) {
-		tmp = eap_fast_process_eap_payload_tlv(
-			sm, data, ret, req, tlv.eap_payload_tlv,
-			tlv.eap_payload_tlv_len);
-		resp = wpabuf_concat(resp, tmp);
-	}
-
-	if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
-			   "acknowledging success");
-		failed = 1;
-	} else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
-		tmp = eap_fast_process_pac(sm, data, ret, tlv.pac,
-					   tlv.pac_len);
-		resp = wpabuf_concat(resp, tmp);
-	}
-
-	if (data->current_pac == NULL && data->provisioning &&
-	    !data->anon_provisioning && !tlv.pac &&
-	    (tlv.iresult == EAP_TLV_RESULT_SUCCESS ||
-	     tlv.result == EAP_TLV_RESULT_SUCCESS)) {
-		/*
-		 * Need to request Tunnel PAC when using authenticated
-		 * provisioning.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
-		tmp = eap_fast_pac_request();
-		resp = wpabuf_concat(resp, tmp);
-	}
-
-	if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
-		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
-		resp = wpabuf_concat(tmp, resp);
-	} else if (failed) {
-		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
-		resp = wpabuf_concat(tmp, resp);
-	}
-
-	if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
-	    tlv.crypto_binding && data->phase2_success) {
-		if (data->anon_provisioning) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
-				   "provisioning completed successfully.");
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
-				   "completed successfully.");
-			if (data->provisioning)
-				ret->methodState = METHOD_MAY_CONT;
-			else
-				ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_UNCOND_SUCC;
-		}
-	}
-
-	if (resp == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
-			   "empty response packet");
-		resp = wpabuf_alloc(1);
-	}
-
-	return eap_fast_encrypt_response(sm, data, resp, req->identifier,
-					 out_data);
-}
-
-
-static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
-			    struct eap_method_ret *ret,
-			    const struct eap_hdr *req,
-			    const struct wpabuf *in_data,
-			    struct wpabuf **out_data)
-{
-	struct wpabuf *in_decrypted;
-	int res;
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
-		   " Phase 2", (unsigned long) wpabuf_len(in_data));
-
-	if (data->pending_phase2_req) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: 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;
-		goto continue_req;
-	}
-
-	if (wpabuf_len(in_data) == 0) {
-		/* Received TLS ACK - requesting more fragments */
-		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
-					    data->fast_version,
-					    req->identifier, NULL, out_data);
-	}
-
-	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
-	if (res)
-		return res;
-
-continue_req:
-	wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
-			in_decrypted);
-
-	if (wpabuf_len(in_decrypted) < 4) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
-			   "TLV frame (len=%lu)",
-			   (unsigned long) wpabuf_len(in_decrypted));
-		wpabuf_free(in_decrypted);
-		return -1;
-	}
-
-	res = eap_fast_process_decrypted(sm, data, ret, req,
-					 in_decrypted, out_data);
-
-	wpabuf_free(in_decrypted);
-
-	return res;
-}
-
-
-static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len)
-{
-	const u8 *a_id;
-	struct pac_tlv_hdr *hdr;
-
-	/*
-	 * Parse authority identity (A-ID) from the EAP-FAST/Start. This
-	 * supports both raw A-ID and one inside an A-ID TLV.
-	 */
-	a_id = buf;
-	*id_len = len;
-	if (len > sizeof(*hdr)) {
-		int tlen;
-		hdr = (struct pac_tlv_hdr *) buf;
-		tlen = be_to_host16(hdr->len);
-		if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
-		    sizeof(*hdr) + tlen <= len) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV "
-				   "(Start)");
-			a_id = (u8 *) (hdr + 1);
-			*id_len = tlen;
-		}
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len);
-
-	return a_id;
-}
-
-
-static void eap_fast_select_pac(struct eap_fast_data *data,
-				const u8 *a_id, size_t a_id_len)
-{
-	data->current_pac = eap_fast_get_pac(data->pac, a_id, a_id_len,
-					     PAC_TYPE_TUNNEL_PAC);
-	if (data->current_pac == NULL) {
-		/*
-		 * Tunnel PAC was not available for this A-ID. Try to use
-		 * Machine Authentication PAC, if one is available.
-		 */
-		data->current_pac = eap_fast_get_pac(
-			data->pac, a_id, a_id_len,
-			PAC_TYPE_MACHINE_AUTHENTICATION);
-	}
-
-	if (data->current_pac) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this A-ID "
-			   "(PAC-Type %d)", data->current_pac->pac_type);
-		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
-				  data->current_pac->a_id_info,
-				  data->current_pac->a_id_info_len);
-	}
-}
-
-
-static int eap_fast_use_pac_opaque(struct eap_sm *sm,
-				   struct eap_fast_data *data,
-				   struct eap_fast_pac *pac)
-{
-	u8 *tlv;
-	size_t tlv_len, olen;
-	struct eap_tlv_hdr *ehdr;
-
-	olen = pac->pac_opaque_len;
-	tlv_len = sizeof(*ehdr) + olen;
-	tlv = os_malloc(tlv_len);
-	if (tlv) {
-		ehdr = (struct eap_tlv_hdr *) tlv;
-		ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
-		ehdr->length = host_to_be16(olen);
-		os_memcpy(ehdr + 1, pac->pac_opaque, olen);
-	}
-	if (tlv == NULL ||
-	    tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
-					    TLS_EXT_PAC_OPAQUE,
-					    tlv, tlv_len) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to add PAC-Opaque TLS "
-			   "extension");
-		os_free(tlv);
-		return -1;
-	}
-	os_free(tlv);
-
-	return 0;
-}
-
-
-static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
-					 struct eap_fast_data *data)
-{
-	if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
-					    TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to remove PAC-Opaque "
-			   "TLS extension");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
-					     struct eap_fast_data *data)
-{
-	u8 ciphers[5];
-	int count = 0;
-
-	if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling unauthenticated "
-			   "provisioning TLS cipher suites");
-		ciphers[count++] = TLS_CIPHER_ANON_DH_AES128_SHA;
-	}
-
-	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_AES128_SHA;
-		ciphers[count++] = TLS_CIPHER_AES128_SHA;
-		ciphers[count++] = TLS_CIPHER_RC4_SHA;
-	}
-
-	ciphers[count++] = TLS_CIPHER_NONE;
-
-	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
-					   ciphers)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Could not configure TLS "
-			   "cipher suites for provisioning");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_process_start(struct eap_sm *sm,
-				  struct eap_fast_data *data, u8 flags,
-				  const u8 *pos, size_t left)
-{
-	const u8 *a_id;
-	size_t a_id_len;
-
-	/* EAP-FAST Version negotiation (section 3.1) */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)",
-		   flags & EAP_TLS_VERSION_MASK, data->fast_version);
-	if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version)
-		data->fast_version = flags & EAP_TLS_VERSION_MASK;
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
-		   data->fast_version);
-
-	a_id = eap_fast_get_a_id(pos, left, &a_id_len);
-	eap_fast_select_pac(data, a_id, a_id_len);
-
-	if (data->resuming && data->current_pac) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume session - "
-			   "do not add PAC-Opaque to TLS ClientHello");
-		if (eap_fast_clear_pac_opaque_ext(sm, data) < 0)
-			return -1;
-	} else if (data->current_pac) {
-		/*
-		 * PAC found for the A-ID and we are not resuming an old
-		 * session, so add PAC-Opaque extension to ClientHello.
-		 */
-		if (eap_fast_use_pac_opaque(sm, data, data->current_pac) < 0)
-			return -1;
-	} else {
-		/* No PAC found, so we must provision one. */
-		if (!data->provisioning_allowed) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found and "
-				   "provisioning disabled");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
-			   "starting provisioning");
-		if (eap_fast_set_provisioning_ciphers(sm, data) < 0 ||
-		    eap_fast_clear_pac_opaque_ext(sm, data) < 0)
-			return -1;
-		data->provisioning = 1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
-					struct eap_method_ret *ret,
-					const struct wpabuf *reqData)
-{
-	const struct eap_hdr *req;
-	size_t left;
-	int res;
-	u8 flags, id;
-	struct wpabuf *resp;
-	const u8 *pos;
-	struct eap_fast_data *data = priv;
-
-	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
-					reqData, &left, &flags);
-	if (pos == NULL)
-		return NULL;
-
-	req = wpabuf_head(reqData);
-	id = req->identifier;
-
-	if (flags & EAP_TLS_FLAGS_START) {
-		if (eap_fast_process_start(sm, data, flags, pos, left) < 0)
-			return NULL;
-
-		left = 0; /* A-ID is not used in further packet processing */
-	}
-
-	resp = NULL;
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-	    !data->resuming) {
-		/* Process tunneled (encrypted) phase 2 data. */
-		struct wpabuf msg;
-		wpabuf_set(&msg, pos, left);
-		res = eap_fast_decrypt(sm, data, ret, req, &msg, &resp);
-		if (res < 0) {
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			/*
-			 * Ack possible Alert that may have caused failure in
-			 * decryption.
-			 */
-			res = 1;
-		}
-	} else {
-		/* Continue processing TLS handshake (phase 1). */
-		res = eap_peer_tls_process_helper(sm, &data->ssl,
-						  EAP_TYPE_FAST,
-						  data->fast_version, id, pos,
-						  left, &resp);
-
-		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			char cipher[80];
-			wpa_printf(MSG_DEBUG,
-				   "EAP-FAST: TLS done, proceed to Phase 2");
-			if (data->provisioning &&
-			    (!(data->provisioning_allowed &
-			       EAP_FAST_PROV_AUTH) ||
-			     tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
-					    cipher, sizeof(cipher)) < 0 ||
-			     os_strstr(cipher, "ADH-") ||
-			     os_strstr(cipher, "anon"))) {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Using "
-					   "anonymous (unauthenticated) "
-					   "provisioning");
-				data->anon_provisioning = 1;
-			} else
-				data->anon_provisioning = 0;
-			data->resuming = 0;
-			eap_fast_derive_keys(sm, data);
-		}
-
-		if (res == 2) {
-			struct wpabuf msg;
-			/*
-			 * Application data included in the handshake message.
-			 */
-			wpabuf_free(data->pending_phase2_req);
-			data->pending_phase2_req = resp;
-			resp = NULL;
-			wpabuf_set(&msg, pos, left);
-			res = eap_fast_decrypt(sm, data, ret, req, &msg,
-					       &resp);
-		}
-	}
-
-	if (res == 1) {
-		wpabuf_free(resp);
-		return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
-					      data->fast_version);
-	}
-
-	return resp;
-}
-
-
-#if 0 /* FIX */
-static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
-}
-
-
-static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	os_free(data->key_block_p);
-	data->key_block_p = NULL;
-	wpabuf_free(data->pending_phase2_req);
-	data->pending_phase2_req = NULL;
-}
-
-
-static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	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_success = 0;
-	data->resuming = 1;
-	data->provisioning = 0;
-	data->anon_provisioning = 0;
-	data->simck_idx = 0;
-	return priv;
-}
-#endif
-
-
-static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
-			       size_t buflen, int verbose)
-{
-	struct eap_fast_data *data = priv;
-	int len, ret;
-
-	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
-	if (data->phase2_method) {
-		ret = os_snprintf(buf + len, buflen - len,
-				  "EAP-FAST Phase2 method=%s\n",
-				  data->phase2_method->name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			return len;
-		len += ret;
-	}
-	return len;
-}
-
-
-static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	return data->success;
-}
-
-
-static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_fast_data *data = priv;
-	u8 *key;
-
-	if (!data->success)
-		return NULL;
-
-	key = os_malloc(EAP_FAST_KEY_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_FAST_KEY_LEN;
-	os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
-
-	return key;
-}
-
-
-static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_fast_data *data = priv;
-	u8 *key;
-
-	if (!data->success)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_EMSK_LEN;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_fast_init;
-	eap->deinit = eap_fast_deinit;
-	eap->process = eap_fast_process;
-	eap->isKeyAvailable = eap_fast_isKeyAvailable;
-	eap->getKey = eap_fast_getKey;
-	eap->get_status = eap_fast_get_status;
-#if 0
-	eap->has_reauth_data = eap_fast_has_reauth_data;
-	eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
-	eap->init_for_reauth = eap_fast_init_for_reauth;
-#endif
-	eap->get_emsk = eap_fast_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_fast.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_fast.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_fast.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1711 @@
+/*
+ * EAP peer method: EAP-FAST (RFC 4851)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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 "eap_common/eap_tlv_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+#include "eap_fast_pac.h"
+
+#ifdef EAP_FAST_DYNAMIC
+#include "eap_fast_pac.c"
+#endif /* EAP_FAST_DYNAMIC */
+
+/* TODO:
+ * - test session resumption and enable it if it interoperates
+ * - password change (pending mschapv2 packet; replay decrypted packet)
+ */
+
+
+static void eap_fast_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_fast_data {
+	struct eap_ssl_data ssl;
+
+	int fast_version;
+
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int phase2_success;
+
+	struct eap_method_type phase2_type;
+	struct eap_method_type *phase2_types;
+	size_t num_phase2_types;
+	int resuming; /* starting a resumed session */
+	struct eap_fast_key_block_provisioning *key_block_p;
+#define EAP_FAST_PROV_UNAUTH 1
+#define EAP_FAST_PROV_AUTH 2
+	int provisioning_allowed; /* Allowed PAC provisioning modes */
+	int provisioning; /* doing PAC provisioning (not the normal auth) */
+	int anon_provisioning; /* doing anonymous (unauthenticated)
+				* provisioning */
+	int session_ticket_used;
+
+	u8 key_data[EAP_FAST_KEY_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	int success;
+
+	struct eap_fast_pac *pac;
+	struct eap_fast_pac *current_pac;
+	size_t max_pac_list_len;
+	int use_pac_binary_format;
+
+	u8 simck[EAP_FAST_SIMCK_LEN];
+	int simck_idx;
+
+	struct wpabuf *pending_phase2_req;
+};
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+				      const u8 *client_random,
+				      const u8 *server_random,
+				      u8 *master_secret)
+{
+	struct eap_fast_data *data = ctx;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+
+	if (client_random == NULL || server_random == NULL ||
+	    master_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "
+			   "back to full TLS handshake");
+		data->session_ticket_used = 0;
+		if (data->provisioning_allowed) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "
+				   "new PAC-Key");
+			data->provisioning = 1;
+			data->current_pac = NULL;
+		}
+		return 0;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
+
+	if (data->current_pac == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
+			   "using SessionTicket");
+		data->session_ticket_used = 0;
+		return 0;
+	}
+
+	eap_fast_derive_master_secret(data->current_pac->pac_key,
+				      server_random, client_random,
+				      master_secret);
+
+	data->session_ticket_used = 1;
+
+	return 1;
+}
+
+
+static int eap_fast_parse_phase1(struct eap_fast_data *data,
+				 const char *phase1)
+{
+	const char *pos;
+
+	pos = os_strstr(phase1, "fast_provisioning=");
+	if (pos) {
+		data->provisioning_allowed = atoi(pos + 18);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning "
+			   "mode: %d", data->provisioning_allowed);
+	}
+
+	pos = os_strstr(phase1, "fast_max_pac_list_len=");
+	if (pos) {
+		data->max_pac_list_len = atoi(pos + 22);
+		if (data->max_pac_list_len == 0)
+			data->max_pac_list_len = 1;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu",
+			   (unsigned long) data->max_pac_list_len);
+	}
+
+	pos = os_strstr(phase1, "fast_pac_format=binary");
+	if (pos) {
+		data->use_pac_binary_format = 1;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "
+			   "list");
+	}
+
+	return 0;
+}
+
+
+static void * eap_fast_init(struct eap_sm *sm)
+{
+	struct eap_fast_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->fast_version = EAP_FAST_VERSION;
+	data->max_pac_list_len = 10;
+
+	if (config && config->phase1 &&
+	    eap_fast_parse_phase1(data, config->phase1) < 0) {
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	if (eap_peer_select_phase2_methods(config, "auth=",
+					   &data->phase2_types,
+					   &data->num_phase2_types) < 0) {
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	data->phase2_type.vendor = EAP_VENDOR_IETF;
+	data->phase2_type.method = EAP_TYPE_NONE;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_FAST)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+						 eap_fast_session_ticket_cb,
+						 data) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+			   "callback");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	/*
+	 * The local RADIUS server in a Cisco AP does not seem to like empty
+	 * fragments before data, so disable that workaround for CBC.
+	 * TODO: consider making this configurable
+	 */
+	if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS "
+			   "workarounds");
+	}
+
+	if (data->use_pac_binary_format &&
+	    eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	if (!data->use_pac_binary_format &&
+	    eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
+
+	if (data->pac == NULL && !data->provisioning_allowed) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "
+			   "provisioning disabled");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_fast_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	struct eap_fast_pac *pac, *prev;
+
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->deinit(sm, data->phase2_priv);
+	os_free(data->phase2_types);
+	os_free(data->key_block_p);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+
+	pac = data->pac;
+	prev = NULL;
+	while (pac) {
+		prev = pac;
+		pac = pac->next;
+		eap_fast_free_pac(prev);
+	}
+	wpabuf_free(data->pending_phase2_req);
+	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);
+	data->success = 1;
+	return 0;
+}
+
+
+static void eap_fast_derive_key_auth(struct eap_sm *sm,
+				     struct eap_fast_data *data)
+{
+	u8 *sks;
+
+	/* RFC 4851, Section 5.1:
+	 * Extra key material after TLS key_block: session_key_seed[40]
+	 */
+
+	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+				  EAP_FAST_SKS_LEN);
+	if (sks == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
+			   "session_key_seed");
+		return;
+	}
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			sks, EAP_FAST_SKS_LEN);
+	data->simck_idx = 0;
+	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+	os_free(sks);
+}
+
+
+static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
+					     struct eap_fast_data *data)
+{
+	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");
+		return;
+	}
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			data->key_block_p->session_key_seed,
+			sizeof(data->key_block_p->session_key_seed));
+	data->simck_idx = 0;
+	os_memcpy(data->simck, data->key_block_p->session_key_seed,
+		  EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
+			data->key_block_p->server_challenge,
+			sizeof(data->key_block_p->server_challenge));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
+			data->key_block_p->client_challenge,
+			sizeof(data->key_block_p->client_challenge));
+}
+
+
+static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
+{
+	if (data->anon_provisioning)
+		eap_fast_derive_key_provisioning(sm, data);
+	else
+		eap_fast_derive_key_auth(sm, data);
+}
+
+
+static int eap_fast_init_phase2_method(struct eap_sm *sm,
+				       struct eap_fast_data *data)
+{
+	data->phase2_method =
+		eap_peer_get_eap_method(data->phase2_type.vendor,
+					data->phase2_type.method);
+	if (data->phase2_method == NULL)
+		return -1;
+
+	if (data->key_block_p) {
+		sm->auth_challenge = data->key_block_p->server_challenge;
+		sm->peer_challenge = data->key_block_p->client_challenge;
+	}
+	sm->init_phase2 = 1;
+	data->phase2_priv = data->phase2_method->init(sm);
+	sm->init_phase2 = 0;
+	sm->auth_challenge = NULL;
+	sm->peer_challenge = NULL;
+
+	return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
+{
+	size_t i;
+
+	/* TODO: TNC with anonymous provisioning; need to require both
+	 * completed MSCHAPv2 and TNC */
+
+	if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
+			   "during unauthenticated provisioning; reject phase2"
+			   " type %d", type);
+		return -1;
+	}
+
+#ifdef EAP_TNC
+	if (type == EAP_TYPE_TNC) {
+		data->phase2_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_type.method = EAP_TYPE_TNC;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
+			   "vendor %d method %d for TNC",
+			   data->phase2_type.vendor,
+			   data->phase2_type.method);
+		return 0;
+	}
+#endif /* EAP_TNC */
+
+	for (i = 0; i < data->num_phase2_types; i++) {
+		if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
+		    data->phase2_types[i].method != type)
+			continue;
+
+		data->phase2_type.vendor = data->phase2_types[i].vendor;
+		data->phase2_type.method = data->phase2_types[i].method;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
+			   "vendor %d method %d",
+			   data->phase2_type.vendor,
+			   data->phase2_type.method);
+		break;
+	}
+
+	if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
+		return -1;
+
+	return 0;
+}
+
+
+static int eap_fast_phase2_request(struct eap_sm *sm,
+				   struct eap_fast_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_method_ret iret;
+	struct eap_peer_config *config = eap_get_config(sm);
+	struct wpabuf msg;
+
+	if (len <= sizeof(struct eap_hdr)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: too short "
+			   "Phase 2 request (len=%lu)", (unsigned long) len);
+		return -1;
+	}
+	pos = (u8 *) (hdr + 1);
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
+	if (*pos == EAP_TYPE_IDENTITY) {
+		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
+		return 0;
+	}
+
+	if (data->phase2_priv && data->phase2_method &&
+	    *pos != data->phase2_type.method) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
+			   "deinitialize previous method");
+		data->phase2_method->deinit(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+		data->phase2_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_type.method = EAP_TYPE_NONE;
+	}
+
+	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+	    data->phase2_type.method == EAP_TYPE_NONE &&
+	    eap_fast_select_phase2_method(data, *pos) < 0) {
+		if (eap_peer_tls_phase2_nak(data->phase2_types,
+					    data->num_phase2_types,
+					    hdr, resp))
+			return -1;
+		return 0;
+	}
+
+	if ((data->phase2_priv == NULL &&
+	     eap_fast_init_phase2_method(sm, data) < 0) ||
+	    data->phase2_method == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
+			   "Phase 2 EAP method %d", *pos);
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return -1;
+	}
+
+	os_memset(&iret, 0, sizeof(iret));
+	wpabuf_set(&msg, hdr, len);
+	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
+					     &msg);
+	if (*resp == NULL ||
+	    (iret.methodState == METHOD_DONE &&
+	     iret.decision == DECISION_FAIL)) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+	} else if ((iret.methodState == METHOD_DONE ||
+		    iret.methodState == METHOD_MAY_CONT) &&
+		   (iret.decision == DECISION_UNCOND_SUCC ||
+		    iret.decision == DECISION_COND_SUCC)) {
+		data->phase2_success = 1;
+	}
+
+	if (*resp == NULL && config &&
+	    (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_alloc_copy(hdr, len);
+	} else if (*resp == NULL)
+		return -1;
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type)
+{
+	struct wpabuf *buf;
+	struct eap_tlv_nak_tlv *nak;
+	buf = wpabuf_alloc(sizeof(*nak));
+	if (buf == NULL)
+		return NULL;
+	nak = wpabuf_put(buf, sizeof(*nak));
+	nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
+	nak->length = host_to_be16(6);
+	nak->vendor_id = host_to_be32(vendor_id);
+	nak->nak_type = host_to_be16(tlv_type);
+	return buf;
+}
+
+
+static struct wpabuf * eap_fast_tlv_result(int status, int intermediate)
+{
+	struct wpabuf *buf;
+	struct eap_tlv_intermediate_result_tlv *result;
+	buf = wpabuf_alloc(sizeof(*result));
+	if (buf == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)",
+		   intermediate ? "Intermediate " : "", status);
+	result = wpabuf_put(buf, sizeof(*result));
+	result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+					(intermediate ?
+					 EAP_TLV_INTERMEDIATE_RESULT_TLV :
+					 EAP_TLV_RESULT_TLV));
+	result->length = host_to_be16(2);
+	result->status = host_to_be16(status);
+	return buf;
+}
+
+
+static struct wpabuf * eap_fast_tlv_pac_ack(void)
+{
+	struct wpabuf *buf;
+	struct eap_tlv_result_tlv *res;
+	struct eap_tlv_pac_ack_tlv *ack;
+
+	buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
+	if (buf == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)");
+	ack = wpabuf_put(buf, sizeof(*ack));
+	ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |
+				     EAP_TLV_TYPE_MANDATORY);
+	ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));
+	ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
+	ack->pac_len = host_to_be16(2);
+	ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+	return buf;
+}
+
+
+static struct wpabuf * eap_fast_process_eap_payload_tlv(
+	struct eap_sm *sm, struct eap_fast_data *data,
+	struct eap_method_ret *ret,
+	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
+{
+	struct eap_hdr *hdr;
+	struct wpabuf *resp = NULL;
+
+	if (eap_payload_tlv_len < sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
+			   "Payload TLV (len=%lu)",
+			   (unsigned long) eap_payload_tlv_len);
+		return NULL;
+	}
+
+	hdr = (struct eap_hdr *) eap_payload_tlv;
+	if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in "
+			   "EAP Payload TLV");
+		return NULL;
+	}
+
+	if (hdr->code != EAP_CODE_REQUEST) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		return NULL;
+	}
+
+	if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing "
+			   "failed");
+		return NULL;
+	}
+
+	return eap_fast_tlv_eap_payload(resp);
+}
+
+
+static int eap_fast_validate_crypto_binding(
+	struct eap_tlv_crypto_binding_tlv *_bind)
+{
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
+		   "Received Version %d SubType %d",
+		   _bind->version, _bind->received_version, _bind->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    _bind->nonce, sizeof(_bind->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    _bind->compound_mac, sizeof(_bind->compound_mac));
+
+	if (_bind->version != EAP_FAST_VERSION ||
+	    _bind->received_version != EAP_FAST_VERSION ||
+	    _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
+			   "Crypto-Binding TLV: Version %d "
+			   "Received Version %d SubType %d",
+			   _bind->version, _bind->received_version,
+			   _bind->subtype);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void eap_fast_write_crypto_binding(
+	struct eap_tlv_crypto_binding_tlv *rbind,
+	struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk)
+{
+	rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+				       EAP_TLV_CRYPTO_BINDING_TLV);
+	rbind->length = host_to_be16(sizeof(*rbind) -
+				     sizeof(struct eap_tlv_hdr));
+	rbind->version = EAP_FAST_VERSION;
+	rbind->received_version = _bind->version;
+	rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
+	os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
+	inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
+	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind),
+		  rbind->compound_mac);
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
+		   "Received Version %d SubType %d",
+		   rbind->version, rbind->received_version, rbind->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    rbind->nonce, sizeof(rbind->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    rbind->compound_mac, sizeof(rbind->compound_mac));
+}
+
+
+static int eap_fast_get_phase2_key(struct eap_sm *sm,
+				   struct eap_fast_data *data,
+				   u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+
+	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+			   "available");
+		return -1;
+	}
+
+	if (data->phase2_method->isKeyAvailable == NULL ||
+	    data->phase2_method->getKey == NULL)
+		return 0;
+
+	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
+	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data,
+			    u8 *cmk)
+{
+	u8 isk[32], imck[60];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
+		   "calculation", data->simck_idx + 1);
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+	 *                 MSK[j], 60)
+	 * S-IMCK[j] = first 40 octets of IMCK[j]
+	 * CMK[j] = last 20 octets of IMCK[j]
+	 */
+
+	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));
+	data->simck_idx++;
+	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+			data->simck, EAP_FAST_SIMCK_LEN);
+	os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+			cmk, EAP_FAST_CMK_LEN);
+
+	return 0;
+}
+
+
+static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type)
+{
+	struct eap_tlv_hdr *pac;
+	struct eap_tlv_request_action_tlv *act;
+	struct eap_tlv_pac_type_tlv *type;
+
+	act = (struct eap_tlv_request_action_tlv *) pos;
+	act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV);
+	act->length = host_to_be16(2);
+	act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV);
+
+	pac = (struct eap_tlv_hdr *) (act + 1);
+	pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV);
+	pac->length = host_to_be16(sizeof(*type));
+
+	type = (struct eap_tlv_pac_type_tlv *) (pac + 1);
+	type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE);
+	type->length = host_to_be16(2);
+	type->pac_type = host_to_be16(pac_type);
+
+	return (u8 *) (type + 1);
+}
+
+
+static struct wpabuf * eap_fast_process_crypto_binding(
+	struct eap_sm *sm, struct eap_fast_data *data,
+	struct eap_method_ret *ret,
+	struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len)
+{
+	struct wpabuf *resp;
+	u8 *pos;
+	u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN];
+	int res;
+	size_t len;
+
+	if (eap_fast_validate_crypto_binding(_bind) < 0)
+		return NULL;
+
+	if (eap_fast_get_cmk(sm, data, cmk) < 0)
+		return NULL;
+
+	/* Validate received Compound MAC */
+	os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
+	os_memset(_bind->compound_mac, 0, sizeof(cmac));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
+		    "MAC calculation", (u8 *) _bind, bind_len);
+	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
+		  _bind->compound_mac);
+	res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
+		    cmac, sizeof(cmac));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
+		    _bind->compound_mac, sizeof(cmac));
+	if (res != 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
+		os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
+		return NULL;
+	}
+
+	/*
+	 * Compound MAC was valid, so authentication succeeded. Reply with
+	 * crypto binding to allow server to complete authentication.
+	 */
+
+	len = sizeof(struct eap_tlv_crypto_binding_tlv);
+	resp = wpabuf_alloc(len);
+	if (resp == NULL)
+		return NULL;
+
+	if (!data->anon_provisioning && data->phase2_success &&
+	    eap_fast_derive_msk(data) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		data->phase2_success = 0;
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
+	eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
+				      pos, _bind, cmk);
+
+	return resp;
+}
+
+
+static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type,
+				   u8 *pos, size_t len, int *pac_key_found)
+{
+	switch (type & 0x7fff) {
+	case PAC_TYPE_PAC_KEY:
+		wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len);
+		if (len != EAP_FAST_PAC_KEY_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key "
+				   "length %lu", (unsigned long) len);
+			break;
+		}
+		*pac_key_found = 1;
+		os_memcpy(entry->pac_key, pos, len);
+		break;
+	case PAC_TYPE_PAC_OPAQUE:
+		wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len);
+		entry->pac_opaque = pos;
+		entry->pac_opaque_len = len;
+		break;
+	case PAC_TYPE_PAC_INFO:
+		wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len);
+		entry->pac_info = pos;
+		entry->pac_info_len = len;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d",
+			   type);
+		break;
+	}
+}
+
+
+static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry,
+				    u8 *pac, size_t pac_len)
+{
+	struct pac_tlv_hdr *hdr;
+	u8 *pos;
+	size_t left, len;
+	int type, pac_key_found = 0;
+
+	pos = pac;
+	left = pac_len;
+
+	while (left > sizeof(*hdr)) {
+		hdr = (struct pac_tlv_hdr *) pos;
+		type = be_to_host16(hdr->type);
+		len = be_to_host16(hdr->len);
+		pos += sizeof(*hdr);
+		left -= sizeof(*hdr);
+		if (len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun "
+				   "(type=%d len=%lu left=%lu)",
+				   type, (unsigned long) len,
+				   (unsigned long) left);
+			return -1;
+		}
+
+		eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
+
+		pos += len;
+		left -= len;
+	}
+
+	if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include "
+			   "all the required fields");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
+				   u8 *pos, size_t len)
+{
+	u16 pac_type;
+	u32 lifetime;
+	struct os_time now;
+
+	switch (type & 0x7fff) {
+	case PAC_TYPE_CRED_LIFETIME:
+		if (len != 4) {
+			wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - "
+				    "Invalid CRED_LIFETIME length - ignored",
+				    pos, len);
+			return 0;
+		}
+
+		/*
+		 * This is not currently saved separately in PAC files since
+		 * the server can automatically initiate PAC update when
+		 * needed. Anyway, the information is available from PAC-Info
+		 * dump if it is needed for something in the future.
+		 */
+		lifetime = WPA_GET_BE32(pos);
+		os_get_time(&now);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d "
+			   "(%d days)",
+			   lifetime, (lifetime - (u32) now.sec) / 86400);
+		break;
+	case PAC_TYPE_A_ID:
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID",
+				  pos, len);
+		entry->a_id = pos;
+		entry->a_id_len = len;
+		break;
+	case PAC_TYPE_I_ID:
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID",
+				  pos, len);
+		entry->i_id = pos;
+		entry->i_id_len = len;
+		break;
+	case PAC_TYPE_A_ID_INFO:
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info",
+				  pos, len);
+		entry->a_id_info = pos;
+		entry->a_id_info_len = len;
+		break;
+	case PAC_TYPE_PAC_TYPE:
+		/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
+		if (len != 2) {
+			wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
+				   "length %lu (expected 2)",
+				   (unsigned long) len);
+			wpa_hexdump_ascii(MSG_DEBUG,
+					  "EAP-FAST: PAC-Info - PAC-Type",
+					  pos, len);
+			return -1;
+		}
+		pac_type = WPA_GET_BE16(pos);
+		if (pac_type != PAC_TYPE_TUNNEL_PAC &&
+		    pac_type != PAC_TYPE_USER_AUTHORIZATION &&
+		    pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) {
+			wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type "
+				   "%d", pac_type);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d",
+			   pac_type);
+		entry->pac_type = pac_type;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info "
+			   "type %d", type);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
+{
+	struct pac_tlv_hdr *hdr;
+	u8 *pos;
+	size_t left, len;
+	int type;
+
+	/* RFC 5422, Section 4.2.4 */
+
+	/* PAC-Type defaults to Tunnel PAC (Type 1) */
+	entry->pac_type = PAC_TYPE_TUNNEL_PAC;
+
+	pos = entry->pac_info;
+	left = entry->pac_info_len;
+	while (left > sizeof(*hdr)) {
+		hdr = (struct pac_tlv_hdr *) pos;
+		type = be_to_host16(hdr->type);
+		len = be_to_host16(hdr->len);
+		pos += sizeof(*hdr);
+		left -= sizeof(*hdr);
+		if (len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun "
+				   "(type=%d len=%lu left=%lu)",
+				   type, (unsigned long) len,
+				   (unsigned long) left);
+			return -1;
+		}
+
+		if (eap_fast_parse_pac_info(entry, type, pos, len) < 0)
+			return -1;
+
+		pos += len;
+		left -= len;
+	}
+
+	if (entry->a_id == NULL || entry->a_id_info == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include "
+			   "all the required fields");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm,
+					    struct eap_fast_data *data,
+					    struct eap_method_ret *ret,
+					    u8 *pac, size_t pac_len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	struct eap_fast_pac entry;
+
+	os_memset(&entry, 0, sizeof(entry));
+	if (eap_fast_process_pac_tlv(&entry, pac, pac_len) ||
+	    eap_fast_process_pac_info(&entry))
+		return NULL;
+
+	eap_fast_add_pac(&data->pac, &data->current_pac, &entry);
+	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
+	if (data->use_pac_binary_format)
+		eap_fast_save_pac_bin(sm, data->pac, config->pac_file);
+	else
+		eap_fast_save_pac(sm, data->pac, config->pac_file);
+
+	if (data->provisioning) {
+		if (data->anon_provisioning) {
+			/*
+			 * Unauthenticated provisioning does not provide keying
+			 * material and must end with an EAP-Failure.
+			 * Authentication will be done separately after this.
+			 */
+			data->success = 0;
+			ret->decision = DECISION_FAIL;
+		} else {
+			/*
+			 * Server may or may not allow authenticated
+			 * provisioning also for key generation.
+			 */
+			ret->decision = DECISION_COND_SUCC;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
+			   "- Provisioning completed successfully");
+	} else {
+		/*
+		 * This is PAC refreshing, i.e., normal authentication that is
+		 * expected to be completed with an EAP-Success. However,
+		 * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
+		 * after protected success exchange in case of EAP-Fast
+		 * provisioning, so we better use DECISION_COND_SUCC here
+		 * instead of DECISION_UNCOND_SUCC.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
+			   "- PAC refreshing completed successfully");
+		ret->decision = DECISION_COND_SUCC;
+	}
+	ret->methodState = METHOD_DONE;
+	return eap_fast_tlv_pac_ack();
+}
+
+
+static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
+				    struct eap_fast_tlv_parse *tlv,
+				    struct wpabuf **resp)
+{
+	int mandatory, tlv_type, len, res;
+	u8 *pos, *end;
+
+	os_memset(tlv, 0, sizeof(*tlv));
+
+	/* Parse TLVs from the decrypted Phase 2 data */
+	pos = wpabuf_mhead(decrypted);
+	end = pos + wpabuf_len(decrypted);
+	while (pos + 4 < end) {
+		mandatory = pos[0] & 0x80;
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + len > end) {
+			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
+			   "TLV type %d length %d%s",
+			   tlv_type, len, mandatory ? " (mandatory)" : "");
+
+		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
+		if (res == -2)
+			break;
+		if (res < 0) {
+			if (mandatory) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
+					   "mandatory TLV type %d", tlv_type);
+				*resp = eap_fast_tlv_nak(0, tlv_type);
+				break;
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
+					   "unknown optional TLV type %d",
+					   tlv_type);
+			}
+		}
+
+		pos += len;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_encrypt_response(struct eap_sm *sm,
+				     struct eap_fast_data *data,
+				     struct wpabuf *resp,
+				     u8 identifier, struct wpabuf **out_data)
+{
+	if (resp == NULL)
+		return 0;
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data",
+			resp);
+	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
+				 data->fast_version, identifier,
+				 resp, out_data)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
+			   "frame");
+	}
+	wpabuf_free(resp);
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_pac_request(void)
+{
+	struct wpabuf *tmp;
+	u8 *pos, *pos2;
+
+	tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) +
+			   sizeof(struct eap_tlv_request_action_tlv) +
+			   sizeof(struct eap_tlv_pac_type_tlv));
+	if (tmp == NULL)
+		return NULL;
+
+	pos = wpabuf_put(tmp, 0);
+	pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
+	wpabuf_put(tmp, pos2 - pos);
+	return tmp;
+}
+
+
+static int eap_fast_process_decrypted(struct eap_sm *sm,
+				      struct eap_fast_data *data,
+				      struct eap_method_ret *ret,
+				      const struct eap_hdr *req,
+				      struct wpabuf *decrypted,
+				      struct wpabuf **out_data)
+{
+	struct wpabuf *resp = NULL, *tmp;
+	struct eap_fast_tlv_parse tlv;
+	int failed = 0;
+
+	if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0)
+		return 0;
+	if (resp)
+		return eap_fast_encrypt_response(sm, data, resp,
+						 req->identifier, out_data);
+
+	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
+		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+		return eap_fast_encrypt_response(sm, data, resp,
+						 req->identifier, out_data);
+	}
+
+	if (tlv.iresult == EAP_TLV_RESULT_FAILURE) {
+		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
+		return eap_fast_encrypt_response(sm, data, resp,
+						 req->identifier, out_data);
+	}
+
+	if (tlv.crypto_binding) {
+		tmp = eap_fast_process_crypto_binding(sm, data, ret,
+						      tlv.crypto_binding,
+						      tlv.crypto_binding_len);
+		if (tmp == NULL)
+			failed = 1;
+		else
+			resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) {
+		tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE :
+					  EAP_TLV_RESULT_SUCCESS, 1);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.eap_payload_tlv) {
+		tmp = eap_fast_process_eap_payload_tlv(
+			sm, data, ret, tlv.eap_payload_tlv,
+			tlv.eap_payload_tlv_len);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
+			   "acknowledging success");
+		failed = 1;
+	} else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
+		tmp = eap_fast_process_pac(sm, data, ret, tlv.pac,
+					   tlv.pac_len);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (data->current_pac == NULL && data->provisioning &&
+	    !data->anon_provisioning && !tlv.pac &&
+	    (tlv.iresult == EAP_TLV_RESULT_SUCCESS ||
+	     tlv.result == EAP_TLV_RESULT_SUCCESS)) {
+		/*
+		 * Need to request Tunnel PAC when using authenticated
+		 * provisioning.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
+		tmp = eap_fast_pac_request();
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
+		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
+		resp = wpabuf_concat(tmp, resp);
+	} else if (failed) {
+		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+		resp = wpabuf_concat(tmp, resp);
+	}
+
+	if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
+	    tlv.crypto_binding && data->phase2_success) {
+		if (data->anon_provisioning) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
+				   "provisioning completed successfully.");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+				   "completed successfully.");
+			if (data->provisioning)
+				ret->methodState = METHOD_MAY_CONT;
+			else
+				ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_UNCOND_SUCC;
+		}
+	}
+
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
+			   "empty response packet");
+		resp = wpabuf_alloc(1);
+	}
+
+	return eap_fast_encrypt_response(sm, data, resp, req->identifier,
+					 out_data);
+}
+
+
+static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
+			    struct eap_method_ret *ret,
+			    const struct eap_hdr *req,
+			    const struct wpabuf *in_data,
+			    struct wpabuf **out_data)
+{
+	struct wpabuf *in_decrypted;
+	int res;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_data));
+
+	if (data->pending_phase2_req) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: 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;
+		goto continue_req;
+	}
+
+	if (wpabuf_len(in_data) == 0) {
+		/* Received TLS ACK - requesting more fragments */
+		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST,
+					    data->fast_version,
+					    req->identifier, NULL, out_data);
+	}
+
+	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
+	if (res)
+		return res;
+
+continue_req:
+	wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)",
+			in_decrypted);
+
+	if (wpabuf_len(in_decrypted) < 4) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
+			   "TLV frame (len=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted));
+		wpabuf_free(in_decrypted);
+		return -1;
+	}
+
+	res = eap_fast_process_decrypted(sm, data, ret, req,
+					 in_decrypted, out_data);
+
+	wpabuf_free(in_decrypted);
+
+	return res;
+}
+
+
+static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len)
+{
+	const u8 *a_id;
+	struct pac_tlv_hdr *hdr;
+
+	/*
+	 * Parse authority identity (A-ID) from the EAP-FAST/Start. This
+	 * supports both raw A-ID and one inside an A-ID TLV.
+	 */
+	a_id = buf;
+	*id_len = len;
+	if (len > sizeof(*hdr)) {
+		int tlen;
+		hdr = (struct pac_tlv_hdr *) buf;
+		tlen = be_to_host16(hdr->len);
+		if (be_to_host16(hdr->type) == PAC_TYPE_A_ID &&
+		    sizeof(*hdr) + tlen <= len) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV "
+				   "(Start)");
+			a_id = (u8 *) (hdr + 1);
+			*id_len = tlen;
+		}
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len);
+
+	return a_id;
+}
+
+
+static void eap_fast_select_pac(struct eap_fast_data *data,
+				const u8 *a_id, size_t a_id_len)
+{
+	data->current_pac = eap_fast_get_pac(data->pac, a_id, a_id_len,
+					     PAC_TYPE_TUNNEL_PAC);
+	if (data->current_pac == NULL) {
+		/*
+		 * Tunnel PAC was not available for this A-ID. Try to use
+		 * Machine Authentication PAC, if one is available.
+		 */
+		data->current_pac = eap_fast_get_pac(
+			data->pac, a_id, a_id_len,
+			PAC_TYPE_MACHINE_AUTHENTICATION);
+	}
+
+	if (data->current_pac) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this A-ID "
+			   "(PAC-Type %d)", data->current_pac->pac_type);
+		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info",
+				  data->current_pac->a_id_info,
+				  data->current_pac->a_id_info_len);
+	}
+}
+
+
+static int eap_fast_use_pac_opaque(struct eap_sm *sm,
+				   struct eap_fast_data *data,
+				   struct eap_fast_pac *pac)
+{
+	u8 *tlv;
+	size_t tlv_len, olen;
+	struct eap_tlv_hdr *ehdr;
+
+	olen = pac->pac_opaque_len;
+	tlv_len = sizeof(*ehdr) + olen;
+	tlv = os_malloc(tlv_len);
+	if (tlv) {
+		ehdr = (struct eap_tlv_hdr *) tlv;
+		ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
+		ehdr->length = host_to_be16(olen);
+		os_memcpy(ehdr + 1, pac->pac_opaque, olen);
+	}
+	if (tlv == NULL ||
+	    tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
+					    TLS_EXT_PAC_OPAQUE,
+					    tlv, tlv_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to add PAC-Opaque TLS "
+			   "extension");
+		os_free(tlv);
+		return -1;
+	}
+	os_free(tlv);
+
+	return 0;
+}
+
+
+static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm,
+					 struct eap_fast_data *data)
+{
+	if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
+					    TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to remove PAC-Opaque "
+			   "TLS extension");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm,
+					     struct eap_fast_data *data)
+{
+	u8 ciphers[5];
+	int count = 0;
+
+	if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling unauthenticated "
+			   "provisioning TLS cipher suites");
+		ciphers[count++] = TLS_CIPHER_ANON_DH_AES128_SHA;
+	}
+
+	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_AES128_SHA;
+		ciphers[count++] = TLS_CIPHER_AES128_SHA;
+		ciphers[count++] = TLS_CIPHER_RC4_SHA;
+	}
+
+	ciphers[count++] = TLS_CIPHER_NONE;
+
+	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+					   ciphers)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Could not configure TLS "
+			   "cipher suites for provisioning");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_process_start(struct eap_sm *sm,
+				  struct eap_fast_data *data, u8 flags,
+				  const u8 *pos, size_t left)
+{
+	const u8 *a_id;
+	size_t a_id_len;
+
+	/* EAP-FAST Version negotiation (section 3.1) */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)",
+		   flags & EAP_TLS_VERSION_MASK, data->fast_version);
+	if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version)
+		data->fast_version = flags & EAP_TLS_VERSION_MASK;
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d",
+		   data->fast_version);
+
+	a_id = eap_fast_get_a_id(pos, left, &a_id_len);
+	eap_fast_select_pac(data, a_id, a_id_len);
+
+	if (data->resuming && data->current_pac) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume session - "
+			   "do not add PAC-Opaque to TLS ClientHello");
+		if (eap_fast_clear_pac_opaque_ext(sm, data) < 0)
+			return -1;
+	} else if (data->current_pac) {
+		/*
+		 * PAC found for the A-ID and we are not resuming an old
+		 * session, so add PAC-Opaque extension to ClientHello.
+		 */
+		if (eap_fast_use_pac_opaque(sm, data, data->current_pac) < 0)
+			return -1;
+	} else {
+		/* No PAC found, so we must provision one. */
+		if (!data->provisioning_allowed) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found and "
+				   "provisioning disabled");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
+			   "starting provisioning");
+		if (eap_fast_set_provisioning_ciphers(sm, data) < 0 ||
+		    eap_fast_clear_pac_opaque_ext(sm, data) < 0)
+			return -1;
+		data->provisioning = 1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	const struct eap_hdr *req;
+	size_t left;
+	int res;
+	u8 flags, id;
+	struct wpabuf *resp;
+	const u8 *pos;
+	struct eap_fast_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
+					reqData, &left, &flags);
+	if (pos == NULL)
+		return NULL;
+
+	req = wpabuf_head(reqData);
+	id = req->identifier;
+
+	if (flags & EAP_TLS_FLAGS_START) {
+		if (eap_fast_process_start(sm, data, flags, pos, left) < 0)
+			return NULL;
+
+		left = 0; /* A-ID is not used in further packet processing */
+	}
+
+	resp = NULL;
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+	    !data->resuming) {
+		/* Process tunneled (encrypted) phase 2 data. */
+		struct wpabuf msg;
+		wpabuf_set(&msg, pos, left);
+		res = eap_fast_decrypt(sm, data, ret, req, &msg, &resp);
+		if (res < 0) {
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			/*
+			 * Ack possible Alert that may have caused failure in
+			 * decryption.
+			 */
+			res = 1;
+		}
+	} else {
+		/* Continue processing TLS handshake (phase 1). */
+		res = eap_peer_tls_process_helper(sm, &data->ssl,
+						  EAP_TYPE_FAST,
+						  data->fast_version, id, pos,
+						  left, &resp);
+
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			char cipher[80];
+			wpa_printf(MSG_DEBUG,
+				   "EAP-FAST: TLS done, proceed to Phase 2");
+			if (data->provisioning &&
+			    (!(data->provisioning_allowed &
+			       EAP_FAST_PROV_AUTH) ||
+			     tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
+					    cipher, sizeof(cipher)) < 0 ||
+			     os_strstr(cipher, "ADH-") ||
+			     os_strstr(cipher, "anon"))) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Using "
+					   "anonymous (unauthenticated) "
+					   "provisioning");
+				data->anon_provisioning = 1;
+			} else
+				data->anon_provisioning = 0;
+			data->resuming = 0;
+			eap_fast_derive_keys(sm, data);
+		}
+
+		if (res == 2) {
+			struct wpabuf msg;
+			/*
+			 * Application data included in the handshake message.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = resp;
+			resp = NULL;
+			wpabuf_set(&msg, pos, left);
+			res = eap_fast_decrypt(sm, data, ret, req, &msg,
+					       &resp);
+		}
+	}
+
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
+					      data->fast_version);
+	}
+
+	return resp;
+}
+
+
+#if 0 /* FIX */
+static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	os_free(data->key_block_p);
+	data->key_block_p = NULL;
+	wpabuf_free(data->pending_phase2_req);
+	data->pending_phase2_req = NULL;
+}
+
+
+static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	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_success = 0;
+	data->resuming = 1;
+	data->provisioning = 0;
+	data->anon_provisioning = 0;
+	data->simck_idx = 0;
+	return priv;
+}
+#endif
+
+
+static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
+			       size_t buflen, int verbose)
+{
+	struct eap_fast_data *data = priv;
+	int len, ret;
+
+	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+	if (data->phase2_method) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "EAP-FAST Phase2 method=%s\n",
+				  data->phase2_method->name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+	return len;
+}
+
+
+static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return data->success;
+}
+
+
+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *key;
+
+	if (!data->success)
+		return NULL;
+
+	key = os_malloc(EAP_FAST_KEY_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_FAST_KEY_LEN;
+	os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
+
+	return key;
+}
+
+
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *key;
+
+	if (!data->success)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_fast_init;
+	eap->deinit = eap_fast_deinit;
+	eap->process = eap_fast_process;
+	eap->isKeyAvailable = eap_fast_isKeyAvailable;
+	eap->getKey = eap_fast_getKey;
+	eap->get_status = eap_fast_get_status;
+#if 0
+	eap->has_reauth_data = eap_fast_has_reauth_data;
+	eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
+	eap->init_for_reauth = eap_fast_init_for_reauth;
+#endif
+	eap->get_emsk = eap_fast_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_fast_pac.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,922 +0,0 @@
-/*
- * EAP peer method: EAP-FAST PAC file processing
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_config.h"
-#include "eap_i.h"
-#include "eap_fast_pac.h"
-
-/* TODO: encrypt PAC-Key in the PAC file */
-
-
-/* Text data format */
-static const char *pac_file_hdr =
-	"wpa_supplicant EAP-FAST PAC file - version 1";
-
-/*
- * Binary data format
- * 4-octet magic value: 6A E4 92 0C
- * 2-octet version (big endian)
- * <version specific data>
- *
- * version=0:
- * Sequence of PAC entries:
- *   2-octet PAC-Type (big endian)
- *   32-octet PAC-Key
- *   2-octet PAC-Opaque length (big endian)
- *   <variable len> PAC-Opaque data (length bytes)
- *   2-octet PAC-Info length (big endian)
- *   <variable len> PAC-Info data (length bytes)
- */
-
-#define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
-#define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
-
-
-/**
- * eap_fast_free_pac - Free PAC data
- * @pac: Pointer to the PAC entry
- *
- * Note that the PAC entry must not be in a list since this function does not
- * remove the list links.
- */
-void eap_fast_free_pac(struct eap_fast_pac *pac)
-{
-	os_free(pac->pac_opaque);
-	os_free(pac->pac_info);
-	os_free(pac->a_id);
-	os_free(pac->i_id);
-	os_free(pac->a_id_info);
-	os_free(pac);
-}
-
-
-/**
- * eap_fast_get_pac - Get a PAC entry based on A-ID
- * @pac_root: Pointer to root of the PAC list
- * @a_id: A-ID to search for
- * @a_id_len: Length of A-ID
- * @pac_type: PAC-Type to search for
- * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
- */
-struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
-				       const u8 *a_id, size_t a_id_len,
-				       u16 pac_type)
-{
-	struct eap_fast_pac *pac = pac_root;
-
-	while (pac) {
-		if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
-		    os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
-			return pac;
-		}
-		pac = pac->next;
-	}
-	return NULL;
-}
-
-
-static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
-				struct eap_fast_pac **pac_current,
-				const u8 *a_id, size_t a_id_len, u16 pac_type)
-{
-	struct eap_fast_pac *pac, *prev;
-
-	pac = *pac_root;
-	prev = NULL;
-
-	while (pac) {
-		if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
-		    os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
-			if (prev == NULL)
-				*pac_root = pac->next;
-			else
-				prev->next = pac->next;
-			if (*pac_current == pac)
-				*pac_current = NULL;
-			eap_fast_free_pac(pac);
-			break;
-		}
-		prev = pac;
-		pac = pac->next;
-	}
-}
-
-
-static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
-			     const u8 *src, size_t src_len)
-{
-	if (src) {
-		*dst = os_malloc(src_len);
-		if (*dst == NULL)
-			return -1;
-		os_memcpy(*dst, src, src_len);
-		*dst_len = src_len;
-	}
-	return 0;
-}
-
-
-/**
- * eap_fast_add_pac - Add a copy of a PAC entry to a list
- * @pac_root: Pointer to PAC list root pointer
- * @pac_current: Pointer to the current PAC pointer
- * @entry: New entry to clone and add to the list
- * Returns: 0 on success, -1 on failure
- *
- * This function makes a clone of the given PAC entry and adds this copied
- * entry to the list (pac_root). If an old entry for the same A-ID is found,
- * it will be removed from the PAC list and in this case, pac_current entry
- * is set to %NULL if it was the removed entry.
- */
-int eap_fast_add_pac(struct eap_fast_pac **pac_root,
-		     struct eap_fast_pac **pac_current,
-		     struct eap_fast_pac *entry)
-{
-	struct eap_fast_pac *pac;
-
-	if (entry == NULL || entry->a_id == NULL)
-		return -1;
-
-	/* Remove a possible old entry for the matching A-ID. */
-	eap_fast_remove_pac(pac_root, pac_current,
-			    entry->a_id, entry->a_id_len, entry->pac_type);
-
-	/* Allocate a new entry and add it to the list of PACs. */
-	pac = os_zalloc(sizeof(*pac));
-	if (pac == NULL)
-		return -1;
-
-	pac->pac_type = entry->pac_type;
-	os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
-	if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
-			      entry->pac_opaque, entry->pac_opaque_len) < 0 ||
-	    eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
-			      entry->pac_info, entry->pac_info_len) < 0 ||
-	    eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
-			      entry->a_id, entry->a_id_len) < 0 ||
-	    eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
-			      entry->i_id, entry->i_id_len) < 0 ||
-	    eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
-			      entry->a_id_info, entry->a_id_info_len) < 0) {
-		eap_fast_free_pac(pac);
-		return -1;
-	}
-
-	pac->next = *pac_root;
-	*pac_root = pac;
-
-	return 0;
-}
-
-
-struct eap_fast_read_ctx {
-	FILE *f;
-	const char *pos;
-	const char *end;
-	int line;
-	char *buf;
-	size_t buf_len;
-};
-
-static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
-{
-	char *pos;
-
-	rc->line++;
-	if (rc->f) {
-		if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
-			return -1;
-	} else {
-		const char *l_end;
-		size_t len;
-		if (rc->pos >= rc->end)
-			return -1;
-		l_end = rc->pos;
-		while (l_end < rc->end && *l_end != '\n')
-			l_end++;
-		len = l_end - rc->pos;
-		if (len >= rc->buf_len)
-			len = rc->buf_len - 1;
-		os_memcpy(rc->buf, rc->pos, len);
-		rc->buf[len] = '\0';
-		rc->pos = l_end + 1;
-	}
-
-	rc->buf[rc->buf_len - 1] = '\0';
-	pos = rc->buf;
-	while (*pos != '\0') {
-		if (*pos == '\n' || *pos == '\r') {
-			*pos = '\0';
-			break;
-		}
-		pos++;
-	}
-
-	pos = os_strchr(rc->buf, '=');
-	if (pos)
-		*pos++ = '\0';
-	*value = pos;
-
-	return 0;
-}
-
-
-static u8 * eap_fast_parse_hex(const char *value, size_t *len)
-{
-	int hlen;
-	u8 *buf;
-
-	if (value == NULL)
-		return NULL;
-	hlen = os_strlen(value);
-	if (hlen & 1)
-		return NULL;
-	*len = hlen / 2;
-	buf = os_malloc(*len);
-	if (buf == NULL)
-		return NULL;
-	if (hexstr2bin(value, buf, *len)) {
-		os_free(buf);
-		return NULL;
-	}
-	return buf;
-}
-
-
-static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
-				  struct eap_fast_read_ctx *rc)
-{
-	os_memset(rc, 0, sizeof(*rc));
-
-	rc->buf_len = 2048;
-	rc->buf = os_malloc(rc->buf_len);
-	if (rc->buf == NULL)
-		return -1;
-
-	if (os_strncmp(pac_file, "blob://", 7) == 0) {
-		const struct wpa_config_blob *blob;
-		blob = eap_get_config_blob(sm, pac_file + 7);
-		if (blob == NULL) {
-			wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
-				   "assume no PAC entries have been "
-				   "provisioned", pac_file + 7);
-			os_free(rc->buf);
-			return -1;
-		}
-		rc->pos = (char *) blob->data;
-		rc->end = (char *) blob->data + blob->len;
-	} else {
-		rc->f = fopen(pac_file, "rb");
-		if (rc->f == NULL) {
-			wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
-				   "assume no PAC entries have been "
-				   "provisioned", pac_file);
-			os_free(rc->buf);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
-{
-	os_free(rc->buf);
-	if (rc->f)
-		fclose(rc->f);
-}
-
-
-static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
-{
-	if (*pac)
-		return "START line without END";
-
-	*pac = os_zalloc(sizeof(struct eap_fast_pac));
-	if (*pac == NULL)
-		return "No memory for PAC entry";
-	(*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
-				       struct eap_fast_pac **pac)
-{
-	if (*pac == NULL)
-		return "END line without START";
-	if (*pac_root) {
-		struct eap_fast_pac *end = *pac_root;
-		while (end->next)
-			end = end->next;
-		end->next = *pac;
-	} else
-		*pac_root = *pac;
-
-	*pac = NULL;
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
-					    char *pos)
-{
-	pac->pac_type = atoi(pos);
-	if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
-	    pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
-	    pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
-		return "Unrecognized PAC-Type";
-
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
-{
-	u8 *key;
-	size_t key_len;
-
-	key = eap_fast_parse_hex(pos, &key_len);
-	if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
-		os_free(key);
-		return "Invalid PAC-Key";
-	}
-
-	os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
-	os_free(key);
-
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
-					      char *pos)
-{
-	os_free(pac->pac_opaque);
-	pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
-	if (pac->pac_opaque == NULL)
-		return "Invalid PAC-Opaque";
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
-{
-	os_free(pac->a_id);
-	pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
-	if (pac->a_id == NULL)
-		return "Invalid A-ID";
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
-{
-	os_free(pac->i_id);
-	pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
-	if (pac->i_id == NULL)
-		return "Invalid I-ID";
-	return NULL;
-}
-
-
-static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
-					     char *pos)
-{
-	os_free(pac->a_id_info);
-	pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len);
-	if (pac->a_id_info == NULL)
-		return "Invalid A-ID-Info";
-	return NULL;
-}
-
-
-/**
- * eap_fast_load_pac - Load PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
-int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
-		      const char *pac_file)
-{
-	struct eap_fast_read_ctx rc;
-	struct eap_fast_pac *pac = NULL;
-	int count = 0;
-	char *pos;
-	const char *err = NULL;
-
-	if (pac_file == NULL)
-		return -1;
-
-	if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
-		return 0;
-
-	if (eap_fast_read_line(&rc, &pos) < 0 ||
-	    os_strcmp(pac_file_hdr, rc.buf) != 0)
-		err = "Unrecognized header line";
-
-	while (!err && eap_fast_read_line(&rc, &pos) == 0) {
-		if (os_strcmp(rc.buf, "START") == 0)
-			err = eap_fast_parse_start(&pac);
-		else if (os_strcmp(rc.buf, "END") == 0) {
-			err = eap_fast_parse_end(pac_root, &pac);
-			count++;
-		} else if (!pac)
-			err = "Unexpected line outside START/END block";
-		else if (os_strcmp(rc.buf, "PAC-Type") == 0)
-			err = eap_fast_parse_pac_type(pac, pos);
-		else if (os_strcmp(rc.buf, "PAC-Key") == 0)
-			err = eap_fast_parse_pac_key(pac, pos);
-		else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
-			err = eap_fast_parse_pac_opaque(pac, pos);
-		else if (os_strcmp(rc.buf, "A-ID") == 0)
-			err = eap_fast_parse_a_id(pac, pos);
-		else if (os_strcmp(rc.buf, "I-ID") == 0)
-			err = eap_fast_parse_i_id(pac, pos);
-		else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
-			err = eap_fast_parse_a_id_info(pac, pos);
-	}
-
-	if (pac) {
-		err = "PAC block not terminated with END";
-		eap_fast_free_pac(pac);
-	}
-
-	eap_fast_deinit_pac_data(&rc);
-
-	if (err) {
-		wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
-			   err, pac_file, rc.line);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
-		   count, pac_file);
-
-	return 0;
-}
-
-
-static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
-			   const char *field, const u8 *data,
-			   size_t len, int txt)
-{
-	size_t i, need;
-	int ret;
-	char *end;
-
-	if (data == NULL || buf == NULL || *buf == NULL ||
-	    pos == NULL || *pos == NULL || *pos < *buf)
-		return;
-
-	need = os_strlen(field) + len * 2 + 30;
-	if (txt)
-		need += os_strlen(field) + len + 20;
-
-	if (*pos - *buf + need > *buf_len) {
-		char *nbuf = os_realloc(*buf, *buf_len + need);
-		if (nbuf == NULL) {
-			os_free(*buf);
-			*buf = NULL;
-			return;
-		}
-		*buf = nbuf;
-		*buf_len += need;
-	}
-	end = *buf + *buf_len;
-
-	ret = os_snprintf(*pos, end - *pos, "%s=", field);
-	if (ret < 0 || ret >= end - *pos)
-		return;
-	*pos += ret;
-	*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
-	ret = os_snprintf(*pos, end - *pos, "\n");
-	if (ret < 0 || ret >= end - *pos)
-		return;
-	*pos += ret;
-
-	if (txt) {
-		ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
-		if (ret < 0 || ret >= end - *pos)
-			return;
-		*pos += ret;
-		for (i = 0; i < len; i++) {
-			ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
-			if (ret < 0 || ret >= end - *pos)
-				return;
-			*pos += ret;
-		}
-		ret = os_snprintf(*pos, end - *pos, "\n");
-		if (ret < 0 || ret >= end - *pos)
-			return;
-		*pos += ret;
-	}
-}
-
-
-static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
-			      char *buf, size_t len)
-{
-	if (os_strncmp(pac_file, "blob://", 7) == 0) {
-		struct wpa_config_blob *blob;
-		blob = os_zalloc(sizeof(*blob));
-		if (blob == NULL)
-			return -1;
-		blob->data = (u8 *) buf;
-		blob->len = len;
-		buf = NULL;
-		blob->name = os_strdup(pac_file + 7);
-		if (blob->name == NULL) {
-			os_free(blob);
-			return -1;
-		}
-		eap_set_config_blob(sm, blob);
-	} else {
-		FILE *f;
-		f = fopen(pac_file, "wb");
-		if (f == NULL) {
-			wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
-				   "file '%s' for writing", pac_file);
-			return -1;
-		}
-		if (fwrite(buf, 1, len, f) != len) {
-			wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
-				   "PACs into '%s'", pac_file);
-			fclose(f);
-			return -1;
-		}
-		os_free(buf);
-		fclose(f);
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
-				 char **pos, size_t *buf_len)
-{
-	int ret;
-
-	ret = os_snprintf(*pos, *buf + *buf_len - *pos,
-			  "START\nPAC-Type=%d\n", pac->pac_type);
-	if (ret < 0 || ret >= *buf + *buf_len - *pos)
-		return -1;
-
-	*pos += ret;
-	eap_fast_write(buf, pos, buf_len, "PAC-Key",
-		       pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0);
-	eap_fast_write(buf, pos, buf_len, "PAC-Opaque",
-		       pac->pac_opaque, pac->pac_opaque_len, 0);
-	eap_fast_write(buf, pos, buf_len, "PAC-Info",
-		       pac->pac_info, pac->pac_info_len, 0);
-	eap_fast_write(buf, pos, buf_len, "A-ID",
-		       pac->a_id, pac->a_id_len, 0);
-	eap_fast_write(buf, pos, buf_len, "I-ID",
-		       pac->i_id, pac->i_id_len, 1);
-	eap_fast_write(buf, pos, buf_len, "A-ID-Info",
-		       pac->a_id_info, pac->a_id_info_len, 1);
-	if (*buf == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
-			   "data");
-		return -1;
-	}
-	ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
-	if (ret < 0 || ret >= *buf + *buf_len - *pos)
-		return -1;
-	*pos += ret;
-
-	return 0;
-}
-
-
-/**
- * eap_fast_save_pac - Save PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
-int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
-		      const char *pac_file)
-{
-	struct eap_fast_pac *pac;
-	int ret, count = 0;
-	char *buf, *pos;
-	size_t buf_len;
-
-	if (pac_file == NULL)
-		return -1;
-
-	buf_len = 1024;
-	pos = buf = os_malloc(buf_len);
-	if (buf == NULL)
-		return -1;
-
-	ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
-	if (ret < 0 || ret >= buf + buf_len - pos) {
-		os_free(buf);
-		return -1;
-	}
-	pos += ret;
-
-	pac = pac_root;
-	while (pac) {
-		if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
-			os_free(buf);
-			return -1;
-		}
-		count++;
-		pac = pac->next;
-	}
-
-	if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
-		os_free(buf);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
-		   count, pac_file);
-
-	return 0;
-}
-
-
-/**
- * eap_fast_pac_list_truncate - Truncate a PAC list to the given length
- * @pac_root: Root of the PAC list
- * @max_len: Maximum length of the list (>= 1)
- * Returns: Number of PAC entries removed
- */
-size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
-				  size_t max_len)
-{
-	struct eap_fast_pac *pac, *prev;
-	size_t count;
-
-	pac = pac_root;
-	prev = NULL;
-	count = 0;
-
-	while (pac) {
-		count++;
-		if (count > max_len)
-			break;
-		prev = pac;
-		pac = pac->next;
-	}
-
-	if (count <= max_len || prev == NULL)
-		return 0;
-
-	count = 0;
-	prev->next = NULL;
-
-	while (pac) {
-		prev = pac;
-		pac = pac->next;
-		eap_fast_free_pac(prev);
-		count++;
-	}
-
-	return count;
-}
-
-
-static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
-{
-	u8 *pos, *end;
-	u16 type, len;
-
-	pos = pac->pac_info;
-	end = pos + pac->pac_info_len;
-
-	while (pos + 4 < end) {
-		type = WPA_GET_BE16(pos);
-		pos += 2;
-		len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + len > end)
-			break;
-
-		if (type == PAC_TYPE_A_ID) {
-			os_free(pac->a_id);
-			pac->a_id = os_malloc(len);
-			if (pac->a_id == NULL)
-				break;
-			os_memcpy(pac->a_id, pos, len);
-			pac->a_id_len = len;
-		}
-
-		if (type == PAC_TYPE_A_ID_INFO) {
-			os_free(pac->a_id_info);
-			pac->a_id_info = os_malloc(len);
-			if (pac->a_id_info == NULL)
-				break;
-			os_memcpy(pac->a_id_info, pos, len);
-			pac->a_id_info_len = len;
-		}
-
-		pos += len;
-	}
-}
-
-
-/**
- * eap_fast_load_pac_bin - Load PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
-int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
-			  const char *pac_file)
-{
-	const struct wpa_config_blob *blob = NULL;
-	u8 *buf, *end, *pos;
-	size_t len, count = 0;
-	struct eap_fast_pac *pac, *prev;
-
-	*pac_root = NULL;
-
-	if (pac_file == NULL)
-		return -1;
-
-	if (os_strncmp(pac_file, "blob://", 7) == 0) {
-		blob = eap_get_config_blob(sm, pac_file + 7);
-		if (blob == NULL) {
-			wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
-				   "assume no PAC entries have been "
-				   "provisioned", pac_file + 7);
-			return 0;
-		}
-		buf = blob->data;
-		len = blob->len;
-	} else {
-		buf = (u8 *) os_readfile(pac_file, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
-				   "assume no PAC entries have been "
-				   "provisioned", pac_file);
-			return 0;
-		}
-	}
-
-	if (len == 0) {
-		if (blob == NULL)
-			os_free(buf);
-		return 0;
-	}
-
-	if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
-	    WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
-			   pac_file);
-		if (blob == NULL)
-			os_free(buf);
-		return -1;
-	}
-
-	pac = prev = NULL;
-	pos = buf + 6;
-	end = buf + len;
-	while (pos < end) {
-		if (end - pos < 2 + 32 + 2 + 2)
-			goto parse_fail;
-
-		pac = os_zalloc(sizeof(*pac));
-		if (pac == NULL)
-			goto parse_fail;
-
-		pac->pac_type = WPA_GET_BE16(pos);
-		pos += 2;
-		os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
-		pos += EAP_FAST_PAC_KEY_LEN;
-		pac->pac_opaque_len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + pac->pac_opaque_len + 2 > end)
-			goto parse_fail;
-		pac->pac_opaque = os_malloc(pac->pac_opaque_len);
-		if (pac->pac_opaque == NULL)
-			goto parse_fail;
-		os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
-		pos += pac->pac_opaque_len;
-		pac->pac_info_len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + pac->pac_info_len > end)
-			goto parse_fail;
-		pac->pac_info = os_malloc(pac->pac_info_len);
-		if (pac->pac_info == NULL)
-			goto parse_fail;
-		os_memcpy(pac->pac_info, pos, pac->pac_info_len);
-		pos += pac->pac_info_len;
-		eap_fast_pac_get_a_id(pac);
-
-		count++;
-		if (prev)
-			prev->next = pac;
-		else
-			*pac_root = pac;
-		prev = pac;
-	}
-
-	if (blob == NULL)
-		os_free(buf);
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
-		   (unsigned long) count, pac_file);
-
-	return 0;
-
-parse_fail:
-	wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
-		   pac_file);
-	if (blob == NULL)
-		os_free(buf);
-	if (pac)
-		eap_fast_free_pac(pac);
-	return -1;
-}
-
-
-/**
- * eap_fast_save_pac_bin - Save PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
-int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
-			  const char *pac_file)
-{
-	size_t len, count = 0;
-	struct eap_fast_pac *pac;
-	u8 *buf, *pos;
-
-	len = 6;
-	pac = pac_root;
-	while (pac) {
-		if (pac->pac_opaque_len > 65535 ||
-		    pac->pac_info_len > 65535)
-			return -1;
-		len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
-			2 + pac->pac_info_len;
-		pac = pac->next;
-	}
-
-	buf = os_malloc(len);
-	if (buf == NULL)
-		return -1;
-
-	pos = buf;
-	WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
-	pos += 4;
-	WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
-	pos += 2;
-
-	pac = pac_root;
-	while (pac) {
-		WPA_PUT_BE16(pos, pac->pac_type);
-		pos += 2;
-		os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
-		pos += EAP_FAST_PAC_KEY_LEN;
-		WPA_PUT_BE16(pos, pac->pac_opaque_len);
-		pos += 2;
-		os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
-		pos += pac->pac_opaque_len;
-		WPA_PUT_BE16(pos, pac->pac_info_len);
-		pos += 2;
-		os_memcpy(pos, pac->pac_info, pac->pac_info_len);
-		pos += pac->pac_info_len;
-
-		pac = pac->next;
-		count++;
-	}
-
-	if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
-		os_free(buf);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
-		   "(bin)", (unsigned long) count, pac_file);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_fast_pac.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast_pac.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,921 @@
+/*
+ * EAP peer method: EAP-FAST PAC file processing
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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 "eap_config.h"
+#include "eap_i.h"
+#include "eap_fast_pac.h"
+
+/* TODO: encrypt PAC-Key in the PAC file */
+
+
+/* Text data format */
+static const char *pac_file_hdr =
+	"wpa_supplicant EAP-FAST PAC file - version 1";
+
+/*
+ * Binary data format
+ * 4-octet magic value: 6A E4 92 0C
+ * 2-octet version (big endian)
+ * <version specific data>
+ *
+ * version=0:
+ * Sequence of PAC entries:
+ *   2-octet PAC-Type (big endian)
+ *   32-octet PAC-Key
+ *   2-octet PAC-Opaque length (big endian)
+ *   <variable len> PAC-Opaque data (length bytes)
+ *   2-octet PAC-Info length (big endian)
+ *   <variable len> PAC-Info data (length bytes)
+ */
+
+#define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c
+#define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0
+
+
+/**
+ * eap_fast_free_pac - Free PAC data
+ * @pac: Pointer to the PAC entry
+ *
+ * Note that the PAC entry must not be in a list since this function does not
+ * remove the list links.
+ */
+void eap_fast_free_pac(struct eap_fast_pac *pac)
+{
+	os_free(pac->pac_opaque);
+	os_free(pac->pac_info);
+	os_free(pac->a_id);
+	os_free(pac->i_id);
+	os_free(pac->a_id_info);
+	os_free(pac);
+}
+
+
+/**
+ * eap_fast_get_pac - Get a PAC entry based on A-ID
+ * @pac_root: Pointer to root of the PAC list
+ * @a_id: A-ID to search for
+ * @a_id_len: Length of A-ID
+ * @pac_type: PAC-Type to search for
+ * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
+ */
+struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
+				       const u8 *a_id, size_t a_id_len,
+				       u16 pac_type)
+{
+	struct eap_fast_pac *pac = pac_root;
+
+	while (pac) {
+		if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
+		    os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
+			return pac;
+		}
+		pac = pac->next;
+	}
+	return NULL;
+}
+
+
+static void eap_fast_remove_pac(struct eap_fast_pac **pac_root,
+				struct eap_fast_pac **pac_current,
+				const u8 *a_id, size_t a_id_len, u16 pac_type)
+{
+	struct eap_fast_pac *pac, *prev;
+
+	pac = *pac_root;
+	prev = NULL;
+
+	while (pac) {
+		if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
+		    os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
+			if (prev == NULL)
+				*pac_root = pac->next;
+			else
+				prev->next = pac->next;
+			if (*pac_current == pac)
+				*pac_current = NULL;
+			eap_fast_free_pac(pac);
+			break;
+		}
+		prev = pac;
+		pac = pac->next;
+	}
+}
+
+
+static int eap_fast_copy_buf(u8 **dst, size_t *dst_len,
+			     const u8 *src, size_t src_len)
+{
+	if (src) {
+		*dst = os_malloc(src_len);
+		if (*dst == NULL)
+			return -1;
+		os_memcpy(*dst, src, src_len);
+		*dst_len = src_len;
+	}
+	return 0;
+}
+
+
+/**
+ * eap_fast_add_pac - Add a copy of a PAC entry to a list
+ * @pac_root: Pointer to PAC list root pointer
+ * @pac_current: Pointer to the current PAC pointer
+ * @entry: New entry to clone and add to the list
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function makes a clone of the given PAC entry and adds this copied
+ * entry to the list (pac_root). If an old entry for the same A-ID is found,
+ * it will be removed from the PAC list and in this case, pac_current entry
+ * is set to %NULL if it was the removed entry.
+ */
+int eap_fast_add_pac(struct eap_fast_pac **pac_root,
+		     struct eap_fast_pac **pac_current,
+		     struct eap_fast_pac *entry)
+{
+	struct eap_fast_pac *pac;
+
+	if (entry == NULL || entry->a_id == NULL)
+		return -1;
+
+	/* Remove a possible old entry for the matching A-ID. */
+	eap_fast_remove_pac(pac_root, pac_current,
+			    entry->a_id, entry->a_id_len, entry->pac_type);
+
+	/* Allocate a new entry and add it to the list of PACs. */
+	pac = os_zalloc(sizeof(*pac));
+	if (pac == NULL)
+		return -1;
+
+	pac->pac_type = entry->pac_type;
+	os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
+	if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
+			      entry->pac_opaque, entry->pac_opaque_len) < 0 ||
+	    eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len,
+			      entry->pac_info, entry->pac_info_len) < 0 ||
+	    eap_fast_copy_buf(&pac->a_id, &pac->a_id_len,
+			      entry->a_id, entry->a_id_len) < 0 ||
+	    eap_fast_copy_buf(&pac->i_id, &pac->i_id_len,
+			      entry->i_id, entry->i_id_len) < 0 ||
+	    eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
+			      entry->a_id_info, entry->a_id_info_len) < 0) {
+		eap_fast_free_pac(pac);
+		return -1;
+	}
+
+	pac->next = *pac_root;
+	*pac_root = pac;
+
+	return 0;
+}
+
+
+struct eap_fast_read_ctx {
+	FILE *f;
+	const char *pos;
+	const char *end;
+	int line;
+	char *buf;
+	size_t buf_len;
+};
+
+static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value)
+{
+	char *pos;
+
+	rc->line++;
+	if (rc->f) {
+		if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
+			return -1;
+	} else {
+		const char *l_end;
+		size_t len;
+		if (rc->pos >= rc->end)
+			return -1;
+		l_end = rc->pos;
+		while (l_end < rc->end && *l_end != '\n')
+			l_end++;
+		len = l_end - rc->pos;
+		if (len >= rc->buf_len)
+			len = rc->buf_len - 1;
+		os_memcpy(rc->buf, rc->pos, len);
+		rc->buf[len] = '\0';
+		rc->pos = l_end + 1;
+	}
+
+	rc->buf[rc->buf_len - 1] = '\0';
+	pos = rc->buf;
+	while (*pos != '\0') {
+		if (*pos == '\n' || *pos == '\r') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+
+	pos = os_strchr(rc->buf, '=');
+	if (pos)
+		*pos++ = '\0';
+	*value = pos;
+
+	return 0;
+}
+
+
+static u8 * eap_fast_parse_hex(const char *value, size_t *len)
+{
+	int hlen;
+	u8 *buf;
+
+	if (value == NULL)
+		return NULL;
+	hlen = os_strlen(value);
+	if (hlen & 1)
+		return NULL;
+	*len = hlen / 2;
+	buf = os_malloc(*len);
+	if (buf == NULL)
+		return NULL;
+	if (hexstr2bin(value, buf, *len)) {
+		os_free(buf);
+		return NULL;
+	}
+	return buf;
+}
+
+
+static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file,
+				  struct eap_fast_read_ctx *rc)
+{
+	os_memset(rc, 0, sizeof(*rc));
+
+	rc->buf_len = 2048;
+	rc->buf = os_malloc(rc->buf_len);
+	if (rc->buf == NULL)
+		return -1;
+
+	if (os_strncmp(pac_file, "blob://", 7) == 0) {
+		const struct wpa_config_blob *blob;
+		blob = eap_get_config_blob(sm, pac_file + 7);
+		if (blob == NULL) {
+			wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
+				   "assume no PAC entries have been "
+				   "provisioned", pac_file + 7);
+			os_free(rc->buf);
+			return -1;
+		}
+		rc->pos = (char *) blob->data;
+		rc->end = (char *) blob->data + blob->len;
+	} else {
+		rc->f = fopen(pac_file, "rb");
+		if (rc->f == NULL) {
+			wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
+				   "assume no PAC entries have been "
+				   "provisioned", pac_file);
+			os_free(rc->buf);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc)
+{
+	os_free(rc->buf);
+	if (rc->f)
+		fclose(rc->f);
+}
+
+
+static const char * eap_fast_parse_start(struct eap_fast_pac **pac)
+{
+	if (*pac)
+		return "START line without END";
+
+	*pac = os_zalloc(sizeof(struct eap_fast_pac));
+	if (*pac == NULL)
+		return "No memory for PAC entry";
+	(*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root,
+				       struct eap_fast_pac **pac)
+{
+	if (*pac == NULL)
+		return "END line without START";
+	if (*pac_root) {
+		struct eap_fast_pac *end = *pac_root;
+		while (end->next)
+			end = end->next;
+		end->next = *pac;
+	} else
+		*pac_root = *pac;
+
+	*pac = NULL;
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac,
+					    char *pos)
+{
+	pac->pac_type = atoi(pos);
+	if (pac->pac_type != PAC_TYPE_TUNNEL_PAC &&
+	    pac->pac_type != PAC_TYPE_USER_AUTHORIZATION &&
+	    pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION)
+		return "Unrecognized PAC-Type";
+
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos)
+{
+	u8 *key;
+	size_t key_len;
+
+	key = eap_fast_parse_hex(pos, &key_len);
+	if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) {
+		os_free(key);
+		return "Invalid PAC-Key";
+	}
+
+	os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
+	os_free(key);
+
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac,
+					      char *pos)
+{
+	os_free(pac->pac_opaque);
+	pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len);
+	if (pac->pac_opaque == NULL)
+		return "Invalid PAC-Opaque";
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos)
+{
+	os_free(pac->a_id);
+	pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
+	if (pac->a_id == NULL)
+		return "Invalid A-ID";
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos)
+{
+	os_free(pac->i_id);
+	pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
+	if (pac->i_id == NULL)
+		return "Invalid I-ID";
+	return NULL;
+}
+
+
+static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac,
+					     char *pos)
+{
+	os_free(pac->a_id_info);
+	pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len);
+	if (pac->a_id_info == NULL)
+		return "Invalid A-ID-Info";
+	return NULL;
+}
+
+
+/**
+ * eap_fast_load_pac - Load PAC entries (text format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Pointer to root of the PAC list (to be filled)
+ * @pac_file: Name of the PAC file/blob to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
+		      const char *pac_file)
+{
+	struct eap_fast_read_ctx rc;
+	struct eap_fast_pac *pac = NULL;
+	int count = 0;
+	char *pos;
+	const char *err = NULL;
+
+	if (pac_file == NULL)
+		return -1;
+
+	if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
+		return 0;
+
+	if (eap_fast_read_line(&rc, &pos) < 0) {
+		/* empty file - assume it is fine to overwrite */
+		eap_fast_deinit_pac_data(&rc);
+		return 0;
+	}
+	if (os_strcmp(pac_file_hdr, rc.buf) != 0)
+		err = "Unrecognized header line";
+
+	while (!err && eap_fast_read_line(&rc, &pos) == 0) {
+		if (os_strcmp(rc.buf, "START") == 0)
+			err = eap_fast_parse_start(&pac);
+		else if (os_strcmp(rc.buf, "END") == 0) {
+			err = eap_fast_parse_end(pac_root, &pac);
+			count++;
+		} else if (!pac)
+			err = "Unexpected line outside START/END block";
+		else if (os_strcmp(rc.buf, "PAC-Type") == 0)
+			err = eap_fast_parse_pac_type(pac, pos);
+		else if (os_strcmp(rc.buf, "PAC-Key") == 0)
+			err = eap_fast_parse_pac_key(pac, pos);
+		else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
+			err = eap_fast_parse_pac_opaque(pac, pos);
+		else if (os_strcmp(rc.buf, "A-ID") == 0)
+			err = eap_fast_parse_a_id(pac, pos);
+		else if (os_strcmp(rc.buf, "I-ID") == 0)
+			err = eap_fast_parse_i_id(pac, pos);
+		else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
+			err = eap_fast_parse_a_id_info(pac, pos);
+	}
+
+	if (pac) {
+		err = "PAC block not terminated with END";
+		eap_fast_free_pac(pac);
+	}
+
+	eap_fast_deinit_pac_data(&rc);
+
+	if (err) {
+		wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'",
+			   err, pac_file, rc.line);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'",
+		   count, pac_file);
+
+	return 0;
+}
+
+
+static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
+			   const char *field, const u8 *data,
+			   size_t len, int txt)
+{
+	size_t i, need;
+	int ret;
+	char *end;
+
+	if (data == NULL || buf == NULL || *buf == NULL ||
+	    pos == NULL || *pos == NULL || *pos < *buf)
+		return;
+
+	need = os_strlen(field) + len * 2 + 30;
+	if (txt)
+		need += os_strlen(field) + len + 20;
+
+	if (*pos - *buf + need > *buf_len) {
+		char *nbuf = os_realloc(*buf, *buf_len + need);
+		if (nbuf == NULL) {
+			os_free(*buf);
+			*buf = NULL;
+			return;
+		}
+		*pos = nbuf + (*pos - *buf);
+		*buf = nbuf;
+		*buf_len += need;
+	}
+	end = *buf + *buf_len;
+
+	ret = os_snprintf(*pos, end - *pos, "%s=", field);
+	if (ret < 0 || ret >= end - *pos)
+		return;
+	*pos += ret;
+	*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
+	ret = os_snprintf(*pos, end - *pos, "\n");
+	if (ret < 0 || ret >= end - *pos)
+		return;
+	*pos += ret;
+
+	if (txt) {
+		ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
+		if (ret < 0 || ret >= end - *pos)
+			return;
+		*pos += ret;
+		for (i = 0; i < len; i++) {
+			ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
+			if (ret < 0 || ret >= end - *pos)
+				return;
+			*pos += ret;
+		}
+		ret = os_snprintf(*pos, end - *pos, "\n");
+		if (ret < 0 || ret >= end - *pos)
+			return;
+		*pos += ret;
+	}
+}
+
+
+static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file,
+			      char *buf, size_t len)
+{
+	if (os_strncmp(pac_file, "blob://", 7) == 0) {
+		struct wpa_config_blob *blob;
+		blob = os_zalloc(sizeof(*blob));
+		if (blob == NULL)
+			return -1;
+		blob->data = (u8 *) buf;
+		blob->len = len;
+		buf = NULL;
+		blob->name = os_strdup(pac_file + 7);
+		if (blob->name == NULL) {
+			os_free(blob);
+			return -1;
+		}
+		eap_set_config_blob(sm, blob);
+	} else {
+		FILE *f;
+		f = fopen(pac_file, "wb");
+		if (f == NULL) {
+			wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
+				   "file '%s' for writing", pac_file);
+			return -1;
+		}
+		if (fwrite(buf, 1, len, f) != len) {
+			wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all "
+				   "PACs into '%s'", pac_file);
+			fclose(f);
+			return -1;
+		}
+		os_free(buf);
+		fclose(f);
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf,
+				 char **pos, size_t *buf_len)
+{
+	int ret;
+
+	ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+			  "START\nPAC-Type=%d\n", pac->pac_type);
+	if (ret < 0 || ret >= *buf + *buf_len - *pos)
+		return -1;
+
+	*pos += ret;
+	eap_fast_write(buf, pos, buf_len, "PAC-Key",
+		       pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0);
+	eap_fast_write(buf, pos, buf_len, "PAC-Opaque",
+		       pac->pac_opaque, pac->pac_opaque_len, 0);
+	eap_fast_write(buf, pos, buf_len, "PAC-Info",
+		       pac->pac_info, pac->pac_info_len, 0);
+	eap_fast_write(buf, pos, buf_len, "A-ID",
+		       pac->a_id, pac->a_id_len, 0);
+	eap_fast_write(buf, pos, buf_len, "I-ID",
+		       pac->i_id, pac->i_id_len, 1);
+	eap_fast_write(buf, pos, buf_len, "A-ID-Info",
+		       pac->a_id_info, pac->a_id_info_len, 1);
+	if (*buf == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
+			   "data");
+		return -1;
+	}
+	ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
+	if (ret < 0 || ret >= *buf + *buf_len - *pos)
+		return -1;
+	*pos += ret;
+
+	return 0;
+}
+
+
+/**
+ * eap_fast_save_pac - Save PAC entries (text format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Root of the PAC list
+ * @pac_file: Name of the PAC file/blob
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
+		      const char *pac_file)
+{
+	struct eap_fast_pac *pac;
+	int ret, count = 0;
+	char *buf, *pos;
+	size_t buf_len;
+
+	if (pac_file == NULL)
+		return -1;
+
+	buf_len = 1024;
+	pos = buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+	if (ret < 0 || ret >= buf + buf_len - pos) {
+		os_free(buf);
+		return -1;
+	}
+	pos += ret;
+
+	pac = pac_root;
+	while (pac) {
+		if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) {
+			os_free(buf);
+			return -1;
+		}
+		count++;
+		pac = pac->next;
+	}
+
+	if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) {
+		os_free(buf);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'",
+		   count, pac_file);
+
+	return 0;
+}
+
+
+/**
+ * eap_fast_pac_list_truncate - Truncate a PAC list to the given length
+ * @pac_root: Root of the PAC list
+ * @max_len: Maximum length of the list (>= 1)
+ * Returns: Number of PAC entries removed
+ */
+size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
+				  size_t max_len)
+{
+	struct eap_fast_pac *pac, *prev;
+	size_t count;
+
+	pac = pac_root;
+	prev = NULL;
+	count = 0;
+
+	while (pac) {
+		count++;
+		if (count > max_len)
+			break;
+		prev = pac;
+		pac = pac->next;
+	}
+
+	if (count <= max_len || prev == NULL)
+		return 0;
+
+	count = 0;
+	prev->next = NULL;
+
+	while (pac) {
+		prev = pac;
+		pac = pac->next;
+		eap_fast_free_pac(prev);
+		count++;
+	}
+
+	return count;
+}
+
+
+static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac)
+{
+	u8 *pos, *end;
+	u16 type, len;
+
+	pos = pac->pac_info;
+	end = pos + pac->pac_info_len;
+
+	while (pos + 4 < end) {
+		type = WPA_GET_BE16(pos);
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + len > end)
+			break;
+
+		if (type == PAC_TYPE_A_ID) {
+			os_free(pac->a_id);
+			pac->a_id = os_malloc(len);
+			if (pac->a_id == NULL)
+				break;
+			os_memcpy(pac->a_id, pos, len);
+			pac->a_id_len = len;
+		}
+
+		if (type == PAC_TYPE_A_ID_INFO) {
+			os_free(pac->a_id_info);
+			pac->a_id_info = os_malloc(len);
+			if (pac->a_id_info == NULL)
+				break;
+			os_memcpy(pac->a_id_info, pos, len);
+			pac->a_id_info_len = len;
+		}
+
+		pos += len;
+	}
+}
+
+
+/**
+ * eap_fast_load_pac_bin - Load PAC entries (binary format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Pointer to root of the PAC list (to be filled)
+ * @pac_file: Name of the PAC file/blob to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
+			  const char *pac_file)
+{
+	const struct wpa_config_blob *blob = NULL;
+	u8 *buf, *end, *pos;
+	size_t len, count = 0;
+	struct eap_fast_pac *pac, *prev;
+
+	*pac_root = NULL;
+
+	if (pac_file == NULL)
+		return -1;
+
+	if (os_strncmp(pac_file, "blob://", 7) == 0) {
+		blob = eap_get_config_blob(sm, pac_file + 7);
+		if (blob == NULL) {
+			wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
+				   "assume no PAC entries have been "
+				   "provisioned", pac_file + 7);
+			return 0;
+		}
+		buf = blob->data;
+		len = blob->len;
+	} else {
+		buf = (u8 *) os_readfile(pac_file, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
+				   "assume no PAC entries have been "
+				   "provisioned", pac_file);
+			return 0;
+		}
+	}
+
+	if (len == 0) {
+		if (blob == NULL)
+			os_free(buf);
+		return 0;
+	}
+
+	if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC ||
+	    WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)",
+			   pac_file);
+		if (blob == NULL)
+			os_free(buf);
+		return -1;
+	}
+
+	pac = prev = NULL;
+	pos = buf + 6;
+	end = buf + len;
+	while (pos < end) {
+		if (end - pos < 2 + 32 + 2 + 2)
+			goto parse_fail;
+
+		pac = os_zalloc(sizeof(*pac));
+		if (pac == NULL)
+			goto parse_fail;
+
+		pac->pac_type = WPA_GET_BE16(pos);
+		pos += 2;
+		os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
+		pos += EAP_FAST_PAC_KEY_LEN;
+		pac->pac_opaque_len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + pac->pac_opaque_len + 2 > end)
+			goto parse_fail;
+		pac->pac_opaque = os_malloc(pac->pac_opaque_len);
+		if (pac->pac_opaque == NULL)
+			goto parse_fail;
+		os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
+		pos += pac->pac_opaque_len;
+		pac->pac_info_len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + pac->pac_info_len > end)
+			goto parse_fail;
+		pac->pac_info = os_malloc(pac->pac_info_len);
+		if (pac->pac_info == NULL)
+			goto parse_fail;
+		os_memcpy(pac->pac_info, pos, pac->pac_info_len);
+		pos += pac->pac_info_len;
+		eap_fast_pac_get_a_id(pac);
+
+		count++;
+		if (prev)
+			prev->next = pac;
+		else
+			*pac_root = pac;
+		prev = pac;
+	}
+
+	if (blob == NULL)
+		os_free(buf);
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)",
+		   (unsigned long) count, pac_file);
+
+	return 0;
+
+parse_fail:
+	wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)",
+		   pac_file);
+	if (blob == NULL)
+		os_free(buf);
+	if (pac)
+		eap_fast_free_pac(pac);
+	return -1;
+}
+
+
+/**
+ * eap_fast_save_pac_bin - Save PAC entries (binary format)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @pac_root: Root of the PAC list
+ * @pac_file: Name of the PAC file/blob
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
+			  const char *pac_file)
+{
+	size_t len, count = 0;
+	struct eap_fast_pac *pac;
+	u8 *buf, *pos;
+
+	len = 6;
+	pac = pac_root;
+	while (pac) {
+		if (pac->pac_opaque_len > 65535 ||
+		    pac->pac_info_len > 65535)
+			return -1;
+		len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
+			2 + pac->pac_info_len;
+		pac = pac->next;
+	}
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	pos = buf;
+	WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC);
+	pos += 4;
+	WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION);
+	pos += 2;
+
+	pac = pac_root;
+	while (pac) {
+		WPA_PUT_BE16(pos, pac->pac_type);
+		pos += 2;
+		os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN);
+		pos += EAP_FAST_PAC_KEY_LEN;
+		WPA_PUT_BE16(pos, pac->pac_opaque_len);
+		pos += 2;
+		os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
+		pos += pac->pac_opaque_len;
+		WPA_PUT_BE16(pos, pac->pac_info_len);
+		pos += 2;
+		os_memcpy(pos, pac->pac_info, pac->pac_info_len);
+		pos += pac->pac_info_len;
+
+		pac = pac->next;
+		count++;
+	}
+
+	if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) {
+		os_free(buf);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' "
+		   "(bin)", (unsigned long) count, pac_file);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_fast_pac.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,56 +0,0 @@
-/*
- * EAP peer method: EAP-FAST PAC file processing
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_FAST_PAC_H
-#define EAP_FAST_PAC_H
-
-#include "eap_common/eap_fast_common.h"
-
-struct eap_fast_pac {
-	struct eap_fast_pac *next;
-
-	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
-	u8 *pac_opaque;
-	size_t pac_opaque_len;
-	u8 *pac_info;
-	size_t pac_info_len;
-	u8 *a_id;
-	size_t a_id_len;
-	u8 *i_id;
-	size_t i_id_len;
-	u8 *a_id_info;
-	size_t a_id_info_len;
-	u16 pac_type;
-};
-
-
-void eap_fast_free_pac(struct eap_fast_pac *pac);
-struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
-				       const u8 *a_id, size_t a_id_len,
-				       u16 pac_type);
-int eap_fast_add_pac(struct eap_fast_pac **pac_root,
-		     struct eap_fast_pac **pac_current,
-		     struct eap_fast_pac *entry);
-int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
-		      const char *pac_file);
-int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
-		      const char *pac_file);
-size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
-				  size_t max_len);
-int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
-			  const char *pac_file);
-int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
-			  const char *pac_file);
-
-#endif /* EAP_FAST_PAC_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_fast_pac.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_fast_pac.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,50 @@
+/*
+ * EAP peer method: EAP-FAST PAC file processing
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_FAST_PAC_H
+#define EAP_FAST_PAC_H
+
+#include "eap_common/eap_fast_common.h"
+
+struct eap_fast_pac {
+	struct eap_fast_pac *next;
+
+	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+	u8 *pac_opaque;
+	size_t pac_opaque_len;
+	u8 *pac_info;
+	size_t pac_info_len;
+	u8 *a_id;
+	size_t a_id_len;
+	u8 *i_id;
+	size_t i_id_len;
+	u8 *a_id_info;
+	size_t a_id_info_len;
+	u16 pac_type;
+};
+
+
+void eap_fast_free_pac(struct eap_fast_pac *pac);
+struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root,
+				       const u8 *a_id, size_t a_id_len,
+				       u16 pac_type);
+int eap_fast_add_pac(struct eap_fast_pac **pac_root,
+		     struct eap_fast_pac **pac_current,
+		     struct eap_fast_pac *entry);
+int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
+		      const char *pac_file);
+int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root,
+		      const char *pac_file);
+size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root,
+				  size_t max_len);
+int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root,
+			  const char *pac_file);
+int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root,
+			  const char *pac_file);
+
+#endif /* EAP_FAST_PAC_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_gpsk.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_gpsk.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_gpsk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,737 +0,0 @@
-/*
- * EAP peer method: EAP-GPSK (RFC 5433)
- * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_peer/eap_i.h"
-#include "eap_common/eap_gpsk_common.h"
-
-struct eap_gpsk_data {
-	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
-	u8 rand_server[EAP_GPSK_RAND_LEN];
-	u8 rand_peer[EAP_GPSK_RAND_LEN];
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 sk[EAP_GPSK_MAX_SK_LEN];
-	size_t sk_len;
-	u8 pk[EAP_GPSK_MAX_PK_LEN];
-	size_t pk_len;
-	u8 session_id;
-	int session_id_set;
-	u8 *id_peer;
-	size_t id_peer_len;
-	u8 *id_server;
-	size_t id_server_len;
-	int vendor; /* CSuite/Specifier */
-	int specifier; /* CSuite/Specifier */
-	u8 *psk;
-	size_t psk_len;
-};
-
-
-static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
-					    u8 identifier,
-					    const u8 *csuite_list,
-					    size_t csuite_list_len);
-static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
-					    u8 identifier);
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char * eap_gpsk_state_txt(int state)
-{
-	switch (state) {
-	case GPSK_1:
-		return "GPSK-1";
-	case GPSK_3:
-		return "GPSK-3";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
-		   eap_gpsk_state_txt(data->state),
-		   eap_gpsk_state_txt(state));
-	data->state = state;
-}
-
-
-static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
-
-
-static void * eap_gpsk_init(struct eap_sm *sm)
-{
-	struct eap_gpsk_data *data;
-	const u8 *identity, *password;
-	size_t identity_len, password_len;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = GPSK_1;
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity) {
-		data->id_peer = os_malloc(identity_len);
-		if (data->id_peer == NULL) {
-			eap_gpsk_deinit(sm, data);
-			return NULL;
-		}
-		os_memcpy(data->id_peer, identity, identity_len);
-		data->id_peer_len = identity_len;
-	}
-
-	data->psk = os_malloc(password_len);
-	if (data->psk == NULL) {
-		eap_gpsk_deinit(sm, data);
-		return NULL;
-	}
-	os_memcpy(data->psk, password, password_len);
-	data->psk_len = password_len;
-
-	return data;
-}
-
-
-static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_gpsk_data *data = priv;
-	os_free(data->id_server);
-	os_free(data->id_peer);
-	os_free(data->psk);
-	os_free(data);
-}
-
-
-static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
-					     const u8 *pos, const u8 *end)
-{
-	u16 alen;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
-		return NULL;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
-		return NULL;
-	}
-	os_free(data->id_server);
-	data->id_server = os_malloc(alen);
-	if (data->id_server == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
-		return NULL;
-	}
-	os_memcpy(data->id_server, pos, alen);
-	data->id_server_len = alen;
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
-			  data->id_server, data->id_server_len);
-	pos += alen;
-
-	return pos;
-}
-
-
-static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
-					       const u8 *pos, const u8 *end)
-{
-	if (pos == NULL)
-		return NULL;
-
-	if (end - pos < EAP_GPSK_RAND_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
-		return NULL;
-	}
-	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
-		    data->rand_server, EAP_GPSK_RAND_LEN);
-	pos += EAP_GPSK_RAND_LEN;
-
-	return pos;
-}
-
-
-static int eap_gpsk_select_csuite(struct eap_sm *sm,
-				  struct eap_gpsk_data *data,
-				  const u8 *csuite_list,
-				  size_t csuite_list_len)
-{
-	struct eap_gpsk_csuite *csuite;
-	int i, count;
-
-	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
-	data->vendor = EAP_GPSK_VENDOR_IETF;
-	data->specifier = EAP_GPSK_CIPHER_RESERVED;
-	csuite = (struct eap_gpsk_csuite *) csuite_list;
-	for (i = 0; i < count; i++) {
-		int vendor, specifier;
-		vendor = WPA_GET_BE32(csuite->vendor);
-		specifier = WPA_GET_BE16(csuite->specifier);
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
-			   i, vendor, specifier);
-		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
-		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
-		    eap_gpsk_supported_ciphersuite(vendor, specifier)) {
-			data->vendor = vendor;
-			data->specifier = specifier;
-		}
-		csuite++;
-	}
-	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
-	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
-		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
-			"ciphersuite found");
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
-		   data->vendor, data->specifier);
-
-	return 0;
-}
-
-
-static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
-					       struct eap_gpsk_data *data,
-					       const u8 **list,
-					       size_t *list_len,
-					       const u8 *pos, const u8 *end)
-{
-	if (pos == NULL)
-		return NULL;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
-		return NULL;
-	}
-	*list_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < (int) *list_len) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
-		return NULL;
-	}
-	if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
-			   (unsigned long) *list_len);
-		return NULL;
-	}
-	*list = pos;
-	pos += *list_len;
-
-	if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
-		return NULL;
-
-	return pos;
-}
-
-
-static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
-					       struct eap_gpsk_data *data,
-					       struct eap_method_ret *ret,
-					       const struct wpabuf *reqData,
-					       const u8 *payload,
-					       size_t payload_len)
-{
-	size_t csuite_list_len;
-	const u8 *csuite_list, *pos, *end;
-	struct wpabuf *resp;
-
-	if (data->state != GPSK_1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
-
-	end = payload + payload_len;
-
-	pos = eap_gpsk_process_id_server(data, payload, end);
-	pos = eap_gpsk_process_rand_server(data, pos, end);
-	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
-					   &csuite_list_len, pos, end);
-	if (pos == NULL) {
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-
-	resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
-				    csuite_list, csuite_list_len);
-	if (resp == NULL)
-		return NULL;
-
-	eap_gpsk_state(data, GPSK_3);
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
-					    u8 identifier,
-					    const u8 *csuite_list,
-					    size_t csuite_list_len)
-{
-	struct wpabuf *resp;
-	size_t len, miclen;
-	u8 *rpos, *start;
-	struct eap_gpsk_csuite *csuite;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
-
-	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
-		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
-		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
-			     EAP_CODE_RESPONSE, identifier);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
-	start = wpabuf_put(resp, 0);
-
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
-			  data->id_peer, data->id_peer_len);
-	wpabuf_put_be16(resp, data->id_peer_len);
-	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
-
-	wpabuf_put_be16(resp, data->id_server_len);
-	wpabuf_put_data(resp, data->id_server, data->id_server_len);
-
-	if (os_get_random(data->rand_peer, EAP_GPSK_RAND_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
-			   "for RAND_Peer");
-		eap_gpsk_state(data, FAILURE);
-		wpabuf_free(resp);
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
-		    data->rand_peer, EAP_GPSK_RAND_LEN);
-	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
-	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
-
-	wpabuf_put_be16(resp, csuite_list_len);
-	wpabuf_put_data(resp, csuite_list, csuite_list_len);
-
-	csuite = wpabuf_put(resp, sizeof(*csuite));
-	WPA_PUT_BE32(csuite->vendor, data->vendor);
-	WPA_PUT_BE16(csuite->specifier, data->specifier);
-
-	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
-				 data->vendor, data->specifier,
-				 data->rand_peer, data->rand_server,
-				 data->id_peer, data->id_peer_len,
-				 data->id_server, data->id_server_len,
-				 data->msk, data->emsk,
-				 data->sk, &data->sk_len,
-				 data->pk, &data->pk_len) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
-		eap_gpsk_state(data, FAILURE);
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	/* No PD_Payload_1 */
-	wpabuf_put_be16(resp, 0);
-
-	rpos = wpabuf_put(resp, miclen);
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, start, rpos - start, rpos) <
-	    0) {
-		eap_gpsk_state(data, FAILURE);
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	return resp;
-}
-
-
-static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
-					 const u8 *pos, const u8 *end)
-{
-	if (end - pos < EAP_GPSK_RAND_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "RAND_Peer");
-		return NULL;
-	}
-	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
-			   "GPSK-3 did not match");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
-			    data->rand_peer, EAP_GPSK_RAND_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
-			    pos, EAP_GPSK_RAND_LEN);
-		return NULL;
-	}
-	pos += EAP_GPSK_RAND_LEN;
-
-	if (end - pos < EAP_GPSK_RAND_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "RAND_Server");
-		return NULL;
-	}
-	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
-			   "GPSK-3 did not match");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
-			    data->rand_server, EAP_GPSK_RAND_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
-			    pos, EAP_GPSK_RAND_LEN);
-		return NULL;
-	}
-	pos += EAP_GPSK_RAND_LEN;
-
-	return pos;
-}
-
-
-static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
-					      const u8 *pos, const u8 *end)
-{
-	size_t len;
-
-	if (pos == NULL)
-		return NULL;
-
-	if (end - pos < (int) 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "length(ID_Server)");
-		return NULL;
-	}
-
-	len = WPA_GET_BE16(pos);
-	pos += 2;
-
-	if (end - pos < (int) len) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "ID_Server");
-		return NULL;
-	}
-
-	if (len != data->id_server_len ||
-	    os_memcmp(pos, data->id_server, len) != 0) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
-			   "the one used in GPSK-1");
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
-				  data->id_server, data->id_server_len);
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
-				  pos, len);
-		return NULL;
-	}
-
-	pos += len;
-
-	return pos;
-}
-
-
-static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
-					   const u8 *pos, const u8 *end)
-{
-	int vendor, specifier;
-	const struct eap_gpsk_csuite *csuite;
-
-	if (pos == NULL)
-		return NULL;
-
-	if (end - pos < (int) sizeof(*csuite)) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "CSuite_Sel");
-		return NULL;
-	}
-	csuite = (const struct eap_gpsk_csuite *) pos;
-	vendor = WPA_GET_BE32(csuite->vendor);
-	specifier = WPA_GET_BE16(csuite->specifier);
-	pos += sizeof(*csuite);
-	if (vendor != data->vendor || specifier != data->specifier) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
-			   "match with the one sent in GPSK-2 (%d:%d)",
-			   vendor, specifier, data->vendor, data->specifier);
-		return NULL;
-	}
-
-	return pos;
-}
-
-
-static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
-						 const u8 *pos, const u8 *end)
-{
-	u16 alen;
-
-	if (pos == NULL)
-		return NULL;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "PD_Payload_2 length");
-		return NULL;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
-			   "%d-octet PD_Payload_2", alen);
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
-	pos += alen;
-
-	return pos;
-}
-
-
-static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
-					       const u8 *payload,
-					       const u8 *pos, const u8 *end)
-{
-	size_t miclen;
-	u8 mic[EAP_GPSK_MAX_MIC_LEN];
-
-	if (pos == NULL)
-		return NULL;
-
-	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	if (end - pos < (int) miclen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
-			   "(left=%lu miclen=%lu)",
-			   (unsigned long) (end - pos),
-			   (unsigned long) miclen);
-		return NULL;
-	}
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, payload, pos - payload, mic)
-	    < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
-		return NULL;
-	}
-	if (os_memcmp(mic, pos, miclen) != 0) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
-		return NULL;
-	}
-	pos += miclen;
-
-	return pos;
-}
-
-
-static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
-					       struct eap_gpsk_data *data,
-					       struct eap_method_ret *ret,
-					       const struct wpabuf *reqData,
-					       const u8 *payload,
-					       size_t payload_len)
-{
-	struct wpabuf *resp;
-	const u8 *pos, *end;
-
-	if (data->state != GPSK_3) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
-
-	end = payload + payload_len;
-
-	pos = eap_gpsk_validate_rand(data, payload, end);
-	pos = eap_gpsk_validate_id_server(data, pos, end);
-	pos = eap_gpsk_validate_csuite(data, pos, end);
-	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
-	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
-
-	if (pos == NULL) {
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-	if (pos != end) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
-			   "data in the end of GPSK-2",
-			   (unsigned long) (end - pos));
-	}
-
-	resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-
-	eap_gpsk_state(data, SUCCESS);
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
-					    u8 identifier)
-{
-	struct wpabuf *resp;
-	u8 *rpos, *start;
-	size_t mlen;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
-
-	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
-			     EAP_CODE_RESPONSE, identifier);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
-	start = wpabuf_put(resp, 0);
-
-	/* No PD_Payload_3 */
-	wpabuf_put_be16(resp, 0);
-
-	rpos = wpabuf_put(resp, mlen);
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, start, rpos - start, rpos) <
-	    0) {
-		eap_gpsk_state(data, FAILURE);
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
-					struct eap_method_ret *ret,
-					const struct wpabuf *reqData)
-{
-	struct eap_gpsk_data *data = priv;
-	struct wpabuf *resp;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
-	if (pos == NULL || len < 1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = FALSE;
-
-	switch (*pos) {
-	case EAP_GPSK_OPCODE_GPSK_1:
-		resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
-					       pos + 1, len - 1);
-		break;
-	case EAP_GPSK_OPCODE_GPSK_3:
-		resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
-					       pos + 1, len - 1);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
-			   "unknown opcode %d", *pos);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_gpsk_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_gpsk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-	*len = EAP_MSK_LEN;
-
-	return key;
-}
-
-
-static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_gpsk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_gpsk_init;
-	eap->deinit = eap_gpsk_deinit;
-	eap->process = eap_gpsk_process;
-	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
-	eap->getKey = eap_gpsk_getKey;
-	eap->get_emsk = eap_gpsk_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_gpsk.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_gpsk.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_gpsk.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_gpsk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,732 @@
+/*
+ * EAP peer method: EAP-GPSK (RFC 5433)
+ * Copyright (c) 2006-2008, Jouni Malinen <j at 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/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_gpsk_common.h"
+
+struct eap_gpsk_data {
+	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
+	u8 rand_server[EAP_GPSK_RAND_LEN];
+	u8 rand_peer[EAP_GPSK_RAND_LEN];
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 sk[EAP_GPSK_MAX_SK_LEN];
+	size_t sk_len;
+	u8 pk[EAP_GPSK_MAX_PK_LEN];
+	size_t pk_len;
+	u8 session_id;
+	int session_id_set;
+	u8 *id_peer;
+	size_t id_peer_len;
+	u8 *id_server;
+	size_t id_server_len;
+	int vendor; /* CSuite/Specifier */
+	int specifier; /* CSuite/Specifier */
+	u8 *psk;
+	size_t psk_len;
+};
+
+
+static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
+					    u8 identifier,
+					    const u8 *csuite_list,
+					    size_t csuite_list_len);
+static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
+					    u8 identifier);
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_gpsk_state_txt(int state)
+{
+	switch (state) {
+	case GPSK_1:
+		return "GPSK-1";
+	case GPSK_3:
+		return "GPSK-3";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
+		   eap_gpsk_state_txt(data->state),
+		   eap_gpsk_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_gpsk_init(struct eap_sm *sm)
+{
+	struct eap_gpsk_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = GPSK_1;
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity) {
+		data->id_peer = os_malloc(identity_len);
+		if (data->id_peer == NULL) {
+			eap_gpsk_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->id_peer, identity, identity_len);
+		data->id_peer_len = identity_len;
+	}
+
+	data->psk = os_malloc(password_len);
+	if (data->psk == NULL) {
+		eap_gpsk_deinit(sm, data);
+		return NULL;
+	}
+	os_memcpy(data->psk, password, password_len);
+	data->psk_len = password_len;
+
+	return data;
+}
+
+
+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	os_free(data->id_server);
+	os_free(data->id_peer);
+	os_free(data->psk);
+	os_free(data);
+}
+
+
+static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
+					     const u8 *pos, const u8 *end)
+{
+	u16 alen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
+		return NULL;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
+		return NULL;
+	}
+	os_free(data->id_server);
+	data->id_server = os_malloc(alen);
+	if (data->id_server == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
+		return NULL;
+	}
+	os_memcpy(data->id_server, pos, alen);
+	data->id_server_len = alen;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
+			  data->id_server, data->id_server_len);
+	pos += alen;
+
+	return pos;
+}
+
+
+static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
+					       const u8 *pos, const u8 *end)
+{
+	if (pos == NULL)
+		return NULL;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
+		return NULL;
+	}
+	os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
+		    data->rand_server, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+
+	return pos;
+}
+
+
+static int eap_gpsk_select_csuite(struct eap_sm *sm,
+				  struct eap_gpsk_data *data,
+				  const u8 *csuite_list,
+				  size_t csuite_list_len)
+{
+	struct eap_gpsk_csuite *csuite;
+	int i, count;
+
+	count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
+	data->vendor = EAP_GPSK_VENDOR_IETF;
+	data->specifier = EAP_GPSK_CIPHER_RESERVED;
+	csuite = (struct eap_gpsk_csuite *) csuite_list;
+	for (i = 0; i < count; i++) {
+		int vendor, specifier;
+		vendor = WPA_GET_BE32(csuite->vendor);
+		specifier = WPA_GET_BE16(csuite->specifier);
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
+			   i, vendor, specifier);
+		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
+		    data->specifier == EAP_GPSK_CIPHER_RESERVED &&
+		    eap_gpsk_supported_ciphersuite(vendor, specifier)) {
+			data->vendor = vendor;
+			data->specifier = specifier;
+		}
+		csuite++;
+	}
+	if (data->vendor == EAP_GPSK_VENDOR_IETF &&
+	    data->specifier == EAP_GPSK_CIPHER_RESERVED) {
+		wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
+			"ciphersuite found");
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
+		   data->vendor, data->specifier);
+
+	return 0;
+}
+
+
+static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
+					       struct eap_gpsk_data *data,
+					       const u8 **list,
+					       size_t *list_len,
+					       const u8 *pos, const u8 *end)
+{
+	if (pos == NULL)
+		return NULL;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
+		return NULL;
+	}
+	*list_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < (int) *list_len) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
+		return NULL;
+	}
+	if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
+			   (unsigned long) *list_len);
+		return NULL;
+	}
+	*list = pos;
+	pos += *list_len;
+
+	if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
+		return NULL;
+
+	return pos;
+}
+
+
+static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
+					       struct eap_gpsk_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	size_t csuite_list_len;
+	const u8 *csuite_list, *pos, *end;
+	struct wpabuf *resp;
+
+	if (data->state != GPSK_1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
+
+	end = payload + payload_len;
+
+	pos = eap_gpsk_process_id_server(data, payload, end);
+	pos = eap_gpsk_process_rand_server(data, pos, end);
+	pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list,
+					   &csuite_list_len, pos, end);
+	if (pos == NULL) {
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData),
+				    csuite_list, csuite_list_len);
+	if (resp == NULL)
+		return NULL;
+
+	eap_gpsk_state(data, GPSK_3);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
+					    u8 identifier,
+					    const u8 *csuite_list,
+					    size_t csuite_list_len)
+{
+	struct wpabuf *resp;
+	size_t len, miclen;
+	u8 *rpos, *start;
+	struct eap_gpsk_csuite *csuite;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len +
+		2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
+		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
+			     EAP_CODE_RESPONSE, identifier);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2);
+	start = wpabuf_put(resp, 0);
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
+			  data->id_peer, data->id_peer_len);
+	wpabuf_put_be16(resp, data->id_peer_len);
+	wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
+
+	wpabuf_put_be16(resp, data->id_server_len);
+	wpabuf_put_data(resp, data->id_server, data->id_server_len);
+
+	if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
+			   "for RAND_Peer");
+		eap_gpsk_state(data, FAILURE);
+		wpabuf_free(resp);
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
+		    data->rand_peer, EAP_GPSK_RAND_LEN);
+	wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN);
+	wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN);
+
+	wpabuf_put_be16(resp, csuite_list_len);
+	wpabuf_put_data(resp, csuite_list, csuite_list_len);
+
+	csuite = wpabuf_put(resp, sizeof(*csuite));
+	WPA_PUT_BE32(csuite->vendor, data->vendor);
+	WPA_PUT_BE16(csuite->specifier, data->specifier);
+
+	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
+				 data->vendor, data->specifier,
+				 data->rand_peer, data->rand_server,
+				 data->id_peer, data->id_peer_len,
+				 data->id_server, data->id_server_len,
+				 data->msk, data->emsk,
+				 data->sk, &data->sk_len,
+				 data->pk, &data->pk_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
+		eap_gpsk_state(data, FAILURE);
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	/* No PD_Payload_1 */
+	wpabuf_put_be16(resp, 0);
+
+	rpos = wpabuf_put(resp, miclen);
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, start, rpos - start, rpos) <
+	    0) {
+		eap_gpsk_state(data, FAILURE);
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	return resp;
+}
+
+
+static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
+					 const u8 *pos, const u8 *end)
+{
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "RAND_Peer");
+		return NULL;
+	}
+	if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and "
+			   "GPSK-3 did not match");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2",
+			    data->rand_peer, EAP_GPSK_RAND_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3",
+			    pos, EAP_GPSK_RAND_LEN);
+		return NULL;
+	}
+	pos += EAP_GPSK_RAND_LEN;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "RAND_Server");
+		return NULL;
+	}
+	if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
+			   "GPSK-3 did not match");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
+			    data->rand_server, EAP_GPSK_RAND_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
+			    pos, EAP_GPSK_RAND_LEN);
+		return NULL;
+	}
+	pos += EAP_GPSK_RAND_LEN;
+
+	return pos;
+}
+
+
+static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
+					      const u8 *pos, const u8 *end)
+{
+	size_t len;
+
+	if (pos == NULL)
+		return NULL;
+
+	if (end - pos < (int) 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "length(ID_Server)");
+		return NULL;
+	}
+
+	len = WPA_GET_BE16(pos);
+	pos += 2;
+
+	if (end - pos < (int) len) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "ID_Server");
+		return NULL;
+	}
+
+	if (len != data->id_server_len ||
+	    os_memcmp(pos, data->id_server, len) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with "
+			   "the one used in GPSK-1");
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1",
+				  data->id_server, data->id_server_len);
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
+				  pos, len);
+		return NULL;
+	}
+
+	pos += len;
+
+	return pos;
+}
+
+
+static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
+					   const u8 *pos, const u8 *end)
+{
+	int vendor, specifier;
+	const struct eap_gpsk_csuite *csuite;
+
+	if (pos == NULL)
+		return NULL;
+
+	if (end - pos < (int) sizeof(*csuite)) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "CSuite_Sel");
+		return NULL;
+	}
+	csuite = (const struct eap_gpsk_csuite *) pos;
+	vendor = WPA_GET_BE32(csuite->vendor);
+	specifier = WPA_GET_BE16(csuite->specifier);
+	pos += sizeof(*csuite);
+	if (vendor != data->vendor || specifier != data->specifier) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
+			   "match with the one sent in GPSK-2 (%d:%d)",
+			   vendor, specifier, data->vendor, data->specifier);
+		return NULL;
+	}
+
+	return pos;
+}
+
+
+static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
+						 const u8 *pos, const u8 *end)
+{
+	u16 alen;
+
+	if (pos == NULL)
+		return NULL;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "PD_Payload_2 length");
+		return NULL;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+			   "%d-octet PD_Payload_2", alen);
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
+	pos += alen;
+
+	return pos;
+}
+
+
+static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
+					       const u8 *payload,
+					       const u8 *pos, const u8 *end)
+{
+	size_t miclen;
+	u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+	if (pos == NULL)
+		return NULL;
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	if (end - pos < (int) miclen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+			   "(left=%lu miclen=%lu)",
+			   (unsigned long) (end - pos),
+			   (unsigned long) miclen);
+		return NULL;
+	}
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, payload, pos - payload, mic)
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+		return NULL;
+	}
+	if (os_memcmp(mic, pos, miclen) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+		return NULL;
+	}
+	pos += miclen;
+
+	return pos;
+}
+
+
+static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
+					       struct eap_gpsk_data *data,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData,
+					       const u8 *payload,
+					       size_t payload_len)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+
+	if (data->state != GPSK_3) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
+
+	end = payload + payload_len;
+
+	pos = eap_gpsk_validate_rand(data, payload, end);
+	pos = eap_gpsk_validate_id_server(data, pos, end);
+	pos = eap_gpsk_validate_csuite(data, pos, end);
+	pos = eap_gpsk_validate_pd_payload_2(data, pos, end);
+	pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end);
+
+	if (pos == NULL) {
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+	if (pos != end) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
+			   "data in the end of GPSK-2",
+			   (unsigned long) (end - pos));
+	}
+
+	resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+
+	eap_gpsk_state(data, SUCCESS);
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data,
+					    u8 identifier)
+{
+	struct wpabuf *resp;
+	u8 *rpos, *start;
+	size_t mlen;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
+
+	mlen = eap_gpsk_mic_len(data->vendor, data->specifier);
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen,
+			     EAP_CODE_RESPONSE, identifier);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4);
+	start = wpabuf_put(resp, 0);
+
+	/* No PD_Payload_3 */
+	wpabuf_put_be16(resp, 0);
+
+	rpos = wpabuf_put(resp, mlen);
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, start, rpos - start, rpos) <
+	    0) {
+		eap_gpsk_state(data, FAILURE);
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	struct eap_gpsk_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	switch (*pos) {
+	case EAP_GPSK_OPCODE_GPSK_1:
+		resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
+					       pos + 1, len - 1);
+		break;
+	case EAP_GPSK_OPCODE_GPSK_3:
+		resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
+					       pos + 1, len - 1);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
+			   "unknown opcode %d", *pos);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gpsk_init;
+	eap->deinit = eap_gpsk_deinit;
+	eap->process = eap_gpsk_process;
+	eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
+	eap->getKey = eap_gpsk_getKey;
+	eap->get_emsk = eap_gpsk_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_gtc.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_gtc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_gtc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,151 +0,0 @@
-/*
- * EAP peer method: EAP-GTC (RFC 3748)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-
-
-struct eap_gtc_data {
-	int prefix;
-};
-
-
-static void * eap_gtc_init(struct eap_sm *sm)
-{
-	struct eap_gtc_data *data;
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
-	    sm->m->method == EAP_TYPE_FAST) {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
-			   "with challenge/response");
-		data->prefix = 1;
-	}
-	return data;
-}
-
-
-static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_gtc_data *data = priv;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_gtc_data *data = priv;
-	struct wpabuf *resp;
-	const u8 *pos, *password, *identity;
-	size_t password_len, identity_len, len, plen;
-	int otp;
-	u8 id;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
-	if (pos == NULL) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	id = eap_get_id(reqData);
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
-	if (data->prefix &&
-	    (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
-			   "expected prefix");
-
-		/* Send an empty response in order to allow tunneled
-		 * acknowledgement of the failure. This will also cover the
-		 * error case which seems to use EAP-MSCHAPv2 like error
-		 * reporting with EAP-GTC inside EAP-FAST tunnel. */
-		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC,
-				     0, EAP_CODE_RESPONSE, id);
-		return resp;
-	}
-
-	password = eap_get_config_otp(sm, &password_len);
-	if (password)
-		otp = 1;
-	else {
-		password = eap_get_config_password(sm, &password_len);
-		otp = 0;
-	}
-
-	if (password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
-		eap_sm_request_otp(sm, (const char *) pos, len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ret->ignore = FALSE;
-
-	ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
-	ret->decision = DECISION_COND_SUCC;
-	ret->allowNotifications = FALSE;
-
-	plen = password_len;
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity == NULL)
-		return NULL;
-	if (data->prefix)
-		plen += 9 + identity_len + 1;
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-	if (data->prefix) {
-		wpabuf_put_data(resp, "RESPONSE=", 9);
-		wpabuf_put_data(resp, identity, identity_len);
-		wpabuf_put_u8(resp, '\0');
-	}
-	wpabuf_put_data(resp, password, password_len);
-	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
-			      wpabuf_head_u8(resp) + sizeof(struct eap_hdr) +
-			      1, plen);
-
-	if (otp) {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
-		eap_clear_config_otp(sm);
-	}
-
-	return resp;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_gtc_init;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_gtc.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_gtc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_gtc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_gtc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,145 @@
+/*
+ * EAP peer method: EAP-GTC (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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 "eap_i.h"
+
+
+struct eap_gtc_data {
+	int prefix;
+};
+
+
+static void * eap_gtc_init(struct eap_sm *sm)
+{
+	struct eap_gtc_data *data;
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+	    sm->m->method == EAP_TYPE_FAST) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+			   "with challenge/response");
+		data->prefix = 1;
+	}
+	return data;
+}
+
+
+static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_gtc_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_gtc_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *password, *identity;
+	size_t password_len, identity_len, len, plen;
+	int otp;
+	u8 id;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	id = eap_get_id(reqData);
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
+	if (data->prefix &&
+	    (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
+			   "expected prefix");
+
+		/* Send an empty response in order to allow tunneled
+		 * acknowledgement of the failure. This will also cover the
+		 * error case which seems to use EAP-MSCHAPv2 like error
+		 * reporting with EAP-GTC inside EAP-FAST tunnel. */
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+				     0, EAP_CODE_RESPONSE, id);
+		return resp;
+	}
+
+	password = eap_get_config_otp(sm, &password_len);
+	if (password)
+		otp = 1;
+	else {
+		password = eap_get_config_password(sm, &password_len);
+		otp = 0;
+	}
+
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+		eap_sm_request_otp(sm, (const char *) pos, len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+
+	ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	plen = password_len;
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity == NULL)
+		return NULL;
+	if (data->prefix)
+		plen += 9 + identity_len + 1;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+	if (data->prefix) {
+		wpabuf_put_data(resp, "RESPONSE=", 9);
+		wpabuf_put_data(resp, identity, identity_len);
+		wpabuf_put_u8(resp, '\0');
+	}
+	wpabuf_put_data(resp, password, password_len);
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
+			      wpabuf_head_u8(resp) + sizeof(struct eap_hdr) +
+			      1, plen);
+
+	if (otp) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
+		eap_clear_config_otp(sm);
+	}
+
+	return resp;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gtc_init;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_i.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,355 +0,0 @@
-/*
- * EAP peer state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_I_H
-#define EAP_I_H
-
-#include "wpabuf.h"
-#include "eap_peer/eap.h"
-#include "eap_common/eap_common.h"
-
-/* 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);
-};
-
-
-/**
- * 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 */
-	const struct eap_method *m; /* selected EAP method */
-	/* not defined in RFC 4137 */
-	Boolean changed;
-	void *eapol_ctx;
-	struct eapol_callbacks *eapol_cb;
-	void *eap_method_priv;
-	int init_phase2;
-	int fast_reauth;
-
-	Boolean rxResp /* LEAP only */;
-	Boolean leap_done;
-	Boolean peap_done;
-	u8 req_md5[16]; /* MD5() of the current EAP packet */
-	u8 last_md5[16]; /* MD5() of the previously received EAP packet; used
-			  * in duplicate request detection. */
-
-	void *msg_ctx;
-	void *scard_ctx;
-	void *ssl_ctx;
-
-	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;
-};
-
-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);
-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);
-
-#endif /* EAP_I_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap_i.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_i.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,354 @@
+/*
+ * EAP peer state machines internal structures (RFC 4137)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at 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 "eap_peer/eap.h"
+#include "eap_common/eap_common.h"
+
+/* 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);
+};
+
+
+/**
+ * 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 */
+	const struct eap_method *m; /* selected EAP method */
+	/* not defined in RFC 4137 */
+	Boolean changed;
+	void *eapol_ctx;
+	struct eapol_callbacks *eapol_cb;
+	void *eap_method_priv;
+	int init_phase2;
+	int fast_reauth;
+
+	Boolean rxResp /* LEAP only */;
+	Boolean leap_done;
+	Boolean peap_done;
+	u8 req_md5[16]; /* MD5() of the current EAP packet */
+	u8 last_md5[16]; /* MD5() 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 ext_password_data *ext_pw;
+	struct wpabuf *ext_pw_buf;
+};
+
+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);
+
+#endif /* EAP_I_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_ikev2.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_ikev2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,506 +0,0 @@
-/*
- * EAP-IKEv2 peer (RFC 5106)
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_common/eap_ikev2_common.h"
-#include "ikev2.h"
-
-
-struct eap_ikev2_data {
-	struct ikev2_responder_data ikev2;
-	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	size_t out_used;
-	size_t fragment_size;
-	int keys_ready;
-	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
-	int keymat_ok;
-};
-
-
-static const char * eap_ikev2_state_txt(int state)
-{
-	switch (state) {
-	case WAIT_START:
-		return "WAIT_START";
-	case PROC_MSG:
-		return "PROC_MSG";
-	case WAIT_FRAG_ACK:
-		return "WAIT_FRAG_ACK";
-	case DONE:
-		return "DONE";
-	case FAIL:
-		return "FAIL";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
-		   eap_ikev2_state_txt(data->state),
-		   eap_ikev2_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_ikev2_init(struct eap_sm *sm)
-{
-	struct eap_ikev2_data *data;
-	const u8 *identity, *password;
-	size_t identity_len, password_len;
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity == NULL) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = WAIT_START;
-	data->fragment_size = IKEV2_FRAGMENT_SIZE;
-	data->ikev2.state = SA_INIT;
-	data->ikev2.peer_auth = PEER_AUTH_SECRET;
-	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
-	if (data->ikev2.key_pad == NULL)
-		goto failed;
-	data->ikev2.key_pad_len = 21;
-	data->ikev2.IDr = os_malloc(identity_len);
-	if (data->ikev2.IDr == NULL)
-		goto failed;
-	os_memcpy(data->ikev2.IDr, identity, identity_len);
-	data->ikev2.IDr_len = identity_len;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (password) {
-		data->ikev2.shared_secret = os_malloc(password_len);
-		if (data->ikev2.shared_secret == NULL)
-			goto failed;
-		os_memcpy(data->ikev2.shared_secret, password, password_len);
-		data->ikev2.shared_secret_len = password_len;
-	}
-
-	return data;
-
-failed:
-	ikev2_responder_deinit(&data->ikev2);
-	os_free(data);
-	return NULL;
-}
-
-
-static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_ikev2_data *data = priv;
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	ikev2_responder_deinit(&data->ikev2);
-	os_free(data);
-}
-
-
-static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
-{
-	if (eap_ikev2_derive_keymat(
-		    data->ikev2.proposal.prf, &data->ikev2.keys,
-		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
-		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
-		    data->keymat) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
-			   "derive key material");
-		return -1;
-	}
-	data->keymat_ok = 1;
-	return 0;
-}
-
-
-static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
-					   struct eap_method_ret *ret, u8 id)
-{
-	struct wpabuf *resp;
-	u8 flags;
-	size_t send_len, plen, icv_len = 0;
-
-	ret->ignore = FALSE;
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
-	ret->allowNotifications = TRUE;
-
-	flags = 0;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (1 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 1;
-		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
-		if (data->out_used == 0) {
-			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-			send_len -= 4;
-		}
-	}
-#ifdef CCNS_PL
-	/* Some issues figuring out the length of the message if Message Length
-	 * field not included?! */
-	if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
-		flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-#endif /* CCNS_PL */
-
-	plen = 1 + send_len;
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
-		plen += 4;
-	if (data->keys_ready) {
-		const struct ikev2_integ_alg *integ;
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
-			   "Data");
-		flags |= IKEV2_FLAGS_ICV_INCLUDED;
-		integ = ikev2_get_integ(data->ikev2.proposal.integ);
-		if (integ == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
-				   "transform / cannot generate ICV");
-			return NULL;
-		}
-		icv_len = integ->hash_len;
-
-		plen += icv_len;
-	}
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, flags); /* Flags */
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
-		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
-		const u8 *msg = wpabuf_head(resp);
-		size_t len = wpabuf_len(resp);
-		ikev2_integ_hash(data->ikev2.proposal.integ,
-				 data->ikev2.keys.SK_ar,
-				 data->ikev2.keys.SK_integ_len,
-				 msg, len, wpabuf_put(resp, icv_len));
-	}
-
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-		switch (data->ikev2.state) {
-		case SA_AUTH:
-			/* SA_INIT was sent out, so message have to be
-			 * integrity protected from now on. */
-			data->keys_ready = 1;
-			break;
-		case IKEV2_DONE:
-			ret->methodState = METHOD_DONE;
-			if (data->state == FAIL)
-				break;
-			ret->decision = DECISION_COND_SUCC;
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
-				   "completed successfully");
-			if (eap_ikev2_peer_keymat(data))
-				break;
-			eap_ikev2_state(data, DONE);
-			break;
-		case IKEV2_FAILED:
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
-				   "failed");
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			break;
-		default:
-			break;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		eap_ikev2_state(data, WAIT_FRAG_ACK);
-	}
-
-	return resp;
-}
-
-
-static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
-				 const struct wpabuf *reqData,
-				 u8 flags, const u8 *pos, const u8 **end)
-{
-	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
-		int icv_len = eap_ikev2_validate_icv(
-			data->ikev2.proposal.integ, &data->ikev2.keys, 1,
-			reqData, pos, *end);
-		if (icv_len < 0)
-			return -1;
-		/* Hide Integrity Checksum Data from further processing */
-		*end -= icv_len;
-	} else if (data->keys_ready) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
-			   "included integrity checksum");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
-				  const u8 *buf, size_t len)
-{
-	/* Process continuation of a pending message */
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
-		eap_ikev2_state(data, FAIL);
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting "
-		   "for %lu bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
-						  struct eap_method_ret *ret,
-						  u8 id, u8 flags,
-						  u32 message_length,
-						  const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
-			   "a fragmented packet");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
-				   "message");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
-}
-
-
-static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
-					 struct eap_method_ret *ret,
-					 const struct wpabuf *reqData)
-{
-	struct eap_ikev2_data *data = priv;
-	const u8 *start, *pos, *end;
-	size_t len;
-	u8 flags, id;
-	u32 message_length = 0;
-	struct wpabuf tmpbuf;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
-	if (pos == NULL) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	id = eap_get_id(reqData);
-
-	start = pos;
-	end = start + len;
-
-	if (len == 0)
-		flags = 0; /* fragment ack */
-	else
-		flags = *pos++;
-
-	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		message_length = WPA_GET_BE32(pos);
-		pos += 4;
-
-		if (message_length < (u32) (end - pos)) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
-				   "Length (%d; %ld remaining in this msg)",
-				   message_length, (long) (end - pos));
-			ret->ignore = TRUE;
-			return NULL;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
-		   "Message Length %u", flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-#ifdef CCNS_PL
-		if (len > 1) /* Empty Flags field included in ACK */
-#else /* CCNS_PL */
-		if (len != 0)
-#endif /* CCNS_PL */
-		{
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
-				   "in WAIT_FRAG_ACK state");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
-		eap_ikev2_state(data, PROC_MSG);
-		return eap_ikev2_build_msg(data, ret, id);
-	}
-
-	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-		
-	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
-		return eap_ikev2_process_fragment(data, ret, id, flags,
-						  message_length, pos,
-						  end - pos);
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
-		if (data->in_buf == &tmpbuf)
-			data->in_buf = NULL;
-		eap_ikev2_state(data, FAIL);
-		return NULL;
-	}
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-
-	if (data->out_buf == NULL) {
-		data->out_buf = ikev2_responder_build(&data->ikev2);
-		if (data->out_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
-				   "IKEv2 message");
-			return NULL;
-		}
-		data->out_used = 0;
-	}
-
-	eap_ikev2_state(data, PROC_MSG);
-	return eap_ikev2_build_msg(data, ret, id);
-}
-
-
-static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_ikev2_data *data = priv;
-	return data->state == DONE && data->keymat_ok;
-}
-
-
-static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_ikev2_data *data = priv;
-	u8 *key;
-
-	if (data->state != DONE || !data->keymat_ok)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key) {
-		os_memcpy(key, data->keymat, EAP_MSK_LEN);
-		*len = EAP_MSK_LEN;
-	}
-
-	return key;
-}
-
-
-static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_ikev2_data *data = priv;
-	u8 *key;
-
-	if (data->state != DONE || !data->keymat_ok)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key) {
-		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
-		*len = EAP_EMSK_LEN;
-	}
-
-	return key;
-}
-
-
-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,
-				    "IKEV2");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_ikev2_init;
-	eap->deinit = eap_ikev2_deinit;
-	eap->process = eap_ikev2_process;
-	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
-	eap->getKey = eap_ikev2_getKey;
-	eap->get_emsk = eap_ikev2_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_ikev2.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_ikev2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_ikev2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,500 @@
+/*
+ * EAP-IKEv2 peer (RFC 5106)
+ * Copyright (c) 2007, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_common/eap_ikev2_common.h"
+#include "ikev2.h"
+
+
+struct eap_ikev2_data {
+	struct ikev2_responder_data ikev2;
+	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
+	int keys_ready;
+	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
+	int keymat_ok;
+};
+
+
+static const char * eap_ikev2_state_txt(int state)
+{
+	switch (state) {
+	case WAIT_START:
+		return "WAIT_START";
+	case PROC_MSG:
+		return "PROC_MSG";
+	case WAIT_FRAG_ACK:
+		return "WAIT_FRAG_ACK";
+	case DONE:
+		return "DONE";
+	case FAIL:
+		return "FAIL";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
+		   eap_ikev2_state_txt(data->state),
+		   eap_ikev2_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_ikev2_init(struct eap_sm *sm)
+{
+	struct eap_ikev2_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity == NULL) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = WAIT_START;
+	data->fragment_size = IKEV2_FRAGMENT_SIZE;
+	data->ikev2.state = SA_INIT;
+	data->ikev2.peer_auth = PEER_AUTH_SECRET;
+	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
+	if (data->ikev2.key_pad == NULL)
+		goto failed;
+	data->ikev2.key_pad_len = 21;
+	data->ikev2.IDr = os_malloc(identity_len);
+	if (data->ikev2.IDr == NULL)
+		goto failed;
+	os_memcpy(data->ikev2.IDr, identity, identity_len);
+	data->ikev2.IDr_len = identity_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password) {
+		data->ikev2.shared_secret = os_malloc(password_len);
+		if (data->ikev2.shared_secret == NULL)
+			goto failed;
+		os_memcpy(data->ikev2.shared_secret, password, password_len);
+		data->ikev2.shared_secret_len = password_len;
+	}
+
+	return data;
+
+failed:
+	ikev2_responder_deinit(&data->ikev2);
+	os_free(data);
+	return NULL;
+}
+
+
+static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_ikev2_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	ikev2_responder_deinit(&data->ikev2);
+	os_free(data);
+}
+
+
+static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data)
+{
+	if (eap_ikev2_derive_keymat(
+		    data->ikev2.proposal.prf, &data->ikev2.keys,
+		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
+		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
+		    data->keymat) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
+			   "derive key material");
+		return -1;
+	}
+	data->keymat_ok = 1;
+	return 0;
+}
+
+
+static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
+					   struct eap_method_ret *ret, u8 id)
+{
+	struct wpabuf *resp;
+	u8 flags;
+	size_t send_len, plen, icv_len = 0;
+
+	ret->ignore = FALSE;
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+#ifdef CCNS_PL
+	/* Some issues figuring out the length of the message if Message Length
+	 * field not included?! */
+	if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
+		flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
+#endif /* CCNS_PL */
+
+	plen = 1 + send_len;
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	if (data->keys_ready) {
+		const struct ikev2_integ_alg *integ;
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
+			   "Data");
+		flags |= IKEV2_FLAGS_ICV_INCLUDED;
+		integ = ikev2_get_integ(data->ikev2.proposal.integ);
+		if (integ == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
+				   "transform / cannot generate ICV");
+			return NULL;
+		}
+		icv_len = integ->hash_len;
+
+		plen += icv_len;
+	}
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, flags); /* Flags */
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
+		const u8 *msg = wpabuf_head(resp);
+		size_t len = wpabuf_len(resp);
+		ikev2_integ_hash(data->ikev2.proposal.integ,
+				 data->ikev2.keys.SK_ar,
+				 data->ikev2.keys.SK_integ_len,
+				 msg, len, wpabuf_put(resp, icv_len));
+	}
+
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		switch (data->ikev2.state) {
+		case SA_AUTH:
+			/* SA_INIT was sent out, so message have to be
+			 * integrity protected from now on. */
+			data->keys_ready = 1;
+			break;
+		case IKEV2_DONE:
+			ret->methodState = METHOD_DONE;
+			if (data->state == FAIL)
+				break;
+			ret->decision = DECISION_COND_SUCC;
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
+				   "completed successfully");
+			if (eap_ikev2_peer_keymat(data))
+				break;
+			eap_ikev2_state(data, DONE);
+			break;
+		case IKEV2_FAILED:
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication "
+				   "failed");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			break;
+		default:
+			break;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_ikev2_state(data, WAIT_FRAG_ACK);
+	}
+
+	return resp;
+}
+
+
+static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
+				 const struct wpabuf *reqData,
+				 u8 flags, const u8 *pos, const u8 **end)
+{
+	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
+		int icv_len = eap_ikev2_validate_icv(
+			data->ikev2.proposal.integ, &data->ikev2.keys, 1,
+			reqData, pos, *end);
+		if (icv_len < 0)
+			return -1;
+		/* Hide Integrity Checksum Data from further processing */
+		*end -= icv_len;
+	} else if (data->keys_ready) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
+			   "included integrity checksum");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
+				  const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
+		eap_ikev2_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting "
+		   "for %lu bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data,
+						  struct eap_method_ret *ret,
+						  u8 id, u8 flags,
+						  u32 message_length,
+						  const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
+			   "a fragmented packet");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
+				   "message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
+}
+
+
+static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
+					 struct eap_method_ret *ret,
+					 const struct wpabuf *reqData)
+{
+	struct eap_ikev2_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 flags, id;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+
+	start = pos;
+	end = start + len;
+
+	if (len == 0)
+		flags = 0; /* fragment ack */
+	else
+		flags = *pos++;
+
+	if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+#ifdef CCNS_PL
+		if (len > 1) /* Empty Flags field included in ACK */
+#else /* CCNS_PL */
+		if (len != 0)
+#endif /* CCNS_PL */
+		{
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
+				   "in WAIT_FRAG_ACK state");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
+		eap_ikev2_state(data, PROC_MSG);
+		return eap_ikev2_build_msg(data, ret, id);
+	}
+
+	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+		
+	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
+		return eap_ikev2_process_fragment(data, ret, id, flags,
+						  message_length, pos,
+						  end - pos);
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) {
+		if (data->in_buf == &tmpbuf)
+			data->in_buf = NULL;
+		eap_ikev2_state(data, FAIL);
+		return NULL;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+
+	if (data->out_buf == NULL) {
+		data->out_buf = ikev2_responder_build(&data->ikev2);
+		if (data->out_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate "
+				   "IKEv2 message");
+			return NULL;
+		}
+		data->out_used = 0;
+	}
+
+	eap_ikev2_state(data, PROC_MSG);
+	return eap_ikev2_build_msg(data, ret, id);
+}
+
+
+static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_ikev2_data *data = priv;
+	return data->state == DONE && data->keymat_ok;
+}
+
+
+static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ikev2_data *data = priv;
+	u8 *key;
+
+	if (data->state != DONE || !data->keymat_ok)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key) {
+		os_memcpy(key, data->keymat, EAP_MSK_LEN);
+		*len = EAP_MSK_LEN;
+	}
+
+	return key;
+}
+
+
+static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ikev2_data *data = priv;
+	u8 *key;
+
+	if (data->state != DONE || !data->keymat_ok)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key) {
+		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
+		*len = EAP_EMSK_LEN;
+	}
+
+	return key;
+}
+
+
+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,
+				    "IKEV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_ikev2_init;
+	eap->deinit = eap_ikev2_deinit;
+	eap->process = eap_ikev2_process;
+	eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
+	eap->getKey = eap_ikev2_getKey;
+	eap->get_emsk = eap_ikev2_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_leap.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_leap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_leap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,415 +0,0 @@
-/*
- * EAP peer method: LEAP
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-#include "crypto/crypto.h"
-#include "eap_i.h"
-
-#define LEAP_VERSION 1
-#define LEAP_CHALLENGE_LEN 8
-#define LEAP_RESPONSE_LEN 24
-#define LEAP_KEY_LEN 16
-
-
-struct eap_leap_data {
-	enum {
-		LEAP_WAIT_CHALLENGE,
-		LEAP_WAIT_SUCCESS,
-		LEAP_WAIT_RESPONSE,
-		LEAP_DONE
-	} state;
-
-	u8 peer_challenge[LEAP_CHALLENGE_LEN];
-	u8 peer_response[LEAP_RESPONSE_LEN];
-
-	u8 ap_challenge[LEAP_CHALLENGE_LEN];
-	u8 ap_response[LEAP_RESPONSE_LEN];
-};
-
-
-static void * eap_leap_init(struct eap_sm *sm)
-{
-	struct eap_leap_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = LEAP_WAIT_CHALLENGE;
-
-	sm->leap_done = FALSE;
-	return data;
-}
-
-
-static void eap_leap_deinit(struct eap_sm *sm, void *priv)
-{
-	os_free(priv);
-}
-
-
-static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
-						struct eap_method_ret *ret,
-						const struct wpabuf *reqData)
-{
-	struct eap_leap_data *data = priv;
-	struct wpabuf *resp;
-	const u8 *pos, *challenge, *identity, *password;
-	u8 challenge_len, *rpos;
-	size_t identity_len, password_len, len;
-	int pwhash;
-
-	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	password = eap_get_config_password2(sm, &password_len, &pwhash);
-	if (identity == NULL || password == NULL)
-		return NULL;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
-	if (pos == NULL || len < 3) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (*pos != LEAP_VERSION) {
-		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
-			   "%d", *pos);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	pos++;
-
-	pos++; /* skip unused byte */
-
-	challenge_len = *pos++;
-	if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
-			   "(challenge_len=%d reqDataLen=%lu)",
-			   challenge_len, (unsigned long) wpabuf_len(reqData));
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	challenge = pos;
-	os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
-		    challenge, LEAP_CHALLENGE_LEN);
-
-	wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
-			     3 + LEAP_RESPONSE_LEN + identity_len,
-			     EAP_CODE_RESPONSE, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-	wpabuf_put_u8(resp, LEAP_VERSION);
-	wpabuf_put_u8(resp, 0); /* unused */
-	wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
-	rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
-	if (pwhash)
-		challenge_response(challenge, password, rpos);
-	else
-		nt_challenge_response(challenge, password, password_len, rpos);
-	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
-		    rpos, LEAP_RESPONSE_LEN);
-	wpabuf_put_data(resp, identity, identity_len);
-
-	data->state = LEAP_WAIT_SUCCESS;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
-						struct eap_method_ret *ret,
-						const struct wpabuf *reqData)
-{
-	struct eap_leap_data *data = priv;
-	struct wpabuf *resp;
-	u8 *pos;
-	const u8 *identity;
-	size_t identity_len;
-
-	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity == NULL)
-		return NULL;
-
-	if (data->state != LEAP_WAIT_SUCCESS) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
-			   "unexpected state (%d) - ignored", data->state);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
-			     3 + LEAP_CHALLENGE_LEN + identity_len,
-			     EAP_CODE_REQUEST, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-	wpabuf_put_u8(resp, LEAP_VERSION);
-	wpabuf_put_u8(resp, 0); /* unused */
-	wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
-	pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
-	if (os_get_random(pos, LEAP_CHALLENGE_LEN)) {
-		wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
-			   "for challenge");
-		wpabuf_free(resp);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
-		    LEAP_CHALLENGE_LEN);
-	wpabuf_put_data(resp, identity, identity_len);
-
-	data->state = LEAP_WAIT_RESPONSE;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
-						 struct eap_method_ret *ret,
-						 const struct wpabuf *reqData)
-{
-	struct eap_leap_data *data = priv;
-	const u8 *pos, *password;
-	u8 response_len, pw_hash[16], pw_hash_hash[16],
-		expected[LEAP_RESPONSE_LEN];
-	size_t password_len, len;
-	int pwhash;
-
-	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
-
-	password = eap_get_config_password2(sm, &password_len, &pwhash);
-	if (password == NULL)
-		return NULL;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
-	if (pos == NULL || len < 3) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (*pos != LEAP_VERSION) {
-		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
-			   "%d", *pos);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	pos++;
-
-	pos++; /* skip unused byte */
-
-	response_len = *pos++;
-	if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
-			   "(response_len=%d reqDataLen=%lu)",
-			   response_len, (unsigned long) wpabuf_len(reqData));
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
-		    pos, LEAP_RESPONSE_LEN);
-	os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
-
-	if (pwhash) {
-		if (hash_nt_password_hash(password, pw_hash_hash)) {
-			ret->ignore = TRUE;
-			return NULL;
-		}
-	} else {
-		if (nt_password_hash(password, password_len, pw_hash) ||
-		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
-			ret->ignore = TRUE;
-			return NULL;
-		}
-	}
-	challenge_response(data->ap_challenge, pw_hash_hash, expected);
-
-	ret->methodState = METHOD_DONE;
-	ret->allowNotifications = FALSE;
-
-	if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
-		wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
-			   "response - authentication failed");
-		wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
-			    expected, LEAP_RESPONSE_LEN);
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-
-	ret->decision = DECISION_UNCOND_SUCC;
-
-	/* LEAP is somewhat odd method since it sends EAP-Success in the middle
-	 * of the authentication. Use special variable to transit EAP state
-	 * machine to SUCCESS state. */
-	sm->leap_done = TRUE;
-	data->state = LEAP_DONE;
-
-	/* No more authentication messages expected; AP will send EAPOL-Key
-	 * frames if encryption is enabled. */
-	return NULL;
-}
-
-
-static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
-					struct eap_method_ret *ret,
-					const struct wpabuf *reqData)
-{
-	const struct eap_hdr *eap;
-	size_t password_len;
-	const u8 *password;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
-		eap_sm_request_password(sm);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	/*
-	 * LEAP needs to be able to handle EAP-Success frame which does not
-	 * include Type field. Consequently, eap_hdr_validate() cannot be used
-	 * here. This validation will be done separately for EAP-Request and
-	 * EAP-Response frames.
-	 */
-	eap = wpabuf_head(reqData);
-	if (wpabuf_len(reqData) < sizeof(*eap) ||
-	    be_to_host16(eap->length) > wpabuf_len(reqData)) {
-		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ret->ignore = FALSE;
-	ret->allowNotifications = TRUE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-
-	sm->leap_done = FALSE;
-
-	switch (eap->code) {
-	case EAP_CODE_REQUEST:
-		return eap_leap_process_request(sm, priv, ret, reqData);
-	case EAP_CODE_SUCCESS:
-		return eap_leap_process_success(sm, priv, ret, reqData);
-	case EAP_CODE_RESPONSE:
-		return eap_leap_process_response(sm, priv, ret, reqData);
-	default:
-		wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
-			   "ignored", eap->code);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-}
-
-
-static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_leap_data *data = priv;
-	return data->state == LEAP_DONE;
-}
-
-
-static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_leap_data *data = priv;
-	u8 *key, pw_hash_hash[16], pw_hash[16];
-	const u8 *addr[5], *password;
-	size_t elen[5], password_len;
-	int pwhash;
-
-	if (data->state != LEAP_DONE)
-		return NULL;
-
-	password = eap_get_config_password2(sm, &password_len, &pwhash);
-	if (password == NULL)
-		return NULL;
-
-	key = os_malloc(LEAP_KEY_LEN);
-	if (key == NULL)
-		return NULL;
-
-	if (pwhash) {
-		if (hash_nt_password_hash(password, pw_hash_hash)) {
-			os_free(key);
-			return NULL;
-		}
-	} else {
-		if (nt_password_hash(password, password_len, pw_hash) ||
-		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
-			os_free(key);
-			return NULL;
-		}
-	}
-	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
-			pw_hash_hash, 16);
-	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
-		    data->peer_challenge, LEAP_CHALLENGE_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
-		    data->peer_response, LEAP_RESPONSE_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
-		    data->ap_challenge, LEAP_CHALLENGE_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
-		    data->ap_response, LEAP_RESPONSE_LEN);
-
-	addr[0] = pw_hash_hash;
-	elen[0] = 16;
-	addr[1] = data->ap_challenge;
-	elen[1] = LEAP_CHALLENGE_LEN;
-	addr[2] = data->ap_response;
-	elen[2] = LEAP_RESPONSE_LEN;
-	addr[3] = data->peer_challenge;
-	elen[3] = LEAP_CHALLENGE_LEN;
-	addr[4] = data->peer_response;
-	elen[4] = LEAP_RESPONSE_LEN;
-	md5_vector(5, addr, elen, key);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
-	*len = LEAP_KEY_LEN;
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_leap_init;
-	eap->deinit = eap_leap_deinit;
-	eap->process = eap_leap_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_leap.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_leap.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_leap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_leap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,410 @@
+/*
+ * EAP peer method: LEAP
+ * Copyright (c) 2004-2007, Jouni Malinen <j at 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/ms_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "eap_i.h"
+
+#define LEAP_VERSION 1
+#define LEAP_CHALLENGE_LEN 8
+#define LEAP_RESPONSE_LEN 24
+#define LEAP_KEY_LEN 16
+
+
+struct eap_leap_data {
+	enum {
+		LEAP_WAIT_CHALLENGE,
+		LEAP_WAIT_SUCCESS,
+		LEAP_WAIT_RESPONSE,
+		LEAP_DONE
+	} state;
+
+	u8 peer_challenge[LEAP_CHALLENGE_LEN];
+	u8 peer_response[LEAP_RESPONSE_LEN];
+
+	u8 ap_challenge[LEAP_CHALLENGE_LEN];
+	u8 ap_response[LEAP_RESPONSE_LEN];
+};
+
+
+static void * eap_leap_init(struct eap_sm *sm)
+{
+	struct eap_leap_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = LEAP_WAIT_CHALLENGE;
+
+	sm->leap_done = FALSE;
+	return data;
+}
+
+
+static void eap_leap_deinit(struct eap_sm *sm, void *priv)
+{
+	os_free(priv);
+}
+
+
+static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
+						struct eap_method_ret *ret,
+						const struct wpabuf *reqData)
+{
+	struct eap_leap_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *challenge, *identity, *password;
+	u8 challenge_len, *rpos;
+	size_t identity_len, password_len, len;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return NULL;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
+	if (pos == NULL || len < 3) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (*pos != LEAP_VERSION) {
+		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
+			   "%d", *pos);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	pos++;
+
+	pos++; /* skip unused byte */
+
+	challenge_len = *pos++;
+	if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
+			   "(challenge_len=%d reqDataLen=%lu)",
+			   challenge_len, (unsigned long) wpabuf_len(reqData));
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	challenge = pos;
+	os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
+		    challenge, LEAP_CHALLENGE_LEN);
+
+	wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
+			     3 + LEAP_RESPONSE_LEN + identity_len,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+	wpabuf_put_u8(resp, LEAP_VERSION);
+	wpabuf_put_u8(resp, 0); /* unused */
+	wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
+	rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
+	if (pwhash)
+		challenge_response(challenge, password, rpos);
+	else
+		nt_challenge_response(challenge, password, password_len, rpos);
+	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
+		    rpos, LEAP_RESPONSE_LEN);
+	wpabuf_put_data(resp, identity, identity_len);
+
+	data->state = LEAP_WAIT_SUCCESS;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
+						struct eap_method_ret *ret,
+						const struct wpabuf *reqData)
+{
+	struct eap_leap_data *data = priv;
+	struct wpabuf *resp;
+	u8 *pos;
+	const u8 *identity;
+	size_t identity_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity == NULL)
+		return NULL;
+
+	if (data->state != LEAP_WAIT_SUCCESS) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
+			   "unexpected state (%d) - ignored", data->state);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
+			     3 + LEAP_CHALLENGE_LEN + identity_len,
+			     EAP_CODE_REQUEST, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+	wpabuf_put_u8(resp, LEAP_VERSION);
+	wpabuf_put_u8(resp, 0); /* unused */
+	wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
+	pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
+	if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
+			   "for challenge");
+		wpabuf_free(resp);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
+		    LEAP_CHALLENGE_LEN);
+	wpabuf_put_data(resp, identity, identity_len);
+
+	data->state = LEAP_WAIT_RESPONSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
+						 struct eap_method_ret *ret,
+						 const struct wpabuf *reqData)
+{
+	struct eap_leap_data *data = priv;
+	const u8 *pos, *password;
+	u8 response_len, pw_hash[16], pw_hash_hash[16],
+		expected[LEAP_RESPONSE_LEN];
+	size_t password_len, len;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
+
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (password == NULL)
+		return NULL;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
+	if (pos == NULL || len < 3) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (*pos != LEAP_VERSION) {
+		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
+			   "%d", *pos);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	pos++;
+
+	pos++; /* skip unused byte */
+
+	response_len = *pos++;
+	if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
+			   "(response_len=%d reqDataLen=%lu)",
+			   response_len, (unsigned long) wpabuf_len(reqData));
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
+		    pos, LEAP_RESPONSE_LEN);
+	os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
+
+	if (pwhash) {
+		if (hash_nt_password_hash(password, pw_hash_hash)) {
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	} else {
+		if (nt_password_hash(password, password_len, pw_hash) ||
+		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+	challenge_response(data->ap_challenge, pw_hash_hash, expected);
+
+	ret->methodState = METHOD_DONE;
+	ret->allowNotifications = FALSE;
+
+	if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
+		wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
+			   "response - authentication failed");
+		wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
+			    expected, LEAP_RESPONSE_LEN);
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+
+	ret->decision = DECISION_UNCOND_SUCC;
+
+	/* LEAP is somewhat odd method since it sends EAP-Success in the middle
+	 * of the authentication. Use special variable to transit EAP state
+	 * machine to SUCCESS state. */
+	sm->leap_done = TRUE;
+	data->state = LEAP_DONE;
+
+	/* No more authentication messages expected; AP will send EAPOL-Key
+	 * frames if encryption is enabled. */
+	return NULL;
+}
+
+
+static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	const struct eap_hdr *eap;
+	size_t password_len;
+	const u8 *password;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
+		eap_sm_request_password(sm);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	/*
+	 * LEAP needs to be able to handle EAP-Success frame which does not
+	 * include Type field. Consequently, eap_hdr_validate() cannot be used
+	 * here. This validation will be done separately for EAP-Request and
+	 * EAP-Response frames.
+	 */
+	eap = wpabuf_head(reqData);
+	if (wpabuf_len(reqData) < sizeof(*eap) ||
+	    be_to_host16(eap->length) > wpabuf_len(reqData)) {
+		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+	ret->allowNotifications = TRUE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+
+	sm->leap_done = FALSE;
+
+	switch (eap->code) {
+	case EAP_CODE_REQUEST:
+		return eap_leap_process_request(sm, priv, ret, reqData);
+	case EAP_CODE_SUCCESS:
+		return eap_leap_process_success(sm, priv, ret, reqData);
+	case EAP_CODE_RESPONSE:
+		return eap_leap_process_response(sm, priv, ret, reqData);
+	default:
+		wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
+			   "ignored", eap->code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+}
+
+
+static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_leap_data *data = priv;
+	return data->state == LEAP_DONE;
+}
+
+
+static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_leap_data *data = priv;
+	u8 *key, pw_hash_hash[16], pw_hash[16];
+	const u8 *addr[5], *password;
+	size_t elen[5], password_len;
+	int pwhash;
+
+	if (data->state != LEAP_DONE)
+		return NULL;
+
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (password == NULL)
+		return NULL;
+
+	key = os_malloc(LEAP_KEY_LEN);
+	if (key == NULL)
+		return NULL;
+
+	if (pwhash) {
+		if (hash_nt_password_hash(password, pw_hash_hash)) {
+			os_free(key);
+			return NULL;
+		}
+	} else {
+		if (nt_password_hash(password, password_len, pw_hash) ||
+		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
+			os_free(key);
+			return NULL;
+		}
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
+			pw_hash_hash, 16);
+	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
+		    data->peer_challenge, LEAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
+		    data->peer_response, LEAP_RESPONSE_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
+		    data->ap_challenge, LEAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
+		    data->ap_response, LEAP_RESPONSE_LEN);
+
+	addr[0] = pw_hash_hash;
+	elen[0] = 16;
+	addr[1] = data->ap_challenge;
+	elen[1] = LEAP_CHALLENGE_LEN;
+	addr[2] = data->ap_response;
+	elen[2] = LEAP_RESPONSE_LEN;
+	addr[3] = data->peer_challenge;
+	elen[3] = LEAP_CHALLENGE_LEN;
+	addr[4] = data->peer_response;
+	elen[4] = LEAP_RESPONSE_LEN;
+	md5_vector(5, addr, elen, key);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
+	*len = LEAP_KEY_LEN;
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_leap_init;
+	eap->deinit = eap_leap_deinit;
+	eap->process = eap_leap_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_md5.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_md5.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,120 +0,0 @@
-/*
- * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_common/chap.h"
-
-
-static void * eap_md5_init(struct eap_sm *sm)
-{
-	/* No need for private data. However, must return non-NULL to indicate
-	 * success. */
-	return (void *) 1;
-}
-
-
-static void eap_md5_deinit(struct eap_sm *sm, void *priv)
-{
-}
-
-
-static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct wpabuf *resp;
-	const u8 *pos, *challenge, *password;
-	u8 *rpos, id;
-	size_t len, challenge_len, password_len;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
-		eap_sm_request_password(sm);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
-	if (pos == NULL || len == 0) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
-			   pos, (unsigned long) len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	/*
-	 * CHAP Challenge:
-	 * Value-Size (1 octet) | Value(Challenge) | Name(optional)
-	 */
-	challenge_len = *pos++;
-	if (challenge_len == 0 || challenge_len > len - 1) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
-			   "(challenge_len=%lu len=%lu)",
-			   (unsigned long) challenge_len, (unsigned long) len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	ret->ignore = FALSE;
-	challenge = pos;
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
-		    challenge, challenge_len);
-
-	wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_COND_SUCC;
-	ret->allowNotifications = TRUE;
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
-			     EAP_CODE_RESPONSE, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-
-	/*
-	 * CHAP Response:
-	 * Value-Size (1 octet) | Value(Response) | Name(optional)
-	 */
-	wpabuf_put_u8(resp, CHAP_MD5_LEN);
-
-	id = eap_get_id(resp);
-	rpos = wpabuf_put(resp, CHAP_MD5_LEN);
-	chap_md5(id, password, password_len, challenge, challenge_len, rpos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
-
-	return resp;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_md5_init;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_md5.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_md5.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_md5.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,120 @@
+/*
+ * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_common/chap.h"
+
+
+static void * eap_md5_init(struct eap_sm *sm)
+{
+	/* No need for private data. However, must return non-NULL to indicate
+	 * success. */
+	return (void *) 1;
+}
+
+
+static void eap_md5_deinit(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *challenge, *password;
+	u8 *rpos, id;
+	size_t len, challenge_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+		eap_sm_request_password(sm);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
+	if (pos == NULL || len == 0) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
+			   pos, (unsigned long) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	/*
+	 * CHAP Challenge:
+	 * Value-Size (1 octet) | Value(Challenge) | Name(optional)
+	 */
+	challenge_len = *pos++;
+	if (challenge_len == 0 || challenge_len > len - 1) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
+			   "(challenge_len=%lu len=%lu)",
+			   (unsigned long) challenge_len, (unsigned long) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	ret->ignore = FALSE;
+	challenge = pos;
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
+		    challenge, challenge_len);
+
+	wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = TRUE;
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+
+	/*
+	 * CHAP Response:
+	 * Value-Size (1 octet) | Value(Response) | Name(optional)
+	 */
+	wpabuf_put_u8(resp, CHAP_MD5_LEN);
+
+	id = eap_get_id(resp);
+	rpos = wpabuf_put(resp, CHAP_MD5_LEN);
+	if (chap_md5(id, password, password_len, challenge, challenge_len,
+		     rpos)) {
+		wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+		ret->ignore = TRUE;
+		wpabuf_free(resp);
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
+
+	return resp;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_md5_init;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_methods.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_methods.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_methods.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,373 +0,0 @@
-/*
- * EAP peer: Method registration
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#ifdef CONFIG_DYNAMIC_EAP_METHODS
-#include <dlfcn.h>
-#endif /* CONFIG_DYNAMIC_EAP_METHODS */
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_methods.h"
-
-
-static struct eap_method *eap_methods = NULL;
-
-
-/**
- * eap_peer_get_eap_method - Get EAP method based on type number
- * @vendor: EAP Vendor-Id (0 = IETF)
- * @method: EAP type number
- * Returns: Pointer to EAP method or %NULL if not found
- */
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (m->vendor == vendor && m->method == method)
-			return m;
-	}
-	return NULL;
-}
-
-
-/**
- * eap_peer_get_type - Get EAP type for the given EAP method name
- * @name: EAP method name, e.g., TLS
- * @vendor: Buffer for returning EAP Vendor-Id
- * Returns: EAP method type or %EAP_TYPE_NONE if not found
- *
- * This function maps EAP type names into EAP type numbers based on the list of
- * EAP methods included in the build.
- */
-EapType eap_peer_get_type(const char *name, int *vendor)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (os_strcmp(m->name, name) == 0) {
-			*vendor = m->vendor;
-			return m->method;
-		}
-	}
-	*vendor = EAP_VENDOR_IETF;
-	return EAP_TYPE_NONE;
-}
-
-
-/**
- * eap_get_name - Get EAP method name for the given EAP type
- * @vendor: EAP Vendor-Id (0 = IETF)
- * @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
- *
- * This function maps EAP type numbers into EAP type names based on the list of
- * EAP methods included in the build.
- */
-const char * eap_get_name(int vendor, EapType type)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (m->vendor == vendor && m->method == type)
-			return m->name;
-	}
-	return NULL;
-}
-
-
-/**
- * eap_get_names - Get space separated list of names for supported EAP methods
- * @buf: Buffer for names
- * @buflen: Buffer length
- * Returns: Number of characters written into buf (not including nul
- * termination)
- */
-size_t eap_get_names(char *buf, size_t buflen)
-{
-	char *pos, *end;
-	struct eap_method *m;
-	int ret;
-
-	if (buflen == 0)
-		return 0;
-
-	pos = buf;
-	end = pos + buflen;
-
-	for (m = eap_methods; m; m = m->next) {
-		ret = os_snprintf(pos, end - pos, "%s%s",
-				  m == eap_methods ? "" : " ", m->name);
-		if (ret < 0 || ret >= end - pos)
-			break;
-		pos += ret;
-	}
-	buf[buflen - 1] = '\0';
-
-	return pos - buf;
-}
-
-
-/**
- * eap_get_names_as_string_array - Get supported EAP methods as string array
- * @num: Buffer for returning the number of items in array, not including %NULL
- * terminator. This parameter can be %NULL if the length is not needed.
- * Returns: A %NULL-terminated array of strings, or %NULL on error.
- *
- * This function returns the list of names for all supported EAP methods as an
- * array of strings. The caller must free the returned array items and the
- * array.
- */
-char ** eap_get_names_as_string_array(size_t *num)
-{
-	struct eap_method *m;
-	size_t array_len = 0;
-	char **array;
-	int i = 0, j;
-
-	for (m = eap_methods; m; m = m->next)
-		array_len++;
-
-	array = os_zalloc(sizeof(char *) * (array_len + 1));
-	if (array == NULL)
-		return NULL;
-
-	for (m = eap_methods; m; m = m->next) {
-		array[i++] = os_strdup(m->name);
-		if (array[i - 1] == NULL) {
-			for (j = 0; j < i; j++)
-				os_free(array[j]);
-			os_free(array);
-			return NULL;
-		}
-	}
-	array[i] = NULL;
-
-	if (num)
-		*num = array_len;
-
-	return array;
-}
-
-
-/**
- * eap_peer_get_methods - Get a list of enabled EAP peer methods
- * @count: Set to number of available methods
- * Returns: List of enabled EAP peer methods
- */
-const struct eap_method * eap_peer_get_methods(size_t *count)
-{
-	int c = 0;
-	struct eap_method *m;
-
-	for (m = eap_methods; m; m = m->next)
-		c++;
-	
-	*count = c;
-	return eap_methods;
-}
-
-
-#ifdef CONFIG_DYNAMIC_EAP_METHODS
-/**
- * eap_peer_method_load - Load a dynamic EAP method library (shared object)
- * @so: File path for the shared object file to load
- * Returns: 0 on success, -1 on failure
- */
-int eap_peer_method_load(const char *so)
-{
-	void *handle;
-	int (*dyn_init)(void);
-	int ret;
-
-	handle = dlopen(so, RTLD_LAZY);
-	if (handle == NULL) {
-		wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
-			   "'%s': %s", so, dlerror());
-		return -1;
-	}
-
-	dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
-	if (dyn_init == NULL) {
-		dlclose(handle);
-		wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
-			   "eap_peer_method_dynamic_init()", so);
-		return -1;
-	}
-
-	ret = dyn_init();
-	if (ret) {
-		dlclose(handle);
-		wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
-			   "ret %d", so, ret);
-		return ret;
-	}
-
-	/* Store the handle for this shared object. It will be freed with
-	 * dlclose() when the EAP method is unregistered. */
-	eap_methods->dl_handle = handle;
-
-	wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
-
-	return 0;
-}
-
-
-/**
- * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
- * @method: Pointer to the dynamically loaded EAP method
- * Returns: 0 on success, -1 on failure
- *
- * This function can be used to unload EAP methods that have been previously
- * loaded with eap_peer_method_load(). Before unloading the method, all
- * references to the method must be removed to make sure that no dereferences
- * of freed memory will occur after unloading.
- */
-int eap_peer_method_unload(struct eap_method *method)
-{
-	struct eap_method *m, *prev;
-	void *handle;
-
-	m = eap_methods;
-	prev = NULL;
-	while (m) {
-		if (m == method)
-			break;
-		prev = m;
-		m = m->next;
-	}
-
-	if (m == NULL || m->dl_handle == NULL)
-		return -1;
-
-	if (prev)
-		prev->next = m->next;
-	else
-		eap_methods = m->next;
-
-	handle = m->dl_handle;
-
-	if (m->free)
-		m->free(m);
-	else
-		eap_peer_method_free(m);
-
-	dlclose(handle);
-
-	return 0;
-}
-#endif /* CONFIG_DYNAMIC_EAP_METHODS */
-
-
-/**
- * eap_peer_method_alloc - Allocate EAP peer method structure
- * @version: Version of the EAP peer method interface (set to
- * EAP_PEER_METHOD_INTERFACE_VERSION)
- * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
- * @method: EAP type number (EAP_TYPE_*)
- * @name: Name of the method (e.g., "TLS")
- * Returns: Allocated EAP method structure or %NULL on failure
- *
- * The returned structure should be freed with eap_peer_method_free() when it
- * is not needed anymore.
- */
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
-					  EapType method, const char *name)
-{
-	struct eap_method *eap;
-	eap = os_zalloc(sizeof(*eap));
-	if (eap == NULL)
-		return NULL;
-	eap->version = version;
-	eap->vendor = vendor;
-	eap->method = method;
-	eap->name = name;
-	return eap;
-}
-
-
-/**
- * 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)
-{
-	os_free(method);
-}
-
-
-/**
- * eap_peer_method_register - Register an EAP peer method
- * @method: EAP method to register
- * 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.
- */
-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)
-		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)
-			return -2;
-		last = m;
-	}
-
-	if (last)
-		last->next = method;
-	else
-		eap_methods = method;
-
-	return 0;
-}
-
-
-/**
- * eap_peer_unregister_methods - Unregister EAP peer methods
- *
- * This function is called at program termination to unregister all EAP peer
- * methods.
- */
-void eap_peer_unregister_methods(void)
-{
-	struct eap_method *m;
-#ifdef CONFIG_DYNAMIC_EAP_METHODS
-	void *handle;
-#endif /* CONFIG_DYNAMIC_EAP_METHODS */
-
-	while (eap_methods) {
-		m = eap_methods;
-		eap_methods = eap_methods->next;
-
-#ifdef CONFIG_DYNAMIC_EAP_METHODS
-		handle = m->dl_handle;
-#endif /* CONFIG_DYNAMIC_EAP_METHODS */
-
-		if (m->free)
-			m->free(m);
-		else
-			eap_peer_method_free(m);
-
-#ifdef CONFIG_DYNAMIC_EAP_METHODS
-		if (handle)
-			dlclose(handle);
-#endif /* CONFIG_DYNAMIC_EAP_METHODS */
-	}
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_methods.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_methods.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_methods.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_methods.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,369 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+#include <dlfcn.h>
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods = NULL;
+
+
+/**
+ * eap_peer_get_eap_method - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == method)
+			return m;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_peer_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_peer_get_type(const char *name, int *vendor)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (os_strcmp(m->name, name) == 0) {
+			*vendor = m->vendor;
+			return m->method;
+		}
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_get_name - Get EAP method name for the given EAP type
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @type: EAP method type
+ * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ *
+ * This function maps EAP type numbers into EAP type names based on the list of
+ * EAP methods included in the build.
+ */
+const char * eap_get_name(int vendor, EapType type)
+{
+	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == type)
+			return m->name;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_get_names - Get space separated list of names for supported EAP methods
+ * @buf: Buffer for names
+ * @buflen: Buffer length
+ * Returns: Number of characters written into buf (not including nul
+ * termination)
+ */
+size_t eap_get_names(char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct eap_method *m;
+	int ret;
+
+	if (buflen == 0)
+		return 0;
+
+	pos = buf;
+	end = pos + buflen;
+
+	for (m = eap_methods; m; m = m->next) {
+		ret = os_snprintf(pos, end - pos, "%s%s",
+				  m == eap_methods ? "" : " ", m->name);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+	}
+	buf[buflen - 1] = '\0';
+
+	return pos - buf;
+}
+
+
+/**
+ * eap_get_names_as_string_array - Get supported EAP methods as string array
+ * @num: Buffer for returning the number of items in array, not including %NULL
+ * terminator. This parameter can be %NULL if the length is not needed.
+ * Returns: A %NULL-terminated array of strings, or %NULL on error.
+ *
+ * This function returns the list of names for all supported EAP methods as an
+ * array of strings. The caller must free the returned array items and the
+ * array.
+ */
+char ** eap_get_names_as_string_array(size_t *num)
+{
+	struct eap_method *m;
+	size_t array_len = 0;
+	char **array;
+	int i = 0, j;
+
+	for (m = eap_methods; m; m = m->next)
+		array_len++;
+
+	array = os_zalloc(sizeof(char *) * (array_len + 1));
+	if (array == NULL)
+		return NULL;
+
+	for (m = eap_methods; m; m = m->next) {
+		array[i++] = os_strdup(m->name);
+		if (array[i - 1] == NULL) {
+			for (j = 0; j < i; j++)
+				os_free(array[j]);
+			os_free(array);
+			return NULL;
+		}
+	}
+	array[i] = NULL;
+
+	if (num)
+		*num = array_len;
+
+	return array;
+}
+
+
+/**
+ * eap_peer_get_methods - Get a list of enabled EAP peer methods
+ * @count: Set to number of available methods
+ * Returns: List of enabled EAP peer methods
+ */
+const struct eap_method * eap_peer_get_methods(size_t *count)
+{
+	int c = 0;
+	struct eap_method *m;
+
+	for (m = eap_methods; m; m = m->next)
+		c++;
+	
+	*count = c;
+	return eap_methods;
+}
+
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+/**
+ * eap_peer_method_load - Load a dynamic EAP method library (shared object)
+ * @so: File path for the shared object file to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_method_load(const char *so)
+{
+	void *handle;
+	int (*dyn_init)(void);
+	int ret;
+
+	handle = dlopen(so, RTLD_LAZY);
+	if (handle == NULL) {
+		wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
+			   "'%s': %s", so, dlerror());
+		return -1;
+	}
+
+	dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
+	if (dyn_init == NULL) {
+		dlclose(handle);
+		wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
+			   "eap_peer_method_dynamic_init()", so);
+		return -1;
+	}
+
+	ret = dyn_init();
+	if (ret) {
+		dlclose(handle);
+		wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
+			   "ret %d", so, ret);
+		return ret;
+	}
+
+	/* Store the handle for this shared object. It will be freed with
+	 * dlclose() when the EAP method is unregistered. */
+	eap_methods->dl_handle = handle;
+
+	wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
+ * @method: Pointer to the dynamically loaded EAP method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to unload EAP methods that have been previously
+ * loaded with eap_peer_method_load(). Before unloading the method, all
+ * references to the method must be removed to make sure that no dereferences
+ * of freed memory will occur after unloading.
+ */
+int eap_peer_method_unload(struct eap_method *method)
+{
+	struct eap_method *m, *prev;
+	void *handle;
+
+	m = eap_methods;
+	prev = NULL;
+	while (m) {
+		if (m == method)
+			break;
+		prev = m;
+		m = m->next;
+	}
+
+	if (m == NULL || m->dl_handle == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = m->next;
+	else
+		eap_methods = m->next;
+
+	handle = m->dl_handle;
+
+	if (m->free)
+		m->free(m);
+	else
+		eap_peer_method_free(m);
+
+	dlclose(handle);
+
+	return 0;
+}
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+
+/**
+ * eap_peer_method_alloc - Allocate EAP peer method structure
+ * @version: Version of the EAP peer method interface (set to
+ * EAP_PEER_METHOD_INTERFACE_VERSION)
+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ * @method: EAP type number (EAP_TYPE_*)
+ * @name: Name of the method (e.g., "TLS")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_peer_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_peer_method_alloc(int version, int vendor,
+					  EapType method, const char *name)
+{
+	struct eap_method *eap;
+	eap = os_zalloc(sizeof(*eap));
+	if (eap == NULL)
+		return NULL;
+	eap->version = version;
+	eap->vendor = vendor;
+	eap->method = method;
+	eap->name = name;
+	return eap;
+}
+
+
+/**
+ * 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)
+{
+	os_free(method);
+}
+
+
+/**
+ * eap_peer_method_register - Register an EAP peer method
+ * @method: EAP method to register
+ * 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.
+ */
+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)
+		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)
+			return -2;
+		last = m;
+	}
+
+	if (last)
+		last->next = method;
+	else
+		eap_methods = method;
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_unregister_methods - Unregister EAP peer methods
+ *
+ * This function is called at program termination to unregister all EAP peer
+ * methods.
+ */
+void eap_peer_unregister_methods(void)
+{
+	struct eap_method *m;
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+	void *handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+	while (eap_methods) {
+		m = eap_methods;
+		eap_methods = eap_methods->next;
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+		handle = m->dl_handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+		if (m->free)
+			m->free(m);
+		else
+			eap_peer_method_free(m);
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+		if (handle)
+			dlclose(handle);
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+	}
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_methods.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_methods.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_methods.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,113 +0,0 @@
-/*
- * EAP peer: Method registration
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_METHODS_H
-#define EAP_METHODS_H
-
-#include "eap_common/eap_defs.h"
-
-const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
-const struct eap_method * eap_peer_get_methods(size_t *count);
-
-struct eap_method * eap_peer_method_alloc(int version, int vendor,
-					  EapType method, const char *name);
-void eap_peer_method_free(struct eap_method *method);
-int eap_peer_method_register(struct eap_method *method);
-
-
-#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)
-{
-	return 0;
-}
-
-static inline int eap_peer_method_unload(struct eap_method *method)
-{
-	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_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);
-
-#endif /* EAP_METHODS_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap_methods.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_methods.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_methods.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_methods.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,109 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2007, Jouni Malinen <j at 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"
+
+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);
+void eap_peer_method_free(struct eap_method *method);
+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)
+{
+	return 0;
+}
+
+static inline int eap_peer_method_unload(struct eap_method *method)
+{
+	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_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);
+
+#endif /* EAP_METHODS_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_mschapv2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,882 +0,0 @@
-/*
- * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
- * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
- * Extensions Protocol, Version 2, for mutual authentication and key
- * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
- * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
- * RFC 3079.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-#include "common/wpa_ctrl.h"
-#include "mschapv2.h"
-#include "eap_i.h"
-#include "eap_config.h"
-
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_mschapv2_hdr {
-	u8 op_code; /* MSCHAPV2_OP_* */
-	u8 mschapv2_id; /* usually same as EAP identifier; must be changed
-			 * for challenges, but not for success/failure */
-	u8 ms_length[2]; /* Note: misaligned; length - 5 */
-	/* followed by data */
-} STRUCT_PACKED;
-
-/* Response Data field */
-struct ms_response {
-	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
-	u8 reserved[8];
-	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
-	u8 flags;
-} STRUCT_PACKED;
-
-/* Change-Password Data field */
-struct ms_change_password {
-	u8 encr_password[516];
-	u8 encr_hash[16];
-	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
-	u8 reserved[8];
-	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
-	u8 flags[2];
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define MSCHAPV2_OP_CHALLENGE 1
-#define MSCHAPV2_OP_RESPONSE 2
-#define MSCHAPV2_OP_SUCCESS 3
-#define MSCHAPV2_OP_FAILURE 4
-#define MSCHAPV2_OP_CHANGE_PASSWORD 7
-
-#define ERROR_RESTRICTED_LOGON_HOURS 646
-#define ERROR_ACCT_DISABLED 647
-#define ERROR_PASSWD_EXPIRED 648
-#define ERROR_NO_DIALIN_PERMISSION 649
-#define ERROR_AUTHENTICATION_FAILURE 691
-#define ERROR_CHANGING_PASSWORD 709
-
-#define PASSWD_CHANGE_CHAL_LEN 16
-#define MSCHAPV2_KEY_LEN 16
-
-
-struct eap_mschapv2_data {
-	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
-	int auth_response_valid;
-
-	int prev_error;
-	u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
-	int passwd_change_challenge_valid;
-	int passwd_change_version;
-
-	/* Optional challenge values generated in EAP-FAST Phase 1 negotiation
-	 */
-	u8 *peer_challenge;
-	u8 *auth_challenge;
-
-	int phase2;
-	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
-	int master_key_valid;
-	int success;
-
-	struct wpabuf *prev_challenge;
-};
-
-
-static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
-
-
-static void * eap_mschapv2_init(struct eap_sm *sm)
-{
-	struct eap_mschapv2_data *data;
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	if (sm->peer_challenge) {
-		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
-		if (data->peer_challenge == NULL) {
-			eap_mschapv2_deinit(sm, data);
-			return NULL;
-		}
-		os_memcpy(data->peer_challenge, sm->peer_challenge,
-			  MSCHAPV2_CHAL_LEN);
-	}
-
-	if (sm->auth_challenge) {
-		data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
-		if (data->auth_challenge == NULL) {
-			eap_mschapv2_deinit(sm, data);
-			return NULL;
-		}
-		os_memcpy(data->auth_challenge, sm->auth_challenge,
-			  MSCHAPV2_CHAL_LEN);
-	}
-
-	data->phase2 = sm->init_phase2;
-
-	return data;
-}
-
-
-static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_mschapv2_data *data = priv;
-	os_free(data->peer_challenge);
-	os_free(data->auth_challenge);
-	wpabuf_free(data->prev_challenge);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_mschapv2_challenge_reply(
-	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id,
-	u8 mschapv2_id, const u8 *auth_challenge)
-{
-	struct wpabuf *resp;
-	struct eap_mschapv2_hdr *ms;
-	u8 *peer_challenge;
-	int ms_len;
-	struct ms_response *r;
-	size_t identity_len, password_len;
-	const u8 *identity, *password;
-	int pwhash;
-
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	password = eap_get_config_password2(sm, &password_len, &pwhash);
-	if (identity == NULL || password == NULL)
-		return NULL;
-
-	ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	ms = wpabuf_put(resp, sizeof(*ms));
-	ms->op_code = MSCHAPV2_OP_RESPONSE;
-	ms->mschapv2_id = mschapv2_id;
-	if (data->prev_error) {
-		/*
-		 * TODO: this does not seem to be enough when processing two
-		 * or more failure messages. IAS did not increment mschapv2_id
-		 * in its own packets, but it seemed to expect the peer to
-		 * increment this for all packets(?).
-		 */
-		ms->mschapv2_id++;
-	}
-	WPA_PUT_BE16(ms->ms_length, ms_len);
-
-	wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */
-
-	/* Response */
-	r = wpabuf_put(resp, sizeof(*r));
-	peer_challenge = r->peer_challenge;
-	if (data->peer_challenge) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
-			   "in Phase 1");
-		peer_challenge = data->peer_challenge;
-		os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
-	} else if (os_get_random(peer_challenge, MSCHAPV2_CHAL_LEN)) {
-		wpabuf_free(resp);
-		return NULL;
-	}
-	os_memset(r->reserved, 0, 8);
-	if (data->auth_challenge) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
-			   "in Phase 1");
-		auth_challenge = data->auth_challenge;
-	}
-	if (mschapv2_derive_response(identity, identity_len, password,
-				     password_len, pwhash, auth_challenge,
-				     peer_challenge, r->nt_response,
-				     data->auth_response, data->master_key)) {
-		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive "
-			   "response");
-		wpabuf_free(resp);
-		return NULL;
-	}
-	data->auth_response_valid = 1;
-	data->master_key_valid = 1;
-
-	r->flags = 0; /* reserved, must be zero */
-
-	wpabuf_put_data(resp, identity, identity_len);
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
-		   "(response)", id, ms->mschapv2_id);
-	return resp;
-}
-
-
-/**
- * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @data: Pointer to private EAP method data from eap_mschapv2_init()
- * @ret: Return values from EAP request validation and processing
- * @req: Pointer to EAP-MSCHAPv2 header from the request
- * @req_len: Length of the EAP-MSCHAPv2 data
- * @id: EAP identifier used in the request
- * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
- * no reply available
- */
-static struct wpabuf * eap_mschapv2_challenge(
-	struct eap_sm *sm, struct eap_mschapv2_data *data,
-	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
-	size_t req_len, u8 id)
-{
-	size_t len, challenge_len;
-	const u8 *pos, *challenge;
-
-	if (eap_get_config_identity(sm, &len) == NULL ||
-	    eap_get_config_password(sm, &len) == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
-	if (req_len < sizeof(*req) + 1) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
-			   "(len %lu)", (unsigned long) req_len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	pos = (const u8 *) (req + 1);
-	challenge_len = *pos++;
-	len = req_len - sizeof(*req) - 1;
-	if (challenge_len != MSCHAPV2_CHAL_LEN) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
-			   "%lu", (unsigned long) challenge_len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (len < challenge_len) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
-			   " packet: len=%lu challenge_len=%lu",
-			   (unsigned long) len, (unsigned long) challenge_len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->passwd_change_challenge_valid) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
-			   "failure message");
-		challenge = data->passwd_change_challenge;
-	} else
-		challenge = pos;
-	pos += challenge_len;
-	len -= challenge_len;
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
-		    pos, len);
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
-					    challenge);
-}
-
-
-static void eap_mschapv2_password_changed(struct eap_sm *sm,
-					  struct eap_mschapv2_data *data)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config && config->new_password) {
-		wpa_msg(sm->msg_ctx, MSG_INFO,
-			WPA_EVENT_PASSWORD_CHANGED
-			"EAP-MSCHAPV2: Password changed successfully");
-		data->prev_error = 0;
-		os_free(config->password);
-		if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
-			config->password = os_malloc(16);
-			config->password_len = 16;
-			if (config->password) {
-				nt_password_hash(config->new_password,
-						 config->new_password_len,
-						 config->password);
-			}
-			os_free(config->new_password);
-		} else {
-			config->password = config->new_password;
-			config->password_len = config->new_password_len;
-		}
-		config->new_password = NULL;
-		config->new_password_len = 0;
-	}
-}
-
-
-/**
- * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @data: Pointer to private EAP method data from eap_mschapv2_init()
- * @ret: Return values from EAP request validation and processing
- * @req: Pointer to EAP-MSCHAPv2 header from the request
- * @req_len: Length of the EAP-MSCHAPv2 data
- * @id: EAP identifier used in th erequest
- * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
- * no reply available
- */
-static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
-					    struct eap_mschapv2_data *data,
-					    struct eap_method_ret *ret,
-					    const struct eap_mschapv2_hdr *req,
-					    size_t req_len, u8 id)
-{
-	struct wpabuf *resp;
-	const u8 *pos;
-	size_t len;
-
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
-	len = req_len - sizeof(*req);
-	pos = (const u8 *) (req + 1);
-	if (!data->auth_response_valid ||
-	    mschapv2_verify_auth_response(data->auth_response, pos, len)) {
-		wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
-			   "response in success request");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
-	len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
-	while (len > 0 && *pos == ' ') {
-		pos++;
-		len--;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
-			  pos, len);
-	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
-
-	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
-	 * message. */
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
-			   "buffer for success response");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
-
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	ret->allowNotifications = FALSE;
-	data->success = 1;
-
-	if (data->prev_error == ERROR_PASSWD_EXPIRED)
-		eap_mschapv2_password_changed(sm, data);
-
-	return resp;
-}
-
-
-static int eap_mschapv2_failure_txt(struct eap_sm *sm,
-				    struct eap_mschapv2_data *data, char *txt)
-{
-	char *pos, *msg = "";
-	int retry = 1;
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	/* For example:
-	 * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
-	 */
-
-	pos = txt;
-
-	if (pos && os_strncmp(pos, "E=", 2) == 0) {
-		pos += 2;
-		data->prev_error = atoi(pos);
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
-			   data->prev_error);
-		pos = os_strchr(pos, ' ');
-		if (pos)
-			pos++;
-	}
-
-	if (pos && os_strncmp(pos, "R=", 2) == 0) {
-		pos += 2;
-		retry = atoi(pos);
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
-			   retry == 1 ? "" : "not ");
-		pos = os_strchr(pos, ' ');
-		if (pos)
-			pos++;
-	}
-
-	if (pos && os_strncmp(pos, "C=", 2) == 0) {
-		int hex_len;
-		pos += 2;
-		hex_len = os_strchr(pos, ' ') - (char *) pos;
-		if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
-			if (hexstr2bin(pos, data->passwd_change_challenge,
-				       PASSWD_CHANGE_CHAL_LEN)) {
-				wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
-					   "failure challenge");
-			} else {
-				wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
-					    "challenge",
-					    data->passwd_change_challenge,
-					    PASSWD_CHANGE_CHAL_LEN);
-				data->passwd_change_challenge_valid = 1;
-			}
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
-				   "challenge len %d", hex_len);
-		}
-		pos = os_strchr(pos, ' ');
-		if (pos)
-			pos++;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
-			   "was not present in failure message");
-	}
-
-	if (pos && os_strncmp(pos, "V=", 2) == 0) {
-		pos += 2;
-		data->passwd_change_version = atoi(pos);
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
-			   "protocol version %d", data->passwd_change_version);
-		pos = os_strchr(pos, ' ');
-		if (pos)
-			pos++;
-	}
-
-	if (pos && os_strncmp(pos, "M=", 2) == 0) {
-		pos += 2;
-		msg = pos;
-	}
-	wpa_msg(sm->msg_ctx, MSG_WARNING,
-		"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
-		"%d)",
-		msg, retry == 1 ? "" : "not ", data->prev_error);
-	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
-	    data->passwd_change_version == 3 && config) {
-		if (config->new_password == NULL) {
-			wpa_msg(sm->msg_ctx, MSG_INFO,
-				"EAP-MSCHAPV2: Password expired - password "
-				"change required");
-			eap_sm_request_new_password(sm);
-		}
-	} else if (retry == 1 && config) {
-		/* TODO: could prevent the current password from being used
-		 * again at least for some period of time */
-		if (!config->mschapv2_retry)
-			eap_sm_request_identity(sm);
-		eap_sm_request_password(sm);
-		config->mschapv2_retry = 1;
-	} else if (config) {
-		/* TODO: prevent retries using same username/password */
-		config->mschapv2_retry = 0;
-	}
-
-	return retry == 1;
-}
-
-
-static struct wpabuf * eap_mschapv2_change_password(
-	struct eap_sm *sm, struct eap_mschapv2_data *data,
-	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
-{
-	struct wpabuf *resp;
-	int ms_len;
-	const u8 *username, *password, *new_password;
-	size_t username_len, password_len, new_password_len;
-	struct eap_mschapv2_hdr *ms;
-	struct ms_change_password *cp;
-	u8 password_hash[16], password_hash_hash[16];
-	int pwhash;
-
-	username = eap_get_config_identity(sm, &username_len);
-	password = eap_get_config_password2(sm, &password_len, &pwhash);
-	new_password = eap_get_config_new_password(sm, &new_password_len);
-	if (username == NULL || password == NULL || new_password == NULL)
-		return NULL;
-
-	username = mschapv2_remove_domain(username, &username_len);
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_COND_SUCC;
-	ret->allowNotifications = TRUE;
-
-	ms_len = sizeof(*ms) + sizeof(*cp);
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	ms = wpabuf_put(resp, sizeof(*ms));
-	ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
-	ms->mschapv2_id = req->mschapv2_id + 1;
-	WPA_PUT_BE16(ms->ms_length, ms_len);
-	cp = wpabuf_put(resp, sizeof(*cp));
-
-	/* Encrypted-Password */
-	if (pwhash) {
-		if (encrypt_pw_block_with_password_hash(
-			    new_password, new_password_len,
-			    password, cp->encr_password))
-			goto fail;
-	} else {
-		if (new_password_encrypted_with_old_nt_password_hash(
-			    new_password, new_password_len,
-			    password, password_len, cp->encr_password))
-			goto fail;
-	}
-
-	/* Encrypted-Hash */
-	if (pwhash) {
-		u8 new_password_hash[16];
-		nt_password_hash(new_password, new_password_len,
-				 new_password_hash);
-		nt_password_hash_encrypted_with_block(password,
-						      new_password_hash,
-						      cp->encr_hash);
-	} else {
-		old_nt_password_hash_encrypted_with_new_nt_password_hash(
-			new_password, new_password_len,
-			password, password_len, cp->encr_hash);
-	}
-
-	/* Peer-Challenge */
-	if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
-		goto fail;
-
-	/* Reserved, must be zero */
-	os_memset(cp->reserved, 0, 8);
-
-	/* NT-Response */
-	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
-		    data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
-		    cp->peer_challenge, MSCHAPV2_CHAL_LEN);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
-			  username, username_len);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
-			      new_password, new_password_len);
-	generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
-			     username, username_len,
-			     new_password, new_password_len,
-			     cp->nt_response);
-	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
-		    cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
-
-	/* Authenticator response is not really needed yet, but calculate it
-	 * here so that challenges need not be saved. */
-	generate_authenticator_response(new_password, new_password_len,
-					cp->peer_challenge,
-					data->passwd_change_challenge,
-					username, username_len,
-					cp->nt_response, data->auth_response);
-	data->auth_response_valid = 1;
-
-	/* Likewise, generate master_key here since we have the needed data
-	 * available. */
-	nt_password_hash(new_password, new_password_len, password_hash);
-	hash_nt_password_hash(password_hash, password_hash_hash);
-	get_master_key(password_hash_hash, cp->nt_response, data->master_key);
-	data->master_key_valid = 1;
-
-	/* Flags */
-	os_memset(cp->flags, 0, 2);
-
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
-		   "(change pw)", id, ms->mschapv2_id);
-
-	return resp;
-
-fail:
-	wpabuf_free(resp);
-	return NULL;
-}
-
-
-/**
- * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @data: Pointer to private EAP method data from eap_mschapv2_init()
- * @ret: Return values from EAP request validation and processing
- * @req: Pointer to EAP-MSCHAPv2 header from the request
- * @req_len: Length of the EAP-MSCHAPv2 data
- * @id: EAP identifier used in th erequest
- * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
- * no reply available
- */
-static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
-					    struct eap_mschapv2_data *data,
-					    struct eap_method_ret *ret,
-					    const struct eap_mschapv2_hdr *req,
-					    size_t req_len, u8 id)
-{
-	struct wpabuf *resp;
-	const u8 *msdata = (const u8 *) (req + 1);
-	char *buf;
-	size_t len = req_len - sizeof(*req);
-	int retry = 0;
-
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
-			  msdata, len);
-	/*
-	 * eap_mschapv2_failure_txt() expects a nul terminated string, so we
-	 * must allocate a large enough temporary buffer to create that since
-	 * the received message does not include nul termination.
-	 */
-	buf = os_malloc(len + 1);
-	if (buf) {
-		os_memcpy(buf, msdata, len);
-		buf[len] = '\0';
-		retry = eap_mschapv2_failure_txt(sm, data, buf);
-		os_free(buf);
-	}
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = FALSE;
-
-	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
-	    data->passwd_change_version == 3) {
-		struct eap_peer_config *config = eap_get_config(sm);
-		if (config && config->new_password)
-			return eap_mschapv2_change_password(sm, data, ret, req,
-							    id);
-		if (config && config->pending_req_new_password)
-			return NULL;
-	} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
-		/* TODO: could try to retry authentication, e.g, after having
-		 * changed the username/password. In this case, EAP MS-CHAP-v2
-		 * Failure Response would not be sent here. */
-		return NULL;
-	}
-
-	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
-	 * message. */
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
-
-	return resp;
-}
-
-
-static int eap_mschapv2_check_config(struct eap_sm *sm)
-{
-	size_t len;
-
-	if (eap_get_config_identity(sm, &len) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
-		eap_sm_request_identity(sm);
-		return -1;
-	}
-
-	if (eap_get_config_password(sm, &len) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
-		eap_sm_request_password(sm);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
-				    const struct eap_mschapv2_hdr *ms)
-{
-	size_t ms_len = WPA_GET_BE16(ms->ms_length);
-
-	if (ms_len == len)
-		return 0;
-
-	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
-		   "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
-	if (sm->workaround) {
-		/* Some authentication servers use invalid ms_len,
-		 * ignore it for interoperability. */
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
-			   " invalid ms_len %lu (len %lu)",
-			   (unsigned long) ms_len,
-			   (unsigned long) len);
-		return 0;
-	}
-
-	return -1;
-}
-
-
-static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
-					const struct wpabuf *reqData)
-{
-	/*
-	 * Store a copy of the challenge message, so that it can be processed
-	 * again in case retry is allowed after a possible failure.
-	 */
-	wpabuf_free(data->prev_challenge);
-	data->prev_challenge = wpabuf_dup(reqData);
-}
-
-
-/**
- * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @priv: Pointer to private EAP method data from eap_mschapv2_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) or %NULL if
- * no reply available
- */
-static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
-					    struct eap_method_ret *ret,
-					    const struct wpabuf *reqData)
-{
-	struct eap_mschapv2_data *data = priv;
-	struct eap_peer_config *config = eap_get_config(sm);
-	const struct eap_mschapv2_hdr *ms;
-	int using_prev_challenge = 0;
-	const u8 *pos;
-	size_t len;
-	u8 id;
-
-	if (eap_mschapv2_check_config(sm)) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (config->mschapv2_retry && data->prev_challenge &&
-	    data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
-			   "with the previous challenge");
-
-		reqData = data->prev_challenge;
-		using_prev_challenge = 1;
-		config->mschapv2_retry = 0;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
-			       &len);
-	if (pos == NULL || len < sizeof(*ms) + 1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ms = (const struct eap_mschapv2_hdr *) pos;
-	if (eap_mschapv2_check_mslen(sm, len, ms)) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	id = eap_get_id(reqData);
-	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
-		   id, ms->mschapv2_id);
-
-	switch (ms->op_code) {
-	case MSCHAPV2_OP_CHALLENGE:
-		if (!using_prev_challenge)
-			eap_mschapv2_copy_challenge(data, reqData);
-		return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
-	case MSCHAPV2_OP_SUCCESS:
-		return eap_mschapv2_success(sm, data, ret, ms, len, id);
-	case MSCHAPV2_OP_FAILURE:
-		return eap_mschapv2_failure(sm, data, ret, ms, len, id);
-	default:
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
-			   ms->op_code);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-}
-
-
-static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_mschapv2_data *data = priv;
-	return data->success && data->master_key_valid;
-}
-
-
-static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_mschapv2_data *data = priv;
-	u8 *key;
-	int key_len;
-
-	if (!data->master_key_valid || !data->success)
-		return NULL;
-
-	key_len = 2 * MSCHAPV2_KEY_LEN;
-
-	key = os_malloc(key_len);
-	if (key == NULL)
-		return NULL;
-
-	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
-	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
-	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 0, 0);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
-			key, key_len);
-
-	*len = key_len;
-	return key;
-}
-
-
-/**
- * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to register EAP-MSCHAPv2 peer method into the EAP
- * method list.
- */
-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,
-				    "MSCHAPV2");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_mschapv2_init;
-	eap->deinit = eap_mschapv2_deinit;
-	eap->process = eap_mschapv2_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_mschapv2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,879 @@
+/*
+ * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
+ * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
+ * Extensions Protocol, Version 2, for mutual authentication and key
+ * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
+ * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
+ * RFC 3079.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/random.h"
+#include "common/wpa_ctrl.h"
+#include "mschapv2.h"
+#include "eap_i.h"
+#include "eap_config.h"
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_mschapv2_hdr {
+	u8 op_code; /* MSCHAPV2_OP_* */
+	u8 mschapv2_id; /* usually same as EAP identifier; must be changed
+			 * for challenges, but not for success/failure */
+	u8 ms_length[2]; /* Note: misaligned; length - 5 */
+	/* followed by data */
+} STRUCT_PACKED;
+
+/* Response Data field */
+struct ms_response {
+	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+	u8 reserved[8];
+	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+	u8 flags;
+} STRUCT_PACKED;
+
+/* Change-Password Data field */
+struct ms_change_password {
+	u8 encr_password[516];
+	u8 encr_hash[16];
+	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+	u8 reserved[8];
+	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+	u8 flags[2];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define MSCHAPV2_OP_CHALLENGE 1
+#define MSCHAPV2_OP_RESPONSE 2
+#define MSCHAPV2_OP_SUCCESS 3
+#define MSCHAPV2_OP_FAILURE 4
+#define MSCHAPV2_OP_CHANGE_PASSWORD 7
+
+#define ERROR_RESTRICTED_LOGON_HOURS 646
+#define ERROR_ACCT_DISABLED 647
+#define ERROR_PASSWD_EXPIRED 648
+#define ERROR_NO_DIALIN_PERMISSION 649
+#define ERROR_AUTHENTICATION_FAILURE 691
+#define ERROR_CHANGING_PASSWORD 709
+
+#define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
+
+
+struct eap_mschapv2_data {
+	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
+	int auth_response_valid;
+
+	int prev_error;
+	u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
+	int passwd_change_challenge_valid;
+	int passwd_change_version;
+
+	/* Optional challenge values generated in EAP-FAST Phase 1 negotiation
+	 */
+	u8 *peer_challenge;
+	u8 *auth_challenge;
+
+	int phase2;
+	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
+	int master_key_valid;
+	int success;
+
+	struct wpabuf *prev_challenge;
+};
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_mschapv2_init(struct eap_sm *sm)
+{
+	struct eap_mschapv2_data *data;
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	if (sm->peer_challenge) {
+		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+		if (data->peer_challenge == NULL) {
+			eap_mschapv2_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->peer_challenge, sm->peer_challenge,
+			  MSCHAPV2_CHAL_LEN);
+	}
+
+	if (sm->auth_challenge) {
+		data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+		if (data->auth_challenge == NULL) {
+			eap_mschapv2_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->auth_challenge, sm->auth_challenge,
+			  MSCHAPV2_CHAL_LEN);
+	}
+
+	data->phase2 = sm->init_phase2;
+
+	return data;
+}
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	os_free(data->peer_challenge);
+	os_free(data->auth_challenge);
+	wpabuf_free(data->prev_challenge);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_mschapv2_challenge_reply(
+	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id,
+	u8 mschapv2_id, const u8 *auth_challenge)
+{
+	struct wpabuf *resp;
+	struct eap_mschapv2_hdr *ms;
+	u8 *peer_challenge;
+	int ms_len;
+	struct ms_response *r;
+	size_t identity_len, password_len;
+	const u8 *identity, *password;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return NULL;
+
+	ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	ms = wpabuf_put(resp, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_RESPONSE;
+	ms->mschapv2_id = mschapv2_id;
+	if (data->prev_error) {
+		/*
+		 * TODO: this does not seem to be enough when processing two
+		 * or more failure messages. IAS did not increment mschapv2_id
+		 * in its own packets, but it seemed to expect the peer to
+		 * increment this for all packets(?).
+		 */
+		ms->mschapv2_id++;
+	}
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */
+
+	/* Response */
+	r = wpabuf_put(resp, sizeof(*r));
+	peer_challenge = r->peer_challenge;
+	if (data->peer_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
+			   "in Phase 1");
+		peer_challenge = data->peer_challenge;
+		os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
+	} else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
+		wpabuf_free(resp);
+		return NULL;
+	}
+	os_memset(r->reserved, 0, 8);
+	if (data->auth_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
+			   "in Phase 1");
+		auth_challenge = data->auth_challenge;
+	}
+	if (mschapv2_derive_response(identity, identity_len, password,
+				     password_len, pwhash, auth_challenge,
+				     peer_challenge, r->nt_response,
+				     data->auth_response, data->master_key)) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive "
+			   "response");
+		wpabuf_free(resp);
+		return NULL;
+	}
+	data->auth_response_valid = 1;
+	data->master_key_valid = 1;
+
+	r->flags = 0; /* reserved, must be zero */
+
+	wpabuf_put_data(resp, identity, identity_len);
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+		   "(response)", id, ms->mschapv2_id);
+	return resp;
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in the request
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_challenge(
+	struct eap_sm *sm, struct eap_mschapv2_data *data,
+	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
+	size_t req_len, u8 id)
+{
+	size_t len, challenge_len;
+	const u8 *pos, *challenge;
+
+	if (eap_get_config_identity(sm, &len) == NULL ||
+	    eap_get_config_password(sm, &len) == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
+	if (req_len < sizeof(*req) + 1) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
+			   "(len %lu)", (unsigned long) req_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	pos = (const u8 *) (req + 1);
+	challenge_len = *pos++;
+	len = req_len - sizeof(*req) - 1;
+	if (challenge_len != MSCHAPV2_CHAL_LEN) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
+			   "%lu", (unsigned long) challenge_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (len < challenge_len) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
+			   " packet: len=%lu challenge_len=%lu",
+			   (unsigned long) len, (unsigned long) challenge_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->passwd_change_challenge_valid) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
+			   "failure message");
+		challenge = data->passwd_change_challenge;
+	} else
+		challenge = pos;
+	pos += challenge_len;
+	len -= challenge_len;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
+		    pos, len);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
+					    challenge);
+}
+
+
+static void eap_mschapv2_password_changed(struct eap_sm *sm,
+					  struct eap_mschapv2_data *data)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config && config->new_password) {
+		wpa_msg(sm->msg_ctx, MSG_INFO,
+			WPA_EVENT_PASSWORD_CHANGED
+			"EAP-MSCHAPV2: Password changed successfully");
+		data->prev_error = 0;
+		os_free(config->password);
+		if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+			/* TODO: update external storage */
+		} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
+			config->password = os_malloc(16);
+			config->password_len = 16;
+			if (config->password) {
+				nt_password_hash(config->new_password,
+						 config->new_password_len,
+						 config->password);
+			}
+			os_free(config->new_password);
+		} else {
+			config->password = config->new_password;
+			config->password_len = config->new_password_len;
+		}
+		config->new_password = NULL;
+		config->new_password_len = 0;
+	}
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
+					    struct eap_mschapv2_data *data,
+					    struct eap_method_ret *ret,
+					    const struct eap_mschapv2_hdr *req,
+					    size_t req_len, u8 id)
+{
+	struct wpabuf *resp;
+	const u8 *pos;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
+	len = req_len - sizeof(*req);
+	pos = (const u8 *) (req + 1);
+	if (!data->auth_response_valid ||
+	    mschapv2_verify_auth_response(data->auth_response, pos, len)) {
+		wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
+			   "response in success request");
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
+	len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
+	while (len > 0 && *pos == ' ') {
+		pos++;
+		len--;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
+			  pos, len);
+	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
+
+	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
+	 * message. */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
+			   "buffer for success response");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	ret->allowNotifications = FALSE;
+	data->success = 1;
+
+	if (data->prev_error == ERROR_PASSWD_EXPIRED)
+		eap_mschapv2_password_changed(sm, data);
+
+	return resp;
+}
+
+
+static int eap_mschapv2_failure_txt(struct eap_sm *sm,
+				    struct eap_mschapv2_data *data, char *txt)
+{
+	char *pos, *msg = "";
+	int retry = 1;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	/* For example:
+	 * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
+	 */
+
+	pos = txt;
+
+	if (pos && os_strncmp(pos, "E=", 2) == 0) {
+		pos += 2;
+		data->prev_error = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
+			   data->prev_error);
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "R=", 2) == 0) {
+		pos += 2;
+		retry = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
+			   retry == 1 ? "" : "not ");
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "C=", 2) == 0) {
+		int hex_len;
+		pos += 2;
+		hex_len = os_strchr(pos, ' ') - (char *) pos;
+		if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
+			if (hexstr2bin(pos, data->passwd_change_challenge,
+				       PASSWD_CHANGE_CHAL_LEN)) {
+				wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
+					   "failure challenge");
+			} else {
+				wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
+					    "challenge",
+					    data->passwd_change_challenge,
+					    PASSWD_CHANGE_CHAL_LEN);
+				data->passwd_change_challenge_valid = 1;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
+				   "challenge len %d", hex_len);
+		}
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
+			   "was not present in failure message");
+	}
+
+	if (pos && os_strncmp(pos, "V=", 2) == 0) {
+		pos += 2;
+		data->passwd_change_version = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
+			   "protocol version %d", data->passwd_change_version);
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "M=", 2) == 0) {
+		pos += 2;
+		msg = pos;
+	}
+	wpa_msg(sm->msg_ctx, MSG_WARNING,
+		"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
+		"%d)",
+		msg, retry == 1 ? "" : "not ", data->prev_error);
+	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+	    data->passwd_change_version == 3 && config) {
+		if (config->new_password == NULL) {
+			wpa_msg(sm->msg_ctx, MSG_INFO,
+				"EAP-MSCHAPV2: Password expired - password "
+				"change required");
+			eap_sm_request_new_password(sm);
+		}
+	} else if (retry == 1 && config) {
+		/* TODO: could prevent the current password from being used
+		 * again at least for some period of time */
+		if (!config->mschapv2_retry)
+			eap_sm_request_identity(sm);
+		eap_sm_request_password(sm);
+		config->mschapv2_retry = 1;
+	} else if (config) {
+		/* TODO: prevent retries using same username/password */
+		config->mschapv2_retry = 0;
+	}
+
+	return retry == 1;
+}
+
+
+static struct wpabuf * eap_mschapv2_change_password(
+	struct eap_sm *sm, struct eap_mschapv2_data *data,
+	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
+{
+	struct wpabuf *resp;
+	int ms_len;
+	const u8 *username, *password, *new_password;
+	size_t username_len, password_len, new_password_len;
+	struct eap_mschapv2_hdr *ms;
+	struct ms_change_password *cp;
+	u8 password_hash[16], password_hash_hash[16];
+	int pwhash;
+
+	username = eap_get_config_identity(sm, &username_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	new_password = eap_get_config_new_password(sm, &new_password_len);
+	if (username == NULL || password == NULL || new_password == NULL)
+		return NULL;
+
+	username = mschapv2_remove_domain(username, &username_len);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = TRUE;
+
+	ms_len = sizeof(*ms) + sizeof(*cp);
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	ms = wpabuf_put(resp, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
+	ms->mschapv2_id = req->mschapv2_id + 1;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+	cp = wpabuf_put(resp, sizeof(*cp));
+
+	/* Encrypted-Password */
+	if (pwhash) {
+		if (encrypt_pw_block_with_password_hash(
+			    new_password, new_password_len,
+			    password, cp->encr_password))
+			goto fail;
+	} else {
+		if (new_password_encrypted_with_old_nt_password_hash(
+			    new_password, new_password_len,
+			    password, password_len, cp->encr_password))
+			goto fail;
+	}
+
+	/* Encrypted-Hash */
+	if (pwhash) {
+		u8 new_password_hash[16];
+		nt_password_hash(new_password, new_password_len,
+				 new_password_hash);
+		nt_password_hash_encrypted_with_block(password,
+						      new_password_hash,
+						      cp->encr_hash);
+	} else {
+		old_nt_password_hash_encrypted_with_new_nt_password_hash(
+			new_password, new_password_len,
+			password, password_len, cp->encr_hash);
+	}
+
+	/* Peer-Challenge */
+	if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
+		goto fail;
+
+	/* Reserved, must be zero */
+	os_memset(cp->reserved, 0, 8);
+
+	/* NT-Response */
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
+		    data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
+		    cp->peer_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
+			  username, username_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
+			      new_password, new_password_len);
+	generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
+			     username, username_len,
+			     new_password, new_password_len,
+			     cp->nt_response);
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
+		    cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
+
+	/* Authenticator response is not really needed yet, but calculate it
+	 * here so that challenges need not be saved. */
+	generate_authenticator_response(new_password, new_password_len,
+					cp->peer_challenge,
+					data->passwd_change_challenge,
+					username, username_len,
+					cp->nt_response, data->auth_response);
+	data->auth_response_valid = 1;
+
+	/* Likewise, generate master_key here since we have the needed data
+	 * available. */
+	nt_password_hash(new_password, new_password_len, password_hash);
+	hash_nt_password_hash(password_hash, password_hash_hash);
+	get_master_key(password_hash_hash, cp->nt_response, data->master_key);
+	data->master_key_valid = 1;
+
+	/* Flags */
+	os_memset(cp->flags, 0, 2);
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+		   "(change pw)", id, ms->mschapv2_id);
+
+	return resp;
+
+fail:
+	wpabuf_free(resp);
+	return NULL;
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
+					    struct eap_mschapv2_data *data,
+					    struct eap_method_ret *ret,
+					    const struct eap_mschapv2_hdr *req,
+					    size_t req_len, u8 id)
+{
+	struct wpabuf *resp;
+	const u8 *msdata = (const u8 *) (req + 1);
+	char *buf;
+	size_t len = req_len - sizeof(*req);
+	int retry = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
+			  msdata, len);
+	/*
+	 * eap_mschapv2_failure_txt() expects a nul terminated string, so we
+	 * must allocate a large enough temporary buffer to create that since
+	 * the received message does not include nul termination.
+	 */
+	buf = os_malloc(len + 1);
+	if (buf) {
+		os_memcpy(buf, msdata, len);
+		buf[len] = '\0';
+		retry = eap_mschapv2_failure_txt(sm, data, buf);
+		os_free(buf);
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+	    data->passwd_change_version == 3) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (config && config->new_password)
+			return eap_mschapv2_change_password(sm, data, ret, req,
+							    id);
+		if (config && config->pending_req_new_password)
+			return NULL;
+	} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
+		/* TODO: could try to retry authentication, e.g, after having
+		 * changed the username/password. In this case, EAP MS-CHAP-v2
+		 * Failure Response would not be sent here. */
+		return NULL;
+	}
+
+	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
+	 * message. */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
+
+	return resp;
+}
+
+
+static int eap_mschapv2_check_config(struct eap_sm *sm)
+{
+	size_t len;
+
+	if (eap_get_config_identity(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
+		eap_sm_request_identity(sm);
+		return -1;
+	}
+
+	if (eap_get_config_password(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+		eap_sm_request_password(sm);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
+				    const struct eap_mschapv2_hdr *ms)
+{
+	size_t ms_len = WPA_GET_BE16(ms->ms_length);
+
+	if (ms_len == len)
+		return 0;
+
+	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
+		   "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
+	if (sm->workaround) {
+		/* Some authentication servers use invalid ms_len,
+		 * ignore it for interoperability. */
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
+			   " invalid ms_len %lu (len %lu)",
+			   (unsigned long) ms_len,
+			   (unsigned long) len);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
+					const struct wpabuf *reqData)
+{
+	/*
+	 * Store a copy of the challenge message, so that it can be processed
+	 * again in case retry is allowed after a possible failure.
+	 */
+	wpabuf_free(data->prev_challenge);
+	data->prev_challenge = wpabuf_dup(reqData);
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @priv: Pointer to private EAP method data from eap_mschapv2_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) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
+					    struct eap_method_ret *ret,
+					    const struct wpabuf *reqData)
+{
+	struct eap_mschapv2_data *data = priv;
+	struct eap_peer_config *config = eap_get_config(sm);
+	const struct eap_mschapv2_hdr *ms;
+	int using_prev_challenge = 0;
+	const u8 *pos;
+	size_t len;
+	u8 id;
+
+	if (eap_mschapv2_check_config(sm)) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (config->mschapv2_retry && data->prev_challenge &&
+	    data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
+			   "with the previous challenge");
+
+		reqData = data->prev_challenge;
+		using_prev_challenge = 1;
+		config->mschapv2_retry = 0;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
+			       &len);
+	if (pos == NULL || len < sizeof(*ms) + 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ms = (const struct eap_mschapv2_hdr *) pos;
+	if (eap_mschapv2_check_mslen(sm, len, ms)) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
+		   id, ms->mschapv2_id);
+
+	switch (ms->op_code) {
+	case MSCHAPV2_OP_CHALLENGE:
+		if (!using_prev_challenge)
+			eap_mschapv2_copy_challenge(data, reqData);
+		return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
+	case MSCHAPV2_OP_SUCCESS:
+		return eap_mschapv2_success(sm, data, ret, ms, len, id);
+	case MSCHAPV2_OP_FAILURE:
+		return eap_mschapv2_failure(sm, data, ret, ms, len, id);
+	default:
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
+			   ms->op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+}
+
+
+static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	return data->success && data->master_key_valid;
+}
+
+
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_mschapv2_data *data = priv;
+	u8 *key;
+	int key_len;
+
+	if (!data->master_key_valid || !data->success)
+		return NULL;
+
+	key_len = 2 * MSCHAPV2_KEY_LEN;
+
+	key = os_malloc(key_len);
+	if (key == NULL)
+		return NULL;
+
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
+	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
+	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				MSCHAPV2_KEY_LEN, 0, 0);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
+			key, key_len);
+
+	*len = key_len;
+	return key;
+}
+
+
+/**
+ * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to register EAP-MSCHAPv2 peer method into the EAP
+ * method list.
+ */
+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,
+				    "MSCHAPV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_mschapv2_init;
+	eap->deinit = eap_mschapv2_deinit;
+	eap->process = eap_mschapv2_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_otp.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_otp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_otp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,107 +0,0 @@
-/*
- * EAP peer method: EAP-OTP (RFC 3748)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-
-
-static void * eap_otp_init(struct eap_sm *sm)
-{
-	/* No need for private data. However, must return non-NULL to indicate
-	 * success. */
-	return (void *) 1;
-}
-
-
-static void eap_otp_deinit(struct eap_sm *sm, void *priv)
-{
-}
-
-
-static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct wpabuf *resp;
-	const u8 *pos, *password;
-	size_t password_len, len;
-	int otp;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len);
-	if (pos == NULL) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
-			  pos, len);
-
-	password = eap_get_config_otp(sm, &password_len);
-	if (password)
-		otp = 1;
-	else {
-		password = eap_get_config_password(sm, &password_len);
-		otp = 0;
-	}
-
-	if (password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
-		eap_sm_request_otp(sm, (const char *) pos, len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ret->ignore = FALSE;
-
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_COND_SUCC;
-	ret->allowNotifications = FALSE;
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len,
-			     EAP_CODE_RESPONSE, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-	wpabuf_put_data(resp, password, password_len);
-	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
-			      password, password_len);
-
-	if (otp) {
-		wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password");
-		eap_clear_config_otp(sm);
-	}
-
-	return resp;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_otp_init;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_otp.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_otp.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_otp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_otp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,101 @@
+/*
+ * EAP peer method: EAP-OTP (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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 "eap_i.h"
+
+
+static void * eap_otp_init(struct eap_sm *sm)
+{
+	/* No need for private data. However, must return non-NULL to indicate
+	 * success. */
+	return (void *) 1;
+}
+
+
+static void eap_otp_deinit(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *password;
+	size_t password_len, len;
+	int otp;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
+			  pos, len);
+
+	password = eap_get_config_otp(sm, &password_len);
+	if (password)
+		otp = 1;
+	else {
+		password = eap_get_config_password(sm, &password_len);
+		otp = 0;
+	}
+
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
+		eap_sm_request_otp(sm, (const char *) pos, len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+	wpabuf_put_data(resp, password, password_len);
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
+			      password, password_len);
+
+	if (otp) {
+		wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password");
+		eap_clear_config_otp(sm);
+	}
+
+	return resp;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_otp_init;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_pax.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_pax.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_pax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,530 +0,0 @@
-/*
- * EAP peer method: EAP-PAX (RFC 4746)
- * Copyright (c) 2005-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_common/eap_pax_common.h"
-#include "eap_i.h"
-
-/*
- * Note: only PAX_STD subprotocol is currently supported
- *
- * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
- * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
- * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
- * RSAES-OAEP).
- */
-
-struct eap_pax_data {
-	enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state;
-	u8 mac_id, dh_group_id, public_key_id;
-	union {
-		u8 e[2 * EAP_PAX_RAND_LEN];
-		struct {
-			u8 x[EAP_PAX_RAND_LEN]; /* server rand */
-			u8 y[EAP_PAX_RAND_LEN]; /* client rand */
-		} r;
-	} rand;
-	char *cid;
-	size_t cid_len;
-	u8 ak[EAP_PAX_AK_LEN];
-	u8 mk[EAP_PAX_MK_LEN];
-	u8 ck[EAP_PAX_CK_LEN];
-	u8 ick[EAP_PAX_ICK_LEN];
-};
-
-
-static void eap_pax_deinit(struct eap_sm *sm, void *priv);
-
-
-static void * eap_pax_init(struct eap_sm *sm)
-{
-	struct eap_pax_data *data;
-	const u8 *identity, *password;
-	size_t identity_len, password_len;
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	password = eap_get_config_password(sm, &password_len);
-	if (!identity || !password) {
-		wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) "
-			   "not configured");
-		return NULL;
-	}
-
-	if (password_len != EAP_PAX_AK_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = PAX_INIT;
-
-	data->cid = os_malloc(identity_len);
-	if (data->cid == NULL) {
-		eap_pax_deinit(sm, data);
-		return NULL;
-	}
-	os_memcpy(data->cid, identity, identity_len);
-	data->cid_len = identity_len;
-
-	os_memcpy(data->ak, password, EAP_PAX_AK_LEN);
-
-	return data;
-}
-
-
-static void eap_pax_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_pax_data *data = priv;
-	os_free(data->cid);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
-					  u8 id, u8 op_code, size_t plen)
-{
-	struct wpabuf *resp;
-	struct eap_pax_hdr *pax;
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
-			     sizeof(*pax) + plen, EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	pax = wpabuf_put(resp, sizeof(*pax));
-	pax->op_code = op_code;
-	pax->flags = 0;
-	pax->mac_id = req->mac_id;
-	pax->dh_group_id = req->dh_group_id;
-	pax->public_key_id = req->public_key_id;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
-					     struct eap_method_ret *ret, u8 id,
-					     const struct eap_pax_hdr *req,
-					     size_t req_plen)
-{
-	struct wpabuf *resp;
-	const u8 *pos;
-	u8 *rpos;
-	size_t left, plen;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)");
-
-	if (data->state != PAX_INIT) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
-			   "unexpected state (%d) - ignored", data->state);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (req->flags & EAP_PAX_FLAGS_CE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
-			   "ignored");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	left = req_plen - sizeof(*req);
-
-	if (left < 2 + EAP_PAX_RAND_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
-			   "payload");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos = (const u8 *) (req + 1);
-	if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
-			   "length %d (expected %d)",
-			   WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos += 2;
-	left -= 2;
-	os_memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)",
-		    data->rand.r.x, EAP_PAX_RAND_LEN);
-	pos += EAP_PAX_RAND_LEN;
-	left -= EAP_PAX_RAND_LEN;
-
-	if (left > 0) {
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
-			    pos, left);
-	}
-
-	if (os_get_random(data->rand.r.y, EAP_PAX_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
-		    data->rand.r.y, EAP_PAX_RAND_LEN);
-
-	if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
-					   data->mk, data->ck, data->ick) < 0)
-	{
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)");
-
-	plen = 2 + EAP_PAX_RAND_LEN + 2 + data->cid_len + 2 + EAP_PAX_MAC_LEN +
-		EAP_PAX_ICV_LEN;
-	resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_STD_2, plen);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_be16(resp, EAP_PAX_RAND_LEN);
-	wpabuf_put_data(resp, data->rand.r.y, EAP_PAX_RAND_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)",
-		    data->rand.r.y, EAP_PAX_RAND_LEN);
-
-	wpabuf_put_be16(resp, data->cid_len);
-	wpabuf_put_data(resp, data->cid, data->cid_len);
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
-			  (u8 *) data->cid, data->cid_len);
-
-	wpabuf_put_be16(resp, EAP_PAX_MAC_LEN);
-	rpos = wpabuf_put(resp, EAP_PAX_MAC_LEN);
-	eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN,
-		    data->rand.r.x, EAP_PAX_RAND_LEN,
-		    data->rand.r.y, EAP_PAX_RAND_LEN,
-		    (u8 *) data->cid, data->cid_len, rpos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
-		    rpos, EAP_PAX_MAC_LEN);
-
-	/* Optional ADE could be added here, if needed */
-
-	rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN);
-	eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
-		    wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
-		    NULL, 0, NULL, 0, rpos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
-
-	data->state = PAX_STD_2_SENT;
-	data->mac_id = req->mac_id;
-	data->dh_group_id = req->dh_group_id;
-	data->public_key_id = req->public_key_id;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
-					     struct eap_method_ret *ret, u8 id,
-					     const struct eap_pax_hdr *req,
-					     size_t req_plen)
-{
-	struct wpabuf *resp;
-	u8 *rpos, mac[EAP_PAX_MAC_LEN];
-	const u8 *pos;
-	size_t left;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)");
-
-	if (data->state != PAX_STD_2_SENT) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
-			   "unexpected state (%d) - ignored", data->state);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (req->flags & EAP_PAX_FLAGS_CE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
-			   "ignored");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	left = req_plen - sizeof(*req);
-
-	if (left < 2 + EAP_PAX_MAC_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
-			   "payload");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos = (const u8 *) (req + 1);
-	if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
-			   "MAC_CK length %d (expected %d)",
-			   WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	pos += 2;
-	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 (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
-			   "received");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
-			    mac, EAP_PAX_MAC_LEN);
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-
-	pos += EAP_PAX_MAC_LEN;
-	left -= EAP_PAX_MAC_LEN;
-
-	if (left > 0) {
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
-			    pos, left);
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)");
-
-	resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_ACK, EAP_PAX_ICV_LEN);
-	if (resp == NULL)
-		return NULL;
-
-	/* 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);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
-
-	data->state = PAX_DONE;
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	ret->allowNotifications = FALSE;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_pax_data *data = priv;
-	const struct eap_pax_hdr *req;
-	struct wpabuf *resp;
-	u8 icvbuf[EAP_PAX_ICV_LEN], id;
-	const u8 *icv, *pos;
-	size_t len;
-	u16 flen, mlen;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len);
-	if (pos == NULL || len < EAP_PAX_ICV_LEN) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	id = eap_get_id(reqData);
-	req = (const struct eap_pax_hdr *) pos;
-	flen = len - EAP_PAX_ICV_LEN;
-	mlen = wpabuf_len(reqData) - EAP_PAX_ICV_LEN;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
-		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
-		   "public_key_id 0x%x",
-		   req->op_code, req->flags, req->mac_id, req->dh_group_id,
-		   req->public_key_id);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
-		    pos, len - EAP_PAX_ICV_LEN);
-
-	if (data->state != PAX_INIT && data->mac_id != req->mac_id) {
-		wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
-			   "authentication (was 0x%d, is 0x%d)",
-			   data->mac_id, req->mac_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) {
-		wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
-			   "authentication (was 0x%d, is 0x%d)",
-			   data->dh_group_id, req->dh_group_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state != PAX_INIT &&
-	    data->public_key_id != req->public_key_id) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
-			   "authentication (was 0x%d, is 0x%d)",
-			   data->public_key_id, req->public_key_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	/* TODO: add support EAP_PAX_HMAC_SHA256_128 */
-	if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
-			   req->mac_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
-			   req->dh_group_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
-			   req->public_key_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (req->flags & EAP_PAX_FLAGS_MF) {
-		/* TODO: add support for reassembling fragments */
-		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
-			   "ignored packet");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	icv = pos + len - EAP_PAX_ICV_LEN;
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
-	if (req->op_code == EAP_PAX_OP_STD_1) {
-		eap_pax_mac(req->mac_id, (u8 *) "", 0,
-			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
-			    icvbuf);
-	} else {
-		eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
-			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
-			    icvbuf);
-	}
-	if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
-			   "message");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
-			    icvbuf, EAP_PAX_ICV_LEN);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	switch (req->op_code) {
-	case EAP_PAX_OP_STD_1:
-		resp = eap_pax_process_std_1(data, ret, id, req, flen);
-		break;
-	case EAP_PAX_OP_STD_3:
-		resp = eap_pax_process_std_3(data, ret, id, req, flen);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
-			   "op_code %d", req->op_code);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (ret->methodState == METHOD_DONE) {
-		ret->allowNotifications = FALSE;
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_pax_data *data = priv;
-	return data->state == PAX_DONE;
-}
-
-
-static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_pax_data *data = priv;
-	u8 *key;
-
-	if (data->state != PAX_DONE)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		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);
-
-	return key;
-}
-
-
-static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_pax_data *data = priv;
-	u8 *key;
-
-	if (data->state != PAX_DONE)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		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);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_pax_init;
-	eap->deinit = eap_pax_deinit;
-	eap->process = eap_pax_process;
-	eap->isKeyAvailable = eap_pax_isKeyAvailable;
-	eap->getKey = eap_pax_getKey;
-	eap->get_emsk = eap_pax_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_pax.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_pax.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_pax.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_pax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,525 @@
+/*
+ * EAP peer method: EAP-PAX (RFC 4746)
+ * Copyright (c) 2005-2008, Jouni Malinen <j at 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/random.h"
+#include "eap_common/eap_pax_common.h"
+#include "eap_i.h"
+
+/*
+ * Note: only PAX_STD subprotocol is currently supported
+ *
+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
+ * RSAES-OAEP).
+ */
+
+struct eap_pax_data {
+	enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state;
+	u8 mac_id, dh_group_id, public_key_id;
+	union {
+		u8 e[2 * EAP_PAX_RAND_LEN];
+		struct {
+			u8 x[EAP_PAX_RAND_LEN]; /* server rand */
+			u8 y[EAP_PAX_RAND_LEN]; /* client rand */
+		} r;
+	} rand;
+	char *cid;
+	size_t cid_len;
+	u8 ak[EAP_PAX_AK_LEN];
+	u8 mk[EAP_PAX_MK_LEN];
+	u8 ck[EAP_PAX_CK_LEN];
+	u8 ick[EAP_PAX_ICK_LEN];
+};
+
+
+static void eap_pax_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_pax_init(struct eap_sm *sm)
+{
+	struct eap_pax_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password(sm, &password_len);
+	if (!identity || !password) {
+		wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) "
+			   "not configured");
+		return NULL;
+	}
+
+	if (password_len != EAP_PAX_AK_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = PAX_INIT;
+
+	data->cid = os_malloc(identity_len);
+	if (data->cid == NULL) {
+		eap_pax_deinit(sm, data);
+		return NULL;
+	}
+	os_memcpy(data->cid, identity, identity_len);
+	data->cid_len = identity_len;
+
+	os_memcpy(data->ak, password, EAP_PAX_AK_LEN);
+
+	return data;
+}
+
+
+static void eap_pax_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_pax_data *data = priv;
+	os_free(data->cid);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
+					  u8 id, u8 op_code, size_t plen)
+{
+	struct wpabuf *resp;
+	struct eap_pax_hdr *pax;
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
+			     sizeof(*pax) + plen, EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	pax = wpabuf_put(resp, sizeof(*pax));
+	pax->op_code = op_code;
+	pax->flags = 0;
+	pax->mac_id = req->mac_id;
+	pax->dh_group_id = req->dh_group_id;
+	pax->public_key_id = req->public_key_id;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data,
+					     struct eap_method_ret *ret, u8 id,
+					     const struct eap_pax_hdr *req,
+					     size_t req_plen)
+{
+	struct wpabuf *resp;
+	const u8 *pos;
+	u8 *rpos;
+	size_t left, plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)");
+
+	if (data->state != PAX_INIT) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
+			   "unexpected state (%d) - ignored", data->state);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (req->flags & EAP_PAX_FLAGS_CE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
+			   "ignored");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	left = req_plen - sizeof(*req);
+
+	if (left < 2 + EAP_PAX_RAND_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
+			   "payload");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = (const u8 *) (req + 1);
+	if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
+			   "length %d (expected %d)",
+			   WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos += 2;
+	left -= 2;
+	os_memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)",
+		    data->rand.r.x, EAP_PAX_RAND_LEN);
+	pos += EAP_PAX_RAND_LEN;
+	left -= EAP_PAX_RAND_LEN;
+
+	if (left > 0) {
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
+			    pos, left);
+	}
+
+	if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
+		    data->rand.r.y, EAP_PAX_RAND_LEN);
+
+	if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
+					   data->mk, data->ck, data->ick) < 0)
+	{
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)");
+
+	plen = 2 + EAP_PAX_RAND_LEN + 2 + data->cid_len + 2 + EAP_PAX_MAC_LEN +
+		EAP_PAX_ICV_LEN;
+	resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_STD_2, plen);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_be16(resp, EAP_PAX_RAND_LEN);
+	wpabuf_put_data(resp, data->rand.r.y, EAP_PAX_RAND_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)",
+		    data->rand.r.y, EAP_PAX_RAND_LEN);
+
+	wpabuf_put_be16(resp, data->cid_len);
+	wpabuf_put_data(resp, data->cid, data->cid_len);
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
+			  (u8 *) data->cid, data->cid_len);
+
+	wpabuf_put_be16(resp, EAP_PAX_MAC_LEN);
+	rpos = wpabuf_put(resp, EAP_PAX_MAC_LEN);
+	eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN,
+		    data->rand.r.x, EAP_PAX_RAND_LEN,
+		    data->rand.r.y, EAP_PAX_RAND_LEN,
+		    (u8 *) data->cid, data->cid_len, rpos);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
+		    rpos, EAP_PAX_MAC_LEN);
+
+	/* Optional ADE could be added here, if needed */
+
+	rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN);
+	eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
+		    wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN,
+		    NULL, 0, NULL, 0, rpos);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
+
+	data->state = PAX_STD_2_SENT;
+	data->mac_id = req->mac_id;
+	data->dh_group_id = req->dh_group_id;
+	data->public_key_id = req->public_key_id;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
+					     struct eap_method_ret *ret, u8 id,
+					     const struct eap_pax_hdr *req,
+					     size_t req_plen)
+{
+	struct wpabuf *resp;
+	u8 *rpos, mac[EAP_PAX_MAC_LEN];
+	const u8 *pos;
+	size_t left;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)");
+
+	if (data->state != PAX_STD_2_SENT) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
+			   "unexpected state (%d) - ignored", data->state);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (req->flags & EAP_PAX_FLAGS_CE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
+			   "ignored");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	left = req_plen - sizeof(*req);
+
+	if (left < 2 + EAP_PAX_MAC_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
+			   "payload");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = (const u8 *) (req + 1);
+	if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
+			   "MAC_CK length %d (expected %d)",
+			   WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	pos += 2;
+	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 (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
+			   "received");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
+			    mac, EAP_PAX_MAC_LEN);
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+
+	pos += EAP_PAX_MAC_LEN;
+	left -= EAP_PAX_MAC_LEN;
+
+	if (left > 0) {
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
+			    pos, left);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)");
+
+	resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_ACK, EAP_PAX_ICV_LEN);
+	if (resp == NULL)
+		return NULL;
+
+	/* 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);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
+
+	data->state = PAX_DONE;
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_pax_data *data = priv;
+	const struct eap_pax_hdr *req;
+	struct wpabuf *resp;
+	u8 icvbuf[EAP_PAX_ICV_LEN], id;
+	const u8 *icv, *pos;
+	size_t len;
+	u16 flen, mlen;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len);
+	if (pos == NULL || len < EAP_PAX_ICV_LEN) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	id = eap_get_id(reqData);
+	req = (const struct eap_pax_hdr *) pos;
+	flen = len - EAP_PAX_ICV_LEN;
+	mlen = wpabuf_len(reqData) - EAP_PAX_ICV_LEN;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
+		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
+		   "public_key_id 0x%x",
+		   req->op_code, req->flags, req->mac_id, req->dh_group_id,
+		   req->public_key_id);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
+		    pos, len - EAP_PAX_ICV_LEN);
+
+	if (data->state != PAX_INIT && data->mac_id != req->mac_id) {
+		wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
+			   "authentication (was 0x%d, is 0x%d)",
+			   data->mac_id, req->mac_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) {
+		wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
+			   "authentication (was 0x%d, is 0x%d)",
+			   data->dh_group_id, req->dh_group_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state != PAX_INIT &&
+	    data->public_key_id != req->public_key_id) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
+			   "authentication (was 0x%d, is 0x%d)",
+			   data->public_key_id, req->public_key_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	/* TODO: add support EAP_PAX_HMAC_SHA256_128 */
+	if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
+			   req->mac_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
+			   req->dh_group_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
+			   req->public_key_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (req->flags & EAP_PAX_FLAGS_MF) {
+		/* TODO: add support for reassembling fragments */
+		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
+			   "ignored packet");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	icv = pos + len - EAP_PAX_ICV_LEN;
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
+	if (req->op_code == EAP_PAX_OP_STD_1) {
+		eap_pax_mac(req->mac_id, (u8 *) "", 0,
+			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
+			    icvbuf);
+	} else {
+		eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
+			    wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
+			    icvbuf);
+	}
+	if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
+			   "message");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
+			    icvbuf, EAP_PAX_ICV_LEN);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	switch (req->op_code) {
+	case EAP_PAX_OP_STD_1:
+		resp = eap_pax_process_std_1(data, ret, id, req, flen);
+		break;
+	case EAP_PAX_OP_STD_3:
+		resp = eap_pax_process_std_3(data, ret, id, req, flen);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
+			   "op_code %d", req->op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_pax_data *data = priv;
+	return data->state == PAX_DONE;
+}
+
+
+static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *key;
+
+	if (data->state != PAX_DONE)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		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);
+
+	return key;
+}
+
+
+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *key;
+
+	if (data->state != PAX_DONE)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		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);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_pax_init;
+	eap->deinit = eap_pax_deinit;
+	eap->process = eap_pax_process;
+	eap->isKeyAvailable = eap_pax_isKeyAvailable;
+	eap->getKey = eap_pax_getKey;
+	eap->get_emsk = eap_pax_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_peap.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_peap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_peap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1288 +0,0 @@
-/*
- * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "eap_common/eap_tlv_common.h"
-#include "eap_common/eap_peap_common.h"
-#include "eap_i.h"
-#include "eap_tls_common.h"
-#include "eap_config.h"
-#include "tncc.h"
-
-
-/* Maximum supported PEAP version
- * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
- * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
- */
-#define EAP_PEAP_VERSION 1
-
-
-static void eap_peap_deinit(struct eap_sm *sm, void *priv);
-
-
-struct eap_peap_data {
-	struct eap_ssl_data ssl;
-
-	int peap_version, force_peap_version, force_new_label;
-
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int phase2_success;
-	int phase2_eap_success;
-	int phase2_eap_started;
-
-	struct eap_method_type phase2_type;
-	struct eap_method_type *phase2_types;
-	size_t num_phase2_types;
-
-	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
-				 * EAP-Success
-				 * 1 = reply with tunneled EAP-Success to inner
-				 * EAP-Success and expect AS to send outer
-				 * (unencrypted) EAP-Success after this
-				 * 2 = reply with PEAP/TLS ACK to inner
-				 * EAP-Success and expect AS to send outer
-				 * (unencrypted) EAP-Success after this */
-	int resuming; /* starting a resumed session */
-	int reauth; /* reauthentication */
-	u8 *key_data;
-
-	struct wpabuf *pending_phase2_req;
-	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
-	int crypto_binding_used;
-	u8 binding_nonce[32];
-	u8 ipmk[40];
-	u8 cmk[20];
-	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
-		  * is enabled. */
-};
-
-
-static int eap_peap_parse_phase1(struct eap_peap_data *data,
-				 const char *phase1)
-{
-	const char *pos;
-
-	pos = os_strstr(phase1, "peapver=");
-	if (pos) {
-		data->force_peap_version = atoi(pos + 8);
-		data->peap_version = data->force_peap_version;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
-			   data->force_peap_version);
-	}
-
-	if (os_strstr(phase1, "peaplabel=1")) {
-		data->force_new_label = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
-			   "derivation");
-	}
-
-	if (os_strstr(phase1, "peap_outer_success=0")) {
-		data->peap_outer_success = 0;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
-			   "tunneled EAP-Success");
-	} else if (os_strstr(phase1, "peap_outer_success=1")) {
-		data->peap_outer_success = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
-			   "after receiving tunneled EAP-Success");
-	} else if (os_strstr(phase1, "peap_outer_success=2")) {
-		data->peap_outer_success = 2;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
-			   "receiving tunneled EAP-Success");
-	}
-
-	if (os_strstr(phase1, "crypto_binding=0")) {
-		data->crypto_binding = NO_BINDING;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
-	} else if (os_strstr(phase1, "crypto_binding=1")) {
-		data->crypto_binding = OPTIONAL_BINDING;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
-	} else if (os_strstr(phase1, "crypto_binding=2")) {
-		data->crypto_binding = REQUIRE_BINDING;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
-	}
-
-#ifdef EAP_TNC
-	if (os_strstr(phase1, "tnc=soh2")) {
-		data->soh = 2;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
-	} else if (os_strstr(phase1, "tnc=soh1")) {
-		data->soh = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
-	} else if (os_strstr(phase1, "tnc=soh")) {
-		data->soh = 2;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
-	}
-#endif /* EAP_TNC */
-
-	return 0;
-}
-
-
-static void * eap_peap_init(struct eap_sm *sm)
-{
-	struct eap_peap_data *data;
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	sm->peap_done = FALSE;
-	data->peap_version = EAP_PEAP_VERSION;
-	data->force_peap_version = -1;
-	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 (eap_peer_select_phase2_methods(config, "auth=",
-					   &data->phase2_types,
-					   &data->num_phase2_types) < 0) {
-		eap_peap_deinit(sm, data);
-		return NULL;
-	}
-
-	data->phase2_type.vendor = EAP_VENDOR_IETF;
-	data->phase2_type.method = EAP_TYPE_NONE;
-
-	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
-		eap_peap_deinit(sm, data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_peap_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	if (data == NULL)
-		return;
-	if (data->phase2_priv && data->phase2_method)
-		data->phase2_method->deinit(sm, data->phase2_priv);
-	os_free(data->phase2_types);
-	eap_peer_tls_ssl_deinit(sm, &data->ssl);
-	os_free(data->key_data);
-	wpabuf_free(data->pending_phase2_req);
-	os_free(data);
-}
-
-
-/**
- * eap_tlv_build_nak - Build EAP-TLV NAK message
- * @id: EAP identifier for the header
- * @nak_type: TLV type (EAP_TLV_*)
- * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
- *
- * This funtion builds an EAP-TLV NAK message. The caller is responsible for
- * freeing the returned buffer.
- */
-static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
-{
-	struct wpabuf *msg;
-
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
-			    EAP_CODE_RESPONSE, id);
-	if (msg == NULL)
-		return NULL;
-
-	wpabuf_put_u8(msg, 0x80); /* Mandatory */
-	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
-	wpabuf_put_be16(msg, 6); /* Length */
-	wpabuf_put_be32(msg, 0); /* Vendor-Id */
-	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
-
-	return msg;
-}
-
-
-static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
-			    u8 *isk, size_t isk_len)
-{
-	u8 *key;
-	size_t key_len;
-
-	os_memset(isk, 0, isk_len);
-	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
-	    data->phase2_method->isKeyAvailable == NULL ||
-	    data->phase2_method->getKey == NULL)
-		return 0;
-
-	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
-	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
-					       &key_len)) == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
-			   "from Phase 2");
-		return -1;
-	}
-
-	if (key_len > isk_len)
-		key_len = isk_len;
-	os_memcpy(isk, key, key_len);
-	os_free(key);
-
-	return 0;
-}
-
-
-static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
-{
-	u8 *tk;
-	u8 isk[32], imck[60];
-
-	/*
-	 * Tunnel key (TK) is the first 60 octets of the key generated by
-	 * phase 1 of PEAP (based on TLS).
-	 */
-	tk = data->key_data;
-	if (tk == NULL)
-		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
-
-	if (data->reauth &&
-	    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);
-		return 0;
-	}
-
-	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
-		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
-
-	/*
-	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
-	 * TempKey = First 40 octets of TK
-	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
-	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
-	 * in the end of the label just before ISK; is that just a typo?)
-	 */
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
-			imck, sizeof(imck));
-
-	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);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
-
-	return 0;
-}
-
-
-static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
-				     struct eap_peap_data *data,
-				     struct wpabuf *buf)
-{
-	u8 *mac;
-	u8 eap_type = EAP_TYPE_PEAP;
-	const u8 *addr[2];
-	size_t len[2];
-	u16 tlv_type;
-
-	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
-	addr[0] = wpabuf_put(buf, 0);
-	len[0] = 60;
-	addr[1] = &eap_type;
-	len[1] = 1;
-
-	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
-	if (data->peap_version >= 2)
-		tlv_type |= EAP_TLV_TYPE_MANDATORY;
-	wpabuf_put_be16(buf, tlv_type);
-	wpabuf_put_be16(buf, 56);
-
-	wpabuf_put_u8(buf, 0); /* Reserved */
-	wpabuf_put_u8(buf, data->peap_version); /* Version */
-	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
-	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
-	wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
-	mac = wpabuf_put(buf, 20); /* Compound_MAC */
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
-		    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);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
-	data->crypto_binding_used = 1;
-
-	return 0;
-}
-
-
-/**
- * eap_tlv_build_result - Build EAP-TLV Result message
- * @id: EAP identifier for the header
- * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
- * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
- *
- * This funtion builds an EAP-TLV Result message. The caller is responsible for
- * freeing the returned buffer.
- */
-static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
-					    struct eap_peap_data *data,
-					    int crypto_tlv_used,
-					    int id, u16 status)
-{
-	struct wpabuf *msg;
-	size_t len;
-
-	if (data->crypto_binding == NO_BINDING)
-		crypto_tlv_used = 0;
-
-	len = 6;
-	if (crypto_tlv_used)
-		len += 60; /* Cryptobinding TLV */
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
-			    EAP_CODE_RESPONSE, id);
-	if (msg == NULL)
-		return NULL;
-
-	wpabuf_put_u8(msg, 0x80); /* Mandatory */
-	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
-	wpabuf_put_be16(msg, 2); /* Length */
-	wpabuf_put_be16(msg, status); /* Status */
-
-	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
-					  struct eap_peap_data *data,
-					  const u8 *crypto_tlv,
-					  size_t crypto_tlv_len)
-{
-	u8 buf[61], mac[SHA1_MAC_LEN];
-	const u8 *pos;
-
-	if (eap_peap_derive_cmk(sm, data) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
-		return -1;
-	}
-
-	if (crypto_tlv_len != 4 + 56) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
-			   "length %d", (int) crypto_tlv_len);
-		return -1;
-	}
-
-	pos = crypto_tlv;
-	pos += 4; /* TLV header */
-	if (pos[1] != data->peap_version) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
-			   "mismatch (was %d; expected %d)",
-			   pos[1], data->peap_version);
-		return -1;
-	}
-
-	if (pos[3] != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
-			   "SubType %d", pos[3]);
-		return -1;
-	}
-	pos += 4;
-	os_memcpy(data->binding_nonce, pos, 32);
-	pos += 32; /* Nonce */
-
-	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
-	os_memcpy(buf, crypto_tlv, 60);
-	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
-	buf[60] = EAP_TYPE_PEAP;
-	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
-		    buf, sizeof(buf));
-	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
-
-	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
-			   "cryptobinding TLV");
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
-			    pos, SHA1_MAC_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
-			    mac, SHA1_MAC_LEN);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
-
-	return 0;
-}
-
-
-/**
- * eap_tlv_process - Process a received EAP-TLV message and generate a response
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @ret: Return values from EAP request validation and processing
- * @req: EAP-TLV request to be processed. The caller must have validated that
- * the buffer is large enough to contain full request (hdr->length bytes) and
- * that the EAP type is EAP_TYPE_TLV.
- * @resp: Buffer to return a pointer to the allocated response message. This
- * field should be initialized to %NULL before the call. The value will be
- * updated if a response message is generated. The caller is responsible for
- * freeing the allocated message.
- * @force_failure: Force negotiation to fail
- * Returns: 0 on success, -1 on failure
- */
-static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
-			   struct eap_method_ret *ret,
-			   const struct wpabuf *req, struct wpabuf **resp,
-			   int force_failure)
-{
-	size_t left, tlv_len;
-	const u8 *pos;
-	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
-	size_t result_tlv_len = 0, crypto_tlv_len = 0;
-	int tlv_type, mandatory;
-
-	/* Parse TLVs */
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
-	if (pos == NULL)
-		return -1;
-	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
-	while (left >= 4) {
-		mandatory = !!(pos[0] & 0x80);
-		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
-		pos += 2;
-		tlv_len = WPA_GET_BE16(pos);
-		pos += 2;
-		left -= 4;
-		if (tlv_len > left) {
-			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
-				   "(tlv_len=%lu left=%lu)",
-				   (unsigned long) tlv_len,
-				   (unsigned long) left);
-			return -1;
-		}
-		switch (tlv_type) {
-		case EAP_TLV_RESULT_TLV:
-			result_tlv = pos;
-			result_tlv_len = tlv_len;
-			break;
-		case EAP_TLV_CRYPTO_BINDING_TLV:
-			crypto_tlv = pos;
-			crypto_tlv_len = tlv_len;
-			break;
-		default:
-			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
-				   "%d%s", tlv_type,
-				   mandatory ? " (mandatory)" : "");
-			if (mandatory) {
-				/* NAK TLV and ignore all TLVs in this packet.
-				 */
-				*resp = eap_tlv_build_nak(eap_get_id(req),
-							  tlv_type);
-				return *resp == NULL ? -1 : 0;
-			}
-			/* Ignore this TLV, but process other TLVs */
-			break;
-		}
-
-		pos += tlv_len;
-		left -= tlv_len;
-	}
-	if (left) {
-		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
-			   "Request (left=%lu)", (unsigned long) left);
-		return -1;
-	}
-
-	/* Process supported TLVs */
-	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
-			    crypto_tlv, crypto_tlv_len);
-		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
-						   crypto_tlv_len + 4) < 0) {
-			if (result_tlv == NULL)
-				return -1;
-			force_failure = 1;
-			crypto_tlv = NULL; /* do not include Cryptobinding TLV
-					    * in response, if the received
-					    * cryptobinding was invalid. */
-		}
-	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
-		return -1;
-	}
-
-	if (result_tlv) {
-		int status, resp_status;
-		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
-			    result_tlv, result_tlv_len);
-		if (result_tlv_len < 2) {
-			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
-				   "(len=%lu)",
-				   (unsigned long) result_tlv_len);
-			return -1;
-		}
-		status = WPA_GET_BE16(result_tlv);
-		if (status == EAP_TLV_RESULT_SUCCESS) {
-			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
-				   "- EAP-TLV/Phase2 Completed");
-			if (force_failure) {
-				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
-					   " - force failed Phase 2");
-				resp_status = EAP_TLV_RESULT_FAILURE;
-				ret->decision = DECISION_FAIL;
-			} else {
-				resp_status = EAP_TLV_RESULT_SUCCESS;
-				ret->decision = DECISION_UNCOND_SUCC;
-			}
-		} else if (status == EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
-			resp_status = EAP_TLV_RESULT_FAILURE;
-			ret->decision = DECISION_FAIL;
-		} else {
-			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
-				   "Status %d", status);
-			resp_status = EAP_TLV_RESULT_FAILURE;
-			ret->decision = DECISION_FAIL;
-		}
-		ret->methodState = METHOD_DONE;
-
-		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
-					     eap_get_id(req), resp_status);
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(e, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(e, buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
-static int eap_peap_phase2_request(struct eap_sm *sm,
-				   struct eap_peap_data *data,
-				   struct eap_method_ret *ret,
-				   struct wpabuf *req,
-				   struct wpabuf **resp)
-{
-	struct eap_hdr *hdr = wpabuf_mhead(req);
-	size_t len = be_to_host16(hdr->length);
-	u8 *pos;
-	struct eap_method_ret iret;
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	if (len <= sizeof(struct eap_hdr)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
-			   "Phase 2 request (len=%lu)", (unsigned long) len);
-		return -1;
-	}
-	pos = (u8 *) (hdr + 1);
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
-	switch (*pos) {
-	case EAP_TYPE_IDENTITY:
-		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
-		break;
-	case EAP_TYPE_TLV:
-		os_memset(&iret, 0, sizeof(iret));
-		if (eap_tlv_process(sm, data, &iret, req, resp,
-				    data->phase2_eap_started &&
-				    !data->phase2_eap_success)) {
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			return -1;
-		}
-		if (iret.methodState == METHOD_DONE ||
-		    iret.methodState == METHOD_MAY_CONT) {
-			ret->methodState = iret.methodState;
-			ret->decision = iret.decision;
-			data->phase2_success = 1;
-		}
-		break;
-	case EAP_TYPE_EXPANDED:
-#ifdef EAP_TNC
-		if (data->soh) {
-			const u8 *epos;
-			size_t eleft;
-
-			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
-						req, &eleft);
-			if (epos) {
-				struct wpabuf *buf;
-				wpa_printf(MSG_DEBUG,
-					   "EAP-PEAP: SoH EAP Extensions");
-				buf = tncc_process_soh_request(data->soh,
-							       epos, eleft);
-				if (buf) {
-					*resp = eap_msg_alloc(
-						EAP_VENDOR_MICROSOFT, 0x21,
-						wpabuf_len(buf),
-						EAP_CODE_RESPONSE,
-						hdr->identifier);
-					if (*resp == NULL) {
-						ret->methodState = METHOD_DONE;
-						ret->decision = DECISION_FAIL;
-						return -1;
-					}
-					wpabuf_put_buf(*resp, buf);
-					wpabuf_free(buf);
-					break;
-				}
-			}
-		}
-#endif /* EAP_TNC */
-		/* fall through */
-	default:
-		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
-		    data->phase2_type.method == EAP_TYPE_NONE) {
-			size_t i;
-			for (i = 0; i < data->num_phase2_types; i++) {
-				if (data->phase2_types[i].vendor !=
-				    EAP_VENDOR_IETF ||
-				    data->phase2_types[i].method != *pos)
-					continue;
-
-				data->phase2_type.vendor =
-					data->phase2_types[i].vendor;
-				data->phase2_type.method =
-					data->phase2_types[i].method;
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
-					   "Phase 2 EAP vendor %d method %d",
-					   data->phase2_type.vendor,
-					   data->phase2_type.method);
-				break;
-			}
-		}
-		if (*pos != data->phase2_type.method ||
-		    *pos == EAP_TYPE_NONE) {
-			if (eap_peer_tls_phase2_nak(data->phase2_types,
-						    data->num_phase2_types,
-						    hdr, resp))
-				return -1;
-			return 0;
-		}
-
-		if (data->phase2_priv == NULL) {
-			data->phase2_method = eap_peer_get_eap_method(
-				data->phase2_type.vendor,
-				data->phase2_type.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-PEAP: failed to initialize "
-				   "Phase 2 EAP method %d", *pos);
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			return -1;
-		}
-		data->phase2_eap_started = 1;
-		os_memset(&iret, 0, sizeof(iret));
-		*resp = data->phase2_method->process(sm, data->phase2_priv,
-						     &iret, req);
-		if ((iret.methodState == METHOD_DONE ||
-		     iret.methodState == METHOD_MAY_CONT) &&
-		    (iret.decision == DECISION_UNCOND_SUCC ||
-		     iret.decision == DECISION_COND_SUCC)) {
-			data->phase2_eap_success = 1;
-			data->phase2_success = 1;
-		}
-		break;
-	}
-
-	if (*resp == NULL &&
-	    (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_alloc_copy(hdr, len);
-	}
-
-	return 0;
-}
-
-
-static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
-			    struct eap_method_ret *ret,
-			    const struct eap_hdr *req,
-			    const struct wpabuf *in_data,
-			    struct wpabuf **out_data)
-{
-	struct wpabuf *in_decrypted = NULL;
-	int res, skip_change = 0;
-	struct eap_hdr *hdr, *rhdr;
-	struct wpabuf *resp = NULL;
-	size_t len;
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
-		   " Phase 2", (unsigned long) wpabuf_len(in_data));
-
-	if (data->pending_phase2_req) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: 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;
-		skip_change = 1;
-		goto continue_req;
-	}
-
-	if (wpabuf_len(in_data) == 0 && sm->workaround &&
-	    data->phase2_success) {
-		/*
-		 * Cisco ACS seems to be using TLS ACK to terminate
-		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
-			   "expected data - acknowledge with TLS ACK since "
-			   "Phase 2 has been completed");
-		ret->decision = DECISION_COND_SUCC;
-		ret->methodState = METHOD_DONE;
-		return 1;
-	} else if (wpabuf_len(in_data) == 0) {
-		/* Received TLS ACK - requesting more fragments */
-		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
-					    data->peap_version,
-					    req->identifier, NULL, out_data);
-	}
-
-	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
-	if (res)
-		return res;
-
-continue_req:
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
-			in_decrypted);
-
-	hdr = wpabuf_mhead(in_decrypted);
-	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
-	    be_to_host16(hdr->length) == 5 &&
-	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
-		/* At least FreeRADIUS seems to send full EAP header with
-		 * EAP Request Identity */
-		skip_change = 1;
-	}
-	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
-	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
-		skip_change = 1;
-	}
-
-	if (data->peap_version == 0 && !skip_change) {
-		struct eap_hdr *nhdr;
-		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
-						   wpabuf_len(in_decrypted));
-		if (nmsg == NULL) {
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
-		wpabuf_put_buf(nmsg, in_decrypted);
-		nhdr->code = req->code;
-		nhdr->identifier = req->identifier;
-		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
-					    wpabuf_len(in_decrypted));
-
-		wpabuf_free(in_decrypted);
-		in_decrypted = nmsg;
-	}
-
-	if (data->peap_version >= 2) {
-		struct eap_tlv_hdr *tlv;
-		struct wpabuf *nmsg;
-
-		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
-				   "EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		tlv = wpabuf_mhead(in_decrypted);
-		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
-		    EAP_TLV_EAP_PAYLOAD_TLV) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		if (sizeof(*tlv) + be_to_host16(tlv->length) >
-		    wpabuf_len(in_decrypted)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
-				   "length");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-		hdr = (struct eap_hdr *) (tlv + 1);
-		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
-				   "EAP packet in EAP TLV");
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-
-		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
-		if (nmsg == NULL) {
-			wpabuf_free(in_decrypted);
-			return 0;
-		}
-
-		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
-		wpabuf_free(in_decrypted);
-		in_decrypted = nmsg;
-	}
-
-	hdr = wpabuf_mhead(in_decrypted);
-	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
-			   "EAP frame (len=%lu)",
-			   (unsigned long) wpabuf_len(in_decrypted));
-		wpabuf_free(in_decrypted);
-		return 0;
-	}
-	len = be_to_host16(hdr->length);
-	if (len > wpabuf_len(in_decrypted)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
-			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
-			   (unsigned long) wpabuf_len(in_decrypted),
-			   (unsigned long) len);
-		wpabuf_free(in_decrypted);
-		return 0;
-	}
-	if (len < wpabuf_len(in_decrypted)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
-			   "shorter length than full decrypted data "
-			   "(%lu < %lu)",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_len(in_decrypted));
-	}
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: 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_peap_phase2_request(sm, data, ret, in_decrypted,
-					    &resp)) {
-			wpabuf_free(in_decrypted);
-			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
-				   "processing failed");
-			return 0;
-		}
-		break;
-	case EAP_CODE_SUCCESS:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
-		if (data->peap_version == 1) {
-			/* EAP-Success within TLS tunnel is used to indicate
-			 * shutdown of the TLS channel. The authentication has
-			 * been completed. */
-			if (data->phase2_eap_started &&
-			    !data->phase2_eap_success) {
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
-					   "Success used to indicate success, "
-					   "but Phase 2 EAP was not yet "
-					   "completed successfully");
-				ret->methodState = METHOD_DONE;
-				ret->decision = DECISION_FAIL;
-				wpabuf_free(in_decrypted);
-				return 0;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
-				   "EAP-Success within TLS tunnel - "
-				   "authentication completed");
-			ret->decision = DECISION_UNCOND_SUCC;
-			ret->methodState = METHOD_DONE;
-			data->phase2_success = 1;
-			if (data->peap_outer_success == 2) {
-				wpabuf_free(in_decrypted);
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
-					   "to finish authentication");
-				return 1;
-			} else if (data->peap_outer_success == 1) {
-				/* Reply with EAP-Success within the TLS
-				 * channel to complete the authentication. */
-				resp = wpabuf_alloc(sizeof(struct eap_hdr));
-				if (resp) {
-					rhdr = wpabuf_put(resp, sizeof(*rhdr));
-					rhdr->code = EAP_CODE_SUCCESS;
-					rhdr->identifier = hdr->identifier;
-					rhdr->length =
-						host_to_be16(sizeof(*rhdr));
-				}
-			} else {
-				/* No EAP-Success expected for Phase 1 (outer,
-				 * unencrypted auth), so force EAP state
-				 * machine to SUCCESS state. */
-				sm->peap_done = TRUE;
-			}
-		} else {
-			/* FIX: ? */
-		}
-		break;
-	case EAP_CODE_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
-		ret->decision = DECISION_FAIL;
-		ret->methodState = METHOD_MAY_CONT;
-		ret->allowNotifications = FALSE;
-		/* Reply with EAP-Failure within the TLS channel to complete
-		 * failure reporting. */
-		resp = wpabuf_alloc(sizeof(struct eap_hdr));
-		if (resp) {
-			rhdr = wpabuf_put(resp, sizeof(*rhdr));
-			rhdr->code = EAP_CODE_FAILURE;
-			rhdr->identifier = hdr->identifier;
-			rhdr->length = host_to_be16(sizeof(*rhdr));
-		}
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
-			   "Phase 2 EAP header", hdr->code);
-		break;
-	}
-
-	wpabuf_free(in_decrypted);
-
-	if (resp) {
-		int skip_change2 = 0;
-		struct wpabuf *rmsg, buf;
-
-		wpa_hexdump_buf_key(MSG_DEBUG,
-				    "EAP-PEAP: Encrypting Phase 2 data", resp);
-		/* PEAP version changes */
-		if (data->peap_version >= 2) {
-			resp = eap_peapv2_tlv_eap_payload(resp);
-			if (resp == NULL)
-				return -1;
-		}
-		if (wpabuf_len(resp) >= 5 &&
-		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
-		    eap_get_type(resp) == EAP_TYPE_TLV)
-			skip_change2 = 1;
-		rmsg = resp;
-		if (data->peap_version == 0 && !skip_change2) {
-			wpabuf_set(&buf, wpabuf_head_u8(resp) +
-				   sizeof(struct eap_hdr),
-				   wpabuf_len(resp) - sizeof(struct eap_hdr));
-			rmsg = &buf;
-		}
-
-		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
-					 data->peap_version, req->identifier,
-					 rmsg, out_data)) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
-				   "a Phase 2 frame");
-		}
-		wpabuf_free(resp);
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
-					struct eap_method_ret *ret,
-					const struct wpabuf *reqData)
-{
-	const struct eap_hdr *req;
-	size_t left;
-	int res;
-	u8 flags, id;
-	struct wpabuf *resp;
-	const u8 *pos;
-	struct eap_peap_data *data = priv;
-
-	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
-					reqData, &left, &flags);
-	if (pos == NULL)
-		return NULL;
-	req = wpabuf_head(reqData);
-	id = req->identifier;
-
-	if (flags & EAP_TLS_FLAGS_START) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
-			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
-			data->peap_version);
-		if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
-			data->peap_version = flags & EAP_TLS_VERSION_MASK;
-		if (data->force_peap_version >= 0 &&
-		    data->force_peap_version != data->peap_version) {
-			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
-				   "forced PEAP version %d",
-				   data->force_peap_version);
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			ret->allowNotifications = FALSE;
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
-			   data->peap_version);
-		left = 0; /* make sure that this frame is empty, even though it
-			   * should always be, anyway */
-	}
-
-	resp = NULL;
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-	    !data->resuming) {
-		struct wpabuf msg;
-		wpabuf_set(&msg, pos, left);
-		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
-	} else {
-		res = eap_peer_tls_process_helper(sm, &data->ssl,
-						  EAP_TYPE_PEAP,
-						  data->peap_version, id, pos,
-						  left, &resp);
-
-		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			char *label;
-			wpa_printf(MSG_DEBUG,
-				   "EAP-PEAP: TLS done, proceed to Phase 2");
-			os_free(data->key_data);
-			/* draft-josefsson-ppext-eap-tls-eap-05.txt
-			 * specifies that PEAPv1 would use "client PEAP
-			 * encryption" as the label. However, most existing
-			 * PEAPv1 implementations seem to be using the old
-			 * label, "client EAP encryption", instead. Use the old
-			 * label by default, but allow it to be configured with
-			 * phase1 parameter peaplabel=1. */
-			if (data->peap_version > 1 || data->force_new_label)
-				label = "client PEAP encryption";
-			else
-				label = "client EAP encryption";
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
-				   "key derivation", label);
-			data->key_data =
-				eap_peer_tls_derive_key(sm, &data->ssl, label,
-							EAP_TLS_KEY_LEN);
-			if (data->key_data) {
-				wpa_hexdump_key(MSG_DEBUG, 
-						"EAP-PEAP: Derived key",
-						data->key_data,
-						EAP_TLS_KEY_LEN);
-			} else {
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
-					   "derive key");
-			}
-
-			if (sm->workaround && data->resuming) {
-				/*
-				 * At least few RADIUS servers (Aegis v1.1.6;
-				 * but not v1.1.4; and Cisco ACS) seem to be
-				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
-				 * ACS) session resumption with outer
-				 * EAP-Success. This does not seem to follow
-				 * draft-josefsson-pppext-eap-tls-eap-05.txt
-				 * section 4.2, so only allow this if EAP
-				 * workarounds are enabled.
-				 */
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
-					   "allow outer EAP-Success to "
-					   "terminate PEAP resumption");
-				ret->decision = DECISION_COND_SUCC;
-				data->phase2_success = 1;
-			}
-
-			data->resuming = 0;
-		}
-
-		if (res == 2) {
-			struct wpabuf msg;
-			/*
-			 * Application data included in the handshake message.
-			 */
-			wpabuf_free(data->pending_phase2_req);
-			data->pending_phase2_req = resp;
-			resp = NULL;
-			wpabuf_set(&msg, pos, left);
-			res = eap_peap_decrypt(sm, data, ret, req, &msg,
-					       &resp);
-		}
-	}
-
-	if (ret->methodState == METHOD_DONE) {
-		ret->allowNotifications = FALSE;
-	}
-
-	if (res == 1) {
-		wpabuf_free(resp);
-		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
-					      data->peap_version);
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-		data->phase2_success;
-}
-
-
-static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	wpabuf_free(data->pending_phase2_req);
-	data->pending_phase2_req = NULL;
-	data->crypto_binding_used = 0;
-}
-
-
-static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	os_free(data->key_data);
-	data->key_data = 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_success = 0;
-	data->phase2_eap_success = 0;
-	data->phase2_eap_started = 0;
-	data->resuming = 1;
-	data->reauth = 1;
-	sm->peap_done = FALSE;
-	return priv;
-}
-
-
-static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
-			       size_t buflen, int verbose)
-{
-	struct eap_peap_data *data = priv;
-	int len, ret;
-
-	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
-	if (data->phase2_method) {
-		ret = os_snprintf(buf + len, buflen - len,
-				  "EAP-PEAPv%d Phase2 method=%s\n",
-				  data->peap_version,
-				  data->phase2_method->name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			return len;
-		len += ret;
-	}
-	return len;
-}
-
-
-static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	return data->key_data != NULL && data->phase2_success;
-}
-
-
-static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_peap_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;
-
-	if (data->crypto_binding_used) {
-		u8 csk[128];
-		/*
-		 * Note: It looks like Microsoft implementation requires null
-		 * termination for this label while the one used for deriving
-		 * IPMK|CMK did not use null termination.
-		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
-		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
-		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
-			    key, EAP_TLS_KEY_LEN);
-	} else
-		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_peap_init;
-	eap->deinit = eap_peap_deinit;
-	eap->process = eap_peap_process;
-	eap->isKeyAvailable = eap_peap_isKeyAvailable;
-	eap->getKey = eap_peap_getKey;
-	eap->get_status = eap_peap_get_status;
-	eap->has_reauth_data = eap_peap_has_reauth_data;
-	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
-	eap->init_for_reauth = eap_peap_init_for_reauth;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_peap.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_peap.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_peap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_peap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1287 @@
+/*
+ * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+#include "tncc.h"
+
+
+/* Maximum supported PEAP version
+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
+ * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
+ */
+#define EAP_PEAP_VERSION 1
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_peap_data {
+	struct eap_ssl_data ssl;
+
+	int peap_version, force_peap_version, force_new_label;
+
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int phase2_success;
+	int phase2_eap_success;
+	int phase2_eap_started;
+
+	struct eap_method_type phase2_type;
+	struct eap_method_type *phase2_types;
+	size_t num_phase2_types;
+
+	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
+				 * EAP-Success
+				 * 1 = reply with tunneled EAP-Success to inner
+				 * EAP-Success and expect AS to send outer
+				 * (unencrypted) EAP-Success after this
+				 * 2 = reply with PEAP/TLS ACK to inner
+				 * EAP-Success and expect AS to send outer
+				 * (unencrypted) EAP-Success after this */
+	int resuming; /* starting a resumed session */
+	int reauth; /* reauthentication */
+	u8 *key_data;
+
+	struct wpabuf *pending_phase2_req;
+	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+	int crypto_binding_used;
+	u8 binding_nonce[32];
+	u8 ipmk[40];
+	u8 cmk[20];
+	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
+		  * is enabled. */
+};
+
+
+static int eap_peap_parse_phase1(struct eap_peap_data *data,
+				 const char *phase1)
+{
+	const char *pos;
+
+	pos = os_strstr(phase1, "peapver=");
+	if (pos) {
+		data->force_peap_version = atoi(pos + 8);
+		data->peap_version = data->force_peap_version;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
+			   data->force_peap_version);
+	}
+
+	if (os_strstr(phase1, "peaplabel=1")) {
+		data->force_new_label = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
+			   "derivation");
+	}
+
+	if (os_strstr(phase1, "peap_outer_success=0")) {
+		data->peap_outer_success = 0;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
+			   "tunneled EAP-Success");
+	} else if (os_strstr(phase1, "peap_outer_success=1")) {
+		data->peap_outer_success = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
+			   "after receiving tunneled EAP-Success");
+	} else if (os_strstr(phase1, "peap_outer_success=2")) {
+		data->peap_outer_success = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
+			   "receiving tunneled EAP-Success");
+	}
+
+	if (os_strstr(phase1, "crypto_binding=0")) {
+		data->crypto_binding = NO_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=1")) {
+		data->crypto_binding = OPTIONAL_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=2")) {
+		data->crypto_binding = REQUIRE_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
+	}
+
+#ifdef EAP_TNC
+	if (os_strstr(phase1, "tnc=soh2")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
+	} else if (os_strstr(phase1, "tnc=soh1")) {
+		data->soh = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
+	} else if (os_strstr(phase1, "tnc=soh")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
+	}
+#endif /* EAP_TNC */
+
+	return 0;
+}
+
+
+static void * eap_peap_init(struct eap_sm *sm)
+{
+	struct eap_peap_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	sm->peap_done = FALSE;
+	data->peap_version = EAP_PEAP_VERSION;
+	data->force_peap_version = -1;
+	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 (eap_peer_select_phase2_methods(config, "auth=",
+					   &data->phase2_types,
+					   &data->num_phase2_types) < 0) {
+		eap_peap_deinit(sm, data);
+		return NULL;
+	}
+
+	data->phase2_type.vendor = EAP_VENDOR_IETF;
+	data->phase2_type.method = EAP_TYPE_NONE;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
+		eap_peap_deinit(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->deinit(sm, data->phase2_priv);
+	os_free(data->phase2_types);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->key_data);
+	wpabuf_free(data->pending_phase2_req);
+	os_free(data);
+}
+
+
+/**
+ * eap_tlv_build_nak - Build EAP-TLV NAK message
+ * @id: EAP identifier for the header
+ * @nak_type: TLV type (EAP_TLV_*)
+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
+ *
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
+	wpabuf_put_be16(msg, 6); /* Length */
+	wpabuf_put_be32(msg, 0); /* Vendor-Id */
+	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
+
+	return msg;
+}
+
+
+static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
+			    u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
+	    data->phase2_method->isKeyAvailable == NULL ||
+	    data->phase2_method->getKey == NULL)
+		return 0;
+
+	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
+	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+	u8 *tk;
+	u8 isk[32], imck[60];
+
+	/*
+	 * Tunnel key (TK) is the first 60 octets of the key generated by
+	 * phase 1 of PEAP (based on TLS).
+	 */
+	tk = data->key_data;
+	if (tk == NULL)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	if (data->reauth &&
+	    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);
+		return 0;
+	}
+
+	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+	/*
+	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
+	 * TempKey = First 40 octets of TK
+	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+	 * in the end of the label just before ISK; is that just a typo?)
+	 */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+			imck, sizeof(imck));
+
+	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);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+	return 0;
+}
+
+
+static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
+				     struct eap_peap_data *data,
+				     struct wpabuf *buf)
+{
+	u8 *mac;
+	u8 eap_type = EAP_TYPE_PEAP;
+	const u8 *addr[2];
+	size_t len[2];
+	u16 tlv_type;
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	addr[0] = wpabuf_put(buf, 0);
+	len[0] = 60;
+	addr[1] = &eap_type;
+	len[1] = 1;
+
+	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+	if (data->peap_version >= 2)
+		tlv_type |= EAP_TLV_TYPE_MANDATORY;
+	wpabuf_put_be16(buf, tlv_type);
+	wpabuf_put_be16(buf, 56);
+
+	wpabuf_put_u8(buf, 0); /* Reserved */
+	wpabuf_put_u8(buf, data->peap_version); /* Version */
+	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
+	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
+	wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
+	mac = wpabuf_put(buf, 20); /* Compound_MAC */
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+		    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);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
+	data->crypto_binding_used = 1;
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_build_result - Build EAP-TLV Result message
+ * @id: EAP identifier for the header
+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
+ *
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
+					    struct eap_peap_data *data,
+					    int crypto_tlv_used,
+					    int id, u16 status)
+{
+	struct wpabuf *msg;
+	size_t len;
+
+	if (data->crypto_binding == NO_BINDING)
+		crypto_tlv_used = 0;
+
+	len = 6;
+	if (crypto_tlv_used)
+		len += 60; /* Cryptobinding TLV */
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
+	wpabuf_put_be16(msg, 2); /* Length */
+	wpabuf_put_be16(msg, status); /* Status */
+
+	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+					  struct eap_peap_data *data,
+					  const u8 *crypto_tlv,
+					  size_t crypto_tlv_len)
+{
+	u8 buf[61], mac[SHA1_MAC_LEN];
+	const u8 *pos;
+
+	if (eap_peap_derive_cmk(sm, data) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
+		return -1;
+	}
+
+	if (crypto_tlv_len != 4 + 56) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+			   "length %d", (int) crypto_tlv_len);
+		return -1;
+	}
+
+	pos = crypto_tlv;
+	pos += 4; /* TLV header */
+	if (pos[1] != data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+			   "mismatch (was %d; expected %d)",
+			   pos[1], data->peap_version);
+		return -1;
+	}
+
+	if (pos[3] != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+			   "SubType %d", pos[3]);
+		return -1;
+	}
+	pos += 4;
+	os_memcpy(data->binding_nonce, pos, 32);
+	pos += 32; /* Nonce */
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	os_memcpy(buf, crypto_tlv, 60);
+	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+	buf[60] = EAP_TYPE_PEAP;
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
+		    buf, sizeof(buf));
+	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+			   "cryptobinding TLV");
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
+			    pos, SHA1_MAC_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
+			    mac, SHA1_MAC_LEN);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_process - Process a received EAP-TLV message and generate a response
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: EAP-TLV request to be processed. The caller must have validated that
+ * the buffer is large enough to contain full request (hdr->length bytes) and
+ * that the EAP type is EAP_TYPE_TLV.
+ * @resp: Buffer to return a pointer to the allocated response message. This
+ * field should be initialized to %NULL before the call. The value will be
+ * updated if a response message is generated. The caller is responsible for
+ * freeing the allocated message.
+ * @force_failure: Force negotiation to fail
+ * Returns: 0 on success, -1 on failure
+ */
+static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
+			   struct eap_method_ret *ret,
+			   const struct wpabuf *req, struct wpabuf **resp,
+			   int force_failure)
+{
+	size_t left, tlv_len;
+	const u8 *pos;
+	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+	size_t result_tlv_len = 0, crypto_tlv_len = 0;
+	int tlv_type, mandatory;
+
+	/* Parse TLVs */
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
+	if (pos == NULL)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		tlv_len = WPA_GET_BE16(pos);
+		pos += 2;
+		left -= 4;
+		if (tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+				   "(tlv_len=%lu left=%lu)",
+				   (unsigned long) tlv_len,
+				   (unsigned long) left);
+			return -1;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_RESULT_TLV:
+			result_tlv = pos;
+			result_tlv_len = tlv_len;
+			break;
+		case EAP_TLV_CRYPTO_BINDING_TLV:
+			crypto_tlv = pos;
+			crypto_tlv_len = tlv_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				/* NAK TLV and ignore all TLVs in this packet.
+				 */
+				*resp = eap_tlv_build_nak(eap_get_id(req),
+							  tlv_type);
+				return *resp == NULL ? -1 : 0;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		return -1;
+	}
+
+	/* Process supported TLVs */
+	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+			    crypto_tlv, crypto_tlv_len);
+		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+						   crypto_tlv_len + 4) < 0) {
+			if (result_tlv == NULL)
+				return -1;
+			force_failure = 1;
+			crypto_tlv = NULL; /* do not include Cryptobinding TLV
+					    * in response, if the received
+					    * cryptobinding was invalid. */
+		}
+	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+		return -1;
+	}
+
+	if (result_tlv) {
+		int status, resp_status;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+			    result_tlv, result_tlv_len);
+		if (result_tlv_len < 2) {
+			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+				   "(len=%lu)",
+				   (unsigned long) result_tlv_len);
+			return -1;
+		}
+		status = WPA_GET_BE16(result_tlv);
+		if (status == EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+				   "- EAP-TLV/Phase2 Completed");
+			if (force_failure) {
+				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
+					   " - force failed Phase 2");
+				resp_status = EAP_TLV_RESULT_FAILURE;
+				ret->decision = DECISION_FAIL;
+			} else {
+				resp_status = EAP_TLV_RESULT_SUCCESS;
+				ret->decision = DECISION_UNCOND_SUCC;
+			}
+		} else if (status == EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		} else {
+			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+				   "Status %d", status);
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		}
+		ret->methodState = METHOD_DONE;
+
+		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
+					     eap_get_id(req), resp_status);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
+{
+	struct wpabuf *e;
+	struct eap_tlv_hdr *tlv;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
+	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
+	if (e == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
+			   "for TLV encapsulation");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	tlv = wpabuf_put(e, sizeof(*tlv));
+	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+				     EAP_TLV_EAP_PAYLOAD_TLV);
+	tlv->length = host_to_be16(wpabuf_len(buf));
+	wpabuf_put_buf(e, buf);
+	wpabuf_free(buf);
+	return e;
+}
+
+
+static int eap_peap_phase2_request(struct eap_sm *sm,
+				   struct eap_peap_data *data,
+				   struct eap_method_ret *ret,
+				   struct wpabuf *req,
+				   struct wpabuf **resp)
+{
+	struct eap_hdr *hdr = wpabuf_mhead(req);
+	size_t len = be_to_host16(hdr->length);
+	u8 *pos;
+	struct eap_method_ret iret;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	if (len <= sizeof(struct eap_hdr)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
+			   "Phase 2 request (len=%lu)", (unsigned long) len);
+		return -1;
+	}
+	pos = (u8 *) (hdr + 1);
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
+	switch (*pos) {
+	case EAP_TYPE_IDENTITY:
+		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
+		break;
+	case EAP_TYPE_TLV:
+		os_memset(&iret, 0, sizeof(iret));
+		if (eap_tlv_process(sm, data, &iret, req, resp,
+				    data->phase2_eap_started &&
+				    !data->phase2_eap_success)) {
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			return -1;
+		}
+		if (iret.methodState == METHOD_DONE ||
+		    iret.methodState == METHOD_MAY_CONT) {
+			ret->methodState = iret.methodState;
+			ret->decision = iret.decision;
+			data->phase2_success = 1;
+		}
+		break;
+	case EAP_TYPE_EXPANDED:
+#ifdef EAP_TNC
+		if (data->soh) {
+			const u8 *epos;
+			size_t eleft;
+
+			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
+						req, &eleft);
+			if (epos) {
+				struct wpabuf *buf;
+				wpa_printf(MSG_DEBUG,
+					   "EAP-PEAP: SoH EAP Extensions");
+				buf = tncc_process_soh_request(data->soh,
+							       epos, eleft);
+				if (buf) {
+					*resp = eap_msg_alloc(
+						EAP_VENDOR_MICROSOFT, 0x21,
+						wpabuf_len(buf),
+						EAP_CODE_RESPONSE,
+						hdr->identifier);
+					if (*resp == NULL) {
+						ret->methodState = METHOD_DONE;
+						ret->decision = DECISION_FAIL;
+						return -1;
+					}
+					wpabuf_put_buf(*resp, buf);
+					wpabuf_free(buf);
+					break;
+				}
+			}
+		}
+#endif /* EAP_TNC */
+		/* fall through */
+	default:
+		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+		    data->phase2_type.method == EAP_TYPE_NONE) {
+			size_t i;
+			for (i = 0; i < data->num_phase2_types; i++) {
+				if (data->phase2_types[i].vendor !=
+				    EAP_VENDOR_IETF ||
+				    data->phase2_types[i].method != *pos)
+					continue;
+
+				data->phase2_type.vendor =
+					data->phase2_types[i].vendor;
+				data->phase2_type.method =
+					data->phase2_types[i].method;
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
+					   "Phase 2 EAP vendor %d method %d",
+					   data->phase2_type.vendor,
+					   data->phase2_type.method);
+				break;
+			}
+		}
+		if (*pos != data->phase2_type.method ||
+		    *pos == EAP_TYPE_NONE) {
+			if (eap_peer_tls_phase2_nak(data->phase2_types,
+						    data->num_phase2_types,
+						    hdr, resp))
+				return -1;
+			return 0;
+		}
+
+		if (data->phase2_priv == NULL) {
+			data->phase2_method = eap_peer_get_eap_method(
+				data->phase2_type.vendor,
+				data->phase2_type.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-PEAP: failed to initialize "
+				   "Phase 2 EAP method %d", *pos);
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			return -1;
+		}
+		data->phase2_eap_started = 1;
+		os_memset(&iret, 0, sizeof(iret));
+		*resp = data->phase2_method->process(sm, data->phase2_priv,
+						     &iret, req);
+		if ((iret.methodState == METHOD_DONE ||
+		     iret.methodState == METHOD_MAY_CONT) &&
+		    (iret.decision == DECISION_UNCOND_SUCC ||
+		     iret.decision == DECISION_COND_SUCC)) {
+			data->phase2_eap_success = 1;
+			data->phase2_success = 1;
+		}
+		break;
+	}
+
+	if (*resp == NULL &&
+	    (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_alloc_copy(hdr, len);
+	}
+
+	return 0;
+}
+
+
+static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
+			    struct eap_method_ret *ret,
+			    const struct eap_hdr *req,
+			    const struct wpabuf *in_data,
+			    struct wpabuf **out_data)
+{
+	struct wpabuf *in_decrypted = NULL;
+	int res, skip_change = 0;
+	struct eap_hdr *hdr, *rhdr;
+	struct wpabuf *resp = NULL;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_data));
+
+	if (data->pending_phase2_req) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: 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;
+		skip_change = 1;
+		goto continue_req;
+	}
+
+	if (wpabuf_len(in_data) == 0 && sm->workaround &&
+	    data->phase2_success) {
+		/*
+		 * Cisco ACS seems to be using TLS ACK to terminate
+		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
+			   "expected data - acknowledge with TLS ACK since "
+			   "Phase 2 has been completed");
+		ret->decision = DECISION_COND_SUCC;
+		ret->methodState = METHOD_DONE;
+		return 1;
+	} else if (wpabuf_len(in_data) == 0) {
+		/* Received TLS ACK - requesting more fragments */
+		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
+					    data->peap_version,
+					    req->identifier, NULL, out_data);
+	}
+
+	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
+	if (res)
+		return res;
+
+continue_req:
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
+			in_decrypted);
+
+	hdr = wpabuf_mhead(in_decrypted);
+	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
+	    be_to_host16(hdr->length) == 5 &&
+	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
+		/* At least FreeRADIUS seems to send full EAP header with
+		 * EAP Request Identity */
+		skip_change = 1;
+	}
+	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
+	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
+		skip_change = 1;
+	}
+
+	if (data->peap_version == 0 && !skip_change) {
+		struct eap_hdr *nhdr;
+		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
+						   wpabuf_len(in_decrypted));
+		if (nmsg == NULL) {
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
+		wpabuf_put_buf(nmsg, in_decrypted);
+		nhdr->code = req->code;
+		nhdr->identifier = req->identifier;
+		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
+					    wpabuf_len(in_decrypted));
+
+		wpabuf_free(in_decrypted);
+		in_decrypted = nmsg;
+	}
+
+	if (data->peap_version >= 2) {
+		struct eap_tlv_hdr *tlv;
+		struct wpabuf *nmsg;
+
+		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
+				   "EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		tlv = wpabuf_mhead(in_decrypted);
+		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
+		    EAP_TLV_EAP_PAYLOAD_TLV) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		if (sizeof(*tlv) + be_to_host16(tlv->length) >
+		    wpabuf_len(in_decrypted)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
+				   "length");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		hdr = (struct eap_hdr *) (tlv + 1);
+		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
+				   "EAP packet in EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+
+		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
+		if (nmsg == NULL) {
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+
+		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
+		wpabuf_free(in_decrypted);
+		in_decrypted = nmsg;
+	}
+
+	hdr = wpabuf_mhead(in_decrypted);
+	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
+			   "EAP frame (len=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted));
+		wpabuf_free(in_decrypted);
+		return 0;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > wpabuf_len(in_decrypted)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
+			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted),
+			   (unsigned long) len);
+		wpabuf_free(in_decrypted);
+		return 0;
+	}
+	if (len < wpabuf_len(in_decrypted)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
+			   "shorter length than full decrypted data "
+			   "(%lu < %lu)",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_len(in_decrypted));
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: 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_peap_phase2_request(sm, data, ret, in_decrypted,
+					    &resp)) {
+			wpabuf_free(in_decrypted);
+			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
+				   "processing failed");
+			return 0;
+		}
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
+		if (data->peap_version == 1) {
+			/* EAP-Success within TLS tunnel is used to indicate
+			 * shutdown of the TLS channel. The authentication has
+			 * been completed. */
+			if (data->phase2_eap_started &&
+			    !data->phase2_eap_success) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
+					   "Success used to indicate success, "
+					   "but Phase 2 EAP was not yet "
+					   "completed successfully");
+				ret->methodState = METHOD_DONE;
+				ret->decision = DECISION_FAIL;
+				wpabuf_free(in_decrypted);
+				return 0;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
+				   "EAP-Success within TLS tunnel - "
+				   "authentication completed");
+			ret->decision = DECISION_UNCOND_SUCC;
+			ret->methodState = METHOD_DONE;
+			data->phase2_success = 1;
+			if (data->peap_outer_success == 2) {
+				wpabuf_free(in_decrypted);
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
+					   "to finish authentication");
+				return 1;
+			} else if (data->peap_outer_success == 1) {
+				/* Reply with EAP-Success within the TLS
+				 * channel to complete the authentication. */
+				resp = wpabuf_alloc(sizeof(struct eap_hdr));
+				if (resp) {
+					rhdr = wpabuf_put(resp, sizeof(*rhdr));
+					rhdr->code = EAP_CODE_SUCCESS;
+					rhdr->identifier = hdr->identifier;
+					rhdr->length =
+						host_to_be16(sizeof(*rhdr));
+				}
+			} else {
+				/* No EAP-Success expected for Phase 1 (outer,
+				 * unencrypted auth), so force EAP state
+				 * machine to SUCCESS state. */
+				sm->peap_done = TRUE;
+			}
+		} else {
+			/* FIX: ? */
+		}
+		break;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
+		ret->decision = DECISION_FAIL;
+		ret->methodState = METHOD_MAY_CONT;
+		ret->allowNotifications = FALSE;
+		/* Reply with EAP-Failure within the TLS channel to complete
+		 * failure reporting. */
+		resp = wpabuf_alloc(sizeof(struct eap_hdr));
+		if (resp) {
+			rhdr = wpabuf_put(resp, sizeof(*rhdr));
+			rhdr->code = EAP_CODE_FAILURE;
+			rhdr->identifier = hdr->identifier;
+			rhdr->length = host_to_be16(sizeof(*rhdr));
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+
+	wpabuf_free(in_decrypted);
+
+	if (resp) {
+		int skip_change2 = 0;
+		struct wpabuf *rmsg, buf;
+
+		wpa_hexdump_buf_key(MSG_DEBUG,
+				    "EAP-PEAP: Encrypting Phase 2 data", resp);
+		/* PEAP version changes */
+		if (data->peap_version >= 2) {
+			resp = eap_peapv2_tlv_eap_payload(resp);
+			if (resp == NULL)
+				return -1;
+		}
+		if (wpabuf_len(resp) >= 5 &&
+		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
+		    eap_get_type(resp) == EAP_TYPE_TLV)
+			skip_change2 = 1;
+		rmsg = resp;
+		if (data->peap_version == 0 && !skip_change2) {
+			wpabuf_set(&buf, wpabuf_head_u8(resp) +
+				   sizeof(struct eap_hdr),
+				   wpabuf_len(resp) - sizeof(struct eap_hdr));
+			rmsg = &buf;
+		}
+
+		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
+					 data->peap_version, req->identifier,
+					 rmsg, out_data)) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
+				   "a Phase 2 frame");
+		}
+		wpabuf_free(resp);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	const struct eap_hdr *req;
+	size_t left;
+	int res;
+	u8 flags, id;
+	struct wpabuf *resp;
+	const u8 *pos;
+	struct eap_peap_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
+					reqData, &left, &flags);
+	if (pos == NULL)
+		return NULL;
+	req = wpabuf_head(reqData);
+	id = req->identifier;
+
+	if (flags & EAP_TLS_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
+			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+			data->peap_version);
+		if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
+			data->peap_version = flags & EAP_TLS_VERSION_MASK;
+		if (data->force_peap_version >= 0 &&
+		    data->force_peap_version != data->peap_version) {
+			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
+				   "forced PEAP version %d",
+				   data->force_peap_version);
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			ret->allowNotifications = FALSE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
+			   data->peap_version);
+		left = 0; /* make sure that this frame is empty, even though it
+			   * should always be, anyway */
+	}
+
+	resp = NULL;
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+	    !data->resuming) {
+		struct wpabuf msg;
+		wpabuf_set(&msg, pos, left);
+		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
+	} else {
+		res = eap_peer_tls_process_helper(sm, &data->ssl,
+						  EAP_TYPE_PEAP,
+						  data->peap_version, id, pos,
+						  left, &resp);
+
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			char *label;
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PEAP: TLS done, proceed to Phase 2");
+			os_free(data->key_data);
+			/* draft-josefsson-ppext-eap-tls-eap-05.txt
+			 * specifies that PEAPv1 would use "client PEAP
+			 * encryption" as the label. However, most existing
+			 * PEAPv1 implementations seem to be using the old
+			 * label, "client EAP encryption", instead. Use the old
+			 * label by default, but allow it to be configured with
+			 * phase1 parameter peaplabel=1. */
+			if (data->peap_version > 1 || data->force_new_label)
+				label = "client PEAP encryption";
+			else
+				label = "client EAP encryption";
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
+				   "key derivation", label);
+			data->key_data =
+				eap_peer_tls_derive_key(sm, &data->ssl, label,
+							EAP_TLS_KEY_LEN);
+			if (data->key_data) {
+				wpa_hexdump_key(MSG_DEBUG, 
+						"EAP-PEAP: Derived key",
+						data->key_data,
+						EAP_TLS_KEY_LEN);
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
+					   "derive key");
+			}
+
+			if (sm->workaround && data->resuming) {
+				/*
+				 * At least few RADIUS servers (Aegis v1.1.6;
+				 * but not v1.1.4; and Cisco ACS) seem to be
+				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
+				 * ACS) session resumption with outer
+				 * EAP-Success. This does not seem to follow
+				 * draft-josefsson-pppext-eap-tls-eap-05.txt
+				 * section 4.2, so only allow this if EAP
+				 * workarounds are enabled.
+				 */
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
+					   "allow outer EAP-Success to "
+					   "terminate PEAP resumption");
+				ret->decision = DECISION_COND_SUCC;
+				data->phase2_success = 1;
+			}
+
+			data->resuming = 0;
+		}
+
+		if (res == 2) {
+			struct wpabuf msg;
+			/*
+			 * Application data included in the handshake message.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = resp;
+			resp = NULL;
+			wpabuf_set(&msg, pos, left);
+			res = eap_peap_decrypt(sm, data, ret, req, &msg,
+					       &resp);
+		}
+	}
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
+					      data->peap_version);
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+		data->phase2_success;
+}
+
+
+static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	wpabuf_free(data->pending_phase2_req);
+	data->pending_phase2_req = NULL;
+	data->crypto_binding_used = 0;
+}
+
+
+static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	os_free(data->key_data);
+	data->key_data = 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_success = 0;
+	data->phase2_eap_success = 0;
+	data->phase2_eap_started = 0;
+	data->resuming = 1;
+	data->reauth = 1;
+	sm->peap_done = FALSE;
+	return priv;
+}
+
+
+static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
+			       size_t buflen, int verbose)
+{
+	struct eap_peap_data *data = priv;
+	int len, ret;
+
+	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+	if (data->phase2_method) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "EAP-PEAPv%d Phase2 method=%s\n",
+				  data->peap_version,
+				  data->phase2_method->name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+	return len;
+}
+
+
+static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return data->key_data != NULL && data->phase2_success;
+}
+
+
+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_peap_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;
+
+	if (data->crypto_binding_used) {
+		u8 csk[128];
+		/*
+		 * Note: It looks like Microsoft implementation requires null
+		 * termination for this label while the one used for deriving
+		 * IPMK|CMK did not use null termination.
+		 */
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+			os_free(key);
+			return NULL;
+		}
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+			    key, EAP_TLS_KEY_LEN);
+	} else
+		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_peap_init;
+	eap->deinit = eap_peap_deinit;
+	eap->process = eap_peap_process;
+	eap->isKeyAvailable = eap_peap_isKeyAvailable;
+	eap->getKey = eap_peap_getKey;
+	eap->get_status = eap_peap_get_status;
+	eap->has_reauth_data = eap_peap_has_reauth_data;
+	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
+	eap->init_for_reauth = eap_peap_init_for_reauth;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_psk.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_psk.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_psk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,482 +0,0 @@
-/*
- * EAP peer method: EAP-PSK (RFC 4764)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Note: EAP-PSK is an EAP authentication method and as such, completely
- * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "eap_common/eap_psk_common.h"
-#include "eap_i.h"
-
-
-struct eap_psk_data {
-	enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
-	u8 rand_p[EAP_PSK_RAND_LEN];
-	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
-	u8 *id_s, *id_p;
-	size_t id_s_len, id_p_len;
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-};
-
-
-static void * eap_psk_init(struct eap_sm *sm)
-{
-	struct eap_psk_data *data;
-	const u8 *identity, *password;
-	size_t identity_len, password_len;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (!password || password_len != 16) {
-		wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
-			   "configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	if (eap_psk_key_setup(password, data->ak, data->kdk)) {
-		os_free(data);
-		return NULL;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
-	data->state = PSK_INIT;
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity) {
-		data->id_p = os_malloc(identity_len);
-		if (data->id_p)
-			os_memcpy(data->id_p, identity, identity_len);
-		data->id_p_len = identity_len;
-	}
-	if (data->id_p == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
-		os_free(data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_psk_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_psk_data *data = priv;
-	os_free(data->id_s);
-	os_free(data->id_p);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
-					 struct eap_method_ret *ret,
-					 const struct wpabuf *reqData)
-{
-	const struct eap_psk_hdr_1 *hdr1;
-	struct eap_psk_hdr_2 *hdr2;
-	struct wpabuf *resp;
-	u8 *buf, *pos;
-	size_t buflen, len;
-	const u8 *cpos;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
-
-	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
-	hdr1 = (const struct eap_psk_hdr_1 *) cpos;
-	if (cpos == NULL || len < sizeof(*hdr1)) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
-			   "length (%lu; expected %lu or more)",
-			   (unsigned long) len,
-			   (unsigned long) sizeof(*hdr1));
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
-	if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
-			   EAP_PSK_FLAGS_GET_T(hdr1->flags));
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
-		    EAP_PSK_RAND_LEN);
-	os_free(data->id_s);
-	data->id_s_len = len - sizeof(*hdr1);
-	data->id_s = os_malloc(data->id_s_len);
-	if (data->id_s == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
-			   "ID_S (len=%lu)", (unsigned long) data->id_s_len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
-			  data->id_s, data->id_s_len);
-
-	if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			     sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE,
-			     eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-	hdr2 = wpabuf_put(resp, sizeof(*hdr2));
-	hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
-	os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
-	os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
-	wpabuf_put_data(resp, data->id_p, data->id_p_len);
-	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
-	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
-	buf = os_malloc(buflen);
-	if (buf == NULL) {
-		wpabuf_free(resp);
-		return NULL;
-	}
-	os_memcpy(buf, data->id_p, data->id_p_len);
-	pos = buf + data->id_p_len;
-	os_memcpy(pos, data->id_s, data->id_s_len);
-	pos += data->id_s_len;
-	os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
-	pos += EAP_PSK_RAND_LEN;
-	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) {
-		os_free(buf);
-		wpabuf_free(resp);
-		return NULL;
-	}
-	os_free(buf);
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
-		    EAP_PSK_RAND_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
-			  data->id_p, data->id_p_len);
-
-	data->state = PSK_MAC_SENT;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
-					 struct eap_method_ret *ret,
-					 const struct wpabuf *reqData)
-{
-	const struct eap_psk_hdr_3 *hdr3;
-	struct eap_psk_hdr_4 *hdr4;
-	struct wpabuf *resp;
-	u8 *buf, *rpchannel, nonce[16], *decrypted;
-	const u8 *pchannel, *tag, *msg;
-	u8 mac[EAP_PSK_MAC_LEN];
-	size_t buflen, left, data_len, len, plen;
-	int failed = 0;
-	const u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			       reqData, &len);
-	hdr3 = (const struct eap_psk_hdr_3 *) pos;
-	if (pos == NULL || len < sizeof(*hdr3)) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
-			   "length (%lu; expected %lu or more)",
-			   (unsigned long) len,
-			   (unsigned long) sizeof(*hdr3));
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	left = len - sizeof(*hdr3);
-	pchannel = (const u8 *) (hdr3 + 1);
-	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
-	if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
-			   EAP_PSK_FLAGS_GET_T(hdr3->flags));
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
-		    EAP_PSK_RAND_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
-
-	if (left < 4 + 16 + 1) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
-			   "third message (len=%lu, expected 21)",
-			   (unsigned long) left);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
-	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return NULL;
-	os_memcpy(buf, data->id_s, data->id_s_len);
-	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
-		os_free(buf);
-		return NULL;
-	}
-	os_free(buf);
-	if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
-		wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
-			   "message");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
-
-	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
-				data->msk, data->emsk)) {
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
-
-	os_memset(nonce, 0, 12);
-	os_memcpy(nonce + 12, pchannel, 4);
-	pchannel += 4;
-	left -= 4;
-
-	tag = pchannel;
-	pchannel += 16;
-	left -= 16;
-
-	msg = pchannel;
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
-		    nonce, sizeof(nonce));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr",
-		    wpabuf_head(reqData), 5);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
-
-	decrypted = os_malloc(left);
-	if (decrypted == NULL) {
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		return NULL;
-	}
-	os_memcpy(decrypted, msg, left);
-
-	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
-				wpabuf_head(reqData),
-				sizeof(struct eap_hdr) + 1 +
-				sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted,
-				left, tag)) {
-		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
-		os_free(decrypted);
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
-		    decrypted, left);
-
-	/* Verify R flag */
-	switch (decrypted[0] >> 6) {
-	case EAP_PSK_R_FLAG_CONT:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
-		failed = 1;
-		break;
-	case EAP_PSK_R_FLAG_DONE_SUCCESS:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
-		break;
-	case EAP_PSK_R_FLAG_DONE_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
-		wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
-			   "authentication");
-		failed = 1;
-		break;
-	}
-
-	data_len = 1;
-	if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1)
-		data_len++;
-	plen = sizeof(*hdr4) + 4 + 16 + data_len;
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen,
-			     EAP_CODE_RESPONSE, eap_get_id(reqData));
-	if (resp == NULL) {
-		os_free(decrypted);
-		return NULL;
-	}
-	hdr4 = wpabuf_put(resp, sizeof(*hdr4));
-	hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
-	os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
-	rpchannel = wpabuf_put(resp, 4 + 16 + data_len);
-
-	/* nonce++ */
-	inc_byte_array(nonce, sizeof(nonce));
-	os_memcpy(rpchannel, nonce + 12, 4);
-
-	if (decrypted[0] & EAP_PSK_E_FLAG) {
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
-		failed = 1;
-		rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
-			EAP_PSK_E_FLAG;
-		if (left > 1) {
-			/* Add empty EXT_Payload with same EXT_Type */
-			rpchannel[4 + 16 + 1] = decrypted[1];
-		}
-	} else if (failed)
-		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
-	else
-		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
-
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
-		    rpchannel + 4 + 16, data_len);
-	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
-				wpabuf_head(resp),
-				sizeof(struct eap_hdr) + 1 + sizeof(*hdr4),
-				rpchannel + 4 + 16, data_len, rpchannel + 4)) {
-		os_free(decrypted);
-		wpabuf_free(resp);
-		return NULL;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
-		    rpchannel, 4 + 16 + data_len);
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
-		   failed ? "un" : "");
-	data->state = PSK_DONE;
-	ret->methodState = METHOD_DONE;
-	ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
-
-	os_free(decrypted);
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_psk_data *data = priv;
-	const u8 *pos;
-	struct wpabuf *resp = NULL;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
-	if (pos == NULL) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	switch (data->state) {
-	case PSK_INIT:
-		resp = eap_psk_process_1(data, ret, reqData);
-		break;
-	case PSK_MAC_SENT:
-		resp = eap_psk_process_3(data, ret, reqData);
-		break;
-	case PSK_DONE:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
-			   "unexpected message");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (ret->methodState == METHOD_DONE) {
-		ret->allowNotifications = FALSE;
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_psk_data *data = priv;
-	return data->state == PSK_DONE;
-}
-
-
-static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_psk_data *data = priv;
-	u8 *key;
-
-	if (data->state != PSK_DONE)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_MSK_LEN;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-
-	return key;
-}
-
-
-static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_psk_data *data = priv;
-	u8 *key;
-
-	if (data->state != PSK_DONE)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_EMSK_LEN;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_psk_init;
-	eap->deinit = eap_psk_deinit;
-	eap->process = eap_psk_process;
-	eap->isKeyAvailable = eap_psk_isKeyAvailable;
-	eap->getKey = eap_psk_getKey;
-	eap->get_emsk = eap_psk_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_psk.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_psk.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_psk.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_psk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,477 @@
+/*
+ * EAP peer method: EAP-PSK (RFC 4764)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Note: EAP-PSK is an EAP authentication method and as such, completely
+ * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/random.h"
+#include "eap_common/eap_psk_common.h"
+#include "eap_i.h"
+
+
+struct eap_psk_data {
+	enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
+	u8 rand_p[EAP_PSK_RAND_LEN];
+	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
+	u8 *id_s, *id_p;
+	size_t id_s_len, id_p_len;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+};
+
+
+static void * eap_psk_init(struct eap_sm *sm)
+{
+	struct eap_psk_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (!password || password_len != 16) {
+		wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not "
+			   "configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	if (eap_psk_key_setup(password, data->ak, data->kdk)) {
+		os_free(data);
+		return NULL;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
+	data->state = PSK_INIT;
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity) {
+		data->id_p = os_malloc(identity_len);
+		if (data->id_p)
+			os_memcpy(data->id_p, identity, identity_len);
+		data->id_p_len = identity_len;
+	}
+	if (data->id_p == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
+		os_free(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_psk_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_psk_data *data = priv;
+	os_free(data->id_s);
+	os_free(data->id_p);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data,
+					 struct eap_method_ret *ret,
+					 const struct wpabuf *reqData)
+{
+	const struct eap_psk_hdr_1 *hdr1;
+	struct eap_psk_hdr_2 *hdr2;
+	struct wpabuf *resp;
+	u8 *buf, *pos;
+	size_t buflen, len;
+	const u8 *cpos;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
+
+	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
+	hdr1 = (const struct eap_psk_hdr_1 *) cpos;
+	if (cpos == NULL || len < sizeof(*hdr1)) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message "
+			   "length (%lu; expected %lu or more)",
+			   (unsigned long) len,
+			   (unsigned long) sizeof(*hdr1));
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
+	if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
+			   EAP_PSK_FLAGS_GET_T(hdr1->flags));
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
+		    EAP_PSK_RAND_LEN);
+	os_free(data->id_s);
+	data->id_s_len = len - sizeof(*hdr1);
+	data->id_s = os_malloc(data->id_s_len);
+	if (data->id_s == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
+			   "ID_S (len=%lu)", (unsigned long) data->id_s_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
+			  data->id_s, data->id_s_len);
+
+	if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
+			     sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE,
+			     eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+	hdr2 = wpabuf_put(resp, sizeof(*hdr2));
+	hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
+	os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
+	os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
+	wpabuf_put_data(resp, data->id_p, data->id_p_len);
+	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
+	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpabuf_free(resp);
+		return NULL;
+	}
+	os_memcpy(buf, data->id_p, data->id_p_len);
+	pos = buf + data->id_p_len;
+	os_memcpy(pos, data->id_s, data->id_s_len);
+	pos += data->id_s_len;
+	os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
+	pos += EAP_PSK_RAND_LEN;
+	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
+	if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) {
+		os_free(buf);
+		wpabuf_free(resp);
+		return NULL;
+	}
+	os_free(buf);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
+		    EAP_PSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P",
+			  data->id_p, data->id_p_len);
+
+	data->state = PSK_MAC_SENT;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
+					 struct eap_method_ret *ret,
+					 const struct wpabuf *reqData)
+{
+	const struct eap_psk_hdr_3 *hdr3;
+	struct eap_psk_hdr_4 *hdr4;
+	struct wpabuf *resp;
+	u8 *buf, *rpchannel, nonce[16], *decrypted;
+	const u8 *pchannel, *tag, *msg;
+	u8 mac[EAP_PSK_MAC_LEN];
+	size_t buflen, left, data_len, len, plen;
+	int failed = 0;
+	const u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
+			       reqData, &len);
+	hdr3 = (const struct eap_psk_hdr_3 *) pos;
+	if (pos == NULL || len < sizeof(*hdr3)) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
+			   "length (%lu; expected %lu or more)",
+			   (unsigned long) len,
+			   (unsigned long) sizeof(*hdr3));
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	left = len - sizeof(*hdr3);
+	pchannel = (const u8 *) (hdr3 + 1);
+	wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
+	if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
+			   EAP_PSK_FLAGS_GET_T(hdr3->flags));
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
+		    EAP_PSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
+
+	if (left < 4 + 16 + 1) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
+			   "third message (len=%lu, expected 21)",
+			   (unsigned long) left);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
+	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return NULL;
+	os_memcpy(buf, data->id_s, data->id_s_len);
+	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
+		os_free(buf);
+		return NULL;
+	}
+	os_free(buf);
+	if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
+		wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
+			   "message");
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
+
+	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
+				data->msk, data->emsk)) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
+
+	os_memset(nonce, 0, 12);
+	os_memcpy(nonce + 12, pchannel, 4);
+	pchannel += 4;
+	left -= 4;
+
+	tag = pchannel;
+	pchannel += 16;
+	left -= 16;
+
+	msg = pchannel;
+
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce",
+		    nonce, sizeof(nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr",
+		    wpabuf_head(reqData), 5);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
+
+	decrypted = os_malloc(left);
+	if (decrypted == NULL) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	os_memcpy(decrypted, msg, left);
+
+	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
+				wpabuf_head(reqData),
+				sizeof(struct eap_hdr) + 1 +
+				sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted,
+				left, tag)) {
+		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
+		os_free(decrypted);
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
+		    decrypted, left);
+
+	/* Verify R flag */
+	switch (decrypted[0] >> 6) {
+	case EAP_PSK_R_FLAG_CONT:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
+		failed = 1;
+		break;
+	case EAP_PSK_R_FLAG_DONE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
+		break;
+	case EAP_PSK_R_FLAG_DONE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
+		wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected "
+			   "authentication");
+		failed = 1;
+		break;
+	}
+
+	data_len = 1;
+	if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1)
+		data_len++;
+	plen = sizeof(*hdr4) + 4 + 16 + data_len;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL) {
+		os_free(decrypted);
+		return NULL;
+	}
+	hdr4 = wpabuf_put(resp, sizeof(*hdr4));
+	hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
+	os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
+	rpchannel = wpabuf_put(resp, 4 + 16 + data_len);
+
+	/* nonce++ */
+	inc_byte_array(nonce, sizeof(nonce));
+	os_memcpy(rpchannel, nonce + 12, 4);
+
+	if (decrypted[0] & EAP_PSK_E_FLAG) {
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
+		failed = 1;
+		rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
+			EAP_PSK_E_FLAG;
+		if (left > 1) {
+			/* Add empty EXT_Payload with same EXT_Type */
+			rpchannel[4 + 16 + 1] = decrypted[1];
+		}
+	} else if (failed)
+		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
+	else
+		rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
+		    rpchannel + 4 + 16, data_len);
+	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
+				wpabuf_head(resp),
+				sizeof(struct eap_hdr) + 1 + sizeof(*hdr4),
+				rpchannel + 4 + 16, data_len, rpchannel + 4)) {
+		os_free(decrypted);
+		wpabuf_free(resp);
+		return NULL;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
+		    rpchannel, 4 + 16 + data_len);
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
+		   failed ? "un" : "");
+	data->state = PSK_DONE;
+	ret->methodState = METHOD_DONE;
+	ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
+
+	os_free(decrypted);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_psk_data *data = priv;
+	const u8 *pos;
+	struct wpabuf *resp = NULL;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	switch (data->state) {
+	case PSK_INIT:
+		resp = eap_psk_process_1(data, ret, reqData);
+		break;
+	case PSK_MAC_SENT:
+		resp = eap_psk_process_3(data, ret, reqData);
+		break;
+	case PSK_DONE:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore "
+			   "unexpected message");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_psk_data *data = priv;
+	return data->state == PSK_DONE;
+}
+
+
+static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *key;
+
+	if (data->state != PSK_DONE)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_MSK_LEN;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+
+	return key;
+}
+
+
+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *key;
+
+	if (data->state != PSK_DONE)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_psk_init;
+	eap->deinit = eap_psk_deinit;
+	eap->process = eap_psk_process;
+	eap->isKeyAvailable = eap_psk_isKeyAvailable;
+	eap->getKey = eap_psk_getKey;
+	eap->get_emsk = eap_psk_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Copied: vendor/wpa/2.0/src/eap_peer/eap_pwd.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_pwd.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_pwd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_pwd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,922 @@
+/*
+ * EAP peer method: EAP-pwd (RFC 5931)
+ * Copyright (c) 2010, Dan Harkins <dharkins at lounge.org>
+ *
+ * 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/sha256.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_pwd_common.h"
+
+
+struct eap_pwd_data {
+	enum {
+		PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
+	} state;
+	u8 *id_peer;
+	size_t id_peer_len;
+	u8 *id_server;
+	size_t id_server_len;
+	u8 *password;
+	size_t password_len;
+	u16 group_num;
+	EAP_PWD_group *grp;
+
+	struct wpabuf *inbuf;
+	size_t in_frag_pos;
+	struct wpabuf *outbuf;
+	size_t out_frag_pos;
+	size_t mtu;
+
+	BIGNUM *k;
+	BIGNUM *private_value;
+	BIGNUM *server_scalar;
+	BIGNUM *my_scalar;
+	EC_POINT *my_element;
+	EC_POINT *server_element;
+
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+
+	BN_CTX *bnctx;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_pwd_state_txt(int state)
+{
+	switch (state) {
+        case PWD_ID_Req:
+		return "PWD-ID-Req";
+        case PWD_Commit_Req:
+		return "PWD-Commit-Req";
+        case PWD_Confirm_Req:
+		return "PWD-Confirm-Req";
+        case SUCCESS:
+		return "SUCCESS";
+        case FAILURE:
+		return "FAILURE";
+        default:
+		return "PWD-UNK";
+	}
+}
+#endif  /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_pwd_state(struct eap_pwd_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-PWD: %s -> %s",
+		   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_pwd_init(struct eap_sm *sm)
+{
+	struct eap_pwd_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
+		return NULL;
+	}
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
+		return NULL;
+	}
+
+	if ((data = os_zalloc(sizeof(*data))) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
+		return NULL;
+	}
+
+	if ((data->bnctx = BN_CTX_new()) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
+		os_free(data);
+		return NULL;
+	}
+
+	if ((data->id_peer = os_malloc(identity_len)) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+		BN_CTX_free(data->bnctx);
+		os_free(data);
+		return NULL;
+	}
+
+	os_memcpy(data->id_peer, identity, identity_len);
+	data->id_peer_len = identity_len;
+
+	if ((data->password = os_malloc(password_len)) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
+		BN_CTX_free(data->bnctx);
+		os_free(data->id_peer);
+		os_free(data);
+		return NULL;
+	}
+	os_memcpy(data->password, password, password_len);
+	data->password_len = password_len;
+
+	data->out_frag_pos = data->in_frag_pos = 0;
+	data->inbuf = data->outbuf = NULL;
+	data->mtu = 1020; /* default from RFC 5931, make it configurable! */
+
+	data->state = PWD_ID_Req;
+
+	return data;
+}
+
+
+static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_pwd_data *data = priv;
+
+	BN_free(data->private_value);
+	BN_free(data->server_scalar);
+	BN_free(data->my_scalar);
+	BN_free(data->k);
+	BN_CTX_free(data->bnctx);
+	EC_POINT_free(data->my_element);
+	EC_POINT_free(data->server_element);
+	os_free(data->id_peer);
+	os_free(data->id_server);
+	os_free(data->password);
+	if (data->grp) {
+		EC_GROUP_free(data->grp->group);
+		EC_POINT_free(data->grp->pwe);
+		BN_free(data->grp->order);
+		BN_free(data->grp->prime);
+		os_free(data->grp);
+	}
+	os_free(data);
+}
+
+
+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pwd_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static void
+eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+			    struct eap_method_ret *ret,
+			    const struct wpabuf *reqData,
+			    const u8 *payload, size_t payload_len)
+{
+	struct eap_pwd_id *id;
+
+	if (data->state != PWD_ID_Req) {
+		ret->ignore = TRUE;
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	if (payload_len < sizeof(struct eap_pwd_id)) {
+		ret->ignore = TRUE;
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	id = (struct eap_pwd_id *) payload;
+	data->group_num = be_to_host16(id->group_num);
+	if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
+	    (id->prf != EAP_PWD_DEFAULT_PRF)) {
+		ret->ignore = TRUE;
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d",
+		   data->group_num);
+
+	data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
+	if (data->id_server == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+	data->id_server_len = payload_len - sizeof(struct eap_pwd_id);
+	os_memcpy(data->id_server, id->identity, data->id_server_len);
+	wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
+			  data->id_server, data->id_server_len);
+
+	if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) ==
+	    NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
+			   "group");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	/* compute PWE */
+	if (compute_password_element(data->grp, data->group_num,
+				     data->password, data->password_len,
+				     data->id_server, data->id_server_len,
+				     data->id_peer, data->id_peer_len,
+				     id->token)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PWD (peer): computed %d bit PWE...",
+		   BN_num_bits(data->grp->prime));
+
+	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
+				    data->id_peer_len);
+	if (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);
+	wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
+	wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
+	wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
+
+	eap_pwd_state(data, PWD_Commit_Req);
+}
+
+
+static void
+eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+				struct eap_method_ret *ret,
+				const struct wpabuf *reqData,
+				const u8 *payload, size_t payload_len)
+{
+	EC_POINT *K = NULL, *point = NULL;
+	BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
+	u16 offset;
+	u8 *ptr, *scalar = NULL, *element = NULL;
+
+	if (((data->private_value = BN_new()) == NULL) ||
+	    ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((cofactor = BN_new()) == NULL) ||
+	    ((data->my_scalar = BN_new()) == NULL) ||
+	    ((mask = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
+		goto fin;
+	}
+
+	if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+		wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
+			   "for curve");
+		goto fin;
+	}
+
+	BN_rand_range(data->private_value, data->grp->order);
+	BN_rand_range(mask, data->grp->order);
+	BN_add(data->my_scalar, data->private_value, mask);
+	BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+	       data->bnctx);
+
+	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
+			  data->grp->pwe, mask, data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
+			   "fail");
+		eap_pwd_state(data, FAILURE);
+		goto fin;
+	}
+
+	if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
+	{
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
+		goto fin;
+	}
+	BN_free(mask);
+
+	if (((x = BN_new()) == NULL) ||
+	    ((y = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
+		goto fin;
+	}
+
+	/* process the request */
+	if (((data->server_scalar = BN_new()) == NULL) ||
+	    ((data->k = BN_new()) == NULL) ||
+	    ((K = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((point = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
+	{
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
+			   "fail");
+		goto fin;
+	}
+
+	/* element, x then y, followed by scalar */
+	ptr = (u8 *) payload;
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
+	ptr += BN_num_bytes(data->grp->prime);
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
+	ptr += BN_num_bytes(data->grp->prime);
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
+	if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
+						 data->server_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
+			   "fail");
+		goto fin;
+	}
+
+	/* check to ensure server's element is not in a small sub-group */
+	if (BN_cmp(cofactor, BN_value_one())) {
+		if (!EC_POINT_mul(data->grp->group, point, NULL,
+				  data->server_element, cofactor, NULL)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+				   "server element by order!\n");
+			goto fin;
+		}
+		if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
+				   "is at infinity!\n");
+			goto fin;
+		}
+	}
+
+	/* compute the shared key, k */
+	if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
+			   data->server_scalar, data->bnctx)) ||
+	    (!EC_POINT_add(data->grp->group, K, K, data->server_element,
+			   data->bnctx)) ||
+	    (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
+			   data->bnctx))) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
+			   "fail");
+		goto fin;
+	}
+
+	/* ensure that the shared key isn't in a small sub-group */
+	if (BN_cmp(cofactor, BN_value_one())) {
+		if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
+				  NULL)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
+				   "shared key point by order");
+			goto fin;
+		}
+	}
+
+	/*
+	 * This check is strictly speaking just for the case above where
+	 * co-factor > 1 but it was suggested that even though this is probably
+	 * never going to happen it is a simple and safe check "just to be
+	 * sure" so let's be safe.
+	 */
+	if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
+			   "infinity!\n");
+		goto fin;
+	}
+
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
+						 NULL, data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
+			   "shared secret from point");
+		goto fin;
+	}
+
+	/* now do the response */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
+		goto fin;
+	}
+
+	if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
+	    ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
+	     NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
+		goto fin;
+	}
+
+	/*
+	 * bignums occupy as little memory as possible so one that is
+	 * sufficiently smaller than the prime or order might need pre-pending
+	 * with zeros.
+	 */
+	os_memset(scalar, 0, BN_num_bytes(data->grp->order));
+	os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, scalar + offset);
+
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, element + offset);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
+
+	data->outbuf = wpabuf_alloc(BN_num_bytes(data->grp->order) +
+				    2 * BN_num_bytes(data->grp->prime));
+	if (data->outbuf == NULL)
+		goto fin;
+
+	/* we send the element as (x,y) follwed by the scalar */
+	wpabuf_put_data(data->outbuf, element,
+			2 * BN_num_bytes(data->grp->prime));
+	wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+
+fin:
+	os_free(scalar);
+	os_free(element);
+	BN_free(x);
+	BN_free(y);
+	BN_free(cofactor);
+	EC_POINT_free(K);
+	EC_POINT_free(point);
+	if (data->outbuf == NULL)
+		eap_pwd_state(data, FAILURE);
+	else
+		eap_pwd_state(data, PWD_Confirm_Req);
+}
+
+
+static void
+eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
+				 struct eap_method_ret *ret,
+				 const struct wpabuf *reqData,
+				 const u8 *payload, size_t payload_len)
+{
+	BIGNUM *x = NULL, *y = NULL;
+	struct crypto_hash *hash;
+	u32 cs;
+	u16 grp;
+	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+	int offset;
+
+	/*
+	 * first build up the ciphersuite which is group | random_function |
+	 *	prf
+	 */
+	grp = htons(data->group_num);
+	ptr = (u8 *) &cs;
+	os_memcpy(ptr, &grp, sizeof(u16));
+	ptr += sizeof(u16);
+	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+	ptr += sizeof(u8);
+	*ptr = EAP_PWD_DEFAULT_PRF;
+
+	/* each component of the cruft will be at most as big as the prime */
+	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm allocation "
+			   "fail");
+		goto fin;
+	}
+
+	/*
+	 * server's commit is H(k | server_element | server_scalar |
+	 *			peer_element | peer_scalar | ciphersuite)
+	 */
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
+
+	/*
+	 * zero the memory each time because this is mod prime math and some
+	 * value may start with a few zeros and the previous one did not.
+	 */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->server_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* my element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* my scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* the ciphersuite */
+	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
+
+	/* random function fin */
+	eap_pwd_h_final(hash, conf);
+
+	ptr = (u8 *) payload;
+	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
+		goto fin;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
+
+	/*
+	 * compute confirm:
+	 *  H(k | peer_element | peer_scalar | server_element | server_scalar |
+	 *    ciphersuite)
+	 */
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
+
+	/* k */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* my element */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* my scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* server element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->server_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* the ciphersuite */
+	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
+
+	/* all done */
+	eap_pwd_h_final(hash, conf);
+
+	if (compute_keys(data->grp, data->bnctx, data->k,
+			 data->my_scalar, data->server_scalar, conf, ptr,
+			 &cs, data->msk, data->emsk) < 0) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
+			   "EMSK");
+		goto fin;
+	}
+
+	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
+	if (data->outbuf == NULL)
+		goto fin;
+
+	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
+
+fin:
+	os_free(cruft);
+	BN_free(x);
+	BN_free(y);
+	ret->methodState = METHOD_DONE;
+	if (data->outbuf == NULL) {
+		ret->decision = DECISION_FAIL;
+		eap_pwd_state(data, FAILURE);
+	} else {
+		ret->decision = DECISION_UNCOND_SUCC;
+		eap_pwd_state(data, SUCCESS);
+	}
+}
+
+
+static struct wpabuf *
+eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
+		const struct wpabuf *reqData)
+{
+	struct eap_pwd_data *data = priv;
+	struct wpabuf *resp = NULL;
+	const u8 *pos, *buf;
+	size_t len;
+	u16 tot_len = 0;
+	u8 lm_exch;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len);
+	if ((pos == NULL) || (len < 1)) {
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Got a frame but pos is %s and "
+			   "len is %d",
+			   pos == NULL ? "NULL" : "not NULL", (int) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	lm_exch = *pos;
+	pos++;                  /* skip over the bits and the exch */
+	len--;
+
+	/*
+	 * we're fragmenting so send out the next fragment
+	 */
+	if (data->out_frag_pos) {
+		/*
+		 * this should be an ACK
+		 */
+		if (len)
+			wpa_printf(MSG_INFO, "Bad Response! Fragmenting but "
+				   "not an ACK");
+
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Got an ACK for a fragment");
+		/*
+		 * check if there are going to be more fragments
+		 */
+		len = wpabuf_len(data->outbuf) - data->out_frag_pos;
+		if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
+			len = data->mtu - EAP_PWD_HDR_SIZE;
+			EAP_PWD_SET_MORE_BIT(lm_exch);
+		}
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+				     EAP_PWD_HDR_SIZE + len,
+				     EAP_CODE_RESPONSE, eap_get_id(reqData));
+		if (resp == NULL) {
+			wpa_printf(MSG_INFO, "Unable to allocate memory for "
+				   "next fragment!");
+			return NULL;
+		}
+		wpabuf_put_u8(resp, lm_exch);
+		buf = wpabuf_head_u8(data->outbuf);
+		wpabuf_put_data(resp, buf + data->out_frag_pos, len);
+		data->out_frag_pos += len;
+		/*
+		 * this is the last fragment so get rid of the out buffer
+		 */
+		if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
+			wpabuf_free(data->outbuf);
+			data->outbuf = NULL;
+			data->out_frag_pos = 0;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
+			   data->out_frag_pos == 0 ? "last" : "next",
+			   (int) len);
+		return resp;
+	}
+
+	/*
+	 * see if this is a fragment that needs buffering
+	 *
+	 * if it's the first fragment there'll be a length field
+	 */
+	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
+		tot_len = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose "
+			   "total length = %d", tot_len);
+		data->inbuf = wpabuf_alloc(tot_len);
+		if (data->inbuf == NULL) {
+			wpa_printf(MSG_INFO, "Out of memory to buffer "
+				   "fragments!");
+			return NULL;
+		}
+		pos += sizeof(u16);
+		len -= sizeof(u16);
+	}
+	/*
+	 * buffer and ACK the fragment
+	 */
+	if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+		data->in_frag_pos += len;
+		if (data->in_frag_pos > wpabuf_size(data->inbuf)) {
+			wpa_printf(MSG_INFO, "EAP-pwd: Buffer overflow attack "
+				   "detected (%d vs. %d)!",
+				   (int) data->in_frag_pos,
+				   (int) wpabuf_len(data->inbuf));
+			wpabuf_free(data->inbuf);
+			data->in_frag_pos = 0;
+			return NULL;
+		}
+		wpabuf_put_data(data->inbuf, pos, len);
+
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+				     EAP_PWD_HDR_SIZE,
+				     EAP_CODE_RESPONSE, eap_get_id(reqData));
+		if (resp != NULL)
+			wpabuf_put_u8(resp, (EAP_PWD_GET_EXCHANGE(lm_exch)));
+		wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a %d byte fragment",
+			   (int) len);
+		return resp;
+	}
+	/*
+	 * 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;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-pwd: processing frame: exch %d, len %d",
+		   EAP_PWD_GET_EXCHANGE(lm_exch), (int) len);
+
+	switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
+	case EAP_PWD_OPCODE_ID_EXCH:
+		eap_pwd_perform_id_exchange(sm, data, ret, reqData,
+					    pos, len);
+		break;
+	case EAP_PWD_OPCODE_COMMIT_EXCH:
+		eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
+						pos, len);
+		break;
+	case EAP_PWD_OPCODE_CONFIRM_EXCH:
+		eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
+						 pos, len);
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
+			   "opcode %d", lm_exch);
+		break;
+	}
+	/*
+	 * if we buffered the just processed input now's the time to free it
+	 */
+	if (data->in_frag_pos) {
+		wpabuf_free(data->inbuf);
+		data->in_frag_pos = 0;
+	}
+
+	if (data->outbuf == NULL)
+		return NULL;        /* generic failure */
+
+	/*
+	 * we have output! Do we need to fragment it?
+	 */
+	len = wpabuf_len(data->outbuf);
+	if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, data->mtu,
+				     EAP_CODE_RESPONSE, eap_get_id(reqData));
+		/*
+		 * if so it's the first so include a length field
+		 */
+		EAP_PWD_SET_LENGTH_BIT(lm_exch);
+		EAP_PWD_SET_MORE_BIT(lm_exch);
+		tot_len = len;
+		/*
+		 * keep the packet at the MTU
+		 */
+		len = data->mtu - EAP_PWD_HDR_SIZE - sizeof(u16);
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, total "
+			   "length = %d", tot_len);
+	} else {
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+				     EAP_PWD_HDR_SIZE + len,
+				     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	}
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, lm_exch);
+	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
+		wpabuf_put_be16(resp, tot_len);
+		data->out_frag_pos += len;
+	}
+	buf = wpabuf_head_u8(data->outbuf);
+	wpabuf_put_data(resp, buf, len);
+	/*
+	 * if we're not fragmenting then there's no need to carry this around
+	 */
+	if (data->out_frag_pos == 0) {
+		wpabuf_free(data->outbuf);
+		data->outbuf = NULL;
+		data->out_frag_pos = 0;
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
+{
+	struct eap_pwd_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pwd_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	if ((key = os_malloc(EAP_EMSK_LEN)) == NULL)
+		return NULL;
+
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+int eap_peer_pwd_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	EVP_add_digest(EVP_sha256());
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_pwd_init;
+	eap->deinit = eap_pwd_deinit;
+	eap->process = eap_pwd_process;
+	eap->isKeyAvailable = eap_pwd_key_available;
+	eap->getKey = eap_pwd_getkey;
+	eap->get_emsk = eap_pwd_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_sake.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_sake.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_sake.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,499 +0,0 @@
-/*
- * EAP peer method: EAP-SAKE (RFC 4763)
- * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_peer/eap_i.h"
-#include "eap_common/eap_sake_common.h"
-
-struct eap_sake_data {
-	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
-	u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
-	u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
-	u8 rand_s[EAP_SAKE_RAND_LEN];
-	u8 rand_p[EAP_SAKE_RAND_LEN];
-	struct {
-		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
-		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
-	} tek;
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 session_id;
-	int session_id_set;
-	u8 *peerid;
-	size_t peerid_len;
-	u8 *serverid;
-	size_t serverid_len;
-};
-
-
-static const char * eap_sake_state_txt(int state)
-{
-	switch (state) {
-	case IDENTITY:
-		return "IDENTITY";
-	case CHALLENGE:
-		return "CHALLENGE";
-	case CONFIRM:
-		return "CONFIRM";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_sake_state(struct eap_sake_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
-		   eap_sake_state_txt(data->state),
-		   eap_sake_state_txt(state));
-	data->state = state;
-}
-
-
-static void eap_sake_deinit(struct eap_sm *sm, void *priv);
-
-
-static void * eap_sake_init(struct eap_sm *sm)
-{
-	struct eap_sake_data *data;
-	const u8 *identity, *password;
-	size_t identity_len, password_len;
-
-	password = eap_get_config_password(sm, &password_len);
-	if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
-			   "configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = IDENTITY;
-
-	identity = eap_get_config_identity(sm, &identity_len);
-	if (identity) {
-		data->peerid = os_malloc(identity_len);
-		if (data->peerid == NULL) {
-			eap_sake_deinit(sm, data);
-			return NULL;
-		}
-		os_memcpy(data->peerid, identity, identity_len);
-		data->peerid_len = identity_len;
-	}
-
-	os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
-	os_memcpy(data->root_secret_b,
-		  password + EAP_SAKE_ROOT_SECRET_LEN,
-		  EAP_SAKE_ROOT_SECRET_LEN);
-
-	return data;
-}
-
-
-static void eap_sake_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_sake_data *data = priv;
-	os_free(data->serverid);
-	os_free(data->peerid);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
-					  int id, size_t length, u8 subtype)
-{
-	struct eap_sake_hdr *sake;
-	struct wpabuf *msg;
-	size_t plen;
-
-	plen = length + sizeof(struct eap_sake_hdr);
-
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
-			    EAP_CODE_RESPONSE, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
-			   "request");
-		return NULL;
-	}
-
-	sake = wpabuf_put(msg, sizeof(*sake));
-	sake->version = EAP_SAKE_VERSION;
-	sake->session_id = data->session_id;
-	sake->subtype = subtype;
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
-						 struct eap_sake_data *data,
-						 struct eap_method_ret *ret,
-						 const struct wpabuf *reqData,
-						 const u8 *payload,
-						 size_t payload_len)
-{
-	struct eap_sake_parse_attr attr;
-	struct wpabuf *resp;
-
-	if (data->state != IDENTITY) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
-
-	if (eap_sake_parse_attributes(payload, payload_len, &attr))
-		return NULL;
-
-	if (!attr.perm_id_req && !attr.any_id_req) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
-			   "AT_ANY_ID_REQ in Request/Identity");
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
-
-	resp = eap_sake_build_msg(data, eap_get_id(reqData),
-				  2 + data->peerid_len,
-				  EAP_SAKE_SUBTYPE_IDENTITY);
-	if (resp == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
-	eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
-			  data->peerid, data->peerid_len);
-
-	eap_sake_state(data, CHALLENGE);
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
-						  struct eap_sake_data *data,
-						  struct eap_method_ret *ret,
-						  const struct wpabuf *reqData,
-						  const u8 *payload,
-						  size_t payload_len)
-{
-	struct eap_sake_parse_attr attr;
-	struct wpabuf *resp;
-	u8 *rpos;
-	size_t rlen;
-
-	if (data->state != IDENTITY && data->state != CHALLENGE) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
-			   "in unexpected state (%d)", data->state);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	if (data->state == IDENTITY)
-		eap_sake_state(data, CHALLENGE);
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
-
-	if (eap_sake_parse_attributes(payload, payload_len, &attr))
-		return NULL;
-
-	if (!attr.rand_s) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
-			   "include AT_RAND_S");
-		return NULL;
-	}
-
-	os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
-		    data->rand_s, EAP_SAKE_RAND_LEN);
-
-	if (os_get_random(data->rand_p, EAP_SAKE_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
-		    data->rand_p, EAP_SAKE_RAND_LEN);
-
-	os_free(data->serverid);
-	data->serverid = NULL;
-	data->serverid_len = 0;
-	if (attr.serverid) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
-				  attr.serverid, attr.serverid_len);
-		data->serverid = os_malloc(attr.serverid_len);
-		if (data->serverid == NULL)
-			return NULL;
-		os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
-		data->serverid_len = attr.serverid_len;
-	}
-
-	eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
-			     data->rand_s, data->rand_p,
-			     (u8 *) &data->tek, data->msk, data->emsk);
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
-
-	rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
-	if (data->peerid)
-		rlen += 2 + data->peerid_len;
-	resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen,
-				  EAP_SAKE_SUBTYPE_CHALLENGE);
-	if (resp == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
-	eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
-			  data->rand_p, EAP_SAKE_RAND_LEN);
-
-	if (data->peerid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
-		eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
-				  data->peerid, data->peerid_len);
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
-	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
-	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
-	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
-	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-				 data->serverid, data->serverid_len,
-				 data->peerid, data->peerid_len, 1,
-				 wpabuf_head(resp), wpabuf_len(resp), rpos,
-				 rpos)) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	eap_sake_state(data, CONFIRM);
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
-						struct eap_sake_data *data,
-						struct eap_method_ret *ret,
-						const struct wpabuf *reqData,
-						const u8 *payload,
-						size_t payload_len)
-{
-	struct eap_sake_parse_attr attr;
-	u8 mic_s[EAP_SAKE_MIC_LEN];
-	struct wpabuf *resp;
-	u8 *rpos;
-
-	if (data->state != CONFIRM) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
-
-	if (eap_sake_parse_attributes(payload, payload_len, &attr))
-		return NULL;
-
-	if (!attr.mic_s) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
-			   "include AT_MIC_S");
-		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 (os_memcmp(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);
-		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, eap_get_id(reqData), 0,
-					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
-
-	resp = eap_sake_build_msg(data, eap_get_id(reqData),
-				  2 + EAP_SAKE_MIC_LEN,
-				  EAP_SAKE_SUBTYPE_CONFIRM);
-	if (resp == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
-	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
-	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
-	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
-	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-				 data->serverid, data->serverid_len,
-				 data->peerid, data->peerid_len, 1,
-				 wpabuf_head(resp), wpabuf_len(resp), rpos,
-				 rpos)) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	eap_sake_state(data, SUCCESS);
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	ret->allowNotifications = FALSE;
-
-	return resp;
-}
-
-
-static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
-					struct eap_method_ret *ret,
-					const struct wpabuf *reqData)
-{
-	struct eap_sake_data *data = priv;
-	const struct eap_sake_hdr *req;
-	struct wpabuf *resp;
-	const u8 *pos, *end;
-	size_t len;
-	u8 subtype, session_id;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
-	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	req = (const struct eap_sake_hdr *) pos;
-	end = pos + len;
-	subtype = req->subtype;
-	session_id = req->session_id;
-	pos = (const u8 *) (req + 1);
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
-		   "session_id %d", subtype, session_id);
-	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
-		    pos, end - pos);
-
-	if (data->session_id_set && data->session_id != session_id) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
-			   session_id, data->session_id);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	data->session_id = session_id;
-	data->session_id_set = 1;
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	switch (subtype) {
-	case EAP_SAKE_SUBTYPE_IDENTITY:
-		resp = eap_sake_process_identity(sm, data, ret, reqData,
-						 pos, end - pos);
-		break;
-	case EAP_SAKE_SUBTYPE_CHALLENGE:
-		resp = eap_sake_process_challenge(sm, data, ret, reqData,
-						  pos, end - pos);
-		break;
-	case EAP_SAKE_SUBTYPE_CONFIRM:
-		resp = eap_sake_process_confirm(sm, data, ret, reqData,
-						pos, end - pos);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
-			   "unknown subtype %d", subtype);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (ret->methodState == METHOD_DONE)
-		ret->allowNotifications = FALSE;
-
-	return resp;
-}
-
-
-static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_sake_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sake_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-	*len = EAP_MSK_LEN;
-
-	return key;
-}
-
-
-static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sake_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_sake_init;
-	eap->deinit = eap_sake_deinit;
-	eap->process = eap_sake_process;
-	eap->isKeyAvailable = eap_sake_isKeyAvailable;
-	eap->getKey = eap_sake_getKey;
-	eap->get_emsk = eap_sake_get_emsk;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_sake.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_sake.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_sake.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_sake.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,494 @@
+/*
+ * EAP peer method: EAP-SAKE (RFC 4763)
+ * Copyright (c) 2006-2008, Jouni Malinen <j at 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/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_common/eap_sake_common.h"
+
+struct eap_sake_data {
+	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
+	u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
+	u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
+	u8 rand_s[EAP_SAKE_RAND_LEN];
+	u8 rand_p[EAP_SAKE_RAND_LEN];
+	struct {
+		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
+		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
+	} tek;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 session_id;
+	int session_id_set;
+	u8 *peerid;
+	size_t peerid_len;
+	u8 *serverid;
+	size_t serverid_len;
+};
+
+
+static const char * eap_sake_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_sake_state(struct eap_sake_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
+		   eap_sake_state_txt(data->state),
+		   eap_sake_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_sake_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_sake_init(struct eap_sm *sm)
+{
+	struct eap_sake_data *data;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length "
+			   "configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = IDENTITY;
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity) {
+		data->peerid = os_malloc(identity_len);
+		if (data->peerid == NULL) {
+			eap_sake_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->peerid, identity, identity_len);
+		data->peerid_len = identity_len;
+	}
+
+	os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN);
+	os_memcpy(data->root_secret_b,
+		  password + EAP_SAKE_ROOT_SECRET_LEN,
+		  EAP_SAKE_ROOT_SECRET_LEN);
+
+	return data;
+}
+
+
+static void eap_sake_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	os_free(data->serverid);
+	os_free(data->peerid);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
+					  int id, size_t length, u8 subtype)
+{
+	struct eap_sake_hdr *sake;
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = length + sizeof(struct eap_sake_hdr);
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
+			   "request");
+		return NULL;
+	}
+
+	sake = wpabuf_put(msg, sizeof(*sake));
+	sake->version = EAP_SAKE_VERSION;
+	sake->session_id = data->session_id;
+	sake->subtype = subtype;
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm,
+						 struct eap_sake_data *data,
+						 struct eap_method_ret *ret,
+						 const struct wpabuf *reqData,
+						 const u8 *payload,
+						 size_t payload_len)
+{
+	struct eap_sake_parse_attr attr;
+	struct wpabuf *resp;
+
+	if (data->state != IDENTITY) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
+
+	if (eap_sake_parse_attributes(payload, payload_len, &attr))
+		return NULL;
+
+	if (!attr.perm_id_req && !attr.any_id_req) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
+			   "AT_ANY_ID_REQ in Request/Identity");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
+
+	resp = eap_sake_build_msg(data, eap_get_id(reqData),
+				  2 + data->peerid_len,
+				  EAP_SAKE_SUBTYPE_IDENTITY);
+	if (resp == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
+	eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
+			  data->peerid, data->peerid_len);
+
+	eap_sake_state(data, CHALLENGE);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm,
+						  struct eap_sake_data *data,
+						  struct eap_method_ret *ret,
+						  const struct wpabuf *reqData,
+						  const u8 *payload,
+						  size_t payload_len)
+{
+	struct eap_sake_parse_attr attr;
+	struct wpabuf *resp;
+	u8 *rpos;
+	size_t rlen;
+
+	if (data->state != IDENTITY && data->state != CHALLENGE) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
+			   "in unexpected state (%d)", data->state);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	if (data->state == IDENTITY)
+		eap_sake_state(data, CHALLENGE);
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
+
+	if (eap_sake_parse_attributes(payload, payload_len, &attr))
+		return NULL;
+
+	if (!attr.rand_s) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
+			   "include AT_RAND_S");
+		return NULL;
+	}
+
+	os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
+		    data->rand_s, EAP_SAKE_RAND_LEN);
+
+	if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
+		    data->rand_p, EAP_SAKE_RAND_LEN);
+
+	os_free(data->serverid);
+	data->serverid = NULL;
+	data->serverid_len = 0;
+	if (attr.serverid) {
+		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
+				  attr.serverid, attr.serverid_len);
+		data->serverid = os_malloc(attr.serverid_len);
+		if (data->serverid == NULL)
+			return NULL;
+		os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
+		data->serverid_len = attr.serverid_len;
+	}
+
+	eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
+			     data->rand_s, data->rand_p,
+			     (u8 *) &data->tek, data->msk, data->emsk);
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
+
+	rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
+	if (data->peerid)
+		rlen += 2 + data->peerid_len;
+	resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen,
+				  EAP_SAKE_SUBTYPE_CHALLENGE);
+	if (resp == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
+	eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P,
+			  data->rand_p, EAP_SAKE_RAND_LEN);
+
+	if (data->peerid) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
+		eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID,
+				  data->peerid, data->peerid_len);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
+	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
+	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
+	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
+	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len, 1,
+				 wpabuf_head(resp), wpabuf_len(resp), rpos,
+				 rpos)) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	eap_sake_state(data, CONFIRM);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
+						struct eap_sake_data *data,
+						struct eap_method_ret *ret,
+						const struct wpabuf *reqData,
+						const u8 *payload,
+						size_t payload_len)
+{
+	struct eap_sake_parse_attr attr;
+	u8 mic_s[EAP_SAKE_MIC_LEN];
+	struct wpabuf *resp;
+	u8 *rpos;
+
+	if (data->state != CONFIRM) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
+
+	if (eap_sake_parse_attributes(payload, payload_len, &attr))
+		return NULL;
+
+	if (!attr.mic_s) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
+			   "include AT_MIC_S");
+		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 (os_memcmp(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);
+		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, eap_get_id(reqData), 0,
+					  EAP_SAKE_SUBTYPE_AUTH_REJECT);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
+
+	resp = eap_sake_build_msg(data, eap_get_id(reqData),
+				  2 + EAP_SAKE_MIC_LEN,
+				  EAP_SAKE_SUBTYPE_CONFIRM);
+	if (resp == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
+	wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P);
+	wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN);
+	rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN);
+	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len, 1,
+				 wpabuf_head(resp), wpabuf_len(resp), rpos,
+				 rpos)) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	eap_sake_state(data, SUCCESS);
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	struct eap_sake_data *data = priv;
+	const struct eap_sake_hdr *req;
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	size_t len;
+	u8 subtype, session_id;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len);
+	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	req = (const struct eap_sake_hdr *) pos;
+	end = pos + len;
+	subtype = req->subtype;
+	session_id = req->session_id;
+	pos = (const u8 *) (req + 1);
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
+		   "session_id %d", subtype, session_id);
+	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
+		    pos, end - pos);
+
+	if (data->session_id_set && data->session_id != session_id) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
+			   session_id, data->session_id);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	data->session_id = session_id;
+	data->session_id_set = 1;
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	switch (subtype) {
+	case EAP_SAKE_SUBTYPE_IDENTITY:
+		resp = eap_sake_process_identity(sm, data, ret, reqData,
+						 pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CHALLENGE:
+		resp = eap_sake_process_challenge(sm, data, ret, reqData,
+						  pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CONFIRM:
+		resp = eap_sake_process_confirm(sm, data, ret, reqData,
+						pos, end - pos);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
+			   "unknown subtype %d", subtype);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (ret->methodState == METHOD_DONE)
+		ret->allowNotifications = FALSE;
+
+	return resp;
+}
+
+
+static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sake_init;
+	eap->deinit = eap_sake_deinit;
+	eap->process = eap_sake_process;
+	eap->isKeyAvailable = eap_sake_isKeyAvailable;
+	eap->getKey = eap_sake_getKey;
+	eap->get_emsk = eap_sake_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_sim.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_sim.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_sim.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1100 +0,0 @@
-/*
- * EAP peer method: EAP-SIM (RFC 4186)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "pcsc_funcs.h"
-#include "crypto/milenage.h"
-#include "eap_peer/eap_i.h"
-#include "eap_config.h"
-#include "eap_common/eap_sim_common.h"
-
-
-struct eap_sim_data {
-	u8 *ver_list;
-	size_t ver_list_len;
-	int selected_version;
-	size_t min_num_chal, num_chal;
-
-	u8 kc[3][EAP_SIM_KC_LEN];
-	u8 sres[3][EAP_SIM_SRES_LEN];
-	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
-	u8 mk[EAP_SIM_MK_LEN];
-	u8 k_aut[EAP_SIM_K_AUT_LEN];
-	u8 k_encr[EAP_SIM_K_ENCR_LEN];
-	u8 msk[EAP_SIM_KEYING_DATA_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 rand[3][GSM_RAND_LEN];
-
-	int num_id_req, num_notification;
-	u8 *pseudonym;
-	size_t pseudonym_len;
-	u8 *reauth_id;
-	size_t reauth_id_len;
-	int reauth;
-	unsigned int counter, counter_too_small;
-	u8 *last_eap_identity;
-	size_t last_eap_identity_len;
-	enum {
-		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
-	} state;
-	int result_ind, use_result_ind;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char * eap_sim_state_txt(int state)
-{
-	switch (state) {
-	case CONTINUE:
-		return "CONTINUE";
-	case RESULT_SUCCESS:
-		return "RESULT_SUCCESS";
-	case RESULT_FAILURE:
-		return "RESULT_FAILURE";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void eap_sim_state(struct eap_sim_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
-		   eap_sim_state_txt(data->state),
-		   eap_sim_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_sim_init(struct eap_sm *sm)
-{
-	struct eap_sim_data *data;
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	if (os_get_random(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);
-		return NULL;
-	}
-
-	data->min_num_chal = 2;
-	if (config && config->phase1) {
-		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
-		if (pos) {
-			data->min_num_chal = atoi(pos + 17);
-			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
-				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
-					   "sim_min_num_chal configuration "
-					   "(%lu, expected 2 or 3)",
-					   (unsigned long) data->min_num_chal);
-				os_free(data);
-				return NULL;
-			}
-			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
-				   "challenges to %lu",
-				   (unsigned long) data->min_num_chal);
-		}
-
-		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
-			NULL;
-	}
-
-	eap_sim_state(data, CONTINUE);
-
-	return data;
-}
-
-
-static void eap_sim_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	if (data) {
-		os_free(data->ver_list);
-		os_free(data->pseudonym);
-		os_free(data->reauth_id);
-		os_free(data->last_eap_identity);
-		os_free(data);
-	}
-}
-
-
-static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
-{
-	struct eap_peer_config *conf;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
-
-	conf = eap_get_config(sm);
-	if (conf == NULL)
-		return -1;
-	if (conf->pcsc) {
-		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
-				   data->sres[0], data->kc[0]) ||
-		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
-				   data->sres[1], data->kc[1]) ||
-		    (data->num_chal > 2 &&
-		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
-				    data->sres[2], data->kc[2]))) {
-			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
-				   "authentication could not be completed");
-			return -1;
-		}
-		return 0;
-	}
-
-#ifdef CONFIG_SIM_SIMULATOR
-	if (conf->password) {
-		u8 opc[16], k[16];
-		const char *pos;
-		size_t i;
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
-			   "implementation for authentication");
-		if (conf->password_len < 65) {
-			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
-				   "password");
-			return -1;
-		}
-		pos = (const char *) conf->password;
-		if (hexstr2bin(pos, k, 16))
-			return -1;
-		pos += 32;
-		if (*pos != ':')
-			return -1;
-		pos++;
-
-		if (hexstr2bin(pos, opc, 16))
-			return -1;
-
-		for (i = 0; i < data->num_chal; i++) {
-			if (gsm_milenage(opc, k, data->rand[i],
-					 data->sres[i], data->kc[i])) {
-				wpa_printf(MSG_DEBUG, "EAP-SIM: "
-					   "GSM-Milenage authentication "
-					   "could not be completed");
-				return -1;
-			}
-			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
-				    data->rand[i], GSM_RAND_LEN);
-			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
-					data->sres[i], EAP_SIM_SRES_LEN);
-			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
-					data->kc[i], EAP_SIM_KC_LEN);
-		}
-		return 0;
-	}
-#endif /* CONFIG_SIM_SIMULATOR */
-
-#ifdef CONFIG_SIM_HARDCODED
-	/* These hardcoded Kc and SRES values are used for testing. RAND to
-	 * KC/SREC mapping is very bogus as far as real authentication is
-	 * concerned, but it is quite useful for cases where the AS is rotating
-	 * the order of pre-configured values. */
-	{
-		size_t i;
-
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
-			   "values for testing");
-
-		for (i = 0; i < data->num_chal; i++) {
-			if (data->rand[i][0] == 0xaa) {
-				os_memcpy(data->kc[i],
-					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
-					  EAP_SIM_KC_LEN);
-				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
-					  EAP_SIM_SRES_LEN);
-			} else if (data->rand[i][0] == 0xbb) {
-				os_memcpy(data->kc[i],
-					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
-					  EAP_SIM_KC_LEN);
-				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
-					  EAP_SIM_SRES_LEN);
-			} else {
-				os_memcpy(data->kc[i],
-					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
-					  EAP_SIM_KC_LEN);
-				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
-					  EAP_SIM_SRES_LEN);
-			}
-		}
-	}
-
-	return 0;
-
-#else /* CONFIG_SIM_HARDCODED */
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
-		   "enabled");
-	return -1;
-
-#endif /* CONFIG_SIM_HARDCODED */
-}
-
-
-static int eap_sim_supported_ver(int version)
-{
-	return version == EAP_SIM_VERSION;
-}
-
-
-#define CLEAR_PSEUDONYM	0x01
-#define CLEAR_REAUTH_ID	0x02
-#define CLEAR_EAP_ID	0x04
-
-static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
-	if (id & CLEAR_PSEUDONYM) {
-		os_free(data->pseudonym);
-		data->pseudonym = NULL;
-		data->pseudonym_len = 0;
-	}
-	if (id & CLEAR_REAUTH_ID) {
-		os_free(data->reauth_id);
-		data->reauth_id = NULL;
-		data->reauth_id_len = 0;
-	}
-	if (id & CLEAR_EAP_ID) {
-		os_free(data->last_eap_identity);
-		data->last_eap_identity = NULL;
-		data->last_eap_identity_len = 0;
-	}
-}
-
-
-static int eap_sim_learn_ids(struct eap_sim_data *data,
-			     struct eap_sim_attrs *attr)
-{
-	if (attr->next_pseudonym) {
-		os_free(data->pseudonym);
-		data->pseudonym = os_malloc(attr->next_pseudonym_len);
-		if (data->pseudonym == NULL) {
-			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
-				   "next pseudonym");
-			return -1;
-		}
-		os_memcpy(data->pseudonym, attr->next_pseudonym,
-			  attr->next_pseudonym_len);
-		data->pseudonym_len = attr->next_pseudonym_len;
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
-				  data->pseudonym,
-				  data->pseudonym_len);
-	}
-
-	if (attr->next_reauth_id) {
-		os_free(data->reauth_id);
-		data->reauth_id = os_malloc(attr->next_reauth_id_len);
-		if (data->reauth_id == NULL) {
-			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
-				   "next reauth_id");
-			return -1;
-		}
-		os_memcpy(data->reauth_id, attr->next_reauth_id,
-			  attr->next_reauth_id_len);
-		data->reauth_id_len = attr->next_reauth_id_len;
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
-				  data->reauth_id,
-				  data->reauth_id_len);
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
-					    int err)
-{
-	struct eap_sim_msg *msg;
-
-	eap_sim_state(data, FAILURE);
-	data->num_id_req = 0;
-	data->num_notification = 0;
-
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
-	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
-					      struct eap_sim_data *data, u8 id,
-					      enum eap_sim_id_req id_req)
-{
-	const u8 *identity = NULL;
-	size_t identity_len = 0;
-	struct eap_sim_msg *msg;
-
-	data->reauth = 0;
-	if (id_req == ANY_ID && data->reauth_id) {
-		identity = data->reauth_id;
-		identity_len = data->reauth_id_len;
-		data->reauth = 1;
-	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
-		   data->pseudonym) {
-		identity = data->pseudonym;
-		identity_len = data->pseudonym_len;
-		eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
-	} else if (id_req != NO_ID_REQ) {
-		identity = eap_get_config_identity(sm, &identity_len);
-		if (identity) {
-			eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
-						 CLEAR_REAUTH_ID);
-		}
-	}
-	if (id_req != NO_ID_REQ)
-		eap_sim_clear_identities(data, CLEAR_EAP_ID);
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
-			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
-	if (!data->reauth) {
-		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
-			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
-		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
-				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
-		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
-			   data->selected_version);
-		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
-				data->selected_version, NULL, 0);
-	}
-
-	if (identity) {
-		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
-				  identity, identity_len);
-		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
-				identity, identity_len);
-	}
-
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
-						  u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_CHALLENGE);
-	if (data->use_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
-				  data->num_chal * EAP_SIM_SRES_LEN);
-}
-
-
-static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
-					       u8 id, int counter_too_small)
-{
-	struct eap_sim_msg *msg;
-	unsigned int counter;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
-		   id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
-	wpa_printf(MSG_DEBUG, "   AT_IV");
-	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
-
-	if (counter_too_small) {
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
-		counter = data->counter_too_small;
-	} else
-		counter = data->counter;
-
-	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
-	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
-
-	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
-			   "AT_ENCR_DATA");
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-	if (data->use_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
-				  EAP_SIM_NONCE_S_LEN);
-}
-
-
-static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
-						     u8 id, u16 notification)
-{
-	struct eap_sim_msg *msg;
-	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
-
-	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
-			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
-	if (k_aut && data->reauth) {
-		wpa_printf(MSG_DEBUG, "   AT_IV");
-		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
-					   EAP_SIM_AT_ENCR_DATA);
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
-				NULL, 0);
-		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
-					     EAP_SIM_AT_PADDING)) {
-			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
-				   "AT_ENCR_DATA");
-			eap_sim_msg_free(msg);
-			return NULL;
-		}
-	}
-	if (k_aut) {
-		wpa_printf(MSG_DEBUG, "   AT_MAC");
-		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	}
-	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
-}
-
-
-static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
-					     struct eap_sim_data *data, u8 id,
-					     struct eap_sim_attrs *attr)
-{
-	int selected_version = -1, id_error;
-	size_t i;
-	u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
-	if (attr->version_list == NULL) {
-		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
-			   "SIM/Start");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNSUPPORTED_VERSION);
-	}
-
-	os_free(data->ver_list);
-	data->ver_list = os_malloc(attr->version_list_len);
-	if (data->ver_list == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
-			   "memory for version list");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-	os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
-	data->ver_list_len = attr->version_list_len;
-	pos = data->ver_list;
-	for (i = 0; i < data->ver_list_len / 2; i++) {
-		int ver = pos[0] * 256 + pos[1];
-		pos += 2;
-		if (eap_sim_supported_ver(ver)) {
-			selected_version = ver;
-			break;
-		}
-	}
-	if (selected_version < 0) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
-			   "version");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNSUPPORTED_VERSION);
-	}
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
-		   selected_version);
-	data->selected_version = selected_version;
-
-	id_error = 0;
-	switch (attr->id_req) {
-	case NO_ID_REQ:
-		break;
-	case ANY_ID:
-		if (data->num_id_req > 0)
-			id_error++;
-		data->num_id_req++;
-		break;
-	case FULLAUTH_ID:
-		if (data->num_id_req > 1)
-			id_error++;
-		data->num_id_req++;
-		break;
-	case PERMANENT_ID:
-		if (data->num_id_req > 2)
-			id_error++;
-		data->num_id_req++;
-		break;
-	}
-	if (id_error) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
-			   "used within one authentication");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	return eap_sim_response_start(sm, data, id, attr->id_req);
-}
-
-
-static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
-						 struct eap_sim_data *data,
-						 u8 id,
-						 const struct wpabuf *reqData,
-						 struct eap_sim_attrs *attr)
-{
-	const u8 *identity;
-	size_t identity_len;
-	struct eap_sim_attrs eattr;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
-	data->reauth = 0;
-	if (!attr->mac || !attr->rand) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
-			   "did not include%s%s",
-			   !attr->mac ? " AT_MAC" : "",
-			   !attr->rand ? " AT_RAND" : "");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
-		   (unsigned long) attr->num_chal);
-	if (attr->num_chal < data->min_num_chal) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
-			   "challenges (%lu)", (unsigned long) attr->num_chal);
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
-	}
-	if (attr->num_chal > 3) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
-			   "(%lu)", (unsigned long) attr->num_chal);
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	/* Verify that RANDs are different */
-	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
-		   GSM_RAND_LEN) == 0 ||
-	    (attr->num_chal > 2 &&
-	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
-			GSM_RAND_LEN) == 0 ||
-	      os_memcmp(attr->rand + GSM_RAND_LEN,
-			attr->rand + 2 * GSM_RAND_LEN,
-			GSM_RAND_LEN) == 0))) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_RAND_NOT_FRESH);
-	}
-
-	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
-	data->num_chal = attr->num_chal;
-		
-	if (eap_sim_gsm_auth(sm, data)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-	if (data->last_eap_identity) {
-		identity = data->last_eap_identity;
-		identity_len = data->last_eap_identity_len;
-	} else if (data->pseudonym) {
-		identity = data->pseudonym;
-		identity_len = data->pseudonym_len;
-	} else
-		identity = eap_get_config_identity(sm, &identity_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
-			  "derivation", identity, identity_len);
-	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
-			  data->selected_version, data->ver_list,
-			  data->ver_list_len, data->num_chal,
-			  (const u8 *) data->kc, data->mk);
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
-			       EAP_SIM_NONCE_MT_LEN)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
-			   "used invalid AT_MAC");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
-
-	if (attr->encr_data) {
-		u8 *decrypted;
-		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-					       attr->encr_data_len, attr->iv,
-					       &eattr, 0);
-		if (decrypted == NULL) {
-			return eap_sim_client_error(
-				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-		}
-		eap_sim_learn_ids(data, &eattr);
-		os_free(decrypted);
-	}
-
-	if (data->result_ind && attr->result_ind)
-		data->use_result_ind = 1;
-
-	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
-		eap_sim_state(data, data->use_result_ind ?
-			      RESULT_SUCCESS : SUCCESS);
-	}
-
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	/* RFC 4186 specifies that counter is initialized to one after
-	 * fullauth, but initializing it to zero makes it easier to implement
-	 * reauth verification. */
-	data->counter = 0;
-	return eap_sim_response_challenge(data, id);
-}
-
-
-static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
-					       struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted;
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
-			   "reauth did not include encrypted data");
-		return -1;
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
-			   "data from notification message");
-		return -1;
-	}
-
-	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
-			   "message does not match with counter in reauth "
-			   "message");
-		os_free(decrypted);
-		return -1;
-	}
-
-	os_free(decrypted);
-	return 0;
-}
-
-
-static int eap_sim_process_notification_auth(struct eap_sim_data *data,
-					     const struct wpabuf *reqData,
-					     struct eap_sim_attrs *attr)
-{
-	if (attr->mac == NULL) {
-		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
-			   "Notification message");
-		return -1;
-	}
-
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
-	{
-		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
-			   "used invalid AT_MAC");
-		return -1;
-	}
-
-	if (data->reauth &&
-	    eap_sim_process_notification_reauth(data, attr)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
-			   "message after reauth");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_sim_process_notification(
-	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
-	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
-	if (data->num_notification > 0) {
-		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
-			   "rounds (only one allowed)");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-	data->num_notification++;
-	if (attr->notification == -1) {
-		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
-			   "Notification message");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if ((attr->notification & 0x4000) == 0 &&
-	    eap_sim_process_notification_auth(data, reqData, attr)) {
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
-	if (attr->notification >= 0 && attr->notification < 32768) {
-		eap_sim_state(data, FAILURE);
-	} else if (attr->notification == EAP_SIM_SUCCESS &&
-		   data->state == RESULT_SUCCESS)
-		eap_sim_state(data, SUCCESS);
-	return eap_sim_response_notification(data, id, attr->notification);
-}
-
-
-static struct wpabuf * eap_sim_process_reauthentication(
-	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
-	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
-
-	if (data->reauth_id == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
-			   "reauthentication, but no reauth_id available");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	data->reauth = 1;
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
-	{
-		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
-			   "did not have valid AT_MAC");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
-			   "message did not include encrypted data");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
-			   "data from reauthentication message");
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (eattr.nonce_s == NULL || eattr.counter < 0) {
-		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
-			   !eattr.nonce_s ? " AT_NONCE_S" : "",
-			   eattr.counter < 0 ? " AT_COUNTER" : "");
-		os_free(decrypted);
-		return eap_sim_client_error(data, id,
-					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-	}
-
-	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
-		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
-			   "(%d <= %d)", eattr.counter, data->counter);
-		data->counter_too_small = eattr.counter;
-		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
-		 * reauth_id must not be used to start a new reauthentication.
-		 * However, since it was used in the last EAP-Response-Identity
-		 * packet, it has to saved for the following fullauth to be
-		 * used in MK derivation. */
-		os_free(data->last_eap_identity);
-		data->last_eap_identity = data->reauth_id;
-		data->last_eap_identity_len = data->reauth_id_len;
-		data->reauth_id = NULL;
-		data->reauth_id_len = 0;
-		os_free(decrypted);
-		return eap_sim_response_reauth(data, id, 1);
-	}
-	data->counter = eattr.counter;
-
-	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
-		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
-
-	eap_sim_derive_keys_reauth(data->counter,
-				   data->reauth_id, data->reauth_id_len,
-				   data->nonce_s, data->mk, data->msk,
-				   data->emsk);
-	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
-	eap_sim_learn_ids(data, &eattr);
-
-	if (data->result_ind && attr->result_ind)
-		data->use_result_ind = 1;
-
-	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
-		eap_sim_state(data, data->use_result_ind ?
-			      RESULT_SUCCESS : SUCCESS);
-	}
-
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
-			   "fast reauths performed - force fullauth");
-		eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
-	}
-	os_free(decrypted);
-	return eap_sim_response_reauth(data, id, 0);
-}
-
-
-static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_sim_data *data = priv;
-	const struct eap_hdr *req;
-	u8 subtype, id;
-	struct wpabuf *res;
-	const u8 *pos;
-	struct eap_sim_attrs attr;
-	size_t len;
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
-	if (eap_get_config_identity(sm, &len) == NULL) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
-		eap_sm_request_identity(sm);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
-	if (pos == NULL || len < 1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-	req = wpabuf_head(reqData);
-	id = req->identifier;
-	len = be_to_host16(req->length);
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-	ret->allowNotifications = TRUE;
-
-	subtype = *pos++;
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
-	pos += 2; /* Reserved */
-
-	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
-			       0)) {
-		res = eap_sim_client_error(data, id,
-					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-		goto done;
-	}
-
-	switch (subtype) {
-	case EAP_SIM_SUBTYPE_START:
-		res = eap_sim_process_start(sm, data, id, &attr);
-		break;
-	case EAP_SIM_SUBTYPE_CHALLENGE:
-		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
-		break;
-	case EAP_SIM_SUBTYPE_NOTIFICATION:
-		res = eap_sim_process_notification(sm, data, id, reqData,
-						   &attr);
-		break;
-	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
-		res = eap_sim_process_reauthentication(sm, data, id, reqData,
-						       &attr);
-		break;
-	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
-		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
-		res = eap_sim_client_error(data, id,
-					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
-		res = eap_sim_client_error(data, id,
-					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
-		break;
-	}
-
-done:
-	if (data->state == FAILURE) {
-		ret->decision = DECISION_FAIL;
-		ret->methodState = METHOD_DONE;
-	} else if (data->state == SUCCESS) {
-		ret->decision = data->use_result_ind ?
-			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
-		ret->methodState = data->use_result_ind ?
-			METHOD_DONE : METHOD_MAY_CONT;
-	} else if (data->state == RESULT_FAILURE)
-		ret->methodState = METHOD_CONT;
-	else if (data->state == RESULT_SUCCESS)
-		ret->methodState = METHOD_CONT;
-
-	if (ret->methodState == METHOD_DONE) {
-		ret->allowNotifications = FALSE;
-	}
-
-	return res;
-}
-
-
-static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	return data->pseudonym || data->reauth_id;
-}
-
-
-static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	eap_sim_clear_identities(data, CLEAR_EAP_ID);
-	data->use_result_ind = 0;
-}
-
-
-static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	if (os_get_random(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);
-		return NULL;
-	}
-	data->num_id_req = 0;
-	data->num_notification = 0;
-	eap_sim_state(data, CONTINUE);
-	return priv;
-}
-
-
-static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
-				       size_t *len)
-{
-	struct eap_sim_data *data = priv;
-
-	if (data->reauth_id) {
-		*len = data->reauth_id_len;
-		return data->reauth_id;
-	}
-
-	if (data->pseudonym) {
-		*len = data->pseudonym_len;
-		return data->pseudonym;
-	}
-
-	return NULL;
-}
-
-
-static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sim_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_SIM_KEYING_DATA_LEN;
-	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
-
-	return key;
-}
-
-
-static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sim_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-
-	*len = EAP_EMSK_LEN;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-
-	return key;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_sim_init;
-	eap->deinit = eap_sim_deinit;
-	eap->process = eap_sim_process;
-	eap->isKeyAvailable = eap_sim_isKeyAvailable;
-	eap->getKey = eap_sim_getKey;
-	eap->has_reauth_data = eap_sim_has_reauth_data;
-	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
-	eap->init_for_reauth = eap_sim_init_for_reauth;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_sim.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_sim.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_sim.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_sim.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1131 @@
+/*
+ * EAP peer method: EAP-SIM (RFC 4186)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "pcsc_funcs.h"
+#include "crypto/milenage.h"
+#include "crypto/random.h"
+#include "eap_peer/eap_i.h"
+#include "eap_config.h"
+#include "eap_common/eap_sim_common.h"
+
+
+struct eap_sim_data {
+	u8 *ver_list;
+	size_t ver_list_len;
+	int selected_version;
+	size_t min_num_chal, num_chal;
+
+	u8 kc[3][EAP_SIM_KC_LEN];
+	u8 sres[3][EAP_SIM_SRES_LEN];
+	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
+	u8 mk[EAP_SIM_MK_LEN];
+	u8 k_aut[EAP_SIM_K_AUT_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 msk[EAP_SIM_KEYING_DATA_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 rand[3][GSM_RAND_LEN];
+
+	int num_id_req, num_notification;
+	u8 *pseudonym;
+	size_t pseudonym_len;
+	u8 *reauth_id;
+	size_t reauth_id_len;
+	int reauth;
+	unsigned int counter, counter_too_small;
+	u8 *last_eap_identity;
+	size_t last_eap_identity_len;
+	enum {
+		CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+	} state;
+	int result_ind, use_result_ind;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_sim_state_txt(int state)
+{
+	switch (state) {
+	case CONTINUE:
+		return "CONTINUE";
+	case RESULT_SUCCESS:
+		return "RESULT_SUCCESS";
+	case RESULT_FAILURE:
+		return "RESULT_FAILURE";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_sim_state(struct eap_sim_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
+		   eap_sim_state_txt(data->state),
+		   eap_sim_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_sim_init(struct eap_sm *sm)
+{
+	struct eap_sim_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	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);
+		return NULL;
+	}
+
+	data->min_num_chal = 2;
+	if (config && config->phase1) {
+		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
+		if (pos) {
+			data->min_num_chal = atoi(pos + 17);
+			if (data->min_num_chal < 2 || data->min_num_chal > 3) {
+				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
+					   "sim_min_num_chal configuration "
+					   "(%lu, expected 2 or 3)",
+					   (unsigned long) data->min_num_chal);
+				os_free(data);
+				return NULL;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
+				   "challenges to %lu",
+				   (unsigned long) data->min_num_chal);
+		}
+
+		data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
+			NULL;
+	}
+
+	if (config && config->anonymous_identity) {
+		data->pseudonym = os_malloc(config->anonymous_identity_len);
+		if (data->pseudonym) {
+			os_memcpy(data->pseudonym, config->anonymous_identity,
+				  config->anonymous_identity_len);
+			data->pseudonym_len = config->anonymous_identity_len;
+		}
+	}
+
+	eap_sim_state(data, CONTINUE);
+
+	return data;
+}
+
+
+static void eap_sim_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	if (data) {
+		os_free(data->ver_list);
+		os_free(data->pseudonym);
+		os_free(data->reauth_id);
+		os_free(data->last_eap_identity);
+		os_free(data);
+	}
+}
+
+
+static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
+{
+	struct eap_peer_config *conf;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
+
+	conf = eap_get_config(sm);
+	if (conf == NULL)
+		return -1;
+	if (conf->pcsc) {
+		if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
+				   data->sres[0], data->kc[0]) ||
+		    scard_gsm_auth(sm->scard_ctx, data->rand[1],
+				   data->sres[1], data->kc[1]) ||
+		    (data->num_chal > 2 &&
+		     scard_gsm_auth(sm->scard_ctx, data->rand[2],
+				    data->sres[2], data->kc[2]))) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
+				   "authentication could not be completed");
+			return -1;
+		}
+		return 0;
+	}
+
+#ifdef CONFIG_SIM_SIMULATOR
+	if (conf->password) {
+		u8 opc[16], k[16];
+		const char *pos;
+		size_t i;
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
+			   "implementation for authentication");
+		if (conf->password_len < 65) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
+				   "password");
+			return -1;
+		}
+		pos = (const char *) conf->password;
+		if (hexstr2bin(pos, k, 16))
+			return -1;
+		pos += 32;
+		if (*pos != ':')
+			return -1;
+		pos++;
+
+		if (hexstr2bin(pos, opc, 16))
+			return -1;
+
+		for (i = 0; i < data->num_chal; i++) {
+			if (gsm_milenage(opc, k, data->rand[i],
+					 data->sres[i], data->kc[i])) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: "
+					   "GSM-Milenage authentication "
+					   "could not be completed");
+				return -1;
+			}
+			wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
+				    data->rand[i], GSM_RAND_LEN);
+			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
+					data->sres[i], EAP_SIM_SRES_LEN);
+			wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
+					data->kc[i], EAP_SIM_KC_LEN);
+		}
+		return 0;
+	}
+#endif /* CONFIG_SIM_SIMULATOR */
+
+#ifdef CONFIG_SIM_HARDCODED
+	/* These hardcoded Kc and SRES values are used for testing. RAND to
+	 * KC/SREC mapping is very bogus as far as real authentication is
+	 * concerned, but it is quite useful for cases where the AS is rotating
+	 * the order of pre-configured values. */
+	{
+		size_t i;
+
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
+			   "values for testing");
+
+		for (i = 0; i < data->num_chal; i++) {
+			if (data->rand[i][0] == 0xaa) {
+				os_memcpy(data->kc[i],
+					  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
+					  EAP_SIM_KC_LEN);
+				os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
+					  EAP_SIM_SRES_LEN);
+			} else if (data->rand[i][0] == 0xbb) {
+				os_memcpy(data->kc[i],
+					  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
+					  EAP_SIM_KC_LEN);
+				os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
+					  EAP_SIM_SRES_LEN);
+			} else {
+				os_memcpy(data->kc[i],
+					  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
+					  EAP_SIM_KC_LEN);
+				os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
+					  EAP_SIM_SRES_LEN);
+			}
+		}
+	}
+
+	return 0;
+
+#else /* CONFIG_SIM_HARDCODED */
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
+		   "enabled");
+	return -1;
+
+#endif /* CONFIG_SIM_HARDCODED */
+}
+
+
+static int eap_sim_supported_ver(int version)
+{
+	return version == EAP_SIM_VERSION;
+}
+
+
+#define CLEAR_PSEUDONYM	0x01
+#define CLEAR_REAUTH_ID	0x02
+#define CLEAR_EAP_ID	0x04
+
+static void eap_sim_clear_identities(struct eap_sm *sm,
+				     struct eap_sim_data *data, int id)
+{
+	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
+		os_free(data->pseudonym);
+		data->pseudonym = NULL;
+		data->pseudonym_len = 0;
+		eap_set_anon_id(sm, NULL, 0);
+	}
+	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
+		os_free(data->reauth_id);
+		data->reauth_id = NULL;
+		data->reauth_id_len = 0;
+	}
+	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
+		os_free(data->last_eap_identity);
+		data->last_eap_identity = NULL;
+		data->last_eap_identity_len = 0;
+	}
+}
+
+
+static int eap_sim_learn_ids(struct eap_sm *sm, struct eap_sim_data *data,
+			     struct eap_sim_attrs *attr)
+{
+	if (attr->next_pseudonym) {
+		const u8 *identity = NULL;
+		size_t identity_len = 0;
+		const u8 *realm = NULL;
+		size_t realm_len = 0;
+
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
+				  attr->next_pseudonym,
+				  attr->next_pseudonym_len);
+		os_free(data->pseudonym);
+		/* Look for the realm of the permanent identity */
+		identity = eap_get_config_identity(sm, &identity_len);
+		if (identity) {
+			for (realm = identity, realm_len = identity_len;
+			     realm_len > 0; realm_len--, realm++) {
+				if (*realm == '@')
+					break;
+			}
+		}
+		data->pseudonym = os_malloc(attr->next_pseudonym_len +
+					    realm_len);
+		if (data->pseudonym == NULL) {
+			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
+				   "next pseudonym");
+			data->pseudonym_len = 0;
+			return -1;
+		}
+		os_memcpy(data->pseudonym, attr->next_pseudonym,
+			  attr->next_pseudonym_len);
+		if (realm_len) {
+			os_memcpy(data->pseudonym + attr->next_pseudonym_len,
+				  realm, realm_len);
+		}
+		data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+		eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+	}
+
+	if (attr->next_reauth_id) {
+		os_free(data->reauth_id);
+		data->reauth_id = os_malloc(attr->next_reauth_id_len);
+		if (data->reauth_id == NULL) {
+			wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
+				   "next reauth_id");
+			data->reauth_id_len = 0;
+			return -1;
+		}
+		os_memcpy(data->reauth_id, attr->next_reauth_id,
+			  attr->next_reauth_id_len);
+		data->reauth_id_len = attr->next_reauth_id_len;
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
+				  data->reauth_id,
+				  data->reauth_id_len);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
+					    int err)
+{
+	struct eap_sim_msg *msg;
+
+	eap_sim_state(data, FAILURE);
+	data->num_id_req = 0;
+	data->num_notification = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
+		   err);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_CLIENT_ERROR);
+	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
+					      struct eap_sim_data *data, u8 id,
+					      enum eap_sim_id_req id_req)
+{
+	const u8 *identity = NULL;
+	size_t identity_len = 0;
+	struct eap_sim_msg *msg;
+
+	data->reauth = 0;
+	if (id_req == ANY_ID && data->reauth_id) {
+		identity = data->reauth_id;
+		identity_len = data->reauth_id_len;
+		data->reauth = 1;
+	} else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
+		   data->pseudonym) {
+		identity = data->pseudonym;
+		identity_len = data->pseudonym_len;
+		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
+	} else if (id_req != NO_ID_REQ) {
+		identity = eap_get_config_identity(sm, &identity_len);
+		if (identity) {
+			eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
+						 CLEAR_REAUTH_ID);
+		}
+	}
+	if (id_req != NO_ID_REQ)
+		eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
+			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
+	if (!data->reauth) {
+		wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
+			    data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
+				data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+		wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
+			   data->selected_version);
+		eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
+				data->selected_version, NULL, 0);
+	}
+
+	if (identity) {
+		wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
+				  identity, identity_len);
+		eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
+				identity, identity_len);
+	}
+
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
+						  u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_CHALLENGE);
+	if (data->use_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
+				  data->num_chal * EAP_SIM_SRES_LEN);
+}
+
+
+static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
+					       u8 id, int counter_too_small,
+					       const u8 *nonce_s)
+{
+	struct eap_sim_msg *msg;
+	unsigned int counter;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
+		   id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter_too_small) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
+		counter = data->counter_too_small;
+	} else
+		counter = data->counter;
+
+	wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
+	eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+	if (data->use_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+				  EAP_SIM_NONCE_S_LEN);
+}
+
+
+static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
+						     u8 id, u16 notification)
+{
+	struct eap_sim_msg *msg;
+	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
+
+	wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
+			       EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
+	if (k_aut && data->reauth) {
+		wpa_printf(MSG_DEBUG, "   AT_IV");
+		wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+		eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+					   EAP_SIM_AT_ENCR_DATA);
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+				NULL, 0);
+		if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+					     EAP_SIM_AT_PADDING)) {
+			wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+				   "AT_ENCR_DATA");
+			eap_sim_msg_free(msg);
+			return NULL;
+		}
+	}
+	if (k_aut) {
+		wpa_printf(MSG_DEBUG, "   AT_MAC");
+		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	}
+	return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+}
+
+
+static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
+					     struct eap_sim_data *data, u8 id,
+					     struct eap_sim_attrs *attr)
+{
+	int selected_version = -1, id_error;
+	size_t i;
+	u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
+	if (attr->version_list == NULL) {
+		wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
+			   "SIM/Start");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNSUPPORTED_VERSION);
+	}
+
+	os_free(data->ver_list);
+	data->ver_list = os_malloc(attr->version_list_len);
+	if (data->ver_list == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
+			   "memory for version list");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+	os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
+	data->ver_list_len = attr->version_list_len;
+	pos = data->ver_list;
+	for (i = 0; i < data->ver_list_len / 2; i++) {
+		int ver = pos[0] * 256 + pos[1];
+		pos += 2;
+		if (eap_sim_supported_ver(ver)) {
+			selected_version = ver;
+			break;
+		}
+	}
+	if (selected_version < 0) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
+			   "version");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNSUPPORTED_VERSION);
+	}
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
+		   selected_version);
+	data->selected_version = selected_version;
+
+	id_error = 0;
+	switch (attr->id_req) {
+	case NO_ID_REQ:
+		break;
+	case ANY_ID:
+		if (data->num_id_req > 0)
+			id_error++;
+		data->num_id_req++;
+		break;
+	case FULLAUTH_ID:
+		if (data->num_id_req > 1)
+			id_error++;
+		data->num_id_req++;
+		break;
+	case PERMANENT_ID:
+		if (data->num_id_req > 2)
+			id_error++;
+		data->num_id_req++;
+		break;
+	}
+	if (id_error) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
+			   "used within one authentication");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	return eap_sim_response_start(sm, data, id, attr->id_req);
+}
+
+
+static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
+						 struct eap_sim_data *data,
+						 u8 id,
+						 const struct wpabuf *reqData,
+						 struct eap_sim_attrs *attr)
+{
+	const u8 *identity;
+	size_t identity_len;
+	struct eap_sim_attrs eattr;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
+	data->reauth = 0;
+	if (!attr->mac || !attr->rand) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+			   "did not include%s%s",
+			   !attr->mac ? " AT_MAC" : "",
+			   !attr->rand ? " AT_RAND" : "");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
+		   (unsigned long) attr->num_chal);
+	if (attr->num_chal < data->min_num_chal) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
+			   "challenges (%lu)", (unsigned long) attr->num_chal);
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
+	}
+	if (attr->num_chal > 3) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
+			   "(%lu)", (unsigned long) attr->num_chal);
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	/* Verify that RANDs are different */
+	if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
+		   GSM_RAND_LEN) == 0 ||
+	    (attr->num_chal > 2 &&
+	     (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
+			GSM_RAND_LEN) == 0 ||
+	      os_memcmp(attr->rand + GSM_RAND_LEN,
+			attr->rand + 2 * GSM_RAND_LEN,
+			GSM_RAND_LEN) == 0))) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_RAND_NOT_FRESH);
+	}
+
+	os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
+	data->num_chal = attr->num_chal;
+		
+	if (eap_sim_gsm_auth(sm, data)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+	if (data->last_eap_identity) {
+		identity = data->last_eap_identity;
+		identity_len = data->last_eap_identity_len;
+	} else if (data->pseudonym) {
+		identity = data->pseudonym;
+		identity_len = data->pseudonym_len;
+	} else
+		identity = eap_get_config_identity(sm, &identity_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
+			  "derivation", identity, identity_len);
+	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
+			  data->selected_version, data->ver_list,
+			  data->ver_list_len, data->num_chal,
+			  (const u8 *) data->kc, data->mk);
+	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+			    data->emsk);
+	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
+			       EAP_SIM_NONCE_MT_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+			   "used invalid AT_MAC");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new reauth identity is received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+
+	if (attr->encr_data) {
+		u8 *decrypted;
+		decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+					       attr->encr_data_len, attr->iv,
+					       &eattr, 0);
+		if (decrypted == NULL) {
+			return eap_sim_client_error(
+				data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		}
+		eap_sim_learn_ids(sm, data, &eattr);
+		os_free(decrypted);
+	}
+
+	if (data->result_ind && attr->result_ind)
+		data->use_result_ind = 1;
+
+	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+		eap_sim_state(data, data->use_result_ind ?
+			      RESULT_SUCCESS : SUCCESS);
+	}
+
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	/* RFC 4186 specifies that counter is initialized to one after
+	 * fullauth, but initializing it to zero makes it easier to implement
+	 * reauth verification. */
+	data->counter = 0;
+	return eap_sim_response_challenge(data, id);
+}
+
+
+static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
+					       struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted;
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
+			   "reauth did not include encrypted data");
+		return -1;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+			   "data from notification message");
+		return -1;
+	}
+
+	if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
+			   "message does not match with counter in reauth "
+			   "message");
+		os_free(decrypted);
+		return -1;
+	}
+
+	os_free(decrypted);
+	return 0;
+}
+
+
+static int eap_sim_process_notification_auth(struct eap_sim_data *data,
+					     const struct wpabuf *reqData,
+					     struct eap_sim_attrs *attr)
+{
+	if (attr->mac == NULL) {
+		wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
+			   "Notification message");
+		return -1;
+	}
+
+	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
+	{
+		wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
+			   "used invalid AT_MAC");
+		return -1;
+	}
+
+	if (data->reauth &&
+	    eap_sim_process_notification_reauth(data, attr)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
+			   "message after reauth");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_sim_process_notification(
+	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
+	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
+	if (data->num_notification > 0) {
+		wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
+			   "rounds (only one allowed)");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+	data->num_notification++;
+	if (attr->notification == -1) {
+		wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
+			   "Notification message");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if ((attr->notification & 0x4000) == 0 &&
+	    eap_sim_process_notification_auth(data, reqData, attr)) {
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
+	if (attr->notification >= 0 && attr->notification < 32768) {
+		eap_sim_state(data, FAILURE);
+	} else if (attr->notification == EAP_SIM_SUCCESS &&
+		   data->state == RESULT_SUCCESS)
+		eap_sim_state(data, SUCCESS);
+	return eap_sim_response_notification(data, id, attr->notification);
+}
+
+
+static struct wpabuf * eap_sim_process_reauthentication(
+	struct eap_sm *sm, struct eap_sim_data *data, u8 id,
+	const struct wpabuf *reqData, struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
+
+	if (data->reauth_id == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
+			   "reauthentication, but no reauth_id available");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	data->reauth = 1;
+	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
+	{
+		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+			   "did not have valid AT_MAC");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+			   "message did not include encrypted data");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+			   "data from reauthentication message");
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (eattr.nonce_s == NULL || eattr.counter < 0) {
+		wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
+			   !eattr.nonce_s ? " AT_NONCE_S" : "",
+			   eattr.counter < 0 ? " AT_COUNTER" : "");
+		os_free(decrypted);
+		return eap_sim_client_error(data, id,
+					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+	}
+
+	if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
+		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
+			   "(%d <= %d)", eattr.counter, data->counter);
+		data->counter_too_small = eattr.counter;
+		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
+		 * reauth_id must not be used to start a new reauthentication.
+		 * However, since it was used in the last EAP-Response-Identity
+		 * packet, it has to saved for the following fullauth to be
+		 * used in MK derivation. */
+		os_free(data->last_eap_identity);
+		data->last_eap_identity = data->reauth_id;
+		data->last_eap_identity_len = data->reauth_id_len;
+		data->reauth_id = NULL;
+		data->reauth_id_len = 0;
+		os_free(decrypted);
+		return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
+	}
+	data->counter = eattr.counter;
+
+	os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
+		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	eap_sim_derive_keys_reauth(data->counter,
+				   data->reauth_id, data->reauth_id_len,
+				   data->nonce_s, data->mk, data->msk,
+				   data->emsk);
+	eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+	eap_sim_learn_ids(sm, data, &eattr);
+
+	if (data->result_ind && attr->result_ind)
+		data->use_result_ind = 1;
+
+	if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+		eap_sim_state(data, data->use_result_ind ?
+			      RESULT_SUCCESS : SUCCESS);
+	}
+
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
+			   "fast reauths performed - force fullauth");
+		eap_sim_clear_identities(sm, data,
+					 CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+	}
+	os_free(decrypted);
+	return eap_sim_response_reauth(data, id, 0, data->nonce_s);
+}
+
+
+static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_sim_data *data = priv;
+	const struct eap_hdr *req;
+	u8 subtype, id;
+	struct wpabuf *res;
+	const u8 *pos;
+	struct eap_sim_attrs attr;
+	size_t len;
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
+	if (eap_get_config_identity(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
+		eap_sm_request_identity(sm);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	req = wpabuf_head(reqData);
+	id = req->identifier;
+	len = be_to_host16(req->length);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	subtype = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
+	pos += 2; /* Reserved */
+
+	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
+			       0)) {
+		res = eap_sim_client_error(data, id,
+					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		goto done;
+	}
+
+	switch (subtype) {
+	case EAP_SIM_SUBTYPE_START:
+		res = eap_sim_process_start(sm, data, id, &attr);
+		break;
+	case EAP_SIM_SUBTYPE_CHALLENGE:
+		res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
+		break;
+	case EAP_SIM_SUBTYPE_NOTIFICATION:
+		res = eap_sim_process_notification(sm, data, id, reqData,
+						   &attr);
+		break;
+	case EAP_SIM_SUBTYPE_REAUTHENTICATION:
+		res = eap_sim_process_reauthentication(sm, data, id, reqData,
+						       &attr);
+		break;
+	case EAP_SIM_SUBTYPE_CLIENT_ERROR:
+		wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
+		res = eap_sim_client_error(data, id,
+					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
+		res = eap_sim_client_error(data, id,
+					   EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		break;
+	}
+
+done:
+	if (data->state == FAILURE) {
+		ret->decision = DECISION_FAIL;
+		ret->methodState = METHOD_DONE;
+	} else if (data->state == SUCCESS) {
+		ret->decision = data->use_result_ind ?
+			DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
+		ret->methodState = data->use_result_ind ?
+			METHOD_DONE : METHOD_MAY_CONT;
+	} else if (data->state == RESULT_FAILURE)
+		ret->methodState = METHOD_CONT;
+	else if (data->state == RESULT_SUCCESS)
+		ret->methodState = METHOD_CONT;
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	return res;
+}
+
+
+static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	return data->pseudonym || data->reauth_id;
+}
+
+
+static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
+	data->use_result_ind = 0;
+}
+
+
+static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
+			   "for NONCE_MT");
+		os_free(data);
+		return NULL;
+	}
+	data->num_id_req = 0;
+	data->num_notification = 0;
+	eap_sim_state(data, CONTINUE);
+	return priv;
+}
+
+
+static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
+				       size_t *len)
+{
+	struct eap_sim_data *data = priv;
+
+	if (data->reauth_id) {
+		*len = data->reauth_id_len;
+		return data->reauth_id;
+	}
+
+	if (data->pseudonym) {
+		*len = data->pseudonym_len;
+		return data->pseudonym;
+	}
+
+	return NULL;
+}
+
+
+static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_SIM_KEYING_DATA_LEN;
+	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+
+	return key;
+}
+
+
+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sim_init;
+	eap->deinit = eap_sim_deinit;
+	eap->process = eap_sim_process;
+	eap->isKeyAvailable = eap_sim_isKeyAvailable;
+	eap->getKey = eap_sim_getKey;
+	eap->has_reauth_data = eap_sim_has_reauth_data;
+	eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
+	eap->init_for_reauth = eap_sim_init_for_reauth;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_tls.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_tls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,289 +0,0 @@
-/*
- * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/tls.h"
-#include "eap_i.h"
-#include "eap_tls_common.h"
-#include "eap_config.h"
-
-
-static void eap_tls_deinit(struct eap_sm *sm, void *priv);
-
-
-struct eap_tls_data {
-	struct eap_ssl_data ssl;
-	u8 *key_data;
-};
-
-
-static void * eap_tls_init(struct eap_sm *sm)
-{
-	struct eap_tls_data *data;
-	struct eap_peer_config *config = eap_get_config(sm);
-	if (config == NULL ||
-	    ((sm->init_phase2 ? config->private_key2 : config->private_key)
-	     == NULL &&
-	     (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
-		wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
-		eap_tls_deinit(sm, data);
-		if (config->engine) {
-			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
-				   "PIN");
-			eap_sm_request_pin(sm);
-			sm->ignore = TRUE;
-		} else if (config->private_key && !config->private_key_passwd)
-		{
-			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
-				   "key passphrase");
-			eap_sm_request_passphrase(sm);
-			sm->ignore = TRUE;
-		}
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_tls_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	if (data == NULL)
-		return;
-	eap_peer_tls_ssl_deinit(sm, &data->ssl);
-	os_free(data->key_data);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
-				       struct eap_tls_data *data,
-				       struct eap_method_ret *ret, int res,
-				       struct wpabuf *resp, u8 id)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
-
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_FAIL;
-
-	if (res == -1) {
-		struct eap_peer_config *config = eap_get_config(sm);
-		if (config) {
-			/*
-			 * The TLS handshake failed. So better forget the old
-			 * PIN. It may be wrong, we cannot be sure but trying
-			 * the wrong one again might block it on the card--so
-			 * better ask the user again.
-			 */
-			os_free(config->pin);
-			config->pin = NULL;
-		}
-	}
-
-	if (resp) {
-		/*
-		 * This is likely an alert message, so send it instead of just
-		 * ACKing the error.
-		 */
-		return resp;
-	}
-
-	return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
-}
-
-
-static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
-			    struct eap_method_ret *ret)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
-
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-
-	os_free(data->key_data);
-	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
-						 "client EAP encryption",
-						 EAP_TLS_KEY_LEN +
-						 EAP_EMSK_LEN);
-	if (data->key_data) {
-		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
-				data->key_data, EAP_TLS_KEY_LEN);
-		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
-				data->key_data + EAP_TLS_KEY_LEN,
-				EAP_EMSK_LEN);
-	} else {
-		wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
-	}
-}
-
-
-static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	size_t left;
-	int res;
-	struct wpabuf *resp;
-	u8 flags, id;
-	const u8 *pos;
-	struct eap_tls_data *data = priv;
-
-	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, 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-TLS: Start");
-		left = 0; /* make sure that this frame is empty, even though it
-			   * should always be, anyway */
-	}
-
-	resp = NULL;
-	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
-					  pos, left, &resp);
-
-	if (res < 0) {
-		return eap_tls_failure(sm, data, ret, res, resp, id);
-	}
-
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
-		eap_tls_success(sm, data, ret);
-
-	if (res == 1) {
-		wpabuf_free(resp);
-		return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
-}
-
-
-static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
-{
-}
-
-
-static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	os_free(data->key_data);
-	data->key_data = NULL;
-	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
-		os_free(data);
-		return NULL;
-	}
-	return priv;
-}
-
-
-static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
-			      size_t buflen, int verbose)
-{
-	struct eap_tls_data *data = priv;
-	return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
-}
-
-
-static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	return data->key_data != NULL;
-}
-
-
-static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_tls_data *data = priv;
-	u8 *key;
-
-	if (data->key_data == NULL)
-		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_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_tls_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_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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_tls_init;
-	eap->deinit = eap_tls_deinit;
-	eap->process = eap_tls_process;
-	eap->isKeyAvailable = eap_tls_isKeyAvailable;
-	eap->getKey = eap_tls_getKey;
-	eap->get_status = eap_tls_get_status;
-	eap->has_reauth_data = eap_tls_has_reauth_data;
-	eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_tls.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_tls.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_tls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,348 @@
+/*
+ * EAP peer method: EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_tls_data {
+	struct eap_ssl_data ssl;
+	u8 *key_data;
+	void *ssl_ctx;
+	u8 eap_type;
+};
+
+
+static void * eap_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL ||
+	    ((sm->init_phase2 ? config->private_key2 : config->private_key)
+	     == NULL &&
+	     (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_deinit(sm, data);
+		if (config->engine) {
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
+				   "PIN");
+			eap_sm_request_pin(sm);
+			sm->ignore = TRUE;
+		} else if (config->private_key && !config->private_key_passwd)
+		{
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
+				   "key passphrase");
+			eap_sm_request_passphrase(sm);
+			sm->ignore = TRUE;
+		}
+		return NULL;
+	}
+
+	data->eap_type = EAP_TYPE_TLS;
+
+	return data;
+}
+
+
+#ifdef EAP_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
+				  EAP_UNAUTH_TLS_TYPE)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_deinit(sm, data);
+		return NULL;
+	}
+
+	data->eap_type = EAP_UNAUTH_TLS_TYPE;
+
+	return data;
+}
+#endif /* EAP_UNAUTH_TLS */
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	if (data == NULL)
+		return;
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->key_data);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
+				       struct eap_tls_data *data,
+				       struct eap_method_ret *ret, int res,
+				       struct wpabuf *resp, u8 id)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+
+	if (res == -1) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (config) {
+			/*
+			 * The TLS handshake failed. So better forget the old
+			 * PIN. It may be wrong, we cannot be sure but trying
+			 * the wrong one again might block it on the card--so
+			 * better ask the user again.
+			 */
+			os_free(config->pin);
+			config->pin = NULL;
+		}
+	}
+
+	if (resp) {
+		/*
+		 * This is likely an alert message, so send it instead of just
+		 * ACKing the error.
+		 */
+		return resp;
+	}
+
+	return eap_peer_tls_build_ack(id, data->eap_type, 0);
+}
+
+
+static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
+			    struct eap_method_ret *ret)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+
+	os_free(data->key_data);
+	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
+						 "client EAP encryption",
+						 EAP_TLS_KEY_LEN +
+						 EAP_EMSK_LEN);
+	if (data->key_data) {
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
+				data->key_data, EAP_TLS_KEY_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
+				data->key_data + EAP_TLS_KEY_LEN,
+				EAP_EMSK_LEN);
+	} else {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
+	}
+}
+
+
+static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	size_t left;
+	int res;
+	struct wpabuf *resp;
+	u8 flags, id;
+	const u8 *pos;
+	struct eap_tls_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, 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-TLS: Start");
+		left = 0; /* make sure that this frame is empty, even though it
+			   * should always be, anyway */
+	}
+
+	resp = NULL;
+	res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
+					  id, pos, left, &resp);
+
+	if (res < 0) {
+		return eap_tls_failure(sm, data, ret, res, resp, id);
+	}
+
+	if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
+		eap_tls_success(sm, data, ret);
+
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, data->eap_type, 0);
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return tls_connection_established(data->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	os_free(data->key_data);
+	data->key_data = NULL;
+	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
+		os_free(data);
+		return NULL;
+	}
+	return priv;
+}
+
+
+static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
+			      size_t buflen, int verbose)
+{
+	struct eap_tls_data *data = priv;
+	return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+}
+
+
+static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return data->key_data != NULL;
+}
+
+
+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL)
+		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_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_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_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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tls_init;
+	eap->deinit = eap_tls_deinit;
+	eap->process = eap_tls_process;
+	eap->isKeyAvailable = eap_tls_isKeyAvailable;
+	eap->getKey = eap_tls_getKey;
+	eap->get_status = eap_tls_get_status;
+	eap->has_reauth_data = eap_tls_has_reauth_data;
+	eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+	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;
+}
+
+
+#ifdef EAP_UNAUTH_TLS
+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_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_unauth_tls_init;
+	eap->deinit = eap_tls_deinit;
+	eap->process = eap_tls_process;
+	eap->isKeyAvailable = eap_tls_isKeyAvailable;
+	eap->getKey = eap_tls_getKey;
+	eap->get_status = eap_tls_get_status;
+	eap->has_reauth_data = eap_tls_has_reauth_data;
+	eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+	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;
+}
+#endif /* EAP_UNAUTH_TLS */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_tls_common.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_tls_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1020 +0,0 @@
-/*
- * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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 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;
-}
-
-
-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->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);
-}
-
-
-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->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);
-}
-
-
-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 (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);
-	}
-	params->tls_ia = data->tls_ia;
-
-	/*
-	 * 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;
-	}
-
-	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;
-
-	data->conn = tls_connection_init(sm->ssl_ctx);
-	if (data->conn == NULL) {
-		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
-			   "connection");
-		return -1;
-	}
-
-	res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
-	if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
-		/*
-		 * At this point with the pkcs11 engine the PIN might be 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.
-		 */
-		os_free(config->pin);
-		config->pin = NULL;
-	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
-		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
-		/*
-		 * We do not know exactly but maybe the PIN was wrong,
-		 * so ask for a new one.
-		 */
-		os_free(config->pin);
-		config->pin = NULL;
-		eap_sm_request_pin(sm);
-		sm->ignore = TRUE;
-		tls_connection_deinit(sm->ssl_ctx, data->conn);
-		data->conn = NULL;
-		return -1;
-	} else if (res) {
-		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
-			   "parameters");
-		tls_connection_deinit(sm->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
- * 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)
-{
-	struct tls_connection_params params;
-
-	if (config == NULL)
-		return -1;
-
-	data->eap = sm;
-	data->phase2 = sm->init_phase2;
-	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(sm->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)
-{
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-
-	out = os_malloc(len);
-	if (out == NULL)
-		return NULL;
-
-	/* First, try to use TLS library function for PRF, if available. */
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-	    0)
-		return out;
-
-	/*
-	 * 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 (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
-		goto fail;
-
-	os_free(rnd);
-	return out;
-
-fail:
-	os_free(out);
-	os_free(rnd);
-	return NULL;
-}
-
-
-/**
- * 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;
-	}
-	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
- * @in_len: Length of in_data
- * @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 u8 *in_data, size_t in_len,
-				 struct wpabuf **out_data)
-{
-	const struct wpabuf *msg;
-	int need_more_input;
-	struct wpabuf *appl_data;
-	struct wpabuf buf;
-
-	wpabuf_set(&buf, in_data, in_len);
-	msg = eap_peer_tls_data_reassemble(data, &buf, &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(sm->ssl_ctx, data->conn,
-						 msg, &appl_data);
-
-	eap_peer_tls_reset_input(data);
-
-	if (appl_data &&
-	    tls_connection_established(sm->ssl_ctx, data->conn) &&
-	    !tls_connection_get_failed(sm->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_msg_alloc(EAP_VENDOR_IETF, 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
- * @in_len: Length of in_data
- * @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 u8 *in_data, size_t in_len,
-				struct wpabuf **out_data)
-{
-	int ret = 0;
-
-	*out_data = NULL;
-
-	if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 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, in_len,
-						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(sm->ssl_ctx, data->conn)) {
-		/* TLS processing has failed - return error */
-		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
-			   "report error");
-		ret = -1;
-		/* TODO: clean pin if engine used? */
-	}
-
-	if (data->tls_out == NULL || 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_msg_alloc(EAP_VENDOR_IETF, 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(sm->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 name[128];
-	int len = 0, ret;
-
-	if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
-		ret = os_snprintf(buf + len, buflen - len,
-				  "EAP TLS cipher=%s\n", name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			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;
-
-	if (tls_get_errors(sm->ssl_ctx)) {
-		wpa_printf(MSG_INFO, "SSL: TLS errors detected");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	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;
-	}
-
-	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(sm->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(sm->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;
-	u8 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);
-		} else {
-			num_methods++;
-			_methods = os_realloc(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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_tls_common.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_tls_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_tls_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1063 @@
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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);
+	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;
+}
+
+
+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->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);
+}
+
+
+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->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);
+}
+
+
+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);
+	}
+
+	/*
+	 * 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;
+	}
+
+	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;
+
+	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_INIT_FAILED) {
+		/*
+		 * At this point with the pkcs11 engine the PIN might be 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.
+		 */
+		os_free(config->pin);
+		config->pin = NULL;
+	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+		/*
+		 * We do not know exactly but maybe the PIN was wrong,
+		 * so ask for a new one.
+		 */
+		os_free(config->pin);
+		config->pin = NULL;
+		eap_sm_request_pin(sm);
+		sm->ignore = TRUE;
+		tls_connection_deinit(data->ssl_ctx, data->conn);
+		data->conn = NULL;
+		return -1;
+	} else 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)
+{
+#ifndef CONFIG_FIPS
+	struct tls_keys keys;
+#endif /* CONFIG_FIPS */
+	u8 *rnd = NULL, *out;
+
+	out = os_malloc(len);
+	if (out == NULL)
+		return NULL;
+
+	/* First, try to use TLS library function for PRF, if available. */
+	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
+	    == 0)
+		return out;
+
+#ifndef CONFIG_FIPS
+	/*
+	 * 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 (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
+		goto fail;
+
+	if (keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.master_key == NULL)
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+	os_memcpy(rnd, keys.client_random, keys.client_random_len);
+	os_memcpy(rnd + keys.client_random_len, keys.server_random,
+		  keys.server_random_len);
+
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
+		goto fail;
+
+	os_free(rnd);
+	return out;
+
+fail:
+#endif /* CONFIG_FIPS */
+	os_free(out);
+	os_free(rnd);
+	return NULL;
+}
+
+
+/**
+ * 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
+ * @in_len: Length of in_data
+ * @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 u8 *in_data, size_t in_len,
+				 struct wpabuf **out_data)
+{
+	const struct wpabuf *msg;
+	int need_more_input;
+	struct wpabuf *appl_data;
+	struct wpabuf buf;
+
+	wpabuf_set(&buf, in_data, in_len);
+	msg = eap_peer_tls_data_reassemble(data, &buf, &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
+ * @in_len: Length of in_data
+ * @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 u8 *in_data, size_t in_len,
+				struct wpabuf **out_data)
+{
+	int ret = 0;
+
+	*out_data = NULL;
+
+	if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 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, in_len,
+						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");
+		ret = -1;
+		/* TODO: clean pin if engine used? */
+	}
+
+	if (data->tls_out == NULL || 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 name[128];
+	int len = 0, ret;
+
+	if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
+	{
+		ret = os_snprintf(buf + len, buflen - len,
+				  "EAP TLS cipher=%s\n", name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			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;
+
+	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
+		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;
+	u8 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);
+		} 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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_tls_common.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_tls_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,126 +0,0 @@
-/*
- * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_TLS_COMMON_H
-#define EAP_TLS_COMMON_H
-
-/**
- * struct eap_ssl_data - TLS data for EAP methods
- */
-struct eap_ssl_data {
-	/**
-	 * conn - TLS connection context data from tls_connection_init()
-	 */
-	struct tls_connection *conn;
-
-	/**
-	 * tls_out - TLS message to be sent out in fragments
-	 */
-	struct wpabuf *tls_out;
-
-	/**
-	 * tls_out_pos - The current position in the outgoing TLS message
-	 */
-	size_t tls_out_pos;
-
-	/**
-	 * tls_out_limit - Maximum fragment size for outgoing TLS messages
-	 */
-	size_t tls_out_limit;
-
-	/**
-	 * tls_in - Received TLS message buffer for re-assembly
-	 */
-	struct wpabuf *tls_in;
-
-	/**
-	 * tls_in_left - Number of remaining bytes in the incoming TLS message
-	 */
-	size_t tls_in_left;
-
-	/**
-	 * tls_in_total - Total number of bytes in the incoming TLS message
-	 */
-	size_t tls_in_total;
-
-	/**
-	 * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
-	 */
-	int phase2;
-
-	/**
-	 * include_tls_length - Whether the TLS length field is included even
-	 * if the TLS data is not fragmented
-	 */
-	int include_tls_length;
-
-	/**
-	 * tls_ia - Whether TLS/IA is enabled for this TLS connection
-	 */
-	int tls_ia;
-
-	/**
-	 * eap - EAP state machine allocated with eap_peer_sm_init()
-	 */
-	struct eap_sm *eap;
-};
-
-
-/* EAP TLS Flags */
-#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
-#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
-#define EAP_TLS_FLAGS_START 0x20
-#define EAP_TLS_VERSION_MASK 0x07
-
- /* could be up to 128 bytes, but only the first 64 bytes are used */
-#define EAP_TLS_KEY_LEN 64
-
-
-int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
-			  struct eap_peer_config *config);
-void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
-u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-			     const char *label, size_t len);
-int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
-				EapType eap_type, int peap_version,
-				u8 id, const u8 *in_data, size_t in_len,
-				struct wpabuf **out_data);
-struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
-				       int peap_version);
-int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
-int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
-			char *buf, size_t buflen, int verbose);
-const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
-				     struct eap_ssl_data *data,
-				     EapType eap_type,
-				     struct eap_method_ret *ret,
-				     const struct wpabuf *reqData,
-				     size_t *len, u8 *flags);
-void eap_peer_tls_reset_input(struct eap_ssl_data *data);
-void eap_peer_tls_reset_output(struct eap_ssl_data *data);
-int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
-			 const struct wpabuf *in_data,
-			 struct wpabuf **in_decrypted);
-int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
-			 EapType eap_type, int peap_version, u8 id,
-			 const struct wpabuf *in_data,
-			 struct wpabuf **out_data);
-int eap_peer_select_phase2_methods(struct eap_peer_config *config,
-				   const char *prefix,
-				   struct eap_method_type **types,
-				   size_t *num_types);
-int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
-			    struct eap_hdr *hdr, struct wpabuf **resp);
-
-#endif /* EAP_TLS_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_peer/eap_tls_common.h (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_tls_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_tls_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_tls_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,128 @@
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TLS_COMMON_H
+#define EAP_TLS_COMMON_H
+
+/**
+ * struct eap_ssl_data - TLS data for EAP methods
+ */
+struct eap_ssl_data {
+	/**
+	 * conn - TLS connection context data from tls_connection_init()
+	 */
+	struct tls_connection *conn;
+
+	/**
+	 * tls_out - TLS message to be sent out in fragments
+	 */
+	struct wpabuf *tls_out;
+
+	/**
+	 * tls_out_pos - The current position in the outgoing TLS message
+	 */
+	size_t tls_out_pos;
+
+	/**
+	 * tls_out_limit - Maximum fragment size for outgoing TLS messages
+	 */
+	size_t tls_out_limit;
+
+	/**
+	 * tls_in - Received TLS message buffer for re-assembly
+	 */
+	struct wpabuf *tls_in;
+
+	/**
+	 * tls_in_left - Number of remaining bytes in the incoming TLS message
+	 */
+	size_t tls_in_left;
+
+	/**
+	 * tls_in_total - Total number of bytes in the incoming TLS message
+	 */
+	size_t tls_in_total;
+
+	/**
+	 * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
+	 */
+	int phase2;
+
+	/**
+	 * include_tls_length - Whether the TLS length field is included even
+	 * if the TLS data is not fragmented
+	 */
+	int include_tls_length;
+
+	/**
+	 * eap - EAP state machine allocated with eap_peer_sm_init()
+	 */
+	struct eap_sm *eap;
+
+	/**
+	 * ssl_ctx - TLS library context to use for the connection
+	 */
+	void *ssl_ctx;
+
+	/**
+	 * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+	 */
+	u8 eap_type;
+};
+
+
+/* EAP TLS Flags */
+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TLS_FLAGS_START 0x20
+#define EAP_TLS_VERSION_MASK 0x07
+
+ /* could be up to 128 bytes, but only the first 64 bytes are used */
+#define EAP_TLS_KEY_LEN 64
+
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
+
+int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+			  struct eap_peer_config *config, u8 eap_type);
+void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
+u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+			     const char *label, size_t len);
+int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+				EapType eap_type, int peap_version,
+				u8 id, const u8 *in_data, size_t in_len,
+				struct wpabuf **out_data);
+struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+				       int peap_version);
+int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
+int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
+			char *buf, size_t buflen, int verbose);
+const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
+				     struct eap_ssl_data *data,
+				     EapType eap_type,
+				     struct eap_method_ret *ret,
+				     const struct wpabuf *reqData,
+				     size_t *len, u8 *flags);
+void eap_peer_tls_reset_input(struct eap_ssl_data *data);
+void eap_peer_tls_reset_output(struct eap_ssl_data *data);
+int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **in_decrypted);
+int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 EapType eap_type, int peap_version, u8 id,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **out_data);
+int eap_peer_select_phase2_methods(struct eap_peer_config *config,
+				   const char *prefix,
+				   struct eap_method_type **types,
+				   size_t *num_types);
+int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
+			    struct eap_hdr *hdr, struct wpabuf **resp);
+
+#endif /* EAP_TLS_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_peer/eap_tnc.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_tnc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_tnc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,434 +0,0 @@
-/*
- * EAP peer method: EAP-TNC (Trusted Network Connect)
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "eap_i.h"
-#include "tncc.h"
-
-
-struct eap_tnc_data {
-	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
-	struct tncc_data *tncc;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	size_t out_used;
-	size_t fragment_size;
-};
-
-
-/* EAP-TNC Flags */
-#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
-#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
-#define EAP_TNC_FLAGS_START 0x20
-#define EAP_TNC_VERSION_MASK 0x07
-
-#define EAP_TNC_VERSION 1
-
-
-static void * eap_tnc_init(struct eap_sm *sm)
-{
-	struct eap_tnc_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = WAIT_START;
-	data->fragment_size = 1300;
-	data->tncc = tncc_init();
-	if (data->tncc == NULL) {
-		os_free(data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_tnc_data *data = priv;
-
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	tncc_deinit(data->tncc);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
-{
-	struct wpabuf *msg;
-
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
-			   "for fragment ack");
-		return NULL;
-	}
-	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
-
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
-					 struct eap_method_ret *ret, u8 id)
-{
-	struct wpabuf *resp;
-	u8 flags;
-	size_t send_len, plen;
-
-	ret->ignore = FALSE;
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
-	ret->allowNotifications = TRUE;
-
-	flags = EAP_TNC_VERSION;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (1 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 1;
-		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
-		if (data->out_used == 0) {
-			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
-			send_len -= 4;
-		}
-	}
-
-	plen = 1 + send_len;
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
-		plen += 4;
-	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, flags); /* Flags */
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
-		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		data->state = WAIT_FRAG_ACK;
-	}
-
-	return resp;
-}
-
-
-static int eap_tnc_process_cont(struct eap_tnc_data *data,
-				const u8 *buf, size_t len)
-{
-	/* Process continuation of a pending message */
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
-		data->state = FAIL;
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
-		   "%lu bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
-						struct eap_method_ret *ret,
-						u8 id, u8 flags,
-						u32 message_length,
-						const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
-			   "fragmented packet");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
-				   "message");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
-}
-
-
-static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_tnc_data *data = priv;
-	struct wpabuf *resp;
-	const u8 *pos, *end;
-	u8 *rpos, *rpos1;
-	size_t len, rlen;
-	size_t imc_len;
-	char *start_buf, *end_buf;
-	size_t start_len, end_len;
-	int tncs_done = 0;
-	u8 flags, id;
-	u32 message_length = 0;
-	struct wpabuf tmpbuf;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
-	if (pos == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
-			   pos, (unsigned long) len);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	id = eap_get_id(reqData);
-
-	end = pos + len;
-
-	if (len == 0)
-		flags = 0; /* fragment ack */
-	else
-		flags = *pos++;
-
-	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
-			   flags & EAP_TNC_VERSION_MASK);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		message_length = WPA_GET_BE32(pos);
-		pos += 4;
-
-		if (message_length < (u32) (end - pos)) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
-				   "Length (%d; %ld remaining in this msg)",
-				   message_length, (long) (end - pos));
-			ret->ignore = TRUE;
-			return NULL;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
-		   "Message Length %u", flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (len > 1) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
-				   "WAIT_FRAG_ACK state");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
-		data->state = PROC_MSG;
-		return eap_tnc_build_msg(data, ret, id);
-	}
-
-	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-		
-	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
-		return eap_tnc_process_fragment(data, ret, id, flags,
-						message_length, pos,
-						end - pos);
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	if (data->state == WAIT_START) {
-		if (!(flags & EAP_TNC_FLAGS_START)) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
-				   "start flag in the first message");
-			ret->ignore = TRUE;
-			goto fail;
-		}
-
-		tncc_init_connection(data->tncc);
-
-		data->state = PROC_MSG;
-	} else {
-		enum tncc_process_res res;
-
-		if (flags & EAP_TNC_FLAGS_START) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
-				   "flag again");
-			ret->ignore = TRUE;
-			goto fail;
-		}
-
-		res = tncc_process_if_tnccs(data->tncc,
-					    wpabuf_head(data->in_buf),
-					    wpabuf_len(data->in_buf));
-		switch (res) {
-		case TNCCS_PROCESS_ERROR:
-			ret->ignore = TRUE;
-			goto fail;
-		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
-		case TNCCS_RECOMMENDATION_ERROR:
-			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
-				   "TNCCS-Recommendation received");
-			break;
-		case TNCCS_RECOMMENDATION_ALLOW:
-			wpa_msg(sm->msg_ctx, MSG_INFO,
-				"TNC: Recommendation = allow");
-			tncs_done = 1;
-			break;
-		case TNCCS_RECOMMENDATION_NONE:
-			wpa_msg(sm->msg_ctx, MSG_INFO,
-				"TNC: Recommendation = none");
-			tncs_done = 1;
-			break;
-		case TNCCS_RECOMMENDATION_ISOLATE:
-			wpa_msg(sm->msg_ctx, MSG_INFO,
-				"TNC: Recommendation = isolate");
-			tncs_done = 1;
-			break;
-		}
-	}
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-
-	ret->ignore = FALSE;
-	ret->methodState = METHOD_MAY_CONT;
-	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));
-		if (resp == NULL)
-			return NULL;
-
-		wpabuf_put_u8(resp, EAP_TNC_VERSION);
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
-			   "empty ACK message");
-		return resp;
-	}
-
-	imc_len = tncc_total_send_len(data->tncc);
-
-	start_buf = tncc_if_tnccs_start(data->tncc);
-	if (start_buf == NULL)
-		return NULL;
-	start_len = os_strlen(start_buf);
-	end_buf = tncc_if_tnccs_end();
-	if (end_buf == NULL) {
-		os_free(start_buf);
-		return NULL;
-	}
-	end_len = os_strlen(end_buf);
-
-	rlen = start_len + imc_len + end_len;
-	resp = wpabuf_alloc(rlen);
-	if (resp == NULL) {
-		os_free(start_buf);
-		os_free(end_buf);
-		return NULL;
-	}
-
-	wpabuf_put_data(resp, start_buf, start_len);
-	os_free(start_buf);
-
-	rpos1 = wpabuf_put(resp, 0);
-	rpos = tncc_copy_send_buf(data->tncc, rpos1);
-	wpabuf_put(resp, rpos - rpos1);
-
-	wpabuf_put_data(resp, end_buf, end_len);
-	os_free(end_buf);
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
-			  wpabuf_head(resp), wpabuf_len(resp));
-
-	data->out_buf = resp;
-	data->state = PROC_MSG;
-	return eap_tnc_build_msg(data, ret, id);
-
-fail:
-	if (data->in_buf == &tmpbuf)
-		data->in_buf = NULL;
-	return NULL;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_tnc_init;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_tnc.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_tnc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_tnc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_tnc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,427 @@
+/*
+ * EAP peer method: EAP-TNC (Trusted Network Connect)
+ * Copyright (c) 2007, Jouni Malinen <j at 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 "eap_i.h"
+#include "tncc.h"
+
+
+struct eap_tnc_data {
+	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
+	struct tncc_data *tncc;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
+};
+
+
+/* EAP-TNC Flags */
+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TNC_FLAGS_START 0x20
+#define EAP_TNC_VERSION_MASK 0x07
+
+#define EAP_TNC_VERSION 1
+
+
+static void * eap_tnc_init(struct eap_sm *sm)
+{
+	struct eap_tnc_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = WAIT_START;
+	data->fragment_size = 1300;
+	data->tncc = tncc_init();
+	if (data->tncc == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	tncc_deinit(data->tncc);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
+					 struct eap_method_ret *ret, u8 id)
+{
+	struct wpabuf *resp;
+	u8 flags;
+	size_t send_len, plen;
+
+	ret->ignore = FALSE;
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	flags = EAP_TNC_VERSION;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, flags); /* Flags */
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		data->state = WAIT_FRAG_ACK;
+	}
+
+	return resp;
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+				const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+		data->state = FAIL;
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
+		   "%lu bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
+						struct eap_method_ret *ret,
+						u8 id, u8 flags,
+						u32 message_length,
+						const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+			   "fragmented packet");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+				   "message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
+}
+
+
+static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_tnc_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *end;
+	u8 *rpos, *rpos1;
+	size_t len, rlen;
+	size_t imc_len;
+	char *start_buf, *end_buf;
+	size_t start_len, end_len;
+	int tncs_done = 0;
+	u8 flags, id;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
+			   pos, (unsigned long) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+
+	end = pos + len;
+
+	if (len == 0)
+		flags = 0; /* fragment ack */
+	else
+		flags = *pos++;
+
+	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
+			   flags & EAP_TNC_VERSION_MASK);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (len > 1) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
+				   "WAIT_FRAG_ACK state");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+		data->state = PROC_MSG;
+		return eap_tnc_build_msg(data, ret, id);
+	}
+
+	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+		
+	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+		return eap_tnc_process_fragment(data, ret, id, flags,
+						message_length, pos,
+						end - pos);
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	if (data->state == WAIT_START) {
+		if (!(flags & EAP_TNC_FLAGS_START)) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
+				   "start flag in the first message");
+			ret->ignore = TRUE;
+			goto fail;
+		}
+
+		tncc_init_connection(data->tncc);
+
+		data->state = PROC_MSG;
+	} else {
+		enum tncc_process_res res;
+
+		if (flags & EAP_TNC_FLAGS_START) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
+				   "flag again");
+			ret->ignore = TRUE;
+			goto fail;
+		}
+
+		res = tncc_process_if_tnccs(data->tncc,
+					    wpabuf_head(data->in_buf),
+					    wpabuf_len(data->in_buf));
+		switch (res) {
+		case TNCCS_PROCESS_ERROR:
+			ret->ignore = TRUE;
+			goto fail;
+		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
+		case TNCCS_RECOMMENDATION_ERROR:
+			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
+				   "TNCCS-Recommendation received");
+			break;
+		case TNCCS_RECOMMENDATION_ALLOW:
+			wpa_msg(sm->msg_ctx, MSG_INFO,
+				"TNC: Recommendation = allow");
+			tncs_done = 1;
+			break;
+		case TNCCS_RECOMMENDATION_NONE:
+			wpa_msg(sm->msg_ctx, MSG_INFO,
+				"TNC: Recommendation = none");
+			tncs_done = 1;
+			break;
+		case TNCCS_RECOMMENDATION_ISOLATE:
+			wpa_msg(sm->msg_ctx, MSG_INFO,
+				"TNC: Recommendation = isolate");
+			tncs_done = 1;
+			break;
+		}
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	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));
+		if (resp == NULL)
+			return NULL;
+
+		wpabuf_put_u8(resp, EAP_TNC_VERSION);
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
+			   "empty ACK message");
+		return resp;
+	}
+
+	imc_len = tncc_total_send_len(data->tncc);
+
+	start_buf = tncc_if_tnccs_start(data->tncc);
+	if (start_buf == NULL)
+		return NULL;
+	start_len = os_strlen(start_buf);
+	end_buf = tncc_if_tnccs_end();
+	if (end_buf == NULL) {
+		os_free(start_buf);
+		return NULL;
+	}
+	end_len = os_strlen(end_buf);
+
+	rlen = start_len + imc_len + end_len;
+	resp = wpabuf_alloc(rlen);
+	if (resp == NULL) {
+		os_free(start_buf);
+		os_free(end_buf);
+		return NULL;
+	}
+
+	wpabuf_put_data(resp, start_buf, start_len);
+	os_free(start_buf);
+
+	rpos1 = wpabuf_put(resp, 0);
+	rpos = tncc_copy_send_buf(data->tncc, rpos1);
+	wpabuf_put(resp, rpos - rpos1);
+
+	wpabuf_put_data(resp, end_buf, end_len);
+	os_free(end_buf);
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
+			  wpabuf_head(resp), wpabuf_len(resp));
+
+	data->out_buf = resp;
+	data->state = PROC_MSG;
+	return eap_tnc_build_msg(data, ret, id);
+
+fail:
+	if (data->in_buf == &tmpbuf)
+		data->in_buf = NULL;
+	return NULL;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tnc_init;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_ttls.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_ttls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_ttls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1986 +0,0 @@
-/*
- * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.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"
-
-
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
-
-
-static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
-
-
-struct eap_ttls_data {
-	struct eap_ssl_data ssl;
-	int ssl_initialized;
-
-	int ttls_version, force_ttls_version;
-
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int phase2_success;
-	int phase2_start;
-
-	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;
-
-	struct wpabuf *pending_phase2_req;
-
-#ifdef EAP_TNC
-	int ready_for_tnc;
-	int tnc_started;
-#endif /* EAP_TNC */
-};
-
-
-static void * eap_ttls_init(struct eap_sm *sm)
-{
-	struct eap_ttls_data *data;
-	struct eap_peer_config *config = eap_get_config(sm);
-	char *selected;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_ttls_version = -1;
-	selected = "EAP";
-	data->phase2_type = EAP_TTLS_PHASE2_EAP;
-
-#if EAP_TTLS_VERSION > 0
-	if (config && config->phase1) {
-		const char *pos = os_strstr(config->phase1, "ttlsver=");
-		if (pos) {
-			data->force_ttls_version = atoi(pos + 8);
-			data->ttls_version = data->force_ttls_version;
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
-				   "%d", data->force_ttls_version);
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
-
-	if (config && config->phase2) {
-		if (os_strstr(config->phase2, "autheap=")) {
-			selected = "EAP";
-			data->phase2_type = EAP_TTLS_PHASE2_EAP;
-		} else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
-			selected = "MSCHAPV2";
-			data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
-		} else if (os_strstr(config->phase2, "auth=MSCHAP")) {
-			selected = "MSCHAP";
-			data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
-		} else if (os_strstr(config->phase2, "auth=PAP")) {
-			selected = "PAP";
-			data->phase2_type = EAP_TTLS_PHASE2_PAP;
-		} else if (os_strstr(config->phase2, "auth=CHAP")) {
-			selected = "CHAP";
-			data->phase2_type = EAP_TTLS_PHASE2_CHAP;
-		}
-	}
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
-
-	if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
-		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_TTLS_VERSION > 0
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_ttls_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_ttls_version);
-			eap_ttls_deinit(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
-	}
-#endif /* EAP_TTLS_VERSION */
-
-	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_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);
-	if (data->ssl_initialized)
-		eap_peer_tls_ssl_deinit(sm, &data->ssl);
-	os_free(data->key_data);
-	wpabuf_free(data->pending_phase2_req);
-	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((flags << 24) | (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;
-}
-
-
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
-static int eap_ttls_v0_derive_key(struct eap_sm *sm,
-				  struct eap_ttls_data *data)
-{
-	os_free(data->key_data);
-	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
-						 "ttls keying material",
-						 EAP_TLS_KEY_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);
-
-	return 0;
-}
-
-
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_v1_derive_key(struct eap_sm *sm,
-				  struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd;
-
-	os_free(data->key_data);
-	data->key_data = NULL;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return -1;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	data->key_data = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || data->key_data == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-			data->key_data, EAP_TLS_KEY_LEN);
-
-	return 0;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
-static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
-					struct eap_ttls_data *data, size_t len)
-{
-#if EAP_TTLS_VERSION > 0
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-#endif /* EAP_TTLS_VERSION */
-
-	if (data->ttls_version == 0) {
-		return eap_peer_tls_derive_key(sm, &data->ssl,
-					       "ttls challenge", len);
-	}
-
-#if EAP_TTLS_VERSION > 0
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
-
-#else /* EAP_TTLS_VERSION */
-
-	return NULL;
-
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
-					 struct eap_ttls_data *data,
-					 struct eap_method_ret *ret)
-{
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0) {
-		const struct eap_method *m = data->phase2_method;
-		void *priv = data->phase2_priv;
-
-		/* TTLSv1 requires TLS/IA FinalPhaseFinished */
-		if (ret->decision == DECISION_UNCOND_SUCC)
-			ret->decision = DECISION_COND_SUCC;
-		ret->methodState = METHOD_CONT;
-
-		if (ret->decision == DECISION_COND_SUCC &&
-		    m->isKeyAvailable && m->getKey &&
-		    m->isKeyAvailable(sm, priv)) {
-			u8 *key;
-			size_t key_len;
-			key = m->getKey(sm, priv, &key_len);
-			if (key) {
-				eap_ttls_ia_permute_inner_secret(
-					sm, data, key, key_len);
-				os_free(key);
-			}
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-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;
-	}
-	eap_ttlsv1_phase2_eap_finish(sm, data, ret);
-
-	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 void eap_ttlsv1_permute_inner(struct eap_sm *sm,
-				     struct eap_ttls_data *data)
-{
-#if EAP_TTLS_VERSION > 0
-	u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-	if (data->ttls_version == 0)
-		return;
-
-	get_asymetric_start_key(data->master_key, session_key,
-				MSCHAPV2_KEY_LEN, 0, 0);
-	get_asymetric_start_key(data->master_key,
-				session_key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 0);
-	eap_ttls_ia_permute_inner_secret(sm, data, session_key,
-					 sizeof(session_key));
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    struct eap_method_ret *ret,
-					    struct wpabuf **resp)
-{
-	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;
-	}
-	peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
-
-	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 */
-	os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
-	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)) {
-		wpabuf_free(msg);
-		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
-			   "response");
-		return -1;
-	}
-	data->auth_response_valid = 1;
-
-	eap_ttlsv1_permute_inner(sm, data);
-
-	pos += 24;
-	os_free(challenge);
-	AVP_PAD(buf, pos);
-
-	wpabuf_put(msg, pos - buf);
-	*resp = msg;
-
-	if (sm->workaround && data->ttls_version == 0) {
-		/* At least FreeRADIUS seems to be terminating
-		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
-		 * packet. */
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
-			   "allow success without tunneled response");
-		ret->methodState = METHOD_MAY_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	}
-
-	return 0;
-}
-
-
-static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
-					  struct eap_ttls_data *data,
-					  struct eap_method_ret *ret,
-					  struct wpabuf **resp)
-{
-	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;
-
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* 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;
-}
-
-
-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;
-
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* 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)
-{
-	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;
-
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* 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;
-}
-
-
-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;
-}
-
-
-#if EAP_TTLS_VERSION > 0
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
-{
-	struct wpabuf *req, *buf;
-
-	buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						    data->ssl.conn,
-						    final);
-	if (buf == NULL)
-		return NULL;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-			    1 + wpabuf_len(buf),
-			    EAP_CODE_RESPONSE, id);
-	if (req == NULL) {
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, data->ttls_version);
-	wpabuf_put_buf(req, buf);
-	wpabuf_free(buf);
-	eap_update_len(req);
-
-	return req;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
-struct ttls_parse_avp {
-	u8 *mschapv2;
-	u8 *eapdata;
-	size_t eap_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_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 == 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");
-		return -1;
-	}
-	wpabuf_free(resp);
-
-	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)
-{
-	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");
-	if (data->ttls_version > 0) {
-		/*
-		 * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
-		 * success, so do not allow connection to be terminated
-		 * yet.
-		 */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		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;
-}
-
-
-#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 */
-
-	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) {
-		if (eap_ttls_encrypt_response(sm, data, resp, identifier,
-					      out_data) < 0)
-			return -1;
-	} else if (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;
-}
-
-
-#if EAP_TTLS_VERSION > 0
-static void eap_ttls_final_phase_finished(struct eap_sm *sm,
-					  struct eap_ttls_data *data,
-					  struct eap_method_ret *ret,
-					  u8 identifier,
-					  struct wpabuf **out_data)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
-	wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	data->phase2_success = 1;
-	*out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
-	eap_ttls_v1_derive_key(sm, data);
-}
-#endif /* EAP_TTLS_VERSION */
-
-
-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 {
-		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;
-
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0 &&
-	    (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
-	    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-						   data->ssl.conn)) {
-		eap_ttls_final_phase_finished(sm, data, ret, identifier,
-					      out_data);
-		goto done;
-	}
-#endif /* EAP_TTLS_VERSION */
-
-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_start(struct eap_sm *sm,
-				  struct eap_ttls_data *data, u8 flags,
-				  struct eap_method_ret *ret)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
-		   flags & EAP_TLS_VERSION_MASK, data->ttls_version);
-#if EAP_TTLS_VERSION > 0
-	if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
-		data->ttls_version = flags & EAP_TLS_VERSION_MASK;
-	if (data->force_ttls_version >= 0 &&
-	    data->force_ttls_version != data->ttls_version) {
-		wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
-			   "forced TTLS version %d",
-			   data->force_ttls_version);
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
-		   data->ttls_version);
-
-	if (data->ttls_version > 0)
-		data->ssl.tls_ia = 1;
-#endif /* EAP_TTLS_VERSION */
-	if (!data->ssl_initialized &&
-	    eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-		return -1;
-	}
-	data->ssl_initialized = 1;
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-
-	return 0;
-}
-
-
-static int eap_ttls_process_handshake(struct eap_sm *sm,
-				      struct eap_ttls_data *data,
-				      struct eap_method_ret *ret,
-				      u8 identifier,
-				      const u8 *in_data, size_t in_len,
-				      struct wpabuf **out_data)
-{
-	int res;
-
-	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
-					  data->ttls_version, identifier,
-					  in_data, in_len, out_data);
-
-	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;
-		if (data->ttls_version == 0)
-			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) {
-		struct wpabuf msg;
-		/*
-		 * Application data included in the handshake message.
-		 */
-		wpabuf_free(data->pending_phase2_req);
-		data->pending_phase2_req = *out_data;
-		*out_data = NULL;
-		wpabuf_set(&msg, in_data, in_len);
-		res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
-				       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 (data->ttls_version == 0 && 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;
-#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 (data->ttls_version == 0 &&
-		   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;
-	}
-}
-
-
-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;
-
-	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) {
-		if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-			return NULL;
-
-		/* 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;
-	} else if (!data->ssl_initialized) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
-			   "include Start flag");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return NULL;
-	}
-
-	resp = NULL;
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
-	    !data->resuming) {
-		struct wpabuf msg;
-		wpabuf_set(&msg, pos, left);
-		res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
-	} else {
-		res = eap_ttls_process_handshake(sm, data, ret, id,
-						 pos, left, &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;
-#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;
-	os_free(data->key_data);
-	data->key_data = 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 (ret < 0 || (size_t) ret >= buflen - len)
-		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 (ret < 0 || (size_t) ret >= buflen - len)
-		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;
-}
-
-
-int eap_peer_ttls_register(void)
-{
-	struct eap_method *eap;
-	int ret;
-
-	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
-				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
-	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->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;
-
-	ret = eap_peer_method_register(eap);
-	if (ret)
-		eap_peer_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_ttls.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_ttls.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_ttls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_ttls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1639 @@
+/*
+ * EAP peer method: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2011, Jouni Malinen <j at 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/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;
+
+	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;
+
+	struct wpabuf *pending_phase2_req;
+
+#ifdef EAP_TNC
+	int ready_for_tnc;
+	int tnc_started;
+#endif /* EAP_TNC */
+};
+
+
+static void * eap_ttls_init(struct eap_sm *sm)
+{
+	struct eap_ttls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+	char *selected;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->ttls_version = EAP_TTLS_VERSION;
+	selected = "EAP";
+	data->phase2_type = EAP_TTLS_PHASE2_EAP;
+
+	if (config && config->phase2) {
+		if (os_strstr(config->phase2, "autheap=")) {
+			selected = "EAP";
+			data->phase2_type = EAP_TTLS_PHASE2_EAP;
+		} else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
+			selected = "MSCHAPV2";
+			data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+		} else if (os_strstr(config->phase2, "auth=MSCHAP")) {
+			selected = "MSCHAP";
+			data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+		} else if (os_strstr(config->phase2, "auth=PAP")) {
+			selected = "PAP";
+			data->phase2_type = EAP_TTLS_PHASE2_PAP;
+		} else if (os_strstr(config->phase2, "auth=CHAP")) {
+			selected = "CHAP";
+			data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
+
+	if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
+		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_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);
+	os_free(data->key_data);
+	wpabuf_free(data->pending_phase2_req);
+	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((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;
+}
+
+
+static int eap_ttls_v0_derive_key(struct eap_sm *sm,
+				  struct eap_ttls_data *data)
+{
+	os_free(data->key_data);
+	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
+						 "ttls keying material",
+						 EAP_TLS_KEY_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);
+
+	return 0;
+}
+
+
+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);
+}
+
+
+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 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;
+
+	if (sm->workaround) {
+		/* At least FreeRADIUS seems to be terminating
+		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
+		 * packet. */
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
+			   "allow success without tunneled response");
+		ret->methodState = METHOD_MAY_CONT;
+		ret->decision = DECISION_COND_SUCC;
+	}
+
+	return 0;
+#else /* EAP_MSCHAPv2 */
+	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+	return -1;
+#endif /* EAP_MSCHAPv2 */
+}
+
+
+static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
+					  struct eap_ttls_data *data,
+					  struct eap_method_ret *ret,
+					  struct wpabuf **resp)
+{
+	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;
+}
+
+
+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)
+{
+	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;
+}
+
+
+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;
+	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_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 == 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");
+		return -1;
+	}
+	wpabuf_free(resp);
+
+	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 */
+
+	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) {
+		if (eap_ttls_encrypt_response(sm, data, resp, identifier,
+					      out_data) < 0)
+			return -1;
+	} else if (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;
+}
+
+
+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 u8 *in_data, size_t in_len,
+				      struct wpabuf **out_data)
+{
+	int res;
+
+	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
+					  data->ttls_version, identifier,
+					  in_data, in_len, out_data);
+
+	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) {
+		struct wpabuf msg;
+		/*
+		 * Application data included in the handshake message.
+		 */
+		wpabuf_free(data->pending_phase2_req);
+		data->pending_phase2_req = *out_data;
+		*out_data = NULL;
+		wpabuf_set(&msg, in_data, in_len);
+		res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
+				       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;
+#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;
+	}
+}
+
+
+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;
+
+	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;
+	}
+
+	resp = NULL;
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+	    !data->resuming) {
+		struct wpabuf msg;
+		wpabuf_set(&msg, pos, left);
+		res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
+	} else {
+		res = eap_ttls_process_handshake(sm, data, ret, id,
+						 pos, left, &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;
+#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;
+	os_free(data->key_data);
+	data->key_data = 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 (ret < 0 || (size_t) ret >= buflen - len)
+		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 (ret < 0 || (size_t) ret >= buflen - len)
+		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;
+}
+
+
+int eap_peer_ttls_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
+	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->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;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_vendor_test.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,195 +0,0 @@
-/*
- * EAP peer method: Test method for vendor specific (expanded) EAP type
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements a vendor specific test method using EAP expanded types.
- * This is only for test use and must not be used for authentication since no
- * security is provided.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#ifdef TEST_PENDING_REQUEST
-#include "eloop.h"
-#endif /* TEST_PENDING_REQUEST */
-
-
-#define EAP_VENDOR_ID 0xfffefd
-#define EAP_VENDOR_TYPE 0xfcfbfaf9
-
-
-/* #define TEST_PENDING_REQUEST */
-
-struct eap_vendor_test_data {
-	enum { INIT, CONFIRM, SUCCESS } state;
-	int first_try;
-};
-
-
-static void * eap_vendor_test_init(struct eap_sm *sm)
-{
-	struct eap_vendor_test_data *data;
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = INIT;
-	data->first_try = 1;
-	return data;
-}
-
-
-static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_vendor_test_data *data = priv;
-	os_free(data);
-}
-
-
-#ifdef TEST_PENDING_REQUEST
-static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eap_sm *sm = eloop_ctx;
-	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending "
-		   "request");
-	eap_notify_pending(sm);
-}
-#endif /* TEST_PENDING_REQUEST */
-
-
-static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
-					       struct eap_method_ret *ret,
-					       const struct wpabuf *reqData)
-{
-	struct eap_vendor_test_data *data = priv;
-	struct wpabuf *resp;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
-	if (pos == NULL || len < 1) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state == INIT && *pos != 1) {
-		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
-			   "%d in INIT state", *pos);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state == CONFIRM && *pos != 3) {
-		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
-			   "%d in CONFIRM state", *pos);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state == SUCCESS) {
-		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
-			   "in SUCCESS state");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state == CONFIRM) {
-#ifdef TEST_PENDING_REQUEST
-		if (data->first_try) {
-			data->first_try = 0;
-			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
-				   "pending request");
-			ret->ignore = TRUE;
-			eloop_register_timeout(1, 0, eap_vendor_ready, sm,
-					       NULL);
-			return NULL;
-		}
-#endif /* TEST_PENDING_REQUEST */
-	}
-
-	ret->ignore = FALSE;
-
-	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
-	ret->allowNotifications = TRUE;
-
-	resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
-			     EAP_CODE_RESPONSE, eap_get_id(reqData));
-	if (resp == NULL)
-		return NULL;
-
-	if (data->state == INIT) {
-		wpabuf_put_u8(resp, 2);
-		data->state = CONFIRM;
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_FAIL;
-	} else {
-		wpabuf_put_u8(resp, 4);
-		data->state = SUCCESS;
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_UNCOND_SUCC;
-	}
-
-	return resp;
-}
-
-
-static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
-{
-	struct eap_vendor_test_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_vendor_test_data *data = priv;
-	u8 *key;
-	const int key_len = 64;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(key_len);
-	if (key == NULL)
-		return NULL;
-
-	os_memset(key, 0x11, key_len / 2);
-	os_memset(key + key_len / 2, 0x22, key_len / 2);
-	*len = key_len;
-
-	return key;
-}
-
-
-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,
-				    "VENDOR-TEST");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_vendor_test_init;
-	eap->deinit = eap_vendor_test_deinit;
-	eap->process = eap_vendor_test_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_vendor_test.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_vendor_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,189 @@
+/*
+ * EAP peer method: Test method for vendor specific (expanded) EAP type
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements a vendor specific test method using EAP expanded types.
+ * This is only for test use and must not be used for authentication since no
+ * security is provided.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#ifdef TEST_PENDING_REQUEST
+#include "eloop.h"
+#endif /* TEST_PENDING_REQUEST */
+
+
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE 0xfcfbfaf9
+
+
+/* #define TEST_PENDING_REQUEST */
+
+struct eap_vendor_test_data {
+	enum { INIT, CONFIRM, SUCCESS } state;
+	int first_try;
+};
+
+
+static void * eap_vendor_test_init(struct eap_sm *sm)
+{
+	struct eap_vendor_test_data *data;
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = INIT;
+	data->first_try = 1;
+	return data;
+}
+
+
+static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	os_free(data);
+}
+
+
+#ifdef TEST_PENDING_REQUEST
+static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eap_sm *sm = eloop_ctx;
+	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending "
+		   "request");
+	eap_notify_pending(sm);
+}
+#endif /* TEST_PENDING_REQUEST */
+
+
+static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv,
+					       struct eap_method_ret *ret,
+					       const struct wpabuf *reqData)
+{
+	struct eap_vendor_test_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len);
+	if (pos == NULL || len < 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == INIT && *pos != 1) {
+		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+			   "%d in INIT state", *pos);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == CONFIRM && *pos != 3) {
+		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+			   "%d in CONFIRM state", *pos);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == SUCCESS) {
+		wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+			   "in SUCCESS state");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == CONFIRM) {
+#ifdef TEST_PENDING_REQUEST
+		if (data->first_try) {
+			data->first_try = 0;
+			wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
+				   "pending request");
+			ret->ignore = TRUE;
+			eloop_register_timeout(1, 0, eap_vendor_ready, sm,
+					       NULL);
+			return NULL;
+		}
+#endif /* TEST_PENDING_REQUEST */
+	}
+
+	ret->ignore = FALSE;
+
+	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+
+	if (data->state == INIT) {
+		wpabuf_put_u8(resp, 2);
+		data->state = CONFIRM;
+		ret->methodState = METHOD_CONT;
+		ret->decision = DECISION_FAIL;
+	} else {
+		wpabuf_put_u8(resp, 4);
+		data->state = SUCCESS;
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_UNCOND_SUCC;
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_vendor_test_data *data = priv;
+	u8 *key;
+	const int key_len = 64;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(key_len);
+	if (key == NULL)
+		return NULL;
+
+	os_memset(key, 0x11, key_len / 2);
+	os_memset(key + key_len / 2, 0x22, key_len / 2);
+	*len = key_len;
+
+	return key;
+}
+
+
+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,
+				    "VENDOR-TEST");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_vendor_test_init;
+	eap->deinit = eap_vendor_test_deinit;
+	eap->process = eap_vendor_test_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/eap_wsc.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/eap_wsc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/eap_wsc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,543 +0,0 @@
-/*
- * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "uuid.h"
-#include "eap_i.h"
-#include "eap_common/eap_wsc_common.h"
-#include "wps/wps.h"
-#include "wps/wps_defs.h"
-
-
-struct eap_wsc_data {
-	enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
-	int registrar;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	enum wsc_op_code in_op_code, out_op_code;
-	size_t out_used;
-	size_t fragment_size;
-	struct wps_data *wps;
-	struct wps_context *wps_ctx;
-};
-
-
-static const char * eap_wsc_state_txt(int state)
-{
-	switch (state) {
-	case WAIT_START:
-		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:
-		return "?";
-	}
-}
-
-
-static void eap_wsc_state(struct eap_wsc_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
-		   eap_wsc_state_txt(data->state),
-		   eap_wsc_state_txt(state));
-	data->state = state;
-}
-
-
-static int eap_wsc_new_ap_settings(struct wps_credential *cred,
-				   const char *params)
-{
-	const char *pos, *end;
-	size_t len;
-
-	os_memset(cred, 0, sizeof(*cred));
-
-	pos = os_strstr(params, "new_ssid=");
-	if (pos == NULL)
-		return 0;
-	pos += 9;
-	end = os_strchr(pos, ' ');
-	if (end == NULL)
-		len = os_strlen(pos);
-	else
-		len = end - pos;
-	if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
-	    hexstr2bin(pos, cred->ssid, len / 2))
-		return -1;
-	cred->ssid_len = len / 2;
-
-	pos = os_strstr(params, "new_auth=");
-	if (pos == NULL)
-		return -1;
-	if (os_strncmp(pos + 9, "OPEN", 4) == 0)
-		cred->auth_type = WPS_AUTH_OPEN;
-	else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
-		cred->auth_type = WPS_AUTH_WPAPSK;
-	else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
-		cred->auth_type = WPS_AUTH_WPA2PSK;
-	else
-		return -1;
-
-	pos = os_strstr(params, "new_encr=");
-	if (pos == NULL)
-		return -1;
-	if (os_strncmp(pos + 9, "NONE", 4) == 0)
-		cred->encr_type = WPS_ENCR_NONE;
-	else if (os_strncmp(pos + 9, "WEP", 3) == 0)
-		cred->encr_type = WPS_ENCR_WEP;
-	else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
-		cred->encr_type = WPS_ENCR_TKIP;
-	else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
-		cred->encr_type = WPS_ENCR_AES;
-	else
-		return -1;
-
-	pos = os_strstr(params, "new_key=");
-	if (pos == NULL)
-		return 0;
-	pos += 8;
-	end = os_strchr(pos, ' ');
-	if (end == NULL)
-		len = os_strlen(pos);
-	else
-		len = end - pos;
-	if ((len & 1) || len > 2 * sizeof(cred->key) ||
-	    hexstr2bin(pos, cred->key, len / 2))
-		return -1;
-	cred->key_len = len / 2;
-
-	return 1;
-}
-
-
-static void * eap_wsc_init(struct eap_sm *sm)
-{
-	struct eap_wsc_data *data;
-	const u8 *identity;
-	size_t identity_len;
-	int registrar;
-	struct wps_config cfg;
-	const char *pos;
-	const char *phase1;
-	struct wps_context *wps;
-	struct wps_credential new_ap_settings;
-	int res;
-
-	wps = sm->wps;
-	if (wps == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
-		return NULL;
-	}
-
-	identity = eap_get_config_identity(sm, &identity_len);
-
-	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
-	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
-		registrar = 1; /* Supplicant is Registrar */
-	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
-	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
-		registrar = 0; /* Supplicant is Enrollee */
-	else {
-		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
-				  identity, identity_len);
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = registrar ? MESG : WAIT_START;
-	data->registrar = registrar;
-	data->wps_ctx = wps;
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	cfg.wps = wps;
-	cfg.registrar = registrar;
-
-	phase1 = eap_get_config_phase1(sm);
-	if (phase1 == NULL) {
-		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
-			   "set");
-		os_free(data);
-		return NULL;
-	}
-
-	pos = os_strstr(phase1, "pin=");
-	if (pos) {
-		pos += 4;
-		cfg.pin = (const u8 *) pos;
-		while (*pos != '\0' && *pos != ' ')
-			pos++;
-		cfg.pin_len = pos - (const char *) cfg.pin;
-	} else {
-		pos = os_strstr(phase1, "pbc=1");
-		if (pos)
-			cfg.pbc = 1;
-	}
-
-	if (cfg.pin == NULL && !cfg.pbc) {
-		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
-			   "configuration data");
-		os_free(data);
-		return NULL;
-	}
-
-	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
-	if (res < 0) {
-		os_free(data);
-		return NULL;
-	}
-	if (res == 1) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
-			   "WPS");
-		cfg.new_ap_settings = &new_ap_settings;
-	}
-
-	data->wps = wps_init(&cfg);
-	if (data->wps == NULL) {
-		os_free(data);
-		return NULL;
-	}
-	data->fragment_size = WSC_FRAGMENT_SIZE;
-
-	if (registrar && cfg.pin) {
-		wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
-				      cfg.pin, cfg.pin_len, 0);
-	}
-
-	/* Use reduced client timeout for WPS to avoid long wait */
-	if (sm->ClientTimeout > 30)
-		sm->ClientTimeout = 30;
-
-	return data;
-}
-
-
-static void eap_wsc_deinit(struct eap_sm *sm, void *priv)
-{
-	struct eap_wsc_data *data = priv;
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	wps_deinit(data->wps);
-	os_free(data->wps_ctx->network_key);
-	data->wps_ctx->network_key = NULL;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,
-					 struct eap_method_ret *ret, u8 id)
-{
-	struct wpabuf *resp;
-	u8 flags;
-	size_t send_len, plen;
-
-	ret->ignore = FALSE;
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
-	ret->allowNotifications = TRUE;
-
-	flags = 0;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (2 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 2;
-		flags |= WSC_FLAGS_MF;
-		if (data->out_used == 0) {
-			flags |= WSC_FLAGS_LF;
-			send_len -= 2;
-		}
-	}
-	plen = 2 + send_len;
-	if (flags & WSC_FLAGS_LF)
-		plen += 2;
-	resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
-			     EAP_CODE_RESPONSE, id);
-	if (resp == NULL)
-		return NULL;
-
-	wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
-	wpabuf_put_u8(resp, flags); /* Flags */
-	if (flags & WSC_FLAGS_LF)
-		wpabuf_put_be16(resp, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	ret->methodState = METHOD_MAY_CONT;
-	ret->decision = DECISION_FAIL;
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-		if ((data->state == FAIL && data->out_op_code == WSC_ACK) ||
-		    data->out_op_code == WSC_NACK ||
-		    data->out_op_code == WSC_Done) {
-			eap_wsc_state(data, FAIL);
-			ret->methodState = METHOD_DONE;
-		} else
-			eap_wsc_state(data, MESG);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		eap_wsc_state(data, WAIT_FRAG_ACK);
-	}
-
-	return resp;
-}
-
-
-static int eap_wsc_process_cont(struct eap_wsc_data *data,
-				const u8 *buf, size_t len, u8 op_code)
-{
-	/* Process continuation of a pending message */
-	if (op_code != data->in_op_code) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
-			   "fragment (expected %d)",
-			   op_code, data->in_op_code);
-		return -1;
-	}
-
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
-		eap_wsc_state(data, FAIL);
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
-		   "for %lu bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
-						struct eap_method_ret *ret,
-						u8 id, u8 flags, u8 op_code,
-						u16 message_length,
-						const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
-			   "fragmented packet");
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
-				   "message");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		data->in_op_code = op_code;
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
-}
-
-
-static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
-				       struct eap_method_ret *ret,
-				       const struct wpabuf *reqData)
-{
-	struct eap_wsc_data *data = priv;
-	const u8 *start, *pos, *end;
-	size_t len;
-	u8 op_code, flags, id;
-	u16 message_length = 0;
-	enum wps_process_res res;
-	struct wpabuf tmpbuf;
-	struct wpabuf *r;
-
-	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
-			       &len);
-	if (pos == NULL || len < 2) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	id = eap_get_id(reqData);
-
-	start = pos;
-	end = start + len;
-
-	op_code = *pos++;
-	flags = *pos++;
-	if (flags & WSC_FLAGS_LF) {
-		if (end - pos < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		message_length = WPA_GET_BE16(pos);
-		pos += 2;
-
-		if (message_length < end - pos) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
-				   "Length");
-			ret->ignore = TRUE;
-			return NULL;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
-		   "Flags 0x%x Message Length %d",
-		   op_code, flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (op_code != WSC_FRAG_ACK) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
-				   "in WAIT_FRAG_ACK state", op_code);
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
-		eap_wsc_state(data, MESG);
-		return eap_wsc_build_msg(data, ret, id);
-	}
-
-	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
-	    op_code != WSC_Done && op_code != WSC_Start) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
-			   op_code);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->state == WAIT_START) {
-		if (op_code != WSC_Start) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
-				   "in WAIT_START state", op_code);
-			ret->ignore = TRUE;
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
-		eap_wsc_state(data, MESG);
-		/* Start message has empty payload, skip processing */
-		goto send_msg;
-	} else if (op_code == WSC_Start) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
-			   op_code);
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (data->in_buf &&
-	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
-		ret->ignore = TRUE;
-		return NULL;
-	}
-
-	if (flags & WSC_FLAGS_MF) {
-		return eap_wsc_process_fragment(data, ret, id, flags, op_code,
-						message_length, pos,
-						end - pos);
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	res = wps_process_msg(data->wps, op_code, data->in_buf);
-	switch (res) {
-	case WPS_DONE:
-		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
-			   "successfully - wait for EAP failure");
-		eap_wsc_state(data, FAIL);
-		break;
-	case WPS_CONTINUE:
-		eap_wsc_state(data, MESG);
-		break;
-	case WPS_FAILURE:
-	case WPS_PENDING:
-		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
-		eap_wsc_state(data, FAIL);
-		break;
-	}
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-
-send_msg:
-	if (data->out_buf == NULL) {
-		data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
-		if (data->out_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
-				   "message from WPS");
-			return NULL;
-		}
-		data->out_used = 0;
-	}
-
-	eap_wsc_state(data, MESG);
-	r = eap_wsc_build_msg(data, ret, id);
-	if (data->state == FAIL && ret->methodState == METHOD_DONE) {
-		/* Use reduced client timeout for WPS to avoid long wait */
-		if (sm->ClientTimeout > 2)
-			sm->ClientTimeout = 2;
-	}
-	return r;
-}
-
-
-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,
-				    "WSC");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_wsc_init;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_peer/eap_wsc.c (from rev 9639, vendor/wpa/dist/src/eap_peer/eap_wsc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/eap_wsc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/eap_wsc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,562 @@
+/*
+ * EAP-WSC peer for Wi-Fi Protected Setup
+ * Copyright (c) 2007-2009, 2012, Jouni Malinen <j at 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 "uuid.h"
+#include "eap_i.h"
+#include "eap_common/eap_wsc_common.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+
+
+struct eap_wsc_data {
+	enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	int registrar;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	enum wsc_op_code in_op_code, out_op_code;
+	size_t out_used;
+	size_t fragment_size;
+	struct wps_data *wps;
+	struct wps_context *wps_ctx;
+};
+
+
+static const char * eap_wsc_state_txt(int state)
+{
+	switch (state) {
+	case WAIT_START:
+		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:
+		return "?";
+	}
+}
+
+
+static void eap_wsc_state(struct eap_wsc_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
+		   eap_wsc_state_txt(data->state),
+		   eap_wsc_state_txt(state));
+	data->state = state;
+}
+
+
+static int eap_wsc_new_ap_settings(struct wps_credential *cred,
+				   const char *params)
+{
+	const char *pos, *end;
+	size_t len;
+
+	os_memset(cred, 0, sizeof(*cred));
+
+	pos = os_strstr(params, "new_ssid=");
+	if (pos == NULL)
+		return 0;
+	pos += 9;
+	end = os_strchr(pos, ' ');
+	if (end == NULL)
+		len = os_strlen(pos);
+	else
+		len = end - pos;
+	if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
+	    hexstr2bin(pos, cred->ssid, len / 2))
+		return -1;
+	cred->ssid_len = len / 2;
+
+	pos = os_strstr(params, "new_auth=");
+	if (pos == NULL)
+		return -1;
+	if (os_strncmp(pos + 9, "OPEN", 4) == 0)
+		cred->auth_type = WPS_AUTH_OPEN;
+	else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
+		cred->auth_type = WPS_AUTH_WPAPSK;
+	else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
+		cred->auth_type = WPS_AUTH_WPA2PSK;
+	else
+		return -1;
+
+	pos = os_strstr(params, "new_encr=");
+	if (pos == NULL)
+		return -1;
+	if (os_strncmp(pos + 9, "NONE", 4) == 0)
+		cred->encr_type = WPS_ENCR_NONE;
+	else if (os_strncmp(pos + 9, "WEP", 3) == 0)
+		cred->encr_type = WPS_ENCR_WEP;
+	else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
+		cred->encr_type = WPS_ENCR_TKIP;
+	else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
+		cred->encr_type = WPS_ENCR_AES;
+	else
+		return -1;
+
+	pos = os_strstr(params, "new_key=");
+	if (pos == NULL)
+		return 0;
+	pos += 8;
+	end = os_strchr(pos, ' ');
+	if (end == NULL)
+		len = os_strlen(pos);
+	else
+		len = end - pos;
+	if ((len & 1) || len > 2 * sizeof(cred->key) ||
+	    hexstr2bin(pos, cred->key, len / 2))
+		return -1;
+	cred->key_len = len / 2;
+
+	return 1;
+}
+
+
+static void * eap_wsc_init(struct eap_sm *sm)
+{
+	struct eap_wsc_data *data;
+	const u8 *identity;
+	size_t identity_len;
+	int registrar;
+	struct wps_config cfg;
+	const char *pos;
+	const char *phase1;
+	struct wps_context *wps;
+	struct wps_credential new_ap_settings;
+	int res;
+	u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+	int nfc = 0;
+
+	wps = sm->wps;
+	if (wps == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
+		return NULL;
+	}
+
+	identity = eap_get_config_identity(sm, &identity_len);
+
+	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
+		registrar = 1; /* Supplicant is Registrar */
+	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
+	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
+		registrar = 0; /* Supplicant is Enrollee */
+	else {
+		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
+				  identity, identity_len);
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = registrar ? MESG : WAIT_START;
+	data->registrar = registrar;
+	data->wps_ctx = wps;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = wps;
+	cfg.registrar = registrar;
+
+	phase1 = eap_get_config_phase1(sm);
+	if (phase1 == NULL) {
+		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
+			   "set");
+		os_free(data);
+		return NULL;
+	}
+
+	pos = os_strstr(phase1, "pin=");
+	if (pos) {
+		pos += 4;
+		cfg.pin = (const u8 *) pos;
+		while (*pos != '\0' && *pos != ' ')
+			pos++;
+		cfg.pin_len = pos - (const char *) cfg.pin;
+		if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
+		    cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
+		    hexstr2bin((const char *) cfg.pin, dev_pw,
+			       cfg.pin_len / 2) == 0) {
+			/* Convert OOB Device Password to binary */
+			cfg.pin = dev_pw;
+			cfg.pin_len /= 2;
+		}
+		if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+			cfg.pin = NULL;
+			cfg.pin_len = 0;
+			nfc = 1;
+		}
+	} else {
+		pos = os_strstr(phase1, "pbc=1");
+		if (pos)
+			cfg.pbc = 1;
+	}
+
+	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
+		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
+			   "configuration data");
+		os_free(data);
+		return NULL;
+	}
+
+	pos = os_strstr(phase1, "dev_pw_id=");
+	if (pos && cfg.pin)
+		cfg.dev_pw_id = atoi(pos + 10);
+
+	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
+	if (res < 0) {
+		os_free(data);
+		return NULL;
+	}
+	if (res == 1) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
+			   "WPS");
+		cfg.new_ap_settings = &new_ap_settings;
+	}
+
+	data->wps = wps_init(&cfg);
+	if (data->wps == NULL) {
+		os_free(data);
+		return NULL;
+	}
+	res = eap_get_config_fragment_size(sm);
+	if (res > 0)
+		data->fragment_size = res;
+	else
+		data->fragment_size = WSC_FRAGMENT_SIZE;
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
+		   (unsigned int) data->fragment_size);
+
+	if (registrar && cfg.pin) {
+		wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
+				      cfg.pin, cfg.pin_len, 0);
+	}
+
+	/* Use reduced client timeout for WPS to avoid long wait */
+	if (sm->ClientTimeout > 30)
+		sm->ClientTimeout = 30;
+
+	return data;
+}
+
+
+static void eap_wsc_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	wps_deinit(data->wps);
+	os_free(data->wps_ctx->network_key);
+	data->wps_ctx->network_key = NULL;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,
+					 struct eap_method_ret *ret, u8 id)
+{
+	struct wpabuf *resp;
+	u8 flags;
+	size_t send_len, plen;
+
+	ret->ignore = FALSE;
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (2 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 2;
+		flags |= WSC_FLAGS_MF;
+		if (data->out_used == 0) {
+			flags |= WSC_FLAGS_LF;
+			send_len -= 2;
+		}
+	}
+	plen = 2 + send_len;
+	if (flags & WSC_FLAGS_LF)
+		plen += 2;
+	resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
+	wpabuf_put_u8(resp, flags); /* Flags */
+	if (flags & WSC_FLAGS_LF)
+		wpabuf_put_be16(resp, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		if ((data->state == FAIL && data->out_op_code == WSC_ACK) ||
+		    data->out_op_code == WSC_NACK ||
+		    data->out_op_code == WSC_Done) {
+			eap_wsc_state(data, FAIL);
+			ret->methodState = METHOD_DONE;
+		} else
+			eap_wsc_state(data, MESG);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_wsc_state(data, WAIT_FRAG_ACK);
+	}
+
+	return resp;
+}
+
+
+static int eap_wsc_process_cont(struct eap_wsc_data *data,
+				const u8 *buf, size_t len, u8 op_code)
+{
+	/* Process continuation of a pending message */
+	if (op_code != data->in_op_code) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
+			   "fragment (expected %d)",
+			   op_code, data->in_op_code);
+		return -1;
+	}
+
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
+		   "for %lu bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
+						struct eap_method_ret *ret,
+						u8 id, u8 flags, u8 op_code,
+						u16 message_length,
+						const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
+			   "fragmented packet");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
+				   "message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		data->in_op_code = op_code;
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
+}
+
+
+static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_wsc_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 op_code, flags, id;
+	u16 message_length = 0;
+	enum wps_process_res res;
+	struct wpabuf tmpbuf;
+	struct wpabuf *r;
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
+			       &len);
+	if (pos == NULL || len < 2) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+
+	start = pos;
+	end = start + len;
+
+	op_code = *pos++;
+	flags = *pos++;
+	if (flags & WSC_FLAGS_LF) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		message_length = WPA_GET_BE16(pos);
+		pos += 2;
+
+		if (message_length < end - pos) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
+				   "Length");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
+		   "Flags 0x%x Message Length %d",
+		   op_code, flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (op_code != WSC_FRAG_ACK) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_FRAG_ACK state", op_code);
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
+		eap_wsc_state(data, MESG);
+		return eap_wsc_build_msg(data, ret, id);
+	}
+
+	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
+	    op_code != WSC_Done && op_code != WSC_Start) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == WAIT_START) {
+		if (op_code != WSC_Start) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_START state", op_code);
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
+		eap_wsc_state(data, MESG);
+		/* Start message has empty payload, skip processing */
+		goto send_msg;
+	} else if (op_code == WSC_Start) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf &&
+	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (flags & WSC_FLAGS_MF) {
+		return eap_wsc_process_fragment(data, ret, id, flags, op_code,
+						message_length, pos,
+						end - pos);
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	res = wps_process_msg(data->wps, op_code, data->in_buf);
+	switch (res) {
+	case WPS_DONE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
+			   "successfully - wait for EAP failure");
+		eap_wsc_state(data, FAIL);
+		break;
+	case WPS_CONTINUE:
+		eap_wsc_state(data, MESG);
+		break;
+	case WPS_FAILURE:
+	case WPS_PENDING:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
+		eap_wsc_state(data, FAIL);
+		break;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+
+send_msg:
+	if (data->out_buf == NULL) {
+		data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
+		if (data->out_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
+				   "message from WPS");
+			return NULL;
+		}
+		data->out_used = 0;
+	}
+
+	eap_wsc_state(data, MESG);
+	r = eap_wsc_build_msg(data, ret, id);
+	if (data->state == FAIL && ret->methodState == METHOD_DONE) {
+		/* Use reduced client timeout for WPS to avoid long wait */
+		if (sm->ClientTimeout > 2)
+			sm->ClientTimeout = 2;
+	}
+	return r;
+}
+
+
+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,
+				    "WSC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_wsc_init;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/ikev2.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/ikev2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1303 +0,0 @@
-/*
- * IKEv2 responder (RFC 4306) for EAP-IKEV2
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/dh_groups.h"
-#include "ikev2.h"
-
-
-void ikev2_responder_deinit(struct ikev2_responder_data *data)
-{
-	ikev2_free_keys(&data->keys);
-	wpabuf_free(data->i_dh_public);
-	wpabuf_free(data->r_dh_private);
-	os_free(data->IDi);
-	os_free(data->IDr);
-	os_free(data->shared_secret);
-	wpabuf_free(data->i_sign_msg);
-	wpabuf_free(data->r_sign_msg);
-	os_free(data->key_pad);
-}
-
-
-static int ikev2_derive_keys(struct ikev2_responder_data *data)
-{
-	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
-	size_t buf_len, pad_len;
-	struct wpabuf *shared;
-	const struct ikev2_integ_alg *integ;
-	const struct ikev2_prf_alg *prf;
-	const struct ikev2_encr_alg *encr;
-	int ret;
-	const u8 *addr[2];
-	size_t len[2];
-
-	/* RFC 4306, Sect. 2.14 */
-
-	integ = ikev2_get_integ(data->proposal.integ);
-	prf = ikev2_get_prf(data->proposal.prf);
-	encr = ikev2_get_encr(data->proposal.encr);
-	if (integ == NULL || prf == NULL || encr == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
-		return -1;
-	}
-
-	shared = dh_derive_shared(data->i_dh_public, data->r_dh_private,
-				  data->dh);
-	if (shared == NULL)
-		return -1;
-
-	/* Construct Ni | Nr | SPIi | SPIr */
-
-	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
-	buf = os_malloc(buf_len);
-	if (buf == NULL) {
-		wpabuf_free(shared);
-		return -1;
-	}
-
-	pos = buf;
-	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
-	pos += data->i_nonce_len;
-	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
-	pos += data->r_nonce_len;
-	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
-	pos += IKEV2_SPI_LEN;
-	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
-#ifdef CCNS_PL
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-	{
-		int i;
-		u8 *tmp = pos - IKEV2_SPI_LEN;
-		/* Incorrect byte re-ordering on little endian hosts.. */
-		for (i = 0; i < IKEV2_SPI_LEN; i++)
-			*tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
-		for (i = 0; i < IKEV2_SPI_LEN; i++)
-			*tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
-	}
-#endif
-#endif /* CCNS_PL */
-
-	/* SKEYSEED = prf(Ni | Nr, g^ir) */
-	/* Use zero-padding per RFC 4306, Sect. 2.14 */
-	pad_len = data->dh->prime_len - wpabuf_len(shared);
-#ifdef CCNS_PL
-	/* Shared secret is not zero-padded correctly */
-	pad_len = 0;
-#endif /* CCNS_PL */
-	pad = os_zalloc(pad_len ? pad_len : 1);
-	if (pad == NULL) {
-		wpabuf_free(shared);
-		os_free(buf);
-		return -1;
-	}
-
-	addr[0] = pad;
-	len[0] = pad_len;
-	addr[1] = wpabuf_head(shared);
-	len[1] = wpabuf_len(shared);
-	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
-			   2, addr, len, skeyseed) < 0) {
-		wpabuf_free(shared);
-		os_free(buf);
-		os_free(pad);
-		return -1;
-	}
-	os_free(pad);
-	wpabuf_free(shared);
-
-	/* DH parameters are not needed anymore, so free them */
-	wpabuf_free(data->i_dh_public);
-	data->i_dh_public = NULL;
-	wpabuf_free(data->r_dh_private);
-	data->r_dh_private = NULL;
-
-	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
-			skeyseed, prf->hash_len);
-
-	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
-				   &data->keys);
-	os_free(buf);
-	return ret;
-}
-
-
-static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
-				 const u8 *pos, const u8 *end)
-{
-	int transform_len;
-	const struct ikev2_transform *t;
-	u16 transform_id;
-	const u8 *tend;
-
-	if (end - pos < (int) sizeof(*t)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
-		return -1;
-	}
-
-	t = (const struct ikev2_transform *) pos;
-	transform_len = WPA_GET_BE16(t->transform_length);
-	if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
-			   transform_len);
-		return -1;
-	}
-	tend = pos + transform_len;
-
-	transform_id = WPA_GET_BE16(t->transform_id);
-
-	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
-	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
-		   "Transform Type: %d  Transform ID: %d",
-		   t->type, transform_len, t->transform_type, transform_id);
-
-	if (t->type != 0 && t->type != 3) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
-		return -1;
-	}
-
-	pos = (const u8 *) (t + 1);
-	if (pos < tend) {
-		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
-			    pos, tend - pos);
-	}
-
-	switch (t->transform_type) {
-	case IKEV2_TRANSFORM_ENCR:
-		if (ikev2_get_encr(transform_id)) {
-			if (transform_id == ENCR_AES_CBC) {
-				if (tend - pos != 4) {
-					wpa_printf(MSG_DEBUG, "IKEV2: No "
-						   "Transform Attr for AES");
-					break;
-				}
-#ifdef CCNS_PL
-				if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
-					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
-						   "Key Size attribute for "
-						   "AES");
-					break;
-				}
-#else /* CCNS_PL */
-				if (WPA_GET_BE16(pos) != 0x800e) {
-					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
-						   "Key Size attribute for "
-						   "AES");
-					break;
-				}
-#endif /* CCNS_PL */
-				if (WPA_GET_BE16(pos + 2) != 128) {
-					wpa_printf(MSG_DEBUG, "IKEV2: "
-						   "Unsupported AES key size "
-						   "%d bits",
-						   WPA_GET_BE16(pos + 2));
-					break;
-				}
-			}
-			prop->encr = transform_id;
-		}
-		break;
-	case IKEV2_TRANSFORM_PRF:
-		if (ikev2_get_prf(transform_id))
-			prop->prf = transform_id;
-		break;
-	case IKEV2_TRANSFORM_INTEG:
-		if (ikev2_get_integ(transform_id))
-			prop->integ = transform_id;
-		break;
-	case IKEV2_TRANSFORM_DH:
-		if (dh_groups_get(transform_id))
-			prop->dh = transform_id;
-		break;
-	}
-
-	return transform_len;
-}
-
-
-static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
-				const u8 *pos, const u8 *end)
-{
-	const u8 *pend, *ppos;
-	int proposal_len, i;
-	const struct ikev2_proposal *p;
-
-	if (end - pos < (int) sizeof(*p)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
-		return -1;
-	}
-
-	/* FIX: AND processing if multiple proposals use the same # */
-
-	p = (const struct ikev2_proposal *) pos;
-	proposal_len = WPA_GET_BE16(p->proposal_length);
-	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
-			   proposal_len);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
-		   p->proposal_num);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
-		   " Protocol ID: %d",
-		   p->type, proposal_len, p->protocol_id);
-	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
-		   p->spi_size, p->num_transforms);
-
-	if (p->type != 0 && p->type != 2) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
-		return -1;
-	}
-
-	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
-			   "(only IKE allowed for EAP-IKEv2)");
-		return -1;
-	}
-
-	if (p->proposal_num != prop->proposal_num) {
-		if (p->proposal_num == prop->proposal_num + 1)
-			prop->proposal_num = p->proposal_num;
-		else {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
-			return -1;
-		}
-	}
-
-	ppos = (const u8 *) (p + 1);
-	pend = pos + proposal_len;
-	if (ppos + p->spi_size > pend) {
-		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
-			   "in proposal");
-		return -1;
-	}
-	if (p->spi_size) {
-		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
-			    ppos, p->spi_size);
-		ppos += p->spi_size;
-	}
-
-	/*
-	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
-	 * subsequent negotiations, it must be 8 for IKE. We only support
-	 * initial case for now.
-	 */
-	if (p->spi_size != 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
-		return -1;
-	}
-
-	if (p->num_transforms == 0) {
-		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
-		return -1;
-	}
-
-	for (i = 0; i < (int) p->num_transforms; i++) {
-		int tlen = ikev2_parse_transform(prop, ppos, pend);
-		if (tlen < 0)
-			return -1;
-		ppos += tlen;
-	}
-
-	if (ppos != pend) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
-			   "transforms");
-		return -1;
-	}
-
-	return proposal_len;
-}
-
-
-static int ikev2_process_sai1(struct ikev2_responder_data *data,
-			      const u8 *sai1, size_t sai1_len)
-{
-	struct ikev2_proposal_data prop;
-	const u8 *pos, *end;
-	int found = 0;
-
-	/* Security Association Payloads: <Proposals> */
-
-	if (sai1 == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: SAi1 not received");
-		return -1;
-	}
-
-	os_memset(&prop, 0, sizeof(prop));
-	prop.proposal_num = 1;
-
-	pos = sai1;
-	end = sai1 + sai1_len;
-
-	while (pos < end) {
-		int plen;
-
-		prop.integ = -1;
-		prop.prf = -1;
-		prop.encr = -1;
-		prop.dh = -1;
-		plen = ikev2_parse_proposal(&prop, pos, end);
-		if (plen < 0)
-			return -1;
-
-		if (!found && prop.integ != -1 && prop.prf != -1 &&
-		    prop.encr != -1 && prop.dh != -1) {
-			os_memcpy(&data->proposal, &prop, sizeof(prop));
-			data->dh = dh_groups_get(prop.dh);
-			found = 1;
-		}
-
-		pos += plen;
-	}
-
-	if (pos != end) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals");
-		return -1;
-	}
-
-	if (!found) {
-		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
-		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
-		   data->proposal.encr, data->proposal.prf,
-		   data->proposal.integ, data->proposal.dh);
-
-	return 0;
-}
-
-
-static int ikev2_process_kei(struct ikev2_responder_data *data,
-			     const u8 *kei, size_t kei_len)
-{
-	u16 group;
-
-	/*
-	 * Key Exchange Payload:
-	 * DH Group # (16 bits)
-	 * RESERVED (16 bits)
-	 * Key Exchange Data (Diffie-Hellman public value)
-	 */
-
-	if (kei == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: KEi not received");
-		return -1;
-	}
-
-	if (kei_len < 4 + 96) {
-		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
-		return -1;
-	}
-
-	group = WPA_GET_BE16(kei);
-	wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group);
-
-	if (group != data->proposal.dh) {
-		wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match "
-			   "with the selected proposal (%u)",
-			   group, data->proposal.dh);
-		/* Reject message with Notify payload of type
-		 * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */
-		data->error_type = INVALID_KE_PAYLOAD;
-		data->state = NOTIFY;
-		return -1;
-	}
-
-	if (data->dh == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
-		return -1;
-	}
-
-	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
-	 * prime modulus.
-	 */
-	if (kei_len - 4 != data->dh->prime_len) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
-			   "%ld (expected %ld)",
-			   (long) (kei_len - 4), (long) data->dh->prime_len);
-		return -1;
-	}
-
-	wpabuf_free(data->i_dh_public);
-	data->i_dh_public = wpabuf_alloc(kei_len - 4);
-	if (data->i_dh_public == NULL)
-		return -1;
-	wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4);
-
-	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
-			data->i_dh_public);
-	
-	return 0;
-}
-
-
-static int ikev2_process_ni(struct ikev2_responder_data *data,
-			    const u8 *ni, size_t ni_len)
-{
-	if (ni == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Ni not received");
-		return -1;
-	}
-
-	if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld",
-		           (long) ni_len);
-		return -1;
-	}
-
-#ifdef CCNS_PL
-	/* Zeros are removed incorrectly from the beginning of the nonces */
-	while (ni_len > 1 && *ni == 0) {
-		ni_len--;
-		ni++;
-	}
-#endif /* CCNS_PL */
-
-	data->i_nonce_len = ni_len;
-	os_memcpy(data->i_nonce, ni, ni_len);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
-		    data->i_nonce, data->i_nonce_len);
-
-	return 0;
-}
-
-
-static int ikev2_process_sa_init(struct ikev2_responder_data *data,
-				 const struct ikev2_hdr *hdr,
-				 struct ikev2_payloads *pl)
-{
-	if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 ||
-	    ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 ||
-	    ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0)
-		return -1;
-
-	os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN);
-
-	return 0;
-}
-
-
-static int ikev2_process_idi(struct ikev2_responder_data *data,
-			     const u8 *idi, size_t idi_len)
-{
-	u8 id_type;
-
-	if (idi == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No IDi received");
-		return -1;
-	}
-
-	if (idi_len < 4) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload");
-		return -1;
-	}
-
-	id_type = idi[0];
-	idi += 4;
-	idi_len -= 4;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type);
-	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len);
-	os_free(data->IDi);
-	data->IDi = os_malloc(idi_len);
-	if (data->IDi == NULL)
-		return -1;
-	os_memcpy(data->IDi, idi, idi_len);
-	data->IDi_len = idi_len;
-	data->IDi_type = id_type;
-
-	return 0;
-}
-
-
-static int ikev2_process_cert(struct ikev2_responder_data *data,
-			      const u8 *cert, size_t cert_len)
-{
-	u8 cert_encoding;
-
-	if (cert == NULL) {
-		if (data->peer_auth == PEER_AUTH_CERT) {
-			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
-			return -1;
-		}
-		return 0;
-	}
-
-	if (cert_len < 1) {
-		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
-		return -1;
-	}
-
-	cert_encoding = cert[0];
-	cert++;
-	cert_len--;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
-
-	/* TODO: validate certificate */
-
-	return 0;
-}
-
-
-static int ikev2_process_auth_cert(struct ikev2_responder_data *data,
-				   u8 method, const u8 *auth, size_t auth_len)
-{
-	if (method != AUTH_RSA_SIGN) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
-			   "method %d", method);
-		return -1;
-	}
-
-	/* TODO: validate AUTH */
-	return 0;
-}
-
-
-static int ikev2_process_auth_secret(struct ikev2_responder_data *data,
-				     u8 method, const u8 *auth,
-				     size_t auth_len)
-{
-	u8 auth_data[IKEV2_MAX_HASH_LEN];
-	const struct ikev2_prf_alg *prf;
-
-	if (method != AUTH_SHARED_KEY_MIC) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
-			   "method %d", method);
-		return -1;
-	}
-
-	/* msg | Nr | prf(SK_pi,IDi') */
-	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
-				   data->IDi, data->IDi_len, data->IDi_type,
-				   &data->keys, 1, data->shared_secret,
-				   data->shared_secret_len,
-				   data->r_nonce, data->r_nonce_len,
-				   data->key_pad, data->key_pad_len,
-				   auth_data) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
-		return -1;
-	}
-
-	wpabuf_free(data->i_sign_msg);
-	data->i_sign_msg = NULL;
-
-	prf = ikev2_get_prf(data->proposal.prf);
-	if (prf == NULL)
-		return -1;
-
-	if (auth_len != prf->hash_len ||
-	    os_memcmp(auth, auth_data, auth_len) != 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
-		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
-			    auth, auth_len);
-		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
-			    auth_data, prf->hash_len);
-		data->error_type = AUTHENTICATION_FAILED;
-		data->state = NOTIFY;
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully "
-		   "using shared keys");
-
-	return 0;
-}
-
-
-static int ikev2_process_auth(struct ikev2_responder_data *data,
-			      const u8 *auth, size_t auth_len)
-{
-	u8 auth_method;
-
-	if (auth == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
-		return -1;
-	}
-
-	if (auth_len < 4) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
-			   "Payload");
-		return -1;
-	}
-
-	auth_method = auth[0];
-	auth += 4;
-	auth_len -= 4;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
-
-	switch (data->peer_auth) {
-	case PEER_AUTH_CERT:
-		return ikev2_process_auth_cert(data, auth_method, auth,
-					       auth_len);
-	case PEER_AUTH_SECRET:
-		return ikev2_process_auth_secret(data, auth_method, auth,
-						 auth_len);
-	}
-
-	return -1;
-}
-
-
-static int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data,
-					   u8 next_payload,
-					   u8 *payload, size_t payload_len)
-{
-	struct ikev2_payloads pl;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
-
-	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
-				 payload_len) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
-			   "payloads");
-		return -1;
-	}
-
-	if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 ||
-	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
-	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
-		return -1;
-
-	return 0;
-}
-
-
-static int ikev2_process_sa_auth(struct ikev2_responder_data *data,
-				 const struct ikev2_hdr *hdr,
-				 struct ikev2_payloads *pl)
-{
-	u8 *decrypted;
-	size_t decrypted_len;
-	int ret;
-
-	decrypted = ikev2_decrypt_payload(data->proposal.encr,
-					  data->proposal.integ,
-					  &data->keys, 1, hdr, pl->encrypted,
-					  pl->encrypted_len, &decrypted_len);
-	if (decrypted == NULL)
-		return -1;
-
-	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
-					      decrypted, decrypted_len);
-	os_free(decrypted);
-
-	return ret;
-}
-
-
-static int ikev2_validate_rx_state(struct ikev2_responder_data *data,
-				   u8 exchange_type, u32 message_id)
-{
-	switch (data->state) {
-	case SA_INIT:
-		/* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */
-		if (exchange_type != IKE_SA_INIT) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in SA_INIT state", exchange_type);
-			return -1;
-		}
-		if (message_id != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in SA_INIT state", message_id);
-			return -1;
-		}
-		break;
-	case SA_AUTH:
-		/* Expect to receive IKE_SA_AUTH:
-		 * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,]
-		 *	AUTH, SAi2, TSi, TSr}
-		 */
-		if (exchange_type != IKE_SA_AUTH) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in SA_AUTH state", exchange_type);
-			return -1;
-		}
-		if (message_id != 1) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in SA_AUTH state", message_id);
-			return -1;
-		}
-		break;
-	case CHILD_SA:
-		if (exchange_type != CREATE_CHILD_SA) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in CHILD_SA state", exchange_type);
-			return -1;
-		}
-		if (message_id != 2) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in CHILD_SA state", message_id);
-			return -1;
-		}
-		break;
-	case NOTIFY:
-	case IKEV2_DONE:
-	case IKEV2_FAILED:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int ikev2_responder_process(struct ikev2_responder_data *data,
-			    const struct wpabuf *buf)
-{
-	const struct ikev2_hdr *hdr;
-	u32 length, message_id;
-	const u8 *pos, *end;
-	struct ikev2_payloads pl;
-
-	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
-		   (unsigned long) wpabuf_len(buf));
-
-	if (wpabuf_len(buf) < sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
-		return -1;
-	}
-
-	data->error_type = 0;
-	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
-	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
-	message_id = WPA_GET_BE32(hdr->message_id);
-	length = WPA_GET_BE32(hdr->length);
-
-	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
-		    hdr->i_spi, IKEV2_SPI_LEN);
-	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Responder's SPI",
-		    hdr->r_spi, IKEV2_SPI_LEN);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
-		   "Exchange Type: %u",
-		   hdr->next_payload, hdr->version, hdr->exchange_type);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
-		   message_id, length);
-
-	if (hdr->version != IKEV2_VERSION) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
-			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
-		return -1;
-	}
-
-	if (length != wpabuf_len(buf)) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
-			   "RX: %lu)", (unsigned long) length,
-			   (unsigned long) wpabuf_len(buf));
-		return -1;
-	}
-
-	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
-		return -1;
-
-	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
-	    IKEV2_HDR_INITIATOR) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
-			   hdr->flags);
-		return -1;
-	}
-
-	if (data->state != SA_INIT) {
-		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
-				   "Initiator's SPI");
-			return -1;
-		}
-		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
-				   "Responder's SPI");
-			return -1;
-		}
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
-		return -1;
-
-	if (data->state == SA_INIT) {
-		data->last_msg = LAST_MSG_SA_INIT;
-		if (ikev2_process_sa_init(data, hdr, &pl) < 0) {
-			if (data->state == NOTIFY)
-				return 0;
-			return -1;
-		}
-		wpabuf_free(data->i_sign_msg);
-		data->i_sign_msg = wpabuf_dup(buf);
-	}
-
-	if (data->state == SA_AUTH) {
-		data->last_msg = LAST_MSG_SA_AUTH;
-		if (ikev2_process_sa_auth(data, hdr, &pl) < 0) {
-			if (data->state == NOTIFY)
-				return 0;
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static void ikev2_build_hdr(struct ikev2_responder_data *data,
-			    struct wpabuf *msg, u8 exchange_type,
-			    u8 next_payload, u32 message_id)
-{
-	struct ikev2_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
-
-	/* HDR - RFC 4306, Sect. 3.1 */
-	hdr = wpabuf_put(msg, sizeof(*hdr));
-	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
-	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
-	hdr->next_payload = next_payload;
-	hdr->version = IKEV2_VERSION;
-	hdr->exchange_type = exchange_type;
-	hdr->flags = IKEV2_HDR_RESPONSE;
-	WPA_PUT_BE32(hdr->message_id, message_id);
-}
-
-
-static int ikev2_build_sar1(struct ikev2_responder_data *data,
-			    struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	struct ikev2_proposal *p;
-	struct ikev2_transform *t;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload");
-
-	/* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-
-	p = wpabuf_put(msg, sizeof(*p));
-#ifdef CCNS_PL
-	/* Seems to require that the Proposal # is 1 even though RFC 4306
-	 * Sect 3.3.1 has following requirement "When a proposal is accepted,
-	 * all of the proposal numbers in the SA payload MUST be the same and
-	 * MUST match the number on the proposal sent that was accepted.".
-	 */
-	p->proposal_num = 1;
-#else /* CCNS_PL */
-	p->proposal_num = data->proposal.proposal_num;
-#endif /* CCNS_PL */
-	p->protocol_id = IKEV2_PROTOCOL_IKE;
-	p->num_transforms = 4;
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	t->transform_type = IKEV2_TRANSFORM_ENCR;
-	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
-	if (data->proposal.encr == ENCR_AES_CBC) {
-		/* Transform Attribute: Key Len = 128 bits */
-#ifdef CCNS_PL
-		wpabuf_put_be16(msg, 0x001d); /* ?? */
-#else /* CCNS_PL */
-		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
-#endif /* CCNS_PL */
-		wpabuf_put_be16(msg, 128); /* 128-bit key */
-	}
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
-	WPA_PUT_BE16(t->transform_length, plen);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_PRF;
-	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_INTEG;
-	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_DH;
-	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
-	WPA_PUT_BE16(p->proposal_length, plen);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-
-	return 0;
-}
-
-
-static int ikev2_build_ker(struct ikev2_responder_data *data,
-			   struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	struct wpabuf *pv;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload");
-
-	pv = dh_init(data->dh, &data->r_dh_private);
-	if (pv == NULL) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
-		return -1;
-	}
-
-	/* KEr - RFC 4306, Sect. 3.4 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-
-	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
-	wpabuf_put(msg, 2); /* RESERVED */
-	/*
-	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
-	 * match the length of the prime.
-	 */
-	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
-	wpabuf_put_buf(msg, pv);
-	wpabuf_free(pv);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_nr(struct ikev2_responder_data *data,
-			  struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload");
-
-	/* Nr - RFC 4306, Sect. 3.9 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len);
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_idr(struct ikev2_responder_data *data,
-			   struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload");
-
-	if (data->IDr == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No IDr available");
-		return -1;
-	}
-
-	/* IDr - RFC 4306, Sect. 3.5 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_u8(msg, ID_KEY_ID);
-	wpabuf_put(msg, 3); /* RESERVED */
-	wpabuf_put_data(msg, data->IDr, data->IDr_len);
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_auth(struct ikev2_responder_data *data,
-			    struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	const struct ikev2_prf_alg *prf;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
-
-	prf = ikev2_get_prf(data->proposal.prf);
-	if (prf == NULL)
-		return -1;
-
-	/* Authentication - RFC 4306, Sect. 3.8 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
-	wpabuf_put(msg, 3); /* RESERVED */
-
-	/* msg | Ni | prf(SK_pr,IDr') */
-	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
-				   data->IDr, data->IDr_len, ID_KEY_ID,
-				   &data->keys, 0, data->shared_secret,
-				   data->shared_secret_len,
-				   data->i_nonce, data->i_nonce_len,
-				   data->key_pad, data->key_pad_len,
-				   wpabuf_put(msg, prf->hash_len)) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
-		return -1;
-	}
-	wpabuf_free(data->r_sign_msg);
-	data->r_sign_msg = NULL;
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_notification(struct ikev2_responder_data *data,
-				    struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload");
-
-	if (data->error_type == 0) {
-		wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type "
-			   "available");
-		return -1;
-	}
-
-	/* Notify - RFC 4306, Sect. 3.10 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-#ifdef CCNS_PL
-	wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
-#else /* CCNS_PL */
-	wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
-#endif /* CCNS_PL */
-	wpabuf_put_u8(msg, 0); /* SPI Size */
-	wpabuf_put_be16(msg, data->error_type);
-
-	switch (data->error_type) {
-	case INVALID_KE_PAYLOAD:
-		if (data->proposal.dh == -1) {
-			wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for "
-				   "INVALID_KE_PAYLOAD notifications");
-			return -1;
-		}
-		wpabuf_put_be16(msg, data->proposal.dh);
-		wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request "
-			   "DH Group #%d", data->proposal.dh);
-		break;
-	case AUTHENTICATION_FAILED:
-		/* no associated data */
-		break;
-	default:
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type "
-			   "%d", data->error_type);
-		return -1;
-	}
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
-{
-	struct wpabuf *msg;
-
-	/* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */
-
-	if (os_get_random(data->r_spi, IKEV2_SPI_LEN))
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI",
-		    data->r_spi, IKEV2_SPI_LEN);
-
-	data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
-	if (os_get_random(data->r_nonce, data->r_nonce_len))
-		return NULL;
-#ifdef CCNS_PL
-	/* Zeros are removed incorrectly from the beginning of the nonces in
-	 * key derivation; as a workaround, make sure Nr does not start with
-	 * zero.. */
-	if (data->r_nonce[0] == 0)
-		data->r_nonce[0] = 1;
-#endif /* CCNS_PL */
-	wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
-
-	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
-	if (msg == NULL)
-		return NULL;
-
-	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
-	if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
-	    ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) ||
-	    ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ?
-			   IKEV2_PAYLOAD_ENCRYPTED :
-			   IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	if (ikev2_derive_keys(data)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	if (data->peer_auth == PEER_AUTH_CERT) {
-		/* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info
-		 * for trust agents */
-	}
-
-	if (data->peer_auth == PEER_AUTH_SECRET) {
-		struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000);
-		if (plain == NULL) {
-			wpabuf_free(msg);
-			return NULL;
-		}
-		if (ikev2_build_idr(data, plain,
-				    IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
-		    ikev2_build_encrypted(data->proposal.encr,
-					  data->proposal.integ,
-					  &data->keys, 0, msg, plain,
-					  IKEV2_PAYLOAD_IDr)) {
-			wpabuf_free(plain);
-			wpabuf_free(msg);
-			return NULL;
-		}
-		wpabuf_free(plain);
-	}
-
-	ikev2_update_hdr(msg);
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
-
-	data->state = SA_AUTH;
-
-	wpabuf_free(data->r_sign_msg);
-	data->r_sign_msg = wpabuf_dup(msg);
-
-	return msg;
-}
-
-
-static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data)
-{
-	struct wpabuf *msg, *plain;
-
-	/* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */
-
-	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
-	if (msg == NULL)
-		return NULL;
-	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
-
-	plain = wpabuf_alloc(data->IDr_len + 1000);
-	if (plain == NULL) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
-	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
-	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
-				  &data->keys, 0, msg, plain,
-				  IKEV2_PAYLOAD_IDr)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
-
-	data->state = IKEV2_DONE;
-
-	return msg;
-}
-
-
-static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data)
-{
-	struct wpabuf *msg;
-
-	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
-	if (msg == NULL)
-		return NULL;
-	if (data->last_msg == LAST_MSG_SA_AUTH) {
-		/* HDR, SK{N} */
-		struct wpabuf *plain = wpabuf_alloc(100);
-		if (plain == NULL) {
-			wpabuf_free(msg);
-			return NULL;
-		}
-		ikev2_build_hdr(data, msg, IKE_SA_AUTH,
-				IKEV2_PAYLOAD_ENCRYPTED, 1);
-		if (ikev2_build_notification(data, plain,
-					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
-		    ikev2_build_encrypted(data->proposal.encr,
-					  data->proposal.integ,
-					  &data->keys, 0, msg, plain,
-					  IKEV2_PAYLOAD_NOTIFICATION)) {
-			wpabuf_free(plain);
-			wpabuf_free(msg);
-			return NULL;
-		}
-		data->state = IKEV2_FAILED;
-	} else {
-		/* HDR, N */
-		ikev2_build_hdr(data, msg, IKE_SA_INIT,
-				IKEV2_PAYLOAD_NOTIFICATION, 0);
-		if (ikev2_build_notification(data, msg,
-					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
-			wpabuf_free(msg);
-			return NULL;
-		}
-		data->state = SA_INIT;
-	}
-
-	ikev2_update_hdr(msg);
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)",
-			msg);
-
-	return msg;
-}
-
-
-struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data)
-{
-	switch (data->state) {
-	case SA_INIT:
-		return ikev2_build_sa_init(data);
-	case SA_AUTH:
-		return ikev2_build_sa_auth(data);
-	case CHILD_SA:
-		return NULL;
-	case NOTIFY:
-		return ikev2_build_notify(data);
-	case IKEV2_DONE:
-	case IKEV2_FAILED:
-		return NULL;
-	}
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/eap_peer/ikev2.c (from rev 9639, vendor/wpa/dist/src/eap_peer/ikev2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/ikev2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1298 @@
+/*
+ * IKEv2 responder (RFC 4306) for EAP-IKEV2
+ * Copyright (c) 2007, Jouni Malinen <j at 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/dh_groups.h"
+#include "crypto/random.h"
+#include "ikev2.h"
+
+
+void ikev2_responder_deinit(struct ikev2_responder_data *data)
+{
+	ikev2_free_keys(&data->keys);
+	wpabuf_free(data->i_dh_public);
+	wpabuf_free(data->r_dh_private);
+	os_free(data->IDi);
+	os_free(data->IDr);
+	os_free(data->shared_secret);
+	wpabuf_free(data->i_sign_msg);
+	wpabuf_free(data->r_sign_msg);
+	os_free(data->key_pad);
+}
+
+
+static int ikev2_derive_keys(struct ikev2_responder_data *data)
+{
+	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
+	size_t buf_len, pad_len;
+	struct wpabuf *shared;
+	const struct ikev2_integ_alg *integ;
+	const struct ikev2_prf_alg *prf;
+	const struct ikev2_encr_alg *encr;
+	int ret;
+	const u8 *addr[2];
+	size_t len[2];
+
+	/* RFC 4306, Sect. 2.14 */
+
+	integ = ikev2_get_integ(data->proposal.integ);
+	prf = ikev2_get_prf(data->proposal.prf);
+	encr = ikev2_get_encr(data->proposal.encr);
+	if (integ == NULL || prf == NULL || encr == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
+		return -1;
+	}
+
+	shared = dh_derive_shared(data->i_dh_public, data->r_dh_private,
+				  data->dh);
+	if (shared == NULL)
+		return -1;
+
+	/* Construct Ni | Nr | SPIi | SPIr */
+
+	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
+	buf = os_malloc(buf_len);
+	if (buf == NULL) {
+		wpabuf_free(shared);
+		return -1;
+	}
+
+	pos = buf;
+	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
+	pos += data->i_nonce_len;
+	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
+	pos += data->r_nonce_len;
+	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
+	pos += IKEV2_SPI_LEN;
+	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
+#ifdef CCNS_PL
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	{
+		int i;
+		u8 *tmp = pos - IKEV2_SPI_LEN;
+		/* Incorrect byte re-ordering on little endian hosts.. */
+		for (i = 0; i < IKEV2_SPI_LEN; i++)
+			*tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
+		for (i = 0; i < IKEV2_SPI_LEN; i++)
+			*tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
+	}
+#endif
+#endif /* CCNS_PL */
+
+	/* SKEYSEED = prf(Ni | Nr, g^ir) */
+	/* Use zero-padding per RFC 4306, Sect. 2.14 */
+	pad_len = data->dh->prime_len - wpabuf_len(shared);
+#ifdef CCNS_PL
+	/* Shared secret is not zero-padded correctly */
+	pad_len = 0;
+#endif /* CCNS_PL */
+	pad = os_zalloc(pad_len ? pad_len : 1);
+	if (pad == NULL) {
+		wpabuf_free(shared);
+		os_free(buf);
+		return -1;
+	}
+
+	addr[0] = pad;
+	len[0] = pad_len;
+	addr[1] = wpabuf_head(shared);
+	len[1] = wpabuf_len(shared);
+	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
+			   2, addr, len, skeyseed) < 0) {
+		wpabuf_free(shared);
+		os_free(buf);
+		os_free(pad);
+		return -1;
+	}
+	os_free(pad);
+	wpabuf_free(shared);
+
+	/* DH parameters are not needed anymore, so free them */
+	wpabuf_free(data->i_dh_public);
+	data->i_dh_public = NULL;
+	wpabuf_free(data->r_dh_private);
+	data->r_dh_private = NULL;
+
+	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
+			skeyseed, prf->hash_len);
+
+	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
+				   &data->keys);
+	os_free(buf);
+	return ret;
+}
+
+
+static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
+				 const u8 *pos, const u8 *end)
+{
+	int transform_len;
+	const struct ikev2_transform *t;
+	u16 transform_id;
+	const u8 *tend;
+
+	if (end - pos < (int) sizeof(*t)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
+		return -1;
+	}
+
+	t = (const struct ikev2_transform *) pos;
+	transform_len = WPA_GET_BE16(t->transform_length);
+	if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
+			   transform_len);
+		return -1;
+	}
+	tend = pos + transform_len;
+
+	transform_id = WPA_GET_BE16(t->transform_id);
+
+	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
+	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
+		   "Transform Type: %d  Transform ID: %d",
+		   t->type, transform_len, t->transform_type, transform_id);
+
+	if (t->type != 0 && t->type != 3) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
+		return -1;
+	}
+
+	pos = (const u8 *) (t + 1);
+	if (pos < tend) {
+		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
+			    pos, tend - pos);
+	}
+
+	switch (t->transform_type) {
+	case IKEV2_TRANSFORM_ENCR:
+		if (ikev2_get_encr(transform_id)) {
+			if (transform_id == ENCR_AES_CBC) {
+				if (tend - pos != 4) {
+					wpa_printf(MSG_DEBUG, "IKEV2: No "
+						   "Transform Attr for AES");
+					break;
+				}
+#ifdef CCNS_PL
+				if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
+					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
+						   "Key Size attribute for "
+						   "AES");
+					break;
+				}
+#else /* CCNS_PL */
+				if (WPA_GET_BE16(pos) != 0x800e) {
+					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
+						   "Key Size attribute for "
+						   "AES");
+					break;
+				}
+#endif /* CCNS_PL */
+				if (WPA_GET_BE16(pos + 2) != 128) {
+					wpa_printf(MSG_DEBUG, "IKEV2: "
+						   "Unsupported AES key size "
+						   "%d bits",
+						   WPA_GET_BE16(pos + 2));
+					break;
+				}
+			}
+			prop->encr = transform_id;
+		}
+		break;
+	case IKEV2_TRANSFORM_PRF:
+		if (ikev2_get_prf(transform_id))
+			prop->prf = transform_id;
+		break;
+	case IKEV2_TRANSFORM_INTEG:
+		if (ikev2_get_integ(transform_id))
+			prop->integ = transform_id;
+		break;
+	case IKEV2_TRANSFORM_DH:
+		if (dh_groups_get(transform_id))
+			prop->dh = transform_id;
+		break;
+	}
+
+	return transform_len;
+}
+
+
+static int ikev2_parse_proposal(struct ikev2_proposal_data *prop,
+				const u8 *pos, const u8 *end)
+{
+	const u8 *pend, *ppos;
+	int proposal_len, i;
+	const struct ikev2_proposal *p;
+
+	if (end - pos < (int) sizeof(*p)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
+		return -1;
+	}
+
+	/* FIX: AND processing if multiple proposals use the same # */
+
+	p = (const struct ikev2_proposal *) pos;
+	proposal_len = WPA_GET_BE16(p->proposal_length);
+	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
+			   proposal_len);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
+		   p->proposal_num);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
+		   " Protocol ID: %d",
+		   p->type, proposal_len, p->protocol_id);
+	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
+		   p->spi_size, p->num_transforms);
+
+	if (p->type != 0 && p->type != 2) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
+		return -1;
+	}
+
+	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
+			   "(only IKE allowed for EAP-IKEv2)");
+		return -1;
+	}
+
+	if (p->proposal_num != prop->proposal_num) {
+		if (p->proposal_num == prop->proposal_num + 1)
+			prop->proposal_num = p->proposal_num;
+		else {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
+			return -1;
+		}
+	}
+
+	ppos = (const u8 *) (p + 1);
+	pend = pos + proposal_len;
+	if (ppos + p->spi_size > pend) {
+		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
+			   "in proposal");
+		return -1;
+	}
+	if (p->spi_size) {
+		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
+			    ppos, p->spi_size);
+		ppos += p->spi_size;
+	}
+
+	/*
+	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
+	 * subsequent negotiations, it must be 8 for IKE. We only support
+	 * initial case for now.
+	 */
+	if (p->spi_size != 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
+		return -1;
+	}
+
+	if (p->num_transforms == 0) {
+		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
+		return -1;
+	}
+
+	for (i = 0; i < (int) p->num_transforms; i++) {
+		int tlen = ikev2_parse_transform(prop, ppos, pend);
+		if (tlen < 0)
+			return -1;
+		ppos += tlen;
+	}
+
+	if (ppos != pend) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
+			   "transforms");
+		return -1;
+	}
+
+	return proposal_len;
+}
+
+
+static int ikev2_process_sai1(struct ikev2_responder_data *data,
+			      const u8 *sai1, size_t sai1_len)
+{
+	struct ikev2_proposal_data prop;
+	const u8 *pos, *end;
+	int found = 0;
+
+	/* Security Association Payloads: <Proposals> */
+
+	if (sai1 == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: SAi1 not received");
+		return -1;
+	}
+
+	os_memset(&prop, 0, sizeof(prop));
+	prop.proposal_num = 1;
+
+	pos = sai1;
+	end = sai1 + sai1_len;
+
+	while (pos < end) {
+		int plen;
+
+		prop.integ = -1;
+		prop.prf = -1;
+		prop.encr = -1;
+		prop.dh = -1;
+		plen = ikev2_parse_proposal(&prop, pos, end);
+		if (plen < 0)
+			return -1;
+
+		if (!found && prop.integ != -1 && prop.prf != -1 &&
+		    prop.encr != -1 && prop.dh != -1) {
+			os_memcpy(&data->proposal, &prop, sizeof(prop));
+			data->dh = dh_groups_get(prop.dh);
+			found = 1;
+		}
+
+		pos += plen;
+	}
+
+	if (pos != end) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals");
+		return -1;
+	}
+
+	if (!found) {
+		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
+		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
+		   data->proposal.encr, data->proposal.prf,
+		   data->proposal.integ, data->proposal.dh);
+
+	return 0;
+}
+
+
+static int ikev2_process_kei(struct ikev2_responder_data *data,
+			     const u8 *kei, size_t kei_len)
+{
+	u16 group;
+
+	/*
+	 * Key Exchange Payload:
+	 * DH Group # (16 bits)
+	 * RESERVED (16 bits)
+	 * Key Exchange Data (Diffie-Hellman public value)
+	 */
+
+	if (kei == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: KEi not received");
+		return -1;
+	}
+
+	if (kei_len < 4 + 96) {
+		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
+		return -1;
+	}
+
+	group = WPA_GET_BE16(kei);
+	wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group);
+
+	if (group != data->proposal.dh) {
+		wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match "
+			   "with the selected proposal (%u)",
+			   group, data->proposal.dh);
+		/* Reject message with Notify payload of type
+		 * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */
+		data->error_type = INVALID_KE_PAYLOAD;
+		data->state = NOTIFY;
+		return -1;
+	}
+
+	if (data->dh == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
+		return -1;
+	}
+
+	/* RFC 4306, Section 3.4:
+	 * The length of DH public value MUST be equal to the length of the
+	 * prime modulus.
+	 */
+	if (kei_len - 4 != data->dh->prime_len) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
+			   "%ld (expected %ld)",
+			   (long) (kei_len - 4), (long) data->dh->prime_len);
+		return -1;
+	}
+
+	wpabuf_free(data->i_dh_public);
+	data->i_dh_public = wpabuf_alloc(kei_len - 4);
+	if (data->i_dh_public == NULL)
+		return -1;
+	wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4);
+
+	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value",
+			data->i_dh_public);
+	
+	return 0;
+}
+
+
+static int ikev2_process_ni(struct ikev2_responder_data *data,
+			    const u8 *ni, size_t ni_len)
+{
+	if (ni == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Ni not received");
+		return -1;
+	}
+
+	if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld",
+		           (long) ni_len);
+		return -1;
+	}
+
+#ifdef CCNS_PL
+	/* Zeros are removed incorrectly from the beginning of the nonces */
+	while (ni_len > 1 && *ni == 0) {
+		ni_len--;
+		ni++;
+	}
+#endif /* CCNS_PL */
+
+	data->i_nonce_len = ni_len;
+	os_memcpy(data->i_nonce, ni, ni_len);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
+		    data->i_nonce, data->i_nonce_len);
+
+	return 0;
+}
+
+
+static int ikev2_process_sa_init(struct ikev2_responder_data *data,
+				 const struct ikev2_hdr *hdr,
+				 struct ikev2_payloads *pl)
+{
+	if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 ||
+	    ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 ||
+	    ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0)
+		return -1;
+
+	os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN);
+
+	return 0;
+}
+
+
+static int ikev2_process_idi(struct ikev2_responder_data *data,
+			     const u8 *idi, size_t idi_len)
+{
+	u8 id_type;
+
+	if (idi == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No IDi received");
+		return -1;
+	}
+
+	if (idi_len < 4) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload");
+		return -1;
+	}
+
+	id_type = idi[0];
+	idi += 4;
+	idi_len -= 4;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type);
+	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len);
+	os_free(data->IDi);
+	data->IDi = os_malloc(idi_len);
+	if (data->IDi == NULL)
+		return -1;
+	os_memcpy(data->IDi, idi, idi_len);
+	data->IDi_len = idi_len;
+	data->IDi_type = id_type;
+
+	return 0;
+}
+
+
+static int ikev2_process_cert(struct ikev2_responder_data *data,
+			      const u8 *cert, size_t cert_len)
+{
+	u8 cert_encoding;
+
+	if (cert == NULL) {
+		if (data->peer_auth == PEER_AUTH_CERT) {
+			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
+			return -1;
+		}
+		return 0;
+	}
+
+	if (cert_len < 1) {
+		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
+		return -1;
+	}
+
+	cert_encoding = cert[0];
+	cert++;
+	cert_len--;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
+
+	/* TODO: validate certificate */
+
+	return 0;
+}
+
+
+static int ikev2_process_auth_cert(struct ikev2_responder_data *data,
+				   u8 method, const u8 *auth, size_t auth_len)
+{
+	if (method != AUTH_RSA_SIGN) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
+			   "method %d", method);
+		return -1;
+	}
+
+	/* TODO: validate AUTH */
+	return 0;
+}
+
+
+static int ikev2_process_auth_secret(struct ikev2_responder_data *data,
+				     u8 method, const u8 *auth,
+				     size_t auth_len)
+{
+	u8 auth_data[IKEV2_MAX_HASH_LEN];
+	const struct ikev2_prf_alg *prf;
+
+	if (method != AUTH_SHARED_KEY_MIC) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
+			   "method %d", method);
+		return -1;
+	}
+
+	/* msg | Nr | prf(SK_pi,IDi') */
+	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
+				   data->IDi, data->IDi_len, data->IDi_type,
+				   &data->keys, 1, data->shared_secret,
+				   data->shared_secret_len,
+				   data->r_nonce, data->r_nonce_len,
+				   data->key_pad, data->key_pad_len,
+				   auth_data) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
+		return -1;
+	}
+
+	wpabuf_free(data->i_sign_msg);
+	data->i_sign_msg = NULL;
+
+	prf = ikev2_get_prf(data->proposal.prf);
+	if (prf == NULL)
+		return -1;
+
+	if (auth_len != prf->hash_len ||
+	    os_memcmp(auth, auth_data, auth_len) != 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
+		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
+			    auth, auth_len);
+		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
+			    auth_data, prf->hash_len);
+		data->error_type = AUTHENTICATION_FAILED;
+		data->state = NOTIFY;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully "
+		   "using shared keys");
+
+	return 0;
+}
+
+
+static int ikev2_process_auth(struct ikev2_responder_data *data,
+			      const u8 *auth, size_t auth_len)
+{
+	u8 auth_method;
+
+	if (auth == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
+		return -1;
+	}
+
+	if (auth_len < 4) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
+			   "Payload");
+		return -1;
+	}
+
+	auth_method = auth[0];
+	auth += 4;
+	auth_len -= 4;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
+
+	switch (data->peer_auth) {
+	case PEER_AUTH_CERT:
+		return ikev2_process_auth_cert(data, auth_method, auth,
+					       auth_len);
+	case PEER_AUTH_SECRET:
+		return ikev2_process_auth_secret(data, auth_method, auth,
+						 auth_len);
+	}
+
+	return -1;
+}
+
+
+static int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data,
+					   u8 next_payload,
+					   u8 *payload, size_t payload_len)
+{
+	struct ikev2_payloads pl;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
+
+	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
+				 payload_len) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
+			   "payloads");
+		return -1;
+	}
+
+	if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 ||
+	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
+	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int ikev2_process_sa_auth(struct ikev2_responder_data *data,
+				 const struct ikev2_hdr *hdr,
+				 struct ikev2_payloads *pl)
+{
+	u8 *decrypted;
+	size_t decrypted_len;
+	int ret;
+
+	decrypted = ikev2_decrypt_payload(data->proposal.encr,
+					  data->proposal.integ,
+					  &data->keys, 1, hdr, pl->encrypted,
+					  pl->encrypted_len, &decrypted_len);
+	if (decrypted == NULL)
+		return -1;
+
+	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
+					      decrypted, decrypted_len);
+	os_free(decrypted);
+
+	return ret;
+}
+
+
+static int ikev2_validate_rx_state(struct ikev2_responder_data *data,
+				   u8 exchange_type, u32 message_id)
+{
+	switch (data->state) {
+	case SA_INIT:
+		/* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */
+		if (exchange_type != IKE_SA_INIT) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in SA_INIT state", exchange_type);
+			return -1;
+		}
+		if (message_id != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in SA_INIT state", message_id);
+			return -1;
+		}
+		break;
+	case SA_AUTH:
+		/* Expect to receive IKE_SA_AUTH:
+		 * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,]
+		 *	AUTH, SAi2, TSi, TSr}
+		 */
+		if (exchange_type != IKE_SA_AUTH) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in SA_AUTH state", exchange_type);
+			return -1;
+		}
+		if (message_id != 1) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in SA_AUTH state", message_id);
+			return -1;
+		}
+		break;
+	case CHILD_SA:
+		if (exchange_type != CREATE_CHILD_SA) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in CHILD_SA state", exchange_type);
+			return -1;
+		}
+		if (message_id != 2) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in CHILD_SA state", message_id);
+			return -1;
+		}
+		break;
+	case NOTIFY:
+	case IKEV2_DONE:
+	case IKEV2_FAILED:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ikev2_responder_process(struct ikev2_responder_data *data,
+			    const struct wpabuf *buf)
+{
+	const struct ikev2_hdr *hdr;
+	u32 length, message_id;
+	const u8 *pos, *end;
+	struct ikev2_payloads pl;
+
+	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
+		   (unsigned long) wpabuf_len(buf));
+
+	if (wpabuf_len(buf) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
+		return -1;
+	}
+
+	data->error_type = 0;
+	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
+	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
+	message_id = WPA_GET_BE32(hdr->message_id);
+	length = WPA_GET_BE32(hdr->length);
+
+	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
+		    hdr->i_spi, IKEV2_SPI_LEN);
+	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Responder's SPI",
+		    hdr->r_spi, IKEV2_SPI_LEN);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
+		   "Exchange Type: %u",
+		   hdr->next_payload, hdr->version, hdr->exchange_type);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
+		   message_id, length);
+
+	if (hdr->version != IKEV2_VERSION) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
+			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
+		return -1;
+	}
+
+	if (length != wpabuf_len(buf)) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
+			   "RX: %lu)", (unsigned long) length,
+			   (unsigned long) wpabuf_len(buf));
+		return -1;
+	}
+
+	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
+		return -1;
+
+	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
+	    IKEV2_HDR_INITIATOR) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
+			   hdr->flags);
+		return -1;
+	}
+
+	if (data->state != SA_INIT) {
+		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
+				   "Initiator's SPI");
+			return -1;
+		}
+		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
+				   "Responder's SPI");
+			return -1;
+		}
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
+		return -1;
+
+	if (data->state == SA_INIT) {
+		data->last_msg = LAST_MSG_SA_INIT;
+		if (ikev2_process_sa_init(data, hdr, &pl) < 0) {
+			if (data->state == NOTIFY)
+				return 0;
+			return -1;
+		}
+		wpabuf_free(data->i_sign_msg);
+		data->i_sign_msg = wpabuf_dup(buf);
+	}
+
+	if (data->state == SA_AUTH) {
+		data->last_msg = LAST_MSG_SA_AUTH;
+		if (ikev2_process_sa_auth(data, hdr, &pl) < 0) {
+			if (data->state == NOTIFY)
+				return 0;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void ikev2_build_hdr(struct ikev2_responder_data *data,
+			    struct wpabuf *msg, u8 exchange_type,
+			    u8 next_payload, u32 message_id)
+{
+	struct ikev2_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
+
+	/* HDR - RFC 4306, Sect. 3.1 */
+	hdr = wpabuf_put(msg, sizeof(*hdr));
+	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
+	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
+	hdr->next_payload = next_payload;
+	hdr->version = IKEV2_VERSION;
+	hdr->exchange_type = exchange_type;
+	hdr->flags = IKEV2_HDR_RESPONSE;
+	WPA_PUT_BE32(hdr->message_id, message_id);
+}
+
+
+static int ikev2_build_sar1(struct ikev2_responder_data *data,
+			    struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	struct ikev2_proposal *p;
+	struct ikev2_transform *t;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload");
+
+	/* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+
+	p = wpabuf_put(msg, sizeof(*p));
+#ifdef CCNS_PL
+	/* Seems to require that the Proposal # is 1 even though RFC 4306
+	 * Sect 3.3.1 has following requirement "When a proposal is accepted,
+	 * all of the proposal numbers in the SA payload MUST be the same and
+	 * MUST match the number on the proposal sent that was accepted.".
+	 */
+	p->proposal_num = 1;
+#else /* CCNS_PL */
+	p->proposal_num = data->proposal.proposal_num;
+#endif /* CCNS_PL */
+	p->protocol_id = IKEV2_PROTOCOL_IKE;
+	p->num_transforms = 4;
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	t->transform_type = IKEV2_TRANSFORM_ENCR;
+	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
+	if (data->proposal.encr == ENCR_AES_CBC) {
+		/* Transform Attribute: Key Len = 128 bits */
+#ifdef CCNS_PL
+		wpabuf_put_be16(msg, 0x001d); /* ?? */
+#else /* CCNS_PL */
+		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
+#endif /* CCNS_PL */
+		wpabuf_put_be16(msg, 128); /* 128-bit key */
+	}
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
+	WPA_PUT_BE16(t->transform_length, plen);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_PRF;
+	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_INTEG;
+	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_DH;
+	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
+	WPA_PUT_BE16(p->proposal_length, plen);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+
+	return 0;
+}
+
+
+static int ikev2_build_ker(struct ikev2_responder_data *data,
+			   struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	struct wpabuf *pv;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload");
+
+	pv = dh_init(data->dh, &data->r_dh_private);
+	if (pv == NULL) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
+		return -1;
+	}
+
+	/* KEr - RFC 4306, Sect. 3.4 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+
+	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
+	wpabuf_put(msg, 2); /* RESERVED */
+	/*
+	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
+	 * match the length of the prime.
+	 */
+	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
+	wpabuf_put_buf(msg, pv);
+	wpabuf_free(pv);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_nr(struct ikev2_responder_data *data,
+			  struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload");
+
+	/* Nr - RFC 4306, Sect. 3.9 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len);
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_idr(struct ikev2_responder_data *data,
+			   struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload");
+
+	if (data->IDr == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No IDr available");
+		return -1;
+	}
+
+	/* IDr - RFC 4306, Sect. 3.5 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_u8(msg, ID_KEY_ID);
+	wpabuf_put(msg, 3); /* RESERVED */
+	wpabuf_put_data(msg, data->IDr, data->IDr_len);
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_auth(struct ikev2_responder_data *data,
+			    struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	const struct ikev2_prf_alg *prf;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
+
+	prf = ikev2_get_prf(data->proposal.prf);
+	if (prf == NULL)
+		return -1;
+
+	/* Authentication - RFC 4306, Sect. 3.8 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
+	wpabuf_put(msg, 3); /* RESERVED */
+
+	/* msg | Ni | prf(SK_pr,IDr') */
+	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
+				   data->IDr, data->IDr_len, ID_KEY_ID,
+				   &data->keys, 0, data->shared_secret,
+				   data->shared_secret_len,
+				   data->i_nonce, data->i_nonce_len,
+				   data->key_pad, data->key_pad_len,
+				   wpabuf_put(msg, prf->hash_len)) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
+		return -1;
+	}
+	wpabuf_free(data->r_sign_msg);
+	data->r_sign_msg = NULL;
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_notification(struct ikev2_responder_data *data,
+				    struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload");
+
+	if (data->error_type == 0) {
+		wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type "
+			   "available");
+		return -1;
+	}
+
+	/* Notify - RFC 4306, Sect. 3.10 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+#ifdef CCNS_PL
+	wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
+#else /* CCNS_PL */
+	wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
+#endif /* CCNS_PL */
+	wpabuf_put_u8(msg, 0); /* SPI Size */
+	wpabuf_put_be16(msg, data->error_type);
+
+	switch (data->error_type) {
+	case INVALID_KE_PAYLOAD:
+		if (data->proposal.dh == -1) {
+			wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for "
+				   "INVALID_KE_PAYLOAD notifications");
+			return -1;
+		}
+		wpabuf_put_be16(msg, data->proposal.dh);
+		wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request "
+			   "DH Group #%d", data->proposal.dh);
+		break;
+	case AUTHENTICATION_FAILED:
+		/* no associated data */
+		break;
+	default:
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type "
+			   "%d", data->error_type);
+		return -1;
+	}
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
+{
+	struct wpabuf *msg;
+
+	/* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */
+
+	if (os_get_random(data->r_spi, IKEV2_SPI_LEN))
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI",
+		    data->r_spi, IKEV2_SPI_LEN);
+
+	data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
+	if (random_get_bytes(data->r_nonce, data->r_nonce_len))
+		return NULL;
+#ifdef CCNS_PL
+	/* Zeros are removed incorrectly from the beginning of the nonces in
+	 * key derivation; as a workaround, make sure Nr does not start with
+	 * zero.. */
+	if (data->r_nonce[0] == 0)
+		data->r_nonce[0] = 1;
+#endif /* CCNS_PL */
+	wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
+
+	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
+	if (msg == NULL)
+		return NULL;
+
+	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
+	if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
+	    ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) ||
+	    ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ?
+			   IKEV2_PAYLOAD_ENCRYPTED :
+			   IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (ikev2_derive_keys(data)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (data->peer_auth == PEER_AUTH_CERT) {
+		/* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info
+		 * for trust agents */
+	}
+
+	if (data->peer_auth == PEER_AUTH_SECRET) {
+		struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000);
+		if (plain == NULL) {
+			wpabuf_free(msg);
+			return NULL;
+		}
+		if (ikev2_build_idr(data, plain,
+				    IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
+		    ikev2_build_encrypted(data->proposal.encr,
+					  data->proposal.integ,
+					  &data->keys, 0, msg, plain,
+					  IKEV2_PAYLOAD_IDr)) {
+			wpabuf_free(plain);
+			wpabuf_free(msg);
+			return NULL;
+		}
+		wpabuf_free(plain);
+	}
+
+	ikev2_update_hdr(msg);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
+
+	data->state = SA_AUTH;
+
+	wpabuf_free(data->r_sign_msg);
+	data->r_sign_msg = wpabuf_dup(msg);
+
+	return msg;
+}
+
+
+static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data)
+{
+	struct wpabuf *msg, *plain;
+
+	/* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */
+
+	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
+	if (msg == NULL)
+		return NULL;
+	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
+
+	plain = wpabuf_alloc(data->IDr_len + 1000);
+	if (plain == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
+	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
+	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
+				  &data->keys, 0, msg, plain,
+				  IKEV2_PAYLOAD_IDr)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
+
+	data->state = IKEV2_DONE;
+
+	return msg;
+}
+
+
+static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data)
+{
+	struct wpabuf *msg;
+
+	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
+	if (msg == NULL)
+		return NULL;
+	if (data->last_msg == LAST_MSG_SA_AUTH) {
+		/* HDR, SK{N} */
+		struct wpabuf *plain = wpabuf_alloc(100);
+		if (plain == NULL) {
+			wpabuf_free(msg);
+			return NULL;
+		}
+		ikev2_build_hdr(data, msg, IKE_SA_AUTH,
+				IKEV2_PAYLOAD_ENCRYPTED, 1);
+		if (ikev2_build_notification(data, plain,
+					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
+		    ikev2_build_encrypted(data->proposal.encr,
+					  data->proposal.integ,
+					  &data->keys, 0, msg, plain,
+					  IKEV2_PAYLOAD_NOTIFICATION)) {
+			wpabuf_free(plain);
+			wpabuf_free(msg);
+			return NULL;
+		}
+		data->state = IKEV2_FAILED;
+	} else {
+		/* HDR, N */
+		ikev2_build_hdr(data, msg, IKE_SA_INIT,
+				IKEV2_PAYLOAD_NOTIFICATION, 0);
+		if (ikev2_build_notification(data, msg,
+					     IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
+			wpabuf_free(msg);
+			return NULL;
+		}
+		data->state = SA_INIT;
+	}
+
+	ikev2_update_hdr(msg);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)",
+			msg);
+
+	return msg;
+}
+
+
+struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data)
+{
+	switch (data->state) {
+	case SA_INIT:
+		return ikev2_build_sa_init(data);
+	case SA_AUTH:
+		return ikev2_build_sa_auth(data);
+	case CHILD_SA:
+		return NULL;
+	case NOTIFY:
+		return ikev2_build_notify(data);
+	case IKEV2_DONE:
+	case IKEV2_FAILED:
+		return NULL;
+	}
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/ikev2.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/ikev2.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/ikev2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,65 +0,0 @@
-/*
- * IKEv2 responder (RFC 4306) for EAP-IKEV2
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IKEV2_H
-#define IKEV2_H
-
-#include "eap_common/ikev2_common.h"
-
-struct ikev2_proposal_data {
-	u8 proposal_num;
-	int integ;
-	int prf;
-	int encr;
-	int dh;
-};
-
-
-struct ikev2_responder_data {
-	enum { SA_INIT, SA_AUTH, CHILD_SA, NOTIFY, IKEV2_DONE, IKEV2_FAILED }
-		state;
-	u8 i_spi[IKEV2_SPI_LEN];
-	u8 r_spi[IKEV2_SPI_LEN];
-	u8 i_nonce[IKEV2_NONCE_MAX_LEN];
-	size_t i_nonce_len;
-	u8 r_nonce[IKEV2_NONCE_MAX_LEN];
-	size_t r_nonce_len;
-	struct wpabuf *i_dh_public;
-	struct wpabuf *r_dh_private;
-	struct ikev2_proposal_data proposal;
-	const struct dh_group *dh;
-	struct ikev2_keys keys;
-	u8 *IDi;
-	size_t IDi_len;
-	u8 IDi_type;
-	u8 *IDr;
-	size_t IDr_len;
-	struct wpabuf *r_sign_msg;
-	struct wpabuf *i_sign_msg;
-	u8 *shared_secret;
-	size_t shared_secret_len;
-	enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth;
-	u8 *key_pad;
-	size_t key_pad_len;
-	u16 error_type;
-	enum { LAST_MSG_SA_INIT, LAST_MSG_SA_AUTH } last_msg;
-};
-
-
-void ikev2_responder_deinit(struct ikev2_responder_data *data);
-int ikev2_responder_process(struct ikev2_responder_data *data,
-			    const struct wpabuf *buf);
-struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data);
-
-#endif /* IKEV2_H */

Copied: vendor/wpa/2.0/src/eap_peer/ikev2.h (from rev 9639, vendor/wpa/dist/src/eap_peer/ikev2.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/ikev2.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/ikev2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,59 @@
+/*
+ * IKEv2 responder (RFC 4306) for EAP-IKEV2
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IKEV2_H
+#define IKEV2_H
+
+#include "eap_common/ikev2_common.h"
+
+struct ikev2_proposal_data {
+	u8 proposal_num;
+	int integ;
+	int prf;
+	int encr;
+	int dh;
+};
+
+
+struct ikev2_responder_data {
+	enum { SA_INIT, SA_AUTH, CHILD_SA, NOTIFY, IKEV2_DONE, IKEV2_FAILED }
+		state;
+	u8 i_spi[IKEV2_SPI_LEN];
+	u8 r_spi[IKEV2_SPI_LEN];
+	u8 i_nonce[IKEV2_NONCE_MAX_LEN];
+	size_t i_nonce_len;
+	u8 r_nonce[IKEV2_NONCE_MAX_LEN];
+	size_t r_nonce_len;
+	struct wpabuf *i_dh_public;
+	struct wpabuf *r_dh_private;
+	struct ikev2_proposal_data proposal;
+	const struct dh_group *dh;
+	struct ikev2_keys keys;
+	u8 *IDi;
+	size_t IDi_len;
+	u8 IDi_type;
+	u8 *IDr;
+	size_t IDr_len;
+	struct wpabuf *r_sign_msg;
+	struct wpabuf *i_sign_msg;
+	u8 *shared_secret;
+	size_t shared_secret_len;
+	enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth;
+	u8 *key_pad;
+	size_t key_pad_len;
+	u16 error_type;
+	enum { LAST_MSG_SA_INIT, LAST_MSG_SA_AUTH } last_msg;
+};
+
+
+void ikev2_responder_deinit(struct ikev2_responder_data *data);
+int ikev2_responder_process(struct ikev2_responder_data *data,
+			    const struct wpabuf *buf);
+struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data);
+
+#endif /* IKEV2_H */

Deleted: vendor/wpa/2.0/src/eap_peer/mschapv2.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/mschapv2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,123 +0,0 @@
-/*
- * MSCHAPV2 (RFC 2759)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-#include "mschapv2.h"
-
-const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
-{
-	size_t i;
-
-	/*
-	 * MSCHAPv2 does not include optional domain name in the
-	 * challenge-response calculation, so remove domain prefix
-	 * (if present).
-	 */
-
-	for (i = 0; i < *len; i++) {
-		if (username[i] == '\\') {
-			*len -= i + 1;
-			return username + i + 1;
-		}
-	}
-
-	return username;
-}
-
-
-int mschapv2_derive_response(const u8 *identity, size_t identity_len,
-			     const u8 *password, size_t password_len,
-			     int pwhash,
-			     const u8 *auth_challenge,
-			     const u8 *peer_challenge,
-			     u8 *nt_response, u8 *auth_response,
-			     u8 *master_key)
-{
-	const u8 *username;
-	size_t username_len;
-	u8 password_hash[16], password_hash_hash[16];
-
-	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
-			  identity, identity_len);
-	username_len = identity_len;
-	username = mschapv2_remove_domain(identity, &username_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
-			  username, username_len);
-
-	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
-		    auth_challenge, MSCHAPV2_CHAL_LEN);
-	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
-		    peer_challenge, MSCHAPV2_CHAL_LEN);
-	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
-			  username, username_len);
-	/* Authenticator response is not really needed yet, but calculate it
-	 * here so that challenges need not be saved. */
-	if (pwhash) {
-		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
-				password, password_len);
-		generate_nt_response_pwhash(auth_challenge, peer_challenge,
-					    username, username_len,
-					    password, nt_response);
-		generate_authenticator_response_pwhash(
-			password, peer_challenge, auth_challenge,
-			username, username_len, nt_response, auth_response);
-	} else {
-		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
-				      password, password_len);
-		generate_nt_response(auth_challenge, peer_challenge,
-				     username, username_len,
-				     password, password_len, nt_response);
-		generate_authenticator_response(password, password_len,
-						peer_challenge, auth_challenge,
-						username, username_len,
-						nt_response, auth_response);
-	}
-	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
-		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
-	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
-		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
-
-	/* Generate master_key here since we have the needed data available. */
-	if (pwhash) {
-		if (hash_nt_password_hash(password, password_hash_hash))
-			return -1;
-	} else {
-		if (nt_password_hash(password, password_len, password_hash) ||
-		    hash_nt_password_hash(password_hash, password_hash_hash))
-			return -1;
-	}
-	get_master_key(password_hash_hash, nt_response, master_key);
-	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
-			master_key, MSCHAPV2_MASTER_KEY_LEN);
-
-	return 0;
-}
-
-
-int mschapv2_verify_auth_response(const u8 *auth_response,
-				  const u8 *buf, size_t buf_len)
-{
-	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
-	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
-	    buf[0] != 'S' || buf[1] != '=' ||
-	    hexstr2bin((char *) (buf + 2), recv_response,
-		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
-	    os_memcmp(auth_response, recv_response,
-		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
-		return -1;
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_peer/mschapv2.c (from rev 9639, vendor/wpa/dist/src/eap_peer/mschapv2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/mschapv2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,124 @@
+/*
+ * MSCHAPV2 (RFC 2759)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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/ms_funcs.h"
+#include "mschapv2.h"
+
+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
+{
+	size_t i;
+
+	/*
+	 * MSCHAPv2 does not include optional domain name in the
+	 * challenge-response calculation, so remove domain prefix
+	 * (if present).
+	 */
+
+	for (i = 0; i < *len; i++) {
+		if (username[i] == '\\') {
+			*len -= i + 1;
+			return username + i + 1;
+		}
+	}
+
+	return username;
+}
+
+
+int mschapv2_derive_response(const u8 *identity, size_t identity_len,
+			     const u8 *password, size_t password_len,
+			     int pwhash,
+			     const u8 *auth_challenge,
+			     const u8 *peer_challenge,
+			     u8 *nt_response, u8 *auth_response,
+			     u8 *master_key)
+{
+	const u8 *username;
+	size_t username_len;
+	u8 password_hash[16], password_hash_hash[16];
+
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
+			  identity, identity_len);
+	username_len = identity_len;
+	username = mschapv2_remove_domain(identity, &username_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
+			  username, username_len);
+
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
+		    auth_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
+		    peer_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
+			  username, username_len);
+	/* Authenticator response is not really needed yet, but calculate it
+	 * here so that challenges need not be saved. */
+	if (pwhash) {
+		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
+				password, password_len);
+		if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
+						username, username_len,
+						password, nt_response) ||
+		    generate_authenticator_response_pwhash(
+			    password, peer_challenge, auth_challenge,
+			    username, username_len, nt_response,
+			    auth_response))
+			return -1;
+	} else {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
+				      password, password_len);
+		if (generate_nt_response(auth_challenge, peer_challenge,
+					 username, username_len,
+					 password, password_len,
+					 nt_response) ||
+		    generate_authenticator_response(password, password_len,
+						    peer_challenge,
+						    auth_challenge,
+						    username, username_len,
+						    nt_response,
+						    auth_response))
+			return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
+		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
+		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
+
+	/* Generate master_key here since we have the needed data available. */
+	if (pwhash) {
+		if (hash_nt_password_hash(password, password_hash_hash))
+			return -1;
+	} else {
+		if (nt_password_hash(password, password_len, password_hash) ||
+		    hash_nt_password_hash(password_hash, password_hash_hash))
+			return -1;
+	}
+	if (get_master_key(password_hash_hash, nt_response, master_key))
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
+			master_key, MSCHAPV2_MASTER_KEY_LEN);
+
+	return 0;
+}
+
+
+int mschapv2_verify_auth_response(const u8 *auth_response,
+				  const u8 *buf, size_t buf_len)
+{
+	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
+	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
+	    buf[0] != 'S' || buf[1] != '=' ||
+	    hexstr2bin((char *) (buf + 2), recv_response,
+		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
+	    os_memcmp(auth_response, recv_response,
+		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
+		return -1;
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/eap_peer/mschapv2.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/mschapv2.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/mschapv2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,34 +0,0 @@
-/*
- * MSCHAPV2 (RFC 2759)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MSCHAPV2_H
-#define MSCHAPV2_H
-
-#define MSCHAPV2_CHAL_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
-#define MSCHAPV2_AUTH_RESPONSE_LEN 20
-#define MSCHAPV2_MASTER_KEY_LEN 16
-
-const u8 * mschapv2_remove_domain(const u8 *username, size_t *len);
-int mschapv2_derive_response(const u8 *username, size_t username_len,
-			     const u8 *password, size_t password_len,
-			     int pwhash,
-			     const u8 *auth_challenge,
-			     const u8 *peer_challenge,
-			     u8 *nt_response, u8 *auth_response,
-			     u8 *master_key);
-int mschapv2_verify_auth_response(const u8 *auth_response,
-				  const u8 *buf, size_t buf_len);
-
-#endif /* MSCHAPV2_H */

Copied: vendor/wpa/2.0/src/eap_peer/mschapv2.h (from rev 9639, vendor/wpa/dist/src/eap_peer/mschapv2.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/mschapv2.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/mschapv2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * MSCHAPV2 (RFC 2759)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MSCHAPV2_H
+#define MSCHAPV2_H
+
+#define MSCHAPV2_CHAL_LEN 16
+#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define MSCHAPV2_AUTH_RESPONSE_LEN 20
+#define MSCHAPV2_MASTER_KEY_LEN 16
+
+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len);
+int mschapv2_derive_response(const u8 *username, size_t username_len,
+			     const u8 *password, size_t password_len,
+			     int pwhash,
+			     const u8 *auth_challenge,
+			     const u8 *peer_challenge,
+			     u8 *nt_response, u8 *auth_response,
+			     u8 *master_key);
+int mschapv2_verify_auth_response(const u8 *auth_response,
+				  const u8 *buf, size_t buf_len);
+
+#endif /* MSCHAPV2_H */

Deleted: vendor/wpa/2.0/src/eap_peer/tncc.c
===================================================================
--- vendor/wpa/dist/src/eap_peer/tncc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/tncc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1369 +0,0 @@
-/*
- * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <dlfcn.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "common.h"
-#include "base64.h"
-#include "tncc.h"
-#include "eap_common/eap_tlv_common.h"
-#include "eap_common/eap_defs.h"
-
-
-#ifdef UNICODE
-#define TSTR "%S"
-#else /* UNICODE */
-#define TSTR "%s"
-#endif /* UNICODE */
-
-
-#define TNC_CONFIG_FILE "/etc/tnc_config"
-#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
-#define IF_TNCCS_START \
-"<?xml version=\"1.0\"?>\n" \
-"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
-"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
-"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
-"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
-"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
-#define IF_TNCCS_END "\n</TNCCS-Batch>"
-
-/* TNC IF-IMC */
-
-typedef unsigned long TNC_UInt32;
-typedef unsigned char *TNC_BufferReference;
-
-typedef TNC_UInt32 TNC_IMCID;
-typedef TNC_UInt32 TNC_ConnectionID;
-typedef TNC_UInt32 TNC_ConnectionState;
-typedef TNC_UInt32 TNC_RetryReason;
-typedef TNC_UInt32 TNC_MessageType;
-typedef TNC_MessageType *TNC_MessageTypeList;
-typedef TNC_UInt32 TNC_VendorID;
-typedef TNC_UInt32 TNC_MessageSubtype;
-typedef TNC_UInt32 TNC_Version;
-typedef TNC_UInt32 TNC_Result;
-
-typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
-	TNC_IMCID imcID,
-	char *functionName,
-	void **pOutfunctionPointer);
-
-#define TNC_RESULT_SUCCESS 0
-#define TNC_RESULT_NOT_INITIALIZED 1
-#define TNC_RESULT_ALREADY_INITIALIZED 2
-#define TNC_RESULT_NO_COMMON_VERSION 3
-#define TNC_RESULT_CANT_RETRY 4
-#define TNC_RESULT_WONT_RETRY 5
-#define TNC_RESULT_INVALID_PARAMETER 6
-#define TNC_RESULT_CANT_RESPOND 7
-#define TNC_RESULT_ILLEGAL_OPERATION 8
-#define TNC_RESULT_OTHER 9
-#define TNC_RESULT_FATAL 10
-
-#define TNC_CONNECTION_STATE_CREATE 0
-#define TNC_CONNECTION_STATE_HANDSHAKE 1
-#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
-#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
-#define TNC_CONNECTION_STATE_ACCESS_NONE 4
-#define TNC_CONNECTION_STATE_DELETE 5
-
-#define TNC_IFIMC_VERSION_1 1
-
-#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
-#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
-
-/* TNCC-TNCS Message Types */
-#define TNC_TNCCS_RECOMMENDATION		0x00000001
-#define TNC_TNCCS_ERROR				0x00000002
-#define TNC_TNCCS_PREFERREDLANGUAGE		0x00000003
-#define TNC_TNCCS_REASONSTRINGS			0x00000004
-
-
-/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
-enum {
-	SSOH_MS_MACHINE_INVENTORY = 1,
-	SSOH_MS_QUARANTINE_STATE = 2,
-	SSOH_MS_PACKET_INFO = 3,
-	SSOH_MS_SYSTEMGENERATED_IDS = 4,
-	SSOH_MS_MACHINENAME = 5,
-	SSOH_MS_CORRELATIONID = 6,
-	SSOH_MS_INSTALLED_SHVS = 7,
-	SSOH_MS_MACHINE_INVENTORY_EX = 8
-};
-
-struct tnc_if_imc {
-	struct tnc_if_imc *next;
-	char *name;
-	char *path;
-	void *dlhandle; /* from dlopen() */
-	TNC_IMCID imcID;
-	TNC_ConnectionID connectionID;
-	TNC_MessageTypeList supported_types;
-	size_t num_supported_types;
-	u8 *imc_send;
-	size_t imc_send_len;
-
-	/* Functions implemented by IMCs (with TNC_IMC_ prefix) */
-	TNC_Result (*Initialize)(
-		TNC_IMCID imcID,
-		TNC_Version minVersion,
-		TNC_Version maxVersion,
-		TNC_Version *pOutActualVersion);
-	TNC_Result (*NotifyConnectionChange)(
-		TNC_IMCID imcID,
-		TNC_ConnectionID connectionID,
-		TNC_ConnectionState newState);
-	TNC_Result (*BeginHandshake)(
-		TNC_IMCID imcID,
-		TNC_ConnectionID connectionID);
-	TNC_Result (*ReceiveMessage)(
-		TNC_IMCID imcID,
-		TNC_ConnectionID connectionID,
-		TNC_BufferReference messageBuffer,
-		TNC_UInt32 messageLength,
-		TNC_MessageType messageType);
-	TNC_Result (*BatchEnding)(
-		TNC_IMCID imcID,
-		TNC_ConnectionID connectionID);
-	TNC_Result (*Terminate)(TNC_IMCID imcID);
-	TNC_Result (*ProvideBindFunction)(
-		TNC_IMCID imcID,
-		TNC_TNCC_BindFunctionPointer bindFunction);
-};
-
-struct tncc_data {
-	struct tnc_if_imc *imc;
-	unsigned int last_batchid;
-};
-
-#define TNC_MAX_IMC_ID 10
-static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
-
-
-/* TNCC functions that IMCs can call */
-
-TNC_Result TNC_TNCC_ReportMessageTypes(
-	TNC_IMCID imcID,
-	TNC_MessageTypeList supportedTypes,
-	TNC_UInt32 typeCount)
-{
-	TNC_UInt32 i;
-	struct tnc_if_imc *imc;
-
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
-		   "typeCount=%lu)",
-		   (unsigned long) imcID, (unsigned long) typeCount);
-
-	for (i = 0; i < typeCount; i++) {
-		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
-			   i, supportedTypes[i]);
-	}
-
-	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	imc = tnc_imc[imcID];
-	os_free(imc->supported_types);
-	imc->supported_types =
-		os_malloc(typeCount * sizeof(TNC_MessageTypeList));
-	if (imc->supported_types == NULL)
-		return TNC_RESULT_FATAL;
-	os_memcpy(imc->supported_types, supportedTypes,
-		  typeCount * sizeof(TNC_MessageTypeList));
-	imc->num_supported_types = typeCount;
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCC_SendMessage(
-	TNC_IMCID imcID,
-	TNC_ConnectionID connectionID,
-	TNC_BufferReference message,
-	TNC_UInt32 messageLength,
-	TNC_MessageType messageType)
-{
-	struct tnc_if_imc *imc;
-	unsigned char *b64;
-	size_t b64len;
-
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
-		   "connectionID=%lu messageType=%lu)",
-		   imcID, connectionID, messageType);
-	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
-			  message, messageLength);
-
-	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	b64 = base64_encode(message, messageLength, &b64len);
-	if (b64 == NULL)
-		return TNC_RESULT_FATAL;
-
-	imc = tnc_imc[imcID];
-	os_free(imc->imc_send);
-	imc->imc_send_len = 0;
-	imc->imc_send = os_zalloc(b64len + 100);
-	if (imc->imc_send == NULL) {
-		os_free(b64);
-		return TNC_RESULT_OTHER;
-	}
-
-	imc->imc_send_len =
-		os_snprintf((char *) imc->imc_send, b64len + 100,
-			    "<IMC-IMV-Message><Type>%08X</Type>"
-			    "<Base64>%s</Base64></IMC-IMV-Message>",
-			    (unsigned int) messageType, b64);
-
-	os_free(b64);
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCC_RequestHandshakeRetry(
-	TNC_IMCID imcID,
-	TNC_ConnectionID connectionID,
-	TNC_RetryReason reason)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
-
-	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	/*
-	 * TODO: trigger a call to eapol_sm_request_reauth(). This would
-	 * require that the IMC continues to be loaded in memory afer
-	 * authentication..
-	 */
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-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')",
-		   imcID, severity, message);
-	return TNC_RESULT_SUCCESS;
-}
-
-
-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')",
-		   imcID, connectionID, message);
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCC_BindFunction(
-	TNC_IMCID imcID,
-	char *functionName,
-	void **pOutfunctionPointer)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
-		   "functionName='%s')", (unsigned long) imcID, functionName);
-
-	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	if (pOutfunctionPointer == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
-		*pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
-	else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
-		*pOutfunctionPointer = TNC_TNCC_SendMessage;
-	else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
-		 0)
-		*pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
-	else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
-		*pOutfunctionPointer = TNC_9048_LogMessage;
-	else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
-		*pOutfunctionPointer = TNC_9048_UserMessage;
-	else
-		*pOutfunctionPointer = NULL;
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-static void * tncc_get_sym(void *handle, char *func)
-{
-	void *fptr;
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#ifdef _WIN32_WCE
-	fptr = GetProcAddressA(handle, func);
-#else /* _WIN32_WCE */
-	fptr = GetProcAddress(handle, func);
-#endif /* _WIN32_WCE */
-#else /* CONFIG_NATIVE_WINDOWS */
-	fptr = dlsym(handle, func);
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	return fptr;
-}
-
-
-static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
-{
-	void *handle = imc->dlhandle;
-
-	/* Mandatory IMC functions */
-	imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
-	if (imc->Initialize == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
-			   "TNC_IMC_Initialize");
-		return -1;
-	}
-
-	imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
-	if (imc->BeginHandshake == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
-			   "TNC_IMC_BeginHandshake");
-		return -1;
-	}
-
-	imc->ProvideBindFunction =
-		tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
-	if (imc->ProvideBindFunction == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
-			   "TNC_IMC_ProvideBindFunction");
-		return -1;
-	}
-
-	/* Optional IMC functions */
-	imc->NotifyConnectionChange =
-		tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
-	imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
-	imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
-	imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
-
-	return 0;
-}
-
-
-static int tncc_imc_initialize(struct tnc_if_imc *imc)
-{
-	TNC_Result res;
-	TNC_Version imc_ver;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
-		   imc->name);
-	res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
-			      TNC_IFIMC_VERSION_1, &imc_ver);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
-		   (unsigned long) res, (unsigned long) imc_ver);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncc_imc_terminate(struct tnc_if_imc *imc)
-{
-	TNC_Result res;
-
-	if (imc->Terminate == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
-		   imc->name);
-	res = imc->Terminate(imc->imcID);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
-{
-	TNC_Result res;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
-		   "IMC '%s'", imc->name);
-	res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
-					     TNC_ConnectionState state)
-{
-	TNC_Result res;
-
-	if (imc->NotifyConnectionChange == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
-		   " for IMC '%s'", (int) state, imc->name);
-	res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
-					  state);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
-{
-	TNC_Result res;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
-		   "'%s'", imc->name);
-	res = imc->BeginHandshake(imc->imcID, imc->connectionID);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncc_load_imc(struct tnc_if_imc *imc)
-{
-	if (imc->path == NULL) {
-		wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
-		   imc->name, imc->path);
-#ifdef CONFIG_NATIVE_WINDOWS
-#ifdef UNICODE
-	{
-		TCHAR *lib = wpa_strdup_tchar(imc->path);
-		if (lib == NULL)
-			return -1;
-		imc->dlhandle = LoadLibrary(lib);
-		os_free(lib);
-	}
-#else /* UNICODE */
-	imc->dlhandle = LoadLibrary(imc->path);
-#endif /* UNICODE */
-	if (imc->dlhandle == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
-			   imc->name, imc->path, (int) GetLastError());
-		return -1;
-	}
-#else /* CONFIG_NATIVE_WINDOWS */
-	imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
-	if (imc->dlhandle == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
-			   imc->name, imc->path, dlerror());
-		return -1;
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	if (tncc_imc_resolve_funcs(imc) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
-		return -1;
-	}
-
-	if (tncc_imc_initialize(imc) < 0 ||
-	    tncc_imc_provide_bind_function(imc) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void tncc_unload_imc(struct tnc_if_imc *imc)
-{
-	tncc_imc_terminate(imc);
-	tnc_imc[imc->imcID] = NULL;
-
-	if (imc->dlhandle) {
-#ifdef CONFIG_NATIVE_WINDOWS
-		FreeLibrary(imc->dlhandle);
-#else /* CONFIG_NATIVE_WINDOWS */
-		dlclose(imc->dlhandle);
-#endif /* CONFIG_NATIVE_WINDOWS */
-	}
-	os_free(imc->name);
-	os_free(imc->path);
-	os_free(imc->supported_types);
-	os_free(imc->imc_send);
-}
-
-
-static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
-{
-	size_t i;
-	unsigned int vendor, subtype;
-
-	if (imc == NULL || imc->supported_types == NULL)
-		return 0;
-
-	vendor = type >> 8;
-	subtype = type & 0xff;
-
-	for (i = 0; i < imc->num_supported_types; i++) {
-		unsigned int svendor, ssubtype;
-		svendor = imc->supported_types[i] >> 8;
-		ssubtype = imc->supported_types[i] & 0xff;
-		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
-		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
-			return 1;
-	}
-
-	return 0;
-}
-
-
-static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
-			      const u8 *msg, size_t len)
-{
-	struct tnc_if_imc *imc;
-	TNC_Result res;
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
-
-	for (imc = tncc->imc; imc; imc = imc->next) {
-		if (imc->ReceiveMessage == NULL ||
-		    !tncc_supported_type(imc, type))
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
-			   imc->name);
-		res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
-					  (TNC_BufferReference) msg, len,
-					  type);
-		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
-			   (unsigned long) res);
-	}
-}
-
-
-void tncc_init_connection(struct tncc_data *tncc)
-{
-	struct tnc_if_imc *imc;
-
-	for (imc = tncc->imc; imc; imc = imc->next) {
-		tncc_imc_notify_connection_change(
-			imc, TNC_CONNECTION_STATE_CREATE);
-		tncc_imc_notify_connection_change(
-			imc, TNC_CONNECTION_STATE_HANDSHAKE);
-
-		os_free(imc->imc_send);
-		imc->imc_send = NULL;
-		imc->imc_send_len = 0;
-
-		tncc_imc_begin_handshake(imc);
-	}
-}
-
-
-size_t tncc_total_send_len(struct tncc_data *tncc)
-{
-	struct tnc_if_imc *imc;
-
-	size_t len = 0;
-	for (imc = tncc->imc; imc; imc = imc->next)
-		len += imc->imc_send_len;
-	return len;
-}
-
-
-u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
-{
-	struct tnc_if_imc *imc;
-
-	for (imc = tncc->imc; imc; imc = imc->next) {
-		if (imc->imc_send == NULL)
-			continue;
-
-		os_memcpy(pos, imc->imc_send, imc->imc_send_len);
-		pos += imc->imc_send_len;
-		os_free(imc->imc_send);
-		imc->imc_send = NULL;
-		imc->imc_send_len = 0;
-	}
-
-	return pos;
-}
-
-
-char * tncc_if_tnccs_start(struct tncc_data *tncc)
-{
-	char *buf = os_malloc(1000);
-	if (buf == NULL)
-		return NULL;
-	tncc->last_batchid++;
-	os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
-	return buf;
-}
-
-
-char * tncc_if_tnccs_end(void)
-{
-	char *buf = os_malloc(100);
-	if (buf == NULL)
-		return NULL;
-	os_snprintf(buf, 100, IF_TNCCS_END);
-	return buf;
-}
-
-
-static void tncc_notify_recommendation(struct tncc_data *tncc,
-				       enum tncc_process_res res)
-{
-	TNC_ConnectionState state;
-	struct tnc_if_imc *imc;
-
-	switch (res) {
-	case TNCCS_RECOMMENDATION_ALLOW:
-		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
-		break;
-	case TNCCS_RECOMMENDATION_NONE:
-		state = TNC_CONNECTION_STATE_ACCESS_NONE;
-		break;
-	case TNCCS_RECOMMENDATION_ISOLATE:
-		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
-		break;
-	default:
-		state = TNC_CONNECTION_STATE_ACCESS_NONE;
-		break;
-	}
-
-	for (imc = tncc->imc; imc; imc = imc->next)
-		tncc_imc_notify_connection_change(imc, state);
-}
-
-
-static int tncc_get_type(char *start, unsigned int *type)
-{
-	char *pos = os_strstr(start, "<Type>");
-	if (pos == NULL)
-		return -1;
-	pos += 6;
-	*type = strtoul(pos, NULL, 16);
-	return 0;
-}
-
-
-static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
-{
-	char *pos, *pos2;
-	unsigned char *decoded;
-
-	pos = os_strstr(start, "<Base64>");
-	if (pos == NULL)
-		return NULL;
-
-	pos += 8;
-	pos2 = os_strstr(pos, "</Base64>");
-	if (pos2 == NULL)
-		return NULL;
-	*pos2 = '\0';
-
-	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
-				decoded_len);
-	*pos2 = '<';
-	if (decoded == NULL) {
-		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
-	}
-
-	return decoded;
-}
-
-
-static enum tncc_process_res tncc_get_recommendation(char *start)
-{
-	char *pos, *pos2, saved;
-	int recom;
-
-	pos = os_strstr(start, "<TNCCS-Recommendation ");
-	if (pos == NULL)
-		return TNCCS_RECOMMENDATION_ERROR;
-
-	pos += 21;
-	pos = os_strstr(pos, " type=");
-	if (pos == NULL)
-		return TNCCS_RECOMMENDATION_ERROR;
-	pos += 6;
-
-	if (*pos == '"')
-		pos++;
-
-	pos2 = pos;
-	while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
-		pos2++;
-
-	if (*pos2 == '\0')
-		return TNCCS_RECOMMENDATION_ERROR;
-
-	saved = *pos2;
-	*pos2 = '\0';
-	wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
-
-	recom = TNCCS_RECOMMENDATION_ERROR;
-	if (os_strcmp(pos, "allow") == 0)
-		recom = TNCCS_RECOMMENDATION_ALLOW;
-	else if (os_strcmp(pos, "none") == 0)
-		recom = TNCCS_RECOMMENDATION_NONE;
-	else if (os_strcmp(pos, "isolate") == 0)
-		recom = TNCCS_RECOMMENDATION_ISOLATE;
-
-	*pos2 = saved;
-
-	return recom;
-}
-
-
-enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
-					    const u8 *msg, size_t len)
-{
-	char *buf, *start, *end, *pos, *pos2, *payload;
-	unsigned int batch_id;
-	unsigned char *decoded;
-	size_t decoded_len;
-	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
-	int recommendation_msg = 0;
-
-	buf = os_malloc(len + 1);
-	if (buf == NULL)
-		return TNCCS_PROCESS_ERROR;
-
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
-	start = os_strstr(buf, "<TNCCS-Batch ");
-	end = os_strstr(buf, "</TNCCS-Batch>");
-	if (start == NULL || end == NULL || start > end) {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-
-	start += 13;
-	while (*start == ' ')
-		start++;
-	*end = '\0';
-
-	pos = os_strstr(start, "BatchId=");
-	if (pos == NULL) {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-
-	pos += 8;
-	if (*pos == '"')
-		pos++;
-	batch_id = atoi(pos);
-	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
-		   batch_id);
-	if (batch_id != tncc->last_batchid + 1) {
-		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
-			   "%u (expected %u)",
-			   batch_id, tncc->last_batchid + 1);
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-	tncc->last_batchid = batch_id;
-
-	while (*pos != '\0' && *pos != '>')
-		pos++;
-	if (*pos == '\0') {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-	pos++;
-	payload = start;
-
-	/*
-	 * <IMC-IMV-Message>
-	 * <Type>01234567</Type>
-	 * <Base64>foo==</Base64>
-	 * </IMC-IMV-Message>
-	 */
-
-	while (*start) {
-		char *endpos;
-		unsigned int type;
-
-		pos = os_strstr(start, "<IMC-IMV-Message>");
-		if (pos == NULL)
-			break;
-		start = pos + 17;
-		end = os_strstr(start, "</IMC-IMV-Message>");
-		if (end == NULL)
-			break;
-		*end = '\0';
-		endpos = end;
-		end += 18;
-
-		if (tncc_get_type(start, &type) < 0) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
-
-		decoded = tncc_get_base64(start, &decoded_len);
-		if (decoded == NULL) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-
-		tncc_send_to_imcs(tncc, type, decoded, decoded_len);
-
-		os_free(decoded);
-
-		start = end;
-	}
-
-	/*
-	 * <TNCC-TNCS-Message>
-	 * <Type>01234567</Type>
-	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
-	 * <Base64>foo==</Base64>
-	 * </TNCC-TNCS-Message>
-	 */
-
-	start = payload;
-	while (*start) {
-		unsigned int type;
-		char *xml, *xmlend, *endpos;
-
-		pos = os_strstr(start, "<TNCC-TNCS-Message>");
-		if (pos == NULL)
-			break;
-		start = pos + 19;
-		end = os_strstr(start, "</TNCC-TNCS-Message>");
-		if (end == NULL)
-			break;
-		*end = '\0';
-		endpos = end;
-		end += 20;
-
-		if (tncc_get_type(start, &type) < 0) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
-			   type);
-
-		/* Base64 OR XML */
-		decoded = NULL;
-		xml = NULL;
-		xmlend = NULL;
-		pos = os_strstr(start, "<XML>");
-		if (pos) {
-			pos += 5;
-			pos2 = os_strstr(pos, "</XML>");
-			if (pos2 == NULL) {
-				*endpos = '<';
-				start = end;
-				continue;
-			}
-			xmlend = pos2;
-			xml = pos;
-		} else {
-			decoded = tncc_get_base64(start, &decoded_len);
-			if (decoded == NULL) {
-				*endpos = '<';
-				start = end;
-				continue;
-			}
-		}
-
-		if (decoded) {
-			wpa_hexdump_ascii(MSG_MSGDUMP,
-					  "TNC: TNCC-TNCS-Message Base64",
-					  decoded, decoded_len);
-			os_free(decoded);
-		}
-
-		if (xml) {
-			wpa_hexdump_ascii(MSG_MSGDUMP,
-					  "TNC: TNCC-TNCS-Message XML",
-					  (unsigned char *) xml,
-					  xmlend - xml);
-		}
-
-		if (type == TNC_TNCCS_RECOMMENDATION && xml) {
-			/*
-			 * <TNCCS-Recommendation type="allow">
-			 * </TNCCS-Recommendation>
-			 */
-			*xmlend = '\0';
-			res = tncc_get_recommendation(xml);
-			*xmlend = '<';
-			recommendation_msg = 1;
-		}
-
-		start = end;
-	}
-
-	os_free(buf);
-
-	if (recommendation_msg)
-		tncc_notify_recommendation(tncc, res);
-
-	return res;
-}
-
-
-#ifdef CONFIG_NATIVE_WINDOWS
-static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
-{
-	HKEY hk, hk2;
-	LONG ret;
-	DWORD i;
-	struct tnc_if_imc *imc, *last;
-	int j;
-
-	last = tncc->imc;
-	while (last && last->next)
-		last = last->next;
-
-	ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
-			   &hk);
-	if (ret != ERROR_SUCCESS)
-		return 0;
-
-	for (i = 0; ; i++) {
-		TCHAR name[255], *val;
-		DWORD namelen, buflen;
-
-		namelen = 255;
-		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
-				   NULL);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
-				   (unsigned int) ret);
-			break;
-		}
-
-		if (namelen >= 255)
-			namelen = 255 - 1;
-		name[namelen] = '\0';
-
-		wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
-
-		ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
-				   "'", name);
-			continue;
-		}
-
-		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
-				      &buflen);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
-				   "IMC key '" TSTR "'", name);
-			RegCloseKey(hk2);
-			continue;
-		}
-
-		val = os_malloc(buflen);
-		if (val == NULL) {
-			RegCloseKey(hk2);
-			continue;
-		}
-
-		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
-				      (LPBYTE) val, &buflen);
-		if (ret != ERROR_SUCCESS) {
-			os_free(val);
-			RegCloseKey(hk2);
-			continue;
-		}
-
-		RegCloseKey(hk2);
-
-		wpa_unicode2ascii_inplace(val);
-		wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
-
-		for (j = 0; j < TNC_MAX_IMC_ID; j++) {
-			if (tnc_imc[j] == NULL)
-				break;
-		}
-		if (j >= TNC_MAX_IMC_ID) {
-			wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
-			os_free(val);
-			continue;
-		}
-
-		imc = os_zalloc(sizeof(*imc));
-		if (imc == NULL) {
-			os_free(val);
-			break;
-		}
-
-		imc->imcID = j;
-
-		wpa_unicode2ascii_inplace(name);
-		imc->name = os_strdup((char *) name);
-		imc->path = os_strdup((char *) val);
-
-		os_free(val);
-
-		if (last == NULL)
-			tncc->imc = imc;
-		else
-			last->next = imc;
-		last = imc;
-
-		tnc_imc[imc->imcID] = imc;
-	}
-
-	RegCloseKey(hk);
-
-	return 0;
-}
-
-
-static int tncc_read_config(struct tncc_data *tncc)
-{
-	if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
-	    tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
-		return -1;
-	return 0;
-}
-
-#else /* CONFIG_NATIVE_WINDOWS */
-
-static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
-{
-	struct tnc_if_imc *imc;
-	char *pos, *pos2;
-	int i;
-
-	for (i = 0; i < TNC_MAX_IMC_ID; i++) {
-		if (tnc_imc[i] == NULL)
-			break;
-	}
-	if (i >= TNC_MAX_IMC_ID) {
-		wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
-		return NULL;
-	}
-
-	imc = os_zalloc(sizeof(*imc));
-	if (imc == NULL) {
-		*error = 1;
-		return NULL;
-	}
-
-	imc->imcID = i;
-
-	pos = start;
-	wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
-	if (pos + 1 >= end || *pos != '"') {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
-			   "(no starting quotation mark)", start);
-		os_free(imc);
-		return NULL;
-	}
-
-	pos++;
-	pos2 = pos;
-	while (pos2 < end && *pos2 != '"')
-		pos2++;
-	if (pos2 >= end) {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
-			   "(no ending quotation mark)", start);
-		os_free(imc);
-		return NULL;
-	}
-	*pos2 = '\0';
-	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
-	imc->name = os_strdup(pos);
-
-	pos = pos2 + 1;
-	if (pos >= end || *pos != ' ') {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
-			   "(no space after name)", start);
-		os_free(imc->name);
-		os_free(imc);
-		return NULL;
-	}
-
-	pos++;
-	wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
-	imc->path = os_strdup(pos);
-	tnc_imc[imc->imcID] = imc;
-
-	return imc;
-}
-
-
-static int tncc_read_config(struct tncc_data *tncc)
-{
-	char *config, *end, *pos, *line_end;
-	size_t config_len;
-	struct tnc_if_imc *imc, *last;
-
-	last = NULL;
-
-	config = os_readfile(TNC_CONFIG_FILE, &config_len);
-	if (config == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
-			   "file '%s'", TNC_CONFIG_FILE);
-		return -1;
-	}
-
-	end = config + config_len;
-	for (pos = config; pos < end; pos = line_end + 1) {
-		line_end = pos;
-		while (*line_end != '\n' && *line_end != '\r' &&
-		       line_end < end)
-			line_end++;
-		*line_end = '\0';
-
-		if (os_strncmp(pos, "IMC ", 4) == 0) {
-			int error = 0;
-
-			imc = tncc_parse_imc(pos + 4, line_end, &error);
-			if (error)
-				return -1;
-			if (imc) {
-				if (last == NULL)
-					tncc->imc = imc;
-				else
-					last->next = imc;
-				last = imc;
-			}
-		}
-	}
-
-	os_free(config);
-
-	return 0;
-}
-
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-struct tncc_data * tncc_init(void)
-{
-	struct tncc_data *tncc;
-	struct tnc_if_imc *imc;
-
-	tncc = os_zalloc(sizeof(*tncc));
-	if (tncc == NULL)
-		return NULL;
-
-	/* TODO:
-	 * move loading and Initialize() to a location that is not
-	 *    re-initialized for every EAP-TNC session (?)
-	 */
-
-	if (tncc_read_config(tncc) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
-		goto failed;
-	}
-
-	for (imc = tncc->imc; imc; imc = imc->next) {
-		if (tncc_load_imc(imc)) {
-			wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
-				   imc->name);
-			goto failed;
-		}
-	}
-
-	return tncc;
-
-failed:
-	tncc_deinit(tncc);
-	return NULL;
-}
-
-
-void tncc_deinit(struct tncc_data *tncc)
-{
-	struct tnc_if_imc *imc, *prev;
-
-	imc = tncc->imc;
-	while (imc) {
-		tncc_unload_imc(imc);
-
-		prev = imc;
-		imc = imc->next;
-		os_free(prev);
-	}
-
-	os_free(tncc);
-}
-
-
-static struct wpabuf * tncc_build_soh(int ver)
-{
-	struct wpabuf *buf;
-	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
-	u8 correlation_id[24];
-	/* TODO: get correct name */
-	char *machinename = "wpa_supplicant at w1.fi";
-
-	if (os_get_random(correlation_id, sizeof(correlation_id)))
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
-		    correlation_id, sizeof(correlation_id));
-
-	buf = wpabuf_alloc(200);
-	if (buf == NULL)
-		return NULL;
-
-	/* Vendor-Specific TLV (Microsoft) - SoH */
-	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
-	tlv_len = wpabuf_put(buf, 2); /* Length */
-	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
-	wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
-	tlv_len2 = wpabuf_put(buf, 2); /* Length */
-
-	/* SoH Header */
-	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
-	outer_len = wpabuf_put(buf, 2);
-	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
-	wpabuf_put_be16(buf, ver); /* Inner Type */
-	inner_len = wpabuf_put(buf, 2);
-
-	if (ver == 2) {
-		/* SoH Mode Sub-Header */
-		/* Outer Type */
-		wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
-		wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
-		wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
-		/* Value: */
-		wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
-		wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
-		wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
-	}
-
-	/* SSoH TLV */
-	/* System-Health-Id */
-	wpabuf_put_be16(buf, 0x0002); /* Type */
-	wpabuf_put_be16(buf, 4); /* Length */
-	wpabuf_put_be32(buf, 79616);
-	/* Vendor-Specific Attribute */
-	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
-	ssoh_len = wpabuf_put(buf, 2);
-	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
-
-	/* MS-Packet-Info */
-	wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
-	/* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
-	 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
-	 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
-	 * would not be in the specified location.
-	 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
-	 */
-	wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
-
-	/* MS-Machine-Inventory */
-	/* TODO: get correct values; 0 = not applicable for OS */
-	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
-	wpabuf_put_be32(buf, 0); /* osVersionMajor */
-	wpabuf_put_be32(buf, 0); /* osVersionMinor */
-	wpabuf_put_be32(buf, 0); /* osVersionBuild */
-	wpabuf_put_be16(buf, 0); /* spVersionMajor */
-	wpabuf_put_be16(buf, 0); /* spVersionMinor */
-	wpabuf_put_be16(buf, 0); /* procArch */
-
-	/* MS-MachineName */
-	wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
-	wpabuf_put_be16(buf, os_strlen(machinename) + 1);
-	wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
-
-	/* MS-CorrelationId */
-	wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
-	wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
-
-	/* MS-Quarantine-State */
-	wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
-	wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
-	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
-	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
-	wpabuf_put_be16(buf, 1); /* urlLenInBytes */
-	wpabuf_put_u8(buf, 0); /* null termination for the url */
-
-	/* MS-Machine-Inventory-Ex */
-	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
-	wpabuf_put_be32(buf, 0); /* Reserved
-				  * (note: Windows XP SP3 uses 0xdecafbad) */
-	wpabuf_put_u8(buf, 1); /* ProductType: Client */
-
-	/* Update SSoH Length */
-	end = wpabuf_put(buf, 0);
-	WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
-
-	/* TODO: SoHReportEntry TLV (zero or more) */
-
-	/* Update length fields */
-	end = wpabuf_put(buf, 0);
-	WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
-	WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
-	WPA_PUT_BE16(outer_len, end - outer_len - 2);
-	WPA_PUT_BE16(inner_len, end - inner_len - 2);
-
-	return buf;
-}
-
-
-struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
-{
-	const u8 *pos;
-
-	wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
-
-	if (len < 12)
-		return NULL;
-
-	/* SoH Request */
-	pos = data;
-
-	/* TLV Type */
-	if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
-		return NULL;
-	pos += 2;
-
-	/* Length */
-	if (WPA_GET_BE16(pos) < 8)
-		return NULL;
-	pos += 2;
-
-	/* Vendor_Id */
-	if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
-		return NULL;
-	pos += 4;
-
-	/* TLV Type */
-	if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
-
-	return tncc_build_soh(2);
-}

Copied: vendor/wpa/2.0/src/eap_peer/tncc.c (from rev 9639, vendor/wpa/dist/src/eap_peer/tncc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/tncc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/tncc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1363 @@
+/*
+ * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <dlfcn.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "common.h"
+#include "base64.h"
+#include "tncc.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
+
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+#define TNC_CONFIG_FILE "/etc/tnc_config"
+#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
+#define IF_TNCCS_START \
+"<?xml version=\"1.0\"?>\n" \
+"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
+"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+#define IF_TNCCS_END "\n</TNCCS-Batch>"
+
+/* TNC IF-IMC */
+
+typedef unsigned long TNC_UInt32;
+typedef unsigned char *TNC_BufferReference;
+
+typedef TNC_UInt32 TNC_IMCID;
+typedef TNC_UInt32 TNC_ConnectionID;
+typedef TNC_UInt32 TNC_ConnectionState;
+typedef TNC_UInt32 TNC_RetryReason;
+typedef TNC_UInt32 TNC_MessageType;
+typedef TNC_MessageType *TNC_MessageTypeList;
+typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_UInt32 TNC_MessageSubtype;
+typedef TNC_UInt32 TNC_Version;
+typedef TNC_UInt32 TNC_Result;
+
+typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
+	TNC_IMCID imcID,
+	char *functionName,
+	void **pOutfunctionPointer);
+
+#define TNC_RESULT_SUCCESS 0
+#define TNC_RESULT_NOT_INITIALIZED 1
+#define TNC_RESULT_ALREADY_INITIALIZED 2
+#define TNC_RESULT_NO_COMMON_VERSION 3
+#define TNC_RESULT_CANT_RETRY 4
+#define TNC_RESULT_WONT_RETRY 5
+#define TNC_RESULT_INVALID_PARAMETER 6
+#define TNC_RESULT_CANT_RESPOND 7
+#define TNC_RESULT_ILLEGAL_OPERATION 8
+#define TNC_RESULT_OTHER 9
+#define TNC_RESULT_FATAL 10
+
+#define TNC_CONNECTION_STATE_CREATE 0
+#define TNC_CONNECTION_STATE_HANDSHAKE 1
+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
+#define TNC_CONNECTION_STATE_ACCESS_NONE 4
+#define TNC_CONNECTION_STATE_DELETE 5
+
+#define TNC_IFIMC_VERSION_1 1
+
+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
+
+/* TNCC-TNCS Message Types */
+#define TNC_TNCCS_RECOMMENDATION		0x00000001
+#define TNC_TNCCS_ERROR				0x00000002
+#define TNC_TNCCS_PREFERREDLANGUAGE		0x00000003
+#define TNC_TNCCS_REASONSTRINGS			0x00000004
+
+
+/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
+enum {
+	SSOH_MS_MACHINE_INVENTORY = 1,
+	SSOH_MS_QUARANTINE_STATE = 2,
+	SSOH_MS_PACKET_INFO = 3,
+	SSOH_MS_SYSTEMGENERATED_IDS = 4,
+	SSOH_MS_MACHINENAME = 5,
+	SSOH_MS_CORRELATIONID = 6,
+	SSOH_MS_INSTALLED_SHVS = 7,
+	SSOH_MS_MACHINE_INVENTORY_EX = 8
+};
+
+struct tnc_if_imc {
+	struct tnc_if_imc *next;
+	char *name;
+	char *path;
+	void *dlhandle; /* from dlopen() */
+	TNC_IMCID imcID;
+	TNC_ConnectionID connectionID;
+	TNC_MessageTypeList supported_types;
+	size_t num_supported_types;
+	u8 *imc_send;
+	size_t imc_send_len;
+
+	/* Functions implemented by IMCs (with TNC_IMC_ prefix) */
+	TNC_Result (*Initialize)(
+		TNC_IMCID imcID,
+		TNC_Version minVersion,
+		TNC_Version maxVersion,
+		TNC_Version *pOutActualVersion);
+	TNC_Result (*NotifyConnectionChange)(
+		TNC_IMCID imcID,
+		TNC_ConnectionID connectionID,
+		TNC_ConnectionState newState);
+	TNC_Result (*BeginHandshake)(
+		TNC_IMCID imcID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*ReceiveMessage)(
+		TNC_IMCID imcID,
+		TNC_ConnectionID connectionID,
+		TNC_BufferReference messageBuffer,
+		TNC_UInt32 messageLength,
+		TNC_MessageType messageType);
+	TNC_Result (*BatchEnding)(
+		TNC_IMCID imcID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*Terminate)(TNC_IMCID imcID);
+	TNC_Result (*ProvideBindFunction)(
+		TNC_IMCID imcID,
+		TNC_TNCC_BindFunctionPointer bindFunction);
+};
+
+struct tncc_data {
+	struct tnc_if_imc *imc;
+	unsigned int last_batchid;
+};
+
+#define TNC_MAX_IMC_ID 10
+static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
+
+
+/* TNCC functions that IMCs can call */
+
+TNC_Result TNC_TNCC_ReportMessageTypes(
+	TNC_IMCID imcID,
+	TNC_MessageTypeList supportedTypes,
+	TNC_UInt32 typeCount)
+{
+	TNC_UInt32 i;
+	struct tnc_if_imc *imc;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
+		   "typeCount=%lu)",
+		   (unsigned long) imcID, (unsigned long) typeCount);
+
+	for (i = 0; i < typeCount; i++) {
+		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
+			   i, supportedTypes[i]);
+	}
+
+	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	imc = tnc_imc[imcID];
+	os_free(imc->supported_types);
+	imc->supported_types =
+		os_malloc(typeCount * sizeof(TNC_MessageType));
+	if (imc->supported_types == NULL)
+		return TNC_RESULT_FATAL;
+	os_memcpy(imc->supported_types, supportedTypes,
+		  typeCount * sizeof(TNC_MessageType));
+	imc->num_supported_types = typeCount;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCC_SendMessage(
+	TNC_IMCID imcID,
+	TNC_ConnectionID connectionID,
+	TNC_BufferReference message,
+	TNC_UInt32 messageLength,
+	TNC_MessageType messageType)
+{
+	struct tnc_if_imc *imc;
+	unsigned char *b64;
+	size_t b64len;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
+		   "connectionID=%lu messageType=%lu)",
+		   imcID, connectionID, messageType);
+	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
+			  message, messageLength);
+
+	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	b64 = base64_encode(message, messageLength, &b64len);
+	if (b64 == NULL)
+		return TNC_RESULT_FATAL;
+
+	imc = tnc_imc[imcID];
+	os_free(imc->imc_send);
+	imc->imc_send_len = 0;
+	imc->imc_send = os_zalloc(b64len + 100);
+	if (imc->imc_send == NULL) {
+		os_free(b64);
+		return TNC_RESULT_OTHER;
+	}
+
+	imc->imc_send_len =
+		os_snprintf((char *) imc->imc_send, b64len + 100,
+			    "<IMC-IMV-Message><Type>%08X</Type>"
+			    "<Base64>%s</Base64></IMC-IMV-Message>",
+			    (unsigned int) messageType, b64);
+
+	os_free(b64);
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCC_RequestHandshakeRetry(
+	TNC_IMCID imcID,
+	TNC_ConnectionID connectionID,
+	TNC_RetryReason reason)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
+
+	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	/*
+	 * TODO: trigger a call to eapol_sm_request_reauth(). This would
+	 * require that the IMC continues to be loaded in memory afer
+	 * authentication..
+	 */
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+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')",
+		   imcID, severity, message);
+	return TNC_RESULT_SUCCESS;
+}
+
+
+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')",
+		   imcID, connectionID, message);
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCC_BindFunction(
+	TNC_IMCID imcID,
+	char *functionName,
+	void **pOutfunctionPointer)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
+		   "functionName='%s')", (unsigned long) imcID, functionName);
+
+	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (pOutfunctionPointer == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
+		*pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
+	else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
+		*pOutfunctionPointer = TNC_TNCC_SendMessage;
+	else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
+		 0)
+		*pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
+	else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
+		*pOutfunctionPointer = TNC_9048_LogMessage;
+	else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
+		*pOutfunctionPointer = TNC_9048_UserMessage;
+	else
+		*pOutfunctionPointer = NULL;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+static void * tncc_get_sym(void *handle, char *func)
+{
+	void *fptr;
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#ifdef _WIN32_WCE
+	fptr = GetProcAddressA(handle, func);
+#else /* _WIN32_WCE */
+	fptr = GetProcAddress(handle, func);
+#endif /* _WIN32_WCE */
+#else /* CONFIG_NATIVE_WINDOWS */
+	fptr = dlsym(handle, func);
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	return fptr;
+}
+
+
+static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
+{
+	void *handle = imc->dlhandle;
+
+	/* Mandatory IMC functions */
+	imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
+	if (imc->Initialize == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
+			   "TNC_IMC_Initialize");
+		return -1;
+	}
+
+	imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
+	if (imc->BeginHandshake == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
+			   "TNC_IMC_BeginHandshake");
+		return -1;
+	}
+
+	imc->ProvideBindFunction =
+		tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
+	if (imc->ProvideBindFunction == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
+			   "TNC_IMC_ProvideBindFunction");
+		return -1;
+	}
+
+	/* Optional IMC functions */
+	imc->NotifyConnectionChange =
+		tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
+	imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
+	imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
+	imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
+
+	return 0;
+}
+
+
+static int tncc_imc_initialize(struct tnc_if_imc *imc)
+{
+	TNC_Result res;
+	TNC_Version imc_ver;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
+		   imc->name);
+	res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
+			      TNC_IFIMC_VERSION_1, &imc_ver);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
+		   (unsigned long) res, (unsigned long) imc_ver);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncc_imc_terminate(struct tnc_if_imc *imc)
+{
+	TNC_Result res;
+
+	if (imc->Terminate == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
+		   imc->name);
+	res = imc->Terminate(imc->imcID);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
+{
+	TNC_Result res;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
+		   "IMC '%s'", imc->name);
+	res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
+					     TNC_ConnectionState state)
+{
+	TNC_Result res;
+
+	if (imc->NotifyConnectionChange == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
+		   " for IMC '%s'", (int) state, imc->name);
+	res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
+					  state);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
+{
+	TNC_Result res;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
+		   "'%s'", imc->name);
+	res = imc->BeginHandshake(imc->imcID, imc->connectionID);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncc_load_imc(struct tnc_if_imc *imc)
+{
+	if (imc->path == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
+		   imc->name, imc->path);
+#ifdef CONFIG_NATIVE_WINDOWS
+#ifdef UNICODE
+	{
+		TCHAR *lib = wpa_strdup_tchar(imc->path);
+		if (lib == NULL)
+			return -1;
+		imc->dlhandle = LoadLibrary(lib);
+		os_free(lib);
+	}
+#else /* UNICODE */
+	imc->dlhandle = LoadLibrary(imc->path);
+#endif /* UNICODE */
+	if (imc->dlhandle == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
+			   imc->name, imc->path, (int) GetLastError());
+		return -1;
+	}
+#else /* CONFIG_NATIVE_WINDOWS */
+	imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
+	if (imc->dlhandle == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
+			   imc->name, imc->path, dlerror());
+		return -1;
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	if (tncc_imc_resolve_funcs(imc) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
+		return -1;
+	}
+
+	if (tncc_imc_initialize(imc) < 0 ||
+	    tncc_imc_provide_bind_function(imc) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void tncc_unload_imc(struct tnc_if_imc *imc)
+{
+	tncc_imc_terminate(imc);
+	tnc_imc[imc->imcID] = NULL;
+
+	if (imc->dlhandle) {
+#ifdef CONFIG_NATIVE_WINDOWS
+		FreeLibrary(imc->dlhandle);
+#else /* CONFIG_NATIVE_WINDOWS */
+		dlclose(imc->dlhandle);
+#endif /* CONFIG_NATIVE_WINDOWS */
+	}
+	os_free(imc->name);
+	os_free(imc->path);
+	os_free(imc->supported_types);
+	os_free(imc->imc_send);
+}
+
+
+static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
+{
+	size_t i;
+	unsigned int vendor, subtype;
+
+	if (imc == NULL || imc->supported_types == NULL)
+		return 0;
+
+	vendor = type >> 8;
+	subtype = type & 0xff;
+
+	for (i = 0; i < imc->num_supported_types; i++) {
+		unsigned int svendor, ssubtype;
+		svendor = imc->supported_types[i] >> 8;
+		ssubtype = imc->supported_types[i] & 0xff;
+		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
+		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
+			      const u8 *msg, size_t len)
+{
+	struct tnc_if_imc *imc;
+	TNC_Result res;
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
+
+	for (imc = tncc->imc; imc; imc = imc->next) {
+		if (imc->ReceiveMessage == NULL ||
+		    !tncc_supported_type(imc, type))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
+			   imc->name);
+		res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
+					  (TNC_BufferReference) msg, len,
+					  type);
+		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+void tncc_init_connection(struct tncc_data *tncc)
+{
+	struct tnc_if_imc *imc;
+
+	for (imc = tncc->imc; imc; imc = imc->next) {
+		tncc_imc_notify_connection_change(
+			imc, TNC_CONNECTION_STATE_CREATE);
+		tncc_imc_notify_connection_change(
+			imc, TNC_CONNECTION_STATE_HANDSHAKE);
+
+		os_free(imc->imc_send);
+		imc->imc_send = NULL;
+		imc->imc_send_len = 0;
+
+		tncc_imc_begin_handshake(imc);
+	}
+}
+
+
+size_t tncc_total_send_len(struct tncc_data *tncc)
+{
+	struct tnc_if_imc *imc;
+
+	size_t len = 0;
+	for (imc = tncc->imc; imc; imc = imc->next)
+		len += imc->imc_send_len;
+	return len;
+}
+
+
+u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
+{
+	struct tnc_if_imc *imc;
+
+	for (imc = tncc->imc; imc; imc = imc->next) {
+		if (imc->imc_send == NULL)
+			continue;
+
+		os_memcpy(pos, imc->imc_send, imc->imc_send_len);
+		pos += imc->imc_send_len;
+		os_free(imc->imc_send);
+		imc->imc_send = NULL;
+		imc->imc_send_len = 0;
+	}
+
+	return pos;
+}
+
+
+char * tncc_if_tnccs_start(struct tncc_data *tncc)
+{
+	char *buf = os_malloc(1000);
+	if (buf == NULL)
+		return NULL;
+	tncc->last_batchid++;
+	os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
+	return buf;
+}
+
+
+char * tncc_if_tnccs_end(void)
+{
+	char *buf = os_malloc(100);
+	if (buf == NULL)
+		return NULL;
+	os_snprintf(buf, 100, IF_TNCCS_END);
+	return buf;
+}
+
+
+static void tncc_notify_recommendation(struct tncc_data *tncc,
+				       enum tncc_process_res res)
+{
+	TNC_ConnectionState state;
+	struct tnc_if_imc *imc;
+
+	switch (res) {
+	case TNCCS_RECOMMENDATION_ALLOW:
+		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+		break;
+	case TNCCS_RECOMMENDATION_NONE:
+		state = TNC_CONNECTION_STATE_ACCESS_NONE;
+		break;
+	case TNCCS_RECOMMENDATION_ISOLATE:
+		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+		break;
+	default:
+		state = TNC_CONNECTION_STATE_ACCESS_NONE;
+		break;
+	}
+
+	for (imc = tncc->imc; imc; imc = imc->next)
+		tncc_imc_notify_connection_change(imc, state);
+}
+
+
+static int tncc_get_type(char *start, unsigned int *type)
+{
+	char *pos = os_strstr(start, "<Type>");
+	if (pos == NULL)
+		return -1;
+	pos += 6;
+	*type = strtoul(pos, NULL, 16);
+	return 0;
+}
+
+
+static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
+{
+	char *pos, *pos2;
+	unsigned char *decoded;
+
+	pos = os_strstr(start, "<Base64>");
+	if (pos == NULL)
+		return NULL;
+
+	pos += 8;
+	pos2 = os_strstr(pos, "</Base64>");
+	if (pos2 == NULL)
+		return NULL;
+	*pos2 = '\0';
+
+	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
+				decoded_len);
+	*pos2 = '<';
+	if (decoded == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
+	}
+
+	return decoded;
+}
+
+
+static enum tncc_process_res tncc_get_recommendation(char *start)
+{
+	char *pos, *pos2, saved;
+	int recom;
+
+	pos = os_strstr(start, "<TNCCS-Recommendation ");
+	if (pos == NULL)
+		return TNCCS_RECOMMENDATION_ERROR;
+
+	pos += 21;
+	pos = os_strstr(pos, " type=");
+	if (pos == NULL)
+		return TNCCS_RECOMMENDATION_ERROR;
+	pos += 6;
+
+	if (*pos == '"')
+		pos++;
+
+	pos2 = pos;
+	while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
+		pos2++;
+
+	if (*pos2 == '\0')
+		return TNCCS_RECOMMENDATION_ERROR;
+
+	saved = *pos2;
+	*pos2 = '\0';
+	wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
+
+	recom = TNCCS_RECOMMENDATION_ERROR;
+	if (os_strcmp(pos, "allow") == 0)
+		recom = TNCCS_RECOMMENDATION_ALLOW;
+	else if (os_strcmp(pos, "none") == 0)
+		recom = TNCCS_RECOMMENDATION_NONE;
+	else if (os_strcmp(pos, "isolate") == 0)
+		recom = TNCCS_RECOMMENDATION_ISOLATE;
+
+	*pos2 = saved;
+
+	return recom;
+}
+
+
+enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
+					    const u8 *msg, size_t len)
+{
+	char *buf, *start, *end, *pos, *pos2, *payload;
+	unsigned int batch_id;
+	unsigned char *decoded;
+	size_t decoded_len;
+	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+	int recommendation_msg = 0;
+
+	buf = os_malloc(len + 1);
+	if (buf == NULL)
+		return TNCCS_PROCESS_ERROR;
+
+	os_memcpy(buf, msg, len);
+	buf[len] = '\0';
+	start = os_strstr(buf, "<TNCCS-Batch ");
+	end = os_strstr(buf, "</TNCCS-Batch>");
+	if (start == NULL || end == NULL || start > end) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	start += 13;
+	while (*start == ' ')
+		start++;
+	*end = '\0';
+
+	pos = os_strstr(start, "BatchId=");
+	if (pos == NULL) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	pos += 8;
+	if (*pos == '"')
+		pos++;
+	batch_id = atoi(pos);
+	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
+		   batch_id);
+	if (batch_id != tncc->last_batchid + 1) {
+		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
+			   "%u (expected %u)",
+			   batch_id, tncc->last_batchid + 1);
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	tncc->last_batchid = batch_id;
+
+	while (*pos != '\0' && *pos != '>')
+		pos++;
+	if (*pos == '\0') {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	pos++;
+	payload = start;
+
+	/*
+	 * <IMC-IMV-Message>
+	 * <Type>01234567</Type>
+	 * <Base64>foo==</Base64>
+	 * </IMC-IMV-Message>
+	 */
+
+	while (*start) {
+		char *endpos;
+		unsigned int type;
+
+		pos = os_strstr(start, "<IMC-IMV-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 17;
+		end = os_strstr(start, "</IMC-IMV-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 18;
+
+		if (tncc_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
+
+		decoded = tncc_get_base64(start, &decoded_len);
+		if (decoded == NULL) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+
+		tncc_send_to_imcs(tncc, type, decoded, decoded_len);
+
+		os_free(decoded);
+
+		start = end;
+	}
+
+	/*
+	 * <TNCC-TNCS-Message>
+	 * <Type>01234567</Type>
+	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
+	 * <Base64>foo==</Base64>
+	 * </TNCC-TNCS-Message>
+	 */
+
+	start = payload;
+	while (*start) {
+		unsigned int type;
+		char *xml, *xmlend, *endpos;
+
+		pos = os_strstr(start, "<TNCC-TNCS-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 19;
+		end = os_strstr(start, "</TNCC-TNCS-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 20;
+
+		if (tncc_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
+			   type);
+
+		/* Base64 OR XML */
+		decoded = NULL;
+		xml = NULL;
+		xmlend = NULL;
+		pos = os_strstr(start, "<XML>");
+		if (pos) {
+			pos += 5;
+			pos2 = os_strstr(pos, "</XML>");
+			if (pos2 == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+			xmlend = pos2;
+			xml = pos;
+		} else {
+			decoded = tncc_get_base64(start, &decoded_len);
+			if (decoded == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+		}
+
+		if (decoded) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message Base64",
+					  decoded, decoded_len);
+			os_free(decoded);
+		}
+
+		if (xml) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message XML",
+					  (unsigned char *) xml,
+					  xmlend - xml);
+		}
+
+		if (type == TNC_TNCCS_RECOMMENDATION && xml) {
+			/*
+			 * <TNCCS-Recommendation type="allow">
+			 * </TNCCS-Recommendation>
+			 */
+			*xmlend = '\0';
+			res = tncc_get_recommendation(xml);
+			*xmlend = '<';
+			recommendation_msg = 1;
+		}
+
+		start = end;
+	}
+
+	os_free(buf);
+
+	if (recommendation_msg)
+		tncc_notify_recommendation(tncc, res);
+
+	return res;
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
+{
+	HKEY hk, hk2;
+	LONG ret;
+	DWORD i;
+	struct tnc_if_imc *imc, *last;
+	int j;
+
+	last = tncc->imc;
+	while (last && last->next)
+		last = last->next;
+
+	ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
+			   &hk);
+	if (ret != ERROR_SUCCESS)
+		return 0;
+
+	for (i = 0; ; i++) {
+		TCHAR name[255], *val;
+		DWORD namelen, buflen;
+
+		namelen = 255;
+		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
+				   NULL);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
+				   (unsigned int) ret);
+			break;
+		}
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = '\0';
+
+		wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
+
+		ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
+				   "'", name);
+			continue;
+		}
+
+		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
+				      &buflen);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
+				   "IMC key '" TSTR "'", name);
+			RegCloseKey(hk2);
+			continue;
+		}
+
+		val = os_malloc(buflen);
+		if (val == NULL) {
+			RegCloseKey(hk2);
+			continue;
+		}
+
+		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
+				      (LPBYTE) val, &buflen);
+		if (ret != ERROR_SUCCESS) {
+			os_free(val);
+			RegCloseKey(hk2);
+			continue;
+		}
+
+		RegCloseKey(hk2);
+
+		wpa_unicode2ascii_inplace(val);
+		wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
+
+		for (j = 0; j < TNC_MAX_IMC_ID; j++) {
+			if (tnc_imc[j] == NULL)
+				break;
+		}
+		if (j >= TNC_MAX_IMC_ID) {
+			wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
+			os_free(val);
+			continue;
+		}
+
+		imc = os_zalloc(sizeof(*imc));
+		if (imc == NULL) {
+			os_free(val);
+			break;
+		}
+
+		imc->imcID = j;
+
+		wpa_unicode2ascii_inplace(name);
+		imc->name = os_strdup((char *) name);
+		imc->path = os_strdup((char *) val);
+
+		os_free(val);
+
+		if (last == NULL)
+			tncc->imc = imc;
+		else
+			last->next = imc;
+		last = imc;
+
+		tnc_imc[imc->imcID] = imc;
+	}
+
+	RegCloseKey(hk);
+
+	return 0;
+}
+
+
+static int tncc_read_config(struct tncc_data *tncc)
+{
+	if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
+	    tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
+		return -1;
+	return 0;
+}
+
+#else /* CONFIG_NATIVE_WINDOWS */
+
+static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
+{
+	struct tnc_if_imc *imc;
+	char *pos, *pos2;
+	int i;
+
+	for (i = 0; i < TNC_MAX_IMC_ID; i++) {
+		if (tnc_imc[i] == NULL)
+			break;
+	}
+	if (i >= TNC_MAX_IMC_ID) {
+		wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
+		return NULL;
+	}
+
+	imc = os_zalloc(sizeof(*imc));
+	if (imc == NULL) {
+		*error = 1;
+		return NULL;
+	}
+
+	imc->imcID = i;
+
+	pos = start;
+	wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
+	if (pos + 1 >= end || *pos != '"') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
+			   "(no starting quotation mark)", start);
+		os_free(imc);
+		return NULL;
+	}
+
+	pos++;
+	pos2 = pos;
+	while (pos2 < end && *pos2 != '"')
+		pos2++;
+	if (pos2 >= end) {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
+			   "(no ending quotation mark)", start);
+		os_free(imc);
+		return NULL;
+	}
+	*pos2 = '\0';
+	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
+	imc->name = os_strdup(pos);
+
+	pos = pos2 + 1;
+	if (pos >= end || *pos != ' ') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
+			   "(no space after name)", start);
+		os_free(imc->name);
+		os_free(imc);
+		return NULL;
+	}
+
+	pos++;
+	wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
+	imc->path = os_strdup(pos);
+	tnc_imc[imc->imcID] = imc;
+
+	return imc;
+}
+
+
+static int tncc_read_config(struct tncc_data *tncc)
+{
+	char *config, *end, *pos, *line_end;
+	size_t config_len;
+	struct tnc_if_imc *imc, *last;
+
+	last = NULL;
+
+	config = os_readfile(TNC_CONFIG_FILE, &config_len);
+	if (config == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
+			   "file '%s'", TNC_CONFIG_FILE);
+		return -1;
+	}
+
+	end = config + config_len;
+	for (pos = config; pos < end; pos = line_end + 1) {
+		line_end = pos;
+		while (*line_end != '\n' && *line_end != '\r' &&
+		       line_end < end)
+			line_end++;
+		*line_end = '\0';
+
+		if (os_strncmp(pos, "IMC ", 4) == 0) {
+			int error = 0;
+
+			imc = tncc_parse_imc(pos + 4, line_end, &error);
+			if (error)
+				return -1;
+			if (imc) {
+				if (last == NULL)
+					tncc->imc = imc;
+				else
+					last->next = imc;
+				last = imc;
+			}
+		}
+	}
+
+	os_free(config);
+
+	return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+struct tncc_data * tncc_init(void)
+{
+	struct tncc_data *tncc;
+	struct tnc_if_imc *imc;
+
+	tncc = os_zalloc(sizeof(*tncc));
+	if (tncc == NULL)
+		return NULL;
+
+	/* TODO:
+	 * move loading and Initialize() to a location that is not
+	 *    re-initialized for every EAP-TNC session (?)
+	 */
+
+	if (tncc_read_config(tncc) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
+		goto failed;
+	}
+
+	for (imc = tncc->imc; imc; imc = imc->next) {
+		if (tncc_load_imc(imc)) {
+			wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
+				   imc->name);
+			goto failed;
+		}
+	}
+
+	return tncc;
+
+failed:
+	tncc_deinit(tncc);
+	return NULL;
+}
+
+
+void tncc_deinit(struct tncc_data *tncc)
+{
+	struct tnc_if_imc *imc, *prev;
+
+	imc = tncc->imc;
+	while (imc) {
+		tncc_unload_imc(imc);
+
+		prev = imc;
+		imc = imc->next;
+		os_free(prev);
+	}
+
+	os_free(tncc);
+}
+
+
+static struct wpabuf * tncc_build_soh(int ver)
+{
+	struct wpabuf *buf;
+	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
+	u8 correlation_id[24];
+	/* TODO: get correct name */
+	char *machinename = "wpa_supplicant at w1.fi";
+
+	if (os_get_random(correlation_id, sizeof(correlation_id)))
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
+		    correlation_id, sizeof(correlation_id));
+
+	buf = wpabuf_alloc(200);
+	if (buf == NULL)
+		return NULL;
+
+	/* Vendor-Specific TLV (Microsoft) - SoH */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+	tlv_len = wpabuf_put(buf, 2); /* Length */
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+	wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
+	tlv_len2 = wpabuf_put(buf, 2); /* Length */
+
+	/* SoH Header */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
+	outer_len = wpabuf_put(buf, 2);
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+	wpabuf_put_be16(buf, ver); /* Inner Type */
+	inner_len = wpabuf_put(buf, 2);
+
+	if (ver == 2) {
+		/* SoH Mode Sub-Header */
+		/* Outer Type */
+		wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+		wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
+		wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+		/* Value: */
+		wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+		wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
+		wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
+	}
+
+	/* SSoH TLV */
+	/* System-Health-Id */
+	wpabuf_put_be16(buf, 0x0002); /* Type */
+	wpabuf_put_be16(buf, 4); /* Length */
+	wpabuf_put_be32(buf, 79616);
+	/* Vendor-Specific Attribute */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+	ssoh_len = wpabuf_put(buf, 2);
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+
+	/* MS-Packet-Info */
+	wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
+	/* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
+	 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
+	 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
+	 * would not be in the specified location.
+	 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
+	 */
+	wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
+
+	/* MS-Machine-Inventory */
+	/* TODO: get correct values; 0 = not applicable for OS */
+	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
+	wpabuf_put_be32(buf, 0); /* osVersionMajor */
+	wpabuf_put_be32(buf, 0); /* osVersionMinor */
+	wpabuf_put_be32(buf, 0); /* osVersionBuild */
+	wpabuf_put_be16(buf, 0); /* spVersionMajor */
+	wpabuf_put_be16(buf, 0); /* spVersionMinor */
+	wpabuf_put_be16(buf, 0); /* procArch */
+
+	/* MS-MachineName */
+	wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
+	wpabuf_put_be16(buf, os_strlen(machinename) + 1);
+	wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
+
+	/* MS-CorrelationId */
+	wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
+	wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+
+	/* MS-Quarantine-State */
+	wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
+	wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
+	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
+	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
+	wpabuf_put_be16(buf, 1); /* urlLenInBytes */
+	wpabuf_put_u8(buf, 0); /* null termination for the url */
+
+	/* MS-Machine-Inventory-Ex */
+	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
+	wpabuf_put_be32(buf, 0); /* Reserved
+				  * (note: Windows XP SP3 uses 0xdecafbad) */
+	wpabuf_put_u8(buf, 1); /* ProductType: Client */
+
+	/* Update SSoH Length */
+	end = wpabuf_put(buf, 0);
+	WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
+
+	/* TODO: SoHReportEntry TLV (zero or more) */
+
+	/* Update length fields */
+	end = wpabuf_put(buf, 0);
+	WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
+	WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
+	WPA_PUT_BE16(outer_len, end - outer_len - 2);
+	WPA_PUT_BE16(inner_len, end - inner_len - 2);
+
+	return buf;
+}
+
+
+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
+{
+	const u8 *pos;
+
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
+
+	if (len < 12)
+		return NULL;
+
+	/* SoH Request */
+	pos = data;
+
+	/* TLV Type */
+	if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
+		return NULL;
+	pos += 2;
+
+	/* Length */
+	if (WPA_GET_BE16(pos) < 8)
+		return NULL;
+	pos += 2;
+
+	/* Vendor_Id */
+	if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
+		return NULL;
+	pos += 4;
+
+	/* TLV Type */
+	if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
+
+	return tncc_build_soh(2);
+}

Deleted: vendor/wpa/2.0/src/eap_peer/tncc.h
===================================================================
--- vendor/wpa/dist/src/eap_peer/tncc.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_peer/tncc.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,42 +0,0 @@
-/*
- * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TNCC_H
-#define TNCC_H
-
-struct tncc_data;
-
-struct tncc_data * tncc_init(void);
-void tncc_deinit(struct tncc_data *tncc);
-void tncc_init_connection(struct tncc_data *tncc);
-size_t tncc_total_send_len(struct tncc_data *tncc);
-u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos);
-char * tncc_if_tnccs_start(struct tncc_data *tncc);
-char * tncc_if_tnccs_end(void);
-
-enum tncc_process_res {
-	TNCCS_PROCESS_ERROR = -1,
-	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
-	TNCCS_RECOMMENDATION_ERROR,
-	TNCCS_RECOMMENDATION_ALLOW,
-	TNCCS_RECOMMENDATION_NONE,
-	TNCCS_RECOMMENDATION_ISOLATE
-};
-
-enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
-					    const u8 *msg, size_t len);
-
-struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len);
-
-#endif /* TNCC_H */

Copied: vendor/wpa/2.0/src/eap_peer/tncc.h (from rev 9639, vendor/wpa/dist/src/eap_peer/tncc.h)
===================================================================
--- vendor/wpa/2.0/src/eap_peer/tncc.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_peer/tncc.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,36 @@
+/*
+ * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TNCC_H
+#define TNCC_H
+
+struct tncc_data;
+
+struct tncc_data * tncc_init(void);
+void tncc_deinit(struct tncc_data *tncc);
+void tncc_init_connection(struct tncc_data *tncc);
+size_t tncc_total_send_len(struct tncc_data *tncc);
+u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos);
+char * tncc_if_tnccs_start(struct tncc_data *tncc);
+char * tncc_if_tnccs_end(void);
+
+enum tncc_process_res {
+	TNCCS_PROCESS_ERROR = -1,
+	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
+	TNCCS_RECOMMENDATION_ERROR,
+	TNCCS_RECOMMENDATION_ALLOW,
+	TNCCS_RECOMMENDATION_NONE,
+	TNCCS_RECOMMENDATION_ISOLATE
+};
+
+enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
+					    const u8 *msg, size_t len);
+
+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len);
+
+#endif /* TNCC_H */

Deleted: vendor/wpa/2.0/src/eap_server/eap.h
===================================================================
--- vendor/wpa/dist/src/eap_server/eap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,124 +0,0 @@
-/*
- * hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_H
-#define EAP_H
-
-#include "common/defs.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "wpabuf.h"
-
-struct eap_sm;
-
-#define EAP_MAX_METHODS 8
-
-#define EAP_TTLS_AUTH_PAP 1
-#define EAP_TTLS_AUTH_CHAP 2
-#define EAP_TTLS_AUTH_MSCHAP 4
-#define EAP_TTLS_AUTH_MSCHAPV2 8
-
-struct eap_user {
-	struct {
-		int vendor;
-		u32 method;
-	} methods[EAP_MAX_METHODS];
-	u8 *password;
-	size_t password_len;
-	int password_hash; /* whether password is hashed with
-			    * nt_password_hash() */
-	int phase2;
-	int force_version;
-	int ttls_auth; /* bitfield of
-			* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
-};
-
-struct eap_eapol_interface {
-	/* Lower layer to full authenticator variables */
-	Boolean eapResp; /* shared with EAPOL Backend Authentication */
-	struct wpabuf *eapRespData;
-	Boolean portEnabled;
-	int retransWhile;
-	Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
-	int eapSRTT;
-	int eapRTTVAR;
-
-	/* Full authenticator to lower layer variables */
-	Boolean eapReq; /* shared with EAPOL Backend Authentication */
-	Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
-	Boolean eapSuccess;
-	Boolean eapFail;
-	Boolean eapTimeout;
-	struct wpabuf *eapReqData;
-	u8 *eapKeyData;
-	size_t eapKeyDataLen;
-	Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
-
-	/* AAA interface to full authenticator variables */
-	Boolean aaaEapReq;
-	Boolean aaaEapNoReq;
-	Boolean aaaSuccess;
-	Boolean aaaFail;
-	struct wpabuf *aaaEapReqData;
-	u8 *aaaEapKeyData;
-	size_t aaaEapKeyDataLen;
-	Boolean aaaEapKeyAvailable;
-	int aaaMethodTimeout;
-
-	/* Full authenticator to AAA interface variables */
-	Boolean aaaEapResp;
-	struct wpabuf *aaaEapRespData;
-	/* aaaIdentity -> eap_get_identity() */
-	Boolean aaaTimeout;
-};
-
-struct eapol_callbacks {
-	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
-			    int phase2, struct eap_user *user);
-	const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
-};
-
-struct eap_config {
-	void *ssl_ctx;
-	void *msg_ctx;
-	void *eap_sim_db_priv;
-	Boolean backend_auth;
-	int eap_server;
-	u8 *pac_opaque_encr_key;
-	u8 *eap_fast_a_id;
-	size_t eap_fast_a_id_len;
-	char *eap_fast_a_id_info;
-	int eap_fast_prov;
-	int pac_key_lifetime;
-	int pac_key_refresh_time;
-	int eap_sim_aka_result_ind;
-	int tnc;
-	struct wps_context *wps;
-	const struct wpabuf *assoc_wps_ie;
-	const u8 *peer_addr;
-};
-
-
-struct eap_sm * eap_server_sm_init(void *eapol_ctx,
-				   struct eapol_callbacks *eapol_cb,
-				   struct eap_config *eap_conf);
-void eap_server_sm_deinit(struct eap_sm *sm);
-int eap_server_sm_step(struct eap_sm *sm);
-void eap_sm_notify_cached(struct eap_sm *sm);
-void eap_sm_pending_cb(struct eap_sm *sm);
-int eap_sm_method_pending(struct eap_sm *sm);
-const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
-struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
-
-#endif /* EAP_H */

Copied: vendor/wpa/2.0/src/eap_server/eap.h (from rev 9639, vendor/wpa/dist/src/eap_server/eap.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,122 @@
+/*
+ * hostapd / EAP Full Authenticator state machine (RFC 4137)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_H
+#define EAP_H
+
+#include "common/defs.h"
+#include "eap_common/eap_defs.h"
+#include "eap_server/eap_methods.h"
+#include "wpabuf.h"
+
+struct eap_sm;
+
+#define EAP_TTLS_AUTH_PAP 1
+#define EAP_TTLS_AUTH_CHAP 2
+#define EAP_TTLS_AUTH_MSCHAP 4
+#define EAP_TTLS_AUTH_MSCHAPV2 8
+
+struct eap_user {
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_MAX_METHODS];
+	u8 *password;
+	size_t password_len;
+	int password_hash; /* whether password is hashed with
+			    * nt_password_hash() */
+	int phase2;
+	int force_version;
+	int ttls_auth; /* bitfield of
+			* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
+};
+
+struct eap_eapol_interface {
+	/* Lower layer to full authenticator variables */
+	Boolean eapResp; /* shared with EAPOL Backend Authentication */
+	struct wpabuf *eapRespData;
+	Boolean portEnabled;
+	int retransWhile;
+	Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
+	int eapSRTT;
+	int eapRTTVAR;
+
+	/* Full authenticator to lower layer variables */
+	Boolean eapReq; /* shared with EAPOL Backend Authentication */
+	Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
+	Boolean eapSuccess;
+	Boolean eapFail;
+	Boolean eapTimeout;
+	struct wpabuf *eapReqData;
+	u8 *eapKeyData;
+	size_t eapKeyDataLen;
+	Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
+
+	/* AAA interface to full authenticator variables */
+	Boolean aaaEapReq;
+	Boolean aaaEapNoReq;
+	Boolean aaaSuccess;
+	Boolean aaaFail;
+	struct wpabuf *aaaEapReqData;
+	u8 *aaaEapKeyData;
+	size_t aaaEapKeyDataLen;
+	Boolean aaaEapKeyAvailable;
+	int aaaMethodTimeout;
+
+	/* Full authenticator to AAA interface variables */
+	Boolean aaaEapResp;
+	struct wpabuf *aaaEapRespData;
+	/* aaaIdentity -> eap_get_identity() */
+	Boolean aaaTimeout;
+};
+
+struct eapol_callbacks {
+	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+			    int phase2, struct eap_user *user);
+	const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
+};
+
+struct eap_config {
+	void *ssl_ctx;
+	void *msg_ctx;
+	void *eap_sim_db_priv;
+	Boolean backend_auth;
+	int eap_server;
+	u16 pwd_group;
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	int eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	struct wps_context *wps;
+	const struct wpabuf *assoc_wps_ie;
+	const struct wpabuf *assoc_p2p_ie;
+	const u8 *peer_addr;
+	int fragment_size;
+
+	int pbc_in_m1;
+};
+
+
+struct eap_sm * eap_server_sm_init(void *eapol_ctx,
+				   struct eapol_callbacks *eapol_cb,
+				   struct eap_config *eap_conf);
+void eap_server_sm_deinit(struct eap_sm *sm);
+int eap_server_sm_step(struct eap_sm *sm);
+void eap_sm_notify_cached(struct eap_sm *sm);
+void eap_sm_pending_cb(struct eap_sm *sm);
+int eap_sm_method_pending(struct eap_sm *sm);
+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+void eap_server_clear_identity(struct eap_sm *sm);
+
+#endif /* EAP_H */

Deleted: vendor/wpa/2.0/src/eap_server/eap_i.h
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,196 +0,0 @@
-/*
- * hostapd / EAP Authenticator state machine internal structures (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_I_H
-#define EAP_I_H
-
-#include "wpabuf.h"
-#include "eap_server/eap.h"
-#include "eap_common/eap_common.h"
-
-/* RFC 4137 - EAP Standalone Authenticator */
-
-/**
- * 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 5.4 of RFC 4137.
- */
-struct eap_method {
-	int vendor;
-	EapType method;
-	const char *name;
-
-	void * (*init)(struct eap_sm *sm);
-	void * (*initPickUp)(struct eap_sm *sm);
-	void (*reset)(struct eap_sm *sm, void *priv);
-
-	struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id);
-	int (*getTimeout)(struct eap_sm *sm, void *priv);
-	Boolean (*check)(struct eap_sm *sm, void *priv,
-			 struct wpabuf *respData);
-	void (*process)(struct eap_sm *sm, void *priv,
-			struct wpabuf *respData);
-	Boolean (*isDone)(struct eap_sm *sm, void *priv);
-	u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
-	/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
-	 * but it is useful in implementing Policy.getDecision() */
-	Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
-
-	/**
-	 * free - Free EAP method data
-	 * @method: Pointer to the method data registered with
-	 * eap_server_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_SERVER_METHOD_INTERFACE_VERSION 1
-	/**
-	 * version - Version of the EAP server method interface
-	 *
-	 * The EAP server method implementation should set this variable to
-	 * EAP_SERVER_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;
-
-	/**
-	 * get_emsk - Get EAP method specific keying extended material (EMSK)
-	 * @sm: Pointer to EAP state machine allocated with eap_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);
-};
-
-/**
- * struct eap_sm - EAP server state machine data
- */
-struct eap_sm {
-	enum {
-		EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
-		EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST,
-		EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST,
-		EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE,
-		EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD,
-		EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
-		EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
-		EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
-		EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
-	} EAP_state;
-
-	/* Constants */
-	int MaxRetrans;
-
-	struct eap_eapol_interface eap_if;
-
-	/* Full authenticator state machine local variables */
-
-	/* Long-term (maintained betwen packets) */
-	EapType currentMethod;
-	int currentId;
-	enum {
-		METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
-	} methodState;
-	int retransCount;
-	struct wpabuf *lastReqData;
-	int methodTimeout;
-
-	/* Short-term (not maintained between packets) */
-	Boolean rxResp;
-	int respId;
-	EapType respMethod;
-	int respVendor;
-	u32 respVendorMethod;
-	Boolean ignore;
-	enum {
-		DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
-		DECISION_PASSTHROUGH
-	} decision;
-
-	/* Miscellaneous variables */
-	const struct eap_method *m; /* selected EAP method */
-	/* not defined in RFC 4137 */
-	Boolean changed;
-	void *eapol_ctx, *msg_ctx;
-	struct eapol_callbacks *eapol_cb;
-	void *eap_method_priv;
-	u8 *identity;
-	size_t identity_len;
-	/* Whether Phase 2 method should validate identity match */
-	int require_identity_match;
-	int lastId; /* Identifier used in the last EAP-Packet */
-	struct eap_user *user;
-	int user_eap_method_index;
-	int init_phase2;
-	void *ssl_ctx;
-	void *eap_sim_db_priv;
-	Boolean backend_auth;
-	Boolean update_user;
-	int eap_server;
-
-	int num_rounds;
-	enum {
-		METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
-	} method_pending;
-
-	u8 *auth_challenge;
-	u8 *peer_challenge;
-
-	u8 *pac_opaque_encr_key;
-	u8 *eap_fast_a_id;
-	size_t eap_fast_a_id_len;
-	char *eap_fast_a_id_info;
-	enum {
-		NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
-	} eap_fast_prov;
-	int pac_key_lifetime;
-	int pac_key_refresh_time;
-	int eap_sim_aka_result_ind;
-	int tnc;
-	struct wps_context *wps;
-	struct wpabuf *assoc_wps_ie;
-
-	Boolean start_reauth;
-
-	u8 peer_addr[ETH_ALEN];
-};
-
-int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
-		 int phase2);
-void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len);
-
-#endif /* EAP_I_H */

Copied: vendor/wpa/2.0/src/eap_server/eap_i.h (from rev 9639, vendor/wpa/dist/src/eap_server/eap_i.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,197 @@
+/*
+ * hostapd / EAP Authenticator state machine internal structures (RFC 4137)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at 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 "eap_server/eap.h"
+#include "eap_common/eap_common.h"
+
+/* RFC 4137 - EAP Standalone Authenticator */
+
+/**
+ * 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 5.4 of RFC 4137.
+ */
+struct eap_method {
+	int vendor;
+	EapType method;
+	const char *name;
+
+	void * (*init)(struct eap_sm *sm);
+	void * (*initPickUp)(struct eap_sm *sm);
+	void (*reset)(struct eap_sm *sm, void *priv);
+
+	struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id);
+	int (*getTimeout)(struct eap_sm *sm, void *priv);
+	Boolean (*check)(struct eap_sm *sm, void *priv,
+			 struct wpabuf *respData);
+	void (*process)(struct eap_sm *sm, void *priv,
+			struct wpabuf *respData);
+	Boolean (*isDone)(struct eap_sm *sm, void *priv);
+	u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
+	/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
+	 * but it is useful in implementing Policy.getDecision() */
+	Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * free - Free EAP method data
+	 * @method: Pointer to the method data registered with
+	 * eap_server_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_SERVER_METHOD_INTERFACE_VERSION 1
+	/**
+	 * version - Version of the EAP server method interface
+	 *
+	 * The EAP server method implementation should set this variable to
+	 * EAP_SERVER_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;
+
+	/**
+	 * get_emsk - Get EAP method specific keying extended material (EMSK)
+	 * @sm: Pointer to EAP state machine allocated with eap_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);
+};
+
+/**
+ * struct eap_sm - EAP server state machine data
+ */
+struct eap_sm {
+	enum {
+		EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
+		EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST,
+		EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST,
+		EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE,
+		EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD,
+		EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
+		EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
+		EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
+		EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
+	} EAP_state;
+
+	/* Constants */
+	int MaxRetrans;
+
+	struct eap_eapol_interface eap_if;
+
+	/* Full authenticator state machine local variables */
+
+	/* Long-term (maintained between packets) */
+	EapType currentMethod;
+	int currentId;
+	enum {
+		METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
+	} methodState;
+	int retransCount;
+	struct wpabuf *lastReqData;
+	int methodTimeout;
+
+	/* Short-term (not maintained between packets) */
+	Boolean rxResp;
+	int respId;
+	EapType respMethod;
+	int respVendor;
+	u32 respVendorMethod;
+	Boolean ignore;
+	enum {
+		DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
+		DECISION_PASSTHROUGH
+	} decision;
+
+	/* Miscellaneous variables */
+	const struct eap_method *m; /* selected EAP method */
+	/* not defined in RFC 4137 */
+	Boolean changed;
+	void *eapol_ctx, *msg_ctx;
+	struct eapol_callbacks *eapol_cb;
+	void *eap_method_priv;
+	u8 *identity;
+	size_t identity_len;
+	/* Whether Phase 2 method should validate identity match */
+	int require_identity_match;
+	int lastId; /* Identifier used in the last EAP-Packet */
+	struct eap_user *user;
+	int user_eap_method_index;
+	int init_phase2;
+	void *ssl_ctx;
+	struct eap_sim_db_data *eap_sim_db_priv;
+	Boolean backend_auth;
+	Boolean update_user;
+	int eap_server;
+
+	int num_rounds;
+	enum {
+		METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
+	} method_pending;
+
+	u8 *auth_challenge;
+	u8 *peer_challenge;
+
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	enum {
+		NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV
+	} eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	u16 pwd_group;
+	struct wps_context *wps;
+	struct wpabuf *assoc_wps_ie;
+	struct wpabuf *assoc_p2p_ie;
+
+	Boolean start_reauth;
+
+	u8 peer_addr[ETH_ALEN];
+
+	/* Fragmentation size for EAP method init() handler */
+	int fragment_size;
+
+	int pbc_in_m1;
+};
+
+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
+		 int phase2);
+void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len);
+
+#endif /* EAP_I_H */

Deleted: vendor/wpa/2.0/src/eap_server/eap_methods.h
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_methods.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_methods.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,53 +0,0 @@
-/*
- * EAP server method registration
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_SERVER_METHODS_H
-#define EAP_SERVER_METHODS_H
-
-#include "eap_common/eap_defs.h"
-
-const struct eap_method * eap_server_get_eap_method(int vendor,
-						    EapType method);
-struct eap_method * eap_server_method_alloc(int version, int vendor,
-					    EapType method, const char *name);
-void eap_server_method_free(struct eap_method *method);
-int eap_server_method_register(struct eap_method *method);
-
-EapType eap_server_get_type(const char *name, int *vendor);
-void eap_server_unregister_methods(void);
-const char * eap_server_get_name(int vendor, EapType type);
-
-/* EAP server method registration calls for statically linked in methods */
-int eap_server_identity_register(void);
-int eap_server_md5_register(void);
-int eap_server_tls_register(void);
-int eap_server_mschapv2_register(void);
-int eap_server_peap_register(void);
-int eap_server_tlv_register(void);
-int eap_server_gtc_register(void);
-int eap_server_ttls_register(void);
-int eap_server_sim_register(void);
-int eap_server_aka_register(void);
-int eap_server_aka_prime_register(void);
-int eap_server_pax_register(void);
-int eap_server_psk_register(void);
-int eap_server_sake_register(void);
-int eap_server_gpsk_register(void);
-int eap_server_vendor_test_register(void);
-int eap_server_fast_register(void);
-int eap_server_wsc_register(void);
-int eap_server_ikev2_register(void);
-int eap_server_tnc_register(void);
-
-#endif /* EAP_SERVER_METHODS_H */

Copied: vendor/wpa/2.0/src/eap_server/eap_methods.h (from rev 9639, vendor/wpa/dist/src/eap_server/eap_methods.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_methods.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_methods.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,49 @@
+/*
+ * EAP server method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_SERVER_METHODS_H
+#define EAP_SERVER_METHODS_H
+
+#include "eap_common/eap_defs.h"
+
+const struct eap_method * eap_server_get_eap_method(int vendor,
+						    EapType method);
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+					    EapType method, const char *name);
+void eap_server_method_free(struct eap_method *method);
+int eap_server_method_register(struct eap_method *method);
+
+EapType eap_server_get_type(const char *name, int *vendor);
+void eap_server_unregister_methods(void);
+const char * eap_server_get_name(int vendor, EapType type);
+
+/* EAP server method registration calls for statically linked in methods */
+int eap_server_identity_register(void);
+int eap_server_md5_register(void);
+int eap_server_tls_register(void);
+int eap_server_unauth_tls_register(void);
+int eap_server_mschapv2_register(void);
+int eap_server_peap_register(void);
+int eap_server_tlv_register(void);
+int eap_server_gtc_register(void);
+int eap_server_ttls_register(void);
+int eap_server_sim_register(void);
+int eap_server_aka_register(void);
+int eap_server_aka_prime_register(void);
+int eap_server_pax_register(void);
+int eap_server_psk_register(void);
+int eap_server_sake_register(void);
+int eap_server_gpsk_register(void);
+int eap_server_vendor_test_register(void);
+int eap_server_fast_register(void);
+int eap_server_wsc_register(void);
+int eap_server_ikev2_register(void);
+int eap_server_tnc_register(void);
+int eap_server_pwd_register(void);
+
+#endif /* EAP_SERVER_METHODS_H */

Deleted: vendor/wpa/2.0/src/eap_server/eap_server.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1364 +0,0 @@
-/*
- * hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This state machine is based on the full authenticator state machine defined
- * in RFC 4137. However, to support backend authentication in RADIUS
- * authentication server functionality, parts of backend authenticator (also
- * from RFC 4137) are mixed in. This functionality is enabled by setting
- * backend_auth configuration variable to TRUE.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "state_machine.h"
-#include "common/wpa_ctrl.h"
-
-#define STATE_MACHINE_DATA struct eap_sm
-#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-
-#define EAP_MAX_AUTH_ROUNDS 50
-
-static void eap_user_free(struct eap_user *user);
-
-
-/* EAP state machines are described in RFC 4137 */
-
-static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
-				   int eapSRTT, int eapRTTVAR,
-				   int methodTimeout);
-static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
-static int eap_sm_getId(const struct wpabuf *data);
-static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
-static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
-static int eap_sm_nextId(struct eap_sm *sm, int id);
-static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
-				 size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
-static int eap_sm_Policy_getDecision(struct eap_sm *sm);
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
-
-
-static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
-{
-	if (src == NULL)
-		return -1;
-
-	wpabuf_free(*dst);
-	*dst = wpabuf_dup(src);
-	return *dst ? 0 : -1;
-}
-
-
-static int eap_copy_data(u8 **dst, size_t *dst_len,
-			 const u8 *src, size_t src_len)
-{
-	if (src == NULL)
-		return -1;
-
-	os_free(*dst);
-	*dst = os_malloc(src_len);
-	if (*dst) {
-		os_memcpy(*dst, src, src_len);
-		*dst_len = src_len;
-		return 0;
-	} else {
-		*dst_len = 0;
-		return -1;
-	}
-}
-
-#define EAP_COPY(dst, src) \
-	eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
-
-
-/**
- * eap_user_get - Fetch user information from the database
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * @identity: Identity (User-Name) of the user
- * @identity_len: Length of identity in bytes
- * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
- * Returns: 0 on success, or -1 on failure
- *
- * This function is used to fetch user information for EAP. The user will be
- * selected based on the specified identity. sm->user and
- * sm->user_eap_method_index are updated for the new user when a matching user
- * is found. sm->user can be used to get user information (e.g., password).
- */
-int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
-		 int phase2)
-{
-	struct eap_user *user;
-
-	if (sm == NULL || sm->eapol_cb == NULL ||
-	    sm->eapol_cb->get_eap_user == NULL)
-		return -1;
-
-	eap_user_free(sm->user);
-	sm->user = NULL;
-
-	user = os_zalloc(sizeof(*user));
-	if (user == NULL)
-	    return -1;
-
-	if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
-				       identity_len, phase2, user) != 0) {
-		eap_user_free(user);
-		return -1;
-	}
-
-	sm->user = user;
-	sm->user_eap_method_index = 0;
-
-	return 0;
-}
-
-
-SM_STATE(EAP, DISABLED)
-{
-	SM_ENTRY(EAP, DISABLED);
-	sm->num_rounds = 0;
-}
-
-
-SM_STATE(EAP, INITIALIZE)
-{
-	SM_ENTRY(EAP, INITIALIZE);
-
-	sm->currentId = -1;
-	sm->eap_if.eapSuccess = FALSE;
-	sm->eap_if.eapFail = FALSE;
-	sm->eap_if.eapTimeout = FALSE;
-	os_free(sm->eap_if.eapKeyData);
-	sm->eap_if.eapKeyData = NULL;
-	sm->eap_if.eapKeyDataLen = 0;
-	sm->eap_if.eapKeyAvailable = FALSE;
-	sm->eap_if.eapRestart = FALSE;
-
-	/*
-	 * This is not defined in RFC 4137, but method state needs to be
-	 * reseted here so that it does not remain in success state when
-	 * re-authentication starts.
-	 */
-	if (sm->m && sm->eap_method_priv) {
-		sm->m->reset(sm, sm->eap_method_priv);
-		sm->eap_method_priv = NULL;
-	}
-	sm->m = NULL;
-	sm->user_eap_method_index = 0;
-
-	if (sm->backend_auth) {
-		sm->currentMethod = EAP_TYPE_NONE;
-		/* parse rxResp, respId, respMethod */
-		eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
-		if (sm->rxResp) {
-			sm->currentId = sm->respId;
-		}
-	}
-	sm->num_rounds = 0;
-	sm->method_pending = METHOD_PENDING_NONE;
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
-		MACSTR, MAC2STR(sm->peer_addr));
-}
-
-
-SM_STATE(EAP, PICK_UP_METHOD)
-{
-	SM_ENTRY(EAP, PICK_UP_METHOD);
-
-	if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
-		sm->currentMethod = sm->respMethod;
-		if (sm->m && sm->eap_method_priv) {
-			sm->m->reset(sm, sm->eap_method_priv);
-			sm->eap_method_priv = NULL;
-		}
-		sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
-						  sm->currentMethod);
-		if (sm->m && sm->m->initPickUp) {
-			sm->eap_method_priv = sm->m->initPickUp(sm);
-			if (sm->eap_method_priv == NULL) {
-				wpa_printf(MSG_DEBUG, "EAP: Failed to "
-					   "initialize EAP method %d",
-					   sm->currentMethod);
-				sm->m = NULL;
-				sm->currentMethod = EAP_TYPE_NONE;
-			}
-		} else {
-			sm->m = NULL;
-			sm->currentMethod = EAP_TYPE_NONE;
-		}
-	}
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
-		"method=%u", sm->currentMethod);
-}
-
-
-SM_STATE(EAP, IDLE)
-{
-	SM_ENTRY(EAP, IDLE);
-
-	sm->eap_if.retransWhile = eap_sm_calculateTimeout(
-		sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
-		sm->methodTimeout);
-}
-
-
-SM_STATE(EAP, RETRANSMIT)
-{
-	SM_ENTRY(EAP, RETRANSMIT);
-
-	sm->retransCount++;
-	if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
-		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
-			sm->eap_if.eapReq = TRUE;
-	}
-}
-
-
-SM_STATE(EAP, RECEIVED)
-{
-	SM_ENTRY(EAP, RECEIVED);
-
-	/* parse rxResp, respId, respMethod */
-	eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
-	sm->num_rounds++;
-}
-
-
-SM_STATE(EAP, DISCARD)
-{
-	SM_ENTRY(EAP, DISCARD);
-	sm->eap_if.eapResp = FALSE;
-	sm->eap_if.eapNoReq = TRUE;
-}
-
-
-SM_STATE(EAP, SEND_REQUEST)
-{
-	SM_ENTRY(EAP, SEND_REQUEST);
-
-	sm->retransCount = 0;
-	if (sm->eap_if.eapReqData) {
-		if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
-		{
-			sm->eap_if.eapResp = FALSE;
-			sm->eap_if.eapReq = TRUE;
-		} else {
-			sm->eap_if.eapResp = FALSE;
-			sm->eap_if.eapReq = FALSE;
-		}
-	} else {
-		wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
-		sm->eap_if.eapResp = FALSE;
-		sm->eap_if.eapReq = FALSE;
-		sm->eap_if.eapNoReq = TRUE;
-	}
-}
-
-
-SM_STATE(EAP, INTEGRITY_CHECK)
-{
-	SM_ENTRY(EAP, INTEGRITY_CHECK);
-
-	if (sm->m->check) {
-		sm->ignore = sm->m->check(sm, sm->eap_method_priv,
-					  sm->eap_if.eapRespData);
-	}
-}
-
-
-SM_STATE(EAP, METHOD_REQUEST)
-{
-	SM_ENTRY(EAP, METHOD_REQUEST);
-
-	if (sm->m == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP: method not initialized");
-		return;
-	}
-
-	sm->currentId = eap_sm_nextId(sm, sm->currentId);
-	wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
-		   sm->currentId);
-	sm->lastId = sm->currentId;
-	wpabuf_free(sm->eap_if.eapReqData);
-	sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
-						sm->currentId);
-	if (sm->m->getTimeout)
-		sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
-	else
-		sm->methodTimeout = 0;
-}
-
-
-SM_STATE(EAP, METHOD_RESPONSE)
-{
-	SM_ENTRY(EAP, METHOD_RESPONSE);
-
-	sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
-	if (sm->m->isDone(sm, sm->eap_method_priv)) {
-		eap_sm_Policy_update(sm, NULL, 0);
-		os_free(sm->eap_if.eapKeyData);
-		if (sm->m->getKey) {
-			sm->eap_if.eapKeyData = sm->m->getKey(
-				sm, sm->eap_method_priv,
-				&sm->eap_if.eapKeyDataLen);
-		} else {
-			sm->eap_if.eapKeyData = NULL;
-			sm->eap_if.eapKeyDataLen = 0;
-		}
-		sm->methodState = METHOD_END;
-	} else {
-		sm->methodState = METHOD_CONTINUE;
-	}
-}
-
-
-SM_STATE(EAP, PROPOSE_METHOD)
-{
-	int vendor;
-	EapType type;
-
-	SM_ENTRY(EAP, PROPOSE_METHOD);
-
-	type = eap_sm_Policy_getNextMethod(sm, &vendor);
-	if (vendor == EAP_VENDOR_IETF)
-		sm->currentMethod = type;
-	else
-		sm->currentMethod = EAP_TYPE_EXPANDED;
-	if (sm->m && sm->eap_method_priv) {
-		sm->m->reset(sm, sm->eap_method_priv);
-		sm->eap_method_priv = NULL;
-	}
-	sm->m = eap_server_get_eap_method(vendor, type);
-	if (sm->m) {
-		sm->eap_method_priv = sm->m->init(sm);
-		if (sm->eap_method_priv == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
-				   "method %d", sm->currentMethod);
-			sm->m = NULL;
-			sm->currentMethod = EAP_TYPE_NONE;
-		}
-	}
-	if (sm->currentMethod == EAP_TYPE_IDENTITY ||
-	    sm->currentMethod == EAP_TYPE_NOTIFICATION)
-		sm->methodState = METHOD_CONTINUE;
-	else
-		sm->methodState = METHOD_PROPOSED;
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
-		"vendor=%u method=%u", vendor, sm->currentMethod);
-}
-
-
-SM_STATE(EAP, NAK)
-{
-	const struct eap_hdr *nak;
-	size_t len = 0;
-	const u8 *pos;
-	const u8 *nak_list = NULL;
-
-	SM_ENTRY(EAP, NAK);
-
-	if (sm->eap_method_priv) {
-		sm->m->reset(sm, sm->eap_method_priv);
-		sm->eap_method_priv = NULL;
-	}
-	sm->m = NULL;
-
-	nak = wpabuf_head(sm->eap_if.eapRespData);
-	if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
-		len = be_to_host16(nak->length);
-		if (len > wpabuf_len(sm->eap_if.eapRespData))
-			len = wpabuf_len(sm->eap_if.eapRespData);
-		pos = (const u8 *) (nak + 1);
-		len -= sizeof(*nak);
-		if (*pos == EAP_TYPE_NAK) {
-			pos++;
-			len--;
-			nak_list = pos;
-		}
-	}
-	eap_sm_Policy_update(sm, nak_list, len);
-}
-
-
-SM_STATE(EAP, SELECT_ACTION)
-{
-	SM_ENTRY(EAP, SELECT_ACTION);
-
-	sm->decision = eap_sm_Policy_getDecision(sm);
-}
-
-
-SM_STATE(EAP, TIMEOUT_FAILURE)
-{
-	SM_ENTRY(EAP, TIMEOUT_FAILURE);
-
-	sm->eap_if.eapTimeout = TRUE;
-}
-
-
-SM_STATE(EAP, FAILURE)
-{
-	SM_ENTRY(EAP, FAILURE);
-
-	wpabuf_free(sm->eap_if.eapReqData);
-	sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
-	wpabuf_free(sm->lastReqData);
-	sm->lastReqData = NULL;
-	sm->eap_if.eapFail = TRUE;
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
-		MACSTR, MAC2STR(sm->peer_addr));
-}
-
-
-SM_STATE(EAP, SUCCESS)
-{
-	SM_ENTRY(EAP, SUCCESS);
-
-	wpabuf_free(sm->eap_if.eapReqData);
-	sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
-	wpabuf_free(sm->lastReqData);
-	sm->lastReqData = NULL;
-	if (sm->eap_if.eapKeyData)
-		sm->eap_if.eapKeyAvailable = TRUE;
-	sm->eap_if.eapSuccess = TRUE;
-
-	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
-		MACSTR, MAC2STR(sm->peer_addr));
-}
-
-
-SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
-{
-	SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
-
-	wpabuf_free(sm->eap_if.aaaEapRespData);
-	sm->eap_if.aaaEapRespData = NULL;
-}
-
-
-SM_STATE(EAP, IDLE2)
-{
-	SM_ENTRY(EAP, IDLE2);
-
-	sm->eap_if.retransWhile = eap_sm_calculateTimeout(
-		sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
-		sm->methodTimeout);
-}
-
-
-SM_STATE(EAP, RETRANSMIT2)
-{
-	SM_ENTRY(EAP, RETRANSMIT2);
-
-	sm->retransCount++;
-	if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
-		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
-			sm->eap_if.eapReq = TRUE;
-	}
-}
-
-
-SM_STATE(EAP, RECEIVED2)
-{
-	SM_ENTRY(EAP, RECEIVED2);
-
-	/* parse rxResp, respId, respMethod */
-	eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
-}
-
-
-SM_STATE(EAP, DISCARD2)
-{
-	SM_ENTRY(EAP, DISCARD2);
-	sm->eap_if.eapResp = FALSE;
-	sm->eap_if.eapNoReq = TRUE;
-}
-
-
-SM_STATE(EAP, SEND_REQUEST2)
-{
-	SM_ENTRY(EAP, SEND_REQUEST2);
-
-	sm->retransCount = 0;
-	if (sm->eap_if.eapReqData) {
-		if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
-		{
-			sm->eap_if.eapResp = FALSE;
-			sm->eap_if.eapReq = TRUE;
-		} else {
-			sm->eap_if.eapResp = FALSE;
-			sm->eap_if.eapReq = FALSE;
-		}
-	} else {
-		wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
-		sm->eap_if.eapResp = FALSE;
-		sm->eap_if.eapReq = FALSE;
-		sm->eap_if.eapNoReq = TRUE;
-	}
-}
-
-
-SM_STATE(EAP, AAA_REQUEST)
-{
-	SM_ENTRY(EAP, AAA_REQUEST);
-
-	if (sm->eap_if.eapRespData == NULL) {
-		wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
-		return;
-	}
-
-	/*
-	 * if (respMethod == IDENTITY)
-	 *	aaaIdentity = eapRespData
-	 * This is already taken care of by the EAP-Identity method which
-	 * stores the identity into sm->identity.
-	 */
-
-	eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
-}
-
-
-SM_STATE(EAP, AAA_RESPONSE)
-{
-	SM_ENTRY(EAP, AAA_RESPONSE);
-
-	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
-	sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
-	sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
-}
-
-
-SM_STATE(EAP, AAA_IDLE)
-{
-	SM_ENTRY(EAP, AAA_IDLE);
-
-	sm->eap_if.aaaFail = FALSE;
-	sm->eap_if.aaaSuccess = FALSE;
-	sm->eap_if.aaaEapReq = FALSE;
-	sm->eap_if.aaaEapNoReq = FALSE;
-	sm->eap_if.aaaEapResp = TRUE;
-}
-
-
-SM_STATE(EAP, TIMEOUT_FAILURE2)
-{
-	SM_ENTRY(EAP, TIMEOUT_FAILURE2);
-
-	sm->eap_if.eapTimeout = TRUE;
-}
-
-
-SM_STATE(EAP, FAILURE2)
-{
-	SM_ENTRY(EAP, FAILURE2);
-
-	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
-	sm->eap_if.eapFail = TRUE;
-}
-
-
-SM_STATE(EAP, SUCCESS2)
-{
-	SM_ENTRY(EAP, SUCCESS2);
-
-	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
-
-	sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
-	if (sm->eap_if.aaaEapKeyAvailable) {
-		EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
-	} else {
-		os_free(sm->eap_if.eapKeyData);
-		sm->eap_if.eapKeyData = NULL;
-		sm->eap_if.eapKeyDataLen = 0;
-	}
-
-	sm->eap_if.eapSuccess = TRUE;
-
-	/*
-	 * Start reauthentication with identity request even though we know the
-	 * previously used identity. This is needed to get reauthentication
-	 * started properly.
-	 */
-	sm->start_reauth = TRUE;
-}
-
-
-SM_STEP(EAP)
-{
-	if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
-		SM_ENTER_GLOBAL(EAP, INITIALIZE);
-	else if (!sm->eap_if.portEnabled)
-		SM_ENTER_GLOBAL(EAP, DISABLED);
-	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
-		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
-			wpa_printf(MSG_DEBUG, "EAP: more than %d "
-				   "authentication rounds - abort",
-				   EAP_MAX_AUTH_ROUNDS);
-			sm->num_rounds++;
-			SM_ENTER_GLOBAL(EAP, FAILURE);
-		}
-	} else switch (sm->EAP_state) {
-	case EAP_INITIALIZE:
-		if (sm->backend_auth) {
-			if (!sm->rxResp)
-				SM_ENTER(EAP, SELECT_ACTION);
-			else if (sm->rxResp &&
-				 (sm->respMethod == EAP_TYPE_NAK ||
-				  (sm->respMethod == EAP_TYPE_EXPANDED &&
-				   sm->respVendor == EAP_VENDOR_IETF &&
-				   sm->respVendorMethod == EAP_TYPE_NAK)))
-				SM_ENTER(EAP, NAK);
-			else
-				SM_ENTER(EAP, PICK_UP_METHOD);
-		} else {
-			SM_ENTER(EAP, SELECT_ACTION);
-		}
-		break;
-	case EAP_PICK_UP_METHOD:
-		if (sm->currentMethod == EAP_TYPE_NONE) {
-			SM_ENTER(EAP, SELECT_ACTION);
-		} else {
-			SM_ENTER(EAP, METHOD_RESPONSE);
-		}
-		break;
-	case EAP_DISABLED:
-		if (sm->eap_if.portEnabled)
-			SM_ENTER(EAP, INITIALIZE);
-		break;
-	case EAP_IDLE:
-		if (sm->eap_if.retransWhile == 0)
-			SM_ENTER(EAP, RETRANSMIT);
-		else if (sm->eap_if.eapResp)
-			SM_ENTER(EAP, RECEIVED);
-		break;
-	case EAP_RETRANSMIT:
-		if (sm->retransCount > sm->MaxRetrans)
-			SM_ENTER(EAP, TIMEOUT_FAILURE);
-		else
-			SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_RECEIVED:
-		if (sm->rxResp && (sm->respId == sm->currentId) &&
-		    (sm->respMethod == EAP_TYPE_NAK ||
-		     (sm->respMethod == EAP_TYPE_EXPANDED &&
-		      sm->respVendor == EAP_VENDOR_IETF &&
-		      sm->respVendorMethod == EAP_TYPE_NAK))
-		    && (sm->methodState == METHOD_PROPOSED))
-			SM_ENTER(EAP, NAK);
-		else if (sm->rxResp && (sm->respId == sm->currentId) &&
-			 ((sm->respMethod == sm->currentMethod) ||
-			  (sm->respMethod == EAP_TYPE_EXPANDED &&
-			   sm->respVendor == EAP_VENDOR_IETF &&
-			   sm->respVendorMethod == sm->currentMethod)))
-			SM_ENTER(EAP, INTEGRITY_CHECK);
-		else {
-			wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
-				   "rxResp=%d respId=%d currentId=%d "
-				   "respMethod=%d currentMethod=%d",
-				   sm->rxResp, sm->respId, sm->currentId,
-				   sm->respMethod, sm->currentMethod);
-			SM_ENTER(EAP, DISCARD);
-		}
-		break;
-	case EAP_DISCARD:
-		SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_SEND_REQUEST:
-		SM_ENTER(EAP, IDLE);
-		break;
-	case EAP_INTEGRITY_CHECK:
-		if (sm->ignore)
-			SM_ENTER(EAP, DISCARD);
-		else
-			SM_ENTER(EAP, METHOD_RESPONSE);
-		break;
-	case EAP_METHOD_REQUEST:
-		SM_ENTER(EAP, SEND_REQUEST);
-		break;
-	case EAP_METHOD_RESPONSE:
-		/*
-		 * Note: Mechanism to allow EAP methods to wait while going
-		 * through pending processing is an extension to RFC 4137
-		 * which only defines the transits to SELECT_ACTION and
-		 * METHOD_REQUEST from this METHOD_RESPONSE state.
-		 */
-		if (sm->methodState == METHOD_END)
-			SM_ENTER(EAP, SELECT_ACTION);
-		else if (sm->method_pending == METHOD_PENDING_WAIT) {
-			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
-				   "processing - wait before proceeding to "
-				   "METHOD_REQUEST state");
-		} else if (sm->method_pending == METHOD_PENDING_CONT) {
-			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
-				   "pending processing - reprocess pending "
-				   "EAP message");
-			sm->method_pending = METHOD_PENDING_NONE;
-			SM_ENTER(EAP, METHOD_RESPONSE);
-		} else
-			SM_ENTER(EAP, METHOD_REQUEST);
-		break;
-	case EAP_PROPOSE_METHOD:
-		/*
-		 * Note: Mechanism to allow EAP methods to wait while going
-		 * through pending processing is an extension to RFC 4137
-		 * which only defines the transit to METHOD_REQUEST from this
-		 * PROPOSE_METHOD state.
-		 */
-		if (sm->method_pending == METHOD_PENDING_WAIT) {
-			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
-				   "processing - wait before proceeding to "
-				   "METHOD_REQUEST state");
-			if (sm->user_eap_method_index > 0)
-				sm->user_eap_method_index--;
-		} else if (sm->method_pending == METHOD_PENDING_CONT) {
-			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
-				   "pending processing - reprocess pending "
-				   "EAP message");
-			sm->method_pending = METHOD_PENDING_NONE;
-			SM_ENTER(EAP, PROPOSE_METHOD);
-		} else
-			SM_ENTER(EAP, METHOD_REQUEST);
-		break;
-	case EAP_NAK:
-		SM_ENTER(EAP, SELECT_ACTION);
-		break;
-	case EAP_SELECT_ACTION:
-		if (sm->decision == DECISION_FAILURE)
-			SM_ENTER(EAP, FAILURE);
-		else if (sm->decision == DECISION_SUCCESS)
-			SM_ENTER(EAP, SUCCESS);
-		else if (sm->decision == DECISION_PASSTHROUGH)
-			SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
-		else
-			SM_ENTER(EAP, PROPOSE_METHOD);
-		break;
-	case EAP_TIMEOUT_FAILURE:
-		break;
-	case EAP_FAILURE:
-		break;
-	case EAP_SUCCESS:
-		break;
-
-	case EAP_INITIALIZE_PASSTHROUGH:
-		if (sm->currentId == -1)
-			SM_ENTER(EAP, AAA_IDLE);
-		else
-			SM_ENTER(EAP, AAA_REQUEST);
-		break;
-	case EAP_IDLE2:
-		if (sm->eap_if.eapResp)
-			SM_ENTER(EAP, RECEIVED2);
-		else if (sm->eap_if.retransWhile == 0)
-			SM_ENTER(EAP, RETRANSMIT2);
-		break;
-	case EAP_RETRANSMIT2:
-		if (sm->retransCount > sm->MaxRetrans)
-			SM_ENTER(EAP, TIMEOUT_FAILURE2);
-		else
-			SM_ENTER(EAP, IDLE2);
-		break;
-	case EAP_RECEIVED2:
-		if (sm->rxResp && (sm->respId == sm->currentId))
-			SM_ENTER(EAP, AAA_REQUEST);
-		else
-			SM_ENTER(EAP, DISCARD2);
-		break;
-	case EAP_DISCARD2:
-		SM_ENTER(EAP, IDLE2);
-		break;
-	case EAP_SEND_REQUEST2:
-		SM_ENTER(EAP, IDLE2);
-		break;
-	case EAP_AAA_REQUEST:
-		SM_ENTER(EAP, AAA_IDLE);
-		break;
-	case EAP_AAA_RESPONSE:
-		SM_ENTER(EAP, SEND_REQUEST2);
-		break;
-	case EAP_AAA_IDLE:
-		if (sm->eap_if.aaaFail)
-			SM_ENTER(EAP, FAILURE2);
-		else if (sm->eap_if.aaaSuccess)
-			SM_ENTER(EAP, SUCCESS2);
-		else if (sm->eap_if.aaaEapReq)
-			SM_ENTER(EAP, AAA_RESPONSE);
-		else if (sm->eap_if.aaaTimeout)
-			SM_ENTER(EAP, TIMEOUT_FAILURE2);
-		break;
-	case EAP_TIMEOUT_FAILURE2:
-		break;
-	case EAP_FAILURE2:
-		break;
-	case EAP_SUCCESS2:
-		break;
-	}
-}
-
-
-static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
-				   int eapSRTT, int eapRTTVAR,
-				   int methodTimeout)
-{
-	int rto, i;
-
-	if (methodTimeout) {
-		/*
-		 * EAP method (either internal or through AAA server, provided
-		 * timeout hint. Use that as-is as a timeout for retransmitting
-		 * the EAP request if no response is received.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
-			   "(from EAP method hint)", methodTimeout);
-		return methodTimeout;
-	}
-
-	/*
-	 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
-	 * of the retransmission timeout. This should be implemented once
-	 * round-trip time measurements are available. For nowm a simple
-	 * backoff mechanism is used instead if there are no EAP method
-	 * specific hints.
-	 *
-	 * SRTT = smoothed round-trip time
-	 * RTTVAR = round-trip time variation
-	 * RTO = retransmission timeout
-	 */
-
-	/*
-	 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
-	 * initial retransmission and then double the RTO to provide back off
-	 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
-	 * modified RTOmax.
-	 */
-	rto = 3;
-	for (i = 0; i < retransCount; i++) {
-		rto *= 2;
-		if (rto >= 20) {
-			rto = 20;
-			break;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
-		   "(from dynamic back off; retransCount=%d)",
-		   rto, retransCount);
-
-	return rto;
-}
-
-
-static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
-{
-	const struct eap_hdr *hdr;
-	size_t plen;
-
-	/* parse rxResp, respId, respMethod */
-	sm->rxResp = FALSE;
-	sm->respId = -1;
-	sm->respMethod = EAP_TYPE_NONE;
-	sm->respVendor = EAP_VENDOR_IETF;
-	sm->respVendorMethod = EAP_TYPE_NONE;
-
-	if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
-		wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
-			   "len=%lu", resp,
-			   resp ? (unsigned long) wpabuf_len(resp) : 0);
-		return;
-	}
-
-	hdr = wpabuf_head(resp);
-	plen = be_to_host16(hdr->length);
-	if (plen > wpabuf_len(resp)) {
-		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
-			   "(len=%lu plen=%lu)",
-			   (unsigned long) wpabuf_len(resp),
-			   (unsigned long) plen);
-		return;
-	}
-
-	sm->respId = hdr->identifier;
-
-	if (hdr->code == EAP_CODE_RESPONSE)
-		sm->rxResp = TRUE;
-
-	if (plen > sizeof(*hdr)) {
-		u8 *pos = (u8 *) (hdr + 1);
-		sm->respMethod = *pos++;
-		if (sm->respMethod == EAP_TYPE_EXPANDED) {
-			if (plen < sizeof(*hdr) + 8) {
-				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
-					   "expanded EAP-Packet (plen=%lu)",
-					   (unsigned long) plen);
-				return;
-			}
-			sm->respVendor = WPA_GET_BE24(pos);
-			pos += 3;
-			sm->respVendorMethod = WPA_GET_BE32(pos);
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
-		   "respMethod=%u respVendor=%u respVendorMethod=%u",
-		   sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
-		   sm->respVendorMethod);
-}
-
-
-static int eap_sm_getId(const struct wpabuf *data)
-{
-	const struct eap_hdr *hdr;
-
-	if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
-		return -1;
-
-	hdr = wpabuf_head(data);
-	wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
-	return hdr->identifier;
-}
-
-
-static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
-{
-	struct wpabuf *msg;
-	struct eap_hdr *resp;
-	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
-
-	msg = wpabuf_alloc(sizeof(*resp));
-	if (msg == NULL)
-		return NULL;
-	resp = wpabuf_put(msg, sizeof(*resp));
-	resp->code = EAP_CODE_SUCCESS;
-	resp->identifier = id;
-	resp->length = host_to_be16(sizeof(*resp));
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
-{
-	struct wpabuf *msg;
-	struct eap_hdr *resp;
-	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
-
-	msg = wpabuf_alloc(sizeof(*resp));
-	if (msg == NULL)
-		return NULL;
-	resp = wpabuf_put(msg, sizeof(*resp));
-	resp->code = EAP_CODE_FAILURE;
-	resp->identifier = id;
-	resp->length = host_to_be16(sizeof(*resp));
-
-	return msg;
-}
-
-
-static int eap_sm_nextId(struct eap_sm *sm, int id)
-{
-	if (id < 0) {
-		/* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
-		 * random number */
-		id = rand() & 0xff;
-		if (id != sm->lastId)
-			return id;
-	}
-	return (id + 1) & 0xff;
-}
-
-
-/**
- * eap_sm_process_nak - Process EAP-Response/Nak
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * @nak_list: Nak list (allowed methods) from the supplicant
- * @len: Length of nak_list in bytes
- *
- * This function is called when EAP-Response/Nak is received from the
- * supplicant. This can happen for both phase 1 and phase 2 authentications.
- */
-void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
-{
-	int i;
-	size_t j;
-
-	if (sm->user == NULL)
-		return;
-
-	wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
-		   "index %d)", sm->user_eap_method_index);
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
-		    (u8 *) sm->user->methods,
-		    EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
-	wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
-		    nak_list, len);
-
-	i = sm->user_eap_method_index;
-	while (i < EAP_MAX_METHODS &&
-	       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-		sm->user->methods[i].method != EAP_TYPE_NONE)) {
-		if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
-			goto not_found;
-		for (j = 0; j < len; j++) {
-			if (nak_list[j] == sm->user->methods[i].method) {
-				break;
-			}
-		}
-
-		if (j < len) {
-			/* found */
-			i++;
-			continue;
-		}
-
-	not_found:
-		/* not found - remove from the list */
-		os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
-			   (EAP_MAX_METHODS - i - 1) *
-			   sizeof(sm->user->methods[0]));
-		sm->user->methods[EAP_MAX_METHODS - 1].vendor =
-			EAP_VENDOR_IETF;
-		sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
-		    (u8 *) sm->user->methods, EAP_MAX_METHODS *
-		    sizeof(sm->user->methods[0]));
-}
-
-
-static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
-				 size_t len)
-{
-	if (nak_list == NULL || sm == NULL || sm->user == NULL)
-		return;
-
-	if (sm->user->phase2) {
-		wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
-			   " info was selected - reject");
-		sm->decision = DECISION_FAILURE;
-		return;
-	}
-
-	eap_sm_process_nak(sm, nak_list, len);
-}
-
-
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
-{
-	EapType next;
-	int idx = sm->user_eap_method_index;
-
-	/* In theory, there should be no problems with starting
-	 * re-authentication with something else than EAP-Request/Identity and
-	 * this does indeed work with wpa_supplicant. However, at least Funk
-	 * Supplicant seemed to ignore re-auth if it skipped
-	 * EAP-Request/Identity.
-	 * Re-auth sets currentId == -1, so that can be used here to select
-	 * whether Identity needs to be requested again. */
-	if (sm->identity == NULL || sm->currentId == -1) {
-		*vendor = EAP_VENDOR_IETF;
-		next = EAP_TYPE_IDENTITY;
-		sm->update_user = TRUE;
-	} else if (sm->user && idx < EAP_MAX_METHODS &&
-		   (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
-		    sm->user->methods[idx].method != EAP_TYPE_NONE)) {
-		*vendor = sm->user->methods[idx].vendor;
-		next = sm->user->methods[idx].method;
-		sm->user_eap_method_index++;
-	} else {
-		*vendor = EAP_VENDOR_IETF;
-		next = EAP_TYPE_NONE;
-	}
-	wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
-		   *vendor, next);
-	return next;
-}
-
-
-static int eap_sm_Policy_getDecision(struct eap_sm *sm)
-{
-	if (!sm->eap_server && sm->identity && !sm->start_reauth) {
-		wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
-		return DECISION_PASSTHROUGH;
-	}
-
-	if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
-	    sm->m->isSuccess(sm, sm->eap_method_priv)) {
-		wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
-			   "SUCCESS");
-		sm->update_user = TRUE;
-		return DECISION_SUCCESS;
-	}
-
-	if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
-	    !sm->m->isSuccess(sm, sm->eap_method_priv)) {
-		wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
-			   "FAILURE");
-		sm->update_user = TRUE;
-		return DECISION_FAILURE;
-	}
-
-	if ((sm->user == NULL || sm->update_user) && sm->identity &&
-	    !sm->start_reauth) {
-		/*
-		 * Allow Identity method to be started once to allow identity
-		 * selection hint to be sent from the authentication server,
-		 * but prevent a loop of Identity requests by only allowing
-		 * this to happen once.
-		 */
-		int id_req = 0;
-		if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
-		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
-		    sm->user->methods[0].method == EAP_TYPE_IDENTITY)
-			id_req = 1;
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
-			wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
-				   "found from database -> FAILURE");
-			return DECISION_FAILURE;
-		}
-		if (id_req && sm->user &&
-		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
-		    sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
-			wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
-				   "identity request loop -> FAILURE");
-			sm->update_user = TRUE;
-			return DECISION_FAILURE;
-		}
-		sm->update_user = FALSE;
-	}
-	sm->start_reauth = FALSE;
-
-	if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-	    (sm->user->methods[sm->user_eap_method_index].vendor !=
-	     EAP_VENDOR_IETF ||
-	     sm->user->methods[sm->user_eap_method_index].method !=
-	     EAP_TYPE_NONE)) {
-		wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
-			   "available -> CONTINUE");
-		return DECISION_CONTINUE;
-	}
-
-	if (sm->identity == NULL || sm->currentId == -1) {
-		wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
-			   "yet -> CONTINUE");
-		return DECISION_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
-		   "FAILURE");
-	return DECISION_FAILURE;
-}
-
-
-static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
-{
-	return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
-}
-
-
-/**
- * eap_server_sm_step - Step EAP server state machine
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * Returns: 1 if EAP state was changed or 0 if not
- *
- * This function advances EAP state machine to a new state to match with the
- * current variables. This should be called whenever variables used by the EAP
- * state machine have changed.
- */
-int eap_server_sm_step(struct eap_sm *sm)
-{
-	int res = 0;
-	do {
-		sm->changed = FALSE;
-		SM_STEP_RUN(EAP);
-		if (sm->changed)
-			res = 1;
-	} while (sm->changed);
-	return res;
-}
-
-
-static void eap_user_free(struct eap_user *user)
-{
-	if (user == NULL)
-		return;
-	os_free(user->password);
-	user->password = NULL;
-	os_free(user);
-}
-
-
-/**
- * eap_server_sm_init - Allocate and initialize EAP server state machine
- * @eapol_ctx: Context data to be used with eapol_cb calls
- * @eapol_cb: Pointer to EAPOL callback functions
- * @conf: EAP configuration
- * Returns: Pointer to the allocated EAP state machine or %NULL on failure
- *
- * This function allocates and initializes an EAP state machine.
- */
-struct eap_sm * eap_server_sm_init(void *eapol_ctx,
-				   struct eapol_callbacks *eapol_cb,
-				   struct eap_config *conf)
-{
-	struct eap_sm *sm;
-
-	sm = os_zalloc(sizeof(*sm));
-	if (sm == NULL)
-		return NULL;
-	sm->eapol_ctx = eapol_ctx;
-	sm->eapol_cb = eapol_cb;
-	sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
-	sm->ssl_ctx = conf->ssl_ctx;
-	sm->msg_ctx = conf->msg_ctx;
-	sm->eap_sim_db_priv = conf->eap_sim_db_priv;
-	sm->backend_auth = conf->backend_auth;
-	sm->eap_server = conf->eap_server;
-	if (conf->pac_opaque_encr_key) {
-		sm->pac_opaque_encr_key = os_malloc(16);
-		if (sm->pac_opaque_encr_key) {
-			os_memcpy(sm->pac_opaque_encr_key,
-				  conf->pac_opaque_encr_key, 16);
-		}
-	}
-	if (conf->eap_fast_a_id) {
-		sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
-		if (sm->eap_fast_a_id) {
-			os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
-				  conf->eap_fast_a_id_len);
-			sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
-		}
-	}
-	if (conf->eap_fast_a_id_info)
-		sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
-	sm->eap_fast_prov = conf->eap_fast_prov;
-	sm->pac_key_lifetime = conf->pac_key_lifetime;
-	sm->pac_key_refresh_time = conf->pac_key_refresh_time;
-	sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
-	sm->tnc = conf->tnc;
-	sm->wps = conf->wps;
-	if (conf->assoc_wps_ie)
-		sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
-	if (conf->peer_addr)
-		os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
-
-	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
-
-	return sm;
-}
-
-
-/**
- * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- *
- * This function deinitializes EAP state machine and frees all allocated
- * resources.
- */
-void eap_server_sm_deinit(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
-	if (sm->m && sm->eap_method_priv)
-		sm->m->reset(sm, sm->eap_method_priv);
-	wpabuf_free(sm->eap_if.eapReqData);
-	os_free(sm->eap_if.eapKeyData);
-	wpabuf_free(sm->lastReqData);
-	wpabuf_free(sm->eap_if.eapRespData);
-	os_free(sm->identity);
-	os_free(sm->pac_opaque_encr_key);
-	os_free(sm->eap_fast_a_id);
-	os_free(sm->eap_fast_a_id_info);
-	wpabuf_free(sm->eap_if.aaaEapReqData);
-	wpabuf_free(sm->eap_if.aaaEapRespData);
-	os_free(sm->eap_if.aaaEapKeyData);
-	eap_user_free(sm->user);
-	wpabuf_free(sm->assoc_wps_ie);
-	os_free(sm);
-}
-
-
-/**
- * eap_sm_notify_cached - Notify EAP state machine of cached PMK
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- *
- * This function is called when PMKSA caching is used to skip EAP
- * authentication.
- */
-void eap_sm_notify_cached(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return;
-
-	sm->EAP_state = EAP_SUCCESS;
-}
-
-
-/**
- * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- *
- * This function is called when data for a pending EAP-Request is received.
- */
-void eap_sm_pending_cb(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
-	if (sm->method_pending == METHOD_PENDING_WAIT)
-		sm->method_pending = METHOD_PENDING_CONT;
-}
-
-
-/**
- * eap_sm_method_pending - Query whether EAP method is waiting for pending data
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * Returns: 1 if method is waiting for pending data or 0 if not
- */
-int eap_sm_method_pending(struct eap_sm *sm)
-{
-	if (sm == NULL)
-		return 0;
-	return sm->method_pending == METHOD_PENDING_WAIT;
-}
-
-
-/**
- * eap_get_identity - Get the user identity (from EAP-Response/Identity)
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * @len: Buffer for returning identity length
- * Returns: Pointer to the user identity or %NULL if not available
- */
-const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
-{
-	*len = sm->identity_len;
-	return sm->identity;
-}
-
-
-/**
- * eap_get_interface - Get pointer to EAP-EAPOL interface data
- * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
- * Returns: Pointer to the EAP-EAPOL interface data
- */
-struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
-{
-	return &sm->eap_if;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1401 @@
+/*
+ * hostapd / EAP Full Authenticator state machine (RFC 4137)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This state machine is based on the full authenticator state machine defined
+ * in RFC 4137. However, to support backend authentication in RADIUS
+ * authentication server functionality, parts of backend authenticator (also
+ * from RFC 4137) are mixed in. This functionality is enabled by setting
+ * backend_auth configuration variable to TRUE.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#include "state_machine.h"
+#include "common/wpa_ctrl.h"
+
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
+
+#define EAP_MAX_AUTH_ROUNDS 50
+
+static void eap_user_free(struct eap_user *user);
+
+
+/* EAP state machines are described in RFC 4137 */
+
+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
+				   int eapSRTT, int eapRTTVAR,
+				   int methodTimeout);
+static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
+static int eap_sm_getId(const struct wpabuf *data);
+static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
+static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
+static int eap_sm_nextId(struct eap_sm *sm, int id);
+static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
+				 size_t len);
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
+static int eap_sm_Policy_getDecision(struct eap_sm *sm);
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+
+
+static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
+{
+	if (src == NULL)
+		return -1;
+
+	wpabuf_free(*dst);
+	*dst = wpabuf_dup(src);
+	return *dst ? 0 : -1;
+}
+
+
+static int eap_copy_data(u8 **dst, size_t *dst_len,
+			 const u8 *src, size_t src_len)
+{
+	if (src == NULL)
+		return -1;
+
+	os_free(*dst);
+	*dst = os_malloc(src_len);
+	if (*dst) {
+		os_memcpy(*dst, src, src_len);
+		*dst_len = src_len;
+		return 0;
+	} else {
+		*dst_len = 0;
+		return -1;
+	}
+}
+
+#define EAP_COPY(dst, src) \
+	eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
+
+
+/**
+ * eap_user_get - Fetch user information from the database
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @identity: Identity (User-Name) of the user
+ * @identity_len: Length of identity in bytes
+ * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function is used to fetch user information for EAP. The user will be
+ * selected based on the specified identity. sm->user and
+ * sm->user_eap_method_index are updated for the new user when a matching user
+ * is found. sm->user can be used to get user information (e.g., password).
+ */
+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
+		 int phase2)
+{
+	struct eap_user *user;
+
+	if (sm == NULL || sm->eapol_cb == NULL ||
+	    sm->eapol_cb->get_eap_user == NULL)
+		return -1;
+
+	eap_user_free(sm->user);
+	sm->user = NULL;
+
+	user = os_zalloc(sizeof(*user));
+	if (user == NULL)
+	    return -1;
+
+	if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
+				       identity_len, phase2, user) != 0) {
+		eap_user_free(user);
+		return -1;
+	}
+
+	sm->user = user;
+	sm->user_eap_method_index = 0;
+
+	return 0;
+}
+
+
+SM_STATE(EAP, DISABLED)
+{
+	SM_ENTRY(EAP, DISABLED);
+	sm->num_rounds = 0;
+}
+
+
+SM_STATE(EAP, INITIALIZE)
+{
+	SM_ENTRY(EAP, INITIALIZE);
+
+	if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+		/*
+		 * Need to allow internal Identity method to be used instead
+		 * of passthrough at the beginning of reauthentication.
+		 */
+		eap_server_clear_identity(sm);
+	}
+
+	sm->currentId = -1;
+	sm->eap_if.eapSuccess = FALSE;
+	sm->eap_if.eapFail = FALSE;
+	sm->eap_if.eapTimeout = FALSE;
+	os_free(sm->eap_if.eapKeyData);
+	sm->eap_if.eapKeyData = NULL;
+	sm->eap_if.eapKeyDataLen = 0;
+	sm->eap_if.eapKeyAvailable = FALSE;
+	sm->eap_if.eapRestart = FALSE;
+
+	/*
+	 * This is not defined in RFC 4137, but method state needs to be
+	 * reseted here so that it does not remain in success state when
+	 * re-authentication starts.
+	 */
+	if (sm->m && sm->eap_method_priv) {
+		sm->m->reset(sm, sm->eap_method_priv);
+		sm->eap_method_priv = NULL;
+	}
+	sm->m = NULL;
+	sm->user_eap_method_index = 0;
+
+	if (sm->backend_auth) {
+		sm->currentMethod = EAP_TYPE_NONE;
+		/* parse rxResp, respId, respMethod */
+		eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
+		if (sm->rxResp) {
+			sm->currentId = sm->respId;
+		}
+	}
+	sm->num_rounds = 0;
+	sm->method_pending = METHOD_PENDING_NONE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+		MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, PICK_UP_METHOD)
+{
+	SM_ENTRY(EAP, PICK_UP_METHOD);
+
+	if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
+		sm->currentMethod = sm->respMethod;
+		if (sm->m && sm->eap_method_priv) {
+			sm->m->reset(sm, sm->eap_method_priv);
+			sm->eap_method_priv = NULL;
+		}
+		sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
+						  sm->currentMethod);
+		if (sm->m && sm->m->initPickUp) {
+			sm->eap_method_priv = sm->m->initPickUp(sm);
+			if (sm->eap_method_priv == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP: Failed to "
+					   "initialize EAP method %d",
+					   sm->currentMethod);
+				sm->m = NULL;
+				sm->currentMethod = EAP_TYPE_NONE;
+			}
+		} else {
+			sm->m = NULL;
+			sm->currentMethod = EAP_TYPE_NONE;
+		}
+	}
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+		"method=%u", sm->currentMethod);
+}
+
+
+SM_STATE(EAP, IDLE)
+{
+	SM_ENTRY(EAP, IDLE);
+
+	sm->eap_if.retransWhile = eap_sm_calculateTimeout(
+		sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
+		sm->methodTimeout);
+}
+
+
+SM_STATE(EAP, RETRANSMIT)
+{
+	SM_ENTRY(EAP, RETRANSMIT);
+
+	sm->retransCount++;
+	if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
+		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
+			sm->eap_if.eapReq = TRUE;
+	}
+}
+
+
+SM_STATE(EAP, RECEIVED)
+{
+	SM_ENTRY(EAP, RECEIVED);
+
+	/* parse rxResp, respId, respMethod */
+	eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
+	sm->num_rounds++;
+}
+
+
+SM_STATE(EAP, DISCARD)
+{
+	SM_ENTRY(EAP, DISCARD);
+	sm->eap_if.eapResp = FALSE;
+	sm->eap_if.eapNoReq = TRUE;
+}
+
+
+SM_STATE(EAP, SEND_REQUEST)
+{
+	SM_ENTRY(EAP, SEND_REQUEST);
+
+	sm->retransCount = 0;
+	if (sm->eap_if.eapReqData) {
+		if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
+		{
+			sm->eap_if.eapResp = FALSE;
+			sm->eap_if.eapReq = TRUE;
+		} else {
+			sm->eap_if.eapResp = FALSE;
+			sm->eap_if.eapReq = FALSE;
+		}
+	} else {
+		wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
+		sm->eap_if.eapResp = FALSE;
+		sm->eap_if.eapReq = FALSE;
+		sm->eap_if.eapNoReq = TRUE;
+	}
+}
+
+
+SM_STATE(EAP, INTEGRITY_CHECK)
+{
+	SM_ENTRY(EAP, INTEGRITY_CHECK);
+
+	if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
+		sm->ignore = TRUE;
+		return;
+	}
+
+	if (sm->m->check) {
+		sm->ignore = sm->m->check(sm, sm->eap_method_priv,
+					  sm->eap_if.eapRespData);
+	}
+}
+
+
+SM_STATE(EAP, METHOD_REQUEST)
+{
+	SM_ENTRY(EAP, METHOD_REQUEST);
+
+	if (sm->m == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP: method not initialized");
+		return;
+	}
+
+	sm->currentId = eap_sm_nextId(sm, sm->currentId);
+	wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
+		   sm->currentId);
+	sm->lastId = sm->currentId;
+	wpabuf_free(sm->eap_if.eapReqData);
+	sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
+						sm->currentId);
+	if (sm->m->getTimeout)
+		sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
+	else
+		sm->methodTimeout = 0;
+}
+
+
+SM_STATE(EAP, METHOD_RESPONSE)
+{
+	SM_ENTRY(EAP, METHOD_RESPONSE);
+
+	if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+		return;
+
+	sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
+	if (sm->m->isDone(sm, sm->eap_method_priv)) {
+		eap_sm_Policy_update(sm, NULL, 0);
+		os_free(sm->eap_if.eapKeyData);
+		if (sm->m->getKey) {
+			sm->eap_if.eapKeyData = sm->m->getKey(
+				sm, sm->eap_method_priv,
+				&sm->eap_if.eapKeyDataLen);
+		} else {
+			sm->eap_if.eapKeyData = NULL;
+			sm->eap_if.eapKeyDataLen = 0;
+		}
+		sm->methodState = METHOD_END;
+	} else {
+		sm->methodState = METHOD_CONTINUE;
+	}
+}
+
+
+SM_STATE(EAP, PROPOSE_METHOD)
+{
+	int vendor;
+	EapType type;
+
+	SM_ENTRY(EAP, PROPOSE_METHOD);
+
+	type = eap_sm_Policy_getNextMethod(sm, &vendor);
+	if (vendor == EAP_VENDOR_IETF)
+		sm->currentMethod = type;
+	else
+		sm->currentMethod = EAP_TYPE_EXPANDED;
+	if (sm->m && sm->eap_method_priv) {
+		sm->m->reset(sm, sm->eap_method_priv);
+		sm->eap_method_priv = NULL;
+	}
+	sm->m = eap_server_get_eap_method(vendor, type);
+	if (sm->m) {
+		sm->eap_method_priv = sm->m->init(sm);
+		if (sm->eap_method_priv == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
+				   "method %d", sm->currentMethod);
+			sm->m = NULL;
+			sm->currentMethod = EAP_TYPE_NONE;
+		}
+	}
+	if (sm->currentMethod == EAP_TYPE_IDENTITY ||
+	    sm->currentMethod == EAP_TYPE_NOTIFICATION)
+		sm->methodState = METHOD_CONTINUE;
+	else
+		sm->methodState = METHOD_PROPOSED;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+		"vendor=%u method=%u", vendor, sm->currentMethod);
+}
+
+
+SM_STATE(EAP, NAK)
+{
+	const struct eap_hdr *nak;
+	size_t len = 0;
+	const u8 *pos;
+	const u8 *nak_list = NULL;
+
+	SM_ENTRY(EAP, NAK);
+
+	if (sm->eap_method_priv) {
+		sm->m->reset(sm, sm->eap_method_priv);
+		sm->eap_method_priv = NULL;
+	}
+	sm->m = NULL;
+
+	if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+		return;
+
+	nak = wpabuf_head(sm->eap_if.eapRespData);
+	if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
+		len = be_to_host16(nak->length);
+		if (len > wpabuf_len(sm->eap_if.eapRespData))
+			len = wpabuf_len(sm->eap_if.eapRespData);
+		pos = (const u8 *) (nak + 1);
+		len -= sizeof(*nak);
+		if (*pos == EAP_TYPE_NAK) {
+			pos++;
+			len--;
+			nak_list = pos;
+		}
+	}
+	eap_sm_Policy_update(sm, nak_list, len);
+}
+
+
+SM_STATE(EAP, SELECT_ACTION)
+{
+	SM_ENTRY(EAP, SELECT_ACTION);
+
+	sm->decision = eap_sm_Policy_getDecision(sm);
+}
+
+
+SM_STATE(EAP, TIMEOUT_FAILURE)
+{
+	SM_ENTRY(EAP, TIMEOUT_FAILURE);
+
+	sm->eap_if.eapTimeout = TRUE;
+}
+
+
+SM_STATE(EAP, FAILURE)
+{
+	SM_ENTRY(EAP, FAILURE);
+
+	wpabuf_free(sm->eap_if.eapReqData);
+	sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
+	wpabuf_free(sm->lastReqData);
+	sm->lastReqData = NULL;
+	sm->eap_if.eapFail = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+		MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, SUCCESS)
+{
+	SM_ENTRY(EAP, SUCCESS);
+
+	wpabuf_free(sm->eap_if.eapReqData);
+	sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
+	wpabuf_free(sm->lastReqData);
+	sm->lastReqData = NULL;
+	if (sm->eap_if.eapKeyData)
+		sm->eap_if.eapKeyAvailable = TRUE;
+	sm->eap_if.eapSuccess = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
+{
+	SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
+
+	wpabuf_free(sm->eap_if.aaaEapRespData);
+	sm->eap_if.aaaEapRespData = NULL;
+}
+
+
+SM_STATE(EAP, IDLE2)
+{
+	SM_ENTRY(EAP, IDLE2);
+
+	sm->eap_if.retransWhile = eap_sm_calculateTimeout(
+		sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
+		sm->methodTimeout);
+}
+
+
+SM_STATE(EAP, RETRANSMIT2)
+{
+	SM_ENTRY(EAP, RETRANSMIT2);
+
+	sm->retransCount++;
+	if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
+		if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
+			sm->eap_if.eapReq = TRUE;
+	}
+}
+
+
+SM_STATE(EAP, RECEIVED2)
+{
+	SM_ENTRY(EAP, RECEIVED2);
+
+	/* parse rxResp, respId, respMethod */
+	eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
+}
+
+
+SM_STATE(EAP, DISCARD2)
+{
+	SM_ENTRY(EAP, DISCARD2);
+	sm->eap_if.eapResp = FALSE;
+	sm->eap_if.eapNoReq = TRUE;
+}
+
+
+SM_STATE(EAP, SEND_REQUEST2)
+{
+	SM_ENTRY(EAP, SEND_REQUEST2);
+
+	sm->retransCount = 0;
+	if (sm->eap_if.eapReqData) {
+		if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
+		{
+			sm->eap_if.eapResp = FALSE;
+			sm->eap_if.eapReq = TRUE;
+		} else {
+			sm->eap_if.eapResp = FALSE;
+			sm->eap_if.eapReq = FALSE;
+		}
+	} else {
+		wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
+		sm->eap_if.eapResp = FALSE;
+		sm->eap_if.eapReq = FALSE;
+		sm->eap_if.eapNoReq = TRUE;
+	}
+}
+
+
+SM_STATE(EAP, AAA_REQUEST)
+{
+	SM_ENTRY(EAP, AAA_REQUEST);
+
+	if (sm->eap_if.eapRespData == NULL) {
+		wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
+		return;
+	}
+
+	/*
+	 * if (respMethod == IDENTITY)
+	 *	aaaIdentity = eapRespData
+	 * This is already taken care of by the EAP-Identity method which
+	 * stores the identity into sm->identity.
+	 */
+
+	eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
+}
+
+
+SM_STATE(EAP, AAA_RESPONSE)
+{
+	SM_ENTRY(EAP, AAA_RESPONSE);
+
+	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
+	sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
+	sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
+}
+
+
+SM_STATE(EAP, AAA_IDLE)
+{
+	SM_ENTRY(EAP, AAA_IDLE);
+
+	sm->eap_if.aaaFail = FALSE;
+	sm->eap_if.aaaSuccess = FALSE;
+	sm->eap_if.aaaEapReq = FALSE;
+	sm->eap_if.aaaEapNoReq = FALSE;
+	sm->eap_if.aaaEapResp = TRUE;
+}
+
+
+SM_STATE(EAP, TIMEOUT_FAILURE2)
+{
+	SM_ENTRY(EAP, TIMEOUT_FAILURE2);
+
+	sm->eap_if.eapTimeout = TRUE;
+}
+
+
+SM_STATE(EAP, FAILURE2)
+{
+	SM_ENTRY(EAP, FAILURE2);
+
+	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
+	sm->eap_if.eapFail = TRUE;
+}
+
+
+SM_STATE(EAP, SUCCESS2)
+{
+	SM_ENTRY(EAP, SUCCESS2);
+
+	eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
+
+	sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
+	if (sm->eap_if.aaaEapKeyAvailable) {
+		EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
+	} else {
+		os_free(sm->eap_if.eapKeyData);
+		sm->eap_if.eapKeyData = NULL;
+		sm->eap_if.eapKeyDataLen = 0;
+	}
+
+	sm->eap_if.eapSuccess = TRUE;
+
+	/*
+	 * Start reauthentication with identity request even though we know the
+	 * previously used identity. This is needed to get reauthentication
+	 * started properly.
+	 */
+	sm->start_reauth = TRUE;
+}
+
+
+SM_STEP(EAP)
+{
+	if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
+		SM_ENTER_GLOBAL(EAP, INITIALIZE);
+	else if (!sm->eap_if.portEnabled)
+		SM_ENTER_GLOBAL(EAP, DISABLED);
+	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
+		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+			wpa_printf(MSG_DEBUG, "EAP: more than %d "
+				   "authentication rounds - abort",
+				   EAP_MAX_AUTH_ROUNDS);
+			sm->num_rounds++;
+			SM_ENTER_GLOBAL(EAP, FAILURE);
+		}
+	} else switch (sm->EAP_state) {
+	case EAP_INITIALIZE:
+		if (sm->backend_auth) {
+			if (!sm->rxResp)
+				SM_ENTER(EAP, SELECT_ACTION);
+			else if (sm->rxResp &&
+				 (sm->respMethod == EAP_TYPE_NAK ||
+				  (sm->respMethod == EAP_TYPE_EXPANDED &&
+				   sm->respVendor == EAP_VENDOR_IETF &&
+				   sm->respVendorMethod == EAP_TYPE_NAK)))
+				SM_ENTER(EAP, NAK);
+			else
+				SM_ENTER(EAP, PICK_UP_METHOD);
+		} else {
+			SM_ENTER(EAP, SELECT_ACTION);
+		}
+		break;
+	case EAP_PICK_UP_METHOD:
+		if (sm->currentMethod == EAP_TYPE_NONE) {
+			SM_ENTER(EAP, SELECT_ACTION);
+		} else {
+			SM_ENTER(EAP, METHOD_RESPONSE);
+		}
+		break;
+	case EAP_DISABLED:
+		if (sm->eap_if.portEnabled)
+			SM_ENTER(EAP, INITIALIZE);
+		break;
+	case EAP_IDLE:
+		if (sm->eap_if.retransWhile == 0)
+			SM_ENTER(EAP, RETRANSMIT);
+		else if (sm->eap_if.eapResp)
+			SM_ENTER(EAP, RECEIVED);
+		break;
+	case EAP_RETRANSMIT:
+		if (sm->retransCount > sm->MaxRetrans)
+			SM_ENTER(EAP, TIMEOUT_FAILURE);
+		else
+			SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_RECEIVED:
+		if (sm->rxResp && (sm->respId == sm->currentId) &&
+		    (sm->respMethod == EAP_TYPE_NAK ||
+		     (sm->respMethod == EAP_TYPE_EXPANDED &&
+		      sm->respVendor == EAP_VENDOR_IETF &&
+		      sm->respVendorMethod == EAP_TYPE_NAK))
+		    && (sm->methodState == METHOD_PROPOSED))
+			SM_ENTER(EAP, NAK);
+		else if (sm->rxResp && (sm->respId == sm->currentId) &&
+			 ((sm->respMethod == sm->currentMethod) ||
+			  (sm->respMethod == EAP_TYPE_EXPANDED &&
+			   sm->respVendor == EAP_VENDOR_IETF &&
+			   sm->respVendorMethod == sm->currentMethod)))
+			SM_ENTER(EAP, INTEGRITY_CHECK);
+		else {
+			wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
+				   "rxResp=%d respId=%d currentId=%d "
+				   "respMethod=%d currentMethod=%d",
+				   sm->rxResp, sm->respId, sm->currentId,
+				   sm->respMethod, sm->currentMethod);
+			SM_ENTER(EAP, DISCARD);
+		}
+		break;
+	case EAP_DISCARD:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_SEND_REQUEST:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_INTEGRITY_CHECK:
+		if (sm->ignore)
+			SM_ENTER(EAP, DISCARD);
+		else
+			SM_ENTER(EAP, METHOD_RESPONSE);
+		break;
+	case EAP_METHOD_REQUEST:
+		SM_ENTER(EAP, SEND_REQUEST);
+		break;
+	case EAP_METHOD_RESPONSE:
+		/*
+		 * Note: Mechanism to allow EAP methods to wait while going
+		 * through pending processing is an extension to RFC 4137
+		 * which only defines the transits to SELECT_ACTION and
+		 * METHOD_REQUEST from this METHOD_RESPONSE state.
+		 */
+		if (sm->methodState == METHOD_END)
+			SM_ENTER(EAP, SELECT_ACTION);
+		else if (sm->method_pending == METHOD_PENDING_WAIT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+				   "processing - wait before proceeding to "
+				   "METHOD_REQUEST state");
+		} else if (sm->method_pending == METHOD_PENDING_CONT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+				   "pending processing - reprocess pending "
+				   "EAP message");
+			sm->method_pending = METHOD_PENDING_NONE;
+			SM_ENTER(EAP, METHOD_RESPONSE);
+		} else
+			SM_ENTER(EAP, METHOD_REQUEST);
+		break;
+	case EAP_PROPOSE_METHOD:
+		/*
+		 * Note: Mechanism to allow EAP methods to wait while going
+		 * through pending processing is an extension to RFC 4137
+		 * which only defines the transit to METHOD_REQUEST from this
+		 * PROPOSE_METHOD state.
+		 */
+		if (sm->method_pending == METHOD_PENDING_WAIT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+				   "processing - wait before proceeding to "
+				   "METHOD_REQUEST state");
+			if (sm->user_eap_method_index > 0)
+				sm->user_eap_method_index--;
+		} else if (sm->method_pending == METHOD_PENDING_CONT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+				   "pending processing - reprocess pending "
+				   "EAP message");
+			sm->method_pending = METHOD_PENDING_NONE;
+			SM_ENTER(EAP, PROPOSE_METHOD);
+		} else
+			SM_ENTER(EAP, METHOD_REQUEST);
+		break;
+	case EAP_NAK:
+		SM_ENTER(EAP, SELECT_ACTION);
+		break;
+	case EAP_SELECT_ACTION:
+		if (sm->decision == DECISION_FAILURE)
+			SM_ENTER(EAP, FAILURE);
+		else if (sm->decision == DECISION_SUCCESS)
+			SM_ENTER(EAP, SUCCESS);
+		else if (sm->decision == DECISION_PASSTHROUGH)
+			SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
+		else
+			SM_ENTER(EAP, PROPOSE_METHOD);
+		break;
+	case EAP_TIMEOUT_FAILURE:
+		break;
+	case EAP_FAILURE:
+		break;
+	case EAP_SUCCESS:
+		break;
+
+	case EAP_INITIALIZE_PASSTHROUGH:
+		if (sm->currentId == -1)
+			SM_ENTER(EAP, AAA_IDLE);
+		else
+			SM_ENTER(EAP, AAA_REQUEST);
+		break;
+	case EAP_IDLE2:
+		if (sm->eap_if.eapResp)
+			SM_ENTER(EAP, RECEIVED2);
+		else if (sm->eap_if.retransWhile == 0)
+			SM_ENTER(EAP, RETRANSMIT2);
+		break;
+	case EAP_RETRANSMIT2:
+		if (sm->retransCount > sm->MaxRetrans)
+			SM_ENTER(EAP, TIMEOUT_FAILURE2);
+		else
+			SM_ENTER(EAP, IDLE2);
+		break;
+	case EAP_RECEIVED2:
+		if (sm->rxResp && (sm->respId == sm->currentId))
+			SM_ENTER(EAP, AAA_REQUEST);
+		else
+			SM_ENTER(EAP, DISCARD2);
+		break;
+	case EAP_DISCARD2:
+		SM_ENTER(EAP, IDLE2);
+		break;
+	case EAP_SEND_REQUEST2:
+		SM_ENTER(EAP, IDLE2);
+		break;
+	case EAP_AAA_REQUEST:
+		SM_ENTER(EAP, AAA_IDLE);
+		break;
+	case EAP_AAA_RESPONSE:
+		SM_ENTER(EAP, SEND_REQUEST2);
+		break;
+	case EAP_AAA_IDLE:
+		if (sm->eap_if.aaaFail)
+			SM_ENTER(EAP, FAILURE2);
+		else if (sm->eap_if.aaaSuccess)
+			SM_ENTER(EAP, SUCCESS2);
+		else if (sm->eap_if.aaaEapReq)
+			SM_ENTER(EAP, AAA_RESPONSE);
+		else if (sm->eap_if.aaaTimeout)
+			SM_ENTER(EAP, TIMEOUT_FAILURE2);
+		break;
+	case EAP_TIMEOUT_FAILURE2:
+		break;
+	case EAP_FAILURE2:
+		break;
+	case EAP_SUCCESS2:
+		break;
+	}
+}
+
+
+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
+				   int eapSRTT, int eapRTTVAR,
+				   int methodTimeout)
+{
+	int rto, i;
+
+	if (methodTimeout) {
+		/*
+		 * EAP method (either internal or through AAA server, provided
+		 * timeout hint. Use that as-is as a timeout for retransmitting
+		 * the EAP request if no response is received.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
+			   "(from EAP method hint)", methodTimeout);
+		return methodTimeout;
+	}
+
+	/*
+	 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
+	 * of the retransmission timeout. This should be implemented once
+	 * round-trip time measurements are available. For nowm a simple
+	 * backoff mechanism is used instead if there are no EAP method
+	 * specific hints.
+	 *
+	 * SRTT = smoothed round-trip time
+	 * RTTVAR = round-trip time variation
+	 * RTO = retransmission timeout
+	 */
+
+	/*
+	 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
+	 * initial retransmission and then double the RTO to provide back off
+	 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
+	 * modified RTOmax.
+	 */
+	rto = 3;
+	for (i = 0; i < retransCount; i++) {
+		rto *= 2;
+		if (rto >= 20) {
+			rto = 20;
+			break;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
+		   "(from dynamic back off; retransCount=%d)",
+		   rto, retransCount);
+
+	return rto;
+}
+
+
+static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
+{
+	const struct eap_hdr *hdr;
+	size_t plen;
+
+	/* parse rxResp, respId, respMethod */
+	sm->rxResp = FALSE;
+	sm->respId = -1;
+	sm->respMethod = EAP_TYPE_NONE;
+	sm->respVendor = EAP_VENDOR_IETF;
+	sm->respVendorMethod = EAP_TYPE_NONE;
+
+	if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
+			   "len=%lu", resp,
+			   resp ? (unsigned long) wpabuf_len(resp) : 0);
+		return;
+	}
+
+	hdr = wpabuf_head(resp);
+	plen = be_to_host16(hdr->length);
+	if (plen > wpabuf_len(resp)) {
+		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
+			   "(len=%lu plen=%lu)",
+			   (unsigned long) wpabuf_len(resp),
+			   (unsigned long) plen);
+		return;
+	}
+
+	sm->respId = hdr->identifier;
+
+	if (hdr->code == EAP_CODE_RESPONSE)
+		sm->rxResp = TRUE;
+
+	if (plen > sizeof(*hdr)) {
+		u8 *pos = (u8 *) (hdr + 1);
+		sm->respMethod = *pos++;
+		if (sm->respMethod == EAP_TYPE_EXPANDED) {
+			if (plen < sizeof(*hdr) + 8) {
+				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+					   "expanded EAP-Packet (plen=%lu)",
+					   (unsigned long) plen);
+				return;
+			}
+			sm->respVendor = WPA_GET_BE24(pos);
+			pos += 3;
+			sm->respVendorMethod = WPA_GET_BE32(pos);
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
+		   "respMethod=%u respVendor=%u respVendorMethod=%u",
+		   sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
+		   sm->respVendorMethod);
+}
+
+
+static int eap_sm_getId(const struct wpabuf *data)
+{
+	const struct eap_hdr *hdr;
+
+	if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
+		return -1;
+
+	hdr = wpabuf_head(data);
+	wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
+	return hdr->identifier;
+}
+
+
+static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
+{
+	struct wpabuf *msg;
+	struct eap_hdr *resp;
+	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
+
+	msg = wpabuf_alloc(sizeof(*resp));
+	if (msg == NULL)
+		return NULL;
+	resp = wpabuf_put(msg, sizeof(*resp));
+	resp->code = EAP_CODE_SUCCESS;
+	resp->identifier = id;
+	resp->length = host_to_be16(sizeof(*resp));
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
+{
+	struct wpabuf *msg;
+	struct eap_hdr *resp;
+	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
+
+	msg = wpabuf_alloc(sizeof(*resp));
+	if (msg == NULL)
+		return NULL;
+	resp = wpabuf_put(msg, sizeof(*resp));
+	resp->code = EAP_CODE_FAILURE;
+	resp->identifier = id;
+	resp->length = host_to_be16(sizeof(*resp));
+
+	return msg;
+}
+
+
+static int eap_sm_nextId(struct eap_sm *sm, int id)
+{
+	if (id < 0) {
+		/* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
+		 * random number */
+		id = rand() & 0xff;
+		if (id != sm->lastId)
+			return id;
+	}
+	return (id + 1) & 0xff;
+}
+
+
+/**
+ * eap_sm_process_nak - Process EAP-Response/Nak
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @nak_list: Nak list (allowed methods) from the supplicant
+ * @len: Length of nak_list in bytes
+ *
+ * This function is called when EAP-Response/Nak is received from the
+ * supplicant. This can happen for both phase 1 and phase 2 authentications.
+ */
+void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
+{
+	int i;
+	size_t j;
+
+	if (sm->user == NULL)
+		return;
+
+	wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
+		   "index %d)", sm->user_eap_method_index);
+
+	wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
+		    (u8 *) sm->user->methods,
+		    EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
+	wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
+		    nak_list, len);
+
+	i = sm->user_eap_method_index;
+	while (i < EAP_MAX_METHODS &&
+	       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+		sm->user->methods[i].method != EAP_TYPE_NONE)) {
+		if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
+			goto not_found;
+		for (j = 0; j < len; j++) {
+			if (nak_list[j] == sm->user->methods[i].method) {
+				break;
+			}
+		}
+
+		if (j < len) {
+			/* found */
+			i++;
+			continue;
+		}
+
+	not_found:
+		/* not found - remove from the list */
+		if (i + 1 < EAP_MAX_METHODS) {
+			os_memmove(&sm->user->methods[i],
+				   &sm->user->methods[i + 1],
+				   (EAP_MAX_METHODS - i - 1) *
+				   sizeof(sm->user->methods[0]));
+		}
+		sm->user->methods[EAP_MAX_METHODS - 1].vendor =
+			EAP_VENDOR_IETF;
+		sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
+		    (u8 *) sm->user->methods, EAP_MAX_METHODS *
+		    sizeof(sm->user->methods[0]));
+}
+
+
+static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
+				 size_t len)
+{
+	if (nak_list == NULL || sm == NULL || sm->user == NULL)
+		return;
+
+	if (sm->user->phase2) {
+		wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
+			   " info was selected - reject");
+		sm->decision = DECISION_FAILURE;
+		return;
+	}
+
+	eap_sm_process_nak(sm, nak_list, len);
+}
+
+
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
+{
+	EapType next;
+	int idx = sm->user_eap_method_index;
+
+	/* In theory, there should be no problems with starting
+	 * re-authentication with something else than EAP-Request/Identity and
+	 * this does indeed work with wpa_supplicant. However, at least Funk
+	 * Supplicant seemed to ignore re-auth if it skipped
+	 * EAP-Request/Identity.
+	 * Re-auth sets currentId == -1, so that can be used here to select
+	 * whether Identity needs to be requested again. */
+	if (sm->identity == NULL || sm->currentId == -1) {
+		*vendor = EAP_VENDOR_IETF;
+		next = EAP_TYPE_IDENTITY;
+		sm->update_user = TRUE;
+	} else if (sm->user && idx < EAP_MAX_METHODS &&
+		   (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
+		    sm->user->methods[idx].method != EAP_TYPE_NONE)) {
+		*vendor = sm->user->methods[idx].vendor;
+		next = sm->user->methods[idx].method;
+		sm->user_eap_method_index++;
+	} else {
+		*vendor = EAP_VENDOR_IETF;
+		next = EAP_TYPE_NONE;
+	}
+	wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
+		   *vendor, next);
+	return next;
+}
+
+
+static int eap_sm_Policy_getDecision(struct eap_sm *sm)
+{
+	if (!sm->eap_server && sm->identity && !sm->start_reauth) {
+		wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
+		return DECISION_PASSTHROUGH;
+	}
+
+	if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
+	    sm->m->isSuccess(sm, sm->eap_method_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
+			   "SUCCESS");
+		sm->update_user = TRUE;
+		return DECISION_SUCCESS;
+	}
+
+	if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
+	    !sm->m->isSuccess(sm, sm->eap_method_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
+			   "FAILURE");
+		sm->update_user = TRUE;
+		return DECISION_FAILURE;
+	}
+
+	if ((sm->user == NULL || sm->update_user) && sm->identity &&
+	    !sm->start_reauth) {
+		/*
+		 * Allow Identity method to be started once to allow identity
+		 * selection hint to be sent from the authentication server,
+		 * but prevent a loop of Identity requests by only allowing
+		 * this to happen once.
+		 */
+		int id_req = 0;
+		if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
+		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[0].method == EAP_TYPE_IDENTITY)
+			id_req = 1;
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
+			wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
+				   "found from database -> FAILURE");
+			return DECISION_FAILURE;
+		}
+		if (id_req && sm->user &&
+		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
+			wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
+				   "identity request loop -> FAILURE");
+			sm->update_user = TRUE;
+			return DECISION_FAILURE;
+		}
+		sm->update_user = FALSE;
+	}
+	sm->start_reauth = FALSE;
+
+	if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+	    (sm->user->methods[sm->user_eap_method_index].vendor !=
+	     EAP_VENDOR_IETF ||
+	     sm->user->methods[sm->user_eap_method_index].method !=
+	     EAP_TYPE_NONE)) {
+		wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
+			   "available -> CONTINUE");
+		return DECISION_CONTINUE;
+	}
+
+	if (sm->identity == NULL || sm->currentId == -1) {
+		wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
+			   "yet -> CONTINUE");
+		return DECISION_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
+		   "FAILURE");
+	return DECISION_FAILURE;
+}
+
+
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+{
+	return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
+}
+
+
+/**
+ * eap_server_sm_step - Step EAP server state machine
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
+int eap_server_sm_step(struct eap_sm *sm)
+{
+	int res = 0;
+	do {
+		sm->changed = FALSE;
+		SM_STEP_RUN(EAP);
+		if (sm->changed)
+			res = 1;
+	} while (sm->changed);
+	return res;
+}
+
+
+static void eap_user_free(struct eap_user *user)
+{
+	if (user == NULL)
+		return;
+	os_free(user->password);
+	user->password = NULL;
+	os_free(user);
+}
+
+
+/**
+ * eap_server_sm_init - Allocate and initialize EAP server state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine.
+ */
+struct eap_sm * eap_server_sm_init(void *eapol_ctx,
+				   struct eapol_callbacks *eapol_cb,
+				   struct eap_config *conf)
+{
+	struct eap_sm *sm;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	sm->eapol_ctx = eapol_ctx;
+	sm->eapol_cb = eapol_cb;
+	sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
+	sm->ssl_ctx = conf->ssl_ctx;
+	sm->msg_ctx = conf->msg_ctx;
+	sm->eap_sim_db_priv = conf->eap_sim_db_priv;
+	sm->backend_auth = conf->backend_auth;
+	sm->eap_server = conf->eap_server;
+	if (conf->pac_opaque_encr_key) {
+		sm->pac_opaque_encr_key = os_malloc(16);
+		if (sm->pac_opaque_encr_key) {
+			os_memcpy(sm->pac_opaque_encr_key,
+				  conf->pac_opaque_encr_key, 16);
+		}
+	}
+	if (conf->eap_fast_a_id) {
+		sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
+		if (sm->eap_fast_a_id) {
+			os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
+				  conf->eap_fast_a_id_len);
+			sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
+		}
+	}
+	if (conf->eap_fast_a_id_info)
+		sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
+	sm->eap_fast_prov = conf->eap_fast_prov;
+	sm->pac_key_lifetime = conf->pac_key_lifetime;
+	sm->pac_key_refresh_time = conf->pac_key_refresh_time;
+	sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	sm->tnc = conf->tnc;
+	sm->wps = conf->wps;
+	if (conf->assoc_wps_ie)
+		sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
+	if (conf->assoc_p2p_ie)
+		sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
+	if (conf->peer_addr)
+		os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
+	sm->fragment_size = conf->fragment_size;
+	sm->pwd_group = conf->pwd_group;
+	sm->pbc_in_m1 = conf->pbc_in_m1;
+
+	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
+
+	return sm;
+}
+
+
+/**
+ * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
+void eap_server_sm_deinit(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
+	if (sm->m && sm->eap_method_priv)
+		sm->m->reset(sm, sm->eap_method_priv);
+	wpabuf_free(sm->eap_if.eapReqData);
+	os_free(sm->eap_if.eapKeyData);
+	wpabuf_free(sm->lastReqData);
+	wpabuf_free(sm->eap_if.eapRespData);
+	os_free(sm->identity);
+	os_free(sm->pac_opaque_encr_key);
+	os_free(sm->eap_fast_a_id);
+	os_free(sm->eap_fast_a_id_info);
+	wpabuf_free(sm->eap_if.aaaEapReqData);
+	wpabuf_free(sm->eap_if.aaaEapRespData);
+	os_free(sm->eap_if.aaaEapKeyData);
+	eap_user_free(sm->user);
+	wpabuf_free(sm->assoc_wps_ie);
+	wpabuf_free(sm->assoc_p2p_ie);
+	os_free(sm);
+}
+
+
+/**
+ * eap_sm_notify_cached - Notify EAP state machine of cached PMK
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ *
+ * This function is called when PMKSA caching is used to skip EAP
+ * authentication.
+ */
+void eap_sm_notify_cached(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	sm->EAP_state = EAP_SUCCESS;
+}
+
+
+/**
+ * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ *
+ * This function is called when data for a pending EAP-Request is received.
+ */
+void eap_sm_pending_cb(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
+	if (sm->method_pending == METHOD_PENDING_WAIT)
+		sm->method_pending = METHOD_PENDING_CONT;
+}
+
+
+/**
+ * eap_sm_method_pending - Query whether EAP method is waiting for pending data
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: 1 if method is waiting for pending data or 0 if not
+ */
+int eap_sm_method_pending(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->method_pending == METHOD_PENDING_WAIT;
+}
+
+
+/**
+ * eap_get_identity - Get the user identity (from EAP-Response/Identity)
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @len: Buffer for returning identity length
+ * Returns: Pointer to the user identity or %NULL if not available
+ */
+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
+{
+	*len = sm->identity_len;
+	return sm->identity;
+}
+
+
+/**
+ * eap_get_interface - Get pointer to EAP-EAPOL interface data
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the EAP-EAPOL interface data
+ */
+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
+{
+	return &sm->eap_if;
+}
+
+
+/**
+ * eap_server_clear_identity - Clear EAP identity information
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ *
+ * This function can be used to clear the EAP identity information in the EAP
+ * server context. This allows the EAP/Identity method to be used again after
+ * EAPOL-Start or EAPOL-Logoff.
+ */
+void eap_server_clear_identity(struct eap_sm *sm)
+{
+	os_free(sm->identity);
+	sm->identity = NULL;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_aka.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_aka.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_aka.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1277 +0,0 @@
-/*
- * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2005-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha256.h"
-#include "crypto/crypto.h"
-#include "eap_common/eap_sim_common.h"
-#include "eap_server/eap_i.h"
-#include "eap_server/eap_sim_db.h"
-
-
-struct eap_aka_data {
-	u8 mk[EAP_SIM_MK_LEN];
-	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
-	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
-	u8 k_encr[EAP_SIM_K_ENCR_LEN];
-	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
-	u8 msk[EAP_SIM_KEYING_DATA_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 rand[EAP_AKA_RAND_LEN];
-	u8 autn[EAP_AKA_AUTN_LEN];
-	u8 ck[EAP_AKA_CK_LEN];
-	u8 ik[EAP_AKA_IK_LEN];
-	u8 res[EAP_AKA_RES_MAX_LEN];
-	size_t res_len;
-	enum {
-		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
-	} state;
-	char *next_pseudonym;
-	char *next_reauth_id;
-	u16 counter;
-	struct eap_sim_reauth *reauth;
-	int auts_reported; /* whether the current AUTS has been reported to the
-			    * eap_sim_db */
-	u16 notification;
-	int use_result_ind;
-
-	struct wpabuf *id_msgs;
-	int pending_id;
-	u8 eap_method;
-	u8 *network_name;
-	size_t network_name_len;
-	u16 kdf;
-};
-
-
-static void eap_aka_determine_identity(struct eap_sm *sm,
-				       struct eap_aka_data *data,
-				       int before_identity, int after_reauth);
-
-
-static const char * eap_aka_state_txt(int state)
-{
-	switch (state) {
-	case IDENTITY:
-		return "IDENTITY";
-	case CHALLENGE:
-		return "CHALLENGE";
-	case REAUTH:
-		return "REAUTH";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	case NOTIFICATION:
-		return "NOTIFICATION";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_aka_state(struct eap_aka_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
-		   eap_aka_state_txt(data->state),
-		   eap_aka_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_aka_init(struct eap_sm *sm)
-{
-	struct eap_aka_data *data;
-
-	if (sm->eap_sim_db_priv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	data->eap_method = EAP_TYPE_AKA;
-
-	data->state = IDENTITY;
-	eap_aka_determine_identity(sm, data, 1, 0);
-	data->pending_id = -1;
-
-	return data;
-}
-
-
-#ifdef EAP_SERVER_AKA_PRIME
-static void * eap_aka_prime_init(struct eap_sm *sm)
-{
-	struct eap_aka_data *data;
-	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
-	char *network_name = "WLAN";
-
-	if (sm->eap_sim_db_priv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	data->eap_method = EAP_TYPE_AKA_PRIME;
-	data->network_name = os_malloc(os_strlen(network_name));
-	if (data->network_name == NULL) {
-		os_free(data);
-		return NULL;
-	}
-
-	data->network_name_len = os_strlen(network_name);
-	os_memcpy(data->network_name, network_name, data->network_name_len);
-
-	data->state = IDENTITY;
-	eap_aka_determine_identity(sm, data, 1, 0);
-	data->pending_id = -1;
-
-	return data;
-}
-#endif /* EAP_SERVER_AKA_PRIME */
-
-
-static void eap_aka_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	os_free(data->next_pseudonym);
-	os_free(data->next_reauth_id);
-	wpabuf_free(data->id_msgs);
-	os_free(data->network_name);
-	os_free(data);
-}
-
-
-static int eap_aka_add_id_msg(struct eap_aka_data *data,
-			      const struct wpabuf *msg)
-{
-	if (msg == NULL)
-		return -1;
-
-	if (data->id_msgs == NULL) {
-		data->id_msgs = wpabuf_dup(msg);
-		return data->id_msgs == NULL ? -1 : 0;
-	}
-
-	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
-		return -1;
-	wpabuf_put_buf(data->id_msgs, msg);
-
-	return 0;
-}
-
-
-static void eap_aka_add_checkcode(struct eap_aka_data *data,
-				  struct eap_sim_msg *msg)
-{
-	const u8 *addr;
-	size_t len;
-	u8 hash[SHA256_MAC_LEN];
-
-	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
-
-	if (data->id_msgs == NULL) {
-		/*
-		 * No EAP-AKA/Identity packets were exchanged - send empty
-		 * checkcode.
-		 */
-		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
-		return;
-	}
-
-	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
-	addr = wpabuf_head(data->id_msgs);
-	len = wpabuf_len(data->id_msgs);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		sha256_vector(1, &addr, &len, hash);
-	else
-		sha1_vector(1, &addr, &len, hash);
-
-	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
-			data->eap_method == EAP_TYPE_AKA_PRIME ?
-			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
-}
-
-
-static int eap_aka_verify_checkcode(struct eap_aka_data *data,
-				    const u8 *checkcode, size_t checkcode_len)
-{
-	const u8 *addr;
-	size_t len;
-	u8 hash[SHA256_MAC_LEN];
-	size_t hash_len;
-
-	if (checkcode == NULL)
-		return -1;
-
-	if (data->id_msgs == NULL) {
-		if (checkcode_len != 0) {
-			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
-				   "indicates that AKA/Identity messages were "
-				   "used, but they were not");
-			return -1;
-		}
-		return 0;
-	}
-
-	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
-		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
-
-	if (checkcode_len != hash_len) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
-			   "that AKA/Identity message were not used, but they "
-			   "were");
-		return -1;
-	}
-
-	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
-	addr = wpabuf_head(data->id_msgs);
-	len = wpabuf_len(data->id_msgs);
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		sha256_vector(1, &addr, &len, hash);
-	else
-		sha1_vector(1, &addr, &len, hash);
-
-	if (os_memcmp(hash, checkcode, hash_len) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
-					      struct eap_aka_data *data, u8 id)
-{
-	struct eap_sim_msg *msg;
-	struct wpabuf *buf;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_IDENTITY);
-	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
-				      sm->identity_len)) {
-		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
-		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
-	} else {
-		/*
-		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
-		 * ignored and the AKA/Identity is used to request the
-		 * identity.
-		 */
-		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
-		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
-	}
-	buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
-	if (eap_aka_add_id_msg(data, buf) < 0) {
-		wpabuf_free(buf);
-		return NULL;
-	}
-	data->pending_id = id;
-	return buf;
-}
-
-
-static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
-			      struct eap_sim_msg *msg, u16 counter,
-			      const u8 *nonce_s)
-{
-	os_free(data->next_pseudonym);
-	data->next_pseudonym =
-		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
-	os_free(data->next_reauth_id);
-	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
-		data->next_reauth_id =
-			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
-			   "count exceeded - force full authentication");
-		data->next_reauth_id = NULL;
-	}
-
-	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
-	    counter == 0 && nonce_s == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "   AT_IV");
-	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
-
-	if (counter > 0) {
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
-	}
-
-	if (nonce_s) {
-		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
-		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
-				EAP_SIM_NONCE_S_LEN);
-	}
-
-	if (data->next_pseudonym) {
-		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
-			   data->next_pseudonym);
-		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
-				os_strlen(data->next_pseudonym),
-				(u8 *) data->next_pseudonym,
-				os_strlen(data->next_pseudonym));
-	}
-
-	if (data->next_reauth_id) {
-		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
-			   data->next_reauth_id);
-		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
-				os_strlen(data->next_reauth_id),
-				(u8 *) data->next_reauth_id,
-				os_strlen(data->next_reauth_id));
-	}
-
-	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
-			   "AT_ENCR_DATA");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
-					       struct eap_aka_data *data,
-					       u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_CHALLENGE);
-	wpa_printf(MSG_DEBUG, "   AT_RAND");
-	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
-	wpa_printf(MSG_DEBUG, "   AT_AUTN");
-	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		if (data->kdf) {
-			/* Add the selected KDF into the beginning */
-			wpa_printf(MSG_DEBUG, "   AT_KDF");
-			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
-					NULL, 0);
-		}
-		wpa_printf(MSG_DEBUG, "   AT_KDF");
-		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
-				NULL, 0);
-		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
-		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
-				data->network_name_len,
-				data->network_name, data->network_name_len);
-	}
-
-	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-
-	eap_aka_add_checkcode(data, msg);
-
-	if (sm->eap_sim_aka_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-
-#ifdef EAP_SERVER_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA) {
-		u16 flags = 0;
-		int i;
-		int aka_prime_preferred = 0;
-
-		i = 0;
-		while (sm->user && i < EAP_MAX_METHODS &&
-		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-			sm->user->methods[i].method != EAP_TYPE_NONE)) {
-			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
-				if (sm->user->methods[i].method ==
-				    EAP_TYPE_AKA)
-					break;
-				if (sm->user->methods[i].method ==
-				    EAP_TYPE_AKA_PRIME) {
-					aka_prime_preferred = 1;
-					break;
-				}
-			}
-			i++;
-		}
-
-		if (aka_prime_preferred)
-			flags |= EAP_AKA_BIDDING_FLAG_D;
-		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
-	}
-#endif /* EAP_SERVER_AKA_PRIME */
-
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
-					    struct eap_aka_data *data, u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
-
-	if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
-		return NULL;
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
-			data->nonce_s, EAP_SIM_NONCE_S_LEN);
-
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
-						 sm->identity,
-						 sm->identity_len,
-						 data->nonce_s,
-						 data->msk, data->emsk);
-	} else {
-		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
-				    data->msk, data->emsk);
-		eap_sim_derive_keys_reauth(data->counter, sm->identity,
-					   sm->identity_len, data->nonce_s,
-					   data->mk, data->msk, data->emsk);
-	}
-
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
-
-	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-
-	eap_aka_add_checkcode(data, msg);
-
-	if (sm->eap_sim_aka_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
-						  struct eap_aka_data *data,
-						  u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
-			       EAP_AKA_SUBTYPE_NOTIFICATION);
-	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
-	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
-			NULL, 0);
-	if (data->use_result_ind) {
-		if (data->reauth) {
-			wpa_printf(MSG_DEBUG, "   AT_IV");
-			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
-						   EAP_SIM_AT_ENCR_DATA);
-			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
-				   data->counter);
-			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
-					NULL, 0);
-
-			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
-						     EAP_SIM_AT_PADDING)) {
-				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
-					   "encrypt AT_ENCR_DATA");
-				eap_sim_msg_free(msg);
-				return NULL;
-			}
-		}
-
-		wpa_printf(MSG_DEBUG, "   AT_MAC");
-		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	}
-	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
-}
-
-
-static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_aka_data *data = priv;
-
-	data->auts_reported = 0;
-	switch (data->state) {
-	case IDENTITY:
-		return eap_aka_build_identity(sm, data, id);
-	case CHALLENGE:
-		return eap_aka_build_challenge(sm, data, id);
-	case REAUTH:
-		return eap_aka_build_reauth(sm, data, id);
-	case NOTIFICATION:
-		return eap_aka_build_notification(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
-			   "buildReq", data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_aka_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
-			       &len);
-	if (pos == NULL || len < 3) {
-		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
-{
-	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
-	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
-		return FALSE;
-
-	switch (data->state) {
-	case IDENTITY:
-		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
-			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case CHALLENGE:
-		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
-		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
-			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case REAUTH:
-		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
-			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case NOTIFICATION:
-		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
-			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
-			   "processing a response", data->state);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_aka_determine_identity(struct eap_sm *sm,
-				       struct eap_aka_data *data,
-				       int before_identity, int after_reauth)
-{
-	const u8 *identity;
-	size_t identity_len;
-	int res;
-
-	identity = NULL;
-	identity_len = 0;
-
-	if (after_reauth && data->reauth) {
-		identity = data->reauth->identity;
-		identity_len = data->reauth->identity_len;
-	} else if (sm->identity && sm->identity_len > 0 &&
-		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	} else {
-		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
-						    sm->identity,
-						    sm->identity_len,
-						    &identity_len);
-		if (identity == NULL) {
-			data->reauth = eap_sim_db_get_reauth_entry(
-				sm->eap_sim_db_priv, sm->identity,
-				sm->identity_len);
-			if (data->reauth &&
-			    data->reauth->aka_prime !=
-			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
-				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
-					   "was for different AKA version");
-				data->reauth = NULL;
-			}
-			if (data->reauth) {
-				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
-					   "re-authentication");
-				identity = data->reauth->identity;
-				identity_len = data->reauth->identity_len;
-				data->counter = data->reauth->counter;
-				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-					os_memcpy(data->k_encr,
-						  data->reauth->k_encr,
-						  EAP_SIM_K_ENCR_LEN);
-					os_memcpy(data->k_aut,
-						  data->reauth->k_aut,
-						  EAP_AKA_PRIME_K_AUT_LEN);
-					os_memcpy(data->k_re,
-						  data->reauth->k_re,
-						  EAP_AKA_PRIME_K_RE_LEN);
-				} else {
-					os_memcpy(data->mk, data->reauth->mk,
-						  EAP_SIM_MK_LEN);
-				}
-			}
-		}
-	}
-
-	if (identity == NULL ||
-	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
-				      sm->identity_len) < 0) {
-		if (before_identity) {
-			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
-				   "not known - send AKA-Identity request");
-			eap_aka_state(data, IDENTITY);
-			return;
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
-				   "permanent user name is known; try to use "
-				   "it");
-			/* eap_sim_db_get_aka_auth() will report failure, if
-			 * this identity is not known. */
-		}
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
-			  identity, identity_len);
-
-	if (!after_reauth && data->reauth) {
-		eap_aka_state(data, REAUTH);
-		return;
-	}
-
-	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
-				      identity_len, data->rand, data->autn,
-				      data->ik, data->ck, data->res,
-				      &data->res_len, sm);
-	if (res == EAP_SIM_DB_PENDING) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
-			   "not yet available - pending request");
-		sm->method_pending = METHOD_PENDING_WAIT;
-		return;
-	}
-
-#ifdef EAP_SERVER_AKA_PRIME
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
-		 * needed 6-octet SQN ^AK for CK',IK' derivation */
-		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
-						 data->autn,
-						 data->network_name,
-						 data->network_name_len);
-	}
-#endif /* EAP_SERVER_AKA_PRIME */
-
-	data->reauth = NULL;
-	data->counter = 0; /* reset re-auth counter since this is full auth */
-
-	if (res != 0) {
-		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
-			   "authentication data for the peer");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-	if (sm->method_pending == METHOD_PENDING_WAIT) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
-			   "available - abort pending wait");
-		sm->method_pending = METHOD_PENDING_NONE;
-	}
-
-	identity_len = sm->identity_len;
-	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
-			   "character from identity");
-		identity_len--;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
-			  sm->identity, identity_len);
-
-	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
-					  data->ck, data->k_encr, data->k_aut,
-					  data->k_re, data->msk, data->emsk);
-	} else {
-		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
-				  data->ck, data->mk);
-		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
-				    data->msk, data->emsk);
-	}
-
-	eap_aka_state(data, CHALLENGE);
-}
-
-
-static void eap_aka_process_identity(struct eap_sm *sm,
-				     struct eap_aka_data *data,
-				     struct wpabuf *respData,
-				     struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
-
-	if (attr->mac || attr->iv || attr->encr_data) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
-			   "received in EAP-Response/AKA-Identity");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	if (attr->identity) {
-		os_free(sm->identity);
-		sm->identity = os_malloc(attr->identity_len);
-		if (sm->identity) {
-			os_memcpy(sm->identity, attr->identity,
-				  attr->identity_len);
-			sm->identity_len = attr->identity_len;
-		}
-	}
-
-	eap_aka_determine_identity(sm, data, 0, 0);
-	if (eap_get_id(respData) == data->pending_id) {
-		data->pending_id = -1;
-		eap_aka_add_id_msg(data, respData);
-	}
-}
-
-
-static int eap_aka_verify_mac(struct eap_aka_data *data,
-			      const struct wpabuf *req,
-			      const u8 *mac, const u8 *extra,
-			      size_t extra_len)
-{
-	if (data->eap_method == EAP_TYPE_AKA_PRIME)
-		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
-						 extra_len);
-	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
-}
-
-
-static void eap_aka_process_challenge(struct eap_sm *sm,
-				      struct eap_aka_data *data,
-				      struct wpabuf *respData,
-				      struct eap_sim_attrs *attr)
-{
-	const u8 *identity;
-	size_t identity_len;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
-
-#ifdef EAP_SERVER_AKA_PRIME
-#if 0
-	/* KDF negotiation; to be enabled only after more than one KDF is
-	 * supported */
-	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
-	    attr->kdf_count == 1 && attr->mac == NULL) {
-		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
-			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
-				   "unknown KDF");
-			data->notification =
-				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-			eap_aka_state(data, NOTIFICATION);
-			return;
-		}
-
-		data->kdf = attr->kdf[0];
-
-		/* Allow negotiation to continue with the selected KDF by
-		 * sending another Challenge message */
-		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
-		return;
-	}
-#endif
-#endif /* EAP_SERVER_AKA_PRIME */
-
-	if (attr->checkcode &&
-	    eap_aka_verify_checkcode(data, attr->checkcode,
-				     attr->checkcode_len)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
-			   "message");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-	if (attr->mac == NULL ||
-	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
-			   "did not include valid AT_MAC");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	/*
-	 * AT_RES is padded, so verify that there is enough room for RES and
-	 * that the RES length in bits matches with the expected RES.
-	 */
-	if (attr->res == NULL || attr->res_len < data->res_len ||
-	    attr->res_len_bits != data->res_len * 8 ||
-	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
-			   "include valid AT_RES (attr len=%lu, res len=%lu "
-			   "bits, expected %lu bits)",
-			   (unsigned long) attr->res_len,
-			   (unsigned long) attr->res_len_bits,
-			   (unsigned long) data->res_len * 8);
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
-		   "correct AT_MAC");
-	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
-		data->use_result_ind = 1;
-		data->notification = EAP_SIM_SUCCESS;
-		eap_aka_state(data, NOTIFICATION);
-	} else
-		eap_aka_state(data, SUCCESS);
-
-	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
-					    sm->identity_len, &identity_len);
-	if (identity == NULL) {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	}
-
-	if (data->next_pseudonym) {
-		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-					 identity_len,
-					 data->next_pseudonym);
-		data->next_pseudonym = NULL;
-	}
-	if (data->next_reauth_id) {
-		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-#ifdef EAP_SERVER_AKA_PRIME
-			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
-						    identity,
-						    identity_len,
-						    data->next_reauth_id,
-						    data->counter + 1,
-						    data->k_encr, data->k_aut,
-						    data->k_re);
-#endif /* EAP_SERVER_AKA_PRIME */
-		} else {
-			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-					      identity_len,
-					      data->next_reauth_id,
-					      data->counter + 1,
-					      data->mk);
-		}
-		data->next_reauth_id = NULL;
-	}
-}
-
-
-static void eap_aka_process_sync_failure(struct eap_sm *sm,
-					 struct eap_aka_data *data,
-					 struct wpabuf *respData,
-					 struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
-
-	if (attr->auts == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
-			   "message did not include valid AT_AUTS");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	/* Avoid re-reporting AUTS when processing pending EAP packet by
-	 * maintaining a local flag stating whether this AUTS has already been
-	 * reported. */
-	if (!data->auts_reported &&
-	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
-				     sm->identity_len, attr->auts,
-				     data->rand)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-	data->auts_reported = 1;
-
-	/* Try again after resynchronization */
-	eap_aka_determine_identity(sm, data, 0, 0);
-}
-
-
-static void eap_aka_process_reauth(struct eap_sm *sm,
-				   struct eap_aka_data *data,
-				   struct wpabuf *respData,
-				   struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted = NULL;
-	const u8 *identity, *id2;
-	size_t identity_len, id2_len;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
-
-	if (attr->mac == NULL ||
-	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
-			       EAP_SIM_NONCE_S_LEN)) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
-			   "did not include valid AT_MAC");
-		goto fail;
-	}
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
-			   "message did not include encrypted data");
-		goto fail;
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
-			   "data from reauthentication message");
-		goto fail;
-	}
-
-	if (eattr.counter != data->counter) {
-		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
-			   "used incorrect counter %u, expected %u",
-			   eattr.counter, data->counter);
-		goto fail;
-	}
-	os_free(decrypted);
-	decrypted = NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
-		   "the correct AT_MAC");
-
-	if (eattr.counter_too_small) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
-			   "included AT_COUNTER_TOO_SMALL - starting full "
-			   "authentication");
-		eap_aka_determine_identity(sm, data, 0, 1);
-		return;
-	}
-
-	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
-		data->use_result_ind = 1;
-		data->notification = EAP_SIM_SUCCESS;
-		eap_aka_state(data, NOTIFICATION);
-	} else
-		eap_aka_state(data, SUCCESS);
-
-	if (data->reauth) {
-		identity = data->reauth->identity;
-		identity_len = data->reauth->identity_len;
-	} else {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	}
-
-	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
-				       identity_len, &id2_len);
-	if (id2) {
-		identity = id2;
-		identity_len = id2_len;
-	}
-
-	if (data->next_pseudonym) {
-		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-					 identity_len, data->next_pseudonym);
-		data->next_pseudonym = NULL;
-	}
-	if (data->next_reauth_id) {
-		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
-#ifdef EAP_SERVER_AKA_PRIME
-			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
-						    identity,
-						    identity_len,
-						    data->next_reauth_id,
-						    data->counter + 1,
-						    data->k_encr, data->k_aut,
-						    data->k_re);
-#endif /* EAP_SERVER_AKA_PRIME */
-		} else {
-			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-					      identity_len,
-					      data->next_reauth_id,
-					      data->counter + 1,
-					      data->mk);
-		}
-		data->next_reauth_id = NULL;
-	} else {
-		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
-		data->reauth = NULL;
-	}
-
-	return;
-
-fail:
-	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-	eap_aka_state(data, NOTIFICATION);
-	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
-	data->reauth = NULL;
-	os_free(decrypted);
-}
-
-
-static void eap_aka_process_client_error(struct eap_sm *sm,
-					 struct eap_aka_data *data,
-					 struct wpabuf *respData,
-					 struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
-		   attr->client_error_code);
-	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
-		eap_aka_state(data, SUCCESS);
-	else
-		eap_aka_state(data, FAILURE);
-}
-
-
-static void eap_aka_process_authentication_reject(
-	struct eap_sm *sm, struct eap_aka_data *data,
-	struct wpabuf *respData, struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
-	eap_aka_state(data, FAILURE);
-}
-
-
-static void eap_aka_process_notification(struct eap_sm *sm,
-					 struct eap_aka_data *data,
-					 struct wpabuf *respData,
-					 struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
-	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
-		eap_aka_state(data, SUCCESS);
-	else
-		eap_aka_state(data, FAILURE);
-}
-
-
-static void eap_aka_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_aka_data *data = priv;
-	const u8 *pos, *end;
-	u8 subtype;
-	size_t len;
-	struct eap_sim_attrs attr;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
-			       &len);
-	if (pos == NULL || len < 3)
-		return;
-
-	end = pos + len;
-	subtype = *pos;
-	pos += 3;
-
-	if (eap_aka_subtype_ok(data, subtype)) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
-			   "EAP-AKA Subtype in EAP Response");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	if (eap_sim_parse_attr(pos, end, &attr,
-			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
-			       0)) {
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
-		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
-		eap_aka_state(data, NOTIFICATION);
-		return;
-	}
-
-	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
-		eap_aka_process_client_error(sm, data, respData, &attr);
-		return;
-	}
-
-	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
-		eap_aka_process_authentication_reject(sm, data, respData,
-						      &attr);
-		return;
-	}
-
-	switch (data->state) {
-	case IDENTITY:
-		eap_aka_process_identity(sm, data, respData, &attr);
-		break;
-	case CHALLENGE:
-		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
-			eap_aka_process_sync_failure(sm, data, respData,
-						     &attr);
-		} else {
-			eap_aka_process_challenge(sm, data, respData, &attr);
-		}
-		break;
-	case REAUTH:
-		eap_aka_process_reauth(sm, data, respData, &attr);
-		break;
-	case NOTIFICATION:
-		eap_aka_process_notification(sm, data, respData, &attr);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
-			   "process", data->state);
-		break;
-	}
-}
-
-
-static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_aka_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
-	*len = EAP_SIM_KEYING_DATA_LEN;
-	return key;
-}
-
-
-static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_aka_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-	return key;
-}
-
-
-static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_aka_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_aka_init;
-	eap->reset = eap_aka_reset;
-	eap->buildReq = eap_aka_buildReq;
-	eap->check = eap_aka_check;
-	eap->process = eap_aka_process;
-	eap->isDone = eap_aka_isDone;
-	eap->getKey = eap_aka_getKey;
-	eap->isSuccess = eap_aka_isSuccess;
-	eap->get_emsk = eap_aka_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}
-
-
-#ifdef EAP_SERVER_AKA_PRIME
-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,
-				      "AKA'");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_aka_prime_init;
-	eap->reset = eap_aka_reset;
-	eap->buildReq = eap_aka_buildReq;
-	eap->check = eap_aka_check;
-	eap->process = eap_aka_process;
-	eap->isDone = eap_aka_isDone;
-	eap->getKey = eap_aka_getKey;
-	eap->isSuccess = eap_aka_isSuccess;
-	eap->get_emsk = eap_aka_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-
-	return ret;
-}
-#endif /* EAP_SERVER_AKA_PRIME */

Copied: vendor/wpa/2.0/src/eap_server/eap_server_aka.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_aka.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_aka.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_aka.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1351 @@
+/*
+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2005-2012, Jouni Malinen <j at 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/sha256.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "eap_common/eap_sim_common.h"
+#include "eap_server/eap_i.h"
+#include "eap_server/eap_sim_db.h"
+
+
+struct eap_aka_data {
+	u8 mk[EAP_SIM_MK_LEN];
+	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
+	u8 msk[EAP_SIM_KEYING_DATA_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 rand[EAP_AKA_RAND_LEN];
+	u8 autn[EAP_AKA_AUTN_LEN];
+	u8 ck[EAP_AKA_CK_LEN];
+	u8 ik[EAP_AKA_IK_LEN];
+	u8 res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	enum {
+		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
+	} state;
+	char *next_pseudonym;
+	char *next_reauth_id;
+	u16 counter;
+	struct eap_sim_reauth *reauth;
+	int auts_reported; /* whether the current AUTS has been reported to the
+			    * eap_sim_db */
+	u16 notification;
+	int use_result_ind;
+
+	struct wpabuf *id_msgs;
+	int pending_id;
+	u8 eap_method;
+	u8 *network_name;
+	size_t network_name_len;
+	u16 kdf;
+	int identity_round;
+	char permanent[20]; /* Permanent username */
+};
+
+
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
+
+
+static const char * eap_aka_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case REAUTH:
+		return "REAUTH";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	case NOTIFICATION:
+		return "NOTIFICATION";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_aka_state(struct eap_aka_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
+		   eap_aka_state_txt(data->state),
+		   eap_aka_state_txt(state));
+	data->state = state;
+}
+
+
+static int eap_aka_check_identity_reauth(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 const char *username)
+{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
+	    username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
+		return 0;
+	if (data->eap_method == EAP_TYPE_AKA &&
+	    username[0] != EAP_AKA_REAUTH_ID_PREFIX)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
+	data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+						   username);
+	if (data->reauth == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
+			   "request full auth identity");
+		/* Remain in IDENTITY state for another round */
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
+	os_strlcpy(data->permanent, data->reauth->permanent,
+		   sizeof(data->permanent));
+	data->counter = data->reauth->counter;
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		os_memcpy(data->k_encr, data->reauth->k_encr,
+			  EAP_SIM_K_ENCR_LEN);
+		os_memcpy(data->k_aut, data->reauth->k_aut,
+			  EAP_AKA_PRIME_K_AUT_LEN);
+		os_memcpy(data->k_re, data->reauth->k_re,
+			  EAP_AKA_PRIME_K_RE_LEN);
+	} else {
+		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
+	}
+
+	eap_aka_state(data, REAUTH);
+	return 1;
+}
+
+
+static void eap_aka_check_identity(struct eap_sm *sm,
+				   struct eap_aka_data *data)
+{
+	char *username;
+
+	/* Check if we already know the identity from EAP-Response/Identity */
+
+	username = sim_get_username(sm->identity, sm->identity_len);
+	if (username == NULL)
+		return;
+
+	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+		os_free(username);
+		/*
+		 * Since re-auth username was recognized, skip AKA/Identity
+		 * exchange.
+		 */
+		return;
+	}
+
+	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+	    (data->eap_method == EAP_TYPE_AKA &&
+	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+		const char *permanent;
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+			   username);
+		permanent = eap_sim_db_get_permanent(
+			sm->eap_sim_db_priv, username);
+		if (permanent == NULL) {
+			os_free(username);
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+				   "identity - request permanent identity");
+			/* Remain in IDENTITY state for another round */
+			return;
+		}
+		os_strlcpy(data->permanent, permanent,
+			   sizeof(data->permanent));
+		/*
+		 * Since pseudonym username was recognized, skip AKA/Identity
+		 * exchange.
+		 */
+		eap_aka_fullauth(sm, data);
+	}
+
+	os_free(username);
+}
+
+
+static void * eap_aka_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data;
+
+	if (sm->eap_sim_db_priv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->eap_method = EAP_TYPE_AKA;
+
+	data->state = IDENTITY;
+	data->pending_id = -1;
+	eap_aka_check_identity(sm, data);
+
+	return data;
+}
+
+
+#ifdef EAP_SERVER_AKA_PRIME
+static void * eap_aka_prime_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data;
+	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
+	char *network_name = "WLAN";
+
+	if (sm->eap_sim_db_priv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->eap_method = EAP_TYPE_AKA_PRIME;
+	data->network_name = (u8 *) os_strdup(network_name);
+	if (data->network_name == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	data->network_name_len = os_strlen(network_name);
+
+	data->state = IDENTITY;
+	data->pending_id = -1;
+	eap_aka_check_identity(sm, data);
+
+	return data;
+}
+#endif /* EAP_SERVER_AKA_PRIME */
+
+
+static void eap_aka_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	os_free(data->next_pseudonym);
+	os_free(data->next_reauth_id);
+	wpabuf_free(data->id_msgs);
+	os_free(data->network_name);
+	os_free(data);
+}
+
+
+static int eap_aka_add_id_msg(struct eap_aka_data *data,
+			      const struct wpabuf *msg)
+{
+	if (msg == NULL)
+		return -1;
+
+	if (data->id_msgs == NULL) {
+		data->id_msgs = wpabuf_dup(msg);
+		return data->id_msgs == NULL ? -1 : 0;
+	}
+
+	if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
+		return -1;
+	wpabuf_put_buf(data->id_msgs, msg);
+
+	return 0;
+}
+
+
+static void eap_aka_add_checkcode(struct eap_aka_data *data,
+				  struct eap_sim_msg *msg)
+{
+	const u8 *addr;
+	size_t len;
+	u8 hash[SHA256_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
+
+	if (data->id_msgs == NULL) {
+		/*
+		 * No EAP-AKA/Identity packets were exchanged - send empty
+		 * checkcode.
+		 */
+		eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
+		return;
+	}
+
+	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
+	addr = wpabuf_head(data->id_msgs);
+	len = wpabuf_len(data->id_msgs);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+		sha1_vector(1, &addr, &len, hash);
+
+	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
+			data->eap_method == EAP_TYPE_AKA_PRIME ?
+			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
+}
+
+
+static int eap_aka_verify_checkcode(struct eap_aka_data *data,
+				    const u8 *checkcode, size_t checkcode_len)
+{
+	const u8 *addr;
+	size_t len;
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
+
+	if (checkcode == NULL)
+		return -1;
+
+	if (data->id_msgs == NULL) {
+		if (checkcode_len != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
+				   "indicates that AKA/Identity messages were "
+				   "used, but they were not");
+			return -1;
+		}
+		return 0;
+	}
+
+	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
+		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
+
+	if (checkcode_len != hash_len) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
+			   "that AKA/Identity message were not used, but they "
+			   "were");
+		return -1;
+	}
+
+	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
+	addr = wpabuf_head(data->id_msgs);
+	len = wpabuf_len(data->id_msgs);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+		sha1_vector(1, &addr, &len, hash);
+
+	if (os_memcmp(hash, checkcode, hash_len) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
+					      struct eap_aka_data *data, u8 id)
+{
+	struct eap_sim_msg *msg;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_IDENTITY);
+	data->identity_round++;
+	if (data->identity_round == 1) {
+		/*
+		 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
+		 * ignored and the AKA/Identity is used to request the
+		 * identity.
+		 */
+		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+	} else if (data->identity_round > 3) {
+		/* Cannot use more than three rounds of Identity messages */
+		eap_sim_msg_free(msg);
+		return NULL;
+	} else if (sm->identity && sm->identity_len > 0 &&
+		   (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+		    sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
+		/* Reauth id may have expired - try fullauth */
+		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+	} else {
+		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+	}
+	buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
+	if (eap_aka_add_id_msg(data, buf) < 0) {
+		wpabuf_free(buf);
+		return NULL;
+	}
+	data->pending_id = id;
+	return buf;
+}
+
+
+static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
+			      struct eap_sim_msg *msg, u16 counter,
+			      const u8 *nonce_s)
+{
+	os_free(data->next_pseudonym);
+	if (nonce_s == NULL) {
+		data->next_pseudonym =
+			eap_sim_db_get_next_pseudonym(
+				sm->eap_sim_db_priv,
+				data->eap_method == EAP_TYPE_AKA_PRIME ?
+				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
+	} else {
+		/* Do not update pseudonym during re-authentication */
+		data->next_pseudonym = NULL;
+	}
+	os_free(data->next_reauth_id);
+	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+		data->next_reauth_id =
+			eap_sim_db_get_next_reauth_id(
+				sm->eap_sim_db_priv,
+				data->eap_method == EAP_TYPE_AKA_PRIME ?
+				EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
+			   "count exceeded - force full authentication");
+		data->next_reauth_id = NULL;
+	}
+
+	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+	    counter == 0 && nonce_s == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter > 0) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+	}
+
+	if (nonce_s) {
+		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
+		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+				EAP_SIM_NONCE_S_LEN);
+	}
+
+	if (data->next_pseudonym) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
+			   data->next_pseudonym);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+				os_strlen(data->next_pseudonym),
+				(u8 *) data->next_pseudonym,
+				os_strlen(data->next_pseudonym));
+	}
+
+	if (data->next_reauth_id) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
+			   data->next_reauth_id);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+				os_strlen(data->next_reauth_id),
+				(u8 *) data->next_reauth_id,
+				os_strlen(data->next_reauth_id));
+	}
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
+					       struct eap_aka_data *data,
+					       u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_RAND");
+	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
+	wpa_printf(MSG_DEBUG, "   AT_AUTN");
+	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		if (data->kdf) {
+			/* Add the selected KDF into the beginning */
+			wpa_printf(MSG_DEBUG, "   AT_KDF");
+			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
+					NULL, 0);
+		}
+		wpa_printf(MSG_DEBUG, "   AT_KDF");
+		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
+				NULL, 0);
+		wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
+		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
+				data->network_name_len,
+				data->network_name, data->network_name_len);
+	}
+
+	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	eap_aka_add_checkcode(data, msg);
+
+	if (sm->eap_sim_aka_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA) {
+		u16 flags = 0;
+		int i;
+		int aka_prime_preferred = 0;
+
+		i = 0;
+		while (sm->user && i < EAP_MAX_METHODS &&
+		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+			sm->user->methods[i].method != EAP_TYPE_NONE)) {
+			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
+				if (sm->user->methods[i].method ==
+				    EAP_TYPE_AKA)
+					break;
+				if (sm->user->methods[i].method ==
+				    EAP_TYPE_AKA_PRIME) {
+					aka_prime_preferred = 1;
+					break;
+				}
+			}
+			i++;
+		}
+
+		if (aka_prime_preferred)
+			flags |= EAP_AKA_BIDDING_FLAG_D;
+		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
+	}
+#endif /* EAP_SERVER_AKA_PRIME */
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
+					    struct eap_aka_data *data, u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
+
+	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+		return NULL;
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
+			data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
+						 sm->identity,
+						 sm->identity_len,
+						 data->nonce_s,
+						 data->msk, data->emsk);
+	} else {
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+		eap_sim_derive_keys_reauth(data->counter, sm->identity,
+					   sm->identity_len, data->nonce_s,
+					   data->mk, data->msk, data->emsk);
+	}
+
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
+
+	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	eap_aka_add_checkcode(data, msg);
+
+	if (sm->eap_sim_aka_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
+						  struct eap_aka_data *data,
+						  u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_NOTIFICATION);
+	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
+	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
+			NULL, 0);
+	if (data->use_result_ind) {
+		if (data->reauth) {
+			wpa_printf(MSG_DEBUG, "   AT_IV");
+			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+						   EAP_SIM_AT_ENCR_DATA);
+			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
+				   data->counter);
+			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+					NULL, 0);
+
+			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+						     EAP_SIM_AT_PADDING)) {
+				wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
+					   "encrypt AT_ENCR_DATA");
+				eap_sim_msg_free(msg);
+				return NULL;
+			}
+		}
+
+		wpa_printf(MSG_DEBUG, "   AT_MAC");
+		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	}
+	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_aka_data *data = priv;
+
+	data->auts_reported = 0;
+	switch (data->state) {
+	case IDENTITY:
+		return eap_aka_build_identity(sm, data, id);
+	case CHALLENGE:
+		return eap_aka_build_challenge(sm, data, id);
+	case REAUTH:
+		return eap_aka_build_reauth(sm, data, id);
+	case NOTIFICATION:
+		return eap_aka_build_notification(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+			   "buildReq", data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_aka_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
+			       &len);
+	if (pos == NULL || len < 3) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
+{
+	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
+	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
+		return FALSE;
+
+	switch (data->state) {
+	case IDENTITY:
+		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case CHALLENGE:
+		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
+		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case REAUTH:
+		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case NOTIFICATION:
+		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
+			   "processing a response", data->state);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_aka_determine_identity(struct eap_sm *sm,
+				       struct eap_aka_data *data)
+{
+	char *username;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
+			  sm->identity, sm->identity_len);
+
+	username = sim_get_username(sm->identity, sm->identity_len);
+	if (username == NULL) {
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+		os_free(username);
+		return;
+	}
+
+	if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
+	      username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
+	     (data->eap_method == EAP_TYPE_AKA &&
+	      username[0] == EAP_AKA_REAUTH_ID_PREFIX)) &&
+	    data->identity_round == 1) {
+		/* Remain in IDENTITY state for another round to request full
+		 * auth identity since we did not recognize reauth id */
+		os_free(username);
+		return;
+	}
+
+	if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+	     username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+	    (data->eap_method == EAP_TYPE_AKA &&
+	     username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+		const char *permanent;
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+			   username);
+		permanent = eap_sim_db_get_permanent(
+			sm->eap_sim_db_priv, username);
+		os_free(username);
+		if (permanent == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+				   "identity - request permanent identity");
+			/* Remain in IDENTITY state for another round */
+			return;
+		}
+		os_strlcpy(data->permanent, permanent,
+			   sizeof(data->permanent));
+	} else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+		    username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+		   (data->eap_method == EAP_TYPE_AKA &&
+		    username[0] == EAP_AKA_PERMANENT_PREFIX)) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
+			   username);
+		os_strlcpy(data->permanent, username, sizeof(data->permanent));
+		os_free(username);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
+			   username);
+		os_free(username);
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	eap_aka_fullauth(sm, data);
+}
+
+
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
+{
+	size_t identity_len;
+	int res;
+
+	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+				      data->rand, data->autn, data->ik,
+				      data->ck, data->res, &data->res_len, sm);
+	if (res == EAP_SIM_DB_PENDING) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+			   "not yet available - pending request");
+		sm->method_pending = METHOD_PENDING_WAIT;
+		return;
+	}
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
+		 * needed 6-octet SQN ^AK for CK',IK' derivation */
+		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
+						 data->autn,
+						 data->network_name,
+						 data->network_name_len);
+	}
+#endif /* EAP_SERVER_AKA_PRIME */
+
+	data->reauth = NULL;
+	data->counter = 0; /* reset re-auth counter since this is full auth */
+
+	if (res != 0) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
+			   "authentication data for the peer");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	if (sm->method_pending == METHOD_PENDING_WAIT) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+			   "available - abort pending wait");
+		sm->method_pending = METHOD_PENDING_NONE;
+	}
+
+	identity_len = sm->identity_len;
+	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
+			   "character from identity");
+		identity_len--;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
+			  sm->identity, identity_len);
+
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
+					  data->ck, data->k_encr, data->k_aut,
+					  data->k_re, data->msk, data->emsk);
+	} else {
+		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
+				  data->ck, data->mk);
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+	}
+
+	eap_aka_state(data, CHALLENGE);
+}
+
+
+static void eap_aka_process_identity(struct eap_sm *sm,
+				     struct eap_aka_data *data,
+				     struct wpabuf *respData,
+				     struct eap_sim_attrs *attr)
+{
+	u8 *new_identity;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
+
+	if (attr->mac || attr->iv || attr->encr_data) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
+			   "received in EAP-Response/AKA-Identity");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	/*
+	 * We always request identity with AKA/Identity, so the peer is
+	 * required to have replied with one.
+	 */
+	if (!attr->identity || attr->identity_len == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
+			   "identity");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	new_identity = os_malloc(attr->identity_len);
+	if (new_identity == NULL) {
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	os_free(sm->identity);
+	sm->identity = new_identity;
+	os_memcpy(sm->identity, attr->identity, attr->identity_len);
+	sm->identity_len = attr->identity_len;
+
+	eap_aka_determine_identity(sm, data);
+	if (eap_get_id(respData) == data->pending_id) {
+		data->pending_id = -1;
+		eap_aka_add_id_msg(data, respData);
+	}
+}
+
+
+static int eap_aka_verify_mac(struct eap_aka_data *data,
+			      const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len)
+{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
+						 extra_len);
+	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
+}
+
+
+static void eap_aka_process_challenge(struct eap_sm *sm,
+				      struct eap_aka_data *data,
+				      struct wpabuf *respData,
+				      struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
+
+#ifdef EAP_SERVER_AKA_PRIME
+#if 0
+	/* KDF negotiation; to be enabled only after more than one KDF is
+	 * supported */
+	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
+	    attr->kdf_count == 1 && attr->mac == NULL) {
+		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
+				   "unknown KDF");
+			data->notification =
+				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+			eap_aka_state(data, NOTIFICATION);
+			return;
+		}
+
+		data->kdf = attr->kdf[0];
+
+		/* Allow negotiation to continue with the selected KDF by
+		 * sending another Challenge message */
+		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
+		return;
+	}
+#endif
+#endif /* EAP_SERVER_AKA_PRIME */
+
+	if (attr->checkcode &&
+	    eap_aka_verify_checkcode(data, attr->checkcode,
+				     attr->checkcode_len)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
+			   "message");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	if (attr->mac == NULL ||
+	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+			   "did not include valid AT_MAC");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	/*
+	 * AT_RES is padded, so verify that there is enough room for RES and
+	 * that the RES length in bits matches with the expected RES.
+	 */
+	if (attr->res == NULL || attr->res_len < data->res_len ||
+	    attr->res_len_bits != data->res_len * 8 ||
+	    os_memcmp(attr->res, data->res, data->res_len) != 0) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
+			   "include valid AT_RES (attr len=%lu, res len=%lu "
+			   "bits, expected %lu bits)",
+			   (unsigned long) attr->res_len,
+			   (unsigned long) attr->res_len_bits,
+			   (unsigned long) data->res_len * 8);
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
+		   "correct AT_MAC");
+	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+		data->use_result_ind = 1;
+		data->notification = EAP_SIM_SUCCESS;
+		eap_aka_state(data, NOTIFICATION);
+	} else
+		eap_aka_state(data, SUCCESS);
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+					 data->next_pseudonym);
+		data->next_pseudonym = NULL;
+	}
+	if (data->next_reauth_id) {
+		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+#ifdef EAP_SERVER_AKA_PRIME
+			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+						    data->permanent,
+						    data->next_reauth_id,
+						    data->counter + 1,
+						    data->k_encr, data->k_aut,
+						    data->k_re);
+#endif /* EAP_SERVER_AKA_PRIME */
+		} else {
+			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+					      data->permanent,
+					      data->next_reauth_id,
+					      data->counter + 1,
+					      data->mk);
+		}
+		data->next_reauth_id = NULL;
+	}
+}
+
+
+static void eap_aka_process_sync_failure(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 struct wpabuf *respData,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
+
+	if (attr->auts == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
+			   "message did not include valid AT_AUTS");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	/* Avoid re-reporting AUTS when processing pending EAP packet by
+	 * maintaining a local flag stating whether this AUTS has already been
+	 * reported. */
+	if (!data->auts_reported &&
+	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+				     attr->auts, data->rand)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	data->auts_reported = 1;
+
+	/* Remain in CHALLENGE state to re-try after resynchronization */
+}
+
+
+static void eap_aka_process_reauth(struct eap_sm *sm,
+				   struct eap_aka_data *data,
+				   struct wpabuf *respData,
+				   struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted = NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
+
+	if (attr->mac == NULL ||
+	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
+			       EAP_SIM_NONCE_S_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
+			   "did not include valid AT_MAC");
+		goto fail;
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+			   "message did not include encrypted data");
+		goto fail;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+			   "data from reauthentication message");
+		goto fail;
+	}
+
+	if (eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
+			   "used incorrect counter %u, expected %u",
+			   eattr.counter, data->counter);
+		goto fail;
+	}
+	os_free(decrypted);
+	decrypted = NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
+		   "the correct AT_MAC");
+
+	if (eattr.counter_too_small) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+			   "included AT_COUNTER_TOO_SMALL - starting full "
+			   "authentication");
+		eap_aka_fullauth(sm, data);
+		return;
+	}
+
+	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+		data->use_result_ind = 1;
+		data->notification = EAP_SIM_SUCCESS;
+		eap_aka_state(data, NOTIFICATION);
+	} else
+		eap_aka_state(data, SUCCESS);
+
+	if (data->next_reauth_id) {
+		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+#ifdef EAP_SERVER_AKA_PRIME
+			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+						    data->permanent,
+						    data->next_reauth_id,
+						    data->counter + 1,
+						    data->k_encr, data->k_aut,
+						    data->k_re);
+#endif /* EAP_SERVER_AKA_PRIME */
+		} else {
+			eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+					      data->permanent,
+					      data->next_reauth_id,
+					      data->counter + 1,
+					      data->mk);
+		}
+		data->next_reauth_id = NULL;
+	} else {
+		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+		data->reauth = NULL;
+	}
+
+	return;
+
+fail:
+	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+	eap_aka_state(data, NOTIFICATION);
+	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+	data->reauth = NULL;
+	os_free(decrypted);
+}
+
+
+static void eap_aka_process_client_error(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 struct wpabuf *respData,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
+		   attr->client_error_code);
+	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
+		eap_aka_state(data, SUCCESS);
+	else
+		eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_authentication_reject(
+	struct eap_sm *sm, struct eap_aka_data *data,
+	struct wpabuf *respData, struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
+	eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_notification(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 struct wpabuf *respData,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
+	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
+		eap_aka_state(data, SUCCESS);
+	else
+		eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_aka_data *data = priv;
+	const u8 *pos, *end;
+	u8 subtype;
+	size_t len;
+	struct eap_sim_attrs attr;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
+			       &len);
+	if (pos == NULL || len < 3)
+		return;
+
+	end = pos + len;
+	subtype = *pos;
+	pos += 3;
+
+	if (eap_aka_subtype_ok(data, subtype)) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
+			   "EAP-AKA Subtype in EAP Response");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (eap_sim_parse_attr(pos, end, &attr,
+			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
+			       0)) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
+		eap_aka_process_client_error(sm, data, respData, &attr);
+		return;
+	}
+
+	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
+		eap_aka_process_authentication_reject(sm, data, respData,
+						      &attr);
+		return;
+	}
+
+	switch (data->state) {
+	case IDENTITY:
+		eap_aka_process_identity(sm, data, respData, &attr);
+		break;
+	case CHALLENGE:
+		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+			eap_aka_process_sync_failure(sm, data, respData,
+						     &attr);
+		} else {
+			eap_aka_process_challenge(sm, data, respData, &attr);
+		}
+		break;
+	case REAUTH:
+		eap_aka_process_reauth(sm, data, respData, &attr);
+		break;
+	case NOTIFICATION:
+		eap_aka_process_notification(sm, data, respData, &attr);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+			   "process", data->state);
+		break;
+	}
+}
+
+
+static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+	*len = EAP_SIM_KEYING_DATA_LEN;
+	return key;
+}
+
+
+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+	return key;
+}
+
+
+static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_init;
+	eap->reset = eap_aka_reset;
+	eap->buildReq = eap_aka_buildReq;
+	eap->check = eap_aka_check;
+	eap->process = eap_aka_process;
+	eap->isDone = eap_aka_isDone;
+	eap->getKey = eap_aka_getKey;
+	eap->isSuccess = eap_aka_isSuccess;
+	eap->get_emsk = eap_aka_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
+
+
+#ifdef EAP_SERVER_AKA_PRIME
+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,
+				      "AKA'");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_prime_init;
+	eap->reset = eap_aka_reset;
+	eap->buildReq = eap_aka_buildReq;
+	eap->check = eap_aka_check;
+	eap->process = eap_aka_process;
+	eap->isDone = eap_aka_isDone;
+	eap->getKey = eap_aka_getKey;
+	eap->isSuccess = eap_aka_isSuccess;
+	eap->get_emsk = eap_aka_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+
+	return ret;
+}
+#endif /* EAP_SERVER_AKA_PRIME */

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_fast.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_fast.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_fast.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1619 +0,0 @@
-/*
- * EAP-FAST server (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "eap_common/eap_tlv_common.h"
-#include "eap_common/eap_fast_common.h"
-#include "eap_i.h"
-#include "eap_tls_common.h"
-
-
-static void eap_fast_reset(struct eap_sm *sm, void *priv);
-
-
-/* Private PAC-Opaque TLV types */
-#define PAC_OPAQUE_TYPE_PAD 0
-#define PAC_OPAQUE_TYPE_KEY 1
-#define PAC_OPAQUE_TYPE_LIFETIME 2
-#define PAC_OPAQUE_TYPE_IDENTITY 3
-
-struct eap_fast_data {
-	struct eap_ssl_data ssl;
-	enum {
-		START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
-		CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE
-	} state;
-
-	int fast_version;
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int force_version;
-	int peer_version;
-
-	u8 crypto_binding_nonce[32];
-	int final_result;
-
-	struct eap_fast_key_block_provisioning *key_block_p;
-
-	u8 simck[EAP_FAST_SIMCK_LEN];
-	u8 cmk[EAP_FAST_CMK_LEN];
-	int simck_idx;
-
-	u8 pac_opaque_encr[16];
-	u8 *srv_id;
-	size_t srv_id_len;
-	char *srv_id_info;
-
-	int anon_provisioning;
-	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
-	struct wpabuf *pending_phase2_resp;
-	u8 *identity; /* from PAC-Opaque */
-	size_t identity_len;
-	int eap_seq;
-	int tnc_started;
-
-	int pac_key_lifetime;
-	int pac_key_refresh_time;
-};
-
-
-static int eap_fast_process_phase2_start(struct eap_sm *sm,
-					 struct eap_fast_data *data);
-
-
-static const char * eap_fast_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case PHASE1:
-		return "PHASE1";
-	case PHASE2_START:
-		return "PHASE2_START";
-	case PHASE2_ID:
-		return "PHASE2_ID";
-	case PHASE2_METHOD:
-		return "PHASE2_METHOD";
-	case CRYPTO_BINDING:
-		return "CRYPTO_BINDING";
-	case REQUEST_PAC:
-		return "REQUEST_PAC";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_fast_state(struct eap_fast_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s",
-		   eap_fast_state_txt(data->state),
-		   eap_fast_state_txt(state));
-	data->state = state;
-}
-
-
-static EapType eap_fast_req_failure(struct eap_sm *sm,
-				    struct eap_fast_data *data)
-{
-	/* TODO: send Result TLV(FAILURE) */
-	eap_fast_state(data, FAILURE);
-	return EAP_TYPE_NONE;
-}
-
-
-static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
-				      const u8 *client_random,
-				      const u8 *server_random,
-				      u8 *master_secret)
-{
-	struct eap_fast_data *data = ctx;
-	const u8 *pac_opaque;
-	size_t pac_opaque_len;
-	u8 *buf, *pos, *end, *pac_key = NULL;
-	os_time_t lifetime = 0;
-	struct os_time now;
-	u8 *identity = NULL;
-	size_t identity_len = 0;
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
-		    ticket, len);
-
-	if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
-			   "SessionTicket");
-		return 0;
-	}
-
-	pac_opaque_len = WPA_GET_BE16(ticket + 2);
-	pac_opaque = ticket + 4;
-	if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
-	    pac_opaque_len > len - 4) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque "
-			   "(len=%lu left=%lu)",
-			   (unsigned long) pac_opaque_len,
-			   (unsigned long) len);
-		return 0;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque",
-		    pac_opaque, pac_opaque_len);
-
-	buf = os_malloc(pac_opaque_len - 8);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
-			   "for decrypting PAC-Opaque");
-		return 0;
-	}
-
-	if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
-		       pac_opaque, buf) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
-			   "PAC-Opaque");
-		os_free(buf);
-		/*
-		 * This may have been caused by server changing the PAC-Opaque
-		 * encryption key, so just ignore this PAC-Opaque instead of
-		 * failing the authentication completely. Provisioning can now
-		 * be used to provision a new PAC.
-		 */
-		return 0;
-	}
-
-	end = buf + pac_opaque_len - 8;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque",
-			buf, end - buf);
-
-	pos = buf;
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-
-		switch (*pos) {
-		case PAC_OPAQUE_TYPE_PAD:
-			pos = end;
-			break;
-		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]);
-				os_free(buf);
-				return -1;
-			}
-			pac_key = pos + 2;
-			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) {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
-					   "PAC-Key lifetime length %d",
-					   pos[1]);
-				os_free(buf);
-				return -1;
-			}
-			lifetime = WPA_GET_BE32(pos + 2);
-			break;
-		case PAC_OPAQUE_TYPE_IDENTITY:
-			identity = pos + 2;
-			identity_len = pos[1];
-			break;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (pac_key == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
-			   "PAC-Opaque");
-		os_free(buf);
-		return -1;
-	}
-
-	if (identity) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
-				  "PAC-Opaque", identity, identity_len);
-		os_free(data->identity);
-		data->identity = os_malloc(identity_len);
-		if (data->identity) {
-			os_memcpy(data->identity, identity, identity_len);
-			data->identity_len = identity_len;
-		}
-	}
-
-	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
-			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
-		data->send_new_pac = 2;
-		/*
-		 * Allow PAC to be used to allow a PAC update with some level
-		 * of server authentication (i.e., do not fall back to full TLS
-		 * handshake since we cannot be sure that the peer would be
-		 * able to validate server certificate now). However, reject
-		 * the authentication since the PAC was not valid anymore. Peer
-		 * can connect again with the newly provisioned PAC after this.
-		 */
-	} else if (lifetime - now.sec < data->pac_key_refresh_time) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send "
-			   "an update if authentication succeeds");
-		data->send_new_pac = 1;
-	}
-
-	eap_fast_derive_master_secret(pac_key, server_random, client_random,
-				      master_secret);
-
-	os_free(buf);
-
-	return 1;
-}
-
-
-static void eap_fast_derive_key_auth(struct eap_sm *sm,
-				     struct eap_fast_data *data)
-{
-	u8 *sks;
-
-	/* RFC 4851, Section 5.1:
-	 * Extra key material after TLS key_block: session_key_seed[40]
-	 */
-
-	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
-				  EAP_FAST_SKS_LEN);
-	if (sks == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
-			   "session_key_seed");
-		return;
-	}
-
-	/*
-	 * RFC 4851, Section 5.2:
-	 * S-IMCK[0] = session_key_seed
-	 */
-	wpa_hexdump_key(MSG_DEBUG,
-			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
-			sks, EAP_FAST_SKS_LEN);
-	data->simck_idx = 0;
-	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
-	os_free(sks);
-}
-
-
-static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
-					     struct eap_fast_data *data)
-{
-	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");
-		return;
-	}
-	/*
-	 * RFC 4851, Section 5.2:
-	 * S-IMCK[0] = session_key_seed
-	 */
-	wpa_hexdump_key(MSG_DEBUG,
-			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
-			data->key_block_p->session_key_seed,
-			sizeof(data->key_block_p->session_key_seed));
-	data->simck_idx = 0;
-	os_memcpy(data->simck, data->key_block_p->session_key_seed,
-		  EAP_FAST_SIMCK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
-			data->key_block_p->server_challenge,
-			sizeof(data->key_block_p->server_challenge));
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
-			data->key_block_p->client_challenge,
-			sizeof(data->key_block_p->client_challenge));
-}
-
-
-static int eap_fast_get_phase2_key(struct eap_sm *sm,
-				   struct eap_fast_data *data,
-				   u8 *isk, size_t isk_len)
-{
-	u8 *key;
-	size_t key_len;
-
-	os_memset(isk, 0, isk_len);
-
-	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
-			   "available");
-		return -1;
-	}
-
-	if (data->phase2_method->getKey == NULL)
-		return 0;
-
-	if ((key = data->phase2_method->getKey(sm, data->phase2_priv,
-					       &key_len)) == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
-			   "from Phase 2");
-		return -1;
-	}
-
-	if (key_len > isk_len)
-		key_len = isk_len;
-	if (key_len == 32 &&
-	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
-	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
-		/*
-		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
-		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
-		 * ISK for EAP-FAST cryptobinding.
-		 */
-		os_memcpy(isk, key + 16, 16);
-		os_memcpy(isk + 16, key, 16);
-	} else
-		os_memcpy(isk, key, key_len);
-	os_free(key);
-
-	return 0;
-}
-
-
-static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
-{
-	u8 isk[32], imck[60];
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)",
-		   data->simck_idx + 1);
-
-	/*
-	 * RFC 4851, Section 5.2:
-	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
-	 *                 MSK[j], 60)
-	 * S-IMCK[j] = first 40 octets of IMCK[j]
-	 * CMK[j] = last 20 octets of IMCK[j]
-	 */
-
-	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));
-	data->simck_idx++;
-	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
-			data->simck, EAP_FAST_SIMCK_LEN);
-	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
-			data->cmk, EAP_FAST_CMK_LEN);
-
-	return 0;
-}
-
-
-static void * eap_fast_init(struct eap_sm *sm)
-{
-	struct eap_fast_data *data;
-	u8 ciphers[5] = {
-		TLS_CIPHER_ANON_DH_AES128_SHA,
-		TLS_CIPHER_AES128_SHA,
-		TLS_CIPHER_RSA_DHE_AES128_SHA,
-		TLS_CIPHER_RC4_SHA,
-		TLS_CIPHER_NONE
-	};
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->fast_version = EAP_FAST_VERSION;
-	data->force_version = -1;
-	if (sm->user && sm->user->force_version >= 0) {
-		data->force_version = sm->user->force_version;
-		wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d",
-			   data->force_version);
-		data->fast_version = data->force_version;
-	}
-	data->state = START;
-
-	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-
-	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
-					   ciphers) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
-			   "suites");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-
-	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
-						 eap_fast_session_ticket_cb,
-						 data) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
-			   "callback");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-
-	if (sm->pac_opaque_encr_key == NULL) {
-		wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
-			   "configured");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-	os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
-		  sizeof(data->pac_opaque_encr));
-
-	if (sm->eap_fast_a_id == NULL) {
-		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-	data->srv_id = os_malloc(sm->eap_fast_a_id_len);
-	if (data->srv_id == NULL) {
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-	os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
-	data->srv_id_len = sm->eap_fast_a_id_len;
-
-	if (sm->eap_fast_a_id_info == NULL) {
-		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-	data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
-	if (data->srv_id_info == NULL) {
-		eap_fast_reset(sm, data);
-		return NULL;
-	}
-
-	/* PAC-Key lifetime in seconds (hard limit) */
-	data->pac_key_lifetime = sm->pac_key_lifetime;
-
-	/*
-	 * PAC-Key refresh time in seconds (soft limit on remaining hard
-	 * limit). The server will generate a new PAC-Key when this number of
-	 * seconds (or fewer) of the lifetime remains.
-	 */
-	data->pac_key_refresh_time = sm->pac_key_refresh_time;
-
-	return data;
-}
-
-
-static void eap_fast_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	if (data == NULL)
-		return;
-	if (data->phase2_priv && data->phase2_method)
-		data->phase2_method->reset(sm, data->phase2_priv);
-	eap_server_tls_ssl_deinit(sm, &data->ssl);
-	os_free(data->srv_id);
-	os_free(data->srv_id_info);
-	os_free(data->key_block_p);
-	wpabuf_free(data->pending_phase2_resp);
-	os_free(data->identity);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_fast_build_start(struct eap_sm *sm,
-					    struct eap_fast_data *data, u8 id)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
-			    1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
-			   " request");
-		eap_fast_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version);
-
-	/* RFC 4851, 4.1.1. Authority ID Data */
-	eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-
-	eap_fast_state(data, PHASE1);
-
-	return req;
-}
-
-
-static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
-{
-	char cipher[64];
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
-
-	if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
-	    < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
-			   "information");
-		eap_fast_state(data, FAILURE);
-		return -1;
-	}
-	data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
-		    
-	if (data->anon_provisioning) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
-		eap_fast_derive_key_provisioning(sm, data);
-	} else
-		eap_fast_derive_key_auth(sm, data);
-
-	eap_fast_state(data, PHASE2_START);
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
-						 struct eap_fast_data *data,
-						 u8 id)
-{
-	struct wpabuf *req;
-
-	if (data->phase2_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
-			   "initialized");
-		return NULL;
-	}
-	req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
-	if (req == NULL)
-		return NULL;
-
-	wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req);
-	return eap_fast_tlv_eap_payload(req);
-}
-
-
-static struct wpabuf * eap_fast_build_crypto_binding(
-	struct eap_sm *sm, struct eap_fast_data *data)
-{
-	struct wpabuf *buf;
-	struct eap_tlv_result_tlv *result;
-	struct eap_tlv_crypto_binding_tlv *binding;
-
-	buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding));
-	if (buf == NULL)
-		return NULL;
-
-	if (data->send_new_pac || data->anon_provisioning ||
-	    data->phase2_method)
-		data->final_result = 0;
-	else
-		data->final_result = 1;
-
-	if (!data->final_result || data->eap_seq > 1) {
-		/* Intermediate-Result */
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV "
-			   "(status=SUCCESS)");
-		result = wpabuf_put(buf, sizeof(*result));
-		result->tlv_type = host_to_be16(
-			EAP_TLV_TYPE_MANDATORY |
-			EAP_TLV_INTERMEDIATE_RESULT_TLV);
-		result->length = host_to_be16(2);
-		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
-	}
-
-	if (data->final_result) {
-		/* Result TLV */
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV "
-			   "(status=SUCCESS)");
-		result = wpabuf_put(buf, sizeof(*result));
-		result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-						EAP_TLV_RESULT_TLV);
-		result->length = host_to_be16(2);
-		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
-	}
-
-	/* Crypto-Binding TLV */
-	binding = wpabuf_put(buf, sizeof(*binding));
-	binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-					 EAP_TLV_CRYPTO_BINDING_TLV);
-	binding->length = host_to_be16(sizeof(*binding) -
-				       sizeof(struct eap_tlv_hdr));
-	binding->version = EAP_FAST_VERSION;
-	binding->received_version = data->peer_version;
-	binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
-	if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) {
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	/*
-	 * RFC 4851, Section 4.2.8:
-	 * The nonce in a request MUST have its least significant bit set to 0.
-	 */
-	binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01;
-
-	os_memcpy(data->crypto_binding_nonce, binding->nonce,
-		  sizeof(binding->nonce));
-
-	/*
-	 * RFC 4851, Section 5.3:
-	 * CMK = CMK[j]
-	 * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
-	 */
-
-	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN,
-		  (u8 *) binding, sizeof(*binding),
-		  binding->compound_mac);
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
-		   "Received Version %d SubType %d",
-		   binding->version, binding->received_version,
-		   binding->subtype);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
-		    binding->nonce, sizeof(binding->nonce));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
-		    binding->compound_mac, sizeof(binding->compound_mac));
-
-	return buf;
-}
-
-
-static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
-					  struct eap_fast_data *data)
-{
-	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
-	u8 *pac_buf, *pac_opaque;
-	struct wpabuf *buf;
-	u8 *pos;
-	size_t buf_len, srv_id_info_len, pac_len;
-	struct eap_tlv_hdr *pac_tlv;
-	struct pac_tlv_hdr *pac_info;
-	struct eap_tlv_result_tlv *result;
-	struct os_time now;
-
-	if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
-	    os_get_time(&now) < 0)
-		return NULL;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
-			pac_key, EAP_FAST_PAC_KEY_LEN);
-
-	pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
-		(2 + sm->identity_len) + 8;
-	pac_buf = os_malloc(pac_len);
-	if (pac_buf == NULL)
-		return NULL;
-
-	srv_id_info_len = os_strlen(data->srv_id_info);
-
-	pos = pac_buf;
-	*pos++ = PAC_OPAQUE_TYPE_KEY;
-	*pos++ = EAP_FAST_PAC_KEY_LEN;
-	os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
-	pos += EAP_FAST_PAC_KEY_LEN;
-
-	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
-	*pos++ = 4;
-	WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
-	pos += 4;
-
-	if (sm->identity) {
-		*pos++ = PAC_OPAQUE_TYPE_IDENTITY;
-		*pos++ = sm->identity_len;
-		os_memcpy(pos, sm->identity, sm->identity_len);
-		pos += sm->identity_len;
-	}
-
-	pac_len = pos - pac_buf;
-	while (pac_len % 8) {
-		*pos++ = PAC_OPAQUE_TYPE_PAD;
-		pac_len++;
-	}
-
-	pac_opaque = os_malloc(pac_len + 8);
-	if (pac_opaque == NULL) {
-		os_free(pac_buf);
-		return NULL;
-	}
-	if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
-		     pac_opaque) < 0) {
-		os_free(pac_buf);
-		os_free(pac_opaque);
-		return NULL;
-	}
-	os_free(pac_buf);
-
-	pac_len += 8;
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
-		    pac_opaque, pac_len);
-
-	buf_len = sizeof(*pac_tlv) +
-		sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN +
-		sizeof(struct pac_tlv_hdr) + pac_len +
-		data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
-	buf = wpabuf_alloc(buf_len);
-	if (buf == NULL) {
-		os_free(pac_opaque);
-		return NULL;
-	}
-
-	/* Result TLV */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
-	result = wpabuf_put(buf, sizeof(*result));
-	WPA_PUT_BE16((u8 *) &result->tlv_type,
-		     EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV);
-	WPA_PUT_BE16((u8 *) &result->length, 2);
-	WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS);
-
-	/* PAC TLV */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
-	pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
-	pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-					 EAP_TLV_PAC_TLV);
-
-	/* PAC-Key */
-	eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN);
-
-	/* PAC-Opaque */
-	eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
-	os_free(pac_opaque);
-
-	/* PAC-Info */
-	pac_info = wpabuf_put(buf, sizeof(*pac_info));
-	pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
-
-	/* PAC-Lifetime (inside PAC-Info) */
-	eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
-	wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
-
-	/* A-ID (inside PAC-Info) */
-	eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-	
-	/* Note: headers may be misaligned after A-ID */
-
-	if (sm->identity) {
-		eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
-				 sm->identity_len);
-	}
-
-	/* A-ID-Info (inside PAC-Info) */
-	eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
-			 srv_id_info_len);
-
-	/* PAC-Type (inside PAC-Info) */
-	eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
-	wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
-
-	/* Update PAC-Info and PAC TLV Length fields */
-	pos = wpabuf_put(buf, 0);
-	pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
-	pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
-
-	return buf;
-}
-
-
-static int eap_fast_encrypt_phase2(struct eap_sm *sm,
-				   struct eap_fast_data *data,
-				   struct wpabuf *plain, int piggyback)
-{
-	struct wpabuf *encr;
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
-			    plain);
-	encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
-	wpabuf_free(plain);
-
-	if (data->ssl.tls_out && piggyback) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
-			   "(len=%d) with last Phase 1 Message (len=%d "
-			   "used=%d)",
-			   (int) wpabuf_len(encr),
-			   (int) wpabuf_len(data->ssl.tls_out),
-			   (int) data->ssl.tls_out_pos);
-		if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
-			wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize "
-				   "output buffer");
-			wpabuf_free(encr);
-			return -1;
-		}
-		wpabuf_put_buf(data->ssl.tls_out, encr);
-		wpabuf_free(encr);
-	} else {
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = encr;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_fast_data *data = priv;
-	struct wpabuf *req = NULL;
-	int piggyback = 0;
-
-	if (data->ssl.state == FRAG_ACK) {
-		return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
-						data->fast_version);
-	}
-
-	if (data->ssl.state == WAIT_FRAG_ACK) {
-		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
-						data->fast_version, id);
-	}
-
-	switch (data->state) {
-	case START:
-		return eap_fast_build_start(sm, data, id);
-	case PHASE1:
-		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			if (eap_fast_phase1_done(sm, data) < 0)
-				return NULL;
-			if (data->state == PHASE2_START) {
-				/*
-				 * Try to generate Phase 2 data to piggyback
-				 * with the end of Phase 1 to avoid extra
-				 * roundtrip.
-				 */
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start "
-					   "Phase 2");
-				if (eap_fast_process_phase2_start(sm, data))
-					break;
-				req = eap_fast_build_phase2_req(sm, data, id);
-				piggyback = 1;
-			}
-		}
-		break;
-	case PHASE2_ID:
-	case PHASE2_METHOD:
-		req = eap_fast_build_phase2_req(sm, data, id);
-		break;
-	case CRYPTO_BINDING:
-		req = eap_fast_build_crypto_binding(sm, data);
-		if (data->phase2_method) {
-			/*
-			 * Include the start of the next EAP method in the
-			 * sequence in the same message with Crypto-Binding to
-			 * save a round-trip.
-			 */
-			struct wpabuf *eap;
-			eap = eap_fast_build_phase2_req(sm, data, id);
-			req = wpabuf_concat(req, eap);
-			eap_fast_state(data, PHASE2_METHOD);
-		}
-		break;
-	case REQUEST_PAC:
-		req = eap_fast_build_pac(sm, data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
-			   __func__, data->state);
-		return NULL;
-	}
-
-	if (req &&
-	    eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0)
-		return NULL;
-
-	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
-					data->fast_version, id);
-}
-
-
-static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
-				EapType eap_type)
-{
-	if (data->phase2_priv && data->phase2_method) {
-		data->phase2_method->reset(sm, data->phase2_priv);
-		data->phase2_method = NULL;
-		data->phase2_priv = NULL;
-	}
-	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
-							eap_type);
-	if (!data->phase2_method)
-		return -1;
-
-	if (data->key_block_p) {
-		sm->auth_challenge = data->key_block_p->server_challenge;
-		sm->peer_challenge = data->key_block_p->client_challenge;
-	}
-	sm->init_phase2 = 1;
-	data->phase2_priv = data->phase2_method->init(sm);
-	sm->init_phase2 = 0;
-	sm->auth_challenge = NULL;
-	sm->peer_challenge = NULL;
-
-	return data->phase2_priv == NULL ? -1 : 0;
-}
-
-
-static void eap_fast_process_phase2_response(struct eap_sm *sm,
-					     struct eap_fast_data *data,
-					     u8 *in_data, size_t in_len)
-{
-	u8 next_type = EAP_TYPE_NONE;
-	struct eap_hdr *hdr;
-	u8 *pos;
-	size_t left;
-	struct wpabuf buf;
-	const struct eap_method *m = data->phase2_method;
-	void *priv = data->phase2_priv;
-
-	if (priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
-			   "initialized?!", __func__);
-		return;
-	}
-
-	hdr = (struct eap_hdr *) in_data;
-	pos = (u8 *) (hdr + 1);
-
-	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
-		left = in_len - sizeof(*hdr);
-		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
-			    "allowed types", pos + 1, left - 1);
-#ifdef EAP_SERVER_TNC
-		if (m && m->vendor == EAP_VENDOR_IETF &&
-		    m->method == EAP_TYPE_TNC) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
-				   "TNC negotiation");
-			next_type = eap_fast_req_failure(sm, data);
-			eap_fast_phase2_init(sm, data, next_type);
-			return;
-		}
-#endif /* EAP_SERVER_TNC */
-		eap_sm_process_nak(sm, pos + 1, left - 1);
-		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index].method !=
-		    EAP_TYPE_NONE) {
-			next_type = sm->user->methods[
-				sm->user_eap_method_index++].method;
-			wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
-				   next_type);
-		} else {
-			next_type = eap_fast_req_failure(sm, data);
-		}
-		eap_fast_phase2_init(sm, data, next_type);
-		return;
-	}
-
-	wpabuf_set(&buf, in_data, in_len);
-
-	if (m->check(sm, priv, &buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
-			   "ignore the packet");
-		next_type = eap_fast_req_failure(sm, data);
-		return;
-	}
-
-	m->process(sm, priv, &buf);
-
-	if (!m->isDone(sm, priv))
-		return;
-
-	if (!m->isSuccess(sm, priv)) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
-		next_type = eap_fast_req_failure(sm, data);
-		eap_fast_phase2_init(sm, data, next_type);
-		return;
-	}
-
-	switch (data->state) {
-	case PHASE2_ID:
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
-					  "Identity not found in the user "
-					  "database",
-					  sm->identity, sm->identity_len);
-			next_type = eap_fast_req_failure(sm, data);
-			break;
-		}
-
-		eap_fast_state(data, PHASE2_METHOD);
-		if (data->anon_provisioning) {
-			/*
-			 * Only EAP-MSCHAPv2 is allowed for anonymous
-			 * provisioning.
-			 */
-			next_type = EAP_TYPE_MSCHAPV2;
-			sm->user_eap_method_index = 0;
-		} else {
-			next_type = sm->user->methods[0].method;
-			sm->user_eap_method_index = 1;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
-		break;
-	case PHASE2_METHOD:
-	case CRYPTO_BINDING:
-		eap_fast_update_icmk(sm, data);
-		eap_fast_state(data, CRYPTO_BINDING);
-		data->eap_seq++;
-		next_type = EAP_TYPE_NONE;
-#ifdef EAP_SERVER_TNC
-		if (sm->tnc && !data->tnc_started) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
-			next_type = EAP_TYPE_TNC;
-			data->tnc_started = 1;
-		}
-#endif /* EAP_SERVER_TNC */
-		break;
-	case FAILURE:
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
-			   __func__, data->state);
-		break;
-	}
-
-	eap_fast_phase2_init(sm, data, next_type);
-}
-
-
-static void eap_fast_process_phase2_eap(struct eap_sm *sm,
-					struct eap_fast_data *data,
-					u8 *in_data, size_t in_len)
-{
-	struct eap_hdr *hdr;
-	size_t len;
-
-	hdr = (struct eap_hdr *) in_data;
-	if (in_len < (int) sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
-			   "EAP frame (len=%lu)", (unsigned long) in_len);
-		eap_fast_req_failure(sm, data);
-		return;
-	}
-	len = be_to_host16(hdr->length);
-	if (len > in_len) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
-			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
-			   (unsigned long) in_len, (unsigned long) len);
-		eap_fast_req_failure(sm, data);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
-		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
-		   (unsigned long) len);
-	switch (hdr->code) {
-	case EAP_CODE_RESPONSE:
-		eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
-			   "Phase 2 EAP header", hdr->code);
-		break;
-	}
-}
-
-
-static int eap_fast_parse_tlvs(struct wpabuf *data,
-			       struct eap_fast_tlv_parse *tlv)
-{
-	int mandatory, tlv_type, len, res;
-	u8 *pos, *end;
-
-	os_memset(tlv, 0, sizeof(*tlv));
-
-	pos = wpabuf_mhead(data);
-	end = pos + wpabuf_len(data);
-	while (pos + 4 < end) {
-		mandatory = pos[0] & 0x80;
-		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
-		pos += 2;
-		len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + len > end) {
-			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
-			   "TLV type %d length %d%s",
-			   tlv_type, len, mandatory ? " (mandatory)" : "");
-
-		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
-		if (res == -2)
-			break;
-		if (res < 0) {
-			if (mandatory) {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
-					   "mandatory TLV type %d", tlv_type);
-				/* TODO: generate Nak TLV */
-				break;
-			} else {
-				wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
-					   "unknown optional TLV type %d",
-					   tlv_type);
-			}
-		}
-
-		pos += len;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_validate_crypto_binding(
-	struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
-	size_t bind_len)
-{
-	u8 cmac[SHA1_MAC_LEN];
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
-		   "Version %d Received Version %d SubType %d",
-		   b->version, b->received_version, b->subtype);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
-		    b->nonce, sizeof(b->nonce));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
-		    b->compound_mac, sizeof(b->compound_mac));
-
-	if (b->version != EAP_FAST_VERSION ||
-	    b->received_version != EAP_FAST_VERSION) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
-			   "in Crypto-Binding: version %d "
-			   "received_version %d", b->version,
-			   b->received_version);
-		return -1;
-	}
-
-	if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
-			   "Crypto-Binding: %d", b->subtype);
-		return -1;
-	}
-
-	if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
-	    (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
-			   "Crypto-Binding");
-		return -1;
-	}
-
-	os_memcpy(cmac, b->compound_mac, sizeof(cmac));
-	os_memset(b->compound_mac, 0, sizeof(cmac));
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
-		    "Compound MAC calculation",
-		    (u8 *) b, bind_len);
-	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
-		  b->compound_mac);
-	if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
-		wpa_hexdump(MSG_MSGDUMP,
-			    "EAP-FAST: Calculated Compound MAC",
-			    b->compound_mac, sizeof(cmac));
-		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
-			   "match");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
-{
-	struct eap_tlv_pac_type_tlv *tlv;
-
-	if (pac == NULL || len != sizeof(*tlv))
-		return 0;
-
-	tlv = (struct eap_tlv_pac_type_tlv *) pac;
-
-	return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
-		be_to_host16(tlv->length) == 2 &&
-		be_to_host16(tlv->pac_type) == type;
-}
-
-
-static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
-					 struct eap_fast_data *data,
-					 struct wpabuf *in_data)
-{
-	struct eap_fast_tlv_parse tlv;
-	int check_crypto_binding = data->state == CRYPTO_BINDING;
-
-	if (eap_fast_parse_tlvs(in_data, &tlv) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received "
-			   "Phase 2 TLVs");
-		return;
-	}
-
-	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated "
-			   "failure");
-		eap_fast_state(data, FAILURE);
-		return;
-	}
-
-	if (data->state == REQUEST_PAC) {
-		u16 type, len, res;
-		if (tlv.pac == NULL || tlv.pac_len < 6) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC "
-				   "Acknowledgement received");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		type = WPA_GET_BE16(tlv.pac);
-		len = WPA_GET_BE16(tlv.pac + 2);
-		res = WPA_GET_BE16(tlv.pac + 4);
-
-		if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
-		    res != EAP_TLV_RESULT_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not "
-				   "contain acknowledgement");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received "
-			   "- PAC provisioning succeeded");
-		eap_fast_state(data, (data->anon_provisioning ||
-				      data->send_new_pac == 2) ?
-			       FAILURE : SUCCESS);
-		return;
-	}
-
-	if (check_crypto_binding) {
-		if (tlv.crypto_binding == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
-				   "TLV received");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		if (data->final_result &&
-		    tlv.result != EAP_TLV_RESULT_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
-				   "without Success Result");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		if (!data->final_result &&
-		    tlv.iresult != EAP_TLV_RESULT_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
-				   "without intermediate Success Result");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding,
-						     tlv.crypto_binding_len)) {
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
-			   "received");
-		if (data->final_result) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
-				   "completed successfully");
-		}
-
-		if (data->anon_provisioning &&
-		    sm->eap_fast_prov != ANON_PROV &&
-		    sm->eap_fast_prov != BOTH_PROV) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
-				   "use unauthenticated provisioning which is "
-				   "disabled");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		if (sm->eap_fast_prov != AUTH_PROV &&
-		    sm->eap_fast_prov != BOTH_PROV &&
-		    tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
-		    eap_fast_pac_type(tlv.pac, tlv.pac_len,
-				      PAC_TYPE_TUNNEL_PAC)) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
-				   "use authenticated provisioning which is "
-				   "disabled");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-
-		if (data->anon_provisioning ||
-		    (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
-		     eap_fast_pac_type(tlv.pac, tlv.pac_len,
-				       PAC_TYPE_TUNNEL_PAC))) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new "
-				   "Tunnel PAC");
-			eap_fast_state(data, REQUEST_PAC);
-		} else if (data->send_new_pac) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
-				   "re-keying of Tunnel PAC");
-			eap_fast_state(data, REQUEST_PAC);
-		} else if (data->final_result)
-			eap_fast_state(data, SUCCESS);
-	}
-
-	if (tlv.eap_payload_tlv) {
-		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
-					    tlv.eap_payload_tlv_len);
-	}
-}
-
-
-static void eap_fast_process_phase2(struct eap_sm *sm,
-				    struct eap_fast_data *data,
-				    struct wpabuf *in_buf)
-{
-	struct wpabuf *in_decrypted;
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
-		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
-
-	if (data->pending_phase2_resp) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
-			   "skip decryption and use old data");
-		eap_fast_process_phase2_tlvs(sm, data,
-					     data->pending_phase2_resp);
-		wpabuf_free(data->pending_phase2_resp);
-		data->pending_phase2_resp = NULL;
-		return;
-	}
-
-	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
-					      in_buf);
-	if (in_decrypted == NULL) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
-			   "data");
-		eap_fast_state(data, FAILURE);
-		return;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs",
-			    in_decrypted);
-
-	eap_fast_process_phase2_tlvs(sm, data, in_decrypted);
-
-	if (sm->method_pending == METHOD_PENDING_WAIT) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in "
-			   "pending wait state - save decrypted response");
-		wpabuf_free(data->pending_phase2_resp);
-		data->pending_phase2_resp = in_decrypted;
-		return;
-	}
-
-	wpabuf_free(in_decrypted);
-}
-
-
-static int eap_fast_process_version(struct eap_sm *sm, void *priv,
-				    int peer_version)
-{
-	struct eap_fast_data *data = priv;
-
-	data->peer_version = peer_version;
-
-	if (data->force_version >= 0 && peer_version != data->force_version) {
-		wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
-			   " version (forced=%d peer=%d) - reject",
-			   data->force_version, peer_version);
-		return -1;
-	}
-
-	if (peer_version < data->fast_version) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
-			   "use version %d",
-			   peer_version, data->fast_version, peer_version);
-		data->fast_version = peer_version;
-	}
-
-	return 0;
-}
-
-
-static int eap_fast_process_phase1(struct eap_sm *sm,
-				   struct eap_fast_data *data)
-{
-	if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
-		eap_fast_state(data, FAILURE);
-		return -1;
-	}
-
-	if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
-	    wpabuf_len(data->ssl.tls_out) > 0)
-		return 1;
-
-	/*
-	 * Phase 1 was completed with the received message (e.g., when using
-	 * abbreviated handshake), so Phase 2 can be started immediately
-	 * without having to send through an empty message to the peer.
-	 */
-
-	return eap_fast_phase1_done(sm, data);
-}
-
-
-static int eap_fast_process_phase2_start(struct eap_sm *sm,
-					 struct eap_fast_data *data)
-{
-	u8 next_type;
-
-	if (data->identity) {
-		os_free(sm->identity);
-		sm->identity = data->identity;
-		data->identity = NULL;
-		sm->identity_len = data->identity_len;
-		data->identity_len = 0;
-		sm->require_identity_match = 1;
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: "
-					  "Phase2 Identity not found "
-					  "in the user database",
-					  sm->identity, sm->identity_len);
-			next_type = eap_fast_req_failure(sm, data);
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
-				   "known - skip Phase 2 Identity Request");
-			next_type = sm->user->methods[0].method;
-			sm->user_eap_method_index = 1;
-		}
-
-		eap_fast_state(data, PHASE2_METHOD);
-	} else {
-		eap_fast_state(data, PHASE2_ID);
-		next_type = EAP_TYPE_IDENTITY;
-	}
-
-	return eap_fast_phase2_init(sm, data, next_type);
-}
-
-
-static void eap_fast_process_msg(struct eap_sm *sm, void *priv,
-				 const struct wpabuf *respData)
-{
-	struct eap_fast_data *data = priv;
-
-	switch (data->state) {
-	case PHASE1:
-		if (eap_fast_process_phase1(sm, data))
-			break;
-
-		/* fall through to PHASE2_START */
-	case PHASE2_START:
-		eap_fast_process_phase2_start(sm, data);
-		break;
-	case PHASE2_ID:
-	case PHASE2_METHOD:
-	case CRYPTO_BINDING:
-	case REQUEST_PAC:
-		eap_fast_process_phase2(sm, data, data->ssl.tls_in);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
-			   data->state, __func__);
-		break;
-	}
-}
-
-
-static void eap_fast_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_fast_data *data = priv;
-	if (eap_server_tls_process(sm, &data->ssl, respData, data,
-				   EAP_TYPE_FAST, eap_fast_process_version,
-				   eap_fast_process_msg) < 0)
-		eap_fast_state(data, FAILURE);
-}
-
-
-static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_fast_data *data = priv;
-	u8 *eapKeyData;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
-	if (eapKeyData == NULL)
-		return NULL;
-
-	eap_fast_derive_eap_msk(data->simck, eapKeyData);
-	*len = EAP_FAST_KEY_LEN;
-
-	return eapKeyData;
-}
-
-
-static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_fast_data *data = priv;
-	u8 *eapKeyData;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	eapKeyData = os_malloc(EAP_EMSK_LEN);
-	if (eapKeyData == NULL)
-		return NULL;
-
-	eap_fast_derive_eap_emsk(data->simck, eapKeyData);
-	*len = EAP_EMSK_LEN;
-
-	return eapKeyData;
-}
-
-
-static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_fast_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_fast_init;
-	eap->reset = eap_fast_reset;
-	eap->buildReq = eap_fast_buildReq;
-	eap->check = eap_fast_check;
-	eap->process = eap_fast_process;
-	eap->isDone = eap_fast_isDone;
-	eap->getKey = eap_fast_getKey;
-	eap->get_emsk = eap_fast_get_emsk;
-	eap->isSuccess = eap_fast_isSuccess;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_fast.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_fast.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_fast.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_fast.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1614 @@
+/*
+ * EAP-FAST server (RFC 4851)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/sha1.h"
+#include "crypto/tls.h"
+#include "crypto/random.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_fast_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv);
+
+
+/* Private PAC-Opaque TLV types */
+#define PAC_OPAQUE_TYPE_PAD 0
+#define PAC_OPAQUE_TYPE_KEY 1
+#define PAC_OPAQUE_TYPE_LIFETIME 2
+#define PAC_OPAQUE_TYPE_IDENTITY 3
+
+struct eap_fast_data {
+	struct eap_ssl_data ssl;
+	enum {
+		START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
+		CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE
+	} state;
+
+	int fast_version;
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int force_version;
+	int peer_version;
+
+	u8 crypto_binding_nonce[32];
+	int final_result;
+
+	struct eap_fast_key_block_provisioning *key_block_p;
+
+	u8 simck[EAP_FAST_SIMCK_LEN];
+	u8 cmk[EAP_FAST_CMK_LEN];
+	int simck_idx;
+
+	u8 pac_opaque_encr[16];
+	u8 *srv_id;
+	size_t srv_id_len;
+	char *srv_id_info;
+
+	int anon_provisioning;
+	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
+	struct wpabuf *pending_phase2_resp;
+	u8 *identity; /* from PAC-Opaque */
+	size_t identity_len;
+	int eap_seq;
+	int tnc_started;
+
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+};
+
+
+static int eap_fast_process_phase2_start(struct eap_sm *sm,
+					 struct eap_fast_data *data);
+
+
+static const char * eap_fast_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case PHASE1:
+		return "PHASE1";
+	case PHASE2_START:
+		return "PHASE2_START";
+	case PHASE2_ID:
+		return "PHASE2_ID";
+	case PHASE2_METHOD:
+		return "PHASE2_METHOD";
+	case CRYPTO_BINDING:
+		return "CRYPTO_BINDING";
+	case REQUEST_PAC:
+		return "REQUEST_PAC";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_fast_state(struct eap_fast_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s",
+		   eap_fast_state_txt(data->state),
+		   eap_fast_state_txt(state));
+	data->state = state;
+}
+
+
+static EapType eap_fast_req_failure(struct eap_sm *sm,
+				    struct eap_fast_data *data)
+{
+	/* TODO: send Result TLV(FAILURE) */
+	eap_fast_state(data, FAILURE);
+	return EAP_TYPE_NONE;
+}
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+				      const u8 *client_random,
+				      const u8 *server_random,
+				      u8 *master_secret)
+{
+	struct eap_fast_data *data = ctx;
+	const u8 *pac_opaque;
+	size_t pac_opaque_len;
+	u8 *buf, *pos, *end, *pac_key = NULL;
+	os_time_t lifetime = 0;
+	struct os_time now;
+	u8 *identity = NULL;
+	size_t identity_len = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
+		    ticket, len);
+
+	if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
+			   "SessionTicket");
+		return 0;
+	}
+
+	pac_opaque_len = WPA_GET_BE16(ticket + 2);
+	pac_opaque = ticket + 4;
+	if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
+	    pac_opaque_len > len - 4) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque "
+			   "(len=%lu left=%lu)",
+			   (unsigned long) pac_opaque_len,
+			   (unsigned long) len);
+		return 0;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque",
+		    pac_opaque, pac_opaque_len);
+
+	buf = os_malloc(pac_opaque_len - 8);
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+			   "for decrypting PAC-Opaque");
+		return 0;
+	}
+
+	if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
+		       pac_opaque, buf) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
+			   "PAC-Opaque");
+		os_free(buf);
+		/*
+		 * This may have been caused by server changing the PAC-Opaque
+		 * encryption key, so just ignore this PAC-Opaque instead of
+		 * failing the authentication completely. Provisioning can now
+		 * be used to provision a new PAC.
+		 */
+		return 0;
+	}
+
+	end = buf + pac_opaque_len - 8;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque",
+			buf, end - buf);
+
+	pos = buf;
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+
+		switch (*pos) {
+		case PAC_OPAQUE_TYPE_PAD:
+			pos = end;
+			break;
+		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]);
+				os_free(buf);
+				return -1;
+			}
+			pac_key = pos + 2;
+			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) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+					   "PAC-Key lifetime length %d",
+					   pos[1]);
+				os_free(buf);
+				return -1;
+			}
+			lifetime = WPA_GET_BE32(pos + 2);
+			break;
+		case PAC_OPAQUE_TYPE_IDENTITY:
+			identity = pos + 2;
+			identity_len = pos[1];
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (pac_key == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
+			   "PAC-Opaque");
+		os_free(buf);
+		return -1;
+	}
+
+	if (identity) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
+				  "PAC-Opaque", identity, identity_len);
+		os_free(data->identity);
+		data->identity = os_malloc(identity_len);
+		if (data->identity) {
+			os_memcpy(data->identity, identity, identity_len);
+			data->identity_len = identity_len;
+		}
+	}
+
+	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
+			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
+		data->send_new_pac = 2;
+		/*
+		 * Allow PAC to be used to allow a PAC update with some level
+		 * of server authentication (i.e., do not fall back to full TLS
+		 * handshake since we cannot be sure that the peer would be
+		 * able to validate server certificate now). However, reject
+		 * the authentication since the PAC was not valid anymore. Peer
+		 * can connect again with the newly provisioned PAC after this.
+		 */
+	} else if (lifetime - now.sec < data->pac_key_refresh_time) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send "
+			   "an update if authentication succeeds");
+		data->send_new_pac = 1;
+	}
+
+	eap_fast_derive_master_secret(pac_key, server_random, client_random,
+				      master_secret);
+
+	os_free(buf);
+
+	return 1;
+}
+
+
+static void eap_fast_derive_key_auth(struct eap_sm *sm,
+				     struct eap_fast_data *data)
+{
+	u8 *sks;
+
+	/* RFC 4851, Section 5.1:
+	 * Extra key material after TLS key_block: session_key_seed[40]
+	 */
+
+	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+				  EAP_FAST_SKS_LEN);
+	if (sks == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
+			   "session_key_seed");
+		return;
+	}
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			sks, EAP_FAST_SKS_LEN);
+	data->simck_idx = 0;
+	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+	os_free(sks);
+}
+
+
+static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
+					     struct eap_fast_data *data)
+{
+	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");
+		return;
+	}
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			data->key_block_p->session_key_seed,
+			sizeof(data->key_block_p->session_key_seed));
+	data->simck_idx = 0;
+	os_memcpy(data->simck, data->key_block_p->session_key_seed,
+		  EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
+			data->key_block_p->server_challenge,
+			sizeof(data->key_block_p->server_challenge));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
+			data->key_block_p->client_challenge,
+			sizeof(data->key_block_p->client_challenge));
+}
+
+
+static int eap_fast_get_phase2_key(struct eap_sm *sm,
+				   struct eap_fast_data *data,
+				   u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+
+	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+			   "available");
+		return -1;
+	}
+
+	if (data->phase2_method->getKey == NULL)
+		return 0;
+
+	if ((key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
+{
+	u8 isk[32], imck[60];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)",
+		   data->simck_idx + 1);
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+	 *                 MSK[j], 60)
+	 * S-IMCK[j] = first 40 octets of IMCK[j]
+	 * CMK[j] = last 20 octets of IMCK[j]
+	 */
+
+	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));
+	data->simck_idx++;
+	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+			data->simck, EAP_FAST_SIMCK_LEN);
+	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+			data->cmk, EAP_FAST_CMK_LEN);
+
+	return 0;
+}
+
+
+static void * eap_fast_init(struct eap_sm *sm)
+{
+	struct eap_fast_data *data;
+	u8 ciphers[5] = {
+		TLS_CIPHER_ANON_DH_AES128_SHA,
+		TLS_CIPHER_AES128_SHA,
+		TLS_CIPHER_RSA_DHE_AES128_SHA,
+		TLS_CIPHER_RC4_SHA,
+		TLS_CIPHER_NONE
+	};
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->fast_version = EAP_FAST_VERSION;
+	data->force_version = -1;
+	if (sm->user && sm->user->force_version >= 0) {
+		data->force_version = sm->user->force_version;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d",
+			   data->force_version);
+		data->fast_version = data->force_version;
+	}
+	data->state = START;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+					   ciphers) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
+			   "suites");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+						 eap_fast_session_ticket_cb,
+						 data) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+			   "callback");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (sm->pac_opaque_encr_key == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
+			   "configured");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+		  sizeof(data->pac_opaque_encr));
+
+	if (sm->eap_fast_a_id == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	data->srv_id = os_malloc(sm->eap_fast_a_id_len);
+	if (data->srv_id == NULL) {
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len);
+	data->srv_id_len = sm->eap_fast_a_id_len;
+
+	if (sm->eap_fast_a_id_info == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	data->srv_id_info = os_strdup(sm->eap_fast_a_id_info);
+	if (data->srv_id_info == NULL) {
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	/* PAC-Key lifetime in seconds (hard limit) */
+	data->pac_key_lifetime = sm->pac_key_lifetime;
+
+	/*
+	 * PAC-Key refresh time in seconds (soft limit on remaining hard
+	 * limit). The server will generate a new PAC-Key when this number of
+	 * seconds (or fewer) of the lifetime remains.
+	 */
+	data->pac_key_refresh_time = sm->pac_key_refresh_time;
+
+	return data;
+}
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->reset(sm, data->phase2_priv);
+	eap_server_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->srv_id);
+	os_free(data->srv_id_info);
+	os_free(data->key_block_p);
+	wpabuf_free(data->pending_phase2_resp);
+	os_free(data->identity);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_fast_build_start(struct eap_sm *sm,
+					    struct eap_fast_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
+			    1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
+			   " request");
+		eap_fast_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version);
+
+	/* RFC 4851, 4.1.1. Authority ID Data */
+	eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
+
+	eap_fast_state(data, PHASE1);
+
+	return req;
+}
+
+
+static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
+{
+	char cipher[64];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
+
+	if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
+			   "information");
+		eap_fast_state(data, FAILURE);
+		return -1;
+	}
+	data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
+		    
+	if (data->anon_provisioning) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
+		eap_fast_derive_key_provisioning(sm, data);
+	} else
+		eap_fast_derive_key_auth(sm, data);
+
+	eap_fast_state(data, PHASE2_START);
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
+						 struct eap_fast_data *data,
+						 u8 id)
+{
+	struct wpabuf *req;
+
+	if (data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+			   "initialized");
+		return NULL;
+	}
+	req = data->phase2_method->buildReq(sm, data->phase2_priv, id);
+	if (req == NULL)
+		return NULL;
+
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req);
+	return eap_fast_tlv_eap_payload(req);
+}
+
+
+static struct wpabuf * eap_fast_build_crypto_binding(
+	struct eap_sm *sm, struct eap_fast_data *data)
+{
+	struct wpabuf *buf;
+	struct eap_tlv_result_tlv *result;
+	struct eap_tlv_crypto_binding_tlv *binding;
+
+	buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding));
+	if (buf == NULL)
+		return NULL;
+
+	if (data->send_new_pac || data->anon_provisioning ||
+	    data->phase2_method)
+		data->final_result = 0;
+	else
+		data->final_result = 1;
+
+	if (!data->final_result || data->eap_seq > 1) {
+		/* Intermediate-Result */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV "
+			   "(status=SUCCESS)");
+		result = wpabuf_put(buf, sizeof(*result));
+		result->tlv_type = host_to_be16(
+			EAP_TLV_TYPE_MANDATORY |
+			EAP_TLV_INTERMEDIATE_RESULT_TLV);
+		result->length = host_to_be16(2);
+		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+	}
+
+	if (data->final_result) {
+		/* Result TLV */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV "
+			   "(status=SUCCESS)");
+		result = wpabuf_put(buf, sizeof(*result));
+		result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+						EAP_TLV_RESULT_TLV);
+		result->length = host_to_be16(2);
+		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+	}
+
+	/* Crypto-Binding TLV */
+	binding = wpabuf_put(buf, sizeof(*binding));
+	binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+					 EAP_TLV_CRYPTO_BINDING_TLV);
+	binding->length = host_to_be16(sizeof(*binding) -
+				       sizeof(struct eap_tlv_hdr));
+	binding->version = EAP_FAST_VERSION;
+	binding->received_version = data->peer_version;
+	binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
+	if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) {
+		wpabuf_free(buf);
+		return NULL;
+	}
+
+	/*
+	 * RFC 4851, Section 4.2.8:
+	 * The nonce in a request MUST have its least significant bit set to 0.
+	 */
+	binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01;
+
+	os_memcpy(data->crypto_binding_nonce, binding->nonce,
+		  sizeof(binding->nonce));
+
+	/*
+	 * RFC 4851, Section 5.3:
+	 * CMK = CMK[j]
+	 * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
+	 */
+
+	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN,
+		  (u8 *) binding, sizeof(*binding),
+		  binding->compound_mac);
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
+		   "Received Version %d SubType %d",
+		   binding->version, binding->received_version,
+		   binding->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    binding->nonce, sizeof(binding->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    binding->compound_mac, sizeof(binding->compound_mac));
+
+	return buf;
+}
+
+
+static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
+					  struct eap_fast_data *data)
+{
+	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+	u8 *pac_buf, *pac_opaque;
+	struct wpabuf *buf;
+	u8 *pos;
+	size_t buf_len, srv_id_info_len, pac_len;
+	struct eap_tlv_hdr *pac_tlv;
+	struct pac_tlv_hdr *pac_info;
+	struct eap_tlv_result_tlv *result;
+	struct os_time now;
+
+	if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+	    os_get_time(&now) < 0)
+		return NULL;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
+			pac_key, EAP_FAST_PAC_KEY_LEN);
+
+	pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
+		(2 + sm->identity_len) + 8;
+	pac_buf = os_malloc(pac_len);
+	if (pac_buf == NULL)
+		return NULL;
+
+	srv_id_info_len = os_strlen(data->srv_id_info);
+
+	pos = pac_buf;
+	*pos++ = PAC_OPAQUE_TYPE_KEY;
+	*pos++ = EAP_FAST_PAC_KEY_LEN;
+	os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
+	pos += EAP_FAST_PAC_KEY_LEN;
+
+	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
+	*pos++ = 4;
+	WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
+	pos += 4;
+
+	if (sm->identity) {
+		*pos++ = PAC_OPAQUE_TYPE_IDENTITY;
+		*pos++ = sm->identity_len;
+		os_memcpy(pos, sm->identity, sm->identity_len);
+		pos += sm->identity_len;
+	}
+
+	pac_len = pos - pac_buf;
+	while (pac_len % 8) {
+		*pos++ = PAC_OPAQUE_TYPE_PAD;
+		pac_len++;
+	}
+
+	pac_opaque = os_malloc(pac_len + 8);
+	if (pac_opaque == NULL) {
+		os_free(pac_buf);
+		return NULL;
+	}
+	if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
+		     pac_opaque) < 0) {
+		os_free(pac_buf);
+		os_free(pac_opaque);
+		return NULL;
+	}
+	os_free(pac_buf);
+
+	pac_len += 8;
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
+		    pac_opaque, pac_len);
+
+	buf_len = sizeof(*pac_tlv) +
+		sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN +
+		sizeof(struct pac_tlv_hdr) + pac_len +
+		data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
+	buf = wpabuf_alloc(buf_len);
+	if (buf == NULL) {
+		os_free(pac_opaque);
+		return NULL;
+	}
+
+	/* Result TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
+	result = wpabuf_put(buf, sizeof(*result));
+	WPA_PUT_BE16((u8 *) &result->tlv_type,
+		     EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV);
+	WPA_PUT_BE16((u8 *) &result->length, 2);
+	WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS);
+
+	/* PAC TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
+	pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
+	pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+					 EAP_TLV_PAC_TLV);
+
+	/* PAC-Key */
+	eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN);
+
+	/* PAC-Opaque */
+	eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
+	os_free(pac_opaque);
+
+	/* PAC-Info */
+	pac_info = wpabuf_put(buf, sizeof(*pac_info));
+	pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
+
+	/* PAC-Lifetime (inside PAC-Info) */
+	eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
+	wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
+
+	/* A-ID (inside PAC-Info) */
+	eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
+	
+	/* Note: headers may be misaligned after A-ID */
+
+	if (sm->identity) {
+		eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
+				 sm->identity_len);
+	}
+
+	/* A-ID-Info (inside PAC-Info) */
+	eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
+			 srv_id_info_len);
+
+	/* PAC-Type (inside PAC-Info) */
+	eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
+	wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
+
+	/* Update PAC-Info and PAC TLV Length fields */
+	pos = wpabuf_put(buf, 0);
+	pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
+	pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
+
+	return buf;
+}
+
+
+static int eap_fast_encrypt_phase2(struct eap_sm *sm,
+				   struct eap_fast_data *data,
+				   struct wpabuf *plain, int piggyback)
+{
+	struct wpabuf *encr;
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
+			    plain);
+	encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
+	wpabuf_free(plain);
+
+	if (data->ssl.tls_out && piggyback) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
+			   "(len=%d) with last Phase 1 Message (len=%d "
+			   "used=%d)",
+			   (int) wpabuf_len(encr),
+			   (int) wpabuf_len(data->ssl.tls_out),
+			   (int) data->ssl.tls_out_pos);
+		if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
+			wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize "
+				   "output buffer");
+			wpabuf_free(encr);
+			return -1;
+		}
+		wpabuf_put_buf(data->ssl.tls_out, encr);
+		wpabuf_free(encr);
+	} else {
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = encr;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_fast_data *data = priv;
+	struct wpabuf *req = NULL;
+	int piggyback = 0;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
+						data->fast_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+						data->fast_version, id);
+	}
+
+	switch (data->state) {
+	case START:
+		return eap_fast_build_start(sm, data, id);
+	case PHASE1:
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			if (eap_fast_phase1_done(sm, data) < 0)
+				return NULL;
+			if (data->state == PHASE2_START) {
+				/*
+				 * Try to generate Phase 2 data to piggyback
+				 * with the end of Phase 1 to avoid extra
+				 * roundtrip.
+				 */
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start "
+					   "Phase 2");
+				if (eap_fast_process_phase2_start(sm, data))
+					break;
+				req = eap_fast_build_phase2_req(sm, data, id);
+				piggyback = 1;
+			}
+		}
+		break;
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+		req = eap_fast_build_phase2_req(sm, data, id);
+		break;
+	case CRYPTO_BINDING:
+		req = eap_fast_build_crypto_binding(sm, data);
+		if (data->phase2_method) {
+			/*
+			 * Include the start of the next EAP method in the
+			 * sequence in the same message with Crypto-Binding to
+			 * save a round-trip.
+			 */
+			struct wpabuf *eap;
+			eap = eap_fast_build_phase2_req(sm, data, id);
+			req = wpabuf_concat(req, eap);
+			eap_fast_state(data, PHASE2_METHOD);
+		}
+		break;
+	case REQUEST_PAC:
+		req = eap_fast_build_pac(sm, data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+			   __func__, data->state);
+		return NULL;
+	}
+
+	if (req &&
+	    eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0)
+		return NULL;
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+					data->fast_version, id);
+}
+
+
+static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
+				EapType eap_type)
+{
+	if (data->phase2_priv && data->phase2_method) {
+		data->phase2_method->reset(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+	}
+	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
+							eap_type);
+	if (!data->phase2_method)
+		return -1;
+
+	if (data->key_block_p) {
+		sm->auth_challenge = data->key_block_p->server_challenge;
+		sm->peer_challenge = data->key_block_p->client_challenge;
+	}
+	sm->init_phase2 = 1;
+	data->phase2_priv = data->phase2_method->init(sm);
+	sm->init_phase2 = 0;
+	sm->auth_challenge = NULL;
+	sm->peer_challenge = NULL;
+
+	return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static void eap_fast_process_phase2_response(struct eap_sm *sm,
+					     struct eap_fast_data *data,
+					     u8 *in_data, size_t in_len)
+{
+	u8 next_type = EAP_TYPE_NONE;
+	struct eap_hdr *hdr;
+	u8 *pos;
+	size_t left;
+	struct wpabuf buf;
+	const struct eap_method *m = data->phase2_method;
+	void *priv = data->phase2_priv;
+
+	if (priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
+			   "initialized?!", __func__);
+		return;
+	}
+
+	hdr = (struct eap_hdr *) in_data;
+	pos = (u8 *) (hdr + 1);
+
+	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = in_len - sizeof(*hdr);
+		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
+			    "allowed types", pos + 1, left - 1);
+#ifdef EAP_SERVER_TNC
+		if (m && m->vendor == EAP_VENDOR_IETF &&
+		    m->method == EAP_TYPE_TNC) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
+				   "TNC negotiation");
+			next_type = eap_fast_req_failure(sm, data);
+			eap_fast_phase2_init(sm, data, next_type);
+			return;
+		}
+#endif /* EAP_SERVER_TNC */
+		eap_sm_process_nak(sm, pos + 1, left - 1);
+		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+		    sm->user->methods[sm->user_eap_method_index].method !=
+		    EAP_TYPE_NONE) {
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
+			wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
+				   next_type);
+		} else {
+			next_type = eap_fast_req_failure(sm, data);
+		}
+		eap_fast_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	wpabuf_set(&buf, in_data, in_len);
+
+	if (m->check(sm, priv, &buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
+			   "ignore the packet");
+		next_type = eap_fast_req_failure(sm, data);
+		return;
+	}
+
+	m->process(sm, priv, &buf);
+
+	if (!m->isDone(sm, priv))
+		return;
+
+	if (!m->isSuccess(sm, priv)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+		next_type = eap_fast_req_failure(sm, data);
+		eap_fast_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	switch (data->state) {
+	case PHASE2_ID:
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			next_type = eap_fast_req_failure(sm, data);
+			break;
+		}
+
+		eap_fast_state(data, PHASE2_METHOD);
+		if (data->anon_provisioning) {
+			/*
+			 * Only EAP-MSCHAPv2 is allowed for anonymous
+			 * provisioning.
+			 */
+			next_type = EAP_TYPE_MSCHAPV2;
+			sm->user_eap_method_index = 0;
+		} else {
+			next_type = sm->user->methods[0].method;
+			sm->user_eap_method_index = 1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+		break;
+	case PHASE2_METHOD:
+	case CRYPTO_BINDING:
+		eap_fast_update_icmk(sm, data);
+		eap_fast_state(data, CRYPTO_BINDING);
+		data->eap_seq++;
+		next_type = EAP_TYPE_NONE;
+#ifdef EAP_SERVER_TNC
+		if (sm->tnc && !data->tnc_started) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+			next_type = EAP_TYPE_TNC;
+			data->tnc_started = 1;
+		}
+#endif /* EAP_SERVER_TNC */
+		break;
+	case FAILURE:
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+			   __func__, data->state);
+		break;
+	}
+
+	eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_phase2_eap(struct eap_sm *sm,
+					struct eap_fast_data *data,
+					u8 *in_data, size_t in_len)
+{
+	struct eap_hdr *hdr;
+	size_t len;
+
+	hdr = (struct eap_hdr *) in_data;
+	if (in_len < (int) sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
+			   "EAP frame (len=%lu)", (unsigned long) in_len);
+		eap_fast_req_failure(sm, data);
+		return;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > in_len) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
+			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+			   (unsigned long) in_len, (unsigned long) len);
+		eap_fast_req_failure(sm, data);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
+		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
+		   (unsigned long) len);
+	switch (hdr->code) {
+	case EAP_CODE_RESPONSE:
+		eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+}
+
+
+static int eap_fast_parse_tlvs(struct wpabuf *data,
+			       struct eap_fast_tlv_parse *tlv)
+{
+	int mandatory, tlv_type, len, res;
+	u8 *pos, *end;
+
+	os_memset(tlv, 0, sizeof(*tlv));
+
+	pos = wpabuf_mhead(data);
+	end = pos + wpabuf_len(data);
+	while (pos + 4 < end) {
+		mandatory = pos[0] & 0x80;
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + len > end) {
+			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
+			   "TLV type %d length %d%s",
+			   tlv_type, len, mandatory ? " (mandatory)" : "");
+
+		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
+		if (res == -2)
+			break;
+		if (res < 0) {
+			if (mandatory) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
+					   "mandatory TLV type %d", tlv_type);
+				/* TODO: generate Nak TLV */
+				break;
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
+					   "unknown optional TLV type %d",
+					   tlv_type);
+			}
+		}
+
+		pos += len;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_validate_crypto_binding(
+	struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
+	size_t bind_len)
+{
+	u8 cmac[SHA1_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
+		   "Version %d Received Version %d SubType %d",
+		   b->version, b->received_version, b->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    b->nonce, sizeof(b->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    b->compound_mac, sizeof(b->compound_mac));
+
+	if (b->version != EAP_FAST_VERSION ||
+	    b->received_version != EAP_FAST_VERSION) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
+			   "in Crypto-Binding: version %d "
+			   "received_version %d", b->version,
+			   b->received_version);
+		return -1;
+	}
+
+	if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
+			   "Crypto-Binding: %d", b->subtype);
+		return -1;
+	}
+
+	if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+	    (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
+			   "Crypto-Binding");
+		return -1;
+	}
+
+	os_memcpy(cmac, b->compound_mac, sizeof(cmac));
+	os_memset(b->compound_mac, 0, sizeof(cmac));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
+		    "Compound MAC calculation",
+		    (u8 *) b, bind_len);
+	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
+		  b->compound_mac);
+	if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+		wpa_hexdump(MSG_MSGDUMP,
+			    "EAP-FAST: Calculated Compound MAC",
+			    b->compound_mac, sizeof(cmac));
+		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
+			   "match");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
+{
+	struct eap_tlv_pac_type_tlv *tlv;
+
+	if (pac == NULL || len != sizeof(*tlv))
+		return 0;
+
+	tlv = (struct eap_tlv_pac_type_tlv *) pac;
+
+	return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
+		be_to_host16(tlv->length) == 2 &&
+		be_to_host16(tlv->pac_type) == type;
+}
+
+
+static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
+					 struct eap_fast_data *data,
+					 struct wpabuf *in_data)
+{
+	struct eap_fast_tlv_parse tlv;
+	int check_crypto_binding = data->state == CRYPTO_BINDING;
+
+	if (eap_fast_parse_tlvs(in_data, &tlv) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received "
+			   "Phase 2 TLVs");
+		return;
+	}
+
+	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated "
+			   "failure");
+		eap_fast_state(data, FAILURE);
+		return;
+	}
+
+	if (data->state == REQUEST_PAC) {
+		u16 type, len, res;
+		if (tlv.pac == NULL || tlv.pac_len < 6) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC "
+				   "Acknowledgement received");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		type = WPA_GET_BE16(tlv.pac);
+		len = WPA_GET_BE16(tlv.pac + 2);
+		res = WPA_GET_BE16(tlv.pac + 4);
+
+		if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
+		    res != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not "
+				   "contain acknowledgement");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received "
+			   "- PAC provisioning succeeded");
+		eap_fast_state(data, (data->anon_provisioning ||
+				      data->send_new_pac == 2) ?
+			       FAILURE : SUCCESS);
+		return;
+	}
+
+	if (check_crypto_binding) {
+		if (tlv.crypto_binding == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
+				   "TLV received");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (data->final_result &&
+		    tlv.result != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+				   "without Success Result");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (!data->final_result &&
+		    tlv.iresult != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+				   "without intermediate Success Result");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding,
+						     tlv.crypto_binding_len)) {
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
+			   "received");
+		if (data->final_result) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+				   "completed successfully");
+		}
+
+		if (data->anon_provisioning &&
+		    sm->eap_fast_prov != ANON_PROV &&
+		    sm->eap_fast_prov != BOTH_PROV) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
+				   "use unauthenticated provisioning which is "
+				   "disabled");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (sm->eap_fast_prov != AUTH_PROV &&
+		    sm->eap_fast_prov != BOTH_PROV &&
+		    tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
+		    eap_fast_pac_type(tlv.pac, tlv.pac_len,
+				      PAC_TYPE_TUNNEL_PAC)) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to "
+				   "use authenticated provisioning which is "
+				   "disabled");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (data->anon_provisioning ||
+		    (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
+		     eap_fast_pac_type(tlv.pac, tlv.pac_len,
+				       PAC_TYPE_TUNNEL_PAC))) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new "
+				   "Tunnel PAC");
+			eap_fast_state(data, REQUEST_PAC);
+		} else if (data->send_new_pac) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
+				   "re-keying of Tunnel PAC");
+			eap_fast_state(data, REQUEST_PAC);
+		} else if (data->final_result)
+			eap_fast_state(data, SUCCESS);
+	}
+
+	if (tlv.eap_payload_tlv) {
+		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+					    tlv.eap_payload_tlv_len);
+	}
+}
+
+
+static void eap_fast_process_phase2(struct eap_sm *sm,
+				    struct eap_fast_data *data,
+				    struct wpabuf *in_buf)
+{
+	struct wpabuf *in_decrypted;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
+
+	if (data->pending_phase2_resp) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
+			   "skip decryption and use old data");
+		eap_fast_process_phase2_tlvs(sm, data,
+					     data->pending_phase2_resp);
+		wpabuf_free(data->pending_phase2_resp);
+		data->pending_phase2_resp = NULL;
+		return;
+	}
+
+	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+					      in_buf);
+	if (in_decrypted == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
+			   "data");
+		eap_fast_state(data, FAILURE);
+		return;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs",
+			    in_decrypted);
+
+	eap_fast_process_phase2_tlvs(sm, data, in_decrypted);
+
+	if (sm->method_pending == METHOD_PENDING_WAIT) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in "
+			   "pending wait state - save decrypted response");
+		wpabuf_free(data->pending_phase2_resp);
+		data->pending_phase2_resp = in_decrypted;
+		return;
+	}
+
+	wpabuf_free(in_decrypted);
+}
+
+
+static int eap_fast_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
+{
+	struct eap_fast_data *data = priv;
+
+	data->peer_version = peer_version;
+
+	if (data->force_version >= 0 && peer_version != data->force_version) {
+		wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
+			   " version (forced=%d peer=%d) - reject",
+			   data->force_version, peer_version);
+		return -1;
+	}
+
+	if (peer_version < data->fast_version) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
+			   "use version %d",
+			   peer_version, data->fast_version, peer_version);
+		data->fast_version = peer_version;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_process_phase1(struct eap_sm *sm,
+				   struct eap_fast_data *data)
+{
+	if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
+		eap_fast_state(data, FAILURE);
+		return -1;
+	}
+
+	if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+	    wpabuf_len(data->ssl.tls_out) > 0)
+		return 1;
+
+	/*
+	 * Phase 1 was completed with the received message (e.g., when using
+	 * abbreviated handshake), so Phase 2 can be started immediately
+	 * without having to send through an empty message to the peer.
+	 */
+
+	return eap_fast_phase1_done(sm, data);
+}
+
+
+static int eap_fast_process_phase2_start(struct eap_sm *sm,
+					 struct eap_fast_data *data)
+{
+	u8 next_type;
+
+	if (data->identity) {
+		os_free(sm->identity);
+		sm->identity = data->identity;
+		data->identity = NULL;
+		sm->identity_len = data->identity_len;
+		data->identity_len = 0;
+		sm->require_identity_match = 1;
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: "
+					  "Phase2 Identity not found "
+					  "in the user database",
+					  sm->identity, sm->identity_len);
+			next_type = eap_fast_req_failure(sm, data);
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
+				   "known - skip Phase 2 Identity Request");
+			next_type = sm->user->methods[0].method;
+			sm->user_eap_method_index = 1;
+		}
+
+		eap_fast_state(data, PHASE2_METHOD);
+	} else {
+		eap_fast_state(data, PHASE2_ID);
+		next_type = EAP_TYPE_IDENTITY;
+	}
+
+	return eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_fast_data *data = priv;
+
+	switch (data->state) {
+	case PHASE1:
+		if (eap_fast_process_phase1(sm, data))
+			break;
+
+		/* fall through to PHASE2_START */
+	case PHASE2_START:
+		eap_fast_process_phase2_start(sm, data);
+		break;
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+	case CRYPTO_BINDING:
+	case REQUEST_PAC:
+		eap_fast_process_phase2(sm, data, data->ssl.tls_in);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
+			   data->state, __func__);
+		break;
+	}
+}
+
+
+static void eap_fast_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_fast_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_FAST, eap_fast_process_version,
+				   eap_fast_process_msg) < 0)
+		eap_fast_state(data, FAILURE);
+}
+
+
+static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
+	if (eapKeyData == NULL)
+		return NULL;
+
+	eap_fast_derive_eap_msk(data->simck, eapKeyData);
+	*len = EAP_FAST_KEY_LEN;
+
+	return eapKeyData;
+}
+
+
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = os_malloc(EAP_EMSK_LEN);
+	if (eapKeyData == NULL)
+		return NULL;
+
+	eap_fast_derive_eap_emsk(data->simck, eapKeyData);
+	*len = EAP_EMSK_LEN;
+
+	return eapKeyData;
+}
+
+
+static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_fast_init;
+	eap->reset = eap_fast_reset;
+	eap->buildReq = eap_fast_buildReq;
+	eap->check = eap_fast_check;
+	eap->process = eap_fast_process;
+	eap->isDone = eap_fast_isDone;
+	eap->getKey = eap_fast_getKey;
+	eap->get_emsk = eap_fast_get_emsk;
+	eap->isSuccess = eap_fast_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_gpsk.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,633 +0,0 @@
-/*
- * hostapd / EAP-GPSK (RFC 5433) server
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap_i.h"
-#include "eap_common/eap_gpsk_common.h"
-
-
-struct eap_gpsk_data {
-	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
-	u8 rand_server[EAP_GPSK_RAND_LEN];
-	u8 rand_peer[EAP_GPSK_RAND_LEN];
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 sk[EAP_GPSK_MAX_SK_LEN];
-	size_t sk_len;
-	u8 pk[EAP_GPSK_MAX_PK_LEN];
-	size_t pk_len;
-	u8 *id_peer;
-	size_t id_peer_len;
-	u8 *id_server;
-	size_t id_server_len;
-#define MAX_NUM_CSUITES 2
-	struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
-	size_t csuite_count;
-	int vendor; /* CSuite/Vendor */
-	int specifier; /* CSuite/Specifier */
-};
-
-
-static const char * eap_gpsk_state_txt(int state)
-{
-	switch (state) {
-	case GPSK_1:
-		return "GPSK-1";
-	case GPSK_3:
-		return "GPSK-3";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
-		   eap_gpsk_state_txt(data->state),
-		   eap_gpsk_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_gpsk_init(struct eap_sm *sm)
-{
-	struct eap_gpsk_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = GPSK_1;
-
-	/* TODO: add support for configuring ID_Server */
-	data->id_server = (u8 *) os_strdup("hostapd");
-	if (data->id_server)
-		data->id_server_len = os_strlen((char *) data->id_server);
-
-	data->csuite_count = 0;
-	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
-					   EAP_GPSK_CIPHER_AES)) {
-		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
-			     EAP_GPSK_VENDOR_IETF);
-		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
-			     EAP_GPSK_CIPHER_AES);
-		data->csuite_count++;
-	}
-	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
-					   EAP_GPSK_CIPHER_SHA256)) {
-		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
-			     EAP_GPSK_VENDOR_IETF);
-		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
-			     EAP_GPSK_CIPHER_SHA256);
-		data->csuite_count++;
-	}
-
-	return data;
-}
-
-
-static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_gpsk_data *data = priv;
-	os_free(data->id_server);
-	os_free(data->id_peer);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
-					     struct eap_gpsk_data *data, u8 id)
-{
-	size_t len;
-	struct wpabuf *req;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
-
-	if (os_get_random(data->rand_server, EAP_GPSK_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
-		    data->rand_server, EAP_GPSK_RAND_LEN);
-
-	len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
-		data->csuite_count * sizeof(struct eap_gpsk_csuite);
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
-			   "for request/GPSK-1");
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
-	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
-	wpabuf_put_be16(req,
-			data->csuite_count * sizeof(struct eap_gpsk_csuite));
-	wpabuf_put_data(req, data->csuite_list,
-			data->csuite_count * sizeof(struct eap_gpsk_csuite));
-
-	return req;
-}
-
-
-static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
-					     struct eap_gpsk_data *data, u8 id)
-{
-	u8 *pos, *start;
-	size_t len, miclen;
-	struct eap_gpsk_csuite *csuite;
-	struct wpabuf *req;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
-
-	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
-		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
-			   "for request/GPSK-3");
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3);
-	start = wpabuf_put(req, 0);
-
-	wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
-	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
-	wpabuf_put_be16(req, data->id_server_len);
-	wpabuf_put_data(req, data->id_server, data->id_server_len);
-	csuite = wpabuf_put(req, sizeof(*csuite));
-	WPA_PUT_BE32(csuite->vendor, data->vendor);
-	WPA_PUT_BE16(csuite->specifier, data->specifier);
-
-	/* no PD_Payload_2 */
-	wpabuf_put_be16(req, 0);
-
-	pos = wpabuf_put(req, miclen);
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, start, pos - start, pos) < 0)
-	{
-		os_free(req);
-		eap_gpsk_state(data, FAILURE);
-		return NULL;
-	}
-
-	return req;
-}
-
-
-static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_gpsk_data *data = priv;
-
-	switch (data->state) {
-	case GPSK_1:
-		return eap_gpsk_build_gpsk_1(sm, data, id);
-	case GPSK_3:
-		return eap_gpsk_build_gpsk_3(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
-			   data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	struct eap_gpsk_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
-		return TRUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
-
-	if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
-		return FALSE;
-
-	if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
-		return FALSE;
-
-	wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
-		   *pos, data->state);
-
-	return TRUE;
-}
-
-
-static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
-				    struct eap_gpsk_data *data,
-				    const u8 *payload, size_t payloadlen)
-{
-	const u8 *pos, *end;
-	u16 alen;
-	const struct eap_gpsk_csuite *csuite;
-	size_t i, miclen;
-	u8 mic[EAP_GPSK_MAX_MIC_LEN];
-
-	if (data->state != GPSK_1)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
-
-	pos = payload;
-	end = payload + payloadlen;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "ID_Peer length");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "ID_Peer");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	os_free(data->id_peer);
-	data->id_peer = os_malloc(alen);
-	if (data->id_peer == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
-			   "%d-octet ID_Peer", alen);
-		return;
-	}
-	os_memcpy(data->id_peer, pos, alen);
-	data->id_peer_len = alen;
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
-			  data->id_peer, data->id_peer_len);
-	pos += alen;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "ID_Server length");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "ID_Server");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (alen != data->id_server_len ||
-	    os_memcmp(pos, data->id_server, alen) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
-			   "GPSK-2 did not match");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	pos += alen;
-
-	if (end - pos < EAP_GPSK_RAND_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "RAND_Peer");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
-		    data->rand_peer, EAP_GPSK_RAND_LEN);
-	pos += EAP_GPSK_RAND_LEN;
-
-	if (end - pos < EAP_GPSK_RAND_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "RAND_Server");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
-			   "GPSK-2 did not match");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
-			    data->rand_server, EAP_GPSK_RAND_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
-			    pos, EAP_GPSK_RAND_LEN);
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	pos += EAP_GPSK_RAND_LEN;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "CSuite_List length");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "CSuite_List");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
-	    os_memcmp(pos, data->csuite_list, alen) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
-			   "GPSK-2 did not match");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	pos += alen;
-
-	if (end - pos < (int) sizeof(*csuite)) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "CSuite_Sel");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	csuite = (const struct eap_gpsk_csuite *) pos;
-	for (i = 0; i < data->csuite_count; i++) {
-		if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
-		    == 0)
-			break;
-	}
-	if (i == data->csuite_count) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
-			   "ciphersuite %d:%d",
-			   WPA_GET_BE32(csuite->vendor),
-			   WPA_GET_BE16(csuite->specifier));
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	data->vendor = WPA_GET_BE32(csuite->vendor);
-	data->specifier = WPA_GET_BE16(csuite->specifier);
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
-		   data->vendor, data->specifier);
-	pos += sizeof(*csuite);	
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "PD_Payload_1 length");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "PD_Payload_1");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
-	pos += alen;
-
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
-			   "for the user");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-
-	if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
-				 data->vendor, data->specifier,
-				 data->rand_peer, data->rand_server,
-				 data->id_peer, data->id_peer_len,
-				 data->id_server, data->id_server_len,
-				 data->msk, data->emsk,
-				 data->sk, &data->sk_len,
-				 data->pk, &data->pk_len) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-
-	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	if (end - pos < (int) miclen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
-			   "(left=%lu miclen=%lu)",
-			   (unsigned long) (end - pos),
-			   (unsigned long) miclen);
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, payload, pos - payload, mic)
-	    < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (os_memcmp(mic, pos, miclen) != 0) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	pos += miclen;
-
-	if (pos != end) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
-			   "data in the end of GPSK-2",
-			   (unsigned long) (end - pos));
-	}
-
-	eap_gpsk_state(data, GPSK_3);
-}
-
-
-static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
-				    struct eap_gpsk_data *data,
-				    const u8 *payload, size_t payloadlen)
-{
-	const u8 *pos, *end;
-	u16 alen;
-	size_t miclen;
-	u8 mic[EAP_GPSK_MAX_MIC_LEN];
-
-	if (data->state != GPSK_3)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
-
-	pos = payload;
-	end = payload + payloadlen;
-
-	if (end - pos < 2) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "PD_Payload_1 length");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	alen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < alen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
-			   "PD_Payload_1");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
-	pos += alen;
-
-	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
-	if (end - pos < (int) miclen) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
-			   "(left=%lu miclen=%lu)",
-			   (unsigned long) (end - pos),
-			   (unsigned long) miclen);
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
-				 data->specifier, payload, pos - payload, mic)
-	    < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	if (os_memcmp(mic, pos, miclen) != 0) {
-		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
-		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	pos += miclen;
-
-	if (pos != end) {
-		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
-			   "data in the end of GPSK-4",
-			   (unsigned long) (end - pos));
-	}
-
-	eap_gpsk_state(data, SUCCESS);
-}
-
-
-static void eap_gpsk_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_gpsk_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
-	if (pos == NULL || len < 1)
-		return;
-
-	switch (*pos) {
-	case EAP_GPSK_OPCODE_GPSK_2:
-		eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1);
-		break;
-	case EAP_GPSK_OPCODE_GPSK_4:
-		eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1);
-		break;
-	}
-}
-
-
-static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_gpsk_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_gpsk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-	*len = EAP_MSK_LEN;
-
-	return key;
-}
-
-
-static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_gpsk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-
-	return key;
-}
-
-
-static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_gpsk_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_gpsk_init;
-	eap->reset = eap_gpsk_reset;
-	eap->buildReq = eap_gpsk_buildReq;
-	eap->check = eap_gpsk_check;
-	eap->process = eap_gpsk_process;
-	eap->isDone = eap_gpsk_isDone;
-	eap->getKey = eap_gpsk_getKey;
-	eap->isSuccess = eap_gpsk_isSuccess;
-	eap->get_emsk = eap_gpsk_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_gpsk.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_gpsk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,628 @@
+/*
+ * hostapd / EAP-GPSK (RFC 5433) server
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_gpsk_common.h"
+
+
+struct eap_gpsk_data {
+	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
+	u8 rand_server[EAP_GPSK_RAND_LEN];
+	u8 rand_peer[EAP_GPSK_RAND_LEN];
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 sk[EAP_GPSK_MAX_SK_LEN];
+	size_t sk_len;
+	u8 pk[EAP_GPSK_MAX_PK_LEN];
+	size_t pk_len;
+	u8 *id_peer;
+	size_t id_peer_len;
+	u8 *id_server;
+	size_t id_server_len;
+#define MAX_NUM_CSUITES 2
+	struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
+	size_t csuite_count;
+	int vendor; /* CSuite/Vendor */
+	int specifier; /* CSuite/Specifier */
+};
+
+
+static const char * eap_gpsk_state_txt(int state)
+{
+	switch (state) {
+	case GPSK_1:
+		return "GPSK-1";
+	case GPSK_3:
+		return "GPSK-3";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
+		   eap_gpsk_state_txt(data->state),
+		   eap_gpsk_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_gpsk_init(struct eap_sm *sm)
+{
+	struct eap_gpsk_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = GPSK_1;
+
+	/* TODO: add support for configuring ID_Server */
+	data->id_server = (u8 *) os_strdup("hostapd");
+	if (data->id_server)
+		data->id_server_len = os_strlen((char *) data->id_server);
+
+	data->csuite_count = 0;
+	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+					   EAP_GPSK_CIPHER_AES)) {
+		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
+			     EAP_GPSK_VENDOR_IETF);
+		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
+			     EAP_GPSK_CIPHER_AES);
+		data->csuite_count++;
+	}
+	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+					   EAP_GPSK_CIPHER_SHA256)) {
+		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
+			     EAP_GPSK_VENDOR_IETF);
+		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
+			     EAP_GPSK_CIPHER_SHA256);
+		data->csuite_count++;
+	}
+
+	return data;
+}
+
+
+static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	os_free(data->id_server);
+	os_free(data->id_peer);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
+					     struct eap_gpsk_data *data, u8 id)
+{
+	size_t len;
+	struct wpabuf *req;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
+
+	if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
+		    data->rand_server, EAP_GPSK_RAND_LEN);
+
+	len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+		data->csuite_count * sizeof(struct eap_gpsk_csuite);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+			   "for request/GPSK-1");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1);
+	wpabuf_put_be16(req, data->id_server_len);
+	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
+	wpabuf_put_be16(req,
+			data->csuite_count * sizeof(struct eap_gpsk_csuite));
+	wpabuf_put_data(req, data->csuite_list,
+			data->csuite_count * sizeof(struct eap_gpsk_csuite));
+
+	return req;
+}
+
+
+static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
+					     struct eap_gpsk_data *data, u8 id)
+{
+	u8 *pos, *start;
+	size_t len, miclen;
+	struct eap_gpsk_csuite *csuite;
+	struct wpabuf *req;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len +
+		sizeof(struct eap_gpsk_csuite) + 2 + miclen;
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+			   "for request/GPSK-3");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3);
+	start = wpabuf_put(req, 0);
+
+	wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN);
+	wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN);
+	wpabuf_put_be16(req, data->id_server_len);
+	wpabuf_put_data(req, data->id_server, data->id_server_len);
+	csuite = wpabuf_put(req, sizeof(*csuite));
+	WPA_PUT_BE32(csuite->vendor, data->vendor);
+	WPA_PUT_BE16(csuite->specifier, data->specifier);
+
+	/* no PD_Payload_2 */
+	wpabuf_put_be16(req, 0);
+
+	pos = wpabuf_put(req, miclen);
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, start, pos - start, pos) < 0)
+	{
+		os_free(req);
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_gpsk_data *data = priv;
+
+	switch (data->state) {
+	case GPSK_1:
+		return eap_gpsk_build_gpsk_1(sm, data, id);
+	case GPSK_3:
+		return eap_gpsk_build_gpsk_3(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	struct eap_gpsk_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
+		return TRUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
+
+	if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
+		return FALSE;
+
+	if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
+		   *pos, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
+				    struct eap_gpsk_data *data,
+				    const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	u16 alen;
+	const struct eap_gpsk_csuite *csuite;
+	size_t i, miclen;
+	u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+	if (data->state != GPSK_1)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Peer length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Peer");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	os_free(data->id_peer);
+	data->id_peer = os_malloc(alen);
+	if (data->id_peer == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
+			   "%d-octet ID_Peer", alen);
+		return;
+	}
+	os_memcpy(data->id_peer, pos, alen);
+	data->id_peer_len = alen;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer",
+			  data->id_peer, data->id_peer_len);
+	pos += alen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Server length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Server");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (alen != data->id_server_len ||
+	    os_memcmp(pos, data->id_server, alen) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
+			   "GPSK-2 did not match");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += alen;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "RAND_Peer");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer",
+		    data->rand_peer, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "RAND_Server");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
+			   "GPSK-2 did not match");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
+			    data->rand_server, EAP_GPSK_RAND_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
+			    pos, EAP_GPSK_RAND_LEN);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += EAP_GPSK_RAND_LEN;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_List length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_List");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
+	    os_memcmp(pos, data->csuite_list, alen) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
+			   "GPSK-2 did not match");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += alen;
+
+	if (end - pos < (int) sizeof(*csuite)) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_Sel");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	csuite = (const struct eap_gpsk_csuite *) pos;
+	for (i = 0; i < data->csuite_count; i++) {
+		if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite))
+		    == 0)
+			break;
+	}
+	if (i == data->csuite_count) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
+			   "ciphersuite %d:%d",
+			   WPA_GET_BE32(csuite->vendor),
+			   WPA_GET_BE16(csuite->specifier));
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	data->vendor = WPA_GET_BE32(csuite->vendor);
+	data->specifier = WPA_GET_BE16(csuite->specifier);
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
+		   data->vendor, data->specifier);
+	pos += sizeof(*csuite);	
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1 length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+	pos += alen;
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
+			   "for the user");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+
+	if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
+				 data->vendor, data->specifier,
+				 data->rand_peer, data->rand_server,
+				 data->id_peer, data->id_peer_len,
+				 data->id_server, data->id_server_len,
+				 data->msk, data->emsk,
+				 data->sk, &data->sk_len,
+				 data->pk, &data->pk_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	if (end - pos < (int) miclen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+			   "(left=%lu miclen=%lu)",
+			   (unsigned long) (end - pos),
+			   (unsigned long) miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, payload, pos - payload, mic)
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (os_memcmp(mic, pos, miclen) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += miclen;
+
+	if (pos != end) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
+			   "data in the end of GPSK-2",
+			   (unsigned long) (end - pos));
+	}
+
+	eap_gpsk_state(data, GPSK_3);
+}
+
+
+static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
+				    struct eap_gpsk_data *data,
+				    const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	u16 alen;
+	size_t miclen;
+	u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+	if (data->state != GPSK_3)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1 length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+	pos += alen;
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	if (end - pos < (int) miclen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+			   "(left=%lu miclen=%lu)",
+			   (unsigned long) (end - pos),
+			   (unsigned long) miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, payload, pos - payload, mic)
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (os_memcmp(mic, pos, miclen) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += miclen;
+
+	if (pos != end) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra "
+			   "data in the end of GPSK-4",
+			   (unsigned long) (end - pos));
+	}
+
+	eap_gpsk_state(data, SUCCESS);
+}
+
+
+static void eap_gpsk_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_gpsk_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	switch (*pos) {
+	case EAP_GPSK_OPCODE_GPSK_2:
+		eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1);
+		break;
+	case EAP_GPSK_OPCODE_GPSK_4:
+		eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1);
+		break;
+	}
+}
+
+
+static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gpsk_init;
+	eap->reset = eap_gpsk_reset;
+	eap->buildReq = eap_gpsk_buildReq;
+	eap->check = eap_gpsk_check;
+	eap->process = eap_gpsk_process;
+	eap->isDone = eap_gpsk_isDone;
+	eap->getKey = eap_gpsk_getKey;
+	eap->isSuccess = eap_gpsk_isSuccess;
+	eap->get_emsk = eap_gpsk_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_gtc.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_gtc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_gtc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,230 +0,0 @@
-/*
- * hostapd / EAP-GTC (RFC 3748)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-
-
-struct eap_gtc_data {
-	enum { CONTINUE, SUCCESS, FAILURE } state;
-	int prefix;
-};
-
-
-static void * eap_gtc_init(struct eap_sm *sm)
-{
-	struct eap_gtc_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = CONTINUE;
-
-#ifdef EAP_SERVER_FAST
-	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
-	    sm->m->method == EAP_TYPE_FAST) {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
-			   "with challenge/response");
-		data->prefix = 1;
-	}
-#endif /* EAP_SERVER_FAST */
-
-	return data;
-}
-
-
-static void eap_gtc_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_gtc_data *data = priv;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_gtc_data *data = priv;
-	struct wpabuf *req;
-	char *msg;
-	size_t msg_len;
-
-	msg = data->prefix ? "CHALLENGE=Password" : "Password";
-
-	msg_len = os_strlen(msg);
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpabuf_put_data(req, msg, msg_len);
-
-	data->state = CONTINUE;
-
-	return req;
-}
-
-
-static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_gtc_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_gtc_data *data = priv;
-	const u8 *pos;
-	size_t rlen;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen);
-	if (pos == NULL || rlen < 1)
-		return; /* Should not happen - frame already validated */
-
-	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
-
-#ifdef EAP_SERVER_FAST
-	if (data->prefix) {
-		const u8 *pos2, *end;
-		/* "RESPONSE=<user>\0<password>" */
-		if (rlen < 10) {
-			wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
-				   "for EAP-FAST prefix");
-			data->state = FAILURE;
-			return;
-		}
-
-		end = pos + rlen;
-		pos += 9;
-		pos2 = pos;
-		while (pos2 < end && *pos2)
-			pos2++;
-		if (pos2 == end) {
-			wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
-				   "response to EAP-FAST prefix");
-			data->state = FAILURE;
-			return;
-		}
-
-		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
-				  pos, pos2 - pos);
-		if (sm->identity && sm->require_identity_match &&
-		    (pos2 - pos != (int) sm->identity_len ||
-		     os_memcmp(pos, sm->identity, sm->identity_len))) {
-			wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
-				   "not match with required Identity");
-			wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
-					  "identity",
-					  sm->identity, sm->identity_len);
-			data->state = FAILURE;
-			return;
-		} else {
-			os_free(sm->identity);
-			sm->identity_len = pos2 - pos;
-			sm->identity = os_malloc(sm->identity_len);
-			if (sm->identity == NULL) {
-				data->state = FAILURE;
-				return;
-			}
-			os_memcpy(sm->identity, pos, sm->identity_len);
-		}
-
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
-					  "Identity not found in the user "
-					  "database",
-					  sm->identity, sm->identity_len);
-			data->state = FAILURE;
-			return;
-		}
-
-		pos = pos2 + 1;
-		rlen = end - pos;
-		wpa_hexdump_ascii_key(MSG_MSGDUMP,
-				      "EAP-GTC: Response password",
-				      pos, rlen);
-	}
-#endif /* EAP_SERVER_FAST */
-
-	if (sm->user == NULL || sm->user->password == NULL ||
-	    sm->user->password_hash) {
-		wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
-			   "configured");
-		data->state = FAILURE;
-		return;
-	}
-
-	if (rlen != sm->user->password_len ||
-	    os_memcmp(pos, sm->user->password, rlen) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
-		data->state = FAILURE;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
-		data->state = SUCCESS;
-	}
-}
-
-
-static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_gtc_data *data = priv;
-	return data->state != CONTINUE;
-}
-
-
-static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_gtc_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_gtc_init;
-	eap->reset = eap_gtc_reset;
-	eap->buildReq = eap_gtc_buildReq;
-	eap->check = eap_gtc_check;
-	eap->process = eap_gtc_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_gtc.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_gtc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_gtc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_gtc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,224 @@
+/*
+ * hostapd / EAP-GTC (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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 "eap_i.h"
+
+
+struct eap_gtc_data {
+	enum { CONTINUE, SUCCESS, FAILURE } state;
+	int prefix;
+};
+
+
+static void * eap_gtc_init(struct eap_sm *sm)
+{
+	struct eap_gtc_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CONTINUE;
+
+#ifdef EAP_SERVER_FAST
+	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+	    sm->m->method == EAP_TYPE_FAST) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+			   "with challenge/response");
+		data->prefix = 1;
+	}
+#endif /* EAP_SERVER_FAST */
+
+	return data;
+}
+
+
+static void eap_gtc_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_gtc_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_gtc_data *data = priv;
+	struct wpabuf *req;
+	char *msg;
+	size_t msg_len;
+
+	msg = data->prefix ? "CHALLENGE=Password" : "Password";
+
+	msg_len = os_strlen(msg);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpabuf_put_data(req, msg, msg_len);
+
+	data->state = CONTINUE;
+
+	return req;
+}
+
+
+static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_gtc_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_gtc_data *data = priv;
+	const u8 *pos;
+	size_t rlen;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen);
+	if (pos == NULL || rlen < 1)
+		return; /* Should not happen - frame already validated */
+
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
+
+#ifdef EAP_SERVER_FAST
+	if (data->prefix) {
+		const u8 *pos2, *end;
+		/* "RESPONSE=<user>\0<password>" */
+		if (rlen < 10) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
+				   "for EAP-FAST prefix");
+			data->state = FAILURE;
+			return;
+		}
+
+		end = pos + rlen;
+		pos += 9;
+		pos2 = pos;
+		while (pos2 < end && *pos2)
+			pos2++;
+		if (pos2 == end) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
+				   "response to EAP-FAST prefix");
+			data->state = FAILURE;
+			return;
+		}
+
+		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
+				  pos, pos2 - pos);
+		if (sm->identity && sm->require_identity_match &&
+		    (pos2 - pos != (int) sm->identity_len ||
+		     os_memcmp(pos, sm->identity, sm->identity_len))) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
+				   "not match with required Identity");
+			wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
+					  "identity",
+					  sm->identity, sm->identity_len);
+			data->state = FAILURE;
+			return;
+		} else {
+			os_free(sm->identity);
+			sm->identity_len = pos2 - pos;
+			sm->identity = os_malloc(sm->identity_len);
+			if (sm->identity == NULL) {
+				data->state = FAILURE;
+				return;
+			}
+			os_memcpy(sm->identity, pos, sm->identity_len);
+		}
+
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			data->state = FAILURE;
+			return;
+		}
+
+		pos = pos2 + 1;
+		rlen = end - pos;
+		wpa_hexdump_ascii_key(MSG_MSGDUMP,
+				      "EAP-GTC: Response password",
+				      pos, rlen);
+	}
+#endif /* EAP_SERVER_FAST */
+
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_hash) {
+		wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
+			   "configured");
+		data->state = FAILURE;
+		return;
+	}
+
+	if (rlen != sm->user->password_len ||
+	    os_memcmp(pos, sm->user->password, rlen) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
+		data->state = FAILURE;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
+		data->state = SUCCESS;
+	}
+}
+
+
+static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_gtc_data *data = priv;
+	return data->state != CONTINUE;
+}
+
+
+static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_gtc_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gtc_init;
+	eap->reset = eap_gtc_reset;
+	eap->buildReq = eap_gtc_buildReq;
+	eap->check = eap_gtc_check;
+	eap->process = eap_gtc_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_identity.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_identity.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_identity.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,180 +0,0 @@
-/*
- * hostapd / EAP-Identity
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-
-
-struct eap_identity_data {
-	enum { CONTINUE, SUCCESS, FAILURE } state;
-	int pick_up;
-};
-
-
-static void * eap_identity_init(struct eap_sm *sm)
-{
-	struct eap_identity_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = CONTINUE;
-
-	return data;
-}
-
-
-static void * eap_identity_initPickUp(struct eap_sm *sm)
-{
-	struct eap_identity_data *data;
-	data = eap_identity_init(sm);
-	if (data) {
-		data->pick_up = 1;
-	}
-	return data;
-}
-
-
-static void eap_identity_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_identity_data *data = priv;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv,
-					     u8 id)
-{
-	struct eap_identity_data *data = priv;
-	struct wpabuf *req;
-	const char *req_data;
-	size_t req_data_len;
-
-	if (sm->eapol_cb->get_eap_req_id_text) {
-		req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx,
-							     &req_data_len);
-	} else {
-		req_data = NULL;
-		req_data_len = 0;
-	}
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
-			   "memory for request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpabuf_put_data(req, req_data, req_data_len);
-
-	return req;
-}
-
-
-static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
-				  struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
-			       respData, &len);
-	if (pos == NULL) {
-		wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_identity_process(struct eap_sm *sm, void *priv,
-				 struct wpabuf *respData)
-{
-	struct eap_identity_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	if (data->pick_up) {
-		if (eap_identity_check(sm, data, respData)) {
-			wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick "
-				   "up already started negotiation");
-			data->state = FAILURE;
-			return;
-		}
-		data->pick_up = 0;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
-			       respData, &len);
-	if (pos == NULL)
-		return; /* Should not happen - frame already validated */
-
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
-	if (sm->identity)
-		sm->update_user = TRUE;
-	os_free(sm->identity);
-	sm->identity = os_malloc(len ? len : 1);
-	if (sm->identity == NULL) {
-		data->state = FAILURE;
-	} else {
-		os_memcpy(sm->identity, pos, len);
-		sm->identity_len = len;
-		data->state = SUCCESS;
-	}
-}
-
-
-static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_identity_data *data = priv;
-	return data->state != CONTINUE;
-}
-
-
-static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_identity_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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,
-				      "Identity");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_identity_init;
-	eap->initPickUp = eap_identity_initPickUp;
-	eap->reset = eap_identity_reset;
-	eap->buildReq = eap_identity_buildReq;
-	eap->check = eap_identity_check;
-	eap->process = eap_identity_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_identity.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_identity.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_identity.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_identity.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,174 @@
+/*
+ * hostapd / EAP-Identity
+ * Copyright (c) 2004-2006, Jouni Malinen <j at 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 "eap_i.h"
+
+
+struct eap_identity_data {
+	enum { CONTINUE, SUCCESS, FAILURE } state;
+	int pick_up;
+};
+
+
+static void * eap_identity_init(struct eap_sm *sm)
+{
+	struct eap_identity_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CONTINUE;
+
+	return data;
+}
+
+
+static void * eap_identity_initPickUp(struct eap_sm *sm)
+{
+	struct eap_identity_data *data;
+	data = eap_identity_init(sm);
+	if (data) {
+		data->pick_up = 1;
+	}
+	return data;
+}
+
+
+static void eap_identity_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_identity_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv,
+					     u8 id)
+{
+	struct eap_identity_data *data = priv;
+	struct wpabuf *req;
+	const char *req_data;
+	size_t req_data_len;
+
+	if (sm->eapol_cb->get_eap_req_id_text) {
+		req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx,
+							     &req_data_len);
+	} else {
+		req_data = NULL;
+		req_data_len = 0;
+	}
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
+			   "memory for request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpabuf_put_data(req, req_data, req_data_len);
+
+	return req;
+}
+
+
+static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
+				  struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+			       respData, &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_identity_process(struct eap_sm *sm, void *priv,
+				 struct wpabuf *respData)
+{
+	struct eap_identity_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	if (data->pick_up) {
+		if (eap_identity_check(sm, data, respData)) {
+			wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick "
+				   "up already started negotiation");
+			data->state = FAILURE;
+			return;
+		}
+		data->pick_up = 0;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+			       respData, &len);
+	if (pos == NULL)
+		return; /* Should not happen - frame already validated */
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
+	if (sm->identity)
+		sm->update_user = TRUE;
+	os_free(sm->identity);
+	sm->identity = os_malloc(len ? len : 1);
+	if (sm->identity == NULL) {
+		data->state = FAILURE;
+	} else {
+		os_memcpy(sm->identity, pos, len);
+		sm->identity_len = len;
+		data->state = SUCCESS;
+	}
+}
+
+
+static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_identity_data *data = priv;
+	return data->state != CONTINUE;
+}
+
+
+static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_identity_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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,
+				      "Identity");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_identity_init;
+	eap->initPickUp = eap_identity_initPickUp;
+	eap->reset = eap_identity_reset;
+	eap->buildReq = eap_identity_buildReq;
+	eap->check = eap_identity_check;
+	eap->process = eap_identity_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_ikev2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,538 +0,0 @@
-/*
- * EAP-IKEv2 server (RFC 5106)
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_common/eap_ikev2_common.h"
-#include "ikev2.h"
-
-
-struct eap_ikev2_data {
-	struct ikev2_initiator_data ikev2;
-	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	size_t out_used;
-	size_t fragment_size;
-	int keys_ready;
-	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
-	int keymat_ok;
-};
-
-
-static const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr,
-					      size_t IDr_len,
-					      size_t *secret_len)
-{
-	struct eap_sm *sm = ctx;
-
-	if (IDr == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default "
-			   "to user identity from EAP-Identity");
-		IDr = sm->identity;
-		IDr_len = sm->identity_len;
-	}
-
-	if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL ||
-	    sm->user->password == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found");
-		return NULL;
-	}
-
-	*secret_len = sm->user->password_len;
-	return sm->user->password;
-}
-
-
-static const char * eap_ikev2_state_txt(int state)
-{
-	switch (state) {
-	case MSG:
-		return "MSG";
-	case FRAG_ACK:
-		return "FRAG_ACK";
-	case WAIT_FRAG_ACK:
-		return "WAIT_FRAG_ACK";
-	case DONE:
-		return "DONE";
-	case FAIL:
-		return "FAIL";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
-		   eap_ikev2_state_txt(data->state),
-		   eap_ikev2_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_ikev2_init(struct eap_sm *sm)
-{
-	struct eap_ikev2_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = MSG;
-	data->fragment_size = IKEV2_FRAGMENT_SIZE;
-	data->ikev2.state = SA_INIT;
-	data->ikev2.peer_auth = PEER_AUTH_SECRET;
-	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
-	if (data->ikev2.key_pad == NULL)
-		goto failed;
-	data->ikev2.key_pad_len = 21;
-
-	/* TODO: make proposals configurable */
-	data->ikev2.proposal.proposal_num = 1;
-	data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96;
-	data->ikev2.proposal.prf = PRF_HMAC_SHA1;
-	data->ikev2.proposal.encr = ENCR_AES_CBC;
-	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
-
-	data->ikev2.IDi = (u8 *) os_strdup("hostapd");
-	data->ikev2.IDi_len = 7;
-
-	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
-	data->ikev2.cb_ctx = sm;
-
-	return data;
-
-failed:
-	ikev2_initiator_deinit(&data->ikev2);
-	os_free(data);
-	return NULL;
-}
-
-
-static void eap_ikev2_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_ikev2_data *data = priv;
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	ikev2_initiator_deinit(&data->ikev2);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id)
-{
-	struct wpabuf *req;
-	u8 flags;
-	size_t send_len, plen, icv_len = 0;
-
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request");
-
-	flags = 0;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (1 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 1;
-		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
-		if (data->out_used == 0) {
-			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-			send_len -= 4;
-		}
-	}
-
-	plen = 1 + send_len;
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
-		plen += 4;
-	if (data->keys_ready) {
-		const struct ikev2_integ_alg *integ;
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
-			   "Data");
-		flags |= IKEV2_FLAGS_ICV_INCLUDED;
-		integ = ikev2_get_integ(data->ikev2.proposal.integ);
-		if (integ == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
-				   "transform / cannot generate ICV");
-			return NULL;
-		}
-		icv_len = integ->hash_len;
-
-		plen += icv_len;
-	}
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL)
-		return NULL;
-
-	wpabuf_put_u8(req, flags); /* Flags */
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
-		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
-		const u8 *msg = wpabuf_head(req);
-		size_t len = wpabuf_len(req);
-		ikev2_integ_hash(data->ikev2.proposal.integ,
-				 data->ikev2.keys.SK_ai,
-				 data->ikev2.keys.SK_integ_len,
-				 msg, len, wpabuf_put(req, icv_len));
-	}
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		eap_ikev2_state(data, WAIT_FRAG_ACK);
-	}
-
-	return req;
-}
-
-
-static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_ikev2_data *data = priv;
-
-	switch (data->state) {
-	case MSG:
-		if (data->out_buf == NULL) {
-			data->out_buf = ikev2_initiator_build(&data->ikev2);
-			if (data->out_buf == NULL) {
-				wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
-					   "generate IKEv2 message");
-				return NULL;
-			}
-			data->out_used = 0;
-		}
-		/* pass through */
-	case WAIT_FRAG_ACK:
-		return eap_ikev2_build_msg(data, id);
-	case FRAG_ACK:
-		return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in "
-			   "buildReq", data->state);
-		return NULL;
-	}
-}
-
-
-static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
-			       struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
-			       &len);
-	if (pos == NULL) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
-				 const struct wpabuf *respData,
-				 u8 flags, const u8 *pos, const u8 **end)
-{
-	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
-		int icv_len = eap_ikev2_validate_icv(
-			data->ikev2.proposal.integ, &data->ikev2.keys, 0,
-			respData, pos, *end);
-		if (icv_len < 0)
-			return -1;
-		/* Hide Integrity Checksum Data from further processing */
-		*end -= icv_len;
-	} else if (data->keys_ready) {
-		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
-			   "included integrity checksum");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
-				  const u8 *buf, size_t len)
-{
-	/* Process continuation of a pending message */
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
-		eap_ikev2_state(data, FAIL);
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu "
-		   "bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
-				      u8 flags, u32 message_length,
-				      const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
-			   "a fragmented packet");
-		return -1;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
-				   "message");
-			return -1;
-		}
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return 0;
-}
-
-
-static int eap_ikev2_server_keymat(struct eap_ikev2_data *data)
-{
-	if (eap_ikev2_derive_keymat(
-		    data->ikev2.proposal.prf, &data->ikev2.keys,
-		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
-		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
-		    data->keymat) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive "
-			   "key material");
-		return -1;
-	}
-	data->keymat_ok = 1;
-	return 0;
-}
-
-
-static void eap_ikev2_process(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	struct eap_ikev2_data *data = priv;
-	const u8 *start, *pos, *end;
-	size_t len;
-	u8 flags;
-	u32 message_length = 0;
-	struct wpabuf tmpbuf;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
-			       &len);
-	if (pos == NULL)
-		return; /* Should not happen; message already verified */
-
-	start = pos;
-	end = start + len;
-
-	if (len == 0) {
-		/* fragment ack */
-		flags = 0;
-	} else
-		flags = *pos++;
-
-	if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) {
-		eap_ikev2_state(data, FAIL);
-		return;
-	}
-
-	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
-			eap_ikev2_state(data, FAIL);
-			return;
-		}
-		message_length = WPA_GET_BE32(pos);
-		pos += 4;
-
-		if (message_length < (u32) (end - pos)) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
-				   "Length (%d; %ld remaining in this msg)",
-				   message_length, (long) (end - pos));
-			eap_ikev2_state(data, FAIL);
-			return;
-		}
-	}
-	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
-		   "Message Length %u", flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (len != 0) {
-			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
-				   "in WAIT_FRAG_ACK state");
-			eap_ikev2_state(data, FAIL);
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
-		eap_ikev2_state(data, MSG);
-		return;
-	}
-
-	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
-		eap_ikev2_state(data, FAIL);
-		return;
-	}
-		
-	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
-		if (eap_ikev2_process_fragment(data, flags, message_length,
-					       pos, end - pos) < 0)
-			eap_ikev2_state(data, FAIL);
-		else
-			eap_ikev2_state(data, FRAG_ACK);
-		return;
-	} else if (data->state == FRAG_ACK) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
-		data->state = MSG;
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) {
-		if (data->in_buf == &tmpbuf)
-			data->in_buf = NULL;
-		eap_ikev2_state(data, FAIL);
-		return;
-	}
-
-	switch (data->ikev2.state) {
-	case SA_AUTH:
-		/* SA_INIT was sent out, so message have to be
-		 * integrity protected from now on. */
-		data->keys_ready = 1;
-		break;
-	case IKEV2_DONE:
-		if (data->state == FAIL)
-			break;
-		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed "
-			   "successfully");
-		if (eap_ikev2_server_keymat(data))
-			break;
-		eap_ikev2_state(data, DONE);
-		break;
-	default:
-		break;
-	}
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-}
-
-
-static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_ikev2_data *data = priv;
-	return data->state == DONE || data->state == FAIL;
-}
-
-
-static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_ikev2_data *data = priv;
-	return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
-		data->keymat_ok;
-}
-
-
-static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_ikev2_data *data = priv;
-	u8 *key;
-
-	if (data->state != DONE || !data->keymat_ok)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key) {
-		os_memcpy(key, data->keymat, EAP_MSK_LEN);
-		*len = EAP_MSK_LEN;
-	}
-
-	return key;
-}
-
-
-static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_ikev2_data *data = priv;
-	u8 *key;
-
-	if (data->state != DONE || !data->keymat_ok)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key) {
-		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
-		*len = EAP_EMSK_LEN;
-	}
-
-	return key;
-}
-
-
-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,
-				      "IKEV2");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_ikev2_init;
-	eap->reset = eap_ikev2_reset;
-	eap->buildReq = eap_ikev2_buildReq;
-	eap->check = eap_ikev2_check;
-	eap->process = eap_ikev2_process;
-	eap->isDone = eap_ikev2_isDone;
-	eap->getKey = eap_ikev2_getKey;
-	eap->isSuccess = eap_ikev2_isSuccess;
-	eap->get_emsk = eap_ikev2_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_ikev2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,533 @@
+/*
+ * EAP-IKEv2 server (RFC 5106)
+ * Copyright (c) 2007, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_common/eap_ikev2_common.h"
+#include "ikev2.h"
+
+
+struct eap_ikev2_data {
+	struct ikev2_initiator_data ikev2;
+	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
+	int keys_ready;
+	u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN];
+	int keymat_ok;
+};
+
+
+static const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr,
+					      size_t IDr_len,
+					      size_t *secret_len)
+{
+	struct eap_sm *sm = ctx;
+
+	if (IDr == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default "
+			   "to user identity from EAP-Identity");
+		IDr = sm->identity;
+		IDr_len = sm->identity_len;
+	}
+
+	if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL ||
+	    sm->user->password == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found");
+		return NULL;
+	}
+
+	*secret_len = sm->user->password_len;
+	return sm->user->password;
+}
+
+
+static const char * eap_ikev2_state_txt(int state)
+{
+	switch (state) {
+	case MSG:
+		return "MSG";
+	case FRAG_ACK:
+		return "FRAG_ACK";
+	case WAIT_FRAG_ACK:
+		return "WAIT_FRAG_ACK";
+	case DONE:
+		return "DONE";
+	case FAIL:
+		return "FAIL";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_ikev2_state(struct eap_ikev2_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s",
+		   eap_ikev2_state_txt(data->state),
+		   eap_ikev2_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_ikev2_init(struct eap_sm *sm)
+{
+	struct eap_ikev2_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = MSG;
+	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
+		IKEV2_FRAGMENT_SIZE;
+	data->ikev2.state = SA_INIT;
+	data->ikev2.peer_auth = PEER_AUTH_SECRET;
+	data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2");
+	if (data->ikev2.key_pad == NULL)
+		goto failed;
+	data->ikev2.key_pad_len = 21;
+
+	/* TODO: make proposals configurable */
+	data->ikev2.proposal.proposal_num = 1;
+	data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96;
+	data->ikev2.proposal.prf = PRF_HMAC_SHA1;
+	data->ikev2.proposal.encr = ENCR_AES_CBC;
+	data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP;
+
+	data->ikev2.IDi = (u8 *) os_strdup("hostapd");
+	data->ikev2.IDi_len = 7;
+
+	data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret;
+	data->ikev2.cb_ctx = sm;
+
+	return data;
+
+failed:
+	ikev2_initiator_deinit(&data->ikev2);
+	os_free(data);
+	return NULL;
+}
+
+
+static void eap_ikev2_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_ikev2_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	ikev2_initiator_deinit(&data->ikev2);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen, icv_len = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request");
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= IKEV2_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	if (data->keys_ready) {
+		const struct ikev2_integ_alg *integ;
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum "
+			   "Data");
+		flags |= IKEV2_FLAGS_ICV_INCLUDED;
+		integ = ikev2_get_integ(data->ikev2.proposal.integ);
+		if (integ == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG "
+				   "transform / cannot generate ICV");
+			return NULL;
+		}
+		icv_len = integ->hash_len;
+
+		plen += icv_len;
+	}
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
+		const u8 *msg = wpabuf_head(req);
+		size_t len = wpabuf_len(req);
+		ikev2_integ_hash(data->ikev2.proposal.integ,
+				 data->ikev2.keys.SK_ai,
+				 data->ikev2.keys.SK_integ_len,
+				 msg, len, wpabuf_put(req, icv_len));
+	}
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_ikev2_state(data, WAIT_FRAG_ACK);
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_ikev2_data *data = priv;
+
+	switch (data->state) {
+	case MSG:
+		if (data->out_buf == NULL) {
+			data->out_buf = ikev2_initiator_build(&data->ikev2);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to "
+					   "generate IKEv2 message");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		/* pass through */
+	case WAIT_FRAG_ACK:
+		return eap_ikev2_build_msg(data, id);
+	case FRAG_ACK:
+		return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in "
+			   "buildReq", data->state);
+		return NULL;
+	}
+}
+
+
+static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv,
+			       struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
+			       &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_ikev2_process_icv(struct eap_ikev2_data *data,
+				 const struct wpabuf *respData,
+				 u8 flags, const u8 *pos, const u8 **end)
+{
+	if (flags & IKEV2_FLAGS_ICV_INCLUDED) {
+		int icv_len = eap_ikev2_validate_icv(
+			data->ikev2.proposal.integ, &data->ikev2.keys, 0,
+			respData, pos, *end);
+		if (icv_len < 0)
+			return -1;
+		/* Hide Integrity Checksum Data from further processing */
+		*end -= icv_len;
+	} else if (data->keys_ready) {
+		wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have "
+			   "included integrity checksum");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_ikev2_process_cont(struct eap_ikev2_data *data,
+				  const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow");
+		eap_ikev2_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_ikev2_process_fragment(struct eap_ikev2_data *data,
+				      u8 flags, u32 message_length,
+				      const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in "
+			   "a fragmented packet");
+		return -1;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
+				   "message");
+			return -1;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return 0;
+}
+
+
+static int eap_ikev2_server_keymat(struct eap_ikev2_data *data)
+{
+	if (eap_ikev2_derive_keymat(
+		    data->ikev2.proposal.prf, &data->ikev2.keys,
+		    data->ikev2.i_nonce, data->ikev2.i_nonce_len,
+		    data->ikev2.r_nonce, data->ikev2.r_nonce_len,
+		    data->keymat) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive "
+			   "key material");
+		return -1;
+	}
+	data->keymat_ok = 1;
+	return 0;
+}
+
+
+static void eap_ikev2_process(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	struct eap_ikev2_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 flags;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData,
+			       &len);
+	if (pos == NULL)
+		return; /* Should not happen; message already verified */
+
+	start = pos;
+	end = start + len;
+
+	if (len == 0) {
+		/* fragment ack */
+		flags = 0;
+	} else
+		flags = *pos++;
+
+	if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) {
+		eap_ikev2_state(data, FAIL);
+		return;
+	}
+
+	if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow");
+			eap_ikev2_state(data, FAIL);
+			return;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			eap_ikev2_state(data, FAIL);
+			return;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (len != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
+				   "in WAIT_FRAG_ACK state");
+			eap_ikev2_state(data, FAIL);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged");
+		eap_ikev2_state(data, MSG);
+		return;
+	}
+
+	if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) {
+		eap_ikev2_state(data, FAIL);
+		return;
+	}
+		
+	if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) {
+		if (eap_ikev2_process_fragment(data, flags, message_length,
+					       pos, end - pos) < 0)
+			eap_ikev2_state(data, FAIL);
+		else
+			eap_ikev2_state(data, FRAG_ACK);
+		return;
+	} else if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+		data->state = MSG;
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) {
+		if (data->in_buf == &tmpbuf)
+			data->in_buf = NULL;
+		eap_ikev2_state(data, FAIL);
+		return;
+	}
+
+	switch (data->ikev2.state) {
+	case SA_AUTH:
+		/* SA_INIT was sent out, so message have to be
+		 * integrity protected from now on. */
+		data->keys_ready = 1;
+		break;
+	case IKEV2_DONE:
+		if (data->state == FAIL)
+			break;
+		wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed "
+			   "successfully");
+		if (eap_ikev2_server_keymat(data))
+			break;
+		eap_ikev2_state(data, DONE);
+		break;
+	default:
+		break;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_ikev2_data *data = priv;
+	return data->state == DONE || data->state == FAIL;
+}
+
+
+static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_ikev2_data *data = priv;
+	return data->state == DONE && data->ikev2.state == IKEV2_DONE &&
+		data->keymat_ok;
+}
+
+
+static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ikev2_data *data = priv;
+	u8 *key;
+
+	if (data->state != DONE || !data->keymat_ok)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key) {
+		os_memcpy(key, data->keymat, EAP_MSK_LEN);
+		*len = EAP_MSK_LEN;
+	}
+
+	return key;
+}
+
+
+static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ikev2_data *data = priv;
+	u8 *key;
+
+	if (data->state != DONE || !data->keymat_ok)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key) {
+		os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN);
+		*len = EAP_EMSK_LEN;
+	}
+
+	return key;
+}
+
+
+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,
+				      "IKEV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_ikev2_init;
+	eap->reset = eap_ikev2_reset;
+	eap->buildReq = eap_ikev2_buildReq;
+	eap->check = eap_ikev2_check;
+	eap->process = eap_ikev2_process;
+	eap->isDone = eap_ikev2_isDone;
+	eap->getKey = eap_ikev2_getKey;
+	eap->isSuccess = eap_ikev2_isSuccess;
+	eap->get_emsk = eap_ikev2_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_md5.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_md5.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,176 +0,0 @@
-/*
- * hostapd / EAP-MD5 server
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_common/chap.h"
-
-
-#define CHALLENGE_LEN 16
-
-struct eap_md5_data {
-	u8 challenge[CHALLENGE_LEN];
-	enum { CONTINUE, SUCCESS, FAILURE } state;
-};
-
-
-static void * eap_md5_init(struct eap_sm *sm)
-{
-	struct eap_md5_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = CONTINUE;
-
-	return data;
-}
-
-
-static void eap_md5_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_md5_data *data = priv;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_md5_data *data = priv;
-	struct wpabuf *req;
-
-	if (os_get_random(data->challenge, CHALLENGE_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, CHALLENGE_LEN);
-	wpabuf_put_data(req, data->challenge, CHALLENGE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge,
-		    CHALLENGE_LEN);
-
-	data->state = CONTINUE;
-
-	return req;
-}
-
-
-static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
-		return TRUE;
-	}
-	if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
-			   "(response_len=%d payload_len=%lu",
-			   *pos, (unsigned long) len);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_md5_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_md5_data *data = priv;
-	const u8 *pos;
-	size_t plen;
-	u8 hash[CHAP_MD5_LEN], id;
-
-	if (sm->user == NULL || sm->user->password == NULL ||
-	    sm->user->password_hash) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not "
-			   "configured");
-		data->state = FAILURE;
-		return;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen);
-	if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN)
-		return; /* Should not happen - frame already validated */
-
-	pos++; /* Skip response len */
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);
-
-	id = eap_get_id(respData);
-	chap_md5(id, sm->user->password, sm->user->password_len,
-		 data->challenge, CHALLENGE_LEN, hash);
-
-	if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
-		data->state = SUCCESS;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure");
-		data->state = FAILURE;
-	}
-}
-
-
-static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_md5_data *data = priv;
-	return data->state != CONTINUE;
-}
-
-
-static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_md5_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_md5_init;
-	eap->reset = eap_md5_reset;
-	eap->buildReq = eap_md5_buildReq;
-	eap->check = eap_md5_check;
-	eap->process = eap_md5_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_md5.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_md5.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_md5.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_md5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,175 @@
+/*
+ * hostapd / EAP-MD5 server
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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/random.h"
+#include "eap_i.h"
+#include "eap_common/chap.h"
+
+
+#define CHALLENGE_LEN 16
+
+struct eap_md5_data {
+	u8 challenge[CHALLENGE_LEN];
+	enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_md5_init(struct eap_sm *sm)
+{
+	struct eap_md5_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CONTINUE;
+
+	return data;
+}
+
+
+static void eap_md5_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_md5_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_md5_data *data = priv;
+	struct wpabuf *req;
+
+	if (random_get_bytes(data->challenge, CHALLENGE_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, CHALLENGE_LEN);
+	wpabuf_put_data(req, data->challenge, CHALLENGE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge,
+		    CHALLENGE_LEN);
+
+	data->state = CONTINUE;
+
+	return req;
+}
+
+
+static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
+		return TRUE;
+	}
+	if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
+			   "(response_len=%d payload_len=%lu",
+			   *pos, (unsigned long) len);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_md5_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_md5_data *data = priv;
+	const u8 *pos;
+	size_t plen;
+	u8 hash[CHAP_MD5_LEN], id;
+
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_hash) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not "
+			   "configured");
+		data->state = FAILURE;
+		return;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen);
+	if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN)
+		return; /* Should not happen - frame already validated */
+
+	pos++; /* Skip response len */
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);
+
+	id = eap_get_id(respData);
+	if (chap_md5(id, sm->user->password, sm->user->password_len,
+		     data->challenge, CHALLENGE_LEN, hash)) {
+		wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+		data->state = FAILURE;
+		return;
+	}
+
+	if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
+		data->state = SUCCESS;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure");
+		data->state = FAILURE;
+	}
+}
+
+
+static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_md5_data *data = priv;
+	return data->state != CONTINUE;
+}
+
+
+static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_md5_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_md5_init;
+	eap->reset = eap_md5_reset;
+	eap->buildReq = eap_md5_buildReq;
+	eap->check = eap_md5_check;
+	eap->process = eap_md5_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_methods.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_methods.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_methods.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,175 +0,0 @@
-/*
- * EAP server method registration
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_methods.h"
-
-
-static struct eap_method *eap_methods;
-
-
-/**
- * eap_server_get_eap_method - Get EAP method based on type number
- * @vendor: EAP Vendor-Id (0 = IETF)
- * @method: EAP type number
- * Returns: Pointer to EAP method or %NULL if not found
- */
-const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (m->vendor == vendor && m->method == method)
-			return m;
-	}
-	return NULL;
-}
-
-
-/**
- * eap_server_get_type - Get EAP type for the given EAP method name
- * @name: EAP method name, e.g., TLS
- * @vendor: Buffer for returning EAP Vendor-Id
- * Returns: EAP method type or %EAP_TYPE_NONE if not found
- *
- * This function maps EAP type names into EAP type numbers based on the list of
- * EAP methods included in the build.
- */
-EapType eap_server_get_type(const char *name, int *vendor)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (os_strcmp(m->name, name) == 0) {
-			*vendor = m->vendor;
-			return m->method;
-		}
-	}
-	*vendor = EAP_VENDOR_IETF;
-	return EAP_TYPE_NONE;
-}
-
-
-/**
- * eap_server_method_alloc - Allocate EAP server method structure
- * @version: Version of the EAP server method interface (set to
- * EAP_SERVER_METHOD_INTERFACE_VERSION)
- * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
- * @method: EAP type number (EAP_TYPE_*)
- * @name: Name of the method (e.g., "TLS")
- * Returns: Allocated EAP method structure or %NULL on failure
- *
- * The returned structure should be freed with eap_server_method_free() when it
- * is not needed anymore.
- */
-struct eap_method * eap_server_method_alloc(int version, int vendor,
-					    EapType method, const char *name)
-{
-	struct eap_method *eap;
-	eap = os_zalloc(sizeof(*eap));
-	if (eap == NULL)
-		return NULL;
-	eap->version = version;
-	eap->vendor = vendor;
-	eap->method = method;
-	eap->name = name;
-	return eap;
-}
-
-
-/**
- * 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)
-{
-	os_free(method);
-}
-
-
-/**
- * eap_server_method_register - Register an EAP server method
- * @method: EAP method to register
- * 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.
- */
-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)
-		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)
-			return -2;
-		last = m;
-	}
-
-	if (last)
-		last->next = method;
-	else
-		eap_methods = method;
-
-	return 0;
-}
-
-
-/**
- * eap_server_unregister_methods - Unregister EAP server methods
- *
- * This function is called at program termination to unregister all EAP server
- * methods.
- */
-void eap_server_unregister_methods(void)
-{
-	struct eap_method *m;
-
-	while (eap_methods) {
-		m = eap_methods;
-		eap_methods = eap_methods->next;
-
-		if (m->free)
-			m->free(m);
-		else
-			eap_server_method_free(m);
-	}
-}
-
-
-/**
- * eap_server_get_name - Get EAP method name for the given EAP type
- * @vendor: EAP Vendor-Id (0 = IETF)
- * @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
- *
- * This function maps EAP type numbers into EAP type names based on the list of
- * EAP methods included in the build.
- */
-const char * eap_server_get_name(int vendor, EapType type)
-{
-	struct eap_method *m;
-	for (m = eap_methods; m; m = m->next) {
-		if (m->vendor == vendor && m->method == type)
-			return m->name;
-	}
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_methods.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_methods.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_methods.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_methods.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,171 @@
+/*
+ * EAP server method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods;
+
+
+/**
+ * eap_server_get_eap_method - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_server_get_eap_method(int vendor, EapType method)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == method)
+			return m;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_server_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_server_get_type(const char *name, int *vendor)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (os_strcmp(m->name, name) == 0) {
+			*vendor = m->vendor;
+			return m->method;
+		}
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_server_method_alloc - Allocate EAP server method structure
+ * @version: Version of the EAP server method interface (set to
+ * EAP_SERVER_METHOD_INTERFACE_VERSION)
+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ * @method: EAP type number (EAP_TYPE_*)
+ * @name: Name of the method (e.g., "TLS")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_server_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+					    EapType method, const char *name)
+{
+	struct eap_method *eap;
+	eap = os_zalloc(sizeof(*eap));
+	if (eap == NULL)
+		return NULL;
+	eap->version = version;
+	eap->vendor = vendor;
+	eap->method = method;
+	eap->name = name;
+	return eap;
+}
+
+
+/**
+ * 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)
+{
+	os_free(method);
+}
+
+
+/**
+ * eap_server_method_register - Register an EAP server method
+ * @method: EAP method to register
+ * 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.
+ */
+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)
+		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)
+			return -2;
+		last = m;
+	}
+
+	if (last)
+		last->next = method;
+	else
+		eap_methods = method;
+
+	return 0;
+}
+
+
+/**
+ * eap_server_unregister_methods - Unregister EAP server methods
+ *
+ * This function is called at program termination to unregister all EAP server
+ * methods.
+ */
+void eap_server_unregister_methods(void)
+{
+	struct eap_method *m;
+
+	while (eap_methods) {
+		m = eap_methods;
+		eap_methods = eap_methods->next;
+
+		if (m->free)
+			m->free(m);
+		else
+			eap_server_method_free(m);
+	}
+}
+
+
+/**
+ * eap_server_get_name - Get EAP method name for the given EAP type
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @type: EAP method type
+ * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ *
+ * This function maps EAP type numbers into EAP type names based on the list of
+ * EAP methods included in the build.
+ */
+const char * eap_server_get_name(int vendor, EapType type)
+{
+	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == type)
+			return m->name;
+	}
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_mschapv2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,574 +0,0 @@
-/*
- * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-#include "eap_i.h"
-
-
-struct eap_mschapv2_hdr {
-	u8 op_code; /* MSCHAPV2_OP_* */
-	u8 mschapv2_id; /* must be changed for challenges, but not for
-			 * success/failure */
-	u8 ms_length[2]; /* Note: misaligned; length - 5 */
-	/* followed by data */
-} STRUCT_PACKED;
-
-#define MSCHAPV2_OP_CHALLENGE 1
-#define MSCHAPV2_OP_RESPONSE 2
-#define MSCHAPV2_OP_SUCCESS 3
-#define MSCHAPV2_OP_FAILURE 4
-#define MSCHAPV2_OP_CHANGE_PASSWORD 7
-
-#define MSCHAPV2_RESP_LEN 49
-
-#define ERROR_RESTRICTED_LOGON_HOURS 646
-#define ERROR_ACCT_DISABLED 647
-#define ERROR_PASSWD_EXPIRED 648
-#define ERROR_NO_DIALIN_PERMISSION 649
-#define ERROR_AUTHENTICATION_FAILURE 691
-#define ERROR_CHANGING_PASSWORD 709
-
-#define PASSWD_CHANGE_CHAL_LEN 16
-#define MSCHAPV2_KEY_LEN 16
-
-
-#define CHALLENGE_LEN 16
-
-struct eap_mschapv2_data {
-	u8 auth_challenge[CHALLENGE_LEN];
-	int auth_challenge_from_tls;
-	u8 *peer_challenge;
-	u8 auth_response[20];
-	enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
-	u8 resp_mschapv2_id;
-	u8 master_key[16];
-	int master_key_valid;
-};
-
-
-static void * eap_mschapv2_init(struct eap_sm *sm)
-{
-	struct eap_mschapv2_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = CHALLENGE;
-
-	if (sm->auth_challenge) {
-		os_memcpy(data->auth_challenge, sm->auth_challenge,
-			  CHALLENGE_LEN);
-		data->auth_challenge_from_tls = 1;
-	}
-
-	if (sm->peer_challenge) {
-		data->peer_challenge = os_malloc(CHALLENGE_LEN);
-		if (data->peer_challenge == NULL) {
-			os_free(data);
-			return NULL;
-		}
-		os_memcpy(data->peer_challenge, sm->peer_challenge,
-			  CHALLENGE_LEN);
-	}
-
-	return data;
-}
-
-
-static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_mschapv2_data *data = priv;
-	if (data == NULL)
-		return;
-
-	os_free(data->peer_challenge);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_mschapv2_build_challenge(
-	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_mschapv2_hdr *ms;
-	char *name = "hostapd"; /* TODO: make this configurable */
-	size_t ms_len;
-
-	if (!data->auth_challenge_from_tls &&
-	    os_get_random(data->auth_challenge, CHALLENGE_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
-			   "data");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
-			   " for request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	ms = wpabuf_put(req, sizeof(*ms));
-	ms->op_code = MSCHAPV2_OP_CHALLENGE;
-	ms->mschapv2_id = id;
-	WPA_PUT_BE16(ms->ms_length, ms_len);
-
-	wpabuf_put_u8(req, CHALLENGE_LEN);
-	if (!data->auth_challenge_from_tls)
-		wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN);
-	else
-		wpabuf_put(req, CHALLENGE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
-		    data->auth_challenge, CHALLENGE_LEN);
-	wpabuf_put_data(req, name, os_strlen(name));
-
-	return req;
-}
-
-
-static struct wpabuf * eap_mschapv2_build_success_req(
-	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_mschapv2_hdr *ms;
-	u8 *msg;
-	char *message = "OK";
-	size_t ms_len;
-
-	ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
-		os_strlen(message);
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
-			   " for request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	ms = wpabuf_put(req, sizeof(*ms));
-	ms->op_code = MSCHAPV2_OP_SUCCESS;
-	ms->mschapv2_id = data->resp_mschapv2_id;
-	WPA_PUT_BE16(ms->ms_length, ms_len);
-	msg = (u8 *) (ms + 1);
-
-	wpabuf_put_u8(req, 'S');
-	wpabuf_put_u8(req, '=');
-	wpa_snprintf_hex_uppercase(
-		wpabuf_put(req, sizeof(data->auth_response) * 2),
-		sizeof(data->auth_response) * 2 + 1,
-		data->auth_response, sizeof(data->auth_response));
-	wpabuf_put_u8(req, ' ');
-	wpabuf_put_u8(req, 'M');
-	wpabuf_put_u8(req, '=');
-	wpabuf_put_data(req, message, os_strlen(message));
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
-			  msg, ms_len - sizeof(*ms));
-
-	return req;
-}
-
-
-static struct wpabuf * eap_mschapv2_build_failure_req(
-	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_mschapv2_hdr *ms;
-	char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
-		"M=FAILED";
-	size_t ms_len;
-
-	ms_len = sizeof(*ms) + os_strlen(message);
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
-			   " for request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	ms = wpabuf_put(req, sizeof(*ms));
-	ms->op_code = MSCHAPV2_OP_FAILURE;
-	ms->mschapv2_id = data->resp_mschapv2_id;
-	WPA_PUT_BE16(ms->ms_length, ms_len);
-
-	wpabuf_put_data(req, message, os_strlen(message));
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
-			  (u8 *) message, os_strlen(message));
-
-	return req;
-}
-
-
-static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
-					     u8 id)
-{
-	struct eap_mschapv2_data *data = priv;
-
-	switch (data->state) {
-	case CHALLENGE:
-		return eap_mschapv2_build_challenge(sm, data, id);
-	case SUCCESS_REQ:
-		return eap_mschapv2_build_success_req(sm, data, id);
-	case FAILURE_REQ:
-		return eap_mschapv2_build_failure_req(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
-			   "buildReq", data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
-				  struct wpabuf *respData)
-{
-	struct eap_mschapv2_data *data = priv;
-	struct eap_mschapv2_hdr *resp;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
-			       &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
-		return TRUE;
-	}
-
-	resp = (struct eap_mschapv2_hdr *) pos;
-	if (data->state == CHALLENGE &&
-	    resp->op_code != MSCHAPV2_OP_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
-			   "ignore op %d", resp->op_code);
-		return TRUE;
-	}
-
-	if (data->state == SUCCESS_REQ &&
-	    resp->op_code != MSCHAPV2_OP_SUCCESS &&
-	    resp->op_code != MSCHAPV2_OP_FAILURE) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
-			   "Failure - ignore op %d", resp->op_code);
-		return TRUE;
-	}
-
-	if (data->state == FAILURE_REQ &&
-	    resp->op_code != MSCHAPV2_OP_FAILURE) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
-			   "- ignore op %d", resp->op_code);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_mschapv2_process_response(struct eap_sm *sm,
-					  struct eap_mschapv2_data *data,
-					  struct wpabuf *respData)
-{
-	struct eap_mschapv2_hdr *resp;
-	const u8 *pos, *end, *peer_challenge, *nt_response, *name;
-	u8 flags;
-	size_t len, name_len, i;
-	u8 expected[24];
-	const u8 *username, *user;
-	size_t username_len, user_len;
-	int res;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
-			       &len);
-	if (pos == NULL || len < 1)
-		return; /* Should not happen - frame already validated */
-
-	end = pos + len;
-	resp = (struct eap_mschapv2_hdr *) pos;
-	pos = (u8 *) (resp + 1);
-
-	if (len < sizeof(*resp) + 1 + 49 ||
-	    resp->op_code != MSCHAPV2_OP_RESPONSE ||
-	    pos[0] != 49) {
-		wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
-				respData);
-		data->state = FAILURE;
-		return;
-	}
-	data->resp_mschapv2_id = resp->mschapv2_id;
-	pos++;
-	peer_challenge = pos;
-	pos += 16 + 8;
-	nt_response = pos;
-	pos += 24;
-	flags = *pos++;
-	name = pos;
-	name_len = end - name;
-
-	if (data->peer_challenge) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
-			   "Peer-Challenge");
-		peer_challenge = data->peer_challenge;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
-		    peer_challenge, 16);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
-	wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
-
-	/* MSCHAPv2 does not include optional domain name in the
-	 * challenge-response calculation, so remove domain prefix
-	 * (if present). */
-	username = sm->identity;
-	username_len = sm->identity_len;
-	for (i = 0; i < username_len; i++) {
-		if (username[i] == '\\') {
-			username_len -= i + 1;
-			username += i + 1;
-			break;
-		}
-	}
-
-	user = name;
-	user_len = name_len;
-	for (i = 0; i < user_len; i++) {
-		if (user[i] == '\\') {
-			user_len -= i + 1;
-			user += i + 1;
-			break;
-		}
-	}
-
-	if (username_len != user_len ||
-	    os_memcmp(username, user, username_len) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
-				  "name", username, username_len);
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
-				  "name", user, user_len);
-		data->state = FAILURE;
-		return;
-	}
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
-			  username, username_len);
-
-	if (sm->user->password_hash) {
-		res = generate_nt_response_pwhash(data->auth_challenge,
-						  peer_challenge,
-						  username, username_len,
-						  sm->user->password,
-						  expected);
-	} else {
-		res = generate_nt_response(data->auth_challenge,
-					   peer_challenge,
-					   username, username_len,
-					   sm->user->password,
-					   sm->user->password_len,
-					   expected);
-	}
-	if (res) {
-		data->state = FAILURE;
-		return;
-	}
-
-	if (os_memcmp(nt_response, expected, 24) == 0) {
-		const u8 *pw_hash;
-		u8 pw_hash_buf[16], pw_hash_hash[16];
-
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
-		data->state = SUCCESS_REQ;
-
-		/* Authenticator response is not really needed yet, but
-		 * calculate it here so that peer_challenge and username need
-		 * not be saved. */
-		if (sm->user->password_hash) {
-			pw_hash = sm->user->password;
-		} else {
-			nt_password_hash(sm->user->password,
-					 sm->user->password_len,
-					 pw_hash_buf);
-			pw_hash = pw_hash_buf;
-		}
-		generate_authenticator_response_pwhash(
-			pw_hash, peer_challenge, data->auth_challenge,
-			username, username_len, nt_response,
-			data->auth_response);
-
-		hash_nt_password_hash(pw_hash, pw_hash_hash);
-		get_master_key(pw_hash_hash, nt_response, data->master_key);
-		data->master_key_valid = 1;
-		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
-				data->master_key, MSCHAPV2_KEY_LEN);
-	} else {
-		wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
-			    expected, 24);
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
-		data->state = FAILURE_REQ;
-	}
-}
-
-
-static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
-					      struct eap_mschapv2_data *data,
-					      struct wpabuf *respData)
-{
-	struct eap_mschapv2_hdr *resp;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
-			       &len);
-	if (pos == NULL || len < 1)
-		return; /* Should not happen - frame already validated */
-
-	resp = (struct eap_mschapv2_hdr *) pos;
-
-	if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
-			   " - authentication completed successfully");
-		data->state = SUCCESS;
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
-			   "Response - peer rejected authentication");
-		data->state = FAILURE;
-	}
-}
-
-
-static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
-					      struct eap_mschapv2_data *data,
-					      struct wpabuf *respData)
-{
-	struct eap_mschapv2_hdr *resp;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
-			       &len);
-	if (pos == NULL || len < 1)
-		return; /* Should not happen - frame already validated */
-
-	resp = (struct eap_mschapv2_hdr *) pos;
-
-	if (resp->op_code == MSCHAPV2_OP_FAILURE) {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
-			   " - authentication failed");
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
-			   "Response - authentication failed");
-	}
-
-	data->state = FAILURE;
-}
-
-
-static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
-				 struct wpabuf *respData)
-{
-	struct eap_mschapv2_data *data = priv;
-
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
-		data->state = FAILURE;
-		return;
-	}
-
-	switch (data->state) {
-	case CHALLENGE:
-		eap_mschapv2_process_response(sm, data, respData);
-		break;
-	case SUCCESS_REQ:
-		eap_mschapv2_process_success_resp(sm, data, respData);
-		break;
-	case FAILURE_REQ:
-		eap_mschapv2_process_failure_resp(sm, data, respData);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
-			   "process", data->state);
-		break;
-	}
-}
-
-
-static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_mschapv2_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_mschapv2_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS || !data->master_key_valid)
-		return NULL;
-
-	*len = 2 * MSCHAPV2_KEY_LEN;
-	key = os_malloc(*len);
-	if (key == NULL)
-		return NULL;
-	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
-	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 1);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
-
-	return key;
-}
-
-
-static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_mschapv2_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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,
-				      "MSCHAPV2");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_mschapv2_init;
-	eap->reset = eap_mschapv2_reset;
-	eap->buildReq = eap_mschapv2_buildReq;
-	eap->check = eap_mschapv2_check;
-	eap->process = eap_mschapv2_process;
-	eap->isDone = eap_mschapv2_isDone;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_mschapv2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_mschapv2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,572 @@
+/*
+ * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
+ * Copyright (c) 2004-2007, Jouni Malinen <j at 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/ms_funcs.h"
+#include "crypto/random.h"
+#include "eap_i.h"
+
+
+struct eap_mschapv2_hdr {
+	u8 op_code; /* MSCHAPV2_OP_* */
+	u8 mschapv2_id; /* must be changed for challenges, but not for
+			 * success/failure */
+	u8 ms_length[2]; /* Note: misaligned; length - 5 */
+	/* followed by data */
+} STRUCT_PACKED;
+
+#define MSCHAPV2_OP_CHALLENGE 1
+#define MSCHAPV2_OP_RESPONSE 2
+#define MSCHAPV2_OP_SUCCESS 3
+#define MSCHAPV2_OP_FAILURE 4
+#define MSCHAPV2_OP_CHANGE_PASSWORD 7
+
+#define MSCHAPV2_RESP_LEN 49
+
+#define ERROR_RESTRICTED_LOGON_HOURS 646
+#define ERROR_ACCT_DISABLED 647
+#define ERROR_PASSWD_EXPIRED 648
+#define ERROR_NO_DIALIN_PERMISSION 649
+#define ERROR_AUTHENTICATION_FAILURE 691
+#define ERROR_CHANGING_PASSWORD 709
+
+#define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
+
+
+#define CHALLENGE_LEN 16
+
+struct eap_mschapv2_data {
+	u8 auth_challenge[CHALLENGE_LEN];
+	int auth_challenge_from_tls;
+	u8 *peer_challenge;
+	u8 auth_response[20];
+	enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
+	u8 resp_mschapv2_id;
+	u8 master_key[16];
+	int master_key_valid;
+};
+
+
+static void * eap_mschapv2_init(struct eap_sm *sm)
+{
+	struct eap_mschapv2_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CHALLENGE;
+
+	if (sm->auth_challenge) {
+		os_memcpy(data->auth_challenge, sm->auth_challenge,
+			  CHALLENGE_LEN);
+		data->auth_challenge_from_tls = 1;
+	}
+
+	if (sm->peer_challenge) {
+		data->peer_challenge = os_malloc(CHALLENGE_LEN);
+		if (data->peer_challenge == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->peer_challenge, sm->peer_challenge,
+			  CHALLENGE_LEN);
+	}
+
+	return data;
+}
+
+
+static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	if (data == NULL)
+		return;
+
+	os_free(data->peer_challenge);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_mschapv2_build_challenge(
+	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_mschapv2_hdr *ms;
+	char *name = "hostapd"; /* TODO: make this configurable */
+	size_t ms_len;
+
+	if (!data->auth_challenge_from_tls &&
+	    random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
+			   "data");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+			   " for request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	ms = wpabuf_put(req, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_CHALLENGE;
+	ms->mschapv2_id = id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	wpabuf_put_u8(req, CHALLENGE_LEN);
+	if (!data->auth_challenge_from_tls)
+		wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN);
+	else
+		wpabuf_put(req, CHALLENGE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
+		    data->auth_challenge, CHALLENGE_LEN);
+	wpabuf_put_data(req, name, os_strlen(name));
+
+	return req;
+}
+
+
+static struct wpabuf * eap_mschapv2_build_success_req(
+	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_mschapv2_hdr *ms;
+	u8 *msg;
+	char *message = "OK";
+	size_t ms_len;
+
+	ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
+		os_strlen(message);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+			   " for request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	ms = wpabuf_put(req, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_SUCCESS;
+	ms->mschapv2_id = data->resp_mschapv2_id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+	msg = (u8 *) (ms + 1);
+
+	wpabuf_put_u8(req, 'S');
+	wpabuf_put_u8(req, '=');
+	wpa_snprintf_hex_uppercase(
+		wpabuf_put(req, sizeof(data->auth_response) * 2),
+		sizeof(data->auth_response) * 2 + 1,
+		data->auth_response, sizeof(data->auth_response));
+	wpabuf_put_u8(req, ' ');
+	wpabuf_put_u8(req, 'M');
+	wpabuf_put_u8(req, '=');
+	wpabuf_put_data(req, message, os_strlen(message));
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
+			  msg, ms_len - sizeof(*ms));
+
+	return req;
+}
+
+
+static struct wpabuf * eap_mschapv2_build_failure_req(
+	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_mschapv2_hdr *ms;
+	char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
+		"M=FAILED";
+	size_t ms_len;
+
+	ms_len = sizeof(*ms) + os_strlen(message);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+			   " for request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	ms = wpabuf_put(req, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_FAILURE;
+	ms->mschapv2_id = data->resp_mschapv2_id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	wpabuf_put_data(req, message, os_strlen(message));
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
+			  (u8 *) message, os_strlen(message));
+
+	return req;
+}
+
+
+static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
+					     u8 id)
+{
+	struct eap_mschapv2_data *data = priv;
+
+	switch (data->state) {
+	case CHALLENGE:
+		return eap_mschapv2_build_challenge(sm, data, id);
+	case SUCCESS_REQ:
+		return eap_mschapv2_build_success_req(sm, data, id);
+	case FAILURE_REQ:
+		return eap_mschapv2_build_failure_req(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
+			   "buildReq", data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
+				  struct wpabuf *respData)
+{
+	struct eap_mschapv2_data *data = priv;
+	struct eap_mschapv2_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
+			       &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
+		return TRUE;
+	}
+
+	resp = (struct eap_mschapv2_hdr *) pos;
+	if (data->state == CHALLENGE &&
+	    resp->op_code != MSCHAPV2_OP_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
+			   "ignore op %d", resp->op_code);
+		return TRUE;
+	}
+
+	if (data->state == SUCCESS_REQ &&
+	    resp->op_code != MSCHAPV2_OP_SUCCESS &&
+	    resp->op_code != MSCHAPV2_OP_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
+			   "Failure - ignore op %d", resp->op_code);
+		return TRUE;
+	}
+
+	if (data->state == FAILURE_REQ &&
+	    resp->op_code != MSCHAPV2_OP_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
+			   "- ignore op %d", resp->op_code);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_mschapv2_process_response(struct eap_sm *sm,
+					  struct eap_mschapv2_data *data,
+					  struct wpabuf *respData)
+{
+	struct eap_mschapv2_hdr *resp;
+	const u8 *pos, *end, *peer_challenge, *nt_response, *name;
+	u8 flags;
+	size_t len, name_len, i;
+	u8 expected[24];
+	const u8 *username, *user;
+	size_t username_len, user_len;
+	int res;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
+			       &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
+
+	end = pos + len;
+	resp = (struct eap_mschapv2_hdr *) pos;
+	pos = (u8 *) (resp + 1);
+
+	if (len < sizeof(*resp) + 1 + 49 ||
+	    resp->op_code != MSCHAPV2_OP_RESPONSE ||
+	    pos[0] != 49) {
+		wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
+				respData);
+		data->state = FAILURE;
+		return;
+	}
+	data->resp_mschapv2_id = resp->mschapv2_id;
+	pos++;
+	peer_challenge = pos;
+	pos += 16 + 8;
+	nt_response = pos;
+	pos += 24;
+	flags = *pos++;
+	name = pos;
+	name_len = end - name;
+
+	if (data->peer_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
+			   "Peer-Challenge");
+		peer_challenge = data->peer_challenge;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
+		    peer_challenge, 16);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
+	wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
+
+	/* MSCHAPv2 does not include optional domain name in the
+	 * challenge-response calculation, so remove domain prefix
+	 * (if present). */
+	username = sm->identity;
+	username_len = sm->identity_len;
+	for (i = 0; i < username_len; i++) {
+		if (username[i] == '\\') {
+			username_len -= i + 1;
+			username += i + 1;
+			break;
+		}
+	}
+
+	user = name;
+	user_len = name_len;
+	for (i = 0; i < user_len; i++) {
+		if (user[i] == '\\') {
+			user_len -= i + 1;
+			user += i + 1;
+			break;
+		}
+	}
+
+	if (username_len != user_len ||
+	    os_memcmp(username, user, username_len) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
+				  "name", username, username_len);
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
+				  "name", user, user_len);
+		data->state = FAILURE;
+		return;
+	}
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
+			  username, username_len);
+
+	if (sm->user->password_hash) {
+		res = generate_nt_response_pwhash(data->auth_challenge,
+						  peer_challenge,
+						  username, username_len,
+						  sm->user->password,
+						  expected);
+	} else {
+		res = generate_nt_response(data->auth_challenge,
+					   peer_challenge,
+					   username, username_len,
+					   sm->user->password,
+					   sm->user->password_len,
+					   expected);
+	}
+	if (res) {
+		data->state = FAILURE;
+		return;
+	}
+
+	if (os_memcmp(nt_response, expected, 24) == 0) {
+		const u8 *pw_hash;
+		u8 pw_hash_buf[16], pw_hash_hash[16];
+
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
+		data->state = SUCCESS_REQ;
+
+		/* Authenticator response is not really needed yet, but
+		 * calculate it here so that peer_challenge and username need
+		 * not be saved. */
+		if (sm->user->password_hash) {
+			pw_hash = sm->user->password;
+		} else {
+			if (nt_password_hash(sm->user->password,
+					     sm->user->password_len,
+					     pw_hash_buf) < 0) {
+				data->state = FAILURE;
+				return;
+			}
+			pw_hash = pw_hash_buf;
+		}
+		generate_authenticator_response_pwhash(
+			pw_hash, peer_challenge, data->auth_challenge,
+			username, username_len, nt_response,
+			data->auth_response);
+
+		hash_nt_password_hash(pw_hash, pw_hash_hash);
+		get_master_key(pw_hash_hash, nt_response, data->master_key);
+		data->master_key_valid = 1;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
+				data->master_key, MSCHAPV2_KEY_LEN);
+	} else {
+		wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
+			    expected, 24);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
+		data->state = FAILURE_REQ;
+	}
+}
+
+
+static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
+					      struct eap_mschapv2_data *data,
+					      struct wpabuf *respData)
+{
+	struct eap_mschapv2_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
+			       &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
+
+	resp = (struct eap_mschapv2_hdr *) pos;
+
+	if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
+			   " - authentication completed successfully");
+		data->state = SUCCESS;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
+			   "Response - peer rejected authentication");
+		data->state = FAILURE;
+	}
+}
+
+
+static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
+					      struct eap_mschapv2_data *data,
+					      struct wpabuf *respData)
+{
+	struct eap_mschapv2_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
+			       &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
+
+	resp = (struct eap_mschapv2_hdr *) pos;
+
+	if (resp->op_code == MSCHAPV2_OP_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
+			   " - authentication failed");
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
+			   "Response - authentication failed");
+	}
+
+	data->state = FAILURE;
+}
+
+
+static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
+				 struct wpabuf *respData)
+{
+	struct eap_mschapv2_data *data = priv;
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+		data->state = FAILURE;
+		return;
+	}
+
+	switch (data->state) {
+	case CHALLENGE:
+		eap_mschapv2_process_response(sm, data, respData);
+		break;
+	case SUCCESS_REQ:
+		eap_mschapv2_process_success_resp(sm, data, respData);
+		break;
+	case FAILURE_REQ:
+		eap_mschapv2_process_failure_resp(sm, data, respData);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
+			   "process", data->state);
+		break;
+	}
+}
+
+
+static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_mschapv2_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS || !data->master_key_valid)
+		return NULL;
+
+	*len = 2 * MSCHAPV2_KEY_LEN;
+	key = os_malloc(*len);
+	if (key == NULL)
+		return NULL;
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
+	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				MSCHAPV2_KEY_LEN, 1, 1);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
+
+	return key;
+}
+
+
+static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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,
+				      "MSCHAPV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_mschapv2_init;
+	eap->reset = eap_mschapv2_reset;
+	eap->buildReq = eap_mschapv2_buildReq;
+	eap->check = eap_mschapv2_check;
+	eap->process = eap_mschapv2_process;
+	eap->isDone = eap_mschapv2_isDone;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_pax.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_pax.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_pax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,569 +0,0 @@
-/*
- * hostapd / EAP-PAX (RFC 4746) server
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap_i.h"
-#include "eap_common/eap_pax_common.h"
-
-/*
- * Note: only PAX_STD subprotocol is currently supported
- *
- * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
- * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
- * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
- * RSAES-OAEP).
- */
-
-struct eap_pax_data {
-	enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
-	u8 mac_id;
-	union {
-		u8 e[2 * EAP_PAX_RAND_LEN];
-		struct {
-			u8 x[EAP_PAX_RAND_LEN]; /* server rand */
-			u8 y[EAP_PAX_RAND_LEN]; /* client rand */
-		} r;
-	} rand;
-	u8 ak[EAP_PAX_AK_LEN];
-	u8 mk[EAP_PAX_MK_LEN];
-	u8 ck[EAP_PAX_CK_LEN];
-	u8 ick[EAP_PAX_ICK_LEN];
-	int keys_set;
-	char *cid;
-	size_t cid_len;
-};
-
-
-static void * eap_pax_init(struct eap_sm *sm)
-{
-	struct eap_pax_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = PAX_STD_1;
-	/*
-	 * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
-	 * supported
-	 */
-	data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
-
-	return data;
-}
-
-
-static void eap_pax_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_pax_data *data = priv;
-	os_free(data->cid);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
-					   struct eap_pax_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_pax_hdr *pax;
-	u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
-
-	if (os_get_random(data->rand.r.x, EAP_PAX_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
-			    sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
-			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	pax = wpabuf_put(req, sizeof(*pax));
-	pax->op_code = EAP_PAX_OP_STD_1;
-	pax->flags = 0;
-	pax->mac_id = data->mac_id;
-	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
-	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
-
-	wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
-	wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
-		    data->rand.r.x, EAP_PAX_RAND_LEN);
-
-	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
-	eap_pax_mac(data->mac_id, (u8 *) "", 0,
-		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
-		    NULL, 0, NULL, 0, pos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
-					   struct eap_pax_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_pax_hdr *pax;
-	u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
-			    sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
-			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	pax = wpabuf_put(req, sizeof(*pax));
-	pax->op_code = EAP_PAX_OP_STD_3;
-	pax->flags = 0;
-	pax->mac_id = data->mac_id;
-	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
-	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
-
-	wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
-	pos = wpabuf_put(req, 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, pos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
-		    pos, EAP_PAX_MAC_LEN);
-	pos += EAP_PAX_MAC_LEN;
-
-	/* Optional ADE could be added here, if needed */
-
-	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
-	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
-		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
-		    NULL, 0, NULL, 0, pos);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_pax_data *data = priv;
-
-	switch (data->state) {
-	case PAX_STD_1:
-		return eap_pax_build_std_1(sm, data, id);
-	case PAX_STD_3:
-		return eap_pax_build_std_3(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
-			   data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_pax_data *data = priv;
-	struct eap_pax_hdr *resp;
-	const u8 *pos;
-	size_t len, mlen;
-	u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
-	if (pos == NULL || len < sizeof(*resp)) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
-		return TRUE;
-	}
-
-	mlen = sizeof(struct eap_hdr) + 1 + len;
-	resp = (struct eap_pax_hdr *) pos;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
-		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
-		   "public_key_id 0x%x",
-		   resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
-		   resp->public_key_id);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
-		    (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
-
-	if (data->state == PAX_STD_1 &&
-	    resp->op_code != EAP_PAX_OP_STD_2) {
-		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
-			   "ignore op %d", resp->op_code);
-		return TRUE;
-	}
-
-	if (data->state == PAX_STD_3 &&
-	    resp->op_code != EAP_PAX_OP_ACK) {
-		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
-			   "ignore op %d", resp->op_code);
-		return TRUE;
-	}
-
-	if (resp->op_code != EAP_PAX_OP_STD_2 &&
-	    resp->op_code != EAP_PAX_OP_ACK) {
-		wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
-			   resp->op_code);
-	}
-
-	if (data->mac_id != resp->mac_id) {
-		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
-			   "received 0x%x", data->mac_id, resp->mac_id);
-		return TRUE;
-	}
-
-	if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
-			   "received 0x%x", EAP_PAX_DH_GROUP_NONE,
-			   resp->dh_group_id);
-		return TRUE;
-	}
-
-	if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
-			   "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
-			   resp->public_key_id);
-		return TRUE;
-	}
-
-	if (resp->flags & EAP_PAX_FLAGS_MF) {
-		/* TODO: add support for reassembling fragments */
-		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
-		return TRUE;
-	}
-
-	if (resp->flags & EAP_PAX_FLAGS_CE) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
-		return TRUE;
-	}
-
-	if (data->keys_set) {
-		if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
-			wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
-			return TRUE;
-		}
-		icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
-		eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
-			    wpabuf_mhead(respData),
-			    wpabuf_len(respData) - EAP_PAX_ICV_LEN,
-			    NULL, 0, NULL, 0, icvbuf);
-		if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
-			wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
-			wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
-				    icvbuf, EAP_PAX_ICV_LEN);
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
-
-static void eap_pax_process_std_2(struct eap_sm *sm,
-				  struct eap_pax_data *data,
-				  struct wpabuf *respData)
-{
-	struct eap_pax_hdr *resp;
-	u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
-	const u8 *pos;
-	size_t len, left;
-	int i;
-
-	if (data->state != PAX_STD_1)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
-	if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
-		return;
-
-	resp = (struct eap_pax_hdr *) pos;
-	pos = (u8 *) (resp + 1);
-	left = len - sizeof(*resp);
-
-	if (left < 2 + EAP_PAX_RAND_LEN ||
-	    WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
-		return;
-	}
-	pos += 2;
-	left -= 2;
-	os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
-		    data->rand.r.y, EAP_PAX_RAND_LEN);
-	pos += EAP_PAX_RAND_LEN;
-	left -= EAP_PAX_RAND_LEN;
-
-	if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
-		return;
-	}
-	data->cid_len = WPA_GET_BE16(pos);
-	os_free(data->cid);
-	data->cid = os_malloc(data->cid_len);
-	if (data->cid == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
-			   "CID");
-		return;
-	}
-	os_memcpy(data->cid, pos + 2, data->cid_len);
-	pos += 2 + data->cid_len;
-	left -= 2 + data->cid_len;
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
-			  (u8 *) data->cid, data->cid_len);
-
-	if (left < 2 + EAP_PAX_MAC_LEN ||
-	    WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
-		return;
-	}
-	pos += 2;
-	left -= 2;
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
-		    pos, EAP_PAX_MAC_LEN);
-
-	if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
-				  (u8 *) data->cid, data->cid_len);
-		data->state = FAILURE;
-		return;
-	}
-
-	for (i = 0;
-	     i < EAP_MAX_METHODS &&
-		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-		      sm->user->methods[i].method != EAP_TYPE_NONE);
-	     i++) {
-		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
-		    sm->user->methods[i].method == EAP_TYPE_PAX)
-			break;
-	}
-
-	if (i >= EAP_MAX_METHODS ||
-	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-	    sm->user->methods[i].method != EAP_TYPE_PAX) {
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-PAX: EAP-PAX not enabled for CID",
-				  (u8 *) data->cid, data->cid_len);
-		data->state = FAILURE;
-		return;
-	}
-
-	if (sm->user->password == NULL ||
-	    sm->user->password_len != EAP_PAX_AK_LEN) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
-				  "user database for CID",
-				  (u8 *) data->cid, data->cid_len);
-		data->state = FAILURE;
-		return;
-	}
-	os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
-
-	if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
-					   data->rand.e, data->mk, data->ck,
-					   data->ick) < 0) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
-			   "key derivation");
-		data->state = FAILURE;
-		return;
-	}
-	data->keys_set = 1;
-
-	eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
-		    data->rand.r.x, EAP_PAX_RAND_LEN,
-		    data->rand.r.y, EAP_PAX_RAND_LEN,
-		    (u8 *) data->cid, data->cid_len, mac);
-	if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
-			   "PAX_STD-2");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
-			    mac, EAP_PAX_MAC_LEN);
-		data->state = FAILURE;
-		return;
-	}
-
-	pos += EAP_PAX_MAC_LEN;
-	left -= EAP_PAX_MAC_LEN;
-
-	if (left < EAP_PAX_ICV_LEN) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
-			   "PAX_STD-2", (unsigned long) left);
-		return;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
-	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
-		    wpabuf_head(respData),
-		    wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
-		    icvbuf);
-	if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
-			    icvbuf, EAP_PAX_ICV_LEN);
-		return;
-	}
-	pos += EAP_PAX_ICV_LEN;
-	left -= EAP_PAX_ICV_LEN;
-
-	if (left > 0) {
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
-			    pos, left);
-	}
-
-	data->state = PAX_STD_3;
-}
-
-
-static void eap_pax_process_ack(struct eap_sm *sm,
-				struct eap_pax_data *data,
-				struct wpabuf *respData)
-{
-	if (data->state != PAX_STD_3)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
-		   "completed successfully");
-	data->state = SUCCESS;
-}
-
-
-static void eap_pax_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_pax_data *data = priv;
-	struct eap_pax_hdr *resp;
-	const u8 *pos;
-	size_t len;
-
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
-			   "configured");
-		data->state = FAILURE;
-		return;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
-	if (pos == NULL || len < sizeof(*resp))
-		return;
-
-	resp = (struct eap_pax_hdr *) pos;
-
-	switch (resp->op_code) {
-	case EAP_PAX_OP_STD_2:
-		eap_pax_process_std_2(sm, data, respData);
-		break;
-	case EAP_PAX_OP_ACK:
-		eap_pax_process_ack(sm, data, respData);
-		break;
-	}
-}
-
-
-static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_pax_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_pax_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		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);
-
-	return key;
-}
-
-
-static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_pax_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		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);
-
-	return key;
-}
-
-
-static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_pax_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_pax_init;
-	eap->reset = eap_pax_reset;
-	eap->buildReq = eap_pax_buildReq;
-	eap->check = eap_pax_check;
-	eap->process = eap_pax_process;
-	eap->isDone = eap_pax_isDone;
-	eap->getKey = eap_pax_getKey;
-	eap->isSuccess = eap_pax_isSuccess;
-	eap->get_emsk = eap_pax_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_pax.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_pax.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_pax.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_pax.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,564 @@
+/*
+ * hostapd / EAP-PAX (RFC 4746) server
+ * Copyright (c) 2005-2007, Jouni Malinen <j at 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/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_pax_common.h"
+
+/*
+ * Note: only PAX_STD subprotocol is currently supported
+ *
+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
+ * RSAES-OAEP).
+ */
+
+struct eap_pax_data {
+	enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state;
+	u8 mac_id;
+	union {
+		u8 e[2 * EAP_PAX_RAND_LEN];
+		struct {
+			u8 x[EAP_PAX_RAND_LEN]; /* server rand */
+			u8 y[EAP_PAX_RAND_LEN]; /* client rand */
+		} r;
+	} rand;
+	u8 ak[EAP_PAX_AK_LEN];
+	u8 mk[EAP_PAX_MK_LEN];
+	u8 ck[EAP_PAX_CK_LEN];
+	u8 ick[EAP_PAX_ICK_LEN];
+	int keys_set;
+	char *cid;
+	size_t cid_len;
+};
+
+
+static void * eap_pax_init(struct eap_sm *sm)
+{
+	struct eap_pax_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = PAX_STD_1;
+	/*
+	 * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
+	 * supported
+	 */
+	data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
+
+	return data;
+}
+
+
+static void eap_pax_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_pax_data *data = priv;
+	os_free(data->cid);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm,
+					   struct eap_pax_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_pax_hdr *pax;
+	u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)");
+
+	if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
+			    sizeof(*pax) + 2 + EAP_PAX_RAND_LEN +
+			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	pax = wpabuf_put(req, sizeof(*pax));
+	pax->op_code = EAP_PAX_OP_STD_1;
+	pax->flags = 0;
+	pax->mac_id = data->mac_id;
+	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
+	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
+
+	wpabuf_put_be16(req, EAP_PAX_RAND_LEN);
+	wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)",
+		    data->rand.r.x, EAP_PAX_RAND_LEN);
+
+	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
+	eap_pax_mac(data->mac_id, (u8 *) "", 0,
+		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+		    NULL, 0, NULL, 0, pos);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm,
+					   struct eap_pax_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_pax_hdr *pax;
+	u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)");
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX,
+			    sizeof(*pax) + 2 + EAP_PAX_MAC_LEN +
+			    EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	pax = wpabuf_put(req, sizeof(*pax));
+	pax->op_code = EAP_PAX_OP_STD_3;
+	pax->flags = 0;
+	pax->mac_id = data->mac_id;
+	pax->dh_group_id = EAP_PAX_DH_GROUP_NONE;
+	pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE;
+
+	wpabuf_put_be16(req, EAP_PAX_MAC_LEN);
+	pos = wpabuf_put(req, 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, pos);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
+		    pos, EAP_PAX_MAC_LEN);
+	pos += EAP_PAX_MAC_LEN;
+
+	/* Optional ADE could be added here, if needed */
+
+	pos = wpabuf_put(req, EAP_PAX_MAC_LEN);
+	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+		    wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN,
+		    NULL, 0, NULL, 0, pos);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_pax_data *data = priv;
+
+	switch (data->state) {
+	case PAX_STD_1:
+		return eap_pax_build_std_1(sm, data, id);
+	case PAX_STD_3:
+		return eap_pax_build_std_3(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_pax_data *data = priv;
+	struct eap_pax_hdr *resp;
+	const u8 *pos;
+	size_t len, mlen;
+	u8 icvbuf[EAP_PAX_ICV_LEN], *icv;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
+	if (pos == NULL || len < sizeof(*resp)) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame");
+		return TRUE;
+	}
+
+	mlen = sizeof(struct eap_hdr) + 1 + len;
+	resp = (struct eap_pax_hdr *) pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
+		   "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
+		   "public_key_id 0x%x",
+		   resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id,
+		   resp->public_key_id);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
+		    (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN);
+
+	if (data->state == PAX_STD_1 &&
+	    resp->op_code != EAP_PAX_OP_STD_2) {
+		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - "
+			   "ignore op %d", resp->op_code);
+		return TRUE;
+	}
+
+	if (data->state == PAX_STD_3 &&
+	    resp->op_code != EAP_PAX_OP_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - "
+			   "ignore op %d", resp->op_code);
+		return TRUE;
+	}
+
+	if (resp->op_code != EAP_PAX_OP_STD_2 &&
+	    resp->op_code != EAP_PAX_OP_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x",
+			   resp->op_code);
+	}
+
+	if (data->mac_id != resp->mac_id) {
+		wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, "
+			   "received 0x%x", data->mac_id, resp->mac_id);
+		return TRUE;
+	}
+
+	if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, "
+			   "received 0x%x", EAP_PAX_DH_GROUP_NONE,
+			   resp->dh_group_id);
+		return TRUE;
+	}
+
+	if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, "
+			   "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE,
+			   resp->public_key_id);
+		return TRUE;
+	}
+
+	if (resp->flags & EAP_PAX_FLAGS_MF) {
+		/* TODO: add support for reassembling fragments */
+		wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported");
+		return TRUE;
+	}
+
+	if (resp->flags & EAP_PAX_FLAGS_CE) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag");
+		return TRUE;
+	}
+
+	if (data->keys_set) {
+		if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) {
+			wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet");
+			return TRUE;
+		}
+		icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN;
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
+		eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+			    wpabuf_mhead(respData),
+			    wpabuf_len(respData) - EAP_PAX_ICV_LEN,
+			    NULL, 0, NULL, 0, icvbuf);
+		if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
+			wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
+			wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
+				    icvbuf, EAP_PAX_ICV_LEN);
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+
+static void eap_pax_process_std_2(struct eap_sm *sm,
+				  struct eap_pax_data *data,
+				  struct wpabuf *respData)
+{
+	struct eap_pax_hdr *resp;
+	u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
+	const u8 *pos;
+	size_t len, left;
+	int i;
+
+	if (data->state != PAX_STD_1)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2");
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
+	if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN)
+		return;
+
+	resp = (struct eap_pax_hdr *) pos;
+	pos = (u8 *) (resp + 1);
+	left = len - sizeof(*resp);
+
+	if (left < 2 + EAP_PAX_RAND_LEN ||
+	    WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)");
+		return;
+	}
+	pos += 2;
+	left -= 2;
+	os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
+		    data->rand.r.y, EAP_PAX_RAND_LEN);
+	pos += EAP_PAX_RAND_LEN;
+	left -= EAP_PAX_RAND_LEN;
+
+	if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
+		return;
+	}
+	data->cid_len = WPA_GET_BE16(pos);
+	os_free(data->cid);
+	data->cid = os_malloc(data->cid_len);
+	if (data->cid == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for "
+			   "CID");
+		return;
+	}
+	os_memcpy(data->cid, pos + 2, data->cid_len);
+	pos += 2 + data->cid_len;
+	left -= 2 + data->cid_len;
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
+			  (u8 *) data->cid, data->cid_len);
+
+	if (left < 2 + EAP_PAX_MAC_LEN ||
+	    WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)");
+		return;
+	}
+	pos += 2;
+	left -= 2;
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
+		    pos, EAP_PAX_MAC_LEN);
+
+	if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID",
+				  (u8 *) data->cid, data->cid_len);
+		data->state = FAILURE;
+		return;
+	}
+
+	for (i = 0;
+	     i < EAP_MAX_METHODS &&
+		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+		      sm->user->methods[i].method != EAP_TYPE_NONE);
+	     i++) {
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_PAX)
+			break;
+	}
+
+	if (i >= EAP_MAX_METHODS ||
+	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+	    sm->user->methods[i].method != EAP_TYPE_PAX) {
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-PAX: EAP-PAX not enabled for CID",
+				  (u8 *) data->cid, data->cid_len);
+		data->state = FAILURE;
+		return;
+	}
+
+	if (sm->user->password == NULL ||
+	    sm->user->password_len != EAP_PAX_AK_LEN) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in "
+				  "user database for CID",
+				  (u8 *) data->cid, data->cid_len);
+		data->state = FAILURE;
+		return;
+	}
+	os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN);
+
+	if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
+					   data->rand.e, data->mk, data->ck,
+					   data->ick) < 0) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
+			   "key derivation");
+		data->state = FAILURE;
+		return;
+	}
+	data->keys_set = 1;
+
+	eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
+		    data->rand.r.x, EAP_PAX_RAND_LEN,
+		    data->rand.r.y, EAP_PAX_RAND_LEN,
+		    (u8 *) data->cid, data->cid_len, mac);
+	if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
+			   "PAX_STD-2");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
+			    mac, EAP_PAX_MAC_LEN);
+		data->state = FAILURE;
+		return;
+	}
+
+	pos += EAP_PAX_MAC_LEN;
+	left -= EAP_PAX_MAC_LEN;
+
+	if (left < EAP_PAX_ICV_LEN) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in "
+			   "PAX_STD-2", (unsigned long) left);
+		return;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN);
+	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+		    wpabuf_head(respData),
+		    wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
+		    icvbuf);
+	if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
+			    icvbuf, EAP_PAX_ICV_LEN);
+		return;
+	}
+	pos += EAP_PAX_ICV_LEN;
+	left -= EAP_PAX_ICV_LEN;
+
+	if (left > 0) {
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
+			    pos, left);
+	}
+
+	data->state = PAX_STD_3;
+}
+
+
+static void eap_pax_process_ack(struct eap_sm *sm,
+				struct eap_pax_data *data,
+				struct wpabuf *respData)
+{
+	if (data->state != PAX_STD_3)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication "
+		   "completed successfully");
+	data->state = SUCCESS;
+}
+
+
+static void eap_pax_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_pax_data *data = priv;
+	struct eap_pax_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
+			   "configured");
+		data->state = FAILURE;
+		return;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len);
+	if (pos == NULL || len < sizeof(*resp))
+		return;
+
+	resp = (struct eap_pax_hdr *) pos;
+
+	switch (resp->op_code) {
+	case EAP_PAX_OP_STD_2:
+		eap_pax_process_std_2(sm, data, respData);
+		break;
+	case EAP_PAX_OP_ACK:
+		eap_pax_process_ack(sm, data, respData);
+		break;
+	}
+}
+
+
+static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_pax_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		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);
+
+	return key;
+}
+
+
+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		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);
+
+	return key;
+}
+
+
+static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_pax_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_pax_init;
+	eap->reset = eap_pax_reset;
+	eap->buildReq = eap_pax_buildReq;
+	eap->check = eap_pax_check;
+	eap->process = eap_pax_process;
+	eap->isDone = eap_pax_isDone;
+	eap->getKey = eap_pax_getKey;
+	eap->isSuccess = eap_pax_isSuccess;
+	eap->get_emsk = eap_pax_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_peap.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_peap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_peap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1386 +0,0 @@
-/*
- * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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_common/eap_tlv_common.h"
-#include "eap_common/eap_peap_common.h"
-#include "tncs.h"
-
-
-/* Maximum supported PEAP version
- * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
- * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
- * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
- */
-#define EAP_PEAP_VERSION 1
-
-
-static void eap_peap_reset(struct eap_sm *sm, void *priv);
-
-
-struct eap_peap_data {
-	struct eap_ssl_data ssl;
-	enum {
-		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
-		PHASE2_METHOD, PHASE2_SOH,
-		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
-	} state;
-
-	int peap_version;
-	int recv_version;
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int force_version;
-	struct wpabuf *pending_phase2_resp;
-	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
-	int crypto_binding_sent;
-	int crypto_binding_used;
-	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
-	u8 binding_nonce[32];
-	u8 ipmk[40];
-	u8 cmk[20];
-	u8 *phase2_key;
-	size_t phase2_key_len;
-	struct wpabuf *soh_response;
-};
-
-
-static const char * eap_peap_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case PHASE1:
-		return "PHASE1";
-	case PHASE1_ID2:
-		return "PHASE1_ID2";
-	case PHASE2_START:
-		return "PHASE2_START";
-	case PHASE2_ID:
-		return "PHASE2_ID";
-	case PHASE2_METHOD:
-		return "PHASE2_METHOD";
-	case PHASE2_SOH:
-		return "PHASE2_SOH";
-	case PHASE2_TLV:
-		return "PHASE2_TLV";
-	case SUCCESS_REQ:
-		return "SUCCESS_REQ";
-	case FAILURE_REQ:
-		return "FAILURE_REQ";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_peap_state(struct eap_peap_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
-		   eap_peap_state_txt(data->state),
-		   eap_peap_state_txt(state));
-	data->state = state;
-}
-
-
-static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(e, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(e, buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
-static void eap_peap_req_success(struct eap_sm *sm,
-				 struct eap_peap_data *data)
-{
-	if (data->state == FAILURE || data->state == FAILURE_REQ) {
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	if (data->peap_version == 0) {
-		data->tlv_request = TLV_REQ_SUCCESS;
-		eap_peap_state(data, PHASE2_TLV);
-	} else {
-		eap_peap_state(data, SUCCESS_REQ);
-	}
-}
-
-
-static void eap_peap_req_failure(struct eap_sm *sm,
-				 struct eap_peap_data *data)
-{
-	if (data->state == FAILURE || data->state == FAILURE_REQ ||
-	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	if (data->peap_version == 0) {
-		data->tlv_request = TLV_REQ_FAILURE;
-		eap_peap_state(data, PHASE2_TLV);
-	} else {
-		eap_peap_state(data, FAILURE_REQ);
-	}
-}
-
-
-static void * eap_peap_init(struct eap_sm *sm)
-{
-	struct eap_peap_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->peap_version = EAP_PEAP_VERSION;
-	data->force_version = -1;
-	if (sm->user && sm->user->force_version >= 0) {
-		data->force_version = sm->user->force_version;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
-			   data->force_version);
-		data->peap_version = data->force_version;
-	}
-	data->state = START;
-	data->crypto_binding = OPTIONAL_BINDING;
-
-	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
-		eap_peap_reset(sm, data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_peap_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	if (data == NULL)
-		return;
-	if (data->phase2_priv && data->phase2_method)
-		data->phase2_method->reset(sm, data->phase2_priv);
-	eap_server_tls_ssl_deinit(sm, &data->ssl);
-	wpabuf_free(data->pending_phase2_resp);
-	os_free(data->phase2_key);
-	wpabuf_free(data->soh_response);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
-					    struct eap_peap_data *data, u8 id)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
-			   " request");
-		eap_peap_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
-
-	eap_peap_state(data, PHASE1);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
-						 struct eap_peap_data *data,
-						 u8 id)
-{
-	struct wpabuf *buf, *encr_req, msgbuf;
-	const u8 *req;
-	size_t req_len;
-
-	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
-		return NULL;
-	}
-	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
-	if (data->peap_version >= 2 && buf)
-		buf = eap_peapv2_tlv_eap_payload(buf);
-	if (buf == NULL)
-		return NULL;
-
-	req = wpabuf_head(buf);
-	req_len = wpabuf_len(buf);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
-			req, req_len);
-
-	if (data->peap_version == 0 &&
-	    data->phase2_method->method != EAP_TYPE_TLV) {
-		req += sizeof(struct eap_hdr);
-		req_len -= sizeof(struct eap_hdr);
-	}
-
-	wpabuf_set(&msgbuf, req, req_len);
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
-	wpabuf_free(buf);
-
-	return encr_req;
-}
-
-
-#ifdef EAP_SERVER_TNC
-static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
-						 struct eap_peap_data *data,
-						 u8 id)
-{
-	struct wpabuf *buf1, *buf, *encr_req, msgbuf;
-	const u8 *req;
-	size_t req_len;
-
-	buf1 = tncs_build_soh_request();
-	if (buf1 == NULL)
-		return NULL;
-
-	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
-			    EAP_CODE_REQUEST, id);
-	if (buf == NULL) {
-		wpabuf_free(buf1);
-		return NULL;
-	}
-	wpabuf_put_buf(buf, buf1);
-	wpabuf_free(buf1);
-
-	req = wpabuf_head(buf);
-	req_len = wpabuf_len(buf);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
-			req, req_len);
-
-	req += sizeof(struct eap_hdr);
-	req_len -= sizeof(struct eap_hdr);
-	wpabuf_set(&msgbuf, req, req_len);
-
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
-	wpabuf_free(buf);
-
-	return encr_req;
-}
-#endif /* EAP_SERVER_TNC */
-
-
-static void eap_peap_get_isk(struct eap_peap_data *data,
-			     u8 *isk, size_t isk_len)
-{
-	size_t key_len;
-
-	os_memset(isk, 0, isk_len);
-	if (data->phase2_key == NULL)
-		return;
-
-	key_len = data->phase2_key_len;
-	if (key_len > isk_len)
-		key_len = isk_len;
-	os_memcpy(isk, data->phase2_key, key_len);
-}
-
-
-static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
-{
-	u8 *tk;
-	u8 isk[32], imck[60];
-
-	/*
-	 * Tunnel key (TK) is the first 60 octets of the key generated by
-	 * phase 1 of PEAP (based on TLS).
-	 */
-	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
-				       EAP_TLS_KEY_LEN);
-	if (tk == NULL)
-		return -1;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
-
-	eap_peap_get_isk(data, isk, sizeof(isk));
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
-
-	/*
-	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
-	 * TempKey = First 40 octets of TK
-	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
-	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
-	 * in the end of the label just before ISK; is that just a typo?)
-	 */
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
-			imck, sizeof(imck));
-
-	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);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
-						 struct eap_peap_data *data,
-						 u8 id)
-{
-	struct wpabuf *buf, *encr_req;
-	size_t mlen;
-
-	mlen = 6; /* Result TLV */
-	if (data->crypto_binding != NO_BINDING)
-		mlen += 60; /* Cryptobinding TLV */
-#ifdef EAP_SERVER_TNC
-	if (data->soh_response)
-		mlen += wpabuf_len(data->soh_response);
-#endif /* EAP_SERVER_TNC */
-
-	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
-			    EAP_CODE_REQUEST, id);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, 0x80); /* Mandatory */
-	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
-	/* Length */
-	wpabuf_put_be16(buf, 2);
-	/* Status */
-	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
-			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
-
-	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
-	    data->crypto_binding != NO_BINDING) {
-		u8 *mac;
-		u8 eap_type = EAP_TYPE_PEAP;
-		const u8 *addr[2];
-		size_t len[2];
-		u16 tlv_type;
-
-#ifdef EAP_SERVER_TNC
-		if (data->soh_response) {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
-				   "Response TLV");
-			wpabuf_put_buf(buf, data->soh_response);
-			wpabuf_free(data->soh_response);
-			data->soh_response = NULL;
-		}
-#endif /* EAP_SERVER_TNC */
-
-		if (eap_peap_derive_cmk(sm, data) < 0 ||
-		    os_get_random(data->binding_nonce, 32)) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-
-		/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
-		addr[0] = wpabuf_put(buf, 0);
-		len[0] = 60;
-		addr[1] = &eap_type;
-		len[1] = 1;
-
-		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
-		if (data->peap_version >= 2)
-			tlv_type |= EAP_TLV_TYPE_MANDATORY;
-		wpabuf_put_be16(buf, tlv_type);
-		wpabuf_put_be16(buf, 56);
-
-		wpabuf_put_u8(buf, 0); /* Reserved */
-		wpabuf_put_u8(buf, data->peap_version); /* Version */
-		wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
-		wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
-		wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
-		mac = wpabuf_put(buf, 20); /* Compound_MAC */
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
-			    data->cmk, 20);
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
-			    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);
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
-			    mac, SHA1_MAC_LEN);
-		data->crypto_binding_sent = 1;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
-			    buf);
-
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
-	wpabuf_free(buf);
-
-	return encr_req;
-}
-
-
-static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
-						  struct eap_peap_data *data,
-						  u8 id, int success)
-{
-	struct wpabuf *encr_req, msgbuf;
-	size_t req_len;
-	struct eap_hdr *hdr;
-
-	req_len = sizeof(*hdr);
-	hdr = os_zalloc(req_len);
-	if (hdr == NULL)
-		return NULL;
-
-	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
-	hdr->identifier = id;
-	hdr->length = host_to_be16(req_len);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
-			(u8 *) hdr, req_len);
-
-	wpabuf_set(&msgbuf, hdr, req_len);
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
-	os_free(hdr);
-
-	return encr_req;
-}
-
-
-static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_peap_data *data = priv;
-
-	if (data->ssl.state == FRAG_ACK) {
-		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
-						data->peap_version);
-	}
-
-	if (data->ssl.state == WAIT_FRAG_ACK) {
-		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
-						data->peap_version, id);
-	}
-
-	switch (data->state) {
-	case START:
-		return eap_peap_build_start(sm, data, id);
-	case PHASE1:
-	case PHASE1_ID2:
-		if (data->peap_version < 2 &&
-		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
-				   "starting Phase2");
-			eap_peap_state(data, PHASE2_START);
-		}
-		break;
-	case PHASE2_ID:
-	case PHASE2_METHOD:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
-		break;
-#ifdef EAP_SERVER_TNC
-	case PHASE2_SOH:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
-		break;
-#endif /* EAP_SERVER_TNC */
-	case PHASE2_TLV:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
-		break;
-	case SUCCESS_REQ:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
-							       1);
-		break;
-	case FAILURE_REQ:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
-							       0);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
-			   __func__, data->state);
-		return NULL;
-	}
-
-	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
-					data->peap_version, id);
-}
-
-
-static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
-				EapType eap_type)
-{
-	if (data->phase2_priv && data->phase2_method) {
-		data->phase2_method->reset(sm, data->phase2_priv);
-		data->phase2_method = NULL;
-		data->phase2_priv = NULL;
-	}
-	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
-							eap_type);
-	if (!data->phase2_method)
-		return -1;
-
-	sm->init_phase2 = 1;
-	data->phase2_priv = data->phase2_method->init(sm);
-	sm->init_phase2 = 0;
-	return 0;
-}
-
-
-static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
-					  struct eap_peap_data *data,
-					  const u8 *crypto_tlv,
-					  size_t crypto_tlv_len)
-{
-	u8 buf[61], mac[SHA1_MAC_LEN];
-	const u8 *pos;
-
-	if (crypto_tlv_len != 4 + 56) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
-			   "length %d", (int) crypto_tlv_len);
-		return -1;
-	}
-
-	pos = crypto_tlv;
-	pos += 4; /* TLV header */
-	if (pos[1] != data->peap_version) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
-			   "mismatch (was %d; expected %d)",
-			   pos[1], data->peap_version);
-		return -1;
-	}
-
-	if (pos[3] != 1) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
-			   "SubType %d", pos[3]);
-		return -1;
-	}
-	pos += 4;
-	pos += 32; /* Nonce */
-
-	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
-	os_memcpy(buf, crypto_tlv, 60);
-	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
-	buf[60] = EAP_TYPE_PEAP;
-	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
-
-	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
-			   "cryptobinding TLV");
-		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
-			    buf, 61);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
-
-	return 0;
-}
-
-
-static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
-					struct eap_peap_data *data,
-					struct wpabuf *in_data)
-{
-	const u8 *pos;
-	size_t left;
-	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
-	size_t result_tlv_len = 0, crypto_tlv_len = 0;
-	int tlv_type, mandatory, tlv_len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
-	if (pos == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
-		return;
-	}
-
-	/* Parse TLVs */
-	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
-	while (left >= 4) {
-		mandatory = !!(pos[0] & 0x80);
-		tlv_type = pos[0] & 0x3f;
-		tlv_type = (tlv_type << 8) | pos[1];
-		tlv_len = ((int) pos[2] << 8) | pos[3];
-		pos += 4;
-		left -= 4;
-		if ((size_t) tlv_len > left) {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
-				   "(tlv_len=%d left=%lu)", tlv_len,
-				   (unsigned long) left);
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-		switch (tlv_type) {
-		case EAP_TLV_RESULT_TLV:
-			result_tlv = pos;
-			result_tlv_len = tlv_len;
-			break;
-		case EAP_TLV_CRYPTO_BINDING_TLV:
-			crypto_tlv = pos;
-			crypto_tlv_len = tlv_len;
-			break;
-		default:
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
-				   "%d%s", tlv_type,
-				   mandatory ? " (mandatory)" : "");
-			if (mandatory) {
-				eap_peap_state(data, FAILURE);
-				return;
-			}
-			/* Ignore this TLV, but process other TLVs */
-			break;
-		}
-
-		pos += tlv_len;
-		left -= tlv_len;
-	}
-	if (left) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
-			   "Request (left=%lu)", (unsigned long) left);
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	/* Process supported TLVs */
-	if (crypto_tlv && data->crypto_binding_sent) {
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
-			    crypto_tlv, crypto_tlv_len);
-		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
-						   crypto_tlv_len + 4) < 0) {
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-		data->crypto_binding_used = 1;
-	} else if (!crypto_tlv && data->crypto_binding_sent &&
-		   data->crypto_binding == REQUIRE_BINDING) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	if (result_tlv) {
-		int status;
-		const char *requested;
-
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
-			    result_tlv, result_tlv_len);
-		if (result_tlv_len < 2) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
-				   "(len=%lu)",
-				   (unsigned long) result_tlv_len);
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-		requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
-			"Failure";
-		status = WPA_GET_BE16(result_tlv);
-		if (status == EAP_TLV_RESULT_SUCCESS) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
-				   "- requested %s", requested);
-			if (data->tlv_request == TLV_REQ_SUCCESS)
-				eap_peap_state(data, SUCCESS);
-			else
-				eap_peap_state(data, FAILURE);
-			
-		} else if (status == EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
-				   "- requested %s", requested);
-			eap_peap_state(data, FAILURE);
-		} else {
-			wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
-				   "Status %d", status);
-			eap_peap_state(data, FAILURE);
-		}
-	}
-}
-
-
-#ifdef EAP_SERVER_TNC
-static void eap_peap_process_phase2_soh(struct eap_sm *sm,
-					struct eap_peap_data *data,
-					struct wpabuf *in_data)
-{
-	const u8 *pos, *vpos;
-	size_t left;
-	const u8 *soh_tlv = NULL;
-	size_t soh_tlv_len = 0;
-	int tlv_type, mandatory, tlv_len, vtlv_len;
-	u8 next_type;
-	u32 vendor_id;
-
-	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
-	if (pos == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
-			   "Extensions Method header - skip TNC");
-		goto auth_method;
-	}
-
-	/* Parse TLVs */
-	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
-	while (left >= 4) {
-		mandatory = !!(pos[0] & 0x80);
-		tlv_type = pos[0] & 0x3f;
-		tlv_type = (tlv_type << 8) | pos[1];
-		tlv_len = ((int) pos[2] << 8) | pos[3];
-		pos += 4;
-		left -= 4;
-		if ((size_t) tlv_len > left) {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
-				   "(tlv_len=%d left=%lu)", tlv_len,
-				   (unsigned long) left);
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-		switch (tlv_type) {
-		case EAP_TLV_VENDOR_SPECIFIC_TLV:
-			if (tlv_len < 4) {
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
-					   "vendor specific TLV (len=%d)",
-					   (int) tlv_len);
-				eap_peap_state(data, FAILURE);
-				return;
-			}
-
-			vendor_id = WPA_GET_BE32(pos);
-			if (vendor_id != EAP_VENDOR_MICROSOFT) {
-				if (mandatory) {
-					eap_peap_state(data, FAILURE);
-					return;
-				}
-				break;
-			}
-
-			vpos = pos + 4;
-			mandatory = !!(vpos[0] & 0x80);
-			tlv_type = vpos[0] & 0x3f;
-			tlv_type = (tlv_type << 8) | vpos[1];
-			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
-			vpos += 4;
-			if (vpos + vtlv_len > pos + left) {
-				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
-					   "underrun");
-				eap_peap_state(data, FAILURE);
-				return;
-			}
-
-			if (tlv_type == 1) {
-				soh_tlv = vpos;
-				soh_tlv_len = vtlv_len;
-				break;
-			}
-
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
-				   "Type %d%s", tlv_type,
-				   mandatory ? " (mandatory)" : "");
-			if (mandatory) {
-				eap_peap_state(data, FAILURE);
-				return;
-			}
-			/* Ignore this TLV, but process other TLVs */
-			break;
-		default:
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
-				   "%d%s", tlv_type,
-				   mandatory ? " (mandatory)" : "");
-			if (mandatory) {
-				eap_peap_state(data, FAILURE);
-				return;
-			}
-			/* Ignore this TLV, but process other TLVs */
-			break;
-		}
-
-		pos += tlv_len;
-		left -= tlv_len;
-	}
-	if (left) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
-			   "Request (left=%lu)", (unsigned long) left);
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	/* Process supported TLVs */
-	if (soh_tlv) {
-		int failure = 0;
-		wpabuf_free(data->soh_response);
-		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
-						      &failure);
-		if (failure) {
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-auth_method:
-	eap_peap_state(data, PHASE2_METHOD);
-	next_type = sm->user->methods[0].method;
-	sm->user_eap_method_index = 1;
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
-	eap_peap_phase2_init(sm, data, next_type);
-}
-#endif /* EAP_SERVER_TNC */
-
-
-static void eap_peap_process_phase2_response(struct eap_sm *sm,
-					     struct eap_peap_data *data,
-					     struct wpabuf *in_data)
-{
-	u8 next_type = EAP_TYPE_NONE;
-	const struct eap_hdr *hdr;
-	const u8 *pos;
-	size_t left;
-
-	if (data->state == PHASE2_TLV) {
-		eap_peap_process_phase2_tlv(sm, data, in_data);
-		return;
-	}
-
-#ifdef EAP_SERVER_TNC
-	if (data->state == PHASE2_SOH) {
-		eap_peap_process_phase2_soh(sm, data, in_data);
-		return;
-	}
-#endif /* EAP_SERVER_TNC */
-
-	if (data->phase2_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
-			   "initialized?!", __func__);
-		return;
-	}
-
-	hdr = wpabuf_head(in_data);
-	pos = (const u8 *) (hdr + 1);
-
-	if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
-		left = wpabuf_len(in_data) - sizeof(*hdr);
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
-			    "allowed types", pos + 1, left - 1);
-		eap_sm_process_nak(sm, pos + 1, left - 1);
-		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index].method !=
-		    EAP_TYPE_NONE) {
-			next_type = sm->user->methods[
-				sm->user_eap_method_index++].method;
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
-				   next_type);
-		} else {
-			eap_peap_req_failure(sm, data);
-			next_type = EAP_TYPE_NONE;
-		}
-		eap_peap_phase2_init(sm, data, next_type);
-		return;
-	}
-
-	if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
-			   "ignore the packet");
-		return;
-	}
-
-	data->phase2_method->process(sm, data->phase2_priv, in_data);
-
-	if (sm->method_pending == METHOD_PENDING_WAIT) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
-			   "pending wait state - save decrypted response");
-		wpabuf_free(data->pending_phase2_resp);
-		data->pending_phase2_resp = wpabuf_dup(in_data);
-	}
-
-	if (!data->phase2_method->isDone(sm, data->phase2_priv))
-		return;
-
-	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
-		eap_peap_req_failure(sm, data);
-		next_type = EAP_TYPE_NONE;
-		eap_peap_phase2_init(sm, data, next_type);
-		return;
-	}
-
-	os_free(data->phase2_key);
-	if (data->phase2_method->getKey) {
-		data->phase2_key = data->phase2_method->getKey(
-			sm, data->phase2_priv, &data->phase2_key_len);
-		if (data->phase2_key == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
-				   "failed");
-			eap_peap_req_failure(sm, data);
-			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
-			return;
-		}
-	}
-
-	switch (data->state) {
-	case PHASE1_ID2:
-	case PHASE2_ID:
-	case PHASE2_SOH:
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
-					  "Identity not found in the user "
-					  "database",
-					  sm->identity, sm->identity_len);
-			eap_peap_req_failure(sm, data);
-			next_type = EAP_TYPE_NONE;
-			break;
-		}
-
-#ifdef EAP_SERVER_TNC
-		if (data->state != PHASE2_SOH && sm->tnc &&
-		    data->peap_version == 0) {
-			eap_peap_state(data, PHASE2_SOH);
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
-				   "TNC (NAP SOH)");
-			next_type = EAP_TYPE_NONE;
-			break;
-		}
-#endif /* EAP_SERVER_TNC */
-
-		eap_peap_state(data, PHASE2_METHOD);
-		next_type = sm->user->methods[0].method;
-		sm->user_eap_method_index = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
-		break;
-	case PHASE2_METHOD:
-		eap_peap_req_success(sm, data);
-		next_type = EAP_TYPE_NONE;
-		break;
-	case FAILURE:
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
-			   __func__, data->state);
-		break;
-	}
-
-	eap_peap_phase2_init(sm, data, next_type);
-}
-
-
-static void eap_peap_process_phase2(struct eap_sm *sm,
-				    struct eap_peap_data *data,
-				    const struct wpabuf *respData,
-				    struct wpabuf *in_buf)
-{
-	struct wpabuf *in_decrypted;
-	const struct eap_hdr *hdr;
-	size_t len;
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
-		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
-
-	if (data->pending_phase2_resp) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
-			   "skip decryption and use old data");
-		eap_peap_process_phase2_response(sm, data,
-						 data->pending_phase2_resp);
-		wpabuf_free(data->pending_phase2_resp);
-		data->pending_phase2_resp = NULL;
-		return;
-	}
-
-	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
-					      in_buf);
-	if (in_decrypted == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
-			   "data");
-		eap_peap_state(data, FAILURE);
-		return;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
-			    in_decrypted);
-
-	hdr = wpabuf_head(in_decrypted);
-
-	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
-		const struct eap_hdr *resp;
-		struct eap_hdr *nhdr;
-		struct wpabuf *nbuf =
-			wpabuf_alloc(sizeof(struct eap_hdr) +
-				     wpabuf_len(in_decrypted));
-		if (nbuf == NULL) {
-			wpabuf_free(in_decrypted);
-			return;
-		}
-
-		resp = wpabuf_head(respData);
-		nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
-		nhdr->code = resp->code;
-		nhdr->identifier = resp->identifier;
-		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
-					    wpabuf_len(in_decrypted));
-		wpabuf_put_buf(nbuf, in_decrypted);
-		wpabuf_free(in_decrypted);
-
-		in_decrypted = nbuf;
-	} else if (data->peap_version >= 2) {
-		struct eap_tlv_hdr *tlv;
-		struct wpabuf *nmsg;
-
-		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
-				   "EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		tlv = wpabuf_mhead(in_decrypted);
-		if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
-		    EAP_TLV_EAP_PAYLOAD_TLV) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		if (sizeof(*tlv) + be_to_host16(tlv->length) >
-		    wpabuf_len(in_decrypted)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
-				   "length");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-		hdr = (struct eap_hdr *) (tlv + 1);
-		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
-			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
-				   "EAP packet in EAP TLV");
-			wpabuf_free(in_decrypted);
-			return;
-		}
-
-		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
-		if (nmsg == NULL) {
-			wpabuf_free(in_decrypted);
-			return;
-		}
-
-		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
-		wpabuf_free(in_decrypted);
-		in_decrypted = nmsg;
-	}
-
-	hdr = wpabuf_head(in_decrypted);
-	if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
-			   "EAP frame (len=%lu)",
-			   (unsigned long) wpabuf_len(in_decrypted));
-		wpabuf_free(in_decrypted);
-		eap_peap_req_failure(sm, data);
-		return;
-	}
-	len = be_to_host16(hdr->length);
-	if (len > wpabuf_len(in_decrypted)) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
-			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
-			   (unsigned long) wpabuf_len(in_decrypted),
-			   (unsigned long) len);
-		wpabuf_free(in_decrypted);
-		eap_peap_req_failure(sm, data);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
-		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
-		   (unsigned long) len);
-	switch (hdr->code) {
-	case EAP_CODE_RESPONSE:
-		eap_peap_process_phase2_response(sm, data, in_decrypted);
-		break;
-	case EAP_CODE_SUCCESS:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
-		if (data->state == SUCCESS_REQ) {
-			eap_peap_state(data, SUCCESS);
-		}
-		break;
-	case EAP_CODE_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
-		eap_peap_state(data, FAILURE);
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
-			   "Phase 2 EAP header", hdr->code);
-		break;
-	}
-
-	wpabuf_free(in_decrypted);
-}
-
-
-static int eap_peapv2_start_phase2(struct eap_sm *sm,
-				   struct eap_peap_data *data)
-{
-	struct wpabuf *buf, *buf2;
-
-	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
-		   "payload in the same message");
-	eap_peap_state(data, PHASE1_ID2);
-	if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
-		return -1;
-
-	/* TODO: which Id to use here? */
-	buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
-	if (buf == NULL)
-		return -1;
-
-	buf2 = eap_peapv2_tlv_eap_payload(buf);
-	if (buf2 == NULL)
-		return -1;
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
-
-	buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-				     buf2);
-	wpabuf_free(buf2);
-
-	if (buf == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
-			   "data");
-		return -1;
-	}
-
-	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
-			buf);
-
-	/* Append TLS data into the pending buffer after the Server Finished */
-	if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
-		wpabuf_free(buf);
-		return -1;
-	}
-	wpabuf_put_buf(data->ssl.tls_out, buf);
-	wpabuf_free(buf);
-
-	return 0;
-}
-
-
-static int eap_peap_process_version(struct eap_sm *sm, void *priv,
-				    int peer_version)
-{
-	struct eap_peap_data *data = priv;
-
-	data->recv_version = peer_version;
-	if (data->force_version >= 0 && peer_version != data->force_version) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
-			   " version (forced=%d peer=%d) - reject",
-			   data->force_version, peer_version);
-		return -1;
-	}
-	if (peer_version < data->peap_version) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
-			   "use version %d",
-			   peer_version, data->peap_version, peer_version);
-		data->peap_version = peer_version;
-	}
-
-	return 0;
-}
-
-
-static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
-				 const struct wpabuf *respData)
-{
-	struct eap_peap_data *data = priv;
-
-	switch (data->state) {
-	case PHASE1:
-		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
-			eap_peap_state(data, FAILURE);
-			break;
-		}
-
-		if (data->peap_version >= 2 &&
-		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			if (eap_peapv2_start_phase2(sm, data)) {
-				eap_peap_state(data, FAILURE);
-				break;
-			}
-		}
-		break;
-	case PHASE2_START:
-		eap_peap_state(data, PHASE2_ID);
-		eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
-		break;
-	case PHASE1_ID2:
-	case PHASE2_ID:
-	case PHASE2_METHOD:
-	case PHASE2_SOH:
-	case PHASE2_TLV:
-		eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
-		break;
-	case SUCCESS_REQ:
-		eap_peap_state(data, SUCCESS);
-		break;
-	case FAILURE_REQ:
-		eap_peap_state(data, FAILURE);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
-			   data->state, __func__);
-		break;
-	}
-}
-
-
-static void eap_peap_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_peap_data *data = priv;
-	if (eap_server_tls_process(sm, &data->ssl, respData, data,
-				   EAP_TYPE_PEAP, eap_peap_process_version,
-				   eap_peap_process_msg) < 0)
-		eap_peap_state(data, FAILURE);
-}
-
-
-static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_peap_data *data = priv;
-	u8 *eapKeyData;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	if (data->crypto_binding_used) {
-		u8 csk[128];
-		/*
-		 * Note: It looks like Microsoft implementation requires null
-		 * termination for this label while the one used for deriving
-		 * IPMK|CMK did not use null termination.
-		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
-		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
-		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
-		if (eapKeyData) {
-			os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
-			*len = EAP_TLS_KEY_LEN;
-			wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
-				    eapKeyData, EAP_TLS_KEY_LEN);
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
-				   "key");
-		}
-
-		return eapKeyData;
-	}
-
-	/* TODO: PEAPv1 - different label in some cases */
-	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption",
-					       EAP_TLS_KEY_LEN);
-	if (eapKeyData) {
-		*len = EAP_TLS_KEY_LEN;
-		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
-			    eapKeyData, EAP_TLS_KEY_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
-	}
-
-	return eapKeyData;
-}
-
-
-static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_peap_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_peap_init;
-	eap->reset = eap_peap_reset;
-	eap->buildReq = eap_peap_buildReq;
-	eap->check = eap_peap_check;
-	eap->process = eap_peap_process;
-	eap->isDone = eap_peap_isDone;
-	eap->getKey = eap_peap_getKey;
-	eap->isSuccess = eap_peap_isSuccess;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_peap.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_peap.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_peap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_peap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1384 @@
+/*
+ * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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 "crypto/random.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
+#include "tncs.h"
+
+
+/* Maximum supported PEAP version
+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
+ * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
+ */
+#define EAP_PEAP_VERSION 1
+
+
+static void eap_peap_reset(struct eap_sm *sm, void *priv);
+
+
+struct eap_peap_data {
+	struct eap_ssl_data ssl;
+	enum {
+		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
+		PHASE2_METHOD, PHASE2_SOH,
+		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
+	} state;
+
+	int peap_version;
+	int recv_version;
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int force_version;
+	struct wpabuf *pending_phase2_resp;
+	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
+	int crypto_binding_sent;
+	int crypto_binding_used;
+	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+	u8 binding_nonce[32];
+	u8 ipmk[40];
+	u8 cmk[20];
+	u8 *phase2_key;
+	size_t phase2_key_len;
+	struct wpabuf *soh_response;
+};
+
+
+static const char * eap_peap_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case PHASE1:
+		return "PHASE1";
+	case PHASE1_ID2:
+		return "PHASE1_ID2";
+	case PHASE2_START:
+		return "PHASE2_START";
+	case PHASE2_ID:
+		return "PHASE2_ID";
+	case PHASE2_METHOD:
+		return "PHASE2_METHOD";
+	case PHASE2_SOH:
+		return "PHASE2_SOH";
+	case PHASE2_TLV:
+		return "PHASE2_TLV";
+	case SUCCESS_REQ:
+		return "SUCCESS_REQ";
+	case FAILURE_REQ:
+		return "FAILURE_REQ";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_peap_state(struct eap_peap_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
+		   eap_peap_state_txt(data->state),
+		   eap_peap_state_txt(state));
+	data->state = state;
+}
+
+
+static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
+{
+	struct wpabuf *e;
+	struct eap_tlv_hdr *tlv;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
+	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
+	if (e == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
+			   "for TLV encapsulation");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	tlv = wpabuf_put(e, sizeof(*tlv));
+	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+				     EAP_TLV_EAP_PAYLOAD_TLV);
+	tlv->length = host_to_be16(wpabuf_len(buf));
+	wpabuf_put_buf(e, buf);
+	wpabuf_free(buf);
+	return e;
+}
+
+
+static void eap_peap_req_success(struct eap_sm *sm,
+				 struct eap_peap_data *data)
+{
+	if (data->state == FAILURE || data->state == FAILURE_REQ) {
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	if (data->peap_version == 0) {
+		data->tlv_request = TLV_REQ_SUCCESS;
+		eap_peap_state(data, PHASE2_TLV);
+	} else {
+		eap_peap_state(data, SUCCESS_REQ);
+	}
+}
+
+
+static void eap_peap_req_failure(struct eap_sm *sm,
+				 struct eap_peap_data *data)
+{
+	if (data->state == FAILURE || data->state == FAILURE_REQ ||
+	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	if (data->peap_version == 0) {
+		data->tlv_request = TLV_REQ_FAILURE;
+		eap_peap_state(data, PHASE2_TLV);
+	} else {
+		eap_peap_state(data, FAILURE_REQ);
+	}
+}
+
+
+static void * eap_peap_init(struct eap_sm *sm)
+{
+	struct eap_peap_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->peap_version = EAP_PEAP_VERSION;
+	data->force_version = -1;
+	if (sm->user && sm->user->force_version >= 0) {
+		data->force_version = sm->user->force_version;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
+			   data->force_version);
+		data->peap_version = data->force_version;
+	}
+	data->state = START;
+	data->crypto_binding = OPTIONAL_BINDING;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
+		eap_peap_reset(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_peap_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->reset(sm, data->phase2_priv);
+	eap_server_tls_ssl_deinit(sm, &data->ssl);
+	wpabuf_free(data->pending_phase2_resp);
+	os_free(data->phase2_key);
+	wpabuf_free(data->soh_response);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
+					    struct eap_peap_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
+			   " request");
+		eap_peap_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
+
+	eap_peap_state(data, PHASE1);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
+						 struct eap_peap_data *data,
+						 u8 id)
+{
+	struct wpabuf *buf, *encr_req, msgbuf;
+	const u8 *req;
+	size_t req_len;
+
+	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
+		return NULL;
+	}
+	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
+	if (data->peap_version >= 2 && buf)
+		buf = eap_peapv2_tlv_eap_payload(buf);
+	if (buf == NULL)
+		return NULL;
+
+	req = wpabuf_head(buf);
+	req_len = wpabuf_len(buf);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
+			req, req_len);
+
+	if (data->peap_version == 0 &&
+	    data->phase2_method->method != EAP_TYPE_TLV) {
+		req += sizeof(struct eap_hdr);
+		req_len -= sizeof(struct eap_hdr);
+	}
+
+	wpabuf_set(&msgbuf, req, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+
+
+#ifdef EAP_SERVER_TNC
+static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
+						 struct eap_peap_data *data,
+						 u8 id)
+{
+	struct wpabuf *buf1, *buf, *encr_req, msgbuf;
+	const u8 *req;
+	size_t req_len;
+
+	buf1 = tncs_build_soh_request();
+	if (buf1 == NULL)
+		return NULL;
+
+	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
+			    EAP_CODE_REQUEST, id);
+	if (buf == NULL) {
+		wpabuf_free(buf1);
+		return NULL;
+	}
+	wpabuf_put_buf(buf, buf1);
+	wpabuf_free(buf1);
+
+	req = wpabuf_head(buf);
+	req_len = wpabuf_len(buf);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
+			req, req_len);
+
+	req += sizeof(struct eap_hdr);
+	req_len -= sizeof(struct eap_hdr);
+	wpabuf_set(&msgbuf, req, req_len);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+#endif /* EAP_SERVER_TNC */
+
+
+static void eap_peap_get_isk(struct eap_peap_data *data,
+			     u8 *isk, size_t isk_len)
+{
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+	if (data->phase2_key == NULL)
+		return;
+
+	key_len = data->phase2_key_len;
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, data->phase2_key, key_len);
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+	u8 *tk;
+	u8 isk[32], imck[60];
+
+	/*
+	 * Tunnel key (TK) is the first 60 octets of the key generated by
+	 * phase 1 of PEAP (based on TLS).
+	 */
+	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
+				       EAP_TLS_KEY_LEN);
+	if (tk == NULL)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	eap_peap_get_isk(data, isk, sizeof(isk));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+	/*
+	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
+	 * TempKey = First 40 octets of TK
+	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+	 * in the end of the label just before ISK; is that just a typo?)
+	 */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+		os_free(tk);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+			imck, sizeof(imck));
+
+	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);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
+						 struct eap_peap_data *data,
+						 u8 id)
+{
+	struct wpabuf *buf, *encr_req;
+	size_t mlen;
+
+	mlen = 6; /* Result TLV */
+	if (data->crypto_binding != NO_BINDING)
+		mlen += 60; /* Cryptobinding TLV */
+#ifdef EAP_SERVER_TNC
+	if (data->soh_response)
+		mlen += wpabuf_len(data->soh_response);
+#endif /* EAP_SERVER_TNC */
+
+	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
+			    EAP_CODE_REQUEST, id);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, 0x80); /* Mandatory */
+	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
+	/* Length */
+	wpabuf_put_be16(buf, 2);
+	/* Status */
+	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
+			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
+
+	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+	    data->crypto_binding != NO_BINDING) {
+		u8 *mac;
+		u8 eap_type = EAP_TYPE_PEAP;
+		const u8 *addr[2];
+		size_t len[2];
+		u16 tlv_type;
+
+#ifdef EAP_SERVER_TNC
+		if (data->soh_response) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
+				   "Response TLV");
+			wpabuf_put_buf(buf, data->soh_response);
+			wpabuf_free(data->soh_response);
+			data->soh_response = NULL;
+		}
+#endif /* EAP_SERVER_TNC */
+
+		if (eap_peap_derive_cmk(sm, data) < 0 ||
+		    random_get_bytes(data->binding_nonce, 32)) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+
+		/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+		addr[0] = wpabuf_put(buf, 0);
+		len[0] = 60;
+		addr[1] = &eap_type;
+		len[1] = 1;
+
+		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+		if (data->peap_version >= 2)
+			tlv_type |= EAP_TLV_TYPE_MANDATORY;
+		wpabuf_put_be16(buf, tlv_type);
+		wpabuf_put_be16(buf, 56);
+
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_u8(buf, data->peap_version); /* Version */
+		wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
+		wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
+		wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
+		mac = wpabuf_put(buf, 20); /* Compound_MAC */
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
+			    data->cmk, 20);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+			    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);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
+			    mac, SHA1_MAC_LEN);
+		data->crypto_binding_sent = 1;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
+			    buf);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+
+
+static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
+						  struct eap_peap_data *data,
+						  u8 id, int success)
+{
+	struct wpabuf *encr_req, msgbuf;
+	size_t req_len;
+	struct eap_hdr *hdr;
+
+	req_len = sizeof(*hdr);
+	hdr = os_zalloc(req_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
+	hdr->identifier = id;
+	hdr->length = host_to_be16(req_len);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
+			(u8 *) hdr, req_len);
+
+	wpabuf_set(&msgbuf, hdr, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
+	os_free(hdr);
+
+	return encr_req;
+}
+
+
+static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_peap_data *data = priv;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
+						data->peap_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+						data->peap_version, id);
+	}
+
+	switch (data->state) {
+	case START:
+		return eap_peap_build_start(sm, data, id);
+	case PHASE1:
+	case PHASE1_ID2:
+		if (data->peap_version < 2 &&
+		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
+				   "starting Phase2");
+			eap_peap_state(data, PHASE2_START);
+		}
+		break;
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
+		break;
+#ifdef EAP_SERVER_TNC
+	case PHASE2_SOH:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
+		break;
+#endif /* EAP_SERVER_TNC */
+	case PHASE2_TLV:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
+		break;
+	case SUCCESS_REQ:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
+							       1);
+		break;
+	case FAILURE_REQ:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
+							       0);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
+			   __func__, data->state);
+		return NULL;
+	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+					data->peap_version, id);
+}
+
+
+static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
+				EapType eap_type)
+{
+	if (data->phase2_priv && data->phase2_method) {
+		data->phase2_method->reset(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+	}
+	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
+							eap_type);
+	if (!data->phase2_method)
+		return -1;
+
+	sm->init_phase2 = 1;
+	data->phase2_priv = data->phase2_method->init(sm);
+	sm->init_phase2 = 0;
+	return 0;
+}
+
+
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+					  struct eap_peap_data *data,
+					  const u8 *crypto_tlv,
+					  size_t crypto_tlv_len)
+{
+	u8 buf[61], mac[SHA1_MAC_LEN];
+	const u8 *pos;
+
+	if (crypto_tlv_len != 4 + 56) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+			   "length %d", (int) crypto_tlv_len);
+		return -1;
+	}
+
+	pos = crypto_tlv;
+	pos += 4; /* TLV header */
+	if (pos[1] != data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+			   "mismatch (was %d; expected %d)",
+			   pos[1], data->peap_version);
+		return -1;
+	}
+
+	if (pos[3] != 1) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+			   "SubType %d", pos[3]);
+		return -1;
+	}
+	pos += 4;
+	pos += 32; /* Nonce */
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	os_memcpy(buf, crypto_tlv, 60);
+	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+	buf[60] = EAP_TYPE_PEAP;
+	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+			   "cryptobinding TLV");
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
+			    buf, 61);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+	return 0;
+}
+
+
+static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
+					struct eap_peap_data *data,
+					struct wpabuf *in_data)
+{
+	const u8 *pos;
+	size_t left;
+	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+	size_t result_tlv_len = 0, crypto_tlv_len = 0;
+	int tlv_type, mandatory, tlv_len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
+		return;
+	}
+
+	/* Parse TLVs */
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = pos[0] & 0x3f;
+		tlv_type = (tlv_type << 8) | pos[1];
+		tlv_len = ((int) pos[2] << 8) | pos[3];
+		pos += 4;
+		left -= 4;
+		if ((size_t) tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+				   "(tlv_len=%d left=%lu)", tlv_len,
+				   (unsigned long) left);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_RESULT_TLV:
+			result_tlv = pos;
+			result_tlv_len = tlv_len;
+			break;
+		case EAP_TLV_CRYPTO_BINDING_TLV:
+			crypto_tlv = pos;
+			crypto_tlv_len = tlv_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	/* Process supported TLVs */
+	if (crypto_tlv && data->crypto_binding_sent) {
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+			    crypto_tlv, crypto_tlv_len);
+		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+						   crypto_tlv_len + 4) < 0) {
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		data->crypto_binding_used = 1;
+	} else if (!crypto_tlv && data->crypto_binding_sent &&
+		   data->crypto_binding == REQUIRE_BINDING) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	if (result_tlv) {
+		int status;
+		const char *requested;
+
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
+			    result_tlv, result_tlv_len);
+		if (result_tlv_len < 2) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
+				   "(len=%lu)",
+				   (unsigned long) result_tlv_len);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
+			"Failure";
+		status = WPA_GET_BE16(result_tlv);
+		if (status == EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
+				   "- requested %s", requested);
+			if (data->tlv_request == TLV_REQ_SUCCESS)
+				eap_peap_state(data, SUCCESS);
+			else
+				eap_peap_state(data, FAILURE);
+			
+		} else if (status == EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
+				   "- requested %s", requested);
+			eap_peap_state(data, FAILURE);
+		} else {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
+				   "Status %d", status);
+			eap_peap_state(data, FAILURE);
+		}
+	}
+}
+
+
+#ifdef EAP_SERVER_TNC
+static void eap_peap_process_phase2_soh(struct eap_sm *sm,
+					struct eap_peap_data *data,
+					struct wpabuf *in_data)
+{
+	const u8 *pos, *vpos;
+	size_t left;
+	const u8 *soh_tlv = NULL;
+	size_t soh_tlv_len = 0;
+	int tlv_type, mandatory, tlv_len, vtlv_len;
+	u8 next_type;
+	u32 vendor_id;
+
+	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
+			   "Extensions Method header - skip TNC");
+		goto auth_method;
+	}
+
+	/* Parse TLVs */
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = pos[0] & 0x3f;
+		tlv_type = (tlv_type << 8) | pos[1];
+		tlv_len = ((int) pos[2] << 8) | pos[3];
+		pos += 4;
+		left -= 4;
+		if ((size_t) tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+				   "(tlv_len=%d left=%lu)", tlv_len,
+				   (unsigned long) left);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_VENDOR_SPECIFIC_TLV:
+			if (tlv_len < 4) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
+					   "vendor specific TLV (len=%d)",
+					   (int) tlv_len);
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+
+			vendor_id = WPA_GET_BE32(pos);
+			if (vendor_id != EAP_VENDOR_MICROSOFT) {
+				if (mandatory) {
+					eap_peap_state(data, FAILURE);
+					return;
+				}
+				break;
+			}
+
+			vpos = pos + 4;
+			mandatory = !!(vpos[0] & 0x80);
+			tlv_type = vpos[0] & 0x3f;
+			tlv_type = (tlv_type << 8) | vpos[1];
+			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
+			vpos += 4;
+			if (vpos + vtlv_len > pos + left) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
+					   "underrun");
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+
+			if (tlv_type == 1) {
+				soh_tlv = vpos;
+				soh_tlv_len = vtlv_len;
+				break;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
+				   "Type %d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	/* Process supported TLVs */
+	if (soh_tlv) {
+		int failure = 0;
+		wpabuf_free(data->soh_response);
+		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
+						      &failure);
+		if (failure) {
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+auth_method:
+	eap_peap_state(data, PHASE2_METHOD);
+	next_type = sm->user->methods[0].method;
+	sm->user_eap_method_index = 1;
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+	eap_peap_phase2_init(sm, data, next_type);
+}
+#endif /* EAP_SERVER_TNC */
+
+
+static void eap_peap_process_phase2_response(struct eap_sm *sm,
+					     struct eap_peap_data *data,
+					     struct wpabuf *in_data)
+{
+	u8 next_type = EAP_TYPE_NONE;
+	const struct eap_hdr *hdr;
+	const u8 *pos;
+	size_t left;
+
+	if (data->state == PHASE2_TLV) {
+		eap_peap_process_phase2_tlv(sm, data, in_data);
+		return;
+	}
+
+#ifdef EAP_SERVER_TNC
+	if (data->state == PHASE2_SOH) {
+		eap_peap_process_phase2_soh(sm, data, in_data);
+		return;
+	}
+#endif /* EAP_SERVER_TNC */
+
+	if (data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
+			   "initialized?!", __func__);
+		return;
+	}
+
+	hdr = wpabuf_head(in_data);
+	pos = (const u8 *) (hdr + 1);
+
+	if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = wpabuf_len(in_data) - sizeof(*hdr);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
+			    "allowed types", pos + 1, left - 1);
+		eap_sm_process_nak(sm, pos + 1, left - 1);
+		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+		    sm->user->methods[sm->user_eap_method_index].method !=
+		    EAP_TYPE_NONE) {
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
+				   next_type);
+		} else {
+			eap_peap_req_failure(sm, data);
+			next_type = EAP_TYPE_NONE;
+		}
+		eap_peap_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
+			   "ignore the packet");
+		return;
+	}
+
+	data->phase2_method->process(sm, data->phase2_priv, in_data);
+
+	if (sm->method_pending == METHOD_PENDING_WAIT) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
+			   "pending wait state - save decrypted response");
+		wpabuf_free(data->pending_phase2_resp);
+		data->pending_phase2_resp = wpabuf_dup(in_data);
+	}
+
+	if (!data->phase2_method->isDone(sm, data->phase2_priv))
+		return;
+
+	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
+		eap_peap_req_failure(sm, data);
+		next_type = EAP_TYPE_NONE;
+		eap_peap_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	os_free(data->phase2_key);
+	if (data->phase2_method->getKey) {
+		data->phase2_key = data->phase2_method->getKey(
+			sm, data->phase2_priv, &data->phase2_key_len);
+		if (data->phase2_key == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
+				   "failed");
+			eap_peap_req_failure(sm, data);
+			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+			return;
+		}
+	}
+
+	switch (data->state) {
+	case PHASE1_ID2:
+	case PHASE2_ID:
+	case PHASE2_SOH:
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			eap_peap_req_failure(sm, data);
+			next_type = EAP_TYPE_NONE;
+			break;
+		}
+
+#ifdef EAP_SERVER_TNC
+		if (data->state != PHASE2_SOH && sm->tnc &&
+		    data->peap_version == 0) {
+			eap_peap_state(data, PHASE2_SOH);
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
+				   "TNC (NAP SOH)");
+			next_type = EAP_TYPE_NONE;
+			break;
+		}
+#endif /* EAP_SERVER_TNC */
+
+		eap_peap_state(data, PHASE2_METHOD);
+		next_type = sm->user->methods[0].method;
+		sm->user_eap_method_index = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+		break;
+	case PHASE2_METHOD:
+		eap_peap_req_success(sm, data);
+		next_type = EAP_TYPE_NONE;
+		break;
+	case FAILURE:
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
+			   __func__, data->state);
+		break;
+	}
+
+	eap_peap_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_peap_process_phase2(struct eap_sm *sm,
+				    struct eap_peap_data *data,
+				    const struct wpabuf *respData,
+				    struct wpabuf *in_buf)
+{
+	struct wpabuf *in_decrypted;
+	const struct eap_hdr *hdr;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
+
+	if (data->pending_phase2_resp) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
+			   "skip decryption and use old data");
+		eap_peap_process_phase2_response(sm, data,
+						 data->pending_phase2_resp);
+		wpabuf_free(data->pending_phase2_resp);
+		data->pending_phase2_resp = NULL;
+		return;
+	}
+
+	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+					      in_buf);
+	if (in_decrypted == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
+			   "data");
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
+			    in_decrypted);
+
+	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
+		const struct eap_hdr *resp;
+		struct eap_hdr *nhdr;
+		struct wpabuf *nbuf =
+			wpabuf_alloc(sizeof(struct eap_hdr) +
+				     wpabuf_len(in_decrypted));
+		if (nbuf == NULL) {
+			wpabuf_free(in_decrypted);
+			return;
+		}
+
+		resp = wpabuf_head(respData);
+		nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
+		nhdr->code = resp->code;
+		nhdr->identifier = resp->identifier;
+		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
+					    wpabuf_len(in_decrypted));
+		wpabuf_put_buf(nbuf, in_decrypted);
+		wpabuf_free(in_decrypted);
+
+		in_decrypted = nbuf;
+	} else if (data->peap_version >= 2) {
+		struct eap_tlv_hdr *tlv;
+		struct wpabuf *nmsg;
+
+		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
+				   "EAP TLV");
+			wpabuf_free(in_decrypted);
+			return;
+		}
+		tlv = wpabuf_mhead(in_decrypted);
+		if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
+		    EAP_TLV_EAP_PAYLOAD_TLV) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
+			wpabuf_free(in_decrypted);
+			return;
+		}
+		if (sizeof(*tlv) + be_to_host16(tlv->length) >
+		    wpabuf_len(in_decrypted)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
+				   "length");
+			wpabuf_free(in_decrypted);
+			return;
+		}
+		hdr = (struct eap_hdr *) (tlv + 1);
+		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
+				   "EAP packet in EAP TLV");
+			wpabuf_free(in_decrypted);
+			return;
+		}
+
+		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
+		if (nmsg == NULL) {
+			wpabuf_free(in_decrypted);
+			return;
+		}
+
+		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
+		wpabuf_free(in_decrypted);
+		in_decrypted = nmsg;
+	}
+
+	hdr = wpabuf_head(in_decrypted);
+	if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
+			   "EAP frame (len=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted));
+		wpabuf_free(in_decrypted);
+		eap_peap_req_failure(sm, data);
+		return;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > wpabuf_len(in_decrypted)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
+			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted),
+			   (unsigned long) len);
+		wpabuf_free(in_decrypted);
+		eap_peap_req_failure(sm, data);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
+		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
+		   (unsigned long) len);
+	switch (hdr->code) {
+	case EAP_CODE_RESPONSE:
+		eap_peap_process_phase2_response(sm, data, in_decrypted);
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
+		if (data->state == SUCCESS_REQ) {
+			eap_peap_state(data, SUCCESS);
+		}
+		break;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
+		eap_peap_state(data, FAILURE);
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+
+	wpabuf_free(in_decrypted);
+}
+
+
+static int eap_peapv2_start_phase2(struct eap_sm *sm,
+				   struct eap_peap_data *data)
+{
+	struct wpabuf *buf, *buf2;
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
+		   "payload in the same message");
+	eap_peap_state(data, PHASE1_ID2);
+	if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
+		return -1;
+
+	/* TODO: which Id to use here? */
+	buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
+	if (buf == NULL)
+		return -1;
+
+	buf2 = eap_peapv2_tlv_eap_payload(buf);
+	if (buf2 == NULL)
+		return -1;
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
+
+	buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+				     buf2);
+	wpabuf_free(buf2);
+
+	if (buf == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
+			   "data");
+		return -1;
+	}
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
+			buf);
+
+	/* Append TLS data into the pending buffer after the Server Finished */
+	if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+	wpabuf_put_buf(data->ssl.tls_out, buf);
+	wpabuf_free(buf);
+
+	return 0;
+}
+
+
+static int eap_peap_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
+{
+	struct eap_peap_data *data = priv;
+
+	data->recv_version = peer_version;
+	if (data->force_version >= 0 && peer_version != data->force_version) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
+			   " version (forced=%d peer=%d) - reject",
+			   data->force_version, peer_version);
+		return -1;
+	}
+	if (peer_version < data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
+			   "use version %d",
+			   peer_version, data->peap_version, peer_version);
+		data->peap_version = peer_version;
+	}
+
+	return 0;
+}
+
+
+static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_peap_data *data = priv;
+
+	switch (data->state) {
+	case PHASE1:
+		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
+			eap_peap_state(data, FAILURE);
+			break;
+		}
+
+		if (data->peap_version >= 2 &&
+		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			if (eap_peapv2_start_phase2(sm, data)) {
+				eap_peap_state(data, FAILURE);
+				break;
+			}
+		}
+		break;
+	case PHASE2_START:
+		eap_peap_state(data, PHASE2_ID);
+		eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+		break;
+	case PHASE1_ID2:
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+	case PHASE2_SOH:
+	case PHASE2_TLV:
+		eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
+		break;
+	case SUCCESS_REQ:
+		eap_peap_state(data, SUCCESS);
+		break;
+	case FAILURE_REQ:
+		eap_peap_state(data, FAILURE);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
+			   data->state, __func__);
+		break;
+	}
+}
+
+
+static void eap_peap_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_peap_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_PEAP, eap_peap_process_version,
+				   eap_peap_process_msg) < 0)
+		eap_peap_state(data, FAILURE);
+}
+
+
+static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_peap_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	if (data->crypto_binding_used) {
+		u8 csk[128];
+		/*
+		 * Note: It looks like Microsoft implementation requires null
+		 * termination for this label while the one used for deriving
+		 * IPMK|CMK did not use null termination.
+		 */
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+			return NULL;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
+		if (eapKeyData) {
+			os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
+			*len = EAP_TLS_KEY_LEN;
+			wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+				    eapKeyData, EAP_TLS_KEY_LEN);
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
+				   "key");
+		}
+
+		return eapKeyData;
+	}
+
+	/* TODO: PEAPv1 - different label in some cases */
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "client EAP encryption",
+					       EAP_TLS_KEY_LEN);
+	if (eapKeyData) {
+		*len = EAP_TLS_KEY_LEN;
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+			    eapKeyData, EAP_TLS_KEY_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
+	}
+
+	return eapKeyData;
+}
+
+
+static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_peap_init;
+	eap->reset = eap_peap_reset;
+	eap->buildReq = eap_peap_buildReq;
+	eap->check = eap_peap_check;
+	eap->process = eap_peap_process;
+	eap->isDone = eap_peap_isDone;
+	eap->getKey = eap_peap_getKey;
+	eap->isSuccess = eap_peap_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_psk.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_psk.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_psk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,517 +0,0 @@
-/*
- * hostapd / EAP-PSK (RFC 4764) server
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Note: EAP-PSK is an EAP authentication method and as such, completely
- * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "eap_common/eap_psk_common.h"
-#include "eap_server/eap_i.h"
-
-
-struct eap_psk_data {
-	enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
-	u8 rand_s[EAP_PSK_RAND_LEN];
-	u8 rand_p[EAP_PSK_RAND_LEN];
-	u8 *id_p, *id_s;
-	size_t id_p_len, id_s_len;
-	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-};
-
-
-static void * eap_psk_init(struct eap_sm *sm)
-{
-	struct eap_psk_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = PSK_1;
-	data->id_s = (u8 *) "hostapd";
-	data->id_s_len = 7;
-
-	return data;
-}
-
-
-static void eap_psk_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_psk_data *data = priv;
-	os_free(data->id_p);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
-				       struct eap_psk_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_psk_hdr_1 *psk;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
-
-	if (os_get_random(data->rand_s, EAP_PSK_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
-		data->state = FAILURE;
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)",
-		    data->rand_s, EAP_PSK_RAND_LEN);
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			    sizeof(*psk) + data->id_s_len,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	psk = wpabuf_put(req, sizeof(*psk));
-	psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
-	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
-	wpabuf_put_data(req, data->id_s, data->id_s_len);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
-				       struct eap_psk_data *data, u8 id)
-{
-	struct wpabuf *req;
-	struct eap_psk_hdr_3 *psk;
-	u8 *buf, *pchannel, nonce[16];
-	size_t buflen;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)");
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
-			    sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
-			   "request");
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	psk = wpabuf_put(req, sizeof(*psk));
-	psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
-	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
-
-	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
-	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		goto fail;
-
-	os_memcpy(buf, data->id_s, data->id_s_len);
-	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s))
-		goto fail;
-	os_free(buf);
-
-	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
-				data->emsk))
-		goto fail;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
-
-	os_memset(nonce, 0, sizeof(nonce));
-	pchannel = wpabuf_put(req, 4 + 16 + 1);
-	os_memcpy(pchannel, nonce + 12, 4);
-	os_memset(pchannel + 4, 0, 16); /* Tag */
-	pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)",
-		    pchannel, 4 + 16 + 1);
-	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
-				wpabuf_head(req), 22,
-				pchannel + 4 + 16, 1, pchannel + 4))
-		goto fail;
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)",
-		    pchannel, 4 + 16 + 1);
-
-	return req;
-
-fail:
-	wpabuf_free(req);
-	data->state = FAILURE;
-	return NULL;
-}
-
-
-static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_psk_data *data = priv;
-
-	switch (data->state) {
-	case PSK_1:
-		return eap_psk_build_1(sm, data, id);
-	case PSK_3:
-		return eap_psk_build_3(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq",
-			   data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_psk_data *data = priv;
-	size_t len;
-	u8 t;
-	const u8 *pos;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
-		return TRUE;
-	}
-	t = EAP_PSK_FLAGS_GET_T(*pos);
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
-
-	if (data->state == PSK_1 && t != 1) {
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
-			   "ignore T=%d", t);
-		return TRUE;
-	}
-
-	if (data->state == PSK_3 && t != 3) {
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
-			   "ignore T=%d", t);
-		return TRUE;
-	}
-
-	if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
-	    (t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_psk_process_2(struct eap_sm *sm,
-			      struct eap_psk_data *data,
-			      struct wpabuf *respData)
-{
-	const struct eap_psk_hdr_2 *resp;
-	u8 *pos, mac[EAP_PSK_MAC_LEN], *buf;
-	size_t left, buflen;
-	int i;
-	const u8 *cpos;
-
-	if (data->state != PSK_1)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2");
-
-	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData,
-				&left);
-	if (cpos == NULL || left < sizeof(*resp)) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
-		return;
-	}
-	resp = (const struct eap_psk_hdr_2 *) cpos;
-	cpos = (const u8 *) (resp + 1);
-	left -= sizeof(*resp);
-
-	os_free(data->id_p);
-	data->id_p = os_malloc(left);
-	if (data->id_p == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
-			   "ID_P");
-		return;
-	}
-	os_memcpy(data->id_p, cpos, left);
-	data->id_p_len = left;
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
-			  data->id_p, data->id_p_len);
-
-	if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P",
-				  data->id_p, data->id_p_len);
-		data->state = FAILURE;
-		return;
-	}
-
-	for (i = 0;
-	     i < EAP_MAX_METHODS &&
-		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-		      sm->user->methods[i].method != EAP_TYPE_NONE);
-	     i++) {
-		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
-		    sm->user->methods[i].method == EAP_TYPE_PSK)
-			break;
-	}
-
-	if (i >= EAP_MAX_METHODS ||
-	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
-	    sm->user->methods[i].method != EAP_TYPE_PSK) {
-		wpa_hexdump_ascii(MSG_DEBUG,
-				  "EAP-PSK: EAP-PSK not enabled for ID_P",
-				  data->id_p, data->id_p_len);
-		data->state = FAILURE;
-		return;
-	}
-
-	if (sm->user->password == NULL ||
-	    sm->user->password_len != EAP_PSK_PSK_LEN) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in "
-				  "user database for ID_P",
-				  data->id_p, data->id_p_len);
-		data->state = FAILURE;
-		return;
-	}
-	if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) {
-		data->state = FAILURE;
-		return;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)",
-		    resp->rand_p, EAP_PSK_RAND_LEN);
-	os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
-
-	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
-	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
-	buf = os_malloc(buflen);
-	if (buf == NULL) {
-		data->state = FAILURE;
-		return;
-	}
-	os_memcpy(buf, data->id_p, data->id_p_len);
-	pos = buf + data->id_p_len;
-	os_memcpy(pos, data->id_s, data->id_s_len);
-	pos += data->id_s_len;
-	os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
-	pos += EAP_PSK_RAND_LEN;
-	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
-		os_free(buf);
-		data->state = FAILURE;
-		return;
-	}
-	os_free(buf);
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
-	if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
-			    mac, EAP_PSK_MAC_LEN);
-		data->state = FAILURE;
-		return;
-	}
-
-	data->state = PSK_3;
-}
-
-
-static void eap_psk_process_4(struct eap_sm *sm,
-			      struct eap_psk_data *data,
-			      struct wpabuf *respData)
-{
-	const struct eap_psk_hdr_4 *resp;
-	u8 *decrypted, nonce[16];
-	size_t left;
-	const u8 *pos, *tag;
-
-	if (data->state != PSK_3)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4");
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left);
-	if (pos == NULL || left < sizeof(*resp)) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
-		return;
-	}
-	resp = (const struct eap_psk_hdr_4 *) pos;
-	pos = (const u8 *) (resp + 1);
-	left -= sizeof(*resp);
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left);
-
-	if (left < 4 + 16 + 1) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
-			   "PSK-4 (len=%lu, expected 21)",
-			   (unsigned long) left);
-		return;
-	}
-
-	if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase");
-		return;
-	}
-
-	os_memset(nonce, 0, 12);
-	os_memcpy(nonce + 12, pos, 4);
-	pos += 4;
-	left -= 4;
-	tag = pos;
-	pos += 16;
-	left -= 16;
-
-	decrypted = os_malloc(left);
-	if (decrypted == NULL)
-		return;
-	os_memcpy(decrypted, pos, left);
-
-	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
-				wpabuf_head(respData), 22, decrypted, left,
-				tag)) {
-		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
-		os_free(decrypted);
-		data->state = FAILURE;
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
-		    decrypted, left);
-
-	/* Verify R flag */
-	switch (decrypted[0] >> 6) {
-	case EAP_PSK_R_FLAG_CONT:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
-		data->state = FAILURE;
-		break;
-	case EAP_PSK_R_FLAG_DONE_SUCCESS:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
-		data->state = SUCCESS;
-		break;
-	case EAP_PSK_R_FLAG_DONE_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
-		data->state = FAILURE;
-		break;
-	}
-	os_free(decrypted);
-}
-
-
-static void eap_psk_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_psk_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
-			   "configured");
-		data->state = FAILURE;
-		return;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
-	if (pos == NULL || len < 1)
-		return;
-
-	switch (EAP_PSK_FLAGS_GET_T(*pos)) {
-	case 1:
-		eap_psk_process_2(sm, data, respData);
-		break;
-	case 3:
-		eap_psk_process_4(sm, data, respData);
-		break;
-	}
-}
-
-
-static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_psk_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_psk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-	*len = EAP_MSK_LEN;
-
-	return key;
-}
-
-
-static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_psk_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-
-	return key;
-}
-
-
-static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_psk_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_psk_init;
-	eap->reset = eap_psk_reset;
-	eap->buildReq = eap_psk_buildReq;
-	eap->check = eap_psk_check;
-	eap->process = eap_psk_process;
-	eap->isDone = eap_psk_isDone;
-	eap->getKey = eap_psk_getKey;
-	eap->isSuccess = eap_psk_isSuccess;
-	eap->get_emsk = eap_psk_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_psk.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_psk.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_psk.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_psk.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,514 @@
+/*
+ * hostapd / EAP-PSK (RFC 4764) server
+ * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Note: EAP-PSK is an EAP authentication method and as such, completely
+ * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/random.h"
+#include "eap_common/eap_psk_common.h"
+#include "eap_server/eap_i.h"
+
+
+struct eap_psk_data {
+	enum { PSK_1, PSK_3, SUCCESS, FAILURE } state;
+	u8 rand_s[EAP_PSK_RAND_LEN];
+	u8 rand_p[EAP_PSK_RAND_LEN];
+	u8 *id_p, *id_s;
+	size_t id_p_len, id_s_len;
+	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+};
+
+
+static void * eap_psk_init(struct eap_sm *sm)
+{
+	struct eap_psk_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = PSK_1;
+	data->id_s = (u8 *) "hostapd";
+	data->id_s_len = 7;
+
+	return data;
+}
+
+
+static void eap_psk_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_psk_data *data = priv;
+	os_free(data->id_p);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_psk_build_1(struct eap_sm *sm,
+				       struct eap_psk_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_psk_hdr_1 *psk;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)");
+
+	if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
+		data->state = FAILURE;
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)",
+		    data->rand_s, EAP_PSK_RAND_LEN);
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
+			    sizeof(*psk) + data->id_s_len,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	psk = wpabuf_put(req, sizeof(*psk));
+	psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
+	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
+	wpabuf_put_data(req, data->id_s, data->id_s_len);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_psk_build_3(struct eap_sm *sm,
+				       struct eap_psk_data *data, u8 id)
+{
+	struct wpabuf *req;
+	struct eap_psk_hdr_3 *psk;
+	u8 *buf, *pchannel, nonce[16];
+	size_t buflen;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)");
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK,
+			    sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory "
+			   "request");
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	psk = wpabuf_put(req, sizeof(*psk));
+	psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
+	os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
+
+	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
+	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		goto fail;
+
+	os_memcpy(buf, data->id_s, data->id_s_len);
+	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
+		os_free(buf);
+		goto fail;
+	}
+	os_free(buf);
+
+	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
+				data->emsk))
+		goto fail;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
+
+	os_memset(nonce, 0, sizeof(nonce));
+	pchannel = wpabuf_put(req, 4 + 16 + 1);
+	os_memcpy(pchannel, nonce + 12, 4);
+	os_memset(pchannel + 4, 0, 16); /* Tag */
+	pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)",
+		    pchannel, 4 + 16 + 1);
+	if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce),
+				wpabuf_head(req), 22,
+				pchannel + 4 + 16, 1, pchannel + 4))
+		goto fail;
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)",
+		    pchannel, 4 + 16 + 1);
+
+	return req;
+
+fail:
+	wpabuf_free(req);
+	data->state = FAILURE;
+	return NULL;
+}
+
+
+static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_psk_data *data = priv;
+
+	switch (data->state) {
+	case PSK_1:
+		return eap_psk_build_1(sm, data, id);
+	case PSK_3:
+		return eap_psk_build_3(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_psk_data *data = priv;
+	size_t len;
+	u8 t;
+	const u8 *pos;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
+		return TRUE;
+	}
+	t = EAP_PSK_FLAGS_GET_T(*pos);
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
+
+	if (data->state == PSK_1 && t != 1) {
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - "
+			   "ignore T=%d", t);
+		return TRUE;
+	}
+
+	if (data->state == PSK_3 && t != 3) {
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - "
+			   "ignore T=%d", t);
+		return TRUE;
+	}
+
+	if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) ||
+	    (t == 3 && len < sizeof(struct eap_psk_hdr_4))) {
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_psk_process_2(struct eap_sm *sm,
+			      struct eap_psk_data *data,
+			      struct wpabuf *respData)
+{
+	const struct eap_psk_hdr_2 *resp;
+	u8 *pos, mac[EAP_PSK_MAC_LEN], *buf;
+	size_t left, buflen;
+	int i;
+	const u8 *cpos;
+
+	if (data->state != PSK_1)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2");
+
+	cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData,
+				&left);
+	if (cpos == NULL || left < sizeof(*resp)) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
+		return;
+	}
+	resp = (const struct eap_psk_hdr_2 *) cpos;
+	cpos = (const u8 *) (resp + 1);
+	left -= sizeof(*resp);
+
+	os_free(data->id_p);
+	data->id_p = os_malloc(left);
+	if (data->id_p == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for "
+			   "ID_P");
+		return;
+	}
+	os_memcpy(data->id_p, cpos, left);
+	data->id_p_len = left;
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P",
+			  data->id_p, data->id_p_len);
+
+	if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P",
+				  data->id_p, data->id_p_len);
+		data->state = FAILURE;
+		return;
+	}
+
+	for (i = 0;
+	     i < EAP_MAX_METHODS &&
+		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+		      sm->user->methods[i].method != EAP_TYPE_NONE);
+	     i++) {
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_PSK)
+			break;
+	}
+
+	if (i >= EAP_MAX_METHODS ||
+	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+	    sm->user->methods[i].method != EAP_TYPE_PSK) {
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP-PSK: EAP-PSK not enabled for ID_P",
+				  data->id_p, data->id_p_len);
+		data->state = FAILURE;
+		return;
+	}
+
+	if (sm->user->password == NULL ||
+	    sm->user->password_len != EAP_PSK_PSK_LEN) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in "
+				  "user database for ID_P",
+				  data->id_p, data->id_p_len);
+		data->state = FAILURE;
+		return;
+	}
+	if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) {
+		data->state = FAILURE;
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
+
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)",
+		    resp->rand_p, EAP_PSK_RAND_LEN);
+	os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN);
+
+	/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
+	buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		data->state = FAILURE;
+		return;
+	}
+	os_memcpy(buf, data->id_p, data->id_p_len);
+	pos = buf + data->id_p_len;
+	os_memcpy(pos, data->id_s, data->id_s_len);
+	pos += data->id_s_len;
+	os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
+	pos += EAP_PSK_RAND_LEN;
+	os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
+	if (omac1_aes_128(data->ak, buf, buflen, mac)) {
+		os_free(buf);
+		data->state = FAILURE;
+		return;
+	}
+	os_free(buf);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
+	if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
+			    mac, EAP_PSK_MAC_LEN);
+		data->state = FAILURE;
+		return;
+	}
+
+	data->state = PSK_3;
+}
+
+
+static void eap_psk_process_4(struct eap_sm *sm,
+			      struct eap_psk_data *data,
+			      struct wpabuf *respData)
+{
+	const struct eap_psk_hdr_4 *resp;
+	u8 *decrypted, nonce[16];
+	size_t left;
+	const u8 *pos, *tag;
+
+	if (data->state != PSK_3)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4");
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left);
+	if (pos == NULL || left < sizeof(*resp)) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
+		return;
+	}
+	resp = (const struct eap_psk_hdr_4 *) pos;
+	pos = (const u8 *) (resp + 1);
+	left -= sizeof(*resp);
+
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left);
+
+	if (left < 4 + 16 + 1) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in "
+			   "PSK-4 (len=%lu, expected 21)",
+			   (unsigned long) left);
+		return;
+	}
+
+	if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase");
+		return;
+	}
+
+	os_memset(nonce, 0, 12);
+	os_memcpy(nonce + 12, pos, 4);
+	pos += 4;
+	left -= 4;
+	tag = pos;
+	pos += 16;
+	left -= 16;
+
+	decrypted = os_malloc(left);
+	if (decrypted == NULL)
+		return;
+	os_memcpy(decrypted, pos, left);
+
+	if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
+				wpabuf_head(respData), 22, decrypted, left,
+				tag)) {
+		wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
+		os_free(decrypted);
+		data->state = FAILURE;
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
+		    decrypted, left);
+
+	/* Verify R flag */
+	switch (decrypted[0] >> 6) {
+	case EAP_PSK_R_FLAG_CONT:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
+		data->state = FAILURE;
+		break;
+	case EAP_PSK_R_FLAG_DONE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
+		data->state = SUCCESS;
+		break;
+	case EAP_PSK_R_FLAG_DONE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE");
+		data->state = FAILURE;
+		break;
+	}
+	os_free(decrypted);
+}
+
+
+static void eap_psk_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_psk_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
+			   "configured");
+		data->state = FAILURE;
+		return;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	switch (EAP_PSK_FLAGS_GET_T(*pos)) {
+	case 1:
+		eap_psk_process_2(sm, data, respData);
+		break;
+	case 3:
+		eap_psk_process_4(sm, data, respData);
+		break;
+	}
+}
+
+
+static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_psk_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_psk_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_psk_init;
+	eap->reset = eap_psk_reset;
+	eap->buildReq = eap_psk_buildReq;
+	eap->check = eap_psk_check;
+	eap->process = eap_psk_process;
+	eap->isDone = eap_psk_isDone;
+	eap->getKey = eap_psk_getKey;
+	eap->isSuccess = eap_psk_isSuccess;
+	eap->get_emsk = eap_psk_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_pwd.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_pwd.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_pwd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_pwd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1045 @@
+/*
+ * hostapd / EAP-pwd (RFC 5931) server
+ * Copyright (c) 2010, Dan Harkins <dharkins at lounge.org>
+ *
+ * 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/sha256.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_pwd_common.h"
+
+
+struct eap_pwd_data {
+	enum {
+		PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
+	} state;
+	u8 *id_peer;
+	size_t id_peer_len;
+	u8 *id_server;
+	size_t id_server_len;
+	u8 *password;
+	size_t password_len;
+	u32 token;
+	u16 group_num;
+	EAP_PWD_group *grp;
+
+	struct wpabuf *inbuf;
+	size_t in_frag_pos;
+	struct wpabuf *outbuf;
+	size_t out_frag_pos;
+	size_t mtu;
+
+	BIGNUM *k;
+	BIGNUM *private_value;
+	BIGNUM *peer_scalar;
+	BIGNUM *my_scalar;
+	EC_POINT *my_element;
+	EC_POINT *peer_element;
+
+	u8 my_confirm[SHA256_MAC_LEN];
+
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+
+	BN_CTX *bnctx;
+};
+
+
+static const char * eap_pwd_state_txt(int state)
+{
+	switch (state) {
+        case PWD_ID_Req:
+		return "PWD-ID-Req";
+        case PWD_Commit_Req:
+		return "PWD-Commit-Req";
+        case PWD_Confirm_Req:
+		return "PWD-Confirm-Req";
+        case SUCCESS:
+		return "SUCCESS";
+        case FAILURE:
+		return "FAILURE";
+        default:
+		return "PWD-Unk";
+	}
+}
+
+
+static void eap_pwd_state(struct eap_pwd_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
+		   eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_pwd_init(struct eap_sm *sm)
+{
+	struct eap_pwd_data *data;
+
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_len == 0) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
+			   "configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->group_num = sm->pwd_group;
+	wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
+		   data->group_num);
+	data->state = PWD_ID_Req;
+
+	data->id_server = (u8 *) os_strdup("server");
+	if (data->id_server)
+		data->id_server_len = os_strlen((char *) data->id_server);
+
+	data->password = os_malloc(sm->user->password_len);
+	if (data->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
+			   "fail");
+		os_free(data->id_server);
+		os_free(data);
+		return NULL;
+	}
+	data->password_len = sm->user->password_len;
+	os_memcpy(data->password, sm->user->password, data->password_len);
+
+	data->bnctx = BN_CTX_new();
+	if (data->bnctx == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
+		os_free(data->password);
+		os_free(data->id_server);
+		os_free(data);
+		return NULL;
+	}
+
+	data->in_frag_pos = data->out_frag_pos = 0;
+	data->inbuf = data->outbuf = NULL;
+	data->mtu = 1020; /* default from RFC 5931, make it configurable! */
+
+	return data;
+}
+
+
+static void eap_pwd_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_pwd_data *data = priv;
+
+	BN_free(data->private_value);
+	BN_free(data->peer_scalar);
+	BN_free(data->my_scalar);
+	BN_free(data->k);
+	BN_CTX_free(data->bnctx);
+	EC_POINT_free(data->my_element);
+	EC_POINT_free(data->peer_element);
+	os_free(data->id_peer);
+	os_free(data->id_server);
+	os_free(data->password);
+	if (data->grp) {
+		EC_GROUP_free(data->grp->group);
+		EC_POINT_free(data->grp->pwe);
+		BN_free(data->grp->order);
+		BN_free(data->grp->prime);
+		os_free(data->grp);
+	}
+	os_free(data);
+}
+
+
+static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data,
+				 u8 id)
+{
+	wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
+	/*
+	 * if we're fragmenting then we already have an id request, just return
+	 */
+	if (data->out_frag_pos)
+		return;
+
+	data->outbuf = wpabuf_alloc(sizeof(struct eap_pwd_id) +
+				    data->id_server_len);
+	if (data->outbuf == NULL) {
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+
+	/* an lfsr is good enough to generate unpredictable tokens */
+	data->token = os_random();
+	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);
+	wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token));
+	wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
+	wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len);
+}
+
+
+static void eap_pwd_build_commit_req(struct eap_sm *sm,
+				     struct eap_pwd_data *data, u8 id)
+{
+	BIGNUM *mask = NULL, *x = NULL, *y = NULL;
+	u8 *scalar = NULL, *element = NULL;
+	u16 offset;
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
+	/*
+	 * if we're fragmenting then we already have an commit request, just
+	 * return
+	 */
+	if (data->out_frag_pos)
+		return;
+
+	if (((data->private_value = BN_new()) == NULL) ||
+	    ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((data->my_scalar = BN_new()) == NULL) ||
+	    ((mask = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
+			   "fail");
+		goto fin;
+	}
+
+	BN_rand_range(data->private_value, data->grp->order);
+	BN_rand_range(mask, data->grp->order);
+	BN_add(data->my_scalar, data->private_value, mask);
+	BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+	       data->bnctx);
+
+	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
+			  data->grp->pwe, mask, data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
+			   "fail");
+		eap_pwd_state(data, FAILURE);
+		goto fin;
+	}
+
+	if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
+	{
+		wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
+			   "fail");
+		goto fin;
+	}
+	BN_free(mask);
+
+	if (((x = BN_new()) == NULL) ||
+	    ((y = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
+			   "fail");
+		goto fin;
+	}
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
+			   "fail");
+		goto fin;
+	}
+
+	if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
+	    ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
+	     NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
+		goto fin;
+	}
+
+	/*
+	 * bignums occupy as little memory as possible so one that is
+	 * sufficiently smaller than the prime or order might need pre-pending
+	 * with zeros.
+	 */
+	os_memset(scalar, 0, BN_num_bytes(data->grp->order));
+	os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, scalar + offset);
+
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, element + offset);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
+
+	data->outbuf = wpabuf_alloc(2 * BN_num_bytes(data->grp->prime) +
+				    BN_num_bytes(data->grp->order));
+	if (data->outbuf == NULL)
+		goto fin;
+
+	/* We send the element as (x,y) followed by the scalar */
+	wpabuf_put_data(data->outbuf, element,
+			2 * BN_num_bytes(data->grp->prime));
+	wpabuf_put_data(data->outbuf, scalar, BN_num_bytes(data->grp->order));
+
+fin:
+	os_free(scalar);
+	os_free(element);
+	BN_free(x);
+	BN_free(y);
+	if (data->outbuf == NULL)
+		eap_pwd_state(data, FAILURE);
+}
+
+
+static void eap_pwd_build_confirm_req(struct eap_sm *sm,
+				      struct eap_pwd_data *data, u8 id)
+{
+	BIGNUM *x = NULL, *y = NULL;
+	struct crypto_hash *hash;
+	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+	u16 grp;
+	int offset;
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
+	/*
+	 * if we're fragmenting then we already have an confirm request, just
+	 * return
+	 */
+	if (data->out_frag_pos)
+		return;
+
+	/* Each component of the cruft will be at most as big as the prime */
+	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
+			   "fail");
+		goto fin;
+	}
+
+	/*
+	 * commit is H(k | server_element | server_scalar | peer_element |
+	 *	       peer_scalar | ciphersuite)
+	 */
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
+
+	/*
+	 * Zero the memory each time because this is mod prime math and some
+	 * value may start with a few zeros and the previous one did not.
+	 *
+	 * First is k
+	 */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* peer element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->peer_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* peer scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* ciphersuite */
+	grp = htons(data->group_num);
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	ptr = cruft;
+	os_memcpy(ptr, &grp, sizeof(u16));
+	ptr += sizeof(u16);
+	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+	ptr += sizeof(u8);
+	*ptr = EAP_PWD_DEFAULT_PRF;
+	ptr += sizeof(u8);
+	eap_pwd_h_update(hash, cruft, ptr - cruft);
+
+	/* all done with the random function */
+	eap_pwd_h_final(hash, conf);
+	os_memcpy(data->my_confirm, conf, SHA256_MAC_LEN);
+
+	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
+	if (data->outbuf == NULL)
+		goto fin;
+
+	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
+
+fin:
+	os_free(cruft);
+	BN_free(x);
+	BN_free(y);
+	if (data->outbuf == NULL)
+		eap_pwd_state(data, FAILURE);
+}
+
+
+static struct wpabuf *
+eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_pwd_data *data = priv;
+	struct wpabuf *req;
+	u8 lm_exch;
+	const u8 *buf;
+	u16 totlen = 0;
+	size_t len;
+
+	/*
+	 * if we're buffering response fragments then just ACK
+	 */
+	if (data->in_frag_pos) {
+		wpa_printf(MSG_DEBUG, "EAP-pwd: ACKing a fragment!!");
+		req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+				    EAP_PWD_HDR_SIZE, EAP_CODE_REQUEST, id);
+		if (req == NULL) {
+			eap_pwd_state(data, FAILURE);
+			return NULL;
+		}
+		switch (data->state) {
+		case PWD_ID_Req:
+			wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
+			break;
+		case PWD_Commit_Req:
+			wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
+			break;
+		case PWD_Confirm_Req:
+			wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
+			break;
+		default:
+			eap_pwd_state(data, FAILURE);   /* just to be sure */
+			wpabuf_free(req);
+			return NULL;
+		}
+		return req;
+	}
+
+	/*
+	 * build the data portion of a request
+	 */
+	switch (data->state) {
+	case PWD_ID_Req:
+		eap_pwd_build_id_req(sm, data, id);
+		lm_exch = EAP_PWD_OPCODE_ID_EXCH;
+		break;
+	case PWD_Commit_Req:
+		eap_pwd_build_commit_req(sm, data, id);
+		lm_exch = EAP_PWD_OPCODE_COMMIT_EXCH;
+		break;
+	case PWD_Confirm_Req:
+		eap_pwd_build_confirm_req(sm, data, id);
+		lm_exch = EAP_PWD_OPCODE_CONFIRM_EXCH;
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
+			   data->state);
+		eap_pwd_state(data, FAILURE);
+		lm_exch = 0;    /* hush now, sweet compiler */
+		break;
+	}
+
+	if (data->state == FAILURE)
+		return NULL;
+
+	/*
+	 * determine whether that data needs to be fragmented
+	 */
+	len = wpabuf_len(data->outbuf) - data->out_frag_pos;
+	if ((len + EAP_PWD_HDR_SIZE) > data->mtu) {
+		len = data->mtu - EAP_PWD_HDR_SIZE;
+		EAP_PWD_SET_MORE_BIT(lm_exch);
+		/*
+		 * if this is the first fragment, need to set the M bit
+		 * and add the total length to the eap_pwd_hdr
+		 */
+		if (data->out_frag_pos == 0) {
+			EAP_PWD_SET_LENGTH_BIT(lm_exch);
+			totlen = wpabuf_len(data->outbuf) +
+				EAP_PWD_HDR_SIZE + sizeof(u16);
+			len -= sizeof(u16);
+			wpa_printf(MSG_DEBUG, "EAP-pwd: Fragmenting output, "
+				   "total length = %d", totlen);
+		}
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Send a %d byte fragment",
+			   (int) len);
+	}
+
+	/*
+	 * alloc an eap request and populate it with the data
+	 */
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
+			    EAP_PWD_HDR_SIZE + len +
+			    (totlen ? sizeof(u16) : 0),
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		eap_pwd_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, lm_exch);
+	if (EAP_PWD_GET_LENGTH_BIT(lm_exch))
+		wpabuf_put_be16(req, totlen);
+
+	buf = wpabuf_head_u8(data->outbuf);
+	wpabuf_put_data(req, buf + data->out_frag_pos, len);
+	data->out_frag_pos += len;
+	/*
+	 * either not fragged or last fragment, either way free up the data
+	 */
+	if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
+		wpabuf_free(data->outbuf);
+		data->out_frag_pos = 0;
+	}
+
+	return req;
+}
+
+
+static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_pwd_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
+		return TRUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: exch = %d, len = %d",
+		   EAP_PWD_GET_EXCHANGE(*pos), (int) len);
+
+	if (data->state == PWD_ID_Req &&
+	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_ID_EXCH))
+		return FALSE;
+
+	if (data->state == PWD_Commit_Req &&
+	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_COMMIT_EXCH))
+		return FALSE;
+
+	if (data->state == PWD_Confirm_Req &&
+	    ((EAP_PWD_GET_EXCHANGE(*pos)) == EAP_PWD_OPCODE_CONFIRM_EXCH))
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
+		   *pos, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_pwd_process_id_resp(struct eap_sm *sm,
+				    struct eap_pwd_data *data,
+				    const u8 *payload, size_t payload_len)
+{
+	struct eap_pwd_id *id;
+
+	if (payload_len < sizeof(struct eap_pwd_id)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
+		return;
+	}
+
+	id = (struct eap_pwd_id *) payload;
+	if ((data->group_num != be_to_host16(id->group_num)) ||
+	    (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
+	    (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
+	    (id->prf != EAP_PWD_DEFAULT_PRF)) {
+		wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
+		eap_pwd_state(data, FAILURE);
+		return;
+	}
+	data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
+	if (data->id_peer == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
+		return;
+	}
+	data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
+	os_memcpy(data->id_peer, id->identity, data->id_peer_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
+			  data->id_peer, data->id_peer_len);
+
+	if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
+			   "group");
+		return;
+	}
+	if (compute_password_element(data->grp, data->group_num,
+				     data->password, data->password_len,
+				     data->id_server, data->id_server_len,
+				     data->id_peer, data->id_peer_len,
+				     (u8 *) &data->token)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
+			   "PWE");
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
+		   BN_num_bits(data->grp->prime));
+
+	eap_pwd_state(data, PWD_Commit_Req);
+}
+
+
+static void
+eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+			    const u8 *payload, size_t payload_len)
+{
+	u8 *ptr;
+	BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
+	EC_POINT *K = NULL, *point = NULL;
+	int res = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
+
+	if (((data->peer_scalar = BN_new()) == NULL) ||
+	    ((data->k = BN_new()) == NULL) ||
+	    ((cofactor = BN_new()) == NULL) ||
+	    ((x = BN_new()) == NULL) ||
+	    ((y = BN_new()) == NULL) ||
+	    ((point = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((K = EC_POINT_new(data->grp->group)) == NULL) ||
+	    ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
+			   "fail");
+		goto fin;
+	}
+
+	if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
+			   "cofactor for curve");
+		goto fin;
+	}
+
+	/* element, x then y, followed by scalar */
+	ptr = (u8 *) payload;
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
+	ptr += BN_num_bytes(data->grp->prime);
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
+	ptr += BN_num_bytes(data->grp->prime);
+	BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
+	if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
+						 data->peer_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
+			   "fail");
+		goto fin;
+	}
+
+	/* check to ensure peer's element is not in a small sub-group */
+	if (BN_cmp(cofactor, BN_value_one())) {
+		if (!EC_POINT_mul(data->grp->group, point, NULL,
+				  data->peer_element, cofactor, NULL)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+				   "multiply peer element by order");
+			goto fin;
+		}
+		if (EC_POINT_is_at_infinity(data->grp->group, point)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
+				   "is at infinity!\n");
+			goto fin;
+		}
+	}
+
+	/* compute the shared key, k */
+	if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
+			   data->peer_scalar, data->bnctx)) ||
+	    (!EC_POINT_add(data->grp->group, K, K, data->peer_element,
+			   data->bnctx)) ||
+	    (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
+			   data->bnctx))) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
+			   "fail");
+		goto fin;
+	}
+
+	/* ensure that the shared key isn't in a small sub-group */
+	if (BN_cmp(cofactor, BN_value_one())) {
+		if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
+				  NULL)) {
+			wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
+				   "multiply shared key point by order!\n");
+			goto fin;
+		}
+	}
+
+	/*
+	 * This check is strictly speaking just for the case above where
+	 * co-factor > 1 but it was suggested that even though this is probably
+	 * never going to happen it is a simple and safe check "just to be
+	 * sure" so let's be safe.
+	 */
+	if (EC_POINT_is_at_infinity(data->grp->group, K)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
+			   "at infinity");
+		goto fin;
+	}
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
+						 NULL, data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
+			   "shared secret from secret point");
+		goto fin;
+	}
+	res = 1;
+
+fin:
+	EC_POINT_free(K);
+	EC_POINT_free(point);
+	BN_free(cofactor);
+	BN_free(x);
+	BN_free(y);
+
+	if (res)
+		eap_pwd_state(data, PWD_Confirm_Req);
+	else
+		eap_pwd_state(data, FAILURE);
+}
+
+
+static void
+eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
+			     const u8 *payload, size_t payload_len)
+{
+	BIGNUM *x = NULL, *y = NULL;
+	struct crypto_hash *hash;
+	u32 cs;
+	u16 grp;
+	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
+	int offset;
+
+	/* build up the ciphersuite: group | random_function | prf */
+	grp = htons(data->group_num);
+	ptr = (u8 *) &cs;
+	os_memcpy(ptr, &grp, sizeof(u16));
+	ptr += sizeof(u16);
+	*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
+	ptr += sizeof(u8);
+	*ptr = EAP_PWD_DEFAULT_PRF;
+
+	/* each component of the cruft will be at most as big as the prime */
+	if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
+	    ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
+		goto fin;
+	}
+
+	/*
+	 * commit is H(k | peer_element | peer_scalar | server_element |
+	 *	       server_scalar | ciphersuite)
+	 */
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
+
+	/* k */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* peer element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->peer_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* peer scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* server element: x, y */
+	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
+						 data->my_element, x, y,
+						 data->bnctx)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
+			   "assignment fail");
+		goto fin;
+	}
+
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
+
+	/* server scalar */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
+
+	/* ciphersuite */
+	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
+
+	/* all done */
+	eap_pwd_h_final(hash, conf);
+
+	ptr = (u8 *) payload;
+	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
+			   "verify");
+		goto fin;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
+	if (compute_keys(data->grp, data->bnctx, data->k,
+			 data->peer_scalar, data->my_scalar, conf,
+			 data->my_confirm, &cs, data->msk, data->emsk) < 0)
+		eap_pwd_state(data, FAILURE);
+	else
+		eap_pwd_state(data, SUCCESS);
+
+fin:
+	os_free(cruft);
+	BN_free(x);
+	BN_free(y);
+}
+
+
+static void eap_pwd_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_pwd_data *data = priv;
+	const u8 *pos;
+	size_t len;
+	u8 lm_exch;
+	u16 tot_len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
+	if ((pos == NULL) || (len < 1)) {
+		wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
+			   (pos == NULL) ? "is NULL" : "is not NULL",
+			   (int) len);
+		return;
+	}
+
+	lm_exch = *pos;
+	pos++;            /* skip over the bits and the exch */
+	len--;
+
+	/*
+	 * if we're fragmenting then this should be an ACK with no data,
+	 * just return and continue fragmenting in the "build" section above
+	 */
+	if (data->out_frag_pos) {
+		if (len > 1)
+			wpa_printf(MSG_INFO, "EAP-pwd: Bad response! "
+				   "Fragmenting but not an ACK");
+		else
+			wpa_printf(MSG_DEBUG, "EAP-pwd: received ACK from "
+				   "peer");
+		return;
+	}
+	/*
+	 * if we're receiving fragmented packets then we need to buffer...
+	 *
+	 * the first fragment has a total length
+	 */
+	if (EAP_PWD_GET_LENGTH_BIT(lm_exch)) {
+		tot_len = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
+			   "length = %d", tot_len);
+		data->inbuf = wpabuf_alloc(tot_len);
+		if (data->inbuf == NULL) {
+			wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
+				   "buffer fragments!");
+			return;
+		}
+		pos += sizeof(u16);
+		len -= sizeof(u16);
+	}
+	/*
+	 * the first and all intermediate fragments have the M bit set
+	 */
+	if (EAP_PWD_GET_MORE_BIT(lm_exch)) {
+		if ((data->in_frag_pos + len) > wpabuf_size(data->inbuf)) {
+			wpa_printf(MSG_DEBUG, "EAP-pwd: Buffer overflow "
+				   "attack detected! (%d+%d > %d)",
+				   (int) data->in_frag_pos, (int) len,
+				   (int) wpabuf_size(data->inbuf));
+			eap_pwd_state(data, FAILURE);
+			return;
+		}
+		wpabuf_put_data(data->inbuf, pos, len);
+		data->in_frag_pos += len;
+		wpa_printf(MSG_DEBUG, "EAP-pwd: Got a %d byte fragment",
+			   (int) len);
+		return;
+	}
+	/*
+	 * last fragment won't have the M bit set (but we're obviously
+	 * 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",
+			   (int) len);
+	}
+	switch (EAP_PWD_GET_EXCHANGE(lm_exch)) {
+	case EAP_PWD_OPCODE_ID_EXCH:
+		eap_pwd_process_id_resp(sm, data, pos, len);
+		break;
+	case EAP_PWD_OPCODE_COMMIT_EXCH:
+		eap_pwd_process_commit_resp(sm, data, pos, len);
+		break;
+	case EAP_PWD_OPCODE_CONFIRM_EXCH:
+		eap_pwd_process_confirm_resp(sm, data, pos, len);
+		break;
+	}
+	/*
+	 * if we had been buffering fragments, here's a great place
+	 * to clean up
+	 */
+	if (data->in_frag_pos) {
+		wpabuf_free(data->inbuf);
+		data->in_frag_pos = 0;
+	}
+}
+
+
+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pwd_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pwd_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
+{
+	struct eap_pwd_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
+{
+	struct eap_pwd_data *data = priv;
+	return (data->state == SUCCESS) || (data->state == FAILURE);
+}
+
+
+int eap_server_pwd_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+	struct timeval tp;
+	struct timezone tz;
+	u32 sr;
+
+	EVP_add_digest(EVP_sha256());
+
+	sr = 0xdeaddada;
+	(void) gettimeofday(&tp, &tz);
+	sr ^= (tp.tv_sec ^ tp.tv_usec);
+	srandom(sr);
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_PWD,
+				      "PWD");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_pwd_init;
+	eap->reset = eap_pwd_reset;
+	eap->buildReq = eap_pwd_build_req;
+	eap->check = eap_pwd_check;
+	eap->process = eap_pwd_process;
+	eap->isDone = eap_pwd_is_done;
+	eap->getKey = eap_pwd_getkey;
+	eap->get_emsk = eap_pwd_get_emsk;
+	eap->isSuccess = eap_pwd_is_success;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
+

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_sake.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_sake.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_sake.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,542 +0,0 @@
-/*
- * hostapd / EAP-SAKE (RFC 4763) server
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap_i.h"
-#include "eap_common/eap_sake_common.h"
-
-
-struct eap_sake_data {
-	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
-	u8 rand_s[EAP_SAKE_RAND_LEN];
-	u8 rand_p[EAP_SAKE_RAND_LEN];
-	struct {
-		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
-		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
-	} tek;
-	u8 msk[EAP_MSK_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 session_id;
-	u8 *peerid;
-	size_t peerid_len;
-	u8 *serverid;
-	size_t serverid_len;
-};
-
-
-static const char * eap_sake_state_txt(int state)
-{
-	switch (state) {
-	case IDENTITY:
-		return "IDENTITY";
-	case CHALLENGE:
-		return "CHALLENGE";
-	case CONFIRM:
-		return "CONFIRM";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_sake_state(struct eap_sake_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
-		   eap_sake_state_txt(data->state),
-		   eap_sake_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_sake_init(struct eap_sm *sm)
-{
-	struct eap_sake_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = CHALLENGE;
-
-	if (os_get_random(&data->session_id, 1)) {
-		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
-		os_free(data);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
-		   data->session_id);
-
-	/* TODO: add support for configuring SERVERID */
-	data->serverid = (u8 *) os_strdup("hostapd");
-	if (data->serverid)
-		data->serverid_len = os_strlen((char *) data->serverid);
-
-	return data;
-}
-
-
-static void eap_sake_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_sake_data *data = priv;
-	os_free(data->serverid);
-	os_free(data->peerid);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
-					  u8 id, size_t length, u8 subtype)
-{
-	struct eap_sake_hdr *sake;
-	struct wpabuf *msg;
-	size_t plen;
-
-	plen = sizeof(struct eap_sake_hdr) + length;
-
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
-			    EAP_CODE_REQUEST, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
-			   "request");
-		return NULL;
-	}
-
-	sake = wpabuf_put(msg, sizeof(*sake));
-	sake->version = EAP_SAKE_VERSION;
-	sake->session_id = data->session_id;
-	sake->subtype = subtype;
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
-					       struct eap_sake_data *data,
-					       u8 id)
-{
-	struct wpabuf *msg;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
-
-	plen = 4;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
-	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
-	if (msg == NULL) {
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
-	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
-
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
-						struct eap_sake_data *data,
-						u8 id)
-{
-	struct wpabuf *msg;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
-
-	if (os_get_random(data->rand_s, EAP_SAKE_RAND_LEN)) {
-		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
-		data->state = FAILURE;
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
-		    data->rand_s, EAP_SAKE_RAND_LEN);
-
-	plen = 2 + EAP_SAKE_RAND_LEN;
-	if (data->serverid)
-		plen += 2 + data->serverid_len;
-	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
-	if (msg == NULL) {
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
-	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
-			  data->rand_s, EAP_SAKE_RAND_LEN);
-
-	if (data->serverid) {
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
-		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
-				  data->serverid, data->serverid_len);
-	}
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
-					      struct eap_sake_data *data,
-					      u8 id)
-{
-	struct wpabuf *msg;
-	u8 *mic;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
-
-	msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
-				 EAP_SAKE_SUBTYPE_CONFIRM);
-	if (msg == NULL) {
-		data->state = FAILURE;
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
-	wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
-	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
-	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
-	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-				 data->serverid, data->serverid_len,
-				 data->peerid, data->peerid_len, 0,
-				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
-	{
-		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
-		data->state = FAILURE;
-		os_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_sake_data *data = priv;
-
-	switch (data->state) {
-	case IDENTITY:
-		return eap_sake_build_identity(sm, data, id);
-	case CHALLENGE:
-		return eap_sake_build_challenge(sm, data, id);
-	case CONFIRM:
-		return eap_sake_build_confirm(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
-			   data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	struct eap_sake_data *data = priv;
-	struct eap_sake_hdr *resp;
-	size_t len;
-	u8 version, session_id, subtype;
-	const u8 *pos;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
-	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
-		return TRUE;
-	}
-
-	resp = (struct eap_sake_hdr *) pos;
-	version = resp->version;
-	session_id = resp->session_id;
-	subtype = resp->subtype;
-
-	if (version != EAP_SAKE_VERSION) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
-		return TRUE;
-	}
-
-	if (session_id != data->session_id) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
-			   session_id, data->session_id);
-		return TRUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
-
-	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
-		return FALSE;
-
-	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
-		return FALSE;
-
-	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
-		return FALSE;
-
-	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
-		return FALSE;
-
-	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
-		   subtype, data->state);
-
-	return TRUE;
-}
-
-
-static void eap_sake_process_identity(struct eap_sm *sm,
-				      struct eap_sake_data *data,
-				      const struct wpabuf *respData,
-				      const u8 *payload, size_t payloadlen)
-{
-	if (data->state != IDENTITY)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
-	/* TODO: update identity and select new user data */
-	eap_sake_state(data, CHALLENGE);
-}
-
-
-static void eap_sake_process_challenge(struct eap_sm *sm,
-				       struct eap_sake_data *data,
-				       const struct wpabuf *respData,
-				       const u8 *payload, size_t payloadlen)
-{
-	struct eap_sake_parse_attr attr;
-	u8 mic_p[EAP_SAKE_MIC_LEN];
-
-	if (data->state != CHALLENGE)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
-
-	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
-		return;
-
-	if (!attr.rand_p || !attr.mic_p) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
-			   "include AT_RAND_P or AT_MIC_P");
-		return;
-	}
-
-	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
-
-	os_free(data->peerid);
-	data->peerid = NULL;
-	data->peerid_len = 0;
-	if (attr.peerid) {
-		data->peerid = os_malloc(attr.peerid_len);
-		if (data->peerid == NULL)
-			return;
-		os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
-		data->peerid_len = attr.peerid_len;
-	}
-
-	if (sm->user == NULL || sm->user->password == NULL ||
-	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
-			   "%d-byte key not configured",
-			   2 * EAP_SAKE_ROOT_SECRET_LEN);
-		data->state = FAILURE;
-		return;
-	}
-	eap_sake_derive_keys(sm->user->password,
-			     sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
-			     data->rand_s, data->rand_p,
-			     (u8 *) &data->tek, data->msk, data->emsk);
-
-	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
-			     data->peerid, data->peerid_len, 1,
-			     wpabuf_head(respData), wpabuf_len(respData),
-			     attr.mic_p, mic_p);
-	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
-		eap_sake_state(data, FAILURE);
-		return;
-	}
-
-	eap_sake_state(data, CONFIRM);
-}
-
-
-static void eap_sake_process_confirm(struct eap_sm *sm,
-				     struct eap_sake_data *data,
-				     const struct wpabuf *respData,
-				     const u8 *payload, size_t payloadlen)
-{
-	struct eap_sake_parse_attr attr;
-	u8 mic_p[EAP_SAKE_MIC_LEN];
-
-	if (data->state != CONFIRM)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
-
-	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
-		return;
-
-	if (!attr.mic_p) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
-			   "include AT_MIC_P");
-		return;
-	}
-
-	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
-			     data->serverid, data->serverid_len,
-			     data->peerid, data->peerid_len, 1,
-			     wpabuf_head(respData), wpabuf_len(respData),
-			     attr.mic_p, mic_p);
-	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
-		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
-		eap_sake_state(data, FAILURE);
-	} else
-		eap_sake_state(data, SUCCESS);
-}
-
-
-static void eap_sake_process_auth_reject(struct eap_sm *sm,
-					 struct eap_sake_data *data,
-					 const struct wpabuf *respData,
-					 const u8 *payload, size_t payloadlen)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
-	eap_sake_state(data, FAILURE);
-}
-
-
-static void eap_sake_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_sake_data *data = priv;
-	struct eap_sake_hdr *resp;
-	u8 subtype;
-	size_t len;
-	const u8 *pos, *end;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
-	if (pos == NULL || len < sizeof(struct eap_sake_hdr))
-		return;
-
-	resp = (struct eap_sake_hdr *) pos;
-	end = pos + len;
-	subtype = resp->subtype;
-	pos = (u8 *) (resp + 1);
-
-	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
-		    pos, end - pos);
-
-	switch (subtype) {
-	case EAP_SAKE_SUBTYPE_IDENTITY:
-		eap_sake_process_identity(sm, data, respData, pos, end - pos);
-		break;
-	case EAP_SAKE_SUBTYPE_CHALLENGE:
-		eap_sake_process_challenge(sm, data, respData, pos, end - pos);
-		break;
-	case EAP_SAKE_SUBTYPE_CONFIRM:
-		eap_sake_process_confirm(sm, data, respData, pos, end - pos);
-		break;
-	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
-		eap_sake_process_auth_reject(sm, data, respData, pos,
-					     end - pos);
-		break;
-	}
-}
-
-
-static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_sake_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sake_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_MSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_MSK_LEN);
-	*len = EAP_MSK_LEN;
-
-	return key;
-}
-
-
-static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sake_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-
-	return key;
-}
-
-
-static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_sake_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_sake_init;
-	eap->reset = eap_sake_reset;
-	eap->buildReq = eap_sake_buildReq;
-	eap->check = eap_sake_check;
-	eap->process = eap_sake_process;
-	eap->isDone = eap_sake_isDone;
-	eap->getKey = eap_sake_getKey;
-	eap->isSuccess = eap_sake_isSuccess;
-	eap->get_emsk = eap_sake_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_sake.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_sake.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_sake.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_sake.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,537 @@
+/*
+ * hostapd / EAP-SAKE (RFC 4763) server
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_sake_common.h"
+
+
+struct eap_sake_data {
+	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
+	u8 rand_s[EAP_SAKE_RAND_LEN];
+	u8 rand_p[EAP_SAKE_RAND_LEN];
+	struct {
+		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
+		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
+	} tek;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 session_id;
+	u8 *peerid;
+	size_t peerid_len;
+	u8 *serverid;
+	size_t serverid_len;
+};
+
+
+static const char * eap_sake_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_sake_state(struct eap_sake_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
+		   eap_sake_state_txt(data->state),
+		   eap_sake_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_sake_init(struct eap_sm *sm)
+{
+	struct eap_sake_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CHALLENGE;
+
+	if (os_get_random(&data->session_id, 1)) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+		os_free(data);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
+		   data->session_id);
+
+	/* TODO: add support for configuring SERVERID */
+	data->serverid = (u8 *) os_strdup("hostapd");
+	if (data->serverid)
+		data->serverid_len = os_strlen((char *) data->serverid);
+
+	return data;
+}
+
+
+static void eap_sake_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	os_free(data->serverid);
+	os_free(data->peerid);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data,
+					  u8 id, size_t length, u8 subtype)
+{
+	struct eap_sake_hdr *sake;
+	struct wpabuf *msg;
+	size_t plen;
+
+	plen = sizeof(struct eap_sake_hdr) + length;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen,
+			    EAP_CODE_REQUEST, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
+			   "request");
+		return NULL;
+	}
+
+	sake = wpabuf_put(msg, sizeof(*sake));
+	sake->version = EAP_SAKE_VERSION;
+	sake->session_id = data->session_id;
+	sake->subtype = subtype;
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm,
+					       struct eap_sake_data *data,
+					       u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
+
+	plen = 4;
+	if (data->serverid)
+		plen += 2 + data->serverid_len;
+	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2);
+
+	if (data->serverid) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+				  data->serverid, data->serverid_len);
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm,
+						struct eap_sake_data *data,
+						u8 id)
+{
+	struct wpabuf *msg;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
+
+	if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+		data->state = FAILURE;
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
+		    data->rand_s, EAP_SAKE_RAND_LEN);
+
+	plen = 2 + EAP_SAKE_RAND_LEN;
+	if (data->serverid)
+		plen += 2 + data->serverid_len;
+	msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
+	eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S,
+			  data->rand_s, EAP_SAKE_RAND_LEN);
+
+	if (data->serverid) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+		eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID,
+				  data->serverid, data->serverid_len);
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm,
+					      struct eap_sake_data *data,
+					      u8 id)
+{
+	struct wpabuf *msg;
+	u8 *mic;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
+
+	msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN,
+				 EAP_SAKE_SUBTYPE_CONFIRM);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
+	wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S);
+	wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN);
+	mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN);
+	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len, 0,
+				 wpabuf_head(msg), wpabuf_len(msg), mic, mic))
+	{
+		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+		data->state = FAILURE;
+		os_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_sake_data *data = priv;
+
+	switch (data->state) {
+	case IDENTITY:
+		return eap_sake_build_identity(sm, data, id);
+	case CHALLENGE:
+		return eap_sake_build_challenge(sm, data, id);
+	case CONFIRM:
+		return eap_sake_build_confirm(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	struct eap_sake_data *data = priv;
+	struct eap_sake_hdr *resp;
+	size_t len;
+	u8 version, session_id, subtype;
+	const u8 *pos;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
+	if (pos == NULL || len < sizeof(struct eap_sake_hdr)) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
+		return TRUE;
+	}
+
+	resp = (struct eap_sake_hdr *) pos;
+	version = resp->version;
+	session_id = resp->session_id;
+	subtype = resp->subtype;
+
+	if (version != EAP_SAKE_VERSION) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
+		return TRUE;
+	}
+
+	if (session_id != data->session_id) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
+			   session_id, data->session_id);
+		return TRUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
+
+	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
+		return FALSE;
+
+	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
+		return FALSE;
+
+	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
+		return FALSE;
+
+	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
+		   subtype, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_sake_process_identity(struct eap_sm *sm,
+				      struct eap_sake_data *data,
+				      const struct wpabuf *respData,
+				      const u8 *payload, size_t payloadlen)
+{
+	if (data->state != IDENTITY)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
+	/* TODO: update identity and select new user data */
+	eap_sake_state(data, CHALLENGE);
+}
+
+
+static void eap_sake_process_challenge(struct eap_sm *sm,
+				       struct eap_sake_data *data,
+				       const struct wpabuf *respData,
+				       const u8 *payload, size_t payloadlen)
+{
+	struct eap_sake_parse_attr attr;
+	u8 mic_p[EAP_SAKE_MIC_LEN];
+
+	if (data->state != CHALLENGE)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
+
+	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+		return;
+
+	if (!attr.rand_p || !attr.mic_p) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
+			   "include AT_RAND_P or AT_MIC_P");
+		return;
+	}
+
+	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
+
+	os_free(data->peerid);
+	data->peerid = NULL;
+	data->peerid_len = 0;
+	if (attr.peerid) {
+		data->peerid = os_malloc(attr.peerid_len);
+		if (data->peerid == NULL)
+			return;
+		os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
+		data->peerid_len = attr.peerid_len;
+	}
+
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
+			   "%d-byte key not configured",
+			   2 * EAP_SAKE_ROOT_SECRET_LEN);
+		data->state = FAILURE;
+		return;
+	}
+	eap_sake_derive_keys(sm->user->password,
+			     sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
+			     data->rand_s, data->rand_p,
+			     (u8 *) &data->tek, data->msk, data->emsk);
+
+	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+			     data->serverid, data->serverid_len,
+			     data->peerid, data->peerid_len, 1,
+			     wpabuf_head(respData), wpabuf_len(respData),
+			     attr.mic_p, mic_p);
+	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+		eap_sake_state(data, FAILURE);
+		return;
+	}
+
+	eap_sake_state(data, CONFIRM);
+}
+
+
+static void eap_sake_process_confirm(struct eap_sm *sm,
+				     struct eap_sake_data *data,
+				     const struct wpabuf *respData,
+				     const u8 *payload, size_t payloadlen)
+{
+	struct eap_sake_parse_attr attr;
+	u8 mic_p[EAP_SAKE_MIC_LEN];
+
+	if (data->state != CONFIRM)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
+
+	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+		return;
+
+	if (!attr.mic_p) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
+			   "include AT_MIC_P");
+		return;
+	}
+
+	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+			     data->serverid, data->serverid_len,
+			     data->peerid, data->peerid_len, 1,
+			     wpabuf_head(respData), wpabuf_len(respData),
+			     attr.mic_p, mic_p);
+	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+		eap_sake_state(data, FAILURE);
+	} else
+		eap_sake_state(data, SUCCESS);
+}
+
+
+static void eap_sake_process_auth_reject(struct eap_sm *sm,
+					 struct eap_sake_data *data,
+					 const struct wpabuf *respData,
+					 const u8 *payload, size_t payloadlen)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
+	eap_sake_state(data, FAILURE);
+}
+
+
+static void eap_sake_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_sake_data *data = priv;
+	struct eap_sake_hdr *resp;
+	u8 subtype;
+	size_t len;
+	const u8 *pos, *end;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len);
+	if (pos == NULL || len < sizeof(struct eap_sake_hdr))
+		return;
+
+	resp = (struct eap_sake_hdr *) pos;
+	end = pos + len;
+	subtype = resp->subtype;
+	pos = (u8 *) (resp + 1);
+
+	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
+		    pos, end - pos);
+
+	switch (subtype) {
+	case EAP_SAKE_SUBTYPE_IDENTITY:
+		eap_sake_process_identity(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CHALLENGE:
+		eap_sake_process_challenge(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CONFIRM:
+		eap_sake_process_confirm(sm, data, respData, pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
+		eap_sake_process_auth_reject(sm, data, respData, pos,
+					     end - pos);
+		break;
+	}
+}
+
+
+static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sake_init;
+	eap->reset = eap_sake_reset;
+	eap->buildReq = eap_sake_buildReq;
+	eap->check = eap_sake_check;
+	eap->process = eap_sake_process;
+	eap->isDone = eap_sake_isDone;
+	eap->getKey = eap_sake_getKey;
+	eap->isSuccess = eap_sake_isSuccess;
+	eap->get_emsk = eap_sake_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_sim.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_sim.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_sim.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,797 +0,0 @@
-/*
- * hostapd / EAP-SIM (RFC 4186)
- * Copyright (c) 2005-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap_i.h"
-#include "eap_common/eap_sim_common.h"
-#include "eap_server/eap_sim_db.h"
-
-
-struct eap_sim_data {
-	u8 mk[EAP_SIM_MK_LEN];
-	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
-	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
-	u8 k_aut[EAP_SIM_K_AUT_LEN];
-	u8 k_encr[EAP_SIM_K_ENCR_LEN];
-	u8 msk[EAP_SIM_KEYING_DATA_LEN];
-	u8 emsk[EAP_EMSK_LEN];
-	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
-	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
-	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
-	int num_chal;
-	enum {
-		START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
-	} state;
-	char *next_pseudonym;
-	char *next_reauth_id;
-	u16 counter;
-	struct eap_sim_reauth *reauth;
-	u16 notification;
-	int use_result_ind;
-};
-
-
-static const char * eap_sim_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case CHALLENGE:
-		return "CHALLENGE";
-	case REAUTH:
-		return "REAUTH";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	case NOTIFICATION:
-		return "NOTIFICATION";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_sim_state(struct eap_sim_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
-		   eap_sim_state_txt(data->state),
-		   eap_sim_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_sim_init(struct eap_sm *sm)
-{
-	struct eap_sim_data *data;
-
-	if (sm->eap_sim_db_priv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = START;
-
-	return data;
-}
-
-
-static void eap_sim_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	os_free(data->next_pseudonym);
-	os_free(data->next_reauth_id);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
-					   struct eap_sim_data *data, u8 id)
-{
-	struct eap_sim_msg *msg;
-	u8 ver[2];
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_START);
-	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
-				      sm->identity_len)) {
-		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
-		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
-	} else {
-		/*
-		 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
-		 * ignored and the SIM/Start is used to request the identity.
-		 */
-		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
-		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
-	}
-	wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
-	ver[0] = 0;
-	ver[1] = EAP_SIM_VERSION;
-	eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
-			ver, sizeof(ver));
-	return eap_sim_msg_finish(msg, NULL, NULL, 0);
-}
-
-
-static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
-			      struct eap_sim_msg *msg, u16 counter,
-			      const u8 *nonce_s)
-{
-	os_free(data->next_pseudonym);
-	data->next_pseudonym =
-		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
-	os_free(data->next_reauth_id);
-	if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
-		data->next_reauth_id =
-			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
-			   "count exceeded - force full authentication");
-		data->next_reauth_id = NULL;
-	}
-
-	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
-	    counter == 0 && nonce_s == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "   AT_IV");
-	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
-
-	if (counter > 0) {
-		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
-		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
-	}
-
-	if (nonce_s) {
-		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
-		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
-				EAP_SIM_NONCE_S_LEN);
-	}
-
-	if (data->next_pseudonym) {
-		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
-			   data->next_pseudonym);
-		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
-				os_strlen(data->next_pseudonym),
-				(u8 *) data->next_pseudonym,
-				os_strlen(data->next_pseudonym));
-	}
-
-	if (data->next_reauth_id) {
-		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
-			   data->next_reauth_id);
-		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
-				os_strlen(data->next_reauth_id),
-				(u8 *) data->next_reauth_id,
-				os_strlen(data->next_reauth_id));
-	}
-
-	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
-			   "AT_ENCR_DATA");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
-					       struct eap_sim_data *data,
-					       u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_CHALLENGE);
-	wpa_printf(MSG_DEBUG, "   AT_RAND");
-	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
-			data->num_chal * GSM_RAND_LEN);
-
-	if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-
-	if (sm->eap_sim_aka_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt,
-				  EAP_SIM_NONCE_MT_LEN);
-}
-
-
-static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
-					    struct eap_sim_data *data, u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
-
-	if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN))
-		return NULL;
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
-			data->nonce_s, EAP_SIM_NONCE_S_LEN);
-
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
-	eap_sim_derive_keys_reauth(data->counter, sm->identity,
-				   sm->identity_len, data->nonce_s, data->mk,
-				   data->msk, data->emsk);
-
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
-
-	if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
-		eap_sim_msg_free(msg);
-		return NULL;
-	}
-
-	if (sm->eap_sim_aka_result_ind) {
-		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
-		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
-	}
-
-	wpa_printf(MSG_DEBUG, "   AT_MAC");
-	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
-}
-
-
-static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
-						  struct eap_sim_data *data,
-						  u8 id)
-{
-	struct eap_sim_msg *msg;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
-			       EAP_SIM_SUBTYPE_NOTIFICATION);
-	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
-	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
-			NULL, 0);
-	if (data->use_result_ind) {
-		if (data->reauth) {
-			wpa_printf(MSG_DEBUG, "   AT_IV");
-			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
-			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
-						   EAP_SIM_AT_ENCR_DATA);
-			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
-				   data->counter);
-			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
-					NULL, 0);
-
-			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
-						     EAP_SIM_AT_PADDING)) {
-				wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
-					   "encrypt AT_ENCR_DATA");
-				eap_sim_msg_free(msg);
-				return NULL;
-			}
-		}
-
-		wpa_printf(MSG_DEBUG, "   AT_MAC");
-		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
-	}
-	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
-}
-
-
-static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_sim_data *data = priv;
-
-	switch (data->state) {
-	case START:
-		return eap_sim_build_start(sm, data, id);
-	case CHALLENGE:
-		return eap_sim_build_challenge(sm, data, id);
-	case REAUTH:
-		return eap_sim_build_reauth(sm, data, id);
-	case NOTIFICATION:
-		return eap_sim_build_notification(sm, data, id);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
-			   "buildReq", data->state);
-		break;
-	}
-	return NULL;
-}
-
-
-static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_sim_data *data = priv;
-	const u8 *pos;
-	size_t len;
-	u8 subtype;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
-	if (pos == NULL || len < 3) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
-		return TRUE;
-	}
-	subtype = *pos;
-
-	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
-		return FALSE;
-
-	switch (data->state) {
-	case START:
-		if (subtype != EAP_SIM_SUBTYPE_START) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case CHALLENGE:
-		if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case REAUTH:
-		if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	case NOTIFICATION:
-		if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
-			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
-				   "subtype %d", subtype);
-			return TRUE;
-		}
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
-			   "processing a response", data->state);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
-{
-	return version == EAP_SIM_VERSION;
-}
-
-
-static void eap_sim_process_start(struct eap_sm *sm,
-				  struct eap_sim_data *data,
-				  struct wpabuf *respData,
-				  struct eap_sim_attrs *attr)
-{
-	const u8 *identity;
-	size_t identity_len;
-	u8 ver_list[2];
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
-
-	if (attr->identity) {
-		os_free(sm->identity);
-		sm->identity = os_malloc(attr->identity_len);
-		if (sm->identity) {
-			os_memcpy(sm->identity, attr->identity,
-				  attr->identity_len);
-			sm->identity_len = attr->identity_len;
-		}
-	}
-
-	identity = NULL;
-	identity_len = 0;
-
-	if (sm->identity && sm->identity_len > 0 &&
-	    sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	} else {
-		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
-						    sm->identity,
-						    sm->identity_len,
-						    &identity_len);
-		if (identity == NULL) {
-			data->reauth = eap_sim_db_get_reauth_entry(
-				sm->eap_sim_db_priv, sm->identity,
-				sm->identity_len);
-			if (data->reauth) {
-				wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
-					   "re-authentication");
-				identity = data->reauth->identity;
-				identity_len = data->reauth->identity_len;
-				data->counter = data->reauth->counter;
-				os_memcpy(data->mk, data->reauth->mk,
-					  EAP_SIM_MK_LEN);
-			}
-		}
-	}
-
-	if (identity == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
-			   " user name");
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
-			  identity, identity_len);
-
-	if (data->reauth) {
-		eap_sim_state(data, REAUTH);
-		return;
-	}
-
-	if (attr->nonce_mt == NULL || attr->selected_version < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
-			   "required attributes");
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	if (!eap_sim_supported_ver(data, attr->selected_version)) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
-			   "version %d", attr->selected_version);
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	data->counter = 0; /* reset re-auth counter since this is full auth */
-	data->reauth = NULL;
-
-	data->num_chal = eap_sim_db_get_gsm_triplets(
-		sm->eap_sim_db_priv, identity, identity_len,
-		EAP_SIM_MAX_CHAL,
-		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
-	if (data->num_chal == EAP_SIM_DB_PENDING) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
-			   "not yet available - pending request");
-		sm->method_pending = METHOD_PENDING_WAIT;
-		return;
-	}
-	if (data->num_chal < 2) {
-		wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
-			   "authentication triplets for the peer");
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	identity_len = sm->identity_len;
-	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
-			   "character from identity");
-		identity_len--;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
-			  sm->identity, identity_len);
-
-	os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
-	WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
-	eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
-			  attr->selected_version, ver_list, sizeof(ver_list),
-			  data->num_chal, (const u8 *) data->kc, data->mk);
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
-
-	eap_sim_state(data, CHALLENGE);
-}
-
-
-static void eap_sim_process_challenge(struct eap_sm *sm,
-				      struct eap_sim_data *data,
-				      struct wpabuf *respData,
-				      struct eap_sim_attrs *attr)
-{
-	const u8 *identity;
-	size_t identity_len;
-
-	if (attr->mac == NULL ||
-	    eap_sim_verify_mac(data->k_aut, respData, attr->mac,
-			       (u8 *) data->sres,
-			       data->num_chal * EAP_SIM_SRES_LEN)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
-			   "did not include valid AT_MAC");
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
-		   "correct AT_MAC");
-	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
-		data->use_result_ind = 1;
-		data->notification = EAP_SIM_SUCCESS;
-		eap_sim_state(data, NOTIFICATION);
-	} else
-		eap_sim_state(data, SUCCESS);
-
-	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
-					    sm->identity_len, &identity_len);
-	if (identity == NULL) {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	}
-
-	if (data->next_pseudonym) {
-		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-					 identity_len,
-					 data->next_pseudonym);
-		data->next_pseudonym = NULL;
-	}
-	if (data->next_reauth_id) {
-		eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-				      identity_len,
-				      data->next_reauth_id, data->counter + 1,
-				      data->mk);
-		data->next_reauth_id = NULL;
-	}
-}
-
-
-static void eap_sim_process_reauth(struct eap_sm *sm,
-				   struct eap_sim_data *data,
-				   struct wpabuf *respData,
-				   struct eap_sim_attrs *attr)
-{
-	struct eap_sim_attrs eattr;
-	u8 *decrypted = NULL;
-	const u8 *identity, *id2;
-	size_t identity_len, id2_len;
-
-	if (attr->mac == NULL ||
-	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
-			       EAP_SIM_NONCE_S_LEN)) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
-			   "did not include valid AT_MAC");
-		goto fail;
-	}
-
-	if (attr->encr_data == NULL || attr->iv == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
-			   "message did not include encrypted data");
-		goto fail;
-	}
-
-	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
-				       attr->encr_data_len, attr->iv, &eattr,
-				       0);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
-			   "data from reauthentication message");
-		goto fail;
-	}
-
-	if (eattr.counter != data->counter) {
-		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
-			   "used incorrect counter %u, expected %u",
-			   eattr.counter, data->counter);
-		goto fail;
-	}
-	os_free(decrypted);
-	decrypted = NULL;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
-		   "the correct AT_MAC");
-	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
-		data->use_result_ind = 1;
-		data->notification = EAP_SIM_SUCCESS;
-		eap_sim_state(data, NOTIFICATION);
-	} else
-		eap_sim_state(data, SUCCESS);
-
-	if (data->reauth) {
-		identity = data->reauth->identity;
-		identity_len = data->reauth->identity_len;
-	} else {
-		identity = sm->identity;
-		identity_len = sm->identity_len;
-	}
-
-	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
-				       identity_len, &id2_len);
-	if (id2) {
-		identity = id2;
-		identity_len = id2_len;
-	}
-
-	if (data->next_pseudonym) {
-		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
-					 identity_len, data->next_pseudonym);
-		data->next_pseudonym = NULL;
-	}
-	if (data->next_reauth_id) {
-		eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-				      identity_len, data->next_reauth_id,
-				      data->counter + 1, data->mk);
-		data->next_reauth_id = NULL;
-	} else {
-		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
-		data->reauth = NULL;
-	}
-
-	return;
-
-fail:
-	eap_sim_state(data, FAILURE);
-	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
-	data->reauth = NULL;
-	os_free(decrypted);
-}
-
-
-static void eap_sim_process_client_error(struct eap_sm *sm,
-					 struct eap_sim_data *data,
-					 struct wpabuf *respData,
-					 struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
-		   attr->client_error_code);
-	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
-		eap_sim_state(data, SUCCESS);
-	else
-		eap_sim_state(data, FAILURE);
-}
-
-
-static void eap_sim_process_notification(struct eap_sm *sm,
-					 struct eap_sim_data *data,
-					 struct wpabuf *respData,
-					 struct eap_sim_attrs *attr)
-{
-	wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
-	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
-		eap_sim_state(data, SUCCESS);
-	else
-		eap_sim_state(data, FAILURE);
-}
-
-
-static void eap_sim_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_sim_data *data = priv;
-	const u8 *pos, *end;
-	u8 subtype;
-	size_t len;
-	struct eap_sim_attrs attr;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
-	if (pos == NULL || len < 3)
-		return;
-
-	end = pos + len;
-	subtype = *pos;
-	pos += 3;
-
-	if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
-		eap_sim_state(data, FAILURE);
-		return;
-	}
-
-	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
-		eap_sim_process_client_error(sm, data, respData, &attr);
-		return;
-	}
-
-	switch (data->state) {
-	case START:
-		eap_sim_process_start(sm, data, respData, &attr);
-		break;
-	case CHALLENGE:
-		eap_sim_process_challenge(sm, data, respData, &attr);
-		break;
-	case REAUTH:
-		eap_sim_process_reauth(sm, data, respData, &attr);
-		break;
-	case NOTIFICATION:
-		eap_sim_process_notification(sm, data, respData, &attr);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
-			   "process", data->state);
-		break;
-	}
-}
-
-
-static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sim_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
-	*len = EAP_SIM_KEYING_DATA_LEN;
-	return key;
-}
-
-
-static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_sim_data *data = priv;
-	u8 *key;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(EAP_EMSK_LEN);
-	if (key == NULL)
-		return NULL;
-	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
-	*len = EAP_EMSK_LEN;
-	return key;
-}
-
-
-static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_sim_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_sim_init;
-	eap->reset = eap_sim_reset;
-	eap->buildReq = eap_sim_buildReq;
-	eap->check = eap_sim_check;
-	eap->process = eap_sim_process;
-	eap->isDone = eap_sim_isDone;
-	eap->getKey = eap_sim_getKey;
-	eap->isSuccess = eap_sim_isSuccess;
-	eap->get_emsk = eap_sim_get_emsk;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_sim.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_sim.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_sim.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_sim.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,847 @@
+/*
+ * hostapd / EAP-SIM (RFC 4186)
+ * Copyright (c) 2005-2012, Jouni Malinen <j at 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/random.h"
+#include "eap_server/eap_i.h"
+#include "eap_common/eap_sim_common.h"
+#include "eap_server/eap_sim_db.h"
+
+
+struct eap_sim_data {
+	u8 mk[EAP_SIM_MK_LEN];
+	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
+	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
+	u8 k_aut[EAP_SIM_K_AUT_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 msk[EAP_SIM_KEYING_DATA_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
+	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+	int num_chal;
+	enum {
+		START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
+	} state;
+	char *next_pseudonym;
+	char *next_reauth_id;
+	u16 counter;
+	struct eap_sim_reauth *reauth;
+	u16 notification;
+	int use_result_ind;
+	int start_round;
+	char permanent[20]; /* Permanent username */
+};
+
+
+static const char * eap_sim_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case REAUTH:
+		return "REAUTH";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	case NOTIFICATION:
+		return "NOTIFICATION";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_sim_state(struct eap_sim_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
+		   eap_sim_state_txt(data->state),
+		   eap_sim_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_sim_init(struct eap_sm *sm)
+{
+	struct eap_sim_data *data;
+
+	if (sm->eap_sim_db_priv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = START;
+
+	return data;
+}
+
+
+static void eap_sim_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	os_free(data->next_pseudonym);
+	os_free(data->next_reauth_id);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
+					   struct eap_sim_data *data, u8 id)
+{
+	struct eap_sim_msg *msg;
+	u8 ver[2];
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_START);
+	data->start_round++;
+	if (data->start_round == 1) {
+		/*
+		 * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
+		 * ignored and the SIM/Start is used to request the identity.
+		 */
+		wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+	} else if (data->start_round > 3) {
+		/* Cannot use more than three rounds of Start messages */
+		eap_sim_msg_free(msg);
+		return NULL;
+	} else if (data->start_round == 0) {
+		/*
+		 * This is a special case that is used to recover from
+		 * AT_COUNTER_TOO_SMALL during re-authentication. Since we
+		 * already know the identity of the peer, there is no need to
+		 * request any identity in this case.
+		 */
+	} else if (sm->identity && sm->identity_len > 0 &&
+		   sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+		/* Reauth id may have expired - try fullauth */
+		wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+	} else {
+		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+	}
+	wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
+	ver[0] = 0;
+	ver[1] = EAP_SIM_VERSION;
+	eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
+			ver, sizeof(ver));
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
+			      struct eap_sim_msg *msg, u16 counter,
+			      const u8 *nonce_s)
+{
+	os_free(data->next_pseudonym);
+	if (nonce_s == NULL) {
+		data->next_pseudonym =
+			eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
+						      EAP_SIM_DB_SIM);
+	} else {
+		/* Do not update pseudonym during re-authentication */
+		data->next_pseudonym = NULL;
+	}
+	os_free(data->next_reauth_id);
+	if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+		data->next_reauth_id =
+			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
+						      EAP_SIM_DB_SIM);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
+			   "count exceeded - force full authentication");
+		data->next_reauth_id = NULL;
+	}
+
+	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+	    counter == 0 && nonce_s == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter > 0) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+	}
+
+	if (nonce_s) {
+		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
+		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+				EAP_SIM_NONCE_S_LEN);
+	}
+
+	if (data->next_pseudonym) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
+			   data->next_pseudonym);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+				os_strlen(data->next_pseudonym),
+				(u8 *) data->next_pseudonym,
+				os_strlen(data->next_pseudonym));
+	}
+
+	if (data->next_reauth_id) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
+			   data->next_reauth_id);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+				os_strlen(data->next_reauth_id),
+				(u8 *) data->next_reauth_id,
+				os_strlen(data->next_reauth_id));
+	}
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
+					       struct eap_sim_data *data,
+					       u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_RAND");
+	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
+			data->num_chal * GSM_RAND_LEN);
+
+	if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	if (sm->eap_sim_aka_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt,
+				  EAP_SIM_NONCE_MT_LEN);
+}
+
+
+static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
+					    struct eap_sim_data *data, u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
+
+	if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+		return NULL;
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
+			data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+			    data->emsk);
+	eap_sim_derive_keys_reauth(data->counter, sm->identity,
+				   sm->identity_len, data->nonce_s, data->mk,
+				   data->msk, data->emsk);
+
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
+
+	if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	if (sm->eap_sim_aka_result_ind) {
+		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
+		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+}
+
+
+static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
+						  struct eap_sim_data *data,
+						  u8 id)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+			       EAP_SIM_SUBTYPE_NOTIFICATION);
+	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
+	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
+			NULL, 0);
+	if (data->use_result_ind) {
+		if (data->reauth) {
+			wpa_printf(MSG_DEBUG, "   AT_IV");
+			wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+			eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
+						   EAP_SIM_AT_ENCR_DATA);
+			wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
+				   data->counter);
+			eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
+					NULL, 0);
+
+			if (eap_sim_msg_add_encr_end(msg, data->k_encr,
+						     EAP_SIM_AT_PADDING)) {
+				wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
+					   "encrypt AT_ENCR_DATA");
+				eap_sim_msg_free(msg);
+				return NULL;
+			}
+		}
+
+		wpa_printf(MSG_DEBUG, "   AT_MAC");
+		eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	}
+	return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+}
+
+
+static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_sim_data *data = priv;
+
+	switch (data->state) {
+	case START:
+		return eap_sim_build_start(sm, data, id);
+	case CHALLENGE:
+		return eap_sim_build_challenge(sm, data, id);
+	case REAUTH:
+		return eap_sim_build_reauth(sm, data, id);
+	case NOTIFICATION:
+		return eap_sim_build_notification(sm, data, id);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
+			   "buildReq", data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
+	if (pos == NULL || len < 3) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
+					  u8 subtype)
+{
+	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
+		return FALSE;
+
+	switch (data->state) {
+	case START:
+		if (subtype != EAP_SIM_SUBTYPE_START) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case CHALLENGE:
+		if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case REAUTH:
+		if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case NOTIFICATION:
+		if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
+			   "processing a response", data->state);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
+{
+	return version == EAP_SIM_VERSION;
+}
+
+
+static void eap_sim_process_start(struct eap_sm *sm,
+				  struct eap_sim_data *data,
+				  struct wpabuf *respData,
+				  struct eap_sim_attrs *attr)
+{
+	size_t identity_len;
+	u8 ver_list[2];
+	u8 *new_identity;
+	char *username;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
+
+	if (data->start_round == 0) {
+		/*
+		 * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
+		 * was requested since we already know it.
+		 */
+		goto skip_id_update;
+	}
+
+	/*
+	 * We always request identity in SIM/Start, so the peer is required to
+	 * have replied with one.
+	 */
+	if (!attr->identity || attr->identity_len == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
+			   "identity");
+		goto failed;
+	}
+
+	new_identity = os_malloc(attr->identity_len);
+	if (new_identity == NULL)
+		goto failed;
+	os_free(sm->identity);
+	sm->identity = new_identity;
+	os_memcpy(sm->identity, attr->identity, attr->identity_len);
+	sm->identity_len = attr->identity_len;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
+			  sm->identity, sm->identity_len);
+	username = sim_get_username(sm->identity, sm->identity_len);
+	if (username == NULL)
+		goto failed;
+
+	if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
+			   username);
+		data->reauth = eap_sim_db_get_reauth_entry(
+			sm->eap_sim_db_priv, username);
+		os_free(username);
+		if (data->reauth == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
+				   "identity - request full auth identity");
+			/* Remain in START state for another round */
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
+		os_strlcpy(data->permanent, data->reauth->permanent,
+			   sizeof(data->permanent));
+		data->counter = data->reauth->counter;
+		os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
+		eap_sim_state(data, REAUTH);
+		return;
+	}
+
+	if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
+		const char *permanent;
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
+			   username);
+		permanent = eap_sim_db_get_permanent(
+			sm->eap_sim_db_priv, username);
+		os_free(username);
+		if (permanent == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
+				   "identity - request permanent identity");
+			/* Remain in START state for another round */
+			return;
+		}
+		os_strlcpy(data->permanent, permanent,
+			   sizeof(data->permanent));
+	} else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
+			   username);
+		os_strlcpy(data->permanent, username, sizeof(data->permanent));
+		os_free(username);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
+			   username);
+		os_free(username);
+		goto failed;
+	}
+
+skip_id_update:
+	/* Full authentication */
+
+	if (attr->nonce_mt == NULL || attr->selected_version < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
+			   "required attributes");
+		goto failed;
+	}
+
+	if (!eap_sim_supported_ver(data, attr->selected_version)) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
+			   "version %d", attr->selected_version);
+		goto failed;
+	}
+
+	data->counter = 0; /* reset re-auth counter since this is full auth */
+	data->reauth = NULL;
+
+	data->num_chal = eap_sim_db_get_gsm_triplets(
+		sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
+		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
+	if (data->num_chal == EAP_SIM_DB_PENDING) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
+			   "not yet available - pending request");
+		sm->method_pending = METHOD_PENDING_WAIT;
+		return;
+	}
+	if (data->num_chal < 2) {
+		wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
+			   "authentication triplets for the peer");
+		goto failed;
+	}
+
+	identity_len = sm->identity_len;
+	while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
+			   "character from identity");
+		identity_len--;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
+			  sm->identity, identity_len);
+
+	os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+	WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
+	eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
+			  attr->selected_version, ver_list, sizeof(ver_list),
+			  data->num_chal, (const u8 *) data->kc, data->mk);
+	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+			    data->emsk);
+
+	eap_sim_state(data, CHALLENGE);
+	return;
+
+failed:
+	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+	eap_sim_state(data, NOTIFICATION);
+}
+
+
+static void eap_sim_process_challenge(struct eap_sm *sm,
+				      struct eap_sim_data *data,
+				      struct wpabuf *respData,
+				      struct eap_sim_attrs *attr)
+{
+	if (attr->mac == NULL ||
+	    eap_sim_verify_mac(data->k_aut, respData, attr->mac,
+			       (u8 *) data->sres,
+			       data->num_chal * EAP_SIM_SRES_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+			   "did not include valid AT_MAC");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_sim_state(data, NOTIFICATION);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
+		   "correct AT_MAC");
+	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+		data->use_result_ind = 1;
+		data->notification = EAP_SIM_SUCCESS;
+		eap_sim_state(data, NOTIFICATION);
+	} else
+		eap_sim_state(data, SUCCESS);
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
+					 data->next_pseudonym);
+		data->next_pseudonym = NULL;
+	}
+	if (data->next_reauth_id) {
+		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+				      data->next_reauth_id, data->counter + 1,
+				      data->mk);
+		data->next_reauth_id = NULL;
+	}
+}
+
+
+static void eap_sim_process_reauth(struct eap_sm *sm,
+				   struct eap_sim_data *data,
+				   struct wpabuf *respData,
+				   struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted = NULL;
+
+	if (attr->mac == NULL ||
+	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
+			       EAP_SIM_NONCE_S_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+			   "did not include valid AT_MAC");
+		goto fail;
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+			   "message did not include encrypted data");
+		goto fail;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+			   "data from reauthentication message");
+		goto fail;
+	}
+
+	if (eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+			   "used incorrect counter %u, expected %u",
+			   eattr.counter, data->counter);
+		goto fail;
+	}
+	os_free(decrypted);
+	decrypted = NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
+		   "the correct AT_MAC");
+
+	if (eattr.counter_too_small) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+			   "included AT_COUNTER_TOO_SMALL - starting full "
+			   "authentication");
+		data->start_round = -1;
+		eap_sim_state(data, START);
+		return;
+	}
+
+	if (sm->eap_sim_aka_result_ind && attr->result_ind) {
+		data->use_result_ind = 1;
+		data->notification = EAP_SIM_SUCCESS;
+		eap_sim_state(data, NOTIFICATION);
+	} else
+		eap_sim_state(data, SUCCESS);
+
+	if (data->next_reauth_id) {
+		eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+				      data->next_reauth_id,
+				      data->counter + 1, data->mk);
+		data->next_reauth_id = NULL;
+	} else {
+		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+		data->reauth = NULL;
+	}
+
+	return;
+
+fail:
+	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+	eap_sim_state(data, NOTIFICATION);
+	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+	data->reauth = NULL;
+	os_free(decrypted);
+}
+
+
+static void eap_sim_process_client_error(struct eap_sm *sm,
+					 struct eap_sim_data *data,
+					 struct wpabuf *respData,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
+		   attr->client_error_code);
+	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
+		eap_sim_state(data, SUCCESS);
+	else
+		eap_sim_state(data, FAILURE);
+}
+
+
+static void eap_sim_process_notification(struct eap_sm *sm,
+					 struct eap_sim_data *data,
+					 struct wpabuf *respData,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
+	if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
+		eap_sim_state(data, SUCCESS);
+	else
+		eap_sim_state(data, FAILURE);
+}
+
+
+static void eap_sim_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_sim_data *data = priv;
+	const u8 *pos, *end;
+	u8 subtype;
+	size_t len;
+	struct eap_sim_attrs attr;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
+	if (pos == NULL || len < 3)
+		return;
+
+	end = pos + len;
+	subtype = *pos;
+	pos += 3;
+
+	if (eap_sim_unexpected_subtype(data, subtype)) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
+			   "EAP-SIM Subtype in EAP Response");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_sim_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
+		if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
+		    (data->state == START || data->state == CHALLENGE ||
+		     data->state == REAUTH)) {
+			data->notification =
+				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+			eap_sim_state(data, NOTIFICATION);
+			return;
+		}
+		eap_sim_state(data, FAILURE);
+		return;
+	}
+
+	if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
+		eap_sim_process_client_error(sm, data, respData, &attr);
+		return;
+	}
+
+	switch (data->state) {
+	case START:
+		eap_sim_process_start(sm, data, respData, &attr);
+		break;
+	case CHALLENGE:
+		eap_sim_process_challenge(sm, data, respData, &attr);
+		break;
+	case REAUTH:
+		eap_sim_process_reauth(sm, data, respData, &attr);
+		break;
+	case NOTIFICATION:
+		eap_sim_process_notification(sm, data, respData, &attr);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
+			   "process", data->state);
+		break;
+	}
+}
+
+
+static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+	*len = EAP_SIM_KEYING_DATA_LEN;
+	return key;
+}
+
+
+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+	return key;
+}
+
+
+static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_sim_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sim_init;
+	eap->reset = eap_sim_reset;
+	eap->buildReq = eap_sim_buildReq;
+	eap->check = eap_sim_check;
+	eap->process = eap_sim_process;
+	eap->isDone = eap_sim_isDone;
+	eap->getKey = eap_sim_getKey;
+	eap->isSuccess = eap_sim_isSuccess;
+	eap->get_emsk = eap_sim_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_tls.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_tls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,286 +0,0 @@
-/*
- * hostapd / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-#include "eap_tls_common.h"
-#include "crypto/tls.h"
-
-
-static void eap_tls_reset(struct eap_sm *sm, void *priv);
-
-
-struct eap_tls_data {
-	struct eap_ssl_data ssl;
-	enum { START, CONTINUE, SUCCESS, FAILURE } state;
-	int established;
-};
-
-
-static const char * eap_tls_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case CONTINUE:
-		return "CONTINUE";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_tls_state(struct eap_tls_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
-		   eap_tls_state_txt(data->state),
-		   eap_tls_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_tls_init(struct eap_sm *sm)
-{
-	struct eap_tls_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = START;
-
-	if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
-		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
-		eap_tls_reset(sm, data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_tls_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	if (data == NULL)
-		return;
-	eap_server_tls_ssl_deinit(sm, &data->ssl);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
-					   struct eap_tls_data *data, u8 id)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
-			    id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
-			   "request");
-		eap_tls_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
-
-	eap_tls_state(data, CONTINUE);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_tls_data *data = priv;
-	struct wpabuf *res;
-
-	if (data->ssl.state == FRAG_ACK) {
-		return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
-	}
-
-	if (data->ssl.state == WAIT_FRAG_ACK) {
-		res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
-					       id);
-		goto check_established;
-	}
-
-	switch (data->state) {
-	case START:
-		return eap_tls_build_start(sm, data, id);
-	case CONTINUE:
-		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
-			data->established = 1;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
-			   __func__, data->state);
-		return NULL;
-	}
-
-	res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
-
-check_established:
-	if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
-		/* TLS handshake has been completed and there are no more
-		 * fragments waiting to be sent out. */
-		wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
-		eap_tls_state(data, SUCCESS);
-	}
-
-	return res;
-}
-
-
-static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
-				const struct wpabuf *respData)
-{
-	struct eap_tls_data *data = priv;
-	if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
-			   "handshake message");
-		return;
-	}
-	if (eap_server_tls_phase1(sm, &data->ssl) < 0)
-		eap_tls_state(data, FAILURE);
-}
-
-
-static void eap_tls_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_tls_data *data = priv;
-	if (eap_server_tls_process(sm, &data->ssl, respData, data,
-				   EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
-	    0)
-		eap_tls_state(data, FAILURE);
-}
-
-
-static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_tls_data *data = priv;
-	u8 *eapKeyData;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption",
-					       EAP_TLS_KEY_LEN);
-	if (eapKeyData) {
-		*len = EAP_TLS_KEY_LEN;
-		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
-			    eapKeyData, EAP_TLS_KEY_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
-	}
-
-	return eapKeyData;
-}
-
-
-static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_tls_data *data = priv;
-	u8 *eapKeyData, *emsk;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-					       "client EAP encryption",
-					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
-	if (eapKeyData) {
-		emsk = os_malloc(EAP_EMSK_LEN);
-		if (emsk)
-			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
-				  EAP_EMSK_LEN);
-		os_free(eapKeyData);
-	} else
-		emsk = NULL;
-
-	if (emsk) {
-		*len = EAP_EMSK_LEN;
-		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
-			    emsk, EAP_EMSK_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
-	}
-
-	return emsk;
-}
-
-
-static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_tls_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_tls_init;
-	eap->reset = eap_tls_reset;
-	eap->buildReq = eap_tls_buildReq;
-	eap->check = eap_tls_check;
-	eap->process = eap_tls_process;
-	eap->isDone = eap_tls_isDone;
-	eap->getKey = eap_tls_getKey;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_tls.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_tls.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_tls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,342 @@
+/*
+ * hostapd / EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2008, Jouni Malinen <j at 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 "eap_i.h"
+#include "eap_tls_common.h"
+#include "crypto/tls.h"
+
+
+static void eap_tls_reset(struct eap_sm *sm, void *priv);
+
+
+struct eap_tls_data {
+	struct eap_ssl_data ssl;
+	enum { START, CONTINUE, SUCCESS, FAILURE } state;
+	int established;
+	u8 eap_type;
+};
+
+
+static const char * eap_tls_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case CONTINUE:
+		return "CONTINUE";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_tls_state(struct eap_tls_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
+		   eap_tls_state_txt(data->state),
+		   eap_tls_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = START;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_reset(sm, data);
+		return NULL;
+	}
+
+	data->eap_type = EAP_TYPE_TLS;
+
+	return data;
+}
+
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = START;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_reset(sm, data);
+		return NULL;
+	}
+
+	data->eap_type = EAP_UNAUTH_TLS_TYPE;
+	return data;
+}
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
+
+static void eap_tls_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	if (data == NULL)
+		return;
+	eap_server_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
+					   struct eap_tls_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
+			   "request");
+		eap_tls_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
+
+	eap_tls_state(data, CONTINUE);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_tls_data *data = priv;
+	struct wpabuf *res;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, data->eap_type, 0);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
+					       id);
+		goto check_established;
+	}
+
+	switch (data->state) {
+	case START:
+		return eap_tls_build_start(sm, data, id);
+	case CONTINUE:
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+			data->established = 1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
+			   __func__, data->state);
+		return NULL;
+	}
+
+	res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
+
+check_established:
+	if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
+		/* TLS handshake has been completed and there are no more
+		 * fragments waiting to be sent out. */
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+		eap_tls_state(data, SUCCESS);
+	}
+
+	return res;
+}
+
+
+static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_tls_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
+		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+				       EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+				       &len);
+	else
+		pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
+				       respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
+				const struct wpabuf *respData)
+{
+	struct eap_tls_data *data = priv;
+	if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
+			   "handshake message");
+		return;
+	}
+	if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+		eap_tls_state(data, FAILURE);
+}
+
+
+static void eap_tls_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_tls_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   data->eap_type, NULL, eap_tls_process_msg) <
+	    0)
+		eap_tls_state(data, FAILURE);
+}
+
+
+static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "client EAP encryption",
+					       EAP_TLS_KEY_LEN);
+	if (eapKeyData) {
+		*len = EAP_TLS_KEY_LEN;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
+			    eapKeyData, EAP_TLS_KEY_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
+	}
+
+	return eapKeyData;
+}
+
+
+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *eapKeyData, *emsk;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "client EAP encryption",
+					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+	if (eapKeyData) {
+		emsk = os_malloc(EAP_EMSK_LEN);
+		if (emsk)
+			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+				  EAP_EMSK_LEN);
+		os_free(eapKeyData);
+	} else
+		emsk = NULL;
+
+	if (emsk) {
+		*len = EAP_EMSK_LEN;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
+			    emsk, EAP_EMSK_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
+	}
+
+	return emsk;
+}
+
+
+static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tls_init;
+	eap->reset = eap_tls_reset;
+	eap->buildReq = eap_tls_buildReq;
+	eap->check = eap_tls_check;
+	eap->process = eap_tls_process;
+	eap->isDone = eap_tls_isDone;
+	eap->getKey = eap_tls_getKey;
+	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;
+}
+
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+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_VENDOR_TYPE_UNAUTH_TLS,
+				      "UNAUTH-TLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_unauth_tls_init;
+	eap->reset = eap_tls_reset;
+	eap->buildReq = eap_tls_buildReq;
+	eap->check = eap_tls_check;
+	eap->process = eap_tls_process;
+	eap->isDone = eap_tls_isDone;
+	eap->getKey = eap_tls_getKey;
+	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;
+}
+#endif /* EAP_SERVER_UNAUTH_TLS */

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_tls_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,401 +0,0 @@
-/*
- * EAP-TLS/PEAP/TTLS/FAST server common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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"
-
-
-static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
-
-
-int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
-			    int verify_peer)
-{
-	data->eap = sm;
-	data->phase2 = sm->init_phase2;
-
-	data->conn = tls_connection_init(sm->ssl_ctx);
-	if (data->conn == NULL) {
-		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
-			   "connection");
-		return -1;
-	}
-
-	if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
-		wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
-			   "of TLS peer certificate");
-		tls_connection_deinit(sm->ssl_ctx, data->conn);
-		data->conn = NULL;
-		return -1;
-	}
-
-	/* TODO: make this configurable */
-	data->tls_out_limit = 1398;
-	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;
-	}
-	return 0;
-}
-
-
-void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
-{
-	tls_connection_deinit(sm->ssl_ctx, data->conn);
-	eap_server_tls_free_in_buf(data);
-	wpabuf_free(data->tls_out);
-	data->tls_out = NULL;
-}
-
-
-u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-			       char *label, size_t len)
-{
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-
-	out = os_malloc(len);
-	if (out == NULL)
-		return NULL;
-
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-	    0)
-		return out;
-
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
-		goto fail;
-
-	os_free(rnd);
-	return out;
-
-fail:
-	os_free(out);
-	os_free(rnd);
-	return NULL;
-}
-
-
-struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
-					 int eap_type, int version, u8 id)
-{
-	struct wpabuf *req;
-	u8 flags;
-	size_t send_len, plen;
-
-	wpa_printf(MSG_DEBUG, "SSL: Generating Request");
-	if (data->tls_out == NULL) {
-		wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
-		return NULL;
-	}
-
-	flags = version;
-	send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
-	if (1 + send_len > data->tls_out_limit) {
-		send_len = data->tls_out_limit - 1;
-		flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
-		if (data->tls_out_pos == 0) {
-			flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
-			send_len -= 4;
-		}
-	}
-
-	plen = 1 + send_len;
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
-		plen += 4;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL)
-		return NULL;
-
-	wpabuf_put_u8(req, flags); /* Flags */
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
-		wpabuf_put_be32(req, wpabuf_len(data->tls_out));
-
-	wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
-			send_len);
-	data->tls_out_pos += send_len;
-
-	if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
-		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->tls_out);
-		data->tls_out = NULL;
-		data->tls_out_pos = 0;
-		data->state = MSG;
-	} else {
-		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->tls_out) -
-			   data->tls_out_pos);
-		data->state = WAIT_FRAG_ACK;
-	}
-
-	return req;
-}
-
-
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
-			    id);
-	if (req == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
-	wpabuf_put_u8(req, version); /* Flags */
-	return req;
-}
-
-
-static int eap_server_tls_process_cont(struct eap_ssl_data *data,
-				       const u8 *buf, size_t len)
-{
-	/* Process continuation of a pending message */
-	if (len > wpabuf_tailroom(data->tls_in)) {
-		wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
-		return -1;
-	}
-
-	wpabuf_put_data(data->tls_in, buf, len);
-	wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
-		   "bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->tls_in));
-
-	return 0;
-}
-
-
-static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
-					   u8 flags, u32 message_length,
-					   const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
-		wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
-			   "fragmented packet");
-		return -1;
-	}
-
-	if (data->tls_in == NULL) {
-		/* First fragment of the message */
-
-		/* Limit length to avoid rogue peers from causing large
-		 * memory allocations. */
-		if (message_length > 65536) {
-			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
-				   " over 64 kB)");
-			return -1;
-		}
-
-		data->tls_in = wpabuf_alloc(message_length);
-		if (data->tls_in == NULL) {
-			wpa_printf(MSG_DEBUG, "SSL: No memory for message");
-			return -1;
-		}
-		wpabuf_put_data(data->tls_in, buf, len);
-		wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->tls_in));
-	}
-
-	return 0;
-}
-
-
-int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
-{
-	if (data->tls_out) {
-		/* This should not happen.. */
-		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
-			   "processing new message");
-		wpabuf_free(data->tls_out);
-		WPA_ASSERT(data->tls_out == NULL);
-	}
-
-	data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
-							data->conn,
-							data->tls_in, NULL);
-	if (data->tls_out == NULL) {
-		wpa_printf(MSG_INFO, "SSL: TLS processing failed");
-		return -1;
-	}
-	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
-		/* TLS processing has failed - return error */
-		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
-			   "report error");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
-				     const u8 **pos, size_t *left)
-{
-	unsigned int tls_msg_len = 0;
-	const u8 *end = *pos + *left;
-
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
-		if (*left < 4) {
-			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
-				   "length");
-			return -1;
-		}
-		tls_msg_len = WPA_GET_BE32(*pos);
-		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
-			   tls_msg_len);
-		*pos += 4;
-		*left -= 4;
-	}
-
-	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
-		   "Message Length %u", flags, tls_msg_len);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (*left != 0) {
-			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
-				   "WAIT_FRAG_ACK state");
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
-		return 1;
-	}
-
-	if (data->tls_in &&
-	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
-		return -1;
-		
-	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
-		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
-						    *pos, end - *pos) < 0)
-			return -1;
-
-		data->state = FRAG_ACK;
-		return 1;
-	}
-
-	if (data->state == FRAG_ACK) {
-		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
-		data->state = MSG;
-	}
-
-	if (data->tls_in == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
-		data->tls_in = &data->tmpbuf;
-	}
-
-	return 0;
-}
-
-
-static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
-{
-	if (data->tls_in != &data->tmpbuf)
-		wpabuf_free(data->tls_in);
-	data->tls_in = NULL;
-}
-
-
-struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
-				       struct eap_ssl_data *data,
-				       const struct wpabuf *plain)
-{
-	struct wpabuf *buf;
-
-	buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
-				     plain);
-	if (buf == NULL) {
-		wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
-		return NULL;
-	}
-
-	return buf;
-}
-
-
-int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
-			   struct wpabuf *respData, void *priv, int eap_type,
-			   int (*proc_version)(struct eap_sm *sm, void *priv,
-					       int peer_version),
-			   void (*proc_msg)(struct eap_sm *sm, void *priv,
-					    const struct wpabuf *respData))
-{
-	const u8 *pos;
-	u8 flags;
-	size_t left;
-	int ret, res = 0;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
-	if (pos == NULL || left < 1)
-		return 0; /* Should not happen - frame already validated */
-	flags = *pos++;
-	left--;
-	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
-		   (unsigned long) wpabuf_len(respData), flags);
-
-	if (proc_version &&
-	    proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
-		return -1;
-
-	ret = eap_server_tls_reassemble(data, flags, &pos, &left);
-	if (ret < 0) {
-		res = -1;
-		goto done;
-	} else if (ret == 1)
-		return 0;
-
-	if (proc_msg)
-		proc_msg(sm, priv, respData);
-
-	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
-		wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
-			   "TLS processing");
-		res = -1;
-	}
-
-done:
-	eap_server_tls_free_in_buf(data);
-
-	return res;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_tls_common.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tls_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,425 @@
+/*
+ * EAP-TLS/PEAP/TTLS/FAST server common functions
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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"
+
+
+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
+
+
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+				  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);
+	return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+			     identifier);
+}
+
+
+int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+			    int verify_peer)
+{
+	data->eap = sm;
+	data->phase2 = sm->init_phase2;
+
+	data->conn = tls_connection_init(sm->ssl_ctx);
+	if (data->conn == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
+			   "connection");
+		return -1;
+	}
+
+	if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
+		wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
+			   "of TLS peer certificate");
+		tls_connection_deinit(sm->ssl_ctx, data->conn);
+		data->conn = NULL;
+		return -1;
+	}
+
+	data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
+	if (data->phase2) {
+		/* Limit the fragment size in the inner TLS authentication
+		 * since the outer authentication with EAP-PEAP does not yet
+		 * support fragmentation */
+		if (data->tls_out_limit > 100)
+			data->tls_out_limit -= 100;
+	}
+	return 0;
+}
+
+
+void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+	tls_connection_deinit(sm->ssl_ctx, data->conn);
+	eap_server_tls_free_in_buf(data);
+	wpabuf_free(data->tls_out);
+	data->tls_out = NULL;
+}
+
+
+u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+			       char *label, size_t len)
+{
+	struct tls_keys keys;
+	u8 *rnd = NULL, *out;
+
+	out = os_malloc(len);
+	if (out == NULL)
+		return NULL;
+
+	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
+	    0)
+		return out;
+
+	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+		goto fail;
+
+	if (keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.master_key == NULL)
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+	os_memcpy(rnd, keys.client_random, keys.client_random_len);
+	os_memcpy(rnd + keys.client_random_len, keys.server_random,
+		  keys.server_random_len);
+
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
+		goto fail;
+
+	os_free(rnd);
+	return out;
+
+fail:
+	os_free(out);
+	os_free(rnd);
+	return NULL;
+}
+
+
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+					 int eap_type, int version, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	wpa_printf(MSG_DEBUG, "SSL: Generating Request");
+	if (data->tls_out == NULL) {
+		wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
+		return NULL;
+	}
+
+	flags = version;
+	send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
+	if (1 + send_len > data->tls_out_limit) {
+		send_len = data->tls_out_limit - 1;
+		flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+		if (data->tls_out_pos == 0) {
+			flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+
+	req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(req, wpabuf_len(data->tls_out));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
+			send_len);
+	data->tls_out_pos += send_len;
+
+	if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
+		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->tls_out);
+		data->tls_out = NULL;
+		data->tls_out_pos = 0;
+		data->state = MSG;
+	} else {
+		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->tls_out) -
+			   data->tls_out_pos);
+		data->state = WAIT_FRAG_ACK;
+	}
+
+	return req;
+}
+
+
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
+{
+	struct wpabuf *req;
+
+	req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+	wpabuf_put_u8(req, version); /* Flags */
+	return req;
+}
+
+
+static int eap_server_tls_process_cont(struct eap_ssl_data *data,
+				       const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->tls_in)) {
+		wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
+		return -1;
+	}
+
+	wpabuf_put_data(data->tls_in, buf, len);
+	wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->tls_in));
+
+	return 0;
+}
+
+
+static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
+					   u8 flags, u32 message_length,
+					   const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
+			   "fragmented packet");
+		return -1;
+	}
+
+	if (data->tls_in == NULL) {
+		/* First fragment of the message */
+
+		/* Limit length to avoid rogue peers from causing large
+		 * memory allocations. */
+		if (message_length > 65536) {
+			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
+				   " over 64 kB)");
+			return -1;
+		}
+
+		if (len > message_length) {
+			wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
+				   "first fragment of frame (TLS Message "
+				   "Length %d bytes)",
+				   (int) len, (int) message_length);
+			return -1;
+		}
+
+		data->tls_in = wpabuf_alloc(message_length);
+		if (data->tls_in == NULL) {
+			wpa_printf(MSG_DEBUG, "SSL: No memory for message");
+			return -1;
+		}
+		wpabuf_put_data(data->tls_in, buf, len);
+		wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->tls_in));
+	}
+
+	return 0;
+}
+
+
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+	if (data->tls_out) {
+		/* This should not happen.. */
+		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
+			   "processing new message");
+		wpabuf_free(data->tls_out);
+		WPA_ASSERT(data->tls_out == NULL);
+	}
+
+	data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
+							data->conn,
+							data->tls_in, NULL);
+	if (data->tls_out == NULL) {
+		wpa_printf(MSG_INFO, "SSL: TLS processing failed");
+		return -1;
+	}
+	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+		/* TLS processing has failed - return error */
+		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
+			   "report error");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
+				     const u8 **pos, size_t *left)
+{
+	unsigned int tls_msg_len = 0;
+	const u8 *end = *pos + *left;
+
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+		if (*left < 4) {
+			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+				   "length");
+			return -1;
+		}
+		tls_msg_len = WPA_GET_BE32(*pos);
+		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
+			   tls_msg_len);
+		*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);
+			return -1;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, tls_msg_len);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (*left != 0) {
+			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
+				   "WAIT_FRAG_ACK state");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
+		return 1;
+	}
+
+	if (data->tls_in &&
+	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
+		return -1;
+		
+	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
+		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
+						    *pos, end - *pos) < 0)
+			return -1;
+
+		data->state = FRAG_ACK;
+		return 1;
+	}
+
+	if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
+		data->state = MSG;
+	}
+
+	if (data->tls_in == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
+		data->tls_in = &data->tmpbuf;
+	}
+
+	return 0;
+}
+
+
+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
+{
+	if (data->tls_in != &data->tmpbuf)
+		wpabuf_free(data->tls_in);
+	data->tls_in = NULL;
+}
+
+
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+				       struct eap_ssl_data *data,
+				       const struct wpabuf *plain)
+{
+	struct wpabuf *buf;
+
+	buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
+				     plain);
+	if (buf == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
+		return NULL;
+	}
+
+	return buf;
+}
+
+
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+			   struct wpabuf *respData, void *priv, int eap_type,
+			   int (*proc_version)(struct eap_sm *sm, void *priv,
+					       int peer_version),
+			   void (*proc_msg)(struct eap_sm *sm, void *priv,
+					    const struct wpabuf *respData))
+{
+	const u8 *pos;
+	u8 flags;
+	size_t left;
+	int ret, res = 0;
+
+	if (eap_type == EAP_UNAUTH_TLS_TYPE)
+		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+				       EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+				       &left);
+	else
+		pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
+				       &left);
+	if (pos == NULL || left < 1)
+		return 0; /* Should not happen - frame already validated */
+	flags = *pos++;
+	left--;
+	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
+		   (unsigned long) wpabuf_len(respData), flags);
+
+	if (proc_version &&
+	    proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
+		return -1;
+
+	ret = eap_server_tls_reassemble(data, flags, &pos, &left);
+	if (ret < 0) {
+		res = -1;
+		goto done;
+	} else if (ret == 1)
+		return 0;
+
+	if (proc_msg)
+		proc_msg(sm, priv, respData);
+
+	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+		wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
+			   "TLS processing");
+		res = -1;
+	}
+
+done:
+	eap_server_tls_free_in_buf(data);
+
+	return res;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_tnc.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_tnc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tnc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,581 +0,0 @@
-/*
- * EAP server method: EAP-TNC (Trusted Network Connect)
- * Copyright (c) 2007-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "eap_i.h"
-#include "tncs.h"
-
-
-struct eap_tnc_data {
-	enum eap_tnc_state {
-		START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE,
-		FAIL
-	} state;
-	enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
-	struct tncs_data *tncs;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	size_t out_used;
-	size_t fragment_size;
-	unsigned int was_done:1;
-	unsigned int was_fail:1;
-};
-
-
-/* EAP-TNC Flags */
-#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
-#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
-#define EAP_TNC_FLAGS_START 0x20
-#define EAP_TNC_VERSION_MASK 0x07
-
-#define EAP_TNC_VERSION 1
-
-
-static const char * eap_tnc_state_txt(enum eap_tnc_state state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case CONTINUE:
-		return "CONTINUE";
-	case RECOMMENDATION:
-		return "RECOMMENDATION";
-	case FRAG_ACK:
-		return "FRAG_ACK";
-	case WAIT_FRAG_ACK:
-		return "WAIT_FRAG_ACK";
-	case DONE:
-		return "DONE";
-	case FAIL:
-		return "FAIL";
-	}
-	return "??";
-}
-
-
-static void eap_tnc_set_state(struct eap_tnc_data *data,
-			      enum eap_tnc_state new_state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s",
-		   eap_tnc_state_txt(data->state),
-		   eap_tnc_state_txt(new_state));
-	data->state = new_state;
-}
-
-
-static void * eap_tnc_init(struct eap_sm *sm)
-{
-	struct eap_tnc_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	eap_tnc_set_state(data, START);
-	data->tncs = tncs_init();
-	if (data->tncs == NULL) {
-		os_free(data);
-		return NULL;
-	}
-
-	data->fragment_size = 1300;
-
-	return data;
-}
-
-
-static void eap_tnc_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_tnc_data *data = priv;
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	tncs_deinit(data->tncs);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
-					   struct eap_tnc_data *data, u8 id)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
-			    id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
-			   "request");
-		eap_tnc_set_state(data, FAIL);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
-
-	eap_tnc_set_state(data, CONTINUE);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
-				     struct eap_tnc_data *data)
-{
-	struct wpabuf *req;
-	u8 *rpos, *rpos1;
-	size_t rlen;
-	char *start_buf, *end_buf;
-	size_t start_len, end_len;
-	size_t imv_len;
-
-	imv_len = tncs_total_send_len(data->tncs);
-
-	start_buf = tncs_if_tnccs_start(data->tncs);
-	if (start_buf == NULL)
-		return NULL;
-	start_len = os_strlen(start_buf);
-	end_buf = tncs_if_tnccs_end();
-	if (end_buf == NULL) {
-		os_free(start_buf);
-		return NULL;
-	}
-	end_len = os_strlen(end_buf);
-
-	rlen = start_len + imv_len + end_len;
-	req = wpabuf_alloc(rlen);
-	if (req == NULL) {
-		os_free(start_buf);
-		os_free(end_buf);
-		return NULL;
-	}
-
-	wpabuf_put_data(req, start_buf, start_len);
-	os_free(start_buf);
-
-	rpos1 = wpabuf_put(req, 0);
-	rpos = tncs_copy_send_buf(data->tncs, rpos1);
-	wpabuf_put(req, rpos - rpos1);
-
-	wpabuf_put_data(req, end_buf, end_len);
-	os_free(end_buf);
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request",
-			  wpabuf_head(req), wpabuf_len(req));
-
-	return req;
-}
-
-
-static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
-						    struct eap_tnc_data *data)
-{
-	switch (data->recommendation) {
-	case ALLOW:
-		eap_tnc_set_state(data, DONE);
-		break;
-	case ISOLATE:
-		eap_tnc_set_state(data, FAIL);
-		/* TODO: support assignment to a different VLAN */
-		break;
-	case NO_ACCESS:
-		eap_tnc_set_state(data, FAIL);
-		break;
-	case NO_RECOMMENDATION:
-		eap_tnc_set_state(data, DONE);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
-		return NULL;
-	}
-
-	return eap_tnc_build(sm, data);
-}
-
-
-static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
-{
-	struct wpabuf *msg;
-
-	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
-	if (msg == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
-			   "for fragment ack");
-		return NULL;
-	}
-	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
-
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
-
-	return msg;
-}
-
-
-static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id)
-{
-	struct wpabuf *req;
-	u8 flags;
-	size_t send_len, plen;
-
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request");
-
-	flags = EAP_TNC_VERSION;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (1 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 1;
-		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
-		if (data->out_used == 0) {
-			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
-			send_len -= 4;
-		}
-	}
-
-	plen = 1 + send_len;
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
-		plen += 4;
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL)
-		return NULL;
-
-	wpabuf_put_u8(req, flags); /* Flags */
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
-		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-		if (data->was_fail)
-			eap_tnc_set_state(data, FAIL);
-		else if (data->was_done)
-			eap_tnc_set_state(data, DONE);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		if (data->state == FAIL)
-			data->was_fail = 1;
-		else if (data->state == DONE)
-			data->was_done = 1;
-		eap_tnc_set_state(data, WAIT_FRAG_ACK);
-	}
-
-	return req;
-}
-
-
-static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_tnc_data *data = priv;
-
-	switch (data->state) {
-	case START:
-		tncs_init_connection(data->tncs);
-		return eap_tnc_build_start(sm, data, id);
-	case CONTINUE:
-		if (data->out_buf == NULL) {
-			data->out_buf = eap_tnc_build(sm, data);
-			if (data->out_buf == NULL) {
-				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
-					   "generate message");
-				return NULL;
-			}
-			data->out_used = 0;
-		}
-		return eap_tnc_build_msg(data, id);
-	case RECOMMENDATION:
-		if (data->out_buf == NULL) {
-			data->out_buf = eap_tnc_build_recommendation(sm, data);
-			if (data->out_buf == NULL) {
-				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
-					   "generate recommendation message");
-				return NULL;
-			}
-			data->out_used = 0;
-		}
-		return eap_tnc_build_msg(data, id);
-	case WAIT_FRAG_ACK:
-		return eap_tnc_build_msg(data, id);
-	case FRAG_ACK:
-		return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST);
-	case DONE:
-	case FAIL:
-		return NULL;
-	}
-
-	return NULL;
-}
-
-
-static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_tnc_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
-			       &len);
-	if (pos == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
-		return TRUE;
-	}
-
-	if (len == 0 && data->state != WAIT_FRAG_ACK) {
-		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
-		return TRUE;
-	}
-
-	if (len == 0)
-		return FALSE; /* Fragment ACK does not include flags */
-
-	if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
-			   *pos & EAP_TNC_VERSION_MASK);
-		return TRUE;
-	}
-
-	if (*pos & EAP_TNC_FLAGS_START) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf)
-{
-	enum tncs_process_res res;
-
-	res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf),
-				    wpabuf_len(inbuf));
-	switch (res) {
-	case TNCCS_RECOMMENDATION_ALLOW:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
-		eap_tnc_set_state(data, RECOMMENDATION);
-		data->recommendation = ALLOW;
-		break;
-	case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
-		eap_tnc_set_state(data, RECOMMENDATION);
-		data->recommendation = NO_RECOMMENDATION;
-		break;
-	case TNCCS_RECOMMENDATION_ISOLATE:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
-		eap_tnc_set_state(data, RECOMMENDATION);
-		data->recommendation = ISOLATE;
-		break;
-	case TNCCS_RECOMMENDATION_NO_ACCESS:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
-		eap_tnc_set_state(data, RECOMMENDATION);
-		data->recommendation = NO_ACCESS;
-		break;
-	case TNCCS_PROCESS_ERROR:
-		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
-		eap_tnc_set_state(data, FAIL);
-		break;
-	default:
-		break;
-	}
-}
-
-
-static int eap_tnc_process_cont(struct eap_tnc_data *data,
-				const u8 *buf, size_t len)
-{
-	/* Process continuation of a pending message */
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
-		eap_tnc_set_state(data, FAIL);
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu "
-		   "bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static int eap_tnc_process_fragment(struct eap_tnc_data *data,
-				    u8 flags, u32 message_length,
-				    const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
-			   "fragmented packet");
-		return -1;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
-				   "message");
-			return -1;
-		}
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
-			   "fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return 0;
-}
-
-
-static void eap_tnc_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_tnc_data *data = priv;
-	const u8 *pos, *end;
-	size_t len;
-	u8 flags;
-	u32 message_length = 0;
-	struct wpabuf tmpbuf;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
-	if (pos == NULL)
-		return; /* Should not happen; message already verified */
-
-	end = pos + len;
-
-	if (len == 1 && (data->state == DONE || data->state == FAIL)) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
-			   "message");
-		return;
-	}
-
-	if (len == 0) {
-		/* fragment ack */
-		flags = 0;
-	} else
-		flags = *pos++;
-
-	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
-			eap_tnc_set_state(data, FAIL);
-			return;
-		}
-		message_length = WPA_GET_BE32(pos);
-		pos += 4;
-
-		if (message_length < (u32) (end - pos)) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
-				   "Length (%d; %ld remaining in this msg)",
-				   message_length, (long) (end - pos));
-			eap_tnc_set_state(data, FAIL);
-			return;
-		}
-	}
-	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
-		   "Message Length %u", flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (len > 1) {
-			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
-				   "in WAIT_FRAG_ACK state");
-			eap_tnc_set_state(data, FAIL);
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
-		eap_tnc_set_state(data, CONTINUE);
-		return;
-	}
-
-	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
-		eap_tnc_set_state(data, FAIL);
-		return;
-	}
-		
-	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
-		if (eap_tnc_process_fragment(data, flags, message_length,
-					     pos, end - pos) < 0)
-			eap_tnc_set_state(data, FAIL);
-		else
-			eap_tnc_set_state(data, FRAG_ACK);
-		return;
-	} else if (data->state == FRAG_ACK) {
-		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
-		eap_tnc_set_state(data, CONTINUE);
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
-			  wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
-	tncs_process(data, data->in_buf);
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-}
-
-
-static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_tnc_data *data = priv;
-	return data->state == DONE || data->state == FAIL;
-}
-
-
-static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_tnc_data *data = priv;
-	return data->state == DONE;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_tnc_init;
-	eap->reset = eap_tnc_reset;
-	eap->buildReq = eap_tnc_buildReq;
-	eap->check = eap_tnc_check;
-	eap->process = eap_tnc_process;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_tnc.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_tnc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_tnc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_tnc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,575 @@
+/*
+ * EAP server method: EAP-TNC (Trusted Network Connect)
+ * Copyright (c) 2007-2010, Jouni Malinen <j at 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 "eap_i.h"
+#include "tncs.h"
+
+
+struct eap_tnc_data {
+	enum eap_tnc_state {
+		START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE,
+		FAIL
+	} state;
+	enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
+	struct tncs_data *tncs;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
+	unsigned int was_done:1;
+	unsigned int was_fail:1;
+};
+
+
+/* EAP-TNC Flags */
+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TNC_FLAGS_START 0x20
+#define EAP_TNC_VERSION_MASK 0x07
+
+#define EAP_TNC_VERSION 1
+
+
+static const char * eap_tnc_state_txt(enum eap_tnc_state state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case CONTINUE:
+		return "CONTINUE";
+	case RECOMMENDATION:
+		return "RECOMMENDATION";
+	case FRAG_ACK:
+		return "FRAG_ACK";
+	case WAIT_FRAG_ACK:
+		return "WAIT_FRAG_ACK";
+	case DONE:
+		return "DONE";
+	case FAIL:
+		return "FAIL";
+	}
+	return "??";
+}
+
+
+static void eap_tnc_set_state(struct eap_tnc_data *data,
+			      enum eap_tnc_state new_state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s",
+		   eap_tnc_state_txt(data->state),
+		   eap_tnc_state_txt(new_state));
+	data->state = new_state;
+}
+
+
+static void * eap_tnc_init(struct eap_sm *sm)
+{
+	struct eap_tnc_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	eap_tnc_set_state(data, START);
+	data->tncs = tncs_init();
+	if (data->tncs == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	data->fragment_size = sm->fragment_size > 100 ?
+		sm->fragment_size - 98 : 1300;
+
+	return data;
+}
+
+
+static void eap_tnc_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	tncs_deinit(data->tncs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
+					   struct eap_tnc_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
+			    id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
+			   "request");
+		eap_tnc_set_state(data, FAIL);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
+
+	eap_tnc_set_state(data, CONTINUE);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
+				     struct eap_tnc_data *data)
+{
+	struct wpabuf *req;
+	u8 *rpos, *rpos1;
+	size_t rlen;
+	char *start_buf, *end_buf;
+	size_t start_len, end_len;
+	size_t imv_len;
+
+	imv_len = tncs_total_send_len(data->tncs);
+
+	start_buf = tncs_if_tnccs_start(data->tncs);
+	if (start_buf == NULL)
+		return NULL;
+	start_len = os_strlen(start_buf);
+	end_buf = tncs_if_tnccs_end();
+	if (end_buf == NULL) {
+		os_free(start_buf);
+		return NULL;
+	}
+	end_len = os_strlen(end_buf);
+
+	rlen = start_len + imv_len + end_len;
+	req = wpabuf_alloc(rlen);
+	if (req == NULL) {
+		os_free(start_buf);
+		os_free(end_buf);
+		return NULL;
+	}
+
+	wpabuf_put_data(req, start_buf, start_len);
+	os_free(start_buf);
+
+	rpos1 = wpabuf_put(req, 0);
+	rpos = tncs_copy_send_buf(data->tncs, rpos1);
+	wpabuf_put(req, rpos - rpos1);
+
+	wpabuf_put_data(req, end_buf, end_len);
+	os_free(end_buf);
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request",
+			  wpabuf_head(req), wpabuf_len(req));
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
+						    struct eap_tnc_data *data)
+{
+	switch (data->recommendation) {
+	case ALLOW:
+		eap_tnc_set_state(data, DONE);
+		break;
+	case ISOLATE:
+		eap_tnc_set_state(data, FAIL);
+		/* TODO: support assignment to a different VLAN */
+		break;
+	case NO_ACCESS:
+		eap_tnc_set_state(data, FAIL);
+		break;
+	case NO_RECOMMENDATION:
+		eap_tnc_set_state(data, DONE);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
+		return NULL;
+	}
+
+	return eap_tnc_build(sm, data);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request");
+
+	flags = EAP_TNC_VERSION;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		if (data->was_fail)
+			eap_tnc_set_state(data, FAIL);
+		else if (data->was_done)
+			eap_tnc_set_state(data, DONE);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		if (data->state == FAIL)
+			data->was_fail = 1;
+		else if (data->state == DONE)
+			data->was_done = 1;
+		eap_tnc_set_state(data, WAIT_FRAG_ACK);
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_tnc_data *data = priv;
+
+	switch (data->state) {
+	case START:
+		tncs_init_connection(data->tncs);
+		return eap_tnc_build_start(sm, data, id);
+	case CONTINUE:
+		if (data->out_buf == NULL) {
+			data->out_buf = eap_tnc_build(sm, data);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+					   "generate message");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		return eap_tnc_build_msg(data, id);
+	case RECOMMENDATION:
+		if (data->out_buf == NULL) {
+			data->out_buf = eap_tnc_build_recommendation(sm, data);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+					   "generate recommendation message");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		return eap_tnc_build_msg(data, id);
+	case WAIT_FRAG_ACK:
+		return eap_tnc_build_msg(data, id);
+	case FRAG_ACK:
+		return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST);
+	case DONE:
+	case FAIL:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+
+static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_tnc_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
+			       &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
+		return TRUE;
+	}
+
+	if (len == 0 && data->state != WAIT_FRAG_ACK) {
+		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
+		return TRUE;
+	}
+
+	if (len == 0)
+		return FALSE; /* Fragment ACK does not include flags */
+
+	if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
+			   *pos & EAP_TNC_VERSION_MASK);
+		return TRUE;
+	}
+
+	if (*pos & EAP_TNC_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf)
+{
+	enum tncs_process_res res;
+
+	res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf),
+				    wpabuf_len(inbuf));
+	switch (res) {
+	case TNCCS_RECOMMENDATION_ALLOW:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
+		eap_tnc_set_state(data, RECOMMENDATION);
+		data->recommendation = ALLOW;
+		break;
+	case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
+		eap_tnc_set_state(data, RECOMMENDATION);
+		data->recommendation = NO_RECOMMENDATION;
+		break;
+	case TNCCS_RECOMMENDATION_ISOLATE:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
+		eap_tnc_set_state(data, RECOMMENDATION);
+		data->recommendation = ISOLATE;
+		break;
+	case TNCCS_RECOMMENDATION_NO_ACCESS:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
+		eap_tnc_set_state(data, RECOMMENDATION);
+		data->recommendation = NO_ACCESS;
+		break;
+	case TNCCS_PROCESS_ERROR:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
+		eap_tnc_set_state(data, FAIL);
+		break;
+	default:
+		break;
+	}
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+				const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+		eap_tnc_set_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_tnc_process_fragment(struct eap_tnc_data *data,
+				    u8 flags, u32 message_length,
+				    const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+			   "fragmented packet");
+		return -1;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+				   "message");
+			return -1;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return 0;
+}
+
+
+static void eap_tnc_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_tnc_data *data = priv;
+	const u8 *pos, *end;
+	size_t len;
+	u8 flags;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
+	if (pos == NULL)
+		return; /* Should not happen; message already verified */
+
+	end = pos + len;
+
+	if (len == 1 && (data->state == DONE || data->state == FAIL)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
+			   "message");
+		return;
+	}
+
+	if (len == 0) {
+		/* fragment ack */
+		flags = 0;
+	} else
+		flags = *pos++;
+
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+			eap_tnc_set_state(data, FAIL);
+			return;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			eap_tnc_set_state(data, FAIL);
+			return;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (len > 1) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
+				   "in WAIT_FRAG_ACK state");
+			eap_tnc_set_state(data, FAIL);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+		eap_tnc_set_state(data, CONTINUE);
+		return;
+	}
+
+	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+		eap_tnc_set_state(data, FAIL);
+		return;
+	}
+		
+	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+		if (eap_tnc_process_fragment(data, flags, message_length,
+					     pos, end - pos) < 0)
+			eap_tnc_set_state(data, FAIL);
+		else
+			eap_tnc_set_state(data, FRAG_ACK);
+		return;
+	} else if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+		eap_tnc_set_state(data, CONTINUE);
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
+			  wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
+	tncs_process(data, data->in_buf);
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	return data->state == DONE || data->state == FAIL;
+}
+
+
+static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	return data->state == DONE;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tnc_init;
+	eap->reset = eap_tnc_reset;
+	eap->buildReq = eap_tnc_buildReq;
+	eap->check = eap_tnc_check;
+	eap->process = eap_tnc_process;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_ttls.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_ttls.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_ttls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1430 +0,0 @@
-/*
- * hostapd / EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/ms_funcs.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "eap_server/eap_i.h"
-#include "eap_server/eap_tls_common.h"
-#include "eap_common/chap.h"
-#include "eap_common/eap_ttls.h"
-
-
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-
-
-static void eap_ttls_reset(struct eap_sm *sm, void *priv);
-
-
-struct eap_ttls_data {
-	struct eap_ssl_data ssl;
-	enum {
-		START, PHASE1, PHASE2_START, PHASE2_METHOD,
-		PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
-	} state;
-
-	int ttls_version;
-	int force_version;
-	const struct eap_method *phase2_method;
-	void *phase2_priv;
-	int mschapv2_resp_ok;
-	u8 mschapv2_auth_response[20];
-	u8 mschapv2_ident;
-	int tls_ia_configured;
-	struct wpabuf *pending_phase2_eap_resp;
-	int tnc_started;
-};
-
-
-static const char * eap_ttls_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "START";
-	case PHASE1:
-		return "PHASE1";
-	case PHASE2_START:
-		return "PHASE2_START";
-	case PHASE2_METHOD:
-		return "PHASE2_METHOD";
-	case PHASE2_MSCHAPV2_RESP:
-		return "PHASE2_MSCHAPV2_RESP";
-	case PHASE_FINISHED:
-		return "PHASE_FINISHED";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "Unknown?!";
-	}
-}
-
-
-static void eap_ttls_state(struct eap_ttls_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s",
-		   eap_ttls_state_txt(data->state),
-		   eap_ttls_state_txt(state));
-	data->state = state;
-}
-
-
-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((flags << 24) | (hdrlen + len));
-
-	return avphdr + hdrlen;
-}
-
-
-static struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp,
-						u32 avp_code, int mandatory)
-{
-	struct wpabuf *avp;
-	u8 *pos;
-
-	avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4);
-	if (avp == NULL) {
-		wpabuf_free(resp);
-		return NULL;
-	}
-
-	pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory,
-			       wpabuf_len(resp));
-	os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp));
-	pos += wpabuf_len(resp);
-	AVP_PAD((const u8 *) wpabuf_head(avp), pos);
-	wpabuf_free(resp);
-	wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp));
-	return avp;
-}
-
-
-struct eap_ttls_avp {
-	 /* Note: eap is allocated memory; caller is responsible for freeing
-	  * it. All the other pointers are pointing to the packet data, i.e.,
-	  * they must not be freed separately. */
-	u8 *eap;
-	size_t eap_len;
-	u8 *user_name;
-	size_t user_name_len;
-	u8 *user_password;
-	size_t user_password_len;
-	u8 *chap_challenge;
-	size_t chap_challenge_len;
-	u8 *chap_password;
-	size_t chap_password_len;
-	u8 *mschap_challenge;
-	size_t mschap_challenge_len;
-	u8 *mschap_response;
-	size_t mschap_response_len;
-	u8 *mschap2_response;
-	size_t mschap2_response_len;
-};
-
-
-static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse)
-{
-	struct ttls_avp *avp;
-	u8 *pos;
-	int left;
-
-	pos = wpabuf_mhead(buf);
-	left = wpabuf_len(buf);
-	os_memset(parse, 0, sizeof(*parse));
-
-	while (left > 0) {
-		u32 avp_code, avp_length, vendor_id = 0;
-		u8 avp_flags, *dpos;
-		size_t pad, 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 ((int) avp_length > left) {
-			wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
-				   "(len=%d, left=%d) - dropped",
-				   (int) avp_length, left);
-			goto fail;
-		}
-		if (avp_length < sizeof(*avp)) {
-			wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length "
-				   "%d", avp_length);
-			goto fail;
-		}
-		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");
-				goto fail;
-			}
-			vendor_id = be_to_host32(* (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) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
-			if (parse->eap == NULL) {
-				parse->eap = os_malloc(dlen);
-				if (parse->eap == NULL) {
-					wpa_printf(MSG_WARNING, "EAP-TTLS: "
-						   "failed to allocate memory "
-						   "for Phase 2 EAP data");
-					goto fail;
-				}
-				os_memcpy(parse->eap, dpos, dlen);
-				parse->eap_len = dlen;
-			} else {
-				u8 *neweap = os_realloc(parse->eap,
-							parse->eap_len + dlen);
-				if (neweap == NULL) {
-					wpa_printf(MSG_WARNING, "EAP-TTLS: "
-						   "failed to allocate memory "
-						   "for Phase 2 EAP data");
-					goto fail;
-				}
-				os_memcpy(neweap + parse->eap_len, dpos, dlen);
-				parse->eap = neweap;
-				parse->eap_len += dlen;
-			}
-		} else if (vendor_id == 0 &&
-			   avp_code == RADIUS_ATTR_USER_NAME) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name",
-					  dpos, dlen);
-			parse->user_name = dpos;
-			parse->user_name_len = dlen;
-		} else if (vendor_id == 0 &&
-			   avp_code == RADIUS_ATTR_USER_PASSWORD) {
-			u8 *password = dpos;
-			size_t password_len = dlen;
-			while (password_len > 0 &&
-			       password[password_len - 1] == '\0') {
-				password_len--;
-			}
-			wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: "
-					      "User-Password (PAP)",
-					      password, password_len);
-			parse->user_password = password;
-			parse->user_password_len = password_len;
-		} else if (vendor_id == 0 &&
-			   avp_code == RADIUS_ATTR_CHAP_CHALLENGE) {
-			wpa_hexdump(MSG_DEBUG,
-				    "EAP-TTLS: CHAP-Challenge (CHAP)",
-				    dpos, dlen);
-			parse->chap_challenge = dpos;
-			parse->chap_challenge_len = dlen;
-		} else if (vendor_id == 0 &&
-			   avp_code == RADIUS_ATTR_CHAP_PASSWORD) {
-			wpa_hexdump(MSG_DEBUG,
-				    "EAP-TTLS: CHAP-Password (CHAP)",
-				    dpos, dlen);
-			parse->chap_password = dpos;
-			parse->chap_password_len = dlen;
-		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
-			   avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) {
-			wpa_hexdump(MSG_DEBUG,
-				    "EAP-TTLS: MS-CHAP-Challenge",
-				    dpos, dlen);
-			parse->mschap_challenge = dpos;
-			parse->mschap_challenge_len = dlen;
-		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
-			   avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) {
-			wpa_hexdump(MSG_DEBUG,
-				    "EAP-TTLS: MS-CHAP-Response (MSCHAP)",
-				    dpos, dlen);
-			parse->mschap_response = dpos;
-			parse->mschap_response_len = dlen;
-		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
-			   avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) {
-			wpa_hexdump(MSG_DEBUG,
-				    "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)",
-				    dpos, dlen);
-			parse->mschap2_response = dpos;
-			parse->mschap2_response_len = dlen;
-		} 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);
-			goto fail;
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported "
-				   "AVP code %d vendor_id %d",
-				   (int) avp_code, (int) vendor_id);
-		}
-
-		pad = (4 - (avp_length & 3)) & 3;
-		pos += avp_length + pad;
-		left -= avp_length + pad;
-	}
-
-	return 0;
-
-fail:
-	os_free(parse->eap);
-	parse->eap = NULL;
-	return -1;
-}
-
-
-static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
-					struct eap_ttls_data *data, size_t len)
-{
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-
-	if (data->ttls_version == 0) {
-		return eap_server_tls_derive_key(sm, &data->ssl,
-						 "ttls challenge", len);
-	}
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
-}
-
-
-static void * eap_ttls_init(struct eap_sm *sm)
-{
-	struct eap_ttls_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_version = -1;
-	if (sm->user && sm->user->force_version >= 0) {
-		data->force_version = sm->user->force_version;
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
-			   data->force_version);
-		data->ttls_version = data->force_version;
-	}
-	data->state = START;
-
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_version);
-			eap_ttls_reset(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
-	}
-
-	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-		eap_ttls_reset(sm, data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static void eap_ttls_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_ttls_data *data = priv;
-	if (data == NULL)
-		return;
-	if (data->phase2_priv && data->phase2_method)
-		data->phase2_method->reset(sm, data->phase2_priv);
-	eap_server_tls_ssl_deinit(sm, &data->ssl);
-	wpabuf_free(data->pending_phase2_eap_resp);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm,
-					    struct eap_ttls_data *data, u8 id)
-{	
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for"
-			   " request");
-		eap_ttls_state(data, FAILURE);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->ttls_version);
-
-	eap_ttls_state(data, PHASE1);
-
-	return req;
-}
-
-
-static struct wpabuf * eap_ttls_build_phase2_eap_req(
-	struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
-{
-	struct wpabuf *buf, *encr_req;
-
-
-	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
-	if (buf == NULL)
-		return NULL;
-
-	wpa_hexdump_buf_key(MSG_DEBUG,
-			    "EAP-TTLS/EAP: Encapsulate Phase 2 data", buf);
-
-	buf = eap_ttls_avp_encapsulate(buf, RADIUS_ATTR_EAP_MESSAGE, 1);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate "
-			   "packet");
-		return NULL;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated "
-			    "Phase 2 data", buf);
-
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
-	wpabuf_free(buf);
-
-	return encr_req;
-}
-
-
-static struct wpabuf * eap_ttls_build_phase2_mschapv2(
-	struct eap_sm *sm, struct eap_ttls_data *data)
-{
-	struct wpabuf *encr_req, msgbuf;
-	u8 *req, *pos, *end;
-	int ret;
-
-	pos = req = os_malloc(100);
-	if (req == NULL)
-		return NULL;
-	end = req + 100;
-
-	if (data->mschapv2_resp_ok) {
-		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS,
-				       RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
-		*pos++ = data->mschapv2_ident;
-		ret = os_snprintf((char *) pos, end - pos, "S=");
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex_uppercase(
-			(char *) pos, end - pos, data->mschapv2_auth_response,
-			sizeof(data->mschapv2_auth_response));
-	} else {
-		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR,
-				       RADIUS_VENDOR_ID_MICROSOFT, 1, 6);
-		os_memcpy(pos, "Failed", 6);
-		pos += 6;
-		AVP_PAD(req, pos);
-	}
-
-	wpabuf_set(&msgbuf, req, pos - req);
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
-			    "data", &msgbuf);
-
-	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
-	os_free(req);
-
-	return encr_req;
-}
-
-
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int final)
-{
-	return tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						     data->ssl.conn, final);
-}
-
-
-static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_ttls_data *data = priv;
-
-	if (data->ssl.state == FRAG_ACK) {
-		return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
-						data->ttls_version);
-	}
-
-	if (data->ssl.state == WAIT_FRAG_ACK) {
-		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
-						data->ttls_version, id);
-	}
-
-	switch (data->state) {
-	case START:
-		return eap_ttls_build_start(sm, data, id);
-	case PHASE1:
-		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
-				   "starting Phase2");
-			eap_ttls_state(data, PHASE2_START);
-		}
-		break;
-	case PHASE2_METHOD:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data,
-								  id);
-		break;
-	case PHASE2_MSCHAPV2_RESP:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
-		break;
-	case PHASE_FINISHED:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
-			   __func__, data->state);
-		return NULL;
-	}
-
-	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
-					data->ttls_version, id);
-}
-
-
-static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
-			      struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-
-
-static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
-					struct eap_ttls_data *data,
-					const u8 *user_password,
-					size_t user_password_len)
-{
-	if (!sm->user || !sm->user->password || sm->user->password_hash ||
-	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user "
-			   "password configured");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (sm->user->password_len != user_password_len ||
-	    os_memcmp(sm->user->password, user_password, user_password_len) !=
-	    0) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
-	eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-		       SUCCESS);
-}
-
-
-static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
-					 struct eap_ttls_data *data,
-					 const u8 *challenge,
-					 size_t challenge_len,
-					 const u8 *password,
-					 size_t password_len)
-{
-	u8 *chal, hash[CHAP_MD5_LEN];
-
-	if (challenge == NULL || password == NULL ||
-	    challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN ||
-	    password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes "
-			   "(challenge len %lu password len %lu)",
-			   (unsigned long) challenge_len,
-			   (unsigned long) password_len);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (!sm->user || !sm->user->password || sm->user->password_hash ||
-	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user "
-			   "password configured");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	chal = eap_ttls_implicit_challenge(sm, data,
-					   EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
-	if (chal == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate "
-			   "challenge from TLS data");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 ||
-	    password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch");
-		os_free(chal);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-	os_free(chal);
-
-	/* MD5(Ident + Password + Challenge) */
-	chap_md5(password[0], sm->user->password, sm->user->password_len,
-		 challenge, challenge_len, hash);
-
-	if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
-		eap_ttls_state(data, FAILURE);
-	}
-}
-
-
-static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
-					   struct eap_ttls_data *data,
-					   u8 *challenge, size_t challenge_len,
-					   u8 *response, size_t response_len)
-{
-	u8 *chal, nt_response[24];
-
-	if (challenge == NULL || response == NULL ||
-	    challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN ||
-	    response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP "
-			   "attributes (challenge len %lu response len %lu)",
-			   (unsigned long) challenge_len,
-			   (unsigned long) response_len);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (!sm->user || !sm->user->password ||
-	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password "
-			   "configured");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	chal = eap_ttls_implicit_challenge(sm, data,
-					   EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
-	if (chal == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate "
-			   "challenge from TLS data");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 ||
-	    response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch");
-		os_free(chal);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-	os_free(chal);
-
-	if (sm->user->password_hash)
-		challenge_response(challenge, sm->user->password, nt_response);
-	else
-		nt_challenge_response(challenge, sm->user->password,
-				      sm->user->password_len, nt_response);
-
-	if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
-			    response + 2 + 24, 24);
-		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected",
-			    nt_response, 24);
-		eap_ttls_state(data, FAILURE);
-	}
-}
-
-
-static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
-					     struct eap_ttls_data *data,
-					     u8 *challenge,
-					     size_t challenge_len,
-					     u8 *response, size_t response_len)
-{
-	u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge,
-		*auth_challenge;
-	size_t username_len, i;
-
-	if (challenge == NULL || response == NULL ||
-	    challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN ||
-	    response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 "
-			   "attributes (challenge len %lu response len %lu)",
-			   (unsigned long) challenge_len,
-			   (unsigned long) response_len);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (!sm->user || !sm->user->password ||
-	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password "
-			   "configured");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	/* MSCHAPv2 does not include optional domain name in the
-	 * challenge-response calculation, so remove domain prefix
-	 * (if present). */
-	username = sm->identity;
-	username_len = sm->identity_len;
-	for (i = 0; i < username_len; i++) {
-		if (username[i] == '\\') {
-			username_len -= i + 1;
-			username += i + 1;
-			break;
-		}
-	}
-
-	chal = eap_ttls_implicit_challenge(
-		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
-	if (chal == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate "
-			   "challenge from TLS data");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 ||
-	    response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch");
-		os_free(chal);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-	os_free(chal);
-
-	auth_challenge = challenge;
-	peer_challenge = response + 2;
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User",
-			  username, username_len);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge",
-		    auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
-	wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge",
-		    peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
-
-	if (sm->user->password_hash) {
-		generate_nt_response_pwhash(auth_challenge, peer_challenge,
-					    username, username_len,
-					    sm->user->password,
-					    nt_response);
-	} else {
-		generate_nt_response(auth_challenge, peer_challenge,
-				     username, username_len,
-				     sm->user->password,
-				     sm->user->password_len,
-				     nt_response);
-	}
-
-	rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
-	if (os_memcmp(nt_response, rx_resp, 24) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
-			   "NT-Response");
-		data->mschapv2_resp_ok = 1;
-		if (data->ttls_version > 0) {
-			const u8 *pw_hash;
-			u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
-			u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-			if (sm->user->password_hash)
-				pw_hash = sm->user->password;
-			else {
-				nt_password_hash(sm->user->password,
-						 sm->user->password_len,
-						 pw_hash_buf);
-				pw_hash = pw_hash_buf;
-			}
-			hash_nt_password_hash(pw_hash, pw_hash_hash);
-			get_master_key(pw_hash_hash, nt_response, master_key);
-			get_asymetric_start_key(master_key, session_key,
-						MSCHAPV2_KEY_LEN, 0, 0);
-			get_asymetric_start_key(master_key,
-						session_key + MSCHAPV2_KEY_LEN,
-						MSCHAPV2_KEY_LEN, 1, 0);
-			eap_ttls_ia_permute_inner_secret(sm, data,
-							 session_key,
-							 sizeof(session_key));
-		}
-
-		if (sm->user->password_hash) {
-			generate_authenticator_response_pwhash(
-				sm->user->password,
-				peer_challenge, auth_challenge,
-				username, username_len, nt_response,
-				data->mschapv2_auth_response);
-		} else {
-			generate_authenticator_response(
-				sm->user->password, sm->user->password_len,
-				peer_challenge, auth_challenge,
-				username, username_len, nt_response,
-				data->mschapv2_auth_response);
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid "
-			   "NT-Response");
-		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received",
-			    rx_resp, 24);
-		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected",
-			    nt_response, 24);
-		data->mschapv2_resp_ok = 0;
-	}
-	eap_ttls_state(data, PHASE2_MSCHAPV2_RESP);
-	data->mschapv2_ident = response[0];
-}
-
-
-static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
-				    struct eap_ttls_data *data,
-				    EapType eap_type)
-{
-	if (data->phase2_priv && data->phase2_method) {
-		data->phase2_method->reset(sm, data->phase2_priv);
-		data->phase2_method = NULL;
-		data->phase2_priv = NULL;
-	}
-	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
-							eap_type);
-	if (!data->phase2_method)
-		return -1;
-
-	sm->init_phase2 = 1;
-	data->phase2_priv = data->phase2_method->init(sm);
-	sm->init_phase2 = 0;
-	return data->phase2_priv == NULL ? -1 : 0;
-}
-
-
-static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
-						 struct eap_ttls_data *data,
-						 u8 *in_data, size_t in_len)
-{
-	u8 next_type = EAP_TYPE_NONE;
-	struct eap_hdr *hdr;
-	u8 *pos;
-	size_t left;
-	struct wpabuf buf;
-	const struct eap_method *m = data->phase2_method;
-	void *priv = data->phase2_priv;
-
-	if (priv == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not "
-			   "initialized?!", __func__);
-		return;
-	}
-
-	hdr = (struct eap_hdr *) in_data;
-	pos = (u8 *) (hdr + 1);
-
-	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
-		left = in_len - sizeof(*hdr);
-		wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; "
-			    "allowed types", pos + 1, left - 1);
-		eap_sm_process_nak(sm, pos + 1, left - 1);
-		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index].method !=
-		    EAP_TYPE_NONE) {
-			next_type = sm->user->methods[
-				sm->user_eap_method_index++].method;
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
-				   next_type);
-			if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
-				wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
-					   "initialize EAP type %d",
-					   next_type);
-				eap_ttls_state(data, FAILURE);
-				return;
-			}
-		} else {
-			eap_ttls_state(data, FAILURE);
-		}
-		return;
-	}
-
-	wpabuf_set(&buf, in_data, in_len);
-
-	if (m->check(sm, priv, &buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to "
-			   "ignore the packet");
-		return;
-	}
-
-	m->process(sm, priv, &buf);
-
-	if (sm->method_pending == METHOD_PENDING_WAIT) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in "
-			   "pending wait state - save decrypted response");
-		wpabuf_free(data->pending_phase2_eap_resp);
-		data->pending_phase2_eap_resp = wpabuf_dup(&buf);
-	}
-
-	if (!m->isDone(sm, priv))
-		return;
-
-	if (!m->isSuccess(sm, priv)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	switch (data->state) {
-	case PHASE2_START:
-		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
-			wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 "
-					  "Identity not found in the user "
-					  "database",
-					  sm->identity, sm->identity_len);
-			eap_ttls_state(data, FAILURE);
-			break;
-		}
-
-		eap_ttls_state(data, PHASE2_METHOD);
-		next_type = sm->user->methods[0].method;
-		sm->user_eap_method_index = 1;
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
-		if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
-				   "EAP type %d", next_type);
-			eap_ttls_state(data, FAILURE);
-		}
-		break;
-	case PHASE2_METHOD:
-		if (data->ttls_version > 0) {
-			if (m->getKey) {
-				u8 *key;
-				size_t key_len;
-				key = m->getKey(sm, priv, &key_len);
-				eap_ttls_ia_permute_inner_secret(sm, data,
-								 key, key_len);
-			}
-			eap_ttls_state(data, PHASE_FINISHED);
-		} else
-			eap_ttls_state(data, SUCCESS);
-		break;
-	case FAILURE:
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
-			   __func__, data->state);
-		break;
-	}
-}
-
-
-static void eap_ttls_process_phase2_eap(struct eap_sm *sm,
-					struct eap_ttls_data *data,
-					const u8 *eap, size_t eap_len)
-{
-	struct eap_hdr *hdr;
-	size_t len;
-
-	if (data->state == PHASE2_START) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
-		if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
-		{
-			wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
-				   "initialize EAP-Identity");
-			return;
-		}
-	}
-
-	if (eap_len < sizeof(*hdr)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP "
-			   "packet (len=%lu)", (unsigned long) eap_len);
-		return;
-	}
-
-	hdr = (struct eap_hdr *) eap;
-	len = be_to_host16(hdr->length);
-	wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d "
-		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
-		   (unsigned long) len);
-	if (len > eap_len) {
-		wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2"
-			   " EAP frame (hdr len=%lu, data len in AVP=%lu)",
-			   (unsigned long) len, (unsigned long) eap_len);
-		return;
-	}
-
-	switch (hdr->code) {
-	case EAP_CODE_RESPONSE:
-		eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr,
-						     len);
-		break;
-	default:
-		wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in "
-			   "Phase 2 EAP header", hdr->code);
-		break;
-	}
-}
-
-
-static void eap_ttls_process_phase2(struct eap_sm *sm,
-				    struct eap_ttls_data *data,
-				    struct wpabuf *in_buf)
-{
-	struct wpabuf *in_decrypted;
-	struct eap_ttls_avp parse;
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
-		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
-
-	if (data->pending_phase2_eap_resp) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response "
-			   "- skip decryption and use old data");
-		eap_ttls_process_phase2_eap(
-			sm, data, wpabuf_head(data->pending_phase2_eap_resp),
-			wpabuf_len(data->pending_phase2_eap_resp));
-		wpabuf_free(data->pending_phase2_eap_resp);
-		data->pending_phase2_eap_resp = NULL;
-		return;
-	}
-
-	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
-					      in_buf);
-	if (in_decrypted == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
-			   "data");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (data->state == PHASE_FINISHED) {
-		if (wpabuf_len(in_decrypted) == 0 &&
-		    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-							   data->ssl.conn)) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
-				   "received");
-			eap_ttls_state(data, SUCCESS);
-		} else {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
-				   "FinalPhaseFinished");
-			eap_ttls_state(data, FAILURE);
-		}
-
-		wpabuf_free(in_decrypted);
-		return;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
-			    in_decrypted);
-
-	if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs");
-		wpabuf_free(in_decrypted);
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	if (parse.user_name) {
-		os_free(sm->identity);
-		sm->identity = os_malloc(parse.user_name_len);
-		if (sm->identity) {
-			os_memcpy(sm->identity, parse.user_name,
-				  parse.user_name_len);
-			sm->identity_len = parse.user_name_len;
-		}
-		if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
-		    != 0) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not "
-				   "found in the user database");
-			eap_ttls_state(data, FAILURE);
-			goto done;
-		}
-	}
-
-#ifdef EAP_SERVER_TNC
-	if (data->tnc_started && parse.eap == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP "
-			   "response from peer");
-		eap_ttls_state(data, FAILURE);
-		goto done;
-	}
-#endif /* EAP_SERVER_TNC */
-
-	if (parse.eap) {
-		eap_ttls_process_phase2_eap(sm, data, parse.eap,
-					    parse.eap_len);
-	} else if (parse.user_password) {
-		eap_ttls_process_phase2_pap(sm, data, parse.user_password,
-					    parse.user_password_len);
-	} else if (parse.chap_password) {
-		eap_ttls_process_phase2_chap(sm, data,
-					     parse.chap_challenge,
-					     parse.chap_challenge_len,
-					     parse.chap_password,
-					     parse.chap_password_len);
-	} else if (parse.mschap_response) {
-		eap_ttls_process_phase2_mschap(sm, data,
-					       parse.mschap_challenge,
-					       parse.mschap_challenge_len,
-					       parse.mschap_response,
-					       parse.mschap_response_len);
-	} else if (parse.mschap2_response) {
-		eap_ttls_process_phase2_mschapv2(sm, data,
-						 parse.mschap_challenge,
-						 parse.mschap_challenge_len,
-						 parse.mschap2_response,
-						 parse.mschap2_response_len);
-	}
-
-done:
-	wpabuf_free(in_decrypted);
-	os_free(parse.eap);
-}
-
-
-static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
-{
-#ifdef EAP_SERVER_TNC
-	if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
-	if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
-		eap_ttls_state(data, FAILURE);
-		return;
-	}
-
-	data->tnc_started = 1;
-	eap_ttls_state(data, PHASE2_METHOD);
-#endif /* EAP_SERVER_TNC */
-}
-
-
-static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
-				    int peer_version)
-{
-	struct eap_ttls_data *data = priv;
-	if (peer_version < data->ttls_version) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
-			   "use version %d",
-			   peer_version, data->ttls_version, peer_version);
-		data->ttls_version = peer_version;
-	}
-
-	if (data->ttls_version > 0 && !data->tls_ia_configured) {
-		if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
-				   "TLS/IA");
-			return -1;
-		}
-		data->tls_ia_configured = 1;
-	}
-
-	return 0;
-}
-
-
-static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
-				 const struct wpabuf *respData)
-{
-	struct eap_ttls_data *data = priv;
-
-	switch (data->state) {
-	case PHASE1:
-		if (eap_server_tls_phase1(sm, &data->ssl) < 0)
-			eap_ttls_state(data, FAILURE);
-		break;
-	case PHASE2_START:
-	case PHASE2_METHOD:
-	case PHASE_FINISHED:
-		eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
-		eap_ttls_start_tnc(sm, data);
-		break;
-	case PHASE2_MSCHAPV2_RESP:
-		if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) ==
-		    0) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
-				   "acknowledged response");
-			eap_ttls_state(data, data->ttls_version > 0 ?
-				       PHASE_FINISHED : SUCCESS);
-		} else if (!data->mschapv2_resp_ok) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
-				   "acknowledged error");
-			eap_ttls_state(data, FAILURE);
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected "
-				   "frame from peer (payload len %lu, "
-				   "expected empty frame)",
-				   (unsigned long)
-				   wpabuf_len(data->ssl.tls_in));
-			eap_ttls_state(data, FAILURE);
-		}
-		eap_ttls_start_tnc(sm, data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s",
-			   data->state, __func__);
-		break;
-	}
-}
-
-
-static void eap_ttls_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	struct eap_ttls_data *data = priv;
-	if (eap_server_tls_process(sm, &data->ssl, respData, data,
-				   EAP_TYPE_TTLS, eap_ttls_process_version,
-				   eap_ttls_process_msg) < 0)
-		eap_ttls_state(data, FAILURE);
-}
-
-
-static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_ttls_data *data = priv;
-	return data->state == SUCCESS || data->state == FAILURE;
-}
-
-
-static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
-				   struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd, *key;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	key = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || key == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	return key;
-}
-
-
-static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_ttls_data *data = priv;
-	u8 *eapKeyData;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	if (data->ttls_version == 0) {
-		eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-						       "ttls keying material",
-						       EAP_TLS_KEY_LEN);
-	} else {
-		eapKeyData = eap_ttls_v1_derive_key(sm, data);
-	}
-
-	if (eapKeyData) {
-		*len = EAP_TLS_KEY_LEN;
-		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-				eapKeyData, EAP_TLS_KEY_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-	}
-
-	return eapKeyData;
-}
-
-
-static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_ttls_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_ttls_init;
-	eap->reset = eap_ttls_reset;
-	eap->buildReq = eap_ttls_buildReq;
-	eap->check = eap_ttls_check;
-	eap->process = eap_ttls_process;
-	eap->isDone = eap_ttls_isDone;
-	eap->getKey = eap_ttls_getKey;
-	eap->isSuccess = eap_ttls_isSuccess;
-
-	ret = eap_server_method_register(eap);
-	if (ret)
-		eap_server_method_free(eap);
-	return ret;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_ttls.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_ttls.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_ttls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_ttls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1193 @@
+/*
+ * hostapd / EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2011, Jouni Malinen <j at 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/ms_funcs.h"
+#include "crypto/sha1.h"
+#include "crypto/tls.h"
+#include "eap_server/eap_i.h"
+#include "eap_server/eap_tls_common.h"
+#include "eap_common/chap.h"
+#include "eap_common/eap_ttls.h"
+
+
+#define EAP_TTLS_VERSION 0
+
+
+static void eap_ttls_reset(struct eap_sm *sm, void *priv);
+
+
+struct eap_ttls_data {
+	struct eap_ssl_data ssl;
+	enum {
+		START, PHASE1, PHASE2_START, PHASE2_METHOD,
+		PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
+	} state;
+
+	int ttls_version;
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int mschapv2_resp_ok;
+	u8 mschapv2_auth_response[20];
+	u8 mschapv2_ident;
+	struct wpabuf *pending_phase2_eap_resp;
+	int tnc_started;
+};
+
+
+static const char * eap_ttls_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case PHASE1:
+		return "PHASE1";
+	case PHASE2_START:
+		return "PHASE2_START";
+	case PHASE2_METHOD:
+		return "PHASE2_METHOD";
+	case PHASE2_MSCHAPV2_RESP:
+		return "PHASE2_MSCHAPV2_RESP";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_ttls_state(struct eap_ttls_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s",
+		   eap_ttls_state_txt(data->state),
+		   eap_ttls_state_txt(state));
+	data->state = state;
+}
+
+
+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 struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp,
+						u32 avp_code, int mandatory)
+{
+	struct wpabuf *avp;
+	u8 *pos;
+
+	avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4);
+	if (avp == NULL) {
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory,
+			       wpabuf_len(resp));
+	os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp));
+	pos += wpabuf_len(resp);
+	AVP_PAD((const u8 *) wpabuf_head(avp), pos);
+	wpabuf_free(resp);
+	wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp));
+	return avp;
+}
+
+
+struct eap_ttls_avp {
+	 /* Note: eap is allocated memory; caller is responsible for freeing
+	  * it. All the other pointers are pointing to the packet data, i.e.,
+	  * they must not be freed separately. */
+	u8 *eap;
+	size_t eap_len;
+	u8 *user_name;
+	size_t user_name_len;
+	u8 *user_password;
+	size_t user_password_len;
+	u8 *chap_challenge;
+	size_t chap_challenge_len;
+	u8 *chap_password;
+	size_t chap_password_len;
+	u8 *mschap_challenge;
+	size_t mschap_challenge_len;
+	u8 *mschap_response;
+	size_t mschap_response_len;
+	u8 *mschap2_response;
+	size_t mschap2_response_len;
+};
+
+
+static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse)
+{
+	struct ttls_avp *avp;
+	u8 *pos;
+	int left;
+
+	pos = wpabuf_mhead(buf);
+	left = wpabuf_len(buf);
+	os_memset(parse, 0, sizeof(*parse));
+
+	while (left > 0) {
+		u32 avp_code, avp_length, vendor_id = 0;
+		u8 avp_flags, *dpos;
+		size_t pad, 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 ((int) avp_length > left) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
+				   "(len=%d, left=%d) - dropped",
+				   (int) avp_length, left);
+			goto fail;
+		}
+		if (avp_length < sizeof(*avp)) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length "
+				   "%d", avp_length);
+			goto fail;
+		}
+		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");
+				goto fail;
+			}
+			vendor_id = be_to_host32(* (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) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
+			if (parse->eap == NULL) {
+				parse->eap = os_malloc(dlen);
+				if (parse->eap == NULL) {
+					wpa_printf(MSG_WARNING, "EAP-TTLS: "
+						   "failed to allocate memory "
+						   "for Phase 2 EAP data");
+					goto fail;
+				}
+				os_memcpy(parse->eap, dpos, dlen);
+				parse->eap_len = dlen;
+			} else {
+				u8 *neweap = os_realloc(parse->eap,
+							parse->eap_len + dlen);
+				if (neweap == NULL) {
+					wpa_printf(MSG_WARNING, "EAP-TTLS: "
+						   "failed to allocate memory "
+						   "for Phase 2 EAP data");
+					goto fail;
+				}
+				os_memcpy(neweap + parse->eap_len, dpos, dlen);
+				parse->eap = neweap;
+				parse->eap_len += dlen;
+			}
+		} else if (vendor_id == 0 &&
+			   avp_code == RADIUS_ATTR_USER_NAME) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name",
+					  dpos, dlen);
+			parse->user_name = dpos;
+			parse->user_name_len = dlen;
+		} else if (vendor_id == 0 &&
+			   avp_code == RADIUS_ATTR_USER_PASSWORD) {
+			u8 *password = dpos;
+			size_t password_len = dlen;
+			while (password_len > 0 &&
+			       password[password_len - 1] == '\0') {
+				password_len--;
+			}
+			wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: "
+					      "User-Password (PAP)",
+					      password, password_len);
+			parse->user_password = password;
+			parse->user_password_len = password_len;
+		} else if (vendor_id == 0 &&
+			   avp_code == RADIUS_ATTR_CHAP_CHALLENGE) {
+			wpa_hexdump(MSG_DEBUG,
+				    "EAP-TTLS: CHAP-Challenge (CHAP)",
+				    dpos, dlen);
+			parse->chap_challenge = dpos;
+			parse->chap_challenge_len = dlen;
+		} else if (vendor_id == 0 &&
+			   avp_code == RADIUS_ATTR_CHAP_PASSWORD) {
+			wpa_hexdump(MSG_DEBUG,
+				    "EAP-TTLS: CHAP-Password (CHAP)",
+				    dpos, dlen);
+			parse->chap_password = dpos;
+			parse->chap_password_len = dlen;
+		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+			   avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) {
+			wpa_hexdump(MSG_DEBUG,
+				    "EAP-TTLS: MS-CHAP-Challenge",
+				    dpos, dlen);
+			parse->mschap_challenge = dpos;
+			parse->mschap_challenge_len = dlen;
+		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+			   avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) {
+			wpa_hexdump(MSG_DEBUG,
+				    "EAP-TTLS: MS-CHAP-Response (MSCHAP)",
+				    dpos, dlen);
+			parse->mschap_response = dpos;
+			parse->mschap_response_len = dlen;
+		} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+			   avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) {
+			wpa_hexdump(MSG_DEBUG,
+				    "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)",
+				    dpos, dlen);
+			parse->mschap2_response = dpos;
+			parse->mschap2_response_len = dlen;
+		} 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);
+			goto fail;
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported "
+				   "AVP code %d vendor_id %d",
+				   (int) avp_code, (int) vendor_id);
+		}
+
+		pad = (4 - (avp_length & 3)) & 3;
+		pos += avp_length + pad;
+		left -= avp_length + pad;
+	}
+
+	return 0;
+
+fail:
+	os_free(parse->eap);
+	parse->eap = NULL;
+	return -1;
+}
+
+
+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
+					struct eap_ttls_data *data, size_t len)
+{
+	return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
+					 len);
+}
+
+
+static void * eap_ttls_init(struct eap_sm *sm)
+{
+	struct eap_ttls_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->ttls_version = EAP_TTLS_VERSION;
+	data->state = START;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+		eap_ttls_reset(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_ttls_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->reset(sm, data->phase2_priv);
+	eap_server_tls_ssl_deinit(sm, &data->ssl);
+	wpabuf_free(data->pending_phase2_eap_resp);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm,
+					    struct eap_ttls_data *data, u8 id)
+{	
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for"
+			   " request");
+		eap_ttls_state(data, FAILURE);
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->ttls_version);
+
+	eap_ttls_state(data, PHASE1);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_ttls_build_phase2_eap_req(
+	struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
+{
+	struct wpabuf *buf, *encr_req;
+
+
+	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
+	if (buf == NULL)
+		return NULL;
+
+	wpa_hexdump_buf_key(MSG_DEBUG,
+			    "EAP-TTLS/EAP: Encapsulate Phase 2 data", buf);
+
+	buf = eap_ttls_avp_encapsulate(buf, RADIUS_ATTR_EAP_MESSAGE, 1);
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate "
+			   "packet");
+		return NULL;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated "
+			    "Phase 2 data", buf);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+
+
+static struct wpabuf * eap_ttls_build_phase2_mschapv2(
+	struct eap_sm *sm, struct eap_ttls_data *data)
+{
+	struct wpabuf *encr_req, msgbuf;
+	u8 *req, *pos, *end;
+	int ret;
+
+	pos = req = os_malloc(100);
+	if (req == NULL)
+		return NULL;
+	end = req + 100;
+
+	if (data->mschapv2_resp_ok) {
+		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS,
+				       RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
+		*pos++ = data->mschapv2_ident;
+		ret = os_snprintf((char *) pos, end - pos, "S=");
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex_uppercase(
+			(char *) pos, end - pos, data->mschapv2_auth_response,
+			sizeof(data->mschapv2_auth_response));
+	} else {
+		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR,
+				       RADIUS_VENDOR_ID_MICROSOFT, 1, 6);
+		os_memcpy(pos, "Failed", 6);
+		pos += 6;
+		AVP_PAD(req, pos);
+	}
+
+	wpabuf_set(&msgbuf, req, pos - req);
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
+			    "data", &msgbuf);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
+	os_free(req);
+
+	return encr_req;
+}
+
+
+static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_ttls_data *data = priv;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
+						data->ttls_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+						data->ttls_version, id);
+	}
+
+	switch (data->state) {
+	case START:
+		return eap_ttls_build_start(sm, data, id);
+	case PHASE1:
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
+				   "starting Phase2");
+			eap_ttls_state(data, PHASE2_START);
+		}
+		break;
+	case PHASE2_METHOD:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data,
+								  id);
+		break;
+	case PHASE2_MSCHAPV2_RESP:
+		wpabuf_free(data->ssl.tls_out);
+		data->ssl.tls_out_pos = 0;
+		data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
+			   __func__, data->state);
+		return NULL;
+	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+					data->ttls_version, id);
+}
+
+
+static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
+			      struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
+					struct eap_ttls_data *data,
+					const u8 *user_password,
+					size_t user_password_len)
+{
+	if (!sm->user || !sm->user->password || sm->user->password_hash ||
+	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user "
+			   "password configured");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (sm->user->password_len != user_password_len ||
+	    os_memcmp(sm->user->password, user_password, user_password_len) !=
+	    0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
+	eap_ttls_state(data, SUCCESS);
+}
+
+
+static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
+					 struct eap_ttls_data *data,
+					 const u8 *challenge,
+					 size_t challenge_len,
+					 const u8 *password,
+					 size_t password_len)
+{
+	u8 *chal, hash[CHAP_MD5_LEN];
+
+	if (challenge == NULL || password == NULL ||
+	    challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN ||
+	    password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes "
+			   "(challenge len %lu password len %lu)",
+			   (unsigned long) challenge_len,
+			   (unsigned long) password_len);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (!sm->user || !sm->user->password || sm->user->password_hash ||
+	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user "
+			   "password configured");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	chal = eap_ttls_implicit_challenge(sm, data,
+					   EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
+	if (chal == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate "
+			   "challenge from TLS data");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 ||
+	    password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch");
+		os_free(chal);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+	os_free(chal);
+
+	/* MD5(Ident + Password + Challenge) */
+	chap_md5(password[0], sm->user->password, sm->user->password_len,
+		 challenge, challenge_len, hash);
+
+	if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
+		eap_ttls_state(data, SUCCESS);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
+		eap_ttls_state(data, FAILURE);
+	}
+}
+
+
+static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
+					   struct eap_ttls_data *data,
+					   u8 *challenge, size_t challenge_len,
+					   u8 *response, size_t response_len)
+{
+	u8 *chal, nt_response[24];
+
+	if (challenge == NULL || response == NULL ||
+	    challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN ||
+	    response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP "
+			   "attributes (challenge len %lu response len %lu)",
+			   (unsigned long) challenge_len,
+			   (unsigned long) response_len);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (!sm->user || !sm->user->password ||
+	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password "
+			   "configured");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	chal = eap_ttls_implicit_challenge(sm, data,
+					   EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
+	if (chal == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate "
+			   "challenge from TLS data");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 ||
+	    response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch");
+		os_free(chal);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+	os_free(chal);
+
+	if (sm->user->password_hash)
+		challenge_response(challenge, sm->user->password, nt_response);
+	else
+		nt_challenge_response(challenge, sm->user->password,
+				      sm->user->password_len, nt_response);
+
+	if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
+		eap_ttls_state(data, SUCCESS);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
+			    response + 2 + 24, 24);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected",
+			    nt_response, 24);
+		eap_ttls_state(data, FAILURE);
+	}
+}
+
+
+static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
+					     struct eap_ttls_data *data,
+					     u8 *challenge,
+					     size_t challenge_len,
+					     u8 *response, size_t response_len)
+{
+	u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge,
+		*auth_challenge;
+	size_t username_len, i;
+
+	if (challenge == NULL || response == NULL ||
+	    challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN ||
+	    response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 "
+			   "attributes (challenge len %lu response len %lu)",
+			   (unsigned long) challenge_len,
+			   (unsigned long) response_len);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (!sm->user || !sm->user->password ||
+	    !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password "
+			   "configured");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (sm->identity == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user identity "
+			   "known");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	/* MSCHAPv2 does not include optional domain name in the
+	 * challenge-response calculation, so remove domain prefix
+	 * (if present). */
+	username = sm->identity;
+	username_len = sm->identity_len;
+	for (i = 0; i < username_len; i++) {
+		if (username[i] == '\\') {
+			username_len -= i + 1;
+			username += i + 1;
+			break;
+		}
+	}
+
+	chal = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
+	if (chal == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate "
+			   "challenge from TLS data");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 ||
+	    response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch");
+		os_free(chal);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+	os_free(chal);
+
+	auth_challenge = challenge;
+	peer_challenge = response + 2;
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User",
+			  username, username_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge",
+		    auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge",
+		    peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+
+	if (sm->user->password_hash) {
+		generate_nt_response_pwhash(auth_challenge, peer_challenge,
+					    username, username_len,
+					    sm->user->password,
+					    nt_response);
+	} else {
+		generate_nt_response(auth_challenge, peer_challenge,
+				     username, username_len,
+				     sm->user->password,
+				     sm->user->password_len,
+				     nt_response);
+	}
+
+	rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
+	if (os_memcmp(nt_response, rx_resp, 24) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
+			   "NT-Response");
+		data->mschapv2_resp_ok = 1;
+
+		if (sm->user->password_hash) {
+			generate_authenticator_response_pwhash(
+				sm->user->password,
+				peer_challenge, auth_challenge,
+				username, username_len, nt_response,
+				data->mschapv2_auth_response);
+		} else {
+			generate_authenticator_response(
+				sm->user->password, sm->user->password_len,
+				peer_challenge, auth_challenge,
+				username, username_len, nt_response,
+				data->mschapv2_auth_response);
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid "
+			   "NT-Response");
+		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received",
+			    rx_resp, 24);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected",
+			    nt_response, 24);
+		data->mschapv2_resp_ok = 0;
+	}
+	eap_ttls_state(data, PHASE2_MSCHAPV2_RESP);
+	data->mschapv2_ident = response[0];
+}
+
+
+static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
+				    struct eap_ttls_data *data,
+				    EapType eap_type)
+{
+	if (data->phase2_priv && data->phase2_method) {
+		data->phase2_method->reset(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+	}
+	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
+							eap_type);
+	if (!data->phase2_method)
+		return -1;
+
+	sm->init_phase2 = 1;
+	data->phase2_priv = data->phase2_method->init(sm);
+	sm->init_phase2 = 0;
+	return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
+						 struct eap_ttls_data *data,
+						 u8 *in_data, size_t in_len)
+{
+	u8 next_type = EAP_TYPE_NONE;
+	struct eap_hdr *hdr;
+	u8 *pos;
+	size_t left;
+	struct wpabuf buf;
+	const struct eap_method *m = data->phase2_method;
+	void *priv = data->phase2_priv;
+
+	if (priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not "
+			   "initialized?!", __func__);
+		return;
+	}
+
+	hdr = (struct eap_hdr *) in_data;
+	pos = (u8 *) (hdr + 1);
+
+	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = in_len - sizeof(*hdr);
+		wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; "
+			    "allowed types", pos + 1, left - 1);
+		eap_sm_process_nak(sm, pos + 1, left - 1);
+		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+		    sm->user->methods[sm->user_eap_method_index].method !=
+		    EAP_TYPE_NONE) {
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
+				   next_type);
+			if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
+				wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
+					   "initialize EAP type %d",
+					   next_type);
+				eap_ttls_state(data, FAILURE);
+				return;
+			}
+		} else {
+			eap_ttls_state(data, FAILURE);
+		}
+		return;
+	}
+
+	wpabuf_set(&buf, in_data, in_len);
+
+	if (m->check(sm, priv, &buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to "
+			   "ignore the packet");
+		return;
+	}
+
+	m->process(sm, priv, &buf);
+
+	if (sm->method_pending == METHOD_PENDING_WAIT) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in "
+			   "pending wait state - save decrypted response");
+		wpabuf_free(data->pending_phase2_eap_resp);
+		data->pending_phase2_eap_resp = wpabuf_dup(&buf);
+	}
+
+	if (!m->isDone(sm, priv))
+		return;
+
+	if (!m->isSuccess(sm, priv)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	switch (data->state) {
+	case PHASE2_START:
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			eap_ttls_state(data, FAILURE);
+			break;
+		}
+
+		eap_ttls_state(data, PHASE2_METHOD);
+		next_type = sm->user->methods[0].method;
+		sm->user_eap_method_index = 1;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
+		if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
+				   "EAP type %d", next_type);
+			eap_ttls_state(data, FAILURE);
+		}
+		break;
+	case PHASE2_METHOD:
+		eap_ttls_state(data, SUCCESS);
+		break;
+	case FAILURE:
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
+			   __func__, data->state);
+		break;
+	}
+}
+
+
+static void eap_ttls_process_phase2_eap(struct eap_sm *sm,
+					struct eap_ttls_data *data,
+					const u8 *eap, size_t eap_len)
+{
+	struct eap_hdr *hdr;
+	size_t len;
+
+	if (data->state == PHASE2_START) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
+		if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
+		{
+			wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
+				   "initialize EAP-Identity");
+			return;
+		}
+	}
+
+	if (eap_len < sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP "
+			   "packet (len=%lu)", (unsigned long) eap_len);
+		return;
+	}
+
+	hdr = (struct eap_hdr *) eap;
+	len = be_to_host16(hdr->length);
+	wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d "
+		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
+		   (unsigned long) len);
+	if (len > eap_len) {
+		wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2"
+			   " EAP frame (hdr len=%lu, data len in AVP=%lu)",
+			   (unsigned long) len, (unsigned long) eap_len);
+		return;
+	}
+
+	switch (hdr->code) {
+	case EAP_CODE_RESPONSE:
+		eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr,
+						     len);
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+}
+
+
+static void eap_ttls_process_phase2(struct eap_sm *sm,
+				    struct eap_ttls_data *data,
+				    struct wpabuf *in_buf)
+{
+	struct wpabuf *in_decrypted;
+	struct eap_ttls_avp parse;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_buf));
+
+	if (data->pending_phase2_eap_resp) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response "
+			   "- skip decryption and use old data");
+		eap_ttls_process_phase2_eap(
+			sm, data, wpabuf_head(data->pending_phase2_eap_resp),
+			wpabuf_len(data->pending_phase2_eap_resp));
+		wpabuf_free(data->pending_phase2_eap_resp);
+		data->pending_phase2_eap_resp = NULL;
+		return;
+	}
+
+	in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+					      in_buf);
+	if (in_decrypted == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
+			   "data");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
+			    in_decrypted);
+
+	if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs");
+		wpabuf_free(in_decrypted);
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	if (parse.user_name) {
+		os_free(sm->identity);
+		sm->identity = os_malloc(parse.user_name_len);
+		if (sm->identity == NULL) {
+			eap_ttls_state(data, FAILURE);
+			goto done;
+		}
+		os_memcpy(sm->identity, parse.user_name, parse.user_name_len);
+		sm->identity_len = parse.user_name_len;
+		if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
+		    != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not "
+				   "found in the user database");
+			eap_ttls_state(data, FAILURE);
+			goto done;
+		}
+	}
+
+#ifdef EAP_SERVER_TNC
+	if (data->tnc_started && parse.eap == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP "
+			   "response from peer");
+		eap_ttls_state(data, FAILURE);
+		goto done;
+	}
+#endif /* EAP_SERVER_TNC */
+
+	if (parse.eap) {
+		eap_ttls_process_phase2_eap(sm, data, parse.eap,
+					    parse.eap_len);
+	} else if (parse.user_password) {
+		eap_ttls_process_phase2_pap(sm, data, parse.user_password,
+					    parse.user_password_len);
+	} else if (parse.chap_password) {
+		eap_ttls_process_phase2_chap(sm, data,
+					     parse.chap_challenge,
+					     parse.chap_challenge_len,
+					     parse.chap_password,
+					     parse.chap_password_len);
+	} else if (parse.mschap_response) {
+		eap_ttls_process_phase2_mschap(sm, data,
+					       parse.mschap_challenge,
+					       parse.mschap_challenge_len,
+					       parse.mschap_response,
+					       parse.mschap_response_len);
+	} else if (parse.mschap2_response) {
+		eap_ttls_process_phase2_mschapv2(sm, data,
+						 parse.mschap_challenge,
+						 parse.mschap_challenge_len,
+						 parse.mschap2_response,
+						 parse.mschap2_response_len);
+	}
+
+done:
+	wpabuf_free(in_decrypted);
+	os_free(parse.eap);
+}
+
+
+static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
+{
+#ifdef EAP_SERVER_TNC
+	if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
+	if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	data->tnc_started = 1;
+	eap_ttls_state(data, PHASE2_METHOD);
+#endif /* EAP_SERVER_TNC */
+}
+
+
+static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
+{
+	struct eap_ttls_data *data = priv;
+	if (peer_version < data->ttls_version) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
+			   "use version %d",
+			   peer_version, data->ttls_version, peer_version);
+		data->ttls_version = peer_version;
+	}
+
+	return 0;
+}
+
+
+static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_ttls_data *data = priv;
+
+	switch (data->state) {
+	case PHASE1:
+		if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+			eap_ttls_state(data, FAILURE);
+		break;
+	case PHASE2_START:
+	case PHASE2_METHOD:
+		eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
+		eap_ttls_start_tnc(sm, data);
+		break;
+	case PHASE2_MSCHAPV2_RESP:
+		if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) ==
+		    0) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
+				   "acknowledged response");
+			eap_ttls_state(data, SUCCESS);
+		} else if (!data->mschapv2_resp_ok) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
+				   "acknowledged error");
+			eap_ttls_state(data, FAILURE);
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected "
+				   "frame from peer (payload len %lu, "
+				   "expected empty frame)",
+				   (unsigned long)
+				   wpabuf_len(data->ssl.tls_in));
+			eap_ttls_state(data, FAILURE);
+		}
+		eap_ttls_start_tnc(sm, data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s",
+			   data->state, __func__);
+		break;
+	}
+}
+
+
+static void eap_ttls_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_ttls_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_TTLS, eap_ttls_process_version,
+				   eap_ttls_process_msg) < 0)
+		eap_ttls_state(data, FAILURE);
+}
+
+
+static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ttls_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "ttls keying material",
+					       EAP_TLS_KEY_LEN);
+	if (eapKeyData) {
+		*len = EAP_TLS_KEY_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
+				eapKeyData, EAP_TLS_KEY_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
+	}
+
+	return eapKeyData;
+}
+
+
+static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_ttls_init;
+	eap->reset = eap_ttls_reset;
+	eap->buildReq = eap_ttls_buildReq;
+	eap->check = eap_ttls_check;
+	eap->process = eap_ttls_process;
+	eap->isDone = eap_ttls_isDone;
+	eap->getKey = eap_ttls_getKey;
+	eap->isSuccess = eap_ttls_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_vendor_test.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,198 +0,0 @@
-/*
- * hostapd / Test method for vendor specific (expanded) EAP type
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_i.h"
-
-
-#define EAP_VENDOR_ID 0xfffefd
-#define EAP_VENDOR_TYPE 0xfcfbfaf9
-
-
-struct eap_vendor_test_data {
-	enum { INIT, CONFIRM, SUCCESS, FAILURE } state;
-};
-
-
-static const char * eap_vendor_test_state_txt(int state)
-{
-	switch (state) {
-	case INIT:
-		return "INIT";
-	case CONFIRM:
-		return "CONFIRM";
-	case SUCCESS:
-		return "SUCCESS";
-	case FAILURE:
-		return "FAILURE";
-	default:
-		return "?";
-	}
-}
-
-
-static void eap_vendor_test_state(struct eap_vendor_test_data *data,
-				  int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s",
-		   eap_vendor_test_state_txt(data->state),
-		   eap_vendor_test_state_txt(state));
-	data->state = state;
-}
-
-
-static void * eap_vendor_test_init(struct eap_sm *sm)
-{
-	struct eap_vendor_test_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = INIT;
-
-	return data;
-}
-
-
-static void eap_vendor_test_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_vendor_test_data *data = priv;
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv,
-						u8 id)
-{
-	struct eap_vendor_test_data *data = priv;
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate "
-			   "memory for request");
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, data->state == INIT ? 1 : 3);
-
-	return req;
-}
-
-
-static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
-				     struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
-	if (pos == NULL || len < 1) {
-		wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static void eap_vendor_test_process(struct eap_sm *sm, void *priv,
-				    struct wpabuf *respData)
-{
-	struct eap_vendor_test_data *data = priv;
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
-	if (pos == NULL || len < 1)
-		return;
-
-	if (data->state == INIT) {
-		if (*pos == 2)
-			eap_vendor_test_state(data, CONFIRM);
-		else
-			eap_vendor_test_state(data, FAILURE);
-	} else if (data->state == CONFIRM) {
-		if (*pos == 4)
-			eap_vendor_test_state(data, SUCCESS);
-		else
-			eap_vendor_test_state(data, FAILURE);
-	} else
-		eap_vendor_test_state(data, FAILURE);
-}
-
-
-static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_vendor_test_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
-{
-	struct eap_vendor_test_data *data = priv;
-	u8 *key;
-	const int key_len = 64;
-
-	if (data->state != SUCCESS)
-		return NULL;
-
-	key = os_malloc(key_len);
-	if (key == NULL)
-		return NULL;
-
-	os_memset(key, 0x11, key_len / 2);
-	os_memset(key + key_len / 2, 0x22, key_len / 2);
-	*len = key_len;
-
-	return key;
-}
-
-
-static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
-{
-	struct eap_vendor_test_data *data = priv;
-	return data->state == SUCCESS;
-}
-
-
-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,
-				      "VENDOR-TEST");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_vendor_test_init;
-	eap->reset = eap_vendor_test_reset;
-	eap->buildReq = eap_vendor_test_buildReq;
-	eap->check = eap_vendor_test_check;
-	eap->process = eap_vendor_test_process;
-	eap->isDone = eap_vendor_test_isDone;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_vendor_test.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_vendor_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,192 @@
+/*
+ * hostapd / Test method for vendor specific (expanded) EAP type
+ * Copyright (c) 2005-2007, Jouni Malinen <j at 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 "eap_i.h"
+
+
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE 0xfcfbfaf9
+
+
+struct eap_vendor_test_data {
+	enum { INIT, CONFIRM, SUCCESS, FAILURE } state;
+};
+
+
+static const char * eap_vendor_test_state_txt(int state)
+{
+	switch (state) {
+	case INIT:
+		return "INIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_vendor_test_state(struct eap_vendor_test_data *data,
+				  int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s",
+		   eap_vendor_test_state_txt(data->state),
+		   eap_vendor_test_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_vendor_test_init(struct eap_sm *sm)
+{
+	struct eap_vendor_test_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = INIT;
+
+	return data;
+}
+
+
+static void eap_vendor_test_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv,
+						u8 id)
+{
+	struct eap_vendor_test_data *data = priv;
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate "
+			   "memory for request");
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, data->state == INIT ? 1 : 3);
+
+	return req;
+}
+
+
+static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
+				     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_vendor_test_process(struct eap_sm *sm, void *priv,
+				    struct wpabuf *respData)
+{
+	struct eap_vendor_test_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	if (data->state == INIT) {
+		if (*pos == 2)
+			eap_vendor_test_state(data, CONFIRM);
+		else
+			eap_vendor_test_state(data, FAILURE);
+	} else if (data->state == CONFIRM) {
+		if (*pos == 4)
+			eap_vendor_test_state(data, SUCCESS);
+		else
+			eap_vendor_test_state(data, FAILURE);
+	} else
+		eap_vendor_test_state(data, FAILURE);
+}
+
+
+static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_vendor_test_data *data = priv;
+	u8 *key;
+	const int key_len = 64;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(key_len);
+	if (key == NULL)
+		return NULL;
+
+	os_memset(key, 0x11, key_len / 2);
+	os_memset(key + key_len / 2, 0x22, key_len / 2);
+	*len = key_len;
+
+	return key;
+}
+
+
+static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+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,
+				      "VENDOR-TEST");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_vendor_test_init;
+	eap->reset = eap_vendor_test_reset;
+	eap->buildReq = eap_vendor_test_buildReq;
+	eap->check = eap_vendor_test_check;
+	eap->process = eap_vendor_test_process;
+	eap->isDone = eap_vendor_test_isDone;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_server_wsc.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_server_wsc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_server_wsc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,509 +0,0 @@
-/*
- * EAP-WSC server for Wi-Fi Protected Setup
- * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "eap_i.h"
-#include "eap_common/eap_wsc_common.h"
-#include "wps/wps.h"
-
-
-struct eap_wsc_data {
-	enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
-	int registrar;
-	struct wpabuf *in_buf;
-	struct wpabuf *out_buf;
-	enum wsc_op_code in_op_code, out_op_code;
-	size_t out_used;
-	size_t fragment_size;
-	struct wps_data *wps;
-	int ext_reg_timeout;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char * eap_wsc_state_txt(int state)
-{
-	switch (state) {
-	case START:
-		return "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:
-		return "?";
-	}
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void eap_wsc_state(struct eap_wsc_data *data, int state)
-{
-	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
-		   eap_wsc_state_txt(data->state),
-		   eap_wsc_state_txt(state));
-	data->state = state;
-}
-
-
-static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eap_sm *sm = eloop_ctx;
-	struct eap_wsc_data *data = timeout_ctx;
-
-	if (sm->method_pending != METHOD_PENDING_WAIT)
-		return;
-
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
-		   "Registrar");
-	data->ext_reg_timeout = 1;
-	eap_sm_pending_cb(sm);
-}
-
-
-static void * eap_wsc_init(struct eap_sm *sm)
-{
-	struct eap_wsc_data *data;
-	int registrar;
-	struct wps_config cfg;
-
-	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
-	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
-	    0)
-		registrar = 0; /* Supplicant is Registrar */
-	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
-		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
-		 == 0)
-		registrar = 1; /* Supplicant is Enrollee */
-	else {
-		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
-				  sm->identity, sm->identity_len);
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->state = registrar ? START : MESG;
-	data->registrar = registrar;
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	cfg.wps = sm->wps;
-	cfg.registrar = registrar;
-	if (registrar) {
-		if (sm->wps == NULL || sm->wps->registrar == NULL) {
-			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
-				   "initialized");
-			os_free(data);
-			return NULL;
-		}
-	} else {
-		if (sm->user == NULL || sm->user->password == NULL) {
-			/*
-			 * In theory, this should not really be needed, but
-			 * Windows 7 uses Registrar mode to probe AP's WPS
-			 * capabilities before trying to use Enrollee and fails
-			 * if the AP does not allow that probing to happen..
-			 */
-			wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
-				   "configured for Enrollee functionality - "
-				   "allow for probing capabilities (M1)");
-		} else {
-			cfg.pin = sm->user->password;
-			cfg.pin_len = sm->user->password_len;
-		}
-	}
-	cfg.assoc_wps_ie = sm->assoc_wps_ie;
-	cfg.peer_addr = sm->peer_addr;
-	if (0 /* TODO: could provide option for forcing PSK format */)
-		 cfg.use_psk_key = 1;
-	data->wps = wps_init(&cfg);
-	if (data->wps == NULL) {
-		os_free(data);
-		return NULL;
-	}
-	data->fragment_size = WSC_FRAGMENT_SIZE;
-
-	return data;
-}
-
-
-static void eap_wsc_reset(struct eap_sm *sm, void *priv)
-{
-	struct eap_wsc_data *data = priv;
-	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
-	wpabuf_free(data->in_buf);
-	wpabuf_free(data->out_buf);
-	wps_deinit(data->wps);
-	os_free(data);
-}
-
-
-static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
-					   struct eap_wsc_data *data, u8 id)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
-			   "request");
-		return NULL;
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
-	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
-	wpabuf_put_u8(req, 0); /* Flags */
-
-	return req;
-}
-
-
-static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
-{
-	struct wpabuf *req;
-	u8 flags;
-	size_t send_len, plen;
-
-	flags = 0;
-	send_len = wpabuf_len(data->out_buf) - data->out_used;
-	if (2 + send_len > data->fragment_size) {
-		send_len = data->fragment_size - 2;
-		flags |= WSC_FLAGS_MF;
-		if (data->out_used == 0) {
-			flags |= WSC_FLAGS_LF;
-			send_len -= 2;
-		}
-	}
-	plen = 2 + send_len;
-	if (flags & WSC_FLAGS_LF)
-		plen += 2;
-	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
-			   "request");
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
-	wpabuf_put_u8(req, flags); /* Flags */
-	if (flags & WSC_FLAGS_LF)
-		wpabuf_put_be16(req, wpabuf_len(data->out_buf));
-
-	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
-			send_len);
-	data->out_used += send_len;
-
-	if (data->out_used == wpabuf_len(data->out_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
-			   "(message sent completely)",
-			   (unsigned long) send_len);
-		wpabuf_free(data->out_buf);
-		data->out_buf = NULL;
-		data->out_used = 0;
-		eap_wsc_state(data, MESG);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
-			   "(%lu more to send)", (unsigned long) send_len,
-			   (unsigned long) wpabuf_len(data->out_buf) -
-			   data->out_used);
-		eap_wsc_state(data, WAIT_FRAG_ACK);
-	}
-
-	return req;
-}
-
-
-static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_wsc_data *data = priv;
-
-	switch (data->state) {
-	case START:
-		return eap_wsc_build_start(sm, data, id);
-	case MESG:
-		if (data->out_buf == NULL) {
-			data->out_buf = wps_get_msg(data->wps,
-						    &data->out_op_code);
-			if (data->out_buf == NULL) {
-				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
-					   "receive message from WPS");
-				return NULL;
-			}
-			data->out_used = 0;
-		}
-		/* pass through */
-	case WAIT_FRAG_ACK:
-		return eap_wsc_build_msg(data, id);
-	case FRAG_ACK:
-		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
-	default:
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
-			   "buildReq", data->state);
-		return NULL;
-	}
-}
-
-
-static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
-{
-	const u8 *pos;
-	size_t len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
-			       respData, &len);
-	if (pos == NULL || len < 2) {
-		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static int eap_wsc_process_cont(struct eap_wsc_data *data,
-				const u8 *buf, size_t len, u8 op_code)
-{
-	/* Process continuation of a pending message */
-	if (op_code != data->in_op_code) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
-			   "fragment (expected %d)",
-			   op_code, data->in_op_code);
-		eap_wsc_state(data, FAIL);
-		return -1;
-	}
-
-	if (len > wpabuf_tailroom(data->in_buf)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
-		eap_wsc_state(data, FAIL);
-		return -1;
-	}
-
-	wpabuf_put_data(data->in_buf, buf, len);
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
-		   "bytes more", (unsigned long) len,
-		   (unsigned long) wpabuf_tailroom(data->in_buf));
-
-	return 0;
-}
-
-
-static int eap_wsc_process_fragment(struct eap_wsc_data *data,
-				    u8 flags, u8 op_code, u16 message_length,
-				    const u8 *buf, size_t len)
-{
-	/* Process a fragment that is not the last one of the message */
-	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
-			   "field in a fragmented packet");
-		return -1;
-	}
-
-	if (data->in_buf == NULL) {
-		/* First fragment of the message */
-		data->in_buf = wpabuf_alloc(message_length);
-		if (data->in_buf == NULL) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
-				   "message");
-			return -1;
-		}
-		data->in_op_code = op_code;
-		wpabuf_put_data(data->in_buf, buf, len);
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
-			   "first fragment, waiting for %lu bytes more",
-			   (unsigned long) len,
-			   (unsigned long) wpabuf_tailroom(data->in_buf));
-	}
-
-	return 0;
-}
-
-
-static void eap_wsc_process(struct eap_sm *sm, void *priv,
-			    struct wpabuf *respData)
-{
-	struct eap_wsc_data *data = priv;
-	const u8 *start, *pos, *end;
-	size_t len;
-	u8 op_code, flags;
-	u16 message_length = 0;
-	enum wps_process_res res;
-	struct wpabuf tmpbuf;
-
-	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
-	if (data->ext_reg_timeout) {
-		eap_wsc_state(data, FAIL);
-		return;
-	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
-			       respData, &len);
-	if (pos == NULL || len < 2)
-		return; /* Should not happen; message already verified */
-
-	start = pos;
-	end = start + len;
-
-	op_code = *pos++;
-	flags = *pos++;
-	if (flags & WSC_FLAGS_LF) {
-		if (end - pos < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
-			return;
-		}
-		message_length = WPA_GET_BE16(pos);
-		pos += 2;
-
-		if (message_length < end - pos) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
-				   "Length");
-			return;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
-		   "Flags 0x%x Message Length %d",
-		   op_code, flags, message_length);
-
-	if (data->state == WAIT_FRAG_ACK) {
-		if (op_code != WSC_FRAG_ACK) {
-			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
-				   "in WAIT_FRAG_ACK state", op_code);
-			eap_wsc_state(data, FAIL);
-			return;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
-		eap_wsc_state(data, MESG);
-		return;
-	}
-
-	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
-	    op_code != WSC_Done) {
-		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
-			   op_code);
-		eap_wsc_state(data, FAIL);
-		return;
-	}
-
-	if (data->in_buf &&
-	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
-		eap_wsc_state(data, FAIL);
-		return;
-	}
-
-	if (flags & WSC_FLAGS_MF) {
-		if (eap_wsc_process_fragment(data, flags, op_code,
-					     message_length, pos, end - pos) <
-		    0)
-			eap_wsc_state(data, FAIL);
-		else
-			eap_wsc_state(data, FRAG_ACK);
-		return;
-	}
-
-	if (data->in_buf == NULL) {
-		/* Wrap unfragmented messages as wpabuf without extra copy */
-		wpabuf_set(&tmpbuf, pos, end - pos);
-		data->in_buf = &tmpbuf;
-	}
-
-	res = wps_process_msg(data->wps, op_code, data->in_buf);
-	switch (res) {
-	case WPS_DONE:
-		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
-			   "successfully - report EAP failure");
-		eap_wsc_state(data, FAIL);
-		break;
-	case WPS_CONTINUE:
-		eap_wsc_state(data, MESG);
-		break;
-	case WPS_FAILURE:
-		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
-		eap_wsc_state(data, FAIL);
-		break;
-	case WPS_PENDING:
-		eap_wsc_state(data, MESG);
-		sm->method_pending = METHOD_PENDING_WAIT;
-		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
-		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
-				       sm, data);
-		break;
-	}
-
-	if (data->in_buf != &tmpbuf)
-		wpabuf_free(data->in_buf);
-	data->in_buf = NULL;
-}
-
-
-static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
-{
-	struct eap_wsc_data *data = priv;
-	return data->state == FAIL;
-}
-
-
-static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
-{
-	/* EAP-WSC will always result in EAP-Failure */
-	return FALSE;
-}
-
-
-static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
-{
-	/* Recommended retransmit times: retransmit timeout 5 seconds,
-	 * per-message timeout 15 seconds, i.e., 3 tries. */
-	sm->MaxRetrans = 2; /* total 3 attempts */
-	return 5;
-}
-
-
-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,
-				      "WSC");
-	if (eap == NULL)
-		return -1;
-
-	eap->init = eap_wsc_init;
-	eap->reset = eap_wsc_reset;
-	eap->buildReq = eap_wsc_buildReq;
-	eap->check = eap_wsc_check;
-	eap->process = eap_wsc_process;
-	eap->isDone = eap_wsc_isDone;
-	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;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_server_wsc.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_server_wsc.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_server_wsc.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_server_wsc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,512 @@
+/*
+ * EAP-WSC server for Wi-Fi Protected Setup
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "eap_i.h"
+#include "eap_common/eap_wsc_common.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+
+
+struct eap_wsc_data {
+	enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	int registrar;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	enum wsc_op_code in_op_code, out_op_code;
+	size_t out_used;
+	size_t fragment_size;
+	struct wps_data *wps;
+	int ext_reg_timeout;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_wsc_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "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:
+		return "?";
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_wsc_state(struct eap_wsc_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
+		   eap_wsc_state_txt(data->state),
+		   eap_wsc_state_txt(state));
+	data->state = state;
+}
+
+
+static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eap_sm *sm = eloop_ctx;
+	struct eap_wsc_data *data = timeout_ctx;
+
+	if (sm->method_pending != METHOD_PENDING_WAIT)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
+		   "Registrar");
+	data->ext_reg_timeout = 1;
+	eap_sm_pending_cb(sm);
+}
+
+
+static void * eap_wsc_init(struct eap_sm *sm)
+{
+	struct eap_wsc_data *data;
+	int registrar;
+	struct wps_config cfg;
+
+	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
+	    0)
+		registrar = 0; /* Supplicant is Registrar */
+	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
+		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
+		 == 0)
+		registrar = 1; /* Supplicant is Enrollee */
+	else {
+		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
+				  sm->identity, sm->identity_len);
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = registrar ? START : MESG;
+	data->registrar = registrar;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = sm->wps;
+	cfg.registrar = registrar;
+	if (registrar) {
+		if (sm->wps == NULL || sm->wps->registrar == NULL) {
+			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
+				   "initialized");
+			os_free(data);
+			return NULL;
+		}
+	} else {
+		if (sm->user == NULL || sm->user->password == NULL) {
+			/*
+			 * In theory, this should not really be needed, but
+			 * Windows 7 uses Registrar mode to probe AP's WPS
+			 * capabilities before trying to use Enrollee and fails
+			 * if the AP does not allow that probing to happen..
+			 */
+			wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
+				   "configured for Enrollee functionality - "
+				   "allow for probing capabilities (M1)");
+		} else {
+			cfg.pin = sm->user->password;
+			cfg.pin_len = sm->user->password_len;
+		}
+	}
+	cfg.assoc_wps_ie = sm->assoc_wps_ie;
+	cfg.peer_addr = sm->peer_addr;
+#ifdef CONFIG_P2P
+	if (sm->assoc_p2p_ie) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
+			   "client");
+		cfg.use_psk_key = 1;
+		cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
+	}
+#endif /* CONFIG_P2P */
+	cfg.pbc_in_m1 = sm->pbc_in_m1;
+	data->wps = wps_init(&cfg);
+	if (data->wps == NULL) {
+		os_free(data);
+		return NULL;
+	}
+	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
+		WSC_FRAGMENT_SIZE;
+
+	return data;
+}
+
+
+static void eap_wsc_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	wps_deinit(data->wps);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
+					   struct eap_wsc_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "request");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
+	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
+	wpabuf_put_u8(req, 0); /* Flags */
+
+	return req;
+}
+
+
+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (2 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 2;
+		flags |= WSC_FLAGS_MF;
+		if (data->out_used == 0) {
+			flags |= WSC_FLAGS_LF;
+			send_len -= 2;
+		}
+	}
+	plen = 2 + send_len;
+	if (flags & WSC_FLAGS_LF)
+		plen += 2;
+	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "request");
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & WSC_FLAGS_LF)
+		wpabuf_put_be16(req, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		eap_wsc_state(data, MESG);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_wsc_state(data, WAIT_FRAG_ACK);
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_wsc_data *data = priv;
+
+	switch (data->state) {
+	case START:
+		return eap_wsc_build_start(sm, data, id);
+	case MESG:
+		if (data->out_buf == NULL) {
+			data->out_buf = wps_get_msg(data->wps,
+						    &data->out_op_code);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
+					   "receive message from WPS");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		/* pass through */
+	case WAIT_FRAG_ACK:
+		return eap_wsc_build_msg(data, id);
+	case FRAG_ACK:
+		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
+			   "buildReq", data->state);
+		return NULL;
+	}
+}
+
+
+static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+			       respData, &len);
+	if (pos == NULL || len < 2) {
+		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_wsc_process_cont(struct eap_wsc_data *data,
+				const u8 *buf, size_t len, u8 op_code)
+{
+	/* Process continuation of a pending message */
+	if (op_code != data->in_op_code) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
+			   "fragment (expected %d)",
+			   op_code, data->in_op_code);
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_wsc_process_fragment(struct eap_wsc_data *data,
+				    u8 flags, u8 op_code, u16 message_length,
+				    const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
+			   "field in a fragmented packet");
+		return -1;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
+				   "message");
+			return -1;
+		}
+		data->in_op_code = op_code;
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
+			   "first fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return 0;
+}
+
+
+static void eap_wsc_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_wsc_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 op_code, flags;
+	u16 message_length = 0;
+	enum wps_process_res res;
+	struct wpabuf tmpbuf;
+
+	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
+	if (data->ext_reg_timeout) {
+		eap_wsc_state(data, FAIL);
+		return;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+			       respData, &len);
+	if (pos == NULL || len < 2)
+		return; /* Should not happen; message already verified */
+
+	start = pos;
+	end = start + len;
+
+	op_code = *pos++;
+	flags = *pos++;
+	if (flags & WSC_FLAGS_LF) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
+			return;
+		}
+		message_length = WPA_GET_BE16(pos);
+		pos += 2;
+
+		if (message_length < end - pos) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
+				   "Length");
+			return;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
+		   "Flags 0x%x Message Length %d",
+		   op_code, flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (op_code != WSC_FRAG_ACK) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_FRAG_ACK state", op_code);
+			eap_wsc_state(data, FAIL);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
+		eap_wsc_state(data, MESG);
+		return;
+	}
+
+	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
+	    op_code != WSC_Done) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		eap_wsc_state(data, FAIL);
+		return;
+	}
+
+	if (data->in_buf &&
+	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
+		eap_wsc_state(data, FAIL);
+		return;
+	}
+
+	if (flags & WSC_FLAGS_MF) {
+		if (eap_wsc_process_fragment(data, flags, op_code,
+					     message_length, pos, end - pos) <
+		    0)
+			eap_wsc_state(data, FAIL);
+		else
+			eap_wsc_state(data, FRAG_ACK);
+		return;
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	res = wps_process_msg(data->wps, op_code, data->in_buf);
+	switch (res) {
+	case WPS_DONE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
+			   "successfully - report EAP failure");
+		eap_wsc_state(data, FAIL);
+		break;
+	case WPS_CONTINUE:
+		eap_wsc_state(data, MESG);
+		break;
+	case WPS_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
+		eap_wsc_state(data, FAIL);
+		break;
+	case WPS_PENDING:
+		eap_wsc_state(data, MESG);
+		sm->method_pending = METHOD_PENDING_WAIT;
+		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
+		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
+				       sm, data);
+		break;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	return data->state == FAIL;
+}
+
+
+static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
+{
+	/* EAP-WSC will always result in EAP-Failure */
+	return FALSE;
+}
+
+
+static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
+{
+	/* Recommended retransmit times: retransmit timeout 5 seconds,
+	 * per-message timeout 15 seconds, i.e., 3 tries. */
+	sm->MaxRetrans = 2; /* total 3 attempts */
+	return 5;
+}
+
+
+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,
+				      "WSC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_wsc_init;
+	eap->reset = eap_wsc_reset;
+	eap->buildReq = eap_wsc_buildReq;
+	eap->check = eap_wsc_check;
+	eap->process = eap_wsc_process;
+	eap->isDone = eap_wsc_isDone;
+	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;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_sim_db.c
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_sim_db.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_sim_db.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1337 +0,0 @@
-/*
- * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This is an example implementation of the EAP-SIM/AKA database/authentication
- * gateway interface that is using an external program as an SS7 gateway to
- * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
- * implementation of such a gateway program. This eap_sim_db.c takes care of
- * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
- * gateway implementations for HLR/AuC access. Alternatively, it can also be
- * completely replaced if the in-memory database of pseudonyms/re-auth
- * identities is not suitable for some cases.
- */
-
-#include "includes.h"
-#include <sys/un.h>
-
-#include "common.h"
-#include "eap_common/eap_sim_common.h"
-#include "eap_server/eap_sim_db.h"
-#include "eloop.h"
-
-struct eap_sim_pseudonym {
-	struct eap_sim_pseudonym *next;
-	u8 *identity;
-	size_t identity_len;
-	char *pseudonym;
-};
-
-struct eap_sim_db_pending {
-	struct eap_sim_db_pending *next;
-	u8 imsi[20];
-	size_t imsi_len;
-	enum { PENDING, SUCCESS, FAILURE } state;
-	void *cb_session_ctx;
-	struct os_time timestamp;
-	int aka;
-	union {
-		struct {
-			u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
-			u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
-			u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
-			int num_chal;
-		} sim;
-		struct {
-			u8 rand[EAP_AKA_RAND_LEN];
-			u8 autn[EAP_AKA_AUTN_LEN];
-			u8 ik[EAP_AKA_IK_LEN];
-			u8 ck[EAP_AKA_CK_LEN];
-			u8 res[EAP_AKA_RES_MAX_LEN];
-			size_t res_len;
-		} aka;
-	} u;
-};
-
-struct eap_sim_db_data {
-	int sock;
-	char *fname;
-	char *local_sock;
-	void (*get_complete_cb)(void *ctx, void *session_ctx);
-	void *ctx;
-	struct eap_sim_pseudonym *pseudonyms;
-	struct eap_sim_reauth *reauths;
-	struct eap_sim_db_pending *pending;
-};
-
-
-static struct eap_sim_db_pending *
-eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
-		       size_t imsi_len, int aka)
-{
-	struct eap_sim_db_pending *entry, *prev = NULL;
-
-	entry = data->pending;
-	while (entry) {
-		if (entry->aka == aka && entry->imsi_len == imsi_len &&
-		    os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				data->pending = entry->next;
-			break;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-	return entry;
-}
-
-
-static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
-				   struct eap_sim_db_pending *entry)
-{
-	entry->next = data->pending;
-	data->pending = entry;
-}
-
-
-static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
-				     const char *imsi, char *buf)
-{
-	char *start, *end, *pos;
-	struct eap_sim_db_pending *entry;
-	int num_chal;
-
-	/*
-	 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
-	 * SIM-RESP-AUTH <IMSI> FAILURE
-	 * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
-	 */
-
-	entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
-	if (entry == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
-			   "received message found");
-		return;
-	}
-
-	start = buf;
-	if (os_strncmp(start, "FAILURE", 7) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
-			   "failure");
-		entry->state = FAILURE;
-		eap_sim_db_add_pending(data, entry);
-		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
-		return;
-	}
-
-	num_chal = 0;
-	while (num_chal < EAP_SIM_MAX_CHAL) {
-		end = os_strchr(start, ' ');
-		if (end)
-			*end = '\0';
-
-		pos = os_strchr(start, ':');
-		if (pos == NULL)
-			goto parse_fail;
-		*pos = '\0';
-		if (hexstr2bin(start, entry->u.sim.kc[num_chal],
-			       EAP_SIM_KC_LEN))
-			goto parse_fail;
-
-		start = pos + 1;
-		pos = os_strchr(start, ':');
-		if (pos == NULL)
-			goto parse_fail;
-		*pos = '\0';
-		if (hexstr2bin(start, entry->u.sim.sres[num_chal],
-			       EAP_SIM_SRES_LEN))
-			goto parse_fail;
-
-		start = pos + 1;
-		if (hexstr2bin(start, entry->u.sim.rand[num_chal],
-			       GSM_RAND_LEN))
-			goto parse_fail;
-
-		num_chal++;
-		if (end == NULL)
-			break;
-		else
-			start = end + 1;
-	}
-	entry->u.sim.num_chal = num_chal;
-
-	entry->state = SUCCESS;
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
-		   "successfully - callback");
-	eap_sim_db_add_pending(data, entry);
-	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
-	return;
-
-parse_fail:
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-	os_free(entry);
-}
-
-
-static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
-				     const char *imsi, char *buf)
-{
-	char *start, *end;
-	struct eap_sim_db_pending *entry;
-
-	/*
-	 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
-	 * AKA-RESP-AUTH <IMSI> FAILURE
-	 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
-	 */
-
-	entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
-	if (entry == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
-			   "received message found");
-		return;
-	}
-
-	start = buf;
-	if (os_strncmp(start, "FAILURE", 7) == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
-			   "failure");
-		entry->state = FAILURE;
-		eap_sim_db_add_pending(data, entry);
-		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
-		return;
-	}
-
-	end = os_strchr(start, ' ');
-	if (end == NULL)
-		goto parse_fail;
-	*end = '\0';
-	if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
-		goto parse_fail;
-
-	start = end + 1;
-	end = os_strchr(start, ' ');
-	if (end == NULL)
-		goto parse_fail;
-	*end = '\0';
-	if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
-		goto parse_fail;
-
-	start = end + 1;
-	end = os_strchr(start, ' ');
-	if (end == NULL)
-		goto parse_fail;
-	*end = '\0';
-	if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
-		goto parse_fail;
-
-	start = end + 1;
-	end = os_strchr(start, ' ');
-	if (end == NULL)
-		goto parse_fail;
-	*end = '\0';
-	if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
-		goto parse_fail;
-
-	start = end + 1;
-	end = os_strchr(start, ' ');
-	if (end)
-		*end = '\0';
-	else {
-		end = start;
-		while (*end)
-			end++;
-	}
-	entry->u.aka.res_len = (end - start) / 2;
-	if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
-		entry->u.aka.res_len = 0;
-		goto parse_fail;
-	}
-	if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
-		goto parse_fail;
-
-	entry->state = SUCCESS;
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
-		   "successfully - callback");
-	eap_sim_db_add_pending(data, entry);
-	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
-	return;
-
-parse_fail:
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-	os_free(entry);
-}
-
-
-static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct eap_sim_db_data *data = eloop_ctx;
-	char buf[1000], *pos, *cmd, *imsi;
-	int res;
-
-	res = recv(sock, buf, sizeof(buf), 0);
-	if (res < 0)
-		return;
-	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
-			      "external source", (u8 *) buf, res);
-	if (res == 0)
-		return;
-	if (res >= (int) sizeof(buf))
-		res = sizeof(buf) - 1;
-	buf[res] = '\0';
-
-	if (data->get_complete_cb == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
-			   "registered");
-		return;
-	}
-
-	/* <cmd> <IMSI> ... */
-
-	cmd = buf;
-	pos = os_strchr(cmd, ' ');
-	if (pos == NULL)
-		goto parse_fail;
-	*pos = '\0';
-	imsi = pos + 1;
-	pos = os_strchr(imsi, ' ');
-	if (pos == NULL)
-		goto parse_fail;
-	*pos = '\0';
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
-		   cmd, imsi);
-
-	if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
-		eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
-	else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
-		eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
-	else
-		wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
-			   "'%s'", cmd);
-	return;
-
-parse_fail:
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-}
-
-
-static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
-{
-	struct sockaddr_un addr;
-	static int counter = 0;
-
-	if (os_strncmp(data->fname, "unix:", 5) != 0)
-		return -1;
-
-	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (data->sock < 0) {
-		perror("socket(eap_sim_db)");
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-		    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
-	data->local_sock = os_strdup(addr.sun_path);
-	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(eap_sim_db)");
-		close(data->sock);
-		data->sock = -1;
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
-	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("connect(eap_sim_db)");
-		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
-				  (u8 *) addr.sun_path,
-				  os_strlen(addr.sun_path));
-		close(data->sock);
-		data->sock = -1;
-		return -1;
-	}
-
-	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
-
-	return 0;
-}
-
-
-static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
-{
-	if (data->sock >= 0) {
-		eloop_unregister_read_sock(data->sock);
-		close(data->sock);
-		data->sock = -1;
-	}
-	if (data->local_sock) {
-		unlink(data->local_sock);
-		os_free(data->local_sock);
-		data->local_sock = NULL;
-	}
-}
-
-
-/**
- * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
- * @config: Configuration data (e.g., file name)
- * @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
- */
-void * eap_sim_db_init(const char *config,
-		       void (*get_complete_cb)(void *ctx, void *session_ctx),
-		       void *ctx)
-{
-	struct eap_sim_db_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	data->sock = -1;
-	data->get_complete_cb = get_complete_cb;
-	data->ctx = ctx;
-	data->fname = os_strdup(config);
-	if (data->fname == NULL)
-		goto fail;
-
-	if (os_strncmp(data->fname, "unix:", 5) == 0) {
-		if (eap_sim_db_open_socket(data))
-			goto fail;
-	}
-
-	return data;
-
-fail:
-	eap_sim_db_close_socket(data);
-	os_free(data->fname);
-	os_free(data);
-	return NULL;
-}
-
-
-static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
-{
-	os_free(p->identity);
-	os_free(p->pseudonym);
-	os_free(p);
-}
-
-
-static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
-{
-	os_free(r->identity);
-	os_free(r->reauth_id);
-	os_free(r);
-}
-
-
-/**
- * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
- * @priv: Private data pointer from eap_sim_db_init()
- */
-void eap_sim_db_deinit(void *priv)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_pseudonym *p, *prev;
-	struct eap_sim_reauth *r, *prevr;
-	struct eap_sim_db_pending *pending, *prev_pending;
-
-	eap_sim_db_close_socket(data);
-	os_free(data->fname);
-
-	p = data->pseudonyms;
-	while (p) {
-		prev = p;
-		p = p->next;
-		eap_sim_db_free_pseudonym(prev);
-	}
-
-	r = data->reauths;
-	while (r) {
-		prevr = r;
-		r = r->next;
-		eap_sim_db_free_reauth(prevr);
-	}
-
-	pending = data->pending;
-	while (pending) {
-		prev_pending = pending;
-		pending = pending->next;
-		os_free(prev_pending);
-	}
-
-	os_free(data);
-}
-
-
-static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
-			   size_t len)
-{
-	int _errno = 0;
-
-	if (send(data->sock, msg, len, 0) < 0) {
-		_errno = errno;
-		perror("send[EAP-SIM DB UNIX]");
-	}
-
-	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
-	    _errno == ECONNREFUSED) {
-		/* Try to reconnect */
-		eap_sim_db_close_socket(data);
-		if (eap_sim_db_open_socket(data) < 0)
-			return -1;
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
-			   "external server");
-		if (send(data->sock, msg, len, 0) < 0) {
-			perror("send[EAP-SIM DB UNIX]");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
-{
-	/* 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 */
-}
-
-
-/**
- * eap_sim_db_get_gsm_triplets - Get GSM triplets
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
- * @max_chal: Maximum number of triplets
- * @_rand: Buffer for RAND values
- * @kc: Buffer for Kc values
- * @sres: Buffer for SRES values
- * @cb_session_ctx: Session callback context for get_complete_cb()
- * Returns: Number of triplets received (has to be less than or equal to
- * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
- * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
- * callback function registered with eap_sim_db_init() will be called once the
- * results become available.
- *
- * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
- * ASCII format.
- *
- * When using an external server for GSM triplets, this function can always
- * start a request and return EAP_SIM_DB_PENDING immediately if authentication
- * triplets are not available. Once the triplets are received, callback
- * function registered with eap_sim_db_init() is called to notify EAP state
- * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
- * function will then be called again and the newly received triplets will then
- * be given to the caller.
- */
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
-				size_t identity_len, int max_chal,
-				u8 *_rand, u8 *kc, u8 *sres,
-				void *cb_session_ctx)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_db_pending *entry;
-	int len, ret;
-	size_t i;
-	char msg[40];
-
-	if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return EAP_SIM_DB_FAILURE;
-	}
-	identity++;
-	identity_len--;
-	for (i = 0; i < identity_len; i++) {
-		if (identity[i] == '@') {
-			identity_len = i;
-			break;
-		}
-	}
-	if (identity_len + 1 > sizeof(entry->imsi)) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return EAP_SIM_DB_FAILURE;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
-			  identity, identity_len);
-
-	entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
-	if (entry) {
-		int num_chal;
-		if (entry->state == FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
-				   "failure");
-			os_free(entry);
-			return EAP_SIM_DB_FAILURE;
-		}
-
-		if (entry->state == PENDING) {
-			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
-				   "still pending");
-			eap_sim_db_add_pending(data, entry);
-			return EAP_SIM_DB_PENDING;
-		}
-
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
-			   "%d challenges", entry->u.sim.num_chal);
-		num_chal = entry->u.sim.num_chal;
-		if (num_chal > max_chal)
-			num_chal = max_chal;
-		os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
-		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);
-		return num_chal;
-	}
-
-	if (data->sock < 0) {
-		if (eap_sim_db_open_socket(data) < 0)
-			return EAP_SIM_DB_FAILURE;
-	}
-
-	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
-	if (len < 0 || len + identity_len >= sizeof(msg))
-		return EAP_SIM_DB_FAILURE;
-	os_memcpy(msg + len, identity, identity_len);
-	len += identity_len;
-	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
-	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
-		return EAP_SIM_DB_FAILURE;
-	len += ret;
-
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
-		    "data for IMSI", identity, identity_len);
-	if (eap_sim_db_send(data, msg, len) < 0)
-		return EAP_SIM_DB_FAILURE;
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL)
-		return EAP_SIM_DB_FAILURE;
-
-	os_get_time(&entry->timestamp);
-	os_memcpy(entry->imsi, identity, identity_len);
-	entry->imsi_len = identity_len;
-	entry->cb_session_ctx = cb_session_ctx;
-	entry->state = PENDING;
-	eap_sim_db_add_pending(data, entry);
-	eap_sim_db_expire_pending(data);
-
-	return EAP_SIM_DB_PENDING;
-}
-
-
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
-			 size_t identity_len)
-{
-	char *pseudonym;
-	size_t len;
-	struct eap_sim_pseudonym *p;
-
-	if (identity_len == 0 ||
-	    (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
-	     identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
-		return NULL;
-
-	/* Remove possible realm from identity */
-	len = 0;
-	while (len < identity_len) {
-		if (identity[len] == '@')
-			break;
-		len++;
-	}
-
-	pseudonym = os_malloc(len + 1);
-	if (pseudonym == NULL)
-		return NULL;
-	os_memcpy(pseudonym, identity, len);
-	pseudonym[len] = '\0';
-
-	p = data->pseudonyms;
-	while (p) {
-		if (os_strcmp(p->pseudonym, pseudonym) == 0)
-			break;
-		p = p->next;
-	}
-
-	os_free(pseudonym);
-
-	return p;
-}
-
-
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
-			    size_t identity_len)
-{
-	struct eap_sim_pseudonym *p;
-
-	if (identity_len == 0 ||
-	    (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
-	     identity[0] != EAP_AKA_PERMANENT_PREFIX))
-		return NULL;
-
-	p = data->pseudonyms;
-	while (p) {
-		if (identity_len == p->identity_len &&
-		    os_memcmp(p->identity, identity, identity_len) == 0)
-			break;
-		p = p->next;
-	}
-
-	return p;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
-		      size_t identity_len)
-{
-	char *reauth_id;
-	size_t len;
-	struct eap_sim_reauth *r;
-
-	if (identity_len == 0 ||
-	    (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
-	     identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
-		return NULL;
-
-	/* Remove possible realm from identity */
-	len = 0;
-	while (len < identity_len) {
-		if (identity[len] == '@')
-			break;
-		len++;
-	}
-
-	reauth_id = os_malloc(len + 1);
-	if (reauth_id == NULL)
-		return NULL;
-	os_memcpy(reauth_id, identity, len);
-	reauth_id[len] = '\0';
-
-	r = data->reauths;
-	while (r) {
-		if (os_strcmp(r->reauth_id, reauth_id) == 0)
-			break;
-		r = r->next;
-	}
-
-	os_free(reauth_id);
-
-	return r;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
-			 size_t identity_len)
-{
-	struct eap_sim_pseudonym *p;
-	struct eap_sim_reauth *r;
-
-	if (identity_len == 0)
-		return NULL;
-
-	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
-	if (p == NULL)
-		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
-	if (p) {
-		identity = p->identity;
-		identity_len = p->identity_len;
-	}
-
-	r = data->reauths;
-	while (r) {
-		if (identity_len == r->identity_len &&
-		    os_memcmp(r->identity, identity, identity_len) == 0)
-			break;
-		r = r->next;
-	}
-
-	return r;
-}
-
-
-/**
- * eap_sim_db_identity_known - Verify whether the given identity is known
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes 
- * Returns: 0 if the user is found or -1 on failure
- *
- * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
- * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
- */
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
-			      size_t identity_len)
-{
-	struct eap_sim_db_data *data = priv;
-
-	if (identity == NULL || identity_len < 2)
-		return -1;
-
-	if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
-	    identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
-		struct eap_sim_pseudonym *p =
-			eap_sim_db_get_pseudonym(data, identity, identity_len);
-		return p ? 0 : -1;
-	}
-
-	if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
-	    identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
-		struct eap_sim_reauth *r =
-			eap_sim_db_get_reauth(data, identity, identity_len);
-		return r ? 0 : -1;
-	}
-
-	if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
-	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
-		/* Unknown identity prefix */
-		return -1;
-	}
-
-	/* TODO: Should consider asking HLR/AuC gateway whether this permanent
-	 * identity is known. If it is, EAP-SIM/AKA can skip identity request.
-	 * In case of EAP-AKA, this would reduce number of needed round-trips.
-	 * Ideally, this would be done with one wait, i.e., just request
-	 * authentication data and store it for the next use. This would then
-	 * need to use similar pending-request functionality as the normal
-	 * request for authentication data at later phase.
-	 */
-	return -1;
-}
-
-
-static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
-{
-	char *id, *pos, *end;
-	u8 buf[10];
-
-	if (os_get_random(buf, sizeof(buf)))
-		return NULL;
-	id = os_malloc(sizeof(buf) * 2 + 2);
-	if (id == NULL)
-		return NULL;
-
-	pos = id;
-	end = id + sizeof(buf) * 2 + 2;
-	*pos++ = prefix;
-	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
-	
-	return id;
-}
-
-
-/**
- * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
- * Returns: Next pseudonym (allocated string) or %NULL on failure
- *
- * This function is used to generate a pseudonym for EAP-SIM. The returned
- * pseudonym is not added to database at this point; it will need to be added
- * with eap_sim_db_add_pseudonym() once the authentication has been completed
- * successfully. Caller is responsible for freeing the returned buffer.
- */
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
-{
-	struct eap_sim_db_data *data = priv;
-	return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
-				   EAP_SIM_PSEUDONYM_PREFIX);
-}
-
-
-/**
- * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
- * @priv: Private data pointer from eap_sim_db_init()
- * @aka: Using EAP-AKA instead of EAP-SIM
- * Returns: Next reauth_id (allocated string) or %NULL on failure
- *
- * This function is used to generate a fast re-authentication identity for
- * EAP-SIM. The returned reauth_id is not added to database at this point; it
- * will need to be added with eap_sim_db_add_reauth() once the authentication
- * has been completed successfully. Caller is responsible for freeing the
- * returned buffer.
- */
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
-{
-	struct eap_sim_db_data *data = priv;
-	return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
-				   EAP_SIM_REAUTH_ID_PREFIX);
-}
-
-
-/**
- * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
- * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
- * free it.
- * Returns: 0 on success, -1 on failure
- *
- * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
- * responsible of freeing pseudonym buffer once it is not needed anymore.
- */
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
-			     size_t identity_len, char *pseudonym)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_pseudonym *p;
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
-			  identity, identity_len);
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
-
-	/* TODO: could store last two pseudonyms */
-	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
-	if (p == NULL)
-		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
-
-	if (p) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
-			   "pseudonym: %s", p->pseudonym);
-		os_free(p->pseudonym);
-		p->pseudonym = pseudonym;
-		return 0;
-	}
-
-	p = os_zalloc(sizeof(*p));
-	if (p == NULL) {
-		os_free(pseudonym);
-		return -1;
-	}
-
-	p->next = data->pseudonyms;
-	p->identity = os_malloc(identity_len);
-	if (p->identity == NULL) {
-		os_free(p);
-		os_free(pseudonym);
-		return -1;
-	}
-	os_memcpy(p->identity, identity, identity_len);
-	p->identity_len = identity_len;
-	p->pseudonym = pseudonym;
-	data->pseudonyms = p;
-
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
-	return 0;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
-			   size_t identity_len, char *reauth_id, u16 counter)
-{
-	struct eap_sim_reauth *r;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
-			  identity, identity_len);
-	wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
-
-	r = eap_sim_db_get_reauth(data, identity, identity_len);
-	if (r == NULL)
-		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
-
-	if (r) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
-			   "reauth_id: %s", r->reauth_id);
-		os_free(r->reauth_id);
-		r->reauth_id = reauth_id;
-	} else {
-		r = os_zalloc(sizeof(*r));
-		if (r == NULL) {
-			os_free(reauth_id);
-			return NULL;
-		}
-
-		r->next = data->reauths;
-		r->identity = os_malloc(identity_len);
-		if (r->identity == NULL) {
-			os_free(r);
-			os_free(reauth_id);
-			return NULL;
-		}
-		os_memcpy(r->identity, identity, identity_len);
-		r->identity_len = identity_len;
-		r->reauth_id = reauth_id;
-		data->reauths = r;
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
-	}
-
-	r->counter = counter;
-
-	return r;
-}
-
-
-/**
- * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
- * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
- * free it.
- * @counter: AT_COUNTER value for fast re-authentication
- * @mk: 16-byte MK from the previous full authentication or %NULL
- * Returns: 0 on success, -1 on failure
- *
- * This function adds a new re-authentication entry for an EAP-SIM user.
- * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
- * anymore.
- */
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
-			  size_t identity_len, char *reauth_id, u16 counter,
-			  const u8 *mk)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_reauth *r;
-
-	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
-				       counter);
-	if (r == NULL)
-		return -1;
-
-	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
-	r->aka_prime = 0;
-
-	return 0;
-}
-
-
-#ifdef EAP_SERVER_AKA_PRIME
-/**
- * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
- * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
- * free it.
- * @counter: AT_COUNTER value for fast re-authentication
- * @k_encr: K_encr from the previous full authentication
- * @k_aut: K_aut from the previous full authentication
- * @k_re: 32-byte K_re from the previous full authentication
- * Returns: 0 on success, -1 on failure
- *
- * This function adds a new re-authentication entry for an EAP-AKA' user.
- * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
- * anymore.
- */
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
-				size_t identity_len, char *reauth_id,
-				u16 counter, const u8 *k_encr, const u8 *k_aut,
-				const u8 *k_re)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_reauth *r;
-
-	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
-				       counter);
-	if (r == NULL)
-		return -1;
-
-	r->aka_prime = 1;
-	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
-	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
-	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
-
-	return 0;
-}
-#endif /* EAP_SERVER_AKA_PRIME */
-
-
-/**
- * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @len: Buffer for length of the returned permanent identity
- * Returns: Pointer to the permanent identity, or %NULL if not found
- */
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
-				    size_t identity_len, size_t *len)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_pseudonym *p;
-
-	if (identity == NULL)
-		return NULL;
-
-	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
-	if (p == NULL)
-		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
-	if (p == NULL)
-		return NULL;
-
-	*len = p->identity_len;
-	return p->identity;
-}
-
-
-/**
- * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity, pseudonym, or
- * reauth_id)
- * @identity_len: Length of identity
- * Returns: Pointer to the re-auth entry, or %NULL if not found
- */
-struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
-			    size_t identity_len)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_reauth *r;
-
-	if (identity == NULL)
-		return NULL;
-	r = eap_sim_db_get_reauth(data, identity, identity_len);
-	if (r == NULL)
-		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
-	return r;
-}
-
-
-/**
- * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @reauth: Pointer to re-authentication entry from
- * eap_sim_db_get_reauth_entry()
- */
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_reauth *r, *prev = NULL;
-	r = data->reauths;
-	while (r) {
-		if (r == reauth) {
-			if (prev)
-				prev->next = r->next;
-			else
-				data->reauths = r->next;
-			eap_sim_db_free_reauth(r);
-			return;
-		}
-		prev = r;
-		r = r->next;
-	}
-}
-
-
-/**
- * eap_sim_db_get_aka_auth - Get AKA authentication values
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
- * @_rand: Buffer for RAND value
- * @autn: Buffer for AUTN value
- * @ik: Buffer for IK value
- * @ck: Buffer for CK value
- * @res: Buffer for RES value
- * @res_len: Buffer for RES length
- * @cb_session_ctx: Session callback context for get_complete_cb()
- * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
- * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
- * case, the callback function registered with eap_sim_db_init() will be
- * called once the results become available.
- *
- * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
- * ASCII format.
- *
- * When using an external server for AKA authentication, this function can
- * always start a request and return EAP_SIM_DB_PENDING immediately if
- * authentication triplets are not available. Once the authentication data are
- * received, callback function registered with eap_sim_db_init() is called to
- * notify EAP state machine to reprocess the message. This
- * eap_sim_db_get_aka_auth() function will then be called again and the newly
- * received triplets will then be given to the caller.
- */
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
-			    size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
-			    u8 *ck, u8 *res, size_t *res_len,
-			    void *cb_session_ctx)
-{
-	struct eap_sim_db_data *data = priv;
-	struct eap_sim_db_pending *entry;
-	int len;
-	size_t i;
-	char msg[40];
-
-	if (identity_len < 2 || identity == NULL ||
-	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return EAP_SIM_DB_FAILURE;
-	}
-	identity++;
-	identity_len--;
-	for (i = 0; i < identity_len; i++) {
-		if (identity[i] == '@') {
-			identity_len = i;
-			break;
-		}
-	}
-	if (identity_len + 1 > sizeof(entry->imsi)) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return EAP_SIM_DB_FAILURE;
-	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
-			  identity, identity_len);
-
-	entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
-	if (entry) {
-		if (entry->state == FAILURE) {
-			os_free(entry);
-			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
-			return EAP_SIM_DB_FAILURE;
-		}
-
-		if (entry->state == PENDING) {
-			eap_sim_db_add_pending(data, entry);
-			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
-			return EAP_SIM_DB_PENDING;
-		}
-
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
-			   "received authentication data");
-		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
-		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
-		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
-		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);
-		return 0;
-	}
-
-	if (data->sock < 0) {
-		if (eap_sim_db_open_socket(data) < 0)
-			return EAP_SIM_DB_FAILURE;
-	}
-
-	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
-	if (len < 0 || len + identity_len >= sizeof(msg))
-		return EAP_SIM_DB_FAILURE;
-	os_memcpy(msg + len, identity, identity_len);
-	len += identity_len;
-
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
-		    "data for IMSI", identity, identity_len);
-	if (eap_sim_db_send(data, msg, len) < 0)
-		return EAP_SIM_DB_FAILURE;
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL)
-		return EAP_SIM_DB_FAILURE;
-
-	os_get_time(&entry->timestamp);
-	entry->aka = 1;
-	os_memcpy(entry->imsi, identity, identity_len);
-	entry->imsi_len = identity_len;
-	entry->cb_session_ctx = cb_session_ctx;
-	entry->state = PENDING;
-	eap_sim_db_add_pending(data, entry);
-	eap_sim_db_expire_pending(data);
-
-	return EAP_SIM_DB_PENDING;
-}
-
-
-/**
- * eap_sim_db_resynchronize - Resynchronize AKA AUTN
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
- * @auts: AUTS value from the peer
- * @_rand: RAND value used in the rejected message
- * Returns: 0 on success, -1 on failure
- *
- * This function is called when the peer reports synchronization failure in the
- * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
- * HLR/AuC to allow it to resynchronize with the peer. After this,
- * eap_sim_db_get_aka_auth() will be called again to to fetch updated
- * RAND/AUTN values for the next challenge.
- */
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
-			     size_t identity_len, const u8 *auts,
-			     const u8 *_rand)
-{
-	struct eap_sim_db_data *data = priv;
-	size_t i;
-
-	if (identity_len < 2 || identity == NULL ||
-	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return -1;
-	}
-	identity++;
-	identity_len--;
-	for (i = 0; i < identity_len; i++) {
-		if (identity[i] == '@') {
-			identity_len = i;
-			break;
-		}
-	}
-	if (identity_len > 20) {
-		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
-				  identity, identity_len);
-		return -1;
-	}
-
-	if (data->sock >= 0) {
-		char msg[100];
-		int len, ret;
-
-		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
-		if (len < 0 || len + identity_len >= sizeof(msg))
-			return -1;
-		os_memcpy(msg + len, identity, identity_len);
-		len += identity_len;
-
-		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
-		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
-			return -1;
-		len += ret;
-		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
-					auts, EAP_AKA_AUTS_LEN);
-		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
-		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
-			return -1;
-		len += ret;
-		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
-					_rand, EAP_AKA_RAND_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
-			    "IMSI", identity, identity_len);
-		if (eap_sim_db_send(data, msg, len) < 0)
-			return -1;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/eap_server/eap_sim_db.c (from rev 9639, vendor/wpa/dist/src/eap_server/eap_sim_db.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_sim_db.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_sim_db.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1501 @@
+/*
+ * hostapd / EAP-SIM database/authenticator gateway
+ * Copyright (c) 2005-2010, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface that is using an external program as an SS7 gateway to
+ * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
+ * implementation of such a gateway program. This eap_sim_db.c takes care of
+ * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
+ * gateway implementations for HLR/AuC access. Alternatively, it can also be
+ * completely replaced if the in-memory database of pseudonyms/re-auth
+ * identities is not suitable for some cases.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "crypto/random.h"
+#include "eap_common/eap_sim_common.h"
+#include "eap_server/eap_sim_db.h"
+#include "eloop.h"
+
+struct eap_sim_pseudonym {
+	struct eap_sim_pseudonym *next;
+	char *permanent; /* permanent username */
+	char *pseudonym; /* pseudonym username */
+};
+
+struct eap_sim_db_pending {
+	struct eap_sim_db_pending *next;
+	char imsi[20];
+	enum { PENDING, SUCCESS, FAILURE } state;
+	void *cb_session_ctx;
+	struct os_time timestamp;
+	int aka;
+	union {
+		struct {
+			u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+			u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
+			u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+			int num_chal;
+		} sim;
+		struct {
+			u8 rand[EAP_AKA_RAND_LEN];
+			u8 autn[EAP_AKA_AUTN_LEN];
+			u8 ik[EAP_AKA_IK_LEN];
+			u8 ck[EAP_AKA_CK_LEN];
+			u8 res[EAP_AKA_RES_MAX_LEN];
+			size_t res_len;
+		} aka;
+	} u;
+};
+
+struct eap_sim_db_data {
+	int sock;
+	char *fname;
+	char *local_sock;
+	void (*get_complete_cb)(void *ctx, void *session_ctx);
+	void *ctx;
+	struct eap_sim_pseudonym *pseudonyms;
+	struct eap_sim_reauth *reauths;
+	struct eap_sim_db_pending *pending;
+#ifdef CONFIG_SQLITE
+	sqlite3 *sqlite_db;
+	char db_tmp_identity[100];
+	char db_tmp_pseudonym_str[100];
+	struct eap_sim_pseudonym db_tmp_pseudonym;
+	struct eap_sim_reauth db_tmp_reauth;
+#endif /* CONFIG_SQLITE */
+};
+
+
+#ifdef CONFIG_SQLITE
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+	char cmd[128];
+	os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+	return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_pseudonym(sqlite3 *db)
+{
+	char *err = NULL;
+	const char *sql =
+		"CREATE TABLE pseudonyms("
+		"  permanent CHAR(21) PRIMARY KEY,"
+		"  pseudonym CHAR(21) NOT NULL"
+		");";
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+		   "pseudonym information");
+	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int db_table_create_reauth(sqlite3 *db)
+{
+	char *err = NULL;
+	const char *sql =
+		"CREATE TABLE reauth("
+		"  permanent CHAR(21) PRIMARY KEY,"
+		"  reauth_id CHAR(21) NOT NULL,"
+		"  counter INTEGER,"
+		"  mk CHAR(40),"
+		"  k_encr CHAR(32),"
+		"  k_aut CHAR(64),"
+		"  k_re CHAR(64)"
+		");";
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+		   "reauth information");
+	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+	sqlite3 *db;
+
+	if (sqlite3_open(db_file, &db)) {
+		wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
+			   "%s: %s", db_file, sqlite3_errmsg(db));
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	if (!db_table_exists(db, "pseudonyms") &&
+	    db_table_create_pseudonym(db) < 0) {
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	if (!db_table_exists(db, "reauth") &&
+	    db_table_create_reauth(db) < 0) {
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	return db;
+}
+
+
+static int valid_db_string(const char *str)
+{
+	const char *pos = str;
+	while (*pos) {
+		if ((*pos < '0' || *pos > '9') &&
+		    (*pos < 'a' || *pos > 'f'))
+			return 0;
+		pos++;
+	}
+	return 1;
+}
+
+
+static int db_add_pseudonym(struct eap_sim_db_data *data,
+			    const char *permanent, char *pseudonym)
+{
+	char cmd[128];
+	char *err = NULL;
+
+	if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
+		os_free(pseudonym);
+		return -1;
+	}
+
+	os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
+		    "(permanent, pseudonym) VALUES ('%s', '%s');",
+		    permanent, pseudonym);
+	os_free(pseudonym);
+	if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+	{
+		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct eap_sim_db_data *data = ctx;
+	int i;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+			os_strlcpy(data->db_tmp_identity, argv[i],
+				   sizeof(data->db_tmp_identity));
+		}
+	}
+
+	return 0;
+}
+
+
+static char *
+db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
+{
+	char cmd[128];
+
+	if (!valid_db_string(pseudonym))
+		return NULL;
+	os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
+		    pseudonym);
+	if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
+	    SQLITE_OK)
+		return NULL;
+	if (data->db_tmp_identity[0] == '\0')
+		return NULL;
+	return data->db_tmp_identity;
+}
+
+
+static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+			 char *reauth_id, u16 counter, const u8 *mk,
+			 const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
+{
+	char cmd[2000], *pos, *end;
+	char *err = NULL;
+
+	if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
+		os_free(reauth_id);
+		return -1;
+	}
+
+	pos = cmd;
+	end = pos + sizeof(cmd);
+	pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
+			   "(permanent, reauth_id, counter%s%s%s%s) "
+			   "VALUES ('%s', '%s', %u",
+			   mk ? ", mk" : "",
+			   k_encr ? ", k_encr" : "",
+			   k_aut ? ", k_aut" : "",
+			   k_re ? ", k_re" : "",
+			   permanent, reauth_id, counter);
+	os_free(reauth_id);
+
+	if (mk) {
+		pos += os_snprintf(pos, end - pos, ", '");
+		pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
+		pos += os_snprintf(pos, end - pos, "'");
+	}
+
+	if (k_encr) {
+		pos += os_snprintf(pos, end - pos, ", '");
+		pos += wpa_snprintf_hex(pos, end - pos, k_encr,
+					EAP_SIM_K_ENCR_LEN);
+		pos += os_snprintf(pos, end - pos, "'");
+	}
+
+	if (k_aut) {
+		pos += os_snprintf(pos, end - pos, ", '");
+		pos += wpa_snprintf_hex(pos, end - pos, k_aut,
+					EAP_AKA_PRIME_K_AUT_LEN);
+		pos += os_snprintf(pos, end - pos, "'");
+	}
+
+	if (k_re) {
+		pos += os_snprintf(pos, end - pos, ", '");
+		pos += wpa_snprintf_hex(pos, end - pos, k_re,
+					EAP_AKA_PRIME_K_RE_LEN);
+		pos += os_snprintf(pos, end - pos, "'");
+	}
+
+	os_snprintf(pos, end - pos, ");");
+
+	if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+	{
+		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct eap_sim_db_data *data = ctx;
+	int i;
+	struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+			os_strlcpy(data->db_tmp_identity, argv[i],
+				   sizeof(data->db_tmp_identity));
+			reauth->permanent = data->db_tmp_identity;
+		} else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
+			reauth->counter = atoi(argv[i]);
+		} else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
+			hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
+		} else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
+			hexstr2bin(argv[i], reauth->k_encr,
+				   sizeof(reauth->k_encr));
+		} else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
+			hexstr2bin(argv[i], reauth->k_aut,
+				   sizeof(reauth->k_aut));
+		} else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
+			hexstr2bin(argv[i], reauth->k_re,
+				   sizeof(reauth->k_re));
+		}
+	}
+
+	return 0;
+}
+
+
+static struct eap_sim_reauth *
+db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
+{
+	char cmd[256];
+
+	if (!valid_db_string(reauth_id))
+		return NULL;
+	os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
+	os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
+		   sizeof(data->db_tmp_pseudonym_str));
+	data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
+	if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
+	    SQLITE_OK)
+		return NULL;
+	if (data->db_tmp_reauth.permanent == NULL)
+		return NULL;
+	return &data->db_tmp_reauth;
+}
+
+
+static void db_remove_reauth(struct eap_sim_db_data *data,
+			     struct eap_sim_reauth *reauth)
+{
+	char cmd[256];
+
+	if (!valid_db_string(reauth->permanent))
+		return;
+	os_snprintf(cmd, sizeof(cmd),
+		    "DELETE FROM reauth WHERE permanent='%s';",
+		    reauth->permanent);
+	sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+static struct eap_sim_db_pending *
+eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
+{
+	struct eap_sim_db_pending *entry, *prev = NULL;
+
+	entry = data->pending;
+	while (entry) {
+		if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				data->pending = entry->next;
+			break;
+		}
+		prev = entry;
+		entry = entry->next;
+	}
+	return entry;
+}
+
+
+static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
+				   struct eap_sim_db_pending *entry)
+{
+	entry->next = data->pending;
+	data->pending = entry;
+}
+
+
+static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
+				     const char *imsi, char *buf)
+{
+	char *start, *end, *pos;
+	struct eap_sim_db_pending *entry;
+	int num_chal;
+
+	/*
+	 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
+	 * SIM-RESP-AUTH <IMSI> FAILURE
+	 * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
+	 */
+
+	entry = eap_sim_db_get_pending(data, imsi, 0);
+	if (entry == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+			   "received message found");
+		return;
+	}
+
+	start = buf;
+	if (os_strncmp(start, "FAILURE", 7) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+			   "failure");
+		entry->state = FAILURE;
+		eap_sim_db_add_pending(data, entry);
+		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+		return;
+	}
+
+	num_chal = 0;
+	while (num_chal < EAP_SIM_MAX_CHAL) {
+		end = os_strchr(start, ' ');
+		if (end)
+			*end = '\0';
+
+		pos = os_strchr(start, ':');
+		if (pos == NULL)
+			goto parse_fail;
+		*pos = '\0';
+		if (hexstr2bin(start, entry->u.sim.kc[num_chal],
+			       EAP_SIM_KC_LEN))
+			goto parse_fail;
+
+		start = pos + 1;
+		pos = os_strchr(start, ':');
+		if (pos == NULL)
+			goto parse_fail;
+		*pos = '\0';
+		if (hexstr2bin(start, entry->u.sim.sres[num_chal],
+			       EAP_SIM_SRES_LEN))
+			goto parse_fail;
+
+		start = pos + 1;
+		if (hexstr2bin(start, entry->u.sim.rand[num_chal],
+			       GSM_RAND_LEN))
+			goto parse_fail;
+
+		num_chal++;
+		if (end == NULL)
+			break;
+		else
+			start = end + 1;
+	}
+	entry->u.sim.num_chal = num_chal;
+
+	entry->state = SUCCESS;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+		   "successfully - callback");
+	eap_sim_db_add_pending(data, entry);
+	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+	os_free(entry);
+}
+
+
+static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
+				     const char *imsi, char *buf)
+{
+	char *start, *end;
+	struct eap_sim_db_pending *entry;
+
+	/*
+	 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+	 * AKA-RESP-AUTH <IMSI> FAILURE
+	 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
+	 */
+
+	entry = eap_sim_db_get_pending(data, imsi, 1);
+	if (entry == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+			   "received message found");
+		return;
+	}
+
+	start = buf;
+	if (os_strncmp(start, "FAILURE", 7) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+			   "failure");
+		entry->state = FAILURE;
+		eap_sim_db_add_pending(data, entry);
+		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+		return;
+	}
+
+	end = os_strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = os_strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = os_strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = os_strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = os_strchr(start, ' ');
+	if (end)
+		*end = '\0';
+	else {
+		end = start;
+		while (*end)
+			end++;
+	}
+	entry->u.aka.res_len = (end - start) / 2;
+	if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
+		entry->u.aka.res_len = 0;
+		goto parse_fail;
+	}
+	if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
+		goto parse_fail;
+
+	entry->state = SUCCESS;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+		   "successfully - callback");
+	eap_sim_db_add_pending(data, entry);
+	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+	os_free(entry);
+}
+
+
+static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct eap_sim_db_data *data = eloop_ctx;
+	char buf[1000], *pos, *cmd, *imsi;
+	int res;
+
+	res = recv(sock, buf, sizeof(buf), 0);
+	if (res < 0)
+		return;
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
+			      "external source", (u8 *) buf, res);
+	if (res == 0)
+		return;
+	if (res >= (int) sizeof(buf))
+		res = sizeof(buf) - 1;
+	buf[res] = '\0';
+
+	if (data->get_complete_cb == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
+			   "registered");
+		return;
+	}
+
+	/* <cmd> <IMSI> ... */
+
+	cmd = buf;
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		goto parse_fail;
+	*pos = '\0';
+	imsi = pos + 1;
+	pos = os_strchr(imsi, ' ');
+	if (pos == NULL)
+		goto parse_fail;
+	*pos = '\0';
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
+		   cmd, imsi);
+
+	if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
+		eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
+	else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
+		eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
+	else
+		wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
+			   "'%s'", cmd);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+}
+
+
+static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
+{
+	struct sockaddr_un addr;
+	static int counter = 0;
+
+	if (os_strncmp(data->fname, "unix:", 5) != 0)
+		return -1;
+
+	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (data->sock < 0) {
+		perror("socket(eap_sim_db)");
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+		    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
+	os_free(data->local_sock);
+	data->local_sock = os_strdup(addr.sun_path);
+	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind(eap_sim_db)");
+		close(data->sock);
+		data->sock = -1;
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
+	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("connect(eap_sim_db)");
+		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
+				  (u8 *) addr.sun_path,
+				  os_strlen(addr.sun_path));
+		close(data->sock);
+		data->sock = -1;
+		return -1;
+	}
+
+	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
+
+	return 0;
+}
+
+
+static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
+{
+	if (data->sock >= 0) {
+		eloop_unregister_read_sock(data->sock);
+		close(data->sock);
+		data->sock = -1;
+	}
+	if (data->local_sock) {
+		unlink(data->local_sock);
+		os_free(data->local_sock);
+		data->local_sock = NULL;
+	}
+}
+
+
+/**
+ * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
+ * @config: Configuration data (e.g., file name)
+ * @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,
+		void (*get_complete_cb)(void *ctx, void *session_ctx),
+		void *ctx)
+{
+	struct eap_sim_db_data *data;
+	char *pos;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->sock = -1;
+	data->get_complete_cb = get_complete_cb;
+	data->ctx = ctx;
+	data->fname = os_strdup(config);
+	if (data->fname == NULL)
+		goto fail;
+	pos = os_strstr(data->fname, " db=");
+	if (pos) {
+		*pos = '\0';
+#ifdef CONFIG_SQLITE
+		pos += 4;
+		data->sqlite_db = db_open(pos);
+		if (data->sqlite_db == NULL)
+			goto fail;
+#endif /* CONFIG_SQLITE */
+	}
+
+	if (os_strncmp(data->fname, "unix:", 5) == 0) {
+		if (eap_sim_db_open_socket(data)) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
+				   "connection not available - will retry "
+				   "later");
+		}
+	}
+
+	return data;
+
+fail:
+	eap_sim_db_close_socket(data);
+	os_free(data->fname);
+	os_free(data);
+	return NULL;
+}
+
+
+static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
+{
+	os_free(p->permanent);
+	os_free(p->pseudonym);
+	os_free(p);
+}
+
+
+static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
+{
+	os_free(r->permanent);
+	os_free(r->reauth_id);
+	os_free(r);
+}
+
+
+/**
+ * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
+ * @priv: Private data pointer from eap_sim_db_init()
+ */
+void eap_sim_db_deinit(void *priv)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_pseudonym *p, *prev;
+	struct eap_sim_reauth *r, *prevr;
+	struct eap_sim_db_pending *pending, *prev_pending;
+
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db) {
+		sqlite3_close(data->sqlite_db);
+		data->sqlite_db = NULL;
+	}
+#endif /* CONFIG_SQLITE */
+
+	eap_sim_db_close_socket(data);
+	os_free(data->fname);
+
+	p = data->pseudonyms;
+	while (p) {
+		prev = p;
+		p = p->next;
+		eap_sim_db_free_pseudonym(prev);
+	}
+
+	r = data->reauths;
+	while (r) {
+		prevr = r;
+		r = r->next;
+		eap_sim_db_free_reauth(prevr);
+	}
+
+	pending = data->pending;
+	while (pending) {
+		prev_pending = pending;
+		pending = pending->next;
+		os_free(prev_pending);
+	}
+
+	os_free(data);
+}
+
+
+static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
+			   size_t len)
+{
+	int _errno = 0;
+
+	if (send(data->sock, msg, len, 0) < 0) {
+		_errno = errno;
+		perror("send[EAP-SIM DB UNIX]");
+	}
+
+	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
+	    _errno == ECONNREFUSED) {
+		/* Try to reconnect */
+		eap_sim_db_close_socket(data);
+		if (eap_sim_db_open_socket(data) < 0)
+			return -1;
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
+			   "external server");
+		if (send(data->sock, msg, len, 0) < 0) {
+			perror("send[EAP-SIM DB UNIX]");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
+{
+	/* 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 */
+}
+
+
+/**
+ * eap_sim_db_get_gsm_triplets - Get GSM triplets
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
+ * @max_chal: Maximum number of triplets
+ * @_rand: Buffer for RAND values
+ * @kc: Buffer for Kc values
+ * @sres: Buffer for SRES values
+ * @cb_session_ctx: Session callback context for get_complete_cb()
+ * Returns: Number of triplets received (has to be less than or equal to
+ * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
+ * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
+ * callback function registered with eap_sim_db_init() will be called once the
+ * results become available.
+ *
+ * When using an external server for GSM triplets, this function can always
+ * start a request and return EAP_SIM_DB_PENDING immediately if authentication
+ * triplets are not available. Once the triplets are received, callback
+ * function registered with eap_sim_db_init() is called to notify EAP state
+ * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
+ * function will then be called again and the newly received triplets will then
+ * be given to the caller.
+ */
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+				const char *username, int max_chal,
+				u8 *_rand, u8 *kc, u8 *sres,
+				void *cb_session_ctx)
+{
+	struct eap_sim_db_pending *entry;
+	int len, ret;
+	char msg[40];
+	const char *imsi;
+	size_t imsi_len;
+
+	if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
+	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+			   username);
+		return EAP_SIM_DB_FAILURE;
+	}
+	imsi = username + 1;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
+		   imsi);
+
+	entry = eap_sim_db_get_pending(data, imsi, 0);
+	if (entry) {
+		int num_chal;
+		if (entry->state == FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+				   "failure");
+			os_free(entry);
+			return EAP_SIM_DB_FAILURE;
+		}
+
+		if (entry->state == PENDING) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+				   "still pending");
+			eap_sim_db_add_pending(data, entry);
+			return EAP_SIM_DB_PENDING;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+			   "%d challenges", entry->u.sim.num_chal);
+		num_chal = entry->u.sim.num_chal;
+		if (num_chal > max_chal)
+			num_chal = max_chal;
+		os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
+		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);
+		return num_chal;
+	}
+
+	if (data->sock < 0) {
+		if (eap_sim_db_open_socket(data) < 0)
+			return EAP_SIM_DB_FAILURE;
+	}
+
+	imsi_len = os_strlen(imsi);
+	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
+	if (len < 0 || len + imsi_len >= sizeof(msg))
+		return EAP_SIM_DB_FAILURE;
+	os_memcpy(msg + len, imsi, imsi_len);
+	len += imsi_len;
+	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
+	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+		return EAP_SIM_DB_FAILURE;
+	len += ret;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
+		   "data for IMSI '%s'", imsi);
+	if (eap_sim_db_send(data, msg, len) < 0)
+		return EAP_SIM_DB_FAILURE;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return EAP_SIM_DB_FAILURE;
+
+	os_get_time(&entry->timestamp);
+	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
+	entry->cb_session_ctx = cb_session_ctx;
+	entry->state = PENDING;
+	eap_sim_db_add_pending(data, entry);
+	eap_sim_db_expire_pending(data);
+
+	return EAP_SIM_DB_PENDING;
+}
+
+
+static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
+{
+	char *id, *pos, *end;
+	u8 buf[10];
+
+	if (random_get_bytes(buf, sizeof(buf)))
+		return NULL;
+	id = os_malloc(sizeof(buf) * 2 + 2);
+	if (id == NULL)
+		return NULL;
+
+	pos = id;
+	end = id + sizeof(buf) * 2 + 2;
+	*pos++ = prefix;
+	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+	
+	return id;
+}
+
+
+/**
+ * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
+ * @data: Private data pointer from eap_sim_db_init()
+ * @method: EAP method (SIM/AKA/AKA')
+ * Returns: Next pseudonym (allocated string) or %NULL on failure
+ *
+ * This function is used to generate a pseudonym for EAP-SIM. The returned
+ * pseudonym is not added to database at this point; it will need to be added
+ * with eap_sim_db_add_pseudonym() once the authentication has been completed
+ * successfully. Caller is responsible for freeing the returned buffer.
+ */
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
+				     enum eap_sim_db_method method)
+{
+	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+	switch (method) {
+	case EAP_SIM_DB_SIM:
+		prefix = EAP_SIM_PSEUDONYM_PREFIX;
+		break;
+	case EAP_SIM_DB_AKA:
+		prefix = EAP_AKA_PSEUDONYM_PREFIX;
+		break;
+	case EAP_SIM_DB_AKA_PRIME:
+		prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
+		break;
+	}
+
+	return eap_sim_db_get_next(data, prefix);
+}
+
+
+/**
+ * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
+ * @data: Private data pointer from eap_sim_db_init()
+ * @method: EAP method (SIM/AKA/AKA')
+ * Returns: Next reauth_id (allocated string) or %NULL on failure
+ *
+ * This function is used to generate a fast re-authentication identity for
+ * EAP-SIM. The returned reauth_id is not added to database at this point; it
+ * will need to be added with eap_sim_db_add_reauth() once the authentication
+ * has been completed successfully. Caller is responsible for freeing the
+ * returned buffer.
+ */
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
+				     enum eap_sim_db_method method)
+{
+	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
+
+	switch (method) {
+	case EAP_SIM_DB_SIM:
+		prefix = EAP_SIM_REAUTH_ID_PREFIX;
+		break;
+	case EAP_SIM_DB_AKA:
+		prefix = EAP_AKA_REAUTH_ID_PREFIX;
+		break;
+	case EAP_SIM_DB_AKA_PRIME:
+		prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
+		break;
+	}
+
+	return eap_sim_db_get_next(data, prefix);
+}
+
+
+/**
+ * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
+ * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
+ * free it.
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
+ * responsible of freeing pseudonym buffer once it is not needed anymore.
+ */
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+			     const char *permanent, char *pseudonym)
+{
+	struct eap_sim_pseudonym *p;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
+		   "username '%s'", pseudonym, permanent);
+
+	/* TODO: could store last two pseudonyms */
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db)
+		return db_add_pseudonym(data, permanent, pseudonym);
+#endif /* CONFIG_SQLITE */
+	for (p = data->pseudonyms; p; p = p->next) {
+		if (os_strcmp(permanent, p->permanent) == 0)
+			break;
+	}
+	if (p) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
+			   "pseudonym: %s", p->pseudonym);
+		os_free(p->pseudonym);
+		p->pseudonym = pseudonym;
+		return 0;
+	}
+
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL) {
+		os_free(pseudonym);
+		return -1;
+	}
+
+	p->next = data->pseudonyms;
+	p->permanent = os_strdup(permanent);
+	if (p->permanent == NULL) {
+		os_free(p);
+		os_free(pseudonym);
+		return -1;
+	}
+	p->pseudonym = pseudonym;
+	data->pseudonyms = p;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
+	return 0;
+}
+
+
+static struct eap_sim_reauth *
+eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
+			   const char *permanent,
+			   char *reauth_id, u16 counter)
+{
+	struct eap_sim_reauth *r;
+
+	for (r = data->reauths; r; r = r->next) {
+		if (os_strcmp(r->permanent, permanent) == 0)
+			break;
+	}
+
+	if (r) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
+			   "reauth_id: %s", r->reauth_id);
+		os_free(r->reauth_id);
+		r->reauth_id = reauth_id;
+	} else {
+		r = os_zalloc(sizeof(*r));
+		if (r == NULL) {
+			os_free(reauth_id);
+			return NULL;
+		}
+
+		r->next = data->reauths;
+		r->permanent = os_strdup(permanent);
+		if (r->permanent == NULL) {
+			os_free(r);
+			os_free(reauth_id);
+			return NULL;
+		}
+		r->reauth_id = reauth_id;
+		data->reauths = r;
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
+	}
+
+	r->counter = counter;
+
+	return r;
+}
+
+
+/**
+ * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
+ * @identity_len: Length of identity
+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
+ * free it.
+ * @counter: AT_COUNTER value for fast re-authentication
+ * @mk: 16-byte MK from the previous full authentication or %NULL
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new re-authentication entry for an EAP-SIM user.
+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
+ * anymore.
+ */
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+			  char *reauth_id, u16 counter, const u8 *mk)
+{
+	struct eap_sim_reauth *r;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+		   "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db)
+		return db_add_reauth(data, permanent, reauth_id, counter, mk,
+				     NULL, NULL, NULL);
+#endif /* CONFIG_SQLITE */
+	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
+	if (r == NULL)
+		return -1;
+
+	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
+
+	return 0;
+}
+
+
+#ifdef EAP_SERVER_AKA_PRIME
+/**
+ * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
+ * free it.
+ * @counter: AT_COUNTER value for fast re-authentication
+ * @k_encr: K_encr from the previous full authentication
+ * @k_aut: K_aut from the previous full authentication
+ * @k_re: 32-byte K_re from the previous full authentication
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new re-authentication entry for an EAP-AKA' user.
+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
+ * anymore.
+ */
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+				const char *permanent, char *reauth_id,
+				u16 counter, const u8 *k_encr,
+				const u8 *k_aut, const u8 *k_re)
+{
+	struct eap_sim_reauth *r;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+		   "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db)
+		return db_add_reauth(data, permanent, reauth_id, counter, NULL,
+				     k_encr, k_aut, k_re);
+#endif /* CONFIG_SQLITE */
+	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
+	if (r == NULL)
+		return -1;
+
+	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
+	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
+
+	return 0;
+}
+#endif /* EAP_SERVER_AKA_PRIME */
+
+
+/**
+ * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @pseudonym: Pseudonym username
+ * Returns: Pointer to permanent username or %NULL if not found
+ */
+const char *
+eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
+{
+	struct eap_sim_pseudonym *p;
+
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db)
+		return db_get_pseudonym(data, pseudonym);
+#endif /* CONFIG_SQLITE */
+
+	p = data->pseudonyms;
+	while (p) {
+		if (os_strcmp(p->pseudonym, pseudonym) == 0)
+			return p->permanent;
+		p = p->next;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
+ * @data: Private data pointer from eap_sim_db_init()
+ * @reauth_id: Fast re-authentication username
+ * Returns: Pointer to the re-auth entry, or %NULL if not found
+ */
+struct eap_sim_reauth *
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+			    const char *reauth_id)
+{
+	struct eap_sim_reauth *r;
+
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db)
+		return db_get_reauth(data, reauth_id);
+#endif /* CONFIG_SQLITE */
+
+	r = data->reauths;
+	while (r) {
+		if (os_strcmp(r->reauth_id, reauth_id) == 0)
+			break;
+		r = r->next;
+	}
+
+	return r;
+}
+
+
+/**
+ * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
+ * @data: Private data pointer from eap_sim_db_init()
+ * @reauth: Pointer to re-authentication entry from
+ * eap_sim_db_get_reauth_entry()
+ */
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+			      struct eap_sim_reauth *reauth)
+{
+	struct eap_sim_reauth *r, *prev = NULL;
+#ifdef CONFIG_SQLITE
+	if (data->sqlite_db) {
+		db_remove_reauth(data, reauth);
+		return;
+	}
+#endif /* CONFIG_SQLITE */
+	r = data->reauths;
+	while (r) {
+		if (r == reauth) {
+			if (prev)
+				prev->next = r->next;
+			else
+				data->reauths = r->next;
+			eap_sim_db_free_reauth(r);
+			return;
+		}
+		prev = r;
+		r = r->next;
+	}
+}
+
+
+/**
+ * eap_sim_db_get_aka_auth - Get AKA authentication values
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
+ * @_rand: Buffer for RAND value
+ * @autn: Buffer for AUTN value
+ * @ik: Buffer for IK value
+ * @ck: Buffer for CK value
+ * @res: Buffer for RES value
+ * @res_len: Buffer for RES length
+ * @cb_session_ctx: Session callback context for get_complete_cb()
+ * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
+ * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
+ * case, the callback function registered with eap_sim_db_init() will be
+ * called once the results become available.
+ *
+ * When using an external server for AKA authentication, this function can
+ * always start a request and return EAP_SIM_DB_PENDING immediately if
+ * authentication triplets are not available. Once the authentication data are
+ * received, callback function registered with eap_sim_db_init() is called to
+ * notify EAP state machine to reprocess the message. This
+ * eap_sim_db_get_aka_auth() function will then be called again and the newly
+ * received triplets will then be given to the caller.
+ */
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+			    u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+			    u8 *res, size_t *res_len, void *cb_session_ctx)
+{
+	struct eap_sim_db_pending *entry;
+	int len;
+	char msg[40];
+	const char *imsi;
+	size_t imsi_len;
+
+	if (username == NULL ||
+	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+			   username);
+		return EAP_SIM_DB_FAILURE;
+	}
+	imsi = username + 1;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+		   imsi);
+
+	entry = eap_sim_db_get_pending(data, imsi, 1);
+	if (entry) {
+		if (entry->state == FAILURE) {
+			os_free(entry);
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
+			return EAP_SIM_DB_FAILURE;
+		}
+
+		if (entry->state == PENDING) {
+			eap_sim_db_add_pending(data, entry);
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
+			return EAP_SIM_DB_PENDING;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
+			   "received authentication data");
+		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
+		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
+		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
+		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);
+		return 0;
+	}
+
+	if (data->sock < 0) {
+		if (eap_sim_db_open_socket(data) < 0)
+			return EAP_SIM_DB_FAILURE;
+	}
+
+	imsi_len = os_strlen(imsi);
+	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
+	if (len < 0 || len + imsi_len >= sizeof(msg))
+		return EAP_SIM_DB_FAILURE;
+	os_memcpy(msg + len, imsi, imsi_len);
+	len += imsi_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
+		    "data for IMSI '%s'", imsi);
+	if (eap_sim_db_send(data, msg, len) < 0)
+		return EAP_SIM_DB_FAILURE;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return EAP_SIM_DB_FAILURE;
+
+	os_get_time(&entry->timestamp);
+	entry->aka = 1;
+	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
+	entry->cb_session_ctx = cb_session_ctx;
+	entry->state = PENDING;
+	eap_sim_db_add_pending(data, entry);
+	eap_sim_db_expire_pending(data);
+
+	return EAP_SIM_DB_PENDING;
+}
+
+
+/**
+ * eap_sim_db_resynchronize - Resynchronize AKA AUTN
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username
+ * @auts: AUTS value from the peer
+ * @_rand: RAND value used in the rejected message
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when the peer reports synchronization failure in the
+ * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
+ * HLR/AuC to allow it to resynchronize with the peer. After this,
+ * eap_sim_db_get_aka_auth() will be called again to to fetch updated
+ * RAND/AUTN values for the next challenge.
+ */
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+			     const char *username,
+			     const u8 *auts, const u8 *_rand)
+{
+	const char *imsi;
+	size_t imsi_len;
+
+	if (username == NULL ||
+	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+	    username[1] == '\0' || os_strlen(username) > 20) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+			   username);
+		return -1;
+	}
+	imsi = username + 1;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+		   imsi);
+
+	if (data->sock >= 0) {
+		char msg[100];
+		int len, ret;
+
+		imsi_len = os_strlen(imsi);
+		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
+		if (len < 0 || len + imsi_len >= sizeof(msg))
+			return -1;
+		os_memcpy(msg + len, imsi, imsi_len);
+		len += imsi_len;
+
+		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
+		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+			return -1;
+		len += ret;
+		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
+					auts, EAP_AKA_AUTS_LEN);
+		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
+		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+			return -1;
+		len += ret;
+		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
+					_rand, EAP_AKA_RAND_LEN);
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
+			   "IMSI '%s'", imsi);
+		if (eap_sim_db_send(data, msg, len) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * sim_get_username - Extract username from SIM identity
+ * @identity: Identity
+ * @identity_len: Identity length
+ * Returns: Allocated buffer with the username part of the identity
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * sim_get_username(const u8 *identity, size_t identity_len)
+{
+	char *username;
+	size_t pos;
+
+	if (identity == NULL)
+		return NULL;
+
+	for (pos = 0; pos < identity_len; pos++) {
+		if (identity[pos] == '@' || identity[pos] == '\0')
+			break;
+	}
+
+	username = os_malloc(pos + 1);
+	if (username == NULL)
+		return NULL;
+	os_memcpy(username, identity, pos);
+	username[pos] = '\0';
+
+	return username;
+}

Deleted: vendor/wpa/2.0/src/eap_server/eap_sim_db.h
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_sim_db.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_sim_db.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,91 +0,0 @@
-/*
- * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_SIM_DB_H
-#define EAP_SIM_DB_H
-
-#include "eap_common/eap_sim_common.h"
-
-/* Identity prefixes */
-#define EAP_SIM_PERMANENT_PREFIX '1'
-#define EAP_SIM_PSEUDONYM_PREFIX '3'
-#define EAP_SIM_REAUTH_ID_PREFIX '5'
-#define EAP_AKA_PERMANENT_PREFIX '0'
-#define EAP_AKA_PSEUDONYM_PREFIX '2'
-#define EAP_AKA_REAUTH_ID_PREFIX '4'
-
-void * eap_sim_db_init(const char *config,
-		       void (*get_complete_cb)(void *ctx, void *session_ctx),
-		       void *ctx);
-
-void eap_sim_db_deinit(void *priv);
-
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
-				size_t identity_len, int max_chal,
-				u8 *_rand, u8 *kc, u8 *sres,
-				void *cb_session_ctx);
-
-#define EAP_SIM_DB_FAILURE -1
-#define EAP_SIM_DB_PENDING -2
-
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
-			      size_t identity_len);
-
-char * eap_sim_db_get_next_pseudonym(void *priv, int aka);
-
-char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
-
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
-			     size_t identity_len, char *pseudonym);
-
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
-			  size_t identity_len, char *reauth_id, u16 counter,
-			  const u8 *mk);
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
-				size_t identity_len, char *reauth_id,
-				u16 counter, const u8 *k_encr, const u8 *k_aut,
-				const u8 *k_re);
-
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
-				    size_t identity_len, size_t *len);
-
-struct eap_sim_reauth {
-	struct eap_sim_reauth *next;
-	u8 *identity;
-	size_t identity_len;
-	char *reauth_id;
-	u16 counter;
-	int aka_prime;
-	u8 mk[EAP_SIM_MK_LEN];
-	u8 k_encr[EAP_SIM_K_ENCR_LEN];
-	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
-	u8 k_re[EAP_AKA_PRIME_K_RE_LEN];
-};
-
-struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
-			    size_t identity_len);
-
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
-
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
-			    size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
-			    u8 *ck, u8 *res, size_t *res_len,
-			    void *cb_session_ctx);
-
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
-			     size_t identity_len, const u8 *auts,
-			     const u8 *_rand);
-
-#endif /* EAP_SIM_DB_H */

Copied: vendor/wpa/2.0/src/eap_server/eap_sim_db.h (from rev 9639, vendor/wpa/dist/src/eap_server/eap_sim_db.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_sim_db.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_sim_db.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,95 @@
+/*
+ * hostapd / EAP-SIM database/authenticator gateway
+ * Copyright (c) 2005-2008, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_SIM_DB_H
+#define EAP_SIM_DB_H
+
+#include "eap_common/eap_sim_common.h"
+
+/* Identity prefixes */
+#define EAP_SIM_PERMANENT_PREFIX '1'
+#define EAP_SIM_PSEUDONYM_PREFIX '3'
+#define EAP_SIM_REAUTH_ID_PREFIX '5'
+#define EAP_AKA_PERMANENT_PREFIX '0'
+#define EAP_AKA_PSEUDONYM_PREFIX '2'
+#define EAP_AKA_REAUTH_ID_PREFIX '4'
+#define EAP_AKA_PRIME_PERMANENT_PREFIX '6'
+#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7'
+#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8'
+
+enum eap_sim_db_method {
+	EAP_SIM_DB_SIM,
+	EAP_SIM_DB_AKA,
+	EAP_SIM_DB_AKA_PRIME
+};
+
+struct eap_sim_db_data;
+
+struct eap_sim_db_data *
+eap_sim_db_init(const char *config,
+		void (*get_complete_cb)(void *ctx, void *session_ctx),
+		void *ctx);
+
+void eap_sim_db_deinit(void *priv);
+
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+				const char *username, int max_chal,
+				u8 *_rand, u8 *kc, u8 *sres,
+				void *cb_session_ctx);
+
+#define EAP_SIM_DB_FAILURE -1
+#define EAP_SIM_DB_PENDING -2
+
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
+				     enum eap_sim_db_method method);
+
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
+				     enum eap_sim_db_method method);
+
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+			     const char *permanent, char *pseudonym);
+
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+			  char *reauth_id, u16 counter, const u8 *mk);
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+				const char *permanent,
+				char *reauth_id, u16 counter, const u8 *k_encr,
+				const u8 *k_aut, const u8 *k_re);
+
+const char * eap_sim_db_get_permanent(struct eap_sim_db_data *data,
+				      const char *pseudonym);
+
+struct eap_sim_reauth {
+	struct eap_sim_reauth *next;
+	char *permanent; /* Permanent username */
+	char *reauth_id; /* Fast re-authentication username */
+	u16 counter;
+	u8 mk[EAP_SIM_MK_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN];
+};
+
+struct eap_sim_reauth *
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+			    const char *reauth_id);
+
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+			      struct eap_sim_reauth *reauth);
+
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+			    u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+			    u8 *res, size_t *res_len, void *cb_session_ctx);
+
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+			     const char *username, const u8 *auts,
+			     const u8 *_rand);
+
+char * sim_get_username(const u8 *identity, size_t identity_len);
+
+#endif /* EAP_SIM_DB_H */

Deleted: vendor/wpa/2.0/src/eap_server/eap_tls_common.h
===================================================================
--- vendor/wpa/dist/src/eap_server/eap_tls_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/eap_tls_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,91 +0,0 @@
-/*
- * EAP-TLS/PEAP/TTLS/FAST server common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAP_TLS_COMMON_H
-#define EAP_TLS_COMMON_H
-
-/**
- * struct eap_ssl_data - TLS data for EAP methods
- */
-struct eap_ssl_data {
-	/**
-	 * conn - TLS connection context data from tls_connection_init()
-	 */
-	struct tls_connection *conn;
-
-	/**
-	 * tls_out - TLS message to be sent out in fragments
-	 */
-	struct wpabuf *tls_out;
-
-	/**
-	 * tls_out_pos - The current position in the outgoing TLS message
-	 */
-	size_t tls_out_pos;
-
-	/**
-	 * tls_out_limit - Maximum fragment size for outgoing TLS messages
-	 */
-	size_t tls_out_limit;
-
-	/**
-	 * tls_in - Received TLS message buffer for re-assembly
-	 */
-	struct wpabuf *tls_in;
-
-	/**
-	 * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
-	 */
-	int phase2;
-
-	/**
-	 * eap - EAP state machine allocated with eap_server_sm_init()
-	 */
-	struct eap_sm *eap;
-
-	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
-	struct wpabuf tmpbuf;
-};
-
-
-/* EAP TLS Flags */
-#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
-#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
-#define EAP_TLS_FLAGS_START 0x20
-#define EAP_TLS_VERSION_MASK 0x07
-
- /* could be up to 128 bytes, but only the first 64 bytes are used */
-#define EAP_TLS_KEY_LEN 64
-
-
-int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
-			    int verify_peer);
-void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
-u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-			       char *label, size_t len);
-struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
-					 int eap_type, int version, u8 id);
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
-int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data);
-struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
-				       struct eap_ssl_data *data,
-				       const struct wpabuf *plain);
-int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
-			   struct wpabuf *respData, void *priv, int eap_type,
-			   int (*proc_version)(struct eap_sm *sm, void *priv,
-					       int peer_version),
-			   void (*proc_msg)(struct eap_sm *sm, void *priv,
-					    const struct wpabuf *respData));
-
-#endif /* EAP_TLS_COMMON_H */

Copied: vendor/wpa/2.0/src/eap_server/eap_tls_common.h (from rev 9639, vendor/wpa/dist/src/eap_server/eap_tls_common.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/eap_tls_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/eap_tls_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,90 @@
+/*
+ * EAP-TLS/PEAP/TTLS/FAST server common functions
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TLS_COMMON_H
+#define EAP_TLS_COMMON_H
+
+/**
+ * struct eap_ssl_data - TLS data for EAP methods
+ */
+struct eap_ssl_data {
+	/**
+	 * conn - TLS connection context data from tls_connection_init()
+	 */
+	struct tls_connection *conn;
+
+	/**
+	 * tls_out - TLS message to be sent out in fragments
+	 */
+	struct wpabuf *tls_out;
+
+	/**
+	 * tls_out_pos - The current position in the outgoing TLS message
+	 */
+	size_t tls_out_pos;
+
+	/**
+	 * tls_out_limit - Maximum fragment size for outgoing TLS messages
+	 */
+	size_t tls_out_limit;
+
+	/**
+	 * tls_in - Received TLS message buffer for re-assembly
+	 */
+	struct wpabuf *tls_in;
+
+	/**
+	 * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
+	 */
+	int phase2;
+
+	/**
+	 * eap - EAP state machine allocated with eap_server_sm_init()
+	 */
+	struct eap_sm *eap;
+
+	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
+	struct wpabuf tmpbuf;
+};
+
+
+/* EAP TLS Flags */
+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TLS_FLAGS_START 0x20
+#define EAP_TLS_VERSION_MASK 0x07
+
+ /* could be up to 128 bytes, but only the first 64 bytes are used */
+#define EAP_TLS_KEY_LEN 64
+
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
+
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+				  u8 code, u8 identifier);
+int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+			    int verify_peer);
+void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
+u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+			       char *label, size_t len);
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+					 int eap_type, int version, u8 id);
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data);
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+				       struct eap_ssl_data *data,
+				       const struct wpabuf *plain);
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+			   struct wpabuf *respData, void *priv, int eap_type,
+			   int (*proc_version)(struct eap_sm *sm, void *priv,
+					       int peer_version),
+			   void (*proc_msg)(struct eap_sm *sm, void *priv,
+					    const struct wpabuf *respData));
+
+#endif /* EAP_TLS_COMMON_H */

Deleted: vendor/wpa/2.0/src/eap_server/ikev2.c
===================================================================
--- vendor/wpa/dist/src/eap_server/ikev2.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1205 +0,0 @@
-/*
- * IKEv2 initiator (RFC 4306) for EAP-IKEV2
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/dh_groups.h"
-#include "ikev2.h"
-
-
-static int ikev2_process_idr(struct ikev2_initiator_data *data,
-			     const u8 *idr, size_t idr_len);
-
-
-void ikev2_initiator_deinit(struct ikev2_initiator_data *data)
-{
-	ikev2_free_keys(&data->keys);
-	wpabuf_free(data->r_dh_public);
-	wpabuf_free(data->i_dh_private);
-	os_free(data->IDi);
-	os_free(data->IDr);
-	os_free(data->shared_secret);
-	wpabuf_free(data->i_sign_msg);
-	wpabuf_free(data->r_sign_msg);
-	os_free(data->key_pad);
-}
-
-
-static int ikev2_derive_keys(struct ikev2_initiator_data *data)
-{
-	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
-	size_t buf_len, pad_len;
-	struct wpabuf *shared;
-	const struct ikev2_integ_alg *integ;
-	const struct ikev2_prf_alg *prf;
-	const struct ikev2_encr_alg *encr;
-	int ret;
-	const u8 *addr[2];
-	size_t len[2];
-
-	/* RFC 4306, Sect. 2.14 */
-
-	integ = ikev2_get_integ(data->proposal.integ);
-	prf = ikev2_get_prf(data->proposal.prf);
-	encr = ikev2_get_encr(data->proposal.encr);
-	if (integ == NULL || prf == NULL || encr == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
-		return -1;
-	}
-
-	shared = dh_derive_shared(data->r_dh_public, data->i_dh_private,
-				  data->dh);
-	if (shared == NULL)
-		return -1;
-
-	/* Construct Ni | Nr | SPIi | SPIr */
-
-	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
-	buf = os_malloc(buf_len);
-	if (buf == NULL) {
-		wpabuf_free(shared);
-		return -1;
-	}
-
-	pos = buf;
-	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
-	pos += data->i_nonce_len;
-	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
-	pos += data->r_nonce_len;
-	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
-	pos += IKEV2_SPI_LEN;
-	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
-
-	/* SKEYSEED = prf(Ni | Nr, g^ir) */
-
-	/* Use zero-padding per RFC 4306, Sect. 2.14 */
-	pad_len = data->dh->prime_len - wpabuf_len(shared);
-	pad = os_zalloc(pad_len ? pad_len : 1);
-	if (pad == NULL) {
-		wpabuf_free(shared);
-		os_free(buf);
-		return -1;
-	}
-	addr[0] = pad;
-	len[0] = pad_len;
-	addr[1] = wpabuf_head(shared);
-	len[1] = wpabuf_len(shared);
-	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
-			   2, addr, len, skeyseed) < 0) {
-		wpabuf_free(shared);
-		os_free(buf);
-		os_free(pad);
-		return -1;
-	}
-	os_free(pad);
-	wpabuf_free(shared);
-
-	/* DH parameters are not needed anymore, so free them */
-	wpabuf_free(data->r_dh_public);
-	data->r_dh_public = NULL;
-	wpabuf_free(data->i_dh_private);
-	data->i_dh_private = NULL;
-
-	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
-			skeyseed, prf->hash_len);
-
-	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
-				   &data->keys);
-	os_free(buf);
-	return ret;
-}
-
-
-static int ikev2_parse_transform(struct ikev2_initiator_data *data,
-				 struct ikev2_proposal_data *prop,
-				 const u8 *pos, const u8 *end)
-{
-	int transform_len;
-	const struct ikev2_transform *t;
-	u16 transform_id;
-	const u8 *tend;
-
-	if (end - pos < (int) sizeof(*t)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
-		return -1;
-	}
-
-	t = (const struct ikev2_transform *) pos;
-	transform_len = WPA_GET_BE16(t->transform_length);
-	if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
-			   transform_len);
-		return -1;
-	}
-	tend = pos + transform_len;
-
-	transform_id = WPA_GET_BE16(t->transform_id);
-
-	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
-	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
-		   "Transform Type: %d  Transform ID: %d",
-		   t->type, transform_len, t->transform_type, transform_id);
-
-	if (t->type != 0 && t->type != 3) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
-		return -1;
-	}
-
-	pos = (const u8 *) (t + 1);
-	if (pos < tend) {
-		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
-			    pos, tend - pos);
-	}
-
-	switch (t->transform_type) {
-	case IKEV2_TRANSFORM_ENCR:
-		if (ikev2_get_encr(transform_id) &&
-		    transform_id == data->proposal.encr) {
-			if (transform_id == ENCR_AES_CBC) {
-				if (tend - pos != 4) {
-					wpa_printf(MSG_DEBUG, "IKEV2: No "
-						   "Transform Attr for AES");
-					break;
-				}
-				if (WPA_GET_BE16(pos) != 0x800e) {
-					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
-						   "Key Size attribute for "
-						   "AES");
-					break;
-				}
-				if (WPA_GET_BE16(pos + 2) != 128) {
-					wpa_printf(MSG_DEBUG, "IKEV2: "
-						   "Unsupported AES key size "
-						   "%d bits",
-						   WPA_GET_BE16(pos + 2));
-					break;
-				}
-			}
-			prop->encr = transform_id;
-		}
-		break;
-	case IKEV2_TRANSFORM_PRF:
-		if (ikev2_get_prf(transform_id) &&
-		    transform_id == data->proposal.prf)
-			prop->prf = transform_id;
-		break;
-	case IKEV2_TRANSFORM_INTEG:
-		if (ikev2_get_integ(transform_id) &&
-		    transform_id == data->proposal.integ)
-			prop->integ = transform_id;
-		break;
-	case IKEV2_TRANSFORM_DH:
-		if (dh_groups_get(transform_id) &&
-		    transform_id == data->proposal.dh)
-			prop->dh = transform_id;
-		break;
-	}
-
-	return transform_len;
-}
-
-
-static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
-				struct ikev2_proposal_data *prop,
-				const u8 *pos, const u8 *end)
-{
-	const u8 *pend, *ppos;
-	int proposal_len, i;
-	const struct ikev2_proposal *p;
-
-	if (end - pos < (int) sizeof(*p)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
-		return -1;
-	}
-
-	p = (const struct ikev2_proposal *) pos;
-	proposal_len = WPA_GET_BE16(p->proposal_length);
-	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
-			   proposal_len);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
-		   p->proposal_num);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
-		   " Protocol ID: %d",
-		   p->type, proposal_len, p->protocol_id);
-	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
-		   p->spi_size, p->num_transforms);
-
-	if (p->type != 0 && p->type != 2) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
-		return -1;
-	}
-
-	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
-			   "(only IKE allowed for EAP-IKEv2)");
-		return -1;
-	}
-
-	if (p->proposal_num != prop->proposal_num) {
-		if (p->proposal_num == prop->proposal_num + 1)
-			prop->proposal_num = p->proposal_num;
-		else {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
-			return -1;
-		}
-	}
-
-	ppos = (const u8 *) (p + 1);
-	pend = pos + proposal_len;
-	if (ppos + p->spi_size > pend) {
-		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
-			   "in proposal");
-		return -1;
-	}
-	if (p->spi_size) {
-		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
-			    ppos, p->spi_size);
-		ppos += p->spi_size;
-	}
-
-	/*
-	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
-	 * subsequent negotiations, it must be 8 for IKE. We only support
-	 * initial case for now.
-	 */
-	if (p->spi_size != 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
-		return -1;
-	}
-
-	if (p->num_transforms == 0) {
-		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
-		return -1;
-	}
-
-	for (i = 0; i < (int) p->num_transforms; i++) {
-		int tlen = ikev2_parse_transform(data, prop, ppos, pend);
-		if (tlen < 0)
-			return -1;
-		ppos += tlen;
-	}
-
-	if (ppos != pend) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
-			   "transforms");
-		return -1;
-	}
-
-	return proposal_len;
-}
-
-
-static int ikev2_process_sar1(struct ikev2_initiator_data *data,
-			      const u8 *sar1, size_t sar1_len)
-{
-	struct ikev2_proposal_data prop;
-	const u8 *pos, *end;
-	int found = 0;
-
-	/* Security Association Payloads: <Proposals> */
-
-	if (sar1 == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: SAr1 not received");
-		return -1;
-	}
-
-	os_memset(&prop, 0, sizeof(prop));
-	prop.proposal_num = 1;
-
-	pos = sar1;
-	end = sar1 + sar1_len;
-
-	while (pos < end) {
-		int plen;
-
-		prop.integ = -1;
-		prop.prf = -1;
-		prop.encr = -1;
-		prop.dh = -1;
-		plen = ikev2_parse_proposal(data, &prop, pos, end);
-		if (plen < 0)
-			return -1;
-
-		if (!found && prop.integ != -1 && prop.prf != -1 &&
-		    prop.encr != -1 && prop.dh != -1) {
-			found = 1;
-		}
-
-		pos += plen;
-
-		/* Only one proposal expected in SAr */
-		break;
-	}
-
-	if (pos != end) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposal");
-		return -1;
-	}
-
-	if (!found) {
-		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
-		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
-		   data->proposal.encr, data->proposal.prf,
-		   data->proposal.integ, data->proposal.dh);
-
-	return 0;
-}
-
-
-static int ikev2_process_ker(struct ikev2_initiator_data *data,
-			     const u8 *ker, size_t ker_len)
-{
-	u16 group;
-
-	/*
-	 * Key Exchange Payload:
-	 * DH Group # (16 bits)
-	 * RESERVED (16 bits)
-	 * Key Exchange Data (Diffie-Hellman public value)
-	 */
-
-	if (ker == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: KEr not received");
-		return -1;
-	}
-
-	if (ker_len < 4 + 96) {
-		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
-		return -1;
-	}
-
-	group = WPA_GET_BE16(ker);
-	wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u", group);
-
-	if (group != data->proposal.dh) {
-		wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match "
-			   "with the selected proposal (%u)",
-			   group, data->proposal.dh);
-		return -1;
-	}
-
-	if (data->dh == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
-		return -1;
-	}
-
-	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
-	 * prime modulus.
-	 */
-	if (ker_len - 4 != data->dh->prime_len) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
-			   "%ld (expected %ld)",
-			   (long) (ker_len - 4), (long) data->dh->prime_len);
-		return -1;
-	}
-
-	wpabuf_free(data->r_dh_public);
-	data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4);
-	if (data->r_dh_public == NULL)
-		return -1;
-
-	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value",
-			data->r_dh_public);
-	
-	return 0;
-}
-
-
-static int ikev2_process_nr(struct ikev2_initiator_data *data,
-			    const u8 *nr, size_t nr_len)
-{
-	if (nr == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Nr not received");
-		return -1;
-	}
-
-	if (nr_len < IKEV2_NONCE_MIN_LEN || nr_len > IKEV2_NONCE_MAX_LEN) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid Nr length %ld",
-			   (long) nr_len);
-		return -1;
-	}
-
-	data->r_nonce_len = nr_len;
-	os_memcpy(data->r_nonce, nr, nr_len);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Nr",
-		    data->r_nonce, data->r_nonce_len);
-
-	return 0;
-}
-
-
-static int ikev2_process_sa_init_encr(struct ikev2_initiator_data *data,
-				      const struct ikev2_hdr *hdr,
-				      const u8 *encrypted,
-				      size_t encrypted_len, u8 next_payload)
-{
-	u8 *decrypted;
-	size_t decrypted_len;
-	struct ikev2_payloads pl;
-	int ret = 0;
-
-	decrypted = ikev2_decrypt_payload(data->proposal.encr,
-					  data->proposal.integ, &data->keys, 0,
-					  hdr, encrypted, encrypted_len,
-					  &decrypted_len);
-	if (decrypted == NULL)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
-
-	if (ikev2_parse_payloads(&pl, next_payload, decrypted,
-				 decrypted + decrypted_len) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
-			   "payloads");
-		return -1;
-	}
-
-	if (pl.idr)
-		ret = ikev2_process_idr(data, pl.idr, pl.idr_len);
-
-	os_free(decrypted);
-
-	return ret;
-}
-
-
-static int ikev2_process_sa_init(struct ikev2_initiator_data *data,
-				 const struct ikev2_hdr *hdr,
-				 struct ikev2_payloads *pl)
-{
-	if (ikev2_process_sar1(data, pl->sa, pl->sa_len) < 0 ||
-	    ikev2_process_ker(data, pl->ke, pl->ke_len) < 0 ||
-	    ikev2_process_nr(data, pl->nonce, pl->nonce_len) < 0)
-		return -1;
-
-	os_memcpy(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN);
-
-	if (ikev2_derive_keys(data) < 0)
-		return -1;
-
-	if (pl->encrypted) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Encrypted payload in SA_INIT - "
-			   "try to get IDr from it");
-		if (ikev2_process_sa_init_encr(data, hdr, pl->encrypted,
-					       pl->encrypted_len,
-					       pl->encr_next_payload) < 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Failed to process "
-				   "encrypted payload");
-			return -1;
-		}
-	}
-
-	data->state = SA_AUTH;
-
-	return 0;
-}
-
-
-static int ikev2_process_idr(struct ikev2_initiator_data *data,
-			     const u8 *idr, size_t idr_len)
-{
-	u8 id_type;
-
-	if (idr == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No IDr received");
-		return -1;
-	}
-
-	if (idr_len < 4) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short IDr payload");
-		return -1;
-	}
-
-	id_type = idr[0];
-	idr += 4;
-	idr_len -= 4;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: IDr ID Type %d", id_type);
-	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDr", idr, idr_len);
-	if (data->IDr) {
-		if (id_type != data->IDr_type || idr_len != data->IDr_len ||
-		    os_memcmp(idr, data->IDr, idr_len) != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: IDr differs from the one "
-				   "received earlier");
-			wpa_printf(MSG_DEBUG, "IKEV2: Previous IDr ID Type %d",
-				   id_type);
-			wpa_hexdump_ascii(MSG_DEBUG, "Previous IKEV2: IDr",
-					  data->IDr, data->IDr_len);
-			return -1;
-		}
-		os_free(data->IDr);
-	}
-	data->IDr = os_malloc(idr_len);
-	if (data->IDr == NULL)
-		return -1;
-	os_memcpy(data->IDr, idr, idr_len);
-	data->IDr_len = idr_len;
-	data->IDr_type = id_type;
-
-	return 0;
-}
-
-
-static int ikev2_process_cert(struct ikev2_initiator_data *data,
-			      const u8 *cert, size_t cert_len)
-{
-	u8 cert_encoding;
-
-	if (cert == NULL) {
-		if (data->peer_auth == PEER_AUTH_CERT) {
-			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
-			return -1;
-		}
-		return 0;
-	}
-
-	if (cert_len < 1) {
-		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
-		return -1;
-	}
-
-	cert_encoding = cert[0];
-	cert++;
-	cert_len--;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
-
-	/* TODO: validate certificate */
-
-	return 0;
-}
-
-
-static int ikev2_process_auth_cert(struct ikev2_initiator_data *data,
-				   u8 method, const u8 *auth, size_t auth_len)
-{
-	if (method != AUTH_RSA_SIGN) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
-			   "method %d", method);
-		return -1;
-	}
-
-	/* TODO: validate AUTH */
-	return 0;
-}
-
-
-static int ikev2_process_auth_secret(struct ikev2_initiator_data *data,
-				     u8 method, const u8 *auth,
-				     size_t auth_len)
-{
-	u8 auth_data[IKEV2_MAX_HASH_LEN];
-	const struct ikev2_prf_alg *prf;
-
-	if (method != AUTH_SHARED_KEY_MIC) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
-			   "method %d", method);
-		return -1;
-	}
-
-	/* msg | Ni | prf(SK_pr,IDr') */
-	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
-				   data->IDr, data->IDr_len, data->IDr_type,
-				   &data->keys, 0, data->shared_secret,
-				   data->shared_secret_len,
-				   data->i_nonce, data->i_nonce_len,
-				   data->key_pad, data->key_pad_len,
-				   auth_data) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
-		return -1;
-	}
-
-	wpabuf_free(data->r_sign_msg);
-	data->r_sign_msg = NULL;
-
-	prf = ikev2_get_prf(data->proposal.prf);
-	if (prf == NULL)
-		return -1;
-
-	if (auth_len != prf->hash_len ||
-	    os_memcmp(auth, auth_data, auth_len) != 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
-		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
-			    auth, auth_len);
-		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
-			    auth_data, prf->hash_len);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully "
-		   "using shared keys");
-
-	return 0;
-}
-
-
-static int ikev2_process_auth(struct ikev2_initiator_data *data,
-			      const u8 *auth, size_t auth_len)
-{
-	u8 auth_method;
-
-	if (auth == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
-		return -1;
-	}
-
-	if (auth_len < 4) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
-			   "Payload");
-		return -1;
-	}
-
-	auth_method = auth[0];
-	auth += 4;
-	auth_len -= 4;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
-	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
-
-	switch (data->peer_auth) {
-	case PEER_AUTH_CERT:
-		return ikev2_process_auth_cert(data, auth_method, auth,
-					       auth_len);
-	case PEER_AUTH_SECRET:
-		return ikev2_process_auth_secret(data, auth_method, auth,
-						 auth_len);
-	}
-
-	return -1;
-}
-
-
-static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data,
-					   u8 next_payload,
-					   u8 *payload, size_t payload_len)
-{
-	struct ikev2_payloads pl;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
-
-	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
-				 payload_len) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
-			   "payloads");
-		return -1;
-	}
-
-	if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 ||
-	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
-	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
-		return -1;
-
-	return 0;
-}
-
-
-static int ikev2_process_sa_auth(struct ikev2_initiator_data *data,
-				 const struct ikev2_hdr *hdr,
-				 struct ikev2_payloads *pl)
-{
-	u8 *decrypted;
-	size_t decrypted_len;
-	int ret;
-
-	decrypted = ikev2_decrypt_payload(data->proposal.encr,
-					  data->proposal.integ,
-					  &data->keys, 0, hdr, pl->encrypted,
-					  pl->encrypted_len, &decrypted_len);
-	if (decrypted == NULL)
-		return -1;
-
-	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
-					      decrypted, decrypted_len);
-	os_free(decrypted);
-
-	if (ret == 0 && !data->unknown_user) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed");
-		data->state = IKEV2_DONE;
-	}
-
-	return ret;
-}
-
-
-static int ikev2_validate_rx_state(struct ikev2_initiator_data *data,
-				   u8 exchange_type, u32 message_id)
-{
-	switch (data->state) {
-	case SA_INIT:
-		/* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ],
-		 * [SK{IDr}] */
-		if (exchange_type != IKE_SA_INIT) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in SA_INIT state", exchange_type);
-			return -1;
-		}
-		if (message_id != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in SA_INIT state", message_id);
-			return -1;
-		}
-		break;
-	case SA_AUTH:
-		/* Expect to receive IKE_SA_AUTH:
-		 * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH}
-		 */
-		if (exchange_type != IKE_SA_AUTH) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in SA_AUTH state", exchange_type);
-			return -1;
-		}
-		if (message_id != 1) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in SA_AUTH state", message_id);
-			return -1;
-		}
-		break;
-	case CHILD_SA:
-		if (exchange_type != CREATE_CHILD_SA) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
-				   "%u in CHILD_SA state", exchange_type);
-			return -1;
-		}
-		if (message_id != 2) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
-				   "in CHILD_SA state", message_id);
-			return -1;
-		}
-		break;
-	case IKEV2_DONE:
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int ikev2_initiator_process(struct ikev2_initiator_data *data,
-			    const struct wpabuf *buf)
-{
-	const struct ikev2_hdr *hdr;
-	u32 length, message_id;
-	const u8 *pos, *end;
-	struct ikev2_payloads pl;
-
-	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
-		   (unsigned long) wpabuf_len(buf));
-
-	if (wpabuf_len(buf) < sizeof(*hdr)) {
-		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
-		return -1;
-	}
-
-	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
-	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
-	message_id = WPA_GET_BE32(hdr->message_id);
-	length = WPA_GET_BE32(hdr->length);
-
-	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
-		    hdr->i_spi, IKEV2_SPI_LEN);
-	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
-		    hdr->r_spi, IKEV2_SPI_LEN);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
-		   "Exchange Type: %u",
-		   hdr->next_payload, hdr->version, hdr->exchange_type);
-	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
-		   message_id, length);
-
-	if (hdr->version != IKEV2_VERSION) {
-		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
-			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
-		return -1;
-	}
-
-	if (length != wpabuf_len(buf)) {
-		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
-			   "RX: %lu)", (unsigned long) length,
-			   (unsigned long) wpabuf_len(buf));
-		return -1;
-	}
-
-	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
-		return -1;
-
-	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
-	    IKEV2_HDR_RESPONSE) {
-		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
-			   hdr->flags);
-		return -1;
-	}
-
-	if (data->state != SA_INIT) {
-		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
-				   "Initiator's SPI");
-			return -1;
-		}
-		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
-			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
-				   "Responder's SPI");
-			return -1;
-		}
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
-		return -1;
-
-	switch (data->state) {
-	case SA_INIT:
-		if (ikev2_process_sa_init(data, hdr, &pl) < 0)
-			return -1;
-		wpabuf_free(data->r_sign_msg);
-		data->r_sign_msg = wpabuf_dup(buf);
-		break;
-	case SA_AUTH:
-		if (ikev2_process_sa_auth(data, hdr, &pl) < 0)
-			return -1;
-		break;
-	case CHILD_SA:
-	case IKEV2_DONE:
-		break;
-	}
-
-	return 0;
-}
-
-
-static void ikev2_build_hdr(struct ikev2_initiator_data *data,
-			    struct wpabuf *msg, u8 exchange_type,
-			    u8 next_payload, u32 message_id)
-{
-	struct ikev2_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
-
-	/* HDR - RFC 4306, Sect. 3.1 */
-	hdr = wpabuf_put(msg, sizeof(*hdr));
-	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
-	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
-	hdr->next_payload = next_payload;
-	hdr->version = IKEV2_VERSION;
-	hdr->exchange_type = exchange_type;
-	hdr->flags = IKEV2_HDR_INITIATOR;
-	WPA_PUT_BE32(hdr->message_id, message_id);
-}
-
-
-static int ikev2_build_sai(struct ikev2_initiator_data *data,
-			    struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	struct ikev2_proposal *p;
-	struct ikev2_transform *t;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload");
-
-	/* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-
-	/* TODO: support for multiple proposals */
-	p = wpabuf_put(msg, sizeof(*p));
-	p->proposal_num = data->proposal.proposal_num;
-	p->protocol_id = IKEV2_PROTOCOL_IKE;
-	p->num_transforms = 4;
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	t->transform_type = IKEV2_TRANSFORM_ENCR;
-	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
-	if (data->proposal.encr == ENCR_AES_CBC) {
-		/* Transform Attribute: Key Len = 128 bits */
-		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
-		wpabuf_put_be16(msg, 128); /* 128-bit key */
-	}
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
-	WPA_PUT_BE16(t->transform_length, plen);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_PRF;
-	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	t->type = 3;
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_INTEG;
-	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
-
-	t = wpabuf_put(msg, sizeof(*t));
-	WPA_PUT_BE16(t->transform_length, sizeof(*t));
-	t->transform_type = IKEV2_TRANSFORM_DH;
-	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
-	WPA_PUT_BE16(p->proposal_length, plen);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-
-	return 0;
-}
-
-
-static int ikev2_build_kei(struct ikev2_initiator_data *data,
-			   struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	struct wpabuf *pv;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload");
-
-	data->dh = dh_groups_get(data->proposal.dh);
-	pv = dh_init(data->dh, &data->i_dh_private);
-	if (pv == NULL) {
-		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
-		return -1;
-	}
-
-	/* KEi - RFC 4306, Sect. 3.4 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-
-	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
-	wpabuf_put(msg, 2); /* RESERVED */
-	/*
-	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
-	 * match the length of the prime.
-	 */
-	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
-	wpabuf_put_buf(msg, pv);
-	os_free(pv);
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_ni(struct ikev2_initiator_data *data,
-			  struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload");
-
-	/* Ni - RFC 4306, Sect. 3.9 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len);
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_idi(struct ikev2_initiator_data *data,
-			   struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload");
-
-	if (data->IDi == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: No IDi available");
-		return -1;
-	}
-
-	/* IDi - RFC 4306, Sect. 3.5 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_u8(msg, ID_KEY_ID);
-	wpabuf_put(msg, 3); /* RESERVED */
-	wpabuf_put_data(msg, data->IDi, data->IDi_len);
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static int ikev2_build_auth(struct ikev2_initiator_data *data,
-			    struct wpabuf *msg, u8 next_payload)
-{
-	struct ikev2_payload_hdr *phdr;
-	size_t plen;
-	const struct ikev2_prf_alg *prf;
-
-	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
-
-	prf = ikev2_get_prf(data->proposal.prf);
-	if (prf == NULL)
-		return -1;
-
-	/* Authentication - RFC 4306, Sect. 3.8 */
-	phdr = wpabuf_put(msg, sizeof(*phdr));
-	phdr->next_payload = next_payload;
-	phdr->flags = 0;
-	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
-	wpabuf_put(msg, 3); /* RESERVED */
-
-	/* msg | Nr | prf(SK_pi,IDi') */
-	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
-				   data->IDi, data->IDi_len, ID_KEY_ID,
-				   &data->keys, 1, data->shared_secret,
-				   data->shared_secret_len,
-				   data->r_nonce, data->r_nonce_len,
-				   data->key_pad, data->key_pad_len,
-				   wpabuf_put(msg, prf->hash_len)) < 0) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
-		return -1;
-	}
-	wpabuf_free(data->i_sign_msg);
-	data->i_sign_msg = NULL;
-
-	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
-	WPA_PUT_BE16(phdr->payload_length, plen);
-	return 0;
-}
-
-
-static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data)
-{
-	struct wpabuf *msg;
-
-	/* build IKE_SA_INIT: HDR, SAi, KEi, Ni */
-
-	if (os_get_random(data->i_spi, IKEV2_SPI_LEN))
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI",
-		    data->i_spi, IKEV2_SPI_LEN);
-
-	data->i_nonce_len = IKEV2_NONCE_MIN_LEN;
-	if (os_get_random(data->i_nonce, data->i_nonce_len))
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len);
-
-	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
-	if (msg == NULL)
-		return NULL;
-
-	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
-	if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
-	    ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) ||
-	    ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	ikev2_update_hdr(msg);
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
-
-	wpabuf_free(data->i_sign_msg);
-	data->i_sign_msg = wpabuf_dup(msg);
-
-	return msg;
-}
-
-
-static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data)
-{
-	struct wpabuf *msg, *plain;
-	const u8 *secret;
-	size_t secret_len;
-
-	secret = data->get_shared_secret(data->cb_ctx, data->IDr,
-					 data->IDr_len, &secret_len);
-	if (secret == NULL) {
-		wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - "
-			   "use fake value");
-		/* RFC 5106, Sect. 7:
-		 * Use a random key to fake AUTH generation in order to prevent
-		 * probing of user identities.
-		 */
-		data->unknown_user = 1;
-		os_free(data->shared_secret);
-		data->shared_secret = os_malloc(16);
-		if (data->shared_secret == NULL)
-			return NULL;
-		data->shared_secret_len = 16;
-		if (os_get_random(data->shared_secret, 16))
-			return NULL;
-	} else {
-		os_free(data->shared_secret);
-		data->shared_secret = os_malloc(secret_len);
-		if (data->shared_secret == NULL)
-			return NULL;
-		os_memcpy(data->shared_secret, secret, secret_len);
-		data->shared_secret_len = secret_len;
-	}
-
-	/* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */
-
-	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
-	if (msg == NULL)
-		return NULL;
-	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
-
-	plain = wpabuf_alloc(data->IDr_len + 1000);
-	if (plain == NULL) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
-	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
-	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
-				  &data->keys, 1, msg, plain,
-				  IKEV2_PAYLOAD_IDi)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
-
-	return msg;
-}
-
-
-struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data)
-{
-	switch (data->state) {
-	case SA_INIT:
-		return ikev2_build_sa_init(data);
-	case SA_AUTH:
-		return ikev2_build_sa_auth(data);
-	case CHILD_SA:
-		return NULL;
-	case IKEV2_DONE:
-		return NULL;
-	}
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/eap_server/ikev2.c (from rev 9639, vendor/wpa/dist/src/eap_server/ikev2.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/ikev2.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/ikev2.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1200 @@
+/*
+ * IKEv2 initiator (RFC 4306) for EAP-IKEV2
+ * Copyright (c) 2007, Jouni Malinen <j at 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/dh_groups.h"
+#include "crypto/random.h"
+#include "ikev2.h"
+
+
+static int ikev2_process_idr(struct ikev2_initiator_data *data,
+			     const u8 *idr, size_t idr_len);
+
+
+void ikev2_initiator_deinit(struct ikev2_initiator_data *data)
+{
+	ikev2_free_keys(&data->keys);
+	wpabuf_free(data->r_dh_public);
+	wpabuf_free(data->i_dh_private);
+	os_free(data->IDi);
+	os_free(data->IDr);
+	os_free(data->shared_secret);
+	wpabuf_free(data->i_sign_msg);
+	wpabuf_free(data->r_sign_msg);
+	os_free(data->key_pad);
+}
+
+
+static int ikev2_derive_keys(struct ikev2_initiator_data *data)
+{
+	u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN];
+	size_t buf_len, pad_len;
+	struct wpabuf *shared;
+	const struct ikev2_integ_alg *integ;
+	const struct ikev2_prf_alg *prf;
+	const struct ikev2_encr_alg *encr;
+	int ret;
+	const u8 *addr[2];
+	size_t len[2];
+
+	/* RFC 4306, Sect. 2.14 */
+
+	integ = ikev2_get_integ(data->proposal.integ);
+	prf = ikev2_get_prf(data->proposal.prf);
+	encr = ikev2_get_encr(data->proposal.encr);
+	if (integ == NULL || prf == NULL || encr == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal");
+		return -1;
+	}
+
+	shared = dh_derive_shared(data->r_dh_public, data->i_dh_private,
+				  data->dh);
+	if (shared == NULL)
+		return -1;
+
+	/* Construct Ni | Nr | SPIi | SPIr */
+
+	buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN;
+	buf = os_malloc(buf_len);
+	if (buf == NULL) {
+		wpabuf_free(shared);
+		return -1;
+	}
+
+	pos = buf;
+	os_memcpy(pos, data->i_nonce, data->i_nonce_len);
+	pos += data->i_nonce_len;
+	os_memcpy(pos, data->r_nonce, data->r_nonce_len);
+	pos += data->r_nonce_len;
+	os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
+	pos += IKEV2_SPI_LEN;
+	os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
+
+	/* SKEYSEED = prf(Ni | Nr, g^ir) */
+
+	/* Use zero-padding per RFC 4306, Sect. 2.14 */
+	pad_len = data->dh->prime_len - wpabuf_len(shared);
+	pad = os_zalloc(pad_len ? pad_len : 1);
+	if (pad == NULL) {
+		wpabuf_free(shared);
+		os_free(buf);
+		return -1;
+	}
+	addr[0] = pad;
+	len[0] = pad_len;
+	addr[1] = wpabuf_head(shared);
+	len[1] = wpabuf_len(shared);
+	if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len,
+			   2, addr, len, skeyseed) < 0) {
+		wpabuf_free(shared);
+		os_free(buf);
+		os_free(pad);
+		return -1;
+	}
+	os_free(pad);
+	wpabuf_free(shared);
+
+	/* DH parameters are not needed anymore, so free them */
+	wpabuf_free(data->r_dh_public);
+	data->r_dh_public = NULL;
+	wpabuf_free(data->i_dh_private);
+	data->i_dh_private = NULL;
+
+	wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED",
+			skeyseed, prf->hash_len);
+
+	ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len,
+				   &data->keys);
+	os_free(buf);
+	return ret;
+}
+
+
+static int ikev2_parse_transform(struct ikev2_initiator_data *data,
+				 struct ikev2_proposal_data *prop,
+				 const u8 *pos, const u8 *end)
+{
+	int transform_len;
+	const struct ikev2_transform *t;
+	u16 transform_id;
+	const u8 *tend;
+
+	if (end - pos < (int) sizeof(*t)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short transform");
+		return -1;
+	}
+
+	t = (const struct ikev2_transform *) pos;
+	transform_len = WPA_GET_BE16(t->transform_length);
+	if (transform_len < (int) sizeof(*t) || pos + transform_len > end) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d",
+			   transform_len);
+		return -1;
+	}
+	tend = pos + transform_len;
+
+	transform_id = WPA_GET_BE16(t->transform_id);
+
+	wpa_printf(MSG_DEBUG, "IKEV2:   Transform:");
+	wpa_printf(MSG_DEBUG, "IKEV2:     Type: %d  Transform Length: %d  "
+		   "Transform Type: %d  Transform ID: %d",
+		   t->type, transform_len, t->transform_type, transform_id);
+
+	if (t->type != 0 && t->type != 3) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type");
+		return -1;
+	}
+
+	pos = (const u8 *) (t + 1);
+	if (pos < tend) {
+		wpa_hexdump(MSG_DEBUG, "IKEV2:     Transform Attributes",
+			    pos, tend - pos);
+	}
+
+	switch (t->transform_type) {
+	case IKEV2_TRANSFORM_ENCR:
+		if (ikev2_get_encr(transform_id) &&
+		    transform_id == data->proposal.encr) {
+			if (transform_id == ENCR_AES_CBC) {
+				if (tend - pos != 4) {
+					wpa_printf(MSG_DEBUG, "IKEV2: No "
+						   "Transform Attr for AES");
+					break;
+				}
+				if (WPA_GET_BE16(pos) != 0x800e) {
+					wpa_printf(MSG_DEBUG, "IKEV2: Not a "
+						   "Key Size attribute for "
+						   "AES");
+					break;
+				}
+				if (WPA_GET_BE16(pos + 2) != 128) {
+					wpa_printf(MSG_DEBUG, "IKEV2: "
+						   "Unsupported AES key size "
+						   "%d bits",
+						   WPA_GET_BE16(pos + 2));
+					break;
+				}
+			}
+			prop->encr = transform_id;
+		}
+		break;
+	case IKEV2_TRANSFORM_PRF:
+		if (ikev2_get_prf(transform_id) &&
+		    transform_id == data->proposal.prf)
+			prop->prf = transform_id;
+		break;
+	case IKEV2_TRANSFORM_INTEG:
+		if (ikev2_get_integ(transform_id) &&
+		    transform_id == data->proposal.integ)
+			prop->integ = transform_id;
+		break;
+	case IKEV2_TRANSFORM_DH:
+		if (dh_groups_get(transform_id) &&
+		    transform_id == data->proposal.dh)
+			prop->dh = transform_id;
+		break;
+	}
+
+	return transform_len;
+}
+
+
+static int ikev2_parse_proposal(struct ikev2_initiator_data *data,
+				struct ikev2_proposal_data *prop,
+				const u8 *pos, const u8 *end)
+{
+	const u8 *pend, *ppos;
+	int proposal_len, i;
+	const struct ikev2_proposal *p;
+
+	if (end - pos < (int) sizeof(*p)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short proposal");
+		return -1;
+	}
+
+	p = (const struct ikev2_proposal *) pos;
+	proposal_len = WPA_GET_BE16(p->proposal_length);
+	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
+			   proposal_len);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d",
+		   p->proposal_num);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Type: %d  Proposal Length: %d "
+		   " Protocol ID: %d",
+		   p->type, proposal_len, p->protocol_id);
+	wpa_printf(MSG_DEBUG, "IKEV2:   SPI Size: %d  Transforms: %d",
+		   p->spi_size, p->num_transforms);
+
+	if (p->type != 0 && p->type != 2) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type");
+		return -1;
+	}
+
+	if (p->protocol_id != IKEV2_PROTOCOL_IKE) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID "
+			   "(only IKE allowed for EAP-IKEv2)");
+		return -1;
+	}
+
+	if (p->proposal_num != prop->proposal_num) {
+		if (p->proposal_num == prop->proposal_num + 1)
+			prop->proposal_num = p->proposal_num;
+		else {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #");
+			return -1;
+		}
+	}
+
+	ppos = (const u8 *) (p + 1);
+	pend = pos + proposal_len;
+	if (ppos + p->spi_size > pend) {
+		wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI "
+			   "in proposal");
+		return -1;
+	}
+	if (p->spi_size) {
+		wpa_hexdump(MSG_DEBUG, "IKEV2:    SPI",
+			    ppos, p->spi_size);
+		ppos += p->spi_size;
+	}
+
+	/*
+	 * For initial IKE_SA negotiation, SPI Size MUST be zero; for
+	 * subsequent negotiations, it must be 8 for IKE. We only support
+	 * initial case for now.
+	 */
+	if (p->spi_size != 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size");
+		return -1;
+	}
+
+	if (p->num_transforms == 0) {
+		wpa_printf(MSG_INFO, "IKEV2: At least one transform required");
+		return -1;
+	}
+
+	for (i = 0; i < (int) p->num_transforms; i++) {
+		int tlen = ikev2_parse_transform(data, prop, ppos, pend);
+		if (tlen < 0)
+			return -1;
+		ppos += tlen;
+	}
+
+	if (ppos != pend) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after "
+			   "transforms");
+		return -1;
+	}
+
+	return proposal_len;
+}
+
+
+static int ikev2_process_sar1(struct ikev2_initiator_data *data,
+			      const u8 *sar1, size_t sar1_len)
+{
+	struct ikev2_proposal_data prop;
+	const u8 *pos, *end;
+	int found = 0;
+
+	/* Security Association Payloads: <Proposals> */
+
+	if (sar1 == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: SAr1 not received");
+		return -1;
+	}
+
+	os_memset(&prop, 0, sizeof(prop));
+	prop.proposal_num = 1;
+
+	pos = sar1;
+	end = sar1 + sar1_len;
+
+	while (pos < end) {
+		int plen;
+
+		prop.integ = -1;
+		prop.prf = -1;
+		prop.encr = -1;
+		prop.dh = -1;
+		plen = ikev2_parse_proposal(data, &prop, pos, end);
+		if (plen < 0)
+			return -1;
+
+		if (!found && prop.integ != -1 && prop.prf != -1 &&
+		    prop.encr != -1 && prop.dh != -1) {
+			found = 1;
+		}
+
+		pos += plen;
+
+		/* Only one proposal expected in SAr */
+		break;
+	}
+
+	if (pos != end) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposal");
+		return -1;
+	}
+
+	if (!found) {
+		wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d "
+		   "INTEG:%d D-H:%d", data->proposal.proposal_num,
+		   data->proposal.encr, data->proposal.prf,
+		   data->proposal.integ, data->proposal.dh);
+
+	return 0;
+}
+
+
+static int ikev2_process_ker(struct ikev2_initiator_data *data,
+			     const u8 *ker, size_t ker_len)
+{
+	u16 group;
+
+	/*
+	 * Key Exchange Payload:
+	 * DH Group # (16 bits)
+	 * RESERVED (16 bits)
+	 * Key Exchange Data (Diffie-Hellman public value)
+	 */
+
+	if (ker == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: KEr not received");
+		return -1;
+	}
+
+	if (ker_len < 4 + 96) {
+		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
+		return -1;
+	}
+
+	group = WPA_GET_BE16(ker);
+	wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u", group);
+
+	if (group != data->proposal.dh) {
+		wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match "
+			   "with the selected proposal (%u)",
+			   group, data->proposal.dh);
+		return -1;
+	}
+
+	if (data->dh == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group");
+		return -1;
+	}
+
+	/* RFC 4306, Section 3.4:
+	 * The length of DH public value MUST be equal to the length of the
+	 * prime modulus.
+	 */
+	if (ker_len - 4 != data->dh->prime_len) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length "
+			   "%ld (expected %ld)",
+			   (long) (ker_len - 4), (long) data->dh->prime_len);
+		return -1;
+	}
+
+	wpabuf_free(data->r_dh_public);
+	data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4);
+	if (data->r_dh_public == NULL)
+		return -1;
+
+	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value",
+			data->r_dh_public);
+	
+	return 0;
+}
+
+
+static int ikev2_process_nr(struct ikev2_initiator_data *data,
+			    const u8 *nr, size_t nr_len)
+{
+	if (nr == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Nr not received");
+		return -1;
+	}
+
+	if (nr_len < IKEV2_NONCE_MIN_LEN || nr_len > IKEV2_NONCE_MAX_LEN) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid Nr length %ld",
+			   (long) nr_len);
+		return -1;
+	}
+
+	data->r_nonce_len = nr_len;
+	os_memcpy(data->r_nonce, nr, nr_len);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Nr",
+		    data->r_nonce, data->r_nonce_len);
+
+	return 0;
+}
+
+
+static int ikev2_process_sa_init_encr(struct ikev2_initiator_data *data,
+				      const struct ikev2_hdr *hdr,
+				      const u8 *encrypted,
+				      size_t encrypted_len, u8 next_payload)
+{
+	u8 *decrypted;
+	size_t decrypted_len;
+	struct ikev2_payloads pl;
+	int ret = 0;
+
+	decrypted = ikev2_decrypt_payload(data->proposal.encr,
+					  data->proposal.integ, &data->keys, 0,
+					  hdr, encrypted, encrypted_len,
+					  &decrypted_len);
+	if (decrypted == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
+
+	if (ikev2_parse_payloads(&pl, next_payload, decrypted,
+				 decrypted + decrypted_len) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
+			   "payloads");
+		return -1;
+	}
+
+	if (pl.idr)
+		ret = ikev2_process_idr(data, pl.idr, pl.idr_len);
+
+	os_free(decrypted);
+
+	return ret;
+}
+
+
+static int ikev2_process_sa_init(struct ikev2_initiator_data *data,
+				 const struct ikev2_hdr *hdr,
+				 struct ikev2_payloads *pl)
+{
+	if (ikev2_process_sar1(data, pl->sa, pl->sa_len) < 0 ||
+	    ikev2_process_ker(data, pl->ke, pl->ke_len) < 0 ||
+	    ikev2_process_nr(data, pl->nonce, pl->nonce_len) < 0)
+		return -1;
+
+	os_memcpy(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN);
+
+	if (ikev2_derive_keys(data) < 0)
+		return -1;
+
+	if (pl->encrypted) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Encrypted payload in SA_INIT - "
+			   "try to get IDr from it");
+		if (ikev2_process_sa_init_encr(data, hdr, pl->encrypted,
+					       pl->encrypted_len,
+					       pl->encr_next_payload) < 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Failed to process "
+				   "encrypted payload");
+			return -1;
+		}
+	}
+
+	data->state = SA_AUTH;
+
+	return 0;
+}
+
+
+static int ikev2_process_idr(struct ikev2_initiator_data *data,
+			     const u8 *idr, size_t idr_len)
+{
+	u8 id_type;
+
+	if (idr == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No IDr received");
+		return -1;
+	}
+
+	if (idr_len < 4) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short IDr payload");
+		return -1;
+	}
+
+	id_type = idr[0];
+	idr += 4;
+	idr_len -= 4;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: IDr ID Type %d", id_type);
+	wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDr", idr, idr_len);
+	if (data->IDr) {
+		if (id_type != data->IDr_type || idr_len != data->IDr_len ||
+		    os_memcmp(idr, data->IDr, idr_len) != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: IDr differs from the one "
+				   "received earlier");
+			wpa_printf(MSG_DEBUG, "IKEV2: Previous IDr ID Type %d",
+				   id_type);
+			wpa_hexdump_ascii(MSG_DEBUG, "Previous IKEV2: IDr",
+					  data->IDr, data->IDr_len);
+			return -1;
+		}
+		os_free(data->IDr);
+	}
+	data->IDr = os_malloc(idr_len);
+	if (data->IDr == NULL)
+		return -1;
+	os_memcpy(data->IDr, idr, idr_len);
+	data->IDr_len = idr_len;
+	data->IDr_type = id_type;
+
+	return 0;
+}
+
+
+static int ikev2_process_cert(struct ikev2_initiator_data *data,
+			      const u8 *cert, size_t cert_len)
+{
+	u8 cert_encoding;
+
+	if (cert == NULL) {
+		if (data->peer_auth == PEER_AUTH_CERT) {
+			wpa_printf(MSG_INFO, "IKEV2: No Certificate received");
+			return -1;
+		}
+		return 0;
+	}
+
+	if (cert_len < 1) {
+		wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field");
+		return -1;
+	}
+
+	cert_encoding = cert[0];
+	cert++;
+	cert_len--;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len);
+
+	/* TODO: validate certificate */
+
+	return 0;
+}
+
+
+static int ikev2_process_auth_cert(struct ikev2_initiator_data *data,
+				   u8 method, const u8 *auth, size_t auth_len)
+{
+	if (method != AUTH_RSA_SIGN) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
+			   "method %d", method);
+		return -1;
+	}
+
+	/* TODO: validate AUTH */
+	return 0;
+}
+
+
+static int ikev2_process_auth_secret(struct ikev2_initiator_data *data,
+				     u8 method, const u8 *auth,
+				     size_t auth_len)
+{
+	u8 auth_data[IKEV2_MAX_HASH_LEN];
+	const struct ikev2_prf_alg *prf;
+
+	if (method != AUTH_SHARED_KEY_MIC) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication "
+			   "method %d", method);
+		return -1;
+	}
+
+	/* msg | Ni | prf(SK_pr,IDr') */
+	if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg,
+				   data->IDr, data->IDr_len, data->IDr_type,
+				   &data->keys, 0, data->shared_secret,
+				   data->shared_secret_len,
+				   data->i_nonce, data->i_nonce_len,
+				   data->key_pad, data->key_pad_len,
+				   auth_data) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
+		return -1;
+	}
+
+	wpabuf_free(data->r_sign_msg);
+	data->r_sign_msg = NULL;
+
+	prf = ikev2_get_prf(data->proposal.prf);
+	if (prf == NULL)
+		return -1;
+
+	if (auth_len != prf->hash_len ||
+	    os_memcmp(auth, auth_data, auth_len) != 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
+		wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
+			    auth, auth_len);
+		wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data",
+			    auth_data, prf->hash_len);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully "
+		   "using shared keys");
+
+	return 0;
+}
+
+
+static int ikev2_process_auth(struct ikev2_initiator_data *data,
+			      const u8 *auth, size_t auth_len)
+{
+	u8 auth_method;
+
+	if (auth == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload");
+		return -1;
+	}
+
+	if (auth_len < 4) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short Authentication "
+			   "Payload");
+		return -1;
+	}
+
+	auth_method = auth[0];
+	auth += 4;
+	auth_len -= 4;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method);
+	wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len);
+
+	switch (data->peer_auth) {
+	case PEER_AUTH_CERT:
+		return ikev2_process_auth_cert(data, auth_method, auth,
+					       auth_len);
+	case PEER_AUTH_SECRET:
+		return ikev2_process_auth_secret(data, auth_method, auth,
+						 auth_len);
+	}
+
+	return -1;
+}
+
+
+static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data,
+					   u8 next_payload,
+					   u8 *payload, size_t payload_len)
+{
+	struct ikev2_payloads pl;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads");
+
+	if (ikev2_parse_payloads(&pl, next_payload, payload, payload +
+				 payload_len) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted "
+			   "payloads");
+		return -1;
+	}
+
+	if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 ||
+	    ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 ||
+	    ikev2_process_auth(data, pl.auth, pl.auth_len) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int ikev2_process_sa_auth(struct ikev2_initiator_data *data,
+				 const struct ikev2_hdr *hdr,
+				 struct ikev2_payloads *pl)
+{
+	u8 *decrypted;
+	size_t decrypted_len;
+	int ret;
+
+	decrypted = ikev2_decrypt_payload(data->proposal.encr,
+					  data->proposal.integ,
+					  &data->keys, 0, hdr, pl->encrypted,
+					  pl->encrypted_len, &decrypted_len);
+	if (decrypted == NULL)
+		return -1;
+
+	ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload,
+					      decrypted, decrypted_len);
+	os_free(decrypted);
+
+	if (ret == 0 && !data->unknown_user) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed");
+		data->state = IKEV2_DONE;
+	}
+
+	return ret;
+}
+
+
+static int ikev2_validate_rx_state(struct ikev2_initiator_data *data,
+				   u8 exchange_type, u32 message_id)
+{
+	switch (data->state) {
+	case SA_INIT:
+		/* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ],
+		 * [SK{IDr}] */
+		if (exchange_type != IKE_SA_INIT) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in SA_INIT state", exchange_type);
+			return -1;
+		}
+		if (message_id != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in SA_INIT state", message_id);
+			return -1;
+		}
+		break;
+	case SA_AUTH:
+		/* Expect to receive IKE_SA_AUTH:
+		 * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH}
+		 */
+		if (exchange_type != IKE_SA_AUTH) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in SA_AUTH state", exchange_type);
+			return -1;
+		}
+		if (message_id != 1) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in SA_AUTH state", message_id);
+			return -1;
+		}
+		break;
+	case CHILD_SA:
+		if (exchange_type != CREATE_CHILD_SA) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type "
+				   "%u in CHILD_SA state", exchange_type);
+			return -1;
+		}
+		if (message_id != 2) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u "
+				   "in CHILD_SA state", message_id);
+			return -1;
+		}
+		break;
+	case IKEV2_DONE:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int ikev2_initiator_process(struct ikev2_initiator_data *data,
+			    const struct wpabuf *buf)
+{
+	const struct ikev2_hdr *hdr;
+	u32 length, message_id;
+	const u8 *pos, *end;
+	struct ikev2_payloads pl;
+
+	wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)",
+		   (unsigned long) wpabuf_len(buf));
+
+	if (wpabuf_len(buf) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR");
+		return -1;
+	}
+
+	hdr = (const struct ikev2_hdr *) wpabuf_head(buf);
+	end = wpabuf_head_u8(buf) + wpabuf_len(buf);
+	message_id = WPA_GET_BE32(hdr->message_id);
+	length = WPA_GET_BE32(hdr->length);
+
+	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
+		    hdr->i_spi, IKEV2_SPI_LEN);
+	wpa_hexdump(MSG_DEBUG, "IKEV2:   IKE_SA Initiator's SPI",
+		    hdr->r_spi, IKEV2_SPI_LEN);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Version: 0x%x  "
+		   "Exchange Type: %u",
+		   hdr->next_payload, hdr->version, hdr->exchange_type);
+	wpa_printf(MSG_DEBUG, "IKEV2:   Message ID: %u  Length: %u",
+		   message_id, length);
+
+	if (hdr->version != IKEV2_VERSION) {
+		wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x "
+			   "(expected 0x%x)", hdr->version, IKEV2_VERSION);
+		return -1;
+	}
+
+	if (length != wpabuf_len(buf)) {
+		wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != "
+			   "RX: %lu)", (unsigned long) length,
+			   (unsigned long) wpabuf_len(buf));
+		return -1;
+	}
+
+	if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0)
+		return -1;
+
+	if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) !=
+	    IKEV2_HDR_RESPONSE) {
+		wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x",
+			   hdr->flags);
+		return -1;
+	}
+
+	if (data->state != SA_INIT) {
+		if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
+				   "Initiator's SPI");
+			return -1;
+		}
+		if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) {
+			wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA "
+				   "Responder's SPI");
+			return -1;
+		}
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0)
+		return -1;
+
+	switch (data->state) {
+	case SA_INIT:
+		if (ikev2_process_sa_init(data, hdr, &pl) < 0)
+			return -1;
+		wpabuf_free(data->r_sign_msg);
+		data->r_sign_msg = wpabuf_dup(buf);
+		break;
+	case SA_AUTH:
+		if (ikev2_process_sa_auth(data, hdr, &pl) < 0)
+			return -1;
+		break;
+	case CHILD_SA:
+	case IKEV2_DONE:
+		break;
+	}
+
+	return 0;
+}
+
+
+static void ikev2_build_hdr(struct ikev2_initiator_data *data,
+			    struct wpabuf *msg, u8 exchange_type,
+			    u8 next_payload, u32 message_id)
+{
+	struct ikev2_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR");
+
+	/* HDR - RFC 4306, Sect. 3.1 */
+	hdr = wpabuf_put(msg, sizeof(*hdr));
+	os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN);
+	os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN);
+	hdr->next_payload = next_payload;
+	hdr->version = IKEV2_VERSION;
+	hdr->exchange_type = exchange_type;
+	hdr->flags = IKEV2_HDR_INITIATOR;
+	WPA_PUT_BE32(hdr->message_id, message_id);
+}
+
+
+static int ikev2_build_sai(struct ikev2_initiator_data *data,
+			    struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	struct ikev2_proposal *p;
+	struct ikev2_transform *t;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload");
+
+	/* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+
+	/* TODO: support for multiple proposals */
+	p = wpabuf_put(msg, sizeof(*p));
+	p->proposal_num = data->proposal.proposal_num;
+	p->protocol_id = IKEV2_PROTOCOL_IKE;
+	p->num_transforms = 4;
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	t->transform_type = IKEV2_TRANSFORM_ENCR;
+	WPA_PUT_BE16(t->transform_id, data->proposal.encr);
+	if (data->proposal.encr == ENCR_AES_CBC) {
+		/* Transform Attribute: Key Len = 128 bits */
+		wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
+		wpabuf_put_be16(msg, 128); /* 128-bit key */
+	}
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
+	WPA_PUT_BE16(t->transform_length, plen);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_PRF;
+	WPA_PUT_BE16(t->transform_id, data->proposal.prf);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	t->type = 3;
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_INTEG;
+	WPA_PUT_BE16(t->transform_id, data->proposal.integ);
+
+	t = wpabuf_put(msg, sizeof(*t));
+	WPA_PUT_BE16(t->transform_length, sizeof(*t));
+	t->transform_type = IKEV2_TRANSFORM_DH;
+	WPA_PUT_BE16(t->transform_id, data->proposal.dh);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p;
+	WPA_PUT_BE16(p->proposal_length, plen);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+
+	return 0;
+}
+
+
+static int ikev2_build_kei(struct ikev2_initiator_data *data,
+			   struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	struct wpabuf *pv;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload");
+
+	data->dh = dh_groups_get(data->proposal.dh);
+	pv = dh_init(data->dh, &data->i_dh_private);
+	if (pv == NULL) {
+		wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH");
+		return -1;
+	}
+
+	/* KEi - RFC 4306, Sect. 3.4 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+
+	wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */
+	wpabuf_put(msg, 2); /* RESERVED */
+	/*
+	 * RFC 4306, Sect. 3.4: possible zero padding for public value to
+	 * match the length of the prime.
+	 */
+	wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
+	wpabuf_put_buf(msg, pv);
+	os_free(pv);
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_ni(struct ikev2_initiator_data *data,
+			  struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload");
+
+	/* Ni - RFC 4306, Sect. 3.9 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len);
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_idi(struct ikev2_initiator_data *data,
+			   struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload");
+
+	if (data->IDi == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: No IDi available");
+		return -1;
+	}
+
+	/* IDi - RFC 4306, Sect. 3.5 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_u8(msg, ID_KEY_ID);
+	wpabuf_put(msg, 3); /* RESERVED */
+	wpabuf_put_data(msg, data->IDi, data->IDi_len);
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static int ikev2_build_auth(struct ikev2_initiator_data *data,
+			    struct wpabuf *msg, u8 next_payload)
+{
+	struct ikev2_payload_hdr *phdr;
+	size_t plen;
+	const struct ikev2_prf_alg *prf;
+
+	wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload");
+
+	prf = ikev2_get_prf(data->proposal.prf);
+	if (prf == NULL)
+		return -1;
+
+	/* Authentication - RFC 4306, Sect. 3.8 */
+	phdr = wpabuf_put(msg, sizeof(*phdr));
+	phdr->next_payload = next_payload;
+	phdr->flags = 0;
+	wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC);
+	wpabuf_put(msg, 3); /* RESERVED */
+
+	/* msg | Nr | prf(SK_pi,IDi') */
+	if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg,
+				   data->IDi, data->IDi_len, ID_KEY_ID,
+				   &data->keys, 1, data->shared_secret,
+				   data->shared_secret_len,
+				   data->r_nonce, data->r_nonce_len,
+				   data->key_pad, data->key_pad_len,
+				   wpabuf_put(msg, prf->hash_len)) < 0) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data");
+		return -1;
+	}
+	wpabuf_free(data->i_sign_msg);
+	data->i_sign_msg = NULL;
+
+	plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
+	WPA_PUT_BE16(phdr->payload_length, plen);
+	return 0;
+}
+
+
+static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data)
+{
+	struct wpabuf *msg;
+
+	/* build IKE_SA_INIT: HDR, SAi, KEi, Ni */
+
+	if (os_get_random(data->i_spi, IKEV2_SPI_LEN))
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI",
+		    data->i_spi, IKEV2_SPI_LEN);
+
+	data->i_nonce_len = IKEV2_NONCE_MIN_LEN;
+	if (random_get_bytes(data->i_nonce, data->i_nonce_len))
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len);
+
+	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000);
+	if (msg == NULL)
+		return NULL;
+
+	ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0);
+	if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) ||
+	    ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) ||
+	    ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	ikev2_update_hdr(msg);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg);
+
+	wpabuf_free(data->i_sign_msg);
+	data->i_sign_msg = wpabuf_dup(msg);
+
+	return msg;
+}
+
+
+static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data)
+{
+	struct wpabuf *msg, *plain;
+	const u8 *secret;
+	size_t secret_len;
+
+	secret = data->get_shared_secret(data->cb_ctx, data->IDr,
+					 data->IDr_len, &secret_len);
+	if (secret == NULL) {
+		wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - "
+			   "use fake value");
+		/* RFC 5106, Sect. 7:
+		 * Use a random key to fake AUTH generation in order to prevent
+		 * probing of user identities.
+		 */
+		data->unknown_user = 1;
+		os_free(data->shared_secret);
+		data->shared_secret = os_malloc(16);
+		if (data->shared_secret == NULL)
+			return NULL;
+		data->shared_secret_len = 16;
+		if (random_get_bytes(data->shared_secret, 16))
+			return NULL;
+	} else {
+		os_free(data->shared_secret);
+		data->shared_secret = os_malloc(secret_len);
+		if (data->shared_secret == NULL)
+			return NULL;
+		os_memcpy(data->shared_secret, secret, secret_len);
+		data->shared_secret_len = secret_len;
+	}
+
+	/* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */
+
+	msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000);
+	if (msg == NULL)
+		return NULL;
+	ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1);
+
+	plain = wpabuf_alloc(data->IDr_len + 1000);
+	if (plain == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) ||
+	    ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) ||
+	    ikev2_build_encrypted(data->proposal.encr, data->proposal.integ,
+				  &data->keys, 1, msg, plain,
+				  IKEV2_PAYLOAD_IDi)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg);
+
+	return msg;
+}
+
+
+struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data)
+{
+	switch (data->state) {
+	case SA_INIT:
+		return ikev2_build_sa_init(data);
+	case SA_AUTH:
+		return ikev2_build_sa_auth(data);
+	case CHILD_SA:
+		return NULL;
+	case IKEV2_DONE:
+		return NULL;
+	}
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/eap_server/ikev2.h
===================================================================
--- vendor/wpa/dist/src/eap_server/ikev2.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/ikev2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,67 +0,0 @@
-/*
- * IKEv2 initiator (RFC 4306) for EAP-IKEV2
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IKEV2_H
-#define IKEV2_H
-
-#include "eap_common/ikev2_common.h"
-
-struct ikev2_proposal_data {
-	u8 proposal_num;
-	int integ;
-	int prf;
-	int encr;
-	int dh;
-};
-
-
-struct ikev2_initiator_data {
-	enum { SA_INIT, SA_AUTH, CHILD_SA, IKEV2_DONE } state;
-	u8 i_spi[IKEV2_SPI_LEN];
-	u8 r_spi[IKEV2_SPI_LEN];
-	u8 i_nonce[IKEV2_NONCE_MAX_LEN];
-	size_t i_nonce_len;
-	u8 r_nonce[IKEV2_NONCE_MAX_LEN];
-	size_t r_nonce_len;
-	struct wpabuf *r_dh_public;
-	struct wpabuf *i_dh_private;
-	struct ikev2_proposal_data proposal;
-	const struct dh_group *dh;
-	struct ikev2_keys keys;
-	u8 *IDi;
-	size_t IDi_len;
-	u8 *IDr;
-	size_t IDr_len;
-	u8 IDr_type;
-	struct wpabuf *r_sign_msg;
-	struct wpabuf *i_sign_msg;
-	u8 *shared_secret;
-	size_t shared_secret_len;
-	enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth;
-	u8 *key_pad;
-	size_t key_pad_len;
-
-	const u8 * (*get_shared_secret)(void *ctx, const u8 *IDr,
-					size_t IDr_len, size_t *secret_len);
-	void *cb_ctx;
-	int unknown_user;
-};
-
-
-void ikev2_initiator_deinit(struct ikev2_initiator_data *data);
-int ikev2_initiator_process(struct ikev2_initiator_data *data,
-			    const struct wpabuf *buf);
-struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data);
-
-#endif /* IKEV2_H */

Copied: vendor/wpa/2.0/src/eap_server/ikev2.h (from rev 9639, vendor/wpa/dist/src/eap_server/ikev2.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/ikev2.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/ikev2.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,61 @@
+/*
+ * IKEv2 initiator (RFC 4306) for EAP-IKEV2
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IKEV2_H
+#define IKEV2_H
+
+#include "eap_common/ikev2_common.h"
+
+struct ikev2_proposal_data {
+	u8 proposal_num;
+	int integ;
+	int prf;
+	int encr;
+	int dh;
+};
+
+
+struct ikev2_initiator_data {
+	enum { SA_INIT, SA_AUTH, CHILD_SA, IKEV2_DONE } state;
+	u8 i_spi[IKEV2_SPI_LEN];
+	u8 r_spi[IKEV2_SPI_LEN];
+	u8 i_nonce[IKEV2_NONCE_MAX_LEN];
+	size_t i_nonce_len;
+	u8 r_nonce[IKEV2_NONCE_MAX_LEN];
+	size_t r_nonce_len;
+	struct wpabuf *r_dh_public;
+	struct wpabuf *i_dh_private;
+	struct ikev2_proposal_data proposal;
+	const struct dh_group *dh;
+	struct ikev2_keys keys;
+	u8 *IDi;
+	size_t IDi_len;
+	u8 *IDr;
+	size_t IDr_len;
+	u8 IDr_type;
+	struct wpabuf *r_sign_msg;
+	struct wpabuf *i_sign_msg;
+	u8 *shared_secret;
+	size_t shared_secret_len;
+	enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth;
+	u8 *key_pad;
+	size_t key_pad_len;
+
+	const u8 * (*get_shared_secret)(void *ctx, const u8 *IDr,
+					size_t IDr_len, size_t *secret_len);
+	void *cb_ctx;
+	int unknown_user;
+};
+
+
+void ikev2_initiator_deinit(struct ikev2_initiator_data *data);
+int ikev2_initiator_process(struct ikev2_initiator_data *data,
+			    const struct wpabuf *buf);
+struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data);
+
+#endif /* IKEV2_H */

Deleted: vendor/wpa/2.0/src/eap_server/tncs.c
===================================================================
--- vendor/wpa/dist/src/eap_server/tncs.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/tncs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1273 +0,0 @@
-/*
- * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
- * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-#include "base64.h"
-#include "tncs.h"
-#include "eap_common/eap_tlv_common.h"
-#include "eap_common/eap_defs.h"
-
-
-/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
- * needed.. */
-
-#define TNC_CONFIG_FILE "/etc/tnc_config"
-#define IF_TNCCS_START \
-"<?xml version=\"1.0\"?>\n" \
-"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
-"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
-"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
-"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
-"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
-#define IF_TNCCS_END "\n</TNCCS-Batch>"
-
-/* TNC IF-IMV */
-
-typedef unsigned long TNC_UInt32;
-typedef unsigned char *TNC_BufferReference;
-
-typedef TNC_UInt32 TNC_IMVID;
-typedef TNC_UInt32 TNC_ConnectionID;
-typedef TNC_UInt32 TNC_ConnectionState;
-typedef TNC_UInt32 TNC_RetryReason;
-typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
-typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
-typedef TNC_UInt32 TNC_MessageType;
-typedef TNC_MessageType *TNC_MessageTypeList;
-typedef TNC_UInt32 TNC_VendorID;
-typedef TNC_UInt32 TNC_Subtype;
-typedef TNC_UInt32 TNC_Version;
-typedef TNC_UInt32 TNC_Result;
-typedef TNC_UInt32 TNC_AttributeID;
-
-typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
-	TNC_IMVID imvID,
-	char *functionName,
-	void **pOutfunctionPointer);
-
-#define TNC_RESULT_SUCCESS 0
-#define TNC_RESULT_NOT_INITIALIZED 1
-#define TNC_RESULT_ALREADY_INITIALIZED 2
-#define TNC_RESULT_NO_COMMON_VERSION 3
-#define TNC_RESULT_CANT_RETRY 4
-#define TNC_RESULT_WONT_RETRY 5
-#define TNC_RESULT_INVALID_PARAMETER 6
-#define TNC_RESULT_CANT_RESPOND 7
-#define TNC_RESULT_ILLEGAL_OPERATION 8
-#define TNC_RESULT_OTHER 9
-#define TNC_RESULT_FATAL 10
-
-#define TNC_CONNECTION_STATE_CREATE 0
-#define TNC_CONNECTION_STATE_HANDSHAKE 1
-#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
-#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
-#define TNC_CONNECTION_STATE_ACCESS_NONE 4
-#define TNC_CONNECTION_STATE_DELETE 5
-
-#define TNC_IFIMV_VERSION_1 1
-
-#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
-#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
-
-/* TNCC-TNCS Message Types */
-#define TNC_TNCCS_RECOMMENDATION		0x00000001
-#define TNC_TNCCS_ERROR				0x00000002
-#define TNC_TNCCS_PREFERREDLANGUAGE		0x00000003
-#define TNC_TNCCS_REASONSTRINGS			0x00000004
-
-/* Possible TNC_IMV_Action_Recommendation values: */
-enum IMV_Action_Recommendation {
-	TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
-	TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
-	TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
-	TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
-};
-
-/* Possible TNC_IMV_Evaluation_Result values: */
-enum IMV_Evaluation_Result {
-	TNC_IMV_EVALUATION_RESULT_COMPLIANT,
-	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
-	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
-	TNC_IMV_EVALUATION_RESULT_ERROR,
-	TNC_IMV_EVALUATION_RESULT_DONT_KNOW
-};
-
-struct tnc_if_imv {
-	struct tnc_if_imv *next;
-	char *name;
-	char *path;
-	void *dlhandle; /* from dlopen() */
-	TNC_IMVID imvID;
-	TNC_MessageTypeList supported_types;
-	size_t num_supported_types;
-
-	/* Functions implemented by IMVs (with TNC_IMV_ prefix) */
-	TNC_Result (*Initialize)(
-		TNC_IMVID imvID,
-		TNC_Version minVersion,
-		TNC_Version maxVersion,
-		TNC_Version *pOutActualVersion);
-	TNC_Result (*NotifyConnectionChange)(
-		TNC_IMVID imvID,
-		TNC_ConnectionID connectionID,
-		TNC_ConnectionState newState);
-	TNC_Result (*ReceiveMessage)(
-		TNC_IMVID imvID,
-		TNC_ConnectionID connectionID,
-		TNC_BufferReference message,
-		TNC_UInt32 messageLength,
-		TNC_MessageType messageType);
-	TNC_Result (*SolicitRecommendation)(
-		TNC_IMVID imvID,
-		TNC_ConnectionID connectionID);
-	TNC_Result (*BatchEnding)(
-		TNC_IMVID imvID,
-		TNC_ConnectionID connectionID);
-	TNC_Result (*Terminate)(TNC_IMVID imvID);
-	TNC_Result (*ProvideBindFunction)(
-		TNC_IMVID imvID,
-		TNC_TNCS_BindFunctionPointer bindFunction);
-};
-
-
-#define TNC_MAX_IMV_ID 10
-
-struct tncs_data {
-	struct tncs_data *next;
-	struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
-	TNC_ConnectionID connectionID;
-	unsigned int last_batchid;
-	enum IMV_Action_Recommendation recommendation;
-	int done;
-
-	struct conn_imv {
-		u8 *imv_send;
-		size_t imv_send_len;
-		enum IMV_Action_Recommendation recommendation;
-		int recommendation_set;
-	} imv_data[TNC_MAX_IMV_ID];
-
-	char *tncs_message;
-};
-
-
-struct tncs_global {
-	struct tnc_if_imv *imv;
-	TNC_ConnectionID next_conn_id;
-	struct tncs_data *connections;
-};
-
-static struct tncs_global *tncs_global_data = NULL;
-
-
-static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
-{
-	struct tnc_if_imv *imv;
-
-	if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
-		return NULL;
-	imv = tncs_global_data->imv;
-	while (imv) {
-		if (imv->imvID == imvID)
-			return imv;
-		imv = imv->next;
-	}
-	return NULL;
-}
-
-
-static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
-{
-	struct tncs_data *tncs;
-
-	if (tncs_global_data == NULL)
-		return NULL;
-
-	tncs = tncs_global_data->connections;
-	while (tncs) {
-		if (tncs->connectionID == connectionID)
-			return tncs;
-		tncs = tncs->next;
-	}
-
-	wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
-		   (unsigned long) connectionID);
-
-	return NULL;
-}
-
-
-/* TNCS functions that IMVs can call */
-TNC_Result TNC_TNCS_ReportMessageTypes(
-	TNC_IMVID imvID,
-	TNC_MessageTypeList supportedTypes,
-	TNC_UInt32 typeCount)
-{
-	TNC_UInt32 i;
-	struct tnc_if_imv *imv;
-
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
-		   "typeCount=%lu)",
-		   (unsigned long) imvID, (unsigned long) typeCount);
-
-	for (i = 0; i < typeCount; i++) {
-		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
-			   i, supportedTypes[i]);
-	}
-
-	imv = tncs_get_imv(imvID);
-	if (imv == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-	os_free(imv->supported_types);
-	imv->supported_types =
-		os_malloc(typeCount * sizeof(TNC_MessageTypeList));
-	if (imv->supported_types == NULL)
-		return TNC_RESULT_FATAL;
-	os_memcpy(imv->supported_types, supportedTypes,
-		  typeCount * sizeof(TNC_MessageTypeList));
-	imv->num_supported_types = typeCount;
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_SendMessage(
-	TNC_IMVID imvID,
-	TNC_ConnectionID connectionID,
-	TNC_BufferReference message,
-	TNC_UInt32 messageLength,
-	TNC_MessageType messageType)
-{
-	struct tncs_data *tncs;
-	unsigned char *b64;
-	size_t b64len;
-
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
-		   "connectionID=%lu messageType=%lu)",
-		   imvID, connectionID, messageType);
-	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
-			  message, messageLength);
-
-	if (tncs_get_imv(imvID) == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	tncs = tncs_get_conn(connectionID);
-	if (tncs == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	b64 = base64_encode(message, messageLength, &b64len);
-	if (b64 == NULL)
-		return TNC_RESULT_FATAL;
-
-	os_free(tncs->imv_data[imvID].imv_send);
-	tncs->imv_data[imvID].imv_send_len = 0;
-	tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
-	if (tncs->imv_data[imvID].imv_send == NULL) {
-		os_free(b64);
-		return TNC_RESULT_OTHER;
-	}
-
-	tncs->imv_data[imvID].imv_send_len =
-		os_snprintf((char *) tncs->imv_data[imvID].imv_send,
-			    b64len + 100,
-			    "<IMC-IMV-Message><Type>%08X</Type>"
-			    "<Base64>%s</Base64></IMC-IMV-Message>",
-			    (unsigned int) messageType, b64);
-
-	os_free(b64);
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_RequestHandshakeRetry(
-	TNC_IMVID imvID,
-	TNC_ConnectionID connectionID,
-	TNC_RetryReason reason)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
-	/* TODO */
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_ProvideRecommendation(
-	TNC_IMVID imvID,
-	TNC_ConnectionID connectionID,
-	TNC_IMV_Action_Recommendation recommendation,
-	TNC_IMV_Evaluation_Result evaluation)
-{
-	struct tncs_data *tncs;
-
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
-		   "connectionID=%lu recommendation=%lu evaluation=%lu)",
-		   (unsigned long) imvID, (unsigned long) connectionID,
-		   (unsigned long) recommendation, (unsigned long) evaluation);
-
-	if (tncs_get_imv(imvID) == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	tncs = tncs_get_conn(connectionID);
-	if (tncs == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	tncs->imv_data[imvID].recommendation = recommendation;
-	tncs->imv_data[imvID].recommendation_set = 1;
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_GetAttribute(
-	TNC_IMVID imvID,
-	TNC_ConnectionID connectionID,
-	TNC_AttributeID attribureID,
-	TNC_UInt32 bufferLength,
-	TNC_BufferReference buffer,
-	TNC_UInt32 *pOutValueLength)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
-	/* TODO */
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_SetAttribute(
-	TNC_IMVID imvID,
-	TNC_ConnectionID connectionID,
-	TNC_AttributeID attribureID,
-	TNC_UInt32 bufferLength,
-	TNC_BufferReference buffer)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
-	/* TODO */
-	return TNC_RESULT_SUCCESS;
-}
-
-
-TNC_Result TNC_TNCS_BindFunction(
-	TNC_IMVID imvID,
-	char *functionName,
-	void **pOutFunctionPointer)
-{
-	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
-		   "functionName='%s')", (unsigned long) imvID, functionName);
-
-	if (tncs_get_imv(imvID) == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	if (pOutFunctionPointer == NULL)
-		return TNC_RESULT_INVALID_PARAMETER;
-
-	if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
-		*pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
-	else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
-		*pOutFunctionPointer = TNC_TNCS_SendMessage;
-	else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
-		 0)
-		*pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
-	else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
-		 0)
-		*pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
-	else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
-		*pOutFunctionPointer = TNC_TNCS_GetAttribute;
-	else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
-		*pOutFunctionPointer = TNC_TNCS_SetAttribute;
-	else
-		*pOutFunctionPointer = NULL;
-
-	return TNC_RESULT_SUCCESS;
-}
-
-
-static void * tncs_get_sym(void *handle, char *func)
-{
-	void *fptr;
-
-	fptr = dlsym(handle, func);
-
-	return fptr;
-}
-
-
-static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
-{
-	void *handle = imv->dlhandle;
-
-	/* Mandatory IMV functions */
-	imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
-	if (imv->Initialize == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
-			   "TNC_IMV_Initialize");
-		return -1;
-	}
-
-	imv->SolicitRecommendation = tncs_get_sym(
-		handle, "TNC_IMV_SolicitRecommendation");
-	if (imv->SolicitRecommendation == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
-			   "TNC_IMV_SolicitRecommendation");
-		return -1;
-	}
-
-	imv->ProvideBindFunction =
-		tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
-	if (imv->ProvideBindFunction == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
-			   "TNC_IMV_ProvideBindFunction");
-		return -1;
-	}
-
-	/* Optional IMV functions */
-	imv->NotifyConnectionChange =
-		tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
-	imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
-	imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
-	imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
-
-	return 0;
-}
-
-
-static int tncs_imv_initialize(struct tnc_if_imv *imv)
-{
-	TNC_Result res;
-	TNC_Version imv_ver;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
-		   imv->name);
-	res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
-			      TNC_IFIMV_VERSION_1, &imv_ver);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
-		   (unsigned long) res, (unsigned long) imv_ver);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncs_imv_terminate(struct tnc_if_imv *imv)
-{
-	TNC_Result res;
-
-	if (imv->Terminate == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
-		   imv->name);
-	res = imv->Terminate(imv->imvID);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
-{
-	TNC_Result res;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
-		   "IMV '%s'", imv->name);
-	res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
-					     TNC_ConnectionID conn,
-					     TNC_ConnectionState state)
-{
-	TNC_Result res;
-
-	if (imv->NotifyConnectionChange == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
-		   " for IMV '%s'", (int) state, imv->name);
-	res = imv->NotifyConnectionChange(imv->imvID, conn, state);
-	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
-		   (unsigned long) res);
-
-	return res == TNC_RESULT_SUCCESS ? 0 : -1;
-}
-
-
-static int tncs_load_imv(struct tnc_if_imv *imv)
-{
-	if (imv->path == NULL) {
-		wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
-		   imv->name, imv->path);
-	imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
-	if (imv->dlhandle == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
-			   imv->name, imv->path, dlerror());
-		return -1;
-	}
-
-	if (tncs_imv_resolve_funcs(imv) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
-		return -1;
-	}
-
-	if (tncs_imv_initialize(imv) < 0 ||
-	    tncs_imv_provide_bind_function(imv) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void tncs_free_imv(struct tnc_if_imv *imv)
-{
-	os_free(imv->name);
-	os_free(imv->path);
-	os_free(imv->supported_types);
-}
-
-static void tncs_unload_imv(struct tnc_if_imv *imv)
-{
-	tncs_imv_terminate(imv);
-
-	if (imv->dlhandle)
-		dlclose(imv->dlhandle);
-
-	tncs_free_imv(imv);
-}
-
-
-static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
-{
-	size_t i;
-	unsigned int vendor, subtype;
-
-	if (imv == NULL || imv->supported_types == NULL)
-		return 0;
-
-	vendor = type >> 8;
-	subtype = type & 0xff;
-
-	for (i = 0; i < imv->num_supported_types; i++) {
-		unsigned int svendor, ssubtype;
-		svendor = imv->supported_types[i] >> 8;
-		ssubtype = imv->supported_types[i] & 0xff;
-		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
-		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
-			return 1;
-	}
-
-	return 0;
-}
-
-
-static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
-			      const u8 *msg, size_t len)
-{
-	struct tnc_if_imv *imv;
-	TNC_Result res;
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
-
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		if (imv->ReceiveMessage == NULL ||
-		    !tncs_supported_type(imv, type))
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
-			   imv->name);
-		res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
-					  (TNC_BufferReference) msg, len,
-					  type);
-		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
-			   (unsigned long) res);
-	}
-}
-
-
-static void tncs_batch_ending(struct tncs_data *tncs)
-{
-	struct tnc_if_imv *imv;
-	TNC_Result res;
-
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		if (imv->BatchEnding == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
-			   imv->name);
-		res = imv->BatchEnding(imv->imvID, tncs->connectionID);
-		wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
-			   (unsigned long) res);
-	}
-}
-
-
-static void tncs_solicit_recommendation(struct tncs_data *tncs)
-{
-	struct tnc_if_imv *imv;
-	TNC_Result res;
-
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		if (tncs->imv_data[imv->imvID].recommendation_set)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
-			   "IMV '%s'", imv->name);
-		res = imv->SolicitRecommendation(imv->imvID,
-						 tncs->connectionID);
-		wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
-			   (unsigned long) res);
-	}
-}
-
-
-void tncs_init_connection(struct tncs_data *tncs)
-{
-	struct tnc_if_imv *imv;
-	int i;
-
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		tncs_imv_notify_connection_change(
-			imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
-		tncs_imv_notify_connection_change(
-			imv, tncs->connectionID,
-			TNC_CONNECTION_STATE_HANDSHAKE);
-	}
-
-	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
-		os_free(tncs->imv_data[i].imv_send);
-		tncs->imv_data[i].imv_send = NULL;
-		tncs->imv_data[i].imv_send_len = 0;
-	}
-}
-
-
-size_t tncs_total_send_len(struct tncs_data *tncs)
-{
-	int i;
-	size_t len = 0;
-
-	for (i = 0; i < TNC_MAX_IMV_ID; i++)
-		len += tncs->imv_data[i].imv_send_len;
-	if (tncs->tncs_message)
-		len += os_strlen(tncs->tncs_message);
-	return len;
-}
-
-
-u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
-{
-	int i;
-
-	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
-		if (tncs->imv_data[i].imv_send == NULL)
-			continue;
-
-		os_memcpy(pos, tncs->imv_data[i].imv_send,
-			  tncs->imv_data[i].imv_send_len);
-		pos += tncs->imv_data[i].imv_send_len;
-		os_free(tncs->imv_data[i].imv_send);
-		tncs->imv_data[i].imv_send = NULL;
-		tncs->imv_data[i].imv_send_len = 0;
-	}
-
-	if (tncs->tncs_message) {
-		size_t len = os_strlen(tncs->tncs_message);
-		os_memcpy(pos, tncs->tncs_message, len);
-		pos += len;
-		os_free(tncs->tncs_message);
-		tncs->tncs_message = NULL;
-	}
-
-	return pos;
-}
-
-
-char * tncs_if_tnccs_start(struct tncs_data *tncs)
-{
-	char *buf = os_malloc(1000);
-	if (buf == NULL)
-		return NULL;
-	tncs->last_batchid++;
-	os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
-	return buf;
-}
-
-
-char * tncs_if_tnccs_end(void)
-{
-	char *buf = os_malloc(100);
-	if (buf == NULL)
-		return NULL;
-	os_snprintf(buf, 100, IF_TNCCS_END);
-	return buf;
-}
-
-
-static int tncs_get_type(char *start, unsigned int *type)
-{
-	char *pos = os_strstr(start, "<Type>");
-	if (pos == NULL)
-		return -1;
-	pos += 6;
-	*type = strtoul(pos, NULL, 16);
-	return 0;
-}
-
-
-static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
-{
-	char *pos, *pos2;
-	unsigned char *decoded;
-
-	pos = os_strstr(start, "<Base64>");
-	if (pos == NULL)
-		return NULL;
-
-	pos += 8;
-	pos2 = os_strstr(pos, "</Base64>");
-	if (pos2 == NULL)
-		return NULL;
-	*pos2 = '\0';
-
-	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
-				decoded_len);
-	*pos2 = '<';
-	if (decoded == NULL) {
-		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
-	}
-
-	return decoded;
-}
-
-
-static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
-{
-	enum IMV_Action_Recommendation rec;
-	struct tnc_if_imv *imv;
-	TNC_ConnectionState state;
-	char *txt;
-
-	wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
-
-	if (tncs->done)
-		return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
-
-	tncs_solicit_recommendation(tncs);
-
-	/* Select the most restrictive recommendation */
-	rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		TNC_IMV_Action_Recommendation irec;
-		irec = tncs->imv_data[imv->imvID].recommendation;
-		if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
-			rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
-		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
-		    rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
-			rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
-		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
-		    rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
-			rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
-	}
-
-	wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
-	tncs->recommendation = rec;
-	tncs->done = 1;
-
-	txt = NULL;
-	switch (rec) {
-	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
-	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
-		txt = "allow";
-		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
-		break;
-	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
-		txt = "isolate";
-		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
-		break;
-	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
-		txt = "none";
-		state = TNC_CONNECTION_STATE_ACCESS_NONE;
-		break;
-	default:
-		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
-		break;
-	}
-
-	if (txt) {
-		os_free(tncs->tncs_message);
-		tncs->tncs_message = os_zalloc(200);
-		if (tncs->tncs_message) {
-			os_snprintf(tncs->tncs_message, 199,
-				    "<TNCC-TNCS-Message><Type>%08X</Type>"
-				    "<XML><TNCCS-Recommendation type=\"%s\">"
-				    "</TNCCS-Recommendation></XML>"
-				    "</TNCC-TNCS-Message>",
-				    TNC_TNCCS_RECOMMENDATION, txt);
-		}
-	}
-
-	for (imv = tncs->imv; imv; imv = imv->next) {
-		tncs_imv_notify_connection_change(imv, tncs->connectionID,
-						  state);
-	}
-
-	switch (rec) {
-	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
-		return TNCCS_RECOMMENDATION_ALLOW;
-	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
-		return TNCCS_RECOMMENDATION_NO_ACCESS;
-	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
-		return TNCCS_RECOMMENDATION_ISOLATE;
-	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
-		return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
-	default:
-		return TNCCS_PROCESS_ERROR;
-	}
-}
-
-
-enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
-					    const u8 *msg, size_t len)
-{
-	char *buf, *start, *end, *pos, *pos2, *payload;
-	unsigned int batch_id;
-	unsigned char *decoded;
-	size_t decoded_len;
-
-	buf = os_malloc(len + 1);
-	if (buf == NULL)
-		return TNCCS_PROCESS_ERROR;
-
-	os_memcpy(buf, msg, len);
-	buf[len] = '\0';
-	start = os_strstr(buf, "<TNCCS-Batch ");
-	end = os_strstr(buf, "</TNCCS-Batch>");
-	if (start == NULL || end == NULL || start > end) {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-
-	start += 13;
-	while (*start == ' ')
-		start++;
-	*end = '\0';
-
-	pos = os_strstr(start, "BatchId=");
-	if (pos == NULL) {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-
-	pos += 8;
-	if (*pos == '"')
-		pos++;
-	batch_id = atoi(pos);
-	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
-		   batch_id);
-	if (batch_id != tncs->last_batchid + 1) {
-		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
-			   "%u (expected %u)",
-			   batch_id, tncs->last_batchid + 1);
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-	tncs->last_batchid = batch_id;
-
-	while (*pos != '\0' && *pos != '>')
-		pos++;
-	if (*pos == '\0') {
-		os_free(buf);
-		return TNCCS_PROCESS_ERROR;
-	}
-	pos++;
-	payload = start;
-
-	/*
-	 * <IMC-IMV-Message>
-	 * <Type>01234567</Type>
-	 * <Base64>foo==</Base64>
-	 * </IMC-IMV-Message>
-	 */
-
-	while (*start) {
-		char *endpos;
-		unsigned int type;
-
-		pos = os_strstr(start, "<IMC-IMV-Message>");
-		if (pos == NULL)
-			break;
-		start = pos + 17;
-		end = os_strstr(start, "</IMC-IMV-Message>");
-		if (end == NULL)
-			break;
-		*end = '\0';
-		endpos = end;
-		end += 18;
-
-		if (tncs_get_type(start, &type) < 0) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
-
-		decoded = tncs_get_base64(start, &decoded_len);
-		if (decoded == NULL) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-
-		tncs_send_to_imvs(tncs, type, decoded, decoded_len);
-
-		os_free(decoded);
-
-		start = end;
-	}
-
-	/*
-	 * <TNCC-TNCS-Message>
-	 * <Type>01234567</Type>
-	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
-	 * <Base64>foo==</Base64>
-	 * </TNCC-TNCS-Message>
-	 */
-
-	start = payload;
-	while (*start) {
-		unsigned int type;
-		char *xml, *xmlend, *endpos;
-
-		pos = os_strstr(start, "<TNCC-TNCS-Message>");
-		if (pos == NULL)
-			break;
-		start = pos + 19;
-		end = os_strstr(start, "</TNCC-TNCS-Message>");
-		if (end == NULL)
-			break;
-		*end = '\0';
-		endpos = end;
-		end += 20;
-
-		if (tncs_get_type(start, &type) < 0) {
-			*endpos = '<';
-			start = end;
-			continue;
-		}
-		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
-			   type);
-
-		/* Base64 OR XML */
-		decoded = NULL;
-		xml = NULL;
-		xmlend = NULL;
-		pos = os_strstr(start, "<XML>");
-		if (pos) {
-			pos += 5;
-			pos2 = os_strstr(pos, "</XML>");
-			if (pos2 == NULL) {
-				*endpos = '<';
-				start = end;
-				continue;
-			}
-			xmlend = pos2;
-			xml = pos;
-		} else {
-			decoded = tncs_get_base64(start, &decoded_len);
-			if (decoded == NULL) {
-				*endpos = '<';
-				start = end;
-				continue;
-			}
-		}
-
-		if (decoded) {
-			wpa_hexdump_ascii(MSG_MSGDUMP,
-					  "TNC: TNCC-TNCS-Message Base64",
-					  decoded, decoded_len);
-			os_free(decoded);
-		}
-
-		if (xml) {
-			wpa_hexdump_ascii(MSG_MSGDUMP,
-					  "TNC: TNCC-TNCS-Message XML",
-					  (unsigned char *) xml,
-					  xmlend - xml);
-		}
-
-		start = end;
-	}
-
-	os_free(buf);
-
-	tncs_batch_ending(tncs);
-
-	if (tncs_total_send_len(tncs) == 0)
-		return tncs_derive_recommendation(tncs);
-
-	return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
-}
-
-
-static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
-					  int *error)
-{
-	struct tnc_if_imv *imv;
-	char *pos, *pos2;
-
-	if (id >= TNC_MAX_IMV_ID) {
-		wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
-		return NULL;
-	}
-
-	imv = os_zalloc(sizeof(*imv));
-	if (imv == NULL) {
-		*error = 1;
-		return NULL;
-	}
-
-	imv->imvID = id;
-
-	pos = start;
-	wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
-	if (pos + 1 >= end || *pos != '"') {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
-			   "(no starting quotation mark)", start);
-		os_free(imv);
-		return NULL;
-	}
-
-	pos++;
-	pos2 = pos;
-	while (pos2 < end && *pos2 != '"')
-		pos2++;
-	if (pos2 >= end) {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
-			   "(no ending quotation mark)", start);
-		os_free(imv);
-		return NULL;
-	}
-	*pos2 = '\0';
-	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
-	imv->name = os_strdup(pos);
-
-	pos = pos2 + 1;
-	if (pos >= end || *pos != ' ') {
-		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
-			   "(no space after name)", start);
-		os_free(imv);
-		return NULL;
-	}
-
-	pos++;
-	wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
-	imv->path = os_strdup(pos);
-
-	return imv;
-}
-
-
-static int tncs_read_config(struct tncs_global *global)
-{
-	char *config, *end, *pos, *line_end;
-	size_t config_len;
-	struct tnc_if_imv *imv, *last;
-	int id = 0;
-
-	last = NULL;
-
-	config = os_readfile(TNC_CONFIG_FILE, &config_len);
-	if (config == NULL) {
-		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
-			   "file '%s'", TNC_CONFIG_FILE);
-		return -1;
-	}
-
-	end = config + config_len;
-	for (pos = config; pos < end; pos = line_end + 1) {
-		line_end = pos;
-		while (*line_end != '\n' && *line_end != '\r' &&
-		       line_end < end)
-			line_end++;
-		*line_end = '\0';
-
-		if (os_strncmp(pos, "IMV ", 4) == 0) {
-			int error = 0;
-
-			imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
-			if (error)
-				return -1;
-			if (imv) {
-				if (last == NULL)
-					global->imv = imv;
-				else
-					last->next = imv;
-				last = imv;
-			}
-		}
-	}
-
-	os_free(config);
-
-	return 0;
-}
-
-
-struct tncs_data * tncs_init(void)
-{
-	struct tncs_data *tncs;
-
-	if (tncs_global_data == NULL)
-		return NULL;
-
-	tncs = os_zalloc(sizeof(*tncs));
-	if (tncs == NULL)
-		return NULL;
-	tncs->imv = tncs_global_data->imv;
-	tncs->connectionID = tncs_global_data->next_conn_id++;
-	tncs->next = tncs_global_data->connections;
-	tncs_global_data->connections = tncs;
-
-	return tncs;
-}
-
-
-void tncs_deinit(struct tncs_data *tncs)
-{
-	int i;
-	struct tncs_data *prev, *conn;
-
-	if (tncs == NULL)
-		return;
-
-	for (i = 0; i < TNC_MAX_IMV_ID; i++)
-		os_free(tncs->imv_data[i].imv_send);
-
-	prev = NULL;
-	conn = tncs_global_data->connections;
-	while (conn) {
-		if (conn == tncs) {
-			if (prev)
-				prev->next = tncs->next;
-			else
-				tncs_global_data->connections = tncs->next;
-			break;
-		}
-		prev = conn;
-		conn = conn->next;
-	}
-
-	os_free(tncs->tncs_message);
-	os_free(tncs);
-}
-
-
-int tncs_global_init(void)
-{
-	struct tnc_if_imv *imv;
-
-	tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
-	if (tncs_global_data == NULL)
-		return -1;
-
-	if (tncs_read_config(tncs_global_data) < 0) {
-		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
-		goto failed;
-	}
-
-	for (imv = tncs_global_data->imv; imv; imv = imv->next) {
-		if (tncs_load_imv(imv)) {
-			wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
-				   imv->name);
-			goto failed;
-		}
-	}
-
-	return 0;
-
-failed:
-	tncs_global_deinit();
-	return -1;
-}
-
-
-void tncs_global_deinit(void)
-{
-	struct tnc_if_imv *imv, *prev;
-
-	if (tncs_global_data == NULL)
-		return;
-
-	imv = tncs_global_data->imv;
-	while (imv) {
-		tncs_unload_imv(imv);
-
-		prev = imv;
-		imv = imv->next;
-		os_free(prev);
-	}
-
-	os_free(tncs_global_data);
-	tncs_global_data = NULL;
-}
-
-
-struct wpabuf * tncs_build_soh_request(void)
-{
-	struct wpabuf *buf;
-
-	/*
-	 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
-	 * Method)
-	 */
-
-	buf = wpabuf_alloc(8 + 4);
-	if (buf == NULL)
-		return NULL;
-
-	/* Vendor-Specific TLV (Microsoft) - SoH Request */
-	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
-	wpabuf_put_be16(buf, 8); /* Length */
-
-	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
-
-	wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
-	wpabuf_put_be16(buf, 0); /* Length */
-
-	return buf;
-}
-
-
-struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
-				 int *failure)
-{
-	wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
-	*failure = 0;
-
-	/* TODO: return MS-SoH Response TLV */
-
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/eap_server/tncs.c (from rev 9639, vendor/wpa/dist/src/eap_server/tncs.c)
===================================================================
--- vendor/wpa/2.0/src/eap_server/tncs.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/tncs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1267 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+#include "base64.h"
+#include "tncs.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
+
+
+/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
+ * needed.. */
+
+#define TNC_CONFIG_FILE "/etc/tnc_config"
+#define IF_TNCCS_START \
+"<?xml version=\"1.0\"?>\n" \
+"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
+"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+#define IF_TNCCS_END "\n</TNCCS-Batch>"
+
+/* TNC IF-IMV */
+
+typedef unsigned long TNC_UInt32;
+typedef unsigned char *TNC_BufferReference;
+
+typedef TNC_UInt32 TNC_IMVID;
+typedef TNC_UInt32 TNC_ConnectionID;
+typedef TNC_UInt32 TNC_ConnectionState;
+typedef TNC_UInt32 TNC_RetryReason;
+typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
+typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
+typedef TNC_UInt32 TNC_MessageType;
+typedef TNC_MessageType *TNC_MessageTypeList;
+typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_UInt32 TNC_Subtype;
+typedef TNC_UInt32 TNC_Version;
+typedef TNC_UInt32 TNC_Result;
+typedef TNC_UInt32 TNC_AttributeID;
+
+typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
+	TNC_IMVID imvID,
+	char *functionName,
+	void **pOutfunctionPointer);
+
+#define TNC_RESULT_SUCCESS 0
+#define TNC_RESULT_NOT_INITIALIZED 1
+#define TNC_RESULT_ALREADY_INITIALIZED 2
+#define TNC_RESULT_NO_COMMON_VERSION 3
+#define TNC_RESULT_CANT_RETRY 4
+#define TNC_RESULT_WONT_RETRY 5
+#define TNC_RESULT_INVALID_PARAMETER 6
+#define TNC_RESULT_CANT_RESPOND 7
+#define TNC_RESULT_ILLEGAL_OPERATION 8
+#define TNC_RESULT_OTHER 9
+#define TNC_RESULT_FATAL 10
+
+#define TNC_CONNECTION_STATE_CREATE 0
+#define TNC_CONNECTION_STATE_HANDSHAKE 1
+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
+#define TNC_CONNECTION_STATE_ACCESS_NONE 4
+#define TNC_CONNECTION_STATE_DELETE 5
+
+#define TNC_IFIMV_VERSION_1 1
+
+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
+
+/* TNCC-TNCS Message Types */
+#define TNC_TNCCS_RECOMMENDATION		0x00000001
+#define TNC_TNCCS_ERROR				0x00000002
+#define TNC_TNCCS_PREFERREDLANGUAGE		0x00000003
+#define TNC_TNCCS_REASONSTRINGS			0x00000004
+
+/* Possible TNC_IMV_Action_Recommendation values: */
+enum IMV_Action_Recommendation {
+	TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
+	TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
+	TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+	TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+/* Possible TNC_IMV_Evaluation_Result values: */
+enum IMV_Evaluation_Result {
+	TNC_IMV_EVALUATION_RESULT_COMPLIANT,
+	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
+	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
+	TNC_IMV_EVALUATION_RESULT_ERROR,
+	TNC_IMV_EVALUATION_RESULT_DONT_KNOW
+};
+
+struct tnc_if_imv {
+	struct tnc_if_imv *next;
+	char *name;
+	char *path;
+	void *dlhandle; /* from dlopen() */
+	TNC_IMVID imvID;
+	TNC_MessageTypeList supported_types;
+	size_t num_supported_types;
+
+	/* Functions implemented by IMVs (with TNC_IMV_ prefix) */
+	TNC_Result (*Initialize)(
+		TNC_IMVID imvID,
+		TNC_Version minVersion,
+		TNC_Version maxVersion,
+		TNC_Version *pOutActualVersion);
+	TNC_Result (*NotifyConnectionChange)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID,
+		TNC_ConnectionState newState);
+	TNC_Result (*ReceiveMessage)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID,
+		TNC_BufferReference message,
+		TNC_UInt32 messageLength,
+		TNC_MessageType messageType);
+	TNC_Result (*SolicitRecommendation)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*BatchEnding)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*Terminate)(TNC_IMVID imvID);
+	TNC_Result (*ProvideBindFunction)(
+		TNC_IMVID imvID,
+		TNC_TNCS_BindFunctionPointer bindFunction);
+};
+
+
+#define TNC_MAX_IMV_ID 10
+
+struct tncs_data {
+	struct tncs_data *next;
+	struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
+	TNC_ConnectionID connectionID;
+	unsigned int last_batchid;
+	enum IMV_Action_Recommendation recommendation;
+	int done;
+
+	struct conn_imv {
+		u8 *imv_send;
+		size_t imv_send_len;
+		enum IMV_Action_Recommendation recommendation;
+		int recommendation_set;
+	} imv_data[TNC_MAX_IMV_ID];
+
+	char *tncs_message;
+};
+
+
+struct tncs_global {
+	struct tnc_if_imv *imv;
+	TNC_ConnectionID next_conn_id;
+	struct tncs_data *connections;
+};
+
+static struct tncs_global *tncs_global_data = NULL;
+
+
+static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
+{
+	struct tnc_if_imv *imv;
+
+	if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
+		return NULL;
+	imv = tncs_global_data->imv;
+	while (imv) {
+		if (imv->imvID == imvID)
+			return imv;
+		imv = imv->next;
+	}
+	return NULL;
+}
+
+
+static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
+{
+	struct tncs_data *tncs;
+
+	if (tncs_global_data == NULL)
+		return NULL;
+
+	tncs = tncs_global_data->connections;
+	while (tncs) {
+		if (tncs->connectionID == connectionID)
+			return tncs;
+		tncs = tncs->next;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
+		   (unsigned long) connectionID);
+
+	return NULL;
+}
+
+
+/* TNCS functions that IMVs can call */
+TNC_Result TNC_TNCS_ReportMessageTypes(
+	TNC_IMVID imvID,
+	TNC_MessageTypeList supportedTypes,
+	TNC_UInt32 typeCount)
+{
+	TNC_UInt32 i;
+	struct tnc_if_imv *imv;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
+		   "typeCount=%lu)",
+		   (unsigned long) imvID, (unsigned long) typeCount);
+
+	for (i = 0; i < typeCount; i++) {
+		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
+			   i, supportedTypes[i]);
+	}
+
+	imv = tncs_get_imv(imvID);
+	if (imv == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+	os_free(imv->supported_types);
+	imv->supported_types =
+		os_malloc(typeCount * sizeof(TNC_MessageType));
+	if (imv->supported_types == NULL)
+		return TNC_RESULT_FATAL;
+	os_memcpy(imv->supported_types, supportedTypes,
+		  typeCount * sizeof(TNC_MessageType));
+	imv->num_supported_types = typeCount;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SendMessage(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_BufferReference message,
+	TNC_UInt32 messageLength,
+	TNC_MessageType messageType)
+{
+	struct tncs_data *tncs;
+	unsigned char *b64;
+	size_t b64len;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
+		   "connectionID=%lu messageType=%lu)",
+		   imvID, connectionID, messageType);
+	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
+			  message, messageLength);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs = tncs_get_conn(connectionID);
+	if (tncs == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	b64 = base64_encode(message, messageLength, &b64len);
+	if (b64 == NULL)
+		return TNC_RESULT_FATAL;
+
+	os_free(tncs->imv_data[imvID].imv_send);
+	tncs->imv_data[imvID].imv_send_len = 0;
+	tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
+	if (tncs->imv_data[imvID].imv_send == NULL) {
+		os_free(b64);
+		return TNC_RESULT_OTHER;
+	}
+
+	tncs->imv_data[imvID].imv_send_len =
+		os_snprintf((char *) tncs->imv_data[imvID].imv_send,
+			    b64len + 100,
+			    "<IMC-IMV-Message><Type>%08X</Type>"
+			    "<Base64>%s</Base64></IMC-IMV-Message>",
+			    (unsigned int) messageType, b64);
+
+	os_free(b64);
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_RequestHandshakeRetry(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_RetryReason reason)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_ProvideRecommendation(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_IMV_Action_Recommendation recommendation,
+	TNC_IMV_Evaluation_Result evaluation)
+{
+	struct tncs_data *tncs;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
+		   "connectionID=%lu recommendation=%lu evaluation=%lu)",
+		   (unsigned long) imvID, (unsigned long) connectionID,
+		   (unsigned long) recommendation, (unsigned long) evaluation);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs = tncs_get_conn(connectionID);
+	if (tncs == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs->imv_data[imvID].recommendation = recommendation;
+	tncs->imv_data[imvID].recommendation_set = 1;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_GetAttribute(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_AttributeID attribureID,
+	TNC_UInt32 bufferLength,
+	TNC_BufferReference buffer,
+	TNC_UInt32 *pOutValueLength)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SetAttribute(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_AttributeID attribureID,
+	TNC_UInt32 bufferLength,
+	TNC_BufferReference buffer)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_BindFunction(
+	TNC_IMVID imvID,
+	char *functionName,
+	void **pOutFunctionPointer)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
+		   "functionName='%s')", (unsigned long) imvID, functionName);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (pOutFunctionPointer == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
+		*pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
+	else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
+		*pOutFunctionPointer = TNC_TNCS_SendMessage;
+	else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
+		 0)
+		*pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
+	else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
+		 0)
+		*pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
+	else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
+		*pOutFunctionPointer = TNC_TNCS_GetAttribute;
+	else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
+		*pOutFunctionPointer = TNC_TNCS_SetAttribute;
+	else
+		*pOutFunctionPointer = NULL;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+static void * tncs_get_sym(void *handle, char *func)
+{
+	void *fptr;
+
+	fptr = dlsym(handle, func);
+
+	return fptr;
+}
+
+
+static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
+{
+	void *handle = imv->dlhandle;
+
+	/* Mandatory IMV functions */
+	imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
+	if (imv->Initialize == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_Initialize");
+		return -1;
+	}
+
+	imv->SolicitRecommendation = tncs_get_sym(
+		handle, "TNC_IMV_SolicitRecommendation");
+	if (imv->SolicitRecommendation == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_SolicitRecommendation");
+		return -1;
+	}
+
+	imv->ProvideBindFunction =
+		tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
+	if (imv->ProvideBindFunction == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_ProvideBindFunction");
+		return -1;
+	}
+
+	/* Optional IMV functions */
+	imv->NotifyConnectionChange =
+		tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
+	imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
+	imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
+	imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
+
+	return 0;
+}
+
+
+static int tncs_imv_initialize(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+	TNC_Version imv_ver;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
+		   imv->name);
+	res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
+			      TNC_IFIMV_VERSION_1, &imv_ver);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
+		   (unsigned long) res, (unsigned long) imv_ver);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_terminate(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+
+	if (imv->Terminate == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
+		   imv->name);
+	res = imv->Terminate(imv->imvID);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
+		   "IMV '%s'", imv->name);
+	res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
+					     TNC_ConnectionID conn,
+					     TNC_ConnectionState state)
+{
+	TNC_Result res;
+
+	if (imv->NotifyConnectionChange == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
+		   " for IMV '%s'", (int) state, imv->name);
+	res = imv->NotifyConnectionChange(imv->imvID, conn, state);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_load_imv(struct tnc_if_imv *imv)
+{
+	if (imv->path == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
+		   imv->name, imv->path);
+	imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
+	if (imv->dlhandle == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
+			   imv->name, imv->path, dlerror());
+		return -1;
+	}
+
+	if (tncs_imv_resolve_funcs(imv) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
+		return -1;
+	}
+
+	if (tncs_imv_initialize(imv) < 0 ||
+	    tncs_imv_provide_bind_function(imv) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void tncs_free_imv(struct tnc_if_imv *imv)
+{
+	os_free(imv->name);
+	os_free(imv->path);
+	os_free(imv->supported_types);
+}
+
+static void tncs_unload_imv(struct tnc_if_imv *imv)
+{
+	tncs_imv_terminate(imv);
+
+	if (imv->dlhandle)
+		dlclose(imv->dlhandle);
+
+	tncs_free_imv(imv);
+}
+
+
+static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
+{
+	size_t i;
+	unsigned int vendor, subtype;
+
+	if (imv == NULL || imv->supported_types == NULL)
+		return 0;
+
+	vendor = type >> 8;
+	subtype = type & 0xff;
+
+	for (i = 0; i < imv->num_supported_types; i++) {
+		unsigned int svendor, ssubtype;
+		svendor = imv->supported_types[i] >> 8;
+		ssubtype = imv->supported_types[i] & 0xff;
+		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
+		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
+			      const u8 *msg, size_t len)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (imv->ReceiveMessage == NULL ||
+		    !tncs_supported_type(imv, type))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
+			   imv->name);
+		res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
+					  (TNC_BufferReference) msg, len,
+					  type);
+		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+static void tncs_batch_ending(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (imv->BatchEnding == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
+			   imv->name);
+		res = imv->BatchEnding(imv->imvID, tncs->connectionID);
+		wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+static void tncs_solicit_recommendation(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (tncs->imv_data[imv->imvID].recommendation_set)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
+			   "IMV '%s'", imv->name);
+		res = imv->SolicitRecommendation(imv->imvID,
+						 tncs->connectionID);
+		wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+void tncs_init_connection(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	int i;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		tncs_imv_notify_connection_change(
+			imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
+		tncs_imv_notify_connection_change(
+			imv, tncs->connectionID,
+			TNC_CONNECTION_STATE_HANDSHAKE);
+	}
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+		os_free(tncs->imv_data[i].imv_send);
+		tncs->imv_data[i].imv_send = NULL;
+		tncs->imv_data[i].imv_send_len = 0;
+	}
+}
+
+
+size_t tncs_total_send_len(struct tncs_data *tncs)
+{
+	int i;
+	size_t len = 0;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++)
+		len += tncs->imv_data[i].imv_send_len;
+	if (tncs->tncs_message)
+		len += os_strlen(tncs->tncs_message);
+	return len;
+}
+
+
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
+{
+	int i;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+		if (tncs->imv_data[i].imv_send == NULL)
+			continue;
+
+		os_memcpy(pos, tncs->imv_data[i].imv_send,
+			  tncs->imv_data[i].imv_send_len);
+		pos += tncs->imv_data[i].imv_send_len;
+		os_free(tncs->imv_data[i].imv_send);
+		tncs->imv_data[i].imv_send = NULL;
+		tncs->imv_data[i].imv_send_len = 0;
+	}
+
+	if (tncs->tncs_message) {
+		size_t len = os_strlen(tncs->tncs_message);
+		os_memcpy(pos, tncs->tncs_message, len);
+		pos += len;
+		os_free(tncs->tncs_message);
+		tncs->tncs_message = NULL;
+	}
+
+	return pos;
+}
+
+
+char * tncs_if_tnccs_start(struct tncs_data *tncs)
+{
+	char *buf = os_malloc(1000);
+	if (buf == NULL)
+		return NULL;
+	tncs->last_batchid++;
+	os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
+	return buf;
+}
+
+
+char * tncs_if_tnccs_end(void)
+{
+	char *buf = os_malloc(100);
+	if (buf == NULL)
+		return NULL;
+	os_snprintf(buf, 100, IF_TNCCS_END);
+	return buf;
+}
+
+
+static int tncs_get_type(char *start, unsigned int *type)
+{
+	char *pos = os_strstr(start, "<Type>");
+	if (pos == NULL)
+		return -1;
+	pos += 6;
+	*type = strtoul(pos, NULL, 16);
+	return 0;
+}
+
+
+static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
+{
+	char *pos, *pos2;
+	unsigned char *decoded;
+
+	pos = os_strstr(start, "<Base64>");
+	if (pos == NULL)
+		return NULL;
+
+	pos += 8;
+	pos2 = os_strstr(pos, "</Base64>");
+	if (pos2 == NULL)
+		return NULL;
+	*pos2 = '\0';
+
+	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
+				decoded_len);
+	*pos2 = '<';
+	if (decoded == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
+	}
+
+	return decoded;
+}
+
+
+static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
+{
+	enum IMV_Action_Recommendation rec;
+	struct tnc_if_imv *imv;
+	TNC_ConnectionState state;
+	char *txt;
+
+	wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
+
+	if (tncs->done)
+		return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+
+	tncs_solicit_recommendation(tncs);
+
+	/* Select the most restrictive recommendation */
+	rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		TNC_IMV_Action_Recommendation irec;
+		irec = tncs->imv_data[imv->imvID].recommendation;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
+		    rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
+		    rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
+	tncs->recommendation = rec;
+	tncs->done = 1;
+
+	txt = NULL;
+	switch (rec) {
+	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+		txt = "allow";
+		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+		break;
+	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+		txt = "isolate";
+		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+		break;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+		txt = "none";
+		state = TNC_CONNECTION_STATE_ACCESS_NONE;
+		break;
+	default:
+		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+		break;
+	}
+
+	if (txt) {
+		os_free(tncs->tncs_message);
+		tncs->tncs_message = os_zalloc(200);
+		if (tncs->tncs_message) {
+			os_snprintf(tncs->tncs_message, 199,
+				    "<TNCC-TNCS-Message><Type>%08X</Type>"
+				    "<XML><TNCCS-Recommendation type=\"%s\">"
+				    "</TNCCS-Recommendation></XML>"
+				    "</TNCC-TNCS-Message>",
+				    TNC_TNCCS_RECOMMENDATION, txt);
+		}
+	}
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		tncs_imv_notify_connection_change(imv, tncs->connectionID,
+						  state);
+	}
+
+	switch (rec) {
+	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+		return TNCCS_RECOMMENDATION_ALLOW;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+		return TNCCS_RECOMMENDATION_NO_ACCESS;
+	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+		return TNCCS_RECOMMENDATION_ISOLATE;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+		return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
+	default:
+		return TNCCS_PROCESS_ERROR;
+	}
+}
+
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+					    const u8 *msg, size_t len)
+{
+	char *buf, *start, *end, *pos, *pos2, *payload;
+	unsigned int batch_id;
+	unsigned char *decoded;
+	size_t decoded_len;
+
+	buf = os_malloc(len + 1);
+	if (buf == NULL)
+		return TNCCS_PROCESS_ERROR;
+
+	os_memcpy(buf, msg, len);
+	buf[len] = '\0';
+	start = os_strstr(buf, "<TNCCS-Batch ");
+	end = os_strstr(buf, "</TNCCS-Batch>");
+	if (start == NULL || end == NULL || start > end) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	start += 13;
+	while (*start == ' ')
+		start++;
+	*end = '\0';
+
+	pos = os_strstr(start, "BatchId=");
+	if (pos == NULL) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	pos += 8;
+	if (*pos == '"')
+		pos++;
+	batch_id = atoi(pos);
+	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
+		   batch_id);
+	if (batch_id != tncs->last_batchid + 1) {
+		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
+			   "%u (expected %u)",
+			   batch_id, tncs->last_batchid + 1);
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	tncs->last_batchid = batch_id;
+
+	while (*pos != '\0' && *pos != '>')
+		pos++;
+	if (*pos == '\0') {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	pos++;
+	payload = start;
+
+	/*
+	 * <IMC-IMV-Message>
+	 * <Type>01234567</Type>
+	 * <Base64>foo==</Base64>
+	 * </IMC-IMV-Message>
+	 */
+
+	while (*start) {
+		char *endpos;
+		unsigned int type;
+
+		pos = os_strstr(start, "<IMC-IMV-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 17;
+		end = os_strstr(start, "</IMC-IMV-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 18;
+
+		if (tncs_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
+
+		decoded = tncs_get_base64(start, &decoded_len);
+		if (decoded == NULL) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+
+		tncs_send_to_imvs(tncs, type, decoded, decoded_len);
+
+		os_free(decoded);
+
+		start = end;
+	}
+
+	/*
+	 * <TNCC-TNCS-Message>
+	 * <Type>01234567</Type>
+	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
+	 * <Base64>foo==</Base64>
+	 * </TNCC-TNCS-Message>
+	 */
+
+	start = payload;
+	while (*start) {
+		unsigned int type;
+		char *xml, *xmlend, *endpos;
+
+		pos = os_strstr(start, "<TNCC-TNCS-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 19;
+		end = os_strstr(start, "</TNCC-TNCS-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 20;
+
+		if (tncs_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
+			   type);
+
+		/* Base64 OR XML */
+		decoded = NULL;
+		xml = NULL;
+		xmlend = NULL;
+		pos = os_strstr(start, "<XML>");
+		if (pos) {
+			pos += 5;
+			pos2 = os_strstr(pos, "</XML>");
+			if (pos2 == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+			xmlend = pos2;
+			xml = pos;
+		} else {
+			decoded = tncs_get_base64(start, &decoded_len);
+			if (decoded == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+		}
+
+		if (decoded) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message Base64",
+					  decoded, decoded_len);
+			os_free(decoded);
+		}
+
+		if (xml) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message XML",
+					  (unsigned char *) xml,
+					  xmlend - xml);
+		}
+
+		start = end;
+	}
+
+	os_free(buf);
+
+	tncs_batch_ending(tncs);
+
+	if (tncs_total_send_len(tncs) == 0)
+		return tncs_derive_recommendation(tncs);
+
+	return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+}
+
+
+static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
+					  int *error)
+{
+	struct tnc_if_imv *imv;
+	char *pos, *pos2;
+
+	if (id >= TNC_MAX_IMV_ID) {
+		wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
+		return NULL;
+	}
+
+	imv = os_zalloc(sizeof(*imv));
+	if (imv == NULL) {
+		*error = 1;
+		return NULL;
+	}
+
+	imv->imvID = id;
+
+	pos = start;
+	wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
+	if (pos + 1 >= end || *pos != '"') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no starting quotation mark)", start);
+		os_free(imv);
+		return NULL;
+	}
+
+	pos++;
+	pos2 = pos;
+	while (pos2 < end && *pos2 != '"')
+		pos2++;
+	if (pos2 >= end) {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no ending quotation mark)", start);
+		os_free(imv);
+		return NULL;
+	}
+	*pos2 = '\0';
+	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
+	imv->name = os_strdup(pos);
+
+	pos = pos2 + 1;
+	if (pos >= end || *pos != ' ') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no space after name)", start);
+		os_free(imv);
+		return NULL;
+	}
+
+	pos++;
+	wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
+	imv->path = os_strdup(pos);
+
+	return imv;
+}
+
+
+static int tncs_read_config(struct tncs_global *global)
+{
+	char *config, *end, *pos, *line_end;
+	size_t config_len;
+	struct tnc_if_imv *imv, *last;
+	int id = 0;
+
+	last = NULL;
+
+	config = os_readfile(TNC_CONFIG_FILE, &config_len);
+	if (config == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
+			   "file '%s'", TNC_CONFIG_FILE);
+		return -1;
+	}
+
+	end = config + config_len;
+	for (pos = config; pos < end; pos = line_end + 1) {
+		line_end = pos;
+		while (*line_end != '\n' && *line_end != '\r' &&
+		       line_end < end)
+			line_end++;
+		*line_end = '\0';
+
+		if (os_strncmp(pos, "IMV ", 4) == 0) {
+			int error = 0;
+
+			imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
+			if (error)
+				return -1;
+			if (imv) {
+				if (last == NULL)
+					global->imv = imv;
+				else
+					last->next = imv;
+				last = imv;
+			}
+		}
+	}
+
+	os_free(config);
+
+	return 0;
+}
+
+
+struct tncs_data * tncs_init(void)
+{
+	struct tncs_data *tncs;
+
+	if (tncs_global_data == NULL)
+		return NULL;
+
+	tncs = os_zalloc(sizeof(*tncs));
+	if (tncs == NULL)
+		return NULL;
+	tncs->imv = tncs_global_data->imv;
+	tncs->connectionID = tncs_global_data->next_conn_id++;
+	tncs->next = tncs_global_data->connections;
+	tncs_global_data->connections = tncs;
+
+	return tncs;
+}
+
+
+void tncs_deinit(struct tncs_data *tncs)
+{
+	int i;
+	struct tncs_data *prev, *conn;
+
+	if (tncs == NULL)
+		return;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++)
+		os_free(tncs->imv_data[i].imv_send);
+
+	prev = NULL;
+	conn = tncs_global_data->connections;
+	while (conn) {
+		if (conn == tncs) {
+			if (prev)
+				prev->next = tncs->next;
+			else
+				tncs_global_data->connections = tncs->next;
+			break;
+		}
+		prev = conn;
+		conn = conn->next;
+	}
+
+	os_free(tncs->tncs_message);
+	os_free(tncs);
+}
+
+
+int tncs_global_init(void)
+{
+	struct tnc_if_imv *imv;
+
+	tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
+	if (tncs_global_data == NULL)
+		return -1;
+
+	if (tncs_read_config(tncs_global_data) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
+		goto failed;
+	}
+
+	for (imv = tncs_global_data->imv; imv; imv = imv->next) {
+		if (tncs_load_imv(imv)) {
+			wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
+				   imv->name);
+			goto failed;
+		}
+	}
+
+	return 0;
+
+failed:
+	tncs_global_deinit();
+	return -1;
+}
+
+
+void tncs_global_deinit(void)
+{
+	struct tnc_if_imv *imv, *prev;
+
+	if (tncs_global_data == NULL)
+		return;
+
+	imv = tncs_global_data->imv;
+	while (imv) {
+		tncs_unload_imv(imv);
+
+		prev = imv;
+		imv = imv->next;
+		os_free(prev);
+	}
+
+	os_free(tncs_global_data);
+	tncs_global_data = NULL;
+}
+
+
+struct wpabuf * tncs_build_soh_request(void)
+{
+	struct wpabuf *buf;
+
+	/*
+	 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
+	 * Method)
+	 */
+
+	buf = wpabuf_alloc(8 + 4);
+	if (buf == NULL)
+		return NULL;
+
+	/* Vendor-Specific TLV (Microsoft) - SoH Request */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+	wpabuf_put_be16(buf, 8); /* Length */
+
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+
+	wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
+	wpabuf_put_be16(buf, 0); /* Length */
+
+	return buf;
+}
+
+
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+				 int *failure)
+{
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
+	*failure = 0;
+
+	/* TODO: return MS-SoH Response TLV */
+
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/eap_server/tncs.h
===================================================================
--- vendor/wpa/dist/src/eap_server/tncs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eap_server/tncs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,49 +0,0 @@
-/*
- * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
- * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TNCS_H
-#define TNCS_H
-
-struct tncs_data;
-
-struct tncs_data * tncs_init(void);
-void tncs_deinit(struct tncs_data *tncs);
-void tncs_init_connection(struct tncs_data *tncs);
-size_t tncs_total_send_len(struct tncs_data *tncs);
-u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos);
-char * tncs_if_tnccs_start(struct tncs_data *tncs);
-char * tncs_if_tnccs_end(void);
-
-enum tncs_process_res {
-	TNCCS_PROCESS_ERROR = -1,
-	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
-	TNCCS_RECOMMENDATION_ERROR,
-	TNCCS_RECOMMENDATION_ALLOW,
-	TNCCS_RECOMMENDATION_NONE,
-	TNCCS_RECOMMENDATION_ISOLATE,
-	TNCCS_RECOMMENDATION_NO_ACCESS,
-	TNCCS_RECOMMENDATION_NO_RECOMMENDATION
-};
-
-enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
-					    const u8 *msg, size_t len);
-
-int tncs_global_init(void);
-void tncs_global_deinit(void);
-
-struct wpabuf * tncs_build_soh_request(void);
-struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
-				 int *failure);
-
-#endif /* TNCS_H */

Copied: vendor/wpa/2.0/src/eap_server/tncs.h (from rev 9639, vendor/wpa/dist/src/eap_server/tncs.h)
===================================================================
--- vendor/wpa/2.0/src/eap_server/tncs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eap_server/tncs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,43 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TNCS_H
+#define TNCS_H
+
+struct tncs_data;
+
+struct tncs_data * tncs_init(void);
+void tncs_deinit(struct tncs_data *tncs);
+void tncs_init_connection(struct tncs_data *tncs);
+size_t tncs_total_send_len(struct tncs_data *tncs);
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos);
+char * tncs_if_tnccs_start(struct tncs_data *tncs);
+char * tncs_if_tnccs_end(void);
+
+enum tncs_process_res {
+	TNCCS_PROCESS_ERROR = -1,
+	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
+	TNCCS_RECOMMENDATION_ERROR,
+	TNCCS_RECOMMENDATION_ALLOW,
+	TNCCS_RECOMMENDATION_NONE,
+	TNCCS_RECOMMENDATION_ISOLATE,
+	TNCCS_RECOMMENDATION_NO_ACCESS,
+	TNCCS_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+					    const u8 *msg, size_t len);
+
+int tncs_global_init(void);
+void tncs_global_deinit(void);
+
+struct wpabuf * tncs_build_soh_request(void);
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+				 int *failure);
+
+#endif /* TNCS_H */

Deleted: vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c
===================================================================
--- vendor/wpa/dist/src/eapol_auth/eapol_auth_dump.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,231 +0,0 @@
-/*
- * IEEE 802.1X-2004 Authenticator - State dump
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_server/eap.h"
-#include "eapol_auth_sm.h"
-#include "eapol_auth_sm_i.h"
-
-static inline const char * port_type_txt(PortTypes pt)
-{
-	switch (pt) {
-	case ForceUnauthorized: return "ForceUnauthorized";
-	case ForceAuthorized: return "ForceAuthorized";
-	case Auto: return "Auto";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * port_state_txt(PortState ps)
-{
-	switch (ps) {
-	case Unauthorized: return "Unauthorized";
-	case Authorized: return "Authorized";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * ctrl_dir_txt(ControlledDirection dir)
-{
-	switch (dir) {
-	case Both: return "Both";
-	case In: return "In";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * auth_pae_state_txt(int s)
-{
-	switch (s) {
-	case AUTH_PAE_INITIALIZE: return "INITIALIZE";
-	case AUTH_PAE_DISCONNECTED: return "DISCONNECTED";
-	case AUTH_PAE_CONNECTING: return "CONNECTING";
-	case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING";
-	case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED";
-	case AUTH_PAE_ABORTING: return "ABORTING";
-	case AUTH_PAE_HELD: return "HELD";
-	case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH";
-	case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH";
-	case AUTH_PAE_RESTART: return "RESTART";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * be_auth_state_txt(int s)
-{
-	switch (s) {
-	case BE_AUTH_REQUEST: return "REQUEST";
-	case BE_AUTH_RESPONSE: return "RESPONSE";
-	case BE_AUTH_SUCCESS: return "SUCCESS";
-	case BE_AUTH_FAIL: return "FAIL";
-	case BE_AUTH_TIMEOUT: return "TIMEOUT";
-	case BE_AUTH_IDLE: return "IDLE";
-	case BE_AUTH_INITIALIZE: return "INITIALIZE";
-	case BE_AUTH_IGNORE: return "IGNORE";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * reauth_timer_state_txt(int s)
-{
-	switch (s) {
-	case REAUTH_TIMER_INITIALIZE: return "INITIALIZE";
-	case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * auth_key_tx_state_txt(int s)
-{
-	switch (s) {
-	case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT";
-	case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * key_rx_state_txt(int s)
-{
-	switch (s) {
-	case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE";
-	case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE";
-	default: return "Unknown";
-	}
-}
-
-
-static inline const char * ctrl_dir_state_txt(int s)
-{
-	switch (s) {
-	case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH";
-	case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH";
-	default: return "Unknown";
-	}
-}
-
-
-void eapol_auth_dump_state(FILE *f, const char *prefix,
-			   struct eapol_state_machine *sm)
-{
-	fprintf(f, "%sEAPOL state machine:\n", prefix);
-	fprintf(f, "%s  aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
-		sm->aWhile, sm->quietWhile, sm->reAuthWhen);
-#define _SB(b) ((b) ? "TRUE" : "FALSE")
-	fprintf(f,
-		"%s  authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
-		"%s  authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
-		"%s  eapSuccess=%s eapTimeout=%s initialize=%s "
-		"keyAvailable=%s\n"
-		"%s  keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
-		"%s  portEnabled=%s portValid=%s reAuthenticate=%s\n",
-		prefix, _SB(sm->authAbort), _SB(sm->authFail),
-		port_state_txt(sm->authPortStatus), _SB(sm->authStart),
-		prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
-		_SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
-		prefix, _SB(sm->eap_if->eapSuccess),
-		_SB(sm->eap_if->eapTimeout),
-		_SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
-		prefix, _SB(sm->keyDone), _SB(sm->keyRun),
-		_SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
-		prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
-		_SB(sm->reAuthenticate));
-
-	fprintf(f, "%s  Authenticator PAE:\n"
-		"%s    state=%s\n"
-		"%s    eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
-		"%s    portMode=%s reAuthCount=%d\n"
-		"%s    quietPeriod=%d reAuthMax=%d\n"
-		"%s    authEntersConnecting=%d\n"
-		"%s    authEapLogoffsWhileConnecting=%d\n"
-		"%s    authEntersAuthenticating=%d\n"
-		"%s    authAuthSuccessesWhileAuthenticating=%d\n"
-		"%s    authAuthTimeoutsWhileAuthenticating=%d\n"
-		"%s    authAuthFailWhileAuthenticating=%d\n"
-		"%s    authAuthEapStartsWhileAuthenticating=%d\n"
-		"%s    authAuthEapLogoffWhileAuthenticating=%d\n"
-		"%s    authAuthReauthsWhileAuthenticated=%d\n"
-		"%s    authAuthEapStartsWhileAuthenticated=%d\n"
-		"%s    authAuthEapLogoffWhileAuthenticated=%d\n",
-		prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
-		_SB(sm->eapolLogoff), _SB(sm->eapolStart),
-		_SB(sm->eap_if->eapRestart),
-		prefix, port_type_txt(sm->portMode), sm->reAuthCount,
-		prefix, sm->quietPeriod, sm->reAuthMax,
-		prefix, sm->authEntersConnecting,
-		prefix, sm->authEapLogoffsWhileConnecting,
-		prefix, sm->authEntersAuthenticating,
-		prefix, sm->authAuthSuccessesWhileAuthenticating,
-		prefix, sm->authAuthTimeoutsWhileAuthenticating,
-		prefix, sm->authAuthFailWhileAuthenticating,
-		prefix, sm->authAuthEapStartsWhileAuthenticating,
-		prefix, sm->authAuthEapLogoffWhileAuthenticating,
-		prefix, sm->authAuthReauthsWhileAuthenticated,
-		prefix, sm->authAuthEapStartsWhileAuthenticated,
-		prefix, sm->authAuthEapLogoffWhileAuthenticated);
-
-	fprintf(f, "%s  Backend Authentication:\n"
-		"%s    state=%s\n"
-		"%s    eapNoReq=%s eapReq=%s eapResp=%s\n"
-		"%s    serverTimeout=%d\n"
-		"%s    backendResponses=%d\n"
-		"%s    backendAccessChallenges=%d\n"
-		"%s    backendOtherRequestsToSupplicant=%d\n"
-		"%s    backendAuthSuccesses=%d\n"
-		"%s    backendAuthFails=%d\n",
-		prefix, prefix,
-		be_auth_state_txt(sm->be_auth_state),
-		prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
-		_SB(sm->eap_if->eapResp),
-		prefix, sm->serverTimeout,
-		prefix, sm->backendResponses,
-		prefix, sm->backendAccessChallenges,
-		prefix, sm->backendOtherRequestsToSupplicant,
-		prefix, sm->backendAuthSuccesses,
-		prefix, sm->backendAuthFails);
-
-	fprintf(f, "%s  Reauthentication Timer:\n"
-		"%s    state=%s\n"
-		"%s    reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
-		reauth_timer_state_txt(sm->reauth_timer_state), prefix,
-		sm->reAuthPeriod, _SB(sm->reAuthEnabled));
-
-	fprintf(f, "%s  Authenticator Key Transmit:\n"
-		"%s    state=%s\n", prefix, prefix,
-		auth_key_tx_state_txt(sm->auth_key_tx_state));
-
-	fprintf(f, "%s  Key Receive:\n"
-		"%s    state=%s\n"
-		"%s    rxKey=%s\n", prefix, prefix,
-		key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
-
-	fprintf(f, "%s  Controlled Directions:\n"
-		"%s    state=%s\n"
-		"%s    adminControlledDirections=%s "
-		"operControlledDirections=%s\n"
-		"%s    operEdge=%s\n", prefix, prefix,
-		ctrl_dir_state_txt(sm->ctrl_dir_state),
-		prefix, ctrl_dir_txt(sm->adminControlledDirections),
-		ctrl_dir_txt(sm->operControlledDirections),
-		prefix, _SB(sm->operEdge));
-#undef _SB
-}

Copied: vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c (from rev 9639, vendor/wpa/dist/src/eapol_auth/eapol_auth_dump.c)
===================================================================
--- vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_dump.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,225 @@
+/*
+ * IEEE 802.1X-2004 Authenticator - State dump
+ * Copyright (c) 2002-2009, Jouni Malinen <j at 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 "eap_server/eap.h"
+#include "eapol_auth_sm.h"
+#include "eapol_auth_sm_i.h"
+
+static inline const char * port_type_txt(PortTypes pt)
+{
+	switch (pt) {
+	case ForceUnauthorized: return "ForceUnauthorized";
+	case ForceAuthorized: return "ForceAuthorized";
+	case Auto: return "Auto";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * port_state_txt(PortState ps)
+{
+	switch (ps) {
+	case Unauthorized: return "Unauthorized";
+	case Authorized: return "Authorized";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * ctrl_dir_txt(ControlledDirection dir)
+{
+	switch (dir) {
+	case Both: return "Both";
+	case In: return "In";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * auth_pae_state_txt(int s)
+{
+	switch (s) {
+	case AUTH_PAE_INITIALIZE: return "INITIALIZE";
+	case AUTH_PAE_DISCONNECTED: return "DISCONNECTED";
+	case AUTH_PAE_CONNECTING: return "CONNECTING";
+	case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING";
+	case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED";
+	case AUTH_PAE_ABORTING: return "ABORTING";
+	case AUTH_PAE_HELD: return "HELD";
+	case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH";
+	case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH";
+	case AUTH_PAE_RESTART: return "RESTART";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * be_auth_state_txt(int s)
+{
+	switch (s) {
+	case BE_AUTH_REQUEST: return "REQUEST";
+	case BE_AUTH_RESPONSE: return "RESPONSE";
+	case BE_AUTH_SUCCESS: return "SUCCESS";
+	case BE_AUTH_FAIL: return "FAIL";
+	case BE_AUTH_TIMEOUT: return "TIMEOUT";
+	case BE_AUTH_IDLE: return "IDLE";
+	case BE_AUTH_INITIALIZE: return "INITIALIZE";
+	case BE_AUTH_IGNORE: return "IGNORE";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * reauth_timer_state_txt(int s)
+{
+	switch (s) {
+	case REAUTH_TIMER_INITIALIZE: return "INITIALIZE";
+	case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * auth_key_tx_state_txt(int s)
+{
+	switch (s) {
+	case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT";
+	case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * key_rx_state_txt(int s)
+{
+	switch (s) {
+	case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE";
+	case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE";
+	default: return "Unknown";
+	}
+}
+
+
+static inline const char * ctrl_dir_state_txt(int s)
+{
+	switch (s) {
+	case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH";
+	case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH";
+	default: return "Unknown";
+	}
+}
+
+
+void eapol_auth_dump_state(FILE *f, const char *prefix,
+			   struct eapol_state_machine *sm)
+{
+	fprintf(f, "%sEAPOL state machine:\n", prefix);
+	fprintf(f, "%s  aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
+		sm->aWhile, sm->quietWhile, sm->reAuthWhen);
+#define _SB(b) ((b) ? "TRUE" : "FALSE")
+	fprintf(f,
+		"%s  authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
+		"%s  authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
+		"%s  eapSuccess=%s eapTimeout=%s initialize=%s "
+		"keyAvailable=%s\n"
+		"%s  keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
+		"%s  portEnabled=%s portValid=%s reAuthenticate=%s\n",
+		prefix, _SB(sm->authAbort), _SB(sm->authFail),
+		port_state_txt(sm->authPortStatus), _SB(sm->authStart),
+		prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
+		_SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
+		prefix, _SB(sm->eap_if->eapSuccess),
+		_SB(sm->eap_if->eapTimeout),
+		_SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
+		prefix, _SB(sm->keyDone), _SB(sm->keyRun),
+		_SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
+		prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
+		_SB(sm->reAuthenticate));
+
+	fprintf(f, "%s  Authenticator PAE:\n"
+		"%s    state=%s\n"
+		"%s    eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
+		"%s    portMode=%s reAuthCount=%d\n"
+		"%s    quietPeriod=%d reAuthMax=%d\n"
+		"%s    authEntersConnecting=%d\n"
+		"%s    authEapLogoffsWhileConnecting=%d\n"
+		"%s    authEntersAuthenticating=%d\n"
+		"%s    authAuthSuccessesWhileAuthenticating=%d\n"
+		"%s    authAuthTimeoutsWhileAuthenticating=%d\n"
+		"%s    authAuthFailWhileAuthenticating=%d\n"
+		"%s    authAuthEapStartsWhileAuthenticating=%d\n"
+		"%s    authAuthEapLogoffWhileAuthenticating=%d\n"
+		"%s    authAuthReauthsWhileAuthenticated=%d\n"
+		"%s    authAuthEapStartsWhileAuthenticated=%d\n"
+		"%s    authAuthEapLogoffWhileAuthenticated=%d\n",
+		prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
+		_SB(sm->eapolLogoff), _SB(sm->eapolStart),
+		_SB(sm->eap_if->eapRestart),
+		prefix, port_type_txt(sm->portMode), sm->reAuthCount,
+		prefix, sm->quietPeriod, sm->reAuthMax,
+		prefix, sm->authEntersConnecting,
+		prefix, sm->authEapLogoffsWhileConnecting,
+		prefix, sm->authEntersAuthenticating,
+		prefix, sm->authAuthSuccessesWhileAuthenticating,
+		prefix, sm->authAuthTimeoutsWhileAuthenticating,
+		prefix, sm->authAuthFailWhileAuthenticating,
+		prefix, sm->authAuthEapStartsWhileAuthenticating,
+		prefix, sm->authAuthEapLogoffWhileAuthenticating,
+		prefix, sm->authAuthReauthsWhileAuthenticated,
+		prefix, sm->authAuthEapStartsWhileAuthenticated,
+		prefix, sm->authAuthEapLogoffWhileAuthenticated);
+
+	fprintf(f, "%s  Backend Authentication:\n"
+		"%s    state=%s\n"
+		"%s    eapNoReq=%s eapReq=%s eapResp=%s\n"
+		"%s    serverTimeout=%d\n"
+		"%s    backendResponses=%d\n"
+		"%s    backendAccessChallenges=%d\n"
+		"%s    backendOtherRequestsToSupplicant=%d\n"
+		"%s    backendAuthSuccesses=%d\n"
+		"%s    backendAuthFails=%d\n",
+		prefix, prefix,
+		be_auth_state_txt(sm->be_auth_state),
+		prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
+		_SB(sm->eap_if->eapResp),
+		prefix, sm->serverTimeout,
+		prefix, sm->backendResponses,
+		prefix, sm->backendAccessChallenges,
+		prefix, sm->backendOtherRequestsToSupplicant,
+		prefix, sm->backendAuthSuccesses,
+		prefix, sm->backendAuthFails);
+
+	fprintf(f, "%s  Reauthentication Timer:\n"
+		"%s    state=%s\n"
+		"%s    reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
+		reauth_timer_state_txt(sm->reauth_timer_state), prefix,
+		sm->reAuthPeriod, _SB(sm->reAuthEnabled));
+
+	fprintf(f, "%s  Authenticator Key Transmit:\n"
+		"%s    state=%s\n", prefix, prefix,
+		auth_key_tx_state_txt(sm->auth_key_tx_state));
+
+	fprintf(f, "%s  Key Receive:\n"
+		"%s    state=%s\n"
+		"%s    rxKey=%s\n", prefix, prefix,
+		key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
+
+	fprintf(f, "%s  Controlled Directions:\n"
+		"%s    state=%s\n"
+		"%s    adminControlledDirections=%s "
+		"operControlledDirections=%s\n"
+		"%s    operEdge=%s\n", prefix, prefix,
+		ctrl_dir_state_txt(sm->ctrl_dir_state),
+		prefix, ctrl_dir_txt(sm->adminControlledDirections),
+		ctrl_dir_txt(sm->operControlledDirections),
+		prefix, _SB(sm->operEdge));
+#undef _SB
+}

Deleted: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c
===================================================================
--- vendor/wpa/dist/src/eapol_auth/eapol_auth_sm.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1139 +0,0 @@
-/*
- * IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "state_machine.h"
-#include "common/eapol_common.h"
-#include "eap_common/eap_defs.h"
-#include "eap_common/eap_common.h"
-#include "eap_server/eap.h"
-#include "eapol_auth_sm.h"
-#include "eapol_auth_sm_i.h"
-
-#define STATE_MACHINE_DATA struct eapol_state_machine
-#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
-#define STATE_MACHINE_ADDR sm->addr
-
-static struct eapol_callbacks eapol_cb;
-
-/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
-
-#define setPortAuthorized() \
-sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
-#define setPortUnauthorized() \
-sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
-
-/* procedures */
-#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
-#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
-#define txReq() eapol_auth_tx_req(sm)
-#define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
-#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
-#define processKey() do { } while (0)
-
-
-static void eapol_sm_step_run(struct eapol_state_machine *sm);
-static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
-static void eapol_auth_initialize(struct eapol_state_machine *sm);
-
-
-static void eapol_auth_logger(struct eapol_authenticator *eapol,
-			      const u8 *addr, eapol_logger_level level,
-			      const char *txt)
-{
-	if (eapol->cb.logger == NULL)
-		return;
-	eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
-}
-
-
-static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
-			       const u8 *addr, eapol_logger_level level,
-			       const char *fmt, ...)
-{
-	char *format;
-	int maxlen;
-	va_list ap;
-
-	if (eapol->cb.logger == NULL)
-		return;
-
-	maxlen = os_strlen(fmt) + 100;
-	format = os_malloc(maxlen);
-	if (!format)
-		return;
-
-	va_start(ap, fmt);
-	vsnprintf(format, maxlen, fmt, ap);
-	va_end(ap);
-
-	eapol_auth_logger(eapol, addr, level, format);
-
-	os_free(format);
-}
-
-
-static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
-				     int success)
-{
-	struct eap_hdr eap;
-
-	os_memset(&eap, 0, sizeof(eap));
-
-	eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
-	eap.identifier = ++sm->last_eap_id;
-	eap.length = host_to_be16(sizeof(eap));
-
-	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
-			   "Sending canned EAP packet %s (identifier %d)",
-			   success ? "SUCCESS" : "FAILURE", eap.identifier);
-	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
-				 IEEE802_1X_TYPE_EAP_PACKET,
-				 (u8 *) &eap, sizeof(eap));
-	sm->dot1xAuthEapolFramesTx++;
-}
-
-
-static void eapol_auth_tx_req(struct eapol_state_machine *sm)
-{
-	if (sm->eap_if->eapReqData == NULL ||
-	    wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
-		eapol_auth_logger(sm->eapol, sm->addr,
-				  EAPOL_LOGGER_DEBUG,
-				  "TxReq called, but there is no EAP request "
-				  "from authentication server");
-		return;
-	}
-
-	if (sm->flags & EAPOL_SM_WAIT_START) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
-			   " while waiting for EAPOL-Start",
-			   MAC2STR(sm->addr));
-		return;
-	}
-
-	sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
-	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
-			   "Sending EAP Packet (identifier %d)",
-			   sm->last_eap_id);
-	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
-				 IEEE802_1X_TYPE_EAP_PACKET,
-				 wpabuf_head(sm->eap_if->eapReqData),
-				 wpabuf_len(sm->eap_if->eapReqData));
-	sm->dot1xAuthEapolFramesTx++;
-	if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
-		sm->dot1xAuthEapolReqIdFramesTx++;
-	else
-		sm->dot1xAuthEapolReqFramesTx++;
-}
-
-
-/**
- * eapol_port_timers_tick - Port Timers state machine
- * @eloop_ctx: struct eapol_state_machine *
- * @timeout_ctx: Not used
- *
- * This statemachine is implemented as a function that will be called
- * once a second as a registered event loop timeout.
- */
-static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eapol_state_machine *state = timeout_ctx;
-
-	if (state->aWhile > 0) {
-		state->aWhile--;
-		if (state->aWhile == 0) {
-			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
-				   " - aWhile --> 0",
-				   MAC2STR(state->addr));
-		}
-	}
-
-	if (state->quietWhile > 0) {
-		state->quietWhile--;
-		if (state->quietWhile == 0) {
-			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
-				   " - quietWhile --> 0",
-				   MAC2STR(state->addr));
-		}
-	}
-
-	if (state->reAuthWhen > 0) {
-		state->reAuthWhen--;
-		if (state->reAuthWhen == 0) {
-			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
-				   " - reAuthWhen --> 0",
-				   MAC2STR(state->addr));
-		}
-	}
-
-	if (state->eap_if->retransWhile > 0) {
-		state->eap_if->retransWhile--;
-		if (state->eap_if->retransWhile == 0) {
-			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
-				   " - (EAP) retransWhile --> 0",
-				   MAC2STR(state->addr));
-		}
-	}
-
-	eapol_sm_step_run(state);
-
-	eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
-}
-
-
-
-/* Authenticator PAE state machine */
-
-SM_STATE(AUTH_PAE, INITIALIZE)
-{
-	SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
-	sm->portMode = Auto;
-}
-
-
-SM_STATE(AUTH_PAE, DISCONNECTED)
-{
-	int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
-
-	if (sm->eapolLogoff) {
-		if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
-			sm->authEapLogoffsWhileConnecting++;
-		else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
-			sm->authAuthEapLogoffWhileAuthenticated++;
-	}
-
-	SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
-
-	sm->authPortStatus = Unauthorized;
-	setPortUnauthorized();
-	sm->reAuthCount = 0;
-	sm->eapolLogoff = FALSE;
-	if (!from_initialize) {
-		sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-				       sm->flags & EAPOL_SM_PREAUTH);
-	}
-}
-
-
-SM_STATE(AUTH_PAE, RESTART)
-{
-	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
-		if (sm->reAuthenticate)
-			sm->authAuthReauthsWhileAuthenticated++;
-		if (sm->eapolStart)
-			sm->authAuthEapStartsWhileAuthenticated++;
-		if (sm->eapolLogoff)
-			sm->authAuthEapLogoffWhileAuthenticated++;
-	}
-
-	SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
-
-	sm->eap_if->eapRestart = TRUE;
-}
-
-
-SM_STATE(AUTH_PAE, CONNECTING)
-{
-	if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
-		sm->authEntersConnecting++;
-
-	SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
-
-	sm->reAuthenticate = FALSE;
-	sm->reAuthCount++;
-}
-
-
-SM_STATE(AUTH_PAE, HELD)
-{
-	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
-		sm->authAuthFailWhileAuthenticating++;
-
-	SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
-
-	sm->authPortStatus = Unauthorized;
-	setPortUnauthorized();
-	sm->quietWhile = sm->quietPeriod;
-	sm->eapolLogoff = FALSE;
-
-	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
-			   "authentication failed - EAP type: %d (%s)",
-			   sm->eap_type_authsrv,
-			   eap_server_get_name(0, sm->eap_type_authsrv));
-	if (sm->eap_type_authsrv != sm->eap_type_supp) {
-		eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
-				   "Supplicant used different EAP type: "
-				   "%d (%s)", sm->eap_type_supp,
-				   eap_server_get_name(0, sm->eap_type_supp));
-	}
-	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
-			       sm->flags & EAPOL_SM_PREAUTH);
-}
-
-
-SM_STATE(AUTH_PAE, AUTHENTICATED)
-{
-	char *extra = "";
-
-	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
-		sm->authAuthSuccessesWhileAuthenticating++;
-							
-	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
-
-	sm->authPortStatus = Authorized;
-	setPortAuthorized();
-	sm->reAuthCount = 0;
-	if (sm->flags & EAPOL_SM_PREAUTH)
-		extra = " (pre-authentication)";
-	else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
-		extra = " (PMKSA cache)";
-	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
-			   "authenticated - EAP type: %d (%s)%s",
-			   sm->eap_type_authsrv,
-			   eap_server_get_name(0, sm->eap_type_authsrv),
-			   extra);
-	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
-			       sm->flags & EAPOL_SM_PREAUTH);
-}
-
-
-SM_STATE(AUTH_PAE, AUTHENTICATING)
-{
-	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
-
-	sm->eapolStart = FALSE;
-	sm->authSuccess = FALSE;
-	sm->authFail = FALSE;
-	sm->authTimeout = FALSE;
-	sm->authStart = TRUE;
-	sm->keyRun = FALSE;
-	sm->keyDone = FALSE;
-}
-
-
-SM_STATE(AUTH_PAE, ABORTING)
-{
-	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
-		if (sm->authTimeout)
-			sm->authAuthTimeoutsWhileAuthenticating++;
-		if (sm->eapolStart)
-			sm->authAuthEapStartsWhileAuthenticating++;
-		if (sm->eapolLogoff)
-			sm->authAuthEapLogoffWhileAuthenticating++;
-	}
-
-	SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
-
-	sm->authAbort = TRUE;
-	sm->keyRun = FALSE;
-	sm->keyDone = FALSE;
-}
-
-
-SM_STATE(AUTH_PAE, FORCE_AUTH)
-{
-	SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
-
-	sm->authPortStatus = Authorized;
-	setPortAuthorized();
-	sm->portMode = ForceAuthorized;
-	sm->eapolStart = FALSE;
-	txCannedSuccess();
-}
-
-
-SM_STATE(AUTH_PAE, FORCE_UNAUTH)
-{
-	SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
-
-	sm->authPortStatus = Unauthorized;
-	setPortUnauthorized();
-	sm->portMode = ForceUnauthorized;
-	sm->eapolStart = FALSE;
-	txCannedFail();
-}
-
-
-SM_STEP(AUTH_PAE)
-{
-	if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
-	    sm->initialize || !sm->eap_if->portEnabled)
-		SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
-	else if (sm->portControl == ForceAuthorized &&
-		 sm->portMode != sm->portControl &&
-		 !(sm->initialize || !sm->eap_if->portEnabled))
-		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
-	else if (sm->portControl == ForceUnauthorized &&
-		 sm->portMode != sm->portControl &&
-		 !(sm->initialize || !sm->eap_if->portEnabled))
-		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
-	else {
-		switch (sm->auth_pae_state) {
-		case AUTH_PAE_INITIALIZE:
-			SM_ENTER(AUTH_PAE, DISCONNECTED);
-			break;
-		case AUTH_PAE_DISCONNECTED:
-			SM_ENTER(AUTH_PAE, RESTART);
-			break;
-		case AUTH_PAE_RESTART:
-			if (!sm->eap_if->eapRestart)
-				SM_ENTER(AUTH_PAE, CONNECTING);
-			break;
-		case AUTH_PAE_HELD:
-			if (sm->quietWhile == 0)
-				SM_ENTER(AUTH_PAE, RESTART);
-			break;
-		case AUTH_PAE_CONNECTING:
-			if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
-				SM_ENTER(AUTH_PAE, DISCONNECTED);
-			else if ((sm->eap_if->eapReq &&
-				  sm->reAuthCount <= sm->reAuthMax) ||
-				 sm->eap_if->eapSuccess || sm->eap_if->eapFail)
-				SM_ENTER(AUTH_PAE, AUTHENTICATING);
-			break;
-		case AUTH_PAE_AUTHENTICATED:
-			if (sm->eapolStart || sm->reAuthenticate)
-				SM_ENTER(AUTH_PAE, RESTART);
-			else if (sm->eapolLogoff || !sm->portValid)
-				SM_ENTER(AUTH_PAE, DISCONNECTED);
-			break;
-		case AUTH_PAE_AUTHENTICATING:
-			if (sm->authSuccess && sm->portValid)
-				SM_ENTER(AUTH_PAE, AUTHENTICATED);
-			else if (sm->authFail ||
-				 (sm->keyDone && !sm->portValid))
-				SM_ENTER(AUTH_PAE, HELD);
-			else if (sm->eapolStart || sm->eapolLogoff ||
-				 sm->authTimeout)
-				SM_ENTER(AUTH_PAE, ABORTING);
-			break;
-		case AUTH_PAE_ABORTING:
-			if (sm->eapolLogoff && !sm->authAbort)
-				SM_ENTER(AUTH_PAE, DISCONNECTED);
-			else if (!sm->eapolLogoff && !sm->authAbort)
-				SM_ENTER(AUTH_PAE, RESTART);
-			break;
-		case AUTH_PAE_FORCE_AUTH:
-			if (sm->eapolStart)
-				SM_ENTER(AUTH_PAE, FORCE_AUTH);
-			break;
-		case AUTH_PAE_FORCE_UNAUTH:
-			if (sm->eapolStart)
-				SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
-			break;
-		}
-	}
-}
-
-
-
-/* Backend Authentication state machine */
-
-SM_STATE(BE_AUTH, INITIALIZE)
-{
-	SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
-
-	abortAuth();
-	sm->eap_if->eapNoReq = FALSE;
-	sm->authAbort = FALSE;
-}
-
-
-SM_STATE(BE_AUTH, REQUEST)
-{
-	SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
-
-	txReq();
-	sm->eap_if->eapReq = FALSE;
-	sm->backendOtherRequestsToSupplicant++;
-
-	/*
-	 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
-	 * it looks like this would be logical thing to do there since the old
-	 * EAP response would not be valid anymore after the new EAP request
-	 * was sent out.
-	 *
-	 * A race condition has been reported, in which hostapd ended up
-	 * sending out EAP-Response/Identity as a response to the first
-	 * EAP-Request from the main EAP method. This can be avoided by
-	 * clearing eapolEap here.
-	 */
-	sm->eapolEap = FALSE;
-}
-
-
-SM_STATE(BE_AUTH, RESPONSE)
-{
-	SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
-
-	sm->authTimeout = FALSE;
-	sm->eapolEap = FALSE;
-	sm->eap_if->eapNoReq = FALSE;
-	sm->aWhile = sm->serverTimeout;
-	sm->eap_if->eapResp = TRUE;
-	/* sendRespToServer(); */
-	sm->backendResponses++;
-}
-
-
-SM_STATE(BE_AUTH, SUCCESS)
-{
-	SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
-
-	txReq();
-	sm->authSuccess = TRUE;
-	sm->keyRun = TRUE;
-}
-
-
-SM_STATE(BE_AUTH, FAIL)
-{
-	SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
-
-	txReq();
-	sm->authFail = TRUE;
-}
-
-
-SM_STATE(BE_AUTH, TIMEOUT)
-{
-	SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
-
-	sm->authTimeout = TRUE;
-}
-
-
-SM_STATE(BE_AUTH, IDLE)
-{
-	SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
-
-	sm->authStart = FALSE;
-}
-
-
-SM_STATE(BE_AUTH, IGNORE)
-{
-	SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
-
-	sm->eap_if->eapNoReq = FALSE;
-}
-
-
-SM_STEP(BE_AUTH)
-{
-	if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
-		SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
-		return;
-	}
-
-	switch (sm->be_auth_state) {
-	case BE_AUTH_INITIALIZE:
-		SM_ENTER(BE_AUTH, IDLE);
-		break;
-	case BE_AUTH_REQUEST:
-		if (sm->eapolEap)
-			SM_ENTER(BE_AUTH, RESPONSE);
-		else if (sm->eap_if->eapReq)
-			SM_ENTER(BE_AUTH, REQUEST);
-		else if (sm->eap_if->eapTimeout)
-			SM_ENTER(BE_AUTH, TIMEOUT);
-		break;
-	case BE_AUTH_RESPONSE:
-		if (sm->eap_if->eapNoReq)
-			SM_ENTER(BE_AUTH, IGNORE);
-		if (sm->eap_if->eapReq) {
-			sm->backendAccessChallenges++;
-			SM_ENTER(BE_AUTH, REQUEST);
-		} else if (sm->aWhile == 0)
-			SM_ENTER(BE_AUTH, TIMEOUT);
-		else if (sm->eap_if->eapFail) {
-			sm->backendAuthFails++;
-			SM_ENTER(BE_AUTH, FAIL);
-		} else if (sm->eap_if->eapSuccess) {
-			sm->backendAuthSuccesses++;
-			SM_ENTER(BE_AUTH, SUCCESS);
-		}
-		break;
-	case BE_AUTH_SUCCESS:
-		SM_ENTER(BE_AUTH, IDLE);
-		break;
-	case BE_AUTH_FAIL:
-		SM_ENTER(BE_AUTH, IDLE);
-		break;
-	case BE_AUTH_TIMEOUT:
-		SM_ENTER(BE_AUTH, IDLE);
-		break;
-	case BE_AUTH_IDLE:
-		if (sm->eap_if->eapFail && sm->authStart)
-			SM_ENTER(BE_AUTH, FAIL);
-		else if (sm->eap_if->eapReq && sm->authStart)
-			SM_ENTER(BE_AUTH, REQUEST);
-		else if (sm->eap_if->eapSuccess && sm->authStart)
-			SM_ENTER(BE_AUTH, SUCCESS);
-		break;
-	case BE_AUTH_IGNORE:
-		if (sm->eapolEap)
-			SM_ENTER(BE_AUTH, RESPONSE);
-		else if (sm->eap_if->eapReq)
-			SM_ENTER(BE_AUTH, REQUEST);
-		else if (sm->eap_if->eapTimeout)
-			SM_ENTER(BE_AUTH, TIMEOUT);
-		break;
-	}
-}
-
-
-
-/* Reauthentication Timer state machine */
-
-SM_STATE(REAUTH_TIMER, INITIALIZE)
-{
-	SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
-
-	sm->reAuthWhen = sm->reAuthPeriod;
-}
-
-
-SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
-{
-	SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
-
-	sm->reAuthenticate = TRUE;
-	sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
-				  EAPOL_AUTH_REAUTHENTICATE);
-}
-
-
-SM_STEP(REAUTH_TIMER)
-{
-	if (sm->portControl != Auto || sm->initialize ||
-	    sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
-		SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
-		return;
-	}
-
-	switch (sm->reauth_timer_state) {
-	case REAUTH_TIMER_INITIALIZE:
-		if (sm->reAuthWhen == 0)
-			SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
-		break;
-	case REAUTH_TIMER_REAUTHENTICATE:
-		SM_ENTER(REAUTH_TIMER, INITIALIZE);
-		break;
-	}
-}
-
-
-
-/* Authenticator Key Transmit state machine */
-
-SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
-{
-	SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
-}
-
-
-SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
-{
-	SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
-
-	txKey();
-	sm->eap_if->eapKeyAvailable = FALSE;
-	sm->keyDone = TRUE;
-}
-
-
-SM_STEP(AUTH_KEY_TX)
-{
-	if (sm->initialize || sm->portControl != Auto) {
-		SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
-		return;
-	}
-
-	switch (sm->auth_key_tx_state) {
-	case AUTH_KEY_TX_NO_KEY_TRANSMIT:
-		if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
-		    sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
-			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
-		break;
-	case AUTH_KEY_TX_KEY_TRANSMIT:
-		if (!sm->keyTxEnabled || !sm->keyRun)
-			SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
-		else if (sm->eap_if->eapKeyAvailable)
-			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
-		break;
-	}
-}
-
-
-
-/* Key Receive state machine */
-
-SM_STATE(KEY_RX, NO_KEY_RECEIVE)
-{
-	SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
-}
-
-
-SM_STATE(KEY_RX, KEY_RECEIVE)
-{
-	SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
-
-	processKey();
-	sm->rxKey = FALSE;
-}
-
-
-SM_STEP(KEY_RX)
-{
-	if (sm->initialize || !sm->eap_if->portEnabled) {
-		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
-		return;
-	}
-
-	switch (sm->key_rx_state) {
-	case KEY_RX_NO_KEY_RECEIVE:
-		if (sm->rxKey)
-			SM_ENTER(KEY_RX, KEY_RECEIVE);
-		break;
-	case KEY_RX_KEY_RECEIVE:
-		if (sm->rxKey)
-			SM_ENTER(KEY_RX, KEY_RECEIVE);
-		break;
-	}
-}
-
-
-
-/* Controlled Directions state machine */
-
-SM_STATE(CTRL_DIR, FORCE_BOTH)
-{
-	SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
-	sm->operControlledDirections = Both;
-}
-
-
-SM_STATE(CTRL_DIR, IN_OR_BOTH)
-{
-	SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
-	sm->operControlledDirections = sm->adminControlledDirections;
-}
-
-
-SM_STEP(CTRL_DIR)
-{
-	if (sm->initialize) {
-		SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
-		return;
-	}
-
-	switch (sm->ctrl_dir_state) {
-	case CTRL_DIR_FORCE_BOTH:
-		if (sm->eap_if->portEnabled && sm->operEdge)
-			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
-		break;
-	case CTRL_DIR_IN_OR_BOTH:
-		if (sm->operControlledDirections !=
-		    sm->adminControlledDirections)
-			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
-		if (!sm->eap_if->portEnabled || !sm->operEdge)
-			SM_ENTER(CTRL_DIR, FORCE_BOTH);
-		break;
-	}
-}
-
-
-
-struct eapol_state_machine *
-eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
-		 int flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx)
-{
-	struct eapol_state_machine *sm;
-	struct eap_config eap_conf;
-
-	if (eapol == NULL)
-		return NULL;
-
-	sm = os_zalloc(sizeof(*sm));
-	if (sm == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
-			   "failed");
-		return NULL;
-	}
-	sm->radius_identifier = -1;
-	os_memcpy(sm->addr, addr, ETH_ALEN);
-	sm->flags = flags;
-
-	sm->eapol = eapol;
-	sm->sta = sta_ctx;
-
-	/* Set default values for state machine constants */
-	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
-	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
-	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
-
-	sm->be_auth_state = BE_AUTH_INITIALIZE;
-	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
-
-	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
-	sm->reAuthPeriod = eapol->conf.eap_reauth_period;
-	sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
-
-	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
-
-	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
-
-	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
-
-	sm->portControl = Auto;
-
-	if (!eapol->conf.wpa &&
-	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
-		sm->keyTxEnabled = TRUE;
-	else
-		sm->keyTxEnabled = FALSE;
-	if (eapol->conf.wpa)
-		sm->portValid = FALSE;
-	else
-		sm->portValid = TRUE;
-
-	os_memset(&eap_conf, 0, sizeof(eap_conf));
-	eap_conf.eap_server = eapol->conf.eap_server;
-	eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
-	eap_conf.msg_ctx = eapol->conf.msg_ctx;
-	eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
-	eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
-	eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
-	eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
-	eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
-	eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
-	eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
-	eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
-	eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
-	eap_conf.tnc = eapol->conf.tnc;
-	eap_conf.wps = eapol->conf.wps;
-	eap_conf.assoc_wps_ie = assoc_wps_ie;
-	eap_conf.peer_addr = addr;
-	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
-	if (sm->eap == NULL) {
-		eapol_auth_free(sm);
-		return NULL;
-	}
-	sm->eap_if = eap_get_interface(sm->eap);
-
-	eapol_auth_initialize(sm);
-
-	return sm;
-}
-
-
-void eapol_auth_free(struct eapol_state_machine *sm)
-{
-	if (sm == NULL)
-		return;
-
-	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
-	eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
-	if (sm->eap)
-		eap_server_sm_deinit(sm->eap);
-	os_free(sm);
-}
-
-
-static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
-				    const u8 *addr)
-{
-	return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
-}
-
-
-static void eapol_sm_step_run(struct eapol_state_machine *sm)
-{
-	struct eapol_authenticator *eapol = sm->eapol;
-	u8 addr[ETH_ALEN];
-	unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
-		prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
-	int max_steps = 100;
-
-	os_memcpy(addr, sm->addr, ETH_ALEN);
-
-	/*
-	 * Allow EAPOL state machines to run as long as there are state
-	 * changes, but exit and return here through event loop if more than
-	 * 100 steps is needed as a precaution against infinite loops inside
-	 * eloop callback.
-	 */
-restart:
-	prev_auth_pae = sm->auth_pae_state;
-	prev_be_auth = sm->be_auth_state;
-	prev_reauth_timer = sm->reauth_timer_state;
-	prev_auth_key_tx = sm->auth_key_tx_state;
-	prev_key_rx = sm->key_rx_state;
-	prev_ctrl_dir = sm->ctrl_dir_state;
-
-	SM_STEP_RUN(AUTH_PAE);
-	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
-		SM_STEP_RUN(BE_AUTH);
-	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
-		SM_STEP_RUN(REAUTH_TIMER);
-	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
-		SM_STEP_RUN(AUTH_KEY_TX);
-	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
-		SM_STEP_RUN(KEY_RX);
-	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
-		SM_STEP_RUN(CTRL_DIR);
-
-	if (prev_auth_pae != sm->auth_pae_state ||
-	    prev_be_auth != sm->be_auth_state ||
-	    prev_reauth_timer != sm->reauth_timer_state ||
-	    prev_auth_key_tx != sm->auth_key_tx_state ||
-	    prev_key_rx != sm->key_rx_state ||
-	    prev_ctrl_dir != sm->ctrl_dir_state) {
-		if (--max_steps > 0)
-			goto restart;
-		/* Re-run from eloop timeout */
-		eapol_auth_step(sm);
-		return;
-	}
-
-	if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
-		if (eap_server_sm_step(sm->eap)) {
-			if (--max_steps > 0)
-				goto restart;
-			/* Re-run from eloop timeout */
-			eapol_auth_step(sm);
-			return;
-		}
-
-		/* TODO: find a better location for this */
-		if (sm->eap_if->aaaEapResp) {
-			sm->eap_if->aaaEapResp = FALSE;
-			if (sm->eap_if->aaaEapRespData == NULL) {
-				wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
-					   "but no aaaEapRespData available");
-				return;
-			}
-			sm->eapol->cb.aaa_send(
-				sm->eapol->conf.ctx, sm->sta,
-				wpabuf_head(sm->eap_if->aaaEapRespData),
-				wpabuf_len(sm->eap_if->aaaEapRespData));
-		}
-	}
-
-	if (eapol_sm_sta_entry_alive(eapol, addr))
-		sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
-					  EAPOL_AUTH_SM_CHANGE);
-}
-
-
-static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eapol_state_machine *sm = eloop_ctx;
-	eapol_sm_step_run(sm);
-}
-
-
-/**
- * eapol_auth_step - Advance EAPOL state machines
- * @sm: EAPOL state machine
- *
- * This function is called to advance EAPOL state machines after any change
- * that could affect their state.
- */
-void eapol_auth_step(struct eapol_state_machine *sm)
-{
-	/*
-	 * Run eapol_sm_step_run from a registered timeout to make sure that
-	 * other possible timeouts/events are processed and to avoid long
-	 * function call chains.
-	 */
-
-	eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
-}
-
-
-static void eapol_auth_initialize(struct eapol_state_machine *sm)
-{
-	sm->initializing = TRUE;
-	/* Initialize the state machines by asserting initialize and then
-	 * deasserting it after one step */
-	sm->initialize = TRUE;
-	eapol_sm_step_run(sm);
-	sm->initialize = FALSE;
-	eapol_sm_step_run(sm);
-	sm->initializing = FALSE;
-
-	/* Start one second tick for port timers state machine */
-	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
-	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
-}
-
-
-static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
-				 size_t identity_len, int phase2,
-				 struct eap_user *user)
-{
-	struct eapol_state_machine *sm = ctx;
-	return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
-					  identity_len, phase2, user);
-}
-
-
-static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
-{
-	struct eapol_state_machine *sm = ctx;
-	*len = sm->eapol->conf.eap_req_id_text_len;
-	return sm->eapol->conf.eap_req_id_text;
-}
-
-
-static struct eapol_callbacks eapol_cb =
-{
-	eapol_sm_get_eap_user,
-	eapol_sm_get_eap_req_id_text
-};
-
-
-int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
-{
-	if (sm == NULL || ctx != sm->eap)
-		return -1;
-
-	eap_sm_pending_cb(sm->eap);
-	eapol_auth_step(sm);
-
-	return 0;
-}
-
-
-static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
-				 struct eapol_auth_config *src)
-{
-	dst->ctx = src->ctx;
-	dst->eap_reauth_period = src->eap_reauth_period;
-	dst->wpa = src->wpa;
-	dst->individual_wep_key_len = src->individual_wep_key_len;
-	dst->eap_server = src->eap_server;
-	dst->ssl_ctx = src->ssl_ctx;
-	dst->msg_ctx = src->msg_ctx;
-	dst->eap_sim_db_priv = src->eap_sim_db_priv;
-	os_free(dst->eap_req_id_text);
-	if (src->eap_req_id_text) {
-		dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
-		if (dst->eap_req_id_text == NULL)
-			return -1;
-		os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
-			  src->eap_req_id_text_len);
-		dst->eap_req_id_text_len = src->eap_req_id_text_len;
-	} else {
-		dst->eap_req_id_text = NULL;
-		dst->eap_req_id_text_len = 0;
-	}
-	if (src->pac_opaque_encr_key) {
-		dst->pac_opaque_encr_key = os_malloc(16);
-		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
-			  16);
-	} else
-		dst->pac_opaque_encr_key = NULL;
-	if (src->eap_fast_a_id) {
-		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
-		if (dst->eap_fast_a_id == NULL) {
-			os_free(dst->eap_req_id_text);
-			return -1;
-		}
-		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
-			  src->eap_fast_a_id_len);
-		dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
-	} else
-		dst->eap_fast_a_id = NULL;
-	if (src->eap_fast_a_id_info) {
-		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
-		if (dst->eap_fast_a_id_info == NULL) {
-			os_free(dst->eap_req_id_text);
-			os_free(dst->eap_fast_a_id);
-			return -1;
-		}
-	} else
-		dst->eap_fast_a_id_info = NULL;
-	dst->eap_fast_prov = src->eap_fast_prov;
-	dst->pac_key_lifetime = src->pac_key_lifetime;
-	dst->pac_key_refresh_time = src->pac_key_refresh_time;
-	dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
-	dst->tnc = src->tnc;
-	dst->wps = src->wps;
-	return 0;
-}
-
-
-static void eapol_auth_conf_free(struct eapol_auth_config *conf)
-{
-	os_free(conf->eap_req_id_text);
-	conf->eap_req_id_text = NULL;
-	os_free(conf->pac_opaque_encr_key);
-	conf->pac_opaque_encr_key = NULL;
-	os_free(conf->eap_fast_a_id);
-	conf->eap_fast_a_id = NULL;
-	os_free(conf->eap_fast_a_id_info);
-	conf->eap_fast_a_id_info = NULL;
-}
-
-
-struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
-					     struct eapol_auth_cb *cb)
-{
-	struct eapol_authenticator *eapol;
-
-	eapol = os_zalloc(sizeof(*eapol));
-	if (eapol == NULL)
-		return NULL;
-
-	if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
-		os_free(eapol);
-		return NULL;
-	}
-
-	if (conf->individual_wep_key_len > 0) {
-		/* use key0 in individual key and key1 in broadcast key */
-		eapol->default_wep_key_idx = 1;
-	}
-
-	eapol->cb.eapol_send = cb->eapol_send;
-	eapol->cb.aaa_send = cb->aaa_send;
-	eapol->cb.finished = cb->finished;
-	eapol->cb.get_eap_user = cb->get_eap_user;
-	eapol->cb.sta_entry_alive = cb->sta_entry_alive;
-	eapol->cb.logger = cb->logger;
-	eapol->cb.set_port_authorized = cb->set_port_authorized;
-	eapol->cb.abort_auth = cb->abort_auth;
-	eapol->cb.tx_key = cb->tx_key;
-	eapol->cb.eapol_event = cb->eapol_event;
-
-	return eapol;
-}
-
-
-void eapol_auth_deinit(struct eapol_authenticator *eapol)
-{
-	if (eapol == NULL)
-		return;
-
-	eapol_auth_conf_free(&eapol->conf);
-	os_free(eapol->default_wep_key);
-	os_free(eapol);
-}

Copied: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c (from rev 9639, vendor/wpa/dist/src/eapol_auth/eapol_auth_sm.c)
===================================================================
--- vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1151 @@
+/*
+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "state_machine.h"
+#include "common/eapol_common.h"
+#include "eap_common/eap_defs.h"
+#include "eap_common/eap_common.h"
+#include "eap_server/eap.h"
+#include "eapol_auth_sm.h"
+#include "eapol_auth_sm_i.h"
+
+#define STATE_MACHINE_DATA struct eapol_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
+#define STATE_MACHINE_ADDR sm->addr
+
+static struct eapol_callbacks eapol_cb;
+
+/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
+
+#define setPortAuthorized() \
+sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
+#define setPortUnauthorized() \
+sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
+
+/* procedures */
+#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
+#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
+#define txReq() eapol_auth_tx_req(sm)
+#define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
+#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
+#define processKey() do { } while (0)
+
+
+static void eapol_sm_step_run(struct eapol_state_machine *sm);
+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
+static void eapol_auth_initialize(struct eapol_state_machine *sm);
+
+
+static void eapol_auth_logger(struct eapol_authenticator *eapol,
+			      const u8 *addr, eapol_logger_level level,
+			      const char *txt)
+{
+	if (eapol->cb.logger == NULL)
+		return;
+	eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
+}
+
+
+static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
+			       const u8 *addr, eapol_logger_level level,
+			       const char *fmt, ...)
+{
+	char *format;
+	int maxlen;
+	va_list ap;
+
+	if (eapol->cb.logger == NULL)
+		return;
+
+	maxlen = os_strlen(fmt) + 100;
+	format = os_malloc(maxlen);
+	if (!format)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(format, maxlen, fmt, ap);
+	va_end(ap);
+
+	eapol_auth_logger(eapol, addr, level, format);
+
+	os_free(format);
+}
+
+
+static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
+				     int success)
+{
+	struct eap_hdr eap;
+
+	os_memset(&eap, 0, sizeof(eap));
+
+	eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
+	eap.identifier = ++sm->last_eap_id;
+	eap.length = host_to_be16(sizeof(eap));
+
+	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
+			   "Sending canned EAP packet %s (identifier %d)",
+			   success ? "SUCCESS" : "FAILURE", eap.identifier);
+	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
+				 IEEE802_1X_TYPE_EAP_PACKET,
+				 (u8 *) &eap, sizeof(eap));
+	sm->dot1xAuthEapolFramesTx++;
+}
+
+
+static void eapol_auth_tx_req(struct eapol_state_machine *sm)
+{
+	if (sm->eap_if->eapReqData == NULL ||
+	    wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
+		eapol_auth_logger(sm->eapol, sm->addr,
+				  EAPOL_LOGGER_DEBUG,
+				  "TxReq called, but there is no EAP request "
+				  "from authentication server");
+		return;
+	}
+
+	if (sm->flags & EAPOL_SM_WAIT_START) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
+			   " while waiting for EAPOL-Start",
+			   MAC2STR(sm->addr));
+		return;
+	}
+
+	sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
+	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
+			   "Sending EAP Packet (identifier %d)",
+			   sm->last_eap_id);
+	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
+				 IEEE802_1X_TYPE_EAP_PACKET,
+				 wpabuf_head(sm->eap_if->eapReqData),
+				 wpabuf_len(sm->eap_if->eapReqData));
+	sm->dot1xAuthEapolFramesTx++;
+	if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
+		sm->dot1xAuthEapolReqIdFramesTx++;
+	else
+		sm->dot1xAuthEapolReqFramesTx++;
+}
+
+
+/**
+ * eapol_port_timers_tick - Port Timers state machine
+ * @eloop_ctx: struct eapol_state_machine *
+ * @timeout_ctx: Not used
+ *
+ * This statemachine is implemented as a function that will be called
+ * once a second as a registered event loop timeout.
+ */
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_state_machine *state = timeout_ctx;
+
+	if (state->aWhile > 0) {
+		state->aWhile--;
+		if (state->aWhile == 0) {
+			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+				   " - aWhile --> 0",
+				   MAC2STR(state->addr));
+		}
+	}
+
+	if (state->quietWhile > 0) {
+		state->quietWhile--;
+		if (state->quietWhile == 0) {
+			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+				   " - quietWhile --> 0",
+				   MAC2STR(state->addr));
+		}
+	}
+
+	if (state->reAuthWhen > 0) {
+		state->reAuthWhen--;
+		if (state->reAuthWhen == 0) {
+			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+				   " - reAuthWhen --> 0",
+				   MAC2STR(state->addr));
+		}
+	}
+
+	if (state->eap_if->retransWhile > 0) {
+		state->eap_if->retransWhile--;
+		if (state->eap_if->retransWhile == 0) {
+			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
+				   " - (EAP) retransWhile --> 0",
+				   MAC2STR(state->addr));
+		}
+	}
+
+	eapol_sm_step_run(state);
+
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
+}
+
+
+
+/* Authenticator PAE state machine */
+
+SM_STATE(AUTH_PAE, INITIALIZE)
+{
+	SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
+	sm->portMode = Auto;
+}
+
+
+SM_STATE(AUTH_PAE, DISCONNECTED)
+{
+	int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
+
+	if (sm->eapolLogoff) {
+		if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
+			sm->authEapLogoffsWhileConnecting++;
+		else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
+			sm->authAuthEapLogoffWhileAuthenticated++;
+	}
+
+	SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
+
+	sm->authPortStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->reAuthCount = 0;
+	sm->eapolLogoff = FALSE;
+	if (!from_initialize) {
+		sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
+				       sm->flags & EAPOL_SM_PREAUTH);
+	}
+}
+
+
+SM_STATE(AUTH_PAE, RESTART)
+{
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
+		if (sm->reAuthenticate)
+			sm->authAuthReauthsWhileAuthenticated++;
+		if (sm->eapolStart)
+			sm->authAuthEapStartsWhileAuthenticated++;
+		if (sm->eapolLogoff)
+			sm->authAuthEapLogoffWhileAuthenticated++;
+	}
+
+	SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
+
+	sm->eap_if->eapRestart = TRUE;
+}
+
+
+SM_STATE(AUTH_PAE, CONNECTING)
+{
+	if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
+		sm->authEntersConnecting++;
+
+	SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
+
+	sm->reAuthenticate = FALSE;
+	sm->reAuthCount++;
+}
+
+
+SM_STATE(AUTH_PAE, HELD)
+{
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
+		sm->authAuthFailWhileAuthenticating++;
+
+	SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
+
+	sm->authPortStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->quietWhile = sm->quietPeriod;
+	sm->eapolLogoff = FALSE;
+
+	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
+			   "authentication failed - EAP type: %d (%s)",
+			   sm->eap_type_authsrv,
+			   eap_server_get_name(0, sm->eap_type_authsrv));
+	if (sm->eap_type_authsrv != sm->eap_type_supp) {
+		eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
+				   "Supplicant used different EAP type: "
+				   "%d (%s)", sm->eap_type_supp,
+				   eap_server_get_name(0, sm->eap_type_supp));
+	}
+	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
+			       sm->flags & EAPOL_SM_PREAUTH);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATED)
+{
+	char *extra = "";
+
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
+		sm->authAuthSuccessesWhileAuthenticating++;
+							
+	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
+
+	sm->authPortStatus = Authorized;
+	setPortAuthorized();
+	sm->reAuthCount = 0;
+	if (sm->flags & EAPOL_SM_PREAUTH)
+		extra = " (pre-authentication)";
+	else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
+		extra = " (PMKSA cache)";
+	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
+			   "authenticated - EAP type: %d (%s)%s",
+			   sm->eap_type_authsrv,
+			   eap_server_get_name(0, sm->eap_type_authsrv),
+			   extra);
+	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
+			       sm->flags & EAPOL_SM_PREAUTH);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATING)
+{
+	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
+
+	sm->eapolStart = FALSE;
+	sm->authSuccess = FALSE;
+	sm->authFail = FALSE;
+	sm->authTimeout = FALSE;
+	sm->authStart = TRUE;
+	sm->keyRun = FALSE;
+	sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, ABORTING)
+{
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
+		if (sm->authTimeout)
+			sm->authAuthTimeoutsWhileAuthenticating++;
+		if (sm->eapolStart)
+			sm->authAuthEapStartsWhileAuthenticating++;
+		if (sm->eapolLogoff)
+			sm->authAuthEapLogoffWhileAuthenticating++;
+	}
+
+	SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
+
+	sm->authAbort = TRUE;
+	sm->keyRun = FALSE;
+	sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_AUTH)
+{
+	SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
+
+	sm->authPortStatus = Authorized;
+	setPortAuthorized();
+	sm->portMode = ForceAuthorized;
+	sm->eapolStart = FALSE;
+	txCannedSuccess();
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_UNAUTH)
+{
+	SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
+
+	sm->authPortStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->portMode = ForceUnauthorized;
+	sm->eapolStart = FALSE;
+	txCannedFail();
+}
+
+
+SM_STEP(AUTH_PAE)
+{
+	if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
+	    sm->initialize || !sm->eap_if->portEnabled)
+		SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
+	else if (sm->portControl == ForceAuthorized &&
+		 sm->portMode != sm->portControl &&
+		 !(sm->initialize || !sm->eap_if->portEnabled))
+		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
+	else if (sm->portControl == ForceUnauthorized &&
+		 sm->portMode != sm->portControl &&
+		 !(sm->initialize || !sm->eap_if->portEnabled))
+		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
+	else {
+		switch (sm->auth_pae_state) {
+		case AUTH_PAE_INITIALIZE:
+			SM_ENTER(AUTH_PAE, DISCONNECTED);
+			break;
+		case AUTH_PAE_DISCONNECTED:
+			SM_ENTER(AUTH_PAE, RESTART);
+			break;
+		case AUTH_PAE_RESTART:
+			if (!sm->eap_if->eapRestart)
+				SM_ENTER(AUTH_PAE, CONNECTING);
+			break;
+		case AUTH_PAE_HELD:
+			if (sm->quietWhile == 0)
+				SM_ENTER(AUTH_PAE, RESTART);
+			break;
+		case AUTH_PAE_CONNECTING:
+			if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			else if ((sm->eap_if->eapReq &&
+				  sm->reAuthCount <= sm->reAuthMax) ||
+				 sm->eap_if->eapSuccess || sm->eap_if->eapFail)
+				SM_ENTER(AUTH_PAE, AUTHENTICATING);
+			break;
+		case AUTH_PAE_AUTHENTICATED:
+			if (sm->eapolStart || sm->reAuthenticate)
+				SM_ENTER(AUTH_PAE, RESTART);
+			else if (sm->eapolLogoff || !sm->portValid)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			break;
+		case AUTH_PAE_AUTHENTICATING:
+			if (sm->authSuccess && sm->portValid)
+				SM_ENTER(AUTH_PAE, AUTHENTICATED);
+			else if (sm->authFail ||
+				 (sm->keyDone && !sm->portValid))
+				SM_ENTER(AUTH_PAE, HELD);
+			else if (sm->eapolStart || sm->eapolLogoff ||
+				 sm->authTimeout)
+				SM_ENTER(AUTH_PAE, ABORTING);
+			break;
+		case AUTH_PAE_ABORTING:
+			if (sm->eapolLogoff && !sm->authAbort)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			else if (!sm->eapolLogoff && !sm->authAbort)
+				SM_ENTER(AUTH_PAE, RESTART);
+			break;
+		case AUTH_PAE_FORCE_AUTH:
+			if (sm->eapolStart)
+				SM_ENTER(AUTH_PAE, FORCE_AUTH);
+			break;
+		case AUTH_PAE_FORCE_UNAUTH:
+			if (sm->eapolStart)
+				SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+			break;
+		}
+	}
+}
+
+
+
+/* Backend Authentication state machine */
+
+SM_STATE(BE_AUTH, INITIALIZE)
+{
+	SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
+
+	abortAuth();
+	sm->eap_if->eapNoReq = FALSE;
+	sm->authAbort = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, REQUEST)
+{
+	SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
+
+	txReq();
+	sm->eap_if->eapReq = FALSE;
+	sm->backendOtherRequestsToSupplicant++;
+
+	/*
+	 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
+	 * it looks like this would be logical thing to do there since the old
+	 * EAP response would not be valid anymore after the new EAP request
+	 * was sent out.
+	 *
+	 * A race condition has been reported, in which hostapd ended up
+	 * sending out EAP-Response/Identity as a response to the first
+	 * EAP-Request from the main EAP method. This can be avoided by
+	 * clearing eapolEap here.
+	 */
+	sm->eapolEap = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, RESPONSE)
+{
+	SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
+
+	sm->authTimeout = FALSE;
+	sm->eapolEap = FALSE;
+	sm->eap_if->eapNoReq = FALSE;
+	sm->aWhile = sm->serverTimeout;
+	sm->eap_if->eapResp = TRUE;
+	/* sendRespToServer(); */
+	sm->backendResponses++;
+}
+
+
+SM_STATE(BE_AUTH, SUCCESS)
+{
+	SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
+
+	txReq();
+	sm->authSuccess = TRUE;
+	sm->keyRun = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, FAIL)
+{
+	SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
+
+	txReq();
+	sm->authFail = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, TIMEOUT)
+{
+	SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
+
+	sm->authTimeout = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, IDLE)
+{
+	SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
+
+	sm->authStart = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, IGNORE)
+{
+	SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
+
+	sm->eap_if->eapNoReq = FALSE;
+}
+
+
+SM_STEP(BE_AUTH)
+{
+	if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
+		SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
+		return;
+	}
+
+	switch (sm->be_auth_state) {
+	case BE_AUTH_INITIALIZE:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_REQUEST:
+		if (sm->eapolEap)
+			SM_ENTER(BE_AUTH, RESPONSE);
+		else if (sm->eap_if->eapReq)
+			SM_ENTER(BE_AUTH, REQUEST);
+		else if (sm->eap_if->eapTimeout)
+			SM_ENTER(BE_AUTH, TIMEOUT);
+		break;
+	case BE_AUTH_RESPONSE:
+		if (sm->eap_if->eapNoReq)
+			SM_ENTER(BE_AUTH, IGNORE);
+		if (sm->eap_if->eapReq) {
+			sm->backendAccessChallenges++;
+			SM_ENTER(BE_AUTH, REQUEST);
+		} else if (sm->aWhile == 0)
+			SM_ENTER(BE_AUTH, TIMEOUT);
+		else if (sm->eap_if->eapFail) {
+			sm->backendAuthFails++;
+			SM_ENTER(BE_AUTH, FAIL);
+		} else if (sm->eap_if->eapSuccess) {
+			sm->backendAuthSuccesses++;
+			SM_ENTER(BE_AUTH, SUCCESS);
+		}
+		break;
+	case BE_AUTH_SUCCESS:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_FAIL:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_TIMEOUT:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_IDLE:
+		if (sm->eap_if->eapFail && sm->authStart)
+			SM_ENTER(BE_AUTH, FAIL);
+		else if (sm->eap_if->eapReq && sm->authStart)
+			SM_ENTER(BE_AUTH, REQUEST);
+		else if (sm->eap_if->eapSuccess && sm->authStart)
+			SM_ENTER(BE_AUTH, SUCCESS);
+		break;
+	case BE_AUTH_IGNORE:
+		if (sm->eapolEap)
+			SM_ENTER(BE_AUTH, RESPONSE);
+		else if (sm->eap_if->eapReq)
+			SM_ENTER(BE_AUTH, REQUEST);
+		else if (sm->eap_if->eapTimeout)
+			SM_ENTER(BE_AUTH, TIMEOUT);
+		break;
+	}
+}
+
+
+
+/* Reauthentication Timer state machine */
+
+SM_STATE(REAUTH_TIMER, INITIALIZE)
+{
+	SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
+
+	sm->reAuthWhen = sm->reAuthPeriod;
+}
+
+
+SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
+{
+	SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
+
+	sm->reAuthenticate = TRUE;
+	sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
+				  EAPOL_AUTH_REAUTHENTICATE);
+}
+
+
+SM_STEP(REAUTH_TIMER)
+{
+	if (sm->portControl != Auto || sm->initialize ||
+	    sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
+		SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
+		return;
+	}
+
+	switch (sm->reauth_timer_state) {
+	case REAUTH_TIMER_INITIALIZE:
+		if (sm->reAuthWhen == 0)
+			SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
+		break;
+	case REAUTH_TIMER_REAUTHENTICATE:
+		SM_ENTER(REAUTH_TIMER, INITIALIZE);
+		break;
+	}
+}
+
+
+
+/* Authenticator Key Transmit state machine */
+
+SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
+{
+	SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
+}
+
+
+SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
+{
+	SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
+
+	txKey();
+	sm->eap_if->eapKeyAvailable = FALSE;
+	sm->keyDone = TRUE;
+}
+
+
+SM_STEP(AUTH_KEY_TX)
+{
+	if (sm->initialize || sm->portControl != Auto) {
+		SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+		return;
+	}
+
+	switch (sm->auth_key_tx_state) {
+	case AUTH_KEY_TX_NO_KEY_TRANSMIT:
+		if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
+		    sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
+			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+		break;
+	case AUTH_KEY_TX_KEY_TRANSMIT:
+		if (!sm->keyTxEnabled || !sm->keyRun)
+			SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+		else if (sm->eap_if->eapKeyAvailable)
+			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+		break;
+	}
+}
+
+
+
+/* Key Receive state machine */
+
+SM_STATE(KEY_RX, NO_KEY_RECEIVE)
+{
+	SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
+}
+
+
+SM_STATE(KEY_RX, KEY_RECEIVE)
+{
+	SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
+
+	processKey();
+	sm->rxKey = FALSE;
+}
+
+
+SM_STEP(KEY_RX)
+{
+	if (sm->initialize || !sm->eap_if->portEnabled) {
+		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
+		return;
+	}
+
+	switch (sm->key_rx_state) {
+	case KEY_RX_NO_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	case KEY_RX_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	}
+}
+
+
+
+/* Controlled Directions state machine */
+
+SM_STATE(CTRL_DIR, FORCE_BOTH)
+{
+	SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
+	sm->operControlledDirections = Both;
+}
+
+
+SM_STATE(CTRL_DIR, IN_OR_BOTH)
+{
+	SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
+	sm->operControlledDirections = sm->adminControlledDirections;
+}
+
+
+SM_STEP(CTRL_DIR)
+{
+	if (sm->initialize) {
+		SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
+		return;
+	}
+
+	switch (sm->ctrl_dir_state) {
+	case CTRL_DIR_FORCE_BOTH:
+		if (sm->eap_if->portEnabled && sm->operEdge)
+			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+		break;
+	case CTRL_DIR_IN_OR_BOTH:
+		if (sm->operControlledDirections !=
+		    sm->adminControlledDirections)
+			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+		if (!sm->eap_if->portEnabled || !sm->operEdge)
+			SM_ENTER(CTRL_DIR, FORCE_BOTH);
+		break;
+	}
+}
+
+
+
+struct eapol_state_machine *
+eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
+		 int flags, const struct wpabuf *assoc_wps_ie,
+		 const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+		 const char *identity, const char *radius_cui)
+{
+	struct eapol_state_machine *sm;
+	struct eap_config eap_conf;
+
+	if (eapol == NULL)
+		return NULL;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
+			   "failed");
+		return NULL;
+	}
+	sm->radius_identifier = -1;
+	os_memcpy(sm->addr, addr, ETH_ALEN);
+	sm->flags = flags;
+
+	sm->eapol = eapol;
+	sm->sta = sta_ctx;
+
+	/* Set default values for state machine constants */
+	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
+	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
+	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
+
+	sm->be_auth_state = BE_AUTH_INITIALIZE;
+	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
+
+	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
+	sm->reAuthPeriod = eapol->conf.eap_reauth_period;
+	sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
+
+	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
+
+	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
+
+	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
+
+	sm->portControl = Auto;
+
+	if (!eapol->conf.wpa &&
+	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
+		sm->keyTxEnabled = TRUE;
+	else
+		sm->keyTxEnabled = FALSE;
+	if (eapol->conf.wpa)
+		sm->portValid = FALSE;
+	else
+		sm->portValid = TRUE;
+
+	os_memset(&eap_conf, 0, sizeof(eap_conf));
+	eap_conf.eap_server = eapol->conf.eap_server;
+	eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
+	eap_conf.msg_ctx = eapol->conf.msg_ctx;
+	eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
+	eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
+	eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
+	eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
+	eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
+	eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
+	eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
+	eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
+	eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
+	eap_conf.tnc = eapol->conf.tnc;
+	eap_conf.wps = eapol->conf.wps;
+	eap_conf.assoc_wps_ie = assoc_wps_ie;
+	eap_conf.assoc_p2p_ie = assoc_p2p_ie;
+	eap_conf.peer_addr = addr;
+	eap_conf.fragment_size = eapol->conf.fragment_size;
+	eap_conf.pwd_group = eapol->conf.pwd_group;
+	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
+	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
+	if (sm->eap == NULL) {
+		eapol_auth_free(sm);
+		return NULL;
+	}
+	sm->eap_if = eap_get_interface(sm->eap);
+
+	eapol_auth_initialize(sm);
+
+	if (identity) {
+		sm->identity = (u8 *) os_strdup(identity);
+		if (sm->identity)
+			sm->identity_len = os_strlen(identity);
+	}
+	if (radius_cui)
+		sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+						   os_strlen(radius_cui));
+
+	return sm;
+}
+
+
+void eapol_auth_free(struct eapol_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
+	if (sm->eap)
+		eap_server_sm_deinit(sm->eap);
+	os_free(sm);
+}
+
+
+static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
+				    const u8 *addr)
+{
+	return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
+}
+
+
+static void eapol_sm_step_run(struct eapol_state_machine *sm)
+{
+	struct eapol_authenticator *eapol = sm->eapol;
+	u8 addr[ETH_ALEN];
+	unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
+		prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
+	int max_steps = 100;
+
+	os_memcpy(addr, sm->addr, ETH_ALEN);
+
+	/*
+	 * Allow EAPOL state machines to run as long as there are state
+	 * changes, but exit and return here through event loop if more than
+	 * 100 steps is needed as a precaution against infinite loops inside
+	 * eloop callback.
+	 */
+restart:
+	prev_auth_pae = sm->auth_pae_state;
+	prev_be_auth = sm->be_auth_state;
+	prev_reauth_timer = sm->reauth_timer_state;
+	prev_auth_key_tx = sm->auth_key_tx_state;
+	prev_key_rx = sm->key_rx_state;
+	prev_ctrl_dir = sm->ctrl_dir_state;
+
+	SM_STEP_RUN(AUTH_PAE);
+	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+		SM_STEP_RUN(BE_AUTH);
+	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+		SM_STEP_RUN(REAUTH_TIMER);
+	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+		SM_STEP_RUN(AUTH_KEY_TX);
+	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+		SM_STEP_RUN(KEY_RX);
+	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
+		SM_STEP_RUN(CTRL_DIR);
+
+	if (prev_auth_pae != sm->auth_pae_state ||
+	    prev_be_auth != sm->be_auth_state ||
+	    prev_reauth_timer != sm->reauth_timer_state ||
+	    prev_auth_key_tx != sm->auth_key_tx_state ||
+	    prev_key_rx != sm->key_rx_state ||
+	    prev_ctrl_dir != sm->ctrl_dir_state) {
+		if (--max_steps > 0)
+			goto restart;
+		/* Re-run from eloop timeout */
+		eapol_auth_step(sm);
+		return;
+	}
+
+	if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
+		if (eap_server_sm_step(sm->eap)) {
+			if (--max_steps > 0)
+				goto restart;
+			/* Re-run from eloop timeout */
+			eapol_auth_step(sm);
+			return;
+		}
+
+		/* TODO: find a better location for this */
+		if (sm->eap_if->aaaEapResp) {
+			sm->eap_if->aaaEapResp = FALSE;
+			if (sm->eap_if->aaaEapRespData == NULL) {
+				wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
+					   "but no aaaEapRespData available");
+				return;
+			}
+			sm->eapol->cb.aaa_send(
+				sm->eapol->conf.ctx, sm->sta,
+				wpabuf_head(sm->eap_if->aaaEapRespData),
+				wpabuf_len(sm->eap_if->aaaEapRespData));
+		}
+	}
+
+	if (eapol_sm_sta_entry_alive(eapol, addr))
+		sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
+					  EAPOL_AUTH_SM_CHANGE);
+}
+
+
+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_state_machine *sm = eloop_ctx;
+	eapol_sm_step_run(sm);
+}
+
+
+/**
+ * eapol_auth_step - Advance EAPOL state machines
+ * @sm: EAPOL state machine
+ *
+ * This function is called to advance EAPOL state machines after any change
+ * that could affect their state.
+ */
+void eapol_auth_step(struct eapol_state_machine *sm)
+{
+	/*
+	 * Run eapol_sm_step_run from a registered timeout to make sure that
+	 * other possible timeouts/events are processed and to avoid long
+	 * function call chains.
+	 */
+
+	eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
+}
+
+
+static void eapol_auth_initialize(struct eapol_state_machine *sm)
+{
+	sm->initializing = TRUE;
+	/* Initialize the state machines by asserting initialize and then
+	 * deasserting it after one step */
+	sm->initialize = TRUE;
+	eapol_sm_step_run(sm);
+	sm->initialize = FALSE;
+	eapol_sm_step_run(sm);
+	sm->initializing = FALSE;
+
+	/* Start one second tick for port timers state machine */
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+}
+
+
+static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
+				 size_t identity_len, int phase2,
+				 struct eap_user *user)
+{
+	struct eapol_state_machine *sm = ctx;
+	return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
+					  identity_len, phase2, user);
+}
+
+
+static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
+{
+	struct eapol_state_machine *sm = ctx;
+	*len = sm->eapol->conf.eap_req_id_text_len;
+	return sm->eapol->conf.eap_req_id_text;
+}
+
+
+static struct eapol_callbacks eapol_cb =
+{
+	eapol_sm_get_eap_user,
+	eapol_sm_get_eap_req_id_text
+};
+
+
+int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
+{
+	if (sm == NULL || ctx == NULL || ctx != sm->eap)
+		return -1;
+
+	eap_sm_pending_cb(sm->eap);
+	eapol_auth_step(sm);
+
+	return 0;
+}
+
+
+static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
+				 struct eapol_auth_config *src)
+{
+	dst->ctx = src->ctx;
+	dst->eap_reauth_period = src->eap_reauth_period;
+	dst->wpa = src->wpa;
+	dst->individual_wep_key_len = src->individual_wep_key_len;
+	dst->eap_server = src->eap_server;
+	dst->ssl_ctx = src->ssl_ctx;
+	dst->msg_ctx = src->msg_ctx;
+	dst->eap_sim_db_priv = src->eap_sim_db_priv;
+	os_free(dst->eap_req_id_text);
+	dst->pwd_group = src->pwd_group;
+	dst->pbc_in_m1 = src->pbc_in_m1;
+	if (src->eap_req_id_text) {
+		dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
+		if (dst->eap_req_id_text == NULL)
+			return -1;
+		os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
+			  src->eap_req_id_text_len);
+		dst->eap_req_id_text_len = src->eap_req_id_text_len;
+	} else {
+		dst->eap_req_id_text = NULL;
+		dst->eap_req_id_text_len = 0;
+	}
+	if (src->pac_opaque_encr_key) {
+		dst->pac_opaque_encr_key = os_malloc(16);
+		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
+			  16);
+	} else
+		dst->pac_opaque_encr_key = NULL;
+	if (src->eap_fast_a_id) {
+		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
+		if (dst->eap_fast_a_id == NULL) {
+			os_free(dst->eap_req_id_text);
+			return -1;
+		}
+		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
+			  src->eap_fast_a_id_len);
+		dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
+	} else
+		dst->eap_fast_a_id = NULL;
+	if (src->eap_fast_a_id_info) {
+		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
+		if (dst->eap_fast_a_id_info == NULL) {
+			os_free(dst->eap_req_id_text);
+			os_free(dst->eap_fast_a_id);
+			return -1;
+		}
+	} else
+		dst->eap_fast_a_id_info = NULL;
+	dst->eap_fast_prov = src->eap_fast_prov;
+	dst->pac_key_lifetime = src->pac_key_lifetime;
+	dst->pac_key_refresh_time = src->pac_key_refresh_time;
+	dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
+	dst->tnc = src->tnc;
+	dst->wps = src->wps;
+	dst->fragment_size = src->fragment_size;
+	return 0;
+}
+
+
+static void eapol_auth_conf_free(struct eapol_auth_config *conf)
+{
+	os_free(conf->eap_req_id_text);
+	conf->eap_req_id_text = NULL;
+	os_free(conf->pac_opaque_encr_key);
+	conf->pac_opaque_encr_key = NULL;
+	os_free(conf->eap_fast_a_id);
+	conf->eap_fast_a_id = NULL;
+	os_free(conf->eap_fast_a_id_info);
+	conf->eap_fast_a_id_info = NULL;
+}
+
+
+struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
+					     struct eapol_auth_cb *cb)
+{
+	struct eapol_authenticator *eapol;
+
+	eapol = os_zalloc(sizeof(*eapol));
+	if (eapol == NULL)
+		return NULL;
+
+	if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
+		os_free(eapol);
+		return NULL;
+	}
+
+	if (conf->individual_wep_key_len > 0) {
+		/* use key0 in individual key and key1 in broadcast key */
+		eapol->default_wep_key_idx = 1;
+	}
+
+	eapol->cb.eapol_send = cb->eapol_send;
+	eapol->cb.aaa_send = cb->aaa_send;
+	eapol->cb.finished = cb->finished;
+	eapol->cb.get_eap_user = cb->get_eap_user;
+	eapol->cb.sta_entry_alive = cb->sta_entry_alive;
+	eapol->cb.logger = cb->logger;
+	eapol->cb.set_port_authorized = cb->set_port_authorized;
+	eapol->cb.abort_auth = cb->abort_auth;
+	eapol->cb.tx_key = cb->tx_key;
+	eapol->cb.eapol_event = cb->eapol_event;
+
+	return eapol;
+}
+
+
+void eapol_auth_deinit(struct eapol_authenticator *eapol)
+{
+	if (eapol == NULL)
+		return;
+
+	eapol_auth_conf_free(&eapol->conf);
+	os_free(eapol->default_wep_key);
+	os_free(eapol);
+}

Deleted: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h
===================================================================
--- vendor/wpa/dist/src/eapol_auth/eapol_auth_sm.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,89 +0,0 @@
-/*
- * IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAPOL_AUTH_SM_H
-#define EAPOL_AUTH_SM_H
-
-#define EAPOL_SM_PREAUTH BIT(0)
-#define EAPOL_SM_WAIT_START BIT(1)
-#define EAPOL_SM_USES_WPA BIT(2)
-#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
-
-struct eapol_auth_config {
-	int eap_reauth_period;
-	int wpa;
-	int individual_wep_key_len;
-	int eap_server;
-	void *ssl_ctx;
-	void *msg_ctx;
-	void *eap_sim_db_priv;
-	char *eap_req_id_text; /* a copy of this will be allocated */
-	size_t eap_req_id_text_len;
-	u8 *pac_opaque_encr_key;
-	u8 *eap_fast_a_id;
-	size_t eap_fast_a_id_len;
-	char *eap_fast_a_id_info;
-	int eap_fast_prov;
-	int pac_key_lifetime;
-	int pac_key_refresh_time;
-	int eap_sim_aka_result_ind;
-	int tnc;
-	struct wps_context *wps;
-
-	/* Opaque context pointer to owner data for callback functions */
-	void *ctx;
-};
-
-struct eap_user;
-
-typedef enum {
-	EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
-} eapol_logger_level;
-
-enum eapol_event {
-	EAPOL_AUTH_SM_CHANGE,
-	EAPOL_AUTH_REAUTHENTICATE
-};
-
-struct eapol_auth_cb {
-	void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data,
-			   size_t datalen);
-	void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
-			 size_t datalen);
-	void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
-	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
-			    int phase2, struct eap_user *user);
-	int (*sta_entry_alive)(void *ctx, const u8 *addr);
-	void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level,
-		       const char *txt);
-	void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized);
-	void (*abort_auth)(void *ctx, void *sta_ctx);
-	void (*tx_key)(void *ctx, void *sta_ctx);
-	void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type);
-};
-
-
-struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
-					     struct eapol_auth_cb *cb);
-void eapol_auth_deinit(struct eapol_authenticator *eapol);
-struct eapol_state_machine *
-eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
-		 int flags, const struct wpabuf *assoc_wps_ie, void *sta_ctx);
-void eapol_auth_free(struct eapol_state_machine *sm);
-void eapol_auth_step(struct eapol_state_machine *sm);
-void eapol_auth_dump_state(FILE *f, const char *prefix,
-			   struct eapol_state_machine *sm);
-int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
-
-#endif /* EAPOL_AUTH_SM_H */

Copied: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h (from rev 9639, vendor/wpa/dist/src/eapol_auth/eapol_auth_sm.h)
===================================================================
--- vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,88 @@
+/*
+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_AUTH_SM_H
+#define EAPOL_AUTH_SM_H
+
+#define EAPOL_SM_PREAUTH BIT(0)
+#define EAPOL_SM_WAIT_START BIT(1)
+#define EAPOL_SM_USES_WPA BIT(2)
+#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3)
+
+struct eapol_auth_config {
+	int eap_reauth_period;
+	int wpa;
+	int individual_wep_key_len;
+	int eap_server;
+	void *ssl_ctx;
+	void *msg_ctx;
+	void *eap_sim_db_priv;
+	char *eap_req_id_text; /* a copy of this will be allocated */
+	size_t eap_req_id_text_len;
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	int eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	struct wps_context *wps;
+	int fragment_size;
+	u16 pwd_group;
+	int pbc_in_m1;
+
+	/* Opaque context pointer to owner data for callback functions */
+	void *ctx;
+};
+
+struct eap_user;
+
+typedef enum {
+	EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
+} eapol_logger_level;
+
+enum eapol_event {
+	EAPOL_AUTH_SM_CHANGE,
+	EAPOL_AUTH_REAUTHENTICATE
+};
+
+struct eapol_auth_cb {
+	void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data,
+			   size_t datalen);
+	void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
+			 size_t datalen);
+	void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
+	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+			    int phase2, struct eap_user *user);
+	int (*sta_entry_alive)(void *ctx, const u8 *addr);
+	void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level,
+		       const char *txt);
+	void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized);
+	void (*abort_auth)(void *ctx, void *sta_ctx);
+	void (*tx_key)(void *ctx, void *sta_ctx);
+	void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type);
+};
+
+
+struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
+					     struct eapol_auth_cb *cb);
+void eapol_auth_deinit(struct eapol_authenticator *eapol);
+struct eapol_state_machine *
+eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
+		 int flags, const struct wpabuf *assoc_wps_ie,
+		 const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+		 const char *identity, const char *radius_cui);
+void eapol_auth_free(struct eapol_state_machine *sm);
+void eapol_auth_step(struct eapol_state_machine *sm);
+void eapol_auth_dump_state(FILE *f, const char *prefix,
+			   struct eapol_state_machine *sm);
+int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
+
+#endif /* EAPOL_AUTH_SM_H */

Deleted: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h
===================================================================
--- vendor/wpa/dist/src/eapol_auth/eapol_auth_sm_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,183 +0,0 @@
-/*
- * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions)
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAPOL_AUTH_SM_I_H
-#define EAPOL_AUTH_SM_I_H
-
-#include "common/defs.h"
-#include "radius/radius.h"
-
-/* IEEE Std 802.1X-2004, Ch. 8.2 */
-
-typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
-	PortTypes;
-typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
-typedef enum { Both = 0, In = 1 } ControlledDirection;
-typedef unsigned int Counter;
-
-
-/**
- * struct eapol_authenticator - Global EAPOL authenticator data
- */
-struct eapol_authenticator {
-	struct eapol_auth_config conf;
-	struct eapol_auth_cb cb;
-
-	u8 *default_wep_key;
-	u8 default_wep_key_idx;
-};
-
-
-/**
- * struct eapol_state_machine - Per-Supplicant Authenticator state machines
- */
-struct eapol_state_machine {
-	/* timers */
-	int aWhile;
-	int quietWhile;
-	int reAuthWhen;
-
-	/* global variables */
-	Boolean authAbort;
-	Boolean authFail;
-	PortState authPortStatus;
-	Boolean authStart;
-	Boolean authTimeout;
-	Boolean authSuccess;
-	Boolean eapolEap;
-	Boolean initialize;
-	Boolean keyDone;
-	Boolean keyRun;
-	Boolean keyTxEnabled;
-	PortTypes portControl;
-	Boolean portValid;
-	Boolean reAuthenticate;
-
-	/* Port Timers state machine */
-	/* 'Boolean tick' implicitly handled as registered timeout */
-
-	/* Authenticator PAE state machine */
-	enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
-	       AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
-	       AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
-	       AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
-	/* variables */
-	Boolean eapolLogoff;
-	Boolean eapolStart;
-	PortTypes portMode;
-	unsigned int reAuthCount;
-	/* constants */
-	unsigned int quietPeriod; /* default 60; 0..65535 */
-#define AUTH_PAE_DEFAULT_quietPeriod 60
-	unsigned int reAuthMax; /* default 2 */
-#define AUTH_PAE_DEFAULT_reAuthMax 2
-	/* counters */
-	Counter authEntersConnecting;
-	Counter authEapLogoffsWhileConnecting;
-	Counter authEntersAuthenticating;
-	Counter authAuthSuccessesWhileAuthenticating;
-	Counter authAuthTimeoutsWhileAuthenticating;
-	Counter authAuthFailWhileAuthenticating;
-	Counter authAuthEapStartsWhileAuthenticating;
-	Counter authAuthEapLogoffWhileAuthenticating;
-	Counter authAuthReauthsWhileAuthenticated;
-	Counter authAuthEapStartsWhileAuthenticated;
-	Counter authAuthEapLogoffWhileAuthenticated;
-
-	/* Backend Authentication state machine */
-	enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
-	       BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
-	       BE_AUTH_IGNORE
-	} be_auth_state;
-	/* constants */
-	unsigned int serverTimeout; /* default 30; 1..X */
-#define BE_AUTH_DEFAULT_serverTimeout 30
-	/* counters */
-	Counter backendResponses;
-	Counter backendAccessChallenges;
-	Counter backendOtherRequestsToSupplicant;
-	Counter backendAuthSuccesses;
-	Counter backendAuthFails;
-
-	/* Reauthentication Timer state machine */
-	enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
-	} reauth_timer_state;
-	/* constants */
-	unsigned int reAuthPeriod; /* default 3600 s */
-	Boolean reAuthEnabled;
-
-	/* Authenticator Key Transmit state machine */
-	enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
-	} auth_key_tx_state;
-
-	/* Key Receive state machine */
-	enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
-	/* variables */
-	Boolean rxKey;
-
-	/* Controlled Directions state machine */
-	enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
-	/* variables */
-	ControlledDirection adminControlledDirections;
-	ControlledDirection operControlledDirections;
-	Boolean operEdge;
-
-	/* Authenticator Statistics Table */
-	Counter dot1xAuthEapolFramesRx;
-	Counter dot1xAuthEapolFramesTx;
-	Counter dot1xAuthEapolStartFramesRx;
-	Counter dot1xAuthEapolLogoffFramesRx;
-	Counter dot1xAuthEapolRespIdFramesRx;
-	Counter dot1xAuthEapolRespFramesRx;
-	Counter dot1xAuthEapolReqIdFramesTx;
-	Counter dot1xAuthEapolReqFramesTx;
-	Counter dot1xAuthInvalidEapolFramesRx;
-	Counter dot1xAuthEapLengthErrorFramesRx;
-	Counter dot1xAuthLastEapolFrameVersion;
-
-	/* Other variables - not defined in IEEE 802.1X */
-	u8 addr[ETH_ALEN]; /* Supplicant address */
-	int flags; /* EAPOL_SM_* */
-
-	/* EAPOL/AAA <-> EAP full authenticator interface */
-	struct eap_eapol_interface *eap_if;
-
-	int radius_identifier;
-	/* TODO: check when the last messages can be released */
-	struct radius_msg *last_recv_radius;
-	u8 last_eap_id; /* last used EAP Identifier */
-	u8 *identity;
-	size_t identity_len;
-	u8 eap_type_authsrv; /* EAP type of the last EAP packet from
-			      * Authentication server */
-	u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
-	struct radius_class_data radius_class;
-
-	/* 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 */
-	Boolean changed;
-
-	struct eapol_authenticator *eapol;
-
-	void *sta; /* station context pointer to use in callbacks */
-};
-
-#endif /* EAPOL_AUTH_SM_I_H */

Copied: vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h (from rev 9639, vendor/wpa/dist/src/eapol_auth/eapol_auth_sm_i.h)
===================================================================
--- vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_auth/eapol_auth_sm_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,178 @@
+/*
+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions)
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_AUTH_SM_I_H
+#define EAPOL_AUTH_SM_I_H
+
+#include "common/defs.h"
+#include "radius/radius.h"
+
+/* IEEE Std 802.1X-2004, Ch. 8.2 */
+
+typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
+	PortTypes;
+typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
+typedef enum { Both = 0, In = 1 } ControlledDirection;
+typedef unsigned int Counter;
+
+
+/**
+ * struct eapol_authenticator - Global EAPOL authenticator data
+ */
+struct eapol_authenticator {
+	struct eapol_auth_config conf;
+	struct eapol_auth_cb cb;
+
+	u8 *default_wep_key;
+	u8 default_wep_key_idx;
+};
+
+
+/**
+ * struct eapol_state_machine - Per-Supplicant Authenticator state machines
+ */
+struct eapol_state_machine {
+	/* timers */
+	int aWhile;
+	int quietWhile;
+	int reAuthWhen;
+
+	/* global variables */
+	Boolean authAbort;
+	Boolean authFail;
+	PortState authPortStatus;
+	Boolean authStart;
+	Boolean authTimeout;
+	Boolean authSuccess;
+	Boolean eapolEap;
+	Boolean initialize;
+	Boolean keyDone;
+	Boolean keyRun;
+	Boolean keyTxEnabled;
+	PortTypes portControl;
+	Boolean portValid;
+	Boolean reAuthenticate;
+
+	/* Port Timers state machine */
+	/* 'Boolean tick' implicitly handled as registered timeout */
+
+	/* Authenticator PAE state machine */
+	enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
+	       AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
+	       AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
+	       AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
+	/* variables */
+	Boolean eapolLogoff;
+	Boolean eapolStart;
+	PortTypes portMode;
+	unsigned int reAuthCount;
+	/* constants */
+	unsigned int quietPeriod; /* default 60; 0..65535 */
+#define AUTH_PAE_DEFAULT_quietPeriod 60
+	unsigned int reAuthMax; /* default 2 */
+#define AUTH_PAE_DEFAULT_reAuthMax 2
+	/* counters */
+	Counter authEntersConnecting;
+	Counter authEapLogoffsWhileConnecting;
+	Counter authEntersAuthenticating;
+	Counter authAuthSuccessesWhileAuthenticating;
+	Counter authAuthTimeoutsWhileAuthenticating;
+	Counter authAuthFailWhileAuthenticating;
+	Counter authAuthEapStartsWhileAuthenticating;
+	Counter authAuthEapLogoffWhileAuthenticating;
+	Counter authAuthReauthsWhileAuthenticated;
+	Counter authAuthEapStartsWhileAuthenticated;
+	Counter authAuthEapLogoffWhileAuthenticated;
+
+	/* Backend Authentication state machine */
+	enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
+	       BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
+	       BE_AUTH_IGNORE
+	} be_auth_state;
+	/* constants */
+	unsigned int serverTimeout; /* default 30; 1..X */
+#define BE_AUTH_DEFAULT_serverTimeout 30
+	/* counters */
+	Counter backendResponses;
+	Counter backendAccessChallenges;
+	Counter backendOtherRequestsToSupplicant;
+	Counter backendAuthSuccesses;
+	Counter backendAuthFails;
+
+	/* Reauthentication Timer state machine */
+	enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
+	} reauth_timer_state;
+	/* constants */
+	unsigned int reAuthPeriod; /* default 3600 s */
+	Boolean reAuthEnabled;
+
+	/* Authenticator Key Transmit state machine */
+	enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
+	} auth_key_tx_state;
+
+	/* Key Receive state machine */
+	enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
+	/* variables */
+	Boolean rxKey;
+
+	/* Controlled Directions state machine */
+	enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
+	/* variables */
+	ControlledDirection adminControlledDirections;
+	ControlledDirection operControlledDirections;
+	Boolean operEdge;
+
+	/* Authenticator Statistics Table */
+	Counter dot1xAuthEapolFramesRx;
+	Counter dot1xAuthEapolFramesTx;
+	Counter dot1xAuthEapolStartFramesRx;
+	Counter dot1xAuthEapolLogoffFramesRx;
+	Counter dot1xAuthEapolRespIdFramesRx;
+	Counter dot1xAuthEapolRespFramesRx;
+	Counter dot1xAuthEapolReqIdFramesTx;
+	Counter dot1xAuthEapolReqFramesTx;
+	Counter dot1xAuthInvalidEapolFramesRx;
+	Counter dot1xAuthEapLengthErrorFramesRx;
+	Counter dot1xAuthLastEapolFrameVersion;
+
+	/* Other variables - not defined in IEEE 802.1X */
+	u8 addr[ETH_ALEN]; /* Supplicant address */
+	int flags; /* EAPOL_SM_* */
+
+	/* EAPOL/AAA <-> EAP full authenticator interface */
+	struct eap_eapol_interface *eap_if;
+
+	int radius_identifier;
+	/* TODO: check when the last messages can be released */
+	struct radius_msg *last_recv_radius;
+	u8 last_eap_id; /* last used EAP Identifier */
+	u8 *identity;
+	size_t identity_len;
+	u8 eap_type_authsrv; /* EAP type of the last EAP packet from
+			      * Authentication server */
+	u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
+	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 */
+	Boolean changed;
+
+	struct eapol_authenticator *eapol;
+
+	void *sta; /* station context pointer to use in callbacks */
+};
+
+#endif /* EAPOL_AUTH_SM_I_H */

Deleted: vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c
===================================================================
--- vendor/wpa/dist/src/eapol_supp/eapol_supp_sm.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1898 +0,0 @@
-/*
- * EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "state_machine.h"
-#include "wpabuf.h"
-#include "eloop.h"
-#include "crypto/crypto.h"
-#include "crypto/md5.h"
-#include "common/eapol_common.h"
-#include "eap_peer/eap.h"
-#include "eapol_supp_sm.h"
-
-#define STATE_MACHINE_DATA struct eapol_sm
-#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
-
-
-/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
-
-/**
- * struct eapol_sm - Internal data for EAPOL state machines
- */
-struct eapol_sm {
-	/* Timers */
-	unsigned int authWhile;
-	unsigned int heldWhile;
-	unsigned int startWhen;
-	unsigned int idleWhile; /* for EAP state machine */
-	int timer_tick_enabled;
-
-	/* Global variables */
-	Boolean eapFail;
-	Boolean eapolEap;
-	Boolean eapSuccess;
-	Boolean initialize;
-	Boolean keyDone;
-	Boolean keyRun;
-	PortControl portControl;
-	Boolean portEnabled;
-	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
-	Boolean portValid;
-	Boolean suppAbort;
-	Boolean suppFail;
-	Boolean suppStart;
-	Boolean suppSuccess;
-	Boolean suppTimeout;
-
-	/* Supplicant PAE state machine */
-	enum {
-		SUPP_PAE_UNKNOWN = 0,
-		SUPP_PAE_DISCONNECTED = 1,
-		SUPP_PAE_LOGOFF = 2,
-		SUPP_PAE_CONNECTING = 3,
-		SUPP_PAE_AUTHENTICATING = 4,
-		SUPP_PAE_AUTHENTICATED = 5,
-		/* unused(6) */
-		SUPP_PAE_HELD = 7,
-		SUPP_PAE_RESTART = 8,
-		SUPP_PAE_S_FORCE_AUTH = 9,
-		SUPP_PAE_S_FORCE_UNAUTH = 10
-	} SUPP_PAE_state; /* dot1xSuppPaeState */
-	/* Variables */
-	Boolean userLogoff;
-	Boolean logoffSent;
-	unsigned int startCount;
-	Boolean eapRestart;
-	PortControl sPortMode;
-	/* Constants */
-	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
-	unsigned int startPeriod; /* dot1xSuppStartPeriod */
-	unsigned int maxStart; /* dot1xSuppMaxStart */
-
-	/* Key Receive state machine */
-	enum {
-		KEY_RX_UNKNOWN = 0,
-		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
-	} KEY_RX_state;
-	/* Variables */
-	Boolean rxKey;
-
-	/* Supplicant Backend state machine */
-	enum {
-		SUPP_BE_UNKNOWN = 0,
-		SUPP_BE_INITIALIZE = 1,
-		SUPP_BE_IDLE = 2,
-		SUPP_BE_REQUEST = 3,
-		SUPP_BE_RECEIVE = 4,
-		SUPP_BE_RESPONSE = 5,
-		SUPP_BE_FAIL = 6,
-		SUPP_BE_TIMEOUT = 7, 
-		SUPP_BE_SUCCESS = 8
-	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
-	/* Variables */
-	Boolean eapNoResp;
-	Boolean eapReq;
-	Boolean eapResp;
-	/* Constants */
-	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
-
-	/* Statistics */
-	unsigned int dot1xSuppEapolFramesRx;
-	unsigned int dot1xSuppEapolFramesTx;
-	unsigned int dot1xSuppEapolStartFramesTx;
-	unsigned int dot1xSuppEapolLogoffFramesTx;
-	unsigned int dot1xSuppEapolRespFramesTx;
-	unsigned int dot1xSuppEapolReqIdFramesRx;
-	unsigned int dot1xSuppEapolReqFramesRx;
-	unsigned int dot1xSuppInvalidEapolFramesRx;
-	unsigned int dot1xSuppEapLengthErrorFramesRx;
-	unsigned int dot1xSuppLastEapolFrameVersion;
-	unsigned char dot1xSuppLastEapolFrameSource[6];
-
-	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
-	Boolean changed;
-	struct eap_sm *eap;
-	struct eap_peer_config *config;
-	Boolean initial_req;
-	u8 *last_rx_key;
-	size_t last_rx_key_len;
-	struct wpabuf *eapReqData; /* for EAP */
-	Boolean altAccept; /* for EAP */
-	Boolean altReject; /* for EAP */
-	Boolean replay_counter_valid;
-	u8 last_replay_counter[16];
-	struct eapol_config conf;
-	struct eapol_ctx *ctx;
-	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
-		cb_status;
-	Boolean cached_pmk;
-
-	Boolean unicast_key_received, broadcast_key_received;
-};
-
-
-#define IEEE8021X_REPLAY_COUNTER_LEN 8
-#define IEEE8021X_KEY_SIGN_LEN 16
-#define IEEE8021X_KEY_IV_LEN 16
-
-#define IEEE8021X_KEY_INDEX_FLAG 0x80
-#define IEEE8021X_KEY_INDEX_MASK 0x03
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee802_1x_eapol_key {
-	u8 type;
-	/* Note: key_length is unaligned */
-	u8 key_length[2];
-	/* does not repeat within the life of the keying material used to
-	 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
-	u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
-	u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
-	u8 key_index; /* key flag in the most significant bit:
-		       * 0 = broadcast (default key),
-		       * 1 = unicast (key mapping key); key index is in the
-		       * 7 least significant bits */
-	/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
-	 * the key */
-	u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
-
-	/* followed by key: if packet body length = 44 + key length, then the
-	 * key field (of key_length bytes) contains the key in encrypted form;
-	 * if packet body length = 44, key field is absent and key_length
-	 * represents the number of least significant octets from
-	 * MS-MPPE-Send-Key attribute to be used as the keying material;
-	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-static void eapol_sm_txLogoff(struct eapol_sm *sm);
-static void eapol_sm_txStart(struct eapol_sm *sm);
-static void eapol_sm_processKey(struct eapol_sm *sm);
-static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
-static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
-static void eapol_sm_abortSupp(struct eapol_sm *sm);
-static void eapol_sm_abort_cached(struct eapol_sm *sm);
-static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
-static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
-static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
-
-
-/* Port Timers state machine - implemented as a function that will be called
- * once a second as a registered event loop timeout */
-static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eapol_sm *sm = timeout_ctx;
-
-	if (sm->authWhile > 0) {
-		sm->authWhile--;
-		if (sm->authWhile == 0)
-			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
-	}
-	if (sm->heldWhile > 0) {
-		sm->heldWhile--;
-		if (sm->heldWhile == 0)
-			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
-	}
-	if (sm->startWhen > 0) {
-		sm->startWhen--;
-		if (sm->startWhen == 0)
-			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
-	}
-	if (sm->idleWhile > 0) {
-		sm->idleWhile--;
-		if (sm->idleWhile == 0)
-			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
-	}
-
-	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
-		eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
-				       sm);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
-		sm->timer_tick_enabled = 0;
-	}
-	eapol_sm_step(sm);
-}
-
-
-static void eapol_enable_timer_tick(struct eapol_sm *sm)
-{
-	if (sm->timer_tick_enabled)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
-	sm->timer_tick_enabled = 1;
-	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
-	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
-}
-
-
-SM_STATE(SUPP_PAE, LOGOFF)
-{
-	SM_ENTRY(SUPP_PAE, LOGOFF);
-	eapol_sm_txLogoff(sm);
-	sm->logoffSent = TRUE;
-	sm->suppPortStatus = Unauthorized;
-	eapol_sm_set_port_unauthorized(sm);
-}
-
-
-SM_STATE(SUPP_PAE, DISCONNECTED)
-{
-	SM_ENTRY(SUPP_PAE, DISCONNECTED);
-	sm->sPortMode = Auto;
-	sm->startCount = 0;
-	sm->logoffSent = FALSE;
-	sm->suppPortStatus = Unauthorized;
-	eapol_sm_set_port_unauthorized(sm);
-	sm->suppAbort = TRUE;
-
-	sm->unicast_key_received = FALSE;
-	sm->broadcast_key_received = FALSE;
-}
-
-
-SM_STATE(SUPP_PAE, CONNECTING)
-{
-	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
-	SM_ENTRY(SUPP_PAE, CONNECTING);
-	if (send_start) {
-		sm->startWhen = sm->startPeriod;
-		sm->startCount++;
-	} else {
-		/*
-		 * Do not send EAPOL-Start immediately since in most cases,
-		 * Authenticator is going to start authentication immediately
-		 * after association and an extra EAPOL-Start is just going to
-		 * delay authentication. Use a short timeout to send the first
-		 * EAPOL-Start if Authenticator does not start authentication.
-		 */
-#ifdef CONFIG_WPS
-		/* Reduce latency on starting WPS negotiation. */
-		sm->startWhen = 1;
-#else /* CONFIG_WPS */
-		sm->startWhen = 3;
-#endif /* CONFIG_WPS */
-	}
-	eapol_enable_timer_tick(sm);
-	sm->eapolEap = FALSE;
-	if (send_start)
-		eapol_sm_txStart(sm);
-}
-
-
-SM_STATE(SUPP_PAE, AUTHENTICATING)
-{
-	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
-	sm->startCount = 0;
-	sm->suppSuccess = FALSE;
-	sm->suppFail = FALSE;
-	sm->suppTimeout = FALSE;
-	sm->keyRun = FALSE;
-	sm->keyDone = FALSE;
-	sm->suppStart = TRUE;
-}
-
-
-SM_STATE(SUPP_PAE, HELD)
-{
-	SM_ENTRY(SUPP_PAE, HELD);
-	sm->heldWhile = sm->heldPeriod;
-	eapol_enable_timer_tick(sm);
-	sm->suppPortStatus = Unauthorized;
-	eapol_sm_set_port_unauthorized(sm);
-	sm->cb_status = EAPOL_CB_FAILURE;
-}
-
-
-SM_STATE(SUPP_PAE, AUTHENTICATED)
-{
-	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
-	sm->suppPortStatus = Authorized;
-	eapol_sm_set_port_authorized(sm);
-	sm->cb_status = EAPOL_CB_SUCCESS;
-}
-
-
-SM_STATE(SUPP_PAE, RESTART)
-{
-	SM_ENTRY(SUPP_PAE, RESTART);
-	sm->eapRestart = TRUE;
-}
-
-
-SM_STATE(SUPP_PAE, S_FORCE_AUTH)
-{
-	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
-	sm->suppPortStatus = Authorized;
-	eapol_sm_set_port_authorized(sm);
-	sm->sPortMode = ForceAuthorized;
-}
-
-
-SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
-{
-	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
-	sm->suppPortStatus = Unauthorized;
-	eapol_sm_set_port_unauthorized(sm);
-	sm->sPortMode = ForceUnauthorized;
-	eapol_sm_txLogoff(sm);
-}
-
-
-SM_STEP(SUPP_PAE)
-{
-	if ((sm->userLogoff && !sm->logoffSent) &&
-	    !(sm->initialize || !sm->portEnabled))
-		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
-	else if (((sm->portControl == Auto) &&
-		  (sm->sPortMode != sm->portControl)) ||
-		 sm->initialize || !sm->portEnabled)
-		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
-	else if ((sm->portControl == ForceAuthorized) &&
-		 (sm->sPortMode != sm->portControl) &&
-		 !(sm->initialize || !sm->portEnabled))
-		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
-	else if ((sm->portControl == ForceUnauthorized) &&
-		 (sm->sPortMode != sm->portControl) &&
-		 !(sm->initialize || !sm->portEnabled))
-		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
-	else switch (sm->SUPP_PAE_state) {
-	case SUPP_PAE_UNKNOWN:
-		break;
-	case SUPP_PAE_LOGOFF:
-		if (!sm->userLogoff)
-			SM_ENTER(SUPP_PAE, DISCONNECTED);
-		break;
-	case SUPP_PAE_DISCONNECTED:
-		SM_ENTER(SUPP_PAE, CONNECTING);
-		break;
-	case SUPP_PAE_CONNECTING:
-		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
-			SM_ENTER(SUPP_PAE, CONNECTING);
-		else if (sm->startWhen == 0 &&
-			 sm->startCount >= sm->maxStart &&
-			 sm->portValid)
-			SM_ENTER(SUPP_PAE, AUTHENTICATED);
-		else if (sm->eapSuccess || sm->eapFail)
-			SM_ENTER(SUPP_PAE, AUTHENTICATING);
-		else if (sm->eapolEap)
-			SM_ENTER(SUPP_PAE, RESTART);
-		else if (sm->startWhen == 0 &&
-			 sm->startCount >= sm->maxStart &&
-			 !sm->portValid)
-			SM_ENTER(SUPP_PAE, HELD);
-		break;
-	case SUPP_PAE_AUTHENTICATING:
-		if (sm->eapSuccess && !sm->portValid &&
-		    sm->conf.accept_802_1x_keys &&
-		    sm->conf.required_keys == 0) {
-			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
-				   "plaintext connection; no EAPOL-Key frames "
-				   "required");
-			sm->portValid = TRUE;
-			if (sm->ctx->eapol_done_cb)
-				sm->ctx->eapol_done_cb(sm->ctx->ctx);
-		}
-		if (sm->eapSuccess && sm->portValid)
-			SM_ENTER(SUPP_PAE, AUTHENTICATED);
-		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
-			SM_ENTER(SUPP_PAE, HELD);
-		else if (sm->suppTimeout)
-			SM_ENTER(SUPP_PAE, CONNECTING);
-		break;
-	case SUPP_PAE_HELD:
-		if (sm->heldWhile == 0)
-			SM_ENTER(SUPP_PAE, CONNECTING);
-		else if (sm->eapolEap)
-			SM_ENTER(SUPP_PAE, RESTART);
-		break;
-	case SUPP_PAE_AUTHENTICATED:
-		if (sm->eapolEap && sm->portValid)
-			SM_ENTER(SUPP_PAE, RESTART);
-		else if (!sm->portValid)
-			SM_ENTER(SUPP_PAE, DISCONNECTED);
-		break;
-	case SUPP_PAE_RESTART:
-		if (!sm->eapRestart)
-			SM_ENTER(SUPP_PAE, AUTHENTICATING);
-		break;
-	case SUPP_PAE_S_FORCE_AUTH:
-		break;
-	case SUPP_PAE_S_FORCE_UNAUTH:
-		break;
-	}
-}
-
-
-SM_STATE(KEY_RX, NO_KEY_RECEIVE)
-{
-	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
-}
-
-
-SM_STATE(KEY_RX, KEY_RECEIVE)
-{
-	SM_ENTRY(KEY_RX, KEY_RECEIVE);
-	eapol_sm_processKey(sm);
-	sm->rxKey = FALSE;
-}
-
-
-SM_STEP(KEY_RX)
-{
-	if (sm->initialize || !sm->portEnabled)
-		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
-	switch (sm->KEY_RX_state) {
-	case KEY_RX_UNKNOWN:
-		break;
-	case KEY_RX_NO_KEY_RECEIVE:
-		if (sm->rxKey)
-			SM_ENTER(KEY_RX, KEY_RECEIVE);
-		break;
-	case KEY_RX_KEY_RECEIVE:
-		if (sm->rxKey)
-			SM_ENTER(KEY_RX, KEY_RECEIVE);
-		break;
-	}
-}
-
-
-SM_STATE(SUPP_BE, REQUEST)
-{
-	SM_ENTRY(SUPP_BE, REQUEST);
-	sm->authWhile = 0;
-	sm->eapReq = TRUE;
-	eapol_sm_getSuppRsp(sm);
-}
-
-
-SM_STATE(SUPP_BE, RESPONSE)
-{
-	SM_ENTRY(SUPP_BE, RESPONSE);
-	eapol_sm_txSuppRsp(sm);
-	sm->eapResp = FALSE;
-}
-
-
-SM_STATE(SUPP_BE, SUCCESS)
-{
-	SM_ENTRY(SUPP_BE, SUCCESS);
-	sm->keyRun = TRUE;
-	sm->suppSuccess = TRUE;
-
-	if (eap_key_available(sm->eap)) {
-		/* New key received - clear IEEE 802.1X EAPOL-Key replay
-		 * counter */
-		sm->replay_counter_valid = FALSE;
-	}
-}
-
-
-SM_STATE(SUPP_BE, FAIL)
-{
-	SM_ENTRY(SUPP_BE, FAIL);
-	sm->suppFail = TRUE;
-}
-
-
-SM_STATE(SUPP_BE, TIMEOUT)
-{
-	SM_ENTRY(SUPP_BE, TIMEOUT);
-	sm->suppTimeout = TRUE;
-}
-
-
-SM_STATE(SUPP_BE, IDLE)
-{
-	SM_ENTRY(SUPP_BE, IDLE);
-	sm->suppStart = FALSE;
-	sm->initial_req = TRUE;
-}
-
-
-SM_STATE(SUPP_BE, INITIALIZE)
-{
-	SM_ENTRY(SUPP_BE, INITIALIZE);
-	eapol_sm_abortSupp(sm);
-	sm->suppAbort = FALSE;
-}
-
-
-SM_STATE(SUPP_BE, RECEIVE)
-{
-	SM_ENTRY(SUPP_BE, RECEIVE);
-	sm->authWhile = sm->authPeriod;
-	eapol_enable_timer_tick(sm);
-	sm->eapolEap = FALSE;
-	sm->eapNoResp = FALSE;
-	sm->initial_req = FALSE;
-}
-
-
-SM_STEP(SUPP_BE)
-{
-	if (sm->initialize || sm->suppAbort)
-		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
-	else switch (sm->SUPP_BE_state) {
-	case SUPP_BE_UNKNOWN:
-		break;
-	case SUPP_BE_REQUEST:
-		/*
-		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
-		 * and SUCCESS based on eapFail and eapSuccess, respectively.
-		 * However, IEEE Std 802.1X-2004 is also specifying that
-		 * eapNoResp should be set in conjuction with eapSuccess and
-		 * eapFail which would mean that more than one of the
-		 * transitions here would be activated at the same time.
-		 * Skipping RESPONSE and/or RECEIVE states in these cases can
-		 * cause problems and the direct transitions to do not seem
-		 * correct. Because of this, the conditions for these
-		 * transitions are verified only after eapNoResp. They are
-		 * unlikely to be used since eapNoResp should always be set if
-		 * either of eapSuccess or eapFail is set.
-		 */
-		if (sm->eapResp && sm->eapNoResp) {
-			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
-				   "eapResp and eapNoResp set?!");
-		}
-		if (sm->eapResp)
-			SM_ENTER(SUPP_BE, RESPONSE);
-		else if (sm->eapNoResp)
-			SM_ENTER(SUPP_BE, RECEIVE);
-		else if (sm->eapFail)
-			SM_ENTER(SUPP_BE, FAIL);
-		else if (sm->eapSuccess)
-			SM_ENTER(SUPP_BE, SUCCESS);
-		break;
-	case SUPP_BE_RESPONSE:
-		SM_ENTER(SUPP_BE, RECEIVE);
-		break;
-	case SUPP_BE_SUCCESS:
-		SM_ENTER(SUPP_BE, IDLE);
-		break;
-	case SUPP_BE_FAIL:
-		SM_ENTER(SUPP_BE, IDLE);
-		break;
-	case SUPP_BE_TIMEOUT:
-		SM_ENTER(SUPP_BE, IDLE);
-		break;
-	case SUPP_BE_IDLE:
-		if (sm->eapFail && sm->suppStart)
-			SM_ENTER(SUPP_BE, FAIL);
-		else if (sm->eapolEap && sm->suppStart)
-			SM_ENTER(SUPP_BE, REQUEST);
-		else if (sm->eapSuccess && sm->suppStart)
-			SM_ENTER(SUPP_BE, SUCCESS);
-		break;
-	case SUPP_BE_INITIALIZE:
-		SM_ENTER(SUPP_BE, IDLE);
-		break;
-	case SUPP_BE_RECEIVE:
-		if (sm->eapolEap)
-			SM_ENTER(SUPP_BE, REQUEST);
-		else if (sm->eapFail)
-			SM_ENTER(SUPP_BE, FAIL);
-		else if (sm->authWhile == 0)
-			SM_ENTER(SUPP_BE, TIMEOUT);
-		else if (sm->eapSuccess)
-			SM_ENTER(SUPP_BE, SUCCESS);
-		break;
-	}
-}
-
-
-static void eapol_sm_txLogoff(struct eapol_sm *sm)
-{
-	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
-	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
-			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
-	sm->dot1xSuppEapolLogoffFramesTx++;
-	sm->dot1xSuppEapolFramesTx++;
-}
-
-
-static void eapol_sm_txStart(struct eapol_sm *sm)
-{
-	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
-	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
-			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
-	sm->dot1xSuppEapolStartFramesTx++;
-	sm->dot1xSuppEapolFramesTx++;
-}
-
-
-#define IEEE8021X_ENCR_KEY_LEN 32
-#define IEEE8021X_SIGN_KEY_LEN 32
-
-struct eap_key_data {
-	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
-	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
-};
-
-
-static void eapol_sm_processKey(struct eapol_sm *sm)
-{
-	struct ieee802_1x_hdr *hdr;
-	struct ieee802_1x_eapol_key *key;
-	struct eap_key_data keydata;
-	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
-	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
-	int key_len, res, sign_key_len, encr_key_len;
-	u16 rx_key_length;
-
-	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
-	if (sm->last_rx_key == NULL)
-		return;
-
-	if (!sm->conf.accept_802_1x_keys) {
-		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
-			   " even though this was not accepted - "
-			   "ignoring this packet");
-		return;
-	}
-
-	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
-	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
-	if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
-		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
-		return;
-	}
-	rx_key_length = WPA_GET_BE16(key->key_length);
-	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
-		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
-		   hdr->version, hdr->type, be_to_host16(hdr->length),
-		   key->type, rx_key_length, key->key_index);
-
-	eapol_sm_notify_lower_layer_success(sm, 1);
-	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
-	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
-	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
-			   "decrypting EAPOL-Key keys");
-		return;
-	}
-	if (res == 16) {
-		/* LEAP derives only 16 bytes of keying material. */
-		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
-		if (res) {
-			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
-				   "master key for decrypting EAPOL-Key keys");
-			return;
-		}
-		sign_key_len = 16;
-		encr_key_len = 16;
-		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
-	} else if (res) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
-			   "data for decrypting EAPOL-Key keys (res=%d)", res);
-		return;
-	}
-
-	/* The key replay_counter must increase when same master key */
-	if (sm->replay_counter_valid &&
-	    os_memcmp(sm->last_replay_counter, key->replay_counter,
-		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
-		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
-			   "not increase - ignoring key");
-		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
-			    sm->last_replay_counter,
-			    IEEE8021X_REPLAY_COUNTER_LEN);
-		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
-			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
-		return;
-	}
-
-	/* Verify key signature (HMAC-MD5) */
-	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
-	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
-	hmac_md5(keydata.sign_key, sign_key_len,
-		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
-		 key->key_signature);
-	if (os_memcmp(orig_key_sign, key->key_signature,
-		      IEEE8021X_KEY_SIGN_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
-			   "EAPOL-Key packet");
-		os_memcpy(key->key_signature, orig_key_sign,
-			  IEEE8021X_KEY_SIGN_LEN);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
-
-	key_len = be_to_host16(hdr->length) - sizeof(*key);
-	if (key_len > 32 || rx_key_length > 32) {
-		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
-			   key_len ? key_len : rx_key_length);
-		return;
-	}
-	if (key_len == rx_key_length) {
-		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
-		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
-			  encr_key_len);
-		os_memcpy(datakey, key + 1, key_len);
-		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
-			 datakey, key_len);
-		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
-				datakey, key_len);
-	} else if (key_len == 0) {
-		/*
-		 * IEEE 802.1X-2004 specifies that least significant Key Length
-		 * octets from MS-MPPE-Send-Key are used as the key if the key
-		 * data is not present. This seems to be meaning the beginning
-		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
-		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
-		 * Anyway, taking the beginning of the keying material from EAP
-		 * seems to interoperate with Authenticators.
-		 */
-		key_len = rx_key_length;
-		os_memcpy(datakey, keydata.encr_key, key_len);
-		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
-				"material data encryption key",
-				datakey, key_len);
-	} else {
-		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
-			   "(key_length=%d)", key_len, rx_key_length);
-		return;
-	}
-
-	sm->replay_counter_valid = TRUE;
-	os_memcpy(sm->last_replay_counter, key->replay_counter,
-		  IEEE8021X_REPLAY_COUNTER_LEN);
-
-	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
-		   "len %d",
-		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
-		   "unicast" : "broadcast",
-		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
-
-	if (sm->ctx->set_wep_key &&
-	    sm->ctx->set_wep_key(sm->ctx->ctx,
-				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
-				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
-				 datakey, key_len) < 0) {
-		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
-			   " driver.");
-	} else {
-		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
-			sm->unicast_key_received = TRUE;
-		else
-			sm->broadcast_key_received = TRUE;
-
-		if ((sm->unicast_key_received ||
-		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
-		    (sm->broadcast_key_received ||
-		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
-		{
-			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
-				   "frames received");
-			sm->portValid = TRUE;
-			if (sm->ctx->eapol_done_cb)
-				sm->ctx->eapol_done_cb(sm->ctx->ctx);
-		}
-	}
-}
-
-
-static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
-{
-	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
-	/* EAP layer processing; no special code is needed, since Supplicant
-	 * Backend state machine is waiting for eapNoResp or eapResp to be set
-	 * and these are only set in the EAP state machine when the processing
-	 * has finished. */
-}
-
-
-static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
-{
-	struct wpabuf *resp;
-
-	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
-	resp = eap_get_eapRespData(sm->eap);
-	if (resp == NULL) {
-		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
-			   "not available");
-		return;
-	}
-
-	/* Send EAP-Packet from the EAP layer to the Authenticator */
-	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
-			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
-			    wpabuf_len(resp));
-
-	/* eapRespData is not used anymore, so free it here */
-	wpabuf_free(resp);
-
-	if (sm->initial_req)
-		sm->dot1xSuppEapolReqIdFramesRx++;
-	else
-		sm->dot1xSuppEapolReqFramesRx++;
-	sm->dot1xSuppEapolRespFramesTx++;
-	sm->dot1xSuppEapolFramesTx++;
-}
-
-
-static void eapol_sm_abortSupp(struct eapol_sm *sm)
-{
-	/* release system resources that may have been allocated for the
-	 * authentication session */
-	os_free(sm->last_rx_key);
-	sm->last_rx_key = NULL;
-	wpabuf_free(sm->eapReqData);
-	sm->eapReqData = NULL;
-	eap_sm_abort(sm->eap);
-}
-
-
-static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	eapol_sm_step(timeout_ctx);
-}
-
-
-static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
-{
-	if (sm->ctx->port_cb)
-		sm->ctx->port_cb(sm->ctx->ctx, 1);
-}
-
-
-static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
-{
-	if (sm->ctx->port_cb)
-		sm->ctx->port_cb(sm->ctx->ctx, 0);
-}
-
-
-/**
- * eapol_sm_step - EAPOL state machine step function
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * This function is called to notify the state machine about changed external
- * variables. It will step through the EAPOL state machines in loop to process
- * all triggered state changes.
- */
-void eapol_sm_step(struct eapol_sm *sm)
-{
-	int i;
-
-	/* In theory, it should be ok to run this in loop until !changed.
-	 * However, it is better to use a limit on number of iterations to
-	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
-	 * state machine were to generate a busy loop. */
-	for (i = 0; i < 100; i++) {
-		sm->changed = FALSE;
-		SM_STEP_RUN(SUPP_PAE);
-		SM_STEP_RUN(KEY_RX);
-		SM_STEP_RUN(SUPP_BE);
-		if (eap_peer_sm_step(sm->eap))
-			sm->changed = TRUE;
-		if (!sm->changed)
-			break;
-	}
-
-	if (sm->changed) {
-		/* restart EAPOL state machine step from timeout call in order
-		 * to allow other events to be processed. */
-		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
-		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
-	}
-
-	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
-		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
-		sm->cb_status = EAPOL_CB_IN_PROGRESS;
-		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
-	}
-}
-
-
-#ifdef CONFIG_CTRL_IFACE
-static const char *eapol_supp_pae_state(int state)
-{
-	switch (state) {
-	case SUPP_PAE_LOGOFF:
-		return "LOGOFF";
-	case SUPP_PAE_DISCONNECTED:
-		return "DISCONNECTED";
-	case SUPP_PAE_CONNECTING:
-		return "CONNECTING";
-	case SUPP_PAE_AUTHENTICATING:
-		return "AUTHENTICATING";
-	case SUPP_PAE_HELD:
-		return "HELD";
-	case SUPP_PAE_AUTHENTICATED:
-		return "AUTHENTICATED";
-	case SUPP_PAE_RESTART:
-		return "RESTART";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-static const char *eapol_supp_be_state(int state)
-{
-	switch (state) {
-	case SUPP_BE_REQUEST:
-		return "REQUEST";
-	case SUPP_BE_RESPONSE:
-		return "RESPONSE";
-	case SUPP_BE_SUCCESS:
-		return "SUCCESS";
-	case SUPP_BE_FAIL:
-		return "FAIL";
-	case SUPP_BE_TIMEOUT:
-		return "TIMEOUT";
-	case SUPP_BE_IDLE:
-		return "IDLE";
-	case SUPP_BE_INITIALIZE:
-		return "INITIALIZE";
-	case SUPP_BE_RECEIVE:
-		return "RECEIVE";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-static const char * eapol_port_status(PortStatus status)
-{
-	if (status == Authorized)
-		return "Authorized";
-	else
-		return "Unauthorized";
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static const char * eapol_port_control(PortControl ctrl)
-{
-	switch (ctrl) {
-	case Auto:
-		return "Auto";
-	case ForceUnauthorized:
-		return "ForceUnauthorized";
-	case ForceAuthorized:
-		return "ForceAuthorized";
-	default:
-		return "Unknown";
-	}
-}
-#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-
-
-/**
- * eapol_sm_configure - Set EAPOL variables
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @heldPeriod: dot1xSuppHeldPeriod
- * @authPeriod: dot1xSuppAuthPeriod
- * @startPeriod: dot1xSuppStartPeriod
- * @maxStart: dot1xSuppMaxStart
- *
- * Set configurable EAPOL state machine variables. Each variable can be set to
- * the given value or ignored if set to -1 (to set only some of the variables).
- */
-void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
-			int startPeriod, int maxStart)
-{
-	if (sm == NULL)
-		return;
-	if (heldPeriod >= 0)
-		sm->heldPeriod = heldPeriod;
-	if (authPeriod >= 0)
-		sm->authPeriod = authPeriod;
-	if (startPeriod >= 0)
-		sm->startPeriod = startPeriod;
-	if (maxStart >= 0)
-		sm->maxStart = maxStart;
-}
-
-
-#ifdef CONFIG_CTRL_IFACE
-/**
- * eapol_sm_get_status - Get EAPOL state machine status
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_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 EAPOL state machine for status information. This function fills in a
- * text area with current status information from the EAPOL state machine. If
- * the buffer (buf) is not large enough, status information will be truncated
- * to fit the buffer.
- */
-int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
-			int verbose)
-{
-	int len, ret;
-	if (sm == NULL)
-		return 0;
-
-	len = os_snprintf(buf, buflen,
-			  "Supplicant PAE state=%s\n"
-			  "suppPortStatus=%s\n",
-			  eapol_supp_pae_state(sm->SUPP_PAE_state),
-			  eapol_port_status(sm->suppPortStatus));
-	if (len < 0 || (size_t) len >= buflen)
-		return 0;
-
-	if (verbose) {
-		ret = os_snprintf(buf + len, buflen - len,
-				  "heldPeriod=%u\n"
-				  "authPeriod=%u\n"
-				  "startPeriod=%u\n"
-				  "maxStart=%u\n"
-				  "portControl=%s\n"
-				  "Supplicant Backend state=%s\n",
-				  sm->heldPeriod,
-				  sm->authPeriod,
-				  sm->startPeriod,
-				  sm->maxStart,
-				  eapol_port_control(sm->portControl),
-				  eapol_supp_be_state(sm->SUPP_BE_state));
-		if (ret < 0 || (size_t) ret >= buflen - len)
-			return len;
-		len += ret;
-	}
-
-	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
-
-	return len;
-}
-
-
-/**
- * eapol_sm_get_mib - Get EAPOL state machine MIBs
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @buf: Buffer for MIB information
- * @buflen: Maximum buffer length
- * Returns: Number of bytes written to buf.
- *
- * Query EAPOL state machine for MIB information. This function fills in a
- * text area with current MIB information from the EAPOL state machine. If
- * the buffer (buf) is not large enough, MIB information will be truncated to
- * fit the buffer.
- */
-int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
-{
-	size_t len;
-	int ret;
-
-	if (sm == NULL)
-		return 0;
-	ret = os_snprintf(buf, buflen,
-			  "dot1xSuppPaeState=%d\n"
-			  "dot1xSuppHeldPeriod=%u\n"
-			  "dot1xSuppAuthPeriod=%u\n"
-			  "dot1xSuppStartPeriod=%u\n"
-			  "dot1xSuppMaxStart=%u\n"
-			  "dot1xSuppSuppControlledPortStatus=%s\n"
-			  "dot1xSuppBackendPaeState=%d\n",
-			  sm->SUPP_PAE_state,
-			  sm->heldPeriod,
-			  sm->authPeriod,
-			  sm->startPeriod,
-			  sm->maxStart,
-			  sm->suppPortStatus == Authorized ?
-			  "Authorized" : "Unauthorized",
-			  sm->SUPP_BE_state);
-
-	if (ret < 0 || (size_t) ret >= buflen)
-		return 0;
-	len = ret;
-
-	ret = os_snprintf(buf + len, buflen - len,
-			  "dot1xSuppEapolFramesRx=%u\n"
-			  "dot1xSuppEapolFramesTx=%u\n"
-			  "dot1xSuppEapolStartFramesTx=%u\n"
-			  "dot1xSuppEapolLogoffFramesTx=%u\n"
-			  "dot1xSuppEapolRespFramesTx=%u\n"
-			  "dot1xSuppEapolReqIdFramesRx=%u\n"
-			  "dot1xSuppEapolReqFramesRx=%u\n"
-			  "dot1xSuppInvalidEapolFramesRx=%u\n"
-			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
-			  "dot1xSuppLastEapolFrameVersion=%u\n"
-			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
-			  sm->dot1xSuppEapolFramesRx,
-			  sm->dot1xSuppEapolFramesTx,
-			  sm->dot1xSuppEapolStartFramesTx,
-			  sm->dot1xSuppEapolLogoffFramesTx,
-			  sm->dot1xSuppEapolRespFramesTx,
-			  sm->dot1xSuppEapolReqIdFramesRx,
-			  sm->dot1xSuppEapolReqFramesRx,
-			  sm->dot1xSuppInvalidEapolFramesRx,
-			  sm->dot1xSuppEapLengthErrorFramesRx,
-			  sm->dot1xSuppLastEapolFrameVersion,
-			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
-
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	return len;
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-/**
- * eapol_sm_rx_eapol - Process received EAPOL frames
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @src: Source MAC address of the EAPOL packet
- * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
- * @len: Length of the EAPOL frame
- * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
- * -1 failure
- */
-int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
-		      size_t len)
-{
-	const struct ieee802_1x_hdr *hdr;
-	const struct ieee802_1x_eapol_key *key;
-	int data_len;
-	int res = 1;
-	size_t plen;
-
-	if (sm == NULL)
-		return 0;
-	sm->dot1xSuppEapolFramesRx++;
-	if (len < sizeof(*hdr)) {
-		sm->dot1xSuppInvalidEapolFramesRx++;
-		return 0;
-	}
-	hdr = (const struct ieee802_1x_hdr *) buf;
-	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
-	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
-	if (hdr->version < EAPOL_VERSION) {
-		/* TODO: backwards compatibility */
-	}
-	plen = be_to_host16(hdr->length);
-	if (plen > len - sizeof(*hdr)) {
-		sm->dot1xSuppEapLengthErrorFramesRx++;
-		return 0;
-	}
-#ifdef CONFIG_WPS
-	if (sm->conf.workaround &&
-	    plen < len - sizeof(*hdr) &&
-	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
-	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
-		const struct eap_hdr *ehdr =
-			(const struct eap_hdr *) (hdr + 1);
-		u16 elen;
-
-		elen = be_to_host16(ehdr->length);
-		if (elen > plen && elen <= len - sizeof(*hdr)) {
-			/*
-			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
-			 * packets with too short EAPOL header length field
-			 * (14 octets). This is fixed in firmware Ver.1.49.
-			 * As a workaround, fix the EAPOL header based on the
-			 * correct length in the EAP packet.
-			 */
-			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
-				   "payload length based on EAP header: "
-				   "%d -> %d", (int) plen, elen);
-			plen = elen;
-		}
-	}
-#endif /* CONFIG_WPS */
-	data_len = plen + sizeof(*hdr);
-
-	switch (hdr->type) {
-	case IEEE802_1X_TYPE_EAP_PACKET:
-		if (sm->cached_pmk) {
-			/* Trying to use PMKSA caching, but Authenticator did
-			 * not seem to have a matching entry. Need to restart
-			 * EAPOL state machines.
-			 */
-			eapol_sm_abort_cached(sm);
-		}
-		wpabuf_free(sm->eapReqData);
-		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
-		if (sm->eapReqData) {
-			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
-				   "frame");
-			sm->eapolEap = TRUE;
-			eapol_sm_step(sm);
-		}
-		break;
-	case IEEE802_1X_TYPE_EAPOL_KEY:
-		if (plen < sizeof(*key)) {
-			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
-				   "frame received");
-			break;
-		}
-		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
-		if (key->type == EAPOL_KEY_TYPE_WPA ||
-		    key->type == EAPOL_KEY_TYPE_RSN) {
-			/* WPA Supplicant takes care of this frame. */
-			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
-				   "frame in EAPOL state machines");
-			res = 0;
-			break;
-		}
-		if (key->type != EAPOL_KEY_TYPE_RC4) {
-			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
-				   "EAPOL-Key type %d", key->type);
-			break;
-		}
-		os_free(sm->last_rx_key);
-		sm->last_rx_key = os_malloc(data_len);
-		if (sm->last_rx_key) {
-			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
-				   "frame");
-			os_memcpy(sm->last_rx_key, buf, data_len);
-			sm->last_rx_key_len = data_len;
-			sm->rxKey = TRUE;
-			eapol_sm_step(sm);
-		}
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
-			   hdr->type);
-		sm->dot1xSuppInvalidEapolFramesRx++;
-		break;
-	}
-
-	return res;
-}
-
-
-/**
- * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machine about transmitted EAPOL packet from an external
- * component, e.g., WPA. This will update the statistics.
- */
-void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
-{
-	if (sm)
-		sm->dot1xSuppEapolFramesTx++;
-}
-
-
-/**
- * eapol_sm_notify_portEnabled - Notification about portEnabled change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @enabled: New portEnabled value
- *
- * Notify EAPOL state machine about new portEnabled value.
- */
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
-		   "portEnabled=%d", enabled);
-	sm->portEnabled = enabled;
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_portValid - Notification about portValid change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @valid: New portValid value
- *
- * Notify EAPOL state machine about new portValid value.
- */
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
-		   "portValid=%d", valid);
-	sm->portValid = valid;
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_eap_success - Notification of external EAP success trigger
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @success: %TRUE = set success, %FALSE = clear success
- *
- * Notify the EAPOL state machine that external event has forced EAP state to
- * success (success = %TRUE). This can be cleared by setting success = %FALSE.
- *
- * This function is called to update EAP state when WPA-PSK key handshake has
- * been completed successfully since WPA-PSK does not use EAP state machine.
- */
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
-		   "EAP success=%d", success);
-	sm->eapSuccess = success;
-	sm->altAccept = success;
-	if (success)
-		eap_notify_success(sm->eap);
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @fail: %TRUE = set failure, %FALSE = clear failure
- *
- * Notify EAPOL state machine that external event has forced EAP state to
- * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
- */
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
-		   "EAP fail=%d", fail);
-	sm->eapFail = fail;
-	sm->altReject = fail;
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_config - Notification of EAPOL configuration change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @config: Pointer to current network EAP configuration
- * @conf: Pointer to EAPOL configuration data
- *
- * Notify EAPOL state machine that configuration has changed. config will be
- * stored as a backpointer to network configuration. This can be %NULL to clear
- * the stored pointed. conf will be copied to local EAPOL/EAP configuration
- * data. If conf is %NULL, this part of the configuration change will be
- * skipped.
- */
-void eapol_sm_notify_config(struct eapol_sm *sm,
-			    struct eap_peer_config *config,
-			    const struct eapol_config *conf)
-{
-	if (sm == NULL)
-		return;
-
-	sm->config = config;
-
-	if (conf == NULL)
-		return;
-
-	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
-	sm->conf.required_keys = conf->required_keys;
-	sm->conf.fast_reauth = conf->fast_reauth;
-	sm->conf.workaround = conf->workaround;
-	if (sm->eap) {
-		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
-		eap_set_workaround(sm->eap, conf->workaround);
-		eap_set_force_disabled(sm->eap, conf->eap_disabled);
-	}
-}
-
-
-/**
- * eapol_sm_get_key - Get master session key (MSK) from EAP
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @key: Pointer for key buffer
- * @len: Number of bytes to copy to key
- * Returns: 0 on success (len of key available), maximum available key len
- * (>0) if key is available but it is shorter than len, or -1 on failure.
- *
- * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
- * is available only after a successful authentication.
- */
-int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
-{
-	const u8 *eap_key;
-	size_t eap_len;
-
-	if (sm == NULL || !eap_key_available(sm->eap)) {
-		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
-		return -1;
-	}
-	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
-	if (eap_key == NULL) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
-		return -1;
-	}
-	if (len > eap_len) {
-		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
-			   "available (len=%lu)",
-			   (unsigned long) len, (unsigned long) eap_len);
-		return eap_len;
-	}
-	os_memcpy(key, eap_key, len);
-	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
-		   (unsigned long) len);
-	return 0;
-}
-
-
-/**
- * eapol_sm_notify_logoff - Notification of logon/logoff commands
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @logoff: Whether command was logoff
- *
- * Notify EAPOL state machines that user requested logon/logoff.
- */
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
-{
-	if (sm) {
-		sm->userLogoff = logoff;
-		eapol_sm_step(sm);
-	}
-}
-
-
-/**
- * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that PMKSA caching was successful. This is used
- * to move EAPOL and EAP state machines into authenticated/successful state.
- */
-void eapol_sm_notify_cached(struct eapol_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
-	sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
-	sm->suppPortStatus = Authorized;
-	eapol_sm_set_port_authorized(sm);
-	sm->portValid = TRUE;
-	eap_notify_success(sm->eap);
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @attempt: Whether PMKSA caching is tried
- *
- * Notify EAPOL state machines whether PMKSA caching is used.
- */
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
-{
-	if (sm == NULL)
-		return;
-	if (attempt) {
-		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
-		sm->cached_pmk = TRUE;
-	} else {
-		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
-		sm->cached_pmk = FALSE;
-	}
-}
-
-
-static void eapol_sm_abort_cached(struct eapol_sm *sm)
-{
-	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
-		   "doing full EAP authentication");
-	if (sm == NULL)
-		return;
-	sm->cached_pmk = FALSE;
-	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
-	sm->suppPortStatus = Unauthorized;
-	eapol_sm_set_port_unauthorized(sm);
-
-	/* Make sure we do not start sending EAPOL-Start frames first, but
-	 * instead move to RESTART state to start EAPOL authentication. */
-	sm->startWhen = 3;
-	eapol_enable_timer_tick(sm);
-
-	if (sm->ctx->aborted_cached)
-		sm->ctx->aborted_cached(sm->ctx->ctx);
-}
-
-
-/**
- * eapol_sm_register_scard_ctx - Notification of smart card context
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @ctx: Context data for smart card operations
- *
- * Notify EAPOL state machines of context data for smart card operations. This
- * context data will be used as a parameter for scard_*() functions.
- */
-void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
-{
-	if (sm) {
-		sm->ctx->scard_ctx = ctx;
-		eap_register_scard_ctx(sm->eap, ctx);
-	}
-}
-
-
-/**
- * eapol_sm_notify_portControl - Notification of portControl changes
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @portControl: New value for portControl variable
- *
- * Notify EAPOL state machines that portControl variable has changed.
- */
-void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
-{
-	if (sm == NULL)
-		return;
-	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
-		   "portControl=%s", eapol_port_control(portControl));
-	sm->portControl = portControl;
-	eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_notify_ctrl_attached - Notification of attached monitor
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that a monitor was attached to the control
- * interface to trigger re-sending of pending requests for user input.
- */
-void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	eap_sm_notify_ctrl_attached(sm->eap);
-}
-
-
-/**
- * eapol_sm_notify_ctrl_response - Notification of received user input
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that a control response, i.e., user
- * input, was received in order to trigger retrying of a pending EAP request.
- */
-void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	if (sm->eapReqData && !sm->eapReq) {
-		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
-			   "input) notification - retrying pending EAP "
-			   "Request");
-		sm->eapolEap = TRUE;
-		sm->eapReq = TRUE;
-		eapol_sm_step(sm);
-	}
-}
-
-
-/**
- * eapol_sm_request_reauth - Request reauthentication
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * This function can be used to request EAPOL reauthentication, e.g., when the
- * current PMKSA entry is nearing expiration.
- */
-void eapol_sm_request_reauth(struct eapol_sm *sm)
-{
-	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
-		return;
-	eapol_sm_txStart(sm);
-}
-
-
-/**
- * eapol_sm_notify_lower_layer_success - Notification of lower layer success
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @in_eapol_sm: Whether the caller is already running inside EAPOL state
- * machine loop (eapol_sm_step())
- *
- * Notify EAPOL (and EAP) state machines that a lower layer has detected a
- * successful authentication. This is used to recover from dropped EAP-Success
- * messages.
- */
-void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
-{
-	if (sm == NULL)
-		return;
-	eap_notify_lower_layer_success(sm->eap);
-	if (!in_eapol_sm)
-		eapol_sm_step(sm);
-}
-
-
-/**
- * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- */
-void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
-{
-	if (sm)
-		eap_invalidate_cached_session(sm->eap);
-}
-
-
-static struct eap_peer_config * eapol_sm_get_config(void *ctx)
-{
-	struct eapol_sm *sm = ctx;
-	return sm ? sm->config : NULL;
-}
-
-
-static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL || sm->eapReqData == NULL)
-		return NULL;
-
-	return sm->eapReqData;
-}
-
-
-static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL)
-		return FALSE;
-	switch (variable) {
-	case EAPOL_eapSuccess:
-		return sm->eapSuccess;
-	case EAPOL_eapRestart:
-		return sm->eapRestart;
-	case EAPOL_eapFail:
-		return sm->eapFail;
-	case EAPOL_eapResp:
-		return sm->eapResp;
-	case EAPOL_eapNoResp:
-		return sm->eapNoResp;
-	case EAPOL_eapReq:
-		return sm->eapReq;
-	case EAPOL_portEnabled:
-		return sm->portEnabled;
-	case EAPOL_altAccept:
-		return sm->altAccept;
-	case EAPOL_altReject:
-		return sm->altReject;
-	}
-	return FALSE;
-}
-
-
-static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
-			      Boolean value)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL)
-		return;
-	switch (variable) {
-	case EAPOL_eapSuccess:
-		sm->eapSuccess = value;
-		break;
-	case EAPOL_eapRestart:
-		sm->eapRestart = value;
-		break;
-	case EAPOL_eapFail:
-		sm->eapFail = value;
-		break;
-	case EAPOL_eapResp:
-		sm->eapResp = value;
-		break;
-	case EAPOL_eapNoResp:
-		sm->eapNoResp = value;
-		break;
-	case EAPOL_eapReq:
-		sm->eapReq = value;
-		break;
-	case EAPOL_portEnabled:
-		sm->portEnabled = value;
-		break;
-	case EAPOL_altAccept:
-		sm->altAccept = value;
-		break;
-	case EAPOL_altReject:
-		sm->altReject = value;
-		break;
-	}
-}
-
-
-static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL)
-		return 0;
-	switch (variable) {
-	case EAPOL_idleWhile:
-		return sm->idleWhile;
-	}
-	return 0;
-}
-
-
-static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
-			     unsigned int value)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL)
-		return;
-	switch (variable) {
-	case EAPOL_idleWhile:
-		sm->idleWhile = value;
-		eapol_enable_timer_tick(sm);
-		break;
-	}
-}
-
-
-static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
-{
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct eapol_sm *sm = ctx;
-	if (sm && sm->ctx && sm->ctx->set_config_blob)
-		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-}
-
-
-static const struct wpa_config_blob *
-eapol_sm_get_config_blob(void *ctx, const char *name)
-{
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct eapol_sm *sm = ctx;
-	if (sm && sm->ctx && sm->ctx->get_config_blob)
-		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
-	else
-		return NULL;
-#else /* CONFIG_NO_CONFIG_BLOBS */
-	return NULL;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-}
-
-
-static void eapol_sm_notify_pending(void *ctx)
-{
-	struct eapol_sm *sm = ctx;
-	if (sm == NULL)
-		return;
-	if (sm->eapReqData && !sm->eapReq) {
-		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
-			   "state machine - retrying pending EAP Request");
-		sm->eapolEap = TRUE;
-		sm->eapReq = TRUE;
-		eapol_sm_step(sm);
-	}
-}
-
-
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
-				      const char *txt)
-{
-	struct eapol_sm *sm = ctx;
-	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
-	if (sm->ctx->eap_param_needed)
-		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eapol_sm_eap_param_needed NULL
-#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-
-
-static struct eapol_callbacks eapol_cb =
-{
-	eapol_sm_get_config,
-	eapol_sm_get_bool,
-	eapol_sm_set_bool,
-	eapol_sm_get_int,
-	eapol_sm_set_int,
-	eapol_sm_get_eapReqData,
-	eapol_sm_set_config_blob,
-	eapol_sm_get_config_blob,
-	eapol_sm_notify_pending,
-	eapol_sm_eap_param_needed
-};
-
-
-/**
- * eapol_sm_init - Initialize EAPOL state machine
- * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
- * and EAPOL state machine will free it in eapol_sm_deinit()
- * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
- *
- * Allocate and initialize an EAPOL state machine.
- */
-struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
-{
-	struct eapol_sm *sm;
-	struct eap_config conf;
-	sm = os_zalloc(sizeof(*sm));
-	if (sm == NULL)
-		return NULL;
-	sm->ctx = ctx;
-
-	sm->portControl = Auto;
-
-	/* Supplicant PAE state machine */
-	sm->heldPeriod = 60;
-	sm->startPeriod = 30;
-	sm->maxStart = 3;
-
-	/* Supplicant Backend state machine */
-	sm->authPeriod = 30;
-
-	os_memset(&conf, 0, sizeof(conf));
-	conf.opensc_engine_path = ctx->opensc_engine_path;
-	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
-	conf.pkcs11_module_path = ctx->pkcs11_module_path;
-	conf.wps = ctx->wps;
-
-	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
-	if (sm->eap == NULL) {
-		os_free(sm);
-		return NULL;
-	}
-
-	/* Initialize EAPOL state machines */
-	sm->initialize = TRUE;
-	eapol_sm_step(sm);
-	sm->initialize = FALSE;
-	eapol_sm_step(sm);
-
-	sm->timer_tick_enabled = 1;
-	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
-
-	return sm;
-}
-
-
-/**
- * eapol_sm_deinit - Deinitialize EAPOL state machine
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Deinitialize and free EAPOL state machine.
- */
-void eapol_sm_deinit(struct eapol_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
-	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
-	eap_peer_sm_deinit(sm->eap);
-	os_free(sm->last_rx_key);
-	wpabuf_free(sm->eapReqData);
-	os_free(sm->ctx);
-	os_free(sm);
-}

Copied: vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c (from rev 9639, vendor/wpa/dist/src/eapol_supp/eapol_supp_sm.c)
===================================================================
--- vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1938 @@
+/*
+ * EAPOL supplicant state machines
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "state_machine.h"
+#include "wpabuf.h"
+#include "eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/md5.h"
+#include "common/eapol_common.h"
+#include "eap_peer/eap.h"
+#include "eapol_supp_sm.h"
+
+#define STATE_MACHINE_DATA struct eapol_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
+
+
+/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
+
+/**
+ * struct eapol_sm - Internal data for EAPOL state machines
+ */
+struct eapol_sm {
+	/* Timers */
+	unsigned int authWhile;
+	unsigned int heldWhile;
+	unsigned int startWhen;
+	unsigned int idleWhile; /* for EAP state machine */
+	int timer_tick_enabled;
+
+	/* Global variables */
+	Boolean eapFail;
+	Boolean eapolEap;
+	Boolean eapSuccess;
+	Boolean initialize;
+	Boolean keyDone;
+	Boolean keyRun;
+	PortControl portControl;
+	Boolean portEnabled;
+	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
+	Boolean portValid;
+	Boolean suppAbort;
+	Boolean suppFail;
+	Boolean suppStart;
+	Boolean suppSuccess;
+	Boolean suppTimeout;
+
+	/* Supplicant PAE state machine */
+	enum {
+		SUPP_PAE_UNKNOWN = 0,
+		SUPP_PAE_DISCONNECTED = 1,
+		SUPP_PAE_LOGOFF = 2,
+		SUPP_PAE_CONNECTING = 3,
+		SUPP_PAE_AUTHENTICATING = 4,
+		SUPP_PAE_AUTHENTICATED = 5,
+		/* unused(6) */
+		SUPP_PAE_HELD = 7,
+		SUPP_PAE_RESTART = 8,
+		SUPP_PAE_S_FORCE_AUTH = 9,
+		SUPP_PAE_S_FORCE_UNAUTH = 10
+	} SUPP_PAE_state; /* dot1xSuppPaeState */
+	/* Variables */
+	Boolean userLogoff;
+	Boolean logoffSent;
+	unsigned int startCount;
+	Boolean eapRestart;
+	PortControl sPortMode;
+	/* Constants */
+	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
+	unsigned int startPeriod; /* dot1xSuppStartPeriod */
+	unsigned int maxStart; /* dot1xSuppMaxStart */
+
+	/* Key Receive state machine */
+	enum {
+		KEY_RX_UNKNOWN = 0,
+		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
+	} KEY_RX_state;
+	/* Variables */
+	Boolean rxKey;
+
+	/* Supplicant Backend state machine */
+	enum {
+		SUPP_BE_UNKNOWN = 0,
+		SUPP_BE_INITIALIZE = 1,
+		SUPP_BE_IDLE = 2,
+		SUPP_BE_REQUEST = 3,
+		SUPP_BE_RECEIVE = 4,
+		SUPP_BE_RESPONSE = 5,
+		SUPP_BE_FAIL = 6,
+		SUPP_BE_TIMEOUT = 7, 
+		SUPP_BE_SUCCESS = 8
+	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
+	/* Variables */
+	Boolean eapNoResp;
+	Boolean eapReq;
+	Boolean eapResp;
+	/* Constants */
+	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
+
+	/* Statistics */
+	unsigned int dot1xSuppEapolFramesRx;
+	unsigned int dot1xSuppEapolFramesTx;
+	unsigned int dot1xSuppEapolStartFramesTx;
+	unsigned int dot1xSuppEapolLogoffFramesTx;
+	unsigned int dot1xSuppEapolRespFramesTx;
+	unsigned int dot1xSuppEapolReqIdFramesRx;
+	unsigned int dot1xSuppEapolReqFramesRx;
+	unsigned int dot1xSuppInvalidEapolFramesRx;
+	unsigned int dot1xSuppEapLengthErrorFramesRx;
+	unsigned int dot1xSuppLastEapolFrameVersion;
+	unsigned char dot1xSuppLastEapolFrameSource[6];
+
+	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
+	Boolean changed;
+	struct eap_sm *eap;
+	struct eap_peer_config *config;
+	Boolean initial_req;
+	u8 *last_rx_key;
+	size_t last_rx_key_len;
+	struct wpabuf *eapReqData; /* for EAP */
+	Boolean altAccept; /* for EAP */
+	Boolean altReject; /* for EAP */
+	Boolean replay_counter_valid;
+	u8 last_replay_counter[16];
+	struct eapol_config conf;
+	struct eapol_ctx *ctx;
+	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
+		cb_status;
+	Boolean cached_pmk;
+
+	Boolean unicast_key_received, broadcast_key_received;
+};
+
+
+static void eapol_sm_txLogoff(struct eapol_sm *sm);
+static void eapol_sm_txStart(struct eapol_sm *sm);
+static void eapol_sm_processKey(struct eapol_sm *sm);
+static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
+static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
+static void eapol_sm_abortSupp(struct eapol_sm *sm);
+static void eapol_sm_abort_cached(struct eapol_sm *sm);
+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
+static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
+
+
+/* Port Timers state machine - implemented as a function that will be called
+ * once a second as a registered event loop timeout */
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_sm *sm = timeout_ctx;
+
+	if (sm->authWhile > 0) {
+		sm->authWhile--;
+		if (sm->authWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
+	}
+	if (sm->heldWhile > 0) {
+		sm->heldWhile--;
+		if (sm->heldWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
+	}
+	if (sm->startWhen > 0) {
+		sm->startWhen--;
+		if (sm->startWhen == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
+	}
+	if (sm->idleWhile > 0) {
+		sm->idleWhile--;
+		if (sm->idleWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
+	}
+
+	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
+		eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
+				       sm);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
+		sm->timer_tick_enabled = 0;
+	}
+	eapol_sm_step(sm);
+}
+
+
+static void eapol_enable_timer_tick(struct eapol_sm *sm)
+{
+	if (sm->timer_tick_enabled)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
+	sm->timer_tick_enabled = 1;
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+}
+
+
+SM_STATE(SUPP_PAE, LOGOFF)
+{
+	SM_ENTRY(SUPP_PAE, LOGOFF);
+	eapol_sm_txLogoff(sm);
+	sm->logoffSent = TRUE;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+}
+
+
+SM_STATE(SUPP_PAE, DISCONNECTED)
+{
+	SM_ENTRY(SUPP_PAE, DISCONNECTED);
+	sm->sPortMode = Auto;
+	sm->startCount = 0;
+	sm->logoffSent = FALSE;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->suppAbort = TRUE;
+
+	sm->unicast_key_received = FALSE;
+	sm->broadcast_key_received = FALSE;
+
+	/*
+	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when the port is
+	 * not enabled. Since this variable is used only within HELD state,
+	 * clearing it on initialization does not change actual state machine
+	 * behavior.
+	 */
+	sm->heldWhile = 0;
+}
+
+
+SM_STATE(SUPP_PAE, CONNECTING)
+{
+	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
+	SM_ENTRY(SUPP_PAE, CONNECTING);
+	if (send_start) {
+		sm->startWhen = sm->startPeriod;
+		sm->startCount++;
+	} else {
+		/*
+		 * Do not send EAPOL-Start immediately since in most cases,
+		 * Authenticator is going to start authentication immediately
+		 * after association and an extra EAPOL-Start is just going to
+		 * delay authentication. Use a short timeout to send the first
+		 * EAPOL-Start if Authenticator does not start authentication.
+		 */
+#ifdef CONFIG_WPS
+		/* Reduce latency on starting WPS negotiation. */
+		sm->startWhen = 1;
+#else /* CONFIG_WPS */
+		sm->startWhen = 3;
+#endif /* CONFIG_WPS */
+	}
+	eapol_enable_timer_tick(sm);
+	sm->eapolEap = FALSE;
+	if (send_start)
+		eapol_sm_txStart(sm);
+}
+
+
+SM_STATE(SUPP_PAE, AUTHENTICATING)
+{
+	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
+	sm->startCount = 0;
+	sm->suppSuccess = FALSE;
+	sm->suppFail = FALSE;
+	sm->suppTimeout = FALSE;
+	sm->keyRun = FALSE;
+	sm->keyDone = FALSE;
+	sm->suppStart = TRUE;
+}
+
+
+SM_STATE(SUPP_PAE, HELD)
+{
+	SM_ENTRY(SUPP_PAE, HELD);
+	sm->heldWhile = sm->heldPeriod;
+	eapol_enable_timer_tick(sm);
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->cb_status = EAPOL_CB_FAILURE;
+}
+
+
+SM_STATE(SUPP_PAE, AUTHENTICATED)
+{
+	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
+	sm->suppPortStatus = Authorized;
+	eapol_sm_set_port_authorized(sm);
+	sm->cb_status = EAPOL_CB_SUCCESS;
+}
+
+
+SM_STATE(SUPP_PAE, RESTART)
+{
+	SM_ENTRY(SUPP_PAE, RESTART);
+	sm->eapRestart = TRUE;
+}
+
+
+SM_STATE(SUPP_PAE, S_FORCE_AUTH)
+{
+	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
+	sm->suppPortStatus = Authorized;
+	eapol_sm_set_port_authorized(sm);
+	sm->sPortMode = ForceAuthorized;
+}
+
+
+SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
+{
+	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->sPortMode = ForceUnauthorized;
+	eapol_sm_txLogoff(sm);
+}
+
+
+SM_STEP(SUPP_PAE)
+{
+	if ((sm->userLogoff && !sm->logoffSent) &&
+	    !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
+	else if (((sm->portControl == Auto) &&
+		  (sm->sPortMode != sm->portControl)) ||
+		 sm->initialize || !sm->portEnabled)
+		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
+	else if ((sm->portControl == ForceAuthorized) &&
+		 (sm->sPortMode != sm->portControl) &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
+	else if ((sm->portControl == ForceUnauthorized) &&
+		 (sm->sPortMode != sm->portControl) &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
+	else switch (sm->SUPP_PAE_state) {
+	case SUPP_PAE_UNKNOWN:
+		break;
+	case SUPP_PAE_LOGOFF:
+		if (!sm->userLogoff)
+			SM_ENTER(SUPP_PAE, DISCONNECTED);
+		break;
+	case SUPP_PAE_DISCONNECTED:
+		SM_ENTER(SUPP_PAE, CONNECTING);
+		break;
+	case SUPP_PAE_CONNECTING:
+		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		else if (sm->startWhen == 0 &&
+			 sm->startCount >= sm->maxStart &&
+			 sm->portValid)
+			SM_ENTER(SUPP_PAE, AUTHENTICATED);
+		else if (sm->eapSuccess || sm->eapFail)
+			SM_ENTER(SUPP_PAE, AUTHENTICATING);
+		else if (sm->eapolEap)
+			SM_ENTER(SUPP_PAE, RESTART);
+		else if (sm->startWhen == 0 &&
+			 sm->startCount >= sm->maxStart &&
+			 !sm->portValid)
+			SM_ENTER(SUPP_PAE, HELD);
+		break;
+	case SUPP_PAE_AUTHENTICATING:
+		if (sm->eapSuccess && !sm->portValid &&
+		    sm->conf.accept_802_1x_keys &&
+		    sm->conf.required_keys == 0) {
+			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
+				   "plaintext connection; no EAPOL-Key frames "
+				   "required");
+			sm->portValid = TRUE;
+			if (sm->ctx->eapol_done_cb)
+				sm->ctx->eapol_done_cb(sm->ctx->ctx);
+		}
+		if (sm->eapSuccess && sm->portValid)
+			SM_ENTER(SUPP_PAE, AUTHENTICATED);
+		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
+			SM_ENTER(SUPP_PAE, HELD);
+		else if (sm->suppTimeout)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		break;
+	case SUPP_PAE_HELD:
+		if (sm->heldWhile == 0)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		else if (sm->eapolEap)
+			SM_ENTER(SUPP_PAE, RESTART);
+		break;
+	case SUPP_PAE_AUTHENTICATED:
+		if (sm->eapolEap && sm->portValid)
+			SM_ENTER(SUPP_PAE, RESTART);
+		else if (!sm->portValid)
+			SM_ENTER(SUPP_PAE, DISCONNECTED);
+		break;
+	case SUPP_PAE_RESTART:
+		if (!sm->eapRestart)
+			SM_ENTER(SUPP_PAE, AUTHENTICATING);
+		break;
+	case SUPP_PAE_S_FORCE_AUTH:
+		break;
+	case SUPP_PAE_S_FORCE_UNAUTH:
+		break;
+	}
+}
+
+
+SM_STATE(KEY_RX, NO_KEY_RECEIVE)
+{
+	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
+}
+
+
+SM_STATE(KEY_RX, KEY_RECEIVE)
+{
+	SM_ENTRY(KEY_RX, KEY_RECEIVE);
+	eapol_sm_processKey(sm);
+	sm->rxKey = FALSE;
+}
+
+
+SM_STEP(KEY_RX)
+{
+	if (sm->initialize || !sm->portEnabled)
+		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
+	switch (sm->KEY_RX_state) {
+	case KEY_RX_UNKNOWN:
+		break;
+	case KEY_RX_NO_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	case KEY_RX_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	}
+}
+
+
+SM_STATE(SUPP_BE, REQUEST)
+{
+	SM_ENTRY(SUPP_BE, REQUEST);
+	sm->authWhile = 0;
+	sm->eapReq = TRUE;
+	eapol_sm_getSuppRsp(sm);
+}
+
+
+SM_STATE(SUPP_BE, RESPONSE)
+{
+	SM_ENTRY(SUPP_BE, RESPONSE);
+	eapol_sm_txSuppRsp(sm);
+	sm->eapResp = FALSE;
+}
+
+
+SM_STATE(SUPP_BE, SUCCESS)
+{
+	SM_ENTRY(SUPP_BE, SUCCESS);
+	sm->keyRun = TRUE;
+	sm->suppSuccess = TRUE;
+
+	if (eap_key_available(sm->eap)) {
+		/* New key received - clear IEEE 802.1X EAPOL-Key replay
+		 * counter */
+		sm->replay_counter_valid = FALSE;
+	}
+}
+
+
+SM_STATE(SUPP_BE, FAIL)
+{
+	SM_ENTRY(SUPP_BE, FAIL);
+	sm->suppFail = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, TIMEOUT)
+{
+	SM_ENTRY(SUPP_BE, TIMEOUT);
+	sm->suppTimeout = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, IDLE)
+{
+	SM_ENTRY(SUPP_BE, IDLE);
+	sm->suppStart = FALSE;
+	sm->initial_req = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, INITIALIZE)
+{
+	SM_ENTRY(SUPP_BE, INITIALIZE);
+	eapol_sm_abortSupp(sm);
+	sm->suppAbort = FALSE;
+
+	/*
+	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when the port is
+	 * not enabled. Since this variable is used only within RECEIVE state,
+	 * clearing it on initialization does not change actual state machine
+	 * behavior.
+	 */
+	sm->authWhile = 0;
+}
+
+
+SM_STATE(SUPP_BE, RECEIVE)
+{
+	SM_ENTRY(SUPP_BE, RECEIVE);
+	sm->authWhile = sm->authPeriod;
+	eapol_enable_timer_tick(sm);
+	sm->eapolEap = FALSE;
+	sm->eapNoResp = FALSE;
+	sm->initial_req = FALSE;
+}
+
+
+SM_STEP(SUPP_BE)
+{
+	if (sm->initialize || sm->suppAbort)
+		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
+	else switch (sm->SUPP_BE_state) {
+	case SUPP_BE_UNKNOWN:
+		break;
+	case SUPP_BE_REQUEST:
+		/*
+		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
+		 * and SUCCESS based on eapFail and eapSuccess, respectively.
+		 * However, IEEE Std 802.1X-2004 is also specifying that
+		 * eapNoResp should be set in conjunction with eapSuccess and
+		 * eapFail which would mean that more than one of the
+		 * transitions here would be activated at the same time.
+		 * Skipping RESPONSE and/or RECEIVE states in these cases can
+		 * cause problems and the direct transitions to do not seem
+		 * correct. Because of this, the conditions for these
+		 * transitions are verified only after eapNoResp. They are
+		 * unlikely to be used since eapNoResp should always be set if
+		 * either of eapSuccess or eapFail is set.
+		 */
+		if (sm->eapResp && sm->eapNoResp) {
+			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
+				   "eapResp and eapNoResp set?!");
+		}
+		if (sm->eapResp)
+			SM_ENTER(SUPP_BE, RESPONSE);
+		else if (sm->eapNoResp)
+			SM_ENTER(SUPP_BE, RECEIVE);
+		else if (sm->eapFail)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->eapSuccess)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	case SUPP_BE_RESPONSE:
+		SM_ENTER(SUPP_BE, RECEIVE);
+		break;
+	case SUPP_BE_SUCCESS:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_FAIL:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_TIMEOUT:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_IDLE:
+		if (sm->eapFail && sm->suppStart)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->eapolEap && sm->suppStart)
+			SM_ENTER(SUPP_BE, REQUEST);
+		else if (sm->eapSuccess && sm->suppStart)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	case SUPP_BE_INITIALIZE:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_RECEIVE:
+		if (sm->eapolEap)
+			SM_ENTER(SUPP_BE, REQUEST);
+		else if (sm->eapFail)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->authWhile == 0)
+			SM_ENTER(SUPP_BE, TIMEOUT);
+		else if (sm->eapSuccess)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	}
+}
+
+
+static void eapol_sm_txLogoff(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
+	sm->dot1xSuppEapolLogoffFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+static void eapol_sm_txStart(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
+	sm->dot1xSuppEapolStartFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+#define IEEE8021X_ENCR_KEY_LEN 32
+#define IEEE8021X_SIGN_KEY_LEN 32
+
+struct eap_key_data {
+	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
+	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
+};
+
+
+static void eapol_sm_processKey(struct eapol_sm *sm)
+{
+#ifndef CONFIG_FIPS
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	struct eap_key_data keydata;
+	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
+	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
+	int key_len, res, sign_key_len, encr_key_len;
+	u16 rx_key_length;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
+	if (sm->last_rx_key == NULL)
+		return;
+
+	if (!sm->conf.accept_802_1x_keys) {
+		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
+			   " even though this was not accepted - "
+			   "ignoring this packet");
+		return;
+	}
+
+	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
+		return;
+	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	plen = be_to_host16(hdr->length);
+	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
+		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
+		return;
+	}
+	rx_key_length = WPA_GET_BE16(key->key_length);
+	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
+		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
+		   hdr->version, hdr->type, be_to_host16(hdr->length),
+		   key->type, rx_key_length, key->key_index);
+
+	eapol_sm_notify_lower_layer_success(sm, 1);
+	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
+	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
+	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
+			   "decrypting EAPOL-Key keys");
+		return;
+	}
+	if (res == 16) {
+		/* LEAP derives only 16 bytes of keying material. */
+		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
+		if (res) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
+				   "master key for decrypting EAPOL-Key keys");
+			return;
+		}
+		sign_key_len = 16;
+		encr_key_len = 16;
+		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
+	} else if (res) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
+			   "data for decrypting EAPOL-Key keys (res=%d)", res);
+		return;
+	}
+
+	/* The key replay_counter must increase when same master key */
+	if (sm->replay_counter_valid &&
+	    os_memcmp(sm->last_replay_counter, key->replay_counter,
+		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
+		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
+			   "not increase - ignoring key");
+		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
+			    sm->last_replay_counter,
+			    IEEE8021X_REPLAY_COUNTER_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
+			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
+		return;
+	}
+
+	/* Verify key signature (HMAC-MD5) */
+	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
+	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
+	hmac_md5(keydata.sign_key, sign_key_len,
+		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
+		 key->key_signature);
+	if (os_memcmp(orig_key_sign, key->key_signature,
+		      IEEE8021X_KEY_SIGN_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
+			   "EAPOL-Key packet");
+		os_memcpy(key->key_signature, orig_key_sign,
+			  IEEE8021X_KEY_SIGN_LEN);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
+
+	key_len = plen - sizeof(*key);
+	if (key_len > 32 || rx_key_length > 32) {
+		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
+			   key_len ? key_len : rx_key_length);
+		return;
+	}
+	if (key_len == rx_key_length) {
+		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
+		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
+			  encr_key_len);
+		os_memcpy(datakey, key + 1, key_len);
+		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
+			 datakey, key_len);
+		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
+				datakey, key_len);
+	} else if (key_len == 0) {
+		/*
+		 * IEEE 802.1X-2004 specifies that least significant Key Length
+		 * octets from MS-MPPE-Send-Key are used as the key if the key
+		 * data is not present. This seems to be meaning the beginning
+		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
+		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
+		 * Anyway, taking the beginning of the keying material from EAP
+		 * seems to interoperate with Authenticators.
+		 */
+		key_len = rx_key_length;
+		os_memcpy(datakey, keydata.encr_key, key_len);
+		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
+				"material data encryption key",
+				datakey, key_len);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
+			   "(key_length=%d)", key_len, rx_key_length);
+		return;
+	}
+
+	sm->replay_counter_valid = TRUE;
+	os_memcpy(sm->last_replay_counter, key->replay_counter,
+		  IEEE8021X_REPLAY_COUNTER_LEN);
+
+	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
+		   "len %d",
+		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
+		   "unicast" : "broadcast",
+		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
+
+	if (sm->ctx->set_wep_key &&
+	    sm->ctx->set_wep_key(sm->ctx->ctx,
+				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
+				 datakey, key_len) < 0) {
+		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
+			   " driver.");
+	} else {
+		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
+			sm->unicast_key_received = TRUE;
+		else
+			sm->broadcast_key_received = TRUE;
+
+		if ((sm->unicast_key_received ||
+		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
+		    (sm->broadcast_key_received ||
+		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
+		{
+			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
+				   "frames received");
+			sm->portValid = TRUE;
+			if (sm->ctx->eapol_done_cb)
+				sm->ctx->eapol_done_cb(sm->ctx->ctx);
+		}
+	}
+#endif /* CONFIG_FIPS */
+}
+
+
+static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
+	/* EAP layer processing; no special code is needed, since Supplicant
+	 * Backend state machine is waiting for eapNoResp or eapResp to be set
+	 * and these are only set in the EAP state machine when the processing
+	 * has finished. */
+}
+
+
+static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
+{
+	struct wpabuf *resp;
+
+	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+	resp = eap_get_eapRespData(sm->eap);
+	if (resp == NULL) {
+		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
+			   "not available");
+		return;
+	}
+
+	/* Send EAP-Packet from the EAP layer to the Authenticator */
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
+			    wpabuf_len(resp));
+
+	/* eapRespData is not used anymore, so free it here */
+	wpabuf_free(resp);
+
+	if (sm->initial_req)
+		sm->dot1xSuppEapolReqIdFramesRx++;
+	else
+		sm->dot1xSuppEapolReqFramesRx++;
+	sm->dot1xSuppEapolRespFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+static void eapol_sm_abortSupp(struct eapol_sm *sm)
+{
+	/* release system resources that may have been allocated for the
+	 * authentication session */
+	os_free(sm->last_rx_key);
+	sm->last_rx_key = NULL;
+	wpabuf_free(sm->eapReqData);
+	sm->eapReqData = NULL;
+	eap_sm_abort(sm->eap);
+}
+
+
+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	eapol_sm_step(timeout_ctx);
+}
+
+
+static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
+{
+	if (sm->ctx->port_cb)
+		sm->ctx->port_cb(sm->ctx->ctx, 1);
+}
+
+
+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
+{
+	if (sm->ctx->port_cb)
+		sm->ctx->port_cb(sm->ctx->ctx, 0);
+}
+
+
+/**
+ * eapol_sm_step - EAPOL state machine step function
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function is called to notify the state machine about changed external
+ * variables. It will step through the EAPOL state machines in loop to process
+ * all triggered state changes.
+ */
+void eapol_sm_step(struct eapol_sm *sm)
+{
+	int i;
+
+	/* In theory, it should be ok to run this in loop until !changed.
+	 * However, it is better to use a limit on number of iterations to
+	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
+	 * state machine were to generate a busy loop. */
+	for (i = 0; i < 100; i++) {
+		sm->changed = FALSE;
+		SM_STEP_RUN(SUPP_PAE);
+		SM_STEP_RUN(KEY_RX);
+		SM_STEP_RUN(SUPP_BE);
+		if (eap_peer_sm_step(sm->eap))
+			sm->changed = TRUE;
+		if (!sm->changed)
+			break;
+	}
+
+	if (sm->changed) {
+		/* restart EAPOL state machine step from timeout call in order
+		 * to allow other events to be processed. */
+		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
+		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
+	}
+
+	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
+		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+		sm->cb_status = EAPOL_CB_IN_PROGRESS;
+		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+	}
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static const char *eapol_supp_pae_state(int state)
+{
+	switch (state) {
+	case SUPP_PAE_LOGOFF:
+		return "LOGOFF";
+	case SUPP_PAE_DISCONNECTED:
+		return "DISCONNECTED";
+	case SUPP_PAE_CONNECTING:
+		return "CONNECTING";
+	case SUPP_PAE_AUTHENTICATING:
+		return "AUTHENTICATING";
+	case SUPP_PAE_HELD:
+		return "HELD";
+	case SUPP_PAE_AUTHENTICATED:
+		return "AUTHENTICATED";
+	case SUPP_PAE_RESTART:
+		return "RESTART";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char *eapol_supp_be_state(int state)
+{
+	switch (state) {
+	case SUPP_BE_REQUEST:
+		return "REQUEST";
+	case SUPP_BE_RESPONSE:
+		return "RESPONSE";
+	case SUPP_BE_SUCCESS:
+		return "SUCCESS";
+	case SUPP_BE_FAIL:
+		return "FAIL";
+	case SUPP_BE_TIMEOUT:
+		return "TIMEOUT";
+	case SUPP_BE_IDLE:
+		return "IDLE";
+	case SUPP_BE_INITIALIZE:
+		return "INITIALIZE";
+	case SUPP_BE_RECEIVE:
+		return "RECEIVE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char * eapol_port_status(PortStatus status)
+{
+	if (status == Authorized)
+		return "Authorized";
+	else
+		return "Unauthorized";
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eapol_port_control(PortControl ctrl)
+{
+	switch (ctrl) {
+	case Auto:
+		return "Auto";
+	case ForceUnauthorized:
+		return "ForceUnauthorized";
+	case ForceAuthorized:
+		return "ForceAuthorized";
+	default:
+		return "Unknown";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+/**
+ * eapol_sm_configure - Set EAPOL variables
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @heldPeriod: dot1xSuppHeldPeriod
+ * @authPeriod: dot1xSuppAuthPeriod
+ * @startPeriod: dot1xSuppStartPeriod
+ * @maxStart: dot1xSuppMaxStart
+ *
+ * Set configurable EAPOL state machine variables. Each variable can be set to
+ * the given value or ignored if set to -1 (to set only some of the variables).
+ */
+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
+			int startPeriod, int maxStart)
+{
+	if (sm == NULL)
+		return;
+	if (heldPeriod >= 0)
+		sm->heldPeriod = heldPeriod;
+	if (authPeriod >= 0)
+		sm->authPeriod = authPeriod;
+	if (startPeriod >= 0)
+		sm->startPeriod = startPeriod;
+	if (maxStart >= 0)
+		sm->maxStart = maxStart;
+}
+
+
+/**
+ * eapol_sm_get_method_name - Get EAPOL method name
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * Returns: Static string containing name of current eap method or NULL
+ */
+const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
+	    sm->suppPortStatus != Authorized)
+		return NULL;
+
+	return eap_sm_get_method_name(sm->eap);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+/**
+ * eapol_sm_get_status - Get EAPOL state machine status
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_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 EAPOL state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
+			int verbose)
+{
+	int len, ret;
+	if (sm == NULL)
+		return 0;
+
+	len = os_snprintf(buf, buflen,
+			  "Supplicant PAE state=%s\n"
+			  "suppPortStatus=%s\n",
+			  eapol_supp_pae_state(sm->SUPP_PAE_state),
+			  eapol_port_status(sm->suppPortStatus));
+	if (len < 0 || (size_t) len >= buflen)
+		return 0;
+
+	if (verbose) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "heldPeriod=%u\n"
+				  "authPeriod=%u\n"
+				  "startPeriod=%u\n"
+				  "maxStart=%u\n"
+				  "portControl=%s\n"
+				  "Supplicant Backend state=%s\n",
+				  sm->heldPeriod,
+				  sm->authPeriod,
+				  sm->startPeriod,
+				  sm->maxStart,
+				  eapol_port_control(sm->portControl),
+				  eapol_supp_be_state(sm->SUPP_BE_state));
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
+
+	return len;
+}
+
+
+/**
+ * eapol_sm_get_mib - Get EAPOL state machine MIBs
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @buf: Buffer for MIB information
+ * @buflen: Maximum buffer length
+ * Returns: Number of bytes written to buf.
+ *
+ * Query EAPOL state machine for MIB information. This function fills in a
+ * text area with current MIB information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, MIB information will be truncated to
+ * fit the buffer.
+ */
+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
+{
+	size_t len;
+	int ret;
+
+	if (sm == NULL)
+		return 0;
+	ret = os_snprintf(buf, buflen,
+			  "dot1xSuppPaeState=%d\n"
+			  "dot1xSuppHeldPeriod=%u\n"
+			  "dot1xSuppAuthPeriod=%u\n"
+			  "dot1xSuppStartPeriod=%u\n"
+			  "dot1xSuppMaxStart=%u\n"
+			  "dot1xSuppSuppControlledPortStatus=%s\n"
+			  "dot1xSuppBackendPaeState=%d\n",
+			  sm->SUPP_PAE_state,
+			  sm->heldPeriod,
+			  sm->authPeriod,
+			  sm->startPeriod,
+			  sm->maxStart,
+			  sm->suppPortStatus == Authorized ?
+			  "Authorized" : "Unauthorized",
+			  sm->SUPP_BE_state);
+
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	len = ret;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xSuppEapolFramesRx=%u\n"
+			  "dot1xSuppEapolFramesTx=%u\n"
+			  "dot1xSuppEapolStartFramesTx=%u\n"
+			  "dot1xSuppEapolLogoffFramesTx=%u\n"
+			  "dot1xSuppEapolRespFramesTx=%u\n"
+			  "dot1xSuppEapolReqIdFramesRx=%u\n"
+			  "dot1xSuppEapolReqFramesRx=%u\n"
+			  "dot1xSuppInvalidEapolFramesRx=%u\n"
+			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
+			  "dot1xSuppLastEapolFrameVersion=%u\n"
+			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
+			  sm->dot1xSuppEapolFramesRx,
+			  sm->dot1xSuppEapolFramesTx,
+			  sm->dot1xSuppEapolStartFramesTx,
+			  sm->dot1xSuppEapolLogoffFramesTx,
+			  sm->dot1xSuppEapolRespFramesTx,
+			  sm->dot1xSuppEapolReqIdFramesRx,
+			  sm->dot1xSuppEapolReqFramesRx,
+			  sm->dot1xSuppInvalidEapolFramesRx,
+			  sm->dot1xSuppEapLengthErrorFramesRx,
+			  sm->dot1xSuppLastEapolFrameVersion,
+			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
+
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+/**
+ * eapol_sm_rx_eapol - Process received EAPOL frames
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @src: Source MAC address of the EAPOL packet
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
+ * -1 failure
+ */
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+		      size_t len)
+{
+	const struct ieee802_1x_hdr *hdr;
+	const struct ieee802_1x_eapol_key *key;
+	int data_len;
+	int res = 1;
+	size_t plen;
+
+	if (sm == NULL)
+		return 0;
+	sm->dot1xSuppEapolFramesRx++;
+	if (len < sizeof(*hdr)) {
+		sm->dot1xSuppInvalidEapolFramesRx++;
+		return 0;
+	}
+	hdr = (const struct ieee802_1x_hdr *) buf;
+	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
+	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
+	if (hdr->version < EAPOL_VERSION) {
+		/* TODO: backwards compatibility */
+	}
+	plen = be_to_host16(hdr->length);
+	if (plen > len - sizeof(*hdr)) {
+		sm->dot1xSuppEapLengthErrorFramesRx++;
+		return 0;
+	}
+#ifdef CONFIG_WPS
+	if (sm->conf.workaround &&
+	    plen < len - sizeof(*hdr) &&
+	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
+	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
+		const struct eap_hdr *ehdr =
+			(const struct eap_hdr *) (hdr + 1);
+		u16 elen;
+
+		elen = be_to_host16(ehdr->length);
+		if (elen > plen && elen <= len - sizeof(*hdr)) {
+			/*
+			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
+			 * packets with too short EAPOL header length field
+			 * (14 octets). This is fixed in firmware Ver.1.49.
+			 * As a workaround, fix the EAPOL header based on the
+			 * correct length in the EAP packet.
+			 */
+			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
+				   "payload length based on EAP header: "
+				   "%d -> %d", (int) plen, elen);
+			plen = elen;
+		}
+	}
+#endif /* CONFIG_WPS */
+	data_len = plen + sizeof(*hdr);
+
+	switch (hdr->type) {
+	case IEEE802_1X_TYPE_EAP_PACKET:
+		if (sm->cached_pmk) {
+			/* Trying to use PMKSA caching, but Authenticator did
+			 * not seem to have a matching entry. Need to restart
+			 * EAPOL state machines.
+			 */
+			eapol_sm_abort_cached(sm);
+		}
+		wpabuf_free(sm->eapReqData);
+		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
+		if (sm->eapReqData) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
+				   "frame");
+			sm->eapolEap = TRUE;
+			eapol_sm_step(sm);
+		}
+		break;
+	case IEEE802_1X_TYPE_EAPOL_KEY:
+		if (plen < sizeof(*key)) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
+				   "frame received");
+			break;
+		}
+		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
+		if (key->type == EAPOL_KEY_TYPE_WPA ||
+		    key->type == EAPOL_KEY_TYPE_RSN) {
+			/* WPA Supplicant takes care of this frame. */
+			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
+				   "frame in EAPOL state machines");
+			res = 0;
+			break;
+		}
+		if (key->type != EAPOL_KEY_TYPE_RC4) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
+				   "EAPOL-Key type %d", key->type);
+			break;
+		}
+		os_free(sm->last_rx_key);
+		sm->last_rx_key = os_malloc(data_len);
+		if (sm->last_rx_key) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
+				   "frame");
+			os_memcpy(sm->last_rx_key, buf, data_len);
+			sm->last_rx_key_len = data_len;
+			sm->rxKey = TRUE;
+			eapol_sm_step(sm);
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
+			   hdr->type);
+		sm->dot1xSuppInvalidEapolFramesRx++;
+		break;
+	}
+
+	return res;
+}
+
+
+/**
+ * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machine about transmitted EAPOL packet from an external
+ * component, e.g., WPA. This will update the statistics.
+ */
+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
+{
+	if (sm)
+		sm->dot1xSuppEapolFramesTx++;
+}
+
+
+/**
+ * eapol_sm_notify_portEnabled - Notification about portEnabled change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @enabled: New portEnabled value
+ *
+ * Notify EAPOL state machine about new portEnabled value.
+ */
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portEnabled=%d", enabled);
+	sm->portEnabled = enabled;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_portValid - Notification about portValid change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @valid: New portValid value
+ *
+ * Notify EAPOL state machine about new portValid value.
+ */
+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portValid=%d", valid);
+	sm->portValid = valid;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_eap_success - Notification of external EAP success trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @success: %TRUE = set success, %FALSE = clear success
+ *
+ * Notify the EAPOL state machine that external event has forced EAP state to
+ * success (success = %TRUE). This can be cleared by setting success = %FALSE.
+ *
+ * This function is called to update EAP state when WPA-PSK key handshake has
+ * been completed successfully since WPA-PSK does not use EAP state machine.
+ */
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "EAP success=%d", success);
+	sm->eapSuccess = success;
+	sm->altAccept = success;
+	if (success)
+		eap_notify_success(sm->eap);
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @fail: %TRUE = set failure, %FALSE = clear failure
+ *
+ * Notify EAPOL state machine that external event has forced EAP state to
+ * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
+ */
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "EAP fail=%d", fail);
+	sm->eapFail = fail;
+	sm->altReject = fail;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_config - Notification of EAPOL configuration change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @config: Pointer to current network EAP configuration
+ * @conf: Pointer to EAPOL configuration data
+ *
+ * Notify EAPOL state machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed. conf will be copied to local EAPOL/EAP configuration
+ * data. If conf is %NULL, this part of the configuration change will be
+ * skipped.
+ */
+void eapol_sm_notify_config(struct eapol_sm *sm,
+			    struct eap_peer_config *config,
+			    const struct eapol_config *conf)
+{
+	if (sm == NULL)
+		return;
+
+	sm->config = config;
+
+	if (conf == NULL)
+		return;
+
+	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
+	sm->conf.required_keys = conf->required_keys;
+	sm->conf.fast_reauth = conf->fast_reauth;
+	sm->conf.workaround = conf->workaround;
+	if (sm->eap) {
+		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
+		eap_set_workaround(sm->eap, conf->workaround);
+		eap_set_force_disabled(sm->eap, conf->eap_disabled);
+	}
+}
+
+
+/**
+ * eapol_sm_get_key - Get master session key (MSK) from EAP
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @key: Pointer for key buffer
+ * @len: Number of bytes to copy to key
+ * Returns: 0 on success (len of key available), maximum available key len
+ * (>0) if key is available but it is shorter than len, or -1 on failure.
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
+ * is available only after a successful authentication.
+ */
+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
+{
+	const u8 *eap_key;
+	size_t eap_len;
+
+	if (sm == NULL || !eap_key_available(sm->eap)) {
+		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+		return -1;
+	}
+	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
+	if (eap_key == NULL) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
+		return -1;
+	}
+	if (len > eap_len) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
+			   "available (len=%lu)",
+			   (unsigned long) len, (unsigned long) eap_len);
+		return eap_len;
+	}
+	os_memcpy(key, eap_key, len);
+	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
+		   (unsigned long) len);
+	return 0;
+}
+
+
+/**
+ * eapol_sm_notify_logoff - Notification of logon/logoff commands
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @logoff: Whether command was logoff
+ *
+ * Notify EAPOL state machines that user requested logon/logoff.
+ */
+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+{
+	if (sm) {
+		sm->userLogoff = logoff;
+		eapol_sm_step(sm);
+	}
+}
+
+
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that PMKSA caching was successful. This is used
+ * to move EAPOL and EAP state machines into authenticated/successful state.
+ */
+void eapol_sm_notify_cached(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
+	sm->eapSuccess = TRUE;
+	eap_notify_success(sm->eap);
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @attempt: Whether PMKSA caching is tried
+ *
+ * Notify EAPOL state machines whether PMKSA caching is used.
+ */
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
+{
+	if (sm == NULL)
+		return;
+	if (attempt) {
+		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
+		sm->cached_pmk = TRUE;
+	} else {
+		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
+		sm->cached_pmk = FALSE;
+	}
+}
+
+
+static void eapol_sm_abort_cached(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
+		   "doing full EAP authentication");
+	if (sm == NULL)
+		return;
+	sm->cached_pmk = FALSE;
+	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+
+	/* Make sure we do not start sending EAPOL-Start frames first, but
+	 * instead move to RESTART state to start EAPOL authentication. */
+	sm->startWhen = 3;
+	eapol_enable_timer_tick(sm);
+
+	if (sm->ctx->aborted_cached)
+		sm->ctx->aborted_cached(sm->ctx->ctx);
+}
+
+
+/**
+ * eapol_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @ctx: Context data for smart card operations
+ *
+ * Notify EAPOL state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
+{
+	if (sm) {
+		sm->ctx->scard_ctx = ctx;
+		eap_register_scard_ctx(sm->eap, ctx);
+	}
+}
+
+
+/**
+ * eapol_sm_notify_portControl - Notification of portControl changes
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @portControl: New value for portControl variable
+ *
+ * Notify EAPOL state machines that portControl variable has changed.
+ */
+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portControl=%s", eapol_port_control(portControl));
+	sm->portControl = portControl;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eap_sm_notify_ctrl_attached(sm->eap);
+}
+
+
+/**
+ * eapol_sm_notify_ctrl_response - Notification of received user input
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a control response, i.e., user
+ * input, was received in order to trigger retrying of a pending EAP request.
+ */
+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	if (sm->eapReqData && !sm->eapReq) {
+		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
+			   "input) notification - retrying pending EAP "
+			   "Request");
+		sm->eapolEap = TRUE;
+		sm->eapReq = TRUE;
+		eapol_sm_step(sm);
+	}
+}
+
+
+/**
+ * eapol_sm_request_reauth - Request reauthentication
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function can be used to request EAPOL reauthentication, e.g., when the
+ * current PMKSA entry is nearing expiration.
+ */
+void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
+		return;
+	eapol_sm_txStart(sm);
+}
+
+
+/**
+ * eapol_sm_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @in_eapol_sm: Whether the caller is already running inside EAPOL state
+ * machine loop (eapol_sm_step())
+ *
+ * Notify EAPOL (and EAP) state machines that a lower layer has detected a
+ * successful authentication. This is used to recover from dropped EAP-Success
+ * messages.
+ */
+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
+{
+	if (sm == NULL)
+		return;
+	eap_notify_lower_layer_success(sm->eap);
+	if (!in_eapol_sm)
+		eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+	if (sm)
+		eap_invalidate_cached_session(sm->eap);
+}
+
+
+static struct eap_peer_config * eapol_sm_get_config(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	return sm ? sm->config : NULL;
+}
+
+
+static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL || sm->eapReqData == NULL)
+		return NULL;
+
+	return sm->eapReqData;
+}
+
+
+static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return FALSE;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		return sm->eapSuccess;
+	case EAPOL_eapRestart:
+		return sm->eapRestart;
+	case EAPOL_eapFail:
+		return sm->eapFail;
+	case EAPOL_eapResp:
+		return sm->eapResp;
+	case EAPOL_eapNoResp:
+		return sm->eapNoResp;
+	case EAPOL_eapReq:
+		return sm->eapReq;
+	case EAPOL_portEnabled:
+		return sm->portEnabled;
+	case EAPOL_altAccept:
+		return sm->altAccept;
+	case EAPOL_altReject:
+		return sm->altReject;
+	}
+	return FALSE;
+}
+
+
+static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
+			      Boolean value)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		sm->eapSuccess = value;
+		break;
+	case EAPOL_eapRestart:
+		sm->eapRestart = value;
+		break;
+	case EAPOL_eapFail:
+		sm->eapFail = value;
+		break;
+	case EAPOL_eapResp:
+		sm->eapResp = value;
+		break;
+	case EAPOL_eapNoResp:
+		sm->eapNoResp = value;
+		break;
+	case EAPOL_eapReq:
+		sm->eapReq = value;
+		break;
+	case EAPOL_portEnabled:
+		sm->portEnabled = value;
+		break;
+	case EAPOL_altAccept:
+		sm->altAccept = value;
+		break;
+	case EAPOL_altReject:
+		sm->altReject = value;
+		break;
+	}
+}
+
+
+static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return 0;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		return sm->idleWhile;
+	}
+	return 0;
+}
+
+
+static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
+			     unsigned int value)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		sm->idleWhile = value;
+		if (sm->idleWhile > 0)
+			eapol_enable_timer_tick(sm);
+		break;
+	}
+}
+
+
+static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct eapol_sm *sm = ctx;
+	if (sm && sm->ctx && sm->ctx->set_config_blob)
+		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+static const struct wpa_config_blob *
+eapol_sm_get_config_blob(void *ctx, const char *name)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct eapol_sm *sm = ctx;
+	if (sm && sm->ctx && sm->ctx->get_config_blob)
+		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
+	else
+		return NULL;
+#else /* CONFIG_NO_CONFIG_BLOBS */
+	return NULL;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+static void eapol_sm_notify_pending(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	if (sm->eapReqData && !sm->eapReq) {
+		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
+			   "state machine - retrying pending EAP Request");
+		sm->eapolEap = TRUE;
+		sm->eapReq = TRUE;
+		eapol_sm_step(sm);
+	}
+}
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+				      const char *txt)
+{
+	struct eapol_sm *sm = ctx;
+	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
+	if (sm->ctx->eap_param_needed)
+		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_sm_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
+				 const char *cert_hash,
+				 const struct wpabuf *cert)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm->ctx->cert_cb)
+		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
+				 cert_hash, cert);
+}
+
+
+static void eapol_sm_notify_status(void *ctx, const char *status,
+				   const char *parameter)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->status_cb)
+		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
+}
+
+
+static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->set_anon_id)
+		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
+}
+
+
+static struct eapol_callbacks eapol_cb =
+{
+	eapol_sm_get_config,
+	eapol_sm_get_bool,
+	eapol_sm_set_bool,
+	eapol_sm_get_int,
+	eapol_sm_set_int,
+	eapol_sm_get_eapReqData,
+	eapol_sm_set_config_blob,
+	eapol_sm_get_config_blob,
+	eapol_sm_notify_pending,
+	eapol_sm_eap_param_needed,
+	eapol_sm_notify_cert,
+	eapol_sm_notify_status,
+	eapol_sm_set_anon_id
+};
+
+
+/**
+ * eapol_sm_init - Initialize EAPOL state machine
+ * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
+ * and EAPOL state machine will free it in eapol_sm_deinit()
+ * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
+ *
+ * Allocate and initialize an EAPOL state machine.
+ */
+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
+{
+	struct eapol_sm *sm;
+	struct eap_config conf;
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	sm->ctx = ctx;
+
+	sm->portControl = Auto;
+
+	/* Supplicant PAE state machine */
+	sm->heldPeriod = 60;
+	sm->startPeriod = 30;
+	sm->maxStart = 3;
+
+	/* Supplicant Backend state machine */
+	sm->authPeriod = 30;
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.opensc_engine_path = ctx->opensc_engine_path;
+	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
+	conf.pkcs11_module_path = ctx->pkcs11_module_path;
+	conf.wps = ctx->wps;
+	conf.cert_in_cb = ctx->cert_in_cb;
+
+	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
+	if (sm->eap == NULL) {
+		os_free(sm);
+		return NULL;
+	}
+
+	/* Initialize EAPOL state machines */
+	sm->initialize = TRUE;
+	eapol_sm_step(sm);
+	sm->initialize = FALSE;
+	eapol_sm_step(sm);
+
+	sm->timer_tick_enabled = 1;
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+
+	return sm;
+}
+
+
+/**
+ * eapol_sm_deinit - Deinitialize EAPOL state machine
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Deinitialize and free EAPOL state machine.
+ */
+void eapol_sm_deinit(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eap_peer_sm_deinit(sm->eap);
+	os_free(sm->last_rx_key);
+	wpabuf_free(sm->eapReqData);
+	os_free(sm->ctx);
+	os_free(sm);
+}
+
+
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+			     struct ext_password_data *ext)
+{
+	if (sm && sm->eap)
+		eap_sm_set_ext_pw_ctx(sm->eap, ext);
+}
+
+
+int eapol_sm_failed(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return !sm->eapSuccess && sm->eapFail;
+}

Deleted: vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h
===================================================================
--- vendor/wpa/dist/src/eapol_supp/eapol_supp_sm.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,347 +0,0 @@
-/*
- * EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef EAPOL_SUPP_SM_H
-#define EAPOL_SUPP_SM_H
-
-#include "common/defs.h"
-
-typedef enum { Unauthorized, Authorized } PortStatus;
-typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
-
-/**
- * struct eapol_config - Per network configuration for EAPOL state machines
- */
-struct eapol_config {
-	/**
-	 * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames
-	 *
-	 * This variable should be set to 1 when using EAPOL state machines
-	 * with non-WPA security policy to generate dynamic WEP keys. When
-	 * using WPA, this should be set to 0 so that WPA state machine can
-	 * process the EAPOL-Key frames.
-	 */
-	int accept_802_1x_keys;
-
-#define EAPOL_REQUIRE_KEY_UNICAST BIT(0)
-#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1)
-	/**
-	 * required_keys - Which EAPOL-Key packets are required
-	 *
-	 * This variable determines which EAPOL-Key packets are required before
-	 * marking connection authenticated. This is a bit field of
-	 * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags.
-	 */
-	int required_keys;
-
-	/**
-	 * fast_reauth - Whether fast EAP reauthentication is enabled
-	 */
-	int fast_reauth;
-
-	/**
-	 * workaround - Whether EAP workarounds are enabled
-	 */
-	unsigned int workaround;
-
-	/**
-	 * eap_disabled - Whether EAP is disabled
-	 */
-	int eap_disabled;
-};
-
-struct eapol_sm;
-struct wpa_config_blob;
-
-/**
- * struct eapol_ctx - Global (for all networks) EAPOL state machine context
- */
-struct eapol_ctx {
-	/**
-	 * ctx - Pointer to arbitrary upper level context
-	 */
-	void *ctx;
-
-	/**
-	 * preauth - IEEE 802.11i/RSN pre-authentication
-	 *
-	 * This EAPOL state machine is used for IEEE 802.11i/RSN
-	 * pre-authentication
-	 */
-	int preauth;
-
-	/**
-	 * cb - Function to be called when EAPOL negotiation has been completed
-	 * @eapol: Pointer to EAPOL state machine data
-	 * @success: Whether the authentication was completed successfully
-	 * @ctx: Pointer to context data (cb_ctx)
-	 *
-	 * This optional callback function will be called when the EAPOL
-	 * authentication has been completed. This allows the owner of the
-	 * EAPOL state machine to process the key and terminate the EAPOL state
-	 * machine. Currently, this is used only in RSN pre-authentication.
-	 */
-	void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
-
-	/**
-	 * cb_ctx - Callback context for cb()
-	 */
-	void *cb_ctx;
-
-	/**
-	 * msg_ctx - Callback context for wpa_msg() calls
-	 */
-	void *msg_ctx;
-
-	/**
-	 * scard_ctx - Callback context for PC/SC scard_*() function calls
-	 *
-	 * This context can be updated with eapol_sm_register_scard_ctx().
-	 */
-	void *scard_ctx;
-
-	/**
-	 * eapol_send_ctx - Callback context for eapol_send() calls
-	 */
-	void *eapol_send_ctx;
-
-	/**
-	 * eapol_done_cb - Function to be called at successful completion
-	 * @ctx: Callback context (ctx)
-	 *
-	 * This function is called at the successful completion of EAPOL
-	 * authentication. If dynamic WEP keys are used, this is called only
-	 * after all the expected keys have been received.
-	 */
-	void (*eapol_done_cb)(void *ctx);
-
-	/**
-	 * eapol_send - Send EAPOL packets
-	 * @ctx: Callback context (eapol_send_ctx)
-	 * @type: EAPOL type (IEEE802_1X_TYPE_*)
-	 * @buf: Pointer to EAPOL payload
-	 * @len: Length of the EAPOL payload
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len);
-
-	/**
-	 * set_wep_key - Configure WEP keys
-	 * @ctx: Callback context (ctx)
-	 * @unicast: Non-zero = unicast, 0 = multicast/broadcast key
-	 * @keyidx: Key index (0..3)
-	 * @key: WEP key
-	 * @keylen: Length of the WEP key
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_wep_key)(void *ctx, int unicast, int keyidx,
-			   const u8 *key, size_t keylen);
-
-	/**
-	 * set_config_blob - Set or add a named configuration blob
-	 * @ctx: Callback context (ctx)
-	 * @blob: New value for the blob
-	 *
-	 * Adds a new configuration blob or replaces the current value of an
-	 * existing blob.
-	 */
-	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
-
-	/**
-	 * get_config_blob - Get a named configuration blob
-	 * @ctx: Callback context (ctx)
-	 * @name: Name of the blob
-	 * Returns: Pointer to blob data or %NULL if not found
-	 */
-	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
-							  const char *name);
-
-	/**
-	 * aborted_cached - Notify that cached PMK attempt was aborted
-	 * @ctx: Callback context (ctx)
-	 */
-	void (*aborted_cached)(void *ctx);
-
-	/**
-	 * opensc_engine_path - Path to the OpenSSL engine for opensc
-	 *
-	 * This is an OpenSSL specific configuration option for loading OpenSC
-	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
-	 */
-	const char *opensc_engine_path;
-
-	/**
-	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
-	 *
-	 * This is an OpenSSL specific configuration option for loading PKCS#11
-	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
-	 */
-	const char *pkcs11_engine_path;
-
-	/**
-	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
-	 *
-	 * This is an OpenSSL specific configuration option for configuring
-	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
-	 * module is not loaded.
-	 */
-	const char *pkcs11_module_path;
-
-	/**
-	 * wps - WPS context data
-	 *
-	 * This is only used by EAP-WSC and can be left %NULL if not available.
-	 */
-	struct wps_context *wps;
-
-	/**
-	 * eap_param_needed - Notify that EAP parameter is needed
-	 * @ctx: Callback context (ctx)
-	 * @field: Field name (e.g., "IDENTITY")
-	 * @txt: User readable text describing the required parameter
-	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
-				 const char *txt);
-
-	/**
-	 * port_cb - Set port authorized/unauthorized callback (optional)
-	 * @ctx: Callback context (ctx)
-	 * @authorized: Whether the supplicant port is now in authorized state
-	 */
-	void (*port_cb)(void *ctx, int authorized);
-};
-
-
-struct eap_peer_config;
-
-#ifdef IEEE8021X_EAPOL
-struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx);
-void eapol_sm_deinit(struct eapol_sm *sm);
-void eapol_sm_step(struct eapol_sm *sm);
-int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
-			int verbose);
-int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen);
-void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
-			int startPeriod, int maxStart);
-int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
-		      size_t len);
-void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
-void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
-void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
-void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
-void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
-void eapol_sm_notify_config(struct eapol_sm *sm,
-			    struct eap_peer_config *config,
-			    const struct eapol_config *conf);
-int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
-void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
-void eapol_sm_notify_cached(struct eapol_sm *sm);
-void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt);
-void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
-void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
-void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
-void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
-void eapol_sm_request_reauth(struct eapol_sm *sm);
-void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
-void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
-#else /* IEEE8021X_EAPOL */
-static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
-{
-	free(ctx);
-	return (struct eapol_sm *) 1;
-}
-static inline void eapol_sm_deinit(struct eapol_sm *sm)
-{
-}
-static inline void eapol_sm_step(struct eapol_sm *sm)
-{
-}
-static inline int eapol_sm_get_status(struct eapol_sm *sm, char *buf,
-				      size_t buflen, int verbose)
-{
-	return 0;
-}
-static inline int eapol_sm_get_mib(struct eapol_sm *sm, char *buf,
-				   size_t buflen)
-{
-	return 0;
-}
-static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod,
-				      int authPeriod, int startPeriod,
-				      int maxStart)
-{
-}
-static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
-				    const u8 *buf, size_t len)
-{
-	return 0;
-}
-static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
-{
-}
-static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm,
-					       Boolean enabled)
-{
-}
-static inline void eapol_sm_notify_portValid(struct eapol_sm *sm,
-					     Boolean valid)
-{
-}
-static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm,
-					       Boolean success)
-{
-}
-static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
-{
-}
-static inline void eapol_sm_notify_config(struct eapol_sm *sm,
-					  struct eap_peer_config *config,
-					  struct eapol_config *conf)
-{
-}
-static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
-{
-	return -1;
-}
-static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
-{
-}
-static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
-{
-}
-#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0)
-#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0)
-static inline void eapol_sm_notify_portControl(struct eapol_sm *sm,
-					       PortControl portControl)
-{
-}
-static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
-{
-}
-static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
-{
-}
-static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
-{
-}
-static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm,
-						       int in_eapol_sm)
-{
-}
-static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
-{
-}
-#endif /* IEEE8021X_EAPOL */
-
-#endif /* EAPOL_SUPP_SM_H */

Copied: vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h (from rev 9639, vendor/wpa/dist/src/eapol_supp/eapol_supp_sm.h)
===================================================================
--- vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h	                        (rev 0)
+++ vendor/wpa/2.0/src/eapol_supp/eapol_supp_sm.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,391 @@
+/*
+ * EAPOL supplicant state machines
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_SUPP_SM_H
+#define EAPOL_SUPP_SM_H
+
+#include "common/defs.h"
+
+typedef enum { Unauthorized, Authorized } PortStatus;
+typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
+
+/**
+ * struct eapol_config - Per network configuration for EAPOL state machines
+ */
+struct eapol_config {
+	/**
+	 * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames
+	 *
+	 * This variable should be set to 1 when using EAPOL state machines
+	 * with non-WPA security policy to generate dynamic WEP keys. When
+	 * using WPA, this should be set to 0 so that WPA state machine can
+	 * process the EAPOL-Key frames.
+	 */
+	int accept_802_1x_keys;
+
+#define EAPOL_REQUIRE_KEY_UNICAST BIT(0)
+#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1)
+	/**
+	 * required_keys - Which EAPOL-Key packets are required
+	 *
+	 * This variable determines which EAPOL-Key packets are required before
+	 * marking connection authenticated. This is a bit field of
+	 * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags.
+	 */
+	int required_keys;
+
+	/**
+	 * fast_reauth - Whether fast EAP reauthentication is enabled
+	 */
+	int fast_reauth;
+
+	/**
+	 * workaround - Whether EAP workarounds are enabled
+	 */
+	unsigned int workaround;
+
+	/**
+	 * eap_disabled - Whether EAP is disabled
+	 */
+	int eap_disabled;
+};
+
+struct eapol_sm;
+struct wpa_config_blob;
+
+/**
+ * struct eapol_ctx - Global (for all networks) EAPOL state machine context
+ */
+struct eapol_ctx {
+	/**
+	 * ctx - Pointer to arbitrary upper level context
+	 */
+	void *ctx;
+
+	/**
+	 * preauth - IEEE 802.11i/RSN pre-authentication
+	 *
+	 * This EAPOL state machine is used for IEEE 802.11i/RSN
+	 * pre-authentication
+	 */
+	int preauth;
+
+	/**
+	 * cb - Function to be called when EAPOL negotiation has been completed
+	 * @eapol: Pointer to EAPOL state machine data
+	 * @success: Whether the authentication was completed successfully
+	 * @ctx: Pointer to context data (cb_ctx)
+	 *
+	 * This optional callback function will be called when the EAPOL
+	 * authentication has been completed. This allows the owner of the
+	 * EAPOL state machine to process the key and terminate the EAPOL state
+	 * machine. Currently, this is used only in RSN pre-authentication.
+	 */
+	void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
+
+	/**
+	 * cb_ctx - Callback context for cb()
+	 */
+	void *cb_ctx;
+
+	/**
+	 * msg_ctx - Callback context for wpa_msg() calls
+	 */
+	void *msg_ctx;
+
+	/**
+	 * scard_ctx - Callback context for PC/SC scard_*() function calls
+	 *
+	 * This context can be updated with eapol_sm_register_scard_ctx().
+	 */
+	void *scard_ctx;
+
+	/**
+	 * eapol_send_ctx - Callback context for eapol_send() calls
+	 */
+	void *eapol_send_ctx;
+
+	/**
+	 * eapol_done_cb - Function to be called at successful completion
+	 * @ctx: Callback context (ctx)
+	 *
+	 * This function is called at the successful completion of EAPOL
+	 * authentication. If dynamic WEP keys are used, this is called only
+	 * after all the expected keys have been received.
+	 */
+	void (*eapol_done_cb)(void *ctx);
+
+	/**
+	 * eapol_send - Send EAPOL packets
+	 * @ctx: Callback context (eapol_send_ctx)
+	 * @type: EAPOL type (IEEE802_1X_TYPE_*)
+	 * @buf: Pointer to EAPOL payload
+	 * @len: Length of the EAPOL payload
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len);
+
+	/**
+	 * set_wep_key - Configure WEP keys
+	 * @ctx: Callback context (ctx)
+	 * @unicast: Non-zero = unicast, 0 = multicast/broadcast key
+	 * @keyidx: Key index (0..3)
+	 * @key: WEP key
+	 * @keylen: Length of the WEP key
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_wep_key)(void *ctx, int unicast, int keyidx,
+			   const u8 *key, size_t keylen);
+
+	/**
+	 * set_config_blob - Set or add a named configuration blob
+	 * @ctx: Callback context (ctx)
+	 * @blob: New value for the blob
+	 *
+	 * Adds a new configuration blob or replaces the current value of an
+	 * existing blob.
+	 */
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+	/**
+	 * get_config_blob - Get a named configuration blob
+	 * @ctx: Callback context (ctx)
+	 * @name: Name of the blob
+	 * Returns: Pointer to blob data or %NULL if not found
+	 */
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+
+	/**
+	 * aborted_cached - Notify that cached PMK attempt was aborted
+	 * @ctx: Callback context (ctx)
+	 */
+	void (*aborted_cached)(void *ctx);
+
+	/**
+	 * opensc_engine_path - Path to the OpenSSL engine for opensc
+	 *
+	 * This is an OpenSSL specific configuration option for loading OpenSC
+	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+	 */
+	const char *opensc_engine_path;
+
+	/**
+	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+	 *
+	 * This is an OpenSSL specific configuration option for loading PKCS#11
+	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+	 */
+	const char *pkcs11_engine_path;
+
+	/**
+	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+	 *
+	 * This is an OpenSSL specific configuration option for configuring
+	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+	 * module is not loaded.
+	 */
+	const char *pkcs11_module_path;
+
+	/**
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * eap_param_needed - Notify that EAP parameter is needed
+	 * @ctx: Callback context (ctx)
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
+	 * @txt: User readable text describing the required parameter
+	 */
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
+				 const char *txt);
+
+	/**
+	 * port_cb - Set port authorized/unauthorized callback (optional)
+	 * @ctx: Callback context (ctx)
+	 * @authorized: Whether the supplicant port is now in authorized state
+	 */
+	void (*port_cb)(void *ctx, int authorized);
+
+	/**
+	 * cert_cb - Notification of a peer certificate
+	 * @ctx: Callback context (ctx)
+	 * @depth: Depth in certificate chain (0 = server)
+	 * @subject: Subject of the peer certificate
+	 * @cert_hash: SHA-256 hash of the certificate
+	 * @cert: Peer certificate
+	 */
+	void (*cert_cb)(void *ctx, int depth, const char *subject,
+			const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
+
+	/**
+	 * status_cb - Notification of a change in EAP status
+	 * @ctx: Callback context (ctx)
+	 * @status: Step in the process of EAP authentication
+	 * @parameter: Step-specific parameter, e.g., EAP method name
+	 */
+	void (*status_cb)(void *ctx, const char *status,
+			  const char *parameter);
+
+	/**
+	 * set_anon_id - Set or add anonymous identity
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @id: Anonymous identity (e.g., EAP-SIM pseudonym)
+	 * @len: Length of anonymous identity in octets
+	 */
+	void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+};
+
+
+struct eap_peer_config;
+struct ext_password_data;
+
+#ifdef IEEE8021X_EAPOL
+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx);
+void eapol_sm_deinit(struct eapol_sm *sm);
+void eapol_sm_step(struct eapol_sm *sm);
+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
+			int verbose);
+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen);
+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
+			int startPeriod, int maxStart);
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+		      size_t len);
+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
+void eapol_sm_notify_config(struct eapol_sm *sm,
+			    struct eap_peer_config *config,
+			    const struct eapol_config *conf);
+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
+void eapol_sm_notify_cached(struct eapol_sm *sm);
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt);
+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
+void eapol_sm_request_reauth(struct eapol_sm *sm);
+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
+const char * eapol_sm_get_method_name(struct eapol_sm *sm);
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+			     struct ext_password_data *ext);
+int eapol_sm_failed(struct eapol_sm *sm);
+#else /* IEEE8021X_EAPOL */
+static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
+{
+	free(ctx);
+	return (struct eapol_sm *) 1;
+}
+static inline void eapol_sm_deinit(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_step(struct eapol_sm *sm)
+{
+}
+static inline int eapol_sm_get_status(struct eapol_sm *sm, char *buf,
+				      size_t buflen, int verbose)
+{
+	return 0;
+}
+static inline int eapol_sm_get_mib(struct eapol_sm *sm, char *buf,
+				   size_t buflen)
+{
+	return 0;
+}
+static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod,
+				      int authPeriod, int startPeriod,
+				      int maxStart)
+{
+}
+static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
+				    const u8 *buf, size_t len)
+{
+	return 0;
+}
+static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm,
+					       Boolean enabled)
+{
+}
+static inline void eapol_sm_notify_portValid(struct eapol_sm *sm,
+					     Boolean valid)
+{
+}
+static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm,
+					       Boolean success)
+{
+}
+static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+{
+}
+static inline void eapol_sm_notify_config(struct eapol_sm *sm,
+					  struct eap_peer_config *config,
+					  struct eapol_config *conf)
+{
+}
+static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
+{
+	return -1;
+}
+static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+{
+}
+static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
+{
+}
+#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0)
+#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0)
+static inline void eapol_sm_notify_portControl(struct eapol_sm *sm,
+					       PortControl portControl)
+{
+}
+static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm,
+						       int in_eapol_sm)
+{
+}
+static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+}
+static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+	return NULL;
+}
+static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+					   struct ext_password_data *ext)
+{
+}
+static inline int eapol_sm_failed(struct eapol_sm *sm)
+{
+	return 0;
+}
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* EAPOL_SUPP_SM_H */

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet.h
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,130 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet interface definition
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file defines an interface for layer 2 (link layer) packet sending and
- * receiving. l2_packet_linux.c is one implementation for such a layer 2
- * implementation using Linux packet sockets and l2_packet_pcap.c another one
- * using libpcap and libdnet. When porting %wpa_supplicant to other operating
- * systems, a new l2_packet implementation may need to be added.
- */
-
-#ifndef L2_PACKET_H
-#define L2_PACKET_H
-
-/**
- * struct l2_packet_data - Internal l2_packet data structure
- *
- * This structure is used by the l2_packet implementation to store its private
- * data. Other files use a pointer to this data when calling the l2_packet
- * functions, but the contents of this structure should not be used directly
- * outside l2_packet implementation.
- */
-struct l2_packet_data;
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct l2_ethhdr {
-	u8 h_dest[ETH_ALEN];
-	u8 h_source[ETH_ALEN];
-	be16 h_proto;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-/**
- * l2_packet_init - Initialize l2_packet interface
- * @ifname: Interface name
- * @own_addr: Optional own MAC address if available from driver interface or
- *	%NULL if not available
- * @protocol: Ethernet protocol number in host byte order
- * @rx_callback: Callback function that will be called for each received packet
- * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
- * @l2_hdr: 1 = include layer 2 header, 0 = do not include header
- * Returns: Pointer to internal data or %NULL on failure
- *
- * rx_callback function will be called with src_addr pointing to the source
- * address (MAC address) of the the packet. If l2_hdr is set to 0, buf
- * points to len bytes of the payload after the layer 2 header and similarly,
- * TX buffers start with payload. This behavior can be changed by setting
- * l2_hdr=1 to include the layer 2 header in the data buffer.
- */
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr);
-
-/**
- * l2_packet_deinit - Deinitialize l2_packet interface
- * @l2: Pointer to internal l2_packet data from l2_packet_init()
- */
-void l2_packet_deinit(struct l2_packet_data *l2);
-
-/**
- * l2_packet_get_own_addr - Get own layer 2 address
- * @l2: Pointer to internal l2_packet data from l2_packet_init()
- * @addr: Buffer for the own address (6 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
-
-/**
- * l2_packet_send - Send a packet
- * @l2: Pointer to internal l2_packet data from l2_packet_init()
- * @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
- * @proto: Protocol/ethertype for the packet in host byte order (only used if
- * l2_hdr == 0)
- * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
- * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
- * is included.
- * @len: Length of the buffer (including l2 header only if l2_hdr == 1)
- * Returns: >=0 on success, <0 on failure
- */
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len);
-
-/**
- * l2_packet_get_ip_addr - Get the current IP address from the interface
- * @l2: Pointer to internal l2_packet data from l2_packet_init()
- * @buf: Buffer for the IP address in text format
- * @len: Maximum buffer length
- * Returns: 0 on success, -1 on failure
- *
- * This function can be used to get the current IP address from the interface
- * bound to the l2_packet. This is mainly for status information and the IP
- * address will be stored as an ASCII string. This function is not essential
- * for %wpa_supplicant operation, so full implementation is not required.
- * l2_packet implementation will need to define the function, but it can return
- * -1 if the IP address information is not available.
- */
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
-
-
-/**
- * l2_packet_notify_auth_start - Notify l2_packet about start of authentication
- * @l2: Pointer to internal l2_packet data from l2_packet_init()
- *
- * This function is called when authentication is expected to start, e.g., when
- * association has been completed, in order to prepare l2_packet implementation
- * for EAPOL frames. This function is used mainly if the l2_packet code needs
- * to do polling in which case it can increasing polling frequency. This can
- * also be an empty function if the l2_packet implementation does not benefit
- * from knowing about the starting authentication.
- */
-void l2_packet_notify_auth_start(struct l2_packet_data *l2);
-
-#endif /* L2_PACKET_H */

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet.h (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet.h)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet.h	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,124 @@
+/*
+ * WPA Supplicant - Layer2 packet interface definition
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines an interface for layer 2 (link layer) packet sending and
+ * receiving. l2_packet_linux.c is one implementation for such a layer 2
+ * implementation using Linux packet sockets and l2_packet_pcap.c another one
+ * using libpcap and libdnet. When porting %wpa_supplicant to other operating
+ * systems, a new l2_packet implementation may need to be added.
+ */
+
+#ifndef L2_PACKET_H
+#define L2_PACKET_H
+
+/**
+ * struct l2_packet_data - Internal l2_packet data structure
+ *
+ * This structure is used by the l2_packet implementation to store its private
+ * data. Other files use a pointer to this data when calling the l2_packet
+ * functions, but the contents of this structure should not be used directly
+ * outside l2_packet implementation.
+ */
+struct l2_packet_data;
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct l2_ethhdr {
+	u8 h_dest[ETH_ALEN];
+	u8 h_source[ETH_ALEN];
+	be16 h_proto;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+/**
+ * l2_packet_init - Initialize l2_packet interface
+ * @ifname: Interface name
+ * @own_addr: Optional own MAC address if available from driver interface or
+ *	%NULL if not available
+ * @protocol: Ethernet protocol number in host byte order
+ * @rx_callback: Callback function that will be called for each received packet
+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
+ * @l2_hdr: 1 = include layer 2 header, 0 = do not include header
+ * Returns: Pointer to internal data or %NULL on failure
+ *
+ * rx_callback function will be called with src_addr pointing to the source
+ * address (MAC address) of the the packet. If l2_hdr is set to 0, buf
+ * points to len bytes of the payload after the layer 2 header and similarly,
+ * TX buffers start with payload. This behavior can be changed by setting
+ * l2_hdr=1 to include the layer 2 header in the data buffer.
+ */
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr);
+
+/**
+ * l2_packet_deinit - Deinitialize l2_packet interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ */
+void l2_packet_deinit(struct l2_packet_data *l2);
+
+/**
+ * l2_packet_get_own_addr - Get own layer 2 address
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @addr: Buffer for the own address (6 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
+
+/**
+ * l2_packet_send - Send a packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
+ * @proto: Protocol/ethertype for the packet in host byte order (only used if
+ * l2_hdr == 0)
+ * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
+ * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
+ * is included.
+ * @len: Length of the buffer (including l2 header only if l2_hdr == 1)
+ * Returns: >=0 on success, <0 on failure
+ */
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len);
+
+/**
+ * l2_packet_get_ip_addr - Get the current IP address from the interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @buf: Buffer for the IP address in text format
+ * @len: Maximum buffer length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to get the current IP address from the interface
+ * bound to the l2_packet. This is mainly for status information and the IP
+ * address will be stored as an ASCII string. This function is not essential
+ * for %wpa_supplicant operation, so full implementation is not required.
+ * l2_packet implementation will need to define the function, but it can return
+ * -1 if the IP address information is not available.
+ */
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
+
+
+/**
+ * l2_packet_notify_auth_start - Notify l2_packet about start of authentication
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ *
+ * This function is called when authentication is expected to start, e.g., when
+ * association has been completed, in order to prepare l2_packet implementation
+ * for EAPOL frames. This function is used mainly if the l2_packet code needs
+ * to do polling in which case it can increasing polling frequency. This can
+ * also be an empty function if the l2_packet implementation does not benefit
+ * from knowing about the starting authentication.
+ */
+void l2_packet_notify_auth_start(struct l2_packet_data *l2);
+
+#endif /* L2_PACKET_H */

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_freebsd.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,285 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with FreeBSD
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2005, Sam Leffler <sam at errno.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#if defined(__APPLE__) || defined(__GLIBC__)
-#include <net/bpf.h>
-#endif /* __APPLE__ */
-#include <pcap.h>
-
-#include <sys/ioctl.h>
-#include <sys/sysctl.h>
-
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/route.h>
-#include <netinet/in.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-struct l2_packet_data {
-	pcap_t *pcap;
-	char ifname[100];
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
-		     * buffers */
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	if (!l2->l2_hdr) {
-		int ret;
-		struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len);
-		if (eth == NULL)
-			return -1;
-		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
-		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
-		eth->h_proto = htons(proto);
-		os_memcpy(eth + 1, buf, len);
-		ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth));
-		os_free(eth);
-		return ret;
-	} else
-		return pcap_inject(l2->pcap, buf, len);
-}
-
-
-static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	pcap_t *pcap = sock_ctx;
-	struct pcap_pkthdr hdr;
-	const u_char *packet;
-	struct l2_ethhdr *ethhdr;
-	unsigned char *buf;
-	size_t len;
-
-	packet = pcap_next(pcap, &hdr);
-
-	if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
-		return;
-
-	ethhdr = (struct l2_ethhdr *) packet;
-	if (l2->l2_hdr) {
-		buf = (unsigned char *) ethhdr;
-		len = hdr.caplen;
-	} else {
-		buf = (unsigned char *) (ethhdr + 1);
-		len = hdr.caplen - sizeof(*ethhdr);
-	}
-	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
-}
-
-
-static int l2_packet_init_libpcap(struct l2_packet_data *l2,
-				  unsigned short protocol)
-{
-	bpf_u_int32 pcap_maskp, pcap_netp;
-	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
-	struct bpf_program pcap_fp;
-
-	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
-	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
-	if (l2->pcap == NULL) {
-		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
-		fprintf(stderr, "ifname='%s'\n", l2->ifname);
-		return -1;
-	}
-	if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
-	    pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
-		fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
-			pcap_geterr(l2->pcap));
-		return -1;
-	}
-	os_snprintf(pcap_filter, sizeof(pcap_filter),
-		    "not ether src " MACSTR " and "
-		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
-		    "ether proto 0x%x",
-		    MAC2STR(l2->own_addr), /* do not receive own packets */
-		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
-		    protocol);
-	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
-		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
-		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	pcap_freecode(&pcap_fp);
-	/*
-	 * When libpcap uses BPF we must enable "immediate mode" to
-	 * receive frames right away; otherwise the system may
-	 * buffer them for us.
-	 */
-	{
-		unsigned int on = 1;
-		if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
-			fprintf(stderr, "%s: cannot enable immediate mode on "
-				"interface %s: %s\n",
-				__func__, l2->ifname, strerror(errno));
-			/* XXX should we fail? */
-		}
-	}
-
-	eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
-				 l2_packet_receive, l2, l2->pcap);
-
-	return 0;
-}
-
-
-static int eth_get(const char *device, u8 ea[ETH_ALEN])
-{
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	u_char *p, *buf;
-	size_t len;
-	int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-	if ((buf = os_malloc(len)) == NULL)
-		return -1;
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		os_free(buf);
-		return -1;
-	}
-	for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
-		ifm = (struct if_msghdr *)p;
-		sdl = (struct sockaddr_dl *)(ifm + 1);
-		if (ifm->ifm_type != RTM_IFINFO ||
-		    (ifm->ifm_addrs & RTA_IFP) == 0)
-			continue;
-		if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
-		    os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
-			continue;
-		os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
-		break;
-	}
-	os_free(buf);
-
-	if (p >= buf + len) {
-		errno = ESRCH;
-		return -1;
-	}
-	return 0;
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-	if (eth_get(l2->ifname, l2->own_addr) < 0) {
-		fprintf(stderr, "Failed to get link-level address for "
-			"interface '%s'.\n", l2->ifname);
-		os_free(l2);
-		return NULL;
-	}
-
-	if (l2_packet_init_libpcap(l2, protocol)) {
-		os_free(l2);
-		return NULL;
-	}
-
-	return l2;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 != NULL) {
-		if (l2->pcap) {
-			eloop_unregister_read_sock(
-				pcap_get_selectable_fd(l2->pcap));
-			pcap_close(l2->pcap);
-		}
-		os_free(l2);
-	}
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	pcap_if_t *devs, *dev;
-	struct pcap_addr *addr;
-	struct sockaddr_in *saddr;
-	int found = 0;
-	char err[PCAP_ERRBUF_SIZE + 1];
-
-	if (pcap_findalldevs(&devs, err) < 0) {
-		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
-		return -1;
-	}
-
-	for (dev = devs; dev && !found; dev = dev->next) {
-		if (os_strcmp(dev->name, l2->ifname) != 0)
-			continue;
-
-		addr = dev->addresses;
-		while (addr) {
-			saddr = (struct sockaddr_in *) addr->addr;
-			if (saddr && saddr->sin_family == AF_INET) {
-				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
-					   len);
-				found = 1;
-				break;
-			}
-			addr = addr->next;
-		}
-	}
-
-	pcap_freealldevs(devs);
-
-	return found ? 0 : -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_freebsd.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_freebsd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,310 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with FreeBSD
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2005, Sam Leffler <sam at errno.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#if defined(__APPLE__) || defined(__GLIBC__)
+#include <net/bpf.h>
+#endif /* __APPLE__ */
+#include <pcap.h>
+
+#include <sys/ioctl.h>
+#ifdef __sun__
+#include <libdlpi.h>
+#else /* __sun__ */
+#include <sys/sysctl.h>
+#endif /* __sun__ */
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct l2_packet_data {
+	pcap_t *pcap;
+	char ifname[100];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+		     * buffers */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	if (!l2->l2_hdr) {
+		int ret;
+		struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len);
+		if (eth == NULL)
+			return -1;
+		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+		eth->h_proto = htons(proto);
+		os_memcpy(eth + 1, buf, len);
+		ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth));
+		os_free(eth);
+		return ret;
+	} else
+		return pcap_inject(l2->pcap, buf, len);
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	pcap_t *pcap = sock_ctx;
+	struct pcap_pkthdr hdr;
+	const u_char *packet;
+	struct l2_ethhdr *ethhdr;
+	unsigned char *buf;
+	size_t len;
+
+	packet = pcap_next(pcap, &hdr);
+
+	if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+		return;
+
+	ethhdr = (struct l2_ethhdr *) packet;
+	if (l2->l2_hdr) {
+		buf = (unsigned char *) ethhdr;
+		len = hdr.caplen;
+	} else {
+		buf = (unsigned char *) (ethhdr + 1);
+		len = hdr.caplen - sizeof(*ethhdr);
+	}
+	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+				  unsigned short protocol)
+{
+	bpf_u_int32 pcap_maskp, pcap_netp;
+	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+	struct bpf_program pcap_fp;
+
+	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
+	if (l2->pcap == NULL) {
+		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+		fprintf(stderr, "ifname='%s'\n", l2->ifname);
+		return -1;
+	}
+	if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
+	    pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
+		fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
+			pcap_geterr(l2->pcap));
+		return -1;
+	}
+	os_snprintf(pcap_filter, sizeof(pcap_filter),
+		    "not ether src " MACSTR " and "
+		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+		    "ether proto 0x%x",
+		    MAC2STR(l2->own_addr), /* do not receive own packets */
+		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+		    protocol);
+	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	pcap_freecode(&pcap_fp);
+#ifndef __sun__
+	/*
+	 * When libpcap uses BPF we must enable "immediate mode" to
+	 * receive frames right away; otherwise the system may
+	 * buffer them for us.
+	 */
+	{
+		unsigned int on = 1;
+		if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
+			fprintf(stderr, "%s: cannot enable immediate mode on "
+				"interface %s: %s\n",
+				__func__, l2->ifname, strerror(errno));
+			/* XXX should we fail? */
+		}
+	}
+#endif /* __sun__ */
+
+	eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+				 l2_packet_receive, l2, l2->pcap);
+
+	return 0;
+}
+
+
+static int eth_get(const char *device, u8 ea[ETH_ALEN])
+{
+#ifdef __sun__
+	dlpi_handle_t dh;
+	u32 physaddrlen = DLPI_PHYSADDR_MAX;
+	u8 physaddr[DLPI_PHYSADDR_MAX];
+	int retval;
+
+	retval = dlpi_open(device, &dh, 0);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "dlpi_open error: %s",
+			   dlpi_strerror(retval));
+		return -1;
+	}
+
+	retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr,
+				   &physaddrlen);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "dlpi_get_physaddr error: %s",
+			   dlpi_strerror(retval));
+		dlpi_close(dh);
+		return -1;
+	}
+	os_memcpy(ea, physaddr, ETH_ALEN);
+	dlpi_close(dh);
+#else /* __sun__ */
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	u_char *p, *buf;
+	size_t len;
+	int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+	if ((buf = os_malloc(len)) == NULL)
+		return -1;
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		os_free(buf);
+		return -1;
+	}
+	for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
+		ifm = (struct if_msghdr *)p;
+		sdl = (struct sockaddr_dl *)(ifm + 1);
+		if (ifm->ifm_type != RTM_IFINFO ||
+		    (ifm->ifm_addrs & RTA_IFP) == 0)
+			continue;
+		if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
+		    os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
+			continue;
+		os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
+		break;
+	}
+	os_free(buf);
+
+	if (p >= buf + len) {
+		errno = ESRCH;
+		return -1;
+	}
+#endif /* __sun__ */
+	return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	if (eth_get(l2->ifname, l2->own_addr) < 0) {
+		fprintf(stderr, "Failed to get link-level address for "
+			"interface '%s'.\n", l2->ifname);
+		os_free(l2);
+		return NULL;
+	}
+
+	if (l2_packet_init_libpcap(l2, protocol)) {
+		os_free(l2);
+		return NULL;
+	}
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 != NULL) {
+		if (l2->pcap) {
+			eloop_unregister_read_sock(
+				pcap_get_selectable_fd(l2->pcap));
+			pcap_close(l2->pcap);
+		}
+		os_free(l2);
+	}
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	pcap_if_t *devs, *dev;
+	struct pcap_addr *addr;
+	struct sockaddr_in *saddr;
+	int found = 0;
+	char err[PCAP_ERRBUF_SIZE + 1];
+
+	if (pcap_findalldevs(&devs, err) < 0) {
+		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+		return -1;
+	}
+
+	for (dev = devs; dev && !found; dev = dev->next) {
+		if (os_strcmp(dev->name, l2->ifname) != 0)
+			continue;
+
+		addr = dev->addresses;
+		while (addr) {
+			saddr = (struct sockaddr_in *) addr->addr;
+			if (saddr && saddr->sin_family == AF_INET) {
+				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+					   len);
+				found = 1;
+				break;
+			}
+			addr = addr->next;
+		}
+	}
+
+	pcap_freealldevs(devs);
+
+	return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_linux.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,200 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with Linux packet sockets
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-#include <netpacket/packet.h>
-#include <net/if.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-
-struct l2_packet_data {
-	int fd; /* packet socket for EAPOL frames */
-	char ifname[IFNAMSIZ + 1];
-	int ifindex;
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
-		     * buffers */
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	int ret;
-	if (l2 == NULL)
-		return -1;
-	if (l2->l2_hdr) {
-		ret = send(l2->fd, buf, len, 0);
-		if (ret < 0)
-			perror("l2_packet_send - send");
-	} else {
-		struct sockaddr_ll ll;
-		os_memset(&ll, 0, sizeof(ll));
-		ll.sll_family = AF_PACKET;
-		ll.sll_ifindex = l2->ifindex;
-		ll.sll_protocol = htons(proto);
-		ll.sll_halen = ETH_ALEN;
-		os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
-		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
-			     sizeof(ll));
-		if (ret < 0)
-			perror("l2_packet_send - sendto");
-	}
-	return ret;
-}
-
-
-static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	u8 buf[2300];
-	int res;
-	struct sockaddr_ll ll;
-	socklen_t fromlen;
-
-	os_memset(&ll, 0, sizeof(ll));
-	fromlen = sizeof(ll);
-	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
-		       &fromlen);
-	if (res < 0) {
-		perror("l2_packet_receive - recvfrom");
-		return;
-	}
-
-	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-	struct ifreq ifr;
-	struct sockaddr_ll ll;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-	l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
-			htons(protocol));
-	if (l2->fd < 0) {
-		perror("socket(PF_PACKET)");
-		os_free(l2);
-		return NULL;
-	}
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
-	if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
-		perror("ioctl[SIOCGIFINDEX]");
-		close(l2->fd);
-		os_free(l2);
-		return NULL;
-	}
-	l2->ifindex = ifr.ifr_ifindex;
-
-	os_memset(&ll, 0, sizeof(ll));
-	ll.sll_family = PF_PACKET;
-	ll.sll_ifindex = ifr.ifr_ifindex;
-	ll.sll_protocol = htons(protocol);
-	if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("bind[PF_PACKET]");
-		close(l2->fd);
-		os_free(l2);
-		return NULL;
-	}
-
-	if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
-		perror("ioctl[SIOCGIFHWADDR]");
-		close(l2->fd);
-		os_free(l2);
-		return NULL;
-	}
-	os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-
-	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
-
-	return l2;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	if (l2->fd >= 0) {
-		eloop_unregister_read_sock(l2->fd);
-		close(l2->fd);
-	}
-		
-	os_free(l2);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	int s;
-	struct ifreq ifr;
-	struct sockaddr_in *saddr;
-	size_t res;
-
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket");
-		return -1;
-	}
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
-	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
-		if (errno != EADDRNOTAVAIL)
-			perror("ioctl[SIOCGIFADDR]");
-		close(s);
-		return -1;
-	}
-	close(s);
-	saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
-	if (saddr->sin_family != AF_INET)
-		return -1;
-	res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
-	if (res >= len)
-		return -1;
-	return 0;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_linux.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_linux.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,204 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Linux packet sockets
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <netpacket/packet.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+	int fd; /* packet socket for EAPOL frames */
+	char ifname[IFNAMSIZ + 1];
+	int ifindex;
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+		     * buffers */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	int ret;
+	if (l2 == NULL)
+		return -1;
+	if (l2->l2_hdr) {
+		ret = send(l2->fd, buf, len, 0);
+		if (ret < 0)
+			wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
+				   strerror(errno));
+	} else {
+		struct sockaddr_ll ll;
+		os_memset(&ll, 0, sizeof(ll));
+		ll.sll_family = AF_PACKET;
+		ll.sll_ifindex = l2->ifindex;
+		ll.sll_protocol = htons(proto);
+		ll.sll_halen = ETH_ALEN;
+		os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
+		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
+			     sizeof(ll));
+		if (ret < 0) {
+			wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
+				   strerror(errno));
+		}
+	}
+	return ret;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	u8 buf[2300];
+	int res;
+	struct sockaddr_ll ll;
+	socklen_t fromlen;
+
+	os_memset(&ll, 0, sizeof(ll));
+	fromlen = sizeof(ll);
+	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
+		       &fromlen);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s",
+			   strerror(errno));
+		return;
+	}
+
+	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+	struct ifreq ifr;
+	struct sockaddr_ll ll;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
+			htons(protocol));
+	if (l2->fd < 0) {
+		wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s",
+			   __func__, strerror(errno));
+		os_free(l2);
+		return NULL;
+	}
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+	if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
+		wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s",
+			   __func__, strerror(errno));
+		close(l2->fd);
+		os_free(l2);
+		return NULL;
+	}
+	l2->ifindex = ifr.ifr_ifindex;
+
+	os_memset(&ll, 0, sizeof(ll));
+	ll.sll_family = PF_PACKET;
+	ll.sll_ifindex = ifr.ifr_ifindex;
+	ll.sll_protocol = htons(protocol);
+	if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
+			   __func__, strerror(errno));
+		close(l2->fd);
+		os_free(l2);
+		return NULL;
+	}
+
+	if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
+		wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s",
+			   __func__, strerror(errno));
+		close(l2->fd);
+		os_free(l2);
+		return NULL;
+	}
+	os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	if (l2->fd >= 0) {
+		eloop_unregister_read_sock(l2->fd);
+		close(l2->fd);
+	}
+		
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	int s;
+	struct ifreq ifr;
+	struct sockaddr_in *saddr;
+	size_t res;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		wpa_printf(MSG_ERROR, "%s: socket: %s",
+			   __func__, strerror(errno));
+		return -1;
+	}
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+	if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+		if (errno != EADDRNOTAVAIL)
+			wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s",
+				   __func__, strerror(errno));
+		close(s);
+		return -1;
+	}
+	close(s);
+	saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
+	if (saddr->sin_family != AF_INET)
+		return -1;
+	res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
+	if (res >= len)
+		return -1;
+	return 0;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_ndis.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,522 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This implementation requires Windows specific event loop implementation,
- * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with
- * driver_ndis.c, so only that driver interface can be used and
- * CONFIG_USE_NDISUIO must be defined.
- *
- * WinXP version of the code uses overlapped I/O and a single threaded design
- * with callback functions from I/O code. WinCE version uses a separate RX
- * thread that blocks on ReadFile() whenever the media status is connected.
- */
-
-#include "includes.h"
-#include <winsock2.h>
-#include <ntddndis.h>
-
-#ifdef _WIN32_WCE
-#include <winioctl.h>
-#include <nuiouser.h>
-#endif /* _WIN32_WCE */
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-#ifndef _WIN32_WCE
-/* from nuiouser.h */
-#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
-#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
-	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
-#define IOCTL_NDISUIO_SET_ETHER_TYPE \
-	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-#endif /* _WIN32_WCE */
-
-/* From driver_ndis.c to shared the handle to NDISUIO */
-HANDLE driver_ndis_get_ndisuio_handle(void);
-
-/*
- * NDISUIO supports filtering of only one ethertype at the time, so we must
- * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth
- * whenever wpa_supplicant is trying to pre-authenticate and then switching
- * back to EAPOL when pre-authentication has been completed.
- */
-
-struct l2_packet_data;
-
-struct l2_packet_ndisuio_global {
-	int refcount;
-	unsigned short first_proto;
-	struct l2_packet_data *l2[2];
-#ifdef _WIN32_WCE
-	HANDLE rx_thread;
-	HANDLE stop_request;
-	HANDLE ready_for_read;
-	HANDLE rx_processed;
-#endif /* _WIN32_WCE */
-};
-
-static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;
-
-struct l2_packet_data {
-	char ifname[100];
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
-		     * rx_callback and l2_packet_send() */
-	HANDLE rx_avail;
-#ifndef _WIN32_WCE
-	OVERLAPPED rx_overlapped;
-#endif /* _WIN32_WCE */
-	u8 rx_buf[1514];
-	DWORD rx_written;
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	BOOL res;
-	DWORD written;
-	struct l2_ethhdr *eth;
-#ifndef _WIN32_WCE
-	OVERLAPPED overlapped;
-#endif /* _WIN32_WCE */
-	OVERLAPPED *o;
-
-	if (l2 == NULL)
-		return -1;
-
-#ifdef _WIN32_WCE
-	o = NULL;
-#else /* _WIN32_WCE */
-	os_memset(&overlapped, 0, sizeof(overlapped));
-	o = &overlapped;
-#endif /* _WIN32_WCE */
-
-	if (l2->l2_hdr) {
-		res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,
-				&written, o);
-	} else {
-		size_t mlen = sizeof(*eth) + len;
-		eth = os_malloc(mlen);
-		if (eth == NULL)
-			return -1;
-
-		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
-		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
-		eth->h_proto = htons(proto);
-		os_memcpy(eth + 1, buf, len);
-		res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,
-				&written, o);
-		os_free(eth);
-	}
-
-	if (!res) {
-		DWORD err = GetLastError();
-#ifndef _WIN32_WCE
-		if (err == ERROR_IO_PENDING) {
-			wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending "
-				   "write to complete");
-			res = GetOverlappedResult(
-				driver_ndis_get_ndisuio_handle(), &overlapped,
-				&written, TRUE);
-			if (!res) {
-				wpa_printf(MSG_DEBUG, "L2(NDISUIO): "
-					   "GetOverlappedResult failed: %d",
-					   (int) GetLastError());
-				return -1;
-			}
-			return 0;
-		}
-#endif /* _WIN32_WCE */
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",
-			   (int) GetLastError());
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void l2_packet_callback(struct l2_packet_data *l2);
-
-#ifdef _WIN32_WCE
-static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2)
-{
-	HANDLE handles[2];
-
-	wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");
-	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
-		      sizeof(l2->rx_buf), &l2->rx_written, NULL)) {
-		DWORD err = GetLastError();
-		wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "
-			   "%d", (int) err);
-		/*
-		 * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED
-		 * error whenever the connection is not up. Yield the thread to
-		 * avoid triggering a busy loop. Connection event should stop
-		 * us from looping for long, but we need to allow enough CPU
-		 * for the main thread to process the media disconnection.
-		 */
-		Sleep(100);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",
-		   (int) l2->rx_written);
-
-	/*
-	 * Notify the main thread about the availability of a frame and wait
-	 * for the frame to be processed.
-	 */
-	SetEvent(l2->rx_avail);
-	handles[0] = l2_ndisuio_global->stop_request;
-	handles[1] = l2_ndisuio_global->rx_processed;
-	WaitForMultipleObjects(2, handles, FALSE, INFINITE);
-	ResetEvent(l2_ndisuio_global->rx_processed);
-}
-
-
-static DWORD WINAPI l2_packet_rx_thread(LPVOID arg)
-{
-	struct l2_packet_data *l2 = arg;
-	DWORD res;
-	HANDLE handles[2];
-	int run = 1;
-
-	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");
-	handles[0] = l2_ndisuio_global->stop_request;
-	handles[1] = l2_ndisuio_global->ready_for_read;
-
-	/*
-	 * Unfortunately, NDISUIO on WinCE does not seem to support waiting
-	 * on the handle. There do not seem to be anything else that we could
-	 * wait for either. If one were to modify NDISUIO to set a named event
-	 * whenever packets are available, this event could be used here to
-	 * avoid having to poll for new packets or we could even move to use a
-	 * single threaded design.
-	 *
-	 * In addition, NDISUIO on WinCE is returning
-	 * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while
-	 * the adapter is not in connected state. For now, we are just using a
-	 * local event to allow ReadFile calls only after having received NDIS
-	 * media connect event. This event could be easily converted to handle
-	 * another event if the protocol driver is replaced with somewhat more
-	 * useful design.
-	 */
-
-	while (l2_ndisuio_global && run) {
-		res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
-		switch (res) {
-		case WAIT_OBJECT_0:
-			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "
-				   "request to stop RX thread");
-			run = 0;
-			break;
-		case WAIT_OBJECT_0 + 1:
-			l2_packet_rx_thread_try_read(l2);
-			break;
-		case WAIT_FAILED:
-		default:
-			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "
-				   "WaitForMultipleObjects failed: %d",
-				   (int) GetLastError());
-			run = 0;
-			break;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");
-
-	return 0;
-}
-#else /* _WIN32_WCE */
-static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive)
-{
-	os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));
-	l2->rx_overlapped.hEvent = l2->rx_avail;
-	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
-		      sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))
-	{
-		DWORD err = GetLastError();
-		if (err != ERROR_IO_PENDING) {
-			wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "
-				   "%d", (int) err);
-			return -1;
-		}
-		/*
-		 * Once read is completed, l2_packet_rx_event() will be
-		 * called.
-		 */
-	} else {
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "
-			   "without wait for completion");
-		if (!recursive)
-			l2_packet_callback(l2);
-	}
-
-	return 0;
-}
-#endif /* _WIN32_WCE */
-
-
-static void l2_packet_callback(struct l2_packet_data *l2)
-{
-	const u8 *rx_buf, *rx_src;
-	size_t rx_len;
-	struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;
-
-	wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",
-		   (int) l2->rx_written);
-
-	if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {
-		rx_buf = (u8 *) ethhdr;
-		rx_len = l2->rx_written;
-	} else {
-		rx_buf = (u8 *) (ethhdr + 1);
-		rx_len = l2->rx_written - sizeof(*ethhdr);
-	}
-	rx_src = ethhdr->h_source;
-
-	l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
-#ifndef _WIN32_WCE
-	l2_ndisuio_start_read(l2, 1);
-#endif /* _WIN32_WCE */
-}
-
-
-static void l2_packet_rx_event(void *eloop_data, void *user_data)
-{
-	struct l2_packet_data *l2 = eloop_data;
-
-	if (l2_ndisuio_global)
-		l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];
-
-	ResetEvent(l2->rx_avail);
-
-#ifndef _WIN32_WCE
-	if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),
-				 &l2->rx_overlapped, &l2->rx_written, FALSE)) {
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "
-			   "failed: %d", (int) GetLastError());
-		return;
-	}
-#endif /* _WIN32_WCE */
-
-	l2_packet_callback(l2);
-
-#ifdef _WIN32_WCE
-	SetEvent(l2_ndisuio_global->rx_processed);
-#endif /* _WIN32_WCE */
-}
-
-
-static int l2_ndisuio_set_ether_type(unsigned short protocol)
-{
-	USHORT proto = htons(protocol);
-	DWORD written;
-
-	if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
-			     IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,
-			     sizeof(proto), NULL, 0, &written, NULL)) {
-		wpa_printf(MSG_ERROR, "L2(NDISUIO): "
-			   "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",
-			   (int) GetLastError());
-		return -1;
-	}
-
-	return 0;
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-
-	if (l2_ndisuio_global == NULL) {
-		l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
-		if (l2_ndisuio_global == NULL)
-			return NULL;
-		l2_ndisuio_global->first_proto = protocol;
-	}
-	if (l2_ndisuio_global->refcount >= 2) {
-		wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
-			   "simultaneous connections allowed");
-		return NULL;
-	}
-	l2_ndisuio_global->refcount++;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;
-
-	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-	if (own_addr)
-		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
-
-	if (l2_ndisuio_set_ether_type(protocol) < 0) {
-		os_free(l2);
-		return NULL;
-	}
-
-	if (l2_ndisuio_global->refcount > 1) {
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
-			   "filtering ethertype to %04x", protocol);
-		if (l2_ndisuio_global->l2[0])
-			l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
-		return l2;
-	}
-
-	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
-	if (l2->rx_avail == NULL) {
-		os_free(l2);
-		return NULL;
-	}
-
-	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
-			     l2_packet_rx_event, l2, NULL);
-
-#ifdef _WIN32_WCE
-	l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
-	/*
-	 * This event is being set based on media connect/disconnect
-	 * notifications in driver_ndis.c.
-	 */
-	l2_ndisuio_global->ready_for_read =
-		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
-	l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
-	if (l2_ndisuio_global->stop_request == NULL ||
-	    l2_ndisuio_global->ready_for_read == NULL ||
-	    l2_ndisuio_global->rx_processed == NULL) {
-		if (l2_ndisuio_global->stop_request) {
-			CloseHandle(l2_ndisuio_global->stop_request);
-			l2_ndisuio_global->stop_request = NULL;
-		}
-		if (l2_ndisuio_global->ready_for_read) {
-			CloseHandle(l2_ndisuio_global->ready_for_read);
-			l2_ndisuio_global->ready_for_read = NULL;
-		}
-		if (l2_ndisuio_global->rx_processed) {
-			CloseHandle(l2_ndisuio_global->rx_processed);
-			l2_ndisuio_global->rx_processed = NULL;
-		}
-		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
-		os_free(l2);
-		return NULL;
-	}
-
-	l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
-						    l2_packet_rx_thread, l2, 0,
-						    NULL);
-	if (l2_ndisuio_global->rx_thread == NULL) {
-		wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
-			   "thread: %d", (int) GetLastError());
-		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
-		CloseHandle(l2_ndisuio_global->stop_request);
-		l2_ndisuio_global->stop_request = NULL;
-		os_free(l2);
-		return NULL;
-	}
-#else /* _WIN32_WCE */
-	l2_ndisuio_start_read(l2, 0);
-#endif /* _WIN32_WCE */
-
-	return l2;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	if (l2_ndisuio_global) {
-		l2_ndisuio_global->refcount--;
-		l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
-		if (l2_ndisuio_global->refcount) {
-			wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
-				   "ethertype to %04x",
-				   l2_ndisuio_global->first_proto);
-			l2_ndisuio_set_ether_type(
-				l2_ndisuio_global->first_proto);
-			return;
-		}
-
-#ifdef _WIN32_WCE
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
-			   "stop");
-		SetEvent(l2_ndisuio_global->stop_request);
-		/*
-		 * Cancel pending ReadFile() in the RX thread (if we were still
-		 * connected at this point).
-		 */
-		if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
-				     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
-				     NULL)) {
-			wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
-				   "failed: %d", (int) GetLastError());
-			/* RX thread will exit blocking ReadFile once NDISUIO
-			 * notices that the adapter is disconnected. */
-		}
-		WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
-		wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
-		CloseHandle(l2_ndisuio_global->rx_thread);
-		CloseHandle(l2_ndisuio_global->stop_request);
-		CloseHandle(l2_ndisuio_global->ready_for_read);
-		CloseHandle(l2_ndisuio_global->rx_processed);
-#endif /* _WIN32_WCE */
-
-		os_free(l2_ndisuio_global);
-		l2_ndisuio_global = NULL;
-	}
-
-#ifndef _WIN32_WCE
-	CancelIo(driver_ndis_get_ndisuio_handle());
-#endif /* _WIN32_WCE */
-
-	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
-	CloseHandle(l2->rx_avail);
-	os_free(l2);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	return -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_ndis.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_ndis.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,516 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This implementation requires Windows specific event loop implementation,
+ * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with
+ * driver_ndis.c, so only that driver interface can be used and
+ * CONFIG_USE_NDISUIO must be defined.
+ *
+ * WinXP version of the code uses overlapped I/O and a single threaded design
+ * with callback functions from I/O code. WinCE version uses a separate RX
+ * thread that blocks on ReadFile() whenever the media status is connected.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+#include <ntddndis.h>
+
+#ifdef _WIN32_WCE
+#include <winioctl.h>
+#include <nuiouser.h>
+#endif /* _WIN32_WCE */
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+#ifndef _WIN32_WCE
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+#define IOCTL_NDISUIO_SET_ETHER_TYPE \
+	_NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#endif /* _WIN32_WCE */
+
+/* From driver_ndis.c to shared the handle to NDISUIO */
+HANDLE driver_ndis_get_ndisuio_handle(void);
+
+/*
+ * NDISUIO supports filtering of only one ethertype at the time, so we must
+ * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth
+ * whenever wpa_supplicant is trying to pre-authenticate and then switching
+ * back to EAPOL when pre-authentication has been completed.
+ */
+
+struct l2_packet_data;
+
+struct l2_packet_ndisuio_global {
+	int refcount;
+	unsigned short first_proto;
+	struct l2_packet_data *l2[2];
+#ifdef _WIN32_WCE
+	HANDLE rx_thread;
+	HANDLE stop_request;
+	HANDLE ready_for_read;
+	HANDLE rx_processed;
+#endif /* _WIN32_WCE */
+};
+
+static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;
+
+struct l2_packet_data {
+	char ifname[100];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
+		     * rx_callback and l2_packet_send() */
+	HANDLE rx_avail;
+#ifndef _WIN32_WCE
+	OVERLAPPED rx_overlapped;
+#endif /* _WIN32_WCE */
+	u8 rx_buf[1514];
+	DWORD rx_written;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	BOOL res;
+	DWORD written;
+	struct l2_ethhdr *eth;
+#ifndef _WIN32_WCE
+	OVERLAPPED overlapped;
+#endif /* _WIN32_WCE */
+	OVERLAPPED *o;
+
+	if (l2 == NULL)
+		return -1;
+
+#ifdef _WIN32_WCE
+	o = NULL;
+#else /* _WIN32_WCE */
+	os_memset(&overlapped, 0, sizeof(overlapped));
+	o = &overlapped;
+#endif /* _WIN32_WCE */
+
+	if (l2->l2_hdr) {
+		res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,
+				&written, o);
+	} else {
+		size_t mlen = sizeof(*eth) + len;
+		eth = os_malloc(mlen);
+		if (eth == NULL)
+			return -1;
+
+		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+		eth->h_proto = htons(proto);
+		os_memcpy(eth + 1, buf, len);
+		res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,
+				&written, o);
+		os_free(eth);
+	}
+
+	if (!res) {
+		DWORD err = GetLastError();
+#ifndef _WIN32_WCE
+		if (err == ERROR_IO_PENDING) {
+			wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending "
+				   "write to complete");
+			res = GetOverlappedResult(
+				driver_ndis_get_ndisuio_handle(), &overlapped,
+				&written, TRUE);
+			if (!res) {
+				wpa_printf(MSG_DEBUG, "L2(NDISUIO): "
+					   "GetOverlappedResult failed: %d",
+					   (int) GetLastError());
+				return -1;
+			}
+			return 0;
+		}
+#endif /* _WIN32_WCE */
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",
+			   (int) GetLastError());
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void l2_packet_callback(struct l2_packet_data *l2);
+
+#ifdef _WIN32_WCE
+static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2)
+{
+	HANDLE handles[2];
+
+	wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");
+	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
+		      sizeof(l2->rx_buf), &l2->rx_written, NULL)) {
+		DWORD err = GetLastError();
+		wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "
+			   "%d", (int) err);
+		/*
+		 * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED
+		 * error whenever the connection is not up. Yield the thread to
+		 * avoid triggering a busy loop. Connection event should stop
+		 * us from looping for long, but we need to allow enough CPU
+		 * for the main thread to process the media disconnection.
+		 */
+		Sleep(100);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",
+		   (int) l2->rx_written);
+
+	/*
+	 * Notify the main thread about the availability of a frame and wait
+	 * for the frame to be processed.
+	 */
+	SetEvent(l2->rx_avail);
+	handles[0] = l2_ndisuio_global->stop_request;
+	handles[1] = l2_ndisuio_global->rx_processed;
+	WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+	ResetEvent(l2_ndisuio_global->rx_processed);
+}
+
+
+static DWORD WINAPI l2_packet_rx_thread(LPVOID arg)
+{
+	struct l2_packet_data *l2 = arg;
+	DWORD res;
+	HANDLE handles[2];
+	int run = 1;
+
+	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");
+	handles[0] = l2_ndisuio_global->stop_request;
+	handles[1] = l2_ndisuio_global->ready_for_read;
+
+	/*
+	 * Unfortunately, NDISUIO on WinCE does not seem to support waiting
+	 * on the handle. There do not seem to be anything else that we could
+	 * wait for either. If one were to modify NDISUIO to set a named event
+	 * whenever packets are available, this event could be used here to
+	 * avoid having to poll for new packets or we could even move to use a
+	 * single threaded design.
+	 *
+	 * In addition, NDISUIO on WinCE is returning
+	 * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while
+	 * the adapter is not in connected state. For now, we are just using a
+	 * local event to allow ReadFile calls only after having received NDIS
+	 * media connect event. This event could be easily converted to handle
+	 * another event if the protocol driver is replaced with somewhat more
+	 * useful design.
+	 */
+
+	while (l2_ndisuio_global && run) {
+		res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+		switch (res) {
+		case WAIT_OBJECT_0:
+			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "
+				   "request to stop RX thread");
+			run = 0;
+			break;
+		case WAIT_OBJECT_0 + 1:
+			l2_packet_rx_thread_try_read(l2);
+			break;
+		case WAIT_FAILED:
+		default:
+			wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "
+				   "WaitForMultipleObjects failed: %d",
+				   (int) GetLastError());
+			run = 0;
+			break;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");
+
+	return 0;
+}
+#else /* _WIN32_WCE */
+static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive)
+{
+	os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));
+	l2->rx_overlapped.hEvent = l2->rx_avail;
+	if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
+		      sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))
+	{
+		DWORD err = GetLastError();
+		if (err != ERROR_IO_PENDING) {
+			wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "
+				   "%d", (int) err);
+			return -1;
+		}
+		/*
+		 * Once read is completed, l2_packet_rx_event() will be
+		 * called.
+		 */
+	} else {
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "
+			   "without wait for completion");
+		if (!recursive)
+			l2_packet_callback(l2);
+	}
+
+	return 0;
+}
+#endif /* _WIN32_WCE */
+
+
+static void l2_packet_callback(struct l2_packet_data *l2)
+{
+	const u8 *rx_buf, *rx_src;
+	size_t rx_len;
+	struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;
+
+	wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",
+		   (int) l2->rx_written);
+
+	if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {
+		rx_buf = (u8 *) ethhdr;
+		rx_len = l2->rx_written;
+	} else {
+		rx_buf = (u8 *) (ethhdr + 1);
+		rx_len = l2->rx_written - sizeof(*ethhdr);
+	}
+	rx_src = ethhdr->h_source;
+
+	l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
+#ifndef _WIN32_WCE
+	l2_ndisuio_start_read(l2, 1);
+#endif /* _WIN32_WCE */
+}
+
+
+static void l2_packet_rx_event(void *eloop_data, void *user_data)
+{
+	struct l2_packet_data *l2 = eloop_data;
+
+	if (l2_ndisuio_global)
+		l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];
+
+	ResetEvent(l2->rx_avail);
+
+#ifndef _WIN32_WCE
+	if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),
+				 &l2->rx_overlapped, &l2->rx_written, FALSE)) {
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "
+			   "failed: %d", (int) GetLastError());
+		return;
+	}
+#endif /* _WIN32_WCE */
+
+	l2_packet_callback(l2);
+
+#ifdef _WIN32_WCE
+	SetEvent(l2_ndisuio_global->rx_processed);
+#endif /* _WIN32_WCE */
+}
+
+
+static int l2_ndisuio_set_ether_type(unsigned short protocol)
+{
+	USHORT proto = htons(protocol);
+	DWORD written;
+
+	if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
+			     IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,
+			     sizeof(proto), NULL, 0, &written, NULL)) {
+		wpa_printf(MSG_ERROR, "L2(NDISUIO): "
+			   "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",
+			   (int) GetLastError());
+		return -1;
+	}
+
+	return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+
+	if (l2_ndisuio_global == NULL) {
+		l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
+		if (l2_ndisuio_global == NULL)
+			return NULL;
+		l2_ndisuio_global->first_proto = protocol;
+	}
+	if (l2_ndisuio_global->refcount >= 2) {
+		wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
+			   "simultaneous connections allowed");
+		return NULL;
+	}
+	l2_ndisuio_global->refcount++;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;
+
+	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	if (own_addr)
+		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+
+	if (l2_ndisuio_set_ether_type(protocol) < 0) {
+		os_free(l2);
+		return NULL;
+	}
+
+	if (l2_ndisuio_global->refcount > 1) {
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
+			   "filtering ethertype to %04x", protocol);
+		if (l2_ndisuio_global->l2[0])
+			l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
+		return l2;
+	}
+
+	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (l2->rx_avail == NULL) {
+		os_free(l2);
+		return NULL;
+	}
+
+	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
+			     l2_packet_rx_event, l2, NULL);
+
+#ifdef _WIN32_WCE
+	l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
+	/*
+	 * This event is being set based on media connect/disconnect
+	 * notifications in driver_ndis.c.
+	 */
+	l2_ndisuio_global->ready_for_read =
+		CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
+	l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (l2_ndisuio_global->stop_request == NULL ||
+	    l2_ndisuio_global->ready_for_read == NULL ||
+	    l2_ndisuio_global->rx_processed == NULL) {
+		if (l2_ndisuio_global->stop_request) {
+			CloseHandle(l2_ndisuio_global->stop_request);
+			l2_ndisuio_global->stop_request = NULL;
+		}
+		if (l2_ndisuio_global->ready_for_read) {
+			CloseHandle(l2_ndisuio_global->ready_for_read);
+			l2_ndisuio_global->ready_for_read = NULL;
+		}
+		if (l2_ndisuio_global->rx_processed) {
+			CloseHandle(l2_ndisuio_global->rx_processed);
+			l2_ndisuio_global->rx_processed = NULL;
+		}
+		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+		os_free(l2);
+		return NULL;
+	}
+
+	l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
+						    l2_packet_rx_thread, l2, 0,
+						    NULL);
+	if (l2_ndisuio_global->rx_thread == NULL) {
+		wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
+			   "thread: %d", (int) GetLastError());
+		eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+		CloseHandle(l2_ndisuio_global->stop_request);
+		l2_ndisuio_global->stop_request = NULL;
+		os_free(l2);
+		return NULL;
+	}
+#else /* _WIN32_WCE */
+	l2_ndisuio_start_read(l2, 0);
+#endif /* _WIN32_WCE */
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	if (l2_ndisuio_global) {
+		l2_ndisuio_global->refcount--;
+		l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
+		if (l2_ndisuio_global->refcount) {
+			wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
+				   "ethertype to %04x",
+				   l2_ndisuio_global->first_proto);
+			l2_ndisuio_set_ether_type(
+				l2_ndisuio_global->first_proto);
+			return;
+		}
+
+#ifdef _WIN32_WCE
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
+			   "stop");
+		SetEvent(l2_ndisuio_global->stop_request);
+		/*
+		 * Cancel pending ReadFile() in the RX thread (if we were still
+		 * connected at this point).
+		 */
+		if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
+				     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
+				     NULL)) {
+			wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
+				   "failed: %d", (int) GetLastError());
+			/* RX thread will exit blocking ReadFile once NDISUIO
+			 * notices that the adapter is disconnected. */
+		}
+		WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
+		wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
+		CloseHandle(l2_ndisuio_global->rx_thread);
+		CloseHandle(l2_ndisuio_global->stop_request);
+		CloseHandle(l2_ndisuio_global->ready_for_read);
+		CloseHandle(l2_ndisuio_global->rx_processed);
+#endif /* _WIN32_WCE */
+
+		os_free(l2_ndisuio_global);
+		l2_ndisuio_global = NULL;
+	}
+
+#ifndef _WIN32_WCE
+	CancelIo(driver_ndis_get_ndisuio_handle());
+#endif /* _WIN32_WCE */
+
+	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+	CloseHandle(l2->rx_avail);
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_none.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,123 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling example with dummy functions
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file can be used as a starting point for layer2 packet implementation.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-
-struct l2_packet_data {
-	char ifname[17];
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
-		     * buffers */
-	int fd;
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	if (l2 == NULL)
-		return -1;
-
-	/*
-	 * TODO: Send frame (may need different implementation depending on
-	 * whether l2->l2_hdr is set).
-	 */
-
-	return 0;
-}
-
-
-static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	u8 buf[2300];
-	int res;
-
-	/* TODO: receive frame (e.g., recv() using sock */
-	buf[0] = 0;
-	res = 0;
-
-	l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */,
-			buf, res);
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-	/*
-	 * TODO: open connection for receiving frames
-	 */
-	l2->fd = -1;
-	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
-
-	return l2;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	if (l2->fd >= 0) {
-		eloop_unregister_read_sock(l2->fd);
-		/* TODO: close connection */
-	}
-		
-	os_free(l2);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	/* TODO: get interface IP address */
-	return -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-	/* This function can be left empty */
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_none.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_none.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,117 @@
+/*
+ * WPA Supplicant - Layer2 packet handling example with dummy functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file can be used as a starting point for layer2 packet implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+	char ifname[17];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+		     * buffers */
+	int fd;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	if (l2 == NULL)
+		return -1;
+
+	/*
+	 * TODO: Send frame (may need different implementation depending on
+	 * whether l2->l2_hdr is set).
+	 */
+
+	return 0;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	u8 buf[2300];
+	int res;
+
+	/* TODO: receive frame (e.g., recv() using sock */
+	buf[0] = 0;
+	res = 0;
+
+	l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */,
+			buf, res);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	/*
+	 * TODO: open connection for receiving frames
+	 */
+	l2->fd = -1;
+	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	if (l2->fd >= 0) {
+		eloop_unregister_read_sock(l2->fd);
+		/* TODO: close connection */
+	}
+		
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	/* TODO: get interface IP address */
+	return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+	/* This function can be left empty */
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_pcap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,386 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/ioctl.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <pcap.h>
-#ifndef CONFIG_WINPCAP
-#include <dnet.h>
-#endif /* CONFIG_WINPCAP */
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-struct l2_packet_data {
-	pcap_t *pcap;
-#ifdef CONFIG_WINPCAP
-	unsigned int num_fast_poll;
-#else /* CONFIG_WINPCAP */
-	eth_t *eth;
-#endif /* CONFIG_WINPCAP */
-	char ifname[100];
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls
-			* to rx_callback */
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-#ifndef CONFIG_WINPCAP
-static int l2_packet_init_libdnet(struct l2_packet_data *l2)
-{
-	eth_addr_t own_addr;
-
-	l2->eth = eth_open(l2->ifname);
-	if (!l2->eth) {
-		printf("Failed to open interface '%s'.\n", l2->ifname);
-		perror("eth_open");
-		return -1;
-	}
-
-	if (eth_get(l2->eth, &own_addr) < 0) {
-		printf("Failed to get own hw address from interface '%s'.\n",
-		       l2->ifname);
-		perror("eth_get");
-		eth_close(l2->eth);
-		l2->eth = NULL;
-		return -1;
-	}
-	os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN);
-
-	return 0;
-}
-#endif /* CONFIG_WINPCAP */
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	int ret;
-	struct l2_ethhdr *eth;
-
-	if (l2 == NULL)
-		return -1;
-
-	if (l2->l2_hdr) {
-#ifdef CONFIG_WINPCAP
-		ret = pcap_sendpacket(l2->pcap, buf, len);
-#else /* CONFIG_WINPCAP */
-		ret = eth_send(l2->eth, buf, len);
-#endif /* CONFIG_WINPCAP */
-	} else {
-		size_t mlen = sizeof(*eth) + len;
-		eth = os_malloc(mlen);
-		if (eth == NULL)
-			return -1;
-
-		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
-		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
-		eth->h_proto = htons(proto);
-		os_memcpy(eth + 1, buf, len);
-
-#ifdef CONFIG_WINPCAP
-		ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
-#else /* CONFIG_WINPCAP */
-		ret = eth_send(l2->eth, (u8 *) eth, mlen);
-#endif /* CONFIG_WINPCAP */
-
-		os_free(eth);
-	}
-
-	return ret;
-}
-
-
-#ifndef CONFIG_WINPCAP
-static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	pcap_t *pcap = sock_ctx;
-	struct pcap_pkthdr hdr;
-	const u_char *packet;
-	struct l2_ethhdr *ethhdr;
-	unsigned char *buf;
-	size_t len;
-
-	packet = pcap_next(pcap, &hdr);
-
-	if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
-		return;
-
-	ethhdr = (struct l2_ethhdr *) packet;
-	if (l2->l2_hdr) {
-		buf = (unsigned char *) ethhdr;
-		len = hdr.caplen;
-	} else {
-		buf = (unsigned char *) (ethhdr + 1);
-		len = hdr.caplen - sizeof(*ethhdr);
-	}
-	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
-}
-#endif /* CONFIG_WINPCAP */
-
-
-#ifdef CONFIG_WINPCAP
-static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
-				 const u_char *pkt_data)
-{
-	struct l2_packet_data *l2 = (struct l2_packet_data *) user;
-	struct l2_ethhdr *ethhdr;
-	unsigned char *buf;
-	size_t len;
-
-	if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
-		return;
-
-	ethhdr = (struct l2_ethhdr *) pkt_data;
-	if (l2->l2_hdr) {
-		buf = (unsigned char *) ethhdr;
-		len = hdr->caplen;
-	} else {
-		buf = (unsigned char *) (ethhdr + 1);
-		len = hdr->caplen - sizeof(*ethhdr);
-	}
-	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
-	/*
-	 * Use shorter poll interval for 3 seconds to reduce latency during key
-	 * handshake.
-	 */
-	l2->num_fast_poll = 3 * 50;
-}
-
-
-static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	pcap_t *pcap = timeout_ctx;
-	int timeout;
-
-	if (l2->num_fast_poll > 0) {
-		timeout = 20000;
-		l2->num_fast_poll--;
-	} else
-		timeout = 100000;
-
-	/* Register new timeout before calling l2_packet_receive() since
-	 * receive handler may free this l2_packet instance (which will
-	 * cancel this timeout). */
-	eloop_register_timeout(0, timeout, l2_packet_receive_timeout,
-			       l2, pcap);
-	pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2);
-}
-#endif /* CONFIG_WINPCAP */
-
-
-static int l2_packet_init_libpcap(struct l2_packet_data *l2,
-				  unsigned short protocol)
-{
-	bpf_u_int32 pcap_maskp, pcap_netp;
-	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
-	struct bpf_program pcap_fp;
-
-#ifdef CONFIG_WINPCAP
-	char ifname[128];
-	os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname);
-	pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
-	l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
-	if (l2->pcap == NULL) {
-		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
-		fprintf(stderr, "ifname='%s'\n", ifname);
-		return -1;
-	}
-	if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
-		fprintf(stderr, "pcap_setnonblock: %s\n",
-			pcap_geterr(l2->pcap));
-#else /* CONFIG_WINPCAP */
-	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
-	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
-	if (l2->pcap == NULL) {
-		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
-		fprintf(stderr, "ifname='%s'\n", l2->ifname);
-		return -1;
-	}
-	if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
-	    pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
-		fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
-			pcap_geterr(l2->pcap));
-		return -1;
-	}
-#endif /* CONFIG_WINPCAP */
-	os_snprintf(pcap_filter, sizeof(pcap_filter),
-		    "not ether src " MACSTR " and "
-		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
-		    "ether proto 0x%x",
-		    MAC2STR(l2->own_addr), /* do not receive own packets */
-		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
-		    protocol);
-	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
-		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
-		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	pcap_freecode(&pcap_fp);
-#ifdef BIOCIMMEDIATE
-	/*
-	 * When libpcap uses BPF we must enable "immediate mode" to
-	 * receive frames right away; otherwise the system may
-	 * buffer them for us.
-	 */
-	{
-		unsigned int on = 1;
-		if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
-			fprintf(stderr, "%s: cannot enable immediate mode on "
-				"interface %s: %s\n",
-				__func__, l2->ifname, strerror(errno));
-			/* XXX should we fail? */
-		}
-	}
-#endif /* BIOCIMMEDIATE */
-
-#ifdef CONFIG_WINPCAP
-	eloop_register_timeout(0, 100000, l2_packet_receive_timeout,
-			       l2, l2->pcap);
-#else /* CONFIG_WINPCAP */
-	eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
-				 l2_packet_receive, l2, l2->pcap);
-#endif /* CONFIG_WINPCAP */
-
-	return 0;
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-#ifdef CONFIG_WINPCAP
-	if (own_addr)
-		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
-#else /* CONFIG_WINPCAP */
-	if (l2_packet_init_libdnet(l2))
-		return NULL;
-#endif /* CONFIG_WINPCAP */
-
-	if (l2_packet_init_libpcap(l2, protocol)) {
-#ifndef CONFIG_WINPCAP
-		eth_close(l2->eth);
-#endif /* CONFIG_WINPCAP */
-		os_free(l2);
-		return NULL;
-	}
-
-	return l2;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-#ifdef CONFIG_WINPCAP
-	eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
-#else /* CONFIG_WINPCAP */
-	if (l2->eth)
-		eth_close(l2->eth);
-	eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
-#endif /* CONFIG_WINPCAP */
-	if (l2->pcap)
-		pcap_close(l2->pcap);
-	os_free(l2);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	pcap_if_t *devs, *dev;
-	struct pcap_addr *addr;
-	struct sockaddr_in *saddr;
-	int found = 0;
-	char err[PCAP_ERRBUF_SIZE + 1];
-
-	if (pcap_findalldevs(&devs, err) < 0) {
-		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
-		return -1;
-	}
-
-	for (dev = devs; dev && !found; dev = dev->next) {
-		if (os_strcmp(dev->name, l2->ifname) != 0)
-			continue;
-
-		addr = dev->addresses;
-		while (addr) {
-			saddr = (struct sockaddr_in *) addr->addr;
-			if (saddr && saddr->sin_family == AF_INET) {
-				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
-					   len);
-				found = 1;
-				break;
-			}
-			addr = addr->next;
-		}
-	}
-
-	pcap_freealldevs(devs);
-
-	return found ? 0 : -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-#ifdef CONFIG_WINPCAP
-	/*
-	 * Use shorter poll interval for 3 seconds to reduce latency during key
-	 * handshake.
-	 */
-	l2->num_fast_poll = 3 * 50;
-	eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
-	eloop_register_timeout(0, 10000, l2_packet_receive_timeout,
-			       l2, l2->pcap);
-#endif /* CONFIG_WINPCAP */
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_pcap.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_pcap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,380 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/ioctl.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <pcap.h>
+#ifndef CONFIG_WINPCAP
+#include <dnet.h>
+#endif /* CONFIG_WINPCAP */
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct l2_packet_data {
+	pcap_t *pcap;
+#ifdef CONFIG_WINPCAP
+	unsigned int num_fast_poll;
+#else /* CONFIG_WINPCAP */
+	eth_t *eth;
+#endif /* CONFIG_WINPCAP */
+	char ifname[100];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls
+			* to rx_callback */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static int l2_packet_init_libdnet(struct l2_packet_data *l2)
+{
+	eth_addr_t own_addr;
+
+	l2->eth = eth_open(l2->ifname);
+	if (!l2->eth) {
+		printf("Failed to open interface '%s'.\n", l2->ifname);
+		perror("eth_open");
+		return -1;
+	}
+
+	if (eth_get(l2->eth, &own_addr) < 0) {
+		printf("Failed to get own hw address from interface '%s'.\n",
+		       l2->ifname);
+		perror("eth_get");
+		eth_close(l2->eth);
+		l2->eth = NULL;
+		return -1;
+	}
+	os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN);
+
+	return 0;
+}
+#endif /* CONFIG_WINPCAP */
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	int ret;
+	struct l2_ethhdr *eth;
+
+	if (l2 == NULL)
+		return -1;
+
+	if (l2->l2_hdr) {
+#ifdef CONFIG_WINPCAP
+		ret = pcap_sendpacket(l2->pcap, buf, len);
+#else /* CONFIG_WINPCAP */
+		ret = eth_send(l2->eth, buf, len);
+#endif /* CONFIG_WINPCAP */
+	} else {
+		size_t mlen = sizeof(*eth) + len;
+		eth = os_malloc(mlen);
+		if (eth == NULL)
+			return -1;
+
+		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+		eth->h_proto = htons(proto);
+		os_memcpy(eth + 1, buf, len);
+
+#ifdef CONFIG_WINPCAP
+		ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+#else /* CONFIG_WINPCAP */
+		ret = eth_send(l2->eth, (u8 *) eth, mlen);
+#endif /* CONFIG_WINPCAP */
+
+		os_free(eth);
+	}
+
+	return ret;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	pcap_t *pcap = sock_ctx;
+	struct pcap_pkthdr hdr;
+	const u_char *packet;
+	struct l2_ethhdr *ethhdr;
+	unsigned char *buf;
+	size_t len;
+
+	packet = pcap_next(pcap, &hdr);
+
+	if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+		return;
+
+	ethhdr = (struct l2_ethhdr *) packet;
+	if (l2->l2_hdr) {
+		buf = (unsigned char *) ethhdr;
+		len = hdr.caplen;
+	} else {
+		buf = (unsigned char *) (ethhdr + 1);
+		len = hdr.caplen - sizeof(*ethhdr);
+	}
+	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+#ifdef CONFIG_WINPCAP
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+				 const u_char *pkt_data)
+{
+	struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+	struct l2_ethhdr *ethhdr;
+	unsigned char *buf;
+	size_t len;
+
+	if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+		return;
+
+	ethhdr = (struct l2_ethhdr *) pkt_data;
+	if (l2->l2_hdr) {
+		buf = (unsigned char *) ethhdr;
+		len = hdr->caplen;
+	} else {
+		buf = (unsigned char *) (ethhdr + 1);
+		len = hdr->caplen - sizeof(*ethhdr);
+	}
+	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+	/*
+	 * Use shorter poll interval for 3 seconds to reduce latency during key
+	 * handshake.
+	 */
+	l2->num_fast_poll = 3 * 50;
+}
+
+
+static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	pcap_t *pcap = timeout_ctx;
+	int timeout;
+
+	if (l2->num_fast_poll > 0) {
+		timeout = 20000;
+		l2->num_fast_poll--;
+	} else
+		timeout = 100000;
+
+	/* Register new timeout before calling l2_packet_receive() since
+	 * receive handler may free this l2_packet instance (which will
+	 * cancel this timeout). */
+	eloop_register_timeout(0, timeout, l2_packet_receive_timeout,
+			       l2, pcap);
+	pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+				  unsigned short protocol)
+{
+	bpf_u_int32 pcap_maskp, pcap_netp;
+	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+	struct bpf_program pcap_fp;
+
+#ifdef CONFIG_WINPCAP
+	char ifname[128];
+	os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname);
+	pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
+	l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
+	if (l2->pcap == NULL) {
+		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+		fprintf(stderr, "ifname='%s'\n", ifname);
+		return -1;
+	}
+	if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
+		fprintf(stderr, "pcap_setnonblock: %s\n",
+			pcap_geterr(l2->pcap));
+#else /* CONFIG_WINPCAP */
+	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
+	if (l2->pcap == NULL) {
+		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+		fprintf(stderr, "ifname='%s'\n", l2->ifname);
+		return -1;
+	}
+	if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
+	    pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
+		fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
+			pcap_geterr(l2->pcap));
+		return -1;
+	}
+#endif /* CONFIG_WINPCAP */
+	os_snprintf(pcap_filter, sizeof(pcap_filter),
+		    "not ether src " MACSTR " and "
+		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+		    "ether proto 0x%x",
+		    MAC2STR(l2->own_addr), /* do not receive own packets */
+		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+		    protocol);
+	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	pcap_freecode(&pcap_fp);
+#ifdef BIOCIMMEDIATE
+	/*
+	 * When libpcap uses BPF we must enable "immediate mode" to
+	 * receive frames right away; otherwise the system may
+	 * buffer them for us.
+	 */
+	{
+		unsigned int on = 1;
+		if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
+			fprintf(stderr, "%s: cannot enable immediate mode on "
+				"interface %s: %s\n",
+				__func__, l2->ifname, strerror(errno));
+			/* XXX should we fail? */
+		}
+	}
+#endif /* BIOCIMMEDIATE */
+
+#ifdef CONFIG_WINPCAP
+	eloop_register_timeout(0, 100000, l2_packet_receive_timeout,
+			       l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+	eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+				 l2_packet_receive, l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+
+	return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+#ifdef CONFIG_WINPCAP
+	if (own_addr)
+		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+#else /* CONFIG_WINPCAP */
+	if (l2_packet_init_libdnet(l2))
+		return NULL;
+#endif /* CONFIG_WINPCAP */
+
+	if (l2_packet_init_libpcap(l2, protocol)) {
+#ifndef CONFIG_WINPCAP
+		eth_close(l2->eth);
+#endif /* CONFIG_WINPCAP */
+		os_free(l2);
+		return NULL;
+	}
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+#ifdef CONFIG_WINPCAP
+	eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+	if (l2->eth)
+		eth_close(l2->eth);
+	eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
+#endif /* CONFIG_WINPCAP */
+	if (l2->pcap)
+		pcap_close(l2->pcap);
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	pcap_if_t *devs, *dev;
+	struct pcap_addr *addr;
+	struct sockaddr_in *saddr;
+	int found = 0;
+	char err[PCAP_ERRBUF_SIZE + 1];
+
+	if (pcap_findalldevs(&devs, err) < 0) {
+		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+		return -1;
+	}
+
+	for (dev = devs; dev && !found; dev = dev->next) {
+		if (os_strcmp(dev->name, l2->ifname) != 0)
+			continue;
+
+		addr = dev->addresses;
+		while (addr) {
+			saddr = (struct sockaddr_in *) addr->addr;
+			if (saddr && saddr->sin_family == AF_INET) {
+				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+					   len);
+				found = 1;
+				break;
+			}
+			addr = addr->next;
+		}
+	}
+
+	pcap_freealldevs(devs);
+
+	return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+#ifdef CONFIG_WINPCAP
+	/*
+	 * Use shorter poll interval for 3 seconds to reduce latency during key
+	 * handshake.
+	 */
+	l2->num_fast_poll = 3 * 50;
+	eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+	eloop_register_timeout(0, 10000, l2_packet_receive_timeout,
+			       l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_privsep.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,267 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with privilege separation
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/un.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-#include "common/privsep_commands.h"
-
-
-struct l2_packet_data {
-	int fd; /* UNIX domain socket for privsep access */
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	u8 own_addr[ETH_ALEN];
-	char *own_socket_path;
-	struct sockaddr_un priv_addr;
-};
-
-
-static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
-			const void *data, size_t data_len)
-{
-	struct msghdr msg;
-	struct iovec io[2];
-
-	io[0].iov_base = &cmd;
-	io[0].iov_len = sizeof(cmd);
-	io[1].iov_base = (u8 *) data;
-	io[1].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = data ? 2 : 1;
-	msg.msg_name = &l2->priv_addr;
-	msg.msg_namelen = sizeof(l2->priv_addr);
-
-	if (sendmsg(l2->fd, &msg, 0) < 0) {
-		perror("L2: sendmsg(cmd)");
-		return -1;
-	}
-
-	return 0;
-}
-
-			     
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	struct msghdr msg;
-	struct iovec io[4];
-	int cmd = PRIVSEP_CMD_L2_SEND;
-
-	io[0].iov_base = &cmd;
-	io[0].iov_len = sizeof(cmd);
-	io[1].iov_base = &dst_addr;
-	io[1].iov_len = ETH_ALEN;
-	io[2].iov_base = &proto;
-	io[2].iov_len = 2;
-	io[3].iov_base = (u8 *) buf;
-	io[3].iov_len = len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 4;
-	msg.msg_name = &l2->priv_addr;
-	msg.msg_namelen = sizeof(l2->priv_addr);
-
-	if (sendmsg(l2->fd, &msg, 0) < 0) {
-		perror("L2: sendmsg(packet_send)");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	u8 buf[2300];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-
-	os_memset(&from, 0, sizeof(from));
-	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
-		       &fromlen);
-	if (res < 0) {
-		perror("l2_packet_receive - recvfrom");
-		return;
-	}
-	if (res < ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "L2: Too show packet received");
-		return;
-	}
-
-	if (from.sun_family != AF_UNIX ||
-	    os_strncmp(from.sun_path, l2->priv_addr.sun_path,
-		       sizeof(from.sun_path)) != 0) {
-		wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
-			   "source");
-		return;
-	}
-
-	l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
-			res - ETH_ALEN);
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-	char *own_dir = "/tmp";
-	char *priv_dir = "/var/run/wpa_priv";
-	size_t len;
-	static unsigned int counter = 0;
-	struct sockaddr_un addr;
-	fd_set rfds;
-	struct timeval tv;
-	int res;
-	u8 reply[ETH_ALEN + 1];
-	int reg_cmd[2];
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-
-	len = os_strlen(own_dir) + 50;
-	l2->own_socket_path = os_malloc(len);
-	if (l2->own_socket_path == NULL) {
-		os_free(l2);
-		return NULL;
-	}
-	os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
-		    own_dir, getpid(), counter++);
-
-	l2->priv_addr.sun_family = AF_UNIX;
-	os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
-		    "%s/%s", priv_dir, ifname);
-
-	l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (l2->fd < 0) {
-		perror("socket(PF_UNIX)");
-		os_free(l2->own_socket_path);
-		l2->own_socket_path = NULL;
-		os_free(l2);
-		return NULL;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
-	if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(PF_UNIX)");
-		goto fail;
-	}
-
-	reg_cmd[0] = protocol;
-	reg_cmd[1] = l2_hdr;
-	if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
-	    < 0) {
-		wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
-		goto fail;
-	}
-
-	FD_ZERO(&rfds);
-	FD_SET(l2->fd, &rfds);
-	tv.tv_sec = 5;
-	tv.tv_usec = 0;
-	res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
-	if (res < 0 && errno != EINTR) {
-		perror("select");
-		goto fail;
-	}
-
-	if (FD_ISSET(l2->fd, &rfds)) {
-		res = recv(l2->fd, reply, sizeof(reply), 0);
-		if (res < 0) {
-			perror("recv");
-			goto fail;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
-			   "registration reply");
-		goto fail;
-	}
-
-	if (res != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
-			   "(len=%d)", res);
-	}
-	os_memcpy(l2->own_addr, reply, ETH_ALEN);
-
-	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
-
-	return l2;
-
-fail:
-	close(l2->fd);
-	l2->fd = -1;
-	unlink(l2->own_socket_path);
-	os_free(l2->own_socket_path);
-	l2->own_socket_path = NULL;
-	os_free(l2);
-	return NULL;
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	if (l2->fd >= 0) {
-		wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
-		eloop_unregister_read_sock(l2->fd);
-		close(l2->fd);
-	}
-
-	if (l2->own_socket_path) {
-		unlink(l2->own_socket_path);
-		os_free(l2->own_socket_path);
-	}
-		
-	os_free(l2);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	/* TODO */
-	return -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-	wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_privsep.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_privsep.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,261 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with privilege separation
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+#include "common/privsep_commands.h"
+
+
+struct l2_packet_data {
+	int fd; /* UNIX domain socket for privsep access */
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	u8 own_addr[ETH_ALEN];
+	char *own_socket_path;
+	struct sockaddr_un priv_addr;
+};
+
+
+static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
+			const void *data, size_t data_len)
+{
+	struct msghdr msg;
+	struct iovec io[2];
+
+	io[0].iov_base = &cmd;
+	io[0].iov_len = sizeof(cmd);
+	io[1].iov_base = (u8 *) data;
+	io[1].iov_len = data_len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = data ? 2 : 1;
+	msg.msg_name = &l2->priv_addr;
+	msg.msg_namelen = sizeof(l2->priv_addr);
+
+	if (sendmsg(l2->fd, &msg, 0) < 0) {
+		perror("L2: sendmsg(cmd)");
+		return -1;
+	}
+
+	return 0;
+}
+
+			     
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	struct msghdr msg;
+	struct iovec io[4];
+	int cmd = PRIVSEP_CMD_L2_SEND;
+
+	io[0].iov_base = &cmd;
+	io[0].iov_len = sizeof(cmd);
+	io[1].iov_base = &dst_addr;
+	io[1].iov_len = ETH_ALEN;
+	io[2].iov_base = &proto;
+	io[2].iov_len = 2;
+	io[3].iov_base = (u8 *) buf;
+	io[3].iov_len = len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 4;
+	msg.msg_name = &l2->priv_addr;
+	msg.msg_namelen = sizeof(l2->priv_addr);
+
+	if (sendmsg(l2->fd, &msg, 0) < 0) {
+		perror("L2: sendmsg(packet_send)");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	u8 buf[2300];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+
+	os_memset(&from, 0, sizeof(from));
+	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+		       &fromlen);
+	if (res < 0) {
+		perror("l2_packet_receive - recvfrom");
+		return;
+	}
+	if (res < ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "L2: Too show packet received");
+		return;
+	}
+
+	if (from.sun_family != AF_UNIX ||
+	    os_strncmp(from.sun_path, l2->priv_addr.sun_path,
+		       sizeof(from.sun_path)) != 0) {
+		wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
+			   "source");
+		return;
+	}
+
+	l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
+			res - ETH_ALEN);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+	char *own_dir = "/tmp";
+	char *priv_dir = "/var/run/wpa_priv";
+	size_t len;
+	static unsigned int counter = 0;
+	struct sockaddr_un addr;
+	fd_set rfds;
+	struct timeval tv;
+	int res;
+	u8 reply[ETH_ALEN + 1];
+	int reg_cmd[2];
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+
+	len = os_strlen(own_dir) + 50;
+	l2->own_socket_path = os_malloc(len);
+	if (l2->own_socket_path == NULL) {
+		os_free(l2);
+		return NULL;
+	}
+	os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
+		    own_dir, getpid(), counter++);
+
+	l2->priv_addr.sun_family = AF_UNIX;
+	os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
+		    "%s/%s", priv_dir, ifname);
+
+	l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (l2->fd < 0) {
+		perror("socket(PF_UNIX)");
+		os_free(l2->own_socket_path);
+		l2->own_socket_path = NULL;
+		os_free(l2);
+		return NULL;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
+	if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("l2-pkt-privsep: bind(PF_UNIX)");
+		goto fail;
+	}
+
+	reg_cmd[0] = protocol;
+	reg_cmd[1] = l2_hdr;
+	if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
+	    < 0) {
+		wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
+		goto fail;
+	}
+
+	FD_ZERO(&rfds);
+	FD_SET(l2->fd, &rfds);
+	tv.tv_sec = 5;
+	tv.tv_usec = 0;
+	res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
+	if (res < 0 && errno != EINTR) {
+		perror("select");
+		goto fail;
+	}
+
+	if (FD_ISSET(l2->fd, &rfds)) {
+		res = recv(l2->fd, reply, sizeof(reply), 0);
+		if (res < 0) {
+			perror("recv");
+			goto fail;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
+			   "registration reply");
+		goto fail;
+	}
+
+	if (res != ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
+			   "(len=%d)", res);
+	}
+	os_memcpy(l2->own_addr, reply, ETH_ALEN);
+
+	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+	return l2;
+
+fail:
+	close(l2->fd);
+	l2->fd = -1;
+	unlink(l2->own_socket_path);
+	os_free(l2->own_socket_path);
+	l2->own_socket_path = NULL;
+	os_free(l2);
+	return NULL;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	if (l2->fd >= 0) {
+		wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
+		eloop_unregister_read_sock(l2->fd);
+		close(l2->fd);
+	}
+
+	if (l2->own_socket_path) {
+		unlink(l2->own_socket_path);
+		os_free(l2->own_socket_path);
+	}
+		
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	/* TODO */
+	return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+	wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
+}

Deleted: vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c
===================================================================
--- vendor/wpa/dist/src/l2_packet/l2_packet_winpcap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,341 +0,0 @@
-/*
- * WPA Supplicant - Layer2 packet handling with WinPcap RX thread
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This l2_packet implementation is explicitly for WinPcap and Windows events.
- * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive
- * frames which means relatively long latency for EAPOL RX processing. The
- * implementation here uses a separate thread to allow WinPcap to be receiving
- * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms
- * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms
- * is added in to receive thread whenever no EAPOL frames has been received for
- * a while. Whenever an EAPOL handshake is expected, this sleep is removed.
- *
- * The RX thread receives a frame and signals main thread through Windows event
- * about the availability of a new frame. Processing the received frame is
- * synchronized with pair of Windows events so that no extra buffer or queuing
- * mechanism is needed. This implementation requires Windows specific event
- * loop implementation, i.e., eloop_win.c.
- *
- * WinPcap has pcap_getevent() that could, in theory at least, be used to
- * implement this kind of waiting with a simpler single-thread design. However,
- * that event handle is not really signaled immediately when receiving each
- * frame, so it does not really work for this kind of use.
- */
-
-#include "includes.h"
-#include <pcap.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
-/*
- * Number of pcap_dispatch() iterations to do without extra wait after each
- * received EAPOL packet or authentication notification. This is used to reduce
- * latency for EAPOL receive.
- */
-static const size_t no_wait_count = 750;
-
-struct l2_packet_data {
-	pcap_t *pcap;
-	unsigned int num_fast_poll;
-	char ifname[100];
-	u8 own_addr[ETH_ALEN];
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len);
-	void *rx_callback_ctx;
-	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
-		     * rx_callback and l2_packet_send() */
-	int running;
-	HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
-	u8 *rx_buf, *rx_src;
-	size_t rx_len;
-	size_t rx_no_wait;
-};
-
-
-int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
-{
-	os_memcpy(addr, l2->own_addr, ETH_ALEN);
-	return 0;
-}
-
-
-int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
-		   const u8 *buf, size_t len)
-{
-	int ret;
-	struct l2_ethhdr *eth;
-
-	if (l2 == NULL)
-		return -1;
-
-	if (l2->l2_hdr) {
-		ret = pcap_sendpacket(l2->pcap, buf, len);
-	} else {
-		size_t mlen = sizeof(*eth) + len;
-		eth = os_malloc(mlen);
-		if (eth == NULL)
-			return -1;
-
-		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
-		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
-		eth->h_proto = htons(proto);
-		os_memcpy(eth + 1, buf, len);
-		ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
-		os_free(eth);
-	}
-
-	return ret;
-}
-
-
-/* pcap_dispatch() callback for the RX thread */
-static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
-				 const u_char *pkt_data)
-{
-	struct l2_packet_data *l2 = (struct l2_packet_data *) user;
-	struct l2_ethhdr *ethhdr;
-
-	if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
-		return;
-
-	ethhdr = (struct l2_ethhdr *) pkt_data;
-	if (l2->l2_hdr) {
-		l2->rx_buf = (u8 *) ethhdr;
-		l2->rx_len = hdr->caplen;
-	} else {
-		l2->rx_buf = (u8 *) (ethhdr + 1);
-		l2->rx_len = hdr->caplen - sizeof(*ethhdr);
-	}
-	l2->rx_src = ethhdr->h_source;
-	SetEvent(l2->rx_avail);
-	WaitForSingleObject(l2->rx_done, INFINITE);
-	ResetEvent(l2->rx_done);
-	l2->rx_no_wait = no_wait_count;
-}
-
-
-/* main RX loop that is running in a separate thread */
-static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
-{
-	struct l2_packet_data *l2 = arg;
-
-	while (l2->running) {
-		pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
-			      (u_char *) l2);
-		if (l2->rx_no_wait > 0)
-			l2->rx_no_wait--;
-		if (WaitForSingleObject(l2->rx_notify,
-					l2->rx_no_wait ? 0 : 50) ==
-		    WAIT_OBJECT_0) {
-			l2->rx_no_wait = no_wait_count;
-			ResetEvent(l2->rx_notify);
-		}
-	}
-	SetEvent(l2->rx_thread_done);
-	ExitThread(0);
-	return 0;
-}
-
-
-/* main thread RX event handler */
-static void l2_packet_rx_event(void *eloop_data, void *user_data)
-{
-	struct l2_packet_data *l2 = eloop_data;
-	l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
-			l2->rx_len);
-	ResetEvent(l2->rx_avail);
-	SetEvent(l2->rx_done);
-}
-
-
-static int l2_packet_init_libpcap(struct l2_packet_data *l2,
-				  unsigned short protocol)
-{
-	bpf_u_int32 pcap_maskp, pcap_netp;
-	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
-	struct bpf_program pcap_fp;
-
-	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
-	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
-	if (l2->pcap == NULL) {
-		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
-		fprintf(stderr, "ifname='%s'\n", l2->ifname);
-		return -1;
-	}
-	os_snprintf(pcap_filter, sizeof(pcap_filter),
-		    "not ether src " MACSTR " and "
-		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
-		    "ether proto 0x%x",
-		    MAC2STR(l2->own_addr), /* do not receive own packets */
-		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
-		    protocol);
-	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
-		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
-		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
-		return -1;
-	}
-
-	pcap_freecode(&pcap_fp);
-
-	return 0;
-}
-
-
-struct l2_packet_data * l2_packet_init(
-	const char *ifname, const u8 *own_addr, unsigned short protocol,
-	void (*rx_callback)(void *ctx, const u8 *src_addr,
-			    const u8 *buf, size_t len),
-	void *rx_callback_ctx, int l2_hdr)
-{
-	struct l2_packet_data *l2;
-	DWORD thread_id;
-
-	l2 = os_zalloc(sizeof(struct l2_packet_data));
-	if (l2 == NULL)
-		return NULL;
-	if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
-		os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
-	else
-		os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
-			    ifname);
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-	l2->l2_hdr = l2_hdr;
-
-	if (own_addr)
-		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
-
-	if (l2_packet_init_libpcap(l2, protocol)) {
-		os_free(l2);
-		return NULL;
-	}
-
-	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
-	l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
-	l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
-	if (l2->rx_avail == NULL || l2->rx_done == NULL ||
-	    l2->rx_notify == NULL) {
-		CloseHandle(l2->rx_avail);
-		CloseHandle(l2->rx_done);
-		CloseHandle(l2->rx_notify);
-		pcap_close(l2->pcap);
-		os_free(l2);
-		return NULL;
-	}
-
-	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
-			     l2_packet_rx_event, l2, NULL);
-
-	l2->running = 1;
-	l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
-				     &thread_id);
-
-	return l2;
-}
-
-
-static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-
-	if (l2->rx_thread_done &&
-	    WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
-		wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
-			   "exit - kill it\n");
-		TerminateThread(l2->rx_thread, 0);
-	}
-	CloseHandle(l2->rx_thread_done);
-	CloseHandle(l2->rx_thread);
-	if (l2->pcap)
-		pcap_close(l2->pcap);
-	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
-	CloseHandle(l2->rx_avail);
-	CloseHandle(l2->rx_done);
-	CloseHandle(l2->rx_notify);
-	os_free(l2);
-}
-
-
-void l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-	l2->running = 0;
-	pcap_breakloop(l2->pcap);
-
-	/*
-	 * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
-	 * event and this event is set in l2_packet_rx_event(). However,
-	 * l2_packet_deinit() may end up being called from l2->rx_callback(),
-	 * so we need to return from here and complete deinitialization in
-	 * a registered timeout to avoid having to forcefully kill the RX
-	 * thread.
-	 */
-	eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
-}
-
-
-int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
-{
-	pcap_if_t *devs, *dev;
-	struct pcap_addr *addr;
-	struct sockaddr_in *saddr;
-	int found = 0;
-	char err[PCAP_ERRBUF_SIZE + 1];
-
-	if (pcap_findalldevs(&devs, err) < 0) {
-		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
-		return -1;
-	}
-
-	for (dev = devs; dev && !found; dev = dev->next) {
-		if (os_strcmp(dev->name, l2->ifname) != 0)
-			continue;
-
-		addr = dev->addresses;
-		while (addr) {
-			saddr = (struct sockaddr_in *) addr->addr;
-			if (saddr && saddr->sin_family == AF_INET) {
-				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
-					   len);
-				found = 1;
-				break;
-			}
-			addr = addr->next;
-		}
-	}
-
-	pcap_freealldevs(devs);
-
-	return found ? 0 : -1;
-}
-
-
-void l2_packet_notify_auth_start(struct l2_packet_data *l2)
-{
-	if (l2)
-		SetEvent(l2->rx_notify);
-}

Copied: vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c (from rev 9639, vendor/wpa/dist/src/l2_packet/l2_packet_winpcap.c)
===================================================================
--- vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/l2_packet/l2_packet_winpcap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,335 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with WinPcap RX thread
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This l2_packet implementation is explicitly for WinPcap and Windows events.
+ * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive
+ * frames which means relatively long latency for EAPOL RX processing. The
+ * implementation here uses a separate thread to allow WinPcap to be receiving
+ * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms
+ * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms
+ * is added in to receive thread whenever no EAPOL frames has been received for
+ * a while. Whenever an EAPOL handshake is expected, this sleep is removed.
+ *
+ * The RX thread receives a frame and signals main thread through Windows event
+ * about the availability of a new frame. Processing the received frame is
+ * synchronized with pair of Windows events so that no extra buffer or queuing
+ * mechanism is needed. This implementation requires Windows specific event
+ * loop implementation, i.e., eloop_win.c.
+ *
+ * WinPcap has pcap_getevent() that could, in theory at least, be used to
+ * implement this kind of waiting with a simpler single-thread design. However,
+ * that event handle is not really signaled immediately when receiving each
+ * frame, so it does not really work for this kind of use.
+ */
+
+#include "includes.h"
+#include <pcap.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+/*
+ * Number of pcap_dispatch() iterations to do without extra wait after each
+ * received EAPOL packet or authentication notification. This is used to reduce
+ * latency for EAPOL receive.
+ */
+static const size_t no_wait_count = 750;
+
+struct l2_packet_data {
+	pcap_t *pcap;
+	unsigned int num_fast_poll;
+	char ifname[100];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
+		     * rx_callback and l2_packet_send() */
+	int running;
+	HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
+	u8 *rx_buf, *rx_src;
+	size_t rx_len;
+	size_t rx_no_wait;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	int ret;
+	struct l2_ethhdr *eth;
+
+	if (l2 == NULL)
+		return -1;
+
+	if (l2->l2_hdr) {
+		ret = pcap_sendpacket(l2->pcap, buf, len);
+	} else {
+		size_t mlen = sizeof(*eth) + len;
+		eth = os_malloc(mlen);
+		if (eth == NULL)
+			return -1;
+
+		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+		eth->h_proto = htons(proto);
+		os_memcpy(eth + 1, buf, len);
+		ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+		os_free(eth);
+	}
+
+	return ret;
+}
+
+
+/* pcap_dispatch() callback for the RX thread */
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+				 const u_char *pkt_data)
+{
+	struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+	struct l2_ethhdr *ethhdr;
+
+	if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+		return;
+
+	ethhdr = (struct l2_ethhdr *) pkt_data;
+	if (l2->l2_hdr) {
+		l2->rx_buf = (u8 *) ethhdr;
+		l2->rx_len = hdr->caplen;
+	} else {
+		l2->rx_buf = (u8 *) (ethhdr + 1);
+		l2->rx_len = hdr->caplen - sizeof(*ethhdr);
+	}
+	l2->rx_src = ethhdr->h_source;
+	SetEvent(l2->rx_avail);
+	WaitForSingleObject(l2->rx_done, INFINITE);
+	ResetEvent(l2->rx_done);
+	l2->rx_no_wait = no_wait_count;
+}
+
+
+/* main RX loop that is running in a separate thread */
+static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
+{
+	struct l2_packet_data *l2 = arg;
+
+	while (l2->running) {
+		pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
+			      (u_char *) l2);
+		if (l2->rx_no_wait > 0)
+			l2->rx_no_wait--;
+		if (WaitForSingleObject(l2->rx_notify,
+					l2->rx_no_wait ? 0 : 50) ==
+		    WAIT_OBJECT_0) {
+			l2->rx_no_wait = no_wait_count;
+			ResetEvent(l2->rx_notify);
+		}
+	}
+	SetEvent(l2->rx_thread_done);
+	ExitThread(0);
+	return 0;
+}
+
+
+/* main thread RX event handler */
+static void l2_packet_rx_event(void *eloop_data, void *user_data)
+{
+	struct l2_packet_data *l2 = eloop_data;
+	l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
+			l2->rx_len);
+	ResetEvent(l2->rx_avail);
+	SetEvent(l2->rx_done);
+}
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+				  unsigned short protocol)
+{
+	bpf_u_int32 pcap_maskp, pcap_netp;
+	char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+	struct bpf_program pcap_fp;
+
+	pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+	l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
+	if (l2->pcap == NULL) {
+		fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+		fprintf(stderr, "ifname='%s'\n", l2->ifname);
+		return -1;
+	}
+	os_snprintf(pcap_filter, sizeof(pcap_filter),
+		    "not ether src " MACSTR " and "
+		    "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+		    "ether proto 0x%x",
+		    MAC2STR(l2->own_addr), /* do not receive own packets */
+		    MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+		    protocol);
+	if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+		fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+		fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+		return -1;
+	}
+
+	pcap_freecode(&pcap_fp);
+
+	return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+	DWORD thread_id;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
+		os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+	else
+		os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
+			    ifname);
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	if (own_addr)
+		os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+
+	if (l2_packet_init_libpcap(l2, protocol)) {
+		os_free(l2);
+		return NULL;
+	}
+
+	l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+	l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+	l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (l2->rx_avail == NULL || l2->rx_done == NULL ||
+	    l2->rx_notify == NULL) {
+		CloseHandle(l2->rx_avail);
+		CloseHandle(l2->rx_done);
+		CloseHandle(l2->rx_notify);
+		pcap_close(l2->pcap);
+		os_free(l2);
+		return NULL;
+	}
+
+	eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
+			     l2_packet_rx_event, l2, NULL);
+
+	l2->running = 1;
+	l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
+				     &thread_id);
+
+	return l2;
+}
+
+
+static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+
+	if (l2->rx_thread_done &&
+	    WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
+		wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
+			   "exit - kill it\n");
+		TerminateThread(l2->rx_thread, 0);
+	}
+	CloseHandle(l2->rx_thread_done);
+	CloseHandle(l2->rx_thread);
+	if (l2->pcap)
+		pcap_close(l2->pcap);
+	eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+	CloseHandle(l2->rx_avail);
+	CloseHandle(l2->rx_done);
+	CloseHandle(l2->rx_notify);
+	os_free(l2);
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	l2->running = 0;
+	pcap_breakloop(l2->pcap);
+
+	/*
+	 * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
+	 * event and this event is set in l2_packet_rx_event(). However,
+	 * l2_packet_deinit() may end up being called from l2->rx_callback(),
+	 * so we need to return from here and complete deinitialization in
+	 * a registered timeout to avoid having to forcefully kill the RX
+	 * thread.
+	 */
+	eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	pcap_if_t *devs, *dev;
+	struct pcap_addr *addr;
+	struct sockaddr_in *saddr;
+	int found = 0;
+	char err[PCAP_ERRBUF_SIZE + 1];
+
+	if (pcap_findalldevs(&devs, err) < 0) {
+		wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+		return -1;
+	}
+
+	for (dev = devs; dev && !found; dev = dev->next) {
+		if (os_strcmp(dev->name, l2->ifname) != 0)
+			continue;
+
+		addr = dev->addresses;
+		while (addr) {
+			saddr = (struct sockaddr_in *) addr->addr;
+			if (saddr && saddr->sin_family == AF_INET) {
+				os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+					   len);
+				found = 1;
+				break;
+			}
+			addr = addr->next;
+		}
+	}
+
+	pcap_freealldevs(devs);
+
+	return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+	if (l2)
+		SetEvent(l2->rx_notify);
+}

Deleted: vendor/wpa/2.0/src/radius/radius.c
===================================================================
--- vendor/wpa/dist/src/radius/radius.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1317 +0,0 @@
-/*
- * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/wpabuf.h"
-#include "crypto/md5.h"
-#include "crypto/crypto.h"
-#include "radius.h"
-
-
-/**
- * struct radius_msg - RADIUS message structure for new and parsed messages
- */
-struct radius_msg {
-	/**
-	 * buf - Allocated buffer for RADIUS message
-	 */
-	struct wpabuf *buf;
-
-	/**
-	 * hdr - Pointer to the RADIUS header in buf
-	 */
-	struct radius_hdr *hdr;
-
-	/**
-	 * attr_pos - Array of indexes to attributes
-	 *
-	 * The values are number of bytes from buf to the beginning of
-	 * struct radius_attr_hdr.
-	 */
-	size_t *attr_pos;
-
-	/**
-	 * attr_size - Total size of the attribute pointer array
-	 */
-	size_t attr_size;
-
-	/**
-	 * attr_used - Total number of attributes in the array
-	 */
-	size_t attr_used;
-};
-
-
-struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
-{
-	return msg->hdr;
-}
-
-
-struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
-{
-	return msg->buf;
-}
-
-
-static struct radius_attr_hdr *
-radius_get_attr_hdr(struct radius_msg *msg, int idx)
-{
-	return (struct radius_attr_hdr *)
-		(wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
-}
-
-
-static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
-{
-	msg->hdr->code = code;
-	msg->hdr->identifier = identifier;
-}
-
-
-static int radius_msg_initialize(struct radius_msg *msg)
-{
-	msg->attr_pos =
-		os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
-	if (msg->attr_pos == NULL)
-		return -1;
-
-	msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
-	msg->attr_used = 0;
-
-	return 0;
-}
-
-
-/**
- * radius_msg_new - Create a new RADIUS message
- * @code: Code for RADIUS header
- * @identifier: Identifier for RADIUS header
- * Returns: Context for RADIUS message or %NULL on failure
- *
- * The caller is responsible for freeing the returned data with
- * radius_msg_free().
- */
-struct radius_msg * radius_msg_new(u8 code, u8 identifier)
-{
-	struct radius_msg *msg;
-
-	msg = os_zalloc(sizeof(*msg));
-	if (msg == NULL)
-		return NULL;
-
-	msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
-	if (msg->buf == NULL || radius_msg_initialize(msg)) {
-		radius_msg_free(msg);
-		return NULL;
-	}
-	msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
-
-	radius_msg_set_hdr(msg, code, identifier);
-
-	return msg;
-}
-
-
-/**
- * radius_msg_free - Free a RADIUS message
- * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
- */
-void radius_msg_free(struct radius_msg *msg)
-{
-	if (msg == NULL)
-		return;
-
-	wpabuf_free(msg->buf);
-	os_free(msg->attr_pos);
-	os_free(msg);
-}
-
-
-static const char *radius_code_string(u8 code)
-{
-	switch (code) {
-	case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
-	case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
-	case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
-	case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
-	case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
-	case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
-	case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
-	case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
-	case RADIUS_CODE_RESERVED: return "Reserved";
-	default: return "?Unknown?";
-	}
-}
-
-
-struct radius_attr_type {
-	u8 type;
-	char *name;
-	enum {
-		RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
-		RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
-	} data_type;
-};
-
-static struct radius_attr_type radius_attrs[] =
-{
-	{ RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
-	{ 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_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_CLASS, "Class", RADIUS_ATTR_UNDIST },
-	{ RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
-	{ RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
-	  RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
-	  RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
-	{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
-	  RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
-	  RADIUS_ATTR_INT32 },
-	{ 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",
-	  RADIUS_ATTR_HEXDUMP },
-	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
-	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
-	  RADIUS_ATTR_UNDIST },
-	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
-	  RADIUS_ATTR_HEXDUMP },
-	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
-	  RADIUS_ATTR_INT32 },
-	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
-	  RADIUS_ATTR_TEXT },
-	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
-};
-#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
-
-
-static struct radius_attr_type *radius_get_attr_type(u8 type)
-{
-	size_t i;
-
-	for (i = 0; i < RADIUS_ATTRS; i++) {
-		if (type == radius_attrs[i].type)
-			return &radius_attrs[i];
-	}
-
-	return NULL;
-}
-
-
-static void print_char(char c)
-{
-	if (c >= 32 && c < 127)
-		printf("%c", c);
-	else
-		printf("<%02x>", c);
-}
-
-
-static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
-{
-	struct radius_attr_type *attr;
-	int i, len;
-	unsigned char *pos;
-
-	attr = radius_get_attr_type(hdr->type);
-
-	printf("   Attribute %d (%s) length=%d\n",
-	       hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
-
-	if (attr == NULL)
-		return;
-
-	len = hdr->length - sizeof(struct radius_attr_hdr);
-	pos = (unsigned char *) (hdr + 1);
-
-	switch (attr->data_type) {
-	case RADIUS_ATTR_TEXT:
-		printf("      Value: '");
-		for (i = 0; i < len; i++)
-			print_char(pos[i]);
-		printf("'\n");
-		break;
-
-	case RADIUS_ATTR_IP:
-		if (len == 4) {
-			struct in_addr addr;
-			os_memcpy(&addr, pos, 4);
-			printf("      Value: %s\n", inet_ntoa(addr));
-		} else
-			printf("      Invalid IP address length %d\n", len);
-		break;
-
-#ifdef CONFIG_IPV6
-	case RADIUS_ATTR_IPV6:
-		if (len == 16) {
-			char buf[128];
-			const char *atxt;
-			struct in6_addr *addr = (struct in6_addr *) pos;
-			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
-			printf("      Value: %s\n", atxt ? atxt : "?");
-		} else
-			printf("      Invalid IPv6 address length %d\n", len);
-		break;
-#endif /* CONFIG_IPV6 */
-
-	case RADIUS_ATTR_HEXDUMP:
-	case RADIUS_ATTR_UNDIST:
-		printf("      Value:");
-		for (i = 0; i < len; i++)
-			printf(" %02x", pos[i]);
-		printf("\n");
-		break;
-
-	case RADIUS_ATTR_INT32:
-		if (len == 4)
-			printf("      Value: %u\n", WPA_GET_BE32(pos));
-		else
-			printf("      Invalid INT32 length %d\n", len);
-		break;
-
-	default:
-		break;
-	}
-}
-
-
-void radius_msg_dump(struct radius_msg *msg)
-{
-	size_t i;
-
-	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
-	       msg->hdr->code, radius_code_string(msg->hdr->code),
-	       msg->hdr->identifier, ntohs(msg->hdr->length));
-
-	for (i = 0; i < msg->attr_used; i++) {
-		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
-		radius_msg_dump_attr(attr);
-	}
-}
-
-
-int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
-		      size_t secret_len)
-{
-	if (secret) {
-		u8 auth[MD5_MAC_LEN];
-		struct radius_attr_hdr *attr;
-
-		os_memset(auth, 0, MD5_MAC_LEN);
-		attr = radius_msg_add_attr(msg,
-					   RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
-					   auth, MD5_MAC_LEN);
-		if (attr == NULL) {
-			wpa_printf(MSG_WARNING, "RADIUS: Could not add "
-				   "Message-Authenticator");
-			return -1;
-		}
-		msg->hdr->length = htons(wpabuf_len(msg->buf));
-		hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-			 wpabuf_len(msg->buf), (u8 *) (attr + 1));
-	} else
-		msg->hdr->length = htons(wpabuf_len(msg->buf));
-
-	if (wpabuf_len(msg->buf) > 0xffff) {
-		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
-			   (unsigned long) wpabuf_len(msg->buf));
-		return -1;
-	}
-	return 0;
-}
-
-
-int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
-			  size_t secret_len, const u8 *req_authenticator)
-{
-	u8 auth[MD5_MAC_LEN];
-	struct radius_attr_hdr *attr;
-	const u8 *addr[4];
-	size_t len[4];
-
-	os_memset(auth, 0, MD5_MAC_LEN);
-	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
-				   auth, MD5_MAC_LEN);
-	if (attr == NULL) {
-		printf("WARNING: Could not add Message-Authenticator\n");
-		return -1;
-	}
-	msg->hdr->length = htons(wpabuf_len(msg->buf));
-	os_memcpy(msg->hdr->authenticator, req_authenticator,
-		  sizeof(msg->hdr->authenticator));
-	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
-		 wpabuf_len(msg->buf), (u8 *) (attr + 1));
-
-	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
-	addr[0] = (u8 *) msg->hdr;
-	len[0] = 1 + 1 + 2;
-	addr[1] = req_authenticator;
-	len[1] = MD5_MAC_LEN;
-	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
-	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
-	addr[3] = secret;
-	len[3] = secret_len;
-	md5_vector(4, addr, len, msg->hdr->authenticator);
-
-	if (wpabuf_len(msg->buf) > 0xffff) {
-		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
-			   (unsigned long) wpabuf_len(msg->buf));
-		return -1;
-	}
-	return 0;
-}
-
-
-void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
-			    size_t secret_len)
-{
-	const u8 *addr[2];
-	size_t len[2];
-
-	msg->hdr->length = htons(wpabuf_len(msg->buf));
-	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
-	addr[0] = wpabuf_head(msg->buf);
-	len[0] = wpabuf_len(msg->buf);
-	addr[1] = secret;
-	len[1] = secret_len;
-	md5_vector(2, addr, len, msg->hdr->authenticator);
-
-	if (wpabuf_len(msg->buf) > 0xffff) {
-		wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
-			   (unsigned long) wpabuf_len(msg->buf));
-	}
-}
-
-
-static int radius_msg_add_attr_to_array(struct radius_msg *msg,
-					struct radius_attr_hdr *attr)
-{
-	if (msg->attr_used >= msg->attr_size) {
-		size_t *nattr_pos;
-		int nlen = msg->attr_size * 2;
-
-		nattr_pos = os_realloc(msg->attr_pos,
-				       nlen * sizeof(*msg->attr_pos));
-		if (nattr_pos == NULL)
-			return -1;
-
-		msg->attr_pos = nattr_pos;
-		msg->attr_size = nlen;
-	}
-
-	msg->attr_pos[msg->attr_used++] =
-		(unsigned char *) attr - wpabuf_head_u8(msg->buf);
-
-	return 0;
-}
-
-
-struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
-					    const u8 *data, size_t data_len)
-{
-	size_t buf_needed;
-	struct radius_attr_hdr *attr;
-
-	if (data_len > RADIUS_MAX_ATTR_LEN) {
-		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
-		       (unsigned long) data_len);
-		return NULL;
-	}
-
-	buf_needed = sizeof(*attr) + data_len;
-
-	if (wpabuf_tailroom(msg->buf) < buf_needed) {
-		/* allocate more space for message buffer */
-		if (wpabuf_resize(&msg->buf, buf_needed) < 0)
-			return NULL;
-		msg->hdr = wpabuf_mhead(msg->buf);
-	}
-
-	attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
-	attr->type = type;
-	attr->length = sizeof(*attr) + data_len;
-	wpabuf_put_data(msg->buf, data, data_len);
-
-	if (radius_msg_add_attr_to_array(msg, attr))
-		return NULL;
-
-	return attr;
-}
-
-
-/**
- * radius_msg_parse - Parse a RADIUS message
- * @data: RADIUS message to be parsed
- * @len: Length of data buffer in octets
- * Returns: Parsed RADIUS message or %NULL on failure
- *
- * This parses a RADIUS message and makes a copy of its data. The caller is
- * responsible for freeing the returned data with radius_msg_free().
- */
-struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
-{
-	struct radius_msg *msg;
-	struct radius_hdr *hdr;
-	struct radius_attr_hdr *attr;
-	size_t msg_len;
-	unsigned char *pos, *end;
-
-	if (data == NULL || len < sizeof(*hdr))
-		return NULL;
-
-	hdr = (struct radius_hdr *) data;
-
-	msg_len = ntohs(hdr->length);
-	if (msg_len < sizeof(*hdr) || msg_len > len) {
-		wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
-		return NULL;
-	}
-
-	if (msg_len < len) {
-		wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
-			   "RADIUS message", (unsigned long) len - msg_len);
-	}
-
-	msg = os_zalloc(sizeof(*msg));
-	if (msg == NULL)
-		return NULL;
-
-	msg->buf = wpabuf_alloc_copy(data, msg_len);
-	if (msg->buf == NULL || radius_msg_initialize(msg)) {
-		radius_msg_free(msg);
-		return NULL;
-	}
-	msg->hdr = wpabuf_mhead(msg->buf);
-
-	/* parse attributes */
-	pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
-	end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
-	while (pos < end) {
-		if ((size_t) (end - pos) < sizeof(*attr))
-			goto fail;
-
-		attr = (struct radius_attr_hdr *) pos;
-
-		if (pos + attr->length > end || attr->length < sizeof(*attr))
-			goto fail;
-
-		/* TODO: check that attr->length is suitable for attr->type */
-
-		if (radius_msg_add_attr_to_array(msg, attr))
-			goto fail;
-
-		pos += attr->length;
-	}
-
-	return msg;
-
- fail:
-	radius_msg_free(msg);
-	return NULL;
-}
-
-
-int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
-{
-	const u8 *pos = data;
-	size_t left = data_len;
-
-	while (left > 0) {
-		int len;
-		if (left > RADIUS_MAX_ATTR_LEN)
-			len = RADIUS_MAX_ATTR_LEN;
-		else
-			len = left;
-
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
-					 pos, len))
-			return 0;
-
-		pos += len;
-		left -= len;
-	}
-
-	return 1;
-}
-
-
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
-{
-	u8 *eap, *pos;
-	size_t len, i;
-	struct radius_attr_hdr *attr;
-
-	if (msg == NULL)
-		return NULL;
-
-	len = 0;
-	for (i = 0; i < msg->attr_used; i++) {
-		attr = radius_get_attr_hdr(msg, i);
-		if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
-			len += attr->length - sizeof(struct radius_attr_hdr);
-	}
-
-	if (len == 0)
-		return NULL;
-
-	eap = os_malloc(len);
-	if (eap == NULL)
-		return NULL;
-
-	pos = eap;
-	for (i = 0; i < msg->attr_used; i++) {
-		attr = radius_get_attr_hdr(msg, i);
-		if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
-			int flen = attr->length - sizeof(*attr);
-			os_memcpy(pos, attr + 1, flen);
-			pos += flen;
-		}
-	}
-
-	if (eap_len)
-		*eap_len = len;
-
-	return eap;
-}
-
-
-int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
-			       size_t secret_len, const u8 *req_auth)
-{
-	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
-	u8 orig_authenticator[16];
-	struct radius_attr_hdr *attr = NULL, *tmp;
-	size_t i;
-
-	for (i = 0; i < msg->attr_used; i++) {
-		tmp = radius_get_attr_hdr(msg, i);
-		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
-			if (attr != NULL) {
-				printf("Multiple Message-Authenticator "
-				       "attributes in RADIUS message\n");
-				return 1;
-			}
-			attr = tmp;
-		}
-	}
-
-	if (attr == NULL) {
-		printf("No Message-Authenticator attribute found\n");
-		return 1;
-	}
-
-	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
-	os_memset(attr + 1, 0, MD5_MAC_LEN);
-	if (req_auth) {
-		os_memcpy(orig_authenticator, msg->hdr->authenticator,
-			  sizeof(orig_authenticator));
-		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);
-	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
-	if (req_auth) {
-		os_memcpy(msg->hdr->authenticator, orig_authenticator,
-			  sizeof(orig_authenticator));
-	}
-
-	if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
-		printf("Invalid Message-Authenticator!\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
-		      size_t secret_len, struct radius_msg *sent_msg, int auth)
-{
-	const u8 *addr[4];
-	size_t len[4];
-	u8 hash[MD5_MAC_LEN];
-
-	if (sent_msg == NULL) {
-		printf("No matching Access-Request message found\n");
-		return 1;
-	}
-
-	if (auth &&
-	    radius_msg_verify_msg_auth(msg, secret, secret_len,
-				       sent_msg->hdr->authenticator)) {
-		return 1;
-	}
-
-	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
-	addr[0] = (u8 *) msg->hdr;
-	len[0] = 1 + 1 + 2;
-	addr[1] = sent_msg->hdr->authenticator;
-	len[1] = MD5_MAC_LEN;
-	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
-	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(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
-		printf("Response Authenticator invalid!\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
-			 u8 type)
-{
-	struct radius_attr_hdr *attr;
-	size_t i;
-	int count = 0;
-
-	for (i = 0; i < src->attr_used; i++) {
-		attr = radius_get_attr_hdr(src, i);
-		if (attr->type == type) {
-			if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
-						 attr->length - sizeof(*attr)))
-				return -1;
-			count++;
-		}
-	}
-
-	return count;
-}
-
-
-/* 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)
-{
-	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);
-}
-
-
-/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
- * Returns the Attribute payload and sets alen to indicate the length of the
- * payload if a vendor attribute with subtype is found, otherwise returns NULL.
- * The returned payload is allocated with os_malloc() and caller must free it
- * by calling os_free().
- */
-static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
-				      u8 subtype, size_t *alen)
-{
-	u8 *data, *pos;
-	size_t i, len;
-
-	if (msg == NULL)
-		return NULL;
-
-	for (i = 0; i < msg->attr_used; i++) {
-		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
-		size_t left;
-		u32 vendor_id;
-		struct radius_attr_vendor *vhdr;
-
-		if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
-			continue;
-
-		left = attr->length - sizeof(*attr);
-		if (left < 4)
-			continue;
-
-		pos = (u8 *) (attr + 1);
-
-		os_memcpy(&vendor_id, pos, 4);
-		pos += 4;
-		left -= 4;
-
-		if (ntohl(vendor_id) != vendor)
-			continue;
-
-		while (left >= sizeof(*vhdr)) {
-			vhdr = (struct radius_attr_vendor *) pos;
-			if (vhdr->vendor_length > left ||
-			    vhdr->vendor_length < sizeof(*vhdr)) {
-				left = 0;
-				break;
-			}
-			if (vhdr->vendor_type != subtype) {
-				pos += vhdr->vendor_length;
-				left -= vhdr->vendor_length;
-				continue;
-			}
-
-			len = vhdr->vendor_length - sizeof(*vhdr);
-			data = os_malloc(len);
-			if (data == NULL)
-				return NULL;
-			os_memcpy(data, pos + sizeof(*vhdr), len);
-			if (alen)
-				*alen = len;
-			return data;
-		}
-	}
-
-	return NULL;
-}
-
-
-static u8 * decrypt_ms_key(const u8 *key, size_t len,
-			   const u8 *req_authenticator,
-			   const u8 *secret, size_t secret_len, size_t *reslen)
-{
-	u8 *plain, *ppos, *res;
-	const u8 *pos;
-	size_t left, plen;
-	u8 hash[MD5_MAC_LEN];
-	int i, first = 1;
-	const u8 *addr[3];
-	size_t elen[3];
-
-	/* key: 16-bit salt followed by encrypted key info */
-
-	if (len < 2 + 16)
-		return NULL;
-
-	pos = key + 2;
-	left = len - 2;
-	if (left % 16) {
-		printf("Invalid ms key len %lu\n", (unsigned long) left);
-		return NULL;
-	}
-
-	plen = left;
-	ppos = plain = os_malloc(plen);
-	if (plain == NULL)
-		return NULL;
-	plain[0] = 0;
-
-	while (left > 0) {
-		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
-		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
-
-		addr[0] = secret;
-		elen[0] = secret_len;
-		if (first) {
-			addr[1] = req_authenticator;
-			elen[1] = MD5_MAC_LEN;
-			addr[2] = key;
-			elen[2] = 2; /* Salt */
-		} else {
-			addr[1] = pos - MD5_MAC_LEN;
-			elen[1] = MD5_MAC_LEN;
-		}
-		md5_vector(first ? 3 : 2, addr, elen, hash);
-		first = 0;
-
-		for (i = 0; i < MD5_MAC_LEN; i++)
-			*ppos++ = *pos++ ^ hash[i];
-		left -= MD5_MAC_LEN;
-	}
-
-	if (plain[0] == 0 || plain[0] > plen - 1) {
-		printf("Failed to decrypt MPPE key\n");
-		os_free(plain);
-		return NULL;
-	}
-
-	res = os_malloc(plain[0]);
-	if (res == NULL) {
-		os_free(plain);
-		return NULL;
-	}
-	os_memcpy(res, plain + 1, plain[0]);
-	if (reslen)
-		*reslen = plain[0];
-	os_free(plain);
-	return res;
-}
-
-
-static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
-			   const u8 *req_authenticator,
-			   const u8 *secret, size_t secret_len,
-			   u8 *ebuf, size_t *elen)
-{
-	int i, len, first = 1;
-	u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
-	const u8 *addr[3];
-	size_t _len[3];
-
-	WPA_PUT_BE16(saltbuf, salt);
-
-	len = 1 + key_len;
-	if (len & 0x0f) {
-		len = (len & 0xf0) + 16;
-	}
-	os_memset(ebuf, 0, len);
-	ebuf[0] = key_len;
-	os_memcpy(ebuf + 1, key, key_len);
-
-	*elen = len;
-
-	pos = ebuf;
-	while (len > 0) {
-		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
-		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
-		addr[0] = secret;
-		_len[0] = secret_len;
-		if (first) {
-			addr[1] = req_authenticator;
-			_len[1] = MD5_MAC_LEN;
-			addr[2] = saltbuf;
-			_len[2] = sizeof(saltbuf);
-		} else {
-			addr[1] = pos - MD5_MAC_LEN;
-			_len[1] = MD5_MAC_LEN;
-		}
-		md5_vector(first ? 3 : 2, addr, _len, hash);
-		first = 0;
-
-		for (i = 0; i < MD5_MAC_LEN; i++)
-			*pos++ ^= hash[i];
-
-		len -= MD5_MAC_LEN;
-	}
-}
-
-
-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)
-{
-	u8 *key;
-	size_t keylen;
-	struct radius_ms_mppe_keys *keys;
-
-	if (msg == NULL || sent_msg == NULL)
-		return NULL;
-
-	keys = os_zalloc(sizeof(*keys));
-	if (keys == NULL)
-		return NULL;
-
-	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
-					 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
-					 &keylen);
-	if (key) {
-		keys->send = decrypt_ms_key(key, keylen,
-					    sent_msg->hdr->authenticator,
-					    secret, secret_len,
-					    &keys->send_len);
-		os_free(key);
-	}
-
-	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
-					 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
-					 &keylen);
-	if (key) {
-		keys->recv = decrypt_ms_key(key, keylen,
-					    sent_msg->hdr->authenticator,
-					    secret, secret_len,
-					    &keys->recv_len);
-		os_free(key);
-	}
-
-	return keys;
-}
-
-
-struct radius_ms_mppe_keys *
-radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
-			  const u8 *secret, size_t secret_len)
-{
-	u8 *key;
-	size_t keylen;
-	struct radius_ms_mppe_keys *keys;
-
-	if (msg == NULL || sent_msg == NULL)
-		return NULL;
-
-	keys = os_zalloc(sizeof(*keys));
-	if (keys == NULL)
-		return NULL;
-
-	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
-					 RADIUS_CISCO_AV_PAIR, &keylen);
-	if (key && keylen == 51 &&
-	    os_memcmp(key, "leap:session-key=", 17) == 0) {
-		keys->recv = decrypt_ms_key(key + 17, keylen - 17,
-					    sent_msg->hdr->authenticator,
-					    secret, secret_len,
-					    &keys->recv_len);
-	}
-	os_free(key);
-
-	return keys;
-}
-
-
-int radius_msg_add_mppe_keys(struct radius_msg *msg,
-			     const u8 *req_authenticator,
-			     const u8 *secret, size_t secret_len,
-			     const u8 *send_key, size_t send_key_len,
-			     const u8 *recv_key, size_t recv_key_len)
-{
-	struct radius_attr_hdr *attr;
-	u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
-	u8 *buf;
-	struct radius_attr_vendor *vhdr;
-	u8 *pos;
-	size_t elen;
-	int hlen;
-	u16 salt;
-
-	hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
-
-	/* MS-MPPE-Send-Key */
-	buf = os_malloc(hlen + send_key_len + 16);
-	if (buf == NULL) {
-		return 0;
-	}
-	pos = buf;
-	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
-	pos += sizeof(vendor_id);
-	vhdr = (struct radius_attr_vendor *) pos;
-	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
-	pos = (u8 *) (vhdr + 1);
-	salt = os_random() | 0x8000;
-	WPA_PUT_BE16(pos, salt);
-	pos += 2;
-	encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
-		       secret_len, pos, &elen);
-	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
-
-	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
-				   buf, hlen + elen);
-	os_free(buf);
-	if (attr == NULL) {
-		return 0;
-	}
-
-	/* MS-MPPE-Recv-Key */
-	buf = os_malloc(hlen + send_key_len + 16);
-	if (buf == NULL) {
-		return 0;
-	}
-	pos = buf;
-	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
-	pos += sizeof(vendor_id);
-	vhdr = (struct radius_attr_vendor *) pos;
-	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
-	pos = (u8 *) (vhdr + 1);
-	salt ^= 1;
-	WPA_PUT_BE16(pos, salt);
-	pos += 2;
-	encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
-		       secret_len, pos, &elen);
-	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
-
-	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
-				   buf, hlen + elen);
-	os_free(buf);
-	if (attr == NULL) {
-		return 0;
-	}
-
-	return 1;
-}
-
-
-/* Add User-Password attribute to a RADIUS message and encrypt it as specified
- * in RFC 2865, Chap. 5.2 */
-struct radius_attr_hdr *
-radius_msg_add_attr_user_password(struct radius_msg *msg,
-				  const u8 *data, size_t data_len,
-				  const u8 *secret, size_t secret_len)
-{
-	u8 buf[128];
-	int padlen, i;
-	size_t buf_len, pos;
-	const u8 *addr[2];
-	size_t len[2];
-	u8 hash[16];
-
-	if (data_len > 128)
-		return NULL;
-
-	os_memcpy(buf, data, data_len);
-	buf_len = data_len;
-
-	padlen = data_len % 16;
-	if (padlen) {
-		padlen = 16 - padlen;
-		os_memset(buf + data_len, 0, padlen);
-		buf_len += padlen;
-	}
-
-	addr[0] = secret;
-	len[0] = secret_len;
-	addr[1] = msg->hdr->authenticator;
-	len[1] = 16;
-	md5_vector(2, addr, len, hash);
-
-	for (i = 0; i < 16; i++)
-		buf[i] ^= hash[i];
-	pos = 16;
-
-	while (pos < buf_len) {
-		addr[0] = secret;
-		len[0] = secret_len;
-		addr[1] = &buf[pos - 16];
-		len[1] = 16;
-		md5_vector(2, addr, len, hash);
-
-		for (i = 0; i < 16; i++)
-			buf[pos + i] ^= hash[i];
-
-		pos += 16;
-	}
-
-	return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
-				   buf, buf_len);
-}
-
-
-int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
-{
-	struct radius_attr_hdr *attr = NULL, *tmp;
-	size_t i, dlen;
-
-	for (i = 0; i < msg->attr_used; i++) {
-		tmp = radius_get_attr_hdr(msg, i);
-		if (tmp->type == type) {
-			attr = tmp;
-			break;
-		}
-	}
-
-	if (!attr)
-		return -1;
-
-	dlen = attr->length - sizeof(*attr);
-	if (buf)
-		os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
-	return dlen;
-}
-
-
-int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
-			    size_t *len, const u8 *start)
-{
-	size_t i;
-	struct radius_attr_hdr *attr = NULL, *tmp;
-
-	for (i = 0; i < msg->attr_used; i++) {
-		tmp = radius_get_attr_hdr(msg, i);
-		if (tmp->type == type &&
-		    (start == NULL || (u8 *) tmp > start)) {
-			attr = tmp;
-			break;
-		}
-	}
-
-	if (!attr)
-		return -1;
-
-	*buf = (u8 *) (attr + 1);
-	*len = attr->length - sizeof(*attr);
-	return 0;
-}
-
-
-int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
-{
-	size_t i;
-	int count;
-
-	for (count = 0, i = 0; i < msg->attr_used; i++) {
-		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
-		if (attr->type == type &&
-		    attr->length >= sizeof(struct radius_attr_hdr) + min_len)
-			count++;
-	}
-
-	return count;
-}
-
-
-struct radius_tunnel_attrs {
-	int tag_used;
-	int type; /* Tunnel-Type */
-	int medium_type; /* Tunnel-Medium-Type */
-	int vlanid;
-};
-
-
-/**
- * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
- * @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
- */
-int radius_msg_get_vlanid(struct radius_msg *msg)
-{
-	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
-	size_t i;
-	struct radius_attr_hdr *attr = NULL;
-	const u8 *data;
-	char buf[10];
-	size_t dlen;
-
-	os_memset(&tunnel, 0, sizeof(tunnel));
-
-	for (i = 0; i < msg->attr_used; i++) {
-		attr = radius_get_attr_hdr(msg, i);
-		data = (const u8 *) (attr + 1);
-		dlen = attr->length - sizeof(*attr);
-		if (attr->length < 3)
-			continue;
-		if (data[0] >= RADIUS_TUNNEL_TAGS)
-			tun = &tunnel[0];
-		else
-			tun = &tunnel[data[0]];
-
-		switch (attr->type) {
-		case RADIUS_ATTR_TUNNEL_TYPE:
-			if (attr->length != 6)
-				break;
-			tun->tag_used++;
-			tun->type = WPA_GET_BE24(data + 1);
-			break;
-		case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
-			if (attr->length != 6)
-				break;
-			tun->tag_used++;
-			tun->medium_type = WPA_GET_BE24(data + 1);
-			break;
-		case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
-			if (data[0] < RADIUS_TUNNEL_TAGS) {
-				data++;
-				dlen--;
-			}
-			if (dlen >= sizeof(buf))
-				break;
-			os_memcpy(buf, data, dlen);
-			buf[dlen] = '\0';
-			tun->tag_used++;
-			tun->vlanid = atoi(buf);
-			break;
-		}
-	}
-
-	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;
-	}
-
-	return -1;
-}
-
-
-void radius_free_class(struct radius_class_data *c)
-{
-	size_t i;
-	if (c == NULL)
-		return;
-	for (i = 0; i < c->count; i++)
-		os_free(c->attr[i].data);
-	os_free(c->attr);
-	c->attr = NULL;
-	c->count = 0;
-}
-
-
-int radius_copy_class(struct radius_class_data *dst,
-		      const struct radius_class_data *src)
-{
-	size_t i;
-
-	if (src->attr == NULL)
-		return 0;
-
-	dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
-	if (dst->attr == NULL)
-		return -1;
-
-	dst->count = 0;
-
-	for (i = 0; i < src->count; i++) {
-		dst->attr[i].data = os_malloc(src->attr[i].len);
-		if (dst->attr[i].data == NULL)
-			break;
-		dst->count++;
-		os_memcpy(dst->attr[i].data, src->attr[i].data,
-			  src->attr[i].len);
-		dst->attr[i].len = src->attr[i].len;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/radius/radius.c (from rev 9639, vendor/wpa/dist/src/radius/radius.c)
===================================================================
--- vendor/wpa/2.0/src/radius/radius.c	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1578 @@
+/*
+ * RADIUS message processing
+ * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j at 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 "utils/wpabuf.h"
+#include "crypto/md5.h"
+#include "crypto/crypto.h"
+#include "radius.h"
+
+
+/**
+ * struct radius_msg - RADIUS message structure for new and parsed messages
+ */
+struct radius_msg {
+	/**
+	 * buf - Allocated buffer for RADIUS message
+	 */
+	struct wpabuf *buf;
+
+	/**
+	 * hdr - Pointer to the RADIUS header in buf
+	 */
+	struct radius_hdr *hdr;
+
+	/**
+	 * attr_pos - Array of indexes to attributes
+	 *
+	 * The values are number of bytes from buf to the beginning of
+	 * struct radius_attr_hdr.
+	 */
+	size_t *attr_pos;
+
+	/**
+	 * attr_size - Total size of the attribute pointer array
+	 */
+	size_t attr_size;
+
+	/**
+	 * attr_used - Total number of attributes in the array
+	 */
+	size_t attr_used;
+};
+
+
+struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
+{
+	return msg->hdr;
+}
+
+
+struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
+{
+	return msg->buf;
+}
+
+
+static struct radius_attr_hdr *
+radius_get_attr_hdr(struct radius_msg *msg, int idx)
+{
+	return (struct radius_attr_hdr *)
+		(wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
+}
+
+
+static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
+{
+	msg->hdr->code = code;
+	msg->hdr->identifier = identifier;
+}
+
+
+static int radius_msg_initialize(struct radius_msg *msg)
+{
+	msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
+				  sizeof(*msg->attr_pos));
+	if (msg->attr_pos == NULL)
+		return -1;
+
+	msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
+	msg->attr_used = 0;
+
+	return 0;
+}
+
+
+/**
+ * radius_msg_new - Create a new RADIUS message
+ * @code: Code for RADIUS header
+ * @identifier: Identifier for RADIUS header
+ * Returns: Context for RADIUS message or %NULL on failure
+ *
+ * The caller is responsible for freeing the returned data with
+ * radius_msg_free().
+ */
+struct radius_msg * radius_msg_new(u8 code, u8 identifier)
+{
+	struct radius_msg *msg;
+
+	msg = os_zalloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
+	if (msg->buf == NULL || radius_msg_initialize(msg)) {
+		radius_msg_free(msg);
+		return NULL;
+	}
+	msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
+
+	radius_msg_set_hdr(msg, code, identifier);
+
+	return msg;
+}
+
+
+/**
+ * radius_msg_free - Free a RADIUS message
+ * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
+ */
+void radius_msg_free(struct radius_msg *msg)
+{
+	if (msg == NULL)
+		return;
+
+	wpabuf_free(msg->buf);
+	os_free(msg->attr_pos);
+	os_free(msg);
+}
+
+
+static const char *radius_code_string(u8 code)
+{
+	switch (code) {
+	case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
+	case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
+	case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
+	case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
+	case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
+	case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
+	case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
+	case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
+	case RADIUS_CODE_RESERVED: return "Reserved";
+	case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
+	case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
+	case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
+	case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
+	case RADIUS_CODE_COA_ACK: return "CoA-ACK";
+	case RADIUS_CODE_COA_NAK: return "CoA-NAK";
+	default: return "?Unknown?";
+	}
+}
+
+
+struct radius_attr_type {
+	u8 type;
+	char *name;
+	enum {
+		RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
+		RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
+	} data_type;
+};
+
+static struct radius_attr_type radius_attrs[] =
+{
+	{ RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
+	{ 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_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_CLASS, "Class", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
+	  RADIUS_ATTR_INT32 },
+	{ 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",
+	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
+	  RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
+	  RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
+	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
+	{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
+};
+#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+
+
+static struct radius_attr_type *radius_get_attr_type(u8 type)
+{
+	size_t i;
+
+	for (i = 0; i < RADIUS_ATTRS; i++) {
+		if (type == radius_attrs[i].type)
+			return &radius_attrs[i];
+	}
+
+	return NULL;
+}
+
+
+static void print_char(char c)
+{
+	if (c >= 32 && c < 127)
+		printf("%c", c);
+	else
+		printf("<%02x>", c);
+}
+
+
+static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
+{
+	struct radius_attr_type *attr;
+	int i, len;
+	unsigned char *pos;
+
+	attr = radius_get_attr_type(hdr->type);
+
+	printf("   Attribute %d (%s) length=%d\n",
+	       hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+
+	if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
+		return;
+
+	len = hdr->length - sizeof(struct radius_attr_hdr);
+	pos = (unsigned char *) (hdr + 1);
+
+	switch (attr->data_type) {
+	case RADIUS_ATTR_TEXT:
+		printf("      Value: '");
+		for (i = 0; i < len; i++)
+			print_char(pos[i]);
+		printf("'\n");
+		break;
+
+	case RADIUS_ATTR_IP:
+		if (len == 4) {
+			struct in_addr addr;
+			os_memcpy(&addr, pos, 4);
+			printf("      Value: %s\n", inet_ntoa(addr));
+		} else
+			printf("      Invalid IP address length %d\n", len);
+		break;
+
+#ifdef CONFIG_IPV6
+	case RADIUS_ATTR_IPV6:
+		if (len == 16) {
+			char buf[128];
+			const char *atxt;
+			struct in6_addr *addr = (struct in6_addr *) pos;
+			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
+			printf("      Value: %s\n", atxt ? atxt : "?");
+		} else
+			printf("      Invalid IPv6 address length %d\n", len);
+		break;
+#endif /* CONFIG_IPV6 */
+
+	case RADIUS_ATTR_HEXDUMP:
+	case RADIUS_ATTR_UNDIST:
+		printf("      Value:");
+		for (i = 0; i < len; i++)
+			printf(" %02x", pos[i]);
+		printf("\n");
+		break;
+
+	case RADIUS_ATTR_INT32:
+		if (len == 4)
+			printf("      Value: %u\n", WPA_GET_BE32(pos));
+		else
+			printf("      Invalid INT32 length %d\n", len);
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+void radius_msg_dump(struct radius_msg *msg)
+{
+	size_t i;
+
+	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
+	       msg->hdr->code, radius_code_string(msg->hdr->code),
+	       msg->hdr->identifier, be_to_host16(msg->hdr->length));
+
+	for (i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		radius_msg_dump_attr(attr);
+	}
+}
+
+
+int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len)
+{
+	if (secret) {
+		u8 auth[MD5_MAC_LEN];
+		struct radius_attr_hdr *attr;
+
+		os_memset(auth, 0, MD5_MAC_LEN);
+		attr = radius_msg_add_attr(msg,
+					   RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+					   auth, MD5_MAC_LEN);
+		if (attr == NULL) {
+			wpa_printf(MSG_WARNING, "RADIUS: Could not add "
+				   "Message-Authenticator");
+			return -1;
+		}
+		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+		hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+			 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+	} else
+		msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+
+	if (wpabuf_len(msg->buf) > 0xffff) {
+		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+			   (unsigned long) wpabuf_len(msg->buf));
+		return -1;
+	}
+	return 0;
+}
+
+
+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
+			  size_t secret_len, const u8 *req_authenticator)
+{
+	u8 auth[MD5_MAC_LEN];
+	struct radius_attr_hdr *attr;
+	const u8 *addr[4];
+	size_t len[4];
+
+	os_memset(auth, 0, MD5_MAC_LEN);
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+				   auth, MD5_MAC_LEN);
+	if (attr == NULL) {
+		printf("WARNING: Could not add Message-Authenticator\n");
+		return -1;
+	}
+	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+	os_memcpy(msg->hdr->authenticator, req_authenticator,
+		  sizeof(msg->hdr->authenticator));
+	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+		 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = 1 + 1 + 2;
+	addr[1] = req_authenticator;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
+	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+	addr[3] = secret;
+	len[3] = secret_len;
+	md5_vector(4, addr, len, msg->hdr->authenticator);
+
+	if (wpabuf_len(msg->buf) > 0xffff) {
+		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+			   (unsigned long) wpabuf_len(msg->buf));
+		return -1;
+	}
+	return 0;
+}
+
+
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len,
+			       const struct radius_hdr *req_hdr)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	u8 auth[MD5_MAC_LEN];
+	struct radius_attr_hdr *attr;
+
+	os_memset(auth, 0, MD5_MAC_LEN);
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+				   auth, MD5_MAC_LEN);
+	if (attr == NULL) {
+		wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
+		return -1;
+	}
+
+	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+	os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
+	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+		 wpabuf_len(msg->buf), (u8 *) (attr + 1));
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	addr[0] = wpabuf_head_u8(msg->buf);
+	len[0] = wpabuf_len(msg->buf);
+	addr[1] = secret;
+	len[1] = secret_len;
+	if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
+		return -1;
+
+	if (wpabuf_len(msg->buf) > 0xffff) {
+		wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+			   (unsigned long) wpabuf_len(msg->buf));
+		return -1;
+	}
+	return 0;
+}
+
+
+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
+			    size_t secret_len)
+{
+	const u8 *addr[2];
+	size_t len[2];
+
+	msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
+	addr[0] = wpabuf_head(msg->buf);
+	len[0] = wpabuf_len(msg->buf);
+	addr[1] = secret;
+	len[1] = secret_len;
+	md5_vector(2, addr, len, msg->hdr->authenticator);
+
+	if (wpabuf_len(msg->buf) > 0xffff) {
+		wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+			   (unsigned long) wpabuf_len(msg->buf));
+	}
+}
+
+
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len)
+{
+	const u8 *addr[4];
+	size_t len[4];
+	u8 zero[MD5_MAC_LEN];
+	u8 hash[MD5_MAC_LEN];
+
+	os_memset(zero, 0, sizeof(zero));
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+	addr[1] = zero;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = (u8 *) (msg->hdr + 1);
+	len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+	addr[3] = secret;
+	len[3] = secret_len;
+	md5_vector(4, addr, len, hash);
+	return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+}
+
+
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+			      size_t secret_len)
+{
+	const u8 *addr[4];
+	size_t len[4];
+	u8 zero[MD5_MAC_LEN];
+	u8 hash[MD5_MAC_LEN];
+	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+	u8 orig_authenticator[16];
+
+	struct radius_attr_hdr *attr = NULL, *tmp;
+	size_t i;
+
+	os_memset(zero, 0, sizeof(zero));
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+	addr[1] = zero;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = (u8 *) (msg->hdr + 1);
+	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(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+		return 1;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+			if (attr != NULL) {
+				wpa_printf(MSG_WARNING, "Multiple "
+					   "Message-Authenticator attributes "
+					   "in RADIUS message");
+				return 1;
+			}
+			attr = tmp;
+		}
+	}
+
+	if (attr == NULL) {
+		/* Message-Authenticator is MAY; not required */
+		return 0;
+	}
+
+	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+	os_memset(attr + 1, 0, MD5_MAC_LEN);
+	os_memcpy(orig_authenticator, msg->hdr->authenticator,
+		  sizeof(orig_authenticator));
+	os_memset(msg->hdr->authenticator, 0,
+		  sizeof(msg->hdr->authenticator));
+	hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+		 wpabuf_len(msg->buf), auth);
+	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+	os_memcpy(msg->hdr->authenticator, orig_authenticator,
+		  sizeof(orig_authenticator));
+
+	return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+}
+
+
+static int radius_msg_add_attr_to_array(struct radius_msg *msg,
+					struct radius_attr_hdr *attr)
+{
+	if (msg->attr_used >= msg->attr_size) {
+		size_t *nattr_pos;
+		int nlen = msg->attr_size * 2;
+
+		nattr_pos = os_realloc_array(msg->attr_pos, nlen,
+					     sizeof(*msg->attr_pos));
+		if (nattr_pos == NULL)
+			return -1;
+
+		msg->attr_pos = nattr_pos;
+		msg->attr_size = nlen;
+	}
+
+	msg->attr_pos[msg->attr_used++] =
+		(unsigned char *) attr - wpabuf_head_u8(msg->buf);
+
+	return 0;
+}
+
+
+struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
+					    const u8 *data, size_t data_len)
+{
+	size_t buf_needed;
+	struct radius_attr_hdr *attr;
+
+	if (data_len > RADIUS_MAX_ATTR_LEN) {
+		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+		       (unsigned long) data_len);
+		return NULL;
+	}
+
+	buf_needed = sizeof(*attr) + data_len;
+
+	if (wpabuf_tailroom(msg->buf) < buf_needed) {
+		/* allocate more space for message buffer */
+		if (wpabuf_resize(&msg->buf, buf_needed) < 0)
+			return NULL;
+		msg->hdr = wpabuf_mhead(msg->buf);
+	}
+
+	attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
+	attr->type = type;
+	attr->length = sizeof(*attr) + data_len;
+	wpabuf_put_data(msg->buf, data, data_len);
+
+	if (radius_msg_add_attr_to_array(msg, attr))
+		return NULL;
+
+	return attr;
+}
+
+
+/**
+ * radius_msg_parse - Parse a RADIUS message
+ * @data: RADIUS message to be parsed
+ * @len: Length of data buffer in octets
+ * Returns: Parsed RADIUS message or %NULL on failure
+ *
+ * This parses a RADIUS message and makes a copy of its data. The caller is
+ * responsible for freeing the returned data with radius_msg_free().
+ */
+struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
+{
+	struct radius_msg *msg;
+	struct radius_hdr *hdr;
+	struct radius_attr_hdr *attr;
+	size_t msg_len;
+	unsigned char *pos, *end;
+
+	if (data == NULL || len < sizeof(*hdr))
+		return NULL;
+
+	hdr = (struct radius_hdr *) data;
+
+	msg_len = be_to_host16(hdr->length);
+	if (msg_len < sizeof(*hdr) || msg_len > len) {
+		wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
+		return NULL;
+	}
+
+	if (msg_len < len) {
+		wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
+			   "RADIUS message", (unsigned long) len - msg_len);
+	}
+
+	msg = os_zalloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	msg->buf = wpabuf_alloc_copy(data, msg_len);
+	if (msg->buf == NULL || radius_msg_initialize(msg)) {
+		radius_msg_free(msg);
+		return NULL;
+	}
+	msg->hdr = wpabuf_mhead(msg->buf);
+
+	/* parse attributes */
+	pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
+	end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
+	while (pos < end) {
+		if ((size_t) (end - pos) < sizeof(*attr))
+			goto fail;
+
+		attr = (struct radius_attr_hdr *) pos;
+
+		if (pos + attr->length > end || attr->length < sizeof(*attr))
+			goto fail;
+
+		/* TODO: check that attr->length is suitable for attr->type */
+
+		if (radius_msg_add_attr_to_array(msg, attr))
+			goto fail;
+
+		pos += attr->length;
+	}
+
+	return msg;
+
+ fail:
+	radius_msg_free(msg);
+	return NULL;
+}
+
+
+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
+{
+	const u8 *pos = data;
+	size_t left = data_len;
+
+	while (left > 0) {
+		int len;
+		if (left > RADIUS_MAX_ATTR_LEN)
+			len = RADIUS_MAX_ATTR_LEN;
+		else
+			len = left;
+
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
+					 pos, len))
+			return 0;
+
+		pos += len;
+		left -= len;
+	}
+
+	return 1;
+}
+
+
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
+{
+	struct wpabuf *eap;
+	size_t len, i;
+	struct radius_attr_hdr *attr;
+
+	if (msg == NULL)
+		return NULL;
+
+	len = 0;
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+		    attr->length > sizeof(struct radius_attr_hdr))
+			len += attr->length - sizeof(struct radius_attr_hdr);
+	}
+
+	if (len == 0)
+		return NULL;
+
+	eap = wpabuf_alloc(len);
+	if (eap == NULL)
+		return NULL;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+		    attr->length > sizeof(struct radius_attr_hdr)) {
+			int flen = attr->length - sizeof(*attr);
+			wpabuf_put_data(eap, attr + 1, flen);
+		}
+	}
+
+	return eap;
+}
+
+
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len, const u8 *req_auth)
+{
+	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+	u8 orig_authenticator[16];
+	struct radius_attr_hdr *attr = NULL, *tmp;
+	size_t i;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+			if (attr != NULL) {
+				printf("Multiple Message-Authenticator "
+				       "attributes in RADIUS message\n");
+				return 1;
+			}
+			attr = tmp;
+		}
+	}
+
+	if (attr == NULL) {
+		printf("No Message-Authenticator attribute found\n");
+		return 1;
+	}
+
+	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+	os_memset(attr + 1, 0, MD5_MAC_LEN);
+	if (req_auth) {
+		os_memcpy(orig_authenticator, msg->hdr->authenticator,
+			  sizeof(orig_authenticator));
+		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);
+	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+	if (req_auth) {
+		os_memcpy(msg->hdr->authenticator, orig_authenticator,
+			  sizeof(orig_authenticator));
+	}
+
+	if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+		printf("Invalid Message-Authenticator!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len, struct radius_msg *sent_msg, int auth)
+{
+	const u8 *addr[4];
+	size_t len[4];
+	u8 hash[MD5_MAC_LEN];
+
+	if (sent_msg == NULL) {
+		printf("No matching Access-Request message found\n");
+		return 1;
+	}
+
+	if (auth &&
+	    radius_msg_verify_msg_auth(msg, secret, secret_len,
+				       sent_msg->hdr->authenticator)) {
+		return 1;
+	}
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = 1 + 1 + 2;
+	addr[1] = sent_msg->hdr->authenticator;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
+	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(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+		printf("Response Authenticator invalid!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+			 u8 type)
+{
+	struct radius_attr_hdr *attr;
+	size_t i;
+	int count = 0;
+
+	for (i = 0; i < src->attr_used; i++) {
+		attr = radius_get_attr_hdr(src, i);
+		if (attr->type == type && attr->length >= sizeof(*attr)) {
+			if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
+						 attr->length - sizeof(*attr)))
+				return -1;
+			count++;
+		}
+	}
+
+	return count;
+}
+
+
+/* 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)
+{
+	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);
+}
+
+
+/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
+ * Returns the Attribute payload and sets alen to indicate the length of the
+ * payload if a vendor attribute with subtype is found, otherwise returns NULL.
+ * The returned payload is allocated with os_malloc() and caller must free it
+ * by calling os_free().
+ */
+static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
+				      u8 subtype, size_t *alen)
+{
+	u8 *data, *pos;
+	size_t i, len;
+
+	if (msg == NULL)
+		return NULL;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		size_t left;
+		u32 vendor_id;
+		struct radius_attr_vendor *vhdr;
+
+		if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
+		    attr->length < sizeof(*attr))
+			continue;
+
+		left = attr->length - sizeof(*attr);
+		if (left < 4)
+			continue;
+
+		pos = (u8 *) (attr + 1);
+
+		os_memcpy(&vendor_id, pos, 4);
+		pos += 4;
+		left -= 4;
+
+		if (ntohl(vendor_id) != vendor)
+			continue;
+
+		while (left >= sizeof(*vhdr)) {
+			vhdr = (struct radius_attr_vendor *) pos;
+			if (vhdr->vendor_length > left ||
+			    vhdr->vendor_length < sizeof(*vhdr)) {
+				left = 0;
+				break;
+			}
+			if (vhdr->vendor_type != subtype) {
+				pos += vhdr->vendor_length;
+				left -= vhdr->vendor_length;
+				continue;
+			}
+
+			len = vhdr->vendor_length - sizeof(*vhdr);
+			data = os_malloc(len);
+			if (data == NULL)
+				return NULL;
+			os_memcpy(data, pos + sizeof(*vhdr), len);
+			if (alen)
+				*alen = len;
+			return data;
+		}
+	}
+
+	return NULL;
+}
+
+
+static u8 * decrypt_ms_key(const u8 *key, size_t len,
+			   const u8 *req_authenticator,
+			   const u8 *secret, size_t secret_len, size_t *reslen)
+{
+	u8 *plain, *ppos, *res;
+	const u8 *pos;
+	size_t left, plen;
+	u8 hash[MD5_MAC_LEN];
+	int i, first = 1;
+	const u8 *addr[3];
+	size_t elen[3];
+
+	/* key: 16-bit salt followed by encrypted key info */
+
+	if (len < 2 + 16)
+		return NULL;
+
+	pos = key + 2;
+	left = len - 2;
+	if (left % 16) {
+		printf("Invalid ms key len %lu\n", (unsigned long) left);
+		return NULL;
+	}
+
+	plen = left;
+	ppos = plain = os_malloc(plen);
+	if (plain == NULL)
+		return NULL;
+	plain[0] = 0;
+
+	while (left > 0) {
+		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
+		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+
+		addr[0] = secret;
+		elen[0] = secret_len;
+		if (first) {
+			addr[1] = req_authenticator;
+			elen[1] = MD5_MAC_LEN;
+			addr[2] = key;
+			elen[2] = 2; /* Salt */
+		} else {
+			addr[1] = pos - MD5_MAC_LEN;
+			elen[1] = MD5_MAC_LEN;
+		}
+		md5_vector(first ? 3 : 2, addr, elen, hash);
+		first = 0;
+
+		for (i = 0; i < MD5_MAC_LEN; i++)
+			*ppos++ = *pos++ ^ hash[i];
+		left -= MD5_MAC_LEN;
+	}
+
+	if (plain[0] == 0 || plain[0] > plen - 1) {
+		printf("Failed to decrypt MPPE key\n");
+		os_free(plain);
+		return NULL;
+	}
+
+	res = os_malloc(plain[0]);
+	if (res == NULL) {
+		os_free(plain);
+		return NULL;
+	}
+	os_memcpy(res, plain + 1, plain[0]);
+	if (reslen)
+		*reslen = plain[0];
+	os_free(plain);
+	return res;
+}
+
+
+static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
+			   const u8 *req_authenticator,
+			   const u8 *secret, size_t secret_len,
+			   u8 *ebuf, size_t *elen)
+{
+	int i, len, first = 1;
+	u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
+	const u8 *addr[3];
+	size_t _len[3];
+
+	WPA_PUT_BE16(saltbuf, salt);
+
+	len = 1 + key_len;
+	if (len & 0x0f) {
+		len = (len & 0xf0) + 16;
+	}
+	os_memset(ebuf, 0, len);
+	ebuf[0] = key_len;
+	os_memcpy(ebuf + 1, key, key_len);
+
+	*elen = len;
+
+	pos = ebuf;
+	while (len > 0) {
+		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
+		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+		addr[0] = secret;
+		_len[0] = secret_len;
+		if (first) {
+			addr[1] = req_authenticator;
+			_len[1] = MD5_MAC_LEN;
+			addr[2] = saltbuf;
+			_len[2] = sizeof(saltbuf);
+		} else {
+			addr[1] = pos - MD5_MAC_LEN;
+			_len[1] = MD5_MAC_LEN;
+		}
+		md5_vector(first ? 3 : 2, addr, _len, hash);
+		first = 0;
+
+		for (i = 0; i < MD5_MAC_LEN; i++)
+			*pos++ ^= hash[i];
+
+		len -= MD5_MAC_LEN;
+	}
+}
+
+
+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)
+{
+	u8 *key;
+	size_t keylen;
+	struct radius_ms_mppe_keys *keys;
+
+	if (msg == NULL || sent_msg == NULL)
+		return NULL;
+
+	keys = os_zalloc(sizeof(*keys));
+	if (keys == NULL)
+		return NULL;
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+					 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
+					 &keylen);
+	if (key) {
+		keys->send = decrypt_ms_key(key, keylen,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->send_len);
+		os_free(key);
+	}
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+					 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
+					 &keylen);
+	if (key) {
+		keys->recv = decrypt_ms_key(key, keylen,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->recv_len);
+		os_free(key);
+	}
+
+	return keys;
+}
+
+
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+			  const u8 *secret, size_t secret_len)
+{
+	u8 *key;
+	size_t keylen;
+	struct radius_ms_mppe_keys *keys;
+
+	if (msg == NULL || sent_msg == NULL)
+		return NULL;
+
+	keys = os_zalloc(sizeof(*keys));
+	if (keys == NULL)
+		return NULL;
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
+					 RADIUS_CISCO_AV_PAIR, &keylen);
+	if (key && keylen == 51 &&
+	    os_memcmp(key, "leap:session-key=", 17) == 0) {
+		keys->recv = decrypt_ms_key(key + 17, keylen - 17,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->recv_len);
+	}
+	os_free(key);
+
+	return keys;
+}
+
+
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+			     const u8 *req_authenticator,
+			     const u8 *secret, size_t secret_len,
+			     const u8 *send_key, size_t send_key_len,
+			     const u8 *recv_key, size_t recv_key_len)
+{
+	struct radius_attr_hdr *attr;
+	u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
+	u8 *buf;
+	struct radius_attr_vendor *vhdr;
+	u8 *pos;
+	size_t elen;
+	int hlen;
+	u16 salt;
+
+	hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
+
+	/* MS-MPPE-Send-Key */
+	buf = os_malloc(hlen + send_key_len + 16);
+	if (buf == NULL) {
+		return 0;
+	}
+	pos = buf;
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
+	pos += sizeof(vendor_id);
+	vhdr = (struct radius_attr_vendor *) pos;
+	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
+	pos = (u8 *) (vhdr + 1);
+	salt = os_random() | 0x8000;
+	WPA_PUT_BE16(pos, salt);
+	pos += 2;
+	encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
+		       secret_len, pos, &elen);
+	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+				   buf, hlen + elen);
+	os_free(buf);
+	if (attr == NULL) {
+		return 0;
+	}
+
+	/* MS-MPPE-Recv-Key */
+	buf = os_malloc(hlen + send_key_len + 16);
+	if (buf == NULL) {
+		return 0;
+	}
+	pos = buf;
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
+	pos += sizeof(vendor_id);
+	vhdr = (struct radius_attr_vendor *) pos;
+	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
+	pos = (u8 *) (vhdr + 1);
+	salt ^= 1;
+	WPA_PUT_BE16(pos, salt);
+	pos += 2;
+	encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
+		       secret_len, pos, &elen);
+	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+				   buf, hlen + elen);
+	os_free(buf);
+	if (attr == NULL) {
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  const u8 *data, size_t data_len,
+				  const u8 *secret, size_t secret_len)
+{
+	u8 buf[128];
+	size_t padlen, i, buf_len, pos;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 hash[16];
+
+	if (data_len > 128)
+		return NULL;
+
+	os_memcpy(buf, data, data_len);
+	buf_len = data_len;
+
+	padlen = data_len % 16;
+	if (padlen && data_len < sizeof(buf)) {
+		padlen = 16 - padlen;
+		os_memset(buf + data_len, 0, padlen);
+		buf_len += padlen;
+	}
+
+	addr[0] = secret;
+	len[0] = secret_len;
+	addr[1] = msg->hdr->authenticator;
+	len[1] = 16;
+	md5_vector(2, addr, len, hash);
+
+	for (i = 0; i < 16; i++)
+		buf[i] ^= hash[i];
+	pos = 16;
+
+	while (pos < buf_len) {
+		addr[0] = secret;
+		len[0] = secret_len;
+		addr[1] = &buf[pos - 16];
+		len[1] = 16;
+		md5_vector(2, addr, len, hash);
+
+		for (i = 0; i < 16; i++)
+			buf[pos + i] ^= hash[i];
+
+		pos += 16;
+	}
+
+	return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
+				   buf, buf_len);
+}
+
+
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
+{
+	struct radius_attr_hdr *attr = NULL, *tmp;
+	size_t i, dlen;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == type) {
+			attr = tmp;
+			break;
+		}
+	}
+
+	if (!attr || attr->length < sizeof(*attr))
+		return -1;
+
+	dlen = attr->length - sizeof(*attr);
+	if (buf)
+		os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+	return dlen;
+}
+
+
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+			    size_t *len, const u8 *start)
+{
+	size_t i;
+	struct radius_attr_hdr *attr = NULL, *tmp;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == type &&
+		    (start == NULL || (u8 *) tmp > start)) {
+			attr = tmp;
+			break;
+		}
+	}
+
+	if (!attr || attr->length < sizeof(*attr))
+		return -1;
+
+	*buf = (u8 *) (attr + 1);
+	*len = attr->length - sizeof(*attr);
+	return 0;
+}
+
+
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
+{
+	size_t i;
+	int count;
+
+	for (count = 0, i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == type &&
+		    attr->length >= sizeof(struct radius_attr_hdr) + min_len)
+			count++;
+	}
+
+	return count;
+}
+
+
+struct radius_tunnel_attrs {
+	int tag_used;
+	int type; /* Tunnel-Type */
+	int medium_type; /* Tunnel-Medium-Type */
+	int vlanid;
+};
+
+
+/**
+ * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * @msg: RADIUS message
+ * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ */
+int radius_msg_get_vlanid(struct radius_msg *msg)
+{
+	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
+	size_t i;
+	struct radius_attr_hdr *attr = NULL;
+	const u8 *data;
+	char buf[10];
+	size_t dlen;
+
+	os_memset(&tunnel, 0, sizeof(tunnel));
+
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr->length < sizeof(*attr))
+			return -1;
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (attr->length < 3)
+			continue;
+		if (data[0] >= RADIUS_TUNNEL_TAGS)
+			tun = &tunnel[0];
+		else
+			tun = &tunnel[data[0]];
+
+		switch (attr->type) {
+		case RADIUS_ATTR_TUNNEL_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->type = WPA_GET_BE24(data + 1);
+			break;
+		case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->medium_type = WPA_GET_BE24(data + 1);
+			break;
+		case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
+			if (data[0] < RADIUS_TUNNEL_TAGS) {
+				data++;
+				dlen--;
+			}
+			if (dlen >= sizeof(buf))
+				break;
+			os_memcpy(buf, data, dlen);
+			buf[dlen] = '\0';
+			tun->tag_used++;
+			tun->vlanid = atoi(buf);
+			break;
+		}
+	}
+
+	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;
+	}
+
+	return -1;
+}
+
+
+/**
+ * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
+ * @msg: Received RADIUS message
+ * @keylen: Length of returned password
+ * @secret: RADIUS shared secret
+ * @secret_len: Length of secret
+ * @sent_msg: Sent RADIUS message
+ * @n: Number of password attribute to return (starting with 0)
+ * Returns: Pointer to n-th password (free with os_free) or %NULL
+ */
+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)
+{
+	u8 *buf = NULL;
+	size_t buflen;
+	const u8 *salt;
+	u8 *str;
+	const u8 *addr[3];
+	size_t len[3];
+	u8 hash[16];
+	u8 *pos;
+	size_t i, j = 0;
+	struct radius_attr_hdr *attr;
+	const u8 *data;
+	size_t dlen;
+	const u8 *fdata = NULL; /* points to found item */
+	size_t fdlen = -1;
+	char *ret = NULL;
+
+	/* find n-th valid Tunnel-Password attribute */
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr == NULL ||
+		    attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
+			continue;
+		}
+		if (attr->length <= 5)
+			continue;
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (dlen <= 3 || dlen % 16 != 3)
+			continue;
+		j++;
+		if (j <= n)
+			continue;
+
+		fdata = data;
+		fdlen = dlen;
+		break;
+	}
+	if (fdata == NULL)
+		goto out;
+
+	/* alloc writable memory for decryption */
+	buf = os_malloc(fdlen);
+	if (buf == NULL)
+		goto out;
+	os_memcpy(buf, fdata, fdlen);
+	buflen = fdlen;
+
+	/* init pointers */
+	salt = buf + 1;
+	str = buf + 3;
+
+	/* decrypt blocks */
+	pos = buf + buflen - 16; /* last block */
+	while (pos >= str + 16) { /* all but the first block */
+		addr[0] = secret;
+		len[0] = secret_len;
+		addr[1] = pos - 16;
+		len[1] = 16;
+		md5_vector(2, addr, len, hash);
+
+		for (i = 0; i < 16; i++)
+			pos[i] ^= hash[i];
+
+		pos -= 16;
+	}
+
+	/* decrypt first block */
+	if (str != pos)
+		goto out;
+	addr[0] = secret;
+	len[0] = secret_len;
+	addr[1] = sent_msg->hdr->authenticator;
+	len[1] = 16;
+	addr[2] = salt;
+	len[2] = 2;
+	md5_vector(3, addr, len, hash);
+
+	for (i = 0; i < 16; i++)
+		pos[i] ^= hash[i];
+
+	/* derive plaintext length from first subfield */
+	*keylen = (unsigned char) str[0];
+	if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
+		/* decryption error - invalid key length */
+		goto out;
+	}
+	if (*keylen == 0) {
+		/* empty password */
+		goto out;
+	}
+
+	/* copy passphrase into new buffer */
+	ret = os_malloc(*keylen);
+	if (ret)
+		os_memcpy(ret, str + 1, *keylen);
+
+out:
+	/* return new buffer */
+	os_free(buf);
+	return ret;
+}
+
+
+void radius_free_class(struct radius_class_data *c)
+{
+	size_t i;
+	if (c == NULL)
+		return;
+	for (i = 0; i < c->count; i++)
+		os_free(c->attr[i].data);
+	os_free(c->attr);
+	c->attr = NULL;
+	c->count = 0;
+}
+
+
+int radius_copy_class(struct radius_class_data *dst,
+		      const struct radius_class_data *src)
+{
+	size_t i;
+
+	if (src->attr == NULL)
+		return 0;
+
+	dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
+	if (dst->attr == NULL)
+		return -1;
+
+	dst->count = 0;
+
+	for (i = 0; i < src->count; i++) {
+		dst->attr[i].data = os_malloc(src->attr[i].len);
+		if (dst->attr[i].data == NULL)
+			break;
+		dst->count++;
+		os_memcpy(dst->attr[i].data, src->attr[i].data,
+			  src->attr[i].len);
+		dst->attr[i].len = src->attr[i].len;
+	}
+
+	return 0;
+}
+
+
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
+{
+	size_t i, j;
+	struct radius_attr_hdr *attr;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+
+		for (j = 0; attrs[j]; j++) {
+			if (attr->type == attrs[j])
+				break;
+		}
+
+		if (attrs[j] == 0)
+			return attr->type; /* unlisted attr */
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/radius/radius.h
===================================================================
--- vendor/wpa/dist/src/radius/radius.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,273 +0,0 @@
-/*
- * RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef RADIUS_H
-#define RADIUS_H
-
-/* RFC 2865 - RADIUS */
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct radius_hdr {
-	u8 code;
-	u8 identifier;
-	u16 length; /* including this header */
-	u8 authenticator[16];
-	/* followed by length-20 octets of attributes */
-} STRUCT_PACKED;
-
-enum { RADIUS_CODE_ACCESS_REQUEST = 1,
-       RADIUS_CODE_ACCESS_ACCEPT = 2,
-       RADIUS_CODE_ACCESS_REJECT = 3,
-       RADIUS_CODE_ACCOUNTING_REQUEST = 4,
-       RADIUS_CODE_ACCOUNTING_RESPONSE = 5,
-       RADIUS_CODE_ACCESS_CHALLENGE = 11,
-       RADIUS_CODE_STATUS_SERVER = 12,
-       RADIUS_CODE_STATUS_CLIENT = 13,
-       RADIUS_CODE_RESERVED = 255
-};
-
-struct radius_attr_hdr {
-	u8 type;
-	u8 length; /* including this header */
-	/* followed by length-2 octets of attribute value */
-} STRUCT_PACKED;
-
-#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
-
-enum { RADIUS_ATTR_USER_NAME = 1,
-       RADIUS_ATTR_USER_PASSWORD = 2,
-       RADIUS_ATTR_NAS_IP_ADDRESS = 4,
-       RADIUS_ATTR_NAS_PORT = 5,
-       RADIUS_ATTR_FRAMED_MTU = 12,
-       RADIUS_ATTR_REPLY_MESSAGE = 18,
-       RADIUS_ATTR_STATE = 24,
-       RADIUS_ATTR_CLASS = 25,
-       RADIUS_ATTR_VENDOR_SPECIFIC = 26,
-       RADIUS_ATTR_SESSION_TIMEOUT = 27,
-       RADIUS_ATTR_IDLE_TIMEOUT = 28,
-       RADIUS_ATTR_TERMINATION_ACTION = 29,
-       RADIUS_ATTR_CALLED_STATION_ID = 30,
-       RADIUS_ATTR_CALLING_STATION_ID = 31,
-       RADIUS_ATTR_NAS_IDENTIFIER = 32,
-       RADIUS_ATTR_PROXY_STATE = 33,
-       RADIUS_ATTR_ACCT_STATUS_TYPE = 40,
-       RADIUS_ATTR_ACCT_DELAY_TIME = 41,
-       RADIUS_ATTR_ACCT_INPUT_OCTETS = 42,
-       RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43,
-       RADIUS_ATTR_ACCT_SESSION_ID = 44,
-       RADIUS_ATTR_ACCT_AUTHENTIC = 45,
-       RADIUS_ATTR_ACCT_SESSION_TIME = 46,
-       RADIUS_ATTR_ACCT_INPUT_PACKETS = 47,
-       RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48,
-       RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49,
-       RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50,
-       RADIUS_ATTR_ACCT_LINK_COUNT = 51,
-       RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
-       RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
-       RADIUS_ATTR_EVENT_TIMESTAMP = 55,
-       RADIUS_ATTR_NAS_PORT_TYPE = 61,
-       RADIUS_ATTR_TUNNEL_TYPE = 64,
-       RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
-       RADIUS_ATTR_CONNECT_INFO = 77,
-       RADIUS_ATTR_EAP_MESSAGE = 79,
-       RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
-       RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
-       RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
-       RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
-       RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
-};
-
-
-/* Termination-Action */
-#define RADIUS_TERMINATION_ACTION_DEFAULT 0
-#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
-
-/* NAS-Port-Type */
-#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19
-
-/* Acct-Status-Type */
-#define RADIUS_ACCT_STATUS_TYPE_START 1
-#define RADIUS_ACCT_STATUS_TYPE_STOP 2
-#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3
-#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7
-#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8
-
-/* Acct-Authentic */
-#define RADIUS_ACCT_AUTHENTIC_RADIUS 1
-#define RADIUS_ACCT_AUTHENTIC_LOCAL 2
-#define RADIUS_ACCT_AUTHENTIC_REMOTE 3
-
-/* Acct-Terminate-Cause */
-#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1
-#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2
-#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3
-#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4
-#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5
-#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6
-#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7
-#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8
-#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9
-#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10
-#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11
-#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12
-#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13
-#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14
-#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15
-#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16
-#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
-#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
-
-#define RADIUS_TUNNEL_TAGS 32
-
-/* Tunnel-Type */
-#define RADIUS_TUNNEL_TYPE_PPTP 1
-#define RADIUS_TUNNEL_TYPE_L2TP 3
-#define RADIUS_TUNNEL_TYPE_IPIP 7
-#define RADIUS_TUNNEL_TYPE_GRE 10
-#define RADIUS_TUNNEL_TYPE_VLAN 13
-
-/* Tunnel-Medium-Type */
-#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1
-#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2
-#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6
-
-
-struct radius_attr_vendor {
-	u8 vendor_type;
-	u8 vendor_length;
-} STRUCT_PACKED;
-
-#define RADIUS_VENDOR_ID_CISCO 9
-#define RADIUS_CISCO_AV_PAIR 1
-
-/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
-#define RADIUS_VENDOR_ID_MICROSOFT 311
-
-enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
-       RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
-};
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-struct radius_ms_mppe_keys {
-	u8 *send;
-	size_t send_len;
-	u8 *recv;
-	size_t recv_len;
-};
-
-
-struct radius_msg;
-
-/* Default size to be allocated for new RADIUS messages */
-#define RADIUS_DEFAULT_MSG_SIZE 1024
-
-/* Default size to be allocated for attribute array */
-#define RADIUS_DEFAULT_ATTR_COUNT 16
-
-
-/* MAC address ASCII format for IEEE 802.1X use
- * (draft-congdon-radius-8021x-20.txt) */
-#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X"
-/* MAC address ASCII format for non-802.1X use */
-#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x"
-
-struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg);
-struct wpabuf * radius_msg_get_buf(struct radius_msg *msg);
-struct radius_msg * radius_msg_new(u8 code, u8 identifier);
-void radius_msg_free(struct radius_msg *msg);
-void radius_msg_dump(struct radius_msg *msg);
-int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
-		      size_t secret_len);
-int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
-			  size_t secret_len, const u8 *req_authenticator);
-void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
-			    size_t secret_len);
-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);
-int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
-		       size_t data_len);
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
-int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
-		      size_t secret_len, struct radius_msg *sent_msg,
-		      int auth);
-int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
-			       size_t secret_len, const u8 *req_auth);
-int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
-			 u8 type);
-void radius_msg_make_authenticator(struct radius_msg *msg,
-				   const u8 *data, size_t len);
-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);
-struct radius_ms_mppe_keys *
-radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
-			  const u8 *secret, size_t secret_len);
-int radius_msg_add_mppe_keys(struct radius_msg *msg,
-			     const u8 *req_authenticator,
-			     const u8 *secret, size_t secret_len,
-			     const u8 *send_key, size_t send_key_len,
-			     const u8 *recv_key, size_t recv_key_len);
-struct radius_attr_hdr *
-radius_msg_add_attr_user_password(struct radius_msg *msg,
-				  const u8 *data, size_t data_len,
-				  const u8 *secret, size_t secret_len);
-int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
-int radius_msg_get_vlanid(struct radius_msg *msg);
-
-static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
-					    u32 value)
-{
-	u32 val = htonl(value);
-	return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL;
-}
-
-static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
-					    u32 *value)
-{
-	u32 val;
-	int res;
-	res = radius_msg_get_attr(msg, type, (u8 *) &val, 4);
-	if (res != 4)
-		return -1;
-
-	*value = ntohl(val);
-	return 0;
-}
-int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
-			    size_t *len, const u8 *start);
-int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
-
-
-struct radius_attr_data {
-	u8 *data;
-	size_t len;
-};
-
-struct radius_class_data {
-	struct radius_attr_data *attr;
-	size_t count;
-};
-
-void radius_free_class(struct radius_class_data *c);
-int radius_copy_class(struct radius_class_data *dst,
-		      const struct radius_class_data *src);
-
-#endif /* RADIUS_H */

Copied: vendor/wpa/2.0/src/radius/radius.h (from rev 9639, vendor/wpa/dist/src/radius/radius.h)
===================================================================
--- vendor/wpa/2.0/src/radius/radius.h	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,287 @@
+/*
+ * RADIUS message processing
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_H
+#define RADIUS_H
+
+/* RFC 2865 - RADIUS */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct radius_hdr {
+	u8 code;
+	u8 identifier;
+	be16 length; /* including this header */
+	u8 authenticator[16];
+	/* followed by length-20 octets of attributes */
+} STRUCT_PACKED;
+
+enum { RADIUS_CODE_ACCESS_REQUEST = 1,
+       RADIUS_CODE_ACCESS_ACCEPT = 2,
+       RADIUS_CODE_ACCESS_REJECT = 3,
+       RADIUS_CODE_ACCOUNTING_REQUEST = 4,
+       RADIUS_CODE_ACCOUNTING_RESPONSE = 5,
+       RADIUS_CODE_ACCESS_CHALLENGE = 11,
+       RADIUS_CODE_STATUS_SERVER = 12,
+       RADIUS_CODE_STATUS_CLIENT = 13,
+       RADIUS_CODE_DISCONNECT_REQUEST = 40,
+       RADIUS_CODE_DISCONNECT_ACK = 41,
+       RADIUS_CODE_DISCONNECT_NAK = 42,
+       RADIUS_CODE_COA_REQUEST = 43,
+       RADIUS_CODE_COA_ACK = 44,
+       RADIUS_CODE_COA_NAK = 45,
+       RADIUS_CODE_RESERVED = 255
+};
+
+struct radius_attr_hdr {
+	u8 type;
+	u8 length; /* including this header */
+	/* followed by length-2 octets of attribute value */
+} STRUCT_PACKED;
+
+#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+
+enum { RADIUS_ATTR_USER_NAME = 1,
+       RADIUS_ATTR_USER_PASSWORD = 2,
+       RADIUS_ATTR_NAS_IP_ADDRESS = 4,
+       RADIUS_ATTR_NAS_PORT = 5,
+       RADIUS_ATTR_FRAMED_MTU = 12,
+       RADIUS_ATTR_REPLY_MESSAGE = 18,
+       RADIUS_ATTR_STATE = 24,
+       RADIUS_ATTR_CLASS = 25,
+       RADIUS_ATTR_VENDOR_SPECIFIC = 26,
+       RADIUS_ATTR_SESSION_TIMEOUT = 27,
+       RADIUS_ATTR_IDLE_TIMEOUT = 28,
+       RADIUS_ATTR_TERMINATION_ACTION = 29,
+       RADIUS_ATTR_CALLED_STATION_ID = 30,
+       RADIUS_ATTR_CALLING_STATION_ID = 31,
+       RADIUS_ATTR_NAS_IDENTIFIER = 32,
+       RADIUS_ATTR_PROXY_STATE = 33,
+       RADIUS_ATTR_ACCT_STATUS_TYPE = 40,
+       RADIUS_ATTR_ACCT_DELAY_TIME = 41,
+       RADIUS_ATTR_ACCT_INPUT_OCTETS = 42,
+       RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43,
+       RADIUS_ATTR_ACCT_SESSION_ID = 44,
+       RADIUS_ATTR_ACCT_AUTHENTIC = 45,
+       RADIUS_ATTR_ACCT_SESSION_TIME = 46,
+       RADIUS_ATTR_ACCT_INPUT_PACKETS = 47,
+       RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48,
+       RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49,
+       RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50,
+       RADIUS_ATTR_ACCT_LINK_COUNT = 51,
+       RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
+       RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
+       RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+       RADIUS_ATTR_NAS_PORT_TYPE = 61,
+       RADIUS_ATTR_TUNNEL_TYPE = 64,
+       RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+       RADIUS_ATTR_TUNNEL_PASSWORD = 69,
+       RADIUS_ATTR_CONNECT_INFO = 77,
+       RADIUS_ATTR_EAP_MESSAGE = 79,
+       RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
+       RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
+       RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
+       RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
+       RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
+       RADIUS_ATTR_ERROR_CAUSE = 101
+};
+
+
+/* Termination-Action */
+#define RADIUS_TERMINATION_ACTION_DEFAULT 0
+#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
+
+/* NAS-Port-Type */
+#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19
+
+/* Acct-Status-Type */
+#define RADIUS_ACCT_STATUS_TYPE_START 1
+#define RADIUS_ACCT_STATUS_TYPE_STOP 2
+#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8
+
+/* Acct-Authentic */
+#define RADIUS_ACCT_AUTHENTIC_RADIUS 1
+#define RADIUS_ACCT_AUTHENTIC_LOCAL 2
+#define RADIUS_ACCT_AUTHENTIC_REMOTE 3
+
+/* Acct-Terminate-Cause */
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3
+#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4
+#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14
+#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15
+#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
+#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
+
+#define RADIUS_TUNNEL_TAGS 32
+
+/* Tunnel-Type */
+#define RADIUS_TUNNEL_TYPE_PPTP 1
+#define RADIUS_TUNNEL_TYPE_L2TP 3
+#define RADIUS_TUNNEL_TYPE_IPIP 7
+#define RADIUS_TUNNEL_TYPE_GRE 10
+#define RADIUS_TUNNEL_TYPE_VLAN 13
+
+/* Tunnel-Medium-Type */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2
+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6
+
+
+struct radius_attr_vendor {
+	u8 vendor_type;
+	u8 vendor_length;
+} STRUCT_PACKED;
+
+#define RADIUS_VENDOR_ID_CISCO 9
+#define RADIUS_CISCO_AV_PAIR 1
+
+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+
+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
+       RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
+};
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+struct radius_ms_mppe_keys {
+	u8 *send;
+	size_t send_len;
+	u8 *recv;
+	size_t recv_len;
+};
+
+
+struct radius_msg;
+
+/* Default size to be allocated for new RADIUS messages */
+#define RADIUS_DEFAULT_MSG_SIZE 1024
+
+/* Default size to be allocated for attribute array */
+#define RADIUS_DEFAULT_ATTR_COUNT 16
+
+
+/* MAC address ASCII format for IEEE 802.1X use
+ * (draft-congdon-radius-8021x-20.txt) */
+#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X"
+/* MAC address ASCII format for non-802.1X use */
+#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg);
+struct wpabuf * radius_msg_get_buf(struct radius_msg *msg);
+struct radius_msg * radius_msg_new(u8 code, u8 identifier);
+void radius_msg_free(struct radius_msg *msg);
+void radius_msg_dump(struct radius_msg *msg);
+int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len);
+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
+			  size_t secret_len, const u8 *req_authenticator);
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len,
+			       const struct radius_hdr *req_hdr);
+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
+			    size_t secret_len);
+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);
+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);
+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
+		       size_t data_len);
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg);
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len, struct radius_msg *sent_msg,
+		      int auth);
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len, const u8 *req_auth);
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+			 u8 type);
+void radius_msg_make_authenticator(struct radius_msg *msg,
+				   const u8 *data, size_t len);
+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);
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+			  const u8 *secret, size_t secret_len);
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+			     const u8 *req_authenticator,
+			     const u8 *secret, size_t secret_len,
+			     const u8 *send_key, size_t send_key_len,
+			     const u8 *recv_key, size_t recv_key_len);
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  const u8 *data, size_t data_len,
+				  const u8 *secret, size_t secret_len);
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+int radius_msg_get_vlanid(struct radius_msg *msg);
+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);
+
+static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
+					    u32 value)
+{
+	u32 val = htonl(value);
+	return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL;
+}
+
+static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
+					    u32 *value)
+{
+	u32 val;
+	int res;
+	res = radius_msg_get_attr(msg, type, (u8 *) &val, 4);
+	if (res != 4)
+		return -1;
+
+	*value = ntohl(val);
+	return 0;
+}
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+			    size_t *len, const u8 *start);
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
+
+
+struct radius_attr_data {
+	u8 *data;
+	size_t len;
+};
+
+struct radius_class_data {
+	struct radius_attr_data *attr;
+	size_t count;
+};
+
+void radius_free_class(struct radius_class_data *c);
+int radius_copy_class(struct radius_class_data *dst,
+		      const struct radius_class_data *src);
+
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+
+#endif /* RADIUS_H */

Deleted: vendor/wpa/2.0/src/radius/radius_client.c
===================================================================
--- vendor/wpa/dist/src/radius/radius_client.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1491 +0,0 @@
-/*
- * RADIUS client
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "radius.h"
-#include "radius_client.h"
-#include "eloop.h"
-
-/* Defaults for RADIUS retransmit values (exponential backoff) */
-
-/**
- * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
- */
-#define RADIUS_CLIENT_FIRST_WAIT 3
-
-/**
- * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
- */
-#define RADIUS_CLIENT_MAX_WAIT 120
-
-/**
- * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
- *
- * Maximum number of retransmit attempts before the entry is removed from
- * retransmit list.
- */
-#define RADIUS_CLIENT_MAX_RETRIES 10
-
-/**
- * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
- *
- * Maximum number of entries in retransmit list (oldest entries will be
- * removed, if this limit is exceeded).
- */
-#define RADIUS_CLIENT_MAX_ENTRIES 30
-
-/**
- * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
- *
- * The number of failed retry attempts after which the RADIUS server will be
- * changed (if one of more backup servers are configured).
- */
-#define RADIUS_CLIENT_NUM_FAILOVER 4
-
-
-/**
- * struct radius_rx_handler - RADIUS client RX handler
- *
- * This data structure is used internally inside the RADIUS client module to
- * store registered RX handlers. These handlers are registered by calls to
- * radius_client_register() and unregistered when the RADIUS client is
- * deinitialized with a call to radius_client_deinit().
- */
-struct radius_rx_handler {
-	/**
-	 * handler - Received RADIUS message handler
-	 */
-	RadiusRxResult (*handler)(struct radius_msg *msg,
-				  struct radius_msg *req,
-				  const u8 *shared_secret,
-				  size_t shared_secret_len,
-				  void *data);
-
-	/**
-	 * data - Context data for the handler
-	 */
-	void *data;
-};
-
-
-/**
- * struct radius_msg_list - RADIUS client message retransmit list
- *
- * This data structure is used internally inside the RADIUS client module to
- * store pending RADIUS requests that may still need to be retransmitted.
- */
-struct radius_msg_list {
-	/**
-	 * addr - STA/client address
-	 *
-	 * This is used to find RADIUS messages for the same STA.
-	 */
-	u8 addr[ETH_ALEN];
-
-	/**
-	 * msg - RADIUS message
-	 */
-	struct radius_msg *msg;
-
-	/**
-	 * msg_type - Message type
-	 */
-	RadiusType msg_type;
-
-	/**
-	 * first_try - Time of the first transmission attempt
-	 */
-	os_time_t first_try;
-
-	/**
-	 * next_try - Time for the next transmission attempt
-	 */
-	os_time_t next_try;
-
-	/**
-	 * attempts - Number of transmission attempts
-	 */
-	int attempts;
-
-	/**
-	 * next_wait - Next retransmission wait time in seconds
-	 */
-	int next_wait;
-
-	/**
-	 * last_attempt - Time of the last transmission attempt
-	 */
-	struct os_time last_attempt;
-
-	/**
-	 * shared_secret - Shared secret with the target RADIUS server
-	 */
-	const u8 *shared_secret;
-
-	/**
-	 * shared_secret_len - shared_secret length in octets
-	 */
-	size_t shared_secret_len;
-
-	/* TODO: server config with failover to backup server(s) */
-
-	/**
-	 * next - Next message in the list
-	 */
-	struct radius_msg_list *next;
-};
-
-
-/**
- * struct radius_client_data - Internal RADIUS client data
- *
- * This data structure is used internally inside the RADIUS client module.
- * External users allocate this by calling radius_client_init() and free it by
- * calling radius_client_deinit(). The pointer to this opaque data is used in
- * calls to other functions as an identifier for the RADIUS client instance.
- */
-struct radius_client_data {
-	/**
-	 * ctx - Context pointer for hostapd_logger() callbacks
-	 */
-	void *ctx;
-
-	/**
-	 * conf - RADIUS client configuration (list of RADIUS servers to use)
-	 */
-	struct hostapd_radius_servers *conf;
-
-	/**
-	 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
-	 */
-	int auth_serv_sock;
-
-	/**
-	 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
-	 */
-	int acct_serv_sock;
-
-	/**
-	 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
-	 */
-	int auth_serv_sock6;
-
-	/**
-	 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
-	 */
-	int acct_serv_sock6;
-
-	/**
-	 * auth_sock - Currently used socket for RADIUS authentication server
-	 */
-	int auth_sock;
-
-	/**
-	 * acct_sock - Currently used socket for RADIUS accounting server
-	 */
-	int acct_sock;
-
-	/**
-	 * auth_handlers - Authentication message handlers
-	 */
-	struct radius_rx_handler *auth_handlers;
-
-	/**
-	 * num_auth_handlers - Number of handlers in auth_handlers
-	 */
-	size_t num_auth_handlers;
-
-	/**
-	 * acct_handlers - Accounting message handlers
-	 */
-	struct radius_rx_handler *acct_handlers;
-
-	/**
-	 * num_acct_handlers - Number of handlers in acct_handlers
-	 */
-	size_t num_acct_handlers;
-
-	/**
-	 * msgs - Pending outgoing RADIUS messages
-	 */
-	struct radius_msg_list *msgs;
-
-	/**
-	 * num_msgs - Number of pending messages in the msgs list
-	 */
-	size_t num_msgs;
-
-	/**
-	 * next_radius_identifier - Next RADIUS message identifier to use
-	 */
-	u8 next_radius_identifier;
-};
-
-
-static int
-radius_change_server(struct radius_client_data *radius,
-		     struct hostapd_radius_server *nserv,
-		     struct hostapd_radius_server *oserv,
-		     int sock, int sock6, int auth);
-static int radius_client_init_acct(struct radius_client_data *radius);
-static int radius_client_init_auth(struct radius_client_data *radius);
-
-
-static void radius_client_msg_free(struct radius_msg_list *req)
-{
-	radius_msg_free(req->msg);
-	os_free(req);
-}
-
-
-/**
- * radius_client_register - Register a RADIUS client RX handler
- * @radius: RADIUS client context from radius_client_init()
- * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
- * @handler: Handler for received RADIUS messages
- * @data: Context pointer for handler callbacks
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to register a handler for processing received RADIUS
- * authentication and accounting messages. The handler() callback function will
- * be called whenever a RADIUS message is received from the active server.
- *
- * There can be multiple registered RADIUS message handlers. The handlers will
- * be called in order until one of them indicates that it has processed or
- * queued the message.
- */
-int radius_client_register(struct radius_client_data *radius,
-			   RadiusType msg_type,
-			   RadiusRxResult (*handler)(struct radius_msg *msg,
-						     struct radius_msg *req,
-						     const u8 *shared_secret,
-						     size_t shared_secret_len,
-						     void *data),
-			   void *data)
-{
-	struct radius_rx_handler **handlers, *newh;
-	size_t *num;
-
-	if (msg_type == RADIUS_ACCT) {
-		handlers = &radius->acct_handlers;
-		num = &radius->num_acct_handlers;
-	} else {
-		handlers = &radius->auth_handlers;
-		num = &radius->num_auth_handlers;
-	}
-
-	newh = os_realloc(*handlers,
-			  (*num + 1) * sizeof(struct radius_rx_handler));
-	if (newh == NULL)
-		return -1;
-
-	newh[*num].handler = handler;
-	newh[*num].data = data;
-	(*num)++;
-	*handlers = newh;
-
-	return 0;
-}
-
-
-static void radius_client_handle_send_error(struct radius_client_data *radius,
-					    int s, RadiusType msg_type)
-{
-#ifndef CONFIG_NATIVE_WINDOWS
-	int _errno = errno;
-	perror("send[RADIUS]");
-	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
-	    _errno == EBADF) {
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_INFO,
-			       "Send failed - maybe interface status changed -"
-			       " try to connect again");
-		eloop_unregister_read_sock(s);
-		close(s);
-		if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
-			radius_client_init_acct(radius);
-		else
-			radius_client_init_auth(radius);
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-static int radius_client_retransmit(struct radius_client_data *radius,
-				    struct radius_msg_list *entry,
-				    os_time_t now)
-{
-	struct hostapd_radius_servers *conf = radius->conf;
-	int s;
-	struct wpabuf *buf;
-
-	if (entry->msg_type == RADIUS_ACCT ||
-	    entry->msg_type == RADIUS_ACCT_INTERIM) {
-		s = radius->acct_sock;
-		if (entry->attempts == 0)
-			conf->acct_server->requests++;
-		else {
-			conf->acct_server->timeouts++;
-			conf->acct_server->retransmissions++;
-		}
-	} else {
-		s = radius->auth_sock;
-		if (entry->attempts == 0)
-			conf->auth_server->requests++;
-		else {
-			conf->auth_server->timeouts++;
-			conf->auth_server->retransmissions++;
-		}
-	}
-
-	/* retransmit; remove entry if too many attempts */
-	entry->attempts++;
-	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
-		       radius_msg_get_hdr(entry->msg)->identifier);
-
-	os_get_time(&entry->last_attempt);
-	buf = radius_msg_get_buf(entry->msg);
-	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
-		radius_client_handle_send_error(radius, s, entry->msg_type);
-
-	entry->next_try = now + entry->next_wait;
-	entry->next_wait *= 2;
-	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
-		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
-	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
-		printf("Removing un-ACKed RADIUS message due to too many "
-		       "failed retransmit attempts\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-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_time now;
-	os_time_t first;
-	struct radius_msg_list *entry, *prev, *tmp;
-	int auth_failover = 0, acct_failover = 0;
-	char abuf[50];
-
-	entry = radius->msgs;
-	if (!entry)
-		return;
-
-	os_get_time(&now);
-	first = 0;
-
-	prev = NULL;
-	while (entry) {
-		if (now.sec >= entry->next_try &&
-		    radius_client_retransmit(radius, entry, now.sec)) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				radius->msgs = entry->next;
-
-			tmp = entry;
-			entry = entry->next;
-			radius_client_msg_free(tmp);
-			radius->num_msgs--;
-			continue;
-		}
-
-		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
-			if (entry->msg_type == RADIUS_ACCT ||
-			    entry->msg_type == RADIUS_ACCT_INTERIM)
-				acct_failover++;
-			else
-				auth_failover++;
-		}
-
-		if (first == 0 || entry->next_try < first)
-			first = entry->next_try;
-
-		prev = entry;
-		entry = entry->next;
-	}
-
-	if (radius->msgs) {
-		if (first < now.sec)
-			first = now.sec;
-		eloop_register_timeout(first - now.sec, 0,
-				       radius_client_timer, radius, NULL);
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
-			       "retransmit in %ld seconds",
-			       (long int) (first - now.sec));
-	}
-
-	if (auth_failover && conf->num_auth_servers > 1) {
-		struct hostapd_radius_server *next, *old;
-		old = conf->auth_server;
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "No response from Authentication server "
-			       "%s:%d - failover",
-			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
-			       old->port);
-
-		for (entry = radius->msgs; entry; entry = entry->next) {
-			if (entry->msg_type == RADIUS_AUTH)
-				old->timeouts++;
-		}
-
-		next = old + 1;
-		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
-			next = conf->auth_servers;
-		conf->auth_server = next;
-		radius_change_server(radius, next, old,
-				     radius->auth_serv_sock,
-				     radius->auth_serv_sock6, 1);
-	}
-
-	if (acct_failover && conf->num_acct_servers > 1) {
-		struct hostapd_radius_server *next, *old;
-		old = conf->acct_server;
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "No response from Accounting server "
-			       "%s:%d - failover",
-			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
-			       old->port);
-
-		for (entry = radius->msgs; entry; entry = entry->next) {
-			if (entry->msg_type == RADIUS_ACCT ||
-			    entry->msg_type == RADIUS_ACCT_INTERIM)
-				old->timeouts++;
-		}
-
-		next = old + 1;
-		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
-			next = conf->acct_servers;
-		conf->acct_server = next;
-		radius_change_server(radius, next, old,
-				     radius->acct_serv_sock,
-				     radius->acct_serv_sock6, 0);
-	}
-}
-
-
-static void radius_client_update_timeout(struct radius_client_data *radius)
-{
-	struct os_time now;
-	os_time_t first;
-	struct radius_msg_list *entry;
-
-	eloop_cancel_timeout(radius_client_timer, radius, NULL);
-
-	if (radius->msgs == NULL) {
-		return;
-	}
-
-	first = 0;
-	for (entry = radius->msgs; entry; entry = entry->next) {
-		if (first == 0 || entry->next_try < first)
-			first = entry->next_try;
-	}
-
-	os_get_time(&now);
-	if (first < now.sec)
-		first = now.sec;
-	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
-			       NULL);
-	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
-		       " %ld seconds\n", (long int) (first - now.sec));
-}
-
-
-static void radius_client_list_add(struct radius_client_data *radius,
-				   struct radius_msg *msg,
-				   RadiusType msg_type,
-				   const u8 *shared_secret,
-				   size_t shared_secret_len, const u8 *addr)
-{
-	struct radius_msg_list *entry, *prev;
-
-	if (eloop_terminated()) {
-		/* No point in adding entries to retransmit queue since event
-		 * loop has already been terminated. */
-		radius_msg_free(msg);
-		return;
-	}
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL) {
-		printf("Failed to add RADIUS packet into retransmit list\n");
-		radius_msg_free(msg);
-		return;
-	}
-
-	if (addr)
-		os_memcpy(entry->addr, addr, ETH_ALEN);
-	entry->msg = msg;
-	entry->msg_type = msg_type;
-	entry->shared_secret = shared_secret;
-	entry->shared_secret_len = shared_secret_len;
-	os_get_time(&entry->last_attempt);
-	entry->first_try = entry->last_attempt.sec;
-	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
-	entry->attempts = 1;
-	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
-	entry->next = radius->msgs;
-	radius->msgs = entry;
-	radius_client_update_timeout(radius);
-
-	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
-		printf("Removing the oldest un-ACKed RADIUS packet due to "
-		       "retransmit list limits.\n");
-		prev = NULL;
-		while (entry->next) {
-			prev = entry;
-			entry = entry->next;
-		}
-		if (prev) {
-			prev->next = NULL;
-			radius_client_msg_free(entry);
-		}
-	} else
-		radius->num_msgs++;
-}
-
-
-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()
- * @msg: RADIUS message to be sent
- * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
- * @addr: MAC address of the device related to this message or %NULL
- * Returns: 0 on success, -1 on failure
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-int radius_client_send(struct radius_client_data *radius,
-		       struct radius_msg *msg, RadiusType msg_type,
-		       const u8 *addr)
-{
-	struct hostapd_radius_servers *conf = radius->conf;
-	const u8 *shared_secret;
-	size_t shared_secret_len;
-	char *name;
-	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 == NULL) {
-			hostapd_logger(radius->ctx, NULL,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_INFO,
-				       "No accounting server configured");
-			return -1;
-		}
-		shared_secret = conf->acct_server->shared_secret;
-		shared_secret_len = conf->acct_server->shared_secret_len;
-		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
-		name = "accounting";
-		s = radius->acct_sock;
-		conf->acct_server->requests++;
-	} else {
-		if (conf->auth_server == NULL) {
-			hostapd_logger(radius->ctx, NULL,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_INFO,
-				       "No authentication server configured");
-			return -1;
-		}
-		shared_secret = conf->auth_server->shared_secret;
-		shared_secret_len = conf->auth_server->shared_secret_len;
-		radius_msg_finish(msg, shared_secret, shared_secret_len);
-		name = "authentication";
-		s = radius->auth_sock;
-		conf->auth_server->requests++;
-	}
-
-	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
-		       "server", name);
-	if (conf->msg_dumps)
-		radius_msg_dump(msg);
-
-	buf = radius_msg_get_buf(msg);
-	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
-	if (res < 0)
-		radius_client_handle_send_error(radius, s, msg_type);
-
-	radius_client_list_add(radius, msg, msg_type, shared_secret,
-			       shared_secret_len, addr);
-
-	return res;
-}
-
-
-static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct radius_client_data *radius = eloop_ctx;
-	struct hostapd_radius_servers *conf = radius->conf;
-	RadiusType msg_type = (RadiusType) sock_ctx;
-	int len, roundtrip;
-	unsigned char buf[3000];
-	struct radius_msg *msg;
-	struct radius_hdr *hdr;
-	struct radius_rx_handler *handlers;
-	size_t num_handlers, i;
-	struct radius_msg_list *req, *prev_req;
-	struct os_time now;
-	struct hostapd_radius_server *rconf;
-	int invalid_authenticator = 0;
-
-	if (msg_type == RADIUS_ACCT) {
-		handlers = radius->acct_handlers;
-		num_handlers = radius->num_acct_handlers;
-		rconf = conf->acct_server;
-	} else {
-		handlers = radius->auth_handlers;
-		num_handlers = radius->num_auth_handlers;
-		rconf = conf->auth_server;
-	}
-
-	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
-	if (len < 0) {
-		perror("recv[RADIUS]");
-		return;
-	}
-	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
-		       "server", len);
-	if (len == sizeof(buf)) {
-		printf("Possibly too long UDP frame for our buffer - "
-		       "dropping it\n");
-		return;
-	}
-
-	msg = radius_msg_parse(buf, len);
-	if (msg == NULL) {
-		printf("Parsing incoming RADIUS frame failed\n");
-		rconf->malformed_responses++;
-		return;
-	}
-	hdr = radius_msg_get_hdr(msg);
-
-	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
-	if (conf->msg_dumps)
-		radius_msg_dump(msg);
-
-	switch (hdr->code) {
-	case RADIUS_CODE_ACCESS_ACCEPT:
-		rconf->access_accepts++;
-		break;
-	case RADIUS_CODE_ACCESS_REJECT:
-		rconf->access_rejects++;
-		break;
-	case RADIUS_CODE_ACCESS_CHALLENGE:
-		rconf->access_challenges++;
-		break;
-	case RADIUS_CODE_ACCOUNTING_RESPONSE:
-		rconf->responses++;
-		break;
-	}
-
-	prev_req = NULL;
-	req = radius->msgs;
-	while (req) {
-		/* TODO: also match by src addr:port of the packet when using
-		 * alternative RADIUS servers (?) */
-		if ((req->msg_type == msg_type ||
-		     (req->msg_type == RADIUS_ACCT_INTERIM &&
-		      msg_type == RADIUS_ACCT)) &&
-		    radius_msg_get_hdr(req->msg)->identifier ==
-		    hdr->identifier)
-			break;
-
-		prev_req = req;
-		req = req->next;
-	}
-
-	if (req == NULL) {
-		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "No matching RADIUS request found (type=%d "
-			       "id=%d) - dropping packet",
-			       msg_type, hdr->identifier);
-		goto fail;
-	}
-
-	os_get_time(&now);
-	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
-		(now.usec - req->last_attempt.usec) / 10000;
-	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Received RADIUS packet matched with a pending "
-		       "request, round trip time %d.%02d sec",
-		       roundtrip / 100, roundtrip % 100);
-	rconf->round_trip_time = roundtrip;
-
-	/* Remove ACKed RADIUS packet from retransmit list */
-	if (prev_req)
-		prev_req->next = req->next;
-	else
-		radius->msgs = req->next;
-	radius->num_msgs--;
-
-	for (i = 0; i < num_handlers; i++) {
-		RadiusRxResult res;
-		res = handlers[i].handler(msg, req->msg, req->shared_secret,
-					  req->shared_secret_len,
-					  handlers[i].data);
-		switch (res) {
-		case RADIUS_RX_PROCESSED:
-			radius_msg_free(msg);
-			/* continue */
-		case RADIUS_RX_QUEUED:
-			radius_client_msg_free(req);
-			return;
-		case RADIUS_RX_INVALID_AUTHENTICATOR:
-			invalid_authenticator++;
-			/* continue */
-		case RADIUS_RX_UNKNOWN:
-			/* continue with next handler */
-			break;
-		}
-	}
-
-	if (invalid_authenticator)
-		rconf->bad_authenticators++;
-	else
-		rconf->unknown_types++;
-	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
-		       "(type=%d code=%d id=%d)%s - dropping packet",
-		       msg_type, hdr->code, hdr->identifier,
-		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
-		       "");
-	radius_client_msg_free(req);
-
- fail:
-	radius_msg_free(msg);
-}
-
-
-/**
- * radius_client_get_id - Get an identifier for a new RADIUS message
- * @radius: RADIUS client context from radius_client_init()
- * Returns: Allocated identifier
- *
- * This function is used to fetch a unique (among pending requests) identifier
- * for a new RADIUS message.
- */
-u8 radius_client_get_id(struct radius_client_data *radius)
-{
-	struct radius_msg_list *entry, *prev, *_remove;
-	u8 id = radius->next_radius_identifier++;
-
-	/* remove entries with matching id from retransmit list to avoid
-	 * using new reply from the RADIUS server with an old request */
-	entry = radius->msgs;
-	prev = NULL;
-	while (entry) {
-		if (radius_msg_get_hdr(entry->msg)->identifier == id) {
-			hostapd_logger(radius->ctx, entry->addr,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "Removing pending RADIUS message, "
-				       "since its id (%d) is reused", id);
-			if (prev)
-				prev->next = entry->next;
-			else
-				radius->msgs = entry->next;
-			_remove = entry;
-		} else {
-			_remove = NULL;
-			prev = entry;
-		}
-		entry = entry->next;
-
-		if (_remove)
-			radius_client_msg_free(_remove);
-	}
-
-	return id;
-}
-
-
-/**
- * radius_client_flush - Flush all pending RADIUS client messages
- * @radius: RADIUS client context from radius_client_init()
- * @only_auth: Whether only authentication messages are removed
- */
-void radius_client_flush(struct radius_client_data *radius, int only_auth)
-{
-	struct radius_msg_list *entry, *prev, *tmp;
-
-	if (!radius)
-		return;
-
-	prev = NULL;
-	entry = radius->msgs;
-
-	while (entry) {
-		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				radius->msgs = entry->next;
-
-			tmp = entry;
-			entry = entry->next;
-			radius_client_msg_free(tmp);
-			radius->num_msgs--;
-		} else {
-			prev = entry;
-			entry = entry->next;
-		}
-	}
-
-	if (radius->msgs == NULL)
-		eloop_cancel_timeout(radius_client_timer, radius, NULL);
-}
-
-
-static void radius_client_update_acct_msgs(struct radius_client_data *radius,
-					   const u8 *shared_secret,
-					   size_t shared_secret_len)
-{
-	struct radius_msg_list *entry;
-
-	if (!radius)
-		return;
-
-	for (entry = radius->msgs; entry; entry = entry->next) {
-		if (entry->msg_type == RADIUS_ACCT) {
-			entry->shared_secret = shared_secret;
-			entry->shared_secret_len = shared_secret_len;
-			radius_msg_finish_acct(entry->msg, shared_secret,
-					       shared_secret_len);
-		}
-	}
-}
-
-
-static int
-radius_change_server(struct radius_client_data *radius,
-		     struct hostapd_radius_server *nserv,
-		     struct hostapd_radius_server *oserv,
-		     int sock, int sock6, int auth)
-{
-	struct sockaddr_in serv, claddr;
-#ifdef CONFIG_IPV6
-	struct sockaddr_in6 serv6, claddr6;
-#endif /* CONFIG_IPV6 */
-	struct sockaddr *addr, *cl_addr;
-	socklen_t addrlen, claddrlen;
-	char abuf[50];
-	int sel_sock;
-	struct radius_msg_list *entry;
-	struct hostapd_radius_servers *conf = radius->conf;
-
-	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
-		       HOSTAPD_LEVEL_INFO,
-		       "%s server %s:%d",
-		       auth ? "Authentication" : "Accounting",
-		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
-		       nserv->port);
-
-	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
-	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
-		      nserv->shared_secret_len) != 0) {
-		/* Pending RADIUS packets used different shared secret, so
-		 * they need to be modified. Update accounting message
-		 * authenticators here. Authentication messages are removed
-		 * since they would require more changes and the new RADIUS
-		 * server may not be prepared to receive them anyway due to
-		 * missing state information. Client will likely retry
-		 * authentication, so this should not be an issue. */
-		if (auth)
-			radius_client_flush(radius, 1);
-		else {
-			radius_client_update_acct_msgs(
-				radius, nserv->shared_secret,
-				nserv->shared_secret_len);
-		}
-	}
-
-	/* Reset retry counters for the new server */
-	for (entry = radius->msgs; entry; entry = entry->next) {
-		if ((auth && entry->msg_type != RADIUS_AUTH) ||
-		    (!auth && entry->msg_type != RADIUS_ACCT))
-			continue;
-		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
-		entry->attempts = 0;
-		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
-	}
-
-	if (radius->msgs) {
-		eloop_cancel_timeout(radius_client_timer, radius, NULL);
-		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
-				       radius_client_timer, radius, NULL);
-	}
-
-	switch (nserv->addr.af) {
-	case AF_INET:
-		os_memset(&serv, 0, sizeof(serv));
-		serv.sin_family = AF_INET;
-		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
-		serv.sin_port = htons(nserv->port);
-		addr = (struct sockaddr *) &serv;
-		addrlen = sizeof(serv);
-		sel_sock = sock;
-		break;
-#ifdef CONFIG_IPV6
-	case AF_INET6:
-		os_memset(&serv6, 0, sizeof(serv6));
-		serv6.sin6_family = AF_INET6;
-		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
-			  sizeof(struct in6_addr));
-		serv6.sin6_port = htons(nserv->port);
-		addr = (struct sockaddr *) &serv6;
-		addrlen = sizeof(serv6);
-		sel_sock = sock6;
-		break;
-#endif /* CONFIG_IPV6 */
-	default:
-		return -1;
-	}
-
-	if (conf->force_client_addr) {
-		switch (conf->client_addr.af) {
-		case AF_INET:
-			os_memset(&claddr, 0, sizeof(claddr));
-			claddr.sin_family = AF_INET;
-			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
-			claddr.sin_port = htons(0);
-			cl_addr = (struct sockaddr *) &claddr;
-			claddrlen = sizeof(claddr);
-			break;
-#ifdef CONFIG_IPV6
-		case AF_INET6:
-			os_memset(&claddr6, 0, sizeof(claddr6));
-			claddr6.sin6_family = AF_INET6;
-			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
-				  sizeof(struct in6_addr));
-			claddr6.sin6_port = htons(0);
-			cl_addr = (struct sockaddr *) &claddr6;
-			claddrlen = sizeof(claddr6);
-			break;
-#endif /* CONFIG_IPV6 */
-		default:
-			return -1;
-		}
-
-		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
-			perror("bind[radius]");
-			return -1;
-		}
-	}
-
-	if (connect(sel_sock, addr, addrlen) < 0) {
-		perror("connect[radius]");
-		return -1;
-	}
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	switch (nserv->addr.af) {
-	case AF_INET:
-		claddrlen = sizeof(claddr);
-		getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
-		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
-			   inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
-		break;
-#ifdef CONFIG_IPV6
-	case AF_INET6: {
-		claddrlen = sizeof(claddr6);
-		getsockname(sel_sock, (struct sockaddr *) &claddr6,
-			    &claddrlen);
-		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
-			   inet_ntop(AF_INET6, &claddr6.sin6_addr,
-				     abuf, sizeof(abuf)),
-			   ntohs(claddr6.sin6_port));
-		break;
-	}
-#endif /* CONFIG_IPV6 */
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	if (auth)
-		radius->auth_sock = sel_sock;
-	else
-		radius->acct_sock = sel_sock;
-
-	return 0;
-}
-
-
-static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct radius_client_data *radius = eloop_ctx;
-	struct hostapd_radius_servers *conf = radius->conf;
-	struct hostapd_radius_server *oserv;
-
-	if (radius->auth_sock >= 0 && conf->auth_servers &&
-	    conf->auth_server != conf->auth_servers) {
-		oserv = conf->auth_server;
-		conf->auth_server = conf->auth_servers;
-		radius_change_server(radius, conf->auth_server, oserv,
-				     radius->auth_serv_sock,
-				     radius->auth_serv_sock6, 1);
-	}
-
-	if (radius->acct_sock >= 0 && conf->acct_servers &&
-	    conf->acct_server != conf->acct_servers) {
-		oserv = conf->acct_server;
-		conf->acct_server = conf->acct_servers;
-		radius_change_server(radius, conf->acct_server, oserv,
-				     radius->acct_serv_sock,
-				     radius->acct_serv_sock6, 0);
-	}
-
-	if (conf->retry_primary_interval)
-		eloop_register_timeout(conf->retry_primary_interval, 0,
-				       radius_retry_primary_timer, radius,
-				       NULL);
-}
-
-
-static int radius_client_disable_pmtu_discovery(int s)
-{
-	int r = -1;
-#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
-	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
-	int action = IP_PMTUDISC_DONT;
-	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
-		       sizeof(action));
-	if (r == -1)
-		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
-			   "%s", strerror(errno));
-#endif
-	return r;
-}
-
-
-static int radius_client_init_auth(struct radius_client_data *radius)
-{
-	struct hostapd_radius_servers *conf = radius->conf;
-	int ok = 0;
-
-	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (radius->auth_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
-	else {
-		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
-		ok++;
-	}
-
-#ifdef CONFIG_IPV6
-	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
-	if (radius->auth_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
-	else
-		ok++;
-#endif /* CONFIG_IPV6 */
-
-	if (ok == 0)
-		return -1;
-
-	radius_change_server(radius, conf->auth_server, NULL,
-			     radius->auth_serv_sock, radius->auth_serv_sock6,
-			     1);
-
-	if (radius->auth_serv_sock >= 0 &&
-	    eloop_register_read_sock(radius->auth_serv_sock,
-				     radius_client_receive, radius,
-				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
-		return -1;
-	}
-
-#ifdef CONFIG_IPV6
-	if (radius->auth_serv_sock6 >= 0 &&
-	    eloop_register_read_sock(radius->auth_serv_sock6,
-				     radius_client_receive, radius,
-				     (void *) RADIUS_AUTH)) {
-		printf("Could not register read socket for authentication "
-		       "server\n");
-		return -1;
-	}
-#endif /* CONFIG_IPV6 */
-
-	return 0;
-}
-
-
-static int radius_client_init_acct(struct radius_client_data *radius)
-{
-	struct hostapd_radius_servers *conf = radius->conf;
-	int ok = 0;
-
-	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (radius->acct_serv_sock < 0)
-		perror("socket[PF_INET,SOCK_DGRAM]");
-	else {
-		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
-		ok++;
-	}
-
-#ifdef CONFIG_IPV6
-	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
-	if (radius->acct_serv_sock6 < 0)
-		perror("socket[PF_INET6,SOCK_DGRAM]");
-	else
-		ok++;
-#endif /* CONFIG_IPV6 */
-
-	if (ok == 0)
-		return -1;
-
-	radius_change_server(radius, conf->acct_server, NULL,
-			     radius->acct_serv_sock, radius->acct_serv_sock6,
-			     0);
-
-	if (radius->acct_serv_sock >= 0 &&
-	    eloop_register_read_sock(radius->acct_serv_sock,
-				     radius_client_receive, radius,
-				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
-		return -1;
-	}
-
-#ifdef CONFIG_IPV6
-	if (radius->acct_serv_sock6 >= 0 &&
-	    eloop_register_read_sock(radius->acct_serv_sock6,
-				     radius_client_receive, radius,
-				     (void *) RADIUS_ACCT)) {
-		printf("Could not register read socket for accounting "
-		       "server\n");
-		return -1;
-	}
-#endif /* CONFIG_IPV6 */
-
-	return 0;
-}
-
-
-/**
- * radius_client_init - Initialize RADIUS client
- * @ctx: Callback context to be used in hostapd_logger() calls
- * @conf: RADIUS client configuration (RADIUS servers)
- * Returns: Pointer to private RADIUS client context or %NULL on failure
- *
- * The caller is responsible for keeping the configuration data available for
- * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
- * called for the returned context pointer.
- */
-struct radius_client_data *
-radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
-{
-	struct radius_client_data *radius;
-
-	radius = os_zalloc(sizeof(struct radius_client_data));
-	if (radius == NULL)
-		return NULL;
-
-	radius->ctx = ctx;
-	radius->conf = conf;
-	radius->auth_serv_sock = radius->acct_serv_sock =
-		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
-		radius->auth_sock = radius->acct_sock = -1;
-
-	if (conf->auth_server && radius_client_init_auth(radius)) {
-		radius_client_deinit(radius);
-		return NULL;
-	}
-
-	if (conf->acct_server && radius_client_init_acct(radius)) {
-		radius_client_deinit(radius);
-		return NULL;
-	}
-
-	if (conf->retry_primary_interval)
-		eloop_register_timeout(conf->retry_primary_interval, 0,
-				       radius_retry_primary_timer, radius,
-				       NULL);
-
-	return radius;
-}
-
-
-/**
- * radius_client_deinit - Deinitialize RADIUS client
- * @radius: RADIUS client context from radius_client_init()
- */
-void radius_client_deinit(struct radius_client_data *radius)
-{
-	if (!radius)
-		return;
-
-	if (radius->auth_serv_sock >= 0)
-		eloop_unregister_read_sock(radius->auth_serv_sock);
-	if (radius->acct_serv_sock >= 0)
-		eloop_unregister_read_sock(radius->acct_serv_sock);
-#ifdef CONFIG_IPV6
-	if (radius->auth_serv_sock6 >= 0)
-		eloop_unregister_read_sock(radius->auth_serv_sock6);
-	if (radius->acct_serv_sock6 >= 0)
-		eloop_unregister_read_sock(radius->acct_serv_sock6);
-#endif /* CONFIG_IPV6 */
-
-	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
-
-	radius_client_flush(radius, 0);
-	os_free(radius->auth_handlers);
-	os_free(radius->acct_handlers);
-	os_free(radius);
-}
-
-
-/**
- * radius_client_flush_auth - Flush pending RADIUS messages for an address
- * @radius: RADIUS client context from radius_client_init()
- * @addr: MAC address of the related device
- *
- * This function can be used to remove pending RADIUS authentication messages
- * that are related to a specific device. The addr parameter is matched with
- * the one used in radius_client_send() call that was used to transmit the
- * authentication request.
- */
-void radius_client_flush_auth(struct radius_client_data *radius,
-			      const u8 *addr)
-{
-	struct radius_msg_list *entry, *prev, *tmp;
-
-	prev = NULL;
-	entry = radius->msgs;
-	while (entry) {
-		if (entry->msg_type == RADIUS_AUTH &&
-		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-			hostapd_logger(radius->ctx, addr,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "Removing pending RADIUS authentication"
-				       " message for removed client");
-
-			if (prev)
-				prev->next = entry->next;
-			else
-				radius->msgs = entry->next;
-
-			tmp = entry;
-			entry = entry->next;
-			radius_client_msg_free(tmp);
-			radius->num_msgs--;
-			continue;
-		}
-
-		prev = entry;
-		entry = entry->next;
-	}
-}
-
-
-static int radius_client_dump_auth_server(char *buf, size_t buflen,
-					  struct hostapd_radius_server *serv,
-					  struct radius_client_data *cli)
-{
-	int pending = 0;
-	struct radius_msg_list *msg;
-	char abuf[50];
-
-	if (cli) {
-		for (msg = cli->msgs; msg; msg = msg->next) {
-			if (msg->msg_type == RADIUS_AUTH)
-				pending++;
-		}
-	}
-
-	return os_snprintf(buf, buflen,
-			   "radiusAuthServerIndex=%d\n"
-			   "radiusAuthServerAddress=%s\n"
-			   "radiusAuthClientServerPortNumber=%d\n"
-			   "radiusAuthClientRoundTripTime=%d\n"
-			   "radiusAuthClientAccessRequests=%u\n"
-			   "radiusAuthClientAccessRetransmissions=%u\n"
-			   "radiusAuthClientAccessAccepts=%u\n"
-			   "radiusAuthClientAccessRejects=%u\n"
-			   "radiusAuthClientAccessChallenges=%u\n"
-			   "radiusAuthClientMalformedAccessResponses=%u\n"
-			   "radiusAuthClientBadAuthenticators=%u\n"
-			   "radiusAuthClientPendingRequests=%u\n"
-			   "radiusAuthClientTimeouts=%u\n"
-			   "radiusAuthClientUnknownTypes=%u\n"
-			   "radiusAuthClientPacketsDropped=%u\n",
-			   serv->index,
-			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
-			   serv->port,
-			   serv->round_trip_time,
-			   serv->requests,
-			   serv->retransmissions,
-			   serv->access_accepts,
-			   serv->access_rejects,
-			   serv->access_challenges,
-			   serv->malformed_responses,
-			   serv->bad_authenticators,
-			   pending,
-			   serv->timeouts,
-			   serv->unknown_types,
-			   serv->packets_dropped);
-}
-
-
-static int radius_client_dump_acct_server(char *buf, size_t buflen,
-					  struct hostapd_radius_server *serv,
-					  struct radius_client_data *cli)
-{
-	int pending = 0;
-	struct radius_msg_list *msg;
-	char abuf[50];
-
-	if (cli) {
-		for (msg = cli->msgs; msg; msg = msg->next) {
-			if (msg->msg_type == RADIUS_ACCT ||
-			    msg->msg_type == RADIUS_ACCT_INTERIM)
-				pending++;
-		}
-	}
-
-	return os_snprintf(buf, buflen,
-			   "radiusAccServerIndex=%d\n"
-			   "radiusAccServerAddress=%s\n"
-			   "radiusAccClientServerPortNumber=%d\n"
-			   "radiusAccClientRoundTripTime=%d\n"
-			   "radiusAccClientRequests=%u\n"
-			   "radiusAccClientRetransmissions=%u\n"
-			   "radiusAccClientResponses=%u\n"
-			   "radiusAccClientMalformedResponses=%u\n"
-			   "radiusAccClientBadAuthenticators=%u\n"
-			   "radiusAccClientPendingRequests=%u\n"
-			   "radiusAccClientTimeouts=%u\n"
-			   "radiusAccClientUnknownTypes=%u\n"
-			   "radiusAccClientPacketsDropped=%u\n",
-			   serv->index,
-			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
-			   serv->port,
-			   serv->round_trip_time,
-			   serv->requests,
-			   serv->retransmissions,
-			   serv->responses,
-			   serv->malformed_responses,
-			   serv->bad_authenticators,
-			   pending,
-			   serv->timeouts,
-			   serv->unknown_types,
-			   serv->packets_dropped);
-}
-
-
-/**
- * radius_client_get_mib - Get RADIUS client MIB information
- * @radius: RADIUS client context from radius_client_init()
- * @buf: Buffer for returning MIB data in text format
- * @buflen: Maximum buf length in octets
- * Returns: Number of octets written into the buffer
- */
-int radius_client_get_mib(struct radius_client_data *radius, char *buf,
-			  size_t buflen)
-{
-	struct hostapd_radius_servers *conf = radius->conf;
-	int i;
-	struct hostapd_radius_server *serv;
-	int count = 0;
-
-	if (conf->auth_servers) {
-		for (i = 0; i < conf->num_auth_servers; i++) {
-			serv = &conf->auth_servers[i];
-			count += radius_client_dump_auth_server(
-				buf + count, buflen - count, serv,
-				serv == conf->auth_server ?
-				radius : NULL);
-		}
-	}
-
-	if (conf->acct_servers) {
-		for (i = 0; i < conf->num_acct_servers; i++) {
-			serv = &conf->acct_servers[i];
-			count += radius_client_dump_acct_server(
-				buf + count, buflen - count, serv,
-				serv == conf->acct_server ?
-				radius : NULL);
-		}
-	}
-
-	return count;
-}

Copied: vendor/wpa/2.0/src/radius/radius_client.c (from rev 9639, vendor/wpa/dist/src/radius/radius_client.c)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_client.c	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1493 @@
+/*
+ * RADIUS client
+ * Copyright (c) 2002-2009, Jouni Malinen <j at 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.h"
+#include "radius_client.h"
+#include "eloop.h"
+
+/* Defaults for RADIUS retransmit values (exponential backoff) */
+
+/**
+ * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
+ */
+#define RADIUS_CLIENT_FIRST_WAIT 3
+
+/**
+ * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
+ */
+#define RADIUS_CLIENT_MAX_WAIT 120
+
+/**
+ * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
+ *
+ * Maximum number of retransmit attempts before the entry is removed from
+ * retransmit list.
+ */
+#define RADIUS_CLIENT_MAX_RETRIES 10
+
+/**
+ * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
+ *
+ * Maximum number of entries in retransmit list (oldest entries will be
+ * removed, if this limit is exceeded).
+ */
+#define RADIUS_CLIENT_MAX_ENTRIES 30
+
+/**
+ * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
+ *
+ * The number of failed retry attempts after which the RADIUS server will be
+ * changed (if one of more backup servers are configured).
+ */
+#define RADIUS_CLIENT_NUM_FAILOVER 4
+
+
+/**
+ * struct radius_rx_handler - RADIUS client RX handler
+ *
+ * This data structure is used internally inside the RADIUS client module to
+ * store registered RX handlers. These handlers are registered by calls to
+ * radius_client_register() and unregistered when the RADIUS client is
+ * deinitialized with a call to radius_client_deinit().
+ */
+struct radius_rx_handler {
+	/**
+	 * handler - Received RADIUS message handler
+	 */
+	RadiusRxResult (*handler)(struct radius_msg *msg,
+				  struct radius_msg *req,
+				  const u8 *shared_secret,
+				  size_t shared_secret_len,
+				  void *data);
+
+	/**
+	 * data - Context data for the handler
+	 */
+	void *data;
+};
+
+
+/**
+ * struct radius_msg_list - RADIUS client message retransmit list
+ *
+ * This data structure is used internally inside the RADIUS client module to
+ * store pending RADIUS requests that may still need to be retransmitted.
+ */
+struct radius_msg_list {
+	/**
+	 * addr - STA/client address
+	 *
+	 * This is used to find RADIUS messages for the same STA.
+	 */
+	u8 addr[ETH_ALEN];
+
+	/**
+	 * msg - RADIUS message
+	 */
+	struct radius_msg *msg;
+
+	/**
+	 * msg_type - Message type
+	 */
+	RadiusType msg_type;
+
+	/**
+	 * first_try - Time of the first transmission attempt
+	 */
+	os_time_t first_try;
+
+	/**
+	 * next_try - Time for the next transmission attempt
+	 */
+	os_time_t next_try;
+
+	/**
+	 * attempts - Number of transmission attempts
+	 */
+	int attempts;
+
+	/**
+	 * next_wait - Next retransmission wait time in seconds
+	 */
+	int next_wait;
+
+	/**
+	 * last_attempt - Time of the last transmission attempt
+	 */
+	struct os_time last_attempt;
+
+	/**
+	 * shared_secret - Shared secret with the target RADIUS server
+	 */
+	const u8 *shared_secret;
+
+	/**
+	 * shared_secret_len - shared_secret length in octets
+	 */
+	size_t shared_secret_len;
+
+	/* TODO: server config with failover to backup server(s) */
+
+	/**
+	 * next - Next message in the list
+	 */
+	struct radius_msg_list *next;
+};
+
+
+/**
+ * struct radius_client_data - Internal RADIUS client data
+ *
+ * This data structure is used internally inside the RADIUS client module.
+ * External users allocate this by calling radius_client_init() and free it by
+ * calling radius_client_deinit(). The pointer to this opaque data is used in
+ * calls to other functions as an identifier for the RADIUS client instance.
+ */
+struct radius_client_data {
+	/**
+	 * ctx - Context pointer for hostapd_logger() callbacks
+	 */
+	void *ctx;
+
+	/**
+	 * conf - RADIUS client configuration (list of RADIUS servers to use)
+	 */
+	struct hostapd_radius_servers *conf;
+
+	/**
+	 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
+	 */
+	int auth_serv_sock;
+
+	/**
+	 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
+	 */
+	int acct_serv_sock;
+
+	/**
+	 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
+	 */
+	int auth_serv_sock6;
+
+	/**
+	 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
+	 */
+	int acct_serv_sock6;
+
+	/**
+	 * auth_sock - Currently used socket for RADIUS authentication server
+	 */
+	int auth_sock;
+
+	/**
+	 * acct_sock - Currently used socket for RADIUS accounting server
+	 */
+	int acct_sock;
+
+	/**
+	 * auth_handlers - Authentication message handlers
+	 */
+	struct radius_rx_handler *auth_handlers;
+
+	/**
+	 * num_auth_handlers - Number of handlers in auth_handlers
+	 */
+	size_t num_auth_handlers;
+
+	/**
+	 * acct_handlers - Accounting message handlers
+	 */
+	struct radius_rx_handler *acct_handlers;
+
+	/**
+	 * num_acct_handlers - Number of handlers in acct_handlers
+	 */
+	size_t num_acct_handlers;
+
+	/**
+	 * msgs - Pending outgoing RADIUS messages
+	 */
+	struct radius_msg_list *msgs;
+
+	/**
+	 * num_msgs - Number of pending messages in the msgs list
+	 */
+	size_t num_msgs;
+
+	/**
+	 * next_radius_identifier - Next RADIUS message identifier to use
+	 */
+	u8 next_radius_identifier;
+};
+
+
+static int
+radius_change_server(struct radius_client_data *radius,
+		     struct hostapd_radius_server *nserv,
+		     struct hostapd_radius_server *oserv,
+		     int sock, int sock6, int auth);
+static int radius_client_init_acct(struct radius_client_data *radius);
+static int radius_client_init_auth(struct radius_client_data *radius);
+
+
+static void radius_client_msg_free(struct radius_msg_list *req)
+{
+	radius_msg_free(req->msg);
+	os_free(req);
+}
+
+
+/**
+ * radius_client_register - Register a RADIUS client RX handler
+ * @radius: RADIUS client context from radius_client_init()
+ * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
+ * @handler: Handler for received RADIUS messages
+ * @data: Context pointer for handler callbacks
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to register a handler for processing received RADIUS
+ * authentication and accounting messages. The handler() callback function will
+ * be called whenever a RADIUS message is received from the active server.
+ *
+ * There can be multiple registered RADIUS message handlers. The handlers will
+ * be called in order until one of them indicates that it has processed or
+ * queued the message.
+ */
+int radius_client_register(struct radius_client_data *radius,
+			   RadiusType msg_type,
+			   RadiusRxResult (*handler)(struct radius_msg *msg,
+						     struct radius_msg *req,
+						     const u8 *shared_secret,
+						     size_t shared_secret_len,
+						     void *data),
+			   void *data)
+{
+	struct radius_rx_handler **handlers, *newh;
+	size_t *num;
+
+	if (msg_type == RADIUS_ACCT) {
+		handlers = &radius->acct_handlers;
+		num = &radius->num_acct_handlers;
+	} else {
+		handlers = &radius->auth_handlers;
+		num = &radius->num_auth_handlers;
+	}
+
+	newh = os_realloc_array(*handlers, *num + 1,
+				sizeof(struct radius_rx_handler));
+	if (newh == NULL)
+		return -1;
+
+	newh[*num].handler = handler;
+	newh[*num].data = data;
+	(*num)++;
+	*handlers = newh;
+
+	return 0;
+}
+
+
+static void radius_client_handle_send_error(struct radius_client_data *radius,
+					    int s, RadiusType msg_type)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+	int _errno = errno;
+	perror("send[RADIUS]");
+	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
+	    _errno == EBADF) {
+		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO,
+			       "Send failed - maybe interface status changed -"
+			       " try to connect again");
+		eloop_unregister_read_sock(s);
+		close(s);
+		if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
+			radius_client_init_acct(radius);
+		else
+			radius_client_init_auth(radius);
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+static int radius_client_retransmit(struct radius_client_data *radius,
+				    struct radius_msg_list *entry,
+				    os_time_t now)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	int s;
+	struct wpabuf *buf;
+
+	if (entry->msg_type == RADIUS_ACCT ||
+	    entry->msg_type == RADIUS_ACCT_INTERIM) {
+		s = radius->acct_sock;
+		if (entry->attempts == 0)
+			conf->acct_server->requests++;
+		else {
+			conf->acct_server->timeouts++;
+			conf->acct_server->retransmissions++;
+		}
+	} else {
+		s = radius->auth_sock;
+		if (entry->attempts == 0)
+			conf->auth_server->requests++;
+		else {
+			conf->auth_server->timeouts++;
+			conf->auth_server->retransmissions++;
+		}
+	}
+
+	/* retransmit; remove entry if too many attempts */
+	entry->attempts++;
+	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
+		       radius_msg_get_hdr(entry->msg)->identifier);
+
+	os_get_time(&entry->last_attempt);
+	buf = radius_msg_get_buf(entry->msg);
+	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
+		radius_client_handle_send_error(radius, s, entry->msg_type);
+
+	entry->next_try = now + entry->next_wait;
+	entry->next_wait *= 2;
+	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
+		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
+	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
+		printf("Removing un-ACKed RADIUS message due to too many "
+		       "failed retransmit attempts\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+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_time now;
+	os_time_t first;
+	struct radius_msg_list *entry, *prev, *tmp;
+	int auth_failover = 0, acct_failover = 0;
+	char abuf[50];
+
+	entry = radius->msgs;
+	if (!entry)
+		return;
+
+	os_get_time(&now);
+	first = 0;
+
+	prev = NULL;
+	while (entry) {
+		if (now.sec >= entry->next_try &&
+		    radius_client_retransmit(radius, entry, now.sec)) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				radius->msgs = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			radius_client_msg_free(tmp);
+			radius->num_msgs--;
+			continue;
+		}
+
+		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
+			if (entry->msg_type == RADIUS_ACCT ||
+			    entry->msg_type == RADIUS_ACCT_INTERIM)
+				acct_failover++;
+			else
+				auth_failover++;
+		}
+
+		if (first == 0 || entry->next_try < first)
+			first = entry->next_try;
+
+		prev = entry;
+		entry = entry->next;
+	}
+
+	if (radius->msgs) {
+		if (first < now.sec)
+			first = now.sec;
+		eloop_register_timeout(first - now.sec, 0,
+				       radius_client_timer, radius, NULL);
+		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
+			       "retransmit in %ld seconds",
+			       (long int) (first - now.sec));
+	}
+
+	if (auth_failover && conf->num_auth_servers > 1) {
+		struct hostapd_radius_server *next, *old;
+		old = conf->auth_server;
+		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "No response from Authentication server "
+			       "%s:%d - failover",
+			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+			       old->port);
+
+		for (entry = radius->msgs; entry; entry = entry->next) {
+			if (entry->msg_type == RADIUS_AUTH)
+				old->timeouts++;
+		}
+
+		next = old + 1;
+		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
+			next = conf->auth_servers;
+		conf->auth_server = next;
+		radius_change_server(radius, next, old,
+				     radius->auth_serv_sock,
+				     radius->auth_serv_sock6, 1);
+	}
+
+	if (acct_failover && conf->num_acct_servers > 1) {
+		struct hostapd_radius_server *next, *old;
+		old = conf->acct_server;
+		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "No response from Accounting server "
+			       "%s:%d - failover",
+			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+			       old->port);
+
+		for (entry = radius->msgs; entry; entry = entry->next) {
+			if (entry->msg_type == RADIUS_ACCT ||
+			    entry->msg_type == RADIUS_ACCT_INTERIM)
+				old->timeouts++;
+		}
+
+		next = old + 1;
+		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
+			next = conf->acct_servers;
+		conf->acct_server = next;
+		radius_change_server(radius, next, old,
+				     radius->acct_serv_sock,
+				     radius->acct_serv_sock6, 0);
+	}
+}
+
+
+static void radius_client_update_timeout(struct radius_client_data *radius)
+{
+	struct os_time now;
+	os_time_t first;
+	struct radius_msg_list *entry;
+
+	eloop_cancel_timeout(radius_client_timer, radius, NULL);
+
+	if (radius->msgs == NULL) {
+		return;
+	}
+
+	first = 0;
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if (first == 0 || entry->next_try < first)
+			first = entry->next_try;
+	}
+
+	os_get_time(&now);
+	if (first < now.sec)
+		first = now.sec;
+	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
+			       NULL);
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
+		       " %ld seconds", (long int) (first - now.sec));
+}
+
+
+static void radius_client_list_add(struct radius_client_data *radius,
+				   struct radius_msg *msg,
+				   RadiusType msg_type,
+				   const u8 *shared_secret,
+				   size_t shared_secret_len, const u8 *addr)
+{
+	struct radius_msg_list *entry, *prev;
+
+	if (eloop_terminated()) {
+		/* No point in adding entries to retransmit queue since event
+		 * loop has already been terminated. */
+		radius_msg_free(msg);
+		return;
+	}
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL) {
+		printf("Failed to add RADIUS packet into retransmit list\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (addr)
+		os_memcpy(entry->addr, addr, ETH_ALEN);
+	entry->msg = msg;
+	entry->msg_type = msg_type;
+	entry->shared_secret = shared_secret;
+	entry->shared_secret_len = shared_secret_len;
+	os_get_time(&entry->last_attempt);
+	entry->first_try = entry->last_attempt.sec;
+	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+	entry->attempts = 1;
+	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+	entry->next = radius->msgs;
+	radius->msgs = entry;
+	radius_client_update_timeout(radius);
+
+	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
+		printf("Removing the oldest un-ACKed RADIUS packet due to "
+		       "retransmit list limits.\n");
+		prev = NULL;
+		while (entry->next) {
+			prev = entry;
+			entry = entry->next;
+		}
+		if (prev) {
+			prev->next = NULL;
+			radius_client_msg_free(entry);
+		}
+	} else
+		radius->num_msgs++;
+}
+
+
+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()
+ * @msg: RADIUS message to be sent
+ * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
+ * @addr: MAC address of the device related to this message or %NULL
+ * Returns: 0 on success, -1 on failure
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ */
+int radius_client_send(struct radius_client_data *radius,
+		       struct radius_msg *msg, RadiusType msg_type,
+		       const u8 *addr)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	const u8 *shared_secret;
+	size_t shared_secret_len;
+	char *name;
+	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 == NULL) {
+			hostapd_logger(radius->ctx, NULL,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "No accounting server configured");
+			return -1;
+		}
+		shared_secret = conf->acct_server->shared_secret;
+		shared_secret_len = conf->acct_server->shared_secret_len;
+		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
+		name = "accounting";
+		s = radius->acct_sock;
+		conf->acct_server->requests++;
+	} else {
+		if (conf->auth_server == NULL) {
+			hostapd_logger(radius->ctx, NULL,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "No authentication server configured");
+			return -1;
+		}
+		shared_secret = conf->auth_server->shared_secret;
+		shared_secret_len = conf->auth_server->shared_secret_len;
+		radius_msg_finish(msg, shared_secret, shared_secret_len);
+		name = "authentication";
+		s = radius->auth_sock;
+		conf->auth_server->requests++;
+	}
+
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
+		       "server", name);
+	if (conf->msg_dumps)
+		radius_msg_dump(msg);
+
+	buf = radius_msg_get_buf(msg);
+	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (res < 0)
+		radius_client_handle_send_error(radius, s, msg_type);
+
+	radius_client_list_add(radius, msg, msg_type, shared_secret,
+			       shared_secret_len, addr);
+
+	return 0;
+}
+
+
+static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct radius_client_data *radius = eloop_ctx;
+	struct hostapd_radius_servers *conf = radius->conf;
+	RadiusType msg_type = (RadiusType) sock_ctx;
+	int len, roundtrip;
+	unsigned char buf[3000];
+	struct radius_msg *msg;
+	struct radius_hdr *hdr;
+	struct radius_rx_handler *handlers;
+	size_t num_handlers, i;
+	struct radius_msg_list *req, *prev_req;
+	struct os_time now;
+	struct hostapd_radius_server *rconf;
+	int invalid_authenticator = 0;
+
+	if (msg_type == RADIUS_ACCT) {
+		handlers = radius->acct_handlers;
+		num_handlers = radius->num_acct_handlers;
+		rconf = conf->acct_server;
+	} else {
+		handlers = radius->auth_handlers;
+		num_handlers = radius->num_auth_handlers;
+		rconf = conf->auth_server;
+	}
+
+	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
+	if (len < 0) {
+		perror("recv[RADIUS]");
+		return;
+	}
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
+		       "server", len);
+	if (len == sizeof(buf)) {
+		printf("Possibly too long UDP frame for our buffer - "
+		       "dropping it\n");
+		return;
+	}
+
+	msg = radius_msg_parse(buf, len);
+	if (msg == NULL) {
+		printf("Parsing incoming RADIUS frame failed\n");
+		rconf->malformed_responses++;
+		return;
+	}
+	hdr = radius_msg_get_hdr(msg);
+
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
+	if (conf->msg_dumps)
+		radius_msg_dump(msg);
+
+	switch (hdr->code) {
+	case RADIUS_CODE_ACCESS_ACCEPT:
+		rconf->access_accepts++;
+		break;
+	case RADIUS_CODE_ACCESS_REJECT:
+		rconf->access_rejects++;
+		break;
+	case RADIUS_CODE_ACCESS_CHALLENGE:
+		rconf->access_challenges++;
+		break;
+	case RADIUS_CODE_ACCOUNTING_RESPONSE:
+		rconf->responses++;
+		break;
+	}
+
+	prev_req = NULL;
+	req = radius->msgs;
+	while (req) {
+		/* TODO: also match by src addr:port of the packet when using
+		 * alternative RADIUS servers (?) */
+		if ((req->msg_type == msg_type ||
+		     (req->msg_type == RADIUS_ACCT_INTERIM &&
+		      msg_type == RADIUS_ACCT)) &&
+		    radius_msg_get_hdr(req->msg)->identifier ==
+		    hdr->identifier)
+			break;
+
+		prev_req = req;
+		req = req->next;
+	}
+
+	if (req == NULL) {
+		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "No matching RADIUS request found (type=%d "
+			       "id=%d) - dropping packet",
+			       msg_type, hdr->identifier);
+		goto fail;
+	}
+
+	os_get_time(&now);
+	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
+		(now.usec - req->last_attempt.usec) / 10000;
+	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Received RADIUS packet matched with a pending "
+		       "request, round trip time %d.%02d sec",
+		       roundtrip / 100, roundtrip % 100);
+	rconf->round_trip_time = roundtrip;
+
+	/* Remove ACKed RADIUS packet from retransmit list */
+	if (prev_req)
+		prev_req->next = req->next;
+	else
+		radius->msgs = req->next;
+	radius->num_msgs--;
+
+	for (i = 0; i < num_handlers; i++) {
+		RadiusRxResult res;
+		res = handlers[i].handler(msg, req->msg, req->shared_secret,
+					  req->shared_secret_len,
+					  handlers[i].data);
+		switch (res) {
+		case RADIUS_RX_PROCESSED:
+			radius_msg_free(msg);
+			/* continue */
+		case RADIUS_RX_QUEUED:
+			radius_client_msg_free(req);
+			return;
+		case RADIUS_RX_INVALID_AUTHENTICATOR:
+			invalid_authenticator++;
+			/* continue */
+		case RADIUS_RX_UNKNOWN:
+			/* continue with next handler */
+			break;
+		}
+	}
+
+	if (invalid_authenticator)
+		rconf->bad_authenticators++;
+	else
+		rconf->unknown_types++;
+	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
+		       "(type=%d code=%d id=%d)%s - dropping packet",
+		       msg_type, hdr->code, hdr->identifier,
+		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
+		       "");
+	radius_client_msg_free(req);
+
+ fail:
+	radius_msg_free(msg);
+}
+
+
+/**
+ * radius_client_get_id - Get an identifier for a new RADIUS message
+ * @radius: RADIUS client context from radius_client_init()
+ * Returns: Allocated identifier
+ *
+ * This function is used to fetch a unique (among pending requests) identifier
+ * for a new RADIUS message.
+ */
+u8 radius_client_get_id(struct radius_client_data *radius)
+{
+	struct radius_msg_list *entry, *prev, *_remove;
+	u8 id = radius->next_radius_identifier++;
+
+	/* remove entries with matching id from retransmit list to avoid
+	 * using new reply from the RADIUS server with an old request */
+	entry = radius->msgs;
+	prev = NULL;
+	while (entry) {
+		if (radius_msg_get_hdr(entry->msg)->identifier == id) {
+			hostapd_logger(radius->ctx, entry->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Removing pending RADIUS message, "
+				       "since its id (%d) is reused", id);
+			if (prev)
+				prev->next = entry->next;
+			else
+				radius->msgs = entry->next;
+			_remove = entry;
+		} else {
+			_remove = NULL;
+			prev = entry;
+		}
+		entry = entry->next;
+
+		if (_remove)
+			radius_client_msg_free(_remove);
+	}
+
+	return id;
+}
+
+
+/**
+ * radius_client_flush - Flush all pending RADIUS client messages
+ * @radius: RADIUS client context from radius_client_init()
+ * @only_auth: Whether only authentication messages are removed
+ */
+void radius_client_flush(struct radius_client_data *radius, int only_auth)
+{
+	struct radius_msg_list *entry, *prev, *tmp;
+
+	if (!radius)
+		return;
+
+	prev = NULL;
+	entry = radius->msgs;
+
+	while (entry) {
+		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				radius->msgs = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			radius_client_msg_free(tmp);
+			radius->num_msgs--;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+
+	if (radius->msgs == NULL)
+		eloop_cancel_timeout(radius_client_timer, radius, NULL);
+}
+
+
+static void radius_client_update_acct_msgs(struct radius_client_data *radius,
+					   const u8 *shared_secret,
+					   size_t shared_secret_len)
+{
+	struct radius_msg_list *entry;
+
+	if (!radius)
+		return;
+
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if (entry->msg_type == RADIUS_ACCT) {
+			entry->shared_secret = shared_secret;
+			entry->shared_secret_len = shared_secret_len;
+			radius_msg_finish_acct(entry->msg, shared_secret,
+					       shared_secret_len);
+		}
+	}
+}
+
+
+static int
+radius_change_server(struct radius_client_data *radius,
+		     struct hostapd_radius_server *nserv,
+		     struct hostapd_radius_server *oserv,
+		     int sock, int sock6, int auth)
+{
+	struct sockaddr_in serv, claddr;
+#ifdef CONFIG_IPV6
+	struct sockaddr_in6 serv6, claddr6;
+#endif /* CONFIG_IPV6 */
+	struct sockaddr *addr, *cl_addr;
+	socklen_t addrlen, claddrlen;
+	char abuf[50];
+	int sel_sock;
+	struct radius_msg_list *entry;
+	struct hostapd_radius_servers *conf = radius->conf;
+
+	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_INFO,
+		       "%s server %s:%d",
+		       auth ? "Authentication" : "Accounting",
+		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
+		       nserv->port);
+
+	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
+	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
+		      nserv->shared_secret_len) != 0) {
+		/* Pending RADIUS packets used different shared secret, so
+		 * they need to be modified. Update accounting message
+		 * authenticators here. Authentication messages are removed
+		 * since they would require more changes and the new RADIUS
+		 * server may not be prepared to receive them anyway due to
+		 * missing state information. Client will likely retry
+		 * authentication, so this should not be an issue. */
+		if (auth)
+			radius_client_flush(radius, 1);
+		else {
+			radius_client_update_acct_msgs(
+				radius, nserv->shared_secret,
+				nserv->shared_secret_len);
+		}
+	}
+
+	/* Reset retry counters for the new server */
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if ((auth && entry->msg_type != RADIUS_AUTH) ||
+		    (!auth && entry->msg_type != RADIUS_ACCT))
+			continue;
+		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+		entry->attempts = 0;
+		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+	}
+
+	if (radius->msgs) {
+		eloop_cancel_timeout(radius_client_timer, radius, NULL);
+		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
+				       radius_client_timer, radius, NULL);
+	}
+
+	switch (nserv->addr.af) {
+	case AF_INET:
+		os_memset(&serv, 0, sizeof(serv));
+		serv.sin_family = AF_INET;
+		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
+		serv.sin_port = htons(nserv->port);
+		addr = (struct sockaddr *) &serv;
+		addrlen = sizeof(serv);
+		sel_sock = sock;
+		break;
+#ifdef CONFIG_IPV6
+	case AF_INET6:
+		os_memset(&serv6, 0, sizeof(serv6));
+		serv6.sin6_family = AF_INET6;
+		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
+			  sizeof(struct in6_addr));
+		serv6.sin6_port = htons(nserv->port);
+		addr = (struct sockaddr *) &serv6;
+		addrlen = sizeof(serv6);
+		sel_sock = sock6;
+		break;
+#endif /* CONFIG_IPV6 */
+	default:
+		return -1;
+	}
+
+	if (conf->force_client_addr) {
+		switch (conf->client_addr.af) {
+		case AF_INET:
+			os_memset(&claddr, 0, sizeof(claddr));
+			claddr.sin_family = AF_INET;
+			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
+			claddr.sin_port = htons(0);
+			cl_addr = (struct sockaddr *) &claddr;
+			claddrlen = sizeof(claddr);
+			break;
+#ifdef CONFIG_IPV6
+		case AF_INET6:
+			os_memset(&claddr6, 0, sizeof(claddr6));
+			claddr6.sin6_family = AF_INET6;
+			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
+				  sizeof(struct in6_addr));
+			claddr6.sin6_port = htons(0);
+			cl_addr = (struct sockaddr *) &claddr6;
+			claddrlen = sizeof(claddr6);
+			break;
+#endif /* CONFIG_IPV6 */
+		default:
+			return -1;
+		}
+
+		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
+			perror("bind[radius]");
+			return -1;
+		}
+	}
+
+	if (connect(sel_sock, addr, addrlen) < 0) {
+		perror("connect[radius]");
+		return -1;
+	}
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	switch (nserv->addr.af) {
+	case AF_INET:
+		claddrlen = sizeof(claddr);
+		getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
+		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+			   inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+		break;
+#ifdef CONFIG_IPV6
+	case AF_INET6: {
+		claddrlen = sizeof(claddr6);
+		getsockname(sel_sock, (struct sockaddr *) &claddr6,
+			    &claddrlen);
+		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+			   inet_ntop(AF_INET6, &claddr6.sin6_addr,
+				     abuf, sizeof(abuf)),
+			   ntohs(claddr6.sin6_port));
+		break;
+	}
+#endif /* CONFIG_IPV6 */
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	if (auth)
+		radius->auth_sock = sel_sock;
+	else
+		radius->acct_sock = sel_sock;
+
+	return 0;
+}
+
+
+static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct radius_client_data *radius = eloop_ctx;
+	struct hostapd_radius_servers *conf = radius->conf;
+	struct hostapd_radius_server *oserv;
+
+	if (radius->auth_sock >= 0 && conf->auth_servers &&
+	    conf->auth_server != conf->auth_servers) {
+		oserv = conf->auth_server;
+		conf->auth_server = conf->auth_servers;
+		radius_change_server(radius, conf->auth_server, oserv,
+				     radius->auth_serv_sock,
+				     radius->auth_serv_sock6, 1);
+	}
+
+	if (radius->acct_sock >= 0 && conf->acct_servers &&
+	    conf->acct_server != conf->acct_servers) {
+		oserv = conf->acct_server;
+		conf->acct_server = conf->acct_servers;
+		radius_change_server(radius, conf->acct_server, oserv,
+				     radius->acct_serv_sock,
+				     radius->acct_serv_sock6, 0);
+	}
+
+	if (conf->retry_primary_interval)
+		eloop_register_timeout(conf->retry_primary_interval, 0,
+				       radius_retry_primary_timer, radius,
+				       NULL);
+}
+
+
+static int radius_client_disable_pmtu_discovery(int s)
+{
+	int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
+	int action = IP_PMTUDISC_DONT;
+	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+		       sizeof(action));
+	if (r == -1)
+		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
+			   "%s", strerror(errno));
+#endif
+	return r;
+}
+
+
+static int radius_client_init_auth(struct radius_client_data *radius)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	int ok = 0;
+
+	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (radius->auth_serv_sock < 0)
+		perror("socket[PF_INET,SOCK_DGRAM]");
+	else {
+		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
+		ok++;
+	}
+
+#ifdef CONFIG_IPV6
+	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (radius->auth_serv_sock6 < 0)
+		perror("socket[PF_INET6,SOCK_DGRAM]");
+	else
+		ok++;
+#endif /* CONFIG_IPV6 */
+
+	if (ok == 0)
+		return -1;
+
+	radius_change_server(radius, conf->auth_server, NULL,
+			     radius->auth_serv_sock, radius->auth_serv_sock6,
+			     1);
+
+	if (radius->auth_serv_sock >= 0 &&
+	    eloop_register_read_sock(radius->auth_serv_sock,
+				     radius_client_receive, radius,
+				     (void *) RADIUS_AUTH)) {
+		printf("Could not register read socket for authentication "
+		       "server\n");
+		return -1;
+	}
+
+#ifdef CONFIG_IPV6
+	if (radius->auth_serv_sock6 >= 0 &&
+	    eloop_register_read_sock(radius->auth_serv_sock6,
+				     radius_client_receive, radius,
+				     (void *) RADIUS_AUTH)) {
+		printf("Could not register read socket for authentication "
+		       "server\n");
+		return -1;
+	}
+#endif /* CONFIG_IPV6 */
+
+	return 0;
+}
+
+
+static int radius_client_init_acct(struct radius_client_data *radius)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	int ok = 0;
+
+	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (radius->acct_serv_sock < 0)
+		perror("socket[PF_INET,SOCK_DGRAM]");
+	else {
+		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
+		ok++;
+	}
+
+#ifdef CONFIG_IPV6
+	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (radius->acct_serv_sock6 < 0)
+		perror("socket[PF_INET6,SOCK_DGRAM]");
+	else
+		ok++;
+#endif /* CONFIG_IPV6 */
+
+	if (ok == 0)
+		return -1;
+
+	radius_change_server(radius, conf->acct_server, NULL,
+			     radius->acct_serv_sock, radius->acct_serv_sock6,
+			     0);
+
+	if (radius->acct_serv_sock >= 0 &&
+	    eloop_register_read_sock(radius->acct_serv_sock,
+				     radius_client_receive, radius,
+				     (void *) RADIUS_ACCT)) {
+		printf("Could not register read socket for accounting "
+		       "server\n");
+		return -1;
+	}
+
+#ifdef CONFIG_IPV6
+	if (radius->acct_serv_sock6 >= 0 &&
+	    eloop_register_read_sock(radius->acct_serv_sock6,
+				     radius_client_receive, radius,
+				     (void *) RADIUS_ACCT)) {
+		printf("Could not register read socket for accounting "
+		       "server\n");
+		return -1;
+	}
+#endif /* CONFIG_IPV6 */
+
+	return 0;
+}
+
+
+/**
+ * radius_client_init - Initialize RADIUS client
+ * @ctx: Callback context to be used in hostapd_logger() calls
+ * @conf: RADIUS client configuration (RADIUS servers)
+ * Returns: Pointer to private RADIUS client context or %NULL on failure
+ *
+ * The caller is responsible for keeping the configuration data available for
+ * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
+ * called for the returned context pointer.
+ */
+struct radius_client_data *
+radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
+{
+	struct radius_client_data *radius;
+
+	radius = os_zalloc(sizeof(struct radius_client_data));
+	if (radius == NULL)
+		return NULL;
+
+	radius->ctx = ctx;
+	radius->conf = conf;
+	radius->auth_serv_sock = radius->acct_serv_sock =
+		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
+		radius->auth_sock = radius->acct_sock = -1;
+
+	if (conf->auth_server && radius_client_init_auth(radius)) {
+		radius_client_deinit(radius);
+		return NULL;
+	}
+
+	if (conf->acct_server && radius_client_init_acct(radius)) {
+		radius_client_deinit(radius);
+		return NULL;
+	}
+
+	if (conf->retry_primary_interval)
+		eloop_register_timeout(conf->retry_primary_interval, 0,
+				       radius_retry_primary_timer, radius,
+				       NULL);
+
+	return radius;
+}
+
+
+/**
+ * radius_client_deinit - Deinitialize RADIUS client
+ * @radius: RADIUS client context from radius_client_init()
+ */
+void radius_client_deinit(struct radius_client_data *radius)
+{
+	if (!radius)
+		return;
+
+	if (radius->auth_serv_sock >= 0)
+		eloop_unregister_read_sock(radius->auth_serv_sock);
+	if (radius->acct_serv_sock >= 0)
+		eloop_unregister_read_sock(radius->acct_serv_sock);
+#ifdef CONFIG_IPV6
+	if (radius->auth_serv_sock6 >= 0)
+		eloop_unregister_read_sock(radius->auth_serv_sock6);
+	if (radius->acct_serv_sock6 >= 0)
+		eloop_unregister_read_sock(radius->acct_serv_sock6);
+#endif /* CONFIG_IPV6 */
+
+	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
+
+	radius_client_flush(radius, 0);
+	os_free(radius->auth_handlers);
+	os_free(radius->acct_handlers);
+	os_free(radius);
+}
+
+
+/**
+ * radius_client_flush_auth - Flush pending RADIUS messages for an address
+ * @radius: RADIUS client context from radius_client_init()
+ * @addr: MAC address of the related device
+ *
+ * This function can be used to remove pending RADIUS authentication messages
+ * that are related to a specific device. The addr parameter is matched with
+ * the one used in radius_client_send() call that was used to transmit the
+ * authentication request.
+ */
+void radius_client_flush_auth(struct radius_client_data *radius,
+			      const u8 *addr)
+{
+	struct radius_msg_list *entry, *prev, *tmp;
+
+	prev = NULL;
+	entry = radius->msgs;
+	while (entry) {
+		if (entry->msg_type == RADIUS_AUTH &&
+		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+			hostapd_logger(radius->ctx, addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Removing pending RADIUS authentication"
+				       " message for removed client");
+
+			if (prev)
+				prev->next = entry->next;
+			else
+				radius->msgs = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			radius_client_msg_free(tmp);
+			radius->num_msgs--;
+			continue;
+		}
+
+		prev = entry;
+		entry = entry->next;
+	}
+}
+
+
+static int radius_client_dump_auth_server(char *buf, size_t buflen,
+					  struct hostapd_radius_server *serv,
+					  struct radius_client_data *cli)
+{
+	int pending = 0;
+	struct radius_msg_list *msg;
+	char abuf[50];
+
+	if (cli) {
+		for (msg = cli->msgs; msg; msg = msg->next) {
+			if (msg->msg_type == RADIUS_AUTH)
+				pending++;
+		}
+	}
+
+	return os_snprintf(buf, buflen,
+			   "radiusAuthServerIndex=%d\n"
+			   "radiusAuthServerAddress=%s\n"
+			   "radiusAuthClientServerPortNumber=%d\n"
+			   "radiusAuthClientRoundTripTime=%d\n"
+			   "radiusAuthClientAccessRequests=%u\n"
+			   "radiusAuthClientAccessRetransmissions=%u\n"
+			   "radiusAuthClientAccessAccepts=%u\n"
+			   "radiusAuthClientAccessRejects=%u\n"
+			   "radiusAuthClientAccessChallenges=%u\n"
+			   "radiusAuthClientMalformedAccessResponses=%u\n"
+			   "radiusAuthClientBadAuthenticators=%u\n"
+			   "radiusAuthClientPendingRequests=%u\n"
+			   "radiusAuthClientTimeouts=%u\n"
+			   "radiusAuthClientUnknownTypes=%u\n"
+			   "radiusAuthClientPacketsDropped=%u\n",
+			   serv->index,
+			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+			   serv->port,
+			   serv->round_trip_time,
+			   serv->requests,
+			   serv->retransmissions,
+			   serv->access_accepts,
+			   serv->access_rejects,
+			   serv->access_challenges,
+			   serv->malformed_responses,
+			   serv->bad_authenticators,
+			   pending,
+			   serv->timeouts,
+			   serv->unknown_types,
+			   serv->packets_dropped);
+}
+
+
+static int radius_client_dump_acct_server(char *buf, size_t buflen,
+					  struct hostapd_radius_server *serv,
+					  struct radius_client_data *cli)
+{
+	int pending = 0;
+	struct radius_msg_list *msg;
+	char abuf[50];
+
+	if (cli) {
+		for (msg = cli->msgs; msg; msg = msg->next) {
+			if (msg->msg_type == RADIUS_ACCT ||
+			    msg->msg_type == RADIUS_ACCT_INTERIM)
+				pending++;
+		}
+	}
+
+	return os_snprintf(buf, buflen,
+			   "radiusAccServerIndex=%d\n"
+			   "radiusAccServerAddress=%s\n"
+			   "radiusAccClientServerPortNumber=%d\n"
+			   "radiusAccClientRoundTripTime=%d\n"
+			   "radiusAccClientRequests=%u\n"
+			   "radiusAccClientRetransmissions=%u\n"
+			   "radiusAccClientResponses=%u\n"
+			   "radiusAccClientMalformedResponses=%u\n"
+			   "radiusAccClientBadAuthenticators=%u\n"
+			   "radiusAccClientPendingRequests=%u\n"
+			   "radiusAccClientTimeouts=%u\n"
+			   "radiusAccClientUnknownTypes=%u\n"
+			   "radiusAccClientPacketsDropped=%u\n",
+			   serv->index,
+			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+			   serv->port,
+			   serv->round_trip_time,
+			   serv->requests,
+			   serv->retransmissions,
+			   serv->responses,
+			   serv->malformed_responses,
+			   serv->bad_authenticators,
+			   pending,
+			   serv->timeouts,
+			   serv->unknown_types,
+			   serv->packets_dropped);
+}
+
+
+/**
+ * radius_client_get_mib - Get RADIUS client MIB information
+ * @radius: RADIUS client context from radius_client_init()
+ * @buf: Buffer for returning MIB data in text format
+ * @buflen: Maximum buf length in octets
+ * Returns: Number of octets written into the buffer
+ */
+int radius_client_get_mib(struct radius_client_data *radius, char *buf,
+			  size_t buflen)
+{
+	struct hostapd_radius_servers *conf = radius->conf;
+	int i;
+	struct hostapd_radius_server *serv;
+	int count = 0;
+
+	if (conf->auth_servers) {
+		for (i = 0; i < conf->num_auth_servers; i++) {
+			serv = &conf->auth_servers[i];
+			count += radius_client_dump_auth_server(
+				buf + count, buflen - count, serv,
+				serv == conf->auth_server ?
+				radius : NULL);
+		}
+	}
+
+	if (conf->acct_servers) {
+		for (i = 0; i < conf->num_acct_servers; i++) {
+			serv = &conf->acct_servers[i];
+			count += radius_client_dump_acct_server(
+				buf + count, buflen - count, serv,
+				serv == conf->acct_server ?
+				radius : NULL);
+		}
+	}
+
+	return count;
+}
+
+
+void radius_client_reconfig(struct radius_client_data *radius,
+			    struct hostapd_radius_servers *conf)
+{
+	if (radius)
+		radius->conf = conf;
+}

Deleted: vendor/wpa/2.0/src/radius/radius_client.h
===================================================================
--- vendor/wpa/dist/src/radius/radius_client.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,263 +0,0 @@
-/*
- * RADIUS client
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef RADIUS_CLIENT_H
-#define RADIUS_CLIENT_H
-
-#include "ip_addr.h"
-
-struct radius_msg;
-
-/**
- * struct hostapd_radius_server - RADIUS server information for RADIUS client
- *
- * This structure contains information about a RADIUS server. The values are
- * mainly for MIB information. The MIB variable prefix (radiusAuth or
- * radiusAcc) depends on whether this is an authentication or accounting
- * server.
- *
- * radiusAuthClientPendingRequests (or radiusAccClientPendingRequests) is the
- * number struct radius_client_data::msgs for matching msg_type.
- */
-struct hostapd_radius_server {
-	/**
-	 * addr - radiusAuthServerAddress or radiusAccServerAddress
-	 */
-	struct hostapd_ip_addr addr;
-
-	/**
-	 * port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber
-	 */
-	int port;
-
-	/**
-	 * shared_secret - Shared secret for authenticating RADIUS messages
-	 */
-	u8 *shared_secret;
-
-	/**
-	 * shared_secret_len - Length of shared_secret in octets
-	 */
-	size_t shared_secret_len;
-
-	/* Dynamic (not from configuration file) MIB data */
-
-	/**
-	 * index - radiusAuthServerIndex or radiusAccServerIndex
-	 */
-	int index;
-
-	/**
-	 * round_trip_time - radiusAuthClientRoundTripTime or radiusAccClientRoundTripTime
-	 * Round-trip time in hundredths of a second.
-	 */
-	int round_trip_time;
-
-	/**
-	 * requests - radiusAuthClientAccessRequests or radiusAccClientRequests
-	 */
-	u32 requests;
-
-	/**
-	 * retransmissions - radiusAuthClientAccessRetransmissions or radiusAccClientRetransmissions
-	 */
-	u32 retransmissions;
-
-	/**
-	 * access_accepts - radiusAuthClientAccessAccepts
-	 */
-	u32 access_accepts;
-
-	/**
-	 * access_rejects - radiusAuthClientAccessRejects
-	 */
-	u32 access_rejects;
-
-	/**
-	 * access_challenges - radiusAuthClientAccessChallenges
-	 */
-	u32 access_challenges;
-
-	/**
-	 * responses - radiusAccClientResponses
-	 */
-	u32 responses;
-
-	/**
-	 * malformed_responses - radiusAuthClientMalformedAccessResponses or radiusAccClientMalformedResponses
-	 */
-	u32 malformed_responses;
-
-	/**
-	 * bad_authenticators - radiusAuthClientBadAuthenticators or radiusAccClientBadAuthenticators
-	 */
-	u32 bad_authenticators;
-
-	/**
-	 * timeouts - radiusAuthClientTimeouts or radiusAccClientTimeouts
-	 */
-	u32 timeouts;
-
-	/**
-	 * unknown_types - radiusAuthClientUnknownTypes or radiusAccClientUnknownTypes
-	 */
-	u32 unknown_types;
-
-	/**
-	 * packets_dropped - radiusAuthClientPacketsDropped or radiusAccClientPacketsDropped
-	 */
-	u32 packets_dropped;
-};
-
-/**
- * struct hostapd_radius_servers - RADIUS servers for RADIUS client
- */
-struct hostapd_radius_servers {
-	/**
-	 * auth_servers - RADIUS Authentication servers in priority order
-	 */
-	struct hostapd_radius_server *auth_servers;
-
-	/**
-	 * num_auth_servers - Number of auth_servers entries
-	 */
-	int num_auth_servers;
-
-	/**
-	 * auth_server - The current Authentication server
-	 */
-	struct hostapd_radius_server *auth_server;
-
-	/**
-	 * acct_servers - RADIUS Accounting servers in priority order
-	 */
-	struct hostapd_radius_server *acct_servers;
-
-	/**
-	 * num_acct_servers - Number of acct_servers entries
-	 */
-	int num_acct_servers;
-
-	/**
-	 * acct_server - The current Accounting server
-	 */
-	struct hostapd_radius_server *acct_server;
-
-	/**
-	 * retry_primary_interval - Retry interval for trying primary server
-	 *
-	 * This specifies a retry interval in sexconds for trying to return to
-	 * the primary RADIUS server. RADIUS client code will automatically try
-	 * to use the next server when the current server is not replying to
-	 * requests. If this interval is set (non-zero), the primary server
-	 * will be retried after the specified number of seconds has passed
-	 * even if the current used secondary server is still working.
-	 */
-	int retry_primary_interval;
-
-	/**
-	 * msg_dumps - Whether RADIUS message details are shown in stdout
-	 */
-	int msg_dumps;
-
-	/**
-	 * client_addr - Client (local) address to use if force_client_addr
-	 */
-	struct hostapd_ip_addr client_addr;
-
-	/**
-	 * force_client_addr - Whether to force client (local) address
-	 */
-	int force_client_addr;
-};
-
-
-/**
- * RadiusType - RADIUS server type for RADIUS client
- */
-typedef enum {
-	/**
-	 * RADIUS authentication
-	 */
-	RADIUS_AUTH,
-
-	/**
-	 * RADIUS_ACCT - RADIUS accounting
-	 */
-	RADIUS_ACCT,
-
-	/**
-	 * RADIUS_ACCT_INTERIM - RADIUS interim accounting message
-	 *
-	 * Used only with radius_client_send(). This behaves just like
-	 * RADIUS_ACCT, but removes any pending interim RADIUS Accounting
-	 * messages for the same STA before sending the new interim update.
-	 */
-	RADIUS_ACCT_INTERIM
-} RadiusType;
-
-/**
- * RadiusRxResult - RADIUS client RX handler result
- */
-typedef enum {
-	/**
-	 * RADIUS_RX_PROCESSED - Message processed
-	 *
-	 * This stops handler calls and frees the message.
-	 */
-	RADIUS_RX_PROCESSED,
-
-	/**
-	 * RADIUS_RX_QUEUED - Message has been queued
-	 *
-	 * This stops handler calls, but does not free the message; the handler
-	 * that returned this is responsible for eventually freeing the
-	 * message.
-	 */
-	RADIUS_RX_QUEUED,
-
-	/**
-	 * RADIUS_RX_UNKNOWN - Message is not for this handler
-	 */
-	RADIUS_RX_UNKNOWN,
-
-	/**
-	 * RADIUS_RX_INVALID_AUTHENTICATOR - Message has invalid Authenticator
-	 */
-	RADIUS_RX_INVALID_AUTHENTICATOR
-} RadiusRxResult;
-
-struct radius_client_data;
-
-int radius_client_register(struct radius_client_data *radius,
-			   RadiusType msg_type,
-			   RadiusRxResult (*handler)
-			   (struct radius_msg *msg, struct radius_msg *req,
-			    const u8 *shared_secret, size_t shared_secret_len,
-			    void *data),
-			   void *data);
-int radius_client_send(struct radius_client_data *radius,
-		       struct radius_msg *msg,
-		       RadiusType msg_type, const u8 *addr);
-u8 radius_client_get_id(struct radius_client_data *radius);
-void radius_client_flush(struct radius_client_data *radius, int only_auth);
-struct radius_client_data *
-radius_client_init(void *ctx, struct hostapd_radius_servers *conf);
-void radius_client_deinit(struct radius_client_data *radius);
-void radius_client_flush_auth(struct radius_client_data *radius,
-			      const u8 *addr);
-int radius_client_get_mib(struct radius_client_data *radius, char *buf,
-			  size_t buflen);
-
-#endif /* RADIUS_CLIENT_H */

Copied: vendor/wpa/2.0/src/radius/radius_client.h (from rev 9639, vendor/wpa/dist/src/radius/radius_client.h)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_client.h	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,259 @@
+/*
+ * RADIUS client
+ * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_CLIENT_H
+#define RADIUS_CLIENT_H
+
+#include "ip_addr.h"
+
+struct radius_msg;
+
+/**
+ * struct hostapd_radius_server - RADIUS server information for RADIUS client
+ *
+ * This structure contains information about a RADIUS server. The values are
+ * mainly for MIB information. The MIB variable prefix (radiusAuth or
+ * radiusAcc) depends on whether this is an authentication or accounting
+ * server.
+ *
+ * radiusAuthClientPendingRequests (or radiusAccClientPendingRequests) is the
+ * number struct radius_client_data::msgs for matching msg_type.
+ */
+struct hostapd_radius_server {
+	/**
+	 * addr - radiusAuthServerAddress or radiusAccServerAddress
+	 */
+	struct hostapd_ip_addr addr;
+
+	/**
+	 * port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber
+	 */
+	int port;
+
+	/**
+	 * shared_secret - Shared secret for authenticating RADIUS messages
+	 */
+	u8 *shared_secret;
+
+	/**
+	 * shared_secret_len - Length of shared_secret in octets
+	 */
+	size_t shared_secret_len;
+
+	/* Dynamic (not from configuration file) MIB data */
+
+	/**
+	 * index - radiusAuthServerIndex or radiusAccServerIndex
+	 */
+	int index;
+
+	/**
+	 * round_trip_time - radiusAuthClientRoundTripTime or radiusAccClientRoundTripTime
+	 * Round-trip time in hundredths of a second.
+	 */
+	int round_trip_time;
+
+	/**
+	 * requests - radiusAuthClientAccessRequests or radiusAccClientRequests
+	 */
+	u32 requests;
+
+	/**
+	 * retransmissions - radiusAuthClientAccessRetransmissions or radiusAccClientRetransmissions
+	 */
+	u32 retransmissions;
+
+	/**
+	 * access_accepts - radiusAuthClientAccessAccepts
+	 */
+	u32 access_accepts;
+
+	/**
+	 * access_rejects - radiusAuthClientAccessRejects
+	 */
+	u32 access_rejects;
+
+	/**
+	 * access_challenges - radiusAuthClientAccessChallenges
+	 */
+	u32 access_challenges;
+
+	/**
+	 * responses - radiusAccClientResponses
+	 */
+	u32 responses;
+
+	/**
+	 * malformed_responses - radiusAuthClientMalformedAccessResponses or radiusAccClientMalformedResponses
+	 */
+	u32 malformed_responses;
+
+	/**
+	 * bad_authenticators - radiusAuthClientBadAuthenticators or radiusAccClientBadAuthenticators
+	 */
+	u32 bad_authenticators;
+
+	/**
+	 * timeouts - radiusAuthClientTimeouts or radiusAccClientTimeouts
+	 */
+	u32 timeouts;
+
+	/**
+	 * unknown_types - radiusAuthClientUnknownTypes or radiusAccClientUnknownTypes
+	 */
+	u32 unknown_types;
+
+	/**
+	 * packets_dropped - radiusAuthClientPacketsDropped or radiusAccClientPacketsDropped
+	 */
+	u32 packets_dropped;
+};
+
+/**
+ * struct hostapd_radius_servers - RADIUS servers for RADIUS client
+ */
+struct hostapd_radius_servers {
+	/**
+	 * auth_servers - RADIUS Authentication servers in priority order
+	 */
+	struct hostapd_radius_server *auth_servers;
+
+	/**
+	 * num_auth_servers - Number of auth_servers entries
+	 */
+	int num_auth_servers;
+
+	/**
+	 * auth_server - The current Authentication server
+	 */
+	struct hostapd_radius_server *auth_server;
+
+	/**
+	 * acct_servers - RADIUS Accounting servers in priority order
+	 */
+	struct hostapd_radius_server *acct_servers;
+
+	/**
+	 * num_acct_servers - Number of acct_servers entries
+	 */
+	int num_acct_servers;
+
+	/**
+	 * acct_server - The current Accounting server
+	 */
+	struct hostapd_radius_server *acct_server;
+
+	/**
+	 * retry_primary_interval - Retry interval for trying primary server
+	 *
+	 * This specifies a retry interval in sexconds for trying to return to
+	 * the primary RADIUS server. RADIUS client code will automatically try
+	 * to use the next server when the current server is not replying to
+	 * requests. If this interval is set (non-zero), the primary server
+	 * will be retried after the specified number of seconds has passed
+	 * even if the current used secondary server is still working.
+	 */
+	int retry_primary_interval;
+
+	/**
+	 * msg_dumps - Whether RADIUS message details are shown in stdout
+	 */
+	int msg_dumps;
+
+	/**
+	 * client_addr - Client (local) address to use if force_client_addr
+	 */
+	struct hostapd_ip_addr client_addr;
+
+	/**
+	 * force_client_addr - Whether to force client (local) address
+	 */
+	int force_client_addr;
+};
+
+
+/**
+ * RadiusType - RADIUS server type for RADIUS client
+ */
+typedef enum {
+	/**
+	 * RADIUS authentication
+	 */
+	RADIUS_AUTH,
+
+	/**
+	 * RADIUS_ACCT - RADIUS accounting
+	 */
+	RADIUS_ACCT,
+
+	/**
+	 * RADIUS_ACCT_INTERIM - RADIUS interim accounting message
+	 *
+	 * Used only with radius_client_send(). This behaves just like
+	 * RADIUS_ACCT, but removes any pending interim RADIUS Accounting
+	 * messages for the same STA before sending the new interim update.
+	 */
+	RADIUS_ACCT_INTERIM
+} RadiusType;
+
+/**
+ * RadiusRxResult - RADIUS client RX handler result
+ */
+typedef enum {
+	/**
+	 * RADIUS_RX_PROCESSED - Message processed
+	 *
+	 * This stops handler calls and frees the message.
+	 */
+	RADIUS_RX_PROCESSED,
+
+	/**
+	 * RADIUS_RX_QUEUED - Message has been queued
+	 *
+	 * This stops handler calls, but does not free the message; the handler
+	 * that returned this is responsible for eventually freeing the
+	 * message.
+	 */
+	RADIUS_RX_QUEUED,
+
+	/**
+	 * RADIUS_RX_UNKNOWN - Message is not for this handler
+	 */
+	RADIUS_RX_UNKNOWN,
+
+	/**
+	 * RADIUS_RX_INVALID_AUTHENTICATOR - Message has invalid Authenticator
+	 */
+	RADIUS_RX_INVALID_AUTHENTICATOR
+} RadiusRxResult;
+
+struct radius_client_data;
+
+int radius_client_register(struct radius_client_data *radius,
+			   RadiusType msg_type,
+			   RadiusRxResult (*handler)
+			   (struct radius_msg *msg, struct radius_msg *req,
+			    const u8 *shared_secret, size_t shared_secret_len,
+			    void *data),
+			   void *data);
+int radius_client_send(struct radius_client_data *radius,
+		       struct radius_msg *msg,
+		       RadiusType msg_type, const u8 *addr);
+u8 radius_client_get_id(struct radius_client_data *radius);
+void radius_client_flush(struct radius_client_data *radius, int only_auth);
+struct radius_client_data *
+radius_client_init(void *ctx, struct hostapd_radius_servers *conf);
+void radius_client_deinit(struct radius_client_data *radius);
+void radius_client_flush_auth(struct radius_client_data *radius,
+			      const u8 *addr);
+int radius_client_get_mib(struct radius_client_data *radius, char *buf,
+			  size_t buflen);
+void radius_client_reconfig(struct radius_client_data *radius,
+			    struct hostapd_radius_servers *conf);
+
+#endif /* RADIUS_CLIENT_H */

Copied: vendor/wpa/2.0/src/radius/radius_das.c (from rev 9639, vendor/wpa/dist/src/radius/radius_das.c)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_das.c	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_das.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,364 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/ip_addr.h"
+#include "radius.h"
+#include "radius_das.h"
+
+
+extern int wpa_debug_level;
+
+
+struct radius_das_data {
+	int sock;
+	u8 *shared_secret;
+	size_t shared_secret_len;
+	struct hostapd_ip_addr client_addr;
+	unsigned int time_window;
+	int require_event_timestamp;
+	void *ctx;
+	enum radius_das_res (*disconnect)(void *ctx,
+					  struct radius_das_attrs *attr);
+};
+
+
+static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
+						 struct radius_msg *msg,
+						 const char *abuf,
+						 int from_port)
+{
+	struct radius_hdr *hdr;
+	struct radius_msg *reply;
+	u8 allowed[] = {
+		RADIUS_ATTR_USER_NAME,
+		RADIUS_ATTR_CALLING_STATION_ID,
+		RADIUS_ATTR_ACCT_SESSION_ID,
+		RADIUS_ATTR_EVENT_TIMESTAMP,
+		RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+		RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+		0
+	};
+	int error = 405;
+	u8 attr;
+	enum radius_das_res res;
+	struct radius_das_attrs attrs;
+	u8 *buf;
+	size_t len;
+	char tmp[100];
+	u8 sta_addr[ETH_ALEN];
+
+	hdr = radius_msg_get_hdr(msg);
+
+	attr = radius_msg_find_unlisted_attr(msg, allowed);
+	if (attr) {
+		wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
+			   "Disconnect-Request from %s:%d", attr,
+			   abuf, from_port);
+		error = 401;
+		goto fail;
+	}
+
+	os_memset(&attrs, 0, sizeof(attrs));
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				    &buf, &len, NULL) == 0) {
+		if (len >= sizeof(tmp))
+			len = sizeof(tmp) - 1;
+		os_memcpy(tmp, buf, len);
+		tmp[len] = '\0';
+		if (hwaddr_aton2(tmp, sta_addr) < 0) {
+			wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+				   "'%s' from %s:%d", tmp, abuf, from_port);
+			error = 407;
+			goto fail;
+		}
+		attrs.sta_addr = sta_addr;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+				    &buf, &len, NULL) == 0) {
+		attrs.user_name = buf;
+		attrs.user_name_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+				    &buf, &len, NULL) == 0) {
+		attrs.acct_session_id = buf;
+		attrs.acct_session_id_len = len;
+	}
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+				    &buf, &len, NULL) == 0) {
+		attrs.cui = buf;
+		attrs.cui_len = len;
+	}
+
+	res = das->disconnect(das->ctx, &attrs);
+	switch (res) {
+	case RADIUS_DAS_NAS_MISMATCH:
+		wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+			   abuf, from_port);
+		error = 403;
+		break;
+	case RADIUS_DAS_SESSION_NOT_FOUND:
+		wpa_printf(MSG_INFO, "DAS: Session not found for request from "
+			   "%s:%d", abuf, from_port);
+		error = 503;
+		break;
+	case RADIUS_DAS_SUCCESS:
+		error = 0;
+		break;
+	}
+
+fail:
+	reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
+			       RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
+	if (reply == NULL)
+		return NULL;
+
+	if (error) {
+		if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+					       error)) {
+			radius_msg_free(reply);
+			return NULL;
+		}
+	}
+
+	return reply;
+}
+
+
+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct radius_das_data *das = eloop_ctx;
+	u8 buf[1500];
+	union {
+		struct sockaddr_storage ss;
+		struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+		struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+	} from;
+	char abuf[50];
+	int from_port = 0;
+	socklen_t fromlen;
+	int len;
+	struct radius_msg *msg, *reply = NULL;
+	struct radius_hdr *hdr;
+	struct wpabuf *rbuf;
+	u32 val;
+	int res;
+	struct os_time now;
+
+	fromlen = sizeof(from);
+	len = recvfrom(sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *) &from.ss, &fromlen);
+	if (len < 0) {
+		wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+		return;
+	}
+
+	os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+	from_port = ntohs(from.sin.sin_port);
+
+	wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+		   len, abuf, from_port);
+	if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+		wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+		return;
+	}
+
+	msg = radius_msg_parse(buf, len);
+	if (msg == NULL) {
+		wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+			   "from %s:%d failed", abuf, from_port);
+		return;
+	}
+
+	if (wpa_debug_level <= MSG_MSGDUMP)
+		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);
+		goto fail;
+	}
+
+	os_get_time(&now);
+	res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+				  (u8 *) &val, 4);
+	if (res == 4) {
+		u32 timestamp = ntohl(val);
+		if (abs(now.sec - timestamp) > das->time_window) {
+			wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
+				   "Event-Timestamp (%u; local time %u) in "
+				   "packet from %s:%d - drop",
+				   timestamp, (unsigned int) now.sec,
+				   abuf, from_port);
+			goto fail;
+		}
+	} else if (das->require_event_timestamp) {
+		wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
+			   "from %s:%d - drop", abuf, from_port);
+		goto fail;
+	}
+
+	hdr = radius_msg_get_hdr(msg);
+
+	switch (hdr->code) {
+	case RADIUS_CODE_DISCONNECT_REQUEST:
+		reply = radius_das_disconnect(das, msg, abuf, from_port);
+		break;
+	case RADIUS_CODE_COA_REQUEST:
+		/* TODO */
+		reply = radius_msg_new(RADIUS_CODE_COA_NAK,
+				       hdr->identifier);
+		if (reply == NULL)
+			break;
+
+		/* Unsupported Service */
+		if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+					       405)) {
+			radius_msg_free(reply);
+			reply = NULL;
+			break;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
+			   "packet from %s:%d",
+			   hdr->code, abuf, from_port);
+	}
+
+	if (reply) {
+		wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
+
+		if (!radius_msg_add_attr_int32(reply,
+					       RADIUS_ATTR_EVENT_TIMESTAMP,
+					       now.sec)) {
+			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+				   "Event-Timestamp attribute");
+		}
+
+		if (radius_msg_finish_das_resp(reply, das->shared_secret,
+					       das->shared_secret_len, hdr) <
+		    0) {
+			wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+				   "Message-Authenticator attribute");
+		}
+
+		if (wpa_debug_level <= MSG_MSGDUMP)
+			radius_msg_dump(reply);
+
+		rbuf = radius_msg_get_buf(reply);
+		res = sendto(das->sock, wpabuf_head(rbuf),
+			     wpabuf_len(rbuf), 0,
+			     (struct sockaddr *) &from.ss, fromlen);
+		if (res < 0) {
+			wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
+				   abuf, from_port, strerror(errno));
+		}
+	}
+
+fail:
+	radius_msg_free(msg);
+	radius_msg_free(reply);
+}
+
+
+static int radius_das_open_socket(int port)
+{
+	int s;
+	struct sockaddr_in addr;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf)
+{
+	struct radius_das_data *das;
+
+	if (conf->port == 0 || conf->shared_secret == NULL ||
+	    conf->client_addr == NULL)
+		return NULL;
+
+	das = os_zalloc(sizeof(*das));
+	if (das == NULL)
+		return NULL;
+
+	das->time_window = conf->time_window;
+	das->require_event_timestamp = conf->require_event_timestamp;
+	das->ctx = conf->ctx;
+	das->disconnect = conf->disconnect;
+
+	os_memcpy(&das->client_addr, conf->client_addr,
+		  sizeof(das->client_addr));
+
+	das->shared_secret = os_malloc(conf->shared_secret_len);
+	if (das->shared_secret == NULL) {
+		radius_das_deinit(das);
+		return NULL;
+	}
+	os_memcpy(das->shared_secret, conf->shared_secret,
+		  conf->shared_secret_len);
+	das->shared_secret_len = conf->shared_secret_len;
+
+	das->sock = radius_das_open_socket(conf->port);
+	if (das->sock < 0) {
+		wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
+			   "DAS");
+		radius_das_deinit(das);
+		return NULL;
+	}
+
+	if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
+	{
+		radius_das_deinit(das);
+		return NULL;
+	}
+
+	return das;
+}
+
+
+void radius_das_deinit(struct radius_das_data *das)
+{
+	if (das == NULL)
+		return;
+
+	if (das->sock >= 0) {
+		eloop_unregister_read_sock(das->sock);
+		close(das->sock);
+	}
+
+	os_free(das->shared_secret);
+	os_free(das);
+}

Copied: vendor/wpa/2.0/src/radius/radius_das.h (from rev 9639, vendor/wpa/dist/src/radius/radius_das.h)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_das.h	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_das.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,47 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS)
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_DAS_H
+#define RADIUS_DAS_H
+
+struct radius_das_data;
+
+enum radius_das_res {
+	RADIUS_DAS_SUCCESS,
+	RADIUS_DAS_NAS_MISMATCH,
+	RADIUS_DAS_SESSION_NOT_FOUND
+};
+
+struct radius_das_attrs {
+	const u8 *sta_addr;
+	const u8 *user_name;
+	size_t user_name_len;
+	const u8 *acct_session_id;
+	size_t acct_session_id_len;
+	const u8 *cui;
+	size_t cui_len;
+};
+
+struct radius_das_conf {
+	int port;
+	const u8 *shared_secret;
+	size_t shared_secret_len;
+	const struct hostapd_ip_addr *client_addr;
+	unsigned int time_window;
+	int require_event_timestamp;
+	void *ctx;
+	enum radius_das_res (*disconnect)(void *ctx,
+					  struct radius_das_attrs *attr);
+};
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf);
+
+void radius_das_deinit(struct radius_das_data *data);
+
+#endif /* RADIUS_DAS_H */

Deleted: vendor/wpa/2.0/src/radius/radius_server.c
===================================================================
--- vendor/wpa/dist/src/radius/radius_server.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1518 +0,0 @@
-/*
- * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <net/if.h>
-
-#include "common.h"
-#include "radius.h"
-#include "eloop.h"
-#include "eap_server/eap.h"
-#include "radius_server.h"
-
-/**
- * RADIUS_SESSION_TIMEOUT - Session timeout in seconds
- */
-#define RADIUS_SESSION_TIMEOUT 60
-
-/**
- * RADIUS_MAX_SESSION - Maximum number of active sessions
- */
-#define RADIUS_MAX_SESSION 100
-
-/**
- * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
- */
-#define RADIUS_MAX_MSG_LEN 3000
-
-static struct eapol_callbacks radius_server_eapol_cb;
-
-struct radius_client;
-struct radius_server_data;
-
-/**
- * struct radius_server_counters - RADIUS server statistics counters
- */
-struct radius_server_counters {
-	u32 access_requests;
-	u32 invalid_requests;
-	u32 dup_access_requests;
-	u32 access_accepts;
-	u32 access_rejects;
-	u32 access_challenges;
-	u32 malformed_access_requests;
-	u32 bad_authenticators;
-	u32 packets_dropped;
-	u32 unknown_types;
-};
-
-/**
- * struct radius_session - Internal RADIUS server data for a session
- */
-struct radius_session {
-	struct radius_session *next;
-	struct radius_client *client;
-	struct radius_server_data *server;
-	unsigned int sess_id;
-	struct eap_sm *eap;
-	struct eap_eapol_interface *eap_if;
-
-	struct radius_msg *last_msg;
-	char *last_from_addr;
-	int last_from_port;
-	struct sockaddr_storage last_from;
-	socklen_t last_fromlen;
-	u8 last_identifier;
-	struct radius_msg *last_reply;
-	u8 last_authenticator[16];
-};
-
-/**
- * struct radius_client - Internal RADIUS server data for a client
- */
-struct radius_client {
-	struct radius_client *next;
-	struct in_addr addr;
-	struct in_addr mask;
-#ifdef CONFIG_IPV6
-	struct in6_addr addr6;
-	struct in6_addr mask6;
-#endif /* CONFIG_IPV6 */
-	char *shared_secret;
-	int shared_secret_len;
-	struct radius_session *sessions;
-	struct radius_server_counters counters;
-};
-
-/**
- * struct radius_server_data - Internal RADIUS server data
- */
-struct radius_server_data {
-	/**
-	 * auth_sock - Socket for RADIUS authentication messages
-	 */
-	int auth_sock;
-
-	/**
-	 * clients - List of authorized RADIUS clients
-	 */
-	struct radius_client *clients;
-
-	/**
-	 * next_sess_id - Next session identifier
-	 */
-	unsigned int next_sess_id;
-
-	/**
-	 * conf_ctx - Context pointer for callbacks
-	 *
-	 * This is used as the ctx argument in get_eap_user() calls.
-	 */
-	void *conf_ctx;
-
-	/**
-	 * num_sess - Number of active sessions
-	 */
-	int num_sess;
-
-	/**
-	 * eap_sim_db_priv - EAP-SIM/AKA database context
-	 *
-	 * This is passed to the EAP-SIM/AKA server implementation as a
-	 * callback context.
-	 */
-	void *eap_sim_db_priv;
-
-	/**
-	 * ssl_ctx - TLS context
-	 *
-	 * This is passed to the EAP server implementation as a callback
-	 * context for TLS operations.
-	 */
-	void *ssl_ctx;
-
-	/**
-	 * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
-	 *
-	 * This parameter is used to set a key for EAP-FAST to encrypt the
-	 * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
-	 * set, must point to a 16-octet key.
-	 */
-	u8 *pac_opaque_encr_key;
-
-	/**
-	 * eap_fast_a_id - EAP-FAST authority identity (A-ID)
-	 *
-	 * If EAP-FAST is not used, this can be set to %NULL. In theory, this
-	 * is a variable length field, but due to some existing implementations
-	 * requiring A-ID to be 16 octets in length, it is recommended to use
-	 * that length for the field to provide interoperability with deployed
-	 * peer implementations.
-	 */
-	u8 *eap_fast_a_id;
-
-	/**
-	 * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
-	 */
-	size_t eap_fast_a_id_len;
-
-	/**
-	 * eap_fast_a_id_info - EAP-FAST authority identifier information
-	 *
-	 * This A-ID-Info contains a user-friendly name for the A-ID. For
-	 * example, this could be the enterprise and server names in
-	 * human-readable format. This field is encoded as UTF-8. If EAP-FAST
-	 * is not used, this can be set to %NULL.
-	 */
-	char *eap_fast_a_id_info;
-
-	/**
-	 * eap_fast_prov - EAP-FAST provisioning modes
-	 *
-	 * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
-	 * 2 = only authenticated provisioning allowed, 3 = both provisioning
-	 * modes allowed.
-	 */
-	int eap_fast_prov;
-
-	/**
-	 * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
-	 *
-	 * This is the hard limit on how long a provisioned PAC-Key can be
-	 * used.
-	 */
-	int pac_key_lifetime;
-
-	/**
-	 * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
-	 *
-	 * This is a soft limit on the PAC-Key. The server will automatically
-	 * generate a new PAC-Key when this number of seconds (or fewer) of the
-	 * lifetime remains.
-	 */
-	int pac_key_refresh_time;
-
-	/**
-	 * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
-	 *
-	 * This controls whether the protected success/failure indication
-	 * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
-	 */
-	int eap_sim_aka_result_ind;
-
-	/**
-	 * tnc - Trusted Network Connect (TNC)
-	 *
-	 * This controls whether TNC is enabled and will be required before the
-	 * peer is allowed to connect. Note: This is only used with EAP-TTLS
-	 * and EAP-FAST. If any other EAP method is enabled, the peer will be
-	 * allowed to connect without TNC.
-	 */
-	int tnc;
-
-	/**
-	 * wps - Wi-Fi Protected Setup context
-	 *
-	 * If WPS is used with an external RADIUS server (which is quite
-	 * unlikely configuration), this is used to provide a pointer to WPS
-	 * context data. Normally, this can be set to %NULL.
-	 */
-	struct wps_context *wps;
-
-	/**
-	 * ipv6 - Whether to enable IPv6 support in the RADIUS server
-	 */
-	int ipv6;
-
-	/**
-	 * start_time - Timestamp of server start
-	 */
-	struct os_time start_time;
-
-	/**
-	 * counters - Statistics counters for server operations
-	 *
-	 * These counters are the sum over all clients.
-	 */
-	struct radius_server_counters counters;
-
-	/**
-	 * get_eap_user - Callback for fetching EAP user information
-	 * @ctx: Context data from conf_ctx
-	 * @identity: User identity
-	 * @identity_len: identity buffer length in octets
-	 * @phase2: Whether this is for Phase 2 identity
-	 * @user: Data structure for filling in the user information
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is used to fetch information from user database. The callback
-	 * will fill in information about allowed EAP methods and the user
-	 * password. The password field will be an allocated copy of the
-	 * password data and RADIUS server will free it after use.
-	 */
-	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
-			    int phase2, struct eap_user *user);
-
-	/**
-	 * eap_req_id_text - Optional data for EAP-Request/Identity
-	 *
-	 * This can be used to configure an optional, displayable message that
-	 * will be sent in EAP-Request/Identity. This string can contain an
-	 * ASCII-0 character (nul) to separate network infromation per RFC
-	 * 4284. The actual string length is explicit provided in
-	 * eap_req_id_text_len since nul character will not be used as a string
-	 * terminator.
-	 */
-	char *eap_req_id_text;
-
-	/**
-	 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
-	 */
-	size_t eap_req_id_text_len;
-
-	/*
-	 * msg_ctx - Context data for wpa_msg() calls
-	 */
-	void *msg_ctx;
-};
-
-
-extern int wpa_debug_level;
-
-#define RADIUS_DEBUG(args...) \
-wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
-#define RADIUS_ERROR(args...) \
-wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
-#define RADIUS_DUMP(args...) \
-wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
-#define RADIUS_DUMP_ASCII(args...) \
-wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
-
-
-static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
-static void radius_server_session_remove_timeout(void *eloop_ctx,
-						 void *timeout_ctx);
-
-
-static struct radius_client *
-radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
-			 int ipv6)
-{
-	struct radius_client *client = data->clients;
-
-	while (client) {
-#ifdef CONFIG_IPV6
-		if (ipv6) {
-			struct in6_addr *addr6;
-			int i;
-
-			addr6 = (struct in6_addr *) addr;
-			for (i = 0; i < 16; i++) {
-				if ((addr6->s6_addr[i] &
-				     client->mask6.s6_addr[i]) !=
-				    (client->addr6.s6_addr[i] &
-				     client->mask6.s6_addr[i])) {
-					i = 17;
-					break;
-				}
-			}
-			if (i == 16) {
-				break;
-			}
-		}
-#endif /* CONFIG_IPV6 */
-		if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
-		    (addr->s_addr & client->mask.s_addr)) {
-			break;
-		}
-
-		client = client->next;
-	}
-
-	return client;
-}
-
-
-static struct radius_session *
-radius_server_get_session(struct radius_client *client, unsigned int sess_id)
-{
-	struct radius_session *sess = client->sessions;
-
-	while (sess) {
-		if (sess->sess_id == sess_id) {
-			break;
-		}
-		sess = sess->next;
-	}
-
-	return sess;
-}
-
-
-static void radius_server_session_free(struct radius_server_data *data,
-				       struct radius_session *sess)
-{
-	eloop_cancel_timeout(radius_server_session_timeout, data, sess);
-	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
-	eap_server_sm_deinit(sess->eap);
-	radius_msg_free(sess->last_msg);
-	os_free(sess->last_from_addr);
-	radius_msg_free(sess->last_reply);
-	os_free(sess);
-	data->num_sess--;
-}
-
-
-static void radius_server_session_remove(struct radius_server_data *data,
-					 struct radius_session *sess)
-{
-	struct radius_client *client = sess->client;
-	struct radius_session *session, *prev;
-
-	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
-
-	prev = NULL;
-	session = client->sessions;
-	while (session) {
-		if (session == sess) {
-			if (prev == NULL) {
-				client->sessions = sess->next;
-			} else {
-				prev->next = sess->next;
-			}
-			radius_server_session_free(data, sess);
-			break;
-		}
-		prev = session;
-		session = session->next;
-	}
-}
-
-
-static void radius_server_session_remove_timeout(void *eloop_ctx,
-						 void *timeout_ctx)
-{
-	struct radius_server_data *data = eloop_ctx;
-	struct radius_session *sess = timeout_ctx;
-	RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
-	radius_server_session_remove(data, sess);
-}
-
-
-static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct radius_server_data *data = eloop_ctx;
-	struct radius_session *sess = timeout_ctx;
-
-	RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
-	radius_server_session_remove(data, sess);
-}
-
-
-static struct radius_session *
-radius_server_new_session(struct radius_server_data *data,
-			  struct radius_client *client)
-{
-	struct radius_session *sess;
-
-	if (data->num_sess >= RADIUS_MAX_SESSION) {
-		RADIUS_DEBUG("Maximum number of existing session - no room "
-			     "for a new session");
-		return NULL;
-	}
-
-	sess = os_zalloc(sizeof(*sess));
-	if (sess == NULL)
-		return NULL;
-
-	sess->server = data;
-	sess->client = client;
-	sess->sess_id = data->next_sess_id++;
-	sess->next = client->sessions;
-	client->sessions = sess;
-	eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
-			       radius_server_session_timeout, data, sess);
-	data->num_sess++;
-	return sess;
-}
-
-
-static struct radius_session *
-radius_server_get_new_session(struct radius_server_data *data,
-			      struct radius_client *client,
-			      struct radius_msg *msg)
-{
-	u8 *user;
-	size_t user_len;
-	int res;
-	struct radius_session *sess;
-	struct eap_config eap_conf;
-
-	RADIUS_DEBUG("Creating a new session");
-
-	user = os_malloc(256);
-	if (user == NULL) {
-		return NULL;
-	}
-	res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
-	if (res < 0 || res > 256) {
-		RADIUS_DEBUG("Could not get User-Name");
-		os_free(user);
-		return NULL;
-	}
-	user_len = res;
-	RADIUS_DUMP_ASCII("User-Name", user, user_len);
-
-	res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
-	os_free(user);
-
-	if (res == 0) {
-		RADIUS_DEBUG("Matching user entry found");
-		sess = radius_server_new_session(data, client);
-		if (sess == NULL) {
-			RADIUS_DEBUG("Failed to create a new session");
-			return NULL;
-		}
-	} else {
-		RADIUS_DEBUG("User-Name not found from user database");
-		return NULL;
-	}
-
-	os_memset(&eap_conf, 0, sizeof(eap_conf));
-	eap_conf.ssl_ctx = data->ssl_ctx;
-	eap_conf.msg_ctx = data->msg_ctx;
-	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
-	eap_conf.backend_auth = TRUE;
-	eap_conf.eap_server = 1;
-	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
-	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
-	eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
-	eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
-	eap_conf.eap_fast_prov = data->eap_fast_prov;
-	eap_conf.pac_key_lifetime = data->pac_key_lifetime;
-	eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
-	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
-	eap_conf.tnc = data->tnc;
-	eap_conf.wps = data->wps;
-	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
-				       &eap_conf);
-	if (sess->eap == NULL) {
-		RADIUS_DEBUG("Failed to initialize EAP state machine for the "
-			     "new session");
-		radius_server_session_free(data, sess);
-		return NULL;
-	}
-	sess->eap_if = eap_get_interface(sess->eap);
-	sess->eap_if->eapRestart = TRUE;
-	sess->eap_if->portEnabled = TRUE;
-
-	RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
-
-	return sess;
-}
-
-
-static struct radius_msg *
-radius_server_encapsulate_eap(struct radius_server_data *data,
-			      struct radius_client *client,
-			      struct radius_session *sess,
-			      struct radius_msg *request)
-{
-	struct radius_msg *msg;
-	int code;
-	unsigned int sess_id;
-	struct radius_hdr *hdr = radius_msg_get_hdr(request);
-
-	if (sess->eap_if->eapFail) {
-		sess->eap_if->eapFail = FALSE;
-		code = RADIUS_CODE_ACCESS_REJECT;
-	} else if (sess->eap_if->eapSuccess) {
-		sess->eap_if->eapSuccess = FALSE;
-		code = RADIUS_CODE_ACCESS_ACCEPT;
-	} else {
-		sess->eap_if->eapReq = FALSE;
-		code = RADIUS_CODE_ACCESS_CHALLENGE;
-	}
-
-	msg = radius_msg_new(code, hdr->identifier);
-	if (msg == NULL) {
-		RADIUS_DEBUG("Failed to allocate reply message");
-		return NULL;
-	}
-
-	sess_id = htonl(sess->sess_id);
-	if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
-				 (u8 *) &sess_id, sizeof(sess_id))) {
-		RADIUS_DEBUG("Failed to add State attribute");
-	}
-
-	if (sess->eap_if->eapReqData &&
-	    !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
-				wpabuf_len(sess->eap_if->eapReqData))) {
-		RADIUS_DEBUG("Failed to add EAP-Message attribute");
-	}
-
-	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
-		int len;
-		if (sess->eap_if->eapKeyDataLen > 64) {
-			len = 32;
-		} else {
-			len = sess->eap_if->eapKeyDataLen / 2;
-		}
-		if (!radius_msg_add_mppe_keys(msg, hdr->authenticator,
-					      (u8 *) client->shared_secret,
-					      client->shared_secret_len,
-					      sess->eap_if->eapKeyData + len,
-					      len, sess->eap_if->eapKeyData,
-					      len)) {
-			RADIUS_DEBUG("Failed to add MPPE key attributes");
-		}
-	}
-
-	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
-		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
-		radius_msg_free(msg);
-		return NULL;
-	}
-
-	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
-				  client->shared_secret_len,
-				  hdr->authenticator) < 0) {
-		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
-	}
-
-	return msg;
-}
-
-
-static int radius_server_reject(struct radius_server_data *data,
-				struct radius_client *client,
-				struct radius_msg *request,
-				struct sockaddr *from, socklen_t fromlen,
-				const char *from_addr, int from_port)
-{
-	struct radius_msg *msg;
-	int ret = 0;
-	struct eap_hdr eapfail;
-	struct wpabuf *buf;
-	struct radius_hdr *hdr = radius_msg_get_hdr(request);
-
-	RADIUS_DEBUG("Reject invalid request from %s:%d",
-		     from_addr, from_port);
-
-	msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier);
-	if (msg == NULL) {
-		return -1;
-	}
-
-	os_memset(&eapfail, 0, sizeof(eapfail));
-	eapfail.code = EAP_CODE_FAILURE;
-	eapfail.identifier = 0;
-	eapfail.length = host_to_be16(sizeof(eapfail));
-
-	if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
-		RADIUS_DEBUG("Failed to add EAP-Message attribute");
-	}
-
-	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
-		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
-		radius_msg_free(msg);
-		return -1;
-	}
-
-	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
-				  client->shared_secret_len,
-				  hdr->authenticator) <
-	    0) {
-		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
-	}
-
-	if (wpa_debug_level <= MSG_MSGDUMP) {
-		radius_msg_dump(msg);
-	}
-
-	data->counters.access_rejects++;
-	client->counters.access_rejects++;
-	buf = radius_msg_get_buf(msg);
-	if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
-		   (struct sockaddr *) from, sizeof(*from)) < 0) {
-		perror("sendto[RADIUS SRV]");
-		ret = -1;
-	}
-
-	radius_msg_free(msg);
-
-	return ret;
-}
-
-
-static int radius_server_request(struct radius_server_data *data,
-				 struct radius_msg *msg,
-				 struct sockaddr *from, socklen_t fromlen,
-				 struct radius_client *client,
-				 const char *from_addr, int from_port,
-				 struct radius_session *force_sess)
-{
-	u8 *eap = NULL;
-	size_t eap_len;
-	int res, state_included = 0;
-	u8 statebuf[4];
-	unsigned int state;
-	struct radius_session *sess;
-	struct radius_msg *reply;
-	int is_complete = 0;
-
-	if (force_sess)
-		sess = force_sess;
-	else {
-		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
-					  sizeof(statebuf));
-		state_included = res >= 0;
-		if (res == sizeof(statebuf)) {
-			state = WPA_GET_BE32(statebuf);
-			sess = radius_server_get_session(client, state);
-		} else {
-			sess = NULL;
-		}
-	}
-
-	if (sess) {
-		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
-	} else if (state_included) {
-		RADIUS_DEBUG("State attribute included but no session found");
-		radius_server_reject(data, client, msg, from, fromlen,
-				     from_addr, from_port);
-		return -1;
-	} else {
-		sess = radius_server_get_new_session(data, client, msg);
-		if (sess == NULL) {
-			RADIUS_DEBUG("Could not create a new session");
-			radius_server_reject(data, client, msg, from, fromlen,
-					     from_addr, from_port);
-			return -1;
-		}
-	}
-
-	if (sess->last_from_port == from_port &&
-	    sess->last_identifier == radius_msg_get_hdr(msg)->identifier &&
-	    os_memcmp(sess->last_authenticator,
-		      radius_msg_get_hdr(msg)->authenticator, 16) == 0) {
-		RADIUS_DEBUG("Duplicate message from %s", from_addr);
-		data->counters.dup_access_requests++;
-		client->counters.dup_access_requests++;
-
-		if (sess->last_reply) {
-			struct wpabuf *buf;
-			buf = radius_msg_get_buf(sess->last_reply);
-			res = sendto(data->auth_sock, wpabuf_head(buf),
-				     wpabuf_len(buf), 0,
-				     (struct sockaddr *) from, fromlen);
-			if (res < 0) {
-				perror("sendto[RADIUS SRV]");
-			}
-			return 0;
-		}
-
-		RADIUS_DEBUG("No previous reply available for duplicate "
-			     "message");
-		return -1;
-	}
-		      
-	eap = radius_msg_get_eap(msg, &eap_len);
-	if (eap == NULL) {
-		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
-			     from_addr);
-		data->counters.packets_dropped++;
-		client->counters.packets_dropped++;
-		return -1;
-	}
-
-	RADIUS_DUMP("Received EAP data", eap, eap_len);
-
-	/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
-	 * RFC3579 Sect. 2.6.2.
-	 * Include EAP-Response/Nak with no preferred method if
-	 * code == request.
-	 * If code is not 1-4, discard the packet silently.
-	 * Or is this already done by the EAP state machine? */
-
-	wpabuf_free(sess->eap_if->eapRespData);
-	sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);
-	if (sess->eap_if->eapRespData == NULL)
-		os_free(eap);
-	eap = NULL;
-	sess->eap_if->eapResp = TRUE;
-	eap_server_sm_step(sess->eap);
-
-	if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
-	     sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
-		RADIUS_DUMP("EAP data from the state machine",
-			    wpabuf_head(sess->eap_if->eapReqData),
-			    wpabuf_len(sess->eap_if->eapReqData));
-	} else if (sess->eap_if->eapFail) {
-		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
-			     "set");
-	} else if (eap_sm_method_pending(sess->eap)) {
-		radius_msg_free(sess->last_msg);
-		sess->last_msg = msg;
-		sess->last_from_port = from_port;
-		os_free(sess->last_from_addr);
-		sess->last_from_addr = os_strdup(from_addr);
-		sess->last_fromlen = fromlen;
-		os_memcpy(&sess->last_from, from, fromlen);
-		return -2;
-	} else {
-		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
-			     " Access-Request silently (assuming it was a "
-			     "duplicate)");
-		data->counters.packets_dropped++;
-		client->counters.packets_dropped++;
-		return -1;
-	}
-
-	if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
-		is_complete = 1;
-
-	reply = radius_server_encapsulate_eap(data, client, sess, msg);
-
-	if (reply) {
-		struct wpabuf *buf;
-		struct radius_hdr *hdr;
-
-		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
-		if (wpa_debug_level <= MSG_MSGDUMP) {
-			radius_msg_dump(reply);
-		}
-
-		switch (radius_msg_get_hdr(reply)->code) {
-		case RADIUS_CODE_ACCESS_ACCEPT:
-			data->counters.access_accepts++;
-			client->counters.access_accepts++;
-			break;
-		case RADIUS_CODE_ACCESS_REJECT:
-			data->counters.access_rejects++;
-			client->counters.access_rejects++;
-			break;
-		case RADIUS_CODE_ACCESS_CHALLENGE:
-			data->counters.access_challenges++;
-			client->counters.access_challenges++;
-			break;
-		}
-		buf = radius_msg_get_buf(reply);
-		res = sendto(data->auth_sock, wpabuf_head(buf),
-			     wpabuf_len(buf), 0,
-			     (struct sockaddr *) from, fromlen);
-		if (res < 0) {
-			perror("sendto[RADIUS SRV]");
-		}
-		radius_msg_free(sess->last_reply);
-		sess->last_reply = reply;
-		sess->last_from_port = from_port;
-		hdr = radius_msg_get_hdr(msg);
-		sess->last_identifier = hdr->identifier;
-		os_memcpy(sess->last_authenticator, hdr->authenticator, 16);
-	} else {
-		data->counters.packets_dropped++;
-		client->counters.packets_dropped++;
-	}
-
-	if (is_complete) {
-		RADIUS_DEBUG("Removing completed session 0x%x after timeout",
-			     sess->sess_id);
-		eloop_cancel_timeout(radius_server_session_remove_timeout,
-				     data, sess);
-		eloop_register_timeout(10, 0,
-				       radius_server_session_remove_timeout,
-				       data, sess);
-	}
-
-	return 0;
-}
-
-
-static void radius_server_receive_auth(int sock, void *eloop_ctx,
-				       void *sock_ctx)
-{
-	struct radius_server_data *data = eloop_ctx;
-	u8 *buf = NULL;
-	union {
-		struct sockaddr_storage ss;
-		struct sockaddr_in sin;
-#ifdef CONFIG_IPV6
-		struct sockaddr_in6 sin6;
-#endif /* CONFIG_IPV6 */
-	} from;
-	socklen_t fromlen;
-	int len;
-	struct radius_client *client = NULL;
-	struct radius_msg *msg = NULL;
-	char abuf[50];
-	int from_port = 0;
-
-	buf = os_malloc(RADIUS_MAX_MSG_LEN);
-	if (buf == NULL) {
-		goto fail;
-	}
-
-	fromlen = sizeof(from);
-	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
-		       (struct sockaddr *) &from.ss, &fromlen);
-	if (len < 0) {
-		perror("recvfrom[radius_server]");
-		goto fail;
-	}
-
-#ifdef CONFIG_IPV6
-	if (data->ipv6) {
-		if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
-			      sizeof(abuf)) == NULL)
-			abuf[0] = '\0';
-		from_port = ntohs(from.sin6.sin6_port);
-		RADIUS_DEBUG("Received %d bytes from %s:%d",
-			     len, abuf, from_port);
-
-		client = radius_server_get_client(data,
-						  (struct in_addr *)
-						  &from.sin6.sin6_addr, 1);
-	}
-#endif /* CONFIG_IPV6 */
-
-	if (!data->ipv6) {
-		os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
-		from_port = ntohs(from.sin.sin_port);
-		RADIUS_DEBUG("Received %d bytes from %s:%d",
-			     len, abuf, from_port);
-
-		client = radius_server_get_client(data, &from.sin.sin_addr, 0);
-	}
-
-	RADIUS_DUMP("Received data", buf, len);
-
-	if (client == NULL) {
-		RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
-		data->counters.invalid_requests++;
-		goto fail;
-	}
-
-	msg = radius_msg_parse(buf, len);
-	if (msg == NULL) {
-		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
-		data->counters.malformed_access_requests++;
-		client->counters.malformed_access_requests++;
-		goto fail;
-	}
-
-	os_free(buf);
-	buf = NULL;
-
-	if (wpa_debug_level <= MSG_MSGDUMP) {
-		radius_msg_dump(msg);
-	}
-
-	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
-		RADIUS_DEBUG("Unexpected RADIUS code %d",
-			     radius_msg_get_hdr(msg)->code);
-		data->counters.unknown_types++;
-		client->counters.unknown_types++;
-		goto fail;
-	}
-
-	data->counters.access_requests++;
-	client->counters.access_requests++;
-
-	if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
-				       client->shared_secret_len, NULL)) {
-		RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
-		data->counters.bad_authenticators++;
-		client->counters.bad_authenticators++;
-		goto fail;
-	}
-
-	if (radius_server_request(data, msg, (struct sockaddr *) &from,
-				  fromlen, client, abuf, from_port, NULL) ==
-	    -2)
-		return; /* msg was stored with the session */
-
-fail:
-	radius_msg_free(msg);
-	os_free(buf);
-}
-
-
-static int radius_server_disable_pmtu_discovery(int s)
-{
-	int r = -1;
-#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
-	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
-	int action = IP_PMTUDISC_DONT;
-	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
-		       sizeof(action));
-	if (r == -1)
-		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
-			   "%s", strerror(errno));
-#endif
-	return r;
-}
-
-
-static int radius_server_open_socket(int port)
-{
-	int s;
-	struct sockaddr_in addr;
-
-	s = socket(PF_INET, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket");
-		return -1;
-	}
-
-	radius_server_disable_pmtu_discovery(s);
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons(port);
-	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
-		close(s);
-		return -1;
-	}
-
-	return s;
-}
-
-
-#ifdef CONFIG_IPV6
-static int radius_server_open_socket6(int port)
-{
-	int s;
-	struct sockaddr_in6 addr;
-
-	s = socket(PF_INET6, SOCK_DGRAM, 0);
-	if (s < 0) {
-		perror("socket[IPv6]");
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin6_family = AF_INET6;
-	os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
-	addr.sin6_port = htons(port);
-	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
-		close(s);
-		return -1;
-	}
-
-	return s;
-}
-#endif /* CONFIG_IPV6 */
-
-
-static void radius_server_free_sessions(struct radius_server_data *data,
-					struct radius_session *sessions)
-{
-	struct radius_session *session, *prev;
-
-	session = sessions;
-	while (session) {
-		prev = session;
-		session = session->next;
-		radius_server_session_free(data, prev);
-	}
-}
-
-
-static void radius_server_free_clients(struct radius_server_data *data,
-				       struct radius_client *clients)
-{
-	struct radius_client *client, *prev;
-
-	client = clients;
-	while (client) {
-		prev = client;
-		client = client->next;
-
-		radius_server_free_sessions(data, prev->sessions);
-		os_free(prev->shared_secret);
-		os_free(prev);
-	}
-}
-
-
-static struct radius_client *
-radius_server_read_clients(const char *client_file, int ipv6)
-{
-	FILE *f;
-	const int buf_size = 1024;
-	char *buf, *pos;
-	struct radius_client *clients, *tail, *entry;
-	int line = 0, mask, failed = 0, i;
-	struct in_addr addr;
-#ifdef CONFIG_IPV6
-	struct in6_addr addr6;
-#endif /* CONFIG_IPV6 */
-	unsigned int val;
-
-	f = fopen(client_file, "r");
-	if (f == NULL) {
-		RADIUS_ERROR("Could not open client file '%s'", client_file);
-		return NULL;
-	}
-
-	buf = os_malloc(buf_size);
-	if (buf == NULL) {
-		fclose(f);
-		return NULL;
-	}
-
-	clients = tail = NULL;
-	while (fgets(buf, buf_size, f)) {
-		/* Configuration file format:
-		 * 192.168.1.0/24 secret
-		 * 192.168.1.2 secret
-		 * fe80::211:22ff:fe33:4455/64 secretipv6
-		 */
-		line++;
-		buf[buf_size - 1] = '\0';
-		pos = buf;
-		while (*pos != '\0' && *pos != '\n')
-			pos++;
-		if (*pos == '\n')
-			*pos = '\0';
-		if (*buf == '\0' || *buf == '#')
-			continue;
-
-		pos = buf;
-		while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
-		       (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
-		       (*pos >= 'A' && *pos <= 'F')) {
-			pos++;
-		}
-
-		if (*pos == '\0') {
-			failed = 1;
-			break;
-		}
-
-		if (*pos == '/') {
-			char *end;
-			*pos++ = '\0';
-			mask = strtol(pos, &end, 10);
-			if ((pos == end) ||
-			    (mask < 0 || mask > (ipv6 ? 128 : 32))) {
-				failed = 1;
-				break;
-			}
-			pos = end;
-		} else {
-			mask = ipv6 ? 128 : 32;
-			*pos++ = '\0';
-		}
-
-		if (!ipv6 && inet_aton(buf, &addr) == 0) {
-			failed = 1;
-			break;
-		}
-#ifdef CONFIG_IPV6
-		if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
-			if (inet_pton(AF_INET, buf, &addr) <= 0) {
-				failed = 1;
-				break;
-			}
-			/* Convert IPv4 address to IPv6 */
-			if (mask <= 32)
-				mask += (128 - 32);
-			os_memset(addr6.s6_addr, 0, 10);
-			addr6.s6_addr[10] = 0xff;
-			addr6.s6_addr[11] = 0xff;
-			os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
-				  4);
-		}
-#endif /* CONFIG_IPV6 */
-
-		while (*pos == ' ' || *pos == '\t') {
-			pos++;
-		}
-
-		if (*pos == '\0') {
-			failed = 1;
-			break;
-		}
-
-		entry = os_zalloc(sizeof(*entry));
-		if (entry == NULL) {
-			failed = 1;
-			break;
-		}
-		entry->shared_secret = os_strdup(pos);
-		if (entry->shared_secret == NULL) {
-			failed = 1;
-			os_free(entry);
-			break;
-		}
-		entry->shared_secret_len = os_strlen(entry->shared_secret);
-		entry->addr.s_addr = addr.s_addr;
-		if (!ipv6) {
-			val = 0;
-			for (i = 0; i < mask; i++)
-				val |= 1 << (31 - i);
-			entry->mask.s_addr = htonl(val);
-		}
-#ifdef CONFIG_IPV6
-		if (ipv6) {
-			int offset = mask / 8;
-
-			os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
-			os_memset(entry->mask6.s6_addr, 0xff, offset);
-			val = 0;
-			for (i = 0; i < (mask % 8); i++)
-				val |= 1 << (7 - i);
-			if (offset < 16)
-				entry->mask6.s6_addr[offset] = val;
-		}
-#endif /* CONFIG_IPV6 */
-
-		if (tail == NULL) {
-			clients = tail = entry;
-		} else {
-			tail->next = entry;
-			tail = entry;
-		}
-	}
-
-	if (failed) {
-		RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
-		radius_server_free_clients(NULL, clients);
-		clients = NULL;
-	}
-
-	os_free(buf);
-	fclose(f);
-
-	return clients;
-}
-
-
-/**
- * radius_server_init - Initialize RADIUS server
- * @conf: Configuration for the RADIUS server
- * Returns: Pointer to private RADIUS server context or %NULL on failure
- *
- * This initializes a RADIUS server instance and returns a context pointer that
- * will be used in other calls to the RADIUS server module. The server can be
- * deinitialize by calling radius_server_deinit().
- */
-struct radius_server_data *
-radius_server_init(struct radius_server_conf *conf)
-{
-	struct radius_server_data *data;
-
-#ifndef CONFIG_IPV6
-	if (conf->ipv6) {
-		fprintf(stderr, "RADIUS server compiled without IPv6 "
-			"support.\n");
-		return NULL;
-	}
-#endif /* CONFIG_IPV6 */
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-
-	os_get_time(&data->start_time);
-	data->conf_ctx = conf->conf_ctx;
-	data->eap_sim_db_priv = conf->eap_sim_db_priv;
-	data->ssl_ctx = conf->ssl_ctx;
-	data->msg_ctx = conf->msg_ctx;
-	data->ipv6 = conf->ipv6;
-	if (conf->pac_opaque_encr_key) {
-		data->pac_opaque_encr_key = os_malloc(16);
-		os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
-			  16);
-	}
-	if (conf->eap_fast_a_id) {
-		data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
-		if (data->eap_fast_a_id) {
-			os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
-				  conf->eap_fast_a_id_len);
-			data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
-		}
-	}
-	if (conf->eap_fast_a_id_info)
-		data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
-	data->eap_fast_prov = conf->eap_fast_prov;
-	data->pac_key_lifetime = conf->pac_key_lifetime;
-	data->pac_key_refresh_time = conf->pac_key_refresh_time;
-	data->get_eap_user = conf->get_eap_user;
-	data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
-	data->tnc = conf->tnc;
-	data->wps = conf->wps;
-	if (conf->eap_req_id_text) {
-		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
-		if (data->eap_req_id_text) {
-			os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
-				  conf->eap_req_id_text_len);
-			data->eap_req_id_text_len = conf->eap_req_id_text_len;
-		}
-	}
-
-	data->clients = radius_server_read_clients(conf->client_file,
-						   conf->ipv6);
-	if (data->clients == NULL) {
-		printf("No RADIUS clients configured.\n");
-		radius_server_deinit(data);
-		return NULL;
-	}
-
-#ifdef CONFIG_IPV6
-	if (conf->ipv6)
-		data->auth_sock = radius_server_open_socket6(conf->auth_port);
-	else
-#endif /* CONFIG_IPV6 */
-	data->auth_sock = radius_server_open_socket(conf->auth_port);
-	if (data->auth_sock < 0) {
-		printf("Failed to open UDP socket for RADIUS authentication "
-		       "server\n");
-		radius_server_deinit(data);
-		return NULL;
-	}
-	if (eloop_register_read_sock(data->auth_sock,
-				     radius_server_receive_auth,
-				     data, NULL)) {
-		radius_server_deinit(data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-/**
- * radius_server_deinit - Deinitialize RADIUS server
- * @data: RADIUS server context from radius_server_init()
- */
-void radius_server_deinit(struct radius_server_data *data)
-{
-	if (data == NULL)
-		return;
-
-	if (data->auth_sock >= 0) {
-		eloop_unregister_read_sock(data->auth_sock);
-		close(data->auth_sock);
-	}
-
-	radius_server_free_clients(data, data->clients);
-
-	os_free(data->pac_opaque_encr_key);
-	os_free(data->eap_fast_a_id);
-	os_free(data->eap_fast_a_id_info);
-	os_free(data->eap_req_id_text);
-	os_free(data);
-}
-
-
-/**
- * radius_server_get_mib - Get RADIUS server MIB information
- * @data: RADIUS server context from radius_server_init()
- * @buf: Buffer for returning the MIB data in text format
- * @buflen: buf length in octets
- * Returns: Number of octets written into buf
- */
-int radius_server_get_mib(struct radius_server_data *data, char *buf,
-			  size_t buflen)
-{
-	int ret, uptime;
-	unsigned int idx;
-	char *end, *pos;
-	struct os_time now;
-	struct radius_client *cli;
-
-	/* RFC 2619 - RADIUS Authentication Server MIB */
-
-	if (data == NULL || buflen == 0)
-		return 0;
-
-	pos = buf;
-	end = buf + buflen;
-
-	os_get_time(&now);
-	uptime = (now.sec - data->start_time.sec) * 100 +
-		((now.usec - data->start_time.usec) / 10000) % 100;
-	ret = os_snprintf(pos, end - pos,
-			  "RADIUS-AUTH-SERVER-MIB\n"
-			  "radiusAuthServIdent=hostapd\n"
-			  "radiusAuthServUpTime=%d\n"
-			  "radiusAuthServResetTime=0\n"
-			  "radiusAuthServConfigReset=4\n",
-			  uptime);
-	if (ret < 0 || ret >= end - pos) {
-		*pos = '\0';
-		return pos - buf;
-	}
-	pos += ret;
-
-	ret = os_snprintf(pos, end - pos,
-			  "radiusAuthServTotalAccessRequests=%u\n"
-			  "radiusAuthServTotalInvalidRequests=%u\n"
-			  "radiusAuthServTotalDupAccessRequests=%u\n"
-			  "radiusAuthServTotalAccessAccepts=%u\n"
-			  "radiusAuthServTotalAccessRejects=%u\n"
-			  "radiusAuthServTotalAccessChallenges=%u\n"
-			  "radiusAuthServTotalMalformedAccessRequests=%u\n"
-			  "radiusAuthServTotalBadAuthenticators=%u\n"
-			  "radiusAuthServTotalPacketsDropped=%u\n"
-			  "radiusAuthServTotalUnknownTypes=%u\n",
-			  data->counters.access_requests,
-			  data->counters.invalid_requests,
-			  data->counters.dup_access_requests,
-			  data->counters.access_accepts,
-			  data->counters.access_rejects,
-			  data->counters.access_challenges,
-			  data->counters.malformed_access_requests,
-			  data->counters.bad_authenticators,
-			  data->counters.packets_dropped,
-			  data->counters.unknown_types);
-	if (ret < 0 || ret >= end - pos) {
-		*pos = '\0';
-		return pos - buf;
-	}
-	pos += ret;
-
-	for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
-		char abuf[50], mbuf[50];
-#ifdef CONFIG_IPV6
-		if (data->ipv6) {
-			if (inet_ntop(AF_INET6, &cli->addr6, abuf,
-				      sizeof(abuf)) == NULL)
-				abuf[0] = '\0';
-			if (inet_ntop(AF_INET6, &cli->mask6, abuf,
-				      sizeof(mbuf)) == NULL)
-				mbuf[0] = '\0';
-		}
-#endif /* CONFIG_IPV6 */
-		if (!data->ipv6) {
-			os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
-			os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
-		}
-
-		ret = os_snprintf(pos, end - pos,
-				  "radiusAuthClientIndex=%u\n"
-				  "radiusAuthClientAddress=%s/%s\n"
-				  "radiusAuthServAccessRequests=%u\n"
-				  "radiusAuthServDupAccessRequests=%u\n"
-				  "radiusAuthServAccessAccepts=%u\n"
-				  "radiusAuthServAccessRejects=%u\n"
-				  "radiusAuthServAccessChallenges=%u\n"
-				  "radiusAuthServMalformedAccessRequests=%u\n"
-				  "radiusAuthServBadAuthenticators=%u\n"
-				  "radiusAuthServPacketsDropped=%u\n"
-				  "radiusAuthServUnknownTypes=%u\n",
-				  idx,
-				  abuf, mbuf,
-				  cli->counters.access_requests,
-				  cli->counters.dup_access_requests,
-				  cli->counters.access_accepts,
-				  cli->counters.access_rejects,
-				  cli->counters.access_challenges,
-				  cli->counters.malformed_access_requests,
-				  cli->counters.bad_authenticators,
-				  cli->counters.packets_dropped,
-				  cli->counters.unknown_types);
-		if (ret < 0 || ret >= end - pos) {
-			*pos = '\0';
-			return pos - buf;
-		}
-		pos += ret;
-	}
-
-	return pos - buf;
-}
-
-
-static int radius_server_get_eap_user(void *ctx, const u8 *identity,
-				      size_t identity_len, int phase2,
-				      struct eap_user *user)
-{
-	struct radius_session *sess = ctx;
-	struct radius_server_data *data = sess->server;
-
-	return data->get_eap_user(data->conf_ctx, identity, identity_len,
-				  phase2, user);
-}
-
-
-static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
-{
-	struct radius_session *sess = ctx;
-	struct radius_server_data *data = sess->server;
-	*len = data->eap_req_id_text_len;
-	return data->eap_req_id_text;
-}
-
-
-static struct eapol_callbacks radius_server_eapol_cb =
-{
-	.get_eap_user = radius_server_get_eap_user,
-	.get_eap_req_id_text = radius_server_get_eap_req_id_text,
-};
-
-
-/**
- * radius_server_eap_pending_cb - Pending EAP data notification
- * @data: RADIUS server context from radius_server_init()
- * @ctx: Pending EAP context pointer
- *
- * This function is used to notify EAP server module that a pending operation
- * has been completed and processing of the EAP session can proceed.
- */
-void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
-{
-	struct radius_client *cli;
-	struct radius_session *s, *sess = NULL;
-	struct radius_msg *msg;
-
-	if (data == NULL)
-		return;
-
-	for (cli = data->clients; cli; cli = cli->next) {
-		for (s = cli->sessions; s; s = s->next) {
-			if (s->eap == ctx && s->last_msg) {
-				sess = s;
-				break;
-			}
-			if (sess)
-				break;
-		}
-		if (sess)
-			break;
-	}
-
-	if (sess == NULL) {
-		RADIUS_DEBUG("No session matched callback ctx");
-		return;
-	}
-
-	msg = sess->last_msg;
-	sess->last_msg = NULL;
-	eap_sm_pending_cb(sess->eap);
-	if (radius_server_request(data, msg,
-				  (struct sockaddr *) &sess->last_from,
-				  sess->last_fromlen, cli,
-				  sess->last_from_addr,
-				  sess->last_from_port, sess) == -2)
-		return; /* msg was stored with the session */
-
-	radius_msg_free(msg);
-}

Copied: vendor/wpa/2.0/src/radius/radius_server.c (from rev 9639, vendor/wpa/dist/src/radius/radius_server.c)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_server.c	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1547 @@
+/*
+ * RADIUS authentication server
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+
+#include "common.h"
+#include "radius.h"
+#include "eloop.h"
+#include "eap_server/eap.h"
+#include "radius_server.h"
+
+/**
+ * RADIUS_SESSION_TIMEOUT - Session timeout in seconds
+ */
+#define RADIUS_SESSION_TIMEOUT 60
+
+/**
+ * RADIUS_MAX_SESSION - Maximum number of active sessions
+ */
+#define RADIUS_MAX_SESSION 100
+
+/**
+ * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
+ */
+#define RADIUS_MAX_MSG_LEN 3000
+
+static struct eapol_callbacks radius_server_eapol_cb;
+
+struct radius_client;
+struct radius_server_data;
+
+/**
+ * struct radius_server_counters - RADIUS server statistics counters
+ */
+struct radius_server_counters {
+	u32 access_requests;
+	u32 invalid_requests;
+	u32 dup_access_requests;
+	u32 access_accepts;
+	u32 access_rejects;
+	u32 access_challenges;
+	u32 malformed_access_requests;
+	u32 bad_authenticators;
+	u32 packets_dropped;
+	u32 unknown_types;
+};
+
+/**
+ * struct radius_session - Internal RADIUS server data for a session
+ */
+struct radius_session {
+	struct radius_session *next;
+	struct radius_client *client;
+	struct radius_server_data *server;
+	unsigned int sess_id;
+	struct eap_sm *eap;
+	struct eap_eapol_interface *eap_if;
+
+	struct radius_msg *last_msg;
+	char *last_from_addr;
+	int last_from_port;
+	struct sockaddr_storage last_from;
+	socklen_t last_fromlen;
+	u8 last_identifier;
+	struct radius_msg *last_reply;
+	u8 last_authenticator[16];
+};
+
+/**
+ * struct radius_client - Internal RADIUS server data for a client
+ */
+struct radius_client {
+	struct radius_client *next;
+	struct in_addr addr;
+	struct in_addr mask;
+#ifdef CONFIG_IPV6
+	struct in6_addr addr6;
+	struct in6_addr mask6;
+#endif /* CONFIG_IPV6 */
+	char *shared_secret;
+	int shared_secret_len;
+	struct radius_session *sessions;
+	struct radius_server_counters counters;
+};
+
+/**
+ * struct radius_server_data - Internal RADIUS server data
+ */
+struct radius_server_data {
+	/**
+	 * auth_sock - Socket for RADIUS authentication messages
+	 */
+	int auth_sock;
+
+	/**
+	 * clients - List of authorized RADIUS clients
+	 */
+	struct radius_client *clients;
+
+	/**
+	 * next_sess_id - Next session identifier
+	 */
+	unsigned int next_sess_id;
+
+	/**
+	 * conf_ctx - Context pointer for callbacks
+	 *
+	 * This is used as the ctx argument in get_eap_user() calls.
+	 */
+	void *conf_ctx;
+
+	/**
+	 * num_sess - Number of active sessions
+	 */
+	int num_sess;
+
+	/**
+	 * eap_sim_db_priv - EAP-SIM/AKA database context
+	 *
+	 * This is passed to the EAP-SIM/AKA server implementation as a
+	 * callback context.
+	 */
+	void *eap_sim_db_priv;
+
+	/**
+	 * ssl_ctx - TLS context
+	 *
+	 * This is passed to the EAP server implementation as a callback
+	 * context for TLS operations.
+	 */
+	void *ssl_ctx;
+
+	/**
+	 * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+	 *
+	 * This parameter is used to set a key for EAP-FAST to encrypt the
+	 * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+	 * set, must point to a 16-octet key.
+	 */
+	u8 *pac_opaque_encr_key;
+
+	/**
+	 * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+	 *
+	 * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+	 * is a variable length field, but due to some existing implementations
+	 * requiring A-ID to be 16 octets in length, it is recommended to use
+	 * that length for the field to provide interoperability with deployed
+	 * peer implementations.
+	 */
+	u8 *eap_fast_a_id;
+
+	/**
+	 * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+	 */
+	size_t eap_fast_a_id_len;
+
+	/**
+	 * eap_fast_a_id_info - EAP-FAST authority identifier information
+	 *
+	 * This A-ID-Info contains a user-friendly name for the A-ID. For
+	 * example, this could be the enterprise and server names in
+	 * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+	 * is not used, this can be set to %NULL.
+	 */
+	char *eap_fast_a_id_info;
+
+	/**
+	 * eap_fast_prov - EAP-FAST provisioning modes
+	 *
+	 * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+	 * 2 = only authenticated provisioning allowed, 3 = both provisioning
+	 * modes allowed.
+	 */
+	int eap_fast_prov;
+
+	/**
+	 * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+	 *
+	 * This is the hard limit on how long a provisioned PAC-Key can be
+	 * used.
+	 */
+	int pac_key_lifetime;
+
+	/**
+	 * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+	 *
+	 * This is a soft limit on the PAC-Key. The server will automatically
+	 * generate a new PAC-Key when this number of seconds (or fewer) of the
+	 * lifetime remains.
+	 */
+	int pac_key_refresh_time;
+
+	/**
+	 * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+	 *
+	 * This controls whether the protected success/failure indication
+	 * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+	 */
+	int eap_sim_aka_result_ind;
+
+	/**
+	 * tnc - Trusted Network Connect (TNC)
+	 *
+	 * This controls whether TNC is enabled and will be required before the
+	 * peer is allowed to connect. Note: This is only used with EAP-TTLS
+	 * and EAP-FAST. If any other EAP method is enabled, the peer will be
+	 * allowed to connect without TNC.
+	 */
+	int tnc;
+
+	/**
+	 * pwd_group - The D-H group assigned for EAP-pwd
+	 *
+	 * If EAP-pwd is not used it can be set to zero.
+	 */
+	u16 pwd_group;
+
+	/**
+	 * wps - Wi-Fi Protected Setup context
+	 *
+	 * If WPS is used with an external RADIUS server (which is quite
+	 * unlikely configuration), this is used to provide a pointer to WPS
+	 * context data. Normally, this can be set to %NULL.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * ipv6 - Whether to enable IPv6 support in the RADIUS server
+	 */
+	int ipv6;
+
+	/**
+	 * start_time - Timestamp of server start
+	 */
+	struct os_time start_time;
+
+	/**
+	 * counters - Statistics counters for server operations
+	 *
+	 * These counters are the sum over all clients.
+	 */
+	struct radius_server_counters counters;
+
+	/**
+	 * get_eap_user - Callback for fetching EAP user information
+	 * @ctx: Context data from conf_ctx
+	 * @identity: User identity
+	 * @identity_len: identity buffer length in octets
+	 * @phase2: Whether this is for Phase 2 identity
+	 * @user: Data structure for filling in the user information
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is used to fetch information from user database. The callback
+	 * will fill in information about allowed EAP methods and the user
+	 * password. The password field will be an allocated copy of the
+	 * password data and RADIUS server will free it after use.
+	 */
+	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+			    int phase2, struct eap_user *user);
+
+	/**
+	 * eap_req_id_text - Optional data for EAP-Request/Identity
+	 *
+	 * This can be used to configure an optional, displayable message that
+	 * will be sent in EAP-Request/Identity. This string can contain an
+	 * ASCII-0 character (nul) to separate network infromation per RFC
+	 * 4284. The actual string length is explicit provided in
+	 * eap_req_id_text_len since nul character will not be used as a string
+	 * terminator.
+	 */
+	char *eap_req_id_text;
+
+	/**
+	 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
+	 */
+	size_t eap_req_id_text_len;
+
+	/*
+	 * msg_ctx - Context data for wpa_msg() calls
+	 */
+	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+};
+
+
+extern int wpa_debug_level;
+
+#define RADIUS_DEBUG(args...) \
+wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
+#define RADIUS_ERROR(args...) \
+wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
+#define RADIUS_DUMP(args...) \
+wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
+#define RADIUS_DUMP_ASCII(args...) \
+wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
+
+
+static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
+static void radius_server_session_remove_timeout(void *eloop_ctx,
+						 void *timeout_ctx);
+
+
+static struct radius_client *
+radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
+			 int ipv6)
+{
+	struct radius_client *client = data->clients;
+
+	while (client) {
+#ifdef CONFIG_IPV6
+		if (ipv6) {
+			struct in6_addr *addr6;
+			int i;
+
+			addr6 = (struct in6_addr *) addr;
+			for (i = 0; i < 16; i++) {
+				if ((addr6->s6_addr[i] &
+				     client->mask6.s6_addr[i]) !=
+				    (client->addr6.s6_addr[i] &
+				     client->mask6.s6_addr[i])) {
+					i = 17;
+					break;
+				}
+			}
+			if (i == 16) {
+				break;
+			}
+		}
+#endif /* CONFIG_IPV6 */
+		if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
+		    (addr->s_addr & client->mask.s_addr)) {
+			break;
+		}
+
+		client = client->next;
+	}
+
+	return client;
+}
+
+
+static struct radius_session *
+radius_server_get_session(struct radius_client *client, unsigned int sess_id)
+{
+	struct radius_session *sess = client->sessions;
+
+	while (sess) {
+		if (sess->sess_id == sess_id) {
+			break;
+		}
+		sess = sess->next;
+	}
+
+	return sess;
+}
+
+
+static void radius_server_session_free(struct radius_server_data *data,
+				       struct radius_session *sess)
+{
+	eloop_cancel_timeout(radius_server_session_timeout, data, sess);
+	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
+	eap_server_sm_deinit(sess->eap);
+	radius_msg_free(sess->last_msg);
+	os_free(sess->last_from_addr);
+	radius_msg_free(sess->last_reply);
+	os_free(sess);
+	data->num_sess--;
+}
+
+
+static void radius_server_session_remove(struct radius_server_data *data,
+					 struct radius_session *sess)
+{
+	struct radius_client *client = sess->client;
+	struct radius_session *session, *prev;
+
+	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
+
+	prev = NULL;
+	session = client->sessions;
+	while (session) {
+		if (session == sess) {
+			if (prev == NULL) {
+				client->sessions = sess->next;
+			} else {
+				prev->next = sess->next;
+			}
+			radius_server_session_free(data, sess);
+			break;
+		}
+		prev = session;
+		session = session->next;
+	}
+}
+
+
+static void radius_server_session_remove_timeout(void *eloop_ctx,
+						 void *timeout_ctx)
+{
+	struct radius_server_data *data = eloop_ctx;
+	struct radius_session *sess = timeout_ctx;
+	RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
+	radius_server_session_remove(data, sess);
+}
+
+
+static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct radius_server_data *data = eloop_ctx;
+	struct radius_session *sess = timeout_ctx;
+
+	RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
+	radius_server_session_remove(data, sess);
+}
+
+
+static struct radius_session *
+radius_server_new_session(struct radius_server_data *data,
+			  struct radius_client *client)
+{
+	struct radius_session *sess;
+
+	if (data->num_sess >= RADIUS_MAX_SESSION) {
+		RADIUS_DEBUG("Maximum number of existing session - no room "
+			     "for a new session");
+		return NULL;
+	}
+
+	sess = os_zalloc(sizeof(*sess));
+	if (sess == NULL)
+		return NULL;
+
+	sess->server = data;
+	sess->client = client;
+	sess->sess_id = data->next_sess_id++;
+	sess->next = client->sessions;
+	client->sessions = sess;
+	eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
+			       radius_server_session_timeout, data, sess);
+	data->num_sess++;
+	return sess;
+}
+
+
+static struct radius_session *
+radius_server_get_new_session(struct radius_server_data *data,
+			      struct radius_client *client,
+			      struct radius_msg *msg)
+{
+	u8 *user;
+	size_t user_len;
+	int res;
+	struct radius_session *sess;
+	struct eap_config eap_conf;
+
+	RADIUS_DEBUG("Creating a new session");
+
+	user = os_malloc(256);
+	if (user == NULL) {
+		return NULL;
+	}
+	res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
+	if (res < 0 || res > 256) {
+		RADIUS_DEBUG("Could not get User-Name");
+		os_free(user);
+		return NULL;
+	}
+	user_len = res;
+	RADIUS_DUMP_ASCII("User-Name", user, user_len);
+
+	res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
+	os_free(user);
+
+	if (res == 0) {
+		RADIUS_DEBUG("Matching user entry found");
+		sess = radius_server_new_session(data, client);
+		if (sess == NULL) {
+			RADIUS_DEBUG("Failed to create a new session");
+			return NULL;
+		}
+	} else {
+		RADIUS_DEBUG("User-Name not found from user database");
+		return NULL;
+	}
+
+	os_memset(&eap_conf, 0, sizeof(eap_conf));
+	eap_conf.ssl_ctx = data->ssl_ctx;
+	eap_conf.msg_ctx = data->msg_ctx;
+	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
+	eap_conf.backend_auth = TRUE;
+	eap_conf.eap_server = 1;
+	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
+	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
+	eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
+	eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
+	eap_conf.eap_fast_prov = data->eap_fast_prov;
+	eap_conf.pac_key_lifetime = data->pac_key_lifetime;
+	eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
+	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
+	eap_conf.tnc = data->tnc;
+	eap_conf.wps = data->wps;
+	eap_conf.pwd_group = data->pwd_group;
+	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
+				       &eap_conf);
+	if (sess->eap == NULL) {
+		RADIUS_DEBUG("Failed to initialize EAP state machine for the "
+			     "new session");
+		radius_server_session_free(data, sess);
+		return NULL;
+	}
+	sess->eap_if = eap_get_interface(sess->eap);
+	sess->eap_if->eapRestart = TRUE;
+	sess->eap_if->portEnabled = TRUE;
+
+	RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
+
+	return sess;
+}
+
+
+static struct radius_msg *
+radius_server_encapsulate_eap(struct radius_server_data *data,
+			      struct radius_client *client,
+			      struct radius_session *sess,
+			      struct radius_msg *request)
+{
+	struct radius_msg *msg;
+	int code;
+	unsigned int sess_id;
+	struct radius_hdr *hdr = radius_msg_get_hdr(request);
+
+	if (sess->eap_if->eapFail) {
+		sess->eap_if->eapFail = FALSE;
+		code = RADIUS_CODE_ACCESS_REJECT;
+	} else if (sess->eap_if->eapSuccess) {
+		sess->eap_if->eapSuccess = FALSE;
+		code = RADIUS_CODE_ACCESS_ACCEPT;
+	} else {
+		sess->eap_if->eapReq = FALSE;
+		code = RADIUS_CODE_ACCESS_CHALLENGE;
+	}
+
+	msg = radius_msg_new(code, hdr->identifier);
+	if (msg == NULL) {
+		RADIUS_DEBUG("Failed to allocate reply message");
+		return NULL;
+	}
+
+	sess_id = htonl(sess->sess_id);
+	if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
+				 (u8 *) &sess_id, sizeof(sess_id))) {
+		RADIUS_DEBUG("Failed to add State attribute");
+	}
+
+	if (sess->eap_if->eapReqData &&
+	    !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
+				wpabuf_len(sess->eap_if->eapReqData))) {
+		RADIUS_DEBUG("Failed to add EAP-Message attribute");
+	}
+
+	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
+		int len;
+#ifdef CONFIG_RADIUS_TEST
+		if (data->dump_msk_file) {
+			FILE *f;
+			char buf[2 * 64 + 1];
+			f = fopen(data->dump_msk_file, "a");
+			if (f) {
+				len = sess->eap_if->eapKeyDataLen;
+				if (len > 64)
+					len = 64;
+				len = wpa_snprintf_hex(
+					buf, sizeof(buf),
+					sess->eap_if->eapKeyData, len);
+				buf[len] = '\0';
+				fprintf(f, "%s\n", buf);
+				fclose(f);
+			}
+		}
+#endif /* CONFIG_RADIUS_TEST */
+		if (sess->eap_if->eapKeyDataLen > 64) {
+			len = 32;
+		} else {
+			len = sess->eap_if->eapKeyDataLen / 2;
+		}
+		if (!radius_msg_add_mppe_keys(msg, hdr->authenticator,
+					      (u8 *) client->shared_secret,
+					      client->shared_secret_len,
+					      sess->eap_if->eapKeyData + len,
+					      len, sess->eap_if->eapKeyData,
+					      len)) {
+			RADIUS_DEBUG("Failed to add MPPE key attributes");
+		}
+	}
+
+	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
+		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
+		radius_msg_free(msg);
+		return NULL;
+	}
+
+	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
+				  client->shared_secret_len,
+				  hdr->authenticator) < 0) {
+		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+	}
+
+	return msg;
+}
+
+
+static int radius_server_reject(struct radius_server_data *data,
+				struct radius_client *client,
+				struct radius_msg *request,
+				struct sockaddr *from, socklen_t fromlen,
+				const char *from_addr, int from_port)
+{
+	struct radius_msg *msg;
+	int ret = 0;
+	struct eap_hdr eapfail;
+	struct wpabuf *buf;
+	struct radius_hdr *hdr = radius_msg_get_hdr(request);
+
+	RADIUS_DEBUG("Reject invalid request from %s:%d",
+		     from_addr, from_port);
+
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier);
+	if (msg == NULL) {
+		return -1;
+	}
+
+	os_memset(&eapfail, 0, sizeof(eapfail));
+	eapfail.code = EAP_CODE_FAILURE;
+	eapfail.identifier = 0;
+	eapfail.length = host_to_be16(sizeof(eapfail));
+
+	if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
+		RADIUS_DEBUG("Failed to add EAP-Message attribute");
+	}
+
+	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
+		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
+		radius_msg_free(msg);
+		return -1;
+	}
+
+	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
+				  client->shared_secret_len,
+				  hdr->authenticator) <
+	    0) {
+		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+	}
+
+	if (wpa_debug_level <= MSG_MSGDUMP) {
+		radius_msg_dump(msg);
+	}
+
+	data->counters.access_rejects++;
+	client->counters.access_rejects++;
+	buf = radius_msg_get_buf(msg);
+	if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
+		   (struct sockaddr *) from, sizeof(*from)) < 0) {
+		perror("sendto[RADIUS SRV]");
+		ret = -1;
+	}
+
+	radius_msg_free(msg);
+
+	return ret;
+}
+
+
+static int radius_server_request(struct radius_server_data *data,
+				 struct radius_msg *msg,
+				 struct sockaddr *from, socklen_t fromlen,
+				 struct radius_client *client,
+				 const char *from_addr, int from_port,
+				 struct radius_session *force_sess)
+{
+	struct wpabuf *eap = NULL;
+	int res, state_included = 0;
+	u8 statebuf[4];
+	unsigned int state;
+	struct radius_session *sess;
+	struct radius_msg *reply;
+	int is_complete = 0;
+
+	if (force_sess)
+		sess = force_sess;
+	else {
+		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
+					  sizeof(statebuf));
+		state_included = res >= 0;
+		if (res == sizeof(statebuf)) {
+			state = WPA_GET_BE32(statebuf);
+			sess = radius_server_get_session(client, state);
+		} else {
+			sess = NULL;
+		}
+	}
+
+	if (sess) {
+		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
+	} else if (state_included) {
+		RADIUS_DEBUG("State attribute included but no session found");
+		radius_server_reject(data, client, msg, from, fromlen,
+				     from_addr, from_port);
+		return -1;
+	} else {
+		sess = radius_server_get_new_session(data, client, msg);
+		if (sess == NULL) {
+			RADIUS_DEBUG("Could not create a new session");
+			radius_server_reject(data, client, msg, from, fromlen,
+					     from_addr, from_port);
+			return -1;
+		}
+	}
+
+	if (sess->last_from_port == from_port &&
+	    sess->last_identifier == radius_msg_get_hdr(msg)->identifier &&
+	    os_memcmp(sess->last_authenticator,
+		      radius_msg_get_hdr(msg)->authenticator, 16) == 0) {
+		RADIUS_DEBUG("Duplicate message from %s", from_addr);
+		data->counters.dup_access_requests++;
+		client->counters.dup_access_requests++;
+
+		if (sess->last_reply) {
+			struct wpabuf *buf;
+			buf = radius_msg_get_buf(sess->last_reply);
+			res = sendto(data->auth_sock, wpabuf_head(buf),
+				     wpabuf_len(buf), 0,
+				     (struct sockaddr *) from, fromlen);
+			if (res < 0) {
+				perror("sendto[RADIUS SRV]");
+			}
+			return 0;
+		}
+
+		RADIUS_DEBUG("No previous reply available for duplicate "
+			     "message");
+		return -1;
+	}
+		      
+	eap = radius_msg_get_eap(msg);
+	if (eap == NULL) {
+		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
+			     from_addr);
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
+		return -1;
+	}
+
+	RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));
+
+	/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
+	 * RFC3579 Sect. 2.6.2.
+	 * Include EAP-Response/Nak with no preferred method if
+	 * code == request.
+	 * If code is not 1-4, discard the packet silently.
+	 * Or is this already done by the EAP state machine? */
+
+	wpabuf_free(sess->eap_if->eapRespData);
+	sess->eap_if->eapRespData = eap;
+	sess->eap_if->eapResp = TRUE;
+	eap_server_sm_step(sess->eap);
+
+	if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
+	     sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
+		RADIUS_DUMP("EAP data from the state machine",
+			    wpabuf_head(sess->eap_if->eapReqData),
+			    wpabuf_len(sess->eap_if->eapReqData));
+	} else if (sess->eap_if->eapFail) {
+		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
+			     "set");
+	} else if (eap_sm_method_pending(sess->eap)) {
+		radius_msg_free(sess->last_msg);
+		sess->last_msg = msg;
+		sess->last_from_port = from_port;
+		os_free(sess->last_from_addr);
+		sess->last_from_addr = os_strdup(from_addr);
+		sess->last_fromlen = fromlen;
+		os_memcpy(&sess->last_from, from, fromlen);
+		return -2;
+	} else {
+		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
+			     " Access-Request silently (assuming it was a "
+			     "duplicate)");
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
+		return -1;
+	}
+
+	if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
+		is_complete = 1;
+
+	reply = radius_server_encapsulate_eap(data, client, sess, msg);
+
+	if (reply) {
+		struct wpabuf *buf;
+		struct radius_hdr *hdr;
+
+		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
+		if (wpa_debug_level <= MSG_MSGDUMP) {
+			radius_msg_dump(reply);
+		}
+
+		switch (radius_msg_get_hdr(reply)->code) {
+		case RADIUS_CODE_ACCESS_ACCEPT:
+			data->counters.access_accepts++;
+			client->counters.access_accepts++;
+			break;
+		case RADIUS_CODE_ACCESS_REJECT:
+			data->counters.access_rejects++;
+			client->counters.access_rejects++;
+			break;
+		case RADIUS_CODE_ACCESS_CHALLENGE:
+			data->counters.access_challenges++;
+			client->counters.access_challenges++;
+			break;
+		}
+		buf = radius_msg_get_buf(reply);
+		res = sendto(data->auth_sock, wpabuf_head(buf),
+			     wpabuf_len(buf), 0,
+			     (struct sockaddr *) from, fromlen);
+		if (res < 0) {
+			perror("sendto[RADIUS SRV]");
+		}
+		radius_msg_free(sess->last_reply);
+		sess->last_reply = reply;
+		sess->last_from_port = from_port;
+		hdr = radius_msg_get_hdr(msg);
+		sess->last_identifier = hdr->identifier;
+		os_memcpy(sess->last_authenticator, hdr->authenticator, 16);
+	} else {
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
+	}
+
+	if (is_complete) {
+		RADIUS_DEBUG("Removing completed session 0x%x after timeout",
+			     sess->sess_id);
+		eloop_cancel_timeout(radius_server_session_remove_timeout,
+				     data, sess);
+		eloop_register_timeout(10, 0,
+				       radius_server_session_remove_timeout,
+				       data, sess);
+	}
+
+	return 0;
+}
+
+
+static void radius_server_receive_auth(int sock, void *eloop_ctx,
+				       void *sock_ctx)
+{
+	struct radius_server_data *data = eloop_ctx;
+	u8 *buf = NULL;
+	union {
+		struct sockaddr_storage ss;
+		struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+		struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+	} from;
+	socklen_t fromlen;
+	int len;
+	struct radius_client *client = NULL;
+	struct radius_msg *msg = NULL;
+	char abuf[50];
+	int from_port = 0;
+
+	buf = os_malloc(RADIUS_MAX_MSG_LEN);
+	if (buf == NULL) {
+		goto fail;
+	}
+
+	fromlen = sizeof(from);
+	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
+		       (struct sockaddr *) &from.ss, &fromlen);
+	if (len < 0) {
+		perror("recvfrom[radius_server]");
+		goto fail;
+	}
+
+#ifdef CONFIG_IPV6
+	if (data->ipv6) {
+		if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+			      sizeof(abuf)) == NULL)
+			abuf[0] = '\0';
+		from_port = ntohs(from.sin6.sin6_port);
+		RADIUS_DEBUG("Received %d bytes from %s:%d",
+			     len, abuf, from_port);
+
+		client = radius_server_get_client(data,
+						  (struct in_addr *)
+						  &from.sin6.sin6_addr, 1);
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (!data->ipv6) {
+		os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+		from_port = ntohs(from.sin.sin_port);
+		RADIUS_DEBUG("Received %d bytes from %s:%d",
+			     len, abuf, from_port);
+
+		client = radius_server_get_client(data, &from.sin.sin_addr, 0);
+	}
+
+	RADIUS_DUMP("Received data", buf, len);
+
+	if (client == NULL) {
+		RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+		data->counters.invalid_requests++;
+		goto fail;
+	}
+
+	msg = radius_msg_parse(buf, len);
+	if (msg == NULL) {
+		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+		data->counters.malformed_access_requests++;
+		client->counters.malformed_access_requests++;
+		goto fail;
+	}
+
+	os_free(buf);
+	buf = NULL;
+
+	if (wpa_debug_level <= MSG_MSGDUMP) {
+		radius_msg_dump(msg);
+	}
+
+	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
+		RADIUS_DEBUG("Unexpected RADIUS code %d",
+			     radius_msg_get_hdr(msg)->code);
+		data->counters.unknown_types++;
+		client->counters.unknown_types++;
+		goto fail;
+	}
+
+	data->counters.access_requests++;
+	client->counters.access_requests++;
+
+	if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
+				       client->shared_secret_len, NULL)) {
+		RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
+		data->counters.bad_authenticators++;
+		client->counters.bad_authenticators++;
+		goto fail;
+	}
+
+	if (radius_server_request(data, msg, (struct sockaddr *) &from,
+				  fromlen, client, abuf, from_port, NULL) ==
+	    -2)
+		return; /* msg was stored with the session */
+
+fail:
+	radius_msg_free(msg);
+	os_free(buf);
+}
+
+
+static int radius_server_disable_pmtu_discovery(int s)
+{
+	int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
+	int action = IP_PMTUDISC_DONT;
+	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+		       sizeof(action));
+	if (r == -1)
+		wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
+			   "%s", strerror(errno));
+#endif
+	return r;
+}
+
+
+static int radius_server_open_socket(int port)
+{
+	int s;
+	struct sockaddr_in addr;
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket");
+		return -1;
+	}
+
+	radius_server_disable_pmtu_discovery(s);
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+
+
+#ifdef CONFIG_IPV6
+static int radius_server_open_socket6(int port)
+{
+	int s;
+	struct sockaddr_in6 addr;
+
+	s = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket[IPv6]");
+		return -1;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin6_family = AF_INET6;
+	os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
+	addr.sin6_port = htons(port);
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+#endif /* CONFIG_IPV6 */
+
+
+static void radius_server_free_sessions(struct radius_server_data *data,
+					struct radius_session *sessions)
+{
+	struct radius_session *session, *prev;
+
+	session = sessions;
+	while (session) {
+		prev = session;
+		session = session->next;
+		radius_server_session_free(data, prev);
+	}
+}
+
+
+static void radius_server_free_clients(struct radius_server_data *data,
+				       struct radius_client *clients)
+{
+	struct radius_client *client, *prev;
+
+	client = clients;
+	while (client) {
+		prev = client;
+		client = client->next;
+
+		radius_server_free_sessions(data, prev->sessions);
+		os_free(prev->shared_secret);
+		os_free(prev);
+	}
+}
+
+
+static struct radius_client *
+radius_server_read_clients(const char *client_file, int ipv6)
+{
+	FILE *f;
+	const int buf_size = 1024;
+	char *buf, *pos;
+	struct radius_client *clients, *tail, *entry;
+	int line = 0, mask, failed = 0, i;
+	struct in_addr addr;
+#ifdef CONFIG_IPV6
+	struct in6_addr addr6;
+#endif /* CONFIG_IPV6 */
+	unsigned int val;
+
+	f = fopen(client_file, "r");
+	if (f == NULL) {
+		RADIUS_ERROR("Could not open client file '%s'", client_file);
+		return NULL;
+	}
+
+	buf = os_malloc(buf_size);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	clients = tail = NULL;
+	while (fgets(buf, buf_size, f)) {
+		/* Configuration file format:
+		 * 192.168.1.0/24 secret
+		 * 192.168.1.2 secret
+		 * fe80::211:22ff:fe33:4455/64 secretipv6
+		 */
+		line++;
+		buf[buf_size - 1] = '\0';
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		if (*buf == '\0' || *buf == '#')
+			continue;
+
+		pos = buf;
+		while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
+		       (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
+		       (*pos >= 'A' && *pos <= 'F')) {
+			pos++;
+		}
+
+		if (*pos == '\0') {
+			failed = 1;
+			break;
+		}
+
+		if (*pos == '/') {
+			char *end;
+			*pos++ = '\0';
+			mask = strtol(pos, &end, 10);
+			if ((pos == end) ||
+			    (mask < 0 || mask > (ipv6 ? 128 : 32))) {
+				failed = 1;
+				break;
+			}
+			pos = end;
+		} else {
+			mask = ipv6 ? 128 : 32;
+			*pos++ = '\0';
+		}
+
+		if (!ipv6 && inet_aton(buf, &addr) == 0) {
+			failed = 1;
+			break;
+		}
+#ifdef CONFIG_IPV6
+		if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
+			if (inet_pton(AF_INET, buf, &addr) <= 0) {
+				failed = 1;
+				break;
+			}
+			/* Convert IPv4 address to IPv6 */
+			if (mask <= 32)
+				mask += (128 - 32);
+			os_memset(addr6.s6_addr, 0, 10);
+			addr6.s6_addr[10] = 0xff;
+			addr6.s6_addr[11] = 0xff;
+			os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
+				  4);
+		}
+#endif /* CONFIG_IPV6 */
+
+		while (*pos == ' ' || *pos == '\t') {
+			pos++;
+		}
+
+		if (*pos == '\0') {
+			failed = 1;
+			break;
+		}
+
+		entry = os_zalloc(sizeof(*entry));
+		if (entry == NULL) {
+			failed = 1;
+			break;
+		}
+		entry->shared_secret = os_strdup(pos);
+		if (entry->shared_secret == NULL) {
+			failed = 1;
+			os_free(entry);
+			break;
+		}
+		entry->shared_secret_len = os_strlen(entry->shared_secret);
+		entry->addr.s_addr = addr.s_addr;
+		if (!ipv6) {
+			val = 0;
+			for (i = 0; i < mask; i++)
+				val |= 1 << (31 - i);
+			entry->mask.s_addr = htonl(val);
+		}
+#ifdef CONFIG_IPV6
+		if (ipv6) {
+			int offset = mask / 8;
+
+			os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
+			os_memset(entry->mask6.s6_addr, 0xff, offset);
+			val = 0;
+			for (i = 0; i < (mask % 8); i++)
+				val |= 1 << (7 - i);
+			if (offset < 16)
+				entry->mask6.s6_addr[offset] = val;
+		}
+#endif /* CONFIG_IPV6 */
+
+		if (tail == NULL) {
+			clients = tail = entry;
+		} else {
+			tail->next = entry;
+			tail = entry;
+		}
+	}
+
+	if (failed) {
+		RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
+		radius_server_free_clients(NULL, clients);
+		clients = NULL;
+	}
+
+	os_free(buf);
+	fclose(f);
+
+	return clients;
+}
+
+
+/**
+ * radius_server_init - Initialize RADIUS server
+ * @conf: Configuration for the RADIUS server
+ * Returns: Pointer to private RADIUS server context or %NULL on failure
+ *
+ * This initializes a RADIUS server instance and returns a context pointer that
+ * will be used in other calls to the RADIUS server module. The server can be
+ * deinitialize by calling radius_server_deinit().
+ */
+struct radius_server_data *
+radius_server_init(struct radius_server_conf *conf)
+{
+	struct radius_server_data *data;
+
+#ifndef CONFIG_IPV6
+	if (conf->ipv6) {
+		fprintf(stderr, "RADIUS server compiled without IPv6 "
+			"support.\n");
+		return NULL;
+	}
+#endif /* CONFIG_IPV6 */
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	os_get_time(&data->start_time);
+	data->conf_ctx = conf->conf_ctx;
+	data->eap_sim_db_priv = conf->eap_sim_db_priv;
+	data->ssl_ctx = conf->ssl_ctx;
+	data->msg_ctx = conf->msg_ctx;
+	data->ipv6 = conf->ipv6;
+	if (conf->pac_opaque_encr_key) {
+		data->pac_opaque_encr_key = os_malloc(16);
+		os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
+			  16);
+	}
+	if (conf->eap_fast_a_id) {
+		data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
+		if (data->eap_fast_a_id) {
+			os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
+				  conf->eap_fast_a_id_len);
+			data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
+		}
+	}
+	if (conf->eap_fast_a_id_info)
+		data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
+	data->eap_fast_prov = conf->eap_fast_prov;
+	data->pac_key_lifetime = conf->pac_key_lifetime;
+	data->pac_key_refresh_time = conf->pac_key_refresh_time;
+	data->get_eap_user = conf->get_eap_user;
+	data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	data->tnc = conf->tnc;
+	data->wps = conf->wps;
+	data->pwd_group = conf->pwd_group;
+	if (conf->eap_req_id_text) {
+		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
+		if (data->eap_req_id_text) {
+			os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+				  conf->eap_req_id_text_len);
+			data->eap_req_id_text_len = conf->eap_req_id_text_len;
+		}
+	}
+
+#ifdef CONFIG_RADIUS_TEST
+	if (conf->dump_msk_file)
+		data->dump_msk_file = os_strdup(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
+	data->clients = radius_server_read_clients(conf->client_file,
+						   conf->ipv6);
+	if (data->clients == NULL) {
+		printf("No RADIUS clients configured.\n");
+		radius_server_deinit(data);
+		return NULL;
+	}
+
+#ifdef CONFIG_IPV6
+	if (conf->ipv6)
+		data->auth_sock = radius_server_open_socket6(conf->auth_port);
+	else
+#endif /* CONFIG_IPV6 */
+	data->auth_sock = radius_server_open_socket(conf->auth_port);
+	if (data->auth_sock < 0) {
+		printf("Failed to open UDP socket for RADIUS authentication "
+		       "server\n");
+		radius_server_deinit(data);
+		return NULL;
+	}
+	if (eloop_register_read_sock(data->auth_sock,
+				     radius_server_receive_auth,
+				     data, NULL)) {
+		radius_server_deinit(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+/**
+ * radius_server_deinit - Deinitialize RADIUS server
+ * @data: RADIUS server context from radius_server_init()
+ */
+void radius_server_deinit(struct radius_server_data *data)
+{
+	if (data == NULL)
+		return;
+
+	if (data->auth_sock >= 0) {
+		eloop_unregister_read_sock(data->auth_sock);
+		close(data->auth_sock);
+	}
+
+	radius_server_free_clients(data, data->clients);
+
+	os_free(data->pac_opaque_encr_key);
+	os_free(data->eap_fast_a_id);
+	os_free(data->eap_fast_a_id_info);
+	os_free(data->eap_req_id_text);
+#ifdef CONFIG_RADIUS_TEST
+	os_free(data->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+	os_free(data);
+}
+
+
+/**
+ * radius_server_get_mib - Get RADIUS server MIB information
+ * @data: RADIUS server context from radius_server_init()
+ * @buf: Buffer for returning the MIB data in text format
+ * @buflen: buf length in octets
+ * Returns: Number of octets written into buf
+ */
+int radius_server_get_mib(struct radius_server_data *data, char *buf,
+			  size_t buflen)
+{
+	int ret, uptime;
+	unsigned int idx;
+	char *end, *pos;
+	struct os_time now;
+	struct radius_client *cli;
+
+	/* RFC 2619 - RADIUS Authentication Server MIB */
+
+	if (data == NULL || buflen == 0)
+		return 0;
+
+	pos = buf;
+	end = buf + buflen;
+
+	os_get_time(&now);
+	uptime = (now.sec - data->start_time.sec) * 100 +
+		((now.usec - data->start_time.usec) / 10000) % 100;
+	ret = os_snprintf(pos, end - pos,
+			  "RADIUS-AUTH-SERVER-MIB\n"
+			  "radiusAuthServIdent=hostapd\n"
+			  "radiusAuthServUpTime=%d\n"
+			  "radiusAuthServResetTime=0\n"
+			  "radiusAuthServConfigReset=4\n",
+			  uptime);
+	if (ret < 0 || ret >= end - pos) {
+		*pos = '\0';
+		return pos - buf;
+	}
+	pos += ret;
+
+	ret = os_snprintf(pos, end - pos,
+			  "radiusAuthServTotalAccessRequests=%u\n"
+			  "radiusAuthServTotalInvalidRequests=%u\n"
+			  "radiusAuthServTotalDupAccessRequests=%u\n"
+			  "radiusAuthServTotalAccessAccepts=%u\n"
+			  "radiusAuthServTotalAccessRejects=%u\n"
+			  "radiusAuthServTotalAccessChallenges=%u\n"
+			  "radiusAuthServTotalMalformedAccessRequests=%u\n"
+			  "radiusAuthServTotalBadAuthenticators=%u\n"
+			  "radiusAuthServTotalPacketsDropped=%u\n"
+			  "radiusAuthServTotalUnknownTypes=%u\n",
+			  data->counters.access_requests,
+			  data->counters.invalid_requests,
+			  data->counters.dup_access_requests,
+			  data->counters.access_accepts,
+			  data->counters.access_rejects,
+			  data->counters.access_challenges,
+			  data->counters.malformed_access_requests,
+			  data->counters.bad_authenticators,
+			  data->counters.packets_dropped,
+			  data->counters.unknown_types);
+	if (ret < 0 || ret >= end - pos) {
+		*pos = '\0';
+		return pos - buf;
+	}
+	pos += ret;
+
+	for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
+		char abuf[50], mbuf[50];
+#ifdef CONFIG_IPV6
+		if (data->ipv6) {
+			if (inet_ntop(AF_INET6, &cli->addr6, abuf,
+				      sizeof(abuf)) == NULL)
+				abuf[0] = '\0';
+			if (inet_ntop(AF_INET6, &cli->mask6, abuf,
+				      sizeof(mbuf)) == NULL)
+				mbuf[0] = '\0';
+		}
+#endif /* CONFIG_IPV6 */
+		if (!data->ipv6) {
+			os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
+			os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
+		}
+
+		ret = os_snprintf(pos, end - pos,
+				  "radiusAuthClientIndex=%u\n"
+				  "radiusAuthClientAddress=%s/%s\n"
+				  "radiusAuthServAccessRequests=%u\n"
+				  "radiusAuthServDupAccessRequests=%u\n"
+				  "radiusAuthServAccessAccepts=%u\n"
+				  "radiusAuthServAccessRejects=%u\n"
+				  "radiusAuthServAccessChallenges=%u\n"
+				  "radiusAuthServMalformedAccessRequests=%u\n"
+				  "radiusAuthServBadAuthenticators=%u\n"
+				  "radiusAuthServPacketsDropped=%u\n"
+				  "radiusAuthServUnknownTypes=%u\n",
+				  idx,
+				  abuf, mbuf,
+				  cli->counters.access_requests,
+				  cli->counters.dup_access_requests,
+				  cli->counters.access_accepts,
+				  cli->counters.access_rejects,
+				  cli->counters.access_challenges,
+				  cli->counters.malformed_access_requests,
+				  cli->counters.bad_authenticators,
+				  cli->counters.packets_dropped,
+				  cli->counters.unknown_types);
+		if (ret < 0 || ret >= end - pos) {
+			*pos = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int radius_server_get_eap_user(void *ctx, const u8 *identity,
+				      size_t identity_len, int phase2,
+				      struct eap_user *user)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+
+	return data->get_eap_user(data->conf_ctx, identity, identity_len,
+				  phase2, user);
+}
+
+
+static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+	*len = data->eap_req_id_text_len;
+	return data->eap_req_id_text;
+}
+
+
+static struct eapol_callbacks radius_server_eapol_cb =
+{
+	.get_eap_user = radius_server_get_eap_user,
+	.get_eap_req_id_text = radius_server_get_eap_req_id_text,
+};
+
+
+/**
+ * radius_server_eap_pending_cb - Pending EAP data notification
+ * @data: RADIUS server context from radius_server_init()
+ * @ctx: Pending EAP context pointer
+ *
+ * This function is used to notify EAP server module that a pending operation
+ * has been completed and processing of the EAP session can proceed.
+ */
+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
+{
+	struct radius_client *cli;
+	struct radius_session *s, *sess = NULL;
+	struct radius_msg *msg;
+
+	if (data == NULL)
+		return;
+
+	for (cli = data->clients; cli; cli = cli->next) {
+		for (s = cli->sessions; s; s = s->next) {
+			if (s->eap == ctx && s->last_msg) {
+				sess = s;
+				break;
+			}
+			if (sess)
+				break;
+		}
+		if (sess)
+			break;
+	}
+
+	if (sess == NULL) {
+		RADIUS_DEBUG("No session matched callback ctx");
+		return;
+	}
+
+	msg = sess->last_msg;
+	sess->last_msg = NULL;
+	eap_sm_pending_cb(sess->eap);
+	if (radius_server_request(data, msg,
+				  (struct sockaddr *) &sess->last_from,
+				  sess->last_fromlen, cli,
+				  sess->last_from_addr,
+				  sess->last_from_port, sess) == -2)
+		return; /* msg was stored with the session */
+
+	radius_msg_free(msg);
+}

Deleted: vendor/wpa/2.0/src/radius/radius_server.h
===================================================================
--- vendor/wpa/dist/src/radius/radius_server.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/radius/radius_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,210 +0,0 @@
-/*
- * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef RADIUS_SERVER_H
-#define RADIUS_SERVER_H
-
-struct radius_server_data;
-struct eap_user;
-
-/**
- * struct radius_server_conf - RADIUS server configuration
- */
-struct radius_server_conf {
-	/**
-	 * auth_port - UDP port to listen to as an authentication server
-	 */
-	int auth_port;
-
-	/**
-	 * client_file - RADIUS client configuration file
-	 *
-	 * This file contains the RADIUS clients and the shared secret to be
-	 * used with them in a format where each client is on its own line. The
-	 * first item on the line is the IPv4 or IPv6 address of the client
-	 * with an optional address mask to allow full network to be specified
-	 * (e.g., 192.168.1.2 or 192.168.1.0/24). This is followed by white
-	 * space (space or tabulator) and the shared secret. Lines starting
-	 * with '#' are skipped and can be used as comments.
-	 */
-	char *client_file;
-
-	/**
-	 * conf_ctx - Context pointer for callbacks
-	 *
-	 * This is used as the ctx argument in get_eap_user() calls.
-	 */
-	void *conf_ctx;
-
-	/**
-	 * eap_sim_db_priv - EAP-SIM/AKA database context
-	 *
-	 * This is passed to the EAP-SIM/AKA server implementation as a
-	 * callback context.
-	 */
-	void *eap_sim_db_priv;
-
-	/**
-	 * ssl_ctx - TLS context
-	 *
-	 * This is passed to the EAP server implementation as a callback
-	 * context for TLS operations.
-	 */
-	void *ssl_ctx;
-
-	/**
-	 * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
-	 *
-	 * This parameter is used to set a key for EAP-FAST to encrypt the
-	 * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
-	 * set, must point to a 16-octet key.
-	 */
-	u8 *pac_opaque_encr_key;
-
-	/**
-	 * eap_fast_a_id - EAP-FAST authority identity (A-ID)
-	 *
-	 * If EAP-FAST is not used, this can be set to %NULL. In theory, this
-	 * is a variable length field, but due to some existing implementations
-	 * requiring A-ID to be 16 octets in length, it is recommended to use
-	 * that length for the field to provide interoperability with deployed
-	 * peer implementations.
-	 */
-	u8 *eap_fast_a_id;
-
-	/**
-	 * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
-	 */
-	size_t eap_fast_a_id_len;
-
-	/**
-	 * eap_fast_a_id_info - EAP-FAST authority identifier information
-	 *
-	 * This A-ID-Info contains a user-friendly name for the A-ID. For
-	 * example, this could be the enterprise and server names in
-	 * human-readable format. This field is encoded as UTF-8. If EAP-FAST
-	 * is not used, this can be set to %NULL.
-	 */
-	char *eap_fast_a_id_info;
-
-	/**
-	 * eap_fast_prov - EAP-FAST provisioning modes
-	 *
-	 * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
-	 * 2 = only authenticated provisioning allowed, 3 = both provisioning
-	 * modes allowed.
-	 */
-	int eap_fast_prov;
-
-	/**
-	 * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
-	 *
-	 * This is the hard limit on how long a provisioned PAC-Key can be
-	 * used.
-	 */
-	int pac_key_lifetime;
-
-	/**
-	 * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
-	 *
-	 * This is a soft limit on the PAC-Key. The server will automatically
-	 * generate a new PAC-Key when this number of seconds (or fewer) of the
-	 * lifetime remains.
-	 */
-	int pac_key_refresh_time;
-
-	/**
-	 * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
-	 *
-	 * This controls whether the protected success/failure indication
-	 * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
-	 */
-	int eap_sim_aka_result_ind;
-
-	/**
-	 * tnc - Trusted Network Connect (TNC)
-	 *
-	 * This controls whether TNC is enabled and will be required before the
-	 * peer is allowed to connect. Note: This is only used with EAP-TTLS
-	 * and EAP-FAST. If any other EAP method is enabled, the peer will be
-	 * allowed to connect without TNC.
-	 */
-	int tnc;
-
-	/**
-	 * wps - Wi-Fi Protected Setup context
-	 *
-	 * If WPS is used with an external RADIUS server (which is quite
-	 * unlikely configuration), this is used to provide a pointer to WPS
-	 * context data. Normally, this can be set to %NULL.
-	 */
-	struct wps_context *wps;
-
-	/**
-	 * ipv6 - Whether to enable IPv6 support in the RADIUS server
-	 */
-	int ipv6;
-
-	/**
-	 * get_eap_user - Callback for fetching EAP user information
-	 * @ctx: Context data from conf_ctx
-	 * @identity: User identity
-	 * @identity_len: identity buffer length in octets
-	 * @phase2: Whether this is for Phase 2 identity
-	 * @user: Data structure for filling in the user information
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This is used to fetch information from user database. The callback
-	 * will fill in information about allowed EAP methods and the user
-	 * password. The password field will be an allocated copy of the
-	 * password data and RADIUS server will free it after use.
-	 */
-	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
-			    int phase2, struct eap_user *user);
-
-	/**
-	 * eap_req_id_text - Optional data for EAP-Request/Identity
-	 *
-	 * This can be used to configure an optional, displayable message that
-	 * will be sent in EAP-Request/Identity. This string can contain an
-	 * ASCII-0 character (nul) to separate network infromation per RFC
-	 * 4284. The actual string length is explicit provided in
-	 * eap_req_id_text_len since nul character will not be used as a string
-	 * terminator.
-	 */
-	const char *eap_req_id_text;
-
-	/**
-	 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
-	 */
-	size_t eap_req_id_text_len;
-
-	/*
-	 * msg_ctx - Context data for wpa_msg() calls
-	 */
-	void *msg_ctx;
-};
-
-
-struct radius_server_data *
-radius_server_init(struct radius_server_conf *conf);
-
-void radius_server_deinit(struct radius_server_data *data);
-
-int radius_server_get_mib(struct radius_server_data *data, char *buf,
-			  size_t buflen);
-
-void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
-
-#endif /* RADIUS_SERVER_H */

Copied: vendor/wpa/2.0/src/radius/radius_server.h (from rev 9639, vendor/wpa/dist/src/radius/radius_server.h)
===================================================================
--- vendor/wpa/2.0/src/radius/radius_server.h	                        (rev 0)
+++ vendor/wpa/2.0/src/radius/radius_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,215 @@
+/*
+ * RADIUS authentication server
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_SERVER_H
+#define RADIUS_SERVER_H
+
+struct radius_server_data;
+struct eap_user;
+
+/**
+ * struct radius_server_conf - RADIUS server configuration
+ */
+struct radius_server_conf {
+	/**
+	 * auth_port - UDP port to listen to as an authentication server
+	 */
+	int auth_port;
+
+	/**
+	 * client_file - RADIUS client configuration file
+	 *
+	 * This file contains the RADIUS clients and the shared secret to be
+	 * used with them in a format where each client is on its own line. The
+	 * first item on the line is the IPv4 or IPv6 address of the client
+	 * with an optional address mask to allow full network to be specified
+	 * (e.g., 192.168.1.2 or 192.168.1.0/24). This is followed by white
+	 * space (space or tabulator) and the shared secret. Lines starting
+	 * with '#' are skipped and can be used as comments.
+	 */
+	char *client_file;
+
+	/**
+	 * conf_ctx - Context pointer for callbacks
+	 *
+	 * This is used as the ctx argument in get_eap_user() calls.
+	 */
+	void *conf_ctx;
+
+	/**
+	 * eap_sim_db_priv - EAP-SIM/AKA database context
+	 *
+	 * This is passed to the EAP-SIM/AKA server implementation as a
+	 * callback context.
+	 */
+	void *eap_sim_db_priv;
+
+	/**
+	 * ssl_ctx - TLS context
+	 *
+	 * This is passed to the EAP server implementation as a callback
+	 * context for TLS operations.
+	 */
+	void *ssl_ctx;
+
+	/**
+	 * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST
+	 *
+	 * This parameter is used to set a key for EAP-FAST to encrypt the
+	 * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If
+	 * set, must point to a 16-octet key.
+	 */
+	u8 *pac_opaque_encr_key;
+
+	/**
+	 * eap_fast_a_id - EAP-FAST authority identity (A-ID)
+	 *
+	 * If EAP-FAST is not used, this can be set to %NULL. In theory, this
+	 * is a variable length field, but due to some existing implementations
+	 * requiring A-ID to be 16 octets in length, it is recommended to use
+	 * that length for the field to provide interoperability with deployed
+	 * peer implementations.
+	 */
+	u8 *eap_fast_a_id;
+
+	/**
+	 * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets
+	 */
+	size_t eap_fast_a_id_len;
+
+	/**
+	 * eap_fast_a_id_info - EAP-FAST authority identifier information
+	 *
+	 * This A-ID-Info contains a user-friendly name for the A-ID. For
+	 * example, this could be the enterprise and server names in
+	 * human-readable format. This field is encoded as UTF-8. If EAP-FAST
+	 * is not used, this can be set to %NULL.
+	 */
+	char *eap_fast_a_id_info;
+
+	/**
+	 * eap_fast_prov - EAP-FAST provisioning modes
+	 *
+	 * 0 = provisioning disabled, 1 = only anonymous provisioning allowed,
+	 * 2 = only authenticated provisioning allowed, 3 = both provisioning
+	 * modes allowed.
+	 */
+	int eap_fast_prov;
+
+	/**
+	 * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds
+	 *
+	 * This is the hard limit on how long a provisioned PAC-Key can be
+	 * used.
+	 */
+	int pac_key_lifetime;
+
+	/**
+	 * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds
+	 *
+	 * This is a soft limit on the PAC-Key. The server will automatically
+	 * generate a new PAC-Key when this number of seconds (or fewer) of the
+	 * lifetime remains.
+	 */
+	int pac_key_refresh_time;
+
+	/**
+	 * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
+	 *
+	 * This controls whether the protected success/failure indication
+	 * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
+	 */
+	int eap_sim_aka_result_ind;
+
+	/**
+	 * tnc - Trusted Network Connect (TNC)
+	 *
+	 * This controls whether TNC is enabled and will be required before the
+	 * peer is allowed to connect. Note: This is only used with EAP-TTLS
+	 * and EAP-FAST. If any other EAP method is enabled, the peer will be
+	 * allowed to connect without TNC.
+	 */
+	int tnc;
+
+	/**
+	 * pwd_group - EAP-pwd D-H group
+	 *
+	 * This is used to select which D-H group to use with EAP-pwd.
+	 */
+	u16 pwd_group;
+
+	/**
+	 * wps - Wi-Fi Protected Setup context
+	 *
+	 * If WPS is used with an external RADIUS server (which is quite
+	 * unlikely configuration), this is used to provide a pointer to WPS
+	 * context data. Normally, this can be set to %NULL.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * ipv6 - Whether to enable IPv6 support in the RADIUS server
+	 */
+	int ipv6;
+
+	/**
+	 * get_eap_user - Callback for fetching EAP user information
+	 * @ctx: Context data from conf_ctx
+	 * @identity: User identity
+	 * @identity_len: identity buffer length in octets
+	 * @phase2: Whether this is for Phase 2 identity
+	 * @user: Data structure for filling in the user information
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is used to fetch information from user database. The callback
+	 * will fill in information about allowed EAP methods and the user
+	 * password. The password field will be an allocated copy of the
+	 * password data and RADIUS server will free it after use.
+	 */
+	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+			    int phase2, struct eap_user *user);
+
+	/**
+	 * eap_req_id_text - Optional data for EAP-Request/Identity
+	 *
+	 * This can be used to configure an optional, displayable message that
+	 * will be sent in EAP-Request/Identity. This string can contain an
+	 * ASCII-0 character (nul) to separate network infromation per RFC
+	 * 4284. The actual string length is explicit provided in
+	 * eap_req_id_text_len since nul character will not be used as a string
+	 * terminator.
+	 */
+	const char *eap_req_id_text;
+
+	/**
+	 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
+	 */
+	size_t eap_req_id_text_len;
+
+	/*
+	 * msg_ctx - Context data for wpa_msg() calls
+	 */
+	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	const char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+};
+
+
+struct radius_server_data *
+radius_server_init(struct radius_server_conf *conf);
+
+void radius_server_deinit(struct radius_server_data *data);
+
+int radius_server_get_mib(struct radius_server_data *data, char *buf,
+			  size_t buflen);
+
+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
+
+#endif /* RADIUS_SERVER_H */

Deleted: vendor/wpa/2.0/src/rsn_supp/peerkey.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/peerkey.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/peerkey.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1184 +0,0 @@
-/*
- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#ifdef CONFIG_PEERKEY
-
-#include "common.h"
-#include "eloop.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "common/ieee802_11_defs.h"
-#include "wpa.h"
-#include "wpa_i.h"
-#include "wpa_ie.h"
-#include "peerkey.h"
-
-
-static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
-{
-	os_memcpy(pos, ie, ie_len);
-	return pos + ie_len;
-}
-
-
-static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
-{
-	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-	*pos++ = RSN_SELECTOR_LEN + data_len;
-	RSN_SELECTOR_PUT(pos, kde);
-	pos += RSN_SELECTOR_LEN;
-	os_memcpy(pos, data, data_len);
-	pos += data_len;
-	return pos;
-}
-
-
-static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
-	struct wpa_sm *sm = eloop_ctx;
-	struct wpa_peerkey *peerkey = timeout_ctx;
-#endif
-	/* TODO: time out SMK and any STK that was generated using this SMK */
-}
-
-
-static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
-					struct wpa_peerkey *peerkey)
-{
-	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
-	os_free(peerkey);
-}
-
-
-static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
-					 const u8 *peer,
-					 u16 mui, u16 error_type, int ver)
-{
-	size_t rlen;
-	struct wpa_eapol_key *err;
-	struct rsn_error_kde error;
-	u8 *rbuf, *pos;
-	size_t kde_len;
-	u16 key_info;
-
-	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
-	if (peer)
-		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
-				  NULL, sizeof(*err) + kde_len, &rlen,
-				  (void *) &err);
-	if (rbuf == NULL)
-		return -1;
-
-	err->type = EAPOL_KEY_TYPE_RSN;
-	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
-		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
-		WPA_KEY_INFO_REQUEST;
-	WPA_PUT_BE16(err->key_info, key_info);
-	WPA_PUT_BE16(err->key_length, 0);
-	os_memcpy(err->replay_counter, sm->request_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
-	pos = (u8 *) (err + 1);
-
-	if (peer) {
-		/* Peer MAC Address KDE */
-		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
-	}
-
-	/* Error KDE */
-	error.mui = host_to_be16(mui);
-	error.error_type = host_to_be16(error_type);
-	wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
-
-	if (peer) {
-		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
-			   MACSTR " mui %d error_type %d)",
-			   MAC2STR(peer), mui, error_type);
-	} else {
-		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
-			   "(mui %d error_type %d)", mui, error_type);
-	}
-
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, err->key_mic);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
-				      const unsigned char *src_addr,
-				      const struct wpa_eapol_key *key,
-				      int ver, struct wpa_peerkey *peerkey)
-{
-	size_t rlen;
-	struct wpa_eapol_key *reply;
-	u8 *rbuf, *pos;
-	size_t kde_len;
-	u16 key_info;
-
-	/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
-	kde_len = peerkey->rsnie_p_len +
-		2 + RSN_SELECTOR_LEN + ETH_ALEN +
-		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
-				  NULL, sizeof(*reply) + kde_len, &rlen,
-				  (void *) &reply);
-	if (rbuf == NULL)
-		return -1;
-
-	reply->type = EAPOL_KEY_TYPE_RSN;
-	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
-		WPA_KEY_INFO_SECURE;
-	WPA_PUT_BE16(reply->key_info, key_info);
-	WPA_PUT_BE16(reply->key_length, 0);
-	os_memcpy(reply->replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-
-	os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
-
-	WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
-	pos = (u8 *) (reply + 1);
-
-	/* Peer RSN IE */
-	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
-
-	/* Initiator MAC Address KDE */
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
-
-	/* Initiator Nonce */
-	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
-
-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m2(
-	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
-{
-	struct wpa_peerkey *peerkey;
-	struct wpa_eapol_ie_parse kde;
-	struct wpa_ie_data ie;
-	int cipher;
-	struct rsn_ie_hdr *hdr;
-	u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
-
-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
-		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
-			   "the current network");
-		return -1;
-	}
-
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
-		return -1;
-	}
-
-	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
-	    kde.mac_addr_len < ETH_ALEN) {
-		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
-			   "SMK M2");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
-		   MAC2STR(kde.mac_addr));
-
-	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
-		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
-			   "M2");
-		return -1;
-	}
-
-	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
-		return -1;
-	}
-
-	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
-	if (cipher & WPA_CIPHER_CCMP) {
-		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
-		cipher = WPA_CIPHER_CCMP;
-	} else if (cipher & WPA_CIPHER_TKIP) {
-		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
-		cipher = WPA_CIPHER_TKIP;
-	} else {
-		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
-		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
-					      STK_MUI_SMK, STK_ERR_CPHR_NS,
-					      ver);
-		return -1;
-	}
-
-	/* TODO: find existing entry and if found, use that instead of adding
-	 * a new one; how to handle the case where both ends initiate at the
-	 * same time? */
-	peerkey = os_zalloc(sizeof(*peerkey));
-	if (peerkey == NULL)
-		return -1;
-	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
-	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
-	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
-	peerkey->rsnie_i_len = kde.rsn_ie_len;
-	peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
-	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			   WPA_KEY_MGMT_PSK_SHA256))
-		peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
-
-	if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"WPA: Failed to get random data for PNonce");
-		wpa_supplicant_peerkey_free(sm, peerkey);
-		return -1;
-	}
-
-	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
-	hdr->elem_id = WLAN_EID_RSN;
-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
-	pos = (u8 *) (hdr + 1);
-	/* Group Suite can be anything for SMK RSN IE; receiver will just
-	 * ignore it. */
-	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	pos += RSN_SELECTOR_LEN;
-	/* Include only the selected cipher in pairwise cipher suite */
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-	if (cipher == WPA_CIPHER_CCMP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	else if (cipher == WPA_CIPHER_TKIP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	pos += RSN_SELECTOR_LEN;
-
-	hdr->len = (pos - peerkey->rsnie_p) - 2;
-	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
-	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
-		    peerkey->rsnie_p, peerkey->rsnie_p_len);
-
-	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
-
-	peerkey->next = sm->peerkey;
-	sm->peerkey = peerkey;
-
-	return 0;
-}
-
-
-/**
- * rsn_smkid - Derive SMK identifier
- * @smk: Station master key (32 bytes)
- * @pnonce: Peer Nonce
- * @mac_p: Peer MAC address
- * @inonce: Initiator Nonce
- * @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
- *
- * 8.5.1.4 Station to station (STK) key hierarchy
- * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
- */
-static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
-		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
-		      int use_sha256)
-{
-	char *title = "SMK Name";
-	const u8 *addr[5];
-	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
-				ETH_ALEN };
-	unsigned char hash[SHA256_MAC_LEN];
-
-	addr[0] = (u8 *) title;
-	addr[1] = pnonce;
-	addr[2] = mac_p;
-	addr[3] = inonce;
-	addr[4] = mac_i;
-
-#ifdef CONFIG_IEEE80211W
-	if (use_sha256)
-		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
-	else
-#endif /* CONFIG_IEEE80211W */
-		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
-	os_memcpy(smkid, hash, PMKID_LEN);
-}
-
-
-static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
-					   struct wpa_peerkey *peerkey)
-{
-	size_t mlen;
-	struct wpa_eapol_key *msg;
-	u8 *mbuf;
-	size_t kde_len;
-	u16 key_info, ver;
-
-	kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
-
-	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*msg) + kde_len, &mlen,
-				  (void *) &msg);
-	if (mbuf == NULL)
-		return;
-
-	msg->type = EAPOL_KEY_TYPE_RSN;
-
-	if (peerkey->cipher == WPA_CIPHER_CCMP)
-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
-	WPA_PUT_BE16(msg->key_info, key_info);
-
-	if (peerkey->cipher == WPA_CIPHER_CCMP)
-		WPA_PUT_BE16(msg->key_length, 16);
-	else
-		WPA_PUT_BE16(msg->key_length, 32);
-
-	os_memcpy(msg->replay_counter, peerkey->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(msg->key_data_length, kde_len);
-	wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
-		    peerkey->smkid, PMKID_LEN);
-
-	if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"RSN: Failed to get random data for INonce (STK)");
-		os_free(mbuf);
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
-		    peerkey->inonce, WPA_NONCE_LEN);
-	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
-
-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
-		   MAC2STR(peerkey->addr));
-	wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
-			   mbuf, mlen, NULL);
-}
-
-
-static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
-					   struct wpa_peerkey *peerkey)
-{
-	size_t mlen;
-	struct wpa_eapol_key *msg;
-	u8 *mbuf, *pos;
-	size_t kde_len;
-	u16 key_info, ver;
-	be32 lifetime;
-
-	kde_len = peerkey->rsnie_i_len +
-		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
-
-	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*msg) + kde_len, &mlen,
-				  (void *) &msg);
-	if (mbuf == NULL)
-		return;
-
-	msg->type = EAPOL_KEY_TYPE_RSN;
-
-	if (peerkey->cipher == WPA_CIPHER_CCMP)
-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
-		WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
-	WPA_PUT_BE16(msg->key_info, key_info);
-
-	if (peerkey->cipher == WPA_CIPHER_CCMP)
-		WPA_PUT_BE16(msg->key_length, 16);
-	else
-		WPA_PUT_BE16(msg->key_length, 32);
-
-	os_memcpy(msg->replay_counter, peerkey->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(msg->key_data_length, kde_len);
-	pos = (u8 *) (msg + 1);
-	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
-	lifetime = host_to_be32(peerkey->lifetime);
-	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
-		    (u8 *) &lifetime, sizeof(lifetime));
-
-	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
-
-	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
-		   MAC2STR(peerkey->addr));
-	wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
-			   ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
-}
-
-
-static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
-					 struct wpa_eapol_ie_parse *kde)
-{
-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
-		   MAC2STR(kde->mac_addr));
-
-	if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
-	{
-		wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
-			   "match with the one used in SMK M3");
-		return -1;
-	}
-
-	if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
-			   "match with the one received in SMK M2");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
-					 const unsigned char *src_addr,
-					 const struct wpa_eapol_key *key,
-					 int ver,
-					 struct wpa_peerkey *peerkey,
-					 struct wpa_eapol_ie_parse *kde)
-{
-	int cipher;
-	struct wpa_ie_data ie;
-
-	wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
-		   MAC2STR(kde->mac_addr));
-	if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
-	    wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
-		wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
-		/* TODO: abort negotiation */
-		return -1;
-	}
-
-	if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
-			   "not match with INonce used in SMK M1");
-		return -1;
-	}
-
-	if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
-	{
-		wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
-			   "match with the one used in SMK M1");
-		return -1;
-	}
-
-	os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
-	peerkey->rsnie_p_len = kde->rsn_ie_len;
-	os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
-
-	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
-	if (cipher & WPA_CIPHER_CCMP) {
-		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
-		peerkey->cipher = WPA_CIPHER_CCMP;
-	} else if (cipher & WPA_CIPHER_TKIP) {
-		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
-		peerkey->cipher = WPA_CIPHER_TKIP;
-	} else {
-		wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
-			   "unacceptable cipher", MAC2STR(kde->mac_addr));
-		wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
-					      STK_MUI_SMK, STK_ERR_CPHR_NS,
-					      ver);
-		/* TODO: abort negotiation */
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_process_smk_m45(
-	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len, int ver)
-{
-	struct wpa_peerkey *peerkey;
-	struct wpa_eapol_ie_parse kde;
-	u32 lifetime;
-	struct os_time now;
-
-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
-			   "the current network");
-		return -1;
-	}
-
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
-		return -1;
-	}
-
-	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
-	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
-	    kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
-	    kde.lifetime == NULL || kde.lifetime_len < 4) {
-		wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
-			   "Lifetime KDE in SMK M4/M5");
-		return -1;
-	}
-
-	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
-		if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
-		    os_memcmp(peerkey->initiator ? peerkey->inonce :
-			   peerkey->pnonce,
-			   key->key_nonce, WPA_NONCE_LEN) == 0)
-			break;
-	}
-	if (peerkey == NULL) {
-		wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
-			   "for SMK M4/M5: peer " MACSTR,
-			   MAC2STR(kde.mac_addr));
-		return -1;
-	}
-
-	if (peerkey->initiator) {
-		if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
-						  peerkey, &kde) < 0)
-			return -1;
-	} else {
-		if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
-			return -1;
-	}
-
-	os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
-	peerkey->smk_complete = 1;
-	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
-	lifetime = WPA_GET_BE32(kde.lifetime);
-	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
-	if (lifetime > 1000000000)
-		lifetime = 1000000000; /* avoid overflowing expiration time */
-	peerkey->lifetime = lifetime;
-	os_get_time(&now);
-	peerkey->expiration = now.sec + lifetime;
-	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
-			       sm, peerkey);
-
-	if (peerkey->initiator) {
-		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
-			  peerkey->inonce, sm->own_addr, peerkey->smkid,
-			  peerkey->use_sha256);
-		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
-	} else {
-		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
-			  peerkey->inonce, peerkey->addr, peerkey->smkid,
-			  peerkey->use_sha256);
-	}
-	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_process_smk_error(
-	struct wpa_sm *sm, const unsigned char *src_addr,
-	const struct wpa_eapol_key *key, size_t extra_len)
-{
-	struct wpa_eapol_ie_parse kde;
-	struct rsn_error_kde error;
-	u8 peer[ETH_ALEN];
-	u16 error_type;
-
-	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
-
-	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
-		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
-			   "the current network");
-		return -1;
-	}
-
-	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
-	    0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
-		return -1;
-	}
-
-	if (kde.error == NULL || kde.error_len < sizeof(error)) {
-		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
-		return -1;
-	}
-
-	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
-		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
-	else
-		os_memset(peer, 0, ETH_ALEN);
-	os_memcpy(&error, kde.error, sizeof(error));
-	error_type = be_to_host16(error.error_type);
-	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
-		MACSTR,
-		be_to_host16(error.mui), error_type,
-		MAC2STR(peer));
-
-	if (kde.mac_addr &&
-	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
-	     error_type == STK_ERR_CPHR_NS)) {
-		struct wpa_peerkey *peerkey;
-
-		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
-			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
-			    0)
-				break;
-		}
-		if (peerkey == NULL) {
-			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
-				   "found for SMK Error");
-			return -1;
-		}
-		/* TODO: abort SMK/STK handshake and remove all related keys */
-	}
-
-	return 0;
-}
-
-
-static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
-					      struct wpa_peerkey *peerkey,
-					      const struct wpa_eapol_key *key,
-					      u16 ver)
-{
-	struct wpa_eapol_ie_parse ie;
-	const u8 *kde;
-	size_t len, kde_buf_len;
-	struct wpa_ptk *stk;
-	u8 buf[8], *kde_buf, *pos;
-	be32 lifetime;
-
-	wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
-	os_memset(&ie, 0, sizeof(ie));
-
-	/* RSN: msg 1/4 should contain SMKID for the selected SMK */
-	kde = (const u8 *) (key + 1);
-	len = WPA_GET_BE16(key->key_data_length);
-	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
-	if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
-		return;
-	}
-	if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
-		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
-			    ie.pmkid, PMKID_LEN);
-		return;
-	}
-
-	if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"RSN: Failed to get random data for PNonce");
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
-		    peerkey->pnonce, WPA_NONCE_LEN);
-
-	/* Calculate STK which will be stored as a temporary STK until it has
-	 * been verified when processing message 3/4. */
-	stk = &peerkey->tstk;
-	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
-		       sm->own_addr, peerkey->addr,
-		       peerkey->pnonce, key->key_nonce,
-		       (u8 *) stk, sizeof(*stk),
-		       peerkey->use_sha256);
-	/* Supplicant: swap tx/rx Mic keys */
-	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
-	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
-	os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
-	peerkey->tstk_set = 1;
-
-	kde_buf_len = peerkey->rsnie_p_len +
-		2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
-		2 + RSN_SELECTOR_LEN + PMKID_LEN;
-	kde_buf = os_malloc(kde_buf_len);
-	if (kde_buf == NULL)
-		return;
-	pos = kde_buf;
-	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
-	lifetime = host_to_be32(peerkey->lifetime);
-	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
-			  (u8 *) &lifetime, sizeof(lifetime));
-	wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
-
-	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
-				       peerkey->pnonce, kde_buf, kde_buf_len,
-				       stk)) {
-		os_free(kde_buf);
-		return;
-	}
-	os_free(kde_buf);
-
-	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
-}
-
-
-static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
-					       struct wpa_peerkey *peerkey,
-					       struct wpa_eapol_ie_parse *kde)
-{
-	u32 lifetime;
-	struct os_time now;
-
-	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
-		return;
-
-	lifetime = WPA_GET_BE32(kde->lifetime);
-
-	if (lifetime >= peerkey->lifetime) {
-		wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
-			   "which is larger than or equal to own value %u "
-			   "seconds - ignored", lifetime, peerkey->lifetime);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
-		   "(own was %u seconds) - updated",
-		   lifetime, peerkey->lifetime);
-	peerkey->lifetime = lifetime;
-
-	os_get_time(&now);
-	peerkey->expiration = now.sec + lifetime;
-	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
-	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
-			       sm, peerkey);
-}
-
-
-static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
-					      struct wpa_peerkey *peerkey,
-					      const struct wpa_eapol_key *key,
-					      u16 ver)
-{
-	struct wpa_eapol_ie_parse kde;
-	const u8 *keydata;
-	size_t len;
-
-	wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
-	os_memset(&kde, 0, sizeof(kde));
-
-	/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
-	 * from the peer. It may also include Lifetime KDE. */
-	keydata = (const u8 *) (key + 1);
-	len = WPA_GET_BE16(key->key_data_length);
-	wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
-	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
-	    kde.pmkid == NULL || kde.rsn_ie == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
-		return;
-	}
-
-	if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
-		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
-			    kde.pmkid, PMKID_LEN);
-		return;
-	}
-
-	if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
-	    os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
-		wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
-			   "handshakes did not match");
-		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
-			    peerkey->rsnie_p, peerkey->rsnie_p_len);
-		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
-			    kde.rsn_ie, kde.rsn_ie_len);
-		return;
-	}
-
-	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
-
-	wpa_supplicant_send_stk_3_of_4(sm, peerkey);
-	os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
-}
-
-
-static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
-					      struct wpa_peerkey *peerkey,
-					      const struct wpa_eapol_key *key,
-					      u16 ver)
-{
-	struct wpa_eapol_ie_parse kde;
-	const u8 *keydata;
-	size_t len, key_len;
-	const u8 *_key;
-	u8 key_buf[32], rsc[6];
-
-	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
-	os_memset(&kde, 0, sizeof(kde));
-
-	/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
-	 * Lifetime KDE. */
-	keydata = (const u8 *) (key + 1);
-	len = WPA_GET_BE16(key->key_data_length);
-	wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
-	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
-		wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
-			   "STK 3/4");
-		return;
-	}
-
-	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
-	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
-		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
-			   "handshakes did not match");
-		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
-			    "handshake",
-			    peerkey->rsnie_i, peerkey->rsnie_i_len);
-		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
-			    "handshake",
-			    kde.rsn_ie, kde.rsn_ie_len);
-		return;
-	}
-
-	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
-			   "4-Way Handshake differs from 3 of STK 4-Way "
-			   "Handshake - drop packet (src=" MACSTR ")",
-			   MAC2STR(peerkey->addr));
-		return;
-	}
-
-	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
-
-	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
-				       WPA_GET_BE16(key->key_info),
-				       NULL, 0, &peerkey->stk))
-		return;
-
-	_key = (u8 *) peerkey->stk.tk1;
-	if (peerkey->cipher == WPA_CIPHER_TKIP) {
-		/* Swap Tx/Rx keys for Michael MIC */
-		os_memcpy(key_buf, _key, 16);
-		os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
-		os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
-		_key = key_buf;
-		key_len = 32;
-	} else
-		key_len = 16;
-
-	os_memset(rsc, 0, 6);
-	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
-			   rsc, sizeof(rsc), _key, key_len) < 0) {
-		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
-			   "driver.");
-		return;
-	}
-}
-
-
-static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
-					      struct wpa_peerkey *peerkey,
-					      const struct wpa_eapol_key *key,
-					      u16 ver)
-{
-	u8 rsc[6];
-
-	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
-
-	os_memset(rsc, 0, 6);
-	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
-			   rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
-			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
-		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
-			   "driver.");
-		return;
-	}
-}
-
-
-/**
- * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @peerkey: Pointer to the PeerKey data for the peer
- * @key: Pointer to the EAPOL-Key frame header
- * @ver: Version bits from EAPOL-Key Key Info
- * @buf: Pointer to the beginning of EAPOL-Key frame
- * @len: Length of the EAPOL-Key frame
- * Returns: 0 on success, -1 on failure
- */
-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
-				 struct wpa_peerkey *peerkey,
-				 struct wpa_eapol_key *key, u16 ver,
-				 const u8 *buf, size_t len)
-{
-	u8 mic[16];
-	int ok = 0;
-
-	if (peerkey->initiator && !peerkey->stk_set) {
-		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
-			       sm->own_addr, peerkey->addr,
-			       peerkey->inonce, key->key_nonce,
-			       (u8 *) &peerkey->stk, sizeof(peerkey->stk),
-			       peerkey->use_sha256);
-		peerkey->stk_set = 1;
-	}
-
-	os_memcpy(mic, key->key_mic, 16);
-	if (peerkey->tstk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
-				   "when using TSTK - ignoring TSTK");
-		} else {
-			ok = 1;
-			peerkey->tstk_set = 0;
-			peerkey->stk_set = 1;
-			os_memcpy(&peerkey->stk, &peerkey->tstk,
-				  sizeof(peerkey->stk));
-		}
-	}
-
-	if (!ok && peerkey->stk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
-				   "- dropping packet");
-			return -1;
-		}
-		ok = 1;
-	}
-
-	if (!ok) {
-		wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
-			   "- dropping packet");
-		return -1;
-	}
-
-	os_memcpy(peerkey->replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	peerkey->replay_counter_set = 1;
-	return 0;
-}
-
-
-/**
- * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @peer: MAC address of the peer STA
- * Returns: 0 on success, or -1 on failure
- *
- * Send an EAPOL-Key Request to the current authenticator to start STK
- * handshake with the peer.
- */
-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
-{
-	size_t rlen, kde_len;
-	struct wpa_eapol_key *req;
-	int key_info, ver;
-	u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
-	u16 count;
-	struct rsn_ie_hdr *hdr;
-	struct wpa_peerkey *peerkey;
-	struct wpa_ie_data ie;
-
-	if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
-		return -1;
-
-	if (sm->ap_rsn_ie &&
-	    wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
-	    !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
-		wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
-		return -1;
-	}
-
-	if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	if (wpa_sm_get_bssid(sm, bssid) < 0) {
-		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
-			   "SMK M1");
-		return -1;
-	}
-
-	/* TODO: find existing entry and if found, use that instead of adding
-	 * a new one */
-	peerkey = os_zalloc(sizeof(*peerkey));
-	if (peerkey == NULL)
-		return -1;
-	peerkey->initiator = 1;
-	os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
-	if (wpa_key_mgmt_sha256(sm->key_mgmt))
-		peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
-
-	/* SMK M1:
-	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
-	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
-	 */
-
-	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
-	hdr->elem_id = WLAN_EID_RSN;
-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
-	pos = (u8 *) (hdr + 1);
-	/* Group Suite can be anything for SMK RSN IE; receiver will just
-	 * ignore it. */
-	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	pos += RSN_SELECTOR_LEN;
-	count_pos = pos;
-	pos += 2;
-
-	count = 0;
-	if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-		pos += RSN_SELECTOR_LEN;
-		count++;
-	}
-	if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-		pos += RSN_SELECTOR_LEN;
-		count++;
-	}
-	WPA_PUT_LE16(count_pos, count);
-
-	hdr->len = (pos - peerkey->rsnie_i) - 2;
-	peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
-	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
-		    peerkey->rsnie_i, peerkey->rsnie_i_len);
-
-	kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*req) + kde_len, &rlen,
-				  (void *) &req);
-	if (rbuf == NULL) {
-		wpa_supplicant_peerkey_free(sm, peerkey);
-		return -1;
-	}
-
-	req->type = EAPOL_KEY_TYPE_RSN;
-	key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
-		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
-	WPA_PUT_BE16(req->key_info, key_info);
-	WPA_PUT_BE16(req->key_length, 0);
-	os_memcpy(req->replay_counter, sm->request_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
-
-	if (os_get_random(peerkey->inonce, WPA_NONCE_LEN)) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-			"WPA: Failed to get random data for INonce");
-		os_free(rbuf);
-		wpa_supplicant_peerkey_free(sm, peerkey);
-		return -1;
-	}
-	os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
-		    req->key_nonce, WPA_NONCE_LEN);
-
-	WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
-	pos = (u8 *) (req + 1);
-
-	/* Initiator RSN IE */
-	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
-	/* Peer MAC address KDE */
-	wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
-
-	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
-		   MACSTR ")", MAC2STR(peer));
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
-			   rbuf, rlen, req->key_mic);
-
-	peerkey->next = sm->peerkey;
-	sm->peerkey = peerkey;
-
-	return 0;
-}
-
-
-/**
- * peerkey_deinit - Free PeerKey values
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void peerkey_deinit(struct wpa_sm *sm)
-{
-	struct wpa_peerkey *prev, *peerkey = sm->peerkey;
-	while (peerkey) {
-		prev = peerkey;
-		peerkey = peerkey->next;
-		os_free(prev);
-	}
-}
-
-
-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
-			   struct wpa_eapol_key *key, u16 key_info, u16 ver)
-{
-	if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
-	    (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
-		/* 3/4 STK 4-Way Handshake */
-		wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
-	} else if (key_info & WPA_KEY_INFO_ACK) {
-		/* 1/4 STK 4-Way Handshake */
-		wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
-	} else if (key_info & WPA_KEY_INFO_SECURE) {
-		/* 4/4 STK 4-Way Handshake */
-		wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
-	} else {
-		/* 2/4 STK 4-Way Handshake */
-		wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
-	}
-}
-
-
-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-			  struct wpa_eapol_key *key, size_t extra_len,
-			  u16 key_info, u16 ver)
-{
-	if (key_info & WPA_KEY_INFO_ERROR) {
-		/* SMK Error */
-		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
-	} else if (key_info & WPA_KEY_INFO_ACK) {
-		/* SMK M2 */
-		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
-					      ver);
-	} else {
-		/* SMK M4 or M5 */
-		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
-					       ver);
-	}
-}
-
-#endif /* CONFIG_PEERKEY */

Copied: vendor/wpa/2.0/src/rsn_supp/peerkey.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/peerkey.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/peerkey.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/peerkey.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1174 @@
+/*
+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_PEERKEY
+
+#include "common.h"
+#include "eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+#include "peerkey.h"
+
+
+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
+{
+	os_memcpy(pos, ie, ie_len);
+	return pos + ie_len;
+}
+
+
+static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
+{
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = RSN_SELECTOR_LEN + data_len;
+	RSN_SELECTOR_PUT(pos, kde);
+	pos += RSN_SELECTOR_LEN;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	return pos;
+}
+
+
+static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+	struct wpa_sm *sm = eloop_ctx;
+	struct wpa_peerkey *peerkey = timeout_ctx;
+#endif
+	/* TODO: time out SMK and any STK that was generated using this SMK */
+}
+
+
+static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
+					struct wpa_peerkey *peerkey)
+{
+	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+	os_free(peerkey);
+}
+
+
+static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
+					 const u8 *peer,
+					 u16 mui, u16 error_type, int ver)
+{
+	size_t rlen;
+	struct wpa_eapol_key *err;
+	struct rsn_error_kde error;
+	u8 *rbuf, *pos;
+	size_t kde_len;
+	u16 key_info;
+
+	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
+	if (peer)
+		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*err) + kde_len, &rlen,
+				  (void *) &err);
+	if (rbuf == NULL)
+		return -1;
+
+	err->type = EAPOL_KEY_TYPE_RSN;
+	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
+		WPA_KEY_INFO_REQUEST;
+	WPA_PUT_BE16(err->key_info, key_info);
+	WPA_PUT_BE16(err->key_length, 0);
+	os_memcpy(err->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
+	pos = (u8 *) (err + 1);
+
+	if (peer) {
+		/* Peer MAC Address KDE */
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+	}
+
+	/* Error KDE */
+	error.mui = host_to_be16(mui);
+	error.error_type = host_to_be16(error_type);
+	wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
+
+	if (peer) {
+		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
+			   MACSTR " mui %d error_type %d)",
+			   MAC2STR(peer), mui, error_type);
+	} else {
+		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
+			   "(mui %d error_type %d)", mui, error_type);
+	}
+
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, err->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
+				      const unsigned char *src_addr,
+				      const struct wpa_eapol_key *key,
+				      int ver, struct wpa_peerkey *peerkey)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf, *pos;
+	size_t kde_len;
+	u16 key_info;
+
+	/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
+	kde_len = peerkey->rsnie_p_len +
+		2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*reply) + kde_len, &rlen,
+				  (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = EAPOL_KEY_TYPE_RSN;
+	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	WPA_PUT_BE16(reply->key_length, 0);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
+	pos = (u8 *) (reply + 1);
+
+	/* Peer RSN IE */
+	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+	/* Initiator MAC Address KDE */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
+
+	/* Initiator Nonce */
+	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m2(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+	struct wpa_peerkey *peerkey;
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_ie_data ie;
+	int cipher;
+	struct rsn_ie_hdr *hdr;
+	u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
+		return -1;
+	}
+
+	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+	    kde.mac_addr_len < ETH_ALEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+			   "SMK M2");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
+		   MAC2STR(kde.mac_addr));
+
+	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
+		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
+			   "M2");
+		return -1;
+	}
+
+	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
+		return -1;
+	}
+
+	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
+	if (cipher & WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+		cipher = WPA_CIPHER_CCMP;
+	} else if (cipher & WPA_CIPHER_GCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+		cipher = WPA_CIPHER_GCMP;
+	} else if (cipher & WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+		cipher = WPA_CIPHER_TKIP;
+	} else {
+		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
+		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
+					      STK_MUI_SMK, STK_ERR_CPHR_NS,
+					      ver);
+		return -1;
+	}
+
+	/* TODO: find existing entry and if found, use that instead of adding
+	 * a new one; how to handle the case where both ends initiate at the
+	 * same time? */
+	peerkey = os_zalloc(sizeof(*peerkey));
+	if (peerkey == NULL)
+		return -1;
+	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
+	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
+	peerkey->rsnie_i_len = kde.rsn_ie_len;
+	peerkey->cipher = cipher;
+#ifdef CONFIG_IEEE80211W
+	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			   WPA_KEY_MGMT_PSK_SHA256))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
+
+	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to get random data for PNonce");
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+
+	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+	/* Group Suite can be anything for SMK RSN IE; receiver will just
+	 * ignore it. */
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+	/* Include only the selected cipher in pairwise cipher suite */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	hdr->len = (pos - peerkey->rsnie_p) - 2;
+	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
+	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+		    peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
+
+	peerkey->next = sm->peerkey;
+	sm->peerkey = peerkey;
+
+	return 0;
+}
+
+
+/**
+ * rsn_smkid - Derive SMK identifier
+ * @smk: Station master key (32 bytes)
+ * @pnonce: Peer Nonce
+ * @mac_p: Peer MAC address
+ * @inonce: Initiator Nonce
+ * @mac_i: Initiator MAC address
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * 8.5.1.4 Station to station (STK) key hierarchy
+ * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
+ */
+static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
+		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
+		      int use_sha256)
+{
+	char *title = "SMK Name";
+	const u8 *addr[5];
+	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
+				ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = pnonce;
+	addr[2] = mac_p;
+	addr[3] = inonce;
+	addr[4] = mac_i;
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
+	os_memcpy(smkid, hash, PMKID_LEN);
+}
+
+
+static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
+					   struct wpa_peerkey *peerkey)
+{
+	size_t mlen;
+	struct wpa_eapol_key *msg;
+	u8 *mbuf;
+	size_t kde_len;
+	u16 key_info, ver;
+
+	kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+
+	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*msg) + kde_len, &mlen,
+				  (void *) &msg);
+	if (mbuf == NULL)
+		return;
+
+	msg->type = EAPOL_KEY_TYPE_RSN;
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
+	WPA_PUT_BE16(msg->key_info, key_info);
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		WPA_PUT_BE16(msg->key_length, 16);
+	else
+		WPA_PUT_BE16(msg->key_length, 32);
+
+	os_memcpy(msg->replay_counter, peerkey->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(msg->key_data_length, kde_len);
+	wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
+		    peerkey->smkid, PMKID_LEN);
+
+	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"RSN: Failed to get random data for INonce (STK)");
+		os_free(mbuf);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
+		    peerkey->inonce, WPA_NONCE_LEN);
+	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
+		   MAC2STR(peerkey->addr));
+	wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+			   mbuf, mlen, NULL);
+}
+
+
+static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
+					   struct wpa_peerkey *peerkey)
+{
+	size_t mlen;
+	struct wpa_eapol_key *msg;
+	u8 *mbuf, *pos;
+	size_t kde_len;
+	u16 key_info, ver;
+	be32 lifetime;
+
+	kde_len = peerkey->rsnie_i_len +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+
+	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*msg) + kde_len, &mlen,
+				  (void *) &msg);
+	if (mbuf == NULL)
+		return;
+
+	msg->type = EAPOL_KEY_TYPE_RSN;
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
+		WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(msg->key_info, key_info);
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		WPA_PUT_BE16(msg->key_length, 16);
+	else
+		WPA_PUT_BE16(msg->key_length, 32);
+
+	os_memcpy(msg->replay_counter, peerkey->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(msg->key_data_length, kde_len);
+	pos = (u8 *) (msg + 1);
+	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+	lifetime = host_to_be32(peerkey->lifetime);
+	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+		    (u8 *) &lifetime, sizeof(lifetime));
+
+	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
+		   MAC2STR(peerkey->addr));
+	wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
+			   ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+}
+
+
+static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
+					 struct wpa_eapol_ie_parse *kde)
+{
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
+		   MAC2STR(kde->mac_addr));
+
+	if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
+			   "match with the one used in SMK M3");
+		return -1;
+	}
+
+	if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
+			   "match with the one received in SMK M2");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
+					 const unsigned char *src_addr,
+					 const struct wpa_eapol_key *key,
+					 int ver,
+					 struct wpa_peerkey *peerkey,
+					 struct wpa_eapol_ie_parse *kde)
+{
+	int cipher;
+	struct wpa_ie_data ie;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
+		   MAC2STR(kde->mac_addr));
+	if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
+	    wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
+		/* TODO: abort negotiation */
+		return -1;
+	}
+
+	if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
+			   "not match with INonce used in SMK M1");
+		return -1;
+	}
+
+	if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
+			   "match with the one used in SMK M1");
+		return -1;
+	}
+
+	os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
+	peerkey->rsnie_p_len = kde->rsn_ie_len;
+	os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
+
+	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
+	if (cipher & WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_CCMP;
+	} else if (cipher & WPA_CIPHER_GCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_GCMP;
+	} else if (cipher & WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_TKIP;
+	} else {
+		wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
+			   "unacceptable cipher", MAC2STR(kde->mac_addr));
+		wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
+					      STK_MUI_SMK, STK_ERR_CPHR_NS,
+					      ver);
+		/* TODO: abort negotiation */
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m45(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+	struct wpa_peerkey *peerkey;
+	struct wpa_eapol_ie_parse kde;
+	u32 lifetime;
+	struct os_time now;
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
+		return -1;
+	}
+
+	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
+	    kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
+	    kde.lifetime == NULL || kde.lifetime_len < 4) {
+		wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
+			   "Lifetime KDE in SMK M4/M5");
+		return -1;
+	}
+
+	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+		if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
+		    os_memcmp(peerkey->initiator ? peerkey->inonce :
+			   peerkey->pnonce,
+			   key->key_nonce, WPA_NONCE_LEN) == 0)
+			break;
+	}
+	if (peerkey == NULL) {
+		wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
+			   "for SMK M4/M5: peer " MACSTR,
+			   MAC2STR(kde.mac_addr));
+		return -1;
+	}
+
+	if (peerkey->initiator) {
+		if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
+						  peerkey, &kde) < 0)
+			return -1;
+	} else {
+		if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
+			return -1;
+	}
+
+	os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
+	peerkey->smk_complete = 1;
+	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
+	lifetime = WPA_GET_BE32(kde.lifetime);
+	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
+	if (lifetime > 1000000000)
+		lifetime = 1000000000; /* avoid overflowing expiration time */
+	peerkey->lifetime = lifetime;
+	os_get_time(&now);
+	peerkey->expiration = now.sec + lifetime;
+	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+			       sm, peerkey);
+
+	if (peerkey->initiator) {
+		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
+			  peerkey->inonce, sm->own_addr, peerkey->smkid,
+			  peerkey->use_sha256);
+		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
+	} else {
+		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
+			  peerkey->inonce, peerkey->addr, peerkey->smkid,
+			  peerkey->use_sha256);
+	}
+	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_error(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct rsn_error_kde error;
+	u8 peer[ETH_ALEN];
+	u16 error_type;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+		return -1;
+	}
+
+	if (kde.error == NULL || kde.error_len < sizeof(error)) {
+		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
+		return -1;
+	}
+
+	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
+		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
+	else
+		os_memset(peer, 0, ETH_ALEN);
+	os_memcpy(&error, kde.error, sizeof(error));
+	error_type = be_to_host16(error.error_type);
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
+		MACSTR,
+		be_to_host16(error.mui), error_type,
+		MAC2STR(peer));
+
+	if (kde.mac_addr &&
+	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
+	     error_type == STK_ERR_CPHR_NS)) {
+		struct wpa_peerkey *peerkey;
+
+		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
+			    0)
+				break;
+		}
+		if (peerkey == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
+				   "found for SMK Error");
+			return -1;
+		}
+		/* TODO: abort SMK/STK handshake and remove all related keys */
+	}
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse ie;
+	const u8 *kde;
+	size_t len, kde_buf_len;
+	struct wpa_ptk *stk;
+	u8 buf[8], *kde_buf, *pos;
+	be32 lifetime;
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&ie, 0, sizeof(ie));
+
+	/* RSN: msg 1/4 should contain SMKID for the selected SMK */
+	kde = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
+	if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
+		return;
+	}
+	if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
+			    ie.pmkid, PMKID_LEN);
+		return;
+	}
+
+	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"RSN: Failed to get random data for PNonce");
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
+		    peerkey->pnonce, WPA_NONCE_LEN);
+
+	/* Calculate STK which will be stored as a temporary STK until it has
+	 * been verified when processing message 3/4. */
+	stk = &peerkey->tstk;
+	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+		       sm->own_addr, peerkey->addr,
+		       peerkey->pnonce, key->key_nonce,
+		       (u8 *) stk, sizeof(*stk),
+		       peerkey->use_sha256);
+	/* Supplicant: swap tx/rx Mic keys */
+	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
+	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
+	os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+	peerkey->tstk_set = 1;
+
+	kde_buf_len = peerkey->rsnie_p_len +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
+		2 + RSN_SELECTOR_LEN + PMKID_LEN;
+	kde_buf = os_malloc(kde_buf_len);
+	if (kde_buf == NULL)
+		return;
+	pos = kde_buf;
+	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+	lifetime = host_to_be32(peerkey->lifetime);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime));
+	wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
+
+	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
+				       peerkey->pnonce, kde_buf, kde_buf_len,
+				       stk)) {
+		os_free(kde_buf);
+		return;
+	}
+	os_free(kde_buf);
+
+	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
+					       struct wpa_peerkey *peerkey,
+					       struct wpa_eapol_ie_parse *kde)
+{
+	u32 lifetime;
+	struct os_time now;
+
+	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
+		return;
+
+	lifetime = WPA_GET_BE32(kde->lifetime);
+
+	if (lifetime >= peerkey->lifetime) {
+		wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
+			   "which is larger than or equal to own value %u "
+			   "seconds - ignored", lifetime, peerkey->lifetime);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
+		   "(own was %u seconds) - updated",
+		   lifetime, peerkey->lifetime);
+	peerkey->lifetime = lifetime;
+
+	os_get_time(&now);
+	peerkey->expiration = now.sec + lifetime;
+	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+			       sm, peerkey);
+}
+
+
+static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse kde;
+	const u8 *keydata;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&kde, 0, sizeof(kde));
+
+	/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
+	 * from the peer. It may also include Lifetime KDE. */
+	keydata = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
+	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+	    kde.pmkid == NULL || kde.rsn_ie == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
+		return;
+	}
+
+	if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
+			    kde.pmkid, PMKID_LEN);
+		return;
+	}
+
+	if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
+	    os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
+			   "handshakes did not match");
+		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
+			    peerkey->rsnie_p, peerkey->rsnie_p_len);
+		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
+			    kde.rsn_ie, kde.rsn_ie_len);
+		return;
+	}
+
+	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+	wpa_supplicant_send_stk_3_of_4(sm, peerkey);
+	os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse kde;
+	const u8 *keydata;
+	size_t len, key_len;
+	const u8 *_key;
+	u8 key_buf[32], rsc[6];
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&kde, 0, sizeof(kde));
+
+	/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
+	 * Lifetime KDE. */
+	keydata = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
+	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+		wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
+			   "STK 3/4");
+		return;
+	}
+
+	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
+	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
+			   "handshakes did not match");
+		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
+			    "handshake",
+			    peerkey->rsnie_i, peerkey->rsnie_i_len);
+		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
+			    "handshake",
+			    kde.rsn_ie, kde.rsn_ie_len);
+		return;
+	}
+
+	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
+			   "4-Way Handshake differs from 3 of STK 4-Way "
+			   "Handshake - drop packet (src=" MACSTR ")",
+			   MAC2STR(peerkey->addr));
+		return;
+	}
+
+	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
+				       WPA_GET_BE16(key->key_info),
+				       NULL, 0, &peerkey->stk))
+		return;
+
+	_key = (u8 *) peerkey->stk.tk1;
+	if (peerkey->cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		os_memcpy(key_buf, _key, 16);
+		os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
+		os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+		_key = key_buf;
+		key_len = 32;
+	} else
+		key_len = 16;
+
+	os_memset(rsc, 0, 6);
+	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+			   rsc, sizeof(rsc), _key, key_len) < 0) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+			   "driver.");
+		return;
+	}
+}
+
+
+static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	u8 rsc[6];
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(rsc, 0, 6);
+	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+			   rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+			   "driver.");
+		return;
+	}
+}
+
+
+/**
+ * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peerkey: Pointer to the PeerKey data for the peer
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @buf: Pointer to the beginning of EAPOL-Key frame
+ * @len: Length of the EAPOL-Key frame
+ * Returns: 0 on success, -1 on failure
+ */
+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+				 struct wpa_peerkey *peerkey,
+				 struct wpa_eapol_key *key, u16 ver,
+				 const u8 *buf, size_t len)
+{
+	u8 mic[16];
+	int ok = 0;
+
+	if (peerkey->initiator && !peerkey->stk_set) {
+		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+			       sm->own_addr, peerkey->addr,
+			       peerkey->inonce, key->key_nonce,
+			       (u8 *) &peerkey->stk, sizeof(peerkey->stk),
+			       peerkey->use_sha256);
+		peerkey->stk_set = 1;
+	}
+
+	os_memcpy(mic, key->key_mic, 16);
+	if (peerkey->tstk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+				   "when using TSTK - ignoring TSTK");
+		} else {
+			ok = 1;
+			peerkey->tstk_set = 0;
+			peerkey->stk_set = 1;
+			os_memcpy(&peerkey->stk, &peerkey->tstk,
+				  sizeof(peerkey->stk));
+		}
+	}
+
+	if (!ok && peerkey->stk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+				   "- dropping packet");
+			return -1;
+		}
+		ok = 1;
+	}
+
+	if (!ok) {
+		wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
+			   "- dropping packet");
+		return -1;
+	}
+
+	os_memcpy(peerkey->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	peerkey->replay_counter_set = 1;
+	return 0;
+}
+
+
+/**
+ * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peer: MAC address of the peer STA
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Send an EAPOL-Key Request to the current authenticator to start STK
+ * handshake with the peer.
+ */
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+	size_t rlen, kde_len;
+	struct wpa_eapol_key *req;
+	int key_info, ver;
+	u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
+	u16 count;
+	struct rsn_ie_hdr *hdr;
+	struct wpa_peerkey *peerkey;
+	struct wpa_ie_data ie;
+
+	if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
+		return -1;
+
+	if (sm->ap_rsn_ie &&
+	    wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
+	    !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
+		wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
+		return -1;
+	}
+
+	if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	if (wpa_sm_get_bssid(sm, bssid) < 0) {
+		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
+			   "SMK M1");
+		return -1;
+	}
+
+	/* TODO: find existing entry and if found, use that instead of adding
+	 * a new one */
+	peerkey = os_zalloc(sizeof(*peerkey));
+	if (peerkey == NULL)
+		return -1;
+	peerkey->initiator = 1;
+	os_memcpy(peerkey->addr, peer, ETH_ALEN);
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
+
+	/* SMK M1:
+	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
+	 */
+
+	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+	/* Group Suite can be anything for SMK RSN IE; receiver will just
+	 * ignore it. */
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+	count_pos = pos;
+	pos += 2;
+
+	count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
+	pos += count * RSN_SELECTOR_LEN;
+	WPA_PUT_LE16(count_pos, count);
+
+	hdr->len = (pos - peerkey->rsnie_i) - 2;
+	peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
+	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+		    peerkey->rsnie_i, peerkey->rsnie_i_len);
+
+	kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*req) + kde_len, &rlen,
+				  (void *) &req);
+	if (rbuf == NULL) {
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+
+	req->type = EAPOL_KEY_TYPE_RSN;
+	key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
+	WPA_PUT_BE16(req->key_info, key_info);
+	WPA_PUT_BE16(req->key_length, 0);
+	os_memcpy(req->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to get random data for INonce");
+		os_free(rbuf);
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+	os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
+		    req->key_nonce, WPA_NONCE_LEN);
+
+	WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
+	pos = (u8 *) (req + 1);
+
+	/* Initiator RSN IE */
+	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+	/* Peer MAC address KDE */
+	wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+
+	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
+		   MACSTR ")", MAC2STR(peer));
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+			   rbuf, rlen, req->key_mic);
+
+	peerkey->next = sm->peerkey;
+	sm->peerkey = peerkey;
+
+	return 0;
+}
+
+
+/**
+ * peerkey_deinit - Free PeerKey values
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void peerkey_deinit(struct wpa_sm *sm)
+{
+	struct wpa_peerkey *prev, *peerkey = sm->peerkey;
+	while (peerkey) {
+		prev = peerkey;
+		peerkey = peerkey->next;
+		os_free(prev);
+	}
+	sm->peerkey = NULL;
+}
+
+
+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+			   struct wpa_eapol_key *key, u16 key_info, u16 ver)
+{
+	if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
+	    (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
+		/* 3/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
+	} else if (key_info & WPA_KEY_INFO_ACK) {
+		/* 1/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
+	} else if (key_info & WPA_KEY_INFO_SECURE) {
+		/* 4/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
+	} else {
+		/* 2/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
+	}
+}
+
+
+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+			  struct wpa_eapol_key *key, size_t extra_len,
+			  u16 key_info, u16 ver)
+{
+	if (key_info & WPA_KEY_INFO_ERROR) {
+		/* SMK Error */
+		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
+	} else if (key_info & WPA_KEY_INFO_ACK) {
+		/* SMK M2 */
+		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
+					      ver);
+	} else {
+		/* SMK M4 or M5 */
+		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
+					       ver);
+	}
+}
+
+#endif /* CONFIG_PEERKEY */

Deleted: vendor/wpa/2.0/src/rsn_supp/peerkey.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/peerkey.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/peerkey.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,87 +0,0 @@
-/*
- * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PEERKEY_H
-#define PEERKEY_H
-
-#define PEERKEY_MAX_IE_LEN 80
-struct wpa_peerkey {
-	struct wpa_peerkey *next;
-	int initiator; /* whether this end was initator for SMK handshake */
-	u8 addr[ETH_ALEN]; /* other end MAC address */
-	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
-	u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
-	u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
-	size_t rsnie_i_len;
-	u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
-	size_t rsnie_p_len;
-	u8 smk[PMK_LEN];
-	int smk_complete;
-	u8 smkid[PMKID_LEN];
-	u32 lifetime;
-	os_time_t expiration;
-	int cipher; /* Selected cipher (WPA_CIPHER_*) */
-	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
-	int replay_counter_set;
-	int use_sha256; /* whether AKMP indicate SHA256-based derivations */
-
-	struct wpa_ptk stk, tstk;
-	int stk_set, tstk_set;
-};
-
-
-#ifdef CONFIG_PEERKEY
-
-int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
-				 struct wpa_peerkey *peerkey,
-				 struct wpa_eapol_key *key, u16 ver,
-				 const u8 *buf, size_t len);
-void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
-			   struct wpa_eapol_key *key, u16 key_info, u16 ver);
-void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-			  struct wpa_eapol_key *key, size_t extra_len,
-			  u16 key_info, u16 ver);
-void peerkey_deinit(struct wpa_sm *sm);
-
-#else /* CONFIG_PEERKEY */
-
-static inline int
-peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
-			     struct wpa_peerkey *peerkey,
-			     struct wpa_eapol_key *key, u16 ver,
-			     const u8 *buf, size_t len)
-{
-	return -1;
-}
-
-static inline void
-peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
-		      struct wpa_eapol_key *key, u16 key_info, u16 ver)
-{
-}
-
-static inline void
-peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
-		     struct wpa_eapol_key *key, size_t extra_len,
-		     u16 key_info, u16 ver)
-{
-}
-
-static inline void peerkey_deinit(struct wpa_sm *sm)
-{
-}
-
-#endif /* CONFIG_PEERKEY */
-
-#endif /* PEERKEY_H */

Copied: vendor/wpa/2.0/src/rsn_supp/peerkey.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/peerkey.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/peerkey.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/peerkey.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,81 @@
+/*
+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PEERKEY_H
+#define PEERKEY_H
+
+#define PEERKEY_MAX_IE_LEN 80
+struct wpa_peerkey {
+	struct wpa_peerkey *next;
+	int initiator; /* whether this end was initator for SMK handshake */
+	u8 addr[ETH_ALEN]; /* other end MAC address */
+	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
+	u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
+	u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
+	size_t rsnie_i_len;
+	u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
+	size_t rsnie_p_len;
+	u8 smk[PMK_LEN];
+	int smk_complete;
+	u8 smkid[PMKID_LEN];
+	u32 lifetime;
+	os_time_t expiration;
+	int cipher; /* Selected cipher (WPA_CIPHER_*) */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int replay_counter_set;
+	int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+
+	struct wpa_ptk stk, tstk;
+	int stk_set, tstk_set;
+};
+
+
+#ifdef CONFIG_PEERKEY
+
+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+				 struct wpa_peerkey *peerkey,
+				 struct wpa_eapol_key *key, u16 ver,
+				 const u8 *buf, size_t len);
+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+			   struct wpa_eapol_key *key, u16 key_info, u16 ver);
+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+			  struct wpa_eapol_key *key, size_t extra_len,
+			  u16 key_info, u16 ver);
+void peerkey_deinit(struct wpa_sm *sm);
+
+#else /* CONFIG_PEERKEY */
+
+static inline int
+peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+			     struct wpa_peerkey *peerkey,
+			     struct wpa_eapol_key *key, u16 ver,
+			     const u8 *buf, size_t len)
+{
+	return -1;
+}
+
+static inline void
+peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+		      struct wpa_eapol_key *key, u16 key_info, u16 ver)
+{
+}
+
+static inline void
+peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+		     struct wpa_eapol_key *key, size_t extra_len,
+		     u16 key_info, u16 ver)
+{
+}
+
+static inline void peerkey_deinit(struct wpa_sm *sm)
+{
+}
+
+#endif /* CONFIG_PEERKEY */
+
+#endif /* PEERKEY_H */

Deleted: vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/pmksa_cache.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,476 +0,0 @@
-/*
- * WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "wpa.h"
-#include "wpa_i.h"
-#include "pmksa_cache.h"
-
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
-
-static const int pmksa_cache_max_entries = 32;
-
-struct rsn_pmksa_cache {
-	struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
-	int pmksa_count; /* number of entries in PMKSA cache */
-	struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
-
-	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
-			int replace);
-	void *ctx;
-};
-
-
-static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
-
-
-static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
-{
-	os_free(entry);
-}
-
-
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
-				   struct rsn_pmksa_cache_entry *entry,
-				   int replace)
-{
-	pmksa->pmksa_count--;
-	pmksa->free_cb(entry, pmksa->ctx, replace);
-	_pmksa_cache_free_entry(entry);
-}
-
-
-static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
-{
-	struct rsn_pmksa_cache *pmksa = eloop_ctx;
-	struct os_time now;
-
-	os_get_time(&now);
-	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
-		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-		pmksa->pmksa = entry->next;
-		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
-			   MACSTR, MAC2STR(entry->aa));
-		pmksa_cache_free_entry(pmksa, entry, 0);
-	}
-
-	pmksa_cache_set_expiration(pmksa);
-}
-
-
-static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
-{
-	struct rsn_pmksa_cache *pmksa = eloop_ctx;
-	pmksa->sm->cur_pmksa = NULL;
-	eapol_sm_request_reauth(pmksa->sm->eapol);
-}
-
-
-static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
-{
-	int sec;
-	struct rsn_pmksa_cache_entry *entry;
-	struct os_time now;
-
-	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
-	eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
-	if (pmksa->pmksa == NULL)
-		return;
-	os_get_time(&now);
-	sec = pmksa->pmksa->expiration - now.sec;
-	if (sec < 0)
-		sec = 0;
-	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
-
-	entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
-		pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL);
-	if (entry) {
-		sec = pmksa->pmksa->reauth_time - now.sec;
-		if (sec < 0)
-			sec = 0;
-		eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
-				       NULL);
-	}
-}
-
-
-/**
- * pmksa_cache_add - Add a PMKSA cache entry
- * @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)
- * @aa: Authenticator address
- * @spa: Supplicant address
- * @network_ctx: Network configuration context for this PMK
- * @akmp: WPA_KEY_MGMT_* used in key derivation
- * Returns: Pointer to the added PMKSA cache entry or %NULL on error
- *
- * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
- * cache. If an old entry is already in the cache for the same Authenticator,
- * this entry will be replaced with the new entry. PMKID will be calculated
- * based on the PMK and the driver interface is notified of the new PMKID.
- */
-struct rsn_pmksa_cache_entry *
-pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
-{
-	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
-	struct os_time now;
-
-	if (pmk_len > PMK_LEN)
-		return NULL;
-
-	entry = os_zalloc(sizeof(*entry));
-	if (entry == NULL)
-		return NULL;
-	os_memcpy(entry->pmk, pmk, pmk_len);
-	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
-		  wpa_key_mgmt_sha256(akmp));
-	os_get_time(&now);
-	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
-	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
-		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
-	entry->akmp = akmp;
-	os_memcpy(entry->aa, aa, ETH_ALEN);
-	entry->network_ctx = network_ctx;
-
-	/* Replace an old entry for the same Authenticator (if found) with the
-	 * new entry */
-	pos = pmksa->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
-			if (pos->pmk_len == pmk_len &&
-			    os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
-			    os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
-			    0) {
-				wpa_printf(MSG_DEBUG, "WPA: reusing previous "
-					   "PMKSA entry");
-				os_free(entry);
-				return pos;
-			}
-			if (prev == NULL)
-				pmksa->pmksa = pos->next;
-			else
-				prev->next = pos->next;
-			if (pos == pmksa->sm->cur_pmksa) {
-				/* We are about to replace the current PMKSA
-				 * cache entry. This happens when the PMKSA
-				 * caching attempt fails, so we don't want to
-				 * force pmksa_cache_free_entry() to disconnect
-				 * at this point. Let's just make sure the old
-				 * PMKSA cache entry will not be used in the
-				 * future.
-				 */
-				wpa_printf(MSG_DEBUG, "RSN: replacing current "
-					   "PMKSA entry");
-				pmksa->sm->cur_pmksa = NULL;
-			}
-			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
-				   "the current AP");
-			pmksa_cache_free_entry(pmksa, pos, 1);
-			break;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-
-	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
-		/* Remove the oldest entry to make room for the new entry */
-		pos = pmksa->pmksa;
-		pmksa->pmksa = pos->next;
-		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
-			   "entry (for " MACSTR ") to make room for new one",
-			   MAC2STR(pos->aa));
-		wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
-		pmksa_cache_free_entry(pmksa, pos, 0);
-	}
-
-	/* Add the new entry; order by expiration time */
-	pos = pmksa->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (pos->expiration > entry->expiration)
-			break;
-		prev = pos;
-		pos = pos->next;
-	}
-	if (prev == NULL) {
-		entry->next = pmksa->pmksa;
-		pmksa->pmksa = entry;
-		pmksa_cache_set_expiration(pmksa);
-	} else {
-		entry->next = prev->next;
-		prev->next = entry;
-	}
-	pmksa->pmksa_count++;
-	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
-		   MAC2STR(entry->aa));
-	wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
-
-	return entry;
-}
-
-
-/**
- * pmksa_cache_deinit - Free all entries in PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- */
-void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
-{
-	struct rsn_pmksa_cache_entry *entry, *prev;
-
-	if (pmksa == NULL)
-		return;
-
-	entry = pmksa->pmksa;
-	pmksa->pmksa = NULL;
-	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		os_free(prev);
-	}
-	pmksa_cache_set_expiration(pmksa);
-	os_free(pmksa);
-}
-
-
-/**
- * pmksa_cache_get - Fetch a PMKSA cache entry
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- * @aa: Authenticator address or %NULL to match any
- * @pmkid: PMKID or %NULL to match any
- * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
- */
-struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
-					       const u8 *aa, const u8 *pmkid)
-{
-	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-	while (entry) {
-		if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
-		    (pmkid == NULL ||
-		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
-			return entry;
-		entry = entry->next;
-	}
-	return NULL;
-}
-
-
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-	while (entry) {
-		entry->network_ctx = NULL;
-		entry = entry->next;
-	}
-}
-
-
-static struct rsn_pmksa_cache_entry *
-pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
-			const struct rsn_pmksa_cache_entry *old_entry,
-			const u8 *aa)
-{
-	struct rsn_pmksa_cache_entry *new_entry;
-
-	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
-				    aa, pmksa->sm->own_addr,
-				    old_entry->network_ctx, old_entry->akmp);
-	if (new_entry == NULL)
-		return NULL;
-
-	/* TODO: reorder entries based on expiration time? */
-	new_entry->expiration = old_entry->expiration;
-	new_entry->opportunistic = 1;
-
-	return new_entry;
-}
-
-
-/**
- * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- * @network_ctx: Network configuration context
- * @aa: Authenticator address for the new AP
- * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
- *
- * Try to create a new PMKSA cache entry opportunistically by guessing that the
- * new AP is sharing the same PMK as another AP that has the same SSID and has
- * already an entry in PMKSA cache.
- */
-struct rsn_pmksa_cache_entry *
-pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
-			      const u8 *aa)
-{
-	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-
-	if (network_ctx == NULL)
-		return NULL;
-	while (entry) {
-		if (entry->network_ctx == network_ctx) {
-			entry = pmksa_cache_clone_entry(pmksa, entry, aa);
-			if (entry) {
-				wpa_printf(MSG_DEBUG, "RSN: added "
-					   "opportunistic PMKSA cache entry "
-					   "for " MACSTR, MAC2STR(aa));
-			}
-			return entry;
-		}
-		entry = entry->next;
-	}
-	return NULL;
-}
-
-
-/**
- * pmksa_cache_get_current - Get the current used PMKSA entry
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
- */
-struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return NULL;
-	return sm->cur_pmksa;
-}
-
-
-/**
- * pmksa_cache_clear_current - Clear the current PMKSA entry selection
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void pmksa_cache_clear_current(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	sm->cur_pmksa = NULL;
-}
-
-
-/**
- * pmksa_cache_set_current - Set the current PMKSA entry selection
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @pmkid: PMKID for selecting PMKSA or %NULL if not used
- * @bssid: BSSID for PMKSA or %NULL if not used
- * @network_ctx: Network configuration context
- * @try_opportunistic: Whether to allow opportunistic PMKSA caching
- * Returns: 0 if PMKSA was found or -1 if no matching entry was found
- */
-int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
-			    const u8 *bssid, void *network_ctx,
-			    int try_opportunistic)
-{
-	struct rsn_pmksa_cache *pmksa = sm->pmksa;
-	sm->cur_pmksa = NULL;
-	if (pmkid)
-		sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid);
-	if (sm->cur_pmksa == NULL && bssid)
-		sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL);
-	if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
-		sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
-							      network_ctx,
-							      bssid);
-	if (sm->cur_pmksa) {
-		wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
-			    sm->cur_pmksa->pmkid, PMKID_LEN);
-		return 0;
-	}
-	return -1;
-}
-
-
-/**
- * pmksa_cache_list - Dump text list of entries in PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- * @buf: Buffer for the list
- * @len: Length of the buffer
- * Returns: number of bytes written to buffer
- *
- * This function is used to generate a text format representation of the
- * current PMKSA cache contents for the ctrl_iface PMKSA command.
- */
-int pmksa_cache_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_time now;
-
-	os_get_time(&now);
-	ret = os_snprintf(pos, buf + len - pos,
-			  "Index / AA / PMKID / expiration (in seconds) / "
-			  "opportunistic\n");
-	if (ret < 0 || ret >= buf + len - pos)
-		return pos - buf;
-	pos += ret;
-	i = 0;
-	entry = pmksa->pmksa;
-	while (entry) {
-		i++;
-		ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
-				  i, MAC2STR(entry->aa));
-		if (ret < 0 || ret >= buf + len - pos)
-			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 (ret < 0 || ret >= buf + len - pos)
-			return pos - buf;
-		pos += ret;
-		entry = entry->next;
-	}
-	return pos - buf;
-}
-
-
-/**
- * pmksa_cache_init - Initialize PMKSA cache
- * @free_cb: Callback function to be called when a PMKSA cache entry is freed
- * @ctx: Context pointer for free_cb function
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * Returns: Pointer to PMKSA cache data or %NULL on failure
- */
-struct rsn_pmksa_cache *
-pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				 void *ctx, int replace),
-		 void *ctx, struct wpa_sm *sm)
-{
-	struct rsn_pmksa_cache *pmksa;
-
-	pmksa = os_zalloc(sizeof(*pmksa));
-	if (pmksa) {
-		pmksa->free_cb = free_cb;
-		pmksa->ctx = ctx;
-		pmksa->sm = sm;
-	}
-
-	return pmksa;
-}
-
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */

Copied: vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/pmksa_cache.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/pmksa_cache.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,512 @@
+/*
+ * WPA Supplicant - RSN PMKSA cache
+ * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa.h"
+#include "wpa_i.h"
+#include "pmksa_cache.h"
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+static const int pmksa_cache_max_entries = 32;
+
+struct rsn_pmksa_cache {
+	struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
+	int pmksa_count; /* number of entries in PMKSA cache */
+	struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
+
+	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
+			enum pmksa_free_reason reason);
+	void *ctx;
+};
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+	os_free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry,
+				   enum pmksa_free_reason reason)
+{
+	wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+	pmksa->pmksa_count--;
+	pmksa->free_cb(entry, pmksa->ctx, reason);
+	_pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+		pmksa->pmksa = entry->next;
+		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+			   MACSTR, MAC2STR(entry->aa));
+		pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
+	}
+
+	pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	pmksa->sm->cur_pmksa = NULL;
+	eapol_sm_request_reauth(pmksa->sm->eapol);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+	int sec;
+	struct rsn_pmksa_cache_entry *entry;
+	struct os_time now;
+
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
+	if (pmksa->pmksa == NULL)
+		return;
+	os_get_time(&now);
+	sec = pmksa->pmksa->expiration - now.sec;
+	if (sec < 0)
+		sec = 0;
+	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+
+	entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
+		pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
+	if (entry) {
+		sec = pmksa->pmksa->reauth_time - now.sec;
+		if (sec < 0)
+			sec = 0;
+		eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
+				       NULL);
+	}
+}
+
+
+/**
+ * pmksa_cache_add - Add a PMKSA cache entry
+ * @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)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @network_ctx: Network configuration context for this PMK
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Authenticator,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK and the driver interface is notified of the new PMKID.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+	struct os_time now;
+
+	if (pmk_len > PMK_LEN)
+		return NULL;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmk, pmk, pmk_len);
+	entry->pmk_len = pmk_len;
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
+	os_get_time(&now);
+	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
+	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
+		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
+	entry->akmp = akmp;
+	os_memcpy(entry->aa, aa, ETH_ALEN);
+	entry->network_ctx = network_ctx;
+
+	/* Replace an old entry for the same Authenticator (if found) with the
+	 * new entry */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
+			if (pos->pmk_len == pmk_len &&
+			    os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
+			    os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
+			    0) {
+				wpa_printf(MSG_DEBUG, "WPA: reusing previous "
+					   "PMKSA entry");
+				os_free(entry);
+				return pos;
+			}
+			if (prev == NULL)
+				pmksa->pmksa = pos->next;
+			else
+				prev->next = pos->next;
+			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+				   "the current AP");
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
+
+			/*
+			 * If OKC is used, there may be other PMKSA cache
+			 * entries based on the same PMK. These needs to be
+			 * flushed so that a new entry can be created based on
+			 * the new PMK.
+			 */
+			pmksa_cache_flush(pmksa, network_ctx);
+			break;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+		/* Remove the oldest entry to make room for the new entry */
+		pos = pmksa->pmksa;
+
+		if (pos == pmksa->sm->cur_pmksa) {
+			/*
+			 * Never remove the current PMKSA cache entry, since
+			 * it's in use, and removing it triggers a needless
+			 * deauthentication.
+			 */
+			pos = pos->next;
+			pmksa->pmksa->next = pos ? pos->next : NULL;
+		} else
+			pmksa->pmksa = pos->next;
+
+		if (pos) {
+			wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
+				   "PMKSA cache entry (for " MACSTR ") to "
+				   "make room for new one",
+				   MAC2STR(pos->aa));
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
+		}
+	}
+
+	/* Add the new entry; order by expiration time */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos->expiration > entry->expiration)
+			break;
+		prev = pos;
+		pos = pos->next;
+	}
+	if (prev == NULL) {
+		entry->next = pmksa->pmksa;
+		pmksa->pmksa = entry;
+		pmksa_cache_set_expiration(pmksa);
+	} else {
+		entry->next = prev->next;
+		prev->next = entry;
+	}
+	pmksa->pmksa_count++;
+	wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
+		   " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
+	wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+
+	return entry;
+}
+
+
+/**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+	int removed = 0;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+				   "for " MACSTR, MAC2STR(entry->aa));
+			if (prev)
+				prev->next = entry->next;
+			else
+				pmksa->pmksa = entry->next;
+			tmp = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
+			removed++;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+	if (removed)
+		pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
+ * pmksa_cache_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ */
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev;
+
+	if (pmksa == NULL)
+		return;
+
+	entry = pmksa->pmksa;
+	pmksa->pmksa = NULL;
+	while (entry) {
+		prev = entry;
+		entry = entry->next;
+		os_free(prev);
+	}
+	pmksa_cache_set_expiration(pmksa);
+	os_free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @aa: Authenticator address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * @network_ctx: Network context or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *aa, const u8 *pmkid,
+					       const void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+	while (entry) {
+		if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
+		    (pmkid == NULL ||
+		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+		    (network_ctx == NULL || network_ctx == entry->network_ctx))
+			return entry;
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
+			const struct rsn_pmksa_cache_entry *old_entry,
+			const u8 *aa)
+{
+	struct rsn_pmksa_cache_entry *new_entry;
+
+	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+				    aa, pmksa->sm->own_addr,
+				    old_entry->network_ctx, old_entry->akmp);
+	if (new_entry == NULL)
+		return NULL;
+
+	/* TODO: reorder entries based on expiration time? */
+	new_entry->expiration = old_entry->expiration;
+	new_entry->opportunistic = 1;
+
+	return new_entry;
+}
+
+
+/**
+ * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context
+ * @aa: Authenticator address for the new AP
+ * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
+ *
+ * Try to create a new PMKSA cache entry opportunistically by guessing that the
+ * new AP is sharing the same PMK as another AP that has the same SSID and has
+ * already an entry in PMKSA cache.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+			      const u8 *aa)
+{
+	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+
+	wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
+	if (network_ctx == NULL)
+		return NULL;
+	while (entry) {
+		if (entry->network_ctx == network_ctx) {
+			entry = pmksa_cache_clone_entry(pmksa, entry, aa);
+			if (entry) {
+				wpa_printf(MSG_DEBUG, "RSN: added "
+					   "opportunistic PMKSA cache entry "
+					   "for " MACSTR, MAC2STR(aa));
+			}
+			return entry;
+		}
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_current - Get the current used PMKSA entry
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return NULL;
+	return sm->cur_pmksa;
+}
+
+
+/**
+ * pmksa_cache_clear_current - Clear the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	sm->cur_pmksa = NULL;
+}
+
+
+/**
+ * pmksa_cache_set_current - Set the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmkid: PMKID for selecting PMKSA or %NULL if not used
+ * @bssid: BSSID for PMKSA or %NULL if not used
+ * @network_ctx: Network configuration context
+ * @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * Returns: 0 if PMKSA was found or -1 if no matching entry was found
+ */
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+			    const u8 *bssid, void *network_ctx,
+			    int try_opportunistic)
+{
+	struct rsn_pmksa_cache *pmksa = sm->pmksa;
+	wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
+		   "try_opportunistic=%d", network_ctx, try_opportunistic);
+	if (pmkid)
+		wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
+			    pmkid, PMKID_LEN);
+	if (bssid)
+		wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
+			   MAC2STR(bssid));
+
+	sm->cur_pmksa = NULL;
+	if (pmkid)
+		sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
+						network_ctx);
+	if (sm->cur_pmksa == NULL && bssid)
+		sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
+						network_ctx);
+	if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
+		sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
+							      network_ctx,
+							      bssid);
+	if (sm->cur_pmksa) {
+		wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
+			    sm->cur_pmksa->pmkid, PMKID_LEN);
+		return 0;
+	}
+	wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found");
+	return -1;
+}
+
+
+/**
+ * pmksa_cache_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_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_time now;
+
+	os_get_time(&now);
+	ret = os_snprintf(pos, buf + len - pos,
+			  "Index / AA / PMKID / expiration (in seconds) / "
+			  "opportunistic\n");
+	if (ret < 0 || ret >= buf + len - pos)
+		return pos - buf;
+	pos += ret;
+	i = 0;
+	entry = pmksa->pmksa;
+	while (entry) {
+		i++;
+		ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+				  i, MAC2STR(entry->aa));
+		if (ret < 0 || ret >= buf + len - pos)
+			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 (ret < 0 || ret >= buf + len - pos)
+			return pos - buf;
+		pos += ret;
+		entry = entry->next;
+	}
+	return pos - buf;
+}
+
+
+/**
+ * pmksa_cache_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason),
+		 void *ctx, struct wpa_sm *sm)
+{
+	struct rsn_pmksa_cache *pmksa;
+
+	pmksa = os_zalloc(sizeof(*pmksa));
+	if (pmksa) {
+		pmksa->free_cb = free_cb;
+		pmksa->ctx = ctx;
+		pmksa->sm = sm;
+	}
+
+	return pmksa;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */

Deleted: vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/pmksa_cache.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,127 +0,0 @@
-/*
- * wpa_supplicant - WPA2/RSN PMKSA cache functions
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PMKSA_CACHE_H
-#define PMKSA_CACHE_H
-
-/**
- * struct rsn_pmksa_cache_entry - PMKSA cache entry
- */
-struct rsn_pmksa_cache_entry {
-	struct rsn_pmksa_cache_entry *next;
-	u8 pmkid[PMKID_LEN];
-	u8 pmk[PMK_LEN];
-	size_t pmk_len;
-	os_time_t expiration;
-	int akmp; /* WPA_KEY_MGMT_* */
-	u8 aa[ETH_ALEN];
-
-	os_time_t reauth_time;
-
-	/**
-	 * network_ctx - Network configuration context
-	 *
-	 * This field is only used to match PMKSA cache entries to a specific
-	 * network configuration (e.g., a specific SSID and security policy).
-	 * This can be a pointer to the configuration entry, but PMKSA caching
-	 * code does not dereference the value and this could be any kind of
-	 * identifier.
-	 */
-	void *network_ctx;
-	int opportunistic;
-};
-
-struct rsn_pmksa_cache;
-
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
-
-struct rsn_pmksa_cache *
-pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				 void *ctx, int replace),
-		 void *ctx, struct wpa_sm *sm);
-void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
-struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
-					       const u8 *aa, const u8 *pmkid);
-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 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
-struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
-void pmksa_cache_clear_current(struct wpa_sm *sm);
-int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
-			    const u8 *bssid, void *network_ctx,
-			    int try_opportunistic);
-struct rsn_pmksa_cache_entry *
-pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
-			      void *network_ctx, const u8 *aa);
-
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
-
-static inline struct rsn_pmksa_cache *
-pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
-				 void *ctx, int replace),
-		 void *ctx, struct wpa_sm *sm)
-{
-	return (void *) -1;
-}
-
-static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
-{
-}
-
-static inline struct rsn_pmksa_cache_entry *
-pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid)
-{
-	return NULL;
-}
-
-static inline struct rsn_pmksa_cache_entry *
-pmksa_cache_get_current(struct wpa_sm *sm)
-{
-	return NULL;
-}
-
-static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
-				   size_t len)
-{
-	return -1;
-}
-
-static inline struct rsn_pmksa_cache_entry *
-pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
-{
-	return NULL;
-}
-
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
-static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
-{
-}
-
-static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
-					  const u8 *bssid,
-					  void *network_ctx,
-					  int try_opportunistic)
-{
-	return -1;
-}
-
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
-
-#endif /* PMKSA_CACHE_H */

Copied: vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/pmksa_cache.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/pmksa_cache.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,130 @@
+/*
+ * wpa_supplicant - WPA2/RSN PMKSA cache functions
+ * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+	struct rsn_pmksa_cache_entry *next;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	os_time_t expiration;
+	int akmp; /* WPA_KEY_MGMT_* */
+	u8 aa[ETH_ALEN];
+
+	os_time_t reauth_time;
+
+	/**
+	 * network_ctx - Network configuration context
+	 *
+	 * This field is only used to match PMKSA cache entries to a specific
+	 * network configuration (e.g., a specific SSID and security policy).
+	 * This can be a pointer to the configuration entry, but PMKSA caching
+	 * code does not dereference the value and this could be any kind of
+	 * identifier.
+	 */
+	void *network_ctx;
+	int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+enum pmksa_free_reason {
+	PMKSA_FREE,
+	PMKSA_REPLACE,
+	PMKSA_EXPIRE,
+};
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason),
+		 void *ctx, struct wpa_sm *sm);
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *aa, const u8 *pmkid,
+					       const void *network_ctx);
+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 *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);
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+			    const u8 *bssid, void *network_ctx,
+			    int try_opportunistic);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
+			      void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+static inline struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, int reason),
+		 void *ctx, struct wpa_sm *sm)
+{
+	return (void *) -1;
+}
+
+static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
+		const void *network_ctx)
+{
+	return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get_current(struct wpa_sm *sm)
+{
+	return NULL;
+}
+
+static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
+				   size_t len)
+{
+	return -1;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+	return NULL;
+}
+
+static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+}
+
+static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+					  const u8 *bssid,
+					  void *network_ctx,
+					  int try_opportunistic)
+{
+	return -1;
+}
+
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+				     void *network_ctx)
+{
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+#endif /* PMKSA_CACHE_H */

Deleted: vendor/wpa/2.0/src/rsn_supp/preauth.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/preauth.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/preauth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,518 +0,0 @@
-/*
- * RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa.h"
-#include "eloop.h"
-#include "l2_packet/l2_packet.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "preauth.h"
-#include "pmksa_cache.h"
-#include "wpa_i.h"
-#include "common/ieee802_11_defs.h"
-
-
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
-
-#define PMKID_CANDIDATE_PRIO_SCAN 1000
-
-
-struct rsn_pmksa_candidate {
-	struct dl_list list;
-	u8 bssid[ETH_ALEN];
-	int priority;
-};
-
-
-/**
- * pmksa_candidate_free - Free all entries in PMKSA candidate list
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void pmksa_candidate_free(struct wpa_sm *sm)
-{
-	struct rsn_pmksa_candidate *entry, *n;
-
-	if (sm == NULL)
-		return;
-
-	dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
-			      struct rsn_pmksa_candidate, list) {
-		dl_list_del(&entry->list);
-		os_free(entry);
-	}
-}
-
-
-static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
-				const u8 *buf, size_t len)
-{
-	struct wpa_sm *sm = ctx;
-
-	wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
-	wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
-
-	if (sm->preauth_eapol == NULL ||
-	    is_zero_ether_addr(sm->preauth_bssid) ||
-	    os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
-			   "unexpected source " MACSTR " - dropped",
-			   MAC2STR(src_addr));
-		return;
-	}
-
-	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
-}
-
-
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
-				 void *ctx)
-{
-	struct wpa_sm *sm = ctx;
-	u8 pmk[PMK_LEN];
-
-	if (success) {
-		int res, pmk_len;
-		pmk_len = PMK_LEN;
-		res = eapol_sm_get_key(eapol, 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(eapol, pmk, 16);
-			pmk_len = 16;
-		}
-		if (res == 0) {
-			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,
-					sm->preauth_bssid, sm->own_addr,
-					sm->network_ctx,
-					WPA_KEY_MGMT_IEEE8021X);
-		} else {
-			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-				"RSN: failed to get master session key from "
-				"pre-auth EAPOL state machines");
-			success = 0;
-		}
-	}
-
-	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
-		MACSTR " %s", MAC2STR(sm->preauth_bssid),
-		success ? "completed successfully" : "failed");
-
-	rsn_preauth_deinit(sm);
-	rsn_preauth_candidate_process(sm);
-}
-
-
-static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_sm *sm = eloop_ctx;
-
-	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
-		MACSTR " timed out", MAC2STR(sm->preauth_bssid));
-	rsn_preauth_deinit(sm);
-	rsn_preauth_candidate_process(sm);
-}
-
-
-static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
-				  size_t len)
-{
-	struct wpa_sm *sm = ctx;
-	u8 *msg;
-	size_t msglen;
-	int res;
-
-	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
-	 * extra copy here */
-
-	if (sm->l2_preauth == NULL)
-		return -1;
-
-	msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
-	if (msg == NULL)
-		return -1;
-
-	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
-	res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
-			     ETH_P_RSN_PREAUTH, msg, msglen);
-	os_free(msg);
-	return res;
-}
-
-
-/**
- * rsn_preauth_init - Start new RSN pre-authentication
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @dst: Authenticator address (BSSID) with which to preauthenticate
- * @eap_conf: Current EAP configuration
- * Returns: 0 on success, -1 on another pre-authentication is in progress,
- * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
- * initialization failure, -4 on memory allocation failure
- *
- * This function request an RSN pre-authentication with a given destination
- * address. This is usually called for PMKSA candidates found from scan results
- * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
- * pre-authentication.
- */
-int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
-		     struct eap_peer_config *eap_conf)
-{
-	struct eapol_config eapol_conf;
-	struct eapol_ctx *ctx;
-
-	if (sm->preauth_eapol)
-		return -1;
-
-	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
-		"RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
-
-	sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
-					ETH_P_RSN_PREAUTH,
-					rsn_preauth_receive, sm, 0);
-	if (sm->l2_preauth == NULL) {
-		wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
-			   "processing for pre-authentication");
-		return -2;
-	}
-
-	if (sm->bridge_ifname) {
-		sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
-						   sm->own_addr,
-						   ETH_P_RSN_PREAUTH,
-						   rsn_preauth_receive, sm, 0);
-		if (sm->l2_preauth_br == NULL) {
-			wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
-				   "packet processing (bridge) for "
-				   "pre-authentication");
-			return -2;
-		}
-	}
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL) {
-		wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
-		return -4;
-	}
-	ctx->ctx = sm->ctx->ctx;
-	ctx->msg_ctx = sm->ctx->ctx;
-	ctx->preauth = 1;
-	ctx->cb = rsn_preauth_eapol_cb;
-	ctx->cb_ctx = sm;
-	ctx->scard_ctx = sm->scard_ctx;
-	ctx->eapol_send = rsn_preauth_eapol_send;
-	ctx->eapol_send_ctx = sm;
-	ctx->set_config_blob = sm->ctx->set_config_blob;
-	ctx->get_config_blob = sm->ctx->get_config_blob;
-
-	sm->preauth_eapol = eapol_sm_init(ctx);
-	if (sm->preauth_eapol == NULL) {
-		os_free(ctx);
-		wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
-			   "state machines for pre-authentication");
-		return -3;
-	}
-	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
-	eapol_conf.accept_802_1x_keys = 0;
-	eapol_conf.required_keys = 0;
-	eapol_conf.fast_reauth = sm->fast_reauth;
-	eapol_conf.workaround = sm->eap_workaround;
-	eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
-	/*
-	 * Use a shorter startPeriod with preauthentication since the first
-	 * preauth EAPOL-Start frame may end up being dropped due to race
-	 * condition in the AP between the data receive and key configuration
-	 * after the 4-Way Handshake.
-	 */
-	eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
-	os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
-
-	eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
-	/* 802.1X::portControl = Auto */
-	eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
-
-	eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
-			       rsn_preauth_timeout, sm, NULL);
-
-	return 0;
-}
-
-
-/**
- * rsn_preauth_deinit - Abort RSN pre-authentication
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * This function aborts the current RSN pre-authentication (if one is started)
- * and frees resources allocated for it.
- */
-void rsn_preauth_deinit(struct wpa_sm *sm)
-{
-	if (sm == NULL || !sm->preauth_eapol)
-		return;
-
-	eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
-	eapol_sm_deinit(sm->preauth_eapol);
-	sm->preauth_eapol = NULL;
-	os_memset(sm->preauth_bssid, 0, ETH_ALEN);
-
-	l2_packet_deinit(sm->l2_preauth);
-	sm->l2_preauth = NULL;
-	if (sm->l2_preauth_br) {
-		l2_packet_deinit(sm->l2_preauth_br);
-		sm->l2_preauth_br = NULL;
-	}
-}
-
-
-/**
- * rsn_preauth_candidate_process - Process PMKSA candidates
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * Go through the PMKSA candidates and start pre-authentication if a candidate
- * without an existing PMKSA cache entry is found. Processed candidates will be
- * removed from the list.
- */
-void rsn_preauth_candidate_process(struct wpa_sm *sm)
-{
-	struct rsn_pmksa_candidate *candidate, *n;
-
-	if (dl_list_empty(&sm->pmksa_candidates))
-		return;
-
-	/* TODO: drop priority for old candidate entries */
-
-	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
-		"list");
-	if (sm->preauth_eapol ||
-	    sm->proto != WPA_PROTO_RSN ||
-	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
-	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
-			"state for new pre-authentication");
-		return; /* invalid state for new pre-auth */
-	}
-
-	dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
-			      struct rsn_pmksa_candidate, list) {
-		struct rsn_pmksa_cache_entry *p = NULL;
-		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
-		if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
-		    (p == NULL || p->opportunistic)) {
-			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
-				"candidate " MACSTR
-				" selected for pre-authentication",
-				MAC2STR(candidate->bssid));
-			dl_list_del(&candidate->list);
-			rsn_preauth_init(sm, candidate->bssid,
-					 sm->eap_conf_ctx);
-			os_free(candidate);
-			return;
-		}
-		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
-			MACSTR " does not need pre-authentication anymore",
-			MAC2STR(candidate->bssid));
-		/* Some drivers (e.g., NDIS) expect to get notified about the
-		 * PMKIDs again, so report the existing data now. */
-		if (p) {
-			wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
-		}
-
-		dl_list_del(&candidate->list);
-		os_free(candidate);
-	}
-	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
-		"candidates");
-}
-
-
-/**
- * pmksa_candidate_add - Add a new PMKSA candidate
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @bssid: BSSID (authenticator address) of the candidate
- * @prio: Priority (the smaller number, the higher priority)
- * @preauth: Whether the candidate AP advertises support for pre-authentication
- *
- * This function is used to add PMKSA candidates for RSN pre-authentication. It
- * is called from scan result processing and from driver events for PMKSA
- * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
- */
-void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
-			 int prio, int preauth)
-{
-	struct rsn_pmksa_candidate *cand, *pos;
-
-	if (sm->network_ctx && sm->proactive_key_caching)
-		pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
-					      bssid);
-
-	if (!preauth) {
-		wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
-			   "preauth flag");
-		return;
-	}
-
-	/* If BSSID already on candidate list, update the priority of the old
-	 * entry. Do not override priority based on normal scan results. */
-	cand = NULL;
-	dl_list_for_each(pos, &sm->pmksa_candidates,
-			 struct rsn_pmksa_candidate, list) {
-		if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
-			cand = pos;
-			break;
-		}
-	}
-
-	if (cand) {
-		dl_list_del(&cand->list);
-		if (prio < PMKID_CANDIDATE_PRIO_SCAN)
-			cand->priority = prio;
-	} else {
-		cand = os_zalloc(sizeof(*cand));
-		if (cand == NULL)
-			return;
-		os_memcpy(cand->bssid, bssid, ETH_ALEN);
-		cand->priority = prio;
-	}
-
-	/* Add candidate to the list; order by increasing priority value. i.e.,
-	 * highest priority (smallest value) first. */
-	dl_list_for_each(pos, &sm->pmksa_candidates,
-			 struct rsn_pmksa_candidate, list) {
-		if (cand->priority <= pos->priority) {
-			dl_list_add(pos->list.prev, &cand->list);
-			cand = NULL;
-			break;
-		}
-	}
-	if (cand)
-		dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
-
-	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
-		"candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
-	rsn_preauth_candidate_process(sm);
-}
-
-
-/* TODO: schedule periodic scans if current AP supports preauth */
-
-/**
- * rsn_preauth_scan_results - Start processing scan results for canditates
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * Returns: 0 if ready to process results or -1 to skip processing
- *
- * This functions is used to notify RSN code about start of new scan results
- * processing. The actual scan results will be provided by calling
- * rsn_preauth_scan_result() for each BSS if this function returned 0.
- */
-int rsn_preauth_scan_results(struct wpa_sm *sm)
-{
-	if (sm->ssid_len == 0)
-		return -1;
-
-	/*
-	 * TODO: is it ok to free all candidates? What about the entries
-	 * received from EVENT_PMKID_CANDIDATE?
-	 */
-	pmksa_candidate_free(sm);
-
-	return 0;
-}
-
-
-/**
- * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * Add all suitable APs (Authenticators) from scan results into PMKSA
- * candidate list.
- */
-void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
-			     const u8 *ssid, const u8 *rsn)
-{
-	struct wpa_ie_data ie;
-	struct rsn_pmksa_cache_entry *pmksa;
-
-	if (ssid[1] != sm->ssid_len ||
-	    os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
-		return; /* Not for the current SSID */
-
-	if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
-		return; /* Ignore current AP */
-
-	if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
-		return;
-
-	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL);
-	if (pmksa && (!pmksa->opportunistic ||
-		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
-		return;
-
-	/* Give less priority to candidates found from normal scan results. */
-	pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
-			    ie.capabilities & WPA_CAPABILITY_PREAUTH);
-}
-
-
-#ifdef CONFIG_CTRL_IFACE
-/**
- * rsn_preauth_get_status - Get pre-authentication status
- * @sm: Pointer to WPA state machine data from wpa_sm_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 WPA2 pre-authentication for status information. This function fills in
- * a text area with current status information. If the buffer (buf) is not
- * large enough, status information will be truncated to fit the buffer.
- */
-int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
-			   int verbose)
-{
-	char *pos = buf, *end = buf + buflen;
-	int res, ret;
-
-	if (sm->preauth_eapol) {
-		ret = os_snprintf(pos, end - pos, "Pre-authentication "
-				  "EAPOL state machines:\n");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		res = eapol_sm_get_status(sm->preauth_eapol,
-					  pos, end - pos, verbose);
-		if (res >= 0)
-			pos += res;
-	}
-
-	return pos - buf;
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-/**
- * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-int rsn_preauth_in_progress(struct wpa_sm *sm)
-{
-	return sm->preauth_eapol != NULL;
-}
-
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */

Copied: vendor/wpa/2.0/src/rsn_supp/preauth.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/preauth.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/preauth.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/preauth.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,511 @@
+/*
+ * RSN pre-authentication (supplicant)
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "l2_packet/l2_packet.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
+#include "wpa_i.h"
+
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+#define PMKID_CANDIDATE_PRIO_SCAN 1000
+
+
+struct rsn_pmksa_candidate {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	int priority;
+};
+
+
+/**
+ * pmksa_candidate_free - Free all entries in PMKSA candidate list
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_candidate_free(struct wpa_sm *sm)
+{
+	struct rsn_pmksa_candidate *entry, *n;
+
+	if (sm == NULL)
+		return;
+
+	dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
+			      struct rsn_pmksa_candidate, list) {
+		dl_list_del(&entry->list);
+		os_free(entry);
+	}
+}
+
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+				const u8 *buf, size_t len)
+{
+	struct wpa_sm *sm = ctx;
+
+	wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
+	wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
+
+	if (sm->preauth_eapol == NULL ||
+	    is_zero_ether_addr(sm->preauth_bssid) ||
+	    os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
+			   "unexpected source " MACSTR " - dropped",
+			   MAC2STR(src_addr));
+		return;
+	}
+
+	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
+}
+
+
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+				 void *ctx)
+{
+	struct wpa_sm *sm = ctx;
+	u8 pmk[PMK_LEN];
+
+	if (success) {
+		int res, pmk_len;
+		pmk_len = PMK_LEN;
+		res = eapol_sm_get_key(eapol, 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(eapol, pmk, 16);
+			pmk_len = 16;
+		}
+		if (res == 0) {
+			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,
+					sm->preauth_bssid, sm->own_addr,
+					sm->network_ctx,
+					WPA_KEY_MGMT_IEEE8021X);
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"RSN: failed to get master session key from "
+				"pre-auth EAPOL state machines");
+			success = 0;
+		}
+	}
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
+		MACSTR " %s", MAC2STR(sm->preauth_bssid),
+		success ? "completed successfully" : "failed");
+
+	rsn_preauth_deinit(sm);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
+		MACSTR " timed out", MAC2STR(sm->preauth_bssid));
+	rsn_preauth_deinit(sm);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
+				  size_t len)
+{
+	struct wpa_sm *sm = ctx;
+	u8 *msg;
+	size_t msglen;
+	int res;
+
+	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
+	 * extra copy here */
+
+	if (sm->l2_preauth == NULL)
+		return -1;
+
+	msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
+	if (msg == NULL)
+		return -1;
+
+	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
+	res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
+			     ETH_P_RSN_PREAUTH, msg, msglen);
+	os_free(msg);
+	return res;
+}
+
+
+/**
+ * rsn_preauth_init - Start new RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Authenticator address (BSSID) with which to preauthenticate
+ * @eap_conf: Current EAP configuration
+ * Returns: 0 on success, -1 on another pre-authentication is in progress,
+ * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
+ * initialization failure, -4 on memory allocation failure
+ *
+ * This function request an RSN pre-authentication with a given destination
+ * address. This is usually called for PMKSA candidates found from scan results
+ * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
+ * pre-authentication.
+ */
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+		     struct eap_peer_config *eap_conf)
+{
+	struct eapol_config eapol_conf;
+	struct eapol_ctx *ctx;
+
+	if (sm->preauth_eapol)
+		return -1;
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
+
+	sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
+					ETH_P_RSN_PREAUTH,
+					rsn_preauth_receive, sm, 0);
+	if (sm->l2_preauth == NULL) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
+			   "processing for pre-authentication");
+		return -2;
+	}
+
+	if (sm->bridge_ifname) {
+		sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
+						   sm->own_addr,
+						   ETH_P_RSN_PREAUTH,
+						   rsn_preauth_receive, sm, 0);
+		if (sm->l2_preauth_br == NULL) {
+			wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
+				   "packet processing (bridge) for "
+				   "pre-authentication");
+			return -2;
+		}
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
+		return -4;
+	}
+	ctx->ctx = sm->ctx->ctx;
+	ctx->msg_ctx = sm->ctx->ctx;
+	ctx->preauth = 1;
+	ctx->cb = rsn_preauth_eapol_cb;
+	ctx->cb_ctx = sm;
+	ctx->scard_ctx = sm->scard_ctx;
+	ctx->eapol_send = rsn_preauth_eapol_send;
+	ctx->eapol_send_ctx = sm;
+	ctx->set_config_blob = sm->ctx->set_config_blob;
+	ctx->get_config_blob = sm->ctx->get_config_blob;
+
+	sm->preauth_eapol = eapol_sm_init(ctx);
+	if (sm->preauth_eapol == NULL) {
+		os_free(ctx);
+		wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
+			   "state machines for pre-authentication");
+		return -3;
+	}
+	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+	eapol_conf.accept_802_1x_keys = 0;
+	eapol_conf.required_keys = 0;
+	eapol_conf.fast_reauth = sm->fast_reauth;
+	eapol_conf.workaround = sm->eap_workaround;
+	eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
+	/*
+	 * Use a shorter startPeriod with preauthentication since the first
+	 * preauth EAPOL-Start frame may end up being dropped due to race
+	 * condition in the AP between the data receive and key configuration
+	 * after the 4-Way Handshake.
+	 */
+	eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
+	os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
+
+	eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+	/* 802.1X::portControl = Auto */
+	eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+
+	eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
+			       rsn_preauth_timeout, sm, NULL);
+
+	return 0;
+}
+
+
+/**
+ * rsn_preauth_deinit - Abort RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function aborts the current RSN pre-authentication (if one is started)
+ * and frees resources allocated for it.
+ */
+void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+	if (sm == NULL || !sm->preauth_eapol)
+		return;
+
+	eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
+	eapol_sm_deinit(sm->preauth_eapol);
+	sm->preauth_eapol = NULL;
+	os_memset(sm->preauth_bssid, 0, ETH_ALEN);
+
+	l2_packet_deinit(sm->l2_preauth);
+	sm->l2_preauth = NULL;
+	if (sm->l2_preauth_br) {
+		l2_packet_deinit(sm->l2_preauth_br);
+		sm->l2_preauth_br = NULL;
+	}
+}
+
+
+/**
+ * rsn_preauth_candidate_process - Process PMKSA candidates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Go through the PMKSA candidates and start pre-authentication if a candidate
+ * without an existing PMKSA cache entry is found. Processed candidates will be
+ * removed from the list.
+ */
+void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+	struct rsn_pmksa_candidate *candidate, *n;
+
+	if (dl_list_empty(&sm->pmksa_candidates))
+		return;
+
+	/* TODO: drop priority for old candidate entries */
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
+		"list");
+	if (sm->preauth_eapol ||
+	    sm->proto != WPA_PROTO_RSN ||
+	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
+	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
+			"state for new pre-authentication");
+		return; /* invalid state for new pre-auth */
+	}
+
+	dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
+			      struct rsn_pmksa_candidate, list) {
+		struct rsn_pmksa_cache_entry *p = NULL;
+		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL);
+		if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
+		    (p == NULL || p->opportunistic)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
+				"candidate " MACSTR
+				" selected for pre-authentication",
+				MAC2STR(candidate->bssid));
+			dl_list_del(&candidate->list);
+			rsn_preauth_init(sm, candidate->bssid,
+					 sm->eap_conf_ctx);
+			os_free(candidate);
+			return;
+		}
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
+			MACSTR " does not need pre-authentication anymore",
+			MAC2STR(candidate->bssid));
+		/* Some drivers (e.g., NDIS) expect to get notified about the
+		 * PMKIDs again, so report the existing data now. */
+		if (p) {
+			wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+		}
+
+		dl_list_del(&candidate->list);
+		os_free(candidate);
+	}
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
+		"candidates");
+}
+
+
+/**
+ * pmksa_candidate_add - Add a new PMKSA candidate
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: BSSID (authenticator address) of the candidate
+ * @prio: Priority (the smaller number, the higher priority)
+ * @preauth: Whether the candidate AP advertises support for pre-authentication
+ *
+ * This function is used to add PMKSA candidates for RSN pre-authentication. It
+ * is called from scan result processing and from driver events for PMKSA
+ * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
+ */
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+			 int prio, int preauth)
+{
+	struct rsn_pmksa_candidate *cand, *pos;
+
+	if (sm->network_ctx && sm->proactive_key_caching)
+		pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
+					      bssid);
+
+	if (!preauth) {
+		wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
+			   "preauth flag");
+		return;
+	}
+
+	/* If BSSID already on candidate list, update the priority of the old
+	 * entry. Do not override priority based on normal scan results. */
+	cand = NULL;
+	dl_list_for_each(pos, &sm->pmksa_candidates,
+			 struct rsn_pmksa_candidate, list) {
+		if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
+			cand = pos;
+			break;
+		}
+	}
+
+	if (cand) {
+		dl_list_del(&cand->list);
+		if (prio < PMKID_CANDIDATE_PRIO_SCAN)
+			cand->priority = prio;
+	} else {
+		cand = os_zalloc(sizeof(*cand));
+		if (cand == NULL)
+			return;
+		os_memcpy(cand->bssid, bssid, ETH_ALEN);
+		cand->priority = prio;
+	}
+
+	/* Add candidate to the list; order by increasing priority value. i.e.,
+	 * highest priority (smallest value) first. */
+	dl_list_for_each(pos, &sm->pmksa_candidates,
+			 struct rsn_pmksa_candidate, list) {
+		if (cand->priority <= pos->priority) {
+			dl_list_add(pos->list.prev, &cand->list);
+			cand = NULL;
+			break;
+		}
+	}
+	if (cand)
+		dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
+		"candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+/* TODO: schedule periodic scans if current AP supports preauth */
+
+/**
+ * rsn_preauth_scan_results - Start processing scan results for canditates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: 0 if ready to process results or -1 to skip processing
+ *
+ * This functions is used to notify RSN code about start of new scan results
+ * processing. The actual scan results will be provided by calling
+ * rsn_preauth_scan_result() for each BSS if this function returned 0.
+ */
+int rsn_preauth_scan_results(struct wpa_sm *sm)
+{
+	if (sm->ssid_len == 0)
+		return -1;
+
+	/*
+	 * TODO: is it ok to free all candidates? What about the entries
+	 * received from EVENT_PMKID_CANDIDATE?
+	 */
+	pmksa_candidate_free(sm);
+
+	return 0;
+}
+
+
+/**
+ * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Add all suitable APs (Authenticators) from scan results into PMKSA
+ * candidate list.
+ */
+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+			     const u8 *ssid, const u8 *rsn)
+{
+	struct wpa_ie_data ie;
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	if (ssid[1] != sm->ssid_len ||
+	    os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
+		return; /* Not for the current SSID */
+
+	if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
+		return; /* Ignore current AP */
+
+	if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
+		return;
+
+	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
+	if (pmksa && (!pmksa->opportunistic ||
+		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
+		return;
+
+	/* Give less priority to candidates found from normal scan results. */
+	pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
+			    ie.capabilities & WPA_CAPABILITY_PREAUTH);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+/**
+ * rsn_preauth_get_status - Get pre-authentication status
+ * @sm: Pointer to WPA state machine data from wpa_sm_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 WPA2 pre-authentication for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+			   int verbose)
+{
+	char *pos = buf, *end = buf + buflen;
+	int res, ret;
+
+	if (sm->preauth_eapol) {
+		ret = os_snprintf(pos, end - pos, "Pre-authentication "
+				  "EAPOL state machines:\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		res = eapol_sm_get_status(sm->preauth_eapol,
+					  pos, end - pos, verbose);
+		if (res >= 0)
+			pos += res;
+	}
+
+	return pos - buf;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+/**
+ * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+	return sm->preauth_eapol != NULL;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */

Deleted: vendor/wpa/2.0/src/rsn_supp/preauth.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/preauth.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/preauth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,85 +0,0 @@
-/*
- * wpa_supplicant - WPA2/RSN pre-authentication functions
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PREAUTH_H
-#define PREAUTH_H
-
-struct wpa_scan_results;
-
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
-
-void pmksa_candidate_free(struct wpa_sm *sm);
-int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
-		     struct eap_peer_config *eap_conf);
-void rsn_preauth_deinit(struct wpa_sm *sm);
-int rsn_preauth_scan_results(struct wpa_sm *sm);
-void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
-			     const u8 *ssid, const u8 *rsn);
-void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
-			 int prio, int preauth);
-void rsn_preauth_candidate_process(struct wpa_sm *sm);
-int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
-			   int verbose);
-int rsn_preauth_in_progress(struct wpa_sm *sm);
-
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
-
-static inline void pmksa_candidate_free(struct wpa_sm *sm)
-{
-}
-
-static inline void rsn_preauth_candidate_process(struct wpa_sm *sm)
-{
-}
-
-static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
-				   struct eap_peer_config *eap_conf)
-{
-	return -1;
-}
-
-static inline void rsn_preauth_deinit(struct wpa_sm *sm)
-{
-}
-
-static inline int rsn_preauth_scan_results(struct wpa_sm *sm)
-{
-	return -1;
-}
-
-static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
-					   const u8 *ssid, const u8 *rsn)
-{
-}
-
-static inline void pmksa_candidate_add(struct wpa_sm *sm,
-				       const u8 *bssid,
-				       int prio, int preauth)
-{
-}
-
-static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf,
-					 size_t buflen, int verbose)
-{
-	return 0;
-}
-
-static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
-{
-	return 0;
-}
-
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
-
-#endif /* PREAUTH_H */

Copied: vendor/wpa/2.0/src/rsn_supp/preauth.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/preauth.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/preauth.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/preauth.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,79 @@
+/*
+ * wpa_supplicant - WPA2/RSN pre-authentication functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PREAUTH_H
+#define PREAUTH_H
+
+struct wpa_scan_results;
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+void pmksa_candidate_free(struct wpa_sm *sm);
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+		     struct eap_peer_config *eap_conf);
+void rsn_preauth_deinit(struct wpa_sm *sm);
+int rsn_preauth_scan_results(struct wpa_sm *sm);
+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+			     const u8 *ssid, const u8 *rsn);
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+			 int prio, int preauth);
+void rsn_preauth_candidate_process(struct wpa_sm *sm);
+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+			   int verbose);
+int rsn_preauth_in_progress(struct wpa_sm *sm);
+
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+static inline void pmksa_candidate_free(struct wpa_sm *sm)
+{
+}
+
+static inline void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+}
+
+static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+				   struct eap_peer_config *eap_conf)
+{
+	return -1;
+}
+
+static inline void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+}
+
+static inline int rsn_preauth_scan_results(struct wpa_sm *sm)
+{
+	return -1;
+}
+
+static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+					   const u8 *ssid, const u8 *rsn)
+{
+}
+
+static inline void pmksa_candidate_add(struct wpa_sm *sm,
+				       const u8 *bssid,
+				       int prio, int preauth)
+{
+}
+
+static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf,
+					 size_t buflen, int verbose)
+{
+	return 0;
+}
+
+static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+#endif /* PREAUTH_H */

Copied: vendor/wpa/2.0/src/rsn_supp/tdls.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/tdls.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/tdls.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/tdls.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2334 @@
+/*
+ * wpa_supplicant - TDLS
+ * Copyright (c) 2010-2011, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/os.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/sha256.h"
+#include "crypto/crypto.h"
+#include "crypto/aes_wrap.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_ie.h"
+#include "rsn_supp/wpa_i.h"
+#include "drivers/driver.h"
+#include "l2_packet/l2_packet.h"
+
+#ifdef CONFIG_TDLS_TESTING
+#define TDLS_TESTING_LONG_FRAME BIT(0)
+#define TDLS_TESTING_ALT_RSN_IE BIT(1)
+#define TDLS_TESTING_DIFF_BSSID BIT(2)
+#define TDLS_TESTING_SHORT_LIFETIME BIT(3)
+#define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4)
+#define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5)
+#define TDLS_TESTING_LONG_LIFETIME BIT(6)
+#define TDLS_TESTING_CONCURRENT_INIT BIT(7)
+#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8)
+#define TDLS_TESTING_DECLINE_RESP BIT(9)
+#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
+unsigned int tdls_testing = 0;
+#endif /* CONFIG_TDLS_TESTING */
+
+#define TPK_LIFETIME 43200 /* 12 hours */
+#define TPK_RETRY_COUNT 3
+#define TPK_TIMEOUT 5000 /* in milliseconds */
+
+#define TDLS_MIC_LEN		16
+
+#define TDLS_TIMEOUT_LEN	4
+
+struct wpa_tdls_ftie {
+	u8 ie_type; /* FTIE */
+	u8 ie_len;
+	u8 mic_ctrl[2];
+	u8 mic[TDLS_MIC_LEN];
+	u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */
+	u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */
+	/* followed by optional elements */
+} STRUCT_PACKED;
+
+struct wpa_tdls_timeoutie {
+	u8 ie_type; /* Timeout IE */
+	u8 ie_len;
+	u8 interval_type;
+	u8 value[TDLS_TIMEOUT_LEN];
+} STRUCT_PACKED;
+
+struct wpa_tdls_lnkid {
+	u8 ie_type; /* Link Identifier IE */
+	u8 ie_len;
+	u8 bssid[ETH_ALEN];
+	u8 init_sta[ETH_ALEN];
+	u8 resp_sta[ETH_ALEN];
+} STRUCT_PACKED;
+
+/* TDLS frame headers as per IEEE Std 802.11z-2010 */
+struct wpa_tdls_frame {
+	u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */
+	u8 category; /* Category */
+	u8 action; /* Action (enum tdls_frame_type) */
+} STRUCT_PACKED;
+
+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+
+
+#define TDLS_MAX_IE_LEN 80
+#define IEEE80211_MAX_SUPP_RATES 32
+
+struct wpa_tdls_peer {
+	struct wpa_tdls_peer *next;
+	int initiator; /* whether this end was initiator for TDLS setup */
+	u8 addr[ETH_ALEN]; /* other end MAC address */
+	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
+	u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */
+	u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */
+	size_t rsnie_i_len;
+	u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */
+	size_t rsnie_p_len;
+	u32 lifetime;
+	int cipher; /* Selected cipher (WPA_CIPHER_*) */
+	u8 dtoken;
+
+	struct tpk {
+		u8 kck[16]; /* TPK-KCK */
+		u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
+	} tpk;
+	int tpk_set;
+	int tpk_success;
+
+	struct tpk_timer {
+		u8 dest[ETH_ALEN];
+		int count;      /* Retry Count */
+		int timer;      /* Timeout in milliseconds */
+		u8 action_code; /* TDLS frame type */
+		u8 dialog_token;
+		u16 status_code;
+		int buf_len;    /* length of TPK message for retransmission */
+		u8 *buf;        /* buffer for TPK message */
+	} sm_tmr;
+
+	u16 capability;
+
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+	size_t supp_rates_len;
+};
+
+
+static int wpa_tdls_get_privacy(struct wpa_sm *sm)
+{
+	/*
+	 * Get info needed from supplicant to check if the current BSS supports
+	 * security. Other than OPEN mode, rest are considered secured
+	 * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake.
+	 */
+	return sm->pairwise_cipher != WPA_CIPHER_NONE;
+}
+
+
+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
+{
+	os_memcpy(pos, ie, ie_len);
+	return pos + ie_len;
+}
+
+
+static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+	if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
+			   0, 0, NULL, 0, NULL, 0) < 0) {
+		wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
+			   "the driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+	u8 key_len;
+	u8 rsc[6];
+	enum wpa_alg alg;
+
+	os_memset(rsc, 0, 6);
+
+	switch (peer->cipher) {
+	case WPA_CIPHER_CCMP:
+		alg = WPA_ALG_CCMP;
+		key_len = 16;
+		break;
+	case WPA_CIPHER_NONE:
+		wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: "
+			   "NONE - do not use pairwise keys");
+		return -1;
+	default:
+		wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d",
+			   sm->pairwise_cipher);
+		return -1;
+	}
+
+	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
+			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
+			   "driver");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
+				 u8 action_code, u8 dialog_token,
+				 u16 status_code, const u8 *buf, size_t len)
+{
+	return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
+				     status_code, buf, len);
+}
+
+
+static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
+			     u8 dialog_token, u16 status_code,
+			     const u8 *msg, size_t msg_len)
+{
+	struct wpa_tdls_peer *peer;
+
+	wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u "
+		   "dialog_token=%u status_code=%u msg_len=%u",
+		   MAC2STR(dest), action_code, dialog_token, status_code,
+		   (unsigned int) msg_len);
+
+	if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
+				  status_code, msg, msg_len)) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to send message "
+			   "(action_code=%u)", action_code);
+		return -1;
+	}
+
+	if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
+	    action_code == WLAN_TDLS_TEARDOWN ||
+	    action_code == WLAN_TDLS_DISCOVERY_REQUEST ||
+	    action_code == WLAN_TDLS_DISCOVERY_RESPONSE)
+		return 0; /* No retries */
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+			   "retry " MACSTR, MAC2STR(dest));
+		return 0;
+	}
+
+	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+	peer->sm_tmr.count = TPK_RETRY_COUNT;
+	peer->sm_tmr.timer = TPK_TIMEOUT;
+
+	/* Copy message to resend on timeout */
+	os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
+	peer->sm_tmr.action_code = action_code;
+	peer->sm_tmr.dialog_token = dialog_token;
+	peer->sm_tmr.status_code = status_code;
+	peer->sm_tmr.buf_len = msg_len;
+	os_free(peer->sm_tmr.buf);
+	peer->sm_tmr.buf = os_malloc(msg_len);
+	if (peer->sm_tmr.buf == NULL)
+		return -1;
+	os_memcpy(peer->sm_tmr.buf, msg, msg_len);
+
+	wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
+		   "(action_code=%u)", action_code);
+	eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+			       wpa_tdls_tpk_retry_timeout, sm, peer);
+	return 0;
+}
+
+
+static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+				u16 reason_code, int free_peer)
+{
+	int ret;
+
+	if (sm->tdls_external_setup) {
+		ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+
+		/* disable the link after teardown was sent */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	} else {
+		ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+	}
+
+	if (sm->tdls_external_setup || free_peer)
+		wpa_tdls_peer_free(sm, peer);
+
+	return ret;
+}
+
+
+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+
+	struct wpa_sm *sm = eloop_ctx;
+	struct wpa_tdls_peer *peer = timeout_ctx;
+
+	if (peer->sm_tmr.count) {
+		peer->sm_tmr.count--;
+		peer->sm_tmr.timer = TPK_TIMEOUT;
+
+		wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
+			   "(action_code=%u)",
+			   peer->sm_tmr.action_code);
+
+		if (peer->sm_tmr.buf == NULL) {
+			wpa_printf(MSG_INFO, "TDLS: No retry buffer available "
+				   "for action_code=%u",
+				   peer->sm_tmr.action_code);
+			eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm,
+					     peer);
+			return;
+		}
+
+		/* resend TPK Handshake Message to Peer */
+		if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest,
+					  peer->sm_tmr.action_code,
+					  peer->sm_tmr.dialog_token,
+					  peer->sm_tmr.status_code,
+					  peer->sm_tmr.buf,
+					  peer->sm_tmr.buf_len)) {
+			wpa_printf(MSG_INFO, "TDLS: Failed to retry "
+				   "transmission");
+		}
+
+		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+		eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+				       wpa_tdls_tpk_retry_timeout, sm, peer);
+	} else {
+		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+		wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+	}
+}
+
+
+static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm,
+					      struct wpa_tdls_peer *peer,
+					      u8 action_code)
+{
+	if (action_code == peer->sm_tmr.action_code) {
+		wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for "
+			   "action_code=%u", action_code);
+
+		/* Cancel Timeout registered */
+		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+
+		/* free all resources meant for retry */
+		os_free(peer->sm_tmr.buf);
+		peer->sm_tmr.buf = NULL;
+
+		peer->sm_tmr.count = 0;
+		peer->sm_tmr.timer = 0;
+		peer->sm_tmr.buf_len = 0;
+		peer->sm_tmr.action_code = 0xff;
+	} else {
+		wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout "
+			   "(Unknown action_code=%u)", action_code);
+	}
+}
+
+
+static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer,
+				  const u8 *own_addr, const u8 *bssid)
+{
+	u8 key_input[SHA256_MAC_LEN];
+	const u8 *nonce[2];
+	size_t len[2];
+	u8 data[3 * ETH_ALEN];
+
+	/* IEEE Std 802.11z-2010 8.5.9.1:
+	 * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce))
+	 */
+	len[0] = WPA_NONCE_LEN;
+	len[1] = WPA_NONCE_LEN;
+	if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) {
+		nonce[0] = peer->inonce;
+		nonce[1] = peer->rnonce;
+	} else {
+		nonce[0] = peer->rnonce;
+		nonce[1] = peer->inonce;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN);
+	sha256_vector(2, nonce, len, key_input);
+	wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input",
+			key_input, SHA256_MAC_LEN);
+
+	/*
+	 * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK",
+	 *	min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY)
+	 * TODO: is N_KEY really included in KDF Context and if so, in which
+	 * presentation format (little endian 16-bit?) is it used? It gets
+	 * added by the KDF anyway..
+	 */
+
+	if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) {
+		os_memcpy(data, own_addr, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN);
+	} else {
+		os_memcpy(data, peer->addr, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN);
+	}
+	os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN);
+	wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data));
+
+	sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data),
+		   (u8 *) &peer->tpk, sizeof(peer->tpk));
+	wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK",
+			peer->tpk.kck, sizeof(peer->tpk.kck));
+	wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK",
+			peer->tpk.tk, sizeof(peer->tpk.tk));
+	peer->tpk_set = 1;
+}
+
+
+/**
+ * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC
+ * @kck: TPK-KCK
+ * @lnkid: Pointer to the beginning of Link Identifier IE
+ * @rsnie: Pointer to the beginning of RSN IE used for handshake
+ * @timeoutie: Pointer to the beginning of Timeout IE used for handshake
+ * @ftie: Pointer to the beginning of FT IE
+ * @mic: Pointer for writing MIC
+ *
+ * Calculate MIC for TDLS frame.
+ */
+static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid,
+			     const u8 *rsnie, const u8 *timeoutie,
+			     const u8 *ftie, u8 *mic)
+{
+	u8 *buf, *pos;
+	struct wpa_tdls_ftie *_ftie;
+	const struct wpa_tdls_lnkid *_lnkid;
+	int ret;
+	int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] +
+		2 + timeoutie[1] + 2 + ftie[1];
+	buf = os_zalloc(len);
+	if (!buf) {
+		wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation");
+		return -1;
+	}
+
+	pos = buf;
+	_lnkid = (const struct wpa_tdls_lnkid *) lnkid;
+	/* 1) TDLS initiator STA MAC address */
+	os_memcpy(pos, _lnkid->init_sta, ETH_ALEN);
+	pos += ETH_ALEN;
+	/* 2) TDLS responder STA MAC address */
+	os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN);
+	pos += ETH_ALEN;
+	/* 3) Transaction Sequence number */
+	*pos++ = trans_seq;
+	/* 4) Link Identifier IE */
+	os_memcpy(pos, lnkid, 2 + lnkid[1]);
+	pos += 2 + lnkid[1];
+	/* 5) RSN IE */
+	os_memcpy(pos, rsnie, 2 + rsnie[1]);
+	pos += 2 + rsnie[1];
+	/* 6) Timeout Interval IE */
+	os_memcpy(pos, timeoutie, 2 + timeoutie[1]);
+	pos += 2 + timeoutie[1];
+	/* 7) FTIE, with the MIC field of the FTIE set to 0 */
+	os_memcpy(pos, ftie, 2 + ftie[1]);
+	_ftie = (struct wpa_tdls_ftie *) pos;
+	os_memset(_ftie->mic, 0, TDLS_MIC_LEN);
+	pos += 2 + ftie[1];
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+	wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16);
+	ret = omac1_aes_128(kck, buf, pos - buf, mic);
+	os_free(buf);
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+	return ret;
+}
+
+
+/**
+ * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame
+ * @kck: TPK-KCK
+ * @trans_seq: Transaction Sequence Number (4 - Teardown)
+ * @rcode: Reason code for Teardown
+ * @dtoken: Dialog Token used for that particular link
+ * @lnkid: Pointer to the beginning of Link Identifier IE
+ * @ftie: Pointer to the beginning of FT IE
+ * @mic: Pointer for writing MIC
+ *
+ * Calculate MIC for TDLS frame.
+ */
+static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode,
+				     u8 dtoken, const u8 *lnkid,
+				     const u8 *ftie, u8 *mic)
+{
+	u8 *buf, *pos;
+	struct wpa_tdls_ftie *_ftie;
+	int ret;
+	int len;
+
+	if (lnkid == NULL)
+		return -1;
+
+	len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) +
+		sizeof(trans_seq) + 2 + ftie[1];
+
+	buf = os_zalloc(len);
+	if (!buf) {
+		wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation");
+		return -1;
+	}
+
+	pos = buf;
+	/* 1) Link Identifier IE */
+	os_memcpy(pos, lnkid, 2 + lnkid[1]);
+	pos += 2 + lnkid[1];
+	/* 2) Reason Code */
+	WPA_PUT_LE16(pos, rcode);
+	pos += sizeof(rcode);
+	/* 3) Dialog token */
+	*pos++ = dtoken;
+	/* 4) Transaction Sequence number */
+	*pos++ = trans_seq;
+	/* 7) FTIE, with the MIC field of the FTIE set to 0 */
+	os_memcpy(pos, ftie, 2 + ftie[1]);
+	_ftie = (struct wpa_tdls_ftie *) pos;
+	os_memset(_ftie->mic, 0, TDLS_MIC_LEN);
+	pos += 2 + ftie[1];
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf);
+	wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16);
+	ret = omac1_aes_128(kck, buf, pos - buf, mic);
+	os_free(buf);
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16);
+	return ret;
+}
+
+
+static int wpa_supplicant_verify_tdls_mic(u8 trans_seq,
+					  struct wpa_tdls_peer *peer,
+					  const u8 *lnkid, const u8 *timeoutie,
+					  const struct wpa_tdls_ftie *ftie)
+{
+	u8 mic[16];
+
+	if (peer->tpk_set) {
+		wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid,
+				  peer->rsnie_p, timeoutie, (u8 *) ftie,
+				  mic);
+		if (os_memcmp(mic, ftie->mic, 16) != 0) {
+			wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - "
+				   "dropping packet");
+			wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC",
+				    ftie->mic, 16);
+			wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC",
+				    mic, 16);
+			return -1;
+		}
+	} else {
+		wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, "
+			   "TPK not set - dropping packet");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpa_supplicant_verify_tdls_mic_teardown(
+	u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer,
+	const u8 *lnkid, const struct wpa_tdls_ftie *ftie)
+{
+	u8 mic[16];
+
+	if (peer->tpk_set) {
+		wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode,
+					  dtoken, lnkid, (u8 *) ftie, mic);
+		if (os_memcmp(mic, ftie->mic, 16) != 0) {
+			wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - "
+				   "dropping packet");
+			return -1;
+		}
+	} else {
+		wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown "
+			   "MIC, TPK not set - dropping packet");
+		return -1;
+	}
+	return 0;
+}
+
+
+static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+	struct wpa_tdls_peer *peer = timeout_ctx;
+
+	/*
+	 * On TPK lifetime expiration, we have an option of either tearing down
+	 * the direct link or trying to re-initiate it. The selection of what
+	 * to do is not strictly speaking controlled by our role in the expired
+	 * link, but for now, use that to select whether to renew or tear down
+	 * the link.
+	 */
+
+	if (peer->initiator) {
+		wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
+			   " - try to renew", MAC2STR(peer->addr));
+		wpa_tdls_start(sm, peer->addr);
+	} else {
+		wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
+			   " - tear down", MAC2STR(peer->addr));
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+	}
+}
+
+
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
+		   MAC2STR(peer->addr));
+	eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+	peer->initiator = 0;
+	os_free(peer->sm_tmr.buf);
+	peer->sm_tmr.buf = NULL;
+	peer->rsnie_i_len = peer->rsnie_p_len = 0;
+	peer->cipher = 0;
+	peer->tpk_set = peer->tpk_success = 0;
+	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
+	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
+	os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
+}
+
+
+static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+			    struct wpa_tdls_lnkid *lnkid)
+{
+	lnkid->ie_type = WLAN_EID_LINK_ID;
+	lnkid->ie_len = 3 * ETH_ALEN;
+	os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN);
+	if (peer->initiator) {
+		os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN);
+		os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN);
+	} else {
+		os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN);
+		os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN);
+	}
+}
+
+
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+	struct wpa_tdls_peer *peer;
+	struct wpa_tdls_ftie *ftie;
+	struct wpa_tdls_lnkid lnkid;
+	u8 dialog_token;
+	u8 *rbuf, *pos;
+	int ielen;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	/* Find the node and free from the list */
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+			   "Teardown " MACSTR, MAC2STR(addr));
+		return 0;
+	}
+
+	dialog_token = peer->dtoken;
+
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
+		   MAC2STR(addr));
+
+	ielen = 0;
+	if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) {
+		/* To add FTIE for Teardown request and compute MIC */
+		ielen += sizeof(*ftie);
+#ifdef CONFIG_TDLS_TESTING
+		if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+			ielen += 170;
+#endif /* CONFIG_TDLS_TESTING */
+	}
+
+	rbuf = os_zalloc(ielen + 1);
+	if (rbuf == NULL)
+		return -1;
+	pos = rbuf;
+
+	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+		goto skip_ies;
+
+	ftie = (struct wpa_tdls_ftie *) pos;
+	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+	/* Using the recent nonce which should be for CONFIRM frame */
+	os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+	ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+	pos = (u8 *) (ftie + 1);
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+			   "FTIE");
+		ftie->ie_len += 170;
+		*pos++ = 255; /* FTIE subelem */
+		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake",
+		    (u8 *) ftie, pos - (u8 *) ftie);
+
+	/* compute MIC before sending */
+	wpa_tdls_linkid(sm, peer, &lnkid);
+	wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code,
+				  dialog_token, (u8 *) &lnkid, (u8 *) ftie,
+				  ftie->mic);
+
+skip_ies:
+	/* TODO: register for a Timeout handler, if Teardown is not received at
+	 * the other end, then try again another time */
+
+	/* request driver to send Teardown using this FTIE */
+	wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
+			  WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
+			  pos - rbuf);
+	os_free(rbuf);
+
+	/* clear the Peerkey statemachine */
+	wpa_tdls_peer_free(sm, peer);
+
+	return 0;
+}
+
+
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR
+		   " for link Teardown", MAC2STR(addr));
+		return -1;
+	}
+
+	if (!peer->tpk_success) {
+		wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+		   " not connected - cannot Teardown link", MAC2STR(addr));
+		return -1;
+	}
+
+	return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+}
+
+
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer) {
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+		wpa_tdls_peer_free(sm, peer);
+	}
+}
+
+
+static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
+				  const u8 *buf, size_t len)
+{
+	struct wpa_tdls_peer *peer = NULL;
+	struct wpa_tdls_ftie *ftie;
+	struct wpa_tdls_lnkid *lnkid;
+	struct wpa_eapol_ie_parse kde;
+	u16 reason_code;
+	const u8 *pos;
+	int ielen;
+
+	/* Find the node and free from the list */
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
+			   "Teardown " MACSTR, MAC2STR(src_addr));
+		return 0;
+	}
+
+	pos = buf;
+	pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+	reason_code = WPA_GET_LE16(pos);
+	pos += 2;
+
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR
+		   " (reason code %u)", MAC2STR(src_addr), reason_code);
+
+	ielen = len - (pos - buf); /* start of IE in buf */
+	if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown");
+		return -1;
+	}
+
+	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+		wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
+			   "Teardown");
+		return -1;
+	}
+	lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+		goto skip_ftie;
+
+	if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown");
+		return -1;
+	}
+
+	ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+	/* Process MIC check to see if TDLS Teardown is right */
+	if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code,
+						    peer->dtoken, peer,
+						    (u8 *) lnkid, ftie) < 0) {
+		wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS "
+			   "Teardown Request from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+skip_ftie:
+	/*
+	 * Request the driver to disable the direct link and clear associated
+	 * keys.
+	 */
+	wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+
+	/* clear the Peerkey statemachine */
+	wpa_tdls_peer_free(sm, peer);
+
+	return 0;
+}
+
+
+/**
+ * wpa_tdls_send_error - To send suitable TDLS status response with
+ *	appropriate status code mentioning reason for error/failure.
+ * @dst 	- MAC addr of Peer station
+ * @tdls_action - TDLS frame type for which error code is sent
+ * @status 	- status code mentioning reason
+ */
+
+static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
+			       u8 tdls_action, u8 dialog_token, u16 status)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR
+		   " (action=%u status=%u)",
+		   MAC2STR(dst), tdls_action, status);
+	return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
+				 NULL, 0);
+}
+
+
+static struct wpa_tdls_peer *
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
+		   MAC2STR(addr));
+
+	peer = os_zalloc(sizeof(*peer));
+	if (peer == NULL)
+		return NULL;
+
+	os_memcpy(peer->addr, addr, ETH_ALEN);
+	peer->next = sm->tdls;
+	sm->tdls = peer;
+
+	return peer;
+}
+
+
+static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
+				struct wpa_tdls_peer *peer)
+{
+	size_t buf_len;
+	struct wpa_tdls_timeoutie timeoutie;
+	u16 rsn_capab;
+	struct wpa_tdls_ftie *ftie;
+	u8 *rbuf, *pos, *count_pos;
+	u16 count;
+	struct rsn_ie_hdr *hdr;
+
+	if (!wpa_tdls_get_privacy(sm)) {
+		wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
+		peer->rsnie_i_len = 0;
+		goto skip_rsnie;
+	}
+
+	/*
+	 * TPK Handshake Message 1:
+	 * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I,
+	 * Timeout Interval IE))
+	 */
+
+	/* Filling RSN IE */
+	hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+
+	pos = (u8 *) (hdr + 1);
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+	pos += RSN_SELECTOR_LEN;
+	count_pos = pos;
+	pos += 2;
+
+	count = 0;
+
+	/*
+	 * AES-CCMP is the default Encryption preferred for TDLS, so
+	 * RSN IE is filled only with CCMP CIPHER
+	 * Note: TKIP is not used to encrypt TDLS link.
+	 *
+	 * Regardless of the cipher used on the AP connection, select CCMP
+	 * here.
+	 */
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+	count++;
+
+	WPA_PUT_LE16(count_pos, count);
+
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+	pos += RSN_SELECTOR_LEN;
+
+	rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+	rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) {
+		wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for "
+			   "testing");
+		rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	WPA_PUT_LE16(pos, rsn_capab);
+	pos += 2;
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) {
+		/* Number of PMKIDs */
+		*pos++ = 0x00;
+		*pos++ = 0x00;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	hdr->len = (pos - peer->rsnie_i) - 2;
+	peer->rsnie_i_len = pos - peer->rsnie_i;
+	wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
+		    peer->rsnie_i, peer->rsnie_i_len);
+
+skip_rsnie:
+	buf_len = 0;
+	if (wpa_tdls_get_privacy(sm))
+		buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+			sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+	if (wpa_tdls_get_privacy(sm) &&
+	    (tdls_testing & TDLS_TESTING_LONG_FRAME))
+		buf_len += 170;
+	if (tdls_testing & TDLS_TESTING_DIFF_BSSID)
+		buf_len += sizeof(struct wpa_tdls_lnkid);
+#endif /* CONFIG_TDLS_TESTING */
+	rbuf = os_zalloc(buf_len + 1);
+	if (rbuf == NULL) {
+		wpa_tdls_peer_free(sm, peer);
+		return -1;
+	}
+	pos = rbuf;
+
+	if (!wpa_tdls_get_privacy(sm))
+		goto skip_ies;
+
+	/* Initiator RSN IE */
+	pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+
+	ftie = (struct wpa_tdls_ftie *) pos;
+	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+	ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+
+	if (os_get_random(peer->inonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"TDLS: Failed to get random data for initiator Nonce");
+		os_free(rbuf);
+		wpa_tdls_peer_free(sm, peer);
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
+		    peer->inonce, WPA_NONCE_LEN);
+	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1",
+		    (u8 *) ftie, sizeof(struct wpa_tdls_ftie));
+
+	pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+			   "FTIE");
+		ftie->ie_len += 170;
+		*pos++ = 255; /* FTIE subelem */
+		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	/* Lifetime */
+	peer->lifetime = TPK_LIFETIME;
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK "
+			   "lifetime");
+		peer->lifetime = 301;
+	}
+	if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK "
+			   "lifetime");
+		peer->lifetime = 0xffffffff;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+				     sizeof(timeoutie), peer->lifetime);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+
+skip_ies:
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
+			   "Link Identifier");
+		struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
+		wpa_tdls_linkid(sm, peer, l);
+		l->bssid[5] ^= 0x01;
+		pos += sizeof(*l);
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK "
+		   "Handshake Message 1 (peer " MACSTR ")",
+		   MAC2STR(peer->addr));
+
+	wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
+			  rbuf, pos - rbuf);
+	os_free(rbuf);
+
+	return 0;
+}
+
+
+static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
+				const unsigned char *src_addr, u8 dtoken,
+				struct wpa_tdls_lnkid *lnkid,
+				const struct wpa_tdls_peer *peer)
+{
+	u8 *rbuf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+	struct wpa_tdls_timeoutie timeoutie;
+	struct wpa_tdls_ftie *ftie;
+
+	buf_len = 0;
+	if (wpa_tdls_get_privacy(sm)) {
+		/* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce),
+		 * Lifetime */
+		buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+			sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+		if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+			buf_len += 170;
+#endif /* CONFIG_TDLS_TESTING */
+	}
+
+	rbuf = os_zalloc(buf_len + 1);
+	if (rbuf == NULL)
+		return -1;
+	pos = rbuf;
+
+	if (!wpa_tdls_get_privacy(sm))
+		goto skip_ies;
+
+	/* Peer RSN IE */
+	pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
+
+	ftie = (struct wpa_tdls_ftie *) pos;
+	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+	/* TODO: ftie->mic_control to set 2-RESPONSE */
+	os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+	ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2",
+		    (u8 *) ftie, sizeof(*ftie));
+
+	pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+			   "FTIE");
+		ftie->ie_len += 170;
+		*pos++ = 255; /* FTIE subelem */
+		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	/* Lifetime */
+	lifetime = peer->lifetime;
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK "
+			   "lifetime in response");
+		lifetime++;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+				     sizeof(timeoutie), lifetime);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator",
+		   lifetime);
+
+	/* compute MIC before sending */
+	wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
+			  (u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+
+skip_ies:
+	wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
+			  rbuf, pos - rbuf);
+	os_free(rbuf);
+
+	return 0;
+}
+
+
+static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
+				const unsigned char *src_addr, u8 dtoken,
+				struct wpa_tdls_lnkid *lnkid,
+				const struct wpa_tdls_peer *peer)
+{
+	u8 *rbuf, *pos;
+	size_t buf_len;
+	struct wpa_tdls_ftie *ftie;
+	struct wpa_tdls_timeoutie timeoutie;
+	u32 lifetime;
+
+	buf_len = 0;
+	if (wpa_tdls_get_privacy(sm)) {
+		/* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce),
+		 * Lifetime */
+		buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
+			sizeof(struct wpa_tdls_timeoutie);
+#ifdef CONFIG_TDLS_TESTING
+		if (tdls_testing & TDLS_TESTING_LONG_FRAME)
+			buf_len += 170;
+#endif /* CONFIG_TDLS_TESTING */
+	}
+
+	rbuf = os_zalloc(buf_len + 1);
+	if (rbuf == NULL)
+		return -1;
+	pos = rbuf;
+
+	if (!wpa_tdls_get_privacy(sm))
+		goto skip_ies;
+
+	/* Peer RSN IE */
+	pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
+
+	ftie = (struct wpa_tdls_ftie *) pos;
+	ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+	/*TODO: ftie->mic_control to set 3-CONFIRM */
+	os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
+	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
+	ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
+
+	pos = (u8 *) (ftie + 1);
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
+			   "FTIE");
+		ftie->ie_len += 170;
+		*pos++ = 255; /* FTIE subelem */
+		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	/* Lifetime */
+	lifetime = peer->lifetime;
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK "
+			   "lifetime in confirm");
+		lifetime++;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+				     sizeof(timeoutie), lifetime);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds",
+		   lifetime);
+
+	/* compute MIC before sending */
+	wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
+			  (u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+
+skip_ies:
+	wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
+			  rbuf, pos - rbuf);
+	os_free(rbuf);
+
+	return 0;
+}
+
+
+static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
+					    struct wpa_tdls_peer *peer,
+					    u8 dialog_token)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
+		   "(peer " MACSTR ")", MAC2STR(peer->addr));
+
+	return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+				 dialog_token, 0, NULL, 0);
+}
+
+
+static int
+wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_eapol_ie_parse kde;
+	const struct wpa_tdls_lnkid *lnkid;
+	struct wpa_tdls_peer *peer;
+	size_t min_req_len = sizeof(struct wpa_tdls_frame) +
+		1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid);
+	u8 dialog_token;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR,
+		   MAC2STR(addr));
+
+	if (len < min_req_len) {
+		wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: "
+			   "%d", (int) len);
+		return -1;
+	}
+
+	dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+
+	if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
+				     len - (sizeof(struct wpa_tdls_frame) + 1),
+				     &kde) < 0)
+		return -1;
+
+	if (!kde.lnkid) {
+		wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
+			   "Request");
+		return -1;
+	}
+
+	lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different "
+			   " BSS " MACSTR, MAC2STR(lnkid->bssid));
+		return -1;
+	}
+
+	peer = wpa_tdls_add_peer(sm, addr);
+	if (peer == NULL)
+		return -1;
+
+	return wpa_tdls_send_discovery_response(sm, peer, dialog_token);
+}
+
+
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
+		   MACSTR, MAC2STR(addr));
+	return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
+				 1, 0, NULL, 0);
+}
+
+
+static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
+			   struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_rates) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
+		return -1;
+	}
+
+	peer->supp_rates_len = kde->supp_rates_len - 2;
+	if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
+		peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
+	os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
+
+	if (kde->ext_supp_rates) {
+		int clen = kde->ext_supp_rates_len - 2;
+		if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
+			clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
+		os_memcpy(peer->supp_rates + peer->supp_rates_len,
+			  kde->ext_supp_rates + 2, clen);
+		peer->supp_rates_len += clen;
+	}
+
+	return 0;
+}
+
+
+static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_tdls_peer *peer;
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_ie_data ie;
+	int cipher;
+	const u8 *cpos;
+	struct wpa_tdls_ftie *ftie = NULL;
+	struct wpa_tdls_timeoutie *timeoutie;
+	struct wpa_tdls_lnkid *lnkid;
+	u32 lifetime = 0;
+#if 0
+	struct rsn_ie_hdr *hdr;
+	u8 *pos;
+	u16 rsn_capab;
+	u16 rsn_ver;
+#endif
+	u8 dtoken;
+	u16 ielen;
+	u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	int tdls_prohibited = sm->tdls_prohibited;
+	int existing_peer = 0;
+
+	if (len < 3 + 3)
+		return -1;
+
+	cpos = buf;
+	cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+	/* driver had already verified the frame format */
+	dtoken = *cpos++; /* dialog token */
+
+	wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
+			existing_peer = 1;
+			break;
+		}
+	}
+
+	if (peer == NULL) {
+		peer = wpa_tdls_add_peer(sm, src_addr);
+		if (peer == NULL)
+			goto error;
+	}
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(cpos);
+	cpos += 2;
+
+	ielen = len - (cpos - buf); /* start of IE in buf */
+	if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1");
+		goto error;
+	}
+
+	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+		wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
+			   "TPK M1");
+		goto error;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1",
+		    kde.lnkid, kde.lnkid_len);
+	lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
+		status = WLAN_STATUS_NOT_IN_SAME_BSS;
+		goto error;
+	}
+
+	wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
+		   MAC2STR(src_addr));
+
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+		for (peer = sm->tdls; peer; peer = peer->next) {
+			if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+				break;
+		}
+		if (peer == NULL) {
+			peer = wpa_tdls_add_peer(sm, src_addr);
+			if (peer == NULL)
+				goto error;
+		}
+		wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
+			   "TDLS setup - send own request");
+		peer->initiator = 1;
+		wpa_tdls_send_tpk_m1(sm, peer);
+	}
+
+	if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
+	    tdls_prohibited) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition "
+			   "on TDLS");
+		tdls_prohibited = 0;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	if (tdls_prohibited) {
+		wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS");
+		status = WLAN_STATUS_REQUEST_DECLINED;
+		goto error;
+	}
+
+	if (!wpa_tdls_get_privacy(sm)) {
+		if (kde.rsn_ie) {
+			wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while "
+				   "security is disabled");
+			status = WLAN_STATUS_SECURITY_DISABLED;
+			goto error;
+		}
+		goto skip_rsn;
+	}
+
+	if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) ||
+	    kde.rsn_ie == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1");
+		status = WLAN_STATUS_INVALID_PARAMETERS;
+		goto error;
+	}
+
+	if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+		wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in "
+			   "TPK M1");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto error;
+	}
+
+	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto error;
+	}
+
+	cipher = ie.pairwise_cipher;
+	if (cipher & WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
+		cipher = WPA_CIPHER_CCMP;
+	} else {
+		wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1");
+		status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		goto error;
+	}
+
+	if ((ie.capabilities &
+	     (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) !=
+	    WPA_CAPABILITY_PEERKEY_ENABLED) {
+		wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in "
+			   "TPK M1");
+		status = WLAN_STATUS_INVALID_RSN_IE_CAPAB;
+		goto error;
+	}
+
+	/* Lifetime */
+	if (kde.key_lifetime == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1");
+		status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+		goto error;
+	}
+	timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+	lifetime = WPA_GET_LE32(timeoutie->value);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime);
+	if (lifetime < 300) {
+		wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime");
+		status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+		goto error;
+	}
+
+skip_rsn:
+	/* If found, use existing entry instead of adding a new one;
+	 * how to handle the case where both ends initiate at the
+	 * same time? */
+	if (existing_peer) {
+		if (peer->tpk_success) {
+			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+				   "direct link is enabled - tear down the "
+				   "old link first");
+#if 0
+			/* TODO: Disabling the link would be more proper
+			 * operation here, but it seems to trigger a race with
+			 * some drivers handling the new request frame. */
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+#else
+			if (sm->tdls_external_setup)
+				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+						 src_addr);
+			else
+				wpa_tdls_del_key(sm, peer);
+#endif
+			wpa_tdls_peer_free(sm, peer);
+		}
+
+		/*
+		 * An entry is already present, so check if we already sent a
+		 * TDLS Setup Request. If so, compare MAC addresses and let the
+		 * STA with the lower MAC address continue as the initiator.
+		 * The other negotiation is terminated.
+		 */
+		if (peer->initiator) {
+			if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+				wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+					   "from peer with higher address "
+					   MACSTR, MAC2STR(src_addr));
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+					   "from peer with lower address "
+					   MACSTR " (terminate previously "
+					   "initiated negotiation",
+					   MAC2STR(src_addr));
+				wpa_tdls_peer_free(sm, peer);
+			}
+		}
+	}
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+		if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
+			/*
+			 * The request frame from us is going to win, so do not
+			 * replace information based on this request frame from
+			 * the peer.
+			 */
+			goto skip_rsn_check;
+		}
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	peer->initiator = 0; /* Need to check */
+	peer->dtoken = dtoken;
+
+	if (!wpa_tdls_get_privacy(sm)) {
+		peer->rsnie_i_len = 0;
+		peer->rsnie_p_len = 0;
+		peer->cipher = WPA_CIPHER_NONE;
+		goto skip_rsn_check;
+	}
+
+	ftie = (struct wpa_tdls_ftie *) kde.ftie;
+	os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+	os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
+	peer->rsnie_i_len = kde.rsn_ie_len;
+	peer->cipher = cipher;
+
+	if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->ctx, MSG_WARNING,
+			"TDLS: Failed to get random data for responder nonce");
+		wpa_tdls_peer_free(sm, peer);
+		goto error;
+	}
+
+#if 0
+	/* get version info from RSNIE received from Peer */
+	hdr = (struct rsn_ie_hdr *) kde.rsn_ie;
+	rsn_ver = WPA_GET_LE16(hdr->version);
+
+	/* use min(peer's version, out version) */
+	if (rsn_ver > RSN_VERSION)
+		rsn_ver = RSN_VERSION;
+
+	hdr = (struct rsn_ie_hdr *) peer->rsnie_p;
+
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, rsn_ver);
+	pos = (u8 *) (hdr + 1);
+
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+	pos += RSN_SELECTOR_LEN;
+	/* Include only the selected cipher in pairwise cipher suite */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	if (cipher == WPA_CIPHER_CCMP)
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+	pos += RSN_SELECTOR_LEN;
+
+	rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+	rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+	WPA_PUT_LE16(pos, rsn_capab);
+	pos += 2;
+
+	hdr->len = (pos - peer->rsnie_p) - 2;
+	peer->rsnie_p_len = pos - peer->rsnie_p;
+#endif
+
+	/* temp fix: validation of RSNIE later */
+	os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len);
+	peer->rsnie_p_len = peer->rsnie_i_len;
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
+		    peer->rsnie_p, peer->rsnie_p_len);
+
+	peer->lifetime = lifetime;
+
+	wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
+
+skip_rsn_check:
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
+	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
+			    status);
+	return -1;
+}
+
+
+static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+	peer->tpk_success = 1;
+	eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+	if (wpa_tdls_get_privacy(sm)) {
+		u32 lifetime = peer->lifetime;
+		/*
+		 * Start the initiator process a bit earlier to avoid race
+		 * condition with the responder sending teardown request.
+		 */
+		if (lifetime > 3 && peer->initiator)
+			lifetime -= 3;
+		eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout,
+				       sm, peer);
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK "
+			   "expiration");
+		eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+	}
+#endif /* CONFIG_TDLS_TESTING */
+	}
+
+	/* add supported rates and capabilities to the TDLS peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+				peer->supp_rates, peer->supp_rates_len);
+
+	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+}
+
+
+static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_tdls_peer *peer;
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_ie_data ie;
+	int cipher;
+	struct wpa_tdls_ftie *ftie;
+	struct wpa_tdls_timeoutie *timeoutie;
+	struct wpa_tdls_lnkid *lnkid;
+	u32 lifetime;
+	u8 dtoken;
+	int ielen;
+	u16 status;
+	const u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
+		   "(Peer " MACSTR ")", MAC2STR(src_addr));
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+	if (peer == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No matching peer found for "
+			   "TPK M2: " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+	wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
+
+	if (len < 3 + 2 + 1)
+		return -1;
+	pos = buf;
+	pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+	status = WPA_GET_LE16(pos);
+	pos += 2 /* status code */;
+
+	if (status != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
+			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+		return -1;
+	}
+
+	status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	/* TODO: need to verify dialog token matches here or in kernel */
+	dtoken = *pos++; /* dialog token */
+
+	wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
+
+	if (len < 3 + 2 + 1 + 2)
+		return -1;
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(pos);
+	pos += 2;
+
+	ielen = len - (pos - buf); /* start of IE in buf */
+	if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
+		goto error;
+	}
+
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_DECLINE_RESP) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response");
+		status = WLAN_STATUS_REQUEST_DECLINED;
+		goto error;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+		wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
+			   "TPK M2");
+		goto error;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2",
+		    kde.lnkid, kde.lnkid_len);
+	lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS");
+		status = WLAN_STATUS_NOT_IN_SAME_BSS;
+		goto error;
+	}
+
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
+	if (!wpa_tdls_get_privacy(sm)) {
+		peer->rsnie_p_len = 0;
+		peer->cipher = WPA_CIPHER_NONE;
+		goto skip_rsn;
+	}
+
+	if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) ||
+	    kde.rsn_ie == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2");
+		status = WLAN_STATUS_INVALID_PARAMETERS;
+		goto error;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
+		    kde.rsn_ie, kde.rsn_ie_len);
+
+	/*
+	 * FIX: bitwise comparison of RSN IE is not the correct way of
+	 * validation this. It can be different, but certain fields must
+	 * match. Since we list only a single pairwise cipher in TPK M1, the
+	 * memcmp is likely to work in most cases, though.
+	 */
+	if (kde.rsn_ie_len != peer->rsnie_i_len ||
+	    os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) {
+		wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does "
+			   "not match with RSN IE used in TPK M1");
+		wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1",
+			    peer->rsnie_i, peer->rsnie_i_len);
+		wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
+			    kde.rsn_ie, kde.rsn_ie_len);
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto error;
+	}
+
+	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2");
+		status = WLAN_STATUS_INVALID_RSNIE;
+		goto error;
+	}
+
+	cipher = ie.pairwise_cipher;
+	if (cipher == WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
+		cipher = WPA_CIPHER_CCMP;
+	} else {
+		wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2");
+		status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		goto error;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2",
+		    kde.ftie, sizeof(*ftie));
+	ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+	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 */
+		return -1;
+	}
+
+	/* Responder Nonce and RSN IE */
+	os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN);
+	os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len);
+	peer->rsnie_p_len = kde.rsn_ie_len;
+	peer->cipher = cipher;
+
+	/* Lifetime */
+	if (kde.key_lifetime == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2");
+		status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+		goto error;
+	}
+	timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+	lifetime = WPA_GET_LE32(timeoutie->value);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2",
+		   lifetime);
+	if (lifetime != peer->lifetime) {
+		wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
+			   "TPK M2 (expected %u)", lifetime, peer->lifetime);
+		status = WLAN_STATUS_UNACCEPTABLE_LIFETIME;
+		goto error;
+	}
+
+	wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
+
+	/* Process MIC check to see if TPK M2 is right */
+	if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid,
+					   (u8 *) timeoutie, ftie) < 0) {
+		/* Discard the frame */
+		wpa_tdls_del_key(sm, peer);
+		wpa_tdls_peer_free(sm, peer);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+		return -1;
+	}
+
+	wpa_tdls_set_key(sm, peer);
+
+skip_rsn:
+	peer->dtoken = dtoken;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
+		   "TPK Handshake Message 3");
+	wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
+
+	wpa_tdls_enable_link(sm, peer);
+
+	return 0;
+
+error:
+	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
+			    status);
+	if (sm->tdls_external_setup)
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+	return -1;
+}
+
+
+static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_tdls_peer *peer;
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_tdls_ftie *ftie;
+	struct wpa_tdls_timeoutie *timeoutie;
+	struct wpa_tdls_lnkid *lnkid;
+	int ielen;
+	u16 status;
+	const u8 *pos;
+	u32 lifetime;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
+		   "(Peer " MACSTR ")", MAC2STR(src_addr));
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+	if (peer == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No matching peer found for "
+			   "TPK M3: " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+	wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
+
+	if (len < 3 + 3)
+		return -1;
+	pos = buf;
+	pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
+
+	status = WPA_GET_LE16(pos);
+
+	if (status != 0) {
+		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
+			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+		return -1;
+	}
+	pos += 2 /* status code */ + 1 /* dialog token */;
+
+	ielen = len - (pos - buf); /* start of IE in buf */
+	if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
+		wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
+		return -1;
+	}
+
+	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
+		wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
+		    (u8 *) kde.lnkid, kde.lnkid_len);
+	lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
+		return -1;
+	}
+
+	if (!wpa_tdls_get_privacy(sm))
+		goto skip_rsn;
+
+	if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
+		    kde.ftie, sizeof(*ftie));
+	ftie = (struct wpa_tdls_ftie *) kde.ftie;
+
+	if (kde.rsn_ie == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
+		    kde.rsn_ie, kde.rsn_ie_len);
+	if (kde.rsn_ie_len != peer->rsnie_p_len ||
+	    os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
+		wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
+			   "with the one sent in TPK M2");
+		return -1;
+	}
+
+	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");
+		return -1;
+	}
+
+	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");
+		return -1;
+	}
+
+	if (kde.key_lifetime == NULL) {
+		wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
+		return -1;
+	}
+	timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
+	wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
+		    (u8 *) timeoutie, sizeof(*timeoutie));
+	lifetime = WPA_GET_LE32(timeoutie->value);
+	wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3",
+		   lifetime);
+	if (lifetime != peer->lifetime) {
+		wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
+			   "TPK M3 (expected %u)", lifetime, peer->lifetime);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+		return -1;
+	}
+
+	if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
+					   (u8 *) timeoutie, ftie) < 0) {
+		wpa_tdls_del_key(sm, peer);
+		wpa_tdls_peer_free(sm, peer);
+		return -1;
+	}
+
+	if (wpa_tdls_set_key(sm, peer) < 0)
+		return -1;
+
+skip_rsn:
+	wpa_tdls_enable_link(sm, peer);
+
+	return 0;
+}
+
+
+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs)
+{
+	struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie;
+
+	os_memset(lifetime, 0, ie_len);
+	lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL;
+	lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2;
+	lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME;
+	WPA_PUT_LE32(lifetime->value, tsecs);
+	os_memcpy(pos, ie, ie_len);
+	return pos + ie_len;
+}
+
+
+/**
+ * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1)
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peer: MAC address of the peer STA
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Send TPK Handshake Message 1 info to driver to start TDLS
+ * handshake with the peer.
+ */
+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+	int tdls_prohibited = sm->tdls_prohibited;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+#ifdef CONFIG_TDLS_TESTING
+	if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) &&
+	    tdls_prohibited) {
+		wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition "
+			   "on TDLS");
+		tdls_prohibited = 0;
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
+	if (tdls_prohibited) {
+		wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - "
+			   "reject request to start setup");
+		return -1;
+	}
+
+	/* Find existing entry and if found, use that instead of adding
+	 * a new one */
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL) {
+		peer = wpa_tdls_add_peer(sm, addr);
+		if (peer == NULL)
+			return -1;
+	}
+
+	peer->initiator = 1;
+
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL || !peer->tpk_success)
+		return -1;
+
+	if (sm->tdls_external_setup) {
+		/*
+		 * Disable previous link to allow renegotiation to be completed
+		 * on AP path.
+		 */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	}
+
+	return wpa_tdls_start(sm, addr);
+}
+
+
+/**
+ * wpa_supplicant_rx_tdls - Receive TDLS data frame
+ *
+ * This function is called to receive TDLS (ethertype = 0x890d) data frames.
+ */
+static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_sm *sm = ctx;
+	struct wpa_tdls_frame *tf;
+
+	wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
+		    buf, len);
+
+	if (sm->tdls_disabled || !sm->tdls_supported) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled "
+			   "or unsupported by driver");
+		return;
+	}
+
+	if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message");
+		return;
+	}
+
+	if (len < sizeof(*tf)) {
+		wpa_printf(MSG_INFO, "TDLS: Drop too short frame");
+		return;
+	}
+
+	/* Check to make sure its a valid encapsulated TDLS frame */
+	tf = (struct wpa_tdls_frame *) buf;
+	if (tf->payloadtype != 2 /* TDLS_RFTYPE */ ||
+	    tf->category != WLAN_ACTION_TDLS) {
+		wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u "
+			   "category=%u action=%u",
+			   tf->payloadtype, tf->category, tf->action);
+		return;
+	}
+
+	switch (tf->action) {
+	case WLAN_TDLS_SETUP_REQUEST:
+		wpa_tdls_process_tpk_m1(sm, src_addr, buf, len);
+		break;
+	case WLAN_TDLS_SETUP_RESPONSE:
+		wpa_tdls_process_tpk_m2(sm, src_addr, buf, len);
+		break;
+	case WLAN_TDLS_SETUP_CONFIRM:
+		wpa_tdls_process_tpk_m3(sm, src_addr, buf, len);
+		break;
+	case WLAN_TDLS_TEARDOWN:
+		wpa_tdls_recv_teardown(sm, src_addr, buf, len);
+		break;
+	case WLAN_TDLS_DISCOVERY_REQUEST:
+		wpa_tdls_process_discovery_request(sm, src_addr, buf, len);
+		break;
+	default:
+		/* Kernel code will process remaining frames */
+		wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
+			   tf->action);
+		break;
+	}
+}
+
+
+/**
+ * wpa_tdls_init - Initialize driver interface parameters for TDLS
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters for TDLS.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_tdls_init(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return -1;
+
+	sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
+				     sm->ifname,
+				     sm->own_addr,
+				     ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls,
+				     sm, 0);
+	if (sm->l2_tdls == NULL) {
+		wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet "
+			   "connection");
+		return -1;
+	}
+
+	/*
+	 * Drivers that support TDLS but don't implement the get_capa callback
+	 * are assumed to perform everything internally
+	 */
+	if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
+				 &sm->tdls_external_setup) < 0) {
+		sm->tdls_supported = 1;
+		sm->tdls_external_setup = 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by "
+		   "driver", sm->tdls_supported ? "" : " not");
+	wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
+		   sm->tdls_external_setup ? "external" : "internal");
+
+	return 0;
+}
+
+
+static void wpa_tdls_remove_peers(struct wpa_sm *sm)
+{
+	struct wpa_tdls_peer *peer, *tmp;
+
+	peer = sm->tdls;
+	sm->tdls = NULL;
+
+	while (peer) {
+		int res;
+		tmp = peer->next;
+		res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+		wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
+			   MAC2STR(peer->addr), res);
+		wpa_tdls_peer_free(sm, peer);
+		os_free(peer);
+		peer = tmp;
+	}
+}
+
+
+/**
+ * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS
+ *
+ * This function is called to recover driver interface parameters for TDLS
+ * and frees resources allocated for it.
+ */
+void wpa_tdls_deinit(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->l2_tdls)
+		l2_packet_deinit(sm->l2_tdls);
+	sm->l2_tdls = NULL;
+
+	wpa_tdls_remove_peers(sm);
+}
+
+
+void wpa_tdls_assoc(struct wpa_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association");
+	wpa_tdls_remove_peers(sm);
+}
+
+
+void wpa_tdls_disassoc(struct wpa_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation");
+	wpa_tdls_remove_peers(sm);
+}
+
+
+static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+{
+	struct wpa_eapol_ie_parse elems;
+
+	if (ies == NULL)
+		return 0;
+
+	if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
+		return 0;
+
+	if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+		return 0;
+
+	 /* bit 38 - TDLS Prohibited */
+	return !!(elems.ext_capab[2 + 4] & 0x40);
+}
+
+
+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
+{
+	sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
+		   sm->tdls_prohibited ? "prohibited" : "allowed");
+}
+
+
+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
+{
+	if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+		wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
+			   "(Re)Association Response IEs");
+		sm->tdls_prohibited = 1;
+	}
+}
+
+
+void wpa_tdls_enable(struct wpa_sm *sm, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled");
+	sm->tdls_disabled = !enabled;
+}
+
+
+int wpa_tdls_is_external_setup(struct wpa_sm *sm)
+{
+	return sm->tdls_external_setup;
+}

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2566 +0,0 @@
-/*
- * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "wpa.h"
-#include "eloop.h"
-#include "preauth.h"
-#include "pmksa_cache.h"
-#include "wpa_i.h"
-#include "wpa_ie.h"
-#include "peerkey.h"
-
-
-/**
- * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @kck: Key Confirmation Key (KCK, part of PTK)
- * @ver: Version field from Key Info
- * @dest: Destination address for the frame
- * @proto: Ethertype (usually ETH_P_EAPOL)
- * @msg: EAPOL-Key message
- * @msg_len: Length of message
- * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
- */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
-			int ver, const u8 *dest, u16 proto,
-			u8 *msg, size_t msg_len, u8 *key_mic)
-{
-	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
-		/*
-		 * Association event was not yet received; try to fetch
-		 * BSSID from the driver.
-		 */
-		if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
-			wpa_printf(MSG_DEBUG, "WPA: Failed to read BSSID for "
-				   "EAPOL-Key destination address");
-		} else {
-			dest = sm->bssid;
-			wpa_printf(MSG_DEBUG, "WPA: Use BSSID (" MACSTR
-				   ") as the destination for EAPOL-Key",
-				   MAC2STR(dest));
-		}
-	}
-	if (key_mic &&
-	    wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
-		wpa_printf(MSG_ERROR, "WPA: Failed to generate EAPOL-Key "
-			   "version %d MIC", ver);
-		goto out;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
-	wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
-	eapol_sm_notify_tx_eapol_key(sm->eapol);
-out:
-	os_free(msg);
-}
-
-
-/**
- * wpa_sm_key_request - Send EAPOL-Key Request
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @error: Indicate whether this is an Michael MIC error report
- * @pairwise: 1 = error report for pairwise packet, 0 = for group packet
- *
- * Send an EAPOL-Key Request to the current authenticator. This function is
- * used to request rekeying and it is usually called when a local Michael MIC
- * failure is detected.
- */
-void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
-{
-	size_t rlen;
-	struct wpa_eapol_key *reply;
-	int key_info, ver;
-	u8 bssid[ETH_ALEN], *rbuf;
-
-	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
-		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
-	else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	if (wpa_sm_get_bssid(sm, bssid) < 0) {
-		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
-			   "request");
-		return;
-	}
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply), &rlen, (void *) &reply);
-	if (rbuf == NULL)
-		return;
-
-	reply->type = sm->proto == WPA_PROTO_RSN ?
-		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;
-	if (error)
-		key_info |= WPA_KEY_INFO_ERROR;
-	if (pairwise)
-		key_info |= WPA_KEY_INFO_KEY_TYPE;
-	WPA_PUT_BE16(reply->key_info, key_info);
-	WPA_PUT_BE16(reply->key_length, 0);
-	os_memcpy(reply->replay_counter, sm->request_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(reply->key_data_length, 0);
-
-	wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d "
-		   "pairwise=%d ptk_set=%d len=%lu)",
-		   error, pairwise, sm->ptk_set, (unsigned long) rlen);
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
-			   rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
-			   reply->key_mic : NULL);
-}
-
-
-static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
-				  const unsigned char *src_addr,
-				  const u8 *pmkid)
-{
-	int abort_cached = 0;
-
-	if (pmkid && !sm->cur_pmksa) {
-		/* When using drivers that generate RSN IE, wpa_supplicant may
-		 * not have enough time to get the association information
-		 * event before receiving this 1/4 message, so try to find a
-		 * matching PMKSA cache entry here. */
-		sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid);
-		if (sm->cur_pmksa) {
-			wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from "
-				   "PMKSA cache");
-		} else {
-			wpa_printf(MSG_DEBUG, "RSN: no matching PMKID found");
-			abort_cached = 1;
-		}
-	}
-
-	if (pmkid && sm->cur_pmksa &&
-	    os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
-		wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
-		wpa_sm_set_pmk_from_pmksa(sm);
-		wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
-				sm->pmk, sm->pmk_len);
-		eapol_sm_notify_cached(sm->eapol);
-#ifdef CONFIG_IEEE80211R
-		sm->xxkey_len = 0;
-#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 (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;
-		} else {
-#ifdef CONFIG_IEEE80211R
-			u8 buf[2 * PMK_LEN];
-			if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
-			{
-				os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
-				sm->xxkey_len = PMK_LEN;
-				os_memset(buf, 0, sizeof(buf));
-			}
-#endif /* CONFIG_IEEE80211R */
-		}
-		if (res == 0) {
-			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
-					"machines", sm->pmk, pmk_len);
-			sm->pmk_len = pmk_len;
-			if (sm->proto == WPA_PROTO_RSN) {
-				pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len,
-						src_addr, sm->own_addr,
-						sm->network_ctx, sm->key_mgmt);
-			}
-			if (!sm->cur_pmksa && pmkid &&
-			    pmksa_cache_get(sm->pmksa, src_addr, pmkid)) {
-				wpa_printf(MSG_DEBUG, "RSN: the new PMK "
-					   "matches with the PMKID");
-				abort_cached = 0;
-			}
-		} else {
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-				"WPA: Failed to get master session key from "
-				"EAPOL state machines");
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-				"WPA: Key handshake aborted");
-			if (sm->cur_pmksa) {
-				wpa_printf(MSG_DEBUG, "RSN: Cancelled PMKSA "
-					   "caching attempt");
-				sm->cur_pmksa = NULL;
-				abort_cached = 1;
-			} else if (!abort_cached) {
-				return -1;
-			}
-		}
-	}
-
-	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) {
-		/* Send EAPOL-Start to trigger full EAP authentication. */
-		u8 *buf;
-		size_t buflen;
-
-		wpa_printf(MSG_DEBUG, "RSN: no PMKSA entry found - trigger "
-			   "full EAP authentication");
-		buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
-					 NULL, 0, &buflen, NULL);
-		if (buf) {
-			wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
-					  buf, buflen);
-			os_free(buf);
-			return -2;
-		}
-
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @dst: Destination address for the frame
- * @key: Pointer to the EAPOL-Key frame header
- * @ver: Version bits from EAPOL-Key Key Info
- * @nonce: Nonce value for the EAPOL-Key frame
- * @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
- */
-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,
-			       const u8 *wpa_ie, size_t wpa_ie_len,
-			       struct wpa_ptk *ptk)
-{
-	size_t rlen;
-	struct wpa_eapol_key *reply;
-	u8 *rbuf;
-	u8 *rsn_ie_buf = NULL;
-
-	if (wpa_ie == NULL) {
-		wpa_printf(MSG_WARNING, "WPA: No wpa_ie set - cannot "
-			   "generate msg 2/4");
-		return -1;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
-		int res;
-
-		/*
-		 * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
-		 * FTIE from (Re)Association Response.
-		 */
-		rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN +
-				       sm->assoc_resp_ies_len);
-		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,
-				       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,
-				  sm->assoc_resp_ies_len);
-			wpa_ie_len += sm->assoc_resp_ies_len;
-		}
-
-		wpa_ie = rsn_ie_buf;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
-				  NULL, sizeof(*reply) + wpa_ie_len,
-				  &rlen, (void *) &reply);
-	if (rbuf == NULL) {
-		os_free(rsn_ie_buf);
-		return -1;
-	}
-
-	reply->type = sm->proto == WPA_PROTO_RSN ?
-		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	WPA_PUT_BE16(reply->key_info,
-		     ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
-	if (sm->proto == WPA_PROTO_RSN)
-		WPA_PUT_BE16(reply->key_length, 0);
-	else
-		os_memcpy(reply->key_length, key->key_length, 2);
-	os_memcpy(reply->replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
-	os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
-	os_free(rsn_ie_buf);
-
-	os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
-	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
-
-	return 0;
-}
-
-
-static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
-			  const struct wpa_eapol_key *key,
-			  struct wpa_ptk *ptk)
-{
-	size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->key_mgmt))
-		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
-#endif /* CONFIG_IEEE80211R */
-
-	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
-		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
-		       (u8 *) ptk, ptk_len,
-		       wpa_key_mgmt_sha256(sm->key_mgmt));
-	return 0;
-}
-
-
-static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
-					  const unsigned char *src_addr,
-					  const struct wpa_eapol_key *key,
-					  u16 ver)
-{
-	struct wpa_eapol_ie_parse ie;
-	struct wpa_ptk *ptk;
-	u8 buf[8];
-	int res;
-
-	if (wpa_sm_get_network_ctx(sm) == NULL) {
-		wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of "
-			   "4).");
-		return;
-	}
-
-	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
-	wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
-	os_memset(&ie, 0, sizeof(ie));
-
-#ifndef CONFIG_NO_WPA2
-	if (sm->proto == WPA_PROTO_RSN) {
-		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
-		const u8 *_buf = (const u8 *) (key + 1);
-		size_t len = WPA_GET_BE16(key->key_data_length);
-		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
-		wpa_supplicant_parse_ies(_buf, len, &ie);
-		if (ie.pmkid) {
-			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
-				    "Authenticator", ie.pmkid, PMKID_LEN);
-		}
-	}
-#endif /* CONFIG_NO_WPA2 */
-
-	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
-	if (res == -2) {
-		wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - "
-			   "requesting full EAP authentication");
-		return;
-	}
-	if (res)
-		goto failed;
-
-	if (sm->renew_snonce) {
-		if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-				"WPA: Failed to get random data for SNonce");
-			goto failed;
-		}
-		sm->renew_snonce = 0;
-		wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
-			    sm->snonce, WPA_NONCE_LEN);
-	}
-
-	/* Calculate PTK which will be stored as a temporary PTK until it has
-	 * been verified when processing message 3/4. */
-	ptk = &sm->tptk;
-	wpa_derive_ptk(sm, src_addr, key, ptk);
-	/* Supplicant: swap tx/rx Mic keys */
-	os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
-	os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
-	os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
-	sm->tptk_set = 1;
-
-	if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
-				       sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
-				       ptk))
-		goto failed;
-
-	os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
-	return;
-
-failed:
-	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
-}
-
-
-static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_sm *sm = eloop_ctx;
-	rsn_preauth_candidate_process(sm);
-}
-
-
-static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
-					    const u8 *addr, int secure)
-{
-	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-		"WPA: Key negotiation completed with "
-		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
-		wpa_cipher_txt(sm->pairwise_cipher),
-		wpa_cipher_txt(sm->group_cipher));
-	wpa_sm_cancel_auth_timeout(sm);
-	wpa_sm_set_state(sm, WPA_COMPLETED);
-
-	if (secure) {
-		wpa_sm_mlme_setprotection(
-			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
-			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
-		eapol_sm_notify_portValid(sm->eapol, TRUE);
-		if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
-			eapol_sm_notify_eap_success(sm->eapol, TRUE);
-		/*
-		 * Start preauthentication after a short wait to avoid a
-		 * possible race condition between the data receive and key
-		 * configuration after the 4-Way Handshake. This increases the
-		 * likelyhood of the first preauth EAPOL-Start frame getting to
-		 * the target AP.
-		 */
-		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
-	}
-
-	if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
-		wpa_printf(MSG_DEBUG, "RSN: Authenticator accepted "
-			   "opportunistic PMKSA entry - marking it valid");
-		sm->cur_pmksa->opportunistic = 0;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
-		/* Prepare for the next transition */
-		wpa_ft_prepare_auth_request(sm, NULL);
-	}
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_sm *sm = eloop_ctx;
-	wpa_printf(MSG_DEBUG, "WPA: Request PTK rekeying");
-	wpa_sm_key_request(sm, 0, 1);
-}
-
-
-static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key)
-{
-	int keylen, rsclen;
-	enum wpa_alg alg;
-	const u8 *key_rsc;
-	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");
-
-	switch (sm->pairwise_cipher) {
-	case WPA_CIPHER_CCMP:
-		alg = WPA_ALG_CCMP;
-		keylen = 16;
-		rsclen = 6;
-		break;
-	case WPA_CIPHER_TKIP:
-		alg = WPA_ALG_TKIP;
-		keylen = 32;
-		rsclen = 6;
-		break;
-	case WPA_CIPHER_NONE:
-		wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
-			   "NONE - do not use pairwise keys");
-		return 0;
-	default:
-		wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
-			   sm->pairwise_cipher);
-		return -1;
-	}
-
-	if (sm->proto == WPA_PROTO_RSN) {
-		key_rsc = null_rsc;
-	} else {
-		key_rsc = key->key_rsc;
-		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
-	}
-
-	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   (u8 *) sm->ptk.tk1, keylen) < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
-			   "driver (alg=%d keylen=%d bssid=" MACSTR ")",
-			   alg, keylen, MAC2STR(sm->bssid));
-		return -1;
-	}
-
-	if (sm->wpa_ptk_rekey) {
-		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
-		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
-				       sm, NULL);
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_check_group_cipher(int group_cipher,
-					     int keylen, int maxkeylen,
-					     int *key_rsc_len,
-					     enum wpa_alg *alg)
-{
-	int ret = 0;
-
-	switch (group_cipher) {
-	case WPA_CIPHER_CCMP:
-		if (keylen != 16 || maxkeylen < 16) {
-			ret = -1;
-			break;
-		}
-		*key_rsc_len = 6;
-		*alg = WPA_ALG_CCMP;
-		break;
-	case WPA_CIPHER_TKIP:
-		if (keylen != 32 || maxkeylen < 32) {
-			ret = -1;
-			break;
-		}
-		*key_rsc_len = 6;
-		*alg = WPA_ALG_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		if (keylen != 13 || maxkeylen < 13) {
-			ret = -1;
-			break;
-		}
-		*key_rsc_len = 0;
-		*alg = WPA_ALG_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		if (keylen != 5 || maxkeylen < 5) {
-			ret = -1;
-			break;
-		}
-		*key_rsc_len = 0;
-		*alg = WPA_ALG_WEP;
-		break;
-	default:
-		wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
-			   group_cipher);
-		return -1;
-	}
-
-	if (ret < 0 ) {
-		wpa_printf(MSG_WARNING, "WPA: Unsupported %s Group Cipher key "
-			   "length %d (%d).",
-			   wpa_cipher_txt(group_cipher), keylen, maxkeylen);
-	}
-
-	return ret;
-}
-
-
-struct wpa_gtk_data {
-	enum wpa_alg alg;
-	int tx, key_rsc_len, keyidx;
-	u8 gtk[32];
-	int gtk_len;
-};
-
-
-static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
-				      const struct wpa_gtk_data *gd,
-				      const u8 *key_rsc)
-{
-	const u8 *_gtk = gd->gtk;
-	u8 gtk_buf[32];
-
-	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
-	wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
-		   "(keyidx=%d tx=%d len=%d).", gd->keyidx, gd->tx,
-		   gd->gtk_len);
-	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
-	if (sm->group_cipher == WPA_CIPHER_TKIP) {
-		/* Swap Tx/Rx keys for Michael MIC */
-		os_memcpy(gtk_buf, gd->gtk, 16);
-		os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
-		os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
-		_gtk = gtk_buf;
-	}
-	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
-		if (wpa_sm_set_key(sm, gd->alg,
-				   (u8 *) "\xff\xff\xff\xff\xff\xff",
-				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
-				   _gtk, gd->gtk_len) < 0) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to set "
-				   "GTK to the driver (Group only).");
-			return -1;
-		}
-	} else if (wpa_sm_set_key(sm, gd->alg,
-				  (u8 *) "\xff\xff\xff\xff\xff\xff",
-				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
-				  _gtk, gd->gtk_len) < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
-			   "the driver (alg=%d keylen=%d keyidx=%d)",
-			   gd->alg, gd->gtk_len, gd->keyidx);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
-						int tx)
-{
-	if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
-		/* Ignore Tx bit for GTK if a pairwise key is used. One AP
-		 * seemed to set this bit (incorrectly, since Tx is only when
-		 * doing Group Key only APs) and without this workaround, the
-		 * data connection does not work because wpa_supplicant
-		 * configured non-zero keyidx to be used for unicast. */
-		wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but pairwise "
-			   "keys are used - ignore Tx bit");
-		return 0;
-	}
-	return tx;
-}
-
-
-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)
-{
-#ifndef CONFIG_NO_WPA2
-	struct wpa_gtk_data gd;
-
-	/*
-	 * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
-	 * GTK KDE format:
-	 * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7]
-	 * Reserved [bits 0-7]
-	 * GTK
-	 */
-
-	os_memset(&gd, 0, sizeof(gd));
-	wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
-			gtk, gtk_len);
-
-	if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk))
-		return -1;
-
-	gd.keyidx = gtk[0] & 0x3;
-	gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
-						     !!(gtk[0] & BIT(2)));
-	gtk += 2;
-	gtk_len -= 2;
-
-	os_memcpy(gd.gtk, gtk, gtk_len);
-	gd.gtk_len = gtk_len;
-
-	if (wpa_supplicant_check_group_cipher(sm->group_cipher,
-					      gtk_len, gtk_len,
-					      &gd.key_rsc_len, &gd.alg) ||
-	    wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
-		wpa_printf(MSG_DEBUG, "RSN: Failed to install GTK");
-		return -1;
-	}
-
-	wpa_supplicant_key_neg_complete(sm, sm->bssid,
-					key_info & WPA_KEY_INFO_SECURE);
-	return 0;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
-}
-
-
-static int ieee80211w_set_keys(struct wpa_sm *sm,
-			       struct wpa_eapol_ie_parse *ie)
-{
-#ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
-		return 0;
-
-	if (ie->igtk) {
-		const struct wpa_igtk_kde *igtk;
-		u16 keyidx;
-		if (ie->igtk_len != sizeof(*igtk))
-			return -1;
-		igtk = (const struct wpa_igtk_kde *) ie->igtk;
-		keyidx = WPA_GET_LE16(igtk->keyid);
-		wpa_printf(MSG_DEBUG, "WPA: IGTK keyid %d "
-			   "pn %02x%02x%02x%02x%02x%02x",
-			   keyidx, MAC2STR(igtk->pn));
-		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
-				igtk->igtk, WPA_IGTK_LEN);
-		if (keyidx > 4095) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KeyID %d",
-				   keyidx);
-			return -1;
-		}
-		if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
-				   (u8 *) "\xff\xff\xff\xff\xff\xff",
-				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-				   igtk->igtk, WPA_IGTK_LEN) < 0) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to configure IGTK"
-				   " to the driver");
-			return -1;
-		}
-	}
-
-	return 0;
-#else /* CONFIG_IEEE80211W */
-	return 0;
-#endif /* CONFIG_IEEE80211W */
-}
-
-
-static void wpa_report_ie_mismatch(struct wpa_sm *sm,
-				   const char *reason, const u8 *src_addr,
-				   const u8 *wpa_ie, size_t wpa_ie_len,
-				   const u8 *rsn_ie, size_t rsn_ie_len)
-{
-	wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
-		reason, MAC2STR(src_addr));
-
-	if (sm->ap_wpa_ie) {
-		wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
-			    sm->ap_wpa_ie, sm->ap_wpa_ie_len);
-	}
-	if (wpa_ie) {
-		if (!sm->ap_wpa_ie) {
-			wpa_printf(MSG_INFO, "WPA: No WPA IE in "
-				   "Beacon/ProbeResp");
-		}
-		wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg",
-			    wpa_ie, wpa_ie_len);
-	}
-
-	if (sm->ap_rsn_ie) {
-		wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp",
-			    sm->ap_rsn_ie, sm->ap_rsn_ie_len);
-	}
-	if (rsn_ie) {
-		if (!sm->ap_rsn_ie) {
-			wpa_printf(MSG_INFO, "WPA: No RSN IE in "
-				   "Beacon/ProbeResp");
-		}
-		wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg",
-			    rsn_ie, rsn_ie_len);
-	}
-
-	wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-static int ft_validate_mdie(struct wpa_sm *sm,
-			    const unsigned char *src_addr,
-			    struct wpa_eapol_ie_parse *ie,
-			    const u8 *assoc_resp_mdie)
-{
-	struct rsn_mdie *mdie;
-
-	mdie = (struct rsn_mdie *) (ie->mdie + 2);
-	if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: MDIE in msg 3/4 did not "
-			   "match with the current mobility domain");
-		return -1;
-	}
-
-	if (assoc_resp_mdie &&
-	    (assoc_resp_mdie[1] != ie->mdie[1] ||
-	     os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) {
-		wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
-		wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4",
-			    ie->mdie, 2 + ie->mdie[1]);
-		wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response",
-			    assoc_resp_mdie, 2 + assoc_resp_mdie[1]);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int ft_validate_ftie(struct wpa_sm *sm,
-			    const unsigned char *src_addr,
-			    struct wpa_eapol_ie_parse *ie,
-			    const u8 *assoc_resp_ftie)
-{
-	if (ie->ftie == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No FTIE in EAPOL-Key msg 3/4");
-		return -1;
-	}
-
-	if (assoc_resp_ftie == NULL)
-		return 0;
-
-	if (assoc_resp_ftie[1] != ie->ftie[1] ||
-	    os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
-		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4",
-			    ie->ftie, 2 + ie->ftie[1]);
-		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response",
-			    assoc_resp_ftie, 2 + assoc_resp_ftie[1]);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int ft_validate_rsnie(struct wpa_sm *sm,
-			     const unsigned char *src_addr,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	struct wpa_ie_data rsn;
-
-	if (!ie->rsn_ie)
-		return 0;
-
-	/*
-	 * Verify that PMKR1Name from EAPOL-Key message 3/4
-	 * matches with the value we derived.
-	 */
-	if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 ||
-	    rsn.num_pmkid != 1 || rsn.pmkid == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
-			   "FT 4-way handshake message 3/4");
-		return -1;
-	}
-
-	if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: PMKR1Name mismatch in "
-			   "FT 4-way handshake message 3/4");
-		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator",
-			    rsn.pmkid, WPA_PMK_NAME_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
-			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
-					 const unsigned char *src_addr,
-					 struct wpa_eapol_ie_parse *ie)
-{
-	const u8 *pos, *end, *mdie = NULL, *ftie = NULL;
-
-	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)
-				break;
-			switch (*pos) {
-			case WLAN_EID_MOBILITY_DOMAIN:
-				mdie = pos;
-				break;
-			case WLAN_EID_FAST_BSS_TRANSITION:
-				ftie = pos;
-				break;
-			}
-			pos += 2 + pos[1];
-		}
-	}
-
-	if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 ||
-	    ft_validate_ftie(sm, src_addr, ie, ftie) < 0 ||
-	    ft_validate_rsnie(sm, src_addr, ie) < 0)
-		return -1;
-
-	return 0;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
-				      const unsigned char *src_addr,
-				      struct wpa_eapol_ie_parse *ie)
-{
-	if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
-		wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE for this AP known. "
-			   "Trying to get from scan results");
-		if (wpa_sm_get_beacon_ie(sm) < 0) {
-			wpa_printf(MSG_WARNING, "WPA: Could not find AP from "
-				   "the scan results");
-		} else {
-			wpa_printf(MSG_DEBUG, "WPA: Found the current AP from "
-				   "updated scan results");
-		}
-	}
-
-	if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
-	    (sm->ap_wpa_ie || sm->ap_rsn_ie)) {
-		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
-				       "with IE in Beacon/ProbeResp (no IE?)",
-				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
-				       ie->rsn_ie, ie->rsn_ie_len);
-		return -1;
-	}
-
-	if ((ie->wpa_ie && sm->ap_wpa_ie &&
-	     (ie->wpa_ie_len != sm->ap_wpa_ie_len ||
-	      os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
-	    (ie->rsn_ie && sm->ap_rsn_ie &&
-	     wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
-				sm->ap_rsn_ie, sm->ap_rsn_ie_len,
-				ie->rsn_ie, ie->rsn_ie_len))) {
-		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
-				       "with IE in Beacon/ProbeResp",
-				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
-				       ie->rsn_ie, ie->rsn_ie_len);
-		return -1;
-	}
-
-	if (sm->proto == WPA_PROTO_WPA &&
-	    ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) {
-		wpa_report_ie_mismatch(sm, "Possible downgrade attack "
-				       "detected - RSN was enabled and RSN IE "
-				       "was in msg 3/4, but not in "
-				       "Beacon/ProbeResp",
-				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
-				       ie->rsn_ie, ie->rsn_ie_len);
-		return -1;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->key_mgmt) &&
-	    wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
-		return -1;
-#endif /* CONFIG_IEEE80211R */
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @dst: Destination address for the frame
- * @key: Pointer to the EAPOL-Key frame header
- * @ver: Version bits from EAPOL-Key Key Info
- * @key_info: Key Info
- * @kde: KDEs to include the EAPOL-Key frame
- * @kde_len: Length of KDEs
- * @ptk: PTK to use for keyed hash and encryption
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
-			       const struct wpa_eapol_key *key,
-			       u16 ver, u16 key_info,
-			       const u8 *kde, size_t kde_len,
-			       struct wpa_ptk *ptk)
-{
-	size_t rlen;
-	struct wpa_eapol_key *reply;
-	u8 *rbuf;
-
-	if (kde)
-		wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply) + kde_len,
-				  &rlen, (void *) &reply);
-	if (rbuf == NULL)
-		return -1;
-
-	reply->type = sm->proto == WPA_PROTO_RSN ?
-		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	key_info &= WPA_KEY_INFO_SECURE;
-	key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
-	WPA_PUT_BE16(reply->key_info, key_info);
-	if (sm->proto == WPA_PROTO_RSN)
-		WPA_PUT_BE16(reply->key_length, 0);
-	else
-		os_memcpy(reply->key_length, key->key_length, 2);
-	os_memcpy(reply->replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(reply->key_data_length, kde_len);
-	if (kde)
-		os_memcpy(reply + 1, kde, kde_len);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
-	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
-
-	return 0;
-}
-
-
-static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
-					  const struct wpa_eapol_key *key,
-					  u16 ver)
-{
-	u16 key_info, keylen, len;
-	const u8 *pos;
-	struct wpa_eapol_ie_parse ie;
-
-	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
-	wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
-
-	key_info = WPA_GET_BE16(key->key_info);
-
-	pos = (const u8 *) (key + 1);
-	len = WPA_GET_BE16(key->key_data_length);
-	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
-	wpa_supplicant_parse_ies(pos, len, &ie);
-	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-		wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
-		goto failed;
-	}
-#ifdef CONFIG_IEEE80211W
-	if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-		wpa_printf(MSG_WARNING, "WPA: IGTK KDE in unencrypted key "
-			   "data");
-		goto failed;
-	}
-
-	if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
-		wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KDE length %lu",
-			   (unsigned long) ie.igtk_len);
-		goto failed;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
-		goto failed;
-
-	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way "
-			   "Handshake differs from 3 of 4-Way Handshake - drop"
-			   " packet (src=" MACSTR ")", MAC2STR(sm->bssid));
-		goto failed;
-	}
-
-	keylen = WPA_GET_BE16(key->key_length);
-	switch (sm->pairwise_cipher) {
-	case WPA_CIPHER_CCMP:
-		if (keylen != 16) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
-				   "%d (src=" MACSTR ")",
-				   keylen, MAC2STR(sm->bssid));
-			goto failed;
-		}
-		break;
-	case WPA_CIPHER_TKIP:
-		if (keylen != 32) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid TKIP key length "
-				   "%d (src=" MACSTR ")",
-				   keylen, MAC2STR(sm->bssid));
-			goto failed;
-		}
-		break;
-	}
-
-	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
-				       NULL, 0, &sm->ptk)) {
-		goto failed;
-	}
-
-	/* SNonce was successfully used in msg 3/4, so mark it to be renewed
-	 * for the next 4-Way Handshake. If msg 3 is received again, the old
-	 * SNonce will still be used to avoid changing PTK. */
-	sm->renew_snonce = 1;
-
-	if (key_info & WPA_KEY_INFO_INSTALL) {
-		if (wpa_supplicant_install_ptk(sm, key))
-			goto failed;
-	}
-
-	if (key_info & WPA_KEY_INFO_SECURE) {
-		wpa_sm_mlme_setprotection(
-			sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
-			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
-		eapol_sm_notify_portValid(sm->eapol, TRUE);
-	}
-	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
-
-	if (ie.gtk &&
-	    wpa_supplicant_pairwise_gtk(sm, key,
-					ie.gtk, ie.gtk_len, key_info) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to configure GTK");
-		goto failed;
-	}
-
-	if (ieee80211w_set_keys(sm, &ie) < 0) {
-		wpa_printf(MSG_INFO, "RSN: Failed to configure IGTK");
-		goto failed;
-	}
-
-	return;
-
-failed:
-	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
-}
-
-
-static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
-					     const u8 *keydata,
-					     size_t keydatalen,
-					     u16 key_info,
-					     struct wpa_gtk_data *gd)
-{
-	int maxkeylen;
-	struct wpa_eapol_ie_parse ie;
-
-	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
-	wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
-	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-		wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
-		return -1;
-	}
-	if (ie.gtk == NULL) {
-		wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key msg 1/2");
-		return -1;
-	}
-	maxkeylen = gd->gtk_len = ie.gtk_len - 2;
-
-	if (wpa_supplicant_check_group_cipher(sm->group_cipher,
-					      gd->gtk_len, maxkeylen,
-					      &gd->key_rsc_len, &gd->alg))
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
-		    ie.gtk, ie.gtk_len);
-	gd->keyidx = ie.gtk[0] & 0x3;
-	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
-						      !!(ie.gtk[0] & BIT(2)));
-	if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
-		wpa_printf(MSG_INFO, "RSN: Too long GTK in GTK IE "
-			   "(len=%lu)", (unsigned long) ie.gtk_len - 2);
-		return -1;
-	}
-	os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
-
-	if (ieee80211w_set_keys(sm, &ie) < 0)
-		wpa_printf(MSG_INFO, "RSN: Failed to configure IGTK");
-
-	return 0;
-}
-
-
-static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
-					     const struct wpa_eapol_key *key,
-					     size_t keydatalen, int key_info,
-					     size_t extra_len, u16 ver,
-					     struct wpa_gtk_data *gd)
-{
-	size_t maxkeylen;
-	u8 ek[32];
-
-	gd->gtk_len = WPA_GET_BE16(key->key_length);
-	maxkeylen = keydatalen;
-	if (keydatalen > extra_len) {
-		wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
-			   " key_data_length=%lu > extra_len=%lu",
-			   (unsigned long) keydatalen,
-			   (unsigned long) extra_len);
-		return -1;
-	}
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		if (maxkeylen < 8) {
-			wpa_printf(MSG_INFO, "WPA: Too short maxkeylen (%lu)",
-				   (unsigned long) maxkeylen);
-			return -1;
-		}
-		maxkeylen -= 8;
-	}
-
-	if (wpa_supplicant_check_group_cipher(sm->group_cipher,
-					      gd->gtk_len, maxkeylen,
-					      &gd->key_rsc_len, &gd->alg))
-		return -1;
-
-	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
-		WPA_KEY_INFO_KEY_INDEX_SHIFT;
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
-		os_memcpy(ek, key->key_iv, 16);
-		os_memcpy(ek + 16, sm->ptk.kek, 16);
-		if (keydatalen > sizeof(gd->gtk)) {
-			wpa_printf(MSG_WARNING, "WPA: RC4 key data "
-				   "too long (%lu)",
-				   (unsigned long) keydatalen);
-			return -1;
-		}
-		os_memcpy(gd->gtk, key + 1, keydatalen);
-		if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
-			wpa_printf(MSG_ERROR, "WPA: RC4 failed");
-			return -1;
-		}
-	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		if (keydatalen % 8) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported AES-WRAP "
-				   "len %lu", (unsigned long) keydatalen);
-			return -1;
-		}
-		if (maxkeylen > sizeof(gd->gtk)) {
-			wpa_printf(MSG_WARNING, "WPA: AES-WRAP key data "
-				   "too long (keydatalen=%lu maxkeylen=%lu)",
-				   (unsigned long) keydatalen,
-				   (unsigned long) maxkeylen);
-			return -1;
-		}
-		if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
-			       (const u8 *) (key + 1), gd->gtk)) {
-			wpa_printf(MSG_WARNING, "WPA: AES unwrap "
-				   "failed - could not decrypt GTK");
-			return -1;
-		}
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d",
-			   ver);
-		return -1;
-	}
-	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
-		sm, !!(key_info & WPA_KEY_INFO_TXRX));
-	return 0;
-}
-
-
-static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key,
-				      int ver, u16 key_info)
-{
-	size_t rlen;
-	struct wpa_eapol_key *reply;
-	u8 *rbuf;
-
-	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-				  sizeof(*reply), &rlen, (void *) &reply);
-	if (rbuf == NULL)
-		return -1;
-
-	reply->type = sm->proto == WPA_PROTO_RSN ?
-		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
-	key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
-	WPA_PUT_BE16(reply->key_info, key_info);
-	if (sm->proto == WPA_PROTO_RSN)
-		WPA_PUT_BE16(reply->key_length, 0);
-	else
-		os_memcpy(reply->key_length, key->key_length, 2);
-	os_memcpy(reply->replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-
-	WPA_PUT_BE16(reply->key_data_length, 0);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
-	wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
-			   rbuf, rlen, reply->key_mic);
-
-	return 0;
-}
-
-
-static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
-					  const unsigned char *src_addr,
-					  const struct wpa_eapol_key *key,
-					  int extra_len, u16 ver)
-{
-	u16 key_info, keydatalen;
-	int rekey, ret;
-	struct wpa_gtk_data gd;
-
-	os_memset(&gd, 0, sizeof(gd));
-
-	rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
-	wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from "
-		   MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
-	key_info = WPA_GET_BE16(key->key_info);
-	keydatalen = WPA_GET_BE16(key->key_data_length);
-
-	if (sm->proto == WPA_PROTO_RSN) {
-		ret = wpa_supplicant_process_1_of_2_rsn(sm,
-							(const u8 *) (key + 1),
-							keydatalen, key_info,
-							&gd);
-	} else {
-		ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
-							key_info, extra_len,
-							ver, &gd);
-	}
-
-	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
-
-	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))
-		goto failed;
-
-	if (rekey) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
-			"completed with " MACSTR " [GTK=%s]",
-			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
-		wpa_sm_cancel_auth_timeout(sm);
-		wpa_sm_set_state(sm, WPA_COMPLETED);
-	} else {
-		wpa_supplicant_key_neg_complete(sm, sm->bssid,
-						key_info &
-						WPA_KEY_INFO_SECURE);
-	}
-	return;
-
-failed:
-	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
-}
-
-
-static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
-					       struct wpa_eapol_key *key,
-					       u16 ver,
-					       const u8 *buf, size_t len)
-{
-	u8 mic[16];
-	int ok = 0;
-
-	os_memcpy(mic, key->key_mic, 16);
-	if (sm->tptk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-				   "when using TPTK - ignoring TPTK");
-		} else {
-			ok = 1;
-			sm->tptk_set = 0;
-			sm->ptk_set = 1;
-			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
-		}
-	}
-
-	if (!ok && sm->ptk_set) {
-		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
-				  key->key_mic);
-		if (os_memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-				   "- dropping packet");
-			return -1;
-		}
-		ok = 1;
-	}
-
-	if (!ok) {
-		wpa_printf(MSG_WARNING, "WPA: Could not verify EAPOL-Key MIC "
-			   "- dropping packet");
-		return -1;
-	}
-
-	os_memcpy(sm->rx_replay_counter, key->replay_counter,
-		  WPA_REPLAY_COUNTER_LEN);
-	sm->rx_replay_counter_set = 1;
-	return 0;
-}
-
-
-/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
-static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
-					   struct wpa_eapol_key *key, u16 ver)
-{
-	u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
-	wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
-		    (u8 *) (key + 1), keydatalen);
-	if (!sm->ptk_set) {
-		wpa_printf(MSG_WARNING, "WPA: PTK not available, "
-			   "cannot decrypt EAPOL-Key key data.");
-		return -1;
-	}
-
-	/* Decrypt key data here so that this operation does not need
-	 * to be implemented separately for each message type. */
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
-		u8 ek[32];
-		os_memcpy(ek, key->key_iv, 16);
-		os_memcpy(ek + 16, sm->ptk.kek, 16);
-		if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
-			wpa_printf(MSG_ERROR, "WPA: RC4 failed");
-			return -1;
-		}
-	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
-		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-		u8 *buf;
-		if (keydatalen % 8) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported "
-				   "AES-WRAP len %d", keydatalen);
-			return -1;
-		}
-		keydatalen -= 8; /* AES-WRAP adds 8 bytes */
-		buf = os_malloc(keydatalen);
-		if (buf == NULL) {
-			wpa_printf(MSG_WARNING, "WPA: No memory for "
-				   "AES-UNWRAP buffer");
-			return -1;
-		}
-		if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
-			       (u8 *) (key + 1), buf)) {
-			os_free(buf);
-			wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - "
-				   "could not decrypt EAPOL-Key key data");
-			return -1;
-		}
-		os_memcpy(key + 1, buf, keydatalen);
-		os_free(buf);
-		WPA_PUT_BE16(key->key_data_length, keydatalen);
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Unsupported key_info type %d",
-			   ver);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
-			(u8 *) (key + 1), keydatalen);
-	return 0;
-}
-
-
-/**
- * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void wpa_sm_aborted_cached(struct wpa_sm *sm)
-{
-	if (sm && sm->cur_pmksa) {
-		wpa_printf(MSG_DEBUG, "RSN: Cancelling PMKSA caching attempt");
-		sm->cur_pmksa = NULL;
-	}
-}
-
-
-static void wpa_eapol_key_dump(const struct wpa_eapol_key *key)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	u16 key_info = WPA_GET_BE16(key->key_info);
-
-	wpa_printf(MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
-	wpa_printf(MSG_DEBUG, "  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s"
-		   "%s%s%s%s%s%s%s)",
-		   key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
-		   (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
-		   WPA_KEY_INFO_KEY_INDEX_SHIFT,
-		   (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
-		   key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
-		   key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
-		   key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
-		   key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
-		   key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
-		   key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
-		   key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
-		   key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
-	wpa_printf(MSG_DEBUG, "  key_length=%u key_data_length=%u",
-		   WPA_GET_BE16(key->key_length),
-		   WPA_GET_BE16(key->key_data_length));
-	wpa_hexdump(MSG_DEBUG, "  replay_counter",
-		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
-	wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16);
-	wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8);
-	wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8);
-	wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-/**
- * wpa_sm_rx_eapol - Process received WPA EAPOL frames
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @src_addr: Source MAC address of the EAPOL packet
- * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
- * @len: Length of the EAPOL frame
- * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
- *
- * This function is called for each received EAPOL frame. Other than EAPOL-Key
- * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
- * only processing WPA and WPA2 EAPOL-Key frames.
- *
- * The received EAPOL-Key packets are validated and valid packets are replied
- * to. In addition, key material (PTK, GTK) is configured at the end of a
- * successful key handshake.
- */
-int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-		    const u8 *buf, size_t len)
-{
-	size_t plen, data_len, extra_len;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *key;
-	u16 key_info, ver;
-	u8 *tmp;
-	int ret = -1;
-	struct wpa_peerkey *peerkey = NULL;
-
-#ifdef CONFIG_IEEE80211R
-	sm->ft_completed = 0;
-#endif /* CONFIG_IEEE80211R */
-
-	if (len < sizeof(*hdr) + sizeof(*key)) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA "
-			   "EAPOL-Key (len %lu, expecting at least %lu)",
-			   (unsigned long) len,
-			   (unsigned long) sizeof(*hdr) + sizeof(*key));
-		return 0;
-	}
-
-	tmp = os_malloc(len);
-	if (tmp == NULL)
-		return -1;
-	os_memcpy(tmp, buf, len);
-
-	hdr = (struct ieee802_1x_hdr *) tmp;
-	key = (struct wpa_eapol_key *) (hdr + 1);
-	plen = be_to_host16(hdr->length);
-	data_len = plen + sizeof(*hdr);
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%lu",
-		   hdr->version, hdr->type, (unsigned long) plen);
-
-	if (hdr->version < EAPOL_VERSION) {
-		/* TODO: backwards compatibility */
-	}
-	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, "
-			"not a Key frame", hdr->type);
-		ret = 0;
-		goto out;
-	}
-	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu "
-			   "invalid (frame size %lu)",
-			   (unsigned long) plen, (unsigned long) len);
-		ret = 0;
-		goto out;
-	}
-
-	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
-	{
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, "
-			   "discarded", key->type);
-		ret = 0;
-		goto out;
-	}
-	wpa_eapol_key_dump(key);
-
-	eapol_sm_notify_lower_layer_success(sm->eapol, 0);
-	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
-	if (data_len < len) {
-		wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE "
-			   "802.1X data", (unsigned long) len - data_len);
-	}
-	key_info = WPA_GET_BE16(key->key_info);
-	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
-	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
-	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor "
-			   "version %d.", ver);
-		goto out;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
-		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
-		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-			wpa_printf(MSG_INFO, "FT: AP did not use "
-				   "AES-128-CMAC.");
-			goto out;
-		}
-	} else
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
-		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-			wpa_printf(MSG_INFO, "WPA: AP did not use the "
-				   "negotiated AES-128-CMAC.");
-			goto out;
-		}
-	} else
-#endif /* CONFIG_IEEE80211W */
-	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
-	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
-			   "descriptor version (%d) is not 2.", ver);
-		if (sm->group_cipher != WPA_CIPHER_CCMP &&
-		    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
-			/* Earlier versions of IEEE 802.11i did not explicitly
-			 * require version 2 descriptor for all EAPOL-Key
-			 * packets, so allow group keys to use version 1 if
-			 * CCMP is not used for them. */
-			wpa_printf(MSG_INFO, "WPA: Backwards compatibility: "
-				   "allow invalid version for non-CCMP group "
-				   "keys");
-		} else
-			goto out;
-	}
-
-#ifdef CONFIG_PEERKEY
-	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
-		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
-			break;
-	}
-
-	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
-		if (!peerkey->initiator && peerkey->replay_counter_set &&
-		    os_memcmp(key->replay_counter, peerkey->replay_counter,
-			      WPA_REPLAY_COUNTER_LEN) <= 0) {
-			wpa_printf(MSG_WARNING, "RSN: EAPOL-Key Replay "
-				   "Counter did not increase (STK) - dropping "
-				   "packet");
-			goto out;
-		} else if (peerkey->initiator) {
-			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
-			os_memcpy(_tmp, key->replay_counter,
-				  WPA_REPLAY_COUNTER_LEN);
-			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
-			if (os_memcmp(_tmp, peerkey->replay_counter,
-				      WPA_REPLAY_COUNTER_LEN) != 0) {
-				wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key Replay "
-					   "Counter did not match (STK) - "
-					   "dropping packet");
-				goto out;
-			}
-		}
-	}
-
-	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
-		wpa_printf(MSG_INFO, "RSN: Ack bit in key_info from STK peer");
-		goto out;
-	}
-#endif /* CONFIG_PEERKEY */
-
-	if (!peerkey && sm->rx_replay_counter_set &&
-	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
-		      WPA_REPLAY_COUNTER_LEN) <= 0) {
-		wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not"
-			   " increase - dropping packet");
-		goto out;
-	}
-
-	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
-#ifdef CONFIG_PEERKEY
-	    && (peerkey == NULL || !peerkey->initiator)
-#endif /* CONFIG_PEERKEY */
-		) {
-		wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info");
-		goto out;
-	}
-
-	if (key_info & WPA_KEY_INFO_REQUEST) {
-		wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - "
-			   "dropped");
-		goto out;
-	}
-
-	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
-	    wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
-		goto out;
-
-#ifdef CONFIG_PEERKEY
-	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
-	    peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
-		goto out;
-#endif /* CONFIG_PEERKEY */
-
-	extra_len = data_len - sizeof(*hdr) - sizeof(*key);
-
-	if (WPA_GET_BE16(key->key_data_length) > extra_len) {
-		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
-			"frame - key_data overflow (%d > %lu)",
-			WPA_GET_BE16(key->key_data_length),
-			(unsigned long) extra_len);
-		goto out;
-	}
-	extra_len = WPA_GET_BE16(key->key_data_length);
-
-	if (sm->proto == WPA_PROTO_RSN &&
-	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-		if (wpa_supplicant_decrypt_key_data(sm, key, ver))
-			goto out;
-		extra_len = WPA_GET_BE16(key->key_data_length);
-	}
-
-	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
-		if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
-			wpa_printf(MSG_WARNING, "WPA: Ignored EAPOL-Key "
-				   "(Pairwise) with non-zero key index");
-			goto out;
-		}
-		if (peerkey) {
-			/* PeerKey 4-Way Handshake */
-			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
-		} else if (key_info & WPA_KEY_INFO_MIC) {
-			/* 3/4 4-Way Handshake */
-			wpa_supplicant_process_3_of_4(sm, key, ver);
-		} else {
-			/* 1/4 4-Way Handshake */
-			wpa_supplicant_process_1_of_4(sm, src_addr, key,
-						      ver);
-		}
-	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
-		/* PeerKey SMK Handshake */
-		peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
-				     ver);
-	} else {
-		if (key_info & WPA_KEY_INFO_MIC) {
-			/* 1/2 Group Key Handshake */
-			wpa_supplicant_process_1_of_2(sm, src_addr, key,
-						      extra_len, ver);
-		} else {
-			wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) "
-				   "without Mic bit - dropped");
-		}
-	}
-
-	ret = 1;
-
-out:
-	os_free(tmp);
-	return ret;
-}
-
-
-#ifdef CONFIG_CTRL_IFACE
-static int wpa_cipher_bits(int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_CCMP:
-		return 128;
-	case WPA_CIPHER_TKIP:
-		return 256;
-	case WPA_CIPHER_WEP104:
-		return 104;
-	case WPA_CIPHER_WEP40:
-		return 40;
-	default:
-		return 0;
-	}
-}
-
-
-static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
-{
-	switch (sm->key_mgmt) {
-	case WPA_KEY_MGMT_IEEE8021X:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
-			WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
-	case WPA_KEY_MGMT_PSK:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X :
-			WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
-#ifdef CONFIG_IEEE80211R
-	case WPA_KEY_MGMT_FT_IEEE8021X:
-		return RSN_AUTH_KEY_MGMT_FT_802_1X;
-	case WPA_KEY_MGMT_FT_PSK:
-		return RSN_AUTH_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	case WPA_KEY_MGMT_IEEE8021X_SHA256:
-		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
-	case WPA_KEY_MGMT_PSK_SHA256:
-		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
-#endif /* CONFIG_IEEE80211W */
-	case WPA_KEY_MGMT_WPA_NONE:
-		return WPA_AUTH_KEY_MGMT_NONE;
-	default:
-		return 0;
-	}
-}
-
-
-static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_CCMP:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
-	case WPA_CIPHER_TKIP:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
-	case WPA_CIPHER_WEP104:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
-	case WPA_CIPHER_WEP40:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
-	case WPA_CIPHER_NONE:
-		return (sm->proto == WPA_PROTO_RSN ?
-			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
-	default:
-		return 0;
-	}
-}
-
-
-#define RSN_SUITE "%02x-%02x-%02x-%d"
-#define RSN_SUITE_ARG(s) \
-((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
-
-/**
- * wpa_sm_get_mib - Dump text list of MIB entries
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @buf: Buffer for the list
- * @buflen: Length of the buffer
- * Returns: Number of bytes written to buffer
- *
- * This function is used fetch dot11 MIB variables.
- */
-int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
-{
-	char pmkid_txt[PMKID_LEN * 2 + 1];
-	int rsna, ret;
-	size_t len;
-
-	if (sm->cur_pmksa) {
-		wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
-				 sm->cur_pmksa->pmkid, PMKID_LEN);
-	} else
-		pmkid_txt[0] = '\0';
-
-	if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
-	     wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
-	    sm->proto == WPA_PROTO_RSN)
-		rsna = 1;
-	else
-		rsna = 0;
-
-	ret = os_snprintf(buf, buflen,
-			  "dot11RSNAOptionImplemented=TRUE\n"
-			  "dot11RSNAPreauthenticationImplemented=TRUE\n"
-			  "dot11RSNAEnabled=%s\n"
-			  "dot11RSNAPreauthenticationEnabled=%s\n"
-			  "dot11RSNAConfigVersion=%d\n"
-			  "dot11RSNAConfigPairwiseKeysSupported=5\n"
-			  "dot11RSNAConfigGroupCipherSize=%d\n"
-			  "dot11RSNAConfigPMKLifetime=%d\n"
-			  "dot11RSNAConfigPMKReauthThreshold=%d\n"
-			  "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
-			  "dot11RSNAConfigSATimeout=%d\n",
-			  rsna ? "TRUE" : "FALSE",
-			  rsna ? "TRUE" : "FALSE",
-			  RSN_VERSION,
-			  wpa_cipher_bits(sm->group_cipher),
-			  sm->dot11RSNAConfigPMKLifetime,
-			  sm->dot11RSNAConfigPMKReauthThreshold,
-			  sm->dot11RSNAConfigSATimeout);
-	if (ret < 0 || (size_t) ret >= buflen)
-		return 0;
-	len = ret;
-
-	ret = os_snprintf(
-		buf + len, buflen - len,
-		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
-		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
-		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
-		"dot11RSNAPMKIDUsed=%s\n"
-		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
-		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
-		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
-		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
-		"dot11RSNA4WayHandshakeFailures=%u\n",
-		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
-		RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
-		RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
-		pmkid_txt,
-		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
-		RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
-		RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
-		sm->dot11RSNA4WayHandshakeFailures);
-	if (ret >= 0 && (size_t) ret < buflen)
-		len += ret;
-
-	return (int) len;
-}
-#endif /* CONFIG_CTRL_IFACE */
-
-
-static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
-				 void *ctx, int replace)
-{
-	struct wpa_sm *sm = ctx;
-
-	if (sm->cur_pmksa == entry ||
-	    (sm->pmk_len == entry->pmk_len &&
-	     os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
-		wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
-		sm->cur_pmksa = NULL;
-
-		if (replace) {
-			/* A new entry is being added, so no need to
-			 * deauthenticate in this case. This happens when EAP
-			 * authentication is completed again (reauth or failed
-			 * PMKSA caching attempt). */
-			return;
-		}
-
-		os_memset(sm->pmk, 0, sizeof(sm->pmk));
-		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
-	}
-}
-
-
-/**
- * wpa_sm_init - Initialize WPA state machine
- * @ctx: Context pointer for callbacks; this needs to be an allocated buffer
- * Returns: Pointer to the allocated WPA state machine data
- *
- * This function is used to allocate a new WPA state machine and the returned
- * value is passed to all WPA state machine calls.
- */
-struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
-{
-	struct wpa_sm *sm;
-
-	sm = os_zalloc(sizeof(*sm));
-	if (sm == NULL)
-		return NULL;
-	dl_list_init(&sm->pmksa_candidates);
-	sm->renew_snonce = 1;
-	sm->ctx = ctx;
-
-	sm->dot11RSNAConfigPMKLifetime = 43200;
-	sm->dot11RSNAConfigPMKReauthThreshold = 70;
-	sm->dot11RSNAConfigSATimeout = 60;
-
-	sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
-	if (sm->pmksa == NULL) {
-		wpa_printf(MSG_ERROR, "RSN: PMKSA cache initialization "
-			   "failed");
-		os_free(sm);
-		return NULL;
-	}
-
-	return sm;
-}
-
-
-/**
- * wpa_sm_deinit - Deinitialize WPA state machine
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void wpa_sm_deinit(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return;
-	pmksa_cache_deinit(sm->pmksa);
-	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
-	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
-	os_free(sm->assoc_wpa_ie);
-	os_free(sm->ap_wpa_ie);
-	os_free(sm->ap_rsn_ie);
-	os_free(sm->ctx);
-	peerkey_deinit(sm);
-#ifdef CONFIG_IEEE80211R
-	os_free(sm->assoc_resp_ies);
-#endif /* CONFIG_IEEE80211R */
-	os_free(sm);
-}
-
-
-/**
- * wpa_sm_notify_assoc - Notify WPA state machine about association
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @bssid: The BSSID of the new association
- *
- * This function is called to let WPA state machine know that the connection
- * was established.
- */
-void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
-{
-	int clear_ptk = 1;
-
-	if (sm == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "WPA: Association event - clear replay counter");
-	os_memcpy(sm->bssid, bssid, ETH_ALEN);
-	os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
-	sm->rx_replay_counter_set = 0;
-	sm->renew_snonce = 1;
-	if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
-		rsn_preauth_deinit(sm);
-
-#ifdef CONFIG_IEEE80211R
-	if (wpa_ft_is_completed(sm)) {
-		/*
-		 * Clear portValid to kick EAPOL state machine to re-enter
-		 * AUTHENTICATED state to get the EAPOL port Authorized.
-		 */
-		eapol_sm_notify_portValid(sm->eapol, FALSE);
-		wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
-
-		/* Prepare for the next transition */
-		wpa_ft_prepare_auth_request(sm, NULL);
-
-		clear_ptk = 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (clear_ptk) {
-		/*
-		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
-		 * this is not part of a Fast BSS Transition.
-		 */
-		wpa_printf(MSG_DEBUG, "WPA: Clear old PTK");
-		sm->ptk_set = 0;
-		sm->tptk_set = 0;
-	}
-}
-
-
-/**
- * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * This function is called to let WPA state machine know that the connection
- * was lost. This will abort any existing pre-authentication session.
- */
-void wpa_sm_notify_disassoc(struct wpa_sm *sm)
-{
-	rsn_preauth_deinit(sm);
-	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
-		sm->dot11RSNA4WayHandshakeFailures++;
-}
-
-
-/**
- * wpa_sm_set_pmk - Set PMK
- * @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
- *
- * Configure the PMK for WPA state machine.
- */
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
-{
-	if (sm == NULL)
-		return;
-
-	sm->pmk_len = pmk_len;
-	os_memcpy(sm->pmk, pmk, pmk_len);
-
-#ifdef CONFIG_IEEE80211R
-	/* Set XXKey to be PSK for FT key derivation */
-	sm->xxkey_len = pmk_len;
-	os_memcpy(sm->xxkey, pmk, pmk_len);
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-/**
- * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
- * will be cleared.
- */
-void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return;
-
-	if (sm->cur_pmksa) {
-		sm->pmk_len = sm->cur_pmksa->pmk_len;
-		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
-	} else {
-		sm->pmk_len = PMK_LEN;
-		os_memset(sm->pmk, 0, PMK_LEN);
-	}
-}
-
-
-/**
- * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @fast_reauth: Whether fast reauthentication (EAP) is allowed
- */
-void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
-{
-	if (sm)
-		sm->fast_reauth = fast_reauth;
-}
-
-
-/**
- * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @scard_ctx: Context pointer for smartcard related callback functions
- */
-void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
-{
-	if (sm == NULL)
-		return;
-	sm->scard_ctx = scard_ctx;
-	if (sm->preauth_eapol)
-		eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx);
-}
-
-
-/**
- * wpa_sm_set_config - Notification of current configration change
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @config: Pointer to current network configuration
- *
- * Notify WPA state machine that configuration has changed. config will be
- * stored as a backpointer to network configuration. This can be %NULL to clear
- * the stored pointed.
- */
-void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
-{
-	if (!sm)
-		return;
-
-	if (config) {
-		sm->network_ctx = config->network_ctx;
-		sm->peerkey_enabled = config->peerkey_enabled;
-		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
-		sm->proactive_key_caching = config->proactive_key_caching;
-		sm->eap_workaround = config->eap_workaround;
-		sm->eap_conf_ctx = config->eap_conf_ctx;
-		if (config->ssid) {
-			os_memcpy(sm->ssid, config->ssid, config->ssid_len);
-			sm->ssid_len = config->ssid_len;
-		} else
-			sm->ssid_len = 0;
-		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
-	} else {
-		sm->network_ctx = NULL;
-		sm->peerkey_enabled = 0;
-		sm->allowed_pairwise_cipher = 0;
-		sm->proactive_key_caching = 0;
-		sm->eap_workaround = 0;
-		sm->eap_conf_ctx = NULL;
-		sm->ssid_len = 0;
-		sm->wpa_ptk_rekey = 0;
-	}
-	if (config == NULL || config->network_ctx != sm->network_ctx)
-		pmksa_cache_notify_reconfig(sm->pmksa);
-}
-
-
-/**
- * wpa_sm_set_own_addr - Set own MAC address
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @addr: Own MAC address
- */
-void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
-{
-	if (sm)
-		os_memcpy(sm->own_addr, addr, ETH_ALEN);
-}
-
-
-/**
- * wpa_sm_set_ifname - Set network interface name
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ifname: Interface name
- * @bridge_ifname: Optional bridge interface name (for pre-auth)
- */
-void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
-		       const char *bridge_ifname)
-{
-	if (sm) {
-		sm->ifname = ifname;
-		sm->bridge_ifname = bridge_ifname;
-	}
-}
-
-
-/**
- * wpa_sm_set_eapol - Set EAPOL state machine pointer
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init()
- */
-void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
-{
-	if (sm)
-		sm->eapol = eapol;
-}
-
-
-/**
- * wpa_sm_set_param - Set WPA state machine parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @param: Parameter field
- * @value: Parameter value
- * Returns: 0 on success, -1 on failure
- */
-int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
-		     unsigned int value)
-{
-	int ret = 0;
-
-	if (sm == NULL)
-		return -1;
-
-	switch (param) {
-	case RSNA_PMK_LIFETIME:
-		if (value > 0)
-			sm->dot11RSNAConfigPMKLifetime = value;
-		else
-			ret = -1;
-		break;
-	case RSNA_PMK_REAUTH_THRESHOLD:
-		if (value > 0 && value <= 100)
-			sm->dot11RSNAConfigPMKReauthThreshold = value;
-		else
-			ret = -1;
-		break;
-	case RSNA_SA_TIMEOUT:
-		if (value > 0)
-			sm->dot11RSNAConfigSATimeout = value;
-		else
-			ret = -1;
-		break;
-	case WPA_PARAM_PROTO:
-		sm->proto = value;
-		break;
-	case WPA_PARAM_PAIRWISE:
-		sm->pairwise_cipher = value;
-		break;
-	case WPA_PARAM_GROUP:
-		sm->group_cipher = value;
-		break;
-	case WPA_PARAM_KEY_MGMT:
-		sm->key_mgmt = value;
-		break;
-#ifdef CONFIG_IEEE80211W
-	case WPA_PARAM_MGMT_GROUP:
-		sm->mgmt_group_cipher = value;
-		break;
-#endif /* CONFIG_IEEE80211W */
-	case WPA_PARAM_RSN_ENABLED:
-		sm->rsn_enabled = value;
-		break;
-	case WPA_PARAM_MFP:
-		sm->mfp = value;
-		break;
-	default:
-		break;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_sm_get_param - Get WPA state machine parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @param: Parameter field
- * Returns: Parameter value
- */
-unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
-{
-	if (sm == NULL)
-		return 0;
-
-	switch (param) {
-	case RSNA_PMK_LIFETIME:
-		return sm->dot11RSNAConfigPMKLifetime;
-	case RSNA_PMK_REAUTH_THRESHOLD:
-		return sm->dot11RSNAConfigPMKReauthThreshold;
-	case RSNA_SA_TIMEOUT:
-		return sm->dot11RSNAConfigSATimeout;
-	case WPA_PARAM_PROTO:
-		return sm->proto;
-	case WPA_PARAM_PAIRWISE:
-		return sm->pairwise_cipher;
-	case WPA_PARAM_GROUP:
-		return sm->group_cipher;
-	case WPA_PARAM_KEY_MGMT:
-		return sm->key_mgmt;
-#ifdef CONFIG_IEEE80211W
-	case WPA_PARAM_MGMT_GROUP:
-		return sm->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
-	case WPA_PARAM_RSN_ENABLED:
-		return sm->rsn_enabled;
-	default:
-		return 0;
-	}
-}
-
-
-/**
- * wpa_sm_get_status - Get WPA state machine
- * @sm: Pointer to WPA state machine data from wpa_sm_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 WPA state machine for status information. This function fills in
- * a text area with current status information. If the buffer (buf) is not
- * large enough, status information will be truncated to fit the buffer.
- */
-int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
-		      int verbose)
-{
-	char *pos = buf, *end = buf + buflen;
-	int ret;
-
-	ret = os_snprintf(pos, end - pos,
-			  "pairwise_cipher=%s\n"
-			  "group_cipher=%s\n"
-			  "key_mgmt=%s\n",
-			  wpa_cipher_txt(sm->pairwise_cipher),
-			  wpa_cipher_txt(sm->group_cipher),
-			  wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-	return pos - buf;
-}
-
-
-/**
- * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @wpa_ie: Pointer to buffer for WPA/RSN IE
- * @wpa_ie_len: Pointer to the length of the wpa_ie buffer
- * Returns: 0 on success, -1 on failure
- */
-int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
-				    size_t *wpa_ie_len)
-{
-	int res;
-
-	if (sm == NULL)
-		return -1;
-
-	res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
-	if (res < 0)
-		return -1;
-	*wpa_ie_len = res;
-
-	wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
-		    wpa_ie, *wpa_ie_len);
-
-	if (sm->assoc_wpa_ie == NULL) {
-		/*
-		 * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
-		 * the correct version of the IE even if PMKSA caching is
-		 * aborted (which would remove PMKID from IE generation).
-		 */
-		sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
-		if (sm->assoc_wpa_ie == NULL)
-			return -1;
-
-		os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
-		sm->assoc_wpa_ie_len = *wpa_ie_len;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ie: Pointer to IE data (starting from id)
- * @len: IE length
- * Returns: 0 on success, -1 on failure
- *
- * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
- * Request frame. The IE will be used to override the default value generated
- * with wpa_sm_set_assoc_wpa_ie_default().
- */
-int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
-{
-	if (sm == NULL)
-		return -1;
-
-	os_free(sm->assoc_wpa_ie);
-	if (ie == NULL || len == 0) {
-		wpa_printf(MSG_DEBUG, "WPA: clearing own WPA/RSN IE");
-		sm->assoc_wpa_ie = NULL;
-		sm->assoc_wpa_ie_len = 0;
-	} else {
-		wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
-		sm->assoc_wpa_ie = os_malloc(len);
-		if (sm->assoc_wpa_ie == NULL)
-			return -1;
-
-		os_memcpy(sm->assoc_wpa_ie, ie, len);
-		sm->assoc_wpa_ie_len = len;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ie: Pointer to IE data (starting from id)
- * @len: IE length
- * Returns: 0 on success, -1 on failure
- *
- * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
- * frame.
- */
-int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
-{
-	if (sm == NULL)
-		return -1;
-
-	os_free(sm->ap_wpa_ie);
-	if (ie == NULL || len == 0) {
-		wpa_printf(MSG_DEBUG, "WPA: clearing AP WPA IE");
-		sm->ap_wpa_ie = NULL;
-		sm->ap_wpa_ie_len = 0;
-	} else {
-		wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
-		sm->ap_wpa_ie = os_malloc(len);
-		if (sm->ap_wpa_ie == NULL)
-			return -1;
-
-		os_memcpy(sm->ap_wpa_ie, ie, len);
-		sm->ap_wpa_ie_len = len;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ie: Pointer to IE data (starting from id)
- * @len: IE length
- * Returns: 0 on success, -1 on failure
- *
- * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
- * frame.
- */
-int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
-{
-	if (sm == NULL)
-		return -1;
-
-	os_free(sm->ap_rsn_ie);
-	if (ie == NULL || len == 0) {
-		wpa_printf(MSG_DEBUG, "WPA: clearing AP RSN IE");
-		sm->ap_rsn_ie = NULL;
-		sm->ap_rsn_ie_len = 0;
-	} else {
-		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
-		sm->ap_rsn_ie = os_malloc(len);
-		if (sm->ap_rsn_ie == NULL)
-			return -1;
-
-		os_memcpy(sm->ap_rsn_ie, ie, len);
-		sm->ap_rsn_ie_len = len;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @data: Pointer to data area for parsing results
- * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure
- *
- * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the
- * parsed data into data.
- */
-int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
-{
-	if (sm == NULL || sm->assoc_wpa_ie == NULL) {
-		wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE available from "
-			   "association info");
-		return -1;
-	}
-	if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
-		return -2;
-	return 0;
-}
-
-
-int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
-{
-#ifndef CONFIG_NO_WPA2
-	return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
-}
-
-
-void wpa_sm_drop_sa(struct wpa_sm *sm)
-{
-	wpa_printf(MSG_DEBUG, "WPA: Clear old PMK and PTK");
-	sm->ptk_set = 0;
-	sm->tptk_set = 0;
-	os_memset(sm->pmk, 0, sizeof(sm->pmk));
-	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
-	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
-}
-
-
-int wpa_sm_has_ptk(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return 0;
-	return sm->ptk_set;
-}

Copied: vendor/wpa/2.0/src/rsn_supp/wpa.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2702 @@
+/*
+ * WPA Supplicant - WPA state machine and EAPOL-Key processing
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+#include "peerkey.h"
+
+
+/**
+ * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @kck: Key Confirmation Key (KCK, part of PTK)
+ * @ver: Version field from Key Info
+ * @dest: Destination address for the frame
+ * @proto: Ethertype (usually ETH_P_EAPOL)
+ * @msg: EAPOL-Key message
+ * @msg_len: Length of message
+ * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ */
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+			int ver, const u8 *dest, u16 proto,
+			u8 *msg, size_t msg_len, u8 *key_mic)
+{
+	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
+		/*
+		 * Association event was not yet received; try to fetch
+		 * BSSID from the driver.
+		 */
+		if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Failed to read BSSID for "
+				"EAPOL-Key destination address");
+		} else {
+			dest = sm->bssid;
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Use BSSID (" MACSTR
+				") as the destination for EAPOL-Key",
+				MAC2STR(dest));
+		}
+	}
+	if (key_mic &&
+	    wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+			"WPA: Failed to generate EAPOL-Key "
+			"version %d MIC", ver);
+		goto out;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
+	wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
+	wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+	eapol_sm_notify_tx_eapol_key(sm->eapol);
+out:
+	os_free(msg);
+}
+
+
+/**
+ * wpa_sm_key_request - Send EAPOL-Key Request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @error: Indicate whether this is an Michael MIC error report
+ * @pairwise: 1 = error report for pairwise packet, 0 = for group packet
+ *
+ * Send an EAPOL-Key Request to the current authenticator. This function is
+ * used to request rekeying and it is usually called when a local Michael MIC
+ * failure is detected.
+ */
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	int key_info, ver;
+	u8 bssid[ETH_ALEN], *rbuf;
+
+	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
+		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+	else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	if (wpa_sm_get_bssid(sm, bssid) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"Failed to read BSSID for EAPOL-Key request");
+		return;
+	}
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply), &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		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;
+	if (error)
+		key_info |= WPA_KEY_INFO_ERROR;
+	if (pairwise)
+		key_info |= WPA_KEY_INFO_KEY_TYPE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	WPA_PUT_BE16(reply->key_length, 0);
+	os_memcpy(reply->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, 0);
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"WPA: Sending EAPOL-Key Request (error=%d "
+		"pairwise=%d ptk_set=%d len=%lu)",
+		error, pairwise, sm->ptk_set, (unsigned long) rlen);
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+			   rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
+			   reply->key_mic : NULL);
+}
+
+
+static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
+				  const unsigned char *src_addr,
+				  const u8 *pmkid)
+{
+	int abort_cached = 0;
+
+	if (pmkid && !sm->cur_pmksa) {
+		/* When using drivers that generate RSN IE, wpa_supplicant may
+		 * not have enough time to get the association information
+		 * event before receiving this 1/4 message, so try to find a
+		 * matching PMKSA cache entry here. */
+		sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
+						NULL);
+		if (sm->cur_pmksa) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: found matching PMKID from PMKSA cache");
+		} else {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: no matching PMKID found");
+			abort_cached = 1;
+		}
+	}
+
+	if (pmkid && sm->cur_pmksa &&
+	    os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
+		wpa_sm_set_pmk_from_pmksa(sm);
+		wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
+				sm->pmk, sm->pmk_len);
+		eapol_sm_notify_cached(sm->eapol);
+#ifdef CONFIG_IEEE80211R
+		sm->xxkey_len = 0;
+#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 (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;
+		} else {
+#ifdef CONFIG_IEEE80211R
+			u8 buf[2 * PMK_LEN];
+			if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
+			{
+				os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
+				sm->xxkey_len = PMK_LEN;
+				os_memset(buf, 0, sizeof(buf));
+			}
+#endif /* CONFIG_IEEE80211R */
+		}
+		if (res == 0) {
+			struct rsn_pmksa_cache_entry *sa = NULL;
+			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
+					"machines", sm->pmk, pmk_len);
+			sm->pmk_len = pmk_len;
+			if (sm->proto == WPA_PROTO_RSN &&
+			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+				sa = pmksa_cache_add(sm->pmksa,
+						     sm->pmk, pmk_len,
+						     src_addr, sm->own_addr,
+						     sm->network_ctx,
+						     sm->key_mgmt);
+			}
+			if (!sm->cur_pmksa && pmkid &&
+			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
+			{
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: the new PMK matches with the "
+					"PMKID");
+				abort_cached = 0;
+			}
+
+			if (!sm->cur_pmksa)
+				sm->cur_pmksa = sa;
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to get master session key from "
+				"EAPOL state machines - key handshake "
+				"aborted");
+			if (sm->cur_pmksa) {
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: Cancelled PMKSA caching "
+					"attempt");
+				sm->cur_pmksa = NULL;
+				abort_cached = 1;
+			} else if (!abort_cached) {
+				return -1;
+			}
+		}
+	}
+
+	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+	    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* Send EAPOL-Start to trigger full EAP authentication. */
+		u8 *buf;
+		size_t buflen;
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: no PMKSA entry found - trigger "
+			"full EAP authentication");
+		buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
+					 NULL, 0, &buflen, NULL);
+		if (buf) {
+			wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
+					  buf, buflen);
+			os_free(buf);
+			return -2;
+		}
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Destination address for the frame
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @nonce: Nonce value for the EAPOL-Key frame
+ * @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
+ */
+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,
+			       const u8 *wpa_ie, size_t wpa_ie_len,
+			       struct wpa_ptk *ptk)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+	u8 *rsn_ie_buf = NULL;
+
+	if (wpa_ie == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
+			"cannot generate msg 2/4");
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		int res;
+
+		/*
+		 * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
+		 * FTIE from (Re)Association Response.
+		 */
+		rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN +
+				       sm->assoc_resp_ies_len);
+		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,
+				       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,
+				  sm->assoc_resp_ies_len);
+			wpa_ie_len += sm->assoc_resp_ies_len;
+		}
+
+		wpa_ie = rsn_ie_buf;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*reply) + wpa_ie_len,
+				  &rlen, (void *) &reply);
+	if (rbuf == NULL) {
+		os_free(rsn_ie_buf);
+		return -1;
+	}
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	WPA_PUT_BE16(reply->key_info,
+		     ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
+		    WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+	os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+	os_free(rsn_ie_buf);
+
+	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, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
+			  const struct wpa_eapol_key *key,
+			  struct wpa_ptk *ptk)
+{
+	size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt))
+		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
+		       (u8 *) ptk, ptk_len,
+		       wpa_key_mgmt_sha256(sm->key_mgmt));
+	return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
+					  const unsigned char *src_addr,
+					  const struct wpa_eapol_key *key,
+					  u16 ver)
+{
+	struct wpa_eapol_ie_parse ie;
+	struct wpa_ptk *ptk;
+	u8 buf[8];
+	int res;
+
+	if (wpa_sm_get_network_ctx(sm) == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
+			"found (msg 1 of 4)");
+		return;
+	}
+
+	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+
+	os_memset(&ie, 0, sizeof(ie));
+
+#ifndef CONFIG_NO_WPA2
+	if (sm->proto == WPA_PROTO_RSN) {
+		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
+		const u8 *_buf = (const u8 *) (key + 1);
+		size_t len = WPA_GET_BE16(key->key_data_length);
+		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
+		if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+			goto failed;
+		if (ie.pmkid) {
+			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
+				    "Authenticator", ie.pmkid, PMKID_LEN);
+		}
+	}
+#endif /* CONFIG_NO_WPA2 */
+
+	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
+	if (res == -2) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
+			"msg 1/4 - requesting full EAP authentication");
+		return;
+	}
+	if (res)
+		goto failed;
+
+	if (sm->renew_snonce) {
+		if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to get random data for SNonce");
+			goto failed;
+		}
+		sm->renew_snonce = 0;
+		wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+	}
+
+	/* Calculate PTK which will be stored as a temporary PTK until it has
+	 * been verified when processing message 3/4. */
+	ptk = &sm->tptk;
+	wpa_derive_ptk(sm, src_addr, key, ptk);
+	/* Supplicant: swap tx/rx Mic keys */
+	os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
+	os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
+	os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+	sm->tptk_set = 1;
+
+	if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
+				       sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
+				       ptk))
+		goto failed;
+
+	os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
+					    const u8 *addr, int secure)
+{
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"WPA: Key negotiation completed with "
+		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
+		wpa_cipher_txt(sm->pairwise_cipher),
+		wpa_cipher_txt(sm->group_cipher));
+	wpa_sm_cancel_auth_timeout(sm);
+	wpa_sm_set_state(sm, WPA_COMPLETED);
+
+	if (secure) {
+		wpa_sm_mlme_setprotection(
+			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+		eapol_sm_notify_portValid(sm->eapol, TRUE);
+		if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
+			eapol_sm_notify_eap_success(sm->eapol, TRUE);
+		/*
+		 * Start preauthentication after a short wait to avoid a
+		 * possible race condition between the data receive and key
+		 * configuration after the 4-Way Handshake. This increases the
+		 * likelihood of the first preauth EAPOL-Start frame getting to
+		 * the target AP.
+		 */
+		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+	}
+
+	if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Authenticator accepted "
+			"opportunistic PMKSA entry - marking it valid");
+		sm->cur_pmksa->opportunistic = 0;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* Prepare for the next transition */
+		wpa_ft_prepare_auth_request(sm, NULL);
+	}
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying");
+	wpa_sm_key_request(sm, 0, 1);
+}
+
+
+static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
+				      const struct wpa_eapol_key *key)
+{
+	int keylen, rsclen;
+	enum wpa_alg alg;
+	const u8 *key_rsc;
+	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Installing PTK to the driver");
+
+	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
+			"Suite: NONE - do not use pairwise keys");
+		return 0;
+	}
+
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported pairwise cipher %d",
+			sm->pairwise_cipher);
+		return -1;
+	}
+
+	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+
+	if (sm->proto == WPA_PROTO_RSN) {
+		key_rsc = null_rsc;
+	} else {
+		key_rsc = key->key_rsc;
+		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
+	}
+
+	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
+			   (u8 *) sm->ptk.tk1, keylen) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to set PTK to the "
+			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
+			alg, keylen, MAC2STR(sm->bssid));
+		return -1;
+	}
+
+	if (sm->wpa_ptk_rekey) {
+		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
+				       sm, NULL);
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
+					     int group_cipher,
+					     int keylen, int maxkeylen,
+					     int *key_rsc_len,
+					     enum wpa_alg *alg)
+{
+	int klen;
+
+	*alg = wpa_cipher_to_alg(group_cipher);
+	if (*alg == WPA_ALG_NONE) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported Group Cipher %d",
+			group_cipher);
+		return -1;
+	}
+	*key_rsc_len = wpa_cipher_rsc_len(group_cipher);
+
+	klen = wpa_cipher_key_len(group_cipher);
+	if (keylen != klen || maxkeylen < klen) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported %s Group Cipher key length %d (%d)",
+			wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+		return -1;
+	}
+	return 0;
+}
+
+
+struct wpa_gtk_data {
+	enum wpa_alg alg;
+	int tx, key_rsc_len, keyidx;
+	u8 gtk[32];
+	int gtk_len;
+};
+
+
+static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
+				      const struct wpa_gtk_data *gd,
+				      const u8 *key_rsc)
+{
+	const u8 *_gtk = gd->gtk;
+	u8 gtk_buf[32];
+
+	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
+		gd->keyidx, gd->tx, gd->gtk_len);
+	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
+	if (sm->group_cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		os_memcpy(gtk_buf, gd->gtk, 16);
+		os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
+		os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
+		_gtk = gtk_buf;
+	}
+	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+		if (wpa_sm_set_key(sm, gd->alg, NULL,
+				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
+				   _gtk, gd->gtk_len) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to set GTK to the driver "
+				"(Group only)");
+			return -1;
+		}
+	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
+				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
+				  _gtk, gd->gtk_len) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to set GTK to "
+			"the driver (alg=%d keylen=%d keyidx=%d)",
+			gd->alg, gd->gtk_len, gd->keyidx);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
+						int tx)
+{
+	if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
+		/* Ignore Tx bit for GTK if a pairwise key is used. One AP
+		 * seemed to set this bit (incorrectly, since Tx is only when
+		 * doing Group Key only APs) and without this workaround, the
+		 * data connection does not work because wpa_supplicant
+		 * configured non-zero keyidx to be used for unicast. */
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Tx bit set for GTK, but pairwise "
+			"keys are used - ignore Tx bit");
+		return 0;
+	}
+	return tx;
+}
+
+
+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)
+{
+#ifndef CONFIG_NO_WPA2
+	struct wpa_gtk_data gd;
+
+	/*
+	 * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
+	 * GTK KDE format:
+	 * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7]
+	 * Reserved [bits 0-7]
+	 * GTK
+	 */
+
+	os_memset(&gd, 0, sizeof(gd));
+	wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
+			gtk, gtk_len);
+
+	if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk))
+		return -1;
+
+	gd.keyidx = gtk[0] & 0x3;
+	gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+						     !!(gtk[0] & BIT(2)));
+	gtk += 2;
+	gtk_len -= 2;
+
+	os_memcpy(gd.gtk, gtk, gtk_len);
+	gd.gtk_len = gtk_len;
+
+	if (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_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Failed to install GTK");
+		return -1;
+	}
+
+	wpa_supplicant_key_neg_complete(sm, sm->bssid,
+					key_info & WPA_KEY_INFO_SECURE);
+	return 0;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int ieee80211w_set_keys(struct wpa_sm *sm,
+			       struct wpa_eapol_ie_parse *ie)
+{
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+		return 0;
+
+	if (ie->igtk) {
+		const struct wpa_igtk_kde *igtk;
+		u16 keyidx;
+		if (ie->igtk_len != sizeof(*igtk))
+			return -1;
+		igtk = (const struct wpa_igtk_kde *) ie->igtk;
+		keyidx = WPA_GET_LE16(igtk->keyid);
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
+			"pn %02x%02x%02x%02x%02x%02x",
+			keyidx, MAC2STR(igtk->pn));
+		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
+				igtk->igtk, WPA_IGTK_LEN);
+		if (keyidx > 4095) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid IGTK KeyID %d", keyidx);
+			return -1;
+		}
+		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
+				   igtk->igtk, WPA_IGTK_LEN) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to configure IGTK to the driver");
+			return -1;
+		}
+	}
+
+	return 0;
+#else /* CONFIG_IEEE80211W */
+	return 0;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_report_ie_mismatch(struct wpa_sm *sm,
+				   const char *reason, const u8 *src_addr,
+				   const u8 *wpa_ie, size_t wpa_ie_len,
+				   const u8 *rsn_ie, size_t rsn_ie_len)
+{
+	wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
+		reason, MAC2STR(src_addr));
+
+	if (sm->ap_wpa_ie) {
+		wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
+			    sm->ap_wpa_ie, sm->ap_wpa_ie_len);
+	}
+	if (wpa_ie) {
+		if (!sm->ap_wpa_ie) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: No WPA IE in Beacon/ProbeResp");
+		}
+		wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg",
+			    wpa_ie, wpa_ie_len);
+	}
+
+	if (sm->ap_rsn_ie) {
+		wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp",
+			    sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+	}
+	if (rsn_ie) {
+		if (!sm->ap_rsn_ie) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: No RSN IE in Beacon/ProbeResp");
+		}
+		wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg",
+			    rsn_ie, rsn_ie_len);
+	}
+
+	wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int ft_validate_mdie(struct wpa_sm *sm,
+			    const unsigned char *src_addr,
+			    struct wpa_eapol_ie_parse *ie,
+			    const u8 *assoc_resp_mdie)
+{
+	struct rsn_mdie *mdie;
+
+	mdie = (struct rsn_mdie *) (ie->mdie + 2);
+	if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did "
+			"not match with the current mobility domain");
+		return -1;
+	}
+
+	if (assoc_resp_mdie &&
+	    (assoc_resp_mdie[1] != ie->mdie[1] ||
+	     os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4",
+			    ie->mdie, 2 + ie->mdie[1]);
+		wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response",
+			    assoc_resp_mdie, 2 + assoc_resp_mdie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int ft_validate_ftie(struct wpa_sm *sm,
+			    const unsigned char *src_addr,
+			    struct wpa_eapol_ie_parse *ie,
+			    const u8 *assoc_resp_ftie)
+{
+	if (ie->ftie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: No FTIE in EAPOL-Key msg 3/4");
+		return -1;
+	}
+
+	if (assoc_resp_ftie == NULL)
+		return 0;
+
+	if (assoc_resp_ftie[1] != ie->ftie[1] ||
+	    os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4",
+			    ie->ftie, 2 + ie->ftie[1]);
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response",
+			    assoc_resp_ftie, 2 + assoc_resp_ftie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int ft_validate_rsnie(struct wpa_sm *sm,
+			     const unsigned char *src_addr,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	struct wpa_ie_data rsn;
+
+	if (!ie->rsn_ie)
+		return 0;
+
+	/*
+	 * Verify that PMKR1Name from EAPOL-Key message 3/4
+	 * matches with the value we derived.
+	 */
+	if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 ||
+	    rsn.num_pmkid != 1 || rsn.pmkid == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in "
+			"FT 4-way handshake message 3/4");
+		return -1;
+	}
+
+	if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: PMKR1Name mismatch in "
+			"FT 4-way handshake message 3/4");
+		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator",
+			    rsn.pmkid, WPA_PMK_NAME_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
+			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
+					 const unsigned char *src_addr,
+					 struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end, *mdie = NULL, *ftie = NULL;
+
+	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)
+				break;
+			switch (*pos) {
+			case WLAN_EID_MOBILITY_DOMAIN:
+				mdie = pos;
+				break;
+			case WLAN_EID_FAST_BSS_TRANSITION:
+				ftie = pos;
+				break;
+			}
+			pos += 2 + pos[1];
+		}
+	}
+
+	if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 ||
+	    ft_validate_ftie(sm, src_addr, ie, ftie) < 0 ||
+	    ft_validate_rsnie(sm, src_addr, ie) < 0)
+		return -1;
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
+				      const unsigned char *src_addr,
+				      struct wpa_eapol_ie_parse *ie)
+{
+	if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: No WPA/RSN IE for this AP known. "
+			"Trying to get from scan results");
+		if (wpa_sm_get_beacon_ie(sm) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Could not find AP from "
+				"the scan results");
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Found the current AP from "
+				"updated scan results");
+		}
+	}
+
+	if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
+	    (sm->ap_wpa_ie || sm->ap_rsn_ie)) {
+		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
+				       "with IE in Beacon/ProbeResp (no IE?)",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+	if ((ie->wpa_ie && sm->ap_wpa_ie &&
+	     (ie->wpa_ie_len != sm->ap_wpa_ie_len ||
+	      os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
+	    (ie->rsn_ie && sm->ap_rsn_ie &&
+	     wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+				sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+				ie->rsn_ie, ie->rsn_ie_len))) {
+		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
+				       "with IE in Beacon/ProbeResp",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+	if (sm->proto == WPA_PROTO_WPA &&
+	    ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) {
+		wpa_report_ie_mismatch(sm, "Possible downgrade attack "
+				       "detected - RSN was enabled and RSN IE "
+				       "was in msg 3/4, but not in "
+				       "Beacon/ProbeResp",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt) &&
+	    wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
+		return -1;
+#endif /* CONFIG_IEEE80211R */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Destination address for the frame
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @key_info: Key Info
+ * @kde: KDEs to include the EAPOL-Key frame
+ * @kde_len: Length of KDEs
+ * @ptk: PTK to use for keyed hash and encryption
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       u16 ver, u16 key_info,
+			       const u8 *kde, size_t kde_len,
+			       struct wpa_ptk *ptk)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+
+	if (kde)
+		wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply) + kde_len,
+				  &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info &= WPA_KEY_INFO_SECURE;
+	key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, kde_len);
+	if (kde)
+		os_memcpy(reply + 1, kde, kde_len);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
+	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
+					  const struct wpa_eapol_key *key,
+					  u16 ver)
+{
+	u16 key_info, keylen, len;
+	const u8 *pos;
+	struct wpa_eapol_ie_parse ie;
+
+	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	pos = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
+	if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+		goto failed;
+	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: GTK IE in unencrypted key data");
+		goto failed;
+	}
+#ifdef CONFIG_IEEE80211W
+	if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: IGTK KDE in unencrypted key data");
+		goto failed;
+	}
+
+	if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid IGTK KDE length %lu",
+			(unsigned long) ie.igtk_len);
+		goto failed;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
+		goto failed;
+
+	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: ANonce from message 1 of 4-Way Handshake "
+			"differs from 3 of 4-Way Handshake - drop packet (src="
+			MACSTR ")", MAC2STR(sm->bssid));
+		goto failed;
+	}
+
+	keylen = WPA_GET_BE16(key->key_length);
+	if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid %s key length %d (src=" MACSTR
+			")", wpa_cipher_txt(sm->pairwise_cipher), keylen,
+			MAC2STR(sm->bssid));
+		goto failed;
+	}
+
+	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
+				       NULL, 0, &sm->ptk)) {
+		goto failed;
+	}
+
+	/* SNonce was successfully used in msg 3/4, so mark it to be renewed
+	 * for the next 4-Way Handshake. If msg 3 is received again, the old
+	 * SNonce will still be used to avoid changing PTK. */
+	sm->renew_snonce = 1;
+
+	if (key_info & WPA_KEY_INFO_INSTALL) {
+		if (wpa_supplicant_install_ptk(sm, key))
+			goto failed;
+	}
+
+	if (key_info & WPA_KEY_INFO_SECURE) {
+		wpa_sm_mlme_setprotection(
+			sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+		eapol_sm_notify_portValid(sm->eapol, TRUE);
+	}
+	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+
+	if (ie.gtk &&
+	    wpa_supplicant_pairwise_gtk(sm, key,
+					ie.gtk, ie.gtk_len, key_info) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure GTK");
+		goto failed;
+	}
+
+	if (ieee80211w_set_keys(sm, &ie) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure IGTK");
+		goto failed;
+	}
+
+	wpa_sm_set_rekey_offload(sm);
+
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
+					     const u8 *keydata,
+					     size_t keydatalen,
+					     u16 key_info,
+					     struct wpa_gtk_data *gd)
+{
+	int maxkeylen;
+	struct wpa_eapol_ie_parse ie;
+
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+		return -1;
+	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: GTK IE in unencrypted key data");
+		return -1;
+	}
+	if (ie.gtk == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: No GTK IE in Group Key msg 1/2");
+		return -1;
+	}
+	maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+
+	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gd->gtk_len, maxkeylen,
+					      &gd->key_rsc_len, &gd->alg))
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
+		    ie.gtk, ie.gtk_len);
+	gd->keyidx = ie.gtk[0] & 0x3;
+	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+						      !!(ie.gtk[0] & BIT(2)));
+	if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Too long GTK in GTK IE (len=%lu)",
+			(unsigned long) ie.gtk_len - 2);
+		return -1;
+	}
+	os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+
+	if (ieee80211w_set_keys(sm, &ie) < 0)
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure IGTK");
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
+					     const struct wpa_eapol_key *key,
+					     size_t keydatalen, int key_info,
+					     size_t extra_len, u16 ver,
+					     struct wpa_gtk_data *gd)
+{
+	size_t maxkeylen;
+	u8 ek[32];
+
+	gd->gtk_len = WPA_GET_BE16(key->key_length);
+	maxkeylen = keydatalen;
+	if (keydatalen > extra_len) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Truncated EAPOL-Key packet: "
+			"key_data_length=%lu > extra_len=%lu",
+			(unsigned long) keydatalen, (unsigned long) extra_len);
+		return -1;
+	}
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		if (maxkeylen < 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: Too short maxkeylen (%lu)",
+				(unsigned long) maxkeylen);
+			return -1;
+		}
+		maxkeylen -= 8;
+	}
+
+	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gd->gtk_len, maxkeylen,
+					      &gd->key_rsc_len, &gd->alg))
+		return -1;
+
+	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+		WPA_KEY_INFO_KEY_INDEX_SHIFT;
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+		os_memcpy(ek, key->key_iv, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		if (keydatalen > sizeof(gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: RC4 key data too long (%lu)",
+				(unsigned long) keydatalen);
+			return -1;
+		}
+		os_memcpy(gd->gtk, key + 1, keydatalen);
+		if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: RC4 failed");
+			return -1;
+		}
+	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		if (keydatalen % 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Unsupported AES-WRAP len %lu",
+				(unsigned long) keydatalen);
+			return -1;
+		}
+		if (maxkeylen > sizeof(gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES-WRAP key data "
+				"too long (keydatalen=%lu maxkeylen=%lu)",
+				(unsigned long) keydatalen,
+				(unsigned long) maxkeylen);
+			return -1;
+		}
+		if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
+			       (const u8 *) (key + 1), gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES unwrap failed - could not decrypt "
+				"GTK");
+			return -1;
+		}
+	} else {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported key_info type %d", ver);
+		return -1;
+	}
+	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
+		sm, !!(key_info & WPA_KEY_INFO_TXRX));
+	return 0;
+}
+
+
+static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
+				      const struct wpa_eapol_key *key,
+				      int ver, u16 key_info)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply), &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
+	key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	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, ver, sm->bssid, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
+					  const unsigned char *src_addr,
+					  const struct wpa_eapol_key *key,
+					  int extra_len, u16 ver)
+{
+	u16 key_info, keydatalen;
+	int rekey, ret;
+	struct wpa_gtk_data gd;
+
+	os_memset(&gd, 0, sizeof(gd));
+
+	rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+
+	key_info = WPA_GET_BE16(key->key_info);
+	keydatalen = WPA_GET_BE16(key->key_data_length);
+
+	if (sm->proto == WPA_PROTO_RSN) {
+		ret = wpa_supplicant_process_1_of_2_rsn(sm,
+							(const u8 *) (key + 1),
+							keydatalen, key_info,
+							&gd);
+	} else {
+		ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
+							key_info, extra_len,
+							ver, &gd);
+	}
+
+	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+
+	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))
+		goto failed;
+
+	if (rekey) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
+			"completed with " MACSTR " [GTK=%s]",
+			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
+		wpa_sm_cancel_auth_timeout(sm);
+		wpa_sm_set_state(sm, WPA_COMPLETED);
+
+		wpa_sm_set_rekey_offload(sm);
+	} else {
+		wpa_supplicant_key_neg_complete(sm, sm->bssid,
+						key_info &
+						WPA_KEY_INFO_SECURE);
+	}
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
+					       struct wpa_eapol_key *key,
+					       u16 ver,
+					       const u8 *buf, size_t len)
+{
+	u8 mic[16];
+	int ok = 0;
+
+	os_memcpy(mic, key->key_mic, 16);
+	if (sm->tptk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid EAPOL-Key MIC "
+				"when using TPTK - ignoring TPTK");
+		} else {
+			ok = 1;
+			sm->tptk_set = 0;
+			sm->ptk_set = 1;
+			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+		}
+	}
+
+	if (!ok && sm->ptk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid EAPOL-Key MIC - "
+				"dropping packet");
+			return -1;
+		}
+		ok = 1;
+	}
+
+	if (!ok) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Could not verify EAPOL-Key MIC - "
+			"dropping packet");
+		return -1;
+	}
+
+	os_memcpy(sm->rx_replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	sm->rx_replay_counter_set = 1;
+	return 0;
+}
+
+
+/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
+static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
+					   struct wpa_eapol_key *key, u16 ver)
+{
+	u16 keydatalen = WPA_GET_BE16(key->key_data_length);
+
+	wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
+		    (u8 *) (key + 1), keydatalen);
+	if (!sm->ptk_set) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
+			"Data");
+		return -1;
+	}
+
+	/* Decrypt key data here so that this operation does not need
+	 * to be implemented separately for each message type. */
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+		u8 ek[32];
+		os_memcpy(ek, key->key_iv, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: RC4 failed");
+			return -1;
+		}
+	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+		u8 *buf;
+		if (keydatalen % 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Unsupported AES-WRAP len %d",
+				keydatalen);
+			return -1;
+		}
+		keydatalen -= 8; /* AES-WRAP adds 8 bytes */
+		buf = os_malloc(keydatalen);
+		if (buf == NULL) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: No memory for AES-UNWRAP buffer");
+			return -1;
+		}
+		if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
+			       (u8 *) (key + 1), buf)) {
+			os_free(buf);
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES unwrap failed - "
+				"could not decrypt EAPOL-Key key data");
+			return -1;
+		}
+		os_memcpy(key + 1, buf, keydatalen);
+		os_free(buf);
+		WPA_PUT_BE16(key->key_data_length, keydatalen);
+	} else {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported key_info type %d", ver);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
+			(u8 *) (key + 1), keydatalen);
+	return 0;
+}
+
+
+/**
+ * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+	if (sm && sm->cur_pmksa) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Cancelling PMKSA caching attempt");
+		sm->cur_pmksa = NULL;
+	}
+}
+
+
+static void wpa_eapol_key_dump(struct wpa_sm *sm,
+			       const struct wpa_eapol_key *key)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	u16 key_info = WPA_GET_BE16(key->key_info);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)",
+		key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
+		(key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+		WPA_KEY_INFO_KEY_INDEX_SHIFT,
+		(key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
+		key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
+		key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
+		key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
+		key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
+		key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
+		key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
+		key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
+		key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"  key_length=%u key_data_length=%u",
+		WPA_GET_BE16(key->key_length),
+		WPA_GET_BE16(key->key_data_length));
+	wpa_hexdump(MSG_DEBUG, "  replay_counter",
+		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16);
+	wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8);
+	wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8);
+	wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
+ * wpa_sm_rx_eapol - Process received WPA EAPOL frames
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @src_addr: Source MAC address of the EAPOL packet
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
+ *
+ * This function is called for each received EAPOL frame. Other than EAPOL-Key
+ * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
+ * only processing WPA and WPA2 EAPOL-Key frames.
+ *
+ * The received EAPOL-Key packets are validated and valid packets are replied
+ * to. In addition, key material (PTK, GTK) is configured at the end of a
+ * successful key handshake.
+ */
+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+		    const u8 *buf, size_t len)
+{
+	size_t plen, data_len, extra_len;
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info, ver;
+	u8 *tmp;
+	int ret = -1;
+	struct wpa_peerkey *peerkey = NULL;
+
+#ifdef CONFIG_IEEE80211R
+	sm->ft_completed = 0;
+#endif /* CONFIG_IEEE80211R */
+
+	if (len < sizeof(*hdr) + sizeof(*key)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame too short to be a WPA "
+			"EAPOL-Key (len %lu, expecting at least %lu)",
+			(unsigned long) len,
+			(unsigned long) sizeof(*hdr) + sizeof(*key));
+		return 0;
+	}
+
+	tmp = os_malloc(len);
+	if (tmp == NULL)
+		return -1;
+	os_memcpy(tmp, buf, len);
+
+	hdr = (struct ieee802_1x_hdr *) tmp;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	plen = be_to_host16(hdr->length);
+	data_len = plen + sizeof(*hdr);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"IEEE 802.1X RX: version=%d type=%d length=%lu",
+		hdr->version, hdr->type, (unsigned long) plen);
+
+	if (hdr->version < EAPOL_VERSION) {
+		/* TODO: backwards compatibility */
+	}
+	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame (type %u) discarded, "
+			"not a Key frame", hdr->type);
+		ret = 0;
+		goto out;
+	}
+	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame payload size %lu "
+			"invalid (frame size %lu)",
+			(unsigned long) plen, (unsigned long) len);
+		ret = 0;
+		goto out;
+	}
+
+	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
+	{
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL-Key type (%d) unknown, discarded",
+			key->type);
+		ret = 0;
+		goto out;
+	}
+	wpa_eapol_key_dump(sm, key);
+
+	eapol_sm_notify_lower_layer_success(sm->eapol, 0);
+	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
+	if (data_len < len) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: ignoring %lu bytes after the IEEE 802.1X data",
+			(unsigned long) len - data_len);
+	}
+	key_info = WPA_GET_BE16(key->key_info);
+	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Unsupported EAPOL-Key descriptor version %d",
+			ver);
+		goto out;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"FT: AP did not use AES-128-CMAC");
+			goto out;
+		}
+	} else
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: AP did not use the "
+				"negotiated AES-128-CMAC");
+			goto out;
+		}
+	} else
+#endif /* CONFIG_IEEE80211W */
+	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: CCMP is used, but EAPOL-Key "
+			"descriptor version (%d) is not 2", ver);
+		if (sm->group_cipher != WPA_CIPHER_CCMP &&
+		    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+			/* Earlier versions of IEEE 802.11i did not explicitly
+			 * require version 2 descriptor for all EAPOL-Key
+			 * packets, so allow group keys to use version 1 if
+			 * CCMP is not used for them. */
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: Backwards compatibility: allow invalid "
+				"version for non-CCMP group keys");
+		} else
+			goto out;
+	}
+	if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: GCMP is used, but EAPOL-Key "
+			"descriptor version (%d) is not 2", ver);
+		goto out;
+	}
+
+#ifdef CONFIG_PEERKEY
+	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
+		if (!peerkey->initiator && peerkey->replay_counter_set &&
+		    os_memcmp(key->replay_counter, peerkey->replay_counter,
+			      WPA_REPLAY_COUNTER_LEN) <= 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"RSN: EAPOL-Key Replay Counter did not "
+				"increase (STK) - dropping packet");
+			goto out;
+		} else if (peerkey->initiator) {
+			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
+			os_memcpy(_tmp, key->replay_counter,
+				  WPA_REPLAY_COUNTER_LEN);
+			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
+			if (os_memcmp(_tmp, peerkey->replay_counter,
+				      WPA_REPLAY_COUNTER_LEN) != 0) {
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: EAPOL-Key Replay "
+					"Counter did not match (STK) - "
+					"dropping packet");
+				goto out;
+			}
+		}
+	}
+
+	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Ack bit in key_info from STK peer");
+		goto out;
+	}
+#endif /* CONFIG_PEERKEY */
+
+	if (!peerkey && sm->rx_replay_counter_set &&
+	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
+		      WPA_REPLAY_COUNTER_LEN) <= 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: EAPOL-Key Replay Counter did not increase - "
+			"dropping packet");
+		goto out;
+	}
+
+	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
+#ifdef CONFIG_PEERKEY
+	    && (peerkey == NULL || !peerkey->initiator)
+#endif /* CONFIG_PEERKEY */
+		) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: No Ack bit in key_info");
+		goto out;
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: EAPOL-Key with Request bit - dropped");
+		goto out;
+	}
+
+	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
+	    wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+		goto out;
+
+#ifdef CONFIG_PEERKEY
+	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
+	    peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+		goto out;
+#endif /* CONFIG_PEERKEY */
+
+	extra_len = data_len - sizeof(*hdr) - sizeof(*key);
+
+	if (WPA_GET_BE16(key->key_data_length) > extra_len) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+			"frame - key_data overflow (%d > %lu)",
+			WPA_GET_BE16(key->key_data_length),
+			(unsigned long) extra_len);
+		goto out;
+	}
+	extra_len = WPA_GET_BE16(key->key_data_length);
+
+	if (sm->proto == WPA_PROTO_RSN &&
+	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+			goto out;
+		extra_len = WPA_GET_BE16(key->key_data_length);
+	}
+
+	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+		if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Ignored EAPOL-Key (Pairwise) with "
+				"non-zero key index");
+			goto out;
+		}
+		if (peerkey) {
+			/* PeerKey 4-Way Handshake */
+			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+		} else if (key_info & WPA_KEY_INFO_MIC) {
+			/* 3/4 4-Way Handshake */
+			wpa_supplicant_process_3_of_4(sm, key, ver);
+		} else {
+			/* 1/4 4-Way Handshake */
+			wpa_supplicant_process_1_of_4(sm, src_addr, key,
+						      ver);
+		}
+	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+		/* PeerKey SMK Handshake */
+		peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+				     ver);
+	} else {
+		if (key_info & WPA_KEY_INFO_MIC) {
+			/* 1/2 Group Key Handshake */
+			wpa_supplicant_process_1_of_2(sm, src_addr, key,
+						      extra_len, ver);
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: EAPOL-Key (Group) without Mic bit - "
+				"dropped");
+		}
+	}
+
+	ret = 1;
+
+out:
+	os_free(tmp);
+	return ret;
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
+{
+	switch (sm->key_mgmt) {
+	case WPA_KEY_MGMT_IEEE8021X:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
+			WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	case WPA_KEY_MGMT_PSK:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X :
+			WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+#ifdef CONFIG_IEEE80211R
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return RSN_AUTH_KEY_MGMT_FT_802_1X;
+	case WPA_KEY_MGMT_FT_PSK:
+		return RSN_AUTH_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_KEY_MGMT_CCKM:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_CCKM:
+			WPA_AUTH_KEY_MGMT_CCKM);
+	case WPA_KEY_MGMT_WPA_NONE:
+		return WPA_AUTH_KEY_MGMT_NONE;
+	default:
+		return 0;
+	}
+}
+
+
+#define RSN_SUITE "%02x-%02x-%02x-%d"
+#define RSN_SUITE_ARG(s) \
+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+
+/**
+ * wpa_sm_get_mib - Dump text list of MIB entries
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for the list
+ * @buflen: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used fetch dot11 MIB variables.
+ */
+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
+{
+	char pmkid_txt[PMKID_LEN * 2 + 1];
+	int rsna, ret;
+	size_t len;
+
+	if (sm->cur_pmksa) {
+		wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+				 sm->cur_pmksa->pmkid, PMKID_LEN);
+	} else
+		pmkid_txt[0] = '\0';
+
+	if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+	     wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
+	    sm->proto == WPA_PROTO_RSN)
+		rsna = 1;
+	else
+		rsna = 0;
+
+	ret = os_snprintf(buf, buflen,
+			  "dot11RSNAOptionImplemented=TRUE\n"
+			  "dot11RSNAPreauthenticationImplemented=TRUE\n"
+			  "dot11RSNAEnabled=%s\n"
+			  "dot11RSNAPreauthenticationEnabled=%s\n"
+			  "dot11RSNAConfigVersion=%d\n"
+			  "dot11RSNAConfigPairwiseKeysSupported=5\n"
+			  "dot11RSNAConfigGroupCipherSize=%d\n"
+			  "dot11RSNAConfigPMKLifetime=%d\n"
+			  "dot11RSNAConfigPMKReauthThreshold=%d\n"
+			  "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
+			  "dot11RSNAConfigSATimeout=%d\n",
+			  rsna ? "TRUE" : "FALSE",
+			  rsna ? "TRUE" : "FALSE",
+			  RSN_VERSION,
+			  wpa_cipher_key_len(sm->group_cipher) * 8,
+			  sm->dot11RSNAConfigPMKLifetime,
+			  sm->dot11RSNAConfigPMKReauthThreshold,
+			  sm->dot11RSNAConfigSATimeout);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	len = ret;
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAPMKIDUsed=%s\n"
+		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
+		"dot11RSNA4WayHandshakeFailures=%u\n",
+		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->pairwise_cipher)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->group_cipher)),
+		pmkid_txt,
+		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->pairwise_cipher)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->group_cipher)),
+		sm->dot11RSNA4WayHandshakeFailures);
+	if (ret >= 0 && (size_t) ret < buflen)
+		len += ret;
+
+	return (int) len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason)
+{
+	struct wpa_sm *sm = ctx;
+	int deauth = 0;
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+		MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+	if (sm->cur_pmksa == entry) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: %s current PMKSA entry",
+			reason == PMKSA_REPLACE ? "replaced" : "removed");
+		pmksa_cache_clear_current(sm);
+
+		/*
+		 * If an entry is simply being replaced, there's no need to
+		 * deauthenticate because it will be immediately re-added.
+		 * This happens when EAP authentication is completed again
+		 * (reauth or failed PMKSA caching attempt).
+		 */
+		if (reason != PMKSA_REPLACE)
+			deauth = 1;
+	}
+
+	if (reason == PMKSA_EXPIRE &&
+	    (sm->pmk_len == entry->pmk_len &&
+	     os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: deauthenticating due to expired PMK");
+		pmksa_cache_clear_current(sm);
+		deauth = 1;
+	}
+
+	if (deauth) {
+		os_memset(sm->pmk, 0, sizeof(sm->pmk));
+		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+	}
+}
+
+
+/**
+ * wpa_sm_init - Initialize WPA state machine
+ * @ctx: Context pointer for callbacks; this needs to be an allocated buffer
+ * Returns: Pointer to the allocated WPA state machine data
+ *
+ * This function is used to allocate a new WPA state machine and the returned
+ * value is passed to all WPA state machine calls.
+ */
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+	struct wpa_sm *sm;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	dl_list_init(&sm->pmksa_candidates);
+	sm->renew_snonce = 1;
+	sm->ctx = ctx;
+
+	sm->dot11RSNAConfigPMKLifetime = 43200;
+	sm->dot11RSNAConfigPMKReauthThreshold = 70;
+	sm->dot11RSNAConfigSATimeout = 60;
+
+	sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
+	if (sm->pmksa == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+			"RSN: PMKSA cache initialization failed");
+		os_free(sm);
+		return NULL;
+	}
+
+	return sm;
+}
+
+
+/**
+ * wpa_sm_deinit - Deinitialize WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_deinit(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	pmksa_cache_deinit(sm->pmksa);
+	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+	os_free(sm->assoc_wpa_ie);
+	os_free(sm->ap_wpa_ie);
+	os_free(sm->ap_rsn_ie);
+	os_free(sm->ctx);
+	peerkey_deinit(sm);
+#ifdef CONFIG_IEEE80211R
+	os_free(sm->assoc_resp_ies);
+#endif /* CONFIG_IEEE80211R */
+	os_free(sm);
+}
+
+
+/**
+ * wpa_sm_notify_assoc - Notify WPA state machine about association
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: The BSSID of the new association
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was established.
+ */
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+	int clear_ptk = 1;
+
+	if (sm == NULL)
+		return;
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Association event - clear replay counter");
+	os_memcpy(sm->bssid, bssid, ETH_ALEN);
+	os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+	sm->rx_replay_counter_set = 0;
+	sm->renew_snonce = 1;
+	if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
+		rsn_preauth_deinit(sm);
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_ft_is_completed(sm)) {
+		/*
+		 * Clear portValid to kick EAPOL state machine to re-enter
+		 * AUTHENTICATED state to get the EAPOL port Authorized.
+		 */
+		eapol_sm_notify_portValid(sm->eapol, FALSE);
+		wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
+
+		/* Prepare for the next transition */
+		wpa_ft_prepare_auth_request(sm, NULL);
+
+		clear_ptk = 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (clear_ptk) {
+		/*
+		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
+		 * this is not part of a Fast BSS Transition.
+		 */
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
+		sm->ptk_set = 0;
+		sm->tptk_set = 0;
+	}
+
+#ifdef CONFIG_TDLS
+	wpa_tdls_assoc(sm);
+#endif /* CONFIG_TDLS */
+}
+
+
+/**
+ * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was lost. This will abort any existing pre-authentication session.
+ */
+void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+	rsn_preauth_deinit(sm);
+	pmksa_cache_clear_current(sm);
+	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
+		sm->dot11RSNA4WayHandshakeFailures++;
+#ifdef CONFIG_TDLS
+	wpa_tdls_disassoc(sm);
+#endif /* CONFIG_TDLS */
+}
+
+
+/**
+ * wpa_sm_set_pmk - Set PMK
+ * @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
+ *
+ * Configure the PMK for WPA state machine.
+ */
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+{
+	if (sm == NULL)
+		return;
+
+	sm->pmk_len = pmk_len;
+	os_memcpy(sm->pmk, pmk, pmk_len);
+
+#ifdef CONFIG_IEEE80211R
+	/* Set XXKey to be PSK for FT key derivation */
+	sm->xxkey_len = pmk_len;
+	os_memcpy(sm->xxkey, pmk, pmk_len);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+/**
+ * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
+ * will be cleared.
+ */
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->cur_pmksa) {
+		sm->pmk_len = sm->cur_pmksa->pmk_len;
+		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
+	} else {
+		sm->pmk_len = PMK_LEN;
+		os_memset(sm->pmk, 0, PMK_LEN);
+	}
+}
+
+
+/**
+ * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @fast_reauth: Whether fast reauthentication (EAP) is allowed
+ */
+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+	if (sm)
+		sm->fast_reauth = fast_reauth;
+}
+
+
+/**
+ * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @scard_ctx: Context pointer for smartcard related callback functions
+ */
+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
+{
+	if (sm == NULL)
+		return;
+	sm->scard_ctx = scard_ctx;
+	if (sm->preauth_eapol)
+		eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx);
+}
+
+
+/**
+ * wpa_sm_set_config - Notification of current configration change
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @config: Pointer to current network configuration
+ *
+ * Notify WPA state machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed.
+ */
+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
+{
+	if (!sm)
+		return;
+
+	if (config) {
+		sm->network_ctx = config->network_ctx;
+		sm->peerkey_enabled = config->peerkey_enabled;
+		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
+		sm->proactive_key_caching = config->proactive_key_caching;
+		sm->eap_workaround = config->eap_workaround;
+		sm->eap_conf_ctx = config->eap_conf_ctx;
+		if (config->ssid) {
+			os_memcpy(sm->ssid, config->ssid, config->ssid_len);
+			sm->ssid_len = config->ssid_len;
+		} else
+			sm->ssid_len = 0;
+		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+	} else {
+		sm->network_ctx = NULL;
+		sm->peerkey_enabled = 0;
+		sm->allowed_pairwise_cipher = 0;
+		sm->proactive_key_caching = 0;
+		sm->eap_workaround = 0;
+		sm->eap_conf_ctx = NULL;
+		sm->ssid_len = 0;
+		sm->wpa_ptk_rekey = 0;
+	}
+}
+
+
+/**
+ * wpa_sm_set_own_addr - Set own MAC address
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @addr: Own MAC address
+ */
+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm)
+		os_memcpy(sm->own_addr, addr, ETH_ALEN);
+}
+
+
+/**
+ * wpa_sm_set_ifname - Set network interface name
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ifname: Interface name
+ * @bridge_ifname: Optional bridge interface name (for pre-auth)
+ */
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+		       const char *bridge_ifname)
+{
+	if (sm) {
+		sm->ifname = ifname;
+		sm->bridge_ifname = bridge_ifname;
+	}
+}
+
+
+/**
+ * wpa_sm_set_eapol - Set EAPOL state machine pointer
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+	if (sm)
+		sm->eapol = eapol;
+}
+
+
+/**
+ * wpa_sm_set_param - Set WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * @value: Parameter value
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+		     unsigned int value)
+{
+	int ret = 0;
+
+	if (sm == NULL)
+		return -1;
+
+	switch (param) {
+	case RSNA_PMK_LIFETIME:
+		if (value > 0)
+			sm->dot11RSNAConfigPMKLifetime = value;
+		else
+			ret = -1;
+		break;
+	case RSNA_PMK_REAUTH_THRESHOLD:
+		if (value > 0 && value <= 100)
+			sm->dot11RSNAConfigPMKReauthThreshold = value;
+		else
+			ret = -1;
+		break;
+	case RSNA_SA_TIMEOUT:
+		if (value > 0)
+			sm->dot11RSNAConfigSATimeout = value;
+		else
+			ret = -1;
+		break;
+	case WPA_PARAM_PROTO:
+		sm->proto = value;
+		break;
+	case WPA_PARAM_PAIRWISE:
+		sm->pairwise_cipher = value;
+		break;
+	case WPA_PARAM_GROUP:
+		sm->group_cipher = value;
+		break;
+	case WPA_PARAM_KEY_MGMT:
+		sm->key_mgmt = value;
+		break;
+#ifdef CONFIG_IEEE80211W
+	case WPA_PARAM_MGMT_GROUP:
+		sm->mgmt_group_cipher = value;
+		break;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_PARAM_RSN_ENABLED:
+		sm->rsn_enabled = value;
+		break;
+	case WPA_PARAM_MFP:
+		sm->mfp = value;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_sm_get_param - Get WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * Returns: Parameter value
+ */
+unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
+{
+	if (sm == NULL)
+		return 0;
+
+	switch (param) {
+	case RSNA_PMK_LIFETIME:
+		return sm->dot11RSNAConfigPMKLifetime;
+	case RSNA_PMK_REAUTH_THRESHOLD:
+		return sm->dot11RSNAConfigPMKReauthThreshold;
+	case RSNA_SA_TIMEOUT:
+		return sm->dot11RSNAConfigSATimeout;
+	case WPA_PARAM_PROTO:
+		return sm->proto;
+	case WPA_PARAM_PAIRWISE:
+		return sm->pairwise_cipher;
+	case WPA_PARAM_GROUP:
+		return sm->group_cipher;
+	case WPA_PARAM_KEY_MGMT:
+		return sm->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+	case WPA_PARAM_MGMT_GROUP:
+		return sm->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_PARAM_RSN_ENABLED:
+		return sm->rsn_enabled;
+	default:
+		return 0;
+	}
+}
+
+
+/**
+ * wpa_sm_get_status - Get WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_sm_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 WPA state machine for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+		      int verbose)
+{
+	char *pos = buf, *end = buf + buflen;
+	int ret;
+
+	ret = os_snprintf(pos, end - pos,
+			  "pairwise_cipher=%s\n"
+			  "group_cipher=%s\n"
+			  "key_mgmt=%s\n",
+			  wpa_cipher_txt(sm->pairwise_cipher),
+			  wpa_cipher_txt(sm->group_cipher),
+			  wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+		struct wpa_ie_data rsn;
+		if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
+		    >= 0 &&
+		    rsn.capabilities & (WPA_CAPABILITY_MFPR |
+					WPA_CAPABILITY_MFPC)) {
+			ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+					  (rsn.capabilities &
+					   WPA_CAPABILITY_MFPR) ? 2 : 1);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+	}
+
+	return pos - buf;
+}
+
+
+/**
+ * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to buffer for WPA/RSN IE
+ * @wpa_ie_len: Pointer to the length of the wpa_ie buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
+				    size_t *wpa_ie_len)
+{
+	int res;
+
+	if (sm == NULL)
+		return -1;
+
+	res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
+	if (res < 0)
+		return -1;
+	*wpa_ie_len = res;
+
+	wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
+		    wpa_ie, *wpa_ie_len);
+
+	if (sm->assoc_wpa_ie == NULL) {
+		/*
+		 * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
+		 * the correct version of the IE even if PMKSA caching is
+		 * aborted (which would remove PMKID from IE generation).
+		 */
+		sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
+		if (sm->assoc_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
+		sm->assoc_wpa_ie_len = *wpa_ie_len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
+ * Request frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_wpa_ie_default().
+ */
+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->assoc_wpa_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing own WPA/RSN IE");
+		sm->assoc_wpa_ie = NULL;
+		sm->assoc_wpa_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
+		sm->assoc_wpa_ie = os_malloc(len);
+		if (sm->assoc_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->assoc_wpa_ie, ie, len);
+		sm->assoc_wpa_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->ap_wpa_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing AP WPA IE");
+		sm->ap_wpa_ie = NULL;
+		sm->ap_wpa_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
+		sm->ap_wpa_ie = os_malloc(len);
+		if (sm->ap_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->ap_wpa_ie, ie, len);
+		sm->ap_wpa_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->ap_rsn_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing AP RSN IE");
+		sm->ap_rsn_ie = NULL;
+		sm->ap_rsn_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
+		sm->ap_rsn_ie = os_malloc(len);
+		if (sm->ap_rsn_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->ap_rsn_ie, ie, len);
+		sm->ap_rsn_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure
+ *
+ * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the
+ * parsed data into data.
+ */
+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
+{
+	if (sm == NULL)
+		return -1;
+
+	if (sm->assoc_wpa_ie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: No WPA/RSN IE available from association info");
+		return -1;
+	}
+	if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
+		return -2;
+	return 0;
+}
+
+
+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
+{
+#ifndef CONFIG_NO_WPA2
+	return pmksa_cache_list(sm->pmksa, buf, len);
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+void wpa_sm_drop_sa(struct wpa_sm *sm)
+{
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
+	sm->ptk_set = 0;
+	sm->tptk_set = 0;
+	os_memset(sm->pmk, 0, sizeof(sm->pmk));
+	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
+	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+}
+
+
+int wpa_sm_has_ptk(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->ptk_set;
+}
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+	pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+#ifdef CONFIG_WNM
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
+{
+	struct wpa_gtk_data gd;
+#ifdef CONFIG_IEEE80211W
+	struct wpa_igtk_kde igd;
+	u16 keyidx;
+#endif /* CONFIG_IEEE80211W */
+	u16 keyinfo;
+	u8 keylen;  /* plaintext key len */
+	u8 *key_rsc;
+
+	os_memset(&gd, 0, sizeof(gd));
+#ifdef CONFIG_IEEE80211W
+	os_memset(&igd, 0, sizeof(igd));
+#endif /* CONFIG_IEEE80211W */
+
+	keylen = wpa_cipher_key_len(sm->group_cipher);
+	gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+	gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+	if (gd.alg == WPA_ALG_NONE) {
+		wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+		return -1;
+	}
+
+	if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+		key_rsc = buf + 5;
+		keyinfo = WPA_GET_LE16(buf + 2);
+		gd.gtk_len = keylen;
+		if (gd.gtk_len != buf[4]) {
+			wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
+				   gd.gtk_len, buf[4]);
+			return -1;
+		}
+		gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
+		gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
+		         sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
+
+		os_memcpy(gd.gtk, buf + 13, gd.gtk_len);
+
+		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
+				gd.gtk, gd.gtk_len);
+		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
+				   "WNM mode");
+			return -1;
+		}
+#ifdef CONFIG_IEEE80211W
+	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+		os_memcpy(igd.keyid, buf + 2, 2);
+		os_memcpy(igd.pn, buf + 4, 6);
+
+		keyidx = WPA_GET_LE16(igd.keyid);
+		os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
+
+		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
+				igd.igtk, WPA_IGTK_LEN);
+		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				   keyidx, 0, igd.pn, sizeof(igd.pn),
+				   igd.igtk, WPA_IGTK_LEN) < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
+				   "WNM mode");
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else {
+		wpa_printf(MSG_DEBUG, "Unknown element id");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_WNM */

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,333 +0,0 @@
-/*
- * wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_H
-#define WPA_H
-
-#include "common/defs.h"
-#include "common/eapol_common.h"
-#include "common/wpa_common.h"
-
-struct wpa_sm;
-struct eapol_sm;
-struct wpa_config_blob;
-
-struct wpa_sm_ctx {
-	void *ctx; /* pointer to arbitrary upper level context */
-	void *msg_ctx; /* upper level context for wpa_msg() calls */
-
-	void (*set_state)(void *ctx, enum wpa_states state);
-	enum wpa_states (*get_state)(void *ctx);
-	void (*deauthenticate)(void * ctx, int reason_code); 
-	void (*disassociate)(void *ctx, int reason_code);
-	int (*set_key)(void *ctx, enum wpa_alg alg,
-		       const u8 *addr, int key_idx, int set_tx,
-		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
-	void * (*get_network_ctx)(void *ctx);
-	int (*get_bssid)(void *ctx, u8 *bssid);
-	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
-			  size_t len);
-	int (*get_beacon_ie)(void *ctx);
-	void (*cancel_auth_timeout)(void *ctx);
-	u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
-			    size_t *msg_len, void **data_pos);
-	int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
-	int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
-	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
-	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
-							  const char *name);
-	int (*mlme_setprotection)(void *ctx, const u8 *addr,
-				  int protection_type, int key_type);
-	int (*update_ft_ies)(void *ctx, const u8 *md, const u8 *ies,
-			     size_t ies_len);
-	int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap,
-			      const u8 *ies, size_t ies_len);
-	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
-};
-
-
-enum wpa_sm_conf_params {
-	RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */,
-	RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */,
-	RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */,
-	WPA_PARAM_PROTO,
-	WPA_PARAM_PAIRWISE,
-	WPA_PARAM_GROUP,
-	WPA_PARAM_KEY_MGMT,
-	WPA_PARAM_MGMT_GROUP,
-	WPA_PARAM_RSN_ENABLED,
-	WPA_PARAM_MFP
-};
-
-struct rsn_supp_config {
-	void *network_ctx;
-	int peerkey_enabled;
-	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
-	int proactive_key_caching;
-	int eap_workaround;
-	void *eap_conf_ctx;
-	const u8 *ssid;
-	size_t ssid_len;
-	int wpa_ptk_rekey;
-};
-
-#ifndef CONFIG_NO_WPA
-
-struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
-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);
-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);
-void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config);
-void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
-void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
-		       const char *bridge_ifname);
-void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
-int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
-				    size_t *wpa_ie_len);
-int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
-int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
-
-int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
-		     unsigned int value);
-unsigned int wpa_sm_get_param(struct wpa_sm *sm,
-			      enum wpa_sm_conf_params param);
-
-int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
-		      int verbose);
-
-void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
-
-int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
-		     struct wpa_ie_data *data);
-
-void wpa_sm_aborted_cached(struct wpa_sm *sm);
-int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-		    const u8 *buf, size_t len);
-int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
-int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
-void wpa_sm_drop_sa(struct wpa_sm *sm);
-int wpa_sm_has_ptk(struct wpa_sm *sm);
-
-#else /* CONFIG_NO_WPA */
-
-static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
-{
-	return (struct wpa_sm *) 1;
-}
-
-static inline void wpa_sm_deinit(struct wpa_sm *sm)
-{
-}
-
-static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
-{
-}
-
-static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
-{
-}
-
-static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
-				  size_t pmk_len)
-{
-}
-
-static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
-{
-}
-
-static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
-{
-}
-
-static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
-{
-}
-
-static inline void wpa_sm_set_config(struct wpa_sm *sm,
-				     struct rsn_supp_config *config)
-{
-}
-
-static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
-{
-}
-
-static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
-				     const char *bridge_ifname)
-{
-}
-
-static inline void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
-{
-}
-
-static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie,
-					  size_t len)
-{
-	return -1;
-}
-
-static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm,
-						  u8 *wpa_ie,
-						  size_t *wpa_ie_len)
-{
-	return -1;
-}
-
-static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie,
-				       size_t len)
-{
-	return -1;
-}
-
-static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
-				       size_t len)
-{
-	return -1;
-}
-
-static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
-{
-	return 0;
-}
-
-static inline int wpa_sm_set_param(struct wpa_sm *sm,
-				   enum wpa_sm_conf_params param,
-				   unsigned int value)
-{
-	return -1;
-}
-
-static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
-					    enum wpa_sm_conf_params param)
-{
-	return 0;
-}
-
-static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
-				    size_t buflen, int verbose)
-{
-	return 0;
-}
-
-static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
-				      int pairwise)
-{
-}
-
-static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
-				   struct wpa_ie_data *data)
-{
-	return -1;
-}
-
-static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
-{
-}
-
-static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
-				  const u8 *buf, size_t len)
-{
-	return -1;
-}
-
-static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm,
-					  struct wpa_ie_data *data)
-{
-	return -1;
-}
-
-static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf,
-					  size_t len)
-{
-	return -1;
-}
-
-static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
-{
-}
-
-static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
-{
-	return 0;
-}
-
-#endif /* CONFIG_NO_WPA */
-
-#ifdef CONFIG_PEERKEY
-int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
-#else /* CONFIG_PEERKEY */
-static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
-{
-	return -1;
-}
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211R
-
-int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
-int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
-int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-			    int ft_action, const u8 *target_ap,
-			    const u8 *ric_ies, size_t ric_ies_len);
-int wpa_ft_is_completed(struct wpa_sm *sm);
-int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
-				 size_t ies_len, const u8 *src_addr);
-int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
-			 const u8 *mdie);
-
-#else /* CONFIG_IEEE80211R */
-
-static inline int
-wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
-{
-	return 0;
-}
-
-static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm,
-					      const u8 *mdie)
-{
-	return 0;
-}
-
-static inline int
-wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-			int ft_action, const u8 *target_ap)
-{
-	return 0;
-}
-
-static inline int wpa_ft_is_completed(struct wpa_sm *sm)
-{
-	return 0;
-}
-
-static inline int
-wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-			     const u8 *src_addr)
-{
-	return -1;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-#endif /* WPA_H */

Copied: vendor/wpa/2.0/src/rsn_supp/wpa.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,370 @@
+/*
+ * wpa_supplicant - WPA definitions
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_H
+#define WPA_H
+
+#include "common/defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
+
+struct wpa_sm;
+struct eapol_sm;
+struct wpa_config_blob;
+
+struct wpa_sm_ctx {
+	void *ctx; /* pointer to arbitrary upper level context */
+	void *msg_ctx; /* upper level context for wpa_msg() calls */
+
+	void (*set_state)(void *ctx, enum wpa_states state);
+	enum wpa_states (*get_state)(void *ctx);
+	void (*deauthenticate)(void * ctx, int reason_code); 
+	int (*set_key)(void *ctx, enum wpa_alg alg,
+		       const u8 *addr, int key_idx, int set_tx,
+		       const u8 *seq, size_t seq_len,
+		       const u8 *key, size_t key_len);
+	void * (*get_network_ctx)(void *ctx);
+	int (*get_bssid)(void *ctx, u8 *bssid);
+	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+			  size_t len);
+	int (*get_beacon_ie)(void *ctx);
+	void (*cancel_auth_timeout)(void *ctx);
+	u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
+			    size_t *msg_len, void **data_pos);
+	int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+	int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+	int (*mlme_setprotection)(void *ctx, const u8 *addr,
+				  int protection_type, int key_type);
+	int (*update_ft_ies)(void *ctx, const u8 *md, const u8 *ies,
+			     size_t ies_len);
+	int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap,
+			      const u8 *ies, size_t ies_len);
+	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
+#ifdef CONFIG_TDLS
+	int (*tdls_get_capa)(void *ctx, int *tdls_supported,
+			     int *tdls_ext_setup);
+	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
+			      u8 action_code, u8 dialog_token,
+			      u16 status_code, const u8 *buf, size_t len);
+	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+				u16 capability, const u8 *supp_rates,
+				size_t supp_rates_len);
+#endif /* CONFIG_TDLS */
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+				  const u8 *replay_ctr);
+};
+
+
+enum wpa_sm_conf_params {
+	RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */,
+	RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */,
+	RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */,
+	WPA_PARAM_PROTO,
+	WPA_PARAM_PAIRWISE,
+	WPA_PARAM_GROUP,
+	WPA_PARAM_KEY_MGMT,
+	WPA_PARAM_MGMT_GROUP,
+	WPA_PARAM_RSN_ENABLED,
+	WPA_PARAM_MFP
+};
+
+struct rsn_supp_config {
+	void *network_ctx;
+	int peerkey_enabled;
+	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
+	int proactive_key_caching;
+	int eap_workaround;
+	void *eap_conf_ctx;
+	const u8 *ssid;
+	size_t ssid_len;
+	int wpa_ptk_rekey;
+};
+
+#ifndef CONFIG_NO_WPA
+
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
+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);
+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);
+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config);
+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+		       const char *bridge_ifname);
+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
+				    size_t *wpa_ie_len);
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
+
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+		     unsigned int value);
+unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+			      enum wpa_sm_conf_params param);
+
+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+		      int verbose);
+
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
+
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+		     struct wpa_ie_data *data);
+
+void wpa_sm_aborted_cached(struct wpa_sm *sm);
+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+		    const u8 *buf, size_t len);
+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+void wpa_sm_drop_sa(struct wpa_sm *sm);
+int wpa_sm_has_ptk(struct wpa_sm *sm);
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
+#else /* CONFIG_NO_WPA */
+
+static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+	return (struct wpa_sm *) 1;
+}
+
+static inline void wpa_sm_deinit(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+
+static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
+				  size_t pmk_len)
+{
+}
+
+static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+}
+
+static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
+{
+}
+
+static inline void wpa_sm_set_config(struct wpa_sm *sm,
+				     struct rsn_supp_config *config)
+{
+}
+
+static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
+{
+}
+
+static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+				     const char *bridge_ifname)
+{
+}
+
+static inline void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+					  size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm,
+						  u8 *wpa_ie,
+						  size_t *wpa_ie_len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+				       size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
+				       size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
+{
+	return 0;
+}
+
+static inline int wpa_sm_set_param(struct wpa_sm *sm,
+				   enum wpa_sm_conf_params param,
+				   unsigned int value)
+{
+	return -1;
+}
+
+static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+					    enum wpa_sm_conf_params param)
+{
+	return 0;
+}
+
+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
+				    size_t buflen, int verbose)
+{
+	return 0;
+}
+
+static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
+				      int pairwise)
+{
+}
+
+static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+				   struct wpa_ie_data *data)
+{
+	return -1;
+}
+
+static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+}
+
+static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+				  const u8 *buf, size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm,
+					  struct wpa_ie_data *data)
+{
+	return -1;
+}
+
+static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf,
+					  size_t len)
+{
+	return -1;
+}
+
+static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
+{
+}
+
+static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+					    const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+					    void *network_ctx)
+{
+}
+
+#endif /* CONFIG_NO_WPA */
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+#else /* CONFIG_PEERKEY */
+static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+	return -1;
+}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211R
+
+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			    int ft_action, const u8 *target_ap,
+			    const u8 *ric_ies, size_t ric_ies_len);
+int wpa_ft_is_completed(struct wpa_sm *sm);
+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
+				 size_t ies_len, const u8 *src_addr);
+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
+			 const u8 *mdie);
+
+#else /* CONFIG_IEEE80211R */
+
+static inline int
+wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	return 0;
+}
+
+static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm,
+					      const u8 *mdie)
+{
+	return 0;
+}
+
+static inline int
+wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			int ft_action, const u8 *target_ap)
+{
+	return 0;
+}
+
+static inline int wpa_ft_is_completed(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline int
+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			     const u8 *src_addr)
+{
+	return -1;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/* tdls.c */
+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_deinit(struct wpa_sm *sm);
+void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+
+#endif /* WPA_H */

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa_ft.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa_ft.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ft.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1040 +0,0 @@
-/*
- * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "wpa.h"
-#include "wpa_i.h"
-#include "wpa_ie.h"
-
-#ifdef CONFIG_IEEE80211R
-
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *tie;
-	size_t tie_len;
-	const u8 *igtk;
-	size_t igtk_len;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
-int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
-		      const struct wpa_eapol_key *key,
-		      struct wpa_ptk *ptk, size_t ptk_len)
-{
-	u8 ptk_name[WPA_PMK_NAME_LEN];
-	const u8 *anonce = key->key_nonce;
-
-	if (sm->xxkey_len == 0) {
-		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
-			   "derivation");
-		return -1;
-	}
-
-	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
-			  sm->ssid_len, sm->mobility_domain,
-			  sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
-			  sm->pmk_r0, sm->pmk_r0_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
-		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
-	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
-			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
-		    WPA_PMK_NAME_LEN);
-	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
-			  sm->bssid, sm->pmk_r1_name,
-			  (u8 *) ptk, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	return 0;
-}
-
-
-/**
- * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ies: Association Response IEs or %NULL to clear FT parameters
- * @ies_len: Length of ies buffer in octets
- * Returns: 0 on success, -1 on failure
- */
-int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
-{
-	struct wpa_ft_ies ft;
-
-	if (sm == NULL)
-		return 0;
-
-	if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
-		return -1;
-
-	if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
-		return -1;
-
-	if (ft.mdie) {
-		wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
-			    ft.mdie, MOBILITY_DOMAIN_ID_LEN);
-		os_memcpy(sm->mobility_domain, ft.mdie,
-			  MOBILITY_DOMAIN_ID_LEN);
-		sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
-		wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
-			   sm->mdie_ft_capab);
-	} else
-		os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
-
-	if (ft.r0kh_id) {
-		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
-			    ft.r0kh_id, ft.r0kh_id_len);
-		os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
-		sm->r0kh_id_len = ft.r0kh_id_len;
-	} else {
-		/* FIX: When should R0KH-ID be cleared? We need to keep the
-		 * old R0KH-ID in order to be able to use this during FT. */
-		/*
-		 * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN);
-		 * sm->r0kh_id_len = 0;
-		 */
-	}
-
-	if (ft.r1kh_id) {
-		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
-			    ft.r1kh_id, FT_R1KH_ID_LEN);
-		os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
-	} else
-		os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
-
-	os_free(sm->assoc_resp_ies);
-	sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
-	if (sm->assoc_resp_ies) {
-		u8 *pos = sm->assoc_resp_ies;
-		if (ft.mdie) {
-			os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
-			pos += ft.mdie_len + 2;
-		}
-		if (ft.ftie) {
-			os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
-			pos += ft.ftie_len + 2;
-		}
-		sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies;
-		wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from "
-			    "(Re)Association Response",
-			    sm->assoc_resp_ies, sm->assoc_resp_ies_len);
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @len: Buffer for returning the length of the IEs
- * @anonce: ANonce or %NULL if not yet available
- * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
- * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
- * @target_ap: Target AP address
- * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
- * @ric_ies_len: Length of ric_ies buffer in octets
- * @ap_mdie: Mobility Domain IE from the target AP
- * Returns: Pointer to buffer with IEs or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer with os_free();
- */
-static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
-			       const u8 *anonce, const u8 *pmk_name,
-			       const u8 *kck, const u8 *target_ap,
-			       const u8 *ric_ies, size_t ric_ies_len,
-			       const u8 *ap_mdie)
-{
-	size_t buf_len;
-	u8 *buf, *pos, *ftie_len, *ftie_pos;
-	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	struct rsn_ie_hdr *rsnie;
-	u16 capab;
-
-	sm->ft_completed = 0;
-
-	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
-		2 + sm->r0kh_id_len + ric_ies_len + 100;
-	buf = os_zalloc(buf_len);
-	if (buf == NULL)
-		return NULL;
-	pos = buf;
-
-	/* RSNIE[PMKR0Name/PMKR1Name] */
-	rsnie = (struct rsn_ie_hdr *) pos;
-	rsnie->elem_id = WLAN_EID_RSN;
-	WPA_PUT_LE16(rsnie->version, RSN_VERSION);
-	pos = (u8 *) (rsnie + 1);
-
-	/* Group Suite Selector */
-	if (sm->group_cipher == WPA_CIPHER_CCMP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	else if (sm->group_cipher == WPA_CIPHER_TKIP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	else {
-		wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
-			   sm->group_cipher);
-		os_free(buf);
-		return NULL;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	/* Pairwise Suite Count */
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-
-	/* Pairwise Suite List */
-	if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	else if (sm->pairwise_cipher == WPA_CIPHER_TKIP)
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	else {
-		wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
-			   sm->pairwise_cipher);
-		os_free(buf);
-		return NULL;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	/* Authenticated Key Management Suite Count */
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-
-	/* Authenticated Key Management Suite List */
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
-	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
-	else {
-		wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
-			   sm->key_mgmt);
-		os_free(buf);
-		return NULL;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	/* RSN Capabilities */
-	capab = 0;
-#ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
-		capab |= WPA_CAPABILITY_MFPC;
-#endif /* CONFIG_IEEE80211W */
-	WPA_PUT_LE16(pos, capab);
-	pos += 2;
-
-	/* PMKID Count */
-	WPA_PUT_LE16(pos, 1);
-	pos += 2;
-
-	/* PMKID List [PMKR0Name/PMKR1Name] */
-	os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
-	pos += WPA_PMK_NAME_LEN;
-
-#ifdef CONFIG_IEEE80211W
-	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
-		/* Management Group Cipher Suite */
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
-		pos += RSN_SELECTOR_LEN;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	rsnie->len = (pos - (u8 *) rsnie) - 2;
-
-	/* MDIE */
-	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-	*pos++ = sizeof(*mdie);
-	mdie = (struct rsn_mdie *) pos;
-	pos += sizeof(*mdie);
-	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
-		  MOBILITY_DOMAIN_ID_LEN);
-	mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
-		sm->mdie_ft_capab;
-
-	/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
-	ftie_pos = pos;
-	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
-	ftie_len = pos++;
-	ftie = (struct rsn_ftie *) pos;
-	pos += sizeof(*ftie);
-	os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
-	if (anonce)
-		os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
-	if (kck) {
-		/* R1KH-ID sub-element in third FT message */
-		*pos++ = FTIE_SUBELEM_R1KH_ID;
-		*pos++ = FT_R1KH_ID_LEN;
-		os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN);
-		pos += FT_R1KH_ID_LEN;
-	}
-	/* R0KH-ID sub-element */
-	*pos++ = FTIE_SUBELEM_R0KH_ID;
-	*pos++ = sm->r0kh_id_len;
-	os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
-	pos += sm->r0kh_id_len;
-	*ftie_len = pos - ftie_len - 1;
-
-	if (ric_ies) {
-		/* RIC Request */
-		os_memcpy(pos, ric_ies, ric_ies_len);
-		pos += ric_ies_len;
-	}
-
-	if (kck) {
-		/*
-		 * IEEE Std 802.11r-2008, 11A.8.4
-		 * MIC shall be calculated over:
-		 * non-AP STA MAC address
-		 * Target AP MAC address
-		 * Transaction seq number (5 for ReassocReq, 3 otherwise)
-		 * RSN IE
-		 * MDIE
-		 * FTIE (with MIC field set to 0)
-		 * RIC-Request (if present)
-		 */
-		/* Information element count */
-		ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
-							       ric_ies_len);
-		if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
-			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
-			       ftie_pos, 2 + *ftie_len,
-			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
-			       ric_ies_len, ftie->mic) < 0) {
-			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
-			os_free(buf);
-			return NULL;
-		}
-	}
-
-	*len = pos - buf;
-
-	return buf;
-}
-
-
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		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]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			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]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-#ifdef CONFIG_IEEE80211W
-		case FTIE_SUBELEM_IGTK:
-			parse->igtk = pos + 2;
-			parse->igtk_len = pos[1];
-			break;
-#endif /* CONFIG_IEEE80211W */
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_TIMEOUT_INTERVAL:
-			parse->tie = pos + 2;
-			parse->tie_len = pos[1];
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (parse->tie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* 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];
-	}
-	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);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
-{
-	int keylen;
-	enum wpa_alg alg;
-	u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };
-
-	wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
-
-	switch (sm->pairwise_cipher) {
-	case WPA_CIPHER_CCMP:
-		alg = WPA_ALG_CCMP;
-		keylen = 16;
-		break;
-	case WPA_CIPHER_TKIP:
-		alg = WPA_ALG_TKIP;
-		keylen = 32;
-		break;
-	default:
-		wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
-			   sm->pairwise_cipher);
-		return -1;
-	}
-
-	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
-			   sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
-		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_ft_prepare_auth_request - Generate over-the-air auth request
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @mdie: Target AP MDIE
- * Returns: 0 on success, -1 on failure
- */
-int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
-{
-	u8 *ft_ies;
-	size_t ft_ies_len;
-
-	/* Generate a new SNonce */
-	if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
-		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
-		return -1;
-	}
-
-	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, sm->bssid, NULL, 0, mdie);
-	if (ft_ies) {
-		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
-				     ft_ies, ft_ies_len);
-		os_free(ft_ies);
-	}
-
-	return 0;
-}
-
-
-int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
-			    int ft_action, const u8 *target_ap,
-			    const u8 *ric_ies, size_t ric_ies_len)
-{
-	u8 *ft_ies;
-	size_t ft_ies_len, ptk_len;
-	struct wpa_ft_ies parse;
-	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	u8 ptk_name[WPA_PMK_NAME_LEN];
-	int ret;
-	const u8 *bssid;
-
-	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
-	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
-
-	if (ft_action) {
-		if (!sm->over_the_ds_in_progress) {
-			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
-				   "- drop FT Action Response");
-			return -1;
-		}
-
-		if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
-			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
-				   "with this Target AP - drop FT Action "
-				   "Response");
-			return -1;
-		}
-	}
-
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
-		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
-			   "enabled for this connection");
-		return -1;
-	}
-
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
-		return -1;
-	}
-
-	mdie = (struct rsn_mdie *) parse.mdie;
-	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
-		return -1;
-	}
-
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return -1;
-	}
-
-	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
-		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
-			    sm->snonce, WPA_NONCE_LEN);
-		return -1;
-	}
-
-	if (parse.r0kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (parse.r0kh_id_len != sm->r0kh_id_len ||
-	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
-			   "the current R0KH-ID");
-		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
-			    parse.r0kh_id, parse.r0kh_id_len);
-		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
-			    sm->r0kh_id, sm->r0kh_id_len);
-		return -1;
-	}
-
-	if (parse.r1kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (parse.rsn_pmkid == NULL ||
-	    os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
-		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
-			   "RSNIE");
-		return -1;
-	}
-
-	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
-	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
-	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
-			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
-		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
-
-	bssid = target_ap;
-	ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
-	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
-			  bssid, sm->pmk_r1_name,
-			  (u8 *) &sm->ptk, ptk_len, ptk_name);
-	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
-			(u8 *) &sm->ptk, ptk_len);
-	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
-	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
-				    sm->pmk_r1_name, sm->ptk.kck, bssid,
-				    ric_ies, ric_ies_len,
-				    parse.mdie ? parse.mdie - 2 : NULL);
-	if (ft_ies) {
-		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
-				     ft_ies, ft_ies_len);
-		os_free(ft_ies);
-	}
-
-	wpa_sm_mark_authenticated(sm, bssid);
-	ret = wpa_ft_install_ptk(sm, bssid);
-	if (ret) {
-		/*
-		 * Some drivers do not support key configuration when we are
-		 * not associated with the target AP. Work around this by
-		 * trying again after the following reassociation gets
-		 * completed.
-		 */
-		wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
-			   "association - try again after reassociation");
-		sm->set_ptk_after_assoc = 1;
-	} else
-		sm->set_ptk_after_assoc = 0;
-
-	sm->ft_completed = 1;
-	if (ft_action) {
-		/*
-		 * The caller is expected trigger re-association with the
-		 * Target AP.
-		 */
-		os_memcpy(sm->bssid, target_ap, ETH_ALEN);
-	}
-
-	return 0;
-}
-
-
-int wpa_ft_is_completed(struct wpa_sm *sm)
-{
-	if (sm == NULL)
-		return 0;
-
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK)
-		return 0;
-
-	return sm->ft_completed;
-}
-
-
-static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
-				      size_t gtk_elem_len)
-{
-	u8 gtk[32];
-	int keyidx;
-	enum wpa_alg alg;
-	size_t gtk_len, keylen, rsc_len;
-
-	if (gtk_elem == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
-		return 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
-			gtk_elem, gtk_elem_len);
-
-	if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
-	    gtk_elem_len - 19 > sizeof(gtk)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
-			   "length %lu", (unsigned long) gtk_elem_len);
-		return -1;
-	}
-	gtk_len = gtk_elem_len - 19;
-	if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) {
-		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
-			   "decrypt GTK");
-		return -1;
-	}
-
-	switch (sm->group_cipher) {
-	case WPA_CIPHER_CCMP:
-		keylen = 16;
-		rsc_len = 6;
-		alg = WPA_ALG_CCMP;
-		break;
-	case WPA_CIPHER_TKIP:
-		keylen = 32;
-		rsc_len = 6;
-		alg = WPA_ALG_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		keylen = 13;
-		rsc_len = 0;
-		alg = WPA_ALG_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		keylen = 5;
-		rsc_len = 0;
-		alg = WPA_ALG_WEP;
-		break;
-	default:
-		wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
-			   sm->group_cipher);
-		return -1;
-	}
-
-	if (gtk_len < keylen) {
-		wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
-		return -1;
-	}
-
-	/* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */
-
-	keyidx = WPA_GET_LE16(gtk_elem) & 0x03;
-
-	if (gtk_elem[2] != keylen) {
-		wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
-			   "negotiated %lu",
-			   gtk_elem[2], (unsigned long) keylen);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
-	if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
-			   keyidx, 0, gtk_elem + 3, rsc_len, gtk, keylen) <
-	    0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
-			   "driver.");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
-				       size_t igtk_elem_len)
-{
-	u8 igtk[WPA_IGTK_LEN];
-	u16 keyidx;
-
-	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
-		return 0;
-
-	if (igtk_elem == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
-		return 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
-			igtk_elem, igtk_elem_len);
-
-	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
-			   "length %lu", (unsigned long) igtk_elem_len);
-		return -1;
-	}
-	if (igtk_elem[8] != WPA_IGTK_LEN) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
-			   "%d", igtk_elem[8]);
-		return -1;
-	}
-
-	if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
-		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
-			   "decrypt IGTK");
-		return -1;
-	}
-
-	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
-
-	keyidx = WPA_GET_LE16(igtk_elem);
-
-	wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
-			WPA_IGTK_LEN);
-	if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff",
-			   keyidx, 0, igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) <
-	    0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
-			   "driver.");
-		return -1;
-	}
-
-	return 0;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
-int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
-				 size_t ies_len, const u8 *src_addr)
-{
-	struct wpa_ft_ies parse;
-	struct rsn_mdie *mdie;
-	struct rsn_ftie *ftie;
-	unsigned int count;
-	u8 mic[16];
-
-	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
-
-	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
-		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
-			   "enabled for this connection");
-		return -1;
-	}
-
-	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
-		return -1;
-	}
-
-	mdie = (struct rsn_mdie *) parse.mdie;
-	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
-	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
-		      MOBILITY_DOMAIN_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
-		return -1;
-	}
-
-	ftie = (struct rsn_ftie *) parse.ftie;
-	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
-		return -1;
-	}
-
-	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
-		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
-			    ftie->snonce, WPA_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
-			    sm->snonce, WPA_NONCE_LEN);
-		return -1;
-	}
-
-	if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
-		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
-			    ftie->anonce, WPA_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
-			    sm->anonce, WPA_NONCE_LEN);
-		return -1;
-	}
-
-	if (parse.r0kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (parse.r0kh_id_len != sm->r0kh_id_len ||
-	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
-			   "the current R0KH-ID");
-		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
-			    parse.r0kh_id, parse.r0kh_id_len);
-		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
-			    sm->r0kh_id, sm->r0kh_id_len);
-		return -1;
-	}
-
-	if (parse.r1kh_id == NULL) {
-		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
-		return -1;
-	}
-
-	if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
-			   "ReassocResp");
-		return -1;
-	}
-
-	if (parse.rsn_pmkid == NULL ||
-	    os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
-		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
-			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
-		return -1;
-	}
-
-	count = 3;
-	if (parse.tie)
-		count++;
-	if (ftie->mic_control[1] != count) {
-		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
-			   "Control: received %u expected %u",
-			   ftie->mic_control[1], count);
-		return -1;
-	}
-
-	if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
-		       parse.mdie - 2, parse.mdie_len + 2,
-		       parse.ftie - 2, parse.ftie_len + 2,
-		       parse.rsn - 2, parse.rsn_len + 2,
-		       parse.ric, parse.ric_len,
-		       mic) < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
-		return -1;
-	}
-
-	if (os_memcmp(mic, ftie->mic, 16) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
-		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
-		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
-		return -1;
-	}
-
-	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
-		return -1;
-
-#ifdef CONFIG_IEEE80211W
-	if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
-		return -1;
-#endif /* CONFIG_IEEE80211W */
-
-	if (sm->set_ptk_after_assoc) {
-		wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
-			   "are associated");
-		if (wpa_ft_install_ptk(sm, src_addr) < 0)
-			return -1;
-		sm->set_ptk_after_assoc = 0;
-	}
-
-	if (parse.ric) {
-		wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
-			    parse.ric, parse.ric_len);
-		/* TODO: parse response and inform driver about results */
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_ft_start_over_ds - Generate over-the-DS auth request
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @target_ap: Target AP Address
- * @mdie: Mobility Domain IE from the target AP
- * Returns: 0 on success, -1 on failure
- */
-int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
-			 const u8 *mdie)
-{
-	u8 *ft_ies;
-	size_t ft_ies_len;
-
-	wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
-		   MAC2STR(target_ap));
-
-	/* Generate a new SNonce */
-	if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
-		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
-		return -1;
-	}
-
-	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
-				    NULL, target_ap, NULL, 0, mdie);
-	if (ft_ies) {
-		sm->over_the_ds_in_progress = 1;
-		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
-		wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
-		os_free(ft_ies);
-	}
-
-	return 0;
-}
-
-#endif /* CONFIG_IEEE80211R */

Copied: vendor/wpa/2.0/src/rsn_supp/wpa_ft.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa_ft.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa_ft.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ft.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,832 @@
+/*
+ * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
+ * Copyright (c) 2006-2007, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wpa.h"
+#include "wpa_i.h"
+
+#ifdef CONFIG_IEEE80211R
+
+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
+		      const struct wpa_eapol_key *key,
+		      struct wpa_ptk *ptk, size_t ptk_len)
+{
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	const u8 *anonce = key->key_nonce;
+
+	if (sm->xxkey_len == 0) {
+		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
+			   "derivation");
+		return -1;
+	}
+
+	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+			  sm->ssid_len, sm->mobility_domain,
+			  sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+			  sm->pmk_r0, sm->pmk_r0_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
+		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
+			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+			  sm->bssid, sm->pmk_r1_name,
+			  (u8 *) ptk, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ies: Association Response IEs or %NULL to clear FT parameters
+ * @ies_len: Length of ies buffer in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	struct wpa_ft_ies ft;
+
+	if (sm == NULL)
+		return 0;
+
+	if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
+		return -1;
+
+	if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+		return -1;
+
+	if (ft.mdie) {
+		wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+			    ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+		os_memcpy(sm->mobility_domain, ft.mdie,
+			  MOBILITY_DOMAIN_ID_LEN);
+		sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+		wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+			   sm->mdie_ft_capab);
+	} else
+		os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+
+	if (ft.r0kh_id) {
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
+			    ft.r0kh_id, ft.r0kh_id_len);
+		os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
+		sm->r0kh_id_len = ft.r0kh_id_len;
+	} else {
+		/* FIX: When should R0KH-ID be cleared? We need to keep the
+		 * old R0KH-ID in order to be able to use this during FT. */
+		/*
+		 * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN);
+		 * sm->r0kh_id_len = 0;
+		 */
+	}
+
+	if (ft.r1kh_id) {
+		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
+			    ft.r1kh_id, FT_R1KH_ID_LEN);
+		os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
+	} else
+		os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+
+	os_free(sm->assoc_resp_ies);
+	sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
+	if (sm->assoc_resp_ies) {
+		u8 *pos = sm->assoc_resp_ies;
+		if (ft.mdie) {
+			os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+			pos += ft.mdie_len + 2;
+		}
+		if (ft.ftie) {
+			os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
+			pos += ft.ftie_len + 2;
+		}
+		sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies;
+		wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from "
+			    "(Re)Association Response",
+			    sm->assoc_resp_ies, sm->assoc_resp_ies_len);
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @len: Buffer for returning the length of the IEs
+ * @anonce: ANonce or %NULL if not yet available
+ * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
+ * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @target_ap: Target AP address
+ * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
+ * @ric_ies_len: Length of ric_ies buffer in octets
+ * @ap_mdie: Mobility Domain IE from the target AP
+ * Returns: Pointer to buffer with IEs or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free();
+ */
+static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
+			       const u8 *anonce, const u8 *pmk_name,
+			       const u8 *kck, const u8 *target_ap,
+			       const u8 *ric_ies, size_t ric_ies_len,
+			       const u8 *ap_mdie)
+{
+	size_t buf_len;
+	u8 *buf, *pos, *ftie_len, *ftie_pos;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	struct rsn_ie_hdr *rsnie;
+	u16 capab;
+
+	sm->ft_completed = 0;
+
+	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+		2 + sm->r0kh_id_len + ric_ies_len + 100;
+	buf = os_zalloc(buf_len);
+	if (buf == NULL)
+		return NULL;
+	pos = buf;
+
+	/* RSNIE[PMKR0Name/PMKR1Name] */
+	rsnie = (struct rsn_ie_hdr *) pos;
+	rsnie->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(rsnie->version, RSN_VERSION);
+	pos = (u8 *) (rsnie + 1);
+
+	/* Group Suite Selector */
+	if (sm->group_cipher != WPA_CIPHER_CCMP &&
+	    sm->group_cipher != WPA_CIPHER_GCMP &&
+	    sm->group_cipher != WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
+			   sm->group_cipher);
+		os_free(buf);
+		return NULL;
+	}
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+						  sm->group_cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	/* Pairwise Suite Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* Pairwise Suite List */
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
+			   sm->pairwise_cipher);
+		os_free(buf);
+		return NULL;
+	}
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+						  sm->pairwise_cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	/* Authenticated Key Management Suite Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* Authenticated Key Management Suite List */
+	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+	else {
+		wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
+			   sm->key_mgmt);
+		os_free(buf);
+		return NULL;
+	}
+	pos += RSN_SELECTOR_LEN;
+
+	/* RSN Capabilities */
+	capab = 0;
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+		capab |= WPA_CAPABILITY_MFPC;
+#endif /* CONFIG_IEEE80211W */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	/* PMKID Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* PMKID List [PMKR0Name/PMKR1Name] */
+	os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
+	pos += WPA_PMK_NAME_LEN;
+
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	rsnie->len = (pos - (u8 *) rsnie) - 2;
+
+	/* MDIE */
+	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+	*pos++ = sizeof(*mdie);
+	mdie = (struct rsn_mdie *) pos;
+	pos += sizeof(*mdie);
+	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
+		  MOBILITY_DOMAIN_ID_LEN);
+	mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
+		sm->mdie_ft_capab;
+
+	/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
+	ftie_pos = pos;
+	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
+	ftie_len = pos++;
+	ftie = (struct rsn_ftie *) pos;
+	pos += sizeof(*ftie);
+	os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+	if (anonce)
+		os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+	if (kck) {
+		/* R1KH-ID sub-element in third FT message */
+		*pos++ = FTIE_SUBELEM_R1KH_ID;
+		*pos++ = FT_R1KH_ID_LEN;
+		os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN);
+		pos += FT_R1KH_ID_LEN;
+	}
+	/* R0KH-ID sub-element */
+	*pos++ = FTIE_SUBELEM_R0KH_ID;
+	*pos++ = sm->r0kh_id_len;
+	os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
+	pos += sm->r0kh_id_len;
+	*ftie_len = pos - ftie_len - 1;
+
+	if (ric_ies) {
+		/* RIC Request */
+		os_memcpy(pos, ric_ies, ric_ies_len);
+		pos += ric_ies_len;
+	}
+
+	if (kck) {
+		/*
+		 * IEEE Std 802.11r-2008, 11A.8.4
+		 * MIC shall be calculated over:
+		 * non-AP STA MAC address
+		 * Target AP MAC address
+		 * Transaction seq number (5 for ReassocReq, 3 otherwise)
+		 * RSN IE
+		 * MDIE
+		 * FTIE (with MIC field set to 0)
+		 * RIC-Request (if present)
+		 */
+		/* Information element count */
+		ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
+							       ric_ies_len);
+		if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
+			       ftie_pos, 2 + *ftie_len,
+			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
+			       ric_ies_len, ftie->mic) < 0) {
+			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
+			os_free(buf);
+			return NULL;
+		}
+	}
+
+	*len = pos - buf;
+
+	return buf;
+}
+
+
+static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
+{
+	int keylen;
+	enum wpa_alg alg;
+	u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };
+
+	wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
+
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
+			   sm->pairwise_cipher);
+		return -1;
+	}
+
+	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+
+	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
+			   sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_ft_prepare_auth_request - Generate over-the-air auth request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @mdie: Target AP MDIE
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len;
+
+	/* Generate a new SNonce */
+	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
+		return -1;
+	}
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
+				    NULL, sm->bssid, NULL, 0, mdie);
+	if (ft_ies) {
+		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
+				     ft_ies, ft_ies_len);
+		os_free(ft_ies);
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			    int ft_action, const u8 *target_ap,
+			    const u8 *ric_ies, size_t ric_ies_len)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len, ptk_len;
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	int ret;
+	const u8 *bssid;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
+	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
+
+	if (ft_action) {
+		if (!sm->over_the_ds_in_progress) {
+			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
+				   "- drop FT Action Response");
+			return -1;
+		}
+
+		if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
+				   "with this Target AP - drop FT Action "
+				   "Response");
+			return -1;
+		}
+	}
+
+	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
+			   "enabled for this connection");
+		return -1;
+	}
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return -1;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
+			   "RSNIE");
+		return -1;
+	}
+
+	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
+	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
+	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
+			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
+		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	bssid = target_ap;
+	ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
+	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
+			  bssid, sm->pmk_r1_name,
+			  (u8 *) &sm->ptk, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
+			(u8 *) &sm->ptk, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
+				    sm->pmk_r1_name, sm->ptk.kck, bssid,
+				    ric_ies, ric_ies_len,
+				    parse.mdie ? parse.mdie - 2 : NULL);
+	if (ft_ies) {
+		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
+				     ft_ies, ft_ies_len);
+		os_free(ft_ies);
+	}
+
+	wpa_sm_mark_authenticated(sm, bssid);
+	ret = wpa_ft_install_ptk(sm, bssid);
+	if (ret) {
+		/*
+		 * Some drivers do not support key configuration when we are
+		 * not associated with the target AP. Work around this by
+		 * trying again after the following reassociation gets
+		 * completed.
+		 */
+		wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
+			   "association - try again after reassociation");
+		sm->set_ptk_after_assoc = 1;
+	} else
+		sm->set_ptk_after_assoc = 0;
+
+	sm->ft_completed = 1;
+	if (ft_action) {
+		/*
+		 * The caller is expected trigger re-association with the
+		 * Target AP.
+		 */
+		os_memcpy(sm->bssid, target_ap, ETH_ALEN);
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_is_completed(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+
+	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK)
+		return 0;
+
+	return sm->ft_completed;
+}
+
+
+static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
+				      size_t gtk_elem_len)
+{
+	u8 gtk[32];
+	int keyidx;
+	enum wpa_alg alg;
+	size_t gtk_len, keylen, rsc_len;
+
+	if (gtk_elem == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
+		return 0;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
+			gtk_elem, gtk_elem_len);
+
+	if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
+	    gtk_elem_len - 19 > sizeof(gtk)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
+			   "length %lu", (unsigned long) gtk_elem_len);
+		return -1;
+	}
+	gtk_len = gtk_elem_len - 19;
+	if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) {
+		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
+			   "decrypt GTK");
+		return -1;
+	}
+
+	keylen = wpa_cipher_key_len(sm->group_cipher);
+	rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+	alg = wpa_cipher_to_alg(sm->group_cipher);
+	if (alg == WPA_ALG_NONE) {
+		wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
+			   sm->group_cipher);
+		return -1;
+	}
+
+	if (gtk_len < keylen) {
+		wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
+		return -1;
+	}
+
+	/* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */
+
+	keyidx = WPA_GET_LE16(gtk_elem) & 0x03;
+
+	if (gtk_elem[2] != keylen) {
+		wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
+			   "negotiated %lu",
+			   gtk_elem[2], (unsigned long) keylen);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
+			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
+			   "driver.");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
+				       size_t igtk_elem_len)
+{
+	u8 igtk[WPA_IGTK_LEN];
+	u16 keyidx;
+
+	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+		return 0;
+
+	if (igtk_elem == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
+		return 0;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
+			igtk_elem, igtk_elem_len);
+
+	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
+			   "length %lu", (unsigned long) igtk_elem_len);
+		return -1;
+	}
+	if (igtk_elem[8] != WPA_IGTK_LEN) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
+			   "%d", igtk_elem[8]);
+		return -1;
+	}
+
+	if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
+		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
+			   "decrypt IGTK");
+		return -1;
+	}
+
+	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+	keyidx = WPA_GET_LE16(igtk_elem);
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
+			WPA_IGTK_LEN);
+	if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
+			   igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
+		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
+			   "driver.");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
+				 size_t ies_len, const u8 *src_addr)
+{
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	unsigned int count;
+	u8 mic[16];
+
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
+
+	if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	    sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
+			   "enabled for this connection");
+		return -1;
+	}
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return -1;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
+			    ftie->anonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
+			    sm->anonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
+			   "ReassocResp");
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
+			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
+		return -1;
+	}
+
+	count = 3;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+	if (ftie->mic_control[1] != count) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
+			   "Control: received %u expected %u",
+			   ftie->mic_control[1], count);
+		return -1;
+	}
+
+	if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+		       parse.mdie - 2, parse.mdie_len + 2,
+		       parse.ftie - 2, parse.ftie_len + 2,
+		       parse.rsn - 2, parse.rsn_len + 2,
+		       parse.ric, parse.ric_len,
+		       mic) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+		return -1;
+	}
+
+	if (os_memcmp(mic, ftie->mic, 16) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+		return -1;
+	}
+
+	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
+		return -1;
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+		return -1;
+#endif /* CONFIG_IEEE80211W */
+
+	if (sm->set_ptk_after_assoc) {
+		wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
+			   "are associated");
+		if (wpa_ft_install_ptk(sm, src_addr) < 0)
+			return -1;
+		sm->set_ptk_after_assoc = 0;
+	}
+
+	if (parse.ric) {
+		wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
+			    parse.ric, parse.ric_len);
+		/* TODO: parse response and inform driver about results */
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_ft_start_over_ds - Generate over-the-DS auth request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @target_ap: Target AP Address
+ * @mdie: Mobility Domain IE from the target AP
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
+			 const u8 *mdie)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len;
+
+	wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
+		   MAC2STR(target_ap));
+
+	/* Generate a new SNonce */
+	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
+		return -1;
+	}
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
+				    NULL, target_ap, NULL, 0, mdie);
+	if (ft_ies) {
+		sm->over_the_ds_in_progress = 1;
+		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
+		wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
+		os_free(ft_ies);
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa_i.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,259 +0,0 @@
-/*
- * Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_I_H
-#define WPA_I_H
-
-#include "utils/list.h"
-
-struct wpa_peerkey;
-struct wpa_eapol_key;
-
-/**
- * struct wpa_sm - Internal WPA state machine data
- */
-struct wpa_sm {
-	u8 pmk[PMK_LEN];
-	size_t pmk_len;
-	struct wpa_ptk ptk, tptk;
-	int ptk_set, tptk_set;
-	u8 snonce[WPA_NONCE_LEN];
-	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
-	int renew_snonce;
-	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
-	int rx_replay_counter_set;
-	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
-
-	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
-
-	struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
-	struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
-	struct dl_list pmksa_candidates;
-
-	struct l2_packet_data *l2_preauth;
-	struct l2_packet_data *l2_preauth_br;
-	u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
-				     * 00:00:00:00:00:00 if no pre-auth is
-				     * in progress */
-	struct eapol_sm *preauth_eapol;
-
-	struct wpa_sm_ctx *ctx;
-
-	void *scard_ctx; /* context for smartcard callbacks */
-	int fast_reauth; /* whether EAP fast re-authentication is enabled */
-
-	void *network_ctx;
-	int peerkey_enabled;
-	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
-	int proactive_key_caching;
-	int eap_workaround;
-	void *eap_conf_ctx;
-	u8 ssid[32];
-	size_t ssid_len;
-	int wpa_ptk_rekey;
-
-	u8 own_addr[ETH_ALEN];
-	const char *ifname;
-	const char *bridge_ifname;
-	u8 bssid[ETH_ALEN];
-
-	unsigned int dot11RSNAConfigPMKLifetime;
-	unsigned int dot11RSNAConfigPMKReauthThreshold;
-	unsigned int dot11RSNAConfigSATimeout;
-
-	unsigned int dot11RSNA4WayHandshakeFailures;
-
-	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
-	unsigned int proto;
-	unsigned int pairwise_cipher;
-	unsigned int group_cipher;
-	unsigned int key_mgmt;
-	unsigned int mgmt_group_cipher;
-
-	int rsn_enabled; /* Whether RSN is enabled in configuration */
-	int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
-
-	u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
-	size_t assoc_wpa_ie_len;
-	u8 *ap_wpa_ie, *ap_rsn_ie;
-	size_t ap_wpa_ie_len, ap_rsn_ie_len;
-
-#ifdef CONFIG_PEERKEY
-	struct wpa_peerkey *peerkey;
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211R
-	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
-	size_t xxkey_len;
-	u8 pmk_r0[PMK_LEN];
-	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
-	u8 pmk_r1[PMK_LEN];
-	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
-	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
-	u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
-	size_t r0kh_id_len;
-	u8 r1kh_id[FT_R1KH_ID_LEN];
-	int ft_completed;
-	int over_the_ds_in_progress;
-	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
-	int set_ptk_after_assoc;
-	u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
-	u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
-	size_t assoc_resp_ies_len;
-#endif /* CONFIG_IEEE80211R */
-};
-
-
-static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state)
-{
-	WPA_ASSERT(sm->ctx->set_state);
-	sm->ctx->set_state(sm->ctx->ctx, state);
-}
-
-static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)
-{
-	WPA_ASSERT(sm->ctx->get_state);
-	return sm->ctx->get_state(sm->ctx->ctx);
-}
-
-static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
-{
-	WPA_ASSERT(sm->ctx->deauthenticate);
-	sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
-}
-
-static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
-{
-	WPA_ASSERT(sm->ctx->disassociate);
-	sm->ctx->disassociate(sm->ctx->ctx, reason_code);
-}
-
-static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
-				 const u8 *addr, int key_idx, int set_tx,
-				 const u8 *seq, size_t seq_len,
-				 const u8 *key, size_t key_len)
-{
-	WPA_ASSERT(sm->ctx->set_key);
-	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
-				seq, seq_len, key, key_len);
-}
-
-static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
-{
-	WPA_ASSERT(sm->ctx->get_network_ctx);
-	return sm->ctx->get_network_ctx(sm->ctx->ctx);
-}
-
-static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)
-{
-	WPA_ASSERT(sm->ctx->get_bssid);
-	return sm->ctx->get_bssid(sm->ctx->ctx, bssid);
-}
-
-static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest,
-				    u16 proto, const u8 *buf, size_t len)
-{
-	WPA_ASSERT(sm->ctx->ether_send);
-	return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len);
-}
-
-static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
-{
-	WPA_ASSERT(sm->ctx->get_beacon_ie);
-	return sm->ctx->get_beacon_ie(sm->ctx->ctx);
-}
-
-static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)
-{
-	WPA_ASSERT(sm->ctx->cancel_auth_timeout);
-	sm->ctx->cancel_auth_timeout(sm->ctx->ctx);
-}
-
-static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
-				      const void *data, u16 data_len,
-				      size_t *msg_len, void **data_pos)
-{
-	WPA_ASSERT(sm->ctx->alloc_eapol);
-	return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len,
-				    msg_len, data_pos);
-}
-
-static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
-				   const u8 *pmkid)
-{
-	WPA_ASSERT(sm->ctx->add_pmkid);
-	return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
-}
-
-static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
-				      const u8 *pmkid)
-{
-	WPA_ASSERT(sm->ctx->remove_pmkid);
-	return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
-}
-
-static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
-					    int protect_type, int key_type)
-{
-	WPA_ASSERT(sm->ctx->mlme_setprotection);
-	return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type,
-					   key_type);
-}
-
-static inline int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md,
-				       const u8 *ies, size_t ies_len)
-{
-	if (sm->ctx->update_ft_ies)
-		return sm->ctx->update_ft_ies(sm->ctx->ctx, md, ies, ies_len);
-	return -1;
-}
-
-static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action,
-					const u8 *target_ap,
-					const u8 *ies, size_t ies_len)
-{
-	if (sm->ctx->send_ft_action)
-		return sm->ctx->send_ft_action(sm->ctx->ctx, action, target_ap,
-					       ies, ies_len);
-	return -1;
-}
-
-static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
-					    const u8 *target_ap)
-{
-	if (sm->ctx->mark_authenticated)
-		return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap);
-	return -1;
-}
-
-
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
-			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,
-			       const u8 *wpa_ie, size_t wpa_ie_len,
-			       struct wpa_ptk *ptk);
-int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
-			       const struct wpa_eapol_key *key,
-			       u16 ver, u16 key_info,
-			       const u8 *kde, size_t kde_len,
-			       struct wpa_ptk *ptk);
-
-int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
-		      const struct wpa_eapol_key *key,
-		      struct wpa_ptk *ptk, size_t ptk_len);
-
-#endif /* WPA_I_H */

Copied: vendor/wpa/2.0/src/rsn_supp/wpa_i.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa_i.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,317 @@
+/*
+ * Internal WPA/RSN supplicant state machine definitions
+ * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_I_H
+#define WPA_I_H
+
+#include "utils/list.h"
+
+struct wpa_peerkey;
+struct wpa_tdls_peer;
+struct wpa_eapol_key;
+
+/**
+ * struct wpa_sm - Internal WPA state machine data
+ */
+struct wpa_sm {
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	struct wpa_ptk ptk, tptk;
+	int ptk_set, tptk_set;
+	u8 snonce[WPA_NONCE_LEN];
+	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
+	int renew_snonce;
+	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int rx_replay_counter_set;
+	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+
+	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
+
+	struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
+	struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
+	struct dl_list pmksa_candidates;
+
+	struct l2_packet_data *l2_preauth;
+	struct l2_packet_data *l2_preauth_br;
+	struct l2_packet_data *l2_tdls;
+	u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
+				     * 00:00:00:00:00:00 if no pre-auth is
+				     * in progress */
+	struct eapol_sm *preauth_eapol;
+
+	struct wpa_sm_ctx *ctx;
+
+	void *scard_ctx; /* context for smartcard callbacks */
+	int fast_reauth; /* whether EAP fast re-authentication is enabled */
+
+	void *network_ctx;
+	int peerkey_enabled;
+	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
+	int proactive_key_caching;
+	int eap_workaround;
+	void *eap_conf_ctx;
+	u8 ssid[32];
+	size_t ssid_len;
+	int wpa_ptk_rekey;
+
+	u8 own_addr[ETH_ALEN];
+	const char *ifname;
+	const char *bridge_ifname;
+	u8 bssid[ETH_ALEN];
+
+	unsigned int dot11RSNAConfigPMKLifetime;
+	unsigned int dot11RSNAConfigPMKReauthThreshold;
+	unsigned int dot11RSNAConfigSATimeout;
+
+	unsigned int dot11RSNA4WayHandshakeFailures;
+
+	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
+	unsigned int proto;
+	unsigned int pairwise_cipher;
+	unsigned int group_cipher;
+	unsigned int key_mgmt;
+	unsigned int mgmt_group_cipher;
+
+	int rsn_enabled; /* Whether RSN is enabled in configuration */
+	int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
+
+	u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
+	size_t assoc_wpa_ie_len;
+	u8 *ap_wpa_ie, *ap_rsn_ie;
+	size_t ap_wpa_ie_len, ap_rsn_ie_len;
+
+#ifdef CONFIG_PEERKEY
+	struct wpa_peerkey *peerkey;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+	struct wpa_tdls_peer *tdls;
+	int tdls_prohibited;
+	int tdls_disabled;
+
+	/* The driver supports TDLS */
+	int tdls_supported;
+
+	/*
+	 * The driver requires explicit discovery/setup/teardown frames sent
+	 * to it via tdls_mgmt.
+	 */
+	int tdls_external_setup;
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_IEEE80211R
+	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	size_t xxkey_len;
+	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
+	size_t r0kh_id_len;
+	u8 r1kh_id[FT_R1KH_ID_LEN];
+	int ft_completed;
+	int over_the_ds_in_progress;
+	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
+	int set_ptk_after_assoc;
+	u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
+	u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
+	size_t assoc_resp_ies_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+
+static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state)
+{
+	WPA_ASSERT(sm->ctx->set_state);
+	sm->ctx->set_state(sm->ctx->ctx, state);
+}
+
+static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_state);
+	return sm->ctx->get_state(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
+{
+	WPA_ASSERT(sm->ctx->deauthenticate);
+	sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
+}
+
+static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
+				 const u8 *addr, int key_idx, int set_tx,
+				 const u8 *seq, size_t seq_len,
+				 const u8 *key, size_t key_len)
+{
+	WPA_ASSERT(sm->ctx->set_key);
+	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
+				seq, seq_len, key, key_len);
+}
+
+static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_network_ctx);
+	return sm->ctx->get_network_ctx(sm->ctx->ctx);
+}
+
+static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)
+{
+	WPA_ASSERT(sm->ctx->get_bssid);
+	return sm->ctx->get_bssid(sm->ctx->ctx, bssid);
+}
+
+static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest,
+				    u16 proto, const u8 *buf, size_t len)
+{
+	WPA_ASSERT(sm->ctx->ether_send);
+	return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len);
+}
+
+static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_beacon_ie);
+	return sm->ctx->get_beacon_ie(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->cancel_auth_timeout);
+	sm->ctx->cancel_auth_timeout(sm->ctx->ctx);
+}
+
+static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
+				      const void *data, u16 data_len,
+				      size_t *msg_len, void **data_pos)
+{
+	WPA_ASSERT(sm->ctx->alloc_eapol);
+	return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len,
+				    msg_len, data_pos);
+}
+
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
+				   const u8 *pmkid)
+{
+	WPA_ASSERT(sm->ctx->add_pmkid);
+	return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
+				      const u8 *pmkid)
+{
+	WPA_ASSERT(sm->ctx->remove_pmkid);
+	return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
+					    int protect_type, int key_type)
+{
+	WPA_ASSERT(sm->ctx->mlme_setprotection);
+	return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type,
+					   key_type);
+}
+
+static inline int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md,
+				       const u8 *ies, size_t ies_len)
+{
+	if (sm->ctx->update_ft_ies)
+		return sm->ctx->update_ft_ies(sm->ctx->ctx, md, ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action,
+					const u8 *target_ap,
+					const u8 *ies, size_t ies_len)
+{
+	if (sm->ctx->send_ft_action)
+		return sm->ctx->send_ft_action(sm->ctx->ctx, action, target_ap,
+					       ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
+					    const u8 *target_ap)
+{
+	if (sm->ctx->mark_authenticated)
+		return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap);
+	return -1;
+}
+
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+	if (!sm->ctx->set_rekey_offload)
+		return;
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+				   sm->ptk.kck, sm->rx_replay_counter);
+}
+
+#ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+				       int *tdls_supported,
+				       int *tdls_ext_setup)
+{
+	if (sm->ctx->tdls_get_capa)
+		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+					      tdls_ext_setup);
+	return -1;
+}
+
+static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
+					u8 action_code, u8 dialog_token,
+					u16 status_code, const u8 *buf,
+					size_t len)
+{
+	if (sm->ctx->send_tdls_mgmt)
+		return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
+					       dialog_token, status_code,
+					       buf, len);
+	return -1;
+}
+
+static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
+				   const u8 *peer)
+{
+	if (sm->ctx->tdls_oper)
+		return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
+	return -1;
+}
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+			u16 capability, const u8 *supp_rates,
+			size_t supp_rates_len)
+{
+	if (sm->ctx->tdls_peer_addset)
+		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+						 capability, supp_rates,
+						 supp_rates_len);
+	return -1;
+}
+#endif /* CONFIG_TDLS */
+
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+			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,
+			       const u8 *wpa_ie, size_t wpa_ie_len,
+			       struct wpa_ptk *ptk);
+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       u16 ver, u16 key_info,
+			       const u8 *kde, size_t kde_len,
+			       struct wpa_ptk *ptk);
+
+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
+		      const struct wpa_eapol_key *key,
+		      struct wpa_ptk *ptk, size_t ptk_len);
+
+void wpa_tdls_assoc(struct wpa_sm *sm);
+void wpa_tdls_disassoc(struct wpa_sm *sm);
+
+#endif /* WPA_I_H */

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa_ie.c
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa_ie.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ie.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,581 +0,0 @@
-/*
- * wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa.h"
-#include "pmksa_cache.h"
-#include "common/ieee802_11_defs.h"
-#include "wpa_i.h"
-#include "wpa_ie.h"
-
-
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-		return WPA_CIPHER_NONE;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-		return WPA_CIPHER_WEP40;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-		return WPA_CIPHER_TKIP;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-		return WPA_CIPHER_CCMP;
-	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-		return WPA_CIPHER_WEP104;
-	return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-		return WPA_KEY_MGMT_IEEE8021X;
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-		return WPA_KEY_MGMT_PSK;
-	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-		return WPA_KEY_MGMT_WPA_NONE;
-	return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-				struct wpa_ie_data *data)
-{
-	const struct wpa_ie_hdr *hdr;
-	const u8 *pos;
-	int left;
-	int i, count;
-
-	os_memset(data, 0, sizeof(*data));
-	data->proto = WPA_PROTO_WPA;
-	data->pairwise_cipher = WPA_CIPHER_TKIP;
-	data->group_cipher = WPA_CIPHER_TKIP;
-	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	data->capabilities = 0;
-	data->pmkid = NULL;
-	data->num_pmkid = 0;
-	data->mgmt_group_cipher = 0;
-
-	if (wpa_ie_len == 0) {
-		/* No WPA IE - fail silently */
-		return -1;
-	}
-
-	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
-		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
-			   __func__, (unsigned long) wpa_ie_len);
-		return -1;
-	}
-
-	hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-	    hdr->len != wpa_ie_len - 2 ||
-	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-			   __func__);
-		return -1;
-	}
-
-	pos = (const u8 *) (hdr + 1);
-	left = wpa_ie_len - sizeof(*hdr);
-
-	if (left >= WPA_SELECTOR_LEN) {
-		data->group_cipher = wpa_selector_to_bitfield(pos);
-		pos += WPA_SELECTOR_LEN;
-		left -= WPA_SELECTOR_LEN;
-	} else if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
-			   __func__, left);
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
-				   "count %u left %u", __func__, count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
-			   __func__);
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
-				   "count %u left %u", __func__, count, left);
-			return -1;
-		}
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-			pos += WPA_SELECTOR_LEN;
-			left -= WPA_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
-			   __func__);
-		return -1;
-	}
-
-	if (left >= 2) {
-		data->capabilities = WPA_GET_LE16(pos);
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
-			   __func__, left);
-	}
-
-	return 0;
-}
-
-
-/**
- * wpa_parse_wpa_ie - Parse WPA/RSN IE
- * @wpa_ie: Pointer to WPA or RSN IE
- * @wpa_ie_len: Length of the WPA/RSN IE
- * @data: Pointer to data area for parsing results
- * Returns: 0 on success, -1 on failure
- *
- * Parse the contents of WPA or RSN IE and write the parsed data into data.
- */
-int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
-		     struct wpa_ie_data *data)
-{
-	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
-		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
-	else
-		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
-}
-
-
-static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
-			      int pairwise_cipher, int group_cipher,
-			      int key_mgmt)
-{
-	u8 *pos;
-	struct wpa_ie_hdr *hdr;
-
-	if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
-	    2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
-		return -1;
-
-	hdr = (struct wpa_ie_hdr *) wpa_ie;
-	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
-	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
-	WPA_PUT_LE16(hdr->version, WPA_VERSION);
-	pos = (u8 *) (hdr + 1);
-
-	if (group_cipher == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-	} else if (group_cipher == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-	} else if (group_cipher == WPA_CIPHER_WEP104) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
-	} else if (group_cipher == WPA_CIPHER_WEP40) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
-			   group_cipher);
-		return -1;
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (pairwise_cipher == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-	} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-	} else if (pairwise_cipher == WPA_CIPHER_NONE) {
-		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
-			   pairwise_cipher);
-		return -1;
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
-	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
-		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
-	} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
-		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
-			   key_mgmt);
-		return -1;
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	/* WPA Capabilities; use defaults, so no need to include it */
-
-	hdr->len = (pos - wpa_ie) - 2;
-
-	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
-
-	return pos - wpa_ie;
-}
-
-
-static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
-			      int pairwise_cipher, int group_cipher,
-			      int key_mgmt, int mgmt_group_cipher,
-			      struct wpa_sm *sm)
-{
-#ifndef CONFIG_NO_WPA2
-	u8 *pos;
-	struct rsn_ie_hdr *hdr;
-	u16 capab;
-
-	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
-	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
-	    (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
-		wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
-			   (unsigned long) rsn_ie_len);
-		return -1;
-	}
-
-	hdr = (struct rsn_ie_hdr *) rsn_ie;
-	hdr->elem_id = WLAN_EID_RSN;
-	WPA_PUT_LE16(hdr->version, RSN_VERSION);
-	pos = (u8 *) (hdr + 1);
-
-	if (group_cipher == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	} else if (group_cipher == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	} else if (group_cipher == WPA_CIPHER_WEP104) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
-	} else if (group_cipher == WPA_CIPHER_WEP40) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
-			   group_cipher);
-		return -1;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (pairwise_cipher == WPA_CIPHER_CCMP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-	} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-	} else if (pairwise_cipher == WPA_CIPHER_NONE) {
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
-			   pairwise_cipher);
-		return -1;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
-	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
-#ifdef CONFIG_IEEE80211R
-	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
-	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
-	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
-		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
-			   key_mgmt);
-		return -1;
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	/* RSN Capabilities */
-	capab = 0;
-#ifdef CONFIG_IEEE80211W
-	if (sm->mfp)
-		capab |= WPA_CAPABILITY_MFPC;
-	if (sm->mfp == 2)
-		capab |= WPA_CAPABILITY_MFPR;
-#endif /* CONFIG_IEEE80211W */
-	WPA_PUT_LE16(pos, capab);
-	pos += 2;
-
-	if (sm->cur_pmksa) {
-		/* PMKID Count (2 octets, little endian) */
-		*pos++ = 1;
-		*pos++ = 0;
-		/* PMKID */
-		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
-		pos += PMKID_LEN;
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
-		if (!sm->cur_pmksa) {
-			/* PMKID Count */
-			WPA_PUT_LE16(pos, 0);
-			pos += 2;
-		}
-
-		/* Management Group Cipher Suite */
-		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
-		pos += RSN_SELECTOR_LEN;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	hdr->len = (pos - rsn_ie) - 2;
-
-	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
-
-	return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-	return -1;
-#endif /* CONFIG_NO_WPA2 */
-}
-
-
-/**
- * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
- * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
- * Returns: Length of the generated WPA/RSN IE or -1 on failure
- */
-int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
-{
-	if (sm->proto == WPA_PROTO_RSN)
-		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
-					  sm->pairwise_cipher,
-					  sm->group_cipher,
-					  sm->key_mgmt, sm->mgmt_group_cipher,
-					  sm);
-	else
-		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
-					  sm->pairwise_cipher,
-					  sm->group_cipher,
-					  sm->key_mgmt);
-}
-
-
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	if (pos[1] == 0)
-		return 1;
-
-	if (pos[1] >= 6 &&
-	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
-	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
-	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
-		ie->wpa_ie = pos;
-		ie->wpa_ie_len = pos[1] + 2;
-		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
-			    ie->wpa_ie, ie->wpa_ie_len);
-		return 0;
-	}
-
-	if (pos + 1 + RSN_SELECTOR_LEN < end &&
-	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
-		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
-			    pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
-		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
-				pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
-		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
-		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
-			    pos, pos[1] + 2);
-		return 0;
-	}
-
-#ifdef CONFIG_PEERKEY
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
-		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
-				pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
-		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
-		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
-			    pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
-		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
-		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
-			    pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
-		ie->error = pos + 2 + RSN_SELECTOR_LEN;
-		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
-			    pos, pos[1] + 2);
-		return 0;
-	}
-#endif /* CONFIG_PEERKEY */
-
-#ifdef CONFIG_IEEE80211W
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
-		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
-		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
-		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
-				pos, pos[1] + 2);
-		return 0;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	const u8 *pos, *end;
-	int ret = 0;
-
-	os_memset(ie, 0, sizeof(*ie));
-	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
-		if (pos[0] == 0xdd &&
-		    ((pos == buf + len - 1) || pos[1] == 0)) {
-			/* Ignore padding */
-			break;
-		}
-		if (pos + 2 + pos[1] > end) {
-			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
-				   "underflow (ie=%d len=%d pos=%d)",
-				   pos[0], pos[1], (int) (pos - buf));
-			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
-					buf, len);
-			ret = -1;
-			break;
-		}
-		if (*pos == WLAN_EID_RSN) {
-			ie->rsn_ie = pos;
-			ie->rsn_ie_len = pos[1] + 2;
-			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
-				    ie->rsn_ie, ie->rsn_ie_len);
-#ifdef CONFIG_IEEE80211R
-		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
-			ie->mdie = pos;
-			ie->mdie_len = pos[1] + 2;
-			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
-				    ie->mdie, ie->mdie_len);
-		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
-			ie->ftie = pos;
-			ie->ftie_len = pos[1] + 2;
-			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
-				    ie->ftie, ie->ftie_len);
-		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
-			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
-				ie->reassoc_deadline = pos;
-				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
-					    "in EAPOL-Key",
-					    ie->reassoc_deadline, pos[1] + 2);
-			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
-				ie->key_lifetime = pos;
-				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
-					    "in EAPOL-Key",
-					    ie->key_lifetime, pos[1] + 2);
-			} else {
-				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
-					    "EAPOL-Key Key Data IE",
-					    pos, 2 + pos[1]);
-			}
-#endif /* CONFIG_IEEE80211R */
-		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
-			ret = wpa_parse_generic(pos, end, ie);
-			if (ret < 0)
-				break;
-			if (ret > 0) {
-				ret = 0;
-				break;
-			}
-		} else {
-			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
-				    "Key Data IE", pos, 2 + pos[1]);
-		}
-	}
-
-	return ret;
-}

Copied: vendor/wpa/2.0/src/rsn_supp/wpa_ie.c (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa_ie.c)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa_ie.c	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ie.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,445 @@
+/*
+ * wpa_supplicant - WPA/RSN IE and KDE processing
+ * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa.h"
+#include "pmksa_cache.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+
+
+/**
+ * wpa_parse_wpa_ie - Parse WPA/RSN IE
+ * @wpa_ie: Pointer to WPA or RSN IE
+ * @wpa_ie_len: Length of the WPA/RSN IE
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 on failure
+ *
+ * Parse the contents of WPA or RSN IE and write the parsed data into data.
+ */
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+		     struct wpa_ie_data *data)
+{
+	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
+		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+	else
+		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
+}
+
+
+static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
+			      int pairwise_cipher, int group_cipher,
+			      int key_mgmt)
+{
+	u8 *pos;
+	struct wpa_ie_hdr *hdr;
+	u32 suite;
+
+	if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
+	    2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
+		return -1;
+
+	hdr = (struct wpa_ie_hdr *) wpa_ie;
+	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
+	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
+	WPA_PUT_LE16(hdr->version, WPA_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
+	if (suite == 0) {
+		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+			   group_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
+	if (suite == 0 ||
+	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+	     pairwise_cipher != WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+			   pairwise_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
+	} else {
+		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
+			   key_mgmt);
+		return -1;
+	}
+	pos += WPA_SELECTOR_LEN;
+
+	/* WPA Capabilities; use defaults, so no need to include it */
+
+	hdr->len = (pos - wpa_ie) - 2;
+
+	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
+
+	return pos - wpa_ie;
+}
+
+
+static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
+			      int pairwise_cipher, int group_cipher,
+			      int key_mgmt, int mgmt_group_cipher,
+			      struct wpa_sm *sm)
+{
+#ifndef CONFIG_NO_WPA2
+	u8 *pos;
+	struct rsn_ie_hdr *hdr;
+	u16 capab;
+	u32 suite;
+
+	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
+	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
+	    (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
+		wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
+			   (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (struct rsn_ie_hdr *) rsn_ie;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+	if (suite == 0) {
+		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+			   group_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+	if (suite == 0 ||
+	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+	     pairwise_cipher != WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+			   pairwise_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
+#ifdef CONFIG_IEEE80211R
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
+	} else {
+		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
+			   key_mgmt);
+		return -1;
+	}
+	pos += RSN_SELECTOR_LEN;
+
+	/* RSN Capabilities */
+	capab = 0;
+#ifdef CONFIG_IEEE80211W
+	if (sm->mfp)
+		capab |= WPA_CAPABILITY_MFPC;
+	if (sm->mfp == 2)
+		capab |= WPA_CAPABILITY_MFPR;
+#endif /* CONFIG_IEEE80211W */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	if (sm->cur_pmksa) {
+		/* PMKID Count (2 octets, little endian) */
+		*pos++ = 1;
+		*pos++ = 0;
+		/* PMKID */
+		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
+		pos += PMKID_LEN;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+		if (!sm->cur_pmksa) {
+			/* PMKID Count */
+			WPA_PUT_LE16(pos, 0);
+			pos += 2;
+		}
+
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	hdr->len = (pos - rsn_ie) - 2;
+
+	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
+
+	return pos - rsn_ie;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+/**
+ * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
+ * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
+ * Returns: Length of the generated WPA/RSN IE or -1 on failure
+ */
+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
+{
+	if (sm->proto == WPA_PROTO_RSN)
+		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
+					  sm->pairwise_cipher,
+					  sm->group_cipher,
+					  sm->key_mgmt, sm->mgmt_group_cipher,
+					  sm);
+	else
+		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
+					  sm->pairwise_cipher,
+					  sm->group_cipher,
+					  sm->key_mgmt);
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+			    ie->wpa_ie, ie->wpa_ie_len);
+		return 0;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < end &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
+		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
+		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
+		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
+		ie->error = pos + 2 + RSN_SELECTOR_LEN;
+		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	os_memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+					buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+				    ie->rsn_ie, ie->rsn_ie_len);
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+			ie->mdie = pos;
+			ie->mdie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+				    ie->mdie, ie->mdie_len);
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+			ie->ftie = pos;
+			ie->ftie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+				    ie->ftie, ie->ftie_len);
+		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+				ie->reassoc_deadline = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+					    "in EAPOL-Key",
+					    ie->reassoc_deadline, pos[1] + 2);
+			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+				ie->key_lifetime = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+					    "in EAPOL-Key",
+					    ie->key_lifetime, pos[1] + 2);
+			} else {
+				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+					    "EAPOL-Key Key Data IE",
+					    pos, 2 + pos[1]);
+			}
+		} else if (*pos == WLAN_EID_LINK_ID) {
+			if (pos[1] >= 18) {
+				ie->lnkid = pos;
+				ie->lnkid_len = pos[1] + 2;
+			}
+		} else if (*pos == WLAN_EID_EXT_CAPAB) {
+			ie->ext_capab = pos;
+			ie->ext_capab_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_SUPP_RATES) {
+			ie->supp_rates = pos;
+			ie->supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+			ie->ext_supp_rates = pos;
+			ie->ext_supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+				    "Key Data IE", pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/rsn_supp/wpa_ie.h
===================================================================
--- vendor/wpa/dist/src/rsn_supp/wpa_ie.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ie.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,56 +0,0 @@
-/*
- * wpa_supplicant - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_IE_H
-#define WPA_IE_H
-
-struct wpa_eapol_ie_parse {
-	const u8 *wpa_ie;
-	size_t wpa_ie_len;
-	const u8 *rsn_ie;
-	size_t rsn_ie_len;
-	const u8 *pmkid;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *mac_addr;
-	size_t mac_addr_len;
-#ifdef CONFIG_PEERKEY
-	const u8 *smk;
-	size_t smk_len;
-	const u8 *nonce;
-	size_t nonce_len;
-	const u8 *lifetime;
-	size_t lifetime_len;
-	const u8 *error;
-	size_t error_len;
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211W
-	const u8 *igtk;
-	size_t igtk_len;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *reassoc_deadline;
-	const u8 *key_lifetime;
-#endif /* CONFIG_IEEE80211R */
-};
-
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
-			     struct wpa_eapol_ie_parse *ie);
-int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
-
-#endif /* WPA_IE_H */

Copied: vendor/wpa/2.0/src/rsn_supp/wpa_ie.h (from rev 9639, vendor/wpa/dist/src/rsn_supp/wpa_ie.h)
===================================================================
--- vendor/wpa/2.0/src/rsn_supp/wpa_ie.h	                        (rev 0)
+++ vendor/wpa/2.0/src/rsn_supp/wpa_ie.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,58 @@
+/*
+ * wpa_supplicant - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_IE_H
+#define WPA_IE_H
+
+struct wpa_sm;
+
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+	const u8 *smk;
+	size_t smk_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *lifetime;
+	size_t lifetime_len;
+	const u8 *error;
+	size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+	const u8 *igtk;
+	size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *reassoc_deadline;
+	const u8 *key_lifetime;
+	const u8 *lnkid;
+	size_t lnkid_len;
+	const u8 *ext_capab;
+	size_t ext_capab_len;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	const u8 *ext_supp_rates;
+	size_t ext_supp_rates_len;
+};
+
+int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie);
+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+
+#endif /* WPA_IE_H */

Deleted: vendor/wpa/2.0/src/tls/Makefile
===================================================================
--- vendor/wpa/dist/src/tls/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,37 +0,0 @@
-all: libtls.a
-
-clean:
-	rm -f *~ *.o *.d libtls.a
-
-install:
-	@echo Nothing to be made.
-
-
-include ../lib.rules
-
-CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
-CFLAGS += -DCONFIG_CRYPTO_INTERNAL
-
-LIB_OBJS= \
-	asn1.o \
-	bignum.o \
-	pkcs1.o \
-	pkcs5.o \
-	pkcs8.o \
-	rsa.o \
-	tlsv1_client.o \
-	tlsv1_client_read.o \
-	tlsv1_client_write.o \
-	tlsv1_common.o \
-	tlsv1_cred.o \
-	tlsv1_record.o \
-	tlsv1_server.o \
-	tlsv1_server_read.o \
-	tlsv1_server_write.o \
-	x509v3.o
-
-
-libtls.a: $(LIB_OBJS)
-	$(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/src/tls/Makefile (from rev 9639, vendor/wpa/dist/src/tls/Makefile)
===================================================================
--- vendor/wpa/2.0/src/tls/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,39 @@
+all: libtls.a
+
+clean:
+	rm -f *~ *.o *.d libtls.a
+
+install:
+	@echo Nothing to be made.
+
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
+
+LIB_OBJS= \
+	asn1.o \
+	bignum.o \
+	pkcs1.o \
+	pkcs5.o \
+	pkcs8.o \
+	rsa.o \
+	tlsv1_client.o \
+	tlsv1_client_read.o \
+	tlsv1_client_write.o \
+	tlsv1_common.o \
+	tlsv1_cred.o \
+	tlsv1_record.o \
+	tlsv1_server.o \
+	tlsv1_server_read.o \
+	tlsv1_server_write.o \
+	x509v3.o
+
+
+libtls.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/src/tls/asn1.c
===================================================================
--- vendor/wpa/dist/src/tls/asn1.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/asn1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,212 +0,0 @@
-/*
- * ASN.1 DER parsing
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "asn1.h"
-
-int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
-{
-	const u8 *pos, *end;
-	u8 tmp;
-
-	os_memset(hdr, 0, sizeof(*hdr));
-	pos = buf;
-	end = buf + len;
-
-	hdr->identifier = *pos++;
-	hdr->class = hdr->identifier >> 6;
-	hdr->constructed = !!(hdr->identifier & (1 << 5));
-
-	if ((hdr->identifier & 0x1f) == 0x1f) {
-		hdr->tag = 0;
-		do {
-			if (pos >= end) {
-				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
-					   "underflow");
-				return -1;
-			}
-			tmp = *pos++;
-			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
-				   "0x%02x", tmp);
-			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
-		} while (tmp & 0x80);
-	} else
-		hdr->tag = hdr->identifier & 0x1f;
-
-	tmp = *pos++;
-	if (tmp & 0x80) {
-		if (tmp == 0xff) {
-			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
-				   "value 0xff used");
-			return -1;
-		}
-		tmp &= 0x7f; /* number of subsequent octets */
-		hdr->length = 0;
-		if (tmp > 4) {
-			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
-			return -1;
-		}
-		while (tmp--) {
-			if (pos >= end) {
-				wpa_printf(MSG_DEBUG, "ASN.1: Length "
-					   "underflow");
-				return -1;
-			}
-			hdr->length = (hdr->length << 8) | *pos++;
-		}
-	} else {
-		/* Short form - length 0..127 in one octet */
-		hdr->length = tmp;
-	}
-
-	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
-		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
-		return -1;
-	}
-
-	hdr->payload = pos;
-	return 0;
-}
-
-
-int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
-{
-	const u8 *pos, *end;
-	unsigned long val;
-	u8 tmp;
-
-	os_memset(oid, 0, sizeof(*oid));
-
-	pos = buf;
-	end = buf + len;
-
-	while (pos < end) {
-		val = 0;
-
-		do {
-			if (pos >= end)
-				return -1;
-			tmp = *pos++;
-			val = (val << 7) | (tmp & 0x7f);
-		} while (tmp & 0x80);
-
-		if (oid->len >= ASN1_MAX_OID_LEN) {
-			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
-			return -1;
-		}
-		if (oid->len == 0) {
-			/*
-			 * The first octet encodes the first two object
-			 * identifier components in (X*40) + Y formula.
-			 * X = 0..2.
-			 */
-			oid->oid[0] = val / 40;
-			if (oid->oid[0] > 2)
-				oid->oid[0] = 2;
-			oid->oid[1] = val - oid->oid[0] * 40;
-			oid->len = 2;
-		} else
-			oid->oid[oid->len++] = val;
-	}
-
-	return 0;
-}
-
-
-int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
-		 const u8 **next)
-{
-	struct asn1_hdr hdr;
-
-	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
-		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
-			   "tag 0x%x", hdr.class, hdr.tag);
-		return -1;
-	}
-
-	*next = hdr.payload + hdr.length;
-
-	return asn1_parse_oid(hdr.payload, hdr.length, oid);
-}
-
-
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
-{
-	char *pos = buf;
-	size_t i;
-	int ret;
-
-	if (len == 0)
-		return;
-
-	buf[0] = '\0';
-
-	for (i = 0; i < oid->len; i++) {
-		ret = os_snprintf(pos, buf + len - pos,
-				  "%s%lu",
-				  i == 0 ? "" : ".", oid->oid[i]);
-		if (ret < 0 || ret >= buf + len - pos)
-			break;
-		pos += ret;
-	}
-	buf[len - 1] = '\0';
-}
-
-
-static u8 rotate_bits(u8 octet)
-{
-	int i;
-	u8 res;
-
-	res = 0;
-	for (i = 0; i < 8; i++) {
-		res <<= 1;
-		if (octet & 1)
-			res |= 1;
-		octet >>= 1;
-	}
-
-	return res;
-}
-
-
-unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
-{
-	unsigned long val = 0;
-	const u8 *pos = buf;
-
-	/* BER requires that unused bits are zero, so we can ignore the number
-	 * of unused bits */
-	pos++;
-
-	if (len >= 2)
-		val |= rotate_bits(*pos++);
-	if (len >= 3)
-		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
-	if (len >= 4)
-		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
-	if (len >= 5)
-		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
-	if (len >= 6)
-		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
-			   "(BIT STRING length %lu)",
-			   __func__, (unsigned long) len);
-
-	return val;
-}

Copied: vendor/wpa/2.0/src/tls/asn1.c (from rev 9639, vendor/wpa/dist/src/tls/asn1.c)
===================================================================
--- vendor/wpa/2.0/src/tls/asn1.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/asn1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,206 @@
+/*
+ * ASN.1 DER parsing
+ * Copyright (c) 2006, Jouni Malinen <j at 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 "asn1.h"
+
+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
+{
+	const u8 *pos, *end;
+	u8 tmp;
+
+	os_memset(hdr, 0, sizeof(*hdr));
+	pos = buf;
+	end = buf + len;
+
+	hdr->identifier = *pos++;
+	hdr->class = hdr->identifier >> 6;
+	hdr->constructed = !!(hdr->identifier & (1 << 5));
+
+	if ((hdr->identifier & 0x1f) == 0x1f) {
+		hdr->tag = 0;
+		do {
+			if (pos >= end) {
+				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
+					   "underflow");
+				return -1;
+			}
+			tmp = *pos++;
+			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
+				   "0x%02x", tmp);
+			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
+		} while (tmp & 0x80);
+	} else
+		hdr->tag = hdr->identifier & 0x1f;
+
+	tmp = *pos++;
+	if (tmp & 0x80) {
+		if (tmp == 0xff) {
+			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
+				   "value 0xff used");
+			return -1;
+		}
+		tmp &= 0x7f; /* number of subsequent octets */
+		hdr->length = 0;
+		if (tmp > 4) {
+			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
+			return -1;
+		}
+		while (tmp--) {
+			if (pos >= end) {
+				wpa_printf(MSG_DEBUG, "ASN.1: Length "
+					   "underflow");
+				return -1;
+			}
+			hdr->length = (hdr->length << 8) | *pos++;
+		}
+	} else {
+		/* Short form - length 0..127 in one octet */
+		hdr->length = tmp;
+	}
+
+	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
+		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
+		return -1;
+	}
+
+	hdr->payload = pos;
+	return 0;
+}
+
+
+int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
+{
+	const u8 *pos, *end;
+	unsigned long val;
+	u8 tmp;
+
+	os_memset(oid, 0, sizeof(*oid));
+
+	pos = buf;
+	end = buf + len;
+
+	while (pos < end) {
+		val = 0;
+
+		do {
+			if (pos >= end)
+				return -1;
+			tmp = *pos++;
+			val = (val << 7) | (tmp & 0x7f);
+		} while (tmp & 0x80);
+
+		if (oid->len >= ASN1_MAX_OID_LEN) {
+			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
+			return -1;
+		}
+		if (oid->len == 0) {
+			/*
+			 * The first octet encodes the first two object
+			 * identifier components in (X*40) + Y formula.
+			 * X = 0..2.
+			 */
+			oid->oid[0] = val / 40;
+			if (oid->oid[0] > 2)
+				oid->oid[0] = 2;
+			oid->oid[1] = val - oid->oid[0] * 40;
+			oid->len = 2;
+		} else
+			oid->oid[oid->len++] = val;
+	}
+
+	return 0;
+}
+
+
+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
+		 const u8 **next)
+{
+	struct asn1_hdr hdr;
+
+	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
+		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
+			   "tag 0x%x", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	*next = hdr.payload + hdr.length;
+
+	return asn1_parse_oid(hdr.payload, hdr.length, oid);
+}
+
+
+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
+{
+	char *pos = buf;
+	size_t i;
+	int ret;
+
+	if (len == 0)
+		return;
+
+	buf[0] = '\0';
+
+	for (i = 0; i < oid->len; i++) {
+		ret = os_snprintf(pos, buf + len - pos,
+				  "%s%lu",
+				  i == 0 ? "" : ".", oid->oid[i]);
+		if (ret < 0 || ret >= buf + len - pos)
+			break;
+		pos += ret;
+	}
+	buf[len - 1] = '\0';
+}
+
+
+static u8 rotate_bits(u8 octet)
+{
+	int i;
+	u8 res;
+
+	res = 0;
+	for (i = 0; i < 8; i++) {
+		res <<= 1;
+		if (octet & 1)
+			res |= 1;
+		octet >>= 1;
+	}
+
+	return res;
+}
+
+
+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
+{
+	unsigned long val = 0;
+	const u8 *pos = buf;
+
+	/* BER requires that unused bits are zero, so we can ignore the number
+	 * of unused bits */
+	pos++;
+
+	if (len >= 2)
+		val |= rotate_bits(*pos++);
+	if (len >= 3)
+		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
+	if (len >= 4)
+		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
+	if (len >= 5)
+		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
+	if (len >= 6)
+		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
+			   "(BIT STRING length %lu)",
+			   __func__, (unsigned long) len);
+
+	return val;
+}

Deleted: vendor/wpa/2.0/src/tls/asn1.h
===================================================================
--- vendor/wpa/dist/src/tls/asn1.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/asn1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,72 +0,0 @@
-/*
- * ASN.1 DER parsing
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef ASN1_H
-#define ASN1_H
-
-#define ASN1_TAG_EOC		0x00 /* not used with DER */
-#define ASN1_TAG_BOOLEAN	0x01
-#define ASN1_TAG_INTEGER	0x02
-#define ASN1_TAG_BITSTRING	0x03
-#define ASN1_TAG_OCTETSTRING	0x04
-#define ASN1_TAG_NULL		0x05
-#define ASN1_TAG_OID		0x06
-#define ASN1_TAG_OBJECT_DESCRIPTOR	0x07 /* not yet parsed */
-#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_UTF8STRING	0x0C /* not yet parsed */
-#define ANS1_TAG_RELATIVE_OID	0x0D
-#define ASN1_TAG_SEQUENCE	0x10 /* shall be constructed */
-#define ASN1_TAG_SET		0x11
-#define ASN1_TAG_NUMERICSTRING	0x12 /* not yet parsed */
-#define ASN1_TAG_PRINTABLESTRING	0x13
-#define ASN1_TAG_TG1STRING	0x14 /* not yet parsed */
-#define ASN1_TAG_VIDEOTEXSTRING	0x15 /* not yet parsed */
-#define ASN1_TAG_IA5STRING	0x16
-#define ASN1_TAG_UTCTIME	0x17
-#define ASN1_TAG_GENERALIZEDTIME	0x18 /* not yet parsed */
-#define ASN1_TAG_GRAPHICSTRING	0x19 /* not yet parsed */
-#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_CLASS_UNIVERSAL		0
-#define ASN1_CLASS_APPLICATION		1
-#define ASN1_CLASS_CONTEXT_SPECIFIC	2
-#define ASN1_CLASS_PRIVATE		3
-
-
-struct asn1_hdr {
-	const u8 *payload;
-	u8 identifier, class, constructed;
-	unsigned int tag, length;
-};
-
-#define ASN1_MAX_OID_LEN 20
-struct asn1_oid {
-	unsigned long oid[ASN1_MAX_OID_LEN];
-	size_t len;
-};
-
-
-int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
-int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
-int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
-		 const u8 **next);
-void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
-unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
-
-#endif /* ASN1_H */

Copied: vendor/wpa/2.0/src/tls/asn1.h (from rev 9639, vendor/wpa/dist/src/tls/asn1.h)
===================================================================
--- vendor/wpa/2.0/src/tls/asn1.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/asn1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,66 @@
+/*
+ * ASN.1 DER parsing
+ * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ASN1_H
+#define ASN1_H
+
+#define ASN1_TAG_EOC		0x00 /* not used with DER */
+#define ASN1_TAG_BOOLEAN	0x01
+#define ASN1_TAG_INTEGER	0x02
+#define ASN1_TAG_BITSTRING	0x03
+#define ASN1_TAG_OCTETSTRING	0x04
+#define ASN1_TAG_NULL		0x05
+#define ASN1_TAG_OID		0x06
+#define ASN1_TAG_OBJECT_DESCRIPTOR	0x07 /* not yet parsed */
+#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_UTF8STRING	0x0C /* not yet parsed */
+#define ANS1_TAG_RELATIVE_OID	0x0D
+#define ASN1_TAG_SEQUENCE	0x10 /* shall be constructed */
+#define ASN1_TAG_SET		0x11
+#define ASN1_TAG_NUMERICSTRING	0x12 /* not yet parsed */
+#define ASN1_TAG_PRINTABLESTRING	0x13
+#define ASN1_TAG_TG1STRING	0x14 /* not yet parsed */
+#define ASN1_TAG_VIDEOTEXSTRING	0x15 /* not yet parsed */
+#define ASN1_TAG_IA5STRING	0x16
+#define ASN1_TAG_UTCTIME	0x17
+#define ASN1_TAG_GENERALIZEDTIME	0x18 /* not yet parsed */
+#define ASN1_TAG_GRAPHICSTRING	0x19 /* not yet parsed */
+#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_CLASS_UNIVERSAL		0
+#define ASN1_CLASS_APPLICATION		1
+#define ASN1_CLASS_CONTEXT_SPECIFIC	2
+#define ASN1_CLASS_PRIVATE		3
+
+
+struct asn1_hdr {
+	const u8 *payload;
+	u8 identifier, class, constructed;
+	unsigned int tag, length;
+};
+
+#define ASN1_MAX_OID_LEN 20
+struct asn1_oid {
+	unsigned long oid[ASN1_MAX_OID_LEN];
+	size_t len;
+};
+
+
+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
+int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
+		 const u8 **next);
+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
+
+#endif /* ASN1_H */

Deleted: vendor/wpa/2.0/src/tls/bignum.c
===================================================================
--- vendor/wpa/dist/src/tls/bignum.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/bignum.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,230 +0,0 @@
-/*
- * Big number math
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "bignum.h"
-
-#ifdef CONFIG_INTERNAL_LIBTOMMATH
-#include "libtommath.c"
-#else /* CONFIG_INTERNAL_LIBTOMMATH */
-#include <tommath.h>
-#endif /* CONFIG_INTERNAL_LIBTOMMATH */
-
-
-/*
- * The current version is just a wrapper for LibTomMath library, so
- * struct bignum is just typecast to mp_int.
- */
-
-/**
- * bignum_init - Allocate memory for bignum
- * Returns: Pointer to allocated bignum or %NULL on failure
- */
-struct bignum * bignum_init(void)
-{
-	struct bignum *n = os_zalloc(sizeof(mp_int));
-	if (n == NULL)
-		return NULL;
-	if (mp_init((mp_int *) n) != MP_OKAY) {
-		os_free(n);
-		n = NULL;
-	}
-	return n;
-}
-
-
-/**
- * bignum_deinit - Free bignum
- * @n: Bignum from bignum_init()
- */
-void bignum_deinit(struct bignum *n)
-{
-	if (n) {
-		mp_clear((mp_int *) n);
-		os_free(n);
-	}
-}
-
-
-/**
- * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer
- * @n: Bignum from bignum_init()
- * Returns: Length of n if written to a binary buffer
- */
-size_t bignum_get_unsigned_bin_len(struct bignum *n)
-{
-	return mp_unsigned_bin_size((mp_int *) n);
-}
-
-
-/**
- * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum
- * @n: Bignum from bignum_init()
- * @buf: Buffer for the binary number
- * @len: Length of the buffer, can be %NULL if buffer is known to be long
- * enough. Set to used buffer length on success if not %NULL.
- * Returns: 0 on success, -1 on failure
- */
-int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)
-{
-	size_t need = mp_unsigned_bin_size((mp_int *) n);
-	if (len && need > *len) {
-		*len = need;
-		return -1;
-	}
-	if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	if (len)
-		*len = need;
-	return 0;
-}
-
-
-/**
- * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
- * @n: Bignum from bignum_init(); to be set to the given value
- * @buf: Buffer with unsigned binary value
- * @len: Length of buf in octets
- * Returns: 0 on success, -1 on failure
- */
-int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)
-{
-	if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * bignum_cmp - Signed comparison
- * @a: Bignum from bignum_init()
- * @b: Bignum from bignum_init()
- * Returns: 0 on success, -1 on failure
- */
-int bignum_cmp(const struct bignum *a, const struct bignum *b)
-{
-	return mp_cmp((mp_int *) a, (mp_int *) b);
-}
-
-
-/**
- * bignum_cmd_d - Compare bignum to standard integer
- * @a: Bignum from bignum_init()
- * @b: Small integer
- * Returns: 0 on success, -1 on failure
- */
-int bignum_cmp_d(const struct bignum *a, unsigned long b)
-{
-	return mp_cmp_d((mp_int *) a, b);
-}
-
-
-/**
- * bignum_add - c = a + b
- * @a: Bignum from bignum_init()
- * @b: Bignum from bignum_init()
- * @c: Bignum from bignum_init(); used to store the result of a + b
- * Returns: 0 on success, -1 on failure
- */
-int bignum_add(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c)
-{
-	if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * bignum_sub - c = a - b
- * @a: Bignum from bignum_init()
- * @b: Bignum from bignum_init()
- * @c: Bignum from bignum_init(); used to store the result of a - b
- * Returns: 0 on success, -1 on failure
- */
-int bignum_sub(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c)
-{
-	if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * bignum_mul - c = a * b
- * @a: Bignum from bignum_init()
- * @b: Bignum from bignum_init()
- * @c: Bignum from bignum_init(); used to store the result of a * b
- * Returns: 0 on success, -1 on failure
- */
-int bignum_mul(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c)
-{
-	if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * bignum_mulmod - d = a * b (mod c)
- * @a: Bignum from bignum_init()
- * @b: Bignum from bignum_init()
- * @c: Bignum from bignum_init(); modulus
- * @d: Bignum from bignum_init(); used to store the result of a * b (mod c)
- * Returns: 0 on success, -1 on failure
- */
-int bignum_mulmod(const struct bignum *a, const struct bignum *b,
-		  const struct bignum *c, struct bignum *d)
-{
-	if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
-	    != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * bignum_exptmod - Modular exponentiation: d = a^b (mod c)
- * @a: Bignum from bignum_init(); base
- * @b: Bignum from bignum_init(); exponent
- * @c: Bignum from bignum_init(); modulus
- * @d: Bignum from bignum_init(); used to store the result of a^b (mod c)
- * Returns: 0 on success, -1 on failure
- */
-int bignum_exptmod(const struct bignum *a, const struct bignum *b,
-		   const struct bignum *c, struct bignum *d)
-{
-	if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
-	    != MP_OKAY) {
-		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
-		return -1;
-	}
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/bignum.c (from rev 9639, vendor/wpa/dist/src/tls/bignum.c)
===================================================================
--- vendor/wpa/2.0/src/tls/bignum.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/bignum.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,224 @@
+/*
+ * Big number math
+ * Copyright (c) 2006, Jouni Malinen <j at 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 "bignum.h"
+
+#ifdef CONFIG_INTERNAL_LIBTOMMATH
+#include "libtommath.c"
+#else /* CONFIG_INTERNAL_LIBTOMMATH */
+#include <tommath.h>
+#endif /* CONFIG_INTERNAL_LIBTOMMATH */
+
+
+/*
+ * The current version is just a wrapper for LibTomMath library, so
+ * struct bignum is just typecast to mp_int.
+ */
+
+/**
+ * bignum_init - Allocate memory for bignum
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct bignum * bignum_init(void)
+{
+	struct bignum *n = os_zalloc(sizeof(mp_int));
+	if (n == NULL)
+		return NULL;
+	if (mp_init((mp_int *) n) != MP_OKAY) {
+		os_free(n);
+		n = NULL;
+	}
+	return n;
+}
+
+
+/**
+ * bignum_deinit - Free bignum
+ * @n: Bignum from bignum_init()
+ */
+void bignum_deinit(struct bignum *n)
+{
+	if (n) {
+		mp_clear((mp_int *) n);
+		os_free(n);
+	}
+}
+
+
+/**
+ * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer
+ * @n: Bignum from bignum_init()
+ * Returns: Length of n if written to a binary buffer
+ */
+size_t bignum_get_unsigned_bin_len(struct bignum *n)
+{
+	return mp_unsigned_bin_size((mp_int *) n);
+}
+
+
+/**
+ * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum
+ * @n: Bignum from bignum_init()
+ * @buf: Buffer for the binary number
+ * @len: Length of the buffer, can be %NULL if buffer is known to be long
+ * enough. Set to used buffer length on success if not %NULL.
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)
+{
+	size_t need = mp_unsigned_bin_size((mp_int *) n);
+	if (len && need > *len) {
+		*len = need;
+		return -1;
+	}
+	if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	if (len)
+		*len = need;
+	return 0;
+}
+
+
+/**
+ * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
+ * @n: Bignum from bignum_init(); to be set to the given value
+ * @buf: Buffer with unsigned binary value
+ * @len: Length of buf in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)
+{
+	if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * bignum_cmp - Signed comparison
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_cmp(const struct bignum *a, const struct bignum *b)
+{
+	return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+/**
+ * bignum_cmd_d - Compare bignum to standard integer
+ * @a: Bignum from bignum_init()
+ * @b: Small integer
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_cmp_d(const struct bignum *a, unsigned long b)
+{
+	return mp_cmp_d((mp_int *) a, b);
+}
+
+
+/**
+ * bignum_add - c = a + b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_add(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c)
+{
+	if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * bignum_sub - c = a - b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a - b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_sub(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c)
+{
+	if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * bignum_mul - c = a * b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a * b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_mul(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c)
+{
+	if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * bignum_mulmod - d = a * b (mod c)
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); modulus
+ * @d: Bignum from bignum_init(); used to store the result of a * b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_mulmod(const struct bignum *a, const struct bignum *b,
+		  const struct bignum *c, struct bignum *d)
+{
+	if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
+	    != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * bignum_exptmod - Modular exponentiation: d = a^b (mod c)
+ * @a: Bignum from bignum_init(); base
+ * @b: Bignum from bignum_init(); exponent
+ * @c: Bignum from bignum_init(); modulus
+ * @d: Bignum from bignum_init(); used to store the result of a^b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_exptmod(const struct bignum *a, const struct bignum *b,
+		   const struct bignum *c, struct bignum *d)
+{
+	if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
+	    != MP_OKAY) {
+		wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+		return -1;
+	}
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/tls/bignum.h
===================================================================
--- vendor/wpa/dist/src/tls/bignum.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/bignum.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,38 +0,0 @@
-/*
- * Big number math
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BIGNUM_H
-#define BIGNUM_H
-
-struct bignum;
-
-struct bignum * bignum_init(void);
-void bignum_deinit(struct bignum *n);
-size_t bignum_get_unsigned_bin_len(struct bignum *n);
-int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len);
-int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len);
-int bignum_cmp(const struct bignum *a, const struct bignum *b);
-int bignum_cmp_d(const struct bignum *a, unsigned long b);
-int bignum_add(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c);
-int bignum_sub(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c);
-int bignum_mul(const struct bignum *a, const struct bignum *b,
-	       struct bignum *c);
-int bignum_mulmod(const struct bignum *a, const struct bignum *b,
-		  const struct bignum *c, struct bignum *d);
-int bignum_exptmod(const struct bignum *a, const struct bignum *b,
-		   const struct bignum *c, struct bignum *d);
-
-#endif /* BIGNUM_H */

Copied: vendor/wpa/2.0/src/tls/bignum.h (from rev 9639, vendor/wpa/dist/src/tls/bignum.h)
===================================================================
--- vendor/wpa/2.0/src/tls/bignum.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/bignum.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,32 @@
+/*
+ * Big number math
+ * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BIGNUM_H
+#define BIGNUM_H
+
+struct bignum;
+
+struct bignum * bignum_init(void);
+void bignum_deinit(struct bignum *n);
+size_t bignum_get_unsigned_bin_len(struct bignum *n);
+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len);
+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len);
+int bignum_cmp(const struct bignum *a, const struct bignum *b);
+int bignum_cmp_d(const struct bignum *a, unsigned long b);
+int bignum_add(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c);
+int bignum_sub(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c);
+int bignum_mul(const struct bignum *a, const struct bignum *b,
+	       struct bignum *c);
+int bignum_mulmod(const struct bignum *a, const struct bignum *b,
+		  const struct bignum *c, struct bignum *d);
+int bignum_exptmod(const struct bignum *a, const struct bignum *b,
+		   const struct bignum *c, struct bignum *d);
+
+#endif /* BIGNUM_H */

Deleted: vendor/wpa/2.0/src/tls/libtommath.c
===================================================================
--- vendor/wpa/dist/src/tls/libtommath.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/libtommath.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,3381 +0,0 @@
-/*
- * Minimal code for RSA support from LibTomMath 0.41
- * http://libtom.org/
- * http://libtom.org/files/ltm-0.41.tar.bz2
- * This library was released in public domain by Tom St Denis.
- *
- * The combination in this file may not use all of the optimized algorithms
- * from LibTomMath and may be considerable slower than the LibTomMath with its
- * default settings. The main purpose of having this version here is to make it
- * easier to build bignum.c wrapper without having to install and build an
- * external library.
- *
- * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
- * libtommath.c file instead of using the external LibTomMath library.
- */
-
-#ifndef CHAR_BIT
-#define CHAR_BIT 8
-#endif
-
-#define BN_MP_INVMOD_C
-#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
-			   * require BN_MP_EXPTMOD_FAST_C instead */
-#define BN_S_MP_MUL_DIGS_C
-#define BN_MP_INVMOD_SLOW_C
-#define BN_S_MP_SQR_C
-#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
-				 * would require other than mp_reduce */
-
-#ifdef LTM_FAST
-
-/* Use faster div at the cost of about 1 kB */
-#define BN_MP_MUL_D_C
-
-/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
-#define BN_MP_EXPTMOD_FAST_C
-#define BN_MP_MONTGOMERY_SETUP_C
-#define BN_FAST_MP_MONTGOMERY_REDUCE_C
-#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-#define BN_MP_MUL_2_C
-
-/* Include faster sqr at the cost of about 0.5 kB in code */
-#define BN_FAST_S_MP_SQR_C
-
-#else /* LTM_FAST */
-
-#define BN_MP_DIV_SMALL
-#define BN_MP_INIT_MULTI_C
-#define BN_MP_CLEAR_MULTI_C
-#define BN_MP_ABS_C
-#endif /* LTM_FAST */
-
-/* Current uses do not require support for negative exponent in exptmod, so we
- * can save about 1.5 kB in leaving out invmod. */
-#define LTM_NO_NEG_EXP
-
-/* from tommath.h */
-
-#ifndef MIN
-   #define MIN(x,y) ((x)<(y)?(x):(y))
-#endif
-
-#ifndef MAX
-   #define MAX(x,y) ((x)>(y)?(x):(y))
-#endif
-
-#define  OPT_CAST(x)
-
-typedef unsigned long mp_digit;
-typedef u64 mp_word;
-
-#define DIGIT_BIT          28
-#define MP_28BIT
-
-
-#define XMALLOC  os_malloc
-#define XFREE    os_free
-#define XREALLOC os_realloc
-
-
-#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
-
-#define MP_LT        -1   /* less than */
-#define MP_EQ         0   /* equal to */
-#define MP_GT         1   /* greater than */
-
-#define MP_ZPOS       0   /* positive integer */
-#define MP_NEG        1   /* negative */
-
-#define MP_OKAY       0   /* ok result */
-#define MP_MEM        -2  /* out of mem */
-#define MP_VAL        -3  /* invalid input */
-
-#define MP_YES        1   /* yes response */
-#define MP_NO         0   /* no response */
-
-typedef int           mp_err;
-
-/* define this to use lower memory usage routines (exptmods mostly) */
-#define MP_LOW_MEM
-
-/* default precision */
-#ifndef MP_PREC
-   #ifndef MP_LOW_MEM
-      #define MP_PREC                 32     /* default digits of precision */
-   #else
-      #define MP_PREC                 8      /* default digits of precision */
-   #endif   
-#endif
-
-/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
-#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
-
-/* the infamous mp_int structure */
-typedef struct  {
-    int used, alloc, sign;
-    mp_digit *dp;
-} mp_int;
-
-
-/* ---> Basic Manipulations <--- */
-#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
-#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
-#define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
-
-
-/* prototypes for copied functions */
-#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
-static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
-static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
-static int s_mp_sqr(mp_int * a, mp_int * b);
-static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
-
-static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
-
-#ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...);
-#endif
-#ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...);
-#endif
-static int mp_lshd(mp_int * a, int b);
-static void mp_set(mp_int * a, mp_digit b);
-static void mp_clamp(mp_int * a);
-static void mp_exch(mp_int * a, mp_int * b);
-static void mp_rshd(mp_int * a, int b);
-static void mp_zero(mp_int * a);
-static int mp_mod_2d(mp_int * a, int b, mp_int * c);
-static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
-static int mp_init_copy(mp_int * a, mp_int * b);
-static int mp_mul_2d(mp_int * a, int b, mp_int * c);
-#ifndef LTM_NO_NEG_EXP
-static int mp_div_2(mp_int * a, mp_int * b);
-static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
-static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
-#endif /* LTM_NO_NEG_EXP */
-static int mp_copy(mp_int * a, mp_int * b);
-static int mp_count_bits(mp_int * a);
-static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
-static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
-static int mp_grow(mp_int * a, int size);
-static int mp_cmp_mag(mp_int * a, mp_int * b);
-#ifdef BN_MP_ABS_C
-static int mp_abs(mp_int * a, mp_int * b);
-#endif
-static int mp_sqr(mp_int * a, mp_int * b);
-static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
-static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
-static int mp_2expt(mp_int * a, int b);
-static int mp_reduce_setup(mp_int * a, mp_int * b);
-static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
-static int mp_init_size(mp_int * a, int size);
-#ifdef BN_MP_EXPTMOD_FAST_C
-static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
-#endif /* BN_MP_EXPTMOD_FAST_C */
-#ifdef BN_FAST_S_MP_SQR_C
-static int fast_s_mp_sqr (mp_int * a, mp_int * b);
-#endif /* BN_FAST_S_MP_SQR_C */
-#ifdef BN_MP_MUL_D_C
-static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
-#endif /* BN_MP_MUL_D_C */
-
-
-
-/* functions from bn_<func name>.c */
-
-
-/* reverse an array, used for radix code */
-static void bn_reverse (unsigned char *s, int len)
-{
-  int     ix, iy;
-  unsigned char t;
-
-  ix = 0;
-  iy = len - 1;
-  while (ix < iy) {
-    t     = s[ix];
-    s[ix] = s[iy];
-    s[iy] = t;
-    ++ix;
-    --iy;
-  }
-}
-
-
-/* low level addition, based on HAC pp.594, Algorithm 14.7 */
-static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int *x;
-  int     olduse, res, min, max;
-
-  /* find sizes, we let |a| <= |b| which means we have to sort
-   * them.  "x" will point to the input with the most digits
-   */
-  if (a->used > b->used) {
-    min = b->used;
-    max = a->used;
-    x = a;
-  } else {
-    min = a->used;
-    max = b->used;
-    x = b;
-  }
-
-  /* init result */
-  if (c->alloc < max + 1) {
-    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* get old used digit count and set new one */
-  olduse = c->used;
-  c->used = max + 1;
-
-  {
-    register mp_digit u, *tmpa, *tmpb, *tmpc;
-    register int i;
-
-    /* alias for digit pointers */
-
-    /* first input */
-    tmpa = a->dp;
-
-    /* second input */
-    tmpb = b->dp;
-
-    /* destination */
-    tmpc = c->dp;
-
-    /* zero the carry */
-    u = 0;
-    for (i = 0; i < min; i++) {
-      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
-      *tmpc = *tmpa++ + *tmpb++ + u;
-
-      /* U = carry bit of T[i] */
-      u = *tmpc >> ((mp_digit)DIGIT_BIT);
-
-      /* take away carry bit from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* now copy higher words if any, that is in A+B 
-     * if A or B has more digits add those in 
-     */
-    if (min != max) {
-      for (; i < max; i++) {
-        /* T[i] = X[i] + U */
-        *tmpc = x->dp[i] + u;
-
-        /* U = carry bit of T[i] */
-        u = *tmpc >> ((mp_digit)DIGIT_BIT);
-
-        /* take away carry bit from T[i] */
-        *tmpc++ &= MP_MASK;
-      }
-    }
-
-    /* add carry */
-    *tmpc++ = u;
-
-    /* clear digits above oldused */
-    for (i = c->used; i < olduse; i++) {
-      *tmpc++ = 0;
-    }
-  }
-
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
-static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     olduse, res, min, max;
-
-  /* find sizes */
-  min = b->used;
-  max = a->used;
-
-  /* init result */
-  if (c->alloc < max) {
-    if ((res = mp_grow (c, max)) != MP_OKAY) {
-      return res;
-    }
-  }
-  olduse = c->used;
-  c->used = max;
-
-  {
-    register mp_digit u, *tmpa, *tmpb, *tmpc;
-    register int i;
-
-    /* alias for digit pointers */
-    tmpa = a->dp;
-    tmpb = b->dp;
-    tmpc = c->dp;
-
-    /* set carry to zero */
-    u = 0;
-    for (i = 0; i < min; i++) {
-      /* T[i] = A[i] - B[i] - U */
-      *tmpc = *tmpa++ - *tmpb++ - u;
-
-      /* U = carry bit of T[i]
-       * Note this saves performing an AND operation since
-       * if a carry does occur it will propagate all the way to the
-       * MSB.  As a result a single shift is enough to get the carry
-       */
-      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
-
-      /* Clear carry from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* now copy higher words if any, e.g. if A has more digits than B  */
-    for (; i < max; i++) {
-      /* T[i] = A[i] - U */
-      *tmpc = *tmpa++ - u;
-
-      /* U = carry bit of T[i] */
-      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
-
-      /* Clear carry from T[i] */
-      *tmpc++ &= MP_MASK;
-    }
-
-    /* clear digits above used (since we may not have grown result above) */
-    for (i = c->used; i < olduse; i++) {
-      *tmpc++ = 0;
-    }
-  }
-
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* init a new mp_int */
-static int mp_init (mp_int * a)
-{
-  int i;
-
-  /* allocate memory required and clear it */
-  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
-  if (a->dp == NULL) {
-    return MP_MEM;
-  }
-
-  /* set the digits to zero */
-  for (i = 0; i < MP_PREC; i++) {
-      a->dp[i] = 0;
-  }
-
-  /* set the used to zero, allocated digits to the default precision
-   * and sign to positive */
-  a->used  = 0;
-  a->alloc = MP_PREC;
-  a->sign  = MP_ZPOS;
-
-  return MP_OKAY;
-}
-
-
-/* clear one (frees)  */
-static void mp_clear (mp_int * a)
-{
-  int i;
-
-  /* only do anything if a hasn't been freed previously */
-  if (a->dp != NULL) {
-    /* first zero the digits */
-    for (i = 0; i < a->used; i++) {
-        a->dp[i] = 0;
-    }
-
-    /* free ram */
-    XFREE(a->dp);
-
-    /* reset members to make debugging easier */
-    a->dp    = NULL;
-    a->alloc = a->used = 0;
-    a->sign  = MP_ZPOS;
-  }
-}
-
-
-/* high level addition (handles signs) */
-static int mp_add (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     sa, sb, res;
-
-  /* get sign of both inputs */
-  sa = a->sign;
-  sb = b->sign;
-
-  /* handle two cases, not four */
-  if (sa == sb) {
-    /* both positive or both negative */
-    /* add their magnitudes, copy the sign */
-    c->sign = sa;
-    res = s_mp_add (a, b, c);
-  } else {
-    /* one positive, the other negative */
-    /* subtract the one with the greater magnitude from */
-    /* the one of the lesser magnitude.  The result gets */
-    /* the sign of the one with the greater magnitude. */
-    if (mp_cmp_mag (a, b) == MP_LT) {
-      c->sign = sb;
-      res = s_mp_sub (b, a, c);
-    } else {
-      c->sign = sa;
-      res = s_mp_sub (a, b, c);
-    }
-  }
-  return res;
-}
-
-
-/* high level subtraction (handles signs) */
-static int mp_sub (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     sa, sb, res;
-
-  sa = a->sign;
-  sb = b->sign;
-
-  if (sa != sb) {
-    /* subtract a negative from a positive, OR */
-    /* subtract a positive from a negative. */
-    /* In either case, ADD their magnitudes, */
-    /* and use the sign of the first number. */
-    c->sign = sa;
-    res = s_mp_add (a, b, c);
-  } else {
-    /* subtract a positive from a positive, OR */
-    /* subtract a negative from a negative. */
-    /* First, take the difference between their */
-    /* magnitudes, then... */
-    if (mp_cmp_mag (a, b) != MP_LT) {
-      /* Copy the sign from the first */
-      c->sign = sa;
-      /* The first has a larger or equal magnitude */
-      res = s_mp_sub (a, b, c);
-    } else {
-      /* The result has the *opposite* sign from */
-      /* the first number. */
-      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
-      /* The second has a larger magnitude */
-      res = s_mp_sub (b, a, c);
-    }
-  }
-  return res;
-}
-
-
-/* high level multiplication (handles sign) */
-static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
-{
-  int     res, neg;
-  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
-
-  /* use Toom-Cook? */
-#ifdef BN_MP_TOOM_MUL_C
-  if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
-    res = mp_toom_mul(a, b, c);
-  } else 
-#endif
-#ifdef BN_MP_KARATSUBA_MUL_C
-  /* use Karatsuba? */
-  if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
-    res = mp_karatsuba_mul (a, b, c);
-  } else 
-#endif
-  {
-    /* can we use the fast multiplier?
-     *
-     * The fast multiplier can be used if the output will 
-     * have less than MP_WARRAY digits and the number of 
-     * digits won't affect carry propagation
-     */
-#ifdef BN_FAST_S_MP_MUL_DIGS_C
-    int     digs = a->used + b->used + 1;
-
-    if ((digs < MP_WARRAY) &&
-        MIN(a->used, b->used) <= 
-        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-      res = fast_s_mp_mul_digs (a, b, c, digs);
-    } else 
-#endif
-#ifdef BN_S_MP_MUL_DIGS_C
-      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
-#else
-#error mp_mul could fail
-      res = MP_VAL;
-#endif
-
-  }
-  c->sign = (c->used > 0) ? neg : MP_ZPOS;
-  return res;
-}
-
-
-/* d = a * b (mod c) */
-static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-  int     res;
-  mp_int  t;
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-  res = mp_mod (&t, c, d);
-  mp_clear (&t);
-  return res;
-}
-
-
-/* c = a mod b, 0 <= c < b */
-static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int  t;
-  int     res;
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-
-  if (t.sign != b->sign) {
-    res = mp_add (b, &t, c);
-  } else {
-    res = MP_OKAY;
-    mp_exch (&t, c);
-  }
-
-  mp_clear (&t);
-  return res;
-}
-
-
-/* this is a shell function that calls either the normal or Montgomery
- * exptmod functions.  Originally the call to the montgomery code was
- * embedded in the normal function but that wasted alot of stack space
- * for nothing (since 99% of the time the Montgomery code would be called)
- */
-static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
-{
-  int dr;
-
-  /* modulus P must be positive */
-  if (P->sign == MP_NEG) {
-     return MP_VAL;
-  }
-
-  /* if exponent X is negative we have to recurse */
-  if (X->sign == MP_NEG) {
-#ifdef LTM_NO_NEG_EXP
-        return MP_VAL;
-#else /* LTM_NO_NEG_EXP */
-#ifdef BN_MP_INVMOD_C
-     mp_int tmpG, tmpX;
-     int err;
-
-     /* first compute 1/G mod P */
-     if ((err = mp_init(&tmpG)) != MP_OKAY) {
-        return err;
-     }
-     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
-        mp_clear(&tmpG);
-        return err;
-     }
-
-     /* now get |X| */
-     if ((err = mp_init(&tmpX)) != MP_OKAY) {
-        mp_clear(&tmpG);
-        return err;
-     }
-     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
-        mp_clear_multi(&tmpG, &tmpX, NULL);
-        return err;
-     }
-
-     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
-     err = mp_exptmod(&tmpG, &tmpX, P, Y);
-     mp_clear_multi(&tmpG, &tmpX, NULL);
-     return err;
-#else 
-#error mp_exptmod would always fail
-     /* no invmod */
-     return MP_VAL;
-#endif
-#endif /* LTM_NO_NEG_EXP */
-  }
-
-/* modified diminished radix reduction */
-#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
-  if (mp_reduce_is_2k_l(P) == MP_YES) {
-     return s_mp_exptmod(G, X, P, Y, 1);
-  }
-#endif
-
-#ifdef BN_MP_DR_IS_MODULUS_C
-  /* is it a DR modulus? */
-  dr = mp_dr_is_modulus(P);
-#else
-  /* default to no */
-  dr = 0;
-#endif
-
-#ifdef BN_MP_REDUCE_IS_2K_C
-  /* if not, is it a unrestricted DR modulus? */
-  if (dr == 0) {
-     dr = mp_reduce_is_2k(P) << 1;
-  }
-#endif
-    
-  /* if the modulus is odd or dr != 0 use the montgomery method */
-#ifdef BN_MP_EXPTMOD_FAST_C
-  if (mp_isodd (P) == 1 || dr !=  0) {
-    return mp_exptmod_fast (G, X, P, Y, dr);
-  } else {
-#endif
-#ifdef BN_S_MP_EXPTMOD_C
-    /* otherwise use the generic Barrett reduction technique */
-    return s_mp_exptmod (G, X, P, Y, 0);
-#else
-#error mp_exptmod could fail
-    /* no exptmod for evens */
-    return MP_VAL;
-#endif
-#ifdef BN_MP_EXPTMOD_FAST_C
-  }
-#endif
-}
-
-
-/* compare two ints (signed)*/
-static int mp_cmp (mp_int * a, mp_int * b)
-{
-  /* compare based on sign */
-  if (a->sign != b->sign) {
-     if (a->sign == MP_NEG) {
-        return MP_LT;
-     } else {
-        return MP_GT;
-     }
-  }
-  
-  /* compare digits */
-  if (a->sign == MP_NEG) {
-     /* if negative compare opposite direction */
-     return mp_cmp_mag(b, a);
-  } else {
-     return mp_cmp_mag(a, b);
-  }
-}
-
-
-/* compare a digit */
-static int mp_cmp_d(mp_int * a, mp_digit b)
-{
-  /* compare based on sign */
-  if (a->sign == MP_NEG) {
-    return MP_LT;
-  }
-
-  /* compare based on magnitude */
-  if (a->used > 1) {
-    return MP_GT;
-  }
-
-  /* compare the only digit of a to b */
-  if (a->dp[0] > b) {
-    return MP_GT;
-  } else if (a->dp[0] < b) {
-    return MP_LT;
-  } else {
-    return MP_EQ;
-  }
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* hac 14.61, pp608 */
-static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
-{
-  /* b cannot be negative */
-  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
-    return MP_VAL;
-  }
-
-#ifdef BN_FAST_MP_INVMOD_C
-  /* if the modulus is odd we can use a faster routine instead */
-  if (mp_isodd (b) == 1) {
-    return fast_mp_invmod (a, b, c);
-  }
-#endif
-
-#ifdef BN_MP_INVMOD_SLOW_C
-  return mp_invmod_slow(a, b, c);
-#endif
-
-#ifndef BN_FAST_MP_INVMOD_C
-#ifndef BN_MP_INVMOD_SLOW_C
-#error mp_invmod would always fail
-#endif
-#endif
-  return MP_VAL;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* get the size for an unsigned equivalent */
-static int mp_unsigned_bin_size (mp_int * a)
-{
-  int     size = mp_count_bits (a);
-  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* hac 14.61, pp608 */
-static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
-{
-  mp_int  x, y, u, v, A, B, C, D;
-  int     res;
-
-  /* b cannot be negative */
-  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
-    return MP_VAL;
-  }
-
-  /* init temps */
-  if ((res = mp_init_multi(&x, &y, &u, &v, 
-                           &A, &B, &C, &D, NULL)) != MP_OKAY) {
-     return res;
-  }
-
-  /* x = a, y = b */
-  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
-      goto LBL_ERR;
-  }
-  if ((res = mp_copy (b, &y)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-
-  /* 2. [modified] if x,y are both even then return an error! */
-  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
-    res = MP_VAL;
-    goto LBL_ERR;
-  }
-
-  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
-  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
-    goto LBL_ERR;
-  }
-  mp_set (&A, 1);
-  mp_set (&D, 1);
-
-top:
-  /* 4.  while u is even do */
-  while (mp_iseven (&u) == 1) {
-    /* 4.1 u = u/2 */
-    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    /* 4.2 if A or B is odd then */
-    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
-      /* A = (A+y)/2, B = (B-x)/2 */
-      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-    }
-    /* A = A/2, B = B/2 */
-    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* 5.  while v is even do */
-  while (mp_iseven (&v) == 1) {
-    /* 5.1 v = v/2 */
-    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    /* 5.2 if C or D is odd then */
-    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
-      /* C = (C+y)/2, D = (D-x)/2 */
-      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-    }
-    /* C = C/2, D = D/2 */
-    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* 6.  if u >= v then */
-  if (mp_cmp (&u, &v) != MP_LT) {
-    /* u = u - v, A = A - C, B = B - D */
-    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  } else {
-    /* v - v - u, C = C - A, D = D - B */
-    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-
-    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
-      goto LBL_ERR;
-    }
-  }
-
-  /* if not zero goto step 4 */
-  if (mp_iszero (&u) == 0)
-    goto top;
-
-  /* now a = C, b = D, gcd == g*v */
-
-  /* if v != 1 then there is no inverse */
-  if (mp_cmp_d (&v, 1) != MP_EQ) {
-    res = MP_VAL;
-    goto LBL_ERR;
-  }
-
-  /* if its too low */
-  while (mp_cmp_d(&C, 0) == MP_LT) {
-      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-  }
-  
-  /* too big */
-  while (mp_cmp_mag(&C, b) != MP_LT) {
-      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
-         goto LBL_ERR;
-      }
-  }
-  
-  /* C is now the inverse */
-  mp_exch (&C, c);
-  res = MP_OKAY;
-LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
-  return res;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* compare maginitude of two ints (unsigned) */
-static int mp_cmp_mag (mp_int * a, mp_int * b)
-{
-  int     n;
-  mp_digit *tmpa, *tmpb;
-
-  /* compare based on # of non-zero digits */
-  if (a->used > b->used) {
-    return MP_GT;
-  }
-  
-  if (a->used < b->used) {
-    return MP_LT;
-  }
-
-  /* alias for a */
-  tmpa = a->dp + (a->used - 1);
-
-  /* alias for b */
-  tmpb = b->dp + (a->used - 1);
-
-  /* compare based on digits  */
-  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
-    if (*tmpa > *tmpb) {
-      return MP_GT;
-    }
-
-    if (*tmpa < *tmpb) {
-      return MP_LT;
-    }
-  }
-  return MP_EQ;
-}
-
-
-/* reads a unsigned char array, assumes the msb is stored first [big endian] */
-static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
-{
-  int     res;
-
-  /* make sure there are at least two digits */
-  if (a->alloc < 2) {
-     if ((res = mp_grow(a, 2)) != MP_OKAY) {
-        return res;
-     }
-  }
-
-  /* zero the int */
-  mp_zero (a);
-
-  /* read the bytes in */
-  while (c-- > 0) {
-    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
-      return res;
-    }
-
-#ifndef MP_8BIT
-      a->dp[0] |= *b++;
-      a->used += 1;
-#else
-      a->dp[0] = (*b & MP_MASK);
-      a->dp[1] |= ((*b++ >> 7U) & 1);
-      a->used += 2;
-#endif
-  }
-  mp_clamp (a);
-  return MP_OKAY;
-}
-
-
-/* store in unsigned [big endian] format */
-static int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
-{
-  int     x, res;
-  mp_int  t;
-
-  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
-    return res;
-  }
-
-  x = 0;
-  while (mp_iszero (&t) == 0) {
-#ifndef MP_8BIT
-      b[x++] = (unsigned char) (t.dp[0] & 255);
-#else
-      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
-#endif
-    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
-      mp_clear (&t);
-      return res;
-    }
-  }
-  bn_reverse (b, x);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
-static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
-{
-  mp_digit D, r, rr;
-  int     x, res;
-  mp_int  t;
-
-
-  /* if the shift count is <= 0 then we do no work */
-  if (b <= 0) {
-    res = mp_copy (a, c);
-    if (d != NULL) {
-      mp_zero (d);
-    }
-    return res;
-  }
-
-  if ((res = mp_init (&t)) != MP_OKAY) {
-    return res;
-  }
-
-  /* get the remainder */
-  if (d != NULL) {
-    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
-      mp_clear (&t);
-      return res;
-    }
-  }
-
-  /* copy */
-  if ((res = mp_copy (a, c)) != MP_OKAY) {
-    mp_clear (&t);
-    return res;
-  }
-
-  /* shift by as many digits in the bit count */
-  if (b >= (int)DIGIT_BIT) {
-    mp_rshd (c, b / DIGIT_BIT);
-  }
-
-  /* shift any bit count < DIGIT_BIT */
-  D = (mp_digit) (b % DIGIT_BIT);
-  if (D != 0) {
-    register mp_digit *tmpc, mask, shift;
-
-    /* mask */
-    mask = (((mp_digit)1) << D) - 1;
-
-    /* shift for lsb */
-    shift = DIGIT_BIT - D;
-
-    /* alias */
-    tmpc = c->dp + (c->used - 1);
-
-    /* carry */
-    r = 0;
-    for (x = c->used - 1; x >= 0; x--) {
-      /* get the lower  bits of this word in a temp */
-      rr = *tmpc & mask;
-
-      /* shift the current word and mix in the carry bits from the previous word */
-      *tmpc = (*tmpc >> D) | (r << shift);
-      --tmpc;
-
-      /* set the carry to the carry bits of the current word found above */
-      r = rr;
-    }
-  }
-  mp_clamp (c);
-  if (d != NULL) {
-    mp_exch (&t, d);
-  }
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-static int mp_init_copy (mp_int * a, mp_int * b)
-{
-  int     res;
-
-  if ((res = mp_init (a)) != MP_OKAY) {
-    return res;
-  }
-  return mp_copy (b, a);
-}
-
-
-/* set to zero */
-static void mp_zero (mp_int * a)
-{
-  int       n;
-  mp_digit *tmp;
-
-  a->sign = MP_ZPOS;
-  a->used = 0;
-
-  tmp = a->dp;
-  for (n = 0; n < a->alloc; n++) {
-     *tmp++ = 0;
-  }
-}
-
-
-/* copy, b = a */
-static int mp_copy (mp_int * a, mp_int * b)
-{
-  int     res, n;
-
-  /* if dst == src do nothing */
-  if (a == b) {
-    return MP_OKAY;
-  }
-
-  /* grow dest */
-  if (b->alloc < a->used) {
-     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
-        return res;
-     }
-  }
-
-  /* zero b and copy the parameters over */
-  {
-    register mp_digit *tmpa, *tmpb;
-
-    /* pointer aliases */
-
-    /* source */
-    tmpa = a->dp;
-
-    /* destination */
-    tmpb = b->dp;
-
-    /* copy all the digits */
-    for (n = 0; n < a->used; n++) {
-      *tmpb++ = *tmpa++;
-    }
-
-    /* clear high digits */
-    for (; n < b->used; n++) {
-      *tmpb++ = 0;
-    }
-  }
-
-  /* copy used count and sign */
-  b->used = a->used;
-  b->sign = a->sign;
-  return MP_OKAY;
-}
-
-
-/* shift right a certain amount of digits */
-static void mp_rshd (mp_int * a, int b)
-{
-  int     x;
-
-  /* if b <= 0 then ignore it */
-  if (b <= 0) {
-    return;
-  }
-
-  /* if b > used then simply zero it and return */
-  if (a->used <= b) {
-    mp_zero (a);
-    return;
-  }
-
-  {
-    register mp_digit *bottom, *top;
-
-    /* shift the digits down */
-
-    /* bottom */
-    bottom = a->dp;
-
-    /* top [offset into digits] */
-    top = a->dp + b;
-
-    /* this is implemented as a sliding window where 
-     * the window is b-digits long and digits from 
-     * the top of the window are copied to the bottom
-     *
-     * e.g.
-
-     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
-                 /\                   |      ---->
-                  \-------------------/      ---->
-     */
-    for (x = 0; x < (a->used - b); x++) {
-      *bottom++ = *top++;
-    }
-
-    /* zero the top digits */
-    for (; x < a->used; x++) {
-      *bottom++ = 0;
-    }
-  }
-  
-  /* remove excess digits */
-  a->used -= b;
-}
-
-
-/* swap the elements of two integers, for cases where you can't simply swap the 
- * mp_int pointers around
- */
-static void mp_exch (mp_int * a, mp_int * b)
-{
-  mp_int  t;
-
-  t  = *a;
-  *a = *b;
-  *b = t;
-}
-
-
-/* trim unused digits 
- *
- * This is used to ensure that leading zero digits are
- * trimed and the leading "used" digit will be non-zero
- * Typically very fast.  Also fixes the sign if there
- * are no more leading digits
- */
-static void mp_clamp (mp_int * a)
-{
-  /* decrease used while the most significant digit is
-   * zero.
-   */
-  while (a->used > 0 && a->dp[a->used - 1] == 0) {
-    --(a->used);
-  }
-
-  /* reset the sign flag if used == 0 */
-  if (a->used == 0) {
-    a->sign = MP_ZPOS;
-  }
-}
-
-
-/* grow as required */
-static int mp_grow (mp_int * a, int size)
-{
-  int     i;
-  mp_digit *tmp;
-
-  /* if the alloc size is smaller alloc more ram */
-  if (a->alloc < size) {
-    /* ensure there are always at least MP_PREC digits extra on top */
-    size += (MP_PREC * 2) - (size % MP_PREC);
-
-    /* reallocate the array a->dp
-     *
-     * We store the return in a temporary variable
-     * in case the operation failed we don't want
-     * to overwrite the dp member of a.
-     */
-    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
-    if (tmp == NULL) {
-      /* reallocation failed but "a" is still valid [can be freed] */
-      return MP_MEM;
-    }
-
-    /* reallocation succeeded so set a->dp */
-    a->dp = tmp;
-
-    /* zero excess digits */
-    i        = a->alloc;
-    a->alloc = size;
-    for (; i < a->alloc; i++) {
-      a->dp[i] = 0;
-    }
-  }
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_ABS_C
-/* b = |a| 
- *
- * Simple function copies the input and fixes the sign to positive
- */
-static int mp_abs (mp_int * a, mp_int * b)
-{
-  int     res;
-
-  /* copy a to b */
-  if (a != b) {
-     if ((res = mp_copy (a, b)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  /* force the sign of b to positive */
-  b->sign = MP_ZPOS;
-
-  return MP_OKAY;
-}
-#endif
-
-
-/* set to a digit */
-static void mp_set (mp_int * a, mp_digit b)
-{
-  mp_zero (a);
-  a->dp[0] = b & MP_MASK;
-  a->used  = (a->dp[0] != 0) ? 1 : 0;
-}
-
-
-#ifndef LTM_NO_NEG_EXP
-/* b = a/2 */
-static int mp_div_2(mp_int * a, mp_int * b)
-{
-  int     x, res, oldused;
-
-  /* copy */
-  if (b->alloc < a->used) {
-    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  oldused = b->used;
-  b->used = a->used;
-  {
-    register mp_digit r, rr, *tmpa, *tmpb;
-
-    /* source alias */
-    tmpa = a->dp + b->used - 1;
-
-    /* dest alias */
-    tmpb = b->dp + b->used - 1;
-
-    /* carry */
-    r = 0;
-    for (x = b->used - 1; x >= 0; x--) {
-      /* get the carry for the next iteration */
-      rr = *tmpa & 1;
-
-      /* shift the current digit, add in carry and store */
-      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
-
-      /* forward carry to next iteration */
-      r = rr;
-    }
-
-    /* zero excess digits */
-    tmpb = b->dp + b->used;
-    for (x = b->used; x < oldused; x++) {
-      *tmpb++ = 0;
-    }
-  }
-  b->sign = a->sign;
-  mp_clamp (b);
-  return MP_OKAY;
-}
-#endif /* LTM_NO_NEG_EXP */
-
-
-/* shift left by a certain bit count */
-static int mp_mul_2d (mp_int * a, int b, mp_int * c)
-{
-  mp_digit d;
-  int      res;
-
-  /* copy */
-  if (a != c) {
-     if ((res = mp_copy (a, c)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
-     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  /* shift by as many digits in the bit count */
-  if (b >= (int)DIGIT_BIT) {
-    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* shift any bit count < DIGIT_BIT */
-  d = (mp_digit) (b % DIGIT_BIT);
-  if (d != 0) {
-    register mp_digit *tmpc, shift, mask, r, rr;
-    register int x;
-
-    /* bitmask for carries */
-    mask = (((mp_digit)1) << d) - 1;
-
-    /* shift for msbs */
-    shift = DIGIT_BIT - d;
-
-    /* alias */
-    tmpc = c->dp;
-
-    /* carry */
-    r    = 0;
-    for (x = 0; x < c->used; x++) {
-      /* get the higher bits of the current word */
-      rr = (*tmpc >> shift) & mask;
-
-      /* shift the current word and OR in the carry */
-      *tmpc = ((*tmpc << d) | r) & MP_MASK;
-      ++tmpc;
-
-      /* set the carry to the carry bits of the current word */
-      r = rr;
-    }
-    
-    /* set final carry */
-    if (r != 0) {
-       c->dp[(c->used)++] = r;
-    }
-  }
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...) 
-{
-    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
-    int n = 0;                 /* Number of ok inits */
-    mp_int* cur_arg = mp;
-    va_list args;
-
-    va_start(args, mp);        /* init args to next argument from caller */
-    while (cur_arg != NULL) {
-        if (mp_init(cur_arg) != MP_OKAY) {
-            /* Oops - error! Back-track and mp_clear what we already
-               succeeded in init-ing, then return error.
-            */
-            va_list clean_args;
-            
-            /* end the current list */
-            va_end(args);
-            
-            /* now start cleaning up */            
-            cur_arg = mp;
-            va_start(clean_args, mp);
-            while (n--) {
-                mp_clear(cur_arg);
-                cur_arg = va_arg(clean_args, mp_int*);
-            }
-            va_end(clean_args);
-            res = MP_MEM;
-            break;
-        }
-        n++;
-        cur_arg = va_arg(args, mp_int*);
-    }
-    va_end(args);
-    return res;                /* Assumed ok, if error flagged above. */
-}
-#endif
-
-
-#ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...) 
-{
-    mp_int* next_mp = mp;
-    va_list args;
-    va_start(args, mp);
-    while (next_mp != NULL) {
-        mp_clear(next_mp);
-        next_mp = va_arg(args, mp_int*);
-    }
-    va_end(args);
-}
-#endif
-
-
-/* shift left a certain amount of digits */
-static int mp_lshd (mp_int * a, int b)
-{
-  int     x, res;
-
-  /* if its less than zero return */
-  if (b <= 0) {
-    return MP_OKAY;
-  }
-
-  /* grow to fit the new digits */
-  if (a->alloc < a->used + b) {
-     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
-       return res;
-     }
-  }
-
-  {
-    register mp_digit *top, *bottom;
-
-    /* increment the used by the shift amount then copy upwards */
-    a->used += b;
-
-    /* top */
-    top = a->dp + a->used - 1;
-
-    /* base */
-    bottom = a->dp + a->used - 1 - b;
-
-    /* much like mp_rshd this is implemented using a sliding window
-     * except the window goes the otherway around.  Copying from
-     * the bottom to the top.  see bn_mp_rshd.c for more info.
-     */
-    for (x = a->used - 1; x >= b; x--) {
-      *top-- = *bottom--;
-    }
-
-    /* zero the lower digits */
-    top = a->dp;
-    for (x = 0; x < b; x++) {
-      *top++ = 0;
-    }
-  }
-  return MP_OKAY;
-}
-
-
-/* returns the number of bits in an int */
-static int mp_count_bits (mp_int * a)
-{
-  int     r;
-  mp_digit q;
-
-  /* shortcut */
-  if (a->used == 0) {
-    return 0;
-  }
-
-  /* get number of digits and add that */
-  r = (a->used - 1) * DIGIT_BIT;
-  
-  /* take the last digit and count the bits in it */
-  q = a->dp[a->used - 1];
-  while (q > ((mp_digit) 0)) {
-    ++r;
-    q >>= ((mp_digit) 1);
-  }
-  return r;
-}
-
-
-/* calc a value mod 2**b */
-static int mp_mod_2d (mp_int * a, int b, mp_int * c)
-{
-  int     x, res;
-
-  /* if b is <= 0 then zero the int */
-  if (b <= 0) {
-    mp_zero (c);
-    return MP_OKAY;
-  }
-
-  /* if the modulus is larger than the value than return */
-  if (b >= (int) (a->used * DIGIT_BIT)) {
-    res = mp_copy (a, c);
-    return res;
-  }
-
-  /* copy */
-  if ((res = mp_copy (a, c)) != MP_OKAY) {
-    return res;
-  }
-
-  /* zero digits above the last digit of the modulus */
-  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
-    c->dp[x] = 0;
-  }
-  /* clear the digit that is not completely outside/inside the modulus */
-  c->dp[b / DIGIT_BIT] &=
-    (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_DIV_SMALL
-
-/* slower bit-bang division... also smaller */
-static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-   mp_int ta, tb, tq, q;
-   int    res, n, n2;
-
-  /* is divisor zero ? */
-  if (mp_iszero (b) == 1) {
-    return MP_VAL;
-  }
-
-  /* if a < b then q=0, r = a */
-  if (mp_cmp_mag (a, b) == MP_LT) {
-    if (d != NULL) {
-      res = mp_copy (a, d);
-    } else {
-      res = MP_OKAY;
-    }
-    if (c != NULL) {
-      mp_zero (c);
-    }
-    return res;
-  }
-	
-  /* init our temps */
-  if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
-     return res;
-  }
-
-
-  mp_set(&tq, 1);
-  n = mp_count_bits(a) - mp_count_bits(b);
-  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
-      ((res = mp_abs(b, &tb)) != MP_OKAY) || 
-      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
-      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
-      goto LBL_ERR;
-  }
-
-  while (n-- >= 0) {
-     if (mp_cmp(&tb, &ta) != MP_GT) {
-        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
-            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
-           goto LBL_ERR;
-        }
-     }
-     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
-         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
-           goto LBL_ERR;
-     }
-  }
-
-  /* now q == quotient and ta == remainder */
-  n  = a->sign;
-  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
-  if (c != NULL) {
-     mp_exch(c, &q);
-     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
-  }
-  if (d != NULL) {
-     mp_exch(d, &ta);
-     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
-  }
-LBL_ERR:
-   mp_clear_multi(&ta, &tb, &tq, &q, NULL);
-   return res;
-}
-
-#else
-
-/* integer signed division. 
- * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
- * HAC pp.598 Algorithm 14.20
- *
- * Note that the description in HAC is horribly 
- * incomplete.  For example, it doesn't consider 
- * the case where digits are removed from 'x' in 
- * the inner loop.  It also doesn't consider the 
- * case that y has fewer than three digits, etc..
- *
- * The overall algorithm is as described as 
- * 14.20 from HAC but fixed to treat these cases.
-*/
-static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
-{
-  mp_int  q, x, y, t1, t2;
-  int     res, n, t, i, norm, neg;
-
-  /* is divisor zero ? */
-  if (mp_iszero (b) == 1) {
-    return MP_VAL;
-  }
-
-  /* if a < b then q=0, r = a */
-  if (mp_cmp_mag (a, b) == MP_LT) {
-    if (d != NULL) {
-      res = mp_copy (a, d);
-    } else {
-      res = MP_OKAY;
-    }
-    if (c != NULL) {
-      mp_zero (c);
-    }
-    return res;
-  }
-
-  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
-    return res;
-  }
-  q.used = a->used + 2;
-
-  if ((res = mp_init (&t1)) != MP_OKAY) {
-    goto LBL_Q;
-  }
-
-  if ((res = mp_init (&t2)) != MP_OKAY) {
-    goto LBL_T1;
-  }
-
-  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
-    goto LBL_T2;
-  }
-
-  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
-    goto LBL_X;
-  }
-
-  /* fix the sign */
-  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
-  x.sign = y.sign = MP_ZPOS;
-
-  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
-  norm = mp_count_bits(&y) % DIGIT_BIT;
-  if (norm < (int)(DIGIT_BIT-1)) {
-     norm = (DIGIT_BIT-1) - norm;
-     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
-       goto LBL_Y;
-     }
-     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
-       goto LBL_Y;
-     }
-  } else {
-     norm = 0;
-  }
-
-  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
-  n = x.used - 1;
-  t = y.used - 1;
-
-  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
-  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
-    goto LBL_Y;
-  }
-
-  while (mp_cmp (&x, &y) != MP_LT) {
-    ++(q.dp[n - t]);
-    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-  }
-
-  /* reset y by shifting it back down */
-  mp_rshd (&y, n - t);
-
-  /* step 3. for i from n down to (t + 1) */
-  for (i = n; i >= (t + 1); i--) {
-    if (i > x.used) {
-      continue;
-    }
-
-    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
-     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
-    if (x.dp[i] == y.dp[t]) {
-      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
-    } else {
-      mp_word tmp;
-      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
-      tmp |= ((mp_word) x.dp[i - 1]);
-      tmp /= ((mp_word) y.dp[t]);
-      if (tmp > (mp_word) MP_MASK)
-        tmp = MP_MASK;
-      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
-    }
-
-    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
-             xi * b**2 + xi-1 * b + xi-2 
-     
-       do q{i-t-1} -= 1; 
-    */
-    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
-    do {
-      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
-
-      /* find left hand */
-      mp_zero (&t1);
-      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
-      t1.dp[1] = y.dp[t];
-      t1.used = 2;
-      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-
-      /* find right hand */
-      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
-      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
-      t2.dp[2] = x.dp[i];
-      t2.used = 3;
-    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
-
-    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
-    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
-      goto LBL_Y;
-    }
-
-    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
-    if (x.sign == MP_NEG) {
-      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
-        goto LBL_Y;
-      }
-
-      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
-    }
-  }
-
-  /* now q is the quotient and x is the remainder 
-   * [which we have to normalize] 
-   */
-  
-  /* get sign before writing to c */
-  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
-
-  if (c != NULL) {
-    mp_clamp (&q);
-    mp_exch (&q, c);
-    c->sign = neg;
-  }
-
-  if (d != NULL) {
-    mp_div_2d (&x, norm, &x, NULL);
-    mp_exch (&x, d);
-  }
-
-  res = MP_OKAY;
-
-LBL_Y:mp_clear (&y);
-LBL_X:mp_clear (&x);
-LBL_T2:mp_clear (&t2);
-LBL_T1:mp_clear (&t1);
-LBL_Q:mp_clear (&q);
-  return res;
-}
-
-#endif
-
-
-#ifdef MP_LOW_MEM
-   #define TAB_SIZE 32
-#else
-   #define TAB_SIZE 256
-#endif
-
-static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
-{
-  mp_int  M[TAB_SIZE], res, mu;
-  mp_digit buf;
-  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
-  int (*redux)(mp_int*,mp_int*,mp_int*);
-
-  /* find window size */
-  x = mp_count_bits (X);
-  if (x <= 7) {
-    winsize = 2;
-  } else if (x <= 36) {
-    winsize = 3;
-  } else if (x <= 140) {
-    winsize = 4;
-  } else if (x <= 450) {
-    winsize = 5;
-  } else if (x <= 1303) {
-    winsize = 6;
-  } else if (x <= 3529) {
-    winsize = 7;
-  } else {
-    winsize = 8;
-  }
-
-#ifdef MP_LOW_MEM
-    if (winsize > 5) {
-       winsize = 5;
-    }
-#endif
-
-  /* init M array */
-  /* init first cell */
-  if ((err = mp_init(&M[1])) != MP_OKAY) {
-     return err; 
-  }
-
-  /* now init the second half of the array */
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    if ((err = mp_init(&M[x])) != MP_OKAY) {
-      for (y = 1<<(winsize-1); y < x; y++) {
-        mp_clear (&M[y]);
-      }
-      mp_clear(&M[1]);
-      return err;
-    }
-  }
-
-  /* create mu, used for Barrett reduction */
-  if ((err = mp_init (&mu)) != MP_OKAY) {
-    goto LBL_M;
-  }
-  
-  if (redmode == 0) {
-     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
-        goto LBL_MU;
-     }
-     redux = mp_reduce;
-  } else {
-     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
-        goto LBL_MU;
-     }
-     redux = mp_reduce_2k_l;
-  }    
-
-  /* create M table
-   *
-   * The M table contains powers of the base, 
-   * e.g. M[x] = G**x mod P
-   *
-   * The first half of the table is not 
-   * computed though accept for M[0] and M[1]
-   */
-  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
-    goto LBL_MU;
-  }
-
-  /* compute the value at M[1<<(winsize-1)] by squaring 
-   * M[1] (winsize-1) times 
-   */
-  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
-    goto LBL_MU;
-  }
-
-  for (x = 0; x < (winsize - 1); x++) {
-    /* square it */
-    if ((err = mp_sqr (&M[1 << (winsize - 1)], 
-                       &M[1 << (winsize - 1)])) != MP_OKAY) {
-      goto LBL_MU;
-    }
-
-    /* reduce modulo P */
-    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
-      goto LBL_MU;
-    }
-  }
-
-  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
-   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
-   */
-  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
-    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
-      goto LBL_MU;
-    }
-    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
-      goto LBL_MU;
-    }
-  }
-
-  /* setup result */
-  if ((err = mp_init (&res)) != MP_OKAY) {
-    goto LBL_MU;
-  }
-  mp_set (&res, 1);
-
-  /* set initial mode and bit cnt */
-  mode   = 0;
-  bitcnt = 1;
-  buf    = 0;
-  digidx = X->used - 1;
-  bitcpy = 0;
-  bitbuf = 0;
-
-  for (;;) {
-    /* grab next digit as required */
-    if (--bitcnt == 0) {
-      /* if digidx == -1 we are out of digits */
-      if (digidx == -1) {
-        break;
-      }
-      /* read next digit and reset the bitcnt */
-      buf    = X->dp[digidx--];
-      bitcnt = (int) DIGIT_BIT;
-    }
-
-    /* grab the next msb from the exponent */
-    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
-    buf <<= (mp_digit)1;
-
-    /* if the bit is zero and mode == 0 then we ignore it
-     * These represent the leading zero bits before the first 1 bit
-     * in the exponent.  Technically this opt is not required but it
-     * does lower the # of trivial squaring/reductions used
-     */
-    if (mode == 0 && y == 0) {
-      continue;
-    }
-
-    /* if the bit is zero and mode == 1 then we square */
-    if (mode == 1 && y == 0) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      continue;
-    }
-
-    /* else we add it to the window */
-    bitbuf |= (y << (winsize - ++bitcpy));
-    mode    = 2;
-
-    if (bitcpy == winsize) {
-      /* ok window is filled so square as required and multiply  */
-      /* square first */
-      for (x = 0; x < winsize; x++) {
-        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-
-      /* then multiply */
-      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* empty window and reset */
-      bitcpy = 0;
-      bitbuf = 0;
-      mode   = 1;
-    }
-  }
-
-  /* if bits remain then square/multiply */
-  if (mode == 2 && bitcpy > 0) {
-    /* square then multiply if the bit is set */
-    for (x = 0; x < bitcpy; x++) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      bitbuf <<= 1;
-      if ((bitbuf & (1 << winsize)) != 0) {
-        /* then multiply */
-        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-    }
-  }
-
-  mp_exch (&res, Y);
-  err = MP_OKAY;
-LBL_RES:mp_clear (&res);
-LBL_MU:mp_clear (&mu);
-LBL_M:
-  mp_clear(&M[1]);
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    mp_clear (&M[x]);
-  }
-  return err;
-}
-
-
-/* computes b = a*a */
-static int mp_sqr (mp_int * a, mp_int * b)
-{
-  int     res;
-
-#ifdef BN_MP_TOOM_SQR_C
-  /* use Toom-Cook? */
-  if (a->used >= TOOM_SQR_CUTOFF) {
-    res = mp_toom_sqr(a, b);
-  /* Karatsuba? */
-  } else 
-#endif
-#ifdef BN_MP_KARATSUBA_SQR_C
-if (a->used >= KARATSUBA_SQR_CUTOFF) {
-    res = mp_karatsuba_sqr (a, b);
-  } else 
-#endif
-  {
-#ifdef BN_FAST_S_MP_SQR_C
-    /* can we use the fast comba multiplier? */
-    if ((a->used * 2 + 1) < MP_WARRAY && 
-         a->used < 
-         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
-      res = fast_s_mp_sqr (a, b);
-    } else
-#endif
-#ifdef BN_S_MP_SQR_C
-      res = s_mp_sqr (a, b);
-#else
-#error mp_sqr could fail
-      res = MP_VAL;
-#endif
-  }
-  b->sign = MP_ZPOS;
-  return res;
-}
-
-
-/* reduces a modulo n where n is of the form 2**p - d 
-   This differs from reduce_2k since "d" can be larger
-   than a single digit.
-*/
-static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
-{
-   mp_int q;
-   int    p, res;
-   
-   if ((res = mp_init(&q)) != MP_OKAY) {
-      return res;
-   }
-   
-   p = mp_count_bits(n);    
-top:
-   /* q = a/2**p, a = a mod 2**p */
-   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
-      goto ERR;
-   }
-   
-   /* q = q * d */
-   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { 
-      goto ERR;
-   }
-   
-   /* a = a + q */
-   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
-      goto ERR;
-   }
-   
-   if (mp_cmp_mag(a, n) != MP_LT) {
-      s_mp_sub(a, n, a);
-      goto top;
-   }
-   
-ERR:
-   mp_clear(&q);
-   return res;
-}
-
-
-/* determines the setup value */
-static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
-{
-   int    res;
-   mp_int tmp;
-   
-   if ((res = mp_init(&tmp)) != MP_OKAY) {
-      return res;
-   }
-   
-   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
-      goto ERR;
-   }
-   
-   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
-      goto ERR;
-   }
-   
-ERR:
-   mp_clear(&tmp);
-   return res;
-}
-
-
-/* computes a = 2**b 
- *
- * Simple algorithm which zeroes the int, grows it then just sets one bit
- * as required.
- */
-static int mp_2expt (mp_int * a, int b)
-{
-  int     res;
-
-  /* zero a as per default */
-  mp_zero (a);
-
-  /* grow a to accomodate the single bit */
-  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
-    return res;
-  }
-
-  /* set the used count of where the bit will go */
-  a->used = b / DIGIT_BIT + 1;
-
-  /* put the single bit in its place */
-  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
-
-  return MP_OKAY;
-}
-
-
-/* pre-calculate the value required for Barrett reduction
- * For a given modulus "b" it calulates the value required in "a"
- */
-static int mp_reduce_setup (mp_int * a, mp_int * b)
-{
-  int     res;
-  
-  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
-    return res;
-  }
-  return mp_div (a, b, a, NULL);
-}
-
-
-/* reduces x mod m, assumes 0 < x < m**2, mu is 
- * precomputed via mp_reduce_setup.
- * From HAC pp.604 Algorithm 14.42
- */
-static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
-{
-  mp_int  q;
-  int     res, um = m->used;
-
-  /* q = x */
-  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
-    return res;
-  }
-
-  /* q1 = x / b**(k-1)  */
-  mp_rshd (&q, um - 1);         
-
-  /* according to HAC this optimization is ok */
-  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
-    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  } else {
-#ifdef BN_S_MP_MUL_HIGH_DIGS_C
-    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
-    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-#else 
-    { 
-#error mp_reduce would always fail
-      res = MP_VAL;
-      goto CLEANUP;
-    }
-#endif
-  }
-
-  /* q3 = q2 / b**(k+1) */
-  mp_rshd (&q, um + 1);         
-
-  /* x = x mod b**(k+1), quick (no division) */
-  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* q = q * m mod b**(k+1), quick (no division) */
-  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* x = x - q */
-  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
-    goto CLEANUP;
-  }
-
-  /* If x < 0, add b**(k+1) to it */
-  if (mp_cmp_d (x, 0) == MP_LT) {
-    mp_set (&q, 1);
-    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-    if ((res = mp_add (x, &q, x)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  }
-
-  /* Back off if it's too big */
-  while (mp_cmp (x, m) != MP_LT) {
-    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
-      goto CLEANUP;
-    }
-  }
-  
-CLEANUP:
-  mp_clear (&q);
-
-  return res;
-}
-
-
-/* multiplies |a| * |b| and only computes upto digs digits of result
- * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
- * many digits of output are created.
- */
-static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  mp_int  t;
-  int     res, pa, pb, ix, iy;
-  mp_digit u;
-  mp_word r;
-  mp_digit tmpx, *tmpt, *tmpy;
-
-  /* can we use the fast multiplier? */
-  if (((digs) < MP_WARRAY) &&
-      MIN (a->used, b->used) < 
-          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-    return fast_s_mp_mul_digs (a, b, c, digs);
-  }
-
-  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
-    return res;
-  }
-  t.used = digs;
-
-  /* compute the digits of the product directly */
-  pa = a->used;
-  for (ix = 0; ix < pa; ix++) {
-    /* set the carry to zero */
-    u = 0;
-
-    /* limit ourselves to making digs digits of output */
-    pb = MIN (b->used, digs - ix);
-
-    /* setup some aliases */
-    /* copy of the digit from a used within the nested loop */
-    tmpx = a->dp[ix];
-    
-    /* an alias for the destination shifted ix places */
-    tmpt = t.dp + ix;
-    
-    /* an alias for the digits of b */
-    tmpy = b->dp;
-
-    /* compute the columns of the output and propagate the carry */
-    for (iy = 0; iy < pb; iy++) {
-      /* compute the column as a mp_word */
-      r       = ((mp_word)*tmpt) +
-                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
-                ((mp_word) u);
-
-      /* the new column is the lower part of the result */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* get the carry word from the result */
-      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-    }
-    /* set carry if it is placed below digs */
-    if (ix + iy < digs) {
-      *tmpt = u;
-    }
-  }
-
-  mp_clamp (&t);
-  mp_exch (&t, c);
-
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* Fast (comba) multiplier
- *
- * This is the fast column-array [comba] multiplier.  It is 
- * designed to compute the columns of the product first 
- * then handle the carries afterwards.  This has the effect 
- * of making the nested loops that compute the columns very
- * simple and schedulable on super-scalar processors.
- *
- * This has been modified to produce a variable number of 
- * digits of output so if say only a half-product is required 
- * you don't have to compute the upper half (a feature 
- * required for fast Barrett reduction).
- *
- * Based on Algorithm 14.12 on pp.595 of HAC.
- *
- */
-static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  int     olduse, res, pa, ix, iz;
-  mp_digit W[MP_WARRAY];
-  register mp_word  _W;
-
-  /* grow the destination as required */
-  if (c->alloc < digs) {
-    if ((res = mp_grow (c, digs)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* number of output digits to produce */
-  pa = MIN(digs, a->used + b->used);
-
-  /* clear the carry */
-  _W = 0;
-  for (ix = 0; ix < pa; ix++) { 
-      int      tx, ty;
-      int      iy;
-      mp_digit *tmpx, *tmpy;
-
-      /* get offsets into the two bignums */
-      ty = MIN(b->used-1, ix);
-      tx = ix - ty;
-
-      /* setup temp aliases */
-      tmpx = a->dp + tx;
-      tmpy = b->dp + ty;
-
-      /* this is the number of times the loop will iterrate, essentially 
-         while (tx++ < a->used && ty-- >= 0) { ... }
-       */
-      iy = MIN(a->used-tx, ty+1);
-
-      /* execute loop */
-      for (iz = 0; iz < iy; ++iz) {
-         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
-
-      }
-
-      /* store term */
-      W[ix] = ((mp_digit)_W) & MP_MASK;
-
-      /* make next carry */
-      _W = _W >> ((mp_word)DIGIT_BIT);
- }
-
-  /* setup dest */
-  olduse  = c->used;
-  c->used = pa;
-
-  {
-    register mp_digit *tmpc;
-    tmpc = c->dp;
-    for (ix = 0; ix < pa+1; ix++) {
-      /* now extract the previous digit [below the carry] */
-      *tmpc++ = W[ix];
-    }
-
-    /* clear unused digits [that existed in the old copy of c] */
-    for (; ix < olduse; ix++) {
-      *tmpc++ = 0;
-    }
-  }
-  mp_clamp (c);
-  return MP_OKAY;
-}
-
-
-/* init an mp_init for a given size */
-static int mp_init_size (mp_int * a, int size)
-{
-  int x;
-
-  /* pad size so there are always extra digits */
-  size += (MP_PREC * 2) - (size % MP_PREC);	
-  
-  /* alloc mem */
-  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
-  if (a->dp == NULL) {
-    return MP_MEM;
-  }
-
-  /* set the members */
-  a->used  = 0;
-  a->alloc = size;
-  a->sign  = MP_ZPOS;
-
-  /* zero the digits */
-  for (x = 0; x < size; x++) {
-      a->dp[x] = 0;
-  }
-
-  return MP_OKAY;
-}
-
-
-/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
-static int s_mp_sqr (mp_int * a, mp_int * b)
-{
-  mp_int  t;
-  int     res, ix, iy, pa;
-  mp_word r;
-  mp_digit u, tmpx, *tmpt;
-
-  pa = a->used;
-  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
-    return res;
-  }
-
-  /* default used is maximum possible size */
-  t.used = 2*pa + 1;
-
-  for (ix = 0; ix < pa; ix++) {
-    /* first calculate the digit at 2*ix */
-    /* calculate double precision result */
-    r = ((mp_word) t.dp[2*ix]) +
-        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
-
-    /* store lower part in result */
-    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
-
-    /* get the carry */
-    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-
-    /* left hand side of A[ix] * A[iy] */
-    tmpx        = a->dp[ix];
-
-    /* alias for where to store the results */
-    tmpt        = t.dp + (2*ix + 1);
-    
-    for (iy = ix + 1; iy < pa; iy++) {
-      /* first calculate the product */
-      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
-
-      /* now calculate the double precision result, note we use
-       * addition instead of *2 since it's easier to optimize
-       */
-      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
-
-      /* store lower part */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* get carry */
-      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-    }
-    /* propagate upwards */
-    while (u != ((mp_digit) 0)) {
-      r       = ((mp_word) *tmpt) + ((mp_word) u);
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
-    }
-  }
-
-  mp_clamp (&t);
-  mp_exch (&t, b);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-/* multiplies |a| * |b| and does not compute the lower digs digits
- * [meant to get the higher part of the product]
- */
-static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
-{
-  mp_int  t;
-  int     res, pa, pb, ix, iy;
-  mp_digit u;
-  mp_word r;
-  mp_digit tmpx, *tmpt, *tmpy;
-
-  /* can we use the fast multiplier? */
-#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
-  if (((a->used + b->used + 1) < MP_WARRAY)
-      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-    return fast_s_mp_mul_high_digs (a, b, c, digs);
-  }
-#endif
-
-  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
-    return res;
-  }
-  t.used = a->used + b->used + 1;
-
-  pa = a->used;
-  pb = b->used;
-  for (ix = 0; ix < pa; ix++) {
-    /* clear the carry */
-    u = 0;
-
-    /* left hand side of A[ix] * B[iy] */
-    tmpx = a->dp[ix];
-
-    /* alias to the address of where the digits will be stored */
-    tmpt = &(t.dp[digs]);
-
-    /* alias for where to read the right hand side from */
-    tmpy = b->dp + (digs - ix);
-
-    for (iy = digs - ix; iy < pb; iy++) {
-      /* calculate the double precision result */
-      r       = ((mp_word)*tmpt) +
-                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
-                ((mp_word) u);
-
-      /* get the lower part */
-      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-      /* carry the carry */
-      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-    }
-    *tmpt = u;
-  }
-  mp_clamp (&t);
-  mp_exch (&t, c);
-  mp_clear (&t);
-  return MP_OKAY;
-}
-
-
-#ifdef BN_MP_MONTGOMERY_SETUP_C
-/* setups the montgomery reduction stuff */
-static int
-mp_montgomery_setup (mp_int * n, mp_digit * rho)
-{
-  mp_digit x, b;
-
-/* fast inversion mod 2**k
- *
- * Based on the fact that
- *
- * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
- *                    =>  2*X*A - X*X*A*A = 1
- *                    =>  2*(1) - (1)     = 1
- */
-  b = n->dp[0];
-
-  if ((b & 1) == 0) {
-    return MP_VAL;
-  }
-
-  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
-  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
-#if !defined(MP_8BIT)
-  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
-#endif
-#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
-  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
-#endif
-#ifdef MP_64BIT
-  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
-#endif
-
-  /* rho = -1/m mod b */
-  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
-
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
-/* computes xR**-1 == x (mod N) via Montgomery Reduction
- *
- * This is an optimized implementation of montgomery_reduce
- * which uses the comba method to quickly calculate the columns of the
- * reduction.
- *
- * Based on Algorithm 14.32 on pp.601 of HAC.
-*/
-int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
-{
-  int     ix, res, olduse;
-  mp_word W[MP_WARRAY];
-
-  /* get old used count */
-  olduse = x->used;
-
-  /* grow a as required */
-  if (x->alloc < n->used + 1) {
-    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* first we have to get the digits of the input into
-   * an array of double precision words W[...]
-   */
-  {
-    register mp_word *_W;
-    register mp_digit *tmpx;
-
-    /* alias for the W[] array */
-    _W   = W;
-
-    /* alias for the digits of  x*/
-    tmpx = x->dp;
-
-    /* copy the digits of a into W[0..a->used-1] */
-    for (ix = 0; ix < x->used; ix++) {
-      *_W++ = *tmpx++;
-    }
-
-    /* zero the high words of W[a->used..m->used*2] */
-    for (; ix < n->used * 2 + 1; ix++) {
-      *_W++ = 0;
-    }
-  }
-
-  /* now we proceed to zero successive digits
-   * from the least significant upwards
-   */
-  for (ix = 0; ix < n->used; ix++) {
-    /* mu = ai * m' mod b
-     *
-     * We avoid a double precision multiplication (which isn't required)
-     * by casting the value down to a mp_digit.  Note this requires
-     * that W[ix-1] have  the carry cleared (see after the inner loop)
-     */
-    register mp_digit mu;
-    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
-
-    /* a = a + mu * m * b**i
-     *
-     * This is computed in place and on the fly.  The multiplication
-     * by b**i is handled by offseting which columns the results
-     * are added to.
-     *
-     * Note the comba method normally doesn't handle carries in the
-     * inner loop In this case we fix the carry from the previous
-     * column since the Montgomery reduction requires digits of the
-     * result (so far) [see above] to work.  This is
-     * handled by fixing up one carry after the inner loop.  The
-     * carry fixups are done in order so after these loops the
-     * first m->used words of W[] have the carries fixed
-     */
-    {
-      register int iy;
-      register mp_digit *tmpn;
-      register mp_word *_W;
-
-      /* alias for the digits of the modulus */
-      tmpn = n->dp;
-
-      /* Alias for the columns set by an offset of ix */
-      _W = W + ix;
-
-      /* inner loop */
-      for (iy = 0; iy < n->used; iy++) {
-          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
-      }
-    }
-
-    /* now fix carry for next digit, W[ix+1] */
-    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
-  }
-
-  /* now we have to propagate the carries and
-   * shift the words downward [all those least
-   * significant digits we zeroed].
-   */
-  {
-    register mp_digit *tmpx;
-    register mp_word *_W, *_W1;
-
-    /* nox fix rest of carries */
-
-    /* alias for current word */
-    _W1 = W + ix;
-
-    /* alias for next word, where the carry goes */
-    _W = W + ++ix;
-
-    for (; ix <= n->used * 2 + 1; ix++) {
-      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
-    }
-
-    /* copy out, A = A/b**n
-     *
-     * The result is A/b**n but instead of converting from an
-     * array of mp_word to mp_digit than calling mp_rshd
-     * we just copy them in the right order
-     */
-
-    /* alias for destination word */
-    tmpx = x->dp;
-
-    /* alias for shifted double precision result */
-    _W = W + n->used;
-
-    for (ix = 0; ix < n->used + 1; ix++) {
-      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
-    }
-
-    /* zero oldused digits, if the input a was larger than
-     * m->used+1 we'll have to clear the digits
-     */
-    for (; ix < olduse; ix++) {
-      *tmpx++ = 0;
-    }
-  }
-
-  /* set the max used and clamp */
-  x->used = n->used + 1;
-  mp_clamp (x);
-
-  /* if A >= m then A = A - m */
-  if (mp_cmp_mag (x, n) != MP_LT) {
-    return s_mp_sub (x, n, x);
-  }
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MUL_2_C
-/* b = a*2 */
-static int mp_mul_2(mp_int * a, mp_int * b)
-{
-  int     x, res, oldused;
-
-  /* grow to accomodate result */
-  if (b->alloc < a->used + 1) {
-    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  oldused = b->used;
-  b->used = a->used;
-
-  {
-    register mp_digit r, rr, *tmpa, *tmpb;
-
-    /* alias for source */
-    tmpa = a->dp;
-    
-    /* alias for dest */
-    tmpb = b->dp;
-
-    /* carry */
-    r = 0;
-    for (x = 0; x < a->used; x++) {
-    
-      /* get what will be the *next* carry bit from the 
-       * MSB of the current digit 
-       */
-      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
-      
-      /* now shift up this digit, add in the carry [from the previous] */
-      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
-      
-      /* copy the carry that would be from the source 
-       * digit into the next iteration 
-       */
-      r = rr;
-    }
-
-    /* new leading digit? */
-    if (r != 0) {
-      /* add a MSB which is always 1 at this point */
-      *tmpb = 1;
-      ++(b->used);
-    }
-
-    /* now zero any excess digits on the destination 
-     * that we didn't write to 
-     */
-    tmpb = b->dp + b->used;
-    for (x = b->used; x < oldused; x++) {
-      *tmpb++ = 0;
-    }
-  }
-  b->sign = a->sign;
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-/*
- * shifts with subtractions when the result is greater than b.
- *
- * The method is slightly modified to shift B unconditionally upto just under
- * the leading bit of b.  This saves alot of multiple precision shifting.
- */
-static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
-{
-  int     x, bits, res;
-
-  /* how many bits of last digit does b use */
-  bits = mp_count_bits (b) % DIGIT_BIT;
-
-  if (b->used > 1) {
-     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
-        return res;
-     }
-  } else {
-     mp_set(a, 1);
-     bits = 1;
-  }
-
-
-  /* now compute C = A * B mod b */
-  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
-    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
-      return res;
-    }
-    if (mp_cmp_mag (a, b) != MP_LT) {
-      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
-        return res;
-      }
-    }
-  }
-
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_EXPTMOD_FAST_C
-/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
- *
- * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
- * The value of k changes based on the size of the exponent.
- *
- * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
- */
-
-static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
-{
-  mp_int  M[TAB_SIZE], res;
-  mp_digit buf, mp;
-  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
-
-  /* use a pointer to the reduction algorithm.  This allows us to use
-   * one of many reduction algorithms without modding the guts of
-   * the code with if statements everywhere.
-   */
-  int     (*redux)(mp_int*,mp_int*,mp_digit);
-
-  /* find window size */
-  x = mp_count_bits (X);
-  if (x <= 7) {
-    winsize = 2;
-  } else if (x <= 36) {
-    winsize = 3;
-  } else if (x <= 140) {
-    winsize = 4;
-  } else if (x <= 450) {
-    winsize = 5;
-  } else if (x <= 1303) {
-    winsize = 6;
-  } else if (x <= 3529) {
-    winsize = 7;
-  } else {
-    winsize = 8;
-  }
-
-#ifdef MP_LOW_MEM
-  if (winsize > 5) {
-     winsize = 5;
-  }
-#endif
-
-  /* init M array */
-  /* init first cell */
-  if ((err = mp_init(&M[1])) != MP_OKAY) {
-     return err;
-  }
-
-  /* now init the second half of the array */
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    if ((err = mp_init(&M[x])) != MP_OKAY) {
-      for (y = 1<<(winsize-1); y < x; y++) {
-        mp_clear (&M[y]);
-      }
-      mp_clear(&M[1]);
-      return err;
-    }
-  }
-
-  /* determine and setup reduction code */
-  if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_SETUP_C     
-     /* now setup montgomery  */
-     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
-        goto LBL_M;
-     }
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-
-     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
-#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
-     if (((P->used * 2 + 1) < MP_WARRAY) &&
-          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
-        redux = fast_mp_montgomery_reduce;
-     } else 
-#endif
-     {
-#ifdef BN_MP_MONTGOMERY_REDUCE_C
-        /* use slower baseline Montgomery method */
-        redux = mp_montgomery_reduce;
-#else
-        err = MP_VAL;
-        goto LBL_M;
-#endif
-     }
-  } else if (redmode == 1) {
-#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
-     /* setup DR reduction for moduli of the form B**k - b */
-     mp_dr_setup(P, &mp);
-     redux = mp_dr_reduce;
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-  } else {
-#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
-     /* setup DR reduction for moduli of the form 2**k - b */
-     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
-        goto LBL_M;
-     }
-     redux = mp_reduce_2k;
-#else
-     err = MP_VAL;
-     goto LBL_M;
-#endif
-  }
-
-  /* setup result */
-  if ((err = mp_init (&res)) != MP_OKAY) {
-    goto LBL_M;
-  }
-
-  /* create M table
-   *
-
-   *
-   * The first half of the table is not computed though accept for M[0] and M[1]
-   */
-
-  if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
-     /* now we need R mod m */
-     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
-       goto LBL_RES;
-     }
-#else 
-     err = MP_VAL;
-     goto LBL_RES;
-#endif
-
-     /* now set M[1] to G * R mod m */
-     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
-       goto LBL_RES;
-     }
-  } else {
-     mp_set(&res, 1);
-     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
-        goto LBL_RES;
-     }
-  }
-
-  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
-  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
-    goto LBL_RES;
-  }
-
-  for (x = 0; x < (winsize - 1); x++) {
-    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
-      goto LBL_RES;
-    }
-    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
-      goto LBL_RES;
-    }
-  }
-
-  /* create upper table */
-  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
-    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
-      goto LBL_RES;
-    }
-    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
-      goto LBL_RES;
-    }
-  }
-
-  /* set initial mode and bit cnt */
-  mode   = 0;
-  bitcnt = 1;
-  buf    = 0;
-  digidx = X->used - 1;
-  bitcpy = 0;
-  bitbuf = 0;
-
-  for (;;) {
-    /* grab next digit as required */
-    if (--bitcnt == 0) {
-      /* if digidx == -1 we are out of digits so break */
-      if (digidx == -1) {
-        break;
-      }
-      /* read next digit and reset bitcnt */
-      buf    = X->dp[digidx--];
-      bitcnt = (int)DIGIT_BIT;
-    }
-
-    /* grab the next msb from the exponent */
-    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
-    buf <<= (mp_digit)1;
-
-    /* if the bit is zero and mode == 0 then we ignore it
-     * These represent the leading zero bits before the first 1 bit
-     * in the exponent.  Technically this opt is not required but it
-     * does lower the # of trivial squaring/reductions used
-     */
-    if (mode == 0 && y == 0) {
-      continue;
-    }
-
-    /* if the bit is zero and mode == 1 then we square */
-    if (mode == 1 && y == 0) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      continue;
-    }
-
-    /* else we add it to the window */
-    bitbuf |= (y << (winsize - ++bitcpy));
-    mode    = 2;
-
-    if (bitcpy == winsize) {
-      /* ok window is filled so square as required and multiply  */
-      /* square first */
-      for (x = 0; x < winsize; x++) {
-        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, mp)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-
-      /* then multiply */
-      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* empty window and reset */
-      bitcpy = 0;
-      bitbuf = 0;
-      mode   = 1;
-    }
-  }
-
-  /* if bits remain then square/multiply */
-  if (mode == 2 && bitcpy > 0) {
-    /* square then multiply if the bit is set */
-    for (x = 0; x < bitcpy; x++) {
-      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-      if ((err = redux (&res, P, mp)) != MP_OKAY) {
-        goto LBL_RES;
-      }
-
-      /* get next bit of the window */
-      bitbuf <<= 1;
-      if ((bitbuf & (1 << winsize)) != 0) {
-        /* then multiply */
-        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-        if ((err = redux (&res, P, mp)) != MP_OKAY) {
-          goto LBL_RES;
-        }
-      }
-    }
-  }
-
-  if (redmode == 0) {
-     /* fixup result if Montgomery reduction is used
-      * recall that any value in a Montgomery system is
-      * actually multiplied by R mod n.  So we have
-      * to reduce one more time to cancel out the factor
-      * of R.
-      */
-     if ((err = redux(&res, P, mp)) != MP_OKAY) {
-       goto LBL_RES;
-     }
-  }
-
-  /* swap res with Y */
-  mp_exch (&res, Y);
-  err = MP_OKAY;
-LBL_RES:mp_clear (&res);
-LBL_M:
-  mp_clear(&M[1]);
-  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
-    mp_clear (&M[x]);
-  }
-  return err;
-}
-#endif
-
-
-#ifdef BN_FAST_S_MP_SQR_C
-/* the jist of squaring...
- * you do like mult except the offset of the tmpx [one that 
- * starts closer to zero] can't equal the offset of tmpy.  
- * So basically you set up iy like before then you min it with
- * (ty-tx) so that it never happens.  You double all those 
- * you add in the inner loop
-
-After that loop you do the squares and add them in.
-*/
-
-static int fast_s_mp_sqr (mp_int * a, mp_int * b)
-{
-  int       olduse, res, pa, ix, iz;
-  mp_digit   W[MP_WARRAY], *tmpx;
-  mp_word   W1;
-
-  /* grow the destination as required */
-  pa = a->used + a->used;
-  if (b->alloc < pa) {
-    if ((res = mp_grow (b, pa)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* number of output digits to produce */
-  W1 = 0;
-  for (ix = 0; ix < pa; ix++) { 
-      int      tx, ty, iy;
-      mp_word  _W;
-      mp_digit *tmpy;
-
-      /* clear counter */
-      _W = 0;
-
-      /* get offsets into the two bignums */
-      ty = MIN(a->used-1, ix);
-      tx = ix - ty;
-
-      /* setup temp aliases */
-      tmpx = a->dp + tx;
-      tmpy = a->dp + ty;
-
-      /* this is the number of times the loop will iterrate, essentially
-         while (tx++ < a->used && ty-- >= 0) { ... }
-       */
-      iy = MIN(a->used-tx, ty+1);
-
-      /* now for squaring tx can never equal ty 
-       * we halve the distance since they approach at a rate of 2x
-       * and we have to round because odd cases need to be executed
-       */
-      iy = MIN(iy, (ty-tx+1)>>1);
-
-      /* execute loop */
-      for (iz = 0; iz < iy; iz++) {
-         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
-      }
-
-      /* double the inner product and add carry */
-      _W = _W + _W + W1;
-
-      /* even columns have the square term in them */
-      if ((ix&1) == 0) {
-         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
-      }
-
-      /* store it */
-      W[ix] = (mp_digit)(_W & MP_MASK);
-
-      /* make next carry */
-      W1 = _W >> ((mp_word)DIGIT_BIT);
-  }
-
-  /* setup dest */
-  olduse  = b->used;
-  b->used = a->used+a->used;
-
-  {
-    mp_digit *tmpb;
-    tmpb = b->dp;
-    for (ix = 0; ix < pa; ix++) {
-      *tmpb++ = W[ix] & MP_MASK;
-    }
-
-    /* clear unused digits [that existed in the old copy of c] */
-    for (; ix < olduse; ix++) {
-      *tmpb++ = 0;
-    }
-  }
-  mp_clamp (b);
-  return MP_OKAY;
-}
-#endif
-
-
-#ifdef BN_MP_MUL_D_C
-/* multiply by a digit */
-static int
-mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
-{
-  mp_digit u, *tmpa, *tmpc;
-  mp_word  r;
-  int      ix, res, olduse;
-
-  /* make sure c is big enough to hold a*b */
-  if (c->alloc < a->used + 1) {
-    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
-      return res;
-    }
-  }
-
-  /* get the original destinations used count */
-  olduse = c->used;
-
-  /* set the sign */
-  c->sign = a->sign;
-
-  /* alias for a->dp [source] */
-  tmpa = a->dp;
-
-  /* alias for c->dp [dest] */
-  tmpc = c->dp;
-
-  /* zero carry */
-  u = 0;
-
-  /* compute columns */
-  for (ix = 0; ix < a->used; ix++) {
-    /* compute product and carry sum for this term */
-    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
-
-    /* mask off higher bits to get a single digit */
-    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
-
-    /* send carry into next iteration */
-    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
-  }
-
-  /* store final carry [if any] and increment ix offset  */
-  *tmpc++ = u;
-  ++ix;
-
-  /* now zero digits above the top */
-  while (ix++ < olduse) {
-     *tmpc++ = 0;
-  }
-
-  /* set used count */
-  c->used = a->used + 1;
-  mp_clamp(c);
-
-  return MP_OKAY;
-}
-#endif

Copied: vendor/wpa/2.0/src/tls/libtommath.c (from rev 9639, vendor/wpa/dist/src/tls/libtommath.c)
===================================================================
--- vendor/wpa/2.0/src/tls/libtommath.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/libtommath.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3389 @@
+/*
+ * Minimal code for RSA support from LibTomMath 0.41
+ * http://libtom.org/
+ * http://libtom.org/files/ltm-0.41.tar.bz2
+ * This library was released in public domain by Tom St Denis.
+ *
+ * The combination in this file may not use all of the optimized algorithms
+ * from LibTomMath and may be considerable slower than the LibTomMath with its
+ * default settings. The main purpose of having this version here is to make it
+ * easier to build bignum.c wrapper without having to install and build an
+ * external library.
+ *
+ * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
+ * libtommath.c file instead of using the external LibTomMath library.
+ */
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#define BN_MP_INVMOD_C
+#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
+			   * require BN_MP_EXPTMOD_FAST_C instead */
+#define BN_S_MP_MUL_DIGS_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
+				 * would require other than mp_reduce */
+
+#ifdef LTM_FAST
+
+/* Use faster div at the cost of about 1 kB */
+#define BN_MP_MUL_D_C
+
+/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MUL_2_C
+
+/* Include faster sqr at the cost of about 0.5 kB in code */
+#define BN_FAST_S_MP_SQR_C
+
+#else /* LTM_FAST */
+
+#define BN_MP_DIV_SMALL
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_ABS_C
+#endif /* LTM_FAST */
+
+/* Current uses do not require support for negative exponent in exptmod, so we
+ * can save about 1.5 kB in leaving out invmod. */
+#define LTM_NO_NEG_EXP
+
+/* from tommath.h */
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#define  OPT_CAST(x)
+
+#ifdef __x86_64__
+typedef unsigned long mp_digit;
+typedef unsigned long mp_word __attribute__((mode(TI)));
+
+#define DIGIT_BIT 60
+#define MP_64BIT
+#else
+typedef unsigned long mp_digit;
+typedef u64 mp_word;
+
+#define DIGIT_BIT          28
+#define MP_28BIT
+#endif
+
+
+#define XMALLOC  os_malloc
+#define XFREE    os_free
+#define XREALLOC os_realloc
+
+
+#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+
+#define MP_LT        -1   /* less than */
+#define MP_EQ         0   /* equal to */
+#define MP_GT         1   /* greater than */
+
+#define MP_ZPOS       0   /* positive integer */
+#define MP_NEG        1   /* negative */
+
+#define MP_OKAY       0   /* ok result */
+#define MP_MEM        -2  /* out of mem */
+#define MP_VAL        -3  /* invalid input */
+
+#define MP_YES        1   /* yes response */
+#define MP_NO         0   /* no response */
+
+typedef int           mp_err;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+#define MP_LOW_MEM
+
+/* default precision */
+#ifndef MP_PREC
+   #ifndef MP_LOW_MEM
+      #define MP_PREC                 32     /* default digits of precision */
+   #else
+      #define MP_PREC                 8      /* default digits of precision */
+   #endif   
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct  {
+    int used, alloc, sign;
+    mp_digit *dp;
+} mp_int;
+
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a)  (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+
+/* prototypes for copied functions */
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+static int s_mp_sqr(mp_int * a, mp_int * b);
+static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
+
+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+
+#ifdef BN_MP_INIT_MULTI_C
+static int mp_init_multi(mp_int *mp, ...);
+#endif
+#ifdef BN_MP_CLEAR_MULTI_C
+static void mp_clear_multi(mp_int *mp, ...);
+#endif
+static int mp_lshd(mp_int * a, int b);
+static void mp_set(mp_int * a, mp_digit b);
+static void mp_clamp(mp_int * a);
+static void mp_exch(mp_int * a, mp_int * b);
+static void mp_rshd(mp_int * a, int b);
+static void mp_zero(mp_int * a);
+static int mp_mod_2d(mp_int * a, int b, mp_int * c);
+static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
+static int mp_init_copy(mp_int * a, mp_int * b);
+static int mp_mul_2d(mp_int * a, int b, mp_int * c);
+#ifndef LTM_NO_NEG_EXP
+static int mp_div_2(mp_int * a, mp_int * b);
+static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+#endif /* LTM_NO_NEG_EXP */
+static int mp_copy(mp_int * a, mp_int * b);
+static int mp_count_bits(mp_int * a);
+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_grow(mp_int * a, int size);
+static int mp_cmp_mag(mp_int * a, mp_int * b);
+#ifdef BN_MP_ABS_C
+static int mp_abs(mp_int * a, mp_int * b);
+#endif
+static int mp_sqr(mp_int * a, mp_int * b);
+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+static int mp_2expt(mp_int * a, int b);
+static int mp_reduce_setup(mp_int * a, mp_int * b);
+static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
+static int mp_init_size(mp_int * a, int size);
+#ifdef BN_MP_EXPTMOD_FAST_C
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+#endif /* BN_MP_EXPTMOD_FAST_C */
+#ifdef BN_FAST_S_MP_SQR_C
+static int fast_s_mp_sqr (mp_int * a, mp_int * b);
+#endif /* BN_FAST_S_MP_SQR_C */
+#ifdef BN_MP_MUL_D_C
+static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+#endif /* BN_MP_MUL_D_C */
+
+
+
+/* functions from bn_<func name>.c */
+
+
+/* reverse an array, used for radix code */
+static void bn_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int *x;
+  int     olduse, res, min, max;
+
+  /* find sizes, we let |a| <= |b| which means we have to sort
+   * them.  "x" will point to the input with the most digits
+   */
+  if (a->used > b->used) {
+    min = b->used;
+    max = a->used;
+    x = a;
+  } else {
+    min = a->used;
+    max = b->used;
+    x = b;
+  }
+
+  /* init result */
+  if (c->alloc < max + 1) {
+    if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get old used digit count and set new one */
+  olduse = c->used;
+  c->used = max + 1;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+
+    /* first input */
+    tmpa = a->dp;
+
+    /* second input */
+    tmpb = b->dp;
+
+    /* destination */
+    tmpc = c->dp;
+
+    /* zero the carry */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+      *tmpc = *tmpa++ + *tmpb++ + u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+      /* take away carry bit from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, that is in A+B 
+     * if A or B has more digits add those in 
+     */
+    if (min != max) {
+      for (; i < max; i++) {
+        /* T[i] = X[i] + U */
+        *tmpc = x->dp[i] + u;
+
+        /* U = carry bit of T[i] */
+        u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+        /* take away carry bit from T[i] */
+        *tmpc++ &= MP_MASK;
+      }
+    }
+
+    /* add carry */
+    *tmpc++ = u;
+
+    /* clear digits above oldused */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     olduse, res, min, max;
+
+  /* find sizes */
+  min = b->used;
+  max = a->used;
+
+  /* init result */
+  if (c->alloc < max) {
+    if ((res = mp_grow (c, max)) != MP_OKAY) {
+      return res;
+    }
+  }
+  olduse = c->used;
+  c->used = max;
+
+  {
+    register mp_digit u, *tmpa, *tmpb, *tmpc;
+    register int i;
+
+    /* alias for digit pointers */
+    tmpa = a->dp;
+    tmpb = b->dp;
+    tmpc = c->dp;
+
+    /* set carry to zero */
+    u = 0;
+    for (i = 0; i < min; i++) {
+      /* T[i] = A[i] - B[i] - U */
+      *tmpc = *tmpa++ - *tmpb++ - u;
+
+      /* U = carry bit of T[i]
+       * Note this saves performing an AND operation since
+       * if a carry does occur it will propagate all the way to the
+       * MSB.  As a result a single shift is enough to get the carry
+       */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* now copy higher words if any, e.g. if A has more digits than B  */
+    for (; i < max; i++) {
+      /* T[i] = A[i] - U */
+      *tmpc = *tmpa++ - u;
+
+      /* U = carry bit of T[i] */
+      u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+      /* Clear carry from T[i] */
+      *tmpc++ &= MP_MASK;
+    }
+
+    /* clear digits above used (since we may not have grown result above) */
+    for (i = c->used; i < olduse; i++) {
+      *tmpc++ = 0;
+    }
+  }
+
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* init a new mp_int */
+static int mp_init (mp_int * a)
+{
+  int i;
+
+  /* allocate memory required and clear it */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the digits to zero */
+  for (i = 0; i < MP_PREC; i++) {
+      a->dp[i] = 0;
+  }
+
+  /* set the used to zero, allocated digits to the default precision
+   * and sign to positive */
+  a->used  = 0;
+  a->alloc = MP_PREC;
+  a->sign  = MP_ZPOS;
+
+  return MP_OKAY;
+}
+
+
+/* clear one (frees)  */
+static void mp_clear (mp_int * a)
+{
+  int i;
+
+  /* only do anything if a hasn't been freed previously */
+  if (a->dp != NULL) {
+    /* first zero the digits */
+    for (i = 0; i < a->used; i++) {
+        a->dp[i] = 0;
+    }
+
+    /* free ram */
+    XFREE(a->dp);
+
+    /* reset members to make debugging easier */
+    a->dp    = NULL;
+    a->alloc = a->used = 0;
+    a->sign  = MP_ZPOS;
+  }
+}
+
+
+/* high level addition (handles signs) */
+static int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  /* get sign of both inputs */
+  sa = a->sign;
+  sb = b->sign;
+
+  /* handle two cases, not four */
+  if (sa == sb) {
+    /* both positive or both negative */
+    /* add their magnitudes, copy the sign */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* one positive, the other negative */
+    /* subtract the one with the greater magnitude from */
+    /* the one of the lesser magnitude.  The result gets */
+    /* the sign of the one with the greater magnitude. */
+    if (mp_cmp_mag (a, b) == MP_LT) {
+      c->sign = sb;
+      res = s_mp_sub (b, a, c);
+    } else {
+      c->sign = sa;
+      res = s_mp_sub (a, b, c);
+    }
+  }
+  return res;
+}
+
+
+/* high level subtraction (handles signs) */
+static int mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     sa, sb, res;
+
+  sa = a->sign;
+  sb = b->sign;
+
+  if (sa != sb) {
+    /* subtract a negative from a positive, OR */
+    /* subtract a positive from a negative. */
+    /* In either case, ADD their magnitudes, */
+    /* and use the sign of the first number. */
+    c->sign = sa;
+    res = s_mp_add (a, b, c);
+  } else {
+    /* subtract a positive from a positive, OR */
+    /* subtract a negative from a negative. */
+    /* First, take the difference between their */
+    /* magnitudes, then... */
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      /* Copy the sign from the first */
+      c->sign = sa;
+      /* The first has a larger or equal magnitude */
+      res = s_mp_sub (a, b, c);
+    } else {
+      /* The result has the *opposite* sign from */
+      /* the first number. */
+      c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+      /* The second has a larger magnitude */
+      res = s_mp_sub (b, a, c);
+    }
+  }
+  return res;
+}
+
+
+/* high level multiplication (handles sign) */
+static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+  int     res, neg;
+  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+  /* use Toom-Cook? */
+#ifdef BN_MP_TOOM_MUL_C
+  if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
+    res = mp_toom_mul(a, b, c);
+  } else 
+#endif
+#ifdef BN_MP_KARATSUBA_MUL_C
+  /* use Karatsuba? */
+  if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
+    res = mp_karatsuba_mul (a, b, c);
+  } else 
+#endif
+  {
+    /* can we use the fast multiplier?
+     *
+     * The fast multiplier can be used if the output will 
+     * have less than MP_WARRAY digits and the number of 
+     * digits won't affect carry propagation
+     */
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+    int     digs = a->used + b->used + 1;
+
+    if ((digs < MP_WARRAY) &&
+        MIN(a->used, b->used) <= 
+        (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+      res = fast_s_mp_mul_digs (a, b, c, digs);
+    } else 
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+      res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+#error mp_mul could fail
+      res = MP_VAL;
+#endif
+
+  }
+  c->sign = (c->used > 0) ? neg : MP_ZPOS;
+  return res;
+}
+
+
+/* d = a * b (mod c) */
+static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  int     res;
+  mp_int  t;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+  res = mp_mod (&t, c, d);
+  mp_clear (&t);
+  return res;
+}
+
+
+/* c = a mod b, 0 <= c < b */
+static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  t;
+  int     res;
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  if (t.sign != b->sign) {
+    res = mp_add (b, &t, c);
+  } else {
+    res = MP_OKAY;
+    mp_exch (&t, c);
+  }
+
+  mp_clear (&t);
+  return res;
+}
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions.  Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted a lot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+  int dr;
+
+  /* modulus P must be positive */
+  if (P->sign == MP_NEG) {
+     return MP_VAL;
+  }
+
+  /* if exponent X is negative we have to recurse */
+  if (X->sign == MP_NEG) {
+#ifdef LTM_NO_NEG_EXP
+        return MP_VAL;
+#else /* LTM_NO_NEG_EXP */
+#ifdef BN_MP_INVMOD_C
+     mp_int tmpG, tmpX;
+     int err;
+
+     /* first compute 1/G mod P */
+     if ((err = mp_init(&tmpG)) != MP_OKAY) {
+        return err;
+     }
+     if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+
+     /* now get |X| */
+     if ((err = mp_init(&tmpX)) != MP_OKAY) {
+        mp_clear(&tmpG);
+        return err;
+     }
+     if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+        mp_clear_multi(&tmpG, &tmpX, NULL);
+        return err;
+     }
+
+     /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+     err = mp_exptmod(&tmpG, &tmpX, P, Y);
+     mp_clear_multi(&tmpG, &tmpX, NULL);
+     return err;
+#else 
+#error mp_exptmod would always fail
+     /* no invmod */
+     return MP_VAL;
+#endif
+#endif /* LTM_NO_NEG_EXP */
+  }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
+  if (mp_reduce_is_2k_l(P) == MP_YES) {
+     return s_mp_exptmod(G, X, P, Y, 1);
+  }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+  /* is it a DR modulus? */
+  dr = mp_dr_is_modulus(P);
+#else
+  /* default to no */
+  dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+  /* if not, is it a unrestricted DR modulus? */
+  if (dr == 0) {
+     dr = mp_reduce_is_2k(P) << 1;
+  }
+#endif
+    
+  /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+  if (mp_isodd (P) == 1 || dr !=  0) {
+    return mp_exptmod_fast (G, X, P, Y, dr);
+  } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+    /* otherwise use the generic Barrett reduction technique */
+    return s_mp_exptmod (G, X, P, Y, 0);
+#else
+#error mp_exptmod could fail
+    /* no exptmod for evens */
+    return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+  }
+#endif
+}
+
+
+/* compare two ints (signed)*/
+static int mp_cmp (mp_int * a, mp_int * b)
+{
+  /* compare based on sign */
+  if (a->sign != b->sign) {
+     if (a->sign == MP_NEG) {
+        return MP_LT;
+     } else {
+        return MP_GT;
+     }
+  }
+  
+  /* compare digits */
+  if (a->sign == MP_NEG) {
+     /* if negative compare opposite direction */
+     return mp_cmp_mag(b, a);
+  } else {
+     return mp_cmp_mag(a, b);
+  }
+}
+
+
+/* compare a digit */
+static int mp_cmp_d(mp_int * a, mp_digit b)
+{
+  /* compare based on sign */
+  if (a->sign == MP_NEG) {
+    return MP_LT;
+  }
+
+  /* compare based on magnitude */
+  if (a->used > 1) {
+    return MP_GT;
+  }
+
+  /* compare the only digit of a to b */
+  if (a->dp[0] > b) {
+    return MP_GT;
+  } else if (a->dp[0] < b) {
+    return MP_LT;
+  } else {
+    return MP_EQ;
+  }
+}
+
+
+#ifndef LTM_NO_NEG_EXP
+/* hac 14.61, pp608 */
+static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+#ifdef BN_FAST_MP_INVMOD_C
+  /* if the modulus is odd we can use a faster routine instead */
+  if (mp_isodd (b) == 1) {
+    return fast_mp_invmod (a, b, c);
+  }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+  return mp_invmod_slow(a, b, c);
+#endif
+
+#ifndef BN_FAST_MP_INVMOD_C
+#ifndef BN_MP_INVMOD_SLOW_C
+#error mp_invmod would always fail
+#endif
+#endif
+  return MP_VAL;
+}
+#endif /* LTM_NO_NEG_EXP */
+
+
+/* get the size for an unsigned equivalent */
+static int mp_unsigned_bin_size (mp_int * a)
+{
+  int     size = mp_count_bits (a);
+  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+
+#ifndef LTM_NO_NEG_EXP
+/* hac 14.61, pp608 */
+static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+  mp_int  x, y, u, v, A, B, C, D;
+  int     res;
+
+  /* b cannot be negative */
+  if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+    return MP_VAL;
+  }
+
+  /* init temps */
+  if ((res = mp_init_multi(&x, &y, &u, &v, 
+                           &A, &B, &C, &D, NULL)) != MP_OKAY) {
+     return res;
+  }
+
+  /* x = a, y = b */
+  if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+      goto LBL_ERR;
+  }
+  if ((res = mp_copy (b, &y)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+
+  /* 2. [modified] if x,y are both even then return an error! */
+  if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+    goto LBL_ERR;
+  }
+  mp_set (&A, 1);
+  mp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (mp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 4.2 if A or B is odd then */
+    if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+      /* A = (A+y)/2, B = (B-x)/2 */
+      if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* A = A/2, B = B/2 */
+    if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 5.  while v is even do */
+  while (mp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    /* 5.2 if C or D is odd then */
+    if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+      /* C = (C+y)/2, D = (D-x)/2 */
+      if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+      if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+    }
+    /* C = C/2, D = D/2 */
+    if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+    if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* 6.  if u >= v then */
+  if (mp_cmp (&u, &v) != MP_LT) {
+    /* u = u - v, A = A - C, B = B - D */
+    if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  } else {
+    /* v - v - u, C = C - A, D = D - B */
+    if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+
+    if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+      goto LBL_ERR;
+    }
+  }
+
+  /* if not zero goto step 4 */
+  if (mp_iszero (&u) == 0)
+    goto top;
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (mp_cmp_d (&v, 1) != MP_EQ) {
+    res = MP_VAL;
+    goto LBL_ERR;
+  }
+
+  /* if its too low */
+  while (mp_cmp_d(&C, 0) == MP_LT) {
+      if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+  
+  /* too big */
+  while (mp_cmp_mag(&C, b) != MP_LT) {
+      if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+         goto LBL_ERR;
+      }
+  }
+  
+  /* C is now the inverse */
+  mp_exch (&C, c);
+  res = MP_OKAY;
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+  return res;
+}
+#endif /* LTM_NO_NEG_EXP */
+
+
+/* compare maginitude of two ints (unsigned) */
+static int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+  int     n;
+  mp_digit *tmpa, *tmpb;
+
+  /* compare based on # of non-zero digits */
+  if (a->used > b->used) {
+    return MP_GT;
+  }
+  
+  if (a->used < b->used) {
+    return MP_LT;
+  }
+
+  /* alias for a */
+  tmpa = a->dp + (a->used - 1);
+
+  /* alias for b */
+  tmpb = b->dp + (a->used - 1);
+
+  /* compare based on digits  */
+  for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+    if (*tmpa > *tmpb) {
+      return MP_GT;
+    }
+
+    if (*tmpa < *tmpb) {
+      return MP_LT;
+    }
+  }
+  return MP_EQ;
+}
+
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+  int     res;
+
+  /* make sure there are at least two digits */
+  if (a->alloc < 2) {
+     if ((res = mp_grow(a, 2)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero the int */
+  mp_zero (a);
+
+  /* read the bytes in */
+  while (c-- > 0) {
+    if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+      return res;
+    }
+
+#ifndef MP_8BIT
+      a->dp[0] |= *b++;
+      a->used += 1;
+#else
+      a->dp[0] = (*b & MP_MASK);
+      a->dp[1] |= ((*b++ >> 7U) & 1);
+      a->used += 2;
+#endif
+  }
+  mp_clamp (a);
+  return MP_OKAY;
+}
+
+
+/* store in unsigned [big endian] format */
+static int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+  int     x, res;
+  mp_int  t;
+
+  if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+    return res;
+  }
+
+  x = 0;
+  while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+      b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+    if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+  bn_reverse (b, x);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+  mp_digit D, r, rr;
+  int     x, res;
+  mp_int  t;
+
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    res = mp_copy (a, c);
+    if (d != NULL) {
+      mp_zero (d);
+    }
+    return res;
+  }
+
+  if ((res = mp_init (&t)) != MP_OKAY) {
+    return res;
+  }
+
+  /* get the remainder */
+  if (d != NULL) {
+    if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+      mp_clear (&t);
+      return res;
+    }
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    mp_clear (&t);
+    return res;
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    mp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (mp_digit) (b % DIGIT_BIT);
+  if (D != 0) {
+    register mp_digit *tmpc, mask, shift;
+
+    /* mask */
+    mask = (((mp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from the previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+  }
+  mp_clamp (c);
+  if (d != NULL) {
+    mp_exch (&t, d);
+  }
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+static int mp_init_copy (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  if ((res = mp_init (a)) != MP_OKAY) {
+    return res;
+  }
+  return mp_copy (b, a);
+}
+
+
+/* set to zero */
+static void mp_zero (mp_int * a)
+{
+  int       n;
+  mp_digit *tmp;
+
+  a->sign = MP_ZPOS;
+  a->used = 0;
+
+  tmp = a->dp;
+  for (n = 0; n < a->alloc; n++) {
+     *tmp++ = 0;
+  }
+}
+
+
+/* copy, b = a */
+static int mp_copy (mp_int * a, mp_int * b)
+{
+  int     res, n;
+
+  /* if dst == src do nothing */
+  if (a == b) {
+    return MP_OKAY;
+  }
+
+  /* grow dest */
+  if (b->alloc < a->used) {
+     if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+        return res;
+     }
+  }
+
+  /* zero b and copy the parameters over */
+  {
+    register mp_digit *tmpa, *tmpb;
+
+    /* pointer aliases */
+
+    /* source */
+    tmpa = a->dp;
+
+    /* destination */
+    tmpb = b->dp;
+
+    /* copy all the digits */
+    for (n = 0; n < a->used; n++) {
+      *tmpb++ = *tmpa++;
+    }
+
+    /* clear high digits */
+    for (; n < b->used; n++) {
+      *tmpb++ = 0;
+    }
+  }
+
+  /* copy used count and sign */
+  b->used = a->used;
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+
+
+/* shift right a certain amount of digits */
+static void mp_rshd (mp_int * a, int b)
+{
+  int     x;
+
+  /* if b <= 0 then ignore it */
+  if (b <= 0) {
+    return;
+  }
+
+  /* if b > used then simply zero it and return */
+  if (a->used <= b) {
+    mp_zero (a);
+    return;
+  }
+
+  {
+    register mp_digit *bottom, *top;
+
+    /* shift the digits down */
+
+    /* bottom */
+    bottom = a->dp;
+
+    /* top [offset into digits] */
+    top = a->dp + b;
+
+    /* this is implemented as a sliding window where 
+     * the window is b-digits long and digits from 
+     * the top of the window are copied to the bottom
+     *
+     * e.g.
+
+     b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+                 /\                   |      ---->
+                  \-------------------/      ---->
+     */
+    for (x = 0; x < (a->used - b); x++) {
+      *bottom++ = *top++;
+    }
+
+    /* zero the top digits */
+    for (; x < a->used; x++) {
+      *bottom++ = 0;
+    }
+  }
+  
+  /* remove excess digits */
+  a->used -= b;
+}
+
+
+/* swap the elements of two integers, for cases where you can't simply swap the 
+ * mp_int pointers around
+ */
+static void mp_exch (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+
+  t  = *a;
+  *a = *b;
+  *b = t;
+}
+
+
+/* trim unused digits 
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast.  Also fixes the sign if there
+ * are no more leading digits
+ */
+static void mp_clamp (mp_int * a)
+{
+  /* decrease used while the most significant digit is
+   * zero.
+   */
+  while (a->used > 0 && a->dp[a->used - 1] == 0) {
+    --(a->used);
+  }
+
+  /* reset the sign flag if used == 0 */
+  if (a->used == 0) {
+    a->sign = MP_ZPOS;
+  }
+}
+
+
+/* grow as required */
+static int mp_grow (mp_int * a, int size)
+{
+  int     i;
+  mp_digit *tmp;
+
+  /* if the alloc size is smaller alloc more ram */
+  if (a->alloc < size) {
+    /* ensure there are always at least MP_PREC digits extra on top */
+    size += (MP_PREC * 2) - (size % MP_PREC);
+
+    /* reallocate the array a->dp
+     *
+     * We store the return in a temporary variable
+     * in case the operation failed we don't want
+     * to overwrite the dp member of a.
+     */
+    tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
+    if (tmp == NULL) {
+      /* reallocation failed but "a" is still valid [can be freed] */
+      return MP_MEM;
+    }
+
+    /* reallocation succeeded so set a->dp */
+    a->dp = tmp;
+
+    /* zero excess digits */
+    i        = a->alloc;
+    a->alloc = size;
+    for (; i < a->alloc; i++) {
+      a->dp[i] = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+#ifdef BN_MP_ABS_C
+/* b = |a| 
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+static int mp_abs (mp_int * a, mp_int * b)
+{
+  int     res;
+
+  /* copy a to b */
+  if (a != b) {
+     if ((res = mp_copy (a, b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* force the sign of b to positive */
+  b->sign = MP_ZPOS;
+
+  return MP_OKAY;
+}
+#endif
+
+
+/* set to a digit */
+static void mp_set (mp_int * a, mp_digit b)
+{
+  mp_zero (a);
+  a->dp[0] = b & MP_MASK;
+  a->used  = (a->dp[0] != 0) ? 1 : 0;
+}
+
+
+#ifndef LTM_NO_NEG_EXP
+/* b = a/2 */
+static int mp_div_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* copy */
+  if (b->alloc < a->used) {
+    if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* source alias */
+    tmpa = a->dp + b->used - 1;
+
+    /* dest alias */
+    tmpb = b->dp + b->used - 1;
+
+    /* carry */
+    r = 0;
+    for (x = b->used - 1; x >= 0; x--) {
+      /* get the carry for the next iteration */
+      rr = *tmpa & 1;
+
+      /* shift the current digit, add in carry and store */
+      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+      /* forward carry to next iteration */
+      r = rr;
+    }
+
+    /* zero excess digits */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  mp_clamp (b);
+  return MP_OKAY;
+}
+#endif /* LTM_NO_NEG_EXP */
+
+
+/* shift left by a certain bit count */
+static int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+  mp_digit d;
+  int      res;
+
+  /* copy */
+  if (a != c) {
+     if ((res = mp_copy (a, c)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+     if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  d = (mp_digit) (b % DIGIT_BIT);
+  if (d != 0) {
+    register mp_digit *tmpc, shift, mask, r, rr;
+    register int x;
+
+    /* bitmask for carries */
+    mask = (((mp_digit)1) << d) - 1;
+
+    /* shift for msbs */
+    shift = DIGIT_BIT - d;
+
+    /* alias */
+    tmpc = c->dp;
+
+    /* carry */
+    r    = 0;
+    for (x = 0; x < c->used; x++) {
+      /* get the higher bits of the current word */
+      rr = (*tmpc >> shift) & mask;
+
+      /* shift the current word and OR in the carry */
+      *tmpc = ((*tmpc << d) | r) & MP_MASK;
+      ++tmpc;
+
+      /* set the carry to the carry bits of the current word */
+      r = rr;
+    }
+    
+    /* set final carry */
+    if (r != 0) {
+       c->dp[(c->used)++] = r;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+#ifdef BN_MP_INIT_MULTI_C
+static int mp_init_multi(mp_int *mp, ...) 
+{
+    mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
+    int n = 0;                 /* Number of ok inits */
+    mp_int* cur_arg = mp;
+    va_list args;
+
+    va_start(args, mp);        /* init args to next argument from caller */
+    while (cur_arg != NULL) {
+        if (mp_init(cur_arg) != MP_OKAY) {
+            /* Oops - error! Back-track and mp_clear what we already
+               succeeded in init-ing, then return error.
+            */
+            va_list clean_args;
+            
+            /* end the current list */
+            va_end(args);
+            
+            /* now start cleaning up */            
+            cur_arg = mp;
+            va_start(clean_args, mp);
+            while (n--) {
+                mp_clear(cur_arg);
+                cur_arg = va_arg(clean_args, mp_int*);
+            }
+            va_end(clean_args);
+            res = MP_MEM;
+            break;
+        }
+        n++;
+        cur_arg = va_arg(args, mp_int*);
+    }
+    va_end(args);
+    return res;                /* Assumed ok, if error flagged above. */
+}
+#endif
+
+
+#ifdef BN_MP_CLEAR_MULTI_C
+static void mp_clear_multi(mp_int *mp, ...) 
+{
+    mp_int* next_mp = mp;
+    va_list args;
+    va_start(args, mp);
+    while (next_mp != NULL) {
+        mp_clear(next_mp);
+        next_mp = va_arg(args, mp_int*);
+    }
+    va_end(args);
+}
+#endif
+
+
+/* shift left a certain amount of digits */
+static int mp_lshd (mp_int * a, int b)
+{
+  int     x, res;
+
+  /* if its less than zero return */
+  if (b <= 0) {
+    return MP_OKAY;
+  }
+
+  /* grow to fit the new digits */
+  if (a->alloc < a->used + b) {
+     if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+       return res;
+     }
+  }
+
+  {
+    register mp_digit *top, *bottom;
+
+    /* increment the used by the shift amount then copy upwards */
+    a->used += b;
+
+    /* top */
+    top = a->dp + a->used - 1;
+
+    /* base */
+    bottom = a->dp + a->used - 1 - b;
+
+    /* much like mp_rshd this is implemented using a sliding window
+     * except the window goes the otherway around.  Copying from
+     * the bottom to the top.  see bn_mp_rshd.c for more info.
+     */
+    for (x = a->used - 1; x >= b; x--) {
+      *top-- = *bottom--;
+    }
+
+    /* zero the lower digits */
+    top = a->dp;
+    for (x = 0; x < b; x++) {
+      *top++ = 0;
+    }
+  }
+  return MP_OKAY;
+}
+
+
+/* returns the number of bits in an int */
+static int mp_count_bits (mp_int * a)
+{
+  int     r;
+  mp_digit q;
+
+  /* shortcut */
+  if (a->used == 0) {
+    return 0;
+  }
+
+  /* get number of digits and add that */
+  r = (a->used - 1) * DIGIT_BIT;
+  
+  /* take the last digit and count the bits in it */
+  q = a->dp[a->used - 1];
+  while (q > ((mp_digit) 0)) {
+    ++r;
+    q >>= ((mp_digit) 1);
+  }
+  return r;
+}
+
+
+/* calc a value mod 2**b */
+static int mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+  int     x, res;
+
+  /* if b is <= 0 then zero the int */
+  if (b <= 0) {
+    mp_zero (c);
+    return MP_OKAY;
+  }
+
+  /* if the modulus is larger than the value than return */
+  if (b >= (int) (a->used * DIGIT_BIT)) {
+    res = mp_copy (a, c);
+    return res;
+  }
+
+  /* copy */
+  if ((res = mp_copy (a, c)) != MP_OKAY) {
+    return res;
+  }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &=
+    (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+#ifdef BN_MP_DIV_SMALL
+
+/* slower bit-bang division... also smaller */
+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+   mp_int ta, tb, tq, q;
+   int    res, n, n2;
+
+  /* is divisor zero ? */
+  if (mp_iszero (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (mp_cmp_mag (a, b) == MP_LT) {
+    if (d != NULL) {
+      res = mp_copy (a, d);
+    } else {
+      res = MP_OKAY;
+    }
+    if (c != NULL) {
+      mp_zero (c);
+    }
+    return res;
+  }
+	
+  /* init our temps */
+  if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
+     return res;
+  }
+
+
+  mp_set(&tq, 1);
+  n = mp_count_bits(a) - mp_count_bits(b);
+  if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+      ((res = mp_abs(b, &tb)) != MP_OKAY) || 
+      ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+      ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+      goto LBL_ERR;
+  }
+
+  while (n-- >= 0) {
+     if (mp_cmp(&tb, &ta) != MP_GT) {
+        if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+            ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+           goto LBL_ERR;
+        }
+     }
+     if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+         ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+           goto LBL_ERR;
+     }
+  }
+
+  /* now q == quotient and ta == remainder */
+  n  = a->sign;
+  n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+  if (c != NULL) {
+     mp_exch(c, &q);
+     c->sign  = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+  }
+  if (d != NULL) {
+     mp_exch(d, &ta);
+     d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+  }
+LBL_ERR:
+   mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+   return res;
+}
+
+#else
+
+/* integer signed division. 
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly 
+ * incomplete.  For example, it doesn't consider 
+ * the case where digits are removed from 'x' in 
+ * the inner loop.  It also doesn't consider the 
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as 
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  mp_int  q, x, y, t1, t2;
+  int     res, n, t, i, norm, neg;
+
+  /* is divisor zero ? */
+  if (mp_iszero (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (mp_cmp_mag (a, b) == MP_LT) {
+    if (d != NULL) {
+      res = mp_copy (a, d);
+    } else {
+      res = MP_OKAY;
+    }
+    if (c != NULL) {
+      mp_zero (c);
+    }
+    return res;
+  }
+
+  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
+    return res;
+  }
+  q.used = a->used + 2;
+
+  if ((res = mp_init (&t1)) != MP_OKAY) {
+    goto LBL_Q;
+  }
+
+  if ((res = mp_init (&t2)) != MP_OKAY) {
+    goto LBL_T1;
+  }
+
+  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
+    goto LBL_T2;
+  }
+
+  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
+    goto LBL_X;
+  }
+
+  /* fix the sign */
+  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+  x.sign = y.sign = MP_ZPOS;
+
+  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+  norm = mp_count_bits(&y) % DIGIT_BIT;
+  if (norm < (int)(DIGIT_BIT-1)) {
+     norm = (DIGIT_BIT-1) - norm;
+     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
+       goto LBL_Y;
+     }
+     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
+       goto LBL_Y;
+     }
+  } else {
+     norm = 0;
+  }
+
+  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+  n = x.used - 1;
+  t = y.used - 1;
+
+  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+    goto LBL_Y;
+  }
+
+  while (mp_cmp (&x, &y) != MP_LT) {
+    ++(q.dp[n - t]);
+    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+  }
+
+  /* reset y by shifting it back down */
+  mp_rshd (&y, n - t);
+
+  /* step 3. for i from n down to (t + 1) */
+  for (i = n; i >= (t + 1); i--) {
+    if (i > x.used) {
+      continue;
+    }
+
+    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
+     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+    if (x.dp[i] == y.dp[t]) {
+      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+    } else {
+      mp_word tmp;
+      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+      tmp |= ((mp_word) x.dp[i - 1]);
+      tmp /= ((mp_word) y.dp[t]);
+      if (tmp > (mp_word) MP_MASK)
+        tmp = MP_MASK;
+      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+    }
+
+    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
+             xi * b**2 + xi-1 * b + xi-2 
+     
+       do q{i-t-1} -= 1; 
+    */
+    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+    do {
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+      /* find left hand */
+      mp_zero (&t1);
+      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+      t1.dp[1] = y.dp[t];
+      t1.used = 2;
+      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+
+      /* find right hand */
+      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+      t2.dp[2] = x.dp[i];
+      t2.used = 3;
+    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+    if (x.sign == MP_NEG) {
+      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+    }
+  }
+
+  /* now q is the quotient and x is the remainder 
+   * [which we have to normalize] 
+   */
+  
+  /* get sign before writing to c */
+  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+  if (c != NULL) {
+    mp_clamp (&q);
+    mp_exch (&q, c);
+    c->sign = neg;
+  }
+
+  if (d != NULL) {
+    mp_div_2d (&x, norm, &x, NULL);
+    mp_exch (&x, d);
+  }
+
+  res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+  return res;
+}
+
+#endif
+
+
+#ifdef MP_LOW_MEM
+   #define TAB_SIZE 32
+#else
+   #define TAB_SIZE 256
+#endif
+
+static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+  mp_int  M[TAB_SIZE], res, mu;
+  mp_digit buf;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+  int (*redux)(mp_int*,mp_int*,mp_int*);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+    if (winsize > 5) {
+       winsize = 5;
+    }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err; 
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* create mu, used for Barrett reduction */
+  if ((err = mp_init (&mu)) != MP_OKAY) {
+    goto LBL_M;
+  }
+  
+  if (redmode == 0) {
+     if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce;
+  } else {
+     if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+        goto LBL_MU;
+     }
+     redux = mp_reduce_2k_l;
+  }    
+
+  /* create M table
+   *
+   * The M table contains powers of the base, 
+   * e.g. M[x] = G**x mod P
+   *
+   * The first half of the table is not 
+   * computed though accept for M[0] and M[1]
+   */
+  if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring 
+   * M[1] (winsize-1) times 
+   */
+  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_MU;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    /* square it */
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], 
+                       &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+
+    /* reduce modulo P */
+    if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+   * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+   */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_MU;
+    }
+    if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+      goto LBL_MU;
+    }
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_MU;
+  }
+  mp_set (&res, 1);
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset the bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int) DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+
+
+/* computes b = a*a */
+static int mp_sqr (mp_int * a, mp_int * b)
+{
+  int     res;
+
+#ifdef BN_MP_TOOM_SQR_C
+  /* use Toom-Cook? */
+  if (a->used >= TOOM_SQR_CUTOFF) {
+    res = mp_toom_sqr(a, b);
+  /* Karatsuba? */
+  } else 
+#endif
+#ifdef BN_MP_KARATSUBA_SQR_C
+if (a->used >= KARATSUBA_SQR_CUTOFF) {
+    res = mp_karatsuba_sqr (a, b);
+  } else 
+#endif
+  {
+#ifdef BN_FAST_S_MP_SQR_C
+    /* can we use the fast comba multiplier? */
+    if ((a->used * 2 + 1) < MP_WARRAY && 
+         a->used < 
+         (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+      res = fast_s_mp_sqr (a, b);
+    } else
+#endif
+#ifdef BN_S_MP_SQR_C
+      res = s_mp_sqr (a, b);
+#else
+#error mp_sqr could fail
+      res = MP_VAL;
+#endif
+  }
+  b->sign = MP_ZPOS;
+  return res;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d 
+   This differs from reduce_2k since "d" can be larger
+   than a single digit.
+*/
+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+   mp_int q;
+   int    p, res;
+   
+   if ((res = mp_init(&q)) != MP_OKAY) {
+      return res;
+   }
+   
+   p = mp_count_bits(n);    
+top:
+   /* q = a/2**p, a = a mod 2**p */
+   if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   /* q = q * d */
+   if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { 
+      goto ERR;
+   }
+   
+   /* a = a + q */
+   if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if (mp_cmp_mag(a, n) != MP_LT) {
+      s_mp_sub(a, n, a);
+      goto top;
+   }
+   
+ERR:
+   mp_clear(&q);
+   return res;
+}
+
+
+/* determines the setup value */
+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+   int    res;
+   mp_int tmp;
+   
+   if ((res = mp_init(&tmp)) != MP_OKAY) {
+      return res;
+   }
+   
+   if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+      goto ERR;
+   }
+   
+   if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+      goto ERR;
+   }
+   
+ERR:
+   mp_clear(&tmp);
+   return res;
+}
+
+
+/* computes a = 2**b 
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+static int mp_2expt (mp_int * a, int b)
+{
+  int     res;
+
+  /* zero a as per default */
+  mp_zero (a);
+
+  /* grow a to accommodate the single bit */
+  if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* set the used count of where the bit will go */
+  a->used = b / DIGIT_BIT + 1;
+
+  /* put the single bit in its place */
+  a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+  return MP_OKAY;
+}
+
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+static int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+  int     res;
+  
+  if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+    return res;
+  }
+  return mp_div (a, b, a, NULL);
+}
+
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is 
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+  mp_int  q;
+  int     res, um = m->used;
+
+  /* q = x */
+  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+    return res;
+  }
+
+  /* q1 = x / b**(k-1)  */
+  mp_rshd (&q, um - 1);         
+
+  /* according to HAC this optimization is ok */
+  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+#else 
+    { 
+#error mp_reduce would always fail
+      res = MP_VAL;
+      goto CLEANUP;
+    }
+#endif
+  }
+
+  /* q3 = q2 / b**(k+1) */
+  mp_rshd (&q, um + 1);         
+
+  /* x = x mod b**(k+1), quick (no division) */
+  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* q = q * m mod b**(k+1), quick (no division) */
+  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* x = x - q */
+  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+    goto CLEANUP;
+  }
+
+  /* If x < 0, add b**(k+1) to it */
+  if (mp_cmp_d (x, 0) == MP_LT) {
+    mp_set (&q, 1);
+    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+    if ((res = mp_add (x, &q, x)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  }
+
+  /* Back off if it's too big */
+  while (mp_cmp (x, m) != MP_LT) {
+    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+      goto CLEANUP;
+    }
+  }
+  
+CLEANUP:
+  mp_clear (&q);
+
+  return res;
+}
+
+
+/* multiplies |a| * |b| and only computes up to digs digits of result
+ * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
+ * many digits of output are created.
+ */
+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+  if (((digs) < MP_WARRAY) &&
+      MIN (a->used, b->used) < 
+          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_digs (a, b, c, digs);
+  }
+
+  if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+    return res;
+  }
+  t.used = digs;
+
+  /* compute the digits of the product directly */
+  pa = a->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* set the carry to zero */
+    u = 0;
+
+    /* limit ourselves to making digs digits of output */
+    pb = MIN (b->used, digs - ix);
+
+    /* setup some aliases */
+    /* copy of the digit from a used within the nested loop */
+    tmpx = a->dp[ix];
+    
+    /* an alias for the destination shifted ix places */
+    tmpt = t.dp + ix;
+    
+    /* an alias for the digits of b */
+    tmpy = b->dp;
+
+    /* compute the columns of the output and propagate the carry */
+    for (iy = 0; iy < pb; iy++) {
+      /* compute the column as a mp_word */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* the new column is the lower part of the result */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get the carry word from the result */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    /* set carry if it is placed below digs */
+    if (ix + iy < digs) {
+      *tmpt = u;
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, c);
+
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier.  It is 
+ * designed to compute the columns of the product first 
+ * then handle the carries afterwards.  This has the effect 
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of 
+ * digits of output so if say only a half-product is required 
+ * you don't have to compute the upper half (a feature 
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  int     olduse, res, pa, ix, iz;
+  mp_digit W[MP_WARRAY];
+  register mp_word  _W;
+
+  /* grow the destination as required */
+  if (c->alloc < digs) {
+    if ((res = mp_grow (c, digs)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  pa = MIN(digs, a->used + b->used);
+
+  /* clear the carry */
+  _W = 0;
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty;
+      int      iy;
+      mp_digit *tmpx, *tmpy;
+
+      /* get offsets into the two bignums */
+      ty = MIN(b->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = b->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially 
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; ++iz) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+      }
+
+      /* store term */
+      W[ix] = ((mp_digit)_W) & MP_MASK;
+
+      /* make next carry */
+      _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+  /* setup dest */
+  olduse  = c->used;
+  c->used = pa;
+
+  {
+    register mp_digit *tmpc;
+    tmpc = c->dp;
+    for (ix = 0; ix < pa+1; ix++) {
+      /* now extract the previous digit [below the carry] */
+      *tmpc++ = W[ix];
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpc++ = 0;
+    }
+  }
+  mp_clamp (c);
+  return MP_OKAY;
+}
+
+
+/* init an mp_init for a given size */
+static int mp_init_size (mp_int * a, int size)
+{
+  int x;
+
+  /* pad size so there are always extra digits */
+  size += (MP_PREC * 2) - (size % MP_PREC);	
+  
+  /* alloc mem */
+  a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
+  if (a->dp == NULL) {
+    return MP_MEM;
+  }
+
+  /* set the members */
+  a->used  = 0;
+  a->alloc = size;
+  a->sign  = MP_ZPOS;
+
+  /* zero the digits */
+  for (x = 0; x < size; x++) {
+      a->dp[x] = 0;
+  }
+
+  return MP_OKAY;
+}
+
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+static int s_mp_sqr (mp_int * a, mp_int * b)
+{
+  mp_int  t;
+  int     res, ix, iy, pa;
+  mp_word r;
+  mp_digit u, tmpx, *tmpt;
+
+  pa = a->used;
+  if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+    return res;
+  }
+
+  /* default used is maximum possible size */
+  t.used = 2*pa + 1;
+
+  for (ix = 0; ix < pa; ix++) {
+    /* first calculate the digit at 2*ix */
+    /* calculate double precision result */
+    r = ((mp_word) t.dp[2*ix]) +
+        ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+    /* store lower part in result */
+    t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* get the carry */
+    u           = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+    /* left hand side of A[ix] * A[iy] */
+    tmpx        = a->dp[ix];
+
+    /* alias for where to store the results */
+    tmpt        = t.dp + (2*ix + 1);
+    
+    for (iy = ix + 1; iy < pa; iy++) {
+      /* first calculate the product */
+      r       = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+      /* now calculate the double precision result, note we use
+       * addition instead of *2 since it's easier to optimize
+       */
+      r       = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+      /* store lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* get carry */
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+    /* propagate upwards */
+    while (u != ((mp_digit) 0)) {
+      r       = ((mp_word) *tmpt) + ((mp_word) u);
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+      u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+    }
+  }
+
+  mp_clamp (&t);
+  mp_exch (&t, b);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+  mp_int  t;
+  int     res, pa, pb, ix, iy;
+  mp_digit u;
+  mp_word r;
+  mp_digit tmpx, *tmpt, *tmpy;
+
+  /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+  if (((a->used + b->used + 1) < MP_WARRAY)
+      && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+    return fast_s_mp_mul_high_digs (a, b, c, digs);
+  }
+#endif
+
+  if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+    return res;
+  }
+  t.used = a->used + b->used + 1;
+
+  pa = a->used;
+  pb = b->used;
+  for (ix = 0; ix < pa; ix++) {
+    /* clear the carry */
+    u = 0;
+
+    /* left hand side of A[ix] * B[iy] */
+    tmpx = a->dp[ix];
+
+    /* alias to the address of where the digits will be stored */
+    tmpt = &(t.dp[digs]);
+
+    /* alias for where to read the right hand side from */
+    tmpy = b->dp + (digs - ix);
+
+    for (iy = digs - ix; iy < pb; iy++) {
+      /* calculate the double precision result */
+      r       = ((mp_word)*tmpt) +
+                ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+                ((mp_word) u);
+
+      /* get the lower part */
+      *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+      /* carry the carry */
+      u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+    }
+    *tmpt = u;
+  }
+  mp_clamp (&t);
+  mp_exch (&t, c);
+  mp_clear (&t);
+  return MP_OKAY;
+}
+
+
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* setups the montgomery reduction stuff */
+static int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+  mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = n->dp[0];
+
+  if ((b & 1) == 0) {
+    return MP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, olduse;
+  mp_word W[MP_WARRAY];
+
+  /* get old used count */
+  olduse = x->used;
+
+  /* grow a as required */
+  if (x->alloc < n->used + 1) {
+    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* first we have to get the digits of the input into
+   * an array of double precision words W[...]
+   */
+  {
+    register mp_word *_W;
+    register mp_digit *tmpx;
+
+    /* alias for the W[] array */
+    _W   = W;
+
+    /* alias for the digits of  x*/
+    tmpx = x->dp;
+
+    /* copy the digits of a into W[0..a->used-1] */
+    for (ix = 0; ix < x->used; ix++) {
+      *_W++ = *tmpx++;
+    }
+
+    /* zero the high words of W[a->used..m->used*2] */
+    for (; ix < n->used * 2 + 1; ix++) {
+      *_W++ = 0;
+    }
+  }
+
+  /* now we proceed to zero successive digits
+   * from the least significant upwards
+   */
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * m' mod b
+     *
+     * We avoid a double precision multiplication (which isn't required)
+     * by casting the value down to a mp_digit.  Note this requires
+     * that W[ix-1] have  the carry cleared (see after the inner loop)
+     */
+    register mp_digit mu;
+    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i
+     *
+     * This is computed in place and on the fly.  The multiplication
+     * by b**i is handled by offseting which columns the results
+     * are added to.
+     *
+     * Note the comba method normally doesn't handle carries in the
+     * inner loop In this case we fix the carry from the previous
+     * column since the Montgomery reduction requires digits of the
+     * result (so far) [see above] to work.  This is
+     * handled by fixing up one carry after the inner loop.  The
+     * carry fixups are done in order so after these loops the
+     * first m->used words of W[] have the carries fixed
+     */
+    {
+      register int iy;
+      register mp_digit *tmpn;
+      register mp_word *_W;
+
+      /* alias for the digits of the modulus */
+      tmpn = n->dp;
+
+      /* Alias for the columns set by an offset of ix */
+      _W = W + ix;
+
+      /* inner loop */
+      for (iy = 0; iy < n->used; iy++) {
+          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+      }
+    }
+
+    /* now fix carry for next digit, W[ix+1] */
+    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+  }
+
+  /* now we have to propagate the carries and
+   * shift the words downward [all those least
+   * significant digits we zeroed].
+   */
+  {
+    register mp_digit *tmpx;
+    register mp_word *_W, *_W1;
+
+    /* nox fix rest of carries */
+
+    /* alias for current word */
+    _W1 = W + ix;
+
+    /* alias for next word, where the carry goes */
+    _W = W + ++ix;
+
+    for (; ix <= n->used * 2 + 1; ix++) {
+      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+    }
+
+    /* copy out, A = A/b**n
+     *
+     * The result is A/b**n but instead of converting from an
+     * array of mp_word to mp_digit than calling mp_rshd
+     * we just copy them in the right order
+     */
+
+    /* alias for destination word */
+    tmpx = x->dp;
+
+    /* alias for shifted double precision result */
+    _W = W + n->used;
+
+    for (ix = 0; ix < n->used + 1; ix++) {
+      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+    }
+
+    /* zero oldused digits, if the input a was larger than
+     * m->used+1 we'll have to clear the digits
+     */
+    for (; ix < olduse; ix++) {
+      *tmpx++ = 0;
+    }
+  }
+
+  /* set the max used and clamp */
+  x->used = n->used + 1;
+  mp_clamp (x);
+
+  /* if A >= m then A = A - m */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_2_C
+/* b = a*2 */
+static int mp_mul_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* grow to accommodate result */
+  if (b->alloc < a->used + 1) {
+    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+    
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+    
+      /* get what will be the *next* carry bit from the 
+       * MSB of the current digit 
+       */
+      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+      
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+      
+      /* copy the carry that would be from the source 
+       * digit into the next iteration 
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination 
+     * that we didn't write to 
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally up to just under
+ * the leading bit of b.  This saves a lot of multiple precision shifting.
+ */
+static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+  int     x, bits, res;
+
+  /* how many bits of last digit does b use */
+  bits = mp_count_bits (b) % DIGIT_BIT;
+
+  if (b->used > 1) {
+     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+        return res;
+     }
+  } else {
+     mp_set(a, 1);
+     bits = 1;
+  }
+
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+      return res;
+    }
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+        return res;
+      }
+    }
+  }
+
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_EXPTMOD_FAST_C
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+  mp_int  M[TAB_SIZE], res;
+  mp_digit buf, mp;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* use a pointer to the reduction algorithm.  This allows us to use
+   * one of many reduction algorithms without modding the guts of
+   * the code with if statements everywhere.
+   */
+  int     (*redux)(mp_int*,mp_int*,mp_digit);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+  if (winsize > 5) {
+     winsize = 5;
+  }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err;
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* determine and setup reduction code */
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C     
+     /* now setup montgomery  */
+     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+
+     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+     if (((P->used * 2 + 1) < MP_WARRAY) &&
+          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+        redux = fast_mp_montgomery_reduce;
+     } else 
+#endif
+     {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+        /* use slower baseline Montgomery method */
+        redux = mp_montgomery_reduce;
+#else
+        err = MP_VAL;
+        goto LBL_M;
+#endif
+     }
+  } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+     /* setup DR reduction for moduli of the form B**k - b */
+     mp_dr_setup(P, &mp);
+     redux = mp_dr_reduce;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+     /* setup DR reduction for moduli of the form 2**k - b */
+     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+     redux = mp_reduce_2k;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_M;
+  }
+
+  /* create M table
+   *
+
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+     /* now we need R mod m */
+     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+#else 
+     err = MP_VAL;
+     goto LBL_RES;
+#endif
+
+     /* now set M[1] to G * R mod m */
+     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  } else {
+     mp_set(&res, 1);
+     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+        goto LBL_RES;
+     }
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_RES;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  if (redmode == 0) {
+     /* fixup result if Montgomery reduction is used
+      * recall that any value in a Montgomery system is
+      * actually multiplied by R mod n.  So we have
+      * to reduce one more time to cancel out the factor
+      * of R.
+      */
+     if ((err = redux(&res, P, mp)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  }
+
+  /* swap res with Y */
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+#endif
+
+
+#ifdef BN_FAST_S_MP_SQR_C
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that 
+ * starts closer to zero] can't equal the offset of tmpy.  
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens.  You double all those 
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+static int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+  int       olduse, res, pa, ix, iz;
+  mp_digit   W[MP_WARRAY], *tmpx;
+  mp_word   W1;
+
+  /* grow the destination as required */
+  pa = a->used + a->used;
+  if (b->alloc < pa) {
+    if ((res = mp_grow (b, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  W1 = 0;
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      mp_word  _W;
+      mp_digit *tmpy;
+
+      /* clear counter */
+      _W = 0;
+
+      /* get offsets into the two bignums */
+      ty = MIN(a->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = a->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty 
+       * we halve the distance since they approach at a rate of 2x
+       * and we have to round because odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* double the inner product and add carry */
+      _W = _W + _W + W1;
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+      }
+
+      /* store it */
+      W[ix] = (mp_digit)(_W & MP_MASK);
+
+      /* make next carry */
+      W1 = _W >> ((mp_word)DIGIT_BIT);
+  }
+
+  /* setup dest */
+  olduse  = b->used;
+  b->used = a->used+a->used;
+
+  {
+    mp_digit *tmpb;
+    tmpb = b->dp;
+    for (ix = 0; ix < pa; ix++) {
+      *tmpb++ = W[ix] & MP_MASK;
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpb++ = 0;
+    }
+  }
+  mp_clamp (b);
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_D_C
+/* multiply by a digit */
+static int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit u, *tmpa, *tmpc;
+  mp_word  r;
+  int      ix, res, olduse;
+
+  /* make sure c is big enough to hold a*b */
+  if (c->alloc < a->used + 1) {
+    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get the original destinations used count */
+  olduse = c->used;
+
+  /* set the sign */
+  c->sign = a->sign;
+
+  /* alias for a->dp [source] */
+  tmpa = a->dp;
+
+  /* alias for c->dp [dest] */
+  tmpc = c->dp;
+
+  /* zero carry */
+  u = 0;
+
+  /* compute columns */
+  for (ix = 0; ix < a->used; ix++) {
+    /* compute product and carry sum for this term */
+    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+    /* mask off higher bits to get a single digit */
+    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* send carry into next iteration */
+    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+  }
+
+  /* store final carry [if any] and increment ix offset  */
+  *tmpc++ = u;
+  ++ix;
+
+  /* now zero digits above the top */
+  while (ix++ < olduse) {
+     *tmpc++ = 0;
+  }
+
+  /* set used count */
+  c->used = a->used + 1;
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+#endif

Deleted: vendor/wpa/2.0/src/tls/pkcs1.c
===================================================================
--- vendor/wpa/dist/src/tls/pkcs1.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,201 +0,0 @@
-/*
- * PKCS #1 (RSA Encryption)
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "rsa.h"
-#include "pkcs1.h"
-
-
-static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
-					   const u8 *in, size_t inlen,
-					   u8 *out, size_t *outlen)
-{
-	size_t ps_len;
-	u8 *pos;
-
-	/*
-	 * PKCS #1 v1.5, 8.1:
-	 *
-	 * EB = 00 || BT || PS || 00 || D
-	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
-	 * PS = k-3-||D||; at least eight octets
-	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
-	 * k = length of modulus in octets (modlen)
-	 */
-
-	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
-		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
-			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
-			   __func__, (unsigned long) modlen,
-			   (unsigned long) *outlen,
-			   (unsigned long) inlen);
-		return -1;
-	}
-
-	pos = out;
-	*pos++ = 0x00;
-	*pos++ = block_type; /* BT */
-	ps_len = modlen - inlen - 3;
-	switch (block_type) {
-	case 0:
-		os_memset(pos, 0x00, ps_len);
-		pos += ps_len;
-		break;
-	case 1:
-		os_memset(pos, 0xff, ps_len);
-		pos += ps_len;
-		break;
-	case 2:
-		if (os_get_random(pos, ps_len) < 0) {
-			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
-				   "random data for PS", __func__);
-			return -1;
-		}
-		while (ps_len--) {
-			if (*pos == 0x00)
-				*pos = 0x01;
-			pos++;
-		}
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
-			   "%d", __func__, block_type);
-		return -1;
-	}
-	*pos++ = 0x00;
-	os_memcpy(pos, in, inlen); /* D */
-
-	return 0;
-}
-
-
-int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
-		  int use_private, const u8 *in, size_t inlen,
-		  u8 *out, size_t *outlen)
-{
-	size_t modlen;
-
-	modlen = crypto_rsa_get_modulus_len(key);
-
-	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
-					    out, outlen) < 0)
-		return -1;
-
-	return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
-}
-
-
-int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen)
-{
-	int res;
-	u8 *pos, *end;
-
-	res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1);
-	if (res)
-		return res;
-
-	if (*outlen < 2 || out[0] != 0 || out[1] != 2)
-		return -1;
-
-	/* Skip PS (pseudorandom non-zero octets) */
-	pos = out + 2;
-	end = out + *outlen;
-	while (*pos && pos < end)
-		pos++;
-	if (pos == end)
-		return -1;
-	pos++;
-
-	*outlen -= pos - out;
-
-	/* Strip PKCS #1 header */
-	os_memmove(out, pos, *outlen);
-
-	return 0;
-}
-
-
-int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
-			     const u8 *crypt, size_t crypt_len,
-			     u8 *plain, size_t *plain_len)
-{
-	size_t len;
-	u8 *pos;
-
-	len = *plain_len;
-	if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0)
-		return -1;
-
-	/*
-	 * PKCS #1 v1.5, 8.1:
-	 *
-	 * EB = 00 || BT || PS || 00 || D
-	 * BT = 00 or 01
-	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
-	 * k = length of modulus in octets
-	 */
-
-	if (len < 3 + 8 + 16 /* min hash len */ ||
-	    plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
-		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
-			   "structure");
-		return -1;
-	}
-
-	pos = plain + 3;
-	if (plain[1] == 0x00) {
-		/* BT = 00 */
-		if (plain[2] != 0x00) {
-			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
-				   "PS (BT=00)");
-			return -1;
-		}
-		while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
-			pos++;
-	} else {
-		/* BT = 01 */
-		if (plain[2] != 0xff) {
-			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
-				   "PS (BT=01)");
-			return -1;
-		}
-		while (pos < plain + len && *pos == 0xff)
-			pos++;
-	}
-
-	if (pos - plain - 2 < 8) {
-		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
-		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
-			   "padding");
-		return -1;
-	}
-
-	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
-		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
-			   "structure (2)");
-		return -1;
-	}
-	pos++;
-	len -= pos - plain;
-
-	/* Strip PKCS #1 header */
-	os_memmove(plain, pos, len);
-	*plain_len = len;
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/pkcs1.c (from rev 9639, vendor/wpa/dist/src/tls/pkcs1.c)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs1.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs1.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,195 @@
+/*
+ * PKCS #1 (RSA Encryption)
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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 "rsa.h"
+#include "pkcs1.h"
+
+
+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
+					   const u8 *in, size_t inlen,
+					   u8 *out, size_t *outlen)
+{
+	size_t ps_len;
+	u8 *pos;
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
+	 * PS = k-3-||D||; at least eight octets
+	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
+	 * k = length of modulus in octets (modlen)
+	 */
+
+	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
+			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
+			   __func__, (unsigned long) modlen,
+			   (unsigned long) *outlen,
+			   (unsigned long) inlen);
+		return -1;
+	}
+
+	pos = out;
+	*pos++ = 0x00;
+	*pos++ = block_type; /* BT */
+	ps_len = modlen - inlen - 3;
+	switch (block_type) {
+	case 0:
+		os_memset(pos, 0x00, ps_len);
+		pos += ps_len;
+		break;
+	case 1:
+		os_memset(pos, 0xff, ps_len);
+		pos += ps_len;
+		break;
+	case 2:
+		if (os_get_random(pos, ps_len) < 0) {
+			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
+				   "random data for PS", __func__);
+			return -1;
+		}
+		while (ps_len--) {
+			if (*pos == 0x00)
+				*pos = 0x01;
+			pos++;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
+			   "%d", __func__, block_type);
+		return -1;
+	}
+	*pos++ = 0x00;
+	os_memcpy(pos, in, inlen); /* D */
+
+	return 0;
+}
+
+
+int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
+		  int use_private, const u8 *in, size_t inlen,
+		  u8 *out, size_t *outlen)
+{
+	size_t modlen;
+
+	modlen = crypto_rsa_get_modulus_len(key);
+
+	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
+					    out, outlen) < 0)
+		return -1;
+
+	return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
+}
+
+
+int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	int res;
+	u8 *pos, *end;
+
+	res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1);
+	if (res)
+		return res;
+
+	if (*outlen < 2 || out[0] != 0 || out[1] != 2)
+		return -1;
+
+	/* Skip PS (pseudorandom non-zero octets) */
+	pos = out + 2;
+	end = out + *outlen;
+	while (*pos && pos < end)
+		pos++;
+	if (pos == end)
+		return -1;
+	pos++;
+
+	*outlen -= pos - out;
+
+	/* Strip PKCS #1 header */
+	os_memmove(out, pos, *outlen);
+
+	return 0;
+}
+
+
+int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
+			     const u8 *crypt, size_t crypt_len,
+			     u8 *plain, size_t *plain_len)
+{
+	size_t len;
+	u8 *pos;
+
+	len = *plain_len;
+	if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0)
+		return -1;
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 00 or 01
+	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
+	 * k = length of modulus in octets
+	 */
+
+	if (len < 3 + 8 + 16 /* min hash len */ ||
+	    plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure");
+		return -1;
+	}
+
+	pos = plain + 3;
+	if (plain[1] == 0x00) {
+		/* BT = 00 */
+		if (plain[2] != 0x00) {
+			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+				   "PS (BT=00)");
+			return -1;
+		}
+		while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
+			pos++;
+	} else {
+		/* BT = 01 */
+		if (plain[2] != 0xff) {
+			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+				   "PS (BT=01)");
+			return -1;
+		}
+		while (pos < plain + len && *pos == 0xff)
+			pos++;
+	}
+
+	if (pos - plain - 2 < 8) {
+		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+			   "padding");
+		return -1;
+	}
+
+	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure (2)");
+		return -1;
+	}
+	pos++;
+	len -= pos - plain;
+
+	/* Strip PKCS #1 header */
+	os_memmove(plain, pos, len);
+	*plain_len = len;
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/tls/pkcs1.h
===================================================================
--- vendor/wpa/dist/src/tls/pkcs1.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,28 +0,0 @@
-/*
- * PKCS #1 (RSA Encryption)
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PKCS1_H
-#define PKCS1_H
-
-int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
-		  int use_private, const u8 *in, size_t inlen,
-		  u8 *out, size_t *outlen);
-int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
-				  const u8 *in, size_t inlen,
-				  u8 *out, size_t *outlen);
-int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
-			     const u8 *crypt, size_t crypt_len,
-			     u8 *plain, size_t *plain_len);
-
-#endif /* PKCS1_H */

Copied: vendor/wpa/2.0/src/tls/pkcs1.h (from rev 9639, vendor/wpa/dist/src/tls/pkcs1.h)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs1.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs1.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,22 @@
+/*
+ * PKCS #1 (RSA Encryption)
+ * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PKCS1_H
+#define PKCS1_H
+
+int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
+		  int use_private, const u8 *in, size_t inlen,
+		  u8 *out, size_t *outlen);
+int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen);
+int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
+			     const u8 *crypt, size_t crypt_len,
+			     u8 *plain, size_t *plain_len);
+
+#endif /* PKCS1_H */

Deleted: vendor/wpa/2.0/src/tls/pkcs5.c
===================================================================
--- vendor/wpa/dist/src/tls/pkcs5.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,238 +0,0 @@
-/*
- * PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/crypto.h"
-#include "crypto/md5.h"
-#include "asn1.h"
-#include "pkcs5.h"
-
-
-struct pkcs5_params {
-	enum pkcs5_alg {
-		PKCS5_ALG_UNKNOWN,
-		PKCS5_ALG_MD5_DES_CBC
-	} alg;
-	u8 salt[8];
-	size_t salt_len;
-	unsigned int iter_count;
-};
-
-
-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 */)
-		return PKCS5_ALG_MD5_DES_CBC;
-
-	return PKCS5_ALG_UNKNOWN;
-}
-
-
-static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
-			    struct pkcs5_params *params)
-{
-	struct asn1_hdr hdr;
-	const u8 *enc_alg_end, *pos, *end;
-	struct asn1_oid oid;
-	char obuf[80];
-
-	/* AlgorithmIdentifier */
-
-	enc_alg_end = enc_alg + enc_alg_len;
-
-	os_memset(params, 0, sizeof(*params));
-
-	if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
-			   "(algorithm)");
-		return -1;
-	}
-
-	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
-	wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
-	params->alg = pkcs5_get_alg(&oid);
-	if (params->alg == PKCS5_ALG_UNKNOWN) {
-		wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
-			   "algorithm %s", obuf);
-		return -1;
-	}
-
-	/*
-	 * PKCS#5, Section 8
-	 * PBEParameter ::= SEQUENCE {
-	 *   salt OCTET STRING SIZE(8),
-	 *   iterationCount INTEGER }
-	 */
-
-	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
-			   "(PBEParameter) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-	end = hdr.payload + hdr.length;
-
-	/* salt OCTET STRING SIZE(8) */
-	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 OCTETSTRING SIZE(8) "
-			   "(salt) - 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;
-	}
-
-	return 0;
-}
-
-
-static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
-						const char *passwd)
-{
-	unsigned int i;
-	u8 hash[MD5_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	if (params->alg != PKCS5_ALG_MD5_DES_CBC)
-		return NULL;
-
-	addr[0] = (const u8 *) passwd;
-	len[0] = os_strlen(passwd);
-	addr[1] = params->salt;
-	len[1] = params->salt_len;
-	if (md5_vector(2, addr, len, hash) < 0)
-		return NULL;
-	addr[0] = hash;
-	len[0] = MD5_MAC_LEN;
-	for (i = 1; i < params->iter_count; i++) {
-		if (md5_vector(1, addr, len, hash) < 0)
-			return NULL;
-	}
-	/* TODO: DES key parity bits(?) */
-	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
-	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
-
-	return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
-}
-
-
-u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
-		   const u8 *enc_data, size_t enc_data_len,
-		   const char *passwd, size_t *data_len)
-{
-	struct crypto_cipher *ctx;
-	u8 *eb, pad;
-	struct pkcs5_params params;
-	unsigned int i;
-
-	if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
-		return NULL;
-	}
-
-	ctx = pkcs5_crypto_init(&params, passwd);
-	if (ctx == NULL) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
-		return NULL;
-	}
-
-	/* PKCS #5, Section 7 - Decryption process */
-	if (enc_data_len < 16 || enc_data_len % 8) {
-		wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
-			   "%d", (int) enc_data_len);
-		crypto_cipher_deinit(ctx);
-		return NULL;
-	}
-
-	eb = os_malloc(enc_data_len);
-	if (eb == NULL) {
-		crypto_cipher_deinit(ctx);
-		return NULL;
-	}
-
-	if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
-		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
-		crypto_cipher_deinit(ctx);
-		os_free(eb);
-		return NULL;
-	}
-	crypto_cipher_deinit(ctx);
-
-	pad = eb[enc_data_len - 1];
-	if (pad > 8) {
-		wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
-		os_free(eb);
-		return NULL;
-	}
-	for (i = enc_data_len - pad; i < enc_data_len; i++) {
-		if (eb[i] != pad) {
-			wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
-				    eb + enc_data_len - pad, pad);
-			os_free(eb);
-			return NULL;
-		}
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
-			eb, enc_data_len - pad);
-
-	*data_len = enc_data_len - pad;
-	return eb;
-}

Copied: vendor/wpa/2.0/src/tls/pkcs5.c (from rev 9639, vendor/wpa/dist/src/tls/pkcs5.c)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs5.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs5.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,232 @@
+/*
+ * PKCS #5 (Password-based Encryption)
+ * Copyright (c) 2009, Jouni Malinen <j at 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/crypto.h"
+#include "crypto/md5.h"
+#include "asn1.h"
+#include "pkcs5.h"
+
+
+struct pkcs5_params {
+	enum pkcs5_alg {
+		PKCS5_ALG_UNKNOWN,
+		PKCS5_ALG_MD5_DES_CBC
+	} alg;
+	u8 salt[8];
+	size_t salt_len;
+	unsigned int iter_count;
+};
+
+
+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 */)
+		return PKCS5_ALG_MD5_DES_CBC;
+
+	return PKCS5_ALG_UNKNOWN;
+}
+
+
+static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
+			    struct pkcs5_params *params)
+{
+	struct asn1_hdr hdr;
+	const u8 *enc_alg_end, *pos, *end;
+	struct asn1_oid oid;
+	char obuf[80];
+
+	/* AlgorithmIdentifier */
+
+	enc_alg_end = enc_alg + enc_alg_len;
+
+	os_memset(params, 0, sizeof(*params));
+
+	if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
+			   "(algorithm)");
+		return -1;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
+	params->alg = pkcs5_get_alg(&oid);
+	if (params->alg == PKCS5_ALG_UNKNOWN) {
+		wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
+			   "algorithm %s", obuf);
+		return -1;
+	}
+
+	/*
+	 * PKCS#5, Section 8
+	 * PBEParameter ::= SEQUENCE {
+	 *   salt OCTET STRING SIZE(8),
+	 *   iterationCount INTEGER }
+	 */
+
+	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
+			   "(PBEParameter) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+	end = hdr.payload + hdr.length;
+
+	/* salt OCTET STRING SIZE(8) */
+	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 OCTETSTRING SIZE(8) "
+			   "(salt) - 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;
+	}
+
+	return 0;
+}
+
+
+static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
+						const char *passwd)
+{
+	unsigned int i;
+	u8 hash[MD5_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (params->alg != PKCS5_ALG_MD5_DES_CBC)
+		return NULL;
+
+	addr[0] = (const u8 *) passwd;
+	len[0] = os_strlen(passwd);
+	addr[1] = params->salt;
+	len[1] = params->salt_len;
+	if (md5_vector(2, addr, len, hash) < 0)
+		return NULL;
+	addr[0] = hash;
+	len[0] = MD5_MAC_LEN;
+	for (i = 1; i < params->iter_count; i++) {
+		if (md5_vector(1, addr, len, hash) < 0)
+			return NULL;
+	}
+	/* TODO: DES key parity bits(?) */
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
+	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
+
+	return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
+}
+
+
+u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
+		   const u8 *enc_data, size_t enc_data_len,
+		   const char *passwd, size_t *data_len)
+{
+	struct crypto_cipher *ctx;
+	u8 *eb, pad;
+	struct pkcs5_params params;
+	unsigned int i;
+
+	if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
+		return NULL;
+	}
+
+	ctx = pkcs5_crypto_init(&params, passwd);
+	if (ctx == NULL) {
+		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
+		return NULL;
+	}
+
+	/* PKCS #5, Section 7 - Decryption process */
+	if (enc_data_len < 16 || enc_data_len % 8) {
+		wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
+			   "%d", (int) enc_data_len);
+		crypto_cipher_deinit(ctx);
+		return NULL;
+	}
+
+	eb = os_malloc(enc_data_len);
+	if (eb == NULL) {
+		crypto_cipher_deinit(ctx);
+		return NULL;
+	}
+
+	if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
+		crypto_cipher_deinit(ctx);
+		os_free(eb);
+		return NULL;
+	}
+	crypto_cipher_deinit(ctx);
+
+	pad = eb[enc_data_len - 1];
+	if (pad > 8) {
+		wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
+		os_free(eb);
+		return NULL;
+	}
+	for (i = enc_data_len - pad; i < enc_data_len; i++) {
+		if (eb[i] != pad) {
+			wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
+				    eb + enc_data_len - pad, pad);
+			os_free(eb);
+			return NULL;
+		}
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
+			eb, enc_data_len - pad);
+
+	*data_len = enc_data_len - pad;
+	return eb;
+}

Deleted: vendor/wpa/2.0/src/tls/pkcs5.h
===================================================================
--- vendor/wpa/dist/src/tls/pkcs5.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,22 +0,0 @@
-/*
- * PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PKCS5_H
-#define PKCS5_H
-
-u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
-		   const u8 *enc_data, size_t enc_data_len,
-		   const char *passwd, size_t *data_len);
-
-#endif /* PKCS5_H */

Copied: vendor/wpa/2.0/src/tls/pkcs5.h (from rev 9639, vendor/wpa/dist/src/tls/pkcs5.h)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs5.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs5.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+/*
+ * PKCS #5 (Password-based Encryption)
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PKCS5_H
+#define PKCS5_H
+
+u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
+		   const u8 *enc_data, size_t enc_data_len,
+		   const char *passwd, size_t *data_len);
+
+#endif /* PKCS5_H */

Deleted: vendor/wpa/2.0/src/tls/pkcs8.c
===================================================================
--- vendor/wpa/dist/src/tls/pkcs8.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs8.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,193 +0,0 @@
-/*
- * PKCS #8 (Private-key information syntax)
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "asn1.h"
-#include "bignum.h"
-#include "rsa.h"
-#include "pkcs5.h"
-#include "pkcs8.h"
-
-
-struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-	struct bignum *zero;
-	struct asn1_oid oid;
-	char obuf[80];
-
-	/* PKCS #8, Chapter 6 */
-
-	/* PrivateKeyInfo ::= SEQUENCE */
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
-			   "header (SEQUENCE); assume PKCS #8 not used");
-		return NULL;
-	}
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	/* version Version (Version ::= INTEGER) */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
-			   "class %d tag 0x%x; assume PKCS #8 not used",
-			   hdr.class, hdr.tag);
-		return NULL;
-	}
-
-	zero = bignum_init();
-	if (zero == NULL)
-		return NULL;
-
-	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
-		bignum_deinit(zero);
-		return NULL;
-	}
-	pos = hdr.payload + hdr.length;
-
-	if (bignum_cmp_d(zero, 0) != 0) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
-			   "beginning of private key; not found; assume "
-			   "PKCS #8 not used");
-		bignum_deinit(zero);
-		return NULL;
-	}
-	bignum_deinit(zero);
-
-	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
-	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
-			   "assume PKCS #8 not used",
-			   hdr.class, hdr.tag);
-		return NULL;
-	}
-
-	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
-			   "(algorithm); assume PKCS #8 not used");
-		return NULL;
-	}
-
-	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
-	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
-
-	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] != 1 /* pkcs-1 */ ||
-	    oid.oid[6] != 1 /* rsaEncryption */) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
-			   "algorithm %s", obuf);
-		return NULL;
-	}
-
-	pos = hdr.payload + hdr.length;
-
-	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
-			   "(privateKey) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
-
-	return (struct crypto_private_key *)
-		crypto_rsa_import_private_key(hdr.payload, hdr.length);
-}
-
-
-struct crypto_private_key *
-pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end, *enc_alg;
-	size_t enc_alg_len;
-	u8 *data;
-	size_t data_len;
-
-	if (passwd == NULL)
-		return NULL;
-
-	/*
-	 * PKCS #8, Chapter 7
-	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
-	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
-	 *   encryptedData EncryptedData }
-	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-	 * EncryptedData ::= OCTET STRING
-	 */
-
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
-			   "header (SEQUENCE); assume encrypted PKCS #8 not "
-			   "used");
-		return NULL;
-	}
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
-			   "assume encrypted PKCS #8 not used",
-			   hdr.class, hdr.tag);
-		return NULL;
-	}
-	enc_alg = hdr.payload;
-	enc_alg_len = hdr.length;
-	pos = hdr.payload + hdr.length;
-
-	/* encryptedData EncryptedData */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING) {
-		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
-			   "(encryptedData) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return NULL;
-	}
-
-	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
-			     passwd, &data_len);
-	if (data) {
-		struct crypto_private_key *key;
-		key = pkcs8_key_import(data, data_len);
-		os_free(data);
-		return key;
-	}
-
-	return NULL;
-}

Copied: vendor/wpa/2.0/src/tls/pkcs8.c (from rev 9639, vendor/wpa/dist/src/tls/pkcs8.c)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs8.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs8.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,187 @@
+/*
+ * PKCS #8 (Private-key information syntax)
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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 "asn1.h"
+#include "bignum.h"
+#include "rsa.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
+
+
+struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	struct bignum *zero;
+	struct asn1_oid oid;
+	char obuf[80];
+
+	/* PKCS #8, Chapter 6 */
+
+	/* PrivateKeyInfo ::= SEQUENCE */
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
+			   "header (SEQUENCE); assume PKCS #8 not used");
+		return NULL;
+	}
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/* version Version (Version ::= INTEGER) */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
+			   "class %d tag 0x%x; assume PKCS #8 not used",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	zero = bignum_init();
+	if (zero == NULL)
+		return NULL;
+
+	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
+		bignum_deinit(zero);
+		return NULL;
+	}
+	pos = hdr.payload + hdr.length;
+
+	if (bignum_cmp_d(zero, 0) != 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
+			   "beginning of private key; not found; assume "
+			   "PKCS #8 not used");
+		bignum_deinit(zero);
+		return NULL;
+	}
+	bignum_deinit(zero);
+
+	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
+	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
+			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
+			   "assume PKCS #8 not used",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
+			   "(algorithm); assume PKCS #8 not used");
+		return NULL;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
+
+	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] != 1 /* pkcs-1 */ ||
+	    oid.oid[6] != 1 /* rsaEncryption */) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
+			   "algorithm %s", obuf);
+		return NULL;
+	}
+
+	pos = hdr.payload + hdr.length;
+
+	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
+			   "(privateKey) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
+
+	return (struct crypto_private_key *)
+		crypto_rsa_import_private_key(hdr.payload, hdr.length);
+}
+
+
+struct crypto_private_key *
+pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end, *enc_alg;
+	size_t enc_alg_len;
+	u8 *data;
+	size_t data_len;
+
+	if (passwd == NULL)
+		return NULL;
+
+	/*
+	 * PKCS #8, Chapter 7
+	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
+	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
+	 *   encryptedData EncryptedData }
+	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+	 * EncryptedData ::= OCTET STRING
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
+			   "header (SEQUENCE); assume encrypted PKCS #8 not "
+			   "used");
+		return NULL;
+	}
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
+			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
+			   "assume encrypted PKCS #8 not used",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+	enc_alg = hdr.payload;
+	enc_alg_len = hdr.length;
+	pos = hdr.payload + hdr.length;
+
+	/* encryptedData EncryptedData */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
+			   "(encryptedData) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
+			     passwd, &data_len);
+	if (data) {
+		struct crypto_private_key *key;
+		key = pkcs8_key_import(data, data_len);
+		os_free(data);
+		return key;
+	}
+
+	return NULL;
+}

Deleted: vendor/wpa/2.0/src/tls/pkcs8.h
===================================================================
--- vendor/wpa/dist/src/tls/pkcs8.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/pkcs8.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,22 +0,0 @@
-/*
- * PKCS #8 (Private-key information syntax)
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PKCS8_H
-#define PKCS8_H
-
-struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len);
-struct crypto_private_key *
-pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd);
-
-#endif /* PKCS8_H */

Copied: vendor/wpa/2.0/src/tls/pkcs8.h (from rev 9639, vendor/wpa/dist/src/tls/pkcs8.h)
===================================================================
--- vendor/wpa/2.0/src/tls/pkcs8.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/pkcs8.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+/*
+ * PKCS #8 (Private-key information syntax)
+ * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PKCS8_H
+#define PKCS8_H
+
+struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len);
+struct crypto_private_key *
+pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd);
+
+#endif /* PKCS8_H */

Deleted: vendor/wpa/2.0/src/tls/rsa.c
===================================================================
--- vendor/wpa/dist/src/tls/rsa.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/rsa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,358 +0,0 @@
-/*
- * RSA
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "asn1.h"
-#include "bignum.h"
-#include "rsa.h"
-
-
-struct crypto_rsa_key {
-	int private_key; /* whether private key is set */
-	struct bignum *n; /* modulus (p * q) */
-	struct bignum *e; /* public exponent */
-	/* The following parameters are available only if private_key is set */
-	struct bignum *d; /* private exponent */
-	struct bignum *p; /* prime p (factor of n) */
-	struct bignum *q; /* prime q (factor of n) */
-	struct bignum *dmp1; /* d mod (p - 1); CRT exponent */
-	struct bignum *dmq1; /* d mod (q - 1); CRT exponent */
-	struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */
-};
-
-
-static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
-					   struct bignum *num)
-{
-	struct asn1_hdr hdr;
-
-	if (pos == NULL)
-		return NULL;
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
-			   "tag 0x%x", hdr.class, hdr.tag);
-		return NULL;
-	}
-
-	if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) {
-		wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER");
-		return NULL;
-	}
-
-	return hdr.payload + hdr.length;
-}
-
-
-/**
- * crypto_rsa_import_public_key - Import an RSA public key
- * @buf: Key buffer (DER encoded RSA public key)
- * @len: Key buffer length in bytes
- * Returns: Pointer to the public key or %NULL on failure
- */
-struct crypto_rsa_key *
-crypto_rsa_import_public_key(const u8 *buf, size_t len)
-{
-	struct crypto_rsa_key *key;
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-
-	key = os_zalloc(sizeof(*key));
-	if (key == NULL)
-		return NULL;
-
-	key->n = bignum_init();
-	key->e = bignum_init();
-	if (key->n == NULL || key->e == NULL) {
-		crypto_rsa_free(key);
-		return NULL;
-	}
-
-	/*
-	 * PKCS #1, 7.1:
-	 * RSAPublicKey ::= SEQUENCE {
-	 *     modulus INTEGER, -- n
-	 *     publicExponent INTEGER -- e 
-	 * }
-	 */
-
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
-			   "(public key) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		goto error;
-	}
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	pos = crypto_rsa_parse_integer(pos, end, key->n);
-	pos = crypto_rsa_parse_integer(pos, end, key->e);
-
-	if (pos == NULL)
-		goto error;
-
-	if (pos != end) {
-		wpa_hexdump(MSG_DEBUG,
-			    "RSA: Extra data in public key SEQUENCE",
-			    pos, end - pos);
-		goto error;
-	}
-
-	return key;
-
-error:
-	crypto_rsa_free(key);
-	return NULL;
-}
-
-
-/**
- * crypto_rsa_import_private_key - Import an RSA private key
- * @buf: Key buffer (DER encoded RSA private key)
- * @len: Key buffer length in bytes
- * Returns: Pointer to the private key or %NULL on failure
- */
-struct crypto_rsa_key *
-crypto_rsa_import_private_key(const u8 *buf, size_t len)
-{
-	struct crypto_rsa_key *key;
-	struct bignum *zero;
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-
-	key = os_zalloc(sizeof(*key));
-	if (key == NULL)
-		return NULL;
-
-	key->private_key = 1;
-
-	key->n = bignum_init();
-	key->e = bignum_init();
-	key->d = bignum_init();
-	key->p = bignum_init();
-	key->q = bignum_init();
-	key->dmp1 = bignum_init();
-	key->dmq1 = bignum_init();
-	key->iqmp = bignum_init();
-
-	if (key->n == NULL || key->e == NULL || key->d == NULL ||
-	    key->p == NULL || key->q == NULL || key->dmp1 == NULL ||
-	    key->dmq1 == NULL || key->iqmp == NULL) {
-		crypto_rsa_free(key);
-		return NULL;
-	}
-
-	/*
-	 * PKCS #1, 7.2:
-	 * RSAPrivateKey ::= SEQUENCE {
-	 *    version Version,
-	 *    modulus INTEGER, -- n
-	 *    publicExponent INTEGER, -- e
-	 *    privateExponent INTEGER, -- d
-	 *    prime1 INTEGER, -- p
-	 *    prime2 INTEGER, -- q
-	 *    exponent1 INTEGER, -- d mod (p-1)
-	 *    exponent2 INTEGER, -- d mod (q-1)
-	 *    coefficient INTEGER -- (inverse of q) mod p
-	 * }
-	 *
-	 * Version ::= INTEGER -- shall be 0 for this version of the standard
-	 */
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
-			   "(public key) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		goto error;
-	}
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	zero = bignum_init();
-	if (zero == NULL)
-		goto error;
-	pos = crypto_rsa_parse_integer(pos, end, zero);
-	if (pos == NULL || bignum_cmp_d(zero, 0) != 0) {
-		wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the "
-			   "beginning of private key; not found");
-		bignum_deinit(zero);
-		goto error;
-	}
-	bignum_deinit(zero);
-
-	pos = crypto_rsa_parse_integer(pos, end, key->n);
-	pos = crypto_rsa_parse_integer(pos, end, key->e);
-	pos = crypto_rsa_parse_integer(pos, end, key->d);
-	pos = crypto_rsa_parse_integer(pos, end, key->p);
-	pos = crypto_rsa_parse_integer(pos, end, key->q);
-	pos = crypto_rsa_parse_integer(pos, end, key->dmp1);
-	pos = crypto_rsa_parse_integer(pos, end, key->dmq1);
-	pos = crypto_rsa_parse_integer(pos, end, key->iqmp);
-
-	if (pos == NULL)
-		goto error;
-
-	if (pos != end) {
-		wpa_hexdump(MSG_DEBUG,
-			    "RSA: Extra data in public key SEQUENCE",
-			    pos, end - pos);
-		goto error;
-	}
-
-	return key;
-
-error:
-	crypto_rsa_free(key);
-	return NULL;
-}
-
-
-/**
- * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key
- * @key: RSA key
- * Returns: Modulus length of the key
- */
-size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)
-{
-	return bignum_get_unsigned_bin_len(key->n);
-}
-
-
-/**
- * crypto_rsa_exptmod - RSA modular exponentiation
- * @in: Input data
- * @inlen: Input data length
- * @out: Buffer for output data
- * @outlen: Maximum size of the output buffer and used size on success
- * @key: RSA key
- * @use_private: 1 = Use RSA private key, 0 = Use RSA public key
- * Returns: 0 on success, -1 on failure
- */
-int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
-		       struct crypto_rsa_key *key, int use_private)
-{
-	struct bignum *tmp, *a = NULL, *b = NULL;
-	int ret = -1;
-	size_t modlen;
-
-	if (use_private && !key->private_key)
-		return -1;
-
-	tmp = bignum_init();
-	if (tmp == NULL)
-		return -1;
-
-	if (bignum_set_unsigned_bin(tmp, in, inlen) < 0)
-		goto error;
-	if (bignum_cmp(key->n, tmp) < 0) {
-		/* Too large input value for the RSA key modulus */
-		goto error;
-	}
-
-	if (use_private) {
-		/*
-		 * Decrypt (or sign) using Chinese remainer theorem to speed
-		 * up calculation. This is equivalent to tmp = tmp^d mod n
-		 * (which would require more CPU to calculate directly).
-		 *
-		 * dmp1 = (1/e) mod (p-1)
-		 * dmq1 = (1/e) mod (q-1)
-		 * iqmp = (1/q) mod p, where p > q
-		 * m1 = c^dmp1 mod p
-		 * m2 = c^dmq1 mod q
-		 * h = q^-1 (m1 - m2) mod p
-		 * m = m2 + hq
-		 */
-		a = bignum_init();
-		b = bignum_init();
-		if (a == NULL || b == NULL)
-			goto error;
-
-		/* a = tmp^dmp1 mod p */
-		if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0)
-			goto error;
-
-		/* b = tmp^dmq1 mod q */
-		if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0)
-			goto error;
-
-		/* tmp = (a - b) * (1/q mod p) (mod p) */
-		if (bignum_sub(a, b, tmp) < 0 ||
-		    bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0)
-			goto error;
-
-		/* tmp = b + q * tmp */
-		if (bignum_mul(tmp, key->q, tmp) < 0 ||
-		    bignum_add(tmp, b, tmp) < 0)
-			goto error;
-	} else {
-		/* Encrypt (or verify signature) */
-		/* tmp = tmp^e mod N */
-		if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0)
-			goto error;
-	}
-
-	modlen = crypto_rsa_get_modulus_len(key);
-	if (modlen > *outlen) {
-		*outlen = modlen;
-		goto error;
-	}
-
-	if (bignum_get_unsigned_bin_len(tmp) > modlen)
-		goto error; /* should never happen */
-
-	*outlen = modlen;
-	os_memset(out, 0, modlen);
-	if (bignum_get_unsigned_bin(
-		    tmp, out +
-		    (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0)
-		goto error;
-
-	ret = 0;
-
-error:
-	bignum_deinit(tmp);
-	bignum_deinit(a);
-	bignum_deinit(b);
-	return ret;
-}
-
-
-/**
- * crypto_rsa_free - Free RSA key
- * @key: RSA key to be freed
- *
- * This function frees an RSA key imported with either
- * crypto_rsa_import_public_key() or crypto_rsa_import_private_key().
- */
-void crypto_rsa_free(struct crypto_rsa_key *key)
-{
-	if (key) {
-		bignum_deinit(key->n);
-		bignum_deinit(key->e);
-		bignum_deinit(key->d);
-		bignum_deinit(key->p);
-		bignum_deinit(key->q);
-		bignum_deinit(key->dmp1);
-		bignum_deinit(key->dmq1);
-		bignum_deinit(key->iqmp);
-		os_free(key);
-	}
-}

Copied: vendor/wpa/2.0/src/tls/rsa.c (from rev 9639, vendor/wpa/dist/src/tls/rsa.c)
===================================================================
--- vendor/wpa/2.0/src/tls/rsa.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/rsa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,352 @@
+/*
+ * RSA
+ * Copyright (c) 2006, Jouni Malinen <j at 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 "asn1.h"
+#include "bignum.h"
+#include "rsa.h"
+
+
+struct crypto_rsa_key {
+	int private_key; /* whether private key is set */
+	struct bignum *n; /* modulus (p * q) */
+	struct bignum *e; /* public exponent */
+	/* The following parameters are available only if private_key is set */
+	struct bignum *d; /* private exponent */
+	struct bignum *p; /* prime p (factor of n) */
+	struct bignum *q; /* prime q (factor of n) */
+	struct bignum *dmp1; /* d mod (p - 1); CRT exponent */
+	struct bignum *dmq1; /* d mod (q - 1); CRT exponent */
+	struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */
+};
+
+
+static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
+					   struct bignum *num)
+{
+	struct asn1_hdr hdr;
+
+	if (pos == NULL)
+		return NULL;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
+			   "tag 0x%x", hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) {
+		wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER");
+		return NULL;
+	}
+
+	return hdr.payload + hdr.length;
+}
+
+
+/**
+ * crypto_rsa_import_public_key - Import an RSA public key
+ * @buf: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ */
+struct crypto_rsa_key *
+crypto_rsa_import_public_key(const u8 *buf, size_t len)
+{
+	struct crypto_rsa_key *key;
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	key = os_zalloc(sizeof(*key));
+	if (key == NULL)
+		return NULL;
+
+	key->n = bignum_init();
+	key->e = bignum_init();
+	if (key->n == NULL || key->e == NULL) {
+		crypto_rsa_free(key);
+		return NULL;
+	}
+
+	/*
+	 * PKCS #1, 7.1:
+	 * RSAPublicKey ::= SEQUENCE {
+	 *     modulus INTEGER, -- n
+	 *     publicExponent INTEGER -- e 
+	 * }
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
+			   "(public key) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto error;
+	}
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	pos = crypto_rsa_parse_integer(pos, end, key->n);
+	pos = crypto_rsa_parse_integer(pos, end, key->e);
+
+	if (pos == NULL)
+		goto error;
+
+	if (pos != end) {
+		wpa_hexdump(MSG_DEBUG,
+			    "RSA: Extra data in public key SEQUENCE",
+			    pos, end - pos);
+		goto error;
+	}
+
+	return key;
+
+error:
+	crypto_rsa_free(key);
+	return NULL;
+}
+
+
+/**
+ * crypto_rsa_import_private_key - Import an RSA private key
+ * @buf: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the private key or %NULL on failure
+ */
+struct crypto_rsa_key *
+crypto_rsa_import_private_key(const u8 *buf, size_t len)
+{
+	struct crypto_rsa_key *key;
+	struct bignum *zero;
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	key = os_zalloc(sizeof(*key));
+	if (key == NULL)
+		return NULL;
+
+	key->private_key = 1;
+
+	key->n = bignum_init();
+	key->e = bignum_init();
+	key->d = bignum_init();
+	key->p = bignum_init();
+	key->q = bignum_init();
+	key->dmp1 = bignum_init();
+	key->dmq1 = bignum_init();
+	key->iqmp = bignum_init();
+
+	if (key->n == NULL || key->e == NULL || key->d == NULL ||
+	    key->p == NULL || key->q == NULL || key->dmp1 == NULL ||
+	    key->dmq1 == NULL || key->iqmp == NULL) {
+		crypto_rsa_free(key);
+		return NULL;
+	}
+
+	/*
+	 * PKCS #1, 7.2:
+	 * RSAPrivateKey ::= SEQUENCE {
+	 *    version Version,
+	 *    modulus INTEGER, -- n
+	 *    publicExponent INTEGER, -- e
+	 *    privateExponent INTEGER, -- d
+	 *    prime1 INTEGER, -- p
+	 *    prime2 INTEGER, -- q
+	 *    exponent1 INTEGER, -- d mod (p-1)
+	 *    exponent2 INTEGER, -- d mod (q-1)
+	 *    coefficient INTEGER -- (inverse of q) mod p
+	 * }
+	 *
+	 * Version ::= INTEGER -- shall be 0 for this version of the standard
+	 */
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
+			   "(public key) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		goto error;
+	}
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	zero = bignum_init();
+	if (zero == NULL)
+		goto error;
+	pos = crypto_rsa_parse_integer(pos, end, zero);
+	if (pos == NULL || bignum_cmp_d(zero, 0) != 0) {
+		wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the "
+			   "beginning of private key; not found");
+		bignum_deinit(zero);
+		goto error;
+	}
+	bignum_deinit(zero);
+
+	pos = crypto_rsa_parse_integer(pos, end, key->n);
+	pos = crypto_rsa_parse_integer(pos, end, key->e);
+	pos = crypto_rsa_parse_integer(pos, end, key->d);
+	pos = crypto_rsa_parse_integer(pos, end, key->p);
+	pos = crypto_rsa_parse_integer(pos, end, key->q);
+	pos = crypto_rsa_parse_integer(pos, end, key->dmp1);
+	pos = crypto_rsa_parse_integer(pos, end, key->dmq1);
+	pos = crypto_rsa_parse_integer(pos, end, key->iqmp);
+
+	if (pos == NULL)
+		goto error;
+
+	if (pos != end) {
+		wpa_hexdump(MSG_DEBUG,
+			    "RSA: Extra data in public key SEQUENCE",
+			    pos, end - pos);
+		goto error;
+	}
+
+	return key;
+
+error:
+	crypto_rsa_free(key);
+	return NULL;
+}
+
+
+/**
+ * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key
+ * @key: RSA key
+ * Returns: Modulus length of the key
+ */
+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)
+{
+	return bignum_get_unsigned_bin_len(key->n);
+}
+
+
+/**
+ * crypto_rsa_exptmod - RSA modular exponentiation
+ * @in: Input data
+ * @inlen: Input data length
+ * @out: Buffer for output data
+ * @outlen: Maximum size of the output buffer and used size on success
+ * @key: RSA key
+ * @use_private: 1 = Use RSA private key, 0 = Use RSA public key
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		       struct crypto_rsa_key *key, int use_private)
+{
+	struct bignum *tmp, *a = NULL, *b = NULL;
+	int ret = -1;
+	size_t modlen;
+
+	if (use_private && !key->private_key)
+		return -1;
+
+	tmp = bignum_init();
+	if (tmp == NULL)
+		return -1;
+
+	if (bignum_set_unsigned_bin(tmp, in, inlen) < 0)
+		goto error;
+	if (bignum_cmp(key->n, tmp) < 0) {
+		/* Too large input value for the RSA key modulus */
+		goto error;
+	}
+
+	if (use_private) {
+		/*
+		 * Decrypt (or sign) using Chinese remainer theorem to speed
+		 * up calculation. This is equivalent to tmp = tmp^d mod n
+		 * (which would require more CPU to calculate directly).
+		 *
+		 * dmp1 = (1/e) mod (p-1)
+		 * dmq1 = (1/e) mod (q-1)
+		 * iqmp = (1/q) mod p, where p > q
+		 * m1 = c^dmp1 mod p
+		 * m2 = c^dmq1 mod q
+		 * h = q^-1 (m1 - m2) mod p
+		 * m = m2 + hq
+		 */
+		a = bignum_init();
+		b = bignum_init();
+		if (a == NULL || b == NULL)
+			goto error;
+
+		/* a = tmp^dmp1 mod p */
+		if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0)
+			goto error;
+
+		/* b = tmp^dmq1 mod q */
+		if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0)
+			goto error;
+
+		/* tmp = (a - b) * (1/q mod p) (mod p) */
+		if (bignum_sub(a, b, tmp) < 0 ||
+		    bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0)
+			goto error;
+
+		/* tmp = b + q * tmp */
+		if (bignum_mul(tmp, key->q, tmp) < 0 ||
+		    bignum_add(tmp, b, tmp) < 0)
+			goto error;
+	} else {
+		/* Encrypt (or verify signature) */
+		/* tmp = tmp^e mod N */
+		if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0)
+			goto error;
+	}
+
+	modlen = crypto_rsa_get_modulus_len(key);
+	if (modlen > *outlen) {
+		*outlen = modlen;
+		goto error;
+	}
+
+	if (bignum_get_unsigned_bin_len(tmp) > modlen)
+		goto error; /* should never happen */
+
+	*outlen = modlen;
+	os_memset(out, 0, modlen);
+	if (bignum_get_unsigned_bin(
+		    tmp, out +
+		    (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0)
+		goto error;
+
+	ret = 0;
+
+error:
+	bignum_deinit(tmp);
+	bignum_deinit(a);
+	bignum_deinit(b);
+	return ret;
+}
+
+
+/**
+ * crypto_rsa_free - Free RSA key
+ * @key: RSA key to be freed
+ *
+ * This function frees an RSA key imported with either
+ * crypto_rsa_import_public_key() or crypto_rsa_import_private_key().
+ */
+void crypto_rsa_free(struct crypto_rsa_key *key)
+{
+	if (key) {
+		bignum_deinit(key->n);
+		bignum_deinit(key->e);
+		bignum_deinit(key->d);
+		bignum_deinit(key->p);
+		bignum_deinit(key->q);
+		bignum_deinit(key->dmp1);
+		bignum_deinit(key->dmq1);
+		bignum_deinit(key->iqmp);
+		os_free(key);
+	}
+}

Deleted: vendor/wpa/2.0/src/tls/rsa.h
===================================================================
--- vendor/wpa/dist/src/tls/rsa.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/rsa.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,29 +0,0 @@
-/*
- * RSA
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef RSA_H
-#define RSA_H
-
-struct crypto_rsa_key;
-
-struct crypto_rsa_key *
-crypto_rsa_import_public_key(const u8 *buf, size_t len);
-struct crypto_rsa_key *
-crypto_rsa_import_private_key(const u8 *buf, size_t len);
-size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
-int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
-		       struct crypto_rsa_key *key, int use_private);
-void crypto_rsa_free(struct crypto_rsa_key *key);
-
-#endif /* RSA_H */

Copied: vendor/wpa/2.0/src/tls/rsa.h (from rev 9639, vendor/wpa/dist/src/tls/rsa.h)
===================================================================
--- vendor/wpa/2.0/src/tls/rsa.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/rsa.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * RSA
+ * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RSA_H
+#define RSA_H
+
+struct crypto_rsa_key;
+
+struct crypto_rsa_key *
+crypto_rsa_import_public_key(const u8 *buf, size_t len);
+struct crypto_rsa_key *
+crypto_rsa_import_private_key(const u8 *buf, size_t len);
+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		       struct crypto_rsa_key *key, int use_private);
+void crypto_rsa_free(struct crypto_rsa_key *key);
+
+#endif /* RSA_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_client.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_client.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,667 +0,0 @@
-/*
- * TLSv1 client (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_client.h"
-#include "tlsv1_client_i.h"
-
-/* TODO:
- * Support for a message fragmented across several records (RFC 2246, 6.2.1)
- */
-
-
-void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
-{
-	conn->alert_level = level;
-	conn->alert_description = description;
-}
-
-
-void tlsv1_client_free_dh(struct tlsv1_client *conn)
-{
-	os_free(conn->dh_p);
-	os_free(conn->dh_g);
-	os_free(conn->dh_ys);
-	conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
-}
-
-
-int tls_derive_pre_master_secret(u8 *pre_master_secret)
-{
-	WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
-	if (os_get_random(pre_master_secret + 2,
-			  TLS_PRE_MASTER_SECRET_LEN - 2))
-		return -1;
-	return 0;
-}
-
-
-int tls_derive_keys(struct tlsv1_client *conn,
-		    const u8 *pre_master_secret, size_t pre_master_secret_len)
-{
-	u8 seed[2 * TLS_RANDOM_LEN];
-	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
-	u8 *pos;
-	size_t key_block_len;
-
-	if (pre_master_secret) {
-		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
-				pre_master_secret, pre_master_secret_len);
-		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
-			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
-			    "master secret", seed, 2 * TLS_RANDOM_LEN,
-			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
-				   "master_secret");
-			return -1;
-		}
-		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
-				conn->master_secret, TLS_MASTER_SECRET_LEN);
-	}
-
-	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
-	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
-	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
-		    key_block, key_block_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
-		return -1;
-	}
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
-			key_block, key_block_len);
-
-	pos = key_block;
-
-	/* client_write_MAC_secret */
-	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
-	pos += conn->rl.hash_size;
-	/* server_write_MAC_secret */
-	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
-	pos += conn->rl.hash_size;
-
-	/* client_write_key */
-	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
-	pos += conn->rl.key_material_len;
-	/* server_write_key */
-	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
-	pos += conn->rl.key_material_len;
-
-	/* client_write_IV */
-	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-	/* server_write_IV */
-	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_handshake - Process TLS handshake
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @in_data: Input data from TLS peer
- * @in_len: Input data length
- * @out_len: Length of the output buffer.
- * @appl_data: Pointer to application data pointer, or %NULL if dropped
- * @appl_data_len: Pointer to variable that is set to appl_data length
- * Returns: Pointer to output data, %NULL on failure
- */
-u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
-			    const u8 *in_data, size_t in_len,
-			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len)
-{
-	const u8 *pos, *end;
-	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
-	size_t in_msg_len;
-	int no_appl_data;
-
-	if (conn->state == CLIENT_HELLO) {
-		if (in_len)
-			return NULL;
-		return tls_send_client_hello(conn, out_len);
-	}
-
-	if (in_data == NULL || in_len == 0)
-		return NULL;
-
-	pos = in_data;
-	end = in_data + in_len;
-	in_msg = os_malloc(in_len);
-	if (in_msg == NULL)
-		return NULL;
-
-	/* Each received packet may include multiple records */
-	while (pos < end) {
-		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
-				   "record failed");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			goto failed;
-		}
-		ct = pos[0];
-
-		in_pos = in_msg;
-		in_end = in_msg + in_msg_len;
-
-		/* Each received record may include multiple messages of the
-		 * same ContentType. */
-		while (in_pos < in_end) {
-			in_msg_len = in_end - in_pos;
-			if (tlsv1_client_process_handshake(conn, ct, in_pos,
-							   &in_msg_len,
-							   appl_data,
-							   appl_data_len) < 0)
-				goto failed;
-			in_pos += in_msg_len;
-		}
-
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
-	}
-
-	os_free(in_msg);
-	in_msg = NULL;
-
-	no_appl_data = appl_data == NULL || *appl_data == NULL;
-	msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
-
-failed:
-	os_free(in_msg);
-	if (conn->alert_level) {
-		conn->state = FAILED;
-		os_free(msg);
-		msg = tlsv1_client_send_alert(conn, conn->alert_level,
-					      conn->alert_description,
-					      out_len);
-	} else if (msg == NULL) {
-		msg = os_zalloc(1);
-		*out_len = 0;
-	}
-
-	return msg;
-}
-
-
-/**
- * tlsv1_client_encrypt - Encrypt data into TLS tunnel
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @in_data: Pointer to plaintext data to be encrypted
- * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length 
- * Returns: Number of bytes written to out_data, -1 on failure
- *
- * This function is used after TLS handshake has been completed successfully to
- * send data in the encrypted tunnel.
- */
-int tlsv1_client_encrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
-{
-	size_t rlen;
-
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
-			in_data, in_len);
-
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	return rlen;
-}
-
-
-/**
- * tlsv1_client_decrypt - Decrypt data from TLS tunnel
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @in_data: Pointer to input buffer (encrypted TLS data)
- * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
- *
- * This function is used after TLS handshake has been completed successfully to
- * receive data from the encrypted tunnel.
- */
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
-{
-	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
-	size_t olen;
-
-	pos = in_data;
-	in_end = in_data + in_len;
-	out_pos = out_data;
-	out_end = out_data + out_len;
-
-	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
-		}
-
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
-		}
-		out_pos += olen;
-		if (out_pos > out_end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
-				   "for processing the received record");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			return -1;
-		}
-
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
-	}
-
-	return out_pos - out_data;
-}
-
-
-/**
- * tlsv1_client_global_init - Initialize TLSv1 client
- * Returns: 0 on success, -1 on failure
- *
- * This function must be called before using any other TLSv1 client functions.
- */
-int tlsv1_client_global_init(void)
-{
-	return crypto_global_init();
-}
-
-
-/**
- * tlsv1_client_global_deinit - Deinitialize TLSv1 client
- *
- * This function can be used to deinitialize the TLSv1 client that was
- * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
- * can be called after this before calling tlsv1_client_global_init() again.
- */
-void tlsv1_client_global_deinit(void)
-{
-	crypto_global_deinit();
-}
-
-
-/**
- * tlsv1_client_init - Initialize TLSv1 client connection
- * Returns: Pointer to TLSv1 client connection data or %NULL on failure
- */
-struct tlsv1_client * tlsv1_client_init(void)
-{
-	struct tlsv1_client *conn;
-	size_t count;
-	u16 *suites;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-	conn->state = CLIENT_HELLO;
-
-	if (tls_verify_hash_init(&conn->verify) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
-			   "hash");
-		os_free(conn);
-		return NULL;
-	}
-
-	count = 0;
-	suites = conn->cipher_suites;
-#ifndef CONFIG_CRYPTO_INTERNAL
-	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
-	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
-	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
-	conn->num_cipher_suites = count;
-
-	return conn;
-}
-
-
-/**
- * tlsv1_client_deinit - Deinitialize TLSv1 client connection
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- */
-void tlsv1_client_deinit(struct tlsv1_client *conn)
-{
-	crypto_public_key_free(conn->server_rsa_key);
-	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
-	tlsv1_record_change_write_cipher(&conn->rl);
-	tlsv1_record_change_read_cipher(&conn->rl);
-	tls_verify_hash_free(&conn->verify);
-	os_free(conn->client_hello_ext);
-	tlsv1_client_free_dh(conn);
-	tlsv1_cred_free(conn->cred);
-	os_free(conn);
-}
-
-
-/**
- * tlsv1_client_established - Check whether connection has been established
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * Returns: 1 if connection is established, 0 if not
- */
-int tlsv1_client_established(struct tlsv1_client *conn)
-{
-	return conn->state == ESTABLISHED;
-}
-
-
-/**
- * tlsv1_client_prf - Use TLS-PRF to derive keying material
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @out: Buffer for output data from TLS-PRF
- * @out_len: Length of the output buffer
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
-		     int server_random_first, u8 *out, size_t out_len)
-{
-	u8 seed[2 * TLS_RANDOM_LEN];
-
-	if (conn->state != ESTABLISHED)
-		return -1;
-
-	if (server_random_first) {
-		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
-			  TLS_RANDOM_LEN);
-	} else {
-		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
-			  TLS_RANDOM_LEN);
-	}
-
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
-}
-
-
-/**
- * tlsv1_client_get_cipher - Get current cipher name
- * @conn: TLSv1 client connection data from tlsv1_client_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 tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
-			    size_t buflen)
-{
-	char *cipher;
-
-	switch (conn->rl.cipher_suite) {
-	case TLS_RSA_WITH_RC4_128_MD5:
-		cipher = "RC4-MD5";
-		break;
-	case TLS_RSA_WITH_RC4_128_SHA:
-		cipher = "RC4-SHA";
-		break;
-	case TLS_RSA_WITH_DES_CBC_SHA:
-		cipher = "DES-CBC-SHA";
-		break;
-	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-		cipher = "DES-CBC3-SHA";
-		break;
-	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
-		cipher = "ADH-AES-128-SHA";
-		break;
-	case TLS_RSA_WITH_AES_256_CBC_SHA:
-		cipher = "AES-256-SHA";
-		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
-		break;
-	default:
-		return -1;
-	}
-
-	if (os_strlcpy(buf, cipher, buflen) >= buflen)
-		return -1;
-	return 0;
-}
-
-
-/**
- * tlsv1_client_shutdown - Shutdown TLS connection
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_shutdown(struct tlsv1_client *conn)
-{
-	conn->state = CLIENT_HELLO;
-
-	if (tls_verify_hash_init(&conn->verify) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
-			   "hash");
-		return -1;
-	}
-
-	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
-	tlsv1_record_change_write_cipher(&conn->rl);
-	tlsv1_record_change_read_cipher(&conn->rl);
-
-	conn->certificate_requested = 0;
-	crypto_public_key_free(conn->server_rsa_key);
-	conn->server_rsa_key = NULL;
-	conn->session_resumed = 0;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_resumed - Was session resumption used
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * Returns: 1 if current session used session resumption, 0 if not
- */
-int tlsv1_client_resumed(struct tlsv1_client *conn)
-{
-	return !!conn->session_resumed;
-}
-
-
-/**
- * tlsv1_client_hello_ext - Set TLS extension for ClientHello
- * @conn: TLSv1 client connection data from tlsv1_client_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 tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
-			   const u8 *data, size_t data_len)
-{
-	u8 *pos;
-
-	conn->session_ticket_included = 0;
-	os_free(conn->client_hello_ext);
-	conn->client_hello_ext = NULL;
-	conn->client_hello_ext_len = 0;
-
-	if (data == NULL || data_len == 0)
-		return 0;
-
-	pos = conn->client_hello_ext = os_malloc(6 + 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;
-
-	if (ext_type == TLS_EXT_PAC_OPAQUE) {
-		conn->session_ticket_included = 1;
-		wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_get_keys - Get master key and random data from TLS connection
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @keys: Structure of key/random data (filled on success)
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
-{
-	os_memset(keys, 0, sizeof(*keys));
-	if (conn->state == CLIENT_HELLO)
-		return -1;
-
-	keys->client_random = conn->client_random;
-	keys->client_random_len = TLS_RANDOM_LEN;
-
-	if (conn->state != SERVER_HELLO) {
-		keys->server_random = conn->server_random;
-		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_get_keyblock_size - Get TLS key_block size
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
-{
-	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
-		return -1;
-
-	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-		    conn->rl.iv_size);
-}
-
-
-/**
- * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
- * (TLS_CIPHER_*).
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
-{
-	size_t count;
-	u16 *suites;
-
-	/* TODO: implement proper configuration of cipher suites */
-	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
-		count = 0;
-		suites = conn->cipher_suites;
-#ifndef CONFIG_CRYPTO_INTERNAL
-		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
-		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
-		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
-		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
-		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
-
-		/*
-		 * Cisco AP (at least 350 and 1200 series) local authentication
-		 * server does not know how to search cipher suites from the
-		 * list and seem to require that the last entry in the list is
-		 * the one that it wants to use. However, TLS specification
-		 * requires the list to be in the client preference order. As a
-		 * workaround, add anon-DH AES-128-SHA1 again at the end of the
-		 * list to allow the Cisco code to find it.
-		 */
-		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
-		conn->num_cipher_suites = count;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_set_cred - Set client credentials
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @cred: Credentials from tlsv1_cred_alloc()
- * Returns: 0 on success, -1 on failure
- *
- * On success, the client takes ownership of the credentials block and caller
- * must not free it. On failure, caller is responsible for freeing the
- * credential block.
- */
-int tlsv1_client_set_cred(struct tlsv1_client *conn,
-			  struct tlsv1_credentials *cred)
-{
-	tlsv1_cred_free(conn->cred);
-	conn->cred = cred;
-	return 0;
-}
-
-
-void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
-					tlsv1_client_session_ticket_cb cb,
-					void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
-		   cb, ctx);
-	conn->session_ticket_cb = cb;
-	conn->session_ticket_cb_ctx = ctx;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_client.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_client.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_client.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,794 @@
+/*
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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 "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+/* TODO:
+ * Support for a message fragmented across several records (RFC 2246, 6.2.1)
+ */
+
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
+{
+	conn->alert_level = level;
+	conn->alert_description = description;
+}
+
+
+void tlsv1_client_free_dh(struct tlsv1_client *conn)
+{
+	os_free(conn->dh_p);
+	os_free(conn->dh_g);
+	os_free(conn->dh_ys);
+	conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
+}
+
+
+int tls_derive_pre_master_secret(u8 *pre_master_secret)
+{
+	WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
+	if (os_get_random(pre_master_secret + 2,
+			  TLS_PRE_MASTER_SECRET_LEN - 2))
+		return -1;
+	return 0;
+}
+
+
+int tls_derive_keys(struct tlsv1_client *conn,
+		    const u8 *pre_master_secret, size_t pre_master_secret_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
+	u8 *pos;
+	size_t key_block_len;
+
+	if (pre_master_secret) {
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
+				pre_master_secret, pre_master_secret_len);
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
+			    "master secret", seed, 2 * TLS_RANDOM_LEN,
+			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
+				   "master_secret");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
+				conn->master_secret, TLS_MASTER_SECRET_LEN);
+	}
+
+	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
+	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
+	if (conn->rl.tls_version == TLS_VERSION_1)
+		key_block_len += 2 * conn->rl.iv_size;
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
+		    key_block, key_block_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
+			key_block, key_block_len);
+
+	pos = key_block;
+
+	/* client_write_MAC_secret */
+	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+	/* server_write_MAC_secret */
+	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+
+	/* client_write_key */
+	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+	/* server_write_key */
+	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+
+	if (conn->rl.tls_version == TLS_VERSION_1) {
+		/* client_write_IV */
+		os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+		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
+		 * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+		os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_handshake - Process TLS handshake
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Input data from TLS peer
+ * @in_len: Input data length
+ * @out_len: Length of the output buffer.
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * @appl_data_len: Pointer to variable that is set to appl_data length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
+ * Returns: Pointer to output data, %NULL on failure
+ */
+u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
+			    const u8 *in_data, size_t in_len,
+			    size_t *out_len, u8 **appl_data,
+			    size_t *appl_data_len, int *need_more_data)
+{
+	const u8 *pos, *end;
+	u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
+	size_t in_msg_len;
+	int no_appl_data;
+	int used;
+
+	if (need_more_data)
+		*need_more_data = 0;
+
+	if (conn->state == CLIENT_HELLO) {
+		if (in_len)
+			return NULL;
+		return tls_send_client_hello(conn, out_len);
+	}
+
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			goto failed;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
+
+	if (in_data == NULL || in_len == 0)
+		return NULL;
+
+	pos = in_data;
+	end = in_data + in_len;
+	in_msg = os_malloc(in_len);
+	if (in_msg == NULL)
+		return NULL;
+
+	/* Each received packet may include multiple records */
+	while (pos < end) {
+		in_msg_len = in_len;
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
+				   "record failed");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_INTERNAL_ERROR);
+				goto failed;
+			}
+			os_free(in_msg);
+			if (need_more_data)
+				*need_more_data = 1;
+			return NULL;
+		}
+		ct = pos[0];
+
+		in_pos = in_msg;
+		in_end = in_msg + in_msg_len;
+
+		/* Each received record may include multiple messages of the
+		 * same ContentType. */
+		while (in_pos < in_end) {
+			in_msg_len = in_end - in_pos;
+			if (tlsv1_client_process_handshake(conn, ct, in_pos,
+							   &in_msg_len,
+							   appl_data,
+							   appl_data_len) < 0)
+				goto failed;
+			in_pos += in_msg_len;
+		}
+
+		pos += used;
+	}
+
+	os_free(in_msg);
+	in_msg = NULL;
+
+	no_appl_data = appl_data == NULL || *appl_data == NULL;
+	msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
+
+failed:
+	os_free(in_msg);
+	if (conn->alert_level) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
+		conn->state = FAILED;
+		os_free(msg);
+		msg = tlsv1_client_send_alert(conn, conn->alert_level,
+					      conn->alert_description,
+					      out_len);
+	} else if (msg == NULL) {
+		msg = os_zalloc(1);
+		*out_len = 0;
+	}
+
+	if (need_more_data == NULL || !(*need_more_data)) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
+	}
+
+	return msg;
+}
+
+
+/**
+ * tlsv1_client_encrypt - Encrypt data into TLS tunnel
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Pointer to plaintext data to be encrypted
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (encrypted TLS data)
+ * @out_len: Maximum out_data length 
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel.
+ */
+int tlsv1_client_encrypt(struct tlsv1_client *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len)
+{
+	size_t rlen;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
+			in_data, in_len);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return rlen;
+}
+
+
+/**
+ * tlsv1_client_decrypt - Decrypt data from TLS tunnel
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Pointer to input buffer (encrypted TLS data)
+ * @in_len: Input buffer length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
+ * Returns: Decrypted data or %NULL on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel.
+ */
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data)
+{
+	const u8 *in_end, *pos;
+	int used;
+	u8 alert, *out_pos, ct;
+	size_t olen;
+	struct wpabuf *buf = NULL;
+
+	if (need_more_data)
+		*need_more_data = 0;
+
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
+
+	pos = in_data;
+	in_end = in_data + in_len;
+
+	while (pos < in_end) {
+		ct = pos[0];
+		if (wpabuf_resize(&buf, in_end - pos) < 0) {
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
+		}
+		out_pos = wpabuf_put(buf, 0);
+		olen = wpabuf_tailroom(buf);
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+				   "failed");
+			goto fail;
+		}
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, in_end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				alert = TLS_ALERT_INTERNAL_ERROR;
+				goto fail;
+			}
+			if (need_more_data)
+				*need_more_data = 1;
+			return buf;
+		}
+
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				alert = TLS_ALERT_DECODE_ERROR;
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			alert = out_pos[1];
+			goto fail;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+				   "0x%x when decrypting application data",
+				   pos[0]);
+			alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+			goto fail;
+		}
+
+		wpabuf_put(buf, olen);
+
+		pos += used;
+	}
+
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	return buf;
+
+fail:
+	wpabuf_free(buf);
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+	return NULL;
+}
+
+
+/**
+ * tlsv1_client_global_init - Initialize TLSv1 client
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before using any other TLSv1 client functions.
+ */
+int tlsv1_client_global_init(void)
+{
+	return crypto_global_init();
+}
+
+
+/**
+ * tlsv1_client_global_deinit - Deinitialize TLSv1 client
+ *
+ * This function can be used to deinitialize the TLSv1 client that was
+ * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
+ * can be called after this before calling tlsv1_client_global_init() again.
+ */
+void tlsv1_client_global_deinit(void)
+{
+	crypto_global_deinit();
+}
+
+
+/**
+ * tlsv1_client_init - Initialize TLSv1 client connection
+ * Returns: Pointer to TLSv1 client connection data or %NULL on failure
+ */
+struct tlsv1_client * tlsv1_client_init(void)
+{
+	struct tlsv1_client *conn;
+	size_t count;
+	u16 *suites;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
+			   "hash");
+		os_free(conn);
+		return NULL;
+	}
+
+	count = 0;
+	suites = conn->cipher_suites;
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+	conn->num_cipher_suites = count;
+
+	conn->rl.tls_version = TLS_VERSION;
+
+	return conn;
+}
+
+
+/**
+ * tlsv1_client_deinit - Deinitialize TLSv1 client connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ */
+void tlsv1_client_deinit(struct tlsv1_client *conn)
+{
+	crypto_public_key_free(conn->server_rsa_key);
+	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+	tlsv1_record_change_write_cipher(&conn->rl);
+	tlsv1_record_change_read_cipher(&conn->rl);
+	tls_verify_hash_free(&conn->verify);
+	os_free(conn->client_hello_ext);
+	tlsv1_client_free_dh(conn);
+	tlsv1_cred_free(conn->cred);
+	wpabuf_free(conn->partial_input);
+	os_free(conn);
+}
+
+
+/**
+ * tlsv1_client_established - Check whether connection has been established
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 1 if connection is established, 0 if not
+ */
+int tlsv1_client_established(struct tlsv1_client *conn)
+{
+	return conn->state == ESTABLISHED;
+}
+
+
+/**
+ * tlsv1_client_prf - Use TLS-PRF to derive keying material
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	if (conn->state != ESTABLISHED)
+		return -1;
+
+	if (server_random_first) {
+		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
+			  TLS_RANDOM_LEN);
+	} else {
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+	}
+
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
+		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+}
+
+
+/**
+ * tlsv1_client_get_cipher - Get current cipher name
+ * @conn: TLSv1 client connection data from tlsv1_client_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 tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
+			    size_t buflen)
+{
+	char *cipher;
+
+	switch (conn->rl.cipher_suite) {
+	case TLS_RSA_WITH_RC4_128_MD5:
+		cipher = "RC4-MD5";
+		break;
+	case TLS_RSA_WITH_RC4_128_SHA:
+		cipher = "RC4-SHA";
+		break;
+	case TLS_RSA_WITH_DES_CBC_SHA:
+		cipher = "DES-CBC-SHA";
+		break;
+	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+		cipher = "ADH-AES-128-SHA";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "AES-256-SHA";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "AES-128-SHA256";
+		break;
+	default:
+		return -1;
+	}
+
+	if (os_strlcpy(buf, cipher, buflen) >= buflen)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_shutdown - Shutdown TLS connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_shutdown(struct tlsv1_client *conn)
+{
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
+			   "hash");
+		return -1;
+	}
+
+	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+	tlsv1_record_change_write_cipher(&conn->rl);
+	tlsv1_record_change_read_cipher(&conn->rl);
+
+	conn->certificate_requested = 0;
+	crypto_public_key_free(conn->server_rsa_key);
+	conn->server_rsa_key = NULL;
+	conn->session_resumed = 0;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_resumed - Was session resumption used
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tlsv1_client_resumed(struct tlsv1_client *conn)
+{
+	return !!conn->session_resumed;
+}
+
+
+/**
+ * tlsv1_client_hello_ext - Set TLS extension for ClientHello
+ * @conn: TLSv1 client connection data from tlsv1_client_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 tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
+			   const u8 *data, size_t data_len)
+{
+	u8 *pos;
+
+	conn->session_ticket_included = 0;
+	os_free(conn->client_hello_ext);
+	conn->client_hello_ext = NULL;
+	conn->client_hello_ext_len = 0;
+
+	if (data == NULL || data_len == 0)
+		return 0;
+
+	pos = conn->client_hello_ext = os_malloc(6 + 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;
+
+	if (ext_type == TLS_EXT_PAC_OPAQUE) {
+		conn->session_ticket_included = 1;
+		wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_get_keys - Get master key and random data from TLS connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
+{
+	os_memset(keys, 0, sizeof(*keys));
+	if (conn->state == CLIENT_HELLO)
+		return -1;
+
+	keys->client_random = conn->client_random;
+	keys->client_random_len = TLS_RANDOM_LEN;
+
+	if (conn->state != SERVER_HELLO) {
+		keys->server_random = conn->server_random;
+		keys->server_random_len = TLS_RANDOM_LEN;
+		keys->master_key = conn->master_secret;
+		keys->master_key_len = TLS_MASTER_SECRET_LEN;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_get_keyblock_size - Get TLS key_block size
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
+{
+	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
+		return -1;
+
+	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+		    conn->rl.iv_size);
+}
+
+
+/**
+ * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
+{
+	size_t count;
+	u16 *suites;
+
+	/* TODO: implement proper configuration of cipher suites */
+	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
+		count = 0;
+		suites = conn->cipher_suites;
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
+		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+
+		/*
+		 * Cisco AP (at least 350 and 1200 series) local authentication
+		 * server does not know how to search cipher suites from the
+		 * list and seem to require that the last entry in the list is
+		 * the one that it wants to use. However, TLS specification
+		 * requires the list to be in the client preference order. As a
+		 * workaround, add anon-DH AES-128-SHA1 again at the end of the
+		 * list to allow the Cisco code to find it.
+		 */
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+		conn->num_cipher_suites = count;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_client_set_cred - Set client credentials
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @cred: Credentials from tlsv1_cred_alloc()
+ * Returns: 0 on success, -1 on failure
+ *
+ * On success, the client takes ownership of the credentials block and caller
+ * must not free it. On failure, caller is responsible for freeing the
+ * credential block.
+ */
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+			  struct tlsv1_credentials *cred)
+{
+	tlsv1_cred_free(conn->cred);
+	conn->cred = cred;
+	return 0;
+}
+
+
+void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
+{
+	conn->disable_time_checks = !enabled;
+}
+
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+					tlsv1_client_session_ticket_cb cb,
+					void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+		   cb, ctx);
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_client.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_client.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,59 +0,0 @@
-/*
- * TLSv1 client (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_CLIENT_H
-#define TLSV1_CLIENT_H
-
-#include "tlsv1_cred.h"
-
-struct tlsv1_client;
-
-int tlsv1_client_global_init(void);
-void tlsv1_client_global_deinit(void);
-struct tlsv1_client * tlsv1_client_init(void);
-void tlsv1_client_deinit(struct tlsv1_client *conn);
-int tlsv1_client_established(struct tlsv1_client *conn);
-int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
-		     int server_random_first, u8 *out, size_t out_len);
-u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
-			    const u8 *in_data, size_t in_len,
-			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len);
-int tlsv1_client_encrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
-int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
-			    size_t buflen);
-int tlsv1_client_shutdown(struct tlsv1_client *conn);
-int tlsv1_client_resumed(struct tlsv1_client *conn);
-int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
-			   const u8 *data, size_t data_len);
-int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
-int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
-int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
-int tlsv1_client_set_cred(struct tlsv1_client *conn,
-			  struct tlsv1_credentials *cred);
-
-typedef int (*tlsv1_client_session_ticket_cb)
-(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
- const u8 *server_random, u8 *master_secret);
-
-void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
-					tlsv1_client_session_ticket_cb cb,
-					void *ctx);
-
-#endif /* TLSV1_CLIENT_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_client.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_client.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_client.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,54 @@
+/*
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_CLIENT_H
+#define TLSV1_CLIENT_H
+
+#include "tlsv1_cred.h"
+
+struct tlsv1_client;
+
+int tlsv1_client_global_init(void);
+void tlsv1_client_global_deinit(void);
+struct tlsv1_client * tlsv1_client_init(void);
+void tlsv1_client_deinit(struct tlsv1_client *conn);
+int tlsv1_client_established(struct tlsv1_client *conn);
+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len);
+u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
+			    const u8 *in_data, size_t in_len,
+			    size_t *out_len, u8 **appl_data,
+			    size_t *appl_data_len, int *need_more_data);
+int tlsv1_client_encrypt(struct tlsv1_client *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len);
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data);
+int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
+			    size_t buflen);
+int tlsv1_client_shutdown(struct tlsv1_client *conn);
+int tlsv1_client_resumed(struct tlsv1_client *conn);
+int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
+			   const u8 *data, size_t data_len);
+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+			  struct tlsv1_credentials *cred);
+void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled);
+
+typedef int (*tlsv1_client_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+					tlsv1_client_session_ticket_cb cb,
+					void *ctx);
+
+#endif /* TLSV1_CLIENT_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_client_i.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_client_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,87 +0,0 @@
-/*
- * TLSv1 client - internal structures
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_CLIENT_I_H
-#define TLSV1_CLIENT_I_H
-
-struct tlsv1_client {
-	enum {
-		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
-		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
-		SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
-		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
-		ESTABLISHED, FAILED
-	} state;
-
-	struct tlsv1_record_layer rl;
-
-	u8 session_id[TLS_SESSION_ID_MAX_LEN];
-	size_t session_id_len;
-	u8 client_random[TLS_RANDOM_LEN];
-	u8 server_random[TLS_RANDOM_LEN];
-	u8 master_secret[TLS_MASTER_SECRET_LEN];
-
-	u8 alert_level;
-	u8 alert_description;
-
-	unsigned int certificate_requested:1;
-	unsigned int session_resumed:1;
-	unsigned int session_ticket_included:1;
-	unsigned int use_session_ticket:1;
-
-	struct crypto_public_key *server_rsa_key;
-
-	struct tls_verify_hash verify;
-
-#define MAX_CIPHER_COUNT 30
-	u16 cipher_suites[MAX_CIPHER_COUNT];
-	size_t num_cipher_suites;
-
-	u16 prev_cipher_suite;
-
-	u8 *client_hello_ext;
-	size_t client_hello_ext_len;
-
-	/* The prime modulus used for Diffie-Hellman */
-	u8 *dh_p;
-	size_t dh_p_len;
-	/* The generator used for Diffie-Hellman */
-	u8 *dh_g;
-	size_t dh_g_len;
-	/* The server's Diffie-Hellman public value */
-	u8 *dh_ys;
-	size_t dh_ys_len;
-
-	struct tlsv1_credentials *cred;
-
-	tlsv1_client_session_ticket_cb session_ticket_cb;
-	void *session_ticket_cb_ctx;
-};
-
-
-void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
-void tlsv1_client_free_dh(struct tlsv1_client *conn);
-int tls_derive_pre_master_secret(u8 *pre_master_secret);
-int tls_derive_keys(struct tlsv1_client *conn,
-		    const u8 *pre_master_secret, size_t pre_master_secret_len);
-u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
-u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
-			     u8 description, size_t *out_len);
-u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
-				  int no_appl_data);
-int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
-				   const u8 *buf, size_t *len,
-				   u8 **out_data, size_t *out_len);
-
-#endif /* TLSV1_CLIENT_I_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_client_i.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_client_i.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_client_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,84 @@
+/*
+ * TLSv1 client - internal structures
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_CLIENT_I_H
+#define TLSV1_CLIENT_I_H
+
+struct tlsv1_client {
+	enum {
+		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+		SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
+		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
+		ESTABLISHED, FAILED
+	} state;
+
+	struct tlsv1_record_layer rl;
+
+	u8 session_id[TLS_SESSION_ID_MAX_LEN];
+	size_t session_id_len;
+	u8 client_random[TLS_RANDOM_LEN];
+	u8 server_random[TLS_RANDOM_LEN];
+	u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+	u8 alert_level;
+	u8 alert_description;
+
+	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;
+
+	struct crypto_public_key *server_rsa_key;
+
+	struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+	u16 cipher_suites[MAX_CIPHER_COUNT];
+	size_t num_cipher_suites;
+
+	u16 prev_cipher_suite;
+
+	u8 *client_hello_ext;
+	size_t client_hello_ext_len;
+
+	/* The prime modulus used for Diffie-Hellman */
+	u8 *dh_p;
+	size_t dh_p_len;
+	/* The generator used for Diffie-Hellman */
+	u8 *dh_g;
+	size_t dh_g_len;
+	/* The server's Diffie-Hellman public value */
+	u8 *dh_ys;
+	size_t dh_ys_len;
+
+	struct tlsv1_credentials *cred;
+
+	tlsv1_client_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	struct wpabuf *partial_input;
+};
+
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
+void tlsv1_client_free_dh(struct tlsv1_client *conn);
+int tls_derive_pre_master_secret(u8 *pre_master_secret);
+int tls_derive_keys(struct tlsv1_client *conn,
+		    const u8 *pre_master_secret, size_t pre_master_secret_len);
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+			     u8 description, size_t *out_len);
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+				  int no_appl_data);
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+				   const u8 *buf, size_t *len,
+				   u8 **out_data, size_t *out_len);
+
+#endif /* TLSV1_CLIENT_I_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_client_read.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_client_read.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_read.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,976 +0,0 @@
-/*
- * TLSv1 client - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "x509v3.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_client.h"
-#include "tlsv1_client_i.h"
-
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len);
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len);
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
-					 const u8 *in_data, size_t *in_len);
-
-
-static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
-				    const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, i;
-	u16 cipher_suite;
-
-	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)
-		goto decode_error;
-
-	/* HandshakeType msg_type */
-	if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ServerHello)", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
-	pos++;
-	/* uint24 length */
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left)
-		goto decode_error;
-
-	/* body - ServerHello */
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
-	end = pos + len;
-
-	/* ProtocolVersion server_version */
-	if (end - pos < 2)
-		goto decode_error;
-	if (WPA_GET_BE16(pos) != TLS_VERSION) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ServerHello");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_PROTOCOL_VERSION);
-		return -1;
-	}
-	pos += 2;
-
-	/* Random random */
-	if (end - pos < TLS_RANDOM_LEN)
-		goto decode_error;
-
-	os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
-	pos += TLS_RANDOM_LEN;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
-		    conn->server_random, TLS_RANDOM_LEN);
-
-	/* SessionID session_id */
-	if (end - pos < 1)
-		goto decode_error;
-	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
-		goto decode_error;
-	if (conn->session_id_len && conn->session_id_len == *pos &&
-	    os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
-		pos += 1 + conn->session_id_len;
-		wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
-		conn->session_resumed = 1;
-	} else {
-		conn->session_id_len = *pos;
-		pos++;
-		os_memcpy(conn->session_id, pos, conn->session_id_len);
-		pos += conn->session_id_len;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
-		    conn->session_id, conn->session_id_len);
-
-	/* CipherSuite cipher_suite */
-	if (end - pos < 2)
-		goto decode_error;
-	cipher_suite = WPA_GET_BE16(pos);
-	pos += 2;
-	for (i = 0; i < conn->num_cipher_suites; i++) {
-		if (cipher_suite == conn->cipher_suites[i])
-			break;
-	}
-	if (i == conn->num_cipher_suites) {
-		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
-			   "cipher suite 0x%04x", cipher_suite);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
-			   "cipher suite for a resumed connection (0x%04x != "
-			   "0x%04x)", cipher_suite, conn->prev_cipher_suite);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
-			   "record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	conn->prev_cipher_suite = cipher_suite;
-
-	/* CompressionMethod compression_method */
-	if (end - pos < 1)
-		goto decode_error;
-	if (*pos != TLS_COMPRESSION_NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
-			   "compression 0x%02x", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-	pos++;
-
-	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;
-	}
-
-	if (conn->session_ticket_included && conn->session_ticket_cb) {
-		/* TODO: include SessionTicket extension if one was included in
-		 * ServerHello */
-		int res = conn->session_ticket_cb(
-			conn->session_ticket_cb_ctx, NULL, 0,
-			conn->client_random, conn->server_random,
-			conn->master_secret);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
-				   "indicated failure");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_HANDSHAKE_FAILURE);
-			return -1;
-		}
-		conn->use_session_ticket = !!res;
-	}
-
-	if ((conn->session_resumed || conn->use_session_ticket) &&
-	    tls_derive_keys(conn, NULL, 0)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*in_len = end - in_data;
-
-	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
-		SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
-
-	return 0;
-
-decode_error:
-	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
-	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-	return -1;
-}
-
-
-static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
-				   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, list_len, cert_len, idx;
-	u8 type;
-	struct x509_certificate *chain = NULL, *last = NULL, *cert;
-	int reason;
-
-	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 Certificate message "
-			   "(len=%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: Unexpected Certificate message "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
-		return tls_process_server_key_exchange(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_HELLO_DONE)
-		return tls_process_server_hello_done(conn, ct, in_data,
-						     in_len);
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected Certificate/"
-			   "ServerKeyExchange/CertificateRequest/"
-			   "ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG,
-		   "TLSv1: Received Certificate (certificate_list len %lu)",
-		   (unsigned long) len);
-
-	/*
-	 * opaque ASN.1Cert<2^24-1>;
-	 *
-	 * struct {
-	 *     ASN.1Cert certificate_list<1..2^24-1>;
-	 * } Certificate;
-	 */
-
-	end = pos + len;
-
-	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
-			   "(left=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	list_len = WPA_GET_BE24(pos);
-	pos += 3;
-
-	if ((size_t) (end - pos) != list_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
-			   "length (len=%lu left=%lu)",
-			   (unsigned long) list_len,
-			   (unsigned long) (end - pos));
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	idx = 0;
-	while (pos < end) {
-		if (end - pos < 3) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "certificate_list");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		cert_len = WPA_GET_BE24(pos);
-		pos += 3;
-
-		if ((size_t) (end - pos) < cert_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
-				   "length (len=%lu left=%lu)",
-				   (unsigned long) cert_len,
-				   (unsigned long) (end - pos));
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
-			   (unsigned long) idx, (unsigned long) cert_len);
-
-		if (idx == 0) {
-			crypto_public_key_free(conn->server_rsa_key);
-			if (tls_parse_cert(pos, cert_len,
-					   &conn->server_rsa_key)) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-					   "the certificate");
-				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					  TLS_ALERT_BAD_CERTIFICATE);
-				x509_certificate_chain_free(chain);
-				return -1;
-			}
-		}
-
-		cert = x509_certificate_parse(pos, cert_len);
-		if (cert == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "the certificate");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_BAD_CERTIFICATE);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		if (last == NULL)
-			chain = cert;
-		else
-			last->next = cert;
-		last = cert;
-
-		idx++;
-		pos += cert_len;
-	}
-
-	if (conn->cred &&
-	    x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-					    &reason) < 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;
-			break;
-		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
-			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
-			break;
-		case X509_VALIDATE_CERTIFICATE_REVOKED:
-			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_EXPIRED:
-			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
-			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
-			break;
-		case X509_VALIDATE_UNKNOWN_CA:
-			tls_reason = TLS_ALERT_UNKNOWN_CA;
-			break;
-		default:
-			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
-			break;
-		}
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
-		x509_certificate_chain_free(chain);
-		return -1;
-	}
-
-	x509_certificate_chain_free(chain);
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_KEY_EXCHANGE;
-
-	return 0;
-}
-
-
-static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
-					const u8 *buf, size_t len)
-{
-	const u8 *pos, *end;
-
-	tlsv1_client_free_dh(conn);
-
-	pos = buf;
-	end = buf + len;
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_p_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
-			   (unsigned long) conn->dh_p_len);
-		goto fail;
-	}
-	conn->dh_p = os_malloc(conn->dh_p_len);
-	if (conn->dh_p == NULL)
-		goto fail;
-	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
-	pos += conn->dh_p_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
-		    conn->dh_p, conn->dh_p_len);
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_g_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
-		goto fail;
-	conn->dh_g = os_malloc(conn->dh_g_len);
-	if (conn->dh_g == NULL)
-		goto fail;
-	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
-	pos += conn->dh_g_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
-		    conn->dh_g, conn->dh_g_len);
-	if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
-		goto fail;
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_ys_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
-		goto fail;
-	conn->dh_ys = os_malloc(conn->dh_ys_len);
-	if (conn->dh_ys == NULL)
-		goto fail;
-	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
-	pos += conn->dh_ys_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
-		    conn->dh_ys, conn->dh_ys_len);
-
-	return 0;
-
-fail:
-	wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
-	tlsv1_client_free_dh(conn);
-	return -1;
-}
-
-
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-	const struct tls_cipher_suite *suite;
-
-	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 ServerKeyExchange "
-			   "(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 ServerKeyExchange "
-			   "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_REQUEST)
-		return tls_process_certificate_request(conn, ct, in_data,
-						       in_len);
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
-		return tls_process_server_hello_done(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);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
-
-	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
-			   "with the selected cipher suite");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
-		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_CERTIFICATE_REQUEST;
-
-	return 0;
-}
-
-
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-
-	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 CertificateRequest "
-			   "(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 CertificateRequest "
-			   "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_SERVER_HELLO_DONE)
-		return tls_process_server_hello_done(conn, ct, in_data,
-						     in_len);
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected CertificateRequest/"
-			   "ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
-
-	conn->certificate_requested = 1;
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_HELLO_DONE;
-
-	return 0;
-}
-
-
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
-					 const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-
-	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 ServerHelloDone "
-			   "(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 ServerHelloDone "
-			   "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_SERVER_HELLO_DONE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
-
-	*in_len = end - in_data;
-
-	conn->state = CLIENT_KEY_EXCHANGE;
-
-	return 0;
-}
-
-
-static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
-						 u8 ct, const u8 *in_data,
-						 size_t *in_len)
-{
-	const u8 *pos;
-	size_t left;
-
-	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received content type 0x%x", ct);
-		if (conn->use_session_ticket) {
-			int res;
-			wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
-				   "rejected SessionTicket");
-			conn->use_session_ticket = 0;
-
-			/* Notify upper layers that SessionTicket failed */
-			res = conn->session_ticket_cb(
-				conn->session_ticket_cb_ctx, NULL, 0, NULL,
-				NULL, NULL);
-			if (res < 0) {
-				wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
-					   "callback indicated failure");
-				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					  TLS_ALERT_HANDSHAKE_FAILURE);
-				return -1;
-			}
-
-			conn->state = SERVER_CERTIFICATE;
-			return tls_process_certificate(conn, ct, in_data,
-						       in_len);
-		}
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received data 0x%x", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
-	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
-			   "for record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*in_len = pos + 1 - in_data;
-
-	conn->state = SERVER_FINISHED;
-
-	return 0;
-}
-
-
-static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
-				       const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
-			   "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 record (left=%lu) for "
-			   "Finished",
-			   (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
-			   "type 0x%x", pos[0]);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	len = WPA_GET_BE24(pos + 1);
-
-	pos += 4;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
-			   "(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 (len != TLS_VERIFY_DATA_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
-			   "in Finished: %lu (expected %d)",
-			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
-		    pos, TLS_VERIFY_DATA_LEN);
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify.md5_server == NULL ||
-	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		conn->verify.md5_server = NULL;
-		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
-		conn->verify.sha1_server = NULL;
-		return -1;
-	}
-	conn->verify.md5_server = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_server == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify.sha1_server = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_server = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
-		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
-
-	*in_len = end - in_data;
-
-	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
-		CHANGE_CIPHER_SPEC : ACK_FINISHED;
-
-	return 0;
-}
-
-
-static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
-					const u8 *in_data, size_t *in_len,
-					u8 **out_data, size_t *out_len)
-{
-	const u8 *pos;
-	size_t left;
-
-	if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
-			   "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;
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
-		    pos, left);
-
-	*out_data = os_malloc(left);
-	if (*out_data) {
-		os_memcpy(*out_data, pos, left);
-		*out_len = left;
-	}
-
-	return 0;
-}
-
-
-int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
-				   const u8 *buf, size_t *len,
-				   u8 **out_data, size_t *out_len)
-{
-	if (ct == TLS_CONTENT_TYPE_ALERT) {
-		if (*len < 2) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
-			   buf[0], buf[1]);
-		*len = 2;
-		conn->state = FAILED;
-		return -1;
-	}
-
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
-	    buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
-		size_t hr_len = WPA_GET_BE24(buf + 1);
-		if (hr_len > *len - 4) {
-			wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
-		*len = 4 + hr_len;
-		return 0;
-	}
-
-	switch (conn->state) {
-	case SERVER_HELLO:
-		if (tls_process_server_hello(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CERTIFICATE:
-		if (tls_process_certificate(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_KEY_EXCHANGE:
-		if (tls_process_server_key_exchange(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CERTIFICATE_REQUEST:
-		if (tls_process_certificate_request(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_HELLO_DONE:
-		if (tls_process_server_hello_done(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CHANGE_CIPHER_SPEC:
-		if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_FINISHED:
-		if (tls_process_server_finished(conn, ct, buf, len))
-			return -1;
-		break;
-	case ACK_FINISHED:
-		if (out_data &&
-		    tls_process_application_data(conn, ct, buf, len, out_data,
-						 out_len))
-			return -1;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
-			   "while processing received message",
-			   conn->state);
-		return -1;
-	}
-
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
-		tls_verify_hash_add(&conn->verify, buf, *len);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_client_read.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_client_read.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_client_read.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_read.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,999 @@
+/*
+ * TLSv1 client - read handshake message
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/tls.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+					 const u8 *in_data, size_t *in_len);
+
+
+static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
+				    const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, i;
+	u16 cipher_suite;
+	u16 tls_version;
+
+	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)
+		goto decode_error;
+
+	/* HandshakeType msg_type */
+	if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ServerHello)", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
+	pos++;
+	/* uint24 length */
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left)
+		goto decode_error;
+
+	/* body - ServerHello */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
+	end = pos + len;
+
+	/* ProtocolVersion server_version */
+	if (end - pos < 2)
+		goto decode_error;
+	tls_version = WPA_GET_BE16(pos);
+	if (!tls_version_ok(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,
+			  TLS_ALERT_PROTOCOL_VERSION);
+		return -1;
+	}
+	pos += 2;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(tls_version));
+	conn->rl.tls_version = tls_version;
+
+	/* Random random */
+	if (end - pos < TLS_RANDOM_LEN)
+		goto decode_error;
+
+	os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+		    conn->server_random, TLS_RANDOM_LEN);
+
+	/* SessionID session_id */
+	if (end - pos < 1)
+		goto decode_error;
+	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+		goto decode_error;
+	if (conn->session_id_len && conn->session_id_len == *pos &&
+	    os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
+		pos += 1 + conn->session_id_len;
+		wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
+		conn->session_resumed = 1;
+	} else {
+		conn->session_id_len = *pos;
+		pos++;
+		os_memcpy(conn->session_id, pos, conn->session_id_len);
+		pos += conn->session_id_len;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+		    conn->session_id, conn->session_id_len);
+
+	/* CipherSuite cipher_suite */
+	if (end - pos < 2)
+		goto decode_error;
+	cipher_suite = WPA_GET_BE16(pos);
+	pos += 2;
+	for (i = 0; i < conn->num_cipher_suites; i++) {
+		if (cipher_suite == conn->cipher_suites[i])
+			break;
+	}
+	if (i == conn->num_cipher_suites) {
+		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+			   "cipher suite 0x%04x", cipher_suite);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
+			   "cipher suite for a resumed connection (0x%04x != "
+			   "0x%04x)", cipher_suite, conn->prev_cipher_suite);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+			   "record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	conn->prev_cipher_suite = cipher_suite;
+
+	/* CompressionMethod compression_method */
+	if (end - pos < 1)
+		goto decode_error;
+	if (*pos != TLS_COMPRESSION_NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+			   "compression 0x%02x", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+	pos++;
+
+	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;
+	}
+
+	if (conn->session_ticket_included && conn->session_ticket_cb) {
+		/* TODO: include SessionTicket extension if one was included in
+		 * ServerHello */
+		int res = conn->session_ticket_cb(
+			conn->session_ticket_cb_ctx, NULL, 0,
+			conn->client_random, conn->server_random,
+			conn->master_secret);
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+				   "indicated failure");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_HANDSHAKE_FAILURE);
+			return -1;
+		}
+		conn->use_session_ticket = !!res;
+	}
+
+	if ((conn->session_resumed || conn->use_session_ticket) &&
+	    tls_derive_keys(conn, NULL, 0)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = end - in_data;
+
+	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+		SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
+
+	return 0;
+
+decode_error:
+	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+	return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
+				   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, list_len, cert_len, idx;
+	u8 type;
+	struct x509_certificate *chain = NULL, *last = NULL, *cert;
+	int reason;
+
+	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 Certificate message "
+			   "(len=%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: Unexpected Certificate message "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
+		return tls_process_server_key_exchange(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_HELLO_DONE)
+		return tls_process_server_hello_done(conn, ct, in_data,
+						     in_len);
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected Certificate/"
+			   "ServerKeyExchange/CertificateRequest/"
+			   "ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "TLSv1: Received Certificate (certificate_list len %lu)",
+		   (unsigned long) len);
+
+	/*
+	 * opaque ASN.1Cert<2^24-1>;
+	 *
+	 * struct {
+	 *     ASN.1Cert certificate_list<1..2^24-1>;
+	 * } Certificate;
+	 */
+
+	end = pos + len;
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+			   "(left=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	list_len = WPA_GET_BE24(pos);
+	pos += 3;
+
+	if ((size_t) (end - pos) != list_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+			   "length (len=%lu left=%lu)",
+			   (unsigned long) list_len,
+			   (unsigned long) (end - pos));
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	idx = 0;
+	while (pos < end) {
+		if (end - pos < 3) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "certificate_list");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		cert_len = WPA_GET_BE24(pos);
+		pos += 3;
+
+		if ((size_t) (end - pos) < cert_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+				   "length (len=%lu left=%lu)",
+				   (unsigned long) cert_len,
+				   (unsigned long) (end - pos));
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+			   (unsigned long) idx, (unsigned long) cert_len);
+
+		if (idx == 0) {
+			crypto_public_key_free(conn->server_rsa_key);
+			if (tls_parse_cert(pos, cert_len,
+					   &conn->server_rsa_key)) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+					   "the certificate");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_BAD_CERTIFICATE);
+				x509_certificate_chain_free(chain);
+				return -1;
+			}
+		}
+
+		cert = x509_certificate_parse(pos, cert_len);
+		if (cert == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "the certificate");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		if (last == NULL)
+			chain = cert;
+		else
+			last->next = cert;
+		last = cert;
+
+		idx++;
+		pos += cert_len;
+	}
+
+	if (conn->cred &&
+	    x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+					    &reason, 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;
+			break;
+		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+			break;
+		case X509_VALIDATE_CERTIFICATE_REVOKED:
+			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_EXPIRED:
+			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+			break;
+		case X509_VALIDATE_UNKNOWN_CA:
+			tls_reason = TLS_ALERT_UNKNOWN_CA;
+			break;
+		default:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		}
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+		x509_certificate_chain_free(chain);
+		return -1;
+	}
+
+	x509_certificate_chain_free(chain);
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
+					const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+
+	tlsv1_client_free_dh(conn);
+
+	pos = buf;
+	end = buf + len;
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_p_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
+			   (unsigned long) conn->dh_p_len);
+		goto fail;
+	}
+	conn->dh_p = os_malloc(conn->dh_p_len);
+	if (conn->dh_p == NULL)
+		goto fail;
+	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
+	pos += conn->dh_p_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
+		    conn->dh_p, conn->dh_p_len);
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_g_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+		goto fail;
+	conn->dh_g = os_malloc(conn->dh_g_len);
+	if (conn->dh_g == NULL)
+		goto fail;
+	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
+	pos += conn->dh_g_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
+		    conn->dh_g, conn->dh_g_len);
+	if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
+		goto fail;
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_ys_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+		goto fail;
+	conn->dh_ys = os_malloc(conn->dh_ys_len);
+	if (conn->dh_ys == NULL)
+		goto fail;
+	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
+	pos += conn->dh_ys_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+		    conn->dh_ys, conn->dh_ys_len);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
+	tlsv1_client_free_dh(conn);
+	return -1;
+}
+
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	const struct tls_cipher_suite *suite;
+
+	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 ServerKeyExchange "
+			   "(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 ServerKeyExchange "
+			   "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_REQUEST)
+		return tls_process_certificate_request(conn, ct, in_data,
+						       in_len);
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+		return tls_process_server_hello_done(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);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
+
+	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
+			   "with the selected cipher suite");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_CERTIFICATE_REQUEST;
+
+	return 0;
+}
+
+
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+
+	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 CertificateRequest "
+			   "(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 CertificateRequest "
+			   "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_SERVER_HELLO_DONE)
+		return tls_process_server_hello_done(conn, ct, in_data,
+						     in_len);
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected CertificateRequest/"
+			   "ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
+
+	conn->certificate_requested = 1;
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_HELLO_DONE;
+
+	return 0;
+}
+
+
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+					 const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+
+	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 ServerHelloDone "
+			   "(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 ServerHelloDone "
+			   "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_SERVER_HELLO_DONE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+
+	*in_len = end - in_data;
+
+	conn->state = CLIENT_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
+						 u8 ct, const u8 *in_data,
+						 size_t *in_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received content type 0x%x", ct);
+		if (conn->use_session_ticket) {
+			int res;
+			wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
+				   "rejected SessionTicket");
+			conn->use_session_ticket = 0;
+
+			/* Notify upper layers that SessionTicket failed */
+			res = conn->session_ticket_cb(
+				conn->session_ticket_cb_ctx, NULL, 0, NULL,
+				NULL, NULL);
+			if (res < 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
+					   "callback indicated failure");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_HANDSHAKE_FAILURE);
+				return -1;
+			}
+
+			conn->state = SERVER_CERTIFICATE;
+			return tls_process_certificate(conn, ct, in_data,
+						       in_len);
+		}
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received data 0x%x", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+			   "for record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = pos + 1 - in_data;
+
+	conn->state = SERVER_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
+				       const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+			   "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 record (left=%lu) for "
+			   "Finished",
+			   (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+			   "type 0x%x", pos[0]);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	len = WPA_GET_BE24(pos + 1);
+
+	pos += 4;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+			   "(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 (len != TLS_VERIFY_DATA_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+			   "in Finished: %lu (expected %d)",
+			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+		    pos, TLS_VERIFY_DATA_LEN);
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_server = NULL;
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_server == NULL ||
+	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_server = NULL;
+		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+		conn->verify.sha1_server = NULL;
+		return -1;
+	}
+	conn->verify.md5_server = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_server == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_server = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+	*in_len = end - in_data;
+
+	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+		CHANGE_CIPHER_SPEC : ACK_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
+					const u8 *in_data, size_t *in_len,
+					u8 **out_data, size_t *out_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
+			   "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;
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
+		    pos, left);
+
+	*out_data = os_malloc(left);
+	if (*out_data) {
+		os_memcpy(*out_data, pos, left);
+		*out_len = left;
+	}
+
+	return 0;
+}
+
+
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+				   const u8 *buf, size_t *len,
+				   u8 **out_data, size_t *out_len)
+{
+	if (ct == TLS_CONTENT_TYPE_ALERT) {
+		if (*len < 2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+			   buf[0], buf[1]);
+		*len = 2;
+		conn->state = FAILED;
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
+	    buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
+		size_t hr_len = WPA_GET_BE24(buf + 1);
+		if (hr_len > *len - 4) {
+			wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
+		*len = 4 + hr_len;
+		return 0;
+	}
+
+	switch (conn->state) {
+	case SERVER_HELLO:
+		if (tls_process_server_hello(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CERTIFICATE:
+		if (tls_process_certificate(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_KEY_EXCHANGE:
+		if (tls_process_server_key_exchange(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CERTIFICATE_REQUEST:
+		if (tls_process_certificate_request(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_HELLO_DONE:
+		if (tls_process_server_hello_done(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CHANGE_CIPHER_SPEC:
+		if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_FINISHED:
+		if (tls_process_server_finished(conn, ct, buf, len))
+			return -1;
+		break;
+	case ACK_FINISHED:
+		if (out_data &&
+		    tls_process_application_data(conn, ct, buf, len, out_data,
+						 out_len))
+			return -1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+			   "while processing received message",
+			   conn->state);
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+		tls_verify_hash_add(&conn->verify, buf, *len);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_client_write.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_client_write.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_write.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,797 +0,0 @@
-/*
- * TLSv1 client - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "x509v3.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_client.h"
-#include "tlsv1_client_i.h"
-
-
-static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
-{
-	size_t len = 0;
-	struct x509_certificate *cert;
-
-	if (conn->cred == NULL)
-		return 0;
-
-	cert = conn->cred->cert;
-	while (cert) {
-		len += 3 + cert->cert_len;
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
-						    &cert->issuer);
-	}
-
-	return len;
-}
-
-
-u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
-{
-	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
-	struct os_time now;
-	size_t len, i;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
-	*out_len = 0;
-
-	os_get_time(&now);
-	WPA_PUT_BE32(conn->client_random, now.sec);
-	if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
-		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
-			   "client_random");
-		return NULL;
-	}
-	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;
-	hello = os_malloc(len);
-	if (hello == NULL)
-		return NULL;
-	end = hello + len;
-
-	rhdr = hello;
-	pos = rhdr + TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ClientHello */
-	/* ProtocolVersion client_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 += TLS_RANDOM_LEN;
-	/* SessionID session_id */
-	*pos++ = conn->session_id_len;
-	os_memcpy(pos, conn->session_id, conn->session_id_len);
-	pos += conn->session_id_len;
-	/* CipherSuite cipher_suites<2..2^16-1> */
-	WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
-	pos += 2;
-	for (i = 0; i < conn->num_cipher_suites; i++) {
-		WPA_PUT_BE16(pos, conn->cipher_suites[i]);
-		pos += 2;
-	}
-	/* CompressionMethod compression_methods<1..2^8-1> */
-	*pos++ = 1;
-	*pos++ = TLS_COMPRESSION_NULL;
-
-	if (conn->client_hello_ext) {
-		os_memcpy(pos, conn->client_hello_ext,
-			  conn->client_hello_ext_len);
-		pos += conn->client_hello_ext_len;
-	}
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(hello);
-		return NULL;
-	}
-
-	conn->state = SERVER_HELLO;
-
-	return hello;
-}
-
-
-static int tls_write_client_certificate(struct tlsv1_client *conn,
-					u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
-	size_t rlen;
-	struct x509_certificate *cert;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - Certificate */
-	/* uint24 length (to be filled) */
-	cert_start = pos;
-	pos += 3;
-	cert = conn->cred ? conn->cred->cert : NULL;
-	while (cert) {
-		if (pos + 3 + cert->cert_len > end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
-				   "for Certificate (cert_len=%lu left=%lu)",
-				   (unsigned long) cert->cert_len,
-				   (unsigned long) (end - pos));
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			return -1;
-		}
-		WPA_PUT_BE24(pos, cert->cert_len);
-		pos += 3;
-		os_memcpy(pos, cert->cert_start, cert->cert_len);
-		pos += cert->cert_len;
-
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
-						    &cert->issuer);
-	}
-	if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
-		/*
-		 * Client was not configured with all the needed certificates
-		 * to form a full certificate chain. The server may fail to
-		 * validate the chain unless it is configured with all the
-		 * missing CA certificates.
-		 */
-		wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
-			   "not configured - validation may fail");
-	}
-	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
-		tls_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 tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
-	/* ClientDiffieHellmanPublic */
-	u8 *csecret, *csecret_start, *dh_yc, *shared;
-	size_t csecret_len, dh_yc_len, shared_len;
-
-	csecret_len = conn->dh_p_len;
-	csecret = os_malloc(csecret_len);
-	if (csecret == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
-			   "memory for Yc (Diffie-Hellman)");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	if (os_get_random(csecret, csecret_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
-			   "data for Diffie-Hellman");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-
-	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
-		csecret[0] = 0; /* make sure Yc < p */
-
-	csecret_start = csecret;
-	while (csecret_len > 1 && *csecret_start == 0) {
-		csecret_start++;
-		csecret_len--;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
-			csecret_start, csecret_len);
-
-	/* Yc = g^csecret mod p */
-	dh_yc_len = conn->dh_p_len;
-	dh_yc = os_malloc(dh_yc_len);
-	if (dh_yc == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
-			   "memory for Diffie-Hellman");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-	if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
-			   csecret_start, csecret_len,
-			   conn->dh_p, conn->dh_p_len,
-			   dh_yc, &dh_yc_len)) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		os_free(dh_yc);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
-		    dh_yc, dh_yc_len);
-
-	WPA_PUT_BE16(*pos, dh_yc_len);
-	*pos += 2;
-	if (*pos + dh_yc_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
-			   "message buffer for Yc");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		os_free(dh_yc);
-		return -1;
-	}
-	os_memcpy(*pos, dh_yc, dh_yc_len);
-	*pos += dh_yc_len;
-	os_free(dh_yc);
-
-	shared_len = conn->dh_p_len;
-	shared = os_malloc(shared_len);
-	if (shared == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
-			   "DH");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-
-	/* shared = Ys^csecret mod p */
-	if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
-			   csecret_start, csecret_len,
-			   conn->dh_p, conn->dh_p_len,
-			   shared, &shared_len)) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		os_free(shared);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
-			shared, shared_len);
-
-	os_memset(csecret_start, 0, csecret_len);
-	os_free(csecret);
-	if (tls_derive_keys(conn, shared, shared_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(shared);
-		return -1;
-	}
-	os_memset(shared, 0, shared_len);
-	os_free(shared);
-	tlsv1_client_free_dh(conn);
-	return 0;
-}
-
-
-static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
-	u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
-	size_t clen;
-	int res;
-
-	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
-	    tls_derive_keys(conn, pre_master_secret,
-			    TLS_PRE_MASTER_SECRET_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/* EncryptedPreMasterSecret */
-	if (conn->server_rsa_key == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
-			   "use for encrypting pre-master secret");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
-	*pos += 2;
-	clen = end - *pos;
-	res = crypto_public_key_encrypt_pkcs1_v15(
-		conn->server_rsa_key,
-		pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
-		*pos, &clen);
-	os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	WPA_PUT_BE16(*pos - 2, clen);
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
-		    *pos, clen);
-	*pos += clen;
-
-	return 0;
-}
-
-
-static int tls_write_client_key_exchange(struct tlsv1_client *conn,
-					 u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen;
-	tls_key_exchange keyx;
-	const struct tls_cipher_suite *suite;
-
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite == NULL)
-		keyx = TLS_KEY_X_NULL;
-	else
-		keyx = suite->key_exchange;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
-
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ClientKeyExchange */
-	if (keyx == TLS_KEY_X_DH_anon) {
-		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
-			return -1;
-	} else {
-		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
-			return -1;
-	}
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_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_client_certificate_verify(struct tlsv1_client *conn,
-					       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
-	size_t rlen, hlen, clen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-
-	/*
-	 * RFC 2246: 7.4.3 and 7.4.8:
-	 * Signature signature
-	 *
-	 * RSA:
-	 * digitally-signed struct {
-	 *     opaque md5_hash[16];
-	 *     opaque sha_hash[20];
-	 * };
-	 *
-	 * DSA:
-	 * digitally-signed struct {
-	 *     opaque sha_hash[20];
-	 * };
-	 *
-	 * The hash values are calculated over all handshake messages sent or
-	 * received starting at ClientHello up to, but not including, this
-	 * CertificateVerify message, including the type and length fields of
-	 * the handshake messages.
-	 */
-
-	hpos = hash;
-
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify.md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
-		{
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			conn->verify.md5_cert = NULL;
-			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
-			conn->verify.sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
-
-	conn->verify.md5_cert = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_cert == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
-		conn->verify.sha1_cert = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_cert = NULL;
-
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
-
-	/*
-	 * RFC 2246, 4.7:
-	 * In digital signing, one-way hash functions are used as input for a
-	 * signing algorithm. A digitally-signed element is encoded as an
-	 * opaque vector <0..2^16-1>, where the length is specified by the
-	 * signing algorithm and key.
-	 *
-	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
-	 * MD5) is signed (encrypted with the private key). It is encoded with
-	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
-	 */
-	signed_start = pos; /* length to be filled */
-	pos += 2;
-	clen = end - pos;
-	if (conn->cred == NULL ||
-	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
-					  pos, &clen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	WPA_PUT_BE16(signed_start, clen);
-
-	pos += clen;
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
-		tls_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_client_change_cipher_spec(struct tlsv1_client *conn,
-					       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr;
-	size_t rlen;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
-			   "record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*msgpos = rhdr + rlen;
-
-	return 0;
-}
-
-
-static int tls_write_client_finished(struct tlsv1_client *conn,
-				     u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
-
-	/* Encrypted Handshake Message: Finished */
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify.md5_client == NULL ||
-	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		conn->verify.md5_client = NULL;
-		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
-		conn->verify.sha1_client = NULL;
-		return -1;
-	}
-	conn->verify.md5_client = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_client == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify.sha1_client = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_client = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
-					 size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-	size_t msglen;
-
-	*out_len = 0;
-
-	msglen = 1000;
-	if (conn->certificate_requested)
-		msglen += tls_client_cert_chain_der_len(conn);
-
-	msg = os_malloc(msglen);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + msglen;
-
-	if (conn->certificate_requested) {
-		if (tls_write_client_certificate(conn, &pos, end) < 0) {
-			os_free(msg);
-			return NULL;
-		}
-	}
-
-	if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
-	    (conn->certificate_requested && conn->cred && conn->cred->key &&
-	     tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
-	    tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
-	    tls_write_client_finished(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	conn->state = SERVER_CHANGE_CIPHER_SPEC;
-
-	return msg;
-}
-
-
-static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
-					size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-
-	*out_len = 0;
-
-	msg = os_malloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + 1000;
-
-	if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
-	    tls_write_client_finished(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
-		   "successfully");
-	conn->state = ESTABLISHED;
-
-	return msg;
-}
-
-
-u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
-				  int no_appl_data)
-{
-	switch (conn->state) {
-	case CLIENT_KEY_EXCHANGE:
-		return tls_send_client_key_exchange(conn, out_len);
-	case CHANGE_CIPHER_SPEC:
-		return tls_send_change_cipher_spec(conn, out_len);
-	case ACK_FINISHED:
-		wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
-			   "successfully");
-		conn->state = ESTABLISHED;
-		*out_len = 0;
-		if (no_appl_data) {
-			/* Need to return something to get final TLS ACK. */
-			return os_malloc(1);
-		}
-		return NULL;
-	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
-			   "generating reply", conn->state);
-		return NULL;
-	}
-}
-
-
-u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
-			     u8 description, size_t *out_len)
-{
-	u8 *alert, *pos, *length;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
-	*out_len = 0;
-
-	alert = os_malloc(10);
-	if (alert == NULL)
-		return NULL;
-
-	pos = alert;
-
-	/* TLSPlaintext */
-	/* ContentType type */
-	*pos++ = TLS_CONTENT_TYPE_ALERT;
-	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* uint16 length (to be filled) */
-	length = pos;
-	pos += 2;
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Alert */
-	/* AlertLevel level */
-	*pos++ = level;
-	/* AlertDescription description */
-	*pos++ = description;
-
-	WPA_PUT_BE16(length, pos - length - 2);
-	*out_len = pos - alert;
-
-	return alert;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_client_write.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_client_write.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_client_write.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_client_write.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,866 @@
+/*
+ * TLSv1 client - write handshake message
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/tls.h"
+#include "crypto/random.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
+{
+	size_t len = 0;
+	struct x509_certificate *cert;
+
+	if (conn->cred == NULL)
+		return 0;
+
+	cert = conn->cred->cert;
+	while (cert) {
+		len += 3 + cert->cert_len;
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+
+	return len;
+}
+
+
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
+{
+	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
+	struct os_time now;
+	size_t len, i;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+	*out_len = 0;
+
+	os_get_time(&now);
+	WPA_PUT_BE32(conn->client_random, now.sec);
+	if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "client_random");
+		return NULL;
+	}
+	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;
+	hello = os_malloc(len);
+	if (hello == NULL)
+		return NULL;
+	end = hello + len;
+
+	rhdr = hello;
+	pos = rhdr + TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ClientHello */
+	/* ProtocolVersion client_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 += TLS_RANDOM_LEN;
+	/* SessionID session_id */
+	*pos++ = conn->session_id_len;
+	os_memcpy(pos, conn->session_id, conn->session_id_len);
+	pos += conn->session_id_len;
+	/* CipherSuite cipher_suites<2..2^16-1> */
+	WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
+	pos += 2;
+	for (i = 0; i < conn->num_cipher_suites; i++) {
+		WPA_PUT_BE16(pos, conn->cipher_suites[i]);
+		pos += 2;
+	}
+	/* CompressionMethod compression_methods<1..2^8-1> */
+	*pos++ = 1;
+	*pos++ = TLS_COMPRESSION_NULL;
+
+	if (conn->client_hello_ext) {
+		os_memcpy(pos, conn->client_hello_ext,
+			  conn->client_hello_ext_len);
+		pos += conn->client_hello_ext_len;
+	}
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      out_len) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(hello);
+		return NULL;
+	}
+
+	conn->state = SERVER_HELLO;
+
+	return hello;
+}
+
+
+static int tls_write_client_certificate(struct tlsv1_client *conn,
+					u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+	size_t rlen;
+	struct x509_certificate *cert;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - Certificate */
+	/* uint24 length (to be filled) */
+	cert_start = pos;
+	pos += 3;
+	cert = conn->cred ? conn->cred->cert : NULL;
+	while (cert) {
+		if (pos + 3 + cert->cert_len > end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+				   "for Certificate (cert_len=%lu left=%lu)",
+				   (unsigned long) cert->cert_len,
+				   (unsigned long) (end - pos));
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE24(pos, cert->cert_len);
+		pos += 3;
+		os_memcpy(pos, cert->cert_start, cert->cert_len);
+		pos += cert->cert_len;
+
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+	if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
+		/*
+		 * Client was not configured with all the needed certificates
+		 * to form a full certificate chain. The server may fail to
+		 * validate the chain unless it is configured with all the
+		 * missing CA certificates.
+		 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
+			   "not configured - validation may fail");
+	}
+	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+	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");
+		tls_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 tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+	/* ClientDiffieHellmanPublic */
+	u8 *csecret, *csecret_start, *dh_yc, *shared;
+	size_t csecret_len, dh_yc_len, shared_len;
+
+	csecret_len = conn->dh_p_len;
+	csecret = os_malloc(csecret_len);
+	if (csecret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for Yc (Diffie-Hellman)");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	if (random_get_bytes(csecret, csecret_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+			   "data for Diffie-Hellman");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+
+	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
+		csecret[0] = 0; /* make sure Yc < p */
+
+	csecret_start = csecret;
+	while (csecret_len > 1 && *csecret_start == 0) {
+		csecret_start++;
+		csecret_len--;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
+			csecret_start, csecret_len);
+
+	/* Yc = g^csecret mod p */
+	dh_yc_len = conn->dh_p_len;
+	dh_yc = os_malloc(dh_yc_len);
+	if (dh_yc == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for Diffie-Hellman");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+	if (crypto_mod_exp(conn->dh_g, conn->dh_g_len,
+			   csecret_start, csecret_len,
+			   conn->dh_p, conn->dh_p_len,
+			   dh_yc, &dh_yc_len)) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		os_free(dh_yc);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+		    dh_yc, dh_yc_len);
+
+	WPA_PUT_BE16(*pos, dh_yc_len);
+	*pos += 2;
+	if (*pos + dh_yc_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
+			   "message buffer for Yc");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		os_free(dh_yc);
+		return -1;
+	}
+	os_memcpy(*pos, dh_yc, dh_yc_len);
+	*pos += dh_yc_len;
+	os_free(dh_yc);
+
+	shared_len = conn->dh_p_len;
+	shared = os_malloc(shared_len);
+	if (shared == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+			   "DH");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+
+	/* shared = Ys^csecret mod p */
+	if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
+			   csecret_start, csecret_len,
+			   conn->dh_p, conn->dh_p_len,
+			   shared, &shared_len)) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		os_free(shared);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+			shared, shared_len);
+
+	os_memset(csecret_start, 0, csecret_len);
+	os_free(csecret);
+	if (tls_derive_keys(conn, shared, shared_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(shared);
+		return -1;
+	}
+	os_memset(shared, 0, shared_len);
+	os_free(shared);
+	tlsv1_client_free_dh(conn);
+	return 0;
+}
+
+
+static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+	u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
+	size_t clen;
+	int res;
+
+	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+	    tls_derive_keys(conn, pre_master_secret,
+			    TLS_PRE_MASTER_SECRET_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* EncryptedPreMasterSecret */
+	if (conn->server_rsa_key == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
+			   "use for encrypting pre-master secret");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
+	*pos += 2;
+	clen = end - *pos;
+	res = crypto_public_key_encrypt_pkcs1_v15(
+		conn->server_rsa_key,
+		pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
+		*pos, &clen);
+	os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	WPA_PUT_BE16(*pos - 2, clen);
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
+		    *pos, clen);
+	*pos += clen;
+
+	return 0;
+}
+
+
+static int tls_write_client_key_exchange(struct tlsv1_client *conn,
+					 u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
+
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ClientKeyExchange */
+	if (keyx == TLS_KEY_X_DH_anon) {
+		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+			return -1;
+	} else {
+		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
+			return -1;
+	}
+
+	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 create a record");
+		tls_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_client_certificate_verify(struct tlsv1_client *conn,
+					       u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
+	size_t rlen, hlen, clen;
+	u8 hash[100], *hpos;
+	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+
+	/*
+	 * RFC 2246: 7.4.3 and 7.4.8:
+	 * Signature signature
+	 *
+	 * RSA:
+	 * digitally-signed struct {
+	 *     opaque md5_hash[16];
+	 *     opaque sha_hash[20];
+	 * };
+	 *
+	 * DSA:
+	 * digitally-signed struct {
+	 *     opaque sha_hash[20];
+	 * };
+	 *
+	 * The hash values are calculated over all handshake messages sent or
+	 * received starting at ClientHello up to, but not including, this
+	 * CertificateVerify message, including the type and length fields of
+	 * the handshake messages.
+	 */
+
+	hpos = hash;
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		os_memmove(hash + 19, hash, hlen);
+		hlen += 19;
+		os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+			  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	if (alg == SIGN_ALG_RSA) {
+		hlen = MD5_MAC_LEN;
+		if (conn->verify.md5_cert == NULL ||
+		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+		{
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.md5_cert = NULL;
+			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+			conn->verify.sha1_cert = NULL;
+			return -1;
+		}
+		hpos += MD5_MAC_LEN;
+	} else
+		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+	conn->verify.md5_cert = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_cert == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+		conn->verify.sha1_cert = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_cert = NULL;
+
+	if (alg == SIGN_ALG_RSA)
+		hlen += MD5_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		*pos++ = TLS_HASH_ALG_SHA256;
+		*pos++ = TLS_SIGN_ALG_RSA;
+	}
+#endif /* CONFIG_TLSV12 */
+
+	/*
+	 * RFC 2246, 4.7:
+	 * In digital signing, one-way hash functions are used as input for a
+	 * signing algorithm. A digitally-signed element is encoded as an
+	 * opaque vector <0..2^16-1>, where the length is specified by the
+	 * signing algorithm and key.
+	 *
+	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
+	 * MD5) is signed (encrypted with the private key). It is encoded with
+	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
+	 */
+	signed_start = pos; /* length to be filled */
+	pos += 2;
+	clen = end - pos;
+	if (conn->cred == NULL ||
+	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+					  pos, &clen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	WPA_PUT_BE16(signed_start, clen);
+
+	pos += clen;
+
+	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");
+		tls_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_client_change_cipher_spec(struct tlsv1_client *conn,
+					       u8 **msgpos, u8 *end)
+{
+	size_t rlen;
+	u8 payload[1];
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+			   "record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos += rlen;
+
+	return 0;
+}
+
+
+static int tls_write_client_finished(struct tlsv1_client *conn,
+				     u8 **msgpos, u8 *end)
+{
+	u8 *pos, *hs_start;
+	size_t rlen, hlen;
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+	/* Encrypted Handshake Message: Finished */
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_client == NULL ||
+	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_client = NULL;
+		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+		conn->verify.sha1_client = NULL;
+		return -1;
+	}
+	conn->verify.md5_client = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_client == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_client = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+
+	/* Handshake */
+	pos = hs_start = verify_data;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
+	pos += 3;
+	pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos += rlen;
+
+	return 0;
+}
+
+
+static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
+					 size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+	size_t msglen;
+
+	*out_len = 0;
+
+	msglen = 2000;
+	if (conn->certificate_requested)
+		msglen += tls_client_cert_chain_der_len(conn);
+
+	msg = os_malloc(msglen);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + msglen;
+
+	if (conn->certificate_requested) {
+		if (tls_write_client_certificate(conn, &pos, end) < 0) {
+			os_free(msg);
+			return NULL;
+		}
+	}
+
+	if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
+	    (conn->certificate_requested && conn->cred && conn->cred->key &&
+	     tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
+	    tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_client_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	conn->state = SERVER_CHANGE_CIPHER_SPEC;
+
+	return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
+					size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+
+	*out_len = 0;
+
+	msg = os_malloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + 1000;
+
+	if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_client_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
+		   "successfully");
+	conn->state = ESTABLISHED;
+
+	return msg;
+}
+
+
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+				  int no_appl_data)
+{
+	switch (conn->state) {
+	case CLIENT_KEY_EXCHANGE:
+		return tls_send_client_key_exchange(conn, out_len);
+	case CHANGE_CIPHER_SPEC:
+		return tls_send_change_cipher_spec(conn, out_len);
+	case ACK_FINISHED:
+		wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
+			   "successfully");
+		conn->state = ESTABLISHED;
+		*out_len = 0;
+		if (no_appl_data) {
+			/* Need to return something to get final TLS ACK. */
+			return os_malloc(1);
+		}
+		return NULL;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+			   "generating reply", conn->state);
+		return NULL;
+	}
+}
+
+
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+			     u8 description, size_t *out_len)
+{
+	u8 *alert, *pos, *length;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	*out_len = 0;
+
+	alert = os_malloc(10);
+	if (alert == NULL)
+		return NULL;
+
+	pos = alert;
+
+	/* TLSPlaintext */
+	/* ContentType type */
+	*pos++ = TLS_CONTENT_TYPE_ALERT;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
+	pos += 2;
+	/* uint16 length (to be filled) */
+	length = pos;
+	pos += 2;
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Alert */
+	/* AlertLevel level */
+	*pos++ = level;
+	/* AlertDescription description */
+	*pos++ = description;
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	*out_len = pos - alert;
+
+	return alert;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_common.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,241 +0,0 @@
-/*
- * TLSv1 common routines
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "x509v3.h"
-#include "tlsv1_common.h"
-
-
-/*
- * TODO:
- * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
- * Add support for commonly used cipher suites; don't bother with exportable
- * suites.
- */ 
-
-static const struct tls_cipher_suite tls_cipher_suites[] = {
-	{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
-	  TLS_HASH_NULL },
-	{ TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
-	  TLS_HASH_MD5 },
-	{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
-	  TLS_HASH_SHA },
-	{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
-	  TLS_HASH_SHA },
-	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
-	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
- 	{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
- 	{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
- 	{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
-	{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
-	  TLS_HASH_SHA },
-	{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
-	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
-	  TLS_HASH_SHA },
-	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
-};
-
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
-
-
-static const struct tls_cipher_data tls_ciphers[] = {
-	{ TLS_CIPHER_NULL,         TLS_CIPHER_STREAM,  0,  0,  0,
-	  CRYPTO_CIPHER_NULL },
-	{ TLS_CIPHER_IDEA_CBC,     TLS_CIPHER_BLOCK,  16, 16,  8,
-	  CRYPTO_CIPHER_NULL },
-	{ TLS_CIPHER_RC2_CBC_40,   TLS_CIPHER_BLOCK,   5, 16,  0,
-	  CRYPTO_CIPHER_ALG_RC2 },
-	{ TLS_CIPHER_RC4_40,       TLS_CIPHER_STREAM,  5, 16,  0,
-	  CRYPTO_CIPHER_ALG_RC4 },
-	{ TLS_CIPHER_RC4_128,      TLS_CIPHER_STREAM, 16, 16,  0,
-	  CRYPTO_CIPHER_ALG_RC4 },
-	{ TLS_CIPHER_DES40_CBC,    TLS_CIPHER_BLOCK,   5,  8,  8,
-	  CRYPTO_CIPHER_ALG_DES },
-	{ TLS_CIPHER_DES_CBC,      TLS_CIPHER_BLOCK,   8,  8,  8,
-	  CRYPTO_CIPHER_ALG_DES },
-	{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK,  24, 24,  8,
-	  CRYPTO_CIPHER_ALG_3DES },
-	{ TLS_CIPHER_AES_128_CBC,  TLS_CIPHER_BLOCK,  16, 16, 16,
-	  CRYPTO_CIPHER_ALG_AES },
-	{ TLS_CIPHER_AES_256_CBC,  TLS_CIPHER_BLOCK,  32, 32, 16,
-	  CRYPTO_CIPHER_ALG_AES }
-};
-
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
-
-
-/**
- * tls_get_cipher_suite - Get TLS cipher suite
- * @suite: Cipher suite identifier
- * Returns: Pointer to the cipher data or %NULL if not found
- */
-const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)
-{
-	size_t i;
-	for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++)
-		if (tls_cipher_suites[i].suite == suite)
-			return &tls_cipher_suites[i];
-	return NULL;
-}
-
-
-const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
-{
-	size_t i;
-	for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
-		if (tls_ciphers[i].cipher == cipher)
-			return &tls_ciphers[i];
-	return NULL;
-}
-
-
-int tls_server_key_exchange_allowed(tls_cipher cipher)
-{
-	const struct tls_cipher_suite *suite;
-
-	/* RFC 2246, Section 7.4.3 */
-	suite = tls_get_cipher_suite(cipher);
-	if (suite == NULL)
-		return 0;
-
-	switch (suite->key_exchange) {
-	case TLS_KEY_X_DHE_DSS:
-	case TLS_KEY_X_DHE_DSS_EXPORT:
-	case TLS_KEY_X_DHE_RSA:
-	case TLS_KEY_X_DHE_RSA_EXPORT:
-	case TLS_KEY_X_DH_anon_EXPORT:
-	case TLS_KEY_X_DH_anon:
-		return 1;
-	case TLS_KEY_X_RSA_EXPORT:
-		return 1 /* FIX: public key len > 512 bits */;
-	default:
-		return 0;
-	}
-}
-
-
-/**
- * tls_parse_cert - Parse DER encoded X.509 certificate and get public key
- * @buf: ASN.1 DER encoded certificate
- * @len: Length of the buffer
- * @pk: Buffer for returning the allocated public key
- * Returns: 0 on success, -1 on failure
- *
- * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves
- * the public key from it. The caller is responsible for freeing the public key
- * by calling crypto_public_key_free().
- */
-int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)
-{
-	struct x509_certificate *cert;
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate",
-		    buf, len);
-
-	*pk = crypto_public_key_from_cert(buf, len);
-	if (*pk)
-		return 0;
-
-	cert = x509_certificate_parse(buf, len);
-	if (cert == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 "
-			   "certificate");
-		return -1;
-	}
-
-	/* TODO
-	 * verify key usage (must allow encryption)
-	 *
-	 * All certificate profiles, key and cryptographic formats are
-	 * defined by the IETF PKIX working group [PKIX]. When a key
-	 * usage extension is present, the digitalSignature bit must be
-	 * set for the key to be eligible for signing, as described
-	 * above, and the keyEncipherment bit must be present to allow
-	 * encryption, as described above. The keyAgreement bit must be
-	 * set on Diffie-Hellman certificates. (PKIX: RFC 3280)
-	 */
-
-	*pk = crypto_public_key_import(cert->public_key, cert->public_key_len);
-	x509_certificate_free(cert);
-
-	if (*pk == NULL) {
-		wpa_printf(MSG_ERROR, "TLSv1: Failed to import "
-			   "server public key");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int tls_verify_hash_init(struct tls_verify_hash *verify)
-{
-	tls_verify_hash_free(verify);
-	verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
-	verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
-	verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
-	verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
-	verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
-	verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
-	if (verify->md5_client == NULL || verify->md5_server == NULL ||
-	    verify->md5_cert == NULL || verify->sha1_client == NULL ||
-	    verify->sha1_server == NULL || verify->sha1_cert == NULL) {
-		tls_verify_hash_free(verify);
-		return -1;
-	}
-	return 0;
-}
-
-
-void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
-			 size_t len)
-{
-	if (verify->md5_client && verify->sha1_client) {
-		crypto_hash_update(verify->md5_client, buf, len);
-		crypto_hash_update(verify->sha1_client, buf, len);
-	}
-	if (verify->md5_server && verify->sha1_server) {
-		crypto_hash_update(verify->md5_server, buf, len);
-		crypto_hash_update(verify->sha1_server, buf, len);
-	}
-	if (verify->md5_cert && verify->sha1_cert) {
-		crypto_hash_update(verify->md5_cert, buf, len);
-		crypto_hash_update(verify->sha1_cert, buf, len);
-	}
-}
-
-
-void tls_verify_hash_free(struct tls_verify_hash *verify)
-{
-	crypto_hash_finish(verify->md5_client, NULL, NULL);
-	crypto_hash_finish(verify->md5_server, NULL, NULL);
-	crypto_hash_finish(verify->md5_cert, NULL, NULL);
-	crypto_hash_finish(verify->sha1_client, NULL, NULL);
-	crypto_hash_finish(verify->sha1_server, NULL, NULL);
-	crypto_hash_finish(verify->sha1_cert, NULL, NULL);
-	verify->md5_client = NULL;
-	verify->md5_server = NULL;
-	verify->md5_cert = NULL;
-	verify->sha1_client = NULL;
-	verify->sha1_server = NULL;
-	verify->sha1_cert = NULL;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_common.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_common.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,322 @@
+/*
+ * TLSv1 common routines
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/sha256.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+
+
+/*
+ * TODO:
+ * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ * Add support for commonly used cipher suites; don't bother with exportable
+ * suites.
+ */ 
+
+static const struct tls_cipher_suite tls_cipher_suites[] = {
+	{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
+	  TLS_HASH_NULL },
+	{ TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
+	  TLS_HASH_MD5 },
+	{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
+	  TLS_HASH_SHA },
+	{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
+	  TLS_HASH_SHA },
+	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
+	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ 	{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
+ 	{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
+ 	{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+	{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
+	  TLS_HASH_SHA },
+	{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
+	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
+	  TLS_HASH_SHA },
+	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
+	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
+};
+
+#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+
+
+static const struct tls_cipher_data tls_ciphers[] = {
+	{ TLS_CIPHER_NULL,         TLS_CIPHER_STREAM,  0,  0,  0,
+	  CRYPTO_CIPHER_NULL },
+	{ TLS_CIPHER_IDEA_CBC,     TLS_CIPHER_BLOCK,  16, 16,  8,
+	  CRYPTO_CIPHER_NULL },
+	{ TLS_CIPHER_RC2_CBC_40,   TLS_CIPHER_BLOCK,   5, 16,  0,
+	  CRYPTO_CIPHER_ALG_RC2 },
+	{ TLS_CIPHER_RC4_40,       TLS_CIPHER_STREAM,  5, 16,  0,
+	  CRYPTO_CIPHER_ALG_RC4 },
+	{ TLS_CIPHER_RC4_128,      TLS_CIPHER_STREAM, 16, 16,  0,
+	  CRYPTO_CIPHER_ALG_RC4 },
+	{ TLS_CIPHER_DES40_CBC,    TLS_CIPHER_BLOCK,   5,  8,  8,
+	  CRYPTO_CIPHER_ALG_DES },
+	{ TLS_CIPHER_DES_CBC,      TLS_CIPHER_BLOCK,   8,  8,  8,
+	  CRYPTO_CIPHER_ALG_DES },
+	{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK,  24, 24,  8,
+	  CRYPTO_CIPHER_ALG_3DES },
+	{ TLS_CIPHER_AES_128_CBC,  TLS_CIPHER_BLOCK,  16, 16, 16,
+	  CRYPTO_CIPHER_ALG_AES },
+	{ TLS_CIPHER_AES_256_CBC,  TLS_CIPHER_BLOCK,  32, 32, 16,
+	  CRYPTO_CIPHER_ALG_AES }
+};
+
+#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+
+
+/**
+ * tls_get_cipher_suite - Get TLS cipher suite
+ * @suite: Cipher suite identifier
+ * Returns: Pointer to the cipher data or %NULL if not found
+ */
+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)
+{
+	size_t i;
+	for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++)
+		if (tls_cipher_suites[i].suite == suite)
+			return &tls_cipher_suites[i];
+	return NULL;
+}
+
+
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
+{
+	size_t i;
+	for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
+		if (tls_ciphers[i].cipher == cipher)
+			return &tls_ciphers[i];
+	return NULL;
+}
+
+
+int tls_server_key_exchange_allowed(tls_cipher cipher)
+{
+	const struct tls_cipher_suite *suite;
+
+	/* RFC 2246, Section 7.4.3 */
+	suite = tls_get_cipher_suite(cipher);
+	if (suite == NULL)
+		return 0;
+
+	switch (suite->key_exchange) {
+	case TLS_KEY_X_DHE_DSS:
+	case TLS_KEY_X_DHE_DSS_EXPORT:
+	case TLS_KEY_X_DHE_RSA:
+	case TLS_KEY_X_DHE_RSA_EXPORT:
+	case TLS_KEY_X_DH_anon_EXPORT:
+	case TLS_KEY_X_DH_anon:
+		return 1;
+	case TLS_KEY_X_RSA_EXPORT:
+		return 1 /* FIX: public key len > 512 bits */;
+	default:
+		return 0;
+	}
+}
+
+
+/**
+ * tls_parse_cert - Parse DER encoded X.509 certificate and get public key
+ * @buf: ASN.1 DER encoded certificate
+ * @len: Length of the buffer
+ * @pk: Buffer for returning the allocated public key
+ * Returns: 0 on success, -1 on failure
+ *
+ * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves
+ * the public key from it. The caller is responsible for freeing the public key
+ * by calling crypto_public_key_free().
+ */
+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)
+{
+	struct x509_certificate *cert;
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate",
+		    buf, len);
+
+	*pk = crypto_public_key_from_cert(buf, len);
+	if (*pk)
+		return 0;
+
+	cert = x509_certificate_parse(buf, len);
+	if (cert == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 "
+			   "certificate");
+		return -1;
+	}
+
+	/* TODO
+	 * verify key usage (must allow encryption)
+	 *
+	 * All certificate profiles, key and cryptographic formats are
+	 * defined by the IETF PKIX working group [PKIX]. When a key
+	 * usage extension is present, the digitalSignature bit must be
+	 * set for the key to be eligible for signing, as described
+	 * above, and the keyEncipherment bit must be present to allow
+	 * encryption, as described above. The keyAgreement bit must be
+	 * set on Diffie-Hellman certificates. (PKIX: RFC 3280)
+	 */
+
+	*pk = crypto_public_key_import(cert->public_key, cert->public_key_len);
+	x509_certificate_free(cert);
+
+	if (*pk == NULL) {
+		wpa_printf(MSG_ERROR, "TLSv1: Failed to import "
+			   "server public key");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_verify_hash_init(struct tls_verify_hash *verify)
+{
+	tls_verify_hash_free(verify);
+	verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	if (verify->md5_client == NULL || verify->md5_server == NULL ||
+	    verify->md5_cert == NULL || verify->sha1_client == NULL ||
+	    verify->sha1_server == NULL || verify->sha1_cert == NULL) {
+		tls_verify_hash_free(verify);
+		return -1;
+	}
+#ifdef CONFIG_TLSV12
+	verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+					       0);
+	if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
+	    verify->sha256_cert == NULL) {
+		tls_verify_hash_free(verify);
+		return -1;
+	}
+#endif /* CONFIG_TLSV12 */
+	return 0;
+}
+
+
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+			 size_t len)
+{
+	if (verify->md5_client && verify->sha1_client) {
+		crypto_hash_update(verify->md5_client, buf, len);
+		crypto_hash_update(verify->sha1_client, buf, len);
+	}
+	if (verify->md5_server && verify->sha1_server) {
+		crypto_hash_update(verify->md5_server, buf, len);
+		crypto_hash_update(verify->sha1_server, buf, len);
+	}
+	if (verify->md5_cert && verify->sha1_cert) {
+		crypto_hash_update(verify->md5_cert, buf, len);
+		crypto_hash_update(verify->sha1_cert, buf, len);
+	}
+#ifdef CONFIG_TLSV12
+	if (verify->sha256_client)
+		crypto_hash_update(verify->sha256_client, buf, len);
+	if (verify->sha256_server)
+		crypto_hash_update(verify->sha256_server, buf, len);
+	if (verify->sha256_cert)
+		crypto_hash_update(verify->sha256_cert, buf, len);
+#endif /* CONFIG_TLSV12 */
+}
+
+
+void tls_verify_hash_free(struct tls_verify_hash *verify)
+{
+	crypto_hash_finish(verify->md5_client, NULL, NULL);
+	crypto_hash_finish(verify->md5_server, NULL, NULL);
+	crypto_hash_finish(verify->md5_cert, NULL, NULL);
+	crypto_hash_finish(verify->sha1_client, NULL, NULL);
+	crypto_hash_finish(verify->sha1_server, NULL, NULL);
+	crypto_hash_finish(verify->sha1_cert, NULL, NULL);
+	verify->md5_client = NULL;
+	verify->md5_server = NULL;
+	verify->md5_cert = NULL;
+	verify->sha1_client = NULL;
+	verify->sha1_server = NULL;
+	verify->sha1_cert = NULL;
+#ifdef CONFIG_TLSV12
+	crypto_hash_finish(verify->sha256_client, NULL, NULL);
+	crypto_hash_finish(verify->sha256_server, NULL, NULL);
+	crypto_hash_finish(verify->sha256_cert, NULL, NULL);
+	verify->sha256_client = NULL;
+	verify->sha256_server = NULL;
+	verify->sha256_cert = NULL;
+#endif /* CONFIG_TLSV12 */
+}
+
+
+int tls_version_ok(u16 ver)
+{
+	if (ver == TLS_VERSION_1)
+		return 1;
+#ifdef CONFIG_TLSV11
+	if (ver == TLS_VERSION_1_1)
+		return 1;
+#endif /* CONFIG_TLSV11 */
+#ifdef CONFIG_TLSV12
+	if (ver == TLS_VERSION_1_2)
+		return 1;
+#endif /* CONFIG_TLSV12 */
+
+	return 0;
+}
+
+
+const char * tls_version_str(u16 ver)
+{
+	switch (ver) {
+	case TLS_VERSION_1:
+		return "1.0";
+	case TLS_VERSION_1_1:
+		return "1.1";
+	case TLS_VERSION_1_2:
+		return "1.2";
+	}
+
+	return "?";
+}
+
+
+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)
+{
+#ifdef CONFIG_TLSV12
+	if (ver >= TLS_VERSION_1_2) {
+		tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+			       out, outlen);
+		return 0;
+	}
+#endif /* CONFIG_TLSV12 */
+
+	return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
+				outlen);
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_common.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,216 +0,0 @@
-/*
- * TLSv1 common definitions
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_COMMON_H
-#define TLSV1_COMMON_H
-
-#include "crypto/crypto.h"
-
-#define TLS_VERSION 0x0301 /* TLSv1 */
-#define TLS_RANDOM_LEN 32
-#define TLS_PRE_MASTER_SECRET_LEN 48
-#define TLS_MASTER_SECRET_LEN 48
-#define TLS_SESSION_ID_MAX_LEN 32
-#define TLS_VERIFY_DATA_LEN 12
-
-/* HandshakeType */
-enum {
-	TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
-	TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
-	TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
-	TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */,
-	TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
-	TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
-	TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
-	TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
-	TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
-	TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
-	TLS_HANDSHAKE_TYPE_FINISHED = 20,
-	TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */,
-	TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */
-};
-
-/* CipherSuite */
-#define TLS_NULL_WITH_NULL_NULL			0x0000 /* RFC 2246 */
-#define TLS_RSA_WITH_NULL_MD5			0x0001 /* RFC 2246 */
-#define TLS_RSA_WITH_NULL_SHA			0x0002 /* RFC 2246 */
-#define TLS_RSA_EXPORT_WITH_RC4_40_MD5		0x0003 /* RFC 2246 */
-#define TLS_RSA_WITH_RC4_128_MD5		0x0004 /* RFC 2246 */
-#define TLS_RSA_WITH_RC4_128_SHA		0x0005 /* RFC 2246 */
-#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	0x0006 /* RFC 2246 */
-#define TLS_RSA_WITH_IDEA_CBC_SHA		0x0007 /* RFC 2246 */
-#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	0x0008 /* RFC 2246 */
-#define TLS_RSA_WITH_DES_CBC_SHA		0x0009 /* RFC 2246 */
-#define TLS_RSA_WITH_3DES_EDE_CBC_SHA		0x000A /* RFC 2246 */
-#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	0x000B /* RFC 2246 */
-#define TLS_DH_DSS_WITH_DES_CBC_SHA		0x000C /* RFC 2246 */
-#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	0x000D /* RFC 2246 */
-#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	0x000E /* RFC 2246 */
-#define TLS_DH_RSA_WITH_DES_CBC_SHA		0x000F /* RFC 2246 */
-#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	0x0010 /* RFC 2246 */
-#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	0x0011 /* RFC 2246 */
-#define TLS_DHE_DSS_WITH_DES_CBC_SHA		0x0012 /* RFC 2246 */
-#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	0x0013 /* RFC 2246 */
-#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	0x0014 /* RFC 2246 */
-#define TLS_DHE_RSA_WITH_DES_CBC_SHA		0x0015 /* RFC 2246 */
-#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	0x0016 /* RFC 2246 */
-#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	0x0017 /* RFC 2246 */
-#define TLS_DH_anon_WITH_RC4_128_MD5		0x0018 /* RFC 2246 */
-#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	0x0019 /* RFC 2246 */
-#define TLS_DH_anon_WITH_DES_CBC_SHA		0x001A /* RFC 2246 */
-#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	0x001B /* RFC 2246 */
-#define TLS_RSA_WITH_AES_128_CBC_SHA		0x002F /* RFC 3268 */
-#define TLS_DH_DSS_WITH_AES_128_CBC_SHA		0x0030 /* RFC 3268 */
-#define TLS_DH_RSA_WITH_AES_128_CBC_SHA		0x0031 /* RFC 3268 */
-#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA	0x0032 /* RFC 3268 */
-#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA	0x0033 /* RFC 3268 */
-#define TLS_DH_anon_WITH_AES_128_CBC_SHA	0x0034 /* RFC 3268 */
-#define TLS_RSA_WITH_AES_256_CBC_SHA		0x0035 /* RFC 3268 */
-#define TLS_DH_DSS_WITH_AES_256_CBC_SHA		0x0036 /* RFC 3268 */
-#define TLS_DH_RSA_WITH_AES_256_CBC_SHA		0x0037 /* RFC 3268 */
-#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA	0x0038 /* RFC 3268 */
-#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA	0x0039 /* RFC 3268 */
-#define TLS_DH_anon_WITH_AES_256_CBC_SHA	0x003A /* RFC 3268 */
-
-/* CompressionMethod */
-#define TLS_COMPRESSION_NULL 0
-
-/* AlertLevel */
-#define TLS_ALERT_LEVEL_WARNING 1
-#define TLS_ALERT_LEVEL_FATAL 2
-
-/* AlertDescription */
-#define TLS_ALERT_CLOSE_NOTIFY			0
-#define TLS_ALERT_UNEXPECTED_MESSAGE		10
-#define TLS_ALERT_BAD_RECORD_MAC		20
-#define TLS_ALERT_DECRYPTION_FAILED		21
-#define TLS_ALERT_RECORD_OVERFLOW		22
-#define TLS_ALERT_DECOMPRESSION_FAILURE		30
-#define TLS_ALERT_HANDSHAKE_FAILURE		40
-#define TLS_ALERT_BAD_CERTIFICATE		42
-#define TLS_ALERT_UNSUPPORTED_CERTIFICATE	43
-#define TLS_ALERT_CERTIFICATE_REVOKED		44
-#define TLS_ALERT_CERTIFICATE_EXPIRED		45
-#define TLS_ALERT_CERTIFICATE_UNKNOWN		46
-#define TLS_ALERT_ILLEGAL_PARAMETER		47
-#define TLS_ALERT_UNKNOWN_CA			48
-#define TLS_ALERT_ACCESS_DENIED			49
-#define TLS_ALERT_DECODE_ERROR			50
-#define TLS_ALERT_DECRYPT_ERROR			51
-#define TLS_ALERT_EXPORT_RESTRICTION		60
-#define TLS_ALERT_PROTOCOL_VERSION		70
-#define TLS_ALERT_INSUFFICIENT_SECURITY		71
-#define TLS_ALERT_INTERNAL_ERROR		80
-#define TLS_ALERT_USER_CANCELED			90
-#define TLS_ALERT_NO_RENEGOTIATION		100
-#define TLS_ALERT_UNSUPPORTED_EXTENSION		110 /* RFC 4366 */
-#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE	111 /* RFC 4366 */
-#define TLS_ALERT_UNRECOGNIZED_NAME		112 /* RFC 4366 */
-#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE	113 /* RFC 4366 */
-#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE	114 /* RFC 4366 */
-
-/* ChangeCipherSpec */
-enum {
-	TLS_CHANGE_CIPHER_SPEC = 1
-};
-
-/* TLS Extensions */
-#define TLS_EXT_SERVER_NAME			0 /* RFC 4366 */
-#define TLS_EXT_MAX_FRAGMENT_LENGTH		1 /* RFC 4366 */
-#define TLS_EXT_CLIENT_CERTIFICATE_URL		2 /* RFC 4366 */
-#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_SESSION_TICKET			35 /* RFC 4507 */
-
-#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
-
-
-typedef enum {
-	TLS_KEY_X_NULL,
-	TLS_KEY_X_RSA,
-	TLS_KEY_X_RSA_EXPORT,
-	TLS_KEY_X_DH_DSS_EXPORT,
-	TLS_KEY_X_DH_DSS,
-	TLS_KEY_X_DH_RSA_EXPORT,
-	TLS_KEY_X_DH_RSA,
-	TLS_KEY_X_DHE_DSS_EXPORT,
-	TLS_KEY_X_DHE_DSS,
-	TLS_KEY_X_DHE_RSA_EXPORT,
-	TLS_KEY_X_DHE_RSA,
-	TLS_KEY_X_DH_anon_EXPORT,
-	TLS_KEY_X_DH_anon
-} tls_key_exchange;
-
-typedef enum {
-	TLS_CIPHER_NULL,
-	TLS_CIPHER_RC4_40,
-	TLS_CIPHER_RC4_128,
-	TLS_CIPHER_RC2_CBC_40,
-	TLS_CIPHER_IDEA_CBC,
-	TLS_CIPHER_DES40_CBC,
-	TLS_CIPHER_DES_CBC,
-	TLS_CIPHER_3DES_EDE_CBC,
-	TLS_CIPHER_AES_128_CBC,
-	TLS_CIPHER_AES_256_CBC
-} tls_cipher;
-
-typedef enum {
-	TLS_HASH_NULL,
-	TLS_HASH_MD5,
-	TLS_HASH_SHA
-} tls_hash;
-
-struct tls_cipher_suite {
-	u16 suite;
-	tls_key_exchange key_exchange;
-	tls_cipher cipher;
-	tls_hash hash;
-};
-
-typedef enum {
-	TLS_CIPHER_STREAM,
-	TLS_CIPHER_BLOCK
-} tls_cipher_type;
-
-struct tls_cipher_data {
-	tls_cipher cipher;
-	tls_cipher_type type;
-	size_t key_material;
-	size_t expanded_key_material;
-	size_t block_size; /* also iv_size */
-	enum crypto_cipher_alg alg;
-};
-
-
-struct tls_verify_hash {
-	struct crypto_hash *md5_client;
-	struct crypto_hash *sha1_client;
-	struct crypto_hash *md5_server;
-	struct crypto_hash *sha1_server;
-	struct crypto_hash *md5_cert;
-	struct crypto_hash *sha1_cert;
-};
-
-
-const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
-const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher);
-int tls_server_key_exchange_allowed(tls_cipher cipher);
-int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
-int tls_verify_hash_init(struct tls_verify_hash *verify);
-void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
-			 size_t len);
-void tls_verify_hash_free(struct tls_verify_hash *verify);
-
-#endif /* TLSV1_COMMON_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_common.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_common.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,261 @@
+/*
+ * TLSv1 common definitions
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_COMMON_H
+#define TLSV1_COMMON_H
+
+#include "crypto/crypto.h"
+
+#define TLS_VERSION_1 0x0301 /* TLSv1 */
+#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
+#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */
+#ifdef CONFIG_TLSV12
+#define TLS_VERSION TLS_VERSION_1_2
+#else /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+#define TLS_VERSION TLS_VERSION_1_1
+#else /* CONFIG_TLSV11 */
+#define TLS_VERSION TLS_VERSION_1
+#endif /* CONFIG_TLSV11 */
+#endif /* CONFIG_TLSV12 */
+#define TLS_RANDOM_LEN 32
+#define TLS_PRE_MASTER_SECRET_LEN 48
+#define TLS_MASTER_SECRET_LEN 48
+#define TLS_SESSION_ID_MAX_LEN 32
+#define TLS_VERIFY_DATA_LEN 12
+
+/* HandshakeType */
+enum {
+	TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
+	TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
+	TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
+	TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
+	TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
+	TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
+	TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
+	TLS_HANDSHAKE_TYPE_FINISHED = 20,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */
+};
+
+/* CipherSuite */
+#define TLS_NULL_WITH_NULL_NULL			0x0000 /* RFC 2246 */
+#define TLS_RSA_WITH_NULL_MD5			0x0001 /* RFC 2246 */
+#define TLS_RSA_WITH_NULL_SHA			0x0002 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_RC4_40_MD5		0x0003 /* RFC 2246 */
+#define TLS_RSA_WITH_RC4_128_MD5		0x0004 /* RFC 2246 */
+#define TLS_RSA_WITH_RC4_128_SHA		0x0005 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	0x0006 /* RFC 2246 */
+#define TLS_RSA_WITH_IDEA_CBC_SHA		0x0007 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	0x0008 /* RFC 2246 */
+#define TLS_RSA_WITH_DES_CBC_SHA		0x0009 /* RFC 2246 */
+#define TLS_RSA_WITH_3DES_EDE_CBC_SHA		0x000A /* RFC 2246 */
+#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	0x000B /* RFC 2246 */
+#define TLS_DH_DSS_WITH_DES_CBC_SHA		0x000C /* RFC 2246 */
+#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	0x000D /* RFC 2246 */
+#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	0x000E /* RFC 2246 */
+#define TLS_DH_RSA_WITH_DES_CBC_SHA		0x000F /* RFC 2246 */
+#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	0x0010 /* RFC 2246 */
+#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	0x0011 /* RFC 2246 */
+#define TLS_DHE_DSS_WITH_DES_CBC_SHA		0x0012 /* RFC 2246 */
+#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	0x0013 /* RFC 2246 */
+#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	0x0014 /* RFC 2246 */
+#define TLS_DHE_RSA_WITH_DES_CBC_SHA		0x0015 /* RFC 2246 */
+#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	0x0016 /* RFC 2246 */
+#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	0x0017 /* RFC 2246 */
+#define TLS_DH_anon_WITH_RC4_128_MD5		0x0018 /* RFC 2246 */
+#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	0x0019 /* RFC 2246 */
+#define TLS_DH_anon_WITH_DES_CBC_SHA		0x001A /* RFC 2246 */
+#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	0x001B /* RFC 2246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA		0x002F /* RFC 3268 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA		0x0030 /* RFC 3268 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA		0x0031 /* RFC 3268 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA	0x0032 /* RFC 3268 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA	0x0033 /* RFC 3268 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA	0x0034 /* RFC 3268 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA		0x0035 /* RFC 3268 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA		0x0036 /* RFC 3268 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA		0x0037 /* RFC 3268 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA	0x0038 /* RFC 3268 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA	0x0039 /* RFC 3268 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA	0x003A /* RFC 3268 */
+#define TLS_RSA_WITH_NULL_SHA256		0x003B /* RFC 5246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA256		0x003C /* RFC 5246 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA256		0x003D /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256	0x003E /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256	0x003F /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256	0x0040 /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256	0x0067 /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256	0x0068 /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256	0x0069 /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256	0x006A /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256	0x006B /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA256	0x006C /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA256	0x006D /* RFC 5246 */
+
+/* CompressionMethod */
+#define TLS_COMPRESSION_NULL 0
+
+/* HashAlgorithm */
+enum {
+	TLS_HASH_ALG_NONE = 0,
+	TLS_HASH_ALG_MD5 = 1,
+	TLS_HASH_ALG_SHA1 = 2,
+	TLS_HASH_ALG_SHA224 = 3,
+	TLS_HASH_ALG_SHA256 = 4,
+	TLS_HASH_ALG_SHA384 = 5,
+	TLS_HASH_ALG_SHA512 = 6
+};
+
+/* SignatureAlgorithm */
+enum {
+	TLS_SIGN_ALG_ANONYMOUS = 0,
+	TLS_SIGN_ALG_RSA = 1,
+	TLS_SIGN_ALG_DSA = 2,
+	TLS_SIGN_ALG_ECDSA = 3,
+};
+
+/* AlertLevel */
+#define TLS_ALERT_LEVEL_WARNING 1
+#define TLS_ALERT_LEVEL_FATAL 2
+
+/* AlertDescription */
+#define TLS_ALERT_CLOSE_NOTIFY			0
+#define TLS_ALERT_UNEXPECTED_MESSAGE		10
+#define TLS_ALERT_BAD_RECORD_MAC		20
+#define TLS_ALERT_DECRYPTION_FAILED		21
+#define TLS_ALERT_RECORD_OVERFLOW		22
+#define TLS_ALERT_DECOMPRESSION_FAILURE		30
+#define TLS_ALERT_HANDSHAKE_FAILURE		40
+#define TLS_ALERT_BAD_CERTIFICATE		42
+#define TLS_ALERT_UNSUPPORTED_CERTIFICATE	43
+#define TLS_ALERT_CERTIFICATE_REVOKED		44
+#define TLS_ALERT_CERTIFICATE_EXPIRED		45
+#define TLS_ALERT_CERTIFICATE_UNKNOWN		46
+#define TLS_ALERT_ILLEGAL_PARAMETER		47
+#define TLS_ALERT_UNKNOWN_CA			48
+#define TLS_ALERT_ACCESS_DENIED			49
+#define TLS_ALERT_DECODE_ERROR			50
+#define TLS_ALERT_DECRYPT_ERROR			51
+#define TLS_ALERT_EXPORT_RESTRICTION		60
+#define TLS_ALERT_PROTOCOL_VERSION		70
+#define TLS_ALERT_INSUFFICIENT_SECURITY		71
+#define TLS_ALERT_INTERNAL_ERROR		80
+#define TLS_ALERT_USER_CANCELED			90
+#define TLS_ALERT_NO_RENEGOTIATION		100
+#define TLS_ALERT_UNSUPPORTED_EXTENSION		110 /* RFC 4366 */
+#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE	111 /* RFC 4366 */
+#define TLS_ALERT_UNRECOGNIZED_NAME		112 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE	113 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE	114 /* RFC 4366 */
+
+/* ChangeCipherSpec */
+enum {
+	TLS_CHANGE_CIPHER_SPEC = 1
+};
+
+/* TLS Extensions */
+#define TLS_EXT_SERVER_NAME			0 /* RFC 4366 */
+#define TLS_EXT_MAX_FRAGMENT_LENGTH		1 /* RFC 4366 */
+#define TLS_EXT_CLIENT_CERTIFICATE_URL		2 /* RFC 4366 */
+#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_SESSION_TICKET			35 /* RFC 4507 */
+
+#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
+
+
+typedef enum {
+	TLS_KEY_X_NULL,
+	TLS_KEY_X_RSA,
+	TLS_KEY_X_RSA_EXPORT,
+	TLS_KEY_X_DH_DSS_EXPORT,
+	TLS_KEY_X_DH_DSS,
+	TLS_KEY_X_DH_RSA_EXPORT,
+	TLS_KEY_X_DH_RSA,
+	TLS_KEY_X_DHE_DSS_EXPORT,
+	TLS_KEY_X_DHE_DSS,
+	TLS_KEY_X_DHE_RSA_EXPORT,
+	TLS_KEY_X_DHE_RSA,
+	TLS_KEY_X_DH_anon_EXPORT,
+	TLS_KEY_X_DH_anon
+} tls_key_exchange;
+
+typedef enum {
+	TLS_CIPHER_NULL,
+	TLS_CIPHER_RC4_40,
+	TLS_CIPHER_RC4_128,
+	TLS_CIPHER_RC2_CBC_40,
+	TLS_CIPHER_IDEA_CBC,
+	TLS_CIPHER_DES40_CBC,
+	TLS_CIPHER_DES_CBC,
+	TLS_CIPHER_3DES_EDE_CBC,
+	TLS_CIPHER_AES_128_CBC,
+	TLS_CIPHER_AES_256_CBC
+} tls_cipher;
+
+typedef enum {
+	TLS_HASH_NULL,
+	TLS_HASH_MD5,
+	TLS_HASH_SHA,
+	TLS_HASH_SHA256
+} tls_hash;
+
+struct tls_cipher_suite {
+	u16 suite;
+	tls_key_exchange key_exchange;
+	tls_cipher cipher;
+	tls_hash hash;
+};
+
+typedef enum {
+	TLS_CIPHER_STREAM,
+	TLS_CIPHER_BLOCK
+} tls_cipher_type;
+
+struct tls_cipher_data {
+	tls_cipher cipher;
+	tls_cipher_type type;
+	size_t key_material;
+	size_t expanded_key_material;
+	size_t block_size; /* also iv_size */
+	enum crypto_cipher_alg alg;
+};
+
+
+struct tls_verify_hash {
+	struct crypto_hash *md5_client;
+	struct crypto_hash *sha1_client;
+	struct crypto_hash *sha256_client;
+	struct crypto_hash *md5_server;
+	struct crypto_hash *sha1_server;
+	struct crypto_hash *sha256_server;
+	struct crypto_hash *md5_cert;
+	struct crypto_hash *sha1_cert;
+	struct crypto_hash *sha256_cert;
+};
+
+
+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher);
+int tls_server_key_exchange_allowed(tls_cipher cipher);
+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
+int tls_verify_hash_init(struct tls_verify_hash *verify);
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+			 size_t len);
+void tls_verify_hash_free(struct tls_verify_hash *verify);
+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);
+
+#endif /* TLSV1_COMMON_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_cred.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_cred.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_cred.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,493 +0,0 @@
-/*
- * TLSv1 credentials
- * Copyright (c) 2006-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "crypto/crypto.h"
-#include "x509v3.h"
-#include "tlsv1_cred.h"
-
-
-struct tlsv1_credentials * tlsv1_cred_alloc(void)
-{
-	struct tlsv1_credentials *cred;
-	cred = os_zalloc(sizeof(*cred));
-	return cred;
-}
-
-
-void tlsv1_cred_free(struct tlsv1_credentials *cred)
-{
-	if (cred == NULL)
-		return;
-
-	x509_certificate_chain_free(cred->trusted_certs);
-	x509_certificate_chain_free(cred->cert);
-	crypto_private_key_free(cred->key);
-	os_free(cred->dh_p);
-	os_free(cred->dh_g);
-	os_free(cred);
-}
-
-
-static int tlsv1_add_cert_der(struct x509_certificate **chain,
-			      const u8 *buf, size_t len)
-{
-	struct x509_certificate *cert;
-	char name[128];
-
-	cert = x509_certificate_parse(buf, len);
-	if (cert == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
-			   __func__);
-		return -1;
-	}
-
-	cert->next = *chain;
-	*chain = cert;
-
-	x509_name_string(&cert->subject, name, sizeof(name));
-	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
-
-	return 0;
-}
-
-
-static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
-static const char *pem_cert_end = "-----END CERTIFICATE-----";
-static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
-static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
-static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
-static const char *pem_key2_end = "-----END PRIVATE KEY-----";
-static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
-static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
-
-
-static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
-{
-	size_t i, plen;
-
-	plen = os_strlen(tag);
-	if (len < plen)
-		return NULL;
-
-	for (i = 0; i < len - plen; i++) {
-		if (os_memcmp(buf + i, tag, plen) == 0)
-			return buf + i;
-	}
-
-	return NULL;
-}
-
-
-static int tlsv1_add_cert(struct x509_certificate **chain,
-			  const u8 *buf, size_t len)
-{
-	const u8 *pos, *end;
-	unsigned char *der;
-	size_t der_len;
-
-	pos = search_tag(pem_cert_begin, buf, len);
-	if (!pos) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
-			   "assume DER format");
-		return tlsv1_add_cert_der(chain, buf, len);
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
-		   "DER format");
-
-	while (pos) {
-		pos += os_strlen(pem_cert_begin);
-		end = search_tag(pem_cert_end, pos, buf + len - pos);
-		if (end == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
-				   "certificate end tag (%s)", pem_cert_end);
-			return -1;
-		}
-
-		der = base64_decode(pos, end - pos, &der_len);
-		if (der == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
-				   "certificate");
-			return -1;
-		}
-
-		if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
-				   "certificate after DER conversion");
-			os_free(der);
-			return -1;
-		}
-
-		os_free(der);
-
-		end += os_strlen(pem_cert_end);
-		pos = search_tag(pem_cert_begin, end, buf + len - end);
-	}
-
-	return 0;
-}
-
-
-static int tlsv1_set_cert_chain(struct x509_certificate **chain,
-				const char *cert, const u8 *cert_blob,
-				size_t cert_blob_len)
-{
-	if (cert_blob)
-		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
-
-	if (cert) {
-		u8 *buf;
-		size_t len;
-		int ret;
-
-		buf = (u8 *) os_readfile(cert, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
-				   cert);
-			return -1;
-		}
-
-		ret = tlsv1_add_cert(chain, buf, len);
-		os_free(buf);
-		return ret;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_set_ca_cert - Set trusted CA certificate(s)
- * @cred: TLSv1 credentials from tlsv1_cred_alloc()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: ca_cert_blob length
- * @path: Path to CA certificates (not yet supported)
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
-		      const u8 *cert_blob, size_t cert_blob_len,
-		      const char *path)
-{
-	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
-				 cert_blob, cert_blob_len) < 0)
-		return -1;
-
-	if (path) {
-		/* TODO: add support for reading number of certificate files */
-		wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
-			   "not yet supported");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_set_cert - Set certificate
- * @cred: TLSv1 credentials from tlsv1_cred_alloc()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: cert_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
-		   const u8 *cert_blob, size_t cert_blob_len)
-{
-	return tlsv1_set_cert_chain(&cred->cert, cert,
-				    cert_blob, cert_blob_len);
-}
-
-
-static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
-{
-	const u8 *pos, *end;
-	unsigned char *der;
-	size_t der_len;
-	struct crypto_private_key *pkey;
-
-	pos = search_tag(pem_key_begin, key, len);
-	if (!pos) {
-		pos = search_tag(pem_key2_begin, key, len);
-		if (!pos)
-			return NULL;
-		pos += os_strlen(pem_key2_begin);
-		end = search_tag(pem_key2_end, pos, key + len - pos);
-		if (!end)
-			return NULL;
-	} else {
-		pos += os_strlen(pem_key_begin);
-		end = search_tag(pem_key_end, pos, key + len - pos);
-		if (!end)
-			return NULL;
-	}
-
-	der = base64_decode(pos, end - pos, &der_len);
-	if (!der)
-		return NULL;
-	pkey = crypto_private_key_import(der, der_len, NULL);
-	os_free(der);
-	return pkey;
-}
-
-
-static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
-							 size_t len,
-							 const char *passwd)
-{
-	const u8 *pos, *end;
-	unsigned char *der;
-	size_t der_len;
-	struct crypto_private_key *pkey;
-
-	if (passwd == NULL)
-		return NULL;
-	pos = search_tag(pem_key_enc_begin, key, len);
-	if (!pos)
-		return NULL;
-	pos += os_strlen(pem_key_enc_begin);
-	end = search_tag(pem_key_enc_end, pos, key + len - pos);
-	if (!end)
-		return NULL;
-
-	der = base64_decode(pos, end - pos, &der_len);
-	if (!der)
-		return NULL;
-	pkey = crypto_private_key_import(der, der_len, passwd);
-	os_free(der);
-	return pkey;
-}
-
-
-static int tlsv1_set_key(struct tlsv1_credentials *cred,
-			 const u8 *key, size_t len, const char *passwd)
-{
-	cred->key = crypto_private_key_import(key, len, passwd);
-	if (cred->key == NULL)
-		cred->key = tlsv1_set_key_pem(key, len);
-	if (cred->key == NULL)
-		cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
-	if (cred->key == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * tlsv1_set_private_key - Set private key
- * @cred: TLSv1 credentials from tlsv1_cred_alloc()
- * @private_key: File or reference name for the key in PEM or DER format
- * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
- * passphrase is used.
- * @private_key_blob: private_key as inlined data or %NULL if not used
- * @private_key_blob_len: private_key_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_set_private_key(struct tlsv1_credentials *cred,
-			  const char *private_key,
-			  const char *private_key_passwd,
-			  const u8 *private_key_blob,
-			  size_t private_key_blob_len)
-{
-	crypto_private_key_free(cred->key);
-	cred->key = NULL;
-
-	if (private_key_blob)
-		return tlsv1_set_key(cred, private_key_blob,
-				     private_key_blob_len,
-				     private_key_passwd);
-
-	if (private_key) {
-		u8 *buf;
-		size_t len;
-		int ret;
-
-		buf = (u8 *) os_readfile(private_key, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
-				   private_key);
-			return -1;
-		}
-
-		ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
-		os_free(buf);
-		return ret;
-	}
-
-	return 0;
-}
-
-
-static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
-				  const u8 *dh, size_t len)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-
-	pos = dh;
-	end = dh + len;
-
-	/*
-	 * DHParameter ::= SEQUENCE {
-	 *   prime INTEGER, -- p
-	 *   base INTEGER, -- g
-	 *   privateValueLength INTEGER OPTIONAL }
-	 */
-
-	/* DHParamer ::= SEQUENCE */
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
-			   "valid SEQUENCE - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-
-	/* prime INTEGER */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
-			   "class=%d tag=0x%x", hdr.class, hdr.tag);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
-	if (hdr.length == 0)
-		return -1;
-	os_free(cred->dh_p);
-	cred->dh_p = os_malloc(hdr.length);
-	if (cred->dh_p == NULL)
-		return -1;
-	os_memcpy(cred->dh_p, hdr.payload, hdr.length);
-	cred->dh_p_len = hdr.length;
-	pos = hdr.payload + hdr.length;
-
-	/* base INTEGER */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0)
-		return -1;
-
-	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
-			   "class=%d tag=0x%x", hdr.class, hdr.tag);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
-	if (hdr.length == 0)
-		return -1;
-	os_free(cred->dh_g);
-	cred->dh_g = os_malloc(hdr.length);
-	if (cred->dh_g == NULL)
-		return -1;
-	os_memcpy(cred->dh_g, hdr.payload, hdr.length);
-	cred->dh_g_len = hdr.length;
-
-	return 0;
-}
-
-
-static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
-static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
-
-
-static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
-				   const u8 *buf, size_t len)
-{
-	const u8 *pos, *end;
-	unsigned char *der;
-	size_t der_len;
-
-	pos = search_tag(pem_dhparams_begin, buf, len);
-	if (!pos) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
-			   "assume DER format");
-		return tlsv1_set_dhparams_der(cred, buf, len);
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
-		   "format");
-
-	pos += os_strlen(pem_dhparams_begin);
-	end = search_tag(pem_dhparams_end, pos, buf + len - pos);
-	if (end == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
-			   "tag (%s)", pem_dhparams_end);
-		return -1;
-	}
-
-	der = base64_decode(pos, end - pos, &der_len);
-	if (der == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
-		return -1;
-	}
-
-	if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
-		wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
-			   "DER conversion");
-		os_free(der);
-		return -1;
-	}
-
-	os_free(der);
-
-	return 0;
-}
-
-
-/**
- * tlsv1_set_dhparams - Set Diffie-Hellman parameters
- * @cred: TLSv1 credentials from tlsv1_cred_alloc()
- * @dh_file: File or reference name for the DH params in PEM or DER format
- * @dh_blob: DH params as inlined data or %NULL if not used
- * @dh_blob_len: dh_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
-		       const u8 *dh_blob, size_t dh_blob_len)
-{
-	if (dh_blob)
-		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
-
-	if (dh_file) {
-		u8 *buf;
-		size_t len;
-		int ret;
-
-		buf = (u8 *) os_readfile(dh_file, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
-				   dh_file);
-			return -1;
-		}
-
-		ret = tlsv1_set_dhparams_blob(cred, buf, len);
-		os_free(buf);
-		return ret;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_cred.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_cred.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_cred.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_cred.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,506 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2009, Jouni Malinen <j at 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 "base64.h"
+#include "crypto/crypto.h"
+#include "x509v3.h"
+#include "tlsv1_cred.h"
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void)
+{
+	struct tlsv1_credentials *cred;
+	cred = os_zalloc(sizeof(*cred));
+	return cred;
+}
+
+
+void tlsv1_cred_free(struct tlsv1_credentials *cred)
+{
+	if (cred == NULL)
+		return;
+
+	x509_certificate_chain_free(cred->trusted_certs);
+	x509_certificate_chain_free(cred->cert);
+	crypto_private_key_free(cred->key);
+	os_free(cred->dh_p);
+	os_free(cred->dh_g);
+	os_free(cred);
+}
+
+
+static int tlsv1_add_cert_der(struct x509_certificate **chain,
+			      const u8 *buf, size_t len)
+{
+	struct x509_certificate *cert, *p;
+	char name[128];
+
+	cert = x509_certificate_parse(buf, len);
+	if (cert == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
+			   __func__);
+		return -1;
+	}
+
+	p = *chain;
+	while (p && p->next)
+		p = p->next;
+	if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
+		/*
+		 * The new certificate is the issuer of the last certificate in
+		 * the chain - add the new certificate to the end.
+		 */
+		p->next = cert;
+	} else {
+		/* Add to the beginning of the chain */
+		cert->next = *chain;
+		*chain = cert;
+	}
+
+	x509_name_string(&cert->subject, name, sizeof(name));
+	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
+
+	return 0;
+}
+
+
+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
+static const char *pem_cert_end = "-----END CERTIFICATE-----";
+static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
+static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
+static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
+static const char *pem_key2_end = "-----END PRIVATE KEY-----";
+static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
+static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
+
+
+static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
+{
+	size_t i, plen;
+
+	plen = os_strlen(tag);
+	if (len < plen)
+		return NULL;
+
+	for (i = 0; i < len - plen; i++) {
+		if (os_memcmp(buf + i, tag, plen) == 0)
+			return buf + i;
+	}
+
+	return NULL;
+}
+
+
+static int tlsv1_add_cert(struct x509_certificate **chain,
+			  const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+
+	pos = search_tag(pem_cert_begin, buf, len);
+	if (!pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
+			   "assume DER format");
+		return tlsv1_add_cert_der(chain, buf, len);
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
+		   "DER format");
+
+	while (pos) {
+		pos += os_strlen(pem_cert_begin);
+		end = search_tag(pem_cert_end, pos, buf + len - pos);
+		if (end == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
+				   "certificate end tag (%s)", pem_cert_end);
+			return -1;
+		}
+
+		der = base64_decode(pos, end - pos, &der_len);
+		if (der == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
+				   "certificate");
+			return -1;
+		}
+
+		if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
+				   "certificate after DER conversion");
+			os_free(der);
+			return -1;
+		}
+
+		os_free(der);
+
+		end += os_strlen(pem_cert_end);
+		pos = search_tag(pem_cert_begin, end, buf + len - end);
+	}
+
+	return 0;
+}
+
+
+static int tlsv1_set_cert_chain(struct x509_certificate **chain,
+				const char *cert, const u8 *cert_blob,
+				size_t cert_blob_len)
+{
+	if (cert_blob)
+		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
+
+	if (cert) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(cert, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   cert);
+			return -1;
+		}
+
+		ret = tlsv1_add_cert(chain, buf, len);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_ca_cert - Set trusted CA certificate(s)
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: ca_cert_blob length
+ * @path: Path to CA certificates (not yet supported)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+		      const u8 *cert_blob, size_t cert_blob_len,
+		      const char *path)
+{
+	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
+				 cert_blob, cert_blob_len) < 0)
+		return -1;
+
+	if (path) {
+		/* TODO: add support for reading number of certificate files */
+		wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
+			   "not yet supported");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_cert - Set certificate
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: cert_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+		   const u8 *cert_blob, size_t cert_blob_len)
+{
+	return tlsv1_set_cert_chain(&cred->cert, cert,
+				    cert_blob, cert_blob_len);
+}
+
+
+static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+	struct crypto_private_key *pkey;
+
+	pos = search_tag(pem_key_begin, key, len);
+	if (!pos) {
+		pos = search_tag(pem_key2_begin, key, len);
+		if (!pos)
+			return NULL;
+		pos += os_strlen(pem_key2_begin);
+		end = search_tag(pem_key2_end, pos, key + len - pos);
+		if (!end)
+			return NULL;
+	} else {
+		const u8 *pos2;
+		pos += os_strlen(pem_key_begin);
+		end = search_tag(pem_key_end, pos, key + len - pos);
+		if (!end)
+			return NULL;
+		pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
+		if (pos2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
+				   "format (Proc-Type/DEK-Info)");
+			return NULL;
+		}
+	}
+
+	der = base64_decode(pos, end - pos, &der_len);
+	if (!der)
+		return NULL;
+	pkey = crypto_private_key_import(der, der_len, NULL);
+	os_free(der);
+	return pkey;
+}
+
+
+static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
+							 size_t len,
+							 const char *passwd)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+	struct crypto_private_key *pkey;
+
+	if (passwd == NULL)
+		return NULL;
+	pos = search_tag(pem_key_enc_begin, key, len);
+	if (!pos)
+		return NULL;
+	pos += os_strlen(pem_key_enc_begin);
+	end = search_tag(pem_key_enc_end, pos, key + len - pos);
+	if (!end)
+		return NULL;
+
+	der = base64_decode(pos, end - pos, &der_len);
+	if (!der)
+		return NULL;
+	pkey = crypto_private_key_import(der, der_len, passwd);
+	os_free(der);
+	return pkey;
+}
+
+
+static int tlsv1_set_key(struct tlsv1_credentials *cred,
+			 const u8 *key, size_t len, const char *passwd)
+{
+	cred->key = crypto_private_key_import(key, len, passwd);
+	if (cred->key == NULL)
+		cred->key = tlsv1_set_key_pem(key, len);
+	if (cred->key == NULL)
+		cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
+	if (cred->key == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_private_key - Set private key
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @private_key: File or reference name for the key in PEM or DER format
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+			  const char *private_key,
+			  const char *private_key_passwd,
+			  const u8 *private_key_blob,
+			  size_t private_key_blob_len)
+{
+	crypto_private_key_free(cred->key);
+	cred->key = NULL;
+
+	if (private_key_blob)
+		return tlsv1_set_key(cred, private_key_blob,
+				     private_key_blob_len,
+				     private_key_passwd);
+
+	if (private_key) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(private_key, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   private_key);
+			return -1;
+		}
+
+		ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
+				  const u8 *dh, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	pos = dh;
+	end = dh + len;
+
+	/*
+	 * DHParameter ::= SEQUENCE {
+	 *   prime INTEGER, -- p
+	 *   base INTEGER, -- g
+	 *   privateValueLength INTEGER OPTIONAL }
+	 */
+
+	/* DHParamer ::= SEQUENCE */
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
+			   "valid SEQUENCE - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+
+	/* prime INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
+			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
+	if (hdr.length == 0)
+		return -1;
+	os_free(cred->dh_p);
+	cred->dh_p = os_malloc(hdr.length);
+	if (cred->dh_p == NULL)
+		return -1;
+	os_memcpy(cred->dh_p, hdr.payload, hdr.length);
+	cred->dh_p_len = hdr.length;
+	pos = hdr.payload + hdr.length;
+
+	/* base INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
+			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
+	if (hdr.length == 0)
+		return -1;
+	os_free(cred->dh_g);
+	cred->dh_g = os_malloc(hdr.length);
+	if (cred->dh_g == NULL)
+		return -1;
+	os_memcpy(cred->dh_g, hdr.payload, hdr.length);
+	cred->dh_g_len = hdr.length;
+
+	return 0;
+}
+
+
+static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
+static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
+
+
+static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
+				   const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+
+	pos = search_tag(pem_dhparams_begin, buf, len);
+	if (!pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
+			   "assume DER format");
+		return tlsv1_set_dhparams_der(cred, buf, len);
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
+		   "format");
+
+	pos += os_strlen(pem_dhparams_begin);
+	end = search_tag(pem_dhparams_end, pos, buf + len - pos);
+	if (end == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
+			   "tag (%s)", pem_dhparams_end);
+		return -1;
+	}
+
+	der = base64_decode(pos, end - pos, &der_len);
+	if (der == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
+			   "DER conversion");
+		os_free(der);
+		return -1;
+	}
+
+	os_free(der);
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_dhparams - Set Diffie-Hellman parameters
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @dh_file: File or reference name for the DH params in PEM or DER format
+ * @dh_blob: DH params as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+		       const u8 *dh_blob, size_t dh_blob_len)
+{
+	if (dh_blob)
+		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
+
+	if (dh_file) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(dh_file, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   dh_file);
+			return -1;
+		}
+
+		ret = tlsv1_set_dhparams_blob(cred, buf, len);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_cred.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_cred.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_cred.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,46 +0,0 @@
-/*
- * TLSv1 credentials
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_CRED_H
-#define TLSV1_CRED_H
-
-struct tlsv1_credentials {
-	struct x509_certificate *trusted_certs;
-	struct x509_certificate *cert;
-	struct crypto_private_key *key;
-
-	/* Diffie-Hellman parameters */
-	u8 *dh_p; /* prime */
-	size_t dh_p_len;
-	u8 *dh_g; /* generator */
-	size_t dh_g_len;
-};
-
-
-struct tlsv1_credentials * tlsv1_cred_alloc(void);
-void tlsv1_cred_free(struct tlsv1_credentials *cred);
-int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
-		      const u8 *cert_blob, size_t cert_blob_len,
-		      const char *path);
-int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
-		   const u8 *cert_blob, size_t cert_blob_len);
-int tlsv1_set_private_key(struct tlsv1_credentials *cred,
-			  const char *private_key,
-			  const char *private_key_passwd,
-			  const u8 *private_key_blob,
-			  size_t private_key_blob_len);
-int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
-		       const u8 *dh_blob, size_t dh_blob_len);
-
-#endif /* TLSV1_CRED_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_cred.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_cred.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_cred.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_cred.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,40 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_CRED_H
+#define TLSV1_CRED_H
+
+struct tlsv1_credentials {
+	struct x509_certificate *trusted_certs;
+	struct x509_certificate *cert;
+	struct crypto_private_key *key;
+
+	/* Diffie-Hellman parameters */
+	u8 *dh_p; /* prime */
+	size_t dh_p_len;
+	u8 *dh_g; /* generator */
+	size_t dh_g_len;
+};
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void);
+void tlsv1_cred_free(struct tlsv1_credentials *cred);
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+		      const u8 *cert_blob, size_t cert_blob_len,
+		      const char *path);
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+		   const u8 *cert_blob, size_t cert_blob_len);
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+			  const char *private_key,
+			  const char *private_key_passwd,
+			  const u8 *private_key_blob,
+			  size_t private_key_blob_len);
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+		       const u8 *dh_blob, size_t dh_blob_len);
+
+#endif /* TLSV1_CRED_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_record.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_record.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_record.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,409 +0,0 @@
-/*
- * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-
-
-/**
- * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
- * @rl: Pointer to TLS record layer data
- * @cipher_suite: New cipher suite
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to prepare TLS record layer for cipher suite change.
- * tlsv1_record_change_write_cipher() and
- * tlsv1_record_change_read_cipher() functions can then be used to change the
- * currently used ciphers.
- */
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
-				  u16 cipher_suite)
-{
-	const struct tls_cipher_suite *suite;
-	const struct tls_cipher_data *data;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
-		   cipher_suite);
-	rl->cipher_suite = cipher_suite;
-
-	suite = tls_get_cipher_suite(cipher_suite);
-	if (suite == NULL)
-		return -1;
-
-	if (suite->hash == TLS_HASH_MD5) {
-		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
-		rl->hash_size = MD5_MAC_LEN;
-	} else if (suite->hash == TLS_HASH_SHA) {
-		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
-		rl->hash_size = SHA1_MAC_LEN;
-	}
-
-	data = tls_get_cipher_data(suite->cipher);
-	if (data == NULL)
-		return -1;
-
-	rl->key_material_len = data->key_material;
-	rl->iv_size = data->block_size;
-	rl->cipher_alg = data->alg;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for writing.
- */
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
-		   "0x%04x", rl->cipher_suite);
-	rl->write_cipher_suite = rl->cipher_suite;
-	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
-
-	if (rl->write_cbc) {
-		crypto_cipher_deinit(rl->write_cbc);
-		rl->write_cbc = NULL;
-	}
-	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
-		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
-						   rl->write_iv, rl->write_key,
-						   rl->key_material_len);
-		if (rl->write_cbc == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
-				   "cipher");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for reading.
- */
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
-		   "0x%04x", rl->cipher_suite);
-	rl->read_cipher_suite = rl->cipher_suite;
-	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
-
-	if (rl->read_cbc) {
-		crypto_cipher_deinit(rl->read_cbc);
-		rl->read_cbc = NULL;
-	}
-	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
-		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
-						  rl->read_iv, rl->read_key,
-						  rl->key_material_len);
-		if (rl->read_cbc == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
-				   "cipher");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_send - TLS record layer: Send a message
- * @rl: Pointer to TLS record layer data
- * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
- * @buf_size: Maximum buf size
- * @payload_len: Length of the payload
- * @out_len: Buffer for returning the used buf length
- * Returns: 0 on success, -1 on failure
- *
- * This function fills in the TLS record layer header, adds HMAC, and encrypts
- * the data using the current write cipher.
- */
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len)
-{
-	u8 *pos, *ct_start, *length, *payload;
-	struct crypto_hash *hmac;
-	size_t clen;
-
-	pos = buf;
-	/* ContentType type */
-	ct_start = pos;
-	*pos++ = content_type;
-	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* uint16 length */
-	length = pos;
-	WPA_PUT_BE16(length, payload_len);
-	pos += 2;
-
-	/* opaque fragment[TLSPlaintext.length] */
-	payload = pos;
-	pos += payload_len;
-
-	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
-					rl->hash_size);
-		if (hmac == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to initialize HMAC");
-			return -1;
-		}
-		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
-		/* type + version + length + fragment */
-		crypto_hash_update(hmac, ct_start, pos - ct_start);
-		clen = buf + buf_size - pos;
-		if (clen < rl->hash_size) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
-				   "enough room for MAC");
-			crypto_hash_finish(hmac, NULL, NULL);
-			return -1;
-		}
-
-		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to calculate HMAC");
-			return -1;
-		}
-		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
-			    pos, clen);
-		pos += clen;
-		if (rl->iv_size) {
-			size_t len = pos - payload;
-			size_t pad;
-			pad = (len + 1) % rl->iv_size;
-			if (pad)
-				pad = rl->iv_size - pad;
-			if (pos + pad + 1 > buf + buf_size) {
-				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
-					   "block cipher padding");
-				return -1;
-			}
-			os_memset(pos, pad, pad + 1);
-			pos += pad + 1;
-		}
-
-		if (crypto_cipher_encrypt(rl->write_cbc, payload,
-					  payload, pos - payload) < 0)
-			return -1;
-	}
-
-	WPA_PUT_BE16(length, pos - length - 2);
-	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
-
-	*out_len = pos - buf;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_receive - TLS record layer: Process a received message
- * @rl: Pointer to TLS record layer data
- * @in_data: Received data
- * @in_len: Length of the received data
- * @out_data: Buffer for output data (must be at least as long as in_data)
- * @out_len: Set to maximum out_data length by caller; used to return the
- * length of the used data
- * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
- *
- * This function decrypts the received message, verifies HMAC and TLS record
- * layer header.
- */
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t *out_len, u8 *alert)
-{
-	size_t i, rlen, hlen;
-	u8 padlen;
-	struct crypto_hash *hmac;
-	u8 len[2], hash[100];
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
-		    in_data, in_len);
-
-	if (in_len < TLS_RECORD_HEADER_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
-			   (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
-		   "length %d", in_data[0], in_data[1], in_data[2],
-		   WPA_GET_BE16(in_data + 3));
-
-	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
-	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
-	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
-	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
-			   in_data[0]);
-		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
-		return -1;
-	}
-
-	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
-			   "%d.%d", in_data[1], in_data[2]);
-		*alert = TLS_ALERT_PROTOCOL_VERSION;
-		return -1;
-	}
-
-	rlen = WPA_GET_BE16(in_data + 3);
-
-	/* TLSCiphertext must not be more than 2^14+2048 bytes */
-	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
-			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
-		*alert = TLS_ALERT_RECORD_OVERFLOW;
-		return -1;
-	}
-
-	in_data += TLS_RECORD_HEADER_LEN;
-	in_len -= TLS_RECORD_HEADER_LEN;
-
-	if (rlen > in_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
-			   "(rlen=%lu > in_len=%lu)",
-			   (unsigned long) rlen, (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
-	}
-
-	in_len = rlen;
-
-	if (*out_len < in_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
-			   "processing received record");
-		*alert = TLS_ALERT_INTERNAL_ERROR;
-		return -1;
-	}
-
-	os_memcpy(out_data, in_data, in_len);
-	*out_len = in_len;
-
-	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
-					  out_data, in_len) < 0) {
-			*alert = TLS_ALERT_DECRYPTION_FAILED;
-			return -1;
-		}
-		if (rl->iv_size) {
-			if (in_len == 0) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
-					   " (no pad)");
-				*alert = TLS_ALERT_DECODE_ERROR;
-				return -1;
-			}
-			padlen = out_data[in_len - 1];
-			if (padlen >= in_len) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
-					   "length (%u, in_len=%lu) in "
-					   "received record",
-					   padlen, (unsigned long) in_len);
-				*alert = TLS_ALERT_DECRYPTION_FAILED;
-				return -1;
-			}
-			for (i = in_len - padlen; i < in_len; i++) {
-				if (out_data[i] != padlen) {
-					wpa_hexdump(MSG_DEBUG,
-						    "TLSv1: Invalid pad in "
-						    "received record",
-						    out_data + in_len - padlen,
-						    padlen);
-					*alert = TLS_ALERT_DECRYPTION_FAILED;
-					return -1;
-				}
-			}
-
-			*out_len -= padlen + 1;
-		}
-
-		wpa_hexdump(MSG_MSGDUMP,
-			    "TLSv1: Record Layer - Decrypted data",
-			    out_data, in_len);
-
-		if (*out_len < rl->hash_size) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
-				   "hash value");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
-			return -1;
-		}
-
-		*out_len -= rl->hash_size;
-
-		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
-					rl->hash_size);
-		if (hmac == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to initialize HMAC");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
-			return -1;
-		}
-
-		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
-		/* type + version + length + fragment */
-		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
-		WPA_PUT_BE16(len, *out_len);
-		crypto_hash_update(hmac, len, 2);
-		crypto_hash_update(hmac, out_data, *out_len);
-		hlen = sizeof(hash);
-		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to calculate HMAC");
-			return -1;
-		}
-		if (hlen != rl->hash_size ||
-		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
-				   "received message");
-			*alert = TLS_ALERT_BAD_RECORD_MAC;
-			return -1;
-		}
-	}
-
-	/* TLSCompressed must not be more than 2^14+1024 bytes */
-	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
-			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
-		*alert = TLS_ALERT_RECORD_OVERFLOW;
-		return -1;
-	}
-
-	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_record.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_record.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_record.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_record.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,485 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+
+
+/**
+ * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
+ * @rl: Pointer to TLS record layer data
+ * @cipher_suite: New cipher suite
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to prepare TLS record layer for cipher suite change.
+ * tlsv1_record_change_write_cipher() and
+ * tlsv1_record_change_read_cipher() functions can then be used to change the
+ * currently used ciphers.
+ */
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+				  u16 cipher_suite)
+{
+	const struct tls_cipher_suite *suite;
+	const struct tls_cipher_data *data;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
+		   cipher_suite);
+	rl->cipher_suite = cipher_suite;
+
+	suite = tls_get_cipher_suite(cipher_suite);
+	if (suite == NULL)
+		return -1;
+
+	if (suite->hash == TLS_HASH_MD5) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
+		rl->hash_size = MD5_MAC_LEN;
+	} else if (suite->hash == TLS_HASH_SHA) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
+		rl->hash_size = SHA1_MAC_LEN;
+	} else if (suite->hash == TLS_HASH_SHA256) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
+		rl->hash_size = SHA256_MAC_LEN;
+	}
+
+	data = tls_get_cipher_data(suite->cipher);
+	if (data == NULL)
+		return -1;
+
+	rl->key_material_len = data->key_material;
+	rl->iv_size = data->block_size;
+	rl->cipher_alg = data->alg;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for writing.
+ */
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
+		   "0x%04x", rl->cipher_suite);
+	rl->write_cipher_suite = rl->cipher_suite;
+	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+	if (rl->write_cbc) {
+		crypto_cipher_deinit(rl->write_cbc);
+		rl->write_cbc = NULL;
+	}
+	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
+						   rl->write_iv, rl->write_key,
+						   rl->key_material_len);
+		if (rl->write_cbc == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+				   "cipher");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for reading.
+ */
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
+		   "0x%04x", rl->cipher_suite);
+	rl->read_cipher_suite = rl->cipher_suite;
+	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+	if (rl->read_cbc) {
+		crypto_cipher_deinit(rl->read_cbc);
+		rl->read_cbc = NULL;
+	}
+	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
+						  rl->read_iv, rl->read_key,
+						  rl->key_material_len);
+		if (rl->read_cbc == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+				   "cipher");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_send - TLS record layer: Send a message
+ * @rl: Pointer to TLS record layer data
+ * @content_type: Content type (TLS_CONTENT_TYPE_*)
+ * @buf: Buffer for the generated TLS message (needs to have extra space for
+ * header, IV (TLS v1.1), and HMAC)
+ * @buf_size: Maximum buf size
+ * @payload: Payload to be sent
+ * @payload_len: Length of the payload
+ * @out_len: Buffer for returning the used buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function fills in the TLS record layer header, adds HMAC, and encrypts
+ * the data using the current write cipher.
+ */
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len)
+{
+	u8 *pos, *ct_start, *length, *cpayload;
+	struct crypto_hash *hmac;
+	size_t clen;
+	int explicit_iv;
+
+	pos = buf;
+	if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
+		return -1;
+
+	/* ContentType type */
+	ct_start = pos;
+	*pos++ = content_type;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, rl->tls_version);
+	pos += 2;
+	/* uint16 length */
+	length = pos;
+	WPA_PUT_BE16(length, payload_len);
+	pos += 2;
+
+	cpayload = pos;
+	explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
+		rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
+	if (explicit_iv) {
+		/* opaque IV[Cipherspec.block_length] */
+		if (pos + rl->iv_size > buf + buf_size)
+			return -1;
+
+		/*
+		 * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+
+		if (os_get_random(pos, rl->iv_size))
+			return -1;
+		pos += rl->iv_size;
+	}
+
+	/*
+	 * opaque fragment[TLSPlaintext.length]
+	 * (opaque content[TLSCompressed.length] in GenericBlockCipher)
+	 */
+	if (pos + payload_len > buf + buf_size)
+		return -1;
+	os_memmove(pos, payload, payload_len);
+	pos += payload_len;
+
+	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		/*
+		 * MAC calculated over seq_num + TLSCompressed.type +
+		 * TLSCompressed.version + TLSCompressed.length +
+		 * TLSCompressed.fragment
+		 */
+		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
+					rl->hash_size);
+		if (hmac == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to initialize HMAC");
+			return -1;
+		}
+		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
+		/* type + version + length + fragment */
+		crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
+		crypto_hash_update(hmac, payload, payload_len);
+		clen = buf + buf_size - pos;
+		if (clen < rl->hash_size) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
+				   "enough room for MAC");
+			crypto_hash_finish(hmac, NULL, NULL);
+			return -1;
+		}
+
+		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
+			return -1;
+		}
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
+			    pos, clen);
+		pos += clen;
+		if (rl->iv_size) {
+			size_t len = pos - cpayload;
+			size_t pad;
+			pad = (len + 1) % rl->iv_size;
+			if (pad)
+				pad = rl->iv_size - pad;
+			if (pos + pad + 1 > buf + buf_size) {
+				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
+					   "block cipher padding");
+				return -1;
+			}
+			os_memset(pos, pad, pad + 1);
+			pos += pad + 1;
+		}
+
+		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+					  cpayload, pos - cpayload) < 0)
+			return -1;
+	}
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
+
+	*out_len = pos - buf;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_receive - TLS record layer: Process a received message
+ * @rl: Pointer to TLS record layer data
+ * @in_data: Received data
+ * @in_len: Length of the received data
+ * @out_data: Buffer for output data (must be at least as long as in_data)
+ * @out_len: Set to maximum out_data length by caller; used to return the
+ * length of the used data
+ * @alert: Buffer for returning an alert value on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ *	complete (more data needed), or -1 on failure
+ *
+ * This function decrypts the received message, verifies HMAC and TLS record
+ * layer header.
+ */
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t *out_len, u8 *alert)
+{
+	size_t i, rlen, hlen;
+	u8 padlen;
+	struct crypto_hash *hmac;
+	u8 len[2], hash[100];
+	int force_mac_error = 0;
+	u8 ct;
+
+	if (in_len < TLS_RECORD_HEADER_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+			   "need more data",
+			   (unsigned long) in_len);
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+			    in_data, in_len);
+		return 0;
+	}
+
+	ct = in_data[0];
+	rlen = WPA_GET_BE16(in_data + 3);
+	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
+		   "length %d", ct, in_data[1], in_data[2], (int) rlen);
+
+	/*
+	 * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
+	 * protocol version in record layer. As such, accept any {03,xx} value
+	 * to remain compatible with existing implementations.
+	 */
+	if (in_data[1] != 0x03) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
+			   "%u.%u", in_data[1], in_data[2]);
+		*alert = TLS_ALERT_PROTOCOL_VERSION;
+		return -1;
+	}
+
+	/* TLSCiphertext must not be more than 2^14+2048 bytes */
+	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
+		*alert = TLS_ALERT_RECORD_OVERFLOW;
+		return -1;
+	}
+
+	in_data += TLS_RECORD_HEADER_LEN;
+	in_len -= TLS_RECORD_HEADER_LEN;
+
+	if (rlen > in_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
+			   "(rlen=%lu > in_len=%lu)",
+			   (unsigned long) rlen, (unsigned long) in_len);
+		return 0;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+		    in_data, rlen);
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+	    ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+	    ct != TLS_CONTENT_TYPE_ALERT &&
+	    ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+			   "content type 0x%x", ct);
+		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+		return -1;
+	}
+
+	in_len = rlen;
+
+	if (*out_len < in_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
+			   "processing received record");
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+
+	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		size_t plen;
+		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
+					  out_data, in_len) < 0) {
+			*alert = TLS_ALERT_DECRYPTION_FAILED;
+			return -1;
+		}
+		plen = in_len;
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
+				"data", out_data, plen);
+
+		if (rl->iv_size) {
+			/*
+			 * TLS v1.0 defines different alert values for various
+			 * failures. That may information to aid in attacks, so
+			 * use the same bad_record_mac alert regardless of the
+			 * issues.
+			 *
+			 * In addition, instead of returning immediately on
+			 * error, run through the MAC check to make timing
+			 * attacks more difficult.
+			 */
+
+			if (rl->tls_version >= TLS_VERSION_1_1) {
+				/* Remove opaque IV[Cipherspec.block_length] */
+				if (plen < rl->iv_size) {
+					wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
+						   "enough room for IV");
+					force_mac_error = 1;
+					goto check_mac;
+				}
+				os_memmove(out_data, out_data + rl->iv_size,
+					   plen - rl->iv_size);
+				plen -= rl->iv_size;
+			}
+
+			/* Verify and remove padding */
+			if (plen == 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
+					   " (no pad)");
+				force_mac_error = 1;
+				goto check_mac;
+			}
+			padlen = out_data[plen - 1];
+			if (padlen >= plen) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
+					   "length (%u, plen=%lu) in "
+					   "received record",
+					   padlen, (unsigned long) plen);
+				force_mac_error = 1;
+				goto check_mac;
+			}
+			for (i = plen - padlen - 1; i < plen - 1; i++) {
+				if (out_data[i] != padlen) {
+					wpa_hexdump(MSG_DEBUG,
+						    "TLSv1: Invalid pad in "
+						    "received record",
+						    out_data + plen - padlen -
+						    1, padlen + 1);
+					force_mac_error = 1;
+					goto check_mac;
+				}
+			}
+
+			plen -= padlen + 1;
+
+			wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+					"Decrypted data with IV and padding "
+					"removed", out_data, plen);
+		}
+
+	check_mac:
+		if (plen < rl->hash_size) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
+				   "hash value");
+			*alert = TLS_ALERT_BAD_RECORD_MAC;
+			return -1;
+		}
+
+		plen -= rl->hash_size;
+
+		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
+					rl->hash_size);
+		if (hmac == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to initialize HMAC");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
+			return -1;
+		}
+
+		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
+		/* type + version + length + fragment */
+		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
+		WPA_PUT_BE16(len, plen);
+		crypto_hash_update(hmac, len, 2);
+		crypto_hash_update(hmac, out_data, plen);
+		hlen = sizeof(hash);
+		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
+			return -1;
+		}
+		if (hlen != rl->hash_size ||
+		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
+		    force_mac_error) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
+				   "received message (force_mac_error=%d)",
+				   force_mac_error);
+			*alert = TLS_ALERT_BAD_RECORD_MAC;
+			return -1;
+		}
+
+		*out_len = plen;
+	} else {
+		os_memcpy(out_data, in_data, in_len);
+		*out_len = in_len;
+	}
+
+	/* TLSCompressed must not be more than 2^14+1024 bytes */
+	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
+		*alert = TLS_ALERT_RECORD_OVERFLOW;
+		return -1;
+	}
+
+	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
+
+	return TLS_RECORD_HEADER_LEN + rlen;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_record.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_record.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_record.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,74 +0,0 @@
-/*
- * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_RECORD_H
-#define TLSV1_RECORD_H
-
-#include "crypto/crypto.h"
-
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
-#define TLS_MAX_WRITE_KEY_LEN 32
-#define TLS_MAX_IV_LEN 16
-#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
-				    TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
-
-#define TLS_SEQ_NUM_LEN 8
-#define TLS_RECORD_HEADER_LEN 5
-
-/* ContentType */
-enum {
-	TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
-	TLS_CONTENT_TYPE_ALERT = 21,
-	TLS_CONTENT_TYPE_HANDSHAKE = 22,
-	TLS_CONTENT_TYPE_APPLICATION_DATA = 23
-};
-
-struct tlsv1_record_layer {
-	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
-	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
-	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
-	u8 read_key[TLS_MAX_WRITE_KEY_LEN];
-	u8 write_iv[TLS_MAX_IV_LEN];
-	u8 read_iv[TLS_MAX_IV_LEN];
-
-	size_t hash_size;
-	size_t key_material_len;
-	size_t iv_size; /* also block_size */
-
-	enum crypto_hash_alg hash_alg;
-	enum crypto_cipher_alg cipher_alg;
-
-	u8 write_seq_num[TLS_SEQ_NUM_LEN];
-	u8 read_seq_num[TLS_SEQ_NUM_LEN];
-
-	u16 cipher_suite;
-	u16 write_cipher_suite;
-	u16 read_cipher_suite;
-
-	struct crypto_cipher *write_cbc;
-	struct crypto_cipher *read_cbc;
-};
-
-
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
-				  u16 cipher_suite);
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len);
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t *out_len, u8 *alert);
-
-#endif /* TLSV1_RECORD_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_record.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_record.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_record.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_record.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_RECORD_H
+#define TLSV1_RECORD_H
+
+#include "crypto/crypto.h"
+
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 32
+#define TLS_MAX_WRITE_KEY_LEN 32
+#define TLS_MAX_IV_LEN 16
+#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
+				    TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
+
+#define TLS_SEQ_NUM_LEN 8
+#define TLS_RECORD_HEADER_LEN 5
+
+/* ContentType */
+enum {
+	TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
+	TLS_CONTENT_TYPE_ALERT = 21,
+	TLS_CONTENT_TYPE_HANDSHAKE = 22,
+	TLS_CONTENT_TYPE_APPLICATION_DATA = 23
+};
+
+struct tlsv1_record_layer {
+	u16 tls_version;
+
+	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
+	u8 read_key[TLS_MAX_WRITE_KEY_LEN];
+	u8 write_iv[TLS_MAX_IV_LEN];
+	u8 read_iv[TLS_MAX_IV_LEN];
+
+	size_t hash_size;
+	size_t key_material_len;
+	size_t iv_size; /* also block_size */
+
+	enum crypto_hash_alg hash_alg;
+	enum crypto_cipher_alg cipher_alg;
+
+	u8 write_seq_num[TLS_SEQ_NUM_LEN];
+	u8 read_seq_num[TLS_SEQ_NUM_LEN];
+
+	u16 cipher_suite;
+	u16 write_cipher_suite;
+	u16 read_cipher_suite;
+
+	struct crypto_cipher *write_cbc;
+	struct crypto_cipher *read_cbc;
+};
+
+
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+				  u16 cipher_suite);
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len);
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t *out_len, u8 *alert);
+
+#endif /* TLSV1_RECORD_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_server.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_server.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,592 +0,0 @@
-/*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_server.h"
-#include "tlsv1_server_i.h"
-
-/* TODO:
- * Support for a message fragmented across several records (RFC 2246, 6.2.1)
- */
-
-
-void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
-{
-	conn->alert_level = level;
-	conn->alert_description = description;
-}
-
-
-int tlsv1_server_derive_keys(struct tlsv1_server *conn,
-			     const u8 *pre_master_secret,
-			     size_t pre_master_secret_len)
-{
-	u8 seed[2 * TLS_RANDOM_LEN];
-	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
-	u8 *pos;
-	size_t key_block_len;
-
-	if (pre_master_secret) {
-		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
-				pre_master_secret, pre_master_secret_len);
-		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
-			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
-			    "master secret", seed, 2 * TLS_RANDOM_LEN,
-			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
-				   "master_secret");
-			return -1;
-		}
-		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
-				conn->master_secret, TLS_MASTER_SECRET_LEN);
-	}
-
-	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
-	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
-	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
-		    key_block, key_block_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
-		return -1;
-	}
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
-			key_block, key_block_len);
-
-	pos = key_block;
-
-	/* client_write_MAC_secret */
-	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
-	pos += conn->rl.hash_size;
-	/* server_write_MAC_secret */
-	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
-	pos += conn->rl.hash_size;
-
-	/* client_write_key */
-	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
-	pos += conn->rl.key_material_len;
-	/* server_write_key */
-	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
-	pos += conn->rl.key_material_len;
-
-	/* client_write_IV */
-	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-	/* server_write_IV */
-	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_server_handshake - Process TLS handshake
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @in_data: Input data from TLS peer
- * @in_len: Input data length
- * @out_len: Length of the output buffer.
- * Returns: Pointer to output data, %NULL on failure
- */
-u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
-			    const u8 *in_data, size_t in_len,
-			    size_t *out_len)
-{
-	const u8 *pos, *end;
-	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
-	size_t in_msg_len;
-
-	if (in_data == NULL || in_len == 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
-		return NULL;
-	}
-
-	pos = in_data;
-	end = in_data + in_len;
-	in_msg = os_malloc(in_len);
-	if (in_msg == NULL)
-		return NULL;
-
-	/* Each received packet may include multiple records */
-	while (pos < end) {
-		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
-				   "record failed");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			goto failed;
-		}
-		ct = pos[0];
-
-		in_pos = in_msg;
-		in_end = in_msg + in_msg_len;
-
-		/* Each received record may include multiple messages of the
-		 * same ContentType. */
-		while (in_pos < in_end) {
-			in_msg_len = in_end - in_pos;
-			if (tlsv1_server_process_handshake(conn, ct, in_pos,
-							   &in_msg_len) < 0)
-				goto failed;
-			in_pos += in_msg_len;
-		}
-
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
-	}
-
-	os_free(in_msg);
-	in_msg = NULL;
-
-	msg = tlsv1_server_handshake_write(conn, out_len);
-
-failed:
-	os_free(in_msg);
-	if (conn->alert_level) {
-		if (conn->state == FAILED) {
-			/* Avoid alert loops */
-			wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
-			os_free(msg);
-			return NULL;
-		}
-		conn->state = FAILED;
-		os_free(msg);
-		msg = tlsv1_server_send_alert(conn, conn->alert_level,
-					      conn->alert_description,
-					      out_len);
-	}
-
-	return msg;
-}
-
-
-/**
- * tlsv1_server_encrypt - Encrypt data into TLS tunnel
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @in_data: Pointer to plaintext data to be encrypted
- * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length 
- * Returns: Number of bytes written to out_data, -1 on failure
- *
- * This function is used after TLS handshake has been completed successfully to
- * send data in the encrypted tunnel.
- */
-int tlsv1_server_encrypt(struct tlsv1_server *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
-{
-	size_t rlen;
-
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
-			in_data, in_len);
-
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	return rlen;
-}
-
-
-/**
- * tlsv1_server_decrypt - Decrypt data from TLS tunnel
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @in_data: Pointer to input buffer (encrypted TLS data)
- * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
- *
- * This function is used after TLS handshake has been completed successfully to
- * receive data from the encrypted tunnel.
- */
-int tlsv1_server_decrypt(struct tlsv1_server *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
-{
-	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
-	size_t olen;
-
-	pos = in_data;
-	in_end = in_data + in_len;
-	out_pos = out_data;
-	out_end = out_data + out_len;
-
-	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
-		}
-
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
-		}
-		out_pos += olen;
-		if (out_pos > out_end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
-				   "for processing the received record");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_INTERNAL_ERROR);
-			return -1;
-		}
-
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
-	}
-
-	return out_pos - out_data;
-}
-
-
-/**
- * tlsv1_server_global_init - Initialize TLSv1 server
- * Returns: 0 on success, -1 on failure
- *
- * This function must be called before using any other TLSv1 server functions.
- */
-int tlsv1_server_global_init(void)
-{
-	return crypto_global_init();
-}
-
-
-/**
- * tlsv1_server_global_deinit - Deinitialize TLSv1 server
- *
- * This function can be used to deinitialize the TLSv1 server that was
- * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
- * can be called after this before calling tlsv1_server_global_init() again.
- */
-void tlsv1_server_global_deinit(void)
-{
-	crypto_global_deinit();
-}
-
-
-/**
- * tlsv1_server_init - Initialize TLSv1 server connection
- * @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
- * Returns: Pointer to TLSv1 server connection data or %NULL on failure
- */
-struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
-{
-	struct tlsv1_server *conn;
-	size_t count;
-	u16 *suites;
-
-	conn = os_zalloc(sizeof(*conn));
-	if (conn == NULL)
-		return NULL;
-
-	conn->cred = cred;
-
-	conn->state = CLIENT_HELLO;
-
-	if (tls_verify_hash_init(&conn->verify) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
-			   "hash");
-		os_free(conn);
-		return NULL;
-	}
-
-	count = 0;
-	suites = conn->cipher_suites;
-#ifndef CONFIG_CRYPTO_INTERNAL
-	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
-	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
-	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
-	conn->num_cipher_suites = count;
-
-	return conn;
-}
-
-
-static void tlsv1_server_clear_data(struct tlsv1_server *conn)
-{
-	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
-	tlsv1_record_change_write_cipher(&conn->rl);
-	tlsv1_record_change_read_cipher(&conn->rl);
-	tls_verify_hash_free(&conn->verify);
-
-	crypto_public_key_free(conn->client_rsa_key);
-	conn->client_rsa_key = NULL;
-
-	os_free(conn->session_ticket);
-	conn->session_ticket = NULL;
-	conn->session_ticket_len = 0;
-	conn->use_session_ticket = 0;
-
-	os_free(conn->dh_secret);
-	conn->dh_secret = NULL;
-	conn->dh_secret_len = 0;
-}
-
-
-/**
- * tlsv1_server_deinit - Deinitialize TLSv1 server connection
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- */
-void tlsv1_server_deinit(struct tlsv1_server *conn)
-{
-	tlsv1_server_clear_data(conn);
-	os_free(conn);
-}
-
-
-/**
- * tlsv1_server_established - Check whether connection has been established
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * Returns: 1 if connection is established, 0 if not
- */
-int tlsv1_server_established(struct tlsv1_server *conn)
-{
-	return conn->state == ESTABLISHED;
-}
-
-
-/**
- * tlsv1_server_prf - Use TLS-PRF to derive keying material
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @out: Buffer for output data from TLS-PRF
- * @out_len: Length of the output buffer
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
-		     int server_random_first, u8 *out, size_t out_len)
-{
-	u8 seed[2 * TLS_RANDOM_LEN];
-
-	if (conn->state != ESTABLISHED)
-		return -1;
-
-	if (server_random_first) {
-		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
-			  TLS_RANDOM_LEN);
-	} else {
-		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
-		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
-			  TLS_RANDOM_LEN);
-	}
-
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
-}
-
-
-/**
- * tlsv1_server_get_cipher - Get current cipher name
- * @conn: TLSv1 server connection data from tlsv1_server_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 tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
-			    size_t buflen)
-{
-	char *cipher;
-
-	switch (conn->rl.cipher_suite) {
-	case TLS_RSA_WITH_RC4_128_MD5:
-		cipher = "RC4-MD5";
-		break;
-	case TLS_RSA_WITH_RC4_128_SHA:
-		cipher = "RC4-SHA";
-		break;
-	case TLS_RSA_WITH_DES_CBC_SHA:
-		cipher = "DES-CBC-SHA";
-		break;
-	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-		cipher = "DES-CBC3-SHA";
-		break;
-	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
-		cipher = "ADH-AES-128-SHA";
-		break;
-	case TLS_RSA_WITH_AES_256_CBC_SHA:
-		cipher = "AES-256-SHA";
-		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
-		break;
-	default:
-		return -1;
-	}
-
-	if (os_strlcpy(buf, cipher, buflen) >= buflen)
-		return -1;
-	return 0;
-}
-
-
-/**
- * tlsv1_server_shutdown - Shutdown TLS connection
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_server_shutdown(struct tlsv1_server *conn)
-{
-	conn->state = CLIENT_HELLO;
-
-	if (tls_verify_hash_init(&conn->verify) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
-			   "hash");
-		return -1;
-	}
-
-	tlsv1_server_clear_data(conn);
-
-	return 0;
-}
-
-
-/**
- * tlsv1_server_resumed - Was session resumption used
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * Returns: 1 if current session used session resumption, 0 if not
- */
-int tlsv1_server_resumed(struct tlsv1_server *conn)
-{
-	return 0;
-}
-
-
-/**
- * tlsv1_server_get_keys - Get master key and random data from TLS connection
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @keys: Structure of key/random data (filled on success)
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
-{
-	os_memset(keys, 0, sizeof(*keys));
-	if (conn->state == CLIENT_HELLO)
-		return -1;
-
-	keys->client_random = conn->client_random;
-	keys->client_random_len = TLS_RANDOM_LEN;
-
-	if (conn->state != SERVER_HELLO) {
-		keys->server_random = conn->server_random;
-		keys->server_random_len = TLS_RANDOM_LEN;
-		keys->master_key = conn->master_secret;
-		keys->master_key_len = TLS_MASTER_SECRET_LEN;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_server_get_keyblock_size - Get TLS key_block size
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
-{
-	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
-		return -1;
-
-	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-		    conn->rl.iv_size);
-}
-
-
-/**
- * tlsv1_server_set_cipher_list - Configure acceptable cipher suites
- * @conn: TLSv1 server connection data from tlsv1_server_init()
- * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
- * (TLS_CIPHER_*).
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
-{
-	size_t count;
-	u16 *suites;
-
-	/* TODO: implement proper configuration of cipher suites */
-	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
-		count = 0;
-		suites = conn->cipher_suites;
-#ifndef CONFIG_CRYPTO_INTERNAL
-		suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
-		suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-		suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-		suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
-		suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
-#ifndef CONFIG_CRYPTO_INTERNAL
-		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
-#endif /* CONFIG_CRYPTO_INTERNAL */
-		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
-		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
-		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
-		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
-		conn->num_cipher_suites = count;
-	}
-
-	return 0;
-}
-
-
-int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
-{
-	conn->verify_peer = verify_peer;
-	return 0;
-}
-
-
-void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
-					tlsv1_server_session_ticket_cb cb,
-					void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
-		   cb, ctx);
-	conn->session_ticket_cb = cb;
-	conn->session_ticket_cb_ctx = ctx;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_server.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_server.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_server.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,620 @@
+/*
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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 "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+/* TODO:
+ * Support for a message fragmented across several records (RFC 2246, 6.2.1)
+ */
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
+{
+	conn->alert_level = level;
+	conn->alert_description = description;
+}
+
+
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+			     const u8 *pre_master_secret,
+			     size_t pre_master_secret_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
+	u8 *pos;
+	size_t key_block_len;
+
+	if (pre_master_secret) {
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
+				pre_master_secret, pre_master_secret_len);
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
+			    "master secret", seed, 2 * TLS_RANDOM_LEN,
+			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
+				   "master_secret");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
+				conn->master_secret, TLS_MASTER_SECRET_LEN);
+	}
+
+	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
+	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+			     conn->rl.iv_size);
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
+		    key_block, key_block_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
+			key_block, key_block_len);
+
+	pos = key_block;
+
+	/* client_write_MAC_secret */
+	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+	/* server_write_MAC_secret */
+	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+
+	/* client_write_key */
+	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+	/* server_write_key */
+	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+
+	/* client_write_IV */
+	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+	pos += conn->rl.iv_size;
+	/* server_write_IV */
+	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+	pos += conn->rl.iv_size;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_handshake - Process TLS handshake
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Input data from TLS peer
+ * @in_len: Input data length
+ * @out_len: Length of the output buffer.
+ * Returns: Pointer to output data, %NULL on failure
+ */
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+			    const u8 *in_data, size_t in_len,
+			    size_t *out_len)
+{
+	const u8 *pos, *end;
+	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+	size_t in_msg_len;
+	int used;
+
+	if (in_data == NULL || in_len == 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
+		return NULL;
+	}
+
+	pos = in_data;
+	end = in_data + in_len;
+	in_msg = os_malloc(in_len);
+	if (in_msg == NULL)
+		return NULL;
+
+	/* Each received packet may include multiple records */
+	while (pos < end) {
+		in_msg_len = in_len;
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
+				   "record failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
+		ct = pos[0];
+
+		in_pos = in_msg;
+		in_end = in_msg + in_msg_len;
+
+		/* Each received record may include multiple messages of the
+		 * same ContentType. */
+		while (in_pos < in_end) {
+			in_msg_len = in_end - in_pos;
+			if (tlsv1_server_process_handshake(conn, ct, in_pos,
+							   &in_msg_len) < 0)
+				goto failed;
+			in_pos += in_msg_len;
+		}
+
+		pos += used;
+	}
+
+	os_free(in_msg);
+	in_msg = NULL;
+
+	msg = tlsv1_server_handshake_write(conn, out_len);
+
+failed:
+	os_free(in_msg);
+	if (conn->alert_level) {
+		if (conn->state == FAILED) {
+			/* Avoid alert loops */
+			wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
+			os_free(msg);
+			return NULL;
+		}
+		conn->state = FAILED;
+		os_free(msg);
+		msg = tlsv1_server_send_alert(conn, conn->alert_level,
+					      conn->alert_description,
+					      out_len);
+	}
+
+	return msg;
+}
+
+
+/**
+ * tlsv1_server_encrypt - Encrypt data into TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to plaintext data to be encrypted
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (encrypted TLS data)
+ * @out_len: Maximum out_data length 
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel.
+ */
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len)
+{
+	size_t rlen;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
+			in_data, in_len);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return rlen;
+}
+
+
+/**
+ * tlsv1_server_decrypt - Decrypt data from TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to input buffer (encrypted TLS data)
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel.
+ */
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len)
+{
+	const u8 *in_end, *pos;
+	int used;
+	u8 alert, *out_end, *out_pos, ct;
+	size_t olen;
+
+	pos = in_data;
+	in_end = in_data + in_len;
+	out_pos = out_data;
+	out_end = out_data + out_len;
+
+	while (pos < in_end) {
+		ct = pos[0];
+		olen = out_end - out_pos;
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+				   "failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_DECODE_ERROR);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   out_pos[1]);
+			return -1;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+				   "0x%x", pos[0]);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		out_pos += olen;
+		if (out_pos > out_end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
+				   "for processing the received record");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+
+		pos += used;
+	}
+
+	return out_pos - out_data;
+}
+
+
+/**
+ * tlsv1_server_global_init - Initialize TLSv1 server
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before using any other TLSv1 server functions.
+ */
+int tlsv1_server_global_init(void)
+{
+	return crypto_global_init();
+}
+
+
+/**
+ * tlsv1_server_global_deinit - Deinitialize TLSv1 server
+ *
+ * This function can be used to deinitialize the TLSv1 server that was
+ * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
+ * can be called after this before calling tlsv1_server_global_init() again.
+ */
+void tlsv1_server_global_deinit(void)
+{
+	crypto_global_deinit();
+}
+
+
+/**
+ * tlsv1_server_init - Initialize TLSv1 server connection
+ * @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
+ * Returns: Pointer to TLSv1 server connection data or %NULL on failure
+ */
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
+{
+	struct tlsv1_server *conn;
+	size_t count;
+	u16 *suites;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->cred = cred;
+
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
+			   "hash");
+		os_free(conn);
+		return NULL;
+	}
+
+	count = 0;
+	suites = conn->cipher_suites;
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+	conn->num_cipher_suites = count;
+
+	return conn;
+}
+
+
+static void tlsv1_server_clear_data(struct tlsv1_server *conn)
+{
+	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+	tlsv1_record_change_write_cipher(&conn->rl);
+	tlsv1_record_change_read_cipher(&conn->rl);
+	tls_verify_hash_free(&conn->verify);
+
+	crypto_public_key_free(conn->client_rsa_key);
+	conn->client_rsa_key = NULL;
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+	conn->session_ticket_len = 0;
+	conn->use_session_ticket = 0;
+
+	os_free(conn->dh_secret);
+	conn->dh_secret = NULL;
+	conn->dh_secret_len = 0;
+}
+
+
+/**
+ * tlsv1_server_deinit - Deinitialize TLSv1 server connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ */
+void tlsv1_server_deinit(struct tlsv1_server *conn)
+{
+	tlsv1_server_clear_data(conn);
+	os_free(conn);
+}
+
+
+/**
+ * tlsv1_server_established - Check whether connection has been established
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if connection is established, 0 if not
+ */
+int tlsv1_server_established(struct tlsv1_server *conn)
+{
+	return conn->state == ESTABLISHED;
+}
+
+
+/**
+ * tlsv1_server_prf - Use TLS-PRF to derive keying material
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	if (conn->state != ESTABLISHED)
+		return -1;
+
+	if (server_random_first) {
+		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
+			  TLS_RANDOM_LEN);
+	} else {
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+	}
+
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
+		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+}
+
+
+/**
+ * tlsv1_server_get_cipher - Get current cipher name
+ * @conn: TLSv1 server connection data from tlsv1_server_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 tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+			    size_t buflen)
+{
+	char *cipher;
+
+	switch (conn->rl.cipher_suite) {
+	case TLS_RSA_WITH_RC4_128_MD5:
+		cipher = "RC4-MD5";
+		break;
+	case TLS_RSA_WITH_RC4_128_SHA:
+		cipher = "RC4-SHA";
+		break;
+	case TLS_RSA_WITH_DES_CBC_SHA:
+		cipher = "DES-CBC-SHA";
+		break;
+	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+		cipher = "ADH-AES-128-SHA";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "AES-256-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	default:
+		return -1;
+	}
+
+	if (os_strlcpy(buf, cipher, buflen) >= buflen)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_shutdown - Shutdown TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_shutdown(struct tlsv1_server *conn)
+{
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
+			   "hash");
+		return -1;
+	}
+
+	tlsv1_server_clear_data(conn);
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_resumed - Was session resumption used
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tlsv1_server_resumed(struct tlsv1_server *conn)
+{
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keys - Get master key and random data from TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
+{
+	os_memset(keys, 0, sizeof(*keys));
+	if (conn->state == CLIENT_HELLO)
+		return -1;
+
+	keys->client_random = conn->client_random;
+	keys->client_random_len = TLS_RANDOM_LEN;
+
+	if (conn->state != SERVER_HELLO) {
+		keys->server_random = conn->server_random;
+		keys->server_random_len = TLS_RANDOM_LEN;
+		keys->master_key = conn->master_secret;
+		keys->master_key_len = TLS_MASTER_SECRET_LEN;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keyblock_size - Get TLS key_block size
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
+{
+	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
+		return -1;
+
+	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+		    conn->rl.iv_size);
+}
+
+
+/**
+ * tlsv1_server_set_cipher_list - Configure acceptable cipher suites
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
+{
+	size_t count;
+	u16 *suites;
+
+	/* TODO: implement proper configuration of cipher suites */
+	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
+		count = 0;
+		suites = conn->cipher_suites;
+		suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+		suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+		suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+		suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+		suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
+		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+		conn->num_cipher_suites = count;
+	}
+
+	return 0;
+}
+
+
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
+{
+	conn->verify_peer = verify_peer;
+	return 0;
+}
+
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+					tlsv1_server_session_ticket_cb cb,
+					void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+		   cb, ctx);
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_server.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_server.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,54 +0,0 @@
-/*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_SERVER_H
-#define TLSV1_SERVER_H
-
-#include "tlsv1_cred.h"
-
-struct tlsv1_server;
-
-int tlsv1_server_global_init(void);
-void tlsv1_server_global_deinit(void);
-struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
-void tlsv1_server_deinit(struct tlsv1_server *conn);
-int tlsv1_server_established(struct tlsv1_server *conn);
-int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
-		     int server_random_first, u8 *out, size_t out_len);
-u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
-			    const u8 *in_data, size_t in_len, size_t *out_len);
-int tlsv1_server_encrypt(struct tlsv1_server *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
-int tlsv1_server_decrypt(struct tlsv1_server *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
-int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
-			    size_t buflen);
-int tlsv1_server_shutdown(struct tlsv1_server *conn);
-int tlsv1_server_resumed(struct tlsv1_server *conn);
-int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
-int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
-int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
-int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);
-
-typedef int (*tlsv1_server_session_ticket_cb)
-(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
- const u8 *server_random, u8 *master_secret);
-
-void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
-					tlsv1_server_session_ticket_cb cb,
-					void *ctx);
-
-#endif /* TLSV1_SERVER_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_server.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_server.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_server.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,48 @@
+/*
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_SERVER_H
+#define TLSV1_SERVER_H
+
+#include "tlsv1_cred.h"
+
+struct tlsv1_server;
+
+int tlsv1_server_global_init(void);
+void tlsv1_server_global_deinit(void);
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
+void tlsv1_server_deinit(struct tlsv1_server *conn);
+int tlsv1_server_established(struct tlsv1_server *conn);
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len);
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+			    const u8 *in_data, size_t in_len, size_t *out_len);
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len);
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len);
+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+			    size_t buflen);
+int tlsv1_server_shutdown(struct tlsv1_server *conn);
+int tlsv1_server_resumed(struct tlsv1_server *conn);
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);
+
+typedef int (*tlsv1_server_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+					tlsv1_server_session_ticket_cb cb,
+					void *ctx);
+
+#endif /* TLSV1_SERVER_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_server_i.h
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_server_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,77 +0,0 @@
-/*
- * TLSv1 server - internal structures
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TLSV1_SERVER_I_H
-#define TLSV1_SERVER_I_H
-
-struct tlsv1_server {
-	enum {
-		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
-		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
-		SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,
-		CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,
-		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,
-		ESTABLISHED, FAILED
-	} state;
-
-	struct tlsv1_record_layer rl;
-
-	u8 session_id[TLS_SESSION_ID_MAX_LEN];
-	size_t session_id_len;
-	u8 client_random[TLS_RANDOM_LEN];
-	u8 server_random[TLS_RANDOM_LEN];
-	u8 master_secret[TLS_MASTER_SECRET_LEN];
-
-	u8 alert_level;
-	u8 alert_description;
-
-	struct crypto_public_key *client_rsa_key;
-
-	struct tls_verify_hash verify;
-
-#define MAX_CIPHER_COUNT 30
-	u16 cipher_suites[MAX_CIPHER_COUNT];
-	size_t num_cipher_suites;
-
-	u16 cipher_suite;
-
-	struct tlsv1_credentials *cred;
-
-	int verify_peer;
-	u16 client_version;
-
-	u8 *session_ticket;
-	size_t session_ticket_len;
-
-	tlsv1_server_session_ticket_cb session_ticket_cb;
-	void *session_ticket_cb_ctx;
-
-	int use_session_ticket;
-
-	u8 *dh_secret;
-	size_t dh_secret_len;
-};
-
-
-void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
-int tlsv1_server_derive_keys(struct tlsv1_server *conn,
-			     const u8 *pre_master_secret,
-			     size_t pre_master_secret_len);
-u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len);
-u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
-			     u8 description, size_t *out_len);
-int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
-				   const u8 *buf, size_t *len);
-
-#endif /* TLSV1_SERVER_I_H */

Copied: vendor/wpa/2.0/src/tls/tlsv1_server_i.h (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_server_i.h)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_server_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * TLSv1 server - internal structures
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLSV1_SERVER_I_H
+#define TLSV1_SERVER_I_H
+
+struct tlsv1_server {
+	enum {
+		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+		SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,
+		CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,
+		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,
+		ESTABLISHED, FAILED
+	} state;
+
+	struct tlsv1_record_layer rl;
+
+	u8 session_id[TLS_SESSION_ID_MAX_LEN];
+	size_t session_id_len;
+	u8 client_random[TLS_RANDOM_LEN];
+	u8 server_random[TLS_RANDOM_LEN];
+	u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+	u8 alert_level;
+	u8 alert_description;
+
+	struct crypto_public_key *client_rsa_key;
+
+	struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+	u16 cipher_suites[MAX_CIPHER_COUNT];
+	size_t num_cipher_suites;
+
+	u16 cipher_suite;
+
+	struct tlsv1_credentials *cred;
+
+	int verify_peer;
+	u16 client_version;
+
+	u8 *session_ticket;
+	size_t session_ticket_len;
+
+	tlsv1_server_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	int use_session_ticket;
+
+	u8 *dh_secret;
+	size_t dh_secret_len;
+};
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+			     const u8 *pre_master_secret,
+			     size_t pre_master_secret_len);
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len);
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+			     u8 description, size_t *out_len);
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+				   const u8 *buf, size_t *len);
+
+#endif /* TLSV1_SERVER_I_H */

Deleted: vendor/wpa/2.0/src/tls/tlsv1_server_read.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_server_read.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_read.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1134 +0,0 @@
-/*
- * TLSv1 server - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "x509v3.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_server.h"
-#include "tlsv1_server_i.h"
-
-
-static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len);
-static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
-					  u8 ct, const u8 *in_data,
-					  size_t *in_len);
-
-
-static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
-				    const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end, *c;
-	size_t left, len, i, j;
-	u16 cipher_suite;
-	u16 num_suites;
-	int compr_null_found;
-	u16 ext_type, ext_len;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4)
-		goto decode_error;
-
-	/* HandshakeType msg_type */
-	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ClientHello)", *pos);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
-	pos++;
-	/* uint24 length */
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left)
-		goto decode_error;
-
-	/* body - ClientHello */
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
-	end = pos + len;
-
-	/* ProtocolVersion client_version */
-	if (end - pos < 2)
-		goto decode_error;
-	conn->client_version = WPA_GET_BE16(pos);
-	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
-		   conn->client_version >> 8, conn->client_version & 0xff);
-	if (conn->client_version < TLS_VERSION) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ClientHello");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_PROTOCOL_VERSION);
-		return -1;
-	}
-	pos += 2;
-
-	/* Random random */
-	if (end - pos < TLS_RANDOM_LEN)
-		goto decode_error;
-
-	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
-	pos += TLS_RANDOM_LEN;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
-		    conn->client_random, TLS_RANDOM_LEN);
-
-	/* SessionID session_id */
-	if (end - pos < 1)
-		goto decode_error;
-	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
-		goto decode_error;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
-	pos += 1 + *pos;
-	/* TODO: add support for session resumption */
-
-	/* CipherSuite cipher_suites<2..2^16-1> */
-	if (end - pos < 2)
-		goto decode_error;
-	num_suites = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < num_suites)
-		goto decode_error;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
-		    pos, num_suites);
-	if (num_suites & 1)
-		goto decode_error;
-	num_suites /= 2;
-
-	cipher_suite = 0;
-	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
-		c = pos;
-		for (j = 0; j < num_suites; j++) {
-			u16 tmp = WPA_GET_BE16(c);
-			c += 2;
-			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
-				cipher_suite = tmp;
-				break;
-			}
-		}
-	}
-	pos += num_suites * 2;
-	if (!cipher_suite) {
-		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
-			   "available");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
-			   "record layer");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	conn->cipher_suite = cipher_suite;
-
-	/* CompressionMethod compression_methods<1..2^8-1> */
-	if (end - pos < 1)
-		goto decode_error;
-	num_suites = *pos++;
-	if (end - pos < num_suites)
-		goto decode_error;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
-		    pos, num_suites);
-	compr_null_found = 0;
-	for (i = 0; i < num_suites; i++) {
-		if (*pos++ == TLS_COMPRESSION_NULL)
-			compr_null_found = 1;
-	}
-	if (!compr_null_found) {
-		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
-			   "compression");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (end - pos == 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
-			    "end of ClientHello: 0x%02x", *pos);
-		goto decode_error;
-	}
-
-	if (end - pos >= 2) {
-		/* Extension client_hello_extension_list<0..2^16-1> */
-		ext_len = WPA_GET_BE16(pos);
-		pos += 2;
-
-		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
-			   "extensions", ext_len);
-		if (end - pos != ext_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
-				   "extension list length %u (expected %u)",
-				   ext_len, (unsigned int) (end - pos));
-			goto decode_error;
-		}
-
-		/*
-		 * struct {
-		 *   ExtensionType extension_type (0..65535)
-		 *   opaque extension_data<0..2^16-1>
-		 * } Extension;
-		 */
-
-		while (pos < end) {
-			if (end - pos < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_type field");
-				goto decode_error;
-			}
-
-			ext_type = WPA_GET_BE16(pos);
-			pos += 2;
-
-			if (end - pos < 2) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_data length field");
-				goto decode_error;
-			}
-
-			ext_len = WPA_GET_BE16(pos);
-			pos += 2;
-
-			if (end - pos < ext_len) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
-					   "extension_data field");
-				goto decode_error;
-			}
-
-			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
-				   "type %u", ext_type);
-			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
-				    "Extension data", pos, ext_len);
-
-			if (ext_type == TLS_EXT_SESSION_TICKET) {
-				os_free(conn->session_ticket);
-				conn->session_ticket = os_malloc(ext_len);
-				if (conn->session_ticket) {
-					os_memcpy(conn->session_ticket, pos,
-						  ext_len);
-					conn->session_ticket_len = ext_len;
-				}
-			}
-
-			pos += ext_len;
-		}
-	}
-
-	*in_len = end - in_data;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
-		   "ServerHello");
-	conn->state = SERVER_HELLO;
-
-	return 0;
-
-decode_error:
-	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
-	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			   TLS_ALERT_DECODE_ERROR);
-	return -1;
-}
-
-
-static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
-				   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, list_len, cert_len, idx;
-	u8 type;
-	struct x509_certificate *chain = NULL, *last = NULL, *cert;
-	int reason;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_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 Certificate message "
-			   "(len=%lu)", (unsigned long) left);
-		tlsv1_server_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: Unexpected Certificate message "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
-		if (conn->verify_peer) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
-				   "Certificate");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
-		}
-
-		return tls_process_client_key_exchange(conn, ct, in_data,
-						       in_len);
-	}
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected Certificate/"
-			   "ClientKeyExchange)", type);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG,
-		   "TLSv1: Received Certificate (certificate_list len %lu)",
-		   (unsigned long) len);
-
-	/*
-	 * opaque ASN.1Cert<2^24-1>;
-	 *
-	 * struct {
-	 *     ASN.1Cert certificate_list<1..2^24-1>;
-	 * } Certificate;
-	 */
-
-	end = pos + len;
-
-	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
-			   "(left=%lu)", (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	list_len = WPA_GET_BE24(pos);
-	pos += 3;
-
-	if ((size_t) (end - pos) != list_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
-			   "length (len=%lu left=%lu)",
-			   (unsigned long) list_len,
-			   (unsigned long) (end - pos));
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	idx = 0;
-	while (pos < end) {
-		if (end - pos < 3) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "certificate_list");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		cert_len = WPA_GET_BE24(pos);
-		pos += 3;
-
-		if ((size_t) (end - pos) < cert_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
-				   "length (len=%lu left=%lu)",
-				   (unsigned long) cert_len,
-				   (unsigned long) (end - pos));
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
-			   (unsigned long) idx, (unsigned long) cert_len);
-
-		if (idx == 0) {
-			crypto_public_key_free(conn->client_rsa_key);
-			if (tls_parse_cert(pos, cert_len,
-					   &conn->client_rsa_key)) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-					   "the certificate");
-				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-						   TLS_ALERT_BAD_CERTIFICATE);
-				x509_certificate_chain_free(chain);
-				return -1;
-			}
-		}
-
-		cert = x509_certificate_parse(pos, cert_len);
-		if (cert == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "the certificate");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_BAD_CERTIFICATE);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		if (last == NULL)
-			chain = cert;
-		else
-			last->next = cert;
-		last = cert;
-
-		idx++;
-		pos += cert_len;
-	}
-
-	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-					    &reason) < 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;
-			break;
-		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
-			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
-			break;
-		case X509_VALIDATE_CERTIFICATE_REVOKED:
-			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_EXPIRED:
-			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
-			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
-			break;
-		case X509_VALIDATE_UNKNOWN_CA:
-			tls_reason = TLS_ALERT_UNKNOWN_CA;
-			break;
-		default:
-			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
-			break;
-		}
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
-		x509_certificate_chain_free(chain);
-		return -1;
-	}
-
-	x509_certificate_chain_free(chain);
-
-	*in_len = end - in_data;
-
-	conn->state = CLIENT_KEY_EXCHANGE;
-
-	return 0;
-}
-
-
-static int tls_process_client_key_exchange_rsa(
-	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
-{
-	u8 *out;
-	size_t outlen, outbuflen;
-	u16 encr_len;
-	int res;
-	int use_random = 0;
-
-	if (end - pos < 2) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	encr_len = WPA_GET_BE16(pos);
-	pos += 2;
-
-	outbuflen = outlen = end - pos;
-	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
-			outlen : TLS_PRE_MASTER_SECRET_LEN);
-	if (out == NULL) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/*
-	 * struct {
-	 *   ProtocolVersion client_version;
-	 *   opaque random[46];
-	 * } PreMasterSecret;
-	 *
-	 * struct {
-	 *   public-key-encrypted PreMasterSecret pre_master_secret;
-	 * } EncryptedPreMasterSecret;
-	 */
-
-	/*
-	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
-	 * parsing errors from EncryptedPreMasterSecret processing to the
-	 * client. Instead, a random pre-master secret is used to force the
-	 * handshake to fail.
-	 */
-
-	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
-						 pos, end - pos,
-						 out, &outlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
-			   "PreMasterSecret (encr_len=%d outlen=%lu)",
-			   (int) (end - pos), (unsigned long) outlen);
-		use_random = 1;
-	}
-
-	if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
-			   "length %lu", (unsigned long) outlen);
-		use_random = 1;
-	}
-
-	if (WPA_GET_BE16(out) != conn->client_version) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
-			   "ClientKeyExchange does not match with version in "
-			   "ClientHello");
-		use_random = 1;
-	}
-
-	if (use_random) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
-			   "to avoid revealing information about private key");
-		outlen = TLS_PRE_MASTER_SECRET_LEN;
-		if (os_get_random(out, outlen)) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
-				   "data");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_INTERNAL_ERROR);
-			os_free(out);
-			return -1;
-		}
-	}
-
-	res = tlsv1_server_derive_keys(conn, out, outlen);
-
-	/* Clear the pre-master secret since it is not needed anymore */
-	os_memset(out, 0, outbuflen);
-	os_free(out);
-
-	if (res) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int tls_process_client_key_exchange_dh_anon(
-	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
-{
-	const u8 *dh_yc;
-	u16 dh_yc_len;
-	u8 *shared;
-	size_t shared_len;
-	int res;
-
-	/*
-	 * struct {
-	 *   select (PublicValueEncoding) {
-	 *     case implicit: struct { };
-	 *     case explicit: opaque dh_Yc<1..2^16-1>;
-	 *   } dh_public;
-	 * } ClientDiffieHellmanPublic;
-	 */
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
-		    pos, end - pos);
-
-	if (end == pos) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
-			   "not supported");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
-			   "length");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	dh_yc_len = WPA_GET_BE16(pos);
-	dh_yc = pos + 2;
-
-	if (dh_yc + dh_yc_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
-			   "(length %d)", dh_yc_len);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
-		    dh_yc, dh_yc_len);
-
-	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
-	    conn->dh_secret == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	shared_len = conn->cred->dh_p_len;
-	shared = os_malloc(shared_len);
-	if (shared == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
-			   "DH");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/* shared = Yc^secret mod p */
-	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
-			   conn->dh_secret_len,
-			   conn->cred->dh_p, conn->cred->dh_p_len,
-			   shared, &shared_len)) {
-		os_free(shared);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
-			shared, shared_len);
-
-	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
-	os_free(conn->dh_secret);
-	conn->dh_secret = NULL;
-
-	res = tlsv1_server_derive_keys(conn, shared, shared_len);
-
-	/* Clear the pre-master secret since it is not needed anymore */
-	os_memset(shared, 0, shared_len);
-	os_free(shared);
-
-	if (res) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-	tls_key_exchange keyx;
-	const struct tls_cipher_suite *suite;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_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 ClientKeyExchange "
-			   "(Left=%lu)", (unsigned long) left);
-		tlsv1_server_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 ClientKeyExchange "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	end = pos + len;
-
-	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ClientKeyExchange)", type);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
-
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite == NULL)
-		keyx = TLS_KEY_X_NULL;
-	else
-		keyx = suite->key_exchange;
-
-	if (keyx == TLS_KEY_X_DH_anon &&
-	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
-		return -1;
-
-	if (keyx != TLS_KEY_X_DH_anon &&
-	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
-		return -1;
-
-	*in_len = end - in_data;
-
-	conn->state = CERTIFICATE_VERIFY;
-
-	return 0;
-}
-
-
-static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
-					  const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-	size_t hlen, buflen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-	u16 slen;
-
-	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
-		if (conn->verify_peer) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
-				   "CertificateVerify");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
-		}
-
-		return tls_process_change_cipher_spec(conn, ct, in_data,
-						      in_len);
-	}
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_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 CertificateVerify "
-			   "message (len=%lu)", (unsigned long) left);
-		tlsv1_server_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: Unexpected CertificateVerify "
-			   "message length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	end = pos + len;
-
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected CertificateVerify)", type);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
-
-	/*
-	 * struct {
-	 *   Signature signature;
-	 * } CertificateVerify;
-	 */
-
-	hpos = hash;
-
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify.md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
-		{
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_INTERNAL_ERROR);
-			conn->verify.md5_cert = NULL;
-			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
-			conn->verify.sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
-
-	conn->verify.md5_cert = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_cert == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
-		conn->verify.sha1_cert = NULL;
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_cert = NULL;
-
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
-
-	if (end - pos < 2) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	slen = WPA_GET_BE16(pos);
-	pos += 2;
-	if (end - pos < slen) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
-	if (conn->client_rsa_key == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
-			   "signature");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	buflen = end - pos;
-	buf = os_malloc(end - pos);
-	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
-					    pos, end - pos, buf, &buflen) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
-			buf, buflen);
-
-	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
-			   "CertificateVerify - did not match with calculated "
-			   "hash");
-		os_free(buf);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-
-	os_free(buf);
-
-	*in_len = end - in_data;
-
-	conn->state = CHANGE_CIPHER_SPEC;
-
-	return 0;
-}
-
-
-static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
-					  u8 ct, const u8 *in_data,
-					  size_t *in_len)
-{
-	const u8 *pos;
-	size_t left;
-
-	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received data 0x%x", *pos);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
-	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
-			   "for record layer");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*in_len = pos + 1 - in_data;
-
-	conn->state = CLIENT_FINISHED;
-
-	return 0;
-}
-
-
-static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
-				       const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
-			   "received content type 0x%x", ct);
-		tlsv1_server_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 record (left=%lu) for "
-			   "Finished",
-			   (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
-			   "type 0x%x", pos[0]);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	len = WPA_GET_BE24(pos + 1);
-
-	pos += 4;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
-			   "(len=%lu > left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	end = pos + len;
-	if (len != TLS_VERIFY_DATA_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
-			   "in Finished: %lu (expected %d)",
-			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
-		    pos, TLS_VERIFY_DATA_LEN);
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify.md5_client == NULL ||
-	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		conn->verify.md5_client = NULL;
-		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
-		conn->verify.sha1_client = NULL;
-		return -1;
-	}
-	conn->verify.md5_client = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_client == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify.sha1_client = NULL;
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_client = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
-		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
-
-	*in_len = end - in_data;
-
-	if (conn->use_session_ticket) {
-		/* Abbreviated handshake using session ticket; RFC 4507 */
-		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
-			   "successfully");
-		conn->state = ESTABLISHED;
-	} else {
-		/* Full handshake */
-		conn->state = SERVER_CHANGE_CIPHER_SPEC;
-	}
-
-	return 0;
-}
-
-
-int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
-				   const u8 *buf, size_t *len)
-{
-	if (ct == TLS_CONTENT_TYPE_ALERT) {
-		if (*len < 2) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
-			   buf[0], buf[1]);
-		*len = 2;
-		conn->state = FAILED;
-		return -1;
-	}
-
-	switch (conn->state) {
-	case CLIENT_HELLO:
-		if (tls_process_client_hello(conn, ct, buf, len))
-			return -1;
-		break;
-	case CLIENT_CERTIFICATE:
-		if (tls_process_certificate(conn, ct, buf, len))
-			return -1;
-		break;
-	case CLIENT_KEY_EXCHANGE:
-		if (tls_process_client_key_exchange(conn, ct, buf, len))
-			return -1;
-		break;
-	case CERTIFICATE_VERIFY:
-		if (tls_process_certificate_verify(conn, ct, buf, len))
-			return -1;
-		break;
-	case CHANGE_CIPHER_SPEC:
-		if (tls_process_change_cipher_spec(conn, ct, buf, len))
-			return -1;
-		break;
-	case CLIENT_FINISHED:
-		if (tls_process_client_finished(conn, ct, buf, len))
-			return -1;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
-			   "while processing received message",
-			   conn->state);
-		return -1;
-	}
-
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
-		tls_verify_hash_add(&conn->verify, buf, *len);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_server_read.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_server_read.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_server_read.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_read.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1253 @@
+/*
+ * TLSv1 server - read handshake message
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/tls.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+					  u8 ct, const u8 *in_data,
+					  size_t *in_len);
+
+
+static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
+				    const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end, *c;
+	size_t left, len, i, j;
+	u16 cipher_suite;
+	u16 num_suites;
+	int compr_null_found;
+	u16 ext_type, ext_len;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4)
+		goto decode_error;
+
+	/* HandshakeType msg_type */
+	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ClientHello)", *pos);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+	pos++;
+	/* uint24 length */
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left)
+		goto decode_error;
+
+	/* body - ClientHello */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
+	end = pos + len;
+
+	/* ProtocolVersion client_version */
+	if (end - pos < 2)
+		goto decode_error;
+	conn->client_version = WPA_GET_BE16(pos);
+	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
+		   conn->client_version >> 8, conn->client_version & 0xff);
+	if (conn->client_version < TLS_VERSION_1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+			   "ClientHello %u.%u",
+			   conn->client_version >> 8,
+			   conn->client_version & 0xff);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_PROTOCOL_VERSION);
+		return -1;
+	}
+	pos += 2;
+
+	if (TLS_VERSION == TLS_VERSION_1)
+		conn->rl.tls_version = TLS_VERSION_1;
+#ifdef CONFIG_TLSV12
+	else if (conn->client_version >= TLS_VERSION_1_2)
+		conn->rl.tls_version = TLS_VERSION_1_2;
+#endif /* CONFIG_TLSV12 */
+	else if (conn->client_version > TLS_VERSION_1_1)
+		conn->rl.tls_version = TLS_VERSION_1_1;
+	else
+		conn->rl.tls_version = conn->client_version;
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(conn->rl.tls_version));
+
+	/* Random random */
+	if (end - pos < TLS_RANDOM_LEN)
+		goto decode_error;
+
+	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+		    conn->client_random, TLS_RANDOM_LEN);
+
+	/* SessionID session_id */
+	if (end - pos < 1)
+		goto decode_error;
+	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
+	pos += 1 + *pos;
+	/* TODO: add support for session resumption */
+
+	/* CipherSuite cipher_suites<2..2^16-1> */
+	if (end - pos < 2)
+		goto decode_error;
+	num_suites = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < num_suites)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
+		    pos, num_suites);
+	if (num_suites & 1)
+		goto decode_error;
+	num_suites /= 2;
+
+	cipher_suite = 0;
+	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+		c = pos;
+		for (j = 0; j < num_suites; j++) {
+			u16 tmp = WPA_GET_BE16(c);
+			c += 2;
+			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
+				cipher_suite = tmp;
+				break;
+			}
+		}
+	}
+	pos += num_suites * 2;
+	if (!cipher_suite) {
+		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
+			   "available");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+			   "record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	conn->cipher_suite = cipher_suite;
+
+	/* CompressionMethod compression_methods<1..2^8-1> */
+	if (end - pos < 1)
+		goto decode_error;
+	num_suites = *pos++;
+	if (end - pos < num_suites)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
+		    pos, num_suites);
+	compr_null_found = 0;
+	for (i = 0; i < num_suites; i++) {
+		if (*pos++ == TLS_COMPRESSION_NULL)
+			compr_null_found = 1;
+	}
+	if (!compr_null_found) {
+		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
+			   "compression");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (end - pos == 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
+			    "end of ClientHello: 0x%02x", *pos);
+		goto decode_error;
+	}
+
+	if (end - pos >= 2) {
+		/* Extension client_hello_extension_list<0..2^16-1> */
+		ext_len = WPA_GET_BE16(pos);
+		pos += 2;
+
+		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
+			   "extensions", ext_len);
+		if (end - pos != ext_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
+				   "extension list length %u (expected %u)",
+				   ext_len, (unsigned int) (end - pos));
+			goto decode_error;
+		}
+
+		/*
+		 * struct {
+		 *   ExtensionType extension_type (0..65535)
+		 *   opaque extension_data<0..2^16-1>
+		 * } Extension;
+		 */
+
+		while (pos < end) {
+			if (end - pos < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_type field");
+				goto decode_error;
+			}
+
+			ext_type = WPA_GET_BE16(pos);
+			pos += 2;
+
+			if (end - pos < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_data length field");
+				goto decode_error;
+			}
+
+			ext_len = WPA_GET_BE16(pos);
+			pos += 2;
+
+			if (end - pos < ext_len) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_data field");
+				goto decode_error;
+			}
+
+			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
+				   "type %u", ext_type);
+			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
+				    "Extension data", pos, ext_len);
+
+			if (ext_type == TLS_EXT_SESSION_TICKET) {
+				os_free(conn->session_ticket);
+				conn->session_ticket = os_malloc(ext_len);
+				if (conn->session_ticket) {
+					os_memcpy(conn->session_ticket, pos,
+						  ext_len);
+					conn->session_ticket_len = ext_len;
+				}
+			}
+
+			pos += ext_len;
+		}
+	}
+
+	*in_len = end - in_data;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
+		   "ServerHello");
+	conn->state = SERVER_HELLO;
+
+	return 0;
+
+decode_error:
+	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			   TLS_ALERT_DECODE_ERROR);
+	return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
+				   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, list_len, cert_len, idx;
+	u8 type;
+	struct x509_certificate *chain = NULL, *last = NULL, *cert;
+	int reason;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_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 Certificate message "
+			   "(len=%lu)", (unsigned long) left);
+		tlsv1_server_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: Unexpected Certificate message "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+		if (conn->verify_peer) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+				   "Certificate");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		return tls_process_client_key_exchange(conn, ct, in_data,
+						       in_len);
+	}
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected Certificate/"
+			   "ClientKeyExchange)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "TLSv1: Received Certificate (certificate_list len %lu)",
+		   (unsigned long) len);
+
+	/*
+	 * opaque ASN.1Cert<2^24-1>;
+	 *
+	 * struct {
+	 *     ASN.1Cert certificate_list<1..2^24-1>;
+	 * } Certificate;
+	 */
+
+	end = pos + len;
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+			   "(left=%lu)", (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	list_len = WPA_GET_BE24(pos);
+	pos += 3;
+
+	if ((size_t) (end - pos) != list_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+			   "length (len=%lu left=%lu)",
+			   (unsigned long) list_len,
+			   (unsigned long) (end - pos));
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	idx = 0;
+	while (pos < end) {
+		if (end - pos < 3) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "certificate_list");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		cert_len = WPA_GET_BE24(pos);
+		pos += 3;
+
+		if ((size_t) (end - pos) < cert_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+				   "length (len=%lu left=%lu)",
+				   (unsigned long) cert_len,
+				   (unsigned long) (end - pos));
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+			   (unsigned long) idx, (unsigned long) cert_len);
+
+		if (idx == 0) {
+			crypto_public_key_free(conn->client_rsa_key);
+			if (tls_parse_cert(pos, cert_len,
+					   &conn->client_rsa_key)) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+					   "the certificate");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_BAD_CERTIFICATE);
+				x509_certificate_chain_free(chain);
+				return -1;
+			}
+		}
+
+		cert = x509_certificate_parse(pos, cert_len);
+		if (cert == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "the certificate");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		if (last == NULL)
+			chain = cert;
+		else
+			last->next = cert;
+		last = cert;
+
+		idx++;
+		pos += cert_len;
+	}
+
+	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+					    &reason, 0) < 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;
+			break;
+		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+			break;
+		case X509_VALIDATE_CERTIFICATE_REVOKED:
+			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_EXPIRED:
+			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+			break;
+		case X509_VALIDATE_UNKNOWN_CA:
+			tls_reason = TLS_ALERT_UNKNOWN_CA;
+			break;
+		default:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		}
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+		x509_certificate_chain_free(chain);
+		return -1;
+	}
+
+	x509_certificate_chain_free(chain);
+
+	*in_len = end - in_data;
+
+	conn->state = CLIENT_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange_rsa(
+	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+	u8 *out;
+	size_t outlen, outbuflen;
+	u16 encr_len;
+	int res;
+	int use_random = 0;
+
+	if (end - pos < 2) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	encr_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (pos + encr_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
+			   "format: encr_len=%u left=%u",
+			   encr_len, (unsigned int) (end - pos));
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	outbuflen = outlen = end - pos;
+	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
+			outlen : TLS_PRE_MASTER_SECRET_LEN);
+	if (out == NULL) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/*
+	 * struct {
+	 *   ProtocolVersion client_version;
+	 *   opaque random[46];
+	 * } PreMasterSecret;
+	 *
+	 * struct {
+	 *   public-key-encrypted PreMasterSecret pre_master_secret;
+	 * } EncryptedPreMasterSecret;
+	 */
+
+	/*
+	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
+	 * parsing errors from EncryptedPreMasterSecret processing to the
+	 * client. Instead, a random pre-master secret is used to force the
+	 * handshake to fail.
+	 */
+
+	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
+						 pos, encr_len,
+						 out, &outlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
+			   "PreMasterSecret (encr_len=%u outlen=%lu)",
+			   encr_len, (unsigned long) outlen);
+		use_random = 1;
+	}
+
+	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
+			   "length %lu", (unsigned long) outlen);
+		use_random = 1;
+	}
+
+	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
+			   "ClientKeyExchange does not match with version in "
+			   "ClientHello");
+		use_random = 1;
+	}
+
+	if (use_random) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
+			   "to avoid revealing information about private key");
+		outlen = TLS_PRE_MASTER_SECRET_LEN;
+		if (os_get_random(out, outlen)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+				   "data");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			os_free(out);
+			return -1;
+		}
+	}
+
+	res = tlsv1_server_derive_keys(conn, out, outlen);
+
+	/* Clear the pre-master secret since it is not needed anymore */
+	os_memset(out, 0, outbuflen);
+	os_free(out);
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange_dh_anon(
+	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+	const u8 *dh_yc;
+	u16 dh_yc_len;
+	u8 *shared;
+	size_t shared_len;
+	int res;
+
+	/*
+	 * struct {
+	 *   select (PublicValueEncoding) {
+	 *     case implicit: struct { };
+	 *     case explicit: opaque dh_Yc<1..2^16-1>;
+	 *   } dh_public;
+	 * } ClientDiffieHellmanPublic;
+	 */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
+		    pos, end - pos);
+
+	if (end == pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
+			   "not supported");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
+			   "length");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	dh_yc_len = WPA_GET_BE16(pos);
+	dh_yc = pos + 2;
+
+	if (dh_yc + dh_yc_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
+			   "(length %d)", dh_yc_len);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+		    dh_yc, dh_yc_len);
+
+	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+	    conn->dh_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	shared_len = conn->cred->dh_p_len;
+	shared = os_malloc(shared_len);
+	if (shared == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+			   "DH");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* shared = Yc^secret mod p */
+	if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret,
+			   conn->dh_secret_len,
+			   conn->cred->dh_p, conn->cred->dh_p_len,
+			   shared, &shared_len)) {
+		os_free(shared);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+			shared, shared_len);
+
+	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
+	os_free(conn->dh_secret);
+	conn->dh_secret = NULL;
+
+	res = tlsv1_server_derive_keys(conn, shared, shared_len);
+
+	/* Clear the pre-master secret since it is not needed anymore */
+	os_memset(shared, 0, shared_len);
+	os_free(shared);
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_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 ClientKeyExchange "
+			   "(Left=%lu)", (unsigned long) left);
+		tlsv1_server_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 ClientKeyExchange "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ClientKeyExchange)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	if (keyx == TLS_KEY_X_DH_anon &&
+	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+		return -1;
+
+	if (keyx != TLS_KEY_X_DH_anon &&
+	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
+		return -1;
+
+	*in_len = end - in_data;
+
+	conn->state = CERTIFICATE_VERIFY;
+
+	return 0;
+}
+
+
+static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
+					  const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	size_t hlen, buflen;
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+	u16 slen;
+
+	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		if (conn->verify_peer) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+				   "CertificateVerify");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		return tls_process_change_cipher_spec(conn, ct, in_data,
+						      in_len);
+	}
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_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 CertificateVerify "
+			   "message (len=%lu)", (unsigned long) left);
+		tlsv1_server_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: Unexpected CertificateVerify "
+			   "message length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected CertificateVerify)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+
+	/*
+	 * struct {
+	 *   Signature signature;
+	 * } CertificateVerify;
+	 */
+
+	hpos = hash;
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		if (end - pos < 2) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		if (pos[0] != TLS_HASH_ALG_SHA256 ||
+		    pos[1] != TLS_SIGN_ALG_RSA) {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
+				   "signature(%u) algorithm",
+				   pos[0], pos[1]);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		pos += 2;
+
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	if (alg == SIGN_ALG_RSA) {
+		hlen = MD5_MAC_LEN;
+		if (conn->verify.md5_cert == NULL ||
+		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+		{
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.md5_cert = NULL;
+			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+			conn->verify.sha1_cert = NULL;
+			return -1;
+		}
+		hpos += MD5_MAC_LEN;
+	} else
+		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+	conn->verify.md5_cert = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_cert == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+		conn->verify.sha1_cert = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_cert = NULL;
+
+	if (alg == SIGN_ALG_RSA)
+		hlen += MD5_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+	if (end - pos < 2) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	slen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < slen) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+	if (conn->client_rsa_key == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
+			   "signature");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	buflen = end - pos;
+	buf = os_malloc(end - pos);
+	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
+					    pos, end - pos, buf, &buflen) < 0)
+	{
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+		os_free(buf);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+			buf, buflen);
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		if (buflen >= 19 + 32 &&
+		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
+				   "SHA-256");
+			os_memmove(buf, buf + 19, buflen - 19);
+			buflen -= 19;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
+				   "DigestInfo");
+			os_free(buf);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECRYPT_ERROR);
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
+			   "CertificateVerify - did not match with calculated "
+			   "hash");
+		os_free(buf);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+
+	os_free(buf);
+
+	*in_len = end - in_data;
+
+	conn->state = CHANGE_CIPHER_SPEC;
+
+	return 0;
+}
+
+
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+					  u8 ct, const u8 *in_data,
+					  size_t *in_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received data 0x%x", *pos);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+			   "for record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = pos + 1 - in_data;
+
+	conn->state = CLIENT_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
+				       const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_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 record (left=%lu) for "
+			   "Finished",
+			   (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+			   "type 0x%x", pos[0]);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	len = WPA_GET_BE24(pos + 1);
+
+	pos += 4;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+			   "(len=%lu > left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	end = pos + len;
+	if (len != TLS_VERIFY_DATA_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+			   "in Finished: %lu (expected %d)",
+			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+		    pos, TLS_VERIFY_DATA_LEN);
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_client == NULL ||
+	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_client = NULL;
+		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+		conn->verify.sha1_client = NULL;
+		return -1;
+	}
+	conn->verify.md5_client = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_client == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_client = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+	*in_len = end - in_data;
+
+	if (conn->use_session_ticket) {
+		/* Abbreviated handshake using session ticket; RFC 4507 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
+			   "successfully");
+		conn->state = ESTABLISHED;
+	} else {
+		/* Full handshake */
+		conn->state = SERVER_CHANGE_CIPHER_SPEC;
+	}
+
+	return 0;
+}
+
+
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+				   const u8 *buf, size_t *len)
+{
+	if (ct == TLS_CONTENT_TYPE_ALERT) {
+		if (*len < 2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+			   buf[0], buf[1]);
+		*len = 2;
+		conn->state = FAILED;
+		return -1;
+	}
+
+	switch (conn->state) {
+	case CLIENT_HELLO:
+		if (tls_process_client_hello(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_CERTIFICATE:
+		if (tls_process_certificate(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_KEY_EXCHANGE:
+		if (tls_process_client_key_exchange(conn, ct, buf, len))
+			return -1;
+		break;
+	case CERTIFICATE_VERIFY:
+		if (tls_process_certificate_verify(conn, ct, buf, len))
+			return -1;
+		break;
+	case CHANGE_CIPHER_SPEC:
+		if (tls_process_change_cipher_spec(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_FINISHED:
+		if (tls_process_client_finished(conn, ct, buf, len))
+			return -1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+			   "while processing received message",
+			   conn->state);
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+		tls_verify_hash_add(&conn->verify, buf, *len);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/tls/tlsv1_server_write.c
===================================================================
--- vendor/wpa/dist/src/tls/tlsv1_server_write.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_write.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,790 +0,0 @@
-/*
- * TLSv1 server - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/md5.h"
-#include "crypto/sha1.h"
-#include "crypto/tls.h"
-#include "x509v3.h"
-#include "tlsv1_common.h"
-#include "tlsv1_record.h"
-#include "tlsv1_server.h"
-#include "tlsv1_server_i.h"
-
-
-static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
-{
-	size_t len = 0;
-	struct x509_certificate *cert;
-
-	cert = conn->cred->cert;
-	while (cert) {
-		len += 3 + cert->cert_len;
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
-						    &cert->issuer);
-	}
-
-	return len;
-}
-
-
-static int tls_write_server_hello(struct tlsv1_server *conn,
-				  u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	struct os_time now;
-	size_t rlen;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	os_get_time(&now);
-	WPA_PUT_BE32(conn->server_random, now.sec);
-	if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
-		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
-			   "server_random");
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
-		    conn->server_random, TLS_RANDOM_LEN);
-
-	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
-	if (os_get_random(conn->session_id, conn->session_id_len)) {
-		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
-			   "session_id");
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
-		    conn->session_id, conn->session_id_len);
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ServerHello */
-	/* ProtocolVersion server_version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
-	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
-	pos += TLS_RANDOM_LEN;
-	/* SessionID session_id */
-	*pos++ = conn->session_id_len;
-	os_memcpy(pos, conn->session_id, conn->session_id_len);
-	pos += conn->session_id_len;
-	/* CipherSuite cipher_suite */
-	WPA_PUT_BE16(pos, conn->cipher_suite);
-	pos += 2;
-	/* CompressionMethod compression_method */
-	*pos++ = TLS_COMPRESSION_NULL;
-
-	if (conn->session_ticket && conn->session_ticket_cb) {
-		int res = conn->session_ticket_cb(
-			conn->session_ticket_cb_ctx,
-			conn->session_ticket, conn->session_ticket_len,
-			conn->client_random, conn->server_random,
-			conn->master_secret);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
-				   "indicated failure");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_HANDSHAKE_FAILURE);
-			return -1;
-		}
-		conn->use_session_ticket = res;
-
-		if (conn->use_session_ticket) {
-			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
-					   "derive keys");
-				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-						   TLS_ALERT_INTERNAL_ERROR);
-				return -1;
-			}
-		}
-
-		/*
-		 * RFC 4507 specifies that server would include an empty
-		 * SessionTicket extension in ServerHello and a
-		 * NewSessionTicket message after the ServerHello. However,
-		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
-		 * extension at the moment, does not use such extensions.
-		 *
-		 * TODO: Add support for configuring RFC 4507 behavior and make
-		 * EAP-FAST disable it.
-		 */
-	}
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static int tls_write_server_certificate(struct tlsv1_server *conn,
-					u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
-	size_t rlen;
-	struct x509_certificate *cert;
-	const struct tls_cipher_suite *suite;
-
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
-			   "using anonymous DH");
-		return 0;
-	}
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - Certificate */
-	/* uint24 length (to be filled) */
-	cert_start = pos;
-	pos += 3;
-	cert = conn->cred->cert;
-	while (cert) {
-		if (pos + 3 + cert->cert_len > end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
-				   "for Certificate (cert_len=%lu left=%lu)",
-				   (unsigned long) cert->cert_len,
-				   (unsigned long) (end - pos));
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					   TLS_ALERT_INTERNAL_ERROR);
-			return -1;
-		}
-		WPA_PUT_BE24(pos, cert->cert_len);
-		pos += 3;
-		os_memcpy(pos, cert->cert_start, cert->cert_len);
-		pos += cert->cert_len;
-
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
-						    &cert->issuer);
-	}
-	if (cert == conn->cred->cert || cert == NULL) {
-		/*
-		 * Server was not configured with all the needed certificates
-		 * to form a full certificate chain. The client may fail to
-		 * validate the chain unless it is configured with all the
-		 * missing CA certificates.
-		 */
-		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
-			   "not configured - validation may fail");
-	}
-	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, 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)
-{
-	tls_key_exchange keyx;
-	const struct tls_cipher_suite *suite;
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen;
-	u8 *dh_ys;
-	size_t dh_ys_len;
-
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite == NULL)
-		keyx = TLS_KEY_X_NULL;
-	else
-		keyx = suite->key_exchange;
-
-	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
-		return 0;
-	}
-
-	if (keyx != TLS_KEY_X_DH_anon) {
-		/* TODO? */
-		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
-			   "supported with key exchange type %d", keyx);
-		return -1;
-	}
-
-	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
-	    conn->cred->dh_g == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
-			   "ServerKeyExhcange");
-		return -1;
-	}
-
-	os_free(conn->dh_secret);
-	conn->dh_secret_len = conn->cred->dh_p_len;
-	conn->dh_secret = os_malloc(conn->dh_secret_len);
-	if (conn->dh_secret == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
-			   "memory for secret (Diffie-Hellman)");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
-			   "data for Diffie-Hellman");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		os_free(conn->dh_secret);
-		conn->dh_secret = NULL;
-		return -1;
-	}
-
-	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
-	    0)
-		conn->dh_secret[0] = 0; /* make sure secret < p */
-
-	pos = conn->dh_secret;
-	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
-		pos++;
-	if (pos != conn->dh_secret) {
-		os_memmove(conn->dh_secret, pos,
-			   conn->dh_secret_len - (pos - conn->dh_secret));
-		conn->dh_secret_len -= pos - conn->dh_secret;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
-			conn->dh_secret, conn->dh_secret_len);
-
-	/* Ys = g^secret mod p */
-	dh_ys_len = conn->cred->dh_p_len;
-	dh_ys = os_malloc(dh_ys_len);
-	if (dh_ys == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
-			   "Diffie-Hellman");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
-			   conn->dh_secret, conn->dh_secret_len,
-			   conn->cred->dh_p, conn->cred->dh_p_len,
-			   dh_ys, &dh_ys_len)) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		os_free(dh_ys);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
-		    dh_ys, dh_ys_len);
-
-	/*
-	 * struct {
-	 *    select (KeyExchangeAlgorithm) {
-	 *       case diffie_hellman:
-	 *          ServerDHParams params;
-	 *          Signature signed_params;
-	 *       case rsa:
-	 *          ServerRSAParams params;
-	 *          Signature signed_params;
-	 *    };
-	 * } ServerKeyExchange;
-	 *
-	 * struct {
-	 *    opaque dh_p<1..2^16-1>;
-	 *    opaque dh_g<1..2^16-1>;
-	 *    opaque dh_Ys<1..2^16-1>;
-	 * } ServerDHParams;
-	 */
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-
-	/* body - ServerDHParams */
-	/* dh_p */
-	if (pos + 2 + conn->cred->dh_p_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
-			   "dh_p");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		os_free(dh_ys);
-		return -1;
-	}
-	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
-	pos += 2;
-	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
-	pos += conn->cred->dh_p_len;
-
-	/* dh_g */
-	if (pos + 2 + conn->cred->dh_g_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
-			   "dh_g");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		os_free(dh_ys);
-		return -1;
-	}
-	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
-	pos += 2;
-	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
-	pos += conn->cred->dh_g_len;
-
-	/* dh_Ys */
-	if (pos + 2 + dh_ys_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
-			   "dh_Ys");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		os_free(dh_ys);
-		return -1;
-	}
-	WPA_PUT_BE16(pos, dh_ys_len);
-	pos += 2;
-	os_memcpy(pos, dh_ys, dh_ys_len);
-	pos += dh_ys_len;
-	os_free(dh_ys);
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, 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_certificate_request(struct tlsv1_server *conn,
-						u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen;
-
-	if (!conn->verify_peer) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
-		return 0;
-	}
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - CertificateRequest */
-
-	/*
-	 * enum {
-	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
-	 *   (255)
-	 * } ClientCertificateType;
-	 * ClientCertificateType certificate_types<1..2^8-1>
-	 */
-	*pos++ = 1;
-	*pos++ = 1; /* rsa_sign */
-
-	/*
-	 * opaque DistinguishedName<1..2^16-1>
-	 * DistinguishedName certificate_authorities<3..2^16-1>
-	 */
-	/* TODO: add support for listing DNs for trusted CAs */
-	WPA_PUT_BE16(pos, 0);
-	pos += 2;
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, 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_hello_done(struct tlsv1_server *conn,
-				       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ServerHelloDone (empty) */
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, 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_change_cipher_spec(struct tlsv1_server *conn,
-					       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr;
-	size_t rlen;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
-			   "record layer");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*msgpos = rhdr + rlen;
-
-	return 0;
-}
-
-
-static int tls_write_server_finished(struct tlsv1_server *conn,
-				     u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
-
-	/* Encrypted Handshake Message: Finished */
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify.md5_server == NULL ||
-	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		conn->verify.md5_server = NULL;
-		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
-		conn->verify.sha1_server = NULL;
-		return -1;
-	}
-	conn->verify.md5_server = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify.sha1_server == NULL ||
-	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify.sha1_server = NULL;
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify.sha1_server = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				   TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-	size_t msglen;
-
-	*out_len = 0;
-
-	msglen = 1000 + tls_server_cert_chain_der_len(conn);
-
-	msg = os_malloc(msglen);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + msglen;
-
-	if (tls_write_server_hello(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	if (conn->use_session_ticket) {
-		/* 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) {
-			os_free(msg);
-			return NULL;
-		}
-
-		*out_len = pos - msg;
-
-		conn->state = CHANGE_CIPHER_SPEC;
-
-		return msg;
-	}
-
-	/* Full handshake */
-	if (tls_write_server_certificate(conn, &pos, end) < 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);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	conn->state = CLIENT_CERTIFICATE;
-
-	return msg;
-}
-
-
-static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
-					size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-
-	*out_len = 0;
-
-	msg = os_malloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + 1000;
-
-	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
-	    tls_write_server_finished(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
-	conn->state = ESTABLISHED;
-
-	return msg;
-}
-
-
-u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
-{
-	switch (conn->state) {
-	case SERVER_HELLO:
-		return tls_send_server_hello(conn, out_len);
-	case SERVER_CHANGE_CIPHER_SPEC:
-		return tls_send_change_cipher_spec(conn, out_len);
-	default:
-		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
-			/* Abbreviated handshake was already completed. */
-			return NULL;
-		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
-			   "generating reply", conn->state);
-		return NULL;
-	}
-}
-
-
-u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
-			     u8 description, size_t *out_len)
-{
-	u8 *alert, *pos, *length;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
-	*out_len = 0;
-
-	alert = os_malloc(10);
-	if (alert == NULL)
-		return NULL;
-
-	pos = alert;
-
-	/* TLSPlaintext */
-	/* ContentType type */
-	*pos++ = TLS_CONTENT_TYPE_ALERT;
-	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* uint16 length (to be filled) */
-	length = pos;
-	pos += 2;
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Alert */
-	/* AlertLevel level */
-	*pos++ = level;
-	/* AlertDescription description */
-	*pos++ = description;
-
-	WPA_PUT_BE16(length, pos - length - 2);
-	*out_len = pos - alert;
-
-	return alert;
-}

Copied: vendor/wpa/2.0/src/tls/tlsv1_server_write.c (from rev 9639, vendor/wpa/dist/src/tls/tlsv1_server_write.c)
===================================================================
--- vendor/wpa/2.0/src/tls/tlsv1_server_write.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/tlsv1_server_write.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,801 @@
+/*
+ * TLSv1 server - write handshake message
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/tls.h"
+#include "crypto/random.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
+{
+	size_t len = 0;
+	struct x509_certificate *cert;
+
+	cert = conn->cred->cert;
+	while (cert) {
+		len += 3 + cert->cert_len;
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+
+	return len;
+}
+
+
+static int tls_write_server_hello(struct tlsv1_server *conn,
+				  u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	struct os_time now;
+	size_t rlen;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	os_get_time(&now);
+	WPA_PUT_BE32(conn->server_random, now.sec);
+	if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "server_random");
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+		    conn->server_random, TLS_RANDOM_LEN);
+
+	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
+	if (random_get_bytes(conn->session_id, conn->session_id_len)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "session_id");
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+		    conn->session_id, conn->session_id_len);
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ServerHello */
+	/* ProtocolVersion server_version */
+	WPA_PUT_BE16(pos, conn->rl.tls_version);
+	pos += 2;
+	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
+	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	/* SessionID session_id */
+	*pos++ = conn->session_id_len;
+	os_memcpy(pos, conn->session_id, conn->session_id_len);
+	pos += conn->session_id_len;
+	/* CipherSuite cipher_suite */
+	WPA_PUT_BE16(pos, conn->cipher_suite);
+	pos += 2;
+	/* CompressionMethod compression_method */
+	*pos++ = TLS_COMPRESSION_NULL;
+
+	if (conn->session_ticket && conn->session_ticket_cb) {
+		int res = conn->session_ticket_cb(
+			conn->session_ticket_cb_ctx,
+			conn->session_ticket, conn->session_ticket_len,
+			conn->client_random, conn->server_random,
+			conn->master_secret);
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+				   "indicated failure");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_HANDSHAKE_FAILURE);
+			return -1;
+		}
+		conn->use_session_ticket = res;
+
+		if (conn->use_session_ticket) {
+			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "derive keys");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_INTERNAL_ERROR);
+				return -1;
+			}
+		}
+
+		/*
+		 * RFC 4507 specifies that server would include an empty
+		 * SessionTicket extension in ServerHello and a
+		 * NewSessionTicket message after the ServerHello. However,
+		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
+		 * extension at the moment, does not use such extensions.
+		 *
+		 * TODO: Add support for configuring RFC 4507 behavior and make
+		 * EAP-FAST disable it.
+		 */
+	}
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	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 create TLS record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_certificate(struct tlsv1_server *conn,
+					u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+	size_t rlen;
+	struct x509_certificate *cert;
+	const struct tls_cipher_suite *suite;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
+			   "using anonymous DH");
+		return 0;
+	}
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - Certificate */
+	/* uint24 length (to be filled) */
+	cert_start = pos;
+	pos += 3;
+	cert = conn->cred->cert;
+	while (cert) {
+		if (pos + 3 + cert->cert_len > end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+				   "for Certificate (cert_len=%lu left=%lu)",
+				   (unsigned long) cert->cert_len,
+				   (unsigned long) (end - pos));
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE24(pos, cert->cert_len);
+		pos += 3;
+		os_memcpy(pos, cert->cert_start, cert->cert_len);
+		pos += cert->cert_len;
+
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+	if (cert == conn->cred->cert || cert == NULL) {
+		/*
+		 * Server was not configured with all the needed certificates
+		 * to form a full certificate chain. The client may fail to
+		 * validate the chain unless it is configured with all the
+		 * missing CA certificates.
+		 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
+			   "not configured - validation may fail");
+	}
+	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+	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)
+{
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+	u8 *dh_ys;
+	size_t dh_ys_len;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
+		return 0;
+	}
+
+	if (keyx != TLS_KEY_X_DH_anon) {
+		/* TODO? */
+		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
+			   "supported with key exchange type %d", keyx);
+		return -1;
+	}
+
+	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+	    conn->cred->dh_g == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
+			   "ServerKeyExhcange");
+		return -1;
+	}
+
+	os_free(conn->dh_secret);
+	conn->dh_secret_len = conn->cred->dh_p_len;
+	conn->dh_secret = os_malloc(conn->dh_secret_len);
+	if (conn->dh_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for secret (Diffie-Hellman)");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+			   "data for Diffie-Hellman");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(conn->dh_secret);
+		conn->dh_secret = NULL;
+		return -1;
+	}
+
+	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
+	    0)
+		conn->dh_secret[0] = 0; /* make sure secret < p */
+
+	pos = conn->dh_secret;
+	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
+		pos++;
+	if (pos != conn->dh_secret) {
+		os_memmove(conn->dh_secret, pos,
+			   conn->dh_secret_len - (pos - conn->dh_secret));
+		conn->dh_secret_len -= pos - conn->dh_secret;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
+			conn->dh_secret, conn->dh_secret_len);
+
+	/* Ys = g^secret mod p */
+	dh_ys_len = conn->cred->dh_p_len;
+	dh_ys = os_malloc(dh_ys_len);
+	if (dh_ys == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
+			   "Diffie-Hellman");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
+			   conn->dh_secret, conn->dh_secret_len,
+			   conn->cred->dh_p, conn->cred->dh_p_len,
+			   dh_ys, &dh_ys_len)) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+		    dh_ys, dh_ys_len);
+
+	/*
+	 * struct {
+	 *    select (KeyExchangeAlgorithm) {
+	 *       case diffie_hellman:
+	 *          ServerDHParams params;
+	 *          Signature signed_params;
+	 *       case rsa:
+	 *          ServerRSAParams params;
+	 *          Signature signed_params;
+	 *    };
+	 * } ServerKeyExchange;
+	 *
+	 * struct {
+	 *    opaque dh_p<1..2^16-1>;
+	 *    opaque dh_g<1..2^16-1>;
+	 *    opaque dh_Ys<1..2^16-1>;
+	 * } ServerDHParams;
+	 */
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+
+	/* body - ServerDHParams */
+	/* dh_p */
+	if (pos + 2 + conn->cred->dh_p_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_p");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+	pos += 2;
+	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
+	pos += conn->cred->dh_p_len;
+
+	/* dh_g */
+	if (pos + 2 + conn->cred->dh_g_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_g");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
+	pos += 2;
+	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
+	pos += conn->cred->dh_g_len;
+
+	/* dh_Ys */
+	if (pos + 2 + dh_ys_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_Ys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, dh_ys_len);
+	pos += 2;
+	os_memcpy(pos, dh_ys, dh_ys_len);
+	pos += dh_ys_len;
+	os_free(dh_ys);
+
+	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_certificate_request(struct tlsv1_server *conn,
+						u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+
+	if (!conn->verify_peer) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
+		return 0;
+	}
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - CertificateRequest */
+
+	/*
+	 * enum {
+	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+	 *   (255)
+	 * } ClientCertificateType;
+	 * ClientCertificateType certificate_types<1..2^8-1>
+	 */
+	*pos++ = 1;
+	*pos++ = 1; /* rsa_sign */
+
+	/*
+	 * opaque DistinguishedName<1..2^16-1>
+	 * DistinguishedName certificate_authorities<3..2^16-1>
+	 */
+	/* TODO: add support for listing DNs for trusted CAs */
+	WPA_PUT_BE16(pos, 0);
+	pos += 2;
+
+	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_hello_done(struct tlsv1_server *conn,
+				       u8 **msgpos, u8 *end)
+{
+	u8 *pos;
+	size_t rlen;
+	u8 payload[4];
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	pos = payload;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, 0);
+	pos += 3;
+	/* body - ServerHelloDone (empty) */
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      *msgpos, end - *msgpos, payload, pos - payload,
+			      &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;
+	}
+
+	tls_verify_hash_add(&conn->verify, payload, pos - payload);
+
+	*msgpos += rlen;
+
+	return 0;
+}
+
+
+static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
+					       u8 **msgpos, u8 *end)
+{
+	size_t rlen;
+	u8 payload[1];
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+			   "record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos += rlen;
+
+	return 0;
+}
+
+
+static int tls_write_server_finished(struct tlsv1_server *conn,
+				     u8 **msgpos, u8 *end)
+{
+	u8 *pos, *hs_start;
+	size_t rlen, hlen;
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+	/* Encrypted Handshake Message: Finished */
+
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			conn->verify.sha256_server = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_server == NULL ||
+	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_server = NULL;
+		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+		conn->verify.sha1_server = NULL;
+		return -1;
+	}
+	conn->verify.md5_server = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_server == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_server = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
+
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+
+	/* Handshake */
+	pos = hs_start = verify_data;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
+	pos += 3;
+	pos += TLS_VERIFY_DATA_LEN;
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos += rlen;
+
+	return 0;
+}
+
+
+static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+	size_t msglen;
+
+	*out_len = 0;
+
+	msglen = 1000 + tls_server_cert_chain_der_len(conn);
+
+	msg = os_malloc(msglen);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + msglen;
+
+	if (tls_write_server_hello(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	if (conn->use_session_ticket) {
+		/* 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) {
+			os_free(msg);
+			return NULL;
+		}
+
+		*out_len = pos - msg;
+
+		conn->state = CHANGE_CIPHER_SPEC;
+
+		return msg;
+	}
+
+	/* Full handshake */
+	if (tls_write_server_certificate(conn, &pos, end) < 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);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	conn->state = CLIENT_CERTIFICATE;
+
+	return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
+					size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+
+	*out_len = 0;
+
+	msg = os_malloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + 1000;
+
+	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_server_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+	conn->state = ESTABLISHED;
+
+	return msg;
+}
+
+
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
+{
+	switch (conn->state) {
+	case SERVER_HELLO:
+		return tls_send_server_hello(conn, out_len);
+	case SERVER_CHANGE_CIPHER_SPEC:
+		return tls_send_change_cipher_spec(conn, out_len);
+	default:
+		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
+			/* Abbreviated handshake was already completed. */
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+			   "generating reply", conn->state);
+		return NULL;
+	}
+}
+
+
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+			     u8 description, size_t *out_len)
+{
+	u8 *alert, *pos, *length;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	*out_len = 0;
+
+	alert = os_malloc(10);
+	if (alert == NULL)
+		return NULL;
+
+	pos = alert;
+
+	/* TLSPlaintext */
+	/* ContentType type */
+	*pos++ = TLS_CONTENT_TYPE_ALERT;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
+	pos += 2;
+	/* uint16 length (to be filled) */
+	length = pos;
+	pos += 2;
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Alert */
+	/* AlertLevel level */
+	*pos++ = level;
+	/* AlertDescription description */
+	*pos++ = description;
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	*out_len = pos - alert;
+
+	return alert;
+}

Deleted: vendor/wpa/2.0/src/tls/x509v3.c
===================================================================
--- vendor/wpa/dist/src/tls/x509v3.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/x509v3.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1985 +0,0 @@
-/*
- * X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/crypto.h"
-#include "asn1.h"
-#include "x509v3.h"
-
-
-static void x509_free_name(struct x509_name *name)
-{
-	size_t i;
-
-	for (i = 0; i < name->num_attr; i++) {
-		os_free(name->attr[i].value);
-		name->attr[i].value = NULL;
-		name->attr[i].type = X509_NAME_ATTR_NOT_USED;
-	}
-	name->num_attr = 0;
-	os_free(name->email);
-	name->email = NULL;
-
-	os_free(name->alt_email);
-	os_free(name->dns);
-	os_free(name->uri);
-	os_free(name->ip);
-	name->alt_email = name->dns = name->uri = NULL;
-	name->ip = NULL;
-	name->ip_len = 0;
-	os_memset(&name->rid, 0, sizeof(name->rid));
-}
-
-
-/**
- * x509_certificate_free - Free an X.509 certificate
- * @cert: Certificate to be freed
- */
-void x509_certificate_free(struct x509_certificate *cert)
-{
-	if (cert == NULL)
-		return;
-	if (cert->next) {
-		wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
-			   "was still on a list (next=%p)\n",
-			   cert, cert->next);
-	}
-	x509_free_name(&cert->issuer);
-	x509_free_name(&cert->subject);
-	os_free(cert->public_key);
-	os_free(cert->sign_value);
-	os_free(cert);
-}
-
-
-/**
- * x509_certificate_free - Free an X.509 certificate chain
- * @cert: Pointer to the first certificate in the chain
- */
-void x509_certificate_chain_free(struct x509_certificate *cert)
-{
-	struct x509_certificate *next;
-
-	while (cert) {
-		next = cert->next;
-		cert->next = NULL;
-		x509_certificate_free(cert);
-		cert = next;
-	}
-}
-
-
-static int x509_whitespace(char c)
-{
-	return c == ' ' || c == '\t';
-}
-
-
-static void x509_str_strip_whitespace(char *a)
-{
-	char *ipos, *opos;
-	int remove_whitespace = 1;
-
-	ipos = opos = a;
-
-	while (*ipos) {
-		if (remove_whitespace && x509_whitespace(*ipos))
-			ipos++;
-		else {
-			remove_whitespace = x509_whitespace(*ipos);
-			*opos++ = *ipos++;
-		}
-	}
-
-	*opos-- = '\0';
-	if (opos > a && x509_whitespace(*opos))
-		*opos = '\0';
-}
-
-
-static int x509_str_compare(const char *a, const char *b)
-{
-	char *aa, *bb;
-	int ret;
-
-	if (!a && b)
-		return -1;
-	if (a && !b)
-		return 1;
-	if (!a && !b)
-		return 0;
-
-	aa = os_strdup(a);
-	bb = os_strdup(b);
-
-	if (aa == NULL || bb == NULL) {
-		os_free(aa);
-		os_free(bb);
-		return os_strcasecmp(a, b);
-	}
-
-	x509_str_strip_whitespace(aa);
-	x509_str_strip_whitespace(bb);
-
-	ret = os_strcasecmp(aa, bb);
-
-	os_free(aa);
-	os_free(bb);
-
-	return ret;
-}
-
-
-/**
- * x509_name_compare - Compare X.509 certificate names
- * @a: Certificate name
- * @b: Certificate name
- * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
- * greater than b
- */
-int x509_name_compare(struct x509_name *a, struct x509_name *b)
-{
-	int res;
-	size_t i;
-
-	if (!a && b)
-		return -1;
-	if (a && !b)
-		return 1;
-	if (!a && !b)
-		return 0;
-	if (a->num_attr < b->num_attr)
-		return -1;
-	if (a->num_attr > b->num_attr)
-		return 1;
-
-	for (i = 0; i < a->num_attr; i++) {
-		if (a->attr[i].type < b->attr[i].type)
-			return -1;
-		if (a->attr[i].type > b->attr[i].type)
-			return -1;
-		res = x509_str_compare(a->attr[i].value, b->attr[i].value);
-		if (res)
-			return res;
-	}
-	res = x509_str_compare(a->email, b->email);
-	if (res)
-		return res;
-
-	return 0;
-}
-
-
-static 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;
-
-	/*
-	 * AlgorithmIdentifier ::= SEQUENCE {
-	 *     algorithm            OBJECT IDENTIFIER,
-	 *     parameters           ANY DEFINED BY algorithm OPTIONAL
-	 * }
-	 */
-
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		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))
-		return -1;
-
-	/* TODO: optional parameters */
-
-	return 0;
-}
-
-
-static int x509_parse_public_key(const u8 *buf, size_t len,
-				 struct x509_certificate *cert,
-				 const u8 **next)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-
-	/*
-	 * SubjectPublicKeyInfo ::= SEQUENCE {
-	 *     algorithm            AlgorithmIdentifier,
-	 *     subjectPublicKey     BIT STRING
-	 * }
-	 */
-
-	pos = buf;
-	end = buf + len;
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-
-	if (pos + hdr.length > end)
-		return -1;
-	end = pos + hdr.length;
-	*next = end;
-
-	if (x509_parse_algorithm_identifier(pos, end - pos,
-					    &cert->public_key_alg, &pos))
-		return -1;
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_BITSTRING) {
-		wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
-			   "(subjectPublicKey) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	if (hdr.length < 1)
-		return -1;
-	pos = hdr.payload;
-	if (*pos) {
-		wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
-			   *pos);
-		/*
-		 * TODO: should this be rejected? X.509 certificates are
-		 * unlikely to use such a construction. Now we would end up
-		 * including the extra bits in the buffer which may also be
-		 * ok.
-		 */
-	}
-	os_free(cert->public_key);
-	cert->public_key = os_malloc(hdr.length - 1);
-	if (cert->public_key == NULL) {
-		wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
-			   "public key");
-		return -1;
-	}
-	os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
-	cert->public_key_len = hdr.length - 1;
-	wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
-		    cert->public_key, cert->public_key_len);
-
-	return 0;
-}
-
-
-static 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;
-	struct asn1_oid oid;
-	char *val;
-
-	/*
-	 * Name ::= CHOICE { RDNSequence }
-	 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
-	 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
-	 * AttributeTypeAndValue ::= SEQUENCE {
-	 *     type     AttributeType,
-	 *     value    AttributeValue
-	 * }
-	 * AttributeType ::= OBJECT IDENTIFIER
-	 * AttributeValue ::= ANY DEFINED BY AttributeType
-	 */
-
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(Name / RDNSequencer) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-
-	if (pos + hdr.length > buf + len)
-		return -1;
-
-	end = *next = pos + hdr.length;
-
-	while (pos < end) {
-		enum x509_name_attr_type type;
-
-		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_UNIVERSAL ||
-		    hdr.tag != ASN1_TAG_SET) {
-			wpa_printf(MSG_DEBUG, "X509: Expected SET "
-				   "(RelativeDistinguishedName) - found class "
-				   "%d tag 0x%x", hdr.class, hdr.tag);
-			x509_free_name(name);
-			return -1;
-		}
-
-		set_pos = hdr.payload;
-		pos = set_end = hdr.payload + hdr.length;
-
-		if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_UNIVERSAL ||
-		    hdr.tag != ASN1_TAG_SEQUENCE) {
-			wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-				   "(AttributeTypeAndValue) - found class %d "
-				   "tag 0x%x", hdr.class, hdr.tag);
-			x509_free_name(name);
-			return -1;
-		}
-
-		seq_pos = hdr.payload;
-		seq_end = hdr.payload + hdr.length;
-
-		if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
-			x509_free_name(name);
-			return -1;
-		}
-
-		if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_UNIVERSAL) {
-			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
-				   "AttributeValue");
-			x509_free_name(name);
-			return -1;
-		}
-
-		/* RFC 3280:
-		 * MUST: country, organization, organizational-unit,
-		 * distinguished name qualifier, state or province name,
-		 * common name, serial number.
-		 * SHOULD: locality, title, surname, given name, initials,
-		 * pseudonym, generation qualifier.
-		 * MUST: domainComponent (RFC 2247).
-		 */
-		type = X509_NAME_ATTR_NOT_USED;
-		if (oid.len == 4 &&
-		    oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
-			/* id-at ::= 2.5.4 */
-			switch (oid.oid[3]) {
-			case 3:
-				/* commonName */
-				type = X509_NAME_ATTR_CN;
-				break;
-			case 6:
-				/*  countryName */
-				type = X509_NAME_ATTR_C;
-				break;
-			case 7:
-				/* localityName */
-				type = X509_NAME_ATTR_L;
-				break;
-			case 8:
-				/* stateOrProvinceName */
-				type = X509_NAME_ATTR_ST;
-				break;
-			case 10:
-				/* organizationName */
-				type = X509_NAME_ATTR_O;
-				break;
-			case 11:
-				/* organizationalUnitName */
-				type = X509_NAME_ATTR_OU;
-				break;
-			}
-		} else if (oid.len == 7 &&
-			   oid.oid[0] == 1 && oid.oid[1] == 2 &&
-			   oid.oid[2] == 840 && oid.oid[3] == 113549 &&
-			   oid.oid[4] == 1 && oid.oid[5] == 9 &&
-			   oid.oid[6] == 1) {
-			/* 1.2.840.113549.1.9.1 - e-mailAddress */
-			os_free(name->email);
-			name->email = os_malloc(hdr.length + 1);
-			if (name->email == NULL) {
-				x509_free_name(name);
-				return -1;
-			}
-			os_memcpy(name->email, hdr.payload, hdr.length);
-			name->email[hdr.length] = '\0';
-			continue;
-		} else if (oid.len == 7 &&
-			   oid.oid[0] == 0 && oid.oid[1] == 9 &&
-			   oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
-			   oid.oid[4] == 100 && oid.oid[5] == 1 &&
-			   oid.oid[6] == 25) {
-			/* 0.9.2342.19200300.100.1.25 - domainComponent */
-			type = X509_NAME_ATTR_DC;
-		}
-
-		if (type == X509_NAME_ATTR_NOT_USED) {
-			wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
-				    (u8 *) oid.oid,
-				    oid.len * sizeof(oid.oid[0]));
-			wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
-					  hdr.payload, hdr.length);
-			continue;
-		}
-
-		if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
-			wpa_printf(MSG_INFO, "X509: Too many Name attributes");
-			x509_free_name(name);
-			return -1;
-		}
-
-		val = os_malloc(hdr.length + 1);
-		if (val == NULL) {
-			x509_free_name(name);
-			return -1;
-		}
-		os_memcpy(val, hdr.payload, hdr.length);
-		val[hdr.length] = '\0';
-		if (os_strlen(val) != hdr.length) {
-			wpa_printf(MSG_INFO, "X509: Reject certificate with "
-				   "embedded NUL byte in a string (%s[NUL])",
-				   val);
-			x509_free_name(name);
-			return -1;
-		}
-
-		name->attr[name->num_attr].type = type;
-		name->attr[name->num_attr].value = val;
-		name->num_attr++;
-	}
-
-	return 0;
-}
-
-
-static char * x509_name_attr_str(enum x509_name_attr_type type)
-{
-	switch (type) {
-	case X509_NAME_ATTR_NOT_USED:
-		return "[N/A]";
-	case X509_NAME_ATTR_DC:
-		return "DC";
-	case X509_NAME_ATTR_CN:
-		return "CN";
-	case X509_NAME_ATTR_C:
-		return "C";
-	case X509_NAME_ATTR_L:
-		return "L";
-	case X509_NAME_ATTR_ST:
-		return "ST";
-	case X509_NAME_ATTR_O:
-		return "O";
-	case X509_NAME_ATTR_OU:
-		return "OU";
-	}
-	return "?";
-}
-
-
-/**
- * x509_name_string - Convert an X.509 certificate name into a string
- * @name: Name to convert
- * @buf: Buffer for the string
- * @len: Maximum buffer length
- */
-void x509_name_string(struct x509_name *name, char *buf, size_t len)
-{
-	char *pos, *end;
-	int ret;
-	size_t i;
-
-	if (len == 0)
-		return;
-
-	pos = buf;
-	end = buf + len;
-
-	for (i = 0; i < name->num_attr; i++) {
-		ret = os_snprintf(pos, end - pos, "%s=%s, ",
-				  x509_name_attr_str(name->attr[i].type),
-				  name->attr[i].value);
-		if (ret < 0 || ret >= end - pos)
-			goto done;
-		pos += ret;
-	}
-
-	if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
-		pos--;
-		*pos = '\0';
-		pos--;
-		*pos = '\0';
-	}
-
-	if (name->email) {
-		ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
-				  name->email);
-		if (ret < 0 || ret >= end - pos)
-			goto done;
-		pos += ret;
-	}
-
-done:
-	end[-1] = '\0';
-}
-
-
-static 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;
-
-	/*
-	 * Time ::= CHOICE {
-	 *     utcTime        UTCTime,
-	 *     generalTime    GeneralizedTime
-	 * }
-	 *
-	 * UTCTime: YYMMDDHHMMSSZ
-	 * GeneralizedTime: YYYYMMDDHHMMSSZ
-	 */
-
-	pos = (const char *) buf;
-
-	switch (asn1_tag) {
-	case ASN1_TAG_UTCTIME:
-		if (len != 13 || buf[12] != 'Z') {
-			wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
-					  "UTCTime format", buf, len);
-			return -1;
-		}
-		if (sscanf(pos, "%02d", &year) != 1) {
-			wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
-					  "UTCTime year", buf, len);
-			return -1;
-		}
-		if (year < 50)
-			year += 2000;
-		else
-			year += 1900;
-		pos += 2;
-		break;
-	case ASN1_TAG_GENERALIZEDTIME:
-		if (len != 15 || buf[14] != 'Z') {
-			wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
-					  "GeneralizedTime format", buf, len);
-			return -1;
-		}
-		if (sscanf(pos, "%04d", &year) != 1) {
-			wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
-					  "GeneralizedTime year", buf, len);
-			return -1;
-		}
-		pos += 4;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
-			   "GeneralizedTime - found tag 0x%x", asn1_tag);
-		return -1;
-	}
-
-	if (sscanf(pos, "%02d", &month) != 1) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
-				  "(month)", buf, len);
-		return -1;
-	}
-	pos += 2;
-
-	if (sscanf(pos, "%02d", &day) != 1) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
-				  "(day)", buf, len);
-		return -1;
-	}
-	pos += 2;
-
-	if (sscanf(pos, "%02d", &hour) != 1) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
-				  "(hour)", buf, len);
-		return -1;
-	}
-	pos += 2;
-
-	if (sscanf(pos, "%02d", &min) != 1) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
-				  "(min)", buf, len);
-		return -1;
-	}
-	pos += 2;
-
-	if (sscanf(pos, "%02d", &sec) != 1) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
-				  "(sec)", buf, len);
-		return -1;
-	}
-
-	if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
-				  buf, len);
-		if (year < 1970) {
-			/*
-			 * At least some test certificates have been configured
-			 * to use dates prior to 1970. Set the date to
-			 * beginning of 1970 to handle these case.
-			 */
-			wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
-				   "assume epoch as the time", year);
-			*val = 0;
-			return 0;
-		}
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int x509_parse_validity(const u8 *buf, size_t len,
-			       struct x509_certificate *cert, const u8 **next)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos;
-	size_t plen;
-
-	/*
-	 * Validity ::= SEQUENCE {
-	 *     notBefore      Time,
-	 *     notAfter       Time
-	 * }
-	 *
-	 * RFC 3280, 4.1.2.5:
-	 * CAs conforming to this profile MUST always encode certificate
-	 * validity dates through the year 2049 as UTCTime; certificate
-	 * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
-	 */
-
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(Validity) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-	plen = hdr.length;
-
-	if (pos + plen > buf + len)
-		return -1;
-
-	*next = pos + plen;
-
-	if (asn1_get_next(pos, plen, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
-			    &cert->not_before) < 0) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
-				  "Time", hdr.payload, hdr.length);
-		return -1;
-	}
-
-	pos = hdr.payload + hdr.length;
-	plen = *next - pos;
-
-	if (asn1_get_next(pos, plen, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
-			    &cert->not_after) < 0) {
-		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
-				  "Time", hdr.payload, hdr.length);
-		return -1;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
-		   (unsigned long) cert->not_before,
-		   (unsigned long) cert->not_after);
-
-	return 0;
-}
-
-
-static int x509_id_ce_oid(struct asn1_oid *oid)
-{
-	/* id-ce arc from X.509 for standard X.509v3 extensions */
-	return oid->len >= 4 &&
-		oid->oid[0] == 2 /* joint-iso-ccitt */ &&
-		oid->oid[1] == 5 /* ds */ &&
-		oid->oid[2] == 29 /* id-ce */;
-}
-
-
-static int x509_parse_ext_key_usage(struct x509_certificate *cert,
-				    const u8 *pos, size_t len)
-{
-	struct asn1_hdr hdr;
-
-	/*
-	 * KeyUsage ::= BIT STRING {
-	 *     digitalSignature        (0),
-	 *     nonRepudiation          (1),
-	 *     keyEncipherment         (2),
-	 *     dataEncipherment        (3),
-	 *     keyAgreement            (4),
-	 *     keyCertSign             (5),
-	 *     cRLSign                 (6),
-	 *     encipherOnly            (7),
-	 *     decipherOnly            (8) }
-	 */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_BITSTRING ||
-	    hdr.length < 1) {
-		wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
-			   "KeyUsage; found %d tag 0x%x len %d",
-			   hdr.class, hdr.tag, hdr.length);
-		return -1;
-	}
-
-	cert->extensions_present |= X509_EXT_KEY_USAGE;
-	cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
-
-	wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
-
-	return 0;
-}
-
-
-static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
-					    const u8 *pos, size_t len)
-{
-	struct asn1_hdr hdr;
-	unsigned long value;
-	size_t left;
-
-	/*
-	 * BasicConstraints ::= SEQUENCE {
-	 * cA                      BOOLEAN DEFAULT FALSE,
-	 * pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
-	 */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
-			   "BasicConstraints; found %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
-
-	if (hdr.length == 0)
-		return 0;
-
-	if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL) {
-		wpa_printf(MSG_DEBUG, "X509: Failed to parse "
-			   "BasicConstraints");
-		return -1;
-	}
-
-	if (hdr.tag == ASN1_TAG_BOOLEAN) {
-		if (hdr.length != 1) {
-			wpa_printf(MSG_DEBUG, "X509: Unexpected "
-				   "Boolean length (%u) in BasicConstraints",
-				   hdr.length);
-			return -1;
-		}
-		cert->ca = hdr.payload[0];
-
-		if (hdr.payload + hdr.length == pos + len) {
-			wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
-				   cert->ca);
-			return 0;
-		}
-
-		if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
-				  &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_UNIVERSAL) {
-			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
-				   "BasicConstraints");
-			return -1;
-		}
-	}
-
-	if (hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
-			   "BasicConstraints; found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	pos = hdr.payload;
-	left = hdr.length;
-	value = 0;
-	while (left) {
-		value <<= 8;
-		value |= *pos++;
-		left--;
-	}
-
-	cert->path_len_constraint = value;
-	cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
-
-	wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
-		   "pathLenConstraint=%lu",
-		   cert->ca, cert->path_len_constraint);
-
-	return 0;
-}
-
-
-static int x509_parse_alt_name_rfc8222(struct x509_name *name,
-				       const u8 *pos, size_t len)
-{
-	/* rfc822Name IA5String */
-	wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
-	os_free(name->alt_email);
-	name->alt_email = os_zalloc(len + 1);
-	if (name->alt_email == NULL)
-		return -1;
-	os_memcpy(name->alt_email, pos, len);
-	if (os_strlen(name->alt_email) != len) {
-		wpa_printf(MSG_INFO, "X509: Reject certificate with "
-			   "embedded NUL byte in rfc822Name (%s[NUL])",
-			   name->alt_email);
-		os_free(name->alt_email);
-		name->alt_email = NULL;
-		return -1;
-	}
-	return 0;
-}
-
-
-static int x509_parse_alt_name_dns(struct x509_name *name,
-				   const u8 *pos, size_t len)
-{
-	/* dNSName IA5String */
-	wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
-	os_free(name->dns);
-	name->dns = os_zalloc(len + 1);
-	if (name->dns == NULL)
-		return -1;
-	os_memcpy(name->dns, pos, len);
-	if (os_strlen(name->dns) != len) {
-		wpa_printf(MSG_INFO, "X509: Reject certificate with "
-			   "embedded NUL byte in dNSName (%s[NUL])",
-			   name->dns);
-		os_free(name->dns);
-		name->dns = NULL;
-		return -1;
-	}
-	return 0;
-}
-
-
-static int x509_parse_alt_name_uri(struct x509_name *name,
-				   const u8 *pos, size_t len)
-{
-	/* uniformResourceIdentifier IA5String */
-	wpa_hexdump_ascii(MSG_MSGDUMP,
-			  "X509: altName - uniformResourceIdentifier",
-			  pos, len);
-	os_free(name->uri);
-	name->uri = os_zalloc(len + 1);
-	if (name->uri == NULL)
-		return -1;
-	os_memcpy(name->uri, pos, len);
-	if (os_strlen(name->uri) != len) {
-		wpa_printf(MSG_INFO, "X509: Reject certificate with "
-			   "embedded NUL byte in uniformResourceIdentifier "
-			   "(%s[NUL])", name->uri);
-		os_free(name->uri);
-		name->uri = NULL;
-		return -1;
-	}
-	return 0;
-}
-
-
-static int x509_parse_alt_name_ip(struct x509_name *name,
-				       const u8 *pos, size_t len)
-{
-	/* iPAddress OCTET STRING */
-	wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
-	os_free(name->ip);
-	name->ip = os_malloc(len);
-	if (name->ip == NULL)
-		return -1;
-	os_memcpy(name->ip, pos, len);
-	name->ip_len = len;
-	return 0;
-}
-
-
-static int x509_parse_alt_name_rid(struct x509_name *name,
-				   const u8 *pos, size_t len)
-{
-	char buf[80];
-
-	/* registeredID OBJECT IDENTIFIER */
-	if (asn1_parse_oid(pos, len, &name->rid) < 0)
-		return -1;
-
-	asn1_oid_to_str(&name->rid, buf, sizeof(buf));
-	wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
-
-	return 0;
-}
-
-
-static int x509_parse_ext_alt_name(struct x509_name *name,
-				   const u8 *pos, size_t len)
-{
-	struct asn1_hdr hdr;
-	const u8 *p, *end;
-
-	/*
-	 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-	 *
-	 * GeneralName ::= CHOICE {
-	 *     otherName                       [0]     OtherName,
-	 *     rfc822Name                      [1]     IA5String,
-	 *     dNSName                         [2]     IA5String,
-	 *     x400Address                     [3]     ORAddress,
-	 *     directoryName                   [4]     Name,
-	 *     ediPartyName                    [5]     EDIPartyName,
-	 *     uniformResourceIdentifier       [6]     IA5String,
-	 *     iPAddress                       [7]     OCTET STRING,
-	 *     registeredID                    [8]     OBJECT IDENTIFIER }
-	 *
-	 * OtherName ::= SEQUENCE {
-	 *     type-id    OBJECT IDENTIFIER,
-	 *     value      [0] EXPLICIT ANY DEFINED BY type-id }
-	 *
-	 * EDIPartyName ::= SEQUENCE {
-	 *     nameAssigner            [0]     DirectoryString OPTIONAL,
-	 *     partyName               [1]     DirectoryString }
-	 */
-
-	for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
-		int res;
-
-		if (asn1_get_next(p, end - p, &hdr) < 0) {
-			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
-				   "SubjectAltName item");
-			return -1;
-		}
-
-		if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
-			continue;
-
-		switch (hdr.tag) {
-		case 1:
-			res = x509_parse_alt_name_rfc8222(name, hdr.payload,
-							  hdr.length);
-			break;
-		case 2:
-			res = x509_parse_alt_name_dns(name, hdr.payload,
-						      hdr.length);
-			break;
-		case 6:
-			res = x509_parse_alt_name_uri(name, hdr.payload,
-						      hdr.length);
-			break;
-		case 7:
-			res = x509_parse_alt_name_ip(name, hdr.payload,
-						     hdr.length);
-			break;
-		case 8:
-			res = x509_parse_alt_name_rid(name, hdr.payload,
-						      hdr.length);
-			break;
-		case 0: /* TODO: otherName */
-		case 3: /* TODO: x500Address */
-		case 4: /* TODO: directoryName */
-		case 5: /* TODO: ediPartyName */
-		default:
-			res = 0;
-			break;
-		}
-		if (res < 0)
-			return res;
-	}
-
-	return 0;
-}
-
-
-static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
-					   const u8 *pos, size_t len)
-{
-	struct asn1_hdr hdr;
-
-	/* SubjectAltName ::= GeneralNames */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
-			   "SubjectAltName; found %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
-	cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
-
-	if (hdr.length == 0)
-		return 0;
-
-	return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
-				       hdr.length);
-}
-
-
-static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
-					  const u8 *pos, size_t len)
-{
-	struct asn1_hdr hdr;
-
-	/* IssuerAltName ::= GeneralNames */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
-			   "IssuerAltName; found %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
-	cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
-
-	if (hdr.length == 0)
-		return 0;
-
-	return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
-				       hdr.length);
-}
-
-
-static int x509_parse_extension_data(struct x509_certificate *cert,
-				     struct asn1_oid *oid,
-				     const u8 *pos, size_t len)
-{
-	if (!x509_id_ce_oid(oid))
-		return 1;
-
-	/* TODO: add other extensions required by RFC 3280, Ch 4.2:
-	 * certificate policies (section 4.2.1.5)
-	 * name constraints (section 4.2.1.11)
-	 * policy constraints (section 4.2.1.12)
-	 * extended key usage (section 4.2.1.13)
-	 * inhibit any-policy (section 4.2.1.15)
-	 */
-	switch (oid->oid[3]) {
-	case 15: /* id-ce-keyUsage */
-		return x509_parse_ext_key_usage(cert, pos, len);
-	case 17: /* id-ce-subjectAltName */
-		return x509_parse_ext_subject_alt_name(cert, pos, len);
-	case 18: /* id-ce-issuerAltName */
-		return x509_parse_ext_issuer_alt_name(cert, pos, len);
-	case 19: /* id-ce-basicConstraints */
-		return x509_parse_ext_basic_constraints(cert, pos, len);
-	default:
-		return 1;
-	}
-}
-
-
-static int x509_parse_extension(struct x509_certificate *cert,
-				const u8 *pos, size_t len, const u8 **next)
-{
-	const u8 *end;
-	struct asn1_hdr hdr;
-	struct asn1_oid oid;
-	int critical_ext = 0, res;
-	char buf[80];
-
-	/*
-	 * Extension  ::=  SEQUENCE  {
-	 *     extnID      OBJECT IDENTIFIER,
-	 *     critical    BOOLEAN DEFAULT FALSE,
-	 *     extnValue   OCTET STRING
-	 * }
-	 */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
-			   "Extensions: class %d tag 0x%x; expected SEQUENCE",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-	*next = end = pos + hdr.length;
-
-	if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
-		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
-			   "Extension (expected OID)");
-		return -1;
-	}
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    (hdr.tag != ASN1_TAG_BOOLEAN &&
-	     hdr.tag != ASN1_TAG_OCTETSTRING)) {
-		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
-			   "Extensions: class %d tag 0x%x; expected BOOLEAN "
-			   "or OCTET STRING", hdr.class, hdr.tag);
-		return -1;
-	}
-
-	if (hdr.tag == ASN1_TAG_BOOLEAN) {
-		if (hdr.length != 1) {
-			wpa_printf(MSG_DEBUG, "X509: Unexpected "
-				   "Boolean length (%u)", hdr.length);
-			return -1;
-		}
-		critical_ext = hdr.payload[0];
-		pos = hdr.payload;
-		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-		    (hdr.class != ASN1_CLASS_UNIVERSAL &&
-		     hdr.class != ASN1_CLASS_PRIVATE) ||
-		    hdr.tag != ASN1_TAG_OCTETSTRING) {
-			wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
-				   "in Extensions: class %d tag 0x%x; "
-				   "expected OCTET STRING",
-				   hdr.class, hdr.tag);
-			return -1;
-		}
-	}
-
-	asn1_oid_to_str(&oid, buf, sizeof(buf));
-	wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
-		   buf, critical_ext);
-	wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
-
-	res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
-	if (res < 0)
-		return res;
-	if (res == 1 && critical_ext) {
-		wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
-			   buf);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int x509_parse_extensions(struct x509_certificate *cert,
-				 const u8 *pos, size_t len)
-{
-	const u8 *end;
-	struct asn1_hdr hdr;
-
-	/* Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension */
-
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
-			   "for Extensions: class %d tag 0x%x; "
-			   "expected SEQUENCE", hdr.class, hdr.tag);
-		return -1;
-	}
-
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	while (pos < end) {
-		if (x509_parse_extension(cert, pos, end - pos, &pos)
-		    < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-
-static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
-				      struct x509_certificate *cert,
-				      const u8 **next)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end;
-	size_t left;
-	char sbuf[128];
-	unsigned long value;
-
-	/* tbsCertificate TBSCertificate ::= SEQUENCE */
-	if (asn1_get_next(buf, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
-			   "with a valid SEQUENCE - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-	pos = hdr.payload;
-	end = *next = pos + hdr.length;
-
-	/*
-	 * version [0]  EXPLICIT Version DEFAULT v1
-	 * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
-	 */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0)
-		return -1;
-	pos = hdr.payload;
-
-	if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
-		if (asn1_get_next(pos, end - pos, &hdr) < 0)
-			return -1;
-
-		if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-		    hdr.tag != ASN1_TAG_INTEGER) {
-			wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
-				   "version field - found class %d tag 0x%x",
-				   hdr.class, hdr.tag);
-			return -1;
-		}
-		if (hdr.length != 1) {
-			wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
-				   "length %u (expected 1)", hdr.length);
-			return -1;
-		}
-		pos = hdr.payload;
-		left = hdr.length;
-		value = 0;
-		while (left) {
-			value <<= 8;
-			value |= *pos++;
-			left--;
-		}
-
-		cert->version = value;
-		if (cert->version != X509_CERT_V1 &&
-		    cert->version != X509_CERT_V2 &&
-		    cert->version != X509_CERT_V3) {
-			wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
-				   cert->version + 1);
-			return -1;
-		}
-
-		if (asn1_get_next(pos, end - pos, &hdr) < 0)
-			return -1;
-	} else
-		cert->version = X509_CERT_V1;
-	wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
-
-	/* serialNumber CertificateSerialNumber ::= INTEGER */
-	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_INTEGER) {
-		wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
-			   "serialNumber; class=%d tag=0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	pos = hdr.payload;
-	left = hdr.length;
-	while (left) {
-		cert->serial_number <<= 8;
-		cert->serial_number |= *pos++;
-		left--;
-	}
-	wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
-
-	/* signature AlgorithmIdentifier */
-	if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
-					    &pos))
-		return -1;
-
-	/* issuer Name */
-	if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
-		return -1;
-	x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
-	wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
-
-	/* validity Validity */
-	if (x509_parse_validity(pos, end - pos, cert, &pos))
-		return -1;
-
-	/* subject Name */
-	if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
-		return -1;
-	x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
-	wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
-
-	/* subjectPublicKeyInfo SubjectPublicKeyInfo */
-	if (x509_parse_public_key(pos, end - pos, cert, &pos))
-		return -1;
-
-	if (pos == end)
-		return 0;
-
-	if (cert->version == X509_CERT_V1)
-		return 0;
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
-		wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
-			   " tag to parse optional tbsCertificate "
-			   "field(s); parsed class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		return -1;
-	}
-
-	if (hdr.tag == 1) {
-		/* issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL */
-		wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
-		/* TODO: parse UniqueIdentifier ::= BIT STRING */
-
-		if (hdr.payload + hdr.length == end)
-			return 0;
-
-		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
-			wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
-				   " tag to parse optional tbsCertificate "
-				   "field(s); parsed class %d tag 0x%x",
-				   hdr.class, hdr.tag);
-			return -1;
-		}
-	}
-
-	if (hdr.tag == 2) {
-		/* subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL */
-		wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
-		/* TODO: parse UniqueIdentifier ::= BIT STRING */
-
-		if (hdr.payload + hdr.length == end)
-			return 0;
-
-		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-		    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
-			wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
-				   " tag to parse optional tbsCertificate "
-				   "field(s); parsed class %d tag 0x%x",
-				   hdr.class, hdr.tag);
-			return -1;
-		}
-	}
-
-	if (hdr.tag != 3) {
-		wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
-			   "Context-Specific tag %d in optional "
-			   "tbsCertificate fields", hdr.tag);
-		return 0;
-	}
-
-	/* extensions      [3]  EXPLICIT Extensions OPTIONAL */
-
-	if (cert->version != X509_CERT_V3) {
-		wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
-			   "Extensions data which are only allowed for "
-			   "version 3", cert->version + 1);
-		return -1;
-	}
-
-	if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
-		return -1;
-
-	pos = hdr.payload + hdr.length;
-	if (pos < end) {
-		wpa_hexdump(MSG_DEBUG,
-			    "X509: Ignored extra tbsCertificate data",
-			    pos, end - pos);
-	}
-
-	return 0;
-}
-
-
-static int x509_rsadsi_oid(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 x509_pkcs_oid(struct asn1_oid *oid)
-{
-	return oid->len >= 5 &&
-		x509_rsadsi_oid(oid) &&
-		oid->oid[4] == 1 /* pkcs */;
-}
-
-
-static int x509_digest_oid(struct asn1_oid *oid)
-{
-	return oid->len >= 5 &&
-		x509_rsadsi_oid(oid) &&
-		oid->oid[4] == 2 /* digestAlgorithm */;
-}
-
-
-static int x509_sha1_oid(struct asn1_oid *oid)
-{
-	return oid->len == 6 &&
-		oid->oid[0] == 1 /* iso */ &&
-		oid->oid[1] == 3 /* identified-organization */ &&
-		oid->oid[2] == 14 /* oiw */ &&
-		oid->oid[3] == 3 /* secsig */ &&
-		oid->oid[4] == 2 /* algorithms */ &&
-		oid->oid[5] == 26 /* id-sha1 */;
-}
-
-
-static int x509_sha256_oid(struct asn1_oid *oid)
-{
-	return oid->len == 9 &&
-		oid->oid[0] == 2 /* joint-iso-itu-t */ &&
-		oid->oid[1] == 16 /* country */ &&
-		oid->oid[2] == 840 /* us */ &&
-		oid->oid[3] == 1 /* organization */ &&
-		oid->oid[4] == 101 /* gov */ &&
-		oid->oid[5] == 3 /* csor */ &&
-		oid->oid[6] == 4 /* nistAlgorithm */ &&
-		oid->oid[7] == 2 /* hashAlgs */ &&
-		oid->oid[8] == 1 /* sha256 */;
-}
-
-
-/**
- * x509_certificate_parse - Parse a X.509 certificate in DER format
- * @buf: Pointer to the X.509 certificate in DER format
- * @len: Buffer length
- * Returns: Pointer to the parsed certificate or %NULL on failure
- *
- * Caller is responsible for freeing the returned certificate by calling
- * x509_certificate_free().
- */
-struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
-{
-	struct asn1_hdr hdr;
-	const u8 *pos, *end, *hash_start;
-	struct x509_certificate *cert;
-
-	cert = os_zalloc(sizeof(*cert) + len);
-	if (cert == NULL)
-		return NULL;
-	os_memcpy(cert + 1, buf, len);
-	cert->cert_start = (u8 *) (cert + 1);
-	cert->cert_len = len;
-
-	pos = buf;
-	end = buf + len;
-
-	/* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
-
-	/* Certificate ::= SEQUENCE */
-	if (asn1_get_next(pos, len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
-			   "a valid SEQUENCE - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	pos = hdr.payload;
-
-	if (pos + hdr.length > end) {
-		x509_certificate_free(cert);
-		return NULL;
-	}
-
-	if (pos + hdr.length < end) {
-		wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
-			    "encoded certificate",
-			    pos + hdr.length, end - pos + hdr.length);
-		end = pos + hdr.length;
-	}
-
-	hash_start = pos;
-	cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
-	if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	cert->tbs_cert_len = pos - hash_start;
-
-	/* signatureAlgorithm AlgorithmIdentifier */
-	if (x509_parse_algorithm_identifier(pos, end - pos,
-					    &cert->signature_alg, &pos)) {
-		x509_certificate_free(cert);
-		return NULL;
-	}
-
-	/* signatureValue BIT STRING */
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_BITSTRING) {
-		wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
-			   "(signatureValue) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	if (hdr.length < 1) {
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	pos = hdr.payload;
-	if (*pos) {
-		wpa_printf(MSG_DEBUG, "X509: 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.
-		 */
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	os_free(cert->sign_value);
-	cert->sign_value = os_malloc(hdr.length - 1);
-	if (cert->sign_value == NULL) {
-		wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
-			   "signatureValue");
-		x509_certificate_free(cert);
-		return NULL;
-	}
-	os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
-	cert->sign_value_len = hdr.length - 1;
-	wpa_hexdump(MSG_MSGDUMP, "X509: signature",
-		    cert->sign_value, cert->sign_value_len);
-
-	return cert;
-}
-
-
-/**
- * x509_certificate_check_signature - Verify certificate signature
- * @issuer: Issuer certificate
- * @cert: Certificate to be verified
- * Returns: 0 if cert has a valid signature that was signed by the issuer,
- * -1 if not
- */
-int x509_certificate_check_signature(struct x509_certificate *issuer,
-				     struct x509_certificate *cert)
-{
-	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];
-	size_t hash_len;
-
-	if (!x509_pkcs_oid(&cert->signature.oid) ||
-	    cert->signature.oid.len != 7 ||
-	    cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
-		wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
-			   "algorithm");
-		return -1;
-	}
-
-	pk = crypto_public_key_import(issuer->public_key,
-				      issuer->public_key_len);
-	if (pk == NULL)
-		return -1;
-
-	data_len = cert->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,
-					    &data_len) < 0) {
-		wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
-		crypto_public_key_free(pk);
-		os_free(data);
-		return -1;
-	}
-	crypto_public_key_free(pk);
-
-	wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
-
-	/*
-	 * PKCS #1 v1.5, 10.1.2:
-	 *
-	 * DigestInfo ::= SEQUENCE {
-	 *     digestAlgorithm DigestAlgorithmIdentifier,
-	 *     digest Digest
-	 * }
-	 *
-	 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
-	 *
-	 * Digest ::= OCTET STRING
-	 *
-	 */
-	if (asn1_get_next(data, data_len, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(DigestInfo) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		os_free(data);
-		return -1;
-	}
-
-	pos = hdr.payload;
-	end = pos + hdr.length;
-
-	/*
-	 * X.509:
-	 * AlgorithmIdentifier ::= SEQUENCE {
-	 *     algorithm            OBJECT IDENTIFIER,
-	 *     parameters           ANY DEFINED BY algorithm OPTIONAL
-	 * }
-	 */
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_SEQUENCE) {
-		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
-			   "(AlgorithmIdentifier) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		os_free(data);
-		return -1;
-	}
-	da_end = hdr.payload + hdr.length;
-
-	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
-		wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
-		os_free(data);
-		return -1;
-	}
-
-	if (x509_sha1_oid(&oid)) {
-		if (cert->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]);
-			os_free(data);
-			return -1;
-		}
-		goto skip_digest_oid;
-	}
-
-	if (x509_sha256_oid(&oid)) {
-		if (cert->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]);
-			os_free(data);
-			return -1;
-		}
-		goto skip_digest_oid;
-	}
-
-	if (!x509_digest_oid(&oid)) {
-		wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
-		os_free(data);
-		return -1;
-	}
-	switch (oid.oid[5]) {
-	case 5: /* md5 */
-		if (cert->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]);
-			os_free(data);
-			return -1;
-		}
-		break;
-	case 2: /* md2 */
-	case 4: /* md4 */
-	default:
-		wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
-			   "(%lu)", oid.oid[5]);
-		os_free(data);
-		return -1;
-	}
-
-skip_digest_oid:
-	/* Digest ::= OCTET STRING */
-	pos = da_end;
-	end = data + data_len;
-
-	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-	    hdr.class != ASN1_CLASS_UNIVERSAL ||
-	    hdr.tag != ASN1_TAG_OCTETSTRING) {
-		wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
-			   "(Digest) - found class %d tag 0x%x",
-			   hdr.class, hdr.tag);
-		os_free(data);
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
-		    hdr.payload, hdr.length);
-
-	switch (cert->signature.oid.oid[6]) {
-	case 4: /* md5WithRSAEncryption */
-		md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_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);
-		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);
-		hash_len = 32;
-		wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
-			    hash, hash_len);
-		break;
-	case 2: /* md2WithRSAEncryption */
-	case 12: /* sha384WithRSAEncryption */
-	case 13: /* sha512WithRSAEncryption */
-	default:
-		wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
-			   "algorithm (%lu)", cert->signature.oid.oid[6]);
-		os_free(data);
-		return -1;
-	}
-
-	if (hdr.length != hash_len ||
-	    os_memcmp(hdr.payload, hash, hdr.length) != 0) {
-		wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
-			   "with calculated tbsCertificate hash");
-		os_free(data);
-		return -1;
-	}
-
-	os_free(data);
-
-	wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
-		   "calculated tbsCertificate hash");
-
-	return 0;
-}
-
-
-static int x509_valid_issuer(const struct x509_certificate *cert)
-{
-	if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
-	    !cert->ca) {
-		wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
-			   "issuer");
-		return -1;
-	}
-
-	if (cert->version == X509_CERT_V3 &&
-	    !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
-		wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
-			   "include BasicConstraints extension");
-		return -1;
-	}
-
-	if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
-	    !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
-		wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
-			   "keyCertSign bit in Key Usage");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * x509_certificate_chain_validate - Validate X.509 certificate chain
- * @trusted: List of trusted certificates
- * @chain: Certificate chain to be validated (first chain must be issued by
- * signed by the second certificate in the chain and so on)
- * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
- * Returns: 0 if chain is valid, -1 if not
- */
-int x509_certificate_chain_validate(struct x509_certificate *trusted,
-				    struct x509_certificate *chain,
-				    int *reason)
-{
-	long unsigned idx;
-	int chain_trusted = 0;
-	struct x509_certificate *cert, *trust;
-	char buf[128];
-	struct os_time now;
-
-	*reason = X509_VALIDATE_OK;
-
-	wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
-	os_get_time(&now);
-
-	for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
-		x509_name_string(&cert->subject, buf, sizeof(buf)); 
-		wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
-
-		if (chain_trusted)
-			continue;
-
-		if ((unsigned long) now.sec <
-		    (unsigned long) cert->not_before ||
-		    (unsigned long) now.sec >
-		    (unsigned long) cert->not_after) {
-			wpa_printf(MSG_INFO, "X509: Certificate not valid "
-				   "(now=%lu not_before=%lu not_after=%lu)",
-				   now.sec, cert->not_before, cert->not_after);
-			*reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
-			return -1;
-		}
-
-		if (cert->next) {
-			if (x509_name_compare(&cert->issuer,
-					      &cert->next->subject) != 0) {
-				wpa_printf(MSG_DEBUG, "X509: Certificate "
-					   "chain issuer name mismatch");
-				x509_name_string(&cert->issuer, buf,
-						 sizeof(buf)); 
-				wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
-					   buf);
-				x509_name_string(&cert->next->subject, buf,
-						 sizeof(buf)); 
-				wpa_printf(MSG_DEBUG, "X509: next cert "
-					   "subject: %s", buf);
-				*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
-				return -1;
-			}
-
-			if (x509_valid_issuer(cert->next) < 0) {
-				*reason = X509_VALIDATE_BAD_CERTIFICATE;
-				return -1;
-			}
-
-			if ((cert->next->extensions_present &
-			     X509_EXT_PATH_LEN_CONSTRAINT) &&
-			    idx > cert->next->path_len_constraint) {
-				wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
-					   " not met (idx=%lu issuer "
-					   "pathLenConstraint=%lu)", idx,
-					   cert->next->path_len_constraint);
-				*reason = X509_VALIDATE_BAD_CERTIFICATE;
-				return -1;
-			}
-
-			if (x509_certificate_check_signature(cert->next, cert)
-			    < 0) {
-				wpa_printf(MSG_DEBUG, "X509: Invalid "
-					   "certificate signature within "
-					   "chain");
-				*reason = X509_VALIDATE_BAD_CERTIFICATE;
-				return -1;
-			}
-		}
-
-		for (trust = trusted; trust; trust = trust->next) {
-			if (x509_name_compare(&cert->issuer, &trust->subject)
-			    == 0)
-				break;
-		}
-
-		if (trust) {
-			wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
-				   "list of trusted certificates");
-			if (x509_valid_issuer(trust) < 0) {
-				*reason = X509_VALIDATE_BAD_CERTIFICATE;
-				return -1;
-			}
-
-			if (x509_certificate_check_signature(trust, cert) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "X509: Invalid "
-					   "certificate signature");
-				*reason = X509_VALIDATE_BAD_CERTIFICATE;
-				return -1;
-			}
-
-			wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
-				   "found to complete the chain");
-			chain_trusted = 1;
-		}
-	}
-
-	if (!chain_trusted) {
-		wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
-			   "from the list of trusted certificates");
-		if (trusted) {
-			*reason = X509_VALIDATE_UNKNOWN_CA;
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
-			   "disabled - ignore unknown CA issue");
-	}
-
-	wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
-
-	return 0;
-}
-
-
-/**
- * x509_certificate_get_subject - Get a certificate based on Subject name
- * @chain: Certificate chain to search through
- * @name: Subject name to search for
- * Returns: Pointer to the certificate with the given Subject name or
- * %NULL on failure
- */
-struct x509_certificate *
-x509_certificate_get_subject(struct x509_certificate *chain,
-			     struct x509_name *name)
-{
-	struct x509_certificate *cert;
-
-	for (cert = chain; cert; cert = cert->next) {
-		if (x509_name_compare(&cert->subject, name) == 0)
-			return cert;
-	}
-	return NULL;
-}
-
-
-/**
- * x509_certificate_self_signed - Is the certificate self-signed?
- * @cert: Certificate
- * Returns: 1 if certificate is self-signed, 0 if not
- */
-int x509_certificate_self_signed(struct x509_certificate *cert)
-{
-	return x509_name_compare(&cert->issuer, &cert->subject) == 0;
-}

Copied: vendor/wpa/2.0/src/tls/x509v3.c (from rev 9639, vendor/wpa/dist/src/tls/x509v3.c)
===================================================================
--- vendor/wpa/2.0/src/tls/x509v3.c	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/x509v3.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1980 @@
+/*
+ * X.509v3 certificate parsing and processing (RFC 3280 profile)
+ * Copyright (c) 2006-2011, Jouni Malinen <j at 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/crypto.h"
+#include "asn1.h"
+#include "x509v3.h"
+
+
+static void x509_free_name(struct x509_name *name)
+{
+	size_t i;
+
+	for (i = 0; i < name->num_attr; i++) {
+		os_free(name->attr[i].value);
+		name->attr[i].value = NULL;
+		name->attr[i].type = X509_NAME_ATTR_NOT_USED;
+	}
+	name->num_attr = 0;
+	os_free(name->email);
+	name->email = NULL;
+
+	os_free(name->alt_email);
+	os_free(name->dns);
+	os_free(name->uri);
+	os_free(name->ip);
+	name->alt_email = name->dns = name->uri = NULL;
+	name->ip = NULL;
+	name->ip_len = 0;
+	os_memset(&name->rid, 0, sizeof(name->rid));
+}
+
+
+/**
+ * x509_certificate_free - Free an X.509 certificate
+ * @cert: Certificate to be freed
+ */
+void x509_certificate_free(struct x509_certificate *cert)
+{
+	if (cert == NULL)
+		return;
+	if (cert->next) {
+		wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
+			   "was still on a list (next=%p)\n",
+			   cert, cert->next);
+	}
+	x509_free_name(&cert->issuer);
+	x509_free_name(&cert->subject);
+	os_free(cert->public_key);
+	os_free(cert->sign_value);
+	os_free(cert);
+}
+
+
+/**
+ * x509_certificate_free - Free an X.509 certificate chain
+ * @cert: Pointer to the first certificate in the chain
+ */
+void x509_certificate_chain_free(struct x509_certificate *cert)
+{
+	struct x509_certificate *next;
+
+	while (cert) {
+		next = cert->next;
+		cert->next = NULL;
+		x509_certificate_free(cert);
+		cert = next;
+	}
+}
+
+
+static int x509_whitespace(char c)
+{
+	return c == ' ' || c == '\t';
+}
+
+
+static void x509_str_strip_whitespace(char *a)
+{
+	char *ipos, *opos;
+	int remove_whitespace = 1;
+
+	ipos = opos = a;
+
+	while (*ipos) {
+		if (remove_whitespace && x509_whitespace(*ipos))
+			ipos++;
+		else {
+			remove_whitespace = x509_whitespace(*ipos);
+			*opos++ = *ipos++;
+		}
+	}
+
+	*opos-- = '\0';
+	if (opos > a && x509_whitespace(*opos))
+		*opos = '\0';
+}
+
+
+static int x509_str_compare(const char *a, const char *b)
+{
+	char *aa, *bb;
+	int ret;
+
+	if (!a && b)
+		return -1;
+	if (a && !b)
+		return 1;
+	if (!a && !b)
+		return 0;
+
+	aa = os_strdup(a);
+	bb = os_strdup(b);
+
+	if (aa == NULL || bb == NULL) {
+		os_free(aa);
+		os_free(bb);
+		return os_strcasecmp(a, b);
+	}
+
+	x509_str_strip_whitespace(aa);
+	x509_str_strip_whitespace(bb);
+
+	ret = os_strcasecmp(aa, bb);
+
+	os_free(aa);
+	os_free(bb);
+
+	return ret;
+}
+
+
+/**
+ * x509_name_compare - Compare X.509 certificate names
+ * @a: Certificate name
+ * @b: Certificate name
+ * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
+ * greater than b
+ */
+int x509_name_compare(struct x509_name *a, struct x509_name *b)
+{
+	int res;
+	size_t i;
+
+	if (!a && b)
+		return -1;
+	if (a && !b)
+		return 1;
+	if (!a && !b)
+		return 0;
+	if (a->num_attr < b->num_attr)
+		return -1;
+	if (a->num_attr > b->num_attr)
+		return 1;
+
+	for (i = 0; i < a->num_attr; i++) {
+		if (a->attr[i].type < b->attr[i].type)
+			return -1;
+		if (a->attr[i].type > b->attr[i].type)
+			return -1;
+		res = x509_str_compare(a->attr[i].value, b->attr[i].value);
+		if (res)
+			return res;
+	}
+	res = x509_str_compare(a->email, b->email);
+	if (res)
+		return res;
+
+	return 0;
+}
+
+
+static 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;
+
+	/*
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *     algorithm            OBJECT IDENTIFIER,
+	 *     parameters           ANY DEFINED BY algorithm OPTIONAL
+	 * }
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(AlgorithmIdentifier) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		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))
+		return -1;
+
+	/* TODO: optional parameters */
+
+	return 0;
+}
+
+
+static int x509_parse_public_key(const u8 *buf, size_t len,
+				 struct x509_certificate *cert,
+				 const u8 **next)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	/*
+	 * SubjectPublicKeyInfo ::= SEQUENCE {
+	 *     algorithm            AlgorithmIdentifier,
+	 *     subjectPublicKey     BIT STRING
+	 * }
+	 */
+
+	pos = buf;
+	end = buf + len;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+
+	if (pos + hdr.length > end)
+		return -1;
+	end = pos + hdr.length;
+	*next = end;
+
+	if (x509_parse_algorithm_identifier(pos, end - pos,
+					    &cert->public_key_alg, &pos))
+		return -1;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_BITSTRING) {
+		wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
+			   "(subjectPublicKey) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	if (hdr.length < 1)
+		return -1;
+	pos = hdr.payload;
+	if (*pos) {
+		wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+			   *pos);
+		/*
+		 * TODO: should this be rejected? X.509 certificates are
+		 * unlikely to use such a construction. Now we would end up
+		 * including the extra bits in the buffer which may also be
+		 * ok.
+		 */
+	}
+	os_free(cert->public_key);
+	cert->public_key = os_malloc(hdr.length - 1);
+	if (cert->public_key == NULL) {
+		wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
+			   "public key");
+		return -1;
+	}
+	os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
+	cert->public_key_len = hdr.length - 1;
+	wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
+		    cert->public_key, cert->public_key_len);
+
+	return 0;
+}
+
+
+static 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;
+	struct asn1_oid oid;
+	char *val;
+
+	/*
+	 * Name ::= CHOICE { RDNSequence }
+	 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+	 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+	 * AttributeTypeAndValue ::= SEQUENCE {
+	 *     type     AttributeType,
+	 *     value    AttributeValue
+	 * }
+	 * AttributeType ::= OBJECT IDENTIFIER
+	 * AttributeValue ::= ANY DEFINED BY AttributeType
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(Name / RDNSequencer) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+
+	if (pos + hdr.length > buf + len)
+		return -1;
+
+	end = *next = pos + hdr.length;
+
+	while (pos < end) {
+		enum x509_name_attr_type type;
+
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL ||
+		    hdr.tag != ASN1_TAG_SET) {
+			wpa_printf(MSG_DEBUG, "X509: Expected SET "
+				   "(RelativeDistinguishedName) - found class "
+				   "%d tag 0x%x", hdr.class, hdr.tag);
+			x509_free_name(name);
+			return -1;
+		}
+
+		set_pos = hdr.payload;
+		pos = set_end = hdr.payload + hdr.length;
+
+		if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL ||
+		    hdr.tag != ASN1_TAG_SEQUENCE) {
+			wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+				   "(AttributeTypeAndValue) - found class %d "
+				   "tag 0x%x", hdr.class, hdr.tag);
+			x509_free_name(name);
+			return -1;
+		}
+
+		seq_pos = hdr.payload;
+		seq_end = hdr.payload + hdr.length;
+
+		if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
+			x509_free_name(name);
+			return -1;
+		}
+
+		if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL) {
+			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+				   "AttributeValue");
+			x509_free_name(name);
+			return -1;
+		}
+
+		/* RFC 3280:
+		 * MUST: country, organization, organizational-unit,
+		 * distinguished name qualifier, state or province name,
+		 * common name, serial number.
+		 * SHOULD: locality, title, surname, given name, initials,
+		 * pseudonym, generation qualifier.
+		 * MUST: domainComponent (RFC 2247).
+		 */
+		type = X509_NAME_ATTR_NOT_USED;
+		if (oid.len == 4 &&
+		    oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
+			/* id-at ::= 2.5.4 */
+			switch (oid.oid[3]) {
+			case 3:
+				/* commonName */
+				type = X509_NAME_ATTR_CN;
+				break;
+			case 6:
+				/*  countryName */
+				type = X509_NAME_ATTR_C;
+				break;
+			case 7:
+				/* localityName */
+				type = X509_NAME_ATTR_L;
+				break;
+			case 8:
+				/* stateOrProvinceName */
+				type = X509_NAME_ATTR_ST;
+				break;
+			case 10:
+				/* organizationName */
+				type = X509_NAME_ATTR_O;
+				break;
+			case 11:
+				/* organizationalUnitName */
+				type = X509_NAME_ATTR_OU;
+				break;
+			}
+		} else if (oid.len == 7 &&
+			   oid.oid[0] == 1 && oid.oid[1] == 2 &&
+			   oid.oid[2] == 840 && oid.oid[3] == 113549 &&
+			   oid.oid[4] == 1 && oid.oid[5] == 9 &&
+			   oid.oid[6] == 1) {
+			/* 1.2.840.113549.1.9.1 - e-mailAddress */
+			os_free(name->email);
+			name->email = os_malloc(hdr.length + 1);
+			if (name->email == NULL) {
+				x509_free_name(name);
+				return -1;
+			}
+			os_memcpy(name->email, hdr.payload, hdr.length);
+			name->email[hdr.length] = '\0';
+			continue;
+		} else if (oid.len == 7 &&
+			   oid.oid[0] == 0 && oid.oid[1] == 9 &&
+			   oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
+			   oid.oid[4] == 100 && oid.oid[5] == 1 &&
+			   oid.oid[6] == 25) {
+			/* 0.9.2342.19200300.100.1.25 - domainComponent */
+			type = X509_NAME_ATTR_DC;
+		}
+
+		if (type == X509_NAME_ATTR_NOT_USED) {
+			wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
+				    (u8 *) oid.oid,
+				    oid.len * sizeof(oid.oid[0]));
+			wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
+					  hdr.payload, hdr.length);
+			continue;
+		}
+
+		if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
+			wpa_printf(MSG_INFO, "X509: Too many Name attributes");
+			x509_free_name(name);
+			return -1;
+		}
+
+		val = os_malloc(hdr.length + 1);
+		if (val == NULL) {
+			x509_free_name(name);
+			return -1;
+		}
+		os_memcpy(val, hdr.payload, hdr.length);
+		val[hdr.length] = '\0';
+		if (os_strlen(val) != hdr.length) {
+			wpa_printf(MSG_INFO, "X509: Reject certificate with "
+				   "embedded NUL byte in a string (%s[NUL])",
+				   val);
+			x509_free_name(name);
+			return -1;
+		}
+
+		name->attr[name->num_attr].type = type;
+		name->attr[name->num_attr].value = val;
+		name->num_attr++;
+	}
+
+	return 0;
+}
+
+
+static char * x509_name_attr_str(enum x509_name_attr_type type)
+{
+	switch (type) {
+	case X509_NAME_ATTR_NOT_USED:
+		return "[N/A]";
+	case X509_NAME_ATTR_DC:
+		return "DC";
+	case X509_NAME_ATTR_CN:
+		return "CN";
+	case X509_NAME_ATTR_C:
+		return "C";
+	case X509_NAME_ATTR_L:
+		return "L";
+	case X509_NAME_ATTR_ST:
+		return "ST";
+	case X509_NAME_ATTR_O:
+		return "O";
+	case X509_NAME_ATTR_OU:
+		return "OU";
+	}
+	return "?";
+}
+
+
+/**
+ * x509_name_string - Convert an X.509 certificate name into a string
+ * @name: Name to convert
+ * @buf: Buffer for the string
+ * @len: Maximum buffer length
+ */
+void x509_name_string(struct x509_name *name, char *buf, size_t len)
+{
+	char *pos, *end;
+	int ret;
+	size_t i;
+
+	if (len == 0)
+		return;
+
+	pos = buf;
+	end = buf + len;
+
+	for (i = 0; i < name->num_attr; i++) {
+		ret = os_snprintf(pos, end - pos, "%s=%s, ",
+				  x509_name_attr_str(name->attr[i].type),
+				  name->attr[i].value);
+		if (ret < 0 || ret >= end - pos)
+			goto done;
+		pos += ret;
+	}
+
+	if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
+		pos--;
+		*pos = '\0';
+		pos--;
+		*pos = '\0';
+	}
+
+	if (name->email) {
+		ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
+				  name->email);
+		if (ret < 0 || ret >= end - pos)
+			goto done;
+		pos += ret;
+	}
+
+done:
+	end[-1] = '\0';
+}
+
+
+static 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;
+
+	/*
+	 * Time ::= CHOICE {
+	 *     utcTime        UTCTime,
+	 *     generalTime    GeneralizedTime
+	 * }
+	 *
+	 * UTCTime: YYMMDDHHMMSSZ
+	 * GeneralizedTime: YYYYMMDDHHMMSSZ
+	 */
+
+	pos = (const char *) buf;
+
+	switch (asn1_tag) {
+	case ASN1_TAG_UTCTIME:
+		if (len != 13 || buf[12] != 'Z') {
+			wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
+					  "UTCTime format", buf, len);
+			return -1;
+		}
+		if (sscanf(pos, "%02d", &year) != 1) {
+			wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
+					  "UTCTime year", buf, len);
+			return -1;
+		}
+		if (year < 50)
+			year += 2000;
+		else
+			year += 1900;
+		pos += 2;
+		break;
+	case ASN1_TAG_GENERALIZEDTIME:
+		if (len != 15 || buf[14] != 'Z') {
+			wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
+					  "GeneralizedTime format", buf, len);
+			return -1;
+		}
+		if (sscanf(pos, "%04d", &year) != 1) {
+			wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
+					  "GeneralizedTime year", buf, len);
+			return -1;
+		}
+		pos += 4;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
+			   "GeneralizedTime - found tag 0x%x", asn1_tag);
+		return -1;
+	}
+
+	if (sscanf(pos, "%02d", &month) != 1) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+				  "(month)", buf, len);
+		return -1;
+	}
+	pos += 2;
+
+	if (sscanf(pos, "%02d", &day) != 1) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+				  "(day)", buf, len);
+		return -1;
+	}
+	pos += 2;
+
+	if (sscanf(pos, "%02d", &hour) != 1) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+				  "(hour)", buf, len);
+		return -1;
+	}
+	pos += 2;
+
+	if (sscanf(pos, "%02d", &min) != 1) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+				  "(min)", buf, len);
+		return -1;
+	}
+	pos += 2;
+
+	if (sscanf(pos, "%02d", &sec) != 1) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+				  "(sec)", buf, len);
+		return -1;
+	}
+
+	if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
+				  buf, len);
+		if (year < 1970) {
+			/*
+			 * At least some test certificates have been configured
+			 * to use dates prior to 1970. Set the date to
+			 * beginning of 1970 to handle these case.
+			 */
+			wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
+				   "assume epoch as the time", year);
+			*val = 0;
+			return 0;
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int x509_parse_validity(const u8 *buf, size_t len,
+			       struct x509_certificate *cert, const u8 **next)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos;
+	size_t plen;
+
+	/*
+	 * Validity ::= SEQUENCE {
+	 *     notBefore      Time,
+	 *     notAfter       Time
+	 * }
+	 *
+	 * RFC 3280, 4.1.2.5:
+	 * CAs conforming to this profile MUST always encode certificate
+	 * validity dates through the year 2049 as UTCTime; certificate
+	 * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
+	 */
+
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(Validity) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+	plen = hdr.length;
+
+	if (pos + plen > buf + len)
+		return -1;
+
+	*next = pos + plen;
+
+	if (asn1_get_next(pos, plen, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+			    &cert->not_before) < 0) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
+				  "Time", hdr.payload, hdr.length);
+		return -1;
+	}
+
+	pos = hdr.payload + hdr.length;
+	plen = *next - pos;
+
+	if (asn1_get_next(pos, plen, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+			    &cert->not_after) < 0) {
+		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
+				  "Time", hdr.payload, hdr.length);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
+		   (unsigned long) cert->not_before,
+		   (unsigned long) cert->not_after);
+
+	return 0;
+}
+
+
+static int x509_id_ce_oid(struct asn1_oid *oid)
+{
+	/* id-ce arc from X.509 for standard X.509v3 extensions */
+	return oid->len >= 4 &&
+		oid->oid[0] == 2 /* joint-iso-ccitt */ &&
+		oid->oid[1] == 5 /* ds */ &&
+		oid->oid[2] == 29 /* id-ce */;
+}
+
+
+static int x509_parse_ext_key_usage(struct x509_certificate *cert,
+				    const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+
+	/*
+	 * KeyUsage ::= BIT STRING {
+	 *     digitalSignature        (0),
+	 *     nonRepudiation          (1),
+	 *     keyEncipherment         (2),
+	 *     dataEncipherment        (3),
+	 *     keyAgreement            (4),
+	 *     keyCertSign             (5),
+	 *     cRLSign                 (6),
+	 *     encipherOnly            (7),
+	 *     decipherOnly            (8) }
+	 */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_BITSTRING ||
+	    hdr.length < 1) {
+		wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
+			   "KeyUsage; found %d tag 0x%x len %d",
+			   hdr.class, hdr.tag, hdr.length);
+		return -1;
+	}
+
+	cert->extensions_present |= X509_EXT_KEY_USAGE;
+	cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
+
+	wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
+
+	return 0;
+}
+
+
+static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
+					    const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+	unsigned long value;
+	size_t left;
+
+	/*
+	 * BasicConstraints ::= SEQUENCE {
+	 * cA                      BOOLEAN DEFAULT FALSE,
+	 * pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+	 */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
+			   "BasicConstraints; found %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
+
+	if (hdr.length == 0)
+		return 0;
+
+	if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL) {
+		wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+			   "BasicConstraints");
+		return -1;
+	}
+
+	if (hdr.tag == ASN1_TAG_BOOLEAN) {
+		if (hdr.length != 1) {
+			wpa_printf(MSG_DEBUG, "X509: Unexpected "
+				   "Boolean length (%u) in BasicConstraints",
+				   hdr.length);
+			return -1;
+		}
+		cert->ca = hdr.payload[0];
+
+		if (hdr.payload + hdr.length == pos + len) {
+			wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
+				   cert->ca);
+			return 0;
+		}
+
+		if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
+				  &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_UNIVERSAL) {
+			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+				   "BasicConstraints");
+			return -1;
+		}
+	}
+
+	if (hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
+			   "BasicConstraints; found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	pos = hdr.payload;
+	left = hdr.length;
+	value = 0;
+	while (left) {
+		value <<= 8;
+		value |= *pos++;
+		left--;
+	}
+
+	cert->path_len_constraint = value;
+	cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
+
+	wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
+		   "pathLenConstraint=%lu",
+		   cert->ca, cert->path_len_constraint);
+
+	return 0;
+}
+
+
+static int x509_parse_alt_name_rfc8222(struct x509_name *name,
+				       const u8 *pos, size_t len)
+{
+	/* rfc822Name IA5String */
+	wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
+	os_free(name->alt_email);
+	name->alt_email = os_zalloc(len + 1);
+	if (name->alt_email == NULL)
+		return -1;
+	os_memcpy(name->alt_email, pos, len);
+	if (os_strlen(name->alt_email) != len) {
+		wpa_printf(MSG_INFO, "X509: Reject certificate with "
+			   "embedded NUL byte in rfc822Name (%s[NUL])",
+			   name->alt_email);
+		os_free(name->alt_email);
+		name->alt_email = NULL;
+		return -1;
+	}
+	return 0;
+}
+
+
+static int x509_parse_alt_name_dns(struct x509_name *name,
+				   const u8 *pos, size_t len)
+{
+	/* dNSName IA5String */
+	wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
+	os_free(name->dns);
+	name->dns = os_zalloc(len + 1);
+	if (name->dns == NULL)
+		return -1;
+	os_memcpy(name->dns, pos, len);
+	if (os_strlen(name->dns) != len) {
+		wpa_printf(MSG_INFO, "X509: Reject certificate with "
+			   "embedded NUL byte in dNSName (%s[NUL])",
+			   name->dns);
+		os_free(name->dns);
+		name->dns = NULL;
+		return -1;
+	}
+	return 0;
+}
+
+
+static int x509_parse_alt_name_uri(struct x509_name *name,
+				   const u8 *pos, size_t len)
+{
+	/* uniformResourceIdentifier IA5String */
+	wpa_hexdump_ascii(MSG_MSGDUMP,
+			  "X509: altName - uniformResourceIdentifier",
+			  pos, len);
+	os_free(name->uri);
+	name->uri = os_zalloc(len + 1);
+	if (name->uri == NULL)
+		return -1;
+	os_memcpy(name->uri, pos, len);
+	if (os_strlen(name->uri) != len) {
+		wpa_printf(MSG_INFO, "X509: Reject certificate with "
+			   "embedded NUL byte in uniformResourceIdentifier "
+			   "(%s[NUL])", name->uri);
+		os_free(name->uri);
+		name->uri = NULL;
+		return -1;
+	}
+	return 0;
+}
+
+
+static int x509_parse_alt_name_ip(struct x509_name *name,
+				       const u8 *pos, size_t len)
+{
+	/* iPAddress OCTET STRING */
+	wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
+	os_free(name->ip);
+	name->ip = os_malloc(len);
+	if (name->ip == NULL)
+		return -1;
+	os_memcpy(name->ip, pos, len);
+	name->ip_len = len;
+	return 0;
+}
+
+
+static int x509_parse_alt_name_rid(struct x509_name *name,
+				   const u8 *pos, size_t len)
+{
+	char buf[80];
+
+	/* registeredID OBJECT IDENTIFIER */
+	if (asn1_parse_oid(pos, len, &name->rid) < 0)
+		return -1;
+
+	asn1_oid_to_str(&name->rid, buf, sizeof(buf));
+	wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
+
+	return 0;
+}
+
+
+static int x509_parse_ext_alt_name(struct x509_name *name,
+				   const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *p, *end;
+
+	/*
+	 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+	 *
+	 * GeneralName ::= CHOICE {
+	 *     otherName                       [0]     OtherName,
+	 *     rfc822Name                      [1]     IA5String,
+	 *     dNSName                         [2]     IA5String,
+	 *     x400Address                     [3]     ORAddress,
+	 *     directoryName                   [4]     Name,
+	 *     ediPartyName                    [5]     EDIPartyName,
+	 *     uniformResourceIdentifier       [6]     IA5String,
+	 *     iPAddress                       [7]     OCTET STRING,
+	 *     registeredID                    [8]     OBJECT IDENTIFIER }
+	 *
+	 * OtherName ::= SEQUENCE {
+	 *     type-id    OBJECT IDENTIFIER,
+	 *     value      [0] EXPLICIT ANY DEFINED BY type-id }
+	 *
+	 * EDIPartyName ::= SEQUENCE {
+	 *     nameAssigner            [0]     DirectoryString OPTIONAL,
+	 *     partyName               [1]     DirectoryString }
+	 */
+
+	for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
+		int res;
+
+		if (asn1_get_next(p, end - p, &hdr) < 0) {
+			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+				   "SubjectAltName item");
+			return -1;
+		}
+
+		if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
+			continue;
+
+		switch (hdr.tag) {
+		case 1:
+			res = x509_parse_alt_name_rfc8222(name, hdr.payload,
+							  hdr.length);
+			break;
+		case 2:
+			res = x509_parse_alt_name_dns(name, hdr.payload,
+						      hdr.length);
+			break;
+		case 6:
+			res = x509_parse_alt_name_uri(name, hdr.payload,
+						      hdr.length);
+			break;
+		case 7:
+			res = x509_parse_alt_name_ip(name, hdr.payload,
+						     hdr.length);
+			break;
+		case 8:
+			res = x509_parse_alt_name_rid(name, hdr.payload,
+						      hdr.length);
+			break;
+		case 0: /* TODO: otherName */
+		case 3: /* TODO: x500Address */
+		case 4: /* TODO: directoryName */
+		case 5: /* TODO: ediPartyName */
+		default:
+			res = 0;
+			break;
+		}
+		if (res < 0)
+			return res;
+	}
+
+	return 0;
+}
+
+
+static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
+					   const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+
+	/* SubjectAltName ::= GeneralNames */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
+			   "SubjectAltName; found %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
+	cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
+
+	if (hdr.length == 0)
+		return 0;
+
+	return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
+				       hdr.length);
+}
+
+
+static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
+					  const u8 *pos, size_t len)
+{
+	struct asn1_hdr hdr;
+
+	/* IssuerAltName ::= GeneralNames */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
+			   "IssuerAltName; found %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
+	cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
+
+	if (hdr.length == 0)
+		return 0;
+
+	return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
+				       hdr.length);
+}
+
+
+static int x509_parse_extension_data(struct x509_certificate *cert,
+				     struct asn1_oid *oid,
+				     const u8 *pos, size_t len)
+{
+	if (!x509_id_ce_oid(oid))
+		return 1;
+
+	/* TODO: add other extensions required by RFC 3280, Ch 4.2:
+	 * certificate policies (section 4.2.1.5)
+	 * name constraints (section 4.2.1.11)
+	 * policy constraints (section 4.2.1.12)
+	 * extended key usage (section 4.2.1.13)
+	 * inhibit any-policy (section 4.2.1.15)
+	 */
+	switch (oid->oid[3]) {
+	case 15: /* id-ce-keyUsage */
+		return x509_parse_ext_key_usage(cert, pos, len);
+	case 17: /* id-ce-subjectAltName */
+		return x509_parse_ext_subject_alt_name(cert, pos, len);
+	case 18: /* id-ce-issuerAltName */
+		return x509_parse_ext_issuer_alt_name(cert, pos, len);
+	case 19: /* id-ce-basicConstraints */
+		return x509_parse_ext_basic_constraints(cert, pos, len);
+	default:
+		return 1;
+	}
+}
+
+
+static int x509_parse_extension(struct x509_certificate *cert,
+				const u8 *pos, size_t len, const u8 **next)
+{
+	const u8 *end;
+	struct asn1_hdr hdr;
+	struct asn1_oid oid;
+	int critical_ext = 0, res;
+	char buf[80];
+
+	/*
+	 * Extension  ::=  SEQUENCE  {
+	 *     extnID      OBJECT IDENTIFIER,
+	 *     critical    BOOLEAN DEFAULT FALSE,
+	 *     extnValue   OCTET STRING
+	 * }
+	 */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
+			   "Extensions: class %d tag 0x%x; expected SEQUENCE",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+	*next = end = pos + hdr.length;
+
+	if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
+			   "Extension (expected OID)");
+		return -1;
+	}
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    (hdr.tag != ASN1_TAG_BOOLEAN &&
+	     hdr.tag != ASN1_TAG_OCTETSTRING)) {
+		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
+			   "Extensions: class %d tag 0x%x; expected BOOLEAN "
+			   "or OCTET STRING", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	if (hdr.tag == ASN1_TAG_BOOLEAN) {
+		if (hdr.length != 1) {
+			wpa_printf(MSG_DEBUG, "X509: Unexpected "
+				   "Boolean length (%u)", hdr.length);
+			return -1;
+		}
+		critical_ext = hdr.payload[0];
+		pos = hdr.payload;
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    (hdr.class != ASN1_CLASS_UNIVERSAL &&
+		     hdr.class != ASN1_CLASS_PRIVATE) ||
+		    hdr.tag != ASN1_TAG_OCTETSTRING) {
+			wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
+				   "in Extensions: class %d tag 0x%x; "
+				   "expected OCTET STRING",
+				   hdr.class, hdr.tag);
+			return -1;
+		}
+	}
+
+	asn1_oid_to_str(&oid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
+		   buf, critical_ext);
+	wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
+
+	res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
+	if (res < 0)
+		return res;
+	if (res == 1 && critical_ext) {
+		wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
+			   buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int x509_parse_extensions(struct x509_certificate *cert,
+				 const u8 *pos, size_t len)
+{
+	const u8 *end;
+	struct asn1_hdr hdr;
+
+	/* Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension */
+
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
+			   "for Extensions: class %d tag 0x%x; "
+			   "expected SEQUENCE", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	while (pos < end) {
+		if (x509_parse_extension(cert, pos, end - pos, &pos)
+		    < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
+				      struct x509_certificate *cert,
+				      const u8 **next)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	size_t left;
+	char sbuf[128];
+	unsigned long value;
+
+	/* tbsCertificate TBSCertificate ::= SEQUENCE */
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
+			   "with a valid SEQUENCE - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+	end = *next = pos + hdr.length;
+
+	/*
+	 * version [0]  EXPLICIT Version DEFAULT v1
+	 * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+	 */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0)
+		return -1;
+	pos = hdr.payload;
+
+	if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
+		if (asn1_get_next(pos, end - pos, &hdr) < 0)
+			return -1;
+
+		if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+		    hdr.tag != ASN1_TAG_INTEGER) {
+			wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
+				   "version field - found class %d tag 0x%x",
+				   hdr.class, hdr.tag);
+			return -1;
+		}
+		if (hdr.length != 1) {
+			wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
+				   "length %u (expected 1)", hdr.length);
+			return -1;
+		}
+		pos = hdr.payload;
+		left = hdr.length;
+		value = 0;
+		while (left) {
+			value <<= 8;
+			value |= *pos++;
+			left--;
+		}
+
+		cert->version = value;
+		if (cert->version != X509_CERT_V1 &&
+		    cert->version != X509_CERT_V2 &&
+		    cert->version != X509_CERT_V3) {
+			wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
+				   cert->version + 1);
+			return -1;
+		}
+
+		if (asn1_get_next(pos, end - pos, &hdr) < 0)
+			return -1;
+	} else
+		cert->version = X509_CERT_V1;
+	wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
+
+	/* serialNumber CertificateSerialNumber ::= INTEGER */
+	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
+			   "serialNumber; class=%d tag=0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	pos = hdr.payload;
+	left = hdr.length;
+	while (left) {
+		cert->serial_number <<= 8;
+		cert->serial_number |= *pos++;
+		left--;
+	}
+	wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
+
+	/* signature AlgorithmIdentifier */
+	if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
+					    &pos))
+		return -1;
+
+	/* issuer Name */
+	if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
+		return -1;
+	x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
+	wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
+
+	/* validity Validity */
+	if (x509_parse_validity(pos, end - pos, cert, &pos))
+		return -1;
+
+	/* subject Name */
+	if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
+		return -1;
+	x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+	wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
+
+	/* subjectPublicKeyInfo SubjectPublicKeyInfo */
+	if (x509_parse_public_key(pos, end - pos, cert, &pos))
+		return -1;
+
+	if (pos == end)
+		return 0;
+
+	if (cert->version == X509_CERT_V1)
+		return 0;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+		wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+			   " tag to parse optional tbsCertificate "
+			   "field(s); parsed class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+
+	if (hdr.tag == 1) {
+		/* issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL */
+		wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
+		/* TODO: parse UniqueIdentifier ::= BIT STRING */
+
+		if (hdr.payload + hdr.length == end)
+			return 0;
+
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+			wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+				   " tag to parse optional tbsCertificate "
+				   "field(s); parsed class %d tag 0x%x",
+				   hdr.class, hdr.tag);
+			return -1;
+		}
+	}
+
+	if (hdr.tag == 2) {
+		/* subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL */
+		wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
+		/* TODO: parse UniqueIdentifier ::= BIT STRING */
+
+		if (hdr.payload + hdr.length == end)
+			return 0;
+
+		if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+		    hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+			wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+				   " tag to parse optional tbsCertificate "
+				   "field(s); parsed class %d tag 0x%x",
+				   hdr.class, hdr.tag);
+			return -1;
+		}
+	}
+
+	if (hdr.tag != 3) {
+		wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
+			   "Context-Specific tag %d in optional "
+			   "tbsCertificate fields", hdr.tag);
+		return 0;
+	}
+
+	/* extensions      [3]  EXPLICIT Extensions OPTIONAL */
+
+	if (cert->version != X509_CERT_V3) {
+		wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
+			   "Extensions data which are only allowed for "
+			   "version 3", cert->version + 1);
+		return -1;
+	}
+
+	if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
+		return -1;
+
+	pos = hdr.payload + hdr.length;
+	if (pos < end) {
+		wpa_hexdump(MSG_DEBUG,
+			    "X509: Ignored extra tbsCertificate data",
+			    pos, end - pos);
+	}
+
+	return 0;
+}
+
+
+static int x509_rsadsi_oid(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 x509_pkcs_oid(struct asn1_oid *oid)
+{
+	return oid->len >= 5 &&
+		x509_rsadsi_oid(oid) &&
+		oid->oid[4] == 1 /* pkcs */;
+}
+
+
+static int x509_digest_oid(struct asn1_oid *oid)
+{
+	return oid->len >= 5 &&
+		x509_rsadsi_oid(oid) &&
+		oid->oid[4] == 2 /* digestAlgorithm */;
+}
+
+
+static int x509_sha1_oid(struct asn1_oid *oid)
+{
+	return oid->len == 6 &&
+		oid->oid[0] == 1 /* iso */ &&
+		oid->oid[1] == 3 /* identified-organization */ &&
+		oid->oid[2] == 14 /* oiw */ &&
+		oid->oid[3] == 3 /* secsig */ &&
+		oid->oid[4] == 2 /* algorithms */ &&
+		oid->oid[5] == 26 /* id-sha1 */;
+}
+
+
+static int x509_sha256_oid(struct asn1_oid *oid)
+{
+	return oid->len == 9 &&
+		oid->oid[0] == 2 /* joint-iso-itu-t */ &&
+		oid->oid[1] == 16 /* country */ &&
+		oid->oid[2] == 840 /* us */ &&
+		oid->oid[3] == 1 /* organization */ &&
+		oid->oid[4] == 101 /* gov */ &&
+		oid->oid[5] == 3 /* csor */ &&
+		oid->oid[6] == 4 /* nistAlgorithm */ &&
+		oid->oid[7] == 2 /* hashAlgs */ &&
+		oid->oid[8] == 1 /* sha256 */;
+}
+
+
+/**
+ * x509_certificate_parse - Parse a X.509 certificate in DER format
+ * @buf: Pointer to the X.509 certificate in DER format
+ * @len: Buffer length
+ * Returns: Pointer to the parsed certificate or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned certificate by calling
+ * x509_certificate_free().
+ */
+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end, *hash_start;
+	struct x509_certificate *cert;
+
+	cert = os_zalloc(sizeof(*cert) + len);
+	if (cert == NULL)
+		return NULL;
+	os_memcpy(cert + 1, buf, len);
+	cert->cert_start = (u8 *) (cert + 1);
+	cert->cert_len = len;
+
+	pos = buf;
+	end = buf + len;
+
+	/* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
+
+	/* Certificate ::= SEQUENCE */
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
+			   "a valid SEQUENCE - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	pos = hdr.payload;
+
+	if (pos + hdr.length > end) {
+		x509_certificate_free(cert);
+		return NULL;
+	}
+
+	if (pos + hdr.length < end) {
+		wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
+			    "encoded certificate",
+			    pos + hdr.length, end - pos + hdr.length);
+		end = pos + hdr.length;
+	}
+
+	hash_start = pos;
+	cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
+	if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	cert->tbs_cert_len = pos - hash_start;
+
+	/* signatureAlgorithm AlgorithmIdentifier */
+	if (x509_parse_algorithm_identifier(pos, end - pos,
+					    &cert->signature_alg, &pos)) {
+		x509_certificate_free(cert);
+		return NULL;
+	}
+
+	/* signatureValue BIT STRING */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_BITSTRING) {
+		wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
+			   "(signatureValue) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	if (hdr.length < 1) {
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	pos = hdr.payload;
+	if (*pos) {
+		wpa_printf(MSG_DEBUG, "X509: 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.
+		 */
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	os_free(cert->sign_value);
+	cert->sign_value = os_malloc(hdr.length - 1);
+	if (cert->sign_value == NULL) {
+		wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
+			   "signatureValue");
+		x509_certificate_free(cert);
+		return NULL;
+	}
+	os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
+	cert->sign_value_len = hdr.length - 1;
+	wpa_hexdump(MSG_MSGDUMP, "X509: signature",
+		    cert->sign_value, cert->sign_value_len);
+
+	return cert;
+}
+
+
+/**
+ * x509_certificate_check_signature - Verify certificate signature
+ * @issuer: Issuer certificate
+ * @cert: Certificate to be verified
+ * Returns: 0 if cert has a valid signature that was signed by the issuer,
+ * -1 if not
+ */
+int x509_certificate_check_signature(struct x509_certificate *issuer,
+				     struct x509_certificate *cert)
+{
+	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];
+	size_t hash_len;
+
+	if (!x509_pkcs_oid(&cert->signature.oid) ||
+	    cert->signature.oid.len != 7 ||
+	    cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
+		wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
+			   "algorithm");
+		return -1;
+	}
+
+	pk = crypto_public_key_import(issuer->public_key,
+				      issuer->public_key_len);
+	if (pk == NULL)
+		return -1;
+
+	data_len = cert->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,
+					    &data_len) < 0) {
+		wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
+		crypto_public_key_free(pk);
+		os_free(data);
+		return -1;
+	}
+	crypto_public_key_free(pk);
+
+	wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
+
+	/*
+	 * PKCS #1 v1.5, 10.1.2:
+	 *
+	 * DigestInfo ::= SEQUENCE {
+	 *     digestAlgorithm DigestAlgorithmIdentifier,
+	 *     digest Digest
+	 * }
+	 *
+	 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+	 *
+	 * Digest ::= OCTET STRING
+	 *
+	 */
+	if (asn1_get_next(data, data_len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(DigestInfo) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		os_free(data);
+		return -1;
+	}
+
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/*
+	 * X.509:
+	 * AlgorithmIdentifier ::= SEQUENCE {
+	 *     algorithm            OBJECT IDENTIFIER,
+	 *     parameters           ANY DEFINED BY algorithm OPTIONAL
+	 * }
+	 */
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+			   "(AlgorithmIdentifier) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		os_free(data);
+		return -1;
+	}
+	da_end = hdr.payload + hdr.length;
+
+	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
+		wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
+		os_free(data);
+		return -1;
+	}
+
+	if (x509_sha1_oid(&oid)) {
+		if (cert->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]);
+			os_free(data);
+			return -1;
+		}
+		goto skip_digest_oid;
+	}
+
+	if (x509_sha256_oid(&oid)) {
+		if (cert->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]);
+			os_free(data);
+			return -1;
+		}
+		goto skip_digest_oid;
+	}
+
+	if (!x509_digest_oid(&oid)) {
+		wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
+		os_free(data);
+		return -1;
+	}
+	switch (oid.oid[5]) {
+	case 5: /* md5 */
+		if (cert->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]);
+			os_free(data);
+			return -1;
+		}
+		break;
+	case 2: /* md2 */
+	case 4: /* md4 */
+	default:
+		wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
+			   "(%lu)", oid.oid[5]);
+		os_free(data);
+		return -1;
+	}
+
+skip_digest_oid:
+	/* Digest ::= OCTET STRING */
+	pos = da_end;
+	end = data + data_len;
+
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
+			   "(Digest) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		os_free(data);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
+		    hdr.payload, hdr.length);
+
+	switch (cert->signature.oid.oid[6]) {
+	case 4: /* md5WithRSAEncryption */
+		md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_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);
+		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);
+		hash_len = 32;
+		wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
+			    hash, hash_len);
+		break;
+	case 2: /* md2WithRSAEncryption */
+	case 12: /* sha384WithRSAEncryption */
+	case 13: /* sha512WithRSAEncryption */
+	default:
+		wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
+			   "algorithm (%lu)", cert->signature.oid.oid[6]);
+		os_free(data);
+		return -1;
+	}
+
+	if (hdr.length != hash_len ||
+	    os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+		wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
+			   "with calculated tbsCertificate hash");
+		os_free(data);
+		return -1;
+	}
+
+	os_free(data);
+
+	wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
+		   "calculated tbsCertificate hash");
+
+	return 0;
+}
+
+
+static int x509_valid_issuer(const struct x509_certificate *cert)
+{
+	if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
+	    !cert->ca) {
+		wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
+			   "issuer");
+		return -1;
+	}
+
+	if (cert->version == X509_CERT_V3 &&
+	    !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
+		wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
+			   "include BasicConstraints extension");
+		return -1;
+	}
+
+	if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
+	    !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
+		wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
+			   "keyCertSign bit in Key Usage");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * x509_certificate_chain_validate - Validate X.509 certificate chain
+ * @trusted: List of trusted certificates
+ * @chain: Certificate chain to be validated (first chain must be issued by
+ * signed by the second certificate in the chain and so on)
+ * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
+ * Returns: 0 if chain is valid, -1 if not
+ */
+int x509_certificate_chain_validate(struct x509_certificate *trusted,
+				    struct x509_certificate *chain,
+				    int *reason, int disable_time_checks)
+{
+	long unsigned idx;
+	int chain_trusted = 0;
+	struct x509_certificate *cert, *trust;
+	char buf[128];
+	struct os_time now;
+
+	*reason = X509_VALIDATE_OK;
+
+	wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
+	os_get_time(&now);
+
+	for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+		x509_name_string(&cert->subject, buf, sizeof(buf)); 
+		wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
+
+		if (chain_trusted)
+			continue;
+
+		if (!disable_time_checks &&
+		    ((unsigned long) now.sec <
+		     (unsigned long) cert->not_before ||
+		     (unsigned long) now.sec >
+		     (unsigned long) cert->not_after)) {
+			wpa_printf(MSG_INFO, "X509: Certificate not valid "
+				   "(now=%lu not_before=%lu not_after=%lu)",
+				   now.sec, cert->not_before, cert->not_after);
+			*reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
+			return -1;
+		}
+
+		if (cert->next) {
+			if (x509_name_compare(&cert->issuer,
+					      &cert->next->subject) != 0) {
+				wpa_printf(MSG_DEBUG, "X509: Certificate "
+					   "chain issuer name mismatch");
+				x509_name_string(&cert->issuer, buf,
+						 sizeof(buf)); 
+				wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
+					   buf);
+				x509_name_string(&cert->next->subject, buf,
+						 sizeof(buf)); 
+				wpa_printf(MSG_DEBUG, "X509: next cert "
+					   "subject: %s", buf);
+				*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
+				return -1;
+			}
+
+			if (x509_valid_issuer(cert->next) < 0) {
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
+
+			if ((cert->next->extensions_present &
+			     X509_EXT_PATH_LEN_CONSTRAINT) &&
+			    idx > cert->next->path_len_constraint) {
+				wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
+					   " not met (idx=%lu issuer "
+					   "pathLenConstraint=%lu)", idx,
+					   cert->next->path_len_constraint);
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
+
+			if (x509_certificate_check_signature(cert->next, cert)
+			    < 0) {
+				wpa_printf(MSG_DEBUG, "X509: Invalid "
+					   "certificate signature within "
+					   "chain");
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
+		}
+
+		for (trust = trusted; trust; trust = trust->next) {
+			if (x509_name_compare(&cert->issuer, &trust->subject)
+			    == 0)
+				break;
+		}
+
+		if (trust) {
+			wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
+				   "list of trusted certificates");
+			if (x509_valid_issuer(trust) < 0) {
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
+
+			if (x509_certificate_check_signature(trust, cert) < 0)
+			{
+				wpa_printf(MSG_DEBUG, "X509: Invalid "
+					   "certificate signature");
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
+				   "found to complete the chain");
+			chain_trusted = 1;
+		}
+	}
+
+	if (!chain_trusted) {
+		wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
+			   "from the list of trusted certificates");
+		if (trusted) {
+			*reason = X509_VALIDATE_UNKNOWN_CA;
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
+			   "disabled - ignore unknown CA issue");
+	}
+
+	wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
+
+	return 0;
+}
+
+
+/**
+ * x509_certificate_get_subject - Get a certificate based on Subject name
+ * @chain: Certificate chain to search through
+ * @name: Subject name to search for
+ * Returns: Pointer to the certificate with the given Subject name or
+ * %NULL on failure
+ */
+struct x509_certificate *
+x509_certificate_get_subject(struct x509_certificate *chain,
+			     struct x509_name *name)
+{
+	struct x509_certificate *cert;
+
+	for (cert = chain; cert; cert = cert->next) {
+		if (x509_name_compare(&cert->subject, name) == 0)
+			return cert;
+	}
+	return NULL;
+}
+
+
+/**
+ * x509_certificate_self_signed - Is the certificate self-signed?
+ * @cert: Certificate
+ * Returns: 1 if certificate is self-signed, 0 if not
+ */
+int x509_certificate_self_signed(struct x509_certificate *cert)
+{
+	return x509_name_compare(&cert->issuer, &cert->subject) == 0;
+}

Deleted: vendor/wpa/2.0/src/tls/x509v3.h
===================================================================
--- vendor/wpa/dist/src/tls/x509v3.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/tls/x509v3.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,129 +0,0 @@
-/*
- * X.509v3 certificate parsing and processing
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef X509V3_H
-#define X509V3_H
-
-#include "asn1.h"
-
-struct x509_algorithm_identifier {
-	struct asn1_oid oid;
-};
-
-struct x509_name_attr {
-	enum x509_name_attr_type {
-		X509_NAME_ATTR_NOT_USED,
-		X509_NAME_ATTR_DC,
-		X509_NAME_ATTR_CN,
-		X509_NAME_ATTR_C,
-		X509_NAME_ATTR_L,
-		X509_NAME_ATTR_ST,
-		X509_NAME_ATTR_O,
-		X509_NAME_ATTR_OU
-	} type;
-	char *value;
-};
-
-#define X509_MAX_NAME_ATTRIBUTES 20
-
-struct x509_name {
-	struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];
-	size_t num_attr;
-	char *email; /* emailAddress */
-
-	/* from alternative name extension */
-	char *alt_email; /* rfc822Name */
-	char *dns; /* dNSName */
-	char *uri; /* uniformResourceIdentifier */
-	u8 *ip; /* iPAddress */
-	size_t ip_len; /* IPv4: 4, IPv6: 16 */
-	struct asn1_oid rid; /* registeredID */
-};
-
-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;
-	struct x509_algorithm_identifier signature;
-	struct x509_name issuer;
-	struct x509_name subject;
-	os_time_t not_before;
-	os_time_t not_after;
-	struct x509_algorithm_identifier public_key_alg;
-	u8 *public_key;
-	size_t public_key_len;
-	struct x509_algorithm_identifier signature_alg;
-	u8 *sign_value;
-	size_t sign_value_len;
-
-	/* Extensions */
-	unsigned int extensions_present;
-#define X509_EXT_BASIC_CONSTRAINTS		(1 << 0)
-#define X509_EXT_PATH_LEN_CONSTRAINT		(1 << 1)
-#define X509_EXT_KEY_USAGE			(1 << 2)
-#define X509_EXT_SUBJECT_ALT_NAME		(1 << 3)
-#define X509_EXT_ISSUER_ALT_NAME		(1 << 4)
-
-	/* BasicConstraints */
-	int ca; /* cA */
-	unsigned long path_len_constraint; /* pathLenConstraint */
-
-	/* KeyUsage */
-	unsigned long key_usage;
-#define X509_KEY_USAGE_DIGITAL_SIGNATURE	(1 << 0)
-#define X509_KEY_USAGE_NON_REPUDIATION		(1 << 1)
-#define X509_KEY_USAGE_KEY_ENCIPHERMENT		(1 << 2)
-#define X509_KEY_USAGE_DATA_ENCIPHERMENT	(1 << 3)
-#define X509_KEY_USAGE_KEY_AGREEMENT		(1 << 4)
-#define X509_KEY_USAGE_KEY_CERT_SIGN		(1 << 5)
-#define X509_KEY_USAGE_CRL_SIGN			(1 << 6)
-#define X509_KEY_USAGE_ENCIPHER_ONLY		(1 << 7)
-#define X509_KEY_USAGE_DECIPHER_ONLY		(1 << 8)
-
-	/*
-	 * The DER format certificate follows struct x509_certificate. These
-	 * pointers point to that buffer.
-	 */
-	const u8 *cert_start;
-	size_t cert_len;
-	const u8 *tbs_cert_start;
-	size_t tbs_cert_len;
-};
-
-enum {
-	X509_VALIDATE_OK,
-	X509_VALIDATE_BAD_CERTIFICATE,
-	X509_VALIDATE_UNSUPPORTED_CERTIFICATE,
-	X509_VALIDATE_CERTIFICATE_REVOKED,
-	X509_VALIDATE_CERTIFICATE_EXPIRED,
-	X509_VALIDATE_CERTIFICATE_UNKNOWN,
-	X509_VALIDATE_UNKNOWN_CA
-};
-
-void x509_certificate_free(struct x509_certificate *cert);
-struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
-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_certificate_check_signature(struct x509_certificate *issuer,
-				     struct x509_certificate *cert);
-int x509_certificate_chain_validate(struct x509_certificate *trusted,
-				    struct x509_certificate *chain,
-				    int *reason);
-struct x509_certificate *
-x509_certificate_get_subject(struct x509_certificate *chain,
-			     struct x509_name *name);
-int x509_certificate_self_signed(struct x509_certificate *cert);
-
-#endif /* X509V3_H */

Copied: vendor/wpa/2.0/src/tls/x509v3.h (from rev 9639, vendor/wpa/dist/src/tls/x509v3.h)
===================================================================
--- vendor/wpa/2.0/src/tls/x509v3.h	                        (rev 0)
+++ vendor/wpa/2.0/src/tls/x509v3.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,123 @@
+/*
+ * X.509v3 certificate parsing and processing
+ * Copyright (c) 2006-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef X509V3_H
+#define X509V3_H
+
+#include "asn1.h"
+
+struct x509_algorithm_identifier {
+	struct asn1_oid oid;
+};
+
+struct x509_name_attr {
+	enum x509_name_attr_type {
+		X509_NAME_ATTR_NOT_USED,
+		X509_NAME_ATTR_DC,
+		X509_NAME_ATTR_CN,
+		X509_NAME_ATTR_C,
+		X509_NAME_ATTR_L,
+		X509_NAME_ATTR_ST,
+		X509_NAME_ATTR_O,
+		X509_NAME_ATTR_OU
+	} type;
+	char *value;
+};
+
+#define X509_MAX_NAME_ATTRIBUTES 20
+
+struct x509_name {
+	struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];
+	size_t num_attr;
+	char *email; /* emailAddress */
+
+	/* from alternative name extension */
+	char *alt_email; /* rfc822Name */
+	char *dns; /* dNSName */
+	char *uri; /* uniformResourceIdentifier */
+	u8 *ip; /* iPAddress */
+	size_t ip_len; /* IPv4: 4, IPv6: 16 */
+	struct asn1_oid rid; /* registeredID */
+};
+
+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;
+	struct x509_algorithm_identifier signature;
+	struct x509_name issuer;
+	struct x509_name subject;
+	os_time_t not_before;
+	os_time_t not_after;
+	struct x509_algorithm_identifier public_key_alg;
+	u8 *public_key;
+	size_t public_key_len;
+	struct x509_algorithm_identifier signature_alg;
+	u8 *sign_value;
+	size_t sign_value_len;
+
+	/* Extensions */
+	unsigned int extensions_present;
+#define X509_EXT_BASIC_CONSTRAINTS		(1 << 0)
+#define X509_EXT_PATH_LEN_CONSTRAINT		(1 << 1)
+#define X509_EXT_KEY_USAGE			(1 << 2)
+#define X509_EXT_SUBJECT_ALT_NAME		(1 << 3)
+#define X509_EXT_ISSUER_ALT_NAME		(1 << 4)
+
+	/* BasicConstraints */
+	int ca; /* cA */
+	unsigned long path_len_constraint; /* pathLenConstraint */
+
+	/* KeyUsage */
+	unsigned long key_usage;
+#define X509_KEY_USAGE_DIGITAL_SIGNATURE	(1 << 0)
+#define X509_KEY_USAGE_NON_REPUDIATION		(1 << 1)
+#define X509_KEY_USAGE_KEY_ENCIPHERMENT		(1 << 2)
+#define X509_KEY_USAGE_DATA_ENCIPHERMENT	(1 << 3)
+#define X509_KEY_USAGE_KEY_AGREEMENT		(1 << 4)
+#define X509_KEY_USAGE_KEY_CERT_SIGN		(1 << 5)
+#define X509_KEY_USAGE_CRL_SIGN			(1 << 6)
+#define X509_KEY_USAGE_ENCIPHER_ONLY		(1 << 7)
+#define X509_KEY_USAGE_DECIPHER_ONLY		(1 << 8)
+
+	/*
+	 * The DER format certificate follows struct x509_certificate. These
+	 * pointers point to that buffer.
+	 */
+	const u8 *cert_start;
+	size_t cert_len;
+	const u8 *tbs_cert_start;
+	size_t tbs_cert_len;
+};
+
+enum {
+	X509_VALIDATE_OK,
+	X509_VALIDATE_BAD_CERTIFICATE,
+	X509_VALIDATE_UNSUPPORTED_CERTIFICATE,
+	X509_VALIDATE_CERTIFICATE_REVOKED,
+	X509_VALIDATE_CERTIFICATE_EXPIRED,
+	X509_VALIDATE_CERTIFICATE_UNKNOWN,
+	X509_VALIDATE_UNKNOWN_CA
+};
+
+void x509_certificate_free(struct x509_certificate *cert);
+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
+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_certificate_check_signature(struct x509_certificate *issuer,
+				     struct x509_certificate *cert);
+int x509_certificate_chain_validate(struct x509_certificate *trusted,
+				    struct x509_certificate *chain,
+				    int *reason, int disable_time_checks);
+struct x509_certificate *
+x509_certificate_get_subject(struct x509_certificate *chain,
+			     struct x509_name *name);
+int x509_certificate_self_signed(struct x509_certificate *cert);
+
+#endif /* X509V3_H */

Deleted: vendor/wpa/2.0/src/utils/Makefile
===================================================================
--- vendor/wpa/dist/src/utils/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,36 +0,0 @@
-all: libutils.a
-
-clean:
-	rm -f *~ *.o *.d libutils.a
-
-install:
-	@echo Nothing to be made.
-
-
-include ../lib.rules
-
-#CFLAGS += -DWPA_TRACE
-CFLAGS += -DCONFIG_IPV6
-
-LIB_OBJS= \
-	base64.o \
-	common.o \
-	ip_addr.o \
-	radiotap.o \
-	trace.o \
-	uuid.o \
-	wpa_debug.o \
-	wpabuf.o
-
-# Pick correct OS wrapper implementation
-LIB_OBJS += os_unix.o
-
-# Pick correct event loop implementation
-LIB_OBJS += eloop.o
-
-#LIB_OBJS += pcsc_funcs.o
-
-libutils.a: $(LIB_OBJS)
-	$(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/src/utils/Makefile (from rev 9639, vendor/wpa/dist/src/utils/Makefile)
===================================================================
--- vendor/wpa/2.0/src/utils/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,39 @@
+all: libutils.a
+
+clean:
+	rm -f *~ *.o *.d libutils.a
+
+install:
+	@echo Nothing to be made.
+
+
+include ../lib.rules
+
+#CFLAGS += -DWPA_TRACE
+CFLAGS += -DCONFIG_IPV6
+
+LIB_OBJS= \
+	base64.o \
+	common.o \
+	ip_addr.o \
+	radiotap.o \
+	trace.o \
+	uuid.o \
+	wpa_debug.o \
+	wpabuf.o
+
+# Pick correct OS wrapper implementation
+LIB_OBJS += os_unix.o
+
+# Pick correct event loop implementation
+LIB_OBJS += eloop.o
+
+# Pick correct edit implementation
+LIB_OBJS += edit.o
+
+#LIB_OBJS += pcsc_funcs.o
+
+libutils.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/src/utils/base64.c
===================================================================
--- vendor/wpa/dist/src/utils/base64.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/base64.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,154 +0,0 @@
-/*
- * Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "os.h"
-#include "base64.h"
-
-static const unsigned char base64_table[65] =
-	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/**
- * base64_encode - Base64 encode
- * @src: Data to be encoded
- * @len: Length of the data to be encoded
- * @out_len: Pointer to output length variable, or %NULL if not used
- * Returns: Allocated buffer of out_len bytes of encoded data,
- * or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer. Returned buffer is
- * nul terminated to make it easier to use as a C string. The nul terminator is
- * not included in out_len.
- */
-unsigned char * base64_encode(const unsigned char *src, size_t len,
-			      size_t *out_len)
-{
-	unsigned char *out, *pos;
-	const unsigned char *end, *in;
-	size_t olen;
-	int line_len;
-
-	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
-	olen += olen / 72; /* line feeds */
-	olen++; /* nul termination */
-	if (olen < len)
-		return NULL; /* integer overflow */
-	out = os_malloc(olen);
-	if (out == NULL)
-		return NULL;
-
-	end = src + len;
-	in = src;
-	pos = out;
-	line_len = 0;
-	while (end - in >= 3) {
-		*pos++ = base64_table[in[0] >> 2];
-		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
-		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
-		*pos++ = base64_table[in[2] & 0x3f];
-		in += 3;
-		line_len += 4;
-		if (line_len >= 72) {
-			*pos++ = '\n';
-			line_len = 0;
-		}
-	}
-
-	if (end - in) {
-		*pos++ = base64_table[in[0] >> 2];
-		if (end - in == 1) {
-			*pos++ = base64_table[(in[0] & 0x03) << 4];
-			*pos++ = '=';
-		} else {
-			*pos++ = base64_table[((in[0] & 0x03) << 4) |
-					      (in[1] >> 4)];
-			*pos++ = base64_table[(in[1] & 0x0f) << 2];
-		}
-		*pos++ = '=';
-		line_len += 4;
-	}
-
-	if (line_len)
-		*pos++ = '\n';
-
-	*pos = '\0';
-	if (out_len)
-		*out_len = pos - out;
-	return out;
-}
-
-
-/**
- * base64_decode - Base64 decode
- * @src: Data to be decoded
- * @len: Length of the data to be decoded
- * @out_len: Pointer to output length variable
- * Returns: Allocated buffer of out_len bytes of decoded data,
- * or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer.
- */
-unsigned char * base64_decode(const unsigned char *src, size_t len,
-			      size_t *out_len)
-{
-	unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
-	size_t i, count, olen;
-
-	os_memset(dtable, 0x80, 256);
-	for (i = 0; i < sizeof(base64_table) - 1; i++)
-		dtable[base64_table[i]] = (unsigned char) i;
-	dtable['='] = 0;
-
-	count = 0;
-	for (i = 0; i < len; i++) {
-		if (dtable[src[i]] != 0x80)
-			count++;
-	}
-
-	if (count == 0 || count % 4)
-		return NULL;
-
-	olen = count / 4 * 3;
-	pos = out = os_malloc(olen);
-	if (out == NULL)
-		return NULL;
-
-	count = 0;
-	for (i = 0; i < len; i++) {
-		tmp = dtable[src[i]];
-		if (tmp == 0x80)
-			continue;
-
-		in[count] = src[i];
-		block[count] = tmp;
-		count++;
-		if (count == 4) {
-			*pos++ = (block[0] << 2) | (block[1] >> 4);
-			*pos++ = (block[1] << 4) | (block[2] >> 2);
-			*pos++ = (block[2] << 6) | block[3];
-			count = 0;
-		}
-	}
-
-	if (pos > out) {
-		if (in[2] == '=')
-			pos -= 2;
-		else if (in[3] == '=')
-			pos--;
-	}
-
-	*out_len = pos - out;
-	return out;
-}

Copied: vendor/wpa/2.0/src/utils/base64.c (from rev 9639, vendor/wpa/dist/src/utils/base64.c)
===================================================================
--- vendor/wpa/2.0/src/utils/base64.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/base64.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,155 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+#include "base64.h"
+
+static const unsigned char base64_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char *out, *pos;
+	const unsigned char *end, *in;
+	size_t olen;
+	int line_len;
+
+	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+	olen += olen / 72; /* line feeds */
+	olen++; /* nul termination */
+	if (olen < len)
+		return NULL; /* integer overflow */
+	out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	end = src + len;
+	in = src;
+	pos = out;
+	line_len = 0;
+	while (end - in >= 3) {
+		*pos++ = base64_table[in[0] >> 2];
+		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+		*pos++ = base64_table[in[2] & 0x3f];
+		in += 3;
+		line_len += 4;
+		if (line_len >= 72) {
+			*pos++ = '\n';
+			line_len = 0;
+		}
+	}
+
+	if (end - in) {
+		*pos++ = base64_table[in[0] >> 2];
+		if (end - in == 1) {
+			*pos++ = base64_table[(in[0] & 0x03) << 4];
+			*pos++ = '=';
+		} else {
+			*pos++ = base64_table[((in[0] & 0x03) << 4) |
+					      (in[1] >> 4)];
+			*pos++ = base64_table[(in[1] & 0x0f) << 2];
+		}
+		*pos++ = '=';
+		line_len += 4;
+	}
+
+	if (line_len)
+		*pos++ = '\n';
+
+	*pos = '\0';
+	if (out_len)
+		*out_len = pos - out;
+	return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char dtable[256], *out, *pos, block[4], tmp;
+	size_t i, count, olen;
+	int pad = 0;
+
+	os_memset(dtable, 0x80, 256);
+	for (i = 0; i < sizeof(base64_table) - 1; i++)
+		dtable[base64_table[i]] = (unsigned char) i;
+	dtable['='] = 0;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		if (dtable[src[i]] != 0x80)
+			count++;
+	}
+
+	if (count == 0 || count % 4)
+		return NULL;
+
+	olen = count / 4 * 3;
+	pos = out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		tmp = dtable[src[i]];
+		if (tmp == 0x80)
+			continue;
+
+		if (src[i] == '=')
+			pad++;
+		block[count] = tmp;
+		count++;
+		if (count == 4) {
+			*pos++ = (block[0] << 2) | (block[1] >> 4);
+			*pos++ = (block[1] << 4) | (block[2] >> 2);
+			*pos++ = (block[2] << 6) | block[3];
+			count = 0;
+			if (pad) {
+				if (pad == 1)
+					pos--;
+				else if (pad == 2)
+					pos -= 2;
+				else {
+					/* Invalid padding */
+					os_free(out);
+					return NULL;
+				}
+				break;
+			}
+		}
+	}
+
+	*out_len = pos - out;
+	return out;
+}

Deleted: vendor/wpa/2.0/src/utils/base64.h
===================================================================
--- vendor/wpa/dist/src/utils/base64.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/base64.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,23 +0,0 @@
-/*
- * Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BASE64_H
-#define BASE64_h
-
-unsigned char * base64_encode(const unsigned char *src, size_t len,
-			      size_t *out_len);
-unsigned char * base64_decode(const unsigned char *src, size_t len,
-			      size_t *out_len);
-
-#endif /* BASE64_H */

Copied: vendor/wpa/2.0/src/utils/base64.h (from rev 9639, vendor/wpa/dist/src/utils/base64.h)
===================================================================
--- vendor/wpa/2.0/src/utils/base64.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/base64.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,17 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+
+#endif /* BASE64_H */

Deleted: vendor/wpa/2.0/src/utils/build_config.h
===================================================================
--- vendor/wpa/dist/src/utils/build_config.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/build_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,105 +0,0 @@
-/*
- * wpa_supplicant/hostapd - Build time configuration defines
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This header file can be used to define configuration defines that were
- * originally defined in Makefile. This is mainly meant for IDE use or for
- * systems that do not have suitable 'make' tool. In these cases, it may be
- * easier to have a single place for defining all the needed C pre-processor
- * defines.
- */
-
-#ifndef BUILD_CONFIG_H
-#define BUILD_CONFIG_H
-
-/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
-
-#ifdef CONFIG_WIN32_DEFAULTS
-#define CONFIG_NATIVE_WINDOWS
-#define CONFIG_ANSI_C_EXTRA
-#define CONFIG_WINPCAP
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define PCSC_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_NAMED_PIPE
-#define CONFIG_DRIVER_NDIS
-#define CONFIG_NDIS_EVENTS_INTEGRATED
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define _CRT_SECURE_NO_DEPRECATE
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_WIN32_DEFAULTS */
-
-#ifdef __SYMBIAN32__
-#define OS_NO_C_LIB_DEFINES
-#define CONFIG_ANSI_C_EXTRA
-#define CONFIG_NO_WPA_MSG
-#define CONFIG_NO_HOSTAPD_LOGGER
-#define CONFIG_NO_STDOUT_DEBUG
-#define CONFIG_BACKEND_FILE
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_FAST
-#endif /* __SYMBIAN32__ */
-
-#ifdef CONFIG_XCODE_DEFAULTS
-#define CONFIG_DRIVER_OSX
-#define CONFIG_BACKEND_FILE
-#define IEEE8021X_EAPOL
-#define PKCS12_FUNCS
-#define CONFIG_CTRL_IFACE
-#define CONFIG_CTRL_IFACE_UNIX
-#define CONFIG_DEBUG_FILE
-#define EAP_MD5
-#define EAP_TLS
-#define EAP_MSCHAPv2
-#define EAP_PEAP
-#define EAP_TTLS
-#define EAP_GTC
-#define EAP_OTP
-#define EAP_LEAP
-#define EAP_TNC
-#define CONFIG_WPS
-#define EAP_WSC
-
-#ifdef USE_INTERNAL_CRYPTO
-#define CONFIG_TLS_INTERNAL_CLIENT
-#define CONFIG_INTERNAL_LIBTOMMATH
-#define CONFIG_CRYPTO_INTERNAL
-#endif /* USE_INTERNAL_CRYPTO */
-#endif /* CONFIG_XCODE_DEFAULTS */
-
-#endif /* BUILD_CONFIG_H */

Copied: vendor/wpa/2.0/src/utils/build_config.h (from rev 9639, vendor/wpa/dist/src/utils/build_config.h)
===================================================================
--- vendor/wpa/2.0/src/utils/build_config.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/build_config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,77 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define _CRT_SECURE_NO_DEPRECATE
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#ifdef CONFIG_XCODE_DEFAULTS
+#define CONFIG_DRIVER_OSX
+#define CONFIG_BACKEND_FILE
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_UNIX
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define CONFIG_WPS
+#define EAP_WSC
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_XCODE_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */

Deleted: vendor/wpa/2.0/src/utils/common.c
===================================================================
--- vendor/wpa/dist/src/utils/common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,363 +0,0 @@
-/*
- * wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-
-
-static int hex2num(char c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	if (c >= 'A' && c <= 'F')
-		return c - 'A' + 10;
-	return -1;
-}
-
-
-static int hex2byte(const char *hex)
-{
-	int a, b;
-	a = hex2num(*hex++);
-	if (a < 0)
-		return -1;
-	b = hex2num(*hex++);
-	if (b < 0)
-		return -1;
-	return (a << 4) | b;
-}
-
-
-/**
- * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
- * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
- * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
- * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
- */
-int hwaddr_aton(const char *txt, u8 *addr)
-{
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		int a, b;
-
-		a = hex2num(*txt++);
-		if (a < 0)
-			return -1;
-		b = hex2num(*txt++);
-		if (b < 0)
-			return -1;
-		*addr++ = (a << 4) | b;
-		if (i < 5 && *txt++ != ':')
-			return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
- * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
- * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
- * Returns: Characters used (> 0) on success, -1 on failure
- */
-int hwaddr_aton2(const char *txt, u8 *addr)
-{
-	int i;
-	const char *pos = txt;
-
-	for (i = 0; i < 6; i++) {
-		int a, b;
-
-		while (*pos == ':' || *pos == '.' || *pos == '-')
-			pos++;
-
-		a = hex2num(*pos++);
-		if (a < 0)
-			return -1;
-		b = hex2num(*pos++);
-		if (b < 0)
-			return -1;
-		*addr++ = (a << 4) | b;
-	}
-
-	return pos - txt;
-}
-
-
-/**
- * hexstr2bin - Convert ASCII hex string into binary data
- * @hex: ASCII hex string (e.g., "01ab")
- * @buf: Buffer for the binary data
- * @len: Length of the text to convert in bytes (of buf); hex will be double
- * this size
- * Returns: 0 on success, -1 on failure (invalid hex string)
- */
-int hexstr2bin(const char *hex, u8 *buf, size_t len)
-{
-	size_t i;
-	int a;
-	const char *ipos = hex;
-	u8 *opos = buf;
-
-	for (i = 0; i < len; i++) {
-		a = hex2byte(ipos);
-		if (a < 0)
-			return -1;
-		*opos++ = a;
-		ipos += 2;
-	}
-	return 0;
-}
-
-
-/**
- * inc_byte_array - Increment arbitrary length byte array by one
- * @counter: Pointer to byte array
- * @len: Length of the counter in bytes
- *
- * This function increments the last byte of the counter by one and continues
- * rolling over to more significant bytes if the byte was incremented from
- * 0xff to 0x00.
- */
-void inc_byte_array(u8 *counter, size_t len)
-{
-	int pos = len - 1;
-	while (pos >= 0) {
-		counter[pos]++;
-		if (counter[pos] != 0)
-			break;
-		pos--;
-	}
-}
-
-
-void wpa_get_ntp_timestamp(u8 *buf)
-{
-	struct os_time now;
-	u32 sec, usec;
-	be32 tmp;
-
-	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
-	os_get_time(&now);
-	sec = now.sec + 2208988800U; /* Epoch to 1900 */
-	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
-	usec = now.usec;
-	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
-	tmp = host_to_be32(sec);
-	os_memcpy(buf, (u8 *) &tmp, 4);
-	tmp = host_to_be32(usec);
-	os_memcpy(buf + 4, (u8 *) &tmp, 4);
-}
-
-
-static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
-				    size_t len, int uppercase)
-{
-	size_t i;
-	char *pos = buf, *end = buf + buf_size;
-	int ret;
-	if (buf_size == 0)
-		return 0;
-	for (i = 0; i < len; i++) {
-		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
-				  data[i]);
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return pos - buf;
-		}
-		pos += ret;
-	}
-	end[-1] = '\0';
-	return pos - buf;
-}
-
-/**
- * wpa_snprintf_hex - Print data as a hex string into a buffer
- * @buf: Memory area to use as the output buffer
- * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
- * @data: Data to be printed
- * @len: Length of data in bytes
- * Returns: Number of bytes written
- */
-int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
-{
-	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
-}
-
-
-/**
- * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
- * @buf: Memory area to use as the output buffer
- * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
- * @data: Data to be printed
- * @len: Length of data in bytes
- * Returns: Number of bytes written
- */
-int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
-			       size_t len)
-{
-	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
-}
-
-
-#ifdef CONFIG_ANSI_C_EXTRA
-
-#ifdef _WIN32_WCE
-void perror(const char *s)
-{
-	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
-		   s, (int) GetLastError());
-}
-#endif /* _WIN32_WCE */
-
-
-int optind = 1;
-int optopt;
-char *optarg;
-
-int getopt(int argc, char *const argv[], const char *optstring)
-{
-	static int optchr = 1;
-	char *cp;
-
-	if (optchr == 1) {
-		if (optind >= argc) {
-			/* all arguments processed */
-			return EOF;
-		}
-
-		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
-			/* no option characters */
-			return EOF;
-		}
-	}
-
-	if (os_strcmp(argv[optind], "--") == 0) {
-		/* no more options */
-		optind++;
-		return EOF;
-	}
-
-	optopt = argv[optind][optchr];
-	cp = os_strchr(optstring, optopt);
-	if (cp == NULL || optopt == ':') {
-		if (argv[optind][++optchr] == '\0') {
-			optchr = 1;
-			optind++;
-		}
-		return '?';
-	}
-
-	if (cp[1] == ':') {
-		/* Argument required */
-		optchr = 1;
-		if (argv[optind][optchr + 1]) {
-			/* No space between option and argument */
-			optarg = &argv[optind++][optchr + 1];
-		} else if (++optind >= argc) {
-			/* option requires an argument */
-			return '?';
-		} else {
-			/* Argument in the next argv */
-			optarg = argv[optind++];
-		}
-	} else {
-		/* No argument */
-		if (argv[optind][++optchr] == '\0') {
-			optchr = 1;
-			optind++;
-		}
-		optarg = NULL;
-	}
-	return *cp;
-}
-#endif /* CONFIG_ANSI_C_EXTRA */
-
-
-#ifdef CONFIG_NATIVE_WINDOWS
-/**
- * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
- * @str: Pointer to string to convert
- *
- * This function converts a unicode string to ASCII using the same
- * buffer for output. If UNICODE is not set, the buffer is not
- * modified.
- */
-void wpa_unicode2ascii_inplace(TCHAR *str)
-{
-#ifdef UNICODE
-	char *dst = (char *) str;
-	while (*str)
-		*dst++ = (char) *str++;
-	*dst = '\0';
-#endif /* UNICODE */
-}
-
-
-TCHAR * wpa_strdup_tchar(const char *str)
-{
-#ifdef UNICODE
-	TCHAR *buf;
-	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
-	if (buf == NULL)
-		return NULL;
-	wsprintf(buf, L"%S", str);
-	return buf;
-#else /* UNICODE */
-	return os_strdup(str);
-#endif /* UNICODE */
-}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-/**
- * wpa_ssid_txt - Convert SSID to a printable string
- * @ssid: SSID (32-octet string)
- * @ssid_len: Length of ssid in octets
- * Returns: Pointer to a printable string
- *
- * This function can be used to convert SSIDs into printable form. In most
- * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
- * does not limit the used character set, so anything could be used in an SSID.
- *
- * This function uses a static buffer, so only one call can be used at the
- * time, i.e., this is not re-entrant and the returned buffer must be used
- * before calling this again.
- */
-const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
-{
-	static char ssid_txt[33];
-	char *pos;
-
-	if (ssid_len > 32)
-		ssid_len = 32;
-	os_memcpy(ssid_txt, ssid, ssid_len);
-	ssid_txt[ssid_len] = '\0';
-	for (pos = ssid_txt; *pos != '\0'; pos++) {
-		if ((u8) *pos < 32 || (u8) *pos >= 127)
-			*pos = '_';
-	}
-	return ssid_txt;
-}
-
-
-void * __hide_aliasing_typecast(void *foo)
-{
-	return foo;
-}

Copied: vendor/wpa/2.0/src/utils/common.c (from rev 9639, vendor/wpa/dist/src/utils/common.c)
===================================================================
--- vendor/wpa/2.0/src/utils/common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,612 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j at 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"
+
+
+static int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+
+int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_aton(const char *txt, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		a = hex2num(*txt++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*txt++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+		if (i < 5 && *txt++ != ':')
+			return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
+ * @txt: MAC address as a string (e.g., "001122334455")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_compact_aton(const char *txt, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		a = hex2num(*txt++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*txt++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+	}
+
+	return 0;
+}
+
+/**
+ * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
+ * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: Characters used (> 0) on success, -1 on failure
+ */
+int hwaddr_aton2(const char *txt, u8 *addr)
+{
+	int i;
+	const char *pos = txt;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		while (*pos == ':' || *pos == '.' || *pos == '-')
+			pos++;
+
+		a = hex2num(*pos++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*pos++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+	}
+
+	return pos - txt;
+}
+
+
+/**
+ * hexstr2bin - Convert ASCII hex string into binary data
+ * @hex: ASCII hex string (e.g., "01ab")
+ * @buf: Buffer for the binary data
+ * @len: Length of the text to convert in bytes (of buf); hex will be double
+ * this size
+ * Returns: 0 on success, -1 on failure (invalid hex string)
+ */
+int hexstr2bin(const char *hex, u8 *buf, size_t len)
+{
+	size_t i;
+	int a;
+	const char *ipos = hex;
+	u8 *opos = buf;
+
+	for (i = 0; i < len; i++) {
+		a = hex2byte(ipos);
+		if (a < 0)
+			return -1;
+		*opos++ = a;
+		ipos += 2;
+	}
+	return 0;
+}
+
+
+/**
+ * inc_byte_array - Increment arbitrary length byte array by one
+ * @counter: Pointer to byte array
+ * @len: Length of the counter in bytes
+ *
+ * This function increments the last byte of the counter by one and continues
+ * rolling over to more significant bytes if the byte was incremented from
+ * 0xff to 0x00.
+ */
+void inc_byte_array(u8 *counter, size_t len)
+{
+	int pos = len - 1;
+	while (pos >= 0) {
+		counter[pos]++;
+		if (counter[pos] != 0)
+			break;
+		pos--;
+	}
+}
+
+
+void wpa_get_ntp_timestamp(u8 *buf)
+{
+	struct os_time now;
+	u32 sec, usec;
+	be32 tmp;
+
+	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+	os_get_time(&now);
+	sec = now.sec + 2208988800U; /* Epoch to 1900 */
+	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+	usec = now.usec;
+	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
+	tmp = host_to_be32(sec);
+	os_memcpy(buf, (u8 *) &tmp, 4);
+	tmp = host_to_be32(usec);
+	os_memcpy(buf + 4, (u8 *) &tmp, 4);
+}
+
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+				    size_t len, int uppercase)
+{
+	size_t i;
+	char *pos = buf, *end = buf + buf_size;
+	int ret;
+	if (buf_size == 0)
+		return 0;
+	for (i = 0; i < len; i++) {
+		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+				  data[i]);
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+	end[-1] = '\0';
+	return pos - buf;
+}
+
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
+
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+			       size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+		   s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+	static int optchr = 1;
+	char *cp;
+
+	if (optchr == 1) {
+		if (optind >= argc) {
+			/* all arguments processed */
+			return EOF;
+		}
+
+		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+			/* no option characters */
+			return EOF;
+		}
+	}
+
+	if (os_strcmp(argv[optind], "--") == 0) {
+		/* no more options */
+		optind++;
+		return EOF;
+	}
+
+	optopt = argv[optind][optchr];
+	cp = os_strchr(optstring, optopt);
+	if (cp == NULL || optopt == ':') {
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		return '?';
+	}
+
+	if (cp[1] == ':') {
+		/* Argument required */
+		optchr = 1;
+		if (argv[optind][optchr + 1]) {
+			/* No space between option and argument */
+			optarg = &argv[optind++][optchr + 1];
+		} else if (++optind >= argc) {
+			/* option requires an argument */
+			return '?';
+		} else {
+			/* Argument in the next argv */
+			optarg = argv[optind++];
+		}
+	} else {
+		/* No argument */
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		optarg = NULL;
+	}
+	return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+	char *dst = (char *) str;
+	while (*str)
+		*dst++ = (char) *str++;
+	*dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+	TCHAR *buf;
+	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+	if (buf == NULL)
+		return NULL;
+	wsprintf(buf, L"%S", str);
+	return buf;
+#else /* UNICODE */
+	return os_strdup(str);
+#endif /* UNICODE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
+{
+	char *end = txt + maxlen;
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (txt + 4 > end)
+			break;
+
+		switch (data[i]) {
+		case '\"':
+			*txt++ = '\\';
+			*txt++ = '\"';
+			break;
+		case '\\':
+			*txt++ = '\\';
+			*txt++ = '\\';
+			break;
+		case '\e':
+			*txt++ = '\\';
+			*txt++ = 'e';
+			break;
+		case '\n':
+			*txt++ = '\\';
+			*txt++ = 'n';
+			break;
+		case '\r':
+			*txt++ = '\\';
+			*txt++ = 'r';
+			break;
+		case '\t':
+			*txt++ = '\\';
+			*txt++ = 't';
+			break;
+		default:
+			if (data[i] >= 32 && data[i] <= 127) {
+				*txt++ = data[i];
+			} else {
+				txt += os_snprintf(txt, end - txt, "\\x%02x",
+						   data[i]);
+			}
+			break;
+		}
+	}
+
+	*txt = '\0';
+}
+
+
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
+{
+	const char *pos = str;
+	size_t len = 0;
+	int val;
+
+	while (*pos) {
+		if (len == maxlen)
+			break;
+		switch (*pos) {
+		case '\\':
+			pos++;
+			switch (*pos) {
+			case '\\':
+				buf[len++] = '\\';
+				pos++;
+				break;
+			case '"':
+				buf[len++] = '"';
+				pos++;
+				break;
+			case 'n':
+				buf[len++] = '\n';
+				pos++;
+				break;
+			case 'r':
+				buf[len++] = '\r';
+				pos++;
+				break;
+			case 't':
+				buf[len++] = '\t';
+				pos++;
+				break;
+			case 'e':
+				buf[len++] = '\e';
+				pos++;
+				break;
+			case 'x':
+				pos++;
+				val = hex2byte(pos);
+				if (val < 0) {
+					val = hex2num(*pos);
+					if (val < 0)
+						break;
+					buf[len++] = val;
+					pos++;
+				} else {
+					buf[len++] = val;
+					pos += 2;
+				}
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+				val = *pos++ - '0';
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				buf[len++] = val;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			buf[len++] = *pos++;
+			break;
+		}
+	}
+
+	return len;
+}
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
+{
+	static char ssid_txt[32 * 4 + 1];
+
+	if (ssid == NULL) {
+		ssid_txt[0] = '\0';
+		return ssid_txt;
+	}
+
+	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
+	return ssid_txt;
+}
+
+
+void * __hide_aliasing_typecast(void *foo)
+{
+	return foo;
+}
+
+
+char * wpa_config_parse_string(const char *value, size_t *len)
+{
+	if (*value == '"') {
+		const char *pos;
+		char *str;
+		value++;
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		*len = pos - value;
+		str = os_malloc(*len + 1);
+		if (str == NULL)
+			return NULL;
+		os_memcpy(str, value, *len);
+		str[*len] = '\0';
+		return str;
+	} else if (*value == 'P' && value[1] == '"') {
+		const char *pos;
+		char *tstr, *str;
+		size_t tlen;
+		value += 2;
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		tlen = pos - value;
+		tstr = os_malloc(tlen + 1);
+		if (tstr == NULL)
+			return NULL;
+		os_memcpy(tstr, value, tlen);
+		tstr[tlen] = '\0';
+
+		str = os_malloc(tlen + 1);
+		if (str == NULL) {
+			os_free(tstr);
+			return NULL;
+		}
+
+		*len = printf_decode((u8 *) str, tlen + 1, tstr);
+		os_free(tstr);
+
+		return str;
+	} else {
+		u8 *str;
+		size_t tlen, hlen = os_strlen(value);
+		if (hlen & 1)
+			return NULL;
+		tlen = hlen / 2;
+		str = os_malloc(tlen + 1);
+		if (str == NULL)
+			return NULL;
+		if (hexstr2bin(value, str, tlen)) {
+			os_free(str);
+			return NULL;
+		}
+		str[tlen] = '\0';
+		*len = tlen;
+		return (char *) str;
+	}
+}
+
+
+int is_hex(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;
+}
+
+
+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)
+{
+	size_t len = 0;
+
+	os_memset(res, 0, res_len);
+
+	if (src1) {
+		if (src1_len >= res_len) {
+			os_memcpy(res, src1, res_len);
+			return res_len;
+		}
+
+		os_memcpy(res, src1, src1_len);
+		len += src1_len;
+	}
+
+	if (src2) {
+		if (len + src2_len >= res_len) {
+			os_memcpy(res + len, src2, res_len - len);
+			return res_len;
+		}
+
+		os_memcpy(res + len, src2, src2_len);
+		len += src2_len;
+	}
+
+	return len;
+}

Deleted: vendor/wpa/2.0/src/utils/common.h
===================================================================
--- vendor/wpa/dist/src/utils/common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,477 +0,0 @@
-/*
- * wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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_TI_COMPILER
-#define __BIG_ENDIAN 4321
-#define __LITTLE_ENDIAN 1234
-#ifdef __big_endian__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-#endif /* CONFIG_TI_COMPILER */
-
-#ifdef __SYMBIAN32__
-#define __BIG_ENDIAN 4321
-#define __LITTLE_ENDIAN 1234
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif /* __SYMBIAN32__ */
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock.h>
-
-typedef int socklen_t;
-
-#ifndef MSG_DONTWAIT
-#define MSG_DONTWAIT 0 /* not supported */
-#endif
-
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#ifdef _MSC_VER
-#define inline __inline
-
-#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 */
-
-#ifdef CONFIG_TI_COMPILER
-#ifdef _LLONG_AVAILABLE
-typedef unsigned long long u64;
-#else
-/*
- * TODO: 64-bit variable not available. Using long as a workaround to test the
- * build, but this will likely not work for all operations.
- */
-typedef unsigned long u64;
-#endif
-typedef unsigned int u32;
-typedef unsigned short u16;
-typedef unsigned char u8;
-#define WPA_TYPES_DEFINED
-#endif /* CONFIG_TI_COMPILER */
-
-#ifdef __SYMBIAN32__
-#define __REMOVE_PLATSEC_DIAGNOSTICS__
-#include <e32def.h>
-typedef TUint64 u64;
-typedef TUint32 u32;
-typedef TUint16 u16;
-typedef TUint8 u8;
-#define WPA_TYPES_DEFINED
-#endif /* __SYMBIAN32__ */
-
-#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 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 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 */
-
-#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
-#define WPA_PUT_BE16(a, val)			\
-	do {					\
-		(a)[0] = ((u16) (val)) >> 8;	\
-		(a)[1] = ((u16) (val)) & 0xff;	\
-	} while (0)
-
-#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
-#define WPA_PUT_LE16(a, val)			\
-	do {					\
-		(a)[1] = ((u16) (val)) >> 8;	\
-		(a)[0] = ((u16) (val)) & 0xff;	\
-	} while (0)
-
-#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
-			 ((u32) (a)[2]))
-#define WPA_PUT_BE24(a, val)					\
-	do {							\
-		(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[2] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
-			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
-#define WPA_PUT_BE32(a, val)					\
-	do {							\
-		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
-			 (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
-#define WPA_PUT_LE32(a, val)					\
-	do {							\
-		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
-		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_BE64(a) ((((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]))
-#define WPA_PUT_BE64(a, val)				\
-	do {						\
-		(a)[0] = (u8) (((u64) (val)) >> 56);	\
-		(a)[1] = (u8) (((u64) (val)) >> 48);	\
-		(a)[2] = (u8) (((u64) (val)) >> 40);	\
-		(a)[3] = (u8) (((u64) (val)) >> 32);	\
-		(a)[4] = (u8) (((u64) (val)) >> 24);	\
-		(a)[5] = (u8) (((u64) (val)) >> 16);	\
-		(a)[6] = (u8) (((u64) (val)) >> 8);	\
-		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
-	} while (0)
-
-#define WPA_GET_LE64(a) ((((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]))
-
-
-#ifndef ETH_ALEN
-#define ETH_ALEN 6
-#endif
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-#ifndef ETH_P_ALL
-#define ETH_P_ALL 0x0003
-#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))
-#else
-#define PRINTF_FORMAT(a,b)
-#define STRUCT_PACKED
-#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"
-#endif
-
-#ifndef BIT
-#define BIT(x) (1 << (x))
-#endif
-
-/*
- * Definitions for sparse validation
- * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
- */
-#ifdef __CHECKER__
-#define __force __attribute__((force))
-#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 */
-
-int hwaddr_aton(const char *txt, u8 *addr);
-int hwaddr_aton2(const char *txt, u8 *addr);
-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_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);
-
-#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 */
-
-const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
-
-static inline int is_zero_ether_addr(const u8 *a)
-{
-	return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
-}
-
-#include "wpa_debug.h"
-
-
-/*
- * 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))
-
-#endif /* COMMON_H */

Copied: vendor/wpa/2.0/src/utils/common.h (from rev 9639, vendor/wpa/dist/src/utils/common.h)
===================================================================
--- vendor/wpa/2.0/src/utils/common.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,489 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j at 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_TI_COMPILER
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#ifdef __big_endian__
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif /* CONFIG_TI_COMPILER */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+
+typedef int socklen_t;
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0 /* not supported */
+#endif
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#ifdef _MSC_VER
+#define inline __inline
+
+#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 */
+
+#ifdef CONFIG_TI_COMPILER
+#ifdef _LLONG_AVAILABLE
+typedef unsigned long long u64;
+#else
+/*
+ * TODO: 64-bit variable not available. Using long as a workaround to test the
+ * build, but this will likely not work for all operations.
+ */
+typedef unsigned long u64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#define WPA_TYPES_DEFINED
+#endif /* CONFIG_TI_COMPILER */
+
+#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 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 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 */
+
+#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define WPA_PUT_BE16(a, val)			\
+	do {					\
+		(a)[0] = ((u16) (val)) >> 8;	\
+		(a)[1] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define WPA_PUT_LE16(a, val)			\
+	do {					\
+		(a)[1] = ((u16) (val)) >> 8;	\
+		(a)[0] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+			 ((u32) (a)[2]))
+#define WPA_PUT_BE24(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[2] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define WPA_PUT_BE32(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
+			 (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
+#define WPA_PUT_LE32(a, val)					\
+	do {							\
+		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_BE64(a) ((((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]))
+#define WPA_PUT_BE64(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u64) (val)) >> 56);	\
+		(a)[1] = (u8) (((u64) (val)) >> 48);	\
+		(a)[2] = (u8) (((u64) (val)) >> 40);	\
+		(a)[3] = (u8) (((u64) (val)) >> 32);	\
+		(a)[4] = (u8) (((u64) (val)) >> 24);	\
+		(a)[5] = (u8) (((u64) (val)) >> 16);	\
+		(a)[6] = (u8) (((u64) (val)) >> 8);	\
+		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
+	} while (0)
+
+#define WPA_GET_LE64(a) ((((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]))
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#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))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#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) (1 << (x))
+#endif
+
+/*
+ * Definitions for sparse validation
+ * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
+ */
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#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 */
+
+int hwaddr_aton(const char *txt, u8 *addr);
+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_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);
+
+#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);
+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);
+
+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;
+}
+
+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
+
+#include "wpa_debug.h"
+
+
+/*
+ * 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 */

Copied: vendor/wpa/2.0/src/utils/edit.c (from rev 9639, vendor/wpa/dist/src/utils/edit.c)
===================================================================
--- vendor/wpa/2.0/src/utils/edit.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/edit.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1174 @@
+/*
+ * Command line editing and history
+ * Copyright (c) 2010-2011, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <termios.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "edit.h"
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
+static const char *ps2 = NULL;
+
+#define HISTORY_MAX 100
+
+struct edit_history {
+	struct dl_list list;
+	char str[1];
+};
+
+static struct dl_list history_list;
+static struct edit_history *history_curr;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+	NULL;
+
+static struct termios prevt, newt;
+
+
+#define CLEAR_END_LINE "\e[K"
+
+
+void edit_clear_line(void)
+{
+	int i;
+	putchar('\r');
+	for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
+		putchar(' ');
+}
+
+
+static void move_start(void)
+{
+	cmdbuf_pos = 0;
+	edit_redraw();
+}
+
+
+static void move_end(void)
+{
+	cmdbuf_pos = cmdbuf_len;
+	edit_redraw();
+}
+
+
+static void move_left(void)
+{
+	if (cmdbuf_pos > 0) {
+		cmdbuf_pos--;
+		edit_redraw();
+	}
+}
+
+
+static void move_right(void)
+{
+	if (cmdbuf_pos < cmdbuf_len) {
+		cmdbuf_pos++;
+		edit_redraw();
+	}
+}
+
+
+static void move_word_left(void)
+{
+	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
+		cmdbuf_pos--;
+	while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
+		cmdbuf_pos--;
+	edit_redraw();
+}
+
+
+static void move_word_right(void)
+{
+	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
+		cmdbuf_pos++;
+	while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
+		cmdbuf_pos++;
+	edit_redraw();
+}
+
+
+static void delete_left(void)
+{
+	if (cmdbuf_pos == 0)
+		return;
+
+	edit_clear_line();
+	os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
+		   cmdbuf_len - cmdbuf_pos);
+	cmdbuf_pos--;
+	cmdbuf_len--;
+	edit_redraw();
+}
+
+
+static void delete_current(void)
+{
+	if (cmdbuf_pos == cmdbuf_len)
+		return;
+
+	edit_clear_line();
+	os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
+		   cmdbuf_len - cmdbuf_pos);
+	cmdbuf_len--;
+	edit_redraw();
+}
+
+
+static void delete_word(void)
+{
+	int pos;
+
+	edit_clear_line();
+	pos = cmdbuf_pos;
+	while (pos > 0 && cmdbuf[pos - 1] == ' ')
+		pos--;
+	while (pos > 0 && cmdbuf[pos - 1] != ' ')
+		pos--;
+	os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+	cmdbuf_len -= cmdbuf_pos - pos;
+	cmdbuf_pos = pos;
+	edit_redraw();
+}
+
+
+static void clear_left(void)
+{
+	if (cmdbuf_pos == 0)
+		return;
+
+	edit_clear_line();
+	os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+	cmdbuf_len -= cmdbuf_pos;
+	cmdbuf_pos = 0;
+	edit_redraw();
+}
+
+
+static void clear_right(void)
+{
+	if (cmdbuf_pos == cmdbuf_len)
+		return;
+
+	edit_clear_line();
+	cmdbuf_len = cmdbuf_pos;
+	edit_redraw();
+}
+
+
+static void history_add(const char *str)
+{
+	struct edit_history *h, *match = NULL, *last = NULL;
+	size_t len, count = 0;
+
+	if (str[0] == '\0')
+		return;
+
+	dl_list_for_each(h, &history_list, struct edit_history, list) {
+		if (os_strcmp(str, h->str) == 0) {
+			match = h;
+			break;
+		}
+		last = h;
+		count++;
+	}
+
+	if (match) {
+		dl_list_del(&h->list);
+		dl_list_add(&history_list, &h->list);
+		history_curr = h;
+		return;
+	}
+
+	if (count >= HISTORY_MAX && last) {
+		dl_list_del(&last->list);
+		os_free(last);
+	}
+
+	len = os_strlen(str);
+	h = os_zalloc(sizeof(*h) + len);
+	if (h == NULL)
+		return;
+	dl_list_add(&history_list, &h->list);
+	os_strlcpy(h->str, str, len + 1);
+	history_curr = h;
+}
+
+
+static void history_use(void)
+{
+	edit_clear_line();
+	cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str);
+	os_memcpy(cmdbuf, history_curr->str, cmdbuf_len);
+	edit_redraw();
+}
+
+
+static void history_prev(void)
+{
+	if (history_curr == NULL)
+		return;
+
+	if (history_curr ==
+	    dl_list_first(&history_list, struct edit_history, list)) {
+		if (!currbuf_valid) {
+			cmdbuf[cmdbuf_len] = '\0';
+			os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+			currbuf_valid = 1;
+			history_use();
+			return;
+		}
+	}
+
+	if (history_curr ==
+	    dl_list_last(&history_list, struct edit_history, list))
+		return;
+
+	history_curr = dl_list_entry(history_curr->list.next,
+				     struct edit_history, list);
+	history_use();
+}
+
+
+static void history_next(void)
+{
+	if (history_curr == NULL ||
+	    history_curr ==
+	    dl_list_first(&history_list, struct edit_history, list)) {
+		if (currbuf_valid) {
+			currbuf_valid = 0;
+			edit_clear_line();
+			cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+			os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+			edit_redraw();
+		}
+		return;
+	}
+
+	history_curr = dl_list_entry(history_curr->list.prev,
+				     struct edit_history, list);
+	history_use();
+}
+
+
+static void history_read(const char *fname)
+{
+	FILE *f;
+	char buf[CMD_BUF_LEN], *pos;
+
+	f = fopen(fname, "r");
+	if (f == NULL)
+		return;
+
+	while (fgets(buf, CMD_BUF_LEN, f)) {
+		for (pos = buf; *pos; pos++) {
+			if (*pos == '\r' || *pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+		}
+		history_add(buf);
+	}
+
+	fclose(f);
+}
+
+
+static void history_write(const char *fname,
+			  int (*filter_cb)(void *ctx, const char *cmd))
+{
+	FILE *f;
+	struct edit_history *h;
+
+	f = fopen(fname, "w");
+	if (f == NULL)
+		return;
+
+	dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
+		if (filter_cb && filter_cb(edit_cb_ctx, h->str))
+			continue;
+		fprintf(f, "%s\n", h->str);
+	}
+
+	fclose(f);
+}
+
+
+static void history_debug_dump(void)
+{
+	struct edit_history *h;
+	edit_clear_line();
+	printf("\r");
+	dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
+		printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+	if (currbuf_valid)
+		printf("{%s}\n", currbuf);
+	edit_redraw();
+}
+
+
+static void insert_char(int c)
+{
+	if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
+		return;
+	if (cmdbuf_len == cmdbuf_pos) {
+		cmdbuf[cmdbuf_pos++] = c;
+		cmdbuf_len++;
+		putchar(c);
+		fflush(stdout);
+	} else {
+		os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
+			   cmdbuf_len - cmdbuf_pos);
+		cmdbuf[cmdbuf_pos++] = c;
+		cmdbuf_len++;
+		edit_redraw();
+	}
+}
+
+
+static void process_cmd(void)
+{
+
+	if (cmdbuf_len == 0) {
+		printf("\n%s> ", ps2 ? ps2 : "");
+		fflush(stdout);
+		return;
+	}
+	printf("\n");
+	cmdbuf[cmdbuf_len] = '\0';
+	history_add(cmdbuf);
+	cmdbuf_pos = 0;
+	cmdbuf_len = 0;
+	edit_cmd_cb(edit_cb_ctx, cmdbuf);
+	printf("%s> ", ps2 ? ps2 : "");
+	fflush(stdout);
+}
+
+
+static void free_completions(char **c)
+{
+	int i;
+	if (c == NULL)
+		return;
+	for (i = 0; c[i]; i++)
+		os_free(c[i]);
+	os_free(c);
+}
+
+
+static int filter_strings(char **c, char *str, size_t len)
+{
+	int i, j;
+
+	for (i = 0, j = 0; c[j]; j++) {
+		if (os_strncasecmp(c[j], str, len) == 0) {
+			if (i != j) {
+				c[i] = c[j];
+				c[j] = NULL;
+			}
+			i++;
+		} else {
+			os_free(c[j]);
+			c[j] = NULL;
+		}
+	}
+	c[i] = NULL;
+	return i;
+}
+
+
+static int common_len(const char *a, const char *b)
+{
+	int len = 0;
+	while (a[len] && a[len] == b[len])
+		len++;
+	return len;
+}
+
+
+static int max_common_length(char **c)
+{
+	int len, i;
+
+	len = os_strlen(c[0]);
+	for (i = 1; c[i]; i++) {
+		int same = common_len(c[0], c[i]);
+		if (same < len)
+			len = same;
+	}
+
+	return len;
+}
+
+
+static int cmp_str(const void *a, const void *b)
+{
+	return os_strcmp(* (const char **) a, * (const char **) b);
+}
+
+static void complete(int list)
+{
+	char **c;
+	int i, len, count;
+	int start, end;
+	int room, plen, add_space;
+
+	if (edit_completion_cb == NULL)
+		return;
+
+	cmdbuf[cmdbuf_len] = '\0';
+	c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
+	if (c == NULL)
+		return;
+
+	end = cmdbuf_pos;
+	start = end;
+	while (start > 0 && cmdbuf[start - 1] != ' ')
+		start--;
+	plen = end - start;
+
+	count = filter_strings(c, &cmdbuf[start], plen);
+	if (count == 0) {
+		free_completions(c);
+		return;
+	}
+
+	len = max_common_length(c);
+	if (len <= plen && count > 1) {
+		if (list) {
+			qsort(c, count, sizeof(char *), cmp_str);
+			edit_clear_line();
+			printf("\r");
+			for (i = 0; c[i]; i++)
+				printf("%s%s", i > 0 ? " " : "", c[i]);
+			printf("\n");
+			edit_redraw();
+		}
+		free_completions(c);
+		return;
+	}
+	len -= plen;
+
+	room = sizeof(cmdbuf) - 1 - cmdbuf_len;
+	if (room < len)
+		len = room;
+	add_space = count == 1 && len < room;
+
+	os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
+		   cmdbuf_len - cmdbuf_pos);
+	os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
+	if (add_space)
+		cmdbuf[cmdbuf_pos + len] = ' ';
+
+	cmdbuf_pos += len + add_space;
+	cmdbuf_len += len + add_space;
+
+	edit_redraw();
+
+	free_completions(c);
+}
+
+
+enum edit_key_code {
+	EDIT_KEY_NONE = 256,
+	EDIT_KEY_TAB,
+	EDIT_KEY_UP,
+	EDIT_KEY_DOWN,
+	EDIT_KEY_RIGHT,
+	EDIT_KEY_LEFT,
+	EDIT_KEY_ENTER,
+	EDIT_KEY_BACKSPACE,
+	EDIT_KEY_INSERT,
+	EDIT_KEY_DELETE,
+	EDIT_KEY_HOME,
+	EDIT_KEY_END,
+	EDIT_KEY_PAGE_UP,
+	EDIT_KEY_PAGE_DOWN,
+	EDIT_KEY_F1,
+	EDIT_KEY_F2,
+	EDIT_KEY_F3,
+	EDIT_KEY_F4,
+	EDIT_KEY_F5,
+	EDIT_KEY_F6,
+	EDIT_KEY_F7,
+	EDIT_KEY_F8,
+	EDIT_KEY_F9,
+	EDIT_KEY_F10,
+	EDIT_KEY_F11,
+	EDIT_KEY_F12,
+	EDIT_KEY_CTRL_UP,
+	EDIT_KEY_CTRL_DOWN,
+	EDIT_KEY_CTRL_RIGHT,
+	EDIT_KEY_CTRL_LEFT,
+	EDIT_KEY_CTRL_A,
+	EDIT_KEY_CTRL_B,
+	EDIT_KEY_CTRL_D,
+	EDIT_KEY_CTRL_E,
+	EDIT_KEY_CTRL_F,
+	EDIT_KEY_CTRL_G,
+	EDIT_KEY_CTRL_H,
+	EDIT_KEY_CTRL_J,
+	EDIT_KEY_CTRL_K,
+	EDIT_KEY_CTRL_L,
+	EDIT_KEY_CTRL_N,
+	EDIT_KEY_CTRL_O,
+	EDIT_KEY_CTRL_P,
+	EDIT_KEY_CTRL_R,
+	EDIT_KEY_CTRL_T,
+	EDIT_KEY_CTRL_U,
+	EDIT_KEY_CTRL_V,
+	EDIT_KEY_CTRL_W,
+	EDIT_KEY_ALT_UP,
+	EDIT_KEY_ALT_DOWN,
+	EDIT_KEY_ALT_RIGHT,
+	EDIT_KEY_ALT_LEFT,
+	EDIT_KEY_SHIFT_UP,
+	EDIT_KEY_SHIFT_DOWN,
+	EDIT_KEY_SHIFT_RIGHT,
+	EDIT_KEY_SHIFT_LEFT,
+	EDIT_KEY_ALT_SHIFT_UP,
+	EDIT_KEY_ALT_SHIFT_DOWN,
+	EDIT_KEY_ALT_SHIFT_RIGHT,
+	EDIT_KEY_ALT_SHIFT_LEFT,
+	EDIT_KEY_EOF
+};
+
+static void show_esc_buf(const char *esc_buf, char c, int i)
+{
+	edit_clear_line();
+	printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
+	edit_redraw();
+}
+
+
+static enum edit_key_code esc_seq_to_key1_no(char last)
+{
+	switch (last) {
+	case 'A':
+		return EDIT_KEY_UP;
+	case 'B':
+		return EDIT_KEY_DOWN;
+	case 'C':
+		return EDIT_KEY_RIGHT;
+	case 'D':
+		return EDIT_KEY_LEFT;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key1_shift(char last)
+{
+	switch (last) {
+	case 'A':
+		return EDIT_KEY_SHIFT_UP;
+	case 'B':
+		return EDIT_KEY_SHIFT_DOWN;
+	case 'C':
+		return EDIT_KEY_SHIFT_RIGHT;
+	case 'D':
+		return EDIT_KEY_SHIFT_LEFT;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt(char last)
+{
+	switch (last) {
+	case 'A':
+		return EDIT_KEY_ALT_UP;
+	case 'B':
+		return EDIT_KEY_ALT_DOWN;
+	case 'C':
+		return EDIT_KEY_ALT_RIGHT;
+	case 'D':
+		return EDIT_KEY_ALT_LEFT;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
+{
+	switch (last) {
+	case 'A':
+		return EDIT_KEY_ALT_SHIFT_UP;
+	case 'B':
+		return EDIT_KEY_ALT_SHIFT_DOWN;
+	case 'C':
+		return EDIT_KEY_ALT_SHIFT_RIGHT;
+	case 'D':
+		return EDIT_KEY_ALT_SHIFT_LEFT;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key1_ctrl(char last)
+{
+	switch (last) {
+	case 'A':
+		return EDIT_KEY_CTRL_UP;
+	case 'B':
+		return EDIT_KEY_CTRL_DOWN;
+	case 'C':
+		return EDIT_KEY_CTRL_RIGHT;
+	case 'D':
+		return EDIT_KEY_CTRL_LEFT;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
+{
+	/* ESC-[<param1>;<param2><last> */
+
+	if (param1 < 0 && param2 < 0)
+		return esc_seq_to_key1_no(last);
+
+	if (param1 == 1 && param2 == 2)
+		return esc_seq_to_key1_shift(last);
+
+	if (param1 == 1 && param2 == 3)
+		return esc_seq_to_key1_alt(last);
+
+	if (param1 == 1 && param2 == 4)
+		return esc_seq_to_key1_alt_shift(last);
+
+	if (param1 == 1 && param2 == 5)
+		return esc_seq_to_key1_ctrl(last);
+
+	if (param2 < 0) {
+		if (last != '~')
+			return EDIT_KEY_NONE;
+		switch (param1) {
+		case 2:
+			return EDIT_KEY_INSERT;
+		case 3:
+			return EDIT_KEY_DELETE;
+		case 5:
+			return EDIT_KEY_PAGE_UP;
+		case 6:
+			return EDIT_KEY_PAGE_DOWN;
+		case 15:
+			return EDIT_KEY_F5;
+		case 17:
+			return EDIT_KEY_F6;
+		case 18:
+			return EDIT_KEY_F7;
+		case 19:
+			return EDIT_KEY_F8;
+		case 20:
+			return EDIT_KEY_F9;
+		case 21:
+			return EDIT_KEY_F10;
+		case 23:
+			return EDIT_KEY_F11;
+		case 24:
+			return EDIT_KEY_F12;
+		}
+	}
+
+	return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
+{
+	/* ESC-O<param1>;<param2><last> */
+
+	if (param1 >= 0 || param2 >= 0)
+		return EDIT_KEY_NONE;
+
+	switch (last) {
+	case 'F':
+		return EDIT_KEY_END;
+	case 'H':
+		return EDIT_KEY_HOME;
+	case 'P':
+		return EDIT_KEY_F1;
+	case 'Q':
+		return EDIT_KEY_F2;
+	case 'R':
+		return EDIT_KEY_F3;
+	case 'S':
+		return EDIT_KEY_F4;
+	default:
+		return EDIT_KEY_NONE;
+	}
+}
+
+
+static enum edit_key_code esc_seq_to_key(char *seq)
+{
+	char last, *pos;
+	int param1 = -1, param2 = -1;
+	enum edit_key_code ret = EDIT_KEY_NONE;
+
+	last = '\0';
+	for (pos = seq; *pos; pos++)
+		last = *pos;
+
+	if (seq[1] >= '0' && seq[1] <= '9') {
+		param1 = atoi(&seq[1]);
+		pos = os_strchr(seq, ';');
+		if (pos)
+			param2 = atoi(pos + 1);
+	}
+
+	if (seq[0] == '[')
+		ret = esc_seq_to_key1(param1, param2, last);
+	else if (seq[0] == 'O')
+		ret = esc_seq_to_key2(param1, param2, last);
+
+	if (ret != EDIT_KEY_NONE)
+		return ret;
+
+	edit_clear_line();
+	printf("\rUnknown escape sequence '%s'\n", seq);
+	edit_redraw();
+	return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code edit_read_key(int sock)
+{
+	int c;
+	unsigned char buf[1];
+	int res;
+	static int esc = -1;
+	static char esc_buf[7];
+
+	res = read(sock, buf, 1);
+	if (res < 0)
+		perror("read");
+	if (res <= 0)
+		return EDIT_KEY_EOF;
+
+	c = buf[0];
+
+	if (esc >= 0) {
+		if (c == 27 /* ESC */) {
+			esc = 0;
+			return EDIT_KEY_NONE;
+		}
+
+		if (esc == 6) {
+			show_esc_buf(esc_buf, c, 0);
+			esc = -1;
+		} else {
+			esc_buf[esc++] = c;
+			esc_buf[esc] = '\0';
+		}
+	}
+
+	if (esc == 1) {
+		if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
+			show_esc_buf(esc_buf, c, 1);
+			esc = -1;
+			return EDIT_KEY_NONE;
+		} else
+			return EDIT_KEY_NONE; /* Escape sequence continues */
+	}
+
+	if (esc > 1) {
+		if ((c >= '0' && c <= '9') || c == ';')
+			return EDIT_KEY_NONE; /* Escape sequence continues */
+
+		if (c == '~' || (c >= 'A' && c <= 'Z')) {
+			esc = -1;
+			return esc_seq_to_key(esc_buf);
+		}
+
+		show_esc_buf(esc_buf, c, 2);
+		esc = -1;
+		return EDIT_KEY_NONE;
+	}
+
+	switch (c) {
+	case 1:
+		return EDIT_KEY_CTRL_A;
+	case 2:
+		return EDIT_KEY_CTRL_B;
+	case 4:
+		return EDIT_KEY_CTRL_D;
+	case 5:
+		return EDIT_KEY_CTRL_E;
+	case 6:
+		return EDIT_KEY_CTRL_F;
+	case 7:
+		return EDIT_KEY_CTRL_G;
+	case 8:
+		return EDIT_KEY_CTRL_H;
+	case 9:
+		return EDIT_KEY_TAB;
+	case 10:
+		return EDIT_KEY_CTRL_J;
+	case 13: /* CR */
+		return EDIT_KEY_ENTER;
+	case 11:
+		return EDIT_KEY_CTRL_K;
+	case 12:
+		return EDIT_KEY_CTRL_L;
+	case 14:
+		return EDIT_KEY_CTRL_N;
+	case 15:
+		return EDIT_KEY_CTRL_O;
+	case 16:
+		return EDIT_KEY_CTRL_P;
+	case 18:
+		return EDIT_KEY_CTRL_R;
+	case 20:
+		return EDIT_KEY_CTRL_T;
+	case 21:
+		return EDIT_KEY_CTRL_U;
+	case 22:
+		return EDIT_KEY_CTRL_V;
+	case 23:
+		return EDIT_KEY_CTRL_W;
+	case 27: /* ESC */
+		esc = 0;
+		return EDIT_KEY_NONE;
+	case 127:
+		return EDIT_KEY_BACKSPACE;
+	default:
+		return c;
+	}
+}
+
+
+static char search_buf[21];
+static int search_skip;
+
+static char * search_find(void)
+{
+	struct edit_history *h;
+	size_t len = os_strlen(search_buf);
+	int skip = search_skip;
+
+	if (len == 0)
+		return NULL;
+
+	dl_list_for_each(h, &history_list, struct edit_history, list) {
+		if (os_strstr(h->str, search_buf)) {
+			if (skip == 0)
+				return h->str;
+			skip--;
+		}
+	}
+
+	search_skip = 0;
+	return NULL;
+}
+
+
+static void search_redraw(void)
+{
+	char *match = search_find();
+	printf("\rsearch '%s': %s" CLEAR_END_LINE,
+	       search_buf, match ? match : "");
+	printf("\rsearch '%s", search_buf);
+	fflush(stdout);
+}
+
+
+static void search_start(void)
+{
+	edit_clear_line();
+	search_buf[0] = '\0';
+	search_skip = 0;
+	search_redraw();
+}
+
+
+static void search_clear(void)
+{
+	search_redraw();
+	printf("\r" CLEAR_END_LINE);
+}
+
+
+static void search_stop(void)
+{
+	char *match = search_find();
+	search_buf[0] = '\0';
+	search_clear();
+	if (match) {
+		os_strlcpy(cmdbuf, match, CMD_BUF_LEN);
+		cmdbuf_len = os_strlen(cmdbuf);
+		cmdbuf_pos = cmdbuf_len;
+	}
+	edit_redraw();
+}
+
+
+static void search_cancel(void)
+{
+	search_buf[0] = '\0';
+	search_clear();
+	edit_redraw();
+}
+
+
+static void search_backspace(void)
+{
+	size_t len;
+	len = os_strlen(search_buf);
+	if (len == 0)
+		return;
+	search_buf[len - 1] = '\0';
+	search_skip = 0;
+	search_redraw();
+}
+
+
+static void search_next(void)
+{
+	search_skip++;
+	search_find();
+	search_redraw();
+}
+
+
+static void search_char(char c)
+{
+	size_t len;
+	len = os_strlen(search_buf);
+	if (len == sizeof(search_buf) - 1)
+		return;
+	search_buf[len] = c;
+	search_buf[len + 1] = '\0';
+	search_skip = 0;
+	search_redraw();
+}
+
+
+static enum edit_key_code search_key(enum edit_key_code c)
+{
+	switch (c) {
+	case EDIT_KEY_ENTER:
+	case EDIT_KEY_CTRL_J:
+	case EDIT_KEY_LEFT:
+	case EDIT_KEY_RIGHT:
+	case EDIT_KEY_HOME:
+	case EDIT_KEY_END:
+	case EDIT_KEY_CTRL_A:
+	case EDIT_KEY_CTRL_E:
+		search_stop();
+		return c;
+	case EDIT_KEY_DOWN:
+	case EDIT_KEY_UP:
+		search_cancel();
+		return EDIT_KEY_EOF;
+	case EDIT_KEY_CTRL_H:
+	case EDIT_KEY_BACKSPACE:
+		search_backspace();
+		break;
+	case EDIT_KEY_CTRL_R:
+		search_next();
+		break;
+	default:
+		if (c >= 32 && c <= 255)
+			search_char(c);
+		break;
+	}
+
+	return EDIT_KEY_NONE;
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	static int last_tab = 0;
+	static int search = 0;
+	enum edit_key_code c;
+
+	c = edit_read_key(sock);
+
+	if (search) {
+		c = search_key(c);
+		if (c == EDIT_KEY_NONE)
+			return;
+		search = 0;
+		if (c == EDIT_KEY_EOF)
+			return;
+	}
+
+	if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
+		last_tab = 0;
+
+	switch (c) {
+	case EDIT_KEY_NONE:
+		break;
+	case EDIT_KEY_EOF:
+		edit_eof_cb(edit_cb_ctx);
+		break;
+	case EDIT_KEY_TAB:
+		complete(last_tab);
+		last_tab = 1;
+		break;
+	case EDIT_KEY_UP:
+	case EDIT_KEY_CTRL_P:
+		history_prev();
+		break;
+	case EDIT_KEY_DOWN:
+	case EDIT_KEY_CTRL_N:
+		history_next();
+		break;
+	case EDIT_KEY_RIGHT:
+	case EDIT_KEY_CTRL_F:
+		move_right();
+		break;
+	case EDIT_KEY_LEFT:
+	case EDIT_KEY_CTRL_B:
+		move_left();
+		break;
+	case EDIT_KEY_CTRL_RIGHT:
+		move_word_right();
+		break;
+	case EDIT_KEY_CTRL_LEFT:
+		move_word_left();
+		break;
+	case EDIT_KEY_DELETE:
+		delete_current();
+		break;
+	case EDIT_KEY_END:
+		move_end();
+		break;
+	case EDIT_KEY_HOME:
+	case EDIT_KEY_CTRL_A:
+		move_start();
+		break;
+	case EDIT_KEY_F2:
+		history_debug_dump();
+		break;
+	case EDIT_KEY_CTRL_D:
+		if (cmdbuf_len > 0) {
+			delete_current();
+			return;
+		}
+		printf("\n");
+		edit_eof_cb(edit_cb_ctx);
+		break;
+	case EDIT_KEY_CTRL_E:
+		move_end();
+		break;
+	case EDIT_KEY_CTRL_H:
+	case EDIT_KEY_BACKSPACE:
+		delete_left();
+		break;
+	case EDIT_KEY_ENTER:
+	case EDIT_KEY_CTRL_J:
+		process_cmd();
+		break;
+	case EDIT_KEY_CTRL_K:
+		clear_right();
+		break;
+	case EDIT_KEY_CTRL_L:
+		edit_clear_line();
+		edit_redraw();
+		break;
+	case EDIT_KEY_CTRL_R:
+		search = 1;
+		search_start();
+		break;
+	case EDIT_KEY_CTRL_U:
+		clear_left();
+		break;
+	case EDIT_KEY_CTRL_W:
+		delete_word();
+		break;
+	default:
+		if (c >= 32 && c <= 255)
+			insert_char(c);
+		break;
+	}
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+	      void (*eof_cb)(void *ctx),
+	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+	      void *ctx, const char *history_file, const char *ps)
+{
+	currbuf[0] = '\0';
+	dl_list_init(&history_list);
+	history_curr = NULL;
+	if (history_file)
+		history_read(history_file);
+
+	edit_cb_ctx = ctx;
+	edit_cmd_cb = cmd_cb;
+	edit_eof_cb = eof_cb;
+	edit_completion_cb = completion_cb;
+
+	tcgetattr(STDIN_FILENO, &prevt);
+	newt = prevt;
+	newt.c_lflag &= ~(ICANON | ECHO);
+	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+
+	eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+	ps2 = ps;
+	printf("%s> ", ps2 ? ps2 : "");
+	fflush(stdout);
+
+	return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+		 int (*filter_cb)(void *ctx, const char *cmd))
+{
+	struct edit_history *h;
+	if (history_file)
+		history_write(history_file, filter_cb);
+	while ((h = dl_list_first(&history_list, struct edit_history, list))) {
+		dl_list_del(&h->list);
+		os_free(h);
+	}
+	edit_clear_line();
+	putchar('\r');
+	fflush(stdout);
+	eloop_unregister_read_sock(STDIN_FILENO);
+	tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
+}
+
+
+void edit_redraw(void)
+{
+	char tmp;
+	cmdbuf[cmdbuf_len] = '\0';
+	printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
+	if (cmdbuf_pos != cmdbuf_len) {
+		tmp = cmdbuf[cmdbuf_pos];
+		cmdbuf[cmdbuf_pos] = '\0';
+		printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
+		cmdbuf[cmdbuf_pos] = tmp;
+	}
+	fflush(stdout);
+}

Copied: vendor/wpa/2.0/src/utils/edit.h (from rev 9639, vendor/wpa/dist/src/utils/edit.h)
===================================================================
--- vendor/wpa/2.0/src/utils/edit.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/edit.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,21 @@
+/*
+ * Command line editing and history
+ * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EDIT_H
+#define EDIT_H
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+	      void (*eof_cb)(void *ctx),
+	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+	      void *ctx, const char *history_file, const char *ps);
+void edit_deinit(const char *history_file,
+		 int (*filter_cb)(void *ctx, const char *cmd));
+void edit_clear_line(void);
+void edit_redraw(void);
+
+#endif /* EDIT_H */

Copied: vendor/wpa/2.0/src/utils/edit_readline.c (from rev 9639, vendor/wpa/dist/src/utils/edit_readline.c)
===================================================================
--- vendor/wpa/2.0/src/utils/edit_readline.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/edit_readline.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,192 @@
+/*
+ * Command line editing and history wrapper for readline
+ * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+	NULL;
+
+static char **pending_completions = NULL;
+
+
+static void readline_free_completions(void)
+{
+	int i;
+	if (pending_completions == NULL)
+		return;
+	for (i = 0; pending_completions[i]; i++)
+		os_free(pending_completions[i]);
+	os_free(pending_completions);
+	pending_completions = NULL;
+}
+
+
+static char * readline_completion_func(const char *text, int state)
+{
+	static int pos = 0;
+	static size_t len = 0;
+
+	if (pending_completions == NULL) {
+		rl_attempted_completion_over = 1;
+		return NULL;
+	}
+
+	if (state == 0) {
+		pos = 0;
+		len = os_strlen(text);
+	}
+	for (; pending_completions[pos]; pos++) {
+		if (strncmp(pending_completions[pos], text, len) == 0)
+			return strdup(pending_completions[pos++]);
+	}
+
+	rl_attempted_completion_over = 1;
+	return NULL;
+}
+
+
+static char ** readline_completion(const char *text, int start, int end)
+{
+	readline_free_completions();
+	if (edit_completion_cb)
+		pending_completions = edit_completion_cb(edit_cb_ctx,
+							 rl_line_buffer, end);
+	return rl_completion_matches(text, readline_completion_func);
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	rl_callback_read_char();
+}
+
+
+static void trunc_nl(char *str)
+{
+	char *pos = str;
+	while (*pos != '\0') {
+		if (*pos == '\n') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+}
+
+
+static void readline_cmd_handler(char *cmd)
+{
+	if (cmd && *cmd) {
+		HIST_ENTRY *h;
+		while (next_history())
+			;
+		h = previous_history();
+		if (h == NULL || os_strcmp(cmd, h->line) != 0)
+			add_history(cmd);
+		next_history();
+	}
+	if (cmd == NULL) {
+		edit_eof_cb(edit_cb_ctx);
+		return;
+	}
+	trunc_nl(cmd);
+	edit_cmd_cb(edit_cb_ctx, cmd);
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+	      void (*eof_cb)(void *ctx),
+	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+	      void *ctx, const char *history_file, const char *ps)
+{
+	edit_cb_ctx = ctx;
+	edit_cmd_cb = cmd_cb;
+	edit_eof_cb = eof_cb;
+	edit_completion_cb = completion_cb;
+
+	rl_attempted_completion_function = readline_completion;
+	if (history_file) {
+		read_history(history_file);
+		stifle_history(100);
+	}
+
+	eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+	if (ps) {
+		size_t blen = os_strlen(ps) + 3;
+		char *ps2 = os_malloc(blen);
+		if (ps2) {
+			os_snprintf(ps2, blen, "%s> ", ps);
+			rl_callback_handler_install(ps2, readline_cmd_handler);
+			os_free(ps2);
+			return 0;
+		}
+	}
+
+	rl_callback_handler_install("> ", readline_cmd_handler);
+
+	return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+		 int (*filter_cb)(void *ctx, const char *cmd))
+{
+	rl_set_prompt("");
+	rl_replace_line("", 0);
+	rl_redisplay();
+	rl_callback_handler_remove();
+	readline_free_completions();
+
+	eloop_unregister_read_sock(STDIN_FILENO);
+
+	if (history_file) {
+		/* Save command history, excluding lines that may contain
+		 * passwords. */
+		HIST_ENTRY *h;
+		history_set_pos(0);
+		while ((h = current_history())) {
+			char *p = h->line;
+			while (*p == ' ' || *p == '\t')
+				p++;
+			if (filter_cb && filter_cb(edit_cb_ctx, p)) {
+				h = remove_history(where_history());
+				if (h) {
+					os_free(h->line);
+					free(h->data);
+					os_free(h);
+				} else
+					next_history();
+			} else
+				next_history();
+		}
+		write_history(history_file);
+	}
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+	rl_on_new_line();
+	rl_redisplay();
+}

Copied: vendor/wpa/2.0/src/utils/edit_simple.c (from rev 9639, vendor/wpa/dist/src/utils/edit_simple.c)
===================================================================
--- vendor/wpa/2.0/src/utils/edit_simple.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/edit_simple.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,92 @@
+/*
+ * Minimal command line editing
+ * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+static const char *ps2 = NULL;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	int c;
+	unsigned char buf[1];
+	int res;
+
+	res = read(sock, buf, 1);
+	if (res < 0)
+		perror("read");
+	if (res <= 0) {
+		edit_eof_cb(edit_cb_ctx);
+		return;
+	}
+	c = buf[0];
+
+	if (c == '\r' || c == '\n') {
+		cmdbuf[cmdbuf_pos] = '\0';
+		cmdbuf_pos = 0;
+		edit_cmd_cb(edit_cb_ctx, cmdbuf);
+		printf("%s> ", ps2 ? ps2 : "");
+		fflush(stdout);
+		return;
+	}
+
+	if (c >= 32 && c <= 255) {
+		if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
+			cmdbuf[cmdbuf_pos++] = c;
+		}
+	}
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+	      void (*eof_cb)(void *ctx),
+	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+	      void *ctx, const char *history_file, const char *ps)
+{
+	edit_cb_ctx = ctx;
+	edit_cmd_cb = cmd_cb;
+	edit_eof_cb = eof_cb;
+	eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+	ps2 = ps;
+
+	printf("%s> ", ps2 ? ps2 : "");
+	fflush(stdout);
+
+	return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+		 int (*filter_cb)(void *ctx, const char *cmd))
+{
+	eloop_unregister_read_sock(STDIN_FILENO);
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+	cmdbuf[cmdbuf_pos] = '\0';
+	printf("\r> %s", cmdbuf);
+}

Deleted: vendor/wpa/2.0/src/utils/eloop.c
===================================================================
--- vendor/wpa/dist/src/utils/eloop.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/eloop.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,615 +0,0 @@
-/*
- * Event loop based on select() loop
- * Copyright (c) 2002-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "trace.h"
-#include "list.h"
-#include "eloop.h"
-
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	eloop_sock_handler handler;
-	WPA_TRACE_REF(eloop);
-	WPA_TRACE_REF(user);
-	WPA_TRACE_INFO
-};
-
-struct eloop_timeout {
-	struct dl_list list;
-	struct os_time time;
-	void *eloop_data;
-	void *user_data;
-	eloop_timeout_handler handler;
-	WPA_TRACE_REF(eloop);
-	WPA_TRACE_REF(user);
-	WPA_TRACE_INFO
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	eloop_signal_handler handler;
-	int signaled;
-};
-
-struct eloop_sock_table {
-	int count;
-	struct eloop_sock *table;
-	int changed;
-};
-
-struct eloop_data {
-	int max_sock;
-
-	struct eloop_sock_table readers;
-	struct eloop_sock_table writers;
-	struct eloop_sock_table exceptions;
-
-	struct dl_list timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-	int pending_terminate;
-
-	int terminate;
-	int reader_table_changed;
-};
-
-static struct eloop_data eloop;
-
-
-#ifdef WPA_TRACE
-
-static void eloop_sigsegv_handler(int sig)
-{
-	wpa_trace_show("eloop SIGSEGV");
-	abort();
-}
-
-static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
-{
-	int i;
-	if (table == NULL || table->table == NULL)
-		return;
-	for (i = 0; i < table->count; i++) {
-		wpa_trace_add_ref(&table->table[i], eloop,
-				  table->table[i].eloop_data);
-		wpa_trace_add_ref(&table->table[i], user,
-				  table->table[i].user_data);
-	}
-}
-
-
-static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
-{
-	int i;
-	if (table == NULL || table->table == NULL)
-		return;
-	for (i = 0; i < table->count; i++) {
-		wpa_trace_remove_ref(&table->table[i], eloop,
-				     table->table[i].eloop_data);
-		wpa_trace_remove_ref(&table->table[i], user,
-				     table->table[i].user_data);
-	}
-}
-
-#else /* WPA_TRACE */
-
-#define eloop_trace_sock_add_ref(table) do { } while (0)
-#define eloop_trace_sock_remove_ref(table) do { } while (0)
-
-#endif /* WPA_TRACE */
-
-
-int eloop_init(void)
-{
-	os_memset(&eloop, 0, sizeof(eloop));
-	dl_list_init(&eloop.timeout);
-#ifdef WPA_TRACE
-	signal(SIGSEGV, eloop_sigsegv_handler);
-#endif /* WPA_TRACE */
-	return 0;
-}
-
-
-static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
-                                     int sock, eloop_sock_handler handler,
-                                     void *eloop_data, void *user_data)
-{
-	struct eloop_sock *tmp;
-
-	if (table == NULL)
-		return -1;
-
-	eloop_trace_sock_remove_ref(table);
-	tmp = (struct eloop_sock *)
-		os_realloc(table->table,
-			   (table->count + 1) * sizeof(struct eloop_sock));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[table->count].sock = sock;
-	tmp[table->count].eloop_data = eloop_data;
-	tmp[table->count].user_data = user_data;
-	tmp[table->count].handler = handler;
-	wpa_trace_record(&tmp[table->count]);
-	table->count++;
-	table->table = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-	table->changed = 1;
-	eloop_trace_sock_add_ref(table);
-
-	return 0;
-}
-
-
-static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
-                                         int sock)
-{
-	int i;
-
-	if (table == NULL || table->table == NULL || table->count == 0)
-		return;
-
-	for (i = 0; i < table->count; i++) {
-		if (table->table[i].sock == sock)
-			break;
-	}
-	if (i == table->count)
-		return;
-	eloop_trace_sock_remove_ref(table);
-	if (i != table->count - 1) {
-		os_memmove(&table->table[i], &table->table[i + 1],
-			   (table->count - i - 1) *
-			   sizeof(struct eloop_sock));
-	}
-	table->count--;
-	table->changed = 1;
-	eloop_trace_sock_add_ref(table);
-}
-
-
-static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
-				     fd_set *fds)
-{
-	int i;
-
-	FD_ZERO(fds);
-
-	if (table->table == NULL)
-		return;
-
-	for (i = 0; i < table->count; i++)
-		FD_SET(table->table[i].sock, fds);
-}
-
-
-static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
-				      fd_set *fds)
-{
-	int i;
-
-	if (table == NULL || table->table == NULL)
-		return;
-
-	table->changed = 0;
-	for (i = 0; i < table->count; i++) {
-		if (FD_ISSET(table->table[i].sock, fds)) {
-			table->table[i].handler(table->table[i].sock,
-						table->table[i].eloop_data,
-						table->table[i].user_data);
-			if (table->changed)
-				break;
-		}
-	}
-}
-
-
-static void eloop_sock_table_destroy(struct eloop_sock_table *table)
-{
-	if (table) {
-		int i;
-		for (i = 0; i < table->count && table->table; i++) {
-			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
-				   "sock=%d eloop_data=%p user_data=%p "
-				   "handler=%p",
-				   table->table[i].sock,
-				   table->table[i].eloop_data,
-				   table->table[i].user_data,
-				   table->table[i].handler);
-			wpa_trace_dump_funcname("eloop unregistered socket "
-						"handler",
-						table->table[i].handler);
-			wpa_trace_dump("eloop sock", &table->table[i]);
-		}
-		os_free(table->table);
-	}
-}
-
-
-int eloop_register_read_sock(int sock, eloop_sock_handler handler,
-			     void *eloop_data, void *user_data)
-{
-	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
-				   eloop_data, user_data);
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
-	eloop_unregister_sock(sock, EVENT_TYPE_READ);
-}
-
-
-static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
-{
-	switch (type) {
-	case EVENT_TYPE_READ:
-		return &eloop.readers;
-	case EVENT_TYPE_WRITE:
-		return &eloop.writers;
-	case EVENT_TYPE_EXCEPTION:
-		return &eloop.exceptions;
-	}
-
-	return NULL;
-}
-
-
-int eloop_register_sock(int sock, eloop_event_type type,
-			eloop_sock_handler handler,
-			void *eloop_data, void *user_data)
-{
-	struct eloop_sock_table *table;
-
-	table = eloop_get_sock_table(type);
-	return eloop_sock_table_add_sock(table, sock, handler,
-					 eloop_data, user_data);
-}
-
-
-void eloop_unregister_sock(int sock, eloop_event_type type)
-{
-	struct eloop_sock_table *table;
-
-	table = eloop_get_sock_table(type);
-	eloop_sock_table_remove_sock(table, sock);
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   eloop_timeout_handler handler,
-			   void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp;
-
-	timeout = os_zalloc(sizeof(*timeout));
-	if (timeout == NULL)
-		return -1;
-	if (os_get_time(&timeout->time) < 0) {
-		os_free(timeout);
-		return -1;
-	}
-	timeout->time.sec += secs;
-	timeout->time.usec += usecs;
-	while (timeout->time.usec >= 1000000) {
-		timeout->time.sec++;
-		timeout->time.usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-	wpa_trace_add_ref(timeout, eloop, eloop_data);
-	wpa_trace_add_ref(timeout, user, user_data);
-	wpa_trace_record(timeout);
-
-	/* Maintain timeouts in order of increasing time */
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (os_time_before(&timeout->time, &tmp->time)) {
-			dl_list_add(tmp->list.prev, &timeout->list);
-			return 0;
-		}
-	}
-	dl_list_add_tail(&eloop.timeout, &timeout->list);
-
-	return 0;
-}
-
-
-static void eloop_remove_timeout(struct eloop_timeout *timeout)
-{
-	dl_list_del(&timeout->list);
-	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
-	wpa_trace_remove_ref(timeout, user, timeout->user_data);
-	os_free(timeout);
-}
-
-
-int eloop_cancel_timeout(eloop_timeout_handler handler,
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev;
-	int removed = 0;
-
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		     eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		     user_data == ELOOP_ALL_CTX)) {
-			eloop_remove_timeout(timeout);
-			removed++;
-		}
-	}
-
-	return removed;
-}
-
-
-int eloop_is_timeout_registered(eloop_timeout_handler handler,
-				void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *tmp;
-
-	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
-		if (tmp->handler == handler &&
-		    tmp->eloop_data == eloop_data &&
-		    tmp->user_data == user_data)
-			return 1;
-	}
-
-	return 0;
-}
-
-
-#ifndef CONFIG_NATIVE_WINDOWS
-static void eloop_handle_alarm(int sig)
-{
-	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
-		   "two seconds. Looks like there\n"
-		   "is a bug that ends up in a busy loop that "
-		   "prevents clean shutdown.\n"
-		   "Killing program forcefully.\n");
-	exit(1);
-}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-#ifndef CONFIG_NATIVE_WINDOWS
-	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
-		/* Use SIGALRM to break out from potential busy loops that
-		 * would not allow the program to be killed. */
-		eloop.pending_terminate = 1;
-		signal(SIGALRM, eloop_handle_alarm);
-		alarm(2);
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	if (eloop.pending_terminate) {
-#ifndef CONFIG_NATIVE_WINDOWS
-		alarm(0);
-#endif /* CONFIG_NATIVE_WINDOWS */
-		eloop.pending_terminate = 0;
-	}
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.signals[i].user_data);
-		}
-	}
-}
-
-
-int eloop_register_signal(int sig, eloop_signal_handler handler,
-			  void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = (struct eloop_signal *)
-		os_realloc(eloop.signals,
-			   (eloop.signal_count + 1) *
-			   sizeof(struct eloop_signal));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-	signal(sig, eloop_handle_signal);
-
-	return 0;
-}
-
-
-int eloop_register_signal_terminate(eloop_signal_handler handler,
-				    void *user_data)
-{
-	int ret = eloop_register_signal(SIGINT, handler, user_data);
-	if (ret == 0)
-		ret = eloop_register_signal(SIGTERM, handler, user_data);
-	return ret;
-}
-
-
-int eloop_register_signal_reconfig(eloop_signal_handler handler,
-				   void *user_data)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
-	return 0;
-#else /* CONFIG_NATIVE_WINDOWS */
-	return eloop_register_signal(SIGHUP, handler, user_data);
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-void eloop_run(void)
-{
-	fd_set *rfds, *wfds, *efds;
-	int res;
-	struct timeval _tv;
-	struct os_time tv, now;
-
-	rfds = os_malloc(sizeof(*rfds));
-	wfds = os_malloc(sizeof(*wfds));
-	efds = os_malloc(sizeof(*efds));
-	if (rfds == NULL || wfds == NULL || efds == NULL)
-		goto out;
-
-	while (!eloop.terminate &&
-	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
-		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
-		struct eloop_timeout *timeout;
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &timeout->time))
-				os_time_sub(&timeout->time, &now, &tv);
-			else
-				tv.sec = tv.usec = 0;
-			_tv.tv_sec = tv.sec;
-			_tv.tv_usec = tv.usec;
-		}
-
-		eloop_sock_table_set_fds(&eloop.readers, rfds);
-		eloop_sock_table_set_fds(&eloop.writers, wfds);
-		eloop_sock_table_set_fds(&eloop.exceptions, efds);
-		res = select(eloop.max_sock + 1, rfds, wfds, efds,
-			     timeout ? &_tv : NULL);
-		if (res < 0 && errno != EINTR && errno != 0) {
-			perror("select");
-			goto out;
-		}
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
-					list);
-		if (timeout) {
-			os_get_time(&now);
-			if (!os_time_before(&now, &timeout->time)) {
-				void *eloop_data = timeout->eloop_data;
-				void *user_data = timeout->user_data;
-				eloop_timeout_handler handler =
-					timeout->handler;
-				eloop_remove_timeout(timeout);
-				handler(eloop_data, user_data);
-			}
-
-		}
-
-		if (res <= 0)
-			continue;
-
-		eloop_sock_table_dispatch(&eloop.readers, rfds);
-		eloop_sock_table_dispatch(&eloop.writers, wfds);
-		eloop_sock_table_dispatch(&eloop.exceptions, efds);
-	}
-
-out:
-	os_free(rfds);
-	os_free(wfds);
-	os_free(efds);
-}
-
-
-void eloop_terminate(void)
-{
-	eloop.terminate = 1;
-}
-
-
-void eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-	struct os_time now;
-
-	os_get_time(&now);
-	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
-			      struct eloop_timeout, list) {
-		int sec, usec;
-		sec = timeout->time.sec - now.sec;
-		usec = timeout->time.usec - now.usec;
-		if (timeout->time.usec < now.usec) {
-			sec--;
-			usec += 1000000;
-		}
-		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
-			   "eloop_data=%p user_data=%p handler=%p",
-			   sec, usec, timeout->eloop_data, timeout->user_data,
-			   timeout->handler);
-		wpa_trace_dump_funcname("eloop unregistered timeout handler",
-					timeout->handler);
-		wpa_trace_dump("eloop timeout", timeout);
-		eloop_remove_timeout(timeout);
-	}
-	eloop_sock_table_destroy(&eloop.readers);
-	eloop_sock_table_destroy(&eloop.writers);
-	eloop_sock_table_destroy(&eloop.exceptions);
-	os_free(eloop.signals);
-}
-
-
-int eloop_terminated(void)
-{
-	return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
-	fd_set rfds;
-
-	if (sock < 0)
-		return;
-
-	FD_ZERO(&rfds);
-	FD_SET(sock, &rfds);
-	select(sock + 1, &rfds, NULL, NULL, NULL);
-}

Copied: vendor/wpa/2.0/src/utils/eloop.c (from rev 9639, vendor/wpa/dist/src/utils/eloop.c)
===================================================================
--- vendor/wpa/2.0/src/utils/eloop.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/eloop.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,856 @@
+/*
+ * Event loop based on select() loop
+ * Copyright (c) 2002-2009, Jouni Malinen <j at 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 "trace.h"
+#include "list.h"
+#include "eloop.h"
+
+#ifdef CONFIG_ELOOP_POLL
+#include <assert.h>
+#include <poll.h>
+#endif /* CONFIG_ELOOP_POLL */
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	eloop_sock_handler handler;
+	WPA_TRACE_REF(eloop);
+	WPA_TRACE_REF(user);
+	WPA_TRACE_INFO
+};
+
+struct eloop_timeout {
+	struct dl_list list;
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	eloop_timeout_handler handler;
+	WPA_TRACE_REF(eloop);
+	WPA_TRACE_REF(user);
+	WPA_TRACE_INFO
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	eloop_signal_handler handler;
+	int signaled;
+};
+
+struct eloop_sock_table {
+	int count;
+	struct eloop_sock *table;
+	int changed;
+};
+
+struct eloop_data {
+	int max_sock;
+
+	int count; /* sum of all table counts */
+#ifdef CONFIG_ELOOP_POLL
+	int max_pollfd_map; /* number of pollfds_map currently allocated */
+	int max_poll_fds; /* number of pollfds currently allocated */
+	struct pollfd *pollfds;
+	struct pollfd **pollfds_map;
+#endif /* CONFIG_ELOOP_POLL */
+	struct eloop_sock_table readers;
+	struct eloop_sock_table writers;
+	struct eloop_sock_table exceptions;
+
+	struct dl_list timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+#ifdef WPA_TRACE
+
+static void eloop_sigsegv_handler(int sig)
+{
+	wpa_trace_show("eloop SIGSEGV");
+	abort();
+}
+
+static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
+{
+	int i;
+	if (table == NULL || table->table == NULL)
+		return;
+	for (i = 0; i < table->count; i++) {
+		wpa_trace_add_ref(&table->table[i], eloop,
+				  table->table[i].eloop_data);
+		wpa_trace_add_ref(&table->table[i], user,
+				  table->table[i].user_data);
+	}
+}
+
+
+static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
+{
+	int i;
+	if (table == NULL || table->table == NULL)
+		return;
+	for (i = 0; i < table->count; i++) {
+		wpa_trace_remove_ref(&table->table[i], eloop,
+				     table->table[i].eloop_data);
+		wpa_trace_remove_ref(&table->table[i], user,
+				     table->table[i].user_data);
+	}
+}
+
+#else /* WPA_TRACE */
+
+#define eloop_trace_sock_add_ref(table) do { } while (0)
+#define eloop_trace_sock_remove_ref(table) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+int eloop_init(void)
+{
+	os_memset(&eloop, 0, sizeof(eloop));
+	dl_list_init(&eloop.timeout);
+#ifdef WPA_TRACE
+	signal(SIGSEGV, eloop_sigsegv_handler);
+#endif /* WPA_TRACE */
+	return 0;
+}
+
+
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+                                     int sock, eloop_sock_handler handler,
+                                     void *eloop_data, void *user_data)
+{
+	struct eloop_sock *tmp;
+	int new_max_sock;
+
+	if (sock > eloop.max_sock)
+		new_max_sock = sock;
+	else
+		new_max_sock = eloop.max_sock;
+
+	if (table == NULL)
+		return -1;
+
+#ifdef CONFIG_ELOOP_POLL
+	if (new_max_sock >= eloop.max_pollfd_map) {
+		struct pollfd **nmap;
+		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
+					sizeof(struct pollfd *));
+		if (nmap == NULL)
+			return -1;
+
+		eloop.max_pollfd_map = new_max_sock + 50;
+		eloop.pollfds_map = nmap;
+	}
+
+	if (eloop.count + 1 > eloop.max_poll_fds) {
+		struct pollfd *n;
+		int nmax = eloop.count + 1 + 50;
+		n = os_realloc_array(eloop.pollfds, nmax,
+				     sizeof(struct pollfd));
+		if (n == NULL)
+			return -1;
+
+		eloop.max_poll_fds = nmax;
+		eloop.pollfds = n;
+	}
+#endif /* CONFIG_ELOOP_POLL */
+
+	eloop_trace_sock_remove_ref(table);
+	tmp = os_realloc_array(table->table, table->count + 1,
+			       sizeof(struct eloop_sock));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[table->count].sock = sock;
+	tmp[table->count].eloop_data = eloop_data;
+	tmp[table->count].user_data = user_data;
+	tmp[table->count].handler = handler;
+	wpa_trace_record(&tmp[table->count]);
+	table->count++;
+	table->table = tmp;
+	eloop.max_sock = new_max_sock;
+	eloop.count++;
+	table->changed = 1;
+	eloop_trace_sock_add_ref(table);
+
+	return 0;
+}
+
+
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+                                         int sock)
+{
+	int i;
+
+	if (table == NULL || table->table == NULL || table->count == 0)
+		return;
+
+	for (i = 0; i < table->count; i++) {
+		if (table->table[i].sock == sock)
+			break;
+	}
+	if (i == table->count)
+		return;
+	eloop_trace_sock_remove_ref(table);
+	if (i != table->count - 1) {
+		os_memmove(&table->table[i], &table->table[i + 1],
+			   (table->count - i - 1) *
+			   sizeof(struct eloop_sock));
+	}
+	table->count--;
+	eloop.count--;
+	table->changed = 1;
+	eloop_trace_sock_add_ref(table);
+}
+
+
+#ifdef CONFIG_ELOOP_POLL
+
+static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
+{
+	if (fd < mx && fd >= 0)
+		return pollfds_map[fd];
+	return NULL;
+}
+
+
+static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
+				    struct eloop_sock_table *writers,
+				    struct eloop_sock_table *exceptions,
+				    struct pollfd *pollfds,
+				    struct pollfd **pollfds_map,
+				    int max_pollfd_map)
+{
+	int i;
+	int nxt = 0;
+	int fd;
+	struct pollfd *pfd;
+
+	/* Clear pollfd lookup map. It will be re-populated below. */
+	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
+
+	if (readers && readers->table) {
+		for (i = 0; i < readers->count; i++) {
+			fd = readers->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pollfds[nxt].fd = fd;
+			pollfds[nxt].events = POLLIN;
+			pollfds[nxt].revents = 0;
+			pollfds_map[fd] = &(pollfds[nxt]);
+			nxt++;
+		}
+	}
+
+	if (writers && writers->table) {
+		for (i = 0; i < writers->count; i++) {
+			/*
+			 * See if we already added this descriptor, update it
+			 * if so.
+			 */
+			fd = writers->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pfd = pollfds_map[fd];
+			if (!pfd) {
+				pfd = &(pollfds[nxt]);
+				pfd->events = 0;
+				pfd->fd = fd;
+				pollfds[i].revents = 0;
+				pollfds_map[fd] = pfd;
+				nxt++;
+			}
+			pfd->events |= POLLOUT;
+		}
+	}
+
+	/*
+	 * Exceptions are always checked when using poll, but I suppose it's
+	 * possible that someone registered a socket *only* for exception
+	 * handling. Set the POLLIN bit in this case.
+	 */
+	if (exceptions && exceptions->table) {
+		for (i = 0; i < exceptions->count; i++) {
+			/*
+			 * See if we already added this descriptor, just use it
+			 * if so.
+			 */
+			fd = exceptions->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pfd = pollfds_map[fd];
+			if (!pfd) {
+				pfd = &(pollfds[nxt]);
+				pfd->events = POLLIN;
+				pfd->fd = fd;
+				pollfds[i].revents = 0;
+				pollfds_map[fd] = pfd;
+				nxt++;
+			}
+		}
+	}
+
+	return nxt;
+}
+
+
+static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
+					   struct pollfd **pollfds_map,
+					   int max_pollfd_map,
+					   short int revents)
+{
+	int i;
+	struct pollfd *pfd;
+
+	if (!table || !table->table)
+		return 0;
+
+	table->changed = 0;
+	for (i = 0; i < table->count; i++) {
+		pfd = find_pollfd(pollfds_map, table->table[i].sock,
+				  max_pollfd_map);
+		if (!pfd)
+			continue;
+
+		if (!(pfd->revents & revents))
+			continue;
+
+		table->table[i].handler(table->table[i].sock,
+					table->table[i].eloop_data,
+					table->table[i].user_data);
+		if (table->changed)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
+				      struct eloop_sock_table *writers,
+				      struct eloop_sock_table *exceptions,
+				      struct pollfd **pollfds_map,
+				      int max_pollfd_map)
+{
+	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
+					    max_pollfd_map, POLLIN | POLLERR |
+					    POLLHUP))
+		return; /* pollfds may be invalid at this point */
+
+	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
+					    max_pollfd_map, POLLOUT))
+		return; /* pollfds may be invalid at this point */
+
+	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
+					max_pollfd_map, POLLERR | POLLHUP);
+}
+
+#else /* CONFIG_ELOOP_POLL */
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+				     fd_set *fds)
+{
+	int i;
+
+	FD_ZERO(fds);
+
+	if (table->table == NULL)
+		return;
+
+	for (i = 0; i < table->count; i++)
+		FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+				      fd_set *fds)
+{
+	int i;
+
+	if (table == NULL || table->table == NULL)
+		return;
+
+	table->changed = 0;
+	for (i = 0; i < table->count; i++) {
+		if (FD_ISSET(table->table[i].sock, fds)) {
+			table->table[i].handler(table->table[i].sock,
+						table->table[i].eloop_data,
+						table->table[i].user_data);
+			if (table->changed)
+				break;
+		}
+	}
+}
+
+#endif /* CONFIG_ELOOP_POLL */
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+	if (table) {
+		int i;
+		for (i = 0; i < table->count && table->table; i++) {
+			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
+				   "sock=%d eloop_data=%p user_data=%p "
+				   "handler=%p",
+				   table->table[i].sock,
+				   table->table[i].eloop_data,
+				   table->table[i].user_data,
+				   table->table[i].handler);
+			wpa_trace_dump_funcname("eloop unregistered socket "
+						"handler",
+						table->table[i].handler);
+			wpa_trace_dump("eloop sock", &table->table[i]);
+		}
+		os_free(table->table);
+	}
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data)
+{
+	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+				   eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+	switch (type) {
+	case EVENT_TYPE_READ:
+		return &eloop.readers;
+	case EVENT_TYPE_WRITE:
+		return &eloop.writers;
+	case EVENT_TYPE_EXCEPTION:
+		return &eloop.exceptions;
+	}
+
+	return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+			eloop_sock_handler handler,
+			void *eloop_data, void *user_data)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	return eloop_sock_table_add_sock(table, sock, handler,
+					 eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	eloop_sock_table_remove_sock(table, sock);
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   eloop_timeout_handler handler,
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp;
+	os_time_t now_sec;
+
+	timeout = os_zalloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	if (os_get_time(&timeout->time) < 0) {
+		os_free(timeout);
+		return -1;
+	}
+	now_sec = timeout->time.sec;
+	timeout->time.sec += secs;
+	if (timeout->time.sec < now_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+			   "ever happen - ignore it", secs);
+		os_free(timeout);
+		return 0;
+	}
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	wpa_trace_add_ref(timeout, eloop, eloop_data);
+	wpa_trace_add_ref(timeout, user, user_data);
+	wpa_trace_record(timeout);
+
+	/* Maintain timeouts in order of increasing time */
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (os_time_before(&timeout->time, &tmp->time)) {
+			dl_list_add(tmp->list.prev, &timeout->list);
+			return 0;
+		}
+	}
+	dl_list_add_tail(&eloop.timeout, &timeout->list);
+
+	return 0;
+}
+
+
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+	dl_list_del(&timeout->list);
+	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
+	wpa_trace_remove_ref(timeout, user, timeout->user_data);
+	os_free(timeout);
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev;
+	int removed = 0;
+
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			eloop_remove_timeout(timeout);
+			removed++;
+		}
+	}
+
+	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(int sig)
+{
+	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
+		   "two seconds. Looks like there\n"
+		   "is a bug that ends up in a busy loop that "
+		   "prevents clean shutdown.\n"
+		   "Killing program forcefully.\n");
+	exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+		/* Use SIGALRM to break out from potential busy loops that
+		 * would not allow the program to be killed. */
+		eloop.pending_terminate = 1;
+		signal(SIGALRM, eloop_handle_alarm);
+		alarm(2);
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+		alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.signals[i].user_data);
+		}
+	}
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+			       sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+	signal(sig, eloop_handle_signal);
+
+	return 0;
+}
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data)
+{
+	int ret = eloop_register_signal(SIGINT, handler, user_data);
+	if (ret == 0)
+		ret = eloop_register_signal(SIGTERM, handler, user_data);
+	return ret;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+	return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+#ifdef CONFIG_ELOOP_POLL
+	int num_poll_fds;
+	int timeout_ms = 0;
+#else /* CONFIG_ELOOP_POLL */
+	fd_set *rfds, *wfds, *efds;
+	struct timeval _tv;
+#endif /* CONFIG_ELOOP_POLL */
+	int res;
+	struct os_time tv, now;
+
+#ifndef CONFIG_ELOOP_POLL
+	rfds = os_malloc(sizeof(*rfds));
+	wfds = os_malloc(sizeof(*wfds));
+	efds = os_malloc(sizeof(*efds));
+	if (rfds == NULL || wfds == NULL || efds == NULL)
+		goto out;
+#endif /* CONFIG_ELOOP_POLL */
+
+	while (!eloop.terminate &&
+	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
+		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
+		struct eloop_timeout *timeout;
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
+			os_get_time(&now);
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, &tv);
+			else
+				tv.sec = tv.usec = 0;
+#ifdef CONFIG_ELOOP_POLL
+			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+#else /* CONFIG_ELOOP_POLL */
+			_tv.tv_sec = tv.sec;
+			_tv.tv_usec = tv.usec;
+#endif /* CONFIG_ELOOP_POLL */
+		}
+
+#ifdef CONFIG_ELOOP_POLL
+		num_poll_fds = eloop_sock_table_set_fds(
+			&eloop.readers, &eloop.writers, &eloop.exceptions,
+			eloop.pollfds, eloop.pollfds_map,
+			eloop.max_pollfd_map);
+		res = poll(eloop.pollfds, num_poll_fds,
+			   timeout ? timeout_ms : -1);
+
+		if (res < 0 && errno != EINTR && errno != 0) {
+			perror("poll");
+			goto out;
+		}
+#else /* CONFIG_ELOOP_POLL */
+		eloop_sock_table_set_fds(&eloop.readers, rfds);
+		eloop_sock_table_set_fds(&eloop.writers, wfds);
+		eloop_sock_table_set_fds(&eloop.exceptions, efds);
+		res = select(eloop.max_sock + 1, rfds, wfds, efds,
+			     timeout ? &_tv : NULL);
+		if (res < 0 && errno != EINTR && errno != 0) {
+			perror("select");
+			goto out;
+		}
+#endif /* CONFIG_ELOOP_POLL */
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
+			os_get_time(&now);
+			if (!os_time_before(&now, &timeout->time)) {
+				void *eloop_data = timeout->eloop_data;
+				void *user_data = timeout->user_data;
+				eloop_timeout_handler handler =
+					timeout->handler;
+				eloop_remove_timeout(timeout);
+				handler(eloop_data, user_data);
+			}
+
+		}
+
+		if (res <= 0)
+			continue;
+
+#ifdef CONFIG_ELOOP_POLL
+		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
+					  &eloop.exceptions, eloop.pollfds_map,
+					  eloop.max_pollfd_map);
+#else /* CONFIG_ELOOP_POLL */
+		eloop_sock_table_dispatch(&eloop.readers, rfds);
+		eloop_sock_table_dispatch(&eloop.writers, wfds);
+		eloop_sock_table_dispatch(&eloop.exceptions, efds);
+#endif /* CONFIG_ELOOP_POLL */
+	}
+
+out:
+#ifndef CONFIG_ELOOP_POLL
+	os_free(rfds);
+	os_free(wfds);
+	os_free(efds);
+#endif /* CONFIG_ELOOP_POLL */
+	return;
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+	struct os_time now;
+
+	os_get_time(&now);
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		int sec, usec;
+		sec = timeout->time.sec - now.sec;
+		usec = timeout->time.usec - now.usec;
+		if (timeout->time.usec < now.usec) {
+			sec--;
+			usec += 1000000;
+		}
+		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
+			   "eloop_data=%p user_data=%p handler=%p",
+			   sec, usec, timeout->eloop_data, timeout->user_data,
+			   timeout->handler);
+		wpa_trace_dump_funcname("eloop unregistered timeout handler",
+					timeout->handler);
+		wpa_trace_dump("eloop timeout", timeout);
+		eloop_remove_timeout(timeout);
+	}
+	eloop_sock_table_destroy(&eloop.readers);
+	eloop_sock_table_destroy(&eloop.writers);
+	eloop_sock_table_destroy(&eloop.exceptions);
+	os_free(eloop.signals);
+
+#ifdef CONFIG_ELOOP_POLL
+	os_free(eloop.pollfds);
+	os_free(eloop.pollfds_map);
+#endif /* CONFIG_ELOOP_POLL */
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+#ifdef CONFIG_ELOOP_POLL
+	struct pollfd pfd;
+
+	if (sock < 0)
+		return;
+
+	os_memset(&pfd, 0, sizeof(pfd));
+	pfd.fd = sock;
+	pfd.events = POLLIN;
+
+	poll(&pfd, 1, -1);
+#else /* CONFIG_ELOOP_POLL */
+	fd_set rfds;
+
+	if (sock < 0)
+		return;
+
+	FD_ZERO(&rfds);
+	FD_SET(sock, &rfds);
+	select(sock + 1, &rfds, NULL, NULL, NULL);
+#endif /* CONFIG_ELOOP_POLL */
+}

Deleted: vendor/wpa/2.0/src/utils/eloop.h
===================================================================
--- vendor/wpa/dist/src/utils/eloop.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/eloop.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,316 +0,0 @@
-/*
- * Event loop
- * Copyright (c) 2002-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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
-
-/**
- * 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 targetted 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_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_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_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);
-
-#endif /* ELOOP_H */

Copied: vendor/wpa/2.0/src/utils/eloop.h (from rev 9639, vendor/wpa/dist/src/utils/eloop.h)
===================================================================
--- vendor/wpa/2.0/src/utils/eloop.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/eloop.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,310 @@
+/*
+ * Event loop
+ * Copyright (c) 2002-2006, Jouni Malinen <j at 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
+
+/**
+ * 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_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_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_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);
+
+#endif /* ELOOP_H */

Deleted: vendor/wpa/2.0/src/utils/eloop_none.c
===================================================================
--- vendor/wpa/dist/src/utils/eloop_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/eloop_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,401 +0,0 @@
-/*
- * Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
-};
-
-struct eloop_timeout {
-	struct os_time time;
-	void *eloop_data;
-	void *user_data;
-	void (*handler)(void *eloop_ctx, void *sock_ctx);
-	struct eloop_timeout *next;
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
-	int signaled;
-};
-
-struct eloop_data {
-	int max_sock, reader_count;
-	struct eloop_sock *readers;
-
-	struct eloop_timeout *timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-	int pending_terminate;
-
-	int terminate;
-	int reader_table_changed;
-};
-
-static struct eloop_data eloop;
-
-
-int eloop_init(void)
-{
-	memset(&eloop, 0, sizeof(eloop));
-	return 0;
-}
-
-
-int eloop_register_read_sock(int sock,
-			     void (*handler)(int sock, void *eloop_ctx,
-					     void *sock_ctx),
-			     void *eloop_data, void *user_data)
-{
-	struct eloop_sock *tmp;
-
-	tmp = (struct eloop_sock *)
-		realloc(eloop.readers,
-			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	eloop.reader_count++;
-	eloop.readers = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-	eloop.reader_table_changed = 1;
-
-	return 0;
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
-	int i;
-
-	if (eloop.readers == NULL || eloop.reader_count == 0)
-		return;
-
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
-			break;
-	}
-	if (i == eloop.reader_count)
-		return;
-	if (i != eloop.reader_count - 1) {
-		memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			(eloop.reader_count - i - 1) *
-			sizeof(struct eloop_sock));
-	}
-	eloop.reader_count--;
-	eloop.reader_table_changed = 1;
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
-			   void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp, *prev;
-
-	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
-	if (timeout == NULL)
-		return -1;
-	os_get_time(&timeout->time);
-	timeout->time.sec += secs;
-	timeout->time.usec += usecs;
-	while (timeout->time.usec >= 1000000) {
-		timeout->time.sec++;
-		timeout->time.usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-	timeout->next = NULL;
-
-	if (eloop.timeout == NULL) {
-		eloop.timeout = timeout;
-		return 0;
-	}
-
-	prev = NULL;
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (os_time_before(&timeout->time, &tmp->time))
-			break;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-
-	if (prev == NULL) {
-		timeout->next = eloop.timeout;
-		eloop.timeout = timeout;
-	} else {
-		timeout->next = prev->next;
-		prev->next = timeout;
-	}
-
-	return 0;
-}
-
-
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev, *next;
-	int removed = 0;
-
-	prev = NULL;
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		next = timeout->next;
-
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		     eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		     user_data == ELOOP_ALL_CTX)) {
-			if (prev == NULL)
-				eloop.timeout = next;
-			else
-				prev->next = next;
-			free(timeout);
-			removed++;
-		} else
-			prev = timeout;
-
-		timeout = next;
-	}
-
-	return removed;
-}
-
-
-int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
-						void *timeout_ctx),
-				void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *tmp;
-
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (tmp->handler == handler &&
-		    tmp->eloop_data == eloop_data &&
-		    tmp->user_data == user_data)
-			return 1;
-
-		tmp = tmp->next;
-	}
-
-	return 0;
-}
-
-
-/* TODO: replace with suitable signal handler */
-#if 0
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-#endif
-
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	if (eloop.pending_terminate) {
-		eloop.pending_terminate = 0;
-	}
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.user_data,
-						 eloop.signals[i].user_data);
-		}
-	}
-}
-
-
-int eloop_register_signal(int sig,
-			  void (*handler)(int sig, void *eloop_ctx,
-					  void *signal_ctx),
-			  void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = (struct eloop_signal *)
-		realloc(eloop.signals,
-			(eloop.signal_count + 1) *
-			sizeof(struct eloop_signal));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-
-	/* TODO: register signal handler */
-
-	return 0;
-}
-
-
-int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
-						    void *signal_ctx),
-				    void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	int ret = eloop_register_signal(SIGINT, handler, user_data);
-	if (ret == 0)
-		ret = eloop_register_signal(SIGTERM, handler, user_data);
-	return ret;
-#endif
-	return 0;
-}
-
-
-int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
-						   void *signal_ctx),
-				   void *user_data)
-{
-#if 0
-	/* TODO: for example */
-	return eloop_register_signal(SIGHUP, handler, user_data);
-#endif
-	return 0;
-}
-
-
-void eloop_run(void)
-{
-	int i;
-	struct os_time tv, now;
-
-	while (!eloop.terminate &&
-		(eloop.timeout || eloop.reader_count > 0)) {
-		if (eloop.timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &eloop.timeout->time))
-				os_time_sub(&eloop.timeout->time, &now, &tv);
-			else
-				tv.sec = tv.usec = 0;
-		}
-
-		/*
-		 * TODO: wait for any event (read socket ready, timeout (tv),
-		 * signal
-		 */
-		os_sleep(1, 0); /* just a dummy wait for testing */
-
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		if (eloop.timeout) {
-			struct eloop_timeout *tmp;
-
-			os_get_time(&now);
-			if (!os_time_before(&now, &eloop.timeout->time)) {
-				tmp = eloop.timeout;
-				eloop.timeout = eloop.timeout->next;
-				tmp->handler(tmp->eloop_data,
-					     tmp->user_data);
-				free(tmp);
-			}
-
-		}
-
-		eloop.reader_table_changed = 0;
-		for (i = 0; i < eloop.reader_count; i++) {
-			/*
-			 * TODO: call each handler that has pending data to
-			 * read
-			 */
-			if (0 /* TODO: eloop.readers[i].sock ready */) {
-				eloop.readers[i].handler(
-					eloop.readers[i].sock,
-					eloop.readers[i].eloop_data,
-					eloop.readers[i].user_data);
-				if (eloop.reader_table_changed)
-					break;
-			}
-		}
-	}
-}
-
-
-void eloop_terminate(void)
-{
-	eloop.terminate = 1;
-}
-
-
-void eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		prev = timeout;
-		timeout = timeout->next;
-		free(prev);
-	}
-	free(eloop.readers);
-	free(eloop.signals);
-}
-
-
-int eloop_terminated(void)
-{
-	return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
-	/*
-	 * TODO: wait for the file descriptor to have something available for
-	 * reading
-	 */
-}

Copied: vendor/wpa/2.0/src/utils/eloop_none.c (from rev 9639, vendor/wpa/dist/src/utils/eloop_none.c)
===================================================================
--- vendor/wpa/2.0/src/utils/eloop_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/eloop_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,395 @@
+/*
+ * Event loop - empty template (basic structure, but no OS specific operations)
+ * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(void *eloop_ctx, void *sock_ctx);
+	struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+	int signaled;
+};
+
+struct eloop_data {
+	int max_sock, reader_count;
+	struct eloop_sock *readers;
+
+	struct eloop_timeout *timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void)
+{
+	memset(&eloop, 0, sizeof(eloop));
+	return 0;
+}
+
+
+int eloop_register_read_sock(int sock,
+			     void (*handler)(int sock, void *eloop_ctx,
+					     void *sock_ctx),
+			     void *eloop_data, void *user_data)
+{
+	struct eloop_sock *tmp;
+
+	tmp = (struct eloop_sock *)
+		realloc(eloop.readers,
+			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.reader_count].sock = sock;
+	tmp[eloop.reader_count].eloop_data = eloop_data;
+	tmp[eloop.reader_count].user_data = user_data;
+	tmp[eloop.reader_count].handler = handler;
+	eloop.reader_count++;
+	eloop.readers = tmp;
+	if (sock > eloop.max_sock)
+		eloop.max_sock = sock;
+	eloop.reader_table_changed = 1;
+
+	return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	int i;
+
+	if (eloop.readers == NULL || eloop.reader_count == 0)
+		return;
+
+	for (i = 0; i < eloop.reader_count; i++) {
+		if (eloop.readers[i].sock == sock)
+			break;
+	}
+	if (i == eloop.reader_count)
+		return;
+	if (i != eloop.reader_count - 1) {
+		memmove(&eloop.readers[i], &eloop.readers[i + 1],
+			(eloop.reader_count - i - 1) *
+			sizeof(struct eloop_sock));
+	}
+	eloop.reader_count--;
+	eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp, *prev;
+
+	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	os_get_time(&timeout->time);
+	timeout->time.sec += secs;
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	timeout->next = NULL;
+
+	if (eloop.timeout == NULL) {
+		eloop.timeout = timeout;
+		return 0;
+	}
+
+	prev = NULL;
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (os_time_before(&timeout->time, &tmp->time))
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (prev == NULL) {
+		timeout->next = eloop.timeout;
+		eloop.timeout = timeout;
+	} else {
+		timeout->next = prev->next;
+		prev->next = timeout;
+	}
+
+	return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev, *next;
+	int removed = 0;
+
+	prev = NULL;
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		next = timeout->next;
+
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			if (prev == NULL)
+				eloop.timeout = next;
+			else
+				prev->next = next;
+			free(timeout);
+			removed++;
+		} else
+			prev = timeout;
+
+		timeout = next;
+	}
+
+	return removed;
+}
+
+
+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
+						void *timeout_ctx),
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+
+		tmp = tmp->next;
+	}
+
+	return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.user_data,
+						 eloop.signals[i].user_data);
+		}
+	}
+}
+
+
+int eloop_register_signal(int sig,
+			  void (*handler)(int sig, void *eloop_ctx,
+					  void *signal_ctx),
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = (struct eloop_signal *)
+		realloc(eloop.signals,
+			(eloop.signal_count + 1) *
+			sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+
+	/* TODO: register signal handler */
+
+	return 0;
+}
+
+
+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
+						    void *signal_ctx),
+				    void *user_data)
+{
+#if 0
+	/* TODO: for example */
+	int ret = eloop_register_signal(SIGINT, handler, user_data);
+	if (ret == 0)
+		ret = eloop_register_signal(SIGTERM, handler, user_data);
+	return ret;
+#endif
+	return 0;
+}
+
+
+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
+						   void *signal_ctx),
+				   void *user_data)
+{
+#if 0
+	/* TODO: for example */
+	return eloop_register_signal(SIGHUP, handler, user_data);
+#endif
+	return 0;
+}
+
+
+void eloop_run(void)
+{
+	int i;
+	struct os_time tv, now;
+
+	while (!eloop.terminate &&
+		(eloop.timeout || eloop.reader_count > 0)) {
+		if (eloop.timeout) {
+			os_get_time(&now);
+			if (os_time_before(&now, &eloop.timeout->time))
+				os_time_sub(&eloop.timeout->time, &now, &tv);
+			else
+				tv.sec = tv.usec = 0;
+		}
+
+		/*
+		 * TODO: wait for any event (read socket ready, timeout (tv),
+		 * signal
+		 */
+		os_sleep(1, 0); /* just a dummy wait for testing */
+
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		if (eloop.timeout) {
+			struct eloop_timeout *tmp;
+
+			os_get_time(&now);
+			if (!os_time_before(&now, &eloop.timeout->time)) {
+				tmp = eloop.timeout;
+				eloop.timeout = eloop.timeout->next;
+				tmp->handler(tmp->eloop_data,
+					     tmp->user_data);
+				free(tmp);
+			}
+
+		}
+
+		eloop.reader_table_changed = 0;
+		for (i = 0; i < eloop.reader_count; i++) {
+			/*
+			 * TODO: call each handler that has pending data to
+			 * read
+			 */
+			if (0 /* TODO: eloop.readers[i].sock ready */) {
+				eloop.readers[i].handler(
+					eloop.readers[i].sock,
+					eloop.readers[i].eloop_data,
+					eloop.readers[i].user_data);
+				if (eloop.reader_table_changed)
+					break;
+			}
+		}
+	}
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		prev = timeout;
+		timeout = timeout->next;
+		free(prev);
+	}
+	free(eloop.readers);
+	free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+	/*
+	 * TODO: wait for the file descriptor to have something available for
+	 * reading
+	 */
+}

Deleted: vendor/wpa/2.0/src/utils/eloop_win.c
===================================================================
--- vendor/wpa/dist/src/utils/eloop_win.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/eloop_win.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,611 +0,0 @@
-/*
- * Event loop based on Windows events and WaitForMultipleObjects
- * Copyright (c) 2002-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <winsock2.h>
-
-#include "common.h"
-#include "eloop.h"
-
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	eloop_sock_handler handler;
-	WSAEVENT event;
-};
-
-struct eloop_event {
-	void *eloop_data;
-	void *user_data;
-	eloop_event_handler handler;
-	HANDLE event;
-};
-
-struct eloop_timeout {
-	struct os_time time;
-	void *eloop_data;
-	void *user_data;
-	eloop_timeout_handler handler;
-	struct eloop_timeout *next;
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	eloop_signal_handler handler;
-	int signaled;
-};
-
-struct eloop_data {
-	int max_sock;
-	size_t reader_count;
-	struct eloop_sock *readers;
-
-	size_t event_count;
-	struct eloop_event *events;
-
-	struct eloop_timeout *timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-	int pending_terminate;
-
-	int terminate;
-	int reader_table_changed;
-
-	struct eloop_signal term_signal;
-	HANDLE term_event;
-
-	HANDLE *handles;
-	size_t num_handles;
-};
-
-static struct eloop_data eloop;
-
-
-int eloop_init(void)
-{
-	os_memset(&eloop, 0, sizeof(eloop));
-	eloop.num_handles = 1;
-	eloop.handles = os_malloc(eloop.num_handles *
-				  sizeof(eloop.handles[0]));
-	if (eloop.handles == NULL)
-		return -1;
-
-	eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-	if (eloop.term_event == NULL) {
-		printf("CreateEvent() failed: %d\n",
-		       (int) GetLastError());
-		os_free(eloop.handles);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int eloop_prepare_handles(void)
-{
-	HANDLE *n;
-
-	if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
-		return 0;
-	n = os_realloc(eloop.handles,
-		       eloop.num_handles * 2 * sizeof(eloop.handles[0]));
-	if (n == NULL)
-		return -1;
-	eloop.handles = n;
-	eloop.num_handles *= 2;
-	return 0;
-}
-
-
-int eloop_register_read_sock(int sock, eloop_sock_handler handler,
-			     void *eloop_data, void *user_data)
-{
-	WSAEVENT event;
-	struct eloop_sock *tmp;
-
-	if (eloop_prepare_handles())
-		return -1;
-
-	event = WSACreateEvent();
-	if (event == WSA_INVALID_EVENT) {
-		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
-		return -1;
-	}
-
-	if (WSAEventSelect(sock, event, FD_READ)) {
-		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
-		WSACloseEvent(event);
-		return -1;
-	}
-	tmp = os_realloc(eloop.readers,
-			 (eloop.reader_count + 1) * sizeof(struct eloop_sock));
-	if (tmp == NULL) {
-		WSAEventSelect(sock, event, 0);
-		WSACloseEvent(event);
-		return -1;
-	}
-
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	tmp[eloop.reader_count].event = event;
-	eloop.reader_count++;
-	eloop.readers = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-	eloop.reader_table_changed = 1;
-
-	return 0;
-}
-
-
-void eloop_unregister_read_sock(int sock)
-{
-	size_t i;
-
-	if (eloop.readers == NULL || eloop.reader_count == 0)
-		return;
-
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
-			break;
-	}
-	if (i == eloop.reader_count)
-		return;
-
-	WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
-	WSACloseEvent(eloop.readers[i].event);
-
-	if (i != eloop.reader_count - 1) {
-		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			   (eloop.reader_count - i - 1) *
-			   sizeof(struct eloop_sock));
-	}
-	eloop.reader_count--;
-	eloop.reader_table_changed = 1;
-}
-
-
-int eloop_register_event(void *event, size_t event_size,
-			 eloop_event_handler handler,
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_event *tmp;
-	HANDLE h = event;
-
-	if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
-		return -1;
-
-	if (eloop_prepare_handles())
-		return -1;
-
-	tmp = os_realloc(eloop.events,
-			 (eloop.event_count + 1) * sizeof(struct eloop_event));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.event_count].eloop_data = eloop_data;
-	tmp[eloop.event_count].user_data = user_data;
-	tmp[eloop.event_count].handler = handler;
-	tmp[eloop.event_count].event = h;
-	eloop.event_count++;
-	eloop.events = tmp;
-
-	return 0;
-}
-
-
-void eloop_unregister_event(void *event, size_t event_size)
-{
-	size_t i;
-	HANDLE h = event;
-
-	if (eloop.events == NULL || eloop.event_count == 0 ||
-	    event_size != sizeof(HANDLE))
-		return;
-
-	for (i = 0; i < eloop.event_count; i++) {
-		if (eloop.events[i].event == h)
-			break;
-	}
-	if (i == eloop.event_count)
-		return;
-
-	if (i != eloop.event_count - 1) {
-		os_memmove(&eloop.events[i], &eloop.events[i + 1],
-			   (eloop.event_count - i - 1) *
-			   sizeof(struct eloop_event));
-	}
-	eloop.event_count--;
-}
-
-
-int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   eloop_timeout_handler handler,
-			   void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp, *prev;
-
-	timeout = os_malloc(sizeof(*timeout));
-	if (timeout == NULL)
-		return -1;
-	os_get_time(&timeout->time);
-	timeout->time.sec += secs;
-	timeout->time.usec += usecs;
-	while (timeout->time.usec >= 1000000) {
-		timeout->time.sec++;
-		timeout->time.usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-	timeout->next = NULL;
-
-	if (eloop.timeout == NULL) {
-		eloop.timeout = timeout;
-		return 0;
-	}
-
-	prev = NULL;
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (os_time_before(&timeout->time, &tmp->time))
-			break;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-
-	if (prev == NULL) {
-		timeout->next = eloop.timeout;
-		eloop.timeout = timeout;
-	} else {
-		timeout->next = prev->next;
-		prev->next = timeout;
-	}
-
-	return 0;
-}
-
-
-int eloop_cancel_timeout(eloop_timeout_handler handler,
-			 void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev, *next;
-	int removed = 0;
-
-	prev = NULL;
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		next = timeout->next;
-
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		     eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		     user_data == ELOOP_ALL_CTX)) {
-			if (prev == NULL)
-				eloop.timeout = next;
-			else
-				prev->next = next;
-			os_free(timeout);
-			removed++;
-		} else
-			prev = timeout;
-
-		timeout = next;
-	}
-
-	return removed;
-}
-
-
-int eloop_is_timeout_registered(eloop_timeout_handler handler,
-				void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *tmp;
-
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (tmp->handler == handler &&
-		    tmp->eloop_data == eloop_data &&
-		    tmp->user_data == user_data)
-			return 1;
-
-		tmp = tmp->next;
-	}
-
-	return 0;
-}
-
-
-/* TODO: replace with suitable signal handler */
-#if 0
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-#endif
-
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	if (eloop.pending_terminate) {
-		eloop.pending_terminate = 0;
-	}
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-						 eloop.signals[i].user_data);
-		}
-	}
-
-	if (eloop.term_signal.signaled) {
-		eloop.term_signal.signaled = 0;
-		eloop.term_signal.handler(eloop.term_signal.sig,
-					  eloop.term_signal.user_data);
-	}
-}
-
-
-int eloop_register_signal(int sig, eloop_signal_handler handler,
-			  void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = os_realloc(eloop.signals,
-			 (eloop.signal_count + 1) *
-			 sizeof(struct eloop_signal));
-	if (tmp == NULL)
-		return -1;
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-
-	/* TODO: register signal handler */
-
-	return 0;
-}
-
-
-#ifndef _WIN32_WCE
-static BOOL eloop_handle_console_ctrl(DWORD type)
-{
-	switch (type) {
-	case CTRL_C_EVENT:
-	case CTRL_BREAK_EVENT:
-		eloop.signaled++;
-		eloop.term_signal.signaled++;
-		SetEvent(eloop.term_event);
-		return TRUE;
-	default:
-		return FALSE;
-	}
-}
-#endif /* _WIN32_WCE */
-
-
-int eloop_register_signal_terminate(eloop_signal_handler handler,
-				    void *user_data)
-{
-#ifndef _WIN32_WCE
-	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
-				  TRUE) == 0) {
-		printf("SetConsoleCtrlHandler() failed: %d\n",
-		       (int) GetLastError());
-		return -1;
-	}
-#endif /* _WIN32_WCE */
-
-	eloop.term_signal.handler = handler;
-	eloop.term_signal.user_data = user_data;
-		
-	return 0;
-}
-
-
-int eloop_register_signal_reconfig(eloop_signal_handler handler,
-				   void *user_data)
-{
-	/* TODO */
-	return 0;
-}
-
-
-void eloop_run(void)
-{
-	struct os_time tv, now;
-	DWORD count, ret, timeout, err;
-	size_t i;
-
-	while (!eloop.terminate &&
-	       (eloop.timeout || eloop.reader_count > 0 ||
-		eloop.event_count > 0)) {
-		tv.sec = tv.usec = 0;
-		if (eloop.timeout) {
-			os_get_time(&now);
-			if (os_time_before(&now, &eloop.timeout->time))
-				os_time_sub(&eloop.timeout->time, &now, &tv);
-		}
-
-		count = 0;
-		for (i = 0; i < eloop.event_count; i++)
-			eloop.handles[count++] = eloop.events[i].event;
-
-		for (i = 0; i < eloop.reader_count; i++)
-			eloop.handles[count++] = eloop.readers[i].event;
-
-		if (eloop.term_event)
-			eloop.handles[count++] = eloop.term_event;
-
-		if (eloop.timeout)
-			timeout = tv.sec * 1000 + tv.usec / 1000;
-		else
-			timeout = INFINITE;
-
-		if (count > MAXIMUM_WAIT_OBJECTS) {
-			printf("WaitForMultipleObjects: Too many events: "
-			       "%d > %d (ignoring extra events)\n",
-			       (int) count, MAXIMUM_WAIT_OBJECTS);
-			count = MAXIMUM_WAIT_OBJECTS;
-		}
-#ifdef _WIN32_WCE
-		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
-					     timeout);
-#else /* _WIN32_WCE */
-		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
-					       timeout, TRUE);
-#endif /* _WIN32_WCE */
-		err = GetLastError();
-
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		if (eloop.timeout) {
-			struct eloop_timeout *tmp;
-
-			os_get_time(&now);
-			if (!os_time_before(&now, &eloop.timeout->time)) {
-				tmp = eloop.timeout;
-				eloop.timeout = eloop.timeout->next;
-				tmp->handler(tmp->eloop_data,
-					     tmp->user_data);
-				os_free(tmp);
-			}
-
-		}
-
-		if (ret == WAIT_FAILED) {
-			printf("WaitForMultipleObjects(count=%d) failed: %d\n",
-			       (int) count, (int) err);
-			os_sleep(1, 0);
-			continue;
-		}
-
-#ifndef _WIN32_WCE
-		if (ret == WAIT_IO_COMPLETION)
-			continue;
-#endif /* _WIN32_WCE */
-
-		if (ret == WAIT_TIMEOUT)
-			continue;
-
-		while (ret >= WAIT_OBJECT_0 &&
-		       ret < WAIT_OBJECT_0 + eloop.event_count) {
-			eloop.events[ret].handler(
-				eloop.events[ret].eloop_data,
-				eloop.events[ret].user_data);
-			ret = WaitForMultipleObjects(eloop.event_count,
-						     eloop.handles, FALSE, 0);
-		}
-
-		eloop.reader_table_changed = 0;
-		for (i = 0; i < eloop.reader_count; i++) {
-			WSANETWORKEVENTS events;
-			if (WSAEnumNetworkEvents(eloop.readers[i].sock,
-						 eloop.readers[i].event,
-						 &events) == 0 &&
-			    (events.lNetworkEvents & FD_READ)) {
-				eloop.readers[i].handler(
-					eloop.readers[i].sock,
-					eloop.readers[i].eloop_data,
-					eloop.readers[i].user_data);
-				if (eloop.reader_table_changed)
-					break;
-			}
-		}
-	}
-}
-
-
-void eloop_terminate(void)
-{
-	eloop.terminate = 1;
-	SetEvent(eloop.term_event);
-}
-
-
-void eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		prev = timeout;
-		timeout = timeout->next;
-		os_free(prev);
-	}
-	os_free(eloop.readers);
-	os_free(eloop.signals);
-	if (eloop.term_event)
-		CloseHandle(eloop.term_event);
-	os_free(eloop.handles);
-	eloop.handles = NULL;
-	os_free(eloop.events);
-	eloop.events = NULL;
-}
-
-
-int eloop_terminated(void)
-{
-	return eloop.terminate;
-}
-
-
-void eloop_wait_for_read_sock(int sock)
-{
-	WSAEVENT event;
-
-	event = WSACreateEvent();
-	if (event == WSA_INVALID_EVENT) {
-		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
-		return;
-	}
-
-	if (WSAEventSelect(sock, event, FD_READ)) {
-		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
-		WSACloseEvent(event);
-		return ;
-	}
-
-	WaitForSingleObject(event, INFINITE);
-	WSAEventSelect(sock, event, 0);
-	WSACloseEvent(event);
-}

Copied: vendor/wpa/2.0/src/utils/eloop_win.c (from rev 9639, vendor/wpa/dist/src/utils/eloop_win.c)
===================================================================
--- vendor/wpa/2.0/src/utils/eloop_win.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/eloop_win.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,616 @@
+/*
+ * Event loop based on Windows events and WaitForMultipleObjects
+ * Copyright (c) 2002-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	eloop_sock_handler handler;
+	WSAEVENT event;
+};
+
+struct eloop_event {
+	void *eloop_data;
+	void *user_data;
+	eloop_event_handler handler;
+	HANDLE event;
+};
+
+struct eloop_timeout {
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	eloop_timeout_handler handler;
+	struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	eloop_signal_handler handler;
+	int signaled;
+};
+
+struct eloop_data {
+	int max_sock;
+	size_t reader_count;
+	struct eloop_sock *readers;
+
+	size_t event_count;
+	struct eloop_event *events;
+
+	struct eloop_timeout *timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+
+	struct eloop_signal term_signal;
+	HANDLE term_event;
+
+	HANDLE *handles;
+	size_t num_handles;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void)
+{
+	os_memset(&eloop, 0, sizeof(eloop));
+	eloop.num_handles = 1;
+	eloop.handles = os_malloc(eloop.num_handles *
+				  sizeof(eloop.handles[0]));
+	if (eloop.handles == NULL)
+		return -1;
+
+	eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (eloop.term_event == NULL) {
+		printf("CreateEvent() failed: %d\n",
+		       (int) GetLastError());
+		os_free(eloop.handles);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eloop_prepare_handles(void)
+{
+	HANDLE *n;
+
+	if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
+		return 0;
+	n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
+			     sizeof(eloop.handles[0]));
+	if (n == NULL)
+		return -1;
+	eloop.handles = n;
+	eloop.num_handles *= 2;
+	return 0;
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data)
+{
+	WSAEVENT event;
+	struct eloop_sock *tmp;
+
+	if (eloop_prepare_handles())
+		return -1;
+
+	event = WSACreateEvent();
+	if (event == WSA_INVALID_EVENT) {
+		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+		return -1;
+	}
+
+	if (WSAEventSelect(sock, event, FD_READ)) {
+		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+		WSACloseEvent(event);
+		return -1;
+	}
+	tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+			       sizeof(struct eloop_sock));
+	if (tmp == NULL) {
+		WSAEventSelect(sock, event, 0);
+		WSACloseEvent(event);
+		return -1;
+	}
+
+	tmp[eloop.reader_count].sock = sock;
+	tmp[eloop.reader_count].eloop_data = eloop_data;
+	tmp[eloop.reader_count].user_data = user_data;
+	tmp[eloop.reader_count].handler = handler;
+	tmp[eloop.reader_count].event = event;
+	eloop.reader_count++;
+	eloop.readers = tmp;
+	if (sock > eloop.max_sock)
+		eloop.max_sock = sock;
+	eloop.reader_table_changed = 1;
+
+	return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	size_t i;
+
+	if (eloop.readers == NULL || eloop.reader_count == 0)
+		return;
+
+	for (i = 0; i < eloop.reader_count; i++) {
+		if (eloop.readers[i].sock == sock)
+			break;
+	}
+	if (i == eloop.reader_count)
+		return;
+
+	WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
+	WSACloseEvent(eloop.readers[i].event);
+
+	if (i != eloop.reader_count - 1) {
+		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+			   (eloop.reader_count - i - 1) *
+			   sizeof(struct eloop_sock));
+	}
+	eloop.reader_count--;
+	eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_event(void *event, size_t event_size,
+			 eloop_event_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_event *tmp;
+	HANDLE h = event;
+
+	if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
+		return -1;
+
+	if (eloop_prepare_handles())
+		return -1;
+
+	tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
+			       sizeof(struct eloop_event));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.event_count].eloop_data = eloop_data;
+	tmp[eloop.event_count].user_data = user_data;
+	tmp[eloop.event_count].handler = handler;
+	tmp[eloop.event_count].event = h;
+	eloop.event_count++;
+	eloop.events = tmp;
+
+	return 0;
+}
+
+
+void eloop_unregister_event(void *event, size_t event_size)
+{
+	size_t i;
+	HANDLE h = event;
+
+	if (eloop.events == NULL || eloop.event_count == 0 ||
+	    event_size != sizeof(HANDLE))
+		return;
+
+	for (i = 0; i < eloop.event_count; i++) {
+		if (eloop.events[i].event == h)
+			break;
+	}
+	if (i == eloop.event_count)
+		return;
+
+	if (i != eloop.event_count - 1) {
+		os_memmove(&eloop.events[i], &eloop.events[i + 1],
+			   (eloop.event_count - i - 1) *
+			   sizeof(struct eloop_event));
+	}
+	eloop.event_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   eloop_timeout_handler handler,
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp, *prev;
+	os_time_t now_sec;
+
+	timeout = os_malloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	os_get_time(&timeout->time);
+	now_sec = timeout->time.sec;
+	timeout->time.sec += secs;
+	if (timeout->time.sec < now_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+			   "ever happen - ignore it", secs);
+		os_free(timeout);
+		return 0;
+	}
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	timeout->next = NULL;
+
+	if (eloop.timeout == NULL) {
+		eloop.timeout = timeout;
+		return 0;
+	}
+
+	prev = NULL;
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (os_time_before(&timeout->time, &tmp->time))
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (prev == NULL) {
+		timeout->next = eloop.timeout;
+		eloop.timeout = timeout;
+	} else {
+		timeout->next = prev->next;
+		prev->next = timeout;
+	}
+
+	return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev, *next;
+	int removed = 0;
+
+	prev = NULL;
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		next = timeout->next;
+
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			if (prev == NULL)
+				eloop.timeout = next;
+			else
+				prev->next = next;
+			os_free(timeout);
+			removed++;
+		} else
+			prev = timeout;
+
+		timeout = next;
+	}
+
+	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+
+		tmp = tmp->next;
+	}
+
+	return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.signals[i].user_data);
+		}
+	}
+
+	if (eloop.term_signal.signaled) {
+		eloop.term_signal.signaled = 0;
+		eloop.term_signal.handler(eloop.term_signal.sig,
+					  eloop.term_signal.user_data);
+	}
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+			       sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+
+	/* TODO: register signal handler */
+
+	return 0;
+}
+
+
+#ifndef _WIN32_WCE
+static BOOL eloop_handle_console_ctrl(DWORD type)
+{
+	switch (type) {
+	case CTRL_C_EVENT:
+	case CTRL_BREAK_EVENT:
+		eloop.signaled++;
+		eloop.term_signal.signaled++;
+		SetEvent(eloop.term_event);
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+#endif /* _WIN32_WCE */
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data)
+{
+#ifndef _WIN32_WCE
+	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
+				  TRUE) == 0) {
+		printf("SetConsoleCtrlHandler() failed: %d\n",
+		       (int) GetLastError());
+		return -1;
+	}
+#endif /* _WIN32_WCE */
+
+	eloop.term_signal.handler = handler;
+	eloop.term_signal.user_data = user_data;
+		
+	return 0;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data)
+{
+	/* TODO */
+	return 0;
+}
+
+
+void eloop_run(void)
+{
+	struct os_time tv, now;
+	DWORD count, ret, timeout, err;
+	size_t i;
+
+	while (!eloop.terminate &&
+	       (eloop.timeout || eloop.reader_count > 0 ||
+		eloop.event_count > 0)) {
+		tv.sec = tv.usec = 0;
+		if (eloop.timeout) {
+			os_get_time(&now);
+			if (os_time_before(&now, &eloop.timeout->time))
+				os_time_sub(&eloop.timeout->time, &now, &tv);
+		}
+
+		count = 0;
+		for (i = 0; i < eloop.event_count; i++)
+			eloop.handles[count++] = eloop.events[i].event;
+
+		for (i = 0; i < eloop.reader_count; i++)
+			eloop.handles[count++] = eloop.readers[i].event;
+
+		if (eloop.term_event)
+			eloop.handles[count++] = eloop.term_event;
+
+		if (eloop.timeout)
+			timeout = tv.sec * 1000 + tv.usec / 1000;
+		else
+			timeout = INFINITE;
+
+		if (count > MAXIMUM_WAIT_OBJECTS) {
+			printf("WaitForMultipleObjects: Too many events: "
+			       "%d > %d (ignoring extra events)\n",
+			       (int) count, MAXIMUM_WAIT_OBJECTS);
+			count = MAXIMUM_WAIT_OBJECTS;
+		}
+#ifdef _WIN32_WCE
+		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
+					     timeout);
+#else /* _WIN32_WCE */
+		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
+					       timeout, TRUE);
+#endif /* _WIN32_WCE */
+		err = GetLastError();
+
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		if (eloop.timeout) {
+			struct eloop_timeout *tmp;
+
+			os_get_time(&now);
+			if (!os_time_before(&now, &eloop.timeout->time)) {
+				tmp = eloop.timeout;
+				eloop.timeout = eloop.timeout->next;
+				tmp->handler(tmp->eloop_data,
+					     tmp->user_data);
+				os_free(tmp);
+			}
+
+		}
+
+		if (ret == WAIT_FAILED) {
+			printf("WaitForMultipleObjects(count=%d) failed: %d\n",
+			       (int) count, (int) err);
+			os_sleep(1, 0);
+			continue;
+		}
+
+#ifndef _WIN32_WCE
+		if (ret == WAIT_IO_COMPLETION)
+			continue;
+#endif /* _WIN32_WCE */
+
+		if (ret == WAIT_TIMEOUT)
+			continue;
+
+		while (ret >= WAIT_OBJECT_0 &&
+		       ret < WAIT_OBJECT_0 + eloop.event_count) {
+			eloop.events[ret].handler(
+				eloop.events[ret].eloop_data,
+				eloop.events[ret].user_data);
+			ret = WaitForMultipleObjects(eloop.event_count,
+						     eloop.handles, FALSE, 0);
+		}
+
+		eloop.reader_table_changed = 0;
+		for (i = 0; i < eloop.reader_count; i++) {
+			WSANETWORKEVENTS events;
+			if (WSAEnumNetworkEvents(eloop.readers[i].sock,
+						 eloop.readers[i].event,
+						 &events) == 0 &&
+			    (events.lNetworkEvents & FD_READ)) {
+				eloop.readers[i].handler(
+					eloop.readers[i].sock,
+					eloop.readers[i].eloop_data,
+					eloop.readers[i].user_data);
+				if (eloop.reader_table_changed)
+					break;
+			}
+		}
+	}
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+	SetEvent(eloop.term_event);
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		prev = timeout;
+		timeout = timeout->next;
+		os_free(prev);
+	}
+	os_free(eloop.readers);
+	os_free(eloop.signals);
+	if (eloop.term_event)
+		CloseHandle(eloop.term_event);
+	os_free(eloop.handles);
+	eloop.handles = NULL;
+	os_free(eloop.events);
+	eloop.events = NULL;
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+	WSAEVENT event;
+
+	event = WSACreateEvent();
+	if (event == WSA_INVALID_EVENT) {
+		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+		return;
+	}
+
+	if (WSAEventSelect(sock, event, FD_READ)) {
+		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+		WSACloseEvent(event);
+		return ;
+	}
+
+	WaitForSingleObject(event, INFINITE);
+	WSAEventSelect(sock, event, 0);
+	WSACloseEvent(event);
+}

Copied: vendor/wpa/2.0/src/utils/ext_password.c (from rev 9639, vendor/wpa/dist/src/utils/ext_password.c)
===================================================================
--- vendor/wpa/2.0/src/utils/ext_password.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ext_password.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,116 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#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,
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+	NULL
+};
+
+struct ext_password_data {
+	const struct ext_password_backend *backend;
+	void *priv;
+};
+
+
+struct ext_password_data * ext_password_init(const char *backend,
+					     const char *params)
+{
+	struct ext_password_data *data;
+	int i;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	for (i = 0; backends[i]; i++) {
+		if (os_strcmp(backends[i]->name, backend) == 0) {
+			data->backend = backends[i];
+			break;
+		}
+	}
+
+	if (!data->backend) {
+		os_free(data);
+		return NULL;
+	}
+
+	data->priv = data->backend->init(params);
+	if (data->priv == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+void ext_password_deinit(struct ext_password_data *data)
+{
+	if (data && data->backend && data->priv)
+		data->backend->deinit(data->priv);
+	os_free(data);
+}
+
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+				 const char *name)
+{
+	if (data == NULL)
+		return NULL;
+	return data->backend->get(data->priv, name);
+}
+
+
+struct wpabuf * ext_password_alloc(size_t len)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return NULL;
+
+#ifdef __linux__
+	if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
+		wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
+			   strerror(errno));
+	}
+#endif /* __linux__ */
+
+	return buf;
+}
+
+
+void ext_password_free(struct wpabuf *pw)
+{
+	if (pw == NULL)
+		return;
+	os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
+#ifdef __linux__
+	if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
+		wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
+			   strerror(errno));
+	}
+#endif /* __linux__ */
+	wpabuf_free(pw);
+}

Copied: vendor/wpa/2.0/src/utils/ext_password.h (from rev 9639, vendor/wpa/dist/src/utils/ext_password.h)
===================================================================
--- vendor/wpa/2.0/src/utils/ext_password.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ext_password.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_H
+#define EXT_PASSWORD_H
+
+struct ext_password_data;
+
+#ifdef CONFIG_EXT_PASSWORD
+
+struct ext_password_data * ext_password_init(const char *backend,
+					     const char *params);
+void ext_password_deinit(struct ext_password_data *data);
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+				 const char *name);
+void ext_password_free(struct wpabuf *pw);
+
+#else /* CONFIG_EXT_PASSWORD */
+
+#define ext_password_init(b, p) ((void *) 1)
+#define ext_password_deinit(d) do { } while (0)
+#define ext_password_get(d, n) (NULL)
+#define ext_password_free(p) do { } while (0)
+
+#endif /* CONFIG_EXT_PASSWORD */
+
+#endif /* EXT_PASSWORD_H */

Copied: vendor/wpa/2.0/src/utils/ext_password_i.h (from rev 9639, vendor/wpa/dist/src/utils/ext_password_i.h)
===================================================================
--- vendor/wpa/2.0/src/utils/ext_password_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ext_password_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,23 @@
+/*
+ * External password backend - internal definitions
+ * Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_I_H
+#define EXT_PASSWORD_I_H
+
+#include "ext_password.h"
+
+struct ext_password_backend {
+	const char *name;
+	void * (*init)(const char *params);
+	void (*deinit)(void *ctx);
+	struct wpabuf * (*get)(void *ctx, const char *name);
+};
+
+struct wpabuf * ext_password_alloc(size_t len);
+
+#endif /* EXT_PASSWORD_I_H */

Copied: vendor/wpa/2.0/src/utils/ext_password_test.c (from rev 9639, vendor/wpa/dist/src/utils/ext_password_test.c)
===================================================================
--- vendor/wpa/2.0/src/utils/ext_password_test.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ext_password_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,90 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j at 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 "ext_password_i.h"
+
+
+struct ext_password_test_data {
+	char *params;
+};
+
+
+static void * ext_password_test_init(const char *params)
+{
+	struct ext_password_test_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	if (params)
+		data->params = os_strdup(params);
+
+	return data;
+}
+
+
+static void ext_password_test_deinit(void *ctx)
+{
+	struct ext_password_test_data *data = ctx;
+
+	os_free(data->params);
+	os_free(data);
+}
+
+
+static struct wpabuf * ext_password_test_get(void *ctx, const char *name)
+{
+	struct ext_password_test_data *data = ctx;
+	char *pos, *pos2;
+	size_t nlen;
+
+	wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name);
+
+	pos = data->params;
+	if (pos == NULL)
+		return NULL;
+	nlen = os_strlen(name);
+
+	while (pos && *pos) {
+		if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') {
+			struct wpabuf *buf;
+			pos += nlen + 1;
+			pos2 = pos;
+			while (*pos2 != '|' && *pos2 != '\0')
+				pos2++;
+			buf = ext_password_alloc(pos2 - pos);
+			if (buf == NULL)
+				return NULL;
+			wpabuf_put_data(buf, pos, pos2 - pos);
+			wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value",
+					      wpabuf_head(buf),
+					      wpabuf_len(buf));
+			return buf;
+		}
+
+		pos = os_strchr(pos + 1, '|');
+		if (pos)
+			pos++;
+	}
+
+	wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name);
+
+	return NULL;
+}
+
+
+const struct ext_password_backend ext_password_test = {
+	.name = "test",
+	.init = ext_password_test_init,
+	.deinit = ext_password_test_deinit,
+	.get = ext_password_test_get,
+};

Deleted: vendor/wpa/2.0/src/utils/includes.h
===================================================================
--- vendor/wpa/dist/src/utils/includes.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/includes.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,59 +0,0 @@
-/*
- * wpa_supplicant/hostapd - Default include files
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This header file is included into all C files so that commonly used header
- * files can be selected with OS specific ifdef blocks in one place instead of
- * having to have OS/C library specific selection in many files.
- */
-
-#ifndef INCLUDES_H
-#define INCLUDES_H
-
-/* Include possible build time configuration before including anything else */
-#include "build_config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#ifndef _WIN32_WCE
-#ifndef CONFIG_TI_COMPILER
-#include <signal.h>
-#include <sys/types.h>
-#endif /* CONFIG_TI_COMPILER */
-#include <errno.h>
-#endif /* _WIN32_WCE */
-#include <ctype.h>
-#include <time.h>
-
-#ifndef CONFIG_TI_COMPILER
-#ifndef _MSC_VER
-#include <unistd.h>
-#endif /* _MSC_VER */
-#endif /* CONFIG_TI_COMPILER */
-
-#ifndef CONFIG_NATIVE_WINDOWS
-#ifndef CONFIG_TI_COMPILER
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifndef __vxworks
-#ifndef __SYMBIAN32__
-#include <sys/uio.h>
-#endif /* __SYMBIAN32__ */
-#include <sys/time.h>
-#endif /* __vxworks */
-#endif /* CONFIG_TI_COMPILER */
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#endif /* INCLUDES_H */

Copied: vendor/wpa/2.0/src/utils/includes.h (from rev 9639, vendor/wpa/dist/src/utils/includes.h)
===================================================================
--- vendor/wpa/2.0/src/utils/includes.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/includes.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,50 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This header file is included into all C files so that commonly used header
+ * files can be selected with OS specific ifdef blocks in one place instead of
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+/* Include possible build time configuration before including anything else */
+#include "build_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#ifndef CONFIG_TI_COMPILER
+#include <signal.h>
+#include <sys/types.h>
+#endif /* CONFIG_TI_COMPILER */
+#include <errno.h>
+#endif /* _WIN32_WCE */
+#include <ctype.h>
+
+#ifndef CONFIG_TI_COMPILER
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_TI_COMPILER
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef __vxworks
+#include <sys/uio.h>
+#include <sys/time.h>
+#endif /* __vxworks */
+#endif /* CONFIG_TI_COMPILER */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#endif /* INCLUDES_H */

Deleted: vendor/wpa/2.0/src/utils/ip_addr.c
===================================================================
--- vendor/wpa/dist/src/utils/ip_addr.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/ip_addr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,83 +0,0 @@
-/*
- * IP address processing
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "ip_addr.h"
-
-const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
-			    size_t buflen)
-{
-	if (buflen == 0 || addr == NULL)
-		return NULL;
-
-	if (addr->af == AF_INET) {
-		os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen);
-	} else {
-		buf[0] = '\0';
-	}
-#ifdef CONFIG_IPV6
-	if (addr->af == AF_INET6) {
-		if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL)
-			buf[0] = '\0';
-	}
-#endif /* CONFIG_IPV6 */
-
-	return buf;
-}
-
-
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
-{
-	if (a == NULL && b == NULL)
-		return 0;
-	if (a == NULL || b == NULL)
-		return 1;
-
-	switch (a->af) {
-	case AF_INET:
-		if (a->u.v4.s_addr != b->u.v4.s_addr)
-			return 1;
-		break;
-#ifdef CONFIG_IPV6
-	case AF_INET6:
-		if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
-			return 1;
-		break;
-#endif /* CONFIG_IPV6 */
-	}
-
-	return 0;
-}
-
-
-int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
-{
-#ifndef CONFIG_NATIVE_WINDOWS
-	if (inet_aton(txt, &addr->u.v4)) {
-		addr->af = AF_INET;
-		return 0;
-	}
-
-#ifdef CONFIG_IPV6
-	if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) {
-		addr->af = AF_INET6;
-		return 0;
-	}
-#endif /* CONFIG_IPV6 */
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-	return -1;
-}

Copied: vendor/wpa/2.0/src/utils/ip_addr.c (from rev 9639, vendor/wpa/dist/src/utils/ip_addr.c)
===================================================================
--- vendor/wpa/2.0/src/utils/ip_addr.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ip_addr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,77 @@
+/*
+ * IP address processing
+ * Copyright (c) 2003-2006, Jouni Malinen <j at 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 "ip_addr.h"
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+			    size_t buflen)
+{
+	if (buflen == 0 || addr == NULL)
+		return NULL;
+
+	if (addr->af == AF_INET) {
+		os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen);
+	} else {
+		buf[0] = '\0';
+	}
+#ifdef CONFIG_IPV6
+	if (addr->af == AF_INET6) {
+		if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL)
+			buf[0] = '\0';
+	}
+#endif /* CONFIG_IPV6 */
+
+	return buf;
+}
+
+
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
+{
+	if (a == NULL && b == NULL)
+		return 0;
+	if (a == NULL || b == NULL)
+		return 1;
+
+	switch (a->af) {
+	case AF_INET:
+		if (a->u.v4.s_addr != b->u.v4.s_addr)
+			return 1;
+		break;
+#ifdef CONFIG_IPV6
+	case AF_INET6:
+		if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
+			return 1;
+		break;
+#endif /* CONFIG_IPV6 */
+	}
+
+	return 0;
+}
+
+
+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+	if (inet_aton(txt, &addr->u.v4)) {
+		addr->af = AF_INET;
+		return 0;
+	}
+
+#ifdef CONFIG_IPV6
+	if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) {
+		addr->af = AF_INET6;
+		return 0;
+	}
+#endif /* CONFIG_IPV6 */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	return -1;
+}

Deleted: vendor/wpa/2.0/src/utils/ip_addr.h
===================================================================
--- vendor/wpa/dist/src/utils/ip_addr.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/ip_addr.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,34 +0,0 @@
-/*
- * IP address processing
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IP_ADDR_H
-#define IP_ADDR_H
-
-struct hostapd_ip_addr {
-	int af; /* AF_INET / AF_INET6 */
-	union {
-		struct in_addr v4;
-#ifdef CONFIG_IPV6
-		struct in6_addr v6;
-#endif /* CONFIG_IPV6 */
-		u8 max_len[16];
-	} u;
-};
-
-const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
-			    size_t buflen);
-int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
-int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
-
-#endif /* IP_ADDR_H */

Copied: vendor/wpa/2.0/src/utils/ip_addr.h (from rev 9639, vendor/wpa/dist/src/utils/ip_addr.h)
===================================================================
--- vendor/wpa/2.0/src/utils/ip_addr.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/ip_addr.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * IP address processing
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IP_ADDR_H
+#define IP_ADDR_H
+
+struct hostapd_ip_addr {
+	int af; /* AF_INET / AF_INET6 */
+	union {
+		struct in_addr v4;
+#ifdef CONFIG_IPV6
+		struct in6_addr v6;
+#endif /* CONFIG_IPV6 */
+		u8 max_len[16];
+	} u;
+};
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+			    size_t buflen);
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
+
+#endif /* IP_ADDR_H */

Deleted: vendor/wpa/2.0/src/utils/list.h
===================================================================
--- vendor/wpa/dist/src/utils/list.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/list.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,89 +0,0 @@
-/*
- * Doubly-linked list
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef LIST_H
-#define LIST_H
-
-/**
- * struct dl_list - Doubly-linked list
- */
-struct dl_list {
-	struct dl_list *next;
-	struct dl_list *prev;
-};
-
-static inline void dl_list_init(struct dl_list *list)
-{
-	list->next = list;
-	list->prev = list;
-}
-
-static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
-{
-	item->next = list->next;
-	item->prev = list;
-	list->next->prev = item;
-	list->next = item;
-}
-
-static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
-{
-	dl_list_add(list->prev, item);
-}
-
-static inline void dl_list_del(struct dl_list *item)
-{
-	item->next->prev = item->prev;
-	item->prev->next = item->next;
-	item->next = NULL;
-	item->prev = NULL;
-}
-
-static inline int dl_list_empty(struct dl_list *list)
-{
-	return list->next == list;
-}
-
-static inline unsigned int dl_list_len(struct dl_list *list)
-{
-	struct dl_list *item;
-	int count = 0;
-	for (item = list->next; item != list; item = item->next)
-		count++;
-	return count;
-}
-
-#ifndef offsetof
-#define offsetof(type, member) ((long) &((type *) 0)->member)
-#endif
-
-#define dl_list_entry(item, type, member) \
-	((type *) ((char *) item - offsetof(type, member)))
-
-#define dl_list_first(list, type, member) \
-	(dl_list_empty((list)) ? NULL : \
-	 dl_list_entry((list)->next, type, member))
-
-#define dl_list_for_each(item, list, type, member) \
-	for (item = dl_list_entry((list)->next, type, member); \
-	     &item->member != (list); \
-	     item = dl_list_entry(item->member.next, type, member))
-
-#define dl_list_for_each_safe(item, n, list, type, member) \
-	for (item = dl_list_entry((list)->next, type, member), \
-		     n = dl_list_entry(item->member.next, type, member); \
-	     &item->member != (list); \
-	     item = n, n = dl_list_entry(n->member.next, type, member))
-
-#endif /* LIST_H */

Copied: vendor/wpa/2.0/src/utils/list.h (from rev 9639, vendor/wpa/dist/src/utils/list.h)
===================================================================
--- vendor/wpa/2.0/src/utils/list.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/list.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,95 @@
+/*
+ * Doubly-linked list
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+/**
+ * struct dl_list - Doubly-linked list
+ */
+struct dl_list {
+	struct dl_list *next;
+	struct dl_list *prev;
+};
+
+static inline void dl_list_init(struct dl_list *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
+{
+	item->next = list->next;
+	item->prev = list;
+	list->next->prev = item;
+	list->next = item;
+}
+
+static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
+{
+	dl_list_add(list->prev, item);
+}
+
+static inline void dl_list_del(struct dl_list *item)
+{
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+	item->next = NULL;
+	item->prev = NULL;
+}
+
+static inline int dl_list_empty(struct dl_list *list)
+{
+	return list->next == list;
+}
+
+static inline unsigned int dl_list_len(struct dl_list *list)
+{
+	struct dl_list *item;
+	int count = 0;
+	for (item = list->next; item != list; item = item->next)
+		count++;
+	return count;
+}
+
+#ifndef offsetof
+#define offsetof(type, member) ((long) &((type *) 0)->member)
+#endif
+
+#define dl_list_entry(item, type, member) \
+	((type *) ((char *) item - offsetof(type, member)))
+
+#define dl_list_first(list, type, member) \
+	(dl_list_empty((list)) ? NULL : \
+	 dl_list_entry((list)->next, type, member))
+
+#define dl_list_last(list, type, member) \
+	(dl_list_empty((list)) ? NULL : \
+	 dl_list_entry((list)->prev, type, member))
+
+#define dl_list_for_each(item, list, type, member) \
+	for (item = dl_list_entry((list)->next, type, member); \
+	     &item->member != (list); \
+	     item = dl_list_entry(item->member.next, type, member))
+
+#define dl_list_for_each_safe(item, n, list, type, member) \
+	for (item = dl_list_entry((list)->next, type, member), \
+		     n = dl_list_entry(item->member.next, type, member); \
+	     &item->member != (list); \
+	     item = n, n = dl_list_entry(n->member.next, type, member))
+
+#define dl_list_for_each_reverse(item, list, type, member) \
+	for (item = dl_list_entry((list)->prev, type, member); \
+	     &item->member != (list); \
+	     item = dl_list_entry(item->member.prev, type, member))
+
+#define DEFINE_DL_LIST(name) \
+	struct dl_list name = { &(name), &(name) }
+
+#endif /* LIST_H */

Deleted: vendor/wpa/2.0/src/utils/os.h
===================================================================
--- vendor/wpa/dist/src/utils/os.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/os.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,508 +0,0 @@
-/*
- * OS specific functions
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef OS_H
-#define OS_H
-
-typedef long os_time_t;
-
-/**
- * os_sleep - Sleep (sec, usec)
- * @sec: Number of seconds to sleep
- * @usec: Number of microseconds to sleep
- */
-void os_sleep(os_time_t sec, os_time_t usec);
-
-struct os_time {
-	os_time_t sec;
-	os_time_t usec;
-};
-
-/**
- * os_get_time - Get current time (sec, usec)
- * @t: Pointer to buffer for the time
- * Returns: 0 on success, -1 on failure
- */
-int os_get_time(struct os_time *t);
-
-
-/* Helper macros for handling struct os_time */
-
-#define os_time_before(a, b) \
-	((a)->sec < (b)->sec || \
-	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
-
-#define os_time_sub(a, b, res) do { \
-	(res)->sec = (a)->sec - (b)->sec; \
-	(res)->usec = (a)->usec - (b)->usec; \
-	if ((res)->usec < 0) { \
-		(res)->sec--; \
-		(res)->usec += 1000000; \
-	} \
-} while (0)
-
-/**
- * os_mktime - Convert broken-down time into seconds since 1970-01-01
- * @year: Four digit year
- * @month: Month (1 .. 12)
- * @day: Day of month (1 .. 31)
- * @hour: Hour (0 .. 23)
- * @min: Minute (0 .. 59)
- * @sec: Second (0 .. 60)
- * @t: Buffer for returning calendar time representation (seconds since
- * 1970-01-01 00:00:00)
- * Returns: 0 on success, -1 on failure
- *
- * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
- * which is used by POSIX mktime().
- */
-int os_mktime(int year, int month, int day, int hour, int min, int sec,
-	      os_time_t *t);
-
-
-/**
- * os_daemonize - Run in the background (detach from the controlling terminal)
- * @pid_file: File name to write the process ID to or %NULL to skip this
- * Returns: 0 on success, -1 on failure
- */
-int os_daemonize(const char *pid_file);
-
-/**
- * os_daemonize_terminate - Stop running in the background (remove pid file)
- * @pid_file: File name to write the process ID to or %NULL to skip this
- */
-void os_daemonize_terminate(const char *pid_file);
-
-/**
- * os_get_random - Get cryptographically strong pseudo random data
- * @buf: Buffer for pseudo random data
- * @len: Length of the buffer
- * Returns: 0 on success, -1 on failure
- */
-int os_get_random(unsigned char *buf, size_t len);
-
-/**
- * os_random - Get pseudo random value (not necessarily very strong)
- * Returns: Pseudo random value
- */
-unsigned long os_random(void);
-
-/**
- * os_rel2abs_path - Get an absolute path for a file
- * @rel_path: Relative path to a file
- * Returns: Absolute path for the file or %NULL on failure
- *
- * This function tries to convert a relative path of a file to an absolute path
- * in order for the file to be found even if current working directory has
- * changed. The returned value is allocated and caller is responsible for
- * freeing it. It is acceptable to just return the same path in an allocated
- * buffer, e.g., return strdup(rel_path). This function is only used to find
- * configuration files when os_daemonize() may have changed the current working
- * directory and relative path would be pointing to a different location.
- */
-char * os_rel2abs_path(const char *rel_path);
-
-/**
- * os_program_init - Program initialization (called at start)
- * Returns: 0 on success, -1 on failure
- *
- * This function is called when a programs starts. If there are any OS specific
- * processing that is needed, it can be placed here. It is also acceptable to
- * just return 0 if not special processing is needed.
- */
-int os_program_init(void);
-
-/**
- * os_program_deinit - Program deinitialization (called just before exit)
- *
- * This function is called just before a program exists. If there are any OS
- * specific processing, e.g., freeing resourced allocated in os_program_init(),
- * it should be done here. It is also acceptable for this function to do
- * nothing.
- */
-void os_program_deinit(void);
-
-/**
- * os_setenv - Set environment variable
- * @name: Name of the variable
- * @value: Value to set to the variable
- * @overwrite: Whether existing variable should be overwritten
- * Returns: 0 on success, -1 on error
- *
- * This function is only used for wpa_cli action scripts. OS wrapper does not
- * need to implement this if such functionality is not needed.
- */
-int os_setenv(const char *name, const char *value, int overwrite);
-
-/**
- * os_unsetenv - Delete environent variable
- * @name: Name of the variable
- * Returns: 0 on success, -1 on error
- *
- * This function is only used for wpa_cli action scripts. OS wrapper does not
- * need to implement this if such functionality is not needed.
- */
-int os_unsetenv(const char *name);
-
-/**
- * os_readfile - Read a file to an allocated memory buffer
- * @name: Name of the file to read
- * @len: For returning the length of the allocated buffer
- * Returns: Pointer to the allocated buffer or %NULL on failure
- *
- * This function allocates memory and reads the given file to this buffer. Both
- * binary and text files can be read with this function. The caller is
- * responsible for freeing the returned buffer with os_free().
- */
-char * os_readfile(const char *name, size_t *len);
-
-/**
- * os_zalloc - Allocate and zero memory
- * @size: Number of bytes to allocate
- * Returns: Pointer to allocated and zeroed memory or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer with os_free().
- */
-void * os_zalloc(size_t size);
-
-
-/*
- * The following functions are wrapper for standard ANSI C or POSIX functions.
- * By default, they are just defined to use the standard function name and no
- * os_*.c implementation is needed for them. This avoids extra function calls
- * by allowing the C pre-processor take care of the function name mapping.
- *
- * If the target system uses a C library that does not provide these functions,
- * build_config.h can be used to define the wrappers to use a different
- * function name. This can be done on function-by-function basis since the
- * defines here are only used if build_config.h does not define the os_* name.
- * If needed, os_*.c file can be used to implement the functions that are not
- * included in the C library on the target system. Alternatively,
- * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
- * these functions need to be implemented in os_*.c file for the target system.
- */
-
-#ifdef OS_NO_C_LIB_DEFINES
-
-/**
- * os_malloc - Allocate dynamic memory
- * @size: Size of the buffer to allocate
- * Returns: Allocated buffer or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer with os_free().
- */
-void * os_malloc(size_t size);
-
-/**
- * os_realloc - Re-allocate dynamic memory
- * @ptr: Old buffer from os_malloc() or os_realloc()
- * @size: Size of the new buffer
- * Returns: Allocated buffer or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer with os_free().
- * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
- * not freed and caller is still responsible for freeing it.
- */
-void * os_realloc(void *ptr, size_t size);
-
-/**
- * os_free - Free dynamic memory
- * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
- */
-void os_free(void *ptr);
-
-/**
- * os_memcpy - Copy memory area
- * @dest: Destination
- * @src: Source
- * @n: Number of bytes to copy
- * Returns: dest
- *
- * The memory areas src and dst must not overlap. os_memmove() can be used with
- * overlapping memory.
- */
-void * os_memcpy(void *dest, const void *src, size_t n);
-
-/**
- * os_memmove - Copy memory area
- * @dest: Destination
- * @src: Source
- * @n: Number of bytes to copy
- * Returns: dest
- *
- * The memory areas src and dst may overlap.
- */
-void * os_memmove(void *dest, const void *src, size_t n);
-
-/**
- * os_memset - Fill memory with a constant byte
- * @s: Memory area to be filled
- * @c: Constant byte
- * @n: Number of bytes started from s to fill with c
- * Returns: s
- */
-void * os_memset(void *s, int c, size_t n);
-
-/**
- * os_memcmp - Compare memory areas
- * @s1: First buffer
- * @s2: Second buffer
- * @n: Maximum numbers of octets to compare
- * Returns: An integer less than, equal to, or greater than zero if s1 is
- * found to be less than, to match, or be greater than s2. Only first n
- * characters will be compared.
- */
-int os_memcmp(const void *s1, const void *s2, size_t n);
-
-/**
- * os_strdup - Duplicate a string
- * @s: Source string
- * Returns: Allocated buffer with the string copied into it or %NULL on failure
- *
- * Caller is responsible for freeing the returned buffer with os_free().
- */
-char * os_strdup(const char *s);
-
-/**
- * os_strlen - Calculate the length of a string
- * @s: '\0' terminated string
- * Returns: Number of characters in s (not counting the '\0' terminator)
- */
-size_t os_strlen(const char *s);
-
-/**
- * os_strcasecmp - Compare two strings ignoring case
- * @s1: First string
- * @s2: Second string
- * Returns: An integer less than, equal to, or greater than zero if s1 is
- * found to be less than, to match, or be greatred than s2
- */
-int os_strcasecmp(const char *s1, const char *s2);
-
-/**
- * os_strncasecmp - Compare two strings ignoring case
- * @s1: First string
- * @s2: Second string
- * @n: Maximum numbers of characters to compare
- * Returns: An integer less than, equal to, or greater than zero if s1 is
- * found to be less than, to match, or be greater than s2. Only first n
- * characters will be compared.
- */
-int os_strncasecmp(const char *s1, const char *s2, size_t n);
-
-/**
- * os_strchr - Locate the first occurrence of a character in string
- * @s: String
- * @c: Character to search for
- * Returns: Pointer to the matched character or %NULL if not found
- */
-char * os_strchr(const char *s, int c);
-
-/**
- * os_strrchr - Locate the last occurrence of a character in string
- * @s: String
- * @c: Character to search for
- * Returns: Pointer to the matched character or %NULL if not found
- */
-char * os_strrchr(const char *s, int c);
-
-/**
- * os_strcmp - Compare two strings
- * @s1: First string
- * @s2: Second string
- * Returns: An integer less than, equal to, or greater than zero if s1 is
- * found to be less than, to match, or be greatred than s2
- */
-int os_strcmp(const char *s1, const char *s2);
-
-/**
- * os_strncmp - Compare two strings
- * @s1: First string
- * @s2: Second string
- * @n: Maximum numbers of characters to compare
- * Returns: An integer less than, equal to, or greater than zero if s1 is
- * found to be less than, to match, or be greater than s2. Only first n
- * characters will be compared.
- */
-int os_strncmp(const char *s1, const char *s2, size_t n);
-
-/**
- * os_strncpy - Copy a string
- * @dest: Destination
- * @src: Source
- * @n: Maximum number of characters to copy
- * Returns: dest
- */
-char * os_strncpy(char *dest, const char *src, size_t n);
-
-/**
- * os_strstr - Locate a substring
- * @haystack: String (haystack) to search from
- * @needle: Needle to search from haystack
- * Returns: Pointer to the beginning of the substring or %NULL if not found
- */
-char * os_strstr(const char *haystack, const char *needle);
-
-/**
- * os_snprintf - Print to a memory buffer
- * @str: Memory buffer to print into
- * @size: Maximum length of the str buffer
- * @format: printf format
- * Returns: Number of characters printed (not including trailing '\0').
- *
- * If the output buffer is truncated, number of characters which would have
- * been written is returned. Since some C libraries return -1 in such a case,
- * the caller must be prepared on that value, too, to indicate truncation.
- *
- * Note: Some C library implementations of snprintf() may not guarantee null
- * termination in case the output is truncated. The OS wrapper function of
- * os_snprintf() should provide this guarantee, i.e., to null terminate the
- * output buffer if a C library version of the function is used and if that
- * function does not guarantee null termination.
- *
- * If the target system does not include snprintf(), see, e.g.,
- * http://www.ijs.si/software/snprintf/ for an example of a portable
- * implementation of snprintf.
- */
-int os_snprintf(char *str, size_t size, const char *format, ...);
-
-#else /* OS_NO_C_LIB_DEFINES */
-
-#ifdef WPA_TRACE
-void * os_malloc(size_t size);
-void * os_realloc(void *ptr, size_t size);
-void os_free(void *ptr);
-char * os_strdup(const char *s);
-#else /* WPA_TRACE */
-#ifndef os_malloc
-#define os_malloc(s) malloc((s))
-#endif
-#ifndef os_realloc
-#define os_realloc(p, s) realloc((p), (s))
-#endif
-#ifndef os_free
-#define os_free(p) free((p))
-#endif
-#ifndef os_strdup
-#ifdef _MSC_VER
-#define os_strdup(s) _strdup(s)
-#else
-#define os_strdup(s) strdup(s)
-#endif
-#endif
-#endif /* WPA_TRACE */
-
-#ifndef os_memcpy
-#define os_memcpy(d, s, n) memcpy((d), (s), (n))
-#endif
-#ifndef os_memmove
-#define os_memmove(d, s, n) memmove((d), (s), (n))
-#endif
-#ifndef os_memset
-#define os_memset(s, c, n) memset(s, c, n)
-#endif
-#ifndef os_memcmp
-#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
-#endif
-
-#ifndef os_strlen
-#define os_strlen(s) strlen(s)
-#endif
-#ifndef os_strcasecmp
-#ifdef _MSC_VER
-#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
-#else
-#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
-#endif
-#endif
-#ifndef os_strncasecmp
-#ifdef _MSC_VER
-#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
-#else
-#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
-#endif
-#endif
-#ifndef os_strchr
-#define os_strchr(s, c) strchr((s), (c))
-#endif
-#ifndef os_strcmp
-#define os_strcmp(s1, s2) strcmp((s1), (s2))
-#endif
-#ifndef os_strncmp
-#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
-#endif
-#ifndef os_strncpy
-#define os_strncpy(d, s, n) strncpy((d), (s), (n))
-#endif
-#ifndef os_strrchr
-#define os_strrchr(s, c) strrchr((s), (c))
-#endif
-#ifndef os_strstr
-#define os_strstr(h, n) strstr((h), (n))
-#endif
-
-#ifndef os_snprintf
-#ifdef _MSC_VER
-#define os_snprintf _snprintf
-#else
-#define os_snprintf snprintf
-#endif
-#endif
-
-#endif /* OS_NO_C_LIB_DEFINES */
-
-
-/**
- * os_strlcpy - Copy a string with size bound and NUL-termination
- * @dest: Destination
- * @src: Source
- * @siz: Size of the target buffer
- * Returns: Total length of the target string (length of src) (not including
- * NUL-termination)
- *
- * This function matches in behavior with the strlcpy(3) function in OpenBSD.
- */
-size_t os_strlcpy(char *dest, const char *src, size_t siz);
-
-
-#ifdef OS_REJECT_C_LIB_FUNCTIONS
-#define malloc OS_DO_NOT_USE_malloc
-#define realloc OS_DO_NOT_USE_realloc
-#define free OS_DO_NOT_USE_free
-#define memcpy OS_DO_NOT_USE_memcpy
-#define memmove OS_DO_NOT_USE_memmove
-#define memset OS_DO_NOT_USE_memset
-#define memcmp OS_DO_NOT_USE_memcmp
-#undef strdup
-#define strdup OS_DO_NOT_USE_strdup
-#define strlen OS_DO_NOT_USE_strlen
-#define strcasecmp OS_DO_NOT_USE_strcasecmp
-#define strncasecmp OS_DO_NOT_USE_strncasecmp
-#undef strchr
-#define strchr OS_DO_NOT_USE_strchr
-#undef strcmp
-#define strcmp OS_DO_NOT_USE_strcmp
-#undef strncmp
-#define strncmp OS_DO_NOT_USE_strncmp
-#undef strncpy
-#define strncpy OS_DO_NOT_USE_strncpy
-#define strrchr OS_DO_NOT_USE_strrchr
-#define strstr OS_DO_NOT_USE_strstr
-#undef snprintf
-#define snprintf OS_DO_NOT_USE_snprintf
-
-#define strcpy OS_DO_NOT_USE_strcpy
-#endif /* OS_REJECT_C_LIB_FUNCTIONS */
-
-#endif /* OS_H */

Copied: vendor/wpa/2.0/src/utils/os.h (from rev 9639, vendor/wpa/dist/src/utils/os.h)
===================================================================
--- vendor/wpa/2.0/src/utils/os.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/os.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,539 @@
+/*
+ * OS specific functions
+ * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+	os_time_t sec;
+	os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+	((a)->sec < (b)->sec || \
+	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+	(res)->sec = (a)->sec - (b)->sec; \
+	(res)->usec = (a)->usec - (b)->usec; \
+	if ((res)->usec < 0) { \
+		(res)->sec--; \
+		(res)->usec += 1000000; \
+	} \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
+ * which is used by POSIX mktime().
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t);
+
+struct os_tm {
+	int sec; /* 0..59 or 60 for leap seconds */
+	int min; /* 0..59 */
+	int hour; /* 0..23 */
+	int day; /* 1..31 */
+	int month; /* 1..12 */
+	int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+/**
+ * os_calloc - Allocate and zero memory for an array
+ * @nmemb: Number of members in the array
+ * @size: Number of bytes in each member
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * This function can be used as a wrapper for os_zalloc(nmemb * size) when an
+ * allocation is used for an array. The main benefit over os_zalloc() is in
+ * having an extra check to catch integer overflows in multiplication.
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+static inline void * os_calloc(size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_zalloc(nmemb * size);
+}
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifdef WPA_TRACE
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+char * os_strdup(const char *s);
+#else /* WPA_TRACE */
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#endif /* WPA_TRACE */
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_realloc(ptr, nmemb * size);
+}
+
+
+/**
+ * os_strlcpy - Copy a string with size bound and NUL-termination
+ * @dest: Destination
+ * @src: Source
+ * @siz: Size of the target buffer
+ * Returns: Total length of the target string (length of src) (not including
+ * NUL-termination)
+ *
+ * This function matches in behavior with the strlcpy(3) function in OpenBSD.
+ */
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */

Deleted: vendor/wpa/2.0/src/utils/os_internal.c
===================================================================
--- vendor/wpa/dist/src/utils/os_internal.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/os_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,471 +0,0 @@
-/*
- * wpa_supplicant/hostapd / Internal implementation of OS specific functions
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file is an example of operating system specific  wrapper functions.
- * This version implements many of the functions internally, so it can be used
- * to fill in missing functions from the target system C libraries.
- *
- * Some of the functions are using standard C library calls in order to keep
- * this file in working condition to allow the functions to be tested on a
- * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
- * this file to work correctly. Note that these implementations are only
- * examples and are not optimized for speed.
- */
-
-#include "includes.h"
-
-#undef OS_REJECT_C_LIB_FUNCTIONS
-#include "os.h"
-
-void os_sleep(os_time_t sec, os_time_t usec)
-{
-	if (sec)
-		sleep(sec);
-	if (usec)
-		usleep(usec);
-}
-
-
-int os_get_time(struct os_time *t)
-{
-	int res;
-	struct timeval tv;
-	res = gettimeofday(&tv, NULL);
-	t->sec = tv.tv_sec;
-	t->usec = tv.tv_usec;
-	return res;
-}
-
-
-int os_mktime(int year, int month, int day, int hour, int min, int sec,
-	      os_time_t *t)
-{
-	struct tm tm;
-
-	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
-	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
-	    sec > 60)
-		return -1;
-
-	os_memset(&tm, 0, sizeof(tm));
-	tm.tm_year = year - 1900;
-	tm.tm_mon = month - 1;
-	tm.tm_mday = day;
-	tm.tm_hour = hour;
-	tm.tm_min = min;
-	tm.tm_sec = sec;
-
-	*t = (os_time_t) mktime(&tm);
-	return 0;
-}
-
-
-int os_daemonize(const char *pid_file)
-{
-	if (daemon(0, 0)) {
-		perror("daemon");
-		return -1;
-	}
-
-	if (pid_file) {
-		FILE *f = fopen(pid_file, "w");
-		if (f) {
-			fprintf(f, "%u\n", getpid());
-			fclose(f);
-		}
-	}
-
-	return -0;
-}
-
-
-void os_daemonize_terminate(const char *pid_file)
-{
-	if (pid_file)
-		unlink(pid_file);
-}
-
-
-int os_get_random(unsigned char *buf, size_t len)
-{
-	FILE *f;
-	size_t rc;
-
-	f = fopen("/dev/urandom", "rb");
-	if (f == NULL) {
-		printf("Could not open /dev/urandom.\n");
-		return -1;
-	}
-
-	rc = fread(buf, 1, len, f);
-	fclose(f);
-
-	return rc != len ? -1 : 0;
-}
-
-
-unsigned long os_random(void)
-{
-	return random();
-}
-
-
-char * os_rel2abs_path(const char *rel_path)
-{
-	char *buf = NULL, *cwd, *ret;
-	size_t len = 128, cwd_len, rel_len, ret_len;
-
-	if (rel_path[0] == '/')
-		return os_strdup(rel_path);
-
-	for (;;) {
-		buf = os_malloc(len);
-		if (buf == NULL)
-			return NULL;
-		cwd = getcwd(buf, len);
-		if (cwd == NULL) {
-			os_free(buf);
-			if (errno != ERANGE) {
-				return NULL;
-			}
-			len *= 2;
-		} else {
-			break;
-		}
-	}
-
-	cwd_len = strlen(cwd);
-	rel_len = strlen(rel_path);
-	ret_len = cwd_len + 1 + rel_len + 1;
-	ret = os_malloc(ret_len);
-	if (ret) {
-		os_memcpy(ret, cwd, cwd_len);
-		ret[cwd_len] = '/';
-		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
-		ret[ret_len - 1] = '\0';
-	}
-	os_free(buf);
-	return ret;
-}
-
-
-int os_program_init(void)
-{
-	return 0;
-}
-
-
-void os_program_deinit(void)
-{
-}
-
-
-int os_setenv(const char *name, const char *value, int overwrite)
-{
-	return setenv(name, value, overwrite);
-}
-
-
-int os_unsetenv(const char *name)
-{
-#if defined(__FreeBSD__) || defined(__NetBSD__)
-	unsetenv(name);
-	return 0;
-#else
-	return unsetenv(name);
-#endif
-}
-
-
-char * os_readfile(const char *name, size_t *len)
-{
-	FILE *f;
-	char *buf;
-
-	f = fopen(name, "rb");
-	if (f == NULL)
-		return NULL;
-
-	fseek(f, 0, SEEK_END);
-	*len = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
-	buf = os_malloc(*len);
-	if (buf == NULL) {
-		fclose(f);
-		return NULL;
-	}
-
-	if (fread(buf, 1, *len, f) != *len) {
-		fclose(f);
-		os_free(buf);
-		return NULL;
-	}
-
-	fclose(f);
-
-	return buf;
-}
-
-
-void * os_zalloc(size_t size)
-{
-	void *n = os_malloc(size);
-	if (n)
-		os_memset(n, 0, size);
-	return n;
-}
-
-
-void * os_malloc(size_t size)
-{
-	return malloc(size);
-}
-
-
-void * os_realloc(void *ptr, size_t size)
-{
-	return realloc(ptr, size);
-}
-
-
-void os_free(void *ptr)
-{
-	free(ptr);
-}
-
-
-void * os_memcpy(void *dest, const void *src, size_t n)
-{
-	char *d = dest;
-	const char *s = src;
-	while (n--)
-		*d++ = *s++;
-	return dest;
-}
-
-
-void * os_memmove(void *dest, const void *src, size_t n)
-{
-	if (dest < src)
-		os_memcpy(dest, src, n);
-	else {
-		/* overlapping areas */
-		char *d = (char *) dest + n;
-		const char *s = (const char *) src + n;
-		while (n--)
-			*--d = *--s;
-	}
-	return dest;
-}
-
-
-void * os_memset(void *s, int c, size_t n)
-{
-	char *p = s;
-	while (n--)
-		*p++ = c;
-	return s;
-}
-
-
-int os_memcmp(const void *s1, const void *s2, size_t n)
-{
-	const unsigned char *p1 = s1, *p2 = s2;
-
-	if (n == 0)
-		return 0;
-
-	while (*p1 == *p2) {
-		p1++;
-		p2++;
-		n--;
-		if (n == 0)
-			return 0;
-	}
-
-	return *p1 - *p2;
-}
-
-
-char * os_strdup(const char *s)
-{
-	char *res;
-	size_t len;
-	if (s == NULL)
-		return NULL;
-	len = os_strlen(s);
-	res = os_malloc(len + 1);
-	if (res)
-		os_memcpy(res, s, len + 1);
-	return res;
-}
-
-
-size_t os_strlen(const char *s)
-{
-	const char *p = s;
-	while (*p)
-		p++;
-	return p - s;
-}
-
-
-int os_strcasecmp(const char *s1, const char *s2)
-{
-	/*
-	 * Ignoring case is not required for main functionality, so just use
-	 * the case sensitive version of the function.
-	 */
-	return os_strcmp(s1, s2);
-}
-
-
-int os_strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	/*
-	 * Ignoring case is not required for main functionality, so just use
-	 * the case sensitive version of the function.
-	 */
-	return os_strncmp(s1, s2, n);
-}
-
-
-char * os_strchr(const char *s, int c)
-{
-	while (*s) {
-		if (*s == c)
-			return (char *) s;
-		s++;
-	}
-	return NULL;
-}
-
-
-char * os_strrchr(const char *s, int c)
-{
-	const char *p = s;
-	while (*p)
-		p++;
-	p--;
-	while (p >= s) {
-		if (*p == c)
-			return (char *) p;
-		p--;
-	}
-	return NULL;
-}
-
-
-int os_strcmp(const char *s1, const char *s2)
-{
-	while (*s1 == *s2) {
-		if (*s1 == '\0')
-			break;
-		s1++;
-		s2++;
-	}
-
-	return *s1 - *s2;
-}
-
-
-int os_strncmp(const char *s1, const char *s2, size_t n)
-{
-	if (n == 0)
-		return 0;
-
-	while (*s1 == *s2) {
-		if (*s1 == '\0')
-			break;
-		s1++;
-		s2++;
-		n--;
-		if (n == 0)
-			return 0;
-	}
-
-	return *s1 - *s2;
-}
-
-
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
-	char *d = dest;
-
-	while (n--) {
-		*d = *src;
-		if (*src == '\0')
-			break;
-		d++;
-		src++;
-	}
-
-	return dest;
-}
-
-
-size_t os_strlcpy(char *dest, const char *src, size_t siz)
-{
-	const char *s = src;
-	size_t left = siz;
-
-	if (left) {
-		/* Copy string up to the maximum size of the dest buffer */
-		while (--left != 0) {
-			if ((*dest++ = *s++) == '\0')
-				break;
-		}
-	}
-
-	if (left == 0) {
-		/* Not enough room for the string; force NUL-termination */
-		if (siz != 0)
-			*dest = '\0';
-		while (*s++)
-			; /* determine total src string length */
-	}
-
-	return s - src - 1;
-}
-
-
-char * os_strstr(const char *haystack, const char *needle)
-{
-	size_t len = os_strlen(needle);
-	while (*haystack) {
-		if (os_strncmp(haystack, needle, len) == 0)
-			return (char *) haystack;
-		haystack++;
-	}
-
-	return NULL;
-}
-
-
-int os_snprintf(char *str, size_t size, const char *format, ...)
-{
-	va_list ap;
-	int ret;
-
-	/* See http://www.ijs.si/software/snprintf/ for portable
-	 * implementation of snprintf.
-	 */
-
-	va_start(ap, format);
-	ret = vsnprintf(str, size, format, ap);
-	va_end(ap);
-	if (size > 0)
-		str[size - 1] = '\0';
-	return ret;
-}

Copied: vendor/wpa/2.0/src/utils/os_internal.c (from rev 9639, vendor/wpa/dist/src/utils/os_internal.c)
===================================================================
--- vendor/wpa/2.0/src/utils/os_internal.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/os_internal.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,483 @@
+/*
+ * wpa_supplicant/hostapd / Internal implementation of OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file is an example of operating system specific  wrapper functions.
+ * This version implements many of the functions internally, so it can be used
+ * to fill in missing functions from the target system C libraries.
+ *
+ * Some of the functions are using standard C library calls in order to keep
+ * this file in working condition to allow the functions to be tested on a
+ * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
+ * this file to work correctly. Note that these implementations are only
+ * examples and are not optimized for speed.
+ */
+
+#include "includes.h"
+
+#undef OS_REJECT_C_LIB_FUNCTIONS
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		sleep(sec);
+	if (usec)
+		usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	os_memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	*t = (os_time_t) mktime(&tm);
+	return 0;
+}
+
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	if (daemon(0, 0)) {
+		perror("daemon");
+		return -1;
+	}
+
+	if (pid_file) {
+		FILE *f = fopen(pid_file, "w");
+		if (f) {
+			fprintf(f, "%u\n", getpid());
+			fclose(f);
+		}
+	}
+
+	return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+	if (pid_file)
+		unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "rb");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+	return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	char *buf = NULL, *cwd, *ret;
+	size_t len = 128, cwd_len, rel_len, ret_len;
+
+	if (rel_path[0] == '/')
+		return os_strdup(rel_path);
+
+	for (;;) {
+		buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		cwd = getcwd(buf, len);
+		if (cwd == NULL) {
+			os_free(buf);
+			if (errno != ERANGE) {
+				return NULL;
+			}
+			len *= 2;
+		} else {
+			break;
+		}
+	}
+
+	cwd_len = strlen(cwd);
+	rel_len = strlen(rel_path);
+	ret_len = cwd_len + 1 + rel_len + 1;
+	ret = os_malloc(ret_len);
+	if (ret) {
+		os_memcpy(ret, cwd, cwd_len);
+		ret[cwd_len] = '/';
+		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+		ret[ret_len - 1] = '\0';
+	}
+	os_free(buf);
+	return ret;
+}
+
+
+int os_program_init(void)
+{
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+	unsetenv(name);
+	return 0;
+#else
+	return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	fseek(f, 0, SEEK_END);
+	*len = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	buf = os_malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	if (fread(buf, 1, *len, f) != *len) {
+		fclose(f);
+		os_free(buf);
+		return NULL;
+	}
+
+	fclose(f);
+
+	return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	void *n = os_malloc(size);
+	if (n)
+		os_memset(n, 0, size);
+	return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+	free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+	char *d = dest;
+	const char *s = src;
+	while (n--)
+		*d++ = *s++;
+	return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+	if (dest < src)
+		os_memcpy(dest, src, n);
+	else {
+		/* overlapping areas */
+		char *d = (char *) dest + n;
+		const char *s = (const char *) src + n;
+		while (n--)
+			*--d = *--s;
+	}
+	return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+	char *p = s;
+	while (n--)
+		*p++ = c;
+	return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+	const unsigned char *p1 = s1, *p2 = s2;
+
+	if (n == 0)
+		return 0;
+
+	while (*p1 == *p2) {
+		p1++;
+		p2++;
+		n--;
+		if (n == 0)
+			return 0;
+	}
+
+	return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+	char *res;
+	size_t len;
+	if (s == NULL)
+		return NULL;
+	len = os_strlen(s);
+	res = os_malloc(len + 1);
+	if (res)
+		os_memcpy(res, s, len + 1);
+	return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+	const char *p = s;
+	while (*p)
+		p++;
+	return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+	while (*s) {
+		if (*s == c)
+			return (char *) s;
+		s++;
+	}
+	return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+	const char *p = s;
+	while (*p)
+		p++;
+	p--;
+	while (p >= s) {
+		if (*p == c)
+			return (char *) p;
+		p--;
+	}
+	return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+	while (*s1 == *s2) {
+		if (*s1 == '\0')
+			break;
+		s1++;
+		s2++;
+	}
+
+	return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+	if (n == 0)
+		return 0;
+
+	while (*s1 == *s2) {
+		if (*s1 == '\0')
+			break;
+		s1++;
+		s2++;
+		n--;
+		if (n == 0)
+			return 0;
+	}
+
+	return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+	char *d = dest;
+
+	while (n--) {
+		*d = *src;
+		if (*src == '\0')
+			break;
+		d++;
+		src++;
+	}
+
+	return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+	const char *s = src;
+	size_t left = siz;
+
+	if (left) {
+		/* Copy string up to the maximum size of the dest buffer */
+		while (--left != 0) {
+			if ((*dest++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	if (left == 0) {
+		/* Not enough room for the string; force NUL-termination */
+		if (siz != 0)
+			*dest = '\0';
+		while (*s++)
+			; /* determine total src string length */
+	}
+
+	return s - src - 1;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+	size_t len = os_strlen(needle);
+	while (*haystack) {
+		if (os_strncmp(haystack, needle, len) == 0)
+			return (char *) haystack;
+		haystack++;
+	}
+
+	return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+
+	/* See http://www.ijs.si/software/snprintf/ for portable
+	 * implementation of snprintf.
+	 */
+
+	va_start(ap, format);
+	ret = vsnprintf(str, size, format, ap);
+	va_end(ap);
+	if (size > 0)
+		str[size - 1] = '\0';
+	return ret;
+}

Deleted: vendor/wpa/2.0/src/utils/os_none.c
===================================================================
--- vendor/wpa/dist/src/utils/os_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/os_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,226 +0,0 @@
-/*
- * wpa_supplicant/hostapd / Empty OS specific functions
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file can be used as a starting point when adding a new OS target. The
- * functions here do not really work as-is since they are just empty or only
- * return an error value. os_internal.c can be used as another starting point
- * or reference since it has example implementation of many of these functions.
- */
-
-#include "includes.h"
-
-#include "os.h"
-
-void os_sleep(os_time_t sec, os_time_t usec)
-{
-}
-
-
-int os_get_time(struct os_time *t)
-{
-	return -1;
-}
-
-
-int os_mktime(int year, int month, int day, int hour, int min, int sec,
-	      os_time_t *t)
-{
-	return -1;
-}
-
-
-int os_daemonize(const char *pid_file)
-{
-	return -1;
-}
-
-
-void os_daemonize_terminate(const char *pid_file)
-{
-}
-
-
-int os_get_random(unsigned char *buf, size_t len)
-{
-	return -1;
-}
-
-
-unsigned long os_random(void)
-{
-	return 0;
-}
-
-
-char * os_rel2abs_path(const char *rel_path)
-{
-	return NULL; /* strdup(rel_path) can be used here */
-}
-
-
-int os_program_init(void)
-{
-	return 0;
-}
-
-
-void os_program_deinit(void)
-{
-}
-
-
-int os_setenv(const char *name, const char *value, int overwrite)
-{
-	return -1;
-}
-
-
-int os_unsetenv(const char *name)
-{
-	return -1;
-}
-
-
-char * os_readfile(const char *name, size_t *len)
-{
-	return NULL;
-}
-
-
-void * os_zalloc(size_t size)
-{
-	return NULL;
-}
-
-
-#ifdef OS_NO_C_LIB_DEFINES
-void * os_malloc(size_t size)
-{
-	return NULL;
-}
-
-
-void * os_realloc(void *ptr, size_t size)
-{
-	return NULL;
-}
-
-
-void os_free(void *ptr)
-{
-}
-
-
-void * os_memcpy(void *dest, const void *src, size_t n)
-{
-	return dest;
-}
-
-
-void * os_memmove(void *dest, const void *src, size_t n)
-{
-	return dest;
-}
-
-
-void * os_memset(void *s, int c, size_t n)
-{
-	return s;
-}
-
-
-int os_memcmp(const void *s1, const void *s2, size_t n)
-{
-	return 0;
-}
-
-
-char * os_strdup(const char *s)
-{
-	return NULL;
-}
-
-
-size_t os_strlen(const char *s)
-{
-	return 0;
-}
-
-
-int os_strcasecmp(const char *s1, const char *s2)
-{
-	/*
-	 * Ignoring case is not required for main functionality, so just use
-	 * the case sensitive version of the function.
-	 */
-	return os_strcmp(s1, s2);
-}
-
-
-int os_strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	/*
-	 * Ignoring case is not required for main functionality, so just use
-	 * the case sensitive version of the function.
-	 */
-	return os_strncmp(s1, s2, n);
-}
-
-
-char * os_strchr(const char *s, int c)
-{
-	return NULL;
-}
-
-
-char * os_strrchr(const char *s, int c)
-{
-	return NULL;
-}
-
-
-int os_strcmp(const char *s1, const char *s2)
-{
-	return 0;
-}
-
-
-int os_strncmp(const char *s1, const char *s2, size_t n)
-{
-	return 0;
-}
-
-
-char * os_strncpy(char *dest, const char *src, size_t n)
-{
-	return dest;
-}
-
-
-size_t os_strlcpy(char *dest, const char *src, size_t size)
-{
-	return 0;
-}
-
-
-char * os_strstr(const char *haystack, const char *needle)
-{
-	return NULL;
-}
-
-
-int os_snprintf(char *str, size_t size, const char *format, ...)
-{
-	return 0;
-}
-#endif /* OS_NO_C_LIB_DEFINES */

Copied: vendor/wpa/2.0/src/utils/os_none.c (from rev 9639, vendor/wpa/dist/src/utils/os_none.c)
===================================================================
--- vendor/wpa/2.0/src/utils/os_none.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/os_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,225 @@
+/*
+ * wpa_supplicant/hostapd / Empty OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file can be used as a starting point when adding a new OS target. The
+ * functions here do not really work as-is since they are just empty or only
+ * return an error value. os_internal.c can be used as another starting point
+ * or reference since it has example implementation of many of these functions.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	return -1;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	return -1;
+}
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	return -1;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	return -1;
+}
+
+
+unsigned long os_random(void)
+{
+	return 0;
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	return NULL; /* strdup(rel_path) can be used here */
+}
+
+
+int os_program_init(void)
+{
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+	return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	return NULL;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	return NULL;
+}
+
+
+#ifdef OS_NO_C_LIB_DEFINES
+void * os_malloc(size_t size)
+{
+	return NULL;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	return NULL;
+}
+
+
+void os_free(void *ptr)
+{
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+	return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+	return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+	return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+	return 0;
+}
+
+
+char * os_strdup(const char *s)
+{
+	return NULL;
+}
+
+
+size_t os_strlen(const char *s)
+{
+	return 0;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+	return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+	return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+	return 0;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+	return 0;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+	return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t size)
+{
+	return 0;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+	return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+	return 0;
+}
+#endif /* OS_NO_C_LIB_DEFINES */

Deleted: vendor/wpa/2.0/src/utils/os_unix.c
===================================================================
--- vendor/wpa/dist/src/utils/os_unix.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/os_unix.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,437 +0,0 @@
-/*
- * OS specific functions for UNIX/POSIX systems
- * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "os.h"
-
-#ifdef WPA_TRACE
-
-#include "common.h"
-#include "list.h"
-#include "wpa_debug.h"
-#include "trace.h"
-
-static struct dl_list alloc_list;
-
-#define ALLOC_MAGIC 0xa84ef1b2
-#define FREED_MAGIC 0x67fd487a
-
-struct os_alloc_trace {
-	unsigned int magic;
-	struct dl_list list;
-	size_t len;
-	WPA_TRACE_INFO
-};
-
-#endif /* WPA_TRACE */
-
-
-void os_sleep(os_time_t sec, os_time_t usec)
-{
-	if (sec)
-		sleep(sec);
-	if (usec)
-		usleep(usec);
-}
-
-
-int os_get_time(struct os_time *t)
-{
-	int res;
-	struct timeval tv;
-	res = gettimeofday(&tv, NULL);
-	t->sec = tv.tv_sec;
-	t->usec = tv.tv_usec;
-	return res;
-}
-
-
-int os_mktime(int year, int month, int day, int hour, int min, int sec,
-	      os_time_t *t)
-{
-	struct tm tm, *tm1;
-	time_t t_local, t1, t2;
-	os_time_t tz_offset;
-
-	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
-	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
-	    sec > 60)
-		return -1;
-
-	memset(&tm, 0, sizeof(tm));
-	tm.tm_year = year - 1900;
-	tm.tm_mon = month - 1;
-	tm.tm_mday = day;
-	tm.tm_hour = hour;
-	tm.tm_min = min;
-	tm.tm_sec = sec;
-
-	t_local = mktime(&tm);
-
-	/* figure out offset to UTC */
-	tm1 = localtime(&t_local);
-	if (tm1) {
-		t1 = mktime(tm1);
-		tm1 = gmtime(&t_local);
-		if (tm1) {
-			t2 = mktime(tm1);
-			tz_offset = t2 - t1;
-		} else
-			tz_offset = 0;
-	} else
-		tz_offset = 0;
-
-	*t = (os_time_t) t_local - tz_offset;
-	return 0;
-}
-
-
-#ifdef __APPLE__
-#include <fcntl.h>
-static int os_daemon(int nochdir, int noclose)
-{
-	int devnull;
-
-	if (chdir("/") < 0)
-		return -1;
-
-	devnull = open("/dev/null", O_RDWR);
-	if (devnull < 0)
-		return -1;
-
-	if (dup2(devnull, STDIN_FILENO) < 0) {
-		close(devnull);
-		return -1;
-	}
-
-	if (dup2(devnull, STDOUT_FILENO) < 0) {
-		close(devnull);
-		return -1;
-	}
-
-	if (dup2(devnull, STDERR_FILENO) < 0) {
-		close(devnull);
-		return -1;
-	}
-
-	return 0;
-}
-#else /* __APPLE__ */
-#define os_daemon daemon
-#endif /* __APPLE__ */
-
-
-int os_daemonize(const char *pid_file)
-{
-#ifdef __uClinux__
-	return -1;
-#else /* __uClinux__ */
-	if (os_daemon(0, 0)) {
-		perror("daemon");
-		return -1;
-	}
-
-	if (pid_file) {
-		FILE *f = fopen(pid_file, "w");
-		if (f) {
-			fprintf(f, "%u\n", getpid());
-			fclose(f);
-		}
-	}
-
-	return -0;
-#endif /* __uClinux__ */
-}
-
-
-void os_daemonize_terminate(const char *pid_file)
-{
-	if (pid_file)
-		unlink(pid_file);
-}
-
-
-int os_get_random(unsigned char *buf, size_t len)
-{
-	FILE *f;
-	size_t rc;
-
-	f = fopen("/dev/urandom", "rb");
-	if (f == NULL) {
-		printf("Could not open /dev/urandom.\n");
-		return -1;
-	}
-
-	rc = fread(buf, 1, len, f);
-	fclose(f);
-
-	return rc != len ? -1 : 0;
-}
-
-
-unsigned long os_random(void)
-{
-	return random();
-}
-
-
-char * os_rel2abs_path(const char *rel_path)
-{
-	char *buf = NULL, *cwd, *ret;
-	size_t len = 128, cwd_len, rel_len, ret_len;
-	int last_errno;
-
-	if (rel_path[0] == '/')
-		return os_strdup(rel_path);
-
-	for (;;) {
-		buf = os_malloc(len);
-		if (buf == NULL)
-			return NULL;
-		cwd = getcwd(buf, len);
-		if (cwd == NULL) {
-			last_errno = errno;
-			os_free(buf);
-			if (last_errno != ERANGE)
-				return NULL;
-			len *= 2;
-			if (len > 2000)
-				return NULL;
-		} else {
-			buf[len - 1] = '\0';
-			break;
-		}
-	}
-
-	cwd_len = os_strlen(cwd);
-	rel_len = os_strlen(rel_path);
-	ret_len = cwd_len + 1 + rel_len + 1;
-	ret = os_malloc(ret_len);
-	if (ret) {
-		os_memcpy(ret, cwd, cwd_len);
-		ret[cwd_len] = '/';
-		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
-		ret[ret_len - 1] = '\0';
-	}
-	os_free(buf);
-	return ret;
-}
-
-
-int os_program_init(void)
-{
-#ifdef WPA_TRACE
-	dl_list_init(&alloc_list);
-#endif /* WPA_TRACE */
-	return 0;
-}
-
-
-void os_program_deinit(void)
-{
-#ifdef WPA_TRACE
-	struct os_alloc_trace *a;
-	unsigned long total = 0;
-	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
-		total += a->len;
-		if (a->magic != ALLOC_MAGIC) {
-			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
-				   "len %lu",
-				   a, a->magic, (unsigned long) a->len);
-			continue;
-		}
-		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
-			   a, (unsigned long) a->len);
-		wpa_trace_dump("memleak", a);
-	}
-	if (total)
-		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
-			   (unsigned long) total);
-#endif /* WPA_TRACE */
-}
-
-
-int os_setenv(const char *name, const char *value, int overwrite)
-{
-	return setenv(name, value, overwrite);
-}
-
-
-int os_unsetenv(const char *name)
-{
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
-    defined(__OpenBSD__)
-	unsetenv(name);
-	return 0;
-#else
-	return unsetenv(name);
-#endif
-}
-
-
-char * os_readfile(const char *name, size_t *len)
-{
-	FILE *f;
-	char *buf;
-
-	f = fopen(name, "rb");
-	if (f == NULL)
-		return NULL;
-
-	fseek(f, 0, SEEK_END);
-	*len = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
-	buf = os_malloc(*len);
-	if (buf == NULL) {
-		fclose(f);
-		return NULL;
-	}
-
-	if (fread(buf, 1, *len, f) != *len) {
-		fclose(f);
-		os_free(buf);
-		return NULL;
-	}
-
-	fclose(f);
-
-	return buf;
-}
-
-
-#ifndef WPA_TRACE
-void * os_zalloc(size_t size)
-{
-	return calloc(1, size);
-}
-#endif /* WPA_TRACE */
-
-
-size_t os_strlcpy(char *dest, const char *src, size_t siz)
-{
-	const char *s = src;
-	size_t left = siz;
-
-	if (left) {
-		/* Copy string up to the maximum size of the dest buffer */
-		while (--left != 0) {
-			if ((*dest++ = *s++) == '\0')
-				break;
-		}
-	}
-
-	if (left == 0) {
-		/* Not enough room for the string; force NUL-termination */
-		if (siz != 0)
-			*dest = '\0';
-		while (*s++)
-			; /* determine total src string length */
-	}
-
-	return s - src - 1;
-}
-
-
-#ifdef WPA_TRACE
-
-void * os_malloc(size_t size)
-{
-	struct os_alloc_trace *a;
-	a = malloc(sizeof(*a) + size);
-	if (a == NULL)
-		return NULL;
-	a->magic = ALLOC_MAGIC;
-	dl_list_add(&alloc_list, &a->list);
-	a->len = size;
-	wpa_trace_record(a);
-	return a + 1;
-}
-
-
-void * os_realloc(void *ptr, size_t size)
-{
-	struct os_alloc_trace *a;
-	size_t copy_len;
-	void *n;
-
-	if (ptr == NULL)
-		return os_malloc(size);
-
-	a = (struct os_alloc_trace *) ptr - 1;
-	if (a->magic != ALLOC_MAGIC) {
-		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
-			   a, a->magic,
-			   a->magic == FREED_MAGIC ? " (already freed)" : "");
-		wpa_trace_show("Invalid os_realloc() call");
-		abort();
-	}
-	n = os_malloc(size);
-	if (n == NULL)
-		return NULL;
-	copy_len = a->len;
-	if (copy_len > size)
-		copy_len = size;
-	os_memcpy(n, a + 1, copy_len);
-	os_free(ptr);
-	return n;
-}
-
-
-void os_free(void *ptr)
-{
-	struct os_alloc_trace *a;
-
-	if (ptr == NULL)
-		return;
-	a = (struct os_alloc_trace *) ptr - 1;
-	if (a->magic != ALLOC_MAGIC) {
-		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
-			   a, a->magic,
-			   a->magic == FREED_MAGIC ? " (already freed)" : "");
-		wpa_trace_show("Invalid os_free() call");
-		abort();
-	}
-	dl_list_del(&a->list);
-	a->magic = FREED_MAGIC;
-
-	wpa_trace_check_ref(ptr);
-	free(a);
-}
-
-
-void * os_zalloc(size_t size)
-{
-	void *ptr = os_malloc(size);
-	if (ptr)
-		os_memset(ptr, 0, size);
-	return ptr;
-}
-
-
-char * os_strdup(const char *s)
-{
-	size_t len;
-	char *d;
-	len = os_strlen(s);
-	d = os_malloc(len + 1);
-	if (d == NULL)
-		return NULL;
-	os_memcpy(d, s, len);
-	d[len] = '\0';
-	return d;
-}
-
-#endif /* WPA_TRACE */

Copied: vendor/wpa/2.0/src/utils/os_unix.c (from rev 9639, vendor/wpa/dist/src/utils/os_unix.c)
===================================================================
--- vendor/wpa/2.0/src/utils/os_unix.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/os_unix.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,488 @@
+/*
+ * OS specific functions for UNIX/POSIX systems
+ * Copyright (c) 2005-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include <time.h>
+
+#ifdef ANDROID
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif /* ANDROID */
+
+#include "os.h"
+
+#ifdef WPA_TRACE
+
+#include "common.h"
+#include "wpa_debug.h"
+#include "trace.h"
+#include "list.h"
+
+static struct dl_list alloc_list;
+
+#define ALLOC_MAGIC 0xa84ef1b2
+#define FREED_MAGIC 0x67fd487a
+
+struct os_alloc_trace {
+	unsigned int magic;
+	struct dl_list list;
+	size_t len;
+	WPA_TRACE_INFO
+};
+
+#endif /* WPA_TRACE */
+
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		sleep(sec);
+	if (usec)
+		usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm, *tm1;
+	time_t t_local, t1, t2;
+	os_time_t tz_offset;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	t_local = mktime(&tm);
+
+	/* figure out offset to UTC */
+	tm1 = localtime(&t_local);
+	if (tm1) {
+		t1 = mktime(tm1);
+		tm1 = gmtime(&t_local);
+		if (tm1) {
+			t2 = mktime(tm1);
+			tz_offset = t2 - t1;
+		} else
+			tz_offset = 0;
+	} else
+		tz_offset = 0;
+
+	*t = (os_time_t) t_local - tz_offset;
+	return 0;
+}
+
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
+#ifdef __APPLE__
+#include <fcntl.h>
+static int os_daemon(int nochdir, int noclose)
+{
+	int devnull;
+
+	if (chdir("/") < 0)
+		return -1;
+
+	devnull = open("/dev/null", O_RDWR);
+	if (devnull < 0)
+		return -1;
+
+	if (dup2(devnull, STDIN_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	if (dup2(devnull, STDOUT_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	if (dup2(devnull, STDERR_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	return 0;
+}
+#else /* __APPLE__ */
+#define os_daemon daemon
+#endif /* __APPLE__ */
+
+
+int os_daemonize(const char *pid_file)
+{
+#if defined(__uClinux__) || defined(__sun__)
+	return -1;
+#else /* defined(__uClinux__) || defined(__sun__) */
+	if (os_daemon(0, 0)) {
+		perror("daemon");
+		return -1;
+	}
+
+	if (pid_file) {
+		FILE *f = fopen(pid_file, "w");
+		if (f) {
+			fprintf(f, "%u\n", getpid());
+			fclose(f);
+		}
+	}
+
+	return -0;
+#endif /* defined(__uClinux__) || defined(__sun__) */
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+	if (pid_file)
+		unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "rb");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+	return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	char *buf = NULL, *cwd, *ret;
+	size_t len = 128, cwd_len, rel_len, ret_len;
+	int last_errno;
+
+	if (rel_path[0] == '/')
+		return os_strdup(rel_path);
+
+	for (;;) {
+		buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		cwd = getcwd(buf, len);
+		if (cwd == NULL) {
+			last_errno = errno;
+			os_free(buf);
+			if (last_errno != ERANGE)
+				return NULL;
+			len *= 2;
+			if (len > 2000)
+				return NULL;
+		} else {
+			buf[len - 1] = '\0';
+			break;
+		}
+	}
+
+	cwd_len = os_strlen(cwd);
+	rel_len = os_strlen(rel_path);
+	ret_len = cwd_len + 1 + rel_len + 1;
+	ret = os_malloc(ret_len);
+	if (ret) {
+		os_memcpy(ret, cwd, cwd_len);
+		ret[cwd_len] = '/';
+		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+		ret[ret_len - 1] = '\0';
+	}
+	os_free(buf);
+	return ret;
+}
+
+
+int os_program_init(void)
+{
+#ifdef ANDROID
+	/*
+	 * We ignore errors here since errors are normal if we
+	 * are already running as non-root.
+	 */
+	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+
+	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+
+	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+	setgid(AID_WIFI);
+	setuid(AID_WIFI);
+
+	header.version = _LINUX_CAPABILITY_VERSION;
+	header.pid = 0;
+	cap.effective = cap.permitted =
+		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+	cap.inheritable = 0;
+	capset(&header, &cap);
+#endif /* ANDROID */
+
+#ifdef WPA_TRACE
+	dl_list_init(&alloc_list);
+#endif /* WPA_TRACE */
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef WPA_TRACE
+	struct os_alloc_trace *a;
+	unsigned long total = 0;
+	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
+		total += a->len;
+		if (a->magic != ALLOC_MAGIC) {
+			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
+				   "len %lu",
+				   a, a->magic, (unsigned long) a->len);
+			continue;
+		}
+		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
+			   a, (unsigned long) a->len);
+		wpa_trace_dump("memleak", a);
+	}
+	if (total)
+		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
+			   (unsigned long) total);
+#endif /* WPA_TRACE */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
+    defined(__OpenBSD__)
+	unsetenv(name);
+	return 0;
+#else
+	return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+	long pos;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+		fclose(f);
+		return NULL;
+	}
+	*len = pos;
+	if (fseek(f, 0, SEEK_SET) < 0) {
+		fclose(f);
+		return NULL;
+	}
+
+	buf = os_malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	if (fread(buf, 1, *len, f) != *len) {
+		fclose(f);
+		os_free(buf);
+		return NULL;
+	}
+
+	fclose(f);
+
+	return buf;
+}
+
+
+#ifndef WPA_TRACE
+void * os_zalloc(size_t size)
+{
+	return calloc(1, size);
+}
+#endif /* WPA_TRACE */
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+	const char *s = src;
+	size_t left = siz;
+
+	if (left) {
+		/* Copy string up to the maximum size of the dest buffer */
+		while (--left != 0) {
+			if ((*dest++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	if (left == 0) {
+		/* Not enough room for the string; force NUL-termination */
+		if (siz != 0)
+			*dest = '\0';
+		while (*s++)
+			; /* determine total src string length */
+	}
+
+	return s - src - 1;
+}
+
+
+#ifdef WPA_TRACE
+
+void * os_malloc(size_t size)
+{
+	struct os_alloc_trace *a;
+	a = malloc(sizeof(*a) + size);
+	if (a == NULL)
+		return NULL;
+	a->magic = ALLOC_MAGIC;
+	dl_list_add(&alloc_list, &a->list);
+	a->len = size;
+	wpa_trace_record(a);
+	return a + 1;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	struct os_alloc_trace *a;
+	size_t copy_len;
+	void *n;
+
+	if (ptr == NULL)
+		return os_malloc(size);
+
+	a = (struct os_alloc_trace *) ptr - 1;
+	if (a->magic != ALLOC_MAGIC) {
+		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
+			   a, a->magic,
+			   a->magic == FREED_MAGIC ? " (already freed)" : "");
+		wpa_trace_show("Invalid os_realloc() call");
+		abort();
+	}
+	n = os_malloc(size);
+	if (n == NULL)
+		return NULL;
+	copy_len = a->len;
+	if (copy_len > size)
+		copy_len = size;
+	os_memcpy(n, a + 1, copy_len);
+	os_free(ptr);
+	return n;
+}
+
+
+void os_free(void *ptr)
+{
+	struct os_alloc_trace *a;
+
+	if (ptr == NULL)
+		return;
+	a = (struct os_alloc_trace *) ptr - 1;
+	if (a->magic != ALLOC_MAGIC) {
+		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
+			   a, a->magic,
+			   a->magic == FREED_MAGIC ? " (already freed)" : "");
+		wpa_trace_show("Invalid os_free() call");
+		abort();
+	}
+	dl_list_del(&a->list);
+	a->magic = FREED_MAGIC;
+
+	wpa_trace_check_ref(ptr);
+	free(a);
+}
+
+
+void * os_zalloc(size_t size)
+{
+	void *ptr = os_malloc(size);
+	if (ptr)
+		os_memset(ptr, 0, size);
+	return ptr;
+}
+
+
+char * os_strdup(const char *s)
+{
+	size_t len;
+	char *d;
+	len = os_strlen(s);
+	d = os_malloc(len + 1);
+	if (d == NULL)
+		return NULL;
+	os_memcpy(d, s, len);
+	d[len] = '\0';
+	return d;
+}
+
+#endif /* WPA_TRACE */

Deleted: vendor/wpa/2.0/src/utils/os_win32.c
===================================================================
--- vendor/wpa/dist/src/utils/os_win32.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/os_win32.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,222 +0,0 @@
-/*
- * wpa_supplicant/hostapd / OS specific functions for Win32 systems
- * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <winsock2.h>
-#include <wincrypt.h>
-
-#include "os.h"
-
-void os_sleep(os_time_t sec, os_time_t usec)
-{
-	if (sec)
-		Sleep(sec * 1000);
-	if (usec)
-		Sleep(usec / 1000);
-}
-
-
-int os_get_time(struct os_time *t)
-{
-#define EPOCHFILETIME (116444736000000000ULL)
-	FILETIME ft;
-	LARGE_INTEGER li;
-	ULONGLONG tt;
-
-#ifdef _WIN32_WCE
-	SYSTEMTIME st;
-
-	GetSystemTime(&st);
-	SystemTimeToFileTime(&st, &ft);
-#else /* _WIN32_WCE */
-	GetSystemTimeAsFileTime(&ft);
-#endif /* _WIN32_WCE */
-	li.LowPart = ft.dwLowDateTime;
-	li.HighPart = ft.dwHighDateTime;
-	tt = (li.QuadPart - EPOCHFILETIME) / 10;
-	t->sec = (os_time_t) (tt / 1000000);
-	t->usec = (os_time_t) (tt % 1000000);
-
-	return 0;
-}
-
-
-int os_mktime(int year, int month, int day, int hour, int min, int sec,
-	      os_time_t *t)
-{
-	struct tm tm, *tm1;
-	time_t t_local, t1, t2;
-	os_time_t tz_offset;
-
-	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
-	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
-	    sec > 60)
-		return -1;
-
-	memset(&tm, 0, sizeof(tm));
-	tm.tm_year = year - 1900;
-	tm.tm_mon = month - 1;
-	tm.tm_mday = day;
-	tm.tm_hour = hour;
-	tm.tm_min = min;
-	tm.tm_sec = sec;
-
-	t_local = mktime(&tm);
-
-	/* figure out offset to UTC */
-	tm1 = localtime(&t_local);
-	if (tm1) {
-		t1 = mktime(tm1);
-		tm1 = gmtime(&t_local);
-		if (tm1) {
-			t2 = mktime(tm1);
-			tz_offset = t2 - t1;
-		} else
-			tz_offset = 0;
-	} else
-		tz_offset = 0;
-
-	*t = (os_time_t) t_local - tz_offset;
-	return 0;
-}
-
-
-int os_daemonize(const char *pid_file)
-{
-	/* TODO */
-	return -1;
-}
-
-
-void os_daemonize_terminate(const char *pid_file)
-{
-}
-
-
-int os_get_random(unsigned char *buf, size_t len)
-{
-	HCRYPTPROV prov;
-	BOOL ret;
-
-	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
-				 CRYPT_VERIFYCONTEXT))
-		return -1;
-
-	ret = CryptGenRandom(prov, len, buf);
-	CryptReleaseContext(prov, 0);
-
-	return ret ? 0 : -1;
-}
-
-
-unsigned long os_random(void)
-{
-	return rand();
-}
-
-
-char * os_rel2abs_path(const char *rel_path)
-{
-	return _strdup(rel_path);
-}
-
-
-int os_program_init(void)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
-	WSADATA wsaData;
-	if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
-		printf("Could not find a usable WinSock.dll\n");
-		return -1;
-	}
-#endif /* CONFIG_NATIVE_WINDOWS */
-	return 0;
-}
-
-
-void os_program_deinit(void)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
-	WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-int os_setenv(const char *name, const char *value, int overwrite)
-{
-	return -1;
-}
-
-
-int os_unsetenv(const char *name)
-{
-	return -1;
-}
-
-
-char * os_readfile(const char *name, size_t *len)
-{
-	FILE *f;
-	char *buf;
-
-	f = fopen(name, "rb");
-	if (f == NULL)
-		return NULL;
-
-	fseek(f, 0, SEEK_END);
-	*len = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
-	buf = malloc(*len);
-	if (buf == NULL) {
-		fclose(f);
-		return NULL;
-	}
-
-	fread(buf, 1, *len, f);
-	fclose(f);
-
-	return buf;
-}
-
-
-void * os_zalloc(size_t size)
-{
-	return calloc(1, size);
-}
-
-
-size_t os_strlcpy(char *dest, const char *src, size_t siz)
-{
-	const char *s = src;
-	size_t left = siz;
-
-	if (left) {
-		/* Copy string up to the maximum size of the dest buffer */
-		while (--left != 0) {
-			if ((*dest++ = *s++) == '\0')
-				break;
-		}
-	}
-
-	if (left == 0) {
-		/* Not enough room for the string; force NUL-termination */
-		if (siz != 0)
-			*dest = '\0';
-		while (*s++)
-			; /* determine total src string length */
-	}
-
-	return s - src - 1;
-}

Copied: vendor/wpa/2.0/src/utils/os_win32.c (from rev 9639, vendor/wpa/dist/src/utils/os_win32.c)
===================================================================
--- vendor/wpa/2.0/src/utils/os_win32.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/os_win32.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,235 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions for Win32 systems
+ * Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <time.h>
+#include <winsock2.h>
+#include <wincrypt.h>
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		Sleep(sec * 1000);
+	if (usec)
+		Sleep(usec / 1000);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+#define EPOCHFILETIME (116444736000000000ULL)
+	FILETIME ft;
+	LARGE_INTEGER li;
+	ULONGLONG tt;
+
+#ifdef _WIN32_WCE
+	SYSTEMTIME st;
+
+	GetSystemTime(&st);
+	SystemTimeToFileTime(&st, &ft);
+#else /* _WIN32_WCE */
+	GetSystemTimeAsFileTime(&ft);
+#endif /* _WIN32_WCE */
+	li.LowPart = ft.dwLowDateTime;
+	li.HighPart = ft.dwHighDateTime;
+	tt = (li.QuadPart - EPOCHFILETIME) / 10;
+	t->sec = (os_time_t) (tt / 1000000);
+	t->usec = (os_time_t) (tt % 1000000);
+
+	return 0;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm, *tm1;
+	time_t t_local, t1, t2;
+	os_time_t tz_offset;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	t_local = mktime(&tm);
+
+	/* figure out offset to UTC */
+	tm1 = localtime(&t_local);
+	if (tm1) {
+		t1 = mktime(tm1);
+		tm1 = gmtime(&t_local);
+		if (tm1) {
+			t2 = mktime(tm1);
+			tz_offset = t2 - t1;
+		} else
+			tz_offset = 0;
+	} else
+		tz_offset = 0;
+
+	*t = (os_time_t) t_local - tz_offset;
+	return 0;
+}
+
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	/* TODO */
+	return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	HCRYPTPROV prov;
+	BOOL ret;
+
+	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
+				 CRYPT_VERIFYCONTEXT))
+		return -1;
+
+	ret = CryptGenRandom(prov, len, buf);
+	CryptReleaseContext(prov, 0);
+
+	return ret ? 0 : -1;
+}
+
+
+unsigned long os_random(void)
+{
+	return rand();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	return _strdup(rel_path);
+}
+
+
+int os_program_init(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	WSADATA wsaData;
+	if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+		printf("Could not find a usable WinSock.dll\n");
+		return -1;
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+	return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	fseek(f, 0, SEEK_END);
+	*len = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	buf = malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	fread(buf, 1, *len, f);
+	fclose(f);
+
+	return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	return calloc(1, size);
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+	const char *s = src;
+	size_t left = siz;
+
+	if (left) {
+		/* Copy string up to the maximum size of the dest buffer */
+		while (--left != 0) {
+			if ((*dest++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	if (left == 0) {
+		/* Not enough room for the string; force NUL-termination */
+		if (siz != 0)
+			*dest = '\0';
+		while (*s++)
+			; /* determine total src string length */
+	}
+
+	return s - src - 1;
+}

Deleted: vendor/wpa/2.0/src/utils/pcsc_funcs.c
===================================================================
--- vendor/wpa/dist/src/utils/pcsc_funcs.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/pcsc_funcs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1238 +0,0 @@
-/*
- * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
- * cards through PC/SC smartcard library. These functions are used to implement
- * authentication routines for EAP-SIM and EAP-AKA.
- */
-
-#include "includes.h"
-#include <winscard.h>
-
-#include "common.h"
-#include "pcsc_funcs.h"
-
-
-/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
- * SIM commands:
- * Command APDU: CLA INS P1 P2 P3 Data
- *   CLA (class of instruction): A0 for GSM, 00 for USIM
- *   INS (instruction)
- *   P1 P2 P3 (parameters, P3 = length of Data)
- * Response APDU: Data SW1 SW2
- *   SW1 SW2 (Status words)
- * Commands (INS P1 P2 P3):
- *   SELECT: A4 00 00 02 <file_id, 2 bytes>
- *   GET RESPONSE: C0 00 00 <len>
- *   RUN GSM ALG: 88 00 00 00 <RAND len = 10>
- *   RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
- *	P1 = ID of alg in card
- *	P2 = ID of secret key
- *   READ BINARY: B0 <offset high> <offset low> <len>
- *   READ RECORD: B2 <record number> <mode> <len>
- *	P2 (mode) = '02' (next record), '03' (previous record),
- *		    '04' (absolute mode)
- *   VERIFY CHV: 20 00 <CHV number> 08
- *   CHANGE CHV: 24 00 <CHV number> 10
- *   DISABLE CHV: 26 00 01 08
- *   ENABLE CHV: 28 00 01 08
- *   UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
- *   SLEEP: FA 00 00 00
- */
-
-/* GSM SIM commands */
-#define SIM_CMD_SELECT			0xa0, 0xa4, 0x00, 0x00, 0x02
-#define SIM_CMD_RUN_GSM_ALG		0xa0, 0x88, 0x00, 0x00, 0x10
-#define SIM_CMD_GET_RESPONSE		0xa0, 0xc0, 0x00, 0x00
-#define SIM_CMD_READ_BIN		0xa0, 0xb0, 0x00, 0x00
-#define SIM_CMD_READ_RECORD		0xa0, 0xb2, 0x00, 0x00
-#define SIM_CMD_VERIFY_CHV1		0xa0, 0x20, 0x00, 0x01, 0x08
-
-/* USIM commands */
-#define USIM_CLA			0x00
-#define USIM_CMD_RUN_UMTS_ALG		0x00, 0x88, 0x00, 0x81, 0x22
-#define USIM_CMD_GET_RESPONSE		0x00, 0xc0, 0x00, 0x00
-
-#define SIM_RECORD_MODE_ABSOLUTE 0x04
-
-#define USIM_FSP_TEMPL_TAG		0x62
-
-#define USIM_TLV_FILE_DESC		0x82
-#define USIM_TLV_FILE_ID		0x83
-#define USIM_TLV_DF_NAME		0x84
-#define USIM_TLV_PROPR_INFO		0xA5
-#define USIM_TLV_LIFE_CYCLE_STATUS	0x8A
-#define USIM_TLV_FILE_SIZE		0x80
-#define USIM_TLV_TOTAL_FILE_SIZE	0x81
-#define USIM_TLV_PIN_STATUS_TEMPLATE	0xC6
-#define USIM_TLV_SHORT_FILE_ID		0x88
-
-#define USIM_PS_DO_TAG			0x90
-
-#define AKA_RAND_LEN 16
-#define AKA_AUTN_LEN 16
-#define AKA_AUTS_LEN 14
-#define RES_MAX_LEN 16
-#define IK_LEN 16
-#define CK_LEN 16
-
-
-typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
-
-struct scard_data {
-	SCARDCONTEXT ctx;
-	SCARDHANDLE card;
-	DWORD protocol;
-	sim_types sim_type;
-	int pin1_required;
-};
-
-#ifdef __MINGW32_VERSION
-/* MinGW does not yet support WinScard, so load the needed functions
- * dynamically from winscard.dll for now. */
-
-static HINSTANCE dll = NULL; /* winscard.dll */
-
-static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
-#undef SCARD_PCI_T0
-#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
-#undef SCARD_PCI_T1
-#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
-
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardEstablishContext)(IN DWORD dwScope,
-			     IN LPCVOID pvReserved1,
-			     IN LPCVOID pvReserved2,
-			     OUT LPSCARDCONTEXT phContext);
-#define SCardEstablishContext dll_SCardEstablishContext
-
-static long (*dll_SCardReleaseContext)(long hContext);
-#define SCardReleaseContext dll_SCardReleaseContext
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
-			 IN LPCSTR mszGroups,
-			 OUT LPSTR mszReaders,
-			 IN OUT LPDWORD pcchReaders);
-#undef SCardListReaders
-#define SCardListReaders dll_SCardListReadersA
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
-		     IN LPCSTR szReader,
-		     IN DWORD dwShareMode,
-		     IN DWORD dwPreferredProtocols,
-		     OUT LPSCARDHANDLE phCard,
-		     OUT LPDWORD pdwActiveProtocol);
-#undef SCardConnect
-#define SCardConnect dll_SCardConnectA
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
-		       IN DWORD dwDisposition);
-#define SCardDisconnect dll_SCardDisconnect
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardTransmit)(IN SCARDHANDLE hCard,
-		     IN LPCSCARD_IO_REQUEST pioSendPci,
-		     IN LPCBYTE pbSendBuffer,
-		     IN DWORD cbSendLength,
-		     IN OUT LPSCARD_IO_REQUEST pioRecvPci,
-		     OUT LPBYTE pbRecvBuffer,
-		     IN OUT LPDWORD pcbRecvLength);
-#define SCardTransmit dll_SCardTransmit
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
-#define SCardBeginTransaction dll_SCardBeginTransaction
-
-static WINSCARDAPI LONG WINAPI
-(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
-#define SCardEndTransaction dll_SCardEndTransaction
-
-
-static int mingw_load_symbols(void)
-{
-	char *sym;
-
-	if (dll)
-		return 0;
-
-	dll = LoadLibrary("winscard");
-	if (dll == NULL) {
-		wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
-			   "library");
-		return -1;
-	}
-
-#define LOADSYM(s) \
-	sym = #s; \
-	dll_ ## s = (void *) GetProcAddress(dll, sym); \
-	if (dll_ ## s == NULL) \
-		goto fail;
-
-	LOADSYM(SCardEstablishContext);
-	LOADSYM(SCardReleaseContext);
-	LOADSYM(SCardListReadersA);
-	LOADSYM(SCardConnectA);
-	LOADSYM(SCardDisconnect);
-	LOADSYM(SCardTransmit);
-	LOADSYM(SCardBeginTransaction);
-	LOADSYM(SCardEndTransaction);
-	LOADSYM(g_rgSCardT0Pci);
-	LOADSYM(g_rgSCardT1Pci);
-
-#undef LOADSYM
-
-	return 0;
-
-fail:
-	wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
-		   "winscard.dll", sym);
-	FreeLibrary(dll);
-	dll = NULL;
-	return -1;
-}
-
-
-static void mingw_unload_symbols(void)
-{
-	if (dll == NULL)
-		return;
-
-	FreeLibrary(dll);
-	dll = NULL;
-}
-
-#else /* __MINGW32_VERSION */
-
-#define mingw_load_symbols() 0
-#define mingw_unload_symbols() do { } while (0)
-
-#endif /* __MINGW32_VERSION */
-
-
-static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
-			      unsigned char *buf, size_t *buf_len,
-			      sim_types sim_type, unsigned char *aid,
-			      size_t aidlen);
-static int scard_select_file(struct scard_data *scard, unsigned short file_id,
-			     unsigned char *buf, size_t *buf_len);
-static int scard_verify_pin(struct scard_data *scard, const char *pin);
-static int scard_get_record_len(struct scard_data *scard,
-				unsigned char recnum, unsigned char mode);
-static int scard_read_record(struct scard_data *scard,
-			     unsigned char *data, size_t len,
-			     unsigned char recnum, unsigned char mode);
-
-
-static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
-				 int *ps_do, int *file_len)
-{
-		unsigned char *pos, *end;
-
-		if (ps_do)
-			*ps_do = -1;
-		if (file_len)
-			*file_len = -1;
-
-		pos = buf;
-		end = pos + buf_len;
-		if (*pos != USIM_FSP_TEMPL_TAG) {
-			wpa_printf(MSG_DEBUG, "SCARD: file header did not "
-				   "start with FSP template tag");
-			return -1;
-		}
-		pos++;
-		if (pos >= end)
-			return -1;
-		if ((pos + pos[0]) < end)
-			end = pos + 1 + pos[0];
-		pos++;
-		wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
-			    pos, end - pos);
-
-		while (pos + 1 < end) {
-			wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
-				   "0x%02x len=%d", pos[0], pos[1]);
-			if (pos + 2 + pos[1] > end)
-				break;
-
-			if (pos[0] == USIM_TLV_FILE_SIZE &&
-			    (pos[1] == 1 || pos[1] == 2) && file_len) {
-				if (pos[1] == 1)
-					*file_len = (int) pos[2];
-				else
-					*file_len = ((int) pos[2] << 8) |
-						(int) pos[3];
-				wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
-					   *file_len);
-			}
-
-			if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
-			    pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
-			    pos[3] >= 1 && ps_do) {
-				wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
-					   pos[4]);
-				*ps_do = (int) pos[4];
-			}
-
-			pos += 2 + pos[1];
-
-			if (pos == end)
-				return 0;
-		}
-		return -1;
-}
-
-
-static int scard_pin_needed(struct scard_data *scard,
-			    unsigned char *hdr, size_t hlen)
-{
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		if (hlen > SCARD_CHV1_OFFSET &&
-		    !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
-			return 1;
-		return 0;
-	}
-
-	if (scard->sim_type == SCARD_USIM) {
-		int ps_do;
-		if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
-			return -1;
-		/* TODO: there could be more than one PS_DO entry because of
-		 * multiple PINs in key reference.. */
-		if (ps_do > 0 && (ps_do & 0x80))
-			return 1;
-		return 0;
-	}
-
-	return -1;
-}
-
-
-static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
-			 size_t maxlen)
-{
-	int rlen, rec;
-	struct efdir {
-		unsigned char appl_template_tag; /* 0x61 */
-		unsigned char appl_template_len;
-		unsigned char appl_id_tag; /* 0x4f */
-		unsigned char aid_len;
-		unsigned char rid[5];
-		unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
-	} *efdir;
-	unsigned char buf[100];
-	size_t blen;
-
-	efdir = (struct efdir *) buf;
-	blen = sizeof(buf);
-	if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
-		wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
-		return -1;
-	}
-	wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
-
-	for (rec = 1; rec < 10; rec++) {
-		rlen = scard_get_record_len(scard, rec,
-					    SIM_RECORD_MODE_ABSOLUTE);
-		if (rlen < 0) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
-				   "record length");
-			return -1;
-		}
-		blen = sizeof(buf);
-		if (rlen > (int) blen) {
-			wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
-			return -1;
-		}
-		if (scard_read_record(scard, buf, rlen, rec,
-				      SIM_RECORD_MODE_ABSOLUTE) < 0) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
-				   "EF_DIR record %d", rec);
-			return -1;
-		}
-		wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
-
-		if (efdir->appl_template_tag != 0x61) {
-			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
-				   "template tag 0x%x",
-				   efdir->appl_template_tag);
-			continue;
-		}
-
-		if (efdir->appl_template_len > rlen - 2) {
-			wpa_printf(MSG_DEBUG, "SCARD: Too long application "
-				   "template (len=%d rlen=%d)",
-				   efdir->appl_template_len, rlen);
-			continue;
-		}
-
-		if (efdir->appl_id_tag != 0x4f) {
-			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
-				   "identifier tag 0x%x", efdir->appl_id_tag);
-			continue;
-		}
-
-		if (efdir->aid_len < 1 || efdir->aid_len > 16) {
-			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
-				   efdir->aid_len);
-			continue;
-		}
-
-		wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
-			    efdir->rid, efdir->aid_len);
-
-		if (efdir->appl_code[0] == 0x10 &&
-		    efdir->appl_code[1] == 0x02) {
-			wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
-				   "EF_DIR record %d", rec);
-			break;
-		}
-	}
-
-	if (rec >= 10) {
-		wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
-			   "from EF_DIR records");
-		return -1;
-	}
-
-	if (efdir->aid_len > maxlen) {
-		wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
-		return -1;
-	}
-
-	os_memcpy(aid, efdir->rid, efdir->aid_len);
-
-	return efdir->aid_len;
-}
-
-
-/**
- * scard_init - Initialize SIM/USIM connection using PC/SC
- * @sim_type: Allowed SIM types (SIM, USIM, or both)
- * Returns: Pointer to private data structure, or %NULL on failure
- *
- * This function is used to initialize SIM/USIM connection. PC/SC is used to
- * open connection to the SIM/USIM card and the card is verified to support the
- * selected sim_type. In addition, local flag is set if a PIN is needed to
- * access some of the card functions. Once the connection is not needed
- * anymore, scard_deinit() can be used to close it.
- */
-struct scard_data * scard_init(scard_sim_type sim_type)
-{
-	long ret;
-	unsigned long len;
-	struct scard_data *scard;
-#ifdef CONFIG_NATIVE_WINDOWS
-	TCHAR *readers = NULL;
-#else /* CONFIG_NATIVE_WINDOWS */
-	char *readers = NULL;
-#endif /* CONFIG_NATIVE_WINDOWS */
-	unsigned char buf[100];
-	size_t blen;
-	int transaction = 0;
-	int pin_needed;
-
-	wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
-	if (mingw_load_symbols())
-		return NULL;
-	scard = os_zalloc(sizeof(*scard));
-	if (scard == NULL)
-		return NULL;
-
-	ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
-				    &scard->ctx);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
-			   "context (err=%ld)", ret);
-		goto failed;
-	}
-
-	ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
-			   "(err=%ld)", ret);
-		goto failed;
-	}
-
-#ifdef UNICODE
-	len *= 2;
-#endif /* UNICODE */
-	readers = os_malloc(len);
-	if (readers == NULL) {
-		wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
-		goto failed;
-	}
-
-	ret = SCardListReaders(scard->ctx, NULL, readers, &len);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
-			   "(err=%ld)", ret);
-		goto failed;
-	}
-	if (len < 3) {
-		wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
-			   "available.");
-		goto failed;
-	}
-	/* readers is a list of available reader. Last entry is terminated with
-	 * double NUL.
-	 * TODO: add support for selecting the reader; now just use the first
-	 * one.. */
-#ifdef UNICODE
-	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
-#else /* UNICODE */
-	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
-#endif /* UNICODE */
-
-	ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
-			   SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
-	if (ret != SCARD_S_SUCCESS) {
-		if (ret == (long) SCARD_E_NO_SMARTCARD)
-			wpa_printf(MSG_INFO, "No smart card inserted.");
-		else
-			wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
-		goto failed;
-	}
-
-	os_free(readers);
-	readers = NULL;
-
-	wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
-		   (unsigned int) scard->card, scard->protocol,
-		   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
-
-	ret = SCardBeginTransaction(scard->card);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
-			   "0x%x", (unsigned int) ret);
-		goto failed;
-	}
-	transaction = 1;
-
-	blen = sizeof(buf);
-
-	scard->sim_type = SCARD_GSM_SIM;
-	if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
-		wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
-		if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
-				       SCARD_USIM, NULL, 0)) {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
-			if (sim_type == SCARD_USIM_ONLY)
-				goto failed;
-			wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
-			scard->sim_type = SCARD_GSM_SIM;
-		} else {
-			wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
-			scard->sim_type = SCARD_USIM;
-		}
-	}
-
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		blen = sizeof(buf);
-		if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
-			goto failed;
-		}
-
-		blen = sizeof(buf);
-		if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
-			goto failed;
-		}
-	} else {
-		unsigned char aid[32];
-		int aid_len;
-
-		aid_len = scard_get_aid(scard, aid, sizeof(aid));
-		if (aid_len < 0) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
-				   "3G USIM app - try to use standard 3G RID");
-			os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
-			aid_len = 5;
-		}
-		wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
-
-		/* Select based on AID = 3G RID from EF_DIR. This is usually
-		 * starting with A0 00 00 00 87. */
-		blen = sizeof(buf);
-		if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
-				       aid, aid_len)) {
-			wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
-				   "app");
-			wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
-				    aid, aid_len);
-			goto failed;
-		}
-	}
-
-	/* Verify whether CHV1 (PIN1) is needed to access the card. */
-	pin_needed = scard_pin_needed(scard, buf, blen);
-	if (pin_needed < 0) {
-		wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
-			   "is needed");
-		goto failed;
-	}
-	if (pin_needed) {
-		scard->pin1_required = 1;
-		wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
-	}
-
-	ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
-			   "0x%x", (unsigned int) ret);
-	}
-
-	return scard;
-
-failed:
-	if (transaction)
-		SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
-	os_free(readers);
-	scard_deinit(scard);
-	return NULL;
-}
-
-
-/**
- * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
- * @scard: Pointer to private data from scard_init()
- * @pin: PIN code as an ASCII string (e.g., "1234")
- * Returns: 0 on success, -1 on failure
- */
-int scard_set_pin(struct scard_data *scard, const char *pin)
-{
-	if (scard == NULL)
-		return -1;
-
-	/* Verify whether CHV1 (PIN1) is needed to access the card. */
-	if (scard->pin1_required) {
-		if (pin == NULL) {
-			wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
-				   "access");
-			return -1;
-		}
-		if (scard_verify_pin(scard, pin)) {
-			wpa_printf(MSG_INFO, "PIN verification failed for "
-				"SIM access");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- * scard_deinit - Deinitialize SIM/USIM connection
- * @scard: Pointer to private data from scard_init()
- *
- * This function closes the SIM/USIM connect opened with scard_init().
- */
-void scard_deinit(struct scard_data *scard)
-{
-	long ret;
-
-	if (scard == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
-	if (scard->card) {
-		ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
-		if (ret != SCARD_S_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
-				   "smart card (err=%ld)", ret);
-		}
-	}
-
-	if (scard->ctx) {
-		ret = SCardReleaseContext(scard->ctx);
-		if (ret != SCARD_S_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "Failed to release smart card "
-				   "context (err=%ld)", ret);
-		}
-	}
-	os_free(scard);
-	mingw_unload_symbols();
-}
-
-
-static long scard_transmit(struct scard_data *scard,
-			   unsigned char *_send, size_t send_len,
-			   unsigned char *_recv, size_t *recv_len)
-{
-	long ret;
-	unsigned long rlen;
-
-	wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
-			_send, send_len);
-	rlen = *recv_len;
-	ret = SCardTransmit(scard->card,
-			    scard->protocol == SCARD_PROTOCOL_T1 ?
-			    SCARD_PCI_T1 : SCARD_PCI_T0,
-			    _send, (unsigned long) send_len,
-			    NULL, _recv, &rlen);
-	*recv_len = rlen;
-	if (ret == SCARD_S_SUCCESS) {
-		wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
-			    _recv, rlen);
-	} else {
-		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
-			   "(err=0x%lx)", ret);
-	}
-	return ret;
-}
-
-
-static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
-			      unsigned char *buf, size_t *buf_len,
-			      sim_types sim_type, unsigned char *aid,
-			      size_t aidlen)
-{
-	long ret;
-	unsigned char resp[3];
-	unsigned char cmd[50] = { SIM_CMD_SELECT };
-	int cmdlen;
-	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
-	size_t len, rlen;
-
-	if (sim_type == SCARD_USIM) {
-		cmd[0] = USIM_CLA;
-		cmd[3] = 0x04;
-		get_resp[0] = USIM_CLA;
-	}
-
-	wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
-	if (aid) {
-		wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
-			    aid, aidlen);
-		if (5 + aidlen > sizeof(cmd))
-			return -1;
-		cmd[2] = 0x04; /* Select by AID */
-		cmd[4] = aidlen; /* len */
-		os_memcpy(cmd + 5, aid, aidlen);
-		cmdlen = 5 + aidlen;
-	} else {
-		cmd[5] = file_id >> 8;
-		cmd[6] = file_id & 0xff;
-		cmdlen = 7;
-	}
-	len = sizeof(resp);
-	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
-			   "(err=0x%lx)", ret);
-		return -1;
-	}
-
-	if (len != 2) {
-		wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
-			   "%d (expected 2)", (int) len);
-		return -1;
-	}
-
-	if (resp[0] == 0x98 && resp[1] == 0x04) {
-		/* Security status not satisfied (PIN_WLAN) */
-		wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
-			   "(PIN_WLAN)");
-		return -1;
-	}
-
-	if (resp[0] == 0x6e) {
-		wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
-		return -1;
-	}
-
-	if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
-		wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
-			   "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
-		return -1;
-	}
-	/* Normal ending of command; resp[1] bytes available */
-	get_resp[4] = resp[1];
-	wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
-		   resp[1]);
-
-	rlen = *buf_len;
-	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
-	if (ret == SCARD_S_SUCCESS) {
-		*buf_len = resp[1] < rlen ? resp[1] : rlen;
-		return 0;
-	}
-
-	wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
-	return -1;
-}
-
-
-static int scard_select_file(struct scard_data *scard, unsigned short file_id,
-			     unsigned char *buf, size_t *buf_len)
-{
-	return _scard_select_file(scard, file_id, buf, buf_len,
-				  scard->sim_type, NULL, 0);
-}
-
-
-static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
-				unsigned char mode)
-{
-	unsigned char buf[255];
-	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
-	size_t blen;
-	long ret;
-
-	if (scard->sim_type == SCARD_USIM)
-		cmd[0] = USIM_CLA;
-	cmd[2] = recnum;
-	cmd[3] = mode;
-	cmd[4] = sizeof(buf);
-
-	blen = sizeof(buf);
-	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
-	if (ret != SCARD_S_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
-			   "length for record %d", recnum);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
-		    buf, blen);
-
-	if (blen < 2 || buf[0] != 0x6c) {
-		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
-			   "length determination");
-		return -1;
-	}
-
-	return buf[1];
-}
-
-
-static int scard_read_record(struct scard_data *scard,
-			     unsigned char *data, size_t len,
-			     unsigned char recnum, unsigned char mode)
-{
-	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
-	size_t blen = len + 3;
-	unsigned char *buf;
-	long ret;
-
-	if (scard->sim_type == SCARD_USIM)
-		cmd[0] = USIM_CLA;
-	cmd[2] = recnum;
-	cmd[3] = mode;
-	cmd[4] = len;
-
-	buf = os_malloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
-	if (ret != SCARD_S_SUCCESS) {
-		os_free(buf);
-		return -2;
-	}
-	if (blen != len + 2) {
-		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
-			   "length %ld (expected %ld)",
-			   (long) blen, (long) len + 2);
-		os_free(buf);
-		return -3;
-	}
-
-	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
-		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
-			   "status %02x %02x (expected 90 00)",
-			   buf[len], buf[len + 1]);
-		os_free(buf);
-		return -4;
-	}
-
-	os_memcpy(data, buf, len);
-	os_free(buf);
-
-	return 0;
-}
-
-
-static int scard_read_file(struct scard_data *scard,
-			   unsigned char *data, size_t len)
-{
-	unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
-	size_t blen = len + 3;
-	unsigned char *buf;
-	long ret;
-
-	cmd[4] = len;
-
-	buf = os_malloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	if (scard->sim_type == SCARD_USIM)
-		cmd[0] = USIM_CLA;
-	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
-	if (ret != SCARD_S_SUCCESS) {
-		os_free(buf);
-		return -2;
-	}
-	if (blen != len + 2) {
-		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
-			   "length %ld (expected %ld)",
-			   (long) blen, (long) len + 2);
-		os_free(buf);
-		return -3;
-	}
-
-	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
-		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
-			   "status %02x %02x (expected 90 00)",
-			   buf[len], buf[len + 1]);
-		os_free(buf);
-		return -4;
-	}
-
-	os_memcpy(data, buf, len);
-	os_free(buf);
-
-	return 0;
-}
-
-
-static int scard_verify_pin(struct scard_data *scard, const char *pin)
-{
-	long ret;
-	unsigned char resp[3];
-	unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
-	size_t len;
-
-	wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
-
-	if (pin == NULL || os_strlen(pin) > 8)
-		return -1;
-
-	if (scard->sim_type == SCARD_USIM)
-		cmd[0] = USIM_CLA;
-	os_memcpy(cmd + 5, pin, os_strlen(pin));
-	os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
-
-	len = sizeof(resp);
-	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
-	if (ret != SCARD_S_SUCCESS)
-		return -2;
-
-	if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
-		wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
-	return 0;
-}
-
-
-/**
- * scard_get_imsi - Read IMSI from SIM/USIM card
- * @scard: Pointer to private data from scard_init()
- * @imsi: Buffer for IMSI
- * @len: Length of imsi buffer; set to IMSI length on success
- * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
- * selection returns invalid result code, -3 if parsing FSP template file fails
- * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
- * to needed length), -5 if reading IMSI file fails.
- *
- * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
- * file is PIN protected, scard_set_pin() must have been used to set the
- * correct PIN code before calling scard_get_imsi().
- */
-int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
-{
-	unsigned char buf[100];
-	size_t blen, imsilen, i;
-	char *pos;
-
-	wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
-	blen = sizeof(buf);
-	if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
-		return -1;
-	if (blen < 4) {
-		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
-			   "header (len=%ld)", (long) blen);
-		return -2;
-	}
-
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		blen = (buf[2] << 8) | buf[3];
-	} else {
-		int file_size;
-		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
-			return -3;
-		blen = file_size;
-	}
-	if (blen < 2 || blen > sizeof(buf)) {
-		wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
-			   (long) blen);
-		return -3;
-	}
-
-	imsilen = (blen - 2) * 2 + 1;
-	wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
-		   (long) blen, (long) imsilen);
-	if (blen < 2 || imsilen > *len) {
-		*len = imsilen;
-		return -4;
-	}
-
-	if (scard_read_file(scard, buf, blen))
-		return -5;
-
-	pos = imsi;
-	*pos++ = '0' + (buf[1] >> 4 & 0x0f);
-	for (i = 2; i < blen; i++) {
-		unsigned char digit;
-
-		digit = buf[i] & 0x0f;
-		if (digit < 10)
-			*pos++ = '0' + digit;
-		else
-			imsilen--;
-
-		digit = buf[i] >> 4 & 0x0f;
-		if (digit < 10)
-			*pos++ = '0' + digit;
-		else
-			imsilen--;
-	}
-	*len = imsilen;
-
-	return 0;
-}
-
-
-/**
- * scard_gsm_auth - Run GSM authentication command on SIM card
- * @scard: Pointer to private data from scard_init()
- * @_rand: 16-byte RAND value from HLR/AuC
- * @sres: 4-byte buffer for SRES
- * @kc: 8-byte buffer for Kc
- * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
- * -2 if authentication command execution fails, -3 if unknown response code
- * for authentication command is received, -4 if reading of response fails,
- * -5 if if response data is of unexpected length
- *
- * This function performs GSM authentication using SIM/USIM card and the
- * provided RAND value from HLR/AuC. If authentication command can be completed
- * successfully, SRES and Kc values will be written into sres and kc buffers.
- */
-int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
-		   unsigned char *sres, unsigned char *kc)
-{
-	unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
-	int cmdlen;
-	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
-	unsigned char resp[3], buf[12 + 3 + 2];
-	size_t len;
-	long ret;
-
-	if (scard == NULL)
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		cmdlen = 5 + 16;
-		os_memcpy(cmd + 5, _rand, 16);
-	} else {
-		cmdlen = 5 + 1 + 16;
-		cmd[0] = USIM_CLA;
-		cmd[3] = 0x80;
-		cmd[4] = 17;
-		cmd[5] = 16;
-		os_memcpy(cmd + 6, _rand, 16);
-	}
-	len = sizeof(resp);
-	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
-	if (ret != SCARD_S_SUCCESS)
-		return -2;
-
-	if ((scard->sim_type == SCARD_GSM_SIM &&
-	     (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
-	    (scard->sim_type == SCARD_USIM &&
-	     (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
-		wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
-			   "auth request (len=%ld resp=%02x %02x)",
-			   (long) len, resp[0], resp[1]);
-		return -3;
-	}
-	get_resp[4] = resp[1];
-
-	len = sizeof(buf);
-	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
-	if (ret != SCARD_S_SUCCESS)
-		return -4;
-
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		if (len != 4 + 8 + 2) {
-			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
-				   "length for GSM auth (len=%ld, expected 14)",
-				   (long) len);
-			return -5;
-		}
-		os_memcpy(sres, buf, 4);
-		os_memcpy(kc, buf + 4, 8);
-	} else {
-		if (len != 1 + 4 + 1 + 8 + 2) {
-			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
-				   "length for USIM auth (len=%ld, "
-				   "expected 16)", (long) len);
-			return -5;
-		}
-		if (buf[0] != 4 || buf[5] != 8) {
-			wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
-				   "length (%d %d, expected 4 8)",
-				   buf[0], buf[5]);
-		}
-		os_memcpy(sres, buf + 1, 4);
-		os_memcpy(kc, buf + 6, 8);
-	}
-
-	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
-	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
-
-	return 0;
-}
-
-
-/**
- * scard_umts_auth - Run UMTS authentication command on USIM card
- * @scard: Pointer to private data from scard_init()
- * @_rand: 16-byte RAND value from HLR/AuC
- * @autn: 16-byte AUTN value from HLR/AuC
- * @res: 16-byte buffer for RES
- * @res_len: Variable that will be set to RES length
- * @ik: 16-byte buffer for IK
- * @ck: 16-byte buffer for CK
- * @auts: 14-byte buffer for AUTS
- * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
- * failure
- *
- * This function performs AKA authentication using USIM card and the provided
- * RAND and AUTN values from HLR/AuC. If authentication command can be
- * completed successfully, RES, IK, and CK values will be written into provided
- * buffers and res_len is set to length of received RES value. If USIM reports
- * synchronization failure, the received AUTS value will be written into auts
- * buffer. In this case, RES, IK, and CK are not valid.
- */
-int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
-		    const unsigned char *autn,
-		    unsigned char *res, size_t *res_len,
-		    unsigned char *ik, unsigned char *ck, unsigned char *auts)
-{
-	unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
-		{ USIM_CMD_RUN_UMTS_ALG };
-	unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
-	unsigned char resp[3], buf[64], *pos, *end;
-	size_t len;
-	long ret;
-
-	if (scard == NULL)
-		return -1;
-
-	if (scard->sim_type == SCARD_GSM_SIM) {
-		wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
-			   "auth");
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
-	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
-	cmd[5] = AKA_RAND_LEN;
-	os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
-	cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
-	os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
-
-	len = sizeof(resp);
-	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
-	if (ret != SCARD_S_SUCCESS)
-		return -1;
-
-	if (len <= sizeof(resp))
-		wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
-
-	if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
-		wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
-			   "MAC != XMAC");
-		return -1;
-	} else if (len != 2 || resp[0] != 0x61) {
-		wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
-			   "auth request (len=%ld resp=%02x %02x)",
-			   (long) len, resp[0], resp[1]);
-		return -1;
-	}
-	get_resp[4] = resp[1];
-
-	len = sizeof(buf);
-	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
-	if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
-		return -1;
-
-	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
-	if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
-	    buf[1] == AKA_AUTS_LEN) {
-		wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
-		os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
-		wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
-		return -2;
-	} else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
-		pos = buf + 1;
-		end = buf + len;
-
-		/* RES */
-		if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
-			wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
-			return -1;
-		}
-		*res_len = *pos++;
-		os_memcpy(res, pos, *res_len);
-		pos += *res_len;
-		wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
-
-		/* CK */
-		if (pos[0] != CK_LEN || pos + CK_LEN > end) {
-			wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
-			return -1;
-		}
-		pos++;
-		os_memcpy(ck, pos, CK_LEN);
-		pos += CK_LEN;
-		wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
-
-		/* IK */
-		if (pos[0] != IK_LEN || pos + IK_LEN > end) {
-			wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
-			return -1;
-		}
-		pos++;
-		os_memcpy(ik, pos, IK_LEN);
-		pos += IK_LEN;
-		wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
-
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
-	return -1;
-}

Copied: vendor/wpa/2.0/src/utils/pcsc_funcs.c (from rev 9639, vendor/wpa/dist/src/utils/pcsc_funcs.c)
===================================================================
--- vendor/wpa/2.0/src/utils/pcsc_funcs.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/pcsc_funcs.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1427 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2007, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
+ * cards through PC/SC smartcard library. These functions are used to implement
+ * authentication routines for EAP-SIM and EAP-AKA.
+ */
+
+#include "includes.h"
+#include <winscard.h>
+
+#include "common.h"
+#include "pcsc_funcs.h"
+
+
+/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
+ * SIM commands:
+ * Command APDU: CLA INS P1 P2 P3 Data
+ *   CLA (class of instruction): A0 for GSM, 00 for USIM
+ *   INS (instruction)
+ *   P1 P2 P3 (parameters, P3 = length of Data)
+ * Response APDU: Data SW1 SW2
+ *   SW1 SW2 (Status words)
+ * Commands (INS P1 P2 P3):
+ *   SELECT: A4 00 00 02 <file_id, 2 bytes>
+ *   GET RESPONSE: C0 00 00 <len>
+ *   RUN GSM ALG: 88 00 00 00 <RAND len = 10>
+ *   RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
+ *	P1 = ID of alg in card
+ *	P2 = ID of secret key
+ *   READ BINARY: B0 <offset high> <offset low> <len>
+ *   READ RECORD: B2 <record number> <mode> <len>
+ *	P2 (mode) = '02' (next record), '03' (previous record),
+ *		    '04' (absolute mode)
+ *   VERIFY CHV: 20 00 <CHV number> 08
+ *   CHANGE CHV: 24 00 <CHV number> 10
+ *   DISABLE CHV: 26 00 01 08
+ *   ENABLE CHV: 28 00 01 08
+ *   UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
+ *   SLEEP: FA 00 00 00
+ */
+
+/* GSM SIM commands */
+#define SIM_CMD_SELECT			0xa0, 0xa4, 0x00, 0x00, 0x02
+#define SIM_CMD_RUN_GSM_ALG		0xa0, 0x88, 0x00, 0x00, 0x10
+#define SIM_CMD_GET_RESPONSE		0xa0, 0xc0, 0x00, 0x00
+#define SIM_CMD_READ_BIN		0xa0, 0xb0, 0x00, 0x00
+#define SIM_CMD_READ_RECORD		0xa0, 0xb2, 0x00, 0x00
+#define SIM_CMD_VERIFY_CHV1		0xa0, 0x20, 0x00, 0x01, 0x08
+
+/* USIM commands */
+#define USIM_CLA			0x00
+#define USIM_CMD_RUN_UMTS_ALG		0x00, 0x88, 0x00, 0x81, 0x22
+#define USIM_CMD_GET_RESPONSE		0x00, 0xc0, 0x00, 0x00
+
+#define SIM_RECORD_MODE_ABSOLUTE 0x04
+
+#define USIM_FSP_TEMPL_TAG		0x62
+
+#define USIM_TLV_FILE_DESC		0x82
+#define USIM_TLV_FILE_ID		0x83
+#define USIM_TLV_DF_NAME		0x84
+#define USIM_TLV_PROPR_INFO		0xA5
+#define USIM_TLV_LIFE_CYCLE_STATUS	0x8A
+#define USIM_TLV_FILE_SIZE		0x80
+#define USIM_TLV_TOTAL_FILE_SIZE	0x81
+#define USIM_TLV_PIN_STATUS_TEMPLATE	0xC6
+#define USIM_TLV_SHORT_FILE_ID		0x88
+#define USIM_TLV_SECURITY_ATTR_8B	0x8B
+#define USIM_TLV_SECURITY_ATTR_8C	0x8C
+#define USIM_TLV_SECURITY_ATTR_AB	0xAB
+
+#define USIM_PS_DO_TAG			0x90
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+#define AKA_AUTS_LEN 14
+#define RES_MAX_LEN 16
+#define IK_LEN 16
+#define CK_LEN 16
+
+
+/* GSM files
+ * File type in first octet:
+ * 3F = Master File
+ * 7F = Dedicated File
+ * 2F = Elementary File under the Master File
+ * 6F = Elementary File under a Dedicated File
+ */
+#define SCARD_FILE_MF		0x3F00
+#define SCARD_FILE_GSM_DF	0x7F20
+#define SCARD_FILE_UMTS_DF	0x7F50
+#define SCARD_FILE_GSM_EF_IMSI	0x6F07
+#define SCARD_FILE_GSM_EF_AD	0x6FAD
+#define SCARD_FILE_EF_DIR	0x2F00
+#define SCARD_FILE_EF_ICCID	0x2FE2
+#define SCARD_FILE_EF_CK	0x6FE1
+#define SCARD_FILE_EF_IK	0x6FE2
+
+#define SCARD_CHV1_OFFSET	13
+#define SCARD_CHV1_FLAG		0x80
+
+
+typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
+
+struct scard_data {
+	SCARDCONTEXT ctx;
+	SCARDHANDLE card;
+	DWORD protocol;
+	sim_types sim_type;
+	int pin1_required;
+};
+
+#ifdef __MINGW32_VERSION
+/* MinGW does not yet support WinScard, so load the needed functions
+ * dynamically from winscard.dll for now. */
+
+static HINSTANCE dll = NULL; /* winscard.dll */
+
+static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
+#undef SCARD_PCI_T0
+#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
+#undef SCARD_PCI_T1
+#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
+
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEstablishContext)(IN DWORD dwScope,
+			     IN LPCVOID pvReserved1,
+			     IN LPCVOID pvReserved2,
+			     OUT LPSCARDCONTEXT phContext);
+#define SCardEstablishContext dll_SCardEstablishContext
+
+static long (*dll_SCardReleaseContext)(long hContext);
+#define SCardReleaseContext dll_SCardReleaseContext
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
+			 IN LPCSTR mszGroups,
+			 OUT LPSTR mszReaders,
+			 IN OUT LPDWORD pcchReaders);
+#undef SCardListReaders
+#define SCardListReaders dll_SCardListReadersA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
+		     IN LPCSTR szReader,
+		     IN DWORD dwShareMode,
+		     IN DWORD dwPreferredProtocols,
+		     OUT LPSCARDHANDLE phCard,
+		     OUT LPDWORD pdwActiveProtocol);
+#undef SCardConnect
+#define SCardConnect dll_SCardConnectA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
+		       IN DWORD dwDisposition);
+#define SCardDisconnect dll_SCardDisconnect
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardTransmit)(IN SCARDHANDLE hCard,
+		     IN LPCSCARD_IO_REQUEST pioSendPci,
+		     IN LPCBYTE pbSendBuffer,
+		     IN DWORD cbSendLength,
+		     IN OUT LPSCARD_IO_REQUEST pioRecvPci,
+		     OUT LPBYTE pbRecvBuffer,
+		     IN OUT LPDWORD pcbRecvLength);
+#define SCardTransmit dll_SCardTransmit
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
+#define SCardBeginTransaction dll_SCardBeginTransaction
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
+#define SCardEndTransaction dll_SCardEndTransaction
+
+
+static int mingw_load_symbols(void)
+{
+	char *sym;
+
+	if (dll)
+		return 0;
+
+	dll = LoadLibrary("winscard");
+	if (dll == NULL) {
+		wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
+			   "library");
+		return -1;
+	}
+
+#define LOADSYM(s) \
+	sym = #s; \
+	dll_ ## s = (void *) GetProcAddress(dll, sym); \
+	if (dll_ ## s == NULL) \
+		goto fail;
+
+	LOADSYM(SCardEstablishContext);
+	LOADSYM(SCardReleaseContext);
+	LOADSYM(SCardListReadersA);
+	LOADSYM(SCardConnectA);
+	LOADSYM(SCardDisconnect);
+	LOADSYM(SCardTransmit);
+	LOADSYM(SCardBeginTransaction);
+	LOADSYM(SCardEndTransaction);
+	LOADSYM(g_rgSCardT0Pci);
+	LOADSYM(g_rgSCardT1Pci);
+
+#undef LOADSYM
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
+		   "winscard.dll", sym);
+	FreeLibrary(dll);
+	dll = NULL;
+	return -1;
+}
+
+
+static void mingw_unload_symbols(void)
+{
+	if (dll == NULL)
+		return;
+
+	FreeLibrary(dll);
+	dll = NULL;
+}
+
+#else /* __MINGW32_VERSION */
+
+#define mingw_load_symbols() 0
+#define mingw_unload_symbols() do { } while (0)
+
+#endif /* __MINGW32_VERSION */
+
+
+static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
+			      unsigned char *buf, size_t *buf_len,
+			      sim_types sim_type, unsigned char *aid,
+			      size_t aidlen);
+static int scard_select_file(struct scard_data *scard, unsigned short file_id,
+			     unsigned char *buf, size_t *buf_len);
+static int scard_verify_pin(struct scard_data *scard, const char *pin);
+static int scard_get_record_len(struct scard_data *scard,
+				unsigned char recnum, unsigned char mode);
+static int scard_read_record(struct scard_data *scard,
+			     unsigned char *data, size_t len,
+			     unsigned char recnum, unsigned char mode);
+
+
+static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
+				 int *ps_do, int *file_len)
+{
+	unsigned char *pos, *end;
+
+	if (ps_do)
+		*ps_do = -1;
+	if (file_len)
+		*file_len = -1;
+
+	pos = buf;
+	end = pos + buf_len;
+	if (*pos != USIM_FSP_TEMPL_TAG) {
+		wpa_printf(MSG_DEBUG, "SCARD: file header did not "
+			   "start with FSP template tag");
+		return -1;
+	}
+	pos++;
+	if (pos >= end)
+		return -1;
+	if ((pos + pos[0]) < end)
+		end = pos + 1 + pos[0];
+	pos++;
+	wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
+		    pos, end - pos);
+
+	while (pos + 1 < end) {
+		wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
+			   pos[0], pos[1]);
+		if (pos + 2 + pos[1] > end)
+			break;
+
+		switch (pos[0]) {
+		case USIM_TLV_FILE_DESC:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
+				    pos + 2, pos[1]);
+			break;
+		case USIM_TLV_FILE_ID:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
+				    pos + 2, pos[1]);
+			break;
+		case USIM_TLV_DF_NAME:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
+				    pos + 2, pos[1]);
+			break;
+		case USIM_TLV_PROPR_INFO:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
+				    "information TLV", pos + 2, pos[1]);
+			break;
+		case USIM_TLV_LIFE_CYCLE_STATUS:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
+				    "Integer TLV", pos + 2, pos[1]);
+			break;
+		case USIM_TLV_FILE_SIZE:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
+				    pos + 2, pos[1]);
+			if ((pos[1] == 1 || pos[1] == 2) && file_len) {
+				if (pos[1] == 1)
+					*file_len = (int) pos[2];
+				else
+					*file_len = ((int) pos[2] << 8) |
+						(int) pos[3];
+				wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
+					   *file_len);
+			}
+			break;
+		case USIM_TLV_TOTAL_FILE_SIZE:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
+				    pos + 2, pos[1]);
+			break;
+		case USIM_TLV_PIN_STATUS_TEMPLATE:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
+				    "DO TLV", pos + 2, pos[1]);
+			if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
+			    pos[3] >= 1 && ps_do) {
+				wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
+					   pos[4]);
+				*ps_do = (int) pos[4];
+			}
+			break;
+		case USIM_TLV_SHORT_FILE_ID:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
+				    "Identifier (SFI) TLV", pos + 2, pos[1]);
+			break;
+		case USIM_TLV_SECURITY_ATTR_8B:
+		case USIM_TLV_SECURITY_ATTR_8C:
+		case USIM_TLV_SECURITY_ATTR_AB:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
+				    "TLV", pos + 2, pos[1]);
+			break;
+		default:
+			wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
+				    pos, 2 + pos[1]);
+			break;
+		}
+
+		pos += 2 + pos[1];
+
+		if (pos == end)
+			return 0;
+	}
+	return -1;
+}
+
+
+static int scard_pin_needed(struct scard_data *scard,
+			    unsigned char *hdr, size_t hlen)
+{
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		if (hlen > SCARD_CHV1_OFFSET &&
+		    !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
+			return 1;
+		return 0;
+	}
+
+	if (scard->sim_type == SCARD_USIM) {
+		int ps_do;
+		if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
+			return -1;
+		/* TODO: there could be more than one PS_DO entry because of
+		 * multiple PINs in key reference.. */
+		if (ps_do > 0 && (ps_do & 0x80))
+			return 1;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
+			 size_t maxlen)
+{
+	int rlen, rec;
+	struct efdir {
+		unsigned char appl_template_tag; /* 0x61 */
+		unsigned char appl_template_len;
+		unsigned char appl_id_tag; /* 0x4f */
+		unsigned char aid_len;
+		unsigned char rid[5];
+		unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
+	} *efdir;
+	unsigned char buf[127];
+	size_t blen;
+
+	efdir = (struct efdir *) buf;
+	blen = sizeof(buf);
+	if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
+		wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
+
+	for (rec = 1; rec < 10; rec++) {
+		rlen = scard_get_record_len(scard, rec,
+					    SIM_RECORD_MODE_ABSOLUTE);
+		if (rlen < 0) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
+				   "record length");
+			return -1;
+		}
+		blen = sizeof(buf);
+		if (rlen > (int) blen) {
+			wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
+			return -1;
+		}
+		if (scard_read_record(scard, buf, rlen, rec,
+				      SIM_RECORD_MODE_ABSOLUTE) < 0) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
+				   "EF_DIR record %d", rec);
+			return -1;
+		}
+		wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
+
+		if (efdir->appl_template_tag != 0x61) {
+			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+				   "template tag 0x%x",
+				   efdir->appl_template_tag);
+			continue;
+		}
+
+		if (efdir->appl_template_len > rlen - 2) {
+			wpa_printf(MSG_DEBUG, "SCARD: Too long application "
+				   "template (len=%d rlen=%d)",
+				   efdir->appl_template_len, rlen);
+			continue;
+		}
+
+		if (efdir->appl_id_tag != 0x4f) {
+			wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+				   "identifier tag 0x%x", efdir->appl_id_tag);
+			continue;
+		}
+
+		if (efdir->aid_len < 1 || efdir->aid_len > 16) {
+			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
+				   efdir->aid_len);
+			continue;
+		}
+
+		wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
+			    efdir->rid, efdir->aid_len);
+
+		if (efdir->appl_code[0] == 0x10 &&
+		    efdir->appl_code[1] == 0x02) {
+			wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
+				   "EF_DIR record %d", rec);
+			break;
+		}
+	}
+
+	if (rec >= 10) {
+		wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
+			   "from EF_DIR records");
+		return -1;
+	}
+
+	if (efdir->aid_len > maxlen) {
+		wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
+		return -1;
+	}
+
+	os_memcpy(aid, efdir->rid, efdir->aid_len);
+
+	return efdir->aid_len;
+}
+
+
+/**
+ * scard_init - Initialize SIM/USIM connection using PC/SC
+ * @sim_type: Allowed SIM types (SIM, USIM, or both)
+ * @reader: Reader name prefix to search for
+ * Returns: Pointer to private data structure, or %NULL on failure
+ *
+ * This function is used to initialize SIM/USIM connection. PC/SC is used to
+ * open connection to the SIM/USIM card and the card is verified to support the
+ * selected sim_type. In addition, local flag is set if a PIN is needed to
+ * access some of the card functions. Once the connection is not needed
+ * anymore, scard_deinit() can be used to close it.
+ */
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader)
+{
+	long ret;
+	unsigned long len, pos;
+	struct scard_data *scard;
+#ifdef CONFIG_NATIVE_WINDOWS
+	TCHAR *readers = NULL;
+#else /* CONFIG_NATIVE_WINDOWS */
+	char *readers = NULL;
+#endif /* CONFIG_NATIVE_WINDOWS */
+	unsigned char buf[100];
+	size_t blen;
+	int transaction = 0;
+	int pin_needed;
+
+	wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
+	if (mingw_load_symbols())
+		return NULL;
+	scard = os_zalloc(sizeof(*scard));
+	if (scard == NULL)
+		return NULL;
+
+	ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
+				    &scard->ctx);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
+			   "context (err=%ld)", ret);
+		goto failed;
+	}
+
+	ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
+			   "(err=%ld)", ret);
+		goto failed;
+	}
+
+#ifdef UNICODE
+	len *= 2;
+#endif /* UNICODE */
+	readers = os_malloc(len);
+	if (readers == NULL) {
+		wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
+		goto failed;
+	}
+
+	ret = SCardListReaders(scard->ctx, NULL, readers, &len);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
+			   "(err=%ld)", ret);
+		goto failed;
+	}
+	if (len < 3) {
+		wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
+			   "available.");
+		goto failed;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len);
+	/*
+	 * readers is a list of available readers. The last entry is terminated
+	 * with double null.
+	 */
+	pos = 0;
+#ifdef UNICODE
+	/* TODO */
+#else /* UNICODE */
+	while (pos < len) {
+		if (reader == NULL ||
+		    os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0)
+			break;
+		while (pos < len && readers[pos])
+			pos++;
+		pos++; /* skip separating null */
+		if (pos < len && readers[pos] == '\0')
+			pos = len; /* double null terminates list */
+	}
+#endif /* UNICODE */
+	if (pos >= len) {
+		wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' "
+			   "found", reader);
+		goto failed;
+	}
+
+#ifdef UNICODE
+	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]);
+#else /* UNICODE */
+	wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]);
+#endif /* UNICODE */
+
+	ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED,
+			   SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+			   &scard->card, &scard->protocol);
+	if (ret != SCARD_S_SUCCESS) {
+		if (ret == (long) SCARD_E_NO_SMARTCARD)
+			wpa_printf(MSG_INFO, "No smart card inserted.");
+		else
+			wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
+		goto failed;
+	}
+
+	os_free(readers);
+	readers = NULL;
+
+	wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
+		   (unsigned int) scard->card, scard->protocol,
+		   scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
+
+	ret = SCardBeginTransaction(scard->card);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
+			   "0x%x", (unsigned int) ret);
+		goto failed;
+	}
+	transaction = 1;
+
+	blen = sizeof(buf);
+
+	scard->sim_type = SCARD_GSM_SIM;
+	if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
+		wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
+		if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
+				       SCARD_USIM, NULL, 0)) {
+			wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
+			if (sim_type == SCARD_USIM_ONLY)
+				goto failed;
+			wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
+			scard->sim_type = SCARD_GSM_SIM;
+		} else {
+			wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+			scard->sim_type = SCARD_USIM;
+		}
+	}
+
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		blen = sizeof(buf);
+		if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
+			goto failed;
+		}
+
+		blen = sizeof(buf);
+		if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
+			goto failed;
+		}
+	} else {
+		unsigned char aid[32];
+		int aid_len;
+
+		aid_len = scard_get_aid(scard, aid, sizeof(aid));
+		if (aid_len < 0) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
+				   "3G USIM app - try to use standard 3G RID");
+			os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
+			aid_len = 5;
+		}
+		wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
+
+		/* Select based on AID = 3G RID from EF_DIR. This is usually
+		 * starting with A0 00 00 00 87. */
+		blen = sizeof(buf);
+		if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
+				       aid, aid_len)) {
+			wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
+				   "app");
+			wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
+				    aid, aid_len);
+			goto failed;
+		}
+	}
+
+	/* Verify whether CHV1 (PIN1) is needed to access the card. */
+	pin_needed = scard_pin_needed(scard, buf, blen);
+	if (pin_needed < 0) {
+		wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
+			   "is needed");
+		goto failed;
+	}
+	if (pin_needed) {
+		scard->pin1_required = 1;
+		wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access (retry "
+			   "counter=%d)", scard_get_pin_retry_counter(scard));
+	}
+
+	ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
+			   "0x%x", (unsigned int) ret);
+	}
+
+	return scard;
+
+failed:
+	if (transaction)
+		SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+	os_free(readers);
+	scard_deinit(scard);
+	return NULL;
+}
+
+
+/**
+ * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
+ * @scard: Pointer to private data from scard_init()
+ * @pin: PIN code as an ASCII string (e.g., "1234")
+ * Returns: 0 on success, -1 on failure
+ */
+int scard_set_pin(struct scard_data *scard, const char *pin)
+{
+	if (scard == NULL)
+		return -1;
+
+	/* Verify whether CHV1 (PIN1) is needed to access the card. */
+	if (scard->pin1_required) {
+		if (pin == NULL) {
+			wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
+				   "access");
+			return -1;
+		}
+		if (scard_verify_pin(scard, pin)) {
+			wpa_printf(MSG_INFO, "PIN verification failed for "
+				"SIM access");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * scard_deinit - Deinitialize SIM/USIM connection
+ * @scard: Pointer to private data from scard_init()
+ *
+ * This function closes the SIM/USIM connect opened with scard_init().
+ */
+void scard_deinit(struct scard_data *scard)
+{
+	long ret;
+
+	if (scard == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
+	if (scard->card) {
+		ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
+		if (ret != SCARD_S_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
+				   "smart card (err=%ld)", ret);
+		}
+	}
+
+	if (scard->ctx) {
+		ret = SCardReleaseContext(scard->ctx);
+		if (ret != SCARD_S_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "Failed to release smart card "
+				   "context (err=%ld)", ret);
+		}
+	}
+	os_free(scard);
+	mingw_unload_symbols();
+}
+
+
+static long scard_transmit(struct scard_data *scard,
+			   unsigned char *_send, size_t send_len,
+			   unsigned char *_recv, size_t *recv_len)
+{
+	long ret;
+	unsigned long rlen;
+
+	wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
+			_send, send_len);
+	rlen = *recv_len;
+	ret = SCardTransmit(scard->card,
+			    scard->protocol == SCARD_PROTOCOL_T1 ?
+			    SCARD_PCI_T1 : SCARD_PCI_T0,
+			    _send, (unsigned long) send_len,
+			    NULL, _recv, &rlen);
+	*recv_len = rlen;
+	if (ret == SCARD_S_SUCCESS) {
+		wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
+			    _recv, rlen);
+	} else {
+		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+			   "(err=0x%lx)", ret);
+	}
+	return ret;
+}
+
+
+static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
+			      unsigned char *buf, size_t *buf_len,
+			      sim_types sim_type, unsigned char *aid,
+			      size_t aidlen)
+{
+	long ret;
+	unsigned char resp[3];
+	unsigned char cmd[50] = { SIM_CMD_SELECT };
+	int cmdlen;
+	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+	size_t len, rlen;
+
+	if (sim_type == SCARD_USIM) {
+		cmd[0] = USIM_CLA;
+		cmd[3] = 0x04;
+		get_resp[0] = USIM_CLA;
+	}
+
+	wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
+	if (aid) {
+		wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
+			    aid, aidlen);
+		if (5 + aidlen > sizeof(cmd))
+			return -1;
+		cmd[2] = 0x04; /* Select by AID */
+		cmd[4] = aidlen; /* len */
+		os_memcpy(cmd + 5, aid, aidlen);
+		cmdlen = 5 + aidlen;
+	} else {
+		cmd[5] = file_id >> 8;
+		cmd[6] = file_id & 0xff;
+		cmdlen = 7;
+	}
+	len = sizeof(resp);
+	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+			   "(err=0x%lx)", ret);
+		return -1;
+	}
+
+	if (len != 2) {
+		wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
+			   "%d (expected 2)", (int) len);
+		return -1;
+	}
+
+	if (resp[0] == 0x98 && resp[1] == 0x04) {
+		/* Security status not satisfied (PIN_WLAN) */
+		wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
+			   "(PIN_WLAN)");
+		return -1;
+	}
+
+	if (resp[0] == 0x6e) {
+		wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
+		return -1;
+	}
+
+	if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
+		wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
+			   "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
+		return -1;
+	}
+	/* Normal ending of command; resp[1] bytes available */
+	get_resp[4] = resp[1];
+	wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
+		   resp[1]);
+
+	rlen = *buf_len;
+	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
+	if (ret == SCARD_S_SUCCESS) {
+		*buf_len = resp[1] < rlen ? resp[1] : rlen;
+		return 0;
+	}
+
+	wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
+	return -1;
+}
+
+
+static int scard_select_file(struct scard_data *scard, unsigned short file_id,
+			     unsigned char *buf, size_t *buf_len)
+{
+	return _scard_select_file(scard, file_id, buf, buf_len,
+				  scard->sim_type, NULL, 0);
+}
+
+
+static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
+				unsigned char mode)
+{
+	unsigned char buf[255];
+	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+	size_t blen;
+	long ret;
+
+	if (scard->sim_type == SCARD_USIM)
+		cmd[0] = USIM_CLA;
+	cmd[2] = recnum;
+	cmd[3] = mode;
+	cmd[4] = sizeof(buf);
+
+	blen = sizeof(buf);
+	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+	if (ret != SCARD_S_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
+			   "length for record %d", recnum);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
+		    buf, blen);
+
+	if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
+		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
+			   "length determination");
+		return -1;
+	}
+
+	return buf[1];
+}
+
+
+static int scard_read_record(struct scard_data *scard,
+			     unsigned char *data, size_t len,
+			     unsigned char recnum, unsigned char mode)
+{
+	unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+	size_t blen = len + 3;
+	unsigned char *buf;
+	long ret;
+
+	if (scard->sim_type == SCARD_USIM)
+		cmd[0] = USIM_CLA;
+	cmd[2] = recnum;
+	cmd[3] = mode;
+	cmd[4] = len;
+
+	buf = os_malloc(blen);
+	if (buf == NULL)
+		return -1;
+
+	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+	if (ret != SCARD_S_SUCCESS) {
+		os_free(buf);
+		return -2;
+	}
+	if (blen != len + 2) {
+		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+			   "length %ld (expected %ld)",
+			   (long) blen, (long) len + 2);
+		os_free(buf);
+		return -3;
+	}
+
+	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+		wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+			   "status %02x %02x (expected 90 00)",
+			   buf[len], buf[len + 1]);
+		os_free(buf);
+		return -4;
+	}
+
+	os_memcpy(data, buf, len);
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int scard_read_file(struct scard_data *scard,
+			   unsigned char *data, size_t len)
+{
+	unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
+	size_t blen = len + 3;
+	unsigned char *buf;
+	long ret;
+
+	cmd[4] = len;
+
+	buf = os_malloc(blen);
+	if (buf == NULL)
+		return -1;
+
+	if (scard->sim_type == SCARD_USIM)
+		cmd[0] = USIM_CLA;
+	ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+	if (ret != SCARD_S_SUCCESS) {
+		os_free(buf);
+		return -2;
+	}
+	if (blen != len + 2) {
+		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
+			   "length %ld (expected %ld)",
+			   (long) blen, (long) len + 2);
+		os_free(buf);
+		return -3;
+	}
+
+	if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+		wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
+			   "status %02x %02x (expected 90 00)",
+			   buf[len], buf[len + 1]);
+		os_free(buf);
+		return -4;
+	}
+
+	os_memcpy(data, buf, len);
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int scard_verify_pin(struct scard_data *scard, const char *pin)
+{
+	long ret;
+	unsigned char resp[3];
+	unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
+
+	if (pin == NULL || os_strlen(pin) > 8)
+		return -1;
+
+	if (scard->sim_type == SCARD_USIM)
+		cmd[0] = USIM_CLA;
+	os_memcpy(cmd + 5, pin, os_strlen(pin));
+	os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
+
+	len = sizeof(resp);
+	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+	if (ret != SCARD_S_SUCCESS)
+		return -2;
+
+	if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
+		wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
+	return 0;
+}
+
+
+int scard_get_pin_retry_counter(struct scard_data *scard)
+{
+	long ret;
+	unsigned char resp[3];
+	unsigned char cmd[5] = { SIM_CMD_VERIFY_CHV1 };
+	size_t len;
+	u16 val;
+
+	wpa_printf(MSG_DEBUG, "SCARD: fetching PIN retry counter");
+
+	if (scard->sim_type == SCARD_USIM)
+		cmd[0] = USIM_CLA;
+	cmd[4] = 0; /* Empty data */
+
+	len = sizeof(resp);
+	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+	if (ret != SCARD_S_SUCCESS)
+		return -2;
+
+	if (len != 2) {
+		wpa_printf(MSG_WARNING, "SCARD: failed to fetch PIN retry "
+			   "counter");
+		return -1;
+	}
+
+	val = WPA_GET_BE16(resp);
+	if (val == 0x63c0 || val == 0x6983) {
+		wpa_printf(MSG_DEBUG, "SCARD: PIN has been blocked");
+		return 0;
+	}
+
+	if (val >= 0x63c0 && val <= 0x63cf)
+		return val & 0x000f;
+
+	wpa_printf(MSG_DEBUG, "SCARD: Unexpected PIN retry counter response "
+		   "value 0x%x", val);
+	return 0;
+}
+
+
+/**
+ * scard_get_imsi - Read IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @imsi: Buffer for IMSI
+ * @len: Length of imsi buffer; set to IMSI length on success
+ * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
+ * selection returns invalid result code, -3 if parsing FSP template file fails
+ * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
+ * to needed length), -5 if reading IMSI file fails.
+ *
+ * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
+ * file is PIN protected, scard_set_pin() must have been used to set the
+ * correct PIN code before calling scard_get_imsi().
+ */
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
+{
+	unsigned char buf[100];
+	size_t blen, imsilen, i;
+	char *pos;
+
+	wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
+	blen = sizeof(buf);
+	if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
+		return -1;
+	if (blen < 4) {
+		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
+			   "header (len=%ld)", (long) blen);
+		return -2;
+	}
+
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		blen = (buf[2] << 8) | buf[3];
+	} else {
+		int file_size;
+		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
+			return -3;
+		blen = file_size;
+	}
+	if (blen < 2 || blen > sizeof(buf)) {
+		wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
+			   (long) blen);
+		return -3;
+	}
+
+	imsilen = (blen - 2) * 2 + 1;
+	wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
+		   (long) blen, (long) imsilen);
+	if (blen < 2 || imsilen > *len) {
+		*len = imsilen;
+		return -4;
+	}
+
+	if (scard_read_file(scard, buf, blen))
+		return -5;
+
+	pos = imsi;
+	*pos++ = '0' + (buf[1] >> 4 & 0x0f);
+	for (i = 2; i < blen; i++) {
+		unsigned char digit;
+
+		digit = buf[i] & 0x0f;
+		if (digit < 10)
+			*pos++ = '0' + digit;
+		else
+			imsilen--;
+
+		digit = buf[i] >> 4 & 0x0f;
+		if (digit < 10)
+			*pos++ = '0' + digit;
+		else
+			imsilen--;
+	}
+	*len = imsilen;
+
+	return 0;
+}
+
+
+/**
+ * scard_get_mnc_len - Read length of MNC in the IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * Returns: length (>0) on success, -1 if administrative data file cannot be
+ * selected, -2 if administrative data file selection returns invalid result
+ * code, -3 if parsing FSP template file fails (USIM only), -4 if length of
+ * the file is unexpected, -5 if reading file fails, -6 if MNC length is not
+ * in range (i.e. 2 or 3), -7 if MNC length is not available.
+ *
+ */
+int scard_get_mnc_len(struct scard_data *scard)
+{
+	unsigned char buf[100];
+	size_t blen;
+	int file_size;
+
+	wpa_printf(MSG_DEBUG, "SCARD: reading MNC len from (GSM) EF-AD");
+	blen = sizeof(buf);
+	if (scard_select_file(scard, SCARD_FILE_GSM_EF_AD, buf, &blen))
+		return -1;
+	if (blen < 4) {
+		wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-AD "
+			   "header (len=%ld)", (long) blen);
+		return -2;
+	}
+
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		file_size = (buf[2] << 8) | buf[3];
+	} else {
+		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
+			return -3;
+	}
+	if (file_size == 3) {
+		wpa_printf(MSG_DEBUG, "SCARD: MNC length not available");
+		return -7;
+	}
+	if (file_size < 4 || file_size > (int) sizeof(buf)) {
+		wpa_printf(MSG_DEBUG, "SCARD: invalid file length=%ld",
+			   (long) file_size);
+		return -4;
+	}
+
+	if (scard_read_file(scard, buf, file_size))
+		return -5;
+	buf[3] = buf[3] & 0x0f; /* upper nibble reserved for future use  */
+	if (buf[3] < 2 || buf[3] > 3) {
+		wpa_printf(MSG_DEBUG, "SCARD: invalid MNC length=%ld",
+			   (long) buf[3]);
+		return -6;
+	}
+	wpa_printf(MSG_DEBUG, "SCARD: MNC length=%ld", (long) buf[3]);
+	return buf[3];
+}
+
+
+/**
+ * scard_gsm_auth - Run GSM authentication command on SIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @sres: 4-byte buffer for SRES
+ * @kc: 8-byte buffer for Kc
+ * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
+ * -2 if authentication command execution fails, -3 if unknown response code
+ * for authentication command is received, -4 if reading of response fails,
+ * -5 if if response data is of unexpected length
+ *
+ * This function performs GSM authentication using SIM/USIM card and the
+ * provided RAND value from HLR/AuC. If authentication command can be completed
+ * successfully, SRES and Kc values will be written into sres and kc buffers.
+ */
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
+		   unsigned char *sres, unsigned char *kc)
+{
+	unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
+	int cmdlen;
+	unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+	unsigned char resp[3], buf[12 + 3 + 2];
+	size_t len;
+	long ret;
+
+	if (scard == NULL)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		cmdlen = 5 + 16;
+		os_memcpy(cmd + 5, _rand, 16);
+	} else {
+		cmdlen = 5 + 1 + 16;
+		cmd[0] = USIM_CLA;
+		cmd[3] = 0x80;
+		cmd[4] = 17;
+		cmd[5] = 16;
+		os_memcpy(cmd + 6, _rand, 16);
+	}
+	len = sizeof(resp);
+	ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
+	if (ret != SCARD_S_SUCCESS)
+		return -2;
+
+	if ((scard->sim_type == SCARD_GSM_SIM &&
+	     (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
+	    (scard->sim_type == SCARD_USIM &&
+	     (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
+		wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
+			   "auth request (len=%ld resp=%02x %02x)",
+			   (long) len, resp[0], resp[1]);
+		return -3;
+	}
+	get_resp[4] = resp[1];
+
+	len = sizeof(buf);
+	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+	if (ret != SCARD_S_SUCCESS)
+		return -4;
+
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		if (len != 4 + 8 + 2) {
+			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+				   "length for GSM auth (len=%ld, expected 14)",
+				   (long) len);
+			return -5;
+		}
+		os_memcpy(sres, buf, 4);
+		os_memcpy(kc, buf + 4, 8);
+	} else {
+		if (len != 1 + 4 + 1 + 8 + 2) {
+			wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+				   "length for USIM auth (len=%ld, "
+				   "expected 16)", (long) len);
+			return -5;
+		}
+		if (buf[0] != 4 || buf[5] != 8) {
+			wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
+				   "length (%d %d, expected 4 8)",
+				   buf[0], buf[5]);
+		}
+		os_memcpy(sres, buf + 1, 4);
+		os_memcpy(kc, buf + 6, 8);
+	}
+
+	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
+	wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
+
+	return 0;
+}
+
+
+/**
+ * scard_umts_auth - Run UMTS authentication command on USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @autn: 16-byte AUTN value from HLR/AuC
+ * @res: 16-byte buffer for RES
+ * @res_len: Variable that will be set to RES length
+ * @ik: 16-byte buffer for IK
+ * @ck: 16-byte buffer for CK
+ * @auts: 14-byte buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
+ * failure
+ *
+ * This function performs AKA authentication using USIM card and the provided
+ * RAND and AUTN values from HLR/AuC. If authentication command can be
+ * completed successfully, RES, IK, and CK values will be written into provided
+ * buffers and res_len is set to length of received RES value. If USIM reports
+ * synchronization failure, the received AUTS value will be written into auts
+ * buffer. In this case, RES, IK, and CK are not valid.
+ */
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+		    const unsigned char *autn,
+		    unsigned char *res, size_t *res_len,
+		    unsigned char *ik, unsigned char *ck, unsigned char *auts)
+{
+	unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
+		{ USIM_CMD_RUN_UMTS_ALG };
+	unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
+	unsigned char resp[3], buf[64], *pos, *end;
+	size_t len;
+	long ret;
+
+	if (scard == NULL)
+		return -1;
+
+	if (scard->sim_type == SCARD_GSM_SIM) {
+		wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
+			   "auth");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
+	cmd[5] = AKA_RAND_LEN;
+	os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
+	cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
+	os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
+
+	len = sizeof(resp);
+	ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+	if (ret != SCARD_S_SUCCESS)
+		return -1;
+
+	if (len <= sizeof(resp))
+		wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
+
+	if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
+		wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
+			   "MAC != XMAC");
+		return -1;
+	} else if (len != 2 || resp[0] != 0x61) {
+		wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
+			   "auth request (len=%ld resp=%02x %02x)",
+			   (long) len, resp[0], resp[1]);
+		return -1;
+	}
+	get_resp[4] = resp[1];
+
+	len = sizeof(buf);
+	ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+	if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
+	if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
+	    buf[1] == AKA_AUTS_LEN) {
+		wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
+		os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
+		wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
+		return -2;
+	} else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
+		pos = buf + 1;
+		end = buf + len;
+
+		/* RES */
+		if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
+			wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
+			return -1;
+		}
+		*res_len = *pos++;
+		os_memcpy(res, pos, *res_len);
+		pos += *res_len;
+		wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
+
+		/* CK */
+		if (pos[0] != CK_LEN || pos + CK_LEN > end) {
+			wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
+			return -1;
+		}
+		pos++;
+		os_memcpy(ck, pos, CK_LEN);
+		pos += CK_LEN;
+		wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
+
+		/* IK */
+		if (pos[0] != IK_LEN || pos + IK_LEN > end) {
+			wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
+			return -1;
+		}
+		pos++;
+		os_memcpy(ik, pos, IK_LEN);
+		pos += IK_LEN;
+		wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
+
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
+	return -1;
+}
+
+
+int scard_supports_umts(struct scard_data *scard)
+{
+	return scard->sim_type == SCARD_USIM;
+}

Deleted: vendor/wpa/2.0/src/utils/pcsc_funcs.h
===================================================================
--- vendor/wpa/dist/src/utils/pcsc_funcs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/pcsc_funcs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,68 +0,0 @@
-/*
- * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef PCSC_FUNCS_H
-#define PCSC_FUNCS_H
-
-/* GSM files
- * File type in first octet:
- * 3F = Master File
- * 7F = Dedicated File
- * 2F = Elementary File under the Master File
- * 6F = Elementary File under a Dedicated File
- */
-#define SCARD_FILE_MF		0x3F00
-#define SCARD_FILE_GSM_DF	0x7F20
-#define SCARD_FILE_UMTS_DF	0x7F50
-#define SCARD_FILE_GSM_EF_IMSI	0x6F07
-#define SCARD_FILE_EF_DIR	0x2F00
-#define SCARD_FILE_EF_ICCID	0x2FE2
-#define SCARD_FILE_EF_CK	0x6FE1
-#define SCARD_FILE_EF_IK	0x6FE2
-
-#define SCARD_CHV1_OFFSET	13
-#define SCARD_CHV1_FLAG		0x80
-
-typedef enum {
-	SCARD_GSM_SIM_ONLY,
-	SCARD_USIM_ONLY,
-	SCARD_TRY_BOTH
-} scard_sim_type;
-
-
-#ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type);
-void scard_deinit(struct scard_data *scard);
-
-int scard_set_pin(struct scard_data *scard, const char *pin);
-int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
-int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
-		   unsigned char *sres, unsigned char *kc);
-int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
-		    const unsigned char *autn,
-		    unsigned char *res, size_t *res_len,
-		    unsigned char *ik, unsigned char *ck, unsigned char *auts);
-
-#else /* PCSC_FUNCS */
-
-#define scard_init(s) NULL
-#define scard_deinit(s) do { } while (0)
-#define scard_set_pin(s, p) -1
-#define scard_get_imsi(s, i, l) -1
-#define scard_gsm_auth(s, r, s2, k) -1
-#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
-
-#endif /* PCSC_FUNCS */
-
-#endif /* PCSC_FUNCS_H */

Copied: vendor/wpa/2.0/src/utils/pcsc_funcs.h (from rev 9639, vendor/wpa/dist/src/utils/pcsc_funcs.h)
===================================================================
--- vendor/wpa/2.0/src/utils/pcsc_funcs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/pcsc_funcs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2006, 2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PCSC_FUNCS_H
+#define PCSC_FUNCS_H
+
+typedef enum {
+	SCARD_GSM_SIM_ONLY,
+	SCARD_USIM_ONLY,
+	SCARD_TRY_BOTH
+} scard_sim_type;
+
+
+#ifdef PCSC_FUNCS
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
+void scard_deinit(struct scard_data *scard);
+
+int scard_set_pin(struct scard_data *scard, const char *pin);
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
+int scard_get_mnc_len(struct scard_data *scard);
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
+		   unsigned char *sres, unsigned char *kc);
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+		    const unsigned char *autn,
+		    unsigned char *res, size_t *res_len,
+		    unsigned char *ik, unsigned char *ck, unsigned char *auts);
+int scard_get_pin_retry_counter(struct scard_data *scard);
+int scard_supports_umts(struct scard_data *scard);
+
+#else /* PCSC_FUNCS */
+
+#define scard_init(s, r) NULL
+#define scard_deinit(s) do { } while (0)
+#define scard_set_pin(s, p) -1
+#define scard_get_imsi(s, i, l) -1
+#define scard_get_mnc_len(s) -1
+#define scard_gsm_auth(s, r, s2, k) -1
+#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
+#define scard_get_pin_retry_counter(s) -1
+#define scard_supports_umts(s) 0
+
+#endif /* PCSC_FUNCS */
+
+#endif /* PCSC_FUNCS_H */

Deleted: vendor/wpa/2.0/src/utils/radiotap.h
===================================================================
--- vendor/wpa/dist/src/utils/radiotap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/radiotap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,242 +0,0 @@
-/* $FreeBSD: vendor/wpa/0.7.3/src/utils/radiotap.h 214501 2010-10-29 08:01:21Z rpaulo $ */
-/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
-
-/*-
- * Copyright (c) 2003, 2004 David Young.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
-/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn at kismetwireless.net)
- */
-
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <stdint.h>
-
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION		0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/* The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
- */
-struct ieee80211_radiotap_header {
-	uint8_t it_version;	/* Version 0. Only increases
-				 * for drastic changes,
-				 * introduction of compatible
-				 * new fields does not count.
-				 */
-	uint8_t it_pad;
-	uint16_t 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
-				 * fields are present. Set bit 31
-				 * (0x80000000) to extend the
-				 * bitmap by another 32 bits.
-				 * Additional extensions are made
-				 * by setting bit 31.
-				 */
-};
-
-/* Name                                 Data type    Units
- * ----                                 ---------    -----
- *
- * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
- *
- *      Value in microseconds of the MAC's 64-bit 802.11 Time
- *      Synchronization Function timer when the first bit of the
- *      MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL           2 x uint16_t   MHz, bitmap
- *
- *      Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS              uint16_t       see below
- *
- *      For frequency-hopping radios, the hop set (first byte)
- *      and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE              u8           500kb/s
- *
- *      Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF signal power at the antenna, decibel difference from
- *      one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      RF noise power at the antenna, decibel difference from one
- *      milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
- *
- *      RF signal power at the antenna, decibel difference from an
- *      arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
- *
- *      RF noise power at the antenna, decibel difference from an
- *      arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY      uint16_t       unitless
- *
- *      Quality of Barker code lock. Unitless. Monotonically
- *      nondecreasing with "better" lock strength. Called "Signal
- *      Quality" in datasheets.  (Is there a standard way to measure
- *      this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION    uint16_t       unitless
- *
- *      Transmit power expressed as unitless distance from max
- *      power set at factory calibration.  0 is max power.
- *      Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t       decibels (dB)
- *
- *      Transmit power expressed as decibel distance from max power
- *      set at factory calibration.  0 is max power.  Monotonically
- *      nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
- *                                                   one milliwatt (dBm)
- *
- *      Transmit power expressed as dBm (decibels from a 1 milliwatt
- *      reference). This is the absolute power level measured at
- *      the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
- *
- *      Properties of transmitted and received frames. See flags
- *      defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
- *
- *      Unitless indication of the Rx/Tx antenna for this packet.
- *      The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS          uint16_t       bitmap
- *
- *     Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS          uint16_t       bitmap
- *
- *     Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
- *
- *     Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
- *
- *     Number of unicast retries a transmitted frame used.
- *
- */
-enum ieee80211_radiotap_type {
-	IEEE80211_RADIOTAP_TSFT = 0,
-	IEEE80211_RADIOTAP_FLAGS = 1,
-	IEEE80211_RADIOTAP_RATE = 2,
-	IEEE80211_RADIOTAP_CHANNEL = 3,
-	IEEE80211_RADIOTAP_FHSS = 4,
-	IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
-	IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
-	IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
-	IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
-	IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
-	IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
-	IEEE80211_RADIOTAP_ANTENNA = 11,
-	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
-	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
-	IEEE80211_RADIOTAP_RX_FLAGS = 14,
-	IEEE80211_RADIOTAP_TX_FLAGS = 15,
-	IEEE80211_RADIOTAP_RTS_RETRIES = 16,
-	IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-	IEEE80211_RADIOTAP_EXT = 31
-};
-
-/* Channel flags. */
-#define	IEEE80211_CHAN_TURBO	0x0010	/* Turbo channel */
-#define	IEEE80211_CHAN_CCK	0x0020	/* CCK channel */
-#define	IEEE80211_CHAN_OFDM	0x0040	/* OFDM channel */
-#define	IEEE80211_CHAN_2GHZ	0x0080	/* 2 GHz spectrum channel. */
-#define	IEEE80211_CHAN_5GHZ	0x0100	/* 5 GHz spectrum channel */
-#define	IEEE80211_CHAN_PASSIVE	0x0200	/* Only passive scan allowed */
-#define	IEEE80211_CHAN_DYN	0x0400	/* Dynamic CCK-OFDM channel */
-#define	IEEE80211_CHAN_GFSK	0x0800	/* GFSK channel (FHSS PHY) */
-
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
-						 * during CFP
-						 */
-#define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
-						 * with short
-						 * preamble
-						 */
-#define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
-						 * with WEP encryption
-						 */
-#define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
-						 * with fragmentation
-						 */
-#define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
-#define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
-						 * 802.11 header and payload
-						 * (to 32-bit boundary)
-						 */
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
-
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL	0x0001	/* failed due to excessive
-						 * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
-
-#endif				/* IEEE80211_RADIOTAP_H */

Copied: vendor/wpa/2.0/src/utils/radiotap.h (from rev 9639, vendor/wpa/dist/src/utils/radiotap.h)
===================================================================
--- vendor/wpa/2.0/src/utils/radiotap.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/radiotap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,243 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn at kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <stdint.h>
+
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION		0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+	uint8_t it_version;	/* Version 0. Only increases
+				 * for drastic changes,
+				 * introduction of compatible
+				 * new fields does not count.
+				 */
+	uint8_t it_pad;
+	uint16_t 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
+				 * fields are present. Set bit 31
+				 * (0x80000000) to extend the
+				 * bitmap by another 32 bits.
+				 * Additional extensions are made
+				 * by setting bit 31.
+				 */
+};
+
+/* Name                                 Data type    Units
+ * ----                                 ---------    -----
+ *
+ * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
+ *
+ *      Value in microseconds of the MAC's 64-bit 802.11 Time
+ *      Synchronization Function timer when the first bit of the
+ *      MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL           2 x uint16_t   MHz, bitmap
+ *
+ *      Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS              uint16_t       see below
+ *
+ *      For frequency-hopping radios, the hop set (first byte)
+ *      and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE              u8           500kb/s
+ *
+ *      Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      RF signal power at the antenna, decibel difference from
+ *      one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      RF noise power at the antenna, decibel difference from one
+ *      milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
+ *
+ *      RF signal power at the antenna, decibel difference from an
+ *      arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
+ *
+ *      RF noise power at the antenna, decibel difference from an
+ *      arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY      uint16_t       unitless
+ *
+ *      Quality of Barker code lock. Unitless. Monotonically
+ *      nondecreasing with "better" lock strength. Called "Signal
+ *      Quality" in datasheets.  (Is there a standard way to measure
+ *      this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION    uint16_t       unitless
+ *
+ *      Transmit power expressed as unitless distance from max
+ *      power set at factory calibration.  0 is max power.
+ *      Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t       decibels (dB)
+ *
+ *      Transmit power expressed as decibel distance from max power
+ *      set at factory calibration.  0 is max power.  Monotonically
+ *      nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
+ *                                                   one milliwatt (dBm)
+ *
+ *      Transmit power expressed as dBm (decibels from a 1 milliwatt
+ *      reference). This is the absolute power level measured at
+ *      the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
+ *
+ *      Properties of transmitted and received frames. See flags
+ *      defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
+ *
+ *      Unitless indication of the Rx/Tx antenna for this packet.
+ *      The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS          uint16_t       bitmap
+ *
+ *     Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS          uint16_t       bitmap
+ *
+ *     Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
+ *
+ *     Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
+ *
+ *     Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+	IEEE80211_RADIOTAP_TSFT = 0,
+	IEEE80211_RADIOTAP_FLAGS = 1,
+	IEEE80211_RADIOTAP_RATE = 2,
+	IEEE80211_RADIOTAP_CHANNEL = 3,
+	IEEE80211_RADIOTAP_FHSS = 4,
+	IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+	IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+	IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+	IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+	IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+	IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+	IEEE80211_RADIOTAP_ANTENNA = 11,
+	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+	IEEE80211_RADIOTAP_RX_FLAGS = 14,
+	IEEE80211_RADIOTAP_TX_FLAGS = 15,
+	IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+	IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+	IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define	IEEE80211_CHAN_TURBO	0x0010	/* Turbo channel */
+#define	IEEE80211_CHAN_CCK	0x0020	/* CCK channel */
+#define	IEEE80211_CHAN_OFDM	0x0040	/* OFDM channel */
+#define	IEEE80211_CHAN_2GHZ	0x0080	/* 2 GHz spectrum channel. */
+#define	IEEE80211_CHAN_5GHZ	0x0100	/* 5 GHz spectrum channel */
+#define	IEEE80211_CHAN_PASSIVE	0x0200	/* Only passive scan allowed */
+#define	IEEE80211_CHAN_DYN	0x0400	/* Dynamic CCK-OFDM channel */
+#define	IEEE80211_CHAN_GFSK	0x0800	/* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define	IEEE80211_RADIOTAP_F_CFP	0x01	/* sent/received
+						 * during CFP
+						 */
+#define	IEEE80211_RADIOTAP_F_SHORTPRE	0x02	/* sent/received
+						 * with short
+						 * preamble
+						 */
+#define	IEEE80211_RADIOTAP_F_WEP	0x04	/* sent/received
+						 * with WEP encryption
+						 */
+#define	IEEE80211_RADIOTAP_F_FRAG	0x08	/* sent/received
+						 * with fragmentation
+						 */
+#define	IEEE80211_RADIOTAP_F_FCS	0x10	/* frame includes FCS */
+#define	IEEE80211_RADIOTAP_F_DATAPAD	0x20	/* frame has padding between
+						 * 802.11 header and payload
+						 * (to 32-bit boundary)
+						 */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL	0x0001	/* failed due to excessive
+						 * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ACK */
+
+#endif				/* IEEE80211_RADIOTAP_H */

Deleted: vendor/wpa/2.0/src/utils/radiotap_iter.h
===================================================================
--- vendor/wpa/dist/src/utils/radiotap_iter.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/radiotap_iter.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,41 +0,0 @@
-#ifndef __RADIOTAP_ITER_H
-#define __RADIOTAP_ITER_H
-
-#include "radiotap.h"
-
-/* Radiotap header iteration
- *   implemented in radiotap.c
- */
-/**
- * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
- * @rtheader: pointer to the radiotap header we are walking through
- * @max_length: length of radiotap header in cpu byte ordering
- * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
- * @this_arg: pointer to current radiotap arg
- * @arg_index: internal next argument index
- * @arg: internal next argument pointer
- * @next_bitmap: internal pointer to next present u32
- * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
- */
-
-struct ieee80211_radiotap_iterator {
-	struct ieee80211_radiotap_header *rtheader;
-	int max_length;
-	int this_arg_index;
-	unsigned char *this_arg;
-
-	int arg_index;
-	unsigned char *arg;
-	uint32_t *next_bitmap;
-	uint32_t bitmap_shifter;
-};
-
-extern int ieee80211_radiotap_iterator_init(
-   struct ieee80211_radiotap_iterator *iterator,
-   struct ieee80211_radiotap_header *radiotap_header,
-   int max_length);
-
-extern int ieee80211_radiotap_iterator_next(
-   struct ieee80211_radiotap_iterator *iterator);
-
-#endif /* __RADIOTAP_ITER_H */

Copied: vendor/wpa/2.0/src/utils/radiotap_iter.h (from rev 9639, vendor/wpa/dist/src/utils/radiotap_iter.h)
===================================================================
--- vendor/wpa/2.0/src/utils/radiotap_iter.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/radiotap_iter.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,56 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007		Andy Green <andy at warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef __RADIOTAP_ITER_H
+#define __RADIOTAP_ITER_H
+
+#include "radiotap.h"
+
+/* Radiotap header iteration
+ *   implemented in radiotap.c
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+	struct ieee80211_radiotap_header *rtheader;
+	int max_length;
+	int this_arg_index;
+	unsigned char *this_arg;
+
+	int arg_index;
+	unsigned char *arg;
+	uint32_t *next_bitmap;
+	uint32_t bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+   struct ieee80211_radiotap_iterator *iterator,
+   struct ieee80211_radiotap_header *radiotap_header,
+   int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+   struct ieee80211_radiotap_iterator *iterator);
+
+#endif /* __RADIOTAP_ITER_H */

Deleted: vendor/wpa/2.0/src/utils/state_machine.h
===================================================================
--- vendor/wpa/dist/src/utils/state_machine.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/state_machine.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,144 +0,0 @@
-/*
- * wpa_supplicant/hostapd - State machine definitions
- * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file includes a set of pre-processor macros that can be used to
- * implement a state machine. In addition to including this header file, each
- * file implementing a state machine must define STATE_MACHINE_DATA to be the
- * data structure including state variables (enum machine_state,
- * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
- * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
- * a group of state machines with shared data structure, STATE_MACHINE_ADDR
- * needs to be defined to point to the MAC address used in debug output.
- * SM_ENTRY_M macro can be used to define similar group of state machines
- * without this additional debug info.
- */
-
-#ifndef STATE_MACHINE_H
-#define STATE_MACHINE_H
-
-/**
- * SM_STATE - Declaration of a state machine function
- * @machine: State machine name
- * @state: State machine state
- *
- * This macro is used to declare a state machine function. It is used in place
- * of a C function definition to declare functions to be run when the state is
- * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
- */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
-	int global)
-
-/**
- * SM_ENTRY - State machine function entry point
- * @machine: State machine name
- * @state: State machine state
- *
- * This macro is used inside each state machine function declared with
- * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
- * after declaration of possible local variables. This macro prints debug
- * information about state transition and update the state machine state.
- */
-#define SM_ENTRY(machine, state) \
-if (!global || sm->machine ## _state != machine ## _ ## state) { \
-	sm->changed = TRUE; \
-	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
-		   " entering state " #state); \
-} \
-sm->machine ## _state = machine ## _ ## state;
-
-/**
- * SM_ENTRY_M - State machine function entry point for state machine group
- * @machine: State machine name
- * @_state: State machine state
- * @data: State variable prefix (full variable: prefix_state)
- *
- * This macro is like SM_ENTRY, but for state machine groups that use a shared
- * data structure for more than one state machine. Both machine and prefix
- * parameters are set to "sub-state machine" name. prefix is used to allow more
- * than one state variable to be stored in the same data structure.
- */
-#define SM_ENTRY_M(machine, _state, data) \
-if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
-	sm->changed = TRUE; \
-	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
-		   #machine " entering state " #_state); \
-} \
-sm->data ## _ ## state = machine ## _ ## _state;
-
-/**
- * SM_ENTRY_MA - State machine function entry point for state machine group
- * @machine: State machine name
- * @_state: State machine state
- * @data: State variable prefix (full variable: prefix_state)
- *
- * This macro is like SM_ENTRY_M, but a MAC address is included in debug
- * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to
- * be included in debug.
- */
-#define SM_ENTRY_MA(machine, _state, data) \
-if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
-	sm->changed = TRUE; \
-	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
-		   #machine " entering state " #_state, \
-		   MAC2STR(STATE_MACHINE_ADDR)); \
-} \
-sm->data ## _ ## state = machine ## _ ## _state;
-
-/**
- * SM_ENTER - Enter a new state machine state
- * @machine: State machine name
- * @state: State machine state
- *
- * This macro expands to a function call to a state machine function defined
- * with SM_STATE macro. SM_ENTER is used in a state machine step function to
- * move the state machine to a new state.
- */
-#define SM_ENTER(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 0)
-
-/**
- * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
- * @machine: State machine name
- * @state: State machine state
- *
- * This macro is like SM_ENTER, but this is used when entering a new state
- * based on a global (not specific to any particular state) rule. A separate
- * macro is used to avoid unwanted debug message floods when the same global
- * rule is forcing a state machine to remain in on state.
- */
-#define SM_ENTER_GLOBAL(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 1)
-
-/**
- * SM_STEP - Declaration of a state machine step function
- * @machine: State machine name
- *
- * This macro is used to declare a state machine step function. It is used in
- * place of a C function definition to declare a function that is used to move
- * state machine to a new state based on state variables. This function uses
- * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
- */
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
-
-/**
- * SM_STEP_RUN - Call the state machine step function
- * @machine: State machine name
- *
- * This macro expands to a function call to a state machine step function
- * defined with SM_STEP macro.
- */
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-#endif /* STATE_MACHINE_H */

Copied: vendor/wpa/2.0/src/utils/state_machine.h (from rev 9639, vendor/wpa/dist/src/utils/state_machine.h)
===================================================================
--- vendor/wpa/2.0/src/utils/state_machine.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/state_machine.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,138 @@
+/*
+ * wpa_supplicant/hostapd - State machine definitions
+ * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file includes a set of pre-processor macros that can be used to
+ * implement a state machine. In addition to including this header file, each
+ * file implementing a state machine must define STATE_MACHINE_DATA to be the
+ * data structure including state variables (enum machine_state,
+ * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
+ * a group of state machines with shared data structure, STATE_MACHINE_ADDR
+ * needs to be defined to point to the MAC address used in debug output.
+ * SM_ENTRY_M macro can be used to define similar group of state machines
+ * without this additional debug info.
+ */
+
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+/**
+ * SM_STATE - Declaration of a state machine function
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used to declare a state machine function. It is used in place
+ * of a C function definition to declare functions to be run when the state is
+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
+ */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
+	int global)
+
+/**
+ * SM_ENTRY - State machine function entry point
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used inside each state machine function declared with
+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
+ * after declaration of possible local variables. This macro prints debug
+ * information about state transition and update the state machine state.
+ */
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
+		   " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+/**
+ * SM_ENTRY_M - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY, but for state machine groups that use a shared
+ * data structure for more than one state machine. Both machine and prefix
+ * parameters are set to "sub-state machine" name. prefix is used to allow more
+ * than one state variable to be stored in the same data structure.
+ */
+#define SM_ENTRY_M(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
+		   #machine " entering state " #_state); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTRY_MA - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY_M, but a MAC address is included in debug
+ * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to
+ * be included in debug.
+ */
+#define SM_ENTRY_MA(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
+		   #machine " entering state " #_state, \
+		   MAC2STR(STATE_MACHINE_ADDR)); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTER - Enter a new state machine state
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro expands to a function call to a state machine function defined
+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to
+ * move the state machine to a new state.
+ */
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+
+/**
+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is like SM_ENTER, but this is used when entering a new state
+ * based on a global (not specific to any particular state) rule. A separate
+ * macro is used to avoid unwanted debug message floods when the same global
+ * rule is forcing a state machine to remain in on state.
+ */
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+/**
+ * SM_STEP - Declaration of a state machine step function
+ * @machine: State machine name
+ *
+ * This macro is used to declare a state machine step function. It is used in
+ * place of a C function definition to declare a function that is used to move
+ * state machine to a new state based on state variables. This function uses
+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
+ */
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
+
+/**
+ * SM_STEP_RUN - Call the state machine step function
+ * @machine: State machine name
+ *
+ * This macro expands to a function call to a state machine step function
+ * defined with SM_STEP macro.
+ */
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+#endif /* STATE_MACHINE_H */

Deleted: vendor/wpa/2.0/src/utils/trace.c
===================================================================
--- vendor/wpa/dist/src/utils/trace.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/trace.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,329 +0,0 @@
-/*
- * Backtrace debugging
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "trace.h"
-
-#ifdef WPA_TRACE
-
-static struct dl_list active_references =
-{ &active_references, &active_references };
-
-#ifdef WPA_TRACE_BFD
-#include <bfd.h>
-#ifdef __linux__
-#include <demangle.h>
-#else /* __linux__ */
-#include <libiberty/demangle.h>
-#endif /* __linux__ */
-
-static char *prg_fname = NULL;
-static bfd *cached_abfd = NULL;
-static asymbol **syms = NULL;
-
-static void get_prg_fname(void)
-{
-	char exe[50], fname[512];
-	int len;
-	os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
-	len = readlink(exe, fname, sizeof(fname) - 1);
-	if (len < 0 || len >= (int) sizeof(fname)) {
-		perror("readlink");
-		return;
-	}
-	fname[len] = '\0';
-	prg_fname = strdup(fname);
-}
-
-
-static bfd * open_bfd(const char *fname)
-{
-	bfd *abfd;
-	char **matching;
-
-	abfd = bfd_openr(prg_fname, NULL);
-	if (abfd == NULL) {
-		wpa_printf(MSG_INFO, "bfd_openr failed");
-		return NULL;
-	}
-
-	if (bfd_check_format(abfd, bfd_archive)) {
-		wpa_printf(MSG_INFO, "bfd_check_format failed");
-		bfd_close(abfd);
-		return NULL;
-	}
-
-	if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
-		wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
-		free(matching);
-		bfd_close(abfd);
-		return NULL;
-	}
-
-	return abfd;
-}
-
-
-static void read_syms(bfd *abfd)
-{
-	long storage, symcount;
-	bfd_boolean dynamic = FALSE;
-
-	if (syms)
-		return;
-
-	if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
-		wpa_printf(MSG_INFO, "No symbols");
-		return;
-	}
-
-	storage = bfd_get_symtab_upper_bound(abfd);
-	if (storage == 0) {
-		storage = bfd_get_dynamic_symtab_upper_bound(abfd);
-		dynamic = TRUE;
-	}
-	if (storage < 0) {
-		wpa_printf(MSG_INFO, "Unknown symtab upper bound");
-		return;
-	}
-
-	syms = malloc(storage);
-	if (syms == NULL) {
-		wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
-			   "(%ld bytes)", storage);
-		return;
-	}
-	if (dynamic)
-		symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
-	else
-		symcount = bfd_canonicalize_symtab(abfd, syms);
-	if (symcount < 0) {
-		wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
-			   dynamic ? "dynamic " : "");
-		free(syms);
-		syms = NULL;
-		return;
-	}
-}
-
-
-struct bfd_data {
-	bfd_vma pc;
-	bfd_boolean found;
-	const char *filename;
-	const char *function;
-	unsigned int line;
-};
-
-
-static void find_addr_sect(bfd *abfd, asection *section, void *obj)
-{
-	struct bfd_data *data = obj;
-	bfd_vma vma;
-	bfd_size_type size;
-
-	if (data->found)
-		return;
-
-	if (!(bfd_get_section_vma(abfd, section)))
-		return;
-
-	vma = bfd_get_section_vma(abfd, section);
-	if (data->pc < vma)
-		return;
-
-	size = bfd_get_section_size(section);
-	if (data->pc >= vma + size)
-		return;
-
-	data->found = bfd_find_nearest_line(abfd, section, syms,
-					    data->pc - vma,
-					    &data->filename,
-					    &data->function,
-					    &data->line);
-}
-
-
-static void wpa_trace_bfd_addr(void *pc)
-{
-	bfd *abfd = cached_abfd;
-	struct bfd_data data;
-	const char *name;
-	char *aname = NULL;
-	const char *filename;
-
-	if (abfd == NULL)
-		return;
-
-	data.pc = (bfd_vma) pc;
-	data.found = FALSE;
-	bfd_map_over_sections(abfd, find_addr_sect, &data);
-
-	if (!data.found)
-		return;
-
-	do {
-		if (data.function)
-			aname = bfd_demangle(abfd, data.function,
-					     DMGL_ANSI | DMGL_PARAMS);
-		name = aname ? aname : data.function;
-		filename = data.filename;
-		if (filename) {
-			char *end = os_strrchr(filename, '/');
-			int i = 0;
-			while (*filename && *filename == prg_fname[i] &&
-			       filename <= end) {
-				filename++;
-				i++;
-			}
-		}
-		wpa_printf(MSG_INFO, "     %s() %s:%u",
-			   name, filename, data.line);
-		free(aname);
-
-		data.found = bfd_find_inliner_info(abfd, &data.filename,
-						   &data.function, &data.line);
-	} while (data.found);
-}
-
-
-static const char * wpa_trace_bfd_addr2func(void *pc)
-{
-	bfd *abfd = cached_abfd;
-	struct bfd_data data;
-
-	if (abfd == NULL)
-		return NULL;
-
-	data.pc = (bfd_vma) pc;
-	data.found = FALSE;
-	bfd_map_over_sections(abfd, find_addr_sect, &data);
-
-	if (!data.found)
-		return NULL;
-
-	return data.function;
-}
-
-
-static void wpa_trace_bfd_init(void)
-{
-	if (!prg_fname) {
-		get_prg_fname();
-		if (!prg_fname)
-			return;
-	}
-
-	if (!cached_abfd) {
-		cached_abfd = open_bfd(prg_fname);
-		if (!cached_abfd) {
-			wpa_printf(MSG_INFO, "Failed to open bfd");
-			return;
-		}
-	}
-
-	read_syms(cached_abfd);
-	if (!syms) {
-		wpa_printf(MSG_INFO, "Failed to read symbols");
-		return;
-	}
-}
-
-
-void wpa_trace_dump_funcname(const char *title, void *pc)
-{
-	wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
-	wpa_trace_bfd_init();
-	wpa_trace_bfd_addr(pc);
-}
-
-#else /* WPA_TRACE_BFD */
-
-#define wpa_trace_bfd_init() do { } while (0)
-#define wpa_trace_bfd_addr(pc) do { } while (0)
-#define wpa_trace_bfd_addr2func(pc) NULL
-
-#endif /* WPA_TRACE_BFD */
-
-void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
-{
-	char **sym;
-	int i;
-	enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
-
-	wpa_trace_bfd_init();
-	wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
-	sym = backtrace_symbols(btrace, btrace_num);
-	state = TRACE_HEAD;
-	for (i = 0; i < btrace_num; i++) {
-		const char *func = wpa_trace_bfd_addr2func(btrace[i]);
-		if (state == TRACE_HEAD && func &&
-		    (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
-		     os_strcmp(func, "wpa_trace_check_ref") == 0 ||
-		     os_strcmp(func, "wpa_trace_show") == 0))
-			continue;
-		if (state == TRACE_TAIL && sym && sym[i] &&
-		    os_strstr(sym[i], "__libc_start_main"))
-			break;
-		if (state == TRACE_HEAD)
-			state = TRACE_RELEVANT;
-		if (sym)
-			wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
-		else
-			wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
-		wpa_trace_bfd_addr(btrace[i]);
-		if (state == TRACE_RELEVANT && func &&
-		    os_strcmp(func, "main") == 0)
-			state = TRACE_TAIL;
-	}
-	free(sym);
-	wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
-}
-
-
-void wpa_trace_show(const char *title)
-{
-	struct info {
-		WPA_TRACE_INFO
-	} info;
-	wpa_trace_record(&info);
-	wpa_trace_dump(title, &info);
-}
-
-
-void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
-{
-	if (addr == NULL)
-		return;
-	ref->addr = addr;
-	wpa_trace_record(ref);
-	dl_list_add(&active_references, &ref->list);
-}
-
-
-void wpa_trace_check_ref(const void *addr)
-{
-	struct wpa_trace_ref *ref;
-	dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
-		if (addr != ref->addr)
-			continue;
-		wpa_trace_show("Freeing referenced memory");
-		wpa_trace_dump("Reference registration", ref);
-		abort();
-	}
-}
-
-#endif /* WPA_TRACE */

Copied: vendor/wpa/2.0/src/utils/trace.c (from rev 9639, vendor/wpa/dist/src/utils/trace.c)
===================================================================
--- vendor/wpa/2.0/src/utils/trace.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/trace.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,323 @@
+/*
+ * Backtrace debugging
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "trace.h"
+
+#ifdef WPA_TRACE
+
+static struct dl_list active_references =
+{ &active_references, &active_references };
+
+#ifdef WPA_TRACE_BFD
+#include <bfd.h>
+#ifdef __linux__
+#include <demangle.h>
+#else /* __linux__ */
+#include <libiberty/demangle.h>
+#endif /* __linux__ */
+
+static char *prg_fname = NULL;
+static bfd *cached_abfd = NULL;
+static asymbol **syms = NULL;
+
+static void get_prg_fname(void)
+{
+	char exe[50], fname[512];
+	int len;
+	os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
+	len = readlink(exe, fname, sizeof(fname) - 1);
+	if (len < 0 || len >= (int) sizeof(fname)) {
+		perror("readlink");
+		return;
+	}
+	fname[len] = '\0';
+	prg_fname = strdup(fname);
+}
+
+
+static bfd * open_bfd(const char *fname)
+{
+	bfd *abfd;
+	char **matching;
+
+	abfd = bfd_openr(prg_fname, NULL);
+	if (abfd == NULL) {
+		wpa_printf(MSG_INFO, "bfd_openr failed");
+		return NULL;
+	}
+
+	if (bfd_check_format(abfd, bfd_archive)) {
+		wpa_printf(MSG_INFO, "bfd_check_format failed");
+		bfd_close(abfd);
+		return NULL;
+	}
+
+	if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
+		wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
+		free(matching);
+		bfd_close(abfd);
+		return NULL;
+	}
+
+	return abfd;
+}
+
+
+static void read_syms(bfd *abfd)
+{
+	long storage, symcount;
+	bfd_boolean dynamic = FALSE;
+
+	if (syms)
+		return;
+
+	if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
+		wpa_printf(MSG_INFO, "No symbols");
+		return;
+	}
+
+	storage = bfd_get_symtab_upper_bound(abfd);
+	if (storage == 0) {
+		storage = bfd_get_dynamic_symtab_upper_bound(abfd);
+		dynamic = TRUE;
+	}
+	if (storage < 0) {
+		wpa_printf(MSG_INFO, "Unknown symtab upper bound");
+		return;
+	}
+
+	syms = malloc(storage);
+	if (syms == NULL) {
+		wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
+			   "(%ld bytes)", storage);
+		return;
+	}
+	if (dynamic)
+		symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
+	else
+		symcount = bfd_canonicalize_symtab(abfd, syms);
+	if (symcount < 0) {
+		wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
+			   dynamic ? "dynamic " : "");
+		free(syms);
+		syms = NULL;
+		return;
+	}
+}
+
+
+struct bfd_data {
+	bfd_vma pc;
+	bfd_boolean found;
+	const char *filename;
+	const char *function;
+	unsigned int line;
+};
+
+
+static void find_addr_sect(bfd *abfd, asection *section, void *obj)
+{
+	struct bfd_data *data = obj;
+	bfd_vma vma;
+	bfd_size_type size;
+
+	if (data->found)
+		return;
+
+	if (!(bfd_get_section_vma(abfd, section)))
+		return;
+
+	vma = bfd_get_section_vma(abfd, section);
+	if (data->pc < vma)
+		return;
+
+	size = bfd_get_section_size(section);
+	if (data->pc >= vma + size)
+		return;
+
+	data->found = bfd_find_nearest_line(abfd, section, syms,
+					    data->pc - vma,
+					    &data->filename,
+					    &data->function,
+					    &data->line);
+}
+
+
+static void wpa_trace_bfd_addr(void *pc)
+{
+	bfd *abfd = cached_abfd;
+	struct bfd_data data;
+	const char *name;
+	char *aname = NULL;
+	const char *filename;
+
+	if (abfd == NULL)
+		return;
+
+	data.pc = (bfd_vma) pc;
+	data.found = FALSE;
+	bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+	if (!data.found)
+		return;
+
+	do {
+		if (data.function)
+			aname = bfd_demangle(abfd, data.function,
+					     DMGL_ANSI | DMGL_PARAMS);
+		name = aname ? aname : data.function;
+		filename = data.filename;
+		if (filename) {
+			char *end = os_strrchr(filename, '/');
+			int i = 0;
+			while (*filename && *filename == prg_fname[i] &&
+			       filename <= end) {
+				filename++;
+				i++;
+			}
+		}
+		wpa_printf(MSG_INFO, "     %s() %s:%u",
+			   name, filename, data.line);
+		free(aname);
+
+		data.found = bfd_find_inliner_info(abfd, &data.filename,
+						   &data.function, &data.line);
+	} while (data.found);
+}
+
+
+static const char * wpa_trace_bfd_addr2func(void *pc)
+{
+	bfd *abfd = cached_abfd;
+	struct bfd_data data;
+
+	if (abfd == NULL)
+		return NULL;
+
+	data.pc = (bfd_vma) pc;
+	data.found = FALSE;
+	bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+	if (!data.found)
+		return NULL;
+
+	return data.function;
+}
+
+
+static void wpa_trace_bfd_init(void)
+{
+	if (!prg_fname) {
+		get_prg_fname();
+		if (!prg_fname)
+			return;
+	}
+
+	if (!cached_abfd) {
+		cached_abfd = open_bfd(prg_fname);
+		if (!cached_abfd) {
+			wpa_printf(MSG_INFO, "Failed to open bfd");
+			return;
+		}
+	}
+
+	read_syms(cached_abfd);
+	if (!syms) {
+		wpa_printf(MSG_INFO, "Failed to read symbols");
+		return;
+	}
+}
+
+
+void wpa_trace_dump_funcname(const char *title, void *pc)
+{
+	wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
+	wpa_trace_bfd_init();
+	wpa_trace_bfd_addr(pc);
+}
+
+#else /* WPA_TRACE_BFD */
+
+#define wpa_trace_bfd_init() do { } while (0)
+#define wpa_trace_bfd_addr(pc) do { } while (0)
+#define wpa_trace_bfd_addr2func(pc) NULL
+
+#endif /* WPA_TRACE_BFD */
+
+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
+{
+	char **sym;
+	int i;
+	enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
+
+	wpa_trace_bfd_init();
+	wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
+	sym = backtrace_symbols(btrace, btrace_num);
+	state = TRACE_HEAD;
+	for (i = 0; i < btrace_num; i++) {
+		const char *func = wpa_trace_bfd_addr2func(btrace[i]);
+		if (state == TRACE_HEAD && func &&
+		    (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
+		     os_strcmp(func, "wpa_trace_check_ref") == 0 ||
+		     os_strcmp(func, "wpa_trace_show") == 0))
+			continue;
+		if (state == TRACE_TAIL && sym && sym[i] &&
+		    os_strstr(sym[i], "__libc_start_main"))
+			break;
+		if (state == TRACE_HEAD)
+			state = TRACE_RELEVANT;
+		if (sym)
+			wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
+		else
+			wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
+		wpa_trace_bfd_addr(btrace[i]);
+		if (state == TRACE_RELEVANT && func &&
+		    os_strcmp(func, "main") == 0)
+			state = TRACE_TAIL;
+	}
+	free(sym);
+	wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
+}
+
+
+void wpa_trace_show(const char *title)
+{
+	struct info {
+		WPA_TRACE_INFO
+	} info;
+	wpa_trace_record(&info);
+	wpa_trace_dump(title, &info);
+}
+
+
+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
+{
+	if (addr == NULL)
+		return;
+	ref->addr = addr;
+	wpa_trace_record(ref);
+	dl_list_add(&active_references, &ref->list);
+}
+
+
+void wpa_trace_check_ref(const void *addr)
+{
+	struct wpa_trace_ref *ref;
+	dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
+		if (addr != ref->addr)
+			continue;
+		wpa_trace_show("Freeing referenced memory");
+		wpa_trace_dump("Reference registration", ref);
+		abort();
+	}
+}
+
+#endif /* WPA_TRACE */

Deleted: vendor/wpa/2.0/src/utils/trace.h
===================================================================
--- vendor/wpa/dist/src/utils/trace.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/trace.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,74 +0,0 @@
-/*
- * Backtrace debugging
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef TRACE_H
-#define TRACE_H
-
-#define WPA_TRACE_LEN 16
-
-#ifdef WPA_TRACE
-#include <execinfo.h>
-
-#include "list.h"
-
-#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num;
-
-struct wpa_trace_ref {
-	struct dl_list list;
-	const void *addr;
-	WPA_TRACE_INFO
-};
-#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name
-
-#define wpa_trace_dump(title, ptr) \
-	wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num)
-void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num);
-#define wpa_trace_record(ptr) \
-	(ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN)
-void wpa_trace_show(const char *title);
-#define wpa_trace_add_ref(ptr, name, addr) \
-	wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr))
-void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr);
-#define wpa_trace_remove_ref(ptr, name, addr)	\
-	do { \
-		if ((addr)) \
-			dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
-	} while (0)
-void wpa_trace_check_ref(const void *addr);
-
-#else /* WPA_TRACE */
-
-#define WPA_TRACE_INFO
-#define WPA_TRACE_REF(n)
-#define wpa_trace_dump(title, ptr) do { } while (0)
-#define wpa_trace_record(ptr) do { } while (0)
-#define wpa_trace_show(title) do { } while (0)
-#define wpa_trace_add_ref(ptr, name, addr) do { } while (0)
-#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0)
-#define wpa_trace_check_ref(addr) do { } while (0)
-
-#endif /* WPA_TRACE */
-
-
-#ifdef WPA_TRACE_BFD
-
-void wpa_trace_dump_funcname(const char *title, void *pc);
-
-#else /* WPA_TRACE_BFD */
-
-#define wpa_trace_dump_funcname(title, pc) do { } while (0)
-
-#endif /* WPA_TRACE_BFD */
-
-#endif /* TRACE_H */

Copied: vendor/wpa/2.0/src/utils/trace.h (from rev 9639, vendor/wpa/dist/src/utils/trace.h)
===================================================================
--- vendor/wpa/2.0/src/utils/trace.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/trace.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,68 @@
+/*
+ * Backtrace debugging
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#define WPA_TRACE_LEN 16
+
+#ifdef WPA_TRACE
+#include <execinfo.h>
+
+#include "list.h"
+
+#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num;
+
+struct wpa_trace_ref {
+	struct dl_list list;
+	const void *addr;
+	WPA_TRACE_INFO
+};
+#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name
+
+#define wpa_trace_dump(title, ptr) \
+	wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num)
+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num);
+#define wpa_trace_record(ptr) \
+	(ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN)
+void wpa_trace_show(const char *title);
+#define wpa_trace_add_ref(ptr, name, addr) \
+	wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr))
+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr);
+#define wpa_trace_remove_ref(ptr, name, addr)	\
+	do { \
+		if ((addr)) \
+			dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
+	} while (0)
+void wpa_trace_check_ref(const void *addr);
+
+#else /* WPA_TRACE */
+
+#define WPA_TRACE_INFO
+#define WPA_TRACE_REF(n)
+#define wpa_trace_dump(title, ptr) do { } while (0)
+#define wpa_trace_record(ptr) do { } while (0)
+#define wpa_trace_show(title) do { } while (0)
+#define wpa_trace_add_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_check_ref(addr) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+#ifdef WPA_TRACE_BFD
+
+void wpa_trace_dump_funcname(const char *title, void *pc);
+
+#else /* WPA_TRACE_BFD */
+
+#define wpa_trace_dump_funcname(title, pc) do { } while (0)
+
+#endif /* WPA_TRACE_BFD */
+
+#endif /* TRACE_H */

Deleted: vendor/wpa/2.0/src/utils/uuid.c
===================================================================
--- vendor/wpa/dist/src/utils/uuid.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/uuid.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,77 +0,0 @@
-/*
- * Universally Unique IDentifier (UUID)
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "uuid.h"
-
-int uuid_str2bin(const char *str, u8 *bin)
-{
-	const char *pos;
-	u8 *opos;
-
-	pos = str;
-	opos = bin;
-
-	if (hexstr2bin(pos, opos, 4))
-		return -1;
-	pos += 8;
-	opos += 4;
-
-	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
-		return -1;
-	pos += 4;
-	opos += 2;
-
-	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
-		return -1;
-	pos += 4;
-	opos += 2;
-
-	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
-		return -1;
-	pos += 4;
-	opos += 2;
-
-	if (*pos++ != '-' || hexstr2bin(pos, opos, 6))
-		return -1;
-
-	return 0;
-}
-
-
-int uuid_bin2str(const u8 *bin, char *str, size_t max_len)
-{
-	int len;
-	len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-			  "%02x%02x-%02x%02x%02x%02x%02x%02x",
-			  bin[0], bin[1], bin[2], bin[3],
-			  bin[4], bin[5], bin[6], bin[7],
-			  bin[8], bin[9], bin[10], bin[11],
-			  bin[12], bin[13], bin[14], bin[15]);
-	if (len < 0 || (size_t) len >= max_len)
-		return -1;
-	return 0;
-}
-
-
-int is_nil_uuid(const u8 *uuid)
-{
-	int i;
-	for (i = 0; i < UUID_LEN; i++)
-		if (uuid[i])
-			return 0;
-	return 1;
-}

Copied: vendor/wpa/2.0/src/utils/uuid.c (from rev 9639, vendor/wpa/dist/src/utils/uuid.c)
===================================================================
--- vendor/wpa/2.0/src/utils/uuid.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/uuid.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,71 @@
+/*
+ * Universally Unique IDentifier (UUID)
+ * Copyright (c) 2008, Jouni Malinen <j at 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 "uuid.h"
+
+int uuid_str2bin(const char *str, u8 *bin)
+{
+	const char *pos;
+	u8 *opos;
+
+	pos = str;
+	opos = bin;
+
+	if (hexstr2bin(pos, opos, 4))
+		return -1;
+	pos += 8;
+	opos += 4;
+
+	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+		return -1;
+	pos += 4;
+	opos += 2;
+
+	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+		return -1;
+	pos += 4;
+	opos += 2;
+
+	if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+		return -1;
+	pos += 4;
+	opos += 2;
+
+	if (*pos++ != '-' || hexstr2bin(pos, opos, 6))
+		return -1;
+
+	return 0;
+}
+
+
+int uuid_bin2str(const u8 *bin, char *str, size_t max_len)
+{
+	int len;
+	len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+			  "%02x%02x-%02x%02x%02x%02x%02x%02x",
+			  bin[0], bin[1], bin[2], bin[3],
+			  bin[4], bin[5], bin[6], bin[7],
+			  bin[8], bin[9], bin[10], bin[11],
+			  bin[12], bin[13], bin[14], bin[15]);
+	if (len < 0 || (size_t) len >= max_len)
+		return -1;
+	return 0;
+}
+
+
+int is_nil_uuid(const u8 *uuid)
+{
+	int i;
+	for (i = 0; i < UUID_LEN; i++)
+		if (uuid[i])
+			return 0;
+	return 1;
+}

Deleted: vendor/wpa/2.0/src/utils/uuid.h
===================================================================
--- vendor/wpa/dist/src/utils/uuid.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/uuid.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,24 +0,0 @@
-/*
- * Universally Unique IDentifier (UUID)
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef UUID_H
-#define UUID_H
-
-#define UUID_LEN 16
-
-int uuid_str2bin(const char *str, u8 *bin);
-int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
-int is_nil_uuid(const u8 *uuid);
-
-#endif /* UUID_H */

Copied: vendor/wpa/2.0/src/utils/uuid.h (from rev 9639, vendor/wpa/dist/src/utils/uuid.h)
===================================================================
--- vendor/wpa/2.0/src/utils/uuid.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/uuid.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,18 @@
+/*
+ * Universally Unique IDentifier (UUID)
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef UUID_H
+#define UUID_H
+
+#define UUID_LEN 16
+
+int uuid_str2bin(const char *str, u8 *bin);
+int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
+int is_nil_uuid(const u8 *uuid);
+
+#endif /* UUID_H */

Deleted: vendor/wpa/2.0/src/utils/wpa_debug.c
===================================================================
--- vendor/wpa/dist/src/utils/wpa_debug.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/wpa_debug.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,400 +0,0 @@
-/*
- * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING 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_FILE
-static FILE *out_file = NULL;
-#endif /* CONFIG_DEBUG_FILE */
-int wpa_debug_level = MSG_INFO;
-int wpa_debug_show_keys = 0;
-int wpa_debug_timestamp = 0;
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-
-void wpa_debug_print_timestamp(void)
-{
-	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);
-}
-
-
-#ifdef CONFIG_DEBUG_SYSLOG
-void wpa_debug_open_syslog(void)
-{
-	openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON);
-	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 */
-
-
-/**
- * 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_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 */
-	}
-	va_end(ap);
-}
-
-
-static void _wpa_hexdump(int level, const char *title, const u8 *buf,
-			 size_t len, int show)
-{
-	size_t i;
-	if (level < wpa_debug_level)
-		return;
-	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 */
-}
-
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
-{
-	_wpa_hexdump(level, title, buf, len, 1);
-}
-
-
-void wpa_hexdump_key(int level, const char *title, const u8 *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 u8 *buf,
-			       size_t len, int show)
-{
-	size_t i, llen;
-	const u8 *pos = buf;
-	const size_t line_len = 16;
-
-	if (level < wpa_debug_level)
-		return;
-	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 */
-}
-
-
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
-{
-	_wpa_hexdump_ascii(level, title, buf, len, 1);
-}
-
-
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
-			   size_t len)
-{
-	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
-}
-
-
-int wpa_debug_open_file(const char *path)
-{
-#ifdef CONFIG_DEBUG_FILE
-	if (!path)
-		return 0;
-	out_file = fopen(path, "a");
-	if (out_file == NULL) {
-		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
-			   "output file, using standard output");
-		return -1;
-	}
-#ifndef _WIN32
-	setvbuf(out_file, NULL, _IOLBF, 0);
-#endif /* _WIN32 */
-#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;
-#endif /* CONFIG_DEBUG_FILE */
-}
-
-#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;
-}
-
-
-void wpa_msg(void *ctx, int level, const char *fmt, ...)
-{
-	va_list ap;
-	char *buf;
-	const int buflen = 2048;
-	int len;
-
-	buf = os_malloc(buflen);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "wpa_msg: 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, buf, len);
-	os_free(buf);
-}
-
-
-void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
-{
-	va_list ap;
-	char *buf;
-	const int buflen = 2048;
-	int len;
-
-	if (!wpa_msg_cb)
-		return;
-
-	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, 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;
-	const int buflen = 2048;
-	int len;
-
-	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);
-	os_free(buf);
-}
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */

Copied: vendor/wpa/2.0/src/utils/wpa_debug.c (from rev 9639, vendor/wpa/dist/src/utils/wpa_debug.c)
===================================================================
--- vendor/wpa/2.0/src/utils/wpa_debug.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/wpa_debug.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,688 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j at 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 (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 ? " ..." : "");
+		os_free(strbuf);
+		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);
+		os_free(strbuf);
+		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 u8 *buf, size_t len)
+{
+	_wpa_hexdump(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_key(int level, const char *title, const u8 *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 u8 *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", buf[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 u8 *buf, size_t len)
+{
+	_wpa_hexdump_ascii(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *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;
+	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;
+	}
+	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, using standard output");
+		return -1;
+	}
+#ifndef _WIN32
+	setvbuf(out_file, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+#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 */
+}
+
+#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;
+	const int buflen = 2048;
+	int len;
+	char prefix[130];
+
+	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 (res < 0 || res >= (int) sizeof(prefix))
+				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, buf, len);
+	os_free(buf);
+}
+
+
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+
+	if (!wpa_msg_cb)
+		return;
+
+	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, 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;
+	const int buflen = 2048;
+	int len;
+
+	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);
+	os_free(buf);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */

Deleted: vendor/wpa/2.0/src/utils/wpa_debug.h
===================================================================
--- vendor/wpa/dist/src/utils/wpa_debug.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/wpa_debug.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,256 +0,0 @@
-/*
- * wpa_supplicant/hostapd / Debug prints
- * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_DEBUG_H
-#define WPA_DEBUG_H
-
-#include "wpabuf.h"
-
-/* Debugging function - conditional printf and hex dump. Driver wrappers can
- * use these for debugging purposes. */
-
-enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
-
-#ifdef CONFIG_NO_STDOUT_DEBUG
-
-#define wpa_debug_print_timestamp() do { } while (0)
-#define wpa_printf(args...) do { } while (0)
-#define wpa_hexdump(l,t,b,le) do { } while (0)
-#define wpa_hexdump_buf(l,t,b) do { } while (0)
-#define wpa_hexdump_key(l,t,b,le) do { } while (0)
-#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
-#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
-#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
-#define wpa_debug_open_file(p) do { } while (0)
-#define wpa_debug_close_file() do { } while (0)
-
-#else /* CONFIG_NO_STDOUT_DEBUG */
-
-int wpa_debug_open_file(const char *path);
-void wpa_debug_close_file(void);
-
-/**
- * wpa_debug_printf_timestamp - Print timestamp for debug output
- *
- * This function prints a timestamp in seconds_from_1970.microsoconds
- * format if debug output has been configured to include timestamps in debug
- * messages.
- */
-void wpa_debug_print_timestamp(void);
-
-/**
- * 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, ...)
-PRINTF_FORMAT(2, 3);
-
-/**
- * wpa_hexdump - conditional hex dump
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the buf
- *
- * 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. The contents of buf is printed out has hex dump.
- */
-void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
-
-static inline void wpa_hexdump_buf(int level, const char *title,
-				   const struct wpabuf *buf)
-{
-	wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf));
-}
-
-/**
- * wpa_hexdump_key - conditional hex dump, hide keys
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the buf
- *
- * 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. The contents of buf is printed out has hex dump. This works
- * like wpa_hexdump(), but by default, does not include secret keys (passwords,
- * etc.) in debug output.
- */
-void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
-
-static inline void wpa_hexdump_buf_key(int level, const char *title,
-				       const struct wpabuf *buf)
-{
-	wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf));
-}
-
-/**
- * wpa_hexdump_ascii - conditional hex dump
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the buf
- *
- * 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. The contents of buf is printed out has hex dump with both
- * the hex numbers and ASCII characters (for printable range) are shown. 16
- * bytes per line will be shown.
- */
-void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
-		       size_t len);
-
-/**
- * wpa_hexdump_ascii_key - conditional hex dump, hide keys
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the buf
- *
- * 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. The contents of buf is printed out has hex dump with both
- * the hex numbers and ASCII characters (for printable range) are shown. 16
- * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
- * default, does not include secret keys (passwords, etc.) in debug output.
- */
-void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
-			   size_t len);
-
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-#ifdef CONFIG_NO_WPA_MSG
-#define wpa_msg(args...) do { } while (0)
-#define wpa_msg_ctrl(args...) do { } while (0)
-#define wpa_msg_register_cb(f) do { } while (0)
-#else /* CONFIG_NO_WPA_MSG */
-/**
- * wpa_msg - Conditional printf for default target and ctrl_iface monitors
- * @ctx: Pointer to context data; this is the ctx variable registered
- *	with struct wpa_driver_ops::init()
- * @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. This function is like wpa_printf(), but it also sends the
- * same message to all attached ctrl_iface monitors.
- *
- * Note: New line '\n' is added to the end of the text when printing to stdout.
- */
-void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
-
-/**
- * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
- * @ctx: Pointer to context data; this is the ctx variable registered
- *	with struct wpa_driver_ops::init()
- * @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.
- * This function is like wpa_msg(), but it sends the output only to the
- * attached ctrl_iface monitors. In other words, it can be used for frequent
- * events that do not need to be sent to syslog.
- */
-void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
-PRINTF_FORMAT(3, 4);
-
-typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
-				size_t len);
-
-/**
- * wpa_msg_register_cb - Register callback function for wpa_msg() messages
- * @func: Callback function (%NULL to unregister)
- */
-void wpa_msg_register_cb(wpa_msg_cb_func func);
-#endif /* CONFIG_NO_WPA_MSG */
-
-
-#ifdef CONFIG_NO_HOSTAPD_LOGGER
-#define hostapd_logger(args...) do { } while (0)
-#define hostapd_logger_register_cb(f) do { } while (0)
-#else /* CONFIG_NO_HOSTAPD_LOGGER */
-void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
-		    const char *fmt, ...) PRINTF_FORMAT(5, 6);
-
-typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
-				       unsigned int module, int level,
-				       const char *txt, size_t len);
-
-/**
- * hostapd_logger_register_cb - Register callback function for hostapd_logger()
- * @func: Callback function (%NULL to unregister)
- */
-void hostapd_logger_register_cb(hostapd_logger_cb_func func);
-#endif /* CONFIG_NO_HOSTAPD_LOGGER */
-
-#define HOSTAPD_MODULE_IEEE80211	0x00000001
-#define HOSTAPD_MODULE_IEEE8021X	0x00000002
-#define HOSTAPD_MODULE_RADIUS		0x00000004
-#define HOSTAPD_MODULE_WPA		0x00000008
-#define HOSTAPD_MODULE_DRIVER		0x00000010
-#define HOSTAPD_MODULE_IAPP		0x00000020
-#define HOSTAPD_MODULE_MLME		0x00000040
-
-enum hostapd_logger_level {
-	HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
-	HOSTAPD_LEVEL_DEBUG = 1,
-	HOSTAPD_LEVEL_INFO = 2,
-	HOSTAPD_LEVEL_NOTICE = 3,
-	HOSTAPD_LEVEL_WARNING = 4
-};
-
-
-#ifdef CONFIG_DEBUG_SYSLOG
-
-void wpa_debug_open_syslog(void);
-void wpa_debug_close_syslog(void);
-
-#else /* CONFIG_DEBUG_SYSLOG */
-
-static inline void wpa_debug_open_syslog(void)
-{
-}
-
-static inline void wpa_debug_close_syslog(void)
-{
-}
-
-#endif /* CONFIG_DEBUG_SYSLOG */
-
-
-#ifdef EAPOL_TEST
-#define WPA_ASSERT(a)						       \
-	do {							       \
-		if (!(a)) {					       \
-			printf("WPA_ASSERT FAILED '" #a "' "	       \
-			       "%s %s:%d\n",			       \
-			       __FUNCTION__, __FILE__, __LINE__);      \
-			exit(1);				       \
-		}						       \
-	} while (0)
-#else
-#define WPA_ASSERT(a) do { } while (0)
-#endif
-
-#endif /* WPA_DEBUG_H */

Copied: vendor/wpa/2.0/src/utils/wpa_debug.h (from rev 9639, vendor/wpa/dist/src/utils/wpa_debug.h)
===================================================================
--- vendor/wpa/2.0/src/utils/wpa_debug.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/wpa_debug.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,291 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_DEBUG_H
+#define WPA_DEBUG_H
+
+#include "wpabuf.h"
+
+/* Debugging function - conditional printf and hex dump. Driver wrappers can
+ * use these for debugging purposes. */
+
+enum {
+	MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
+};
+
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+#define wpa_debug_print_timestamp() do { } while (0)
+#define wpa_printf(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf(l,t,b) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
+#define wpa_debug_open_file(p) do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
+#define wpa_dbg(args...) do { } while (0)
+
+static inline int wpa_debug_reopen_file(void)
+{
+	return 0;
+}
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+int wpa_debug_open_file(const char *path);
+int wpa_debug_reopen_file(void);
+void wpa_debug_close_file(void);
+
+/**
+ * wpa_debug_printf_timestamp - Print timestamp for debug output
+ *
+ * This function prints a timestamp in seconds_from_1970.microsoconds
+ * format if debug output has been configured to include timestamps in debug
+ * messages.
+ */
+void wpa_debug_print_timestamp(void);
+
+/**
+ * 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, ...)
+PRINTF_FORMAT(2, 3);
+
+/**
+ * wpa_hexdump - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump.
+ */
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf(int level, const char *title,
+				   const struct wpabuf *buf)
+{
+	wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
+		    buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump. This works
+ * like wpa_hexdump(), but by default, does not include secret keys (passwords,
+ * etc.) in debug output.
+ */
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf_key(int level, const char *title,
+				       const struct wpabuf *buf)
+{
+	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
+			buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_ascii - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown.
+ */
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+		       size_t len);
+
+/**
+ * wpa_hexdump_ascii_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
+ * default, does not include secret keys (passwords, etc.) in debug output.
+ */
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+			   size_t len);
+
+/*
+ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
+ * binary size. As such, it should be used with debugging messages that are not
+ * needed in the control interface while wpa_msg() has to be used for anything
+ * that needs to shown to control interface monitors.
+ */
+#define wpa_dbg(args...) wpa_msg(args)
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_register_cb(f) do { } while (0)
+#define wpa_msg_register_ifname_cb(f) do { } while (0)
+#else /* CONFIG_NO_WPA_MSG */
+/**
+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @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. This function is like wpa_printf(), but it also sends the
+ * same message to all attached ctrl_iface monitors.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @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.
+ * This function is like wpa_msg(), but it sends the output only to the
+ * attached ctrl_iface monitors. In other words, it can be used for frequent
+ * events that do not need to be sent to syslog.
+ */
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+				size_t len);
+
+/**
+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages
+ * @func: Callback function (%NULL to unregister)
+ */
+void wpa_msg_register_cb(wpa_msg_cb_func func);
+
+typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
+
+#endif /* CONFIG_NO_WPA_MSG */
+
+#ifdef CONFIG_NO_HOSTAPD_LOGGER
+#define hostapd_logger(args...) do { } while (0)
+#define hostapd_logger_register_cb(f) do { } while (0)
+#else /* CONFIG_NO_HOSTAPD_LOGGER */
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+		    const char *fmt, ...) PRINTF_FORMAT(5, 6);
+
+typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
+				       unsigned int module, int level,
+				       const char *txt, size_t len);
+
+/**
+ * hostapd_logger_register_cb - Register callback function for hostapd_logger()
+ * @func: Callback function (%NULL to unregister)
+ */
+void hostapd_logger_register_cb(hostapd_logger_cb_func func);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+#define HOSTAPD_MODULE_IEEE80211	0x00000001
+#define HOSTAPD_MODULE_IEEE8021X	0x00000002
+#define HOSTAPD_MODULE_RADIUS		0x00000004
+#define HOSTAPD_MODULE_WPA		0x00000008
+#define HOSTAPD_MODULE_DRIVER		0x00000010
+#define HOSTAPD_MODULE_IAPP		0x00000020
+#define HOSTAPD_MODULE_MLME		0x00000040
+
+enum hostapd_logger_level {
+	HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
+	HOSTAPD_LEVEL_DEBUG = 1,
+	HOSTAPD_LEVEL_INFO = 2,
+	HOSTAPD_LEVEL_NOTICE = 3,
+	HOSTAPD_LEVEL_WARNING = 4
+};
+
+
+#ifdef CONFIG_DEBUG_SYSLOG
+
+void wpa_debug_open_syslog(void);
+void wpa_debug_close_syslog(void);
+
+#else /* CONFIG_DEBUG_SYSLOG */
+
+static inline void wpa_debug_open_syslog(void)
+{
+}
+
+static inline void wpa_debug_close_syslog(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void);
+void wpa_debug_close_linux_tracing(void);
+
+#else /* CONFIG_DEBUG_LINUX_TRACING */
+
+static inline int wpa_debug_open_linux_tracing(void)
+{
+	return 0;
+}
+
+static inline void wpa_debug_close_linux_tracing(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
+#ifdef EAPOL_TEST
+#define WPA_ASSERT(a)						       \
+	do {							       \
+		if (!(a)) {					       \
+			printf("WPA_ASSERT FAILED '" #a "' "	       \
+			       "%s %s:%d\n",			       \
+			       __FUNCTION__, __FILE__, __LINE__);      \
+			exit(1);				       \
+		}						       \
+	} while (0)
+#else
+#define WPA_ASSERT(a) do { } while (0)
+#endif
+
+#endif /* WPA_DEBUG_H */

Deleted: vendor/wpa/2.0/src/utils/wpabuf.c
===================================================================
--- vendor/wpa/dist/src/utils/wpabuf.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/wpabuf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,304 +0,0 @@
-/*
- * Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "trace.h"
-#include "wpabuf.h"
-
-#ifdef WPA_TRACE
-#define WPABUF_MAGIC 0x51a974e3
-
-struct wpabuf_trace {
-	unsigned int magic;
-};
-
-static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
-{
-	return (struct wpabuf_trace *)
-		((const u8 *) buf - sizeof(struct wpabuf_trace));
-}
-#endif /* WPA_TRACE */
-
-
-static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
-{
-#ifdef WPA_TRACE
-	struct wpabuf_trace *trace = wpabuf_get_trace(buf);
-	if (trace->magic != WPABUF_MAGIC) {
-		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
-			   trace->magic);
-	}
-#endif /* WPA_TRACE */
-	wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
-		   buf, (unsigned long) buf->size, (unsigned long) buf->used,
-		   (unsigned long) len);
-	wpa_trace_show("wpabuf overflow");
-	abort();
-}
-
-
-int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
-{
-	struct wpabuf *buf = *_buf;
-#ifdef WPA_TRACE
-	struct wpabuf_trace *trace;
-#endif /* WPA_TRACE */
-
-	if (buf == NULL) {
-		*_buf = wpabuf_alloc(add_len);
-		return *_buf == NULL ? -1 : 0;
-	}
-
-#ifdef WPA_TRACE
-	trace = wpabuf_get_trace(buf);
-	if (trace->magic != WPABUF_MAGIC) {
-		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
-			   trace->magic);
-		wpa_trace_show("wpabuf_resize invalid magic");
-		abort();
-	}
-#endif /* WPA_TRACE */
-
-	if (buf->used + add_len > buf->size) {
-		unsigned char *nbuf;
-		if (buf->ext_data) {
-			nbuf = os_realloc(buf->ext_data, buf->used + add_len);
-			if (nbuf == NULL)
-				return -1;
-			os_memset(nbuf + buf->used, 0, add_len);
-			buf->ext_data = nbuf;
-		} else {
-#ifdef WPA_TRACE
-			nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
-					  sizeof(struct wpabuf) +
-					  buf->used + add_len);
-			if (nbuf == NULL)
-				return -1;
-			trace = (struct wpabuf_trace *) nbuf;
-			buf = (struct wpabuf *) (trace + 1);
-			os_memset(nbuf + sizeof(struct wpabuf_trace) +
-				  sizeof(struct wpabuf) + buf->used, 0,
-				  add_len);
-#else /* WPA_TRACE */
-			nbuf = os_realloc(buf, sizeof(struct wpabuf) +
-					  buf->used + add_len);
-			if (nbuf == NULL)
-				return -1;
-			buf = (struct wpabuf *) nbuf;
-			os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
-				  add_len);
-#endif /* WPA_TRACE */
-			*_buf = buf;
-		}
-		buf->size = buf->used + add_len;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpabuf_alloc - Allocate a wpabuf of the given size
- * @len: Length for the allocated buffer
- * Returns: Buffer to the allocated wpabuf or %NULL on failure
- */
-struct wpabuf * wpabuf_alloc(size_t len)
-{
-#ifdef WPA_TRACE
-	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
-					       sizeof(struct wpabuf) + len);
-	struct wpabuf *buf;
-	if (trace == NULL)
-		return NULL;
-	trace->magic = WPABUF_MAGIC;
-	buf = (struct wpabuf *) (trace + 1);
-#else /* WPA_TRACE */
-	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
-	if (buf == NULL)
-		return NULL;
-#endif /* WPA_TRACE */
-
-	buf->size = len;
-	return buf;
-}
-
-
-struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
-{
-#ifdef WPA_TRACE
-	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
-					       sizeof(struct wpabuf));
-	struct wpabuf *buf;
-	if (trace == NULL)
-		return NULL;
-	trace->magic = WPABUF_MAGIC;
-	buf = (struct wpabuf *) (trace + 1);
-#else /* WPA_TRACE */
-	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
-	if (buf == NULL)
-		return NULL;
-#endif /* WPA_TRACE */
-
-	buf->size = len;
-	buf->used = len;
-	buf->ext_data = data;
-
-	return buf;
-}
-
-
-struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
-{
-	struct wpabuf *buf = wpabuf_alloc(len);
-	if (buf)
-		wpabuf_put_data(buf, data, len);
-	return buf;
-}
-
-
-struct wpabuf * wpabuf_dup(const struct wpabuf *src)
-{
-	struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
-	if (buf)
-		wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
-	return buf;
-}
-
-
-/**
- * wpabuf_free - Free a wpabuf
- * @buf: wpabuf buffer
- */
-void wpabuf_free(struct wpabuf *buf)
-{
-#ifdef WPA_TRACE
-	struct wpabuf_trace *trace;
-	if (buf == NULL)
-		return;
-	trace = wpabuf_get_trace(buf);
-	if (trace->magic != WPABUF_MAGIC) {
-		wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
-			   trace->magic);
-		wpa_trace_show("wpabuf_free magic mismatch");
-		abort();
-	}
-	os_free(buf->ext_data);
-	os_free(trace);
-#else /* WPA_TRACE */
-	if (buf == NULL)
-		return;
-	os_free(buf->ext_data);
-	os_free(buf);
-#endif /* WPA_TRACE */
-}
-
-
-void * wpabuf_put(struct wpabuf *buf, size_t len)
-{
-	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
-	buf->used += len;
-	if (buf->used > buf->size) {
-		wpabuf_overflow(buf, len);
-	}
-	return tmp;
-}
-
-
-/**
- * wpabuf_concat - Concatenate two buffers into a newly allocated one
- * @a: First buffer
- * @b: Second buffer
- * Returns: wpabuf with concatenated a + b data or %NULL on failure
- *
- * Both buffers a and b will be freed regardless of the return value. Input
- * buffers can be %NULL which is interpreted as an empty buffer.
- */
-struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
-{
-	struct wpabuf *n = NULL;
-	size_t len = 0;
-
-	if (b == NULL)
-		return a;
-
-	if (a)
-		len += wpabuf_len(a);
-	if (b)
-		len += wpabuf_len(b);
-
-	n = wpabuf_alloc(len);
-	if (n) {
-		if (a)
-			wpabuf_put_buf(n, a);
-		if (b)
-			wpabuf_put_buf(n, b);
-	}
-
-	wpabuf_free(a);
-	wpabuf_free(b);
-
-	return n;
-}
-
-
-/**
- * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
- * @buf: Buffer to be padded
- * @len: Length for the padded buffer
- * Returns: wpabuf padded to len octets or %NULL on failure
- *
- * If buf is longer than len octets or of same size, it will be returned as-is.
- * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
- * by the source data. The source buffer will be freed on error, i.e., caller
- * will only be responsible on freeing the returned buffer. If buf is %NULL,
- * %NULL will be returned.
- */
-struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
-{
-	struct wpabuf *ret;
-	size_t blen;
-
-	if (buf == NULL)
-		return NULL;
-
-	blen = wpabuf_len(buf);
-	if (blen >= len)
-		return buf;
-
-	ret = wpabuf_alloc(len);
-	if (ret) {
-		os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
-		wpabuf_put_buf(ret, buf);
-	}
-	wpabuf_free(buf);
-
-	return ret;
-}
-
-
-void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
-{
-	va_list ap;
-	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
-	int res;
-
-	va_start(ap, fmt);
-	res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
-	va_end(ap);
-	if (res < 0 || (size_t) res >= buf->size - buf->used)
-		wpabuf_overflow(buf, res);
-	buf->used += res;
-}

Copied: vendor/wpa/2.0/src/utils/wpabuf.c (from rev 9639, vendor/wpa/dist/src/utils/wpabuf.c)
===================================================================
--- vendor/wpa/2.0/src/utils/wpabuf.c	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/wpabuf.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,303 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2012, Jouni Malinen <j at 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 "trace.h"
+#include "wpabuf.h"
+
+#ifdef WPA_TRACE
+#define WPABUF_MAGIC 0x51a974e3
+
+struct wpabuf_trace {
+	unsigned int magic;
+};
+
+static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
+{
+	return (struct wpabuf_trace *)
+		((const u8 *) buf - sizeof(struct wpabuf_trace));
+}
+#endif /* WPA_TRACE */
+
+
+static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+			   trace->magic);
+	}
+#endif /* WPA_TRACE */
+	wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
+		   buf, (unsigned long) buf->size, (unsigned long) buf->used,
+		   (unsigned long) len);
+	wpa_trace_show("wpabuf overflow");
+	abort();
+}
+
+
+int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
+{
+	struct wpabuf *buf = *_buf;
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace;
+#endif /* WPA_TRACE */
+
+	if (buf == NULL) {
+		*_buf = wpabuf_alloc(add_len);
+		return *_buf == NULL ? -1 : 0;
+	}
+
+#ifdef WPA_TRACE
+	trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+			   trace->magic);
+		wpa_trace_show("wpabuf_resize invalid magic");
+		abort();
+	}
+#endif /* WPA_TRACE */
+
+	if (buf->used + add_len > buf->size) {
+		unsigned char *nbuf;
+		if (buf->flags & WPABUF_FLAG_EXT_DATA) {
+			nbuf = os_realloc(buf->buf, buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			os_memset(nbuf + buf->used, 0, add_len);
+			buf->buf = nbuf;
+		} else {
+#ifdef WPA_TRACE
+			nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
+					  sizeof(struct wpabuf) +
+					  buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			trace = (struct wpabuf_trace *) nbuf;
+			buf = (struct wpabuf *) (trace + 1);
+			os_memset(nbuf + sizeof(struct wpabuf_trace) +
+				  sizeof(struct wpabuf) + buf->used, 0,
+				  add_len);
+#else /* WPA_TRACE */
+			nbuf = os_realloc(buf, sizeof(struct wpabuf) +
+					  buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			buf = (struct wpabuf *) nbuf;
+			os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
+				  add_len);
+#endif /* WPA_TRACE */
+			buf->buf = (u8 *) (buf + 1);
+			*_buf = buf;
+		}
+		buf->size = buf->used + add_len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpabuf_alloc - Allocate a wpabuf of the given size
+ * @len: Length for the allocated buffer
+ * Returns: Buffer to the allocated wpabuf or %NULL on failure
+ */
+struct wpabuf * wpabuf_alloc(size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+					       sizeof(struct wpabuf) + len);
+	struct wpabuf *buf;
+	if (trace == NULL)
+		return NULL;
+	trace->magic = WPABUF_MAGIC;
+	buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
+	if (buf == NULL)
+		return NULL;
+#endif /* WPA_TRACE */
+
+	buf->size = len;
+	buf->buf = (u8 *) (buf + 1);
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+					       sizeof(struct wpabuf));
+	struct wpabuf *buf;
+	if (trace == NULL)
+		return NULL;
+	trace->magic = WPABUF_MAGIC;
+	buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
+	if (buf == NULL)
+		return NULL;
+#endif /* WPA_TRACE */
+
+	buf->size = len;
+	buf->used = len;
+	buf->buf = data;
+	buf->flags |= WPABUF_FLAG_EXT_DATA;
+
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
+{
+	struct wpabuf *buf = wpabuf_alloc(len);
+	if (buf)
+		wpabuf_put_data(buf, data, len);
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_dup(const struct wpabuf *src)
+{
+	struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
+	if (buf)
+		wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
+	return buf;
+}
+
+
+/**
+ * wpabuf_free - Free a wpabuf
+ * @buf: wpabuf buffer
+ */
+void wpabuf_free(struct wpabuf *buf)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace;
+	if (buf == NULL)
+		return;
+	trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
+			   trace->magic);
+		wpa_trace_show("wpabuf_free magic mismatch");
+		abort();
+	}
+	if (buf->flags & WPABUF_FLAG_EXT_DATA)
+		os_free(buf->buf);
+	os_free(trace);
+#else /* WPA_TRACE */
+	if (buf == NULL)
+		return;
+	if (buf->flags & WPABUF_FLAG_EXT_DATA)
+		os_free(buf->buf);
+	os_free(buf);
+#endif /* WPA_TRACE */
+}
+
+
+void * wpabuf_put(struct wpabuf *buf, size_t len)
+{
+	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+	buf->used += len;
+	if (buf->used > buf->size) {
+		wpabuf_overflow(buf, len);
+	}
+	return tmp;
+}
+
+
+/**
+ * wpabuf_concat - Concatenate two buffers into a newly allocated one
+ * @a: First buffer
+ * @b: Second buffer
+ * Returns: wpabuf with concatenated a + b data or %NULL on failure
+ *
+ * Both buffers a and b will be freed regardless of the return value. Input
+ * buffers can be %NULL which is interpreted as an empty buffer.
+ */
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
+{
+	struct wpabuf *n = NULL;
+	size_t len = 0;
+
+	if (b == NULL)
+		return a;
+
+	if (a)
+		len += wpabuf_len(a);
+	if (b)
+		len += wpabuf_len(b);
+
+	n = wpabuf_alloc(len);
+	if (n) {
+		if (a)
+			wpabuf_put_buf(n, a);
+		if (b)
+			wpabuf_put_buf(n, b);
+	}
+
+	wpabuf_free(a);
+	wpabuf_free(b);
+
+	return n;
+}
+
+
+/**
+ * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
+ * @buf: Buffer to be padded
+ * @len: Length for the padded buffer
+ * Returns: wpabuf padded to len octets or %NULL on failure
+ *
+ * If buf is longer than len octets or of same size, it will be returned as-is.
+ * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
+ * by the source data. The source buffer will be freed on error, i.e., caller
+ * will only be responsible on freeing the returned buffer. If buf is %NULL,
+ * %NULL will be returned.
+ */
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
+{
+	struct wpabuf *ret;
+	size_t blen;
+
+	if (buf == NULL)
+		return NULL;
+
+	blen = wpabuf_len(buf);
+	if (blen >= len)
+		return buf;
+
+	ret = wpabuf_alloc(len);
+	if (ret) {
+		os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
+		wpabuf_put_buf(ret, buf);
+	}
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
+{
+	va_list ap;
+	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+	int res;
+
+	va_start(ap, fmt);
+	res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
+	va_end(ap);
+	if (res < 0 || (size_t) res >= buf->size - buf->used)
+		wpabuf_overflow(buf, res);
+	buf->used += res;
+}

Deleted: vendor/wpa/2.0/src/utils/wpabuf.h
===================================================================
--- vendor/wpa/dist/src/utils/wpabuf.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/utils/wpabuf.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,162 +0,0 @@
-/*
- * Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPABUF_H
-#define WPABUF_H
-
-/*
- * 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 *ext_data; /* pointer to external data; NULL if data follows
-		       * struct wpabuf */
-	/* 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_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);
-
-
-/**
- * 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)
-{
-	if (buf->ext_data)
-		return buf->ext_data;
-	return buf + 1;
-}
-
-static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
-{
-	return 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)
-{
-	if (buf->ext_data)
-		return buf->ext_data;
-	return buf + 1;
-}
-
-static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
-{
-	return wpabuf_mhead(buf);
-}
-
-static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
-{
-	u8 *pos = wpabuf_put(buf, 1);
-	*pos = data;
-}
-
-static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
-{
-	u8 *pos = wpabuf_put(buf, 2);
-	WPA_PUT_LE16(pos, data);
-}
-
-static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
-{
-	u8 *pos = wpabuf_put(buf, 2);
-	WPA_PUT_BE16(pos, data);
-}
-
-static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
-{
-	u8 *pos = wpabuf_put(buf, 3);
-	WPA_PUT_BE24(pos, data);
-}
-
-static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
-{
-	u8 *pos = 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->ext_data = (u8 *) 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));
-}
-
-#endif /* WPABUF_H */

Copied: vendor/wpa/2.0/src/utils/wpabuf.h (from rev 9639, vendor/wpa/dist/src/utils/wpabuf.h)
===================================================================
--- vendor/wpa/2.0/src/utils/wpabuf.h	                        (rev 0)
+++ vendor/wpa/2.0/src/utils/wpabuf.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,162 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2012, Jouni Malinen <j at 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
+
+/* 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_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);
+
+
+/**
+ * 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 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)
+{
+	return wpabuf_mhead(buf);
+}
+
+static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
+{
+	u8 *pos = wpabuf_put(buf, 1);
+	*pos = data;
+}
+
+static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
+{
+	u8 *pos = wpabuf_put(buf, 2);
+	WPA_PUT_LE16(pos, data);
+}
+
+static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = wpabuf_put(buf, 4);
+	WPA_PUT_LE32(pos, data);
+}
+
+static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
+{
+	u8 *pos = wpabuf_put(buf, 2);
+	WPA_PUT_BE16(pos, data);
+}
+
+static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = wpabuf_put(buf, 3);
+	WPA_PUT_BE24(pos, data);
+}
+
+static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = 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));
+}
+
+#endif /* WPABUF_H */

Deleted: vendor/wpa/2.0/src/wps/http_client.c
===================================================================
--- vendor/wpa/dist/src/wps/http_client.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/http_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,371 +0,0 @@
-/*
- * http_client - HTTP client
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <fcntl.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "httpread.h"
-#include "http_client.h"
-
-
-#define HTTP_CLIENT_TIMEOUT 30
-
-
-struct http_client {
-	struct sockaddr_in dst;
-	int sd;
-	struct wpabuf *req;
-	size_t req_pos;
-	size_t max_response;
-
-	void (*cb)(void *ctx, struct http_client *c,
-		   enum http_client_event event);
-	void *cb_ctx;
-	struct httpread *hread;
-	struct wpabuf body;
-};
-
-
-static void http_client_timeout(void *eloop_data, void *user_ctx)
-{
-	struct http_client *c = eloop_data;
-	wpa_printf(MSG_DEBUG, "HTTP: Timeout");
-	c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
-}
-
-
-static void http_client_got_response(struct httpread *handle, void *cookie,
-				     enum httpread_event e)
-{
-	struct http_client *c = cookie;
-
-	eloop_cancel_timeout(http_client_timeout, c, NULL);
-	switch (e) {
-	case HTTPREAD_EVENT_FILE_READY:
-		if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
-		{
-			int reply_code = httpread_reply_code_get(c->hread);
-			if (reply_code == 200 /* OK */) {
-				wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
-					   "%s:%d",
-					   inet_ntoa(c->dst.sin_addr),
-					   ntohs(c->dst.sin_port));
-				c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
-			} else {
-				wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
-					   "%s:%d", reply_code,
-					   inet_ntoa(c->dst.sin_addr),
-					   ntohs(c->dst.sin_port));
-				c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
-			}
-		} else
-			c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
-		break;
-	case HTTPREAD_EVENT_TIMEOUT:
-		c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
-		break;
-	case HTTPREAD_EVENT_ERROR:
-		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
-		break;
-	}
-}
-
-
-static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct http_client *c = eloop_ctx;
-	int res;
-
-	wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
-		   "bytes remaining)",
-		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
-		   (unsigned long) wpabuf_len(c->req),
-		   (unsigned long) wpabuf_len(c->req) - c->req_pos);
-
-	res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
-		   wpabuf_len(c->req) - c->req_pos, 0);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
-			   strerror(errno));
-		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
-		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
-		return;
-	}
-
-	if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
-		wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
-			   "remaining",
-			   res, (unsigned long) wpabuf_len(c->req),
-			   (unsigned long) wpabuf_len(c->req) - c->req_pos -
-			   res);
-		c->req_pos += res;
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
-		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
-	eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
-	wpabuf_free(c->req);
-	c->req = NULL;
-
-	c->hread = httpread_create(c->sd, http_client_got_response, c,
-				   c->max_response, HTTP_CLIENT_TIMEOUT);
-	if (c->hread == NULL) {
-		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
-		return;
-	}
-}
-
-
-struct http_client * http_client_addr(struct sockaddr_in *dst,
-				      struct wpabuf *req, size_t max_response,
-				      void (*cb)(void *ctx,
-						 struct http_client *c,
-						 enum http_client_event event),
-				      void *cb_ctx)
-{
-	struct http_client *c;
-
-	c = os_zalloc(sizeof(*c));
-	if (c == NULL)
-		return NULL;
-	c->sd = -1;
-	c->dst = *dst;
-	c->max_response = max_response;
-	c->cb = cb;
-	c->cb_ctx = cb_ctx;
-
-	c->sd = socket(AF_INET, SOCK_STREAM, 0);
-	if (c->sd < 0) {
-		http_client_free(c);
-		return NULL;
-	}
-
-	if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
-		wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
-			   strerror(errno));
-		http_client_free(c);
-		return NULL;
-	}
-
-	if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
-		if (errno != EINPROGRESS) {
-			wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
-				   strerror(errno));
-			http_client_free(c);
-			return NULL;
-		}
-
-		/*
-		 * Continue connecting in the background; eloop will call us
-		 * once the connection is ready (or failed).
-		 */
-	}
-
-	if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
-				c, NULL)) {
-		http_client_free(c);
-		return NULL;
-	}
-
-	if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT, 0, http_client_timeout,
-				   c, NULL)) {
-		http_client_free(c);
-		return NULL;
-	}
-
-	c->req = req;
-
-	return c;
-}
-
-
-char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
-			     char **ret_path)
-{
-	char *u, *addr, *port, *path;
-
-	u = os_strdup(url);
-	if (u == NULL)
-		return NULL;
-
-	os_memset(dst, 0, sizeof(*dst));
-	dst->sin_family = AF_INET;
-	addr = u + 7;
-	path = os_strchr(addr, '/');
-	port = os_strchr(addr, ':');
-	if (path == NULL) {
-		path = "/";
-	} else {
-		*path = '\0'; /* temporary nul termination for address */
-		if (port > path)
-			port = NULL;
-	}
-	if (port)
-		*port++ = '\0';
-
-	if (inet_aton(addr, &dst->sin_addr) == 0) {
-		/* TODO: name lookup */
-		wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
-			   "(addr='%s' port='%s')",
-			   url, addr, port);
-		os_free(u);
-		return NULL;
-	}
-
-	if (port)
-		dst->sin_port = htons(atoi(port));
-	else
-		dst->sin_port = htons(80);
-
-	if (*path == '\0') {
-		/* remove temporary nul termination for address */
-		*path = '/';
-	}
-
-	*ret_path = path;
-
-	return u;
-}
-
-
-struct http_client * http_client_url(const char *url,
-				     struct wpabuf *req, size_t max_response,
-				     void (*cb)(void *ctx,
-						struct http_client *c,
-						enum http_client_event event),
-				     void *cb_ctx)
-{
-	struct sockaddr_in dst;
-	struct http_client *c;
-	char *u, *path;
-	struct wpabuf *req_buf = NULL;
-
-	if (os_strncmp(url, "http://", 7) != 0)
-		return NULL;
-	u = http_client_url_parse(url, &dst, &path);
-	if (u == NULL)
-		return NULL;
-
-	if (req == NULL) {
-		req_buf = wpabuf_alloc(os_strlen(url) + 1000);
-		if (req_buf == NULL) {
-			os_free(u);
-			return NULL;
-		}
-		req = req_buf;
-		wpabuf_printf(req,
-			      "GET %s HTTP/1.1\r\n"
-			      "Cache-Control: no-cache\r\n"
-			      "Pragma: no-cache\r\n"
-			      "Accept: text/xml, application/xml\r\n"
-			      "User-Agent: wpa_supplicant\r\n"
-			      "Host: %s:%d\r\n"
-			      "\r\n",
-			      path, inet_ntoa(dst.sin_addr),
-			      ntohs(dst.sin_port));
-	}
-	os_free(u);
-
-	c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
-	if (c == NULL) {
-		wpabuf_free(req_buf);
-		return NULL;
-	}
-
-	return c;
-}
-
-
-void http_client_free(struct http_client *c)
-{
-	if (c == NULL)
-		return;
-	httpread_destroy(c->hread);
-	wpabuf_free(c->req);
-	if (c->sd >= 0) {
-		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
-		close(c->sd);
-	}
-	eloop_cancel_timeout(http_client_timeout, c, NULL);
-	os_free(c);
-}
-
-
-struct wpabuf * http_client_get_body(struct http_client *c)
-{
-	if (c->hread == NULL)
-		return NULL;
-	wpabuf_set(&c->body, httpread_data_get(c->hread),
-		   httpread_length_get(c->hread));
-	return &c->body;
-}
-
-
-char * http_client_get_hdr_line(struct http_client *c, const char *tag)
-{
-	if (c->hread == NULL)
-		return NULL;
-	return httpread_hdr_line_get(c->hread, tag);
-}
-
-
-char * http_link_update(char *url, const char *base)
-{
-	char *n;
-	size_t len;
-	const char *pos;
-
-	/* RFC 2396, Chapter 5.2 */
-	/* TODO: consider adding all cases described in RFC 2396 */
-
-	if (url == NULL)
-		return NULL;
-
-	if (os_strncmp(url, "http://", 7) == 0)
-		return url; /* absolute link */
-
-	if (os_strncmp(base, "http://", 7) != 0)
-		return url; /* unable to handle base URL */
-
-	len = os_strlen(url) + 1 + os_strlen(base) + 1;
-	n = os_malloc(len);
-	if (n == NULL)
-		return url; /* failed */
-
-	if (url[0] == '/') {
-		pos = os_strchr(base + 7, '/');
-		if (pos == NULL) {
-			os_snprintf(n, len, "%s%s", base, url);
-		} else {
-			os_memcpy(n, base, pos - base);
-			os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
-		}
-	} else {
-		pos = os_strrchr(base + 7, '/');
-		if (pos == NULL) {
-			os_snprintf(n, len, "%s/%s", base, url);
-		} else {
-			os_memcpy(n, base, pos - base + 1);
-			os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
-				  1);
-		}
-	}
-
-	os_free(url);
-
-	return n;
-}

Copied: vendor/wpa/2.0/src/wps/http_client.c (from rev 9639, vendor/wpa/dist/src/wps/http_client.c)
===================================================================
--- vendor/wpa/2.0/src/wps/http_client.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/http_client.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,368 @@
+/*
+ * http_client - HTTP client
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "httpread.h"
+#include "http_client.h"
+
+
+#define HTTP_CLIENT_TIMEOUT_SEC 30
+
+
+struct http_client {
+	struct sockaddr_in dst;
+	int sd;
+	struct wpabuf *req;
+	size_t req_pos;
+	size_t max_response;
+
+	void (*cb)(void *ctx, struct http_client *c,
+		   enum http_client_event event);
+	void *cb_ctx;
+	struct httpread *hread;
+	struct wpabuf body;
+};
+
+
+static void http_client_timeout(void *eloop_data, void *user_ctx)
+{
+	struct http_client *c = eloop_data;
+	wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c);
+	c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
+}
+
+
+static void http_client_got_response(struct httpread *handle, void *cookie,
+				     enum httpread_event e)
+{
+	struct http_client *c = cookie;
+
+	wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p "
+		   "e=%d", handle, cookie, e);
+
+	eloop_cancel_timeout(http_client_timeout, c, NULL);
+	switch (e) {
+	case HTTPREAD_EVENT_FILE_READY:
+		if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY)
+		{
+			int reply_code = httpread_reply_code_get(c->hread);
+			if (reply_code == 200 /* OK */) {
+				wpa_printf(MSG_DEBUG, "HTTP: Response OK from "
+					   "%s:%d",
+					   inet_ntoa(c->dst.sin_addr),
+					   ntohs(c->dst.sin_port));
+				c->cb(c->cb_ctx, c, HTTP_CLIENT_OK);
+			} else {
+				wpa_printf(MSG_DEBUG, "HTTP: Error %d from "
+					   "%s:%d", reply_code,
+					   inet_ntoa(c->dst.sin_addr),
+					   ntohs(c->dst.sin_port));
+				c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
+			}
+		} else
+			c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY);
+		break;
+	case HTTPREAD_EVENT_TIMEOUT:
+		c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT);
+		break;
+	case HTTPREAD_EVENT_ERROR:
+		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
+		break;
+	}
+}
+
+
+static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct http_client *c = eloop_ctx;
+	int res;
+
+	wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu "
+		   "bytes remaining)",
+		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port),
+		   (unsigned long) wpabuf_len(c->req),
+		   (unsigned long) wpabuf_len(c->req) - c->req_pos);
+
+	res = send(c->sd, wpabuf_head(c->req) + c->req_pos,
+		   wpabuf_len(c->req) - c->req_pos, 0);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s",
+			   strerror(errno));
+		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
+		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
+		return;
+	}
+
+	if ((size_t) res < wpabuf_len(c->req) - c->req_pos) {
+		wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes "
+			   "remaining",
+			   res, (unsigned long) wpabuf_len(c->req),
+			   (unsigned long) wpabuf_len(c->req) - c->req_pos -
+			   res);
+		c->req_pos += res;
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d",
+		   inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port));
+	eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
+	wpabuf_free(c->req);
+	c->req = NULL;
+
+	c->hread = httpread_create(c->sd, http_client_got_response, c,
+				   c->max_response, HTTP_CLIENT_TIMEOUT_SEC);
+	if (c->hread == NULL) {
+		c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED);
+		return;
+	}
+}
+
+
+struct http_client * http_client_addr(struct sockaddr_in *dst,
+				      struct wpabuf *req, size_t max_response,
+				      void (*cb)(void *ctx,
+						 struct http_client *c,
+						 enum http_client_event event),
+				      void *cb_ctx)
+{
+	struct http_client *c;
+
+	c = os_zalloc(sizeof(*c));
+	if (c == NULL)
+		return NULL;
+	c->sd = -1;
+	c->dst = *dst;
+	c->max_response = max_response;
+	c->cb = cb;
+	c->cb_ctx = cb_ctx;
+
+	c->sd = socket(AF_INET, SOCK_STREAM, 0);
+	if (c->sd < 0) {
+		http_client_free(c);
+		return NULL;
+	}
+
+	if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) {
+		wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s",
+			   strerror(errno));
+		http_client_free(c);
+		return NULL;
+	}
+
+	if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) {
+		if (errno != EINPROGRESS) {
+			wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s",
+				   strerror(errno));
+			http_client_free(c);
+			return NULL;
+		}
+
+		/*
+		 * Continue connecting in the background; eloop will call us
+		 * once the connection is ready (or failed).
+		 */
+	}
+
+	if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready,
+				c, NULL)) {
+		http_client_free(c);
+		return NULL;
+	}
+
+	if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0,
+				   http_client_timeout, c, NULL)) {
+		http_client_free(c);
+		return NULL;
+	}
+
+	c->req = req;
+
+	return c;
+}
+
+
+char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
+			     char **ret_path)
+{
+	char *u, *addr, *port, *path;
+
+	u = os_strdup(url);
+	if (u == NULL)
+		return NULL;
+
+	os_memset(dst, 0, sizeof(*dst));
+	dst->sin_family = AF_INET;
+	addr = u + 7;
+	path = os_strchr(addr, '/');
+	port = os_strchr(addr, ':');
+	if (path == NULL) {
+		path = "/";
+	} else {
+		*path = '\0'; /* temporary nul termination for address */
+		if (port > path)
+			port = NULL;
+	}
+	if (port)
+		*port++ = '\0';
+
+	if (inet_aton(addr, &dst->sin_addr) == 0) {
+		/* TODO: name lookup */
+		wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' "
+			   "(addr='%s' port='%s')",
+			   url, addr, port);
+		os_free(u);
+		return NULL;
+	}
+
+	if (port)
+		dst->sin_port = htons(atoi(port));
+	else
+		dst->sin_port = htons(80);
+
+	if (*path == '\0') {
+		/* remove temporary nul termination for address */
+		*path = '/';
+	}
+
+	*ret_path = path;
+
+	return u;
+}
+
+
+struct http_client * http_client_url(const char *url,
+				     struct wpabuf *req, size_t max_response,
+				     void (*cb)(void *ctx,
+						struct http_client *c,
+						enum http_client_event event),
+				     void *cb_ctx)
+{
+	struct sockaddr_in dst;
+	struct http_client *c;
+	char *u, *path;
+	struct wpabuf *req_buf = NULL;
+
+	if (os_strncmp(url, "http://", 7) != 0)
+		return NULL;
+	u = http_client_url_parse(url, &dst, &path);
+	if (u == NULL)
+		return NULL;
+
+	if (req == NULL) {
+		req_buf = wpabuf_alloc(os_strlen(url) + 1000);
+		if (req_buf == NULL) {
+			os_free(u);
+			return NULL;
+		}
+		req = req_buf;
+		wpabuf_printf(req,
+			      "GET %s HTTP/1.1\r\n"
+			      "Cache-Control: no-cache\r\n"
+			      "Pragma: no-cache\r\n"
+			      "Accept: text/xml, application/xml\r\n"
+			      "User-Agent: wpa_supplicant\r\n"
+			      "Host: %s:%d\r\n"
+			      "\r\n",
+			      path, inet_ntoa(dst.sin_addr),
+			      ntohs(dst.sin_port));
+	}
+	os_free(u);
+
+	c = http_client_addr(&dst, req, max_response, cb, cb_ctx);
+	if (c == NULL) {
+		wpabuf_free(req_buf);
+		return NULL;
+	}
+
+	return c;
+}
+
+
+void http_client_free(struct http_client *c)
+{
+	if (c == NULL)
+		return;
+	httpread_destroy(c->hread);
+	wpabuf_free(c->req);
+	if (c->sd >= 0) {
+		eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE);
+		close(c->sd);
+	}
+	eloop_cancel_timeout(http_client_timeout, c, NULL);
+	os_free(c);
+}
+
+
+struct wpabuf * http_client_get_body(struct http_client *c)
+{
+	if (c->hread == NULL)
+		return NULL;
+	wpabuf_set(&c->body, httpread_data_get(c->hread),
+		   httpread_length_get(c->hread));
+	return &c->body;
+}
+
+
+char * http_client_get_hdr_line(struct http_client *c, const char *tag)
+{
+	if (c->hread == NULL)
+		return NULL;
+	return httpread_hdr_line_get(c->hread, tag);
+}
+
+
+char * http_link_update(char *url, const char *base)
+{
+	char *n;
+	size_t len;
+	const char *pos;
+
+	/* RFC 2396, Chapter 5.2 */
+	/* TODO: consider adding all cases described in RFC 2396 */
+
+	if (url == NULL)
+		return NULL;
+
+	if (os_strncmp(url, "http://", 7) == 0)
+		return url; /* absolute link */
+
+	if (os_strncmp(base, "http://", 7) != 0)
+		return url; /* unable to handle base URL */
+
+	len = os_strlen(url) + 1 + os_strlen(base) + 1;
+	n = os_malloc(len);
+	if (n == NULL)
+		return url; /* failed */
+
+	if (url[0] == '/') {
+		pos = os_strchr(base + 7, '/');
+		if (pos == NULL) {
+			os_snprintf(n, len, "%s%s", base, url);
+		} else {
+			os_memcpy(n, base, pos - base);
+			os_memcpy(n + (pos - base), url, os_strlen(url) + 1);
+		}
+	} else {
+		pos = os_strrchr(base + 7, '/');
+		if (pos == NULL) {
+			os_snprintf(n, len, "%s/%s", base, url);
+		} else {
+			os_memcpy(n, base, pos - base + 1);
+			os_memcpy(n + (pos - base) + 1, url, os_strlen(url) +
+				  1);
+		}
+	}
+
+	os_free(url);
+
+	return n;
+}

Deleted: vendor/wpa/2.0/src/wps/http_client.h
===================================================================
--- vendor/wpa/dist/src/wps/http_client.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/http_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,46 +0,0 @@
-/*
- * http_client - HTTP client
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HTTP_CLIENT_H
-#define HTTP_CLIENT_H
-
-struct http_client;
-
-enum http_client_event {
-	HTTP_CLIENT_FAILED,
-	HTTP_CLIENT_TIMEOUT,
-	HTTP_CLIENT_OK,
-	HTTP_CLIENT_INVALID_REPLY,
-};
-
-char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
-			     char **path);
-struct http_client * http_client_addr(struct sockaddr_in *dst,
-				      struct wpabuf *req, size_t max_response,
-				      void (*cb)(void *ctx,
-						 struct http_client *c,
-						 enum http_client_event event),
-				      void *cb_ctx);
-struct http_client * http_client_url(const char *url,
-				     struct wpabuf *req, size_t max_response,
-				     void (*cb)(void *ctx,
-						struct http_client *c,
-						enum http_client_event event),
-				     void *cb_ctx);
-void http_client_free(struct http_client *c);
-struct wpabuf * http_client_get_body(struct http_client *c);
-char * http_client_get_hdr_line(struct http_client *c, const char *tag);
-char * http_link_update(char *url, const char *base);
-
-#endif /* HTTP_CLIENT_H */

Copied: vendor/wpa/2.0/src/wps/http_client.h (from rev 9639, vendor/wpa/dist/src/wps/http_client.h)
===================================================================
--- vendor/wpa/2.0/src/wps/http_client.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/http_client.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,40 @@
+/*
+ * http_client - HTTP client
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HTTP_CLIENT_H
+#define HTTP_CLIENT_H
+
+struct http_client;
+
+enum http_client_event {
+	HTTP_CLIENT_FAILED,
+	HTTP_CLIENT_TIMEOUT,
+	HTTP_CLIENT_OK,
+	HTTP_CLIENT_INVALID_REPLY,
+};
+
+char * http_client_url_parse(const char *url, struct sockaddr_in *dst,
+			     char **path);
+struct http_client * http_client_addr(struct sockaddr_in *dst,
+				      struct wpabuf *req, size_t max_response,
+				      void (*cb)(void *ctx,
+						 struct http_client *c,
+						 enum http_client_event event),
+				      void *cb_ctx);
+struct http_client * http_client_url(const char *url,
+				     struct wpabuf *req, size_t max_response,
+				     void (*cb)(void *ctx,
+						struct http_client *c,
+						enum http_client_event event),
+				     void *cb_ctx);
+void http_client_free(struct http_client *c);
+struct wpabuf * http_client_get_body(struct http_client *c);
+char * http_client_get_hdr_line(struct http_client *c, const char *tag);
+char * http_link_update(char *url, const char *base);
+
+#endif /* HTTP_CLIENT_H */

Deleted: vendor/wpa/2.0/src/wps/http_server.c
===================================================================
--- vendor/wpa/dist/src/wps/http_server.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/http_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,312 +0,0 @@
-/*
- * http_server - HTTP server
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <fcntl.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "httpread.h"
-#include "http_server.h"
-
-#define HTTP_SERVER_TIMEOUT 30
-#define HTTP_SERVER_MAX_REQ_LEN 8000
-#define HTTP_SERVER_MAX_CONNECTIONS 10
-
-struct http_request {
-	struct http_request *next;
-	struct http_server *srv;
-	int fd;
-	struct sockaddr_in cli;
-	struct httpread *hread;
-};
-
-struct http_server {
-	void (*cb)(void *ctx, struct http_request *req);
-	void *cb_ctx;
-
-	int fd;
-	int port;
-
-	struct http_request *requests;
-	unsigned int request_count;
-};
-
-
-static void http_request_cb(struct httpread *handle, void *cookie,
-			    enum httpread_event en)
-{
-	struct http_request *req = cookie;
-	struct http_server *srv = req->srv;
-
-	if (en == HTTPREAD_EVENT_FILE_READY) {
-		wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received",
-			   inet_ntoa(req->cli.sin_addr),
-			   ntohs(req->cli.sin_port));
-		srv->cb(srv->cb_ctx, req);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received "
-		   "completely", inet_ntoa(req->cli.sin_addr),
-		   ntohs(req->cli.sin_port));
-	http_request_deinit(req);
-}
-
-
-static struct http_request * http_request_init(struct http_server *srv, int fd,
-					       struct sockaddr_in *cli)
-{
-	struct http_request *req;
-
-	if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) {
-		wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests");
-		return NULL;
-	}
-
-	req = os_zalloc(sizeof(*req));
-	if (req == NULL)
-		return NULL;
-
-	req->srv = srv;
-	req->fd = fd;
-	req->cli = *cli;
-
-	req->hread = httpread_create(req->fd, http_request_cb, req,
-				     HTTP_SERVER_MAX_REQ_LEN,
-				     HTTP_SERVER_TIMEOUT);
-	if (req->hread == NULL) {
-		http_request_deinit(req);
-		return NULL;
-	}
-
-	return req;
-}
-
-
-void http_request_deinit(struct http_request *req)
-{
-	struct http_request *r, *p;
-	struct http_server *srv;
-
-	if (req == NULL)
-		return;
-
-	srv = req->srv;
-	p = NULL;
-	r = srv->requests;
-	while (r) {
-		if (r == req) {
-			if (p)
-				p->next = r->next;
-			else
-				srv->requests = r->next;
-			srv->request_count--;
-			break;
-		}
-		p = r;
-		r = r->next;
-	}
-
-	httpread_destroy(req->hread);
-	close(req->fd);
-	os_free(req);
-}
-
-
-static void http_request_free_all(struct http_request *req)
-{
-	struct http_request *prev;
-	while (req) {
-		prev = req;
-		req = req->next;
-		http_request_deinit(prev);
-	}
-}
-
-
-void http_request_send(struct http_request *req, struct wpabuf *resp)
-{
-	int res;
-
-	wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d",
-		   (unsigned long) wpabuf_len(resp),
-		   inet_ntoa(req->cli.sin_addr),
-		   ntohs(req->cli.sin_port));
-
-	res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s",
-			   strerror(errno));
-	} else if ((size_t) res < wpabuf_len(resp)) {
-		wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes",
-			   res, (unsigned long) wpabuf_len(resp));
-		/* TODO: add eloop handler for sending rest of the data */
-	}
-
-	wpabuf_free(resp);
-}
-
-
-void http_request_send_and_deinit(struct http_request *req,
-				  struct wpabuf *resp)
-{
-	http_request_send(req, resp);
-	http_request_deinit(req);
-}
-
-
-enum httpread_hdr_type http_request_get_type(struct http_request *req)
-{
-	return httpread_hdr_type_get(req->hread);
-}
-
-
-char * http_request_get_uri(struct http_request *req)
-{
-	return httpread_uri_get(req->hread);
-}
-
-
-char * http_request_get_hdr(struct http_request *req)
-{
-	return httpread_hdr_get(req->hread);
-}
-
-
-char * http_request_get_data(struct http_request *req)
-{
-	return httpread_data_get(req->hread);
-}
-
-
-char * http_request_get_hdr_line(struct http_request *req, const char *tag)
-{
-	return httpread_hdr_line_get(req->hread, tag);
-}
-
-
-struct sockaddr_in * http_request_get_cli_addr(struct http_request *req)
-{
-	return &req->cli;
-}
-
-
-static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
-{
-	struct sockaddr_in addr;
-	socklen_t addr_len = sizeof(addr);
-	struct http_server *srv = eloop_ctx;
-	int conn;
-	struct http_request *req;
-
-	conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
-	if (conn < 0) {
-		wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: "
-			   "%s", strerror(errno));
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
-		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
-
-	req = http_request_init(srv, conn, &addr);
-	if (req == NULL) {
-		close(conn);
-		return;
-	}
-
-	req->next = srv->requests;
-	srv->requests = req;
-	srv->request_count++;
-}
-
-
-struct http_server * http_server_init(struct in_addr *addr, int port,
-				      void (*cb)(void *ctx,
-						 struct http_request *req),
-				      void *cb_ctx)
-{
-	struct sockaddr_in sin;
-	struct http_server *srv;
-
-	srv = os_zalloc(sizeof(*srv));
-	if (srv == NULL)
-		return NULL;
-	srv->cb = cb;
-	srv->cb_ctx = cb_ctx;
-
-	srv->fd = socket(AF_INET, SOCK_STREAM, 0);
-	if (srv->fd < 0)
-		goto fail;
-	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
-		goto fail;
-	if (port < 0)
-		srv->port = 49152;
-	else
-		srv->port = port;
-
-	os_memset(&sin, 0, sizeof(sin));
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = addr->s_addr;
-
-	for (;;) {
-		sin.sin_port = htons(srv->port);
-		if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0)
-			break;
-		if (errno == EADDRINUSE) {
-			/* search for unused port */
-			if (++srv->port == 65535 || port >= 0)
-				goto fail;
-			continue;
-		}
-		wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: "
-			   "%s", srv->port, strerror(errno));
-		goto fail;
-	}
-	if (listen(srv->fd, 10 /* max backlog */) < 0)
-		goto fail;
-	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
-		goto fail;
-	if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb,
-				srv, NULL))
-		goto fail;
-
-	wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d",
-		   inet_ntoa(*addr), srv->port);
-
-	return srv;
-
-fail:
-	http_server_deinit(srv);
-	return NULL;
-}
-
-
-void http_server_deinit(struct http_server *srv)
-{
-	if (srv == NULL)
-		return;
-	if (srv->fd >= 0) {
-		eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
-		close(srv->fd);
-	}
-	http_request_free_all(srv->requests);
-
-	os_free(srv);
-}
-
-
-int http_server_get_port(struct http_server *srv)
-{
-	return srv->port;
-}

Copied: vendor/wpa/2.0/src/wps/http_server.c (from rev 9639, vendor/wpa/dist/src/wps/http_server.c)
===================================================================
--- vendor/wpa/2.0/src/wps/http_server.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/http_server.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,306 @@
+/*
+ * http_server - HTTP server
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "httpread.h"
+#include "http_server.h"
+
+#define HTTP_SERVER_TIMEOUT 30
+#define HTTP_SERVER_MAX_REQ_LEN 8000
+#define HTTP_SERVER_MAX_CONNECTIONS 10
+
+struct http_request {
+	struct http_request *next;
+	struct http_server *srv;
+	int fd;
+	struct sockaddr_in cli;
+	struct httpread *hread;
+};
+
+struct http_server {
+	void (*cb)(void *ctx, struct http_request *req);
+	void *cb_ctx;
+
+	int fd;
+	int port;
+
+	struct http_request *requests;
+	unsigned int request_count;
+};
+
+
+static void http_request_cb(struct httpread *handle, void *cookie,
+			    enum httpread_event en)
+{
+	struct http_request *req = cookie;
+	struct http_server *srv = req->srv;
+
+	if (en == HTTPREAD_EVENT_FILE_READY) {
+		wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received",
+			   inet_ntoa(req->cli.sin_addr),
+			   ntohs(req->cli.sin_port));
+		srv->cb(srv->cb_ctx, req);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received "
+		   "completely", inet_ntoa(req->cli.sin_addr),
+		   ntohs(req->cli.sin_port));
+	http_request_deinit(req);
+}
+
+
+static struct http_request * http_request_init(struct http_server *srv, int fd,
+					       struct sockaddr_in *cli)
+{
+	struct http_request *req;
+
+	if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) {
+		wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests");
+		return NULL;
+	}
+
+	req = os_zalloc(sizeof(*req));
+	if (req == NULL)
+		return NULL;
+
+	req->srv = srv;
+	req->fd = fd;
+	req->cli = *cli;
+
+	req->hread = httpread_create(req->fd, http_request_cb, req,
+				     HTTP_SERVER_MAX_REQ_LEN,
+				     HTTP_SERVER_TIMEOUT);
+	if (req->hread == NULL) {
+		http_request_deinit(req);
+		return NULL;
+	}
+
+	return req;
+}
+
+
+void http_request_deinit(struct http_request *req)
+{
+	struct http_request *r, *p;
+	struct http_server *srv;
+
+	if (req == NULL)
+		return;
+
+	srv = req->srv;
+	p = NULL;
+	r = srv->requests;
+	while (r) {
+		if (r == req) {
+			if (p)
+				p->next = r->next;
+			else
+				srv->requests = r->next;
+			srv->request_count--;
+			break;
+		}
+		p = r;
+		r = r->next;
+	}
+
+	httpread_destroy(req->hread);
+	close(req->fd);
+	os_free(req);
+}
+
+
+static void http_request_free_all(struct http_request *req)
+{
+	struct http_request *prev;
+	while (req) {
+		prev = req;
+		req = req->next;
+		http_request_deinit(prev);
+	}
+}
+
+
+void http_request_send(struct http_request *req, struct wpabuf *resp)
+{
+	int res;
+
+	wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d",
+		   (unsigned long) wpabuf_len(resp),
+		   inet_ntoa(req->cli.sin_addr),
+		   ntohs(req->cli.sin_port));
+
+	res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s",
+			   strerror(errno));
+	} else if ((size_t) res < wpabuf_len(resp)) {
+		wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes",
+			   res, (unsigned long) wpabuf_len(resp));
+		/* TODO: add eloop handler for sending rest of the data */
+	}
+
+	wpabuf_free(resp);
+}
+
+
+void http_request_send_and_deinit(struct http_request *req,
+				  struct wpabuf *resp)
+{
+	http_request_send(req, resp);
+	http_request_deinit(req);
+}
+
+
+enum httpread_hdr_type http_request_get_type(struct http_request *req)
+{
+	return httpread_hdr_type_get(req->hread);
+}
+
+
+char * http_request_get_uri(struct http_request *req)
+{
+	return httpread_uri_get(req->hread);
+}
+
+
+char * http_request_get_hdr(struct http_request *req)
+{
+	return httpread_hdr_get(req->hread);
+}
+
+
+char * http_request_get_data(struct http_request *req)
+{
+	return httpread_data_get(req->hread);
+}
+
+
+char * http_request_get_hdr_line(struct http_request *req, const char *tag)
+{
+	return httpread_hdr_line_get(req->hread, tag);
+}
+
+
+struct sockaddr_in * http_request_get_cli_addr(struct http_request *req)
+{
+	return &req->cli;
+}
+
+
+static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
+{
+	struct sockaddr_in addr;
+	socklen_t addr_len = sizeof(addr);
+	struct http_server *srv = eloop_ctx;
+	int conn;
+	struct http_request *req;
+
+	conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
+	if (conn < 0) {
+		wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: "
+			   "%s", strerror(errno));
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
+		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+
+	req = http_request_init(srv, conn, &addr);
+	if (req == NULL) {
+		close(conn);
+		return;
+	}
+
+	req->next = srv->requests;
+	srv->requests = req;
+	srv->request_count++;
+}
+
+
+struct http_server * http_server_init(struct in_addr *addr, int port,
+				      void (*cb)(void *ctx,
+						 struct http_request *req),
+				      void *cb_ctx)
+{
+	struct sockaddr_in sin;
+	struct http_server *srv;
+
+	srv = os_zalloc(sizeof(*srv));
+	if (srv == NULL)
+		return NULL;
+	srv->cb = cb;
+	srv->cb_ctx = cb_ctx;
+
+	srv->fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (srv->fd < 0)
+		goto fail;
+	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
+		goto fail;
+	if (port < 0)
+		srv->port = 49152;
+	else
+		srv->port = port;
+
+	os_memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = addr->s_addr;
+
+	for (;;) {
+		sin.sin_port = htons(srv->port);
+		if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0)
+			break;
+		if (errno == EADDRINUSE) {
+			/* search for unused port */
+			if (++srv->port == 65535 || port >= 0)
+				goto fail;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: "
+			   "%s", srv->port, strerror(errno));
+		goto fail;
+	}
+	if (listen(srv->fd, 10 /* max backlog */) < 0)
+		goto fail;
+	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
+		goto fail;
+	if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb,
+				srv, NULL))
+		goto fail;
+
+	wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d",
+		   inet_ntoa(*addr), srv->port);
+
+	return srv;
+
+fail:
+	http_server_deinit(srv);
+	return NULL;
+}
+
+
+void http_server_deinit(struct http_server *srv)
+{
+	if (srv == NULL)
+		return;
+	if (srv->fd >= 0) {
+		eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
+		close(srv->fd);
+	}
+	http_request_free_all(srv->requests);
+
+	os_free(srv);
+}
+
+
+int http_server_get_port(struct http_server *srv)
+{
+	return srv->port;
+}

Deleted: vendor/wpa/2.0/src/wps/http_server.h
===================================================================
--- vendor/wpa/dist/src/wps/http_server.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/http_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,39 +0,0 @@
-/*
- * http_server - HTTP server
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HTTP_SERVER_H
-#define HTTP_SERVER_H
-
-struct http_server;
-struct http_request;
-
-void http_request_deinit(struct http_request *req);
-void http_request_send(struct http_request *req, struct wpabuf *resp);
-void http_request_send_and_deinit(struct http_request *req,
-				  struct wpabuf *resp);
-enum httpread_hdr_type http_request_get_type(struct http_request *req);
-char * http_request_get_uri(struct http_request *req);
-char * http_request_get_hdr(struct http_request *req);
-char * http_request_get_data(struct http_request *req);
-char * http_request_get_hdr_line(struct http_request *req, const char *tag);
-struct sockaddr_in * http_request_get_cli_addr(struct http_request *req);
-
-struct http_server * http_server_init(struct in_addr *addr, int port,
-				      void (*cb)(void *ctx,
-						 struct http_request *req),
-				      void *cb_ctx);
-void http_server_deinit(struct http_server *srv);
-int http_server_get_port(struct http_server *srv);
-
-#endif /* HTTP_SERVER_H */

Copied: vendor/wpa/2.0/src/wps/http_server.h (from rev 9639, vendor/wpa/dist/src/wps/http_server.h)
===================================================================
--- vendor/wpa/2.0/src/wps/http_server.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/http_server.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,33 @@
+/*
+ * http_server - HTTP server
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HTTP_SERVER_H
+#define HTTP_SERVER_H
+
+struct http_server;
+struct http_request;
+
+void http_request_deinit(struct http_request *req);
+void http_request_send(struct http_request *req, struct wpabuf *resp);
+void http_request_send_and_deinit(struct http_request *req,
+				  struct wpabuf *resp);
+enum httpread_hdr_type http_request_get_type(struct http_request *req);
+char * http_request_get_uri(struct http_request *req);
+char * http_request_get_hdr(struct http_request *req);
+char * http_request_get_data(struct http_request *req);
+char * http_request_get_hdr_line(struct http_request *req, const char *tag);
+struct sockaddr_in * http_request_get_cli_addr(struct http_request *req);
+
+struct http_server * http_server_init(struct in_addr *addr, int port,
+				      void (*cb)(void *ctx,
+						 struct http_request *req),
+				      void *cb_ctx);
+void http_server_deinit(struct http_server *srv);
+int http_server_get_port(struct http_server *srv);
+
+#endif /* HTTP_SERVER_H */

Deleted: vendor/wpa/2.0/src/wps/httpread.c
===================================================================
--- vendor/wpa/dist/src/wps/httpread.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/httpread.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,861 +0,0 @@
-/*
- * httpread - Manage reading file(s) from HTTP/TCP socket
- * Author: Ted Merrill
- * Copyright 2008 Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * The files are buffered via internal callbacks from eloop, then presented to
- * an application callback routine when completely read into memory. May also
- * be used if no file is expected but just to get the header, including HTTP
- * replies (e.g. HTTP/1.1 200 OK etc.).
- *
- * This does not attempt to be an optimally efficient implementation, but does
- * attempt to be of reasonably small size and memory consumption; assuming that
- * only small files are to be read. A maximum file size is provided by
- * application and enforced.
- *
- * It is assumed that the application does not expect any of the following:
- * -- transfer encoding other than chunked
- * -- trailer fields
- * It is assumed that, even if the other side requested that the connection be
- * kept open, that we will close it (thus HTTP messages sent by application
- * should have the connection closed field); this is allowed by HTTP/1.1 and
- * simplifies things for us.
- *
- * Other limitations:
- * -- HTTP header may not exceed a hard-coded size.
- *
- * Notes:
- * This code would be massively simpler without some of the new features of
- * HTTP/1.1, especially chunked data.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "httpread.h"
-
-
-/* Tunable parameters */
-#define HTTPREAD_READBUF_SIZE 1024      /* read in chunks of this size */
-#define HTTPREAD_HEADER_MAX_SIZE 4096   /* max allowed for headers */
-#define HTTPREAD_BODYBUF_DELTA 4096     /* increase allocation by this */
-
-#if 0
-/* httpread_debug -- set this global variable > 0 e.g. from debugger
- * to enable debugs (larger numbers for more debugs)
- * Make this a #define of 0 to eliminate the debugging code.
- */
-int httpread_debug = 99;
-#else
-#define httpread_debug 0        /* eliminates even the debugging code */
-#endif
-
-
-/* control instance -- actual definition (opaque to application)
- */
-struct httpread {
-	/* information from creation */
-	int sd;         /* descriptor of TCP socket to read from */
-	void (*cb)(struct httpread *handle, void *cookie,
-		    enum httpread_event e);  /* call on event */
-	void *cookie;   /* pass to callback */
-	int max_bytes;          /* maximum file size else abort it */
-	int timeout_seconds;            /* 0 or total duration timeout period */
-
-	/* dynamically used information follows */
-	int sd_registered;      /* nonzero if we need to unregister socket */
-	int to_registered;      /* nonzero if we need to unregister timeout */
-
-	int got_hdr;            /* nonzero when header is finalized */
-	char hdr[HTTPREAD_HEADER_MAX_SIZE+1];   /* headers stored here */
-	int hdr_nbytes;
-
-	enum httpread_hdr_type hdr_type;
-	int version;            /* 1 if we've seen 1.1 */
-	int reply_code;         /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
-	int got_content_length; /* true if we know content length for sure */
-	int content_length;     /* body length,  iff got_content_length */
-	int chunked;            /* nonzero for chunked data */
-	char *uri;
-
-	int got_body;           /* nonzero when body is finalized */
-	char *body;
-	int body_nbytes;
-	int body_alloc_nbytes;  /* amount allocated */
-
-	int got_file;           /* here when we are done */
-
-	/* The following apply if data is chunked: */
-	int in_chunk_data;      /* 0=in/at header, 1=in the data or tail*/
-	int chunk_start;        /* offset in body of chunk hdr or data */
-	int chunk_size;         /* data of chunk (not hdr or ending CRLF)*/
-	int in_trailer;         /* in header fields after data (chunked only)*/
-	enum trailer_state {
-		trailer_line_begin = 0,
-		trailer_empty_cr,       /* empty line + CR */
-		trailer_nonempty,
-		trailer_nonempty_cr,
-	} trailer_state;
-};
-
-
-/* Check words for equality, where words consist of graphical characters
- * delimited by whitespace
- * Returns nonzero if "equal" doing case insensitive comparison.
- */
-static int word_eq(char *s1, char *s2)
-{
-	int c1;
-	int c2;
-	int end1 = 0;
-	int end2 = 0;
-	for (;;) {
-		c1 = *s1++;
-		c2 = *s2++;
-		if (isalpha(c1) && isupper(c1))
-			c1 = tolower(c1);
-		if (isalpha(c2) && isupper(c2))
-			c2 = tolower(c2);
-		end1 = !isgraph(c1);
-		end2 = !isgraph(c2);
-		if (end1 || end2 || c1 != c2)
-			break;
-	}
-	return end1 && end2;  /* reached end of both words? */
-}
-
-
-/* convert hex to binary
- * Requires that c have been previously tested true with isxdigit().
- */
-static int hex_value(int c)
-{
-	if (isdigit(c))
-		return c - '0';
-	if (islower(c))
-		return 10 + c - 'a';
-	return 10 + c - 'A';
-}
-
-
-static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
-
-/* httpread_destroy -- if h is non-NULL, clean up
- * This must eventually be called by the application following
- * call of the application's callback and may be called
- * earlier if desired.
- */
-void httpread_destroy(struct httpread *h)
-{
-	if (httpread_debug >= 10)
-		wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
-	if (!h)
-		return;
-
-	if (h->to_registered)
-		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-	h->to_registered = 0;
-	if (h->sd_registered)
-		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-	h->sd_registered = 0;
-	os_free(h->body);
-	os_free(h->uri);
-	os_memset(h, 0, sizeof(*h));  /* aid debugging */
-	h->sd = -1;     /* aid debugging */
-	os_free(h);
-}
-
-
-/* httpread_timeout_handler -- called on excessive total duration
- */
-static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
-{
-	struct httpread *h = user_ctx;
-	wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
-	h->to_registered = 0;   /* is self-cancelling */
-	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
-}
-
-
-/* Analyze options only so far as is needed to correctly obtain the file.
- * The application can look at the raw header to find other options.
- */
-static int httpread_hdr_option_analyze(
-	struct httpread *h,
-	char *hbp       /* pointer to current line in header buffer */
-	)
-{
-	if (word_eq(hbp, "CONTENT-LENGTH:")) {
-		while (isgraph(*hbp))
-			hbp++;
-		while (*hbp == ' ' || *hbp == '\t')
-			hbp++;
-		if (!isdigit(*hbp))
-			return -1;
-		h->content_length = atol(hbp);
-		h->got_content_length = 1;
-		return 0;
-	}
-	if (word_eq(hbp, "TRANSFER_ENCODING:") ||
-	    word_eq(hbp, "TRANSFER-ENCODING:")) {
-		while (isgraph(*hbp))
-			hbp++;
-		while (*hbp == ' ' || *hbp == '\t')
-			hbp++;
-		/* There should (?) be no encodings of interest
-		 * other than chunked...
-		 */
-		if (word_eq(hbp, "CHUNKED")) {
-			h->chunked = 1;
-			h->in_chunk_data = 0;
-			/* ignore possible ;<parameters> */
-		}
-		return 0;
-	}
-	/* skip anything we don't know, which is a lot */
-	return 0;
-}
-
-
-static int httpread_hdr_analyze(struct httpread *h)
-{
-	char *hbp = h->hdr;      /* pointer into h->hdr */
-	int standard_first_line = 1;
-
-	/* First line is special */
-	h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
-	if (!isgraph(*hbp))
-		goto bad;
-	if (os_strncmp(hbp, "HTTP/", 5) == 0) {
-		h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
-		standard_first_line = 0;
-		hbp += 5;
-		if (hbp[0] == '1' && hbp[1] == '.' &&
-		    isdigit(hbp[2]) && hbp[2] != '0')
-			h->version = 1;
-		while (isgraph(*hbp))
-			hbp++;
-		while (*hbp == ' ' || *hbp == '\t')
-			hbp++;
-		if (!isdigit(*hbp))
-			goto bad;
-		h->reply_code = atol(hbp);
-	} else if (word_eq(hbp, "GET"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_GET;
-	else if (word_eq(hbp, "HEAD"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
-	else if (word_eq(hbp, "POST"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_POST;
-	else if (word_eq(hbp, "PUT"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
-	else if (word_eq(hbp, "DELETE"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
-	else if (word_eq(hbp, "TRACE"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
-	else if (word_eq(hbp, "CONNECT"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
-	else if (word_eq(hbp, "NOTIFY"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
-	else if (word_eq(hbp, "M-SEARCH"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
-	else if (word_eq(hbp, "M-POST"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
-	else if (word_eq(hbp, "SUBSCRIBE"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
-	else if (word_eq(hbp, "UNSUBSCRIBE"))
-		h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
-	else {
-	}
-
-	if (standard_first_line) {
-		char *rawuri;
-		char *uri;
-		/* skip type */
-		while (isgraph(*hbp))
-			hbp++;
-		while (*hbp == ' ' || *hbp == '\t')
-			hbp++;
-		/* parse uri.
-		 * Find length, allocate memory for translated
-		 * copy, then translate by changing %<hex><hex>
-		 * into represented value.
-		 */
-		rawuri = hbp;
-		while (isgraph(*hbp))
-			hbp++;
-		h->uri = os_malloc((hbp - rawuri) + 1);
-		if (h->uri == NULL)
-			goto bad;
-		uri = h->uri;
-		while (rawuri < hbp) {
-			int c = *rawuri;
-			if (c == '%' &&
-			    isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
-				*uri++ = (hex_value(rawuri[1]) << 4) |
-					hex_value(rawuri[2]);
-				rawuri += 3;
-			} else {
-				*uri++ = c;
-				rawuri++;
-			}
-		}
-		*uri = 0;       /* null terminate */
-		while (isgraph(*hbp))
-			hbp++;
-		while (*hbp == ' ' || *hbp == '\t')
-			hbp++;
-		/* get version */
-		if (0 == strncmp(hbp, "HTTP/", 5)) {
-			hbp += 5;
-			if (hbp[0] == '1' && hbp[1] == '.' &&
-			    isdigit(hbp[2]) && hbp[2] != '0')
-				h->version = 1;
-		}
-	}
-	/* skip rest of line */
-	while (*hbp)
-		if (*hbp++ == '\n')
-			break;
-
-	/* Remainder of lines are options, in any order;
-	 * or empty line to terminate
-	 */
-	for (;;) {
-		/* Empty line to terminate */
-		if (hbp[0] == '\n' ||
-		    (hbp[0] == '\r' && hbp[1] == '\n'))
-			break;
-		if (!isgraph(*hbp))
-			goto bad;
-		if (httpread_hdr_option_analyze(h, hbp))
-			goto bad;
-		/* skip line */
-		while (*hbp)
-			if (*hbp++ == '\n')
-				break;
-	}
-
-	/* chunked overrides content-length always */
-	if (h->chunked)
-		h->got_content_length = 0;
-
-	/* For some types, we should not try to read a body
-	 * This is in addition to the application determining
-	 * that we should not read a body.
-	 */
-	switch (h->hdr_type) {
-	case HTTPREAD_HDR_TYPE_REPLY:
-		/* Some codes can have a body and some not.
-		 * For now, just assume that any other than 200
-		 * do not...
-		 */
-		if (h->reply_code != 200)
-			h->max_bytes = 0;
-		break;
-	case HTTPREAD_HDR_TYPE_GET:
-	case HTTPREAD_HDR_TYPE_HEAD:
-		/* in practice it appears that it is assumed
-		 * that GETs have a body length of 0... ?
-		 */
-		if (h->chunked == 0 && h->got_content_length == 0)
-			h->max_bytes = 0;
-		break;
-	case HTTPREAD_HDR_TYPE_POST:
-	case HTTPREAD_HDR_TYPE_PUT:
-	case HTTPREAD_HDR_TYPE_DELETE:
-	case HTTPREAD_HDR_TYPE_TRACE:
-	case HTTPREAD_HDR_TYPE_CONNECT:
-	case HTTPREAD_HDR_TYPE_NOTIFY:
-	case HTTPREAD_HDR_TYPE_M_SEARCH:
-	case HTTPREAD_HDR_TYPE_M_POST:
-	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
-	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
-	default:
-		break;
-	}
-
-	return 0;
-
-bad:
-	/* Error */
-	return -1;
-}
-
-
-/* httpread_read_handler -- called when socket ready to read
- *
- * Note: any extra data we read past end of transmitted file is ignored;
- * if we were to support keeping connections open for multiple files then
- * this would have to be addressed.
- */
-static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
-{
-	struct httpread *h = sock_ctx;
-	int nread;
-	char *rbp;      /* pointer into read buffer */
-	char *hbp;      /* pointer into header buffer */
-	char *bbp;      /* pointer into body buffer */
-	char readbuf[HTTPREAD_READBUF_SIZE];  /* temp use to read into */
-
-	if (httpread_debug >= 20)
-		wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
-
-	/* read some at a time, then search for the interal
-	 * boundaries between header and data and etc.
-	 */
-	nread = read(h->sd, readbuf, sizeof(readbuf));
-	if (nread < 0)
-		goto bad;
-	if (nread == 0) {
-		/* end of transmission... this may be normal
-		 * or may be an error... in some cases we can't
-		 * tell which so we must assume it is normal then.
-		 */
-		if (!h->got_hdr) {
-			/* Must at least have completed header */
-			wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
-			goto bad;
-		}
-		if (h->chunked || h->got_content_length) {
-			/* Premature EOF; e.g. dropped connection */
-			wpa_printf(MSG_DEBUG,
-				   "httpread premature eof(%p) %d/%d",
-				   h, h->body_nbytes,
-				   h->content_length);
-			goto bad;
-		}
-		/* No explicit length, hopefully we have all the data
-		 * although dropped connections can cause false
-		 * end
-		 */
-		if (httpread_debug >= 10)
-			wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
-			h->got_body = 1;
-			goto got_file;
-	}
-	rbp = readbuf;
-
-	/* Header consists of text lines (terminated by both CR and LF)
-	 * and an empty line (CR LF only).
-	 */
-	if (!h->got_hdr) {
-		hbp = h->hdr + h->hdr_nbytes;
-		/* add to headers until:
-		 *      -- we run out of data in read buffer
-		 *      -- or, we run out of header buffer room
-		 *      -- or, we get double CRLF in headers
-		 */
-		for (;;) {
-			if (nread == 0)
-				goto get_more;
-			if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
-				goto bad;
-			}
-			*hbp++ = *rbp++;
-			nread--;
-			h->hdr_nbytes++;
-			if (h->hdr_nbytes >= 4 &&
-			    hbp[-1] == '\n' &&
-			    hbp[-2] == '\r' &&
-			    hbp[-3] == '\n' &&
-			    hbp[-4] == '\r' ) {
-				h->got_hdr = 1;
-				*hbp = 0;       /* null terminate */
-				break;
-			}
-		}
-		/* here we've just finished reading the header */
-		if (httpread_hdr_analyze(h)) {
-			wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
-			goto bad;
-		}
-		if (h->max_bytes == 0) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread no body hdr end(%p)", h);
-			goto got_file;
-		}
-		if (h->got_content_length && h->content_length == 0) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread zero content length(%p)",
-					   h);
-			goto got_file;
-		}
-	}
-
-	/* Certain types of requests never have data and so
-	 * must be specially recognized.
-	 */
-	if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
-	    !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
-	    !os_strncasecmp(h->hdr, "HEAD", 4) ||
-	    !os_strncasecmp(h->hdr, "GET", 3)) {
-		if (!h->got_body) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread NO BODY for sp. type");
-		}
-		h->got_body = 1;
-		goto got_file;
-	}
-
-	/* Data can be just plain binary data, or if "chunked"
-	 * consists of chunks each with a header, ending with
-	 * an ending header.
-	 */
-	if (nread == 0)
-		goto get_more;
-	if (!h->got_body) {
-		/* Here to get (more of) body */
-		/* ensure we have enough room for worst case for body
-		 * plus a null termination character
-		 */
-		if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
-			char *new_body;
-			int new_alloc_nbytes;
-
-			if (h->body_nbytes >= h->max_bytes)
-				goto bad;
-			new_alloc_nbytes = h->body_alloc_nbytes +
-				HTTPREAD_BODYBUF_DELTA;
-			/* For content-length case, the first time
-			 * through we allocate the whole amount
-			 * we need.
-			 */
-			if (h->got_content_length &&
-			    new_alloc_nbytes < (h->content_length + 1))
-				new_alloc_nbytes = h->content_length + 1;
-			if ((new_body = os_realloc(h->body, new_alloc_nbytes))
-			    == NULL)
-				goto bad;
-
-			h->body = new_body;
-			h->body_alloc_nbytes = new_alloc_nbytes;
-		}
-		/* add bytes */
-		bbp = h->body + h->body_nbytes;
-		for (;;) {
-			int ncopy;
-			/* See if we need to stop */
-			if (h->chunked && h->in_chunk_data == 0) {
-				/* in chunk header */
-				char *cbp = h->body + h->chunk_start;
-				if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
-				    bbp[-1] == '\n') {
-					/* end of chunk hdr line */
-					/* hdr line consists solely
-					 * of a hex numeral and CFLF
-					 */
-					if (!isxdigit(*cbp))
-						goto bad;
-					h->chunk_size = strtoul(cbp, NULL, 16);
-					/* throw away chunk header
-					 * so we have only real data
-					 */
-					h->body_nbytes = h->chunk_start;
-					bbp = cbp;
-					if (h->chunk_size == 0) {
-						/* end of chunking */
-						/* trailer follows */
-						h->in_trailer = 1;
-						if (httpread_debug >= 20)
-							wpa_printf(
-								MSG_DEBUG,
-								"httpread end chunks(%p)", h);
-						break;
-					}
-					h->in_chunk_data = 1;
-					/* leave chunk_start alone */
-				}
-			} else if (h->chunked) {
-				/* in chunk data */
-				if ((h->body_nbytes - h->chunk_start) ==
-				    (h->chunk_size + 2)) {
-					/* end of chunk reached,
-					 * new chunk starts
-					 */
-					/* check chunk ended w/ CRLF
-					 * which we'll throw away
-					 */
-					if (bbp[-1] == '\n' &&
-					    bbp[-2] == '\r') {
-					} else
-						goto bad;
-					h->body_nbytes -= 2;
-					bbp -= 2;
-					h->chunk_start = h->body_nbytes;
-					h->in_chunk_data = 0;
-					h->chunk_size = 0; /* just in case */
-				}
-			} else if (h->got_content_length &&
-				   h->body_nbytes >= h->content_length) {
-				h->got_body = 1;
-				if (httpread_debug >= 10)
-					wpa_printf(
-						MSG_DEBUG,
-						"httpread got content(%p)", h);
-				goto got_file;
-			}
-			if (nread <= 0)
-				break;
-			/* Now transfer. Optimize using memcpy where we can. */
-			if (h->chunked && h->in_chunk_data) {
-				/* copy up to remainder of chunk data
-				 * plus the required CR+LF at end
-				 */
-				ncopy = (h->chunk_start + h->chunk_size + 2) -
-					h->body_nbytes;
-			} else if (h->chunked) {
-				/*in chunk header -- don't optimize */
-				*bbp++ = *rbp++;
-				nread--;
-				h->body_nbytes++;
-				continue;
-			} else if (h->got_content_length) {
-				ncopy = h->content_length - h->body_nbytes;
-			} else {
-				ncopy = nread;
-			}
-			/* Note: should never be 0 */
-			if (ncopy > nread)
-				ncopy = nread;
-			os_memcpy(bbp, rbp, ncopy);
-			bbp += ncopy;
-			h->body_nbytes += ncopy;
-			rbp += ncopy;
-			nread -= ncopy;
-		}       /* body copy loop */
-	}       /* !got_body */
-	if (h->chunked && h->in_trailer) {
-		/* If "chunked" then there is always a trailer,
-		 * consisting of zero or more non-empty lines
-		 * ending with CR LF and then an empty line w/ CR LF.
-		 * We do NOT support trailers except to skip them --
-		 * this is supported (generally) by the http spec.
-		 */
-		bbp = h->body + h->body_nbytes;
-		for (;;) {
-			int c;
-			if (nread <= 0)
-				break;
-			c = *rbp++;
-			nread--;
-			switch (h->trailer_state) {
-			case trailer_line_begin:
-				if (c == '\r')
-					h->trailer_state = trailer_empty_cr;
-				else
-					h->trailer_state = trailer_nonempty;
-				break;
-			case trailer_empty_cr:
-				/* end empty line */
-				if (c == '\n') {
-					h->trailer_state = trailer_line_begin;
-					h->in_trailer = 0;
-					if (httpread_debug >= 10)
-						wpa_printf(
-							MSG_DEBUG,
-							"httpread got content(%p)", h);
-					h->got_body = 1;
-					goto got_file;
-				}
-				h->trailer_state = trailer_nonempty;
-				break;
-			case trailer_nonempty:
-				if (c == '\r')
-					h->trailer_state = trailer_nonempty_cr;
-				break;
-			case trailer_nonempty_cr:
-				if (c == '\n')
-					h->trailer_state = trailer_line_begin;
-				else
-					h->trailer_state = trailer_nonempty;
-				break;
-			}
-		}
-	}
-	goto get_more;
-
-bad:
-	/* Error */
-	wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
-	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
-	return;
-
-get_more:
-	return;
-
-got_file:
-	if (httpread_debug >= 10)
-		wpa_printf(MSG_DEBUG,
-			   "httpread got file %d bytes type %d",
-			   h->body_nbytes, h->hdr_type);
-	/* Null terminate for convenience of some applications */
-	if (h->body)
-		h->body[h->body_nbytes] = 0; /* null terminate */
-	h->got_file = 1;
-	/* Assume that we do NOT support keeping connection alive,
-	 * and just in case somehow we don't get destroyed right away,
-	 * unregister now.
-	 */
-	if (h->sd_registered)
-		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
-	h->sd_registered = 0;
-	/* The application can destroy us whenever they feel like...
-	 * cancel timeout.
-	 */
-	if (h->to_registered)
-		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
-	h->to_registered = 0;
-	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
-}
-
-
-/* httpread_create -- start a new reading session making use of eloop.
- * The new instance will use the socket descriptor for reading (until
- * it gets a file and not after) but will not close the socket, even
- * when the instance is destroyed (the application must do that).
- * Return NULL on error.
- *
- * Provided that httpread_create successfully returns a handle,
- * the callback fnc is called to handle httpread_event events.
- * The caller should do destroy on any errors or unknown events.
- *
- * Pass max_bytes == 0 to not read body at all (required for e.g.
- * reply to HEAD request).
- */
-struct httpread * httpread_create(
-	int sd,	 /* descriptor of TCP socket to read from */
-	void (*cb)(struct httpread *handle, void *cookie,
-		   enum httpread_event e),  /* call on event */
-	void *cookie,    /* pass to callback */
-	int max_bytes,	  /* maximum body size else abort it */
-	int timeout_seconds     /* 0; or total duration timeout period */
-	)
-{
-	struct httpread *h = NULL;
-
-	h = os_zalloc(sizeof(*h));
-	if (h == NULL)
-		goto fail;
-	h->sd = sd;
-	h->cb = cb;
-	h->cookie = cookie;
-	h->max_bytes = max_bytes;
-	h->timeout_seconds = timeout_seconds;
-
-	if (timeout_seconds > 0) {
-		if (eloop_register_timeout(timeout_seconds, 0,
-					   httpread_timeout_handler,
-					   NULL, h)) {
-			/* No way to recover (from malloc failure) */
-			goto fail;
-		}
-		h->to_registered = 1;
-	}
-	if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
-				NULL, h)) {
-		/* No way to recover (from malloc failure) */
-		goto fail;
-	}
-	h->sd_registered = 1;
-	return h;
-
-fail:
-
-	/* Error */
-	httpread_destroy(h);
-	return NULL;
-}
-
-
-/* httpread_hdr_type_get -- When file is ready, returns header type. */
-enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
-{
-	return h->hdr_type;
-}
-
-
-/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
- * or possibly NULL (which would be an error).
- */
-char * httpread_uri_get(struct httpread *h)
-{
-	return h->uri;
-}
-
-
-/* httpread_reply_code_get -- When reply is ready, returns reply code */
-int httpread_reply_code_get(struct httpread *h)
-{
-	return h->reply_code;
-}
-
-
-/* httpread_length_get -- When file is ready, returns file length. */
-int httpread_length_get(struct httpread *h)
-{
-	return h->body_nbytes;
-}
-
-
-/* httpread_data_get -- When file is ready, returns file content
- * with null byte appened.
- * Might return NULL in some error condition.
- */
-void * httpread_data_get(struct httpread *h)
-{
-	return h->body ? h->body : "";
-}
-
-
-/* httpread_hdr_get -- When file is ready, returns header content
- * with null byte appended.
- * Might return NULL in some error condition.
- */
-char * httpread_hdr_get(struct httpread *h)
-{
-	return h->hdr;
-}
-
-
-/* httpread_hdr_line_get -- When file is ready, returns pointer
- * to line within header content matching the given tag
- * (after the tag itself and any spaces/tabs).
- *
- * The tag should end with a colon for reliable matching.
- *
- * If not found, returns NULL;
- */
-char * httpread_hdr_line_get(struct httpread *h, const char *tag)
-{
-	int tag_len = os_strlen(tag);
-	char *hdr = h->hdr;
-	hdr = os_strchr(hdr, '\n');
-	if (hdr == NULL)
-		return NULL;
-	hdr++;
-	for (;;) {
-		if (!os_strncasecmp(hdr, tag, tag_len)) {
-			hdr += tag_len;
-			while (*hdr == ' ' || *hdr == '\t')
-				hdr++;
-			return hdr;
-		}
-		hdr = os_strchr(hdr, '\n');
-		if (hdr == NULL)
-			return NULL;
-		hdr++;
-	}
-}

Copied: vendor/wpa/2.0/src/wps/httpread.c (from rev 9639, vendor/wpa/dist/src/wps/httpread.c)
===================================================================
--- vendor/wpa/2.0/src/wps/httpread.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/httpread.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,855 @@
+/*
+ * httpread - Manage reading file(s) from HTTP/TCP socket
+ * Author: Ted Merrill
+ * Copyright 2008 Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * The files are buffered via internal callbacks from eloop, then presented to
+ * an application callback routine when completely read into memory. May also
+ * be used if no file is expected but just to get the header, including HTTP
+ * replies (e.g. HTTP/1.1 200 OK etc.).
+ *
+ * This does not attempt to be an optimally efficient implementation, but does
+ * attempt to be of reasonably small size and memory consumption; assuming that
+ * only small files are to be read. A maximum file size is provided by
+ * application and enforced.
+ *
+ * It is assumed that the application does not expect any of the following:
+ * -- transfer encoding other than chunked
+ * -- trailer fields
+ * It is assumed that, even if the other side requested that the connection be
+ * kept open, that we will close it (thus HTTP messages sent by application
+ * should have the connection closed field); this is allowed by HTTP/1.1 and
+ * simplifies things for us.
+ *
+ * Other limitations:
+ * -- HTTP header may not exceed a hard-coded size.
+ *
+ * Notes:
+ * This code would be massively simpler without some of the new features of
+ * HTTP/1.1, especially chunked data.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "httpread.h"
+
+
+/* Tunable parameters */
+#define HTTPREAD_READBUF_SIZE 1024      /* read in chunks of this size */
+#define HTTPREAD_HEADER_MAX_SIZE 4096   /* max allowed for headers */
+#define HTTPREAD_BODYBUF_DELTA 4096     /* increase allocation by this */
+
+#if 0
+/* httpread_debug -- set this global variable > 0 e.g. from debugger
+ * to enable debugs (larger numbers for more debugs)
+ * Make this a #define of 0 to eliminate the debugging code.
+ */
+int httpread_debug = 99;
+#else
+#define httpread_debug 0        /* eliminates even the debugging code */
+#endif
+
+
+/* control instance -- actual definition (opaque to application)
+ */
+struct httpread {
+	/* information from creation */
+	int sd;         /* descriptor of TCP socket to read from */
+	void (*cb)(struct httpread *handle, void *cookie,
+		    enum httpread_event e);  /* call on event */
+	void *cookie;   /* pass to callback */
+	int max_bytes;          /* maximum file size else abort it */
+	int timeout_seconds;            /* 0 or total duration timeout period */
+
+	/* dynamically used information follows */
+	int sd_registered;      /* nonzero if we need to unregister socket */
+	int to_registered;      /* nonzero if we need to unregister timeout */
+
+	int got_hdr;            /* nonzero when header is finalized */
+	char hdr[HTTPREAD_HEADER_MAX_SIZE+1];   /* headers stored here */
+	int hdr_nbytes;
+
+	enum httpread_hdr_type hdr_type;
+	int version;            /* 1 if we've seen 1.1 */
+	int reply_code;         /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */
+	int got_content_length; /* true if we know content length for sure */
+	int content_length;     /* body length,  iff got_content_length */
+	int chunked;            /* nonzero for chunked data */
+	char *uri;
+
+	int got_body;           /* nonzero when body is finalized */
+	char *body;
+	int body_nbytes;
+	int body_alloc_nbytes;  /* amount allocated */
+
+	int got_file;           /* here when we are done */
+
+	/* The following apply if data is chunked: */
+	int in_chunk_data;      /* 0=in/at header, 1=in the data or tail*/
+	int chunk_start;        /* offset in body of chunk hdr or data */
+	int chunk_size;         /* data of chunk (not hdr or ending CRLF)*/
+	int in_trailer;         /* in header fields after data (chunked only)*/
+	enum trailer_state {
+		trailer_line_begin = 0,
+		trailer_empty_cr,       /* empty line + CR */
+		trailer_nonempty,
+		trailer_nonempty_cr,
+	} trailer_state;
+};
+
+
+/* Check words for equality, where words consist of graphical characters
+ * delimited by whitespace
+ * Returns nonzero if "equal" doing case insensitive comparison.
+ */
+static int word_eq(char *s1, char *s2)
+{
+	int c1;
+	int c2;
+	int end1 = 0;
+	int end2 = 0;
+	for (;;) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if (isalpha(c1) && isupper(c1))
+			c1 = tolower(c1);
+		if (isalpha(c2) && isupper(c2))
+			c2 = tolower(c2);
+		end1 = !isgraph(c1);
+		end2 = !isgraph(c2);
+		if (end1 || end2 || c1 != c2)
+			break;
+	}
+	return end1 && end2;  /* reached end of both words? */
+}
+
+
+/* convert hex to binary
+ * Requires that c have been previously tested true with isxdigit().
+ */
+static int hex_value(int c)
+{
+	if (isdigit(c))
+		return c - '0';
+	if (islower(c))
+		return 10 + c - 'a';
+	return 10 + c - 'A';
+}
+
+
+static void httpread_timeout_handler(void *eloop_data, void *user_ctx);
+
+/* httpread_destroy -- if h is non-NULL, clean up
+ * This must eventually be called by the application following
+ * call of the application's callback and may be called
+ * earlier if desired.
+ */
+void httpread_destroy(struct httpread *h)
+{
+	if (httpread_debug >= 10)
+		wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
+	if (!h)
+		return;
+
+	if (h->to_registered)
+		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+	h->to_registered = 0;
+	if (h->sd_registered)
+		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
+	h->sd_registered = 0;
+	os_free(h->body);
+	os_free(h->uri);
+	os_memset(h, 0, sizeof(*h));  /* aid debugging */
+	h->sd = -1;     /* aid debugging */
+	os_free(h);
+}
+
+
+/* httpread_timeout_handler -- called on excessive total duration
+ */
+static void httpread_timeout_handler(void *eloop_data, void *user_ctx)
+{
+	struct httpread *h = user_ctx;
+	wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h);
+	h->to_registered = 0;   /* is self-cancelling */
+	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT);
+}
+
+
+/* Analyze options only so far as is needed to correctly obtain the file.
+ * The application can look at the raw header to find other options.
+ */
+static int httpread_hdr_option_analyze(
+	struct httpread *h,
+	char *hbp       /* pointer to current line in header buffer */
+	)
+{
+	if (word_eq(hbp, "CONTENT-LENGTH:")) {
+		while (isgraph(*hbp))
+			hbp++;
+		while (*hbp == ' ' || *hbp == '\t')
+			hbp++;
+		if (!isdigit(*hbp))
+			return -1;
+		h->content_length = atol(hbp);
+		h->got_content_length = 1;
+		return 0;
+	}
+	if (word_eq(hbp, "TRANSFER_ENCODING:") ||
+	    word_eq(hbp, "TRANSFER-ENCODING:")) {
+		while (isgraph(*hbp))
+			hbp++;
+		while (*hbp == ' ' || *hbp == '\t')
+			hbp++;
+		/* There should (?) be no encodings of interest
+		 * other than chunked...
+		 */
+		if (word_eq(hbp, "CHUNKED")) {
+			h->chunked = 1;
+			h->in_chunk_data = 0;
+			/* ignore possible ;<parameters> */
+		}
+		return 0;
+	}
+	/* skip anything we don't know, which is a lot */
+	return 0;
+}
+
+
+static int httpread_hdr_analyze(struct httpread *h)
+{
+	char *hbp = h->hdr;      /* pointer into h->hdr */
+	int standard_first_line = 1;
+
+	/* First line is special */
+	h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN;
+	if (!isgraph(*hbp))
+		goto bad;
+	if (os_strncmp(hbp, "HTTP/", 5) == 0) {
+		h->hdr_type = HTTPREAD_HDR_TYPE_REPLY;
+		standard_first_line = 0;
+		hbp += 5;
+		if (hbp[0] == '1' && hbp[1] == '.' &&
+		    isdigit(hbp[2]) && hbp[2] != '0')
+			h->version = 1;
+		while (isgraph(*hbp))
+			hbp++;
+		while (*hbp == ' ' || *hbp == '\t')
+			hbp++;
+		if (!isdigit(*hbp))
+			goto bad;
+		h->reply_code = atol(hbp);
+	} else if (word_eq(hbp, "GET"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_GET;
+	else if (word_eq(hbp, "HEAD"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_HEAD;
+	else if (word_eq(hbp, "POST"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_POST;
+	else if (word_eq(hbp, "PUT"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_PUT;
+	else if (word_eq(hbp, "DELETE"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_DELETE;
+	else if (word_eq(hbp, "TRACE"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_TRACE;
+	else if (word_eq(hbp, "CONNECT"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT;
+	else if (word_eq(hbp, "NOTIFY"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY;
+	else if (word_eq(hbp, "M-SEARCH"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH;
+	else if (word_eq(hbp, "M-POST"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_M_POST;
+	else if (word_eq(hbp, "SUBSCRIBE"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE;
+	else if (word_eq(hbp, "UNSUBSCRIBE"))
+		h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE;
+	else {
+	}
+
+	if (standard_first_line) {
+		char *rawuri;
+		char *uri;
+		/* skip type */
+		while (isgraph(*hbp))
+			hbp++;
+		while (*hbp == ' ' || *hbp == '\t')
+			hbp++;
+		/* parse uri.
+		 * Find length, allocate memory for translated
+		 * copy, then translate by changing %<hex><hex>
+		 * into represented value.
+		 */
+		rawuri = hbp;
+		while (isgraph(*hbp))
+			hbp++;
+		h->uri = os_malloc((hbp - rawuri) + 1);
+		if (h->uri == NULL)
+			goto bad;
+		uri = h->uri;
+		while (rawuri < hbp) {
+			int c = *rawuri;
+			if (c == '%' &&
+			    isxdigit(rawuri[1]) && isxdigit(rawuri[2])) {
+				*uri++ = (hex_value(rawuri[1]) << 4) |
+					hex_value(rawuri[2]);
+				rawuri += 3;
+			} else {
+				*uri++ = c;
+				rawuri++;
+			}
+		}
+		*uri = 0;       /* null terminate */
+		while (isgraph(*hbp))
+			hbp++;
+		while (*hbp == ' ' || *hbp == '\t')
+			hbp++;
+		/* get version */
+		if (0 == strncmp(hbp, "HTTP/", 5)) {
+			hbp += 5;
+			if (hbp[0] == '1' && hbp[1] == '.' &&
+			    isdigit(hbp[2]) && hbp[2] != '0')
+				h->version = 1;
+		}
+	}
+	/* skip rest of line */
+	while (*hbp)
+		if (*hbp++ == '\n')
+			break;
+
+	/* Remainder of lines are options, in any order;
+	 * or empty line to terminate
+	 */
+	for (;;) {
+		/* Empty line to terminate */
+		if (hbp[0] == '\n' ||
+		    (hbp[0] == '\r' && hbp[1] == '\n'))
+			break;
+		if (!isgraph(*hbp))
+			goto bad;
+		if (httpread_hdr_option_analyze(h, hbp))
+			goto bad;
+		/* skip line */
+		while (*hbp)
+			if (*hbp++ == '\n')
+				break;
+	}
+
+	/* chunked overrides content-length always */
+	if (h->chunked)
+		h->got_content_length = 0;
+
+	/* For some types, we should not try to read a body
+	 * This is in addition to the application determining
+	 * that we should not read a body.
+	 */
+	switch (h->hdr_type) {
+	case HTTPREAD_HDR_TYPE_REPLY:
+		/* Some codes can have a body and some not.
+		 * For now, just assume that any other than 200
+		 * do not...
+		 */
+		if (h->reply_code != 200)
+			h->max_bytes = 0;
+		break;
+	case HTTPREAD_HDR_TYPE_GET:
+	case HTTPREAD_HDR_TYPE_HEAD:
+		/* in practice it appears that it is assumed
+		 * that GETs have a body length of 0... ?
+		 */
+		if (h->chunked == 0 && h->got_content_length == 0)
+			h->max_bytes = 0;
+		break;
+	case HTTPREAD_HDR_TYPE_POST:
+	case HTTPREAD_HDR_TYPE_PUT:
+	case HTTPREAD_HDR_TYPE_DELETE:
+	case HTTPREAD_HDR_TYPE_TRACE:
+	case HTTPREAD_HDR_TYPE_CONNECT:
+	case HTTPREAD_HDR_TYPE_NOTIFY:
+	case HTTPREAD_HDR_TYPE_M_SEARCH:
+	case HTTPREAD_HDR_TYPE_M_POST:
+	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
+	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
+	default:
+		break;
+	}
+
+	return 0;
+
+bad:
+	/* Error */
+	return -1;
+}
+
+
+/* httpread_read_handler -- called when socket ready to read
+ *
+ * Note: any extra data we read past end of transmitted file is ignored;
+ * if we were to support keeping connections open for multiple files then
+ * this would have to be addressed.
+ */
+static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+	struct httpread *h = sock_ctx;
+	int nread;
+	char *rbp;      /* pointer into read buffer */
+	char *hbp;      /* pointer into header buffer */
+	char *bbp;      /* pointer into body buffer */
+	char readbuf[HTTPREAD_READBUF_SIZE];  /* temp use to read into */
+
+	if (httpread_debug >= 20)
+		wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
+
+	/* read some at a time, then search for the interal
+	 * boundaries between header and data and etc.
+	 */
+	nread = read(h->sd, readbuf, sizeof(readbuf));
+	if (nread < 0)
+		goto bad;
+	if (nread == 0) {
+		/* end of transmission... this may be normal
+		 * or may be an error... in some cases we can't
+		 * tell which so we must assume it is normal then.
+		 */
+		if (!h->got_hdr) {
+			/* Must at least have completed header */
+			wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h);
+			goto bad;
+		}
+		if (h->chunked || h->got_content_length) {
+			/* Premature EOF; e.g. dropped connection */
+			wpa_printf(MSG_DEBUG,
+				   "httpread premature eof(%p) %d/%d",
+				   h, h->body_nbytes,
+				   h->content_length);
+			goto bad;
+		}
+		/* No explicit length, hopefully we have all the data
+		 * although dropped connections can cause false
+		 * end
+		 */
+		if (httpread_debug >= 10)
+			wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
+			h->got_body = 1;
+			goto got_file;
+	}
+	rbp = readbuf;
+
+	/* Header consists of text lines (terminated by both CR and LF)
+	 * and an empty line (CR LF only).
+	 */
+	if (!h->got_hdr) {
+		hbp = h->hdr + h->hdr_nbytes;
+		/* add to headers until:
+		 *      -- we run out of data in read buffer
+		 *      -- or, we run out of header buffer room
+		 *      -- or, we get double CRLF in headers
+		 */
+		for (;;) {
+			if (nread == 0)
+				goto get_more;
+			if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
+				goto bad;
+			}
+			*hbp++ = *rbp++;
+			nread--;
+			h->hdr_nbytes++;
+			if (h->hdr_nbytes >= 4 &&
+			    hbp[-1] == '\n' &&
+			    hbp[-2] == '\r' &&
+			    hbp[-3] == '\n' &&
+			    hbp[-4] == '\r' ) {
+				h->got_hdr = 1;
+				*hbp = 0;       /* null terminate */
+				break;
+			}
+		}
+		/* here we've just finished reading the header */
+		if (httpread_hdr_analyze(h)) {
+			wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h);
+			goto bad;
+		}
+		if (h->max_bytes == 0) {
+			if (httpread_debug >= 10)
+				wpa_printf(MSG_DEBUG,
+					   "httpread no body hdr end(%p)", h);
+			goto got_file;
+		}
+		if (h->got_content_length && h->content_length == 0) {
+			if (httpread_debug >= 10)
+				wpa_printf(MSG_DEBUG,
+					   "httpread zero content length(%p)",
+					   h);
+			goto got_file;
+		}
+	}
+
+	/* Certain types of requests never have data and so
+	 * must be specially recognized.
+	 */
+	if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) ||
+	    !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) ||
+	    !os_strncasecmp(h->hdr, "HEAD", 4) ||
+	    !os_strncasecmp(h->hdr, "GET", 3)) {
+		if (!h->got_body) {
+			if (httpread_debug >= 10)
+				wpa_printf(MSG_DEBUG,
+					   "httpread NO BODY for sp. type");
+		}
+		h->got_body = 1;
+		goto got_file;
+	}
+
+	/* Data can be just plain binary data, or if "chunked"
+	 * consists of chunks each with a header, ending with
+	 * an ending header.
+	 */
+	if (nread == 0)
+		goto get_more;
+	if (!h->got_body) {
+		/* Here to get (more of) body */
+		/* ensure we have enough room for worst case for body
+		 * plus a null termination character
+		 */
+		if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) {
+			char *new_body;
+			int new_alloc_nbytes;
+
+			if (h->body_nbytes >= h->max_bytes)
+				goto bad;
+			new_alloc_nbytes = h->body_alloc_nbytes +
+				HTTPREAD_BODYBUF_DELTA;
+			/* For content-length case, the first time
+			 * through we allocate the whole amount
+			 * we need.
+			 */
+			if (h->got_content_length &&
+			    new_alloc_nbytes < (h->content_length + 1))
+				new_alloc_nbytes = h->content_length + 1;
+			if ((new_body = os_realloc(h->body, new_alloc_nbytes))
+			    == NULL)
+				goto bad;
+
+			h->body = new_body;
+			h->body_alloc_nbytes = new_alloc_nbytes;
+		}
+		/* add bytes */
+		bbp = h->body + h->body_nbytes;
+		for (;;) {
+			int ncopy;
+			/* See if we need to stop */
+			if (h->chunked && h->in_chunk_data == 0) {
+				/* in chunk header */
+				char *cbp = h->body + h->chunk_start;
+				if (bbp-cbp >= 2 && bbp[-2] == '\r' &&
+				    bbp[-1] == '\n') {
+					/* end of chunk hdr line */
+					/* hdr line consists solely
+					 * of a hex numeral and CFLF
+					 */
+					if (!isxdigit(*cbp))
+						goto bad;
+					h->chunk_size = strtoul(cbp, NULL, 16);
+					/* throw away chunk header
+					 * so we have only real data
+					 */
+					h->body_nbytes = h->chunk_start;
+					bbp = cbp;
+					if (h->chunk_size == 0) {
+						/* end of chunking */
+						/* trailer follows */
+						h->in_trailer = 1;
+						if (httpread_debug >= 20)
+							wpa_printf(
+								MSG_DEBUG,
+								"httpread end chunks(%p)", h);
+						break;
+					}
+					h->in_chunk_data = 1;
+					/* leave chunk_start alone */
+				}
+			} else if (h->chunked) {
+				/* in chunk data */
+				if ((h->body_nbytes - h->chunk_start) ==
+				    (h->chunk_size + 2)) {
+					/* end of chunk reached,
+					 * new chunk starts
+					 */
+					/* check chunk ended w/ CRLF
+					 * which we'll throw away
+					 */
+					if (bbp[-1] == '\n' &&
+					    bbp[-2] == '\r') {
+					} else
+						goto bad;
+					h->body_nbytes -= 2;
+					bbp -= 2;
+					h->chunk_start = h->body_nbytes;
+					h->in_chunk_data = 0;
+					h->chunk_size = 0; /* just in case */
+				}
+			} else if (h->got_content_length &&
+				   h->body_nbytes >= h->content_length) {
+				h->got_body = 1;
+				if (httpread_debug >= 10)
+					wpa_printf(
+						MSG_DEBUG,
+						"httpread got content(%p)", h);
+				goto got_file;
+			}
+			if (nread <= 0)
+				break;
+			/* Now transfer. Optimize using memcpy where we can. */
+			if (h->chunked && h->in_chunk_data) {
+				/* copy up to remainder of chunk data
+				 * plus the required CR+LF at end
+				 */
+				ncopy = (h->chunk_start + h->chunk_size + 2) -
+					h->body_nbytes;
+			} else if (h->chunked) {
+				/*in chunk header -- don't optimize */
+				*bbp++ = *rbp++;
+				nread--;
+				h->body_nbytes++;
+				continue;
+			} else if (h->got_content_length) {
+				ncopy = h->content_length - h->body_nbytes;
+			} else {
+				ncopy = nread;
+			}
+			/* Note: should never be 0 */
+			if (ncopy > nread)
+				ncopy = nread;
+			os_memcpy(bbp, rbp, ncopy);
+			bbp += ncopy;
+			h->body_nbytes += ncopy;
+			rbp += ncopy;
+			nread -= ncopy;
+		}       /* body copy loop */
+	}       /* !got_body */
+	if (h->chunked && h->in_trailer) {
+		/* If "chunked" then there is always a trailer,
+		 * consisting of zero or more non-empty lines
+		 * ending with CR LF and then an empty line w/ CR LF.
+		 * We do NOT support trailers except to skip them --
+		 * this is supported (generally) by the http spec.
+		 */
+		bbp = h->body + h->body_nbytes;
+		for (;;) {
+			int c;
+			if (nread <= 0)
+				break;
+			c = *rbp++;
+			nread--;
+			switch (h->trailer_state) {
+			case trailer_line_begin:
+				if (c == '\r')
+					h->trailer_state = trailer_empty_cr;
+				else
+					h->trailer_state = trailer_nonempty;
+				break;
+			case trailer_empty_cr:
+				/* end empty line */
+				if (c == '\n') {
+					h->trailer_state = trailer_line_begin;
+					h->in_trailer = 0;
+					if (httpread_debug >= 10)
+						wpa_printf(
+							MSG_DEBUG,
+							"httpread got content(%p)", h);
+					h->got_body = 1;
+					goto got_file;
+				}
+				h->trailer_state = trailer_nonempty;
+				break;
+			case trailer_nonempty:
+				if (c == '\r')
+					h->trailer_state = trailer_nonempty_cr;
+				break;
+			case trailer_nonempty_cr:
+				if (c == '\n')
+					h->trailer_state = trailer_line_begin;
+				else
+					h->trailer_state = trailer_nonempty;
+				break;
+			}
+		}
+	}
+	goto get_more;
+
+bad:
+	/* Error */
+	wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h);
+	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR);
+	return;
+
+get_more:
+	return;
+
+got_file:
+	if (httpread_debug >= 10)
+		wpa_printf(MSG_DEBUG,
+			   "httpread got file %d bytes type %d",
+			   h->body_nbytes, h->hdr_type);
+	/* Null terminate for convenience of some applications */
+	if (h->body)
+		h->body[h->body_nbytes] = 0; /* null terminate */
+	h->got_file = 1;
+	/* Assume that we do NOT support keeping connection alive,
+	 * and just in case somehow we don't get destroyed right away,
+	 * unregister now.
+	 */
+	if (h->sd_registered)
+		eloop_unregister_sock(h->sd, EVENT_TYPE_READ);
+	h->sd_registered = 0;
+	/* The application can destroy us whenever they feel like...
+	 * cancel timeout.
+	 */
+	if (h->to_registered)
+		eloop_cancel_timeout(httpread_timeout_handler, NULL, h);
+	h->to_registered = 0;
+	(*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY);
+}
+
+
+/* httpread_create -- start a new reading session making use of eloop.
+ * The new instance will use the socket descriptor for reading (until
+ * it gets a file and not after) but will not close the socket, even
+ * when the instance is destroyed (the application must do that).
+ * Return NULL on error.
+ *
+ * Provided that httpread_create successfully returns a handle,
+ * the callback fnc is called to handle httpread_event events.
+ * The caller should do destroy on any errors or unknown events.
+ *
+ * Pass max_bytes == 0 to not read body at all (required for e.g.
+ * reply to HEAD request).
+ */
+struct httpread * httpread_create(
+	int sd,	 /* descriptor of TCP socket to read from */
+	void (*cb)(struct httpread *handle, void *cookie,
+		   enum httpread_event e),  /* call on event */
+	void *cookie,    /* pass to callback */
+	int max_bytes,	  /* maximum body size else abort it */
+	int timeout_seconds     /* 0; or total duration timeout period */
+	)
+{
+	struct httpread *h = NULL;
+
+	h = os_zalloc(sizeof(*h));
+	if (h == NULL)
+		goto fail;
+	h->sd = sd;
+	h->cb = cb;
+	h->cookie = cookie;
+	h->max_bytes = max_bytes;
+	h->timeout_seconds = timeout_seconds;
+
+	if (timeout_seconds > 0) {
+		if (eloop_register_timeout(timeout_seconds, 0,
+					   httpread_timeout_handler,
+					   NULL, h)) {
+			/* No way to recover (from malloc failure) */
+			goto fail;
+		}
+		h->to_registered = 1;
+	}
+	if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler,
+				NULL, h)) {
+		/* No way to recover (from malloc failure) */
+		goto fail;
+	}
+	h->sd_registered = 1;
+	return h;
+
+fail:
+
+	/* Error */
+	httpread_destroy(h);
+	return NULL;
+}
+
+
+/* httpread_hdr_type_get -- When file is ready, returns header type. */
+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h)
+{
+	return h->hdr_type;
+}
+
+
+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
+ * or possibly NULL (which would be an error).
+ */
+char * httpread_uri_get(struct httpread *h)
+{
+	return h->uri;
+}
+
+
+/* httpread_reply_code_get -- When reply is ready, returns reply code */
+int httpread_reply_code_get(struct httpread *h)
+{
+	return h->reply_code;
+}
+
+
+/* httpread_length_get -- When file is ready, returns file length. */
+int httpread_length_get(struct httpread *h)
+{
+	return h->body_nbytes;
+}
+
+
+/* httpread_data_get -- When file is ready, returns file content
+ * with null byte appened.
+ * Might return NULL in some error condition.
+ */
+void * httpread_data_get(struct httpread *h)
+{
+	return h->body ? h->body : "";
+}
+
+
+/* httpread_hdr_get -- When file is ready, returns header content
+ * with null byte appended.
+ * Might return NULL in some error condition.
+ */
+char * httpread_hdr_get(struct httpread *h)
+{
+	return h->hdr;
+}
+
+
+/* httpread_hdr_line_get -- When file is ready, returns pointer
+ * to line within header content matching the given tag
+ * (after the tag itself and any spaces/tabs).
+ *
+ * The tag should end with a colon for reliable matching.
+ *
+ * If not found, returns NULL;
+ */
+char * httpread_hdr_line_get(struct httpread *h, const char *tag)
+{
+	int tag_len = os_strlen(tag);
+	char *hdr = h->hdr;
+	hdr = os_strchr(hdr, '\n');
+	if (hdr == NULL)
+		return NULL;
+	hdr++;
+	for (;;) {
+		if (!os_strncasecmp(hdr, tag, tag_len)) {
+			hdr += tag_len;
+			while (*hdr == ' ' || *hdr == '\t')
+				hdr++;
+			return hdr;
+		}
+		hdr = os_strchr(hdr, '\n');
+		if (hdr == NULL)
+			return NULL;
+		hdr++;
+	}
+}

Deleted: vendor/wpa/2.0/src/wps/httpread.h
===================================================================
--- vendor/wpa/dist/src/wps/httpread.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/httpread.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,123 +0,0 @@
-/*
- * httpread - Manage reading file(s) from HTTP/TCP socket
- * Author: Ted Merrill
- * Copyright 2008 Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef HTTPREAD_H
-#define HTTPREAD_H
-
-/* event types (passed to callback) */
-enum httpread_event {
-	HTTPREAD_EVENT_FILE_READY = 1,        /* including reply ready */
-	HTTPREAD_EVENT_TIMEOUT = 2,
-	HTTPREAD_EVENT_ERROR = 3      /* misc. error, esp malloc error */
-};
-
-
-/* header type detected
- * available to callback via call to httpread_reply_code_get()
- */
-enum httpread_hdr_type {
-	HTTPREAD_HDR_TYPE_UNKNOWN = 0,      /* none of the following */
-	HTTPREAD_HDR_TYPE_REPLY = 1,        /* hdr begins w/ HTTP/ */
-	HTTPREAD_HDR_TYPE_GET = 2,          /* hdr begins with GET<sp> */
-	HTTPREAD_HDR_TYPE_HEAD = 3,         /* hdr begins with HEAD<sp> */
-	HTTPREAD_HDR_TYPE_POST = 4,         /* hdr begins with POST<sp> */
-	HTTPREAD_HDR_TYPE_PUT = 5,          /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_DELETE = 6,       /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_TRACE = 7,        /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_CONNECT = 8,      /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_NOTIFY = 9,       /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_M_SEARCH = 10,    /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_M_POST = 11,      /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_SUBSCRIBE = 12,   /* hdr begins with ... */
-	HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */
-
-	HTTPREAD_N_HDR_TYPES    /* keep last */
-};
-
-
-/* control instance -- opaque struct declaration
- */
-struct httpread;
-
-
-/* httpread_destroy -- if h is non-NULL, clean up
- * This must eventually be called by the application following
- * call of the application's callback and may be called
- * earlier if desired.
- */
-void httpread_destroy(struct httpread *h);
-
-/* httpread_create -- start a new reading session making use of eloop.
- * The new instance will use the socket descriptor for reading (until
- * it gets a file and not after) but will not close the socket, even
- * when the instance is destroyed (the application must do that).
- * Return NULL on error.
- *
- * Provided that httpread_create successfully returns a handle,
- * the callback fnc is called to handle httpread_event events.
- * The caller should do destroy on any errors or unknown events.
- *
- * Pass max_bytes == 0 to not read body at all (required for e.g.
- * reply to HEAD request).
- */
-struct httpread * httpread_create(
-	int sd,         /* descriptor of TCP socket to read from */
-	void (*cb)(struct httpread *handle, void *cookie,
-		    enum httpread_event e),  /* call on event */
-	void *cookie,    /* pass to callback */
-	int max_bytes,          /* maximum file size else abort it */
-	int timeout_seconds     /* 0; or total duration timeout period */
-	);
-
-/* httpread_hdr_type_get -- When file is ready, returns header type.
- */
-enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h);
-
-
-/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
- * or possibly NULL (which would be an error).
- */
-char *httpread_uri_get(struct httpread *h);
-
-/* httpread_reply_code_get -- When reply is ready, returns reply code */
-int httpread_reply_code_get(struct httpread *h);
-
-
-/* httpread_length_get -- When file is ready, returns file length. */
-int httpread_length_get(struct httpread *h);
-
-/* httpread_data_get -- When file is ready, returns file content
- * with null byte appened.
- * Might return NULL in some error condition.
- */
-void * httpread_data_get(struct httpread *h);
-
-/* httpread_hdr_get -- When file is ready, returns header content
- * with null byte appended.
- * Might return NULL in some error condition.
- */
-char * httpread_hdr_get(struct httpread *h);
-
-/* httpread_hdr_line_get -- When file is ready, returns pointer
- * to line within header content matching the given tag
- * (after the tag itself and any spaces/tabs).
- *
- * The tag should end with a colon for reliable matching.
- *
- * If not found, returns NULL;
- */
-char * httpread_hdr_line_get(struct httpread *h, const char *tag);
-
-#endif /* HTTPREAD_H */

Copied: vendor/wpa/2.0/src/wps/httpread.h (from rev 9639, vendor/wpa/dist/src/wps/httpread.h)
===================================================================
--- vendor/wpa/2.0/src/wps/httpread.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/httpread.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,117 @@
+/*
+ * httpread - Manage reading file(s) from HTTP/TCP socket
+ * Author: Ted Merrill
+ * Copyright 2008 Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HTTPREAD_H
+#define HTTPREAD_H
+
+/* event types (passed to callback) */
+enum httpread_event {
+	HTTPREAD_EVENT_FILE_READY = 1,        /* including reply ready */
+	HTTPREAD_EVENT_TIMEOUT = 2,
+	HTTPREAD_EVENT_ERROR = 3      /* misc. error, esp malloc error */
+};
+
+
+/* header type detected
+ * available to callback via call to httpread_reply_code_get()
+ */
+enum httpread_hdr_type {
+	HTTPREAD_HDR_TYPE_UNKNOWN = 0,      /* none of the following */
+	HTTPREAD_HDR_TYPE_REPLY = 1,        /* hdr begins w/ HTTP/ */
+	HTTPREAD_HDR_TYPE_GET = 2,          /* hdr begins with GET<sp> */
+	HTTPREAD_HDR_TYPE_HEAD = 3,         /* hdr begins with HEAD<sp> */
+	HTTPREAD_HDR_TYPE_POST = 4,         /* hdr begins with POST<sp> */
+	HTTPREAD_HDR_TYPE_PUT = 5,          /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_DELETE = 6,       /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_TRACE = 7,        /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_CONNECT = 8,      /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_NOTIFY = 9,       /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_M_SEARCH = 10,    /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_M_POST = 11,      /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_SUBSCRIBE = 12,   /* hdr begins with ... */
+	HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */
+
+	HTTPREAD_N_HDR_TYPES    /* keep last */
+};
+
+
+/* control instance -- opaque struct declaration
+ */
+struct httpread;
+
+
+/* httpread_destroy -- if h is non-NULL, clean up
+ * This must eventually be called by the application following
+ * call of the application's callback and may be called
+ * earlier if desired.
+ */
+void httpread_destroy(struct httpread *h);
+
+/* httpread_create -- start a new reading session making use of eloop.
+ * The new instance will use the socket descriptor for reading (until
+ * it gets a file and not after) but will not close the socket, even
+ * when the instance is destroyed (the application must do that).
+ * Return NULL on error.
+ *
+ * Provided that httpread_create successfully returns a handle,
+ * the callback fnc is called to handle httpread_event events.
+ * The caller should do destroy on any errors or unknown events.
+ *
+ * Pass max_bytes == 0 to not read body at all (required for e.g.
+ * reply to HEAD request).
+ */
+struct httpread * httpread_create(
+	int sd,         /* descriptor of TCP socket to read from */
+	void (*cb)(struct httpread *handle, void *cookie,
+		    enum httpread_event e),  /* call on event */
+	void *cookie,    /* pass to callback */
+	int max_bytes,          /* maximum file size else abort it */
+	int timeout_seconds     /* 0; or total duration timeout period */
+	);
+
+/* httpread_hdr_type_get -- When file is ready, returns header type.
+ */
+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h);
+
+
+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI
+ * or possibly NULL (which would be an error).
+ */
+char *httpread_uri_get(struct httpread *h);
+
+/* httpread_reply_code_get -- When reply is ready, returns reply code */
+int httpread_reply_code_get(struct httpread *h);
+
+
+/* httpread_length_get -- When file is ready, returns file length. */
+int httpread_length_get(struct httpread *h);
+
+/* httpread_data_get -- When file is ready, returns file content
+ * with null byte appened.
+ * Might return NULL in some error condition.
+ */
+void * httpread_data_get(struct httpread *h);
+
+/* httpread_hdr_get -- When file is ready, returns header content
+ * with null byte appended.
+ * Might return NULL in some error condition.
+ */
+char * httpread_hdr_get(struct httpread *h);
+
+/* httpread_hdr_line_get -- When file is ready, returns pointer
+ * to line within header content matching the given tag
+ * (after the tag itself and any spaces/tabs).
+ *
+ * The tag should end with a colon for reliable matching.
+ *
+ * If not found, returns NULL;
+ */
+char * httpread_hdr_line_get(struct httpread *h, const char *tag);
+
+#endif /* HTTPREAD_H */

Deleted: vendor/wpa/2.0/src/wps/ndef.c
===================================================================
--- vendor/wpa/dist/src/wps/ndef.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/ndef.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,175 +0,0 @@
-/*
- * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup
- *   Reference is "NFCForum-TS-NDEF_1.0 2006-07-24".
- * Copyright (c) 2009, Masashi Honma <honma at ictec.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-#include "wps/wps.h"
-#include "wps/wps_i.h"
-
-#define FLAG_MESSAGE_BEGIN (1 << 7)
-#define FLAG_MESSAGE_END (1 << 6)
-#define FLAG_CHUNK (1 << 5)
-#define FLAG_SHORT_RECORD (1 << 4)
-#define FLAG_ID_LENGTH_PRESENT (1 << 3)
-#define FLAG_TNF_RFC2046 (0x02)
-
-struct ndef_record {
-	u8 *type;
-	u8 *id;
-	u8 *payload;
-	u8 type_length;
-	u8 id_length;
-	u32 payload_length;
-	u32 total_length;
-};
-
-static char wifi_handover_type[] = "application/vnd.wfa.wsc";
-
-static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record)
-{
-	u8 *pos = data + 1;
-
-	if (size < 2)
-		return -1;
-	record->type_length = *pos++;
-	if (data[0] & FLAG_SHORT_RECORD) {
-		if (size < 3)
-			return -1;
-		record->payload_length = *pos++;
-	} else {
-		if (size < 6)
-			return -1;
-		record->payload_length = ntohl(*(u32 *)pos);
-		pos += sizeof(u32);
-	}
-
-	if (data[0] & FLAG_ID_LENGTH_PRESENT) {
-		if ((int) size < pos - data + 1)
-			return -1;
-		record->id_length = *pos++;
-	} else
-		record->id_length = 0;
-
-	record->type = record->type_length == 0 ? NULL : pos;
-	pos += record->type_length;
-
-	record->id = record->id_length == 0 ? NULL : pos;
-	pos += record->id_length;
-
-	record->payload = record->payload_length == 0 ? NULL : pos;
-	pos += record->payload_length;
-
-	record->total_length = pos - data;
-	if (record->total_length > size)
-		return -1;
-	return 0;
-}
-
-
-static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
-					  int (*filter)(struct ndef_record *))
-{
-	struct ndef_record record;
-	int len = wpabuf_len(buf);
-	u8 *data = wpabuf_mhead(buf);
-
-	while (len > 0) {
-		if (ndef_parse_record(data, len, &record) < 0) {
-			wpa_printf(MSG_ERROR, "NDEF : Failed to parse");
-			return NULL;
-		}
-		if (filter == NULL || filter(&record))
-			return wpabuf_alloc_copy(record.payload,
-						 record.payload_length);
-		data += record.total_length;
-		len -= record.total_length;
-	}
-	wpa_printf(MSG_ERROR, "NDEF : Record not found");
-	return NULL;
-}
-
-
-static struct wpabuf * ndef_build_record(u8 flags, void *type,
-					 u8 type_length, void *id,
-					 u8 id_length, void *payload,
-					 u32 payload_length)
-{
-	struct wpabuf *record;
-	size_t total_len;
-	int short_record;
-	u8 local_flag;
-
-	short_record = payload_length < 256 ? 1 : 0;
-
-	total_len = 2; /* flag + type length */
-	/* payload length */
-	total_len += short_record ? sizeof(u8) : sizeof(u32);
-	if (id_length > 0)
-		total_len += 1;
-	total_len += type_length + id_length + payload_length;
-	record = wpabuf_alloc(total_len);
-	if (record == NULL) {
-		wpa_printf(MSG_ERROR, "NDEF : Failed to allocate "
-			   "record for build");
-		return NULL;
-	}
-
-	local_flag = flags;
-	if (id_length > 0)
-		local_flag |= FLAG_ID_LENGTH_PRESENT;
-	if (short_record)
-		local_flag |= FLAG_SHORT_RECORD;
-	wpabuf_put_u8(record, local_flag);
-
-	wpabuf_put_u8(record, type_length);
-
-	if (short_record)
-		wpabuf_put_u8(record, payload_length);
-	else
-		wpabuf_put_be32(record, payload_length);
-
-	if (id_length > 0)
-		wpabuf_put_u8(record, id_length);
-	wpabuf_put_data(record, type, type_length);
-	wpabuf_put_data(record, id, id_length);
-	wpabuf_put_data(record, payload, payload_length);
-	return record;
-}
-
-
-static int wifi_filter(struct ndef_record *record)
-{
-	if (record->type_length != os_strlen(wifi_handover_type))
-		return 0;
-	if (os_memcmp(record->type, wifi_handover_type,
-		      os_strlen(wifi_handover_type)) != 0)
-		return 0;
-	return 1;
-}
-
-
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf)
-{
-	return ndef_parse_records(buf, wifi_filter);
-}
-
-
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf)
-{
-	return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
-				 FLAG_TNF_RFC2046, wifi_handover_type,
-				 os_strlen(wifi_handover_type), NULL, 0,
-				 wpabuf_mhead(buf), wpabuf_len(buf));
-}

Copied: vendor/wpa/2.0/src/wps/ndef.c (from rev 9639, vendor/wpa/dist/src/wps/ndef.c)
===================================================================
--- vendor/wpa/2.0/src/wps/ndef.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/ndef.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,245 @@
+/*
+ * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup
+ *   Reference is "NFCForum-TS-NDEF_1.0 2006-07-24".
+ * Copyright (c) 2009-2012, Masashi Honma <masashi.honma at 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 "wps/wps.h"
+
+#define FLAG_MESSAGE_BEGIN (1 << 7)
+#define FLAG_MESSAGE_END (1 << 6)
+#define FLAG_CHUNK (1 << 5)
+#define FLAG_SHORT_RECORD (1 << 4)
+#define FLAG_ID_LENGTH_PRESENT (1 << 3)
+#define FLAG_TNF_NFC_FORUM (0x01)
+#define FLAG_TNF_RFC2046 (0x02)
+
+struct ndef_record {
+	const u8 *type;
+	const u8 *id;
+	const u8 *payload;
+	u8 type_length;
+	u8 id_length;
+	u32 payload_length;
+	u32 total_length;
+};
+
+static char wifi_handover_type[] = "application/vnd.wfa.wsc";
+
+static int ndef_parse_record(const u8 *data, u32 size,
+			     struct ndef_record *record)
+{
+	const u8 *pos = data + 1;
+
+	if (size < 2)
+		return -1;
+	record->type_length = *pos++;
+	if (data[0] & FLAG_SHORT_RECORD) {
+		if (size < 3)
+			return -1;
+		record->payload_length = *pos++;
+	} else {
+		if (size < 6)
+			return -1;
+		record->payload_length = ntohl(*(u32 *)pos);
+		pos += sizeof(u32);
+	}
+
+	if (data[0] & FLAG_ID_LENGTH_PRESENT) {
+		if ((int) size < pos - data + 1)
+			return -1;
+		record->id_length = *pos++;
+	} else
+		record->id_length = 0;
+
+	record->type = record->type_length == 0 ? NULL : pos;
+	pos += record->type_length;
+
+	record->id = record->id_length == 0 ? NULL : pos;
+	pos += record->id_length;
+
+	record->payload = record->payload_length == 0 ? NULL : pos;
+	pos += record->payload_length;
+
+	record->total_length = pos - data;
+	if (record->total_length > size)
+		return -1;
+	return 0;
+}
+
+
+static struct wpabuf * ndef_parse_records(const struct wpabuf *buf,
+					  int (*filter)(struct ndef_record *))
+{
+	struct ndef_record record;
+	int len = wpabuf_len(buf);
+	const u8 *data = wpabuf_head(buf);
+
+	while (len > 0) {
+		if (ndef_parse_record(data, len, &record) < 0) {
+			wpa_printf(MSG_ERROR, "NDEF : Failed to parse");
+			return NULL;
+		}
+		if (filter == NULL || filter(&record))
+			return wpabuf_alloc_copy(record.payload,
+						 record.payload_length);
+		data += record.total_length;
+		len -= record.total_length;
+	}
+	wpa_printf(MSG_ERROR, "NDEF : Record not found");
+	return NULL;
+}
+
+
+static struct wpabuf * ndef_build_record(u8 flags, void *type,
+					 u8 type_length, void *id,
+					 u8 id_length,
+					 const struct wpabuf *payload)
+{
+	struct wpabuf *record;
+	size_t total_len;
+	int short_record;
+	u8 local_flag;
+	size_t payload_length = wpabuf_len(payload);
+
+	short_record = payload_length < 256 ? 1 : 0;
+
+	total_len = 2; /* flag + type length */
+	/* payload length */
+	total_len += short_record ? sizeof(u8) : sizeof(u32);
+	if (id_length > 0)
+		total_len += 1;
+	total_len += type_length + id_length + payload_length;
+	record = wpabuf_alloc(total_len);
+	if (record == NULL) {
+		wpa_printf(MSG_ERROR, "NDEF : Failed to allocate "
+			   "record for build");
+		return NULL;
+	}
+
+	local_flag = flags;
+	if (id_length > 0)
+		local_flag |= FLAG_ID_LENGTH_PRESENT;
+	if (short_record)
+		local_flag |= FLAG_SHORT_RECORD;
+	wpabuf_put_u8(record, local_flag);
+
+	wpabuf_put_u8(record, type_length);
+
+	if (short_record)
+		wpabuf_put_u8(record, payload_length);
+	else
+		wpabuf_put_be32(record, payload_length);
+
+	if (id_length > 0)
+		wpabuf_put_u8(record, id_length);
+	wpabuf_put_data(record, type, type_length);
+	wpabuf_put_data(record, id, id_length);
+	wpabuf_put_buf(record, payload);
+	return record;
+}
+
+
+static int wifi_filter(struct ndef_record *record)
+{
+	if (record->type_length != os_strlen(wifi_handover_type))
+		return 0;
+	if (os_memcmp(record->type, wifi_handover_type,
+		      os_strlen(wifi_handover_type)) != 0)
+		return 0;
+	return 1;
+}
+
+
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf)
+{
+	return ndef_parse_records(buf, wifi_filter);
+}
+
+
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf)
+{
+	return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END |
+				 FLAG_TNF_RFC2046, wifi_handover_type,
+				 os_strlen(wifi_handover_type), NULL, 0, buf);
+}
+
+
+struct wpabuf * ndef_build_wifi_hr(void)
+{
+	struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
+	struct wpabuf *carrier, *hc;
+
+	rn = wpabuf_alloc(2);
+	if (rn == NULL)
+		return NULL;
+	wpabuf_put_be16(rn, os_random() & 0xffff);
+
+	cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
+			       NULL, 0, rn);
+	wpabuf_free(rn);
+
+	if (cr == NULL)
+		return NULL;
+
+	ac_payload = wpabuf_alloc(4);
+	if (ac_payload == NULL) {
+		wpabuf_free(cr);
+		return NULL;
+	}
+	wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
+	wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
+	wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
+	wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
+
+	ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
+			       NULL, 0, ac_payload);
+	wpabuf_free(ac_payload);
+	if (ac == NULL) {
+		wpabuf_free(cr);
+		return NULL;
+	}
+
+	hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
+	if (hr_payload == NULL) {
+		wpabuf_free(cr);
+		wpabuf_free(ac);
+		return NULL;
+	}
+
+	wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
+	wpabuf_put_buf(hr_payload, cr);
+	wpabuf_put_buf(hr_payload, ac);
+	wpabuf_free(cr);
+	wpabuf_free(ac);
+
+	hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
+			       NULL, 0, hr_payload);
+	wpabuf_free(hr_payload);
+	if (hr == NULL)
+		return NULL;
+
+	carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+	if (carrier == NULL) {
+		wpabuf_free(hr);
+		return NULL;
+	}
+	wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+	wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+	wpabuf_put_str(carrier, wifi_handover_type);
+
+	hc = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+			       "0", 1, carrier);
+	wpabuf_free(carrier);
+	if (hc == NULL) {
+		wpabuf_free(hr);
+		return NULL;
+	}
+
+	return wpabuf_concat(hr, hc);
+}

Deleted: vendor/wpa/2.0/src/wps/upnp_xml.c
===================================================================
--- vendor/wpa/dist/src/wps/upnp_xml.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/upnp_xml.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,252 +0,0 @@
-/*
- * UPnP XML helper routines
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "http.h"
-#include "upnp_xml.h"
-
-
-/*
- * XML parsing and formatting
- *
- * XML is a markup language based on unicode; usually (and in our case,
- * always!) based on utf-8. utf-8 uses a variable number of bytes per
- * character. utf-8 has the advantage that all non-ASCII unicode characters are
- * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII
- * characters are single ascii bytes, thus we can use typical text processing.
- *
- * (One other interesting thing about utf-8 is that it is possible to look at
- * any random byte and determine if it is the first byte of a character as
- * versus a continuation byte).
- *
- * The base syntax of XML uses a few ASCII punctionation characters; any
- * characters that would appear in the payload data are rewritten using
- * sequences, e.g., & for ampersand(&) and &lt for left angle bracket (<).
- * Five such escapes total (more can be defined but that does not apply to our
- * case). Thus we can safely parse for angle brackets etc.
- *
- * XML describes tree structures of tagged data, with each element beginning
- * with an opening tag <label> and ending with a closing tag </label> with
- * matching label. (There is also a self-closing tag <label/> which is supposed
- * to be equivalent to <label></label>, i.e., no payload, but we are unlikely
- * to see it for our purpose).
- *
- * Actually the opening tags are a little more complicated because they can
- * contain "attributes" after the label (delimited by ascii space or tab chars)
- * of the form attribute_label="value" or attribute_label='value'; as it turns
- * out we do not have to read any of these attributes, just ignore them.
- *
- * Labels are any sequence of chars other than space, tab, right angle bracket
- * (and ?), but may have an inner structure of <namespace><colon><plain_label>.
- * As it turns out, we can ignore the namespaces, in fact we can ignore the
- * entire tree hierarchy, because the plain labels we are looking for will be
- * unique (not in general, but for this application). We do however have to be
- * careful to skip over the namespaces.
- *
- * In generating XML we have to be more careful, but that is easy because
- * everything we do is pretty canned. The only real care to take is to escape
- * any special chars in our payload.
- */
-
-/**
- * xml_next_tag - Advance to next tag
- * @in: Input
- * @out: OUT: start of tag just after '<'
- * @out_tagname: OUT: start of name of tag, skipping namespace
- * @end: OUT: one after tag
- * Returns: 0 on success, 1 on failure
- *
- * A tag has form:
- *     <left angle bracket><...><right angle bracket>
- * Within the angle brackets, there is an optional leading forward slash (which
- * makes the tag an ending tag), then an optional leading label (followed by
- * colon) and then the tag name itself.
- *
- * Note that angle brackets present in the original data must have been encoded
- * as < and > so they will not trouble us.
- */
-static int xml_next_tag(const char *in, const char **out,
-			const char **out_tagname, const char **end)
-{
-	while (*in && *in != '<')
-		in++;
-	if (*in != '<')
-		return 1;
-	*out = ++in;
-	if (*in == '/')
-		in++;
-	*out_tagname = in; /* maybe */
-	while (isalnum(*in) || *in == '-')
-		in++;
-	if (*in == ':')
-		*out_tagname = ++in;
-	while (*in && *in != '>')
-		in++;
-	if (*in != '>')
-		return 1;
-	*end = ++in;
-	return 0;
-}
-
-
-/* xml_data_encode -- format data for xml file, escaping special characters.
- *
- * Note that we assume we are using utf8 both as input and as output!
- * In utf8, characters may be classed as follows:
- *     0xxxxxxx(2) -- 1 byte ascii char
- *     11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80
- *         110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here)
- *         1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here)
- *         11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here)
- *      10xxxxxx(2) -- extension byte (6 payload bits per byte)
- *      Some values implied by the above are however illegal because they
- *      do not represent unicode chars or are not the shortest encoding.
- * Actually, we can almost entirely ignore the above and just do
- * text processing same as for ascii text.
- *
- * XML is written with arbitrary unicode characters, except that five
- * characters have special meaning and so must be escaped where they
- * appear in payload data... which we do here.
- */
-void xml_data_encode(struct wpabuf *buf, const char *data, int len)
-{
-	int i;
-	for (i = 0; i < len; i++) {
-		u8 c = ((u8 *) data)[i];
-		if (c == '<') {
-			wpabuf_put_str(buf, "<");
-			continue;
-		}
-		if (c == '>') {
-			wpabuf_put_str(buf, ">");
-			continue;
-		}
-		if (c == '&') {
-			wpabuf_put_str(buf, "&");
-			continue;
-		}
-		if (c == '\'') {
-			wpabuf_put_str(buf, "'");
-			continue;
-		}
-		if (c == '"') {
-			wpabuf_put_str(buf, """);
-			continue;
-		}
-		/*
-		 * We could try to represent control characters using the
-		 * sequence: &#x; where x is replaced by a hex numeral, but not
-		 * clear why we would do this.
-		 */
-		wpabuf_put_u8(buf, c);
-	}
-}
-
-
-/* xml_add_tagged_data -- format tagged data as a new xml line.
- *
- * tag must not have any special chars.
- * data may have special chars, which are escaped.
- */
-void xml_add_tagged_data(struct wpabuf *buf, const char *tag, const char *data)
-{
-	wpabuf_printf(buf, "<%s>", tag);
-	xml_data_encode(buf, data, os_strlen(data));
-	wpabuf_printf(buf, "</%s>\n", tag);
-}
-
-
-/* A POST body looks something like (per upnp spec):
- * <?xml version="1.0"?>
- * <s:Envelope
- *     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
- *     s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
- *   <s:Body>
- *     <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
- *       <argumentName>in arg value</argumentName>
- *       other in args and their values go here, if any
- *     </u:actionName>
- *   </s:Body>
- * </s:Envelope>
- *
- * where :
- *      s: might be some other namespace name followed by colon
- *      u: might be some other namespace name followed by colon
- *      actionName will be replaced according to action requested
- *      schema following actionName will be WFA scheme instead
- *      argumentName will be actual argument name
- *      (in arg value) will be actual argument value
- */
-char * xml_get_first_item(const char *doc, const char *item)
-{
-	const char *match = item;
-	int match_len = os_strlen(item);
-	const char *tag, *tagname, *end;
-	char *value;
-
-	/*
-	 * This is crude: ignore any possible tag name conflicts and go right
-	 * to the first tag of this name. This should be ok for the limited
-	 * domain of UPnP messages.
-	 */
-	for (;;) {
-		if (xml_next_tag(doc, &tag, &tagname, &end))
-			return NULL;
-		doc = end;
-		if (!os_strncasecmp(tagname, match, match_len) &&
-		    *tag != '/' &&
-		    (tagname[match_len] == '>' ||
-		     !isgraph(tagname[match_len]))) {
-			break;
-		}
-	}
-	end = doc;
-	while (*end && *end != '<')
-		end++;
-	value = os_zalloc(1 + (end - doc));
-	if (value == NULL)
-		return NULL;
-	os_memcpy(value, doc, end - doc);
-	return value;
-}
-
-
-struct wpabuf * xml_get_base64_item(const char *data, const char *name,
-				    enum http_reply_code *ret)
-{
-	char *msg;
-	struct wpabuf *buf;
-	unsigned char *decoded;
-	size_t len;
-
-	msg = xml_get_first_item(data, name);
-	if (msg == NULL) {
-		*ret = UPNP_ARG_VALUE_INVALID;
-		return NULL;
-	}
-
-	decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
-	os_free(msg);
-	if (decoded == NULL) {
-		*ret = UPNP_OUT_OF_MEMORY;
-		return NULL;
-	}
-
-	buf = wpabuf_alloc_ext_data(decoded, len);
-	if (buf == NULL) {
-		os_free(decoded);
-		*ret = UPNP_OUT_OF_MEMORY;
-		return NULL;
-	}
-	return buf;
-}

Copied: vendor/wpa/2.0/src/wps/upnp_xml.c (from rev 9639, vendor/wpa/dist/src/wps/upnp_xml.c)
===================================================================
--- vendor/wpa/2.0/src/wps/upnp_xml.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/upnp_xml.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,252 @@
+/*
+ * UPnP XML helper routines
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "http.h"
+#include "upnp_xml.h"
+
+
+/*
+ * XML parsing and formatting
+ *
+ * XML is a markup language based on unicode; usually (and in our case,
+ * always!) based on utf-8. utf-8 uses a variable number of bytes per
+ * character. utf-8 has the advantage that all non-ASCII unicode characters are
+ * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII
+ * characters are single ascii bytes, thus we can use typical text processing.
+ *
+ * (One other interesting thing about utf-8 is that it is possible to look at
+ * any random byte and determine if it is the first byte of a character as
+ * versus a continuation byte).
+ *
+ * The base syntax of XML uses a few ASCII punctionation characters; any
+ * characters that would appear in the payload data are rewritten using
+ * sequences, e.g., & for ampersand(&) and &lt for left angle bracket (<).
+ * Five such escapes total (more can be defined but that does not apply to our
+ * case). Thus we can safely parse for angle brackets etc.
+ *
+ * XML describes tree structures of tagged data, with each element beginning
+ * with an opening tag <label> and ending with a closing tag </label> with
+ * matching label. (There is also a self-closing tag <label/> which is supposed
+ * to be equivalent to <label></label>, i.e., no payload, but we are unlikely
+ * to see it for our purpose).
+ *
+ * Actually the opening tags are a little more complicated because they can
+ * contain "attributes" after the label (delimited by ascii space or tab chars)
+ * of the form attribute_label="value" or attribute_label='value'; as it turns
+ * out we do not have to read any of these attributes, just ignore them.
+ *
+ * Labels are any sequence of chars other than space, tab, right angle bracket
+ * (and ?), but may have an inner structure of <namespace><colon><plain_label>.
+ * As it turns out, we can ignore the namespaces, in fact we can ignore the
+ * entire tree hierarchy, because the plain labels we are looking for will be
+ * unique (not in general, but for this application). We do however have to be
+ * careful to skip over the namespaces.
+ *
+ * In generating XML we have to be more careful, but that is easy because
+ * everything we do is pretty canned. The only real care to take is to escape
+ * any special chars in our payload.
+ */
+
+/**
+ * xml_next_tag - Advance to next tag
+ * @in: Input
+ * @out: OUT: start of tag just after '<'
+ * @out_tagname: OUT: start of name of tag, skipping namespace
+ * @end: OUT: one after tag
+ * Returns: 0 on success, 1 on failure
+ *
+ * A tag has form:
+ *     <left angle bracket><...><right angle bracket>
+ * Within the angle brackets, there is an optional leading forward slash (which
+ * makes the tag an ending tag), then an optional leading label (followed by
+ * colon) and then the tag name itself.
+ *
+ * Note that angle brackets present in the original data must have been encoded
+ * as < and > so they will not trouble us.
+ */
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end)
+{
+	while (*in && *in != '<')
+		in++;
+	if (*in != '<')
+		return 1;
+	*out = ++in;
+	if (*in == '/')
+		in++;
+	*out_tagname = in; /* maybe */
+	while (isalnum(*in) || *in == '-')
+		in++;
+	if (*in == ':')
+		*out_tagname = ++in;
+	while (*in && *in != '>')
+		in++;
+	if (*in != '>')
+		return 1;
+	*end = ++in;
+	return 0;
+}
+
+
+/* xml_data_encode -- format data for xml file, escaping special characters.
+ *
+ * Note that we assume we are using utf8 both as input and as output!
+ * In utf8, characters may be classed as follows:
+ *     0xxxxxxx(2) -- 1 byte ascii char
+ *     11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80
+ *         110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here)
+ *         1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here)
+ *         11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here)
+ *      10xxxxxx(2) -- extension byte (6 payload bits per byte)
+ *      Some values implied by the above are however illegal because they
+ *      do not represent unicode chars or are not the shortest encoding.
+ * Actually, we can almost entirely ignore the above and just do
+ * text processing same as for ascii text.
+ *
+ * XML is written with arbitrary unicode characters, except that five
+ * characters have special meaning and so must be escaped where they
+ * appear in payload data... which we do here.
+ */
+void xml_data_encode(struct wpabuf *buf, const char *data, int len)
+{
+	int i;
+	for (i = 0; i < len; i++) {
+		u8 c = ((u8 *) data)[i];
+		if (c == '<') {
+			wpabuf_put_str(buf, "<");
+			continue;
+		}
+		if (c == '>') {
+			wpabuf_put_str(buf, ">");
+			continue;
+		}
+		if (c == '&') {
+			wpabuf_put_str(buf, "&");
+			continue;
+		}
+		if (c == '\'') {
+			wpabuf_put_str(buf, "'");
+			continue;
+		}
+		if (c == '"') {
+			wpabuf_put_str(buf, """);
+			continue;
+		}
+		/*
+		 * We could try to represent control characters using the
+		 * sequence: &#x; where x is replaced by a hex numeral, but not
+		 * clear why we would do this.
+		 */
+		wpabuf_put_u8(buf, c);
+	}
+}
+
+
+/* xml_add_tagged_data -- format tagged data as a new xml line.
+ *
+ * tag must not have any special chars.
+ * data may have special chars, which are escaped.
+ */
+void xml_add_tagged_data(struct wpabuf *buf, const char *tag, const char *data)
+{
+	wpabuf_printf(buf, "<%s>", tag);
+	xml_data_encode(buf, data, os_strlen(data));
+	wpabuf_printf(buf, "</%s>\n", tag);
+}
+
+
+/* A POST body looks something like (per upnp spec):
+ * <?xml version="1.0"?>
+ * <s:Envelope
+ *     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
+ *     s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ *   <s:Body>
+ *     <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
+ *       <argumentName>in arg value</argumentName>
+ *       other in args and their values go here, if any
+ *     </u:actionName>
+ *   </s:Body>
+ * </s:Envelope>
+ *
+ * where :
+ *      s: might be some other namespace name followed by colon
+ *      u: might be some other namespace name followed by colon
+ *      actionName will be replaced according to action requested
+ *      schema following actionName will be WFA scheme instead
+ *      argumentName will be actual argument name
+ *      (in arg value) will be actual argument value
+ */
+char * xml_get_first_item(const char *doc, const char *item)
+{
+	const char *match = item;
+	int match_len = os_strlen(item);
+	const char *tag, *tagname, *end;
+	char *value;
+
+	/*
+	 * This is crude: ignore any possible tag name conflicts and go right
+	 * to the first tag of this name. This should be ok for the limited
+	 * domain of UPnP messages.
+	 */
+	for (;;) {
+		if (xml_next_tag(doc, &tag, &tagname, &end))
+			return NULL;
+		doc = end;
+		if (!os_strncasecmp(tagname, match, match_len) &&
+		    *tag != '/' &&
+		    (tagname[match_len] == '>' ||
+		     !isgraph(tagname[match_len]))) {
+			break;
+		}
+	}
+	end = doc;
+	while (*end && *end != '<')
+		end++;
+	value = os_zalloc(1 + (end - doc));
+	if (value == NULL)
+		return NULL;
+	os_memcpy(value, doc, end - doc);
+	return value;
+}
+
+
+struct wpabuf * xml_get_base64_item(const char *data, const char *name,
+				    enum http_reply_code *ret)
+{
+	char *msg;
+	struct wpabuf *buf;
+	unsigned char *decoded;
+	size_t len;
+
+	msg = xml_get_first_item(data, name);
+	if (msg == NULL) {
+		*ret = UPNP_ARG_VALUE_INVALID;
+		return NULL;
+	}
+
+	decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
+	os_free(msg);
+	if (decoded == NULL) {
+		*ret = UPNP_OUT_OF_MEMORY;
+		return NULL;
+	}
+
+	buf = wpabuf_alloc_ext_data(decoded, len);
+	if (buf == NULL) {
+		os_free(decoded);
+		*ret = UPNP_OUT_OF_MEMORY;
+		return NULL;
+	}
+	return buf;
+}

Deleted: vendor/wpa/2.0/src/wps/upnp_xml.h
===================================================================
--- vendor/wpa/dist/src/wps/upnp_xml.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/upnp_xml.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,23 +0,0 @@
-/*
- * UPnP XML helper routines
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#ifndef UPNP_XML_H
-#define UPNP_XML_H
-
-#include "http.h"
-
-void xml_data_encode(struct wpabuf *buf, const char *data, int len);
-void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
-			 const char *data);
-char * xml_get_first_item(const char *doc, const char *item);
-struct wpabuf * xml_get_base64_item(const char *data, const char *name,
-				    enum http_reply_code *ret);
-
-#endif /* UPNP_XML_H */

Copied: vendor/wpa/2.0/src/wps/upnp_xml.h (from rev 9639, vendor/wpa/dist/src/wps/upnp_xml.h)
===================================================================
--- vendor/wpa/2.0/src/wps/upnp_xml.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/upnp_xml.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,25 @@
+/*
+ * UPnP XML helper routines
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#ifndef UPNP_XML_H
+#define UPNP_XML_H
+
+#include "http.h"
+
+void xml_data_encode(struct wpabuf *buf, const char *data, int len);
+void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
+			 const char *data);
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end);
+char * xml_get_first_item(const char *doc, const char *item);
+struct wpabuf * xml_get_base64_item(const char *data, const char *name,
+				    enum http_reply_code *ret);
+
+#endif /* UPNP_XML_H */

Deleted: vendor/wpa/2.0/src/wps/wps.c
===================================================================
--- vendor/wpa/dist/src/wps/wps.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,497 +0,0 @@
-/*
- * Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/dh_group5.h"
-#include "common/ieee802_11_defs.h"
-#include "wps_i.h"
-#include "wps_dev_attr.h"
-
-
-/**
- * wps_init - Initialize WPS Registration protocol data
- * @cfg: WPS configuration
- * Returns: Pointer to allocated data or %NULL on failure
- *
- * This function is used to initialize WPS data for a registration protocol
- * instance (i.e., each run of registration protocol as a Registrar of
- * Enrollee. The caller is responsible for freeing this data after the
- * registration run has been completed by calling wps_deinit().
- */
-struct wps_data * wps_init(const struct wps_config *cfg)
-{
-	struct wps_data *data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->wps = cfg->wps;
-	data->registrar = cfg->registrar;
-	if (cfg->registrar) {
-		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
-	} else {
-		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
-		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
-	}
-	if (cfg->pin) {
-		data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
-			DEV_PW_DEFAULT : data->wps->oob_dev_pw_id;
-		data->dev_password = os_malloc(cfg->pin_len);
-		if (data->dev_password == NULL) {
-			os_free(data);
-			return NULL;
-		}
-		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
-		data->dev_password_len = cfg->pin_len;
-	}
-
-	data->pbc = cfg->pbc;
-	if (cfg->pbc) {
-		/* Use special PIN '00000000' for PBC */
-		data->dev_pw_id = DEV_PW_PUSHBUTTON;
-		os_free(data->dev_password);
-		data->dev_password = os_malloc(8);
-		if (data->dev_password == NULL) {
-			os_free(data);
-			return NULL;
-		}
-		os_memset(data->dev_password, '0', 8);
-		data->dev_password_len = 8;
-	}
-
-	data->state = data->registrar ? RECV_M1 : SEND_M1;
-
-	if (cfg->assoc_wps_ie) {
-		struct wps_parse_attr attr;
-		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
-				cfg->assoc_wps_ie);
-		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
-			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
-				   "from (Re)AssocReq");
-		} else if (attr.request_type == NULL) {
-			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
-				   "in (Re)AssocReq WPS IE");
-		} else {
-			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
-				   "in (Re)AssocReq WPS IE): %d",
-				   *attr.request_type);
-			data->request_type = *attr.request_type;
-		}
-	}
-
-	if (cfg->new_ap_settings) {
-		data->new_ap_settings =
-			os_malloc(sizeof(*data->new_ap_settings));
-		if (data->new_ap_settings == NULL) {
-			os_free(data);
-			return NULL;
-		}
-		os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
-			  sizeof(*data->new_ap_settings));
-	}
-
-	if (cfg->peer_addr)
-		os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
-
-	data->use_psk_key = cfg->use_psk_key;
-
-	return data;
-}
-
-
-/**
- * wps_deinit - Deinitialize WPS Registration protocol data
- * @data: WPS Registration protocol data from wps_init()
- */
-void wps_deinit(struct wps_data *data)
-{
-	if (data->wps_pin_revealed) {
-		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
-			   "negotiation failed");
-		if (data->registrar)
-			wps_registrar_invalidate_pin(data->wps->registrar,
-						     data->uuid_e);
-	} else if (data->registrar)
-		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
-
-	wpabuf_free(data->dh_privkey);
-	wpabuf_free(data->dh_pubkey_e);
-	wpabuf_free(data->dh_pubkey_r);
-	wpabuf_free(data->last_msg);
-	os_free(data->dev_password);
-	os_free(data->new_psk);
-	wps_device_data_free(&data->peer_dev);
-	os_free(data->new_ap_settings);
-	dh5_free(data->dh_ctx);
-	os_free(data);
-}
-
-
-/**
- * wps_process_msg - Process a WPS message
- * @wps: WPS Registration protocol data from wps_init()
- * @op_code: Message OP Code
- * @msg: Message data
- * Returns: Processing result
- *
- * This function is used to process WPS messages with OP Codes WSC_ACK,
- * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
- * responsible for reassembling the messages before calling this function.
- * Response to this message is built by calling wps_get_msg().
- */
-enum wps_process_res wps_process_msg(struct wps_data *wps,
-				     enum wsc_op_code op_code,
-				     const struct wpabuf *msg)
-{
-	if (wps->registrar)
-		return wps_registrar_process_msg(wps, op_code, msg);
-	else
-		return wps_enrollee_process_msg(wps, op_code, msg);
-}
-
-
-/**
- * wps_get_msg - Build a WPS message
- * @wps: WPS Registration protocol data from wps_init()
- * @op_code: Buffer for returning message OP Code
- * Returns: The generated WPS message or %NULL on failure
- *
- * This function is used to build a response to a message processed by calling
- * wps_process_msg(). The caller is responsible for freeing the buffer.
- */
-struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
-{
-	if (wps->registrar)
-		return wps_registrar_get_msg(wps, op_code);
-	else
-		return wps_enrollee_get_msg(wps, op_code);
-}
-
-
-/**
- * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: 1 if PBC Registrar is active, 0 if not
- */
-int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	/*
-	 * In theory, this could also verify that attr.sel_reg_config_methods
-	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
-	 * do not set Selected Registrar Config Methods attribute properly, so
-	 * it is safer to just use Device Password ID here.
-	 */
-
-	if (wps_parse_msg(msg, &attr) < 0 ||
-	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
-	    !attr.dev_password_id ||
-	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
-		return 0;
-
-	return 1;
-}
-
-
-/**
- * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: 1 if PIN Registrar is active, 0 if not
- */
-int wps_is_selected_pin_registrar(const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	/*
-	 * In theory, this could also verify that attr.sel_reg_config_methods
-	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
-	 * but some deployed AP implementations do not set Selected Registrar
-	 * Config Methods attribute properly, so it is safer to just use
-	 * Device Password ID here.
-	 */
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return 0;
-
-	if (!attr.selected_registrar || *attr.selected_registrar == 0)
-		return 0;
-
-	if (attr.dev_password_id != NULL &&
-	    WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
-		return 0;
-
-	return 1;
-}
-
-
-/**
- * wps_get_uuid_e - Get UUID-E from WPS IE
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: Pointer to UUID-E or %NULL if not included
- *
- * The returned pointer is to the msg contents and it remains valid only as
- * long as the msg buffer is valid.
- */
-const u8 * wps_get_uuid_e(const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return NULL;
-	return attr.uuid_e;
-}
-
-
-/**
- * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
- * @req_type: Value for Request Type attribute
- * Returns: WPS IE or %NULL on failure
- *
- * The caller is responsible for freeing the buffer.
- */
-struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
-{
-	struct wpabuf *ie;
-	u8 *len;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
-		   "Request");
-	ie = wpabuf_alloc(100);
-	if (ie == NULL)
-		return NULL;
-
-	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-	len = wpabuf_put(ie, 1);
-	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-
-	if (wps_build_version(ie) ||
-	    wps_build_req_type(ie, req_type)) {
-		wpabuf_free(ie);
-		return NULL;
-	}
-
-	*len = wpabuf_len(ie) - 2;
-
-	return ie;
-}
-
-
-/**
- * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response
- * Returns: WPS IE or %NULL on failure
- *
- * The caller is responsible for freeing the buffer.
- */
-struct wpabuf * wps_build_assoc_resp_ie(void)
-{
-	struct wpabuf *ie;
-	u8 *len;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
-		   "Response");
-	ie = wpabuf_alloc(100);
-	if (ie == NULL)
-		return NULL;
-
-	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-	len = wpabuf_put(ie, 1);
-	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-
-	if (wps_build_version(ie) ||
-	    wps_build_resp_type(ie, WPS_RESP_AP)) {
-		wpabuf_free(ie);
-		return NULL;
-	}
-
-	*len = wpabuf_len(ie) - 2;
-
-	return ie;
-}
-
-
-/**
- * wps_build_probe_req_ie - Build WPS IE for Probe Request
- * @pbc: Whether searching for PBC mode APs
- * @dev: Device attributes
- * @uuid: Own UUID
- * @req_type: Value for Request Type attribute
- * Returns: WPS IE or %NULL on failure
- *
- * The caller is responsible for freeing the buffer.
- */
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
-				       const u8 *uuid,
-				       enum wps_request_type req_type)
-{
-	struct wpabuf *ie;
-	u8 *len;
-	u16 methods;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
-
-	ie = wpabuf_alloc(200);
-	if (ie == NULL)
-		return NULL;
-
-	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-	len = wpabuf_put(ie, 1);
-	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-
-	if (pbc)
-		methods = WPS_CONFIG_PUSHBUTTON;
-	else {
-		methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
-			WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
-		methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-		methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-	}
-
-	if (wps_build_version(ie) ||
-	    wps_build_req_type(ie, req_type) ||
-	    wps_build_config_methods(ie, methods) ||
-	    wps_build_uuid_e(ie, uuid) ||
-	    wps_build_primary_dev_type(dev, ie) ||
-	    wps_build_rf_bands(dev, ie) ||
-	    wps_build_assoc_state(NULL, ie) ||
-	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
-	    wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
-				      DEV_PW_DEFAULT)) {
-		wpabuf_free(ie);
-		return NULL;
-	}
-
-	*len = wpabuf_len(ie) - 2;
-
-	return ie;
-}
-
-
-void wps_free_pending_msgs(struct upnp_pending_message *msgs)
-{
-	struct upnp_pending_message *p, *prev;
-	p = msgs;
-	while (p) {
-		prev = p;
-		p = p->next;
-		wpabuf_free(prev->msg);
-		os_free(prev);
-	}
-}
-
-
-int wps_attr_text(struct wpabuf *data, char *buf, char *end)
-{
-	struct wps_parse_attr attr;
-	char *pos = buf;
-	int ret;
-
-	if (wps_parse_msg(data, &attr) < 0)
-		return -1;
-
-	if (attr.wps_state) {
-		if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED)
-			ret = os_snprintf(pos, end - pos,
-					  "wps_state=unconfigured\n");
-		else if (*attr.wps_state == WPS_STATE_CONFIGURED)
-			ret = os_snprintf(pos, end - pos,
-					  "wps_state=configured\n");
-		else
-			ret = 0;
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.ap_setup_locked && *attr.ap_setup_locked) {
-		ret = os_snprintf(pos, end - pos,
-				  "wps_ap_setup_locked=1\n");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.selected_registrar && *attr.selected_registrar) {
-		ret = os_snprintf(pos, end - pos,
-				  "wps_selected_registrar=1\n");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.dev_password_id) {
-		ret = os_snprintf(pos, end - pos,
-				  "wps_device_password_id=%u\n",
-				  WPA_GET_BE16(attr.dev_password_id));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.sel_reg_config_methods) {
-		ret = os_snprintf(pos, end - pos,
-				  "wps_selected_registrar_config_methods="
-				  "0x%04x\n",
-				  WPA_GET_BE16(attr.sel_reg_config_methods));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.primary_dev_type) {
-		char devtype[WPS_DEV_TYPE_BUFSIZE];
-		ret = os_snprintf(pos, end - pos,
-				  "wps_primary_device_type=%s\n",
-				  wps_dev_type_bin2str(attr.primary_dev_type,
-						       devtype,
-						       sizeof(devtype)));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.dev_name) {
-		char *str = os_malloc(attr.dev_name_len + 1);
-		size_t i;
-		if (str == NULL)
-			return pos - buf;
-		for (i = 0; i < attr.dev_name_len; i++) {
-			if (attr.dev_name[i] < 32)
-				str[i] = '_';
-			else
-				str[i] = attr.dev_name[i];
-		}
-		str[i] = '\0';
-		ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
-		os_free(str);
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (attr.config_methods) {
-		ret = os_snprintf(pos, end - pos,
-				  "wps_config_methods=0x%04x\n",
-				  WPA_GET_BE16(attr.config_methods));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	return pos - buf;
-}

Copied: vendor/wpa/2.0/src/wps/wps.c (from rev 9639, vendor/wpa/dist/src/wps/wps.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,633 @@
+/*
+ * Wi-Fi Protected Setup
+ * Copyright (c) 2007-2009, Jouni Malinen <j at 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/dh_group5.h"
+#include "common/ieee802_11_defs.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+#ifdef CONFIG_WPS_TESTING
+int wps_version_number = 0x20;
+int wps_testing_dummy_cred = 0;
+#endif /* CONFIG_WPS_TESTING */
+
+
+/**
+ * wps_init - Initialize WPS Registration protocol data
+ * @cfg: WPS configuration
+ * Returns: Pointer to allocated data or %NULL on failure
+ *
+ * This function is used to initialize WPS data for a registration protocol
+ * instance (i.e., each run of registration protocol as a Registrar of
+ * Enrollee. The caller is responsible for freeing this data after the
+ * registration run has been completed by calling wps_deinit().
+ */
+struct wps_data * wps_init(const struct wps_config *cfg)
+{
+	struct wps_data *data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->wps = cfg->wps;
+	data->registrar = cfg->registrar;
+	if (cfg->registrar) {
+		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
+	} else {
+		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
+		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
+	}
+	if (cfg->pin) {
+		data->dev_pw_id = cfg->dev_pw_id;
+		data->dev_password = os_malloc(cfg->pin_len);
+		if (data->dev_password == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
+		data->dev_password_len = cfg->pin_len;
+	}
+
+#ifdef CONFIG_WPS_NFC
+	if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+		data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
+		os_free(data->dev_password);
+		data->dev_password =
+			os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+		if (data->dev_password == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->dev_password,
+			  wpabuf_head(cfg->wps->ap_nfc_dev_pw),
+			  wpabuf_len(cfg->wps->ap_nfc_dev_pw));
+		data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+	}
+#endif /* CONFIG_WPS_NFC */
+
+	data->pbc = cfg->pbc;
+	if (cfg->pbc) {
+		/* Use special PIN '00000000' for PBC */
+		data->dev_pw_id = DEV_PW_PUSHBUTTON;
+		os_free(data->dev_password);
+		data->dev_password = (u8 *) os_strdup("00000000");
+		if (data->dev_password == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		data->dev_password_len = 8;
+	}
+
+	data->state = data->registrar ? RECV_M1 : SEND_M1;
+
+	if (cfg->assoc_wps_ie) {
+		struct wps_parse_attr attr;
+		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
+				cfg->assoc_wps_ie);
+		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
+				   "from (Re)AssocReq");
+		} else if (attr.request_type == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
+				   "in (Re)AssocReq WPS IE");
+		} else {
+			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
+				   "in (Re)AssocReq WPS IE): %d",
+				   *attr.request_type);
+			data->request_type = *attr.request_type;
+		}
+	}
+
+	if (cfg->new_ap_settings) {
+		data->new_ap_settings =
+			os_malloc(sizeof(*data->new_ap_settings));
+		if (data->new_ap_settings == NULL) {
+			os_free(data->dev_password);
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
+			  sizeof(*data->new_ap_settings));
+	}
+
+	if (cfg->peer_addr)
+		os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
+	if (cfg->p2p_dev_addr)
+		os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN);
+
+	data->use_psk_key = cfg->use_psk_key;
+	data->pbc_in_m1 = cfg->pbc_in_m1;
+
+	return data;
+}
+
+
+/**
+ * wps_deinit - Deinitialize WPS Registration protocol data
+ * @data: WPS Registration protocol data from wps_init()
+ */
+void wps_deinit(struct wps_data *data)
+{
+#ifdef CONFIG_WPS_NFC
+	if (data->registrar && data->nfc_pw_token)
+		wps_registrar_remove_nfc_pw_token(data->wps->registrar,
+						  data->nfc_pw_token);
+#endif /* CONFIG_WPS_NFC */
+
+	if (data->wps_pin_revealed) {
+		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
+			   "negotiation failed");
+		if (data->registrar)
+			wps_registrar_invalidate_pin(data->wps->registrar,
+						     data->uuid_e);
+	} else if (data->registrar)
+		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
+
+	wpabuf_free(data->dh_privkey);
+	wpabuf_free(data->dh_pubkey_e);
+	wpabuf_free(data->dh_pubkey_r);
+	wpabuf_free(data->last_msg);
+	os_free(data->dev_password);
+	os_free(data->new_psk);
+	wps_device_data_free(&data->peer_dev);
+	os_free(data->new_ap_settings);
+	dh5_free(data->dh_ctx);
+	os_free(data->nfc_pw_token);
+	os_free(data);
+}
+
+
+/**
+ * wps_process_msg - Process a WPS message
+ * @wps: WPS Registration protocol data from wps_init()
+ * @op_code: Message OP Code
+ * @msg: Message data
+ * Returns: Processing result
+ *
+ * This function is used to process WPS messages with OP Codes WSC_ACK,
+ * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
+ * responsible for reassembling the messages before calling this function.
+ * Response to this message is built by calling wps_get_msg().
+ */
+enum wps_process_res wps_process_msg(struct wps_data *wps,
+				     enum wsc_op_code op_code,
+				     const struct wpabuf *msg)
+{
+	if (wps->registrar)
+		return wps_registrar_process_msg(wps, op_code, msg);
+	else
+		return wps_enrollee_process_msg(wps, op_code, msg);
+}
+
+
+/**
+ * wps_get_msg - Build a WPS message
+ * @wps: WPS Registration protocol data from wps_init()
+ * @op_code: Buffer for returning message OP Code
+ * Returns: The generated WPS message or %NULL on failure
+ *
+ * This function is used to build a response to a message processed by calling
+ * wps_process_msg(). The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
+{
+	if (wps->registrar)
+		return wps_registrar_get_msg(wps, op_code);
+	else
+		return wps_enrollee_get_msg(wps, op_code);
+}
+
+
+/**
+ * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PBC Registrar is active, 0 if not
+ */
+int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	/*
+	 * In theory, this could also verify that attr.sel_reg_config_methods
+	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
+	 * do not set Selected Registrar Config Methods attribute properly, so
+	 * it is safer to just use Device Password ID here.
+	 */
+
+	if (wps_parse_msg(msg, &attr) < 0 ||
+	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
+	    !attr.dev_password_id ||
+	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
+		return 0;
+
+#ifdef CONFIG_WPS_STRICT
+	if (!attr.sel_reg_config_methods ||
+	    !(WPA_GET_BE16(attr.sel_reg_config_methods) &
+	      WPS_CONFIG_PUSHBUTTON))
+		return 0;
+#endif /* CONFIG_WPS_STRICT */
+
+	return 1;
+}
+
+
+static int is_selected_pin_registrar(struct wps_parse_attr *attr)
+{
+	/*
+	 * In theory, this could also verify that attr.sel_reg_config_methods
+	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
+	 * but some deployed AP implementations do not set Selected Registrar
+	 * Config Methods attribute properly, so it is safer to just use
+	 * Device Password ID here.
+	 */
+
+	if (!attr->selected_registrar || *attr->selected_registrar == 0)
+		return 0;
+
+	if (attr->dev_password_id != NULL &&
+	    WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
+		return 0;
+
+#ifdef CONFIG_WPS_STRICT
+	if (!attr->sel_reg_config_methods ||
+	    !(WPA_GET_BE16(attr->sel_reg_config_methods) &
+	      (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)))
+		return 0;
+#endif /* CONFIG_WPS_STRICT */
+
+	return 1;
+}
+
+
+/**
+ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PIN Registrar is active, 0 if not
+ */
+int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return 0;
+
+	return is_selected_pin_registrar(&attr);
+}
+
+
+/**
+ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * @addr: MAC address to search for
+ * @ver1_compat: Whether to use version 1 compatibility mode
+ * Returns: 2 if the specified address is explicit authorized, 1 if address is
+ * authorized (broadcast), 0 if not
+ */
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+			   int ver1_compat)
+{
+	struct wps_parse_attr attr;
+	unsigned int i;
+	const u8 *pos;
+	const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return 0;
+
+	if (!attr.version2 && ver1_compat) {
+		/*
+		 * Version 1.0 AP - AuthorizedMACs not used, so revert back to
+		 * old mechanism of using SelectedRegistrar.
+		 */
+		return is_selected_pin_registrar(&attr);
+	}
+
+	if (!attr.authorized_macs)
+		return 0;
+
+	pos = attr.authorized_macs;
+	for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
+		if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+			return 2;
+		if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
+			return 1;
+		pos += ETH_ALEN;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wps_ap_priority_compar - Prioritize WPS IE from two APs
+ * @wps_a: WPS IE contents from Beacon or Probe Response frame
+ * @wps_b: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if wps_b is considered more likely selection for WPS
+ * provisioning, -1 if wps_a is considered more like, or 0 if no preference
+ */
+int wps_ap_priority_compar(const struct wpabuf *wps_a,
+			   const struct wpabuf *wps_b)
+{
+	struct wps_parse_attr attr_a, attr_b;
+	int sel_a, sel_b;
+
+	if (wps_a == NULL || wps_parse_msg(wps_a, &attr_a) < 0)
+		return 1;
+	if (wps_b == NULL || wps_parse_msg(wps_b, &attr_b) < 0)
+		return -1;
+
+	sel_a = attr_a.selected_registrar && *attr_a.selected_registrar != 0;
+	sel_b = attr_b.selected_registrar && *attr_b.selected_registrar != 0;
+
+	if (sel_a && !sel_b)
+		return -1;
+	if (!sel_a && sel_b)
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * wps_get_uuid_e - Get UUID-E from WPS IE
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: Pointer to UUID-E or %NULL if not included
+ *
+ * The returned pointer is to the msg contents and it remains valid only as
+ * long as the msg buffer is valid.
+ */
+const u8 * wps_get_uuid_e(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return NULL;
+	return attr.uuid_e;
+}
+
+
+/**
+ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
+ */
+int wps_is_20(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
+		return 0;
+	return attr.version2 != NULL;
+}
+
+
+/**
+ * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
+ * @req_type: Value for Request Type attribute
+ * Returns: WPS IE or %NULL on failure
+ *
+ * The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
+{
+	struct wpabuf *ie;
+	u8 *len;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
+		   "Request");
+	ie = wpabuf_alloc(100);
+	if (ie == NULL)
+		return NULL;
+
+	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+	len = wpabuf_put(ie, 1);
+	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+
+	if (wps_build_version(ie) ||
+	    wps_build_req_type(ie, req_type) ||
+	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+
+	*len = wpabuf_len(ie) - 2;
+
+	return ie;
+}
+
+
+/**
+ * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response
+ * Returns: WPS IE or %NULL on failure
+ *
+ * The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_build_assoc_resp_ie(void)
+{
+	struct wpabuf *ie;
+	u8 *len;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
+		   "Response");
+	ie = wpabuf_alloc(100);
+	if (ie == NULL)
+		return NULL;
+
+	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+	len = wpabuf_put(ie, 1);
+	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+
+	if (wps_build_version(ie) ||
+	    wps_build_resp_type(ie, WPS_RESP_AP) ||
+	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+
+	*len = wpabuf_len(ie) - 2;
+
+	return ie;
+}
+
+
+/**
+ * wps_build_probe_req_ie - Build WPS IE for Probe Request
+ * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
+ * most other use cases)
+ * @dev: Device attributes
+ * @uuid: Own UUID
+ * @req_type: Value for Request Type attribute
+ * @num_req_dev_types: Number of requested device types
+ * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
+ *	%NULL if none
+ * Returns: WPS IE or %NULL on failure
+ *
+ * The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
+				       const u8 *uuid,
+				       enum wps_request_type req_type,
+				       unsigned int num_req_dev_types,
+				       const u8 *req_dev_types)
+{
+	struct wpabuf *ie;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
+
+	ie = wpabuf_alloc(500);
+	if (ie == NULL)
+		return NULL;
+
+	if (wps_build_version(ie) ||
+	    wps_build_req_type(ie, req_type) ||
+	    wps_build_config_methods(ie, dev->config_methods) ||
+	    wps_build_uuid_e(ie, uuid) ||
+	    wps_build_primary_dev_type(dev, ie) ||
+	    wps_build_rf_bands(dev, ie) ||
+	    wps_build_assoc_state(NULL, ie) ||
+	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
+	    wps_build_dev_password_id(ie, pw_id) ||
+#ifdef CONFIG_WPS2
+	    wps_build_manufacturer(dev, ie) ||
+	    wps_build_model_name(dev, ie) ||
+	    wps_build_model_number(dev, ie) ||
+	    wps_build_dev_name(dev, ie) ||
+	    wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
+#endif /* CONFIG_WPS2 */
+	    wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
+	    ||
+	    wps_build_secondary_dev_type(dev, ie)
+		) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+
+#ifndef CONFIG_WPS2
+	if (dev->p2p && wps_build_dev_name(dev, ie)) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+#endif /* CONFIG_WPS2 */
+
+	return wps_ie_encapsulate(ie);
+}
+
+
+void wps_free_pending_msgs(struct upnp_pending_message *msgs)
+{
+	struct upnp_pending_message *p, *prev;
+	p = msgs;
+	while (p) {
+		prev = p;
+		p = p->next;
+		wpabuf_free(prev->msg);
+		os_free(prev);
+	}
+}
+
+
+int wps_attr_text(struct wpabuf *data, char *buf, char *end)
+{
+	struct wps_parse_attr attr;
+	char *pos = buf;
+	int ret;
+
+	if (wps_parse_msg(data, &attr) < 0)
+		return -1;
+
+	if (attr.wps_state) {
+		if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED)
+			ret = os_snprintf(pos, end - pos,
+					  "wps_state=unconfigured\n");
+		else if (*attr.wps_state == WPS_STATE_CONFIGURED)
+			ret = os_snprintf(pos, end - pos,
+					  "wps_state=configured\n");
+		else
+			ret = 0;
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.ap_setup_locked && *attr.ap_setup_locked) {
+		ret = os_snprintf(pos, end - pos,
+				  "wps_ap_setup_locked=1\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.selected_registrar && *attr.selected_registrar) {
+		ret = os_snprintf(pos, end - pos,
+				  "wps_selected_registrar=1\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.dev_password_id) {
+		ret = os_snprintf(pos, end - pos,
+				  "wps_device_password_id=%u\n",
+				  WPA_GET_BE16(attr.dev_password_id));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.sel_reg_config_methods) {
+		ret = os_snprintf(pos, end - pos,
+				  "wps_selected_registrar_config_methods="
+				  "0x%04x\n",
+				  WPA_GET_BE16(attr.sel_reg_config_methods));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.primary_dev_type) {
+		char devtype[WPS_DEV_TYPE_BUFSIZE];
+		ret = os_snprintf(pos, end - pos,
+				  "wps_primary_device_type=%s\n",
+				  wps_dev_type_bin2str(attr.primary_dev_type,
+						       devtype,
+						       sizeof(devtype)));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.dev_name) {
+		char *str = os_malloc(attr.dev_name_len + 1);
+		size_t i;
+		if (str == NULL)
+			return pos - buf;
+		for (i = 0; i < attr.dev_name_len; i++) {
+			if (attr.dev_name[i] < 32)
+				str[i] = '_';
+			else
+				str[i] = attr.dev_name[i];
+		}
+		str[i] = '\0';
+		ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
+		os_free(str);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (attr.config_methods) {
+		ret = os_snprintf(pos, end - pos,
+				  "wps_config_methods=0x%04x\n",
+				  WPA_GET_BE16(attr.config_methods));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}

Deleted: vendor/wpa/2.0/src/wps/wps.h
===================================================================
--- vendor/wpa/dist/src/wps/wps.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,736 +0,0 @@
-/*
- * Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_H
-#define WPS_H
-
-#include "wps_defs.h"
-
-/**
- * enum wsc_op_code - EAP-WSC OP-Code values
- */
-enum wsc_op_code {
-	WSC_UPnP = 0 /* No OP Code in UPnP transport */,
-	WSC_Start = 0x01,
-	WSC_ACK = 0x02,
-	WSC_NACK = 0x03,
-	WSC_MSG = 0x04,
-	WSC_Done = 0x05,
-	WSC_FRAG_ACK = 0x06
-};
-
-struct wps_registrar;
-struct upnp_wps_device_sm;
-struct wps_er;
-
-/**
- * struct wps_credential - WPS Credential
- * @ssid: SSID
- * @ssid_len: Length of SSID
- * @auth_type: Authentication Type (WPS_AUTH_OPEN, .. flags)
- * @encr_type: Encryption Type (WPS_ENCR_NONE, .. flags)
- * @key_idx: Key index
- * @key: Key
- * @key_len: Key length in octets
- * @mac_addr: MAC address of the Credential receiver
- * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
- *	this may be %NULL, if not used
- * @cred_attr_len: Length of cred_attr in octets
- */
-struct wps_credential {
-	u8 ssid[32];
-	size_t ssid_len;
-	u16 auth_type;
-	u16 encr_type;
-	u8 key_idx;
-	u8 key[64];
-	size_t key_len;
-	u8 mac_addr[ETH_ALEN];
-	const u8 *cred_attr;
-	size_t cred_attr_len;
-};
-
-#define WPS_DEV_TYPE_LEN 8
-#define WPS_DEV_TYPE_BUFSIZE 21
-
-/**
- * struct wps_device_data - WPS Device Data
- * @mac_addr: Device MAC address
- * @device_name: Device Name (0..32 octets encoded in UTF-8)
- * @manufacturer: Manufacturer (0..64 octets encoded in UTF-8)
- * @model_name: Model Name (0..32 octets encoded in UTF-8)
- * @model_number: Model Number (0..32 octets encoded in UTF-8)
- * @serial_number: Serial Number (0..32 octets encoded in UTF-8)
- * @pri_dev_type: Primary Device Type
- * @os_version: OS Version
- * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
- */
-struct wps_device_data {
-	u8 mac_addr[ETH_ALEN];
-	char *device_name;
-	char *manufacturer;
-	char *model_name;
-	char *model_number;
-	char *serial_number;
-	u8 pri_dev_type[WPS_DEV_TYPE_LEN];
-	u32 os_version;
-	u8 rf_bands;
-};
-
-struct oob_conf_data {
-	enum {
-		OOB_METHOD_UNKNOWN = 0,
-		OOB_METHOD_DEV_PWD_E,
-		OOB_METHOD_DEV_PWD_R,
-		OOB_METHOD_CRED,
-	} oob_method;
-	struct wpabuf *dev_password;
-	struct wpabuf *pubkey_hash;
-};
-
-/**
- * struct wps_config - WPS configuration for a single registration protocol run
- */
-struct wps_config {
-	/**
-	 * wps - Pointer to long term WPS context
-	 */
-	struct wps_context *wps;
-
-	/**
-	 * registrar - Whether this end is a Registrar
-	 */
-	int registrar;
-
-	/**
-	 * pin - Enrollee Device Password (%NULL for Registrar or PBC)
-	 */
-	const u8 *pin;
-
-	/**
-	 * pin_len - Length on pin in octets
-	 */
-	size_t pin_len;
-
-	/**
-	 * pbc - Whether this is protocol run uses PBC
-	 */
-	int pbc;
-
-	/**
-	 * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
-	 */
-	const struct wpabuf *assoc_wps_ie;
-
-	/**
-	 * new_ap_settings - New AP settings (%NULL if not used)
-	 *
-	 * This parameter provides new AP settings when using a wireless
-	 * stations as a Registrar to configure the AP. %NULL means that AP
-	 * will not be reconfigured, i.e., the station will only learn the
-	 * current AP settings by using AP PIN.
-	 */
-	const struct wps_credential *new_ap_settings;
-
-	/**
-	 * peer_addr: MAC address of the peer in AP; %NULL if not AP
-	 */
-	const u8 *peer_addr;
-
-	/**
-	 * use_psk_key - Use PSK format key in Credential
-	 *
-	 * Force PSK format to be used instead of ASCII passphrase when
-	 * building Credential for an Enrollee. The PSK value is set in
-	 * struct wpa_context::psk.
-	 */
-	int use_psk_key;
-};
-
-struct wps_data * wps_init(const struct wps_config *cfg);
-
-void wps_deinit(struct wps_data *data);
-
-/**
- * enum wps_process_res - WPS message processing result
- */
-enum wps_process_res {
-	/**
-	 * WPS_DONE - Processing done
-	 */
-	WPS_DONE,
-
-	/**
-	 * WPS_CONTINUE - Processing continues
-	 */
-	WPS_CONTINUE,
-
-	/**
-	 * WPS_FAILURE - Processing failed
-	 */
-	WPS_FAILURE,
-
-	/**
-	 * WPS_PENDING - Processing continues, but waiting for an external
-	 *	event (e.g., UPnP message from an external Registrar)
-	 */
-	WPS_PENDING
-};
-enum wps_process_res wps_process_msg(struct wps_data *wps,
-				     enum wsc_op_code op_code,
-				     const struct wpabuf *msg);
-
-struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
-
-int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
-int wps_is_selected_pin_registrar(const struct wpabuf *msg);
-const u8 * wps_get_uuid_e(const struct wpabuf *msg);
-
-struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
-struct wpabuf * wps_build_assoc_resp_ie(void);
-struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
-				       const u8 *uuid,
-				       enum wps_request_type req_type);
-
-
-/**
- * struct wps_registrar_config - WPS Registrar configuration
- */
-struct wps_registrar_config {
-	/**
-	 * new_psk_cb - Callback for new PSK
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @mac_addr: MAC address of the Enrollee
-	 * @psk: The new PSK
-	 * @psk_len: The length of psk in octets
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This callback is called when a new per-device PSK is provisioned.
-	 */
-	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
-			  size_t psk_len);
-
-	/**
-	 * set_ie_cb - Callback for WPS IE changes
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @beacon_ie: WPS IE for Beacon
-	 * @probe_resp_ie: WPS IE for Probe Response
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This callback is called whenever the WPS IE in Beacon or Probe
-	 * Response frames needs to be changed (AP only). Callee is responsible
-	 * for freeing the buffers.
-	 */
-	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
-			 struct wpabuf *probe_resp_ie);
-
-	/**
-	 * pin_needed_cb - Callback for requesting a PIN
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @uuid_e: UUID-E of the unknown Enrollee
-	 * @dev: Device Data from the unknown Enrollee
-	 *
-	 * This callback is called whenever an unknown Enrollee requests to use
-	 * PIN method and a matching PIN (Device Password) is not found in
-	 * Registrar data.
-	 */
-	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
-			      const struct wps_device_data *dev);
-
-	/**
-	 * reg_success_cb - Callback for reporting successful registration
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @mac_addr: MAC address of the Enrollee
-	 * @uuid_e: UUID-E of the Enrollee
-	 *
-	 * This callback is called whenever an Enrollee completes registration
-	 * successfully.
-	 */
-	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
-			       const u8 *uuid_e);
-
-	/**
-	 * set_sel_reg_cb - Callback for reporting selected registrar changes
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @sel_reg: Whether the Registrar is selected
-	 * @dev_passwd_id: Device Password ID to indicate with method or
-	 *	specific password the Registrar intends to use
-	 * @sel_reg_config_methods: Bit field of active config methods
-	 *
-	 * This callback is called whenever the Selected Registrar state
-	 * changes (e.g., a new PIN becomes available or PBC is invoked). This
-	 * callback is only used by External Registrar implementation;
-	 * set_ie_cb() is used by AP implementation in similar caes, but it
-	 * provides the full WPS IE data instead of just the minimal Registrar
-	 * state information.
-	 */
-	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
-			       u16 sel_reg_config_methods);
-
-	/**
-	 * enrollee_seen_cb - Callback for reporting Enrollee based on ProbeReq
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @addr: MAC address of the Enrollee
-	 * @uuid_e: UUID of the Enrollee
-	 * @pri_dev_type: Primary device type
-	 * @config_methods: Config Methods
-	 * @dev_password_id: Device Password ID
-	 * @request_type: Request Type
-	 * @dev_name: Device Name (if available)
-	 */
-	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
-				 const u8 *pri_dev_type, u16 config_methods,
-				 u16 dev_password_id, u8 request_type,
-				 const char *dev_name);
-
-	/**
-	 * cb_ctx: Higher layer context data for Registrar callbacks
-	 */
-	void *cb_ctx;
-
-	/**
-	 * skip_cred_build: Do not build credential
-	 *
-	 * This option can be used to disable internal code that builds
-	 * Credential attribute into M8 based on the current network
-	 * configuration and Enrollee capabilities. The extra_cred data will
-	 * then be used as the Credential(s).
-	 */
-	int skip_cred_build;
-
-	/**
-	 * extra_cred: Additional Credential attribute(s)
-	 *
-	 * This optional data (set to %NULL to disable) can be used to add
-	 * Credential attribute(s) for other networks into M8. If
-	 * skip_cred_build is set, this will also override the automatically
-	 * generated Credential attribute.
-	 */
-	const u8 *extra_cred;
-
-	/**
-	 * extra_cred_len: Length of extra_cred in octets
-	 */
-	size_t extra_cred_len;
-
-	/**
-	 * disable_auto_conf - Disable auto-configuration on first registration
-	 *
-	 * By default, the AP that is started in not configured state will
-	 * generate a random PSK and move to configured state when the first
-	 * registration protocol run is completed successfully. This option can
-	 * be used to disable this functionality and leave it up to an external
-	 * program to take care of configuration. This requires the extra_cred
-	 * to be set with a suitable Credential and skip_cred_build being used.
-	 */
-	int disable_auto_conf;
-
-	/**
-	 * static_wep_only - Whether the BSS supports only static WEP
-	 */
-	int static_wep_only;
-};
-
-
-/**
- * enum wps_event - WPS event types
- */
-enum wps_event {
-	/**
-	 * WPS_EV_M2D - M2D received (Registrar did not know us)
-	 */
-	WPS_EV_M2D,
-
-	/**
-	 * WPS_EV_FAIL - Registration failed
-	 */
-	WPS_EV_FAIL,
-
-	/**
-	 * WPS_EV_SUCCESS - Registration succeeded
-	 */
-	WPS_EV_SUCCESS,
-
-	/**
-	 * WPS_EV_PWD_AUTH_FAIL - Password authentication failed
-	 */
-	WPS_EV_PWD_AUTH_FAIL,
-
-	/**
-	 * WPS_EV_PBC_OVERLAP - PBC session overlap detected
-	 */
-	WPS_EV_PBC_OVERLAP,
-
-	/**
-	 * WPS_EV_PBC_TIMEOUT - PBC walktime expired before protocol run start
-	 */
-	WPS_EV_PBC_TIMEOUT,
-
-	/**
-	 * WPS_EV_ER_AP_ADD - ER: AP added
-	 */
-	WPS_EV_ER_AP_ADD,
-
-	/**
-	 * WPS_EV_ER_AP_REMOVE - ER: AP removed
-	 */
-	WPS_EV_ER_AP_REMOVE,
-
-	/**
-	 * WPS_EV_ER_ENROLLEE_ADD - ER: Enrollee added
-	 */
-	WPS_EV_ER_ENROLLEE_ADD,
-
-	/**
-	 * WPS_EV_ER_ENROLLEE_REMOVE - ER: Enrollee removed
-	 */
-	WPS_EV_ER_ENROLLEE_REMOVE
-};
-
-/**
- * union wps_event_data - WPS event data
- */
-union wps_event_data {
-	/**
-	 * struct wps_event_m2d - M2D event data
-	 */
-	struct wps_event_m2d {
-		u16 config_methods;
-		const u8 *manufacturer;
-		size_t manufacturer_len;
-		const u8 *model_name;
-		size_t model_name_len;
-		const u8 *model_number;
-		size_t model_number_len;
-		const u8 *serial_number;
-		size_t serial_number_len;
-		const u8 *dev_name;
-		size_t dev_name_len;
-		const u8 *primary_dev_type; /* 8 octets */
-		u16 config_error;
-		u16 dev_password_id;
-	} m2d;
-
-	/**
-	 * struct wps_event_fail - Registration failure information
-	 * @msg: enum wps_msg_type
-	 */
-	struct wps_event_fail {
-		int msg;
-	} fail;
-
-	struct wps_event_pwd_auth_fail {
-		int enrollee;
-		int part;
-	} pwd_auth_fail;
-
-	struct wps_event_er_ap {
-		const u8 *uuid;
-		const u8 *mac_addr;
-		const char *friendly_name;
-		const char *manufacturer;
-		const char *manufacturer_url;
-		const char *model_description;
-		const char *model_name;
-		const char *model_number;
-		const char *model_url;
-		const char *serial_number;
-		const char *upc;
-		const u8 *pri_dev_type;
-		u8 wps_state;
-	} ap;
-
-	struct wps_event_er_enrollee {
-		const u8 *uuid;
-		const u8 *mac_addr;
-		int m1_received;
-		u16 config_methods;
-		u16 dev_passwd_id;
-		const u8 *pri_dev_type;
-		const char *dev_name;
-		const char *manufacturer;
-		const char *model_name;
-		const char *model_number;
-		const char *serial_number;
-	} enrollee;
-};
-
-/**
- * struct upnp_pending_message - Pending PutWLANResponse messages
- * @next: Pointer to next pending message or %NULL
- * @addr: NewWLANEventMAC
- * @msg: NewMessage
- * @type: Message Type
- */
-struct upnp_pending_message {
-	struct upnp_pending_message *next;
-	u8 addr[ETH_ALEN];
-	struct wpabuf *msg;
-	enum wps_msg_type type;
-};
-
-/**
- * struct wps_context - Long term WPS context data
- *
- * This data is stored at the higher layer Authenticator or Supplicant data
- * structures and it is maintained over multiple registration protocol runs.
- */
-struct wps_context {
-	/**
-	 * ap - Whether the local end is an access point
-	 */
-	int ap;
-
-	/**
-	 * registrar - Pointer to WPS registrar data from wps_registrar_init()
-	 */
-	struct wps_registrar *registrar;
-
-	/**
-	 * wps_state - Current WPS state
-	 */
-	enum wps_state wps_state;
-
-	/**
-	 * ap_setup_locked - Whether AP setup is locked (only used at AP)
-	 */
-	int ap_setup_locked;
-
-	/**
-	 * uuid - Own UUID
-	 */
-	u8 uuid[16];
-
-	/**
-	 * ssid - SSID
-	 *
-	 * This SSID is used by the Registrar to fill in information for
-	 * Credentials. In addition, AP uses it when acting as an Enrollee to
-	 * notify Registrar of the current configuration.
-	 */
-	u8 ssid[32];
-
-	/**
-	 * ssid_len - Length of ssid in octets
-	 */
-	size_t ssid_len;
-
-	/**
-	 * dev - Own WPS device data
-	 */
-	struct wps_device_data dev;
-
-	/**
-	 * oob_conf - OOB Config data
-	 */
-	struct oob_conf_data oob_conf;
-
-	/**
-	 * oob_dev_pw_id - OOB Device password id
-	 */
-	u16 oob_dev_pw_id;
-
-	/**
-	 * dh_ctx - Context data for Diffie-Hellman operation
-	 */
-	void *dh_ctx;
-
-	/**
-	 * dh_privkey - Diffie-Hellman private key
-	 */
-	struct wpabuf *dh_privkey;
-
-	/**
-	 * dh_pubkey_oob - Diffie-Hellman public key
-	 */
-	struct wpabuf *dh_pubkey;
-
-	/**
-	 * config_methods - Enabled configuration methods
-	 *
-	 * Bit field of WPS_CONFIG_*
-	 */
-	u16 config_methods;
-
-	/**
-	 * encr_types - Enabled encryption types (bit field of WPS_ENCR_*)
-	 */
-	u16 encr_types;
-
-	/**
-	 * auth_types - Authentication types (bit field of WPS_AUTH_*)
-	 */
-	u16 auth_types;
-
-	/**
-	 * network_key - The current Network Key (PSK) or %NULL to generate new
-	 *
-	 * If %NULL, Registrar will generate per-device PSK. In addition, AP
-	 * uses this when acting as an Enrollee to notify Registrar of the
-	 * current configuration.
-	 *
-	 * When using WPA/WPA2-Person, this key can be either the ASCII
-	 * passphrase (8..63 characters) or the 32-octet PSK (64 hex
-	 * characters). When this is set to the ASCII passphrase, the PSK can
-	 * be provided in the psk buffer and used per-Enrollee to control which
-	 * key type is included in the Credential (e.g., to reduce calculation
-	 * need on low-powered devices by provisioning PSK while still allowing
-	 * other devices to get the passphrase).
-	 */
-	u8 *network_key;
-
-	/**
-	 * network_key_len - Length of network_key in octets
-	 */
-	size_t network_key_len;
-
-	/**
-	 * psk - The current network PSK
-	 *
-	 * This optional value can be used to provide the current PSK if
-	 * network_key is set to the ASCII passphrase.
-	 */
-	u8 psk[32];
-
-	/**
-	 * psk_set - Whether psk value is set
-	 */
-	int psk_set;
-
-	/**
-	 * ap_settings - AP Settings override for M7 (only used at AP)
-	 *
-	 * If %NULL, AP Settings attributes will be generated based on the
-	 * current network configuration.
-	 */
-	u8 *ap_settings;
-
-	/**
-	 * ap_settings_len - Length of ap_settings in octets
-	 */
-	size_t ap_settings_len;
-
-	/**
-	 * friendly_name - Friendly Name (required for UPnP)
-	 */
-	char *friendly_name;
-
-	/**
-	 * manufacturer_url - Manufacturer URL (optional for UPnP)
-	 */
-	char *manufacturer_url;
-
-	/**
-	 * model_description - Model Description (recommended for UPnP)
-	 */
-	char *model_description;
-
-	/**
-	 * model_url - Model URL (optional for UPnP)
-	 */
-	char *model_url;
-
-	/**
-	 * upc - Universal Product Code (optional for UPnP)
-	 */
-	char *upc;
-
-	/**
-	 * cred_cb - Callback to notify that new Credentials were received
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @cred: The received Credential
-	 * Return: 0 on success, -1 on failure
-	 */
-	int (*cred_cb)(void *ctx, const struct wps_credential *cred);
-
-	/**
-	 * event_cb - Event callback (state information about progress)
-	 * @ctx: Higher layer context data (cb_ctx)
-	 * @event: Event type
-	 * @data: Event data
-	 */
-	void (*event_cb)(void *ctx, enum wps_event event,
-			 union wps_event_data *data);
-
-	/**
-	 * cb_ctx: Higher layer context data for callbacks
-	 */
-	void *cb_ctx;
-
-	struct upnp_wps_device_sm *wps_upnp;
-
-	/* Pending messages from UPnP PutWLANResponse */
-	struct upnp_pending_message *upnp_msgs;
-};
-
-struct oob_device_data {
-	char *device_name;
-	char *device_path;
-	void * (*init_func)(struct wps_context *, struct oob_device_data *,
-			    int);
-	struct wpabuf * (*read_func)(void *);
-	int (*write_func)(void *, struct wpabuf *);
-	void (*deinit_func)(void *);
-};
-
-struct oob_nfc_device_data {
-	int (*init_func)(char *);
-	void * (*read_func)(size_t *);
-	int (*write_func)(void *, size_t);
-	void (*deinit_func)(void);
-};
-
-struct wps_registrar *
-wps_registrar_init(struct wps_context *wps,
-		   const struct wps_registrar_config *cfg);
-void wps_registrar_deinit(struct wps_registrar *reg);
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-			  const u8 *pin, size_t pin_len, int timeout);
-int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
-int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
-int wps_registrar_button_pushed(struct wps_registrar *reg);
-void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
-				const struct wpabuf *wps_data);
-int wps_registrar_update_ie(struct wps_registrar *reg);
-int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
-			   char *buf, size_t buflen);
-
-unsigned int wps_pin_checksum(unsigned int pin);
-unsigned int wps_pin_valid(unsigned int pin);
-unsigned int wps_generate_pin(void);
-void wps_free_pending_msgs(struct upnp_pending_message *msgs);
-
-struct oob_device_data * wps_get_oob_device(char *device_type);
-struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name);
-int wps_get_oob_method(char *method);
-int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
-		    int registrar);
-int wps_attr_text(struct wpabuf *data, char *buf, char *end);
-
-struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname);
-void wps_er_refresh(struct wps_er *er);
-void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
-void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
-			u16 sel_reg_config_methods);
-int wps_er_pbc(struct wps_er *er, const u8 *uuid);
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		 size_t pin_len);
-
-int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
-char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
-			    size_t buf_len);
-void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
-u16 wps_config_methods_str2bin(const char *str);
-
-#endif /* WPS_H */

Copied: vendor/wpa/2.0/src/wps/wps.h (from rev 9639, vendor/wpa/dist/src/wps/wps.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,968 @@
+/*
+ * Wi-Fi Protected Setup
+ * Copyright (c) 2007-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_H
+#define WPS_H
+
+#include "wps_defs.h"
+
+/**
+ * enum wsc_op_code - EAP-WSC OP-Code values
+ */
+enum wsc_op_code {
+	WSC_UPnP = 0 /* No OP Code in UPnP transport */,
+	WSC_Start = 0x01,
+	WSC_ACK = 0x02,
+	WSC_NACK = 0x03,
+	WSC_MSG = 0x04,
+	WSC_Done = 0x05,
+	WSC_FRAG_ACK = 0x06
+};
+
+struct wps_registrar;
+struct upnp_wps_device_sm;
+struct wps_er;
+struct wps_parse_attr;
+
+/**
+ * struct wps_credential - WPS Credential
+ * @ssid: SSID
+ * @ssid_len: Length of SSID
+ * @auth_type: Authentication Type (WPS_AUTH_OPEN, .. flags)
+ * @encr_type: Encryption Type (WPS_ENCR_NONE, .. flags)
+ * @key_idx: Key index
+ * @key: Key
+ * @key_len: Key length in octets
+ * @mac_addr: MAC address of the Credential receiver
+ * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
+ *	this may be %NULL, if not used
+ * @cred_attr_len: Length of cred_attr in octets
+ * @ap_channel: AP channel
+ */
+struct wps_credential {
+	u8 ssid[32];
+	size_t ssid_len;
+	u16 auth_type;
+	u16 encr_type;
+	u8 key_idx;
+	u8 key[64];
+	size_t key_len;
+	u8 mac_addr[ETH_ALEN];
+	const u8 *cred_attr;
+	size_t cred_attr_len;
+	u16 ap_channel;
+};
+
+#define WPS_DEV_TYPE_LEN 8
+#define WPS_DEV_TYPE_BUFSIZE 21
+#define WPS_SEC_DEV_TYPE_MAX_LEN 128
+/* maximum number of advertised WPS vendor extension attributes */
+#define MAX_WPS_VENDOR_EXTENSIONS 10
+/* maximum size of WPS Vendor extension attribute */
+#define WPS_MAX_VENDOR_EXT_LEN 1024
+/* maximum number of parsed WPS vendor extension attributes */
+#define MAX_WPS_PARSE_VENDOR_EXT 10
+
+/**
+ * struct wps_device_data - WPS Device Data
+ * @mac_addr: Device MAC address
+ * @device_name: Device Name (0..32 octets encoded in UTF-8)
+ * @manufacturer: Manufacturer (0..64 octets encoded in UTF-8)
+ * @model_name: Model Name (0..32 octets encoded in UTF-8)
+ * @model_number: Model Number (0..32 octets encoded in UTF-8)
+ * @serial_number: Serial Number (0..32 octets encoded in UTF-8)
+ * @pri_dev_type: Primary Device Type
+ * @sec_dev_type: Array of secondary device types
+ * @num_sec_dev_type: Number of secondary device types
+ * @os_version: OS Version
+ * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
+ * @p2p: Whether the device is a P2P device
+ */
+struct wps_device_data {
+	u8 mac_addr[ETH_ALEN];
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u8 pri_dev_type[WPS_DEV_TYPE_LEN];
+#define WPS_SEC_DEVICE_TYPES 5
+	u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+	u8 num_sec_dev_types;
+	u32 os_version;
+	u8 rf_bands;
+	u16 config_methods;
+	struct wpabuf *vendor_ext_m1;
+	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+
+	int p2p;
+};
+
+/**
+ * struct wps_config - WPS configuration for a single registration protocol run
+ */
+struct wps_config {
+	/**
+	 * wps - Pointer to long term WPS context
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * registrar - Whether this end is a Registrar
+	 */
+	int registrar;
+
+	/**
+	 * pin - Enrollee Device Password (%NULL for Registrar or PBC)
+	 */
+	const u8 *pin;
+
+	/**
+	 * pin_len - Length on pin in octets
+	 */
+	size_t pin_len;
+
+	/**
+	 * pbc - Whether this is protocol run uses PBC
+	 */
+	int pbc;
+
+	/**
+	 * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
+	 */
+	const struct wpabuf *assoc_wps_ie;
+
+	/**
+	 * new_ap_settings - New AP settings (%NULL if not used)
+	 *
+	 * This parameter provides new AP settings when using a wireless
+	 * stations as a Registrar to configure the AP. %NULL means that AP
+	 * will not be reconfigured, i.e., the station will only learn the
+	 * current AP settings by using AP PIN.
+	 */
+	const struct wps_credential *new_ap_settings;
+
+	/**
+	 * peer_addr: MAC address of the peer in AP; %NULL if not AP
+	 */
+	const u8 *peer_addr;
+
+	/**
+	 * use_psk_key - Use PSK format key in Credential
+	 *
+	 * Force PSK format to be used instead of ASCII passphrase when
+	 * building Credential for an Enrollee. The PSK value is set in
+	 * struct wpa_context::psk.
+	 */
+	int use_psk_key;
+
+	/**
+	 * dev_pw_id - Device Password ID for Enrollee when PIN is used
+	 */
+	u16 dev_pw_id;
+
+	/**
+	 * p2p_dev_addr - P2P Device Address from (Re)Association Request
+	 *
+	 * On AP/GO, this is set to the P2P Device Address of the associating
+	 * P2P client if a P2P IE is included in the (Re)Association Request
+	 * frame and the P2P Device Address is included. Otherwise, this is set
+	 * to %NULL to indicate the station does not have a P2P Device Address.
+	 */
+	const u8 *p2p_dev_addr;
+
+	/**
+	 * pbc_in_m1 - Do not remove PushButton config method in M1 (AP)
+	 *
+	 * This can be used to enable a workaround to allow Windows 7 to use
+	 * PBC with the AP.
+	 */
+	int pbc_in_m1;
+};
+
+struct wps_data * wps_init(const struct wps_config *cfg);
+
+void wps_deinit(struct wps_data *data);
+
+/**
+ * enum wps_process_res - WPS message processing result
+ */
+enum wps_process_res {
+	/**
+	 * WPS_DONE - Processing done
+	 */
+	WPS_DONE,
+
+	/**
+	 * WPS_CONTINUE - Processing continues
+	 */
+	WPS_CONTINUE,
+
+	/**
+	 * WPS_FAILURE - Processing failed
+	 */
+	WPS_FAILURE,
+
+	/**
+	 * WPS_PENDING - Processing continues, but waiting for an external
+	 *	event (e.g., UPnP message from an external Registrar)
+	 */
+	WPS_PENDING
+};
+enum wps_process_res wps_process_msg(struct wps_data *wps,
+				     enum wsc_op_code op_code,
+				     const struct wpabuf *msg);
+
+struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
+
+int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
+int wps_is_selected_pin_registrar(const struct wpabuf *msg);
+int wps_ap_priority_compar(const struct wpabuf *wps_a,
+			   const struct wpabuf *wps_b);
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+			   int ver1_compat);
+const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
+
+struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
+struct wpabuf * wps_build_assoc_resp_ie(void);
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
+				       const u8 *uuid,
+				       enum wps_request_type req_type,
+				       unsigned int num_req_dev_types,
+				       const u8 *req_dev_types);
+
+
+/**
+ * struct wps_registrar_config - WPS Registrar configuration
+ */
+struct wps_registrar_config {
+	/**
+	 * new_psk_cb - Callback for new PSK
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @mac_addr: MAC address of the Enrollee
+	 * @psk: The new PSK
+	 * @psk_len: The length of psk in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called when a new per-device PSK is provisioned.
+	 */
+	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
+			  size_t psk_len);
+
+	/**
+	 * set_ie_cb - Callback for WPS IE changes
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @beacon_ie: WPS IE for Beacon
+	 * @probe_resp_ie: WPS IE for Probe Response
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called whenever the WPS IE in Beacon or Probe
+	 * Response frames needs to be changed (AP only). Callee is responsible
+	 * for freeing the buffers.
+	 */
+	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
+			 struct wpabuf *probe_resp_ie);
+
+	/**
+	 * pin_needed_cb - Callback for requesting a PIN
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @uuid_e: UUID-E of the unknown Enrollee
+	 * @dev: Device Data from the unknown Enrollee
+	 *
+	 * This callback is called whenever an unknown Enrollee requests to use
+	 * PIN method and a matching PIN (Device Password) is not found in
+	 * Registrar data.
+	 */
+	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
+			      const struct wps_device_data *dev);
+
+	/**
+	 * reg_success_cb - Callback for reporting successful registration
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @mac_addr: MAC address of the Enrollee
+	 * @uuid_e: UUID-E of the Enrollee
+	 * @dev_pw: Device Password (PIN) used during registration
+	 * @dev_pw_len: Length of dev_pw in octets
+	 *
+	 * This callback is called whenever an Enrollee completes registration
+	 * successfully.
+	 */
+	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
+			       const u8 *uuid_e, const u8 *dev_pw,
+			       size_t dev_pw_len);
+
+	/**
+	 * set_sel_reg_cb - Callback for reporting selected registrar changes
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @sel_reg: Whether the Registrar is selected
+	 * @dev_passwd_id: Device Password ID to indicate with method or
+	 *	specific password the Registrar intends to use
+	 * @sel_reg_config_methods: Bit field of active config methods
+	 *
+	 * This callback is called whenever the Selected Registrar state
+	 * changes (e.g., a new PIN becomes available or PBC is invoked). This
+	 * callback is only used by External Registrar implementation;
+	 * set_ie_cb() is used by AP implementation in similar caes, but it
+	 * provides the full WPS IE data instead of just the minimal Registrar
+	 * state information.
+	 */
+	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
+			       u16 sel_reg_config_methods);
+
+	/**
+	 * enrollee_seen_cb - Callback for reporting Enrollee based on ProbeReq
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @addr: MAC address of the Enrollee
+	 * @uuid_e: UUID of the Enrollee
+	 * @pri_dev_type: Primary device type
+	 * @config_methods: Config Methods
+	 * @dev_password_id: Device Password ID
+	 * @request_type: Request Type
+	 * @dev_name: Device Name (if available)
+	 */
+	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
+				 const u8 *pri_dev_type, u16 config_methods,
+				 u16 dev_password_id, u8 request_type,
+				 const char *dev_name);
+
+	/**
+	 * cb_ctx: Higher layer context data for Registrar callbacks
+	 */
+	void *cb_ctx;
+
+	/**
+	 * skip_cred_build: Do not build credential
+	 *
+	 * This option can be used to disable internal code that builds
+	 * Credential attribute into M8 based on the current network
+	 * configuration and Enrollee capabilities. The extra_cred data will
+	 * then be used as the Credential(s).
+	 */
+	int skip_cred_build;
+
+	/**
+	 * extra_cred: Additional Credential attribute(s)
+	 *
+	 * This optional data (set to %NULL to disable) can be used to add
+	 * Credential attribute(s) for other networks into M8. If
+	 * skip_cred_build is set, this will also override the automatically
+	 * generated Credential attribute.
+	 */
+	const u8 *extra_cred;
+
+	/**
+	 * extra_cred_len: Length of extra_cred in octets
+	 */
+	size_t extra_cred_len;
+
+	/**
+	 * disable_auto_conf - Disable auto-configuration on first registration
+	 *
+	 * By default, the AP that is started in not configured state will
+	 * generate a random PSK and move to configured state when the first
+	 * registration protocol run is completed successfully. This option can
+	 * be used to disable this functionality and leave it up to an external
+	 * program to take care of configuration. This requires the extra_cred
+	 * to be set with a suitable Credential and skip_cred_build being used.
+	 */
+	int disable_auto_conf;
+
+	/**
+	 * static_wep_only - Whether the BSS supports only static WEP
+	 */
+	int static_wep_only;
+
+	/**
+	 * dualband - Whether this is a concurrent dualband AP
+	 */
+	int dualband;
+};
+
+
+/**
+ * enum wps_event - WPS event types
+ */
+enum wps_event {
+	/**
+	 * WPS_EV_M2D - M2D received (Registrar did not know us)
+	 */
+	WPS_EV_M2D,
+
+	/**
+	 * WPS_EV_FAIL - Registration failed
+	 */
+	WPS_EV_FAIL,
+
+	/**
+	 * WPS_EV_SUCCESS - Registration succeeded
+	 */
+	WPS_EV_SUCCESS,
+
+	/**
+	 * WPS_EV_PWD_AUTH_FAIL - Password authentication failed
+	 */
+	WPS_EV_PWD_AUTH_FAIL,
+
+	/**
+	 * WPS_EV_PBC_OVERLAP - PBC session overlap detected
+	 */
+	WPS_EV_PBC_OVERLAP,
+
+	/**
+	 * WPS_EV_PBC_TIMEOUT - PBC walktime expired before protocol run start
+	 */
+	WPS_EV_PBC_TIMEOUT,
+
+	/**
+	 * WPS_EV_ER_AP_ADD - ER: AP added
+	 */
+	WPS_EV_ER_AP_ADD,
+
+	/**
+	 * WPS_EV_ER_AP_REMOVE - ER: AP removed
+	 */
+	WPS_EV_ER_AP_REMOVE,
+
+	/**
+	 * WPS_EV_ER_ENROLLEE_ADD - ER: Enrollee added
+	 */
+	WPS_EV_ER_ENROLLEE_ADD,
+
+	/**
+	 * WPS_EV_ER_ENROLLEE_REMOVE - ER: Enrollee removed
+	 */
+	WPS_EV_ER_ENROLLEE_REMOVE,
+
+	/**
+	 * WPS_EV_ER_AP_SETTINGS - ER: AP Settings learned
+	 */
+	WPS_EV_ER_AP_SETTINGS,
+
+	/**
+	 * WPS_EV_ER_SET_SELECTED_REGISTRAR - ER: SetSelectedRegistrar event
+	 */
+	WPS_EV_ER_SET_SELECTED_REGISTRAR,
+
+	/**
+	 * WPS_EV_AP_PIN_SUCCESS - External Registrar used correct AP PIN
+	 */
+	WPS_EV_AP_PIN_SUCCESS
+};
+
+/**
+ * union wps_event_data - WPS event data
+ */
+union wps_event_data {
+	/**
+	 * struct wps_event_m2d - M2D event data
+	 */
+	struct wps_event_m2d {
+		u16 config_methods;
+		const u8 *manufacturer;
+		size_t manufacturer_len;
+		const u8 *model_name;
+		size_t model_name_len;
+		const u8 *model_number;
+		size_t model_number_len;
+		const u8 *serial_number;
+		size_t serial_number_len;
+		const u8 *dev_name;
+		size_t dev_name_len;
+		const u8 *primary_dev_type; /* 8 octets */
+		u16 config_error;
+		u16 dev_password_id;
+	} m2d;
+
+	/**
+	 * struct wps_event_fail - Registration failure information
+	 * @msg: enum wps_msg_type
+	 */
+	struct wps_event_fail {
+		int msg;
+		u16 config_error;
+		u16 error_indication;
+	} fail;
+
+	struct wps_event_pwd_auth_fail {
+		int enrollee;
+		int part;
+	} pwd_auth_fail;
+
+	struct wps_event_er_ap {
+		const u8 *uuid;
+		const u8 *mac_addr;
+		const char *friendly_name;
+		const char *manufacturer;
+		const char *manufacturer_url;
+		const char *model_description;
+		const char *model_name;
+		const char *model_number;
+		const char *model_url;
+		const char *serial_number;
+		const char *upc;
+		const u8 *pri_dev_type;
+		u8 wps_state;
+	} ap;
+
+	struct wps_event_er_enrollee {
+		const u8 *uuid;
+		const u8 *mac_addr;
+		int m1_received;
+		u16 config_methods;
+		u16 dev_passwd_id;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		const char *manufacturer;
+		const char *model_name;
+		const char *model_number;
+		const char *serial_number;
+	} enrollee;
+
+	struct wps_event_er_ap_settings {
+		const u8 *uuid;
+		const struct wps_credential *cred;
+	} ap_settings;
+
+	struct wps_event_er_set_selected_registrar {
+		const u8 *uuid;
+		int sel_reg;
+		u16 dev_passwd_id;
+		u16 sel_reg_config_methods;
+		enum {
+			WPS_ER_SET_SEL_REG_START,
+			WPS_ER_SET_SEL_REG_DONE,
+			WPS_ER_SET_SEL_REG_FAILED
+		} state;
+	} set_sel_reg;
+};
+
+/**
+ * struct upnp_pending_message - Pending PutWLANResponse messages
+ * @next: Pointer to next pending message or %NULL
+ * @addr: NewWLANEventMAC
+ * @msg: NewMessage
+ * @type: Message Type
+ */
+struct upnp_pending_message {
+	struct upnp_pending_message *next;
+	u8 addr[ETH_ALEN];
+	struct wpabuf *msg;
+	enum wps_msg_type type;
+};
+
+/**
+ * struct wps_context - Long term WPS context data
+ *
+ * This data is stored at the higher layer Authenticator or Supplicant data
+ * structures and it is maintained over multiple registration protocol runs.
+ */
+struct wps_context {
+	/**
+	 * ap - Whether the local end is an access point
+	 */
+	int ap;
+
+	/**
+	 * registrar - Pointer to WPS registrar data from wps_registrar_init()
+	 */
+	struct wps_registrar *registrar;
+
+	/**
+	 * wps_state - Current WPS state
+	 */
+	enum wps_state wps_state;
+
+	/**
+	 * ap_setup_locked - Whether AP setup is locked (only used at AP)
+	 */
+	int ap_setup_locked;
+
+	/**
+	 * uuid - Own UUID
+	 */
+	u8 uuid[16];
+
+	/**
+	 * ssid - SSID
+	 *
+	 * This SSID is used by the Registrar to fill in information for
+	 * Credentials. In addition, AP uses it when acting as an Enrollee to
+	 * notify Registrar of the current configuration.
+	 */
+	u8 ssid[32];
+
+	/**
+	 * ssid_len - Length of ssid in octets
+	 */
+	size_t ssid_len;
+
+	/**
+	 * dev - Own WPS device data
+	 */
+	struct wps_device_data dev;
+
+	/**
+	 * dh_ctx - Context data for Diffie-Hellman operation
+	 */
+	void *dh_ctx;
+
+	/**
+	 * dh_privkey - Diffie-Hellman private key
+	 */
+	struct wpabuf *dh_privkey;
+
+	/**
+	 * dh_pubkey_oob - Diffie-Hellman public key
+	 */
+	struct wpabuf *dh_pubkey;
+
+	/**
+	 * config_methods - Enabled configuration methods
+	 *
+	 * Bit field of WPS_CONFIG_*
+	 */
+	u16 config_methods;
+
+	/**
+	 * encr_types - Enabled encryption types (bit field of WPS_ENCR_*)
+	 */
+	u16 encr_types;
+
+	/**
+	 * auth_types - Authentication types (bit field of WPS_AUTH_*)
+	 */
+	u16 auth_types;
+
+	/**
+	 * network_key - The current Network Key (PSK) or %NULL to generate new
+	 *
+	 * If %NULL, Registrar will generate per-device PSK. In addition, AP
+	 * uses this when acting as an Enrollee to notify Registrar of the
+	 * current configuration.
+	 *
+	 * When using WPA/WPA2-Person, this key can be either the ASCII
+	 * passphrase (8..63 characters) or the 32-octet PSK (64 hex
+	 * characters). When this is set to the ASCII passphrase, the PSK can
+	 * be provided in the psk buffer and used per-Enrollee to control which
+	 * key type is included in the Credential (e.g., to reduce calculation
+	 * need on low-powered devices by provisioning PSK while still allowing
+	 * other devices to get the passphrase).
+	 */
+	u8 *network_key;
+
+	/**
+	 * network_key_len - Length of network_key in octets
+	 */
+	size_t network_key_len;
+
+	/**
+	 * psk - The current network PSK
+	 *
+	 * This optional value can be used to provide the current PSK if
+	 * network_key is set to the ASCII passphrase.
+	 */
+	u8 psk[32];
+
+	/**
+	 * psk_set - Whether psk value is set
+	 */
+	int psk_set;
+
+	/**
+	 * ap_settings - AP Settings override for M7 (only used at AP)
+	 *
+	 * If %NULL, AP Settings attributes will be generated based on the
+	 * current network configuration.
+	 */
+	u8 *ap_settings;
+
+	/**
+	 * ap_settings_len - Length of ap_settings in octets
+	 */
+	size_t ap_settings_len;
+
+	/**
+	 * friendly_name - Friendly Name (required for UPnP)
+	 */
+	char *friendly_name;
+
+	/**
+	 * manufacturer_url - Manufacturer URL (optional for UPnP)
+	 */
+	char *manufacturer_url;
+
+	/**
+	 * model_description - Model Description (recommended for UPnP)
+	 */
+	char *model_description;
+
+	/**
+	 * model_url - Model URL (optional for UPnP)
+	 */
+	char *model_url;
+
+	/**
+	 * upc - Universal Product Code (optional for UPnP)
+	 */
+	char *upc;
+
+	/**
+	 * cred_cb - Callback to notify that new Credentials were received
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @cred: The received Credential
+	 * Return: 0 on success, -1 on failure
+	 */
+	int (*cred_cb)(void *ctx, const struct wps_credential *cred);
+
+	/**
+	 * event_cb - Event callback (state information about progress)
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @event: Event type
+	 * @data: Event data
+	 */
+	void (*event_cb)(void *ctx, enum wps_event event,
+			 union wps_event_data *data);
+
+	/**
+	 * cb_ctx: Higher layer context data for callbacks
+	 */
+	void *cb_ctx;
+
+	struct upnp_wps_device_sm *wps_upnp;
+
+	/* Pending messages from UPnP PutWLANResponse */
+	struct upnp_pending_message *upnp_msgs;
+
+	u16 ap_nfc_dev_pw_id;
+	struct wpabuf *ap_nfc_dh_pubkey;
+	struct wpabuf *ap_nfc_dh_privkey;
+	struct wpabuf *ap_nfc_dev_pw;
+};
+
+struct wps_registrar *
+wps_registrar_init(struct wps_context *wps,
+		   const struct wps_registrar_config *cfg);
+void wps_registrar_deinit(struct wps_registrar *reg);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+			  const u8 *uuid, const u8 *pin, size_t pin_len,
+			  int timeout);
+int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_wps_cancel(struct wps_registrar *reg);
+int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_button_pushed(struct wps_registrar *reg,
+				const u8 *p2p_dev_addr);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+			    const u8 *dev_pw, size_t dev_pw_len);
+void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
+				const struct wpabuf *wps_data,
+				int p2p_wildcard);
+int wps_registrar_update_ie(struct wps_registrar *reg);
+int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
+			   char *buf, size_t buflen);
+int wps_registrar_config_ap(struct wps_registrar *reg,
+			    struct wps_credential *cred);
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+				   const u8 *pubkey_hash, u16 pw_id,
+				   const u8 *dev_pw, size_t dev_pw_len);
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+					 const u8 *oob_dev_pw,
+					 size_t oob_dev_pw_len);
+
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred);
+
+unsigned int wps_pin_checksum(unsigned int pin);
+unsigned int wps_pin_valid(unsigned int pin);
+unsigned int wps_generate_pin(void);
+int wps_pin_str_valid(const char *pin);
+void wps_free_pending_msgs(struct upnp_pending_message *msgs);
+
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
+int wps_attr_text(struct wpabuf *data, char *buf, char *end);
+
+struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
+			    const char *filter);
+void wps_er_refresh(struct wps_er *er);
+void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
+void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
+			u16 sel_reg_config_methods);
+int wps_er_pbc(struct wps_er *er, const u8 *uuid);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		 size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+		      const struct wps_credential *cred);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		  size_t pin_len, const struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
+
+int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
+char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
+			    size_t buf_len);
+void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
+u16 wps_config_methods_str2bin(const char *str);
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+				       const struct wpabuf *pubkey,
+				       const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+				  struct wpabuf **privkey,
+				  struct wpabuf **dev_pw);
+
+/* ndef.c */
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hr(void);
+
+#ifdef CONFIG_WPS_STRICT
+int wps_validate_beacon(const struct wpabuf *wps_ie);
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,
+				   const u8 *addr);
+int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr);
+int wps_validate_assoc_req(const struct wpabuf *wps_ie);
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie);
+int wps_validate_m1(const struct wpabuf *tlvs);
+int wps_validate_m2(const struct wpabuf *tlvs);
+int wps_validate_m2d(const struct wpabuf *tlvs);
+int wps_validate_m3(const struct wpabuf *tlvs);
+int wps_validate_m4(const struct wpabuf *tlvs);
+int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m5(const struct wpabuf *tlvs);
+int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m6(const struct wpabuf *tlvs);
+int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m7(const struct wpabuf *tlvs);
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_m8(const struct wpabuf *tlvs);
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_wsc_ack(const struct wpabuf *tlvs);
+int wps_validate_wsc_nack(const struct wpabuf *tlvs);
+int wps_validate_wsc_done(const struct wpabuf *tlvs);
+int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs);
+#else /* CONFIG_WPS_STRICT */
+static inline int wps_validate_beacon(const struct wpabuf *wps_ie){
+	return 0;
+}
+
+static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,
+						 int probe, const u8 *addr)
+{
+	return 0;
+}
+
+static inline int wps_validate_probe_req(const struct wpabuf *wps_ie,
+					 const u8 *addr)
+{
+	return 0;
+}
+
+static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+	return 0;
+}
+
+static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+	return 0;
+}
+
+static inline int wps_validate_m1(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m2(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m3(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m4(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m5(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m6(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m7(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap,
+				       int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m8(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap,
+				       int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_upnp_set_selected_registrar(
+	const struct wpabuf *tlvs)
+{
+	return 0;
+}
+#endif /* CONFIG_WPS_STRICT */
+
+#endif /* WPS_H */

Deleted: vendor/wpa/2.0/src/wps/wps_attr_build.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_attr_build.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_attr_build.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,322 +0,0 @@
-/*
- * Wi-Fi Protected Setup - attribute building
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "crypto/dh_group5.h"
-#include "crypto/sha256.h"
-#include "wps_i.h"
-
-
-int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
-{
-	struct wpabuf *pubkey;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
-	wpabuf_free(wps->dh_privkey);
-	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
-		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
-		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
-		wps->dh_ctx = wps->wps->dh_ctx;
-		wps->wps->dh_ctx = NULL;
-		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
-	} else {
-		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
-		wps->dh_privkey = NULL;
-		dh5_free(wps->dh_ctx);
-		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
-		pubkey = wpabuf_zeropad(pubkey, 192);
-	}
-	if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
-			   "Diffie-Hellman handshake");
-		wpabuf_free(pubkey);
-		return -1;
-	}
-
-	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
-	wpabuf_put_be16(msg, wpabuf_len(pubkey));
-	wpabuf_put_buf(msg, pubkey);
-
-	if (wps->registrar) {
-		wpabuf_free(wps->dh_pubkey_r);
-		wps->dh_pubkey_r = pubkey;
-	} else {
-		wpabuf_free(wps->dh_pubkey_e);
-		wps->dh_pubkey_e = pubkey;
-	}
-
-	return 0;
-}
-
-
-int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
-	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, type);
-	return 0;
-}
-
-
-int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Response Type (%d)", type);
-	wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, type);
-	return 0;
-}
-
-
-int wps_build_config_methods(struct wpabuf *msg, u16 methods)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
-	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, methods);
-	return 0;
-}
-
-
-int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
-	wpabuf_put_be16(msg, ATTR_UUID_E);
-	wpabuf_put_be16(msg, WPS_UUID_LEN);
-	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
-	return 0;
-}
-
-
-int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
-	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, id);
-	return 0;
-}
-
-
-int wps_build_config_error(struct wpabuf *msg, u16 err)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
-	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, err);
-	return 0;
-}
-
-
-int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	if (wps->last_msg == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
-			   "building authenticator");
-		return -1;
-	}
-
-	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
-	 * (M_curr* is M_curr without the Authenticator attribute)
-	 */
-	addr[0] = wpabuf_head(wps->last_msg);
-	len[0] = wpabuf_len(wps->last_msg);
-	addr[1] = wpabuf_head(msg);
-	len[1] = wpabuf_len(msg);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
-	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
-	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
-	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
-
-	return 0;
-}
-
-
-int wps_build_version(struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Version");
-	wpabuf_put_be16(msg, ATTR_VERSION);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, WPS_VERSION);
-	return 0;
-}
-
-
-int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
-	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, msg_type);
-	return 0;
-}
-
-
-int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
-	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
-	return 0;
-}
-
-
-int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
-	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
-	return 0;
-}
-
-
-int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
-	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_AUTH_TYPES);
-	return 0;
-}
-
-
-int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
-	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_ENCR_TYPES);
-	return 0;
-}
-
-
-int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
-	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, WPS_CONN_ESS);
-	return 0;
-}
-
-
-int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
-	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
-	return 0;
-}
-
-
-int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
-	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
-		    wpabuf_len(msg), hash);
-
-	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
-	wpabuf_put_be16(msg, WPS_KWA_LEN);
-	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
-	return 0;
-}
-
-
-int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
-			    struct wpabuf *plain)
-{
-	size_t pad_len;
-	const size_t block_size = 16;
-	u8 *iv, *data;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
-
-	/* PKCS#5 v2.0 pad */
-	pad_len = block_size - wpabuf_len(plain) % block_size;
-	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
-
-	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
-	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
-
-	iv = wpabuf_put(msg, block_size);
-	if (os_get_random(iv, block_size) < 0)
-		return -1;
-
-	data = wpabuf_put(msg, 0);
-	wpabuf_put_buf(msg, plain);
-	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
-		return -1;
-
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
-{
-	size_t hash_len;
-	const u8 *addr[1];
-	u8 pubkey_hash[WPS_HASH_LEN];
-	u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
-
-	wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password");
-
-	addr[0] = wpabuf_head(wps->dh_pubkey);
-	hash_len = wpabuf_len(wps->dh_pubkey);
-	sha256_vector(1, addr, &hash_len, pubkey_hash);
-
-	if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
-		wpa_printf(MSG_ERROR, "WPS: device password id "
-			   "generation error");
-		return -1;
-	}
-	wps->oob_dev_pw_id |= 0x0010;
-
-	if (os_get_random(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) < 0) {
-		wpa_printf(MSG_ERROR, "WPS: OOB device password "
-			   "generation error");
-		return -1;
-	}
-
-	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
-	wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
-	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
-	wpabuf_put_be16(msg, wps->oob_dev_pw_id);
-	wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
-	wpa_snprintf_hex_uppercase(
-		wpabuf_put(wps->oob_conf.dev_password,
-			   wpabuf_size(wps->oob_conf.dev_password)),
-		wpabuf_size(wps->oob_conf.dev_password),
-		dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
-	return 0;
-}
-#endif /* CONFIG_WPS_OOB */

Copied: vendor/wpa/2.0/src/wps/wps_attr_build.c (from rev 9639, vendor/wpa/dist/src/wps/wps_attr_build.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_attr_build.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_attr_build.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,403 @@
+/*
+ * Wi-Fi Protected Setup - attribute building
+ * Copyright (c) 2008, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_group5.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "wps_i.h"
+
+
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
+{
+	struct wpabuf *pubkey;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
+	wpabuf_free(wps->dh_privkey);
+	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
+		wps->dh_ctx = wps->wps->dh_ctx;
+		wps->wps->dh_ctx = NULL;
+		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
+#ifdef CONFIG_WPS_NFC
+	} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
+		   wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+		wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+		wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
+		pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
+		wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+#endif /* CONFIG_WPS_NFC */
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
+		wps->dh_privkey = NULL;
+		dh5_free(wps->dh_ctx);
+		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
+		pubkey = wpabuf_zeropad(pubkey, 192);
+	}
+	if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
+			   "Diffie-Hellman handshake");
+		wpabuf_free(pubkey);
+		return -1;
+	}
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
+
+	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
+	wpabuf_put_be16(msg, wpabuf_len(pubkey));
+	wpabuf_put_buf(msg, pubkey);
+
+	if (wps->registrar) {
+		wpabuf_free(wps->dh_pubkey_r);
+		wps->dh_pubkey_r = pubkey;
+	} else {
+		wpabuf_free(wps->dh_pubkey_e);
+		wps->dh_pubkey_e = pubkey;
+	}
+
+	return 0;
+}
+
+
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
+	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, type);
+	return 0;
+}
+
+
+int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Response Type (%d)", type);
+	wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, type);
+	return 0;
+}
+
+
+int wps_build_config_methods(struct wpabuf *msg, u16 methods)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
+	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
+	wpabuf_put_be16(msg, ATTR_UUID_E);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
+	return 0;
+}
+
+
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, id);
+	return 0;
+}
+
+
+int wps_build_config_error(struct wpabuf *msg, u16 err)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
+	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, err);
+	return 0;
+}
+
+
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "building authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
+	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
+	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
+	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
+
+	return 0;
+}
+
+
+int wps_build_version(struct wpabuf *msg)
+{
+	/*
+	 * Note: This attribute is deprecated and set to hardcoded 0x10 for
+	 * backwards compatibility reasons. The real version negotiation is
+	 * done with Version2.
+	 */
+	wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
+	wpabuf_put_be16(msg, ATTR_VERSION);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, 0x10);
+	return 0;
+}
+
+
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+		      const u8 *auth_macs, size_t auth_macs_count)
+{
+#ifdef CONFIG_WPS2
+	u8 *len;
+
+	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+	len = wpabuf_put(msg, 2); /* to be filled */
+	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Version2 (0x%x)", WPS_VERSION);
+	wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
+	wpabuf_put_u8(msg, 1);
+	wpabuf_put_u8(msg, WPS_VERSION);
+
+	if (req_to_enroll) {
+		wpa_printf(MSG_DEBUG, "WPS:  * Request to Enroll (1)");
+		wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
+		wpabuf_put_u8(msg, 1);
+		wpabuf_put_u8(msg, 1);
+	}
+
+	if (auth_macs && auth_macs_count) {
+		size_t i;
+		wpa_printf(MSG_DEBUG, "WPS:  * AuthorizedMACs (count=%d)",
+			   (int) auth_macs_count);
+		wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
+		wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
+		wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
+		for (i = 0; i < auth_macs_count; i++)
+			wpa_printf(MSG_DEBUG, "WPS:    AuthorizedMAC: " MACSTR,
+				   MAC2STR(&auth_macs[i * ETH_ALEN]));
+	}
+
+	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_WPS_TESTING
+	if (WPS_VERSION > 0x20) {
+		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
+			   "attribute");
+		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, 42);
+	}
+#endif /* CONFIG_WPS_TESTING */
+	return 0;
+}
+
+
+int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
+	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, msg_type);
+	return 0;
+}
+
+
+int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
+	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
+	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	u16 auth_types = WPS_AUTH_TYPES;
+#ifdef CONFIG_WPS2
+	auth_types &= ~WPS_AUTH_SHARED;
+#endif /* CONFIG_WPS2 */
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, auth_types);
+	return 0;
+}
+
+
+int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	u16 encr_types = WPS_ENCR_TYPES;
+#ifdef CONFIG_WPS2
+	encr_types &= ~WPS_ENCR_WEP;
+#endif /* CONFIG_WPS2 */
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, encr_types);
+	return 0;
+}
+
+
+int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
+	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_CONN_ESS);
+	return 0;
+}
+
+
+int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
+	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
+	return 0;
+}
+
+
+int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+		    wpabuf_len(msg), hash);
+
+	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
+	wpabuf_put_be16(msg, WPS_KWA_LEN);
+	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
+	return 0;
+}
+
+
+int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
+			    struct wpabuf *plain)
+{
+	size_t pad_len;
+	const size_t block_size = 16;
+	u8 *iv, *data;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
+
+	/* PKCS#5 v2.0 pad */
+	pad_len = block_size - wpabuf_len(plain) % block_size;
+	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
+
+	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
+	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
+
+	iv = wpabuf_put(msg, block_size);
+	if (random_get_bytes(iv, block_size) < 0)
+		return -1;
+
+	data = wpabuf_put(msg, 0);
+	wpabuf_put_buf(msg, plain);
+	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
+		return -1;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_OOB
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+			 const struct wpabuf *pubkey, const u8 *dev_pw,
+			 size_t dev_pw_len)
+{
+	size_t hash_len;
+	const u8 *addr[1];
+	u8 pubkey_hash[WPS_HASH_LEN];
+
+	addr[0] = wpabuf_head(pubkey);
+	hash_len = wpabuf_len(pubkey);
+	sha256_vector(1, addr, &hash_len, pubkey_hash);
+
+	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
+	wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
+	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+	wpabuf_put_be16(msg, dev_pw_id);
+	wpabuf_put_data(msg, dev_pw, dev_pw_len);
+
+	return 0;
+}
+#endif /* CONFIG_WPS_OOB */
+
+
+/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
+struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
+{
+	struct wpabuf *ie;
+	const u8 *pos, *end;
+
+	ie = wpabuf_alloc(wpabuf_len(data) + 100);
+	if (ie == NULL) {
+		wpabuf_free(data);
+		return NULL;
+	}
+
+	pos = wpabuf_head(data);
+	end = pos + wpabuf_len(data);
+
+	while (end > pos) {
+		size_t frag_len = end - pos;
+		if (frag_len > 251)
+			frag_len = 251;
+		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+		wpabuf_put_u8(ie, 4 + frag_len);
+		wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+		wpabuf_put_data(ie, pos, frag_len);
+		pos += frag_len;
+	}
+
+	wpabuf_free(data);
+
+	return ie;
+}

Deleted: vendor/wpa/2.0/src/wps/wps_attr_parse.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_attr_parse.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_attr_parse.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,466 +0,0 @@
-/*
- * Wi-Fi Protected Setup - attribute parsing
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wps_i.h"
-
-#define WPS_WORKAROUNDS
-
-
-static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
-			const u8 *pos, u16 len)
-{
-	switch (type) {
-	case ATTR_VERSION:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
-				   len);
-			return -1;
-		}
-		attr->version = pos;
-		break;
-	case ATTR_MSG_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->msg_type = pos;
-		break;
-	case ATTR_ENROLLEE_NONCE:
-		if (len != WPS_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
-				   "length %u", len);
-			return -1;
-		}
-		attr->enrollee_nonce = pos;
-		break;
-	case ATTR_REGISTRAR_NONCE:
-		if (len != WPS_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
-				   "length %u", len);
-			return -1;
-		}
-		attr->registrar_nonce = pos;
-		break;
-	case ATTR_UUID_E:
-		if (len != WPS_UUID_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
-				   len);
-			return -1;
-		}
-		attr->uuid_e = pos;
-		break;
-	case ATTR_UUID_R:
-		if (len != WPS_UUID_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
-				   len);
-			return -1;
-		}
-		attr->uuid_r = pos;
-		break;
-	case ATTR_AUTH_TYPE_FLAGS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
-				   "Type Flags length %u", len);
-			return -1;
-		}
-		attr->auth_type_flags = pos;
-		break;
-	case ATTR_ENCR_TYPE_FLAGS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
-				   "Flags length %u", len);
-			return -1;
-		}
-		attr->encr_type_flags = pos;
-		break;
-	case ATTR_CONN_TYPE_FLAGS:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
-				   "Flags length %u", len);
-			return -1;
-		}
-		attr->conn_type_flags = pos;
-		break;
-	case ATTR_CONFIG_METHODS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
-				   "length %u", len);
-			return -1;
-		}
-		attr->config_methods = pos;
-		break;
-	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
-				   "Registrar Config Methods length %u", len);
-			return -1;
-		}
-		attr->sel_reg_config_methods = pos;
-		break;
-	case ATTR_PRIMARY_DEV_TYPE:
-		if (len != WPS_DEV_TYPE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->primary_dev_type = pos;
-		break;
-	case ATTR_RF_BANDS:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
-				   "%u", len);
-			return -1;
-		}
-		attr->rf_bands = pos;
-		break;
-	case ATTR_ASSOC_STATE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
-				   "length %u", len);
-			return -1;
-		}
-		attr->assoc_state = pos;
-		break;
-	case ATTR_CONFIG_ERROR:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
-				   "Error length %u", len);
-			return -1;
-		}
-		attr->config_error = pos;
-		break;
-	case ATTR_DEV_PASSWORD_ID:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
-				   "ID length %u", len);
-			return -1;
-		}
-		attr->dev_password_id = pos;
-		break;
-	case ATTR_OOB_DEVICE_PASSWORD:
-		if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
-				   "Password length %u", len);
-			return -1;
-		}
-		attr->oob_dev_password = pos;
-		break;
-	case ATTR_OS_VERSION:
-		if (len != 4) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
-				   "%u", len);
-			return -1;
-		}
-		attr->os_version = pos;
-		break;
-	case ATTR_WPS_STATE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
-				   "Setup State length %u", len);
-			return -1;
-		}
-		attr->wps_state = pos;
-		break;
-	case ATTR_AUTHENTICATOR:
-		if (len != WPS_AUTHENTICATOR_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
-				   "length %u", len);
-			return -1;
-		}
-		attr->authenticator = pos;
-		break;
-	case ATTR_R_HASH1:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
-				   len);
-			return -1;
-		}
-		attr->r_hash1 = pos;
-		break;
-	case ATTR_R_HASH2:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
-				   len);
-			return -1;
-		}
-		attr->r_hash2 = pos;
-		break;
-	case ATTR_E_HASH1:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
-				   len);
-			return -1;
-		}
-		attr->e_hash1 = pos;
-		break;
-	case ATTR_E_HASH2:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
-				   len);
-			return -1;
-		}
-		attr->e_hash2 = pos;
-		break;
-	case ATTR_R_SNONCE1:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->r_snonce1 = pos;
-		break;
-	case ATTR_R_SNONCE2:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->r_snonce2 = pos;
-		break;
-	case ATTR_E_SNONCE1:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->e_snonce1 = pos;
-		break;
-	case ATTR_E_SNONCE2:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->e_snonce2 = pos;
-		break;
-	case ATTR_KEY_WRAP_AUTH:
-		if (len != WPS_KWA_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
-				   "Authenticator length %u", len);
-			return -1;
-		}
-		attr->key_wrap_auth = pos;
-		break;
-	case ATTR_AUTH_TYPE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->auth_type = pos;
-		break;
-	case ATTR_ENCR_TYPE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->encr_type = pos;
-		break;
-	case ATTR_NETWORK_INDEX:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
-				   "length %u", len);
-			return -1;
-		}
-		attr->network_idx = pos;
-		break;
-	case ATTR_NETWORK_KEY_INDEX:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
-				   "length %u", len);
-			return -1;
-		}
-		attr->network_key_idx = pos;
-		break;
-	case ATTR_MAC_ADDR:
-		if (len != ETH_ALEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
-				   "length %u", len);
-			return -1;
-		}
-		attr->mac_addr = pos;
-		break;
-	case ATTR_KEY_PROVIDED_AUTO:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
-				   "Automatically length %u", len);
-			return -1;
-		}
-		attr->key_prov_auto = pos;
-		break;
-	case ATTR_802_1X_ENABLED:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
-				   "length %u", len);
-			return -1;
-		}
-		attr->dot1x_enabled = pos;
-		break;
-	case ATTR_SELECTED_REGISTRAR:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
-				   " length %u", len);
-			return -1;
-		}
-		attr->selected_registrar = pos;
-		break;
-	case ATTR_REQUEST_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->request_type = pos;
-		break;
-	case ATTR_RESPONSE_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->response_type = pos;
-		break;
-	case ATTR_MANUFACTURER:
-		attr->manufacturer = pos;
-		attr->manufacturer_len = len;
-		break;
-	case ATTR_MODEL_NAME:
-		attr->model_name = pos;
-		attr->model_name_len = len;
-		break;
-	case ATTR_MODEL_NUMBER:
-		attr->model_number = pos;
-		attr->model_number_len = len;
-		break;
-	case ATTR_SERIAL_NUMBER:
-		attr->serial_number = pos;
-		attr->serial_number_len = len;
-		break;
-	case ATTR_DEV_NAME:
-		attr->dev_name = pos;
-		attr->dev_name_len = len;
-		break;
-	case ATTR_PUBLIC_KEY:
-		attr->public_key = pos;
-		attr->public_key_len = len;
-		break;
-	case ATTR_ENCR_SETTINGS:
-		attr->encr_settings = pos;
-		attr->encr_settings_len = len;
-		break;
-	case ATTR_CRED:
-		if (attr->num_cred >= MAX_CRED_COUNT) {
-			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
-				   "attribute (max %d credentials)",
-				   MAX_CRED_COUNT);
-			break;
-		}
-		attr->cred[attr->num_cred] = pos;
-		attr->cred_len[attr->num_cred] = len;
-		attr->num_cred++;
-		break;
-	case ATTR_SSID:
-		attr->ssid = pos;
-		attr->ssid_len = len;
-		break;
-	case ATTR_NETWORK_KEY:
-		attr->network_key = pos;
-		attr->network_key_len = len;
-		break;
-	case ATTR_EAP_TYPE:
-		attr->eap_type = pos;
-		attr->eap_type_len = len;
-		break;
-	case ATTR_EAP_IDENTITY:
-		attr->eap_identity = pos;
-		attr->eap_identity_len = len;
-		break;
-	case ATTR_AP_SETUP_LOCKED:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
-				   "length %u", len);
-			return -1;
-		}
-		attr->ap_setup_locked = pos;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
-			   "len=%u", type, len);
-		break;
-	}
-
-	return 0;
-}
-
-
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
-{
-	const u8 *pos, *end;
-	u16 type, len;
-
-	os_memset(attr, 0, sizeof(*attr));
-	pos = wpabuf_head(msg);
-	end = pos + wpabuf_len(msg);
-
-	while (pos < end) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
-				   "%lu bytes remaining",
-				   (unsigned long) (end - pos));
-			return -1;
-		}
-
-		type = WPA_GET_BE16(pos);
-		pos += 2;
-		len = WPA_GET_BE16(pos);
-		pos += 2;
-		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
-			   type, len);
-		if (len > end - pos) {
-			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
-			return -1;
-		}
-
-#ifdef WPS_WORKAROUNDS
-		if (type == 0 && len == 0) {
-			/*
-			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
-			 * end of M1. Skip those to avoid interop issues.
-			 */
-			int i;
-			for (i = 0; i < end - pos; i++) {
-				if (pos[i])
-					break;
-			}
-			if (i == end - pos) {
-				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
-					   "unexpected message padding");
-				break;
-			}
-		}
-#endif /* WPS_WORKAROUNDS */
-
-		if (wps_set_attr(attr, type, pos, len) < 0)
-			return -1;
-
-		pos += len;
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_attr_parse.c (from rev 9639, vendor/wpa/dist/src/wps/wps_attr_parse.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_attr_parse.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_attr_parse.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,641 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008, Jouni Malinen <j at 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 "wps_defs.h"
+#include "wps_attr_parse.h"
+
+#ifndef CONFIG_WPS_STRICT
+#define WPS_WORKAROUNDS
+#endif /* CONFIG_WPS_STRICT */
+
+
+static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
+					  u8 id, u8 len, const u8 *pos)
+{
+	wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
+		   id, len);
+	switch (id) {
+	case WFA_ELEM_VERSION2:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->version2 = pos;
+		break;
+	case WFA_ELEM_AUTHORIZEDMACS:
+		attr->authorized_macs = pos;
+		attr->authorized_macs_len = len;
+		break;
+	case WFA_ELEM_NETWORK_KEY_SHAREABLE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
+				   "Shareable length %u", len);
+			return -1;
+		}
+		attr->network_key_shareable = pos;
+		break;
+	case WFA_ELEM_REQUEST_TO_ENROLL:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_to_enroll = pos;
+		break;
+	case WFA_ELEM_SETTINGS_DELAY_TIME:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
+				   "Time length %u", len);
+			return -1;
+		}
+		attr->settings_delay_time = pos;
+		break;
+	default:
+		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
+			   "Extension subelement %u", id);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
+				    u16 len)
+{
+	const u8 *end = pos + len;
+	u8 id, elen;
+
+	while (pos + 2 < end) {
+		id = *pos++;
+		elen = *pos++;
+		if (pos + elen > end)
+			break;
+		if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
+			return -1;
+		pos += elen;
+	}
+
+	return 0;
+}
+
+
+static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
+				u16 len)
+{
+	u32 vendor_id;
+
+	if (len < 3) {
+		wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
+		return 0;
+	}
+
+	vendor_id = WPA_GET_BE24(pos);
+	switch (vendor_id) {
+	case WPS_VENDOR_ID_WFA:
+		return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
+	}
+
+	/* Handle unknown vendor extensions */
+
+	wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
+		   vendor_id);
+
+	if (len > WPS_MAX_VENDOR_EXT_LEN) {
+		wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
+			   len);
+		return -1;
+	}
+
+	if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
+		wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
+			   "attribute (max %d vendor extensions)",
+			   MAX_WPS_PARSE_VENDOR_EXT);
+		return -1;
+	}
+	attr->vendor_ext[attr->num_vendor_ext] = pos;
+	attr->vendor_ext_len[attr->num_vendor_ext] = len;
+	attr->num_vendor_ext++;
+
+	return 0;
+}
+
+
+static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
+			const u8 *pos, u16 len)
+{
+	switch (type) {
+	case ATTR_VERSION:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
+				   len);
+			return -1;
+		}
+		attr->version = pos;
+		break;
+	case ATTR_MSG_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->msg_type = pos;
+		break;
+	case ATTR_ENROLLEE_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->enrollee_nonce = pos;
+		break;
+	case ATTR_REGISTRAR_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->registrar_nonce = pos;
+		break;
+	case ATTR_UUID_E:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_e = pos;
+		break;
+	case ATTR_UUID_R:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_r = pos;
+		break;
+	case ATTR_AUTH_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type Flags length %u", len);
+			return -1;
+		}
+		attr->auth_type_flags = pos;
+		break;
+	case ATTR_ENCR_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->encr_type_flags = pos;
+		break;
+	case ATTR_CONN_TYPE_FLAGS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->conn_type_flags = pos;
+		break;
+	case ATTR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
+				   "length %u", len);
+			return -1;
+		}
+		attr->config_methods = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
+				   "Registrar Config Methods length %u", len);
+			return -1;
+		}
+		attr->sel_reg_config_methods = pos;
+		break;
+	case ATTR_PRIMARY_DEV_TYPE:
+		if (len != WPS_DEV_TYPE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->primary_dev_type = pos;
+		break;
+	case ATTR_RF_BANDS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
+				   "%u", len);
+			return -1;
+		}
+		attr->rf_bands = pos;
+		break;
+	case ATTR_ASSOC_STATE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
+				   "length %u", len);
+			return -1;
+		}
+		attr->assoc_state = pos;
+		break;
+	case ATTR_CONFIG_ERROR:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
+				   "Error length %u", len);
+			return -1;
+		}
+		attr->config_error = pos;
+		break;
+	case ATTR_DEV_PASSWORD_ID:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
+				   "ID length %u", len);
+			return -1;
+		}
+		attr->dev_password_id = pos;
+		break;
+	case ATTR_OOB_DEVICE_PASSWORD:
+		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+		    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+		    len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+		    WPS_OOB_DEVICE_PASSWORD_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
+				   "Password length %u", len);
+			return -1;
+		}
+		attr->oob_dev_password = pos;
+		attr->oob_dev_password_len = len;
+		break;
+	case ATTR_OS_VERSION:
+		if (len != 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
+				   "%u", len);
+			return -1;
+		}
+		attr->os_version = pos;
+		break;
+	case ATTR_WPS_STATE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
+				   "Setup State length %u", len);
+			return -1;
+		}
+		attr->wps_state = pos;
+		break;
+	case ATTR_AUTHENTICATOR:
+		if (len != WPS_AUTHENTICATOR_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
+				   "length %u", len);
+			return -1;
+		}
+		attr->authenticator = pos;
+		break;
+	case ATTR_R_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash1 = pos;
+		break;
+	case ATTR_R_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash2 = pos;
+		break;
+	case ATTR_E_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash1 = pos;
+		break;
+	case ATTR_E_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash2 = pos;
+		break;
+	case ATTR_R_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce1 = pos;
+		break;
+	case ATTR_R_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce2 = pos;
+		break;
+	case ATTR_E_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce1 = pos;
+		break;
+	case ATTR_E_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce2 = pos;
+		break;
+	case ATTR_KEY_WRAP_AUTH:
+		if (len != WPS_KWA_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
+				   "Authenticator length %u", len);
+			return -1;
+		}
+		attr->key_wrap_auth = pos;
+		break;
+	case ATTR_AUTH_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->auth_type = pos;
+		break;
+	case ATTR_ENCR_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->encr_type = pos;
+		break;
+	case ATTR_NETWORK_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_idx = pos;
+		break;
+	case ATTR_NETWORK_KEY_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_key_idx = pos;
+		break;
+	case ATTR_MAC_ADDR:
+		if (len != ETH_ALEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
+				   "length %u", len);
+			return -1;
+		}
+		attr->mac_addr = pos;
+		break;
+	case ATTR_KEY_PROVIDED_AUTO:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
+				   "Automatically length %u", len);
+			return -1;
+		}
+		attr->key_prov_auto = pos;
+		break;
+	case ATTR_802_1X_ENABLED:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
+				   "length %u", len);
+			return -1;
+		}
+		attr->dot1x_enabled = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
+				   " length %u", len);
+			return -1;
+		}
+		attr->selected_registrar = pos;
+		break;
+	case ATTR_REQUEST_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_type = pos;
+		break;
+	case ATTR_RESPONSE_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->response_type = pos;
+		break;
+	case ATTR_MANUFACTURER:
+		attr->manufacturer = pos;
+		attr->manufacturer_len = len;
+		break;
+	case ATTR_MODEL_NAME:
+		attr->model_name = pos;
+		attr->model_name_len = len;
+		break;
+	case ATTR_MODEL_NUMBER:
+		attr->model_number = pos;
+		attr->model_number_len = len;
+		break;
+	case ATTR_SERIAL_NUMBER:
+		attr->serial_number = pos;
+		attr->serial_number_len = len;
+		break;
+	case ATTR_DEV_NAME:
+		attr->dev_name = pos;
+		attr->dev_name_len = len;
+		break;
+	case ATTR_PUBLIC_KEY:
+		attr->public_key = pos;
+		attr->public_key_len = len;
+		break;
+	case ATTR_ENCR_SETTINGS:
+		attr->encr_settings = pos;
+		attr->encr_settings_len = len;
+		break;
+	case ATTR_CRED:
+		if (attr->num_cred >= MAX_CRED_COUNT) {
+			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
+				   "attribute (max %d credentials)",
+				   MAX_CRED_COUNT);
+			break;
+		}
+		attr->cred[attr->num_cred] = pos;
+		attr->cred_len[attr->num_cred] = len;
+		attr->num_cred++;
+		break;
+	case ATTR_SSID:
+		attr->ssid = pos;
+		attr->ssid_len = len;
+		break;
+	case ATTR_NETWORK_KEY:
+		attr->network_key = pos;
+		attr->network_key_len = len;
+		break;
+	case ATTR_EAP_TYPE:
+		attr->eap_type = pos;
+		attr->eap_type_len = len;
+		break;
+	case ATTR_EAP_IDENTITY:
+		attr->eap_identity = pos;
+		attr->eap_identity_len = len;
+		break;
+	case ATTR_AP_SETUP_LOCKED:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
+				   "length %u", len);
+			return -1;
+		}
+		attr->ap_setup_locked = pos;
+		break;
+	case ATTR_REQUESTED_DEV_TYPE:
+		if (len != WPS_DEV_TYPE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
+				   "Type length %u", len);
+			return -1;
+		}
+		if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
+			wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
+				   "Type attribute (max %u types)",
+				   MAX_REQ_DEV_TYPE_COUNT);
+			break;
+		}
+		attr->req_dev_type[attr->num_req_dev_type] = pos;
+		attr->num_req_dev_type++;
+		break;
+	case ATTR_SECONDARY_DEV_TYPE_LIST:
+		if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
+		    (len % WPS_DEV_TYPE_LEN) > 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->sec_dev_type_list = pos;
+		attr->sec_dev_type_list_len = len;
+		break;
+	case ATTR_VENDOR_EXT:
+		if (wps_parse_vendor_ext(attr, pos, len) < 0)
+			return -1;
+		break;
+	case ATTR_AP_CHANNEL:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
+				   "length %u", len);
+			return -1;
+		}
+		attr->ap_channel = pos;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
+			   "len=%u", type, len);
+		break;
+	}
+
+	return 0;
+}
+
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
+{
+	const u8 *pos, *end;
+	u16 type, len;
+#ifdef WPS_WORKAROUNDS
+	u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
+
+	os_memset(attr, 0, sizeof(*attr));
+	pos = wpabuf_head(msg);
+	end = pos + wpabuf_len(msg);
+
+	while (pos < end) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
+				   "%lu bytes remaining",
+				   (unsigned long) (end - pos));
+			return -1;
+		}
+
+		type = WPA_GET_BE16(pos);
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
+			   type, len);
+		if (len > end - pos) {
+			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
+			wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
+#ifdef WPS_WORKAROUNDS
+			/*
+			 * Some deployed APs seem to have a bug in encoding of
+			 * Network Key attribute in the Credential attribute
+			 * where they add an extra octet after the Network Key
+			 * attribute at least when open network is being
+			 * provisioned.
+			 */
+			if ((type & 0xff00) != 0x1000 &&
+			    prev_type == ATTR_NETWORK_KEY) {
+				wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
+					   "to skip unexpected octet after "
+					   "Network Key");
+				pos -= 3;
+				continue;
+			}
+#endif /* WPS_WORKAROUNDS */
+			return -1;
+		}
+
+#ifdef WPS_WORKAROUNDS
+		if (type == 0 && len == 0) {
+			/*
+			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
+			 * end of M1. Skip those to avoid interop issues.
+			 */
+			int i;
+			for (i = 0; i < end - pos; i++) {
+				if (pos[i])
+					break;
+			}
+			if (i == end - pos) {
+				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
+					   "unexpected message padding");
+				break;
+			}
+		}
+#endif /* WPS_WORKAROUNDS */
+
+		if (wps_set_attr(attr, type, pos, len) < 0)
+			return -1;
+
+#ifdef WPS_WORKAROUNDS
+		prev_type = type;
+#endif /* WPS_WORKAROUNDS */
+		pos += len;
+	}
+
+	return 0;
+}

Copied: vendor/wpa/2.0/src/wps/wps_attr_parse.h (from rev 9639, vendor/wpa/dist/src/wps/wps_attr_parse.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_attr_parse.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_attr_parse.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,108 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_ATTR_PARSE_H
+#define WPS_ATTR_PARSE_H
+
+#include "wps.h"
+
+struct wps_parse_attr {
+	/* fixed length fields */
+	const u8 *version; /* 1 octet */
+	const u8 *version2; /* 1 octet */
+	const u8 *msg_type; /* 1 octet */
+	const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
+	const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
+	const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
+	const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
+	const u8 *auth_type_flags; /* 2 octets */
+	const u8 *encr_type_flags; /* 2 octets */
+	const u8 *conn_type_flags; /* 1 octet */
+	const u8 *config_methods; /* 2 octets */
+	const u8 *sel_reg_config_methods; /* 2 octets */
+	const u8 *primary_dev_type; /* 8 octets */
+	const u8 *rf_bands; /* 1 octet */
+	const u8 *assoc_state; /* 2 octets */
+	const u8 *config_error; /* 2 octets */
+	const u8 *dev_password_id; /* 2 octets */
+	const u8 *os_version; /* 4 octets */
+	const u8 *wps_state; /* 1 octet */
+	const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
+	const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
+	const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
+	const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
+	const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
+	const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
+	const u8 *auth_type; /* 2 octets */
+	const u8 *encr_type; /* 2 octets */
+	const u8 *network_idx; /* 1 octet */
+	const u8 *network_key_idx; /* 1 octet */
+	const u8 *mac_addr; /* ETH_ALEN (6) octets */
+	const u8 *key_prov_auto; /* 1 octet (Bool) */
+	const u8 *dot1x_enabled; /* 1 octet (Bool) */
+	const u8 *selected_registrar; /* 1 octet (Bool) */
+	const u8 *request_type; /* 1 octet */
+	const u8 *response_type; /* 1 octet */
+	const u8 *ap_setup_locked; /* 1 octet */
+	const u8 *settings_delay_time; /* 1 octet */
+	const u8 *network_key_shareable; /* 1 octet (Bool) */
+	const u8 *request_to_enroll; /* 1 octet (Bool) */
+	const u8 *ap_channel; /* 2 octets */
+
+	/* variable length fields */
+	const u8 *manufacturer;
+	size_t manufacturer_len;
+	const u8 *model_name;
+	size_t model_name_len;
+	const u8 *model_number;
+	size_t model_number_len;
+	const u8 *serial_number;
+	size_t serial_number_len;
+	const u8 *dev_name;
+	size_t dev_name_len;
+	const u8 *public_key;
+	size_t public_key_len;
+	const u8 *encr_settings;
+	size_t encr_settings_len;
+	const u8 *ssid; /* <= 32 octets */
+	size_t ssid_len;
+	const u8 *network_key; /* <= 64 octets */
+	size_t network_key_len;
+	const u8 *eap_type; /* <= 8 octets */
+	size_t eap_type_len;
+	const u8 *eap_identity; /* <= 64 octets */
+	size_t eap_identity_len;
+	const u8 *authorized_macs; /* <= 30 octets */
+	size_t authorized_macs_len;
+	const u8 *sec_dev_type_list; /* <= 128 octets */
+	size_t sec_dev_type_list_len;
+	const u8 *oob_dev_password; /* 38..54 octets */
+	size_t oob_dev_password_len;
+
+	/* attributes that can occur multiple times */
+#define MAX_CRED_COUNT 10
+	const u8 *cred[MAX_CRED_COUNT];
+	size_t cred_len[MAX_CRED_COUNT];
+	size_t num_cred;
+
+#define MAX_REQ_DEV_TYPE_COUNT 10
+	const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
+	size_t num_req_dev_type;
+
+	const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+	size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
+	size_t num_vendor_ext;
+};
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
+
+#endif /* WPS_ATTR_PARSE_H */

Deleted: vendor/wpa/2.0/src/wps/wps_attr_process.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_attr_process.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_attr_process.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,330 +0,0 @@
-/*
- * Wi-Fi Protected Setup - attribute processing
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha256.h"
-#include "wps_i.h"
-
-
-int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
-			      const struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	if (authenticator == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
-			   "included");
-		return -1;
-	}
-
-	if (wps->last_msg == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
-			   "validating authenticator");
-		return -1;
-	}
-
-	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
-	 * (M_curr* is M_curr without the Authenticator attribute)
-	 */
-	addr[0] = wpabuf_head(wps->last_msg);
-	len[0] = wpabuf_len(wps->last_msg);
-	addr[1] = wpabuf_head(msg);
-	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
-
-	if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
-			      const u8 *key_wrap_auth)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *head;
-	size_t len;
-
-	if (key_wrap_auth == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
-		return -1;
-	}
-
-	head = wpabuf_head(msg);
-	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
-	if (head + len != key_wrap_auth - 4) {
-		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
-			   "decrypted attribute");
-		return -1;
-	}
-
-	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
-	if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_idx(struct wps_credential *cred,
-					const u8 *idx)
-{
-	if (idx == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Network Index");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
-
-	return 0;
-}
-
-
-static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
-				 size_t ssid_len)
-{
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
-		return -1;
-	}
-
-	/* Remove zero-padding since some Registrar implementations seem to use
-	 * hardcoded 32-octet length for this attribute */
-	while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
-		ssid_len--;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
-	if (ssid_len <= sizeof(cred->ssid)) {
-		os_memcpy(cred->ssid, ssid, ssid_len);
-		cred->ssid_len = ssid_len;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_cred_auth_type(struct wps_credential *cred,
-				      const u8 *auth_type)
-{
-	if (auth_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Authentication Type");
-		return -1;
-	}
-
-	cred->auth_type = WPA_GET_BE16(auth_type);
-	wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
-		   cred->auth_type);
-
-	return 0;
-}
-
-
-static int wps_process_cred_encr_type(struct wps_credential *cred,
-				      const u8 *encr_type)
-{
-	if (encr_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Encryption Type");
-		return -1;
-	}
-
-	cred->encr_type = WPA_GET_BE16(encr_type);
-	wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
-		   cred->encr_type);
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_key_idx(struct wps_credential *cred,
-					    const u8 *key_idx)
-{
-	if (key_idx == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
-	cred->key_idx = *key_idx;
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_key(struct wps_credential *cred,
-					const u8 *key, size_t key_len)
-{
-	if (key == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Network Key");
-		if (cred->auth_type == WPS_AUTH_OPEN &&
-		    cred->encr_type == WPS_ENCR_NONE) {
-			wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow "
-				   "missing mandatory Network Key attribute "
-				   "for open network");
-			return 0;
-		}
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
-	if (key_len <= sizeof(cred->key)) {
-		os_memcpy(cred->key, key, key_len);
-		cred->key_len = key_len;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_cred_mac_addr(struct wps_credential *cred,
-				     const u8 *mac_addr)
-{
-	if (mac_addr == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "MAC Address");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
-	os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
-
-	return 0;
-}
-
-
-static int wps_process_cred_eap_type(struct wps_credential *cred,
-				     const u8 *eap_type, size_t eap_type_len)
-{
-	if (eap_type == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_eap_identity(struct wps_credential *cred,
-					 const u8 *identity,
-					 size_t identity_len)
-{
-	if (identity == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
-			  identity, identity_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
-					  const u8 *key_prov_auto)
-{
-	if (key_prov_auto == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
-		   *key_prov_auto);
-
-	return 0;
-}
-
-
-static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
-					   const u8 *dot1x_enabled)
-{
-	if (dot1x_enabled == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
-
-	return 0;
-}
-
-
-static void wps_workaround_cred_key(struct wps_credential *cred)
-{
-	if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
-	    cred->key_len > 8 && cred->key_len < 64 &&
-	    cred->key[cred->key_len - 1] == 0) {
-		/*
-		 * A deployed external registrar is known to encode ASCII
-		 * passphrases incorrectly. Remove the extra NULL termination
-		 * to fix the encoding.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
-			   "termination from ASCII passphrase");
-		cred->key_len--;
-	}
-}
-
-
-int wps_process_cred(struct wps_parse_attr *attr,
-		     struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Process Credential");
-
-	/* TODO: support multiple Network Keys */
-	if (wps_process_cred_network_idx(cred, attr->network_idx) ||
-	    wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
-	    wps_process_cred_auth_type(cred, attr->auth_type) ||
-	    wps_process_cred_encr_type(cred, attr->encr_type) ||
-	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
-	    wps_process_cred_network_key(cred, attr->network_key,
-					 attr->network_key_len) ||
-	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
-	    wps_process_cred_eap_type(cred, attr->eap_type,
-				      attr->eap_type_len) ||
-	    wps_process_cred_eap_identity(cred, attr->eap_identity,
-					  attr->eap_identity_len) ||
-	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
-	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
-		return -1;
-
-	wps_workaround_cred_key(cred);
-
-	return 0;
-}
-
-
-int wps_process_ap_settings(struct wps_parse_attr *attr,
-			    struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
-	os_memset(cred, 0, sizeof(*cred));
-	/* TODO: optional attributes New Password and Device Password ID */
-	if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
-	    wps_process_cred_auth_type(cred, attr->auth_type) ||
-	    wps_process_cred_encr_type(cred, attr->encr_type) ||
-	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
-	    wps_process_cred_network_key(cred, attr->network_key,
-					 attr->network_key_len) ||
-	    wps_process_cred_mac_addr(cred, attr->mac_addr))
-		return -1;
-
-	wps_workaround_cred_key(cred);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_attr_process.c (from rev 9639, vendor/wpa/dist/src/wps/wps_attr_process.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_attr_process.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_attr_process.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,343 @@
+/*
+ * Wi-Fi Protected Setup - attribute processing
+ * Copyright (c) 2008, Jouni Malinen <j at 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/sha256.h"
+#include "wps_i.h"
+
+
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (authenticator == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
+			   "included");
+		return -1;
+	}
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "validating authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *head;
+	size_t len;
+
+	if (key_wrap_auth == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
+		return -1;
+	}
+
+	head = wpabuf_head(msg);
+	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
+	if (head + len != key_wrap_auth - 4) {
+		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
+			   "decrypted attribute");
+		return -1;
+	}
+
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
+	if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_idx(struct wps_credential *cred,
+					const u8 *idx)
+{
+	if (idx == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Index");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
+
+	return 0;
+}
+
+
+static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
+				 size_t ssid_len)
+{
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
+		return -1;
+	}
+
+	/* Remove zero-padding since some Registrar implementations seem to use
+	 * hardcoded 32-octet length for this attribute */
+	while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
+		ssid_len--;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
+	if (ssid_len <= sizeof(cred->ssid)) {
+		os_memcpy(cred->ssid, ssid, ssid_len);
+		cred->ssid_len = ssid_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_auth_type(struct wps_credential *cred,
+				      const u8 *auth_type)
+{
+	if (auth_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Authentication Type");
+		return -1;
+	}
+
+	cred->auth_type = WPA_GET_BE16(auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
+		   cred->auth_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_encr_type(struct wps_credential *cred,
+				      const u8 *encr_type)
+{
+	if (encr_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Encryption Type");
+		return -1;
+	}
+
+	cred->encr_type = WPA_GET_BE16(encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
+		   cred->encr_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key_idx(struct wps_credential *cred,
+					    const u8 *key_idx)
+{
+	if (key_idx == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
+	cred->key_idx = *key_idx;
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key(struct wps_credential *cred,
+					const u8 *key, size_t key_len)
+{
+	if (key == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Key");
+		if (cred->auth_type == WPS_AUTH_OPEN &&
+		    cred->encr_type == WPS_ENCR_NONE) {
+			wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow "
+				   "missing mandatory Network Key attribute "
+				   "for open network");
+			return 0;
+		}
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
+	if (key_len <= sizeof(cred->key)) {
+		os_memcpy(cred->key, key, key_len);
+		cred->key_len = key_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_mac_addr(struct wps_credential *cred,
+				     const u8 *mac_addr)
+{
+	if (mac_addr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "MAC Address");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
+	os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_type(struct wps_credential *cred,
+				     const u8 *eap_type, size_t eap_type_len)
+{
+	if (eap_type == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_identity(struct wps_credential *cred,
+					 const u8 *identity,
+					 size_t identity_len)
+{
+	if (identity == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
+			  identity, identity_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
+					  const u8 *key_prov_auto)
+{
+	if (key_prov_auto == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
+		   *key_prov_auto);
+
+	return 0;
+}
+
+
+static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
+					   const u8 *dot1x_enabled)
+{
+	if (dot1x_enabled == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
+
+	return 0;
+}
+
+
+static int wps_process_cred_ap_channel(struct wps_credential *cred,
+				       const u8 *ap_channel)
+{
+	if (ap_channel == NULL)
+		return 0; /* optional attribute */
+
+	cred->ap_channel = WPA_GET_BE16(ap_channel);
+	wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
+
+	return 0;
+}
+
+
+static int wps_workaround_cred_key(struct wps_credential *cred)
+{
+	if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
+	    cred->key_len > 8 && cred->key_len < 64 &&
+	    cred->key[cred->key_len - 1] == 0) {
+#ifdef CONFIG_WPS_STRICT
+		wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses "
+			   "forbidden NULL termination");
+		wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
+				      cred->key, cred->key_len);
+		return -1;
+#else /* CONFIG_WPS_STRICT */
+		/*
+		 * A deployed external registrar is known to encode ASCII
+		 * passphrases incorrectly. Remove the extra NULL termination
+		 * to fix the encoding.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
+			   "termination from ASCII passphrase");
+		cred->key_len--;
+#endif /* CONFIG_WPS_STRICT */
+	}
+	return 0;
+}
+
+
+int wps_process_cred(struct wps_parse_attr *attr,
+		     struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Process Credential");
+
+	/* TODO: support multiple Network Keys */
+	if (wps_process_cred_network_idx(cred, attr->network_idx) ||
+	    wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
+	    wps_process_cred_eap_type(cred, attr->eap_type,
+				      attr->eap_type_len) ||
+	    wps_process_cred_eap_identity(cred, attr->eap_identity,
+					  attr->eap_identity_len) ||
+	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
+	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
+	    wps_process_cred_ap_channel(cred, attr->ap_channel))
+		return -1;
+
+	return wps_workaround_cred_key(cred);
+}
+
+
+int wps_process_ap_settings(struct wps_parse_attr *attr,
+			    struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
+	os_memset(cred, 0, sizeof(*cred));
+	/* TODO: optional attributes New Password and Device Password ID */
+	if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr))
+		return -1;
+
+	return wps_workaround_cred_key(cred);
+}

Deleted: vendor/wpa/2.0/src/wps/wps_common.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,635 +0,0 @@
-/*
- * Wi-Fi Protected Setup - common functionality
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/aes_wrap.h"
-#include "crypto/crypto.h"
-#include "crypto/dh_group5.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "wps_i.h"
-#include "wps_dev_attr.h"
-
-
-void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
-	     const char *label, u8 *res, size_t res_len)
-{
-	u8 i_buf[4], key_bits[4];
-	const u8 *addr[4];
-	size_t len[4];
-	int i, iter;
-	u8 hash[SHA256_MAC_LEN], *opos;
-	size_t left;
-
-	WPA_PUT_BE32(key_bits, res_len * 8);
-
-	addr[0] = i_buf;
-	len[0] = sizeof(i_buf);
-	addr[1] = label_prefix;
-	len[1] = label_prefix_len;
-	addr[2] = (const u8 *) label;
-	len[2] = os_strlen(label);
-	addr[3] = key_bits;
-	len[3] = sizeof(key_bits);
-
-	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
-	opos = res;
-	left = res_len;
-
-	for (i = 1; i <= iter; i++) {
-		WPA_PUT_BE32(i_buf, i);
-		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
-		if (i < iter) {
-			os_memcpy(opos, hash, SHA256_MAC_LEN);
-			opos += SHA256_MAC_LEN;
-			left -= SHA256_MAC_LEN;
-		} else
-			os_memcpy(opos, hash, left);
-	}
-}
-
-
-int wps_derive_keys(struct wps_data *wps)
-{
-	struct wpabuf *pubkey, *dh_shared;
-	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
-	const u8 *addr[3];
-	size_t len[3];
-	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
-
-	if (wps->dh_privkey == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
-		return -1;
-	}
-
-	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
-	if (pubkey == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
-		return -1;
-	}
-
-	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
-	dh5_free(wps->dh_ctx);
-	wps->dh_ctx = NULL;
-	dh_shared = wpabuf_zeropad(dh_shared, 192);
-	if (dh_shared == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
-		return -1;
-	}
-
-	/* Own DH private key is not needed anymore */
-	wpabuf_free(wps->dh_privkey);
-	wps->dh_privkey = NULL;
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
-
-	/* DHKey = SHA-256(g^AB mod p) */
-	addr[0] = wpabuf_head(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);
-
-	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
-	addr[0] = wps->nonce_e;
-	len[0] = WPS_NONCE_LEN;
-	addr[1] = wps->mac_addr_e;
-	len[1] = ETH_ALEN;
-	addr[2] = wps->nonce_r;
-	len[2] = WPS_NONCE_LEN;
-	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
-
-	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
-		keys, sizeof(keys));
-	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
-	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
-	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
-		  WPS_EMSK_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
-			wps->authkey, WPS_AUTHKEY_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
-			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
-
-	return 0;
-}
-
-
-void 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);
-	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);
-	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);
-}
-
-
-struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
-					  size_t encr_len)
-{
-	struct wpabuf *decrypted;
-	const size_t block_size = 16;
-	size_t i;
-	u8 pad;
-	const u8 *pos;
-
-	/* AES-128-CBC */
-	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
-	{
-		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
-		return NULL;
-	}
-
-	decrypted = wpabuf_alloc(encr_len - block_size);
-	if (decrypted == NULL)
-		return NULL;
-
-	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
-	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);
-		return NULL;
-	}
-
-	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
-			    decrypted);
-
-	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
-	pad = *pos;
-	if (pad > wpabuf_len(decrypted)) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
-		wpabuf_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);
-			return NULL;
-		}
-	}
-	decrypted->used -= pad;
-
-	return decrypted;
-}
-
-
-/**
- * wps_pin_checksum - Compute PIN checksum
- * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
- * Returns: Checksum digit
- */
-unsigned int wps_pin_checksum(unsigned int pin)
-{
-	unsigned int accum = 0;
-	while (pin) {
-		accum += 3 * (pin % 10);
-		pin /= 10;
-		accum += pin % 10;
-		pin /= 10;
-	}
-
-	return (10 - accum % 10) % 10;
-}
-
-
-/**
- * wps_pin_valid - Check whether a PIN has a valid checksum
- * @pin: Eight digit PIN (i.e., including the checksum digit)
- * Returns: 1 if checksum digit is valid, or 0 if not
- */
-unsigned int wps_pin_valid(unsigned int pin)
-{
-	return wps_pin_checksum(pin / 10) == (pin % 10);
-}
-
-
-/**
- * wps_generate_pin - Generate a random PIN
- * Returns: Eight digit PIN (i.e., including the checksum digit)
- */
-unsigned int wps_generate_pin(void)
-{
-	unsigned int val;
-
-	/* Generate seven random digits for the PIN */
-	if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) {
-		struct os_time now;
-		os_get_time(&now);
-		val = os_random() ^ now.sec ^ now.usec;
-	}
-	val %= 10000000;
-
-	/* Append checksum digit */
-	return val * 10 + wps_pin_checksum(val);
-}
-
-
-void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg)
-{
-	union wps_event_data data;
-
-	if (wps->event_cb == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	data.fail.msg = msg;
-	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
-}
-
-
-void wps_success_event(struct wps_context *wps)
-{
-	if (wps->event_cb == NULL)
-		return;
-
-	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
-}
-
-
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
-{
-	union wps_event_data data;
-
-	if (wps->event_cb == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	data.pwd_auth_fail.enrollee = enrollee;
-	data.pwd_auth_fail.part = part;
-	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
-}
-
-
-void wps_pbc_overlap_event(struct wps_context *wps)
-{
-	if (wps->event_cb == NULL)
-		return;
-
-	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
-}
-
-
-void wps_pbc_timeout_event(struct wps_context *wps)
-{
-	if (wps->event_cb == NULL)
-		return;
-
-	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
-}
-
-
-#ifdef CONFIG_WPS_OOB
-
-static struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
-{
-	struct wps_data data;
-	struct wpabuf *plain;
-
-	plain = wpabuf_alloc(500);
-	if (plain == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-			   "credential");
-		return NULL;
-	}
-
-	os_memset(&data, 0, sizeof(data));
-	data.wps = wps;
-	data.auth_type = wps->auth_types;
-	data.encr_type = wps->encr_types;
-	if (wps_build_version(plain) || wps_build_cred(&data, plain)) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	return plain;
-}
-
-
-static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
-{
-	struct wpabuf *data;
-
-	data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
-	if (data == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-			   "device password attribute");
-		return NULL;
-	}
-
-	wpabuf_free(wps->oob_conf.dev_password);
-	wps->oob_conf.dev_password =
-		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
-	if (wps->oob_conf.dev_password == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-			   "device password");
-		wpabuf_free(data);
-		return NULL;
-	}
-
-	if (wps_build_version(data) ||
-	    wps_build_oob_dev_password(data, wps)) {
-		wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
-			   "attribute error");
-		wpabuf_free(data);
-		return NULL;
-	}
-
-	return data;
-}
-
-
-static int wps_parse_oob_dev_pwd(struct wps_context *wps,
-				 struct wpabuf *data)
-{
-	struct oob_conf_data *oob_conf = &wps->oob_conf;
-	struct wps_parse_attr attr;
-	const u8 *pos;
-
-	if (wps_parse_msg(data, &attr) < 0 ||
-	    attr.oob_dev_password == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
-		return -1;
-	}
-
-	pos = attr.oob_dev_password;
-
-	oob_conf->pubkey_hash =
-		wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
-	if (oob_conf->pubkey_hash == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-			   "public key hash");
-		return -1;
-	}
-	pos += WPS_OOB_PUBKEY_HASH_LEN;
-
-	wps->oob_dev_pw_id = WPA_GET_BE16(pos);
-	pos += sizeof(wps->oob_dev_pw_id);
-
-	oob_conf->dev_password =
-		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
-	if (oob_conf->dev_password == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
-			   "device password");
-		return -1;
-	}
-	wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
-				   wpabuf_size(oob_conf->dev_password)),
-				   wpabuf_size(oob_conf->dev_password), pos,
-				   WPS_OOB_DEVICE_PASSWORD_LEN);
-
-	return 0;
-}
-
-
-static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
-{
-	struct wpabuf msg;
-	struct wps_parse_attr attr;
-	size_t i;
-
-	if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
-		wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
-		return -1;
-	}
-
-	for (i = 0; i < attr.num_cred; i++) {
-		struct wps_credential local_cred;
-		struct wps_parse_attr cattr;
-
-		os_memset(&local_cred, 0, sizeof(local_cred));
-		wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
-		if (wps_parse_msg(&msg, &cattr) < 0 ||
-		    wps_process_cred(&cattr, &local_cred)) {
-			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
-				   "credential");
-			return -1;
-		}
-		wps->cred_cb(wps->cb_ctx, &local_cred);
-	}
-
-	return 0;
-}
-
-
-int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
-		    int registrar)
-{
-	struct wpabuf *data;
-	int ret, write_f, oob_method = wps->oob_conf.oob_method;
-	void *oob_priv;
-
-	write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
-
-	oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
-	if (oob_priv == NULL) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
-		return -1;
-	}
-
-	if (write_f) {
-		if (oob_method == OOB_METHOD_CRED)
-			data = wps_get_oob_cred(wps);
-		else
-			data = wps_get_oob_dev_pwd(wps);
-
-		ret = 0;
-		if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
-			ret = -1;
-	} else {
-		data = oob_dev->read_func(oob_priv);
-		if (data == NULL)
-			ret = -1;
-		else {
-			if (oob_method == OOB_METHOD_CRED)
-				ret = wps_parse_oob_cred(wps, data);
-			else
-				ret = wps_parse_oob_dev_pwd(wps, data);
-		}
-	}
-	wpabuf_free(data);
-	oob_dev->deinit_func(oob_priv);
-
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-struct oob_device_data * wps_get_oob_device(char *device_type)
-{
-#ifdef CONFIG_WPS_UFD
-	if (os_strstr(device_type, "ufd") != NULL)
-		return &oob_ufd_device_data;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-	if (os_strstr(device_type, "nfc") != NULL)
-		return &oob_nfc_device_data;
-#endif /* CONFIG_WPS_NFC */
-
-	return NULL;
-}
-
-
-#ifdef CONFIG_WPS_NFC
-struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
-{
-	if (device_name == NULL)
-		return NULL;
-#ifdef CONFIG_WPS_NFC_PN531
-	if (os_strstr(device_name, "pn531") != NULL)
-		return &oob_nfc_pn531_device_data;
-#endif /* CONFIG_WPS_NFC_PN531 */
-
-	return NULL;
-}
-#endif /* CONFIG_WPS_NFC */
-
-
-int wps_get_oob_method(char *method)
-{
-	if (os_strstr(method, "pin-e") != NULL)
-		return OOB_METHOD_DEV_PWD_E;
-	if (os_strstr(method, "pin-r") != NULL)
-		return OOB_METHOD_DEV_PWD_R;
-	if (os_strstr(method, "cred") != NULL)
-		return OOB_METHOD_CRED;
-	return OOB_METHOD_UNKNOWN;
-}
-
-#endif /* CONFIG_WPS_OOB */
-
-
-int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
-{
-	const char *pos;
-
-	/* <categ>-<OUI>-<subcateg> */
-	WPA_PUT_BE16(dev_type, atoi(str));
-	pos = os_strchr(str, '-');
-	if (pos == NULL)
-		return -1;
-	pos++;
-	if (hexstr2bin(pos, &dev_type[2], 4))
-		return -1;
-	pos = os_strchr(pos, '-');
-	if (pos == NULL)
-		return -1;
-	pos++;
-	WPA_PUT_BE16(&dev_type[6], atoi(pos));
-
-
-	return 0;
-}
-
-
-char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
-			    size_t buf_len)
-{
-	int ret;
-
-	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
-			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
-			  WPA_GET_BE16(&dev_type[6]));
-	if (ret < 0 || (unsigned int) ret >= buf_len)
-		return NULL;
-
-	return buf;
-}
-
-
-void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
-{
-	const u8 *addr[2];
-	size_t len[2];
-	u8 hash[SHA1_MAC_LEN];
-	u8 nsid[16] = {
-		0x52, 0x64, 0x80, 0xf8,
-		0xc9, 0x9b,
-		0x4b, 0xe5,
-		0xa6, 0x55,
-		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
-	};
-
-	addr[0] = nsid;
-	len[0] = sizeof(nsid);
-	addr[1] = mac_addr;
-	len[1] = 6;
-	sha1_vector(2, addr, len, hash);
-	os_memcpy(uuid, hash, 16);
-
-	/* Version: 5 = named-based version using SHA-1 */
-	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
-
-	/* Variant specified in RFC 4122 */
-	uuid[8] = 0x80 | (uuid[8] & 0x3f);
-}
-
-
-u16 wps_config_methods_str2bin(const char *str)
-{
-	u16 methods = 0;
-
-	if (str == NULL) {
-		/* Default to enabling methods based on build configuration */
-		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
-		methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-		methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-	} else {
-		if (os_strstr(str, "usba"))
-			methods |= WPS_CONFIG_USBA;
-		if (os_strstr(str, "ethernet"))
-			methods |= WPS_CONFIG_ETHERNET;
-		if (os_strstr(str, "label"))
-			methods |= WPS_CONFIG_LABEL;
-		if (os_strstr(str, "display"))
-			methods |= WPS_CONFIG_DISPLAY;
-		if (os_strstr(str, "ext_nfc_token"))
-			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
-		if (os_strstr(str, "int_nfc_token"))
-			methods |= WPS_CONFIG_INT_NFC_TOKEN;
-		if (os_strstr(str, "nfc_interface"))
-			methods |= WPS_CONFIG_NFC_INTERFACE;
-		if (os_strstr(str, "push_button"))
-			methods |= WPS_CONFIG_PUSHBUTTON;
-		if (os_strstr(str, "keypad"))
-			methods |= WPS_CONFIG_KEYPAD;
-	}
-
-	return methods;
-}

Copied: vendor/wpa/2.0/src/wps/wps_common.c (from rev 9639, vendor/wpa/dist/src/wps/wps_common.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_common.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,611 @@
+/*
+ * Wi-Fi Protected Setup - common functionality
+ * Copyright (c) 2008-2012, Jouni Malinen <j at 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/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/dh_group5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "wps_i.h"
+
+
+void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
+	     const char *label, u8 *res, size_t res_len)
+{
+	u8 i_buf[4], key_bits[4];
+	const u8 *addr[4];
+	size_t len[4];
+	int i, iter;
+	u8 hash[SHA256_MAC_LEN], *opos;
+	size_t left;
+
+	WPA_PUT_BE32(key_bits, res_len * 8);
+
+	addr[0] = i_buf;
+	len[0] = sizeof(i_buf);
+	addr[1] = label_prefix;
+	len[1] = label_prefix_len;
+	addr[2] = (const u8 *) label;
+	len[2] = os_strlen(label);
+	addr[3] = key_bits;
+	len[3] = sizeof(key_bits);
+
+	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
+	opos = res;
+	left = res_len;
+
+	for (i = 1; i <= iter; i++) {
+		WPA_PUT_BE32(i_buf, i);
+		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
+		if (i < iter) {
+			os_memcpy(opos, hash, SHA256_MAC_LEN);
+			opos += SHA256_MAC_LEN;
+			left -= SHA256_MAC_LEN;
+		} else
+			os_memcpy(opos, hash, left);
+	}
+}
+
+
+int wps_derive_keys(struct wps_data *wps)
+{
+	struct wpabuf *pubkey, *dh_shared;
+	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
+	const u8 *addr[3];
+	size_t len[3];
+	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
+
+	if (wps->dh_privkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
+		return -1;
+	}
+
+	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
+	if (pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
+		return -1;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
+	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
+	dh5_free(wps->dh_ctx);
+	wps->dh_ctx = NULL;
+	dh_shared = wpabuf_zeropad(dh_shared, 192);
+	if (dh_shared == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
+		return -1;
+	}
+
+	/* Own DH private key is not needed anymore */
+	wpabuf_free(wps->dh_privkey);
+	wps->dh_privkey = NULL;
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
+
+	/* DHKey = SHA-256(g^AB mod p) */
+	addr[0] = wpabuf_head(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);
+
+	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
+	addr[0] = wps->nonce_e;
+	len[0] = WPS_NONCE_LEN;
+	addr[1] = wps->mac_addr_e;
+	len[1] = ETH_ALEN;
+	addr[2] = wps->nonce_r;
+	len[2] = WPS_NONCE_LEN;
+	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
+
+	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
+		keys, sizeof(keys));
+	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
+	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
+	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
+		  WPS_EMSK_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
+			wps->authkey, WPS_AUTHKEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
+			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
+
+	return 0;
+}
+
+
+void 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);
+	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);
+	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);
+}
+
+
+struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
+					  size_t encr_len)
+{
+	struct wpabuf *decrypted;
+	const size_t block_size = 16;
+	size_t i;
+	u8 pad;
+	const u8 *pos;
+
+	/* AES-128-CBC */
+	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
+		return NULL;
+	}
+
+	decrypted = wpabuf_alloc(encr_len - block_size);
+	if (decrypted == NULL)
+		return NULL;
+
+	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
+	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);
+		return NULL;
+	}
+
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
+			    decrypted);
+
+	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
+	pad = *pos;
+	if (pad > wpabuf_len(decrypted)) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
+		wpabuf_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);
+			return NULL;
+		}
+	}
+	decrypted->used -= pad;
+
+	return decrypted;
+}
+
+
+/**
+ * wps_pin_checksum - Compute PIN checksum
+ * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
+ * Returns: Checksum digit
+ */
+unsigned int wps_pin_checksum(unsigned int pin)
+{
+	unsigned int accum = 0;
+	while (pin) {
+		accum += 3 * (pin % 10);
+		pin /= 10;
+		accum += pin % 10;
+		pin /= 10;
+	}
+
+	return (10 - accum % 10) % 10;
+}
+
+
+/**
+ * wps_pin_valid - Check whether a PIN has a valid checksum
+ * @pin: Eight digit PIN (i.e., including the checksum digit)
+ * Returns: 1 if checksum digit is valid, or 0 if not
+ */
+unsigned int wps_pin_valid(unsigned int pin)
+{
+	return wps_pin_checksum(pin / 10) == (pin % 10);
+}
+
+
+/**
+ * wps_generate_pin - Generate a random PIN
+ * Returns: Eight digit PIN (i.e., including the checksum digit)
+ */
+unsigned int wps_generate_pin(void)
+{
+	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;
+	}
+	val %= 10000000;
+
+	/* Append checksum digit */
+	return val * 10 + wps_pin_checksum(val);
+}
+
+
+int wps_pin_str_valid(const char *pin)
+{
+	const char *p;
+	size_t len;
+
+	p = pin;
+	while (*p >= '0' && *p <= '9')
+		p++;
+	if (*p != '\0')
+		return 0;
+
+	len = p - pin;
+	return len == 4 || len == 8;
+}
+
+
+void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
+		    u16 config_error, u16 error_indication)
+{
+	union wps_event_data data;
+
+	if (wps->event_cb == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.fail.msg = msg;
+	data.fail.config_error = config_error;
+	data.fail.error_indication = error_indication;
+	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
+}
+
+
+void wps_success_event(struct wps_context *wps)
+{
+	if (wps->event_cb == NULL)
+		return;
+
+	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
+}
+
+
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
+{
+	union wps_event_data data;
+
+	if (wps->event_cb == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.pwd_auth_fail.enrollee = enrollee;
+	data.pwd_auth_fail.part = part;
+	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
+}
+
+
+void wps_pbc_overlap_event(struct wps_context *wps)
+{
+	if (wps->event_cb == NULL)
+		return;
+
+	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
+}
+
+
+void wps_pbc_timeout_event(struct wps_context *wps)
+{
+	if (wps->event_cb == NULL)
+		return;
+
+	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
+}
+
+
+#ifdef CONFIG_WPS_OOB
+
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
+{
+	struct wps_data data;
+	struct wpabuf *plain;
+
+	plain = wpabuf_alloc(500);
+	if (plain == NULL) {
+		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
+			   "credential");
+		return NULL;
+	}
+
+	os_memset(&data, 0, sizeof(data));
+	data.wps = wps;
+	data.auth_type = wps->auth_types;
+	data.encr_type = wps->encr_types;
+	if (wps_build_version(plain) ||
+	    wps_build_cred(&data, plain) ||
+	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	return plain;
+}
+
+
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+				       const struct wpabuf *pubkey,
+				       const struct wpabuf *dev_pw)
+{
+	struct wpabuf *data;
+
+	data = wpabuf_alloc(200);
+	if (data == NULL)
+		return NULL;
+
+	if (wps_build_version(data) ||
+	    wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
+				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
+	    wps_build_wfa_ext(data, 0, NULL, 0)) {
+		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
+			   "token");
+		wpabuf_free(data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
+{
+	struct wpabuf msg;
+	size_t i;
+
+	for (i = 0; i < attr->num_cred; i++) {
+		struct wps_credential local_cred;
+		struct wps_parse_attr cattr;
+
+		os_memset(&local_cred, 0, sizeof(local_cred));
+		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
+		if (wps_parse_msg(&msg, &cattr) < 0 ||
+		    wps_process_cred(&cattr, &local_cred)) {
+			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
+				   "credential");
+			return -1;
+		}
+		wps->cred_cb(wps->cb_ctx, &local_cred);
+	}
+
+	return 0;
+}
+
+
+#endif /* CONFIG_WPS_OOB */
+
+
+int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
+{
+	const char *pos;
+
+	/* <categ>-<OUI>-<subcateg> */
+	WPA_PUT_BE16(dev_type, atoi(str));
+	pos = os_strchr(str, '-');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	if (hexstr2bin(pos, &dev_type[2], 4))
+		return -1;
+	pos = os_strchr(pos, '-');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	WPA_PUT_BE16(&dev_type[6], atoi(pos));
+
+
+	return 0;
+}
+
+
+char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
+			    size_t buf_len)
+{
+	int ret;
+
+	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
+			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
+			  WPA_GET_BE16(&dev_type[6]));
+	if (ret < 0 || (unsigned int) ret >= buf_len)
+		return NULL;
+
+	return buf;
+}
+
+
+void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	u8 hash[SHA1_MAC_LEN];
+	u8 nsid[16] = {
+		0x52, 0x64, 0x80, 0xf8,
+		0xc9, 0x9b,
+		0x4b, 0xe5,
+		0xa6, 0x55,
+		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
+	};
+
+	addr[0] = nsid;
+	len[0] = sizeof(nsid);
+	addr[1] = mac_addr;
+	len[1] = 6;
+	sha1_vector(2, addr, len, hash);
+	os_memcpy(uuid, hash, 16);
+
+	/* Version: 5 = named-based version using SHA-1 */
+	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
+
+	/* Variant specified in RFC 4122 */
+	uuid[8] = 0x80 | (uuid[8] & 0x3f);
+}
+
+
+u16 wps_config_methods_str2bin(const char *str)
+{
+	u16 methods = 0;
+
+	if (str == NULL) {
+		/* Default to enabling methods based on build configuration */
+		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+#ifdef CONFIG_WPS2
+		methods |= WPS_CONFIG_VIRT_DISPLAY;
+#endif /* CONFIG_WPS2 */
+#ifdef CONFIG_WPS_NFC
+		methods |= WPS_CONFIG_NFC_INTERFACE;
+#endif /* CONFIG_WPS_NFC */
+	} else {
+		if (os_strstr(str, "ethernet"))
+			methods |= WPS_CONFIG_ETHERNET;
+		if (os_strstr(str, "label"))
+			methods |= WPS_CONFIG_LABEL;
+		if (os_strstr(str, "display"))
+			methods |= WPS_CONFIG_DISPLAY;
+		if (os_strstr(str, "ext_nfc_token"))
+			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
+		if (os_strstr(str, "int_nfc_token"))
+			methods |= WPS_CONFIG_INT_NFC_TOKEN;
+		if (os_strstr(str, "nfc_interface"))
+			methods |= WPS_CONFIG_NFC_INTERFACE;
+		if (os_strstr(str, "push_button"))
+			methods |= WPS_CONFIG_PUSHBUTTON;
+		if (os_strstr(str, "keypad"))
+			methods |= WPS_CONFIG_KEYPAD;
+#ifdef CONFIG_WPS2
+		if (os_strstr(str, "virtual_display"))
+			methods |= WPS_CONFIG_VIRT_DISPLAY;
+		if (os_strstr(str, "physical_display"))
+			methods |= WPS_CONFIG_PHY_DISPLAY;
+		if (os_strstr(str, "virtual_push_button"))
+			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+		if (os_strstr(str, "physical_push_button"))
+			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+#endif /* CONFIG_WPS2 */
+	}
+
+	return methods;
+}
+
+
+struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_config_error(msg, wps->config_error) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+				  struct wpabuf **privkey,
+				  struct wpabuf **dev_pw)
+{
+	struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
+	void *dh_ctx;
+	u16 val;
+
+	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
+	if (pw == NULL)
+		return NULL;
+
+	if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
+			     WPS_OOB_DEVICE_PASSWORD_LEN) ||
+	    random_get_bytes((u8 *) &val, sizeof(val))) {
+		wpabuf_free(pw);
+		return NULL;
+	}
+
+	dh_ctx = dh5_init(&priv, &pub);
+	if (dh_ctx == NULL) {
+		wpabuf_free(pw);
+		return NULL;
+	}
+	dh5_free(dh_ctx);
+
+	*id = 0x10 + val % 0xfff0;
+	wpabuf_free(*pubkey);
+	*pubkey = pub;
+	wpabuf_free(*privkey);
+	*privkey = priv;
+	wpabuf_free(*dev_pw);
+	*dev_pw = pw;
+
+	ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_WPS_NFC */

Deleted: vendor/wpa/2.0/src/wps/wps_defs.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_defs.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,293 +0,0 @@
-/*
- * Wi-Fi Protected Setup - message definitions
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_DEFS_H
-#define WPS_DEFS_H
-
-#define WPS_VERSION 0x10
-
-/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
-#define WPS_DH_GROUP 5
-
-#define WPS_UUID_LEN 16
-#define WPS_NONCE_LEN 16
-#define WPS_AUTHENTICATOR_LEN 8
-#define WPS_AUTHKEY_LEN 32
-#define WPS_KEYWRAPKEY_LEN 16
-#define WPS_EMSK_LEN 32
-#define WPS_PSK_LEN 16
-#define WPS_SECRET_NONCE_LEN 16
-#define WPS_HASH_LEN 32
-#define WPS_KWA_LEN 8
-#define WPS_MGMTAUTHKEY_LEN 32
-#define WPS_MGMTENCKEY_LEN 16
-#define WPS_MGMT_KEY_ID_LEN 16
-#define WPS_OOB_DEVICE_PASSWORD_ATTR_LEN 54
-#define WPS_OOB_DEVICE_PASSWORD_LEN 32
-#define WPS_OOB_PUBKEY_HASH_LEN 20
-
-/* Attribute Types */
-enum wps_attribute {
-	ATTR_AP_CHANNEL = 0x1001,
-	ATTR_ASSOC_STATE = 0x1002,
-	ATTR_AUTH_TYPE = 0x1003,
-	ATTR_AUTH_TYPE_FLAGS = 0x1004,
-	ATTR_AUTHENTICATOR = 0x1005,
-	ATTR_CONFIG_METHODS = 0x1008,
-	ATTR_CONFIG_ERROR = 0x1009,
-	ATTR_CONFIRM_URL4 = 0x100a,
-	ATTR_CONFIRM_URL6 = 0x100b,
-	ATTR_CONN_TYPE = 0x100c,
-	ATTR_CONN_TYPE_FLAGS = 0x100d,
-	ATTR_CRED = 0x100e,
-	ATTR_ENCR_TYPE = 0x100f,
-	ATTR_ENCR_TYPE_FLAGS = 0x1010,
-	ATTR_DEV_NAME = 0x1011,
-	ATTR_DEV_PASSWORD_ID = 0x1012,
-	ATTR_E_HASH1 = 0x1014,
-	ATTR_E_HASH2 = 0x1015,
-	ATTR_E_SNONCE1 = 0x1016,
-	ATTR_E_SNONCE2 = 0x1017,
-	ATTR_ENCR_SETTINGS = 0x1018,
-	ATTR_ENROLLEE_NONCE = 0x101a,
-	ATTR_FEATURE_ID = 0x101b,
-	ATTR_IDENTITY = 0x101c,
-	ATTR_IDENTITY_PROOF = 0x101d,
-	ATTR_KEY_WRAP_AUTH = 0x101e,
-	ATTR_KEY_ID = 0x101f,
-	ATTR_MAC_ADDR = 0x1020,
-	ATTR_MANUFACTURER = 0x1021,
-	ATTR_MSG_TYPE = 0x1022,
-	ATTR_MODEL_NAME = 0x1023,
-	ATTR_MODEL_NUMBER = 0x1024,
-	ATTR_NETWORK_INDEX = 0x1026,
-	ATTR_NETWORK_KEY = 0x1027,
-	ATTR_NETWORK_KEY_INDEX = 0x1028,
-	ATTR_NEW_DEVICE_NAME = 0x1029,
-	ATTR_NEW_PASSWORD = 0x102a,
-	ATTR_OOB_DEVICE_PASSWORD = 0x102c,
-	ATTR_OS_VERSION = 0x102d,
-	ATTR_POWER_LEVEL = 0x102f,
-	ATTR_PSK_CURRENT = 0x1030,
-	ATTR_PSK_MAX = 0x1031,
-	ATTR_PUBLIC_KEY = 0x1032,
-	ATTR_RADIO_ENABLE = 0x1033,
-	ATTR_REBOOT = 0x1034,
-	ATTR_REGISTRAR_CURRENT = 0x1035,
-	ATTR_REGISTRAR_ESTABLISHED = 0x1036,
-	ATTR_REGISTRAR_LIST = 0x1037,
-	ATTR_REGISTRAR_MAX = 0x1038,
-	ATTR_REGISTRAR_NONCE = 0x1039,
-	ATTR_REQUEST_TYPE = 0x103a,
-	ATTR_RESPONSE_TYPE = 0x103b,
-	ATTR_RF_BANDS = 0x103c,
-	ATTR_R_HASH1 = 0x103d,
-	ATTR_R_HASH2 = 0x103e,
-	ATTR_R_SNONCE1 = 0x103f,
-	ATTR_R_SNONCE2 = 0x1040,
-	ATTR_SELECTED_REGISTRAR = 0x1041,
-	ATTR_SERIAL_NUMBER = 0x1042,
-	ATTR_WPS_STATE = 0x1044,
-	ATTR_SSID = 0x1045,
-	ATTR_TOTAL_NETWORKS = 0x1046,
-	ATTR_UUID_E = 0x1047,
-	ATTR_UUID_R = 0x1048,
-	ATTR_VENDOR_EXT = 0x1049,
-	ATTR_VERSION = 0x104a,
-	ATTR_X509_CERT_REQ = 0x104b,
-	ATTR_X509_CERT = 0x104c,
-	ATTR_EAP_IDENTITY = 0x104d,
-	ATTR_MSG_COUNTER = 0x104e,
-	ATTR_PUBKEY_HASH = 0x104f,
-	ATTR_REKEY_KEY = 0x1050,
-	ATTR_KEY_LIFETIME = 0x1051,
-	ATTR_PERMITTED_CFG_METHODS = 0x1052,
-	ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,
-	ATTR_PRIMARY_DEV_TYPE = 0x1054,
-	ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,
-	ATTR_PORTABLE_DEV = 0x1056,
-	ATTR_AP_SETUP_LOCKED = 0x1057,
-	ATTR_APPLICATION_EXT = 0x1058,
-	ATTR_EAP_TYPE = 0x1059,
-	ATTR_IV = 0x1060,
-	ATTR_KEY_PROVIDED_AUTO = 0x1061,
-	ATTR_802_1X_ENABLED = 0x1062,
-	ATTR_APPSESSIONKEY = 0x1063,
-	ATTR_WEPTRANSMITKEY = 0x1064
-};
-
-/* Device Password ID */
-enum wps_dev_password_id {
-	DEV_PW_DEFAULT = 0x0000,
-	DEV_PW_USER_SPECIFIED = 0x0001,
-	DEV_PW_MACHINE_SPECIFIED = 0x0002,
-	DEV_PW_REKEY = 0x0003,
-	DEV_PW_PUSHBUTTON = 0x0004,
-	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
-};
-
-/* Message Type */
-enum wps_msg_type {
-	WPS_Beacon = 0x01,
-	WPS_ProbeRequest = 0x02,
-	WPS_ProbeResponse = 0x03,
-	WPS_M1 = 0x04,
-	WPS_M2 = 0x05,
-	WPS_M2D = 0x06,
-	WPS_M3 = 0x07,
-	WPS_M4 = 0x08,
-	WPS_M5 = 0x09,
-	WPS_M6 = 0x0a,
-	WPS_M7 = 0x0b,
-	WPS_M8 = 0x0c,
-	WPS_WSC_ACK = 0x0d,
-	WPS_WSC_NACK = 0x0e,
-	WPS_WSC_DONE = 0x0f
-};
-
-/* Authentication Type Flags */
-#define WPS_AUTH_OPEN 0x0001
-#define WPS_AUTH_WPAPSK 0x0002
-#define WPS_AUTH_SHARED 0x0004
-#define WPS_AUTH_WPA 0x0008
-#define WPS_AUTH_WPA2 0x0010
-#define WPS_AUTH_WPA2PSK 0x0020
-#define WPS_AUTH_TYPES (WPS_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \
-			WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)
-
-/* Encryption Type Flags */
-#define WPS_ENCR_NONE 0x0001
-#define WPS_ENCR_WEP 0x0002
-#define WPS_ENCR_TKIP 0x0004
-#define WPS_ENCR_AES 0x0008
-#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
-			WPS_ENCR_AES)
-
-/* Configuration Error */
-enum wps_config_error {
-	WPS_CFG_NO_ERROR = 0,
-	WPS_CFG_OOB_IFACE_READ_ERROR = 1,
-	WPS_CFG_DECRYPTION_CRC_FAILURE = 2,
-	WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,
-	WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,
-	WPS_CFG_SIGNAL_TOO_WEAK = 5,
-	WPS_CFG_NETWORK_AUTH_FAILURE = 6,
-	WPS_CFG_NETWORK_ASSOC_FAILURE = 7,
-	WPS_CFG_NO_DHCP_RESPONSE = 8,
-	WPS_CFG_FAILED_DHCP_CONFIG = 9,
-	WPS_CFG_IP_ADDR_CONFLICT = 10,
-	WPS_CFG_NO_CONN_TO_REGISTRAR = 11,
-	WPS_CFG_MULTIPLE_PBC_DETECTED = 12,
-	WPS_CFG_ROGUE_SUSPECTED = 13,
-	WPS_CFG_DEVICE_BUSY = 14,
-	WPS_CFG_SETUP_LOCKED = 15,
-	WPS_CFG_MSG_TIMEOUT = 16,
-	WPS_CFG_REG_SESS_TIMEOUT = 17,
-	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
-};
-
-/* RF Bands */
-#define WPS_RF_24GHZ 0x01
-#define WPS_RF_50GHZ 0x02
-
-/* Config Methods */
-#define WPS_CONFIG_USBA 0x0001
-#define WPS_CONFIG_ETHERNET 0x0002
-#define WPS_CONFIG_LABEL 0x0004
-#define WPS_CONFIG_DISPLAY 0x0008
-#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
-#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
-#define WPS_CONFIG_NFC_INTERFACE 0x0040
-#define WPS_CONFIG_PUSHBUTTON 0x0080
-#define WPS_CONFIG_KEYPAD 0x0100
-
-/* Connection Type Flags */
-#define WPS_CONN_ESS 0x01
-#define WPS_CONN_IBSS 0x02
-
-/* Wi-Fi Protected Setup State */
-enum wps_state {
-	WPS_STATE_NOT_CONFIGURED = 1,
-	WPS_STATE_CONFIGURED = 2
-};
-
-/* Association State */
-enum wps_assoc_state {
-	WPS_ASSOC_NOT_ASSOC = 0,
-	WPS_ASSOC_CONN_SUCCESS = 1,
-	WPS_ASSOC_CFG_FAILURE = 2,
-	WPS_ASSOC_FAILURE = 3,
-	WPS_ASSOC_IP_FAILURE = 4
-};
-
-
-#define WPS_DEV_OUI_WFA 0x0050f204
-
-enum wps_dev_categ {
-	WPS_DEV_COMPUTER = 1,
-	WPS_DEV_INPUT = 2,
-	WPS_DEV_PRINTER = 3,
-	WPS_DEV_CAMERA = 4,
-	WPS_DEV_STORAGE = 5,
-	WPS_DEV_NETWORK_INFRA = 6,
-	WPS_DEV_DISPLAY = 7,
-	WPS_DEV_MULTIMEDIA = 8,
-	WPS_DEV_GAMING = 9,
-	WPS_DEV_PHONE = 10
-};
-
-enum wps_dev_subcateg {
-	WPS_DEV_COMPUTER_PC = 1,
-	WPS_DEV_COMPUTER_SERVER = 2,
-	WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
-	WPS_DEV_PRINTER_PRINTER = 1,
-	WPS_DEV_PRINTER_SCANNER = 2,
-	WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
-	WPS_DEV_STORAGE_NAS = 1,
-	WPS_DEV_NETWORK_INFRA_AP = 1,
-	WPS_DEV_NETWORK_INFRA_ROUTER = 2,
-	WPS_DEV_NETWORK_INFRA_SWITCH = 3,
-	WPS_DEV_DISPLAY_TV = 1,
-	WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
-	WPS_DEV_DISPLAY_PROJECTOR = 3,
-	WPS_DEV_MULTIMEDIA_DAR = 1,
-	WPS_DEV_MULTIMEDIA_PVR = 2,
-	WPS_DEV_MULTIMEDIA_MCX = 3,
-	WPS_DEV_GAMING_XBOX = 1,
-	WPS_DEV_GAMING_XBOX360 = 2,
-	WPS_DEV_GAMING_PLAYSTATION = 3,
-	WPS_DEV_PHONE_WINDOWS_MOBILE = 1
-};
-
-
-/* Request Type */
-enum wps_request_type {
-	WPS_REQ_ENROLLEE_INFO = 0,
-	WPS_REQ_ENROLLEE = 1,
-	WPS_REQ_REGISTRAR = 2,
-	WPS_REQ_WLAN_MANAGER_REGISTRAR = 3
-};
-
-/* Response Type */
-enum wps_response_type {
-	WPS_RESP_ENROLLEE_INFO = 0,
-	WPS_RESP_ENROLLEE = 1,
-	WPS_RESP_REGISTRAR = 2,
-	WPS_RESP_AP = 3
-};
-
-/* Walk Time for push button configuration (in seconds) */
-#define WPS_PBC_WALK_TIME 120
-
-#endif /* WPS_DEFS_H */

Copied: vendor/wpa/2.0/src/wps/wps_defs.h (from rev 9639, vendor/wpa/dist/src/wps/wps_defs.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_defs.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_defs.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,330 @@
+/*
+ * Wi-Fi Protected Setup - message definitions
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_DEFS_H
+#define WPS_DEFS_H
+
+#ifdef CONFIG_WPS_TESTING
+
+extern int wps_version_number;
+extern int wps_testing_dummy_cred;
+#define WPS_VERSION wps_version_number
+
+#else /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_WPS2
+#define WPS_VERSION 0x20
+#else /* CONFIG_WPS2 */
+#define WPS_VERSION 0x10
+#endif /* CONFIG_WPS2 */
+
+#endif /* CONFIG_WPS_TESTING */
+
+/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
+#define WPS_DH_GROUP 5
+
+#define WPS_UUID_LEN 16
+#define WPS_NONCE_LEN 16
+#define WPS_AUTHENTICATOR_LEN 8
+#define WPS_AUTHKEY_LEN 32
+#define WPS_KEYWRAPKEY_LEN 16
+#define WPS_EMSK_LEN 32
+#define WPS_PSK_LEN 16
+#define WPS_SECRET_NONCE_LEN 16
+#define WPS_HASH_LEN 32
+#define WPS_KWA_LEN 8
+#define WPS_MGMTAUTHKEY_LEN 32
+#define WPS_MGMTENCKEY_LEN 16
+#define WPS_MGMT_KEY_ID_LEN 16
+#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
+#define WPS_OOB_DEVICE_PASSWORD_LEN 32
+#define WPS_OOB_PUBKEY_HASH_LEN 20
+
+/* Attribute Types */
+enum wps_attribute {
+	ATTR_AP_CHANNEL = 0x1001,
+	ATTR_ASSOC_STATE = 0x1002,
+	ATTR_AUTH_TYPE = 0x1003,
+	ATTR_AUTH_TYPE_FLAGS = 0x1004,
+	ATTR_AUTHENTICATOR = 0x1005,
+	ATTR_CONFIG_METHODS = 0x1008,
+	ATTR_CONFIG_ERROR = 0x1009,
+	ATTR_CONFIRM_URL4 = 0x100a,
+	ATTR_CONFIRM_URL6 = 0x100b,
+	ATTR_CONN_TYPE = 0x100c,
+	ATTR_CONN_TYPE_FLAGS = 0x100d,
+	ATTR_CRED = 0x100e,
+	ATTR_ENCR_TYPE = 0x100f,
+	ATTR_ENCR_TYPE_FLAGS = 0x1010,
+	ATTR_DEV_NAME = 0x1011,
+	ATTR_DEV_PASSWORD_ID = 0x1012,
+	ATTR_E_HASH1 = 0x1014,
+	ATTR_E_HASH2 = 0x1015,
+	ATTR_E_SNONCE1 = 0x1016,
+	ATTR_E_SNONCE2 = 0x1017,
+	ATTR_ENCR_SETTINGS = 0x1018,
+	ATTR_ENROLLEE_NONCE = 0x101a,
+	ATTR_FEATURE_ID = 0x101b,
+	ATTR_IDENTITY = 0x101c,
+	ATTR_IDENTITY_PROOF = 0x101d,
+	ATTR_KEY_WRAP_AUTH = 0x101e,
+	ATTR_KEY_ID = 0x101f,
+	ATTR_MAC_ADDR = 0x1020,
+	ATTR_MANUFACTURER = 0x1021,
+	ATTR_MSG_TYPE = 0x1022,
+	ATTR_MODEL_NAME = 0x1023,
+	ATTR_MODEL_NUMBER = 0x1024,
+	ATTR_NETWORK_INDEX = 0x1026,
+	ATTR_NETWORK_KEY = 0x1027,
+	ATTR_NETWORK_KEY_INDEX = 0x1028,
+	ATTR_NEW_DEVICE_NAME = 0x1029,
+	ATTR_NEW_PASSWORD = 0x102a,
+	ATTR_OOB_DEVICE_PASSWORD = 0x102c,
+	ATTR_OS_VERSION = 0x102d,
+	ATTR_POWER_LEVEL = 0x102f,
+	ATTR_PSK_CURRENT = 0x1030,
+	ATTR_PSK_MAX = 0x1031,
+	ATTR_PUBLIC_KEY = 0x1032,
+	ATTR_RADIO_ENABLE = 0x1033,
+	ATTR_REBOOT = 0x1034,
+	ATTR_REGISTRAR_CURRENT = 0x1035,
+	ATTR_REGISTRAR_ESTABLISHED = 0x1036,
+	ATTR_REGISTRAR_LIST = 0x1037,
+	ATTR_REGISTRAR_MAX = 0x1038,
+	ATTR_REGISTRAR_NONCE = 0x1039,
+	ATTR_REQUEST_TYPE = 0x103a,
+	ATTR_RESPONSE_TYPE = 0x103b,
+	ATTR_RF_BANDS = 0x103c,
+	ATTR_R_HASH1 = 0x103d,
+	ATTR_R_HASH2 = 0x103e,
+	ATTR_R_SNONCE1 = 0x103f,
+	ATTR_R_SNONCE2 = 0x1040,
+	ATTR_SELECTED_REGISTRAR = 0x1041,
+	ATTR_SERIAL_NUMBER = 0x1042,
+	ATTR_WPS_STATE = 0x1044,
+	ATTR_SSID = 0x1045,
+	ATTR_TOTAL_NETWORKS = 0x1046,
+	ATTR_UUID_E = 0x1047,
+	ATTR_UUID_R = 0x1048,
+	ATTR_VENDOR_EXT = 0x1049,
+	ATTR_VERSION = 0x104a,
+	ATTR_X509_CERT_REQ = 0x104b,
+	ATTR_X509_CERT = 0x104c,
+	ATTR_EAP_IDENTITY = 0x104d,
+	ATTR_MSG_COUNTER = 0x104e,
+	ATTR_PUBKEY_HASH = 0x104f,
+	ATTR_REKEY_KEY = 0x1050,
+	ATTR_KEY_LIFETIME = 0x1051,
+	ATTR_PERMITTED_CFG_METHODS = 0x1052,
+	ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,
+	ATTR_PRIMARY_DEV_TYPE = 0x1054,
+	ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,
+	ATTR_PORTABLE_DEV = 0x1056,
+	ATTR_AP_SETUP_LOCKED = 0x1057,
+	ATTR_APPLICATION_EXT = 0x1058,
+	ATTR_EAP_TYPE = 0x1059,
+	ATTR_IV = 0x1060,
+	ATTR_KEY_PROVIDED_AUTO = 0x1061,
+	ATTR_802_1X_ENABLED = 0x1062,
+	ATTR_APPSESSIONKEY = 0x1063,
+	ATTR_WEPTRANSMITKEY = 0x1064,
+	ATTR_REQUESTED_DEV_TYPE = 0x106a,
+	ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */
+};
+
+#define WPS_VENDOR_ID_WFA 14122
+
+/* WFA Vendor Extension subelements */
+enum {
+	WFA_ELEM_VERSION2 = 0x00,
+	WFA_ELEM_AUTHORIZEDMACS = 0x01,
+	WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
+	WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
+	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
+};
+
+/* Device Password ID */
+enum wps_dev_password_id {
+	DEV_PW_DEFAULT = 0x0000,
+	DEV_PW_USER_SPECIFIED = 0x0001,
+	DEV_PW_MACHINE_SPECIFIED = 0x0002,
+	DEV_PW_REKEY = 0x0003,
+	DEV_PW_PUSHBUTTON = 0x0004,
+	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+};
+
+/* Message Type */
+enum wps_msg_type {
+	WPS_Beacon = 0x01,
+	WPS_ProbeRequest = 0x02,
+	WPS_ProbeResponse = 0x03,
+	WPS_M1 = 0x04,
+	WPS_M2 = 0x05,
+	WPS_M2D = 0x06,
+	WPS_M3 = 0x07,
+	WPS_M4 = 0x08,
+	WPS_M5 = 0x09,
+	WPS_M6 = 0x0a,
+	WPS_M7 = 0x0b,
+	WPS_M8 = 0x0c,
+	WPS_WSC_ACK = 0x0d,
+	WPS_WSC_NACK = 0x0e,
+	WPS_WSC_DONE = 0x0f
+};
+
+/* Authentication Type Flags */
+#define WPS_AUTH_OPEN 0x0001
+#define WPS_AUTH_WPAPSK 0x0002
+#define WPS_AUTH_SHARED 0x0004
+#define WPS_AUTH_WPA 0x0008
+#define WPS_AUTH_WPA2 0x0010
+#define WPS_AUTH_WPA2PSK 0x0020
+#define WPS_AUTH_TYPES (WPS_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \
+			WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)
+
+/* Encryption Type Flags */
+#define WPS_ENCR_NONE 0x0001
+#define WPS_ENCR_WEP 0x0002
+#define WPS_ENCR_TKIP 0x0004
+#define WPS_ENCR_AES 0x0008
+#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
+			WPS_ENCR_AES)
+
+/* Configuration Error */
+enum wps_config_error {
+	WPS_CFG_NO_ERROR = 0,
+	WPS_CFG_OOB_IFACE_READ_ERROR = 1,
+	WPS_CFG_DECRYPTION_CRC_FAILURE = 2,
+	WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,
+	WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,
+	WPS_CFG_SIGNAL_TOO_WEAK = 5,
+	WPS_CFG_NETWORK_AUTH_FAILURE = 6,
+	WPS_CFG_NETWORK_ASSOC_FAILURE = 7,
+	WPS_CFG_NO_DHCP_RESPONSE = 8,
+	WPS_CFG_FAILED_DHCP_CONFIG = 9,
+	WPS_CFG_IP_ADDR_CONFLICT = 10,
+	WPS_CFG_NO_CONN_TO_REGISTRAR = 11,
+	WPS_CFG_MULTIPLE_PBC_DETECTED = 12,
+	WPS_CFG_ROGUE_SUSPECTED = 13,
+	WPS_CFG_DEVICE_BUSY = 14,
+	WPS_CFG_SETUP_LOCKED = 15,
+	WPS_CFG_MSG_TIMEOUT = 16,
+	WPS_CFG_REG_SESS_TIMEOUT = 17,
+	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
+};
+
+/* Vendor specific Error Indication for WPS event messages */
+enum wps_error_indication {
+	WPS_EI_NO_ERROR,
+	WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
+	WPS_EI_SECURITY_WEP_PROHIBITED,
+	NUM_WPS_EI_VALUES
+};
+
+/* RF Bands */
+#define WPS_RF_24GHZ 0x01
+#define WPS_RF_50GHZ 0x02
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+#ifdef CONFIG_WPS2
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+#endif /* CONFIG_WPS2 */
+
+/* Connection Type Flags */
+#define WPS_CONN_ESS 0x01
+#define WPS_CONN_IBSS 0x02
+
+/* Wi-Fi Protected Setup State */
+enum wps_state {
+	WPS_STATE_NOT_CONFIGURED = 1,
+	WPS_STATE_CONFIGURED = 2
+};
+
+/* Association State */
+enum wps_assoc_state {
+	WPS_ASSOC_NOT_ASSOC = 0,
+	WPS_ASSOC_CONN_SUCCESS = 1,
+	WPS_ASSOC_CFG_FAILURE = 2,
+	WPS_ASSOC_FAILURE = 3,
+	WPS_ASSOC_IP_FAILURE = 4
+};
+
+
+#define WPS_DEV_OUI_WFA 0x0050f204
+
+enum wps_dev_categ {
+	WPS_DEV_COMPUTER = 1,
+	WPS_DEV_INPUT = 2,
+	WPS_DEV_PRINTER = 3,
+	WPS_DEV_CAMERA = 4,
+	WPS_DEV_STORAGE = 5,
+	WPS_DEV_NETWORK_INFRA = 6,
+	WPS_DEV_DISPLAY = 7,
+	WPS_DEV_MULTIMEDIA = 8,
+	WPS_DEV_GAMING = 9,
+	WPS_DEV_PHONE = 10
+};
+
+enum wps_dev_subcateg {
+	WPS_DEV_COMPUTER_PC = 1,
+	WPS_DEV_COMPUTER_SERVER = 2,
+	WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+	WPS_DEV_PRINTER_PRINTER = 1,
+	WPS_DEV_PRINTER_SCANNER = 2,
+	WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+	WPS_DEV_STORAGE_NAS = 1,
+	WPS_DEV_NETWORK_INFRA_AP = 1,
+	WPS_DEV_NETWORK_INFRA_ROUTER = 2,
+	WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+	WPS_DEV_DISPLAY_TV = 1,
+	WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
+	WPS_DEV_DISPLAY_PROJECTOR = 3,
+	WPS_DEV_MULTIMEDIA_DAR = 1,
+	WPS_DEV_MULTIMEDIA_PVR = 2,
+	WPS_DEV_MULTIMEDIA_MCX = 3,
+	WPS_DEV_GAMING_XBOX = 1,
+	WPS_DEV_GAMING_XBOX360 = 2,
+	WPS_DEV_GAMING_PLAYSTATION = 3,
+	WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+};
+
+
+/* Request Type */
+enum wps_request_type {
+	WPS_REQ_ENROLLEE_INFO = 0,
+	WPS_REQ_ENROLLEE = 1,
+	WPS_REQ_REGISTRAR = 2,
+	WPS_REQ_WLAN_MANAGER_REGISTRAR = 3
+};
+
+/* Response Type */
+enum wps_response_type {
+	WPS_RESP_ENROLLEE_INFO = 0,
+	WPS_RESP_ENROLLEE = 1,
+	WPS_RESP_REGISTRAR = 2,
+	WPS_RESP_AP = 3
+};
+
+/* Walk Time for push button configuration (in seconds) */
+#define WPS_PBC_WALK_TIME 120
+
+#define WPS_MAX_AUTHORIZED_MACS 5
+
+#endif /* WPS_DEFS_H */

Deleted: vendor/wpa/2.0/src/wps/wps_dev_attr.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_dev_attr.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_dev_attr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,382 +0,0 @@
-/*
- * Wi-Fi Protected Setup - device attributes
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wps_i.h"
-#include "wps_dev_attr.h"
-
-
-static int wps_build_manufacturer(struct wps_device_data *dev,
-				  struct wpabuf *msg)
-{
-	size_t len;
-	wpa_printf(MSG_DEBUG, "WPS:  * Manufacturer");
-	wpabuf_put_be16(msg, ATTR_MANUFACTURER);
-	len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
-	if (len == 0) {
-		/*
-		 * Some deployed WPS implementations fail to parse zero-length
-		 * attributes. As a workaround, send a null character if the
-		 * device attribute string is empty.
-		 */
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, '\0');
-	} else {
-		wpabuf_put_be16(msg, len);
-		wpabuf_put_data(msg, dev->manufacturer, len);
-	}
-	return 0;
-}
-
-
-static int wps_build_model_name(struct wps_device_data *dev,
-				struct wpabuf *msg)
-{
-	size_t len;
-	wpa_printf(MSG_DEBUG, "WPS:  * Model Name");
-	wpabuf_put_be16(msg, ATTR_MODEL_NAME);
-	len = dev->model_name ? os_strlen(dev->model_name) : 0;
-	if (len == 0) {
-		/*
-		 * Some deployed WPS implementations fail to parse zero-length
-		 * attributes. As a workaround, send a null character if the
-		 * device attribute string is empty.
-		 */
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, '\0');
-	} else {
-		wpabuf_put_be16(msg, len);
-		wpabuf_put_data(msg, dev->model_name, len);
-	}
-	return 0;
-}
-
-
-static int wps_build_model_number(struct wps_device_data *dev,
-				  struct wpabuf *msg)
-{
-	size_t len;
-	wpa_printf(MSG_DEBUG, "WPS:  * Model Number");
-	wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
-	len = dev->model_number ? os_strlen(dev->model_number) : 0;
-	if (len == 0) {
-		/*
-		 * Some deployed WPS implementations fail to parse zero-length
-		 * attributes. As a workaround, send a null character if the
-		 * device attribute string is empty.
-		 */
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, '\0');
-	} else {
-		wpabuf_put_be16(msg, len);
-		wpabuf_put_data(msg, dev->model_number, len);
-	}
-	return 0;
-}
-
-
-static int wps_build_serial_number(struct wps_device_data *dev,
-				   struct wpabuf *msg)
-{
-	size_t len;
-	wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
-	wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
-	len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
-	if (len == 0) {
-		/*
-		 * Some deployed WPS implementations fail to parse zero-length
-		 * attributes. As a workaround, send a null character if the
-		 * device attribute string is empty.
-		 */
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, '\0');
-	} else {
-		wpabuf_put_be16(msg, len);
-		wpabuf_put_data(msg, dev->serial_number, len);
-	}
-	return 0;
-}
-
-
-int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Primary Device Type");
-	wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
-	wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
-	wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN);
-	return 0;
-}
-
-
-static int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
-{
-	size_t len;
-	wpa_printf(MSG_DEBUG, "WPS:  * Device Name");
-	wpabuf_put_be16(msg, ATTR_DEV_NAME);
-	len = dev->device_name ? os_strlen(dev->device_name) : 0;
-	if (len == 0) {
-		/*
-		 * Some deployed WPS implementations fail to parse zero-length
-		 * attributes. As a workaround, send a null character if the
-		 * device attribute string is empty.
-		 */
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, '\0');
-	} else {
-		wpabuf_put_be16(msg, len);
-		wpabuf_put_data(msg, dev->device_name, len);
-	}
-	return 0;
-}
-
-
-int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)
-{
-	if (wps_build_manufacturer(dev, msg) ||
-	    wps_build_model_name(dev, msg) ||
-	    wps_build_model_number(dev, msg) ||
-	    wps_build_serial_number(dev, msg) ||
-	    wps_build_primary_dev_type(dev, msg) ||
-	    wps_build_dev_name(dev, msg))
-		return -1;
-	return 0;
-}
-
-
-int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * OS Version");
-	wpabuf_put_be16(msg, ATTR_OS_VERSION);
-	wpabuf_put_be16(msg, 4);
-	wpabuf_put_be32(msg, 0x80000000 | dev->os_version);
-	return 0;
-}
-
-
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", dev->rf_bands);
-	wpabuf_put_be16(msg, ATTR_RF_BANDS);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, dev->rf_bands);
-	return 0;
-}
-
-
-static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
-				    size_t str_len)
-{
-	if (str == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
-
-	os_free(dev->manufacturer);
-	dev->manufacturer = os_malloc(str_len + 1);
-	if (dev->manufacturer == NULL)
-		return -1;
-	os_memcpy(dev->manufacturer, str, str_len);
-	dev->manufacturer[str_len] = '\0';
-
-	return 0;
-}
-
-
-static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
-				  size_t str_len)
-{
-	if (str == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Model Name received");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
-
-	os_free(dev->model_name);
-	dev->model_name = os_malloc(str_len + 1);
-	if (dev->model_name == NULL)
-		return -1;
-	os_memcpy(dev->model_name, str, str_len);
-	dev->model_name[str_len] = '\0';
-
-	return 0;
-}
-
-
-static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
-				    size_t str_len)
-{
-	if (str == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Model Number received");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
-
-	os_free(dev->model_number);
-	dev->model_number = os_malloc(str_len + 1);
-	if (dev->model_number == NULL)
-		return -1;
-	os_memcpy(dev->model_number, str, str_len);
-	dev->model_number[str_len] = '\0';
-
-	return 0;
-}
-
-
-static int wps_process_serial_number(struct wps_device_data *dev,
-				     const u8 *str, size_t str_len)
-{
-	if (str == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Serial Number received");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
-
-	os_free(dev->serial_number);
-	dev->serial_number = os_malloc(str_len + 1);
-	if (dev->serial_number == NULL)
-		return -1;
-	os_memcpy(dev->serial_number, str, str_len);
-	dev->serial_number[str_len] = '\0';
-
-	return 0;
-}
-
-
-static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
-				size_t str_len)
-{
-	if (str == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Device Name received");
-		return -1;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
-
-	os_free(dev->device_name);
-	dev->device_name = os_malloc(str_len + 1);
-	if (dev->device_name == NULL)
-		return -1;
-	os_memcpy(dev->device_name, str, str_len);
-	dev->device_name[str_len] = '\0';
-
-	return 0;
-}
-
-
-static int wps_process_primary_dev_type(struct wps_device_data *dev,
-					const u8 *dev_type)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-	if (dev_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
-		return -1;
-	}
-
-	os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN);
-	wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s",
-		   wps_dev_type_bin2str(dev->pri_dev_type, devtype,
-					sizeof(devtype)));
-
-	return 0;
-}
-
-
-int wps_process_device_attrs(struct wps_device_data *dev,
-			     struct wps_parse_attr *attr)
-{
-	if (wps_process_manufacturer(dev, attr->manufacturer,
-				     attr->manufacturer_len) ||
-	    wps_process_model_name(dev, attr->model_name,
-				   attr->model_name_len) ||
-	    wps_process_model_number(dev, attr->model_number,
-				     attr->model_number_len) ||
-	    wps_process_serial_number(dev, attr->serial_number,
-				      attr->serial_number_len) ||
-	    wps_process_primary_dev_type(dev, attr->primary_dev_type) ||
-	    wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len))
-		return -1;
-	return 0;
-}
-
-
-int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
-{
-	if (ver == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No OS Version received");
-		return -1;
-	}
-
-	dev->os_version = WPA_GET_BE32(ver);
-	wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version);
-
-	return 0;
-}
-
-
-int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
-{
-	if (bands == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No RF Bands received");
-		return -1;
-	}
-
-	dev->rf_bands = *bands;
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands);
-
-	return 0;
-}
-
-
-void wps_device_data_dup(struct wps_device_data *dst,
-			 const struct wps_device_data *src)
-{
-	if (src->device_name)
-		dst->device_name = os_strdup(src->device_name);
-	if (src->manufacturer)
-		dst->manufacturer = os_strdup(src->manufacturer);
-	if (src->model_name)
-		dst->model_name = os_strdup(src->model_name);
-	if (src->model_number)
-		dst->model_number = os_strdup(src->model_number);
-	if (src->serial_number)
-		dst->serial_number = os_strdup(src->serial_number);
-	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
-	dst->os_version = src->os_version;
-	dst->rf_bands = src->rf_bands;
-}
-
-
-void wps_device_data_free(struct wps_device_data *dev)
-{
-	os_free(dev->device_name);
-	dev->device_name = NULL;
-	os_free(dev->manufacturer);
-	dev->manufacturer = NULL;
-	os_free(dev->model_name);
-	dev->model_name = NULL;
-	os_free(dev->model_number);
-	dev->model_number = NULL;
-	os_free(dev->serial_number);
-	dev->serial_number = NULL;
-}

Copied: vendor/wpa/2.0/src/wps/wps_dev_attr.c (from rev 9639, vendor/wpa/dist/src/wps/wps_dev_attr.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_dev_attr.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_dev_attr.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,452 @@
+/*
+ * Wi-Fi Protected Setup - device attributes
+ * Copyright (c) 2008, Jouni Malinen <j at 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 "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Manufacturer");
+	wpabuf_put_be16(msg, ATTR_MANUFACTURER);
+	len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
+#ifndef CONFIG_WPS_STRICT
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a space character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, ' ');
+		return 0;
+	}
+#endif /* CONFIG_WPS_STRICT */
+	wpabuf_put_be16(msg, len);
+	wpabuf_put_data(msg, dev->manufacturer, len);
+	return 0;
+}
+
+
+int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Model Name");
+	wpabuf_put_be16(msg, ATTR_MODEL_NAME);
+	len = dev->model_name ? os_strlen(dev->model_name) : 0;
+#ifndef CONFIG_WPS_STRICT
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a space character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, ' ');
+		return 0;
+	}
+#endif /* CONFIG_WPS_STRICT */
+	wpabuf_put_be16(msg, len);
+	wpabuf_put_data(msg, dev->model_name, len);
+	return 0;
+}
+
+
+int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Model Number");
+	wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
+	len = dev->model_number ? os_strlen(dev->model_number) : 0;
+#ifndef CONFIG_WPS_STRICT
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a space character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, ' ');
+		return 0;
+	}
+#endif /* CONFIG_WPS_STRICT */
+	wpabuf_put_be16(msg, len);
+	wpabuf_put_data(msg, dev->model_number, len);
+	return 0;
+}
+
+
+static int wps_build_serial_number(struct wps_device_data *dev,
+				   struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
+	wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
+	len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
+#ifndef CONFIG_WPS_STRICT
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a space character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, ' ');
+		return 0;
+	}
+#endif /* CONFIG_WPS_STRICT */
+	wpabuf_put_be16(msg, len);
+	wpabuf_put_data(msg, dev->serial_number, len);
+	return 0;
+}
+
+
+int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Primary Device Type");
+	wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
+	wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
+	wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN);
+	return 0;
+}
+
+
+int wps_build_secondary_dev_type(struct wps_device_data *dev,
+				  struct wpabuf *msg)
+{
+	if (!dev->num_sec_dev_types)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Secondary Device Type");
+	wpabuf_put_be16(msg, ATTR_SECONDARY_DEV_TYPE_LIST);
+	wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
+	wpabuf_put_data(msg, dev->sec_dev_type,
+			WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
+
+	return 0;
+}
+
+
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+			   unsigned int num_req_dev_types,
+			   const u8 *req_dev_types)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_req_dev_types; i++) {
+		wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type",
+			    req_dev_types + i * WPS_DEV_TYPE_LEN,
+			    WPS_DEV_TYPE_LEN);
+		wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE);
+		wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
+		wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN,
+				WPS_DEV_TYPE_LEN);
+	}
+
+	return 0;
+}
+
+
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Name");
+	wpabuf_put_be16(msg, ATTR_DEV_NAME);
+	len = dev->device_name ? os_strlen(dev->device_name) : 0;
+#ifndef CONFIG_WPS_STRICT
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a space character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, ' ');
+		return 0;
+	}
+#endif /* CONFIG_WPS_STRICT */
+	wpabuf_put_be16(msg, len);
+	wpabuf_put_data(msg, dev->device_name, len);
+	return 0;
+}
+
+
+int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	if (wps_build_manufacturer(dev, msg) ||
+	    wps_build_model_name(dev, msg) ||
+	    wps_build_model_number(dev, msg) ||
+	    wps_build_serial_number(dev, msg) ||
+	    wps_build_primary_dev_type(dev, msg) ||
+	    wps_build_dev_name(dev, msg))
+		return -1;
+	return 0;
+}
+
+
+int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * OS Version");
+	wpabuf_put_be16(msg, ATTR_OS_VERSION);
+	wpabuf_put_be16(msg, 4);
+	wpabuf_put_be32(msg, 0x80000000 | dev->os_version);
+	return 0;
+}
+
+
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	if (dev->vendor_ext_m1 != NULL) {
+		wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension M1",
+			    wpabuf_head_u8(dev->vendor_ext_m1),
+			    wpabuf_len(dev->vendor_ext_m1));
+		wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+		wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1));
+		wpabuf_put_buf(msg, dev->vendor_ext_m1);
+	}
+	return 0;
+}
+
+
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", dev->rf_bands);
+	wpabuf_put_be16(msg, ATTR_RF_BANDS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, dev->rf_bands);
+	return 0;
+}
+
+
+int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	int i;
+
+	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+		if (dev->vendor_ext[i] == NULL)
+			continue;
+		wpa_hexdump(MSG_DEBUG, "WPS:  * Vendor Extension",
+			    wpabuf_head_u8(dev->vendor_ext[i]),
+			    wpabuf_len(dev->vendor_ext[i]));
+		wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+		wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i]));
+		wpabuf_put_buf(msg, dev->vendor_ext[i]);
+	}
+
+	return 0;
+}
+
+
+static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
+				    size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
+
+	os_free(dev->manufacturer);
+	dev->manufacturer = os_malloc(str_len + 1);
+	if (dev->manufacturer == NULL)
+		return -1;
+	os_memcpy(dev->manufacturer, str, str_len);
+	dev->manufacturer[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
+				  size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Model Name received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
+
+	os_free(dev->model_name);
+	dev->model_name = os_malloc(str_len + 1);
+	if (dev->model_name == NULL)
+		return -1;
+	os_memcpy(dev->model_name, str, str_len);
+	dev->model_name[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
+				    size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Model Number received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
+
+	os_free(dev->model_number);
+	dev->model_number = os_malloc(str_len + 1);
+	if (dev->model_number == NULL)
+		return -1;
+	os_memcpy(dev->model_number, str, str_len);
+	dev->model_number[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_serial_number(struct wps_device_data *dev,
+				     const u8 *str, size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Serial Number received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
+
+	os_free(dev->serial_number);
+	dev->serial_number = os_malloc(str_len + 1);
+	if (dev->serial_number == NULL)
+		return -1;
+	os_memcpy(dev->serial_number, str, str_len);
+	dev->serial_number[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
+				size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Name received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
+
+	os_free(dev->device_name);
+	dev->device_name = os_malloc(str_len + 1);
+	if (dev->device_name == NULL)
+		return -1;
+	os_memcpy(dev->device_name, str, str_len);
+	dev->device_name[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_primary_dev_type(struct wps_device_data *dev,
+					const u8 *dev_type)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	if (dev_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
+		return -1;
+	}
+
+	os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN);
+	wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s",
+		   wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					sizeof(devtype)));
+
+	return 0;
+}
+
+
+int wps_process_device_attrs(struct wps_device_data *dev,
+			     struct wps_parse_attr *attr)
+{
+	if (wps_process_manufacturer(dev, attr->manufacturer,
+				     attr->manufacturer_len) ||
+	    wps_process_model_name(dev, attr->model_name,
+				   attr->model_name_len) ||
+	    wps_process_model_number(dev, attr->model_number,
+				     attr->model_number_len) ||
+	    wps_process_serial_number(dev, attr->serial_number,
+				      attr->serial_number_len) ||
+	    wps_process_primary_dev_type(dev, attr->primary_dev_type) ||
+	    wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len))
+		return -1;
+	return 0;
+}
+
+
+int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
+{
+	if (ver == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No OS Version received");
+		return -1;
+	}
+
+	dev->os_version = WPA_GET_BE32(ver);
+	wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version);
+
+	return 0;
+}
+
+
+int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
+{
+	if (bands == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No RF Bands received");
+		return -1;
+	}
+
+	dev->rf_bands = *bands;
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands);
+
+	return 0;
+}
+
+
+void wps_device_data_dup(struct wps_device_data *dst,
+			 const struct wps_device_data *src)
+{
+	if (src->device_name)
+		dst->device_name = os_strdup(src->device_name);
+	if (src->manufacturer)
+		dst->manufacturer = os_strdup(src->manufacturer);
+	if (src->model_name)
+		dst->model_name = os_strdup(src->model_name);
+	if (src->model_number)
+		dst->model_number = os_strdup(src->model_number);
+	if (src->serial_number)
+		dst->serial_number = os_strdup(src->serial_number);
+	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
+	dst->os_version = src->os_version;
+	dst->rf_bands = src->rf_bands;
+}
+
+
+void wps_device_data_free(struct wps_device_data *dev)
+{
+	os_free(dev->device_name);
+	dev->device_name = NULL;
+	os_free(dev->manufacturer);
+	dev->manufacturer = NULL;
+	os_free(dev->model_name);
+	dev->model_name = NULL;
+	os_free(dev->model_number);
+	dev->model_number = NULL;
+	os_free(dev->serial_number);
+	dev->serial_number = NULL;
+}

Deleted: vendor/wpa/2.0/src/wps/wps_dev_attr.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_dev_attr.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_dev_attr.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,33 +0,0 @@
-/*
- * Wi-Fi Protected Setup - device attributes
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_DEV_ATTR_H
-#define WPS_DEV_ATTR_H
-
-struct wps_parse_attr;
-
-int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
-int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
-int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
-int wps_build_primary_dev_type(struct wps_device_data *dev,
-			       struct wpabuf *msg);
-int wps_process_device_attrs(struct wps_device_data *dev,
-			     struct wps_parse_attr *attr);
-int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
-int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
-void wps_device_data_dup(struct wps_device_data *dst,
-			 const struct wps_device_data *src);
-void wps_device_data_free(struct wps_device_data *dev);
-
-#endif /* WPS_DEV_ATTR_H */

Copied: vendor/wpa/2.0/src/wps/wps_dev_attr.h (from rev 9639, vendor/wpa/dist/src/wps/wps_dev_attr.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_dev_attr.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_dev_attr.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,39 @@
+/*
+ * Wi-Fi Protected Setup - device attributes
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_DEV_ATTR_H
+#define WPS_DEV_ATTR_H
+
+struct wps_parse_attr;
+
+int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_primary_dev_type(struct wps_device_data *dev,
+			       struct wpabuf *msg);
+int wps_build_secondary_dev_type(struct wps_device_data *dev,
+				 struct wpabuf *msg);
+int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_process_device_attrs(struct wps_device_data *dev,
+			     struct wps_parse_attr *attr);
+int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
+int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
+void wps_device_data_dup(struct wps_device_data *dst,
+			 const struct wps_device_data *src);
+void wps_device_data_free(struct wps_device_data *dev);
+int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
+			   unsigned int num_req_dev_types,
+			   const u8 *req_dev_types);
+
+#endif /* WPS_DEV_ATTR_H */

Deleted: vendor/wpa/2.0/src/wps/wps_enrollee.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_enrollee.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_enrollee.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1240 +0,0 @@
-/*
- * Wi-Fi Protected Setup - Enrollee
- * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/crypto.h"
-#include "crypto/sha256.h"
-#include "wps_i.h"
-#include "wps_dev_attr.h"
-
-
-static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
-	return 0;
-}
-
-
-static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 state;
-	if (wps->wps->ap)
-		state = wps->wps->wps_state;
-	else
-		state = WPS_STATE_NOT_CONFIGURED;
-	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
-		   state);
-	wpabuf_put_be16(msg, ATTR_WPS_STATE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, state);
-	return 0;
-}
-
-
-static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 *hash;
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
-		return -1;
-	wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
-		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
-
-	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
-			   "E-Hash derivation");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash1");
-	wpabuf_put_be16(msg, ATTR_E_HASH1);
-	wpabuf_put_be16(msg, SHA256_MAC_LEN);
-	hash = wpabuf_put(msg, SHA256_MAC_LEN);
-	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
-	addr[0] = wps->snonce;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk1;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
-
-	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash2");
-	wpabuf_put_be16(msg, ATTR_E_HASH2);
-	wpabuf_put_be16(msg, SHA256_MAC_LEN);
-	hash = wpabuf_put(msg, SHA256_MAC_LEN);
-	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
-	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk2;
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
-
-	return 0;
-}
-
-
-static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce1");
-	wpabuf_put_be16(msg, ATTR_E_SNONCE1);
-	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
-	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
-	return 0;
-}
-
-
-static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce2");
-	wpabuf_put_be16(msg, ATTR_E_SNONCE2);
-	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
-	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
-			WPS_SECRET_NONCE_LEN);
-	return 0;
-}
-
-
-static struct wpabuf * wps_build_m1(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	if (os_get_random(wps->nonce_e, WPS_NONCE_LEN) < 0)
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
-		    wps->nonce_e, WPS_NONCE_LEN);
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M1) ||
-	    wps_build_uuid_e(msg, wps->uuid_e) ||
-	    wps_build_mac_addr(wps, msg) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_public_key(wps, msg) ||
-	    wps_build_auth_type_flags(wps, msg) ||
-	    wps_build_encr_type_flags(wps, msg) ||
-	    wps_build_conn_type_flags(wps, msg) ||
-	    wps_build_config_methods(msg, wps->wps->config_methods) ||
-	    wps_build_wps_state(wps, msg) ||
-	    wps_build_device_attrs(&wps->wps->dev, msg) ||
-	    wps_build_rf_bands(&wps->wps->dev, msg) ||
-	    wps_build_assoc_state(wps, msg) ||
-	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
-	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
-	    wps_build_os_version(&wps->wps->dev, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	wps->state = RECV_M2;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m3(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
-
-	if (wps->dev_password == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
-		return NULL;
-	}
-	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M3) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_e_hash(wps, msg) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	wps->state = RECV_M4;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m5(struct wps_data *wps)
-{
-	struct wpabuf *msg, *plain;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
-
-	plain = wpabuf_alloc(200);
-	if (plain == NULL)
-		return NULL;
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M5) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_e_snonce1(wps, plain) ||
-	    wps_build_key_wrap_auth(wps, plain) ||
-	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wps->state = RECV_M6;
-	return msg;
-}
-
-
-static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
-	wpabuf_put_be16(msg, ATTR_SSID);
-	wpabuf_put_be16(msg, wps->wps->ssid_len);
-	wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
-	return 0;
-}
-
-
-static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type");
-	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, wps->wps->auth_types);
-	return 0;
-}
-
-
-static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type");
-	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, wps->wps->encr_types);
-	return 0;
-}
-
-
-static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
-	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
-	wpabuf_put_be16(msg, wps->wps->network_key_len);
-	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
-	return 0;
-}
-
-
-static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (AP BSSID)");
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
-	return 0;
-}
-
-
-static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
-{
-	if (wps->wps->ap_settings) {
-		wpa_printf(MSG_DEBUG, "WPS:  * AP Settings (pre-configured)");
-		wpabuf_put_data(plain, wps->wps->ap_settings,
-				wps->wps->ap_settings_len);
-		return 0;
-	}
-
-	return wps_build_cred_ssid(wps, plain) ||
-		wps_build_cred_mac_addr(wps, plain) ||
-		wps_build_cred_auth_type(wps, plain) ||
-		wps_build_cred_encr_type(wps, plain) ||
-		wps_build_cred_network_key(wps, plain);
-}
-
-
-static struct wpabuf * wps_build_m7(struct wps_data *wps)
-{
-	struct wpabuf *msg, *plain;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
-
-	plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
-	if (plain == NULL)
-		return NULL;
-
-	msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
-	if (msg == NULL) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M7) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_e_snonce2(wps, plain) ||
-	    (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
-	    wps_build_key_wrap_auth(wps, plain) ||
-	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	if (wps->wps->ap && wps->wps->registrar) {
-		/*
-		 * If the Registrar is only learning our current configuration,
-		 * it may not continue protocol run to successful completion.
-		 * Store information here to make sure it remains available.
-		 */
-		wps_device_store(wps->wps->registrar, &wps->peer_dev,
-				 wps->uuid_r);
-	}
-
-	wps->state = RECV_M8;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_DONE) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	if (wps->wps->ap)
-		wps->state = RECV_ACK;
-	else {
-		wps_success_event(wps->wps);
-		wps->state = WPS_FINISHED;
-	}
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_config_error(msg, wps->config_error)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
-				     enum wsc_op_code *op_code)
-{
-	struct wpabuf *msg;
-
-	switch (wps->state) {
-	case SEND_M1:
-		msg = wps_build_m1(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M3:
-		msg = wps_build_m3(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M5:
-		msg = wps_build_m5(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M7:
-		msg = wps_build_m7(wps);
-		*op_code = WSC_MSG;
-		break;
-	case RECEIVED_M2D:
-		if (wps->wps->ap) {
-			msg = wps_build_wsc_nack(wps);
-			*op_code = WSC_NACK;
-			break;
-		}
-		msg = wps_build_wsc_ack(wps);
-		*op_code = WSC_ACK;
-		if (msg) {
-			/* Another M2/M2D may be received */
-			wps->state = RECV_M2;
-		}
-		break;
-	case SEND_WSC_NACK:
-		msg = wps_build_wsc_nack(wps);
-		*op_code = WSC_NACK;
-		break;
-	case WPS_MSG_DONE:
-		msg = wps_build_wsc_done(wps);
-		*op_code = WSC_Done;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
-			   "a message", wps->state);
-		msg = NULL;
-		break;
-	}
-
-	if (*op_code == WSC_MSG && msg) {
-		/* Save a copy of the last message for Authenticator derivation
-		 */
-		wpabuf_free(wps->last_msg);
-		wps->last_msg = wpabuf_dup(msg);
-	}
-
-	return msg;
-}
-
-
-static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
-{
-	if (r_nonce == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
-		return -1;
-	}
-
-	os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
-		    wps->nonce_r, WPS_NONCE_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
-{
-	if (e_nonce == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
-		return -1;
-	}
-
-	if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
-{
-	if (uuid_r == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
-		return -1;
-	}
-
-	os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
-			      size_t pk_len)
-{
-	if (pk == NULL || pk_len == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
-		return -1;
-	}
-
-#ifdef CONFIG_WPS_OOB
-	if (wps->dev_pw_id != DEV_PW_DEFAULT &&
-	    wps->wps->oob_conf.pubkey_hash) {
-		const u8 *addr[1];
-		u8 hash[WPS_HASH_LEN];
-
-		addr[0] = pk;
-		sha256_vector(1, addr, &pk_len, hash);
-		if (os_memcmp(hash,
-			      wpabuf_head(wps->wps->oob_conf.pubkey_hash),
-			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
-			wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
-			return -1;
-		}
-	}
-#endif /* CONFIG_WPS_OOB */
-
-	wpabuf_free(wps->dh_pubkey_r);
-	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
-	if (wps->dh_pubkey_r == NULL)
-		return -1;
-
-	if (wps_derive_keys(wps) < 0)
-		return -1;
-
-	return 0;
-}
-
-
-static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
-{
-	if (r_hash1 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
-		return -1;
-	}
-
-	os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
-{
-	if (r_hash2 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
-		return -1;
-	}
-
-	os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (r_snonce1 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
-			WPS_SECRET_NONCE_LEN);
-
-	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
-	addr[0] = r_snonce1;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk1;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-
-	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
-			   "not match with the pre-committed value");
-		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
-		wps_pwd_auth_fail_event(wps->wps, 1, 1);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
-		   "half of the device password");
-
-	return 0;
-}
-
-
-static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (r_snonce2 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
-			WPS_SECRET_NONCE_LEN);
-
-	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
-	addr[0] = r_snonce2;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk2;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-
-	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
-			   "not match with the pre-committed value");
-		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
-		wps_pwd_auth_fail_event(wps->wps, 1, 2);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
-		   "half of the device password");
-
-	return 0;
-}
-
-
-static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
-			      size_t cred_len)
-{
-	struct wps_parse_attr attr;
-	struct wpabuf msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
-	os_memset(&wps->cred, 0, sizeof(wps->cred));
-	wpabuf_set(&msg, cred, cred_len);
-	if (wps_parse_msg(&msg, &attr) < 0 ||
-	    wps_process_cred(&attr, &wps->cred))
-		return -1;
-
-	if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
-	    0) {
-		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
-			   MACSTR ") does not match with own address (" MACSTR
-			   ")", MAC2STR(wps->cred.mac_addr),
-			   MAC2STR(wps->wps->dev.mac_addr));
-		/*
-		 * In theory, this could be consider fatal error, but there are
-		 * number of deployed implementations using other address here
-		 * due to unclarity in the specification. For interoperability
-		 * reasons, allow this to be processed since we do not really
-		 * use the MAC Address information for anything.
-		 */
-	}
-
-	if (wps->wps->cred_cb) {
-		wps->cred.cred_attr = cred - 4;
-		wps->cred.cred_attr_len = cred_len + 4;
-		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
-		wps->cred.cred_attr = NULL;
-		wps->cred.cred_attr_len = 0;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
-			     size_t cred_len[], size_t num_cred)
-{
-	size_t i;
-
-	if (wps->wps->ap)
-		return 0;
-
-	if (num_cred == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
-			   "received");
-		return -1;
-	}
-
-	for (i = 0; i < num_cred; i++) {
-		if (wps_process_cred_e(wps, cred[i], cred_len[i]))
-			return -1;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_ap_settings_e(struct wps_data *wps,
-				     struct wps_parse_attr *attr,
-				     struct wpabuf *attrs)
-{
-	struct wps_credential cred;
-
-	if (!wps->wps->ap)
-		return 0;
-
-	if (wps_process_ap_settings(attr, &cred) < 0)
-		return -1;
-
-	wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
-		   "Registrar");
-
-	if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
-	    0) {
-		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings ("
-			   MACSTR ") does not match with own address (" MACSTR
-			   ")", MAC2STR(cred.mac_addr),
-			   MAC2STR(wps->wps->dev.mac_addr));
-		/*
-		 * In theory, this could be consider fatal error, but there are
-		 * number of deployed implementations using other address here
-		 * due to unclarity in the specification. For interoperability
-		 * reasons, allow this to be processed since we do not really
-		 * use the MAC Address information for anything.
-		 */
-	}
-
-	if (wps->wps->cred_cb) {
-		cred.cred_attr = wpabuf_head(attrs);
-		cred.cred_attr_len = wpabuf_len(attrs);
-		wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
-	}
-
-	return 0;
-}
-
-
-static enum wps_process_res wps_process_m2(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Received M2");
-
-	if (wps->state != RECV_M2) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M2", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
-	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_uuid_r(wps, attr->uuid_r)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps->wps->ap &&
-	    (wps->wps->ap_setup_locked || wps->dev_password == NULL)) {
-		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
-			   "registration of a new Registrar");
-		wps->config_error = WPS_CFG_SETUP_LOCKED;
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg) ||
-	    wps_process_device_attrs(&wps->peer_dev, attr)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wps->state = SEND_M3;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m2d(struct wps_data *wps,
-					    struct wps_parse_attr *attr)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Received M2D");
-
-	if (wps->state != RECV_M2) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M2D", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
-			  attr->manufacturer, attr->manufacturer_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
-			  attr->model_name, attr->model_name_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
-			  attr->model_number, attr->model_number_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
-			  attr->serial_number, attr->serial_number_len);
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
-			  attr->dev_name, attr->dev_name_len);
-
-	if (wps->wps->event_cb) {
-		union wps_event_data data;
-		struct wps_event_m2d *m2d = &data.m2d;
-		os_memset(&data, 0, sizeof(data));
-		if (attr->config_methods)
-			m2d->config_methods =
-				WPA_GET_BE16(attr->config_methods);
-		m2d->manufacturer = attr->manufacturer;
-		m2d->manufacturer_len = attr->manufacturer_len;
-		m2d->model_name = attr->model_name;
-		m2d->model_name_len = attr->model_name_len;
-		m2d->model_number = attr->model_number;
-		m2d->model_number_len = attr->model_number_len;
-		m2d->serial_number = attr->serial_number;
-		m2d->serial_number_len = attr->serial_number_len;
-		m2d->dev_name = attr->dev_name;
-		m2d->dev_name_len = attr->dev_name_len;
-		m2d->primary_dev_type = attr->primary_dev_type;
-		if (attr->config_error)
-			m2d->config_error =
-				WPA_GET_BE16(attr->config_error);
-		if (attr->dev_password_id)
-			m2d->dev_password_id =
-				WPA_GET_BE16(attr->dev_password_id);
-		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
-	}
-
-	wps->state = RECEIVED_M2D;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m4(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	struct wpabuf *decrypted;
-	struct wps_parse_attr eattr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received M4");
-
-	if (wps->state != RECV_M4) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M4", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg) ||
-	    wps_process_r_hash1(wps, attr->r_hash1) ||
-	    wps_process_r_hash2(wps, attr->r_hash2)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
-					      attr->encr_settings_len);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
-			   "Settings attribute");
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
-		   "attribute");
-	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);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-	wpabuf_free(decrypted);
-
-	wps->state = SEND_M5;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m6(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	struct wpabuf *decrypted;
-	struct wps_parse_attr eattr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received M6");
-
-	if (wps->state != RECV_M6) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M6", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
-					      attr->encr_settings_len);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
-			   "Settings attribute");
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
-		   "attribute");
-	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);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-	wpabuf_free(decrypted);
-
-	wps->state = SEND_M7;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m8(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	struct wpabuf *decrypted;
-	struct wps_parse_attr eattr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received M8");
-
-	if (wps->state != RECV_M8) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M8", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
-					      attr->encr_settings_len);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
-			   "Settings attribute");
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
-		   "attribute");
-	if (wps_parse_msg(decrypted, &eattr) < 0 ||
-	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
-	    wps_process_creds(wps, eattr.cred, eattr.cred_len,
-			      eattr.num_cred) ||
-	    wps_process_ap_settings_e(wps, &eattr, decrypted)) {
-		wpabuf_free(decrypted);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-	wpabuf_free(decrypted);
-
-	wps->state = WPS_MSG_DONE;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
-						const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-	enum wps_process_res ret = WPS_CONTINUE;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	switch (*attr.msg_type) {
-	case WPS_M2:
-		ret = wps_process_m2(wps, msg, &attr);
-		break;
-	case WPS_M2D:
-		ret = wps_process_m2d(wps, &attr);
-		break;
-	case WPS_M4:
-		ret = wps_process_m4(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M4);
-		break;
-	case WPS_M6:
-		ret = wps_process_m6(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M6);
-		break;
-	case WPS_M8:
-		ret = wps_process_m8(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M8);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-	/*
-	 * Save a copy of the last message for Authenticator derivation if we
-	 * are continuing. However, skip M2D since it is not authenticated and
-	 * neither is the ACK/NACK response frame. This allows the possibly
-	 * following M2 to be processed correctly by using the previously sent
-	 * M1 in Authenticator derivation.
-	 */
-	if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
-		/* Save a copy of the last message for Authenticator derivation
-		 */
-		wpabuf_free(wps->last_msg);
-		wps->last_msg = wpabuf_dup(msg);
-	}
-
-	return ret;
-}
-
-
-static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
-						const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_WSC_ACK) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-	if (attr.registrar_nonce == NULL ||
-	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
-	{
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		return WPS_FAILURE;
-	}
-
-	if (wps->state == RECV_ACK && wps->wps->ap) {
-		wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
-			   "completed successfully");
-		wps_success_event(wps->wps);
-		wps->state = WPS_FINISHED;
-		return WPS_DONE;
-	}
-
-	return WPS_FAILURE;
-}
-
-
-static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
-						 const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_WSC_NACK) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-	if (attr.registrar_nonce == NULL ||
-	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
-	{
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
-			    attr.registrar_nonce, WPS_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
-			    wps->nonce_r, WPS_NONCE_LEN);
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
-			    attr.enrollee_nonce, WPS_NONCE_LEN);
-		wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
-			    wps->nonce_e, WPS_NONCE_LEN);
-		return WPS_FAILURE;
-	}
-
-	if (attr.config_error == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
-			   "in WSC_NACK");
-		return WPS_FAILURE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
-		   "Configuration Error %d", WPA_GET_BE16(attr.config_error));
-
-	switch (wps->state) {
-	case RECV_M4:
-		wps_fail_event(wps->wps, WPS_M3);
-		break;
-	case RECV_M6:
-		wps_fail_event(wps->wps, WPS_M5);
-		break;
-	case RECV_M8:
-		wps_fail_event(wps->wps, WPS_M7);
-		break;
-	default:
-		break;
-	}
-
-	/* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
-	 * Enrollee is Authenticator */
-	wps->state = SEND_WSC_NACK;
-
-	return WPS_FAILURE;
-}
-
-
-enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
-					      enum wsc_op_code op_code,
-					      const struct wpabuf *msg)
-{
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
-		   "op_code=%d)",
-		   (unsigned long) wpabuf_len(msg), op_code);
-
-	if (op_code == WSC_UPnP) {
-		/* Determine the OpCode based on message type attribute */
-		struct wps_parse_attr attr;
-		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
-			if (*attr.msg_type == WPS_WSC_ACK)
-				op_code = WSC_ACK;
-			else if (*attr.msg_type == WPS_WSC_NACK)
-				op_code = WSC_NACK;
-		}
-	}
-
-	switch (op_code) {
-	case WSC_MSG:
-	case WSC_UPnP:
-		return wps_process_wsc_msg(wps, msg);
-	case WSC_ACK:
-		return wps_process_wsc_ack(wps, msg);
-	case WSC_NACK:
-		return wps_process_wsc_nack(wps, msg);
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
-		return WPS_FAILURE;
-	}
-}

Copied: vendor/wpa/2.0/src/wps/wps_enrollee.c (from rev 9639, vendor/wpa/dist/src/wps/wps_enrollee.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_enrollee.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_enrollee.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1367 @@
+/*
+ * Wi-Fi Protected Setup - Enrollee
+ * Copyright (c) 2008, Jouni Malinen <j at 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/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
+	return 0;
+}
+
+
+static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 state;
+	if (wps->wps->ap)
+		state = wps->wps->wps_state;
+	else
+		state = WPS_STATE_NOT_CONFIGURED;
+	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
+		   state);
+	wpabuf_put_be16(msg, ATTR_WPS_STATE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, state);
+	return 0;
+}
+
+
+static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 *hash;
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
+		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
+
+	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
+			   "E-Hash derivation");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash1");
+	wpabuf_put_be16(msg, ATTR_E_HASH1);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = wps->snonce;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash2");
+	wpabuf_put_be16(msg, ATTR_E_HASH2);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
+static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce1");
+	wpabuf_put_be16(msg, ATTR_E_SNONCE1);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce2");
+	wpabuf_put_be16(msg, ATTR_E_SNONCE2);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
+			WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static struct wpabuf * wps_build_m1(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+	u16 config_methods;
+
+	if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
+		    wps->nonce_e, WPS_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	config_methods = wps->wps->config_methods;
+	if (wps->wps->ap && !wps->pbc_in_m1 &&
+	    (wps->dev_password_len != 0 ||
+	     (config_methods & WPS_CONFIG_DISPLAY))) {
+		/*
+		 * These are the methods that the AP supports as an Enrollee
+		 * for adding external Registrars, so remove PushButton.
+		 *
+		 * As a workaround for Windows 7 mechanism for probing WPS
+		 * capabilities from M1, leave PushButton option if no PIN
+		 * method is available or if WPS configuration enables PBC
+		 * workaround.
+		 */
+		config_methods &= ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+		config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+				    WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M1) ||
+	    wps_build_uuid_e(msg, wps->uuid_e) ||
+	    wps_build_mac_addr(wps, msg) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_public_key(wps, msg) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods(msg, config_methods) ||
+	    wps_build_wps_state(wps, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
+	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
+	    wps_build_os_version(&wps->wps->dev, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
+	    wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M2;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m3(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
+
+	if (wps->dev_password == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
+		return NULL;
+	}
+	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M3) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_hash(wps, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M4;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m5(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M5) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_snonce1(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    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);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_M6;
+	return msg;
+}
+
+
+static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, wps->wps->ssid_len);
+	wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
+	return 0;
+}
+
+
+static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
+{
+	u16 auth_type = wps->wps->auth_types;
+
+	/* Select the best authentication type */
+	if (auth_type & WPS_AUTH_WPA2PSK)
+		auth_type = WPS_AUTH_WPA2PSK;
+	else if (auth_type & WPS_AUTH_WPAPSK)
+		auth_type = WPS_AUTH_WPAPSK;
+	else if (auth_type & WPS_AUTH_OPEN)
+		auth_type = WPS_AUTH_OPEN;
+	else if (auth_type & WPS_AUTH_SHARED)
+		auth_type = WPS_AUTH_SHARED;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)", auth_type);
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, auth_type);
+	return 0;
+}
+
+
+static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
+{
+	u16 encr_type = wps->wps->encr_types;
+
+	/* Select the best encryption type */
+	if (wps->wps->auth_types & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
+		if (encr_type & WPS_ENCR_AES)
+			encr_type = WPS_ENCR_AES;
+		else if (encr_type & WPS_ENCR_TKIP)
+			encr_type = WPS_ENCR_TKIP;
+	} else {
+		if (encr_type & WPS_ENCR_WEP)
+			encr_type = WPS_ENCR_WEP;
+		else if (encr_type & WPS_ENCR_NONE)
+			encr_type = WPS_ENCR_NONE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)", encr_type);
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, encr_type);
+	return 0;
+}
+
+
+static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
+	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+	wpabuf_put_be16(msg, wps->wps->network_key_len);
+	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
+	return 0;
+}
+
+
+static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (AP BSSID)");
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
+{
+	if (wps->wps->ap_settings) {
+		wpa_printf(MSG_DEBUG, "WPS:  * AP Settings (pre-configured)");
+		wpabuf_put_data(plain, wps->wps->ap_settings,
+				wps->wps->ap_settings_len);
+		return 0;
+	}
+
+	return wps_build_cred_ssid(wps, plain) ||
+		wps_build_cred_mac_addr(wps, plain) ||
+		wps_build_cred_auth_type(wps, plain) ||
+		wps_build_cred_encr_type(wps, plain) ||
+		wps_build_cred_network_key(wps, plain);
+}
+
+
+static struct wpabuf * wps_build_m7(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
+
+	plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M7) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_snonce2(wps, plain) ||
+	    (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    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);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	if (wps->wps->ap && wps->wps->registrar) {
+		/*
+		 * If the Registrar is only learning our current configuration,
+		 * it may not continue protocol run to successful completion.
+		 * Store information here to make sure it remains available.
+		 */
+		wps_device_store(wps->wps->registrar, &wps->peer_dev,
+				 wps->uuid_r);
+	}
+
+	wps->state = RECV_M8;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_DONE) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (wps->wps->ap)
+		wps->state = RECV_ACK;
+	else {
+		wps_success_event(wps->wps);
+		wps->state = WPS_FINISHED;
+	}
+	return msg;
+}
+
+
+struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
+				     enum wsc_op_code *op_code)
+{
+	struct wpabuf *msg;
+
+	switch (wps->state) {
+	case SEND_M1:
+		msg = wps_build_m1(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M3:
+		msg = wps_build_m3(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M5:
+		msg = wps_build_m5(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M7:
+		msg = wps_build_m7(wps);
+		*op_code = WSC_MSG;
+		break;
+	case RECEIVED_M2D:
+		if (wps->wps->ap) {
+			msg = wps_build_wsc_nack(wps);
+			*op_code = WSC_NACK;
+			break;
+		}
+		msg = wps_build_wsc_ack(wps);
+		*op_code = WSC_ACK;
+		if (msg) {
+			/* Another M2/M2D may be received */
+			wps->state = RECV_M2;
+		}
+		break;
+	case SEND_WSC_NACK:
+		msg = wps_build_wsc_nack(wps);
+		*op_code = WSC_NACK;
+		break;
+	case WPS_MSG_DONE:
+		msg = wps_build_wsc_done(wps);
+		*op_code = WSC_Done;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
+			   "a message", wps->state);
+		msg = NULL;
+		break;
+	}
+
+	if (*op_code == WSC_MSG && msg) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return msg;
+}
+
+
+static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
+{
+	if (r_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
+		return -1;
+	}
+
+	os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
+		    wps->nonce_r, WPS_NONCE_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
+{
+	if (e_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
+		return -1;
+	}
+
+	if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
+{
+	if (uuid_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
+		return -1;
+	}
+
+	os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
+			      size_t pk_len)
+{
+	if (pk == NULL || pk_len == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
+		return -1;
+	}
+
+	wpabuf_free(wps->dh_pubkey_r);
+	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
+	if (wps->dh_pubkey_r == NULL)
+		return -1;
+
+	if (wps_derive_keys(wps) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
+{
+	if (r_hash1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
+{
+	if (r_hash2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (r_snonce1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
+			WPS_SECRET_NONCE_LEN);
+
+	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = r_snonce1;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		wps_pwd_auth_fail_event(wps->wps, 1, 1);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (r_snonce2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
+			WPS_SECRET_NONCE_LEN);
+
+	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = r_snonce2;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		wps_pwd_auth_fail_event(wps->wps, 1, 2);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
+			      size_t cred_len, int wps2)
+{
+	struct wps_parse_attr attr;
+	struct wpabuf msg;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
+	os_memset(&wps->cred, 0, sizeof(wps->cred));
+	wpabuf_set(&msg, cred, cred_len);
+	if (wps_parse_msg(&msg, &attr) < 0 ||
+	    wps_process_cred(&attr, &wps->cred))
+		return -1;
+
+	if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
+	    0) {
+		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
+			   MACSTR ") does not match with own address (" MACSTR
+			   ")", MAC2STR(wps->cred.mac_addr),
+			   MAC2STR(wps->wps->dev.mac_addr));
+		/*
+		 * In theory, this could be consider fatal error, but there are
+		 * number of deployed implementations using other address here
+		 * due to unclarity in the specification. For interoperability
+		 * reasons, allow this to be processed since we do not really
+		 * use the MAC Address information for anything.
+		 */
+#ifdef CONFIG_WPS_STRICT
+		if (wps2) {
+			wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+				   "MAC Address in AP Settings");
+			return -1;
+		}
+#endif /* CONFIG_WPS_STRICT */
+	}
+
+#ifdef CONFIG_WPS2
+	if (!(wps->cred.encr_type &
+	      (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+		if (wps->cred.encr_type & WPS_ENCR_WEP) {
+			wpa_printf(MSG_INFO, "WPS: Reject Credential "
+				   "due to WEP configuration");
+			wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
+			return -2;
+		}
+
+		wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
+			   "invalid encr_type 0x%x", wps->cred.encr_type);
+		return -1;
+	}
+#endif /* CONFIG_WPS2 */
+
+	if (wps->wps->cred_cb) {
+		wps->cred.cred_attr = cred - 4;
+		wps->cred.cred_attr_len = cred_len + 4;
+		ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+		wps->cred.cred_attr = NULL;
+		wps->cred.cred_attr_len = 0;
+	}
+
+	return ret;
+}
+
+
+static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
+			     size_t cred_len[], size_t num_cred, int wps2)
+{
+	size_t i;
+	int ok = 0;
+
+	if (wps->wps->ap)
+		return 0;
+
+	if (num_cred == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
+			   "received");
+		return -1;
+	}
+
+	for (i = 0; i < num_cred; i++) {
+		int res;
+		res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
+		if (res == 0)
+			ok++;
+		else if (res == -2)
+			wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped");
+		else
+			return -1;
+	}
+
+	if (ok == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute "
+			   "received");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_ap_settings_e(struct wps_data *wps,
+				     struct wps_parse_attr *attr,
+				     struct wpabuf *attrs, int wps2)
+{
+	struct wps_credential cred;
+
+	if (!wps->wps->ap)
+		return 0;
+
+	if (wps_process_ap_settings(attr, &cred) < 0)
+		return -1;
+
+	wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
+		   "Registrar");
+
+	if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
+	    0) {
+		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings ("
+			   MACSTR ") does not match with own address (" MACSTR
+			   ")", MAC2STR(cred.mac_addr),
+			   MAC2STR(wps->wps->dev.mac_addr));
+		/*
+		 * In theory, this could be consider fatal error, but there are
+		 * number of deployed implementations using other address here
+		 * due to unclarity in the specification. For interoperability
+		 * reasons, allow this to be processed since we do not really
+		 * use the MAC Address information for anything.
+		 */
+#ifdef CONFIG_WPS_STRICT
+		if (wps2) {
+			wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+				   "MAC Address in AP Settings");
+			return -1;
+		}
+#endif /* CONFIG_WPS_STRICT */
+	}
+
+#ifdef CONFIG_WPS2
+	if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
+	{
+		if (cred.encr_type & WPS_ENCR_WEP) {
+			wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
+				   "due to WEP configuration");
+			wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
+			return -1;
+		}
+
+		wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
+			   "invalid encr_type 0x%x", cred.encr_type);
+		return -1;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_WPS_STRICT
+	if (wps2) {
+		if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
+		    WPS_ENCR_TKIP ||
+		    (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+		    WPS_AUTH_WPAPSK) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 "
+				   "AP Settings: WPA-Personal/TKIP only");
+			wps->error_indication =
+				WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED;
+			return -1;
+		}
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+#ifdef CONFIG_WPS2
+	if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
+			   "TKIP+AES");
+		cred.encr_type |= WPS_ENCR_AES;
+	}
+
+	if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+	    WPS_AUTH_WPAPSK) {
+		wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
+			   "WPAPSK+WPA2PSK");
+		cred.auth_type |= WPS_AUTH_WPA2PSK;
+	}
+#endif /* CONFIG_WPS2 */
+
+	if (wps->wps->cred_cb) {
+		cred.cred_attr = wpabuf_head(attrs);
+		cred.cred_attr_len = wpabuf_len(attrs);
+		wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+	}
+
+	return 0;
+}
+
+
+static enum wps_process_res wps_process_m2(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M2");
+
+	if (wps->state != RECV_M2) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M2", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_uuid_r(wps, attr->uuid_r)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	/*
+	 * Stop here on an AP as an Enrollee if AP Setup is locked unless the
+	 * special locked mode is used to allow protocol run up to M7 in order
+	 * to support external Registrars that only learn the current AP
+	 * configuration without changing it.
+	 */
+	if (wps->wps->ap &&
+	    ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) ||
+	     wps->dev_password == NULL)) {
+		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
+			   "registration of a new Registrar");
+		wps->config_error = WPS_CFG_SETUP_LOCKED;
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg) ||
+	    wps_process_device_attrs(&wps->peer_dev, attr)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wps->state = SEND_M3;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m2d(struct wps_data *wps,
+					    struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M2D");
+
+	if (wps->state != RECV_M2) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M2D", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
+			  attr->manufacturer, attr->manufacturer_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
+			  attr->model_name, attr->model_name_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
+			  attr->model_number, attr->model_number_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
+			  attr->serial_number, attr->serial_number_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
+			  attr->dev_name, attr->dev_name_len);
+
+	if (wps->wps->event_cb) {
+		union wps_event_data data;
+		struct wps_event_m2d *m2d = &data.m2d;
+		os_memset(&data, 0, sizeof(data));
+		if (attr->config_methods)
+			m2d->config_methods =
+				WPA_GET_BE16(attr->config_methods);
+		m2d->manufacturer = attr->manufacturer;
+		m2d->manufacturer_len = attr->manufacturer_len;
+		m2d->model_name = attr->model_name;
+		m2d->model_name_len = attr->model_name_len;
+		m2d->model_number = attr->model_number;
+		m2d->model_number_len = attr->model_number_len;
+		m2d->serial_number = attr->serial_number;
+		m2d->serial_number_len = attr->serial_number_len;
+		m2d->dev_name = attr->dev_name;
+		m2d->dev_name_len = attr->dev_name_len;
+		m2d->primary_dev_type = attr->primary_dev_type;
+		if (attr->config_error)
+			m2d->config_error =
+				WPA_GET_BE16(attr->config_error);
+		if (attr->dev_password_id)
+			m2d->dev_password_id =
+				WPA_GET_BE16(attr->dev_password_id);
+		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
+	}
+
+	wps->state = RECEIVED_M2D;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m4(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M4");
+
+	if (wps->state != RECV_M4) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M4", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg) ||
+	    wps_process_r_hash1(wps, attr->r_hash1) ||
+	    wps_process_r_hash2(wps, attr->r_hash2)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	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);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M5;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m6(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M6");
+
+	if (wps->state != RECV_M6) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M6", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	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);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	if (wps->wps->ap)
+		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
+				   NULL);
+
+	wps->state = SEND_M7;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m8(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M8");
+
+	if (wps->state != RECV_M8) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M8", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->wps->ap && wps->wps->ap_setup_locked) {
+		/*
+		 * Stop here if special ap_setup_locked == 2 mode allowed the
+		 * protocol to continue beyond M2. This allows ER to learn the
+		 * current AP settings without changing them.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
+			   "registration of a new Registrar");
+		wps->config_error = WPS_CFG_SETUP_LOCKED;
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_validate_m8_encr(decrypted, wps->wps->ap,
+				 attr->version2 != NULL) < 0) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_creds(wps, eattr.cred, eattr.cred_len,
+			      eattr.num_cred, attr->version2 != NULL) ||
+	    wps_process_ap_settings_e(wps, &eattr, decrypted,
+				      attr->version2 != NULL)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = WPS_MSG_DONE;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	enum wps_process_res ret = WPS_CONTINUE;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	switch (*attr.msg_type) {
+	case WPS_M2:
+		if (wps_validate_m2(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m2(wps, msg, &attr);
+		break;
+	case WPS_M2D:
+		if (wps_validate_m2d(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m2d(wps, &attr);
+		break;
+	case WPS_M4:
+		if (wps_validate_m4(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m4(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M4, wps->config_error,
+				       wps->error_indication);
+		break;
+	case WPS_M6:
+		if (wps_validate_m6(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m6(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M6, wps->config_error,
+				       wps->error_indication);
+		break;
+	case WPS_M8:
+		if (wps_validate_m8(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m8(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M8, wps->config_error,
+				       wps->error_indication);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	/*
+	 * Save a copy of the last message for Authenticator derivation if we
+	 * are continuing. However, skip M2D since it is not authenticated and
+	 * neither is the ACK/NACK response frame. This allows the possibly
+	 * following M2 to be processed correctly by using the previously sent
+	 * M1 in Authenticator derivation.
+	 */
+	if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return ret;
+}
+
+
+static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_ACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (wps->state == RECV_ACK && wps->wps->ap) {
+		wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
+			   "completed successfully");
+		wps_success_event(wps->wps);
+		wps->state = WPS_FINISHED;
+		return WPS_DONE;
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	u16 config_error;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_NACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
+			    attr.registrar_nonce, WPS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
+			    wps->nonce_r, WPS_NONCE_LEN);
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
+			    attr.enrollee_nonce, WPS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
+			    wps->nonce_e, WPS_NONCE_LEN);
+		return WPS_FAILURE;
+	}
+
+	if (attr.config_error == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
+			   "in WSC_NACK");
+		return WPS_FAILURE;
+	}
+
+	config_error = WPA_GET_BE16(attr.config_error);
+	wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
+		   "Configuration Error %d", config_error);
+
+	switch (wps->state) {
+	case RECV_M4:
+		wps_fail_event(wps->wps, WPS_M3, config_error,
+			       wps->error_indication);
+		break;
+	case RECV_M6:
+		wps_fail_event(wps->wps, WPS_M5, config_error,
+			       wps->error_indication);
+		break;
+	case RECV_M8:
+		wps_fail_event(wps->wps, WPS_M7, config_error,
+			       wps->error_indication);
+		break;
+	default:
+		break;
+	}
+
+	/* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
+	 * Enrollee is Authenticator */
+	wps->state = SEND_WSC_NACK;
+
+	return WPS_FAILURE;
+}
+
+
+enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
+					      enum wsc_op_code op_code,
+					      const struct wpabuf *msg)
+{
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
+		   "op_code=%d)",
+		   (unsigned long) wpabuf_len(msg), op_code);
+
+	if (op_code == WSC_UPnP) {
+		/* Determine the OpCode based on message type attribute */
+		struct wps_parse_attr attr;
+		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
+			if (*attr.msg_type == WPS_WSC_ACK)
+				op_code = WSC_ACK;
+			else if (*attr.msg_type == WPS_WSC_NACK)
+				op_code = WSC_NACK;
+		}
+	}
+
+	switch (op_code) {
+	case WSC_MSG:
+	case WSC_UPnP:
+		return wps_process_wsc_msg(wps, msg);
+	case WSC_ACK:
+		if (wps_validate_wsc_ack(msg) < 0)
+			return WPS_FAILURE;
+		return wps_process_wsc_ack(wps, msg);
+	case WSC_NACK:
+		if (wps_validate_wsc_nack(msg) < 0)
+			return WPS_FAILURE;
+		return wps_process_wsc_nack(wps, msg);
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
+		return WPS_FAILURE;
+	}
+}

Deleted: vendor/wpa/2.0/src/wps/wps_er.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_er.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_er.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1663 +0,0 @@
-/*
- * Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "uuid.h"
-#include "eloop.h"
-#include "httpread.h"
-#include "http_client.h"
-#include "http_server.h"
-#include "upnp_xml.h"
-#include "wps_i.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-#include "wps_er.h"
-
-
-static void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
-static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
-static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
-static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
-static int wps_er_send_get_device_info(struct wps_er_ap *ap,
-				       void (*m1_handler)(struct wps_er_ap *ap,
-							  struct wpabuf *m1));
-
-
-static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
-			     enum wps_event event)
-{
-	union wps_event_data data;
-	struct wps_event_er_enrollee *ev = &data.enrollee;
-
-	if (wps->event_cb == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	ev->uuid = sta->uuid;
-	ev->mac_addr = sta->addr;
-	ev->m1_received = sta->m1_received;
-	ev->config_methods = sta->config_methods;
-	ev->dev_passwd_id = sta->dev_passwd_id;
-	ev->pri_dev_type = sta->pri_dev_type;
-	ev->dev_name = sta->dev_name;
-	ev->manufacturer = sta->manufacturer;
-	ev->model_name = sta->model_name;
-	ev->model_number = sta->model_number;
-	ev->serial_number = sta->serial_number;
-	wps->event_cb(wps->cb_ctx, event, &data);
-}
-
-
-static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr)
-{
-	struct wps_er_sta *sta;
-	dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
-		if (os_memcmp(sta->addr, addr, ETH_ALEN) == 0)
-			return sta;
-	}
-	return NULL;
-}
-
-
-static void wps_er_sta_free(struct wps_er_sta *sta)
-{
-	wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
-	if (sta->wps)
-		wps_deinit(sta->wps);
-	os_free(sta->manufacturer);
-	os_free(sta->model_name);
-	os_free(sta->model_number);
-	os_free(sta->serial_number);
-	os_free(sta->dev_name);
-	http_client_free(sta->http);
-	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
-	os_free(sta->cred);
-	os_free(sta);
-}
-
-
-static void wps_er_sta_remove_all(struct wps_er_ap *ap)
-{
-	struct wps_er_sta *prev, *sta;
-	dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
-		wps_er_sta_free(sta);
-}
-
-
-static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
-					struct in_addr *addr, const u8 *uuid)
-{
-	struct wps_er_ap *ap;
-	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
-		if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
-		    (uuid == NULL ||
-		     os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
-			return ap;
-	}
-	return NULL;
-}
-
-
-static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
-{
-	struct wps_er_ap *ap;
-	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
-		if (ap->id == id)
-			return ap;
-	}
-	return NULL;
-}
-
-
-static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
-			    enum wps_event event)
-{
-	union wps_event_data data;
-	struct wps_event_er_ap *evap = &data.ap;
-
-	if (wps->event_cb == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	evap->uuid = ap->uuid;
-	evap->friendly_name = ap->friendly_name;
-	evap->manufacturer = ap->manufacturer;
-	evap->manufacturer_url = ap->manufacturer_url;
-	evap->model_description = ap->model_description;
-	evap->model_name = ap->model_name;
-	evap->model_number = ap->model_number;
-	evap->model_url = ap->model_url;
-	evap->serial_number = ap->serial_number;
-	evap->upc = ap->upc;
-	evap->pri_dev_type = ap->pri_dev_type;
-	evap->wps_state = ap->wps_state;
-	evap->mac_addr = ap->mac_addr;
-	wps->event_cb(wps->cb_ctx, event, &data);
-}
-
-
-static void wps_er_ap_free(struct wps_er_ap *ap)
-{
-	http_client_free(ap->http);
-	ap->http = NULL;
-
-	os_free(ap->location);
-	os_free(ap->friendly_name);
-	os_free(ap->manufacturer);
-	os_free(ap->manufacturer_url);
-	os_free(ap->model_description);
-	os_free(ap->model_name);
-	os_free(ap->model_number);
-	os_free(ap->model_url);
-	os_free(ap->serial_number);
-	os_free(ap->udn);
-	os_free(ap->upc);
-
-	os_free(ap->scpd_url);
-	os_free(ap->control_url);
-	os_free(ap->event_sub_url);
-
-	os_free(ap->ap_settings);
-
-	os_free(ap);
-}
-
-
-static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
-{
-	wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
-		   inet_ntoa(ap->addr), ap->location);
-	dl_list_del(&ap->list);
-	wps_er_ap_free(ap);
-
-	if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
-		eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
-		wps_er_deinit_finish(er, NULL);
-	}
-}
-
-
-static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
-				       enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
-		ap->subscribed = 0;
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
-			   "events");
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-
-	/*
-	 * Need to get rid of the AP entry regardless of whether we managed to
-	 * unsubscribe cleanly or not.
-	 */
-	wps_er_ap_unsubscribed(ap->er, ap);
-}
-
-
-static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
-{
-	struct wpabuf *req;
-	struct sockaddr_in dst;
-	char *url, *path;
-	char sid[100];
-
-	if (ap->event_sub_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
-			   "subscribe");
-		goto fail;
-	}
-	if (ap->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
-			   "send subscribe request");
-		goto fail;
-	}
-
-	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
-		goto fail;
-	}
-
-	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
-	if (req == NULL) {
-		os_free(url);
-		goto fail;
-	}
-	uuid_bin2str(ap->sid, sid, sizeof(sid));
-	wpabuf_printf(req,
-		      "UNSUBSCRIBE %s HTTP/1.1\r\n"
-		      "HOST: %s:%d\r\n"
-		      "SID: uuid:%s\r\n"
-		      "\r\n",
-		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
-	os_free(url);
-	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
-			  wpabuf_head(req), wpabuf_len(req));
-
-	ap->http = http_client_addr(&dst, req, 1000,
-				    wps_er_http_unsubscribe_cb, ap);
-	if (ap->http == NULL) {
-		wpabuf_free(req);
-		goto fail;
-	}
-	return;
-
-fail:
-	/*
-	 * Need to get rid of the AP entry even when we fail to unsubscribe
-	 * cleanly.
-	 */
-	wps_er_ap_unsubscribed(ap->er, ap);
-}
-
-static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
-{
-	wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
-		   inet_ntoa(ap->addr), ap->location);
-	eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
-	wps_er_sta_remove_all(ap);
-	wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
-	http_client_free(ap->http);
-	ap->http = NULL;
-	if (ap->wps) {
-		wps_deinit(ap->wps);
-		ap->wps = NULL;
-	}
-
-	dl_list_del(&ap->list);
-	if (ap->subscribed) {
-		dl_list_add(&er->ap_unsubscribing, &ap->list);
-		wps_er_ap_unsubscribe(er, ap);
-	} else
-		wps_er_ap_free(ap);
-}
-
-
-static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
-{
-	struct wps_er *er = eloop_data;
-	struct wps_er_ap *ap = user_ctx;
-	wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
-	wps_er_ap_remove_entry(er, ap);
-}
-
-
-static int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
-{
-	char *pos;
-	char txt[100];
-
-	if (!sid) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
-			   inet_ntoa(ap->addr), ap->location);
-		return -1;
-	}
-
-	pos = os_strstr(sid, "uuid:");
-	if (!pos) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
-			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
-			   sid);
-		return -1;
-	}
-
-	pos += 5;
-	if (uuid_str2bin(pos, ap->sid) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
-			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
-			   sid);
-		return -1;
-	}
-
-	uuid_bin2str(ap->sid, txt, sizeof(txt));
-	wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
-		   inet_ntoa(ap->addr), ap->location, txt);
-
-	return 0;
-}
-
-
-static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
-				     enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
-		ap->subscribed = 1;
-		wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
-		wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-}
-
-
-static void wps_er_subscribe(struct wps_er_ap *ap)
-{
-	struct wpabuf *req;
-	struct sockaddr_in dst;
-	char *url, *path;
-
-	if (ap->event_sub_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
-			   "subscribe");
-		return;
-	}
-	if (ap->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
-			   "send subscribe request");
-		return;
-	}
-
-	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
-		return;
-	}
-
-	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
-	if (req == NULL) {
-		os_free(url);
-		return;
-	}
-	wpabuf_printf(req,
-		      "SUBSCRIBE %s HTTP/1.1\r\n"
-		      "HOST: %s:%d\r\n"
-		      "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
-		      "NT: upnp:event\r\n"
-		      "TIMEOUT: Second-%d\r\n"
-		      "\r\n",
-		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
-		      ap->er->ip_addr_text, ap->er->http_port,
-		      ap->er->event_id, ap->id, 1800);
-	os_free(url);
-	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
-			  wpabuf_head(req), wpabuf_len(req));
-
-	ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
-				    ap);
-	if (ap->http == NULL)
-		wpabuf_free(req);
-}
-
-
-static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
-{
-	struct wps_parse_attr attr;
-
-	if (wps_parse_msg(m1, &attr) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
-		return;
-	}
-	if (attr.primary_dev_type)
-		os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
-	if (attr.wps_state)
-		ap->wps_state = *attr.wps_state;
-	if (attr.mac_addr)
-		os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
-
-	wps_er_subscribe(ap);
-}
-
-
-static void wps_er_get_device_info(struct wps_er_ap *ap)
-{
-	wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
-}
-
-
-static void wps_er_parse_device_description(struct wps_er_ap *ap,
-					    struct wpabuf *reply)
-{
-	/* Note: reply includes null termination after the buffer data */
-	const char *data = wpabuf_head(reply);
-	char *pos;
-
-	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
-			  wpabuf_head(reply), wpabuf_len(reply));
-
-	ap->friendly_name = xml_get_first_item(data, "friendlyName");
-	wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
-
-	ap->manufacturer = xml_get_first_item(data, "manufacturer");
-	wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
-
-	ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
-	wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
-		   ap->manufacturer_url);
-
-	ap->model_description = xml_get_first_item(data, "modelDescription");
-	wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
-		   ap->model_description);
-
-	ap->model_name = xml_get_first_item(data, "modelName");
-	wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
-
-	ap->model_number = xml_get_first_item(data, "modelNumber");
-	wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
-
-	ap->model_url = xml_get_first_item(data, "modelURL");
-	wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
-
-	ap->serial_number = xml_get_first_item(data, "serialNumber");
-	wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
-
-	ap->udn = xml_get_first_item(data, "UDN");
-	wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
-	pos = os_strstr(ap->udn, "uuid:");
-	if (pos) {
-		pos += 5;
-		if (uuid_str2bin(pos, ap->uuid) < 0)
-			wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
-	}
-
-	ap->upc = xml_get_first_item(data, "UPC");
-	wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
-
-	ap->scpd_url = http_link_update(
-		xml_get_first_item(data, "SCPDURL"), ap->location);
-	wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
-
-	ap->control_url = http_link_update(
-		xml_get_first_item(data, "controlURL"), ap->location);
-	wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
-
-	ap->event_sub_url = http_link_update(
-		xml_get_first_item(data, "eventSubURL"), ap->location);
-	wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
-}
-
-
-static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
-				    enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-	struct wpabuf *reply;
-	int ok = 0;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		reply = http_client_get_body(c);
-		if (reply == NULL)
-			break;
-		wps_er_parse_device_description(ap, reply);
-		ok = 1;
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-	if (ok)
-		wps_er_get_device_info(ap);
-}
-
-
-void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
-		   const char *location, int max_age)
-{
-	struct wps_er_ap *ap;
-
-	ap = wps_er_ap_get(er, addr, uuid);
-	if (ap) {
-		/* Update advertisement timeout */
-		eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
-		eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
-		return;
-	}
-
-	ap = os_zalloc(sizeof(*ap));
-	if (ap == NULL)
-		return;
-	dl_list_init(&ap->sta);
-	ap->er = er;
-	ap->id = ++er->next_ap_id;
-	ap->location = os_strdup(location);
-	if (ap->location == NULL) {
-		os_free(ap);
-		return;
-	}
-	dl_list_add(&er->ap, &ap->list);
-
-	ap->addr.s_addr = addr->s_addr;
-	os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
-	eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
-
-	wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
-		   inet_ntoa(ap->addr), ap->location);
-
-	/* Fetch device description */
-	ap->http = http_client_url(ap->location, NULL, 10000,
-				   wps_er_http_dev_desc_cb, ap);
-}
-
-
-void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
-{
-	struct wps_er_ap *ap;
-	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
-		if (ap->addr.s_addr == addr->s_addr) {
-			wps_er_ap_remove_entry(er, ap);
-			return;
-		}
-	}
-}
-
-
-static void wps_er_ap_remove_all(struct wps_er *er)
-{
-	struct wps_er_ap *prev, *ap;
-	dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
-		wps_er_ap_remove_entry(er, ap);
-}
-
-
-static void http_put_date(struct wpabuf *buf)
-{
-	wpabuf_put_str(buf, "Date: ");
-	format_date(buf);
-	wpabuf_put_str(buf, "\r\n");
-}
-
-
-static void wps_er_http_resp_not_found(struct http_request *req)
-{
-	struct wpabuf *buf;
-	buf = wpabuf_alloc(200);
-	if (buf == NULL) {
-		http_request_deinit(req);
-		return;
-	}
-
-	wpabuf_put_str(buf,
-		       "HTTP/1.1 404 Not Found\r\n"
-		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
-		       "Connection: close\r\n");
-	http_put_date(buf);
-	wpabuf_put_str(buf, "\r\n");
-	http_request_send_and_deinit(req, buf);
-}
-
-
-static void wps_er_http_resp_ok(struct http_request *req)
-{
-	struct wpabuf *buf;
-	buf = wpabuf_alloc(200);
-	if (buf == NULL) {
-		http_request_deinit(req);
-		return;
-	}
-
-	wpabuf_put_str(buf,
-		       "HTTP/1.1 200 OK\r\n"
-		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
-		       "Connection: close\r\n"
-		       "Content-Length: 0\r\n");
-	http_put_date(buf);
-	wpabuf_put_str(buf, "\r\n");
-	http_request_send_and_deinit(req, buf);
-}
-
-
-static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
-{
-	struct wps_er_sta *sta = eloop_data;
-	wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
-	dl_list_del(&sta->list);
-	wps_er_sta_free(sta);
-}
-
-
-static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
-					       const u8 *addr,
-					       struct wps_parse_attr *attr,
-					       int probe_req)
-{
-	struct wps_er_sta *sta = wps_er_sta_get(ap, addr);
-	int new_sta = 0;
-	int m1;
-
-	m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
-
-	if (sta == NULL) {
-		/*
-		 * Only allow new STA entry to be added based on Probe Request
-		 * or M1. This will filter out bogus events and anything that
-		 * may have been ongoing at the time ER subscribed for events.
-		 */
-		if (!probe_req && !m1)
-			return NULL;
-
-		sta = os_zalloc(sizeof(*sta));
-		if (sta == NULL)
-			return NULL;
-		os_memcpy(sta->addr, addr, ETH_ALEN);
-		sta->ap = ap;
-		dl_list_add(&ap->sta, &sta->list);
-		new_sta = 1;
-	}
-
-	if (m1)
-		sta->m1_received = 1;
-
-	if (attr->config_methods && (!probe_req || !sta->m1_received))
-		sta->config_methods = WPA_GET_BE16(attr->config_methods);
-	if (attr->uuid_e && (!probe_req || !sta->m1_received))
-		os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
-	if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
-		os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
-	if (attr->dev_password_id && (!probe_req || !sta->m1_received))
-		sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
-
-	if (attr->manufacturer) {
-		os_free(sta->manufacturer);
-		sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
-		if (sta->manufacturer) {
-			os_memcpy(sta->manufacturer, attr->manufacturer,
-				  attr->manufacturer_len);
-			sta->manufacturer[attr->manufacturer_len] = '\0';
-		}
-	}
-
-	if (attr->model_name) {
-		os_free(sta->model_name);
-		sta->model_name = os_malloc(attr->model_name_len + 1);
-		if (sta->model_name) {
-			os_memcpy(sta->model_name, attr->model_name,
-				  attr->model_name_len);
-			sta->model_name[attr->model_name_len] = '\0';
-		}
-	}
-
-	if (attr->model_number) {
-		os_free(sta->model_number);
-		sta->model_number = os_malloc(attr->model_number_len + 1);
-		if (sta->model_number) {
-			os_memcpy(sta->model_number, attr->model_number,
-				  attr->model_number_len);
-			sta->model_number[attr->model_number_len] = '\0';
-		}
-	}
-
-	if (attr->serial_number) {
-		os_free(sta->serial_number);
-		sta->serial_number = os_malloc(attr->serial_number_len + 1);
-		if (sta->serial_number) {
-			os_memcpy(sta->serial_number, attr->serial_number,
-				  attr->serial_number_len);
-			sta->serial_number[attr->serial_number_len] = '\0';
-		}
-	}
-
-	if (attr->dev_name) {
-		os_free(sta->dev_name);
-		sta->dev_name = os_malloc(attr->dev_name_len + 1);
-		if (sta->dev_name) {
-			os_memcpy(sta->dev_name, attr->dev_name,
-				  attr->dev_name_len);
-			sta->dev_name[attr->dev_name_len] = '\0';
-		}
-	}
-
-	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
-	eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
-
-	if (m1 || new_sta)
-		wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
-
-	return sta;
-}
-
-
-static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
-					       const u8 *addr,
-					       struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
-		   MACSTR, MAC2STR(addr));
-	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
-			"(TLVs from Probe Request)", msg);
-
-	if (wps_parse_msg(msg, &attr) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
-			   "WLANEvent message");
-		return;
-	}
-
-	wps_er_add_sta_data(ap, addr, &attr, 1);
-}
-
-
-static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
-					     enum http_client_event event)
-{
-	struct wps_er_sta *sta = ctx;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
-		break;
-	}
-	http_client_free(sta->http);
-	sta->http = NULL;
-}
-
-
-static const char *soap_prefix =
-	"<?xml version=\"1.0\"?>\n"
-	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
-	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
-	"<s:Body>\n";
-static const char *soap_postfix =
-	"</s:Body>\n</s:Envelope>\n";
-static const char *urn_wfawlanconfig =
-	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
-
-static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
-				       const char *name, const char *arg_name,
-				       const char *path,
-				       const struct sockaddr_in *dst,
-				       char **len_ptr, char **body_ptr)
-{
-	unsigned char *encoded;
-	size_t encoded_len;
-	struct wpabuf *buf;
-
-	if (msg) {
-		encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
-					&encoded_len);
-		if (encoded == NULL)
-			return NULL;
-	} else {
-		encoded = NULL;
-		encoded_len = 0;
-	}
-
-	buf = wpabuf_alloc(1000 + encoded_len);
-	if (buf == NULL) {
-		os_free(encoded);
-		return NULL;
-	}
-
-	wpabuf_printf(buf,
-		      "POST %s HTTP/1.1\r\n"
-		      "Host: %s:%d\r\n"
-		      "Content-Type: text/xml; charset=\"utf-8\"\r\n"
-		      "Content-Length: ",
-		      path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
-
-	*len_ptr = wpabuf_put(buf, 0);
-	wpabuf_printf(buf,
-		      "        \r\n"
-		      "SOAPACTION: \"%s#%s\"\r\n"
-		      "\r\n",
-		      urn_wfawlanconfig, name);
-
-	*body_ptr = wpabuf_put(buf, 0);
-
-	wpabuf_put_str(buf, soap_prefix);
-	wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
-	wpabuf_put_str(buf, urn_wfawlanconfig);
-	wpabuf_put_str(buf, "\">\n");
-	if (encoded) {
-		wpabuf_printf(buf, "<%s>%s</%s>\n",
-			      arg_name, (char *) encoded, arg_name);
-		os_free(encoded);
-	}
-
-	return buf;
-}
-
-
-static void wps_er_soap_end(struct wpabuf *buf, const char *name,
-			    char *len_ptr, char *body_ptr)
-{
-	char len_buf[10];
-	wpabuf_printf(buf, "</u:%s>\n", name);
-	wpabuf_put_str(buf, soap_postfix);
-	os_snprintf(len_buf, sizeof(len_buf), "%d",
-		    (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
-	os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
-}
-
-
-static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
-{
-	struct wpabuf *buf;
-	char *len_ptr, *body_ptr;
-	struct sockaddr_in dst;
-	char *url, *path;
-
-	if (sta->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
-			   "ignore new request");
-		wpabuf_free(msg);
-		return;
-	}
-
-	if (sta->ap->control_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
-		wpabuf_free(msg);
-		return;
-	}
-
-	url = http_client_url_parse(sta->ap->control_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
-		wpabuf_free(msg);
-		return;
-	}
-
-	buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
-			      &len_ptr, &body_ptr);
-	wpabuf_free(msg);
-	os_free(url);
-	if (buf == NULL)
-		return;
-	wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
-		      UPNP_WPS_WLANEVENT_TYPE_EAP);
-	wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
-		      MAC2STR(sta->addr));
-
-	wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
-
-	sta->http = http_client_addr(&dst, buf, 1000,
-				     wps_er_http_put_wlan_response_cb, sta);
-	if (sta->http == NULL)
-		wpabuf_free(buf);
-}
-
-
-static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
-			       enum wsc_op_code op_code)
-{
-	enum wps_process_res res;
-
-	res = wps_process_msg(sta->wps, op_code, msg);
-	if (res == WPS_CONTINUE) {
-		struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
-		if (next)
-			wps_er_sta_send_msg(sta, next);
-	} else {
-		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
-			   "enrollee (res=%d)",
-			   res == WPS_DONE ? "succeeded" : "failed", res);
-		wps_deinit(sta->wps);
-		sta->wps = NULL;
-		if (res == WPS_DONE) {
-			/* Remove the STA entry after short timeout */
-			eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
-			eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
-					       NULL);
-		}
-	}
-}
-
-
-static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
-{
-	struct wps_config cfg;
-
-	if (sta->wps)
-		wps_deinit(sta->wps);
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	cfg.wps = sta->ap->er->wps;
-	cfg.registrar = 1;
-	cfg.peer_addr = sta->addr;
-
-	sta->wps = wps_init(&cfg);
-	if (sta->wps == NULL)
-		return;
-	sta->wps->er = 1;
-	sta->wps->use_cred = sta->ap->ap_settings;
-	if (sta->ap->ap_settings) {
-		os_free(sta->cred);
-		sta->cred = os_malloc(sizeof(*sta->cred));
-		if (sta->cred) {
-			os_memcpy(sta->cred, sta->ap->ap_settings,
-				  sizeof(*sta->cred));
-			sta->cred->cred_attr = NULL;
-			os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
-			sta->wps->use_cred = sta->cred;
-		}
-	}
-
-	wps_er_sta_process(sta, msg, WSC_MSG);
-}
-
-
-static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
-					 struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-	struct wps_er_sta *sta;
-
-	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
-		   MAC2STR(addr));
-	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
-			"(TLVs from EAP-WSC)", msg);
-
-	if (wps_parse_msg(msg, &attr) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
-			   "WLANEvent message");
-		return;
-	}
-
-	sta = wps_er_add_sta_data(ap, addr, &attr, 0);
-	if (sta == NULL)
-		return;
-
-	if (attr.msg_type && *attr.msg_type == WPS_M1)
-		wps_er_sta_start(sta, msg);
-	else if (sta->wps) {
-		enum wsc_op_code op_code = WSC_MSG;
-		if (attr.msg_type) {
-			switch (*attr.msg_type) {
-			case WPS_WSC_ACK:
-				op_code = WSC_ACK;
-				break;
-			case WPS_WSC_NACK:
-				op_code = WSC_NACK;
-				break;
-			case WPS_WSC_DONE:
-				op_code = WSC_Done;
-				break;
-			}
-		}
-		wps_er_sta_process(sta, msg, op_code);
-	}
-}
-
-
-static void wps_er_process_wlanevent(struct wps_er_ap *ap,
-				     struct wpabuf *event)
-{
-	u8 *data;
-	u8 wlan_event_type;
-	u8 wlan_event_mac[ETH_ALEN];
-	struct wpabuf msg;
-
-	wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
-		    wpabuf_head(event), wpabuf_len(event));
-	if (wpabuf_len(event) < 1 + 17) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
-		return;
-	}
-
-	data = wpabuf_mhead(event);
-	wlan_event_type = data[0];
-	if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
-			   "WLANEvent");
-		return;
-	}
-
-	wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
-
-	switch (wlan_event_type) {
-	case 1:
-		wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
-		break;
-	case 2:
-		wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
-			   wlan_event_type);
-		break;
-	}
-}
-
-
-static void wps_er_http_event(struct wps_er *er, struct http_request *req,
-			      unsigned int ap_id)
-{
-	struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
-	struct wpabuf *event;
-	enum http_reply_code ret;
-
-	if (ap == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
-			   "%u", ap_id);
-		wps_er_http_resp_not_found(req);
-		return;
-	}
-	wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
-		   ap_id, http_request_get_data(req));
-
-	event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
-				    &ret);
-	if (event == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
-			   "from the event notification");
-		/*
-		 * Reply with OK anyway to avoid getting unregistered from
-		 * events.
-		 */
-		wps_er_http_resp_ok(req);
-		return;
-	}
-
-	wps_er_process_wlanevent(ap, event);
-
-	wpabuf_free(event);
-	wps_er_http_resp_ok(req);
-}
-
-
-static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
-{
-	char *uri = http_request_get_uri(req);
-
-	if (os_strncmp(uri, "/event/", 7) == 0) {
-		unsigned int event_id;
-		char *pos;
-		event_id = atoi(uri + 7);
-		if (event_id != er->event_id) {
-			wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
-				   "unknown event id %u", event_id);
-			return;
-		}
-		pos = os_strchr(uri + 7, '/');
-		if (pos == NULL)
-			return;
-		pos++;
-		wps_er_http_event(er, req, atoi(pos));
-	} else {
-		wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
-			   uri);
-		wps_er_http_resp_not_found(req);
-	}
-}
-
-
-static void wps_er_http_req(void *ctx, struct http_request *req)
-{
-	struct wps_er *er = ctx;
-	struct sockaddr_in *cli = http_request_get_cli_addr(req);
-	enum httpread_hdr_type type = http_request_get_type(req);
-	struct wpabuf *buf;
-
-	wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
-		   "%s:%d",
-		   http_request_get_uri(req), type,
-		   inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
-
-	switch (type) {
-	case HTTPREAD_HDR_TYPE_NOTIFY:
-		wps_er_http_notify(er, req);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
-			   "%d", type);
-		buf = wpabuf_alloc(200);
-		if (buf == NULL) {
-			http_request_deinit(req);
-			return;
-		}
-		wpabuf_put_str(buf,
-			       "HTTP/1.1 501 Unimplemented\r\n"
-			       "Connection: close\r\n");
-		http_put_date(buf);
-		wpabuf_put_str(buf, "\r\n");
-		http_request_send_and_deinit(req, buf);
-		break;
-	}
-}
-
-
-struct wps_er *
-wps_er_init(struct wps_context *wps, const char *ifname)
-{
-	struct wps_er *er;
-	struct in_addr addr;
-
-	er = os_zalloc(sizeof(*er));
-	if (er == NULL)
-		return NULL;
-	dl_list_init(&er->ap);
-	dl_list_init(&er->ap_unsubscribing);
-
-	er->multicast_sd = -1;
-	er->ssdp_sd = -1;
-
-	os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
-	er->wps = wps;
-	if (os_get_random((unsigned char *) &er->event_id,
-			  sizeof(er->event_id)) < 0) {
-		wps_er_deinit(er, NULL, NULL);
-		return NULL;
-	}
-	/* Limit event_id to < 32 bits to avoid issues with atoi() */
-	er->event_id &= 0x0fffffff;
-
-	if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
-			   er->mac_addr)) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
-			   "for %s. Does it have IP address?", ifname);
-		wps_er_deinit(er, NULL, NULL);
-		return NULL;
-	}
-
-	if (wps_er_ssdp_init(er) < 0) {
-		wps_er_deinit(er, NULL, NULL);
-		return NULL;
-	}
-
-	addr.s_addr = er->ip_addr;
-	er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
-	if (er->http_srv == NULL) {
-		wps_er_deinit(er, NULL, NULL);
-		return NULL;
-	}
-	er->http_port = http_server_get_port(er->http_srv);
-
-	wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
-		   er->ifname, er->ip_addr_text);
-
-	return er;
-}
-
-
-void wps_er_refresh(struct wps_er *er)
-{
-	struct wps_er_ap *ap;
-	struct wps_er_sta *sta;
-
-	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
-		wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
-		dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
-			wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
-	}
-
-	wps_er_send_ssdp_msearch(er);
-}
-
-
-static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
-{
-	struct wps_er *er = eloop_data;
-	void (*deinit_done_cb)(void *ctx);
-	void *deinit_done_ctx;
-
-	wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
-
-	deinit_done_cb = er->deinit_done_cb;
-	deinit_done_ctx = er->deinit_done_ctx;
-	os_free(er->ip_addr_text);
-	os_free(er);
-
-	if (deinit_done_cb)
-		deinit_done_cb(deinit_done_ctx);
-}
-
-
-void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
-{
-	if (er == NULL)
-		return;
-	http_server_deinit(er->http_srv);
-	wps_er_ap_remove_all(er);
-	wps_er_ssdp_deinit(er);
-	eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
-			       wps_er_deinit_finish, er, NULL);
-	wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
-	er->deinitializing = 1;
-	er->deinit_done_cb = cb;
-	er->deinit_done_ctx = ctx;
-}
-
-
-static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
-				       enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-}
-
-
-static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
-{
-	struct wpabuf *buf;
-	char *len_ptr, *body_ptr;
-	struct sockaddr_in dst;
-	char *url, *path;
-
-	if (ap->control_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
-		return;
-	}
-
-	if (ap->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
-			   "ignore new request");
-		return;
-	}
-
-	url = http_client_url_parse(ap->control_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
-		return;
-	}
-
-	buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
-			      &dst, &len_ptr, &body_ptr);
-	os_free(url);
-	if (buf == NULL)
-		return;
-
-	wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
-
-	ap->http = http_client_addr(&dst, buf, 1000,
-				    wps_er_http_set_sel_reg_cb, ap);
-	if (ap->http == NULL)
-		wpabuf_free(buf);
-}
-
-
-static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
-{
-	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, !!sel_reg);
-	return 0;
-}
-
-
-static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
-{
-	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, dev_passwd_id);
-	return 0;
-}
-
-
-static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
-					       u16 sel_reg_config_methods)
-{
-	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, sel_reg_config_methods);
-	return 0;
-}
-
-
-void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
-			u16 sel_reg_config_methods)
-{
-	struct wpabuf *msg;
-	struct wps_er_ap *ap;
-
-	msg = wpabuf_alloc(500);
-	if (msg == NULL)
-		return;
-
-	if (wps_build_version(msg) ||
-	    wps_er_build_selected_registrar(msg, sel_reg) ||
-	    wps_er_build_dev_password_id(msg, dev_passwd_id) ||
-	    wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods)) {
-		wpabuf_free(msg);
-		return;
-	}
-
-	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list)
-		wps_er_send_set_sel_reg(ap, msg);
-
-	wpabuf_free(msg);
-}
-
-
-int wps_er_pbc(struct wps_er *er, const u8 *uuid)
-{
-	if (er == NULL || er->wps == NULL)
-		return -1;
-
-	/*
-	 * TODO: Should enable PBC mode only in a single AP based on which AP
-	 * the Enrollee (uuid) is using. Now, we may end up enabling multiple
-	 * APs in PBC mode which could result in session overlap at the
-	 * Enrollee.
-	 */
-	if (wps_registrar_button_pushed(er->wps->registrar))
-		return -1;
-
-	return 0;
-}
-
-
-static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
-{
-	struct wps_er_ap *ap = ctx;
-	wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
-	os_free(ap->ap_settings);
-	ap->ap_settings = os_malloc(sizeof(*cred));
-	if (ap->ap_settings) {
-		os_memcpy(ap->ap_settings, cred, sizeof(*cred));
-		ap->ap_settings->cred_attr = NULL;
-	}
-
-	/* TODO: send info through ctrl_iface */
-}
-
-
-static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
-				       enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-	struct wpabuf *reply;
-	char *msg = NULL;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
-		reply = http_client_get_body(c);
-		if (reply == NULL)
-			break;
-		msg = os_zalloc(wpabuf_len(reply) + 1);
-		if (msg == NULL)
-			break;
-		os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
-		if (ap->wps) {
-			wps_deinit(ap->wps);
-			ap->wps = NULL;
-		}
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-
-	if (msg) {
-		struct wpabuf *buf;
-		enum http_reply_code ret;
-		buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
-		os_free(msg);
-		if (buf == NULL) {
-			wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
-				   "NewOutMessage from PutMessage response");
-			return;
-		}
-		wps_er_ap_process(ap, buf);
-		wpabuf_free(buf);
-	}
-}
-
-
-static void wps_er_ap_put_message(struct wps_er_ap *ap,
-				  const struct wpabuf *msg)
-{
-	struct wpabuf *buf;
-	char *len_ptr, *body_ptr;
-	struct sockaddr_in dst;
-	char *url, *path;
-
-	if (ap->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
-			   "with the AP - cannot continue learn");
-		return;
-	}
-
-	if (ap->control_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
-		return;
-	}
-
-	url = http_client_url_parse(ap->control_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
-		return;
-	}
-
-	buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
-			      &len_ptr, &body_ptr);
-	os_free(url);
-	if (buf == NULL)
-		return;
-
-	wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
-
-	ap->http = http_client_addr(&dst, buf, 10000,
-				    wps_er_http_put_message_cb, ap);
-	if (ap->http == NULL)
-		wpabuf_free(buf);
-}
-
-
-static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
-{
-	enum wps_process_res res;
-
-	res = wps_process_msg(ap->wps, WSC_MSG, msg);
-	if (res == WPS_CONTINUE) {
-		enum wsc_op_code op_code;
-		struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
-		if (next) {
-			wps_er_ap_put_message(ap, next);
-			wpabuf_free(next);
-		} else {
-			wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
-				   "message");
-			wps_deinit(ap->wps);
-			ap->wps = NULL;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
-			   "AP (res=%d)", res);
-		wps_deinit(ap->wps);
-		ap->wps = NULL;
-	}
-}
-
-
-static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
-{
-	struct wps_config cfg;
-
-	if (ap->wps) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
-			   "progress with this AP");
-		return;
-	}
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	cfg.wps = ap->er->wps;
-	cfg.registrar = 1;
-	ap->wps = wps_init(&cfg);
-	if (ap->wps == NULL)
-		return;
-	ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
-	ap->wps->ap_settings_cb_ctx = ap;
-
-	wps_er_ap_process(ap, m1);
-}
-
-
-static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
-{
-	struct wpabuf *info;
-	enum http_reply_code ret;
-
-	wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
-		   "from the AP");
-	info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
-	if (info == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
-			   "NewDeviceInfo from GetDeviceInfo response");
-		return;
-	}
-
-	ap->m1_handler(ap, info);
-	wpabuf_free(info);
-}
-
-
-static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
-					enum http_client_event event)
-{
-	struct wps_er_ap *ap = ctx;
-	struct wpabuf *reply;
-	char *dev_info = NULL;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
-		reply = http_client_get_body(c);
-		if (reply == NULL)
-			break;
-		dev_info = os_zalloc(wpabuf_len(reply) + 1);
-		if (dev_info == NULL)
-			break;
-		os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
-		break;
-	}
-	http_client_free(ap->http);
-	ap->http = NULL;
-
-	if (dev_info) {
-		wps_er_ap_learn(ap, dev_info);
-		os_free(dev_info);
-	}
-}
-
-
-static int wps_er_send_get_device_info(struct wps_er_ap *ap,
-				       void (*m1_handler)(struct wps_er_ap *ap,
-							  struct wpabuf *m1))
-{
-	struct wpabuf *buf;
-	char *len_ptr, *body_ptr;
-	struct sockaddr_in dst;
-	char *url, *path;
-
-	if (ap->http) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
-			   "with the AP - cannot get device info");
-		return -1;
-	}
-
-	if (ap->control_url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
-		return -1;
-	}
-
-	url = http_client_url_parse(ap->control_url, &dst, &path);
-	if (url == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
-		return -1;
-	}
-
-	buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
-			      &len_ptr, &body_ptr);
-	os_free(url);
-	if (buf == NULL)
-		return -1;
-
-	wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
-
-	ap->http = http_client_addr(&dst, buf, 10000,
-				    wps_er_http_get_dev_info_cb, ap);
-	if (ap->http == NULL) {
-		wpabuf_free(buf);
-		return -1;
-	}
-
-	ap->m1_handler = m1_handler;
-
-	return 0;
-}
-
-
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-		 size_t pin_len)
-{
-	struct wps_er_ap *ap;
-
-	if (er == NULL)
-		return -1;
-
-	ap = wps_er_ap_get(er, NULL, uuid);
-	if (ap == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
-			   "request");
-		return -1;
-	}
-	if (ap->wps) {
-		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
-			   "with the AP - cannot start learn");
-		return -1;
-	}
-
-	if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
-		return -1;
-
-	/* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
-	wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_er.c (from rev 9639, vendor/wpa/dist/src/wps/wps_er.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_er.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_er.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2036 @@
+/*
+ * Wi-Fi Protected Setup - External Registrar
+ * Copyright (c) 2009-2012, Jouni Malinen <j at 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 "base64.h"
+#include "uuid.h"
+#include "eloop.h"
+#include "httpread.h"
+#include "http_client.h"
+#include "http_server.h"
+#include "upnp_xml.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+#include "wps_er.h"
+
+
+static void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
+static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
+static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
+static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
+static int wps_er_send_get_device_info(struct wps_er_ap *ap,
+				       void (*m1_handler)(struct wps_er_ap *ap,
+							  struct wpabuf *m1));
+
+
+static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
+			     enum wps_event event)
+{
+	union wps_event_data data;
+	struct wps_event_er_enrollee *ev = &data.enrollee;
+
+	if (wps->event_cb == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	ev->uuid = sta->uuid;
+	ev->mac_addr = sta->addr;
+	ev->m1_received = sta->m1_received;
+	ev->config_methods = sta->config_methods;
+	ev->dev_passwd_id = sta->dev_passwd_id;
+	ev->pri_dev_type = sta->pri_dev_type;
+	ev->dev_name = sta->dev_name;
+	ev->manufacturer = sta->manufacturer;
+	ev->model_name = sta->model_name;
+	ev->model_number = sta->model_number;
+	ev->serial_number = sta->serial_number;
+	wps->event_cb(wps->cb_ctx, event, &data);
+}
+
+
+static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
+					  const u8 *uuid)
+{
+	struct wps_er_sta *sta;
+	dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
+		if ((addr == NULL ||
+		     os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
+		    (uuid == NULL ||
+		     os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
+			return sta;
+	}
+	return NULL;
+}
+
+
+static void wps_er_sta_free(struct wps_er_sta *sta)
+{
+	wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
+	if (sta->wps)
+		wps_deinit(sta->wps);
+	os_free(sta->manufacturer);
+	os_free(sta->model_name);
+	os_free(sta->model_number);
+	os_free(sta->serial_number);
+	os_free(sta->dev_name);
+	http_client_free(sta->http);
+	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
+	os_free(sta->cred);
+	os_free(sta);
+}
+
+
+static void wps_er_sta_remove_all(struct wps_er_ap *ap)
+{
+	struct wps_er_sta *prev, *sta;
+	dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
+		wps_er_sta_free(sta);
+}
+
+
+static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
+					struct in_addr *addr, const u8 *uuid)
+{
+	struct wps_er_ap *ap;
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
+		    (uuid == NULL ||
+		     os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
+			return ap;
+	}
+	return NULL;
+}
+
+
+static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
+{
+	struct wps_er_ap *ap;
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		if (ap->id == id)
+			return ap;
+	}
+	return NULL;
+}
+
+
+static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
+			    enum wps_event event)
+{
+	union wps_event_data data;
+	struct wps_event_er_ap *evap = &data.ap;
+
+	if (wps->event_cb == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	evap->uuid = ap->uuid;
+	evap->friendly_name = ap->friendly_name;
+	evap->manufacturer = ap->manufacturer;
+	evap->manufacturer_url = ap->manufacturer_url;
+	evap->model_description = ap->model_description;
+	evap->model_name = ap->model_name;
+	evap->model_number = ap->model_number;
+	evap->model_url = ap->model_url;
+	evap->serial_number = ap->serial_number;
+	evap->upc = ap->upc;
+	evap->pri_dev_type = ap->pri_dev_type;
+	evap->wps_state = ap->wps_state;
+	evap->mac_addr = ap->mac_addr;
+	wps->event_cb(wps->cb_ctx, event, &data);
+}
+
+
+static void wps_er_ap_free(struct wps_er_ap *ap)
+{
+	http_client_free(ap->http);
+	ap->http = NULL;
+
+	os_free(ap->location);
+	os_free(ap->friendly_name);
+	os_free(ap->manufacturer);
+	os_free(ap->manufacturer_url);
+	os_free(ap->model_description);
+	os_free(ap->model_name);
+	os_free(ap->model_number);
+	os_free(ap->model_url);
+	os_free(ap->serial_number);
+	os_free(ap->udn);
+	os_free(ap->upc);
+
+	os_free(ap->scpd_url);
+	os_free(ap->control_url);
+	os_free(ap->event_sub_url);
+
+	os_free(ap->ap_settings);
+
+	os_free(ap);
+}
+
+
+static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
+{
+	wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
+		   inet_ntoa(ap->addr), ap->location);
+	dl_list_del(&ap->list);
+	wps_er_ap_free(ap);
+
+	if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
+		eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
+		wps_er_deinit_finish(er, NULL);
+	}
+}
+
+
+static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
+				       enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
+		ap->subscribed = 0;
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
+			   "events");
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+
+	/*
+	 * Need to get rid of the AP entry regardless of whether we managed to
+	 * unsubscribe cleanly or not.
+	 */
+	wps_er_ap_unsubscribed(ap->er, ap);
+}
+
+
+static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
+{
+	struct wpabuf *req;
+	struct sockaddr_in dst;
+	char *url, *path;
+	char sid[100];
+
+	if (ap->event_sub_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
+			   "subscribe");
+		goto fail;
+	}
+	if (ap->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
+			   "send subscribe request");
+		goto fail;
+	}
+
+	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
+		goto fail;
+	}
+
+	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
+	if (req == NULL) {
+		os_free(url);
+		goto fail;
+	}
+	uuid_bin2str(ap->sid, sid, sizeof(sid));
+	wpabuf_printf(req,
+		      "UNSUBSCRIBE %s HTTP/1.1\r\n"
+		      "HOST: %s:%d\r\n"
+		      "SID: uuid:%s\r\n"
+		      "\r\n",
+		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
+	os_free(url);
+	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
+			  wpabuf_head(req), wpabuf_len(req));
+
+	ap->http = http_client_addr(&dst, req, 1000,
+				    wps_er_http_unsubscribe_cb, ap);
+	if (ap->http == NULL) {
+		wpabuf_free(req);
+		goto fail;
+	}
+	return;
+
+fail:
+	/*
+	 * Need to get rid of the AP entry even when we fail to unsubscribe
+	 * cleanly.
+	 */
+	wps_er_ap_unsubscribed(ap->er, ap);
+}
+
+
+static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
+							  const u8 *uuid)
+{
+	struct wps_er_ap_settings *s;
+	dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
+		if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
+			return s;
+	return NULL;
+}
+
+
+int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
+{
+	struct wps_er_ap *ap;
+	struct wps_er_ap_settings *settings;
+
+	ap = wps_er_ap_get(er, addr, NULL);
+	if (ap == NULL || ap->ap_settings == NULL)
+		return -1;
+
+	settings = wps_er_ap_get_settings(er, ap->uuid);
+	if (!settings) {
+		settings = os_zalloc(sizeof(*settings));
+		if (settings == NULL)
+			return -1;
+		os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
+		dl_list_add(&er->ap_settings, &settings->list);
+	}
+	os_memcpy(&settings->ap_settings, ap->ap_settings,
+		  sizeof(struct wps_credential));
+
+	return 0;
+}
+
+
+static int wps_er_ap_use_cached_settings(struct wps_er *er,
+					 struct wps_er_ap *ap)
+{
+	struct wps_er_ap_settings *s;
+
+	if (ap->ap_settings)
+		return 0;
+
+	s = wps_er_ap_get_settings(ap->er, ap->uuid);
+	if (!s)
+		return -1;
+
+	ap->ap_settings = os_malloc(sizeof(*ap->ap_settings));
+	if (ap->ap_settings == NULL)
+		return -1;
+
+	os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings));
+	wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
+	return 0;
+}
+
+
+static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
+{
+	wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
+		   inet_ntoa(ap->addr), ap->location);
+	eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
+	wps_er_sta_remove_all(ap);
+	wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
+	http_client_free(ap->http);
+	ap->http = NULL;
+	if (ap->wps) {
+		wps_deinit(ap->wps);
+		ap->wps = NULL;
+	}
+
+	dl_list_del(&ap->list);
+	if (ap->subscribed) {
+		dl_list_add(&er->ap_unsubscribing, &ap->list);
+		wps_er_ap_unsubscribe(er, ap);
+	} else
+		wps_er_ap_free(ap);
+}
+
+
+static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
+{
+	struct wps_er *er = eloop_data;
+	struct wps_er_ap *ap = user_ctx;
+	wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
+	wps_er_ap_remove_entry(er, ap);
+}
+
+
+static int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
+{
+	char *pos;
+	char txt[100];
+
+	if (!sid) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
+			   inet_ntoa(ap->addr), ap->location);
+		return -1;
+	}
+
+	pos = os_strstr(sid, "uuid:");
+	if (!pos) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
+			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
+			   sid);
+		return -1;
+	}
+
+	pos += 5;
+	if (uuid_str2bin(pos, ap->sid) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
+			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
+			   sid);
+		return -1;
+	}
+
+	uuid_bin2str(ap->sid, txt, sizeof(txt));
+	wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
+		   inet_ntoa(ap->addr), ap->location, txt);
+
+	return 0;
+}
+
+
+static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
+				     enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
+		ap->subscribed = 1;
+		wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
+		wps_er_ap_use_cached_settings(ap->er, ap);
+		wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+}
+
+
+static void wps_er_subscribe(struct wps_er_ap *ap)
+{
+	struct wpabuf *req;
+	struct sockaddr_in dst;
+	char *url, *path;
+
+	if (ap->event_sub_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
+			   "subscribe");
+		return;
+	}
+	if (ap->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
+			   "send subscribe request");
+		return;
+	}
+
+	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
+		return;
+	}
+
+	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
+	if (req == NULL) {
+		os_free(url);
+		return;
+	}
+	wpabuf_printf(req,
+		      "SUBSCRIBE %s HTTP/1.1\r\n"
+		      "HOST: %s:%d\r\n"
+		      "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
+		      "NT: upnp:event\r\n"
+		      "TIMEOUT: Second-%d\r\n"
+		      "\r\n",
+		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
+		      ap->er->ip_addr_text, ap->er->http_port,
+		      ap->er->event_id, ap->id, 1800);
+	os_free(url);
+	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
+			  wpabuf_head(req), wpabuf_len(req));
+
+	ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
+				    ap);
+	if (ap->http == NULL)
+		wpabuf_free(req);
+}
+
+
+static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
+{
+	struct wps_parse_attr attr;
+
+	if (wps_parse_msg(m1, &attr) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
+		return;
+	}
+	if (attr.primary_dev_type)
+		os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
+	if (attr.wps_state)
+		ap->wps_state = *attr.wps_state;
+	if (attr.mac_addr)
+		os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
+
+	wps_er_subscribe(ap);
+}
+
+
+static void wps_er_get_device_info(struct wps_er_ap *ap)
+{
+	wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
+}
+
+
+static const char * wps_er_find_wfadevice(const char *data)
+{
+	const char *tag, *tagname, *end;
+	char *val;
+	int found = 0;
+
+	while (!found) {
+		/* Find next <device> */
+		for (;;) {
+			if (xml_next_tag(data, &tag, &tagname, &end))
+				return NULL;
+			data = end;
+			if (!os_strncasecmp(tagname, "device", 6) &&
+			    *tag != '/' &&
+			    (tagname[6] == '>' || !isgraph(tagname[6]))) {
+				break;
+			}
+		}
+
+		/* Check whether deviceType is WFADevice */
+		val = xml_get_first_item(data, "deviceType");
+		if (val == NULL)
+			return NULL;
+		wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
+		found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
+				      "device:WFADevice:1") == 0;
+		os_free(val);
+	}
+
+	return data;
+}
+
+
+static void wps_er_parse_device_description(struct wps_er_ap *ap,
+					    struct wpabuf *reply)
+{
+	/* Note: reply includes null termination after the buffer data */
+	const char *tmp, *data = wpabuf_head(reply);
+	char *pos;
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
+			  wpabuf_head(reply), wpabuf_len(reply));
+
+	/*
+	 * The root device description may include multiple devices, so first
+	 * find the beginning of the WFADevice description to allow the
+	 * simplistic parser to pick the correct entries.
+	 */
+	tmp = wps_er_find_wfadevice(data);
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
+			   "trying to parse invalid data");
+	} else
+		data = tmp;
+
+	ap->friendly_name = xml_get_first_item(data, "friendlyName");
+	wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
+
+	ap->manufacturer = xml_get_first_item(data, "manufacturer");
+	wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
+
+	ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
+	wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
+		   ap->manufacturer_url);
+
+	ap->model_description = xml_get_first_item(data, "modelDescription");
+	wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
+		   ap->model_description);
+
+	ap->model_name = xml_get_first_item(data, "modelName");
+	wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
+
+	ap->model_number = xml_get_first_item(data, "modelNumber");
+	wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
+
+	ap->model_url = xml_get_first_item(data, "modelURL");
+	wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
+
+	ap->serial_number = xml_get_first_item(data, "serialNumber");
+	wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
+
+	ap->udn = xml_get_first_item(data, "UDN");
+	wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
+	pos = os_strstr(ap->udn, "uuid:");
+	if (pos) {
+		pos += 5;
+		if (uuid_str2bin(pos, ap->uuid) < 0)
+			wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
+	}
+
+	ap->upc = xml_get_first_item(data, "UPC");
+	wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
+
+	ap->scpd_url = http_link_update(
+		xml_get_first_item(data, "SCPDURL"), ap->location);
+	wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
+
+	ap->control_url = http_link_update(
+		xml_get_first_item(data, "controlURL"), ap->location);
+	wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
+
+	ap->event_sub_url = http_link_update(
+		xml_get_first_item(data, "eventSubURL"), ap->location);
+	wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
+}
+
+
+static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
+				    enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+	struct wpabuf *reply;
+	int ok = 0;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		reply = http_client_get_body(c);
+		if (reply == NULL)
+			break;
+		wps_er_parse_device_description(ap, reply);
+		ok = 1;
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+	if (ok)
+		wps_er_get_device_info(ap);
+}
+
+
+void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
+		   const char *location, int max_age)
+{
+	struct wps_er_ap *ap;
+
+	ap = wps_er_ap_get(er, addr, uuid);
+	if (ap) {
+		/* Update advertisement timeout */
+		eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
+		eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
+		return;
+	}
+
+	ap = os_zalloc(sizeof(*ap));
+	if (ap == NULL)
+		return;
+	dl_list_init(&ap->sta);
+	ap->er = er;
+	ap->id = ++er->next_ap_id;
+	ap->location = os_strdup(location);
+	if (ap->location == NULL) {
+		os_free(ap);
+		return;
+	}
+	dl_list_add(&er->ap, &ap->list);
+
+	ap->addr.s_addr = addr->s_addr;
+	os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
+	eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
+
+	wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
+		   inet_ntoa(ap->addr), ap->location);
+
+	/* Fetch device description */
+	ap->http = http_client_url(ap->location, NULL, 10000,
+				   wps_er_http_dev_desc_cb, ap);
+}
+
+
+void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
+{
+	struct wps_er_ap *ap;
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		if (ap->addr.s_addr == addr->s_addr) {
+			wps_er_ap_remove_entry(er, ap);
+			return;
+		}
+	}
+}
+
+
+static void wps_er_ap_remove_all(struct wps_er *er)
+{
+	struct wps_er_ap *prev, *ap;
+	struct wps_er_ap_settings *prev_s, *s;
+	dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
+		wps_er_ap_remove_entry(er, ap);
+	dl_list_for_each_safe(s, prev_s, &er->ap_settings,
+			      struct wps_er_ap_settings, list)
+		os_free(s);
+}
+
+
+static void http_put_date(struct wpabuf *buf)
+{
+	wpabuf_put_str(buf, "Date: ");
+	format_date(buf);
+	wpabuf_put_str(buf, "\r\n");
+}
+
+
+static void wps_er_http_resp_not_found(struct http_request *req)
+{
+	struct wpabuf *buf;
+	buf = wpabuf_alloc(200);
+	if (buf == NULL) {
+		http_request_deinit(req);
+		return;
+	}
+
+	wpabuf_put_str(buf,
+		       "HTTP/1.1 404 Not Found\r\n"
+		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
+		       "Connection: close\r\n");
+	http_put_date(buf);
+	wpabuf_put_str(buf, "\r\n");
+	http_request_send_and_deinit(req, buf);
+}
+
+
+static void wps_er_http_resp_ok(struct http_request *req)
+{
+	struct wpabuf *buf;
+	buf = wpabuf_alloc(200);
+	if (buf == NULL) {
+		http_request_deinit(req);
+		return;
+	}
+
+	wpabuf_put_str(buf,
+		       "HTTP/1.1 200 OK\r\n"
+		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
+		       "Connection: close\r\n"
+		       "Content-Length: 0\r\n");
+	http_put_date(buf);
+	wpabuf_put_str(buf, "\r\n");
+	http_request_send_and_deinit(req, buf);
+}
+
+
+static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
+{
+	struct wps_er_sta *sta = eloop_data;
+	wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
+	dl_list_del(&sta->list);
+	wps_er_sta_free(sta);
+}
+
+
+static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
+					       const u8 *addr,
+					       struct wps_parse_attr *attr,
+					       int probe_req)
+{
+	struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
+	int new_sta = 0;
+	int m1;
+
+	m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
+
+	if (sta == NULL) {
+		/*
+		 * Only allow new STA entry to be added based on Probe Request
+		 * or M1. This will filter out bogus events and anything that
+		 * may have been ongoing at the time ER subscribed for events.
+		 */
+		if (!probe_req && !m1)
+			return NULL;
+
+		sta = os_zalloc(sizeof(*sta));
+		if (sta == NULL)
+			return NULL;
+		os_memcpy(sta->addr, addr, ETH_ALEN);
+		sta->ap = ap;
+		dl_list_add(&ap->sta, &sta->list);
+		new_sta = 1;
+	}
+
+	if (m1)
+		sta->m1_received = 1;
+
+	if (attr->config_methods && (!probe_req || !sta->m1_received))
+		sta->config_methods = WPA_GET_BE16(attr->config_methods);
+	if (attr->uuid_e && (!probe_req || !sta->m1_received))
+		os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
+	if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
+		os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
+	if (attr->dev_password_id && (!probe_req || !sta->m1_received))
+		sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
+
+	if (attr->manufacturer) {
+		os_free(sta->manufacturer);
+		sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
+		if (sta->manufacturer) {
+			os_memcpy(sta->manufacturer, attr->manufacturer,
+				  attr->manufacturer_len);
+			sta->manufacturer[attr->manufacturer_len] = '\0';
+		}
+	}
+
+	if (attr->model_name) {
+		os_free(sta->model_name);
+		sta->model_name = os_malloc(attr->model_name_len + 1);
+		if (sta->model_name) {
+			os_memcpy(sta->model_name, attr->model_name,
+				  attr->model_name_len);
+			sta->model_name[attr->model_name_len] = '\0';
+		}
+	}
+
+	if (attr->model_number) {
+		os_free(sta->model_number);
+		sta->model_number = os_malloc(attr->model_number_len + 1);
+		if (sta->model_number) {
+			os_memcpy(sta->model_number, attr->model_number,
+				  attr->model_number_len);
+			sta->model_number[attr->model_number_len] = '\0';
+		}
+	}
+
+	if (attr->serial_number) {
+		os_free(sta->serial_number);
+		sta->serial_number = os_malloc(attr->serial_number_len + 1);
+		if (sta->serial_number) {
+			os_memcpy(sta->serial_number, attr->serial_number,
+				  attr->serial_number_len);
+			sta->serial_number[attr->serial_number_len] = '\0';
+		}
+	}
+
+	if (attr->dev_name) {
+		os_free(sta->dev_name);
+		sta->dev_name = os_malloc(attr->dev_name_len + 1);
+		if (sta->dev_name) {
+			os_memcpy(sta->dev_name, attr->dev_name,
+				  attr->dev_name_len);
+			sta->dev_name[attr->dev_name_len] = '\0';
+		}
+	}
+
+	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
+	eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
+
+	if (m1 || new_sta)
+		wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
+
+	return sta;
+}
+
+
+static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
+					       const u8 *addr,
+					       struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
+		   MACSTR, MAC2STR(addr));
+	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
+			"(TLVs from Probe Request)", msg);
+
+	if (wps_validate_probe_req(msg, addr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
+			   "Probe Request frame from " MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	if (wps_parse_msg(msg, &attr) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
+			   "WLANEvent message");
+		return;
+	}
+
+	wps_er_add_sta_data(ap, addr, &attr, 1);
+	wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
+}
+
+
+static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
+					     enum http_client_event event)
+{
+	struct wps_er_sta *sta = ctx;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
+		break;
+	}
+	http_client_free(sta->http);
+	sta->http = NULL;
+}
+
+
+static const char *soap_prefix =
+	"<?xml version=\"1.0\"?>\n"
+	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
+	"<s:Body>\n";
+static const char *soap_postfix =
+	"</s:Body>\n</s:Envelope>\n";
+static const char *urn_wfawlanconfig =
+	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
+
+static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
+				       const char *name, const char *arg_name,
+				       const char *path,
+				       const struct sockaddr_in *dst,
+				       char **len_ptr, char **body_ptr)
+{
+	unsigned char *encoded;
+	size_t encoded_len;
+	struct wpabuf *buf;
+
+	if (msg) {
+		encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
+					&encoded_len);
+		if (encoded == NULL)
+			return NULL;
+	} else {
+		encoded = NULL;
+		encoded_len = 0;
+	}
+
+	buf = wpabuf_alloc(1000 + encoded_len);
+	if (buf == NULL) {
+		os_free(encoded);
+		return NULL;
+	}
+
+	wpabuf_printf(buf,
+		      "POST %s HTTP/1.1\r\n"
+		      "Host: %s:%d\r\n"
+		      "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+		      "Content-Length: ",
+		      path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
+
+	*len_ptr = wpabuf_put(buf, 0);
+	wpabuf_printf(buf,
+		      "        \r\n"
+		      "SOAPACTION: \"%s#%s\"\r\n"
+		      "\r\n",
+		      urn_wfawlanconfig, name);
+
+	*body_ptr = wpabuf_put(buf, 0);
+
+	wpabuf_put_str(buf, soap_prefix);
+	wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
+	wpabuf_put_str(buf, urn_wfawlanconfig);
+	wpabuf_put_str(buf, "\">\n");
+	if (encoded) {
+		wpabuf_printf(buf, "<%s>%s</%s>\n",
+			      arg_name, (char *) encoded, arg_name);
+		os_free(encoded);
+	}
+
+	return buf;
+}
+
+
+static void wps_er_soap_end(struct wpabuf *buf, const char *name,
+			    char *len_ptr, char *body_ptr)
+{
+	char len_buf[10];
+	wpabuf_printf(buf, "</u:%s>\n", name);
+	wpabuf_put_str(buf, soap_postfix);
+	os_snprintf(len_buf, sizeof(len_buf), "%d",
+		    (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
+	os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
+}
+
+
+static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
+{
+	struct wpabuf *buf;
+	char *len_ptr, *body_ptr;
+	struct sockaddr_in dst;
+	char *url, *path;
+
+	if (sta->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
+			   "ignore new request");
+		wpabuf_free(msg);
+		return;
+	}
+
+	if (sta->ap->control_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+		wpabuf_free(msg);
+		return;
+	}
+
+	url = http_client_url_parse(sta->ap->control_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+		wpabuf_free(msg);
+		return;
+	}
+
+	buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
+			      &len_ptr, &body_ptr);
+	wpabuf_free(msg);
+	os_free(url);
+	if (buf == NULL)
+		return;
+	wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
+		      UPNP_WPS_WLANEVENT_TYPE_EAP);
+	wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
+		      MAC2STR(sta->addr));
+
+	wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
+
+	sta->http = http_client_addr(&dst, buf, 1000,
+				     wps_er_http_put_wlan_response_cb, sta);
+	if (sta->http == NULL)
+		wpabuf_free(buf);
+}
+
+
+static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
+			       enum wsc_op_code op_code)
+{
+	enum wps_process_res res;
+
+	res = wps_process_msg(sta->wps, op_code, msg);
+	if (res == WPS_CONTINUE) {
+		struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
+		if (next)
+			wps_er_sta_send_msg(sta, next);
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
+			   "enrollee (res=%d)",
+			   res == WPS_DONE ? "succeeded" : "failed", res);
+		wps_deinit(sta->wps);
+		sta->wps = NULL;
+		if (res == WPS_DONE) {
+			/* Remove the STA entry after short timeout */
+			eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
+			eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
+					       NULL);
+		}
+	}
+}
+
+
+static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
+{
+	struct wps_config cfg;
+
+	if (sta->wps)
+		wps_deinit(sta->wps);
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = sta->ap->er->wps;
+	cfg.registrar = 1;
+	cfg.peer_addr = sta->addr;
+
+	sta->wps = wps_init(&cfg);
+	if (sta->wps == NULL)
+		return;
+	sta->wps->er = 1;
+	sta->wps->use_cred = sta->ap->ap_settings;
+	if (sta->ap->ap_settings) {
+		os_free(sta->cred);
+		sta->cred = os_malloc(sizeof(*sta->cred));
+		if (sta->cred) {
+			os_memcpy(sta->cred, sta->ap->ap_settings,
+				  sizeof(*sta->cred));
+			sta->cred->cred_attr = NULL;
+			os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
+			sta->wps->use_cred = sta->cred;
+		}
+	}
+
+	wps_er_sta_process(sta, msg, WSC_MSG);
+}
+
+
+static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
+					 struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	struct wps_er_sta *sta;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
+		   MAC2STR(addr));
+	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
+			"(TLVs from EAP-WSC)", msg);
+
+	if (wps_parse_msg(msg, &attr) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
+			   "WLANEvent message");
+		return;
+	}
+
+	sta = wps_er_add_sta_data(ap, addr, &attr, 0);
+	if (sta == NULL)
+		return;
+
+	if (attr.msg_type && *attr.msg_type == WPS_M1)
+		wps_er_sta_start(sta, msg);
+	else if (sta->wps) {
+		enum wsc_op_code op_code = WSC_MSG;
+		if (attr.msg_type) {
+			switch (*attr.msg_type) {
+			case WPS_WSC_ACK:
+				op_code = WSC_ACK;
+				break;
+			case WPS_WSC_NACK:
+				op_code = WSC_NACK;
+				break;
+			case WPS_WSC_DONE:
+				op_code = WSC_Done;
+				break;
+			}
+		}
+		wps_er_sta_process(sta, msg, op_code);
+	}
+}
+
+
+static void wps_er_process_wlanevent(struct wps_er_ap *ap,
+				     struct wpabuf *event)
+{
+	u8 *data;
+	u8 wlan_event_type;
+	u8 wlan_event_mac[ETH_ALEN];
+	struct wpabuf msg;
+
+	wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
+		    wpabuf_head(event), wpabuf_len(event));
+	if (wpabuf_len(event) < 1 + 17) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
+		return;
+	}
+
+	data = wpabuf_mhead(event);
+	wlan_event_type = data[0];
+	if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
+			   "WLANEvent");
+		return;
+	}
+
+	wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
+
+	switch (wlan_event_type) {
+	case 1:
+		wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
+		break;
+	case 2:
+		wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
+			   wlan_event_type);
+		break;
+	}
+}
+
+
+static void wps_er_http_event(struct wps_er *er, struct http_request *req,
+			      unsigned int ap_id)
+{
+	struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
+	struct wpabuf *event;
+	enum http_reply_code ret;
+
+	if (ap == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
+			   "%u", ap_id);
+		wps_er_http_resp_not_found(req);
+		return;
+	}
+	wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
+		   ap_id, http_request_get_data(req));
+
+	event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
+				    &ret);
+	if (event == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
+			   "from the event notification");
+		/*
+		 * Reply with OK anyway to avoid getting unregistered from
+		 * events.
+		 */
+		wps_er_http_resp_ok(req);
+		return;
+	}
+
+	wps_er_process_wlanevent(ap, event);
+
+	wpabuf_free(event);
+	wps_er_http_resp_ok(req);
+}
+
+
+static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
+{
+	char *uri = http_request_get_uri(req);
+
+	if (os_strncmp(uri, "/event/", 7) == 0) {
+		unsigned int event_id;
+		char *pos;
+		event_id = atoi(uri + 7);
+		if (event_id != er->event_id) {
+			wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
+				   "unknown event id %u", event_id);
+			return;
+		}
+		pos = os_strchr(uri + 7, '/');
+		if (pos == NULL)
+			return;
+		pos++;
+		wps_er_http_event(er, req, atoi(pos));
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
+			   uri);
+		wps_er_http_resp_not_found(req);
+	}
+}
+
+
+static void wps_er_http_req(void *ctx, struct http_request *req)
+{
+	struct wps_er *er = ctx;
+	struct sockaddr_in *cli = http_request_get_cli_addr(req);
+	enum httpread_hdr_type type = http_request_get_type(req);
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
+		   "%s:%d",
+		   http_request_get_uri(req), type,
+		   inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
+
+	switch (type) {
+	case HTTPREAD_HDR_TYPE_NOTIFY:
+		wps_er_http_notify(er, req);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
+			   "%d", type);
+		buf = wpabuf_alloc(200);
+		if (buf == NULL) {
+			http_request_deinit(req);
+			return;
+		}
+		wpabuf_put_str(buf,
+			       "HTTP/1.1 501 Unimplemented\r\n"
+			       "Connection: close\r\n");
+		http_put_date(buf);
+		wpabuf_put_str(buf, "\r\n");
+		http_request_send_and_deinit(req, buf);
+		break;
+	}
+}
+
+
+struct wps_er *
+wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
+{
+	struct wps_er *er;
+	struct in_addr addr;
+
+	er = os_zalloc(sizeof(*er));
+	if (er == NULL)
+		return NULL;
+	dl_list_init(&er->ap);
+	dl_list_init(&er->ap_unsubscribing);
+	dl_list_init(&er->ap_settings);
+
+	er->multicast_sd = -1;
+	er->ssdp_sd = -1;
+
+	os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
+	er->wps = wps;
+	if (os_get_random((unsigned char *) &er->event_id,
+			  sizeof(er->event_id)) < 0) {
+		wps_er_deinit(er, NULL, NULL);
+		return NULL;
+	}
+	/* Limit event_id to < 32 bits to avoid issues with atoi() */
+	er->event_id &= 0x0fffffff;
+
+	if (filter) {
+		if (inet_aton(filter, &er->filter_addr) == 0) {
+			wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
+				   "address %s", filter);
+			wps_er_deinit(er, NULL, NULL);
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
+			   "with %s", filter);
+	}
+	if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text,
+			   er->mac_addr)) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
+			   "for %s. Does it have IP address?", ifname);
+		wps_er_deinit(er, NULL, NULL);
+		return NULL;
+	}
+
+	if (wps_er_ssdp_init(er) < 0) {
+		wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
+		wps_er_deinit(er, NULL, NULL);
+		return NULL;
+	}
+
+	addr.s_addr = er->ip_addr;
+	er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
+	if (er->http_srv == NULL) {
+		wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
+		wps_er_deinit(er, NULL, NULL);
+		return NULL;
+	}
+	er->http_port = http_server_get_port(er->http_srv);
+
+	wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
+		   er->ifname, er->ip_addr_text);
+
+	return er;
+}
+
+
+void wps_er_refresh(struct wps_er *er)
+{
+	struct wps_er_ap *ap;
+	struct wps_er_sta *sta;
+
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
+		dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
+			wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
+	}
+
+	wps_er_send_ssdp_msearch(er);
+}
+
+
+static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
+{
+	struct wps_er *er = eloop_data;
+	void (*deinit_done_cb)(void *ctx);
+	void *deinit_done_ctx;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
+
+	deinit_done_cb = er->deinit_done_cb;
+	deinit_done_ctx = er->deinit_done_ctx;
+	os_free(er->ip_addr_text);
+	os_free(er);
+
+	if (deinit_done_cb)
+		deinit_done_cb(deinit_done_ctx);
+}
+
+
+void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
+{
+	if (er == NULL)
+		return;
+	http_server_deinit(er->http_srv);
+	wps_er_ap_remove_all(er);
+	wps_er_ssdp_deinit(er);
+	eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
+			       wps_er_deinit_finish, er, NULL);
+	wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
+	er->deinitializing = 1;
+	er->deinit_done_cb = cb;
+	er->deinit_done_ctx = ctx;
+}
+
+
+static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
+				       enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+	union wps_event_data data;
+
+	os_memset(&data, 0, sizeof(data));
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
+		data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
+		data.set_sel_reg.uuid = ap->uuid;
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
+		data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
+		data.set_sel_reg.uuid = ap->uuid;
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+
+	if (data.set_sel_reg.uuid)
+		ap->er->wps->event_cb(ap->er->wps->cb_ctx,
+				      WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
+}
+
+
+static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
+{
+	struct wpabuf *buf;
+	char *len_ptr, *body_ptr;
+	struct sockaddr_in dst;
+	char *url, *path;
+
+	if (ap->control_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+		return;
+	}
+
+	if (ap->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
+			   "ignore new request");
+		return;
+	}
+
+	if (ap->wps) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
+			   "skip SetSelectedRegistrar");
+		return;
+	}
+
+	url = http_client_url_parse(ap->control_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+		return;
+	}
+
+	buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
+			      &dst, &len_ptr, &body_ptr);
+	os_free(url);
+	if (buf == NULL)
+		return;
+
+	wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
+
+	ap->http = http_client_addr(&dst, buf, 1000,
+				    wps_er_http_set_sel_reg_cb, ap);
+	if (ap->http == NULL)
+		wpabuf_free(buf);
+}
+
+
+static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
+{
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, !!sel_reg);
+	return 0;
+}
+
+
+static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
+{
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, dev_passwd_id);
+	return 0;
+}
+
+
+static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
+					       u16 sel_reg_config_methods)
+{
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, sel_reg_config_methods);
+	return 0;
+}
+
+
+static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
+{
+#ifdef CONFIG_WPS2
+	wpabuf_put_be16(msg, ATTR_UUID_R);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
+#endif /* CONFIG_WPS2 */
+	return 0;
+}
+
+
+void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
+			u16 sel_reg_config_methods)
+{
+	struct wpabuf *msg;
+	struct wps_er_ap *ap;
+	struct wps_registrar *reg = er->wps->registrar;
+	const u8 *auth_macs;
+#ifdef CONFIG_WPS2
+	u8 bcast[ETH_ALEN];
+#endif /* CONFIG_WPS2 */
+	size_t count;
+	union wps_event_data data;
+
+	if (er->skip_set_sel_reg) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
+		return;
+	}
+
+	msg = wpabuf_alloc(500);
+	if (msg == NULL)
+		return;
+
+	auth_macs = wps_authorized_macs(reg, &count);
+#ifdef CONFIG_WPS2
+	if (count == 0) {
+		os_memset(bcast, 0xff, ETH_ALEN);
+		auth_macs = bcast;
+		count = 1;
+	}
+#endif /* CONFIG_WPS2 */
+
+	if (wps_build_version(msg) ||
+	    wps_er_build_selected_registrar(msg, sel_reg) ||
+	    wps_er_build_dev_password_id(msg, dev_passwd_id) ||
+	    wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
+	    wps_build_wfa_ext(msg, 0, auth_macs, count) ||
+	    wps_er_build_uuid_r(msg, er->wps->uuid)) {
+		wpabuf_free(msg);
+		return;
+	}
+
+	os_memset(&data, 0, sizeof(data));
+	data.set_sel_reg.sel_reg = sel_reg;
+	data.set_sel_reg.dev_passwd_id = dev_passwd_id;
+	data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
+	data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
+
+	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+		if (er->set_sel_reg_uuid_filter &&
+		    os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
+			      WPS_UUID_LEN) != 0)
+			continue;
+		data.set_sel_reg.uuid = ap->uuid;
+		er->wps->event_cb(er->wps->cb_ctx,
+				  WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
+		wps_er_send_set_sel_reg(ap, msg);
+	}
+
+	wpabuf_free(msg);
+}
+
+
+int wps_er_pbc(struct wps_er *er, const u8 *uuid)
+{
+	int res;
+	struct wps_er_ap *ap;
+
+	if (er == NULL || er->wps == NULL)
+		return -1;
+
+	if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
+		wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
+			   "mode");
+		return -2;
+	}
+
+	ap = wps_er_ap_get(er, NULL, uuid);
+	if (ap == NULL) {
+		struct wps_er_sta *sta = NULL;
+		dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+			sta = wps_er_sta_get(ap, NULL, uuid);
+			if (sta) {
+				uuid = ap->uuid;
+				break;
+			}
+		}
+		if (sta == NULL)
+			return -3; /* Unknown UUID */
+	}
+
+	if (ap->ap_settings == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
+		return -4;
+	}
+
+	er->set_sel_reg_uuid_filter = uuid;
+	res = wps_registrar_button_pushed(er->wps->registrar, NULL);
+	er->set_sel_reg_uuid_filter = NULL;
+	if (res)
+		return -1;
+
+	return 0;
+}
+
+
+static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
+{
+	struct wps_er_ap *ap = ctx;
+	union wps_event_data data;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
+	os_free(ap->ap_settings);
+	ap->ap_settings = os_malloc(sizeof(*cred));
+	if (ap->ap_settings) {
+		os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+		ap->ap_settings->cred_attr = NULL;
+	}
+
+	os_memset(&data, 0, sizeof(data));
+	data.ap_settings.uuid = ap->uuid;
+	data.ap_settings.cred = cred;
+	ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
+			      &data);
+}
+
+
+static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
+				       enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+	struct wpabuf *reply;
+	char *msg = NULL;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
+		reply = http_client_get_body(c);
+		if (reply == NULL)
+			break;
+		msg = os_zalloc(wpabuf_len(reply) + 1);
+		if (msg == NULL)
+			break;
+		os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
+		if (ap->wps) {
+			wps_deinit(ap->wps);
+			ap->wps = NULL;
+		}
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+
+	if (msg) {
+		struct wpabuf *buf;
+		enum http_reply_code ret;
+		buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
+		os_free(msg);
+		if (buf == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
+				   "NewOutMessage from PutMessage response");
+			wps_deinit(ap->wps);
+			ap->wps = NULL;
+			return;
+		}
+		wps_er_ap_process(ap, buf);
+		wpabuf_free(buf);
+	}
+}
+
+
+static void wps_er_ap_put_message(struct wps_er_ap *ap,
+				  const struct wpabuf *msg)
+{
+	struct wpabuf *buf;
+	char *len_ptr, *body_ptr;
+	struct sockaddr_in dst;
+	char *url, *path;
+
+	if (ap->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
+			   "with the AP - cannot continue learn");
+		return;
+	}
+
+	if (ap->control_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+		return;
+	}
+
+	url = http_client_url_parse(ap->control_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+		return;
+	}
+
+	buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
+			      &len_ptr, &body_ptr);
+	os_free(url);
+	if (buf == NULL)
+		return;
+
+	wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
+
+	ap->http = http_client_addr(&dst, buf, 10000,
+				    wps_er_http_put_message_cb, ap);
+	if (ap->http == NULL)
+		wpabuf_free(buf);
+}
+
+
+static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
+{
+	enum wps_process_res res;
+	struct wps_parse_attr attr;
+	enum wsc_op_code op_code;
+
+	op_code = WSC_MSG;
+	if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
+		switch (*attr.msg_type) {
+		case WPS_WSC_ACK:
+			op_code = WSC_ACK;
+			break;
+		case WPS_WSC_NACK:
+			op_code = WSC_NACK;
+			break;
+		case WPS_WSC_DONE:
+			op_code = WSC_Done;
+			break;
+		}
+	}
+
+	res = wps_process_msg(ap->wps, op_code, msg);
+	if (res == WPS_CONTINUE) {
+		struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
+		if (next) {
+			wps_er_ap_put_message(ap, next);
+			wpabuf_free(next);
+		} else {
+			wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
+				   "message");
+			wps_deinit(ap->wps);
+			ap->wps = NULL;
+		}
+	} else if (res == WPS_DONE) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
+		wps_deinit(ap->wps);
+		ap->wps = NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
+			   "AP (res=%d)", res);
+		wps_deinit(ap->wps);
+		ap->wps = NULL;
+	}
+}
+
+
+static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
+{
+	struct wps_config cfg;
+
+	if (ap->wps) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
+			   "progress with this AP");
+		return;
+	}
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = ap->er->wps;
+	cfg.registrar = 1;
+	ap->wps = wps_init(&cfg);
+	if (ap->wps == NULL)
+		return;
+	ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
+	ap->wps->ap_settings_cb_ctx = ap;
+
+	wps_er_ap_process(ap, m1);
+}
+
+
+static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
+{
+	struct wpabuf *info;
+	enum http_reply_code ret;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
+		   "from the AP");
+	info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
+	if (info == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
+			   "NewDeviceInfo from GetDeviceInfo response");
+		return;
+	}
+
+	ap->m1_handler(ap, info);
+	wpabuf_free(info);
+}
+
+
+static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
+					enum http_client_event event)
+{
+	struct wps_er_ap *ap = ctx;
+	struct wpabuf *reply;
+	char *dev_info = NULL;
+
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
+		reply = http_client_get_body(c);
+		if (reply == NULL)
+			break;
+		dev_info = os_zalloc(wpabuf_len(reply) + 1);
+		if (dev_info == NULL)
+			break;
+		os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
+		break;
+	case HTTP_CLIENT_FAILED:
+	case HTTP_CLIENT_INVALID_REPLY:
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
+		break;
+	}
+	http_client_free(ap->http);
+	ap->http = NULL;
+
+	if (dev_info) {
+		wps_er_ap_learn(ap, dev_info);
+		os_free(dev_info);
+	}
+}
+
+
+static int wps_er_send_get_device_info(struct wps_er_ap *ap,
+				       void (*m1_handler)(struct wps_er_ap *ap,
+							  struct wpabuf *m1))
+{
+	struct wpabuf *buf;
+	char *len_ptr, *body_ptr;
+	struct sockaddr_in dst;
+	char *url, *path;
+
+	if (ap->http) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
+			   "with the AP - cannot get device info");
+		return -1;
+	}
+
+	if (ap->control_url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
+		return -1;
+	}
+
+	url = http_client_url_parse(ap->control_url, &dst, &path);
+	if (url == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
+		return -1;
+	}
+
+	buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
+			      &len_ptr, &body_ptr);
+	os_free(url);
+	if (buf == NULL)
+		return -1;
+
+	wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
+
+	ap->http = http_client_addr(&dst, buf, 10000,
+				    wps_er_http_get_dev_info_cb, ap);
+	if (ap->http == NULL) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ap->m1_handler = m1_handler;
+
+	return 0;
+}
+
+
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		 size_t pin_len)
+{
+	struct wps_er_ap *ap;
+
+	if (er == NULL)
+		return -1;
+
+	ap = wps_er_ap_get(er, NULL, uuid);
+	if (ap == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
+			   "request");
+		return -1;
+	}
+	if (ap->wps) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
+			   "with the AP - cannot start learn");
+		return -1;
+	}
+
+	if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
+		return -1;
+
+	er->skip_set_sel_reg = 1;
+	wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
+	er->skip_set_sel_reg = 0;
+
+	return 0;
+}
+
+
+int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+		      const struct wps_credential *cred)
+{
+	struct wps_er_ap *ap;
+
+	if (er == NULL)
+		return -1;
+
+	ap = wps_er_ap_get(er, NULL, uuid);
+	if (ap == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
+			   "request");
+		return -1;
+	}
+
+	os_free(ap->ap_settings);
+	ap->ap_settings = os_malloc(sizeof(*cred));
+	if (ap->ap_settings == NULL)
+		return -1;
+	os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+	ap->ap_settings->cred_attr = NULL;
+	wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
+		   "config request");
+
+	return 0;
+}
+
+
+static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
+{
+	struct wps_config cfg;
+
+	if (ap->wps) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
+			   "progress with this AP");
+		return;
+	}
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = ap->er->wps;
+	cfg.registrar = 1;
+	cfg.new_ap_settings = ap->ap_settings;
+	ap->wps = wps_init(&cfg);
+	if (ap->wps == NULL)
+		return;
+	ap->wps->ap_settings_cb = NULL;
+	ap->wps->ap_settings_cb_ctx = NULL;
+
+	wps_er_ap_process(ap, m1);
+}
+
+
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		  size_t pin_len, const struct wps_credential *cred)
+{
+	struct wps_er_ap *ap;
+
+	if (er == NULL)
+		return -1;
+
+	ap = wps_er_ap_get(er, NULL, uuid);
+	if (ap == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
+			   "request");
+		return -1;
+	}
+	if (ap->wps) {
+		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
+			   "with the AP - cannot start config");
+		return -1;
+	}
+
+	os_free(ap->ap_settings);
+	ap->ap_settings = os_malloc(sizeof(*cred));
+	if (ap->ap_settings == NULL)
+		return -1;
+	os_memcpy(ap->ap_settings, cred, sizeof(*cred));
+	ap->ap_settings->cred_attr = NULL;
+
+	if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
+		return -1;
+
+	er->skip_set_sel_reg = 1;
+	wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
+	er->skip_set_sel_reg = 0;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+{
+	struct wps_er_ap *ap;
+	struct wpabuf *ret;
+	struct wps_data data;
+
+	if (er == NULL)
+		return NULL;
+
+	ap = wps_er_ap_get(er, NULL, uuid);
+	if (ap == NULL)
+		return NULL;
+	if (ap->ap_settings == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+			   "selected AP");
+		return NULL;
+	}
+
+	ret = wpabuf_alloc(500);
+	if (ret == NULL)
+		return NULL;
+
+	os_memset(&data, 0, sizeof(data));
+	data.wps = er->wps;
+	data.use_cred = ap->ap_settings;
+	if (wps_build_version(ret) ||
+	    wps_build_cred(&data, ret) ||
+	    wps_build_wfa_ext(ret, 0, NULL, 0)) {
+		wpabuf_free(ret);
+		return NULL;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_WPS_NFC */

Deleted: vendor/wpa/2.0/src/wps/wps_er.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_er.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_er.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,106 +0,0 @@
-/*
- * Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_ER_H
-#define WPS_ER_H
-
-#include "utils/list.h"
-
-struct wps_er_sta {
-	struct dl_list list;
-	struct wps_er_ap *ap;
-	u8 addr[ETH_ALEN];
-	u16 config_methods;
-	u8 uuid[WPS_UUID_LEN];
-	u8 pri_dev_type[8];
-	u16 dev_passwd_id;
-	int m1_received;
-	char *manufacturer;
-	char *model_name;
-	char *model_number;
-	char *serial_number;
-	char *dev_name;
-	struct wps_data *wps;
-	struct http_client *http;
-	struct wps_credential *cred;
-};
-
-struct wps_er_ap {
-	struct dl_list list;
-	struct wps_er *er;
-	struct dl_list sta; /* list of STAs/Enrollees using this AP */
-	struct in_addr addr;
-	char *location;
-	struct http_client *http;
-	struct wps_data *wps;
-
-	u8 uuid[WPS_UUID_LEN];
-	u8 pri_dev_type[8];
-	u8 wps_state;
-	u8 mac_addr[ETH_ALEN];
-	char *friendly_name;
-	char *manufacturer;
-	char *manufacturer_url;
-	char *model_description;
-	char *model_name;
-	char *model_number;
-	char *model_url;
-	char *serial_number;
-	char *udn;
-	char *upc;
-
-	char *scpd_url;
-	char *control_url;
-	char *event_sub_url;
-
-	int subscribed;
-	u8 sid[WPS_UUID_LEN];
-	unsigned int id;
-
-	struct wps_credential *ap_settings;
-
-	void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1);
-};
-
-struct wps_er {
-	struct wps_context *wps;
-	char ifname[17];
-	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
-	char *ip_addr_text; /* IP address of network i.f. we use */
-	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
-	int multicast_sd;
-	int ssdp_sd;
-	struct dl_list ap;
-	struct dl_list ap_unsubscribing;
-	struct http_server *http_srv;
-	int http_port;
-	unsigned int next_ap_id;
-	unsigned int event_id;
-	int deinitializing;
-	void (*deinit_done_cb)(void *ctx);
-	void *deinit_done_ctx;
-};
-
-
-/* wps_er.c */
-void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
-		   const char *location, int max_age);
-void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr);
-
-/* wps_er_ssdp.c */
-int wps_er_ssdp_init(struct wps_er *er);
-void wps_er_ssdp_deinit(struct wps_er *er);
-void wps_er_send_ssdp_msearch(struct wps_er *er);
-
-#endif /* WPS_ER_H */

Copied: vendor/wpa/2.0/src/wps/wps_er.h (from rev 9639, vendor/wpa/dist/src/wps/wps_er.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_er.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_er.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,111 @@
+/*
+ * Wi-Fi Protected Setup - External Registrar
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_ER_H
+#define WPS_ER_H
+
+#include "utils/list.h"
+
+struct wps_er_sta {
+	struct dl_list list;
+	struct wps_er_ap *ap;
+	u8 addr[ETH_ALEN];
+	u16 config_methods;
+	u8 uuid[WPS_UUID_LEN];
+	u8 pri_dev_type[8];
+	u16 dev_passwd_id;
+	int m1_received;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	char *dev_name;
+	struct wps_data *wps;
+	struct http_client *http;
+	struct wps_credential *cred;
+};
+
+struct wps_er_ap {
+	struct dl_list list;
+	struct wps_er *er;
+	struct dl_list sta; /* list of STAs/Enrollees using this AP */
+	struct in_addr addr;
+	char *location;
+	struct http_client *http;
+	struct wps_data *wps;
+
+	u8 uuid[WPS_UUID_LEN];
+	u8 pri_dev_type[8];
+	u8 wps_state;
+	u8 mac_addr[ETH_ALEN];
+	char *friendly_name;
+	char *manufacturer;
+	char *manufacturer_url;
+	char *model_description;
+	char *model_name;
+	char *model_number;
+	char *model_url;
+	char *serial_number;
+	char *udn;
+	char *upc;
+
+	char *scpd_url;
+	char *control_url;
+	char *event_sub_url;
+
+	int subscribed;
+	u8 sid[WPS_UUID_LEN];
+	unsigned int id;
+
+	struct wps_credential *ap_settings;
+
+	void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1);
+};
+
+struct wps_er_ap_settings {
+	struct dl_list list;
+	u8 uuid[WPS_UUID_LEN];
+	struct wps_credential ap_settings;
+};
+
+struct wps_er {
+	struct wps_context *wps;
+	char ifname[17];
+	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
+	char *ip_addr_text; /* IP address of network i.f. we use */
+	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+	int multicast_sd;
+	int ssdp_sd;
+	struct dl_list ap;
+	struct dl_list ap_unsubscribing;
+	struct dl_list ap_settings;
+	struct http_server *http_srv;
+	int http_port;
+	unsigned int next_ap_id;
+	unsigned int event_id;
+	int deinitializing;
+	void (*deinit_done_cb)(void *ctx);
+	void *deinit_done_ctx;
+	struct in_addr filter_addr;
+	int skip_set_sel_reg;
+	const u8 *set_sel_reg_uuid_filter;
+};
+
+
+/* wps_er.c */
+void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
+		   const char *location, int max_age);
+void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr);
+int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr);
+
+/* wps_er_ssdp.c */
+int wps_er_ssdp_init(struct wps_er *er);
+void wps_er_ssdp_deinit(struct wps_er *er);
+void wps_er_send_ssdp_msearch(struct wps_er *er);
+
+#endif /* WPS_ER_H */

Deleted: vendor/wpa/2.0/src/wps/wps_er_ssdp.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_er_ssdp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_er_ssdp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,198 +0,0 @@
-/*
- * Wi-Fi Protected Setup - External Registrar (SSDP)
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "uuid.h"
-#include "eloop.h"
-#include "wps_i.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-#include "wps_er.h"
-
-
-static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
-{
-	struct wps_er *er = eloop_ctx;
-	struct sockaddr_in addr; /* client address */
-	socklen_t addr_len;
-	int nread;
-	char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
-	int wfa = 0, byebye = 0;
-	int max_age = -1;
-	char *location = NULL;
-	u8 uuid[WPS_UUID_LEN];
-
-	addr_len = sizeof(addr);
-	nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
-			 (struct sockaddr *) &addr, &addr_len);
-	if (nread <= 0)
-		return;
-	buf[nread] = '\0';
-
-	wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
-		   inet_ntoa(addr.sin_addr));
-	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
-			  (u8 *) buf, nread);
-
-	if (sd == er->multicast_sd) {
-		/* Reply to M-SEARCH */
-		if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
-			return; /* unexpected response header */
-	} else {
-		/* Unsolicited message (likely NOTIFY or M-SEARCH) */
-		if (os_strncmp(buf, "NOTIFY ", 7) != 0)
-			return; /* only process notifications */
-	}
-
-	os_memset(uuid, 0, sizeof(uuid));
-
-	for (start = buf; start && *start; start = pos) {
-		pos = os_strchr(start, '\n');
-		if (pos) {
-			if (pos[-1] == '\r')
-				pos[-1] = '\0';
-			*pos++ = '\0';
-		}
-		if (os_strstr(start, "schemas-wifialliance-org:device:"
-			      "WFADevice:1"))
-			wfa = 1;
-		if (os_strstr(start, "schemas-wifialliance-org:service:"
-			      "WFAWLANConfig:1"))
-			wfa = 1;
-		if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
-			start += 9;
-			while (*start == ' ')
-				start++;
-			location = start;
-		} else if (os_strncasecmp(start, "NTS:", 4) == 0) {
-			if (os_strstr(start, "ssdp:byebye"))
-				byebye = 1;
-		} else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
-			start += 9;
-			while (*start == ' ')
-				start++;
-			pos2 = os_strstr(start, "max-age=");
-			if (pos2 == NULL)
-				continue;
-			pos2 += 8;
-			max_age = atoi(pos2);
-		} else if (os_strncasecmp(start, "USN:", 4) == 0) {
-			start += 4;
-			pos2 = os_strstr(start, "uuid:");
-			if (pos2) {
-				pos2 += 5;
-				while (*pos2 == ' ')
-					pos2++;
-				if (uuid_str2bin(pos2, uuid) < 0) {
-					wpa_printf(MSG_DEBUG, "WPS ER: "
-						   "Invalid UUID in USN: %s",
-						   pos2);
-					return;
-				}
-			}
-		}
-	}
-
-	if (!wfa)
-		return; /* Not WPS advertisement/reply */
-
-	if (byebye) {
-		wps_er_ap_remove(er, &addr.sin_addr);
-		return;
-	}
-
-	if (!location)
-		return; /* Unknown location */
-
-	if (max_age < 1)
-		return; /* No max-age reported */
-
-	wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
-		   "(packet source: %s  max-age: %d)",
-		   location, inet_ntoa(addr.sin_addr), max_age);
-
-	wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age);
-}
-
-
-void wps_er_send_ssdp_msearch(struct wps_er *er)
-{
-	struct wpabuf *msg;
-	struct sockaddr_in dest;
-
-	msg = wpabuf_alloc(500);
-	if (msg == NULL)
-		return;
-
-	wpabuf_put_str(msg,
-		       "M-SEARCH * HTTP/1.1\r\n"
-		       "HOST: 239.255.255.250:1900\r\n"
-		       "MAN: \"ssdp:discover\"\r\n"
-		       "MX: 3\r\n"
-		       "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
-		       "\r\n"
-		       "\r\n");
-
-	os_memset(&dest, 0, sizeof(dest));
-	dest.sin_family = AF_INET;
-	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
-	dest.sin_port = htons(UPNP_MULTICAST_PORT);
-
-	if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
-		   (struct sockaddr *) &dest, sizeof(dest)) < 0)
-		wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
-			   "%d (%s)", errno, strerror(errno));
-
-	wpabuf_free(msg);
-}
-
-
-int wps_er_ssdp_init(struct wps_er *er)
-{
-	if (add_ssdp_network(er->ifname))
-		return -1;
-
-	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
-	if (er->multicast_sd < 0)
-		return -1;
-
-	er->ssdp_sd = ssdp_listener_open();
-	if (er->ssdp_sd < 0)
-		return -1;
-
-	if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
-				wps_er_ssdp_rx, er, NULL) ||
-	    eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
-				wps_er_ssdp_rx, er, NULL))
-		return -1;
-
-	wps_er_send_ssdp_msearch(er);
-
-	return 0;
-}
-
-
-void wps_er_ssdp_deinit(struct wps_er *er)
-{
-	if (er->multicast_sd >= 0) {
-		eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
-		close(er->multicast_sd);
-	}
-	if (er->ssdp_sd >= 0) {
-		eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
-		close(er->ssdp_sd);
-	}
-}

Copied: vendor/wpa/2.0/src/wps/wps_er_ssdp.c (from rev 9639, vendor/wpa/dist/src/wps/wps_er_ssdp.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_er_ssdp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_er_ssdp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,205 @@
+/*
+ * Wi-Fi Protected Setup - External Registrar (SSDP)
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "uuid.h"
+#include "eloop.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+#include "wps_er.h"
+
+
+static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
+{
+	struct wps_er *er = eloop_ctx;
+	struct sockaddr_in addr; /* client address */
+	socklen_t addr_len;
+	int nread;
+	char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
+	int wfa = 0, byebye = 0;
+	int max_age = -1;
+	char *location = NULL;
+	u8 uuid[WPS_UUID_LEN];
+
+	addr_len = sizeof(addr);
+	nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
+			 (struct sockaddr *) &addr, &addr_len);
+	if (nread <= 0)
+		return;
+	buf[nread] = '\0';
+	if (er->filter_addr.s_addr &&
+	    er->filter_addr.s_addr != addr.sin_addr.s_addr)
+		return;
+
+	wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
+		   inet_ntoa(addr.sin_addr));
+	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
+			  (u8 *) buf, nread);
+
+	if (sd == er->multicast_sd) {
+		/* Reply to M-SEARCH */
+		if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
+			return; /* unexpected response header */
+	} else {
+		/* Unsolicited message (likely NOTIFY or M-SEARCH) */
+		if (os_strncmp(buf, "NOTIFY ", 7) != 0)
+			return; /* only process notifications */
+	}
+
+	os_memset(uuid, 0, sizeof(uuid));
+
+	for (start = buf; start && *start; start = pos) {
+		pos = os_strchr(start, '\n');
+		if (pos) {
+			if (pos[-1] == '\r')
+				pos[-1] = '\0';
+			*pos++ = '\0';
+		}
+		if (os_strstr(start, "schemas-wifialliance-org:device:"
+			      "WFADevice:1"))
+			wfa = 1;
+		if (os_strstr(start, "schemas-wifialliance-org:service:"
+			      "WFAWLANConfig:1"))
+			wfa = 1;
+		if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
+			start += 9;
+			while (*start == ' ')
+				start++;
+			location = start;
+		} else if (os_strncasecmp(start, "NTS:", 4) == 0) {
+			if (os_strstr(start, "ssdp:byebye"))
+				byebye = 1;
+		} else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
+			start += 9;
+			while (*start == ' ')
+				start++;
+			pos2 = os_strstr(start, "max-age=");
+			if (pos2 == NULL)
+				continue;
+			pos2 += 8;
+			max_age = atoi(pos2);
+		} else if (os_strncasecmp(start, "USN:", 4) == 0) {
+			start += 4;
+			pos2 = os_strstr(start, "uuid:");
+			if (pos2) {
+				pos2 += 5;
+				while (*pos2 == ' ')
+					pos2++;
+				if (uuid_str2bin(pos2, uuid) < 0) {
+					wpa_printf(MSG_DEBUG, "WPS ER: "
+						   "Invalid UUID in USN: %s",
+						   pos2);
+					return;
+				}
+			}
+		}
+	}
+
+	if (!wfa)
+		return; /* Not WPS advertisement/reply */
+
+	if (byebye) {
+		wps_er_ap_cache_settings(er, &addr.sin_addr);
+		wps_er_ap_remove(er, &addr.sin_addr);
+		return;
+	}
+
+	if (!location)
+		return; /* Unknown location */
+
+	if (max_age < 1)
+		return; /* No max-age reported */
+
+	wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
+		   "(packet source: %s  max-age: %d)",
+		   location, inet_ntoa(addr.sin_addr), max_age);
+
+	wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age);
+}
+
+
+void wps_er_send_ssdp_msearch(struct wps_er *er)
+{
+	struct wpabuf *msg;
+	struct sockaddr_in dest;
+
+	msg = wpabuf_alloc(500);
+	if (msg == NULL)
+		return;
+
+	wpabuf_put_str(msg,
+		       "M-SEARCH * HTTP/1.1\r\n"
+		       "HOST: 239.255.255.250:1900\r\n"
+		       "MAN: \"ssdp:discover\"\r\n"
+		       "MX: 3\r\n"
+		       "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
+		       "\r\n"
+		       "\r\n");
+
+	os_memset(&dest, 0, sizeof(dest));
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+	dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+	if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+		   (struct sockaddr *) &dest, sizeof(dest)) < 0)
+		wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
+			   "%d (%s)", errno, strerror(errno));
+
+	wpabuf_free(msg);
+}
+
+
+int wps_er_ssdp_init(struct wps_er *er)
+{
+	if (add_ssdp_network(er->ifname)) {
+		wpa_printf(MSG_INFO, "WPS ER: Failed to add routing entry for "
+			   "SSDP");
+		return -1;
+	}
+
+	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
+	if (er->multicast_sd < 0) {
+		wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
+			   "for SSDP");
+		return -1;
+	}
+
+	er->ssdp_sd = ssdp_listener_open();
+	if (er->ssdp_sd < 0) {
+		wpa_printf(MSG_INFO, "WPS ER: Failed to open SSDP listener "
+			   "socket");
+		return -1;
+	}
+
+	if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
+				wps_er_ssdp_rx, er, NULL) ||
+	    eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
+				wps_er_ssdp_rx, er, NULL))
+		return -1;
+
+	wps_er_send_ssdp_msearch(er);
+
+	return 0;
+}
+
+
+void wps_er_ssdp_deinit(struct wps_er *er)
+{
+	if (er->multicast_sd >= 0) {
+		eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
+		close(er->multicast_sd);
+	}
+	if (er->ssdp_sd >= 0) {
+		eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
+		close(er->ssdp_sd);
+	}
+}

Deleted: vendor/wpa/2.0/src/wps/wps_i.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,278 +0,0 @@
-/*
- * Wi-Fi Protected Setup - internal definitions
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_I_H
-#define WPS_I_H
-
-#include "wps.h"
-
-/**
- * struct wps_data - WPS registration protocol data
- *
- * This data is stored at the EAP-WSC server/peer method and it is kept for a
- * single registration protocol run.
- */
-struct wps_data {
-	/**
-	 * wps - Pointer to long term WPS context
-	 */
-	struct wps_context *wps;
-
-	/**
-	 * registrar - Whether this end is a Registrar
-	 */
-	int registrar;
-
-	/**
-	 * er - Whether the local end is an external registrar
-	 */
-	int er;
-
-	enum {
-		/* Enrollee states */
-		SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,
-		RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,
-		SEND_WSC_NACK,
-
-		/* Registrar states */
-		RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,
-		RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK
-	} state;
-
-	u8 uuid_e[WPS_UUID_LEN];
-	u8 uuid_r[WPS_UUID_LEN];
-	u8 mac_addr_e[ETH_ALEN];
-	u8 nonce_e[WPS_NONCE_LEN];
-	u8 nonce_r[WPS_NONCE_LEN];
-	u8 psk1[WPS_PSK_LEN];
-	u8 psk2[WPS_PSK_LEN];
-	u8 snonce[2 * WPS_SECRET_NONCE_LEN];
-	u8 peer_hash1[WPS_HASH_LEN];
-	u8 peer_hash2[WPS_HASH_LEN];
-
-	struct wpabuf *dh_privkey;
-	struct wpabuf *dh_pubkey_e;
-	struct wpabuf *dh_pubkey_r;
-	u8 authkey[WPS_AUTHKEY_LEN];
-	u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
-	u8 emsk[WPS_EMSK_LEN];
-
-	struct wpabuf *last_msg;
-
-	u8 *dev_password;
-	size_t dev_password_len;
-	u16 dev_pw_id;
-	int pbc;
-
-	/**
-	 * request_type - Request Type attribute from (Re)AssocReq
-	 */
-	u8 request_type;
-
-	/**
-	 * encr_type - Available encryption types
-	 */
-	u16 encr_type;
-
-	/**
-	 * auth_type - Available authentication types
-	 */
-	u16 auth_type;
-
-	u8 *new_psk;
-	size_t new_psk_len;
-
-	int wps_pin_revealed;
-	struct wps_credential cred;
-
-	struct wps_device_data peer_dev;
-
-	/**
-	 * config_error - Configuration Error value to be used in NACK
-	 */
-	u16 config_error;
-
-	int ext_reg;
-	int int_reg;
-
-	struct wps_credential *new_ap_settings;
-
-	void *dh_ctx;
-
-	void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred);
-	void *ap_settings_cb_ctx;
-
-	struct wps_credential *use_cred;
-
-	int use_psk_key;
-};
-
-
-struct wps_parse_attr {
-	/* fixed length fields */
-	const u8 *version; /* 1 octet */
-	const u8 *msg_type; /* 1 octet */
-	const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
-	const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
-	const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
-	const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
-	const u8 *auth_type_flags; /* 2 octets */
-	const u8 *encr_type_flags; /* 2 octets */
-	const u8 *conn_type_flags; /* 1 octet */
-	const u8 *config_methods; /* 2 octets */
-	const u8 *sel_reg_config_methods; /* 2 octets */
-	const u8 *primary_dev_type; /* 8 octets */
-	const u8 *rf_bands; /* 1 octet */
-	const u8 *assoc_state; /* 2 octets */
-	const u8 *config_error; /* 2 octets */
-	const u8 *dev_password_id; /* 2 octets */
-	const u8 *oob_dev_password; /* WPS_OOB_DEVICE_PASSWORD_ATTR_LEN (54)
-				     * octets */
-	const u8 *os_version; /* 4 octets */
-	const u8 *wps_state; /* 1 octet */
-	const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
-	const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
-	const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
-	const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
-	const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
-	const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
-	const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
-	const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
-	const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
-	const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
-	const u8 *auth_type; /* 2 octets */
-	const u8 *encr_type; /* 2 octets */
-	const u8 *network_idx; /* 1 octet */
-	const u8 *network_key_idx; /* 1 octet */
-	const u8 *mac_addr; /* ETH_ALEN (6) octets */
-	const u8 *key_prov_auto; /* 1 octet (Bool) */
-	const u8 *dot1x_enabled; /* 1 octet (Bool) */
-	const u8 *selected_registrar; /* 1 octet (Bool) */
-	const u8 *request_type; /* 1 octet */
-	const u8 *response_type; /* 1 octet */
-	const u8 *ap_setup_locked; /* 1 octet */
-
-	/* variable length fields */
-	const u8 *manufacturer;
-	size_t manufacturer_len;
-	const u8 *model_name;
-	size_t model_name_len;
-	const u8 *model_number;
-	size_t model_number_len;
-	const u8 *serial_number;
-	size_t serial_number_len;
-	const u8 *dev_name;
-	size_t dev_name_len;
-	const u8 *public_key;
-	size_t public_key_len;
-	const u8 *encr_settings;
-	size_t encr_settings_len;
-	const u8 *ssid; /* <= 32 octets */
-	size_t ssid_len;
-	const u8 *network_key; /* <= 64 octets */
-	size_t network_key_len;
-	const u8 *eap_type; /* <= 8 octets */
-	size_t eap_type_len;
-	const u8 *eap_identity; /* <= 64 octets */
-	size_t eap_identity_len;
-
-	/* attributes that can occur multiple times */
-#define MAX_CRED_COUNT 10
-	const u8 *cred[MAX_CRED_COUNT];
-	size_t cred_len[MAX_CRED_COUNT];
-	size_t num_cred;
-};
-
-/* wps_common.c */
-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);
-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);
-void wps_success_event(struct wps_context *wps);
-void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
-void wps_pbc_overlap_event(struct wps_context *wps);
-void wps_pbc_timeout_event(struct wps_context *wps);
-
-extern struct oob_device_data oob_ufd_device_data;
-extern struct oob_device_data oob_nfc_device_data;
-extern struct oob_nfc_device_data oob_nfc_pn531_device_data;
-
-/* wps_attr_parse.c */
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
-
-/* wps_attr_build.c */
-int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
-int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type);
-int wps_build_config_methods(struct wpabuf *msg, u16 methods);
-int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
-int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
-int wps_build_config_error(struct wpabuf *msg, u16 err);
-int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
-			    struct wpabuf *plain);
-int wps_build_version(struct wpabuf *msg);
-int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
-int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps);
-
-/* wps_attr_process.c */
-int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
-			      const struct wpabuf *msg);
-int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
-			      const u8 *key_wrap_auth);
-int wps_process_cred(struct wps_parse_attr *attr,
-		     struct wps_credential *cred);
-int wps_process_ap_settings(struct wps_parse_attr *attr,
-			    struct wps_credential *cred);
-
-/* wps_enrollee.c */
-struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
-				     enum wsc_op_code *op_code);
-enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
-					      enum wsc_op_code op_code,
-					      const struct wpabuf *msg);
-
-/* wps_registrar.c */
-struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
-				      enum wsc_op_code *op_code);
-enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
-					       enum wsc_op_code op_code,
-					       const struct wpabuf *msg);
-int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
-int wps_device_store(struct wps_registrar *reg,
-		     struct wps_device_data *dev, const u8 *uuid);
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
-
-/* ndef.c */
-struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
-struct wpabuf * ndef_build_wifi(struct wpabuf *buf);
-
-static inline int wps_version_supported(const u8 *version)
-{
-	/* Require major version match, but allow minor version differences */
-	return version && (*version & 0xf0) == (WPS_VERSION & 0xf0);
-}
-
-#endif /* WPS_I_H */

Copied: vendor/wpa/2.0/src/wps/wps_i.h (from rev 9639, vendor/wpa/dist/src/wps/wps_i.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,203 @@
+/*
+ * Wi-Fi Protected Setup - internal definitions
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_I_H
+#define WPS_I_H
+
+#include "wps.h"
+#include "wps_attr_parse.h"
+
+struct wps_nfc_pw_token;
+
+/**
+ * struct wps_data - WPS registration protocol data
+ *
+ * This data is stored at the EAP-WSC server/peer method and it is kept for a
+ * single registration protocol run.
+ */
+struct wps_data {
+	/**
+	 * wps - Pointer to long term WPS context
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * registrar - Whether this end is a Registrar
+	 */
+	int registrar;
+
+	/**
+	 * er - Whether the local end is an external registrar
+	 */
+	int er;
+
+	enum {
+		/* Enrollee states */
+		SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,
+		RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,
+		SEND_WSC_NACK,
+
+		/* Registrar states */
+		RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,
+		RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK
+	} state;
+
+	u8 uuid_e[WPS_UUID_LEN];
+	u8 uuid_r[WPS_UUID_LEN];
+	u8 mac_addr_e[ETH_ALEN];
+	u8 nonce_e[WPS_NONCE_LEN];
+	u8 nonce_r[WPS_NONCE_LEN];
+	u8 psk1[WPS_PSK_LEN];
+	u8 psk2[WPS_PSK_LEN];
+	u8 snonce[2 * WPS_SECRET_NONCE_LEN];
+	u8 peer_hash1[WPS_HASH_LEN];
+	u8 peer_hash2[WPS_HASH_LEN];
+
+	struct wpabuf *dh_privkey;
+	struct wpabuf *dh_pubkey_e;
+	struct wpabuf *dh_pubkey_r;
+	u8 authkey[WPS_AUTHKEY_LEN];
+	u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
+	u8 emsk[WPS_EMSK_LEN];
+
+	struct wpabuf *last_msg;
+
+	u8 *dev_password;
+	size_t dev_password_len;
+	u16 dev_pw_id;
+	int pbc;
+
+	/**
+	 * request_type - Request Type attribute from (Re)AssocReq
+	 */
+	u8 request_type;
+
+	/**
+	 * encr_type - Available encryption types
+	 */
+	u16 encr_type;
+
+	/**
+	 * auth_type - Available authentication types
+	 */
+	u16 auth_type;
+
+	u8 *new_psk;
+	size_t new_psk_len;
+
+	int wps_pin_revealed;
+	struct wps_credential cred;
+
+	struct wps_device_data peer_dev;
+
+	/**
+	 * config_error - Configuration Error value to be used in NACK
+	 */
+	u16 config_error;
+	u16 error_indication;
+
+	int ext_reg;
+	int int_reg;
+
+	struct wps_credential *new_ap_settings;
+
+	void *dh_ctx;
+
+	void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred);
+	void *ap_settings_cb_ctx;
+
+	struct wps_credential *use_cred;
+
+	int use_psk_key;
+	u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or
+				    * 00:00:00:00:00:00 if not a P2p client */
+	int pbc_in_m1;
+
+	struct wps_nfc_pw_token *nfc_pw_token;
+};
+
+
+/* wps_common.c */
+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);
+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,
+		    u16 config_error, u16 error_indication);
+void wps_success_event(struct wps_context *wps);
+void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
+void wps_pbc_overlap_event(struct wps_context *wps);
+void wps_pbc_timeout_event(struct wps_context *wps);
+
+struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
+struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
+
+/* wps_attr_build.c */
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
+int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type);
+int wps_build_config_methods(struct wpabuf *msg, u16 methods);
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
+int wps_build_config_error(struct wpabuf *msg, u16 err);
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
+			    struct wpabuf *plain);
+int wps_build_version(struct wpabuf *msg);
+int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
+		      const u8 *auth_macs, size_t auth_macs_count);
+int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
+int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
+			 const struct wpabuf *pubkey, const u8 *dev_pw,
+			 size_t dev_pw_len);
+struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
+
+/* wps_attr_process.c */
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg);
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth);
+int wps_process_cred(struct wps_parse_attr *attr,
+		     struct wps_credential *cred);
+int wps_process_ap_settings(struct wps_parse_attr *attr,
+			    struct wps_credential *cred);
+
+/* wps_enrollee.c */
+struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
+				     enum wsc_op_code *op_code);
+enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
+					      enum wsc_op_code op_code,
+					      const struct wpabuf *msg);
+
+/* wps_registrar.c */
+struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
+				      enum wsc_op_code *op_code);
+enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
+					       enum wsc_op_code op_code,
+					       const struct wpabuf *msg);
+int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
+int wps_device_store(struct wps_registrar *reg,
+		     struct wps_device_data *dev, const u8 *uuid);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
+int wps_registrar_pbc_overlap(struct wps_registrar *reg,
+			      const u8 *addr, const u8 *uuid_e);
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+				       struct wps_nfc_pw_token *token);
+
+#endif /* WPS_I_H */

Deleted: vendor/wpa/2.0/src/wps/wps_nfc.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_nfc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_nfc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,117 +0,0 @@
-/*
- * NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma at ictec.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-
-struct wps_nfc_data {
-	struct oob_nfc_device_data *oob_nfc_dev;
-};
-
-
-static void * init_nfc(struct wps_context *wps,
-		       struct oob_device_data *oob_dev, int registrar)
-{
-	struct oob_nfc_device_data *oob_nfc_dev;
-	struct wps_nfc_data *data;
-
-	oob_nfc_dev = wps_get_oob_nfc_device(oob_dev->device_name);
-	if (oob_nfc_dev == NULL) {
-		wpa_printf(MSG_ERROR, "WPS (NFC): Unknown NFC device (%s)",
-			   oob_dev->device_name);
-		return NULL;
-	}
-
-	if (oob_nfc_dev->init_func(oob_dev->device_path) < 0)
-		return NULL;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL) {
-		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
-			   "nfc data area");
-		return NULL;
-	}
-	data->oob_nfc_dev = oob_nfc_dev;
-	return data;
-}
-
-
-static struct wpabuf * read_nfc(void *priv)
-{
-	struct wps_nfc_data *data = priv;
-	struct wpabuf *wifi, *buf;
-	char *raw_data;
-	size_t len;
-
-	raw_data = data->oob_nfc_dev->read_func(&len);
-	if (raw_data == NULL)
-		return NULL;
-
-	wifi = wpabuf_alloc_copy(raw_data, len);
-	os_free(raw_data);
-	if (wifi == NULL) {
-		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
-			   "nfc read area");
-		return NULL;
-	}
-
-	buf = ndef_parse_wifi(wifi);
-	wpabuf_free(wifi);
-	if (buf == NULL)
-		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to unwrap");
-	return buf;
-}
-
-
-static int write_nfc(void *priv, struct wpabuf *buf)
-{
-	struct wps_nfc_data *data = priv;
-	struct wpabuf *wifi;
-	int ret;
-
-	wifi = ndef_build_wifi(buf);
-	if (wifi == NULL) {
-		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to wrap");
-		return -1;
-	}
-
-	ret = data->oob_nfc_dev->write_func(wpabuf_mhead(wifi),
-					    wpabuf_len(wifi));
-	wpabuf_free(wifi);
-	return ret;
-}
-
-
-static void deinit_nfc(void *priv)
-{
-	struct wps_nfc_data *data = priv;
-
-	data->oob_nfc_dev->deinit_func();
-
-	os_free(data);
-}
-
-
-struct oob_device_data oob_nfc_device_data = {
-	.device_name	= NULL,
-	.device_path	= NULL,
-	.init_func	= init_nfc,
-	.read_func	= read_nfc,
-	.write_func	= write_nfc,
-	.deinit_func	= deinit_nfc,
-};

Deleted: vendor/wpa/2.0/src/wps/wps_nfc_pn531.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_nfc_pn531.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_nfc_pn531.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,113 +0,0 @@
-/*
- * NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma at ictec.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-#include "WpsNfcType.h"
-#include "WpsNfc.h"
-
-
-static int init_nfc_pn531(char *path)
-{
-	u32 ret;
-
-	ret = WpsNfcInit();
-	if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to initialize "
-			   "NFC Library: 0x%08x", ret);
-		return -1;
-	}
-
-	ret = WpsNfcOpenDevice((int8 *) path);
-	if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to open "
-			   "NFC Device(%s): 0x%08x", path, ret);
-		goto fail;
-	}
-
-	ret = WpsNfcTokenDiscovery();
-	if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to discover "
-			   "token: 0x%08x", ret);
-		WpsNfcCloseDevice();
-		goto fail;
-	}
-
-	return 0;
-
-fail:
-	WpsNfcDeinit();
-	return -1;
-}
-
-
-static void * read_nfc_pn531(size_t *size)
-{
-	uint32 len;
-	u32 ret;
-	int8 *data;
-
-	ret = WpsNfcRawReadToken(&data, &len);
-	if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to read: 0x%08x",
-			   ret);
-		return NULL;
-	}
-
-	*size = len;
-	return data;
-}
-
-
-static int write_nfc_pn531(void *data, size_t len)
-{
-	u32 ret;
-
-	ret = WpsNfcRawWriteToken(data, len);
-	if (ret != WPS_NFCLIB_ERR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to write: 0x%08x",
-			   ret);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void deinit_nfc_pn531(void)
-{
-	u32 ret;
-
-	ret = WpsNfcCloseDevice();
-	if (ret != WPS_NFCLIB_ERR_SUCCESS)
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to close "
-			   "NFC Device: 0x%08x", ret);
-
-	ret = WpsNfcDeinit();
-	if (ret != WPS_NFCLIB_ERR_SUCCESS)
-		wpa_printf(MSG_ERROR, "WPS (PN531): Failed to deinitialize "
-			   "NFC Library: 0x%08x", ret);
-}
-
-
-struct oob_nfc_device_data oob_nfc_pn531_device_data = {
-	.init_func	= init_nfc_pn531,
-	.read_func	= read_nfc_pn531,
-	.write_func	= write_nfc_pn531,
-	.deinit_func	= deinit_nfc_pn531,
-};

Deleted: vendor/wpa/2.0/src/wps/wps_registrar.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_registrar.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_registrar.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2900 +0,0 @@
-/*
- * Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/base64.h"
-#include "utils/eloop.h"
-#include "utils/uuid.h"
-#include "utils/list.h"
-#include "crypto/crypto.h"
-#include "crypto/sha256.h"
-#include "common/ieee802_11_defs.h"
-#include "wps_i.h"
-#include "wps_dev_attr.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-
-#define WPS_WORKAROUNDS
-
-struct wps_uuid_pin {
-	struct dl_list list;
-	u8 uuid[WPS_UUID_LEN];
-	int wildcard_uuid;
-	u8 *pin;
-	size_t pin_len;
-#define PIN_LOCKED BIT(0)
-#define PIN_EXPIRES BIT(1)
-	int flags;
-	struct os_time expiration;
-};
-
-
-static void wps_free_pin(struct wps_uuid_pin *pin)
-{
-	os_free(pin->pin);
-	os_free(pin);
-}
-
-
-static void wps_remove_pin(struct wps_uuid_pin *pin)
-{
-	dl_list_del(&pin->list);
-	wps_free_pin(pin);
-}
-
-
-static void wps_free_pins(struct dl_list *pins)
-{
-	struct wps_uuid_pin *pin, *prev;
-	dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list)
-		wps_remove_pin(pin);
-}
-
-
-struct wps_pbc_session {
-	struct wps_pbc_session *next;
-	u8 addr[ETH_ALEN];
-	u8 uuid_e[WPS_UUID_LEN];
-	struct os_time timestamp;
-};
-
-
-static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)
-{
-	struct wps_pbc_session *prev;
-
-	while (pbc) {
-		prev = pbc;
-		pbc = pbc->next;
-		os_free(prev);
-	}
-}
-
-
-struct wps_registrar_device {
-	struct wps_registrar_device *next;
-	struct wps_device_data dev;
-	u8 uuid[WPS_UUID_LEN];
-};
-
-
-struct wps_registrar {
-	struct wps_context *wps;
-
-	int pbc;
-	int selected_registrar;
-
-	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
-			  size_t psk_len);
-	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
-			 struct wpabuf *probe_resp_ie);
-	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
-			      const struct wps_device_data *dev);
-	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
-			       const u8 *uuid_e);
-	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
-			       u16 sel_reg_config_methods);
-	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
-				 const u8 *pri_dev_type, u16 config_methods,
-				 u16 dev_password_id, u8 request_type,
-				 const char *dev_name);
-	void *cb_ctx;
-
-	struct dl_list pins;
-	struct wps_pbc_session *pbc_sessions;
-
-	int skip_cred_build;
-	struct wpabuf *extra_cred;
-	int disable_auto_conf;
-	int sel_reg_union;
-	int sel_reg_dev_password_id_override;
-	int sel_reg_config_methods_override;
-	int static_wep_only;
-
-	struct wps_registrar_device *devices;
-
-	int force_pbc_overlap;
-};
-
-
-static int wps_set_ie(struct wps_registrar *reg);
-static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
-static void wps_registrar_set_selected_timeout(void *eloop_ctx,
-					       void *timeout_ctx);
-
-
-static void wps_free_devices(struct wps_registrar_device *dev)
-{
-	struct wps_registrar_device *prev;
-
-	while (dev) {
-		prev = dev;
-		dev = dev->next;
-		wps_device_data_free(&prev->dev);
-		os_free(prev);
-	}
-}
-
-
-static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,
-						    const u8 *addr)
-{
-	struct wps_registrar_device *dev;
-
-	for (dev = reg->devices; dev; dev = dev->next) {
-		if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0)
-			return dev;
-	}
-	return NULL;
-}
-
-
-static void wps_device_clone_data(struct wps_device_data *dst,
-				  struct wps_device_data *src)
-{
-	os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
-	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
-
-#define WPS_STRDUP(n) \
-	os_free(dst->n); \
-	dst->n = src->n ? os_strdup(src->n) : NULL
-
-	WPS_STRDUP(device_name);
-	WPS_STRDUP(manufacturer);
-	WPS_STRDUP(model_name);
-	WPS_STRDUP(model_number);
-	WPS_STRDUP(serial_number);
-#undef WPS_STRDUP
-}
-
-
-int wps_device_store(struct wps_registrar *reg,
-		     struct wps_device_data *dev, const u8 *uuid)
-{
-	struct wps_registrar_device *d;
-
-	d = wps_device_get(reg, dev->mac_addr);
-	if (d == NULL) {
-		d = os_zalloc(sizeof(*d));
-		if (d == NULL)
-			return -1;
-		d->next = reg->devices;
-		reg->devices = d;
-	}
-
-	wps_device_clone_data(&d->dev, dev);
-	os_memcpy(d->uuid, uuid, WPS_UUID_LEN);
-
-	return 0;
-}
-
-
-static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
-					  const u8 *addr, const u8 *uuid_e)
-{
-	struct wps_pbc_session *pbc, *prev = NULL;
-	struct os_time now;
-
-	os_get_time(&now);
-
-	pbc = reg->pbc_sessions;
-	while (pbc) {
-		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
-		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
-			if (prev)
-				prev->next = pbc->next;
-			else
-				reg->pbc_sessions = pbc->next;
-			break;
-		}
-		prev = pbc;
-		pbc = pbc->next;
-	}
-
-	if (!pbc) {
-		pbc = os_zalloc(sizeof(*pbc));
-		if (pbc == NULL)
-			return;
-		os_memcpy(pbc->addr, addr, ETH_ALEN);
-		if (uuid_e)
-			os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN);
-	}
-
-	pbc->next = reg->pbc_sessions;
-	reg->pbc_sessions = pbc;
-	pbc->timestamp = now;
-
-	/* remove entries that have timed out */
-	prev = pbc;
-	pbc = pbc->next;
-
-	while (pbc) {
-		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
-			prev->next = NULL;
-			wps_free_pbc_sessions(pbc);
-			break;
-		}
-		prev = pbc;
-		pbc = pbc->next;
-	}
-}
-
-
-static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
-					     const u8 *addr, const u8 *uuid_e)
-{
-	struct wps_pbc_session *pbc, *prev = NULL;
-
-	pbc = reg->pbc_sessions;
-	while (pbc) {
-		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
-		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
-			if (prev)
-				prev->next = pbc->next;
-			else
-				reg->pbc_sessions = pbc->next;
-			os_free(pbc);
-			break;
-		}
-		prev = pbc;
-		pbc = pbc->next;
-	}
-}
-
-
-static int wps_registrar_pbc_overlap(struct wps_registrar *reg,
-				     const u8 *addr, const u8 *uuid_e)
-{
-	int count = 0;
-	struct wps_pbc_session *pbc;
-	struct os_time now;
-
-	os_get_time(&now);
-
-	for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
-		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME)
-			break;
-		if (addr == NULL || os_memcmp(addr, pbc->addr, ETH_ALEN) ||
-		    uuid_e == NULL ||
-		    os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN))
-			count++;
-	}
-
-	if (addr || uuid_e)
-		count++;
-
-	return count > 1 ? 1 : 0;
-}
-
-
-static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
-		   wps->wps_state);
-	wpabuf_put_be16(msg, ATTR_WPS_STATE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, wps->wps_state);
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS_UPNP
-static void wps_registrar_free_pending_m2(struct wps_context *wps)
-{
-	struct upnp_pending_message *p, *p2, *prev = NULL;
-	p = wps->upnp_msgs;
-	while (p) {
-		if (p->type == WPS_M2 || p->type == WPS_M2D) {
-			if (prev == NULL)
-				wps->upnp_msgs = p->next;
-			else
-				prev->next = p->next;
-			wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
-			p2 = p;
-			p = p->next;
-			wpabuf_free(p2->msg);
-			os_free(p2);
-			continue;
-		}
-		prev = p;
-		p = p->next;
-	}
-}
-#endif /* CONFIG_WPS_UPNP */
-
-
-static int wps_build_ap_setup_locked(struct wps_context *wps,
-				     struct wpabuf *msg)
-{
-	if (wps->ap_setup_locked) {
-		wpa_printf(MSG_DEBUG, "WPS:  * AP Setup Locked");
-		wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
-		wpabuf_put_be16(msg, 1);
-		wpabuf_put_u8(msg, 1);
-	}
-	return 0;
-}
-
-
-static int wps_build_selected_registrar(struct wps_registrar *reg,
-					struct wpabuf *msg)
-{
-	if (!reg->sel_reg_union)
-		return 0;
-	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar");
-	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, 1);
-	return 0;
-}
-
-
-static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
-					     struct wpabuf *msg)
-{
-	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
-	if (!reg->sel_reg_union)
-		return 0;
-	if (reg->sel_reg_dev_password_id_override >= 0)
-		id = reg->sel_reg_dev_password_id_override;
-	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
-	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, id);
-	return 0;
-}
-
-
-static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
-					    struct wpabuf *msg)
-{
-	u16 methods;
-	if (!reg->sel_reg_union)
-		return 0;
-	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-	if (reg->pbc)
-		methods |= WPS_CONFIG_PUSHBUTTON;
-	if (reg->sel_reg_config_methods_override >= 0)
-		methods = reg->sel_reg_config_methods_override;
-	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar Config Methods (%x)",
-		   methods);
-	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, methods);
-	return 0;
-}
-
-
-static int wps_build_probe_config_methods(struct wps_registrar *reg,
-					  struct wpabuf *msg)
-{
-	u16 methods;
-	/*
-	 * These are the methods that the AP supports as an Enrollee for adding
-	 * external Registrars.
-	 */
-	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
-	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, methods);
-	return 0;
-}
-
-
-static int wps_build_config_methods_r(struct wps_registrar *reg,
-				      struct wpabuf *msg)
-{
-	u16 methods;
-	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-	if (reg->pbc)
-		methods |= WPS_CONFIG_PUSHBUTTON;
-	return wps_build_config_methods(msg, methods);
-}
-
-
-/**
- * wps_registrar_init - Initialize WPS Registrar data
- * @wps: Pointer to longterm WPS context
- * @cfg: Registrar configuration
- * Returns: Pointer to allocated Registrar data or %NULL on failure
- *
- * This function is used to initialize WPS Registrar functionality. It can be
- * used for a single Registrar run (e.g., when run in a supplicant) or multiple
- * runs (e.g., when run as an internal Registrar in an AP). Caller is
- * responsible for freeing the returned data with wps_registrar_deinit() when
- * Registrar functionality is not needed anymore.
- */
-struct wps_registrar *
-wps_registrar_init(struct wps_context *wps,
-		   const struct wps_registrar_config *cfg)
-{
-	struct wps_registrar *reg = os_zalloc(sizeof(*reg));
-	if (reg == NULL)
-		return NULL;
-
-	dl_list_init(&reg->pins);
-	reg->wps = wps;
-	reg->new_psk_cb = cfg->new_psk_cb;
-	reg->set_ie_cb = cfg->set_ie_cb;
-	reg->pin_needed_cb = cfg->pin_needed_cb;
-	reg->reg_success_cb = cfg->reg_success_cb;
-	reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
-	reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
-	reg->cb_ctx = cfg->cb_ctx;
-	reg->skip_cred_build = cfg->skip_cred_build;
-	if (cfg->extra_cred) {
-		reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred,
-						    cfg->extra_cred_len);
-		if (reg->extra_cred == NULL) {
-			os_free(reg);
-			return NULL;
-		}
-	}
-	reg->disable_auto_conf = cfg->disable_auto_conf;
-	reg->sel_reg_dev_password_id_override = -1;
-	reg->sel_reg_config_methods_override = -1;
-	reg->static_wep_only = cfg->static_wep_only;
-
-	if (wps_set_ie(reg)) {
-		wps_registrar_deinit(reg);
-		return NULL;
-	}
-
-	return reg;
-}
-
-
-/**
- * wps_registrar_deinit - Deinitialize WPS Registrar data
- * @reg: Registrar data from wps_registrar_init()
- */
-void wps_registrar_deinit(struct wps_registrar *reg)
-{
-	if (reg == NULL)
-		return;
-	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
-	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
-	wps_free_pins(&reg->pins);
-	wps_free_pbc_sessions(reg->pbc_sessions);
-	wpabuf_free(reg->extra_cred);
-	wps_free_devices(reg->devices);
-	os_free(reg);
-}
-
-
-/**
- * wps_registrar_add_pin - Configure a new PIN for Registrar
- * @reg: Registrar data from wps_registrar_init()
- * @uuid: UUID-E or %NULL for wildcard (any UUID)
- * @pin: PIN (Device Password)
- * @pin_len: Length of pin in octets
- * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
- * Returns: 0 on success, -1 on failure
- */
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-			  const u8 *pin, size_t pin_len, int timeout)
-{
-	struct wps_uuid_pin *p;
-
-	p = os_zalloc(sizeof(*p));
-	if (p == NULL)
-		return -1;
-	if (uuid == NULL)
-		p->wildcard_uuid = 1;
-	else
-		os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
-	p->pin = os_malloc(pin_len);
-	if (p->pin == NULL) {
-		os_free(p);
-		return -1;
-	}
-	os_memcpy(p->pin, pin, pin_len);
-	p->pin_len = pin_len;
-
-	if (timeout) {
-		p->flags |= PIN_EXPIRES;
-		os_get_time(&p->expiration);
-		p->expiration.sec += timeout;
-	}
-
-	dl_list_add(&reg->pins, &p->list);
-
-	wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
-		   timeout);
-	wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
-	reg->selected_registrar = 1;
-	reg->pbc = 0;
-	wps_registrar_selected_registrar_changed(reg);
-	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
-	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
-			       wps_registrar_set_selected_timeout,
-			       reg, NULL);
-
-	return 0;
-}
-
-
-static void wps_registrar_expire_pins(struct wps_registrar *reg)
-{
-	struct wps_uuid_pin *pin, *prev;
-	struct os_time now;
-
-	os_get_time(&now);
-	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
-	{
-		if ((pin->flags & PIN_EXPIRES) &&
-		    os_time_before(&pin->expiration, &now)) {
-			wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
-				    pin->uuid, WPS_UUID_LEN);
-			wps_remove_pin(pin);
-		}
-	}
-}
-
-
-/**
- * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
- * @reg: Registrar data from wps_registrar_init()
- * @uuid: UUID-E
- * Returns: 0 on success, -1 on failure (e.g., PIN not found)
- */
-int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
-{
-	struct wps_uuid_pin *pin, *prev;
-
-	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
-	{
-		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
-			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
-				    pin->uuid, WPS_UUID_LEN);
-			wps_remove_pin(pin);
-			return 0;
-		}
-	}
-
-	return -1;
-}
-
-
-static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
-					const u8 *uuid, size_t *pin_len)
-{
-	struct wps_uuid_pin *pin, *found = NULL;
-
-	wps_registrar_expire_pins(reg);
-
-	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
-		if (!pin->wildcard_uuid &&
-		    os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
-			found = pin;
-			break;
-		}
-	}
-
-	if (!found) {
-		/* Check for wildcard UUIDs since none of the UUID-specific
-		 * PINs matched */
-		dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
-			if (pin->wildcard_uuid == 1) {
-				wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
-					   "PIN. Assigned it for this UUID-E");
-				pin->wildcard_uuid = 2;
-				os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
-				found = pin;
-				break;
-			}
-		}
-	}
-
-	if (!found)
-		return NULL;
-
-	/*
-	 * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
-	 * that could otherwise avoid PIN invalidations.
-	 */
-	if (found->flags & PIN_LOCKED) {
-		wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
-			   "allow concurrent re-use");
-		return NULL;
-	}
-	*pin_len = found->pin_len;
-	found->flags |= PIN_LOCKED;
-	return found->pin;
-}
-
-
-/**
- * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E
- * @reg: Registrar data from wps_registrar_init()
- * @uuid: UUID-E
- * Returns: 0 on success, -1 on failure
- *
- * PINs are locked to enforce only one concurrent use. This function unlocks a
- * PIN to allow it to be used again. If the specified PIN was configured using
- * a wildcard UUID, it will be removed instead of allowing multiple uses.
- */
-int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
-{
-	struct wps_uuid_pin *pin;
-
-	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
-		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
-			if (pin->wildcard_uuid == 2) {
-				wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
-					   "wildcard PIN");
-				return wps_registrar_invalidate_pin(reg, uuid);
-			}
-			pin->flags &= ~PIN_LOCKED;
-			return 0;
-		}
-	}
-
-	return -1;
-}
-
-
-static void wps_registrar_stop_pbc(struct wps_registrar *reg)
-{
-	reg->selected_registrar = 0;
-	reg->pbc = 0;
-	wps_registrar_selected_registrar_changed(reg);
-}
-
-
-static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wps_registrar *reg = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
-	wps_pbc_timeout_event(reg->wps);
-	wps_registrar_stop_pbc(reg);
-}
-
-
-/**
- * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
- * @reg: Registrar data from wps_registrar_init()
- * Returns: 0 on success, -1 on failure
- *
- * This function is called on an AP when a push button is pushed to activate
- * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
- * or when a PBC registration is completed.
- */
-int wps_registrar_button_pushed(struct wps_registrar *reg)
-{
-	if (wps_registrar_pbc_overlap(reg, NULL, NULL)) {
-		wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
-			   "mode");
-		wps_pbc_overlap_event(reg->wps);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
-	reg->force_pbc_overlap = 0;
-	reg->selected_registrar = 1;
-	reg->pbc = 1;
-	wps_registrar_selected_registrar_changed(reg);
-
-	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
-	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
-			       reg, NULL);
-	return 0;
-}
-
-
-static void wps_registrar_pbc_completed(struct wps_registrar *reg)
-{
-	wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
-	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
-	wps_registrar_stop_pbc(reg);
-}
-
-
-static void wps_registrar_pin_completed(struct wps_registrar *reg)
-{
-	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
-	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
-	reg->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(reg);
-}
-
-
-/**
- * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
- * @reg: Registrar data from wps_registrar_init()
- * @addr: MAC address of the Probe Request sender
- * @wps_data: WPS IE contents
- *
- * This function is called on an AP when a Probe Request with WPS IE is
- * received. This is used to track PBC mode use and to detect possible overlap
- * situation with other WPS APs.
- */
-void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
-				const struct wpabuf *wps_data)
-{
-	struct wps_parse_attr attr;
-
-	wpa_hexdump_buf(MSG_MSGDUMP,
-			"WPS: Probe Request with WPS data received",
-			wps_data);
-
-	if (wps_parse_msg(wps_data, &attr) < 0)
-		return;
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported ProbeReq WPS IE "
-			   "version 0x%x", attr.version ? *attr.version : 0);
-		return;
-	}
-
-	if (attr.config_methods == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
-			   "Probe Request");
-		return;
-	}
-
-	if (attr.dev_password_id == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute "
-			   "in Probe Request");
-		return;
-	}
-
-	if (reg->enrollee_seen_cb && attr.uuid_e &&
-	    attr.primary_dev_type && attr.request_type) {
-		char *dev_name = NULL;
-		if (attr.dev_name) {
-			dev_name = os_zalloc(attr.dev_name_len + 1);
-			if (dev_name) {
-				os_memcpy(dev_name, attr.dev_name,
-					  attr.dev_name_len);
-			}
-		}
-		reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e,
-				      attr.primary_dev_type,
-				      WPA_GET_BE16(attr.config_methods),
-				      WPA_GET_BE16(attr.dev_password_id),
-				      *attr.request_type, dev_name);
-		os_free(dev_name);
-	}
-
-	if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
-		return; /* Not PBC */
-
-	wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
-		   MACSTR, MAC2STR(addr));
-	if (attr.uuid_e == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No "
-			   "UUID-E included");
-		return;
-	}
-
-	wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
-	if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
-		wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
-		reg->force_pbc_overlap = 1;
-		wps_pbc_overlap_event(reg->wps);
-	}
-}
-
-
-static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
-			  const u8 *psk, size_t psk_len)
-{
-	if (reg->new_psk_cb == NULL)
-		return 0;
-
-	return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len);
-}
-
-
-static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
-			      const struct wps_device_data *dev)
-{
-	if (reg->pin_needed_cb == NULL)
-		return;
-
-	reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
-}
-
-
-static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
-			       const u8 *uuid_e)
-{
-	if (reg->reg_success_cb == NULL)
-		return;
-
-	reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e);
-}
-
-
-static int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,
-			 struct wpabuf *probe_resp_ie)
-{
-	return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie);
-}
-
-
-static void wps_cb_set_sel_reg(struct wps_registrar *reg)
-{
-	u16 methods = 0;
-	if (reg->set_sel_reg_cb == NULL)
-		return;
-
-	if (reg->selected_registrar) {
-		methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-		if (reg->pbc)
-			methods |= WPS_CONFIG_PUSHBUTTON;
-	}
-
-	reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar,
-			    reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT,
-			    methods);
-}
-
-
-/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
-static struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
-{
-	struct wpabuf *ie;
-	const u8 *pos, *end;
-
-	ie = wpabuf_alloc(wpabuf_len(data) + 100);
-	if (ie == NULL) {
-		wpabuf_free(data);
-		return NULL;
-	}
-
-	pos = wpabuf_head(data);
-	end = pos + wpabuf_len(data);
-
-	while (end > pos) {
-		size_t frag_len = end - pos;
-		if (frag_len > 251)
-			frag_len = 251;
-		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
-		wpabuf_put_u8(ie, 4 + frag_len);
-		wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
-		wpabuf_put_data(ie, pos, frag_len);
-		pos += frag_len;
-	}
-
-	wpabuf_free(data);
-
-	return ie;
-}
-
-
-static int wps_set_ie(struct wps_registrar *reg)
-{
-	struct wpabuf *beacon;
-	struct wpabuf *probe;
-
-	if (reg->set_ie_cb == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs");
-
-	beacon = wpabuf_alloc(300);
-	if (beacon == NULL)
-		return -1;
-	probe = wpabuf_alloc(400);
-	if (probe == NULL) {
-		wpabuf_free(beacon);
-		return -1;
-	}
-
-	if (wps_build_version(beacon) ||
-	    wps_build_wps_state(reg->wps, beacon) ||
-	    wps_build_ap_setup_locked(reg->wps, beacon) ||
-	    wps_build_selected_registrar(reg, beacon) ||
-	    wps_build_sel_reg_dev_password_id(reg, beacon) ||
-	    wps_build_sel_reg_config_methods(reg, beacon) ||
-	    wps_build_version(probe) ||
-	    wps_build_wps_state(reg->wps, probe) ||
-	    wps_build_ap_setup_locked(reg->wps, probe) ||
-	    wps_build_selected_registrar(reg, probe) ||
-	    wps_build_sel_reg_dev_password_id(reg, probe) ||
-	    wps_build_sel_reg_config_methods(reg, probe) ||
-	    wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP :
-				WPS_RESP_REGISTRAR) ||
-	    wps_build_uuid_e(probe, reg->wps->uuid) ||
-	    wps_build_device_attrs(&reg->wps->dev, probe) ||
-	    wps_build_probe_config_methods(reg, probe) ||
-	    wps_build_rf_bands(&reg->wps->dev, probe)) {
-		wpabuf_free(beacon);
-		wpabuf_free(probe);
-		return -1;
-	}
-
-	beacon = wps_ie_encapsulate(beacon);
-	probe = wps_ie_encapsulate(probe);
-
-	if (!beacon || !probe) {
-		wpabuf_free(beacon);
-		wpabuf_free(probe);
-		return -1;
-	}
-
-	if (reg->static_wep_only) {
-		/*
-		 * Windows XP and Vista clients can get confused about
-		 * EAP-Identity/Request when they probe the network with
-		 * EAPOL-Start. In such a case, they may assume the network is
-		 * using IEEE 802.1X and prompt user for a certificate while
-		 * the correct (non-WPS) behavior would be to ask for the
-		 * static WEP key. As a workaround, use Microsoft Provisioning
-		 * IE to advertise that legacy 802.1X is not supported.
-		 */
-		const u8 ms_wps[7] = {
-			WLAN_EID_VENDOR_SPECIFIC, 5,
-			/* Microsoft Provisioning IE (00:50:f2:5) */
-			0x00, 0x50, 0xf2, 5,
-			0x00 /* no legacy 802.1X or MS WPS */
-		};
-		wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
-			   "into Beacon/Probe Response frames");
-		wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
-		wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
-	}
-
-	return wps_cb_set_ie(reg, beacon, probe);
-}
-
-
-static int wps_get_dev_password(struct wps_data *wps)
-{
-	const u8 *pin;
-	size_t pin_len = 0;
-
-	os_free(wps->dev_password);
-	wps->dev_password = NULL;
-
-	if (wps->pbc) {
-		wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
-		pin = (const u8 *) "00000000";
-		pin_len = 8;
-	} else {
-		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
-					    &pin_len);
-	}
-	if (pin == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
-			   "the Enrollee");
-		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
-				  &wps->peer_dev);
-		return -1;
-	}
-
-	wps->dev_password = os_malloc(pin_len);
-	if (wps->dev_password == NULL)
-		return -1;
-	os_memcpy(wps->dev_password, pin, pin_len);
-	wps->dev_password_len = pin_len;
-
-	return 0;
-}
-
-
-static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * UUID-R");
-	wpabuf_put_be16(msg, ATTR_UUID_R);
-	wpabuf_put_be16(msg, WPS_UUID_LEN);
-	wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN);
-	return 0;
-}
-
-
-static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 *hash;
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
-		return -1;
-	wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
-		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
-
-	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
-			   "R-Hash derivation");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash1");
-	wpabuf_put_be16(msg, ATTR_R_HASH1);
-	wpabuf_put_be16(msg, SHA256_MAC_LEN);
-	hash = wpabuf_put(msg, SHA256_MAC_LEN);
-	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
-	addr[0] = wps->snonce;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk1;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN);
-
-	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash2");
-	wpabuf_put_be16(msg, ATTR_R_HASH2);
-	wpabuf_put_be16(msg, SHA256_MAC_LEN);
-	hash = wpabuf_put(msg, SHA256_MAC_LEN);
-	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
-	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk2;
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN);
-
-	return 0;
-}
-
-
-static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce1");
-	wpabuf_put_be16(msg, ATTR_R_SNONCE1);
-	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
-	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
-	return 0;
-}
-
-
-static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce2");
-	wpabuf_put_be16(msg, ATTR_R_SNONCE2);
-	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
-	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
-			WPS_SECRET_NONCE_LEN);
-	return 0;
-}
-
-
-static int wps_build_cred_network_idx(struct wpabuf *msg,
-				      const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Network Index");
-	wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, 1);
-	return 0;
-}
-
-
-static int wps_build_cred_ssid(struct wpabuf *msg,
-			       const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
-	wpabuf_put_be16(msg, ATTR_SSID);
-	wpabuf_put_be16(msg, cred->ssid_len);
-	wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
-	return 0;
-}
-
-
-static int wps_build_cred_auth_type(struct wpabuf *msg,
-				    const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
-		   cred->auth_type);
-	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, cred->auth_type);
-	return 0;
-}
-
-
-static int wps_build_cred_encr_type(struct wpabuf *msg,
-				    const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
-		   cred->encr_type);
-	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, cred->encr_type);
-	return 0;
-}
-
-
-static int wps_build_cred_network_key(struct wpabuf *msg,
-				      const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%d)",
-		   (int) cred->key_len);
-	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
-	wpabuf_put_be16(msg, cred->key_len);
-	wpabuf_put_data(msg, cred->key, cred->key_len);
-	return 0;
-}
-
-
-static int wps_build_cred_mac_addr(struct wpabuf *msg,
-				   const struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
-		   MAC2STR(cred->mac_addr));
-	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
-	wpabuf_put_be16(msg, ETH_ALEN);
-	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
-	return 0;
-}
-
-
-static int wps_build_credential(struct wpabuf *msg,
-				const struct wps_credential *cred)
-{
-	if (wps_build_cred_network_idx(msg, cred) ||
-	    wps_build_cred_ssid(msg, cred) ||
-	    wps_build_cred_auth_type(msg, cred) ||
-	    wps_build_cred_encr_type(msg, cred) ||
-	    wps_build_cred_network_key(msg, cred) ||
-	    wps_build_cred_mac_addr(msg, cred))
-		return -1;
-	return 0;
-}
-
-
-int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
-{
-	struct wpabuf *cred;
-
-	if (wps->wps->registrar->skip_cred_build)
-		goto skip_cred_build;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Credential");
-	if (wps->use_cred) {
-		os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred));
-		goto use_provided;
-	}
-	os_memset(&wps->cred, 0, sizeof(wps->cred));
-
-	os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
-	wps->cred.ssid_len = wps->wps->ssid_len;
-
-	/* Select the best authentication and encryption type */
-	if (wps->auth_type & WPS_AUTH_WPA2PSK)
-		wps->auth_type = WPS_AUTH_WPA2PSK;
-	else if (wps->auth_type & WPS_AUTH_WPAPSK)
-		wps->auth_type = WPS_AUTH_WPAPSK;
-	else if (wps->auth_type & WPS_AUTH_OPEN)
-		wps->auth_type = WPS_AUTH_OPEN;
-	else if (wps->auth_type & WPS_AUTH_SHARED)
-		wps->auth_type = WPS_AUTH_SHARED;
-	else {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
-			   wps->auth_type);
-		return -1;
-	}
-	wps->cred.auth_type = wps->auth_type;
-
-	if (wps->auth_type == WPS_AUTH_WPA2PSK ||
-	    wps->auth_type == WPS_AUTH_WPAPSK) {
-		if (wps->encr_type & WPS_ENCR_AES)
-			wps->encr_type = WPS_ENCR_AES;
-		else if (wps->encr_type & WPS_ENCR_TKIP)
-			wps->encr_type = WPS_ENCR_TKIP;
-		else {
-			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
-				   "type for WPA/WPA2");
-			return -1;
-		}
-	} else {
-		if (wps->encr_type & WPS_ENCR_WEP)
-			wps->encr_type = WPS_ENCR_WEP;
-		else if (wps->encr_type & WPS_ENCR_NONE)
-			wps->encr_type = WPS_ENCR_NONE;
-		else {
-			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
-				   "type for non-WPA/WPA2 mode");
-			return -1;
-		}
-	}
-	wps->cred.encr_type = wps->encr_type;
-	/*
-	 * Set MAC address in the Credential to be the Enrollee's MAC address
-	 */
-	os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
-
-	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
-	    !wps->wps->registrar->disable_auto_conf) {
-		u8 r[16];
-		/* Generate a random passphrase */
-		if (os_get_random(r, sizeof(r)) < 0)
-			return -1;
-		os_free(wps->new_psk);
-		wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
-		if (wps->new_psk == NULL)
-			return -1;
-		wps->new_psk_len--; /* remove newline */
-		while (wps->new_psk_len &&
-		       wps->new_psk[wps->new_psk_len - 1] == '=')
-			wps->new_psk_len--;
-		wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
-				      wps->new_psk, wps->new_psk_len);
-		os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
-		wps->cred.key_len = wps->new_psk_len;
-	} else if (wps->use_psk_key && wps->wps->psk_set) {
-		char hex[65];
-		wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
-		wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
-		os_memcpy(wps->cred.key, hex, 32 * 2);
-		wps->cred.key_len = 32 * 2;
-	} else if (wps->wps->network_key) {
-		os_memcpy(wps->cred.key, wps->wps->network_key,
-			  wps->wps->network_key_len);
-		wps->cred.key_len = wps->wps->network_key_len;
-	} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
-		char hex[65];
-		/* Generate a random per-device PSK */
-		os_free(wps->new_psk);
-		wps->new_psk_len = 32;
-		wps->new_psk = os_malloc(wps->new_psk_len);
-		if (wps->new_psk == NULL)
-			return -1;
-		if (os_get_random(wps->new_psk, wps->new_psk_len) < 0) {
-			os_free(wps->new_psk);
-			wps->new_psk = NULL;
-			return -1;
-		}
-		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
-				wps->new_psk, wps->new_psk_len);
-		wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
-				 wps->new_psk_len);
-		os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
-		wps->cred.key_len = wps->new_psk_len * 2;
-	}
-
-use_provided:
-	cred = wpabuf_alloc(200);
-	if (cred == NULL)
-		return -1;
-
-	if (wps_build_credential(cred, &wps->cred)) {
-		wpabuf_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);
-
-skip_cred_build:
-	if (wps->wps->registrar->extra_cred) {
-		wpa_printf(MSG_DEBUG, "WPS:  * Credential (pre-configured)");
-		wpabuf_put_buf(msg, wps->wps->registrar->extra_cred);
-	}
-
-	return 0;
-}
-
-
-static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings");
-
-	if (wps_build_credential(msg, &wps->cred))
-		return -1;
-
-	return 0;
-}
-
-
-static struct wpabuf * wps_build_m2(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	if (os_get_random(wps->nonce_r, WPS_NONCE_LEN) < 0)
-		return NULL;
-	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
-		    wps->nonce_r, WPS_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M2");
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M2) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_uuid_r(wps, msg) ||
-	    wps_build_public_key(wps, msg) ||
-	    wps_derive_keys(wps) ||
-	    wps_build_auth_type_flags(wps, msg) ||
-	    wps_build_encr_type_flags(wps, msg) ||
-	    wps_build_conn_type_flags(wps, msg) ||
-	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
-	    wps_build_device_attrs(&wps->wps->dev, msg) ||
-	    wps_build_rf_bands(&wps->wps->dev, msg) ||
-	    wps_build_assoc_state(wps, msg) ||
-	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
-	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
-	    wps_build_os_version(&wps->wps->dev, msg) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	wps->int_reg = 1;
-	wps->state = RECV_M3;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m2d(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-	u16 err = wps->config_error;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps->wps->ap && wps->wps->ap_setup_locked &&
-	    err == WPS_CFG_NO_ERROR)
-		err = WPS_CFG_SETUP_LOCKED;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M2D) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_uuid_r(wps, msg) ||
-	    wps_build_auth_type_flags(wps, msg) ||
-	    wps_build_encr_type_flags(wps, msg) ||
-	    wps_build_conn_type_flags(wps, msg) ||
-	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
-	    wps_build_device_attrs(&wps->wps->dev, msg) ||
-	    wps_build_rf_bands(&wps->wps->dev, msg) ||
-	    wps_build_assoc_state(wps, msg) ||
-	    wps_build_config_error(msg, err) ||
-	    wps_build_os_version(&wps->wps->dev, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	wps->state = RECV_M2D_ACK;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m4(struct wps_data *wps)
-{
-	struct wpabuf *msg, *plain;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
-
-	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
-
-	plain = wpabuf_alloc(200);
-	if (plain == NULL)
-		return NULL;
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M4) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_r_hash(wps, msg) ||
-	    wps_build_r_snonce1(wps, plain) ||
-	    wps_build_key_wrap_auth(wps, plain) ||
-	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wps->state = RECV_M5;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m6(struct wps_data *wps)
-{
-	struct wpabuf *msg, *plain;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M6");
-
-	plain = wpabuf_alloc(200);
-	if (plain == NULL)
-		return NULL;
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M6) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_r_snonce2(wps, plain) ||
-	    wps_build_key_wrap_auth(wps, plain) ||
-	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wps->wps_pin_revealed = 1;
-	wps->state = RECV_M7;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_m8(struct wps_data *wps)
-{
-	struct wpabuf *msg, *plain;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
-
-	plain = wpabuf_alloc(500);
-	if (plain == NULL)
-		return NULL;
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL) {
-		wpabuf_free(plain);
-		return NULL;
-	}
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_M8) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) ||
-	    (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
-	    wps_build_key_wrap_auth(wps, plain) ||
-	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_authenticator(wps, msg)) {
-		wpabuf_free(plain);
-		wpabuf_free(msg);
-		return NULL;
-	}
-	wpabuf_free(plain);
-
-	wps->state = RECV_DONE;
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
-{
-	struct wpabuf *msg;
-
-	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
-
-	msg = wpabuf_alloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
-	    wps_build_enrollee_nonce(wps, msg) ||
-	    wps_build_registrar_nonce(wps, msg) ||
-	    wps_build_config_error(msg, wps->config_error)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-
-	return msg;
-}
-
-
-struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
-				      enum wsc_op_code *op_code)
-{
-	struct wpabuf *msg;
-
-#ifdef CONFIG_WPS_UPNP
-	if (!wps->int_reg && wps->wps->wps_upnp) {
-		struct upnp_pending_message *p, *prev = NULL;
-		if (wps->ext_reg > 1)
-			wps_registrar_free_pending_m2(wps->wps);
-		p = wps->wps->upnp_msgs;
-		/* TODO: check pending message MAC address */
-		while (p && p->next) {
-			prev = p;
-			p = p->next;
-		}
-		if (p) {
-			wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
-				   "UPnP");
-			if (prev)
-				prev->next = NULL;
-			else
-				wps->wps->upnp_msgs = NULL;
-			msg = p->msg;
-			switch (p->type) {
-			case WPS_WSC_ACK:
-				*op_code = WSC_ACK;
-				break;
-			case WPS_WSC_NACK:
-				*op_code = WSC_NACK;
-				break;
-			default:
-				*op_code = WSC_MSG;
-				break;
-			}
-			os_free(p);
-			if (wps->ext_reg == 0)
-				wps->ext_reg = 1;
-			return msg;
-		}
-	}
-	if (wps->ext_reg) {
-		wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
-			   "pending message available");
-		return NULL;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	switch (wps->state) {
-	case SEND_M2:
-		if (wps_get_dev_password(wps) < 0)
-			msg = wps_build_m2d(wps);
-		else
-			msg = wps_build_m2(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M2D:
-		msg = wps_build_m2d(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M4:
-		msg = wps_build_m4(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M6:
-		msg = wps_build_m6(wps);
-		*op_code = WSC_MSG;
-		break;
-	case SEND_M8:
-		msg = wps_build_m8(wps);
-		*op_code = WSC_MSG;
-		break;
-	case RECV_DONE:
-		msg = wps_build_wsc_ack(wps);
-		*op_code = WSC_ACK;
-		break;
-	case SEND_WSC_NACK:
-		msg = wps_build_wsc_nack(wps);
-		*op_code = WSC_NACK;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
-			   "a message", wps->state);
-		msg = NULL;
-		break;
-	}
-
-	if (*op_code == WSC_MSG && msg) {
-		/* Save a copy of the last message for Authenticator derivation
-		 */
-		wpabuf_free(wps->last_msg);
-		wps->last_msg = wpabuf_dup(msg);
-	}
-
-	return msg;
-}
-
-
-static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
-{
-	if (e_nonce == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
-		return -1;
-	}
-
-	os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
-		    wps->nonce_e, WPS_NONCE_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
-{
-	if (r_nonce == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
-		return -1;
-	}
-
-	if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)
-{
-	if (uuid_e == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No UUID-E received");
-		return -1;
-	}
-
-	os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)
-{
-	if (pw_id == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received");
-		return -1;
-	}
-
-	wps->dev_pw_id = WPA_GET_BE16(pw_id);
-	wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id);
-
-	return 0;
-}
-
-
-static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)
-{
-	if (e_hash1 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received");
-		return -1;
-	}
-
-	os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)
-{
-	if (e_hash2 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received");
-		return -1;
-	}
-
-	os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN);
-
-	return 0;
-}
-
-
-static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (e_snonce1 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received");
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1,
-			WPS_SECRET_NONCE_LEN);
-
-	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
-	addr[0] = e_snonce1;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk1;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-
-	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
-			   "not match with the pre-committed value");
-		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
-		wps_pwd_auth_fail_event(wps->wps, 0, 1);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first "
-		   "half of the device password");
-
-	return 0;
-}
-
-
-static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[4];
-	size_t len[4];
-
-	if (e_snonce2 == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received");
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2,
-			WPS_SECRET_NONCE_LEN);
-
-	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
-	addr[0] = e_snonce2;
-	len[0] = WPS_SECRET_NONCE_LEN;
-	addr[1] = wps->psk2;
-	len[1] = WPS_PSK_LEN;
-	addr[2] = wpabuf_head(wps->dh_pubkey_e);
-	len[2] = wpabuf_len(wps->dh_pubkey_e);
-	addr[3] = wpabuf_head(wps->dh_pubkey_r);
-	len[3] = wpabuf_len(wps->dh_pubkey_r);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
-
-	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
-			   "not match with the pre-committed value");
-		wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
-		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
-		wps_pwd_auth_fail_event(wps->wps, 0, 2);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second "
-		   "half of the device password");
-	wps->wps_pin_revealed = 0;
-	wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e);
-
-	return 0;
-}
-
-
-static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)
-{
-	if (mac_addr == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No MAC Address received");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR,
-		   MAC2STR(mac_addr));
-	os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN);
-	os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN);
-
-	return 0;
-}
-
-
-static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
-			      size_t pk_len)
-{
-	if (pk == NULL || pk_len == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
-		return -1;
-	}
-
-#ifdef CONFIG_WPS_OOB
-	if (wps->wps->oob_conf.pubkey_hash != NULL) {
-		const u8 *addr[1];
-		u8 hash[WPS_HASH_LEN];
-
-		addr[0] = pk;
-		sha256_vector(1, addr, &pk_len, hash);
-		if (os_memcmp(hash,
-			      wpabuf_head(wps->wps->oob_conf.pubkey_hash),
-			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
-			wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
-			return -1;
-		}
-	}
-#endif /* CONFIG_WPS_OOB */
-
-	wpabuf_free(wps->dh_pubkey_e);
-	wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
-	if (wps->dh_pubkey_e == NULL)
-		return -1;
-
-	return 0;
-}
-
-
-static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
-{
-	u16 auth_types;
-
-	if (auth == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags "
-			   "received");
-		return -1;
-	}
-
-	auth_types = WPA_GET_BE16(auth);
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
-		   auth_types);
-	wps->auth_type = wps->wps->auth_types & auth_types;
-	if (wps->auth_type == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
-			   "authentication types (own 0x%x Enrollee 0x%x)",
-			   wps->wps->auth_types, auth_types);
-#ifdef WPS_WORKAROUNDS
-		/*
-		 * Some deployed implementations seem to advertise incorrect
-		 * information in this attribute. For example, Linksys WRT350N
-		 * seems to have a byteorder bug that breaks this negotiation.
-		 * In order to interoperate with existing implementations,
-		 * assume that the Enrollee supports everything we do.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
-			   "does not advertise supported authentication types "
-			   "correctly");
-		wps->auth_type = wps->wps->auth_types;
-#else /* WPS_WORKAROUNDS */
-		return -1;
-#endif /* WPS_WORKAROUNDS */
-	}
-
-	return 0;
-}
-
-
-static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
-{
-	u16 encr_types;
-
-	if (encr == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags "
-			   "received");
-		return -1;
-	}
-
-	encr_types = WPA_GET_BE16(encr);
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x",
-		   encr_types);
-	wps->encr_type = wps->wps->encr_types & encr_types;
-	if (wps->encr_type == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
-			   "encryption types (own 0x%x Enrollee 0x%x)",
-			   wps->wps->encr_types, encr_types);
-#ifdef WPS_WORKAROUNDS
-		/*
-		 * Some deployed implementations seem to advertise incorrect
-		 * information in this attribute. For example, Linksys WRT350N
-		 * seems to have a byteorder bug that breaks this negotiation.
-		 * In order to interoperate with existing implementations,
-		 * assume that the Enrollee supports everything we do.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
-			   "does not advertise supported encryption types "
-			   "correctly");
-		wps->encr_type = wps->wps->encr_types;
-#else /* WPS_WORKAROUNDS */
-		return -1;
-#endif /* WPS_WORKAROUNDS */
-	}
-
-	return 0;
-}
-
-
-static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)
-{
-	if (conn == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags "
-			   "received");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x",
-		   *conn);
-
-	return 0;
-}
-
-
-static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)
-{
-	u16 m;
-
-	if (methods == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Config Methods received");
-		return -1;
-	}
-
-	m = WPA_GET_BE16(methods);
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x"
-		   "%s%s%s%s%s%s%s%s%s", m,
-		   m & WPS_CONFIG_USBA ? " [USBA]" : "",
-		   m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "",
-		   m & WPS_CONFIG_LABEL ? " [Label]" : "",
-		   m & WPS_CONFIG_DISPLAY ? " [Display]" : "",
-		   m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "",
-		   m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "",
-		   m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "",
-		   m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "",
-		   m & WPS_CONFIG_KEYPAD ? " [Keypad]" : "");
-
-	if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) {
-		/*
-		 * The Enrollee does not have a display so it is unlikely to be
-		 * able to show the passphrase to a user and as such, could
-		 * benefit from receiving PSK to reduce key derivation time.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to "
-			   "Enrollee not supporting display");
-		wps->use_psk_key = 1;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_wps_state(struct wps_data *wps, const u8 *state)
-{
-	if (state == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State "
-			   "received");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d",
-		   *state);
-
-	return 0;
-}
-
-
-static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
-{
-	u16 a;
-
-	if (assoc == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Association State received");
-		return -1;
-	}
-
-	a = WPA_GET_BE16(assoc);
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a);
-
-	return 0;
-}
-
-
-static int wps_process_config_error(struct wps_data *wps, const u8 *err)
-{
-	u16 e;
-
-	if (err == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received");
-		return -1;
-	}
-
-	e = WPA_GET_BE16(err);
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e);
-
-	return 0;
-}
-
-
-static enum wps_process_res wps_process_m1(struct wps_data *wps,
-					   struct wps_parse_attr *attr)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Received M1");
-
-	if (wps->state != RECV_M1) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M1", wps->state);
-		return WPS_FAILURE;
-	}
-
-	if (wps_process_uuid_e(wps, attr->uuid_e) ||
-	    wps_process_mac_addr(wps, attr->mac_addr) ||
-	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
-	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
-	    wps_process_auth_type_flags(wps, attr->auth_type_flags) ||
-	    wps_process_encr_type_flags(wps, attr->encr_type_flags) ||
-	    wps_process_conn_type_flags(wps, attr->conn_type_flags) ||
-	    wps_process_config_methods(wps, attr->config_methods) ||
-	    wps_process_wps_state(wps, attr->wps_state) ||
-	    wps_process_device_attrs(&wps->peer_dev, attr) ||
-	    wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) ||
-	    wps_process_assoc_state(wps, attr->assoc_state) ||
-	    wps_process_dev_password_id(wps, attr->dev_password_id) ||
-	    wps_process_config_error(wps, attr->config_error) ||
-	    wps_process_os_version(&wps->peer_dev, attr->os_version))
-		return WPS_FAILURE;
-
-	if (wps->dev_pw_id < 0x10 &&
-	    wps->dev_pw_id != DEV_PW_DEFAULT &&
-	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
-	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
-	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
-	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
-	     !wps->wps->registrar->pbc)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
-			   wps->dev_pw_id);
-		wps->state = SEND_M2D;
-		return WPS_CONTINUE;
-	}
-
-#ifdef CONFIG_WPS_OOB
-	if (wps->dev_pw_id >= 0x10 &&
-	    wps->dev_pw_id != wps->wps->oob_dev_pw_id) {
-		wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID "
-			   "%d mismatch", wps->dev_pw_id);
-		wps->state = SEND_M2D;
-		return WPS_CONTINUE;
-	}
-#endif /* CONFIG_WPS_OOB */
-
-	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
-		if (wps->wps->registrar->force_pbc_overlap ||
-		    wps_registrar_pbc_overlap(wps->wps->registrar,
-					      wps->mac_addr_e, wps->uuid_e)) {
-			wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
-				   "negotiation");
-			wps->state = SEND_M2D;
-			wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
-			wps_pbc_overlap_event(wps->wps);
-			wps->wps->registrar->force_pbc_overlap = 1;
-			return WPS_CONTINUE;
-		}
-		wps_registrar_add_pbc_session(wps->wps->registrar,
-					      wps->mac_addr_e, wps->uuid_e);
-		wps->pbc = 1;
-	}
-
-#ifdef WPS_WORKAROUNDS
-	/*
-	 * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in
-	 * passphrase format. To avoid interop issues, force PSK format to be
-	 * used.
-	 */
-	if (!wps->use_psk_key &&
-	    wps->peer_dev.manufacturer &&
-	    os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 &&
-	    wps->peer_dev.model_name &&
-	    os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in "
-			   "PSK format");
-		wps->use_psk_key = 1;
-	}
-#endif /* WPS_WORKAROUNDS */
-
-	wps->state = SEND_M2;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m3(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Received M3");
-
-	if (wps->state != RECV_M3) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M3", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
-		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
-			   "session overlap");
-		wps->state = SEND_WSC_NACK;
-		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg) ||
-	    wps_process_e_hash1(wps, attr->e_hash1) ||
-	    wps_process_e_hash2(wps, attr->e_hash2)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wps->state = SEND_M4;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_m5(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	struct wpabuf *decrypted;
-	struct wps_parse_attr eattr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received M5");
-
-	if (wps->state != RECV_M5) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M5", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
-		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
-			   "session overlap");
-		wps->state = SEND_WSC_NACK;
-		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
-					      attr->encr_settings_len);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
-			   "Settings attribute");
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
-		   "attribute");
-	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);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-	wpabuf_free(decrypted);
-
-	wps->state = SEND_M6;
-	return WPS_CONTINUE;
-}
-
-
-static void wps_sta_cred_cb(struct wps_data *wps)
-{
-	/*
-	 * Update credential to only include a single authentication and
-	 * encryption type in case the AP configuration includes more than one
-	 * option.
-	 */
-	if (wps->cred.auth_type & WPS_AUTH_WPA2PSK)
-		wps->cred.auth_type = WPS_AUTH_WPA2PSK;
-	else if (wps->cred.auth_type & WPS_AUTH_WPAPSK)
-		wps->cred.auth_type = WPS_AUTH_WPAPSK;
-	if (wps->cred.encr_type & WPS_ENCR_AES)
-		wps->cred.encr_type = WPS_ENCR_AES;
-	else if (wps->cred.encr_type & WPS_ENCR_TKIP)
-		wps->cred.encr_type = WPS_ENCR_TKIP;
-	wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the "
-		   "AP configuration");
-	if (wps->wps->cred_cb)
-		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
-}
-
-
-static void wps_cred_update(struct wps_credential *dst,
-			    struct wps_credential *src)
-{
-	os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
-	dst->ssid_len = src->ssid_len;
-	dst->auth_type = src->auth_type;
-	dst->encr_type = src->encr_type;
-	dst->key_idx = src->key_idx;
-	os_memcpy(dst->key, src->key, sizeof(dst->key));
-	dst->key_len = src->key_len;
-}
-
-
-static int wps_process_ap_settings_r(struct wps_data *wps,
-				     struct wps_parse_attr *attr)
-{
-	if (wps->wps->ap || wps->er)
-		return 0;
-
-	/* AP Settings Attributes in M7 when Enrollee is an AP */
-	if (wps_process_ap_settings(attr, &wps->cred) < 0)
-		return -1;
-
-	wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
-
-	if (wps->new_ap_settings) {
-		wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
-			   "new settings");
-		wps_cred_update(&wps->cred, wps->new_ap_settings);
-		return 0;
-	} else {
-		/*
-		 * Use the AP PIN only to receive the current AP settings, not
-		 * to reconfigure the AP.
-		 */
-		if (wps->ap_settings_cb) {
-			wps->ap_settings_cb(wps->ap_settings_cb_ctx,
-					    &wps->cred);
-			return 1;
-		}
-		wps_sta_cred_cb(wps);
-		return 1;
-	}
-}
-
-
-static enum wps_process_res wps_process_m7(struct wps_data *wps,
-					   const struct wpabuf *msg,
-					   struct wps_parse_attr *attr)
-{
-	struct wpabuf *decrypted;
-	struct wps_parse_attr eattr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received M7");
-
-	if (wps->state != RECV_M7) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving M7", wps->state);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
-		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
-			   "session overlap");
-		wps->state = SEND_WSC_NACK;
-		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
-		return WPS_CONTINUE;
-	}
-
-	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
-	    wps_process_authenticator(wps, attr->authenticator, msg)) {
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
-					      attr->encr_settings_len);
-	if (decrypted == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted "
-			   "Settings attribute");
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
-		   "attribute");
-	if (wps_parse_msg(decrypted, &eattr) < 0 ||
-	    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);
-		wps->state = SEND_WSC_NACK;
-		return WPS_CONTINUE;
-	}
-
-	wpabuf_free(decrypted);
-
-	wps->state = SEND_M8;
-	return WPS_CONTINUE;
-}
-
-
-static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
-						const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-	enum wps_process_res ret = WPS_CONTINUE;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_M1 &&
-	    (attr.registrar_nonce == NULL ||
-	     os_memcmp(wps->nonce_r, attr.registrar_nonce,
-		       WPS_NONCE_LEN != 0))) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		return WPS_FAILURE;
-	}
-
-	switch (*attr.msg_type) {
-	case WPS_M1:
-#ifdef CONFIG_WPS_UPNP
-		if (wps->wps->wps_upnp && attr.mac_addr) {
-			/* Remove old pending messages when starting new run */
-			wps_free_pending_msgs(wps->wps->upnp_msgs);
-			wps->wps->upnp_msgs = NULL;
-
-			upnp_wps_device_send_wlan_event(
-				wps->wps->wps_upnp, attr.mac_addr,
-				UPNP_WPS_WLANEVENT_TYPE_EAP, msg);
-		}
-#endif /* CONFIG_WPS_UPNP */
-		ret = wps_process_m1(wps, &attr);
-		break;
-	case WPS_M3:
-		ret = wps_process_m3(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M3);
-		break;
-	case WPS_M5:
-		ret = wps_process_m5(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M5);
-		break;
-	case WPS_M7:
-		ret = wps_process_m7(wps, msg, &attr);
-		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
-			wps_fail_event(wps->wps, WPS_M7);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-	if (ret == WPS_CONTINUE) {
-		/* Save a copy of the last message for Authenticator derivation
-		 */
-		wpabuf_free(wps->last_msg);
-		wps->last_msg = wpabuf_dup(msg);
-	}
-
-	return ret;
-}
-
-
-static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
-						const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_WSC_ACK) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-#ifdef CONFIG_WPS_UPNP
-	if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
-	    upnp_wps_subscribers(wps->wps->wps_upnp)) {
-		if (wps->wps->upnp_msgs)
-			return WPS_CONTINUE;
-		wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
-			   "external Registrar");
-		return WPS_PENDING;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	if (attr.registrar_nonce == NULL ||
-	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
-	{
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		return WPS_FAILURE;
-	}
-
-	if (wps->state == RECV_M2D_ACK) {
-#ifdef CONFIG_WPS_UPNP
-		if (wps->wps->wps_upnp &&
-		    upnp_wps_subscribers(wps->wps->wps_upnp)) {
-			if (wps->wps->upnp_msgs)
-				return WPS_CONTINUE;
-			if (wps->ext_reg == 0)
-				wps->ext_reg = 1;
-			wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
-				   "external Registrar");
-			return WPS_PENDING;
-		}
-#endif /* CONFIG_WPS_UPNP */
-
-		wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
-			   "terminate negotiation");
-	}
-
-	return WPS_FAILURE;
-}
-
-
-static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
-						 const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-	int old_state;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
-
-	old_state = wps->state;
-	wps->state = SEND_WSC_NACK;
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_WSC_NACK) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-#ifdef CONFIG_WPS_UPNP
-	if (wps->wps->wps_upnp && wps->ext_reg) {
-		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
-			   "Registrar terminated by the Enrollee");
-		return WPS_FAILURE;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	if (attr.registrar_nonce == NULL ||
-	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
-	{
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.config_error == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
-			   "in WSC_NACK");
-		return WPS_FAILURE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
-		   "Configuration Error %d", WPA_GET_BE16(attr.config_error));
-
-	switch (old_state) {
-	case RECV_M3:
-		wps_fail_event(wps->wps, WPS_M2);
-		break;
-	case RECV_M5:
-		wps_fail_event(wps->wps, WPS_M4);
-		break;
-	case RECV_M7:
-		wps_fail_event(wps->wps, WPS_M6);
-		break;
-	case RECV_DONE:
-		wps_fail_event(wps->wps, WPS_M8);
-		break;
-	default:
-		break;
-	}
-
-	return WPS_FAILURE;
-}
-
-
-static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
-						 const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
-
-	if (wps->state != RECV_DONE &&
-	    (!wps->wps->wps_upnp || !wps->ext_reg)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
-			   "receiving WSC_Done", wps->state);
-		return WPS_FAILURE;
-	}
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return WPS_FAILURE;
-
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
-			   attr.version ? *attr.version : 0);
-		return WPS_FAILURE;
-	}
-
-	if (attr.msg_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
-		return WPS_FAILURE;
-	}
-
-	if (*attr.msg_type != WPS_WSC_DONE) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
-			   *attr.msg_type);
-		return WPS_FAILURE;
-	}
-
-#ifdef CONFIG_WPS_UPNP
-	if (wps->wps->wps_upnp && wps->ext_reg) {
-		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
-			   "Registrar completed successfully");
-		wps_device_store(wps->wps->registrar, &wps->peer_dev,
-				 wps->uuid_e);
-		return WPS_DONE;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	if (attr.registrar_nonce == NULL ||
-	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
-	{
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
-		return WPS_FAILURE;
-	}
-
-	if (attr.enrollee_nonce == NULL ||
-	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
-		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
-		return WPS_FAILURE;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
-	wps_device_store(wps->wps->registrar, &wps->peer_dev,
-			 wps->uuid_e);
-
-	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
-	    wps->wps->ap && !wps->wps->registrar->disable_auto_conf) {
-		struct wps_credential cred;
-
-		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
-			   "on first Enrollee connection");
-
-		os_memset(&cred, 0, sizeof(cred));
-		os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
-		cred.ssid_len = wps->wps->ssid_len;
-		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
-		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
-		os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
-		cred.key_len = wps->new_psk_len;
-
-		wps->wps->wps_state = WPS_STATE_CONFIGURED;
-		wpa_hexdump_ascii_key(MSG_DEBUG,
-				      "WPS: Generated random passphrase",
-				      wps->new_psk, wps->new_psk_len);
-		if (wps->wps->cred_cb)
-			wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
-
-		os_free(wps->new_psk);
-		wps->new_psk = NULL;
-	}
-
-	if (!wps->wps->ap && !wps->er)
-		wps_sta_cred_cb(wps);
-
-	if (wps->new_psk) {
-		if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
-				   wps->new_psk, wps->new_psk_len)) {
-			wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
-				   "new PSK");
-		}
-		os_free(wps->new_psk);
-		wps->new_psk = NULL;
-	}
-
-	wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
-
-	if (wps->pbc) {
-		wps_registrar_remove_pbc_session(wps->wps->registrar,
-						 wps->mac_addr_e, wps->uuid_e);
-		wps_registrar_pbc_completed(wps->wps->registrar);
-	} else {
-		wps_registrar_pin_completed(wps->wps->registrar);
-	}
-
-	wps_success_event(wps->wps);
-
-	return WPS_DONE;
-}
-
-
-enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
-					       enum wsc_op_code op_code,
-					       const struct wpabuf *msg)
-{
-	enum wps_process_res ret;
-
-	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
-		   "op_code=%d)",
-		   (unsigned long) wpabuf_len(msg), op_code);
-
-#ifdef CONFIG_WPS_UPNP
-	if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
-		struct wps_parse_attr attr;
-		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
-		    *attr.msg_type == WPS_M3)
-			wps->ext_reg = 2; /* past M2/M2D phase */
-	}
-	if (wps->ext_reg > 1)
-		wps_registrar_free_pending_m2(wps->wps);
-	if (wps->wps->wps_upnp && wps->ext_reg &&
-	    wps->wps->upnp_msgs == NULL &&
-	    (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK))
-	{
-		struct wps_parse_attr attr;
-		int type;
-		if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
-			type = -1;
-		else
-			type = *attr.msg_type;
-		wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)"
-			   " to external Registrar for processing", type);
-		upnp_wps_device_send_wlan_event(wps->wps->wps_upnp,
-						wps->mac_addr_e,
-						UPNP_WPS_WLANEVENT_TYPE_EAP,
-						msg);
-		if (op_code == WSC_MSG)
-			return WPS_PENDING;
-	} else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) {
-		wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using "
-			   "external Registrar");
-		return WPS_CONTINUE;
-	}
-#endif /* CONFIG_WPS_UPNP */
-
-	switch (op_code) {
-	case WSC_MSG:
-		return wps_process_wsc_msg(wps, msg);
-	case WSC_ACK:
-		return wps_process_wsc_ack(wps, msg);
-	case WSC_NACK:
-		return wps_process_wsc_nack(wps, msg);
-	case WSC_Done:
-		ret = wps_process_wsc_done(wps, msg);
-		if (ret == WPS_FAILURE) {
-			wps->state = SEND_WSC_NACK;
-			wps_fail_event(wps->wps, WPS_WSC_DONE);
-		}
-		return ret;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
-		return WPS_FAILURE;
-	}
-}
-
-
-int wps_registrar_update_ie(struct wps_registrar *reg)
-{
-	return wps_set_ie(reg);
-}
-
-
-static void wps_registrar_set_selected_timeout(void *eloop_ctx,
-					       void *timeout_ctx)
-{
-	struct wps_registrar *reg = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - "
-		   "unselect internal Registrar");
-	reg->selected_registrar = 0;
-	reg->pbc = 0;
-	wps_registrar_selected_registrar_changed(reg);
-}
-
-
-#ifdef CONFIG_WPS_UPNP
-static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
-				      struct subscription *s)
-{
-	wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
-		   "config_methods=0x%x)",
-		   s->dev_password_id, s->config_methods);
-	reg->sel_reg_union = 1;
-	if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON)
-		reg->sel_reg_dev_password_id_override = s->dev_password_id;
-	if (reg->sel_reg_config_methods_override == -1)
-		reg->sel_reg_config_methods_override = 0;
-	reg->sel_reg_config_methods_override |= s->config_methods;
-}
-#endif /* CONFIG_WPS_UPNP */
-
-
-static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
-{
-#ifdef CONFIG_WPS_UPNP
-	struct subscription *s;
-
-	if (reg->wps->wps_upnp == NULL)
-		return;
-
-	dl_list_for_each(s, &reg->wps->wps_upnp->subscriptions,
-			 struct subscription, list) {
-		struct subscr_addr *sa;
-		sa = dl_list_first(&s->addr_list, struct subscr_addr, list);
-		if (sa) {
-			wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d",
-				   inet_ntoa(sa->saddr.sin_addr),
-				   ntohs(sa->saddr.sin_port));
-		}
-		if (s->selected_registrar)
-			wps_registrar_sel_reg_add(reg, s);
-		else
-			wpa_printf(MSG_DEBUG, "WPS: External Registrar not "
-				   "selected");
-	}
-#endif /* CONFIG_WPS_UPNP */
-}
-
-
-/**
- * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change
- * @reg: Registrar data from wps_registrar_init()
- *
- * This function is called when selected registrar state changes, e.g., when an
- * AP receives a SetSelectedRegistrar UPnP message.
- */
-void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
-
-	reg->sel_reg_union = reg->selected_registrar;
-	reg->sel_reg_dev_password_id_override = -1;
-	reg->sel_reg_config_methods_override = -1;
-	if (reg->selected_registrar) {
-		reg->sel_reg_config_methods_override =
-			reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-		if (reg->pbc) {
-			reg->sel_reg_dev_password_id_override =
-				DEV_PW_PUSHBUTTON;
-			reg->sel_reg_config_methods_override |=
-				WPS_CONFIG_PUSHBUTTON;
-		}
-		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
-			   "(pbc=%d)", reg->pbc);
-	} else
-		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
-
-	wps_registrar_sel_reg_union(reg);
-
-	wps_set_ie(reg);
-	wps_cb_set_sel_reg(reg);
-}
-
-
-int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
-			   char *buf, size_t buflen)
-{
-	struct wps_registrar_device *d;
-	int len = 0, ret;
-	char uuid[40];
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-
-	d = wps_device_get(reg, addr);
-	if (d == NULL)
-		return 0;
-	if (uuid_bin2str(d->uuid, uuid, sizeof(uuid)))
-		return 0;
-
-	ret = os_snprintf(buf + len, buflen - len,
-			  "wpsUuid=%s\n"
-			  "wpsPrimaryDeviceType=%s\n"
-			  "wpsDeviceName=%s\n"
-			  "wpsManufacturer=%s\n"
-			  "wpsModelName=%s\n"
-			  "wpsModelNumber=%s\n"
-			  "wpsSerialNumber=%s\n",
-			  uuid,
-			  wps_dev_type_bin2str(d->dev.pri_dev_type, devtype,
-					       sizeof(devtype)),
-			  d->dev.device_name ? d->dev.device_name : "",
-			  d->dev.manufacturer ? d->dev.manufacturer : "",
-			  d->dev.model_name ? d->dev.model_name : "",
-			  d->dev.model_number ? d->dev.model_number : "",
-			  d->dev.serial_number ? d->dev.serial_number : "");
-	if (ret < 0 || (size_t) ret >= buflen - len)
-		return len;
-	len += ret;
-
-	return len;
-}

Copied: vendor/wpa/2.0/src/wps/wps_registrar.c (from rev 9639, vendor/wpa/dist/src/wps/wps_registrar.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_registrar.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_registrar.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3552 @@
+/*
+ * Wi-Fi Protected Setup - Registrar
+ * Copyright (c) 2008-2012, Jouni Malinen <j at 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 "utils/base64.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "utils/list.h"
+#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+#ifndef CONFIG_WPS_STRICT
+#define WPS_WORKAROUNDS
+#endif /* CONFIG_WPS_STRICT */
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_pw_token {
+	struct dl_list list;
+	u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+	u16 pw_id;
+	u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+	size_t dev_pw_len;
+};
+
+
+static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
+{
+	dl_list_del(&token->list);
+	os_free(token);
+}
+
+
+static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)
+{
+	struct wps_nfc_pw_token *token, *prev;
+	dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token,
+			      list) {
+		if (pw_id == 0 || pw_id == token->pw_id)
+			wps_remove_nfc_pw_token(token);
+	}
+}
+
+
+static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,
+						      u16 pw_id)
+{
+	struct wps_nfc_pw_token *token;
+	dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) {
+		if (pw_id == token->pw_id)
+			return token;
+	}
+	return NULL;
+}
+
+#else /* CONFIG_WPS_NFC */
+
+#define wps_free_nfc_pw_tokens(t, p) do { } while (0)
+
+#endif /* CONFIG_WPS_NFC */
+
+
+struct wps_uuid_pin {
+	struct dl_list list;
+	u8 uuid[WPS_UUID_LEN];
+	int wildcard_uuid;
+	u8 *pin;
+	size_t pin_len;
+#define PIN_LOCKED BIT(0)
+#define PIN_EXPIRES BIT(1)
+	int flags;
+	struct os_time expiration;
+	u8 enrollee_addr[ETH_ALEN];
+};
+
+
+static void wps_free_pin(struct wps_uuid_pin *pin)
+{
+	os_free(pin->pin);
+	os_free(pin);
+}
+
+
+static void wps_remove_pin(struct wps_uuid_pin *pin)
+{
+	dl_list_del(&pin->list);
+	wps_free_pin(pin);
+}
+
+
+static void wps_free_pins(struct dl_list *pins)
+{
+	struct wps_uuid_pin *pin, *prev;
+	dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list)
+		wps_remove_pin(pin);
+}
+
+
+struct wps_pbc_session {
+	struct wps_pbc_session *next;
+	u8 addr[ETH_ALEN];
+	u8 uuid_e[WPS_UUID_LEN];
+	struct os_time timestamp;
+};
+
+
+static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)
+{
+	struct wps_pbc_session *prev;
+
+	while (pbc) {
+		prev = pbc;
+		pbc = pbc->next;
+		os_free(prev);
+	}
+}
+
+
+struct wps_registrar_device {
+	struct wps_registrar_device *next;
+	struct wps_device_data dev;
+	u8 uuid[WPS_UUID_LEN];
+};
+
+
+struct wps_registrar {
+	struct wps_context *wps;
+
+	int pbc;
+	int selected_registrar;
+
+	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
+			  size_t psk_len);
+	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
+			 struct wpabuf *probe_resp_ie);
+	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
+			      const struct wps_device_data *dev);
+	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
+			       const u8 *uuid_e, const u8 *dev_pw,
+			       size_t dev_pw_len);
+	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
+			       u16 sel_reg_config_methods);
+	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
+				 const u8 *pri_dev_type, u16 config_methods,
+				 u16 dev_password_id, u8 request_type,
+				 const char *dev_name);
+	void *cb_ctx;
+
+	struct dl_list pins;
+	struct dl_list nfc_pw_tokens;
+	struct wps_pbc_session *pbc_sessions;
+
+	int skip_cred_build;
+	struct wpabuf *extra_cred;
+	int disable_auto_conf;
+	int sel_reg_union;
+	int sel_reg_dev_password_id_override;
+	int sel_reg_config_methods_override;
+	int static_wep_only;
+	int dualband;
+
+	struct wps_registrar_device *devices;
+
+	int force_pbc_overlap;
+
+	u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+	u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+
+	u8 p2p_dev_addr[ETH_ALEN];
+
+	u8 pbc_ignore_uuid[WPS_UUID_LEN];
+	struct os_time pbc_ignore_start;
+};
+
+
+static int wps_set_ie(struct wps_registrar *reg);
+static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wps_registrar_set_selected_timeout(void *eloop_ctx,
+					       void *timeout_ctx);
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+				     struct wps_uuid_pin *pin);
+
+
+static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
+					     const u8 *addr)
+{
+	int i;
+	wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR,
+		   MAC2STR(addr));
+	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+		if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was "
+				   "already in the list");
+			return; /* already in list */
+		}
+	for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
+		os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
+			  ETH_ALEN);
+	os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
+		    (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
+}
+
+
+static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
+						const u8 *addr)
+{
+	int i;
+	wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR,
+		   MAC2STR(addr));
+	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
+		if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0)
+			break;
+	}
+	if (i == WPS_MAX_AUTHORIZED_MACS) {
+		wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the "
+			   "list");
+		return; /* not in the list */
+	}
+	for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
+		os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
+			  ETH_ALEN);
+	os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
+		  ETH_ALEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
+		    (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
+}
+
+
+static void wps_free_devices(struct wps_registrar_device *dev)
+{
+	struct wps_registrar_device *prev;
+
+	while (dev) {
+		prev = dev;
+		dev = dev->next;
+		wps_device_data_free(&prev->dev);
+		os_free(prev);
+	}
+}
+
+
+static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,
+						    const u8 *addr)
+{
+	struct wps_registrar_device *dev;
+
+	for (dev = reg->devices; dev; dev = dev->next) {
+		if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0)
+			return dev;
+	}
+	return NULL;
+}
+
+
+static void wps_device_clone_data(struct wps_device_data *dst,
+				  struct wps_device_data *src)
+{
+	os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
+	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
+
+#define WPS_STRDUP(n) \
+	os_free(dst->n); \
+	dst->n = src->n ? os_strdup(src->n) : NULL
+
+	WPS_STRDUP(device_name);
+	WPS_STRDUP(manufacturer);
+	WPS_STRDUP(model_name);
+	WPS_STRDUP(model_number);
+	WPS_STRDUP(serial_number);
+#undef WPS_STRDUP
+}
+
+
+int wps_device_store(struct wps_registrar *reg,
+		     struct wps_device_data *dev, const u8 *uuid)
+{
+	struct wps_registrar_device *d;
+
+	d = wps_device_get(reg, dev->mac_addr);
+	if (d == NULL) {
+		d = os_zalloc(sizeof(*d));
+		if (d == NULL)
+			return -1;
+		d->next = reg->devices;
+		reg->devices = d;
+	}
+
+	wps_device_clone_data(&d->dev, dev);
+	os_memcpy(d->uuid, uuid, WPS_UUID_LEN);
+
+	return 0;
+}
+
+
+static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
+					  const u8 *addr, const u8 *uuid_e)
+{
+	struct wps_pbc_session *pbc, *prev = NULL;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	pbc = reg->pbc_sessions;
+	while (pbc) {
+		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
+		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+			if (prev)
+				prev->next = pbc->next;
+			else
+				reg->pbc_sessions = pbc->next;
+			break;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+
+	if (!pbc) {
+		pbc = os_zalloc(sizeof(*pbc));
+		if (pbc == NULL)
+			return;
+		os_memcpy(pbc->addr, addr, ETH_ALEN);
+		if (uuid_e)
+			os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN);
+	}
+
+	pbc->next = reg->pbc_sessions;
+	reg->pbc_sessions = pbc;
+	pbc->timestamp = now;
+
+	/* remove entries that have timed out */
+	prev = pbc;
+	pbc = pbc->next;
+
+	while (pbc) {
+		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+			prev->next = NULL;
+			wps_free_pbc_sessions(pbc);
+			break;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+}
+
+
+static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
+					     const u8 *uuid_e,
+					     const u8 *p2p_dev_addr)
+{
+	struct wps_pbc_session *pbc, *prev = NULL, *tmp;
+
+	pbc = reg->pbc_sessions;
+	while (pbc) {
+		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
+		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
+		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+		     0)) {
+			if (prev)
+				prev->next = pbc->next;
+			else
+				reg->pbc_sessions = pbc->next;
+			tmp = pbc;
+			pbc = pbc->next;
+			wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for "
+				   "addr=" MACSTR, MAC2STR(tmp->addr));
+			wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E",
+				    tmp->uuid_e, WPS_UUID_LEN);
+			os_free(tmp);
+			continue;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+}
+
+
+int wps_registrar_pbc_overlap(struct wps_registrar *reg,
+			      const u8 *addr, const u8 *uuid_e)
+{
+	int count = 0;
+	struct wps_pbc_session *pbc;
+	struct wps_pbc_session *first = NULL;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
+
+	if (uuid_e) {
+		wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID");
+		wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID",
+			    uuid_e, WPS_UUID_LEN);
+		count++;
+	}
+
+	for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
+		wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR,
+			   MAC2STR(pbc->addr));
+		wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
+			    pbc->uuid_e, WPS_UUID_LEN);
+		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+			wpa_printf(MSG_DEBUG, "WPS: PBC walk time has "
+				   "expired");
+			break;
+		}
+		if (first &&
+		    os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Same Enrollee");
+			continue; /* same Enrollee */
+		}
+		if (uuid_e == NULL ||
+		    os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) {
+			wpa_printf(MSG_DEBUG, "WPS: New Enrollee");
+			count++;
+		}
+		if (first == NULL)
+			first = pbc;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count);
+
+	return count > 1 ? 1 : 0;
+}
+
+
+static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
+		   wps->wps_state);
+	wpabuf_put_be16(msg, ATTR_WPS_STATE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, wps->wps_state);
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+static void wps_registrar_free_pending_m2(struct wps_context *wps)
+{
+	struct upnp_pending_message *p, *p2, *prev = NULL;
+	p = wps->upnp_msgs;
+	while (p) {
+		if (p->type == WPS_M2 || p->type == WPS_M2D) {
+			if (prev == NULL)
+				wps->upnp_msgs = p->next;
+			else
+				prev->next = p->next;
+			wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
+			p2 = p;
+			p = p->next;
+			wpabuf_free(p2->msg);
+			os_free(p2);
+			continue;
+		}
+		prev = p;
+		p = p->next;
+	}
+}
+#endif /* CONFIG_WPS_UPNP */
+
+
+static int wps_build_ap_setup_locked(struct wps_context *wps,
+				     struct wpabuf *msg)
+{
+	if (wps->ap_setup_locked && wps->ap_setup_locked != 2) {
+		wpa_printf(MSG_DEBUG, "WPS:  * AP Setup Locked");
+		wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, 1);
+	}
+	return 0;
+}
+
+
+static int wps_build_selected_registrar(struct wps_registrar *reg,
+					struct wpabuf *msg)
+{
+	if (!reg->sel_reg_union)
+		return 0;
+	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar");
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, 1);
+	return 0;
+}
+
+
+static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
+					     struct wpabuf *msg)
+{
+	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
+	if (!reg->sel_reg_union)
+		return 0;
+	if (reg->sel_reg_dev_password_id_override >= 0)
+		id = reg->sel_reg_dev_password_id_override;
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, id);
+	return 0;
+}
+
+
+static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,
+					struct wpabuf *msg)
+{
+	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
+	if (!reg->sel_reg_union)
+		return 0;
+	if (reg->sel_reg_dev_password_id_override >= 0)
+		id = reg->sel_reg_dev_password_id_override;
+	if (id != DEV_PW_PUSHBUTTON || !reg->dualband)
+		return 0;
+	return wps_build_uuid_e(msg, reg->wps->uuid);
+}
+
+
+static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
+{
+	*methods |= WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+	if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
+	    WPS_CONFIG_VIRT_PUSHBUTTON)
+		*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+	if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) ==
+	    WPS_CONFIG_PHY_PUSHBUTTON)
+		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+	if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
+	    WPS_CONFIG_VIRT_PUSHBUTTON &&
+	    (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
+	    WPS_CONFIG_PHY_PUSHBUTTON) {
+		/*
+		 * Required to include virtual/physical flag, but we were not
+		 * configured with push button type, so have to default to one
+		 * of them.
+		 */
+		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
+	}
+#endif /* CONFIG_WPS2 */
+}
+
+
+static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
+					    struct wpabuf *msg)
+{
+	u16 methods;
+	if (!reg->sel_reg_union)
+		return 0;
+	methods = reg->wps->config_methods;
+	methods &= ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+		     WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+	if (reg->pbc)
+		wps_set_pushbutton(&methods, reg->wps->config_methods);
+	if (reg->sel_reg_config_methods_override >= 0)
+		methods = reg->sel_reg_config_methods_override;
+	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar Config Methods (%x)",
+		   methods);
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+static int wps_build_probe_config_methods(struct wps_registrar *reg,
+					  struct wpabuf *msg)
+{
+	u16 methods;
+	/*
+	 * These are the methods that the AP supports as an Enrollee for adding
+	 * external Registrars.
+	 */
+	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+		     WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
+	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+static int wps_build_config_methods_r(struct wps_registrar *reg,
+				      struct wpabuf *msg)
+{
+	return wps_build_config_methods(msg, reg->wps->config_methods);
+}
+
+
+const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
+{
+	*count = 0;
+
+#ifdef CONFIG_WPS2
+	while (*count < WPS_MAX_AUTHORIZED_MACS) {
+		if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
+			break;
+		(*count)++;
+	}
+#endif /* CONFIG_WPS2 */
+
+	return (const u8 *) reg->authorized_macs_union;
+}
+
+
+/**
+ * wps_registrar_init - Initialize WPS Registrar data
+ * @wps: Pointer to longterm WPS context
+ * @cfg: Registrar configuration
+ * Returns: Pointer to allocated Registrar data or %NULL on failure
+ *
+ * This function is used to initialize WPS Registrar functionality. It can be
+ * used for a single Registrar run (e.g., when run in a supplicant) or multiple
+ * runs (e.g., when run as an internal Registrar in an AP). Caller is
+ * responsible for freeing the returned data with wps_registrar_deinit() when
+ * Registrar functionality is not needed anymore.
+ */
+struct wps_registrar *
+wps_registrar_init(struct wps_context *wps,
+		   const struct wps_registrar_config *cfg)
+{
+	struct wps_registrar *reg = os_zalloc(sizeof(*reg));
+	if (reg == NULL)
+		return NULL;
+
+	dl_list_init(&reg->pins);
+	dl_list_init(&reg->nfc_pw_tokens);
+	reg->wps = wps;
+	reg->new_psk_cb = cfg->new_psk_cb;
+	reg->set_ie_cb = cfg->set_ie_cb;
+	reg->pin_needed_cb = cfg->pin_needed_cb;
+	reg->reg_success_cb = cfg->reg_success_cb;
+	reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
+	reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
+	reg->cb_ctx = cfg->cb_ctx;
+	reg->skip_cred_build = cfg->skip_cred_build;
+	if (cfg->extra_cred) {
+		reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred,
+						    cfg->extra_cred_len);
+		if (reg->extra_cred == NULL) {
+			os_free(reg);
+			return NULL;
+		}
+	}
+	reg->disable_auto_conf = cfg->disable_auto_conf;
+	reg->sel_reg_dev_password_id_override = -1;
+	reg->sel_reg_config_methods_override = -1;
+	reg->static_wep_only = cfg->static_wep_only;
+	reg->dualband = cfg->dualband;
+
+	if (wps_set_ie(reg)) {
+		wps_registrar_deinit(reg);
+		return NULL;
+	}
+
+	return reg;
+}
+
+
+/**
+ * wps_registrar_deinit - Deinitialize WPS Registrar data
+ * @reg: Registrar data from wps_registrar_init()
+ */
+void wps_registrar_deinit(struct wps_registrar *reg)
+{
+	if (reg == NULL)
+		return;
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+	wps_free_pins(&reg->pins);
+	wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
+	wps_free_pbc_sessions(reg->pbc_sessions);
+	wpabuf_free(reg->extra_cred);
+	wps_free_devices(reg->devices);
+	os_free(reg);
+}
+
+
+static void wps_registrar_invalidate_unused(struct wps_registrar *reg)
+{
+	struct wps_uuid_pin *pin;
+
+	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
+		if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalidate previously "
+				   "configured wildcard PIN");
+			wps_registrar_remove_pin(reg, pin);
+			break;
+		}
+	}
+}
+
+
+/**
+ * wps_registrar_add_pin - Configure a new PIN for Registrar
+ * @reg: Registrar data from wps_registrar_init()
+ * @addr: Enrollee MAC address or %NULL if not known
+ * @uuid: UUID-E or %NULL for wildcard (any UUID)
+ * @pin: PIN (Device Password)
+ * @pin_len: Length of pin in octets
+ * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
+ * Returns: 0 on success, -1 on failure
+ */
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+			  const u8 *uuid, const u8 *pin, size_t pin_len,
+			  int timeout)
+{
+	struct wps_uuid_pin *p;
+
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	if (addr)
+		os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
+	if (uuid == NULL)
+		p->wildcard_uuid = 1;
+	else
+		os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
+	p->pin = os_malloc(pin_len);
+	if (p->pin == NULL) {
+		os_free(p);
+		return -1;
+	}
+	os_memcpy(p->pin, pin, pin_len);
+	p->pin_len = pin_len;
+
+	if (timeout) {
+		p->flags |= PIN_EXPIRES;
+		os_get_time(&p->expiration);
+		p->expiration.sec += timeout;
+	}
+
+	if (p->wildcard_uuid)
+		wps_registrar_invalidate_unused(reg);
+
+	dl_list_add(&reg->pins, &p->list);
+
+	wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
+		   timeout);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
+	reg->selected_registrar = 1;
+	reg->pbc = 0;
+	if (addr)
+		wps_registrar_add_authorized_mac(reg, addr);
+	else
+		wps_registrar_add_authorized_mac(
+			reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
+	wps_registrar_selected_registrar_changed(reg);
+	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+			       wps_registrar_set_selected_timeout,
+			       reg, NULL);
+
+	return 0;
+}
+
+
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+				     struct wps_uuid_pin *pin)
+{
+	u8 *addr;
+	u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	if (is_zero_ether_addr(pin->enrollee_addr))
+		addr = bcast;
+	else
+		addr = pin->enrollee_addr;
+	wps_registrar_remove_authorized_mac(reg, addr);
+	wps_remove_pin(pin);
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+
+static void wps_registrar_expire_pins(struct wps_registrar *reg)
+{
+	struct wps_uuid_pin *pin, *prev;
+	struct os_time now;
+
+	os_get_time(&now);
+	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
+	{
+		if ((pin->flags & PIN_EXPIRES) &&
+		    os_time_before(&pin->expiration, &now)) {
+			wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
+				    pin->uuid, WPS_UUID_LEN);
+			wps_registrar_remove_pin(reg, pin);
+		}
+	}
+}
+
+
+/**
+ * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
+ * @reg: Registrar data from wps_registrar_init()
+ * @dev_pw: PIN to search for or %NULL to match any
+ * @dev_pw_len: Length of dev_pw in octets
+ * Returns: 0 on success, -1 if not wildcard PIN is enabled
+ */
+static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
+						 const u8 *dev_pw,
+						 size_t dev_pw_len)
+{
+	struct wps_uuid_pin *pin, *prev;
+
+	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
+	{
+		if (dev_pw && pin->pin &&
+		    (dev_pw_len != pin->pin_len ||
+		     os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0))
+			continue; /* different PIN */
+		if (pin->wildcard_uuid) {
+			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
+				    pin->uuid, WPS_UUID_LEN);
+			wps_registrar_remove_pin(reg, pin);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+/**
+ * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
+ * @reg: Registrar data from wps_registrar_init()
+ * @uuid: UUID-E
+ * Returns: 0 on success, -1 on failure (e.g., PIN not found)
+ */
+int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
+{
+	struct wps_uuid_pin *pin, *prev;
+
+	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
+	{
+		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
+			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
+				    pin->uuid, WPS_UUID_LEN);
+			wps_registrar_remove_pin(reg, pin);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
+					const u8 *uuid, size_t *pin_len)
+{
+	struct wps_uuid_pin *pin, *found = NULL;
+
+	wps_registrar_expire_pins(reg);
+
+	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
+		if (!pin->wildcard_uuid &&
+		    os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
+			found = pin;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* Check for wildcard UUIDs since none of the UUID-specific
+		 * PINs matched */
+		dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
+			if (pin->wildcard_uuid == 1 ||
+			    pin->wildcard_uuid == 2) {
+				wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
+					   "PIN. Assigned it for this UUID-E");
+				pin->wildcard_uuid++;
+				os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
+				found = pin;
+				break;
+			}
+		}
+	}
+
+	if (!found)
+		return NULL;
+
+	/*
+	 * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
+	 * that could otherwise avoid PIN invalidations.
+	 */
+	if (found->flags & PIN_LOCKED) {
+		wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
+			   "allow concurrent re-use");
+		return NULL;
+	}
+	*pin_len = found->pin_len;
+	found->flags |= PIN_LOCKED;
+	return found->pin;
+}
+
+
+/**
+ * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E
+ * @reg: Registrar data from wps_registrar_init()
+ * @uuid: UUID-E
+ * Returns: 0 on success, -1 on failure
+ *
+ * PINs are locked to enforce only one concurrent use. This function unlocks a
+ * PIN to allow it to be used again. If the specified PIN was configured using
+ * a wildcard UUID, it will be removed instead of allowing multiple uses.
+ */
+int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
+{
+	struct wps_uuid_pin *pin;
+
+	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
+		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
+			if (pin->wildcard_uuid == 3) {
+				wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
+					   "wildcard PIN");
+				return wps_registrar_invalidate_pin(reg, uuid);
+			}
+			pin->flags &= ~PIN_LOCKED;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static void wps_registrar_stop_pbc(struct wps_registrar *reg)
+{
+	reg->selected_registrar = 0;
+	reg->pbc = 0;
+	os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
+	wps_registrar_remove_authorized_mac(reg,
+					    (u8 *) "\xff\xff\xff\xff\xff\xff");
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+
+static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wps_registrar *reg = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
+	wps_pbc_timeout_event(reg->wps);
+	wps_registrar_stop_pbc(reg);
+}
+
+
+/**
+ * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
+ * @reg: Registrar data from wps_registrar_init()
+ * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL
+ *	indicates no such filtering
+ * Returns: 0 on success, -1 on failure, -2 on session overlap
+ *
+ * This function is called on an AP when a push button is pushed to activate
+ * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
+ * or when a PBC registration is completed. If more than one Enrollee in active
+ * PBC mode has been detected during the monitor time (previous 2 minutes), the
+ * PBC mode is not activated and -2 is returned to indicate session overlap.
+ * This is skipped if a specific Enrollee is selected.
+ */
+int wps_registrar_button_pushed(struct wps_registrar *reg,
+				const u8 *p2p_dev_addr)
+{
+	if (p2p_dev_addr == NULL &&
+	    wps_registrar_pbc_overlap(reg, NULL, NULL)) {
+		wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
+			   "mode");
+		wps_pbc_overlap_event(reg->wps);
+		return -2;
+	}
+	wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
+	reg->force_pbc_overlap = 0;
+	reg->selected_registrar = 1;
+	reg->pbc = 1;
+	if (p2p_dev_addr)
+		os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
+	else
+		os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
+	wps_registrar_add_authorized_mac(reg,
+					 (u8 *) "\xff\xff\xff\xff\xff\xff");
+	wps_registrar_selected_registrar_changed(reg);
+
+	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
+			       reg, NULL);
+	return 0;
+}
+
+
+static void wps_registrar_pbc_completed(struct wps_registrar *reg)
+{
+	wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	wps_registrar_stop_pbc(reg);
+}
+
+
+static void wps_registrar_pin_completed(struct wps_registrar *reg)
+{
+	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
+	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+	reg->selected_registrar = 0;
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+			    const u8 *dev_pw, size_t dev_pw_len)
+{
+	if (registrar->pbc) {
+		wps_registrar_remove_pbc_session(registrar,
+						 uuid_e, NULL);
+		wps_registrar_pbc_completed(registrar);
+		os_get_time(&registrar->pbc_ignore_start);
+		os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
+	} else {
+		wps_registrar_pin_completed(registrar);
+	}
+
+	if (dev_pw &&
+	    wps_registrar_invalidate_wildcard_pin(registrar, dev_pw,
+						  dev_pw_len) == 0) {
+		wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN",
+				dev_pw, dev_pw_len);
+	}
+}
+
+
+int wps_registrar_wps_cancel(struct wps_registrar *reg)
+{
+	if (reg->pbc) {
+		wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it");
+		wps_registrar_pbc_timeout(reg, NULL);
+		eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+		return 1;
+	} else if (reg->selected_registrar) {
+		/* PIN Method */
+		wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
+		wps_registrar_pin_completed(reg);
+		wps_registrar_invalidate_wildcard_pin(reg, NULL, 0);
+		return 1;
+	}
+	return 0;
+}
+
+
+/**
+ * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
+ * @reg: Registrar data from wps_registrar_init()
+ * @addr: MAC address of the Probe Request sender
+ * @wps_data: WPS IE contents
+ *
+ * This function is called on an AP when a Probe Request with WPS IE is
+ * received. This is used to track PBC mode use and to detect possible overlap
+ * situation with other WPS APs.
+ */
+void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
+				const struct wpabuf *wps_data,
+				int p2p_wildcard)
+{
+	struct wps_parse_attr attr;
+	int skip_add = 0;
+
+	wpa_hexdump_buf(MSG_MSGDUMP,
+			"WPS: Probe Request with WPS data received",
+			wps_data);
+
+	if (wps_parse_msg(wps_data, &attr) < 0)
+		return;
+
+	if (attr.config_methods == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
+			   "Probe Request");
+		return;
+	}
+
+	if (attr.dev_password_id == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute "
+			   "in Probe Request");
+		return;
+	}
+
+	if (reg->enrollee_seen_cb && attr.uuid_e &&
+	    attr.primary_dev_type && attr.request_type && !p2p_wildcard) {
+		char *dev_name = NULL;
+		if (attr.dev_name) {
+			dev_name = os_zalloc(attr.dev_name_len + 1);
+			if (dev_name) {
+				os_memcpy(dev_name, attr.dev_name,
+					  attr.dev_name_len);
+			}
+		}
+		reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e,
+				      attr.primary_dev_type,
+				      WPA_GET_BE16(attr.config_methods),
+				      WPA_GET_BE16(attr.dev_password_id),
+				      *attr.request_type, dev_name);
+		os_free(dev_name);
+	}
+
+	if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
+		return; /* Not PBC */
+
+	wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
+		   MACSTR, MAC2STR(addr));
+	if (attr.uuid_e == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No "
+			   "UUID-E included");
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
+		    WPS_UUID_LEN);
+
+#ifdef WPS_WORKAROUNDS
+	if (reg->pbc_ignore_start.sec &&
+	    os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
+		struct os_time now, dur;
+		os_get_time(&now);
+		os_time_sub(&now, &reg->pbc_ignore_start, &dur);
+		if (dur.sec >= 0 && dur.sec < 5) {
+			wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
+				   "based on Probe Request from the Enrollee "
+				   "that just completed PBC provisioning");
+			skip_add = 1;
+		} else
+			reg->pbc_ignore_start.sec = 0;
+	}
+#endif /* WPS_WORKAROUNDS */
+
+	if (!skip_add)
+		wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+	if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
+		wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
+		reg->force_pbc_overlap = 1;
+		wps_pbc_overlap_event(reg->wps);
+	}
+}
+
+
+static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+			  const u8 *psk, size_t psk_len)
+{
+	if (reg->new_psk_cb == NULL)
+		return 0;
+
+	return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len);
+}
+
+
+static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
+			      const struct wps_device_data *dev)
+{
+	if (reg->pin_needed_cb == NULL)
+		return;
+
+	reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
+}
+
+
+static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
+			       const u8 *uuid_e, const u8 *dev_pw,
+			       size_t dev_pw_len)
+{
+	if (reg->reg_success_cb == NULL)
+		return;
+
+	reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len);
+}
+
+
+static int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,
+			 struct wpabuf *probe_resp_ie)
+{
+	return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie);
+}
+
+
+static void wps_cb_set_sel_reg(struct wps_registrar *reg)
+{
+	u16 methods = 0;
+	if (reg->set_sel_reg_cb == NULL)
+		return;
+
+	if (reg->selected_registrar) {
+		methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+		methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+			     WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+		if (reg->pbc)
+			wps_set_pushbutton(&methods, reg->wps->config_methods);
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d "
+		   "config_methods=0x%x pbc=%d methods=0x%x",
+		   reg->selected_registrar, reg->wps->config_methods,
+		   reg->pbc, methods);
+
+	reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar,
+			    reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT,
+			    methods);
+}
+
+
+static int wps_set_ie(struct wps_registrar *reg)
+{
+	struct wpabuf *beacon;
+	struct wpabuf *probe;
+	const u8 *auth_macs;
+	size_t count;
+	size_t vendor_len = 0;
+	int i;
+
+	if (reg->set_ie_cb == NULL)
+		return 0;
+
+	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+		if (reg->wps->dev.vendor_ext[i]) {
+			vendor_len += 2 + 2;
+			vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]);
+		}
+	}
+
+	beacon = wpabuf_alloc(400 + vendor_len);
+	if (beacon == NULL)
+		return -1;
+	probe = wpabuf_alloc(500 + vendor_len);
+	if (probe == NULL) {
+		wpabuf_free(beacon);
+		return -1;
+	}
+
+	auth_macs = wps_authorized_macs(reg, &count);
+
+	wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
+
+	if (wps_build_version(beacon) ||
+	    wps_build_wps_state(reg->wps, beacon) ||
+	    wps_build_ap_setup_locked(reg->wps, beacon) ||
+	    wps_build_selected_registrar(reg, beacon) ||
+	    wps_build_sel_reg_dev_password_id(reg, beacon) ||
+	    wps_build_sel_reg_config_methods(reg, beacon) ||
+	    wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
+	    (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon)) ||
+	    wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
+	    wps_build_vendor_ext(&reg->wps->dev, beacon)) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+
+#ifdef CONFIG_P2P
+	if (wps_build_dev_name(&reg->wps->dev, beacon) ||
+	    wps_build_primary_dev_type(&reg->wps->dev, beacon)) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+#endif /* CONFIG_P2P */
+
+	wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
+
+	if (wps_build_version(probe) ||
+	    wps_build_wps_state(reg->wps, probe) ||
+	    wps_build_ap_setup_locked(reg->wps, probe) ||
+	    wps_build_selected_registrar(reg, probe) ||
+	    wps_build_sel_reg_dev_password_id(reg, probe) ||
+	    wps_build_sel_reg_config_methods(reg, probe) ||
+	    wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP :
+				WPS_RESP_REGISTRAR) ||
+	    wps_build_uuid_e(probe, reg->wps->uuid) ||
+	    wps_build_device_attrs(&reg->wps->dev, probe) ||
+	    wps_build_probe_config_methods(reg, probe) ||
+	    (reg->dualband && wps_build_rf_bands(&reg->wps->dev, probe)) ||
+	    wps_build_wfa_ext(probe, 0, auth_macs, count) ||
+	    wps_build_vendor_ext(&reg->wps->dev, probe)) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+
+	beacon = wps_ie_encapsulate(beacon);
+	probe = wps_ie_encapsulate(probe);
+
+	if (!beacon || !probe) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+
+	if (reg->static_wep_only) {
+		/*
+		 * Windows XP and Vista clients can get confused about
+		 * EAP-Identity/Request when they probe the network with
+		 * EAPOL-Start. In such a case, they may assume the network is
+		 * using IEEE 802.1X and prompt user for a certificate while
+		 * the correct (non-WPS) behavior would be to ask for the
+		 * static WEP key. As a workaround, use Microsoft Provisioning
+		 * IE to advertise that legacy 802.1X is not supported.
+		 */
+		const u8 ms_wps[7] = {
+			WLAN_EID_VENDOR_SPECIFIC, 5,
+			/* Microsoft Provisioning IE (00:50:f2:5) */
+			0x00, 0x50, 0xf2, 5,
+			0x00 /* no legacy 802.1X or MS WPS */
+		};
+		wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
+			   "into Beacon/Probe Response frames");
+		wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
+		wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
+	}
+
+	return wps_cb_set_ie(reg, beacon, probe);
+}
+
+
+static int wps_get_dev_password(struct wps_data *wps)
+{
+	const u8 *pin;
+	size_t pin_len = 0;
+
+	os_free(wps->dev_password);
+	wps->dev_password = NULL;
+
+	if (wps->pbc) {
+		wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
+		pin = (const u8 *) "00000000";
+		pin_len = 8;
+#ifdef CONFIG_WPS_NFC
+	} else if (wps->nfc_pw_token) {
+		wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
+			   "Password Token");
+		pin = wps->nfc_pw_token->dev_pw;
+		pin_len = wps->nfc_pw_token->dev_pw_len;
+#endif /* CONFIG_WPS_NFC */
+	} else {
+		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
+					    &pin_len);
+	}
+	if (pin == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
+			   "the Enrollee");
+		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
+				  &wps->peer_dev);
+		return -1;
+	}
+
+	wps->dev_password = os_malloc(pin_len);
+	if (wps->dev_password == NULL)
+		return -1;
+	os_memcpy(wps->dev_password, pin, pin_len);
+	wps->dev_password_len = pin_len;
+
+	return 0;
+}
+
+
+static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * UUID-R");
+	wpabuf_put_be16(msg, ATTR_UUID_R);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN);
+	return 0;
+}
+
+
+static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 *hash;
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
+		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
+
+	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
+			   "R-Hash derivation");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash1");
+	wpabuf_put_be16(msg, ATTR_R_HASH1);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = wps->snonce;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash2");
+	wpabuf_put_be16(msg, ATTR_R_HASH2);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
+static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce1");
+	wpabuf_put_be16(msg, ATTR_R_SNONCE1);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce2");
+	wpabuf_put_be16(msg, ATTR_R_SNONCE2);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
+			WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_cred_network_idx(struct wpabuf *msg,
+				      const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Index (1)");
+	wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, 1);
+	return 0;
+}
+
+
+static int wps_build_cred_ssid(struct wpabuf *msg,
+			       const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential",
+			  cred->ssid, cred->ssid_len);
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, cred->ssid_len);
+	wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
+	return 0;
+}
+
+
+static int wps_build_cred_auth_type(struct wpabuf *msg,
+				    const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
+		   cred->auth_type);
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, cred->auth_type);
+	return 0;
+}
+
+
+static int wps_build_cred_encr_type(struct wpabuf *msg,
+				    const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
+		   cred->encr_type);
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, cred->encr_type);
+	return 0;
+}
+
+
+static int wps_build_cred_network_key(struct wpabuf *msg,
+				      const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%d)",
+		   (int) cred->key_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+			cred->key, cred->key_len);
+	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+	wpabuf_put_be16(msg, cred->key_len);
+	wpabuf_put_data(msg, cred->key, cred->key_len);
+	return 0;
+}
+
+
+static int wps_build_cred_mac_addr(struct wpabuf *msg,
+				   const struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
+		   MAC2STR(cred->mac_addr));
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static int wps_build_credential(struct wpabuf *msg,
+				const struct wps_credential *cred)
+{
+	if (wps_build_cred_network_idx(msg, cred) ||
+	    wps_build_cred_ssid(msg, cred) ||
+	    wps_build_cred_auth_type(msg, cred) ||
+	    wps_build_cred_encr_type(msg, cred) ||
+	    wps_build_cred_network_key(msg, cred) ||
+	    wps_build_cred_mac_addr(msg, cred))
+		return -1;
+	return 0;
+}
+
+
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred)
+{
+	struct wpabuf *wbuf;
+	wbuf = wpabuf_alloc(200);
+	if (wbuf == NULL)
+		return -1;
+	if (wps_build_credential(wbuf, cred)) {
+		wpabuf_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);
+	return 0;
+}
+
+
+int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
+{
+	struct wpabuf *cred;
+
+	if (wps->wps->registrar->skip_cred_build)
+		goto skip_cred_build;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Credential");
+	if (wps->use_cred) {
+		os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred));
+		goto use_provided;
+	}
+	os_memset(&wps->cred, 0, sizeof(wps->cred));
+
+	os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
+	wps->cred.ssid_len = wps->wps->ssid_len;
+
+	/* Select the best authentication and encryption type */
+	if (wps->auth_type & WPS_AUTH_WPA2PSK)
+		wps->auth_type = WPS_AUTH_WPA2PSK;
+	else if (wps->auth_type & WPS_AUTH_WPAPSK)
+		wps->auth_type = WPS_AUTH_WPAPSK;
+	else if (wps->auth_type & WPS_AUTH_OPEN)
+		wps->auth_type = WPS_AUTH_OPEN;
+	else if (wps->auth_type & WPS_AUTH_SHARED)
+		wps->auth_type = WPS_AUTH_SHARED;
+	else {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
+			   wps->auth_type);
+		return -1;
+	}
+	wps->cred.auth_type = wps->auth_type;
+
+	if (wps->auth_type == WPS_AUTH_WPA2PSK ||
+	    wps->auth_type == WPS_AUTH_WPAPSK) {
+		if (wps->encr_type & WPS_ENCR_AES)
+			wps->encr_type = WPS_ENCR_AES;
+		else if (wps->encr_type & WPS_ENCR_TKIP)
+			wps->encr_type = WPS_ENCR_TKIP;
+		else {
+			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
+				   "type for WPA/WPA2");
+			return -1;
+		}
+	} else {
+		if (wps->encr_type & WPS_ENCR_WEP)
+			wps->encr_type = WPS_ENCR_WEP;
+		else if (wps->encr_type & WPS_ENCR_NONE)
+			wps->encr_type = WPS_ENCR_NONE;
+		else {
+			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
+				   "type for non-WPA/WPA2 mode");
+			return -1;
+		}
+	}
+	wps->cred.encr_type = wps->encr_type;
+	/*
+	 * Set MAC address in the Credential to be the Enrollee's MAC address
+	 */
+	os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
+
+	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
+	    !wps->wps->registrar->disable_auto_conf) {
+		u8 r[16];
+		/* Generate a random passphrase */
+		if (random_get_bytes(r, sizeof(r)) < 0)
+			return -1;
+		os_free(wps->new_psk);
+		wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
+		if (wps->new_psk == NULL)
+			return -1;
+		wps->new_psk_len--; /* remove newline */
+		while (wps->new_psk_len &&
+		       wps->new_psk[wps->new_psk_len - 1] == '=')
+			wps->new_psk_len--;
+		wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
+				      wps->new_psk, wps->new_psk_len);
+		os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
+		wps->cred.key_len = wps->new_psk_len;
+	} else if (wps->use_psk_key && wps->wps->psk_set) {
+		char hex[65];
+		wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
+		wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
+		os_memcpy(wps->cred.key, hex, 32 * 2);
+		wps->cred.key_len = 32 * 2;
+	} else if (wps->wps->network_key) {
+		os_memcpy(wps->cred.key, wps->wps->network_key,
+			  wps->wps->network_key_len);
+		wps->cred.key_len = wps->wps->network_key_len;
+	} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+		char hex[65];
+		/* Generate a random per-device PSK */
+		os_free(wps->new_psk);
+		wps->new_psk_len = 32;
+		wps->new_psk = os_malloc(wps->new_psk_len);
+		if (wps->new_psk == NULL)
+			return -1;
+		if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+			os_free(wps->new_psk);
+			wps->new_psk = NULL;
+			return -1;
+		}
+		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
+				wps->new_psk, wps->new_psk_len);
+		wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
+				 wps->new_psk_len);
+		os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
+		wps->cred.key_len = wps->new_psk_len * 2;
+	}
+
+use_provided:
+#ifdef CONFIG_WPS_TESTING
+	if (wps_testing_dummy_cred)
+		cred = wpabuf_alloc(200);
+	else
+		cred = NULL;
+	if (cred) {
+		struct wps_credential dummy;
+		wpa_printf(MSG_DEBUG, "WPS: Add dummy credential");
+		os_memset(&dummy, 0, sizeof(dummy));
+		os_memcpy(dummy.ssid, "dummy", 5);
+		dummy.ssid_len = 5;
+		dummy.auth_type = WPS_AUTH_WPA2PSK;
+		dummy.encr_type = WPS_ENCR_AES;
+		os_memcpy(dummy.key, "dummy psk", 9);
+		dummy.key_len = 9;
+		os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN);
+		wps_build_credential(cred, &dummy);
+		wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred);
+
+		wpabuf_put_be16(msg, ATTR_CRED);
+		wpabuf_put_be16(msg, wpabuf_len(cred));
+		wpabuf_put_buf(msg, cred);
+
+		wpabuf_free(cred);
+	}
+#endif /* CONFIG_WPS_TESTING */
+
+	cred = wpabuf_alloc(200);
+	if (cred == NULL)
+		return -1;
+
+	if (wps_build_credential(cred, &wps->cred)) {
+		wpabuf_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);
+
+skip_cred_build:
+	if (wps->wps->registrar->extra_cred) {
+		wpa_printf(MSG_DEBUG, "WPS:  * Credential (pre-configured)");
+		wpabuf_put_buf(msg, wps->wps->registrar->extra_cred);
+	}
+
+	return 0;
+}
+
+
+static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings");
+
+	if (wps_build_credential(msg, &wps->cred))
+		return -1;
+
+	return 0;
+}
+
+
+static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (wps_build_ap_settings(wps, plain)) {
+		wpabuf_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);
+
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m2(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
+		    wps->nonce_r, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M2");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M2) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_uuid_r(wps, msg) ||
+	    wps_build_public_key(wps, msg) ||
+	    wps_derive_keys(wps) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
+	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
+	    wps_build_os_version(&wps->wps->dev, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->int_reg = 1;
+	wps->state = RECV_M3;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m2d(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+	u16 err = wps->config_error;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps->wps->ap && wps->wps->ap_setup_locked &&
+	    err == WPS_CFG_NO_ERROR)
+		err = WPS_CFG_SETUP_LOCKED;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M2D) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_uuid_r(wps, msg) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_config_error(msg, err) ||
+	    wps_build_os_version(&wps->wps->dev, msg) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M2D_ACK;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m4(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
+
+	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M4) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_r_hash(wps, msg) ||
+	    wps_build_r_snonce1(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    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);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_M5;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m6(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M6");
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M6) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_r_snonce2(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    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);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->wps_pin_revealed = 1;
+	wps->state = RECV_M7;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m8(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
+
+	plain = wpabuf_alloc(500);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M8) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) ||
+	    (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    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);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_DONE;
+	return msg;
+}
+
+
+struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
+				      enum wsc_op_code *op_code)
+{
+	struct wpabuf *msg;
+
+#ifdef CONFIG_WPS_UPNP
+	if (!wps->int_reg && wps->wps->wps_upnp) {
+		struct upnp_pending_message *p, *prev = NULL;
+		if (wps->ext_reg > 1)
+			wps_registrar_free_pending_m2(wps->wps);
+		p = wps->wps->upnp_msgs;
+		/* TODO: check pending message MAC address */
+		while (p && p->next) {
+			prev = p;
+			p = p->next;
+		}
+		if (p) {
+			wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
+				   "UPnP");
+			if (prev)
+				prev->next = NULL;
+			else
+				wps->wps->upnp_msgs = NULL;
+			msg = p->msg;
+			switch (p->type) {
+			case WPS_WSC_ACK:
+				*op_code = WSC_ACK;
+				break;
+			case WPS_WSC_NACK:
+				*op_code = WSC_NACK;
+				break;
+			default:
+				*op_code = WSC_MSG;
+				break;
+			}
+			os_free(p);
+			if (wps->ext_reg == 0)
+				wps->ext_reg = 1;
+			return msg;
+		}
+	}
+	if (wps->ext_reg) {
+		wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
+			   "pending message available");
+		return NULL;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	switch (wps->state) {
+	case SEND_M2:
+		if (wps_get_dev_password(wps) < 0)
+			msg = wps_build_m2d(wps);
+		else
+			msg = wps_build_m2(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M2D:
+		msg = wps_build_m2d(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M4:
+		msg = wps_build_m4(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M6:
+		msg = wps_build_m6(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M8:
+		msg = wps_build_m8(wps);
+		*op_code = WSC_MSG;
+		break;
+	case RECV_DONE:
+		msg = wps_build_wsc_ack(wps);
+		*op_code = WSC_ACK;
+		break;
+	case SEND_WSC_NACK:
+		msg = wps_build_wsc_nack(wps);
+		*op_code = WSC_NACK;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
+			   "a message", wps->state);
+		msg = NULL;
+		break;
+	}
+
+	if (*op_code == WSC_MSG && msg) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return msg;
+}
+
+
+static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
+{
+	if (e_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
+		return -1;
+	}
+
+	os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
+		    wps->nonce_e, WPS_NONCE_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
+{
+	if (r_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
+		return -1;
+	}
+
+	if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)
+{
+	if (uuid_e == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-E received");
+		return -1;
+	}
+
+	os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)
+{
+	if (pw_id == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received");
+		return -1;
+	}
+
+	wps->dev_pw_id = WPA_GET_BE16(pw_id);
+	wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id);
+
+	return 0;
+}
+
+
+static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)
+{
+	if (e_hash1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)
+{
+	if (e_hash2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (e_snonce1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1,
+			WPS_SECRET_NONCE_LEN);
+
+	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = e_snonce1;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		wps_pwd_auth_fail_event(wps->wps, 0, 1);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (e_snonce2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2,
+			WPS_SECRET_NONCE_LEN);
+
+	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = e_snonce2;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
+			   "not match with the pre-committed value");
+		wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		wps_pwd_auth_fail_event(wps->wps, 0, 2);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second "
+		   "half of the device password");
+	wps->wps_pin_revealed = 0;
+	wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e);
+
+	/*
+	 * In case wildcard PIN is used and WPS handshake succeeds in the first
+	 * attempt, wps_registrar_unlock_pin() would not free the PIN, so make
+	 * sure the PIN gets invalidated here.
+	 */
+	wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
+
+	return 0;
+}
+
+
+static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)
+{
+	if (mac_addr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No MAC Address received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR,
+		   MAC2STR(mac_addr));
+	os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN);
+	os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+
+static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
+			      size_t pk_len)
+{
+	if (pk == NULL || pk_len == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
+		return -1;
+	}
+
+	wpabuf_free(wps->dh_pubkey_e);
+	wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
+	if (wps->dh_pubkey_e == NULL)
+		return -1;
+
+	return 0;
+}
+
+
+static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
+{
+	u16 auth_types;
+
+	if (auth == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags "
+			   "received");
+		return -1;
+	}
+
+	auth_types = WPA_GET_BE16(auth);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
+		   auth_types);
+	wps->auth_type = wps->wps->auth_types & auth_types;
+	if (wps->auth_type == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
+			   "authentication types (own 0x%x Enrollee 0x%x)",
+			   wps->wps->auth_types, auth_types);
+#ifdef WPS_WORKAROUNDS
+		/*
+		 * Some deployed implementations seem to advertise incorrect
+		 * information in this attribute. For example, Linksys WRT350N
+		 * seems to have a byteorder bug that breaks this negotiation.
+		 * In order to interoperate with existing implementations,
+		 * assume that the Enrollee supports everything we do.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
+			   "does not advertise supported authentication types "
+			   "correctly");
+		wps->auth_type = wps->wps->auth_types;
+#else /* WPS_WORKAROUNDS */
+		return -1;
+#endif /* WPS_WORKAROUNDS */
+	}
+
+	return 0;
+}
+
+
+static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
+{
+	u16 encr_types;
+
+	if (encr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags "
+			   "received");
+		return -1;
+	}
+
+	encr_types = WPA_GET_BE16(encr);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x",
+		   encr_types);
+	wps->encr_type = wps->wps->encr_types & encr_types;
+	if (wps->encr_type == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
+			   "encryption types (own 0x%x Enrollee 0x%x)",
+			   wps->wps->encr_types, encr_types);
+#ifdef WPS_WORKAROUNDS
+		/*
+		 * Some deployed implementations seem to advertise incorrect
+		 * information in this attribute. For example, Linksys WRT350N
+		 * seems to have a byteorder bug that breaks this negotiation.
+		 * In order to interoperate with existing implementations,
+		 * assume that the Enrollee supports everything we do.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
+			   "does not advertise supported encryption types "
+			   "correctly");
+		wps->encr_type = wps->wps->encr_types;
+#else /* WPS_WORKAROUNDS */
+		return -1;
+#endif /* WPS_WORKAROUNDS */
+	}
+
+	return 0;
+}
+
+
+static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)
+{
+	if (conn == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags "
+			   "received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x",
+		   *conn);
+
+	return 0;
+}
+
+
+static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)
+{
+	u16 m;
+
+	if (methods == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Config Methods received");
+		return -1;
+	}
+
+	m = WPA_GET_BE16(methods);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x"
+		   "%s%s%s%s%s%s%s%s%s", m,
+		   m & WPS_CONFIG_USBA ? " [USBA]" : "",
+		   m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "",
+		   m & WPS_CONFIG_LABEL ? " [Label]" : "",
+		   m & WPS_CONFIG_DISPLAY ? " [Display]" : "",
+		   m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "",
+		   m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "",
+		   m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "",
+		   m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "",
+		   m & WPS_CONFIG_KEYPAD ? " [Keypad]" : "");
+
+	if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) {
+		/*
+		 * The Enrollee does not have a display so it is unlikely to be
+		 * able to show the passphrase to a user and as such, could
+		 * benefit from receiving PSK to reduce key derivation time.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to "
+			   "Enrollee not supporting display");
+		wps->use_psk_key = 1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_wps_state(struct wps_data *wps, const u8 *state)
+{
+	if (state == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State "
+			   "received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d",
+		   *state);
+
+	return 0;
+}
+
+
+static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
+{
+	u16 a;
+
+	if (assoc == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Association State received");
+		return -1;
+	}
+
+	a = WPA_GET_BE16(assoc);
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a);
+
+	return 0;
+}
+
+
+static int wps_process_config_error(struct wps_data *wps, const u8 *err)
+{
+	u16 e;
+
+	if (err == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received");
+		return -1;
+	}
+
+	e = WPA_GET_BE16(err);
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e);
+
+	return 0;
+}
+
+
+static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)
+{
+#ifdef CONFIG_P2P
+	struct wps_registrar *reg = wps->wps->registrar;
+
+	if (is_zero_ether_addr(reg->p2p_dev_addr))
+		return 1; /* no filtering in use */
+
+	if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address "
+			   "filtering for PBC: expected " MACSTR " was "
+			   MACSTR " - indicate PBC session overlap",
+			   MAC2STR(reg->p2p_dev_addr),
+			   MAC2STR(wps->p2p_dev_addr));
+		return 0;
+	}
+#endif /* CONFIG_P2P */
+	return 1;
+}
+
+
+static int wps_registrar_skip_overlap(struct wps_data *wps)
+{
+#ifdef CONFIG_P2P
+	struct wps_registrar *reg = wps->wps->registrar;
+
+	if (is_zero_ether_addr(reg->p2p_dev_addr))
+		return 0; /* no specific Enrollee selected */
+
+	if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected "
+			   "Enrollee match");
+		return 1;
+	}
+#endif /* CONFIG_P2P */
+	return 0;
+}
+
+
+static enum wps_process_res wps_process_m1(struct wps_data *wps,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M1");
+
+	if (wps->state != RECV_M1) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M1", wps->state);
+		return WPS_FAILURE;
+	}
+
+	if (wps_process_uuid_e(wps, attr->uuid_e) ||
+	    wps_process_mac_addr(wps, attr->mac_addr) ||
+	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
+	    wps_process_auth_type_flags(wps, attr->auth_type_flags) ||
+	    wps_process_encr_type_flags(wps, attr->encr_type_flags) ||
+	    wps_process_conn_type_flags(wps, attr->conn_type_flags) ||
+	    wps_process_config_methods(wps, attr->config_methods) ||
+	    wps_process_wps_state(wps, attr->wps_state) ||
+	    wps_process_device_attrs(&wps->peer_dev, attr) ||
+	    wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) ||
+	    wps_process_assoc_state(wps, attr->assoc_state) ||
+	    wps_process_dev_password_id(wps, attr->dev_password_id) ||
+	    wps_process_config_error(wps, attr->config_error) ||
+	    wps_process_os_version(&wps->peer_dev, attr->os_version))
+		return WPS_FAILURE;
+
+	if (wps->dev_pw_id < 0x10 &&
+	    wps->dev_pw_id != DEV_PW_DEFAULT &&
+	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
+	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
+	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
+	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
+	     !wps->wps->registrar->pbc)) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
+			   wps->dev_pw_id);
+		wps->state = SEND_M2D;
+		return WPS_CONTINUE;
+	}
+
+#ifdef CONFIG_WPS_NFC
+	if (wps->dev_pw_id >= 0x10) {
+		struct wps_nfc_pw_token *token;
+		const u8 *addr[1];
+		u8 hash[WPS_HASH_LEN];
+
+		token = wps_get_nfc_pw_token(
+			&wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
+		if (token) {
+			wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+				   "Password Token");
+			dl_list_del(&token->list);
+			wps->nfc_pw_token = token;
+
+			addr[0] = attr->public_key;
+			sha256_vector(1, addr, &attr->public_key_len, hash);
+			if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash,
+				      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+				wpa_printf(MSG_ERROR, "WPS: Public Key hash "
+					   "mismatch");
+				return WPS_FAILURE;
+			}
+		}
+	}
+#endif /* CONFIG_WPS_NFC */
+
+	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
+		if ((wps->wps->registrar->force_pbc_overlap ||
+		     wps_registrar_pbc_overlap(wps->wps->registrar,
+					       wps->mac_addr_e, wps->uuid_e) ||
+		     !wps_registrar_p2p_dev_addr_match(wps)) &&
+		    !wps_registrar_skip_overlap(wps)) {
+			wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
+				   "negotiation");
+			wps->state = SEND_M2D;
+			wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+			wps_pbc_overlap_event(wps->wps);
+			wps_fail_event(wps->wps, WPS_M1,
+				       WPS_CFG_MULTIPLE_PBC_DETECTED,
+				       WPS_EI_NO_ERROR);
+			wps->wps->registrar->force_pbc_overlap = 1;
+			return WPS_CONTINUE;
+		}
+		wps_registrar_add_pbc_session(wps->wps->registrar,
+					      wps->mac_addr_e, wps->uuid_e);
+		wps->pbc = 1;
+	}
+
+#ifdef WPS_WORKAROUNDS
+	/*
+	 * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in
+	 * passphrase format. To avoid interop issues, force PSK format to be
+	 * used.
+	 */
+	if (!wps->use_psk_key &&
+	    wps->peer_dev.manufacturer &&
+	    os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 &&
+	    wps->peer_dev.model_name &&
+	    os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in "
+			   "PSK format");
+		wps->use_psk_key = 1;
+	}
+#endif /* WPS_WORKAROUNDS */
+
+	wps->state = SEND_M2;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m3(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M3");
+
+	if (wps->state != RECV_M3) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M3", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+	    !wps_registrar_skip_overlap(wps)) {
+		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+			   "session overlap");
+		wps->state = SEND_WSC_NACK;
+		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg) ||
+	    wps_process_e_hash1(wps, attr->e_hash1) ||
+	    wps_process_e_hash2(wps, attr->e_hash2)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wps->state = SEND_M4;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m5(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M5");
+
+	if (wps->state != RECV_M5) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M5", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+	    !wps_registrar_skip_overlap(wps)) {
+		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+			   "session overlap");
+		wps->state = SEND_WSC_NACK;
+		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	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);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M6;
+	return WPS_CONTINUE;
+}
+
+
+static void wps_sta_cred_cb(struct wps_data *wps)
+{
+	/*
+	 * Update credential to only include a single authentication and
+	 * encryption type in case the AP configuration includes more than one
+	 * option.
+	 */
+	if (wps->cred.auth_type & WPS_AUTH_WPA2PSK)
+		wps->cred.auth_type = WPS_AUTH_WPA2PSK;
+	else if (wps->cred.auth_type & WPS_AUTH_WPAPSK)
+		wps->cred.auth_type = WPS_AUTH_WPAPSK;
+	if (wps->cred.encr_type & WPS_ENCR_AES)
+		wps->cred.encr_type = WPS_ENCR_AES;
+	else if (wps->cred.encr_type & WPS_ENCR_TKIP)
+		wps->cred.encr_type = WPS_ENCR_TKIP;
+	wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the "
+		   "AP configuration");
+	if (wps->wps->cred_cb)
+		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+}
+
+
+static void wps_cred_update(struct wps_credential *dst,
+			    struct wps_credential *src)
+{
+	os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
+	dst->ssid_len = src->ssid_len;
+	dst->auth_type = src->auth_type;
+	dst->encr_type = src->encr_type;
+	dst->key_idx = src->key_idx;
+	os_memcpy(dst->key, src->key, sizeof(dst->key));
+	dst->key_len = src->key_len;
+}
+
+
+static int wps_process_ap_settings_r(struct wps_data *wps,
+				     struct wps_parse_attr *attr)
+{
+	struct wpabuf *msg;
+
+	if (wps->wps->ap || wps->er)
+		return 0;
+
+	/* AP Settings Attributes in M7 when Enrollee is an AP */
+	if (wps_process_ap_settings(attr, &wps->cred) < 0)
+		return -1;
+
+	wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
+
+	if (wps->new_ap_settings) {
+		wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
+			   "new settings");
+		wps_cred_update(&wps->cred, wps->new_ap_settings);
+		return 0;
+	} else {
+		/*
+		 * Use the AP PIN only to receive the current AP settings, not
+		 * to reconfigure the AP.
+		 */
+
+		/*
+		 * Clear selected registrar here since we do not get to
+		 * WSC_Done in this protocol run.
+		 */
+		wps_registrar_pin_completed(wps->wps->registrar);
+
+		msg = wps_build_ap_cred(wps);
+		if (msg == NULL)
+			return -1;
+		wps->cred.cred_attr = wpabuf_head(msg);
+		wps->cred.cred_attr_len = wpabuf_len(msg);
+
+		if (wps->ap_settings_cb) {
+			wps->ap_settings_cb(wps->ap_settings_cb_ctx,
+					    &wps->cred);
+			wpabuf_free(msg);
+			return 1;
+		}
+		wps_sta_cred_cb(wps);
+
+		wps->cred.cred_attr = NULL;
+		wps->cred.cred_attr_len = 0;
+		wpabuf_free(msg);
+
+		return 1;
+	}
+}
+
+
+static enum wps_process_res wps_process_m7(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M7");
+
+	if (wps->state != RECV_M7) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M7", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
+	    !wps_registrar_skip_overlap(wps)) {
+		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+			   "session overlap");
+		wps->state = SEND_WSC_NACK;
+		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
+				 attr->version2 != NULL) < 0) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    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);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M8;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	enum wps_process_res ret = WPS_CONTINUE;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (*attr.msg_type != WPS_M1 &&
+	    (attr.registrar_nonce == NULL ||
+	     os_memcmp(wps->nonce_r, attr.registrar_nonce,
+		       WPS_NONCE_LEN) != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	switch (*attr.msg_type) {
+	case WPS_M1:
+		if (wps_validate_m1(msg) < 0)
+			return WPS_FAILURE;
+#ifdef CONFIG_WPS_UPNP
+		if (wps->wps->wps_upnp && attr.mac_addr) {
+			/* Remove old pending messages when starting new run */
+			wps_free_pending_msgs(wps->wps->upnp_msgs);
+			wps->wps->upnp_msgs = NULL;
+
+			upnp_wps_device_send_wlan_event(
+				wps->wps->wps_upnp, attr.mac_addr,
+				UPNP_WPS_WLANEVENT_TYPE_EAP, msg);
+		}
+#endif /* CONFIG_WPS_UPNP */
+		ret = wps_process_m1(wps, &attr);
+		break;
+	case WPS_M3:
+		if (wps_validate_m3(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m3(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M3, wps->config_error,
+				       wps->error_indication);
+		break;
+	case WPS_M5:
+		if (wps_validate_m5(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m5(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M5, wps->config_error,
+				       wps->error_indication);
+		break;
+	case WPS_M7:
+		if (wps_validate_m7(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_m7(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M7, wps->config_error,
+				       wps->error_indication);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (ret == WPS_CONTINUE) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return ret;
+}
+
+
+static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_ACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+#ifdef CONFIG_WPS_UPNP
+	if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
+	    upnp_wps_subscribers(wps->wps->wps_upnp)) {
+		if (wps->wps->upnp_msgs)
+			return WPS_CONTINUE;
+		wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
+			   "external Registrar");
+		return WPS_PENDING;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (wps->state == RECV_M2D_ACK) {
+#ifdef CONFIG_WPS_UPNP
+		if (wps->wps->wps_upnp &&
+		    upnp_wps_subscribers(wps->wps->wps_upnp)) {
+			if (wps->wps->upnp_msgs)
+				return WPS_CONTINUE;
+			if (wps->ext_reg == 0)
+				wps->ext_reg = 1;
+			wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
+				   "external Registrar");
+			return WPS_PENDING;
+		}
+#endif /* CONFIG_WPS_UPNP */
+
+		wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
+			   "terminate negotiation");
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	int old_state;
+	u16 config_error;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
+
+	old_state = wps->state;
+	wps->state = SEND_WSC_NACK;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_NACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+#ifdef CONFIG_WPS_UPNP
+	if (wps->wps->wps_upnp && wps->ext_reg) {
+		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
+			   "Registrar terminated by the Enrollee");
+		return WPS_FAILURE;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.config_error == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
+			   "in WSC_NACK");
+		return WPS_FAILURE;
+	}
+
+	config_error = WPA_GET_BE16(attr.config_error);
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
+		   "Configuration Error %d", config_error);
+
+	switch (old_state) {
+	case RECV_M3:
+		wps_fail_event(wps->wps, WPS_M2, config_error,
+			       wps->error_indication);
+		break;
+	case RECV_M5:
+		wps_fail_event(wps->wps, WPS_M4, config_error,
+			       wps->error_indication);
+		break;
+	case RECV_M7:
+		wps_fail_event(wps->wps, WPS_M6, config_error,
+			       wps->error_indication);
+		break;
+	case RECV_DONE:
+		wps_fail_event(wps->wps, WPS_M8, config_error,
+			       wps->error_indication);
+		break;
+	default:
+		break;
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
+
+	if (wps->state != RECV_DONE &&
+	    (!wps->wps->wps_upnp || !wps->ext_reg)) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving WSC_Done", wps->state);
+		return WPS_FAILURE;
+	}
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_DONE) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+#ifdef CONFIG_WPS_UPNP
+	if (wps->wps->wps_upnp && wps->ext_reg) {
+		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
+			   "Registrar completed successfully");
+		wps_device_store(wps->wps->registrar, &wps->peer_dev,
+				 wps->uuid_e);
+		return WPS_DONE;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
+	wps_device_store(wps->wps->registrar, &wps->peer_dev,
+			 wps->uuid_e);
+
+	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
+	    wps->wps->ap && !wps->wps->registrar->disable_auto_conf) {
+		struct wps_credential cred;
+
+		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+			   "on first Enrollee connection");
+
+		os_memset(&cred, 0, sizeof(cred));
+		os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
+		cred.ssid_len = wps->wps->ssid_len;
+		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
+		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
+		os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
+		cred.key_len = wps->new_psk_len;
+
+		wps->wps->wps_state = WPS_STATE_CONFIGURED;
+		wpa_hexdump_ascii_key(MSG_DEBUG,
+				      "WPS: Generated random passphrase",
+				      wps->new_psk, wps->new_psk_len);
+		if (wps->wps->cred_cb)
+			wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+
+		os_free(wps->new_psk);
+		wps->new_psk = NULL;
+	}
+
+	if (!wps->wps->ap && !wps->er)
+		wps_sta_cred_cb(wps);
+
+	if (wps->new_psk) {
+		if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
+				   wps->new_psk, wps->new_psk_len)) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
+				   "new PSK");
+		}
+		os_free(wps->new_psk);
+		wps->new_psk = NULL;
+	}
+
+	wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e,
+			   wps->dev_password, wps->dev_password_len);
+
+	if (wps->pbc) {
+		wps_registrar_remove_pbc_session(wps->wps->registrar,
+						 wps->uuid_e,
+						 wps->p2p_dev_addr);
+		wps_registrar_pbc_completed(wps->wps->registrar);
+		os_get_time(&wps->wps->registrar->pbc_ignore_start);
+		os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
+			  WPS_UUID_LEN);
+	} else {
+		wps_registrar_pin_completed(wps->wps->registrar);
+	}
+	/* TODO: maintain AuthorizedMACs somewhere separately for each ER and
+	 * merge them into APs own list.. */
+
+	wps_success_event(wps->wps);
+
+	return WPS_DONE;
+}
+
+
+enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
+					       enum wsc_op_code op_code,
+					       const struct wpabuf *msg)
+{
+	enum wps_process_res ret;
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
+		   "op_code=%d)",
+		   (unsigned long) wpabuf_len(msg), op_code);
+
+#ifdef CONFIG_WPS_UPNP
+	if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
+		struct wps_parse_attr attr;
+		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
+		    *attr.msg_type == WPS_M3)
+			wps->ext_reg = 2; /* past M2/M2D phase */
+	}
+	if (wps->ext_reg > 1)
+		wps_registrar_free_pending_m2(wps->wps);
+	if (wps->wps->wps_upnp && wps->ext_reg &&
+	    wps->wps->upnp_msgs == NULL &&
+	    (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK))
+	{
+		struct wps_parse_attr attr;
+		int type;
+		if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
+			type = -1;
+		else
+			type = *attr.msg_type;
+		wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)"
+			   " to external Registrar for processing", type);
+		upnp_wps_device_send_wlan_event(wps->wps->wps_upnp,
+						wps->mac_addr_e,
+						UPNP_WPS_WLANEVENT_TYPE_EAP,
+						msg);
+		if (op_code == WSC_MSG)
+			return WPS_PENDING;
+	} else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) {
+		wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using "
+			   "external Registrar");
+		return WPS_CONTINUE;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	switch (op_code) {
+	case WSC_MSG:
+		return wps_process_wsc_msg(wps, msg);
+	case WSC_ACK:
+		if (wps_validate_wsc_ack(msg) < 0)
+			return WPS_FAILURE;
+		return wps_process_wsc_ack(wps, msg);
+	case WSC_NACK:
+		if (wps_validate_wsc_nack(msg) < 0)
+			return WPS_FAILURE;
+		return wps_process_wsc_nack(wps, msg);
+	case WSC_Done:
+		if (wps_validate_wsc_done(msg) < 0)
+			return WPS_FAILURE;
+		ret = wps_process_wsc_done(wps, msg);
+		if (ret == WPS_FAILURE) {
+			wps->state = SEND_WSC_NACK;
+			wps_fail_event(wps->wps, WPS_WSC_DONE,
+				       wps->config_error,
+				       wps->error_indication);
+		}
+		return ret;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
+		return WPS_FAILURE;
+	}
+}
+
+
+int wps_registrar_update_ie(struct wps_registrar *reg)
+{
+	return wps_set_ie(reg);
+}
+
+
+static void wps_registrar_set_selected_timeout(void *eloop_ctx,
+					       void *timeout_ctx)
+{
+	struct wps_registrar *reg = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - "
+		   "unselect internal Registrar");
+	reg->selected_registrar = 0;
+	reg->pbc = 0;
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
+				      struct subscription *s)
+{
+	int i, j;
+	wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
+		   "config_methods=0x%x)",
+		   s->dev_password_id, s->config_methods);
+	reg->sel_reg_union = 1;
+	if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON)
+		reg->sel_reg_dev_password_id_override = s->dev_password_id;
+	if (reg->sel_reg_config_methods_override == -1)
+		reg->sel_reg_config_methods_override = 0;
+	reg->sel_reg_config_methods_override |= s->config_methods;
+	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+		if (is_zero_ether_addr(reg->authorized_macs_union[i]))
+			break;
+	for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
+	     j++) {
+		if (is_zero_ether_addr(s->authorized_macs[j]))
+			break;
+		wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: "
+			   MACSTR, MAC2STR(s->authorized_macs[j]));
+		os_memcpy(reg->authorized_macs_union[i],
+			  s->authorized_macs[j], ETH_ALEN);
+		i++;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union",
+		    (u8 *) reg->authorized_macs_union,
+		    sizeof(reg->authorized_macs_union));
+}
+#endif /* CONFIG_WPS_UPNP */
+
+
+static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
+{
+#ifdef CONFIG_WPS_UPNP
+	struct subscription *s;
+
+	if (reg->wps->wps_upnp == NULL)
+		return;
+
+	dl_list_for_each(s, &reg->wps->wps_upnp->subscriptions,
+			 struct subscription, list) {
+		struct subscr_addr *sa;
+		sa = dl_list_first(&s->addr_list, struct subscr_addr, list);
+		if (sa) {
+			wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d",
+				   inet_ntoa(sa->saddr.sin_addr),
+				   ntohs(sa->saddr.sin_port));
+		}
+		if (s->selected_registrar)
+			wps_registrar_sel_reg_add(reg, s);
+		else
+			wpa_printf(MSG_DEBUG, "WPS: External Registrar not "
+				   "selected");
+	}
+#endif /* CONFIG_WPS_UPNP */
+}
+
+
+/**
+ * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change
+ * @reg: Registrar data from wps_registrar_init()
+ *
+ * This function is called when selected registrar state changes, e.g., when an
+ * AP receives a SetSelectedRegistrar UPnP message.
+ */
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
+
+	reg->sel_reg_union = reg->selected_registrar;
+	reg->sel_reg_dev_password_id_override = -1;
+	reg->sel_reg_config_methods_override = -1;
+	os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
+		  WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)",
+		    (u8 *) reg->authorized_macs_union,
+		    sizeof(reg->authorized_macs_union));
+	if (reg->selected_registrar) {
+		u16 methods;
+
+		methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+#ifdef CONFIG_WPS2
+		methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
+			     WPS_CONFIG_PHY_PUSHBUTTON);
+#endif /* CONFIG_WPS2 */
+		if (reg->pbc) {
+			reg->sel_reg_dev_password_id_override =
+				DEV_PW_PUSHBUTTON;
+			wps_set_pushbutton(&methods, reg->wps->config_methods);
+		}
+		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
+			   "(pbc=%d)", reg->pbc);
+		reg->sel_reg_config_methods_override = methods;
+	} else
+		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
+
+	wps_registrar_sel_reg_union(reg);
+
+	wps_set_ie(reg);
+	wps_cb_set_sel_reg(reg);
+}
+
+
+int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
+			   char *buf, size_t buflen)
+{
+	struct wps_registrar_device *d;
+	int len = 0, ret;
+	char uuid[40];
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+	d = wps_device_get(reg, addr);
+	if (d == NULL)
+		return 0;
+	if (uuid_bin2str(d->uuid, uuid, sizeof(uuid)))
+		return 0;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "wpsUuid=%s\n"
+			  "wpsPrimaryDeviceType=%s\n"
+			  "wpsDeviceName=%s\n"
+			  "wpsManufacturer=%s\n"
+			  "wpsModelName=%s\n"
+			  "wpsModelNumber=%s\n"
+			  "wpsSerialNumber=%s\n",
+			  uuid,
+			  wps_dev_type_bin2str(d->dev.pri_dev_type, devtype,
+					       sizeof(devtype)),
+			  d->dev.device_name ? d->dev.device_name : "",
+			  d->dev.manufacturer ? d->dev.manufacturer : "",
+			  d->dev.model_name ? d->dev.model_name : "",
+			  d->dev.model_number ? d->dev.model_number : "",
+			  d->dev.serial_number ? d->dev.serial_number : "");
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+int wps_registrar_config_ap(struct wps_registrar *reg,
+			    struct wps_credential *cred)
+{
+#ifdef CONFIG_WPS2
+	printf("encr_type=0x%x\n", cred->encr_type);
+	if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
+				 WPS_ENCR_AES))) {
+		if (cred->encr_type & WPS_ENCR_WEP) {
+			wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
+				   "due to WEP configuration");
+			return -1;
+		}
+
+		wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
+			   "invalid encr_type 0x%x", cred->encr_type);
+		return -1;
+	}
+
+	if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
+	    WPS_ENCR_TKIP) {
+		wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
+			   "TKIP+AES");
+		cred->encr_type |= WPS_ENCR_AES;
+	}
+
+	if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+	    WPS_AUTH_WPAPSK) {
+		wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
+			   "WPAPSK+WPA2PSK");
+		cred->auth_type |= WPS_AUTH_WPA2PSK;
+	}
+#endif /* CONFIG_WPS2 */
+
+	if (reg->wps->cred_cb)
+		return reg->wps->cred_cb(reg->wps->cb_ctx, cred);
+
+	return -1;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+				   const u8 *pubkey_hash, u16 pw_id,
+				   const u8 *dev_pw, size_t dev_pw_len)
+{
+	struct wps_nfc_pw_token *token;
+
+	if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
+		return -1;
+
+	wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, pw_id);
+
+	token = os_zalloc(sizeof(*token));
+	if (token == NULL)
+		return -1;
+
+	os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+	token->pw_id = pw_id;
+	os_memcpy(token->dev_pw, dev_pw, dev_pw_len);
+	token->dev_pw_len = dev_pw_len;
+
+	dl_list_add(&reg->nfc_pw_tokens, &token->list);
+
+	reg->selected_registrar = 1;
+	reg->pbc = 0;
+	wps_registrar_add_authorized_mac(reg,
+					 (u8 *) "\xff\xff\xff\xff\xff\xff");
+	wps_registrar_selected_registrar_changed(reg);
+	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+			       wps_registrar_set_selected_timeout,
+			       reg, NULL);
+
+	return 0;
+}
+
+
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+					 const u8 *oob_dev_pw,
+					 size_t oob_dev_pw_len)
+{
+	const u8 *pos, *hash, *dev_pw;
+	u16 id;
+	size_t dev_pw_len;
+
+	if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+	    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+	    oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+	    WPS_OOB_DEVICE_PASSWORD_LEN)
+		return -1;
+
+	hash = oob_dev_pw;
+	pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN;
+	id = WPA_GET_BE16(pos);
+	dev_pw = pos + 2;
+	dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw;
+
+	wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u",
+		   id);
+
+	wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
+		    hash, WPS_OOB_PUBKEY_HASH_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
+
+	return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
+					      dev_pw_len);
+}
+
+
+void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
+				       struct wps_nfc_pw_token *token)
+{
+	wps_registrar_remove_authorized_mac(reg,
+					    (u8 *) "\xff\xff\xff\xff\xff\xff");
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+#endif /* CONFIG_WPS_NFC */

Deleted: vendor/wpa/2.0/src/wps/wps_ufd.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_ufd.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_ufd.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,235 +0,0 @@
-/*
- * UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009, Masashi Honma <honma at ictec.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "wps/wps.h"
-#include "wps/wps_i.h"
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#define UFD_DIR1 "%s\\SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
-#define UFD_FILE UFD_DIR2 "\\%s"
-#else /* CONFIG_NATIVE_WINDOWS */
-#define UFD_DIR1 "%s/SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "/WFAWSC"
-#define UFD_FILE UFD_DIR2 "/%s"
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-struct wps_ufd_data {
-	int ufd_fd;
-};
-
-
-static int dev_pwd_e_file_filter(const struct dirent *entry)
-{
-	unsigned int prefix;
-	char ext[5];
-
-	if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
-		return 0;
-	if (prefix == 0)
-		return 0;
-	if (os_strcasecmp(ext, "WFA") != 0)
-		return 0;
-
-	return 1;
-}
-
-
-static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
-{
-	struct dirent **namelist;
-	int i, file_num;
-
-	file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
-			   alphasort);
-	if (file_num < 0) {
-		wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
-			   errno, strerror(errno));
-		return -1;
-	}
-	if (file_num == 0) {
-		wpa_printf(MSG_ERROR, "WPS: OOB file not found");
-		os_free(namelist);
-		return -1;
-	}
-	os_strlcpy(file_name, namelist[0]->d_name, 13);
-	for (i = 0; i < file_num; i++)
-		os_free(namelist[i]);
-	os_free(namelist);
-	return 0;
-}
-
-
-static int get_file_name(struct wps_context *wps, int registrar,
-			 const char *path, char *file_name)
-{
-	switch (wps->oob_conf.oob_method) {
-	case OOB_METHOD_CRED:
-		os_snprintf(file_name, 13, "00000000.WSC");
-		break;
-	case OOB_METHOD_DEV_PWD_E:
-		if (registrar) {
-			char temp[128];
-			os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
-			if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
-				return -1;
-		} else {
-			u8 *mac_addr = wps->dev.mac_addr;
-
-			os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
-				    mac_addr[2], mac_addr[3], mac_addr[4],
-				    mac_addr[5]);
-		}
-		break;
-	case OOB_METHOD_DEV_PWD_R:
-		os_snprintf(file_name, 13, "00000000.WFA");
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int ufd_mkdir(const char *path)
-{
-	if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
-			   "'%s': %d (%s)", path, errno, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-
-static void * init_ufd(struct wps_context *wps,
-		       struct oob_device_data *oob_dev, int registrar)
-{
-	int write_f;
-	char temp[128];
-	char *path = oob_dev->device_path;
-	char filename[13];
-	struct wps_ufd_data *data;
-	int ufd_fd;
-
-	if (path == NULL)
-		return NULL;
-
-	write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
-		!registrar : registrar;
-
-	if (get_file_name(wps, registrar, path, filename) < 0) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
-		return NULL;
-	}
-
-	if (write_f) {
-		os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
-		if (ufd_mkdir(temp))
-			return NULL;
-		os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
-		if (ufd_mkdir(temp))
-			return NULL;
-	}
-
-	os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
-	if (write_f)
-		ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
-			      S_IRUSR | S_IWUSR);
-	else
-		ufd_fd = open(temp, O_RDONLY);
-	if (ufd_fd < 0) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
-			   temp, strerror(errno));
-		return NULL;
-	}
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->ufd_fd = ufd_fd;
-	return data;
-}
-
-
-static struct wpabuf * read_ufd(void *priv)
-{
-	struct wps_ufd_data *data = priv;
-	struct wpabuf *buf;
-	struct stat s;
-	size_t file_size;
-
-	if (fstat(data->ufd_fd, &s) < 0) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
-		return NULL;
-	}
-
-	file_size = s.st_size;
-	buf = wpabuf_alloc(file_size);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
-			   "buffer");
-		return NULL;
-	}
-
-	if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
-	    (int) file_size) {
-		wpabuf_free(buf);
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
-		return NULL;
-	}
-	wpabuf_put(buf, file_size);
-	return buf;
-}
-
-
-static int write_ufd(void *priv, struct wpabuf *buf)
-{
-	struct wps_ufd_data *data = priv;
-
-	if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
-	    (int) wpabuf_len(buf)) {
-		wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
-		return -1;
-	}
-	return 0;
-}
-
-
-static void deinit_ufd(void *priv)
-{
-	struct wps_ufd_data *data = priv;
-	close(data->ufd_fd);
-	os_free(data);
-}
-
-
-struct oob_device_data oob_ufd_device_data = {
-	.device_name	= NULL,
-	.device_path	= NULL,
-	.init_func	= init_ufd,
-	.read_func	= read_ufd,
-	.write_func	= write_ufd,
-	.deinit_func	= deinit_ufd,
-};

Deleted: vendor/wpa/2.0/src/wps/wps_upnp.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1093 +0,0 @@
-/*
- * UPnP WPS Device
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See below for more details on licensing and code history.
- */
-
-/*
- * This has been greatly stripped down from the original file
- * (upnp_wps_device.c) by Ted Merrill, Atheros Communications
- * in order to eliminate use of the bulky libupnp library etc.
- *
- * History:
- * upnp_wps_device.c is/was a shim layer between wps_opt_upnp.c and
- * the libupnp library.
- * The layering (by Sony) was well done; only a very minor modification
- * to API of upnp_wps_device.c was required.
- * libupnp was found to be undesirable because:
- * -- It consumed too much code and data space
- * -- It uses multiple threads, making debugging more difficult
- *      and possibly reducing reliability.
- * -- It uses static variables and only supports one instance.
- * The shim and libupnp are here replaced by special code written
- * specifically for the needs of hostapd.
- * Various shortcuts can and are taken to keep the code size small.
- * Generally, execution time is not as crucial.
- *
- * BUGS:
- * -- UPnP requires that we be able to resolve domain names.
- * While uncommon, if we have to do it then it will stall the entire
- * hostapd program, which is bad.
- * This is because we use the standard linux getaddrinfo() function
- * which is syncronous.
- * An asyncronous solution would be to use the free "ares" library.
- * -- Does not have a robust output buffering scheme.  Uses a single
- * fixed size output buffer per TCP/HTTP connection, with possible (although
- * unlikely) possibility of overflow and likely excessive use of RAM.
- * A better solution would be to write the HTTP output as a buffered stream,
- * using chunking: (handle header specially, then) generate data with
- * a printf-like function into a buffer, catching buffer full condition,
- * then send it out surrounded by http chunking.
- * -- There is some code that could be separated out into the common
- * library to be shared with wpa_supplicant.
- * -- Needs renaming with module prefix to avoid polluting the debugger
- * namespace and causing possible collisions with other static fncs
- * and structure declarations when using the debugger.
- * -- The http error code generation is pretty bogus, hopefully noone cares.
- *
- * Author: Ted Merrill, Atheros Communications, based upon earlier work
- * as explained above and below.
- *
- * Copyright:
- * Copyright 2008 Atheros Communications.
- *
- * The original header (of upnp_wps_device.c) reads:
- *
- *  Copyright (c) 2006-2007 Sony Corporation. All Rights Reserved.
- *
- *  File Name: upnp_wps_device.c
- *  Description: EAP-WPS UPnP device source
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Sony Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Portions from Intel libupnp files, e.g. genlib/net/http/httpreadwrite.c
- * typical header:
- *
- * Copyright (c) 2000-2003 Intel Corporation
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * * Neither name of Intel Corporation nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
- * Overview of WPS over UPnP:
- *
- * UPnP is a protocol that allows devices to discover each other and control
- * each other. In UPnP terminology, a device is either a "device" (a server
- * that provides information about itself and allows itself to be controlled)
- * or a "control point" (a client that controls "devices") or possibly both.
- * This file implements a UPnP "device".
- *
- * For us, we use mostly basic UPnP discovery, but the control part of interest
- * is WPS carried via UPnP messages. There is quite a bit of basic UPnP
- * discovery to do before we can get to WPS, however.
- *
- * UPnP discovery begins with "devices" send out multicast UDP packets to a
- * certain fixed multicast IP address and port, and "control points" sending
- * out other such UDP packets.
- *
- * The packets sent by devices are NOTIFY packets (not to be confused with TCP
- * NOTIFY packets that are used later) and those sent by control points are
- * M-SEARCH packets. These packets contain a simple HTTP style header. The
- * packets are sent redundantly to get around packet loss. Devices respond to
- * M-SEARCH packets with HTTP-like UDP packets containing HTTP/1.1 200 OK
- * messages, which give similar information as the UDP NOTIFY packets.
- *
- * The above UDP packets advertise the (arbitrary) TCP ports that the
- * respective parties will listen to. The control point can then do a HTTP
- * SUBSCRIBE (something like an HTTP PUT) after which the device can do a
- * separate HTTP NOTIFY (also like an HTTP PUT) to do event messaging.
- *
- * The control point will also do HTTP GET of the "device file" listed in the
- * original UDP information from the device (see UPNP_WPS_DEVICE_XML_FILE
- * data), and based on this will do additional GETs... HTTP POSTs are done to
- * cause an action.
- *
- * Beyond some basic information in HTTP headers, additional information is in
- * the HTTP bodies, in a format set by the SOAP and XML standards, a markup
- * language related to HTML used for web pages. This language is intended to
- * provide the ultimate in self-documentation by providing a universal
- * namespace based on pseudo-URLs called URIs. Note that although a URI looks
- * like a URL (a web address), they are never accessed as such but are used
- * only as identifiers.
- *
- * The POST of a GetDeviceInfo gets information similar to what might be
- * obtained from a probe request or response on Wi-Fi. WPS messages M1-M8
- * are passed via a POST of a PutMessage; the M1-M8 WPS messages are converted
- * to a bin64 ascii representation for encapsulation. When proxying messages,
- * WLANEvent and PutWLANResponse are used.
- *
- * This of course glosses over a lot of details.
- */
-
-#include "includes.h"
-
-#include <assert.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "uuid.h"
-#include "base64.h"
-#include "wps.h"
-#include "wps_i.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-
-
-/*
- * UPnP allows a client ("control point") to send a server like us ("device")
- * a domain name for registration, and we are supposed to resolve it. This is
- * bad because, using the standard Linux library, we will stall the entire
- * hostapd waiting for resolution.
- *
- * The "correct" solution would be to use an event driven library for domain
- * name resolution such as "ares". However, this would increase code size
- * further. Since it is unlikely that we'll actually see such domain names, we
- * can just refuse to accept them.
- */
-#define NO_DOMAIN_NAME_RESOLUTION 1  /* 1 to allow only dotted ip addresses */
-
-
-/*
- * UPnP does not scale well. If we were in a room with thousands of control
- * points then potentially we could be expected to handle subscriptions for
- * each of them, which would exhaust our memory. So we must set a limit. In
- * practice we are unlikely to see more than one or two.
- */
-#define MAX_SUBSCRIPTIONS 4    /* how many subscribing clients we handle */
-#define MAX_ADDR_PER_SUBSCRIPTION 8
-
-
-/* Write the current date/time per RFC */
-void format_date(struct wpabuf *buf)
-{
-	const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
-	const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
-		"Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
-	struct tm *date;
-	time_t t;
-
-	t = time(NULL);
-	date = gmtime(&t);
-	wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
-		      &weekday_str[date->tm_wday * 4], date->tm_mday,
-		      &month_str[date->tm_mon * 4], date->tm_year + 1900,
-		      date->tm_hour, date->tm_min, date->tm_sec);
-}
-
-
-/***************************************************************************
- * UUIDs (unique identifiers)
- *
- * These are supposed to be unique in all the world.
- * Sometimes permanent ones are used, sometimes temporary ones
- * based on random numbers... there are different rules for valid content
- * of different types.
- * Each uuid is 16 bytes long.
- **************************************************************************/
-
-/* uuid_make -- construct a random UUID
- * The UPnP documents don't seem to offer any guidelines as to which method to
- * use for constructing UUIDs for subscriptions. Presumably any method from
- * rfc4122 is good enough; I've chosen random number method.
- */
-static void uuid_make(u8 uuid[UUID_LEN])
-{
-	os_get_random(uuid, UUID_LEN);
-
-	/* Replace certain bits as specified in rfc4122 or X.667 */
-	uuid[6] &= 0x0f; uuid[6] |= (4 << 4);   /* version 4 == random gen */
-	uuid[8] &= 0x3f; uuid[8] |= 0x80;
-}
-
-
-/*
- * Subscriber address handling.
- * Since a subscriber may have an arbitrary number of addresses, we have to
- * add a bunch of code to handle them.
- *
- * Addresses are passed in text, and MAY be domain names instead of the (usual
- * and expected) dotted IP addresses. Resolving domain names consumes a lot of
- * resources. Worse, we are currently using the standard Linux getaddrinfo()
- * which will block the entire program until complete or timeout! The proper
- * solution would be to use the "ares" library or similar with more state
- * machine steps etc. or just disable domain name resolution by setting
- * NO_DOMAIN_NAME_RESOLUTION to 1 at top of this file.
- */
-
-/* subscr_addr_delete -- delete single unlinked subscriber address
- * (be sure to unlink first if need be)
- */
-static void subscr_addr_delete(struct subscr_addr *a)
-{
-	/*
-	 * Note: do NOT free domain_and_port or path because they point to
-	 * memory within the allocation of "a".
-	 */
-	os_free(a);
-}
-
-
-/* subscr_addr_free_all -- unlink and delete list of subscriber addresses. */
-static void subscr_addr_free_all(struct subscription *s)
-{
-	struct subscr_addr *a, *tmp;
-	dl_list_for_each_safe(a, tmp, &s->addr_list, struct subscr_addr, list)
-	{
-		dl_list_del(&a->list);
-		subscr_addr_delete(a);
-	}
-}
-
-
-/* subscr_addr_add_url -- add address(es) for one url to subscription */
-static void subscr_addr_add_url(struct subscription *s, const char *url)
-{
-	int alloc_len;
-	char *scratch_mem = NULL;
-	char *mem;
-	char *domain_and_port;
-	char *delim;
-	char *path;
-	char *domain;
-	int port = 80;  /* port to send to (default is port 80) */
-	struct addrinfo hints;
-	struct addrinfo *result = NULL;
-	struct addrinfo *rp;
-	int rerr;
-	struct subscr_addr *a = NULL;
-
-	/* url MUST begin with http: */
-	if (os_strncasecmp(url, "http://", 7))
-		goto fail;
-	url += 7;
-
-	/* allocate memory for the extra stuff we need */
-	alloc_len = (2 * (os_strlen(url) + 1));
-	scratch_mem = os_zalloc(alloc_len);
-	if (scratch_mem == NULL)
-		goto fail;
-	mem = scratch_mem;
-	strcpy(mem, url);
-	domain_and_port = mem;
-	mem += 1 + os_strlen(mem);
-	delim = os_strchr(domain_and_port, '/');
-	if (delim) {
-		*delim++ = 0;   /* null terminate domain and port */
-		path = delim;
-	} else {
-		path = domain_and_port + os_strlen(domain_and_port);
-	}
-	domain = mem;
-	strcpy(domain, domain_and_port);
-	delim = strchr(domain, ':');
-	if (delim) {
-		*delim++ = 0;   /* null terminate domain */
-		if (isdigit(*delim))
-			port = atol(delim);
-	}
-
-	/*
-	 * getaddrinfo does the right thing with dotted decimal notations, or
-	 * will resolve domain names. Resolving domain names will unfortunately
-	 * hang the entire program until it is resolved or it times out
-	 * internal to getaddrinfo; fortunately we think that the use of actual
-	 * domain names (vs. dotted decimal notations) should be uncommon.
-	 */
-	os_memset(&hints, 0, sizeof(struct addrinfo));
-	hints.ai_family = AF_INET;      /* IPv4 */
-	hints.ai_socktype = SOCK_STREAM;
-#if NO_DOMAIN_NAME_RESOLUTION
-	/* Suppress domain name resolutions that would halt
-	 * the program for periods of time
-	 */
-	hints.ai_flags = AI_NUMERICHOST;
-#else
-	/* Allow domain name resolution. */
-	hints.ai_flags = 0;
-#endif
-	hints.ai_protocol = 0;          /* Any protocol? */
-	rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
-			   &hints, &result);
-	if (rerr) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
-			   rerr, gai_strerror(rerr), domain);
-		goto fail;
-	}
-	for (rp = result; rp; rp = rp->ai_next) {
-		/* Limit no. of address to avoid denial of service attack */
-		if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
-			wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: "
-				   "Ignoring excessive addresses");
-			break;
-		}
-
-		a = os_zalloc(sizeof(*a) + alloc_len);
-		if (a == NULL)
-			continue;
-		mem = (void *) (a + 1);
-		a->domain_and_port = mem;
-		strcpy(mem, domain_and_port);
-		mem += 1 + strlen(mem);
-		a->path = mem;
-		if (path[0] != '/')
-			*mem++ = '/';
-		strcpy(mem, path);
-		mem += 1 + strlen(mem);
-		os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
-		a->saddr.sin_port = htons(port);
-
-		dl_list_add(&s->addr_list, &a->list);
-		a = NULL;       /* don't free it below */
-	}
-
-fail:
-	if (result)
-		freeaddrinfo(result);
-	os_free(scratch_mem);
-	os_free(a);
-}
-
-
-/* subscr_addr_list_create -- create list from urls in string.
- *      Each url is enclosed by angle brackets.
- */
-static void subscr_addr_list_create(struct subscription *s,
-				    const char *url_list)
-{
-	char *end;
-	for (;;) {
-		while (*url_list == ' ' || *url_list == '\t')
-			url_list++;
-		if (*url_list != '<')
-			break;
-		url_list++;
-		end = os_strchr(url_list, '>');
-		if (end == NULL)
-			break;
-		*end++ = 0;
-		subscr_addr_add_url(s, url_list);
-		url_list = end;
-	}
-}
-
-
-int send_wpabuf(int fd, struct wpabuf *buf)
-{
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
-		   (unsigned long) wpabuf_len(buf));
-	errno = 0;
-	if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
-	    (int) wpabuf_len(buf)) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
-			   "errno=%d (%s)",
-			   errno, strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void wpabuf_put_property(struct wpabuf *buf, const char *name,
-				const char *value)
-{
-	wpabuf_put_str(buf, "<e:property>");
-	wpabuf_printf(buf, "<%s>", name);
-	if (value)
-		wpabuf_put_str(buf, value);
-	wpabuf_printf(buf, "</%s>", name);
-	wpabuf_put_str(buf, "</e:property>\n");
-}
-
-
-/**
- * upnp_wps_device_send_event - Queue event messages for subscribers
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- *
- * This function queues the last WLANEvent to be sent for all currently
- * subscribed UPnP control points. sm->wlanevent must have been set with the
- * encoded data before calling this function.
- */
-static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
-{
-	/* Enqueue event message for all subscribers */
-	struct wpabuf *buf; /* holds event message */
-	int buf_size = 0;
-	struct subscription *s, *tmp;
-	/* Actually, utf-8 is the default, but it doesn't hurt to specify it */
-	const char *format_head =
-		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
-		"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
-	const char *format_tail = "</e:propertyset>\n";
-
-	if (dl_list_empty(&sm->subscriptions)) {
-		/* optimize */
-		return;
-	}
-
-	/* Determine buffer size needed first */
-	buf_size += os_strlen(format_head);
-	buf_size += 50 + 2 * os_strlen("WLANEvent");
-	if (sm->wlanevent)
-		buf_size += os_strlen(sm->wlanevent);
-	buf_size += os_strlen(format_tail);
-
-	buf = wpabuf_alloc(buf_size);
-	if (buf == NULL)
-		return;
-	wpabuf_put_str(buf, format_head);
-	wpabuf_put_property(buf, "WLANEvent", sm->wlanevent);
-	wpabuf_put_str(buf, format_tail);
-
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s",
-		   (char *) wpabuf_head(buf));
-
-	dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
-			      list) {
-		if (event_add(s, buf)) {
-			wpa_printf(MSG_INFO, "WPS UPnP: Dropping "
-				   "subscriber due to event backlog");
-			dl_list_del(&s->list);
-			subscription_destroy(s);
-		}
-	}
-
-	wpabuf_free(buf);
-}
-
-
-/*
- * Event subscription (subscriber machines register with us to receive event
- * messages).
- * This is the result of an incoming HTTP over TCP SUBSCRIBE request.
- */
-
-/* subscription_destroy -- destroy an unlinked subscription
- * Be sure to unlink first if necessary.
- */
-void subscription_destroy(struct subscription *s)
-{
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
-	subscr_addr_free_all(s);
-	event_delete_all(s);
-	upnp_er_remove_notification(s);
-	os_free(s);
-}
-
-
-/* subscription_list_age -- remove expired subscriptions */
-static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now)
-{
-	struct subscription *s, *tmp;
-	dl_list_for_each_safe(s, tmp, &sm->subscriptions,
-			      struct subscription, list) {
-		if (s->timeout_time > now)
-			break;
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription");
-		dl_list_del(&s->list);
-		subscription_destroy(s);
-	}
-}
-
-
-/* subscription_find -- return existing subscription matching uuid, if any
- * returns NULL if not found
- */
-struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
-					const u8 uuid[UUID_LEN])
-{
-	struct subscription *s;
-	dl_list_for_each(s, &sm->subscriptions, struct subscription, list) {
-		if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0)
-			return s; /* Found match */
-	}
-	return NULL;
-}
-
-
-static struct wpabuf * build_fake_wsc_ack(void)
-{
-	struct wpabuf *msg = wpabuf_alloc(100);
-	if (msg == NULL)
-		return NULL;
-	wpabuf_put_u8(msg, UPNP_WPS_WLANEVENT_TYPE_EAP);
-	wpabuf_put_str(msg, "00:00:00:00:00:00");
-	if (wps_build_version(msg) ||
-	    wps_build_msg_type(msg, WPS_WSC_ACK)) {
-		wpabuf_free(msg);
-		return NULL;
-	}
-	/* Enrollee Nonce */
-	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put(msg, WPS_NONCE_LEN);
-	/* Registrar Nonce */
-	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put(msg, WPS_NONCE_LEN);
-	return msg;
-}
-
-
-/* subscription_first_event -- send format/queue event that is automatically
- * sent on a new subscription.
- */
-static int subscription_first_event(struct subscription *s)
-{
-	/*
-	 * Actually, utf-8 is the default, but it doesn't hurt to specify it.
-	 *
-	 * APStatus is apparently a bit set,
-	 * 0x1 = configuration change (but is always set?)
-	 * 0x10 = ap is locked
-	 *
-	 * Per UPnP spec, we send out the last value of each variable, even
-	 * for WLANEvent, whatever it was.
-	 */
-	char *wlan_event;
-	struct wpabuf *buf;
-	int ap_status = 1;      /* TODO: add 0x10 if access point is locked */
-	const char *head =
-		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
-		"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
-	const char *tail = "</e:propertyset>\n";
-	char txt[10];
-
-	if (s->sm->wlanevent == NULL) {
-		/*
-		 * There has been no events before the subscription. However,
-		 * UPnP device architecture specification requires all the
-		 * evented variables to be included, so generate a dummy event
-		 * for this particular case using a WSC_ACK and all-zeros
-		 * nonces. The ER (UPnP control point) will ignore this, but at
-		 * least it will learn that WLANEvent variable will be used in
-		 * event notifications in the future.
-		 */
-		struct wpabuf *msg;
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Use a fake WSC_ACK as the "
-			   "initial WLANEvent");
-		msg = build_fake_wsc_ack();
-		if (msg) {
-			s->sm->wlanevent = (char *)
-				base64_encode(wpabuf_head(msg),
-					      wpabuf_len(msg), NULL);
-			wpabuf_free(msg);
-		}
-	}
-
-	wlan_event = s->sm->wlanevent;
-	if (wlan_event == NULL || *wlan_event == '\0') {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for "
-			   "initial event message");
-		wlan_event = "";
-	}
-	buf = wpabuf_alloc(500 + os_strlen(wlan_event));
-	if (buf == NULL)
-		return 1;
-
-	wpabuf_put_str(buf, head);
-	wpabuf_put_property(buf, "STAStatus", "1");
-	os_snprintf(txt, sizeof(txt), "%d", ap_status);
-	wpabuf_put_property(buf, "APStatus", txt);
-	if (*wlan_event)
-		wpabuf_put_property(buf, "WLANEvent", wlan_event);
-	wpabuf_put_str(buf, tail);
-
-	if (event_add(s, buf)) {
-		wpabuf_free(buf);
-		return 1;
-	}
-	wpabuf_free(buf);
-
-	return 0;
-}
-
-
-/**
- * subscription_start - Remember a UPnP control point to send events to.
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @callback_urls: Callback URLs
- * Returns: %NULL on error, or pointer to new subscription structure.
- */
-struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
-					 const char *callback_urls)
-{
-	struct subscription *s;
-	time_t now = time(NULL);
-	time_t expire = now + UPNP_SUBSCRIBE_SEC;
-
-	/* Get rid of expired subscriptions so we have room */
-	subscription_list_age(sm, now);
-
-	/* If too many subscriptions, remove oldest */
-	if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) {
-		s = dl_list_first(&sm->subscriptions, struct subscription,
-				  list);
-		wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
-			   "trashing oldest");
-		dl_list_del(&s->list);
-		subscription_destroy(s);
-	}
-
-	s = os_zalloc(sizeof(*s));
-	if (s == NULL)
-		return NULL;
-	dl_list_init(&s->addr_list);
-	dl_list_init(&s->event_queue);
-
-	s->sm = sm;
-	s->timeout_time = expire;
-	uuid_make(s->uuid);
-	subscr_addr_list_create(s, callback_urls);
-	/* Add to end of list, since it has the highest expiration time */
-	dl_list_add_tail(&sm->subscriptions, &s->list);
-	/* Queue up immediate event message (our last event)
-	 * as required by UPnP spec.
-	 */
-	if (subscription_first_event(s)) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to "
-			   "event backlog");
-		dl_list_del(&s->list);
-		subscription_destroy(s);
-		return NULL;
-	}
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription %p started with %s",
-		   s, callback_urls);
-	/* Schedule sending this */
-	event_send_all_later(sm);
-	return s;
-}
-
-
-/* subscription_renew -- find subscription and reset timeout */
-struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
-					 const u8 uuid[UUID_LEN])
-{
-	time_t now = time(NULL);
-	time_t expire = now + UPNP_SUBSCRIBE_SEC;
-	struct subscription *s = subscription_find(sm, uuid);
-	if (s == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewed");
-	dl_list_del(&s->list);
-	s->timeout_time = expire;
-	/* add back to end of list, since it now has highest expiry */
-	dl_list_add_tail(&sm->subscriptions, &s->list);
-	return s;
-}
-
-
-/**
- * upnp_wps_device_send_wlan_event - Event notification
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @from_mac_addr: Source (Enrollee) MAC address for the event
- * @ev_type: Event type
- * @msg: Event data
- * Returns: 0 on success, -1 on failure
- *
- * Tell external Registrars (UPnP control points) that something happened. In
- * particular, events include WPS messages from clients that are proxied to
- * external Registrars.
- */
-int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
-				    const u8 from_mac_addr[ETH_ALEN],
-				    enum upnp_wps_wlanevent_type ev_type,
-				    const struct wpabuf *msg)
-{
-	int ret = -1;
-	char type[2];
-	const u8 *mac = from_mac_addr;
-	char mac_text[18];
-	u8 *raw = NULL;
-	size_t raw_len;
-	char *val;
-	size_t val_len;
-	int pos = 0;
-
-	if (!sm)
-		goto fail;
-
-	os_snprintf(type, sizeof(type), "%1u", ev_type);
-
-	raw_len = 1 + 17 + (msg ? wpabuf_len(msg) : 0);
-	raw = os_zalloc(raw_len);
-	if (!raw)
-		goto fail;
-
-	*(raw + pos) = (u8) ev_type;
-	pos += 1;
-	os_snprintf(mac_text, sizeof(mac_text), MACSTR, MAC2STR(mac));
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Proxying WLANEvent from %s",
-		   mac_text);
-	os_memcpy(raw + pos, mac_text, 17);
-	pos += 17;
-	if (msg) {
-		os_memcpy(raw + pos, wpabuf_head(msg), wpabuf_len(msg));
-		pos += wpabuf_len(msg);
-	}
-	raw_len = pos;
-
-	val = (char *) base64_encode(raw, raw_len, &val_len);
-	if (val == NULL)
-		goto fail;
-
-	os_free(sm->wlanevent);
-	sm->wlanevent = val;
-	upnp_wps_device_send_event(sm);
-
-	ret = 0;
-
-fail:
-	os_free(raw);
-
-	return ret;
-}
-
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <sys/sysctl.h>
-#include <net/route.h>
-#include <net/if_dl.h>
-
-static int eth_get(const char *device, u8 ea[ETH_ALEN])
-{
-	struct if_msghdr *ifm;
-	struct sockaddr_dl *sdl;
-	u_char *p, *buf;
-	size_t len;
-	int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
-
-	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
-		return -1;
-	if ((buf = os_malloc(len)) == NULL)
-		return -1;
-	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
-		os_free(buf);
-		return -1;
-	}
-	for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
-		ifm = (struct if_msghdr *)p;
-		sdl = (struct sockaddr_dl *)(ifm + 1);
-		if (ifm->ifm_type != RTM_IFINFO ||
-		    (ifm->ifm_addrs & RTA_IFP) == 0)
-			continue;
-		if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
-		    os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
-			continue;
-		os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
-		break;
-	}
-	os_free(buf);
-
-	if (p >= buf + len) {
-		errno = ESRCH;
-		return -1;
-	}
-	return 0;
-}
-#endif /* __FreeBSD__ */
-
-
-/**
- * get_netif_info - Get hw and IP addresses for network device
- * @net_if: Selected network interface name
- * @ip_addr: Buffer for returning IP address in network byte order
- * @ip_addr_text: Buffer for returning a pointer to allocated IP address text
- * @mac: Buffer for returning MAC address
- * Returns: 0 on success, -1 on failure
- */
-int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
-		   u8 mac[ETH_ALEN])
-{
-	struct ifreq req;
-	int sock = -1;
-	struct sockaddr_in *addr;
-	struct in_addr in_addr;
-
-	*ip_addr_text = os_zalloc(16);
-	if (*ip_addr_text == NULL)
-		goto fail;
-
-	sock = socket(AF_INET, SOCK_DGRAM, 0);
-	if (sock < 0)
-		goto fail;
-
-	os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
-	if (ioctl(sock, SIOCGIFADDR, &req) < 0) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFADDR failed: %d (%s)",
-			   errno, strerror(errno));
-		goto fail;
-	}
-	addr = (void *) &req.ifr_addr;
-	*ip_addr = addr->sin_addr.s_addr;
-	in_addr.s_addr = *ip_addr;
-	os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
-
-#ifdef __linux__
-	os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
-	if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFHWADDR failed: "
-			   "%d (%s)", errno, strerror(errno));
-		goto fail;
-	}
-	os_memcpy(mac, req.ifr_addr.sa_data, 6);
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-	if (eth_get(net_if, mac) < 0) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
-		goto fail;
-	}
-#else
-#error MAC address fetch not implemented
-#endif
-
-	close(sock);
-	return 0;
-
-fail:
-	if (sock >= 0)
-		close(sock);
-	os_free(*ip_addr_text);
-	*ip_addr_text = NULL;
-	return -1;
-}
-
-
-static void upnp_wps_free_msearchreply(struct dl_list *head)
-{
-	struct advertisement_state_machine *a, *tmp;
-	dl_list_for_each_safe(a, tmp, head, struct advertisement_state_machine,
-			      list)
-		msearchreply_state_machine_stop(a);
-}
-
-
-static void upnp_wps_free_subscriptions(struct dl_list *head)
-{
-	struct subscription *s, *tmp;
-	dl_list_for_each_safe(s, tmp, head, struct subscription, list) {
-		dl_list_del(&s->list);
-		subscription_destroy(s);
-	}
-}
-
-
-/**
- * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- */
-void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
-{
-	if (!sm || !sm->started)
-		return;
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
-	web_listener_stop(sm);
-	upnp_wps_free_msearchreply(&sm->msearch_replies);
-	upnp_wps_free_subscriptions(&sm->subscriptions);
-
-	advertisement_state_machine_stop(sm, 1);
-
-	event_send_stop_all(sm);
-	os_free(sm->wlanevent);
-	sm->wlanevent = NULL;
-	os_free(sm->ip_addr_text);
-	sm->ip_addr_text = NULL;
-	if (sm->multicast_sd >= 0)
-		close(sm->multicast_sd);
-	sm->multicast_sd = -1;
-	ssdp_listener_stop(sm);
-
-	sm->started = 0;
-}
-
-
-/**
- * upnp_wps_device_start - Start WPS UPnP operations on an interface
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @net_if: Selected network interface name
- * Returns: 0 on success, -1 on failure
- */
-int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
-{
-	if (!sm || !net_if)
-		return -1;
-
-	if (sm->started)
-		upnp_wps_device_stop(sm);
-
-	sm->multicast_sd = -1;
-	sm->ssdp_sd = -1;
-	sm->started = 1;
-	sm->advertise_count = 0;
-
-	/* Fix up linux multicast handling */
-	if (add_ssdp_network(net_if))
-		goto fail;
-
-	/* Determine which IP and mac address we're using */
-	if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text,
-			   sm->mac_addr)) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
-			   "for %s. Does it have IP address?", net_if);
-		goto fail;
-	}
-
-	/* Listen for incoming TCP connections so that others
-	 * can fetch our "xml files" from us.
-	 */
-	if (web_listener_start(sm))
-		goto fail;
-
-	/* Set up for receiving discovery (UDP) packets */
-	if (ssdp_listener_start(sm))
-		goto fail;
-
-	/* Set up for sending multicast */
-	if (ssdp_open_multicast(sm) < 0)
-		goto fail;
-
-	/*
-	 * Broadcast NOTIFY messages to let the world know we exist.
-	 * This is done via a state machine since the messages should not be
-	 * all sent out at once.
-	 */
-	if (advertisement_state_machine_start(sm))
-		goto fail;
-
-	return 0;
-
-fail:
-	upnp_wps_device_stop(sm);
-	return -1;
-}
-
-
-/**
- * upnp_wps_device_deinit - Deinitialize WPS UPnP
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- */
-void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
-{
-	if (!sm)
-		return;
-
-	upnp_wps_device_stop(sm);
-
-	if (sm->peer.wps)
-		wps_deinit(sm->peer.wps);
-	os_free(sm->root_dir);
-	os_free(sm->desc_url);
-	os_free(sm->ctx->ap_pin);
-	os_free(sm->ctx);
-	os_free(sm);
-}
-
-
-/**
- * upnp_wps_device_init - Initialize WPS UPnP
- * @ctx: callback table; we must eventually free it
- * @wps: Pointer to longterm WPS context
- * @priv: External context data that will be used in callbacks
- * Returns: WPS UPnP state or %NULL on failure
- */
-struct upnp_wps_device_sm *
-upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
-		     void *priv)
-{
-	struct upnp_wps_device_sm *sm;
-
-	sm = os_zalloc(sizeof(*sm));
-	if (!sm) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init failed");
-		return NULL;
-	}
-
-	sm->ctx = ctx;
-	sm->wps = wps;
-	sm->priv = priv;
-	dl_list_init(&sm->msearch_replies);
-	dl_list_init(&sm->subscriptions);
-
-	return sm;
-}
-
-
-/**
- * upnp_wps_subscribers - Check whether there are any event subscribers
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 if no subscribers, 1 if subscribers
- */
-int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
-{
-	return !dl_list_empty(&sm->subscriptions);
-}
-
-
-int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
-{
-	if (sm == NULL)
-		return 0;
-
-	os_free(sm->ctx->ap_pin);
-	if (ap_pin) {
-		sm->ctx->ap_pin = os_strdup(ap_pin);
-		if (sm->ctx->ap_pin == NULL)
-			return -1;
-	} else
-		sm->ctx->ap_pin = NULL;
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_upnp.c (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1215 @@
+/*
+ * UPnP WPS Device
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * See below for more details on licensing and code history.
+ */
+
+/*
+ * This has been greatly stripped down from the original file
+ * (upnp_wps_device.c) by Ted Merrill, Atheros Communications
+ * in order to eliminate use of the bulky libupnp library etc.
+ *
+ * History:
+ * upnp_wps_device.c is/was a shim layer between wps_opt_upnp.c and
+ * the libupnp library.
+ * The layering (by Sony) was well done; only a very minor modification
+ * to API of upnp_wps_device.c was required.
+ * libupnp was found to be undesirable because:
+ * -- It consumed too much code and data space
+ * -- It uses multiple threads, making debugging more difficult
+ *      and possibly reducing reliability.
+ * -- It uses static variables and only supports one instance.
+ * The shim and libupnp are here replaced by special code written
+ * specifically for the needs of hostapd.
+ * Various shortcuts can and are taken to keep the code size small.
+ * Generally, execution time is not as crucial.
+ *
+ * BUGS:
+ * -- UPnP requires that we be able to resolve domain names.
+ * While uncommon, if we have to do it then it will stall the entire
+ * hostapd program, which is bad.
+ * This is because we use the standard linux getaddrinfo() function
+ * which is syncronous.
+ * An asyncronous solution would be to use the free "ares" library.
+ * -- Does not have a robust output buffering scheme.  Uses a single
+ * fixed size output buffer per TCP/HTTP connection, with possible (although
+ * unlikely) possibility of overflow and likely excessive use of RAM.
+ * A better solution would be to write the HTTP output as a buffered stream,
+ * using chunking: (handle header specially, then) generate data with
+ * a printf-like function into a buffer, catching buffer full condition,
+ * then send it out surrounded by http chunking.
+ * -- There is some code that could be separated out into the common
+ * library to be shared with wpa_supplicant.
+ * -- Needs renaming with module prefix to avoid polluting the debugger
+ * namespace and causing possible collisions with other static fncs
+ * and structure declarations when using the debugger.
+ * -- The http error code generation is pretty bogus, hopefully no one cares.
+ *
+ * Author: Ted Merrill, Atheros Communications, based upon earlier work
+ * as explained above and below.
+ *
+ * Copyright:
+ * Copyright 2008 Atheros Communications.
+ *
+ * The original header (of upnp_wps_device.c) reads:
+ *
+ *  Copyright (c) 2006-2007 Sony Corporation. All Rights Reserved.
+ *
+ *  File Name: upnp_wps_device.c
+ *  Description: EAP-WPS UPnP device source
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Sony Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions from Intel libupnp files, e.g. genlib/net/http/httpreadwrite.c
+ * typical header:
+ *
+ * Copyright (c) 2000-2003 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Overview of WPS over UPnP:
+ *
+ * UPnP is a protocol that allows devices to discover each other and control
+ * each other. In UPnP terminology, a device is either a "device" (a server
+ * that provides information about itself and allows itself to be controlled)
+ * or a "control point" (a client that controls "devices") or possibly both.
+ * This file implements a UPnP "device".
+ *
+ * For us, we use mostly basic UPnP discovery, but the control part of interest
+ * is WPS carried via UPnP messages. There is quite a bit of basic UPnP
+ * discovery to do before we can get to WPS, however.
+ *
+ * UPnP discovery begins with "devices" send out multicast UDP packets to a
+ * certain fixed multicast IP address and port, and "control points" sending
+ * out other such UDP packets.
+ *
+ * The packets sent by devices are NOTIFY packets (not to be confused with TCP
+ * NOTIFY packets that are used later) and those sent by control points are
+ * M-SEARCH packets. These packets contain a simple HTTP style header. The
+ * packets are sent redundantly to get around packet loss. Devices respond to
+ * M-SEARCH packets with HTTP-like UDP packets containing HTTP/1.1 200 OK
+ * messages, which give similar information as the UDP NOTIFY packets.
+ *
+ * The above UDP packets advertise the (arbitrary) TCP ports that the
+ * respective parties will listen to. The control point can then do a HTTP
+ * SUBSCRIBE (something like an HTTP PUT) after which the device can do a
+ * separate HTTP NOTIFY (also like an HTTP PUT) to do event messaging.
+ *
+ * The control point will also do HTTP GET of the "device file" listed in the
+ * original UDP information from the device (see UPNP_WPS_DEVICE_XML_FILE
+ * data), and based on this will do additional GETs... HTTP POSTs are done to
+ * cause an action.
+ *
+ * Beyond some basic information in HTTP headers, additional information is in
+ * the HTTP bodies, in a format set by the SOAP and XML standards, a markup
+ * language related to HTML used for web pages. This language is intended to
+ * provide the ultimate in self-documentation by providing a universal
+ * namespace based on pseudo-URLs called URIs. Note that although a URI looks
+ * like a URL (a web address), they are never accessed as such but are used
+ * only as identifiers.
+ *
+ * The POST of a GetDeviceInfo gets information similar to what might be
+ * obtained from a probe request or response on Wi-Fi. WPS messages M1-M8
+ * are passed via a POST of a PutMessage; the M1-M8 WPS messages are converted
+ * to a bin64 ascii representation for encapsulation. When proxying messages,
+ * WLANEvent and PutWLANResponse are used.
+ *
+ * This of course glosses over a lot of details.
+ */
+
+#include "includes.h"
+
+#include <time.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "uuid.h"
+#include "base64.h"
+#include "wps.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+
+/*
+ * UPnP allows a client ("control point") to send a server like us ("device")
+ * a domain name for registration, and we are supposed to resolve it. This is
+ * bad because, using the standard Linux library, we will stall the entire
+ * hostapd waiting for resolution.
+ *
+ * The "correct" solution would be to use an event driven library for domain
+ * name resolution such as "ares". However, this would increase code size
+ * further. Since it is unlikely that we'll actually see such domain names, we
+ * can just refuse to accept them.
+ */
+#define NO_DOMAIN_NAME_RESOLUTION 1  /* 1 to allow only dotted ip addresses */
+
+
+/*
+ * UPnP does not scale well. If we were in a room with thousands of control
+ * points then potentially we could be expected to handle subscriptions for
+ * each of them, which would exhaust our memory. So we must set a limit. In
+ * practice we are unlikely to see more than one or two.
+ */
+#define MAX_SUBSCRIPTIONS 4    /* how many subscribing clients we handle */
+#define MAX_ADDR_PER_SUBSCRIPTION 8
+
+/* Maximum number of Probe Request events per second */
+#define MAX_EVENTS_PER_SEC 5
+
+
+static struct upnp_wps_device_sm *shared_upnp_device = NULL;
+
+
+/* Write the current date/time per RFC */
+void format_date(struct wpabuf *buf)
+{
+	const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
+	const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
+		"Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
+	struct tm *date;
+	time_t t;
+
+	t = time(NULL);
+	date = gmtime(&t);
+	wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
+		      &weekday_str[date->tm_wday * 4], date->tm_mday,
+		      &month_str[date->tm_mon * 4], date->tm_year + 1900,
+		      date->tm_hour, date->tm_min, date->tm_sec);
+}
+
+
+/***************************************************************************
+ * UUIDs (unique identifiers)
+ *
+ * These are supposed to be unique in all the world.
+ * Sometimes permanent ones are used, sometimes temporary ones
+ * based on random numbers... there are different rules for valid content
+ * of different types.
+ * Each uuid is 16 bytes long.
+ **************************************************************************/
+
+/* uuid_make -- construct a random UUID
+ * The UPnP documents don't seem to offer any guidelines as to which method to
+ * use for constructing UUIDs for subscriptions. Presumably any method from
+ * rfc4122 is good enough; I've chosen random number method.
+ */
+static void uuid_make(u8 uuid[UUID_LEN])
+{
+	os_get_random(uuid, UUID_LEN);
+
+	/* Replace certain bits as specified in rfc4122 or X.667 */
+	uuid[6] &= 0x0f; uuid[6] |= (4 << 4);   /* version 4 == random gen */
+	uuid[8] &= 0x3f; uuid[8] |= 0x80;
+}
+
+
+/*
+ * Subscriber address handling.
+ * Since a subscriber may have an arbitrary number of addresses, we have to
+ * add a bunch of code to handle them.
+ *
+ * Addresses are passed in text, and MAY be domain names instead of the (usual
+ * and expected) dotted IP addresses. Resolving domain names consumes a lot of
+ * resources. Worse, we are currently using the standard Linux getaddrinfo()
+ * which will block the entire program until complete or timeout! The proper
+ * solution would be to use the "ares" library or similar with more state
+ * machine steps etc. or just disable domain name resolution by setting
+ * NO_DOMAIN_NAME_RESOLUTION to 1 at top of this file.
+ */
+
+/* subscr_addr_delete -- delete single unlinked subscriber address
+ * (be sure to unlink first if need be)
+ */
+void subscr_addr_delete(struct subscr_addr *a)
+{
+	/*
+	 * Note: do NOT free domain_and_port or path because they point to
+	 * memory within the allocation of "a".
+	 */
+	os_free(a);
+}
+
+
+/* subscr_addr_free_all -- unlink and delete list of subscriber addresses. */
+static void subscr_addr_free_all(struct subscription *s)
+{
+	struct subscr_addr *a, *tmp;
+	dl_list_for_each_safe(a, tmp, &s->addr_list, struct subscr_addr, list)
+	{
+		dl_list_del(&a->list);
+		subscr_addr_delete(a);
+	}
+}
+
+
+/* subscr_addr_add_url -- add address(es) for one url to subscription */
+static void subscr_addr_add_url(struct subscription *s, const char *url,
+				size_t url_len)
+{
+	int alloc_len;
+	char *scratch_mem = NULL;
+	char *mem;
+	char *host;
+	char *delim;
+	char *path;
+	int port = 80;  /* port to send to (default is port 80) */
+	struct addrinfo hints;
+	struct addrinfo *result = NULL;
+	struct addrinfo *rp;
+	int rerr;
+	size_t host_len, path_len;
+
+	/* url MUST begin with http: */
+	if (url_len < 7 || os_strncasecmp(url, "http://", 7))
+		goto fail;
+	url += 7;
+	url_len -= 7;
+
+	/* Make a copy of the string to allow modification during parsing */
+	scratch_mem = os_malloc(url_len + 1);
+	if (scratch_mem == NULL)
+		goto fail;
+	os_memcpy(scratch_mem, url, url_len);
+	scratch_mem[url_len] = '\0';
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem);
+	host = scratch_mem;
+	path = os_strchr(host, '/');
+	if (path)
+		*path++ = '\0'; /* null terminate host */
+
+	/* Process and remove optional port component */
+	delim = os_strchr(host, ':');
+	if (delim) {
+		*delim = '\0'; /* null terminate host name for now */
+		if (isdigit(delim[1]))
+			port = atol(delim + 1);
+	}
+
+	/*
+	 * getaddrinfo does the right thing with dotted decimal notations, or
+	 * will resolve domain names. Resolving domain names will unfortunately
+	 * hang the entire program until it is resolved or it times out
+	 * internal to getaddrinfo; fortunately we think that the use of actual
+	 * domain names (vs. dotted decimal notations) should be uncommon.
+	 */
+	os_memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_INET;      /* IPv4 */
+	hints.ai_socktype = SOCK_STREAM;
+#if NO_DOMAIN_NAME_RESOLUTION
+	/* Suppress domain name resolutions that would halt
+	 * the program for periods of time
+	 */
+	hints.ai_flags = AI_NUMERICHOST;
+#else
+	/* Allow domain name resolution. */
+	hints.ai_flags = 0;
+#endif
+	hints.ai_protocol = 0;          /* Any protocol? */
+	rerr = getaddrinfo(host, NULL /* fill in port ourselves */,
+			   &hints, &result);
+	if (rerr) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
+			   rerr, gai_strerror(rerr), host);
+		goto fail;
+	}
+
+	if (delim)
+		*delim = ':'; /* Restore port */
+
+	host_len = os_strlen(host);
+	path_len = path ? os_strlen(path) : 0;
+	alloc_len = host_len + 1 + 1 + path_len + 1;
+
+	for (rp = result; rp; rp = rp->ai_next) {
+		struct subscr_addr *a;
+
+		/* Limit no. of address to avoid denial of service attack */
+		if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) {
+			wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: "
+				   "Ignoring excessive addresses");
+			break;
+		}
+
+		a = os_zalloc(sizeof(*a) + alloc_len);
+		if (a == NULL)
+			break;
+		mem = (char *) (a + 1);
+		a->domain_and_port = mem;
+		os_memcpy(mem, host, host_len);
+		mem += host_len + 1;
+		a->path = mem;
+		if (path == NULL || path[0] != '/')
+			*mem++ = '/';
+		if (path)
+			os_memcpy(mem, path, path_len);
+		os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
+		a->saddr.sin_port = htons(port);
+
+		dl_list_add(&s->addr_list, &a->list);
+	}
+
+fail:
+	if (result)
+		freeaddrinfo(result);
+	os_free(scratch_mem);
+}
+
+
+/* subscr_addr_list_create -- create list from urls in string.
+ *      Each url is enclosed by angle brackets.
+ */
+static void subscr_addr_list_create(struct subscription *s,
+				    const char *url_list)
+{
+	const char *end;
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Parsing URL list '%s'", url_list);
+	for (;;) {
+		while (*url_list == ' ' || *url_list == '\t')
+			url_list++;
+		if (*url_list != '<')
+			break;
+		url_list++;
+		end = os_strchr(url_list, '>');
+		if (end == NULL)
+			break;
+		subscr_addr_add_url(s, url_list, end - url_list);
+		url_list = end + 1;
+	}
+}
+
+
+int send_wpabuf(int fd, struct wpabuf *buf)
+{
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
+		   (unsigned long) wpabuf_len(buf));
+	errno = 0;
+	if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
+	    (int) wpabuf_len(buf)) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
+			   "errno=%d (%s)",
+			   errno, strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void wpabuf_put_property(struct wpabuf *buf, const char *name,
+				const char *value)
+{
+	wpabuf_put_str(buf, "<e:property>");
+	wpabuf_printf(buf, "<%s>", name);
+	if (value)
+		wpabuf_put_str(buf, value);
+	wpabuf_printf(buf, "</%s>", name);
+	wpabuf_put_str(buf, "</e:property>\n");
+}
+
+
+/**
+ * upnp_wps_device_send_event - Queue event messages for subscribers
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ *
+ * This function queues the last WLANEvent to be sent for all currently
+ * subscribed UPnP control points. sm->wlanevent must have been set with the
+ * encoded data before calling this function.
+ */
+static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
+{
+	/* Enqueue event message for all subscribers */
+	struct wpabuf *buf; /* holds event message */
+	int buf_size = 0;
+	struct subscription *s, *tmp;
+	/* Actually, utf-8 is the default, but it doesn't hurt to specify it */
+	const char *format_head =
+		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+		"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
+	const char *format_tail = "</e:propertyset>\n";
+	struct os_time now;
+
+	if (dl_list_empty(&sm->subscriptions)) {
+		/* optimize */
+		return;
+	}
+
+	if (os_get_time(&now) == 0) {
+		if (now.sec != sm->last_event_sec) {
+			sm->last_event_sec = now.sec;
+			sm->num_events_in_sec = 1;
+		} else {
+			sm->num_events_in_sec++;
+			/*
+			 * In theory, this should apply to all WLANEvent
+			 * notifications, but EAP messages are of much higher
+			 * priority and Probe Request notifications should not
+			 * be allowed to drop EAP messages, so only throttle
+			 * Probe Request notifications.
+			 */
+			if (sm->num_events_in_sec > MAX_EVENTS_PER_SEC &&
+			    sm->wlanevent_type ==
+			    UPNP_WPS_WLANEVENT_TYPE_PROBE) {
+				wpa_printf(MSG_DEBUG, "WPS UPnP: Throttle "
+					   "event notifications (%u seen "
+					   "during one second)",
+					   sm->num_events_in_sec);
+				return;
+			}
+		}
+	}
+
+	/* Determine buffer size needed first */
+	buf_size += os_strlen(format_head);
+	buf_size += 50 + 2 * os_strlen("WLANEvent");
+	if (sm->wlanevent)
+		buf_size += os_strlen(sm->wlanevent);
+	buf_size += os_strlen(format_tail);
+
+	buf = wpabuf_alloc(buf_size);
+	if (buf == NULL)
+		return;
+	wpabuf_put_str(buf, format_head);
+	wpabuf_put_property(buf, "WLANEvent", sm->wlanevent);
+	wpabuf_put_str(buf, format_tail);
+
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s",
+		   (char *) wpabuf_head(buf));
+
+	dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
+			      list) {
+		event_add(s, buf,
+			  sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE);
+	}
+
+	wpabuf_free(buf);
+}
+
+
+/*
+ * Event subscription (subscriber machines register with us to receive event
+ * messages).
+ * This is the result of an incoming HTTP over TCP SUBSCRIBE request.
+ */
+
+/* subscription_destroy -- destroy an unlinked subscription
+ * Be sure to unlink first if necessary.
+ */
+void subscription_destroy(struct subscription *s)
+{
+	struct upnp_wps_device_interface *iface;
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
+	subscr_addr_free_all(s);
+	event_delete_all(s);
+	dl_list_for_each(iface, &s->sm->interfaces,
+			 struct upnp_wps_device_interface, list)
+		upnp_er_remove_notification(iface->wps->registrar, s);
+	os_free(s);
+}
+
+
+/* subscription_list_age -- remove expired subscriptions */
+static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now)
+{
+	struct subscription *s, *tmp;
+	dl_list_for_each_safe(s, tmp, &sm->subscriptions,
+			      struct subscription, list) {
+		if (s->timeout_time > now)
+			break;
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription");
+		dl_list_del(&s->list);
+		subscription_destroy(s);
+	}
+}
+
+
+/* subscription_find -- return existing subscription matching uuid, if any
+ * returns NULL if not found
+ */
+struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
+					const u8 uuid[UUID_LEN])
+{
+	struct subscription *s;
+	dl_list_for_each(s, &sm->subscriptions, struct subscription, list) {
+		if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0)
+			return s; /* Found match */
+	}
+	return NULL;
+}
+
+
+static struct wpabuf * build_fake_wsc_ack(void)
+{
+	struct wpabuf *msg = wpabuf_alloc(100);
+	if (msg == NULL)
+		return NULL;
+	wpabuf_put_u8(msg, UPNP_WPS_WLANEVENT_TYPE_EAP);
+	wpabuf_put_str(msg, "00:00:00:00:00:00");
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_ACK)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+	/* Enrollee Nonce */
+	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put(msg, WPS_NONCE_LEN);
+	/* Registrar Nonce */
+	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put(msg, WPS_NONCE_LEN);
+	wps_build_wfa_ext(msg, 0, NULL, 0);
+	return msg;
+}
+
+
+/* subscription_first_event -- send format/queue event that is automatically
+ * sent on a new subscription.
+ */
+static int subscription_first_event(struct subscription *s)
+{
+	/*
+	 * Actually, utf-8 is the default, but it doesn't hurt to specify it.
+	 *
+	 * APStatus is apparently a bit set,
+	 * 0x1 = configuration change (but is always set?)
+	 * 0x10 = ap is locked
+	 *
+	 * Per UPnP spec, we send out the last value of each variable, even
+	 * for WLANEvent, whatever it was.
+	 */
+	char *wlan_event;
+	struct wpabuf *buf;
+	int ap_status = 1;      /* TODO: add 0x10 if access point is locked */
+	const char *head =
+		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+		"<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
+	const char *tail = "</e:propertyset>\n";
+	char txt[10];
+	int ret;
+
+	if (s->sm->wlanevent == NULL) {
+		/*
+		 * There has been no events before the subscription. However,
+		 * UPnP device architecture specification requires all the
+		 * evented variables to be included, so generate a dummy event
+		 * for this particular case using a WSC_ACK and all-zeros
+		 * nonces. The ER (UPnP control point) will ignore this, but at
+		 * least it will learn that WLANEvent variable will be used in
+		 * event notifications in the future.
+		 */
+		struct wpabuf *msg;
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Use a fake WSC_ACK as the "
+			   "initial WLANEvent");
+		msg = build_fake_wsc_ack();
+		if (msg) {
+			s->sm->wlanevent = (char *)
+				base64_encode(wpabuf_head(msg),
+					      wpabuf_len(msg), NULL);
+			wpabuf_free(msg);
+		}
+	}
+
+	wlan_event = s->sm->wlanevent;
+	if (wlan_event == NULL || *wlan_event == '\0') {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for "
+			   "initial event message");
+		wlan_event = "";
+	}
+	buf = wpabuf_alloc(500 + os_strlen(wlan_event));
+	if (buf == NULL)
+		return -1;
+
+	wpabuf_put_str(buf, head);
+	wpabuf_put_property(buf, "STAStatus", "1");
+	os_snprintf(txt, sizeof(txt), "%d", ap_status);
+	wpabuf_put_property(buf, "APStatus", txt);
+	if (*wlan_event)
+		wpabuf_put_property(buf, "WLANEvent", wlan_event);
+	wpabuf_put_str(buf, tail);
+
+	ret = event_add(s, buf, 0);
+	if (ret) {
+		wpabuf_free(buf);
+		return ret;
+	}
+	wpabuf_free(buf);
+
+	return 0;
+}
+
+
+/**
+ * subscription_start - Remember a UPnP control point to send events to.
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @callback_urls: Callback URLs
+ * Returns: %NULL on error, or pointer to new subscription structure.
+ */
+struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
+					 const char *callback_urls)
+{
+	struct subscription *s;
+	time_t now = time(NULL);
+	time_t expire = now + UPNP_SUBSCRIBE_SEC;
+
+	/* Get rid of expired subscriptions so we have room */
+	subscription_list_age(sm, now);
+
+	/* If too many subscriptions, remove oldest */
+	if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) {
+		s = dl_list_first(&sm->subscriptions, struct subscription,
+				  list);
+		wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
+			   "trashing oldest");
+		dl_list_del(&s->list);
+		subscription_destroy(s);
+	}
+
+	s = os_zalloc(sizeof(*s));
+	if (s == NULL)
+		return NULL;
+	dl_list_init(&s->addr_list);
+	dl_list_init(&s->event_queue);
+
+	s->sm = sm;
+	s->timeout_time = expire;
+	uuid_make(s->uuid);
+	subscr_addr_list_create(s, callback_urls);
+	if (dl_list_empty(&s->addr_list)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in "
+			   "'%s' - drop subscription", callback_urls);
+		subscription_destroy(s);
+		return NULL;
+	}
+
+	/* Add to end of list, since it has the highest expiration time */
+	dl_list_add_tail(&sm->subscriptions, &s->list);
+	/* Queue up immediate event message (our last event)
+	 * as required by UPnP spec.
+	 */
+	if (subscription_first_event(s)) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to "
+			   "event backlog");
+		dl_list_del(&s->list);
+		subscription_destroy(s);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription %p started with %s",
+		   s, callback_urls);
+	/* Schedule sending this */
+	event_send_all_later(sm);
+	return s;
+}
+
+
+/* subscription_renew -- find subscription and reset timeout */
+struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
+					 const u8 uuid[UUID_LEN])
+{
+	time_t now = time(NULL);
+	time_t expire = now + UPNP_SUBSCRIBE_SEC;
+	struct subscription *s = subscription_find(sm, uuid);
+	if (s == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewed");
+	dl_list_del(&s->list);
+	s->timeout_time = expire;
+	/* add back to end of list, since it now has highest expiry */
+	dl_list_add_tail(&sm->subscriptions, &s->list);
+	return s;
+}
+
+
+/**
+ * upnp_wps_device_send_wlan_event - Event notification
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @from_mac_addr: Source (Enrollee) MAC address for the event
+ * @ev_type: Event type
+ * @msg: Event data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Tell external Registrars (UPnP control points) that something happened. In
+ * particular, events include WPS messages from clients that are proxied to
+ * external Registrars.
+ */
+int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
+				    const u8 from_mac_addr[ETH_ALEN],
+				    enum upnp_wps_wlanevent_type ev_type,
+				    const struct wpabuf *msg)
+{
+	int ret = -1;
+	char type[2];
+	const u8 *mac = from_mac_addr;
+	char mac_text[18];
+	u8 *raw = NULL;
+	size_t raw_len;
+	char *val;
+	size_t val_len;
+	int pos = 0;
+
+	if (!sm)
+		goto fail;
+
+	os_snprintf(type, sizeof(type), "%1u", ev_type);
+
+	raw_len = 1 + 17 + (msg ? wpabuf_len(msg) : 0);
+	raw = os_zalloc(raw_len);
+	if (!raw)
+		goto fail;
+
+	*(raw + pos) = (u8) ev_type;
+	pos += 1;
+	os_snprintf(mac_text, sizeof(mac_text), MACSTR, MAC2STR(mac));
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Proxying WLANEvent from %s",
+		   mac_text);
+	os_memcpy(raw + pos, mac_text, 17);
+	pos += 17;
+	if (msg) {
+		os_memcpy(raw + pos, wpabuf_head(msg), wpabuf_len(msg));
+		pos += wpabuf_len(msg);
+	}
+	raw_len = pos;
+
+	val = (char *) base64_encode(raw, raw_len, &val_len);
+	if (val == NULL)
+		goto fail;
+
+	os_free(sm->wlanevent);
+	sm->wlanevent = val;
+	sm->wlanevent_type = ev_type;
+	upnp_wps_device_send_event(sm);
+
+	ret = 0;
+
+fail:
+	os_free(raw);
+
+	return ret;
+}
+
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+static int eth_get(const char *device, u8 ea[ETH_ALEN])
+{
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	u_char *p, *buf;
+	size_t len;
+	int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+		return -1;
+	if ((buf = os_malloc(len)) == NULL)
+		return -1;
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		os_free(buf);
+		return -1;
+	}
+	for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
+		ifm = (struct if_msghdr *)p;
+		sdl = (struct sockaddr_dl *)(ifm + 1);
+		if (ifm->ifm_type != RTM_IFINFO ||
+		    (ifm->ifm_addrs & RTA_IFP) == 0)
+			continue;
+		if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
+		    os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
+			continue;
+		os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
+		break;
+	}
+	os_free(buf);
+
+	if (p >= buf + len) {
+		errno = ESRCH;
+		return -1;
+	}
+	return 0;
+}
+#endif /* __FreeBSD__ */
+
+
+/**
+ * get_netif_info - Get hw and IP addresses for network device
+ * @net_if: Selected network interface name
+ * @ip_addr: Buffer for returning IP address in network byte order
+ * @ip_addr_text: Buffer for returning a pointer to allocated IP address text
+ * @mac: Buffer for returning MAC address
+ * Returns: 0 on success, -1 on failure
+ */
+int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
+		   u8 mac[ETH_ALEN])
+{
+	struct ifreq req;
+	int sock = -1;
+	struct sockaddr_in *addr;
+	struct in_addr in_addr;
+
+	*ip_addr_text = os_zalloc(16);
+	if (*ip_addr_text == NULL)
+		goto fail;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0)
+		goto fail;
+
+	os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+	if (ioctl(sock, SIOCGIFADDR, &req) < 0) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFADDR failed: %d (%s)",
+			   errno, strerror(errno));
+		goto fail;
+	}
+	addr = (void *) &req.ifr_addr;
+	*ip_addr = addr->sin_addr.s_addr;
+	in_addr.s_addr = *ip_addr;
+	os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
+
+#ifdef __linux__
+	os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
+	if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFHWADDR failed: "
+			   "%d (%s)", errno, strerror(errno));
+		goto fail;
+	}
+	os_memcpy(mac, req.ifr_addr.sa_data, 6);
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	if (eth_get(net_if, mac) < 0) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
+		goto fail;
+	}
+#else
+#error MAC address fetch not implemented
+#endif
+
+	close(sock);
+	return 0;
+
+fail:
+	if (sock >= 0)
+		close(sock);
+	os_free(*ip_addr_text);
+	*ip_addr_text = NULL;
+	return -1;
+}
+
+
+static void upnp_wps_free_msearchreply(struct dl_list *head)
+{
+	struct advertisement_state_machine *a, *tmp;
+	dl_list_for_each_safe(a, tmp, head, struct advertisement_state_machine,
+			      list)
+		msearchreply_state_machine_stop(a);
+}
+
+
+static void upnp_wps_free_subscriptions(struct dl_list *head,
+					struct wps_registrar *reg)
+{
+	struct subscription *s, *tmp;
+	dl_list_for_each_safe(s, tmp, head, struct subscription, list) {
+		if (reg && s->reg != reg)
+			continue;
+		dl_list_del(&s->list);
+		subscription_destroy(s);
+	}
+}
+
+
+/**
+ * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ */
+static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
+{
+	if (!sm || !sm->started)
+		return;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
+	web_listener_stop(sm);
+	upnp_wps_free_msearchreply(&sm->msearch_replies);
+	upnp_wps_free_subscriptions(&sm->subscriptions, NULL);
+
+	advertisement_state_machine_stop(sm, 1);
+
+	event_send_stop_all(sm);
+	os_free(sm->wlanevent);
+	sm->wlanevent = NULL;
+	os_free(sm->ip_addr_text);
+	sm->ip_addr_text = NULL;
+	if (sm->multicast_sd >= 0)
+		close(sm->multicast_sd);
+	sm->multicast_sd = -1;
+	ssdp_listener_stop(sm);
+
+	sm->started = 0;
+}
+
+
+/**
+ * upnp_wps_device_start - Start WPS UPnP operations on an interface
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @net_if: Selected network interface name
+ * Returns: 0 on success, -1 on failure
+ */
+static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
+{
+	if (!sm || !net_if)
+		return -1;
+
+	if (sm->started)
+		upnp_wps_device_stop(sm);
+
+	sm->multicast_sd = -1;
+	sm->ssdp_sd = -1;
+	sm->started = 1;
+	sm->advertise_count = 0;
+
+	/* Fix up linux multicast handling */
+	if (add_ssdp_network(net_if))
+		goto fail;
+
+	/* Determine which IP and mac address we're using */
+	if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text,
+			   sm->mac_addr)) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
+			   "for %s. Does it have IP address?", net_if);
+		goto fail;
+	}
+
+	/* Listen for incoming TCP connections so that others
+	 * can fetch our "xml files" from us.
+	 */
+	if (web_listener_start(sm))
+		goto fail;
+
+	/* Set up for receiving discovery (UDP) packets */
+	if (ssdp_listener_start(sm))
+		goto fail;
+
+	/* Set up for sending multicast */
+	if (ssdp_open_multicast(sm) < 0)
+		goto fail;
+
+	/*
+	 * Broadcast NOTIFY messages to let the world know we exist.
+	 * This is done via a state machine since the messages should not be
+	 * all sent out at once.
+	 */
+	if (advertisement_state_machine_start(sm))
+		goto fail;
+
+	return 0;
+
+fail:
+	upnp_wps_device_stop(sm);
+	return -1;
+}
+
+
+static struct upnp_wps_device_interface *
+upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv)
+{
+	struct upnp_wps_device_interface *iface;
+	dl_list_for_each(iface, &sm->interfaces,
+			 struct upnp_wps_device_interface, list) {
+		if (iface->priv == priv)
+			return iface;
+	}
+	return NULL;
+}
+
+
+/**
+ * upnp_wps_device_deinit - Deinitialize WPS UPnP
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @priv: External context data that was used in upnp_wps_device_init() call
+ */
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
+{
+	struct upnp_wps_device_interface *iface;
+
+	if (!sm)
+		return;
+
+	iface = upnp_wps_get_iface(sm, priv);
+	if (iface == NULL) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: Could not find the interface "
+			   "instance to deinit");
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Deinit interface instance %p", iface);
+	if (dl_list_len(&sm->interfaces) == 1) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Deinitializing last instance "
+			   "- free global device instance");
+		upnp_wps_device_stop(sm);
+	} else
+		upnp_wps_free_subscriptions(&sm->subscriptions,
+					    iface->wps->registrar);
+	dl_list_del(&iface->list);
+
+	if (iface->peer.wps)
+		wps_deinit(iface->peer.wps);
+	os_free(iface->ctx->ap_pin);
+	os_free(iface->ctx);
+	os_free(iface);
+
+	if (dl_list_empty(&sm->interfaces)) {
+		os_free(sm->root_dir);
+		os_free(sm->desc_url);
+		os_free(sm);
+		shared_upnp_device = NULL;
+	}
+}
+
+
+/**
+ * upnp_wps_device_init - Initialize WPS UPnP
+ * @ctx: callback table; we must eventually free it
+ * @wps: Pointer to longterm WPS context
+ * @priv: External context data that will be used in callbacks
+ * @net_if: Selected network interface name
+ * Returns: WPS UPnP state or %NULL on failure
+ */
+struct upnp_wps_device_sm *
+upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
+		     void *priv, char *net_if)
+{
+	struct upnp_wps_device_sm *sm;
+	struct upnp_wps_device_interface *iface;
+	int start = 0;
+
+	iface = os_zalloc(sizeof(*iface));
+	if (iface == NULL) {
+		os_free(ctx->ap_pin);
+		os_free(ctx);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface);
+
+	iface->ctx = ctx;
+	iface->wps = wps;
+	iface->priv = priv;
+
+	if (shared_upnp_device) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Share existing device "
+			   "context");
+		sm = shared_upnp_device;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Initialize device context");
+		sm = os_zalloc(sizeof(*sm));
+		if (!sm) {
+			wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init "
+				   "failed");
+			os_free(iface);
+			os_free(ctx->ap_pin);
+			os_free(ctx);
+			return NULL;
+		}
+		shared_upnp_device = sm;
+
+		dl_list_init(&sm->msearch_replies);
+		dl_list_init(&sm->subscriptions);
+		dl_list_init(&sm->interfaces);
+		start = 1;
+	}
+
+	dl_list_add(&sm->interfaces, &iface->list);
+
+	if (start && upnp_wps_device_start(sm, net_if)) {
+		upnp_wps_device_deinit(sm, priv);
+		return NULL;
+	}
+
+
+	return sm;
+}
+
+
+/**
+ * upnp_wps_subscribers - Check whether there are any event subscribers
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 if no subscribers, 1 if subscribers
+ */
+int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
+{
+	return !dl_list_empty(&sm->subscriptions);
+}
+
+
+int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
+{
+	struct upnp_wps_device_interface *iface;
+	if (sm == NULL)
+		return 0;
+
+	dl_list_for_each(iface, &sm->interfaces,
+			 struct upnp_wps_device_interface, list) {
+		os_free(iface->ctx->ap_pin);
+		if (ap_pin) {
+			iface->ctx->ap_pin = os_strdup(ap_pin);
+			if (iface->ctx->ap_pin == NULL)
+				return -1;
+		} else
+			iface->ctx->ap_pin = NULL;
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/wps/wps_upnp.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,51 +0,0 @@
-/*
- * UPnP WPS Device
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#ifndef WPS_UPNP_H
-#define WPS_UPNP_H
-
-struct upnp_wps_device_sm;
-struct wps_context;
-struct wps_data;
-
-struct upnp_wps_peer {
-	struct wps_data *wps;
-};
-
-enum upnp_wps_wlanevent_type {
-	UPNP_WPS_WLANEVENT_TYPE_PROBE = 1,
-	UPNP_WPS_WLANEVENT_TYPE_EAP = 2
-};
-
-struct upnp_wps_device_ctx {
-	int (*rx_req_put_wlan_response)(
-		void *priv, enum upnp_wps_wlanevent_type ev_type,
-		const u8 *mac_addr, const struct wpabuf *msg,
-		enum wps_msg_type msg_type);
-
-	char *ap_pin;
-};
-
-struct upnp_wps_device_sm *
-upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
-		     void *priv);
-void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm);
-
-int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if);
-void upnp_wps_device_stop(struct upnp_wps_device_sm *sm);
-
-int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
-				    const u8 from_mac_addr[ETH_ALEN],
-				    enum upnp_wps_wlanevent_type ev_type,
-				    const struct wpabuf *msg);
-int upnp_wps_subscribers(struct upnp_wps_device_sm *sm);
-int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin);
-
-#endif /* WPS_UPNP_H */

Copied: vendor/wpa/2.0/src/wps/wps_upnp.h (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,48 @@
+/*
+ * UPnP WPS Device
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#ifndef WPS_UPNP_H
+#define WPS_UPNP_H
+
+struct upnp_wps_device_sm;
+struct wps_context;
+struct wps_data;
+
+struct upnp_wps_peer {
+	struct wps_data *wps;
+};
+
+enum upnp_wps_wlanevent_type {
+	UPNP_WPS_WLANEVENT_TYPE_PROBE = 1,
+	UPNP_WPS_WLANEVENT_TYPE_EAP = 2
+};
+
+struct upnp_wps_device_ctx {
+	int (*rx_req_put_wlan_response)(
+		void *priv, enum upnp_wps_wlanevent_type ev_type,
+		const u8 *mac_addr, const struct wpabuf *msg,
+		enum wps_msg_type msg_type);
+
+	char *ap_pin;
+};
+
+struct upnp_wps_device_sm *
+upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
+		     void *priv, char *net_if);
+void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv);
+
+int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
+				    const u8 from_mac_addr[ETH_ALEN],
+				    enum upnp_wps_wlanevent_type ev_type,
+				    const struct wpabuf *msg);
+int upnp_wps_subscribers(struct upnp_wps_device_sm *sm);
+int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin);
+
+#endif /* WPS_UPNP_H */

Deleted: vendor/wpa/2.0/src/wps/wps_upnp_ap.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp_ap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp_ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,80 +0,0 @@
-/*
- * Wi-Fi Protected Setup - UPnP AP functionality
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "uuid.h"
-#include "wps_i.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-
-
-static void upnp_er_set_selected_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct subscription *s = eloop_ctx;
-	wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
-	s->selected_registrar = 0;
-	wps_registrar_selected_registrar_changed(s->reg);
-}
-
-
-int upnp_er_set_selected_registrar(struct wps_registrar *reg,
-				   struct subscription *s,
-				   const struct wpabuf *msg)
-{
-	struct wps_parse_attr attr;
-
-	wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
-			msg);
-
-	if (wps_parse_msg(msg, &attr) < 0)
-		return -1;
-	if (!wps_version_supported(attr.version)) {
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar "
-			   "version 0x%x", attr.version ? *attr.version : 0);
-		return -1;
-	}
-
-	s->reg = reg;
-	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
-
-	if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
-		wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
-			   "Selected Registrar");
-		s->selected_registrar = 0;
-	} else {
-		s->selected_registrar = 1;
-		s->dev_password_id = attr.dev_password_id ?
-			WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
-		s->config_methods = attr.sel_reg_config_methods ?
-			WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
-		eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
-				       upnp_er_set_selected_timeout, s, NULL);
-	}
-
-	wps_registrar_selected_registrar_changed(reg);
-
-	return 0;
-}
-
-
-void upnp_er_remove_notification(struct subscription *s)
-{
-	s->selected_registrar = 0;
-	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
-	if (s->reg)
-		wps_registrar_selected_registrar_changed(s->reg);
-}

Copied: vendor/wpa/2.0/src/wps/wps_upnp_ap.c (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp_ap.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp_ap.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp_ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,87 @@
+/*
+ * Wi-Fi Protected Setup - UPnP AP functionality
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+
+static void upnp_er_set_selected_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct subscription *s = eloop_ctx;
+	struct wps_registrar *reg = timeout_ctx;
+	wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
+	s->selected_registrar = 0;
+	wps_registrar_selected_registrar_changed(reg);
+}
+
+
+int upnp_er_set_selected_registrar(struct wps_registrar *reg,
+				   struct subscription *s,
+				   const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
+			msg);
+	if (wps_validate_upnp_set_selected_registrar(msg) < 0)
+		return -1;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return -1;
+
+	s->reg = reg;
+	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
+
+	os_memset(s->authorized_macs, 0, sizeof(s->authorized_macs));
+	if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
+			   "Selected Registrar");
+		s->selected_registrar = 0;
+	} else {
+		s->selected_registrar = 1;
+		s->dev_password_id = attr.dev_password_id ?
+			WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
+		s->config_methods = attr.sel_reg_config_methods ?
+			WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+		if (attr.authorized_macs) {
+			int count = attr.authorized_macs_len / ETH_ALEN;
+			if (count > WPS_MAX_AUTHORIZED_MACS)
+				count = WPS_MAX_AUTHORIZED_MACS;
+			os_memcpy(s->authorized_macs, attr.authorized_macs,
+				  count * ETH_ALEN);
+		} else if (!attr.version2) {
+#ifdef CONFIG_WPS2
+			wpa_printf(MSG_DEBUG, "WPS: Add broadcast "
+				   "AuthorizedMACs for WPS 1.0 ER");
+			os_memset(s->authorized_macs, 0xff, ETH_ALEN);
+#endif /* CONFIG_WPS2 */
+		}
+		eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+				       upnp_er_set_selected_timeout, s, reg);
+	}
+
+	wps_registrar_selected_registrar_changed(reg);
+
+	return 0;
+}
+
+
+void upnp_er_remove_notification(struct wps_registrar *reg,
+				 struct subscription *s)
+{
+	s->selected_registrar = 0;
+	eloop_cancel_timeout(upnp_er_set_selected_timeout, s, reg);
+	if (reg)
+		wps_registrar_selected_registrar_changed(reg);
+}

Deleted: vendor/wpa/2.0/src/wps/wps_upnp_event.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp_event.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp_event.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,357 +0,0 @@
-/*
- * UPnP WPS Device - Event processing
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#include "includes.h"
-#include <assert.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "uuid.h"
-#include "http_client.h"
-#include "wps_defs.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-
-/*
- * Event message generation (to subscribers)
- *
- * We make a separate copy for each message for each subscriber. This memory
- * wasted could be limited (adding code complexity) by sharing copies, keeping
- * a usage count and freeing when zero.
- *
- * Sending a message requires using a HTTP over TCP NOTIFY
- * (like a PUT) which requires a number of states..
- */
-
-#define MAX_EVENTS_QUEUED 20   /* How far behind queued events */
-#define EVENT_TIMEOUT_SEC 30   /* Drop sending event after timeout */
-
-/* How long to wait before sending event */
-#define EVENT_DELAY_SECONDS 0
-#define EVENT_DELAY_MSEC 0
-
-/*
- * Event information that we send to each subscriber is remembered in this
- * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
- * over TCP transaction which requires various states.. It may also need to be
- * retried at a different address (if more than one is available).
- *
- * TODO: As an optimization we could share data between subscribers.
- */
-struct wps_event_ {
-	struct dl_list list;
-	struct subscription *s;         /* parent */
-	unsigned subscriber_sequence;   /* which event for this subscription*/
-	unsigned int retry;             /* which retry */
-	struct subscr_addr *addr;       /* address to connect to */
-	struct wpabuf *data;            /* event data to send */
-	struct http_client *http_event;
-};
-
-
-/* event_clean -- clean sockets etc. of event
- * Leaves data, retry count etc. alone.
- */
-static void event_clean(struct wps_event_ *e)
-{
-	if (e->s->current_event == e)
-		e->s->current_event = NULL;
-	http_client_free(e->http_event);
-	e->http_event = NULL;
-}
-
-
-/* event_delete -- delete single unqueued event
- * (be sure to dequeue first if need be)
- */
-static void event_delete(struct wps_event_ *e)
-{
-	event_clean(e);
-	wpabuf_free(e->data);
-	os_free(e);
-}
-
-
-/* event_dequeue -- get next event from the queue
- * Returns NULL if empty.
- */
-static struct wps_event_ *event_dequeue(struct subscription *s)
-{
-	struct wps_event_ *e;
-	e = dl_list_first(&s->event_queue, struct wps_event_, list);
-	if (e)
-		dl_list_del(&e->list);
-	return e;
-}
-
-
-/* event_delete_all -- delete entire event queue and current event */
-void event_delete_all(struct subscription *s)
-{
-	struct wps_event_ *e;
-	while ((e = event_dequeue(s)) != NULL)
-		event_delete(e);
-	if (s->current_event) {
-		event_delete(s->current_event);
-		/* will set: s->current_event = NULL;  */
-	}
-}
-
-
-/**
- * event_retry - Called when we had a failure delivering event msg
- * @e: Event
- * @do_next_address: skip address e.g. on connect fail
- */
-static void event_retry(struct wps_event_ *e, int do_next_address)
-{
-	struct subscription *s = e->s;
-	struct upnp_wps_device_sm *sm = s->sm;
-
-	event_clean(e);
-	/* will set: s->current_event = NULL; */
-
-	if (do_next_address)
-		e->retry++;
-	if (e->retry >= dl_list_len(&s->addr_list)) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
-			   "for %s", e->addr->domain_and_port);
-		return;
-	}
-	dl_list_add(&s->event_queue, &e->list);
-	event_send_all_later(sm);
-}
-
-
-static struct wpabuf * event_build_message(struct wps_event_ *e)
-{
-	struct wpabuf *buf;
-	char *b;
-
-	buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
-	if (buf == NULL)
-		return NULL;
-	wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
-	wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
-	wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
-	wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
-		       "NT: upnp:event\r\n"
-		       "NTS: upnp:propchange\r\n");
-	wpabuf_put_str(buf, "SID: uuid:");
-	b = wpabuf_put(buf, 0);
-	uuid_bin2str(e->s->uuid, b, 80);
-	wpabuf_put(buf, os_strlen(b));
-	wpabuf_put_str(buf, "\r\n");
-	wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
-	wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
-		      (int) wpabuf_len(e->data));
-	wpabuf_put_str(buf, "\r\n"); /* terminating empty line */
-	wpabuf_put_buf(buf, e->data);
-	return buf;
-}
-
-
-static void event_http_cb(void *ctx, struct http_client *c,
-			  enum http_client_event event)
-{
-	struct wps_event_ *e = ctx;
-	struct subscription *s = e->s;
-
-	switch (event) {
-	case HTTP_CLIENT_OK:
-		wpa_printf(MSG_DEBUG,
-			   "WPS UPnP: Got event reply OK from "
-			   "%s", e->addr->domain_and_port);
-		event_delete(e);
-
-		/* Schedule sending more if there is more to send */
-		if (!dl_list_empty(&s->event_queue))
-			event_send_all_later(s->sm);
-		break;
-	case HTTP_CLIENT_FAILED:
-	case HTTP_CLIENT_INVALID_REPLY:
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event to %s",
-			   e->addr->domain_and_port);
-
-		/*
-		 * If other side doesn't like what we say, forget about them.
-		 * (There is no way to tell other side that we are dropping
-		 * them...).
-		 * Alternately, we could just do event_delete(e)
-		 */
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription due to "
-			   "errors");
-		dl_list_del(&s->list);
-		subscription_destroy(s);
-		break;
-	case HTTP_CLIENT_TIMEOUT:
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
-		event_retry(e, 1);
-	}
-}
-
-
-/* event_send_start -- prepare to send a event message to subscriber
- *
- * This gets complicated because:
- * -- The message is sent via TCP and we have to keep the stream open
- *      for 30 seconds to get a response... then close it.
- * -- But we might have other event happen in the meantime...
- *      we have to queue them, if we lose them then the subscriber will
- *      be forced to unsubscribe and subscribe again.
- * -- If multiple URLs are provided then we are supposed to try successive
- *      ones after 30 second timeout.
- * -- The URLs might use domain names instead of dotted decimal addresses,
- *      and resolution of those may cause unwanted sleeping.
- * -- Doing the initial TCP connect can take a while, so we have to come
- *      back after connection and then send the data.
- *
- * Returns nonzero on error;
- *
- * Prerequisite: No current event send (s->current_event == NULL)
- *      and non-empty queue.
- */
-static int event_send_start(struct subscription *s)
-{
-	struct wps_event_ *e;
-	unsigned int itry;
-	struct wpabuf *buf;
-
-	/*
-	 * Assume we are called ONLY with no current event and ONLY with
-	 * nonempty event queue and ONLY with at least one address to send to.
-	 */
-	assert(!dl_list_empty(&s->addr_list));
-	assert(s->current_event == NULL);
-	assert(!dl_list_empty(&s->event_queue));
-
-	s->current_event = e = event_dequeue(s);
-
-	/* Use address according to number of retries */
-	itry = 0;
-	dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list)
-		if (itry++ == e->retry)
-			break;
-	if (itry < e->retry)
-		return -1;
-
-	buf = event_build_message(e);
-	if (buf == NULL) {
-		event_retry(e, 0);
-		return -1;
-	}
-
-	e->http_event = http_client_addr(&e->addr->saddr, buf, 0,
-					 event_http_cb, e);
-	if (e->http_event == NULL) {
-		wpabuf_free(buf);
-		event_retry(e, 0);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/* event_send_all_later_handler -- actually send events as needed */
-static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
-{
-	struct upnp_wps_device_sm *sm = user_ctx;
-	struct subscription *s, *tmp;
-	int nerrors = 0;
-
-	sm->event_send_all_queued = 0;
-	dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
-			      list) {
-		if (dl_list_empty(&s->addr_list)) {
-			/* if we've given up on all addresses */
-			wpa_printf(MSG_DEBUG, "WPS UPnP: Removing "
-				   "subscription with no addresses");
-			dl_list_del(&s->list);
-			subscription_destroy(s);
-		} else {
-			if (s->current_event == NULL /* not busy */ &&
-			    !dl_list_empty(&s->event_queue) /* more to do */) {
-				if (event_send_start(s))
-					nerrors++;
-			}
-		}
-	}
-
-	if (nerrors) {
-		/* Try again later */
-		event_send_all_later(sm);
-	}
-}
-
-
-/* event_send_all_later -- schedule sending events to all subscribers
- * that need it.
- * This avoids two problems:
- * -- After getting a subscription, we should not send the first event
- *      until after our reply is fully queued to be sent back,
- * -- Possible stack depth or infinite recursion issues.
- */
-void event_send_all_later(struct upnp_wps_device_sm *sm)
-{
-	/*
-	 * The exact time in the future isn't too important. Waiting a bit
-	 * might let us do several together.
-	 */
-	if (sm->event_send_all_queued)
-		return;
-	sm->event_send_all_queued = 1;
-	eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
-			       event_send_all_later_handler, NULL, sm);
-}
-
-
-/* event_send_stop_all -- cleanup */
-void event_send_stop_all(struct upnp_wps_device_sm *sm)
-{
-	if (sm->event_send_all_queued)
-		eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
-	sm->event_send_all_queued = 0;
-}
-
-
-/**
- * event_add - Add a new event to a queue
- * @s: Subscription
- * @data: Event data (is copied; caller retains ownership)
- * Returns: 0 on success, 1 on error
- */
-int event_add(struct subscription *s, const struct wpabuf *data)
-{
-	struct wps_event_ *e;
-
-	if (dl_list_len(&s->event_queue) >= MAX_EVENTS_QUEUED) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
-			   "subscriber");
-		return 1;
-	}
-
-	e = os_zalloc(sizeof(*e));
-	if (e == NULL)
-		return 1;
-	dl_list_init(&e->list);
-	e->s = s;
-	e->data = wpabuf_dup(data);
-	if (e->data == NULL) {
-		os_free(e);
-		return 1;
-	}
-	e->subscriber_sequence = s->next_subscriber_sequence++;
-	if (s->next_subscriber_sequence == 0)
-		s->next_subscriber_sequence++;
-	dl_list_add_tail(&s->event_queue, &e->list);
-	event_send_all_later(s->sm);
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_upnp_event.c (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp_event.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp_event.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp_event.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,423 @@
+/*
+ * UPnP WPS Device - Event processing
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+#include <assert.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "http_client.h"
+#include "wps_defs.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+/*
+ * Event message generation (to subscribers)
+ *
+ * We make a separate copy for each message for each subscriber. This memory
+ * wasted could be limited (adding code complexity) by sharing copies, keeping
+ * a usage count and freeing when zero.
+ *
+ * Sending a message requires using a HTTP over TCP NOTIFY
+ * (like a PUT) which requires a number of states..
+ */
+
+#define MAX_EVENTS_QUEUED 20   /* How far behind queued events */
+#define MAX_FAILURES 10 /* Drop subscription after this many failures */
+
+/* How long to wait before sending event */
+#define EVENT_DELAY_SECONDS 0
+#define EVENT_DELAY_MSEC 0
+
+/*
+ * Event information that we send to each subscriber is remembered in this
+ * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
+ * over TCP transaction which requires various states.. It may also need to be
+ * retried at a different address (if more than one is available).
+ *
+ * TODO: As an optimization we could share data between subscribers.
+ */
+struct wps_event_ {
+	struct dl_list list;
+	struct subscription *s;         /* parent */
+	unsigned subscriber_sequence;   /* which event for this subscription*/
+	unsigned int retry;             /* which retry */
+	struct subscr_addr *addr;       /* address to connect to */
+	struct wpabuf *data;            /* event data to send */
+	struct http_client *http_event;
+};
+
+
+/* event_clean -- clean sockets etc. of event
+ * Leaves data, retry count etc. alone.
+ */
+static void event_clean(struct wps_event_ *e)
+{
+	if (e->s->current_event == e)
+		e->s->current_event = NULL;
+	http_client_free(e->http_event);
+	e->http_event = NULL;
+}
+
+
+/* event_delete -- delete single unqueued event
+ * (be sure to dequeue first if need be)
+ */
+static void event_delete(struct wps_event_ *e)
+{
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Delete event %p", e);
+	event_clean(e);
+	wpabuf_free(e->data);
+	os_free(e);
+}
+
+
+/* event_dequeue -- get next event from the queue
+ * Returns NULL if empty.
+ */
+static struct wps_event_ *event_dequeue(struct subscription *s)
+{
+	struct wps_event_ *e;
+	e = dl_list_first(&s->event_queue, struct wps_event_, list);
+	if (e) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Dequeue event %p for "
+			   "subscription %p", e, s);
+		dl_list_del(&e->list);
+	}
+	return e;
+}
+
+
+/* event_delete_all -- delete entire event queue and current event */
+void event_delete_all(struct subscription *s)
+{
+	struct wps_event_ *e;
+	while ((e = event_dequeue(s)) != NULL)
+		event_delete(e);
+	if (s->current_event) {
+		event_delete(s->current_event);
+		/* will set: s->current_event = NULL;  */
+	}
+}
+
+
+/**
+ * event_retry - Called when we had a failure delivering event msg
+ * @e: Event
+ * @do_next_address: skip address e.g. on connect fail
+ */
+static void event_retry(struct wps_event_ *e, int do_next_address)
+{
+	struct subscription *s = e->s;
+	struct upnp_wps_device_sm *sm = s->sm;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Retry event %p for subscription %p",
+		   e, s);
+	event_clean(e);
+	/* will set: s->current_event = NULL; */
+
+	if (do_next_address) {
+		e->retry++;
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Try address %d", e->retry);
+	}
+	if (e->retry >= dl_list_len(&s->addr_list)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
+			   "for %s", e->addr->domain_and_port);
+		event_delete(e);
+		s->last_event_failed = 1;
+		if (!dl_list_empty(&s->event_queue))
+			event_send_all_later(s->sm);
+		return;
+	}
+	dl_list_add(&s->event_queue, &e->list);
+	event_send_all_later(sm);
+}
+
+
+static struct wpabuf * event_build_message(struct wps_event_ *e)
+{
+	struct wpabuf *buf;
+	char *b;
+
+	buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
+	if (buf == NULL)
+		return NULL;
+	wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
+	wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
+	wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
+	wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+		       "NT: upnp:event\r\n"
+		       "NTS: upnp:propchange\r\n");
+	wpabuf_put_str(buf, "SID: uuid:");
+	b = wpabuf_put(buf, 0);
+	uuid_bin2str(e->s->uuid, b, 80);
+	wpabuf_put(buf, os_strlen(b));
+	wpabuf_put_str(buf, "\r\n");
+	wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
+	wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
+		      (int) wpabuf_len(e->data));
+	wpabuf_put_str(buf, "\r\n"); /* terminating empty line */
+	wpabuf_put_buf(buf, e->data);
+	return buf;
+}
+
+
+static void event_addr_failure(struct wps_event_ *e)
+{
+	struct subscription *s = e->s;
+
+	e->addr->num_failures++;
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event %p to %s "
+		   "(num_failures=%u)",
+		   e, e->addr->domain_and_port, e->addr->num_failures);
+
+	if (e->addr->num_failures < MAX_FAILURES) {
+		/* Try other addresses, if available */
+		event_retry(e, 1);
+		return;
+	}
+
+	/*
+	 * If other side doesn't like what we say, forget about them.
+	 * (There is no way to tell other side that we are dropping them...).
+	 */
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription %p "
+		   "address %s due to errors", s, e->addr->domain_and_port);
+	dl_list_del(&e->addr->list);
+	subscr_addr_delete(e->addr);
+	e->addr = NULL;
+
+	if (dl_list_empty(&s->addr_list)) {
+		/* if we've given up on all addresses */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Removing subscription %p "
+			   "with no addresses", s);
+		dl_list_del(&s->list);
+		subscription_destroy(s);
+		return;
+	}
+
+	/* Try other addresses, if available */
+	event_retry(e, 0);
+}
+
+
+static void event_http_cb(void *ctx, struct http_client *c,
+			  enum http_client_event event)
+{
+	struct wps_event_ *e = ctx;
+	struct subscription *s = e->s;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP client callback: e=%p c=%p "
+		   "event=%d", e, c, event);
+	switch (event) {
+	case HTTP_CLIENT_OK:
+		wpa_printf(MSG_DEBUG,
+			   "WPS UPnP: Got event %p reply OK from %s",
+			   e, e->addr->domain_and_port);
+		e->addr->num_failures = 0;
+		s->last_event_failed = 0;
+		event_delete(e);
+
+		/* Schedule sending more if there is more to send */
+		if (!dl_list_empty(&s->event_queue))
+			event_send_all_later(s->sm);
+		break;
+	case HTTP_CLIENT_FAILED:
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
+		event_addr_failure(e);
+		break;
+	case HTTP_CLIENT_INVALID_REPLY:
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid reply");
+		event_addr_failure(e);
+		break;
+	case HTTP_CLIENT_TIMEOUT:
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
+		event_addr_failure(e);
+		break;
+	}
+}
+
+
+/* event_send_start -- prepare to send a event message to subscriber
+ *
+ * This gets complicated because:
+ * -- The message is sent via TCP and we have to keep the stream open
+ *      for 30 seconds to get a response... then close it.
+ * -- But we might have other event happen in the meantime...
+ *      we have to queue them, if we lose them then the subscriber will
+ *      be forced to unsubscribe and subscribe again.
+ * -- If multiple URLs are provided then we are supposed to try successive
+ *      ones after 30 second timeout.
+ * -- The URLs might use domain names instead of dotted decimal addresses,
+ *      and resolution of those may cause unwanted sleeping.
+ * -- Doing the initial TCP connect can take a while, so we have to come
+ *      back after connection and then send the data.
+ *
+ * Returns nonzero on error;
+ *
+ * Prerequisite: No current event send (s->current_event == NULL)
+ *      and non-empty queue.
+ */
+static int event_send_start(struct subscription *s)
+{
+	struct wps_event_ *e;
+	unsigned int itry;
+	struct wpabuf *buf;
+
+	/*
+	 * Assume we are called ONLY with no current event and ONLY with
+	 * nonempty event queue and ONLY with at least one address to send to.
+	 */
+	if (dl_list_empty(&s->addr_list))
+		return -1;
+	if (s->current_event)
+		return -1;
+	if (dl_list_empty(&s->event_queue))
+		return -1;
+
+	s->current_event = e = event_dequeue(s);
+
+	/* Use address according to number of retries */
+	itry = 0;
+	dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list)
+		if (itry++ == e->retry)
+			break;
+	if (itry < e->retry)
+		return -1;
+
+	buf = event_build_message(e);
+	if (buf == NULL) {
+		event_retry(e, 0);
+		return -1;
+	}
+
+	e->http_event = http_client_addr(&e->addr->saddr, buf, 0,
+					 event_http_cb, e);
+	if (e->http_event == NULL) {
+		wpabuf_free(buf);
+		event_retry(e, 0);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/* event_send_all_later_handler -- actually send events as needed */
+static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
+{
+	struct upnp_wps_device_sm *sm = user_ctx;
+	struct subscription *s, *tmp;
+	int nerrors = 0;
+
+	sm->event_send_all_queued = 0;
+	dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
+			      list) {
+		if (s->current_event == NULL /* not busy */ &&
+		    !dl_list_empty(&s->event_queue) /* more to do */) {
+			if (event_send_start(s))
+				nerrors++;
+		}
+	}
+
+	if (nerrors) {
+		/* Try again later */
+		event_send_all_later(sm);
+	}
+}
+
+
+/* event_send_all_later -- schedule sending events to all subscribers
+ * that need it.
+ * This avoids two problems:
+ * -- After getting a subscription, we should not send the first event
+ *      until after our reply is fully queued to be sent back,
+ * -- Possible stack depth or infinite recursion issues.
+ */
+void event_send_all_later(struct upnp_wps_device_sm *sm)
+{
+	/*
+	 * The exact time in the future isn't too important. Waiting a bit
+	 * might let us do several together.
+	 */
+	if (sm->event_send_all_queued)
+		return;
+	sm->event_send_all_queued = 1;
+	eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
+			       event_send_all_later_handler, NULL, sm);
+}
+
+
+/* event_send_stop_all -- cleanup */
+void event_send_stop_all(struct upnp_wps_device_sm *sm)
+{
+	if (sm->event_send_all_queued)
+		eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
+	sm->event_send_all_queued = 0;
+}
+
+
+/**
+ * event_add - Add a new event to a queue
+ * @s: Subscription
+ * @data: Event data (is copied; caller retains ownership)
+ * @probereq: Whether this is a Probe Request event
+ * Returns: 0 on success, -1 on error, 1 on max event queue limit reached
+ */
+int event_add(struct subscription *s, const struct wpabuf *data, int probereq)
+{
+	struct wps_event_ *e;
+	unsigned int len;
+
+	len = dl_list_len(&s->event_queue);
+	if (len >= MAX_EVENTS_QUEUED) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
+			   "subscriber %p", s);
+		if (probereq)
+			return 1;
+
+		/* Drop oldest entry to allow EAP event to be stored. */
+		e = event_dequeue(s);
+		if (!e)
+			return 1;
+		event_delete(e);
+	}
+
+	if (s->last_event_failed && probereq && len > 0) {
+		/*
+		 * Avoid queuing frames for subscribers that may have left
+		 * without unsubscribing.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Do not queue more Probe "
+			   "Request frames for subscription %p since last "
+			   "delivery failed", s);
+		return -1;
+	}
+
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL)
+		return -1;
+	dl_list_init(&e->list);
+	e->s = s;
+	e->data = wpabuf_dup(data);
+	if (e->data == NULL) {
+		os_free(e);
+		return -1;
+	}
+	e->subscriber_sequence = s->next_subscriber_sequence++;
+	if (s->next_subscriber_sequence == 0)
+		s->next_subscriber_sequence++;
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
+		   "(queue len %u)", e, s, len + 1);
+	dl_list_add_tail(&s->event_queue, &e->list);
+	event_send_all_later(s->sm);
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/wps/wps_upnp_i.h
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,179 +0,0 @@
-/*
- * UPnP for WPS / internal definitions
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#ifndef WPS_UPNP_I_H
-#define WPS_UPNP_I_H
-
-#include "utils/list.h"
-#include "http.h"
-
-#define UPNP_MULTICAST_ADDRESS  "239.255.255.250" /* for UPnP multicasting */
-#define UPNP_MULTICAST_PORT 1900 /* UDP port to monitor for UPnP */
-
-/* min subscribe time per UPnP standard */
-#define UPNP_SUBSCRIBE_SEC_MIN 1800
-/* subscribe time we use */
-#define UPNP_SUBSCRIBE_SEC (UPNP_SUBSCRIBE_SEC_MIN + 1)
-
-/* "filenames" used in URLs that we service via our "web server": */
-#define UPNP_WPS_DEVICE_XML_FILE "wps_device.xml"
-#define UPNP_WPS_SCPD_XML_FILE   "wps_scpd.xml"
-#define UPNP_WPS_DEVICE_CONTROL_FILE "wps_control"
-#define UPNP_WPS_DEVICE_EVENT_FILE "wps_event"
-
-#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
-
-
-struct upnp_wps_device_sm;
-struct wps_registrar;
-
-
-enum advertisement_type_enum {
-	ADVERTISE_UP = 0,
-	ADVERTISE_DOWN = 1,
-	MSEARCH_REPLY = 2
-};
-
-/*
- * Advertisements are broadcast via UDP NOTIFYs, and are also the essence of
- * the reply to UDP M-SEARCH requests. This struct handles both cases.
- *
- * A state machine is needed because a number of variant forms must be sent in
- * separate packets and spread out in time to avoid congestion.
- */
-struct advertisement_state_machine {
-	struct dl_list list;
-	enum advertisement_type_enum type;
-	int state;
-	int nerrors;
-	struct sockaddr_in client; /* for M-SEARCH replies */
-};
-
-
-/*
- * An address of a subscriber (who may have multiple addresses). We are
- * supposed to send (via TCP) updates to each subscriber, trying each address
- * for a subscriber until we find one that seems to work.
- */
-struct subscr_addr {
-	struct dl_list list;
-	char *domain_and_port; /* domain and port part of url */
-	char *path; /* "filepath" part of url (from "mem") */
-	struct sockaddr_in saddr; /* address for doing connect */
-};
-
-
-/*
- * Subscribers to our events are recorded in this struct. This includes a max
- * of one outgoing connection (sending an "event message") per subscriber. We
- * also have to age out subscribers unless they renew.
- */
-struct subscription {
-	struct dl_list list;
-	struct upnp_wps_device_sm *sm; /* parent */
-	time_t timeout_time; /* when to age out the subscription */
-	unsigned next_subscriber_sequence; /* number our messages */
-	/*
-	 * This uuid identifies the subscription and is randomly generated by
-	 * us and given to the subscriber when the subscription is accepted;
-	 * and is then included with each event sent to the subscriber.
-	 */
-	u8 uuid[UUID_LEN];
-	/* Linked list of address alternatives (rotate through on failure) */
-	struct dl_list addr_list;
-	struct dl_list event_queue; /* Queued event messages. */
-	struct wps_event_ *current_event; /* non-NULL if being sent (not in q)
-					   */
-
-	/* Information from SetSelectedRegistrar action */
-	u8 selected_registrar;
-	u16 dev_password_id;
-	u16 config_methods;
-	struct wps_registrar *reg;
-};
-
-
-/*
- * Our instance data corresponding to one WiFi network interface
- * (multiple might share the same wired network interface!).
- *
- * This is known as an opaque struct declaration to users of the WPS UPnP code.
- */
-struct upnp_wps_device_sm {
-	struct upnp_wps_device_ctx *ctx; /* callback table */
-	struct wps_context *wps;
-	void *priv;
-	char *root_dir;
-	char *desc_url;
-	int started; /* nonzero if we are active */
-	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
-	char *ip_addr_text; /* IP address of network i.f. we use */
-	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
-	int multicast_sd; /* send multicast messages over this socket */
-	int ssdp_sd; /* receive discovery UPD packets on socket */
-	int ssdp_sd_registered; /* nonzero if we must unregister */
-	unsigned advertise_count; /* how many advertisements done */
-	struct advertisement_state_machine advertisement;
-	struct dl_list msearch_replies;
-	int web_port; /* our port that others get xml files from */
-	struct http_server *web_srv;
-	/* Note: subscriptions are kept in expiry order */
-	struct dl_list subscriptions;
-	int event_send_all_queued; /* if we are scheduled to send events soon
-				    */
-
-	char *wlanevent; /* the last WLANEvent data */
-
-	/* FIX: maintain separate structures for each UPnP peer */
-	struct upnp_wps_peer peer;
-};
-
-/* wps_upnp.c */
-void format_date(struct wpabuf *buf);
-struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
-					 const char *callback_urls);
-struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
-					 const u8 uuid[UUID_LEN]);
-void subscription_destroy(struct subscription *s);
-struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
-					const u8 uuid[UUID_LEN]);
-int send_wpabuf(int fd, struct wpabuf *buf);
-int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
-		   u8 mac[ETH_ALEN]);
-
-/* wps_upnp_ssdp.c */
-void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
-int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
-				      int send_byebye);
-void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
-int ssdp_listener_start(struct upnp_wps_device_sm *sm);
-int ssdp_listener_open(void);
-int add_ssdp_network(const char *net_if);
-int ssdp_open_multicast_sock(u32 ip_addr);
-int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
-
-/* wps_upnp_web.c */
-int web_listener_start(struct upnp_wps_device_sm *sm);
-void web_listener_stop(struct upnp_wps_device_sm *sm);
-
-/* wps_upnp_event.c */
-int event_add(struct subscription *s, const struct wpabuf *data);
-void event_delete_all(struct subscription *s);
-void event_send_all_later(struct upnp_wps_device_sm *sm);
-void event_send_stop_all(struct upnp_wps_device_sm *sm);
-
-/* wps_upnp_ap.c */
-int upnp_er_set_selected_registrar(struct wps_registrar *reg,
-				   struct subscription *s,
-				   const struct wpabuf *msg);
-void upnp_er_remove_notification(struct subscription *s);
-
-#endif /* WPS_UPNP_I_H */

Copied: vendor/wpa/2.0/src/wps/wps_upnp_i.h (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp_i.h)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp_i.h	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,194 @@
+/*
+ * UPnP for WPS / internal definitions
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#ifndef WPS_UPNP_I_H
+#define WPS_UPNP_I_H
+
+#include "utils/list.h"
+#include "http.h"
+
+#define UPNP_MULTICAST_ADDRESS  "239.255.255.250" /* for UPnP multicasting */
+#define UPNP_MULTICAST_PORT 1900 /* UDP port to monitor for UPnP */
+
+/* min subscribe time per UPnP standard */
+#define UPNP_SUBSCRIBE_SEC_MIN 1800
+/* subscribe time we use */
+#define UPNP_SUBSCRIBE_SEC (UPNP_SUBSCRIBE_SEC_MIN + 1)
+
+/* "filenames" used in URLs that we service via our "web server": */
+#define UPNP_WPS_DEVICE_XML_FILE "wps_device.xml"
+#define UPNP_WPS_SCPD_XML_FILE   "wps_scpd.xml"
+#define UPNP_WPS_DEVICE_CONTROL_FILE "wps_control"
+#define UPNP_WPS_DEVICE_EVENT_FILE "wps_event"
+
+#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */
+
+
+struct upnp_wps_device_sm;
+struct wps_registrar;
+
+
+enum advertisement_type_enum {
+	ADVERTISE_UP = 0,
+	ADVERTISE_DOWN = 1,
+	MSEARCH_REPLY = 2
+};
+
+/*
+ * Advertisements are broadcast via UDP NOTIFYs, and are also the essence of
+ * the reply to UDP M-SEARCH requests. This struct handles both cases.
+ *
+ * A state machine is needed because a number of variant forms must be sent in
+ * separate packets and spread out in time to avoid congestion.
+ */
+struct advertisement_state_machine {
+	struct dl_list list;
+	enum advertisement_type_enum type;
+	int state;
+	int nerrors;
+	struct sockaddr_in client; /* for M-SEARCH replies */
+};
+
+
+/*
+ * An address of a subscriber (who may have multiple addresses). We are
+ * supposed to send (via TCP) updates to each subscriber, trying each address
+ * for a subscriber until we find one that seems to work.
+ */
+struct subscr_addr {
+	struct dl_list list;
+	char *domain_and_port; /* domain and port part of url */
+	char *path; /* "filepath" part of url (from "mem") */
+	struct sockaddr_in saddr; /* address for doing connect */
+	unsigned num_failures;
+};
+
+
+/*
+ * Subscribers to our events are recorded in this struct. This includes a max
+ * of one outgoing connection (sending an "event message") per subscriber. We
+ * also have to age out subscribers unless they renew.
+ */
+struct subscription {
+	struct dl_list list;
+	struct upnp_wps_device_sm *sm; /* parent */
+	time_t timeout_time; /* when to age out the subscription */
+	unsigned next_subscriber_sequence; /* number our messages */
+	/*
+	 * This uuid identifies the subscription and is randomly generated by
+	 * us and given to the subscriber when the subscription is accepted;
+	 * and is then included with each event sent to the subscriber.
+	 */
+	u8 uuid[UUID_LEN];
+	/* Linked list of address alternatives (rotate through on failure) */
+	struct dl_list addr_list;
+	struct dl_list event_queue; /* Queued event messages. */
+	struct wps_event_ *current_event; /* non-NULL if being sent (not in q)
+					   */
+	int last_event_failed; /* Whether delivery of last event failed */
+
+	/* Information from SetSelectedRegistrar action */
+	u8 selected_registrar;
+	u16 dev_password_id;
+	u16 config_methods;
+	u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+	struct wps_registrar *reg;
+};
+
+
+struct upnp_wps_device_interface {
+	struct dl_list list;
+	struct upnp_wps_device_ctx *ctx; /* callback table */
+	struct wps_context *wps;
+	void *priv;
+
+	/* FIX: maintain separate structures for each UPnP peer */
+	struct upnp_wps_peer peer;
+};
+
+/*
+ * Our instance data corresponding to the AP device. Note that there may be
+ * multiple wireless interfaces sharing the same UPnP device instance. Each
+ * such interface is stored in the list of struct upnp_wps_device_interface
+ * instances.
+ *
+ * This is known as an opaque struct declaration to users of the WPS UPnP code.
+ */
+struct upnp_wps_device_sm {
+	struct dl_list interfaces; /* struct upnp_wps_device_interface */
+	char *root_dir;
+	char *desc_url;
+	int started; /* nonzero if we are active */
+	u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
+	char *ip_addr_text; /* IP address of network i.f. we use */
+	unsigned ip_addr; /* IP address of network i.f. we use (host order) */
+	int multicast_sd; /* send multicast messages over this socket */
+	int ssdp_sd; /* receive discovery UPD packets on socket */
+	int ssdp_sd_registered; /* nonzero if we must unregister */
+	unsigned advertise_count; /* how many advertisements done */
+	struct advertisement_state_machine advertisement;
+	struct dl_list msearch_replies;
+	int web_port; /* our port that others get xml files from */
+	struct http_server *web_srv;
+	/* Note: subscriptions are kept in expiry order */
+	struct dl_list subscriptions;
+	int event_send_all_queued; /* if we are scheduled to send events soon
+				    */
+
+	char *wlanevent; /* the last WLANEvent data */
+	enum upnp_wps_wlanevent_type wlanevent_type;
+	os_time_t last_event_sec;
+	unsigned int num_events_in_sec;
+};
+
+/* wps_upnp.c */
+void format_date(struct wpabuf *buf);
+struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
+					 const char *callback_urls);
+struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
+					 const u8 uuid[UUID_LEN]);
+void subscription_destroy(struct subscription *s);
+struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
+					const u8 uuid[UUID_LEN]);
+void subscr_addr_delete(struct subscr_addr *a);
+int send_wpabuf(int fd, struct wpabuf *buf);
+int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
+		   u8 mac[ETH_ALEN]);
+
+/* wps_upnp_ssdp.c */
+void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
+int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+				      int send_byebye);
+void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
+int ssdp_listener_start(struct upnp_wps_device_sm *sm);
+int ssdp_listener_open(void);
+int add_ssdp_network(const char *net_if);
+int ssdp_open_multicast_sock(u32 ip_addr);
+int ssdp_open_multicast(struct upnp_wps_device_sm *sm);
+
+/* wps_upnp_web.c */
+int web_listener_start(struct upnp_wps_device_sm *sm);
+void web_listener_stop(struct upnp_wps_device_sm *sm);
+
+/* wps_upnp_event.c */
+int event_add(struct subscription *s, const struct wpabuf *data, int probereq);
+void event_delete_all(struct subscription *s);
+void event_send_all_later(struct upnp_wps_device_sm *sm);
+void event_send_stop_all(struct upnp_wps_device_sm *sm);
+
+/* wps_upnp_ap.c */
+int upnp_er_set_selected_registrar(struct wps_registrar *reg,
+				   struct subscription *s,
+				   const struct wpabuf *msg);
+void upnp_er_remove_notification(struct wps_registrar *reg,
+				 struct subscription *s);
+
+#endif /* WPS_UPNP_I_H */

Deleted: vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp_ssdp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,924 +0,0 @@
-/*
- * UPnP SSDP for WPS
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#include "includes.h"
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <net/route.h>
-
-#include "common.h"
-#include "uuid.h"
-#include "eloop.h"
-#include "wps.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-
-#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */
-#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */
-#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */
-#define MAX_MSEARCH 20          /* max simultaneous M-SEARCH replies ongoing */
-#define SSDP_TARGET  "239.0.0.0"
-#define SSDP_NETMASK "255.0.0.0"
-
-
-/* Check tokens for equality, where tokens consist of letters, digits,
- * underscore and hyphen, and are matched case insensitive.
- */
-static int token_eq(const char *s1, const char *s2)
-{
-	int c1;
-	int c2;
-	int end1 = 0;
-	int end2 = 0;
-	for (;;) {
-		c1 = *s1++;
-		c2 = *s2++;
-		if (isalpha(c1) && isupper(c1))
-			c1 = tolower(c1);
-		if (isalpha(c2) && isupper(c2))
-			c2 = tolower(c2);
-		end1 = !(isalnum(c1) || c1 == '_' || c1 == '-');
-		end2 = !(isalnum(c2) || c2 == '_' || c2 == '-');
-		if (end1 || end2 || c1 != c2)
-			break;
-	}
-	return end1 && end2; /* reached end of both words? */
-}
-
-
-/* Return length of token (see above for definition of token) */
-static int token_length(const char *s)
-{
-	const char *begin = s;
-	for (;; s++) {
-		int c = *s;
-		int end = !(isalnum(c) || c == '_' || c == '-');
-		if (end)
-			break;
-	}
-	return s - begin;
-}
-
-
-/* return length of interword separation.
- * This accepts only spaces/tabs and thus will not traverse a line
- * or buffer ending.
- */
-static int word_separation_length(const char *s)
-{
-	const char *begin = s;
-	for (;; s++) {
-		int c = *s;
-		if (c == ' ' || c == '\t')
-			continue;
-		break;
-	}
-	return s - begin;
-}
-
-
-/* No. of chars through (including) end of line */
-static int line_length(const char *l)
-{
-	const char *lp = l;
-	while (*lp && *lp != '\n')
-		lp++;
-	if (*lp == '\n')
-		lp++;
-	return lp - l;
-}
-
-
-/* No. of chars excluding trailing whitespace */
-static int line_length_stripped(const char *l)
-{
-	const char *lp = l + line_length(l);
-	while (lp > l && !isgraph(lp[-1]))
-		lp--;
-	return lp - 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.
- * The individual packets are spread out in time to limit loss,
- * and then after a much longer period of time the whole sequence
- * is repeated again (for NOTIFYs only).
- **************************************************************************/
-
-/**
- * next_advertisement - Build next message and advance the state machine
- * @a: Advertisement state
- * @islast: Buffer for indicating whether this is the last message (= 1)
- * Returns: The new message (caller is responsible for freeing this)
- *
- * Note: next_advertisement is shared code with msearchreply_* functions
- */
-static struct wpabuf *
-next_advertisement(struct upnp_wps_device_sm *sm,
-		   struct advertisement_state_machine *a, int *islast)
-{
-	struct wpabuf *msg;
-	char *NTString = "";
-	char uuid_string[80];
-
-	*islast = 0;
-	uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
-	msg = wpabuf_alloc(800); /* more than big enough */
-	if (msg == NULL)
-		goto fail;
-	switch (a->type) {
-	case ADVERTISE_UP:
-	case ADVERTISE_DOWN:
-		NTString = "NT";
-		wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n");
-		wpabuf_printf(msg, "HOST: %s:%d\r\n",
-			      UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT);
-		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
-			      UPNP_CACHE_SEC);
-		wpabuf_printf(msg, "NTS: %s\r\n",
-			      (a->type == ADVERTISE_UP ?
-			       "ssdp:alive" : "ssdp:byebye"));
-		break;
-	case MSEARCH_REPLY:
-		NTString = "ST";
-		wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n");
-		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
-			      UPNP_CACHE_SEC);
-
-		wpabuf_put_str(msg, "DATE: ");
-		format_date(msg);
-		wpabuf_put_str(msg, "\r\n");
-
-		wpabuf_put_str(msg, "EXT:\r\n");
-		break;
-	}
-
-	if (a->type != ADVERTISE_DOWN) {
-		/* Where others may get our XML files from */
-		wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n",
-			      sm->ip_addr_text, sm->web_port,
-			      UPNP_WPS_DEVICE_XML_FILE);
-	}
-
-	/* The SERVER line has three comma-separated fields:
-	 *      operating system / version
-	 *      upnp version
-	 *      software package / version
-	 * However, only the UPnP version is really required, the
-	 * others can be place holders... for security reasons
-	 * it is better to NOT provide extra information.
-	 */
-	wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
-
-	switch (a->state / UPNP_ADVERTISE_REPEAT) {
-	case 0:
-		wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString);
-		wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n",
-			      uuid_string);
-		break;
-	case 1:
-		wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string);
-		wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string);
-		break;
-	case 2:
-		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:"
-			      "WFADevice:1\r\n", NTString);
-		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
-			      "org:device:WFADevice:1\r\n", uuid_string);
-		break;
-	case 3:
-		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:"
-			      "WFAWLANConfig:1\r\n", NTString);
-		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
-			      "org:service:WFAWLANConfig:1\r\n", uuid_string);
-		break;
-	}
-	wpabuf_put_str(msg, "\r\n");
-
-	if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT)
-		*islast = 1;
-
-	return msg;
-
-fail:
-	wpabuf_free(msg);
-	return NULL;
-}
-
-
-static void advertisement_state_machine_handler(void *eloop_data,
-						void *user_ctx);
-
-
-/**
- * advertisement_state_machine_stop - Stop SSDP advertisements
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @send_byebye: Send byebye advertisement messages immediately
- */
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
-				      int send_byebye)
-{
-	struct advertisement_state_machine *a = &sm->advertisement;
-	int islast = 0;
-	struct wpabuf *msg;
-	struct sockaddr_in dest;
-
-	eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
-	if (!send_byebye || sm->multicast_sd < 0)
-		return;
-
-	a->type = ADVERTISE_DOWN;
-	a->state = 0;
-
-	os_memset(&dest, 0, sizeof(dest));
-	dest.sin_family = AF_INET;
-	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
-	dest.sin_port = htons(UPNP_MULTICAST_PORT);
-
-	while (!islast) {
-		msg = next_advertisement(sm, a, &islast);
-		if (msg == NULL)
-			break;
-		if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg),
-			   0, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
-			wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto "
-				   "failed: %d (%s)", errno, strerror(errno));
-		}
-		wpabuf_free(msg);
-		a->state++;
-	}
-}
-
-
-static void advertisement_state_machine_handler(void *eloop_data,
-						void *user_ctx)
-{
-	struct upnp_wps_device_sm *sm = user_ctx;
-	struct advertisement_state_machine *a = &sm->advertisement;
-	struct wpabuf *msg;
-	int next_timeout_msec = 100;
-	int next_timeout_sec = 0;
-	struct sockaddr_in dest;
-	int islast = 0;
-
-	/*
-	 * Each is sent twice (in case lost) w/ 100 msec delay between;
-	 * spec says no more than 3 times.
-	 * One pair for rootdevice, one pair for uuid, and a pair each for
-	 * each of the two urns.
-	 * The entire sequence must be repeated before cache control timeout
-	 * (which  is min  1800 seconds),
-	 * recommend random portion of half of the advertised cache control age
-	 * to ensure against loss... perhaps 1800/4 + rand*1800/4 ?
-	 * Delay random interval < 100 msec prior to initial sending.
-	 * TTL of 4
-	 */
-
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state);
-	msg = next_advertisement(sm, a, &islast);
-	if (msg == NULL)
-		return;
-
-	os_memset(&dest, 0, sizeof(dest));
-	dest.sin_family = AF_INET;
-	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
-	dest.sin_port = htons(UPNP_MULTICAST_PORT);
-
-	if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
-		   (struct sockaddr *) &dest, sizeof(dest)) == -1) {
-		wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:"
-			   "%d (%s)", errno, strerror(errno));
-		next_timeout_msec = 0;
-		next_timeout_sec = 10; /* ... later */
-	} else if (islast) {
-		a->state = 0; /* wrap around */
-		if (a->type == ADVERTISE_DOWN) {
-			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP");
-			a->type = ADVERTISE_UP;
-			/* do it all over again right away */
-		} else {
-			u16 r;
-			/*
-			 * Start over again after a long timeout
-			 * (see notes above)
-			 */
-			next_timeout_msec = 0;
-			os_get_random((void *) &r, sizeof(r));
-			next_timeout_sec = UPNP_CACHE_SEC / 4 +
-				(((UPNP_CACHE_SEC / 4) * r) >> 16);
-			sm->advertise_count++;
-			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); "
-				   "next in %d sec",
-				   sm->advertise_count, next_timeout_sec);
-		}
-	} else {
-		a->state++;
-	}
-
-	wpabuf_free(msg);
-
-	eloop_register_timeout(next_timeout_sec, next_timeout_msec,
-			       advertisement_state_machine_handler, NULL, sm);
-}
-
-
-/**
- * advertisement_state_machine_start - Start SSDP advertisements
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 on success, -1 on failure
- */
-int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
-{
-	struct advertisement_state_machine *a = &sm->advertisement;
-	int next_timeout_msec;
-
-	advertisement_state_machine_stop(sm, 0);
-
-	/*
-	 * Start out advertising down, this automatically switches
-	 * to advertising up which signals our restart.
-	 */
-	a->type = ADVERTISE_DOWN;
-	a->state = 0;
-	/* (other fields not used here) */
-
-	/* First timeout should be random interval < 100 msec */
-	next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8;
-	return eloop_register_timeout(0, next_timeout_msec,
-				      advertisement_state_machine_handler,
-				      NULL, sm);
-}
-
-
-/***************************************************************************
- * M-SEARCH replies
- * These are very similar to the multicast advertisements, with some
- * small changes in data content; and they are sent (UDP) to a specific
- * unicast address instead of multicast.
- * They are sent in response to a UDP M-SEARCH packet.
- **************************************************************************/
-
-/**
- * msearchreply_state_machine_stop - Stop M-SEARCH reply state machine
- * @a: Selected advertisement/reply state
- */
-void msearchreply_state_machine_stop(struct advertisement_state_machine *a)
-{
-	wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop");
-	dl_list_del(&a->list);
-	os_free(a);
-}
-
-
-static void msearchreply_state_machine_handler(void *eloop_data,
-					       void *user_ctx)
-{
-	struct advertisement_state_machine *a = user_ctx;
-	struct upnp_wps_device_sm *sm = eloop_data;
-	struct wpabuf *msg;
-	int next_timeout_msec = 100;
-	int next_timeout_sec = 0;
-	int islast = 0;
-
-	/*
-	 * Each response is sent twice (in case lost) w/ 100 msec delay
-	 * between; spec says no more than 3 times.
-	 * One pair for rootdevice, one pair for uuid, and a pair each for
-	 * each of the two urns.
-	 */
-
-	/* TODO: should only send the requested response types */
-
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)",
-		   a->state, inet_ntoa(a->client.sin_addr),
-		   ntohs(a->client.sin_port));
-	msg = next_advertisement(sm, a, &islast);
-	if (msg == NULL)
-		return;
-
-	/*
-	 * Send it on the multicast socket to avoid having to set up another
-	 * socket.
-	 */
-	if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
-		   (struct sockaddr *) &a->client, sizeof(a->client)) < 0) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto "
-			   "errno %d (%s) for %s:%d",
-			   errno, strerror(errno),
-			   inet_ntoa(a->client.sin_addr),
-			   ntohs(a->client.sin_port));
-		/* Ignore error and hope for the best */
-	}
-	wpabuf_free(msg);
-	if (islast) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done");
-		msearchreply_state_machine_stop(a);
-		return;
-	}
-	a->state++;
-
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec",
-		   next_timeout_sec, next_timeout_msec);
-	eloop_register_timeout(next_timeout_sec, next_timeout_msec,
-			       msearchreply_state_machine_handler, sm, a);
-}
-
-
-/**
- * msearchreply_state_machine_start - Reply to M-SEARCH discovery request
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @client: Client address
- * @mx: Maximum delay in seconds
- *
- * Use TTL of 4 (this was done when socket set up).
- * A response should be given in randomized portion of min(MX,120) seconds
- *
- * UPnP-arch-DeviceArchitecture, 1.2.3:
- * To be found, a device must send a UDP response to the source IP address and
- * port that sent the request to the multicast channel. Devices respond if the
- * ST header of the M-SEARCH request is "ssdp:all", "upnp:rootdevice", "uuid:"
- * followed by a UUID that exactly matches one advertised by the device.
- */
-static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,
-					     struct sockaddr_in *client,
-					     int mx)
-{
-	struct advertisement_state_machine *a;
-	int next_timeout_sec;
-	int next_timeout_msec;
-	int replies;
-
-	replies = dl_list_len(&sm->msearch_replies);
-	wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply start (%d "
-		   "outstanding)", replies);
-	if (replies >= MAX_MSEARCH) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Too many outstanding "
-			   "M-SEARCH replies");
-		return;
-	}
-
-	a = os_zalloc(sizeof(*a));
-	if (a == NULL)
-		return;
-	a->type = MSEARCH_REPLY;
-	a->state = 0;
-	os_memcpy(&a->client, client, sizeof(*client));
-	/* Wait time depending on MX value */
-	next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8;
-	next_timeout_sec = next_timeout_msec / 1000;
-	next_timeout_msec = next_timeout_msec % 1000;
-	if (eloop_register_timeout(next_timeout_sec, next_timeout_msec,
-				   msearchreply_state_machine_handler, sm,
-				   a)) {
-		/* No way to recover (from malloc failure) */
-		goto fail;
-	}
-	/* Remember for future cleanup */
-	dl_list_add(&sm->msearch_replies, &a->list);
-	return;
-
-fail:
-	wpa_printf(MSG_INFO, "WPS UPnP: M-SEARCH reply failure!");
-	eloop_cancel_timeout(msearchreply_state_machine_handler, sm, a);
-	os_free(a);
-}
-
-
-/**
- * ssdp_parse_msearch - Process a received M-SEARCH
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @client: Client address
- * @data: NULL terminated M-SEARCH message
- *
- * Given that we have received a header w/ M-SEARCH, act upon it
- *
- * Format of M-SEARCH (case insensitive!):
- *
- * First line must be:
- *      M-SEARCH * HTTP/1.1
- * Other lines in arbitrary order:
- *      HOST:239.255.255.250:1900
- *      ST:<varies -- must match>
- *      MAN:"ssdp:discover"
- *      MX:<varies>
- *
- * It should be noted that when Microsoft Vista is still learning its IP
- * address, it sends out host lines like: HOST:[FF02::C]:1900
- */
-static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
-			       struct sockaddr_in *client, const char *data)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	const char *start = data;
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-	const char *end;
-	int got_host = 0;
-	int got_st = 0, st_match = 0;
-	int got_man = 0;
-	int got_mx = 0;
-	int mx = 0;
-
-	/*
-	 * Skip first line M-SEARCH * HTTP/1.1
-	 * (perhaps we should check remainder of the line for syntax)
-	 */
-	data += line_length(data);
-
-	/* Parse remaining lines */
-	for (; *data != '\0'; data += line_length(data)) {
-		end = data + line_length_stripped(data);
-		if (token_eq(data, "host")) {
-			/* The host line indicates who the packet
-			 * is addressed to... but do we really care?
-			 * Note that Microsoft sometimes does funny
-			 * stuff with the HOST: line.
-			 */
-#if 0   /* could be */
-			data += token_length(data);
-			data += word_separation_length(data);
-			if (*data != ':')
-				goto bad;
-			data++;
-			data += word_separation_length(data);
-			/* UPNP_MULTICAST_ADDRESS */
-			if (!str_starts(data, "239.255.255.250"))
-				goto bad;
-			data += os_strlen("239.255.255.250");
-			if (*data == ':') {
-				if (!str_starts(data, ":1900"))
-					goto bad;
-			}
-#endif  /* could be */
-			got_host = 1;
-			continue;
-		} else if (token_eq(data, "st")) {
-			/* There are a number of forms; we look
-			 * for one that matches our case.
-			 */
-			got_st = 1;
-			data += token_length(data);
-			data += word_separation_length(data);
-			if (*data != ':')
-				continue;
-			data++;
-			data += word_separation_length(data);
-			if (str_starts(data, "ssdp:all")) {
-				st_match = 1;
-				continue;
-			}
-			if (str_starts(data, "upnp:rootdevice")) {
-				st_match = 1;
-				continue;
-			}
-			if (str_starts(data, "uuid:")) {
-				char uuid_string[80];
-				data += os_strlen("uuid:");
-				uuid_bin2str(sm->wps->uuid, uuid_string,
-					     sizeof(uuid_string));
-				if (str_starts(data, uuid_string))
-					st_match = 1;
-				continue;
-			}
-#if 0
-			/* FIX: should we really reply to IGD string? */
-			if (str_starts(data, "urn:schemas-upnp-org:device:"
-				       "InternetGatewayDevice:1")) {
-				st_match = 1;
-				continue;
-			}
-#endif
-			if (str_starts(data, "urn:schemas-wifialliance-org:"
-				       "service:WFAWLANConfig:1")) {
-				st_match = 1;
-				continue;
-			}
-			if (str_starts(data, "urn:schemas-wifialliance-org:"
-				       "device:WFADevice:1")) {
-				st_match = 1;
-				continue;
-			}
-			continue;
-		} else if (token_eq(data, "man")) {
-			data += token_length(data);
-			data += word_separation_length(data);
-			if (*data != ':')
-				continue;
-			data++;
-			data += word_separation_length(data);
-			if (!str_starts(data, "\"ssdp:discover\"")) {
-				wpa_printf(MSG_DEBUG, "WPS UPnP: Unexpected "
-					   "M-SEARCH man-field");
-				goto bad;
-			}
-			got_man = 1;
-			continue;
-		} else if (token_eq(data, "mx")) {
-			data += token_length(data);
-			data += word_separation_length(data);
-			if (*data != ':')
-				continue;
-			data++;
-			data += word_separation_length(data);
-			mx = atol(data);
-			got_mx = 1;
-			continue;
-		}
-		/* ignore anything else */
-	}
-	if (!got_host || !got_st || !got_man || !got_mx || mx < 0) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid M-SEARCH: %d %d %d "
-			   "%d mx=%d", got_host, got_st, got_man, got_mx, mx);
-		goto bad;
-	}
-	if (!st_match) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored M-SEARCH (no ST "
-			   "match)");
-		return;
-	}
-	if (mx > 120)
-		mx = 120; /* UPnP-arch-DeviceArchitecture, 1.2.3 */
-	msearchreply_state_machine_start(sm, client, mx);
-	return;
-
-bad:
-	wpa_printf(MSG_INFO, "WPS UPnP: Failed to parse M-SEARCH");
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH data:\n%s", start);
-}
-
-
-/* Listening for (UDP) discovery (M-SEARCH) packets */
-
-/**
- * ssdp_listener_stop - Stop SSDP listered
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- *
- * This function stops the SSDP listener that was started by calling
- * ssdp_listener_start().
- */
-void ssdp_listener_stop(struct upnp_wps_device_sm *sm)
-{
-	if (sm->ssdp_sd_registered) {
-		eloop_unregister_sock(sm->ssdp_sd, EVENT_TYPE_READ);
-		sm->ssdp_sd_registered = 0;
-	}
-
-	if (sm->ssdp_sd != -1) {
-		close(sm->ssdp_sd);
-		sm->ssdp_sd = -1;
-	}
-
-	eloop_cancel_timeout(msearchreply_state_machine_handler, sm,
-			     ELOOP_ALL_CTX);
-}
-
-
-static void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
-{
-	struct upnp_wps_device_sm *sm = sock_ctx;
-	struct sockaddr_in addr; /* client address */
-	socklen_t addr_len;
-	int nread;
-	char buf[MULTICAST_MAX_READ], *pos;
-
-	addr_len = sizeof(addr);
-	nread = recvfrom(sm->ssdp_sd, buf, sizeof(buf) - 1, 0,
-			 (struct sockaddr *) &addr, &addr_len);
-	if (nread <= 0)
-		return;
-	buf[nread] = '\0'; /* need null termination for algorithm */
-
-	if (str_starts(buf, "NOTIFY ")) {
-		/*
-		 * Silently ignore NOTIFYs to avoid filling debug log with
-		 * unwanted messages.
-		 */
-		return;
-	}
-
-	pos = os_strchr(buf, '\n');
-	if (pos)
-		*pos = '\0';
-	wpa_printf(MSG_MSGDUMP, "WPS UPnP: Received SSDP packet from %s:%d: "
-		   "%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), buf);
-	if (pos)
-		*pos = '\n';
-
-	/* Parse first line */
-	if (os_strncasecmp(buf, "M-SEARCH", os_strlen("M-SEARCH")) == 0 &&
-	    !isgraph(buf[strlen("M-SEARCH")])) {
-		ssdp_parse_msearch(sm, &addr, buf);
-		return;
-	}
-
-	/* Ignore anything else */
-}
-
-
-int ssdp_listener_open(void)
-{
-	struct sockaddr_in addr;
-	struct ip_mreq mcast_addr;
-	int on = 1;
-	/* per UPnP spec, keep IP packet time to live (TTL) small */
-	unsigned char ttl = 4;
-	int sd;
-
-	sd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (sd < 0)
-		goto fail;
-	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
-		goto fail;
-	if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
-		goto fail;
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = htonl(INADDR_ANY);
-	addr.sin_port = htons(UPNP_MULTICAST_PORT);
-	if (bind(sd, (struct sockaddr *) &addr, sizeof(addr)))
-		goto fail;
-	os_memset(&mcast_addr, 0, sizeof(mcast_addr));
-	mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
-	mcast_addr.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
-	if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-		       (char *) &mcast_addr, sizeof(mcast_addr)))
-		goto fail;
-	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
-		       &ttl, sizeof(ttl)))
-		goto fail;
-
-	return sd;
-
-fail:
-	if (sd >= 0)
-		close(sd);
-	return -1;
-}
-
-
-/**
- * ssdp_listener_start - Set up for receiving discovery (UDP) packets
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 on success, -1 on failure
- *
- * The SSDP listener is stopped by calling ssdp_listener_stop().
- */
-int ssdp_listener_start(struct upnp_wps_device_sm *sm)
-{
-	sm->ssdp_sd = ssdp_listener_open();
-
-	if (eloop_register_sock(sm->ssdp_sd, EVENT_TYPE_READ,
-				ssdp_listener_handler, NULL, sm))
-		goto fail;
-	sm->ssdp_sd_registered = 1;
-	return 0;
-
-fail:
-	/* Error */
-	wpa_printf(MSG_ERROR, "WPS UPnP: ssdp_listener_start failed");
-	ssdp_listener_stop(sm);
-	return -1;
-}
-
-
-/**
- * add_ssdp_network - Add routing entry for SSDP
- * @net_if: Selected network interface name
- * Returns: 0 on success, -1 on failure
- *
- * This function assures that the multicast address will be properly
- * handled by Linux networking code (by a modification to routing tables).
- * This must be done per network interface. It really only needs to be done
- * once after booting up, but it does not hurt to call this more frequently
- * "to be safe".
- */
-int add_ssdp_network(const char *net_if)
-{
-#ifdef __linux__
-	int ret = -1;
-	int sock = -1;
-	struct rtentry rt;
-	struct sockaddr_in *sin;
-
-	if (!net_if)
-		goto fail;
-
-	os_memset(&rt, 0, sizeof(rt));
-	sock = socket(AF_INET, SOCK_DGRAM, 0);
-	if (sock < 0)
-		goto fail;
-
-	rt.rt_dev = (char *) net_if;
-	sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in);
-	sin->sin_family = AF_INET;
-	sin->sin_port = 0;
-	sin->sin_addr.s_addr = inet_addr(SSDP_TARGET);
-	sin = aliasing_hide_typecast(&rt.rt_genmask, struct sockaddr_in);
-	sin->sin_family = AF_INET;
-	sin->sin_port = 0;
-	sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK);
-	rt.rt_flags = RTF_UP;
-	if (ioctl(sock, SIOCADDRT, &rt) < 0) {
-		if (errno == EPERM) {
-			wpa_printf(MSG_DEBUG, "add_ssdp_network: No "
-				   "permissions to add routing table entry");
-			/* Continue to allow testing as non-root */
-		} else if (errno != EEXIST) {
-			wpa_printf(MSG_INFO, "add_ssdp_network() ioctl errno "
-				   "%d (%s)", errno, strerror(errno));
-			goto fail;
-		}
-	}
-
-	ret = 0;
-
-fail:
-	if (sock >= 0)
-		close(sock);
-
-	return ret;
-#else /* __linux__ */
-	return 0;
-#endif /* __linux__ */
-}
-
-
-int ssdp_open_multicast_sock(u32 ip_addr)
-{
-	int sd;
-	 /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
-	  * time to live (TTL) small */
-	unsigned char ttl = 4;
-
-	sd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (sd < 0)
-		return -1;
-
-#if 0   /* maybe ok if we sometimes block on writes */
-	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
-		return -1;
-#endif
-
-	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
-		       &ip_addr, sizeof(ip_addr)))
-		return -1;
-	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
-		       &ttl, sizeof(ttl)))
-		return -1;
-
-#if 0   /* not needed, because we don't receive using multicast_sd */
-	{
-		struct ip_mreq mreq;
-		mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
-		mreq.imr_interface.s_addr = ip_addr;
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr "
-			   "0x%x",
-			   mreq.imr_multiaddr.s_addr,
-			   mreq.imr_interface.s_addr);
-		if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
-				sizeof(mreq))) {
-			wpa_printf(MSG_ERROR,
-				   "WPS UPnP: setsockopt "
-				   "IP_ADD_MEMBERSHIP errno %d (%s)",
-				   errno, strerror(errno));
-			return -1;
-		}
-	}
-#endif  /* not needed */
-
-	/*
-	 * TODO: What about IP_MULTICAST_LOOP? It seems to be on by default?
-	 * which aids debugging I suppose but isn't really necessary?
-	 */
-
-	return sd;
-}
-
-
-/**
- * ssdp_open_multicast - Open socket for sending multicast SSDP messages
- * @sm: WPS UPnP state machine from upnp_wps_device_init()
- * Returns: 0 on success, -1 on failure
- */
-int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
-{
-	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
-	if (sm->multicast_sd < 0)
-		return -1;
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp_ssdp.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp_ssdp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,931 @@
+/*
+ * UPnP SSDP for WPS
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <net/route.h>
+
+#include "common.h"
+#include "uuid.h"
+#include "eloop.h"
+#include "wps.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */
+#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */
+#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */
+#define MAX_MSEARCH 20          /* max simultaneous M-SEARCH replies ongoing */
+#define SSDP_TARGET  "239.0.0.0"
+#define SSDP_NETMASK "255.0.0.0"
+
+
+/* Check tokens for equality, where tokens consist of letters, digits,
+ * underscore and hyphen, and are matched case insensitive.
+ */
+static int token_eq(const char *s1, const char *s2)
+{
+	int c1;
+	int c2;
+	int end1 = 0;
+	int end2 = 0;
+	for (;;) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if (isalpha(c1) && isupper(c1))
+			c1 = tolower(c1);
+		if (isalpha(c2) && isupper(c2))
+			c2 = tolower(c2);
+		end1 = !(isalnum(c1) || c1 == '_' || c1 == '-');
+		end2 = !(isalnum(c2) || c2 == '_' || c2 == '-');
+		if (end1 || end2 || c1 != c2)
+			break;
+	}
+	return end1 && end2; /* reached end of both words? */
+}
+
+
+/* Return length of token (see above for definition of token) */
+static int token_length(const char *s)
+{
+	const char *begin = s;
+	for (;; s++) {
+		int c = *s;
+		int end = !(isalnum(c) || c == '_' || c == '-');
+		if (end)
+			break;
+	}
+	return s - begin;
+}
+
+
+/* return length of interword separation.
+ * This accepts only spaces/tabs and thus will not traverse a line
+ * or buffer ending.
+ */
+static int word_separation_length(const char *s)
+{
+	const char *begin = s;
+	for (;; s++) {
+		int c = *s;
+		if (c == ' ' || c == '\t')
+			continue;
+		break;
+	}
+	return s - begin;
+}
+
+
+/* No. of chars through (including) end of line */
+static int line_length(const char *l)
+{
+	const char *lp = l;
+	while (*lp && *lp != '\n')
+		lp++;
+	if (*lp == '\n')
+		lp++;
+	return lp - 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.
+ * The individual packets are spread out in time to limit loss,
+ * and then after a much longer period of time the whole sequence
+ * is repeated again (for NOTIFYs only).
+ **************************************************************************/
+
+/**
+ * next_advertisement - Build next message and advance the state machine
+ * @a: Advertisement state
+ * @islast: Buffer for indicating whether this is the last message (= 1)
+ * Returns: The new message (caller is responsible for freeing this)
+ *
+ * Note: next_advertisement is shared code with msearchreply_* functions
+ */
+static struct wpabuf *
+next_advertisement(struct upnp_wps_device_sm *sm,
+		   struct advertisement_state_machine *a, int *islast)
+{
+	struct wpabuf *msg;
+	char *NTString = "";
+	char uuid_string[80];
+	struct upnp_wps_device_interface *iface;
+
+	*islast = 0;
+	iface = dl_list_first(&sm->interfaces,
+			      struct upnp_wps_device_interface, list);
+	uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
+	msg = wpabuf_alloc(800); /* more than big enough */
+	if (msg == NULL)
+		goto fail;
+	switch (a->type) {
+	case ADVERTISE_UP:
+	case ADVERTISE_DOWN:
+		NTString = "NT";
+		wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n");
+		wpabuf_printf(msg, "HOST: %s:%d\r\n",
+			      UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT);
+		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
+			      UPNP_CACHE_SEC);
+		wpabuf_printf(msg, "NTS: %s\r\n",
+			      (a->type == ADVERTISE_UP ?
+			       "ssdp:alive" : "ssdp:byebye"));
+		break;
+	case MSEARCH_REPLY:
+		NTString = "ST";
+		wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n");
+		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
+			      UPNP_CACHE_SEC);
+
+		wpabuf_put_str(msg, "DATE: ");
+		format_date(msg);
+		wpabuf_put_str(msg, "\r\n");
+
+		wpabuf_put_str(msg, "EXT:\r\n");
+		break;
+	}
+
+	if (a->type != ADVERTISE_DOWN) {
+		/* Where others may get our XML files from */
+		wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n",
+			      sm->ip_addr_text, sm->web_port,
+			      UPNP_WPS_DEVICE_XML_FILE);
+	}
+
+	/* The SERVER line has three comma-separated fields:
+	 *      operating system / version
+	 *      upnp version
+	 *      software package / version
+	 * However, only the UPnP version is really required, the
+	 * others can be place holders... for security reasons
+	 * it is better to NOT provide extra information.
+	 */
+	wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
+
+	switch (a->state / UPNP_ADVERTISE_REPEAT) {
+	case 0:
+		wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString);
+		wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n",
+			      uuid_string);
+		break;
+	case 1:
+		wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string);
+		wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string);
+		break;
+	case 2:
+		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:"
+			      "WFADevice:1\r\n", NTString);
+		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
+			      "org:device:WFADevice:1\r\n", uuid_string);
+		break;
+	case 3:
+		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:"
+			      "WFAWLANConfig:1\r\n", NTString);
+		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
+			      "org:service:WFAWLANConfig:1\r\n", uuid_string);
+		break;
+	}
+	wpabuf_put_str(msg, "\r\n");
+
+	if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT)
+		*islast = 1;
+
+	return msg;
+
+fail:
+	wpabuf_free(msg);
+	return NULL;
+}
+
+
+static void advertisement_state_machine_handler(void *eloop_data,
+						void *user_ctx);
+
+
+/**
+ * advertisement_state_machine_stop - Stop SSDP advertisements
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @send_byebye: Send byebye advertisement messages immediately
+ */
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+				      int send_byebye)
+{
+	struct advertisement_state_machine *a = &sm->advertisement;
+	int islast = 0;
+	struct wpabuf *msg;
+	struct sockaddr_in dest;
+
+	eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
+	if (!send_byebye || sm->multicast_sd < 0)
+		return;
+
+	a->type = ADVERTISE_DOWN;
+	a->state = 0;
+
+	os_memset(&dest, 0, sizeof(dest));
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+	dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+	while (!islast) {
+		msg = next_advertisement(sm, a, &islast);
+		if (msg == NULL)
+			break;
+		if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg),
+			   0, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
+			wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto "
+				   "failed: %d (%s)", errno, strerror(errno));
+		}
+		wpabuf_free(msg);
+		a->state++;
+	}
+}
+
+
+static void advertisement_state_machine_handler(void *eloop_data,
+						void *user_ctx)
+{
+	struct upnp_wps_device_sm *sm = user_ctx;
+	struct advertisement_state_machine *a = &sm->advertisement;
+	struct wpabuf *msg;
+	int next_timeout_msec = 100;
+	int next_timeout_sec = 0;
+	struct sockaddr_in dest;
+	int islast = 0;
+
+	/*
+	 * Each is sent twice (in case lost) w/ 100 msec delay between;
+	 * spec says no more than 3 times.
+	 * One pair for rootdevice, one pair for uuid, and a pair each for
+	 * each of the two urns.
+	 * The entire sequence must be repeated before cache control timeout
+	 * (which  is min  1800 seconds),
+	 * recommend random portion of half of the advertised cache control age
+	 * to ensure against loss... perhaps 1800/4 + rand*1800/4 ?
+	 * Delay random interval < 100 msec prior to initial sending.
+	 * TTL of 4
+	 */
+
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state);
+	msg = next_advertisement(sm, a, &islast);
+	if (msg == NULL)
+		return;
+
+	os_memset(&dest, 0, sizeof(dest));
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+	dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+	if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+		   (struct sockaddr *) &dest, sizeof(dest)) == -1) {
+		wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:"
+			   "%d (%s)", errno, strerror(errno));
+		next_timeout_msec = 0;
+		next_timeout_sec = 10; /* ... later */
+	} else if (islast) {
+		a->state = 0; /* wrap around */
+		if (a->type == ADVERTISE_DOWN) {
+			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP");
+			a->type = ADVERTISE_UP;
+			/* do it all over again right away */
+		} else {
+			u16 r;
+			/*
+			 * Start over again after a long timeout
+			 * (see notes above)
+			 */
+			next_timeout_msec = 0;
+			os_get_random((void *) &r, sizeof(r));
+			next_timeout_sec = UPNP_CACHE_SEC / 4 +
+				(((UPNP_CACHE_SEC / 4) * r) >> 16);
+			sm->advertise_count++;
+			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); "
+				   "next in %d sec",
+				   sm->advertise_count, next_timeout_sec);
+		}
+	} else {
+		a->state++;
+	}
+
+	wpabuf_free(msg);
+
+	eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+			       advertisement_state_machine_handler, NULL, sm);
+}
+
+
+/**
+ * advertisement_state_machine_start - Start SSDP advertisements
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
+{
+	struct advertisement_state_machine *a = &sm->advertisement;
+	int next_timeout_msec;
+
+	advertisement_state_machine_stop(sm, 0);
+
+	/*
+	 * Start out advertising down, this automatically switches
+	 * to advertising up which signals our restart.
+	 */
+	a->type = ADVERTISE_DOWN;
+	a->state = 0;
+	/* (other fields not used here) */
+
+	/* First timeout should be random interval < 100 msec */
+	next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8;
+	return eloop_register_timeout(0, next_timeout_msec,
+				      advertisement_state_machine_handler,
+				      NULL, sm);
+}
+
+
+/***************************************************************************
+ * M-SEARCH replies
+ * These are very similar to the multicast advertisements, with some
+ * small changes in data content; and they are sent (UDP) to a specific
+ * unicast address instead of multicast.
+ * They are sent in response to a UDP M-SEARCH packet.
+ **************************************************************************/
+
+/**
+ * msearchreply_state_machine_stop - Stop M-SEARCH reply state machine
+ * @a: Selected advertisement/reply state
+ */
+void msearchreply_state_machine_stop(struct advertisement_state_machine *a)
+{
+	wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop");
+	dl_list_del(&a->list);
+	os_free(a);
+}
+
+
+static void msearchreply_state_machine_handler(void *eloop_data,
+					       void *user_ctx)
+{
+	struct advertisement_state_machine *a = user_ctx;
+	struct upnp_wps_device_sm *sm = eloop_data;
+	struct wpabuf *msg;
+	int next_timeout_msec = 100;
+	int next_timeout_sec = 0;
+	int islast = 0;
+
+	/*
+	 * Each response is sent twice (in case lost) w/ 100 msec delay
+	 * between; spec says no more than 3 times.
+	 * One pair for rootdevice, one pair for uuid, and a pair each for
+	 * each of the two urns.
+	 */
+
+	/* TODO: should only send the requested response types */
+
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)",
+		   a->state, inet_ntoa(a->client.sin_addr),
+		   ntohs(a->client.sin_port));
+	msg = next_advertisement(sm, a, &islast);
+	if (msg == NULL)
+		return;
+
+	/*
+	 * Send it on the multicast socket to avoid having to set up another
+	 * socket.
+	 */
+	if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
+		   (struct sockaddr *) &a->client, sizeof(a->client)) < 0) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto "
+			   "errno %d (%s) for %s:%d",
+			   errno, strerror(errno),
+			   inet_ntoa(a->client.sin_addr),
+			   ntohs(a->client.sin_port));
+		/* Ignore error and hope for the best */
+	}
+	wpabuf_free(msg);
+	if (islast) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done");
+		msearchreply_state_machine_stop(a);
+		return;
+	}
+	a->state++;
+
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec",
+		   next_timeout_sec, next_timeout_msec);
+	eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+			       msearchreply_state_machine_handler, sm, a);
+}
+
+
+/**
+ * msearchreply_state_machine_start - Reply to M-SEARCH discovery request
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @client: Client address
+ * @mx: Maximum delay in seconds
+ *
+ * Use TTL of 4 (this was done when socket set up).
+ * A response should be given in randomized portion of min(MX,120) seconds
+ *
+ * UPnP-arch-DeviceArchitecture, 1.2.3:
+ * To be found, a device must send a UDP response to the source IP address and
+ * port that sent the request to the multicast channel. Devices respond if the
+ * ST header of the M-SEARCH request is "ssdp:all", "upnp:rootdevice", "uuid:"
+ * followed by a UUID that exactly matches one advertised by the device.
+ */
+static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,
+					     struct sockaddr_in *client,
+					     int mx)
+{
+	struct advertisement_state_machine *a;
+	int next_timeout_sec;
+	int next_timeout_msec;
+	int replies;
+
+	replies = dl_list_len(&sm->msearch_replies);
+	wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply start (%d "
+		   "outstanding)", replies);
+	if (replies >= MAX_MSEARCH) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Too many outstanding "
+			   "M-SEARCH replies");
+		return;
+	}
+
+	a = os_zalloc(sizeof(*a));
+	if (a == NULL)
+		return;
+	a->type = MSEARCH_REPLY;
+	a->state = 0;
+	os_memcpy(&a->client, client, sizeof(*client));
+	/* Wait time depending on MX value */
+	next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8;
+	next_timeout_sec = next_timeout_msec / 1000;
+	next_timeout_msec = next_timeout_msec % 1000;
+	if (eloop_register_timeout(next_timeout_sec, next_timeout_msec,
+				   msearchreply_state_machine_handler, sm,
+				   a)) {
+		/* No way to recover (from malloc failure) */
+		goto fail;
+	}
+	/* Remember for future cleanup */
+	dl_list_add(&sm->msearch_replies, &a->list);
+	return;
+
+fail:
+	wpa_printf(MSG_INFO, "WPS UPnP: M-SEARCH reply failure!");
+	eloop_cancel_timeout(msearchreply_state_machine_handler, sm, a);
+	os_free(a);
+}
+
+
+/**
+ * ssdp_parse_msearch - Process a received M-SEARCH
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @client: Client address
+ * @data: NULL terminated M-SEARCH message
+ *
+ * Given that we have received a header w/ M-SEARCH, act upon it
+ *
+ * Format of M-SEARCH (case insensitive!):
+ *
+ * First line must be:
+ *      M-SEARCH * HTTP/1.1
+ * Other lines in arbitrary order:
+ *      HOST:239.255.255.250:1900
+ *      ST:<varies -- must match>
+ *      MAN:"ssdp:discover"
+ *      MX:<varies>
+ *
+ * It should be noted that when Microsoft Vista is still learning its IP
+ * address, it sends out host lines like: HOST:[FF02::C]:1900
+ */
+static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
+			       struct sockaddr_in *client, const char *data)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	const char *start = data;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+	int got_host = 0;
+	int got_st = 0, st_match = 0;
+	int got_man = 0;
+	int got_mx = 0;
+	int mx = 0;
+
+	/*
+	 * Skip first line M-SEARCH * HTTP/1.1
+	 * (perhaps we should check remainder of the line for syntax)
+	 */
+	data += line_length(data);
+
+	/* Parse remaining lines */
+	for (; *data != '\0'; data += line_length(data)) {
+		if (token_eq(data, "host")) {
+			/* The host line indicates who the packet
+			 * is addressed to... but do we really care?
+			 * Note that Microsoft sometimes does funny
+			 * stuff with the HOST: line.
+			 */
+#if 0   /* could be */
+			data += token_length(data);
+			data += word_separation_length(data);
+			if (*data != ':')
+				goto bad;
+			data++;
+			data += word_separation_length(data);
+			/* UPNP_MULTICAST_ADDRESS */
+			if (!str_starts(data, "239.255.255.250"))
+				goto bad;
+			data += os_strlen("239.255.255.250");
+			if (*data == ':') {
+				if (!str_starts(data, ":1900"))
+					goto bad;
+			}
+#endif  /* could be */
+			got_host = 1;
+			continue;
+		} else if (token_eq(data, "st")) {
+			/* There are a number of forms; we look
+			 * for one that matches our case.
+			 */
+			got_st = 1;
+			data += token_length(data);
+			data += word_separation_length(data);
+			if (*data != ':')
+				continue;
+			data++;
+			data += word_separation_length(data);
+			if (str_starts(data, "ssdp:all")) {
+				st_match = 1;
+				continue;
+			}
+			if (str_starts(data, "upnp:rootdevice")) {
+				st_match = 1;
+				continue;
+			}
+			if (str_starts(data, "uuid:")) {
+				char uuid_string[80];
+				struct upnp_wps_device_interface *iface;
+				iface = dl_list_first(
+					&sm->interfaces,
+					struct upnp_wps_device_interface,
+					list);
+				data += os_strlen("uuid:");
+				uuid_bin2str(iface->wps->uuid, uuid_string,
+					     sizeof(uuid_string));
+				if (str_starts(data, uuid_string))
+					st_match = 1;
+				continue;
+			}
+#if 0
+			/* FIX: should we really reply to IGD string? */
+			if (str_starts(data, "urn:schemas-upnp-org:device:"
+				       "InternetGatewayDevice:1")) {
+				st_match = 1;
+				continue;
+			}
+#endif
+			if (str_starts(data, "urn:schemas-wifialliance-org:"
+				       "service:WFAWLANConfig:1")) {
+				st_match = 1;
+				continue;
+			}
+			if (str_starts(data, "urn:schemas-wifialliance-org:"
+				       "device:WFADevice:1")) {
+				st_match = 1;
+				continue;
+			}
+			continue;
+		} else if (token_eq(data, "man")) {
+			data += token_length(data);
+			data += word_separation_length(data);
+			if (*data != ':')
+				continue;
+			data++;
+			data += word_separation_length(data);
+			if (!str_starts(data, "\"ssdp:discover\"")) {
+				wpa_printf(MSG_DEBUG, "WPS UPnP: Unexpected "
+					   "M-SEARCH man-field");
+				goto bad;
+			}
+			got_man = 1;
+			continue;
+		} else if (token_eq(data, "mx")) {
+			data += token_length(data);
+			data += word_separation_length(data);
+			if (*data != ':')
+				continue;
+			data++;
+			data += word_separation_length(data);
+			mx = atol(data);
+			got_mx = 1;
+			continue;
+		}
+		/* ignore anything else */
+	}
+	if (!got_host || !got_st || !got_man || !got_mx || mx < 0) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid M-SEARCH: %d %d %d "
+			   "%d mx=%d", got_host, got_st, got_man, got_mx, mx);
+		goto bad;
+	}
+	if (!st_match) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored M-SEARCH (no ST "
+			   "match)");
+		return;
+	}
+	if (mx > 120)
+		mx = 120; /* UPnP-arch-DeviceArchitecture, 1.2.3 */
+	msearchreply_state_machine_start(sm, client, mx);
+	return;
+
+bad:
+	wpa_printf(MSG_INFO, "WPS UPnP: Failed to parse M-SEARCH");
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH data:\n%s", start);
+}
+
+
+/* Listening for (UDP) discovery (M-SEARCH) packets */
+
+/**
+ * ssdp_listener_stop - Stop SSDP listered
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ *
+ * This function stops the SSDP listener that was started by calling
+ * ssdp_listener_start().
+ */
+void ssdp_listener_stop(struct upnp_wps_device_sm *sm)
+{
+	if (sm->ssdp_sd_registered) {
+		eloop_unregister_sock(sm->ssdp_sd, EVENT_TYPE_READ);
+		sm->ssdp_sd_registered = 0;
+	}
+
+	if (sm->ssdp_sd != -1) {
+		close(sm->ssdp_sd);
+		sm->ssdp_sd = -1;
+	}
+
+	eloop_cancel_timeout(msearchreply_state_machine_handler, sm,
+			     ELOOP_ALL_CTX);
+}
+
+
+static void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+	struct upnp_wps_device_sm *sm = sock_ctx;
+	struct sockaddr_in addr; /* client address */
+	socklen_t addr_len;
+	int nread;
+	char buf[MULTICAST_MAX_READ], *pos;
+
+	addr_len = sizeof(addr);
+	nread = recvfrom(sm->ssdp_sd, buf, sizeof(buf) - 1, 0,
+			 (struct sockaddr *) &addr, &addr_len);
+	if (nread <= 0)
+		return;
+	buf[nread] = '\0'; /* need null termination for algorithm */
+
+	if (str_starts(buf, "NOTIFY ")) {
+		/*
+		 * Silently ignore NOTIFYs to avoid filling debug log with
+		 * unwanted messages.
+		 */
+		return;
+	}
+
+	pos = os_strchr(buf, '\n');
+	if (pos)
+		*pos = '\0';
+	wpa_printf(MSG_MSGDUMP, "WPS UPnP: Received SSDP packet from %s:%d: "
+		   "%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), buf);
+	if (pos)
+		*pos = '\n';
+
+	/* Parse first line */
+	if (os_strncasecmp(buf, "M-SEARCH", os_strlen("M-SEARCH")) == 0 &&
+	    !isgraph(buf[strlen("M-SEARCH")])) {
+		ssdp_parse_msearch(sm, &addr, buf);
+		return;
+	}
+
+	/* Ignore anything else */
+}
+
+
+int ssdp_listener_open(void)
+{
+	struct sockaddr_in addr;
+	struct ip_mreq mcast_addr;
+	int on = 1;
+	/* per UPnP spec, keep IP packet time to live (TTL) small */
+	unsigned char ttl = 4;
+	int sd;
+
+	sd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sd < 0)
+		goto fail;
+	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
+		goto fail;
+	if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
+		goto fail;
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	addr.sin_port = htons(UPNP_MULTICAST_PORT);
+	if (bind(sd, (struct sockaddr *) &addr, sizeof(addr)))
+		goto fail;
+	os_memset(&mcast_addr, 0, sizeof(mcast_addr));
+	mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
+	mcast_addr.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+	if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+		       (char *) &mcast_addr, sizeof(mcast_addr)))
+		goto fail;
+	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
+		       &ttl, sizeof(ttl)))
+		goto fail;
+
+	return sd;
+
+fail:
+	if (sd >= 0)
+		close(sd);
+	return -1;
+}
+
+
+/**
+ * ssdp_listener_start - Set up for receiving discovery (UDP) packets
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * The SSDP listener is stopped by calling ssdp_listener_stop().
+ */
+int ssdp_listener_start(struct upnp_wps_device_sm *sm)
+{
+	sm->ssdp_sd = ssdp_listener_open();
+
+	if (eloop_register_sock(sm->ssdp_sd, EVENT_TYPE_READ,
+				ssdp_listener_handler, NULL, sm))
+		goto fail;
+	sm->ssdp_sd_registered = 1;
+	return 0;
+
+fail:
+	/* Error */
+	wpa_printf(MSG_ERROR, "WPS UPnP: ssdp_listener_start failed");
+	ssdp_listener_stop(sm);
+	return -1;
+}
+
+
+/**
+ * add_ssdp_network - Add routing entry for SSDP
+ * @net_if: Selected network interface name
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function assures that the multicast address will be properly
+ * handled by Linux networking code (by a modification to routing tables).
+ * This must be done per network interface. It really only needs to be done
+ * once after booting up, but it does not hurt to call this more frequently
+ * "to be safe".
+ */
+int add_ssdp_network(const char *net_if)
+{
+#ifdef __linux__
+	int ret = -1;
+	int sock = -1;
+	struct rtentry rt;
+	struct sockaddr_in *sin;
+
+	if (!net_if)
+		goto fail;
+
+	os_memset(&rt, 0, sizeof(rt));
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0)
+		goto fail;
+
+	rt.rt_dev = (char *) net_if;
+	sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_port = 0;
+	sin->sin_addr.s_addr = inet_addr(SSDP_TARGET);
+	sin = aliasing_hide_typecast(&rt.rt_genmask, struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_port = 0;
+	sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK);
+	rt.rt_flags = RTF_UP;
+	if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+		if (errno == EPERM) {
+			wpa_printf(MSG_DEBUG, "add_ssdp_network: No "
+				   "permissions to add routing table entry");
+			/* Continue to allow testing as non-root */
+		} else if (errno != EEXIST) {
+			wpa_printf(MSG_INFO, "add_ssdp_network() ioctl errno "
+				   "%d (%s)", errno, strerror(errno));
+			goto fail;
+		}
+	}
+
+	ret = 0;
+
+fail:
+	if (sock >= 0)
+		close(sock);
+
+	return ret;
+#else /* __linux__ */
+	return 0;
+#endif /* __linux__ */
+}
+
+
+int ssdp_open_multicast_sock(u32 ip_addr)
+{
+	int sd;
+	 /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet
+	  * time to live (TTL) small */
+	unsigned char ttl = 4;
+
+	sd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sd < 0)
+		return -1;
+
+#if 0   /* maybe ok if we sometimes block on writes */
+	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) {
+		close(sd);
+		return -1;
+	}
+#endif
+
+	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
+		       &ip_addr, sizeof(ip_addr))) {
+		wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: "
+			   "%d (%s)", ip_addr, errno, strerror(errno));
+		close(sd);
+		return -1;
+	}
+	if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
+		       &ttl, sizeof(ttl))) {
+		wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): "
+			   "%d (%s)", errno, strerror(errno));
+		close(sd);
+		return -1;
+	}
+
+#if 0   /* not needed, because we don't receive using multicast_sd */
+	{
+		struct ip_mreq mreq;
+		mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+		mreq.imr_interface.s_addr = ip_addr;
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr "
+			   "0x%x",
+			   mreq.imr_multiaddr.s_addr,
+			   mreq.imr_interface.s_addr);
+		if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
+				sizeof(mreq))) {
+			wpa_printf(MSG_ERROR,
+				   "WPS UPnP: setsockopt "
+				   "IP_ADD_MEMBERSHIP errno %d (%s)",
+				   errno, strerror(errno));
+			close(sd);
+			return -1;
+		}
+	}
+#endif  /* not needed */
+
+	/*
+	 * TODO: What about IP_MULTICAST_LOOP? It seems to be on by default?
+	 * which aids debugging I suppose but isn't really necessary?
+	 */
+
+	return sd;
+}
+
+
+/**
+ * ssdp_open_multicast - Open socket for sending multicast SSDP messages
+ * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
+{
+	sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
+	if (sm->multicast_sd < 0)
+		return -1;
+	return 0;
+}

Deleted: vendor/wpa/2.0/src/wps/wps_upnp_web.c
===================================================================
--- vendor/wpa/dist/src/wps/wps_upnp_web.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/src/wps/wps_upnp_web.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1270 +0,0 @@
-/*
- * UPnP WPS Device - Web connections
- * Copyright (c) 2000-2003 Intel Corporation
- * Copyright (c) 2006-2007 Sony Corporation
- * Copyright (c) 2008-2009 Atheros Communications
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * See wps_upnp.c for more details on licensing and code history.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "base64.h"
-#include "uuid.h"
-#include "httpread.h"
-#include "http_server.h"
-#include "wps_i.h"
-#include "wps_upnp.h"
-#include "wps_upnp_i.h"
-#include "upnp_xml.h"
-
-/***************************************************************************
- * Web connections (we serve pages of info about ourselves, handle
- * requests, etc. etc.).
- **************************************************************************/
-
-#define WEB_CONNECTION_TIMEOUT_SEC 30   /* Drop web connection after t.o. */
-#define WEB_CONNECTION_MAX_READ 8000    /* Max we'll read for TCP request */
-#define MAX_WEB_CONNECTIONS 10          /* max simultaneous web connects */
-
-
-static const char *urn_wfawlanconfig =
-	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
-static const char *http_server_hdr =
-	"Server: unspecified, UPnP/1.0, unspecified\r\n";
-static const char *http_connection_close =
-	"Connection: close\r\n";
-
-/*
- * "Files" that we serve via HTTP. The format of these files is given by
- * WFA WPS specifications. Extra white space has been removed to save space.
- */
-
-static const char wps_scpd_xml[] =
-"<?xml version=\"1.0\"?>\n"
-"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
-"<specVersion><major>1</major><minor>0</minor></specVersion>\n"
-"<actionList>\n"
-"<action>\n"
-"<name>GetDeviceInfo</name>\n"
-"<argumentList>\n"
-"<argument>\n"
-"<name>NewDeviceInfo</name>\n"
-"<direction>out</direction>\n"
-"<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
-"</argument>\n"
-"</argumentList>\n"
-"</action>\n"
-"<action>\n"
-"<name>PutMessage</name>\n"
-"<argumentList>\n"
-"<argument>\n"
-"<name>NewInMessage</name>\n"
-"<direction>in</direction>\n"
-"<relatedStateVariable>InMessage</relatedStateVariable>\n"
-"</argument>\n"
-"<argument>\n"
-"<name>NewOutMessage</name>\n"
-"<direction>out</direction>\n"
-"<relatedStateVariable>OutMessage</relatedStateVariable>\n"
-"</argument>\n"
-"</argumentList>\n"
-"</action>\n"
-"<action>\n"
-"<name>PutWLANResponse</name>\n"
-"<argumentList>\n"
-"<argument>\n"
-"<name>NewMessage</name>\n"
-"<direction>in</direction>\n"
-"<relatedStateVariable>Message</relatedStateVariable>\n"
-"</argument>\n"
-"<argument>\n"
-"<name>NewWLANEventType</name>\n"
-"<direction>in</direction>\n"
-"<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
-"</argument>\n"
-"<argument>\n"
-"<name>NewWLANEventMAC</name>\n"
-"<direction>in</direction>\n"
-"<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
-"</argument>\n"
-"</argumentList>\n"
-"</action>\n"
-"<action>\n"
-"<name>SetSelectedRegistrar</name>\n"
-"<argumentList>\n"
-"<argument>\n"
-"<name>NewMessage</name>\n"
-"<direction>in</direction>\n"
-"<relatedStateVariable>Message</relatedStateVariable>\n"
-"</argument>\n"
-"</argumentList>\n"
-"</action>\n"
-"</actionList>\n"
-"<serviceStateTable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>Message</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>InMessage</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>OutMessage</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>DeviceInfo</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"yes\">\n"
-"<name>APStatus</name>\n"
-"<dataType>ui1</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"yes\">\n"
-"<name>STAStatus</name>\n"
-"<dataType>ui1</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"yes\">\n"
-"<name>WLANEvent</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>WLANEventType</name>\n"
-"<dataType>ui1</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>WLANEventMAC</name>\n"
-"<dataType>string</dataType>\n"
-"</stateVariable>\n"
-"<stateVariable sendEvents=\"no\">\n"
-"<name>WLANResponse</name>\n"
-"<dataType>bin.base64</dataType>\n"
-"</stateVariable>\n"
-"</serviceStateTable>\n"
-"</scpd>\n"
-;
-
-
-static const char *wps_device_xml_prefix =
-	"<?xml version=\"1.0\"?>\n"
-	"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
-	"<specVersion>\n"
-	"<major>1</major>\n"
-	"<minor>0</minor>\n"
-	"</specVersion>\n"
-	"<device>\n"
-	"<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
-	"</deviceType>\n";
-
-static const char *wps_device_xml_postfix =
-	"<serviceList>\n"
-	"<service>\n"
-	"<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
-	"</serviceType>\n"
-	"<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
-	"\n"
-	"<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
-	"<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
-	"<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
-	"</service>\n"
-	"</serviceList>\n"
-	"</device>\n"
-	"</root>\n";
-
-
-/* format_wps_device_xml -- produce content of "file" wps_device.xml
- * (UPNP_WPS_DEVICE_XML_FILE)
- */
-static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
-				  struct wpabuf *buf)
-{
-	const char *s;
-	char uuid_string[80];
-
-	wpabuf_put_str(buf, wps_device_xml_prefix);
-
-	/*
-	 * Add required fields with default values if not configured. Add
-	 * optional and recommended fields only if configured.
-	 */
-	s = sm->wps->friendly_name;
-	s = ((s && *s) ? s : "WPS Access Point");
-	xml_add_tagged_data(buf, "friendlyName", s);
-
-	s = sm->wps->dev.manufacturer;
-	s = ((s && *s) ? s : "");
-	xml_add_tagged_data(buf, "manufacturer", s);
-
-	if (sm->wps->manufacturer_url)
-		xml_add_tagged_data(buf, "manufacturerURL",
-				    sm->wps->manufacturer_url);
-
-	if (sm->wps->model_description)
-		xml_add_tagged_data(buf, "modelDescription",
-				    sm->wps->model_description);
-
-	s = sm->wps->dev.model_name;
-	s = ((s && *s) ? s : "");
-	xml_add_tagged_data(buf, "modelName", s);
-
-	if (sm->wps->dev.model_number)
-		xml_add_tagged_data(buf, "modelNumber",
-				    sm->wps->dev.model_number);
-
-	if (sm->wps->model_url)
-		xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
-
-	if (sm->wps->dev.serial_number)
-		xml_add_tagged_data(buf, "serialNumber",
-				    sm->wps->dev.serial_number);
-
-	uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
-	s = uuid_string;
-	/* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
-	 * easily...
-	 */
-	wpabuf_put_str(buf, "<UDN>uuid:");
-	xml_data_encode(buf, s, os_strlen(s));
-	wpabuf_put_str(buf, "</UDN>\n");
-
-	if (sm->wps->upc)
-		xml_add_tagged_data(buf, "UPC", sm->wps->upc);
-
-	wpabuf_put_str(buf, wps_device_xml_postfix);
-}
-
-
-static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
-{
-	wpabuf_put_str(buf, "HTTP/1.1 ");
-	switch (code) {
-	case HTTP_OK:
-		wpabuf_put_str(buf, "200 OK\r\n");
-		break;
-	case HTTP_BAD_REQUEST:
-		wpabuf_put_str(buf, "400 Bad request\r\n");
-		break;
-	case HTTP_PRECONDITION_FAILED:
-		wpabuf_put_str(buf, "412 Precondition failed\r\n");
-		break;
-	case HTTP_UNIMPLEMENTED:
-		wpabuf_put_str(buf, "501 Unimplemented\r\n");
-		break;
-	case HTTP_INTERNAL_SERVER_ERROR:
-	default:
-		wpabuf_put_str(buf, "500 Internal server error\r\n");
-		break;
-	}
-}
-
-
-static void http_put_date(struct wpabuf *buf)
-{
-	wpabuf_put_str(buf, "Date: ");
-	format_date(buf);
-	wpabuf_put_str(buf, "\r\n");
-}
-
-
-static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
-{
-	http_put_reply_code(buf, code);
-	wpabuf_put_str(buf, http_server_hdr);
-	wpabuf_put_str(buf, http_connection_close);
-	wpabuf_put_str(buf, "Content-Length: 0\r\n"
-		       "\r\n");
-}
-
-
-/* Given that we have received a header w/ GET, act upon it
- *
- * Format of GET (case-insensitive):
- *
- * First line must be:
- *      GET /<file> HTTP/1.1
- * Since we don't do anything fancy we just ignore other lines.
- *
- * Our response (if no error) which includes only required lines is:
- * HTTP/1.1 200 OK
- * Connection: close
- * Content-Type: text/xml
- * Date: <rfc1123-date>
- *
- * Header lines must end with \r\n
- * Per RFC 2616, content-length: is not required but connection:close
- * 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 wpabuf *buf; /* output buffer, allocated */
-	char *put_length_here;
-	char *body_start;
-	enum {
-		GET_DEVICE_XML_FILE,
-		GET_SCPD_XML_FILE
-	} req;
-	size_t extra_len = 0;
-	int body_length;
-	char len_buf[10];
-
-	/*
-	 * It is not required that filenames be case insensitive but it is
-	 * allowed and cannot hurt here.
-	 */
-	if (filename == NULL)
-		filename = "(null)"; /* just in case */
-	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
-		req = GET_DEVICE_XML_FILE;
-		extra_len = 3000;
-		if (sm->wps->friendly_name)
-			extra_len += os_strlen(sm->wps->friendly_name);
-		if (sm->wps->manufacturer_url)
-			extra_len += os_strlen(sm->wps->manufacturer_url);
-		if (sm->wps->model_description)
-			extra_len += os_strlen(sm->wps->model_description);
-		if (sm->wps->model_url)
-			extra_len += os_strlen(sm->wps->model_url);
-		if (sm->wps->upc)
-			extra_len += os_strlen(sm->wps->upc);
-	} else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
-		req = GET_SCPD_XML_FILE;
-		extra_len = os_strlen(wps_scpd_xml);
-	} else {
-		/* File not found */
-		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
-			   filename);
-		buf = wpabuf_alloc(200);
-		if (buf == NULL) {
-			http_request_deinit(hreq);
-			return;
-		}
-		wpabuf_put_str(buf,
-			       "HTTP/1.1 404 Not Found\r\n"
-			       "Connection: close\r\n");
-
-		http_put_date(buf);
-
-		/* terminating empty line */
-		wpabuf_put_str(buf, "\r\n");
-
-		goto send_buf;
-	}
-
-	buf = wpabuf_alloc(1000 + extra_len);
-	if (buf == NULL) {
-		http_request_deinit(hreq);
-		return;
-	}
-
-	wpabuf_put_str(buf,
-		       "HTTP/1.1 200 OK\r\n"
-		       "Content-Type: text/xml; charset=\"utf-8\"\r\n");
-	wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
-	wpabuf_put_str(buf, "Connection: close\r\n");
-	wpabuf_put_str(buf, "Content-Length: ");
-	/*
-	 * We will paste the length in later, leaving some extra whitespace.
-	 * HTTP code is supposed to be tolerant of extra whitespace.
-	 */
-	put_length_here = wpabuf_put(buf, 0);
-	wpabuf_put_str(buf, "        \r\n");
-
-	http_put_date(buf);
-
-	/* terminating empty line */
-	wpabuf_put_str(buf, "\r\n");
-
-	body_start = wpabuf_put(buf, 0);
-
-	switch (req) {
-	case GET_DEVICE_XML_FILE:
-		format_wps_device_xml(sm, buf);
-		break;
-	case GET_SCPD_XML_FILE:
-		wpabuf_put_str(buf, wps_scpd_xml);
-		break;
-	}
-
-	/* Now patch in the content length at the end */
-	body_length = (char *) wpabuf_put(buf, 0) - body_start;
-	os_snprintf(len_buf, 10, "%d", body_length);
-	os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
-
-send_buf:
-	http_request_send_and_deinit(hreq, buf);
-}
-
-
-static enum http_reply_code
-web_process_get_device_info(struct upnp_wps_device_sm *sm,
-			    struct wpabuf **reply, const char **replyname)
-{
-	static const char *name = "NewDeviceInfo";
-	struct wps_config cfg;
-	struct upnp_wps_peer *peer = &sm->peer;
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
-
-	if (sm->ctx->ap_pin == NULL)
-		return HTTP_INTERNAL_SERVER_ERROR;
-
-	/*
-	 * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
-	 * registration over UPnP with the AP acting as an Enrollee. It should
-	 * be noted that this is frequently used just to get the device data,
-	 * i.e., there may not be any intent to actually complete the
-	 * registration.
-	 */
-
-	if (peer->wps)
-		wps_deinit(peer->wps);
-
-	os_memset(&cfg, 0, sizeof(cfg));
-	cfg.wps = sm->wps;
-	cfg.pin = (u8 *) sm->ctx->ap_pin;
-	cfg.pin_len = os_strlen(sm->ctx->ap_pin);
-	peer->wps = wps_init(&cfg);
-	if (peer->wps) {
-		enum wsc_op_code op_code;
-		*reply = wps_get_msg(peer->wps, &op_code);
-		if (*reply == NULL) {
-			wps_deinit(peer->wps);
-			peer->wps = NULL;
-		}
-	} else
-		*reply = NULL;
-	if (*reply == NULL) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
-		return HTTP_INTERNAL_SERVER_ERROR;
-	}
-	*replyname = name;
-	return HTTP_OK;
-}
-
-
-static enum http_reply_code
-web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
-			struct wpabuf **reply, const char **replyname)
-{
-	struct wpabuf *msg;
-	static const char *name = "NewOutMessage";
-	enum http_reply_code ret;
-	enum wps_process_res res;
-	enum wsc_op_code op_code;
-
-	/*
-	 * PutMessage is used by external UPnP-based Registrar to perform WPS
-	 * operation with the access point itself; as compared with
-	 * PutWLANResponse which is for proxying.
-	 */
-	wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
-	msg = xml_get_base64_item(data, "NewInMessage", &ret);
-	if (msg == NULL)
-		return ret;
-	res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg);
-	if (res == WPS_FAILURE)
-		*reply = NULL;
-	else
-		*reply = wps_get_msg(sm->peer.wps, &op_code);
-	wpabuf_free(msg);
-	if (*reply == NULL)
-		return HTTP_INTERNAL_SERVER_ERROR;
-	*replyname = name;
-	return HTTP_OK;
-}
-
-
-static enum http_reply_code
-web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
-			      struct wpabuf **reply, const char **replyname)
-{
-	struct wpabuf *msg;
-	enum http_reply_code ret;
-	u8 macaddr[ETH_ALEN];
-	int ev_type;
-	int type;
-	char *val;
-
-	/*
-	 * External UPnP-based Registrar is passing us a message to be proxied
-	 * over to a Wi-Fi -based client of ours.
-	 */
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
-	msg = xml_get_base64_item(data, "NewMessage", &ret);
-	if (msg == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
-			   "from PutWLANResponse");
-		return ret;
-	}
-	val = xml_get_first_item(data, "NewWLANEventType");
-	if (val == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
-			   "PutWLANResponse");
-		wpabuf_free(msg);
-		return UPNP_ARG_VALUE_INVALID;
-	}
-	ev_type = atol(val);
-	os_free(val);
-	val = xml_get_first_item(data, "NewWLANEventMAC");
-	if (val == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
-			   "PutWLANResponse");
-		wpabuf_free(msg);
-		return UPNP_ARG_VALUE_INVALID;
-	}
-	if (hwaddr_aton(val, macaddr)) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
-			   "PutWLANResponse: '%s'", val);
-		if (hwaddr_aton2(val, macaddr) > 0) {
-			/*
-			 * At least some versions of Intel PROset seem to be
-			 * using dot-deliminated MAC address format here.
-			 */
-			wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
-				   "incorrect MAC address format in "
-				   "NewWLANEventMAC");
-		} else {
-			wpabuf_free(msg);
-			os_free(val);
-			return UPNP_ARG_VALUE_INVALID;
-		}
-	}
-	os_free(val);
-	if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
-		struct wps_parse_attr attr;
-		if (wps_parse_msg(msg, &attr) < 0 ||
-		    attr.msg_type == NULL)
-			type = -1;
-		else
-			type = *attr.msg_type;
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
-	} else
-		type = -1;
-	if (!sm->ctx->rx_req_put_wlan_response ||
-	    sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
-					      type)) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
-			   "rx_req_put_wlan_response");
-		wpabuf_free(msg);
-		return HTTP_INTERNAL_SERVER_ERROR;
-	}
-	wpabuf_free(msg);
-	*replyname = NULL;
-	*reply = NULL;
-	return HTTP_OK;
-}
-
-
-static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
-{
-	struct subscr_addr *a;
-
-	dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
-		if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
-			return 1;
-	}
-	return 0;
-}
-
-
-static struct subscription * find_er(struct upnp_wps_device_sm *sm,
-				     struct sockaddr_in *cli)
-{
-	struct subscription *s;
-	dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
-		if (find_er_addr(s, cli))
-			return s;
-	return NULL;
-}
-
-
-static enum http_reply_code
-web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
-				   struct sockaddr_in *cli, char *data,
-				   struct wpabuf **reply,
-				   const char **replyname)
-{
-	struct wpabuf *msg;
-	enum http_reply_code ret;
-	struct subscription *s;
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
-	s = find_er(sm, cli);
-	if (s == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
-			   "from unknown ER");
-		return UPNP_ACTION_FAILED;
-	}
-	msg = xml_get_base64_item(data, "NewMessage", &ret);
-	if (msg == NULL)
-		return ret;
-	if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
-		wpabuf_free(msg);
-		return HTTP_INTERNAL_SERVER_ERROR;
-	}
-	wpabuf_free(msg);
-	*replyname = NULL;
-	*reply = NULL;
-	return HTTP_OK;
-}
-
-
-static const char *soap_prefix =
-	"<?xml version=\"1.0\"?>\n"
-	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
-	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
-	"<s:Body>\n";
-static const char *soap_postfix =
-	"</s:Body>\n</s:Envelope>\n";
-
-static const char *soap_error_prefix =
-	"<s:Fault>\n"
-	"<faultcode>s:Client</faultcode>\n"
-	"<faultstring>UPnPError</faultstring>\n"
-	"<detail>\n"
-	"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
-static const char *soap_error_postfix =
-	"<errorDescription>Error</errorDescription>\n"
-	"</UPnPError>\n"
-	"</detail>\n"
-	"</s:Fault>\n";
-
-static void web_connection_send_reply(struct http_request *req,
-				      enum http_reply_code ret,
-				      const char *action, int action_len,
-				      const struct wpabuf *reply,
-				      const char *replyname)
-{
-	struct wpabuf *buf;
-	char *replydata;
-	char *put_length_here = NULL;
-	char *body_start = NULL;
-
-	if (reply) {
-		size_t len;
-		replydata = (char *) base64_encode(wpabuf_head(reply),
-						   wpabuf_len(reply), &len);
-	} else
-		replydata = NULL;
-
-	/* Parameters of the response:
-	 *      action(action_len) -- action we are responding to
-	 *      replyname -- a name we need for the reply
-	 *      replydata -- NULL or null-terminated string
-	 */
-	buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
-			   (action_len > 0 ? action_len * 2 : 0));
-	if (buf == NULL) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
-			   "POST");
-		os_free(replydata);
-		http_request_deinit(req);
-		return;
-	}
-
-	/*
-	 * Assuming we will be successful, put in the output header first.
-	 * Note: we do not keep connections alive (and httpread does
-	 * not support it)... therefore we must have Connection: close.
-	 */
-	if (ret == HTTP_OK) {
-		wpabuf_put_str(buf,
-			       "HTTP/1.1 200 OK\r\n"
-			       "Content-Type: text/xml; "
-			       "charset=\"utf-8\"\r\n");
-	} else {
-		wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
-	}
-	wpabuf_put_str(buf, http_connection_close);
-
-	wpabuf_put_str(buf, "Content-Length: ");
-	/*
-	 * We will paste the length in later, leaving some extra whitespace.
-	 * HTTP code is supposed to be tolerant of extra whitespace.
-	 */
-	put_length_here = wpabuf_put(buf, 0);
-	wpabuf_put_str(buf, "        \r\n");
-
-	http_put_date(buf);
-
-	/* terminating empty line */
-	wpabuf_put_str(buf, "\r\n");
-
-	body_start = wpabuf_put(buf, 0);
-
-	if (ret == HTTP_OK) {
-		wpabuf_put_str(buf, soap_prefix);
-		wpabuf_put_str(buf, "<u:");
-		wpabuf_put_data(buf, action, action_len);
-		wpabuf_put_str(buf, "Response xmlns:u=\"");
-		wpabuf_put_str(buf, urn_wfawlanconfig);
-		wpabuf_put_str(buf, "\">\n");
-		if (replydata && replyname) {
-			/* TODO: might possibly need to escape part of reply
-			 * data? ...
-			 * probably not, unlikely to have ampersand(&) or left
-			 * angle bracket (<) in it...
-			 */
-			wpabuf_printf(buf, "<%s>", replyname);
-			wpabuf_put_str(buf, replydata);
-			wpabuf_printf(buf, "</%s>\n", replyname);
-		}
-		wpabuf_put_str(buf, "</u:");
-		wpabuf_put_data(buf, action, action_len);
-		wpabuf_put_str(buf, "Response>\n");
-		wpabuf_put_str(buf, soap_postfix);
-	} else {
-		/* Error case */
-		wpabuf_put_str(buf, soap_prefix);
-		wpabuf_put_str(buf, soap_error_prefix);
-		wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
-		wpabuf_put_str(buf, soap_error_postfix);
-		wpabuf_put_str(buf, soap_postfix);
-	}
-	os_free(replydata);
-
-	/* Now patch in the content length at the end */
-	if (body_start && put_length_here) {
-		int body_length = (char *) wpabuf_put(buf, 0) - body_start;
-		char len_buf[10];
-		os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
-		os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
-	}
-
-	http_request_send_and_deinit(req, buf);
-}
-
-
-static const char * web_get_action(struct http_request *req,
-				   size_t *action_len)
-{
-	const char *match;
-	int match_len;
-	char *b;
-	char *action;
-
-	*action_len = 0;
-	/* The SOAPAction line of the header tells us what we want to do */
-	b = http_request_get_hdr_line(req, "SOAPAction:");
-	if (b == NULL)
-		return NULL;
-	if (*b == '"')
-		b++;
-	else
-		return NULL;
-	match = urn_wfawlanconfig;
-	match_len = os_strlen(urn_wfawlanconfig) - 1;
-	if (os_strncasecmp(b, match, match_len))
-		return NULL;
-	b += match_len;
-	/* skip over version */
-	while (isgraph(*b) && *b != '#')
-		b++;
-	if (*b != '#')
-		return NULL;
-	b++;
-	/* Following the sharp(#) should be the action and a double quote */
-	action = b;
-	while (isgraph(*b) && *b != '"')
-		b++;
-	if (*b != '"')
-		return NULL;
-	*action_len = b - action;
-	return action;
-}
-
-
-/* Given that we have received a header w/ POST, act upon it
- *
- * Format of POST (case-insensitive):
- *
- * First line must be:
- *      POST /<file> HTTP/1.1
- * Since we don't do anything fancy we just ignore other lines.
- *
- * Our response (if no error) which includes only required lines is:
- * HTTP/1.1 200 OK
- * Connection: close
- * Content-Type: text/xml
- * Date: <rfc1123-date>
- *
- * Header lines must end with \r\n
- * Per RFC 2616, content-length: is not required but connection:close
- * would appear to be required (given that we will be closing it!).
- */
-static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
-				      struct sockaddr_in *cli,
-				      struct http_request *req,
-				      const char *filename)
-{
-	enum http_reply_code ret;
-	char *data = http_request_get_data(req); /* body of http msg */
-	const char *action = NULL;
-	size_t action_len = 0;
-	const char *replyname = NULL; /* argument name for the reply */
-	struct wpabuf *reply = NULL; /* data for the reply */
-
-	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
-			   filename);
-		ret = HTTP_NOT_FOUND;
-		goto bad;
-	}
-
-	ret = UPNP_INVALID_ACTION;
-	action = web_get_action(req, &action_len);
-	if (action == NULL)
-		goto bad;
-
-	if (!os_strncasecmp("GetDeviceInfo", action, action_len))
-		ret = web_process_get_device_info(sm, &reply, &replyname);
-	else if (!os_strncasecmp("PutMessage", action, action_len))
-		ret = web_process_put_message(sm, data, &reply, &replyname);
-	else if (!os_strncasecmp("PutWLANResponse", action, action_len))
-		ret = web_process_put_wlan_response(sm, data, &reply,
-						    &replyname);
-	else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
-		ret = web_process_set_selected_registrar(sm, cli, data, &reply,
-							 &replyname);
-	else
-		wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
-
-bad:
-	if (ret != HTTP_OK)
-		wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
-	web_connection_send_reply(req, ret, action, action_len, reply,
-				  replyname);
-	wpabuf_free(reply);
-}
-
-
-/* Given that we have received a header w/ SUBSCRIBE, act upon it
- *
- * Format of SUBSCRIBE (case-insensitive):
- *
- * First line must be:
- *      SUBSCRIBE /wps_event HTTP/1.1
- *
- * Our response (if no error) which includes only required lines is:
- * HTTP/1.1 200 OK
- * Server: xx, UPnP/1.0, xx
- * SID: uuid:xxxxxxxxx
- * Timeout: Second-<n>
- * Content-Length: 0
- * Date: xxxx
- *
- * Header lines must end with \r\n
- * Per RFC 2616, content-length: is not required but connection:close
- * would appear to be required (given that we will be closing it!).
- */
-static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
-					   struct http_request *req,
-					   const char *filename)
-{
-	struct wpabuf *buf;
-	char *b;
-	char *hdr = http_request_get_hdr(req);
-	char *h;
-	char *match;
-	int match_len;
-	char *end;
-	int len;
-	int got_nt = 0;
-	u8 uuid[UUID_LEN];
-	int got_uuid = 0;
-	char *callback_urls = NULL;
-	struct subscription *s = NULL;
-	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
-
-	buf = wpabuf_alloc(1000);
-	if (buf == NULL) {
-		http_request_deinit(req);
-		return;
-	}
-
-	/* Parse/validate headers */
-	h = hdr;
-	/* First line: SUBSCRIBE /wps_event HTTP/1.1
-	 * has already been parsed.
-	 */
-	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
-		ret = HTTP_PRECONDITION_FAILED;
-		goto error;
-	}
-	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
-	end = os_strchr(h, '\n');
-
-	for (; end != NULL; h = end + 1) {
-		/* Option line by option line */
-		h = end + 1;
-		end = os_strchr(h, '\n');
-		if (end == NULL)
-			break; /* no unterminated lines allowed */
-
-		/* NT assures that it is our type of subscription;
-		 * not used for a renewl.
-		 **/
-		match = "NT:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			match = "upnp:event";
-			match_len = os_strlen(match);
-			if (os_strncasecmp(h, match, match_len) != 0) {
-				ret = HTTP_BAD_REQUEST;
-				goto error;
-			}
-			got_nt = 1;
-			continue;
-		}
-		/* HOST should refer to us */
-#if 0
-		match = "HOST:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			.....
-		}
-#endif
-		/* CALLBACK gives one or more URLs for NOTIFYs
-		 * to be sent as a result of the subscription.
-		 * Each URL is enclosed in angle brackets.
-		 */
-		match = "CALLBACK:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			len = end - h;
-			os_free(callback_urls);
-			callback_urls = os_malloc(len + 1);
-			if (callback_urls == NULL) {
-				ret = HTTP_INTERNAL_SERVER_ERROR;
-				goto error;
-			}
-			os_memcpy(callback_urls, h, len);
-			callback_urls[len] = 0;
-			continue;
-		}
-		/* SID is only for renewal */
-		match = "SID:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			match = "uuid:";
-			match_len = os_strlen(match);
-			if (os_strncasecmp(h, match, match_len) != 0) {
-				ret = HTTP_BAD_REQUEST;
-				goto error;
-			}
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			if (uuid_str2bin(h, uuid)) {
-				ret = HTTP_BAD_REQUEST;
-				goto error;
-			}
-			got_uuid = 1;
-			continue;
-		}
-		/* TIMEOUT is requested timeout, but apparently we can
-		 * just ignore this.
-		 */
-	}
-
-	if (got_uuid) {
-		/* renewal */
-		if (callback_urls) {
-			ret = HTTP_BAD_REQUEST;
-			goto error;
-		}
-		s = subscription_renew(sm, uuid);
-		if (s == NULL) {
-			ret = HTTP_PRECONDITION_FAILED;
-			goto error;
-		}
-	} else if (callback_urls) {
-		if (!got_nt) {
-			ret = HTTP_PRECONDITION_FAILED;
-			goto error;
-		}
-		s = subscription_start(sm, callback_urls);
-		if (s == NULL) {
-			ret = HTTP_INTERNAL_SERVER_ERROR;
-			goto error;
-		}
-	} else {
-		ret = HTTP_PRECONDITION_FAILED;
-		goto error;
-	}
-
-	/* success */
-	http_put_reply_code(buf, HTTP_OK);
-	wpabuf_put_str(buf, http_server_hdr);
-	wpabuf_put_str(buf, http_connection_close);
-	wpabuf_put_str(buf, "Content-Length: 0\r\n");
-	wpabuf_put_str(buf, "SID: uuid:");
-	/* subscription id */
-	b = wpabuf_put(buf, 0);
-	uuid_bin2str(s->uuid, b, 80);
-	wpabuf_put(buf, os_strlen(b));
-	wpabuf_put_str(buf, "\r\n");
-	wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
-	http_put_date(buf);
-	/* And empty line to terminate header: */
-	wpabuf_put_str(buf, "\r\n");
-
-	os_free(callback_urls);
-	http_request_send_and_deinit(req, buf);
-	return;
-
-error:
-	/* Per UPnP spec:
-	* Errors
-	* Incompatible headers
-	*   400 Bad Request. If SID header and one of NT or CALLBACK headers
-	*     are present, the publisher must respond with HTTP error
-	*     400 Bad Request.
-	* Missing or invalid CALLBACK
-	*   412 Precondition Failed. If CALLBACK header is missing or does not
-	*     contain a valid HTTP URL, the publisher must respond with HTTP
-	*     error 412 Precondition Failed.
-	* Invalid NT
-	*   412 Precondition Failed. If NT header does not equal upnp:event,
-	*     the publisher must respond with HTTP error 412 Precondition
-	*     Failed.
-	* [For resubscription, use 412 if unknown uuid].
-	* Unable to accept subscription
-	*   5xx. If a publisher is not able to accept a subscription (such as
-	*     due to insufficient resources), it must respond with a
-	*     HTTP 500-series error code.
-	*   599 Too many subscriptions (not a standard HTTP error)
-	*/
-	http_put_empty(buf, ret);
-	http_request_send_and_deinit(req, buf);
-	os_free(callback_urls);
-}
-
-
-/* Given that we have received a header w/ UNSUBSCRIBE, act upon it
- *
- * Format of UNSUBSCRIBE (case-insensitive):
- *
- * First line must be:
- *      UNSUBSCRIBE /wps_event HTTP/1.1
- *
- * Our response (if no error) which includes only required lines is:
- * HTTP/1.1 200 OK
- * Content-Length: 0
- *
- * Header lines must end with \r\n
- * Per RFC 2616, content-length: is not required but connection:close
- * would appear to be required (given that we will be closing it!).
- */
-static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
-					     struct http_request *req,
-					     const char *filename)
-{
-	struct wpabuf *buf;
-	char *hdr = http_request_get_hdr(req);
-	char *h;
-	char *match;
-	int match_len;
-	char *end;
-	u8 uuid[UUID_LEN];
-	int got_uuid = 0;
-	struct subscription *s = NULL;
-	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
-
-	/* Parse/validate headers */
-	h = hdr;
-	/* First line: UNSUBSCRIBE /wps_event HTTP/1.1
-	 * has already been parsed.
-	 */
-	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
-		ret = HTTP_PRECONDITION_FAILED;
-		goto send_msg;
-	}
-	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
-	end = os_strchr(h, '\n');
-
-	for (; end != NULL; h = end + 1) {
-		/* Option line by option line */
-		h = end + 1;
-		end = os_strchr(h, '\n');
-		if (end == NULL)
-			break; /* no unterminated lines allowed */
-
-		/* HOST should refer to us */
-#if 0
-		match = "HOST:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			.....
-		}
-#endif
-		/* SID is only for renewal */
-		match = "SID:";
-		match_len = os_strlen(match);
-		if (os_strncasecmp(h, match, match_len) == 0) {
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			match = "uuid:";
-			match_len = os_strlen(match);
-			if (os_strncasecmp(h, match, match_len) != 0) {
-				ret = HTTP_BAD_REQUEST;
-				goto send_msg;
-			}
-			h += match_len;
-			while (*h == ' ' || *h == '\t')
-				h++;
-			if (uuid_str2bin(h, uuid)) {
-				ret = HTTP_BAD_REQUEST;
-				goto send_msg;
-			}
-			got_uuid = 1;
-			continue;
-		}
-	}
-
-	if (got_uuid) {
-		s = subscription_find(sm, uuid);
-		if (s) {
-			struct subscr_addr *sa;
-			sa = dl_list_first(&s->addr_list, struct subscr_addr,
-					   list);
-			wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
-				   s, (sa && sa->domain_and_port) ?
-				   sa->domain_and_port : "-null-");
-			dl_list_del(&s->list);
-			subscription_destroy(s);
-		}
-	} else {
-		wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
-			   "found)");
-		ret = HTTP_PRECONDITION_FAILED;
-		goto send_msg;
-	}
-
-	ret = HTTP_OK;
-
-send_msg:
-	buf = wpabuf_alloc(200);
-	if (buf == NULL) {
-		http_request_deinit(req);
-		return;
-	}
-	http_put_empty(buf, ret);
-	http_request_send_and_deinit(req, buf);
-}
-
-
-/* Send error in response to unknown requests */
-static void web_connection_unimplemented(struct http_request *req)
-{
-	struct wpabuf *buf;
-	buf = wpabuf_alloc(200);
-	if (buf == NULL) {
-		http_request_deinit(req);
-		return;
-	}
-	http_put_empty(buf, HTTP_UNIMPLEMENTED);
-	http_request_send_and_deinit(req, buf);
-}
-
-
-
-/* Called when we have gotten an apparently valid http request.
- */
-static void web_connection_check_data(void *ctx, struct http_request *req)
-{
-	struct upnp_wps_device_sm *sm = ctx;
-	enum httpread_hdr_type htype = http_request_get_type(req);
-	char *filename = http_request_get_uri(req);
-	struct sockaddr_in *cli = http_request_get_cli_addr(req);
-
-	if (!filename) {
-		wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
-		http_request_deinit(req);
-		return;
-	}
-	/* Trim leading slashes from filename */
-	while (*filename == '/')
-		filename++;
-
-	wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
-		   htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
-
-	switch (htype) {
-	case HTTPREAD_HDR_TYPE_GET:
-		web_connection_parse_get(sm, req, filename);
-		break;
-	case HTTPREAD_HDR_TYPE_POST:
-		web_connection_parse_post(sm, cli, req, filename);
-		break;
-	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
-		web_connection_parse_subscribe(sm, req, filename);
-		break;
-	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
-		web_connection_parse_unsubscribe(sm, req, filename);
-		break;
-
-		/* We are not required to support M-POST; just plain
-		 * POST is supposed to work, so we only support that.
-		 * If for some reason we need to support M-POST, it is
-		 * mostly the same as POST, with small differences.
-		 */
-	default:
-		/* Send 501 for anything else */
-		web_connection_unimplemented(req);
-		break;
-	}
-}
-
-
-/*
- * Listening for web connections
- * We have a single TCP listening port, and hand off connections as we get
- * them.
- */
-
-void web_listener_stop(struct upnp_wps_device_sm *sm)
-{
-	http_server_deinit(sm->web_srv);
-	sm->web_srv = NULL;
-}
-
-
-int web_listener_start(struct upnp_wps_device_sm *sm)
-{
-	struct in_addr addr;
-	addr.s_addr = sm->ip_addr;
-	sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
-				       sm);
-	if (sm->web_srv == NULL) {
-		web_listener_stop(sm);
-		return -1;
-	}
-	sm->web_port = http_server_get_port(sm->web_srv);
-
-	return 0;
-}

Copied: vendor/wpa/2.0/src/wps/wps_upnp_web.c (from rev 9639, vendor/wpa/dist/src/wps/wps_upnp_web.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_upnp_web.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_upnp_web.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1324 @@
+/*
+ * UPnP WPS Device - Web connections
+ * Copyright (c) 2000-2003 Intel Corporation
+ * Copyright (c) 2006-2007 Sony Corporation
+ * Copyright (c) 2008-2009 Atheros Communications
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * See wps_upnp.c for more details on licensing and code history.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "uuid.h"
+#include "httpread.h"
+#include "http_server.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+#include "upnp_xml.h"
+
+/***************************************************************************
+ * Web connections (we serve pages of info about ourselves, handle
+ * requests, etc. etc.).
+ **************************************************************************/
+
+#define WEB_CONNECTION_TIMEOUT_SEC 30   /* Drop web connection after t.o. */
+#define WEB_CONNECTION_MAX_READ 8000    /* Max we'll read for TCP request */
+#define MAX_WEB_CONNECTIONS 10          /* max simultaneous web connects */
+
+
+static const char *urn_wfawlanconfig =
+	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
+static const char *http_server_hdr =
+	"Server: unspecified, UPnP/1.0, unspecified\r\n";
+static const char *http_connection_close =
+	"Connection: close\r\n";
+
+/*
+ * "Files" that we serve via HTTP. The format of these files is given by
+ * WFA WPS specifications. Extra white space has been removed to save space.
+ */
+
+static const char wps_scpd_xml[] =
+"<?xml version=\"1.0\"?>\n"
+"<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
+"<specVersion><major>1</major><minor>0</minor></specVersion>\n"
+"<actionList>\n"
+"<action>\n"
+"<name>GetDeviceInfo</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewDeviceInfo</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>PutMessage</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewInMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>InMessage</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewOutMessage</name>\n"
+"<direction>out</direction>\n"
+"<relatedStateVariable>OutMessage</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>PutWLANResponse</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewWLANEventType</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
+"</argument>\n"
+"<argument>\n"
+"<name>NewWLANEventMAC</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"<action>\n"
+"<name>SetSelectedRegistrar</name>\n"
+"<argumentList>\n"
+"<argument>\n"
+"<name>NewMessage</name>\n"
+"<direction>in</direction>\n"
+"<relatedStateVariable>Message</relatedStateVariable>\n"
+"</argument>\n"
+"</argumentList>\n"
+"</action>\n"
+"</actionList>\n"
+"<serviceStateTable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>Message</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>InMessage</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>OutMessage</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>DeviceInfo</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>APStatus</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>STAStatus</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"yes\">\n"
+"<name>WLANEvent</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANEventType</name>\n"
+"<dataType>ui1</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANEventMAC</name>\n"
+"<dataType>string</dataType>\n"
+"</stateVariable>\n"
+"<stateVariable sendEvents=\"no\">\n"
+"<name>WLANResponse</name>\n"
+"<dataType>bin.base64</dataType>\n"
+"</stateVariable>\n"
+"</serviceStateTable>\n"
+"</scpd>\n"
+;
+
+
+static const char *wps_device_xml_prefix =
+	"<?xml version=\"1.0\"?>\n"
+	"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+	"<specVersion>\n"
+	"<major>1</major>\n"
+	"<minor>0</minor>\n"
+	"</specVersion>\n"
+	"<device>\n"
+	"<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
+	"</deviceType>\n";
+
+static const char *wps_device_xml_postfix =
+	"<serviceList>\n"
+	"<service>\n"
+	"<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
+	"</serviceType>\n"
+	"<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
+	"\n"
+	"<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
+	"<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
+	"<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
+	"</service>\n"
+	"</serviceList>\n"
+	"</device>\n"
+	"</root>\n";
+
+
+/* format_wps_device_xml -- produce content of "file" wps_device.xml
+ * (UPNP_WPS_DEVICE_XML_FILE)
+ */
+static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
+				  struct wpabuf *buf)
+{
+	const char *s;
+	char uuid_string[80];
+	struct upnp_wps_device_interface *iface;
+
+	iface = dl_list_first(&sm->interfaces,
+			      struct upnp_wps_device_interface, list);
+
+	wpabuf_put_str(buf, wps_device_xml_prefix);
+
+	/*
+	 * Add required fields with default values if not configured. Add
+	 * optional and recommended fields only if configured.
+	 */
+	s = iface->wps->friendly_name;
+	s = ((s && *s) ? s : "WPS Access Point");
+	xml_add_tagged_data(buf, "friendlyName", s);
+
+	s = iface->wps->dev.manufacturer;
+	s = ((s && *s) ? s : "");
+	xml_add_tagged_data(buf, "manufacturer", s);
+
+	if (iface->wps->manufacturer_url)
+		xml_add_tagged_data(buf, "manufacturerURL",
+				    iface->wps->manufacturer_url);
+
+	if (iface->wps->model_description)
+		xml_add_tagged_data(buf, "modelDescription",
+				    iface->wps->model_description);
+
+	s = iface->wps->dev.model_name;
+	s = ((s && *s) ? s : "");
+	xml_add_tagged_data(buf, "modelName", s);
+
+	if (iface->wps->dev.model_number)
+		xml_add_tagged_data(buf, "modelNumber",
+				    iface->wps->dev.model_number);
+
+	if (iface->wps->model_url)
+		xml_add_tagged_data(buf, "modelURL", iface->wps->model_url);
+
+	if (iface->wps->dev.serial_number)
+		xml_add_tagged_data(buf, "serialNumber",
+				    iface->wps->dev.serial_number);
+
+	uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
+	s = uuid_string;
+	/* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
+	 * easily...
+	 */
+	wpabuf_put_str(buf, "<UDN>uuid:");
+	xml_data_encode(buf, s, os_strlen(s));
+	wpabuf_put_str(buf, "</UDN>\n");
+
+	if (iface->wps->upc)
+		xml_add_tagged_data(buf, "UPC", iface->wps->upc);
+
+	wpabuf_put_str(buf, wps_device_xml_postfix);
+}
+
+
+static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
+{
+	wpabuf_put_str(buf, "HTTP/1.1 ");
+	switch (code) {
+	case HTTP_OK:
+		wpabuf_put_str(buf, "200 OK\r\n");
+		break;
+	case HTTP_BAD_REQUEST:
+		wpabuf_put_str(buf, "400 Bad request\r\n");
+		break;
+	case HTTP_PRECONDITION_FAILED:
+		wpabuf_put_str(buf, "412 Precondition failed\r\n");
+		break;
+	case HTTP_UNIMPLEMENTED:
+		wpabuf_put_str(buf, "501 Unimplemented\r\n");
+		break;
+	case HTTP_INTERNAL_SERVER_ERROR:
+	default:
+		wpabuf_put_str(buf, "500 Internal server error\r\n");
+		break;
+	}
+}
+
+
+static void http_put_date(struct wpabuf *buf)
+{
+	wpabuf_put_str(buf, "Date: ");
+	format_date(buf);
+	wpabuf_put_str(buf, "\r\n");
+}
+
+
+static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
+{
+	http_put_reply_code(buf, code);
+	wpabuf_put_str(buf, http_server_hdr);
+	wpabuf_put_str(buf, http_connection_close);
+	wpabuf_put_str(buf, "Content-Length: 0\r\n"
+		       "\r\n");
+}
+
+
+/* Given that we have received a header w/ GET, act upon it
+ *
+ * Format of GET (case-insensitive):
+ *
+ * First line must be:
+ *      GET /<file> HTTP/1.1
+ * Since we don't do anything fancy we just ignore other lines.
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Connection: close
+ * Content-Type: text/xml
+ * Date: <rfc1123-date>
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * 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 wpabuf *buf; /* output buffer, allocated */
+	char *put_length_here;
+	char *body_start;
+	enum {
+		GET_DEVICE_XML_FILE,
+		GET_SCPD_XML_FILE
+	} req;
+	size_t extra_len = 0;
+	int body_length;
+	char len_buf[10];
+	struct upnp_wps_device_interface *iface;
+
+	iface = dl_list_first(&sm->interfaces,
+			      struct upnp_wps_device_interface, list);
+
+	/*
+	 * It is not required that filenames be case insensitive but it is
+	 * allowed and cannot hurt here.
+	 */
+	if (filename == NULL)
+		filename = "(null)"; /* just in case */
+	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
+		req = GET_DEVICE_XML_FILE;
+		extra_len = 3000;
+		if (iface->wps->friendly_name)
+			extra_len += os_strlen(iface->wps->friendly_name);
+		if (iface->wps->manufacturer_url)
+			extra_len += os_strlen(iface->wps->manufacturer_url);
+		if (iface->wps->model_description)
+			extra_len += os_strlen(iface->wps->model_description);
+		if (iface->wps->model_url)
+			extra_len += os_strlen(iface->wps->model_url);
+		if (iface->wps->upc)
+			extra_len += os_strlen(iface->wps->upc);
+	} else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
+		req = GET_SCPD_XML_FILE;
+		extra_len = os_strlen(wps_scpd_xml);
+	} else {
+		/* File not found */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
+			   filename);
+		buf = wpabuf_alloc(200);
+		if (buf == NULL) {
+			http_request_deinit(hreq);
+			return;
+		}
+		wpabuf_put_str(buf,
+			       "HTTP/1.1 404 Not Found\r\n"
+			       "Connection: close\r\n");
+
+		http_put_date(buf);
+
+		/* terminating empty line */
+		wpabuf_put_str(buf, "\r\n");
+
+		goto send_buf;
+	}
+
+	buf = wpabuf_alloc(1000 + extra_len);
+	if (buf == NULL) {
+		http_request_deinit(hreq);
+		return;
+	}
+
+	wpabuf_put_str(buf,
+		       "HTTP/1.1 200 OK\r\n"
+		       "Content-Type: text/xml; charset=\"utf-8\"\r\n");
+	wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
+	wpabuf_put_str(buf, "Connection: close\r\n");
+	wpabuf_put_str(buf, "Content-Length: ");
+	/*
+	 * We will paste the length in later, leaving some extra whitespace.
+	 * HTTP code is supposed to be tolerant of extra whitespace.
+	 */
+	put_length_here = wpabuf_put(buf, 0);
+	wpabuf_put_str(buf, "        \r\n");
+
+	http_put_date(buf);
+
+	/* terminating empty line */
+	wpabuf_put_str(buf, "\r\n");
+
+	body_start = wpabuf_put(buf, 0);
+
+	switch (req) {
+	case GET_DEVICE_XML_FILE:
+		format_wps_device_xml(sm, buf);
+		break;
+	case GET_SCPD_XML_FILE:
+		wpabuf_put_str(buf, wps_scpd_xml);
+		break;
+	}
+
+	/* Now patch in the content length at the end */
+	body_length = (char *) wpabuf_put(buf, 0) - body_start;
+	os_snprintf(len_buf, 10, "%d", body_length);
+	os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
+
+send_buf:
+	http_request_send_and_deinit(hreq, buf);
+}
+
+
+static enum http_reply_code
+web_process_get_device_info(struct upnp_wps_device_sm *sm,
+			    struct wpabuf **reply, const char **replyname)
+{
+	static const char *name = "NewDeviceInfo";
+	struct wps_config cfg;
+	struct upnp_wps_device_interface *iface;
+	struct upnp_wps_peer *peer;
+
+	iface = dl_list_first(&sm->interfaces,
+			      struct upnp_wps_device_interface, list);
+	peer = &iface->peer;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
+
+	if (iface->ctx->ap_pin == NULL)
+		return HTTP_INTERNAL_SERVER_ERROR;
+
+	/*
+	 * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
+	 * registration over UPnP with the AP acting as an Enrollee. It should
+	 * be noted that this is frequently used just to get the device data,
+	 * i.e., there may not be any intent to actually complete the
+	 * 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;
+	cfg.pin_len = os_strlen(iface->ctx->ap_pin);
+	peer->wps = wps_init(&cfg);
+	if (peer->wps) {
+		enum wsc_op_code op_code;
+		*reply = wps_get_msg(peer->wps, &op_code);
+		if (*reply == NULL) {
+			wps_deinit(peer->wps);
+			peer->wps = NULL;
+		}
+	} else
+		*reply = NULL;
+	if (*reply == NULL) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
+		return HTTP_INTERNAL_SERVER_ERROR;
+	}
+	*replyname = name;
+	return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
+			struct wpabuf **reply, const char **replyname)
+{
+	struct wpabuf *msg;
+	static const char *name = "NewOutMessage";
+	enum http_reply_code ret;
+	enum wps_process_res res;
+	enum wsc_op_code op_code;
+	struct upnp_wps_device_interface *iface;
+
+	iface = dl_list_first(&sm->interfaces,
+			      struct upnp_wps_device_interface, list);
+
+	/*
+	 * PutMessage is used by external UPnP-based Registrar to perform WPS
+	 * operation with the access point itself; as compared with
+	 * PutWLANResponse which is for proxying.
+	 */
+	wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
+	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)
+		*reply = NULL;
+	else
+		*reply = wps_get_msg(iface->peer.wps, &op_code);
+	wpabuf_free(msg);
+	if (*reply == NULL)
+		return HTTP_INTERNAL_SERVER_ERROR;
+	*replyname = name;
+	return HTTP_OK;
+}
+
+
+static enum http_reply_code
+web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
+			      struct wpabuf **reply, const char **replyname)
+{
+	struct wpabuf *msg;
+	enum http_reply_code ret;
+	u8 macaddr[ETH_ALEN];
+	int ev_type;
+	int type;
+	char *val;
+	struct upnp_wps_device_interface *iface;
+	int ok = 0;
+
+	/*
+	 * External UPnP-based Registrar is passing us a message to be proxied
+	 * over to a Wi-Fi -based client of ours.
+	 */
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
+	msg = xml_get_base64_item(data, "NewMessage", &ret);
+	if (msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
+			   "from PutWLANResponse");
+		return ret;
+	}
+	val = xml_get_first_item(data, "NewWLANEventType");
+	if (val == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
+			   "PutWLANResponse");
+		wpabuf_free(msg);
+		return UPNP_ARG_VALUE_INVALID;
+	}
+	ev_type = atol(val);
+	os_free(val);
+	val = xml_get_first_item(data, "NewWLANEventMAC");
+	if (val == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
+			   "PutWLANResponse");
+		wpabuf_free(msg);
+		return UPNP_ARG_VALUE_INVALID;
+	}
+	if (hwaddr_aton(val, macaddr)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
+			   "PutWLANResponse: '%s'", val);
+#ifdef CONFIG_WPS_STRICT
+		{
+			struct wps_parse_attr attr;
+			if (wps_parse_msg(msg, &attr) < 0 || attr.version2) {
+				wpabuf_free(msg);
+				os_free(val);
+				return UPNP_ARG_VALUE_INVALID;
+			}
+		}
+#endif /* CONFIG_WPS_STRICT */
+		if (hwaddr_aton2(val, macaddr) > 0) {
+			/*
+			 * At least some versions of Intel PROset seem to be
+			 * using dot-deliminated MAC address format here.
+			 */
+			wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
+				   "incorrect MAC address format in "
+				   "NewWLANEventMAC: %s -> " MACSTR,
+				   val, MAC2STR(macaddr));
+		} else {
+			wpabuf_free(msg);
+			os_free(val);
+			return UPNP_ARG_VALUE_INVALID;
+		}
+	}
+	os_free(val);
+	if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
+		struct wps_parse_attr attr;
+		if (wps_parse_msg(msg, &attr) < 0 ||
+		    attr.msg_type == NULL)
+			type = -1;
+		else
+			type = *attr.msg_type;
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
+	} else
+		type = -1;
+	dl_list_for_each(iface, &sm->interfaces,
+			 struct upnp_wps_device_interface, list) {
+		if (iface->ctx->rx_req_put_wlan_response &&
+		    iface->ctx->rx_req_put_wlan_response(iface->priv, ev_type,
+							 macaddr, msg, type)
+		    == 0)
+			ok = 1;
+	}
+
+	if (!ok) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
+			   "rx_req_put_wlan_response");
+		wpabuf_free(msg);
+		return HTTP_INTERNAL_SERVER_ERROR;
+	}
+	wpabuf_free(msg);
+	*replyname = NULL;
+	*reply = NULL;
+	return HTTP_OK;
+}
+
+
+static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
+{
+	struct subscr_addr *a;
+
+	dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
+		if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
+			return 1;
+	}
+	return 0;
+}
+
+
+static struct subscription * find_er(struct upnp_wps_device_sm *sm,
+				     struct sockaddr_in *cli)
+{
+	struct subscription *s;
+	dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
+		if (find_er_addr(s, cli))
+			return s;
+	return NULL;
+}
+
+
+static enum http_reply_code
+web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
+				   struct sockaddr_in *cli, char *data,
+				   struct wpabuf **reply,
+				   const char **replyname)
+{
+	struct wpabuf *msg;
+	enum http_reply_code ret;
+	struct subscription *s;
+	struct upnp_wps_device_interface *iface;
+	int err = 0;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
+	s = find_er(sm, cli);
+	if (s == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
+			   "from unknown ER");
+		return UPNP_ACTION_FAILED;
+	}
+	msg = xml_get_base64_item(data, "NewMessage", &ret);
+	if (msg == NULL)
+		return ret;
+	dl_list_for_each(iface, &sm->interfaces,
+			 struct upnp_wps_device_interface, list) {
+		if (upnp_er_set_selected_registrar(iface->wps->registrar, s,
+						   msg))
+			err = 1;
+	}
+	wpabuf_free(msg);
+	if (err)
+		return HTTP_INTERNAL_SERVER_ERROR;
+	*replyname = NULL;
+	*reply = NULL;
+	return HTTP_OK;
+}
+
+
+static const char *soap_prefix =
+	"<?xml version=\"1.0\"?>\n"
+	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
+	"<s:Body>\n";
+static const char *soap_postfix =
+	"</s:Body>\n</s:Envelope>\n";
+
+static const char *soap_error_prefix =
+	"<s:Fault>\n"
+	"<faultcode>s:Client</faultcode>\n"
+	"<faultstring>UPnPError</faultstring>\n"
+	"<detail>\n"
+	"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
+static const char *soap_error_postfix =
+	"<errorDescription>Error</errorDescription>\n"
+	"</UPnPError>\n"
+	"</detail>\n"
+	"</s:Fault>\n";
+
+static void web_connection_send_reply(struct http_request *req,
+				      enum http_reply_code ret,
+				      const char *action, int action_len,
+				      const struct wpabuf *reply,
+				      const char *replyname)
+{
+	struct wpabuf *buf;
+	char *replydata;
+	char *put_length_here = NULL;
+	char *body_start = NULL;
+
+	if (reply) {
+		size_t len;
+		replydata = (char *) base64_encode(wpabuf_head(reply),
+						   wpabuf_len(reply), &len);
+	} else
+		replydata = NULL;
+
+	/* Parameters of the response:
+	 *      action(action_len) -- action we are responding to
+	 *      replyname -- a name we need for the reply
+	 *      replydata -- NULL or null-terminated string
+	 */
+	buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
+			   (action_len > 0 ? action_len * 2 : 0));
+	if (buf == NULL) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
+			   "POST");
+		os_free(replydata);
+		http_request_deinit(req);
+		return;
+	}
+
+	/*
+	 * Assuming we will be successful, put in the output header first.
+	 * Note: we do not keep connections alive (and httpread does
+	 * not support it)... therefore we must have Connection: close.
+	 */
+	if (ret == HTTP_OK) {
+		wpabuf_put_str(buf,
+			       "HTTP/1.1 200 OK\r\n"
+			       "Content-Type: text/xml; "
+			       "charset=\"utf-8\"\r\n");
+	} else {
+		wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
+	}
+	wpabuf_put_str(buf, http_connection_close);
+
+	wpabuf_put_str(buf, "Content-Length: ");
+	/*
+	 * We will paste the length in later, leaving some extra whitespace.
+	 * HTTP code is supposed to be tolerant of extra whitespace.
+	 */
+	put_length_here = wpabuf_put(buf, 0);
+	wpabuf_put_str(buf, "        \r\n");
+
+	http_put_date(buf);
+
+	/* terminating empty line */
+	wpabuf_put_str(buf, "\r\n");
+
+	body_start = wpabuf_put(buf, 0);
+
+	if (ret == HTTP_OK) {
+		wpabuf_put_str(buf, soap_prefix);
+		wpabuf_put_str(buf, "<u:");
+		wpabuf_put_data(buf, action, action_len);
+		wpabuf_put_str(buf, "Response xmlns:u=\"");
+		wpabuf_put_str(buf, urn_wfawlanconfig);
+		wpabuf_put_str(buf, "\">\n");
+		if (replydata && replyname) {
+			/* TODO: might possibly need to escape part of reply
+			 * data? ...
+			 * probably not, unlikely to have ampersand(&) or left
+			 * angle bracket (<) in it...
+			 */
+			wpabuf_printf(buf, "<%s>", replyname);
+			wpabuf_put_str(buf, replydata);
+			wpabuf_printf(buf, "</%s>\n", replyname);
+		}
+		wpabuf_put_str(buf, "</u:");
+		wpabuf_put_data(buf, action, action_len);
+		wpabuf_put_str(buf, "Response>\n");
+		wpabuf_put_str(buf, soap_postfix);
+	} else {
+		/* Error case */
+		wpabuf_put_str(buf, soap_prefix);
+		wpabuf_put_str(buf, soap_error_prefix);
+		wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
+		wpabuf_put_str(buf, soap_error_postfix);
+		wpabuf_put_str(buf, soap_postfix);
+	}
+	os_free(replydata);
+
+	/* Now patch in the content length at the end */
+	if (body_start && put_length_here) {
+		int body_length = (char *) wpabuf_put(buf, 0) - body_start;
+		char len_buf[10];
+		os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
+		os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
+	}
+
+	http_request_send_and_deinit(req, buf);
+}
+
+
+static const char * web_get_action(struct http_request *req,
+				   size_t *action_len)
+{
+	const char *match;
+	int match_len;
+	char *b;
+	char *action;
+
+	*action_len = 0;
+	/* The SOAPAction line of the header tells us what we want to do */
+	b = http_request_get_hdr_line(req, "SOAPAction:");
+	if (b == NULL)
+		return NULL;
+	if (*b == '"')
+		b++;
+	else
+		return NULL;
+	match = urn_wfawlanconfig;
+	match_len = os_strlen(urn_wfawlanconfig) - 1;
+	if (os_strncasecmp(b, match, match_len))
+		return NULL;
+	b += match_len;
+	/* skip over version */
+	while (isgraph(*b) && *b != '#')
+		b++;
+	if (*b != '#')
+		return NULL;
+	b++;
+	/* Following the sharp(#) should be the action and a double quote */
+	action = b;
+	while (isgraph(*b) && *b != '"')
+		b++;
+	if (*b != '"')
+		return NULL;
+	*action_len = b - action;
+	return action;
+}
+
+
+/* Given that we have received a header w/ POST, act upon it
+ *
+ * Format of POST (case-insensitive):
+ *
+ * First line must be:
+ *      POST /<file> HTTP/1.1
+ * Since we don't do anything fancy we just ignore other lines.
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Connection: close
+ * Content-Type: text/xml
+ * Date: <rfc1123-date>
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
+				      struct sockaddr_in *cli,
+				      struct http_request *req,
+				      const char *filename)
+{
+	enum http_reply_code ret;
+	char *data = http_request_get_data(req); /* body of http msg */
+	const char *action = NULL;
+	size_t action_len = 0;
+	const char *replyname = NULL; /* argument name for the reply */
+	struct wpabuf *reply = NULL; /* data for the reply */
+
+	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
+			   filename);
+		ret = HTTP_NOT_FOUND;
+		goto bad;
+	}
+
+	ret = UPNP_INVALID_ACTION;
+	action = web_get_action(req, &action_len);
+	if (action == NULL)
+		goto bad;
+
+	if (!os_strncasecmp("GetDeviceInfo", action, action_len))
+		ret = web_process_get_device_info(sm, &reply, &replyname);
+	else if (!os_strncasecmp("PutMessage", action, action_len))
+		ret = web_process_put_message(sm, data, &reply, &replyname);
+	else if (!os_strncasecmp("PutWLANResponse", action, action_len))
+		ret = web_process_put_wlan_response(sm, data, &reply,
+						    &replyname);
+	else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
+		ret = web_process_set_selected_registrar(sm, cli, data, &reply,
+							 &replyname);
+	else
+		wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
+
+bad:
+	if (ret != HTTP_OK)
+		wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
+	web_connection_send_reply(req, ret, action, action_len, reply,
+				  replyname);
+	wpabuf_free(reply);
+}
+
+
+/* Given that we have received a header w/ SUBSCRIBE, act upon it
+ *
+ * Format of SUBSCRIBE (case-insensitive):
+ *
+ * First line must be:
+ *      SUBSCRIBE /wps_event HTTP/1.1
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Server: xx, UPnP/1.0, xx
+ * SID: uuid:xxxxxxxxx
+ * Timeout: Second-<n>
+ * Content-Length: 0
+ * Date: xxxx
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
+					   struct http_request *req,
+					   const char *filename)
+{
+	struct wpabuf *buf;
+	char *b;
+	char *hdr = http_request_get_hdr(req);
+	char *h;
+	char *match;
+	int match_len;
+	char *end;
+	int len;
+	int got_nt = 0;
+	u8 uuid[UUID_LEN];
+	int got_uuid = 0;
+	char *callback_urls = NULL;
+	struct subscription *s = NULL;
+	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
+
+	buf = wpabuf_alloc(1000);
+	if (buf == NULL) {
+		http_request_deinit(req);
+		return;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE",
+			  (u8 *) hdr, os_strlen(hdr));
+
+	/* Parse/validate headers */
+	h = hdr;
+	/* First line: SUBSCRIBE /wps_event HTTP/1.1
+	 * has already been parsed.
+	 */
+	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
+		ret = HTTP_PRECONDITION_FAILED;
+		goto error;
+	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
+	end = os_strchr(h, '\n');
+
+	for (; end != NULL; h = end + 1) {
+		/* Option line by option line */
+		h = end + 1;
+		end = os_strchr(h, '\n');
+		if (end == NULL)
+			break; /* no unterminated lines allowed */
+
+		/* NT assures that it is our type of subscription;
+		 * not used for a renewal.
+		 **/
+		match = "NT:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			match = "upnp:event";
+			match_len = os_strlen(match);
+			if (os_strncasecmp(h, match, match_len) != 0) {
+				ret = HTTP_BAD_REQUEST;
+				goto error;
+			}
+			got_nt = 1;
+			continue;
+		}
+		/* HOST should refer to us */
+#if 0
+		match = "HOST:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			.....
+		}
+#endif
+		/* CALLBACK gives one or more URLs for NOTIFYs
+		 * to be sent as a result of the subscription.
+		 * Each URL is enclosed in angle brackets.
+		 */
+		match = "CALLBACK:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			len = end - h;
+			os_free(callback_urls);
+			callback_urls = os_malloc(len + 1);
+			if (callback_urls == NULL) {
+				ret = HTTP_INTERNAL_SERVER_ERROR;
+				goto error;
+			}
+			os_memcpy(callback_urls, h, len);
+			callback_urls[len] = 0;
+			continue;
+		}
+		/* SID is only for renewal */
+		match = "SID:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			match = "uuid:";
+			match_len = os_strlen(match);
+			if (os_strncasecmp(h, match, match_len) != 0) {
+				ret = HTTP_BAD_REQUEST;
+				goto error;
+			}
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			if (uuid_str2bin(h, uuid)) {
+				ret = HTTP_BAD_REQUEST;
+				goto error;
+			}
+			got_uuid = 1;
+			continue;
+		}
+		/* TIMEOUT is requested timeout, but apparently we can
+		 * just ignore this.
+		 */
+	}
+
+	if (got_uuid) {
+		/* renewal */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewal");
+		if (callback_urls) {
+			ret = HTTP_BAD_REQUEST;
+			goto error;
+		}
+		s = subscription_renew(sm, uuid);
+		if (s == NULL) {
+			char str[80];
+			uuid_bin2str(uuid, str, sizeof(str));
+			wpa_printf(MSG_DEBUG, "WPS UPnP: Could not find "
+				   "SID %s", str);
+			ret = HTTP_PRECONDITION_FAILED;
+			goto error;
+		}
+	} else if (callback_urls) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: New subscription");
+		if (!got_nt) {
+			ret = HTTP_PRECONDITION_FAILED;
+			goto error;
+		}
+		s = subscription_start(sm, callback_urls);
+		if (s == NULL) {
+			ret = HTTP_INTERNAL_SERVER_ERROR;
+			goto error;
+		}
+	} else {
+		ret = HTTP_PRECONDITION_FAILED;
+		goto error;
+	}
+
+	/* success */
+	http_put_reply_code(buf, HTTP_OK);
+	wpabuf_put_str(buf, http_server_hdr);
+	wpabuf_put_str(buf, http_connection_close);
+	wpabuf_put_str(buf, "Content-Length: 0\r\n");
+	wpabuf_put_str(buf, "SID: uuid:");
+	/* subscription id */
+	b = wpabuf_put(buf, 0);
+	uuid_bin2str(s->uuid, b, 80);
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Assigned SID %s", b);
+	wpabuf_put(buf, os_strlen(b));
+	wpabuf_put_str(buf, "\r\n");
+	wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
+	http_put_date(buf);
+	/* And empty line to terminate header: */
+	wpabuf_put_str(buf, "\r\n");
+
+	os_free(callback_urls);
+	http_request_send_and_deinit(req, buf);
+	return;
+
+error:
+	/* Per UPnP spec:
+	* Errors
+	* Incompatible headers
+	*   400 Bad Request. If SID header and one of NT or CALLBACK headers
+	*     are present, the publisher must respond with HTTP error
+	*     400 Bad Request.
+	* Missing or invalid CALLBACK
+	*   412 Precondition Failed. If CALLBACK header is missing or does not
+	*     contain a valid HTTP URL, the publisher must respond with HTTP
+	*     error 412 Precondition Failed.
+	* Invalid NT
+	*   412 Precondition Failed. If NT header does not equal upnp:event,
+	*     the publisher must respond with HTTP error 412 Precondition
+	*     Failed.
+	* [For resubscription, use 412 if unknown uuid].
+	* Unable to accept subscription
+	*   5xx. If a publisher is not able to accept a subscription (such as
+	*     due to insufficient resources), it must respond with a
+	*     HTTP 500-series error code.
+	*   599 Too many subscriptions (not a standard HTTP error)
+	*/
+	wpa_printf(MSG_DEBUG, "WPS UPnP: SUBSCRIBE failed - return %d", ret);
+	http_put_empty(buf, ret);
+	http_request_send_and_deinit(req, buf);
+	os_free(callback_urls);
+}
+
+
+/* Given that we have received a header w/ UNSUBSCRIBE, act upon it
+ *
+ * Format of UNSUBSCRIBE (case-insensitive):
+ *
+ * First line must be:
+ *      UNSUBSCRIBE /wps_event HTTP/1.1
+ *
+ * Our response (if no error) which includes only required lines is:
+ * HTTP/1.1 200 OK
+ * Content-Length: 0
+ *
+ * Header lines must end with \r\n
+ * Per RFC 2616, content-length: is not required but connection:close
+ * would appear to be required (given that we will be closing it!).
+ */
+static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
+					     struct http_request *req,
+					     const char *filename)
+{
+	struct wpabuf *buf;
+	char *hdr = http_request_get_hdr(req);
+	char *h;
+	char *match;
+	int match_len;
+	char *end;
+	u8 uuid[UUID_LEN];
+	int got_uuid = 0;
+	struct subscription *s = NULL;
+	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
+
+	/* Parse/validate headers */
+	h = hdr;
+	/* First line: UNSUBSCRIBE /wps_event HTTP/1.1
+	 * has already been parsed.
+	 */
+	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
+		ret = HTTP_PRECONDITION_FAILED;
+		goto send_msg;
+	}
+	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
+	end = os_strchr(h, '\n');
+
+	for (; end != NULL; h = end + 1) {
+		/* Option line by option line */
+		h = end + 1;
+		end = os_strchr(h, '\n');
+		if (end == NULL)
+			break; /* no unterminated lines allowed */
+
+		/* HOST should refer to us */
+#if 0
+		match = "HOST:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			.....
+		}
+#endif
+		/* SID is only for renewal */
+		match = "SID:";
+		match_len = os_strlen(match);
+		if (os_strncasecmp(h, match, match_len) == 0) {
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			match = "uuid:";
+			match_len = os_strlen(match);
+			if (os_strncasecmp(h, match, match_len) != 0) {
+				ret = HTTP_BAD_REQUEST;
+				goto send_msg;
+			}
+			h += match_len;
+			while (*h == ' ' || *h == '\t')
+				h++;
+			if (uuid_str2bin(h, uuid)) {
+				ret = HTTP_BAD_REQUEST;
+				goto send_msg;
+			}
+			got_uuid = 1;
+			continue;
+		}
+	}
+
+	if (got_uuid) {
+		s = subscription_find(sm, uuid);
+		if (s) {
+			struct subscr_addr *sa;
+			sa = dl_list_first(&s->addr_list, struct subscr_addr,
+					   list);
+			wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
+				   s, (sa && sa->domain_and_port) ?
+				   sa->domain_and_port : "-null-");
+			dl_list_del(&s->list);
+			subscription_destroy(s);
+		}
+	} else {
+		wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
+			   "found)");
+		ret = HTTP_PRECONDITION_FAILED;
+		goto send_msg;
+	}
+
+	ret = HTTP_OK;
+
+send_msg:
+	buf = wpabuf_alloc(200);
+	if (buf == NULL) {
+		http_request_deinit(req);
+		return;
+	}
+	http_put_empty(buf, ret);
+	http_request_send_and_deinit(req, buf);
+}
+
+
+/* Send error in response to unknown requests */
+static void web_connection_unimplemented(struct http_request *req)
+{
+	struct wpabuf *buf;
+	buf = wpabuf_alloc(200);
+	if (buf == NULL) {
+		http_request_deinit(req);
+		return;
+	}
+	http_put_empty(buf, HTTP_UNIMPLEMENTED);
+	http_request_send_and_deinit(req, buf);
+}
+
+
+
+/* Called when we have gotten an apparently valid http request.
+ */
+static void web_connection_check_data(void *ctx, struct http_request *req)
+{
+	struct upnp_wps_device_sm *sm = ctx;
+	enum httpread_hdr_type htype = http_request_get_type(req);
+	char *filename = http_request_get_uri(req);
+	struct sockaddr_in *cli = http_request_get_cli_addr(req);
+
+	if (!filename) {
+		wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
+		http_request_deinit(req);
+		return;
+	}
+	/* Trim leading slashes from filename */
+	while (*filename == '/')
+		filename++;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
+		   htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
+
+	switch (htype) {
+	case HTTPREAD_HDR_TYPE_GET:
+		web_connection_parse_get(sm, req, filename);
+		break;
+	case HTTPREAD_HDR_TYPE_POST:
+		web_connection_parse_post(sm, cli, req, filename);
+		break;
+	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
+		web_connection_parse_subscribe(sm, req, filename);
+		break;
+	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
+		web_connection_parse_unsubscribe(sm, req, filename);
+		break;
+
+		/* We are not required to support M-POST; just plain
+		 * POST is supposed to work, so we only support that.
+		 * If for some reason we need to support M-POST, it is
+		 * mostly the same as POST, with small differences.
+		 */
+	default:
+		/* Send 501 for anything else */
+		web_connection_unimplemented(req);
+		break;
+	}
+}
+
+
+/*
+ * Listening for web connections
+ * We have a single TCP listening port, and hand off connections as we get
+ * them.
+ */
+
+void web_listener_stop(struct upnp_wps_device_sm *sm)
+{
+	http_server_deinit(sm->web_srv);
+	sm->web_srv = NULL;
+}
+
+
+int web_listener_start(struct upnp_wps_device_sm *sm)
+{
+	struct in_addr addr;
+	addr.s_addr = sm->ip_addr;
+	sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
+				       sm);
+	if (sm->web_srv == NULL) {
+		web_listener_stop(sm);
+		return -1;
+	}
+	sm->web_port = http_server_get_port(sm->web_srv);
+
+	return 0;
+}

Copied: vendor/wpa/2.0/src/wps/wps_validate.c (from rev 9639, vendor/wpa/dist/src/wps/wps_validate.c)
===================================================================
--- vendor/wpa/2.0/src/wps/wps_validate.c	                        (rev 0)
+++ vendor/wpa/2.0/src/wps/wps_validate.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1975 @@
+/*
+ * Wi-Fi Protected Setup - Strict protocol validation routines
+ * Copyright (c) 2010, Atheros Communications, 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 "wps_i.h"
+#include "wps.h"
+
+
+#ifndef WPS_STRICT_ALL
+#define WPS_STRICT_WPS2
+#endif /* WPS_STRICT_ALL */
+
+
+static int wps_validate_version(const u8 *version, int mandatory)
+{
+	if (version == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Version attribute "
+				   "missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*version != 0x10) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version attribute "
+			   "value 0x%x", *version);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_version2(const u8 *version2, int mandatory)
+{
+	if (version2 == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Version2 attribute "
+				   "missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*version2 < 0x20) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version2 attribute "
+			   "value 0x%x", *version2);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_request_type(const u8 *request_type, int mandatory)
+{
+	if (request_type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Request Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*request_type > 0x03) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request Type "
+			   "attribute value 0x%x", *request_type);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_response_type(const u8 *response_type, int mandatory)
+{
+	if (response_type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Response Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*response_type > 0x03) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Response Type "
+			   "attribute value 0x%x", *response_type);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int valid_config_methods(u16 val, int wps2)
+{
+	if (wps2) {
+		if ((val & 0x6000) && !(val & WPS_CONFIG_DISPLAY)) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+				   "Display flag without old Display flag "
+				   "set");
+			return 0;
+		}
+		if (!(val & 0x6000) && (val & WPS_CONFIG_DISPLAY)) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Display flag "
+				   "without Physical/Virtual Display flag");
+			return 0;
+		}
+		if ((val & 0x0600) && !(val & WPS_CONFIG_PUSHBUTTON)) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+				   "PushButton flag without old PushButton "
+				   "flag set");
+			return 0;
+		}
+		if (!(val & 0x0600) && (val & WPS_CONFIG_PUSHBUTTON)) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: PushButton flag "
+				   "without Physical/Virtual PushButton flag");
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+static int wps_validate_config_methods(const u8 *config_methods, int wps2,
+				       int mandatory)
+{
+	u16 val;
+
+	if (config_methods == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Configuration "
+				   "Methods attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+
+	val = WPA_GET_BE16(config_methods);
+	if (!valid_config_methods(val, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+			   "Methods attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_ap_config_methods(const u8 *config_methods, int wps2,
+					  int mandatory)
+{
+	u16 val;
+
+	if (wps_validate_config_methods(config_methods, wps2, mandatory) < 0)
+		return -1;
+	if (config_methods == NULL)
+		return 0;
+	val = WPA_GET_BE16(config_methods);
+	if (val & WPS_CONFIG_PUSHBUTTON) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+			   "Methods attribute value 0x%04x in AP info "
+			   "(PushButton not allowed for registering new ER)",
+			   val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_uuid_e(const u8 *uuid_e, int mandatory)
+{
+	if (uuid_e == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: UUID-E "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_uuid_r(const u8 *uuid_r, int mandatory)
+{
+	if (uuid_r == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: UUID-R "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_primary_dev_type(const u8 *primary_dev_type,
+					 int mandatory)
+{
+	if (primary_dev_type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Primary Device Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_rf_bands(const u8 *rf_bands, int mandatory)
+{
+	if (rf_bands == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: RF Bands "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*rf_bands != WPS_RF_24GHZ && *rf_bands != WPS_RF_50GHZ &&
+	    *rf_bands != (WPS_RF_24GHZ | WPS_RF_50GHZ)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Rf Bands "
+			   "attribute value 0x%x", *rf_bands);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_assoc_state(const u8 *assoc_state, int mandatory)
+{
+	u16 val;
+	if (assoc_state == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Association State "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(assoc_state);
+	if (val > 4) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Association State "
+			   "attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_config_error(const u8 *config_error, int mandatory)
+{
+	u16 val;
+
+	if (config_error == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Configuration Error "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(config_error);
+	if (val > 18) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error "
+			   "attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_dev_password_id(const u8 *dev_password_id,
+					int mandatory)
+{
+	u16 val;
+
+	if (dev_password_id == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Device Password ID "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(dev_password_id);
+	if (val >= 0x0006 && val <= 0x000f) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID "
+			   "attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_manufacturer(const u8 *manufacturer, size_t len,
+				     int mandatory)
+{
+	if (manufacturer == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Manufacturer "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 0 && manufacturer[len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Manufacturer "
+			   "attribute value", manufacturer, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_model_name(const u8 *model_name, size_t len,
+				   int mandatory)
+{
+	if (model_name == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Model Name "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 0 && model_name[len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Name "
+			   "attribute value", model_name, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_model_number(const u8 *model_number, size_t len,
+				     int mandatory)
+{
+	if (model_number == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Model Number "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 0 && model_number[len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Number "
+			   "attribute value", model_number, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_serial_number(const u8 *serial_number, size_t len,
+				      int mandatory)
+{
+	if (serial_number == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Serial Number "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 0 && serial_number[len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Serial "
+				  "Number attribute value",
+				  serial_number, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_dev_name(const u8 *dev_name, size_t len,
+				 int mandatory)
+{
+	if (dev_name == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Device Name "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 0 && dev_name[len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Device Name "
+			   "attribute value", dev_name, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_request_to_enroll(const u8 *request_to_enroll,
+					  int mandatory)
+{
+	if (request_to_enroll == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Request to Enroll "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*request_to_enroll > 0x01) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request to Enroll "
+			   "attribute value 0x%x", *request_to_enroll);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_req_dev_type(const u8 *req_dev_type[], size_t num,
+				     int mandatory)
+{
+	if (num == 0) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Requested Device "
+				   "Type attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_wps_state(const u8 *wps_state, int mandatory)
+{
+	if (wps_state == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Wi-Fi Protected "
+				   "Setup State attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*wps_state != WPS_STATE_NOT_CONFIGURED &&
+	    *wps_state != WPS_STATE_CONFIGURED) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Wi-Fi Protected "
+			   "Setup State attribute value 0x%x", *wps_state);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_ap_setup_locked(const u8 *ap_setup_locked,
+					int mandatory)
+{
+	if (ap_setup_locked == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: AP Setup Locked "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*ap_setup_locked > 1) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid AP Setup Locked "
+			   "attribute value 0x%x", *ap_setup_locked);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_selected_registrar(const u8 *selected_registrar,
+					   int mandatory)
+{
+	if (selected_registrar == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*selected_registrar > 1) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+			   "attribute value 0x%x", *selected_registrar);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_sel_reg_config_methods(const u8 *config_methods,
+					       int wps2, int mandatory)
+{
+	u16 val;
+
+	if (config_methods == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+				   "Configuration Methods attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+
+	val = WPA_GET_BE16(config_methods);
+	if (!valid_config_methods(val, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+			   "Configuration Methods attribute value 0x%04x",
+			   val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_authorized_macs(const u8 *authorized_macs, size_t len,
+					int mandatory)
+{
+	if (authorized_macs == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Authorized MACs "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len > 30 && (len % ETH_ALEN) != 0) {
+		wpa_hexdump(MSG_INFO, "WPS-STRICT: Invalid Authorized "
+			    "MACs attribute value", authorized_macs, len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_msg_type(const u8 *msg_type, int mandatory)
+{
+	if (msg_type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Message Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*msg_type < WPS_Beacon || *msg_type > WPS_WSC_DONE) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Message Type "
+			   "attribute value 0x%x", *msg_type);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_mac_addr(const u8 *mac_addr, int mandatory)
+{
+	if (mac_addr == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: MAC Address "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (mac_addr[0] & 0x01) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid MAC Address "
+			   "attribute value " MACSTR, MAC2STR(mac_addr));
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_enrollee_nonce(const u8 *enrollee_nonce, int mandatory)
+{
+	if (enrollee_nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Enrollee Nonce "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_registrar_nonce(const u8 *registrar_nonce,
+					int mandatory)
+{
+	if (registrar_nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Registrar Nonce "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_public_key(const u8 *public_key, size_t len,
+				   int mandatory)
+{
+	if (public_key == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Public Key "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len != 192) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Public Key "
+			   "attribute length %d", (int) len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int num_bits_set(u16 val)
+{
+	int c;
+	for (c = 0; val; c++)
+		val &= val - 1;
+	return c;
+}
+
+
+static int wps_validate_auth_type_flags(const u8 *flags, int mandatory)
+{
+	u16 val;
+
+	if (flags == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+				   "Flags attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(flags);
+	if ((val & ~WPS_AUTH_TYPES) || !(val & WPS_AUTH_WPA2PSK)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+			   "Flags attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_auth_type(const u8 *type, int mandatory)
+{
+	u16 val;
+
+	if (type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(type);
+	if ((val & ~WPS_AUTH_TYPES) || val == 0 ||
+	    (num_bits_set(val) > 1 &&
+	     val != (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+			   "attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_encr_type_flags(const u8 *flags, int mandatory)
+{
+	u16 val;
+
+	if (flags == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+				   "Flags attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(flags);
+	if ((val & ~WPS_ENCR_TYPES) || !(val & WPS_ENCR_AES)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+			   "Flags attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_encr_type(const u8 *type, int mandatory)
+{
+	u16 val;
+
+	if (type == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	val = WPA_GET_BE16(type);
+	if ((val & ~WPS_ENCR_TYPES) || val == 0 ||
+	    (num_bits_set(val) > 1 && val != (WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+			   "attribute value 0x%04x", val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_conn_type_flags(const u8 *flags, int mandatory)
+{
+	if (flags == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Connection Type "
+				   "Flags attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if ((*flags & ~(WPS_CONN_ESS | WPS_CONN_IBSS)) ||
+	    !(*flags & WPS_CONN_ESS)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Connection Type "
+			   "Flags attribute value 0x%02x", *flags);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_os_version(const u8 *os_version, int mandatory)
+{
+	if (os_version == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: OS Version "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_authenticator(const u8 *authenticator, int mandatory)
+{
+	if (authenticator == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Authenticator "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_e_hash1(const u8 *hash, int mandatory)
+{
+	if (hash == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash1 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_e_hash2(const u8 *hash, int mandatory)
+{
+	if (hash == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash2 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_r_hash1(const u8 *hash, int mandatory)
+{
+	if (hash == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash1 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_r_hash2(const u8 *hash, int mandatory)
+{
+	if (hash == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash2 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_encr_settings(const u8 *encr_settings, size_t len,
+				   int mandatory)
+{
+	if (encr_settings == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Encrypted Settings "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (len < 16) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encrypted Settings "
+			   "attribute length %d", (int) len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_settings_delay_time(const u8 *delay, int mandatory)
+{
+	if (delay == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Settings Delay Time "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_r_snonce1(const u8 *nonce, int mandatory)
+{
+	if (nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce1 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_r_snonce2(const u8 *nonce, int mandatory)
+{
+	if (nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce2 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_e_snonce1(const u8 *nonce, int mandatory)
+{
+	if (nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce1 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_e_snonce2(const u8 *nonce, int mandatory)
+{
+	if (nonce == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce2 "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_key_wrap_auth(const u8 *auth, int mandatory)
+{
+	if (auth == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Key Wrap "
+				   "Authenticator attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_ssid(const u8 *ssid, size_t ssid_len, int mandatory)
+{
+	if (ssid == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: SSID "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (ssid_len == 0 || ssid[ssid_len - 1] == 0) {
+		wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid SSID "
+				  "attribute value", ssid, ssid_len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_network_key_index(const u8 *idx, int mandatory)
+{
+	if (idx == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Network Key Index "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_network_idx(const u8 *idx, int mandatory)
+{
+	if (idx == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Network Index "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+
+static int wps_validate_network_key(const u8 *key, size_t key_len,
+				    const u8 *encr_type, int mandatory)
+{
+	if (key == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (((encr_type == NULL || WPA_GET_BE16(encr_type) != WPS_ENCR_WEP) &&
+	     key_len > 8 && key_len < 64 && key[key_len - 1] == 0) ||
+	    key_len > 64) {
+		wpa_hexdump_ascii_key(MSG_INFO, "WPS-STRICT: Invalid Network "
+				      "Key attribute value", key, key_len);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_network_key_shareable(const u8 *val, int mandatory)
+{
+	if (val == NULL) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+				   "Shareable attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+	if (*val > 1) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Network Key "
+			   "Shareable attribute value 0x%x", *val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wps_validate_cred(const u8 *cred, size_t len)
+{
+	struct wps_parse_attr attr;
+	struct wpabuf buf;
+
+	if (cred == NULL)
+		return -1;
+	wpabuf_set(&buf, cred, len);
+	if (wps_parse_msg(&buf, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse Credential");
+		return -1;
+	}
+
+	if (wps_validate_network_idx(attr.network_idx, 1) ||
+	    wps_validate_ssid(attr.ssid, attr.ssid_len, 1) ||
+	    wps_validate_auth_type(attr.auth_type, 1) ||
+	    wps_validate_encr_type(attr.encr_type, 1) ||
+	    wps_validate_network_key_index(attr.network_key_idx, 0) ||
+	    wps_validate_network_key(attr.network_key, attr.network_key_len,
+				     attr.encr_type, 1) ||
+	    wps_validate_mac_addr(attr.mac_addr, 1) ||
+	    wps_validate_network_key_shareable(attr.network_key_shareable, 0))
+	{
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Credential");
+		return -1;
+	}
+
+
+	return 0;
+}
+
+
+static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+				   int mandatory)
+{
+	size_t i;
+
+	if (num == 0) {
+		if (mandatory) {
+			wpa_printf(MSG_INFO, "WPS-STRICT: Credential "
+				   "attribute missing");
+			return -1;
+		}
+		return 0;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (wps_validate_cred(cred[i], len[i]) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_validate_beacon(const struct wpabuf *wps_ie)
+{
+	struct wps_parse_attr attr;
+	int wps2, sel_reg;
+
+	if (wps_ie == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in Beacon frame");
+		return -1;
+	}
+	if (wps_parse_msg(wps_ie, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+			   "Beacon frame");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	sel_reg = attr.selected_registrar != NULL &&
+		*attr.selected_registrar != 0;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_wps_state(attr.wps_state, 1) ||
+	    wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+	    wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+	    wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+						wps2, sel_reg) ||
+	    wps_validate_uuid_e(attr.uuid_e, 0) ||
+	    wps_validate_rf_bands(attr.rf_bands, 0) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authorized_macs(attr.authorized_macs,
+					 attr.authorized_macs_len, 0)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Beacon frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,
+				   const u8 *addr)
+{
+	struct wps_parse_attr attr;
+	int wps2, sel_reg;
+
+	if (wps_ie == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+			   "%sProbe Response frame", probe ? "" : "Beacon/");
+		return -1;
+	}
+	if (wps_parse_msg(wps_ie, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+			   "%sProbe Response frame", probe ? "" : "Beacon/");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	sel_reg = attr.selected_registrar != NULL &&
+		*attr.selected_registrar != 0;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_wps_state(attr.wps_state, 1) ||
+	    wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+	    wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+	    wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+						wps2, sel_reg) ||
+	    wps_validate_response_type(attr.response_type, probe) ||
+	    wps_validate_uuid_e(attr.uuid_e, probe) ||
+	    wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+				      probe) ||
+	    wps_validate_model_name(attr.model_name, attr.model_name_len,
+				    probe) ||
+	    wps_validate_model_number(attr.model_number, attr.model_number_len,
+				      probe) ||
+	    wps_validate_serial_number(attr.serial_number,
+				       attr.serial_number_len, probe) ||
+	    wps_validate_primary_dev_type(attr.primary_dev_type, probe) ||
+	    wps_validate_dev_name(attr.dev_name, attr.dev_name_len, probe) ||
+	    wps_validate_ap_config_methods(attr.config_methods, wps2, probe) ||
+	    wps_validate_rf_bands(attr.rf_bands, 0) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authorized_macs(attr.authorized_macs,
+					 attr.authorized_macs_len, 0)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid %sProbe Response "
+			   "frame from " MACSTR, probe ? "" : "Beacon/",
+			   MAC2STR(addr));
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (wps_ie == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+			   "Probe Request frame");
+		return -1;
+	}
+	if (wps_parse_msg(wps_ie, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+			   "Probe Request frame");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_request_type(attr.request_type, 1) ||
+	    wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+	    wps_validate_uuid_e(attr.uuid_e, attr.uuid_r == NULL) ||
+	    wps_validate_uuid_r(attr.uuid_r, attr.uuid_e == NULL) ||
+	    wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+	    wps_validate_rf_bands(attr.rf_bands, 1) ||
+	    wps_validate_assoc_state(attr.assoc_state, 1) ||
+	    wps_validate_config_error(attr.config_error, 1) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+				      wps2) ||
+	    wps_validate_model_name(attr.model_name, attr.model_name_len,
+				    wps2) ||
+	    wps_validate_model_number(attr.model_number, attr.model_number_len,
+				      wps2) ||
+	    wps_validate_dev_name(attr.dev_name, attr.dev_name_len, wps2) ||
+	    wps_validate_request_to_enroll(attr.request_to_enroll, 0) ||
+	    wps_validate_req_dev_type(attr.req_dev_type, attr.num_req_dev_type,
+				      0)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Probe Request "
+			   "frame from " MACSTR, MAC2STR(addr));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (wps_ie == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+			   "(Re)Association Request frame");
+		return -1;
+	}
+	if (wps_parse_msg(wps_ie, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+			   "(Re)Association Request frame");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_request_type(attr.request_type, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+			   "Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (wps_ie == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+			   "(Re)Association Response frame");
+		return -1;
+	}
+	if (wps_parse_msg(wps_ie, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+			   "(Re)Association Response frame");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_response_type(attr.response_type, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+			   "Response frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m1(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M1");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M1");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_uuid_e(attr.uuid_e, 1) ||
+	    wps_validate_mac_addr(attr.mac_addr, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+	    wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+	    wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+	    wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+	    wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+	    wps_validate_wps_state(attr.wps_state, 1) ||
+	    wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+				      1) ||
+	    wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+	    wps_validate_model_number(attr.model_number, attr.model_number_len,
+				      1) ||
+	    wps_validate_serial_number(attr.serial_number,
+				       attr.serial_number_len, 1) ||
+	    wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+	    wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+	    wps_validate_rf_bands(attr.rf_bands, 1) ||
+	    wps_validate_assoc_state(attr.assoc_state, 1) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+	    wps_validate_config_error(attr.config_error, 1) ||
+	    wps_validate_os_version(attr.os_version, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_request_to_enroll(attr.request_to_enroll, 0)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M1");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m2(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M2");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_uuid_r(attr.uuid_r, 1) ||
+	    wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+	    wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+	    wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+	    wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+	    wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+	    wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+				      1) ||
+	    wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+	    wps_validate_model_number(attr.model_number, attr.model_number_len,
+				      1) ||
+	    wps_validate_serial_number(attr.serial_number,
+				       attr.serial_number_len, 1) ||
+	    wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+	    wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+	    wps_validate_rf_bands(attr.rf_bands, 1) ||
+	    wps_validate_assoc_state(attr.assoc_state, 1) ||
+	    wps_validate_config_error(attr.config_error, 1) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+	    wps_validate_os_version(attr.os_version, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2D");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M2D");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_uuid_r(attr.uuid_r, 1) ||
+	    wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+	    wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+	    wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+	    wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+	    wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+				      1) ||
+	    wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+	    wps_validate_model_number(attr.model_number, attr.model_number_len,
+				      1) ||
+	    wps_validate_serial_number(attr.serial_number,
+				       attr.serial_number_len, 1) ||
+	    wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+	    wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+	    wps_validate_rf_bands(attr.rf_bands, 1) ||
+	    wps_validate_assoc_state(attr.assoc_state, 1) ||
+	    wps_validate_config_error(attr.config_error, 1) ||
+	    wps_validate_os_version(attr.os_version, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2D");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m3(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M3");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M3");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_e_hash1(attr.e_hash1, 1) ||
+	    wps_validate_e_hash2(attr.e_hash2, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M3");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m4(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M4");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_r_hash1(attr.r_hash1, 1) ||
+	    wps_validate_r_hash2(attr.r_hash2, 1) ||
+	    wps_validate_encr_settings(attr.encr_settings,
+				       attr.encr_settings_len, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)
+{
+	struct wps_parse_attr attr;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4 encrypted "
+			   "settings");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M4 encrypted settings");
+		return -1;
+	}
+
+	if (wps_validate_r_snonce1(attr.r_snonce1, 1) ||
+	    wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4 encrypted "
+			   "settings");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m5(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M5");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_encr_settings(attr.encr_settings,
+				       attr.encr_settings_len, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)
+{
+	struct wps_parse_attr attr;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5 encrypted "
+			   "settings");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M5 encrypted settings");
+		return -1;
+	}
+
+	if (wps_validate_e_snonce1(attr.e_snonce1, 1) ||
+	    wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5 encrypted "
+			   "settings");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m6(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M6");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_encr_settings(attr.encr_settings,
+				       attr.encr_settings_len, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)
+{
+	struct wps_parse_attr attr;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6 encrypted "
+			   "settings");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M6 encrypted settings");
+		return -1;
+	}
+
+	if (wps_validate_r_snonce2(attr.r_snonce2, 1) ||
+	    wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6 encrypted "
+			   "settings");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m7(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M7");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_encr_settings(attr.encr_settings,
+				       attr.encr_settings_len, 1) ||
+	    wps_validate_settings_delay_time(attr.settings_delay_time, 0) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2)
+{
+	struct wps_parse_attr attr;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7 encrypted "
+			   "settings");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M7 encrypted settings");
+		return -1;
+	}
+
+	if (wps_validate_e_snonce2(attr.e_snonce2, 1) ||
+	    wps_validate_ssid(attr.ssid, attr.ssid_len, !ap) ||
+	    wps_validate_mac_addr(attr.mac_addr, !ap) ||
+	    wps_validate_auth_type(attr.auth_type, !ap) ||
+	    wps_validate_encr_type(attr.encr_type, !ap) ||
+	    wps_validate_network_key_index(attr.network_key_idx, 0) ||
+	    wps_validate_network_key(attr.network_key, attr.network_key_len,
+				     attr.encr_type, !ap) ||
+	    wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7 encrypted "
+			   "settings");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m8(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M8");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_encr_settings(attr.encr_settings,
+				       attr.encr_settings_len, 1) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authenticator(attr.authenticator, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2)
+{
+	struct wps_parse_attr attr;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8 encrypted "
+			   "settings");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in M8 encrypted settings");
+		return -1;
+	}
+
+	if (wps_validate_ssid(attr.ssid, attr.ssid_len, ap) ||
+	    wps_validate_auth_type(attr.auth_type, ap) ||
+	    wps_validate_encr_type(attr.encr_type, ap) ||
+	    wps_validate_network_key_index(attr.network_key_idx, 0) ||
+	    wps_validate_mac_addr(attr.mac_addr, ap) ||
+	    wps_validate_credential(attr.cred, attr.cred_len, attr.num_cred,
+				    !ap) ||
+	    wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8 encrypted "
+			   "settings");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_ACK");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in WSC_ACK");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_ACK");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_NACK");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in WSC_NACK");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_config_error(attr.config_error, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_NACK");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_Done");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in WSC_Done");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_msg_type(attr.msg_type, 1) ||
+	    wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+	    wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+	    wps_validate_version2(attr.version2, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_Done");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}
+
+
+int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs)
+{
+	struct wps_parse_attr attr;
+	int wps2;
+	int sel_reg;
+
+	if (tlvs == NULL) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in "
+			   "SetSelectedRegistrar");
+		return -1;
+	}
+	if (wps_parse_msg(tlvs, &attr) < 0) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+			   "in SetSelectedRegistrar");
+		return -1;
+	}
+
+	wps2 = attr.version2 != NULL;
+	sel_reg = attr.selected_registrar != NULL &&
+		*attr.selected_registrar != 0;
+	if (wps_validate_version(attr.version, 1) ||
+	    wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+	    wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+						wps2, sel_reg) ||
+	    wps_validate_version2(attr.version2, wps2) ||
+	    wps_validate_authorized_macs(attr.authorized_macs,
+					 attr.authorized_macs_len, wps2) ||
+	    wps_validate_uuid_r(attr.uuid_r, wps2)) {
+		wpa_printf(MSG_INFO, "WPS-STRICT: Invalid "
+			   "SetSelectedRegistrar");
+#ifdef WPS_STRICT_WPS2
+		if (wps2)
+			return -1;
+#else /* WPS_STRICT_WPS2 */
+		return -1;
+#endif /* WPS_STRICT_WPS2 */
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/.gitignore
===================================================================
--- vendor/wpa/dist/wpa_supplicant/.gitignore	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/.gitignore	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,8 +0,0 @@
-*.d
-.config
-eapol_test
-preauth_test
-wpa_cli
-wpa_passphrase
-wpa_supplicant
-wpa_priv

Copied: vendor/wpa/2.0/wpa_supplicant/.gitignore (from rev 9639, vendor/wpa/dist/wpa_supplicant/.gitignore)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/.gitignore	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/.gitignore	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1 @@
+*.service

Deleted: vendor/wpa/2.0/wpa_supplicant/ChangeLog
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ChangeLog	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ChangeLog	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1314 +0,0 @@
-ChangeLog for wpa_supplicant
-
-2010-09-07 - v0.7.3
-	* fixed fallback from failed PMKSA caching into full EAP authentication
-	  [Bug 355]
-	* fixed issue with early D-Bus signals during initialization
-	* fixed X.509 name handling in internal TLS
-	* fixed WPS ER to use corrent Enrollee MAC Address in Credential
-	* fixed scanning routines ot improve AP selection for WPS
-	* added WPS workaround for open networks
-	* fixed WPS Diffie-Hellman derivation to use correct public key length
-	* fixed wpa_supplicant AP mode operations to ignore Supplicant and
-	  scan result events
-	* improved SME operations with nl80211
-	* fixed WPS ER event_id handling in some cases
-	* fixed some issues with bgscan simple to avoid unnecessary scans
-	* fixed issue with l2_packet_ndis overlapped writes corrupting stack
-	  [Bug 328]
-	* updated WinPcap to the latest stable version 4.1.2 in Windows
-	  installer
-
-2010-04-18 - v0.7.2
-	* nl80211: fixed number of issues with roaming
-	* avoid unnecessary roaming if multiple APs with similar signal
-	  strength are present in scan results
-	* add TLS client events and server probing to ease design of
-	  automatic detection of EAP parameters
-	* add option for server certificate matching (SHA256 hash of the
-	  certificate) instead of trusted CA certificate configuration
-	* bsd: Cleaned up driver wrapper and added various low-level
-	  configuration options
-	* wpa_gui-qt4: do not show too frequent WPS AP available events as
-	  tray messages
-	* TNC: fixed issues with fragmentation
-	* EAP-TNC: add Flags field into fragment acknowledgement (needed to
-	  interoperate with other implementations; may potentially breaks
-	  compatibility with older wpa_supplicant/hostapd versions)
-	* wpa_cli: added option for using a separate process to receive event
-	  messages to reduce latency in showing these
-	  (CFLAGS += -DCONFIG_WPA_CLI_FORK=y in .config to enable this)
-	* maximum BSS table size can now be configured (bss_max_count)
-	* BSSes to be included in the BSS table can be filtered based on
-	  configured SSIDs to save memory (filter_ssids)
-	* fix number of issues with IEEE 802.11r/FT; this version is not
-	  backwards compatible with old versions
-	* nl80211: add support for IEEE 802.11r/FT protocol (both over-the-air
-	  and over-the-DS)
-	* add freq_list network configuration parameter to allow the AP
-	  selection to filter out entries based on the operating channel
-	* add signal strength change events for bgscan; this allows more
-	  dynamic changes to background scanning interval based on changes in
-	  the signal strength with the current AP; this improves roaming within
-	  ESS quite a bit, e.g., with bgscan="simple:30:-45:300" in the network
-	  configuration block to request background scans less frequently when
-	  signal strength remains good and to automatically trigger background
-	  scans whenever signal strength drops noticeably
-	  (this is currently only available with nl80211)
-	* add BSSID and reason code (if available) to disconnect event messages
-	* wpa_gui-qt4: more complete support for translating the GUI with
-	  linguist and add German translation
-	* fix DH padding with internal crypto code (mainly, for WPS)
-	* do not trigger initial scan automatically anymore if there are no
-	  enabled networks
-
-2010-01-16 - v0.7.1
-	* cleaned up driver wrapper API (struct wpa_driver_ops); the new API
-	  is not fully backwards compatible, so out-of-tree driver wrappers
-	  will need modifications
-	* cleaned up various module interfaces
-	* merge hostapd and wpa_supplicant developers' documentation into a
-	  single document
-	* nl80211: use explicit deauthentication to clear cfg80211 state to
-	  avoid issues when roaming between APs
-	* dbus: major design changes in the new D-Bus API
-	  (fi.w1.wpa_supplicant1)
-	* nl80211: added support for IBSS networks
-	* added internal debugging mechanism with backtrace support and memory
-	  allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
-	* added WPS ER unsubscription command to more cleanly unregister from
-	  receiving UPnP events when ER is terminated
-	* cleaned up AP mode operations to avoid need for virtual driver_ops
-	  wrapper
-	* added BSS table to maintain more complete scan result information
-	  over multiple scans (that may include only partial results)
-	* wpa_gui-qt4: update Peers dialog information more dynamically while
-	  the dialog is kept open
-	* fixed PKCS#12 use with OpenSSL 1.0.0
-	* driver_wext: Added cfg80211-specific optimization to avoid some
-	  unnecessary scans and to speed up association
-
-2009-11-21 - v0.7.0
-	* increased wpa_cli ping interval to 5 seconds and made this
-	  configurable with a new command line options (-G<seconds>)
-	* fixed scan buffer processing with WEXT to handle up to 65535
-	  byte result buffer (previously, limited to 32768 bytes)
-	* allow multiple driver wrappers to be specified on command line
-	  (e.g., -Dnl80211,wext); the first one that is able to initialize the
-	  interface will be used
-	* added support for multiple SSIDs per scan request to optimize
-	  scan_ssid=1 operations in ap_scan=1 mode (i.e., search for hidden
-	  SSIDs); this requires driver support and can currently be used only
-	  with nl80211
-	* added support for WPS USBA out-of-band mechanism with USB Flash
-	  Drives (UFD) (CONFIG_WPS_UFD=y)
-	* driver_ndis: add PAE group address to the multicast address list to
-	  fix wired IEEE 802.1X authentication
-	* fixed IEEE 802.11r key derivation function to match with the standard
-	  (note: this breaks interoperability with previous version) [Bug 303]
-	* added better support for drivers that allow separate authentication
-	  and association commands (e.g., mac80211-based Linux drivers with
-	  nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol
-	  to be used (IEEE 802.11r)
-	* fixed SHA-256 based key derivation function to match with the
-	  standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
-	  (note: this breaks interoperability with previous version) [Bug 307]
-	* use shared driver wrapper files with hostapd
-	* added AP mode functionality (CONFIG_AP=y) with mode=2 in the network
-	  block; this can be used for open and WPA2-Personal networks
-	  (optionally, with WPS); this links in parts of hostapd functionality
-	  into wpa_supplicant
-	* wpa_gui-qt4: added new Peers dialog to show information about peers
-	  (other devices, including APs and stations, etc. in the neighborhood)
-	* added support for WPS External Registrar functionality (configure APs
-	  and enroll new devices); can be used with wpa_gui-qt4 Peers dialog
-	  and wpa_cli commands wps_er_start, wps_er_stop, wps_er_pin,
-	  wps_er_pbc, wps_er_learn
-	  (this can also be used with a new 'none' driver wrapper if no
-	  wireless device or IEEE 802.1X on wired is needed)
-	* driver_nl80211: multiple updates to provide support for new Linux
-	  nl80211/mac80211 functionality
-	* updated management frame protection to use IEEE Std 802.11w-2009
-	* fixed number of small WPS issues and added workarounds to
-	  interoperate with common deployed broken implementations
-	* added support for NFC out-of-band mechanism with WPS
-	* driver_ndis: fixed wired IEEE 802.1X authentication with PAE group
-	  address frames
-	* added preliminary support for IEEE 802.11r RIC processing
-	* added support for specifying subset of enabled frequencies to scan
-	  (scan_freq option in the network configuration block); this can speed
-	  up scanning process considerably if it is known that only a small
-	  subset of channels is actually used in the network (this is currently
-	  supported only with -Dnl80211)
-	* added a workaround for race condition between receiving the
-	  association event and the following EAPOL-Key
-	* added background scan and roaming infrastructure to allow
-	  network-specific optimizations to be used to improve roaming within
-	  an ESS (same SSID)
-	* added new DBus interface (fi.w1.wpa_supplicant1)
-
-2009-01-06 - v0.6.7
-	* added support for Wi-Fi Protected Setup (WPS)
-	  (wpa_supplicant can now be configured to act as a WPS Enrollee to
-	  enroll credentials for a network using PIN and PBC methods; in
-	  addition, wpa_supplicant can act as a wireless WPS Registrar to
-	  configure an AP); WPS support can be enabled by adding CONFIG_WPS=y
-	  into .config and setting the runtime configuration variables in
-	  wpa_supplicant.conf (see WPS section in the example configuration
-	  file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to
-	  manage WPS negotiation; see README-WPS for more details
-	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
-	* added support for using driver_test over UDP socket
-	* fixed PEAPv0 Cryptobinding interoperability issue with Windows Server
-	  2008 NPS; optional cryptobinding is now enabled (again) by default
-	* fixed PSK editing in wpa_gui
-	* changed EAP-GPSK to use the IANA assigned EAP method type 51
-	* added a Windows installer that includes WinPcap and all the needed
-	  DLLs; in addition, it set up the registry automatically so that user
-	  will only need start wpa_gui to get prompted to start the wpasvc
-	  servide and add a new interface if needed through wpa_gui dialog
-	* updated management frame protection to use IEEE 802.11w/D7.0
-
-2008-11-23 - v0.6.6
-	* added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA
-	  (can be used to simulate test SIM/USIM card with a known private key;
-	  enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config
-	  and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration)
-	* added a new network configuration option, wpa_ptk_rekey, that can be
-	  used to enforce frequent PTK rekeying, e.g., to mitigate some attacks
-	  against TKIP deficiencies
-	* added an optional mitigation mechanism for certain attacks against
-	  TKIP by delaying Michael MIC error reports by a random amount of time
-	  between 0 and 60 seconds; this can be enabled with a build option
-	  CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config
-	* fixed EAP-AKA to use RES Length field in AT_RES as length in bits,
-	  not bytes
-	* updated OpenSSL code for EAP-FAST to use an updated version of the
-	  session ticket overriding API that was included into the upstream
-	  OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
-	  needed with that version anymore)
-	* updated userspace MLME instructions to match with the current Linux
-	  mac80211 implementation; please also note that this can only be used
-	  with driver_nl80211.c (the old code from driver_wext.c was removed)
-	* added support (Linux only) for RoboSwitch chipsets (often found in
-	  consumer grade routers); driver interface 'roboswitch'
-	* fixed canceling of PMKSA caching when using drivers that generate
-	  RSN IE and refuse to drop PMKIDs that wpa_supplicant does not know
-	  about
-
-2008-11-01 - v0.6.5
-	* added support for SHA-256 as X.509 certificate digest when using the
-	  internal X.509/TLSv1 implementation
-	* updated management frame protection to use IEEE 802.11w/D6.0
-	* added support for using SHA256-based stronger key derivation for WPA2
-	  (IEEE 802.11w)
-	* fixed FT (IEEE 802.11r) authentication after a failed association to
-	  use correct FTIE
-	* added support for configuring Phase 2 (inner/tunneled) authentication
-	  method with wpa_gui-qt4
-
-2008-08-10 - v0.6.4
-	* added support for EAP Sequences in EAP-FAST Phase 2
-	* added support for using TNC with EAP-FAST
-	* added driver_ps3 for the PS3 Linux wireless driver
-	* added support for optional cryptobinding with PEAPv0
-	* fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
-	  allow fallback to full handshake if server rejects PAC-Opaque
-	* added fragmentation support for EAP-TNC
-	* added support for parsing PKCS #8 formatted private keys into the
-	  internal TLS implementation (both PKCS #1 RSA key and PKCS #8
-	  encapsulated RSA key can now be used)
-	* added option of using faster, but larger, routines in the internal
-	  LibTomMath (for internal TLS implementation) to speed up DH and RSA
-	  calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y)
-	* fixed race condition between disassociation event and group key
-	  handshake to avoid getting stuck in incorrect state [Bug 261]
-	* fixed opportunistic key caching (proactive_key_caching)
-
-2008-02-22 - v0.6.3
-	* removed 'nai' and 'eappsk' network configuration variables that were
-	  previously used for configuring user identity and key for EAP-PSK,
-	  EAP-PAX, EAP-SAKE, and EAP-GPSK. 'identity' field is now used as the
-	  replacement for 'nai' (if old configuration used a separate
-	  'identity' value, that would now be configured as
-	  'anonymous_identity'). 'password' field is now used as the
-	  replacement for 'eappsk' (it can also be set using hexstring to
-	  present random binary data)
-	* removed '-w' command line parameter (wait for interface to be added,
-	  if needed); cleaner way of handling this functionality is to use an
-	  external mechanism (e.g., hotplug scripts) that start wpa_supplicant
-	  when an interface is added
-	* updated FT support to use the latest draft, IEEE 802.11r/D9.0
-	* added ctrl_iface monitor event (CTRL-EVENT-SCAN-RESULTS) for
-	  indicating when new scan results become available
-	* added new ctrl_iface command, BSS, to allow scan results to be
-	  fetched without hitting the message size limits (this command
-	  can be used to iterate through the scan results one BSS at the time)
-	* fixed EAP-SIM not to include AT_NONCE_MT and AT_SELECTED_VERSION
-	  attributes in EAP-SIM Start/Response when using fast reauthentication
-	* fixed EAPOL not to end up in infinite loop when processing dynamic
-	  WEP keys with IEEE 802.1X
-	* fixed problems in getting NDIS events from WMI on Windows 2000
-
-2008-01-01 - v0.6.2
-	* added support for Makefile builds to include debug-log-to-a-file
-	  functionality (CONFIG_DEBUG_FILE=y and -f<path> on command line)
-	* fixed EAP-SIM and EAP-AKA message parser to validate attribute
-	  lengths properly to avoid potential crash caused by invalid messages
-	* added data structure for storing allocated buffers (struct wpabuf);
-	  this does not affect wpa_supplicant usage, but many of the APIs
-	  changed and various interfaces (e.g., EAP) is not compatible with old
-	  versions
-	* added support for protecting EAP-AKA/Identity messages with
-	  AT_CHECKCODE (optional feature in RFC 4187)
-	* added support for protected result indication with AT_RESULT_IND for
-	  EAP-SIM and EAP-AKA (phase1="result_ind=1")
-	* added driver_wext workaround for race condition between scanning and
-	  association with drivers that take very long time to scan all
-	  channels (e.g., madwifi with dual-band cards); wpa_supplicant is now
-	  using a longer hardcoded timeout for the scan if the driver supports
-	  notifications for scan completion (SIOCGIWSCAN event); this helps,
-	  e.g., in cases where wpa_supplicant and madwifi driver ended up in
-	  loop where the driver did not even try to associate
-	* stop EAPOL timer tick when no timers are in use in order to reduce
-	  power consumption (no need to wake up the process once per second)
-	  [Bug 237]
-	* added support for privilege separation (run only minimal part of
-	  wpa_supplicant functionality as root and rest as unprivileged,
-	  non-root process); see 'Privilege separation' in README for details;
-	  this is disabled by default and can be enabled with CONFIG_PRIVSEP=y
-	  in .config
-	* changed scan results data structure to include all information
-	  elements to make it easier to support new IEs; old get_scan_result()
-	  driver_ops is still supported for backwards compatibility (results
-	  are converted internally to the new format), but all drivers should
-	  start using the new get_scan_results2() to make them more likely to
-	  work with new features
-	* Qt4 version of wpa_gui (wpa_gui-qt4 subdirectory) is now native Qt4
-	  application, i.e., it does not require Qt3Support anymore; Windows
-	  binary of wpa_gui.exe is now from this directory and only requires
-	  QtCore4.dll and QtGui4.dll libraries
-	* updated Windows binary build to use Qt 4.3.3 and made Qt DLLs
-	  available as a separate package to make wpa_gui installation easier:
-	  http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
-	* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
-	  only shared key/password authentication is supported in this version
-
-2007-11-24 - v0.6.1
-	* added support for configuring password as NtPasswordHash
-	  (16-byte MD4 hash of password) in hash:<32 hex digits> format
-	* added support for fallback from abbreviated TLS handshake to
-	  full handshake when using EAP-FAST (e.g., due to an expired
-	  PAC-Opaque)
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-07.txt)
-	* added support for drivers that take care of RSN 4-way handshake
-	  internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and
-	  WPA_ALG_PMK in set_key)
-	* added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in
-	  .config); this version supports only ap_scan=2 mode and allow the
-	  driver to take care of the 4-way handshake
-	* fixed a buffer overflow in parsing TSF from scan results when using
-	  driver_wext.c with a driver that includes the TSF (e.g., iwl4965)
-	  [Bug 232]
-	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
-	* fixed an integer overflow issue in the ASN.1 parser used by the
-	  (experimental) internal TLS implementation to avoid a potential
-	  buffer read overflow
-	* fixed a race condition with -W option (wait for a control interface
-	  monitor before starting) that could have caused the first messages to
-	  be lost
-	* added support for processing TNCC-TNCS-Messages to report
-	  recommendation (allow/none/isolate) when using TNC [Bug 243]
-
-2007-05-28 - v0.6.0
-	* added network configuration parameter 'frequency' for setting
-	  initial channel for IBSS (adhoc) networks
-	* added experimental IEEE 802.11r/D6.0 support
-	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
-	* updated EAP-PSK to use the IANA-allocated EAP type 47
-	* fixed EAP-PAX key derivation
-	* fixed EAP-PSK bit ordering of the Flags field
-	* fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in
-	  tunnelled identity request (previously, the identifier from the outer
-	  method was used, not the tunnelled identifier which could be
-	  different)
-	* added support for fragmentation of outer TLS packets during Phase 2
-	  of EAP-PEAP/TTLS/FAST
-	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
-	* added support for EAP-FAST authentication with inner methods that
-	  generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported
-	  for PAC provisioning)
-	* added support for authenticated EAP-FAST provisioning
-	* added support for configuring maximum number of EAP-FAST PACs to
-	  store in a PAC list (fast_max_pac_list_len=<max> in phase1 string)
-	* added support for storing EAP-FAST PACs in binary format
-	  (fast_pac_format=binary in phase1 string)
-	* fixed dbus ctrl_iface to validate message interface before
-	  dispatching to avoid a possible segfault [Bug 190]
-	* fixed PeerKey key derivation to use the correct PRF label
-	* updated Windows binary build to link against OpenSSL 0.9.8d and
-	  added support for EAP-FAST
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-04.txt)
-	* fixed EAP-AKA Notification processing to allow Notification to be
-	  processed after AKA Challenge response has been sent
-	* updated to use IEEE 802.11w/D2.0 for management frame protection
-	  (still experimental)
-	* fixed EAP-TTLS implementation not to crash on use of freed memory
-	  if TLS library initialization fails
-	* added support for EAP-TNC (Trusted Network Connect)
-	  (this version implements the EAP-TNC method and EAP-TTLS changes
-	  needed to run two methods in sequence (IF-T) and the IF-IMC and
-	  IF-TNCCS interfaces from TNCC)
-
-2006-11-24 - v0.5.6
-	* added experimental, integrated TLSv1 client implementation with the
-	  needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
-	  setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
-	  .config); this can be useful, e.g., if the target system does not
-	  have a suitable TLS library and a minimal code size is required
-	  (total size of this internal TLS/crypto code is bit under 50 kB on
-	  x86 and the crypto code is shared by rest of the supplicant so some
-	  of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB)
-	* removed STAKey handshake since PeerKey handshake has replaced it in
-	  IEEE 802.11ma and there are no known deployments of STAKey
-	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
-	  draft (draft-ietf-emu-eap-gpsk-01.txt)
-	* added preliminary implementation of IEEE 802.11w/D1.0 (management
-	  frame protection)
-	  (Note: this requires driver support to work properly.)
-	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
-	* fixed Windows named pipes ctrl_iface to not stop listening for
-	  commands if client program opens a named pipe and closes it
-	  immediately without sending a command
-	* fixed USIM PIN status determination for the case that PIN is not
-	  needed (this allows EAP-AKA to be used with USIM cards that do not
-	  use PIN)
-	* added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to
-	  be used with cards that do not support file selection based on
-	  partial AID
-	* added support for matching the subjectAltName of the authentication
-	  server certificate against multiple name components (e.g.,
-	  altsubject_match="DNS:server.example.com;DNS:server2.example.com")
-	* fixed EAP-SIM/AKA key derivation for re-authentication case (only
-	  affects IEEE 802.1X with dynamic WEP keys)
-	* changed ctrl_iface network configuration 'get' operations to not
-	  return password/key material; if these fields are requested, "*"
-	  will be returned if the password/key is set, but the value of the
-	  parameter is not exposed
-
-2006-08-27 - v0.5.5
-	* added support for building Windows version with UNICODE defined
-	  (wide-char functions)
-	* driver_ndis: fixed static WEP configuration to avoid race condition
-	  issues with some NDIS drivers between association and setting WEP
-	  keys
-	* driver_ndis: added validation for IELength value in scan results to
-	  avoid crashes when using buggy NDIS drivers [Bug 165]
-	* fixed Release|Win32 target in the Visual Studio project files
-	  (previously, only Debug|Win32 target was set properly)
-	* changed control interface API call wpa_ctrl_pending() to allow it to
-	  return -1 on error (e.g., connection lost); control interface clients
-	  will need to make sure that they verify that the value is indeed >0
-	  when determining whether there are pending messages
-	* added an alternative control interface backend for Windows targets:
-	  Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default
-	  control interface mechanism for Windows builds (previously, UDP to
-	  localhost was used)
-	* changed ctrl_interface configuration for UNIX domain sockets:
-	  - deprecated ctrl_interface_group variable (it may be removed in
-	    future versions)
-	  - allow both directory and group be configured with ctrl_interface
-	    in following format: DIR=/var/run/wpa_supplicant GROUP=wheel
-	  - ctrl_interface=/var/run/wpa_supplicant is still supported for the
-	    case when group is not changed
-	* added support for controlling more than one interface per process in
-	  Windows version
-	* added a workaround for a case where the AP is using unknown address
-	  (e.g., MAC address of the wired interface) as the source address for
-	  EAPOL-Key frames; previously, that source address was used as the
-	  destination for EAPOL-Key frames and in key derivation; now, BSSID is
-	  used even if the source address does not match with it
-	  (this resolves an interoperability issue with Thomson SpeedTouch 580)
-	* added a workaround for UDP-based control interface (which was used in
-	  Windows builds before this release) to prevent packets with forged
-	  addresses from being accepted as local control requests
-	* removed ndis_events.cpp and possibility of using external
-	  ndis_events.exe; C version (ndis_events.c) is fully functional and
-	  there is no desire to maintain two separate versions of this
-	  implementation
-	* ndis_events: Changed NDIS event notification design to use WMI to
-	  learn the adapter description through Win32_PnPEntity class; this
-	  should fix some cases where the adapter name was not recognized
-	  correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500
-	  USB) [Bug 113]
-	* fixed selection of the first network in ap_scan=2 mode; previously,
-	  wpa_supplicant could get stuck in SCANNING state when only the first
-	  network for enabled (e.g., after 'wpa_cli select_network 0')
-	* winsvc: added support for configuring ctrl_interface parameters in
-	  registry (ctrl_interface string value in
-	  HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is
-	  required to enable control interface (previously, this was hardcoded
-	  to be enabled)
-	* allow wpa_gui subdirectory to be built with both Qt3 and Qt4
-	* converted wpa_gui-qt4 subdirectory to use Qt4 specific project format
-
-2006-06-20 - v0.5.4
-	* fixed build with CONFIG_STAKEY=y [Bug 143]
-	* added support for doing MLME (IEEE 802.11 management frame
-	  processing) in wpa_supplicant when using Devicescape IEEE 802.11
-	  stack (wireless-dev.git tree)
-	* added a new network block configuration option, fragment_size, to
-	  configure the maximum EAP fragment size
-	* driver_ndis: Disable WZC automatically for the selected interface to
-	  avoid conflicts with two programs trying to control the radio; WZC
-	  will be re-enabled (if it was enabled originally) when wpa_supplicant
-	  is terminated
-	* added an experimental TLSv1 client implementation
-	  (CONFIG_TLS=internal) that can be used instead of an external TLS
-	  library, e.g., to reduce total size requirement on systems that do
-	  not include any TLS library by default (this is not yet complete;
-	  basic functionality is there, but certificate validation is not yet
-	  included)
-	* added PeerKey handshake implementation for IEEE 802.11e
-	  direct link setup (DLS) to replace STAKey handshake
-	* fixed WPA PSK update through ctrl_iface for the case where the old
-	  PSK was derived from an ASCII passphrase and the new PSK is set as
-	  a raw PSK (hex string)
-	* added new configuration option for identifying which network block
-	  was used (id_str in wpa_supplicant.conf; included on
-	  WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental
-	  variable in wpa_cli action scripts; in addition WPA_ID variable is
-	  set to the current unique identifier that wpa_supplicant assigned
-	  automatically for the network and that can be used with
-	  GET_NETWORK/SET_NETWORK ctrl_iface commands)
-	* wpa_cli action script is now called only when the connect/disconnect
-	  status changes or when associating with a different network
-	* fixed configuration parser not to remove CCMP from group cipher list
-	  if WPA-None (adhoc) is used (pairwise=NONE in that case)
-	* fixed integrated NDIS events processing not to hang the process due
-	  to a missed change in eloop_win.c API in v0.5.3 [Bug 155]
-	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
-	  draft-clancy-emu-eap-shared-secret-00.txt)
-	* added Microsoft Visual Studio 2005 solution and project files for
-	  build wpa_supplicant for Windows (see vs2005 subdirectory)
-	* eloop_win: fixed unregistration of Windows events
-	* l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet
-	  at the end of RSN pre-authentication and added unregistration of
-	  a Windows event to avoid getting eloop_win stuck with an invalid
-	  handle
-	* driver_ndis: added support for selecting AP based on BSSID
-	* added new environmental variable for wpa_cli action scripts:
-	  WPA_CTRL_DIR is the current control interface directory
-	* driver_ndis: added support for using NDISUIO instead of WinPcap for
-	  OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new
-	  l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build
-	  wpa_supplicant without requiring WinPcap; note that using NDISUIO
-	  requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows
-	  only one application to open the device
-	* changed NDIS driver naming to only include device GUID, e.g.,
-	  {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap
-	  specific \Device\NPF_ prefix before the GUID; the prefix is still
-	  allowed for backwards compatibility, but it is not required anymore
-	  when specifying the interface
-	* driver_ndis: re-initialize driver interface is the adapter is removed
-	  and re-inserted [Bug 159]
-	* driver_madwifi: fixed TKIP and CCMP sequence number configuration on
-	  big endian hosts [Bug 146]
-
-2006-04-27 - v0.5.3
-	* fixed EAP-GTC response to include correct user identity when run as
-	  phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2)
-	* driver_ndis: Fixed encryption mode configuration for unencrypted
-	  networks (some NDIS drivers ignored this, but others, e.g., Broadcom,
-	  refused to associate with open networks) [Bug 106]
-	* driver_ndis: use BSSID OID polling to detect when IBSS network is
-	  formed even when ndis_events code is included since some NDIS drivers
-	  do not generate media connect events in IBSS mode
-	* config_winreg: allow global ctrl_interface parameter to be configured
-	  in Windows registry
-	* config_winreg: added support for saving configuration data into
-	  Windows registry
-	* added support for controlling network device operational state
-	  (dormant/up) for Linux 2.6.17 to improve DHCP processing (see
-	  http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client
-	  that can use this information)
-	* driver_wext: added support for WE-21 change to SSID configuration
-	* driver_wext: fixed privacy configuration for static WEP keys mode
-	  [Bug 140]
-	* added an optional driver_ops callback for MLME-SETPROTECTION.request
-	  primitive
-	* added support for EAP-SAKE (no EAP method number allocated yet, so
-	  this is using the same experimental type 255 as EAP-PSK)
-	* added support for dynamically loading EAP methods (.so files) instead
-	  of requiring them to be statically linked in; this is disabled by
-	  default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information
-	  on how to use this)
-
-2006-03-19 - v0.5.2
-	* do not try to use USIM APDUs when initializing PC/SC for SIM card
-	  access for a network that has not enabled EAP-AKA
-	* fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in
-	  v0.5.1 due to the new support for expanded EAP types)
-	* added support for generating EAP Expanded Nak
-	* try to fetch scan results once before requesting new scan when
-	  starting up in ap_scan=1 mode (this can speed up initial association
-	  a lot with, e.g., madwifi-ng driver)
-	* added support for receiving EAPOL frames from a Linux bridge
-	  interface (-bbr0 on command line)
-	* fixed EAPOL re-authentication for sessions that used PMKSA caching
-	* changed EAP method registration to use a dynamic list of methods
-	  instead of a static list generated at build time
-	* fixed PMKSA cache deinitialization not to use freed memory when
-	  removing PMKSA entries
-	* fixed a memory leak in EAP-TTLS re-authentication
-	* reject WPA/WPA2 message 3/4 if it does not include any valid
-	  WPA/RSN IE
-	* driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg
-	  if the driver does not support SIOCSIWAUTH
-
-2006-01-29 - v0.5.1
-	* driver_test: added better support for multiple APs and STAs by using
-	  a directory with sockets that include MAC address for each device in
-	  the name (driver_param=test_dir=/tmp/test)
-	* added support for EAP expanded type (vendor specific EAP methods)
-	* added AP_SCAN command into ctrl_iface so that ap_scan configuration
-	  option can be changed if needed
-	* wpa_cli/wpa_gui: skip non-socket files in control directory when
-	  using UNIX domain sockets; this avoids selecting an incorrect
-	  interface (e.g., a PID file could be in this directory, even though
-	  use of this directory for something else than socket files is not
-	  recommended)
-	* fixed TLS library deinitialization after RSN pre-authentication not
-	  to disable TLS library for normal authentication
-	* driver_wext: Remove null-termination from SSID length if the driver
-	  used it; some Linux drivers do this and they were causing problems in
-	  wpa_supplicant not finding matching configuration block. This change
-	  would break a case where the SSID actually ends in '\0', but that is
-	  not likely to happen in real use.
-	* fixed PMKSA cache processing not to trigger deauthentication if the
-	  current PMKSA cache entry is replaced with a valid new entry
-	* fixed PC/SC initialization for ap_scan != 1 modes (this fixes
-	  EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or
-	  ap_scan=2)
-
-2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
-	* added experimental STAKey handshake implementation for IEEE 802.11e
-	  direct link setup (DLS); note: this is disabled by default in both
-	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
-	  and stakey=1)
-	* fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to
-	  decrypt AT_ENCR_DATA attributes correctly
-	* fixed EAP-AKA to allow resynchronization within the same session
-	* made code closer to ANSI C89 standard to make it easier to port to
-	  other C libraries and compilers
-	* started moving operating system or C library specific functions into
-	  wrapper functions defined in os.h and implemented in os_*.c to make
-	  code more portable
-	* wpa_supplicant can now be built with Microsoft Visual C++
-	  (e.g., with the freely available Toolkit 2003 version or Visual
-	  C++ 2005 Express Edition and Platform SDK); see nmake.mak for an
-	  example makefile for nmake
-	* added support for using Windows registry for command line parameters
-	  (CONFIG_MAIN=main_winsvc) and configuration data
-	  (CONFIG_BACKEND=winreg); see win_example.reg for an example registry
-	  contents; this version can be run both as a Windows service and as a
-	  normal application; 'wpasvc.exe app' to start as applicant,
-	  'wpasvc.exe reg <full path to wpasvc.exe>' to register a service,
-	  'net start wpasvc' to start the service, 'wpasvc.exe unreg' to
-	  unregister a service
-	* made it possible to link ndis_events.exe functionality into
-	  wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED
-	* added better support for multiple control interface backends
-	  (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported
-	* fixed PC/SC code to use correct length for GSM AUTH command buffer
-	  and to not use pioRecvPci with SCardTransmit() calls; these were not
-	  causing visible problems with pcsc-lite, but Windows Winscard.dll
-	  refused the previously used parameters; this fixes EAP-SIM and
-	  EAP-AKA authentication using SIM/USIM card under Windows
-	* added new event loop implementation for Windows using
-	  WaitForMultipleObject() instead of select() in order to allow waiting
-	  for non-socket objects; this can be selected with
-	  CONFIG_ELOOP=eloop_win in .config
-	* added support for selecting l2_packet implementation in .config
-	  (CONFIG_L2_PACKET; following options are available now: linux, pcap,
-	  winpcap, freebsd, none)
-	* added new l2_packet implementation for WinPcap
-	  (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to
-	  reduce latency in EAPOL receive processing from about 100 ms to about
-	  3 ms
-	* added support for EAP-FAST key derivation using other ciphers than
-	  RC4-128-SHA for authentication and AES128-SHA for provisioning
-	* added support for configuring CA certificate as DER file and as a
-	  configuration blob
-	* fixed private key configuration as configuration blob and added
-	  support for using PKCS#12 as a blob
-	* tls_gnutls: added support for using PKCS#12 files; added support for
-	  session resumption
-	* added support for loading trusted CA certificates from Windows
-	  certificate store: ca_cert="cert_store://<name>", where <name> is
-	  likely CA (Intermediate CA certificates) or ROOT (root certificates)
-	* added C version of ndis_events.cpp and made it possible to build this
-	  with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more
-	  easily on cross-compilation builds
-	* added wpasvc.exe into Windows binary release; this is an alternative
-	  version of wpa_supplicant.exe with configuration backend using
-	  Windows registry and with the entry point designed to run as a
-	  Windows service
-	* integrated ndis_events.exe functionality into wpa_supplicant.exe and
-	  wpasvc.exe and removed this additional tool from the Windows binary
-	  release since it is not needed anymore
-	* load winscard.dll functions dynamically when building with MinGW
-	  since MinGW does not yet include winscard library
-
-2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
-	* l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap
-	  and WinPcap to receive frames sent to PAE group address
-	* disable EAP state machine when IEEE 802.1X authentication is not used
-	  in order to get rid of bogus "EAP failed" messages
-	* fixed OpenSSL error reporting to go through all pending errors to
-	  avoid confusing reports of old errors being reported at later point
-	  during handshake
-	* fixed configuration file updating to not write empty variables
-	  (e.g., proto or key_mgmt) that the file parser would not accept
-	* fixed ADD_NETWORK ctrl_iface command to use the same default values
-	  for variables as empty network definitions read from config file
-	  would get
-	* fixed EAP state machine to not discard EAP-Failure messages in many
-	  cases (e.g., during TLS handshake)
-	* fixed a infinite loop in private key reading if the configured file
-	  cannot be parsed successfully
-	* driver_madwifi: added support for madwifi-ng
-	* wpa_gui: do not display password/PSK field contents
-	* wpa_gui: added CA certificate configuration
-	* driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID
-	* driver_ndis: include Beacon IEs in AssocInfo in order to notice if
-	  the new AP is using different WPA/RSN IE
-	* use longer timeout for IEEE 802.11 association to avoid problems with
-	  drivers that may take more than five second to associate
-
-2005-10-27 - v0.4.6
-	* allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in
-	  RSN IE, but WPA IE would match with wpa_supplicant configuration
-	* added support for named configuration blobs in order to avoid having
-	  to use file system for external files (e.g., certificates);
-	  variables can be set to "blob://<blob name>" instead of file path to
-	  use a named blob; supported fields: pac_file, client_cert,
-	  private_key
-	* fixed RSN pre-authentication (it was broken in the clean up of WPA
-	  state machine interface in v0.4.5)
-	* driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make
-	  sure the driver configures broadcast decryption correctly
-	* added ca_path (and ca_path2) configuration variables that can be used
-	  to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the
-	  system-wide trusted CA list
-	* added support for starting wpa_supplicant without a configuration
-	  file (-C argument must be used to set ctrl_interface parameter for
-	  this case; in addition, -p argument can be used to provide
-	  driver_param; these new arguments can also be used with a
-	  configuration to override the values from the configuration)
-	* added global control interface that can be optionally used for adding
-	  and removing network interfaces dynamically (-g command line argument
-	  for both wpa_supplicant and wpa_cli) without having to restart
-	  wpa_supplicant process
-	* wpa_gui:
-	  - try to save configuration whenever something is modified
-	  - added WEP key configuration
-	  - added possibility to edit the current network configuration
-	* driver_ndis: fixed driver polling not to increase frequency on each
-	  received EAPOL frame due to incorrectly cancelled timeout
-	* added simple configuration file examples (in examples subdirectory)
-	* fixed driver_wext.c to filter wireless events based on ifindex to
-	  avoid interfaces receiving events from other interfaces
-	* delay sending initial EAPOL-Start couple of seconds to speed up
-	  authentication for the most common case of Authenticator starting
-	  EAP authentication immediately after association
-
-2005-09-25 - v0.4.5
-	* added a workaround for clearing keys with ndiswrapper to allow
-	  roaming from WPA enabled AP to plaintext one
-	* added docbook documentation (doc/docbook) that can be used to
-	  generate, e.g., man pages
-	* l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for
-	  PF_PACKET in order to prepare for network devices that do not use
-	  Ethernet headers (e.g., network stack with native IEEE 802.11 frames)
-	* use receipt of EAPOL-Key frame as a lower layer success indication
-	  for EAP state machine to allow recovery from dropped EAP-Success
-	  frame
-	* cleaned up internal EAPOL frame processing by not including link
-	  layer (Ethernet) header during WPA and EAPOL/EAP processing; this
-	  header is added only when transmitted the frame; this makes it easier
-	  to use wpa_supplicant on link layers that use different header than
-	  Ethernet
-	* updated EAP-PSK to use draft 9 by default since this can now be
-	  tested with hostapd; removed support for draft 3, including
-	  server_nai configuration option from network blocks
-	* driver_wired: add PAE address to the multicast address list in order
-	  to be able to receive EAPOL frames with drivers that do not include
-	  these multicast addresses by default
-	* driver_wext: add support for WE-19
-	* added support for multiple configuration backends (CONFIG_BACKEND
-	  option); currently, only 'file' is supported (i.e., the format used
-	  in wpa_supplicant.conf)
-	* added support for updating configuration ('wpa_cli save_config');
-	  this is disabled by default and can be enabled with global
-	  update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli
-	  and wpa_gui to store the configuration changes in a permanent store
-	* added GET_NETWORK ctrl_iface command
-	  (e.g., 'wpa_cli get_network 0 ssid')
-
-2005-08-21 - v0.4.4
-	* replaced OpenSSL patch for EAP-FAST support
-	  (openssl-tls-extensions.patch) with a more generic and correct
-	  patch (the new patch is not compatible with the previous one, so the
-	  OpenSSL library will need to be patched with the new patch in order
-	  to be able to build wpa_supplicant with EAP-FAST support)
-	* added support for using Windows certificate store (through CryptoAPI)
-	  for client certificate and private key operations (EAP-TLS)
-	  (see wpa_supplicant.conf for more information on how to configure
-	  this with private_key)
-	* ported wpa_gui to Windows
-	* added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be
-	  built with the open source version of the Qt4 for Windows
-	* allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used
-	  with drivers that do not support WPA
-	* ndis_events: fixed Windows 2000 support
-	* added support for enabling/disabling networks from the list of all
-	  configured networks ('wpa_cli enable_network <network id>' and
-	  'wpa_cli disable_network <network id>')
-	* added support for adding and removing network from the current
-	  configuration ('wpa_cli add_network' and 'wpa_cli remove_network
-	  <network id>'); added networks are disabled by default and they can
-	  be enabled with enable_network command once the configuration is done
-	  for the new network; note: configuration file is not yet updated, so
-	  these new networks are lost when wpa_supplicant is restarted
-	* added support for setting network configuration parameters through
-	  the control interface, for example:
-	  wpa_cli set_network 0 ssid "\"my network\""
-	* fixed parsing of strings that include both " and # within double
-	  quoted area (e.g., "start"#end")
-	* added EAP workaround for PEAP session resumption: allow outer,
-	  i.e., not tunneled, EAP-Success to terminate session since; this can
-	  be disabled with eap_workaround=0
-	  (this was allowed for PEAPv1 before, but now it is also allowed for
-	  PEAPv0 since at least one RADIUS authentication server seems to be
-	  doing this for PEAPv0, too)
-	* wpa_gui: added preliminary support for adding new networks to the
-	  wpa_supplicant configuration (double click on the scan results to
-	  open network configuration)
-
-2005-06-26 - v0.4.3
-	* removed interface for external EAPOL/EAP supplicant (e.g.,
-	  Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required
-	  anymore and is unlikely to be used by anyone
-	* driver_ndis: fixed WinPcap 3.0 support
-	* fixed build with CONFIG_DNET_PCAP=y on Linux
-	* l2_packet: moved different implementations into separate files
-	  (l2_packet_*.c)
-
-2005-06-12 - v0.4.2
-	* driver_ipw: updated driver structures to match with ipw2200-1.0.4
-	  (note: ipw2100-1.1.0 is likely to require an update to work with
-	  this)
-	* added support for using ap_scan=2 mode with multiple network blocks;
-	  wpa_supplicant will go through the networks one by one until the
-	  driver reports a successful association; this uses the same order for
-	  networks as scan_ssid=1 scans, i.e., the priority field is ignored
-	  and the network block order in the file is used instead
-	* fixed a potential issue in RSN pre-authentication ending up using
-	  freed memory if pre-authentication times out
-	* added support for matching alternative subject name extensions of the
-	  authentication server certificate; new configuration variables
-	  altsubject_match and altsubject_match2
-	* driver_ndis: added support for IEEE 802.1X authentication with wired
-	  NDIS drivers
-	* added support for querying private key password (EAP-TLS) through the
-	  control interface (wpa_cli/wpa_gui) if one is not included in the
-	  configuration file
-	* driver_broadcom: fixed couple of memory leaks in scan result
-	  processing
-	* EAP-PAX is now registered as EAP type 46
-	* fixed EAP-PAX MAC calculation
-	* fixed EAP-PAX CK and ICK key derivation
-	* added support for using password with EAP-PAX (as an alternative to
-	  entering key with eappsk); SHA-1 hash of the password will be used as
-	  the key in this case
-	* added support for arbitrary driver interface parameters through the
-	  configuration file with a new driver_param field; this adds a new
-	  driver_ops function set_param()
-	* added possibility to override l2_packet module with driver interface
-	  API (new send_eapol handler); this can be used to implement driver
-	  specific TX/RX functions for EAPOL frames
-	* fixed ctrl_interface_group processing for the case where gid is
-	  entered as a number, not group name
-	* driver_test: added support for testing hostapd with wpa_supplicant
-	  by using test driver interface without any kernel drivers or network
-	  cards
-
-2005-05-22 - v0.4.1
-	* driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL
-	  packets to be encrypted; this was apparently broken by the changed
-	  ioctl order in v0.4.0
-	* driver_madwifi: added preliminary support for compiling against 'BSD'
-	  branch of madwifi CVS tree
-	* added support for EAP-MSCHAPv2 password retries within the same EAP
-	  authentication session
-	* added support for password changes with EAP-MSCHAPv2 (used when the
-	  password has expired)
-	* added support for reading additional certificates from PKCS#12 files
-	  and adding them to the certificate chain
-	* fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys
-	  were used
-	* fixed a possible double free in EAP-TTLS fast-reauthentication when
-	  identity or password is entered through control interface
-	* display EAP Notification messages to user through control interface
-	  with "CTRL-EVENT-EAP-NOTIFICATION" prefix
-	* added GUI version of wpa_cli, wpa_gui; this is not build
-	  automatically with 'make'; use 'make wpa_gui' to build (this requires
-	  Qt development tools)
-	* added 'disconnect' command to control interface for setting
-	  wpa_supplicant in state where it will not associate before
-	  'reassociate' command has been used
-	* added support for selecting a network from the list of all configured
-	  networks ('wpa_cli select_network <network id>'; this disabled all
-	  other networks; to re-enable, 'wpa_cli select_network any')
-	* added support for getting scan results through control interface
-	* added EAP workaround for PEAPv1 session resumption: allow outer,
-	  i.e., not tunneled, EAP-Success to terminate session since; this can
-	  be disabled with eap_workaround=0
-
-2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
-	* added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be
-	  used to reduce the size of the wpa_supplicant considerably if
-	  debugging code is not needed
-	* fixed EAPOL-Key validation to drop packets with invalid Key Data
-	  Length; such frames could have crashed wpa_supplicant due to buffer
-	  overflow
-	* added support for wired authentication (IEEE 802.1X on wired
-	  Ethernet); driver interface 'wired'
-	* obsoleted set_wpa() handler in the driver interface API (it can be
-	  replaced by moving enable/disable functionality into init()/deinit())
-	  (calls to set_wpa() are still present for backwards compatibility,
-	  but they may be removed in the future)
-	* driver_madwifi: fixed association in plaintext mode
-	* modified the EAP workaround that accepts EAP-Success with incorrect
-	  Identifier to be even less strict about verification in order to
-	  interoperate with some authentication servers
-	* added support for sending TLS alerts
-	* added support for 'any' SSID wildcard; if ssid is not configured or
-	  is set to an empty string, any SSID will be accepted for non-WPA AP
-	* added support for asking PIN (for SIM) from frontends (e.g.,
-	  wpa_cli); if a PIN is needed, but not included in the configuration
-	  file, a control interface request is sent and EAP processing is
-	  delayed until the PIN is available
-	* added support for using external devices (e.g., a smartcard) for
-	  private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config);
-	  new wpa_supplicant.conf variables:
-	  - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path
-	  - network: engine, engine_id, key_id
-	* added experimental support for EAP-PAX
-	* added monitor mode for wpa_cli (-a<path to a program to run>) that
-	  allows external commands (e.g., shell scripts) to be run based on
-	  wpa_supplicant events, e.g., when authentication has been completed
-	  and data connection is ready; other related wpa_cli arguments:
-	  -B (run in background), -P (write PID file); wpa_supplicant has a new
-	  command line argument (-W) that can be used to make it wait until a
-	  control interface command is received in order to avoid missing
-	  events
-	* added support for opportunistic WPA2 PMKSA key caching (disabled by
-	  default, can be enabled with proactive_key_caching=1)
-	* fixed RSN IE in 4-Way Handshake message 2/4 for the case where
-	  Authenticator rejects PMKSA caching attempt and the driver is not
-	  using assoc_info events
-	* added -P<pid file> argument for wpa_supplicant to write the current
-	  process id into a file
-
-2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
-	* added new phase1 option parameter, include_tls_length=1, to force
-	  wpa_supplicant to add TLS Message Length field to all TLS messages
-	  even if the packet is not fragmented; this may be needed with some
-	  authentication servers
-	* fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when
-	  using drivers that take care of AP selection (e.g., when using
-	  ap_scan=2)
-	* fixed reprocessing of pending request after ctrl_iface requests for
-	  identity/password/otp
-	* fixed ctrl_iface requests for identity/password/otp in Phase 2 of
-	  EAP-PEAP and EAP-TTLS
-	* all drivers using driver_wext: set interface up and select Managed
-	  mode when starting wpa_supplicant; set interface down when exiting
-	* renamed driver_ipw2100.c to driver_ipw.c since it now supports both
-	  ipw2100 and ipw2200; please note that this also changed the
-	  configuration variable in .config to CONFIG_DRIVER_IPW
-
-2005-01-24 - v0.3.6
-	* fixed a busy loop introduced in v0.3.5 for scan result processing
-	  when no matching AP is found
-
-2005-01-23 - v0.3.5
-	* added a workaround for an interoperability issue with a Cisco AP
-	  when using WPA2-PSK
-	* fixed non-WPA IEEE 802.1X to use the same authentication timeout as
-	  WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow
-	  retransmission of dropped frames)
-	* fixed issues with 64-bit CPUs and SHA1 cleanup in previous version
-	  (e.g., segfault when processing EAPOL-Key frames)
-	* fixed EAP workaround and fast reauthentication configuration for
-	  RSN pre-authentication; previously these were disabled and
-	  pre-authentication would fail if the used authentication server
-	  requires EAP workarounds
-	* added support for blacklisting APs that fail or timeout
-	  authentication in ap_scan=1 mode so that all APs are tried in cases
-	  where the ones with strongest signal level are failing authentication
-	* fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS
-	  authentication attempt
-	* allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded
-	  in the previous authentication (previously, only Phase 1 success was
-	  verified)
-
-2005-01-09 - v0.3.4
-	* added preliminary support for IBSS (ad-hoc) mode configuration
-	  (mode=1 in network block); this included a new key_mgmt mode
-	  WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no
-	  key management; see wpa_supplicant.conf for more details and an
-	  example on how to configure this (note: this is currently implemented
-	  only for driver_hostapd.c, but the changes should be trivial to add
-	  in associate() handler for other drivers, too (assuming the driver
-	  supports WPA-None)
-	* added preliminary port for native Windows (i.e., no cygwin) using
-	  mingw
-
-2005-01-02 - v0.3.3
-	* added optional support for GNU Readline and History Libraries for
-	  wpa_cli (CONFIG_READLINE)
-	* cleaned up EAP state machine <-> method interface and number of
-	  small problems with error case processing not terminating on
-	  EAP-Failure but waiting for timeout
-	* added couple of workarounds for interoperability issues with a
-	  Cisco AP when using WPA2
-	* added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt);
-	  Note: This requires a patch for openssl to add support for TLS
-	  extensions and number of workarounds for operations without
-	  certificates. Proof of concept type of experimental patch is
-	  included in openssl-tls-extensions.patch.
-
-2004-12-19 - v0.3.2
-	* fixed private key loading for cases where passphrase is not set
-	* fixed Windows/cygwin L2 packet handler freeing; previous version
-	  could cause a segfault when RSN pre-authentication was completed
-	* added support for PMKSA caching with drivers that generate RSN IEs
-	  (e.g., NDIS); currently, this is only implemented in driver_ndis.c,
-	  but similar code can be easily added to driver_ndiswrapper.c once
-	  ndiswrapper gets full support for RSN PMKSA caching
-	* improved recovery from PMKID mismatches by requesting full EAP
-	  authentication in case of failed PMKSA caching attempt
-	* driver_ndis: added support for NDIS NdisMIncidateStatus() events
-	  (this requires that ndis_events is ran while wpa_supplicant is
-	  running)
-	* driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys
-	* added support for driver interfaces to replace the interface name
-	  based on driver/OS specific mapping, e.g., in case of driver_ndis,
-	  this allows the beginning of the adapter description to be used as
-	  the interface name
-	* added support for CR+LF (Windows-style) line ends in configuration
-	  file
-	* driver_ndis: enable radio before starting scanning, disable radio
-	  when exiting
-	* modified association event handler to set portEnabled = FALSE before
-	  clearing port Valid in order to reset EAP state machine and avoid
-	  problems with new authentication getting ignored because of state
-	  machines ending up in AUTHENTICATED/SUCCESS state based on old
-	  information
-	* added support for driver events to add PMKID candidates in order to
-	  allow drivers to give priority to most likely roaming candidates
-	* driver_hostap: moved PrivacyInvoked configuration to associate()
-	  function so that this will not be set for plaintext connections
-	* added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver
-	  interface can distinguish plaintext and IEEE 802.1X (no WPA)
-	  authentication
-	* fixed static WEP key configuration to use broadcast/default type for
-	  all keys (previously, the default TX key was configured as pairwise/
-	  unicast key)
-	* driver_ndis: added legacy WPA capability detection for non-WPA2
-	  drivers
-	* added support for setting static WEP keys for IEEE 802.1X without
-	  dynamic WEP keying (eapol_flags=0)
-
-2004-12-12 - v0.3.1
-	* added support for reading PKCS#12 (PFX) files (as a replacement for
-	  PEM/DER) to get certificate and private key (CONFIG_PKCS12)
-	* fixed compilation with CONFIG_PCSC=y
-	* added new ap_scan mode, ap_scan=2, for drivers that take care of
-	  association, but need to be configured with security policy and SSID,
-	  e.g., ndiswrapper and NDIS driver; this mode should allow such
-	  drivers to work with hidden SSIDs and optimized roaming; when
-	  ap_scan=2 is used, only the first network block in the configuration
-	  file is used and this configuration should have explicit security
-	  policy (i.e., only one option in the lists) for key_mgmt, pairwise,
-	  group, proto variables
-	* added experimental port of wpa_supplicant for Windows
-	  - driver_ndis.c driver interface (NDIS OIDs)
-	  - currently, this requires cygwin and WinPcap
-	  - small utility, win_if_list, can be used to get interface name
-	* control interface can now be removed at build time; add
-	  CONFIG_CTRL_IFACE=y to .config to maintain old functionality
-	* optional Xsupplicant interface can now be removed at build time;
-	  (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back)
-	* added auth_alg to driver interface associate() parameters to make it
-	  easier for drivers to configure authentication algorithm as part of
-	  the association
-
-2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
-	* driver_broadcom: added new driver interface for Broadcom wl.o driver
-	  (a generic driver for Broadcom IEEE 802.11a/g cards)
-	* wpa_cli: fixed parsing of -p <path> command line argument
-	* PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS
-	  ACK, not tunneled EAP-Success (of which only the first byte was
-	  actually send due to a bug in previous code); this seems to
-	  interoperate with most RADIUS servers that implements PEAPv1
-	* PEAPv1: added support for terminating PEAP authentication on tunneled
-	  EAP-Success message; this can be configured by adding
-	  peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf
-	  (some RADIUS servers require this whereas others require a tunneled
-	  reply
-	* PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to
-	  the old label for key derivation; previously, the default was 1,
-	  but it looks like most existing PEAPv1 implementations use the old
-	  label which is thus more suitable default option
-	* added support for EAP-PSK (draft-bersani-eap-psk-03.txt)
-	* fixed parsing of wep_tx_keyidx
-	* added support for configuring list of allowed Phase 2 EAP types
-	  (for both EAP-PEAP and EAP-TTLS) instead of only one type
-	* added support for configuring IEEE 802.11 authentication algorithm
-	  (auth_alg; mainly for using Shared Key authentication with static
-	  WEP keys)
-	* added support for EAP-AKA (with UMTS SIM)
-	* fixed couple of errors in PCSC handling that could have caused
-	  random-looking errors for EAP-SIM
-	* added support for EAP-SIM pseudonyms and fast re-authentication
-	* added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS
-	  session resumption)
-	* added support for EAP-SIM with two challanges
-	  (phase1="sim_min_num_chal=3" can be used to require three challenges)
-	* added support for configuring DH/DSA parameters for an ephemeral DH
-	  key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters
-	  dh_file and dh_file2 (phase 2); this adds support for using DSA keys
-	  and optional DH key exchange to achieve forward secracy with RSA keys
-	* added support for matching subject of the authentication server
-	  certificate with a substring when using EAP-TLS/PEAP/TTLS; new
-	  configuration variables subject_match and subject_match2
-	* changed SSID configuration in driver_wext.c (used by many driver
-	  interfaces) to use ssid_len+1 as the length for SSID since some Linux
-	  drivers expect this
-	* fixed couple of unaligned reads in scan result parsing to fix WPA
-	  connection on some platforms (e.g., ARM)
-	* added driver interface for Intel ipw2100 driver
-	* added support for LEAP with WPA
-	* added support for larger scan results report (old limit was 4 kB of
-	  data, i.e., about 35 or so APs) when using Linux wireless extensions
-	  v17 or newer
-	* fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start
-	  only if there is a PMKSA cache entry for the current AP
-	* fixed error handling for case where reading of scan results fails:
-	  must schedule a new scan or wpa_supplicant will remain waiting
-	  forever
-	* changed debug output to remove shared password/key material by
-	  default; all key information can be included with -K command line
-	  argument to match the previous behavior
-	* added support for timestamping debug log messages (disabled by
-	  default, can be enabled with -t command line argument)
-	* set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104
-	  if keys are not configured to be used; this fixes IEEE 802.1X mode
-	  with drivers that use this information to configure whether Privacy
-	  bit can be in Beacon frames (e.g., ndiswrapper)
-	* avoid clearing driver keys if no keys have been configured since last
-	  key clear request; this seems to improve reliability of group key
-	  handshake for ndiswrapper & NDIS driver which seems to be suffering
-	  of some kind of timing issue when the keys are cleared again after
-	  association
-	* changed driver interface API:
-	  - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which
-	    version is being used (now, this is set to 2; previously, it was
-	    not defined)
-	  - pass pointer to private data structure to all calls
-	  - the new API is not backwards compatible; all in-tree driver
-	    interfaces has been converted to the new API
-	* added support for controlling multiple interfaces (radios) per
-	  wpa_supplicant process; each interface needs to be listed on the
-	  command line (-c, -i, -D arguments) with -N as a separator
-	  (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi)
-	* added a workaround for EAP servers that incorrectly use same Id for
-	  sequential EAP packets
-	* changed libpcap/libdnet configuration to use .config variable,
-	  CONFIG_DNET_PCAP, instead of requiring Makefile modification
-	* improved downgrade attack detection in IE verification of msg 3/4:
-	  verify both WPA and RSN IEs, if present, not only the selected one;
-	  reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or
-	  Probe Response frame, and RSN is enabled in wpa_supplicant
-	  configuration
-	* fixed WPA msg 3/4 processing to allow Key Data field contain other
-	  IEs than just one WPA IE
-	* added support for FreeBSD and driver interface for the BSD net80211
-	  layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the
-	  required kernel mods have not yet been committed
-	* made EAP workarounds configurable; enabled by default, can be
-	  disabled with network block option eap_workaround=0
-
-2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
-	* resolved couple of interoperability issues with EAP-PEAPv1 and
-	  Phase 2 (inner EAP) fragment reassembly
-	* driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the
-	  AP is using non-zero key index for the unicast key and key index zero
-	  for the broadcast key
-	* driver_hostap: fixed IEEE 802.1X WEP key updates and
-	  re-authentication by allowing unencrypted EAPOL frames when not using
-	  WPA
-	* added a new driver interface, 'wext', which uses only standard,
-	  driver independent functionality in Linux wireless extensions;
-	  currently, this can be used only for non-WPA IEEE 802.1X mode, but
-	  eventually, this is to be extended to support full WPA/WPA2 once
-	  Linux wireless extensions get support for this
-	* added support for mode in which the driver is responsible for AP
-	  scanning and selection; this is disabled by default and can be
-	  enabled with global ap_scan=0 variable in wpa_supplicant.conf;
-	  this mode can be used, e.g., with generic 'wext' driver interface to
-	  use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver
-	  supporting wireless extensions.
-	* driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g.,
-	  operation with an AP that does not include SSID in the Beacon frames)
-	* added support for new EAP authentication methods:
-	  EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP
-	* added support for asking one-time-passwords from frontends (e.g.,
-	  wpa_cli); this 'otp' command works otherwise like 'password' command,
-	  but the password is used only once and the frontend will be asked for
-	  a new password whenever a request from authenticator requires a
-	  password; this can be used with both EAP-OTP and EAP-GTC
-	* changed wpa_cli to automatically re-establish connection so that it
-	  does not need to be re-started when wpa_supplicant is terminated and
-	  started again
-	* improved user data (identity/password/otp) requests through
-	  frontends: process pending EAPOL packets after getting new
-	  information so that full authentication does not need to be
-	  restarted; in addition, send pending requests again whenever a new
-	  frontend is attached
-	* changed control frontends to use a new directory for socket files to
-	  make it easier for wpa_cli to automatically select between interfaces
-	  and to provide access control for the control interface;
-	  wpa_supplicant.conf: ctrl_interface is now a path
-	  (/var/run/wpa_supplicant is the recommended path) and
-	  ctrl_interface_group can be used to select which group gets access to
-	  the control interface;
-	  wpa_cli: by default, try to connect to the first interface available
-	  in /var/run/wpa_supplicant; this path can be overriden with -p option
-	  and an interface can be selected with -i option (i.e., in most common
-	  cases, wpa_cli does not need to get any arguments)
-	* added support for LEAP
-	* added driver interface for Linux ndiswrapper
-	* added priority option for network blocks in the configuration file;
-	  this allows networks to be grouped based on priority (the scan
-	  results are searched for matches with network blocks in this order)
-
-2004-06-20 - v0.2.3
-	* sort scan results to improve AP selection
-	* fixed control interface socket removal for some error cases
-	* improved scan requesting and authentication timeout
-	* small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and
-	  TLS processing
-	* PEAP version can now be forced with phase1="peapver=<ver>"
-	  (mostly for testing; by default, the highest version supported by
-	  both the Supplicant and Authentication Server is selected
-	  automatically)
-	* added support for madwifi driver (Atheros ar521x)
-	* added a workaround for cases where AP sets Install Tx/Rx bit for
-	  WPA Group Key messages when pairwise keys are used (without this,
-	  the Group Key would be used for Tx and the AP would drop frames
-	  from the station)
-	* added GSM SIM/USIM interface for GSM authentication algorithm for
-	  EAP-SIM; this requires pcsc-lite
-	* added support for ATMEL AT76C5XXx driver
-	* fixed IEEE 802.1X WEP key derivation in the case where Authenticator
-	  does not include key data in the EAPOL-Key frame (i.e., part of
-	  EAP keying material is used as data encryption key)
-	* added support for using plaintext and static WEP networks
-	  (key_mgmt=NONE)
-
-2004-05-31 - v0.2.2
-	* added support for new EAP authentication methods:
-	  EAP-TTLS/EAP-MD5-Challenge
-	  EAP-TTLS/EAP-GTC
-	  EAP-TTLS/EAP-MSCHAPv2
-	  EAP-TTLS/EAP-TLS
-	  EAP-TTLS/MSCHAPv2
-	  EAP-TTLS/MSCHAP
-	  EAP-TTLS/PAP
-	  EAP-TTLS/CHAP
-	  EAP-PEAP/TLS
-	  EAP-PEAP/GTC
-	  EAP-PEAP/MD5-Challenge
-	  EAP-GTC
-	  EAP-SIM (not yet complete; needs GSM/SIM authentication interface)
-	* added support for anonymous identity (to be used when identity is
-	  sent in plaintext; real identity will be used within TLS protected
-	  tunnel (e.g., with EAP-TTLS)
-	* added event messages from wpa_supplicant to frontends, e.g., wpa_cli
-	* added support for requesting identity and password information using
-	  control interface; in other words, the password for EAP-PEAP or
-	  EAP-TTLS does not need to be included in the configuration file since
-	  a frontand (e.g., wpa_cli) can ask it from the user
-	* improved RSN pre-authentication to use a candidate list and process
-	  all candidates from each scan; not only one per scan
-	* fixed RSN IE and WPA IE capabilities field parsing
-	* ignore Tx bit in GTK IE when Pairwise keys are used
-	* avoid making new scan requests during IEEE 802.1X negotiation
-	* use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant
-	  with TLS support (this replaces the included implementation with
-	  library code to save about 8 kB since the library code is needed
-	  anyway for TLS)
-	* fixed WPA-PSK only mode when compiled without IEEE 802.1X support
-	  (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config)
-
-2004-05-06 - v0.2.1
-	* added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1)
-	  Supplicant
-	  - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1]
-	  - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf]
-	  - EAP-MD5 (cannot be used with WPA-RADIUS)
-	    [draft-ietf-eap-rfc2284bis-09.txt]
-	  - EAP-TLS [RFC 2716]
-	  - EAP-MSCHAPv2 (currently used only with EAP-PEAP)
-	  - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt]
-	    [draft-kamath-pppext-eap-mschapv2-00.txt]
-	    (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by
-	    default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey)
-	  - new configuration file options: eap, identity, password, ca_cert,
-	    client_cert, privatekey, private_key_passwd
-	  - Xsupplicant is not required anymore, but it can be used by
-	    disabling the internal IEEE 802.1X Supplicant with -e command line
-	    option
-	  - this code is not included in the default build; Makefile need to
-	    be edited for this (uncomment lines for selected functionality)
-	  - EAP-TLS and EAP-PEAP require openssl libraries
-	* use module prefix in debug messages (WPA, EAP, EAP-TLS, ..)
-	* added support for non-WPA IEEE 802.1X mode with dynamic WEP keys
-	  (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X
-	   EAPOL-Key frames instead of WPA key handshakes)
-	* added support for IEEE 802.11i/RSN (WPA2)
-	  - improved PTK Key Handshake
-	  - PMKSA caching, pre-authentication
-	* fixed wpa_supplicant to ignore possible extra data after WPA
-	  EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using
-	  TPTK' error from message 3 of 4-Way Handshake in case the AP
-	  includes extra data after the EAPOL-Key)
-	* added interface for external programs (frontends) to control
-	  wpa_supplicant
-	  - CLI example (wpa_cli) with interactive mode and command line
-	    mode
-	  - replaced SIGUSR1 status/statistics with the new control interface
-	* made some feature compile time configurable
-	  - .config file for make
-	  - driver interfaces (hostap, hermes, ..)
-	  - EAPOL/EAP functions
-
-2004-02-15 - v0.2.0
-	* Initial version of wpa_supplicant

Copied: vendor/wpa/2.0/wpa_supplicant/ChangeLog (from rev 9639, vendor/wpa/dist/wpa_supplicant/ChangeLog)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ChangeLog	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ChangeLog	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1699 @@
+ChangeLog for wpa_supplicant
+
+2013-01-12 - v2.0
+	* removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+	* removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+	  hostap, madwifi (hostap and madwifi remain available for hostapd;
+	  their wpa_supplicant functionality is obsoleted by wext)
+	* improved debug logging (human readable event names, interface name
+	  included in more entries)
+	* changed AP mode behavior to enable WPS only for open and
+	  WPA/WPA2-Personal configuration
+	* improved P2P concurrency operations
+	  - better coordination of concurrent scan and P2P search operations
+	  - avoid concurrent remain-on-channel operation requests by canceling
+	    previous operations prior to starting a new one
+	  - reject operations that would require multi-channel concurrency if
+	    the driver does not support it
+	  - add parameter to select whether STA or P2P connection is preferred
+	    if the driver cannot support both at the same time
+	  - allow driver to indicate channel changes
+	  - added optional delay=<search delay in milliseconds> parameter for
+	    p2p_find to avoid taking all radio resources
+	  - use 500 ms p2p_find search delay by default during concurrent
+	    operations
+	  - allow all channels in GO Negotiation if the driver supports
+	    multi-channel concurrency
+	* added number of small changes to make it easier for static analyzers
+	  to understand the implementation
+	* fixed number of small bugs (see git logs for more details)
+	* nl80211: number of updates to use new cfg80211/nl80211 functionality
+	  - replace monitor interface with nl80211 commands for AP mode
+	  - additional information for driver-based AP SME
+	  - STA entry authorization in RSN IBSS
+	* EAP-pwd:
+	  - fixed KDF for group 21 and zero-padding
+	  - added support for fragmentation
+	  - increased maximum number of hunting-and-pecking iterations
+	* avoid excessive Probe Response retries for broadcast Probe Request
+	  frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+	* added "GET country" ctrl_iface command
+	* do not save an invalid network block in wpa_supplicant.conf to avoid
+	  problems reading the file on next start
+	* send STA connected/disconnected ctrl_iface events to both the P2P
+	  group and parent interfaces
+	* added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+	* added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+	  network offload with sched_scan driver command
+	* merged in number of changes from Android repository for P2P, nl80211,
+	  and build parameters
+	* changed P2P GO mode configuration to use driver capabilities to
+	  automatically enable HT operations when supported
+	* added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+	  for WPS use cases in AP mode
+	* EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+	  behavior
+	* improved reassociation behavior in cases where association is rejected
+	  or when an AP disconnects us to handle common load balancing
+	  mechanisms
+	  - try to avoid extra scans when the needed information is available
+	* added optional "join" argument for p2p_prov_disc ctrl_iface command
+	* added group ifname to P2P-PROV-DISC-* events
+	* added P2P Device Address to AP-STA-DISCONNECTED event and use
+	  p2p_dev_addr parameter name with AP-STA-CONNECTED
+	* added workarounds for WPS PBC overlap detection for some P2P use cases
+	  where deployed stations work incorrectly
+	* optimize WPS connection speed by disconnecting prior to WPS scan and
+	  by using single channel scans when AP channel is known
+	* PCSC and SIM/USIM improvements:
+	  - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+	    issues with some USIM cards
+	  - try to read MNC length from SIM/USIM
+	  - build realm according to 3GPP TS 23.003 with identity from the SIM
+	  - allow T1 protocol to be enabled
+	* added more WPS and P2P information available through D-Bus
+	* improve P2P negotiation robustness
+	  - extra waits to get ACK frames through
+	  - longer timeouts for cases where deployed devices have been
+	    identified have issues meeting the specification requirements
+	  - more retries for some P2P frames
+	  - handle race conditions in GO Negotiation start by both devices
+	  - ignore unexpected GO Negotiation Response frame
+	* added support for libnl 3.2 and newer
+	* added P2P persistent group info to P2P_PEER data
+	* maintain a list of P2P Clients for persistent group on GO
+	* AP: increased initial group key handshake retransmit timeout to 500 ms
+	* added optional dev_id parameter for p2p_find
+	* added P2P-FIND-STOPPED ctrl_iface event
+	* fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+	  and driver-based BSS selection
+	* do not expire P2P peer entries while connected with the peer in a
+	  group
+	* fixed WSC element inclusion in cases where P2P is disabled
+	* AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+	* EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+	* EAP-SIM/AKA: append realm to pseudonym identity
+	* EAP-SIM/AKA: store pseudonym identity in network configuration to
+	  allow it to persist over multiple EAP sessions and wpa_supplicant
+	  restarts
+	* EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+	  breaks interoperability with older versions
+	* added support for WFA Hotspot 2.0
+	  - GAS/ANQP to fetch network information
+	  - credential configuration and automatic network selections based on
+	    credential match with ANQP information
+	* limited PMKSA cache entries to be used only with the network context
+	  that was used to create them
+	* improved PMKSA cache expiration to avoid unnecessary disconnections
+	* adjusted bgscan_simple fast-scan backoff to avoid too frequent
+	  background scans
+	* removed ctrl_iface event on P2P PD Response in join-group case
+	* added option to fetch BSS table entry based on P2P Device Address
+	  ("BSS p2p_dev_addr=<P2P Device Address>")
+	* added BSS entry age to ctrl_iface BSS command output
+	* added optional MASK=0xH option for ctrl_iface BSS command to select
+	  which fields are included in the response
+	* added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+	  fetch information about several BSSes in one call
+	* simplified licensing terms by selecting the BSD license as the only
+	  alternative
+	* added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+	  disable channels from P2P use
+	* added p2p_pref_chan configuration parameter to allow preferred P2P
+	  channels to be specified
+	* added support for advertising immediate availability of a WPS
+	  credential for P2P use cases
+	* optimized scan operations for P2P use cases (use single channel scan
+	  for a specific SSID when possible)
+	* EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+	* SME: do not use reassociation after explicit disconnection request
+	  (local or a notification from an AP)
+	* added support for sending debug info to Linux tracing (-T on command
+	  line)
+	* added support for using Deauthentication reason code 3 as an
+	  indication of P2P group termination
+	* added wps_vendor_ext_m1 configuration parameter to allow vendor
+	  specific attributes to be added to WPS M1
+	* started using separate TLS library context for tunneled TLS
+	  (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+	  certificate configuration between Phase 1 and Phase 2
+	* added optional "auto" parameter for p2p_connect to request automatic
+	  GO Negotiation vs. join-a-group selection
+	* added disabled_scan_offload parameter to disable automatic scan
+	  offloading (sched_scan)
+	* added optional persistent=<network id> parameter for p2p_connect to
+	  allow forcing of a specific SSID/passphrase for GO Negotiation
+	* added support for OBSS scan requests and 20/40 BSS coexistence reports
+	* reject PD Request for unknown group
+	* removed scripts and notes related to Windows binary releases (which
+	  have not been used starting from 1.x)
+	* added initial support for WNM operations
+	  - Keep-alive based on BSS max idle period
+	  - WNM-Sleep Mode
+	  - minimal BSS Transition Management processing
+	* added autoscan module to control scanning behavior while not connected
+	  - autoscan_periodic and autoscan_exponential modules
+	* added new WPS NFC ctrl_iface mechanism
+	  - added initial support NFC connection handover
+	  - removed obsoleted WPS_OOB command (including support for deprecated
+	    UFD config_method)
+	* added optional framework for external password storage ("ext:<name>")
+	* wpa_cli: added optional support for controlling wpa_supplicant
+	  remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+	* wpa_cli: extended tab completion to more commands
+	* changed SSID output to use printf-escaped strings instead of masking
+	  of non-ASCII characters
+	  - SSID can now be configured in the same format: ssid=P"abc\x00test"
+	* removed default ACM=1 from AC_VO and AC_VI
+	* added optional "ht40" argument for P2P ctrl_iface commands to allow
+	  40 MHz channels to be requested on the 5 GHz band
+	* added optional parameters for p2p_invite command to specify channel
+	  when reinvoking a persistent group as the GO
+	* improved FIPS mode builds with OpenSSL
+	  - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+	    OpenSSL FIPS object module
+	  - replace low level OpenSSL AES API calls to use EVP
+	  - use OpenSSL keying material exporter when possible
+	  - do not export TLS keys in FIPS mode
+	  - remove MD5 from CONFIG_FIPS=y builds
+	  - use OpenSSL function for PKBDF2 passphrase-to-PSK
+	  - use OpenSSL HMAC implementation
+	  - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+	    DRBG to be used in FIPS mode
+	  - use OpenSSL CMAC implementation
+	* added mechanism to disable TLS Session Ticket extension
+	  - a workaround for servers that do not support TLS extensions that
+	    was enabled by default in recent OpenSSL versions
+	  - tls_disable_session_ticket=1
+	  - automatically disable TLS Session Ticket extension by default when
+	    using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+	* changed VENDOR-TEST EAP method to use proper private enterprise number
+	  (this will not interoperate with older versions)
+	* disable network block temporarily on authentication failures
+	* improved WPS AP selection during WPS PIN iteration
+	* added support for configuring GCMP cipher for IEEE 802.11ad
+	* added support for Wi-Fi Display extensions
+	  - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+	  - SET wifi_display <0/1> to disable/enable WFD support
+	  - WFD service discovery
+	  - an external program is needed to manage the audio/video streaming
+	    and codecs
+	* optimized scan result use for network selection
+	  - use the internal BSS table instead of raw scan results
+	  - allow unnecessary scans to be skipped if fresh information is
+	    available (e.g., after GAS/ANQP round for Interworking)
+	* added support for 256-bit AES with internal TLS implementation
+	* allow peer to propose channel in P2P invitation process for a
+	  persistent group
+	* added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+	  from network selection
+	* re-enable the networks disabled during WPS operations
+	* allow P2P functionality to be disabled per interface (p2p_disabled=1)
+	* added secondary device types into P2P_PEER output
+	* added an option to disable use of a separate P2P group interface
+	  (p2p_no_group_iface=1)
+	* fixed P2P Bonjour SD to match entries with both compressed and not
+	  compressed domain name format and support multiple Bonjour PTR matches
+	  for the same key
+	* use deauthentication instead of disassociation for all disconnection
+	  operations; this removes the now unused disassociate() wpa_driver_ops
+	  callback
+	* optimized PSK generation on P2P GO by caching results to avoid
+	  multiple PBKDF2 operations
+	* added okc=1 global configuration parameter to allow OKC to be enabled
+	  by default for all network blocks
+	* added a workaround for WPS PBC session overlap detection to avoid
+	  interop issues with deployed station implementations that do not
+	  remove active PBC indication from Probe Request frames properly
+	* added basic support for 60 GHz band
+	* extend EAPOL frames processing workaround for roaming cases
+	  (postpone processing of unexpected EAPOL frame until association
+	  event to handle reordered events)
+
+2012-05-10 - v1.0
+	* bsd: Add support for setting HT values in IFM_MMASK.
+	* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+	  This allows the driver to use PS buffering of Deauthentication and
+	  Disassociation frames when the STA is in power save sleep. Only
+	  available with drivers that provide TX status events for Deauth/
+	  Disassoc frames (nl80211).
+	* Drop oldest unknown BSS table entries first. This makes it less
+	  likely to hit connection issues in environments with huge number
+	  of visible APs.
+	* Add systemd support.
+	* Add support for setting the syslog facility from the config file
+	  at build time.
+	* atheros: Add support for IEEE 802.11w configuration.
+	* AP mode: Allow enable HT20 if driver supports it, by setting the
+	  config parameter ieee80211n.
+	* Allow AP mode to disconnect STAs based on low ACK condition (when
+	  the data connection is not working properly, e.g., due to the STA
+	  going outside the range of the AP). Disabled by default, enable by
+	  config option disassoc_low_ack.
+	* nl80211:
+	  - Support GTK rekey offload.
+	  - Support PMKSA candidate events. This adds support for RSN
+	    pre-authentication with nl80211 interface and drivers that handle
+	    roaming internally.
+	* dbus:
+	  - Add a DBus signal for EAP SM requests, emitted on the Interface
+	    object.
+	  - Export max scan ssids supported by the driver as MaxScanSSID.
+	  - Add signal Certification for information about server certification.
+	  - Add BSSExpireAge and BSSExpireCount interface properties and
+	    support set/get, which allows for setting BSS cache expiration age
+	    and expiration scan count.
+	  - Add ConfigFile to AddInterface properties.
+	  - Add Interface.Country property and support to get/set the value.
+	  - Add DBus property CurrentAuthMode.
+	  - P2P DBus API added.
+	  - Emit property changed events (for property BSSs) when adding/
+	    removing BSSs.
+	  - Treat '' in SSIDs of Interface.Scan as a request for broadcast
+	    scan, instead of ignoring it.
+	  - Add DBus getter/setter for FastReauth.
+	  - Raise PropertiesChanged on org.freedesktop.DBus.Properties.
+	* wpa_cli:
+	  - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+	    due to inactivity.
+	  - Make second argument to set command optional. This can be used to
+	    indicate a zero length value.
+	  - Add signal_poll command.
+	  - Add bss_expire_age and bss_expire_count commands to set/get BSS
+	    cache expiration age and expiration scan count.
+	  - Add ability to set scan interval (the time in seconds wpa_s waits
+	    before requesting a new scan after failing to find a suitable
+	    network in scan results) using scan_interval command.
+	  - Add event CTRL-EVENT-ASSOC-REJECT for association rejected.
+	  - Add command get version, that returns wpa_supplicant version string.
+	  - Add command sta_autoconnect for disabling automatic reconnection
+	    on receiving disconnection event.
+	  - Setting bssid parameter to an empty string "" or any can now be
+	    used to clear the bssid_set flag in a network block, i.e., to remove
+	    bssid filtering.
+	  - Add tdls_testing command to add a special testing feature for
+	    changing TDLS behavior. Build param CONFIG_TDLS_TESTING must be
+	    enabled as well.
+	  - For interworking, add wpa_cli commands interworking_select,
+	    interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp.
+	  - Many P2P commands were added. See README-P2P.
+	  - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+	  - Allow set command to change global config parameters.
+	  - Add log_level command, which can be used to display the current
+	    debugging level and to change the log level during run time.
+	  - Add note command, which can be used to insert notes to the debug
+	    log.
+	  - Add internal line edit implementation. CONFIG_WPA_CLI_EDIT=y
+	    can now be used to build wpa_cli with internal implementation of
+	    line editing and history support. This can be used as a replacement
+	    for CONFIG_READLINE=y.
+	* AP mode: Add max_num_sta config option, which can be used to limit
+	  the number of stations allowed to connect to the AP.
+	* Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+	  config file.
+	* wext: Increase scan timeout from 5 to 10 seconds.
+	* Add blacklist command, allowing an external program to
+	  manage the BSS blacklist and display its current contents.
+	* WPS:
+	  - Add wpa_cli wps_pin get command for generating random PINs. This can
+	    be used in a UI to generate a PIN without starting WPS (or P2P)
+	    operation.
+	  - Set RF bands based on driver capabilities, instead of hardcoding
+	    them.
+	  - Add mechanism for indicating non-standard WPS errors.
+	  - Add CONFIG_WPS_REG_DISABLE_OPEN=y option to disable open networks
+	    by default.
+	  - Add wps_ap_pin cli command for wpa_supplicant AP mode.
+	  - Add wps_check_pin cli command for processing PIN from user input.
+	    UIs can use this command to process a PIN entered by a user and to
+	    validate the checksum digit (if present).
+	  - Cancel WPS operation on PBC session overlap detection.
+	  - New wps_cancel command in wpa_cli will cancel a pending WPS
+	    operation.
+	  - wpa_cli action: Add WPS_EVENT_SUCCESS and WPS_EVENT_FAIL handlers.
+	  - Trigger WPS config update on Manufacturer, Model Name, Model
+	    Number, and Serial Number changes.
+	  - Fragment size is now configurable for EAP-WSC peer. Use
+	    wpa_cli set wps_fragment_size <val>.
+	  - Disable AP PIN after 10 consecutive failures. Slow down attacks on
+	    failures up to 10.
+	  - Allow AP to start in Enrollee mode without AP PIN for probing, to
+	    be compatible with Windows 7.
+	  - Add Config Error into WPS-FAIL events to provide more info to the
+	    user on how to resolve the issue.
+	  - Label and Display config methods are not allowed to be enabled
+	    at the same time, since it is unclear which PIN to use if both
+	    methods are advertised.
+	  - When controlling multiple interfaces:
+	     - apply WPS commands to all interfaces configured to use WPS
+	     - apply WPS config changes to all interfaces that use WPS
+	     - when an attack is detected on any interface, disable AP PIN on
+	       all interfaces
+	* WPS ER:
+	  - Add special AP Setup Locked mode to allow read only ER.
+	    ap_setup_locked=2 can now be used to enable a special mode where
+	    WPS ER can learn the current AP settings, but cannot change them.
+	  - Show SetSelectedRegistrar events as ctrl_iface events
+	  - Add wps_er_set_config to enroll a network based on a local
+	    network configuration block instead of having to (re-)learn the
+	    current AP settings with wps_er_learn.
+	  - Allow AP filtering based on IP address, add ctrl_iface event for
+	    learned AP settings, add wps_er_config command to configure an AP.
+	* WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+	  - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+	    for testing protocol extensibility.
+	  - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+	    workarounds.
+	  - Add support for AuthorizedMACs attribute.
+	* TDLS:
+	  - Propogate TDLS related nl80211 capability flags from kernel and
+	    add them as driver capability flags. If the driver doesn't support
+	    capabilities, assume TDLS is supported internally. When TDLS is
+	    explicitly not supported, disable all user facing TDLS operations.
+	  - Allow TDLS to be disabled at runtime (mostly for testing).
+	    Use set tdls_disabled.
+	  - Honor AP TDLS settings that prohibit/allow TDLS.
+	  - Add a special testing feature for changing TDLS behavior. Use
+	    CONFIG_TDLS_TESTING build param to enable. Configure at runtime
+	    with tdls_testing cli command.
+	  - Add support for TDLS 802.11z.
+	* wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+	  wlantest can be used to capture frames from a monitor interface
+	  for realtime capturing or from pcap files for offline analysis.
+	* Interworking: Support added for 802.11u. Enable in .config with
+	  CONFIG_INTERWORKING. See wpa_supplicant.conf for config parameters
+	  for interworking. wpa_cli commands added to support this are
+	  interworking_select, interworking_connect, anqp_get, fetch_anqp,
+	  and stop_fetch_anqp.
+	* Android: Add build and runtime support for Android wpa_supplicant.
+	* bgscan learn: Add new bgscan that learns BSS information based on
+	  previous scans, and uses that information to dynamically generate
+	  the list of channels for background scans.
+	* Add a new debug message level for excessive information. Use
+	  -ddd to enable.
+	* TLS: Add support for tls_disable_time_checks=1 in client mode.
+	* Internal TLS:
+	  - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+	    CONFIG_TLSV11.
+	  - Add domainComponent parser for X.509 names.
+	* Linux: Add RFKill support by adding an interface state "disabled".
+	* Reorder some IEs to get closer to IEEE 802.11 standard. Move
+	  WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+	  Move HT IEs to be later in (Re)Assoc Resp.
+	* Solaris: Add support for wired 802.1X client.
+	* Wi-Fi Direct support. See README-P2P for more information.
+	* Many bugfixes.
+
+2010-04-18 - v0.7.2
+	* nl80211: fixed number of issues with roaming
+	* avoid unnecessary roaming if multiple APs with similar signal
+	  strength are present in scan results
+	* add TLS client events and server probing to ease design of
+	  automatic detection of EAP parameters
+	* add option for server certificate matching (SHA256 hash of the
+	  certificate) instead of trusted CA certificate configuration
+	* bsd: Cleaned up driver wrapper and added various low-level
+	  configuration options
+	* wpa_gui-qt4: do not show too frequent WPS AP available events as
+	  tray messages
+	* TNC: fixed issues with fragmentation
+	* EAP-TNC: add Flags field into fragment acknowledgement (needed to
+	  interoperate with other implementations; may potentially breaks
+	  compatibility with older wpa_supplicant/hostapd versions)
+	* wpa_cli: added option for using a separate process to receive event
+	  messages to reduce latency in showing these
+	  (CFLAGS += -DCONFIG_WPA_CLI_FORK=y in .config to enable this)
+	* maximum BSS table size can now be configured (bss_max_count)
+	* BSSes to be included in the BSS table can be filtered based on
+	  configured SSIDs to save memory (filter_ssids)
+	* fix number of issues with IEEE 802.11r/FT; this version is not
+	  backwards compatible with old versions
+	* nl80211: add support for IEEE 802.11r/FT protocol (both over-the-air
+	  and over-the-DS)
+	* add freq_list network configuration parameter to allow the AP
+	  selection to filter out entries based on the operating channel
+	* add signal strength change events for bgscan; this allows more
+	  dynamic changes to background scanning interval based on changes in
+	  the signal strength with the current AP; this improves roaming within
+	  ESS quite a bit, e.g., with bgscan="simple:30:-45:300" in the network
+	  configuration block to request background scans less frequently when
+	  signal strength remains good and to automatically trigger background
+	  scans whenever signal strength drops noticeably
+	  (this is currently only available with nl80211)
+	* add BSSID and reason code (if available) to disconnect event messages
+	* wpa_gui-qt4: more complete support for translating the GUI with
+	  linguist and add German translation
+	* fix DH padding with internal crypto code (mainly, for WPS)
+	* do not trigger initial scan automatically anymore if there are no
+	  enabled networks
+
+2010-01-16 - v0.7.1
+	* cleaned up driver wrapper API (struct wpa_driver_ops); the new API
+	  is not fully backwards compatible, so out-of-tree driver wrappers
+	  will need modifications
+	* cleaned up various module interfaces
+	* merge hostapd and wpa_supplicant developers' documentation into a
+	  single document
+	* nl80211: use explicit deauthentication to clear cfg80211 state to
+	  avoid issues when roaming between APs
+	* dbus: major design changes in the new D-Bus API
+	  (fi.w1.wpa_supplicant1)
+	* nl80211: added support for IBSS networks
+	* added internal debugging mechanism with backtrace support and memory
+	  allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
+	* added WPS ER unsubscription command to more cleanly unregister from
+	  receiving UPnP events when ER is terminated
+	* cleaned up AP mode operations to avoid need for virtual driver_ops
+	  wrapper
+	* added BSS table to maintain more complete scan result information
+	  over multiple scans (that may include only partial results)
+	* wpa_gui-qt4: update Peers dialog information more dynamically while
+	  the dialog is kept open
+	* fixed PKCS#12 use with OpenSSL 1.0.0
+	* driver_wext: Added cfg80211-specific optimization to avoid some
+	  unnecessary scans and to speed up association
+
+2009-11-21 - v0.7.0
+	* increased wpa_cli ping interval to 5 seconds and made this
+	  configurable with a new command line options (-G<seconds>)
+	* fixed scan buffer processing with WEXT to handle up to 65535
+	  byte result buffer (previously, limited to 32768 bytes)
+	* allow multiple driver wrappers to be specified on command line
+	  (e.g., -Dnl80211,wext); the first one that is able to initialize the
+	  interface will be used
+	* added support for multiple SSIDs per scan request to optimize
+	  scan_ssid=1 operations in ap_scan=1 mode (i.e., search for hidden
+	  SSIDs); this requires driver support and can currently be used only
+	  with nl80211
+	* added support for WPS USBA out-of-band mechanism with USB Flash
+	  Drives (UFD) (CONFIG_WPS_UFD=y)
+	* driver_ndis: add PAE group address to the multicast address list to
+	  fix wired IEEE 802.1X authentication
+	* fixed IEEE 802.11r key derivation function to match with the standard
+	  (note: this breaks interoperability with previous version) [Bug 303]
+	* added better support for drivers that allow separate authentication
+	  and association commands (e.g., mac80211-based Linux drivers with
+	  nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol
+	  to be used (IEEE 802.11r)
+	* fixed SHA-256 based key derivation function to match with the
+	  standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+	  (note: this breaks interoperability with previous version) [Bug 307]
+	* use shared driver wrapper files with hostapd
+	* added AP mode functionality (CONFIG_AP=y) with mode=2 in the network
+	  block; this can be used for open and WPA2-Personal networks
+	  (optionally, with WPS); this links in parts of hostapd functionality
+	  into wpa_supplicant
+	* wpa_gui-qt4: added new Peers dialog to show information about peers
+	  (other devices, including APs and stations, etc. in the neighborhood)
+	* added support for WPS External Registrar functionality (configure APs
+	  and enroll new devices); can be used with wpa_gui-qt4 Peers dialog
+	  and wpa_cli commands wps_er_start, wps_er_stop, wps_er_pin,
+	  wps_er_pbc, wps_er_learn
+	  (this can also be used with a new 'none' driver wrapper if no
+	  wireless device or IEEE 802.1X on wired is needed)
+	* driver_nl80211: multiple updates to provide support for new Linux
+	  nl80211/mac80211 functionality
+	* updated management frame protection to use IEEE Std 802.11w-2009
+	* fixed number of small WPS issues and added workarounds to
+	  interoperate with common deployed broken implementations
+	* added support for NFC out-of-band mechanism with WPS
+	* driver_ndis: fixed wired IEEE 802.1X authentication with PAE group
+	  address frames
+	* added preliminary support for IEEE 802.11r RIC processing
+	* added support for specifying subset of enabled frequencies to scan
+	  (scan_freq option in the network configuration block); this can speed
+	  up scanning process considerably if it is known that only a small
+	  subset of channels is actually used in the network (this is currently
+	  supported only with -Dnl80211)
+	* added a workaround for race condition between receiving the
+	  association event and the following EAPOL-Key
+	* added background scan and roaming infrastructure to allow
+	  network-specific optimizations to be used to improve roaming within
+	  an ESS (same SSID)
+	* added new DBus interface (fi.w1.wpa_supplicant1)
+
+2009-01-06 - v0.6.7
+	* added support for Wi-Fi Protected Setup (WPS)
+	  (wpa_supplicant can now be configured to act as a WPS Enrollee to
+	  enroll credentials for a network using PIN and PBC methods; in
+	  addition, wpa_supplicant can act as a wireless WPS Registrar to
+	  configure an AP); WPS support can be enabled by adding CONFIG_WPS=y
+	  into .config and setting the runtime configuration variables in
+	  wpa_supplicant.conf (see WPS section in the example configuration
+	  file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to
+	  manage WPS negotiation; see README-WPS for more details
+	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+	* added support for using driver_test over UDP socket
+	* fixed PEAPv0 Cryptobinding interoperability issue with Windows Server
+	  2008 NPS; optional cryptobinding is now enabled (again) by default
+	* fixed PSK editing in wpa_gui
+	* changed EAP-GPSK to use the IANA assigned EAP method type 51
+	* added a Windows installer that includes WinPcap and all the needed
+	  DLLs; in addition, it set up the registry automatically so that user
+	  will only need start wpa_gui to get prompted to start the wpasvc
+	  servide and add a new interface if needed through wpa_gui dialog
+	* updated management frame protection to use IEEE 802.11w/D7.0
+
+2008-11-23 - v0.6.6
+	* added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA
+	  (can be used to simulate test SIM/USIM card with a known private key;
+	  enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config
+	  and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration)
+	* added a new network configuration option, wpa_ptk_rekey, that can be
+	  used to enforce frequent PTK rekeying, e.g., to mitigate some attacks
+	  against TKIP deficiencies
+	* added an optional mitigation mechanism for certain attacks against
+	  TKIP by delaying Michael MIC error reports by a random amount of time
+	  between 0 and 60 seconds; this can be enabled with a build option
+	  CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config
+	* fixed EAP-AKA to use RES Length field in AT_RES as length in bits,
+	  not bytes
+	* updated OpenSSL code for EAP-FAST to use an updated version of the
+	  session ticket overriding API that was included into the upstream
+	  OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
+	  needed with that version anymore)
+	* updated userspace MLME instructions to match with the current Linux
+	  mac80211 implementation; please also note that this can only be used
+	  with driver_nl80211.c (the old code from driver_wext.c was removed)
+	* added support (Linux only) for RoboSwitch chipsets (often found in
+	  consumer grade routers); driver interface 'roboswitch'
+	* fixed canceling of PMKSA caching when using drivers that generate
+	  RSN IE and refuse to drop PMKIDs that wpa_supplicant does not know
+	  about
+
+2008-11-01 - v0.6.5
+	* added support for SHA-256 as X.509 certificate digest when using the
+	  internal X.509/TLSv1 implementation
+	* updated management frame protection to use IEEE 802.11w/D6.0
+	* added support for using SHA256-based stronger key derivation for WPA2
+	  (IEEE 802.11w)
+	* fixed FT (IEEE 802.11r) authentication after a failed association to
+	  use correct FTIE
+	* added support for configuring Phase 2 (inner/tunneled) authentication
+	  method with wpa_gui-qt4
+
+2008-08-10 - v0.6.4
+	* added support for EAP Sequences in EAP-FAST Phase 2
+	* added support for using TNC with EAP-FAST
+	* added driver_ps3 for the PS3 Linux wireless driver
+	* added support for optional cryptobinding with PEAPv0
+	* fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
+	  allow fallback to full handshake if server rejects PAC-Opaque
+	* added fragmentation support for EAP-TNC
+	* added support for parsing PKCS #8 formatted private keys into the
+	  internal TLS implementation (both PKCS #1 RSA key and PKCS #8
+	  encapsulated RSA key can now be used)
+	* added option of using faster, but larger, routines in the internal
+	  LibTomMath (for internal TLS implementation) to speed up DH and RSA
+	  calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y)
+	* fixed race condition between disassociation event and group key
+	  handshake to avoid getting stuck in incorrect state [Bug 261]
+	* fixed opportunistic key caching (proactive_key_caching)
+
+2008-02-22 - v0.6.3
+	* removed 'nai' and 'eappsk' network configuration variables that were
+	  previously used for configuring user identity and key for EAP-PSK,
+	  EAP-PAX, EAP-SAKE, and EAP-GPSK. 'identity' field is now used as the
+	  replacement for 'nai' (if old configuration used a separate
+	  'identity' value, that would now be configured as
+	  'anonymous_identity'). 'password' field is now used as the
+	  replacement for 'eappsk' (it can also be set using hexstring to
+	  present random binary data)
+	* removed '-w' command line parameter (wait for interface to be added,
+	  if needed); cleaner way of handling this functionality is to use an
+	  external mechanism (e.g., hotplug scripts) that start wpa_supplicant
+	  when an interface is added
+	* updated FT support to use the latest draft, IEEE 802.11r/D9.0
+	* added ctrl_iface monitor event (CTRL-EVENT-SCAN-RESULTS) for
+	  indicating when new scan results become available
+	* added new ctrl_iface command, BSS, to allow scan results to be
+	  fetched without hitting the message size limits (this command
+	  can be used to iterate through the scan results one BSS at the time)
+	* fixed EAP-SIM not to include AT_NONCE_MT and AT_SELECTED_VERSION
+	  attributes in EAP-SIM Start/Response when using fast reauthentication
+	* fixed EAPOL not to end up in infinite loop when processing dynamic
+	  WEP keys with IEEE 802.1X
+	* fixed problems in getting NDIS events from WMI on Windows 2000
+
+2008-01-01 - v0.6.2
+	* added support for Makefile builds to include debug-log-to-a-file
+	  functionality (CONFIG_DEBUG_FILE=y and -f<path> on command line)
+	* fixed EAP-SIM and EAP-AKA message parser to validate attribute
+	  lengths properly to avoid potential crash caused by invalid messages
+	* added data structure for storing allocated buffers (struct wpabuf);
+	  this does not affect wpa_supplicant usage, but many of the APIs
+	  changed and various interfaces (e.g., EAP) is not compatible with old
+	  versions
+	* added support for protecting EAP-AKA/Identity messages with
+	  AT_CHECKCODE (optional feature in RFC 4187)
+	* added support for protected result indication with AT_RESULT_IND for
+	  EAP-SIM and EAP-AKA (phase1="result_ind=1")
+	* added driver_wext workaround for race condition between scanning and
+	  association with drivers that take very long time to scan all
+	  channels (e.g., madwifi with dual-band cards); wpa_supplicant is now
+	  using a longer hardcoded timeout for the scan if the driver supports
+	  notifications for scan completion (SIOCGIWSCAN event); this helps,
+	  e.g., in cases where wpa_supplicant and madwifi driver ended up in
+	  loop where the driver did not even try to associate
+	* stop EAPOL timer tick when no timers are in use in order to reduce
+	  power consumption (no need to wake up the process once per second)
+	  [Bug 237]
+	* added support for privilege separation (run only minimal part of
+	  wpa_supplicant functionality as root and rest as unprivileged,
+	  non-root process); see 'Privilege separation' in README for details;
+	  this is disabled by default and can be enabled with CONFIG_PRIVSEP=y
+	  in .config
+	* changed scan results data structure to include all information
+	  elements to make it easier to support new IEs; old get_scan_result()
+	  driver_ops is still supported for backwards compatibility (results
+	  are converted internally to the new format), but all drivers should
+	  start using the new get_scan_results2() to make them more likely to
+	  work with new features
+	* Qt4 version of wpa_gui (wpa_gui-qt4 subdirectory) is now native Qt4
+	  application, i.e., it does not require Qt3Support anymore; Windows
+	  binary of wpa_gui.exe is now from this directory and only requires
+	  QtCore4.dll and QtGui4.dll libraries
+	* updated Windows binary build to use Qt 4.3.3 and made Qt DLLs
+	  available as a separate package to make wpa_gui installation easier:
+	  http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
+	* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
+	  only shared key/password authentication is supported in this version
+
+2007-11-24 - v0.6.1
+	* added support for configuring password as NtPasswordHash
+	  (16-byte MD4 hash of password) in hash:<32 hex digits> format
+	* added support for fallback from abbreviated TLS handshake to
+	  full handshake when using EAP-FAST (e.g., due to an expired
+	  PAC-Opaque)
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-07.txt)
+	* added support for drivers that take care of RSN 4-way handshake
+	  internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and
+	  WPA_ALG_PMK in set_key)
+	* added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in
+	  .config); this version supports only ap_scan=2 mode and allow the
+	  driver to take care of the 4-way handshake
+	* fixed a buffer overflow in parsing TSF from scan results when using
+	  driver_wext.c with a driver that includes the TSF (e.g., iwl4965)
+	  [Bug 232]
+	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
+	* fixed an integer overflow issue in the ASN.1 parser used by the
+	  (experimental) internal TLS implementation to avoid a potential
+	  buffer read overflow
+	* fixed a race condition with -W option (wait for a control interface
+	  monitor before starting) that could have caused the first messages to
+	  be lost
+	* added support for processing TNCC-TNCS-Messages to report
+	  recommendation (allow/none/isolate) when using TNC [Bug 243]
+
+2007-05-28 - v0.6.0
+	* added network configuration parameter 'frequency' for setting
+	  initial channel for IBSS (adhoc) networks
+	* added experimental IEEE 802.11r/D6.0 support
+	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+	* updated EAP-PSK to use the IANA-allocated EAP type 47
+	* fixed EAP-PAX key derivation
+	* fixed EAP-PSK bit ordering of the Flags field
+	* fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in
+	  tunnelled identity request (previously, the identifier from the outer
+	  method was used, not the tunnelled identifier which could be
+	  different)
+	* added support for fragmentation of outer TLS packets during Phase 2
+	  of EAP-PEAP/TTLS/FAST
+	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
+	* added support for EAP-FAST authentication with inner methods that
+	  generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported
+	  for PAC provisioning)
+	* added support for authenticated EAP-FAST provisioning
+	* added support for configuring maximum number of EAP-FAST PACs to
+	  store in a PAC list (fast_max_pac_list_len=<max> in phase1 string)
+	* added support for storing EAP-FAST PACs in binary format
+	  (fast_pac_format=binary in phase1 string)
+	* fixed dbus ctrl_iface to validate message interface before
+	  dispatching to avoid a possible segfault [Bug 190]
+	* fixed PeerKey key derivation to use the correct PRF label
+	* updated Windows binary build to link against OpenSSL 0.9.8d and
+	  added support for EAP-FAST
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-04.txt)
+	* fixed EAP-AKA Notification processing to allow Notification to be
+	  processed after AKA Challenge response has been sent
+	* updated to use IEEE 802.11w/D2.0 for management frame protection
+	  (still experimental)
+	* fixed EAP-TTLS implementation not to crash on use of freed memory
+	  if TLS library initialization fails
+	* added support for EAP-TNC (Trusted Network Connect)
+	  (this version implements the EAP-TNC method and EAP-TTLS changes
+	  needed to run two methods in sequence (IF-T) and the IF-IMC and
+	  IF-TNCCS interfaces from TNCC)
+
+2006-11-24 - v0.5.6
+	* added experimental, integrated TLSv1 client implementation with the
+	  needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+	  setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+	  .config); this can be useful, e.g., if the target system does not
+	  have a suitable TLS library and a minimal code size is required
+	  (total size of this internal TLS/crypto code is bit under 50 kB on
+	  x86 and the crypto code is shared by rest of the supplicant so some
+	  of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB)
+	* removed STAKey handshake since PeerKey handshake has replaced it in
+	  IEEE 802.11ma and there are no known deployments of STAKey
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-01.txt)
+	* added preliminary implementation of IEEE 802.11w/D1.0 (management
+	  frame protection)
+	  (Note: this requires driver support to work properly.)
+	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+	* fixed Windows named pipes ctrl_iface to not stop listening for
+	  commands if client program opens a named pipe and closes it
+	  immediately without sending a command
+	* fixed USIM PIN status determination for the case that PIN is not
+	  needed (this allows EAP-AKA to be used with USIM cards that do not
+	  use PIN)
+	* added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to
+	  be used with cards that do not support file selection based on
+	  partial AID
+	* added support for matching the subjectAltName of the authentication
+	  server certificate against multiple name components (e.g.,
+	  altsubject_match="DNS:server.example.com;DNS:server2.example.com")
+	* fixed EAP-SIM/AKA key derivation for re-authentication case (only
+	  affects IEEE 802.1X with dynamic WEP keys)
+	* changed ctrl_iface network configuration 'get' operations to not
+	  return password/key material; if these fields are requested, "*"
+	  will be returned if the password/key is set, but the value of the
+	  parameter is not exposed
+
+2006-08-27 - v0.5.5
+	* added support for building Windows version with UNICODE defined
+	  (wide-char functions)
+	* driver_ndis: fixed static WEP configuration to avoid race condition
+	  issues with some NDIS drivers between association and setting WEP
+	  keys
+	* driver_ndis: added validation for IELength value in scan results to
+	  avoid crashes when using buggy NDIS drivers [Bug 165]
+	* fixed Release|Win32 target in the Visual Studio project files
+	  (previously, only Debug|Win32 target was set properly)
+	* changed control interface API call wpa_ctrl_pending() to allow it to
+	  return -1 on error (e.g., connection lost); control interface clients
+	  will need to make sure that they verify that the value is indeed >0
+	  when determining whether there are pending messages
+	* added an alternative control interface backend for Windows targets:
+	  Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default
+	  control interface mechanism for Windows builds (previously, UDP to
+	  localhost was used)
+	* changed ctrl_interface configuration for UNIX domain sockets:
+	  - deprecated ctrl_interface_group variable (it may be removed in
+	    future versions)
+	  - allow both directory and group be configured with ctrl_interface
+	    in following format: DIR=/var/run/wpa_supplicant GROUP=wheel
+	  - ctrl_interface=/var/run/wpa_supplicant is still supported for the
+	    case when group is not changed
+	* added support for controlling more than one interface per process in
+	  Windows version
+	* added a workaround for a case where the AP is using unknown address
+	  (e.g., MAC address of the wired interface) as the source address for
+	  EAPOL-Key frames; previously, that source address was used as the
+	  destination for EAPOL-Key frames and in key derivation; now, BSSID is
+	  used even if the source address does not match with it
+	  (this resolves an interoperability issue with Thomson SpeedTouch 580)
+	* added a workaround for UDP-based control interface (which was used in
+	  Windows builds before this release) to prevent packets with forged
+	  addresses from being accepted as local control requests
+	* removed ndis_events.cpp and possibility of using external
+	  ndis_events.exe; C version (ndis_events.c) is fully functional and
+	  there is no desire to maintain two separate versions of this
+	  implementation
+	* ndis_events: Changed NDIS event notification design to use WMI to
+	  learn the adapter description through Win32_PnPEntity class; this
+	  should fix some cases where the adapter name was not recognized
+	  correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500
+	  USB) [Bug 113]
+	* fixed selection of the first network in ap_scan=2 mode; previously,
+	  wpa_supplicant could get stuck in SCANNING state when only the first
+	  network for enabled (e.g., after 'wpa_cli select_network 0')
+	* winsvc: added support for configuring ctrl_interface parameters in
+	  registry (ctrl_interface string value in
+	  HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is
+	  required to enable control interface (previously, this was hardcoded
+	  to be enabled)
+	* allow wpa_gui subdirectory to be built with both Qt3 and Qt4
+	* converted wpa_gui-qt4 subdirectory to use Qt4 specific project format
+
+2006-06-20 - v0.5.4
+	* fixed build with CONFIG_STAKEY=y [Bug 143]
+	* added support for doing MLME (IEEE 802.11 management frame
+	  processing) in wpa_supplicant when using Devicescape IEEE 802.11
+	  stack (wireless-dev.git tree)
+	* added a new network block configuration option, fragment_size, to
+	  configure the maximum EAP fragment size
+	* driver_ndis: Disable WZC automatically for the selected interface to
+	  avoid conflicts with two programs trying to control the radio; WZC
+	  will be re-enabled (if it was enabled originally) when wpa_supplicant
+	  is terminated
+	* added an experimental TLSv1 client implementation
+	  (CONFIG_TLS=internal) that can be used instead of an external TLS
+	  library, e.g., to reduce total size requirement on systems that do
+	  not include any TLS library by default (this is not yet complete;
+	  basic functionality is there, but certificate validation is not yet
+	  included)
+	* added PeerKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS) to replace STAKey handshake
+	* fixed WPA PSK update through ctrl_iface for the case where the old
+	  PSK was derived from an ASCII passphrase and the new PSK is set as
+	  a raw PSK (hex string)
+	* added new configuration option for identifying which network block
+	  was used (id_str in wpa_supplicant.conf; included on
+	  WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental
+	  variable in wpa_cli action scripts; in addition WPA_ID variable is
+	  set to the current unique identifier that wpa_supplicant assigned
+	  automatically for the network and that can be used with
+	  GET_NETWORK/SET_NETWORK ctrl_iface commands)
+	* wpa_cli action script is now called only when the connect/disconnect
+	  status changes or when associating with a different network
+	* fixed configuration parser not to remove CCMP from group cipher list
+	  if WPA-None (adhoc) is used (pairwise=NONE in that case)
+	* fixed integrated NDIS events processing not to hang the process due
+	  to a missed change in eloop_win.c API in v0.5.3 [Bug 155]
+	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+	  draft-clancy-emu-eap-shared-secret-00.txt)
+	* added Microsoft Visual Studio 2005 solution and project files for
+	  build wpa_supplicant for Windows (see vs2005 subdirectory)
+	* eloop_win: fixed unregistration of Windows events
+	* l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet
+	  at the end of RSN pre-authentication and added unregistration of
+	  a Windows event to avoid getting eloop_win stuck with an invalid
+	  handle
+	* driver_ndis: added support for selecting AP based on BSSID
+	* added new environmental variable for wpa_cli action scripts:
+	  WPA_CTRL_DIR is the current control interface directory
+	* driver_ndis: added support for using NDISUIO instead of WinPcap for
+	  OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new
+	  l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build
+	  wpa_supplicant without requiring WinPcap; note that using NDISUIO
+	  requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows
+	  only one application to open the device
+	* changed NDIS driver naming to only include device GUID, e.g.,
+	  {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap
+	  specific \Device\NPF_ prefix before the GUID; the prefix is still
+	  allowed for backwards compatibility, but it is not required anymore
+	  when specifying the interface
+	* driver_ndis: re-initialize driver interface is the adapter is removed
+	  and re-inserted [Bug 159]
+	* driver_madwifi: fixed TKIP and CCMP sequence number configuration on
+	  big endian hosts [Bug 146]
+
+2006-04-27 - v0.5.3
+	* fixed EAP-GTC response to include correct user identity when run as
+	  phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2)
+	* driver_ndis: Fixed encryption mode configuration for unencrypted
+	  networks (some NDIS drivers ignored this, but others, e.g., Broadcom,
+	  refused to associate with open networks) [Bug 106]
+	* driver_ndis: use BSSID OID polling to detect when IBSS network is
+	  formed even when ndis_events code is included since some NDIS drivers
+	  do not generate media connect events in IBSS mode
+	* config_winreg: allow global ctrl_interface parameter to be configured
+	  in Windows registry
+	* config_winreg: added support for saving configuration data into
+	  Windows registry
+	* added support for controlling network device operational state
+	  (dormant/up) for Linux 2.6.17 to improve DHCP processing (see
+	  http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client
+	  that can use this information)
+	* driver_wext: added support for WE-21 change to SSID configuration
+	* driver_wext: fixed privacy configuration for static WEP keys mode
+	  [Bug 140]
+	* added an optional driver_ops callback for MLME-SETPROTECTION.request
+	  primitive
+	* added support for EAP-SAKE (no EAP method number allocated yet, so
+	  this is using the same experimental type 255 as EAP-PSK)
+	* added support for dynamically loading EAP methods (.so files) instead
+	  of requiring them to be statically linked in; this is disabled by
+	  default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information
+	  on how to use this)
+
+2006-03-19 - v0.5.2
+	* do not try to use USIM APDUs when initializing PC/SC for SIM card
+	  access for a network that has not enabled EAP-AKA
+	* fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in
+	  v0.5.1 due to the new support for expanded EAP types)
+	* added support for generating EAP Expanded Nak
+	* try to fetch scan results once before requesting new scan when
+	  starting up in ap_scan=1 mode (this can speed up initial association
+	  a lot with, e.g., madwifi-ng driver)
+	* added support for receiving EAPOL frames from a Linux bridge
+	  interface (-bbr0 on command line)
+	* fixed EAPOL re-authentication for sessions that used PMKSA caching
+	* changed EAP method registration to use a dynamic list of methods
+	  instead of a static list generated at build time
+	* fixed PMKSA cache deinitialization not to use freed memory when
+	  removing PMKSA entries
+	* fixed a memory leak in EAP-TTLS re-authentication
+	* reject WPA/WPA2 message 3/4 if it does not include any valid
+	  WPA/RSN IE
+	* driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg
+	  if the driver does not support SIOCSIWAUTH
+
+2006-01-29 - v0.5.1
+	* driver_test: added better support for multiple APs and STAs by using
+	  a directory with sockets that include MAC address for each device in
+	  the name (driver_param=test_dir=/tmp/test)
+	* added support for EAP expanded type (vendor specific EAP methods)
+	* added AP_SCAN command into ctrl_iface so that ap_scan configuration
+	  option can be changed if needed
+	* wpa_cli/wpa_gui: skip non-socket files in control directory when
+	  using UNIX domain sockets; this avoids selecting an incorrect
+	  interface (e.g., a PID file could be in this directory, even though
+	  use of this directory for something else than socket files is not
+	  recommended)
+	* fixed TLS library deinitialization after RSN pre-authentication not
+	  to disable TLS library for normal authentication
+	* driver_wext: Remove null-termination from SSID length if the driver
+	  used it; some Linux drivers do this and they were causing problems in
+	  wpa_supplicant not finding matching configuration block. This change
+	  would break a case where the SSID actually ends in '\0', but that is
+	  not likely to happen in real use.
+	* fixed PMKSA cache processing not to trigger deauthentication if the
+	  current PMKSA cache entry is replaced with a valid new entry
+	* fixed PC/SC initialization for ap_scan != 1 modes (this fixes
+	  EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or
+	  ap_scan=2)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+	* added experimental STAKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS); note: this is disabled by default in both
+	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+	  and stakey=1)
+	* fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to
+	  decrypt AT_ENCR_DATA attributes correctly
+	* fixed EAP-AKA to allow resynchronization within the same session
+	* made code closer to ANSI C89 standard to make it easier to port to
+	  other C libraries and compilers
+	* started moving operating system or C library specific functions into
+	  wrapper functions defined in os.h and implemented in os_*.c to make
+	  code more portable
+	* wpa_supplicant can now be built with Microsoft Visual C++
+	  (e.g., with the freely available Toolkit 2003 version or Visual
+	  C++ 2005 Express Edition and Platform SDK); see nmake.mak for an
+	  example makefile for nmake
+	* added support for using Windows registry for command line parameters
+	  (CONFIG_MAIN=main_winsvc) and configuration data
+	  (CONFIG_BACKEND=winreg); see win_example.reg for an example registry
+	  contents; this version can be run both as a Windows service and as a
+	  normal application; 'wpasvc.exe app' to start as applicant,
+	  'wpasvc.exe reg <full path to wpasvc.exe>' to register a service,
+	  'net start wpasvc' to start the service, 'wpasvc.exe unreg' to
+	  unregister a service
+	* made it possible to link ndis_events.exe functionality into
+	  wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED
+	* added better support for multiple control interface backends
+	  (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported
+	* fixed PC/SC code to use correct length for GSM AUTH command buffer
+	  and to not use pioRecvPci with SCardTransmit() calls; these were not
+	  causing visible problems with pcsc-lite, but Windows Winscard.dll
+	  refused the previously used parameters; this fixes EAP-SIM and
+	  EAP-AKA authentication using SIM/USIM card under Windows
+	* added new event loop implementation for Windows using
+	  WaitForMultipleObject() instead of select() in order to allow waiting
+	  for non-socket objects; this can be selected with
+	  CONFIG_ELOOP=eloop_win in .config
+	* added support for selecting l2_packet implementation in .config
+	  (CONFIG_L2_PACKET; following options are available now: linux, pcap,
+	  winpcap, freebsd, none)
+	* added new l2_packet implementation for WinPcap
+	  (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to
+	  reduce latency in EAPOL receive processing from about 100 ms to about
+	  3 ms
+	* added support for EAP-FAST key derivation using other ciphers than
+	  RC4-128-SHA for authentication and AES128-SHA for provisioning
+	* added support for configuring CA certificate as DER file and as a
+	  configuration blob
+	* fixed private key configuration as configuration blob and added
+	  support for using PKCS#12 as a blob
+	* tls_gnutls: added support for using PKCS#12 files; added support for
+	  session resumption
+	* added support for loading trusted CA certificates from Windows
+	  certificate store: ca_cert="cert_store://<name>", where <name> is
+	  likely CA (Intermediate CA certificates) or ROOT (root certificates)
+	* added C version of ndis_events.cpp and made it possible to build this
+	  with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more
+	  easily on cross-compilation builds
+	* added wpasvc.exe into Windows binary release; this is an alternative
+	  version of wpa_supplicant.exe with configuration backend using
+	  Windows registry and with the entry point designed to run as a
+	  Windows service
+	* integrated ndis_events.exe functionality into wpa_supplicant.exe and
+	  wpasvc.exe and removed this additional tool from the Windows binary
+	  release since it is not needed anymore
+	* load winscard.dll functions dynamically when building with MinGW
+	  since MinGW does not yet include winscard library
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+	* l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap
+	  and WinPcap to receive frames sent to PAE group address
+	* disable EAP state machine when IEEE 802.1X authentication is not used
+	  in order to get rid of bogus "EAP failed" messages
+	* fixed OpenSSL error reporting to go through all pending errors to
+	  avoid confusing reports of old errors being reported at later point
+	  during handshake
+	* fixed configuration file updating to not write empty variables
+	  (e.g., proto or key_mgmt) that the file parser would not accept
+	* fixed ADD_NETWORK ctrl_iface command to use the same default values
+	  for variables as empty network definitions read from config file
+	  would get
+	* fixed EAP state machine to not discard EAP-Failure messages in many
+	  cases (e.g., during TLS handshake)
+	* fixed a infinite loop in private key reading if the configured file
+	  cannot be parsed successfully
+	* driver_madwifi: added support for madwifi-ng
+	* wpa_gui: do not display password/PSK field contents
+	* wpa_gui: added CA certificate configuration
+	* driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID
+	* driver_ndis: include Beacon IEs in AssocInfo in order to notice if
+	  the new AP is using different WPA/RSN IE
+	* use longer timeout for IEEE 802.11 association to avoid problems with
+	  drivers that may take more than five second to associate
+
+2005-10-27 - v0.4.6
+	* allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in
+	  RSN IE, but WPA IE would match with wpa_supplicant configuration
+	* added support for named configuration blobs in order to avoid having
+	  to use file system for external files (e.g., certificates);
+	  variables can be set to "blob://<blob name>" instead of file path to
+	  use a named blob; supported fields: pac_file, client_cert,
+	  private_key
+	* fixed RSN pre-authentication (it was broken in the clean up of WPA
+	  state machine interface in v0.4.5)
+	* driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make
+	  sure the driver configures broadcast decryption correctly
+	* added ca_path (and ca_path2) configuration variables that can be used
+	  to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the
+	  system-wide trusted CA list
+	* added support for starting wpa_supplicant without a configuration
+	  file (-C argument must be used to set ctrl_interface parameter for
+	  this case; in addition, -p argument can be used to provide
+	  driver_param; these new arguments can also be used with a
+	  configuration to override the values from the configuration)
+	* added global control interface that can be optionally used for adding
+	  and removing network interfaces dynamically (-g command line argument
+	  for both wpa_supplicant and wpa_cli) without having to restart
+	  wpa_supplicant process
+	* wpa_gui:
+	  - try to save configuration whenever something is modified
+	  - added WEP key configuration
+	  - added possibility to edit the current network configuration
+	* driver_ndis: fixed driver polling not to increase frequency on each
+	  received EAPOL frame due to incorrectly cancelled timeout
+	* added simple configuration file examples (in examples subdirectory)
+	* fixed driver_wext.c to filter wireless events based on ifindex to
+	  avoid interfaces receiving events from other interfaces
+	* delay sending initial EAPOL-Start couple of seconds to speed up
+	  authentication for the most common case of Authenticator starting
+	  EAP authentication immediately after association
+
+2005-09-25 - v0.4.5
+	* added a workaround for clearing keys with ndiswrapper to allow
+	  roaming from WPA enabled AP to plaintext one
+	* added docbook documentation (doc/docbook) that can be used to
+	  generate, e.g., man pages
+	* l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for
+	  PF_PACKET in order to prepare for network devices that do not use
+	  Ethernet headers (e.g., network stack with native IEEE 802.11 frames)
+	* use receipt of EAPOL-Key frame as a lower layer success indication
+	  for EAP state machine to allow recovery from dropped EAP-Success
+	  frame
+	* cleaned up internal EAPOL frame processing by not including link
+	  layer (Ethernet) header during WPA and EAPOL/EAP processing; this
+	  header is added only when transmitted the frame; this makes it easier
+	  to use wpa_supplicant on link layers that use different header than
+	  Ethernet
+	* updated EAP-PSK to use draft 9 by default since this can now be
+	  tested with hostapd; removed support for draft 3, including
+	  server_nai configuration option from network blocks
+	* driver_wired: add PAE address to the multicast address list in order
+	  to be able to receive EAPOL frames with drivers that do not include
+	  these multicast addresses by default
+	* driver_wext: add support for WE-19
+	* added support for multiple configuration backends (CONFIG_BACKEND
+	  option); currently, only 'file' is supported (i.e., the format used
+	  in wpa_supplicant.conf)
+	* added support for updating configuration ('wpa_cli save_config');
+	  this is disabled by default and can be enabled with global
+	  update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli
+	  and wpa_gui to store the configuration changes in a permanent store
+	* added GET_NETWORK ctrl_iface command
+	  (e.g., 'wpa_cli get_network 0 ssid')
+
+2005-08-21 - v0.4.4
+	* replaced OpenSSL patch for EAP-FAST support
+	  (openssl-tls-extensions.patch) with a more generic and correct
+	  patch (the new patch is not compatible with the previous one, so the
+	  OpenSSL library will need to be patched with the new patch in order
+	  to be able to build wpa_supplicant with EAP-FAST support)
+	* added support for using Windows certificate store (through CryptoAPI)
+	  for client certificate and private key operations (EAP-TLS)
+	  (see wpa_supplicant.conf for more information on how to configure
+	  this with private_key)
+	* ported wpa_gui to Windows
+	* added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be
+	  built with the open source version of the Qt4 for Windows
+	* allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used
+	  with drivers that do not support WPA
+	* ndis_events: fixed Windows 2000 support
+	* added support for enabling/disabling networks from the list of all
+	  configured networks ('wpa_cli enable_network <network id>' and
+	  'wpa_cli disable_network <network id>')
+	* added support for adding and removing network from the current
+	  configuration ('wpa_cli add_network' and 'wpa_cli remove_network
+	  <network id>'); added networks are disabled by default and they can
+	  be enabled with enable_network command once the configuration is done
+	  for the new network; note: configuration file is not yet updated, so
+	  these new networks are lost when wpa_supplicant is restarted
+	* added support for setting network configuration parameters through
+	  the control interface, for example:
+	  wpa_cli set_network 0 ssid "\"my network\""
+	* fixed parsing of strings that include both " and # within double
+	  quoted area (e.g., "start"#end")
+	* added EAP workaround for PEAP session resumption: allow outer,
+	  i.e., not tunneled, EAP-Success to terminate session since; this can
+	  be disabled with eap_workaround=0
+	  (this was allowed for PEAPv1 before, but now it is also allowed for
+	  PEAPv0 since at least one RADIUS authentication server seems to be
+	  doing this for PEAPv0, too)
+	* wpa_gui: added preliminary support for adding new networks to the
+	  wpa_supplicant configuration (double click on the scan results to
+	  open network configuration)
+
+2005-06-26 - v0.4.3
+	* removed interface for external EAPOL/EAP supplicant (e.g.,
+	  Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required
+	  anymore and is unlikely to be used by anyone
+	* driver_ndis: fixed WinPcap 3.0 support
+	* fixed build with CONFIG_DNET_PCAP=y on Linux
+	* l2_packet: moved different implementations into separate files
+	  (l2_packet_*.c)
+
+2005-06-12 - v0.4.2
+	* driver_ipw: updated driver structures to match with ipw2200-1.0.4
+	  (note: ipw2100-1.1.0 is likely to require an update to work with
+	  this)
+	* added support for using ap_scan=2 mode with multiple network blocks;
+	  wpa_supplicant will go through the networks one by one until the
+	  driver reports a successful association; this uses the same order for
+	  networks as scan_ssid=1 scans, i.e., the priority field is ignored
+	  and the network block order in the file is used instead
+	* fixed a potential issue in RSN pre-authentication ending up using
+	  freed memory if pre-authentication times out
+	* added support for matching alternative subject name extensions of the
+	  authentication server certificate; new configuration variables
+	  altsubject_match and altsubject_match2
+	* driver_ndis: added support for IEEE 802.1X authentication with wired
+	  NDIS drivers
+	* added support for querying private key password (EAP-TLS) through the
+	  control interface (wpa_cli/wpa_gui) if one is not included in the
+	  configuration file
+	* driver_broadcom: fixed couple of memory leaks in scan result
+	  processing
+	* EAP-PAX is now registered as EAP type 46
+	* fixed EAP-PAX MAC calculation
+	* fixed EAP-PAX CK and ICK key derivation
+	* added support for using password with EAP-PAX (as an alternative to
+	  entering key with eappsk); SHA-1 hash of the password will be used as
+	  the key in this case
+	* added support for arbitrary driver interface parameters through the
+	  configuration file with a new driver_param field; this adds a new
+	  driver_ops function set_param()
+	* added possibility to override l2_packet module with driver interface
+	  API (new send_eapol handler); this can be used to implement driver
+	  specific TX/RX functions for EAPOL frames
+	* fixed ctrl_interface_group processing for the case where gid is
+	  entered as a number, not group name
+	* driver_test: added support for testing hostapd with wpa_supplicant
+	  by using test driver interface without any kernel drivers or network
+	  cards
+
+2005-05-22 - v0.4.1
+	* driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL
+	  packets to be encrypted; this was apparently broken by the changed
+	  ioctl order in v0.4.0
+	* driver_madwifi: added preliminary support for compiling against 'BSD'
+	  branch of madwifi CVS tree
+	* added support for EAP-MSCHAPv2 password retries within the same EAP
+	  authentication session
+	* added support for password changes with EAP-MSCHAPv2 (used when the
+	  password has expired)
+	* added support for reading additional certificates from PKCS#12 files
+	  and adding them to the certificate chain
+	* fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys
+	  were used
+	* fixed a possible double free in EAP-TTLS fast-reauthentication when
+	  identity or password is entered through control interface
+	* display EAP Notification messages to user through control interface
+	  with "CTRL-EVENT-EAP-NOTIFICATION" prefix
+	* added GUI version of wpa_cli, wpa_gui; this is not build
+	  automatically with 'make'; use 'make wpa_gui' to build (this requires
+	  Qt development tools)
+	* added 'disconnect' command to control interface for setting
+	  wpa_supplicant in state where it will not associate before
+	  'reassociate' command has been used
+	* added support for selecting a network from the list of all configured
+	  networks ('wpa_cli select_network <network id>'; this disabled all
+	  other networks; to re-enable, 'wpa_cli select_network any')
+	* added support for getting scan results through control interface
+	* added EAP workaround for PEAPv1 session resumption: allow outer,
+	  i.e., not tunneled, EAP-Success to terminate session since; this can
+	  be disabled with eap_workaround=0
+
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+	* added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be
+	  used to reduce the size of the wpa_supplicant considerably if
+	  debugging code is not needed
+	* fixed EAPOL-Key validation to drop packets with invalid Key Data
+	  Length; such frames could have crashed wpa_supplicant due to buffer
+	  overflow
+	* added support for wired authentication (IEEE 802.1X on wired
+	  Ethernet); driver interface 'wired'
+	* obsoleted set_wpa() handler in the driver interface API (it can be
+	  replaced by moving enable/disable functionality into init()/deinit())
+	  (calls to set_wpa() are still present for backwards compatibility,
+	  but they may be removed in the future)
+	* driver_madwifi: fixed association in plaintext mode
+	* modified the EAP workaround that accepts EAP-Success with incorrect
+	  Identifier to be even less strict about verification in order to
+	  interoperate with some authentication servers
+	* added support for sending TLS alerts
+	* added support for 'any' SSID wildcard; if ssid is not configured or
+	  is set to an empty string, any SSID will be accepted for non-WPA AP
+	* added support for asking PIN (for SIM) from frontends (e.g.,
+	  wpa_cli); if a PIN is needed, but not included in the configuration
+	  file, a control interface request is sent and EAP processing is
+	  delayed until the PIN is available
+	* added support for using external devices (e.g., a smartcard) for
+	  private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config);
+	  new wpa_supplicant.conf variables:
+	  - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path
+	  - network: engine, engine_id, key_id
+	* added experimental support for EAP-PAX
+	* added monitor mode for wpa_cli (-a<path to a program to run>) that
+	  allows external commands (e.g., shell scripts) to be run based on
+	  wpa_supplicant events, e.g., when authentication has been completed
+	  and data connection is ready; other related wpa_cli arguments:
+	  -B (run in background), -P (write PID file); wpa_supplicant has a new
+	  command line argument (-W) that can be used to make it wait until a
+	  control interface command is received in order to avoid missing
+	  events
+	* added support for opportunistic WPA2 PMKSA key caching (disabled by
+	  default, can be enabled with proactive_key_caching=1)
+	* fixed RSN IE in 4-Way Handshake message 2/4 for the case where
+	  Authenticator rejects PMKSA caching attempt and the driver is not
+	  using assoc_info events
+	* added -P<pid file> argument for wpa_supplicant to write the current
+	  process id into a file
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+	* added new phase1 option parameter, include_tls_length=1, to force
+	  wpa_supplicant to add TLS Message Length field to all TLS messages
+	  even if the packet is not fragmented; this may be needed with some
+	  authentication servers
+	* fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when
+	  using drivers that take care of AP selection (e.g., when using
+	  ap_scan=2)
+	* fixed reprocessing of pending request after ctrl_iface requests for
+	  identity/password/otp
+	* fixed ctrl_iface requests for identity/password/otp in Phase 2 of
+	  EAP-PEAP and EAP-TTLS
+	* all drivers using driver_wext: set interface up and select Managed
+	  mode when starting wpa_supplicant; set interface down when exiting
+	* renamed driver_ipw2100.c to driver_ipw.c since it now supports both
+	  ipw2100 and ipw2200; please note that this also changed the
+	  configuration variable in .config to CONFIG_DRIVER_IPW
+
+2005-01-24 - v0.3.6
+	* fixed a busy loop introduced in v0.3.5 for scan result processing
+	  when no matching AP is found
+
+2005-01-23 - v0.3.5
+	* added a workaround for an interoperability issue with a Cisco AP
+	  when using WPA2-PSK
+	* fixed non-WPA IEEE 802.1X to use the same authentication timeout as
+	  WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow
+	  retransmission of dropped frames)
+	* fixed issues with 64-bit CPUs and SHA1 cleanup in previous version
+	  (e.g., segfault when processing EAPOL-Key frames)
+	* fixed EAP workaround and fast reauthentication configuration for
+	  RSN pre-authentication; previously these were disabled and
+	  pre-authentication would fail if the used authentication server
+	  requires EAP workarounds
+	* added support for blacklisting APs that fail or timeout
+	  authentication in ap_scan=1 mode so that all APs are tried in cases
+	  where the ones with strongest signal level are failing authentication
+	* fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS
+	  authentication attempt
+	* allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded
+	  in the previous authentication (previously, only Phase 1 success was
+	  verified)
+
+2005-01-09 - v0.3.4
+	* added preliminary support for IBSS (ad-hoc) mode configuration
+	  (mode=1 in network block); this included a new key_mgmt mode
+	  WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no
+	  key management; see wpa_supplicant.conf for more details and an
+	  example on how to configure this (note: this is currently implemented
+	  only for driver_hostapd.c, but the changes should be trivial to add
+	  in associate() handler for other drivers, too (assuming the driver
+	  supports WPA-None)
+	* added preliminary port for native Windows (i.e., no cygwin) using
+	  mingw
+
+2005-01-02 - v0.3.3
+	* added optional support for GNU Readline and History Libraries for
+	  wpa_cli (CONFIG_READLINE)
+	* cleaned up EAP state machine <-> method interface and number of
+	  small problems with error case processing not terminating on
+	  EAP-Failure but waiting for timeout
+	* added couple of workarounds for interoperability issues with a
+	  Cisco AP when using WPA2
+	* added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt);
+	  Note: This requires a patch for openssl to add support for TLS
+	  extensions and number of workarounds for operations without
+	  certificates. Proof of concept type of experimental patch is
+	  included in openssl-tls-extensions.patch.
+
+2004-12-19 - v0.3.2
+	* fixed private key loading for cases where passphrase is not set
+	* fixed Windows/cygwin L2 packet handler freeing; previous version
+	  could cause a segfault when RSN pre-authentication was completed
+	* added support for PMKSA caching with drivers that generate RSN IEs
+	  (e.g., NDIS); currently, this is only implemented in driver_ndis.c,
+	  but similar code can be easily added to driver_ndiswrapper.c once
+	  ndiswrapper gets full support for RSN PMKSA caching
+	* improved recovery from PMKID mismatches by requesting full EAP
+	  authentication in case of failed PMKSA caching attempt
+	* driver_ndis: added support for NDIS NdisMIncidateStatus() events
+	  (this requires that ndis_events is ran while wpa_supplicant is
+	  running)
+	* driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys
+	* added support for driver interfaces to replace the interface name
+	  based on driver/OS specific mapping, e.g., in case of driver_ndis,
+	  this allows the beginning of the adapter description to be used as
+	  the interface name
+	* added support for CR+LF (Windows-style) line ends in configuration
+	  file
+	* driver_ndis: enable radio before starting scanning, disable radio
+	  when exiting
+	* modified association event handler to set portEnabled = FALSE before
+	  clearing port Valid in order to reset EAP state machine and avoid
+	  problems with new authentication getting ignored because of state
+	  machines ending up in AUTHENTICATED/SUCCESS state based on old
+	  information
+	* added support for driver events to add PMKID candidates in order to
+	  allow drivers to give priority to most likely roaming candidates
+	* driver_hostap: moved PrivacyInvoked configuration to associate()
+	  function so that this will not be set for plaintext connections
+	* added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver
+	  interface can distinguish plaintext and IEEE 802.1X (no WPA)
+	  authentication
+	* fixed static WEP key configuration to use broadcast/default type for
+	  all keys (previously, the default TX key was configured as pairwise/
+	  unicast key)
+	* driver_ndis: added legacy WPA capability detection for non-WPA2
+	  drivers
+	* added support for setting static WEP keys for IEEE 802.1X without
+	  dynamic WEP keying (eapol_flags=0)
+
+2004-12-12 - v0.3.1
+	* added support for reading PKCS#12 (PFX) files (as a replacement for
+	  PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+	* fixed compilation with CONFIG_PCSC=y
+	* added new ap_scan mode, ap_scan=2, for drivers that take care of
+	  association, but need to be configured with security policy and SSID,
+	  e.g., ndiswrapper and NDIS driver; this mode should allow such
+	  drivers to work with hidden SSIDs and optimized roaming; when
+	  ap_scan=2 is used, only the first network block in the configuration
+	  file is used and this configuration should have explicit security
+	  policy (i.e., only one option in the lists) for key_mgmt, pairwise,
+	  group, proto variables
+	* added experimental port of wpa_supplicant for Windows
+	  - driver_ndis.c driver interface (NDIS OIDs)
+	  - currently, this requires cygwin and WinPcap
+	  - small utility, win_if_list, can be used to get interface name
+	* control interface can now be removed at build time; add
+	  CONFIG_CTRL_IFACE=y to .config to maintain old functionality
+	* optional Xsupplicant interface can now be removed at build time;
+	  (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back)
+	* added auth_alg to driver interface associate() parameters to make it
+	  easier for drivers to configure authentication algorithm as part of
+	  the association
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+	* driver_broadcom: added new driver interface for Broadcom wl.o driver
+	  (a generic driver for Broadcom IEEE 802.11a/g cards)
+	* wpa_cli: fixed parsing of -p <path> command line argument
+	* PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS
+	  ACK, not tunneled EAP-Success (of which only the first byte was
+	  actually send due to a bug in previous code); this seems to
+	  interoperate with most RADIUS servers that implements PEAPv1
+	* PEAPv1: added support for terminating PEAP authentication on tunneled
+	  EAP-Success message; this can be configured by adding
+	  peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf
+	  (some RADIUS servers require this whereas others require a tunneled
+	  reply
+	* PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to
+	  the old label for key derivation; previously, the default was 1,
+	  but it looks like most existing PEAPv1 implementations use the old
+	  label which is thus more suitable default option
+	* added support for EAP-PSK (draft-bersani-eap-psk-03.txt)
+	* fixed parsing of wep_tx_keyidx
+	* added support for configuring list of allowed Phase 2 EAP types
+	  (for both EAP-PEAP and EAP-TTLS) instead of only one type
+	* added support for configuring IEEE 802.11 authentication algorithm
+	  (auth_alg; mainly for using Shared Key authentication with static
+	  WEP keys)
+	* added support for EAP-AKA (with UMTS SIM)
+	* fixed couple of errors in PCSC handling that could have caused
+	  random-looking errors for EAP-SIM
+	* added support for EAP-SIM pseudonyms and fast re-authentication
+	* added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS
+	  session resumption)
+	* added support for EAP-SIM with two challanges
+	  (phase1="sim_min_num_chal=3" can be used to require three challenges)
+	* added support for configuring DH/DSA parameters for an ephemeral DH
+	  key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters
+	  dh_file and dh_file2 (phase 2); this adds support for using DSA keys
+	  and optional DH key exchange to achieve forward secracy with RSA keys
+	* added support for matching subject of the authentication server
+	  certificate with a substring when using EAP-TLS/PEAP/TTLS; new
+	  configuration variables subject_match and subject_match2
+	* changed SSID configuration in driver_wext.c (used by many driver
+	  interfaces) to use ssid_len+1 as the length for SSID since some Linux
+	  drivers expect this
+	* fixed couple of unaligned reads in scan result parsing to fix WPA
+	  connection on some platforms (e.g., ARM)
+	* added driver interface for Intel ipw2100 driver
+	* added support for LEAP with WPA
+	* added support for larger scan results report (old limit was 4 kB of
+	  data, i.e., about 35 or so APs) when using Linux wireless extensions
+	  v17 or newer
+	* fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start
+	  only if there is a PMKSA cache entry for the current AP
+	* fixed error handling for case where reading of scan results fails:
+	  must schedule a new scan or wpa_supplicant will remain waiting
+	  forever
+	* changed debug output to remove shared password/key material by
+	  default; all key information can be included with -K command line
+	  argument to match the previous behavior
+	* added support for timestamping debug log messages (disabled by
+	  default, can be enabled with -t command line argument)
+	* set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104
+	  if keys are not configured to be used; this fixes IEEE 802.1X mode
+	  with drivers that use this information to configure whether Privacy
+	  bit can be in Beacon frames (e.g., ndiswrapper)
+	* avoid clearing driver keys if no keys have been configured since last
+	  key clear request; this seems to improve reliability of group key
+	  handshake for ndiswrapper & NDIS driver which seems to be suffering
+	  of some kind of timing issue when the keys are cleared again after
+	  association
+	* changed driver interface API:
+	  - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which
+	    version is being used (now, this is set to 2; previously, it was
+	    not defined)
+	  - pass pointer to private data structure to all calls
+	  - the new API is not backwards compatible; all in-tree driver
+	    interfaces has been converted to the new API
+	* added support for controlling multiple interfaces (radios) per
+	  wpa_supplicant process; each interface needs to be listed on the
+	  command line (-c, -i, -D arguments) with -N as a separator
+	  (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi)
+	* added a workaround for EAP servers that incorrectly use same Id for
+	  sequential EAP packets
+	* changed libpcap/libdnet configuration to use .config variable,
+	  CONFIG_DNET_PCAP, instead of requiring Makefile modification
+	* improved downgrade attack detection in IE verification of msg 3/4:
+	  verify both WPA and RSN IEs, if present, not only the selected one;
+	  reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or
+	  Probe Response frame, and RSN is enabled in wpa_supplicant
+	  configuration
+	* fixed WPA msg 3/4 processing to allow Key Data field contain other
+	  IEs than just one WPA IE
+	* added support for FreeBSD and driver interface for the BSD net80211
+	  layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the
+	  required kernel mods have not yet been committed
+	* made EAP workarounds configurable; enabled by default, can be
+	  disabled with network block option eap_workaround=0
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+	* resolved couple of interoperability issues with EAP-PEAPv1 and
+	  Phase 2 (inner EAP) fragment reassembly
+	* driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the
+	  AP is using non-zero key index for the unicast key and key index zero
+	  for the broadcast key
+	* driver_hostap: fixed IEEE 802.1X WEP key updates and
+	  re-authentication by allowing unencrypted EAPOL frames when not using
+	  WPA
+	* added a new driver interface, 'wext', which uses only standard,
+	  driver independent functionality in Linux wireless extensions;
+	  currently, this can be used only for non-WPA IEEE 802.1X mode, but
+	  eventually, this is to be extended to support full WPA/WPA2 once
+	  Linux wireless extensions get support for this
+	* added support for mode in which the driver is responsible for AP
+	  scanning and selection; this is disabled by default and can be
+	  enabled with global ap_scan=0 variable in wpa_supplicant.conf;
+	  this mode can be used, e.g., with generic 'wext' driver interface to
+	  use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver
+	  supporting wireless extensions.
+	* driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g.,
+	  operation with an AP that does not include SSID in the Beacon frames)
+	* added support for new EAP authentication methods:
+	  EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP
+	* added support for asking one-time-passwords from frontends (e.g.,
+	  wpa_cli); this 'otp' command works otherwise like 'password' command,
+	  but the password is used only once and the frontend will be asked for
+	  a new password whenever a request from authenticator requires a
+	  password; this can be used with both EAP-OTP and EAP-GTC
+	* changed wpa_cli to automatically re-establish connection so that it
+	  does not need to be re-started when wpa_supplicant is terminated and
+	  started again
+	* improved user data (identity/password/otp) requests through
+	  frontends: process pending EAPOL packets after getting new
+	  information so that full authentication does not need to be
+	  restarted; in addition, send pending requests again whenever a new
+	  frontend is attached
+	* changed control frontends to use a new directory for socket files to
+	  make it easier for wpa_cli to automatically select between interfaces
+	  and to provide access control for the control interface;
+	  wpa_supplicant.conf: ctrl_interface is now a path
+	  (/var/run/wpa_supplicant is the recommended path) and
+	  ctrl_interface_group can be used to select which group gets access to
+	  the control interface;
+	  wpa_cli: by default, try to connect to the first interface available
+	  in /var/run/wpa_supplicant; this path can be overriden with -p option
+	  and an interface can be selected with -i option (i.e., in most common
+	  cases, wpa_cli does not need to get any arguments)
+	* added support for LEAP
+	* added driver interface for Linux ndiswrapper
+	* added priority option for network blocks in the configuration file;
+	  this allows networks to be grouped based on priority (the scan
+	  results are searched for matches with network blocks in this order)
+
+2004-06-20 - v0.2.3
+	* sort scan results to improve AP selection
+	* fixed control interface socket removal for some error cases
+	* improved scan requesting and authentication timeout
+	* small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and
+	  TLS processing
+	* PEAP version can now be forced with phase1="peapver=<ver>"
+	  (mostly for testing; by default, the highest version supported by
+	  both the Supplicant and Authentication Server is selected
+	  automatically)
+	* added support for madwifi driver (Atheros ar521x)
+	* added a workaround for cases where AP sets Install Tx/Rx bit for
+	  WPA Group Key messages when pairwise keys are used (without this,
+	  the Group Key would be used for Tx and the AP would drop frames
+	  from the station)
+	* added GSM SIM/USIM interface for GSM authentication algorithm for
+	  EAP-SIM; this requires pcsc-lite
+	* added support for ATMEL AT76C5XXx driver
+	* fixed IEEE 802.1X WEP key derivation in the case where Authenticator
+	  does not include key data in the EAPOL-Key frame (i.e., part of
+	  EAP keying material is used as data encryption key)
+	* added support for using plaintext and static WEP networks
+	  (key_mgmt=NONE)
+
+2004-05-31 - v0.2.2
+	* added support for new EAP authentication methods:
+	  EAP-TTLS/EAP-MD5-Challenge
+	  EAP-TTLS/EAP-GTC
+	  EAP-TTLS/EAP-MSCHAPv2
+	  EAP-TTLS/EAP-TLS
+	  EAP-TTLS/MSCHAPv2
+	  EAP-TTLS/MSCHAP
+	  EAP-TTLS/PAP
+	  EAP-TTLS/CHAP
+	  EAP-PEAP/TLS
+	  EAP-PEAP/GTC
+	  EAP-PEAP/MD5-Challenge
+	  EAP-GTC
+	  EAP-SIM (not yet complete; needs GSM/SIM authentication interface)
+	* added support for anonymous identity (to be used when identity is
+	  sent in plaintext; real identity will be used within TLS protected
+	  tunnel (e.g., with EAP-TTLS)
+	* added event messages from wpa_supplicant to frontends, e.g., wpa_cli
+	* added support for requesting identity and password information using
+	  control interface; in other words, the password for EAP-PEAP or
+	  EAP-TTLS does not need to be included in the configuration file since
+	  a frontand (e.g., wpa_cli) can ask it from the user
+	* improved RSN pre-authentication to use a candidate list and process
+	  all candidates from each scan; not only one per scan
+	* fixed RSN IE and WPA IE capabilities field parsing
+	* ignore Tx bit in GTK IE when Pairwise keys are used
+	* avoid making new scan requests during IEEE 802.1X negotiation
+	* use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant
+	  with TLS support (this replaces the included implementation with
+	  library code to save about 8 kB since the library code is needed
+	  anyway for TLS)
+	* fixed WPA-PSK only mode when compiled without IEEE 802.1X support
+	  (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config)
+
+2004-05-06 - v0.2.1
+	* added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1)
+	  Supplicant
+	  - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1]
+	  - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf]
+	  - EAP-MD5 (cannot be used with WPA-RADIUS)
+	    [draft-ietf-eap-rfc2284bis-09.txt]
+	  - EAP-TLS [RFC 2716]
+	  - EAP-MSCHAPv2 (currently used only with EAP-PEAP)
+	  - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt]
+	    [draft-kamath-pppext-eap-mschapv2-00.txt]
+	    (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by
+	    default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey)
+	  - new configuration file options: eap, identity, password, ca_cert,
+	    client_cert, privatekey, private_key_passwd
+	  - Xsupplicant is not required anymore, but it can be used by
+	    disabling the internal IEEE 802.1X Supplicant with -e command line
+	    option
+	  - this code is not included in the default build; Makefile need to
+	    be edited for this (uncomment lines for selected functionality)
+	  - EAP-TLS and EAP-PEAP require openssl libraries
+	* use module prefix in debug messages (WPA, EAP, EAP-TLS, ..)
+	* added support for non-WPA IEEE 802.1X mode with dynamic WEP keys
+	  (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X
+	   EAPOL-Key frames instead of WPA key handshakes)
+	* added support for IEEE 802.11i/RSN (WPA2)
+	  - improved PTK Key Handshake
+	  - PMKSA caching, pre-authentication
+	* fixed wpa_supplicant to ignore possible extra data after WPA
+	  EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using
+	  TPTK' error from message 3 of 4-Way Handshake in case the AP
+	  includes extra data after the EAPOL-Key)
+	* added interface for external programs (frontends) to control
+	  wpa_supplicant
+	  - CLI example (wpa_cli) with interactive mode and command line
+	    mode
+	  - replaced SIGUSR1 status/statistics with the new control interface
+	* made some feature compile time configurable
+	  - .config file for make
+	  - driver interfaces (hostap, hermes, ..)
+	  - EAPOL/EAP functions
+
+2004-02-15 - v0.2.0
+	* Initial version of wpa_supplicant

Deleted: vendor/wpa/2.0/wpa_supplicant/Makefile
===================================================================
--- vendor/wpa/dist/wpa_supplicant/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1380 +0,0 @@
-ifndef CC
-CC=gcc
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
-
-export LIBDIR ?= /usr/local/lib/
-export BINDIR ?= /usr/local/sbin/
-
-CFLAGS += -I../src
-CFLAGS += -I../src/utils
-
-ALL=wpa_supplicant wpa_passphrase wpa_cli
-
-all: verify_config $(ALL) dynamic_eap_methods
-
-verify_config:
-	@if [ ! -r .config ]; then \
-		echo 'Building wpa_supplicant requires a configuration file'; \
-		echo '(.config). See README for more instructions. You can'; \
-		echo 'run "cp defconfig .config" to create an example'; \
-		echo 'configuration.'; \
-		exit 1; \
-	fi
-
-mkconfig:
-	@if [ -f .config ]; then \
-		echo '.config exists - did not replace it'; \
-		exit 1; \
-	fi
-	echo CONFIG_DRIVER_HOSTAP=y >> .config
-	echo CONFIG_DRIVER_WEXT=y >> .config
-
-install: all
-	mkdir -p $(DESTDIR)$(BINDIR)
-	for i in $(ALL); do cp $$i $(DESTDIR)$(BINDIR)/$$i; done
-	$(MAKE) -C ../src install
-
-OBJS = config.o
-OBJS += notify.o
-OBJS += bss.o
-OBJS += eap_register.o
-OBJS += ../src/utils/common.o
-OBJS += ../src/utils/wpa_debug.o
-OBJS += ../src/utils/wpabuf.o
-OBJS_p = wpa_passphrase.o
-OBJS_p += ../src/utils/common.o
-OBJS_p += ../src/utils/wpa_debug.o
-OBJS_p += ../src/utils/wpabuf.o
-OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
-
--include .config
-
-ifndef CONFIG_OS
-ifdef CONFIG_NATIVE_WINDOWS
-CONFIG_OS=win32
-else
-CONFIG_OS=unix
-endif
-endif
-
-ifeq ($(CONFIG_OS), internal)
-CFLAGS += -DOS_NO_C_LIB_DEFINES
-endif
-
-OBJS += ../src/utils/os_$(CONFIG_OS).o
-OBJS_p += ../src/utils/os_$(CONFIG_OS).o
-OBJS_c += ../src/utils/os_$(CONFIG_OS).o
-
-ifdef CONFIG_WPA_TRACE
-CFLAGS += -DWPA_TRACE
-OBJS += ../src/utils/trace.o
-OBJS_p += ../src/utils/trace.o
-OBJS_c += ../src/utils/trace.o
-OBJS_c += ../src/utils/wpa_debug.o
-LDFLAGS += -rdynamic
-CFLAGS += -funwind-tables
-ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DWPA_TRACE_BFD
-LIBS += -lbfd
-LIBS_p += -lbfd
-LIBS_c += -lbfd
-endif
-endif
-
-ifndef CONFIG_ELOOP
-CONFIG_ELOOP=eloop
-endif
-OBJS += ../src/utils/$(CONFIG_ELOOP).o
-
-
-ifdef CONFIG_EAPOL_TEST
-CFLAGS += -Werror -DEAPOL_TEST
-endif
-
-ifndef CONFIG_BACKEND
-CONFIG_BACKEND=file
-endif
-
-ifeq ($(CONFIG_BACKEND), file)
-OBJS += config_file.o
-ifndef CONFIG_NO_CONFIG_BLOBS
-NEED_BASE64=y
-endif
-CFLAGS += -DCONFIG_BACKEND_FILE
-endif
-
-ifeq ($(CONFIG_BACKEND), winreg)
-OBJS += config_winreg.o
-endif
-
-ifeq ($(CONFIG_BACKEND), none)
-OBJS += config_none.o
-endif
-
-ifdef CONFIG_NO_CONFIG_WRITE
-CFLAGS += -DCONFIG_NO_CONFIG_WRITE
-endif
-
-ifdef CONFIG_NO_CONFIG_BLOBS
-CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
-endif
-
-ifdef CONFIG_NO_SCAN_PROCESSING
-CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
-endif
-
-ifdef CONFIG_IEEE80211W
-CFLAGS += -DCONFIG_IEEE80211W
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-endif
-
-ifdef CONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211R
-OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_80211_COMMON=y
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-endif
-
-ifdef CONFIG_PEERKEY
-CFLAGS += -DCONFIG_PEERKEY
-endif
-
-ifndef CONFIG_NO_WPA
-OBJS += ../src/rsn_supp/wpa.o
-OBJS += ../src/rsn_supp/preauth.o
-OBJS += ../src/rsn_supp/pmksa_cache.o
-OBJS += ../src/rsn_supp/peerkey.o
-OBJS += ../src/rsn_supp/wpa_ie.o
-OBJS += ../src/common/wpa_common.o
-NEED_AES=y
-NEED_SHA1=y
-NEED_MD5=y
-NEED_RC4=y
-else
-CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
-endif
-
-ifdef CONFIG_IBSS_RSN
-NEED_RSN_AUTHENTICATOR=y
-CFLAGS += -DCONFIG_IBSS_RSN
-OBJS += ibss_rsn.o
-endif
-
-ifdef CONFIG_NO_WPA2
-CFLAGS += -DCONFIG_NO_WPA2
-endif
-
-include ../src/drivers/drivers.mak
-ifdef CONFIG_AP
-OBJS_d += $(DRV_BOTH_OBJS)
-CFLAGS += $(DRV_BOTH_CFLAGS)
-LDFLAGS += $(DRV_BOTH_LDFLAGS)
-LIBS += $(DRV_BOTH_LIBS)
-else
-NEED_AP_MLME=
-OBJS_d += $(DRV_WPA_OBJS)
-CFLAGS += $(DRV_WPA_CFLAGS)
-LDFLAGS += $(DRV_WPA_LDFLAGS)
-LIBS += $(DRV_WPA_LIBS)
-endif
-
-ifndef CONFIG_L2_PACKET
-CONFIG_L2_PACKET=linux
-endif
-
-OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o
-
-ifeq ($(CONFIG_L2_PACKET), pcap)
-ifdef CONFIG_WINPCAP
-CFLAGS += -DCONFIG_WINPCAP
-LIBS += -lwpcap -lpacket
-LIBS_w += -lwpcap
-else
-LIBS += -ldnet -lpcap
-endif
-endif
-
-ifeq ($(CONFIG_L2_PACKET), winpcap)
-LIBS += -lwpcap -lpacket
-LIBS_w += -lwpcap
-endif
-
-ifeq ($(CONFIG_L2_PACKET), freebsd)
-LIBS += -lpcap
-endif
-
-ifdef CONFIG_EAP_TLS
-# EAP-TLS
-ifeq ($(CONFIG_EAP_TLS), dyn)
-CFLAGS += -DEAP_TLS_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_tls.so
-else
-CFLAGS += -DEAP_TLS
-OBJS += ../src/eap_peer/eap_tls.o
-OBJS_h += ../src/eap_server/eap_server_tls.o
-endif
-TLS_FUNCS=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_PEAP
-# EAP-PEAP
-ifeq ($(CONFIG_EAP_PEAP), dyn)
-CFLAGS += -DEAP_PEAP_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_peap.so
-else
-CFLAGS += -DEAP_PEAP
-OBJS += ../src/eap_peer/eap_peap.o
-OBJS += ../src/eap_common/eap_peap_common.o
-OBJS_h += ../src/eap_server/eap_server_peap.o
-endif
-TLS_FUNCS=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_TTLS
-# EAP-TTLS
-ifeq ($(CONFIG_EAP_TTLS), dyn)
-CFLAGS += -DEAP_TTLS_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_ttls.so
-else
-CFLAGS += -DEAP_TTLS
-OBJS += ../src/eap_peer/eap_ttls.o
-OBJS_h += ../src/eap_server/eap_server_ttls.o
-endif
-MS_FUNCS=y
-TLS_FUNCS=y
-CHAP=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_MD5
-# EAP-MD5
-ifeq ($(CONFIG_EAP_MD5), dyn)
-CFLAGS += -DEAP_MD5_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_md5.so
-else
-CFLAGS += -DEAP_MD5
-OBJS += ../src/eap_peer/eap_md5.o
-OBJS_h += ../src/eap_server/eap_server_md5.o
-endif
-CHAP=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-# backwards compatibility for old spelling
-ifdef CONFIG_MSCHAPV2
-ifndef CONFIG_EAP_MSCHAPV2
-CONFIG_EAP_MSCHAPV2=y
-endif
-endif
-
-ifdef CONFIG_EAP_MSCHAPV2
-# EAP-MSCHAPv2
-ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
-CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_mschapv2.so
-EAPDYN += ../src/eap_peer/mschapv2.so
-else
-CFLAGS += -DEAP_MSCHAPv2
-OBJS += ../src/eap_peer/eap_mschapv2.o
-OBJS += ../src/eap_peer/mschapv2.o
-OBJS_h += ../src/eap_server/eap_server_mschapv2.o
-endif
-MS_FUNCS=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_GTC
-# EAP-GTC
-ifeq ($(CONFIG_EAP_GTC), dyn)
-CFLAGS += -DEAP_GTC_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_gtc.so
-else
-CFLAGS += -DEAP_GTC
-OBJS += ../src/eap_peer/eap_gtc.o
-OBJS_h += ../src/eap_server/eap_server_gtc.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_OTP
-# EAP-OTP
-ifeq ($(CONFIG_EAP_OTP), dyn)
-CFLAGS += -DEAP_OTP_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_otp.so
-else
-CFLAGS += -DEAP_OTP
-OBJS += ../src/eap_peer/eap_otp.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_SIM
-# EAP-SIM
-ifeq ($(CONFIG_EAP_SIM), dyn)
-CFLAGS += -DEAP_SIM_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_sim.so
-else
-CFLAGS += -DEAP_SIM
-OBJS += ../src/eap_peer/eap_sim.o
-OBJS_h += ../src/eap_server/eap_server_sim.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_SIM_COMMON=y
-NEED_AES_CBC=y
-endif
-
-ifdef CONFIG_EAP_LEAP
-# EAP-LEAP
-ifeq ($(CONFIG_EAP_LEAP), dyn)
-CFLAGS += -DEAP_LEAP_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_leap.so
-else
-CFLAGS += -DEAP_LEAP
-OBJS += ../src/eap_peer/eap_leap.o
-endif
-MS_FUNCS=y
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_PSK
-# EAP-PSK
-ifeq ($(CONFIG_EAP_PSK), dyn)
-CFLAGS += -DEAP_PSK_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_psk.so
-else
-CFLAGS += -DEAP_PSK
-OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o
-OBJS_h += ../src/eap_server/eap_server_psk.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-NEED_AES=y
-NEED_AES_OMAC1=y
-NEED_AES_ENCBLOCK=y
-NEED_AES_EAX=y
-endif
-
-ifdef CONFIG_EAP_AKA
-# EAP-AKA
-ifeq ($(CONFIG_EAP_AKA), dyn)
-CFLAGS += -DEAP_AKA_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_aka.so
-else
-CFLAGS += -DEAP_AKA
-OBJS += ../src/eap_peer/eap_aka.o
-OBJS_h += ../src/eap_server/eap_server_aka.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_SIM_COMMON=y
-NEED_AES_CBC=y
-endif
-
-ifdef CONFIG_EAP_AKA_PRIME
-# EAP-AKA'
-ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
-CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
-else
-CFLAGS += -DEAP_AKA_PRIME
-endif
-NEED_SHA256=y
-endif
-
-ifdef CONFIG_EAP_SIM_COMMON
-OBJS += ../src/eap_common/eap_sim_common.o
-OBJS_h += ../src/eap_server/eap_sim_db.o
-NEED_AES=y
-NEED_FIPS186_2_PRF=y
-endif
-
-ifdef CONFIG_EAP_FAST
-# EAP-FAST
-ifeq ($(CONFIG_EAP_FAST), dyn)
-CFLAGS += -DEAP_FAST_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_fast.so
-EAPDYN += ../src/eap_common/eap_fast_common.o
-else
-CFLAGS += -DEAP_FAST
-OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
-OBJS += ../src/eap_common/eap_fast_common.o
-OBJS_h += ../src/eap_server/eap_server_fast.o
-endif
-TLS_FUNCS=y
-CONFIG_IEEE8021X_EAPOL=y
-NEED_T_PRF=y
-endif
-
-ifdef CONFIG_EAP_PAX
-# EAP-PAX
-ifeq ($(CONFIG_EAP_PAX), dyn)
-CFLAGS += -DEAP_PAX_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_pax.so
-else
-CFLAGS += -DEAP_PAX
-OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o
-OBJS_h += ../src/eap_server/eap_server_pax.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_SAKE
-# EAP-SAKE
-ifeq ($(CONFIG_EAP_SAKE), dyn)
-CFLAGS += -DEAP_SAKE_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_sake.so
-else
-CFLAGS += -DEAP_SAKE
-OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o
-OBJS_h += ../src/eap_server/eap_server_sake.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_GPSK
-# EAP-GPSK
-ifeq ($(CONFIG_EAP_GPSK), dyn)
-CFLAGS += -DEAP_GPSK_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_gpsk.so
-else
-CFLAGS += -DEAP_GPSK
-OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
-OBJS_h += ../src/eap_server/eap_server_gpsk.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-ifdef CONFIG_EAP_GPSK_SHA256
-CFLAGS += -DEAP_GPSK_SHA256
-endif
-NEED_SHA256=y
-NEED_AES_OMAC1=y
-endif
-
-ifdef CONFIG_WPS
-# EAP-WSC
-CFLAGS += -DCONFIG_WPS -DEAP_WSC
-OBJS += wps_supplicant.o
-OBJS += ../src/utils/uuid.o
-OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
-OBJS += ../src/wps/wps.o
-OBJS += ../src/wps/wps_common.o
-OBJS += ../src/wps/wps_attr_parse.o
-OBJS += ../src/wps/wps_attr_build.o
-OBJS += ../src/wps/wps_attr_process.o
-OBJS += ../src/wps/wps_dev_attr.o
-OBJS += ../src/wps/wps_enrollee.o
-OBJS += ../src/wps/wps_registrar.o
-OBJS_h += ../src/eap_server/eap_server_wsc.o
-CONFIG_IEEE8021X_EAPOL=y
-NEED_DH_GROUPS=y
-NEED_SHA256=y
-NEED_BASE64=y
-NEED_80211_COMMON=y
-NEED_AES_CBC=y
-NEED_MODEXP=y
-
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
-ifdef CONFIG_WPS_NFC
-CFLAGS += -DCONFIG_WPS_NFC
-OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
-NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
-endif
-
-ifdef NEED_WPS_OOB
-CFLAGS += -DCONFIG_WPS_OOB
-endif
-
-ifdef CONFIG_WPS_ER
-CONFIG_WPS_UPNP=y
-CFLAGS += -DCONFIG_WPS_ER
-OBJS += ../src/wps/wps_er.o
-OBJS += ../src/wps/wps_er_ssdp.o
-endif
-
-ifdef CONFIG_WPS_UPNP
-CFLAGS += -DCONFIG_WPS_UPNP
-OBJS += ../src/wps/wps_upnp.o
-OBJS += ../src/wps/wps_upnp_ssdp.o
-OBJS += ../src/wps/wps_upnp_web.o
-OBJS += ../src/wps/wps_upnp_event.o
-OBJS += ../src/wps/wps_upnp_ap.o
-OBJS += ../src/wps/upnp_xml.o
-OBJS += ../src/wps/httpread.o
-OBJS += ../src/wps/http_client.o
-OBJS += ../src/wps/http_server.o
-endif
-
-endif
-
-ifdef CONFIG_EAP_IKEV2
-# EAP-IKEv2
-ifeq ($(CONFIG_EAP_IKEV2), dyn)
-CFLAGS += -DEAP_IKEV2_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_ikev2.so ../src/eap_peer/ikev2.o
-EAPDYN += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
-else
-CFLAGS += -DEAP_IKEV2
-OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o
-OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
-OBJS_h += ../src/eap_server/eap_server_ikev2.o
-OBJS_h += ../src/eap_server/ikev2.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-NEED_DH_GROUPS=y
-NEED_DH_GROUPS_ALL=y
-NEED_MODEXP=y
-NEED_CIPHER=y
-endif
-
-ifdef CONFIG_EAP_VENDOR_TEST
-ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
-CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
-EAPDYN += ../src/eap_peer/eap_vendor_test.so
-else
-CFLAGS += -DEAP_VENDOR_TEST
-OBJS += ../src/eap_peer/eap_vendor_test.o
-OBJS_h += ../src/eap_server/eap_server_vendor_test.o
-endif
-CONFIG_IEEE8021X_EAPOL=y
-endif
-
-ifdef CONFIG_EAP_TNC
-# EAP-TNC
-CFLAGS += -DEAP_TNC
-OBJS += ../src/eap_peer/eap_tnc.o
-OBJS += ../src/eap_peer/tncc.o
-OBJS_h += ../src/eap_server/eap_server_tnc.o
-OBJS_h += ../src/eap_server/tncs.o
-NEED_BASE64=y
-ifndef CONFIG_NATIVE_WINDOWS
-ifndef CONFIG_DRIVER_BSD
-LIBS += -ldl
-endif
-endif
-endif
-
-ifdef CONFIG_IEEE8021X_EAPOL
-# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
-CFLAGS += -DIEEE8021X_EAPOL
-OBJS += ../src/eapol_supp/eapol_supp_sm.o
-OBJS += ../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o
-NEED_EAP_COMMON=y
-ifdef CONFIG_DYNAMIC_EAP_METHODS
-CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
-LIBS += -ldl -rdynamic
-endif
-endif
-
-ifdef CONFIG_AP
-NEED_80211_COMMON=y
-NEED_EAP_COMMON=y
-NEED_RSN_AUTHENTICATOR=y
-CFLAGS += -DCONFIG_AP
-OBJS += ap.o
-CFLAGS += -DCONFIG_NO_RADIUS
-CFLAGS += -DCONFIG_NO_ACCOUNTING
-CFLAGS += -DCONFIG_NO_VLAN
-OBJS += ../src/ap/hostapd.o
-OBJS += ../src/ap/wpa_auth_glue.o
-OBJS += ../src/ap/utils.o
-OBJS += ../src/ap/authsrv.o
-OBJS += ../src/ap/ap_config.o
-OBJS += ../src/utils/ip_addr.o
-OBJS += ../src/ap/sta_info.o
-OBJS += ../src/ap/tkip_countermeasures.o
-OBJS += ../src/ap/ap_mlme.o
-OBJS += ../src/ap/ieee802_1x.o
-OBJS += ../src/eapol_auth/eapol_auth_sm.o
-OBJS += ../src/ap/ieee802_11_auth.o
-OBJS += ../src/ap/drv_callbacks.o
-OBJS += ../src/ap/ap_drv_ops.o
-ifdef CONFIG_CTRL_IFACE
-OBJS += ../src/ap/ctrl_iface_ap.o
-endif
-
-CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
-OBJS += ../src/eap_server/eap_server.o
-OBJS += ../src/eap_server/eap_server_identity.o
-OBJS += ../src/eap_server/eap_server_methods.o
-
-ifdef CONFIG_IEEE80211N
-CFLAGS += -DCONFIG_IEEE80211N
-endif
-
-ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
-OBJS += ../src/ap/wmm.o
-OBJS += ../src/ap/ap_list.o
-OBJS += ../src/ap/ieee802_11.o
-OBJS += ../src/ap/hw_features.o
-ifdef CONFIG_IEEE80211N
-OBJS += ../src/ap/ieee802_11_ht.o
-endif
-CFLAGS += -DNEED_AP_MLME
-endif
-ifdef CONFIG_WPS
-CFLAGS += -DEAP_SERVER_WSC
-OBJS += ../src/ap/wps_hostapd.o
-OBJS += ../src/eap_server/eap_server_wsc.o
-endif
-endif
-
-ifdef NEED_RSN_AUTHENTICATOR
-CFLAGS += -DCONFIG_NO_RADIUS
-NEED_AES_WRAP=y
-OBJS += ../src/ap/wpa_auth.o
-OBJS += ../src/ap/wpa_auth_ie.o
-OBJS += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R
-OBJS += ../src/ap/wpa_auth_ft.o
-endif
-ifdef CONFIG_PEERKEY
-OBJS += ../src/ap/peerkey_auth.o
-endif
-endif
-
-ifdef CONFIG_EAP_SERVER
-CFLAGS += -DEAP_SERVER
-OBJS_h += ../src/eap_server/eap_server.o
-OBJS_h += ../src/eap_server/eap_server_identity.o
-OBJS_h += ../src/eap_server/eap_server_methods.o
-endif
-
-ifdef CONFIG_RADIUS_CLIENT
-OBJS_h += ../src/utils/ip_addr.o
-OBJS_h += ../src/radius/radius.o
-OBJS_h += ../src/radius/radius_client.o
-endif
-
-ifdef CONFIG_AUTHENTICATOR
-OBJS_h += ../src/eapol_auth/eapol_auth_sm.o
-OBJS_h += ../src/ap/ieee802_1x.o
-endif
-
-ifdef CONFIG_WPA_AUTHENTICATOR
-OBJS_h += ../src/ap/wpa_auth.o
-OBJS_h += ../src/ap/wpa_auth_ie.o
-OBJS_h += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R
-OBJS_h += ../src/ap/wpa_auth_ft.o
-endif
-ifdef CONFIG_PEERKEY
-OBJS_h += ../src/ap/peerkey_auth.o
-endif
-endif
-
-ifdef CONFIG_PCSC
-# PC/SC interface for smartcards (USIM, GSM SIM)
-CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
-OBJS += ../src/utils/pcsc_funcs.o
-# -lpthread may not be needed depending on how pcsc-lite was configured
-ifdef CONFIG_NATIVE_WINDOWS
-#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
-#dynamic symbol loading that is now used in pcsc_funcs.c
-#LIBS += -lwinscard
-else
-LIBS += -lpcsclite -lpthread
-endif
-endif
-
-ifdef CONFIG_SIM_SIMULATOR
-CFLAGS += -DCONFIG_SIM_SIMULATOR
-NEED_MILENAGE=y
-endif
-
-ifdef CONFIG_USIM_SIMULATOR
-CFLAGS += -DCONFIG_USIM_SIMULATOR
-NEED_MILENAGE=y
-endif
-
-ifdef NEED_MILENAGE
-OBJS += ../src/crypto/milenage.o
-endif
-
-ifdef CONFIG_PKCS12
-CFLAGS += -DPKCS12_FUNCS
-endif
-
-ifdef CONFIG_SMARTCARD
-CFLAGS += -DCONFIG_SMARTCARD
-endif
-
-ifdef MS_FUNCS
-OBJS += ../src/crypto/ms_funcs.o
-NEED_DES=y
-NEED_MD4=y
-endif
-
-ifdef CHAP
-OBJS += ../src/eap_common/chap.o
-endif
-
-ifdef TLS_FUNCS
-NEED_DES=y
-# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
-OBJS += ../src/eap_peer/eap_tls_common.o
-OBJS_h += ../src/eap_server/eap_server_tls_common.o
-NEED_TLS_PRF=y
-endif
-
-ifndef CONFIG_TLS
-CONFIG_TLS=openssl
-endif
-
-ifeq ($(CONFIG_TLS), openssl)
-ifdef TLS_FUNCS
-CFLAGS += -DEAP_TLS_OPENSSL
-OBJS += ../src/crypto/tls_openssl.o
-LIBS += -lssl
-endif
-OBJS += ../src/crypto/crypto_openssl.o
-OBJS_p += ../src/crypto/crypto_openssl.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_openssl.o
-endif
-LIBS += -lcrypto
-LIBS_p += -lcrypto
-endif
-
-ifeq ($(CONFIG_TLS), gnutls)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_gnutls.o
-LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
-endif
-OBJS += ../src/crypto/crypto_gnutls.o
-OBJS_p += ../src/crypto/crypto_gnutls.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_gnutls.o
-endif
-LIBS += -lgcrypt
-LIBS_p += -lgcrypt
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_schannel.o
-endif
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_cryptoapi.o
-endif
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-OBJS_p += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_nss.o
-endif
-LIBS += -lnss3
-LIBS_p += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
-ifeq ($(CONFIG_TLS), internal)
-ifndef CONFIG_CRYPTO
-CONFIG_CRYPTO=internal
-endif
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/crypto_internal-rsa.o
-OBJS += ../src/crypto/tls_internal.o
-OBJS += ../src/tls/tlsv1_common.o
-OBJS += ../src/tls/tlsv1_record.o
-OBJS += ../src/tls/tlsv1_cred.o
-OBJS += ../src/tls/tlsv1_client.o
-OBJS += ../src/tls/tlsv1_client_write.o
-OBJS += ../src/tls/tlsv1_client_read.o
-OBJS += ../src/tls/asn1.o
-OBJS += ../src/tls/rsa.o
-OBJS += ../src/tls/x509v3.o
-OBJS += ../src/tls/pkcs1.o
-OBJS += ../src/tls/pkcs5.o
-OBJS += ../src/tls/pkcs8.o
-NEED_SHA256=y
-NEED_BASE64=y
-NEED_TLS_PRF=y
-NEED_MODEXP=y
-NEED_CIPHER=y
-CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
-endif
-ifdef NEED_CIPHER
-NEED_DES=y
-OBJS += ../src/crypto/crypto_internal-cipher.o
-endif
-ifdef NEED_MODEXP
-OBJS += ../src/crypto/crypto_internal-modexp.o
-OBJS += ../src/tls/bignum.o
-endif
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS += ../src/crypto/crypto_libtomcrypt.o
-OBJS_p += ../src/crypto/crypto_libtomcrypt.o
-LIBS += -ltomcrypt -ltfm
-LIBS_p += -ltomcrypt -ltfm
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-ifeq ($(CONFIG_CRYPTO), internal)
-OBJS += ../src/crypto/crypto_internal.o
-OBJS_p += ../src/crypto/crypto_internal.o
-NEED_AES_ENC=y
-CFLAGS += -DCONFIG_CRYPTO_INTERNAL
-ifdef CONFIG_INTERNAL_LIBTOMMATH
-CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
-ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
-CFLAGS += -DLTM_FAST
-endif
-else
-LIBS += -ltommath
-LIBS_p += -ltommath
-endif
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_DES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_MD5=y
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-ifeq ($(CONFIG_CRYPTO), cryptoapi)
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-endif
-endif
-
-ifeq ($(CONFIG_TLS), none)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_none.o
-CFLAGS += -DEAP_TLS_NONE
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD5=y
-endif
-OBJS += ../src/crypto/crypto_none.o
-OBJS_p += ../src/crypto/crypto_none.o
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-endif
-
-ifdef TLS_FUNCS
-ifdef CONFIG_SMARTCARD
-ifndef CONFIG_NATIVE_WINDOWS
-ifneq ($(CONFIG_L2_PACKET), freebsd)
-LIBS += -ldl
-endif
-endif
-endif
-endif
-
-ifndef TLS_FUNCS
-OBJS += ../src/crypto/tls_none.o
-ifeq ($(CONFIG_TLS), internal)
-CONFIG_INTERNAL_AES=y
-CONFIG_INTERNAL_SHA1=y
-CONFIG_INTERNAL_MD5=y
-CONFIG_INTERNAL_RC4=y
-endif
-endif
-
-AESOBJS = # none so far (see below)
-ifdef CONFIG_INTERNAL_AES
-AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
-endif
-
-AESOBJS += ../src/crypto/aes-unwrap.o
-ifdef NEED_AES_EAX
-AESOBJS += ../src/crypto/aes-eax.o
-NEED_AES_CTR=y
-endif
-ifdef NEED_AES_CTR
-AESOBJS += ../src/crypto/aes-ctr.o
-endif
-ifdef NEED_AES_ENCBLOCK
-AESOBJS += ../src/crypto/aes-encblock.o
-endif
-ifdef NEED_AES_OMAC1
-NEED_AES_ENC=y
-AESOBJS += ../src/crypto/aes-omac1.o
-endif
-ifdef NEED_AES_WRAP
-NEED_AES_ENC=y
-AESOBJS += ../src/crypto/aes-wrap.o
-endif
-ifdef NEED_AES_CBC
-NEED_AES_ENC=y
-AESOBJS += ../src/crypto/aes-cbc.o
-endif
-ifdef NEED_AES_ENC
-ifdef CONFIG_INTERNAL_AES
-AESOBJS += ../src/crypto/aes-internal-enc.o
-endif
-endif
-ifdef NEED_AES
-OBJS += $(AESOBJS)
-endif
-
-ifdef NEED_SHA1
-SHA1OBJS += ../src/crypto/sha1.o
-ifdef CONFIG_INTERNAL_SHA1
-SHA1OBJS += ../src/crypto/sha1-internal.o
-ifdef NEED_FIPS186_2_PRF
-SHA1OBJS += ../src/crypto/fips_prf_internal.o
-endif
-endif
-ifndef CONFIG_NO_WPA_PASSPHRASE
-SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
-endif
-ifdef NEED_T_PRF
-SHA1OBJS += ../src/crypto/sha1-tprf.o
-endif
-ifdef NEED_TLS_PRF
-SHA1OBJS += ../src/crypto/sha1-tlsprf.o
-endif
-endif
-
-MD5OBJS = ../src/crypto/md5.o
-ifdef NEED_MD5
-ifdef CONFIG_INTERNAL_MD5
-MD5OBJS += ../src/crypto/md5-internal.o
-endif
-ifdef CONFIG_FIPS
-MD5OBJS += ../src/crypto/md5-non-fips.o
-endif
-OBJS += $(MD5OBJS)
-OBJS_p += $(MD5OBJS)
-endif
-
-ifdef NEED_MD4
-ifdef CONFIG_INTERNAL_MD4
-OBJS += ../src/crypto/md4-internal.o
-endif
-endif
-
-DESOBJS = # none needed when not internal
-ifdef NEED_DES
-ifdef CONFIG_INTERNAL_DES
-DESOBJS += ../src/crypto/des-internal.o
-endif
-endif
-
-ifdef NEED_RC4
-ifdef CONFIG_INTERNAL_RC4
-OBJS += ../src/crypto/rc4.o
-endif
-endif
-
-SHA256OBJS = # none by default
-ifdef NEED_SHA256
-CFLAGS += -DCONFIG_SHA256
-SHA256OBJS += ../src/crypto/sha256.o
-ifdef CONFIG_INTERNAL_SHA256
-SHA256OBJS += ../src/crypto/sha256-internal.o
-endif
-OBJS += $(SHA256OBJS)
-endif
-
-ifdef NEED_DH_GROUPS
-OBJS += ../src/crypto/dh_groups.o
-endif
-ifdef NEED_DH_GROUPS_ALL
-CFLAGS += -DALL_DH_GROUPS
-endif
-ifdef CONFIG_INTERNAL_DH_GROUP5
-ifdef NEED_DH_GROUPS
-OBJS += ../src/crypto/dh_group5.o
-endif
-endif
-
-ifdef CONFIG_CTRL_IFACE
-ifeq ($(CONFIG_CTRL_IFACE), y)
-ifdef CONFIG_NATIVE_WINDOWS
-CONFIG_CTRL_IFACE=named_pipe
-else
-CONFIG_CTRL_IFACE=unix
-endif
-endif
-CFLAGS += -DCONFIG_CTRL_IFACE
-ifeq ($(CONFIG_CTRL_IFACE), unix)
-CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
-endif
-ifeq ($(CONFIG_CTRL_IFACE), udp)
-CFLAGS += -DCONFIG_CTRL_IFACE_UDP
-endif
-ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
-CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
-endif
-OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
-endif
-
-ifdef CONFIG_CTRL_IFACE_DBUS
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
-DBUS_OBJS += dbus/dbus_old.o dbus/dbus_old_handlers.o
-ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_old_handlers_wps.o
-endif
-DBUS_OBJS += dbus/dbus_dict_helpers.o
-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_version=$(subst ., ,$(shell pkg-config --modversion dbus-1))
-DBUS_VERSION_MAJOR=$(word 1,$(dbus_version))
-DBUS_VERSION_MINOR=$(word 2,$(dbus_version))
-ifeq ($(DBUS_VERSION_MAJOR),)
-DBUS_VERSION_MAJOR=0
-endif
-ifeq ($(DBUS_VERSION_MINOR),)
-DBUS_VERSION_MINOR=0
-endif
-DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR)
-DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR)
-DBUS_CFLAGS += $(DBUS_INCLUDE)
-endif
-
-ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-DBUS=y
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-DBUS_OBJS ?= dbus/dbus_dict_helpers.o
-DBUS_OBJS += dbus/dbus_new_helpers.o
-DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
-ifdef CONFIG_WPS
-DBUS_OBJS += dbus/dbus_new_handlers_wps.o
-endif
-ifndef DBUS_LIBS
-DBUS_LIBS := $(shell pkg-config --libs dbus-1)
-endif
-ifndef DBUS_INCLUDE
-DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
-endif
-ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-DBUS_OBJS += dbus/dbus_new_introspect.o
-DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
-endif
-DBUS_CFLAGS += $(DBUS_INCLUDE)
-endif
-
-ifdef DBUS
-DBUS_CFLAGS += -DCONFIG_DBUS
-DBUS_OBJS += dbus/dbus_common.o
-endif
-
-OBJS += $(DBUS_OBJS)
-CFLAGS += $(DBUS_CFLAGS)
-LIBS += $(DBUS_LIBS)
-
-ifdef CONFIG_READLINE
-CFLAGS += -DCONFIG_READLINE
-LIBS_c += -lncurses -lreadline
-endif
-
-ifdef CONFIG_NATIVE_WINDOWS
-CFLAGS += -DCONFIG_NATIVE_WINDOWS
-LIBS += -lws2_32 -lgdi32 -lcrypt32
-LIBS_c += -lws2_32
-LIBS_p += -lws2_32 -lgdi32
-ifeq ($(CONFIG_CRYPTO), cryptoapi)
-LIBS_p += -lcrypt32
-endif
-endif
-
-ifdef CONFIG_NO_STDOUT_DEBUG
-CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
-ifndef CONFIG_CTRL_IFACE
-CFLAGS += -DCONFIG_NO_WPA_MSG
-endif
-endif
-
-ifdef CONFIG_IPV6
-# for eapol_test only
-CFLAGS += -DCONFIG_IPV6
-endif
-
-ifdef NEED_BASE64
-OBJS += ../src/utils/base64.o
-endif
-
-ifdef NEED_SME
-NEED_80211_COMMON=y
-OBJS += sme.o
-CFLAGS += -DCONFIG_SME
-endif
-
-ifdef CONFIG_CLIENT_MLME
-OBJS += mlme.o
-CFLAGS += -DCONFIG_CLIENT_MLME
-NEED_80211_COMMON=y
-endif
-
-ifdef NEED_80211_COMMON
-OBJS += ../src/common/ieee802_11_common.o
-endif
-
-ifdef NEED_EAP_COMMON
-OBJS += ../src/eap_common/eap_common.o
-endif
-
-ifndef CONFIG_MAIN
-CONFIG_MAIN=main
-endif
-
-ifdef CONFIG_DEBUG_SYSLOG
-CFLAGS += -DCONFIG_DEBUG_SYSLOG
-endif
-
-ifdef CONFIG_DEBUG_FILE
-CFLAGS += -DCONFIG_DEBUG_FILE
-endif
-
-ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
-CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
-endif
-
-ifdef CONFIG_FIPS
-CFLAGS += -DCONFIG_FIPS
-endif
-
-OBJS += $(SHA1OBJS) $(DESOBJS)
-
-OBJS_p += $(SHA1OBJS)
-
-ifdef CONFIG_BGSCAN_SIMPLE
-CFLAGS += -DCONFIG_BGSCAN_SIMPLE
-OBJS += bgscan_simple.o
-NEED_BGSCAN=y
-endif
-
-ifdef NEED_BGSCAN
-CFLAGS += -DCONFIG_BGSCAN
-OBJS += bgscan.o
-endif
-
-OBJS_wpa_rm := ctrl_iface.o mlme.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
-OBJS_t += ../src/radius/radius.o
-ifndef CONFIG_AP
-OBJS_t += ../src/utils/ip_addr.o
-endif
-OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
-OBJS += $(CONFIG_MAIN).o
-
-ifdef CONFIG_PRIVSEP
-OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o
-OBJS_priv += $(OBJS_l2)
-OBJS_priv += ../src/utils/os_$(CONFIG_OS).o
-OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o
-OBJS_priv += ../src/utils/common.o
-OBJS_priv += ../src/utils/wpa_debug.o
-OBJS_priv += ../src/utils/wpabuf.o
-OBJS_priv += wpa_priv.o
-ifdef CONFIG_DRIVER_TEST
-OBJS_priv += $(SHA1OBJS)
-OBJS_priv += $(MD5OBJS)
-ifeq ($(CONFIG_TLS), openssl)
-OBJS_priv += ../src/crypto/crypto_openssl.o
-endif
-ifeq ($(CONFIG_TLS), gnutls)
-OBJS_priv += ../src/crypto/crypto_gnutls.o
-endif
-ifeq ($(CONFIG_TLS), nss)
-OBJS_priv += ../src/crypto/crypto_nss.o
-endif
-ifeq ($(CONFIG_TLS), internal)
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS_priv += ../src/crypto/crypto_libtomcrypt.o
-else
-OBJS_priv += ../src/crypto/crypto_internal.o
-endif
-endif
-endif # CONFIG_DRIVER_TEST
-OBJS += ../src/l2_packet/l2_packet_privsep.o
-OBJS += ../src/drivers/driver_privsep.o
-EXTRA_progs += wpa_priv
-else
-OBJS += $(OBJS_d) ../src/drivers/drivers.o
-OBJS += $(OBJS_l2)
-endif
-
-ifdef CONFIG_NDIS_EVENTS_INTEGRATED
-CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
-OBJS += ../src/drivers/ndis_events.o
-EXTRALIBS += -loleaut32 -lole32 -luuid
-ifdef PLATFORMSDKLIB
-EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
-else
-EXTRALIBS += WbemUuid.Lib
-endif
-endif
-
-ifndef LDO
-LDO=$(CC)
-endif
-
-dynamic_eap_methods: $(EAPDYN)
-
-../src/drivers/build.wpa_supplicant:
-	@if [ -f ../src/drivers/build.hostapd ]; then \
-		$(MAKE) -C ../src/drivers clean; \
-	fi
-	@touch ../src/drivers/build.wpa_supplicant
-
-BCHECK=../src/drivers/build.wpa_supplicant
-
-wpa_priv: $(BCHECK) $(OBJS_priv)
-	$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
-
-wpa_supplicant: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
-	$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
-
-eapol_test: .config $(OBJS_t)
-	$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
-
-preauth_test: .config $(OBJS_t2) 
-	$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
-
-wpa_passphrase: $(OBJS_p)
-	$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
-
-wpa_cli: $(OBJS_c)
-	$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
-
-link_test: $(OBJS) $(OBJS_h) tests/link_test.o
-	$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
-
-test_wpa: $(OBJS_wpa) $(OBJS_h)
-	$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
-
-win_if_list: win_if_list.c
-	$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
-
-eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-		-Deap_peer_psk_register=eap_peer_method_dynamic_init
-
-eap_pax.so: ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-		-Deap_peer_pax_register=eap_peer_method_dynamic_init
-
-eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-		-Deap_peer_sake_register=eap_peer_method_dynamic_init
-
-eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-		-Deap_peer_wsc_register=eap_peer_method_dynamic_init
-
-eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-		-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
-
-%.so: %.c
-	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
-		-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-
-%.o: %.c
-	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
-	@$(E) "  CC " $<
-
-wpa_supplicant.exe: wpa_supplicant
-	mv -f $< $@
-wpa_cli.exe: wpa_cli
-	mv -f $< $@
-wpa_passphrase.exe: wpa_passphrase
-	mv -f $< $@
-win_if_list.exe: win_if_list
-	mv -f $< $@
-eapol_test.exe: eapol_test
-	mv -f $< $@
-
-WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
-
-windows-bin: $(WINALL)
-	$(STRIP) $(WINALL)
-
-wpa_gui/Makefile:
-	qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro 
-
-wpa_gui: wpa_gui/Makefile
-	$(MAKE) -C wpa_gui
-
-wpa_gui-qt4/Makefile:
-	qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro 
-
-wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts
-	lrelease wpa_gui-qt4/wpa_gui.pro
-
-wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm
-	$(MAKE) -C wpa_gui-qt4
-
-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
-
-clean:
-	$(MAKE) -C ../src clean
-	$(MAKE) -C dbus clean
-	rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
-	rm -f wpa_priv
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/wpa_supplicant/Makefile (from rev 9639, vendor/wpa/dist/wpa_supplicant/Makefile)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1630 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+export LIBDIR ?= /usr/local/lib/
+export BINDIR ?= /usr/local/sbin/
+PKG_CONFIG ?= pkg-config
+
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+-include .config
+
+BINALL=wpa_supplicant wpa_cli
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+BINALL += wpa_passphrase
+endif
+
+ALL = $(BINALL)
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant at .service
+ALL += systemd/wpa_supplicant-nl80211 at .service
+ALL += systemd/wpa_supplicant-wired at .service
+ALL += dbus/fi.epitest.hostap.WPASupplicant.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+
+
+all: verify_config $(ALL) dynamic_eap_methods
+
+verify_config:
+	@if [ ! -r .config ]; then \
+		echo 'Building wpa_supplicant requires a configuration file'; \
+		echo '(.config). See README for more instructions. You can'; \
+		echo 'run "cp defconfig .config" to create an example'; \
+		echo 'configuration.'; \
+		exit 1; \
+	fi
+
+mkconfig:
+	@if [ -f .config ]; then \
+		echo '.config exists - did not replace it'; \
+		exit 1; \
+	fi
+	echo CONFIG_DRIVER_HOSTAP=y >> .config
+	echo CONFIG_DRIVER_WEXT=y >> .config
+
+$(DESTDIR)$(BINDIR)/%: %
+	install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
+	$(MAKE) -C ../src install
+
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
+OBJS = config.o
+OBJS += notify.o
+OBJS += bss.o
+OBJS += eap_register.o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS_p = wpa_passphrase.o
+OBJS_p += ../src/utils/common.o
+OBJS_p += ../src/utils/wpa_debug.o
+OBJS_p += ../src/utils/wpabuf.o
+OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/common.o
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS_p += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+OBJS_p += ../src/utils/trace.o
+OBJS_c += ../src/utils/trace.o
+OBJS_priv += ../src/utils/trace.o
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_p += -lbfd
+LIBS_c += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+
+ifdef CONFIG_ELOOP_POLL
+CFLAGS += -DCONFIG_ELOOP_POLL
+endif
+
+
+ifdef CONFIG_EAPOL_TEST
+CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifdef CONFIG_HT_OVERRIDES
+CFLAGS += -DCONFIG_HT_OVERRIDES
+endif
+
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.o
+ifndef CONFIG_NO_CONFIG_BLOBS
+NEED_BASE64=y
+endif
+CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.o
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.o
+endif
+
+ifdef CONFIG_NO_CONFIG_WRITE
+CFLAGS += -DCONFIG_NO_CONFIG_WRITE
+endif
+
+ifdef CONFIG_NO_CONFIG_BLOBS
+CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
+endif
+
+ifdef CONFIG_NO_SCAN_PROCESSING
+CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/rsn_supp/wpa_ft.o
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += wnm_sta.o
+endif
+
+ifdef CONFIG_TDLS
+CFLAGS += -DCONFIG_TDLS
+OBJS += ../src/rsn_supp/tdls.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_TDLS_TESTING
+CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += ../src/rsn_supp/wpa.o
+OBJS += ../src/rsn_supp/preauth.o
+OBJS += ../src/rsn_supp/pmksa_cache.o
+OBJS += ../src/rsn_supp/peerkey.o
+OBJS += ../src/rsn_supp/wpa_ie.o
+OBJS += ../src/common/wpa_common.o
+NEED_AES=y
+NEED_SHA1=y
+NEED_MD5=y
+NEED_RC4=y
+else
+CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_IBSS_RSN
+NEED_RSN_AUTHENTICATOR=y
+CFLAGS += -DCONFIG_IBSS_RSN
+OBJS += ibss_rsn.o
+endif
+
+ifdef CONFIG_P2P
+OBJS += p2p_supplicant.o
+OBJS += ../src/p2p/p2p.o
+OBJS += ../src/p2p/p2p_utils.o
+OBJS += ../src/p2p/p2p_parse.o
+OBJS += ../src/p2p/p2p_build.o
+OBJS += ../src/p2p/p2p_go_neg.o
+OBJS += ../src/p2p/p2p_sd.o
+OBJS += ../src/p2p/p2p_pd.o
+OBJS += ../src/p2p/p2p_invitation.o
+OBJS += ../src/p2p/p2p_dev_disc.o
+OBJS += ../src/p2p/p2p_group.o
+OBJS += ../src/ap/p2p_hostapd.o
+CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
+NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
+ifdef CONFIG_P2P_STRICT
+CFLAGS += -DCONFIG_P2P_STRICT
+endif
+endif
+
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.o
+CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.o
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
+ifdef CONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA2
+endif
+
+include ../src/drivers/drivers.mak
+ifdef CONFIG_AP
+OBJS_d += $(DRV_BOTH_OBJS)
+CFLAGS += $(DRV_BOTH_CFLAGS)
+LDFLAGS += $(DRV_BOTH_LDFLAGS)
+LIBS += $(DRV_BOTH_LIBS)
+else
+NEED_AP_MLME=
+OBJS_d += $(DRV_WPA_OBJS)
+CFLAGS += $(DRV_WPA_CFLAGS)
+LDFLAGS += $(DRV_WPA_LDFLAGS)
+LIBS += $(DRV_WPA_LIBS)
+endif
+
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
+ifdef CONFIG_WINPCAP
+CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_tls.so
+else
+CFLAGS += -DEAP_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_server_tls.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_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
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_peap.so
+else
+CFLAGS += -DEAP_PEAP
+OBJS += ../src/eap_peer/eap_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+OBJS_h += ../src/eap_server/eap_server_peap.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_ttls.so
+else
+CFLAGS += -DEAP_TTLS
+OBJS += ../src/eap_peer/eap_ttls.o
+OBJS_h += ../src/eap_server/eap_server_ttls.o
+endif
+MS_FUNCS=y
+TLS_FUNCS=y
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_md5.so
+else
+CFLAGS += -DEAP_MD5
+OBJS += ../src/eap_peer/eap_md5.o
+OBJS_h += ../src/eap_server/eap_server_md5.o
+endif
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_mschapv2.so
+EAPDYN += ../src/eap_peer/mschapv2.so
+else
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += ../src/eap_peer/eap_mschapv2.o
+OBJS += ../src/eap_peer/mschapv2.o
+OBJS_h += ../src/eap_server/eap_server_mschapv2.o
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_gtc.so
+else
+CFLAGS += -DEAP_GTC
+OBJS += ../src/eap_peer/eap_gtc.o
+OBJS_h += ../src/eap_server/eap_server_gtc.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_otp.so
+else
+CFLAGS += -DEAP_OTP
+OBJS += ../src/eap_peer/eap_otp.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_sim.so
+else
+CFLAGS += -DEAP_SIM
+OBJS += ../src/eap_peer/eap_sim.o
+OBJS_h += ../src/eap_server/eap_server_sim.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_leap.so
+else
+CFLAGS += -DEAP_LEAP
+OBJS += ../src/eap_peer/eap_leap.o
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+ifeq ($(CONFIG_EAP_PSK), dyn)
+CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_psk.so
+else
+CFLAGS += -DEAP_PSK
+OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o
+OBJS_h += ../src/eap_server/eap_server_psk.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_aka.so
+else
+CFLAGS += -DEAP_AKA
+OBJS += ../src/eap_peer/eap_aka.o
+OBJS_h += ../src/eap_server/eap_server_aka.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+CFLAGS += -DEAP_AKA_PRIME
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+OBJS_h += ../src/eap_server/eap_sim_db.o
+NEED_AES=y
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+ifeq ($(CONFIG_EAP_FAST), dyn)
+CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_fast.so
+EAPDYN += ../src/eap_common/eap_fast_common.o
+else
+CFLAGS += -DEAP_FAST
+OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS += ../src/eap_common/eap_fast_common.o
+OBJS_h += ../src/eap_server/eap_server_fast.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+ifeq ($(CONFIG_EAP_PAX), dyn)
+CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_pax.so
+else
+CFLAGS += -DEAP_PAX
+OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o
+OBJS_h += ../src/eap_server/eap_server_pax.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_sake.so
+else
+CFLAGS += -DEAP_SAKE
+OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o
+OBJS_h += ../src/eap_server/eap_server_sake.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_gpsk.so
+else
+CFLAGS += -DEAP_GPSK
+OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
+OBJS_h += ../src/eap_server/eap_server_gpsk.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_PWD
+OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
+OBJS_h += ../src/eap_server/eap_pwd.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
+# EAP-WSC
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.o
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+OBJS_h += ../src/eap_server/eap_server_wsc.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_80211_COMMON=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_ER
+CONFIG_WPS_UPNP=y
+CFLAGS += -DCONFIG_WPS_ER
+OBJS += ../src/wps/wps_er.o
+OBJS += ../src/wps/wps_er_ssdp.o
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+ifdef CONFIG_WPS_REG_DISABLE_OPEN
+CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+# EAP-IKEv2
+ifeq ($(CONFIG_EAP_IKEV2), dyn)
+CFLAGS += -DEAP_IKEV2_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_ikev2.so ../src/eap_peer/ikev2.o
+EAPDYN += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+else
+CFLAGS += -DEAP_IKEV2
+OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+OBJS_h += ../src/eap_server/eap_server_ikev2.o
+OBJS_h += ../src/eap_server/ikev2.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_vendor_test.so
+else
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += ../src/eap_peer/eap_vendor_test.o
+OBJS_h += ../src/eap_server/eap_server_vendor_test.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+# EAP-TNC
+CFLAGS += -DEAP_TNC
+OBJS += ../src/eap_peer/eap_tnc.o
+OBJS += ../src/eap_peer/tncc.o
+OBJS_h += ../src/eap_server/eap_server_tnc.o
+OBJS_h += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+CFLAGS += -DIEEE8021X_EAPOL
+OBJS += ../src/eapol_supp/eapol_supp_sm.o
+OBJS += ../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o
+NEED_EAP_COMMON=y
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
+endif
+
+ifdef CONFIG_AP
+NEED_80211_COMMON=y
+NEED_EAP_COMMON=y
+NEED_RSN_AUTHENTICATOR=y
+CFLAGS += -DCONFIG_AP
+OBJS += ap.o
+CFLAGS += -DCONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_VLAN
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
+ifdef CONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
+ifdef CONFIG_CTRL_IFACE
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_server/eap_server_identity.o
+OBJS += ../src/eap_server/eap_server_methods.o
+
+ifdef CONFIG_IEEE80211N
+CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_WPS
+CFLAGS += -DEAP_SERVER_WSC
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o
+endif
+ifdef CONFIG_INTERWORKING
+OBJS += ../src/ap/gas_serv.o
+endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
+endif
+
+ifdef NEED_RSN_AUTHENTICATOR
+CFLAGS += -DCONFIG_NO_RADIUS
+NEED_AES_WRAP=y
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+ifdef CONFIG_IEEE80211R
+OBJS += ../src/ap/wpa_auth_ft.o
+endif
+ifdef CONFIG_PEERKEY
+OBJS += ../src/ap/peerkey_auth.o
+endif
+endif
+
+ifdef CONFIG_EAP_SERVER
+CFLAGS += -DEAP_SERVER
+OBJS_h += ../src/eap_server/eap_server.o
+OBJS_h += ../src/eap_server/eap_server_identity.o
+OBJS_h += ../src/eap_server/eap_server_methods.o
+endif
+
+ifdef CONFIG_RADIUS_CLIENT
+OBJS_h += ../src/utils/ip_addr.o
+OBJS_h += ../src/radius/radius.o
+OBJS_h += ../src/radius/radius_client.o
+endif
+
+ifdef CONFIG_AUTHENTICATOR
+OBJS_h += ../src/eapol_auth/eapol_auth_sm.o
+OBJS_h += ../src/ap/ieee802_1x.o
+endif
+
+ifdef CONFIG_WPA_AUTHENTICATOR
+OBJS_h += ../src/ap/wpa_auth.o
+OBJS_h += ../src/ap/wpa_auth_ie.o
+OBJS_h += ../src/ap/pmksa_cache_auth.o
+ifdef CONFIG_IEEE80211R
+OBJS_h += ../src/ap/wpa_auth_ft.o
+endif
+ifdef CONFIG_PEERKEY
+OBJS_h += ../src/ap/peerkey_auth.o
+endif
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += ../src/utils/pcsc_funcs.o
+# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
+LIBS += -lpcsclite -lpthread
+endif
+endif
+
+ifdef CONFIG_SIM_SIMULATOR
+CFLAGS += -DCONFIG_SIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef CONFIG_USIM_SIMULATOR
+CFLAGS += -DCONFIG_USIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef NEED_MILENAGE
+OBJS += ../src/crypto/milenage.o
+NEED_AES_ENCBLOCK=y
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef CONFIG_SMARTCARD
+CFLAGS += -DCONFIG_SMARTCARD
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, 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
+NEED_MD5=y
+endif
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+OBJS_p += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_gnutls.o
+OBJS_p += ../src/crypto/crypto_gnutls.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_gnutls.o
+endif
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_schannel.o
+endif
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_cryptoapi.o
+endif
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_nss.o
+LIBS += -lssl3
+endif
+OBJS += ../src/crypto/crypto_nss.o
+OBJS_p += ../src/crypto/crypto_nss.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_nss.o
+endif
+LIBS += -lnss3
+LIBS_p += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o
+OBJS += ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/asn1.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+OBJS_p += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+OBJS_p += ../src/crypto/crypto_internal.o
+NEED_AES_ENC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifdef TLS_FUNCS
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifneq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -ldl
+endif
+endif
+endif
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far (see below)
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
+endif
+
+AESOBJS += ../src/crypto/aes-unwrap.o
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+ifdef NEED_AES_OMAC1
+NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+endif
+ifdef NEED_AES_WRAP
+NEED_AES_ENC=y
+AESOBJS += ../src/crypto/aes-wrap.o
+endif
+ifdef NEED_AES_CBC
+NEED_AES_ENC=y
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+ifdef NEED_AES_ENC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-enc.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+else
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+MD5OBJS += ../src/crypto/md5-internal.o
+endif
+OBJS += $(MD5OBJS)
+OBJS_p += $(MD5OBJS)
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+DESOBJS = # none needed when not internal
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+DESOBJS += ../src/crypto/des-internal.o
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += ../src/crypto/rc4.o
+endif
+endif
+
+SHA256OBJS = # none by default
+ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+SHA256OBJS += ../src/crypto/sha256.o
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
+ifdef CONFIG_INTERNAL_SHA256
+SHA256OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+OBJS += $(SHA256OBJS)
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+endif
+
+ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
+CFLAGS += -DCONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
+OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS
+DBUS=y
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
+DBUS_OBJS += dbus/dbus_old.o dbus/dbus_old_handlers.o
+ifdef CONFIG_WPS
+DBUS_OBJS += dbus/dbus_old_handlers_wps.o
+endif
+DBUS_OBJS += dbus/dbus_dict_helpers.o
+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
+
+ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+DBUS=y
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+DBUS_OBJS ?= dbus/dbus_dict_helpers.o
+DBUS_OBJS += dbus/dbus_new_helpers.o
+DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o
+ifdef CONFIG_WPS
+DBUS_OBJS += dbus/dbus_new_handlers_wps.o
+endif
+ifdef CONFIG_P2P
+DBUS_OBJS += dbus/dbus_new_handlers_p2p.o
+endif
+ifndef DBUS_LIBS
+DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
+endif
+ifndef DBUS_INCLUDE
+DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
+endif
+ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+DBUS_OBJS += dbus/dbus_new_introspect.o
+DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+endif
+DBUS_CFLAGS += $(DBUS_INCLUDE)
+endif
+
+ifdef DBUS
+DBUS_CFLAGS += -DCONFIG_DBUS
+DBUS_OBJS += dbus/dbus_common.o
+endif
+
+OBJS += $(DBUS_OBJS)
+CFLAGS += $(DBUS_CFLAGS)
+LIBS += $(DBUS_LIBS)
+
+ifdef CONFIG_READLINE
+OBJS_c += ../src/utils/edit_readline.o
+LIBS_c += -lncurses -lreadline
+else
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32 -lgdi32 -lcrypt32
+LIBS_c += -lws2_32
+LIBS_p += -lws2_32 -lgdi32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef NEED_SME
+NEED_80211_COMMON=y
+OBJS += sme.o
+CFLAGS += -DCONFIG_SME
+endif
+
+ifdef NEED_80211_COMMON
+OBJS += ../src/common/ieee802_11_common.o
+endif
+
+ifdef NEED_EAP_COMMON
+OBJS += ../src/eap_common/eap_common.o
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+CFLAGS += -DCONFIG_DEBUG_SYSLOG
+ifdef CONFIG_DEBUG_SYSLOG_FACILITY
+CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)"
+endif
+endif
+
+ifdef CONFIG_DEBUG_LINUX_TRACING
+CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
+endif
+
+ifdef CONFIG_FIPS
+CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
+endif
+
+OBJS += $(SHA1OBJS) $(DESOBJS)
+
+OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
+
+ifdef CONFIG_BGSCAN_SIMPLE
+CFLAGS += -DCONFIG_BGSCAN_SIMPLE
+OBJS += bgscan_simple.o
+NEED_BGSCAN=y
+endif
+
+ifdef CONFIG_BGSCAN_LEARN
+CFLAGS += -DCONFIG_BGSCAN_LEARN
+OBJS += bgscan_learn.o
+NEED_BGSCAN=y
+endif
+
+ifdef NEED_BGSCAN
+CFLAGS += -DCONFIG_BGSCAN
+OBJS += bgscan.o
+endif
+
+ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL
+OBJS += autoscan_exponential.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef CONFIG_AUTOSCAN_PERIODIC
+CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC
+OBJS += autoscan_periodic.o
+NEED_AUTOSCAN=y
+endif
+
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += gas_query.o
+CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.o
+CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += ../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
+OBJS_t += ../src/radius/radius.o
+ifndef CONFIG_AP
+OBJS_t += ../src/utils/ip_addr.o
+endif
+OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+
+OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
+OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o
+
+OBJS += $(CONFIG_MAIN).o
+
+ifdef CONFIG_PRIVSEP
+OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o
+OBJS_priv += $(OBJS_l2)
+OBJS_priv += ../src/utils/os_$(CONFIG_OS).o
+OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_priv += ../src/utils/common.o
+OBJS_priv += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/wpabuf.o
+OBJS_priv += wpa_priv.o
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += ../src/common/ieee802_11_common.o
+endif
+ifdef CONFIG_DRIVER_TEST
+OBJS_priv += $(SHA1OBJS)
+OBJS_priv += $(MD5OBJS)
+ifeq ($(CONFIG_TLS), openssl)
+OBJS_priv += ../src/crypto/crypto_openssl.o
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS_priv += ../src/crypto/crypto_gnutls.o
+endif
+ifeq ($(CONFIG_TLS), nss)
+OBJS_priv += ../src/crypto/crypto_nss.o
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS_priv += ../src/crypto/crypto_libtomcrypt.o
+else
+OBJS_priv += ../src/crypto/crypto_internal.o
+endif
+endif
+endif # CONFIG_DRIVER_TEST
+OBJS += ../src/l2_packet/l2_packet_privsep.o
+OBJS += ../src/drivers/driver_privsep.o
+EXTRA_progs += wpa_priv
+else
+OBJS += $(OBJS_d) ../src/drivers/drivers.o
+OBJS += $(OBJS_l2)
+endif
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += ../src/drivers/ndis_events.o
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+dynamic_eap_methods: $(EAPDYN)
+
+../src/drivers/build.wpa_supplicant:
+	@if [ -f ../src/drivers/build.hostapd ]; then \
+		$(MAKE) -C ../src/drivers clean; \
+	fi
+	@touch ../src/drivers/build.wpa_supplicant
+
+BCHECK=../src/drivers/build.wpa_supplicant
+
+wpa_priv: $(BCHECK) $(OBJS_priv)
+	$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+	@$(E) "  LD " $@
+
+$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
+
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
+	$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+	@$(E) "  LD " $@
+
+eapol_test: $(OBJS_t)
+	$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+	@$(E) "  LD " $@
+
+preauth_test: $(OBJS_t2)
+	$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+	@$(E) "  LD " $@
+
+wpa_passphrase: $(OBJS_p)
+	$(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+	@$(E) "  LD " $@
+
+wpa_cli: $(OBJS_c)
+	$(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+	@$(E) "  LD " $@
+
+link_test: $(OBJS) $(OBJS_h) tests/link_test.o
+	$(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+	@$(E) "  LD " $@
+
+test_wpa: $(OBJS_wpa) $(OBJS_h)
+	$(Q)$(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+	@$(E) "  LD " $@
+
+nfc_pw_token: $(OBJS_nfc)
+	$(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS)
+	@$(E) "  LD " $@
+
+win_if_list: win_if_list.c
+	$(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+	@$(E) "  LD " $@
+
+eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_psk_register=eap_peer_method_dynamic_init
+
+eap_pax.so: ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_pax_register=eap_peer_method_dynamic_init
+
+eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_sake_register=eap_peer_method_dynamic_init
+
+eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_wsc_register=eap_peer_method_dynamic_init
+
+eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
+
+%.so: %.c
+	$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
+		-D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+%.service: %.service.in
+	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
+%@.service: %.service.arg.in
+	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
+wpa_supplicant.exe: wpa_supplicant
+	mv -f $< $@
+wpa_cli.exe: wpa_cli
+	mv -f $< $@
+wpa_passphrase.exe: wpa_passphrase
+	mv -f $< $@
+win_if_list.exe: win_if_list
+	mv -f $< $@
+eapol_test.exe: eapol_test
+	mv -f $< $@
+
+WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
+
+windows-bin: $(WINALL)
+	$(STRIP) $(WINALL)
+
+wpa_gui:
+	@echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
+
+wpa_gui-qt4/Makefile:
+	qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro 
+
+wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts
+	lrelease wpa_gui-qt4/wpa_gui.pro
+
+wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm
+	$(MAKE) -C wpa_gui-qt4
+
+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:
+	$(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
+clean:
+	$(MAKE) -C ../src clean
+	$(MAKE) -C dbus clean
+	rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+	rm -f wpa_priv
+	rm -f nfc_pw_token
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/wpa_supplicant/README
===================================================================
--- vendor/wpa/dist/wpa_supplicant/README	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1032 +0,0 @@
-WPA Supplicant
-==============
-
-Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi> and contributors
-All Rights Reserved.
-
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-
-
-License
--------
-
-GPL v2:
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License version 2 as
-published by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-
-(this copy of the license is in COPYING file)
-
-
-Alternatively, this software may be distributed, used, and modified
-under the terms of BSD license:
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name(s) of the above-listed copyright holder(s) nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-Features
---------
-
-Supported WPA/IEEE 802.11i features:
-- WPA-PSK ("WPA-Personal")
-- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
-  Following authentication methods are supported with an integrate IEEE 802.1X
-  Supplicant:
-  * EAP-TLS
-  * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
-  * EAP-TTLS/EAP-MD5-Challenge
-  * EAP-TTLS/EAP-GTC
-  * EAP-TTLS/EAP-OTP
-  * EAP-TTLS/EAP-MSCHAPv2
-  * EAP-TTLS/EAP-TLS
-  * EAP-TTLS/MSCHAPv2
-  * EAP-TTLS/MSCHAP
-  * EAP-TTLS/PAP
-  * EAP-TTLS/CHAP
-  * EAP-SIM
-  * EAP-AKA
-  * EAP-PSK
-  * EAP-PAX
-  * EAP-SAKE
-  * EAP-IKEv2
-  * EAP-GPSK
-  * LEAP (note: requires special support from the driver for IEEE 802.11
-	  authentication)
-  (following methods are supported, but since they do not generate keying
-   material, they cannot be used with WPA or IEEE 802.1X WEP keying)
-  * EAP-MD5-Challenge 
-  * EAP-MSCHAPv2
-  * EAP-GTC
-  * EAP-OTP
-- key management for CCMP, TKIP, WEP104, WEP40
-- RSN/WPA2 (IEEE 802.11i)
-  * pre-authentication
-  * PMKSA caching
-
-Supported TLS/crypto libraries:
-- OpenSSL (default)
-- GnuTLS
-
-Internal TLS/crypto implementation (optional):
-- can be used in place of an external TLS/crypto library
-- TLSv1
-- X.509 certificate processing
-- PKCS #1
-- ASN.1
-- RSA
-- bignum
-- minimal size (ca. 50 kB binary, parts of which are already needed for WPA;
-  TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86)
-
-
-Requirements
-------------
-
-Current hardware/software requirements:
-- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer
-- FreeBSD 6-CURRENT
-- NetBSD-current
-- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
-- drivers:
-	Linux drivers that support WPA/WPA2 configuration with the generic
-	Linux wireless extensions (WE-18 or newer). Even though there are
-	number of driver specific interface included in wpa_supplicant, please
-	note that Linux drivers are moving to use generic wireless extensions
-	and driver_wext (-Dwext on wpa_supplicant command line) should be the
-	default option to start with before falling back to driver specific
-	interface.
-
-	Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
-	(http://hostap.epitest.fi/)
-	Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
-	Please note that station firmware version needs to be 1.7.0 or newer
-	to work in WPA mode.
-
-	Linuxant DriverLoader (http://www.linuxant.com/driverloader/)
-	with Windows NDIS driver for your wlan card supporting WPA.
-
-	Agere Systems Inc. Linux Driver
-	(http://www.agere.com/support/drivers/)
-	Please note that the driver interface file (driver_hermes.c) and
-	hardware specific include files are not included in the
-	wpa_supplicant distribution. You will need to copy these from the
-	source package of the Agere driver.
-
-	madwifi driver for cards based on Atheros chip set (ar521x)
-	(http://sourceforge.net/projects/madwifi/)
-	Please note that you will need to modify the wpa_supplicant .config
-	file to use the correct path for the madwifi driver root directory
-	(CFLAGS += -I../madwifi/wpa line in example defconfig).
-
-	ATMEL AT76C5XXx driver for USB and PCMCIA cards
-	(http://atmelwlandriver.sourceforge.net/).
-
-	Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
-	Windows NDIS driver.
-
-	Broadcom wl.o driver (old version only)
-	This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
-	However, it is proprietary driver that is not publicly available
-	except for couple of exceptions, mainly Broadcom-based APs/wireless
-	routers that use Linux. The driver binary can be downloaded, e.g.,
-	from Linksys support site (http://www.linksys.com/support/gpl.asp)
-	for Linksys WRT54G. The GPL tarball includes cross-compiler and
-	the needed header file, wlioctl.h, for compiling wpa_supplicant.
-	This driver support in wpa_supplicant is expected to work also with
-	other devices based on Broadcom driver (assuming the driver includes
-	client mode support). Please note that the newer Broadcom driver
-	("hybrid Linux driver") supports Linux wireless extensions and does
-	not need (or even work) with the specific driver wrapper. Use -Dwext
-	with that driver.
-
-	Intel ipw2100 driver
-	(http://sourceforge.net/projects/ipw2100/)
-
-	Intel ipw2200 driver
-	(http://sourceforge.net/projects/ipw2200/)
-
-	In theory, any driver that supports Linux wireless extensions can be
-	used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
-	configuration file.
-
-	Wired Ethernet drivers (with ap_scan=0)
-
-	BSD net80211 layer (e.g., Atheros driver)
-	At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current.
-
-	Windows NDIS
-	The current Windows port requires WinPcap (http://winpcap.polito.it/).
-	See README-Windows.txt for more information.
-
-wpa_supplicant was designed to be portable for different drivers and
-operating systems. Hopefully, support for more wlan cards and OSes will be
-added in the future. See developer's documentation
-(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the
-design of wpa_supplicant and porting to other drivers. One main goal
-is to add full WPA/WPA2 support to Linux wireless extensions to allow
-new drivers to be supported without having to implement new
-driver-specific interface code in wpa_supplicant.
-
-Optional libraries for layer2 packet processing:
-- libpcap (tested with 0.7.2, most relatively recent versions assumed to work,
-	this is likely to be available with most distributions,
-	http://tcpdump.org/)
-- libdnet (tested with v1.4, most versions assumed to work,
-	http://libdnet.sourceforge.net/)
-
-These libraries are _not_ used in the default Linux build. Instead,
-internal Linux specific implementation is used. libpcap/libdnet are
-more portable and they can be used by adding CONFIG_L2_PACKET=pcap into
-.config. They may also be selected automatically for other operating
-systems. In case of Windows builds, WinPcap is used by default
-(CONFIG_L2_PACKET=winpcap).
-
-
-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
-  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
-needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5,
-EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so
-they should only be enabled if testing the EAPOL/EAP state
-machines. However, there can be used as inner authentication
-algorithms with EAP-PEAP and EAP-TTLS.
-
-See Building and installing section below for more detailed
-information about the wpa_supplicant build time configuration.
-
-
-
-WPA
----
-
-The original security mechanism of IEEE 802.11 standard was not
-designed to be strong and has proven to be insufficient for most
-networks that require some kind of security. Task group I (Security)
-of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
-to address the flaws of the base standard and has in practice
-completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
-802.11 standard was approved in June 2004 and published in July 2004.
-
-Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
-IEEE 802.11i work (draft 3.0) to define a subset of the security
-enhancements that can be implemented with existing wlan hardware. This
-is called Wi-Fi Protected Access<TM> (WPA). This has now become a
-mandatory component of interoperability testing and certification done
-by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
-site (http://www.wi-fi.org/OpenSection/protected_access.asp).
-
-IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
-for protecting wireless networks. WEP uses RC4 with 40-bit keys,
-24-bit initialization vector (IV), and CRC32 to protect against packet
-forgery. All these choices have proven to be insufficient: key space is
-too small against current attacks, RC4 key scheduling is insufficient
-(beginning of the pseudorandom stream should be skipped), IV space is
-too small and IV reuse makes attacks easier, there is no replay
-protection, and non-keyed authentication does not protect against bit
-flipping packet data.
-
-WPA is an intermediate solution for the security issues. It uses
-Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
-compromise on strong security and possibility to use existing
-hardware. It still uses RC4 for the encryption like WEP, but with
-per-packet RC4 keys. In addition, it implements replay protection,
-keyed packet authentication mechanism (Michael MIC).
-
-Keys can be managed using two different mechanisms. WPA can either use
-an external authentication server (e.g., RADIUS) and EAP just like
-IEEE 802.1X is using or pre-shared keys without need for additional
-servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
-respectively. Both mechanisms will generate a master session key for
-the Authenticator (AP) and Supplicant (client station).
-
-WPA implements a new key handshake (4-Way Handshake and Group Key
-Handshake) for generating and exchanging data encryption keys between
-the Authenticator and Supplicant. This handshake is also used to
-verify that both Authenticator and Supplicant know the master session
-key. These handshakes are identical regardless of the selected key
-management mechanism (only the method for generating master session
-key changes).
-
-
-
-IEEE 802.11i / WPA2
--------------------
-
-The design for parts of IEEE 802.11i that were not included in WPA has
-finished (May 2004) and this amendment to IEEE 802.11 was approved in
-June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
-version of WPA called WPA2. This includes, e.g., support for more
-robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
-to replace TKIP and optimizations for handoff (reduced number of
-messages in initial key handshake, pre-authentication, and PMKSA caching).
-
-
-
-wpa_supplicant
---------------
-
-wpa_supplicant is an implementation of the WPA Supplicant component,
-i.e., the part that runs in the client stations. It implements WPA key
-negotiation with a WPA Authenticator and EAP authentication with
-Authentication Server. In addition, it controls the roaming and IEEE
-802.11 authentication/association of the wlan driver.
-
-wpa_supplicant is designed to be a "daemon" program that runs in the
-background and acts as the backend component controlling the wireless
-connection. wpa_supplicant supports separate frontend programs and an
-example text-based frontend, wpa_cli, is included with wpa_supplicant.
-
-Following steps are used when associating with an AP using WPA:
-
-- wpa_supplicant requests the kernel driver to scan neighboring BSSes
-- wpa_supplicant selects a BSS based on its configuration
-- wpa_supplicant requests the kernel driver to associate with the chosen
-  BSS
-- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP
-  authentication with the authentication server (proxied by the
-  Authenticator in the AP)
-- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
-- If WPA-PSK: wpa_supplicant uses PSK as the master session key
-- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
-  with the Authenticator (AP)
-- wpa_supplicant configures encryption keys for unicast and broadcast
-- normal data packets can be transmitted and received
-
-
-
-Building and installing
------------------------
-
-In order to be able to build wpa_supplicant, you will first need to
-select which parts of it will be included. This is done by creating a
-build time configuration file, .config, in the wpa_supplicant root
-directory. Configuration options are text lines using following
-format: CONFIG_<option>=y. Lines starting with # are considered
-comments and are ignored. See defconfig file for an example configuration
-and a list of available options and additional notes.
-
-The build time configuration can be used to select only the needed
-features and limit the binary size and requirements for external
-libraries. The main configuration parts are the selection of which
-driver interfaces (e.g., hostap, madwifi, ..) and which authentication
-methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
-
-Following build time configuration options are used to control IEEE
-802.1X/EAPOL and EAP state machines and all EAP methods. Including
-TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
-library for TLS implementation. Alternatively, GnuTLS or the internal
-TLSv1 implementation can be used for TLS functionaly.
-
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_MD5=y
-CONFIG_EAP_MSCHAPV2=y
-CONFIG_EAP_TLS=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_OTP=y
-CONFIG_EAP_SIM=y
-CONFIG_EAP_AKA=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
-
-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
-(http://www.linuxnet.com/) for smart card access.
-
-CONFIG_PCSC=y
-
-Following options can be added to .config to select which driver
-interfaces are included. Hermes driver interface needs to be downloaded
-from Agere (see above).
-
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
-CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_RALINK=y
-CONFIG_DRIVER_NDISWRAPPER=y
-CONFIG_DRIVER_BROADCOM=y
-CONFIG_DRIVER_IPW=y
-CONFIG_DRIVER_BSD=y
-CONFIG_DRIVER_NDIS=y
-
-Following example includes all features and driver interfaces that are
-included in the wpa_supplicant package:
-
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
-CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_NDISWRAPPER=y
-CONFIG_DRIVER_BROADCOM=y
-CONFIG_DRIVER_IPW=y
-CONFIG_DRIVER_BSD=y
-CONFIG_DRIVER_NDIS=y
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_MD5=y
-CONFIG_EAP_MSCHAPV2=y
-CONFIG_EAP_TLS=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_OTP=y
-CONFIG_EAP_SIM=y
-CONFIG_EAP_AKA=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_PCSC=y
-
-EAP-PEAP and EAP-TTLS will automatically include configured EAP
-methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection.
-
-
-After you have created a configuration file, you can build
-wpa_supplicant and wpa_cli with 'make' command. You may then install
-the binaries to a suitable system directory, e.g., /usr/local/bin.
-
-Example commands:
-
-# build wpa_supplicant and wpa_cli
-make
-# install binaries (this may need root privileges)
-cp wpa_cli wpa_supplicant /usr/local/bin
-
-
-You will need to make a configuration file, e.g.,
-/etc/wpa_supplicant.conf, with network configuration for the networks
-you are going to use. Configuration file section below includes
-explanation fo the configuration file format and includes various
-examples. Once the configuration is ready, you can test whether the
-configuration work by first running wpa_supplicant with following
-command to start it on foreground with debugging enabled:
-
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
-
-Assuming everything goes fine, you can start using following command
-to start wpa_supplicant on background without debugging:
-
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
-
-Please note that if you included more than one driver interface in the
-build time configuration (.config), you may need to specify which
-interface to use by including -D<driver name> option on the command
-line. See following section for more details on command line options
-for wpa_supplicant.
-
-
-
-Command line options
---------------------
-
-usage:
-  wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
-        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
-        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
-        [-p<driver_param>] [-b<br_ifname>] ...]
-
-options:
-  -b = optional bridge interface name
-  -B = run daemon in the background
-  -c = Configuration file
-  -C = ctrl_interface parameter (only used if -c is not)
-  -i = interface name
-  -d = increase debugging verbosity (-dd even more)
-  -D = driver name (can be multiple drivers: nl80211,wext)
-  -f = Log output to default log location (normally /tmp)
-  -g = global ctrl_interface
-  -K = include keys (passwords, etc.) in debug output
-  -t = include timestamp in debug messages
-  -h = show this help text
-  -L = show license (GPL and BSD)
-  -p = driver parameters
-  -P = PID file
-  -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
-  -N = start describing new interface
-
-drivers:
-  hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
-	(this can also be used with Linuxant DriverLoader)
-  hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
-  madwifi = MADWIFI 802.11 support (Atheros, etc.) (deprecated; use wext)
-  atmel = ATMEL AT76C5XXx (USB, PCMCIA)
-  wext = Linux wireless extensions (generic)
-  ralink = Ralink Client driver
-  ndiswrapper = Linux ndiswrapper (deprecated; use wext)
-  broadcom = Broadcom wl.o driver
-  ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer)
-  wired = wpa_supplicant wired Ethernet driver
-  roboswitch = wpa_supplicant Broadcom switch driver
-  bsd = BSD 802.11 support (Atheros, etc.)
-  ndis = Windows NDIS driver
-
-In most common cases, wpa_supplicant is started with
-
-wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
-
-This makes the process fork into background.
-
-The easiest way to debug problems, and to get debug log for bug
-reports, is to start wpa_supplicant on foreground with debugging
-enabled:
-
-wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
-
-If the specific driver wrapper is not known beforehand, it is possible
-to specify multiple comma separated driver wrappers on the command
-line. wpa_supplicant will use the first driver wrapper that is able to
-initialize the interface.
-
-wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
-
-
-wpa_supplicant can control multiple interfaces (radios) either by
-running one process for each interface separately or by running just
-one process and list of options at command line. Each interface is
-separated with -N argument. As an example, following command would
-start wpa_supplicant for two interfaces:
-
-wpa_supplicant \
-	-c wpa1.conf -i wlan0 -D hostap -N \
-	-c wpa2.conf -i ath0 -D madwifi
-
-
-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:
-
-wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0
-
-
-Configuration file
-------------------
-
-wpa_supplicant is configured using a text file that lists all accepted
-networks and security policies, including pre-shared keys. See
-example configuration file, wpa_supplicant.conf, for detailed
-information about the configuration format and supported fields.
-
-Changes to configuration file can be reloaded be sending SIGHUP signal
-to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly,
-reloading can be triggered with 'wpa_cli reconfigure' command.
-
-Configuration file can include one or more network blocks, e.g., one
-for each used SSID. wpa_supplicant will automatically select the best
-betwork based on the order of network blocks in the configuration
-file, network security level (WPA/WPA2 is preferred), and signal
-strength.
-
-Example configuration files for some common configurations:
-
-1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work
-   network
-
-# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-#
-# home network; allow all valid ciphers
-network={
-	ssid="home"
-	scan_ssid=1
-	key_mgmt=WPA-PSK
-	psk="very secret passphrase"
-}
-#
-# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
-network={
-	ssid="work"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	pairwise=CCMP TKIP
-	group=CCMP TKIP
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-}
-
-
-2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel
-   (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series)
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=PEAP
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase1="peaplabel=0"
-	phase2="auth=MSCHAPV2"
-}
-
-
-3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
-   unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user at example.com"
-	anonymous_identity="anonymous at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase2="auth=MD5"
-}
-
-
-4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and
-   broadcast); use EAP-TLS for authentication
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="1x-test"
-	scan_ssid=1
-	key_mgmt=IEEE8021X
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	eapol_flags=3
-}
-
-
-5) Catch all example that allows more or less all configuration modes. The
-   configuration options are used based on what security policy is used in the
-   selected SSID. This is mostly for testing and is not recommended for normal
-   use.
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
-	pairwise=CCMP TKIP
-	group=CCMP TKIP WEP104 WEP40
-	psk="very secret passphrase"
-	eap=TTLS PEAP TLS
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	phase1="peaplabel=0"
-	ca_cert2="/etc/cert/ca2.pem"
-	client_cert2="/etc/cer/user.pem"
-	private_key2="/etc/cer/user.prv"
-	private_key2_passwd="password"
-}
-
-
-6) Authentication for wired Ethernet. This can be used with 'wired' or
-   'roboswitch' interface (-Dwired or -Droboswitch on command line).
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-ap_scan=0
-network={
-	key_mgmt=IEEE8021X
-	eap=MD5
-	identity="user"
-	password="password"
-	eapol_flags=0
-}
-
-
-
-Certificates
-------------
-
-Some EAP authentication methods require use of certificates. EAP-TLS
-uses both server side and client certificates whereas EAP-PEAP and
-EAP-TTLS only require the server side certificate. When client
-certificate is used, a matching private key file has to also be
-included in configuration. If the private key uses a passphrase, this
-has to be configured in wpa_supplicant.conf ("private_key_passwd").
-
-wpa_supplicant supports X.509 certificates in PEM and DER
-formats. User certificate and private key can be included in the same
-file.
-
-If the user certificate and private key is received in PKCS#12/PFX
-format, they need to be converted to suitable PEM/DER format for
-wpa_supplicant. This can be done, e.g., with following commands:
-
-# convert client certificate and private key to PEM format
-openssl pkcs12 -in example.pfx -out user.pem -clcerts
-# convert CA certificate (if included in PFX file) to PEM format
-openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
-
-
-
-wpa_cli
--------
-
-wpa_cli is a text-based frontend program for interacting with
-wpa_supplicant. It is used to query current status, change
-configuration, trigger events, and request interactive user input.
-
-wpa_cli can show the current authentication status, selected security
-mode, dot11 and dot1x MIBs, etc. In addition, it can configure some
-variables like EAPOL state machine parameters and trigger events like
-reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
-interface to request authentication information, like username and
-password, if these are not included in the configuration. This can be
-used to implement, e.g., one-time-passwords or generic token card
-authentication where the authentication is based on a
-challenge-response that uses an external device for generating the
-response.
-
-The control interface of wpa_supplicant can be configured to allow
-non-root user access (ctrl_interface_group in the configuration
-file). This makes it possible to run wpa_cli with a normal user
-account.
-
-wpa_cli supports two modes: interactive and command line. Both modes
-share the same command set and the main difference is in interactive
-mode providing access to unsolicited messages (event messages,
-username/password requests).
-
-Interactive mode is started when wpa_cli is executed without including
-the command as a command line parameter. Commands are then entered on
-the wpa_cli prompt. In command line mode, the same commands are
-entered as command line arguments for wpa_cli.
-
-
-Interactive authentication parameters request
-
-When wpa_supplicant need authentication parameters, like username and
-password, which are not present in the configuration file, it sends a
-request message to all attached frontend programs, e.g., wpa_cli in
-interactive mode. wpa_cli shows these requests with
-"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or
-OTP (one-time-password). <id> is a unique identifier for the current
-network. <text> is description of the request. In case of OTP request,
-it includes the challenge from the authentication server.
-
-The reply to these requests can be given with 'identity', 'password',
-and 'otp' commands. <id> needs to be copied from the the matching
-request. 'password' and 'otp' commands can be used regardless of
-whether the request was for PASSWORD or OTP. The main difference
-between these two commands is that values given with 'password' are
-remembered as long as wpa_supplicant is running whereas values given
-with 'otp' are used only once and then forgotten, i.e., wpa_supplicant
-will ask frontend for a new value for every use. This can be used to
-implement one-time-password lists and generic token card -based
-authentication.
-
-Example request for password and a matching reply:
-
-CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
-> password 1 mysecretpassword
-
-Example request for generic token card challenge-response:
-
-CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
-> otp 2 9876
-
-
-wpa_cli commands
-
-  status = get current WPA/EAPOL/EAP status
-  mib = get MIB variables (dot1x, dot11)
-  help = show this usage help
-  interface [ifname] = show interfaces/select interface
-  level <debug level> = change debug level
-  license = show full wpa_cli license
-  logoff = IEEE 802.1X EAPOL state machine logoff
-  logon = IEEE 802.1X EAPOL state machine logon
-  set = set variables (shows list of variables when run without arguments)
-  pmksa = show PMKSA cache
-  reassociate = force reassociation
-  reconfigure = force wpa_supplicant to re-read its configuration file
-  preauthenticate <BSSID> = force preauthentication
-  identity <network id> <identity> = configure identity for an SSID
-  password <network id> <password> = configure password for an SSID
-  pin <network id> <pin> = configure pin for an SSID
-  otp <network id> <password> = configure one-time-password for an SSID
-  passphrase <network id> <passphrase> = configure private key passphrase
-    for an SSID
-  bssid <network id> <BSSID> = set preferred BSSID for an SSID
-  list_networks = list configured networks
-  select_network <network id> = select a network (disable others)
-  enable_network <network id> = enable a network
-  disable_network <network id> = disable a network
-  add_network = add a network
-  remove_network <network id> = remove a network
-  set_network <network id> <variable> <value> = set network variables (shows
-    list of variables when run without arguments)
-  get_network <network id> <variable> = get network variables
-  save_config = save the current configuration
-  disconnect = disconnect and wait for reassociate command before connecting
-  scan = request new BSS scan
-  scan_results = get latest scan results
-  get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
-  terminate = terminate wpa_supplicant
-  quit = exit wpa_cli
-
-
-wpa_cli command line options
-
-wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \
-        [-P<pid file>] [-g<global ctrl>]  [command..]
-  -h = help (show this usage text)
-  -v = shown version information
-  -a = run in daemon mode executing the action file based on events from
-       wpa_supplicant
-  -B = run a daemon in the background
-  default path: /var/run/wpa_supplicant
-  default interface: first interface found in socket path
-
-
-Using wpa_cli to run external program on connect/disconnect
------------------------------------------------------------
-
-wpa_cli can used to run external programs whenever wpa_supplicant
-connects or disconnects from a network. This can be used, e.g., to
-update network configuration and/or trigget DHCP client to update IP
-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
-more than one interface being used at the same time):
-
-wpa_cli -a/sbin/wpa_action.sh -B
-
-The action file (-a option, /sbin/wpa_action.sh in this example) will
-be executed whenever wpa_supplicant completes authentication (connect
-event) or detects disconnection). The action script will be called
-with two command line arguments: interface name and event (CONNECTED
-or DISCONNECTED). If the action script needs to get more information
-about the current network, it can use 'wpa_cli status' to query
-wpa_supplicant for more information.
-
-Following example can be used as a simple template for an action
-script:
-
-#!/bin/sh
-
-IFNAME=$1
-CMD=$2
-
-if [ "$CMD" == "CONNECTED" ]; then
-    SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=`
-    # configure network, signal DHCP client, etc.
-fi
-
-if [ "$CMD" == "DISCONNECTED" ]; then
-    # remove network configuration, if needed
-fi
-
-
-
-Integrating with pcmcia-cs/cardmgr scripts
-------------------------------------------
-
-wpa_supplicant needs to be running when using a wireless network with
-WPA. It can be started either from system startup scripts or from
-pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be
-completed before data frames can be exchanged, so wpa_supplicant
-should be started before DHCP client.
-
-For example, following small changes to pcmcia-cs scripts can be used
-to enable WPA support:
-
-Add MODE="Managed" and WPA="y" to the network scheme in
-/etc/pcmcia/wireless.opts.
-
-Add the following block to the end of 'start' action handler in
-/etc/pcmcia/wireless:
-
-    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-	/usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf \
-		-i$DEVICE
-    fi
-
-Add the following block to the end of 'stop' action handler (may need
-to be separated from other actions) in /etc/pcmcia/wireless:
-
-    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-	killall wpa_supplicant
-    fi
-
-This will make cardmgr start wpa_supplicant when the card is plugged
-in.
-
-
-
-Dynamic interface add and operation without configuration files
----------------------------------------------------------------
-
-wpa_supplicant can be started without any configuration files or
-network interfaces. When used in this way, a global (i.e., per
-wpa_supplicant process) control interface is used to add and remove
-network interfaces. Each network interface can then be configured
-through a per-network interface control interface. For example,
-following commands show how to start wpa_supplicant without any
-network interfaces and then add a network interface and configure a
-network (SSID):
-
-# Start wpa_supplicant in the background
-wpa_supplicant -g/var/run/wpa_supplicant-global -B
-
-# Add a new interface (wlan0, no configuration file, driver=wext, and
-# enable control interface)
-wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
-	"" wext /var/run/wpa_supplicant
-
-# Configure a network using the newly added network interface:
-wpa_cli -iwlan0 add_network
-wpa_cli -iwlan0 set_network 0 ssid '"test"'
-wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK
-wpa_cli -iwlan0 set_network 0 psk '"12345678"'
-wpa_cli -iwlan0 set_network 0 pairwise TKIP
-wpa_cli -iwlan0 set_network 0 group TKIP
-wpa_cli -iwlan0 set_network 0 proto WPA
-wpa_cli -iwlan0 enable_network 0
-
-# At this point, the new network interface should start trying to associate
-# with the WPA-PSK network using SSID test.
-
-# Remove network interface
-wpa_cli -g/var/run/wpa_supplicant-global interface_remove wlan0
-
-
-Privilege separation
---------------------
-
-To minimize the size of code that needs to be run with root privileges
-(e.g., to control wireless interface operation), wpa_supplicant
-supports optional privilege separation. If enabled, this separates the
-privileged operations into a separate process (wpa_priv) while leaving
-rest of the code (e.g., EAP authentication and WPA handshakes) into an
-unprivileged process (wpa_supplicant) that can be run as non-root
-user. Privilege separation restricts the effects of potential software
-errors by containing the majority of the code in an unprivileged
-process to avoid full system compromise.
-
-Privilege separation is not enabled by default and it can be enabled
-by adding CONFIG_PRIVSEP=y to the build configuration (.config). When
-enabled, the privileged operations (driver wrapper and l2_packet) are
-linked into a separate daemon program, wpa_priv. The unprivileged
-program, wpa_supplicant, will be built with a special driver/l2_packet
-wrappers that communicate with the privileged wpa_priv process to
-perform the needed operations. wpa_priv can control what privileged
-are allowed.
-
-wpa_priv needs to be run with network admin privileges (usually, root
-user). It opens a UNIX domain socket for each interface that is
-included on the command line; any other interface will be off limits
-for wpa_supplicant in this kind of configuration. After this,
-wpa_supplicant can be run as a non-root user (e.g., all standard users
-on a laptop or as a special non-privileged user account created just
-for this purpose to limit access to user files even further).
-
-
-Example configuration:
-- create user group for users that are allowed to use wpa_supplicant
-  ('wpapriv' in this example) and assign users that should be able to
-  use wpa_supplicant into that group
-- create /var/run/wpa_priv directory for UNIX domain sockets and control
-  user access by setting it accessible only for the wpapriv group:
-  mkdir /var/run/wpa_priv
-  chown root:wpapriv /var/run/wpa_priv
-  chmod 0750 /var/run/wpa_priv
-- start wpa_priv as root (e.g., from system startup scripts) with the
-  enabled interfaces configured on the command line:
-  wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0
-- run wpa_supplicant as non-root with a user that is in wpapriv group:
-  wpa_supplicant -i ath0 -c wpa_supplicant.conf
-
-wpa_priv does not use the network interface before wpa_supplicant is
-started, so it is fine to include network interfaces that are not
-available at the time wpa_priv is started. As an alternative, wpa_priv
-can be started when an interface is added (hotplug/udev/etc. scripts).
-wpa_priv can control multiple interface with one process, but it is
-also possible to run multiple wpa_priv processes at the same time, if
-desired.

Copied: vendor/wpa/2.0/wpa_supplicant/README (from rev 9639, vendor/wpa/dist/wpa_supplicant/README)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/README	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/README	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,946 @@
+WPA Supplicant
+==============
+
+Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi> and contributors
+All Rights Reserved.
+
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+  Following authentication methods are supported with an integrate IEEE 802.1X
+  Supplicant:
+  * EAP-TLS
+  * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
+  * EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
+  * EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
+  * EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
+  * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
+  * EAP-TTLS/EAP-MD5-Challenge
+  * EAP-TTLS/EAP-GTC
+  * EAP-TTLS/EAP-OTP
+  * EAP-TTLS/EAP-MSCHAPv2
+  * EAP-TTLS/EAP-TLS
+  * EAP-TTLS/MSCHAPv2
+  * EAP-TTLS/MSCHAP
+  * EAP-TTLS/PAP
+  * EAP-TTLS/CHAP
+  * EAP-SIM
+  * EAP-AKA
+  * EAP-PSK
+  * EAP-PAX
+  * EAP-SAKE
+  * EAP-IKEv2
+  * EAP-GPSK
+  * LEAP (note: requires special support from the driver for IEEE 802.11
+	  authentication)
+  (following methods are supported, but since they do not generate keying
+   material, they cannot be used with WPA or IEEE 802.1X WEP keying)
+  * EAP-MD5-Challenge 
+  * EAP-MSCHAPv2
+  * EAP-GTC
+  * EAP-OTP
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i)
+  * pre-authentication
+  * PMKSA caching
+
+Supported TLS/crypto libraries:
+- OpenSSL (default)
+- GnuTLS
+
+Internal TLS/crypto implementation (optional):
+- can be used in place of an external TLS/crypto library
+- TLSv1
+- X.509 certificate processing
+- PKCS #1
+- ASN.1
+- RSA
+- bignum
+- minimal size (ca. 50 kB binary, parts of which are already needed for WPA;
+  TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86)
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer
+- FreeBSD 6-CURRENT
+- NetBSD-current
+- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
+- drivers:
+	Linux drivers that support WPA/WPA2 configuration with the generic
+	Linux wireless extensions (WE-18 or newer). Even though there are
+	number of driver specific interface included in wpa_supplicant, please
+	note that Linux drivers are moving to use generic wireless extensions
+	and driver_wext (-Dwext on wpa_supplicant command line) should be the
+	default option to start with before falling back to driver specific
+	interface.
+
+	In theory, any driver that supports Linux wireless extensions can be
+	used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
+	configuration file.
+
+	Wired Ethernet drivers (with ap_scan=0)
+
+	BSD net80211 layer (e.g., Atheros driver)
+	At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current.
+
+	Windows NDIS
+	The current Windows port requires WinPcap (http://winpcap.polito.it/).
+	See README-Windows.txt for more information.
+
+wpa_supplicant was designed to be portable for different drivers and
+operating systems. Hopefully, support for more wlan cards and OSes will be
+added in the future. See developer's documentation
+(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the
+design of wpa_supplicant and porting to other drivers. One main goal
+is to add full WPA/WPA2 support to Linux wireless extensions to allow
+new drivers to be supported without having to implement new
+driver-specific interface code in wpa_supplicant.
+
+Optional libraries for layer2 packet processing:
+- libpcap (tested with 0.7.2, most relatively recent versions assumed to work,
+	this is likely to be available with most distributions,
+	http://tcpdump.org/)
+- libdnet (tested with v1.4, most versions assumed to work,
+	http://libdnet.sourceforge.net/)
+
+These libraries are _not_ used in the default Linux build. Instead,
+internal Linux specific implementation is used. libpcap/libdnet are
+more portable and they can be used by adding CONFIG_L2_PACKET=pcap into
+.config. They may also be selected automatically for other operating
+systems. In case of Windows builds, WinPcap is used by default
+(CONFIG_L2_PACKET=winpcap).
+
+
+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
+  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
+needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5,
+EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so
+they should only be enabled if testing the EAPOL/EAP state
+machines. However, there can be used as inner authentication
+algorithms with EAP-PEAP and EAP-TTLS.
+
+See Building and installing section below for more detailed
+information about the wpa_supplicant build time configuration.
+
+
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proven to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+
+
+wpa_supplicant
+--------------
+
+wpa_supplicant is an implementation of the WPA Supplicant component,
+i.e., the part that runs in the client stations. It implements WPA key
+negotiation with a WPA Authenticator and EAP authentication with
+Authentication Server. In addition, it controls the roaming and IEEE
+802.11 authentication/association of the wlan driver.
+
+wpa_supplicant is designed to be a "daemon" program that runs in the
+background and acts as the backend component controlling the wireless
+connection. wpa_supplicant supports separate frontend programs and an
+example text-based frontend, wpa_cli, is included with wpa_supplicant.
+
+Following steps are used when associating with an AP using WPA:
+
+- wpa_supplicant requests the kernel driver to scan neighboring BSSes
+- wpa_supplicant selects a BSS based on its configuration
+- wpa_supplicant requests the kernel driver to associate with the chosen
+  BSS
+- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP
+  authentication with the authentication server (proxied by the
+  Authenticator in the AP)
+- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
+- If WPA-PSK: wpa_supplicant uses PSK as the master session key
+- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
+  with the Authenticator (AP)
+- wpa_supplicant configures encryption keys for unicast and broadcast
+- normal data packets can be transmitted and received
+
+
+
+Building and installing
+-----------------------
+
+In order to be able to build wpa_supplicant, you will first need to
+select which parts of it will be included. This is done by creating a
+build time configuration file, .config, in the wpa_supplicant root
+directory. Configuration options are text lines using following
+format: CONFIG_<option>=y. Lines starting with # are considered
+comments and are ignored. See defconfig file for an example configuration
+and a list of available options and additional notes.
+
+The build time configuration can be used to select only the needed
+features and limit the binary size and requirements for external
+libraries. The main configuration parts are the selection of which
+driver interfaces (e.g., nl80211, wext, ..) and which authentication
+methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
+
+Following build time configuration options are used to control IEEE
+802.1X/EAPOL and EAP state machines and all EAP methods. Including
+TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
+library for TLS implementation. Alternatively, GnuTLS or the internal
+TLSv1 implementation can be used for TLS functionaly.
+
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_MD5=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_OTP=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=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
+
+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
+(http://www.linuxnet.com/) for smart card access.
+
+CONFIG_PCSC=y
+
+Following options can be added to .config to select which driver
+interfaces are included.
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_BSD=y
+CONFIG_DRIVER_NDIS=y
+
+Following example includes some more features and driver interfaces that
+are included in the wpa_supplicant package:
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_BSD=y
+CONFIG_DRIVER_NDIS=y
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_MD5=y
+CONFIG_EAP_MSCHAPV2=y
+CONFIG_EAP_TLS=y
+CONFIG_EAP_PEAP=y
+CONFIG_EAP_TTLS=y
+CONFIG_EAP_GTC=y
+CONFIG_EAP_OTP=y
+CONFIG_EAP_SIM=y
+CONFIG_EAP_AKA=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_PCSC=y
+
+EAP-PEAP and EAP-TTLS will automatically include configured EAP
+methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection.
+
+
+After you have created a configuration file, you can build
+wpa_supplicant and wpa_cli with 'make' command. You may then install
+the binaries to a suitable system directory, e.g., /usr/local/bin.
+
+Example commands:
+
+# build wpa_supplicant and wpa_cli
+make
+# install binaries (this may need root privileges)
+cp wpa_cli wpa_supplicant /usr/local/bin
+
+
+You will need to make a configuration file, e.g.,
+/etc/wpa_supplicant.conf, with network configuration for the networks
+you are going to use. Configuration file section below includes
+explanation fo the configuration file format and includes various
+examples. Once the configuration is ready, you can test whether the
+configuration work by first running wpa_supplicant with following
+command to start it on foreground with debugging enabled:
+
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+
+Assuming everything goes fine, you can start using following command
+to start wpa_supplicant on background without debugging:
+
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+
+Please note that if you included more than one driver interface in the
+build time configuration (.config), you may need to specify which
+interface to use by including -D<driver name> option on the command
+line. See following section for more details on command line options
+for wpa_supplicant.
+
+
+
+Command line options
+--------------------
+
+usage:
+  wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
+        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
+        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+        [-p<driver_param>] [-b<br_ifname>] ...]
+
+options:
+  -b = optional bridge interface name
+  -B = run daemon in the background
+  -c = Configuration file
+  -C = ctrl_interface parameter (only used if -c is not)
+  -i = interface name
+  -d = increase debugging verbosity (-dd even more)
+  -D = driver name (can be multiple drivers: nl80211,wext)
+  -f = Log output to default log location (normally /tmp)
+  -g = global ctrl_interface
+  -K = include keys (passwords, etc.) in debug output
+  -t = include timestamp in debug messages
+  -h = show this help text
+  -L = show license (BSD)
+  -p = driver parameters
+  -P = PID file
+  -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
+  -N = start describing new interface
+
+drivers:
+  wext = Linux wireless extensions (generic)
+  wired = wpa_supplicant wired Ethernet driver
+  roboswitch = wpa_supplicant Broadcom switch driver
+  bsd = BSD 802.11 support (Atheros, etc.)
+  ndis = Windows NDIS driver
+
+In most common cases, wpa_supplicant is started with
+
+wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
+
+This makes the process fork into background.
+
+The easiest way to debug problems, and to get debug log for bug
+reports, is to start wpa_supplicant on foreground with debugging
+enabled:
+
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+
+If the specific driver wrapper is not known beforehand, it is possible
+to specify multiple comma separated driver wrappers on the command
+line. wpa_supplicant will use the first driver wrapper that is able to
+initialize the interface.
+
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+
+
+wpa_supplicant can control multiple interfaces (radios) either by
+running one process for each interface separately or by running just
+one process and list of options at command line. Each interface is
+separated with -N argument. As an example, following command would
+start wpa_supplicant for two interfaces:
+
+wpa_supplicant \
+	-c wpa1.conf -i wlan0 -D nl80211 -N \
+	-c wpa2.conf -i wlan1 -D wext
+
+
+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:
+
+wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
+
+
+Configuration file
+------------------
+
+wpa_supplicant is configured using a text file that lists all accepted
+networks and security policies, including pre-shared keys. See
+example configuration file, wpa_supplicant.conf, for detailed
+information about the configuration format and supported fields.
+
+Changes to configuration file can be reloaded be sending SIGHUP signal
+to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly,
+reloading can be triggered with 'wpa_cli reconfigure' command.
+
+Configuration file can include one or more network blocks, e.g., one
+for each used SSID. wpa_supplicant will automatically select the best
+betwork based on the order of network blocks in the configuration
+file, network security level (WPA/WPA2 is preferred), and signal
+strength.
+
+Example configuration files for some common configurations:
+
+1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work
+   network
+
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+#
+# home network; allow all valid ciphers
+network={
+	ssid="home"
+	scan_ssid=1
+	key_mgmt=WPA-PSK
+	psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+	ssid="work"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	pairwise=CCMP TKIP
+	group=CCMP TKIP
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+}
+
+
+2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel
+   (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series)
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	eap=PEAP
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase1="peaplabel=0"
+	phase2="auth=MSCHAPV2"
+}
+
+
+3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
+   unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user at example.com"
+	anonymous_identity="anonymous at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase2="auth=MD5"
+}
+
+
+4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and
+   broadcast); use EAP-TLS for authentication
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+	ssid="1x-test"
+	scan_ssid=1
+	key_mgmt=IEEE8021X
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	eapol_flags=3
+}
+
+
+5) Catch all example that allows more or less all configuration modes. The
+   configuration options are used based on what security policy is used in the
+   selected SSID. This is mostly for testing and is not recommended for normal
+   use.
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+	pairwise=CCMP TKIP
+	group=CCMP TKIP WEP104 WEP40
+	psk="very secret passphrase"
+	eap=TTLS PEAP TLS
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	phase1="peaplabel=0"
+	ca_cert2="/etc/cert/ca2.pem"
+	client_cert2="/etc/cer/user.pem"
+	private_key2="/etc/cer/user.prv"
+	private_key2_passwd="password"
+}
+
+
+6) Authentication for wired Ethernet. This can be used with 'wired' or
+   'roboswitch' interface (-Dwired or -Droboswitch on command line).
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+ap_scan=0
+network={
+	key_mgmt=IEEE8021X
+	eap=MD5
+	identity="user"
+	password="password"
+	eapol_flags=0
+}
+
+
+
+Certificates
+------------
+
+Some EAP authentication methods require use of certificates. EAP-TLS
+uses both server side and client certificates whereas EAP-PEAP and
+EAP-TTLS only require the server side certificate. When client
+certificate is used, a matching private key file has to also be
+included in configuration. If the private key uses a passphrase, this
+has to be configured in wpa_supplicant.conf ("private_key_passwd").
+
+wpa_supplicant supports X.509 certificates in PEM and DER
+formats. User certificate and private key can be included in the same
+file.
+
+If the user certificate and private key is received in PKCS#12/PFX
+format, they need to be converted to suitable PEM/DER format for
+wpa_supplicant. This can be done, e.g., with following commands:
+
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+
+
+
+wpa_cli
+-------
+
+wpa_cli is a text-based frontend program for interacting with
+wpa_supplicant. It is used to query current status, change
+configuration, trigger events, and request interactive user input.
+
+wpa_cli can show the current authentication status, selected security
+mode, dot11 and dot1x MIBs, etc. In addition, it can configure some
+variables like EAPOL state machine parameters and trigger events like
+reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
+interface to request authentication information, like username and
+password, if these are not included in the configuration. This can be
+used to implement, e.g., one-time-passwords or generic token card
+authentication where the authentication is based on a
+challenge-response that uses an external device for generating the
+response.
+
+The control interface of wpa_supplicant can be configured to allow
+non-root user access (ctrl_interface_group in the configuration
+file). This makes it possible to run wpa_cli with a normal user
+account.
+
+wpa_cli supports two modes: interactive and command line. Both modes
+share the same command set and the main difference is in interactive
+mode providing access to unsolicited messages (event messages,
+username/password requests).
+
+Interactive mode is started when wpa_cli is executed without including
+the command as a command line parameter. Commands are then entered on
+the wpa_cli prompt. In command line mode, the same commands are
+entered as command line arguments for wpa_cli.
+
+
+Interactive authentication parameters request
+
+When wpa_supplicant need authentication parameters, like username and
+password, which are not present in the configuration file, it sends a
+request message to all attached frontend programs, e.g., wpa_cli in
+interactive mode. wpa_cli shows these requests with
+"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or
+OTP (one-time-password). <id> is a unique identifier for the current
+network. <text> is description of the request. In case of OTP request,
+it includes the challenge from the authentication server.
+
+The reply to these requests can be given with 'identity', 'password',
+and 'otp' commands. <id> needs to be copied from the the matching
+request. 'password' and 'otp' commands can be used regardless of
+whether the request was for PASSWORD or OTP. The main difference
+between these two commands is that values given with 'password' are
+remembered as long as wpa_supplicant is running whereas values given
+with 'otp' are used only once and then forgotten, i.e., wpa_supplicant
+will ask frontend for a new value for every use. This can be used to
+implement one-time-password lists and generic token card -based
+authentication.
+
+Example request for password and a matching reply:
+
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+
+Example request for generic token card challenge-response:
+
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+
+
+wpa_cli commands
+
+  status = get current WPA/EAPOL/EAP status
+  mib = get MIB variables (dot1x, dot11)
+  help = show this usage help
+  interface [ifname] = show interfaces/select interface
+  level <debug level> = change debug level
+  license = show full wpa_cli license
+  logoff = IEEE 802.1X EAPOL state machine logoff
+  logon = IEEE 802.1X EAPOL state machine logon
+  set = set variables (shows list of variables when run without arguments)
+  pmksa = show PMKSA cache
+  reassociate = force reassociation
+  reconfigure = force wpa_supplicant to re-read its configuration file
+  preauthenticate <BSSID> = force preauthentication
+  identity <network id> <identity> = configure identity for an SSID
+  password <network id> <password> = configure password for an SSID
+  pin <network id> <pin> = configure pin for an SSID
+  otp <network id> <password> = configure one-time-password for an SSID
+  passphrase <network id> <passphrase> = configure private key passphrase
+    for an SSID
+  bssid <network id> <BSSID> = set preferred BSSID for an SSID
+  list_networks = list configured networks
+  select_network <network id> = select a network (disable others)
+  enable_network <network id> = enable a network
+  disable_network <network id> = disable a network
+  add_network = add a network
+  remove_network <network id> = remove a network
+  set_network <network id> <variable> <value> = set network variables (shows
+    list of variables when run without arguments)
+  get_network <network id> <variable> = get network variables
+  save_config = save the current configuration
+  disconnect = disconnect and wait for reassociate command before connecting
+  scan = request new BSS scan
+  scan_results = get latest scan results
+  get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
+  terminate = terminate wpa_supplicant
+  quit = exit wpa_cli
+
+
+wpa_cli command line options
+
+wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \
+        [-P<pid file>] [-g<global ctrl>]  [command..]
+  -h = help (show this usage text)
+  -v = shown version information
+  -a = run in daemon mode executing the action file based on events from
+       wpa_supplicant
+  -B = run a daemon in the background
+  default path: /var/run/wpa_supplicant
+  default interface: first interface found in socket path
+
+
+Using wpa_cli to run external program on connect/disconnect
+-----------------------------------------------------------
+
+wpa_cli can used to run external programs whenever wpa_supplicant
+connects or disconnects from a network. This can be used, e.g., to
+update network configuration and/or trigget DHCP client to update IP
+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
+more than one interface being used at the same time):
+
+wpa_cli -a/sbin/wpa_action.sh -B
+
+The action file (-a option, /sbin/wpa_action.sh in this example) will
+be executed whenever wpa_supplicant completes authentication (connect
+event) or detects disconnection). The action script will be called
+with two command line arguments: interface name and event (CONNECTED
+or DISCONNECTED). If the action script needs to get more information
+about the current network, it can use 'wpa_cli status' to query
+wpa_supplicant for more information.
+
+Following example can be used as a simple template for an action
+script:
+
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+if [ "$CMD" = "CONNECTED" ]; then
+    SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=`
+    # configure network, signal DHCP client, etc.
+fi
+
+if [ "$CMD" = "DISCONNECTED" ]; then
+    # remove network configuration, if needed
+    SSID=
+fi
+
+
+
+Integrating with pcmcia-cs/cardmgr scripts
+------------------------------------------
+
+wpa_supplicant needs to be running when using a wireless network with
+WPA. It can be started either from system startup scripts or from
+pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be
+completed before data frames can be exchanged, so wpa_supplicant
+should be started before DHCP client.
+
+For example, following small changes to pcmcia-cs scripts can be used
+to enable WPA support:
+
+Add MODE="Managed" and WPA="y" to the network scheme in
+/etc/pcmcia/wireless.opts.
+
+Add the following block to the end of 'start' action handler in
+/etc/pcmcia/wireless:
+
+    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+	/usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf \
+		-i$DEVICE
+    fi
+
+Add the following block to the end of 'stop' action handler (may need
+to be separated from other actions) in /etc/pcmcia/wireless:
+
+    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+	killall wpa_supplicant
+    fi
+
+This will make cardmgr start wpa_supplicant when the card is plugged
+in.
+
+
+
+Dynamic interface add and operation without configuration files
+---------------------------------------------------------------
+
+wpa_supplicant can be started without any configuration files or
+network interfaces. When used in this way, a global (i.e., per
+wpa_supplicant process) control interface is used to add and remove
+network interfaces. Each network interface can then be configured
+through a per-network interface control interface. For example,
+following commands show how to start wpa_supplicant without any
+network interfaces and then add a network interface and configure a
+network (SSID):
+
+# Start wpa_supplicant in the background
+wpa_supplicant -g/var/run/wpa_supplicant-global -B
+
+# Add a new interface (wlan0, no configuration file, driver=wext, and
+# enable control interface)
+wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
+	"" wext /var/run/wpa_supplicant
+
+# Configure a network using the newly added network interface:
+wpa_cli -iwlan0 add_network
+wpa_cli -iwlan0 set_network 0 ssid '"test"'
+wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK
+wpa_cli -iwlan0 set_network 0 psk '"12345678"'
+wpa_cli -iwlan0 set_network 0 pairwise TKIP
+wpa_cli -iwlan0 set_network 0 group TKIP
+wpa_cli -iwlan0 set_network 0 proto WPA
+wpa_cli -iwlan0 enable_network 0
+
+# At this point, the new network interface should start trying to associate
+# with the WPA-PSK network using SSID test.
+
+# Remove network interface
+wpa_cli -g/var/run/wpa_supplicant-global interface_remove wlan0
+
+
+Privilege separation
+--------------------
+
+To minimize the size of code that needs to be run with root privileges
+(e.g., to control wireless interface operation), wpa_supplicant
+supports optional privilege separation. If enabled, this separates the
+privileged operations into a separate process (wpa_priv) while leaving
+rest of the code (e.g., EAP authentication and WPA handshakes) into an
+unprivileged process (wpa_supplicant) that can be run as non-root
+user. Privilege separation restricts the effects of potential software
+errors by containing the majority of the code in an unprivileged
+process to avoid full system compromise.
+
+Privilege separation is not enabled by default and it can be enabled
+by adding CONFIG_PRIVSEP=y to the build configuration (.config). When
+enabled, the privileged operations (driver wrapper and l2_packet) are
+linked into a separate daemon program, wpa_priv. The unprivileged
+program, wpa_supplicant, will be built with a special driver/l2_packet
+wrappers that communicate with the privileged wpa_priv process to
+perform the needed operations. wpa_priv can control what privileged
+are allowed.
+
+wpa_priv needs to be run with network admin privileges (usually, root
+user). It opens a UNIX domain socket for each interface that is
+included on the command line; any other interface will be off limits
+for wpa_supplicant in this kind of configuration. After this,
+wpa_supplicant can be run as a non-root user (e.g., all standard users
+on a laptop or as a special non-privileged user account created just
+for this purpose to limit access to user files even further).
+
+
+Example configuration:
+- create user group for users that are allowed to use wpa_supplicant
+  ('wpapriv' in this example) and assign users that should be able to
+  use wpa_supplicant into that group
+- create /var/run/wpa_priv directory for UNIX domain sockets and control
+  user access by setting it accessible only for the wpapriv group:
+  mkdir /var/run/wpa_priv
+  chown root:wpapriv /var/run/wpa_priv
+  chmod 0750 /var/run/wpa_priv
+- start wpa_priv as root (e.g., from system startup scripts) with the
+  enabled interfaces configured on the command line:
+  wpa_priv -B -P /var/run/wpa_priv.pid wext:ath0
+- run wpa_supplicant as non-root with a user that is in wpapriv group:
+  wpa_supplicant -i ath0 -c wpa_supplicant.conf
+
+wpa_priv does not use the network interface before wpa_supplicant is
+started, so it is fine to include network interfaces that are not
+available at the time wpa_priv is started. As an alternative, wpa_priv
+can be started when an interface is added (hotplug/udev/etc. scripts).
+wpa_priv can control multiple interface with one process, but it is
+also possible to run multiple wpa_priv processes at the same time, if
+desired.

Copied: vendor/wpa/2.0/wpa_supplicant/README-HS20 (from rev 9639, vendor/wpa/dist/wpa_supplicant/README-HS20)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/README-HS20	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/README-HS20	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,475 @@
+wpa_supplicant and Hotspot 2.0
+==============================
+
+This document describe how the IEEE 802.11u Interworking and Wi-Fi
+Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be
+configured and how an external component on the client e.g., management
+GUI or Wi-Fi framework) is used to manage this functionality.
+
+
+Introduction to Wi-Fi Hotspot 2.0
+---------------------------------
+
+Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used
+in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about
+this is available in this white paper:
+
+http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless
+
+The Hotspot 2.0 specification is also available from WFA:
+https://www.wi-fi.org/knowledge-center/published-specifications
+
+The core Interworking functionality (network selection, GAS/ANQP) were
+standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std
+802.11-2012.
+
+
+wpa_supplicant network selection
+--------------------------------
+
+Interworking support added option for configuring credentials that can
+work with multiple networks as an alternative to configuration of
+network blocks (e.g., per-SSID parameters). When requested to perform
+network selection, wpa_supplicant picks the highest priority enabled
+network block or credential. If a credential is picked (based on ANQP
+information from APs), a temporary network block is created
+automatically for the matching network. This temporary network block is
+used similarly to the network blocks that can be configured by the user,
+but it is not stored into the configuration file and is meant to be used
+only for temporary period of time since a new one can be created
+whenever needed based on ANQP information and the credential.
+
+By default, wpa_supplicant is not using automatic network selection
+unless requested explicitly with the interworking_select command. This
+can be changed with the auto_interworking=1 parameter to perform network
+selection automatically whenever trying to find a network for connection
+and none of the enabled network blocks match with the scan results. This
+case works similarly to "interworking_select auto", i.e., wpa_supplicant
+will internally determine which network or credential is going to be
+used based on configured priorities, scan results, and ANQP information.
+
+
+wpa_supplicant configuration
+----------------------------
+
+Interworking and Hotspot 2.0 functionality are optional components that
+need to be enabled in the wpa_supplicant build configuration
+(.config). This is done by adding following parameters into that file:
+
+CONFIG_INTERWORKING=y
+CONFIG_HS20=y
+
+It should be noted that this functionality requires a driver that
+supports GAS/ANQP operations. This uses the same design as P2P, i.e.,
+Action frame processing and building in user space within
+wpa_supplicant. The Linux nl80211 driver interface provides the needed
+functionality for this.
+
+
+There are number of run-time configuration parameters (e.g., in
+wpa_supplicant.conf when using the configuration file) that can be used
+to control Hotspot 2.0 operations.
+
+# Enable Interworking
+interworking=1
+
+# Enable Hotspot 2.0
+hs20=1
+
+# Parameters for controlling scanning
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+#hessid=00:11:22:33:44:55
+
+# Access Network Type
+# When Interworking is enabled, scans can be limited to APs that advertise the
+# specified Access Network Type (0..15; with 15 indicating wildcard match).
+# This value controls the Access Network Type value in Probe Request frames.
+#access_network_type=15
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+#     (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+#     credentials have been configured and scan did not find a
+#     matching network block
+#auto_interworking=0
+
+
+Credentials can be pre-configured for automatic network selection:
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# priority: Priority group
+#	By default, all networks and credentials get the same priority group
+#	(0). This field can be used to give higher priority for credentials
+#	(and similarly in struct wpa_ssid for network blocks) to change the
+#	Interworking automatic networking selection behavior. The matching
+#	network (based on either an enabled network block or a credential)
+#	with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+#	This field is used with Interworking networking selection for a case
+#	where client certificate/private key is used for authentication
+#	(EAP-TLS). 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.
+#
+# 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.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+#	format
+#
+# domain: Home service provider FQDN
+#	This is used to compare against the Domain Name List to figure out
+#	whether the AP is operated by the Home SP.
+#
+# roaming_consortium: Roaming Consortium OI
+#	If roaming_consortium_len is non-zero, this field contains the
+#	Roaming Consortium OI that can be used to determine which access
+#	points support authentication with this credential. This is an
+#	alternative to the use of the realm parameter. When using Roaming
+#	Consortium to match the network, the EAP parameters need to be
+#	pre-configured with the credential since the NAI Realm information
+#	may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+#	This optional field can be used to specify which EAP method will be
+#	used with this credential. If not set, the EAP method is selected
+#	automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+#	This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+#	This optional field is used with like the 'eap' parameter.
+#
+# excluded_ssid: Excluded SSID
+#	This optional field can be used to excluded specific SSID(s) from
+#	matching with the network. Multiple entries can be used to specify more
+#	than one SSID.
+#
+# for example:
+#
+#cred={
+#	realm="example.com"
+#	username="user at example.com"
+#	password="password"
+#	ca_cert="/etc/wpa_supplicant/ca.pem"
+#	domain="example.com"
+#}
+#
+#cred={
+#	imsi="310026-000000000"
+#	milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+#	realm="example.com"
+#	username="user"
+#	password="password"
+#	ca_cert="/etc/wpa_supplicant/ca.pem"
+#	domain="example.com"
+#	roaming_consortium=223344
+#	eap=TTLS
+#	phase2="auth=MSCHAPV2"
+#}
+
+
+Control interface
+-----------------
+
+wpa_supplicant provides a control interface that can be used from
+external programs to manage various operations. The included command
+line tool, wpa_cli, can be used for manual testing with this interface.
+
+Following wpa_cli interactive mode commands show some examples of manual
+operations related to Hotspot 2.0:
+
+Remove configured networks and credentials:
+
+> remove_network all
+OK
+> remove_cred all
+OK
+
+
+Add a username/password credential:
+
+> add_cred
+0
+> set_cred 0 realm "mail.example.com"
+OK
+> set_cred 0 username "username"
+OK
+> set_cred 0 password "password"
+OK
+> set_cred 0 priority 1
+OK
+
+Add a SIM credential using a simulated SIM/USIM card for testing:
+
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123"
+OK
+> set_cred 1 priority 1
+OK
+
+Note: the return value of add_cred is used as the first argument to
+the following set_cred commands.
+
+
+Add a WPA2-Enterprise network:
+
+> add_network
+0
+> set_network 0 key_mgmt WPA-EAP
+OK
+> set_network 0 ssid "enterprise"
+OK
+> set_network 0 eap TTLS
+OK
+> set_network 0 anonymous_identity "anonymous"
+OK
+> set_network 0 identity "user"
+OK
+> set_network 0 password "password"
+OK
+> set_network 0 priority 0
+OK
+> enable_network 0 no-connect
+OK
+
+
+Add an open network:
+
+> add_network
+3
+> set_network 3 key_mgmt NONE
+OK
+> set_network 3 ssid "coffee-shop"
+OK
+> select_network 3
+OK
+
+Note: the return value of add_network is used as the first argument to
+the following set_network commands.
+
+The preferred credentials/networks can be indicated with the priority
+parameter (1 is higher priority than 0).
+
+
+Interworking network selection can be started with interworking_select
+command. This instructs wpa_supplicant to run a network scan and iterate
+through the discovered APs to request ANQP information from the APs that
+advertise support for Interworking/Hotspot 2.0:
+
+> interworking_select
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<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
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+
+
+INTERWORKING-AP event messages indicate the APs that support network
+selection and for which there is a matching
+credential. interworking_connect command can be used to select a network
+to connect with:
+
+
+> interworking_connect 02:00:00:00:01:00
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=]
+
+
+wpa_supplicant creates a temporary network block for the selected
+network based on the configured credential and ANQP information from the
+AP:
+
+> list_networks
+network id / ssid / bssid / flags
+0	Example Network	any	[CURRENT]
+> get_network 0 key_mgmt
+WPA-EAP
+> get_network 0 eap
+TTLS
+
+
+Alternatively to using an external program to select the network,
+"interworking_select auto" command can be used to request wpa_supplicant
+to select which network to use based on configured priorities:
+
+
+> remove_network all
+OK
+<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1
+> interworking_select auto
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<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
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=]
+
+
+The connection status can be shown with the status command:
+
+> status
+bssid=02:00:00:00:01:00
+ssid=Example Network
+id=0
+mode=station
+pairwise_cipher=CCMP       <--- link layer security indication
+group_cipher=CCMP
+key_mgmt=WPA2/IEEE 802.1X/EAP
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+hs20=1      <--- HS 2.0 indication
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+selectedMethod=21 (EAP-TTLS)
+EAP TLS cipher=AES-128-SHA
+EAP-TTLSv0 Phase2 method=PAP
+
+
+> status
+bssid=02:00:00:00:02:00
+ssid=coffee-shop
+id=3
+mode=station
+pairwise_cipher=NONE
+group_cipher=NONE
+key_mgmt=NONE
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+
+
+Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status
+command output. Link layer security is indicated with the
+pairwise_cipher (CCMP = secure, NONE = no encryption used).
+
+
+Also the scan results include the Hotspot 2.0 indication:
+
+> scan_results
+bssid / frequency / signal level / flags / ssid
+02:00:00:00:01:00	2412	-30	[WPA2-EAP-CCMP][ESS][HS20]	Example Network
+
+
+ANQP information for the BSS can be fetched using the BSS command:
+
+> bss 02:00:00:00:01:00
+id=1
+bssid=02:00:00:00:01:00
+freq=2412
+beacon_int=100
+capabilities=0x0411
+qual=0
+noise=-92
+level=-30
+tsf=1345573286517276
+age=105
+ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000
+flags=[WPA2-EAP-CCMP][ESS][HS20]
+ssid=Example Network
+anqp_roaming_consortium=031122330510203040500601020304050603fedcba
+
+
+ANQP queries can also be requested with the anqp_get and hs20_anqp_get
+commands:
+
+> anqp_get 02:00:00:00:01:00 261
+OK
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+> hs20_anqp_get 02:00:00:00:01:00 2
+OK
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+
+In addition, fetch_anqp command can be used to request similar set of
+ANQP queries to be done as is run as part of interworking_select:
+
+> scan
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+> fetch_anqp
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<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

Copied: vendor/wpa/2.0/wpa_supplicant/README-P2P (from rev 9639, vendor/wpa/dist/wpa_supplicant/README-P2P)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/README-P2P	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/README-P2P	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,560 @@
+wpa_supplicant and Wi-Fi P2P
+============================
+
+This document describes how the Wi-Fi P2P implementation in
+wpa_supplicant can be configured and how an external component on the
+client (e.g., management GUI) is used to enable WPS enrollment and
+registrar registration.
+
+
+Introduction to Wi-Fi P2P
+-------------------------
+
+TODO
+
+More information about Wi-Fi P2P is available from Wi-Fi Alliance:
+http://www.wi-fi.org/Wi-Fi_Direct.php
+
+
+wpa_supplicant implementation
+-----------------------------
+
+TODO
+
+
+wpa_supplicant configuration
+----------------------------
+
+Wi-Fi P2P is an optional component that needs to be enabled in the
+wpa_supplicant build configuration (.config). Here is an example
+configuration that includes Wi-Fi P2P support and Linux nl80211
+-based driver interface:
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_CTRL_IFACE=y
+CONFIG_P2P=y
+CONFIG_AP=y
+CONFIG_WPS=y
+
+
+In run-time configuration file (wpa_supplicant.conf), some parameters
+for P2P may be set. In order to make the devices easier to recognize,
+device_name and device_type should be specified. For example,
+something like this should be included:
+
+ctrl_interface=/var/run/wpa_supplicant
+device_name=My P2P Device
+device_type=1-0050F204-1
+
+
+wpa_cli
+-------
+
+Actual Wi-Fi P2P operations are requested during runtime. These can be
+done for example using wpa_cli (which is described below) or a GUI
+like wpa_gui-qt4.
+
+
+wpa_cli starts in interactive mode if no command string is included on
+the command line. By default, it will select the first network interface
+that it can find (and that wpa_supplicant controls). If more than one
+interface is in use, it may be necessary to select one of the explicitly
+by adding -i argument on the command line (e.g., 'wpa_cli -i wlan1').
+
+Most of the P2P operations are done on the main interface (e.g., the
+interface that is automatically added when the driver is loaded, e.g.,
+wlan0). When using a separate virtual interface for group operations
+(e.g., wlan1), the control interface for that group interface may need
+to be used for some operations (mainly WPS activation in GO). This may
+change in the future so that all the needed operations could be done
+over the main control interface.
+
+Device Discovery
+
+p2p_find [timeout in seconds] [type=<social|progressive>] \
+	[dev_id=<addr>] [delay=<search delay in ms>]
+
+The default behavior is to run a single full scan in the beginning and
+then scan only social channels. type=social will scan only social
+channels, i.e., it skips the initial full scan. type=progressive is
+like the default behavior, but it will scan through all the channels
+progressively one channel at the time in the Search state rounds. This
+will help in finding new groups or groups missed during the initial
+full scan.
+
+The optional dev_id option can be used to specify a single P2P peer to
+search for. The optional delay parameter can be used to request an extra
+delay to be used between search iterations (e.g., to free up radio
+resources for concurrent operations).
+
+p2p_listen [timeout in seconds]
+
+Start Listen-only state (become discoverable without searching for
+other devices). Optional parameter can be used to specify the duration
+for the Listen operation in seconds. This command may not be of that
+much use during normal operations and is mainly designed for
+testing. It can also be used to keep the device discoverable without
+having to maintain a group.
+
+p2p_stop_find
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+p2p_flush
+
+Flush P2P peer table and state.
+
+Group Formation
+
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join|auto]
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "p2p_prov_disc
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+The optional "join" parameter can be used to indicate that this command
+is requesting an already running GO to prepare for a new client. This is
+mainly used with "display" to request it to display a PIN. The "auto"
+parameter can be used to request wpa_supplicant to automatically figure
+out whether the peer device is operating as a GO and if so, use
+join-a-group style PD instead of GO Negotiation style PD.
+
+p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
+	[persistent|persistent=<network id>] [join|auth]
+	[go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The <pbc|pin|PIN#> parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [display|keypad] is used with PIN method
+to specify which PIN is used (display=dynamically generated random PIN
+from local display, keypad=PIN entered from peer display). "persistent"
+parameter can be used to request a persistent group to be formed. The
+"persistent=<network id>" alternative can be used to pre-populate
+SSID/passphrase configuration based on a previously used persistent
+group where this device was the GO. The previously used parameters will
+then be used if the local end becomes the GO in GO Negotiation (which
+can be forced with go_intent=15).
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part. This will send a Provision
+Discovery Request message to the target GO before associating for WPS
+provisioning.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+"go_intent" can be used to override the default GO Intent for this GO
+Negotiation.
+
+"freq" can be used to set a forced operating channel (e.g., freq=2412
+to select 2.4 GHz channel 1).
+
+"provdisc" can be used to request a Provision Discovery exchange to be
+used prior to starting GO Negotiation as a workaround with some deployed
+P2P implementations that require this to allow the user to accept the
+connection.
+
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent=<network id> can be used to specify restart of
+a persistent group. Optional freq=<freq in MHz> can be used to force
+the GO to be started on a specific frequency. Special freq=2 or freq=5
+options can be used to request the best 2.4 GHz or 5 GHz band channel
+to be selected automatically.
+
+p2p_reject <peer device address>
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+p2p_group_remove <group interface>
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+p2p_cancel
+
+Cancel an ongoing P2P group formation and joining-a-group related
+operation. This operations unauthorizes the specific peer device (if any
+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
+step. If the WPS provisioning step has been completed, the group is not
+terminated.
+
+Service Discovery
+
+p2p_serv_disc_req
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump. For
+example,
+
+p2p_serv_disc_req 00:00:00:00:00:00 02000001
+
+schedules a request for listing all available services of all service
+discovery protocols and requests this to be sent to all discovered
+peers (note: this can result in long response frames). The pending
+requests are sent during device discovery (see p2p_find).
+
+Only a single pending wildcard query is supported, but there can be
+multiple pending peer device specific queries (each will be sent in
+sequence whenever the peer is found).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+For UPnP, an alternative command format can be used to specify a
+single query TLV (i.e., a service discovery for a specific UPnP
+service):
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp <version hex> <ST: from M-SEARCH>
+
+For example:
+
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+Additional examples for queries:
+
+# list of all Bonjour services
+p2p_serv_disc_req 00:00:00:00:00:00 02000101
+
+# list of all UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 02000201
+
+# list of all WS-Discovery services
+p2p_serv_disc_req 00:00:00:00:00:00 02000301
+
+# list of all Bonjour and UPnP services
+p2p_serv_disc_req 00:00:00:00:00:00 0200010102000202
+
+# Apple File Sharing over TCP
+p2p_serv_disc_req 00:00:00:00:00:00 130001010b5f6166706f766572746370c00c000c01
+
+# Bonjour SSTH (supported service type hash)
+p2p_serv_disc_req 00:00:00:00:00:00 05000101000000
+
+# UPnP examples
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 ssdp:all
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 upnp:rootdevice
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
+p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+# Wi-Fi Display examples
+# format: wifi-display <list of roles> <list of subelements>
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
+p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+
+p2p_serv_disc_cancel_req <query identifier>
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by p2p_serv_disc_req, e.g., "p2p_serv_disc_cancel_req 1f77628".
+
+p2p_serv_disc_resp
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example, "p2p_serv_disc_resp 2437 02:40:61:c2:f3:b7
+1 0300000101". This command is used only if external program is used
+to process the request (see p2p_serv_disc_external).
+
+p2p_service_update
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed. This is only needed when external
+service discovery processing is enabled since the commands to
+pre-configure services for internal processing will increment the
+indicator automatically.
+
+p2p_serv_disc_external <0|1>
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will process
+each request based on pre-configured services), 1 = external
+processing of requests (external program is responsible for replying
+to service discovery requests with p2p_serv_disc_resp). Please note
+that there is quite strict limit on how quickly the response needs to
+be transmitted, so use of the internal processing is strongly
+recommended.
+
+p2p_service_add bonjour <query hexdump> <RDATA hexdump>
+
+Add a local Bonjour service for internal SD query processing.
+
+Examples:
+
+# AFP Over TCP (PTR)
+p2p_service_add bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027
+# AFP Over TCP (TXT) (RDATA=null)
+p2p_service_add bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00
+
+# IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.)
+p2p_service_add bonjour 045f697070c00c000c01 094d795072696e746572c027
+# IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript)
+p2p_service_add bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074
+
+# Supported Service Type Hash (SSTH)
+p2p_service_add bonjour 000000 <32-byte bitfield as hexdump>
+(note: see P2P spec Annex E.4 for information on how to construct the bitfield)
+
+p2p_service_del bonjour <query hexdump>
+
+Remove a local Bonjour service from internal SD query processing.
+
+p2p_service_add upnp <version hex> <service>
+
+Add a local UPnP service for internal SD query processing.
+
+Examples:
+
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice
+p2p_service_add upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2
+p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1
+
+p2p_service_del upnp <version hex> <service>
+
+Remove a local UPnP service from internal SD query processing.
+
+p2p_service_flush
+
+Remove all local services from internal SD query processing.
+
+Invitation
+
+p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
+	[go_dev_addr=address] [freq=<freq in MHz>] [ht40]
+
+Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
+persistent group (e.g., persistent=4). If the peer device is the GO of
+the persistent group, the peer parameter is not needed. Otherwise it is
+used to specify which device to invite. go_dev_addr parameter can be
+used to override the GO device address for Invitation Request should
+it be not known for some reason (this should not be needed in most
+cases). When reinvoking a persistent group, the GO device can specify
+the frequency for the group with the freq parameter.
+
+Group Operations
+
+(These are used on the group interface.)
+
+wps_pin <any|address> <PIN>
+
+Start WPS PIN method. This allows a single WPS Enrollee to connect to
+the AP/GO. This is used on the GO when a P2P client joins an existing
+group. The second parameter is the address of the Enrollee or a string
+"any" to allow any station to use the entered PIN (which will restrict
+the PIN for one-time-use). PIN is the Enrollee PIN read either from a
+label or display on the P2P Client/WPS Enrollee.
+
+wps_pbc
+
+Start WPS PBC method (i.e., push the button). This allows a single WPS
+Enrollee to connect to the AP/GO. This is used on the GO when a P2P
+client joins an existing group.
+
+p2p_get_passphrase
+
+Get the passphrase for a group (only available when acting as a GO).
+
+p2p_presence_req [<duration> <interval>] [<duration> <interval>]
+
+Send a P2P Presence Request to the GO (this is only available when
+acting as a P2P client). If no duration/interval pairs are given, the
+request indicates that this client has no special needs for GO
+presence. the first parameter pair gives the preferred duration and
+interval values in microseconds. If the second pair is included, that
+indicates which value would be acceptable.
+
+Parameters
+
+p2p_ext_listen [<period> <interval>]
+
+Configure Extended Listen Timing. If the parameters are omitted, this
+feature is disabled. If the parameters are included, Listen State will
+be entered every interval msec for at least period msec. Both values
+have acceptable range of 1-65535 (with interval obviously having to be
+larger than or equal to duration). If the P2P module is not idle at
+the time the Extended Listen Timing timeout occurs, the Listen State
+operation will be skipped.
+
+The configured values will also be advertised to other P2P Devices. The
+received values are available in the p2p_peer command output:
+
+ext_listen_period=100 ext_listen_interval=5000
+
+p2p_set <field> <value>
+
+Change dynamic P2P parameters
+
+p2p_set discoverability <0/1>
+
+Disable/enable advertisement of client discoverability. This is
+enabled by default and this parameter is mainly used to allow testing
+of device discoverability.
+
+p2p_set managed <0/1>
+
+Disable/enable managed P2P Device operations. This is disabled by
+default.
+
+p2p_set listen_channel <1/6/11>
+
+Set P2P Listen channel. This is mainly meant for testing purposes and
+changing the Listen channel during normal operations can result in
+protocol failures.
+
+p2p_set ssid_postfix <postfix>
+
+Set postfix string to be added to the automatically generated P2P SSID
+(DIRECT-<two random characters>). For example, postfix of "-testing"
+could result in the SSID becoming DIRECT-ab-testing.
+
+set <field> <value>
+
+Set global configuration parameters which may also affect P2P
+operations. The format on these parameters is same as is used in
+wpa_supplicant.conf. Only the parameters listen here should be
+changed. Modifying other parameters may result in incorrect behavior
+since not all existing users of the parameters are updated.
+
+set uuid <UUID>
+
+Set WPS UUID (by default, this is generated based on the MAC address).
+
+set device_name <device name>
+
+Set WPS Device Name (also included in some P2P messages).
+
+set manufacturer <manufacturer>
+
+Set WPS Manufacturer.
+
+set model_name <model name>
+
+Set WPS Model Name.
+
+set model_number <model number>
+
+Set WPS Model Number.
+
+set serial_number <serial number>
+
+Set WPS Serial Number.
+
+set device_type <device type>
+
+Set WPS Device Type.
+
+set os_version <OS version>
+
+Set WPS OS Version.
+
+set config_methods <config methods>
+
+Set WPS Configuration Methods.
+
+set sec_device_type <device type>
+
+Add a new Secondary Device Type.
+
+set p2p_go_intent <GO intent>
+
+Set the default P2P GO Intent. Note: This value can be overridden in
+p2p_connect command and as such, there should be no need to change the
+default value here during normal operations.
+
+set p2p_ssid_postfix <P2P SSID postfix>
+
+Set P2P SSID postfix.
+
+set persistent_reconnect <0/1>
+
+Disable/enabled persistent reconnect for reinvocation of persistent
+groups. If enabled, invitations to reinvoke a persistent group will be
+accepted without separate authorization (e.g., user interaction).
+
+set country <two character country code>
+
+Set country code (this is included in some P2P messages).
+
+Status
+
+p2p_peers [discovered]
+
+List P2P Device Addresses of all the P2P peers we know. The optional
+"discovered" parameter filters out the peers that we have not fully
+discovered, i.e., which we have only seen in a received Probe Request
+frame.
+
+p2p_peer <P2P Device Address>
+
+Fetch information about a known P2P peer.
+
+Group Status
+
+(These are used on the group interface.)
+
+status
+
+Show status information (connection state, role, use encryption
+parameters, IP address, etc.).
+
+sta
+
+Show information about an associated station (when acting in AP/GO role).
+
+all_sta
+
+Lists the currently associated stations.
+
+Configuration data
+
+list_networks
+
+Lists the configured networks, including stored information for
+persistent groups. The identifier in this list is used with
+p2p_group_add and p2p_invite to indicate which persistent group is to
+be reinvoked.
+
+remove_network <network id>
+
+Remove a network entry from configuration. 
+
+
+wpa_cli action script
+---------------------
+
+See examples/p2p-action.sh
+
+TODO: describe DHCP/DNS setup
+TODO: cross-connection

Deleted: vendor/wpa/2.0/wpa_supplicant/README-WPS
===================================================================
--- vendor/wpa/dist/wpa_supplicant/README-WPS	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/README-WPS	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,200 +0,0 @@
-wpa_supplicant and Wi-Fi Protected Setup (WPS)
-==============================================
-
-This document describes how the WPS implementation in wpa_supplicant
-can be configured and how an external component on the client (e.g.,
-management GUI) is used to enable WPS enrollment and registrar
-registration.
-
-
-Introduction to WPS
--------------------
-
-Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
-wireless network. It allows automated generation of random keys (WPA
-passphrase/PSK) and configuration of an access point and client
-devices. WPS includes number of methods for setting up connections
-with PIN method and push-button configuration (PBC) being the most
-commonly deployed options.
-
-While WPS can enable more home networks to use encryption in the
-wireless network, it should be noted that the use of the PIN and
-especially PBC mechanisms for authenticating the initial key setup is
-not very secure. As such, use of WPS may not be suitable for
-environments that require secure network access without chance for
-allowing outsiders to gain access during the setup phase.
-
-WPS uses following terms to describe the entities participating in the
-network setup:
-- access point: the WLAN access point
-- Registrar: a device that control a network and can authorize
-  addition of new devices); this may be either in the AP ("internal
-  Registrar") or in an external device, e.g., a laptop, ("external
-  Registrar")
-- Enrollee: a device that is being authorized to use the network
-
-It should also be noted that the AP and a client device may change
-roles (i.e., AP acts as an Enrollee and client device as a Registrar)
-when WPS is used to configure the access point.
-
-
-More information about WPS is available from Wi-Fi Alliance:
-http://www.wi-fi.org/wifi-protected-setup
-
-
-wpa_supplicant implementation
------------------------------
-
-wpa_supplicant includes an optional WPS component that can be used as
-an Enrollee to enroll new network credential or as a Registrar to
-configure an AP. The current version of wpa_supplicant does not
-support operation as an external WLAN Management Registrar for adding
-new client devices or configuring the AP over UPnP.
-
-
-wpa_supplicant configuration
-----------------------------
-
-WPS is an optional component that needs to be enabled in
-wpa_supplicant build configuration (.config). Here is an example
-configuration that includes WPS support and Linux wireless extensions
--based driver interface:
-
-CONFIG_DRIVER_WEXT=y
-CONFIG_WPS=y
-
-
-WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
-the device. This is configured in the runtime configuration for
-wpa_supplicant (if not set, UUID will be generated based on local MAC
-address):
-
-# example UUID for WPS
-uuid=12345678-9abc-def0-1234-56789abcdef0
-
-The network configuration blocks needed for WPS are added
-automatically based on control interface commands, so they do not need
-to be added explicitly in the configuration file.
-
-WPS registration will generate new network blocks for the acquired
-credentials. If these are to be stored for future use (after
-restarting wpa_supplicant), wpa_supplicant will need to be configured
-to allow configuration file updates:
-
-update_config=1
-
-
-
-External operations
--------------------
-
-WPS requires either a device PIN code (usually, 8-digit number) or a
-pushbutton event (for PBC) to allow a new WPS Enrollee to join the
-network. wpa_supplicant uses the control interface as an input channel
-for these events.
-
-If the client device has a display, a random PIN has to be generated
-for each WPS registration session. wpa_supplicant can do this with a
-control interface request, e.g., by calling wpa_cli:
-
-wpa_cli wps_pin any
-
-This will return the generated 8-digit PIN which will then need to be
-entered at the Registrar to complete WPS registration. At that point,
-the client will be enrolled with credentials needed to connect to the
-AP to access the network.
-
-
-If the client device does not have a display that could show the
-random PIN, a hardcoded PIN that is printed on a label can be
-used. wpa_supplicant is notified this with a control interface
-request, e.g., by calling wpa_cli:
-
-wpa_cli wps_pin any 12345670
-
-This starts the WPS negotiation in the same way as above with the
-generated PIN.
-
-
-If the client design wants to support optional WPS PBC mode, this can
-be enabled by either a physical button in the client device or a
-virtual button in the user interface. The PBC operation requires that
-a button is also pressed at the AP/Registrar at about the same time (2
-minute window). wpa_supplicant is notified of the local button event
-over the control interface, e.g., by calling wpa_cli:
-
-wpa_cli wps_pbc
-
-At this point, the AP/Registrar has two minutes to complete WPS
-negotiation which will generate a new WPA PSK in the same way as the
-PIN method described above.
-
-
-If the client wants to operate in the Registrar role to learn the
-current AP configuration and optionally, to configure an AP,
-wpa_supplicant is notified over the control interface, e.g., with
-wpa_cli:
-
-wpa_cli wps_reg <AP BSSID> <AP PIN>
-(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
-
-This is used to fetch the current AP settings instead of actually
-changing them. The main difference with the wps_pin command is that
-wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a
-PIN generated at the client.
-
-In order to change the AP configuration, the new configuration
-parameters are given to the wps_reg command:
-
-wpa_cli wps_reg <AP BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
-examples:
-  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678
-  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE ""
-
-<auth> must be one of the following: OPEN WPAPSK WPA2PSK
-<encr> must be one of the following: NONE WEP TKIP CCMP
-
-
-Scanning
---------
-
-Scan results ('wpa_cli scan_results' or 'wpa_cli bss <idx>') include a
-flags field that is used to indicate whether the BSS support WPS. If
-the AP support WPS, but has not recently activated a Registrar, [WPS]
-flag will be included. If PIN method has been recently selected,
-[WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode
-is in progress. GUI programs can use these as triggers for suggesting
-a guided WPS configuration to the user. In addition, control interface
-monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if
-there are WPS enabled APs in scan results without having to go through
-all the details in the GUI. These notification could be used, e.g., to
-suggest possible WPS connection to the user.
-
-
-wpa_gui
--------
-
-wpa_gui-qt4 directory contains a sample GUI that shows an example of
-how WPS support can be integrated into the GUI. Its main window has a
-WPS tab that guides user through WPS registration with automatic AP
-selection. In addition, it shows how WPS can be started manually by
-selecting an AP from scan results.
-
-
-Credential processing
----------------------
-
-By default, wpa_supplicant processes received credentials and updates
-its configuration internally. However, it is possible to
-control these operations from external programs, if desired.
-
-This internal processing can be disabled with wps_cred_processing=1
-option. When this is used, an external program is responsible for
-processing the credential attributes and updating wpa_supplicant
-configuration based on them.
-
-Following control interface messages are sent out for external programs:
-
-WPS-CRED-RECEIVED  <hexdump of Credential attribute(s)>
-For example:
-<2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727

Copied: vendor/wpa/2.0/wpa_supplicant/README-WPS (from rev 9639, vendor/wpa/dist/wpa_supplicant/README-WPS)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/README-WPS	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/README-WPS	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,377 @@
+wpa_supplicant and Wi-Fi Protected Setup (WPS)
+==============================================
+
+This document describes how the WPS implementation in wpa_supplicant
+can be configured and how an external component on the client (e.g.,
+management GUI) is used to enable WPS enrollment and registrar
+registration.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+  addition of new devices); this may be either in the AP ("internal
+  Registrar") or in an external device, e.g., a laptop, ("external
+  Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+wpa_supplicant implementation
+-----------------------------
+
+wpa_supplicant includes an optional WPS component that can be used as
+an Enrollee to enroll new network credential or as a Registrar to
+configure an AP.
+
+
+wpa_supplicant configuration
+----------------------------
+
+WPS is an optional component that needs to be enabled in
+wpa_supplicant build configuration (.config). Here is an example
+configuration that includes WPS support and Linux nl80211 -based
+driver interface:
+
+CONFIG_DRIVER_NL80211=y
+CONFIG_WPS=y
+CONFIG_WPS2=y
+
+If you want to enable WPS external registrar (ER) functionality, you
+will also need to add following line:
+
+CONFIG_WPS_ER=y
+
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
+
+WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
+the device. This is configured in the runtime configuration for
+wpa_supplicant (if not set, UUID will be generated based on local MAC
+address):
+
+# example UUID for WPS
+uuid=12345678-9abc-def0-1234-56789abcdef0
+
+The network configuration blocks needed for WPS are added
+automatically based on control interface commands, so they do not need
+to be added explicitly in the configuration file.
+
+WPS registration will generate new network blocks for the acquired
+credentials. If these are to be stored for future use (after
+restarting wpa_supplicant), wpa_supplicant will need to be configured
+to allow configuration file updates:
+
+update_config=1
+
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. wpa_supplicant uses the control interface as an input channel
+for these events.
+
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "wpa_cli wps_check_pin <PIN>" can be used to do such processing.
+It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum
+digit is incorrect, or the processed PIN (non-digit characters removed)
+if the PIN is valid.
+
+If the client device has a display, a random PIN has to be generated
+for each WPS registration session. wpa_supplicant can do this with a
+control interface request, e.g., by calling wpa_cli:
+
+wpa_cli wps_pin any
+
+This will return the generated 8-digit PIN which will then need to be
+entered at the Registrar to complete WPS registration. At that point,
+the client will be enrolled with credentials needed to connect to the
+AP to access the network.
+
+
+If the client device does not have a display that could show the
+random PIN, a hardcoded PIN that is printed on a label can be
+used. wpa_supplicant is notified this with a control interface
+request, e.g., by calling wpa_cli:
+
+wpa_cli wps_pin any 12345670
+
+This starts the WPS negotiation in the same way as above with the
+generated PIN.
+
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
+
+If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
+can be used to generate a new PIN without starting WPS negotiation.
+This random PIN can then be passed as an argument to another wps_pin
+call when the actual operation should be started.
+
+If the client design wants to support optional WPS PBC mode, this can
+be enabled by either a physical button in the client device or a
+virtual button in the user interface. The PBC operation requires that
+a button is also pressed at the AP/Registrar at about the same time (2
+minute window). wpa_supplicant is notified of the local button event
+over the control interface, e.g., by calling wpa_cli:
+
+wpa_cli wps_pbc
+
+At this point, the AP/Registrar has two minutes to complete WPS
+negotiation which will generate a new WPA PSK in the same way as the
+PIN method described above.
+
+
+If the client wants to operate in the Registrar role to learn the
+current AP configuration and optionally, to configure an AP,
+wpa_supplicant is notified over the control interface, e.g., with
+wpa_cli:
+
+wpa_cli wps_reg <AP BSSID> <AP PIN>
+(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
+
+This is used to fetch the current AP settings instead of actually
+changing them. The main difference with the wps_pin command is that
+wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a
+PIN generated at the client.
+
+In order to change the AP configuration, the new configuration
+parameters are given to the wps_reg command:
+
+wpa_cli wps_reg <AP BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
+examples:
+  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678
+  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+Scanning
+--------
+
+Scan results ('wpa_cli scan_results' or 'wpa_cli bss <idx>') include a
+flags field that is used to indicate whether the BSS support WPS. If
+the AP support WPS, but has not recently activated a Registrar, [WPS]
+flag will be included. If PIN method has been recently selected,
+[WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode
+is in progress. GUI programs can use these as triggers for suggesting
+a guided WPS configuration to the user. In addition, control interface
+monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if
+there are WPS enabled APs in scan results without having to go through
+all the details in the GUI. These notification could be used, e.g., to
+suggest possible WPS connection to the user.
+
+
+wpa_gui
+-------
+
+wpa_gui-qt4 directory contains a sample GUI that shows an example of
+how WPS support can be integrated into the GUI. Its main window has a
+WPS tab that guides user through WPS registration with automatic AP
+selection. In addition, it shows how WPS can be started manually by
+selecting an AP from scan results.
+
+
+Credential processing
+---------------------
+
+By default, wpa_supplicant processes received credentials and updates
+its configuration internally. However, it is possible to
+control these operations from external programs, if desired.
+
+This internal processing can be disabled with wps_cred_processing=1
+option. When this is used, an external program is responsible for
+processing the credential attributes and updating wpa_supplicant
+configuration based on them.
+
+Following control interface messages are sent out for external programs:
+
+WPS-CRED-RECEIVED  <hexdump of Credential attribute(s)>
+For example:
+<2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727
+
+
+wpa_supplicant as WPS External Registrar (ER)
+---------------------------------------------
+
+wpa_supplicant can be used as a WPS ER to configure an AP or enroll
+new Enrollee to join the network. This functionality uses UPnP and
+requires that a working IP connectivity is available with the AP (this
+can be either over a wired or wireless connection).
+
+Separate wpa_supplicant process can be started for WPS ER
+operations. A special "none" driver can be used in such a case to
+indicate that no local network interface is actually controlled. For
+example, following command could be used to start the ER:
+
+wpa_supplicant -Dnone -c er.conf -ieth0
+
+Sample er.conf:
+
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
+device_name=WPS External Registrar
+
+
+wpa_cli commands for ER functionality:
+
+wps_er_start [IP address]
+- start WPS ER functionality
+- the optional IP address parameter can be used to filter operations only
+  to include a single AP
+- if run again while ER is active, the stored information (discovered APs
+  and Enrollees) are shown again
+
+wps_er_stop
+- stop WPS ER functionality
+
+wps_er_learn <UUID> <AP PIN>
+- learn AP configuration
+
+wps_er_set_config <UUID> <network id>
+- use AP configuration from a locally configured network (e.g., from
+  wps_reg command); this does not change the AP's configuration, but
+  only prepares a configuration to be used when enrolling a new device
+  to the AP
+
+wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+- examples:
+  wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
+  wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+wps_er_pbc <Enrollee UUID>
+- accept an Enrollee PBC using External Registrar
+
+wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+- add an Enrollee PIN to External Registrar
+- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
+- if the MAC address of the enrollee is known, it should be configured
+  to allow the AP to advertise list of authorized enrollees
+
+
+WPS ER events:
+
+WPS_EVENT_ER_AP_ADD
+- WPS ER discovered an AP
+
+WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/
+
+WPS_EVENT_ER_AP_REMOVE
+- WPS ER removed an AP entry
+
+WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002
+
+WPS_EVENT_ER_ENROLLEE_ADD
+- WPS ER discovered a new Enrollee
+
+WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 pri_dev_type=1-0050F204-1 |Wireless Client|Company|cmodel|123|12345|
+
+WPS_EVENT_ER_ENROLLEE_REMOVE
+- WPS ER removed an Enrollee entry
+
+WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27
+
+WPS-ER-AP-SETTINGS
+- WPS ER learned AP settings
+
+WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the station acts as an Enrollee, a local NFC tag with a password
+token can be used by touching the NFC interface of a Registrar.
+
+"wps_nfc [BSSID]" command starts WPS protocol run with the local end as
+the Enrollee using the NFC password token that is either pre-configured
+in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The included nfc_pw_token tool
+(build with "make nfc_pw_token") can be used to generate NFC password
+tokens during manufacturing (each station needs to have its own random
+keys).
+
+If the station includes NFC interface and reads an NFC tag with a MIME
+media type "application/vnd.wfa.wsc", the NDEF message payload (with or
+without NDEF encapsulation) can be delivered to wpa_supplicant using the
+following wpa_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a configuration token, the network is added to
+wpa_supplicant configuration. If the NFC tag contains a password token,
+the token is added to the WPS Registrar component. This information can
+then be used with wps_reg command (when the NFC password token was from
+an AP) using a special value "nfc-pw" in place of the PIN parameter. If
+the ER functionality has been started (wps_er_start), the NFC password
+token is used to enable enrollment of a new station (that was the source
+of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.

Deleted: vendor/wpa/2.0/wpa_supplicant/README-Windows.txt
===================================================================
--- vendor/wpa/dist/wpa_supplicant/README-Windows.txt	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/README-Windows.txt	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,450 +0,0 @@
-wpa_supplicant for Windows
-==========================
-
-Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi> and contributors
-All Rights Reserved.
-
-This program is dual-licensed under both the GPL version 2 and BSD
-license. Either license may be used at your option.
-
-This product includes software developed by the OpenSSL Project
-for use in the OpenSSL Toolkit (http://www.openssl.org/). This
-product includes cryptographic software written by Eric Young
-(eay at cryptsoft.com).
-
-
-wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
-Supplicant on Windows. The current port requires that WinPcap
-(http://winpcap.polito.it/) is installed for accessing packets and the
-driver interface. Both release versions 3.0 and 3.1 are supported.
-
-The current port is still somewhat experimental. It has been tested
-mainly on Windows XP (SP2) with limited set of NDIS drivers. In
-addition, the current version has been reported to work with Windows
-2000.
-
-All security modes have been verified to work (at least complete
-authentication and successfully ping a wired host):
-- plaintext
-- static WEP / open system authentication
-- static WEP / shared key authentication
-- IEEE 802.1X with dynamic WEP keys
-- WPA-PSK, TKIP, CCMP, TKIP+CCMP
-- WPA-EAP, TKIP, CCMP, TKIP+CCMP
-- WPA2-PSK, TKIP, CCMP, TKIP+CCMP
-- WPA2-EAP, TKIP, CCMP, TKIP+CCMP
-
-
-Binary version
---------------
-
-Compiled binary version of the wpa_supplicant and additional tools is
-available from http://w1.fi/wpa_supplicant/. These binaries can be
-used after installing WinPcap.
-
-wpa_gui uses Qt 4 framework and may need additional dynamic libraries
-(DLLs). These libraries are available from
-http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
-You can copy the DLL files from this ZIP package into the same directory
-with wpa_gui.exe to allow wpa_gui to be started.
-
-
-Building wpa_supplicant with mingw
-----------------------------------
-
-The default build setup for wpa_supplicant is to use MinGW and
-cross-compiling from Linux to MinGW/Windows. It should also be
-possible to build this under Windows using the MinGW tools, but that
-is not tested nor supported and is likely to require some changes to
-the Makefile unless cygwin is used.
-
-
-Building wpa_supplicant with MSVC
----------------------------------
-
-wpa_supplicant can be built with Microsoft Visual C++ compiler. This
-has been tested with Microsoft Visual C++ Toolkit 2003 and Visual
-Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE
-can also be used by creating a project that includes the files and
-defines mentioned in nmake.mak. Example VS2005 solution and project
-files are included in vs2005 subdirectory. This can be used as a
-starting point for building the programs with VS2005 IDE. Visual Studio
-2008 Express Edition is also able to use these project files.
-
-WinPcap development package is needed for the build and this can be
-downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The
-default nmake.mak expects this to be unpacked into C:\dev\WpdPack so
-that Include and Lib directories are in this directory. The files can be
-stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to
-match with the selected directory. In case a project file in the IDE is
-used, these Include and Lib directories need to be added to project
-properties as additional include/library directories.
-
-OpenSSL source package can be downloaded from
-http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and
-installed following instructions in INSTALL.W32. Note that if EAP-FAST
-support will be included in the wpa_supplicant, OpenSSL needs to be
-patched to# support it openssl-0.9.8i-tls-extensions.patch. The example
-nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but
-this directory can be modified by changing OPENSSLDIR variable in
-nmake.mak.
-
-If you do not need EAP-FAST support, you may also be able to use Win32
-binary installation package of OpenSSL from
-http://www.slproweb.com/products/Win32OpenSSL.html instead of building
-the library yourself. In this case, you will need to copy Include and
-Lib directories in suitable directory, e.g., C:\dev\openssl for the
-default nmake.mak. Copy {Win32OpenSSLRoot}\include into
-C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with
-files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib).
-This will end up using dynamically linked OpenSSL (i.e., .dll files are
-needed) for it. Alternative, you can copy files from
-{Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll
-files needed).
-
-
-Building wpa_supplicant for cygwin
-----------------------------------
-
-wpa_supplicant can be built for cygwin by installing the needed
-development packages for cygwin. This includes things like compiler,
-make, openssl development package, etc. In addition, developer's pack
-for WinPcap (WPdpack.zip) from
-http://winpcap.polito.it/install/default.htm is needed.
-
-.config file should enable only one driver interface,
-CONFIG_DRIVER_NDIS. In addition, include directories may need to be
-added to match the system. An example configuration is available in
-defconfig. The library and include files for WinPcap will either need
-to be installed in compiler/linker default directories or their
-location will need to be adding to .config when building
-wpa_supplicant.
-
-Othen than this, the build should be more or less identical to Linux
-version, i.e., just run make after having created .config file. An
-additional tool, win_if_list.exe, can be built by running "make
-win_if_list".
-
-
-Building wpa_gui
-----------------
-
-wpa_gui uses Qt application framework from Trolltech. It can be built
-with the open source version of Qt4 and MinGW. Following commands can
-be used to build the binary in the Qt 4 Command Prompt:
-
-# go to the root directory of wpa_supplicant source code
-cd wpa_gui-qt4
-qmake -o Makefile wpa_gui.pro
-make
-# the wpa_gui.exe binary is created into 'release' subdirectory
-
-
-Using wpa_supplicant for Windows
---------------------------------
-
-wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to
-Linux version, so instructions in README and example wpa_supplicant.conf
-should be applicable for most parts. In addition, there is another
-version of wpa_supplicant, wpasvc.exe, which can be used as a Windows
-service and which reads its configuration from registry instead of
-text file.
-
-When using access points in "hidden SSID" mode, ap_scan=2 mode need to
-be used (see wpa_supplicant.conf for more information).
-
-Windows NDIS/WinPcap uses quite long interface names, so some care
-will be needed when starting wpa_supplicant. Alternatively, the
-adapter description can be used as the interface name which may be
-easier since it is usually in more human-readable
-format. win_if_list.exe can be used to find out the proper interface
-name.
-
-Example steps in starting up wpa_supplicant:
-
-# win_if_list.exe
-ifname: \Device\NPF_GenericNdisWanAdapter
-description: Generic NdisWan adapter
-
-ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2}
-description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler)
-
-ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211}
-description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler)
-
-
-Since the example configuration used Atheros WLAN card, the middle one
-is the correct interface in this case. The interface name for -i
-command line option is the full string following "ifname:" (the
-"\Device\NPF_" prefix can be removed). In other words, wpa_supplicant
-would be started with the following command:
-
-# wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d
-
--d optional enables some more debugging (use -dd for even more, if
-needed). It can be left out if debugging information is not needed.
-
-With the alternative mechanism for selecting the interface, this
-command has identical results in this case:
-
-# wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d
-
-
-Simple configuration example for WPA-PSK:
-
-#ap_scan=2
-ctrl_interface=
-network={
-	ssid="test"
-	key_mgmt=WPA-PSK
-	proto=WPA
-	pairwise=TKIP
-	psk="secret passphrase"
-}
-
-(remove '#' from the comment out ap_scan line to enable mode in which
-wpa_supplicant tries to associate with the SSID without doing
-scanning; this allows APs with hidden SSIDs to be used)
-
-
-wpa_cli.exe and wpa_gui.exe can be used to interact with the
-wpa_supplicant.exe program in the same way as with Linux. Note that
-ctrl_interface is using UNIX domain sockets when built for cygwin, but
-the native build for Windows uses named pipes and the contents of the
-ctrl_interface configuration item is used to control access to the
-interface. Anyway, this variable has to be included in the configuration
-to enable the control interface.
-
-
-Example SDDL string formats:
-
-(local admins group has permission, but nobody else):
-
-ctrl_interface=SDDL=D:(A;;GA;;;BA)
-
-("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and
-"BA" == "builtin administrators" == the local admins.  The empty fields
-are for flags and object GUIDs, none of which should be required in this
-case.)
-
-(local admins and the local "power users" group have permissions,
-but nobody else):
-
-ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU)
-
-(One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and
-one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.)
-
-(close to wide open, but you have to be a valid user on
-the machine):
-
-ctrl_interface=SDDL=D:(A;;GA;;;AU)
-
-(One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users"
-group.)
-
-This one would allow absolutely everyone (including anonymous
-users) -- this is *not* recommended, since named pipes can be attached
-to from anywhere on the network (i.e. there's no "this machine only"
-like there is with 127.0.0.1 sockets):
-
-ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN)
-
-(BU == "builtin users", "AN" == "anonymous")
-
-See also [1] for the format of ACEs, and [2] for the possible strings
-that can be used for principal names.
-
-[1]
-http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp
-[2]
-http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp
-
-
-Starting wpa_supplicant as a Windows service (wpasvc.exe)
----------------------------------------------------------
-
-wpa_supplicant can be started as a Windows service by using wpasvc.exe
-program that is alternative build of wpa_supplicant.exe. Most of the
-core functionality of wpasvc.exe is identical to wpa_supplicant.exe,
-but it is using Windows registry for configuration information instead
-of a text file and command line parameters. In addition, it can be
-registered as a service that can be started automatically or manually
-like any other Windows service.
-
-The root of wpa_supplicant configuration in registry is
-HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global
-parameters and a 'interfaces' subkey with all the interface configuration
-(adapter to confname mapping). Each such mapping is a subkey that has
-'adapter', 'config', and 'ctrl_interface' values.
-
-This program can be run either as a normal command line application,
-e.g., for debugging, with 'wpasvc.exe app' or as a Windows service.
-Service need to be registered with 'wpasvc.exe reg <full path to
-wpasvc.exe>'. Alternatively, 'wpasvc.exe reg' can be used to register
-the service with the current location of wpasvc.exe. After this, wpasvc
-can be started like any other Windows service (e.g., 'net start wpasvc')
-or it can be configured to start automatically through the Services tool
-in administrative tasks. The service can be unregistered with
-'wpasvc.exe unreg'.
-
-If the service is set to start during system bootup to make the
-network connection available before any user has logged in, there may
-be a long (half a minute or so) delay in starting up wpa_supplicant
-due to WinPcap needing a driver called "Network Monitor Driver" which
-is started by default on demand.
-
-To speed up wpa_supplicant start during system bootup, "Network
-Monitor Driver" can be configured to be started sooner by setting its
-startup type to System instead of the default Demand. To do this, open
-up Device Manager, select Show Hidden Devices, expand the "Non
-Plug-and-Play devices" branch, double click "Network Monitor Driver",
-go to the Driver tab, and change the Demand setting to System instead.
-
-Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs
-key. Each configuration profile has its own key under this. In terms of text
-files, each profile would map to a separate text file with possibly multiple
-networks. Under each profile, there is a networks key that lists all
-networks as a subkey. Each network has set of values in the same way as
-network block in the configuration file. In addition, blobs subkey has
-possible blobs as values.
-
-HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
-   ssid="example"
-   key_mgmt=WPA-PSK
-
-See win_example.reg for an example on how to setup wpasvc.exe
-parameters in registry. It can also be imported to registry as a
-starting point for the configuration.
-
-
-
-License information for third party software used in this product:
-
-  OpenSSL License
-  ---------------
-
-/* ====================================================================
- * Copyright (c) 1998-2004 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer. 
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core at openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay at cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh at cryptsoft.com).
- *
- */
-
- Original SSLeay License
- -----------------------
-
-/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay at cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- * 
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh at cryptsoft.com).
- * 
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay at cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from 
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
- * 
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * 
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-
-
-   Qt Open Source Edition
-   ----------------------
-
-The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA.
-Qt Open Source Edition is licensed under GPL version 2.
-
-Source code for the library is available at
-http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip

Deleted: vendor/wpa/2.0/wpa_supplicant/ap.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ap.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,481 +0,0 @@
-/*
- * WPA Supplicant - Basic AP mode support routines
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2009, Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
-#include "ap/hostapd.h"
-#include "ap/ap_config.h"
-#ifdef NEED_AP_MLME
-#include "ap/ieee802_11.h"
-#endif /* NEED_AP_MLME */
-#include "ap/ieee802_1x.h"
-#include "ap/wps_hostapd.h"
-#include "ap/ctrl_iface_ap.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "eap_common/eap_wsc_common.h"
-#include "wps/wps.h"
-#include "config_ssid.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "ap.h"
-
-
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
-				  struct wpa_ssid *ssid,
-				  struct hostapd_config *conf)
-{
-	struct hostapd_bss_config *bss = &conf->bss[0];
-	int pairwise;
-
-	conf->driver = wpa_s->driver;
-
-	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
-
-	if (ssid->frequency == 0) {
-		/* default channel 11 */
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-		conf->channel = 11;
-	} else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-		conf->channel = (ssid->frequency - 2407) / 5;
-	} else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
-		   (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
-		conf->channel = (ssid->frequency - 5000) / 5;
-	} else {
-		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
-			   ssid->frequency);
-		return -1;
-	}
-
-	/* TODO: enable HT if driver supports it;
-	 * drop to 11b if driver does not support 11g */
-
-	if (ssid->ssid_len == 0) {
-		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
-		return -1;
-	}
-	os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
-	bss->ssid.ssid[ssid->ssid_len] = '\0';
-	bss->ssid.ssid_len = ssid->ssid_len;
-	bss->ssid.ssid_set = 1;
-
-	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
-		bss->wpa = ssid->proto;
-	bss->wpa_key_mgmt = ssid->key_mgmt;
-	bss->wpa_pairwise = ssid->pairwise_cipher;
-	if (ssid->passphrase) {
-		bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
-	} else if (ssid->psk_set) {
-		os_free(bss->ssid.wpa_psk);
-		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
-		if (bss->ssid.wpa_psk == NULL)
-			return -1;
-		os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
-		bss->ssid.wpa_psk->group = 1;
-	}
-
-	/* Select group cipher based on the enabled pairwise cipher suites */
-	pairwise = 0;
-	if (bss->wpa & 1)
-		pairwise |= bss->wpa_pairwise;
-	if (bss->wpa & 2) {
-		if (bss->rsn_pairwise == 0)
-			bss->rsn_pairwise = bss->wpa_pairwise;
-		pairwise |= bss->rsn_pairwise;
-	}
-	if (pairwise & WPA_CIPHER_TKIP)
-		bss->wpa_group = WPA_CIPHER_TKIP;
-	else
-		bss->wpa_group = WPA_CIPHER_CCMP;
-
-	if (bss->wpa && bss->ieee802_1x)
-		bss->ssid.security_policy = SECURITY_WPA;
-	else if (bss->wpa)
-		bss->ssid.security_policy = SECURITY_WPA_PSK;
-	else if (bss->ieee802_1x) {
-		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
-		bss->ssid.wep.default_len = bss->default_wep_key_len;
-	} else if (bss->ssid.wep.keys_set)
-		bss->ssid.security_policy = SECURITY_STATIC_WEP;
-	else
-		bss->ssid.security_policy = SECURITY_PLAINTEXT;
-
-#ifdef CONFIG_WPS
-	/*
-	 * Enable WPS by default, but require user interaction to actually use
-	 * it. Only the internal Registrar is supported.
-	 */
-	bss->eap_server = 1;
-	bss->wps_state = 2;
-	bss->ap_setup_locked = 1;
-	if (wpa_s->conf->config_methods)
-		bss->config_methods = os_strdup(wpa_s->conf->config_methods);
-	if (wpa_s->conf->device_type)
-		bss->device_type = os_strdup(wpa_s->conf->device_type);
-#endif /* CONFIG_WPS */
-
-	return 0;
-}
-
-
-static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
-{
-}
-
-
-static int ap_probe_req_rx(void *ctx, const u8 *addr, const u8 *ie,
-			   size_t ie_len)
-{
-	return 0;
-}
-
-
-static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
-				  const u8 *uuid_e)
-{
-}
-
-
-int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
-			     struct wpa_ssid *ssid)
-{
-	struct wpa_driver_associate_params params;
-	struct hostapd_iface *hapd_iface;
-	struct hostapd_config *conf;
-	size_t i;
-
-	if (ssid->ssid == NULL || ssid->ssid_len == 0) {
-		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
-		return -1;
-	}
-
-	wpa_supplicant_ap_deinit(wpa_s);
-
-	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
-		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-
-	os_memset(&params, 0, sizeof(params));
-	params.ssid = ssid->ssid;
-	params.ssid_len = ssid->ssid_len;
-	switch (ssid->mode) {
-	case WPAS_MODE_INFRA:
-		params.mode = IEEE80211_MODE_INFRA;
-		break;
-	case WPAS_MODE_IBSS:
-		params.mode = IEEE80211_MODE_IBSS;
-		break;
-	case WPAS_MODE_AP:
-		params.mode = IEEE80211_MODE_AP;
-		break;
-	}
-	params.freq = ssid->frequency;
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
-		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
-	else
-		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
-	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
-
-	if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
-		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-	else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
-		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
-	else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
-		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-	else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
-			   "cipher.");
-		return -1;
-	}
-	params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
-	params.group_suite = params.pairwise_suite;
-
-	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));
-	if (hapd_iface == NULL)
-		return -1;
-	hapd_iface->owner = wpa_s;
-
-	wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
-	if (conf == NULL) {
-		wpa_supplicant_ap_deinit(wpa_s);
-		return -1;
-	}
-
-	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
-		wpa_printf(MSG_ERROR, "Failed to create AP configuration");
-		wpa_supplicant_ap_deinit(wpa_s);
-		return -1;
-	}
-
-	hapd_iface->num_bss = conf->num_bss;
-	hapd_iface->bss = os_zalloc(conf->num_bss *
-				    sizeof(struct hostapd_data *));
-	if (hapd_iface->bss == NULL) {
-		wpa_supplicant_ap_deinit(wpa_s);
-		return -1;
-	}
-
-	for (i = 0; i < conf->num_bss; i++) {
-		hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
-		if (hapd_iface->bss[i] == NULL) {
-			wpa_supplicant_ap_deinit(wpa_s);
-			return -1;
-		}
-
-		hapd_iface->bss[i]->msg_ctx = wpa_s;
-		hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
-		hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
-		hostapd_register_probereq_cb(hapd_iface->bss[i],
-					     ap_probe_req_rx, wpa_s);
-		hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
-		hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
-	}
-
-	os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
-	hapd_iface->bss[0]->driver = wpa_s->driver;
-	hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
-
-	if (hostapd_setup_interface(wpa_s->ap_iface)) {
-		wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
-		wpa_supplicant_ap_deinit(wpa_s);
-		return -1;
-	}
-
-	wpa_s->current_ssid = ssid;
-	os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
-	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
-	if (wpa_s->ap_configured_cb)
-		wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
-					wpa_s->ap_configured_cb_data);
-
-	return 0;
-}
-
-
-void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->ap_iface == NULL)
-		return;
-
-	wpa_s->current_ssid = NULL;
-	hostapd_interface_deinit(wpa_s->ap_iface);
-	hostapd_interface_free(wpa_s->ap_iface);
-	wpa_s->ap_iface = NULL;
-	wpa_drv_deinit_ap(wpa_s);
-}
-
-
-void ap_tx_status(void *ctx, const u8 *addr,
-		  const u8 *buf, size_t len, int ack)
-{
-#ifdef NEED_AP_MLME
-	struct wpa_supplicant *wpa_s = ctx;
-	hostapd_tx_status(wpa_s->ap_iface->bss[0], addr, buf, len, ack);
-#endif /* NEED_AP_MLME */
-}
-
-
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len)
-{
-#ifdef NEED_AP_MLME
-	struct wpa_supplicant *wpa_s = ctx;
-	const struct ieee80211_hdr *hdr =
-		(const struct ieee80211_hdr *) frame;
-	u16 fc = le_to_host16(hdr->frame_control);
-	ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], hdr->addr2,
-				   (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-				   (WLAN_FC_TODS | WLAN_FC_FROMDS));
-#endif /* NEED_AP_MLME */
-}
-
-
-void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt)
-{
-#ifdef NEED_AP_MLME
-	struct wpa_supplicant *wpa_s = ctx;
-	struct hostapd_frame_info fi;
-	os_memset(&fi, 0, sizeof(fi));
-	fi.datarate = rx_mgmt->datarate;
-	fi.ssi_signal = rx_mgmt->ssi_signal;
-	ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame,
-			rx_mgmt->frame_len, &fi);
-#endif /* NEED_AP_MLME */
-}
-
-
-void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok)
-{
-#ifdef NEED_AP_MLME
-	struct wpa_supplicant *wpa_s = ctx;
-	ieee802_11_mgmt_cb(wpa_s->ap_iface->bss[0], buf, len, stype, ok);
-#endif /* NEED_AP_MLME */
-}
-
-
-void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
-				const u8 *src_addr, const u8 *buf, size_t len)
-{
-	ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len);
-}
-
-
-#ifdef CONFIG_WPS
-
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	if (!wpa_s->ap_iface)
-		return -1;
-	return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0]);
-}
-
-
-int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			      const char *pin, char *buf, size_t buflen)
-{
-	int ret, ret_len = 0;
-
-	if (!wpa_s->ap_iface)
-		return -1;
-
-	if (pin == NULL) {
-		unsigned int rpin = wps_generate_pin();
-		ret_len = os_snprintf(buf, buflen, "%d", rpin);
-		pin = buf;
-	}
-
-	ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
-	if (ret)
-		return -1;
-	return ret_len;
-}
-
-#endif /* CONFIG_WPS */
-
-
-#ifdef CONFIG_CTRL_IFACE
-
-int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
-			    char *buf, size_t buflen)
-{
-	if (wpa_s->ap_iface == NULL)
-		return -1;
-	return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
-					    buf, buflen);
-}
-
-
-int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
-		      char *buf, size_t buflen)
-{
-	if (wpa_s->ap_iface == NULL)
-		return -1;
-	return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
-				      buf, buflen);
-}
-
-
-int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
-			   char *buf, size_t buflen)
-{
-	if (wpa_s->ap_iface == NULL)
-		return -1;
-	return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
-					   buf, buflen);
-}
-
-
-int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
-				 size_t buflen, int verbose)
-{
-	char *pos = buf, *end = buf + buflen;
-	int ret;
-	struct hostapd_bss_config *conf;
-
-	if (wpa_s->ap_iface == NULL)
-		return -1;
-
-	conf = wpa_s->ap_iface->bss[0]->conf;
-	if (conf->wpa == 0)
-		return 0;
-
-	ret = os_snprintf(pos, end - pos,
-			  "pairwise_cipher=%s\n"
-			  "group_cipher=%s\n"
-			  "key_mgmt=%s\n",
-			  wpa_cipher_txt(conf->rsn_pairwise),
-			  wpa_cipher_txt(conf->wpa_group),
-			  wpa_key_mgmt_txt(conf->wpa_key_mgmt,
-					   conf->wpa));
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-	return pos - buf;
-}
-
-#endif /* CONFIG_CTRL_IFACE */
-
-
-int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
-				      const u8 *addr)
-{
-	struct hostapd_data *hapd;
-	struct hostapd_bss_config *conf;
-
-	if (!wpa_s->ap_iface)
-		return -1;
-
-	if (addr)
-		wpa_printf(MSG_DEBUG, "AP: Set MAC address filter: " MACSTR,
-			   MAC2STR(addr));
-	else
-		wpa_printf(MSG_DEBUG, "AP: Clear MAC address filter");
-
-	hapd = wpa_s->ap_iface->bss[0];
-	conf = hapd->conf;
-
-	os_free(conf->accept_mac);
-	conf->accept_mac = NULL;
-	conf->num_accept_mac = 0;
-	os_free(conf->deny_mac);
-	conf->deny_mac = NULL;
-	conf->num_deny_mac = 0;
-
-	if (addr == NULL) {
-		conf->macaddr_acl = ACCEPT_UNLESS_DENIED;
-		return 0;
-	}
-
-	conf->macaddr_acl = DENY_UNLESS_ACCEPTED;
-	conf->accept_mac = os_zalloc(sizeof(struct mac_acl_entry));
-	if (conf->accept_mac == NULL)
-		return -1;
-	os_memcpy(conf->accept_mac[0].addr, addr, ETH_ALEN);
-	conf->num_accept_mac = 1;
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ap.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ap.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ap.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ap.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1033 @@
+/*
+ * WPA Supplicant - Basic AP mode support routines
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#ifdef NEED_AP_MLME
+#include "ap/ieee802_11.h"
+#endif /* NEED_AP_MLME */
+#include "ap/beacon.h"
+#include "ap/ieee802_1x.h"
+#include "ap/wps_hostapd.h"
+#include "ap/ctrl_iface_ap.h"
+#include "wps/wps.h"
+#include "common/ieee802_11_defs.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "p2p_supplicant.h"
+#include "ap.h"
+#include "ap/sta_info.h"
+#include "notify.h"
+
+
+#ifdef CONFIG_WPS
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+#endif /* CONFIG_WPS */
+
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid,
+				  struct hostapd_config *conf)
+{
+	struct hostapd_bss_config *bss = &conf->bss[0];
+	int pairwise;
+
+	conf->driver = wpa_s->driver;
+
+	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
+
+	if (ssid->frequency == 0) {
+		/* default channel 11 */
+		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+		conf->channel = 11;
+	} else if (ssid->frequency >= 2412 && ssid->frequency <= 2472) {
+		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+		conf->channel = (ssid->frequency - 2407) / 5;
+	} else if ((ssid->frequency >= 5180 && ssid->frequency <= 5240) ||
+		   (ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
+		conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+		conf->channel = (ssid->frequency - 5000) / 5;
+	} else if (ssid->frequency >= 56160 + 2160 * 1 &&
+		   ssid->frequency <= 56160 + 2160 * 4) {
+		conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+		conf->channel = (ssid->frequency - 56160) / 2160;
+	} else {
+		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+			   ssid->frequency);
+		return -1;
+	}
+
+	/* TODO: enable HT40 if driver supports it;
+	 * drop to 11b if driver does not support 11g */
+
+#ifdef CONFIG_IEEE80211N
+	/*
+	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n
+	 * and a mask of allowed capabilities within conf->ht_capab.
+	 * Using default config settings for: conf->ht_op_mode_fixed,
+	 * conf->secondary_channel, conf->require_ht
+	 */
+	if (wpa_s->hw.modes) {
+		struct hostapd_hw_modes *mode = NULL;
+		int i, no_ht = 0;
+		for (i = 0; i < wpa_s->hw.num_modes; i++) {
+			if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
+				mode = &wpa_s->hw.modes[i];
+				break;
+			}
+		}
+
+#ifdef CONFIG_HT_OVERRIDES
+		if (ssid->disable_ht) {
+			conf->ieee80211n = 0;
+			conf->ht_capab = 0;
+			no_ht = 1;
+		}
+#endif /* CONFIG_HT_OVERRIDES */
+
+		if (!no_ht && mode && mode->ht_capab) {
+			conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+			if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+			    (mode->ht_capab &
+			     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+			    ssid->ht40)
+				conf->secondary_channel =
+					wpas_p2p_get_ht40_mode(wpa_s, mode,
+							       conf->channel);
+			if (conf->secondary_channel)
+				conf->ht_capab |=
+					HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
+
+			/*
+			 * white-list capabilities that won't cause issues
+			 * to connecting stations, while leaving the current
+			 * capabilities intact (currently disabled SMPS).
+			 */
+			conf->ht_capab |= mode->ht_capab &
+				(HT_CAP_INFO_GREEN_FIELD |
+				 HT_CAP_INFO_SHORT_GI20MHZ |
+				 HT_CAP_INFO_SHORT_GI40MHZ |
+				 HT_CAP_INFO_RX_STBC_MASK |
+				 HT_CAP_INFO_MAX_AMSDU_SIZE);
+		}
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_P2P
+	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+		/* Remove 802.11b rates from supported and basic rate sets */
+		int *list = os_malloc(4 * sizeof(int));
+		if (list) {
+			list[0] = 60;
+			list[1] = 120;
+			list[2] = 240;
+			list[3] = -1;
+		}
+		conf->basic_rates = list;
+
+		list = os_malloc(9 * sizeof(int));
+		if (list) {
+			list[0] = 60;
+			list[1] = 90;
+			list[2] = 120;
+			list[3] = 180;
+			list[4] = 240;
+			list[5] = 360;
+			list[6] = 480;
+			list[7] = 540;
+			list[8] = -1;
+		}
+		conf->supported_rates = list;
+	}
+
+	bss->isolate = !wpa_s->conf->p2p_intra_bss;
+#endif /* CONFIG_P2P */
+
+	if (ssid->ssid_len == 0) {
+		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
+		return -1;
+	}
+	os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
+	bss->ssid.ssid_len = ssid->ssid_len;
+	bss->ssid.ssid_set = 1;
+
+	bss->ignore_broadcast_ssid = ssid->ignore_broadcast_ssid;
+
+	if (ssid->auth_alg)
+		bss->auth_algs = ssid->auth_alg;
+
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
+		bss->wpa = ssid->proto;
+	bss->wpa_key_mgmt = ssid->key_mgmt;
+	bss->wpa_pairwise = ssid->pairwise_cipher;
+	if (ssid->psk_set) {
+		os_free(bss->ssid.wpa_psk);
+		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+		if (bss->ssid.wpa_psk == NULL)
+			return -1;
+		os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
+		bss->ssid.wpa_psk->group = 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] ||
+		   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
+		struct hostapd_wep_keys *wep = &bss->ssid.wep;
+		int i;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (ssid->wep_key_len[i] == 0)
+				continue;
+			wep->key[i] = os_malloc(ssid->wep_key_len[i]);
+			if (wep->key[i] == NULL)
+				return -1;
+			os_memcpy(wep->key[i], ssid->wep_key[i],
+				  ssid->wep_key_len[i]);
+			wep->len[i] = ssid->wep_key_len[i];
+		}
+		wep->idx = ssid->wep_tx_keyidx;
+		wep->keys_set = 1;
+	}
+
+	if (ssid->ap_max_inactivity)
+		bss->ap_max_inactivity = ssid->ap_max_inactivity;
+
+	if (ssid->dtim_period)
+		bss->dtim_period = ssid->dtim_period;
+
+	/* Select group cipher based on the enabled pairwise cipher suites */
+	pairwise = 0;
+	if (bss->wpa & 1)
+		pairwise |= bss->wpa_pairwise;
+	if (bss->wpa & 2) {
+		if (bss->rsn_pairwise == 0)
+			bss->rsn_pairwise = bss->wpa_pairwise;
+		pairwise |= bss->rsn_pairwise;
+	}
+	if (pairwise & WPA_CIPHER_TKIP)
+		bss->wpa_group = WPA_CIPHER_TKIP;
+	else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+		 WPA_CIPHER_GCMP)
+		bss->wpa_group = WPA_CIPHER_GCMP;
+	else
+		bss->wpa_group = WPA_CIPHER_CCMP;
+
+	if (bss->wpa && bss->ieee802_1x)
+		bss->ssid.security_policy = SECURITY_WPA;
+	else if (bss->wpa)
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+
+#ifdef CONFIG_WPS
+	/*
+	 * Enable WPS by default for open and WPA/WPA2-Personal network, but
+	 * require user interaction to actually use it. Only the internal
+	 * Registrar is supported.
+	 */
+	if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
+	    bss->ssid.security_policy != SECURITY_PLAINTEXT)
+		goto no_wps;
+#ifdef CONFIG_WPS2
+	if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
+	    (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+		goto no_wps; /* WPS2 does not allow WPA/TKIP-only
+			      * configuration */
+#endif /* CONFIG_WPS2 */
+	bss->eap_server = 1;
+
+	if (!ssid->ignore_broadcast_ssid)
+		bss->wps_state = 2;
+
+	bss->ap_setup_locked = 2;
+	if (wpa_s->conf->config_methods)
+		bss->config_methods = os_strdup(wpa_s->conf->config_methods);
+	os_memcpy(bss->device_type, wpa_s->conf->device_type,
+		  WPS_DEV_TYPE_LEN);
+	if (wpa_s->conf->device_name) {
+		bss->device_name = os_strdup(wpa_s->conf->device_name);
+		bss->friendly_name = os_strdup(wpa_s->conf->device_name);
+	}
+	if (wpa_s->conf->manufacturer)
+		bss->manufacturer = os_strdup(wpa_s->conf->manufacturer);
+	if (wpa_s->conf->model_name)
+		bss->model_name = os_strdup(wpa_s->conf->model_name);
+	if (wpa_s->conf->model_number)
+		bss->model_number = os_strdup(wpa_s->conf->model_number);
+	if (wpa_s->conf->serial_number)
+		bss->serial_number = os_strdup(wpa_s->conf->serial_number);
+	if (is_nil_uuid(wpa_s->conf->uuid))
+		os_memcpy(bss->uuid, wpa_s->wps->uuid, WPS_UUID_LEN);
+	else
+		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;
+no_wps:
+#endif /* CONFIG_WPS */
+
+	if (wpa_s->max_stations &&
+	    wpa_s->max_stations < wpa_s->conf->max_num_sta)
+		bss->max_num_sta = wpa_s->max_stations;
+	else
+		bss->max_num_sta = wpa_s->conf->max_num_sta;
+
+	bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+
+	return 0;
+}
+
+
+static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *wpa_s = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	size_t hdr_len;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+	if (hdr_len > len)
+		return;
+	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+			   mgmt->u.action.category,
+			   &mgmt->u.action.u.vs_public_action.action,
+			   len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_event_cb(void *ctx, enum wps_event event,
+			    union wps_event_data *data)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (event == WPS_EV_FAIL) {
+		struct wps_event_fail *fail = &data->fail;
+
+		if (wpa_s->parent && wpa_s->parent != 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
+				"msg=%d config_error=%d",
+				fail->msg, fail->config_error);
+		}
+		wpas_p2p_wps_failed(wpa_s, fail);
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
+				 int authorized, const u8 *p2p_dev_addr)
+{
+	wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
+}
+
+
+static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *wpa_s = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	size_t hdr_len;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+	if (hdr_len > len)
+		return -1;
+	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+			   mgmt->u.action.category,
+			   &mgmt->u.action.u.vs_public_action.action,
+			   len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+	return 0;
+}
+
+
+static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
+			   const u8 *bssid, const u8 *ie, size_t ie_len,
+			   int ssi_signal)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
+				     ssi_signal);
+#else /* CONFIG_P2P */
+	return 0;
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
+				  const u8 *uuid_e)
+{
+#ifdef CONFIG_P2P
+	struct wpa_supplicant *wpa_s = ctx;
+	wpas_p2p_wps_success(wpa_s, mac_addr, 1);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_ap_configured_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+	if (wpa_s->ap_configured_cb)
+		wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
+					wpa_s->ap_configured_cb_data);
+}
+
+
+int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid)
+{
+	struct wpa_driver_associate_params params;
+	struct hostapd_iface *hapd_iface;
+	struct hostapd_config *conf;
+	size_t i;
+
+	if (ssid->ssid == NULL || ssid->ssid_len == 0) {
+		wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
+		return -1;
+	}
+
+	wpa_supplicant_ap_deinit(wpa_s);
+
+	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
+		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+	os_memset(&params, 0, sizeof(params));
+	params.ssid = ssid->ssid;
+	params.ssid_len = ssid->ssid_len;
+	switch (ssid->mode) {
+	case WPAS_MODE_INFRA:
+		params.mode = IEEE80211_MODE_INFRA;
+		break;
+	case WPAS_MODE_IBSS:
+		params.mode = IEEE80211_MODE_IBSS;
+		break;
+	case WPAS_MODE_AP:
+	case WPAS_MODE_P2P_GO:
+	case WPAS_MODE_P2P_GROUP_FORMATION:
+		params.mode = IEEE80211_MODE_AP;
+		break;
+	}
+	params.freq = ssid->frequency;
+
+	params.wpa_proto = ssid->proto;
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
+	else
+		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
+	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+
+	if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
+		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+	else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
+		wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+	else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
+		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
+	else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
+		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+	else {
+		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
+			   "cipher.");
+		return -1;
+	}
+	params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+	params.group_suite = params.pairwise_suite;
+
+#ifdef CONFIG_P2P
+	if (ssid->mode == WPAS_MODE_P2P_GO ||
+	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+		params.p2p = 1;
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->parent->set_ap_uapsd)
+		params.uapsd = wpa_s->parent->ap_uapsd;
+	else
+		params.uapsd = -1;
+
+	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));
+	if (hapd_iface == NULL)
+		return -1;
+	hapd_iface->owner = wpa_s;
+	hapd_iface->drv_flags = wpa_s->drv_flags;
+	hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
+
+	wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
+	if (conf == NULL) {
+		wpa_supplicant_ap_deinit(wpa_s);
+		return -1;
+	}
+
+	os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+		  wpa_s->conf->wmm_ac_params,
+		  sizeof(wpa_s->conf->wmm_ac_params));
+
+	if (params.uapsd > 0) {
+		conf->bss->wmm_enabled = 1;
+		conf->bss->wmm_uapsd = 1;
+	}
+
+	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
+		wpa_printf(MSG_ERROR, "Failed to create AP configuration");
+		wpa_supplicant_ap_deinit(wpa_s);
+		return -1;
+	}
+
+#ifdef CONFIG_P2P
+	if (ssid->mode == WPAS_MODE_P2P_GO)
+		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+		conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+			P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
+	hapd_iface->num_bss = conf->num_bss;
+	hapd_iface->bss = os_calloc(conf->num_bss,
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL) {
+		wpa_supplicant_ap_deinit(wpa_s);
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd_iface->bss[i] == NULL) {
+			wpa_supplicant_ap_deinit(wpa_s);
+			return -1;
+		}
+
+		hapd_iface->bss[i]->msg_ctx = wpa_s;
+		hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
+		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;
+		hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s;
+		hostapd_register_probereq_cb(hapd_iface->bss[i],
+					     ap_probe_req_rx, wpa_s);
+		hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
+		hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
+		hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb;
+		hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s;
+		hapd_iface->bss[i]->sta_authorized_cb = ap_sta_authorized_cb;
+		hapd_iface->bss[i]->sta_authorized_cb_ctx = wpa_s;
+#ifdef CONFIG_P2P
+		hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
+		hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(wpa_s,
+								    ssid);
+#endif /* CONFIG_P2P */
+		hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
+		hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
+	}
+
+	os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
+	hapd_iface->bss[0]->driver = wpa_s->driver;
+	hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
+
+	wpa_s->current_ssid = ssid;
+	os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
+	wpa_s->assoc_freq = ssid->frequency;
+
+	if (hostapd_setup_interface(wpa_s->ap_iface)) {
+		wpa_printf(MSG_ERROR, "Failed to initialize AP interface");
+		wpa_supplicant_ap_deinit(wpa_s);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS
+	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+#endif /* CONFIG_WPS */
+
+	if (wpa_s->ap_iface == NULL)
+		return;
+
+	wpa_s->current_ssid = NULL;
+	wpa_s->assoc_freq = 0;
+#ifdef CONFIG_P2P
+	if (wpa_s->ap_iface->bss)
+		wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+	wpas_p2p_group_deinit(wpa_s);
+#endif /* CONFIG_P2P */
+	hostapd_interface_deinit(wpa_s->ap_iface);
+	hostapd_interface_free(wpa_s->ap_iface);
+	wpa_s->ap_iface = NULL;
+	wpa_drv_deinit_ap(wpa_s);
+}
+
+
+void ap_tx_status(void *ctx, const u8 *addr,
+		  const u8 *buf, size_t len, int ack)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	hostapd_tx_status(wpa_s->ap_iface->bss[0], addr, buf, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+			const u8 *data, size_t len, int ack)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_client_poll_ok(void *ctx, const u8 *addr)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->ap_iface)
+		hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	struct hostapd_frame_info fi;
+	os_memset(&fi, 0, sizeof(fi));
+	fi.datarate = rx_mgmt->datarate;
+	fi.ssi_signal = rx_mgmt->ssi_signal;
+	ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame,
+			rx_mgmt->frame_len, &fi);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	ieee802_11_mgmt_cb(wpa_s->ap_iface->bss[0], buf, len, stype, ok);
+#endif /* NEED_AP_MLME */
+}
+
+
+void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
+				const u8 *src_addr, const u8 *buf, size_t len)
+{
+	ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len);
+}
+
+
+#ifdef CONFIG_WPS
+
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const u8 *p2p_dev_addr)
+{
+	if (!wpa_s->ap_iface)
+		return -1;
+	return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0],
+					 p2p_dev_addr);
+}
+
+
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+	struct wps_registrar *reg;
+	int reg_sel = 0, wps_sta = 0;
+
+	if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
+		return -1;
+
+	reg = wpa_s->ap_iface->bss[0]->wps->registrar;
+	reg_sel = wps_registrar_wps_cancel(reg);
+	wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
+				  ap_sta_wps_cancel, NULL);
+
+	if (!reg_sel && !wps_sta) {
+		wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
+			   "time");
+		return -1;
+	}
+
+	/*
+	 * There are 2 cases to return wps cancel as success:
+	 * 1. When wps cancel was initiated but no connection has been
+	 *    established with client yet.
+	 * 2. Client is in the middle of exchanging WPS messages.
+	 */
+
+	return 0;
+}
+
+
+int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const char *pin, char *buf, size_t buflen,
+			      int timeout)
+{
+	int ret, ret_len = 0;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+
+	if (pin == NULL) {
+		unsigned int rpin = wps_generate_pin();
+		ret_len = os_snprintf(buf, buflen, "%08d", rpin);
+		pin = buf;
+	} else
+		ret_len = os_snprintf(buf, buflen, "%s", pin);
+
+	ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
+				  timeout);
+	if (ret)
+		return -1;
+	return ret_len;
+}
+
+
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_data;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+	wpas_wps_ap_pin_disable(wpa_s);
+}
+
+
+static void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout)
+{
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface == NULL)
+		return;
+	hapd = wpa_s->ap_iface->bss[0];
+	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+	hapd->ap_pin_failures = 0;
+	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+	if (timeout > 0)
+		eloop_register_timeout(timeout, 0,
+				       wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+	hapd = wpa_s->ap_iface->bss[0];
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = NULL;
+	eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
+{
+	struct hostapd_data *hapd;
+	unsigned int pin;
+	char pin_txt[9];
+
+	if (wpa_s->ap_iface == NULL)
+		return NULL;
+	hapd = wpa_s->ap_iface->bss[0];
+	pin = wps_generate_pin();
+	os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = os_strdup(pin_txt);
+	if (hapd->conf->ap_pin == NULL)
+		return NULL;
+	wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+	return hapd->conf->ap_pin;
+}
+
+
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_data *hapd;
+	if (wpa_s->ap_iface == NULL)
+		return NULL;
+	hapd = wpa_s->ap_iface->bss[0];
+	return hapd->conf->ap_pin;
+}
+
+
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+			int timeout)
+{
+	struct hostapd_data *hapd;
+	char pin_txt[9];
+	int ret;
+
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	hapd = wpa_s->ap_iface->bss[0];
+	ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
+	if (ret < 0 || ret >= (int) sizeof(pin_txt))
+		return -1;
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = os_strdup(pin_txt);
+	if (hapd->conf->ap_pin == NULL)
+		return -1;
+	wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+	return 0;
+}
+
+
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface == NULL)
+		return;
+	hapd = wpa_s->ap_iface->bss[0];
+
+	/*
+	 * Registrar failed to prove its knowledge of the AP PIN. Disable AP
+	 * PIN if this happens multiple times to slow down brute force attacks.
+	 */
+	hapd->ap_pin_failures++;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+		   hapd->ap_pin_failures);
+	if (hapd->ap_pin_failures < 3)
+		return;
+
+	wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN");
+	hapd->ap_pin_failures = 0;
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = NULL;
+}
+
+#endif /* CONFIG_WPS */
+
+
+#ifdef CONFIG_CTRL_IFACE
+
+int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
+			    char *buf, size_t buflen)
+{
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
+					    buf, buflen);
+}
+
+
+int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
+		      char *buf, size_t buflen)
+{
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
+				      buf, buflen);
+}
+
+
+int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
+			   char *buf, size_t buflen)
+{
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
+					   buf, buflen);
+}
+
+
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+				   const char *txtaddr)
+{
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	return hostapd_ctrl_iface_disassociate(wpa_s->ap_iface->bss[0],
+					       txtaddr);
+}
+
+
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+				     const char *txtaddr)
+{
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+	return hostapd_ctrl_iface_deauthenticate(wpa_s->ap_iface->bss[0],
+						 txtaddr);
+}
+
+
+int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
+				 size_t buflen, int verbose)
+{
+	char *pos = buf, *end = buf + buflen;
+	int ret;
+	struct hostapd_bss_config *conf;
+
+	if (wpa_s->ap_iface == NULL)
+		return -1;
+
+	conf = wpa_s->ap_iface->bss[0]->conf;
+	if (conf->wpa == 0)
+		return 0;
+
+	ret = os_snprintf(pos, end - pos,
+			  "pairwise_cipher=%s\n"
+			  "group_cipher=%s\n"
+			  "key_mgmt=%s\n",
+			  wpa_cipher_txt(conf->rsn_pairwise),
+			  wpa_cipher_txt(conf->wpa_group),
+			  wpa_key_mgmt_txt(conf->wpa_key_mgmt,
+					   conf->wpa));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+	return pos - buf;
+}
+
+#endif /* CONFIG_CTRL_IFACE */
+
+
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_iface *iface = wpa_s->ap_iface;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct hostapd_data *hapd;
+
+	if (ssid == NULL || wpa_s->ap_iface == NULL ||
+	    ssid->mode == WPAS_MODE_INFRA ||
+	    ssid->mode == WPAS_MODE_IBSS)
+		return -1;
+
+#ifdef CONFIG_P2P
+	if (ssid->mode == WPAS_MODE_P2P_GO)
+		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+	else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+		iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+			P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
+	hapd = iface->bss[0];
+	if (hapd->drv_priv == NULL)
+		return -1;
+	ieee802_11_set_beacons(iface);
+	hostapd_set_ap_wps_ie(hapd);
+
+	return 0;
+}
+
+
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+		       int offset)
+{
+	if (!wpa_s->ap_iface)
+		return;
+
+	wpa_s->assoc_freq = freq;
+	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+}
+
+
+int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
+				      const u8 *addr)
+{
+	struct hostapd_data *hapd;
+	struct hostapd_bss_config *conf;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+
+	if (addr)
+		wpa_printf(MSG_DEBUG, "AP: Set MAC address filter: " MACSTR,
+			   MAC2STR(addr));
+	else
+		wpa_printf(MSG_DEBUG, "AP: Clear MAC address filter");
+
+	hapd = wpa_s->ap_iface->bss[0];
+	conf = hapd->conf;
+
+	os_free(conf->accept_mac);
+	conf->accept_mac = NULL;
+	conf->num_accept_mac = 0;
+	os_free(conf->deny_mac);
+	conf->deny_mac = NULL;
+	conf->num_deny_mac = 0;
+
+	if (addr == NULL) {
+		conf->macaddr_acl = ACCEPT_UNLESS_DENIED;
+		return 0;
+	}
+
+	conf->macaddr_acl = DENY_UNLESS_ACCEPTED;
+	conf->accept_mac = os_zalloc(sizeof(struct mac_acl_entry));
+	if (conf->accept_mac == NULL)
+		return -1;
+	os_memcpy(conf->accept_mac[0].addr, addr, ETH_ALEN);
+	conf->num_accept_mac = 1;
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ap.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ap.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,43 +0,0 @@
-/*
- * WPA Supplicant - Basic AP mode support routines
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2009, Atheros Communications
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef AP_H
-#define AP_H
-
-int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
-			     struct wpa_ssid *ssid);
-void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
-				const u8 *src_addr, const u8 *buf, size_t len);
-int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			      const char *pin, char *buf, size_t buflen);
-int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
-			    char *buf, size_t buflen);
-int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
-		      char *buf, size_t buflen);
-int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
-			   char *buf, size_t buflen);
-int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
-				 size_t buflen, int verbose);
-void ap_tx_status(void *ctx, const u8 *addr,
-		  const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len);
-void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
-void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
-int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
-				      const u8 *addr);
-
-#endif /* AP_H */

Copied: vendor/wpa/2.0/wpa_supplicant/ap.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/ap.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ap.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ap.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,56 @@
+/*
+ * WPA Supplicant - Basic AP mode support routines
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_H
+#define AP_H
+
+int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid);
+void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
+				const u8 *src_addr, const u8 *buf, size_t len);
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const u8 *p2p_dev_addr);
+int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const char *pin, char *buf, size_t buflen,
+			      int timeout);
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s);
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+			int timeout);
+int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
+			    char *buf, size_t buflen);
+int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
+		      char *buf, size_t buflen);
+int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
+			   char *buf, size_t buflen);
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+				     const char *txtaddr);
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+				   const char *txtaddr);
+int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
+				 size_t buflen, int verbose);
+void ap_tx_status(void *ctx, const u8 *addr,
+		  const u8 *buf, size_t len, int ack);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+			const u8 *data, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
+void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
+void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
+				      const u8 *addr);
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+		       int offset);
+
+#endif /* AP_H */

Copied: vendor/wpa/2.0/wpa_supplicant/autoscan.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/autoscan.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/autoscan.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/autoscan.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,143 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#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
+	&autoscan_exponential_ops,
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+	&autoscan_periodic_ops,
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+	NULL
+};
+
+
+static void request_scan(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
+
+	if (wpa_supplicant_req_sched_scan(wpa_s))
+		wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
+}
+
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+	const char *name = wpa_s->conf->autoscan;
+	const char *params;
+	size_t nlen;
+	int i;
+	const struct autoscan_ops *ops = NULL;
+
+	if (wpa_s->autoscan && wpa_s->autoscan_priv)
+		return 0;
+
+	if (name == NULL)
+		return 0;
+
+	params = os_strchr(name, ':');
+	if (params == NULL) {
+		params = "";
+		nlen = os_strlen(name);
+	} else {
+		nlen = params - name;
+		params++;
+	}
+
+	for (i = 0; autoscan_modules[i]; i++) {
+		if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
+			ops = autoscan_modules[i];
+			break;
+		}
+	}
+
+	if (ops == NULL) {
+		wpa_printf(MSG_ERROR, "autoscan: Could not find module "
+			   "matching the parameter '%s'", name);
+		return -1;
+	}
+
+	wpa_s->autoscan_params = NULL;
+
+	wpa_s->autoscan_priv = ops->init(wpa_s, params);
+	if (wpa_s->autoscan_priv == NULL)
+		return -1;
+	wpa_s->autoscan = ops;
+
+	wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
+		   "parameters '%s'", ops->name, params);
+	if (!req_scan)
+		return 0;
+
+	/*
+	 * Cancelling existing scan requests, if any.
+	 */
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	/*
+	 * Firing first scan, which will lead to call autoscan_notify_scan.
+	 */
+	request_scan(wpa_s);
+
+	return 0;
+}
+
+
+void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+		wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
+			   wpa_s->autoscan->name);
+		wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
+		wpa_s->autoscan = NULL;
+		wpa_s->autoscan_priv = NULL;
+
+		wpa_s->scan_interval = 5;
+		wpa_s->sched_scan_interval = 0;
+	}
+}
+
+
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+			 struct wpa_scan_results *scan_res)
+{
+	int interval;
+
+	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+		interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
+							scan_res);
+
+		if (interval <= 0)
+			return -1;
+
+		wpa_s->scan_interval = interval;
+		wpa_s->sched_scan_interval = interval;
+
+		request_scan(wpa_s);
+	}
+
+	return 0;
+}

Copied: vendor/wpa/2.0/wpa_supplicant/autoscan.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/autoscan.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/autoscan.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/autoscan.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+	const char *name;
+
+	void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+	void (*deinit)(void *priv);
+
+	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+			 struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+	return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+				       struct wpa_scan_results *scan_res)
+{
+	return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/autoscan_exponential.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/autoscan_exponential.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/autoscan_exponential.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/autoscan_exponential.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,104 @@
+/*
+ * WPA Supplicant - auto scan exponential module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+struct autoscan_exponential_data {
+	struct wpa_supplicant *wpa_s;
+	int base;
+	int limit;
+	int interval;
+};
+
+
+static int
+autoscan_exponential_get_params(struct autoscan_exponential_data *data,
+				const char *params)
+{
+	const char *pos;
+
+	if (params == NULL)
+		return -1;
+
+	data->base = atoi(params);
+
+	pos = os_strchr(params, ':');
+	if (pos == NULL)
+		return -1;
+
+	pos++;
+	data->limit = atoi(pos);
+
+	return 0;
+}
+
+
+static void * autoscan_exponential_init(struct wpa_supplicant *wpa_s,
+					const char *params)
+{
+	struct autoscan_exponential_data *data;
+
+	data = os_zalloc(sizeof(struct autoscan_exponential_data));
+	if (data == NULL)
+		return NULL;
+
+	if (autoscan_exponential_get_params(data, params) < 0) {
+		os_free(data);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "autoscan exponential: base exponential is %d "
+		   "and limit is %d", data->base, data->limit);
+
+	data->wpa_s = wpa_s;
+
+	return data;
+}
+
+
+static void autoscan_exponential_deinit(void *priv)
+{
+	struct autoscan_exponential_data *data = priv;
+
+	os_free(data);
+}
+
+
+static int autoscan_exponential_notify_scan(void *priv,
+					    struct wpa_scan_results *scan_res)
+{
+	struct autoscan_exponential_data *data = priv;
+
+	wpa_printf(MSG_DEBUG, "autoscan exponential: scan result "
+		   "notification");
+
+	if (data->interval >= data->limit)
+		return data->limit;
+
+	if (data->interval <= 0)
+		data->interval = data->base;
+	else {
+		data->interval = data->interval * data->base;
+		if (data->interval > data->limit)
+			return data->limit;
+	}
+
+	return data->interval;
+}
+
+
+const struct autoscan_ops autoscan_exponential_ops = {
+	.name = "exponential",
+	.init = autoscan_exponential_init,
+	.deinit = autoscan_exponential_deinit,
+	.notify_scan = autoscan_exponential_notify_scan,
+};

Copied: vendor/wpa/2.0/wpa_supplicant/autoscan_periodic.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/autoscan_periodic.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/autoscan_periodic.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/autoscan_periodic.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,85 @@
+/*
+ * WPA Supplicant - auto scan periodic module
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "autoscan.h"
+
+
+struct autoscan_periodic_data {
+	int periodic_interval;
+};
+
+
+static int autoscan_periodic_get_params(struct autoscan_periodic_data *data,
+					const char *params)
+{
+	int interval;
+
+	if (params == NULL)
+		return -1;
+
+	interval = atoi(params);
+
+	if (interval < 0)
+		return -1;
+
+	data->periodic_interval = interval;
+
+	return 0;
+}
+
+
+static void * autoscan_periodic_init(struct wpa_supplicant *wpa_s,
+				     const char *params)
+{
+	struct autoscan_periodic_data *data;
+
+	data = os_zalloc(sizeof(struct autoscan_periodic_data));
+	if (data == NULL)
+		return NULL;
+
+	if (autoscan_periodic_get_params(data, params) < 0) {
+		os_free(data);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "autoscan periodic: interval is %d",
+		   data->periodic_interval);
+
+	return data;
+}
+
+
+static void autoscan_periodic_deinit(void *priv)
+{
+	struct autoscan_periodic_data *data = priv;
+
+	os_free(data);
+}
+
+
+static int autoscan_periodic_notify_scan(void *priv,
+					 struct wpa_scan_results *scan_res)
+{
+	struct autoscan_periodic_data *data = priv;
+
+	wpa_printf(MSG_DEBUG, "autoscan periodic: scan result notification");
+
+	return data->periodic_interval;
+}
+
+
+const struct autoscan_ops autoscan_periodic_ops = {
+	.name = "periodic",
+	.init = autoscan_periodic_init,
+	.deinit = autoscan_periodic_deinit,
+	.notify_scan = autoscan_periodic_notify_scan,
+};

Deleted: vendor/wpa/2.0/wpa_supplicant/bgscan.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/bgscan.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,110 +0,0 @@
-/*
- * WPA Supplicant - background scan and roaming interface
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-#include "config_ssid.h"
-#include "bgscan.h"
-
-#ifdef CONFIG_BGSCAN_SIMPLE
-extern const struct bgscan_ops bgscan_simple_ops;
-#endif /* CONFIG_BGSCAN_SIMPLE */
-
-static const struct bgscan_ops * bgscan_modules[] = {
-#ifdef CONFIG_BGSCAN_SIMPLE
-	&bgscan_simple_ops,
-#endif /* CONFIG_BGSCAN_SIMPLE */
-	NULL
-};
-
-
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	const char *name = ssid->bgscan;
-	const char *params;
-	size_t nlen;
-	int i;
-	const struct bgscan_ops *ops = NULL;
-
-	bgscan_deinit(wpa_s);
-	if (name == NULL)
-		return 0;
-
-	params = os_strchr(name, ':');
-	if (params == NULL) {
-		params = "";
-		nlen = os_strlen(name);
-	} else {
-		nlen = params - name;
-		params++;
-	}
-
-	for (i = 0; bgscan_modules[i]; i++) {
-		if (os_strncmp(name, bgscan_modules[i]->name, nlen) == 0) {
-			ops = bgscan_modules[i];
-			break;
-		}
-	}
-
-	if (ops == NULL) {
-		wpa_printf(MSG_ERROR, "bgscan: Could not find module "
-			   "matching the parameter '%s'", name);
-		return -1;
-	}
-
-	wpa_s->bgscan_priv = ops->init(wpa_s, params, ssid);
-	if (wpa_s->bgscan_priv == NULL)
-		return -1;
-	wpa_s->bgscan = ops;
-	wpa_printf(MSG_DEBUG, "bgscan: Initialized module '%s' with "
-		   "parameters '%s'", ops->name, params);
-
-	return 0;
-}
-
-
-void bgscan_deinit(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->bgscan && wpa_s->bgscan_priv) {
-		wpa_printf(MSG_DEBUG, "bgscan: Deinitializing module '%s'",
-			   wpa_s->bgscan->name);
-		wpa_s->bgscan->deinit(wpa_s->bgscan_priv);
-		wpa_s->bgscan = NULL;
-		wpa_s->bgscan_priv = NULL;
-	}
-}
-
-
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->bgscan && wpa_s->bgscan_priv)
-		return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv);
-	return 0;
-}
-
-
-void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->bgscan && wpa_s->bgscan_priv)
-		wpa_s->bgscan->notify_beacon_loss(wpa_s->bgscan_priv);
-}
-
-
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above)
-{
-	if (wpa_s->bgscan && wpa_s->bgscan_priv)
-		wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/bgscan.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/bgscan.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bgscan.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,117 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "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
+	&bgscan_simple_ops,
+#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+	&bgscan_learn_ops,
+#endif /* CONFIG_BGSCAN_LEARN */
+	NULL
+};
+
+
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	const char *name = ssid->bgscan;
+	const char *params;
+	size_t nlen;
+	int i;
+	const struct bgscan_ops *ops = NULL;
+
+	bgscan_deinit(wpa_s);
+	if (name == NULL)
+		return 0;
+
+	params = os_strchr(name, ':');
+	if (params == NULL) {
+		params = "";
+		nlen = os_strlen(name);
+	} else {
+		nlen = params - name;
+		params++;
+	}
+
+	for (i = 0; bgscan_modules[i]; i++) {
+		if (os_strncmp(name, bgscan_modules[i]->name, nlen) == 0) {
+			ops = bgscan_modules[i];
+			break;
+		}
+	}
+
+	if (ops == NULL) {
+		wpa_printf(MSG_ERROR, "bgscan: Could not find module "
+			   "matching the parameter '%s'", name);
+		return -1;
+	}
+
+	wpa_s->bgscan_priv = ops->init(wpa_s, params, ssid);
+	if (wpa_s->bgscan_priv == NULL)
+		return -1;
+	wpa_s->bgscan = ops;
+	wpa_printf(MSG_DEBUG, "bgscan: Initialized module '%s' with "
+		   "parameters '%s'", ops->name, params);
+
+	return 0;
+}
+
+
+void bgscan_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+		wpa_printf(MSG_DEBUG, "bgscan: Deinitializing module '%s'",
+			   wpa_s->bgscan->name);
+		wpa_s->bgscan->deinit(wpa_s->bgscan_priv);
+		wpa_s->bgscan = NULL;
+		wpa_s->bgscan_priv = NULL;
+	}
+}
+
+
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res)
+{
+	if (wpa_s->bgscan && wpa_s->bgscan_priv)
+		return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv,
+						  scan_res);
+	return 0;
+}
+
+
+void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->bgscan && wpa_s->bgscan_priv)
+		wpa_s->bgscan->notify_beacon_loss(wpa_s->bgscan_priv);
+}
+
+
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+				 int current_signal, int current_noise,
+				 int current_txrate)
+{
+	if (wpa_s->bgscan && wpa_s->bgscan_priv)
+		wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above,
+						    current_signal,
+						    current_noise,
+						    current_txrate);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/bgscan.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/bgscan.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,69 +0,0 @@
-/*
- * WPA Supplicant - background scan and roaming interface
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BGSCAN_H
-#define BGSCAN_H
-
-struct wpa_supplicant;
-struct wpa_ssid;
-
-struct bgscan_ops {
-	const char *name;
-
-	void * (*init)(struct wpa_supplicant *wpa_s, const char *params,
-		       const struct wpa_ssid *ssid);
-	void (*deinit)(void *priv);
-
-	int (*notify_scan)(void *priv);
-	void (*notify_beacon_loss)(void *priv);
-	void (*notify_signal_change)(void *priv, int above);
-};
-
-#ifdef CONFIG_BGSCAN
-
-int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-void bgscan_deinit(struct wpa_supplicant *wpa_s);
-int bgscan_notify_scan(struct wpa_supplicant *wpa_s);
-void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
-void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above);
-
-#else /* CONFIG_BGSCAN */
-
-static inline int bgscan_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid)
-{
-	return 0;
-}
-
-static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
-					       int above)
-{
-}
-
-#endif /* CONFIG_BGSCAN */
-
-#endif /* BGSCAN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/bgscan.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/bgscan.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bgscan.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,72 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BGSCAN_H
+#define BGSCAN_H
+
+struct wpa_supplicant;
+struct wpa_ssid;
+
+struct bgscan_ops {
+	const char *name;
+
+	void * (*init)(struct wpa_supplicant *wpa_s, const char *params,
+		       const struct wpa_ssid *ssid);
+	void (*deinit)(void *priv);
+
+	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+	void (*notify_beacon_loss)(void *priv);
+	void (*notify_signal_change)(void *priv, int above,
+				     int current_signal,
+				     int current_noise,
+				     int current_txrate);
+};
+
+#ifdef CONFIG_BGSCAN
+
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+void bgscan_deinit(struct wpa_supplicant *wpa_s);
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res);
+void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+				 int current_signal, int current_noise,
+				 int current_txrate);
+
+#else /* CONFIG_BGSCAN */
+
+static inline int bgscan_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_scan_results *scan_res)
+{
+	return 0;
+}
+
+static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
+					       int above, int current_signal,
+					       int current_noise,
+					       int current_txrate)
+{
+}
+
+#endif /* CONFIG_BGSCAN */
+
+#endif /* BGSCAN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/bgscan_learn.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/bgscan_learn.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bgscan_learn.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan_learn.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,607 @@
+/*
+ * WPA Supplicant - background scan and roaming module: learn
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "config_ssid.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "bgscan.h"
+
+struct bgscan_learn_bss {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	u8 *neigh; /* num_neigh * ETH_ALEN buffer */
+	size_t num_neigh;
+};
+
+struct bgscan_learn_data {
+	struct wpa_supplicant *wpa_s;
+	const struct wpa_ssid *ssid;
+	int scan_interval;
+	int signal_threshold;
+	int short_interval; /* use if signal < threshold */
+	int long_interval; /* use if signal > threshold */
+	struct os_time last_bgscan;
+	char *fname;
+	struct dl_list bss;
+	int *supp_freqs;
+	int probe_idx;
+};
+
+
+static void bss_free(struct bgscan_learn_bss *bss)
+{
+	os_free(bss->neigh);
+	os_free(bss);
+}
+
+
+static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid)
+{
+	size_t i;
+
+	if (array == NULL || array_len == 0)
+		return 0;
+
+	for (i = 0; i < array_len; i++) {
+		if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss,
+				      const u8 *bssid)
+{
+	u8 *n;
+
+	if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+		return;
+	if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
+		return;
+
+	n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
+	if (n == NULL)
+		return;
+
+	os_memcpy(n + bss->num_neigh * ETH_ALEN, bssid, ETH_ALEN);
+	bss->neigh = n;
+	bss->num_neigh++;
+}
+
+
+static struct bgscan_learn_bss * bgscan_learn_get_bss(
+	struct bgscan_learn_data *data, const u8 *bssid)
+{
+	struct bgscan_learn_bss *bss;
+
+	dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+static int bgscan_learn_load(struct bgscan_learn_data *data)
+{
+	FILE *f;
+	char buf[128];
+	struct bgscan_learn_bss *bss;
+
+	if (data->fname == NULL)
+		return 0;
+
+	f = fopen(data->fname, "r");
+	if (f == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s",
+		   data->fname);
+
+	if (fgets(buf, sizeof(buf), f) == NULL ||
+	    os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) {
+		wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s",
+			   data->fname);
+		fclose(f);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		if (os_strncmp(buf, "BSS ", 4) == 0) {
+			bss = os_zalloc(sizeof(*bss));
+			if (!bss)
+				continue;
+			if (hwaddr_aton(buf + 4, bss->bssid) < 0) {
+				bss_free(bss);
+				continue;
+			}
+			bss->freq = atoi(buf + 4 + 18);
+			dl_list_add(&data->bss, &bss->list);
+			wpa_printf(MSG_DEBUG, "bgscan learn: Loaded BSS "
+				   "entry: " MACSTR " freq=%d",
+				   MAC2STR(bss->bssid), bss->freq);
+		}
+
+		if (os_strncmp(buf, "NEIGHBOR ", 9) == 0) {
+			u8 addr[ETH_ALEN];
+
+			if (hwaddr_aton(buf + 9, addr) < 0)
+				continue;
+			bss = bgscan_learn_get_bss(data, addr);
+			if (bss == NULL)
+				continue;
+			if (hwaddr_aton(buf + 9 + 18, addr) < 0)
+				continue;
+
+			bgscan_learn_add_neighbor(bss, addr);
+		}
+	}
+
+	fclose(f);
+	return 0;
+}
+
+
+static void bgscan_learn_save(struct bgscan_learn_data *data)
+{
+	FILE *f;
+	struct bgscan_learn_bss *bss;
+
+	if (data->fname == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s",
+		   data->fname);
+
+	f = fopen(data->fname, "w");
+	if (f == NULL)
+		return;
+	fprintf(f, "wpa_supplicant-bgscan-learn\n");
+
+	dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+		fprintf(f, "BSS " MACSTR " %d\n",
+			MAC2STR(bss->bssid), bss->freq);
+	}
+
+	dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+		size_t i;
+		for (i = 0; i < bss->num_neigh; i++) {
+			fprintf(f, "NEIGHBOR " MACSTR " " MACSTR "\n",
+				MAC2STR(bss->bssid),
+				MAC2STR(bss->neigh + i * ETH_ALEN));
+		}
+	}
+
+	fclose(f);
+}
+
+
+static int in_array(int *array, int val)
+{
+	int i;
+
+	if (array == NULL)
+		return 0;
+
+	for (i = 0; array[i]; i++) {
+		if (array[i] == val)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int * bgscan_learn_get_freqs(struct bgscan_learn_data *data,
+				    size_t *count)
+{
+	struct bgscan_learn_bss *bss;
+	int *freqs = NULL, *n;
+
+	*count = 0;
+
+	dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
+		if (in_array(freqs, bss->freq))
+			continue;
+		n = os_realloc_array(freqs, *count + 2, sizeof(int));
+		if (n == NULL)
+			return freqs;
+		freqs = n;
+		freqs[*count] = bss->freq;
+		(*count)++;
+		freqs[*count] = 0;
+	}
+
+	return freqs;
+}
+
+
+static int * bgscan_learn_get_probe_freq(struct bgscan_learn_data *data,
+					 int *freqs, size_t count)
+{
+	int idx, *n;
+
+	if (data->supp_freqs == NULL)
+		return freqs;
+
+	idx = data->probe_idx + 1;
+	while (idx != data->probe_idx) {
+		if (data->supp_freqs[idx] == 0) {
+			if (data->probe_idx == 0)
+				break;
+			idx = 0;
+		}
+		if (!in_array(freqs, data->supp_freqs[idx])) {
+			wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
+				   "%u", data->supp_freqs[idx]);
+			data->probe_idx = idx;
+			n = os_realloc_array(freqs, count + 2, sizeof(int));
+			if (n == NULL)
+				return freqs;
+			freqs = n;
+			freqs[count] = data->supp_freqs[idx];
+			count++;
+			freqs[count] = 0;
+			break;
+		}
+
+		idx++;
+	}
+
+	return freqs;
+}
+
+
+static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct bgscan_learn_data *data = eloop_ctx;
+	struct wpa_supplicant *wpa_s = data->wpa_s;
+	struct wpa_driver_scan_params params;
+	int *freqs = NULL;
+	size_t count, i;
+	char msg[100], *pos;
+
+	os_memset(&params, 0, sizeof(params));
+	params.num_ssids = 1;
+	params.ssids[0].ssid = data->ssid->ssid;
+	params.ssids[0].ssid_len = data->ssid->ssid_len;
+	if (data->ssid->scan_freq)
+		params.freqs = data->ssid->scan_freq;
+	else {
+		freqs = bgscan_learn_get_freqs(data, &count);
+		wpa_printf(MSG_DEBUG, "bgscan learn: BSSes in this ESS have "
+			   "been seen on %u channels", (unsigned int) count);
+		freqs = bgscan_learn_get_probe_freq(data, freqs, count);
+
+		msg[0] = '\0';
+		pos = msg;
+		for (i = 0; freqs && freqs[i]; i++) {
+			int ret;
+			ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
+					  freqs[i]);
+			if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+				break;
+			pos += ret;
+		}
+		pos[0] = '\0';
+		wpa_printf(MSG_DEBUG, "bgscan learn: Scanning frequencies:%s",
+			   msg);
+		params.freqs = freqs;
+	}
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
+	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+		wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
+		eloop_register_timeout(data->scan_interval, 0,
+				       bgscan_learn_timeout, data, NULL);
+	} else
+		os_get_time(&data->last_bgscan);
+	os_free(freqs);
+}
+
+
+static int bgscan_learn_get_params(struct bgscan_learn_data *data,
+				   const char *params)
+{
+	const char *pos;
+
+	if (params == NULL)
+		return 0;
+
+	data->short_interval = atoi(params);
+
+	pos = os_strchr(params, ':');
+	if (pos == NULL)
+		return 0;
+	pos++;
+	data->signal_threshold = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL) {
+		wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval "
+			   "for high signal");
+		return -1;
+	}
+	pos++;
+	data->long_interval = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos) {
+		pos++;
+		data->fname = os_strdup(pos);
+	}
+
+	return 0;
+}
+
+
+static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
+{
+	struct hostapd_hw_modes *modes;
+	int i, j, *freqs = NULL, *n;
+	size_t count = 0;
+
+	modes = wpa_s->hw.modes;
+	if (modes == NULL)
+		return NULL;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			n = os_realloc_array(freqs, count + 2, sizeof(int));
+			if (n == NULL)
+				continue;
+
+			freqs = n;
+			freqs[count] = modes[i].channels[j].freq;
+			count++;
+			freqs[count] = 0;
+		}
+	}
+
+	return freqs;
+}
+
+
+static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
+				const char *params,
+				const struct wpa_ssid *ssid)
+{
+	struct bgscan_learn_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	dl_list_init(&data->bss);
+	data->wpa_s = wpa_s;
+	data->ssid = ssid;
+	if (bgscan_learn_get_params(data, params) < 0) {
+		os_free(data->fname);
+		os_free(data);
+		return NULL;
+	}
+	if (data->short_interval <= 0)
+		data->short_interval = 30;
+	if (data->long_interval <= 0)
+		data->long_interval = 30;
+
+	if (bgscan_learn_load(data) < 0) {
+		os_free(data->fname);
+		os_free(data);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d  "
+		   "Short bgscan interval %d  Long bgscan interval %d",
+		   data->signal_threshold, data->short_interval,
+		   data->long_interval);
+
+	if (data->signal_threshold &&
+	    wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
+		wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable "
+			   "signal strength monitoring");
+	}
+
+	data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
+	data->scan_interval = data->short_interval;
+	eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+			       data, NULL);
+
+	/*
+	 * This function is called immediately after an association, so it is
+	 * reasonable to assume that a scan was completed recently. This makes
+	 * us skip an immediate new scan in cases where the current signal
+	 * level is below the bgscan threshold.
+	 */
+	os_get_time(&data->last_bgscan);
+
+	return data;
+}
+
+
+static void bgscan_learn_deinit(void *priv)
+{
+	struct bgscan_learn_data *data = priv;
+	struct bgscan_learn_bss *bss, *n;
+
+	bgscan_learn_save(data);
+	eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+	if (data->signal_threshold)
+		wpa_drv_signal_monitor(data->wpa_s, 0, 0);
+	os_free(data->fname);
+	dl_list_for_each_safe(bss, n, &data->bss, struct bgscan_learn_bss,
+			      list) {
+		dl_list_del(&bss->list);
+		bss_free(bss);
+	}
+	os_free(data->supp_freqs);
+	os_free(data);
+}
+
+
+static int bgscan_learn_bss_match(struct bgscan_learn_data *data,
+				  struct wpa_scan_res *bss)
+{
+	const u8 *ie;
+
+	ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+	if (ie == NULL)
+		return 0;
+
+	if (data->ssid->ssid_len != ie[1] ||
+	    os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0)
+		return 0; /* SSID mismatch */
+
+	return 1;
+}
+
+
+static int bgscan_learn_notify_scan(void *priv,
+				    struct wpa_scan_results *scan_res)
+{
+	struct bgscan_learn_data *data = priv;
+	size_t i, j;
+#define MAX_BSS 50
+	u8 bssid[MAX_BSS * ETH_ALEN];
+	size_t num_bssid = 0;
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification");
+
+	eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+	eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
+			       data, NULL);
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *res = scan_res->res[i];
+		if (!bgscan_learn_bss_match(data, res))
+			continue;
+
+		if (num_bssid < MAX_BSS) {
+			os_memcpy(bssid + num_bssid * ETH_ALEN, res->bssid,
+				  ETH_ALEN);
+			num_bssid++;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "bgscan learn: %u matching BSSes in scan "
+		   "results", (unsigned int) num_bssid);
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *res = scan_res->res[i];
+		struct bgscan_learn_bss *bss;
+
+		if (!bgscan_learn_bss_match(data, res))
+			continue;
+
+		bss = bgscan_learn_get_bss(data, res->bssid);
+		if (bss && bss->freq != res->freq) {
+			wpa_printf(MSG_DEBUG, "bgscan learn: Update BSS "
+			   MACSTR " freq %d -> %d",
+				   MAC2STR(res->bssid), bss->freq, res->freq);
+			bss->freq = res->freq;
+		} else if (!bss) {
+			wpa_printf(MSG_DEBUG, "bgscan learn: Add BSS " MACSTR
+				   " freq=%d", MAC2STR(res->bssid), res->freq);
+			bss = os_zalloc(sizeof(*bss));
+			if (!bss)
+				continue;
+			os_memcpy(bss->bssid, res->bssid, ETH_ALEN);
+			bss->freq = res->freq;
+			dl_list_add(&data->bss, &bss->list);
+		}
+
+		for (j = 0; j < num_bssid; j++) {
+			u8 *addr = bssid + j * ETH_ALEN;
+			bgscan_learn_add_neighbor(bss, addr);
+		}
+	}
+
+	/*
+	 * A more advanced bgscan could process scan results internally, select
+	 * the BSS and request roam if needed. This sample uses the existing
+	 * BSS/ESS selection routine. Change this to return 1 if selection is
+	 * done inside the bgscan module.
+	 */
+
+	return 0;
+}
+
+
+static void bgscan_learn_notify_beacon_loss(void *priv)
+{
+	wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss");
+	/* TODO: speed up background scanning */
+}
+
+
+static void bgscan_learn_notify_signal_change(void *priv, int above,
+					      int current_signal,
+					      int current_noise,
+					      int current_txrate)
+{
+	struct bgscan_learn_data *data = priv;
+	int scan = 0;
+	struct os_time now;
+
+	if (data->short_interval == data->long_interval ||
+	    data->signal_threshold == 0)
+		return;
+
+	wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed "
+		   "(above=%d current_signal=%d current_noise=%d "
+		   "current_txrate=%d)", above, current_signal,
+		   current_noise, current_txrate);
+	if (data->scan_interval == data->long_interval && !above) {
+		wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
+			   "interval");
+		data->scan_interval = data->short_interval;
+		os_get_time(&now);
+		if (now.sec > data->last_bgscan.sec + 1)
+			scan = 1;
+	} else if (data->scan_interval == data->short_interval && above) {
+		wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan "
+			   "interval");
+		data->scan_interval = data->long_interval;
+		eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+		eloop_register_timeout(data->scan_interval, 0,
+				       bgscan_learn_timeout, data, NULL);
+	} else if (!above) {
+		/*
+		 * Signal dropped further 4 dB. Request a new scan if we have
+		 * not yet scanned in a while.
+		 */
+		os_get_time(&now);
+		if (now.sec > data->last_bgscan.sec + 10)
+			scan = 1;
+	}
+
+	if (scan) {
+		wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan");
+		eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
+		eloop_register_timeout(0, 0, bgscan_learn_timeout, data, NULL);
+	}
+}
+
+
+const struct bgscan_ops bgscan_learn_ops = {
+	.name = "learn",
+	.init = bgscan_learn_init,
+	.deinit = bgscan_learn_deinit,
+	.notify_scan = bgscan_learn_notify_scan,
+	.notify_beacon_loss = bgscan_learn_notify_beacon_loss,
+	.notify_signal_change = bgscan_learn_notify_signal_change,
+};

Deleted: vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/bgscan_simple.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,230 +0,0 @@
-/*
- * WPA Supplicant - background scan and roaming module: simple
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "drivers/driver.h"
-#include "config_ssid.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "scan.h"
-#include "bgscan.h"
-
-struct bgscan_simple_data {
-	struct wpa_supplicant *wpa_s;
-	const struct wpa_ssid *ssid;
-	int scan_interval;
-	int signal_threshold;
-	int short_interval; /* use if signal < threshold */
-	int long_interval; /* use if signal > threshold */
-	struct os_time last_bgscan;
-};
-
-
-static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct bgscan_simple_data *data = eloop_ctx;
-	struct wpa_supplicant *wpa_s = data->wpa_s;
-	struct wpa_driver_scan_params params;
-
-	os_memset(&params, 0, sizeof(params));
-	params.num_ssids = 1;
-	params.ssids[0].ssid = data->ssid->ssid;
-	params.ssids[0].ssid_len = data->ssid->ssid_len;
-	params.freqs = data->ssid->scan_freq;
-
-	/*
-	 * A more advanced bgscan module would learn about most like channels
-	 * over time and request scans only for some channels (probing others
-	 * every now and then) to reduce effect on the data connection.
-	 */
-
-	wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
-		wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
-		eloop_register_timeout(data->scan_interval, 0,
-				       bgscan_simple_timeout, data, NULL);
-	} else
-		os_get_time(&data->last_bgscan);
-}
-
-
-static int bgscan_simple_get_params(struct bgscan_simple_data *data,
-				    const char *params)
-{
-	const char *pos;
-
-	if (params == NULL)
-		return 0;
-
-	data->short_interval = atoi(params);
-
-	pos = os_strchr(params, ':');
-	if (pos == NULL)
-		return 0;
-	pos++;
-	data->signal_threshold = atoi(pos);
-	pos = os_strchr(pos, ':');
-	if (pos == NULL) {
-		wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval "
-			   "for high signal");
-		return -1;
-	}
-	pos++;
-	data->long_interval = atoi(pos);
-
-	return 0;
-}
-
-
-static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
-				 const char *params,
-				 const struct wpa_ssid *ssid)
-{
-	struct bgscan_simple_data *data;
-
-	data = os_zalloc(sizeof(*data));
-	if (data == NULL)
-		return NULL;
-	data->wpa_s = wpa_s;
-	data->ssid = ssid;
-	if (bgscan_simple_get_params(data, params) < 0) {
-		os_free(data);
-		return NULL;
-	}
-	if (data->short_interval <= 0)
-		data->short_interval = 30;
-	if (data->long_interval <= 0)
-		data->long_interval = 30;
-
-	wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d  "
-		   "Short bgscan interval %d  Long bgscan interval %d",
-		   data->signal_threshold, data->short_interval,
-		   data->long_interval);
-
-	if (data->signal_threshold &&
-	    wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
-		wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable "
-			   "signal strength monitoring");
-	}
-
-	data->scan_interval = data->short_interval;
-	eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
-			       data, NULL);
-
-	/*
-	 * This function is called immediately after an association, so it is
-	 * reasonable to assume that a scan was completed recently. This makes
-	 * us skip an immediate new scan in cases where the current signal
-	 * level is below the bgscan threshold.
-	 */
-	os_get_time(&data->last_bgscan);
-
-	return data;
-}
-
-
-static void bgscan_simple_deinit(void *priv)
-{
-	struct bgscan_simple_data *data = priv;
-	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
-	if (data->signal_threshold)
-		wpa_drv_signal_monitor(data->wpa_s, 0, 0);
-	os_free(data);
-}
-
-
-static int bgscan_simple_notify_scan(void *priv)
-{
-	struct bgscan_simple_data *data = priv;
-
-	wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification");
-
-	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
-	eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
-			       data, NULL);
-
-	/*
-	 * A more advanced bgscan could process scan results internally, select
-	 * the BSS and request roam if needed. This sample uses the existing
-	 * BSS/ESS selection routine. Change this to return 1 if selection is
-	 * done inside the bgscan module.
-	 */
-
-	return 0;
-}
-
-
-static void bgscan_simple_notify_beacon_loss(void *priv)
-{
-	wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss");
-	/* TODO: speed up background scanning */
-}
-
-
-static void bgscan_simple_notify_signal_change(void *priv, int above)
-{
-	struct bgscan_simple_data *data = priv;
-	int scan = 0;
-	struct os_time now;
-
-	if (data->short_interval == data->long_interval ||
-	    data->signal_threshold == 0)
-		return;
-
-	wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
-		   "(above=%d)", above);
-	if (data->scan_interval == data->long_interval && !above) {
-		wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
-			   "bgscan interval");
-		data->scan_interval = data->short_interval;
-		os_get_time(&now);
-		if (now.sec > data->last_bgscan.sec + 1)
-			scan = 1;
-	} else if (data->scan_interval == data->short_interval && above) {
-		wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
-			   "interval");
-		data->scan_interval = data->long_interval;
-		eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
-		eloop_register_timeout(data->scan_interval, 0,
-				       bgscan_simple_timeout, data, NULL);
-	} else if (!above) {
-		/*
-		 * Signal dropped further 4 dB. Request a new scan if we have
-		 * not yet scanned in a while.
-		 */
-		os_get_time(&now);
-		if (now.sec > data->last_bgscan.sec + 10)
-			scan = 1;
-	}
-
-	if (scan) {
-		wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan");
-		eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
-		eloop_register_timeout(0, 0, bgscan_simple_timeout, data,
-				       NULL);
-	}
-}
-
-
-const struct bgscan_ops bgscan_simple_ops = {
-	.name = "simple",
-	.init = bgscan_simple_init,
-	.deinit = bgscan_simple_deinit,
-	.notify_scan = bgscan_simple_notify_scan,
-	.notify_beacon_loss = bgscan_simple_notify_beacon_loss,
-	.notify_signal_change = bgscan_simple_notify_signal_change,
-};

Copied: vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/bgscan_simple.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bgscan_simple.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,283 @@
+/*
+ * WPA Supplicant - background scan and roaming module: simple
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "drivers/driver.h"
+#include "config_ssid.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "bgscan.h"
+
+struct bgscan_simple_data {
+	struct wpa_supplicant *wpa_s;
+	const struct wpa_ssid *ssid;
+	int scan_interval;
+	int signal_threshold;
+	int short_scan_count; /* counter for scans using short scan interval */
+	int max_short_scans; /* maximum times we short-scan before back-off */
+	int short_interval; /* use if signal < threshold */
+	int long_interval; /* use if signal > threshold */
+	struct os_time last_bgscan;
+};
+
+
+static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct bgscan_simple_data *data = eloop_ctx;
+	struct wpa_supplicant *wpa_s = data->wpa_s;
+	struct wpa_driver_scan_params params;
+
+	os_memset(&params, 0, sizeof(params));
+	params.num_ssids = 1;
+	params.ssids[0].ssid = data->ssid->ssid;
+	params.ssids[0].ssid_len = data->ssid->ssid_len;
+	params.freqs = data->ssid->scan_freq;
+
+	/*
+	 * A more advanced bgscan module would learn about most like channels
+	 * over time and request scans only for some channels (probing others
+	 * every now and then) to reduce effect on the data connection.
+	 */
+
+	wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
+	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+		wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
+		eloop_register_timeout(data->scan_interval, 0,
+				       bgscan_simple_timeout, data, NULL);
+	} else {
+		if (data->scan_interval == data->short_interval) {
+			data->short_scan_count++;
+			/*
+			 * Spend at most the duration of a long scan interval
+			 * scanning at the short scan interval. After that,
+			 * revert to the long scan interval.
+			 */
+			if (data->short_scan_count > data->max_short_scans) {
+				data->scan_interval = data->long_interval;
+				wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
+					   "off to long scan interval");
+			}
+		} else if (data->short_scan_count > 0) {
+			/*
+			 * If we lasted a long scan interval without any
+			 * CQM triggers, decrease the short-scan count,
+			 * which allows 1 more short-scan interval to
+			 * occur in the future when CQM triggers.
+			 */
+			data->short_scan_count--;
+		}
+		os_get_time(&data->last_bgscan);
+	}
+}
+
+
+static int bgscan_simple_get_params(struct bgscan_simple_data *data,
+				    const char *params)
+{
+	const char *pos;
+
+	if (params == NULL)
+		return 0;
+
+	data->short_interval = atoi(params);
+
+	pos = os_strchr(params, ':');
+	if (pos == NULL)
+		return 0;
+	pos++;
+	data->signal_threshold = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL) {
+		wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval "
+			   "for high signal");
+		return -1;
+	}
+	pos++;
+	data->long_interval = atoi(pos);
+
+	return 0;
+}
+
+
+static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
+				 const char *params,
+				 const struct wpa_ssid *ssid)
+{
+	struct bgscan_simple_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->wpa_s = wpa_s;
+	data->ssid = ssid;
+	if (bgscan_simple_get_params(data, params) < 0) {
+		os_free(data);
+		return NULL;
+	}
+	if (data->short_interval <= 0)
+		data->short_interval = 30;
+	if (data->long_interval <= 0)
+		data->long_interval = 30;
+
+	wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d  "
+		   "Short bgscan interval %d  Long bgscan interval %d",
+		   data->signal_threshold, data->short_interval,
+		   data->long_interval);
+
+	if (data->signal_threshold &&
+	    wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
+		wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable "
+			   "signal strength monitoring");
+	}
+
+	data->scan_interval = data->short_interval;
+	data->max_short_scans = data->long_interval / data->short_interval + 1;
+	if (data->signal_threshold) {
+		/* Poll for signal info to set initial scan interval */
+		struct wpa_signal_info siginfo;
+		if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+		    siginfo.current_signal >= data->signal_threshold)
+			data->scan_interval = data->long_interval;
+	}
+	wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d",
+		   data->scan_interval);
+	eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
+			       data, NULL);
+
+	/*
+	 * This function is called immediately after an association, so it is
+	 * reasonable to assume that a scan was completed recently. This makes
+	 * us skip an immediate new scan in cases where the current signal
+	 * level is below the bgscan threshold.
+	 */
+	os_get_time(&data->last_bgscan);
+
+	return data;
+}
+
+
+static void bgscan_simple_deinit(void *priv)
+{
+	struct bgscan_simple_data *data = priv;
+	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+	if (data->signal_threshold)
+		wpa_drv_signal_monitor(data->wpa_s, 0, 0);
+	os_free(data);
+}
+
+
+static int bgscan_simple_notify_scan(void *priv,
+				     struct wpa_scan_results *scan_res)
+{
+	struct bgscan_simple_data *data = priv;
+
+	wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification");
+
+	eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+	eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
+			       data, NULL);
+
+	/*
+	 * A more advanced bgscan could process scan results internally, select
+	 * the BSS and request roam if needed. This sample uses the existing
+	 * BSS/ESS selection routine. Change this to return 1 if selection is
+	 * done inside the bgscan module.
+	 */
+
+	return 0;
+}
+
+
+static void bgscan_simple_notify_beacon_loss(void *priv)
+{
+	wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss");
+	/* TODO: speed up background scanning */
+}
+
+
+static void bgscan_simple_notify_signal_change(void *priv, int above,
+					       int current_signal,
+					       int current_noise,
+					       int current_txrate)
+{
+	struct bgscan_simple_data *data = priv;
+	int scan = 0;
+	struct os_time now;
+
+	if (data->short_interval == data->long_interval ||
+	    data->signal_threshold == 0)
+		return;
+
+	wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
+		   "(above=%d current_signal=%d current_noise=%d "
+		   "current_txrate=%d))", above, current_signal,
+		   current_noise, current_txrate);
+	if (data->scan_interval == data->long_interval && !above) {
+		wpa_printf(MSG_DEBUG, "bgscan simple: Start using short "
+			   "bgscan interval");
+		data->scan_interval = data->short_interval;
+		os_get_time(&now);
+		if (now.sec > data->last_bgscan.sec + 1 &&
+		    data->short_scan_count <= data->max_short_scans)
+			/*
+			 * If we haven't just previously (<1 second ago)
+			 * performed a scan, and we haven't depleted our
+			 * budget for short-scans, perform a scan
+			 * immediately.
+			 */
+			scan = 1;
+		else if (data->last_bgscan.sec + data->long_interval >
+			 now.sec + data->scan_interval) {
+			/*
+			 * Restart scan interval timer if currently scheduled
+			 * scan is too far in the future.
+			 */
+			eloop_cancel_timeout(bgscan_simple_timeout, data,
+					     NULL);
+			eloop_register_timeout(data->scan_interval, 0,
+					       bgscan_simple_timeout, data,
+					       NULL);
+		}
+	} else if (data->scan_interval == data->short_interval && above) {
+		wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
+			   "interval");
+		data->scan_interval = data->long_interval;
+		eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+		eloop_register_timeout(data->scan_interval, 0,
+				       bgscan_simple_timeout, data, NULL);
+	} else if (!above) {
+		/*
+		 * Signal dropped further 4 dB. Request a new scan if we have
+		 * not yet scanned in a while.
+		 */
+		os_get_time(&now);
+		if (now.sec > data->last_bgscan.sec + 10)
+			scan = 1;
+	}
+
+	if (scan) {
+		wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan");
+		eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+		eloop_register_timeout(0, 0, bgscan_simple_timeout, data,
+				       NULL);
+	}
+}
+
+
+const struct bgscan_ops bgscan_simple_ops = {
+	.name = "simple",
+	.init = bgscan_simple_init,
+	.deinit = bgscan_simple_deinit,
+	.notify_scan = bgscan_simple_notify_scan,
+	.notify_beacon_loss = bgscan_simple_notify_beacon_loss,
+	.notify_signal_change = bgscan_simple_notify_signal_change,
+};

Deleted: vendor/wpa/2.0/wpa_supplicant/blacklist.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/blacklist.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/blacklist.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,133 +0,0 @@
-/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-#include "blacklist.h"
-
-/**
- * wpa_blacklist_get - Get the blacklist entry for a BSSID
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID
- * Returns: Matching blacklist entry for the BSSID or %NULL if not found
- */
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
-					 const u8 *bssid)
-{
-	struct wpa_blacklist *e;
-
-	e = wpa_s->blacklist;
-	while (e) {
-		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
-			return e;
-		e = e->next;
-	}
-
-	return NULL;
-}
-
-
-/**
- * wpa_blacklist_add - Add an BSSID to the blacklist
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be added to the blacklist
- * Returns: 0 on success, -1 on failure
- *
- * This function adds the specified BSSID to the blacklist or increases the
- * blacklist count if the BSSID was already listed. It should be called when
- * an association attempt fails either due to the selected BSS rejecting
- * association or due to timeout.
- *
- * This blacklist is used to force %wpa_supplicant to go through all available
- * BSSes before retrying to associate with an BSS that rejected or timed out
- * association. It does not prevent the listed BSS from being used; it only
- * changes the order in which they are tried.
- */
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct wpa_blacklist *e;
-
-	e = wpa_blacklist_get(wpa_s, bssid);
-	if (e) {
-		e->count++;
-		wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
-			   "incremented to %d",
-			   MAC2STR(bssid), e->count);
-		return 0;
-	}
-
-	e = os_zalloc(sizeof(*e));
-	if (e == NULL)
-		return -1;
-	os_memcpy(e->bssid, bssid, ETH_ALEN);
-	e->count = 1;
-	e->next = wpa_s->blacklist;
-	wpa_s->blacklist = e;
-	wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
-		   MAC2STR(bssid));
-
-	return 0;
-}
-
-
-/**
- * wpa_blacklist_del - Remove an BSSID from the blacklist
- * @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be removed from the blacklist
- * Returns: 0 on success, -1 on failure
- */
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct wpa_blacklist *e, *prev = NULL;
-
-	e = wpa_s->blacklist;
-	while (e) {
-		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
-			if (prev == NULL) {
-				wpa_s->blacklist = e->next;
-			} else {
-				prev->next = e->next;
-			}
-			wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
-				   "blacklist", MAC2STR(bssid));
-			os_free(e);
-			return 0;
-		}
-		prev = e;
-		e = e->next;
-	}
-	return -1;
-}
-
-
-/**
- * wpa_blacklist_clear - Clear the blacklist of all entries
- * @wpa_s: Pointer to wpa_supplicant data
- */
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_blacklist *e, *prev;
-
-	e = wpa_s->blacklist;
-	wpa_s->blacklist = NULL;
-	while (e) {
-		prev = e;
-		e = e->next;
-		wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
-			   "blacklist (clear)", MAC2STR(prev->bssid));
-		os_free(prev);
-	}
-}

Copied: vendor/wpa/2.0/wpa_supplicant/blacklist.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/blacklist.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/blacklist.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/blacklist.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,141 @@
+/*
+ * wpa_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "blacklist.h"
+
+/**
+ * wpa_blacklist_get - Get the blacklist entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ */
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid)
+{
+	struct wpa_blacklist *e;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return NULL;
+
+	e = wpa_s->blacklist;
+	while (e) {
+		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+			return e;
+		e = e->next;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_blacklist_add - Add an BSSID to the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the blacklist
+ * Returns: Current blacklist count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the blacklist or increases the
+ * blacklist count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This blacklist is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_blacklist *e;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return -1;
+
+	e = wpa_blacklist_get(wpa_s, bssid);
+	if (e) {
+		e->count++;
+		wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
+			   "incremented to %d",
+			   MAC2STR(bssid), e->count);
+		return e->count;
+	}
+
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL)
+		return -1;
+	os_memcpy(e->bssid, bssid, ETH_ALEN);
+	e->count = 1;
+	e->next = wpa_s->blacklist;
+	wpa_s->blacklist = e;
+	wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
+		   MAC2STR(bssid));
+
+	return e->count;
+}
+
+
+/**
+ * wpa_blacklist_del - Remove an BSSID from the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be removed from the blacklist
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_blacklist *e, *prev = NULL;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return -1;
+
+	e = wpa_s->blacklist;
+	while (e) {
+		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+			if (prev == NULL) {
+				wpa_s->blacklist = e->next;
+			} else {
+				prev->next = e->next;
+			}
+			wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+				   "blacklist", MAC2STR(bssid));
+			os_free(e);
+			return 0;
+		}
+		prev = e;
+		e = e->next;
+	}
+	return -1;
+}
+
+
+/**
+ * wpa_blacklist_clear - Clear the blacklist of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_blacklist *e, *prev;
+	int max_count = 0;
+
+	e = wpa_s->blacklist;
+	wpa_s->blacklist = NULL;
+	while (e) {
+		if (e->count > max_count)
+			max_count = e->count;
+		prev = e;
+		e = e->next;
+		wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+			   "blacklist (clear)", MAC2STR(prev->bssid));
+		os_free(prev);
+	}
+
+	wpa_s->extra_blacklist_count += max_count;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/blacklist.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/blacklist.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/blacklist.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,30 +0,0 @@
-/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BLACKLIST_H
-#define BLACKLIST_H
-
-struct wpa_blacklist {
-	struct wpa_blacklist *next;
-	u8 bssid[ETH_ALEN];
-	int count;
-};
-
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
-					 const u8 *bssid);
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
-
-#endif /* BLACKLIST_H */

Copied: vendor/wpa/2.0/wpa_supplicant/blacklist.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/blacklist.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/blacklist.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/blacklist.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,24 @@
+/*
+ * wpa_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BLACKLIST_H
+#define BLACKLIST_H
+
+struct wpa_blacklist {
+	struct wpa_blacklist *next;
+	u8 bssid[ETH_ALEN];
+	int count;
+};
+
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid);
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
+
+#endif /* BLACKLIST_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/bss.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/bss.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/bss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,606 +0,0 @@
-/*
- * BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "drivers/driver.h"
-#include "wpa_supplicant_i.h"
-#include "config.h"
-#include "notify.h"
-#include "scan.h"
-#include "bss.h"
-
-
-/**
- * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
- */
-#define WPA_BSS_EXPIRATION_PERIOD 10
-
-/**
- * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired
- *
- * This value control the time in seconds after which a BSS entry gets removed
- * if it has not been updated or is not in use.
- */
-#define WPA_BSS_EXPIRATION_AGE 180
-
-/**
- * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans
- *
- * If the BSS entry has not been seen in this many scans, it will be removed.
- * Value 1 means that the entry is removed after the first scan without the
- * BSSID being seen. Larger values can be used to avoid BSS entries
- * disappearing if they are not visible in every scan (e.g., low signal quality
- * or interference).
- */
-#define WPA_BSS_EXPIRATION_SCAN_COUNT 2
-
-#define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
-#define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
-#define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
-#define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
-#define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
-#define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
-#define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
-#define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
-#define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
-
-
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-{
-	dl_list_del(&bss->list);
-	dl_list_del(&bss->list_id);
-	wpa_s->num_bss--;
-	wpa_printf(MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR " SSID '%s'",
-		   bss->id, MAC2STR(bss->bssid),
-		   wpa_ssid_txt(bss->ssid, bss->ssid_len));
-	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
-	os_free(bss);
-}
-
-
-struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			     const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_bss *bss;
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
-		    bss->ssid_len == ssid_len &&
-		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
-			return bss;
-	}
-	return NULL;
-}
-
-
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
-{
-	os_time_t usec;
-
-	dst->flags = src->flags;
-	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
-	dst->freq = src->freq;
-	dst->beacon_int = src->beacon_int;
-	dst->caps = src->caps;
-	dst->qual = src->qual;
-	dst->noise = src->noise;
-	dst->level = src->level;
-	dst->tsf = src->tsf;
-
-	os_get_time(&dst->last_update);
-	dst->last_update.sec -= src->age / 1000;
-	usec = (src->age % 1000) * 1000;
-	if (dst->last_update.usec < usec) {
-		dst->last_update.sec--;
-		dst->last_update.usec += 1000000;
-	}
-	dst->last_update.usec -= usec;
-}
-
-
-static void wpa_bss_add(struct wpa_supplicant *wpa_s,
-			const u8 *ssid, size_t ssid_len,
-			struct wpa_scan_res *res)
-{
-	struct wpa_bss *bss;
-
-	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
-	if (bss == NULL)
-		return;
-	bss->id = wpa_s->bss_next_id++;
-	bss->last_update_idx = wpa_s->bss_update_idx;
-	wpa_bss_copy_res(bss, res);
-	os_memcpy(bss->ssid, ssid, ssid_len);
-	bss->ssid_len = ssid_len;
-	bss->ie_len = res->ie_len;
-	bss->beacon_ie_len = res->beacon_ie_len;
-	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
-
-	dl_list_add_tail(&wpa_s->bss, &bss->list);
-	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
-	wpa_s->num_bss++;
-	wpa_printf(MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR " SSID '%s'",
-		   bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
-	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
-	if (wpa_s->num_bss > wpa_s->conf->bss_max_count) {
-		/* Remove the oldest entry */
-		wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
-						    struct wpa_bss, list));
-	}
-}
-
-
-static int are_ies_equal(const struct wpa_bss *old,
-			 const struct wpa_scan_res *new, u32 ie)
-{
-	const u8 *old_ie, *new_ie;
-	struct wpabuf *old_ie_buff = NULL;
-	struct wpabuf *new_ie_buff = NULL;
-	int new_ie_len, old_ie_len, ret, is_multi;
-
-	switch (ie) {
-	case WPA_IE_VENDOR_TYPE:
-		old_ie = wpa_bss_get_vendor_ie(old, ie);
-		new_ie = wpa_scan_get_vendor_ie(new, ie);
-		is_multi = 0;
-		break;
-	case WPS_IE_VENDOR_TYPE:
-		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
-		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
-		is_multi = 1;
-		break;
-	case WLAN_EID_RSN:
-	case WLAN_EID_SUPP_RATES:
-	case WLAN_EID_EXT_SUPP_RATES:
-		old_ie = wpa_bss_get_ie(old, ie);
-		new_ie = wpa_scan_get_ie(new, ie);
-		is_multi = 0;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
-		return 0;
-	}
-
-	if (is_multi) {
-		/* in case of multiple IEs stored in buffer */
-		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
-		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
-		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
-		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
-	} else {
-		/* in case of single IE */
-		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
-		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
-	}
-
-	ret = (old_ie_len == new_ie_len &&
-	       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
-
-	wpabuf_free(old_ie_buff);
-	wpabuf_free(new_ie_buff);
-
-	return ret;
-}
-
-
-static u32 wpa_bss_compare_res(const struct wpa_bss *old,
-			       const struct wpa_scan_res *new)
-{
-	u32 changes = 0;
-	int caps_diff = old->caps ^ new->caps;
-
-	if (old->freq != new->freq)
-		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
-
-	if (old->level != new->level)
-		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
-
-	if (caps_diff & IEEE80211_CAP_PRIVACY)
-		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
-
-	if (caps_diff & IEEE80211_CAP_IBSS)
-		changes |= WPA_BSS_MODE_CHANGED_FLAG;
-
-	if (old->ie_len == new->ie_len &&
-	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
-		return changes;
-	changes |= WPA_BSS_IES_CHANGED_FLAG;
-
-	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
-		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
-
-	if (!are_ies_equal(old, new, WLAN_EID_RSN))
-		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
-
-	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
-		changes |= WPA_BSS_WPS_CHANGED_FLAG;
-
-	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
-	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
-		changes |= WPA_BSS_RATES_CHANGED_FLAG;
-
-	return changes;
-}
-
-
-static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
-			       const struct wpa_bss *bss)
-{
-	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
-		wpas_notify_bss_freq_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
-		wpas_notify_bss_signal_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
-		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
-		wpas_notify_bss_mode_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
-		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
-		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
-		wpas_notify_bss_wps_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_IES_CHANGED_FLAG)
-		wpas_notify_bss_ies_changed(wpa_s, bss->id);
-
-	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
-		wpas_notify_bss_rates_changed(wpa_s, bss->id);
-}
-
-
-static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
-			   struct wpa_scan_res *res)
-{
-	u32 changes;
-
-	changes = wpa_bss_compare_res(bss, res);
-	bss->scan_miss_count = 0;
-	bss->last_update_idx = wpa_s->bss_update_idx;
-	wpa_bss_copy_res(bss, res);
-	/* Move the entry to the end of the list */
-	dl_list_del(&bss->list);
-	if (bss->ie_len + bss->beacon_ie_len >=
-	    res->ie_len + res->beacon_ie_len) {
-		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
-		bss->ie_len = res->ie_len;
-		bss->beacon_ie_len = res->beacon_ie_len;
-	} else {
-		struct wpa_bss *nbss;
-		struct dl_list *prev = bss->list_id.prev;
-		dl_list_del(&bss->list_id);
-		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
-				  res->beacon_ie_len);
-		if (nbss) {
-			bss = nbss;
-			os_memcpy(bss + 1, res + 1,
-				  res->ie_len + res->beacon_ie_len);
-			bss->ie_len = res->ie_len;
-			bss->beacon_ie_len = res->beacon_ie_len;
-		}
-		dl_list_add(prev, &bss->list_id);
-	}
-	dl_list_add_tail(&wpa_s->bss, &bss->list);
-
-	notify_bss_changes(wpa_s, changes, bss);
-}
-
-
-static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-{
-	return bss == wpa_s->current_bss ||
-		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
-		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
-}
-
-
-void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->bss_update_idx++;
-	wpa_printf(MSG_DEBUG, "BSS: Start scan result update %u",
-		   wpa_s->bss_update_idx);
-}
-
-
-void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
-			     struct wpa_scan_res *res)
-{
-	const u8 *ssid;
-	struct wpa_bss *bss;
-
-	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR,
-			   MAC2STR(res->bssid));
-		return;
-	}
-	if (ssid[1] > 32) {
-		wpa_printf(MSG_DEBUG, "BSS: Too long SSID IE included for "
-			   MACSTR, MAC2STR(res->bssid));
-		return;
-	}
-
-	/* TODO: add option for ignoring BSSes we are not interested in
-	 * (to save memory) */
-	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
-	if (bss == NULL)
-		wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
-	else
-		wpa_bss_update(wpa_s, bss, res);
-}
-
-
-static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
-				    const struct scan_info *info)
-{
-	int found;
-	size_t i;
-
-	if (info == NULL)
-		return 1;
-
-	if (info->num_freqs) {
-		found = 0;
-		for (i = 0; i < info->num_freqs; i++) {
-			if (bss->freq == info->freqs[i]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			return 0;
-	}
-
-	if (info->num_ssids) {
-		found = 0;
-		for (i = 0; i < info->num_ssids; i++) {
-			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
-			if ((s->ssid == NULL || s->ssid_len == 0) ||
-			    (s->ssid_len == bss->ssid_len &&
-			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
-			     0)) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			return 0;
-	}
-
-	return 1;
-}
-
-
-void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
-			int new_scan)
-{
-	struct wpa_bss *bss, *n;
-
-	if (!new_scan)
-		return; /* do not expire entries without new scan */
-
-	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
-		if (wpa_bss_in_use(wpa_s, bss))
-			continue;
-		if (!wpa_bss_included_in_scan(bss, info))
-			continue; /* expire only BSSes that were scanned */
-		if (bss->last_update_idx < wpa_s->bss_update_idx)
-			bss->scan_miss_count++;
-		if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) {
-			wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to no "
-				   "match in scan", bss->id);
-			wpa_bss_remove(wpa_s, bss);
-		}
-	}
-}
-
-
-static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct wpa_bss *bss, *n;
-	struct os_time t;
-
-	if (dl_list_empty(&wpa_s->bss))
-		return;
-
-	os_get_time(&t);
-	t.sec -= WPA_BSS_EXPIRATION_AGE;
-
-	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
-		if (wpa_bss_in_use(wpa_s, bss))
-			continue;
-
-		if (os_time_before(&bss->last_update, &t)) {
-			wpa_printf(MSG_DEBUG, "BSS: Expire BSS %u due to age",
-				   bss->id);
-			wpa_bss_remove(wpa_s, bss);
-		} else
-			break;
-	}
-	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
-			       wpa_bss_timeout, wpa_s, NULL);
-}
-
-
-int wpa_bss_init(struct wpa_supplicant *wpa_s)
-{
-	dl_list_init(&wpa_s->bss);
-	dl_list_init(&wpa_s->bss_id);
-	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
-			       wpa_bss_timeout, wpa_s, NULL);
-	return 0;
-}
-
-
-void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_bss *bss, *n;
-	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
-	if (wpa_s->bss.next == NULL)
-		return; /* BSS table not yet initialized */
-	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list)
-		wpa_bss_remove(wpa_s, bss);
-}
-
-
-struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
-				   const u8 *bssid)
-{
-	struct wpa_bss *bss;
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
-			return bss;
-	}
-	return NULL;
-}
-
-
-struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
-{
-	struct wpa_bss *bss;
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (bss->id == id)
-			return bss;
-	}
-	return NULL;
-}
-
-
-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;
-}
-
-
-const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
-{
-	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] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    vendor_type == WPA_GET_BE32(&pos[2]))
-			return pos;
-		pos += 2 + pos[1];
-	}
-
-	return NULL;
-}
-
-
-struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
-					    u32 vendor_type)
-{
-	struct wpabuf *buf;
-	const u8 *end, *pos;
-
-	buf = wpabuf_alloc(bss->ie_len);
-	if (buf == NULL)
-		return NULL;
-
-	pos = (const u8 *) (bss + 1);
-	end = pos + bss->ie_len;
-
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    vendor_type == WPA_GET_BE32(&pos[2]))
-			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
-		pos += 2 + pos[1];
-	}
-
-	if (wpabuf_len(buf) == 0) {
-		wpabuf_free(buf);
-		buf = NULL;
-	}
-
-	return buf;
-}
-
-
-int wpa_bss_get_max_rate(const struct wpa_bss *bss)
-{
-	int rate = 0;
-	const u8 *ie;
-	int i;
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
-	for (i = 0; ie && i < ie[1]; i++) {
-		if ((ie[i + 2] & 0x7f) > rate)
-			rate = ie[i + 2] & 0x7f;
-	}
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
-	for (i = 0; ie && i < ie[1]; i++) {
-		if ((ie[i + 2] & 0x7f) > rate)
-			rate = ie[i + 2] & 0x7f;
-	}
-
-	return rate;
-}
-
-
-int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
-{
-	const u8 *ie, *ie2;
-	int i, j;
-	unsigned int len;
-	u8 *r;
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
-	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
-
-	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
-
-	r = os_malloc(len);
-	if (!r)
-		return -1;
-
-	for (i = 0; ie && i < ie[1]; i++)
-		r[i] = ie[i + 2] & 0x7f;
-
-	for (j = 0; ie2 && j < ie2[1]; j++)
-		r[i + j] = ie2[j + 2] & 0x7f;
-
-	*rates = r;
-	return len;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/bss.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/bss.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bss.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bss.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1070 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "notify.h"
+#include "scan.h"
+#include "bss.h"
+
+
+/**
+ * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
+ */
+#define WPA_BSS_EXPIRATION_PERIOD 10
+
+#define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
+#define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
+#define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
+#define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
+#define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
+#define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
+#define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
+#define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
+#define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
+
+
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+	const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+	if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+		os_memset(bss->hessid, 0, ETH_ALEN);
+		return;
+	}
+	if (ie[1] == 7)
+		os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+	else
+		os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
+ * Returns: Allocated ANQP data structure or %NULL on failure
+ *
+ * The allocated ANQP data structure has its users count set to 1. It may be
+ * shared by multiple BSS entries and each shared entry is freed with
+ * wpa_bss_anqp_free().
+ */
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+	struct wpa_bss_anqp *anqp;
+	anqp = os_zalloc(sizeof(*anqp));
+	if (anqp == NULL)
+		return NULL;
+	anqp->users = 1;
+	return anqp;
+}
+
+
+/**
+ * wpa_bss_anqp_clone - Clone an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
+ * Returns: Cloned ANQP data structure or %NULL on failure
+ */
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+	struct wpa_bss_anqp *n;
+
+	n = os_zalloc(sizeof(*n));
+	if (n == NULL)
+		return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+	ANQP_DUP(venue_name);
+	ANQP_DUP(network_auth_type);
+	ANQP_DUP(roaming_consortium);
+	ANQP_DUP(ip_addr_type_availability);
+	ANQP_DUP(nai_realm);
+	ANQP_DUP(anqp_3gpp);
+	ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	ANQP_DUP(hs20_operator_friendly_name);
+	ANQP_DUP(hs20_wan_metrics);
+	ANQP_DUP(hs20_connection_capability);
+	ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+	return n;
+}
+
+
+/**
+ * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
+ * @bss: BSS entry
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function ensures the specific BSS entry has an ANQP data structure that
+ * is not shared with any other BSS entry.
+ */
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+	struct wpa_bss_anqp *anqp;
+
+	if (bss->anqp && bss->anqp->users > 1) {
+		/* allocated, but shared - clone an unshared copy */
+		anqp = wpa_bss_anqp_clone(bss->anqp);
+		if (anqp == NULL)
+			return -1;
+		anqp->users = 1;
+		bss->anqp->users--;
+		bss->anqp = anqp;
+		return 0;
+	}
+
+	if (bss->anqp)
+		return 0; /* already allocated and not shared */
+
+	/* not allocated - allocate a new storage area */
+	bss->anqp = wpa_bss_anqp_alloc();
+	return bss->anqp ? 0 : -1;
+}
+
+
+/**
+ * wpa_bss_anqp_free - Free an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
+ */
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+	if (anqp == NULL)
+		return;
+
+	anqp->users--;
+	if (anqp->users > 0) {
+		/* Another BSS entry holds a pointer to this ANQP info */
+		return;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	wpabuf_free(anqp->venue_name);
+	wpabuf_free(anqp->network_auth_type);
+	wpabuf_free(anqp->roaming_consortium);
+	wpabuf_free(anqp->ip_addr_type_availability);
+	wpabuf_free(anqp->nai_realm);
+	wpabuf_free(anqp->anqp_3gpp);
+	wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	wpabuf_free(anqp->hs20_operator_friendly_name);
+	wpabuf_free(anqp->hs20_wan_metrics);
+	wpabuf_free(anqp->hs20_connection_capability);
+	wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+	os_free(anqp);
+}
+
+
+static 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;
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			if (wpa_s->last_scan_res[i] == bss) {
+				os_memmove(&wpa_s->last_scan_res[i],
+					   &wpa_s->last_scan_res[i + 1],
+					   (wpa_s->last_scan_res_used - i - 1)
+					   * sizeof(struct wpa_bss *));
+				wpa_s->last_scan_res_used--;
+				break;
+			}
+		}
+	}
+	dl_list_del(&bss->list);
+	dl_list_del(&bss->list_id);
+	wpa_s->num_bss--;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
+		" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+		wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
+	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
+	wpa_bss_anqp_free(bss->anqp);
+	os_free(bss);
+}
+
+
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+		return NULL;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+		    bss->ssid_len == ssid_len &&
+		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+{
+	os_time_t usec;
+
+	dst->flags = src->flags;
+	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
+	dst->freq = src->freq;
+	dst->beacon_int = src->beacon_int;
+	dst->caps = src->caps;
+	dst->qual = src->qual;
+	dst->noise = src->noise;
+	dst->level = src->level;
+	dst->tsf = src->tsf;
+
+	os_get_time(&dst->last_update);
+	dst->last_update.sec -= src->age / 1000;
+	usec = (src->age % 1000) * 1000;
+	if (dst->last_update.usec < usec) {
+		dst->last_update.sec--;
+		dst->last_update.usec += 1000000;
+	}
+	dst->last_update.usec -= usec;
+}
+
+
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->ssid == NULL || ssid->ssid_len == 0)
+			continue;
+		if (ssid->ssid_len == bss->ssid_len &&
+		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	return bss == wpa_s->current_bss ||
+		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+}
+
+
+static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_known(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	/*
+	 * Remove the oldest entry that does not match with any configured
+	 * network.
+	 */
+	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+		return 0;
+
+	/*
+	 * Remove the oldest entry that isn't currently in use.
+	 */
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_in_use(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
+				    const u8 *ssid, size_t ssid_len,
+				    struct wpa_scan_res *res)
+{
+	struct wpa_bss *bss;
+
+	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
+	if (bss == NULL)
+		return NULL;
+	bss->id = wpa_s->bss_next_id++;
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res);
+	os_memcpy(bss->ssid, ssid, ssid_len);
+	bss->ssid_len = ssid_len;
+	bss->ie_len = res->ie_len;
+	bss->beacon_ie_len = res->beacon_ie_len;
+	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+	wpa_bss_set_hessid(bss);
+
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
+	wpa_s->num_bss++;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
+		" SSID '%s'",
+		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
+	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
+	if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
+	    wpa_bss_remove_oldest(wpa_s) != 0) {
+		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+			   "because all BSSes are in use. We should normally "
+			   "not get here!", (int) wpa_s->num_bss);
+		wpa_s->conf->bss_max_count = wpa_s->num_bss;
+	}
+	return bss;
+}
+
+
+static int are_ies_equal(const struct wpa_bss *old,
+			 const struct wpa_scan_res *new, u32 ie)
+{
+	const u8 *old_ie, *new_ie;
+	struct wpabuf *old_ie_buff = NULL;
+	struct wpabuf *new_ie_buff = NULL;
+	int new_ie_len, old_ie_len, ret, is_multi;
+
+	switch (ie) {
+	case WPA_IE_VENDOR_TYPE:
+		old_ie = wpa_bss_get_vendor_ie(old, ie);
+		new_ie = wpa_scan_get_vendor_ie(new, ie);
+		is_multi = 0;
+		break;
+	case WPS_IE_VENDOR_TYPE:
+		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
+		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
+		is_multi = 1;
+		break;
+	case WLAN_EID_RSN:
+	case WLAN_EID_SUPP_RATES:
+	case WLAN_EID_EXT_SUPP_RATES:
+		old_ie = wpa_bss_get_ie(old, ie);
+		new_ie = wpa_scan_get_ie(new, ie);
+		is_multi = 0;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
+		return 0;
+	}
+
+	if (is_multi) {
+		/* in case of multiple IEs stored in buffer */
+		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
+		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
+		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
+		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
+	} else {
+		/* in case of single IE */
+		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
+		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
+	}
+
+	if (!old_ie || !new_ie)
+		ret = !old_ie && !new_ie;
+	else
+		ret = (old_ie_len == new_ie_len &&
+		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
+
+	wpabuf_free(old_ie_buff);
+	wpabuf_free(new_ie_buff);
+
+	return ret;
+}
+
+
+static u32 wpa_bss_compare_res(const struct wpa_bss *old,
+			       const struct wpa_scan_res *new)
+{
+	u32 changes = 0;
+	int caps_diff = old->caps ^ new->caps;
+
+	if (old->freq != new->freq)
+		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
+
+	if (old->level != new->level)
+		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
+
+	if (caps_diff & IEEE80211_CAP_PRIVACY)
+		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
+
+	if (caps_diff & IEEE80211_CAP_IBSS)
+		changes |= WPA_BSS_MODE_CHANGED_FLAG;
+
+	if (old->ie_len == new->ie_len &&
+	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
+		return changes;
+	changes |= WPA_BSS_IES_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
+		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WLAN_EID_RSN))
+		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
+		changes |= WPA_BSS_WPS_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
+	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
+		changes |= WPA_BSS_RATES_CHANGED_FLAG;
+
+	return changes;
+}
+
+
+static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+			       const struct wpa_bss *bss)
+{
+	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
+		wpas_notify_bss_freq_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
+		wpas_notify_bss_signal_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
+		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
+		wpas_notify_bss_mode_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
+		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
+		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
+		wpas_notify_bss_wps_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_IES_CHANGED_FLAG)
+		wpas_notify_bss_ies_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
+		wpas_notify_bss_rates_changed(wpa_s, bss->id);
+}
+
+
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+	       struct wpa_scan_res *res)
+{
+	u32 changes;
+
+	changes = wpa_bss_compare_res(bss, res);
+	bss->scan_miss_count = 0;
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res);
+	/* Move the entry to the end of the list */
+	dl_list_del(&bss->list);
+	if (bss->ie_len + bss->beacon_ie_len >=
+	    res->ie_len + res->beacon_ie_len) {
+		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+		bss->ie_len = res->ie_len;
+		bss->beacon_ie_len = res->beacon_ie_len;
+	} else {
+		struct wpa_bss *nbss;
+		struct dl_list *prev = bss->list_id.prev;
+		dl_list_del(&bss->list_id);
+		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
+				  res->beacon_ie_len);
+		if (nbss) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (wpa_s->last_scan_res[i] == bss) {
+					wpa_s->last_scan_res[i] = nbss;
+					break;
+				}
+			}
+			if (wpa_s->current_bss == bss)
+				wpa_s->current_bss = nbss;
+			bss = nbss;
+			os_memcpy(bss + 1, res + 1,
+				  res->ie_len + res->beacon_ie_len);
+			bss->ie_len = res->ie_len;
+			bss->beacon_ie_len = res->beacon_ie_len;
+		}
+		dl_list_add(prev, &bss->list_id);
+	}
+	if (changes & WPA_BSS_IES_CHANGED_FLAG)
+		wpa_bss_set_hessid(bss);
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+
+	notify_bss_changes(wpa_s, changes, bss);
+
+	return bss;
+}
+
+
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->bss_update_idx++;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
+		wpa_s->bss_update_idx);
+	wpa_s->last_scan_res_used = 0;
+}
+
+
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res)
+{
+	const u8 *ssid, *p2p;
+	struct wpa_bss *bss;
+
+	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+	if (ssid[1] > 32) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+
+	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+#ifdef CONFIG_P2P
+	if (p2p == NULL &&
+	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+		/*
+		 * If it's a P2P specific interface, then don't update
+		 * the scan result without a P2P IE.
+		 */
+		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
+			   " update for P2P interface", MAC2STR(res->bssid));
+		return;
+	}
+#endif /* CONFIG_P2P */
+	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
+		return; /* Skip P2P listen discovery results here */
+
+	/* TODO: add option for ignoring BSSes we are not interested in
+	 * (to save memory) */
+	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
+	if (bss == NULL)
+		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
+	else
+		bss = wpa_bss_update(wpa_s, bss, res);
+
+	if (bss == NULL)
+		return;
+	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
+		struct wpa_bss **n;
+		unsigned int siz;
+		if (wpa_s->last_scan_res_size == 0)
+			siz = 32;
+		else
+			siz = wpa_s->last_scan_res_size * 2;
+		n = os_realloc_array(wpa_s->last_scan_res, siz,
+				     sizeof(struct wpa_bss *));
+		if (n == NULL)
+			return;
+		wpa_s->last_scan_res = n;
+		wpa_s->last_scan_res_size = siz;
+	}
+
+	wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
+}
+
+
+static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
+				    const struct scan_info *info)
+{
+	int found;
+	size_t i;
+
+	if (info == NULL)
+		return 1;
+
+	if (info->num_freqs) {
+		found = 0;
+		for (i = 0; i < info->num_freqs; i++) {
+			if (bss->freq == info->freqs[i]) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			return 0;
+	}
+
+	if (info->num_ssids) {
+		found = 0;
+		for (i = 0; i < info->num_ssids; i++) {
+			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
+			if ((s->ssid == NULL || s->ssid_len == 0) ||
+			    (s->ssid_len == bss->ssid_len &&
+			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
+			     0)) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
+void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
+			int new_scan)
+{
+	struct wpa_bss *bss, *n;
+
+	wpa_s->last_scan_full = 0;
+	os_get_time(&wpa_s->last_scan);
+	if (!new_scan)
+		return; /* do not expire entries without new scan */
+
+	if (info && !info->aborted && !info->freqs) {
+		size_t i;
+		if (info->num_ssids == 0) {
+			wpa_s->last_scan_full = 1;
+		} else {
+			for (i = 0; i < info->num_ssids; i++) {
+				if (info->ssids[i].ssid == NULL ||
+				    info->ssids[i].ssid_len == 0) {
+					wpa_s->last_scan_full = 1;
+					break;
+				}
+			}
+		}
+	}
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+		if (!wpa_bss_included_in_scan(bss, info))
+			continue; /* expire only BSSes that were scanned */
+		if (bss->last_update_idx < wpa_s->bss_update_idx)
+			bss->scan_miss_count++;
+		if (bss->scan_miss_count >=
+		    wpa_s->conf->bss_expiration_scan_count) {
+			wpa_bss_remove(wpa_s, bss, "no match in scan");
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
+		   "last_scan_full=%d",
+		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
+		   wpa_s->last_scan_full);
+}
+
+
+/**
+ * wpa_bss_flush_by_age - Flush old BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @age: Maximum entry age in seconds
+ *
+ * Remove BSS entries that have not been updated during the last @age seconds.
+ */
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
+{
+	struct wpa_bss *bss, *n;
+	struct os_time t;
+
+	if (dl_list_empty(&wpa_s->bss))
+		return;
+
+	os_get_time(&t);
+	t.sec -= age;
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+
+		if (os_time_before(&bss->last_update, &t)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+		} else
+			break;
+	}
+}
+
+
+static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
+	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
+			       wpa_bss_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
+int wpa_bss_init(struct wpa_supplicant *wpa_s)
+{
+	dl_list_init(&wpa_s->bss);
+	dl_list_init(&wpa_s->bss_id);
+	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
+			       wpa_bss_timeout, wpa_s, NULL);
+	return 0;
+}
+
+
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_flush(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *n;
+
+	if (wpa_s->bss.next == NULL)
+		return; /* BSS table not yet initialized */
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+		wpa_bss_remove(wpa_s, bss, __func__);
+	}
+}
+
+
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+	wpa_bss_flush(wpa_s);
+}
+
+
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid)
+{
+	struct wpa_bss *bss;
+	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+		return NULL;
+	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+#ifdef CONFIG_P2P
+/**
+ * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dev_addr: P2P Device Address of the GO
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+		u8 addr[ETH_ALEN];
+		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+				       addr) == 0 &&
+		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+#endif /* CONFIG_P2P */
+
+
+/**
+ * wpa_bss_get_id - Fetch a BSS table entry based on identifier
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (bss->id == id)
+			return bss;
+	}
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (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 BSS
+ * entry.
+ */
+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;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
+{
+	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] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
+					    u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(bss->ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	end = pos + bss->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ *
+ * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+						   u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(bss->beacon_ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	pos += bss->ie_len;
+	end = pos + bss->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/**
+ * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
+ * @bss: BSS table entry
+ * Returns: Maximum legacy rate in units of 500 kbps
+ */
+int wpa_bss_get_max_rate(const struct wpa_bss *bss)
+{
+	int rate = 0;
+	const u8 *ie;
+	int i;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	return rate;
+}
+
+
+/**
+ * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
+ * @bss: BSS table entry
+ * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
+ * Returns: number of legacy TX rates or -1 on failure
+ *
+ * The caller is responsible for freeing the returned buffer with os_free() in
+ * case of success.
+ */
+int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
+{
+	const u8 *ie, *ie2;
+	int i, j;
+	unsigned int len;
+	u8 *r;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
+
+	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
+
+	r = os_malloc(len);
+	if (!r)
+		return -1;
+
+	for (i = 0; ie && i < ie[1]; i++)
+		r[i] = ie[i + 2] & 0x7f;
+
+	for (j = 0; ie2 && j < ie2[1]; j++)
+		r[i + j] = ie2[j + 2] & 0x7f;
+
+	*rates = r;
+	return len;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/bss.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/bss.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/bss.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,93 +0,0 @@
-/*
- * BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef BSS_H
-#define BSS_H
-
-struct wpa_scan_res;
-
-#define WPA_BSS_QUAL_INVALID		BIT(0)
-#define WPA_BSS_NOISE_INVALID		BIT(1)
-#define WPA_BSS_LEVEL_INVALID		BIT(2)
-#define WPA_BSS_LEVEL_DBM		BIT(3)
-#define WPA_BSS_AUTHENTICATED		BIT(4)
-#define WPA_BSS_ASSOCIATED		BIT(5)
-
-/**
- * struct wpa_bss - BSS table
- * @list: List entry for struct wpa_supplicant::bss
- * @list_id: List entry for struct wpa_supplicant::bss_id
- * @id: Unique identifier for this BSS entry
- * @scan_miss_count: Number of counts without seeing this BSS
- * @flags: information flags about the BSS/IBSS (WPA_BSS_*)
- * @last_update_idx: Index of the last scan update
- * @bssid: BSSID
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @beacon_int: beacon interval in TUs (host byte order)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @tsf: Timestamp of last Beacon/Probe Response frame
- * @last_update: Time of the last update (i.e., Beacon or Probe Response RX)
- * @ie_len: length of the following IE field in octets (from Probe Response)
- * @beacon_ie_len: length of the following Beacon IE field in octets
- *
- * This structure is used to store information about neighboring BSSes in
- * generic format. It is mainly updated based on scan results from the driver.
- */
-struct wpa_bss {
-	struct dl_list list;
-	struct dl_list list_id;
-	unsigned int id;
-	unsigned int scan_miss_count;
-	unsigned int last_update_idx;
-	unsigned int flags;
-	u8 bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
-	int freq;
-	u16 beacon_int;
-	u16 caps;
-	int qual;
-	int noise;
-	int level;
-	u64 tsf;
-	struct os_time last_update;
-	size_t ie_len;
-	size_t beacon_ie_len;
-	/* followed by ie_len octets of IEs */
-	/* followed by beacon_ie_len octets of IEs */
-};
-
-void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
-void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
-			     struct wpa_scan_res *res);
-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);
-void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
-struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			     const u8 *ssid, size_t ssid_len);
-struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
-				   const u8 *bssid);
-struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
-const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
-const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
-struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
-					    u32 vendor_type);
-int wpa_bss_get_max_rate(const struct wpa_bss *bss);
-int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
-
-#endif /* BSS_H */

Copied: vendor/wpa/2.0/wpa_supplicant/bss.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/bss.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/bss.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/bss.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,125 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_H
+#define BSS_H
+
+struct wpa_scan_res;
+
+#define WPA_BSS_QUAL_INVALID		BIT(0)
+#define WPA_BSS_NOISE_INVALID		BIT(1)
+#define WPA_BSS_LEVEL_INVALID		BIT(2)
+#define WPA_BSS_LEVEL_DBM		BIT(3)
+#define WPA_BSS_AUTHENTICATED		BIT(4)
+#define WPA_BSS_ASSOCIATED		BIT(5)
+#define WPA_BSS_ANQP_FETCH_TRIED	BIT(6)
+
+/**
+ * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
+ */
+struct wpa_bss_anqp {
+	/** Number of BSS entries referring to this ANQP data instance */
+	unsigned int users;
+#ifdef CONFIG_INTERWORKING
+	struct wpabuf *venue_name;
+	struct wpabuf *network_auth_type;
+	struct wpabuf *roaming_consortium;
+	struct wpabuf *ip_addr_type_availability;
+	struct wpabuf *nai_realm;
+	struct wpabuf *anqp_3gpp;
+	struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	struct wpabuf *hs20_operator_friendly_name;
+	struct wpabuf *hs20_wan_metrics;
+	struct wpabuf *hs20_connection_capability;
+	struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
+/**
+ * struct wpa_bss - BSS table
+ *
+ * This structure is used to store information about neighboring BSSes in
+ * generic format. It is mainly updated based on scan results from the driver.
+ */
+struct wpa_bss {
+	/** List entry for struct wpa_supplicant::bss */
+	struct dl_list list;
+	/** List entry for struct wpa_supplicant::bss_id */
+	struct dl_list list_id;
+	/** Unique identifier for this BSS entry */
+	unsigned int id;
+	/** Number of counts without seeing this BSS */
+	unsigned int scan_miss_count;
+	/** Index of the last scan update */
+	unsigned int last_update_idx;
+	/** Information flags about the BSS/IBSS (WPA_BSS_*) */
+	unsigned int flags;
+	/** BSSID */
+	u8 bssid[ETH_ALEN];
+	/** HESSID */
+	u8 hessid[ETH_ALEN];
+	/** SSID */
+	u8 ssid[32];
+	/** Length of SSID */
+	size_t ssid_len;
+	/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
+	int freq;
+	/** Beacon interval in TUs (host byte order) */
+	u16 beacon_int;
+	/** Capability information field in host byte order */
+	u16 caps;
+	/** Signal quality */
+	int qual;
+	/** Noise level */
+	int noise;
+	/** Signal level */
+	int level;
+	/** Timestamp of last Beacon/Probe Response frame */
+	u64 tsf;
+	/** Time of the last update (i.e., Beacon or Probe Response RX) */
+	struct os_time last_update;
+	/** ANQP data */
+	struct wpa_bss_anqp *anqp;
+	/** Length of the following IE field in octets (from Probe Response) */
+	size_t ie_len;
+	/** Length of the following Beacon IE field in octets */
+	size_t beacon_ie_len;
+	/* followed by ie_len octets of IEs */
+	/* followed by beacon_ie_len octets of IEs */
+};
+
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res);
+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);
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age);
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len);
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid);
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr);
+struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
+					    u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+						   u32 vendor_type);
+int wpa_bss_get_max_rate(const struct wpa_bss *bss);
+int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
+
+#endif /* BSS_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/config.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2167 +0,0 @@
-/*
- * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-#include "rsn_supp/wpa.h"
-#include "eap_peer/eap.h"
-#include "config.h"
-
-
-#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
-#define NO_CONFIG_WRITE
-#endif
-
-/*
- * Structure for network configuration parsing. This data is used to implement
- * a generic parser for each network block variable. The table of configuration
- * variables is defined below in this file (ssid_fields[]).
- */
-struct parse_data {
-	/* Configuration variable name */
-	char *name;
-
-	/* Parser function for this variable */
-	int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
-		      int line, const char *value);
-
-#ifndef NO_CONFIG_WRITE
-	/* Writer function (i.e., to get the variable in text format from
-	 * internal presentation). */
-	char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
-#endif /* NO_CONFIG_WRITE */
-
-	/* Variable specific parameters for the parser. */
-	void *param1, *param2, *param3, *param4;
-
-	/* 0 = this variable can be included in debug output and ctrl_iface
-	 * 1 = this variable contains key/private data and it must not be
-	 *     included in debug output unless explicitly requested. In
-	 *     addition, this variable will not be readable through the
-	 *     ctrl_iface.
-	 */
-	int key_data;
-};
-
-
-static char * wpa_config_parse_string(const char *value, size_t *len)
-{
-	if (*value == '"') {
-		const char *pos;
-		char *str;
-		value++;
-		pos = os_strrchr(value, '"');
-		if (pos == NULL || pos[1] != '\0')
-			return NULL;
-		*len = pos - value;
-		str = os_malloc(*len + 1);
-		if (str == NULL)
-			return NULL;
-		os_memcpy(str, value, *len);
-		str[*len] = '\0';
-		return str;
-	} else {
-		u8 *str;
-		size_t tlen, hlen = os_strlen(value);
-		if (hlen & 1)
-			return NULL;
-		tlen = hlen / 2;
-		str = os_malloc(tlen + 1);
-		if (str == NULL)
-			return NULL;
-		if (hexstr2bin(value, str, tlen)) {
-			os_free(str);
-			return NULL;
-		}
-		str[tlen] = '\0';
-		*len = tlen;
-		return (char *) str;
-	}
-}
-
-
-static int wpa_config_parse_str(const struct parse_data *data,
-				struct wpa_ssid *ssid,
-				int line, const char *value)
-{
-	size_t res_len, *dst_len;
-	char **dst, *tmp;
-
-	if (os_strcmp(value, "NULL") == 0) {
-		wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
-			   data->name);
-		tmp = NULL;
-		res_len = 0;
-		goto set;
-	}
-
-	tmp = wpa_config_parse_string(value, &res_len);
-	if (tmp == NULL) {
-		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
-			   line, data->name,
-			   data->key_data ? "[KEY DATA REMOVED]" : value);
-		return -1;
-	}
-
-	if (data->key_data) {
-		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
-				      (u8 *) tmp, res_len);
-	} else {
-		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
-				  (u8 *) tmp, res_len);
-	}
-
-	if (data->param3 && res_len < (size_t) data->param3) {
-		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
-			   "min_len=%ld)", line, data->name,
-			   (unsigned long) res_len, (long) data->param3);
-		os_free(tmp);
-		return -1;
-	}
-
-	if (data->param4 && res_len > (size_t) data->param4) {
-		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
-			   "max_len=%ld)", line, data->name,
-			   (unsigned long) res_len, (long) data->param4);
-		os_free(tmp);
-		return -1;
-	}
-
-set:
-	dst = (char **) (((u8 *) ssid) + (long) data->param1);
-	dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
-	os_free(*dst);
-	*dst = tmp;
-	if (data->param2)
-		*dst_len = res_len;
-
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static int is_hex(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;
-}
-
-
-static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
-{
-	char *buf;
-
-	buf = os_malloc(len + 3);
-	if (buf == NULL)
-		return NULL;
-	buf[0] = '"';
-	os_memcpy(buf + 1, value, len);
-	buf[len + 1] = '"';
-	buf[len + 2] = '\0';
-
-	return buf;
-}
-
-
-static char * wpa_config_write_string_hex(const u8 *value, size_t len)
-{
-	char *buf;
-
-	buf = os_zalloc(2 * len + 1);
-	if (buf == NULL)
-		return NULL;
-	wpa_snprintf_hex(buf, 2 * len + 1, value, len);
-
-	return buf;
-}
-
-
-static char * wpa_config_write_string(const u8 *value, size_t len)
-{
-	if (value == NULL)
-		return NULL;
-
-	if (is_hex(value, len))
-		return wpa_config_write_string_hex(value, len);
-	else
-		return wpa_config_write_string_ascii(value, len);
-}
-
-
-static char * wpa_config_write_str(const struct parse_data *data,
-				   struct wpa_ssid *ssid)
-{
-	size_t len;
-	char **src;
-
-	src = (char **) (((u8 *) ssid) + (long) data->param1);
-	if (*src == NULL)
-		return NULL;
-
-	if (data->param2)
-		len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
-	else
-		len = os_strlen(*src);
-
-	return wpa_config_write_string((const u8 *) *src, len);
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_int(const struct parse_data *data,
-				struct wpa_ssid *ssid,
-				int line, const char *value)
-{
-	int *dst;
-
-	dst = (int *) (((u8 *) ssid) + (long) data->param1);
-	*dst = atoi(value);
-	wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
-
-	if (data->param3 && *dst < (long) data->param3) {
-		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
-			   "min_value=%ld)", line, data->name, *dst,
-			   (long) data->param3);
-		*dst = (long) data->param3;
-		return -1;
-	}
-
-	if (data->param4 && *dst > (long) data->param4) {
-		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
-			   "max_value=%ld)", line, data->name, *dst,
-			   (long) data->param4);
-		*dst = (long) data->param4;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_int(const struct parse_data *data,
-				   struct wpa_ssid *ssid)
-{
-	int *src, res;
-	char *value;
-
-	src = (int *) (((u8 *) ssid) + (long) data->param1);
-
-	value = os_malloc(20);
-	if (value == NULL)
-		return NULL;
-	res = os_snprintf(value, 20, "%d", *src);
-	if (res < 0 || res >= 20) {
-		os_free(value);
-		return NULL;
-	}
-	value[20 - 1] = '\0';
-	return value;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_bssid(const struct parse_data *data,
-				  struct wpa_ssid *ssid, int line,
-				  const char *value)
-{
-	if (hwaddr_aton(value, ssid->bssid)) {
-		wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
-			   line, value);
-		return -1;
-	}
-	ssid->bssid_set = 1;
-	wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_bssid(const struct parse_data *data,
-				     struct wpa_ssid *ssid)
-{
-	char *value;
-	int res;
-
-	if (!ssid->bssid_set)
-		return NULL;
-
-	value = os_malloc(20);
-	if (value == NULL)
-		return NULL;
-	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
-	if (res < 0 || res >= 20) {
-		os_free(value);
-		return NULL;
-	}
-	value[20 - 1] = '\0';
-	return value;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_psk(const struct parse_data *data,
-				struct wpa_ssid *ssid, int line,
-				const char *value)
-{
-	if (*value == '"') {
-#ifndef CONFIG_NO_PBKDF2
-		const char *pos;
-		size_t len;
-
-		value++;
-		pos = os_strrchr(value, '"');
-		if (pos)
-			len = pos - value;
-		else
-			len = os_strlen(value);
-		if (len < 8 || len > 63) {
-			wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
-				   "length %lu (expected: 8..63) '%s'.",
-				   line, (unsigned long) len, value);
-			return -1;
-		}
-		wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
-				      (u8 *) value, len);
-		if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
-		    os_memcmp(ssid->passphrase, value, len) == 0)
-			return 0;
-		ssid->psk_set = 0;
-		os_free(ssid->passphrase);
-		ssid->passphrase = os_malloc(len + 1);
-		if (ssid->passphrase == NULL)
-			return -1;
-		os_memcpy(ssid->passphrase, value, len);
-		ssid->passphrase[len] = '\0';
-		return 0;
-#else /* CONFIG_NO_PBKDF2 */
-		wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
-			   "supported.", line);
-		return -1;
-#endif /* CONFIG_NO_PBKDF2 */
-	}
-
-	if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
-	    value[PMK_LEN * 2] != '\0') {
-		wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
-			   line, value);
-		return -1;
-	}
-
-	os_free(ssid->passphrase);
-	ssid->passphrase = NULL;
-
-	ssid->psk_set = 1;
-	wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_psk(const struct parse_data *data,
-				   struct wpa_ssid *ssid)
-{
-	if (ssid->passphrase)
-		return wpa_config_write_string_ascii(
-			(const u8 *) ssid->passphrase,
-			os_strlen(ssid->passphrase));
-
-	if (ssid->psk_set)
-		return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
-
-	return NULL;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_proto(const struct parse_data *data,
-				  struct wpa_ssid *ssid, int line,
-				  const char *value)
-{
-	int val = 0, last, errors = 0;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "WPA") == 0)
-			val |= WPA_PROTO_WPA;
-		else if (os_strcmp(start, "RSN") == 0 ||
-			 os_strcmp(start, "WPA2") == 0)
-			val |= WPA_PROTO_RSN;
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
-				   line, start);
-			errors++;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	if (val == 0) {
-		wpa_printf(MSG_ERROR,
-			   "Line %d: no proto values configured.", line);
-		errors++;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
-	ssid->proto = val;
-	return errors ? -1 : 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_proto(const struct parse_data *data,
-				     struct wpa_ssid *ssid)
-{
-	int first = 1, ret;
-	char *buf, *pos, *end;
-
-	pos = buf = os_zalloc(10);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 10;
-
-	if (ssid->proto & WPA_PROTO_WPA) {
-		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (ssid->proto & WPA_PROTO_RSN) {
-		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return buf;
-		pos += ret;
-		first = 0;
-	}
-
-	return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_key_mgmt(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	int val = 0, last, errors = 0;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "WPA-PSK") == 0)
-			val |= WPA_KEY_MGMT_PSK;
-		else if (os_strcmp(start, "WPA-EAP") == 0)
-			val |= WPA_KEY_MGMT_IEEE8021X;
-		else if (os_strcmp(start, "IEEE8021X") == 0)
-			val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
-		else if (os_strcmp(start, "NONE") == 0)
-			val |= WPA_KEY_MGMT_NONE;
-		else if (os_strcmp(start, "WPA-NONE") == 0)
-			val |= WPA_KEY_MGMT_WPA_NONE;
-#ifdef CONFIG_IEEE80211R
-		else if (os_strcmp(start, "FT-PSK") == 0)
-			val |= WPA_KEY_MGMT_FT_PSK;
-		else if (os_strcmp(start, "FT-EAP") == 0)
-			val |= WPA_KEY_MGMT_FT_IEEE8021X;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
-			val |= WPA_KEY_MGMT_PSK_SHA256;
-		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
-			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-		else if (os_strcmp(start, "WPS") == 0)
-			val |= WPA_KEY_MGMT_WPS;
-#endif /* CONFIG_WPS */
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
-				   line, start);
-			errors++;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	if (val == 0) {
-		wpa_printf(MSG_ERROR,
-			   "Line %d: no key_mgmt values configured.", line);
-		errors++;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
-	ssid->key_mgmt = val;
-	return errors ? -1 : 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_key_mgmt(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	char *buf, *pos, *end;
-	int ret;
-
-	pos = buf = os_zalloc(50);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 50;
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
-		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
-		ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNONE",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
-		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
-				   pos == buf ? "" : " ");
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
-				   pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
-				   pos == buf ? "" : " ");
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
-				   pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_WPS
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-		pos += os_snprintf(pos, end - pos, "%sWPS",
-				   pos == buf ? "" : " ");
-#endif /* CONFIG_WPS */
-
-	return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_cipher(int line, const char *value)
-{
-	int val = 0, last;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "CCMP") == 0)
-			val |= WPA_CIPHER_CCMP;
-		else if (os_strcmp(start, "TKIP") == 0)
-			val |= WPA_CIPHER_TKIP;
-		else if (os_strcmp(start, "WEP104") == 0)
-			val |= WPA_CIPHER_WEP104;
-		else if (os_strcmp(start, "WEP40") == 0)
-			val |= WPA_CIPHER_WEP40;
-		else if (os_strcmp(start, "NONE") == 0)
-			val |= WPA_CIPHER_NONE;
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
-				   line, start);
-			os_free(buf);
-			return -1;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	if (val == 0) {
-		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
-			   line);
-		return -1;
-	}
-	return val;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_cipher(int cipher)
-{
-	char *buf, *pos, *end;
-	int ret;
-
-	pos = buf = os_zalloc(50);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 50;
-
-	if (cipher & WPA_CIPHER_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (cipher & WPA_CIPHER_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (cipher & WPA_CIPHER_WEP104) {
-		ret = os_snprintf(pos, end - pos, "%sWEP104",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (cipher & WPA_CIPHER_WEP40) {
-		ret = os_snprintf(pos, end - pos, "%sWEP40",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (cipher & WPA_CIPHER_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNONE",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_pairwise(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	int val;
-	val = wpa_config_parse_cipher(line, value);
-	if (val == -1)
-		return -1;
-	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
-		wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
-			   "(0x%x).", line, val);
-		return -1;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
-	ssid->pairwise_cipher = val;
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_pairwise(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	return wpa_config_write_cipher(ssid->pairwise_cipher);
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_group(const struct parse_data *data,
-				  struct wpa_ssid *ssid, int line,
-				  const char *value)
-{
-	int val;
-	val = wpa_config_parse_cipher(line, value);
-	if (val == -1)
-		return -1;
-	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
-		    WPA_CIPHER_WEP40)) {
-		wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
-			   "(0x%x).", line, val);
-		return -1;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
-	ssid->group_cipher = val;
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_group(const struct parse_data *data,
-				     struct wpa_ssid *ssid)
-{
-	return wpa_config_write_cipher(ssid->group_cipher);
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_auth_alg(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	int val = 0, last, errors = 0;
-	char *start, *end, *buf;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		if (os_strcmp(start, "OPEN") == 0)
-			val |= WPA_AUTH_ALG_OPEN;
-		else if (os_strcmp(start, "SHARED") == 0)
-			val |= WPA_AUTH_ALG_SHARED;
-		else if (os_strcmp(start, "LEAP") == 0)
-			val |= WPA_AUTH_ALG_LEAP;
-		else {
-			wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
-				   line, start);
-			errors++;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	if (val == 0) {
-		wpa_printf(MSG_ERROR,
-			   "Line %d: no auth_alg values configured.", line);
-		errors++;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
-	ssid->auth_alg = val;
-	return errors ? -1 : 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_auth_alg(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	char *buf, *pos, *end;
-	int ret;
-
-	pos = buf = os_zalloc(30);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 30;
-
-	if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
-		ret = os_snprintf(pos, end - pos, "%sOPEN",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
-		ret = os_snprintf(pos, end - pos, "%sSHARED",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
-		ret = os_snprintf(pos, end - pos, "%sLEAP",
-				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int * wpa_config_parse_freqs(const struct parse_data *data,
-				    struct wpa_ssid *ssid, int line,
-				    const char *value)
-{
-	int *freqs;
-	size_t used, len;
-	const char *pos;
-
-	used = 0;
-	len = 10;
-	freqs = os_zalloc((len + 1) * sizeof(int));
-	if (freqs == NULL)
-		return NULL;
-
-	pos = value;
-	while (pos) {
-		while (*pos == ' ')
-			pos++;
-		if (used == len) {
-			int *n;
-			size_t i;
-			n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
-			if (n == NULL) {
-				os_free(freqs);
-				return NULL;
-			}
-			for (i = len; i <= len * 2; i++)
-				n[i] = 0;
-			freqs = n;
-			len *= 2;
-		}
-
-		freqs[used] = atoi(pos);
-		if (freqs[used] == 0)
-			break;
-		used++;
-		pos = os_strchr(pos + 1, ' ');
-	}
-
-	return freqs;
-}
-
-
-static int wpa_config_parse_scan_freq(const struct parse_data *data,
-				      struct wpa_ssid *ssid, int line,
-				      const char *value)
-{
-	int *freqs;
-
-	freqs = wpa_config_parse_freqs(data, ssid, line, value);
-	if (freqs == NULL)
-		return -1;
-	os_free(ssid->scan_freq);
-	ssid->scan_freq = freqs;
-
-	return 0;
-}
-
-
-static int wpa_config_parse_freq_list(const struct parse_data *data,
-				      struct wpa_ssid *ssid, int line,
-				      const char *value)
-{
-	int *freqs;
-
-	freqs = wpa_config_parse_freqs(data, ssid, line, value);
-	if (freqs == NULL)
-		return -1;
-	os_free(ssid->freq_list);
-	ssid->freq_list = freqs;
-
-	return 0;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_freqs(const struct parse_data *data,
-				     const int *freqs)
-{
-	char *buf, *pos, *end;
-	int i, ret;
-	size_t count;
-
-	if (freqs == NULL)
-		return NULL;
-
-	count = 0;
-	for (i = 0; freqs[i]; i++)
-		count++;
-
-	pos = buf = os_zalloc(10 * count + 1);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 10 * count + 1;
-
-	for (i = 0; freqs[i]; i++) {
-		ret = os_snprintf(pos, end - pos, "%s%u",
-				  i == 0 ? "" : " ", freqs[i]);
-		if (ret < 0 || ret >= end - pos) {
-			end[-1] = '\0';
-			return buf;
-		}
-		pos += ret;
-	}
-
-	return buf;
-}
-
-
-static char * wpa_config_write_scan_freq(const struct parse_data *data,
-					 struct wpa_ssid *ssid)
-{
-	return wpa_config_write_freqs(data, ssid->scan_freq);
-}
-
-
-static char * wpa_config_write_freq_list(const struct parse_data *data,
-					 struct wpa_ssid *ssid)
-{
-	return wpa_config_write_freqs(data, ssid->freq_list);
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-#ifdef IEEE8021X_EAPOL
-static int wpa_config_parse_eap(const struct parse_data *data,
-				struct wpa_ssid *ssid, int line,
-				const char *value)
-{
-	int last, errors = 0;
-	char *start, *end, *buf;
-	struct eap_method_type *methods = NULL, *tmp;
-	size_t num_methods = 0;
-
-	buf = os_strdup(value);
-	if (buf == NULL)
-		return -1;
-	start = buf;
-
-	while (*start != '\0') {
-		while (*start == ' ' || *start == '\t')
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (*end != ' ' && *end != '\t' && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-		tmp = methods;
-		methods = os_realloc(methods,
-				     (num_methods + 1) * sizeof(*methods));
-		if (methods == NULL) {
-			os_free(tmp);
-			os_free(buf);
-			return -1;
-		}
-		methods[num_methods].method = eap_peer_get_type(
-			start, &methods[num_methods].vendor);
-		if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
-		    methods[num_methods].method == EAP_TYPE_NONE) {
-			wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
-				   "'%s'", line, start);
-			wpa_printf(MSG_ERROR, "You may need to add support for"
-				   " this EAP method during wpa_supplicant\n"
-				   "build time configuration.\n"
-				   "See README for more information.");
-			errors++;
-		} else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
-			   methods[num_methods].method == EAP_TYPE_LEAP)
-			ssid->leap++;
-		else
-			ssid->non_leap++;
-		num_methods++;
-		if (last)
-			break;
-		start = end + 1;
-	}
-	os_free(buf);
-
-	tmp = methods;
-	methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
-	if (methods == NULL) {
-		os_free(tmp);
-		return -1;
-	}
-	methods[num_methods].vendor = EAP_VENDOR_IETF;
-	methods[num_methods].method = EAP_TYPE_NONE;
-	num_methods++;
-
-	wpa_hexdump(MSG_MSGDUMP, "eap methods",
-		    (u8 *) methods, num_methods * sizeof(*methods));
-	ssid->eap.eap_methods = methods;
-	return errors ? -1 : 0;
-}
-
-
-static char * wpa_config_write_eap(const struct parse_data *data,
-				   struct wpa_ssid *ssid)
-{
-	int i, ret;
-	char *buf, *pos, *end;
-	const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
-	const char *name;
-
-	if (eap_methods == NULL)
-		return NULL;
-
-	pos = buf = os_zalloc(100);
-	if (buf == NULL)
-		return NULL;
-	end = buf + 100;
-
-	for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
-		     eap_methods[i].method != EAP_TYPE_NONE; i++) {
-		name = eap_get_name(eap_methods[i].vendor,
-				    eap_methods[i].method);
-		if (name) {
-			ret = os_snprintf(pos, end - pos, "%s%s",
-					  pos == buf ? "" : " ", name);
-			if (ret < 0 || ret >= end - pos)
-				break;
-			pos += ret;
-		}
-	}
-
-	end[-1] = '\0';
-
-	return buf;
-}
-
-
-static int wpa_config_parse_password(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	u8 *hash;
-
-	if (os_strcmp(value, "NULL") == 0) {
-		wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
-		os_free(ssid->eap.password);
-		ssid->eap.password = NULL;
-		ssid->eap.password_len = 0;
-		return 0;
-	}
-
-	if (os_strncmp(value, "hash:", 5) != 0) {
-		char *tmp;
-		size_t res_len;
-
-		tmp = wpa_config_parse_string(value, &res_len);
-		if (tmp == NULL) {
-			wpa_printf(MSG_ERROR, "Line %d: failed to parse "
-				   "password.", line);
-			return -1;
-		}
-		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
-				      (u8 *) tmp, res_len);
-
-		os_free(ssid->eap.password);
-		ssid->eap.password = (u8 *) tmp;
-		ssid->eap.password_len = res_len;
-		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
-
-		return 0;
-	}
-
-
-	/* NtPasswordHash: hash:<32 hex digits> */
-	if (os_strlen(value + 5) != 2 * 16) {
-		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
-			   "(expected 32 hex digits)", line);
-		return -1;
-	}
-
-	hash = os_malloc(16);
-	if (hash == NULL)
-		return -1;
-
-	if (hexstr2bin(value + 5, hash, 16)) {
-		os_free(hash);
-		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
-
-	os_free(ssid->eap.password);
-	ssid->eap.password = hash;
-	ssid->eap.password_len = 16;
-	ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
-
-	return 0;
-}
-
-
-static char * wpa_config_write_password(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	char *buf;
-
-	if (ssid->eap.password == NULL)
-		return NULL;
-
-	if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
-		return wpa_config_write_string(
-			ssid->eap.password, ssid->eap.password_len);
-	}
-
-	buf = os_malloc(5 + 32 + 1);
-	if (buf == NULL)
-		return NULL;
-
-	os_memcpy(buf, "hash:", 5);
-	wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
-
-	return buf;
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
-				    const char *value, int idx)
-{
-	char *buf, title[20];
-	int res;
-
-	buf = wpa_config_parse_string(value, len);
-	if (buf == NULL) {
-		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
-			   line, idx, value);
-		return -1;
-	}
-	if (*len > MAX_WEP_KEY_LEN) {
-		wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
-			   line, idx, value);
-		os_free(buf);
-		return -1;
-	}
-	os_memcpy(key, buf, *len);
-	os_free(buf);
-	res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
-	if (res >= 0 && (size_t) res < sizeof(title))
-		wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
-	return 0;
-}
-
-
-static int wpa_config_parse_wep_key0(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	return wpa_config_parse_wep_key(ssid->wep_key[0],
-					&ssid->wep_key_len[0], line,
-					value, 0);
-}
-
-
-static int wpa_config_parse_wep_key1(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	return wpa_config_parse_wep_key(ssid->wep_key[1],
-					&ssid->wep_key_len[1], line,
-					value, 1);
-}
-
-
-static int wpa_config_parse_wep_key2(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	return wpa_config_parse_wep_key(ssid->wep_key[2],
-					&ssid->wep_key_len[2], line,
-					value, 2);
-}
-
-
-static int wpa_config_parse_wep_key3(const struct parse_data *data,
-				     struct wpa_ssid *ssid, int line,
-				     const char *value)
-{
-	return wpa_config_parse_wep_key(ssid->wep_key[3],
-					&ssid->wep_key_len[3], line,
-					value, 3);
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
-{
-	if (ssid->wep_key_len[idx] == 0)
-		return NULL;
-	return wpa_config_write_string(ssid->wep_key[idx],
-				       ssid->wep_key_len[idx]);
-}
-
-
-static char * wpa_config_write_wep_key0(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	return wpa_config_write_wep_key(ssid, 0);
-}
-
-
-static char * wpa_config_write_wep_key1(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	return wpa_config_write_wep_key(ssid, 1);
-}
-
-
-static char * wpa_config_write_wep_key2(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	return wpa_config_write_wep_key(ssid, 2);
-}
-
-
-static char * wpa_config_write_wep_key3(const struct parse_data *data,
-					struct wpa_ssid *ssid)
-{
-	return wpa_config_write_wep_key(ssid, 3);
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-/* Helper macros for network block parser */
-
-#ifdef OFFSET
-#undef OFFSET
-#endif /* OFFSET */
-/* OFFSET: Get offset of a variable within the wpa_ssid structure */
-#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
-
-/* STR: Define a string variable for an ASCII string; f = field name */
-#ifdef NO_CONFIG_WRITE
-#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
-#else /* NO_CONFIG_WRITE */
-#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
-#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
-#endif /* NO_CONFIG_WRITE */
-#define STR(f) _STR(f), NULL, NULL, NULL, 0
-#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
-#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
-#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
-
-/* STR_LEN: Define a string variable with a separate variable for storing the
- * data length. Unlike STR(), this can be used to store arbitrary binary data
- * (i.e., even nul termination character). */
-#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
-#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
-#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
-#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
-#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
-
-/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
- * explicitly specified. */
-#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
-#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
-#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
-
-#ifdef NO_CONFIG_WRITE
-#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
-#else /* NO_CONFIG_WRITE */
-#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
-	OFFSET(f), (void *) 0
-#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
-	OFFSET(eap.f), (void *) 0
-#endif /* NO_CONFIG_WRITE */
-
-/* INT: Define an integer variable */
-#define INT(f) _INT(f), NULL, NULL, 0
-#define INTe(f) _INTe(f), NULL, NULL, 0
-
-/* INT_RANGE: Define an integer variable with allowed value range */
-#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
-
-/* FUNC: Define a configuration variable that uses a custom function for
- * parsing and writing the value. */
-#ifdef NO_CONFIG_WRITE
-#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
-#else /* NO_CONFIG_WRITE */
-#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
-	NULL, NULL, NULL, NULL
-#endif /* NO_CONFIG_WRITE */
-#define FUNC(f) _FUNC(f), 0
-#define FUNC_KEY(f) _FUNC(f), 1
-
-/*
- * Table of network configuration variables. This table is used to parse each
- * network configuration variable, e.g., each line in wpa_supplicant.conf file
- * that is inside a network block.
- *
- * This table is generated using the helper macros defined above and with
- * generous help from the C pre-processor. The field name is stored as a string
- * into .name and for STR and INT types, the offset of the target buffer within
- * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
- * offset to the field containing the length of the configuration variable.
- * .param3 and .param4 can be used to mark the allowed range (length for STR
- * and value for INT).
- *
- * For each configuration line in wpa_supplicant.conf, the parser goes through
- * this table and select the entry that matches with the field name. The parser
- * function (.parser) is then called to parse the actual value of the field.
- *
- * This kind of mechanism makes it easy to add new configuration parameters,
- * since only one line needs to be added into this table and into the
- * struct wpa_ssid definition if the new variable is either a string or
- * integer. More complex types will need to use their own parser and writer
- * functions.
- */
-static const struct parse_data ssid_fields[] = {
-	{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
-	{ INT_RANGE(scan_ssid, 0, 1) },
-	{ FUNC(bssid) },
-	{ FUNC_KEY(psk) },
-	{ FUNC(proto) },
-	{ FUNC(key_mgmt) },
-	{ FUNC(pairwise) },
-	{ FUNC(group) },
-	{ FUNC(auth_alg) },
-	{ FUNC(scan_freq) },
-	{ FUNC(freq_list) },
-#ifdef IEEE8021X_EAPOL
-	{ FUNC(eap) },
-	{ STR_LENe(identity) },
-	{ STR_LENe(anonymous_identity) },
-	{ FUNC_KEY(password) },
-	{ STRe(ca_cert) },
-	{ STRe(ca_path) },
-	{ STRe(client_cert) },
-	{ STRe(private_key) },
-	{ STR_KEYe(private_key_passwd) },
-	{ STRe(dh_file) },
-	{ STRe(subject_match) },
-	{ STRe(altsubject_match) },
-	{ STRe(ca_cert2) },
-	{ STRe(ca_path2) },
-	{ STRe(client_cert2) },
-	{ STRe(private_key2) },
-	{ STR_KEYe(private_key2_passwd) },
-	{ STRe(dh_file2) },
-	{ STRe(subject_match2) },
-	{ STRe(altsubject_match2) },
-	{ STRe(phase1) },
-	{ STRe(phase2) },
-	{ STRe(pcsc) },
-	{ STR_KEYe(pin) },
-	{ STRe(engine_id) },
-	{ STRe(key_id) },
-	{ STRe(cert_id) },
-	{ STRe(ca_cert_id) },
-	{ STR_KEYe(pin2) },
-	{ STRe(engine2_id) },
-	{ STRe(key2_id) },
-	{ STRe(cert2_id) },
-	{ STRe(ca_cert2_id) },
-	{ INTe(engine) },
-	{ INTe(engine2) },
-	{ INT(eapol_flags) },
-#endif /* IEEE8021X_EAPOL */
-	{ FUNC_KEY(wep_key0) },
-	{ FUNC_KEY(wep_key1) },
-	{ FUNC_KEY(wep_key2) },
-	{ FUNC_KEY(wep_key3) },
-	{ INT(wep_tx_keyidx) },
-	{ INT(priority) },
-#ifdef IEEE8021X_EAPOL
-	{ INT(eap_workaround) },
-	{ STRe(pac_file) },
-	{ INTe(fragment_size) },
-#endif /* IEEE8021X_EAPOL */
-	{ INT_RANGE(mode, 0, 2) },
-	{ INT_RANGE(proactive_key_caching, 0, 1) },
-	{ INT_RANGE(disabled, 0, 1) },
-	{ STR(id_str) },
-#ifdef CONFIG_IEEE80211W
-	{ INT_RANGE(ieee80211w, 0, 2) },
-#endif /* CONFIG_IEEE80211W */
-	{ INT_RANGE(peerkey, 0, 1) },
-	{ INT_RANGE(mixed_cell, 0, 1) },
-	{ INT_RANGE(frequency, 0, 10000) },
-	{ INT(wpa_ptk_rekey) },
-	{ STR(bgscan) },
-};
-
-#undef OFFSET
-#undef _STR
-#undef STR
-#undef STR_KEY
-#undef _STR_LEN
-#undef STR_LEN
-#undef STR_LEN_KEY
-#undef _STR_RANGE
-#undef STR_RANGE
-#undef STR_RANGE_KEY
-#undef _INT
-#undef INT
-#undef INT_RANGE
-#undef _FUNC
-#undef FUNC
-#undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
-
-
-/**
- * wpa_config_add_prio_network - Add a network to priority lists
- * @config: Configuration data from wpa_config_read()
- * @ssid: Pointer to the network configuration to be added to the list
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to add a network block to the priority list of
- * networks. This must be called for each network when reading in the full
- * configuration. In addition, this can be used indirectly when updating
- * priorities by calling wpa_config_update_prio_list().
- */
-int wpa_config_add_prio_network(struct wpa_config *config,
-				struct wpa_ssid *ssid)
-{
-	int prio;
-	struct wpa_ssid *prev, **nlist;
-
-	/*
-	 * Add to an existing priority list if one is available for the
-	 * configured priority level for this network.
-	 */
-	for (prio = 0; prio < config->num_prio; prio++) {
-		prev = config->pssid[prio];
-		if (prev->priority == ssid->priority) {
-			while (prev->pnext)
-				prev = prev->pnext;
-			prev->pnext = ssid;
-			return 0;
-		}
-	}
-
-	/* First network for this priority - add a new priority list */
-	nlist = os_realloc(config->pssid,
-			   (config->num_prio + 1) * sizeof(struct wpa_ssid *));
-	if (nlist == NULL)
-		return -1;
-
-	for (prio = 0; prio < config->num_prio; prio++) {
-		if (nlist[prio]->priority < ssid->priority)
-			break;
-	}
-
-	os_memmove(&nlist[prio + 1], &nlist[prio],
-		   (config->num_prio - prio) * sizeof(struct wpa_ssid *));
-
-	nlist[prio] = ssid;
-	config->num_prio++;
-	config->pssid = nlist;
-
-	return 0;
-}
-
-
-/**
- * wpa_config_update_prio_list - Update network priority list
- * @config: Configuration data from wpa_config_read()
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to update the priority list of networks in the
- * configuration when a network is being added or removed. This is also called
- * if a priority for a network is changed.
- */
-int wpa_config_update_prio_list(struct wpa_config *config)
-{
-	struct wpa_ssid *ssid;
-	int ret = 0;
-
-	os_free(config->pssid);
-	config->pssid = NULL;
-	config->num_prio = 0;
-
-	ssid = config->ssid;
-	while (ssid) {
-		ssid->pnext = NULL;
-		if (wpa_config_add_prio_network(config, ssid) < 0)
-			ret = -1;
-		ssid = ssid->next;
-	}
-
-	return ret;
-}
-
-
-#ifdef IEEE8021X_EAPOL
-static void eap_peer_config_free(struct eap_peer_config *eap)
-{
-	os_free(eap->eap_methods);
-	os_free(eap->identity);
-	os_free(eap->anonymous_identity);
-	os_free(eap->password);
-	os_free(eap->ca_cert);
-	os_free(eap->ca_path);
-	os_free(eap->client_cert);
-	os_free(eap->private_key);
-	os_free(eap->private_key_passwd);
-	os_free(eap->dh_file);
-	os_free(eap->subject_match);
-	os_free(eap->altsubject_match);
-	os_free(eap->ca_cert2);
-	os_free(eap->ca_path2);
-	os_free(eap->client_cert2);
-	os_free(eap->private_key2);
-	os_free(eap->private_key2_passwd);
-	os_free(eap->dh_file2);
-	os_free(eap->subject_match2);
-	os_free(eap->altsubject_match2);
-	os_free(eap->phase1);
-	os_free(eap->phase2);
-	os_free(eap->pcsc);
-	os_free(eap->pin);
-	os_free(eap->engine_id);
-	os_free(eap->key_id);
-	os_free(eap->cert_id);
-	os_free(eap->ca_cert_id);
-	os_free(eap->key2_id);
-	os_free(eap->cert2_id);
-	os_free(eap->ca_cert2_id);
-	os_free(eap->pin2);
-	os_free(eap->engine2_id);
-	os_free(eap->otp);
-	os_free(eap->pending_req_otp);
-	os_free(eap->pac_file);
-	os_free(eap->new_password);
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-/**
- * wpa_config_free_ssid - Free network/ssid configuration data
- * @ssid: Configuration data for the network
- *
- * This function frees all resources allocated for the network configuration
- * data.
- */
-void wpa_config_free_ssid(struct wpa_ssid *ssid)
-{
-	os_free(ssid->ssid);
-	os_free(ssid->passphrase);
-#ifdef IEEE8021X_EAPOL
-	eap_peer_config_free(&ssid->eap);
-#endif /* IEEE8021X_EAPOL */
-	os_free(ssid->id_str);
-	os_free(ssid->scan_freq);
-	os_free(ssid->freq_list);
-	os_free(ssid->bgscan);
-	os_free(ssid);
-}
-
-
-/**
- * wpa_config_free - Free configuration data
- * @config: Configuration data from wpa_config_read()
- *
- * This function frees all resources allocated for the configuration data by
- * wpa_config_read().
- */
-void wpa_config_free(struct wpa_config *config)
-{
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct wpa_config_blob *blob, *prevblob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-	struct wpa_ssid *ssid, *prev = NULL;
-	ssid = config->ssid;
-	while (ssid) {
-		prev = ssid;
-		ssid = ssid->next;
-		wpa_config_free_ssid(prev);
-	}
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	blob = config->blobs;
-	prevblob = NULL;
-	while (blob) {
-		prevblob = blob;
-		blob = blob->next;
-		wpa_config_free_blob(prevblob);
-	}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-	os_free(config->ctrl_interface);
-	os_free(config->ctrl_interface_group);
-	os_free(config->opensc_engine_path);
-	os_free(config->pkcs11_engine_path);
-	os_free(config->pkcs11_module_path);
-	os_free(config->driver_param);
-	os_free(config->device_name);
-	os_free(config->manufacturer);
-	os_free(config->model_name);
-	os_free(config->model_number);
-	os_free(config->serial_number);
-	os_free(config->device_type);
-	os_free(config->config_methods);
-	os_free(config->pssid);
-	os_free(config);
-}
-
-
-/**
- * wpa_config_get_network - Get configured network based on id
- * @config: Configuration data from wpa_config_read()
- * @id: Unique network id to search for
- * Returns: Network configuration or %NULL if not found
- */
-struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
-{
-	struct wpa_ssid *ssid;
-
-	ssid = config->ssid;
-	while (ssid) {
-		if (id == ssid->id)
-			break;
-		ssid = ssid->next;
-	}
-
-	return ssid;
-}
-
-
-/**
- * wpa_config_add_network - Add a new network with empty configuration
- * @config: Configuration data from wpa_config_read()
- * Returns: The new network configuration or %NULL if operation failed
- */
-struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
-{
-	int id;
-	struct wpa_ssid *ssid, *last = NULL;
-
-	id = -1;
-	ssid = config->ssid;
-	while (ssid) {
-		if (ssid->id > id)
-			id = ssid->id;
-		last = ssid;
-		ssid = ssid->next;
-	}
-	id++;
-
-	ssid = os_zalloc(sizeof(*ssid));
-	if (ssid == NULL)
-		return NULL;
-	ssid->id = id;
-	if (last)
-		last->next = ssid;
-	else
-		config->ssid = ssid;
-
-	wpa_config_update_prio_list(config);
-
-	return ssid;
-}
-
-
-/**
- * wpa_config_remove_network - Remove a configured network based on id
- * @config: Configuration data from wpa_config_read()
- * @id: Unique network id to search for
- * Returns: 0 on success, or -1 if the network was not found
- */
-int wpa_config_remove_network(struct wpa_config *config, int id)
-{
-	struct wpa_ssid *ssid, *prev = NULL;
-
-	ssid = config->ssid;
-	while (ssid) {
-		if (id == ssid->id)
-			break;
-		prev = ssid;
-		ssid = ssid->next;
-	}
-
-	if (ssid == NULL)
-		return -1;
-
-	if (prev)
-		prev->next = ssid->next;
-	else
-		config->ssid = ssid->next;
-
-	wpa_config_update_prio_list(config);
-	wpa_config_free_ssid(ssid);
-	return 0;
-}
-
-
-/**
- * wpa_config_set_network_defaults - Set network default values
- * @ssid: Pointer to network configuration data
- */
-void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
-{
-	ssid->proto = DEFAULT_PROTO;
-	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
-	ssid->group_cipher = DEFAULT_GROUP;
-	ssid->key_mgmt = DEFAULT_KEY_MGMT;
-#ifdef IEEE8021X_EAPOL
-	ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
-	ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
-	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
-#endif /* IEEE8021X_EAPOL */
-}
-
-
-/**
- * wpa_config_set - Set a variable in network configuration
- * @ssid: Pointer to network configuration data
- * @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
- *
- * This function can be used to set network configuration variables based on
- * both the configuration file and management interface input. The value
- * parameter must be in the same format as the text-based configuration file is
- * using. For example, strings are using double quotation marks.
- */
-int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
-		   int line)
-{
-	size_t i;
-	int ret = 0;
-
-	if (ssid == NULL || var == NULL || value == NULL)
-		return -1;
-
-	for (i = 0; i < NUM_SSID_FIELDS; i++) {
-		const struct parse_data *field = &ssid_fields[i];
-		if (os_strcmp(var, field->name) != 0)
-			continue;
-
-		if (field->parser(field, ssid, line, value)) {
-			if (line) {
-				wpa_printf(MSG_ERROR, "Line %d: failed to "
-					   "parse %s '%s'.", line, var, value);
-			}
-			ret = -1;
-		}
-		break;
-	}
-	if (i == NUM_SSID_FIELDS) {
-		if (line) {
-			wpa_printf(MSG_ERROR, "Line %d: unknown network field "
-				   "'%s'.", line, var);
-		}
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-/**
- * wpa_config_get_all - Get all options from network configuration
- * @ssid: Pointer to network configuration data
- * @get_keys: Determines if keys/passwords will be included in returned list
- * Returns: %NULL terminated list of all set keys and their values in the form
- * of [key1, val1, key2, val2, ... , NULL]
- *
- * This function can be used to get list of all configured network properties.
- * The caller is responsible for freeing the returned list and all its
- * elements.
- */
-char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
-{
-	const struct parse_data *field;
-	char *key, *value;
-	size_t i;
-	char **props;
-	int fields_num;
-
-	props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
-	if (!props)
-		return NULL;
-
-	fields_num = 0;
-	for (i = 0; i < NUM_SSID_FIELDS; i++) {
-		field = &ssid_fields[i];
-		if (field->key_data && !get_keys)
-			continue;
-		value = field->writer(field, ssid);
-		if (value == NULL)
-			continue;
-		if (os_strlen(value) == 0) {
-			os_free(value);
-			continue;
-		}
-
-		key = os_strdup(field->name);
-		if (key == NULL) {
-			os_free(value);
-			goto err;
-		}
-
-		props[fields_num * 2] = key;
-		props[fields_num * 2 + 1] = value;
-
-		fields_num++;
-	}
-
-	return props;
-
-err:
-	value = *props;
-	while (value)
-		os_free(value++);
-	os_free(props);
-	return NULL;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-/**
- * wpa_config_get - Get a variable in network configuration
- * @ssid: Pointer to network configuration data
- * @var: Variable name, e.g., "ssid"
- * Returns: Value of the variable or %NULL on failure
- *
- * This function can be used to get network configuration variables. The
- * returned value is a copy of the configuration variable in text format, i.e,.
- * the same format that the text-based configuration file and wpa_config_set()
- * are using for the value. The caller is responsible for freeing the returned
- * value.
- */
-char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
-{
-	size_t i;
-
-	if (ssid == NULL || var == NULL)
-		return NULL;
-
-	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);
-	}
-
-	return NULL;
-}
-
-
-/**
- * wpa_config_get_no_key - Get a variable in network configuration (no keys)
- * @ssid: Pointer to network configuration data
- * @var: Variable name, e.g., "ssid"
- * Returns: Value of the variable or %NULL on failure
- *
- * This function can be used to get network configuration variable like
- * wpa_config_get(). The only difference is that this functions does not expose
- * key/password material from the configuration. In case a key/password field
- * is requested, the returned value is an empty string or %NULL if the variable
- * is not set or "*" if the variable is set (regardless of its value). The
- * returned value is a copy of the configuration variable in text format, i.e,.
- * the same format that the text-based configuration file and wpa_config_set()
- * are using for the value. The caller is responsible for freeing the returned
- * value.
- */
-char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
-{
-	size_t i;
-
-	if (ssid == NULL || var == NULL)
-		return NULL;
-
-	for (i = 0; i < NUM_SSID_FIELDS; i++) {
-		const struct parse_data *field = &ssid_fields[i];
-		if (os_strcmp(var, field->name) == 0) {
-			char *res = field->writer(field, ssid);
-			if (field->key_data) {
-				if (res && res[0]) {
-					wpa_printf(MSG_DEBUG, "Do not allow "
-						   "key_data field to be "
-						   "exposed");
-					os_free(res);
-					return os_strdup("*");
-				}
-
-				os_free(res);
-				return NULL;
-			}
-			return res;
-		}
-	}
-
-	return NULL;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-/**
- * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
- * @ssid: Pointer to network configuration data
- *
- * This function must be called to update WPA PSK when either SSID or the
- * passphrase has changed for the network configuration.
- */
-void wpa_config_update_psk(struct wpa_ssid *ssid)
-{
-#ifndef CONFIG_NO_PBKDF2
-	pbkdf2_sha1(ssid->passphrase,
-		    (char *) ssid->ssid, ssid->ssid_len, 4096,
-		    ssid->psk, PMK_LEN);
-	wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
-			ssid->psk, PMK_LEN);
-	ssid->psk_set = 1;
-#endif /* CONFIG_NO_PBKDF2 */
-}
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-/**
- * wpa_config_get_blob - Get a named configuration blob
- * @config: Configuration data from wpa_config_read()
- * @name: Name of the blob
- * Returns: Pointer to blob data or %NULL if not found
- */
-const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
-						   const char *name)
-{
-	struct wpa_config_blob *blob = config->blobs;
-
-	while (blob) {
-		if (os_strcmp(blob->name, name) == 0)
-			return blob;
-		blob = blob->next;
-	}
-	return NULL;
-}
-
-
-/**
- * wpa_config_set_blob - Set or add a named configuration blob
- * @config: Configuration data from wpa_config_read()
- * @blob: New value for the blob
- *
- * Adds a new configuration blob or replaces the current value of an existing
- * blob.
- */
-void wpa_config_set_blob(struct wpa_config *config,
-			 struct wpa_config_blob *blob)
-{
-	wpa_config_remove_blob(config, blob->name);
-	blob->next = config->blobs;
-	config->blobs = blob;
-}
-
-
-/**
- * wpa_config_free_blob - Free blob data
- * @blob: Pointer to blob to be freed
- */
-void wpa_config_free_blob(struct wpa_config_blob *blob)
-{
-	if (blob) {
-		os_free(blob->name);
-		os_free(blob->data);
-		os_free(blob);
-	}
-}
-
-
-/**
- * wpa_config_remove_blob - Remove a named configuration blob
- * @config: Configuration data from wpa_config_read()
- * @name: Name of the blob to remove
- * Returns: 0 if blob was removed or -1 if blob was not found
- */
-int wpa_config_remove_blob(struct wpa_config *config, const char *name)
-{
-	struct wpa_config_blob *pos = config->blobs, *prev = NULL;
-
-	while (pos) {
-		if (os_strcmp(pos->name, name) == 0) {
-			if (prev)
-				prev->next = pos->next;
-			else
-				config->blobs = pos->next;
-			wpa_config_free_blob(pos);
-			return 0;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-
-	return -1;
-}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-/**
- * wpa_config_alloc_empty - Allocate an empty configuration
- * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
- * socket
- * @driver_param: Driver parameters
- * Returns: Pointer to allocated configuration data or %NULL on failure
- */
-struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
-					   const char *driver_param)
-{
-	struct wpa_config *config;
-
-	config = os_zalloc(sizeof(*config));
-	if (config == NULL)
-		return NULL;
-	config->eapol_version = DEFAULT_EAPOL_VERSION;
-	config->ap_scan = DEFAULT_AP_SCAN;
-	config->fast_reauth = DEFAULT_FAST_REAUTH;
-	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
-
-	if (ctrl_interface)
-		config->ctrl_interface = os_strdup(ctrl_interface);
-	if (driver_param)
-		config->driver_param = os_strdup(driver_param);
-
-	return config;
-}
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-/**
- * wpa_config_debug_dump_networks - Debug dump of configured networks
- * @config: Configuration data from wpa_config_read()
- */
-void wpa_config_debug_dump_networks(struct wpa_config *config)
-{
-	int prio;
-	struct wpa_ssid *ssid;
-
-	for (prio = 0; prio < config->num_prio; prio++) {
-		ssid = config->pssid[prio];
-		wpa_printf(MSG_DEBUG, "Priority group %d",
-			   ssid->priority);
-		while (ssid) {
-			wpa_printf(MSG_DEBUG, "   id=%d ssid='%s'",
-				   ssid->id,
-				   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-			ssid = ssid->pnext;
-		}
-	}
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */

Copied: vendor/wpa/2.0/wpa_supplicant/config.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/config.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3134 @@
+/*
+ * WPA Supplicant / Configuration parser and common functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "utils/uuid.h"
+#include "crypto/sha1.h"
+#include "rsn_supp/wpa.h"
+#include "eap_peer/eap.h"
+#include "p2p/p2p.h"
+#include "config.h"
+
+
+#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
+#define NO_CONFIG_WRITE
+#endif
+
+/*
+ * Structure for network configuration parsing. This data is used to implement
+ * a generic parser for each network block variable. The table of configuration
+ * variables is defined below in this file (ssid_fields[]).
+ */
+struct parse_data {
+	/* Configuration variable name */
+	char *name;
+
+	/* Parser function for this variable */
+	int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
+		      int line, const char *value);
+
+#ifndef NO_CONFIG_WRITE
+	/* Writer function (i.e., to get the variable in text format from
+	 * internal presentation). */
+	char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
+#endif /* NO_CONFIG_WRITE */
+
+	/* Variable specific parameters for the parser. */
+	void *param1, *param2, *param3, *param4;
+
+	/* 0 = this variable can be included in debug output and ctrl_iface
+	 * 1 = this variable contains key/private data and it must not be
+	 *     included in debug output unless explicitly requested. In
+	 *     addition, this variable will not be readable through the
+	 *     ctrl_iface.
+	 */
+	int key_data;
+};
+
+
+static int wpa_config_parse_str(const struct parse_data *data,
+				struct wpa_ssid *ssid,
+				int line, const char *value)
+{
+	size_t res_len, *dst_len;
+	char **dst, *tmp;
+
+	if (os_strcmp(value, "NULL") == 0) {
+		wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
+			   data->name);
+		tmp = NULL;
+		res_len = 0;
+		goto set;
+	}
+
+	tmp = wpa_config_parse_string(value, &res_len);
+	if (tmp == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
+			   line, data->name,
+			   data->key_data ? "[KEY DATA REMOVED]" : value);
+		return -1;
+	}
+
+	if (data->key_data) {
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+				      (u8 *) tmp, res_len);
+	} else {
+		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+				  (u8 *) tmp, res_len);
+	}
+
+	if (data->param3 && res_len < (size_t) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+			   "min_len=%ld)", line, data->name,
+			   (unsigned long) res_len, (long) data->param3);
+		os_free(tmp);
+		return -1;
+	}
+
+	if (data->param4 && res_len > (size_t) data->param4) {
+		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+			   "max_len=%ld)", line, data->name,
+			   (unsigned long) res_len, (long) data->param4);
+		os_free(tmp);
+		return -1;
+	}
+
+set:
+	dst = (char **) (((u8 *) ssid) + (long) data->param1);
+	dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+	os_free(*dst);
+	*dst = tmp;
+	if (data->param2)
+		*dst_len = res_len;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
+{
+	char *buf;
+
+	buf = os_malloc(len + 3);
+	if (buf == NULL)
+		return NULL;
+	buf[0] = '"';
+	os_memcpy(buf + 1, value, len);
+	buf[len + 1] = '"';
+	buf[len + 2] = '\0';
+
+	return buf;
+}
+
+
+static char * wpa_config_write_string_hex(const u8 *value, size_t len)
+{
+	char *buf;
+
+	buf = os_zalloc(2 * len + 1);
+	if (buf == NULL)
+		return NULL;
+	wpa_snprintf_hex(buf, 2 * len + 1, value, len);
+
+	return buf;
+}
+
+
+static char * wpa_config_write_string(const u8 *value, size_t len)
+{
+	if (value == NULL)
+		return NULL;
+
+	if (is_hex(value, len))
+		return wpa_config_write_string_hex(value, len);
+	else
+		return wpa_config_write_string_ascii(value, len);
+}
+
+
+static char * wpa_config_write_str(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	size_t len;
+	char **src;
+
+	src = (char **) (((u8 *) ssid) + (long) data->param1);
+	if (*src == NULL)
+		return NULL;
+
+	if (data->param2)
+		len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
+	else
+		len = os_strlen(*src);
+
+	return wpa_config_write_string((const u8 *) *src, len);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_int(const struct parse_data *data,
+				struct wpa_ssid *ssid,
+				int line, const char *value)
+{
+	int *dst;
+
+	dst = (int *) (((u8 *) ssid) + (long) data->param1);
+	*dst = atoi(value);
+	wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
+
+	if (data->param3 && *dst < (long) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+			   "min_value=%ld)", line, data->name, *dst,
+			   (long) data->param3);
+		*dst = (long) data->param3;
+		return -1;
+	}
+
+	if (data->param4 && *dst > (long) data->param4) {
+		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+			   "max_value=%ld)", line, data->name, *dst,
+			   (long) data->param4);
+		*dst = (long) data->param4;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_int(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	int *src, res;
+	char *value;
+
+	src = (int *) (((u8 *) ssid) + (long) data->param1);
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, "%d", *src);
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+	    os_strcmp(value, "any") == 0) {
+		ssid->bssid_set = 0;
+		wpa_printf(MSG_MSGDUMP, "BSSID any");
+		return 0;
+	}
+	if (hwaddr_aton(value, ssid->bssid)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
+			   line, value);
+		return -1;
+	}
+	ssid->bssid_set = 1;
+	wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	char *value;
+	int res;
+
+	if (!ssid->bssid_set)
+		return NULL;
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_psk(const struct parse_data *data,
+				struct wpa_ssid *ssid, int line,
+				const char *value)
+{
+#ifdef CONFIG_EXT_PASSWORD
+	if (os_strncmp(value, "ext:", 4) == 0) {
+		os_free(ssid->passphrase);
+		ssid->passphrase = NULL;
+		ssid->psk_set = 0;
+		os_free(ssid->ext_psk);
+		ssid->ext_psk = os_strdup(value + 4);
+		if (ssid->ext_psk == NULL)
+			return -1;
+		wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+			   ssid->ext_psk);
+		return 0;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (*value == '"') {
+#ifndef CONFIG_NO_PBKDF2
+		const char *pos;
+		size_t len;
+
+		value++;
+		pos = os_strrchr(value, '"');
+		if (pos)
+			len = pos - value;
+		else
+			len = os_strlen(value);
+		if (len < 8 || len > 63) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
+				   "length %lu (expected: 8..63) '%s'.",
+				   line, (unsigned long) len, value);
+			return -1;
+		}
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
+				      (u8 *) value, len);
+		if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
+		    os_memcmp(ssid->passphrase, value, len) == 0)
+			return 0;
+		ssid->psk_set = 0;
+		os_free(ssid->passphrase);
+		ssid->passphrase = os_malloc(len + 1);
+		if (ssid->passphrase == NULL)
+			return -1;
+		os_memcpy(ssid->passphrase, value, len);
+		ssid->passphrase[len] = '\0';
+		return 0;
+#else /* CONFIG_NO_PBKDF2 */
+		wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
+			   "supported.", line);
+		return -1;
+#endif /* CONFIG_NO_PBKDF2 */
+	}
+
+	if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
+	    value[PMK_LEN * 2] != '\0') {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+			   line, value);
+		return -1;
+	}
+
+	os_free(ssid->passphrase);
+	ssid->passphrase = NULL;
+
+	ssid->psk_set = 1;
+	wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_EXT_PASSWORD
+	if (ssid->ext_psk) {
+		size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+		char *buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+		return buf;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (ssid->passphrase)
+		return wpa_config_write_string_ascii(
+			(const u8 *) ssid->passphrase,
+			os_strlen(ssid->passphrase));
+
+	if (ssid->psk_set)
+		return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
+
+	return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_proto(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA") == 0)
+			val |= WPA_PROTO_WPA;
+		else if (os_strcmp(start, "RSN") == 0 ||
+			 os_strcmp(start, "WPA2") == 0)
+			val |= WPA_PROTO_RSN;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no proto values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
+	ssid->proto = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_proto(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	int first = 1, ret;
+	char *buf, *pos, *end;
+
+	pos = buf = os_zalloc(10);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 10;
+
+	if (ssid->proto & WPA_PROTO_WPA) {
+		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (ssid->proto & WPA_PROTO_RSN) {
+		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_key_mgmt(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA-PSK") == 0)
+			val |= WPA_KEY_MGMT_PSK;
+		else if (os_strcmp(start, "WPA-EAP") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X;
+		else if (os_strcmp(start, "IEEE8021X") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_KEY_MGMT_NONE;
+		else if (os_strcmp(start, "WPA-NONE") == 0)
+			val |= WPA_KEY_MGMT_WPA_NONE;
+#ifdef CONFIG_IEEE80211R
+		else if (os_strcmp(start, "FT-PSK") == 0)
+			val |= WPA_KEY_MGMT_FT_PSK;
+		else if (os_strcmp(start, "FT-EAP") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+		else if (os_strcmp(start, "WPS") == 0)
+			val |= WPA_KEY_MGMT_WPS;
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+		else if (os_strcmp(start, "SAE") == 0)
+			val |= WPA_KEY_MGMT_SAE;
+		else if (os_strcmp(start, "FT-SAE") == 0)
+			val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no key_mgmt values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
+	ssid->key_mgmt = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_key_mgmt(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(50);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 50;
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
+		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
+				   pos == buf ? "" : " ");
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+				   pos == buf ? "" : " ");
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WPS
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		pos += os_snprintf(pos, end - pos, "%sWPS",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_WPS */
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "CCMP") == 0)
+			val |= WPA_CIPHER_CCMP;
+		else if (os_strcmp(start, "GCMP") == 0)
+			val |= WPA_CIPHER_GCMP;
+		else if (os_strcmp(start, "TKIP") == 0)
+			val |= WPA_CIPHER_TKIP;
+		else if (os_strcmp(start, "WEP104") == 0)
+			val |= WPA_CIPHER_WEP104;
+		else if (os_strcmp(start, "WEP40") == 0)
+			val |= WPA_CIPHER_WEP40;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_CIPHER_NONE;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+			   line);
+		return -1;
+	}
+	return val;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_cipher(int cipher)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(50);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 50;
+
+	if (cipher & WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_pairwise(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val;
+	val = wpa_config_parse_cipher(line, value);
+	if (val == -1)
+		return -1;
+	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+		    WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
+			   "(0x%x).", line, val);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
+	ssid->pairwise_cipher = val;
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_pairwise(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_cipher(ssid->pairwise_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_group(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	int val;
+	val = wpa_config_parse_cipher(line, value);
+	if (val == -1)
+		return -1;
+	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+		    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
+		wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
+			   "(0x%x).", line, val);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
+	ssid->group_cipher = val;
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_group(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	return wpa_config_write_cipher(ssid->group_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_auth_alg(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "OPEN") == 0)
+			val |= WPA_AUTH_ALG_OPEN;
+		else if (os_strcmp(start, "SHARED") == 0)
+			val |= WPA_AUTH_ALG_SHARED;
+		else if (os_strcmp(start, "LEAP") == 0)
+			val |= WPA_AUTH_ALG_LEAP;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no auth_alg values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
+	ssid->auth_alg = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_auth_alg(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(30);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 30;
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
+		ret = os_snprintf(pos, end - pos, "%sOPEN",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
+		ret = os_snprintf(pos, end - pos, "%sSHARED",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
+		ret = os_snprintf(pos, end - pos, "%sLEAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int * wpa_config_parse_freqs(const struct parse_data *data,
+				    struct wpa_ssid *ssid, int line,
+				    const char *value)
+{
+	int *freqs;
+	size_t used, len;
+	const char *pos;
+
+	used = 0;
+	len = 10;
+	freqs = os_calloc(len + 1, sizeof(int));
+	if (freqs == NULL)
+		return NULL;
+
+	pos = value;
+	while (pos) {
+		while (*pos == ' ')
+			pos++;
+		if (used == len) {
+			int *n;
+			size_t i;
+			n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
+			if (n == NULL) {
+				os_free(freqs);
+				return NULL;
+			}
+			for (i = len; i <= len * 2; i++)
+				n[i] = 0;
+			freqs = n;
+			len *= 2;
+		}
+
+		freqs[used] = atoi(pos);
+		if (freqs[used] == 0)
+			break;
+		used++;
+		pos = os_strchr(pos + 1, ' ');
+	}
+
+	return freqs;
+}
+
+
+static int wpa_config_parse_scan_freq(const struct parse_data *data,
+				      struct wpa_ssid *ssid, int line,
+				      const char *value)
+{
+	int *freqs;
+
+	freqs = wpa_config_parse_freqs(data, ssid, line, value);
+	if (freqs == NULL)
+		return -1;
+	os_free(ssid->scan_freq);
+	ssid->scan_freq = freqs;
+
+	return 0;
+}
+
+
+static int wpa_config_parse_freq_list(const struct parse_data *data,
+				      struct wpa_ssid *ssid, int line,
+				      const char *value)
+{
+	int *freqs;
+
+	freqs = wpa_config_parse_freqs(data, ssid, line, value);
+	if (freqs == NULL)
+		return -1;
+	os_free(ssid->freq_list);
+	ssid->freq_list = freqs;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_freqs(const struct parse_data *data,
+				     const int *freqs)
+{
+	char *buf, *pos, *end;
+	int i, ret;
+	size_t count;
+
+	if (freqs == NULL)
+		return NULL;
+
+	count = 0;
+	for (i = 0; freqs[i]; i++)
+		count++;
+
+	pos = buf = os_zalloc(10 * count + 1);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 10 * count + 1;
+
+	for (i = 0; freqs[i]; i++) {
+		ret = os_snprintf(pos, end - pos, "%s%u",
+				  i == 0 ? "" : " ", freqs[i]);
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+
+
+static char * wpa_config_write_scan_freq(const struct parse_data *data,
+					 struct wpa_ssid *ssid)
+{
+	return wpa_config_write_freqs(data, ssid->scan_freq);
+}
+
+
+static char * wpa_config_write_freq_list(const struct parse_data *data,
+					 struct wpa_ssid *ssid)
+{
+	return wpa_config_write_freqs(data, ssid->freq_list);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifdef IEEE8021X_EAPOL
+static int wpa_config_parse_eap(const struct parse_data *data,
+				struct wpa_ssid *ssid, int line,
+				const char *value)
+{
+	int last, errors = 0;
+	char *start, *end, *buf;
+	struct eap_method_type *methods = NULL, *tmp;
+	size_t num_methods = 0;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		tmp = methods;
+		methods = os_realloc_array(methods, num_methods + 1,
+					   sizeof(*methods));
+		if (methods == NULL) {
+			os_free(tmp);
+			os_free(buf);
+			return -1;
+		}
+		methods[num_methods].method = eap_peer_get_type(
+			start, &methods[num_methods].vendor);
+		if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+		    methods[num_methods].method == EAP_TYPE_NONE) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
+				   "'%s'", line, start);
+			wpa_printf(MSG_ERROR, "You may need to add support for"
+				   " this EAP method during wpa_supplicant\n"
+				   "build time configuration.\n"
+				   "See README for more information.");
+			errors++;
+		} else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+			   methods[num_methods].method == EAP_TYPE_LEAP)
+			ssid->leap++;
+		else
+			ssid->non_leap++;
+		num_methods++;
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	tmp = methods;
+	methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
+	if (methods == NULL) {
+		os_free(tmp);
+		return -1;
+	}
+	methods[num_methods].vendor = EAP_VENDOR_IETF;
+	methods[num_methods].method = EAP_TYPE_NONE;
+	num_methods++;
+
+	wpa_hexdump(MSG_MSGDUMP, "eap methods",
+		    (u8 *) methods, num_methods * sizeof(*methods));
+	os_free(ssid->eap.eap_methods);
+	ssid->eap.eap_methods = methods;
+	return errors ? -1 : 0;
+}
+
+
+static char * wpa_config_write_eap(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	int i, ret;
+	char *buf, *pos, *end;
+	const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
+	const char *name;
+
+	if (eap_methods == NULL)
+		return NULL;
+
+	pos = buf = os_zalloc(100);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 100;
+
+	for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
+		     eap_methods[i].method != EAP_TYPE_NONE; i++) {
+		name = eap_get_name(eap_methods[i].vendor,
+				    eap_methods[i].method);
+		if (name) {
+			ret = os_snprintf(pos, end - pos, "%s%s",
+					  pos == buf ? "" : " ", name);
+			if (ret < 0 || ret >= end - pos)
+				break;
+			pos += ret;
+		}
+	}
+
+	end[-1] = '\0';
+
+	return buf;
+}
+
+
+static int wpa_config_parse_password(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	u8 *hash;
+
+	if (os_strcmp(value, "NULL") == 0) {
+		wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
+		os_free(ssid->eap.password);
+		ssid->eap.password = NULL;
+		ssid->eap.password_len = 0;
+		return 0;
+	}
+
+#ifdef CONFIG_EXT_PASSWORD
+	if (os_strncmp(value, "ext:", 4) == 0) {
+		char *name = os_strdup(value + 4);
+		if (name == NULL)
+			return -1;
+		os_free(ssid->eap.password);
+		ssid->eap.password = (u8 *) name;
+		ssid->eap.password_len = os_strlen(name);
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+		ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+		return 0;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (os_strncmp(value, "hash:", 5) != 0) {
+		char *tmp;
+		size_t res_len;
+
+		tmp = wpa_config_parse_string(value, &res_len);
+		if (tmp == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to parse "
+				   "password.", line);
+			return -1;
+		}
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+				      (u8 *) tmp, res_len);
+
+		os_free(ssid->eap.password);
+		ssid->eap.password = (u8 *) tmp;
+		ssid->eap.password_len = res_len;
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
+
+		return 0;
+	}
+
+
+	/* NtPasswordHash: hash:<32 hex digits> */
+	if (os_strlen(value + 5) != 2 * 16) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
+			   "(expected 32 hex digits)", line);
+		return -1;
+	}
+
+	hash = os_malloc(16);
+	if (hash == NULL)
+		return -1;
+
+	if (hexstr2bin(value + 5, hash, 16)) {
+		os_free(hash);
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+	os_free(ssid->eap.password);
+	ssid->eap.password = hash;
+	ssid->eap.password_len = 16;
+	ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+	ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
+
+	return 0;
+}
+
+
+static char * wpa_config_write_password(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf;
+
+	if (ssid->eap.password == NULL)
+		return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+	if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		buf = os_zalloc(4 + ssid->eap.password_len + 1);
+		if (buf == NULL)
+			return NULL;
+		os_memcpy(buf, "ext:", 4);
+		os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+		return buf;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+		return wpa_config_write_string(
+			ssid->eap.password, ssid->eap.password_len);
+	}
+
+	buf = os_malloc(5 + 32 + 1);
+	if (buf == NULL)
+		return NULL;
+
+	os_memcpy(buf, "hash:", 5);
+	wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
+
+	return buf;
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
+				    const char *value, int idx)
+{
+	char *buf, title[20];
+	int res;
+
+	buf = wpa_config_parse_string(value, len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
+			   line, idx, value);
+		return -1;
+	}
+	if (*len > MAX_WEP_KEY_LEN) {
+		wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
+			   line, idx, value);
+		os_free(buf);
+		return -1;
+	}
+	if (*len && *len != 5 && *len != 13 && *len != 16) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+			   "this network block will be ignored",
+			   line, (unsigned int) *len);
+	}
+	os_memcpy(key, buf, *len);
+	os_free(buf);
+	res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
+	if (res >= 0 && (size_t) res < sizeof(title))
+		wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
+	return 0;
+}
+
+
+static int wpa_config_parse_wep_key0(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[0],
+					&ssid->wep_key_len[0], line,
+					value, 0);
+}
+
+
+static int wpa_config_parse_wep_key1(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[1],
+					&ssid->wep_key_len[1], line,
+					value, 1);
+}
+
+
+static int wpa_config_parse_wep_key2(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[2],
+					&ssid->wep_key_len[2], line,
+					value, 2);
+}
+
+
+static int wpa_config_parse_wep_key3(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[3],
+					&ssid->wep_key_len[3], line,
+					value, 3);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
+{
+	if (ssid->wep_key_len[idx] == 0)
+		return NULL;
+	return wpa_config_write_string(ssid->wep_key[idx],
+				       ssid->wep_key_len[idx]);
+}
+
+
+static char * wpa_config_write_wep_key0(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 0);
+}
+
+
+static char * wpa_config_write_wep_key1(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 1);
+}
+
+
+static char * wpa_config_write_wep_key2(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 2);
+}
+
+
+static char * wpa_config_write_wep_key3(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 3);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifdef CONFIG_P2P
+
+static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	const char *pos;
+	u8 *buf, *n, addr[ETH_ALEN];
+	size_t count;
+
+	buf = NULL;
+	count = 0;
+
+	pos = value;
+	while (pos && *pos) {
+		while (*pos == ' ')
+			pos++;
+
+		if (hwaddr_aton(pos, addr)) {
+			if (count == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "p2p_client_list address '%s'.",
+					   line, value);
+				os_free(buf);
+				return -1;
+			}
+			/* continue anyway since this could have been from a
+			 * truncated configuration file line */
+			wpa_printf(MSG_INFO, "Line %d: Ignore likely "
+				   "truncated p2p_client_list address '%s'",
+				   line, pos);
+		} else {
+			n = os_realloc_array(buf, count + 1, ETH_ALEN);
+			if (n == NULL) {
+				os_free(buf);
+				return -1;
+			}
+			buf = n;
+			os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+			os_memcpy(buf, addr, ETH_ALEN);
+			count++;
+			wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
+				    addr, ETH_ALEN);
+		}
+
+		pos = os_strchr(pos, ' ');
+	}
+
+	os_free(ssid->p2p_client_list);
+	ssid->p2p_client_list = buf;
+	ssid->num_p2p_clients = count;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	char *value, *end, *pos;
+	int res;
+	size_t i;
+
+	if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
+		return NULL;
+
+	value = os_malloc(20 * ssid->num_p2p_clients);
+	if (value == NULL)
+		return NULL;
+	pos = value;
+	end = value + 20 * ssid->num_p2p_clients;
+
+	for (i = ssid->num_p2p_clients; i > 0; i--) {
+		res = os_snprintf(pos, end - pos, MACSTR " ",
+				  MAC2STR(ssid->p2p_client_list +
+					  (i - 1) * ETH_ALEN));
+		if (res < 0 || res >= end - pos) {
+			os_free(value);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	if (pos > value)
+		pos[-1] = '\0';
+
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_P2P */
+
+/* Helper macros for network block parser */
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_ssid structure */
+#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
+
+/* STR: Define a string variable for an ASCII string; f = field name */
+#ifdef NO_CONFIG_WRITE
+#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
+#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#else /* NO_CONFIG_WRITE */
+#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
+#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#endif /* NO_CONFIG_WRITE */
+#define STR(f) _STR(f), NULL, NULL, NULL, 0
+#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+
+/* STR_LEN: Define a string variable with a separate variable for storing the
+ * data length. Unlike STR(), this can be used to store arbitrary binary data
+ * (i.e., even nul termination character). */
+#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
+#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
+#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
+
+/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
+ * explicitly specified. */
+#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
+#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
+#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
+
+#ifdef NO_CONFIG_WRITE
+#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
+#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#else /* NO_CONFIG_WRITE */
+#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
+	OFFSET(f), (void *) 0
+#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
+	OFFSET(eap.f), (void *) 0
+#endif /* NO_CONFIG_WRITE */
+
+/* INT: Define an integer variable */
+#define INT(f) _INT(f), NULL, NULL, 0
+#define INTe(f) _INTe(f), NULL, NULL, 0
+
+/* INT_RANGE: Define an integer variable with allowed value range */
+#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
+
+/* FUNC: Define a configuration variable that uses a custom function for
+ * parsing and writing the value. */
+#ifdef NO_CONFIG_WRITE
+#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
+#else /* NO_CONFIG_WRITE */
+#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
+	NULL, NULL, NULL, NULL
+#endif /* NO_CONFIG_WRITE */
+#define FUNC(f) _FUNC(f), 0
+#define FUNC_KEY(f) _FUNC(f), 1
+
+/*
+ * Table of network configuration variables. This table is used to parse each
+ * network configuration variable, e.g., each line in wpa_supplicant.conf file
+ * that is inside a network block.
+ *
+ * This table is generated using the helper macros defined above and with
+ * generous help from the C pre-processor. The field name is stored as a string
+ * into .name and for STR and INT types, the offset of the target buffer within
+ * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
+ * offset to the field containing the length of the configuration variable.
+ * .param3 and .param4 can be used to mark the allowed range (length for STR
+ * and value for INT).
+ *
+ * For each configuration line in wpa_supplicant.conf, the parser goes through
+ * this table and select the entry that matches with the field name. The parser
+ * function (.parser) is then called to parse the actual value of the field.
+ *
+ * This kind of mechanism makes it easy to add new configuration parameters,
+ * since only one line needs to be added into this table and into the
+ * struct wpa_ssid definition if the new variable is either a string or
+ * integer. More complex types will need to use their own parser and writer
+ * functions.
+ */
+static const struct parse_data ssid_fields[] = {
+	{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+	{ INT_RANGE(scan_ssid, 0, 1) },
+	{ FUNC(bssid) },
+	{ FUNC_KEY(psk) },
+	{ FUNC(proto) },
+	{ FUNC(key_mgmt) },
+	{ INT(bg_scan_period) },
+	{ FUNC(pairwise) },
+	{ FUNC(group) },
+	{ FUNC(auth_alg) },
+	{ FUNC(scan_freq) },
+	{ FUNC(freq_list) },
+#ifdef IEEE8021X_EAPOL
+	{ FUNC(eap) },
+	{ STR_LENe(identity) },
+	{ STR_LENe(anonymous_identity) },
+	{ FUNC_KEY(password) },
+	{ STRe(ca_cert) },
+	{ STRe(ca_path) },
+	{ STRe(client_cert) },
+	{ STRe(private_key) },
+	{ STR_KEYe(private_key_passwd) },
+	{ STRe(dh_file) },
+	{ STRe(subject_match) },
+	{ STRe(altsubject_match) },
+	{ STRe(ca_cert2) },
+	{ STRe(ca_path2) },
+	{ STRe(client_cert2) },
+	{ STRe(private_key2) },
+	{ STR_KEYe(private_key2_passwd) },
+	{ STRe(dh_file2) },
+	{ STRe(subject_match2) },
+	{ STRe(altsubject_match2) },
+	{ STRe(phase1) },
+	{ STRe(phase2) },
+	{ STRe(pcsc) },
+	{ STR_KEYe(pin) },
+	{ STRe(engine_id) },
+	{ STRe(key_id) },
+	{ STRe(cert_id) },
+	{ STRe(ca_cert_id) },
+	{ STR_KEYe(pin2) },
+	{ STRe(engine2_id) },
+	{ STRe(key2_id) },
+	{ STRe(cert2_id) },
+	{ STRe(ca_cert2_id) },
+	{ INTe(engine) },
+	{ INTe(engine2) },
+	{ INT(eapol_flags) },
+#endif /* IEEE8021X_EAPOL */
+	{ FUNC_KEY(wep_key0) },
+	{ FUNC_KEY(wep_key1) },
+	{ FUNC_KEY(wep_key2) },
+	{ FUNC_KEY(wep_key3) },
+	{ INT(wep_tx_keyidx) },
+	{ INT(priority) },
+#ifdef IEEE8021X_EAPOL
+	{ INT(eap_workaround) },
+	{ STRe(pac_file) },
+	{ INTe(fragment_size) },
+#endif /* IEEE8021X_EAPOL */
+	{ INT_RANGE(mode, 0, 4) },
+	{ INT_RANGE(proactive_key_caching, 0, 1) },
+	{ INT_RANGE(disabled, 0, 2) },
+	{ STR(id_str) },
+#ifdef CONFIG_IEEE80211W
+	{ INT_RANGE(ieee80211w, 0, 2) },
+#endif /* CONFIG_IEEE80211W */
+	{ INT_RANGE(peerkey, 0, 1) },
+	{ INT_RANGE(mixed_cell, 0, 1) },
+	{ INT_RANGE(frequency, 0, 65000) },
+	{ INT(wpa_ptk_rekey) },
+	{ STR(bgscan) },
+	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
+#ifdef CONFIG_P2P
+	{ FUNC(p2p_client_list) },
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+	{ INT_RANGE(disable_ht, 0, 1) },
+	{ INT_RANGE(disable_ht40, -1, 1) },
+	{ INT_RANGE(disable_sgi, 0, 1) },
+	{ INT_RANGE(disable_max_amsdu, -1, 1) },
+	{ INT_RANGE(ampdu_factor, -1, 3) },
+	{ INT_RANGE(ampdu_density, -1, 7) },
+	{ STR(ht_mcs) },
+#endif /* CONFIG_HT_OVERRIDES */
+	{ INT(ap_max_inactivity) },
+	{ INT(dtim_period) },
+};
+
+#undef OFFSET
+#undef _STR
+#undef STR
+#undef STR_KEY
+#undef _STR_LEN
+#undef STR_LEN
+#undef STR_LEN_KEY
+#undef _STR_RANGE
+#undef STR_RANGE
+#undef STR_RANGE_KEY
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _FUNC
+#undef FUNC
+#undef FUNC_KEY
+#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+
+
+/**
+ * wpa_config_add_prio_network - Add a network to priority lists
+ * @config: Configuration data from wpa_config_read()
+ * @ssid: Pointer to the network configuration to be added to the list
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to add a network block to the priority list of
+ * networks. This must be called for each network when reading in the full
+ * configuration. In addition, this can be used indirectly when updating
+ * priorities by calling wpa_config_update_prio_list().
+ */
+int wpa_config_add_prio_network(struct wpa_config *config,
+				struct wpa_ssid *ssid)
+{
+	int prio;
+	struct wpa_ssid *prev, **nlist;
+
+	/*
+	 * Add to an existing priority list if one is available for the
+	 * configured priority level for this network.
+	 */
+	for (prio = 0; prio < config->num_prio; prio++) {
+		prev = config->pssid[prio];
+		if (prev->priority == ssid->priority) {
+			while (prev->pnext)
+				prev = prev->pnext;
+			prev->pnext = ssid;
+			return 0;
+		}
+	}
+
+	/* First network for this priority - add a new priority list */
+	nlist = os_realloc_array(config->pssid, config->num_prio + 1,
+				 sizeof(struct wpa_ssid *));
+	if (nlist == NULL)
+		return -1;
+
+	for (prio = 0; prio < config->num_prio; prio++) {
+		if (nlist[prio]->priority < ssid->priority) {
+			os_memmove(&nlist[prio + 1], &nlist[prio],
+				   (config->num_prio - prio) *
+				   sizeof(struct wpa_ssid *));
+			break;
+		}
+	}
+
+	nlist[prio] = ssid;
+	config->num_prio++;
+	config->pssid = nlist;
+
+	return 0;
+}
+
+
+/**
+ * wpa_config_update_prio_list - Update network priority list
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to update the priority list of networks in the
+ * configuration when a network is being added or removed. This is also called
+ * if a priority for a network is changed.
+ */
+int wpa_config_update_prio_list(struct wpa_config *config)
+{
+	struct wpa_ssid *ssid;
+	int ret = 0;
+
+	os_free(config->pssid);
+	config->pssid = NULL;
+	config->num_prio = 0;
+
+	ssid = config->ssid;
+	while (ssid) {
+		ssid->pnext = NULL;
+		if (wpa_config_add_prio_network(config, ssid) < 0)
+			ret = -1;
+		ssid = ssid->next;
+	}
+
+	return ret;
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void eap_peer_config_free(struct eap_peer_config *eap)
+{
+	os_free(eap->eap_methods);
+	os_free(eap->identity);
+	os_free(eap->anonymous_identity);
+	os_free(eap->password);
+	os_free(eap->ca_cert);
+	os_free(eap->ca_path);
+	os_free(eap->client_cert);
+	os_free(eap->private_key);
+	os_free(eap->private_key_passwd);
+	os_free(eap->dh_file);
+	os_free(eap->subject_match);
+	os_free(eap->altsubject_match);
+	os_free(eap->ca_cert2);
+	os_free(eap->ca_path2);
+	os_free(eap->client_cert2);
+	os_free(eap->private_key2);
+	os_free(eap->private_key2_passwd);
+	os_free(eap->dh_file2);
+	os_free(eap->subject_match2);
+	os_free(eap->altsubject_match2);
+	os_free(eap->phase1);
+	os_free(eap->phase2);
+	os_free(eap->pcsc);
+	os_free(eap->pin);
+	os_free(eap->engine_id);
+	os_free(eap->key_id);
+	os_free(eap->cert_id);
+	os_free(eap->ca_cert_id);
+	os_free(eap->key2_id);
+	os_free(eap->cert2_id);
+	os_free(eap->ca_cert2_id);
+	os_free(eap->pin2);
+	os_free(eap->engine2_id);
+	os_free(eap->otp);
+	os_free(eap->pending_req_otp);
+	os_free(eap->pac_file);
+	os_free(eap->new_password);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+/**
+ * wpa_config_free_ssid - Free network/ssid configuration data
+ * @ssid: Configuration data for the network
+ *
+ * This function frees all resources allocated for the network configuration
+ * data.
+ */
+void wpa_config_free_ssid(struct wpa_ssid *ssid)
+{
+	os_free(ssid->ssid);
+	os_free(ssid->passphrase);
+	os_free(ssid->ext_psk);
+#ifdef IEEE8021X_EAPOL
+	eap_peer_config_free(&ssid->eap);
+#endif /* IEEE8021X_EAPOL */
+	os_free(ssid->id_str);
+	os_free(ssid->scan_freq);
+	os_free(ssid->freq_list);
+	os_free(ssid->bgscan);
+	os_free(ssid->p2p_client_list);
+#ifdef CONFIG_HT_OVERRIDES
+	os_free(ssid->ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
+	os_free(ssid);
+}
+
+
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+	os_free(cred->realm);
+	os_free(cred->username);
+	os_free(cred->password);
+	os_free(cred->ca_cert);
+	os_free(cred->client_cert);
+	os_free(cred->private_key);
+	os_free(cred->private_key_passwd);
+	os_free(cred->imsi);
+	os_free(cred->milenage);
+	os_free(cred->domain);
+	os_free(cred->eap_method);
+	os_free(cred->phase1);
+	os_free(cred->phase2);
+	os_free(cred->excluded_ssid);
+	os_free(cred);
+}
+
+
+/**
+ * wpa_config_free - Free configuration data
+ * @config: Configuration data from wpa_config_read()
+ *
+ * This function frees all resources allocated for the configuration data by
+ * wpa_config_read().
+ */
+void wpa_config_free(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct wpa_config_blob *blob, *prevblob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+	struct wpa_ssid *ssid, *prev = NULL;
+	struct wpa_cred *cred, *cprev;
+
+	ssid = config->ssid;
+	while (ssid) {
+		prev = ssid;
+		ssid = ssid->next;
+		wpa_config_free_ssid(prev);
+	}
+
+	cred = config->cred;
+	while (cred) {
+		cprev = cred;
+		cred = cred->next;
+		wpa_config_free_cred(cprev);
+	}
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	blob = config->blobs;
+	prevblob = NULL;
+	while (blob) {
+		prevblob = blob;
+		blob = blob->next;
+		wpa_config_free_blob(prevblob);
+	}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+	wpabuf_free(config->wps_vendor_ext_m1);
+	os_free(config->ctrl_interface);
+	os_free(config->ctrl_interface_group);
+	os_free(config->opensc_engine_path);
+	os_free(config->pkcs11_engine_path);
+	os_free(config->pkcs11_module_path);
+	os_free(config->pcsc_reader);
+	os_free(config->pcsc_pin);
+	os_free(config->driver_param);
+	os_free(config->device_name);
+	os_free(config->manufacturer);
+	os_free(config->model_name);
+	os_free(config->model_number);
+	os_free(config->serial_number);
+	os_free(config->config_methods);
+	os_free(config->p2p_ssid_postfix);
+	os_free(config->pssid);
+	os_free(config->p2p_pref_chan);
+	os_free(config->autoscan);
+	wpabuf_free(config->wps_nfc_dh_pubkey);
+	wpabuf_free(config->wps_nfc_dh_privkey);
+	wpabuf_free(config->wps_nfc_dev_pw);
+	os_free(config->ext_password_backend);
+	os_free(config);
+}
+
+
+/**
+ * wpa_config_foreach_network - Iterate over each configured network
+ * @config: Configuration data from wpa_config_read()
+ * @func: Callback function to process each network
+ * @arg: Opaque argument to pass to callback function
+ *
+ * Iterate over the set of configured networks calling the specified
+ * function for each item. We guard against callbacks removing the
+ * supplied network.
+ */
+void wpa_config_foreach_network(struct wpa_config *config,
+				void (*func)(void *, struct wpa_ssid *),
+				void *arg)
+{
+	struct wpa_ssid *ssid, *next;
+
+	ssid = config->ssid;
+	while (ssid) {
+		next = ssid->next;
+		func(arg, ssid);
+		ssid = next;
+	}
+}
+
+
+/**
+ * wpa_config_get_network - Get configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: Network configuration or %NULL if not found
+ */
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
+{
+	struct wpa_ssid *ssid;
+
+	ssid = config->ssid;
+	while (ssid) {
+		if (id == ssid->id)
+			break;
+		ssid = ssid->next;
+	}
+
+	return ssid;
+}
+
+
+/**
+ * wpa_config_add_network - Add a new network with empty configuration
+ * @config: Configuration data from wpa_config_read()
+ * Returns: The new network configuration or %NULL if operation failed
+ */
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
+{
+	int id;
+	struct wpa_ssid *ssid, *last = NULL;
+
+	id = -1;
+	ssid = config->ssid;
+	while (ssid) {
+		if (ssid->id > id)
+			id = ssid->id;
+		last = ssid;
+		ssid = ssid->next;
+	}
+	id++;
+
+	ssid = os_zalloc(sizeof(*ssid));
+	if (ssid == NULL)
+		return NULL;
+	ssid->id = id;
+	if (last)
+		last->next = ssid;
+	else
+		config->ssid = ssid;
+
+	wpa_config_update_prio_list(config);
+
+	return ssid;
+}
+
+
+/**
+ * wpa_config_remove_network - Remove a configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found
+ */
+int wpa_config_remove_network(struct wpa_config *config, int id)
+{
+	struct wpa_ssid *ssid, *prev = NULL;
+
+	ssid = config->ssid;
+	while (ssid) {
+		if (id == ssid->id)
+			break;
+		prev = ssid;
+		ssid = ssid->next;
+	}
+
+	if (ssid == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = ssid->next;
+	else
+		config->ssid = ssid->next;
+
+	wpa_config_update_prio_list(config);
+	wpa_config_free_ssid(ssid);
+	return 0;
+}
+
+
+/**
+ * wpa_config_set_network_defaults - Set network default values
+ * @ssid: Pointer to network configuration data
+ */
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
+{
+	ssid->proto = DEFAULT_PROTO;
+	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+	ssid->group_cipher = DEFAULT_GROUP;
+	ssid->key_mgmt = DEFAULT_KEY_MGMT;
+	ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
+#ifdef IEEE8021X_EAPOL
+	ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
+	ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
+	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_HT_OVERRIDES
+	ssid->disable_ht = DEFAULT_DISABLE_HT;
+	ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+	ssid->disable_sgi = DEFAULT_DISABLE_SGI;
+	ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
+	ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
+	ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
+#endif /* CONFIG_HT_OVERRIDES */
+	ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+/**
+ * wpa_config_set - Set a variable in network configuration
+ * @ssid: Pointer to network configuration data
+ * @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
+ *
+ * This function can be used to set network configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+		   int line)
+{
+	size_t i;
+	int ret = 0;
+
+	if (ssid == NULL || var == NULL || value == NULL)
+		return -1;
+
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		const struct parse_data *field = &ssid_fields[i];
+		if (os_strcmp(var, field->name) != 0)
+			continue;
+
+		if (field->parser(field, ssid, line, value)) {
+			if (line) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "parse %s '%s'.", line, var, value);
+			}
+			ret = -1;
+		}
+		break;
+	}
+	if (i == NUM_SSID_FIELDS) {
+		if (line) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+				   "'%s'.", line, var);
+		}
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value)
+{
+	size_t len;
+	char *buf;
+	int ret;
+
+	len = os_strlen(value);
+	buf = os_malloc(len + 3);
+	if (buf == NULL)
+		return -1;
+	buf[0] = '"';
+	os_memcpy(buf + 1, value, len);
+	buf[len + 1] = '"';
+	buf[len + 2] = '\0';
+	ret = wpa_config_set(ssid, var, buf, 0);
+	os_free(buf);
+	return ret;
+}
+
+
+/**
+ * wpa_config_get_all - Get all options from network configuration
+ * @ssid: Pointer to network configuration data
+ * @get_keys: Determines if keys/passwords will be included in returned list
+ *	(if they may be exported)
+ * Returns: %NULL terminated list of all set keys and their values in the form
+ * of [key1, val1, key2, val2, ... , NULL]
+ *
+ * This function can be used to get list of all configured network properties.
+ * The caller is responsible for freeing the returned list and all its
+ * elements.
+ */
+char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
+{
+	const struct parse_data *field;
+	char *key, *value;
+	size_t i;
+	char **props;
+	int fields_num;
+
+	get_keys = get_keys && ssid->export_keys;
+
+	props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
+	if (!props)
+		return NULL;
+
+	fields_num = 0;
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		field = &ssid_fields[i];
+		if (field->key_data && !get_keys)
+			continue;
+		value = field->writer(field, ssid);
+		if (value == NULL)
+			continue;
+		if (os_strlen(value) == 0) {
+			os_free(value);
+			continue;
+		}
+
+		key = os_strdup(field->name);
+		if (key == NULL) {
+			os_free(value);
+			goto err;
+		}
+
+		props[fields_num * 2] = key;
+		props[fields_num * 2 + 1] = value;
+
+		fields_num++;
+	}
+
+	return props;
+
+err:
+	value = *props;
+	while (value)
+		os_free(value++);
+	os_free(props);
+	return NULL;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+/**
+ * wpa_config_get - Get a variable in network configuration
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variables. The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
+{
+	size_t i;
+
+	if (ssid == NULL || var == NULL)
+		return NULL;
+
+	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);
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_config_get_no_key - Get a variable in network configuration (no keys)
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variable like
+ * wpa_config_get(). The only difference is that this functions does not expose
+ * key/password material from the configuration. In case a key/password field
+ * is requested, the returned value is an empty string or %NULL if the variable
+ * is not set or "*" if the variable is set (regardless of its value). The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
+{
+	size_t i;
+
+	if (ssid == NULL || var == NULL)
+		return NULL;
+
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		const struct parse_data *field = &ssid_fields[i];
+		if (os_strcmp(var, field->name) == 0) {
+			char *res = field->writer(field, ssid);
+			if (field->key_data) {
+				if (res && res[0]) {
+					wpa_printf(MSG_DEBUG, "Do not allow "
+						   "key_data field to be "
+						   "exposed");
+					os_free(res);
+					return os_strdup("*");
+				}
+
+				os_free(res);
+				return NULL;
+			}
+			return res;
+		}
+	}
+
+	return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+/**
+ * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
+ * @ssid: Pointer to network configuration data
+ *
+ * This function must be called to update WPA PSK when either SSID or the
+ * passphrase has changed for the network configuration.
+ */
+void wpa_config_update_psk(struct wpa_ssid *ssid)
+{
+#ifndef CONFIG_NO_PBKDF2
+	pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
+		    ssid->psk, PMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+			ssid->psk, PMK_LEN);
+	ssid->psk_set = 1;
+#endif /* CONFIG_NO_PBKDF2 */
+}
+
+
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+			const char *value, int line)
+{
+	char *val;
+	size_t len;
+
+	if (os_strcmp(var, "priority") == 0) {
+		cred->priority = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "pcsc") == 0) {
+		cred->pcsc = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "eap") == 0) {
+		struct eap_method_type method;
+		method.method = eap_peer_get_type(value, &method.vendor);
+		if (method.vendor == EAP_VENDOR_IETF &&
+		    method.method == EAP_TYPE_NONE) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+				   "for a credential", line, value);
+			return -1;
+		}
+		os_free(cred->eap_method);
+		cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+		if (cred->eap_method == NULL)
+			return -1;
+		os_memcpy(cred->eap_method, &method, sizeof(method));
+		return 0;
+	}
+
+	if (os_strcmp(var, "password") == 0 &&
+	    os_strncmp(value, "ext:", 4) == 0) {
+		os_free(cred->password);
+		cred->password = os_strdup(value);
+		cred->ext_password = 1;
+		return 0;
+	}
+
+	val = wpa_config_parse_string(value, &len);
+	if (val == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+			   "value '%s'.", line, var, value);
+		return -1;
+	}
+
+	if (os_strcmp(var, "realm") == 0) {
+		os_free(cred->realm);
+		cred->realm = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "username") == 0) {
+		os_free(cred->username);
+		cred->username = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "password") == 0) {
+		os_free(cred->password);
+		cred->password = val;
+		cred->ext_password = 0;
+		return 0;
+	}
+
+	if (os_strcmp(var, "ca_cert") == 0) {
+		os_free(cred->ca_cert);
+		cred->ca_cert = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "client_cert") == 0) {
+		os_free(cred->client_cert);
+		cred->client_cert = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "private_key") == 0) {
+		os_free(cred->private_key);
+		cred->private_key = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "private_key_passwd") == 0) {
+		os_free(cred->private_key_passwd);
+		cred->private_key_passwd = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "imsi") == 0) {
+		os_free(cred->imsi);
+		cred->imsi = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "milenage") == 0) {
+		os_free(cred->milenage);
+		cred->milenage = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "domain") == 0) {
+		os_free(cred->domain);
+		cred->domain = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "phase1") == 0) {
+		os_free(cred->phase1);
+		cred->phase1 = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "phase2") == 0) {
+		os_free(cred->phase2);
+		cred->phase2 = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "roaming_consortium") == 0) {
+		if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "roaming_consortium length %d (3..15 "
+				   "expected)", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+		os_memcpy(cred->roaming_consortium, val, len);
+		cred->roaming_consortium_len = len;
+		os_free(val);
+		return 0;
+	}
+
+	if (os_strcmp(var, "excluded_ssid") == 0) {
+		struct excluded_ssid *e;
+
+		if (len > MAX_SSID_LEN) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "excluded_ssid length %d", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+
+		e = os_realloc_array(cred->excluded_ssid,
+				     cred->num_excluded_ssid + 1,
+				     sizeof(struct excluded_ssid));
+		if (e == NULL) {
+			os_free(val);
+			return -1;
+		}
+		cred->excluded_ssid = e;
+
+		e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+		os_memcpy(e->ssid, val, len);
+		e->ssid_len = len;
+
+		os_free(val);
+
+		return 0;
+	}
+
+	if (line) {
+		wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+			   line, var);
+	}
+
+	os_free(val);
+
+	return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+	struct wpa_cred *cred;
+
+	cred = config->cred;
+	while (cred) {
+		if (id == cred->id)
+			break;
+		cred = cred->next;
+	}
+
+	return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+	int id;
+	struct wpa_cred *cred, *last = NULL;
+
+	id = -1;
+	cred = config->cred;
+	while (cred) {
+		if (cred->id > id)
+			id = cred->id;
+		last = cred;
+		cred = cred->next;
+	}
+	id++;
+
+	cred = os_zalloc(sizeof(*cred));
+	if (cred == NULL)
+		return NULL;
+	cred->id = id;
+	if (last)
+		last->next = cred;
+	else
+		config->cred = cred;
+
+	return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+	struct wpa_cred *cred, *prev = NULL;
+
+	cred = config->cred;
+	while (cred) {
+		if (id == cred->id)
+			break;
+		prev = cred;
+		cred = cred->next;
+	}
+
+	if (cred == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = cred->next;
+	else
+		config->cred = cred->next;
+
+	wpa_config_free_cred(cred);
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+/**
+ * wpa_config_get_blob - Get a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+						   const char *name)
+{
+	struct wpa_config_blob *blob = config->blobs;
+
+	while (blob) {
+		if (os_strcmp(blob->name, name) == 0)
+			return blob;
+		blob = blob->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * wpa_config_set_blob - Set or add a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void wpa_config_set_blob(struct wpa_config *config,
+			 struct wpa_config_blob *blob)
+{
+	wpa_config_remove_blob(config, blob->name);
+	blob->next = config->blobs;
+	config->blobs = blob;
+}
+
+
+/**
+ * wpa_config_free_blob - Free blob data
+ * @blob: Pointer to blob to be freed
+ */
+void wpa_config_free_blob(struct wpa_config_blob *blob)
+{
+	if (blob) {
+		os_free(blob->name);
+		os_free(blob->data);
+		os_free(blob);
+	}
+}
+
+
+/**
+ * wpa_config_remove_blob - Remove a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob to remove
+ * Returns: 0 if blob was removed or -1 if blob was not found
+ */
+int wpa_config_remove_blob(struct wpa_config *config, const char *name)
+{
+	struct wpa_config_blob *pos = config->blobs, *prev = NULL;
+
+	while (pos) {
+		if (os_strcmp(pos->name, name) == 0) {
+			if (prev)
+				prev->next = pos->next;
+			else
+				config->blobs = pos->next;
+			wpa_config_free_blob(pos);
+			return 0;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+/**
+ * wpa_config_alloc_empty - Allocate an empty configuration
+ * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
+ * socket
+ * @driver_param: Driver parameters
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ */
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+					   const char *driver_param)
+{
+	struct wpa_config *config;
+	const int aCWmin = 4, aCWmax = 10;
+	const struct hostapd_wmm_ac_params ac_bk =
+		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+	const struct hostapd_wmm_ac_params ac_be =
+		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+
+	config = os_zalloc(sizeof(*config));
+	if (config == NULL)
+		return NULL;
+	config->eapol_version = DEFAULT_EAPOL_VERSION;
+	config->ap_scan = DEFAULT_AP_SCAN;
+	config->fast_reauth = DEFAULT_FAST_REAUTH;
+	config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
+	config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+	config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
+	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
+	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
+	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
+	config->max_num_sta = DEFAULT_MAX_NUM_STA;
+	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+	config->wmm_ac_params[0] = ac_be;
+	config->wmm_ac_params[1] = ac_bk;
+	config->wmm_ac_params[2] = ac_vi;
+	config->wmm_ac_params[3] = ac_vo;
+
+	if (ctrl_interface)
+		config->ctrl_interface = os_strdup(ctrl_interface);
+	if (driver_param)
+		config->driver_param = os_strdup(driver_param);
+
+	return config;
+}
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+/**
+ * wpa_config_debug_dump_networks - Debug dump of configured networks
+ * @config: Configuration data from wpa_config_read()
+ */
+void wpa_config_debug_dump_networks(struct wpa_config *config)
+{
+	int prio;
+	struct wpa_ssid *ssid;
+
+	for (prio = 0; prio < config->num_prio; prio++) {
+		ssid = config->pssid[prio];
+		wpa_printf(MSG_DEBUG, "Priority group %d",
+			   ssid->priority);
+		while (ssid) {
+			wpa_printf(MSG_DEBUG, "   id=%d ssid='%s'",
+				   ssid->id,
+				   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			ssid = ssid->pnext;
+		}
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+struct global_parse_data {
+	char *name;
+	int (*parser)(const struct global_parse_data *data,
+		      struct wpa_config *config, int line, const char *value);
+	void *param1, *param2, *param3;
+	unsigned int changed_flag;
+};
+
+
+static int wpa_global_config_parse_int(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	int *dst;
+	dst = (int *) (((u8 *) config) + (long) data->param1);
+	*dst = atoi(pos);
+	wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
+
+	if (data->param2 && *dst < (long) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+			   "min_value=%ld)", line, data->name, *dst,
+			   (long) data->param2);
+		*dst = (long) data->param2;
+		return -1;
+	}
+
+	if (data->param3 && *dst > (long) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+			   "max_value=%ld)", line, data->name, *dst,
+			   (long) data->param3);
+		*dst = (long) data->param3;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_global_config_parse_str(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	size_t len;
+	char **dst, *tmp;
+
+	len = os_strlen(pos);
+	if (data->param2 && len < (size_t) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+			   "min_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param2);
+		return -1;
+	}
+
+	if (data->param3 && len > (size_t) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+			   "max_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param3);
+		return -1;
+	}
+
+	tmp = os_strdup(pos);
+	if (tmp == NULL)
+		return -1;
+
+	dst = (char **) (((u8 *) config) + (long) data->param1);
+	os_free(*dst);
+	*dst = tmp;
+	wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
+
+	return 0;
+}
+
+
+static int wpa_global_config_parse_bin(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	size_t len;
+	struct wpabuf **dst, *tmp;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+
+	tmp = wpabuf_alloc(len / 2);
+	if (tmp == NULL)
+		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;
+	wpa_printf(MSG_DEBUG, "%s", data->name);
+
+	return 0;
+}
+
+
+static int wpa_config_process_country(const struct global_parse_data *data,
+				      struct wpa_config *config, int line,
+				      const char *pos)
+{
+	if (!pos[0] || !pos[1]) {
+		wpa_printf(MSG_DEBUG, "Invalid country set");
+		return -1;
+	}
+	config->country[0] = pos[0];
+	config->country[1] = pos[1];
+	wpa_printf(MSG_DEBUG, "country='%c%c'",
+		   config->country[0], config->country[1]);
+	return 0;
+}
+
+
+static int wpa_config_process_load_dynamic_eap(
+	const struct global_parse_data *data, struct wpa_config *config,
+	int line, const char *so)
+{
+	int ret;
+	wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
+	ret = eap_peer_method_load(so);
+	if (ret == -2) {
+		wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
+			   "reloading.");
+	} else if (ret) {
+		wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
+			   "method '%s'.", line, so);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS
+
+static int wpa_config_process_uuid(const struct global_parse_data *data,
+				   struct wpa_config *config, int line,
+				   const char *pos)
+{
+	char buf[40];
+	if (uuid_str2bin(pos, config->uuid)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
+		return -1;
+	}
+	uuid_bin2str(config->uuid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "uuid=%s", buf);
+	return 0;
+}
+
+
+static int wpa_config_process_device_type(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	return wps_dev_type_str2bin(pos, config->device_type);
+}
+
+
+static int wpa_config_process_os_version(const struct global_parse_data *data,
+					 struct wpa_config *config, int line,
+					 const char *pos)
+{
+	if (hexstr2bin(pos, config->os_version, 4)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "os_version=%08x",
+		   WPA_GET_BE32(config->os_version));
+	return 0;
+}
+
+
+static int wpa_config_process_wps_vendor_ext_m1(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	struct wpabuf *tmp;
+	int len = os_strlen(pos) / 2;
+	u8 *p;
+
+	if (!len) {
+		wpa_printf(MSG_ERROR, "Line %d: "
+			   "invalid wps_vendor_ext_m1", line);
+		return -1;
+	}
+
+	tmp = wpabuf_alloc(len);
+	if (tmp) {
+		p = wpabuf_put(tmp, len);
+
+		if (hexstr2bin(pos, p, len)) {
+			wpa_printf(MSG_ERROR, "Line %d: "
+				   "invalid wps_vendor_ext_m1", line);
+			wpabuf_free(tmp);
+			return -1;
+		}
+
+		wpabuf_free(config->wps_vendor_ext_m1);
+		config->wps_vendor_ext_m1 = tmp;
+	} else {
+		wpa_printf(MSG_ERROR, "Can not allocate "
+			   "memory for wps_vendor_ext_m1");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+static int wpa_config_process_sec_device_type(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	int idx;
+
+	if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
+		wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
+			   "items", line);
+		return -1;
+	}
+
+	idx = config->num_sec_device_types;
+
+	if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
+		return -1;
+
+	config->num_sec_device_types++;
+	return 0;
+}
+
+
+static int wpa_config_process_p2p_pref_chan(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	struct p2p_channel *pref = NULL, *n;
+	unsigned int num = 0;
+	const char *pos2;
+	u8 op_class, chan;
+
+	/* format: class:chan,class:chan,... */
+
+	while (*pos) {
+		op_class = atoi(pos);
+		pos2 = os_strchr(pos, ':');
+		if (pos2 == NULL)
+			goto fail;
+		pos2++;
+		chan = atoi(pos2);
+
+		n = os_realloc_array(pref, num + 1,
+				     sizeof(struct p2p_channel));
+		if (n == NULL)
+			goto fail;
+		pref = n;
+		pref[num].op_class = op_class;
+		pref[num].chan = chan;
+		num++;
+
+		pos = os_strchr(pos2, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	os_free(config->p2p_pref_chan);
+	config->p2p_pref_chan = pref;
+	config->num_p2p_pref_chan = num;
+	wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+		    (u8 *) config->p2p_pref_chan,
+		    config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+	return 0;
+
+fail:
+	os_free(pref);
+	wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+	return -1;
+}
+#endif /* CONFIG_P2P */
+
+
+static int wpa_config_process_hessid(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	if (hwaddr_aton2(pos, config->hessid) < 0) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
+			   line, pos);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_config structure */
+#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
+
+#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define INT(f) _INT(f), NULL, NULL
+#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
+#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL
+#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+
+static const struct global_parse_data global_fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+	{ STR(ctrl_interface), 0 },
+	{ STR(ctrl_interface_group), 0 } /* deprecated */,
+#endif /* CONFIG_CTRL_IFACE */
+	{ INT_RANGE(eapol_version, 1, 2), 0 },
+	{ INT(ap_scan), 0 },
+	{ INT(disable_scan_offload), 0 },
+	{ INT(fast_reauth), 0 },
+	{ STR(opensc_engine_path), 0 },
+	{ STR(pkcs11_engine_path), 0 },
+	{ STR(pkcs11_module_path), 0 },
+	{ STR(pcsc_reader), 0 },
+	{ STR(pcsc_pin), 0 },
+	{ STR(driver_param), 0 },
+	{ INT(dot11RSNAConfigPMKLifetime), 0 },
+	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
+	{ INT(dot11RSNAConfigSATimeout), 0 },
+#ifndef CONFIG_NO_CONFIG_WRITE
+	{ INT(update_config), 0 },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	{ FUNC_NO_VAR(load_dynamic_eap), 0 },
+#ifdef CONFIG_WPS
+	{ FUNC(uuid), CFG_CHANGED_UUID },
+	{ STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+	{ STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
+	{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
+	{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
+	{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+	{ FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
+	{ INT(p2p_listen_reg_class), 0 },
+	{ INT(p2p_listen_channel), 0 },
+	{ INT(p2p_oper_reg_class), 0 },
+	{ INT(p2p_oper_channel), 0 },
+	{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
+	{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
+	{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
+	{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
+	{ INT(p2p_group_idle), 0 },
+	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+	{ INT(p2p_go_ht40), 0 },
+	{ INT(p2p_disabled), 0 },
+	{ INT(p2p_no_group_iface), 0 },
+#endif /* CONFIG_P2P */
+	{ FUNC(country), CFG_CHANGED_COUNTRY },
+	{ INT(bss_max_count), 0 },
+	{ INT(bss_expiration_age), 0 },
+	{ INT(bss_expiration_scan_count), 0 },
+	{ INT_RANGE(filter_ssids, 0, 1), 0 },
+	{ INT_RANGE(filter_rssi, -100, 0), 0 },
+	{ INT(max_num_sta), 0 },
+	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
+#ifdef CONFIG_HS20
+	{ INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
+	{ INT_RANGE(interworking, 0, 1), 0 },
+	{ FUNC(hessid), 0 },
+	{ INT_RANGE(access_network_type, 0, 15), 0 },
+	{ INT_RANGE(pbc_in_m1, 0, 1), 0 },
+	{ STR(autoscan), 0 },
+	{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+	{ BIN(wps_nfc_dh_pubkey), 0 },
+	{ BIN(wps_nfc_dh_privkey), 0 },
+	{ BIN(wps_nfc_dev_pw), 0 },
+	{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+	{ INT(p2p_go_max_inactivity), 0 },
+	{ INT_RANGE(auto_interworking, 0, 1), 0 },
+	{ INT(okc), 0 },
+	{ INT(pmf), 0 },
+};
+
+#undef FUNC
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _STR
+#undef STR
+#undef STR_RANGE
+#undef BIN
+#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+
+
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
+{
+	size_t i;
+	int ret = 0;
+
+	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+		const struct global_parse_data *field = &global_fields[i];
+		size_t flen = os_strlen(field->name);
+		if (os_strncmp(pos, field->name, flen) != 0 ||
+		    pos[flen] != '=')
+			continue;
+
+		if (field->parser(field, config, line, pos + flen + 1)) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to "
+				   "parse '%s'.", line, pos);
+			ret = -1;
+		}
+		config->changed_parameters |= field->changed_flag;
+		break;
+	}
+	if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+		if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+			char *tmp = os_strchr(pos, '=');
+			if (tmp == NULL) {
+				if (line < 0)
+					return -1;
+				wpa_printf(MSG_ERROR, "Line %d: invalid line "
+					   "'%s'", line, pos);
+				return -1;
+			}
+			*tmp++ = '\0';
+			if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+						  tmp)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+					   "AC item", line);
+				return -1;
+			}
+		}
+#endif /* CONFIG_AP */
+		if (line < 0)
+			return -1;
+		wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
+			   line, pos);
+		ret = -1;
+	}
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/config.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,416 +0,0 @@
-/*
- * WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-#define DEFAULT_EAPOL_VERSION 1
-#ifdef CONFIG_NO_SCAN_PROCESSING
-#define DEFAULT_AP_SCAN 2
-#else /* CONFIG_NO_SCAN_PROCESSING */
-#define DEFAULT_AP_SCAN 1
-#endif /* CONFIG_NO_SCAN_PROCESSING */
-#define DEFAULT_FAST_REAUTH 1
-#define DEFAULT_BSS_MAX_COUNT 200
-
-#include "config_ssid.h"
-
-
-/**
- * struct wpa_config - wpa_supplicant configuration data
- *
- * This data structure is presents the per-interface (radio) configuration
- * data. In many cases, there is only one struct wpa_config instance, but if
- * more than one network interface is being controlled, one instance is used
- * for each.
- */
-struct wpa_config {
-	/**
-	 * ssid - Head of the global network list
-	 *
-	 * This is the head for the list of all the configured networks.
-	 */
-	struct wpa_ssid *ssid;
-
-	/**
-	 * pssid - Per-priority network lists (in priority order)
-	 */
-	struct wpa_ssid **pssid;
-
-	/**
-	 * num_prio - Number of different priorities used in the pssid lists
-	 *
-	 * This indicates how many per-priority network lists are included in
-	 * pssid.
-	 */
-	int num_prio;
-
-	/**
-	 * eapol_version - IEEE 802.1X/EAPOL version number
-	 *
-	 * wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
-	 * defines EAPOL version 2. However, there are many APs that do not
-	 * handle the new version number correctly (they seem to drop the
-	 * frames completely). In order to make wpa_supplicant interoperate
-	 * with these APs, the version number is set to 1 by default. This
-	 * configuration value can be used to set it to the new version (2).
-	 */
-	int eapol_version;
-
-	/**
-	 * ap_scan - AP scanning/selection
-	 *
-	 * By default, wpa_supplicant requests driver to perform AP
-	 * scanning and then uses the scan results to select a
-	 * suitable AP. Another alternative is to allow the driver to
-	 * take care of AP scanning and selection and use
-	 * wpa_supplicant just to process EAPOL frames based on IEEE
-	 * 802.11 association information from the driver.
-	 *
-	 * 1: wpa_supplicant initiates scanning and AP selection (default).
-	 *
-	 * 0: Driver takes care of scanning, AP selection, and IEEE 802.11
-	 * association parameters (e.g., WPA IE generation); this mode can
-	 * also be used with non-WPA drivers when using IEEE 802.1X mode;
-	 * do not try to associate with APs (i.e., external program needs
-	 * to control association). This mode must also be used when using
-	 * wired Ethernet drivers.
-	 *
-	 * 2: like 0, but associate with APs using security policy and SSID
-	 * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS
-	 * drivers to enable operation with hidden SSIDs and optimized roaming;
-	 * in this mode, the network blocks in the configuration are tried
-	 * one by one until the driver reports successful association; each
-	 * network block should have explicit security policy (i.e., only one
-	 * option in the lists) for key_mgmt, pairwise, group, proto variables.
-	 */
-	int ap_scan;
-
-	/**
-	 * ctrl_interface - Parameters for the control interface
-	 *
-	 * If this is specified, %wpa_supplicant will open a control interface
-	 * that is available for external programs to manage %wpa_supplicant.
-	 * The meaning of this string depends on which control interface
-	 * mechanism is used. For all cases, the existance of this parameter
-	 * in configuration is used to determine whether the control interface
-	 * is enabled.
-	 *
-	 * For UNIX domain sockets (default on Linux and BSD): This is a
-	 * directory that will be created for UNIX domain sockets for listening
-	 * to requests from external programs (CLI/GUI, etc.) for status
-	 * information and configuration. The socket file will be named based
-	 * on the interface name, so multiple %wpa_supplicant processes can be
-	 * run at the same time if more than one interface is used.
-	 * /var/run/wpa_supplicant is the recommended directory for sockets and
-	 * by default, wpa_cli will use it when trying to connect with
-	 * %wpa_supplicant.
-	 *
-	 * Access control for the control interface can be configured
-	 * by setting the directory to allow only members of a group
-	 * to use sockets. This way, it is possible to run
-	 * %wpa_supplicant as root (since it needs to change network
-	 * configuration and open raw sockets) and still allow GUI/CLI
-	 * components to be run as non-root users. However, since the
-	 * control interface can be used to change the network
-	 * configuration, this access needs to be protected in many
-	 * cases. By default, %wpa_supplicant is configured to use gid
-	 * 0 (root). If you want to allow non-root users to use the
-	 * control interface, add a new group and change this value to
-	 * match with that group. Add users that should have control
-	 * interface access to this group.
-	 *
-	 * When configuring both the directory and group, use following format:
-	 * DIR=/var/run/wpa_supplicant GROUP=wheel
-	 * DIR=/var/run/wpa_supplicant GROUP=0
-	 * (group can be either group name or gid)
-	 *
-	 * For UDP connections (default on Windows): The value will be ignored.
-	 * This variable is just used to select that the control interface is
-	 * to be created. The value can be set to, e.g., udp
-	 * (ctrl_interface=udp).
-	 *
-	 * For Windows Named Pipe: This value can be used to set the security
-	 * descriptor for controlling access to the control interface. Security
-	 * descriptor can be set using Security Descriptor String Format (see
-	 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp).
-	 * The descriptor string needs to be prefixed with SDDL=. For example,
-	 * ctrl_interface=SDDL=D: would set an empty DACL (which will reject
-	 * all connections).
-	 */
-	char *ctrl_interface;
-
-	/**
-	 * ctrl_interface_group - Control interface group (DEPRECATED)
-	 *
-	 * This variable is only used for backwards compatibility. Group for
-	 * UNIX domain sockets should now be specified using GROUP=group in
-	 * ctrl_interface variable.
-	 */
-	char *ctrl_interface_group;
-
-	/**
-	 * fast_reauth - EAP fast re-authentication (session resumption)
-	 *
-	 * By default, fast re-authentication is enabled for all EAP methods
-	 * that support it. This variable can be used to disable fast
-	 * re-authentication (by setting fast_reauth=0). Normally, there is no
-	 * need to disable fast re-authentication.
-	 */
-	int fast_reauth;
-
-	/**
-	 * opensc_engine_path - Path to the OpenSSL engine for opensc
-	 *
-	 * This is an OpenSSL specific configuration option for loading OpenSC
-	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
-	 */
-	char *opensc_engine_path;
-
-	/**
-	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
-	 *
-	 * This is an OpenSSL specific configuration option for loading PKCS#11
-	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
-	 */
-	char *pkcs11_engine_path;
-
-	/**
-	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
-	 *
-	 * This is an OpenSSL specific configuration option for configuring
-	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
-	 * module is not loaded.
-	 */
-	char *pkcs11_module_path;
-
-	/**
-	 * driver_param - Driver interface parameters
-	 *
-	 * This text string is passed to the selected driver interface with the
-	 * optional struct wpa_driver_ops::set_param() handler. This can be
-	 * used to configure driver specific options without having to add new
-	 * driver interface functionality.
-	 */
-	char *driver_param;
-
-	/**
-	 * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK
-	 *
-	 * dot11 MIB variable for the maximum lifetime of a PMK in the PMK
-	 * cache (unit: seconds).
-	 */
-	unsigned int dot11RSNAConfigPMKLifetime;
-
-	/**
-	 * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold
-	 *
-	 * dot11 MIB variable for the percentage of the PMK lifetime
-	 * that should expire before an IEEE 802.1X reauthentication occurs.
-	 */
-	unsigned int dot11RSNAConfigPMKReauthThreshold;
-
-	/**
-	 * dot11RSNAConfigSATimeout - Security association timeout
-	 *
-	 * dot11 MIB variable for the maximum time a security association
-	 * shall take to set up (unit: seconds).
-	 */
-	unsigned int dot11RSNAConfigSATimeout;
-
-	/**
-	 * update_config - Is wpa_supplicant allowed to update configuration
-	 *
-	 * This variable control whether wpa_supplicant is allow to re-write
-	 * its configuration with wpa_config_write(). If this is zero,
-	 * configuration data is only changed in memory and the external data
-	 * is not overriden. If this is non-zero, wpa_supplicant will update
-	 * the configuration data (e.g., a file) whenever configuration is
-	 * changed. This update may replace the old configuration which can
-	 * remove comments from it in case of a text file configuration.
-	 */
-	int update_config;
-
-	/**
-	 * blobs - Configuration blobs
-	 */
-	struct wpa_config_blob *blobs;
-
-	/**
-	 * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS
-	 */
-	u8 uuid[16];
-
-	/**
-	 * device_name - Device Name (WPS)
-	 * User-friendly description of device; up to 32 octets encoded in
-	 * UTF-8
-	 */
-	char *device_name;
-
-	/**
-	 * manufacturer - Manufacturer (WPS)
-	 * The manufacturer of the device (up to 64 ASCII characters)
-	 */
-	char *manufacturer;
-
-	/**
-	 * model_name - Model Name (WPS)
-	 * Model of the device (up to 32 ASCII characters)
-	 */
-	char *model_name;
-
-	/**
-	 * model_number - Model Number (WPS)
-	 * Additional device description (up to 32 ASCII characters)
-	 */
-	char *model_number;
-
-	/**
-	 * serial_number - Serial Number (WPS)
-	 * Serial number of the device (up to 32 characters)
-	 */
-	char *serial_number;
-
-	/**
-	 * device_type - Primary Device Type (WPS)
-	 * Used format: categ-OUI-subcateg
-	 * categ = Category as an integer value
-	 * OUI = OUI and type octet as a 4-octet hex-encoded value;
-	 *	0050F204 for default WPS OUI
-	 * subcateg = OUI-specific Sub Category as an integer value
-	 * Examples:
-	 *   1-0050F204-1 (Computer / PC)
-	 *   1-0050F204-2 (Computer / Server)
-	 *   5-0050F204-1 (Storage / NAS)
-	 *   6-0050F204-1 (Network Infrastructure / AP)
-	 */
-	char *device_type;
-
-	/**
-	 * config_methods - Config Methods
-	 *
-	 * This is a space-separated list of supported WPS configuration
-	 * methods. For example, "label display push_button keypad".
-	 * Available methods: usba ethernet label display ext_nfc_token
-	 * int_nfc_token nfc_interface push_button keypad.
-	 */
-	char *config_methods;
-
-	/**
-	 * os_version - OS Version (WPS)
-	 * 4-octet operating system version number
-	 */
-	u8 os_version[4];
-
-	/**
-	 * country - Country code
-	 *
-	 * This is the ISO/IEC alpha2 country code for which we are operating
-	 * in
-	 */
-	char country[2];
-
-	/**
-	 * wps_cred_processing - Credential processing
-	 *
-	 *   0 = process received credentials internally
-	 *   1 = do not process received credentials; just pass them over
-	 *	ctrl_iface to external program(s)
-	 *   2 = process received credentials internally and pass them over
-	 *	ctrl_iface to external program(s)
-	 */
-	int wps_cred_processing;
-
-	/**
-	 * bss_max_count - Maximum number of BSS entries to keep in memory
-	 */
-	unsigned int bss_max_count;
-
-	/**
-	 * filter_ssids - SSID-based scan result filtering
-	 *
-	 *   0 = do not filter scan results
-	 *   1 = only include configured SSIDs in scan results/BSS table
-	 */
-	int filter_ssids;
-};
-
-
-/* Prototypes for common functions from config.c */
-
-void wpa_config_free(struct wpa_config *ssid);
-void wpa_config_free_ssid(struct wpa_ssid *ssid);
-struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
-struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
-int wpa_config_remove_network(struct wpa_config *config, int id);
-void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
-int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
-		   int line);
-char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
-char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
-char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
-void wpa_config_update_psk(struct wpa_ssid *ssid);
-int wpa_config_add_prio_network(struct wpa_config *config,
-				struct wpa_ssid *ssid);
-int wpa_config_update_prio_list(struct wpa_config *config);
-const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
-						   const char *name);
-void wpa_config_set_blob(struct wpa_config *config,
-			 struct wpa_config_blob *blob);
-void wpa_config_free_blob(struct wpa_config_blob *blob);
-int wpa_config_remove_blob(struct wpa_config *config, const char *name);
-
-struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
-					   const char *driver_param);
-#ifndef CONFIG_NO_STDOUT_DEBUG
-void wpa_config_debug_dump_networks(struct wpa_config *config);
-#else /* CONFIG_NO_STDOUT_DEBUG */
-#define wpa_config_debug_dump_networks(c) do { } while (0)
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-/* Prototypes for backend specific functions from the selected config_*.c */
-
-/**
- * wpa_config_read - Read and parse configuration database
- * @name: Name of the configuration (e.g., path and file name for the
- * configuration file)
- * Returns: Pointer to allocated configuration data or %NULL on failure
- *
- * This function reads configuration data, parses its contents, and allocates
- * data structures needed for storing configuration information. The allocated
- * data can be freed with wpa_config_free().
- *
- * Each configuration backend needs to implement this function.
- */
-struct wpa_config * wpa_config_read(const char *name);
-
-/**
- * wpa_config_write - Write or update configuration data
- * @name: Name of the configuration (e.g., path and file name for the
- * configuration file)
- * @config: Configuration data from wpa_config_read()
- * Returns: 0 on success, -1 on failure
- *
- * This function write all configuration data into an external database (e.g.,
- * a text file) in a format that can be read with wpa_config_read(). This can
- * be used to allow wpa_supplicant to update its configuration, e.g., when a
- * new network is added or a password is changed.
- *
- * Each configuration backend needs to implement this function.
- */
-int wpa_config_write(const char *name, struct wpa_config *config);
-
-#endif /* CONFIG_H */

Copied: vendor/wpa/2.0/wpa_supplicant/config.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/config.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,884 @@
+/*
+ * WPA Supplicant / Configuration file structures
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define DEFAULT_EAPOL_VERSION 1
+#ifdef CONFIG_NO_SCAN_PROCESSING
+#define DEFAULT_AP_SCAN 2
+#else /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_AP_SCAN 1
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_FAST_REAUTH 1
+#define DEFAULT_P2P_GO_INTENT 7
+#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
+#define DEFAULT_BSS_MAX_COUNT 200
+#define DEFAULT_BSS_EXPIRATION_AGE 180
+#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
+#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_ACCESS_NETWORK_TYPE 15
+
+#include "config_ssid.h"
+#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
+
+
+struct wpa_cred {
+	/**
+	 * next - Next credential in the list
+	 *
+	 * This pointer can be used to iterate over all credentials. The head
+	 * of this list is stored in the cred field of struct wpa_config.
+	 */
+	struct wpa_cred *next;
+
+	/**
+	 * id - Unique id for the credential
+	 *
+	 * This identifier is used as a unique identifier for each credential
+	 * block when using the control interface. Each credential is allocated
+	 * an id when it is being created, either when reading the
+	 * configuration file or when a new credential is added through the
+	 * control interface.
+	 */
+	int id;
+
+	/**
+	 * priority - Priority group
+	 *
+	 * By default, all networks and credentials get the same priority group
+	 * (0). This field can be used to give higher priority for credentials
+	 * (and similarly in struct wpa_ssid for network blocks) to change the
+	 * Interworking automatic networking selection behavior. The matching
+	 * network (based on either an enabled network block or a credential)
+	 * with the highest priority value will be selected.
+	 */
+	int priority;
+
+	/**
+	 * pcsc - Use PC/SC and SIM/USIM card
+	 */
+	int pcsc;
+
+	/**
+	 * realm - Home Realm for Interworking
+	 */
+	char *realm;
+
+	/**
+	 * username - Username for Interworking network selection
+	 */
+	char *username;
+
+	/**
+	 * password - Password for Interworking network selection
+	 */
+	char *password;
+
+	/**
+	 * ext_password - Whether password is a name for external storage
+	 */
+	int ext_password;
+
+	/**
+	 * ca_cert - CA certificate for Interworking network selection
+	 */
+	char *ca_cert;
+
+	/**
+	 * client_cert - File path to client certificate file (PEM/DER)
+	 *
+	 * This field is used with Interworking networking selection for a case
+	 * where client certificate/private key is used for authentication
+	 * (EAP-TLS). 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 *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.
+	 */
+	char *private_key;
+
+	/**
+	 * private_key_passwd - Password for private key file
+	 */
+	char *private_key_passwd;
+
+	/**
+	 * imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+	 */
+	char *imsi;
+
+	/**
+	 * milenage - Milenage parameters for SIM/USIM simulator in
+	 *	<Ki>:<OPc>:<SQN> format
+	 */
+	char *milenage;
+
+	/**
+	 * domain - Home service provider FQDN
+	 *
+	 * This is used to compare against the Domain Name List to figure out
+	 * whether the AP is operated by the Home SP.
+	 */
+	char *domain;
+
+	/**
+	 * roaming_consortium - Roaming Consortium OI
+	 *
+	 * If roaming_consortium_len is non-zero, this field contains the
+	 * Roaming Consortium OI that can be used to determine which access
+	 * points support authentication with this credential. This is an
+	 * alternative to the use of the realm parameter. When using Roaming
+	 * Consortium to match the network, the EAP parameters need to be
+	 * pre-configured with the credential since the NAI Realm information
+	 * may not be available or fetched.
+	 */
+	u8 roaming_consortium[15];
+
+	/**
+	 * roaming_consortium_len - Length of roaming_consortium
+	 */
+	size_t roaming_consortium_len;
+
+	/**
+	 * eap_method - EAP method to use
+	 *
+	 * Pre-configured EAP method to use with this credential or %NULL to
+	 * indicate no EAP method is selected, i.e., the method will be
+	 * selected automatically based on ANQP information.
+	 */
+	struct eap_method_type *eap_method;
+
+	/**
+	 * phase1 - Phase 1 (outer authentication) parameters
+	 *
+	 * Pre-configured EAP parameters or %NULL.
+	 */
+	char *phase1;
+
+	/**
+	 * phase2 - Phase 2 (inner authentication) parameters
+	 *
+	 * Pre-configured EAP parameters or %NULL.
+	 */
+	char *phase2;
+
+	struct excluded_ssid {
+		u8 ssid[MAX_SSID_LEN];
+		size_t ssid_len;
+	} *excluded_ssid;
+	size_t num_excluded_ssid;
+};
+
+
+#define CFG_CHANGED_DEVICE_NAME BIT(0)
+#define CFG_CHANGED_CONFIG_METHODS BIT(1)
+#define CFG_CHANGED_DEVICE_TYPE BIT(2)
+#define CFG_CHANGED_OS_VERSION BIT(3)
+#define CFG_CHANGED_UUID BIT(4)
+#define CFG_CHANGED_COUNTRY BIT(5)
+#define CFG_CHANGED_SEC_DEVICE_TYPE BIT(6)
+#define CFG_CHANGED_P2P_SSID_POSTFIX BIT(7)
+#define CFG_CHANGED_WPS_STRING BIT(8)
+#define CFG_CHANGED_P2P_INTRA_BSS BIT(9)
+#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
+#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
+#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
+#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+
+/**
+ * struct wpa_config - wpa_supplicant configuration data
+ *
+ * This data structure is presents the per-interface (radio) configuration
+ * data. In many cases, there is only one struct wpa_config instance, but if
+ * more than one network interface is being controlled, one instance is used
+ * for each.
+ */
+struct wpa_config {
+	/**
+	 * ssid - Head of the global network list
+	 *
+	 * This is the head for the list of all the configured networks.
+	 */
+	struct wpa_ssid *ssid;
+
+	/**
+	 * pssid - Per-priority network lists (in priority order)
+	 */
+	struct wpa_ssid **pssid;
+
+	/**
+	 * num_prio - Number of different priorities used in the pssid lists
+	 *
+	 * This indicates how many per-priority network lists are included in
+	 * pssid.
+	 */
+	int num_prio;
+
+	/**
+	 * cred - Head of the credential list
+	 *
+	 * This is the head for the list of all the configured credentials.
+	 */
+	struct wpa_cred *cred;
+
+	/**
+	 * eapol_version - IEEE 802.1X/EAPOL version number
+	 *
+	 * wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
+	 * defines EAPOL version 2. However, there are many APs that do not
+	 * handle the new version number correctly (they seem to drop the
+	 * frames completely). In order to make wpa_supplicant interoperate
+	 * with these APs, the version number is set to 1 by default. This
+	 * configuration value can be used to set it to the new version (2).
+	 */
+	int eapol_version;
+
+	/**
+	 * ap_scan - AP scanning/selection
+	 *
+	 * By default, wpa_supplicant requests driver to perform AP
+	 * scanning and then uses the scan results to select a
+	 * suitable AP. Another alternative is to allow the driver to
+	 * take care of AP scanning and selection and use
+	 * wpa_supplicant just to process EAPOL frames based on IEEE
+	 * 802.11 association information from the driver.
+	 *
+	 * 1: wpa_supplicant initiates scanning and AP selection (default).
+	 *
+	 * 0: Driver takes care of scanning, AP selection, and IEEE 802.11
+	 * association parameters (e.g., WPA IE generation); this mode can
+	 * also be used with non-WPA drivers when using IEEE 802.1X mode;
+	 * do not try to associate with APs (i.e., external program needs
+	 * to control association). This mode must also be used when using
+	 * wired Ethernet drivers.
+	 *
+	 * 2: like 0, but associate with APs using security policy and SSID
+	 * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS
+	 * drivers to enable operation with hidden SSIDs and optimized roaming;
+	 * in this mode, the network blocks in the configuration are tried
+	 * one by one until the driver reports successful association; each
+	 * network block should have explicit security policy (i.e., only one
+	 * option in the lists) for key_mgmt, pairwise, group, proto variables.
+	 */
+	int ap_scan;
+
+	/**
+	 * disable_scan_offload - Disable automatic offloading of scan requests
+	 *
+	 * By default, %wpa_supplicant tries to offload scanning if the driver
+	 * indicates support for this (sched_scan). This configuration
+	 * parameter can be used to disable this offloading mechanism.
+	 */
+	int disable_scan_offload;
+
+	/**
+	 * ctrl_interface - Parameters for the control interface
+	 *
+	 * If this is specified, %wpa_supplicant will open a control interface
+	 * that is available for external programs to manage %wpa_supplicant.
+	 * The meaning of this string depends on which control interface
+	 * mechanism is used. For all cases, the existence of this parameter
+	 * in configuration is used to determine whether the control interface
+	 * is enabled.
+	 *
+	 * For UNIX domain sockets (default on Linux and BSD): This is a
+	 * directory that will be created for UNIX domain sockets for listening
+	 * to requests from external programs (CLI/GUI, etc.) for status
+	 * information and configuration. The socket file will be named based
+	 * on the interface name, so multiple %wpa_supplicant processes can be
+	 * run at the same time if more than one interface is used.
+	 * /var/run/wpa_supplicant is the recommended directory for sockets and
+	 * by default, wpa_cli will use it when trying to connect with
+	 * %wpa_supplicant.
+	 *
+	 * Access control for the control interface can be configured
+	 * by setting the directory to allow only members of a group
+	 * to use sockets. This way, it is possible to run
+	 * %wpa_supplicant as root (since it needs to change network
+	 * configuration and open raw sockets) and still allow GUI/CLI
+	 * components to be run as non-root users. However, since the
+	 * control interface can be used to change the network
+	 * configuration, this access needs to be protected in many
+	 * cases. By default, %wpa_supplicant is configured to use gid
+	 * 0 (root). If you want to allow non-root users to use the
+	 * control interface, add a new group and change this value to
+	 * match with that group. Add users that should have control
+	 * interface access to this group.
+	 *
+	 * When configuring both the directory and group, use following format:
+	 * DIR=/var/run/wpa_supplicant GROUP=wheel
+	 * DIR=/var/run/wpa_supplicant GROUP=0
+	 * (group can be either group name or gid)
+	 *
+	 * For UDP connections (default on Windows): The value will be ignored.
+	 * This variable is just used to select that the control interface is
+	 * to be created. The value can be set to, e.g., udp
+	 * (ctrl_interface=udp).
+	 *
+	 * For Windows Named Pipe: This value can be used to set the security
+	 * descriptor for controlling access to the control interface. Security
+	 * descriptor can be set using Security Descriptor String Format (see
+	 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp).
+	 * The descriptor string needs to be prefixed with SDDL=. For example,
+	 * ctrl_interface=SDDL=D: would set an empty DACL (which will reject
+	 * all connections).
+	 */
+	char *ctrl_interface;
+
+	/**
+	 * ctrl_interface_group - Control interface group (DEPRECATED)
+	 *
+	 * This variable is only used for backwards compatibility. Group for
+	 * UNIX domain sockets should now be specified using GROUP=group in
+	 * ctrl_interface variable.
+	 */
+	char *ctrl_interface_group;
+
+	/**
+	 * fast_reauth - EAP fast re-authentication (session resumption)
+	 *
+	 * By default, fast re-authentication is enabled for all EAP methods
+	 * that support it. This variable can be used to disable fast
+	 * re-authentication (by setting fast_reauth=0). Normally, there is no
+	 * need to disable fast re-authentication.
+	 */
+	int fast_reauth;
+
+	/**
+	 * opensc_engine_path - Path to the OpenSSL engine for opensc
+	 *
+	 * This is an OpenSSL specific configuration option for loading OpenSC
+	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+	 */
+	char *opensc_engine_path;
+
+	/**
+	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+	 *
+	 * This is an OpenSSL specific configuration option for loading PKCS#11
+	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+	 */
+	char *pkcs11_engine_path;
+
+	/**
+	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+	 *
+	 * This is an OpenSSL specific configuration option for configuring
+	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+	 * module is not loaded.
+	 */
+	char *pkcs11_module_path;
+
+	/**
+	 * pcsc_reader - PC/SC reader name prefix
+	 *
+	 * If not %NULL, PC/SC reader with a name that matches this prefix is
+	 * initialized for SIM/USIM access. Empty string can be used to match
+	 * the first available reader.
+	 */
+	char *pcsc_reader;
+
+	/**
+	 * pcsc_pin - PIN for USIM, GSM SIM, and smartcards
+	 *
+	 * This field is used to configure PIN for SIM/USIM for EAP-SIM and
+	 * EAP-AKA. If left out, this will be asked through control interface.
+	 */
+	char *pcsc_pin;
+
+	/**
+	 * driver_param - Driver interface parameters
+	 *
+	 * This text string is passed to the selected driver interface with the
+	 * optional struct wpa_driver_ops::set_param() handler. This can be
+	 * used to configure driver specific options without having to add new
+	 * driver interface functionality.
+	 */
+	char *driver_param;
+
+	/**
+	 * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK
+	 *
+	 * dot11 MIB variable for the maximum lifetime of a PMK in the PMK
+	 * cache (unit: seconds).
+	 */
+	unsigned int dot11RSNAConfigPMKLifetime;
+
+	/**
+	 * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold
+	 *
+	 * dot11 MIB variable for the percentage of the PMK lifetime
+	 * that should expire before an IEEE 802.1X reauthentication occurs.
+	 */
+	unsigned int dot11RSNAConfigPMKReauthThreshold;
+
+	/**
+	 * dot11RSNAConfigSATimeout - Security association timeout
+	 *
+	 * dot11 MIB variable for the maximum time a security association
+	 * shall take to set up (unit: seconds).
+	 */
+	unsigned int dot11RSNAConfigSATimeout;
+
+	/**
+	 * update_config - Is wpa_supplicant allowed to update configuration
+	 *
+	 * This variable control whether wpa_supplicant is allow to re-write
+	 * its configuration with wpa_config_write(). If this is zero,
+	 * configuration data is only changed in memory and the external data
+	 * is not overriden. If this is non-zero, wpa_supplicant will update
+	 * the configuration data (e.g., a file) whenever configuration is
+	 * changed. This update may replace the old configuration which can
+	 * remove comments from it in case of a text file configuration.
+	 */
+	int update_config;
+
+	/**
+	 * blobs - Configuration blobs
+	 */
+	struct wpa_config_blob *blobs;
+
+	/**
+	 * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS
+	 */
+	u8 uuid[16];
+
+	/**
+	 * device_name - Device Name (WPS)
+	 * User-friendly description of device; up to 32 octets encoded in
+	 * UTF-8
+	 */
+	char *device_name;
+
+	/**
+	 * manufacturer - Manufacturer (WPS)
+	 * The manufacturer of the device (up to 64 ASCII characters)
+	 */
+	char *manufacturer;
+
+	/**
+	 * model_name - Model Name (WPS)
+	 * Model of the device (up to 32 ASCII characters)
+	 */
+	char *model_name;
+
+	/**
+	 * model_number - Model Number (WPS)
+	 * Additional device description (up to 32 ASCII characters)
+	 */
+	char *model_number;
+
+	/**
+	 * serial_number - Serial Number (WPS)
+	 * Serial number of the device (up to 32 characters)
+	 */
+	char *serial_number;
+
+	/**
+	 * device_type - Primary Device Type (WPS)
+	 */
+	u8 device_type[WPS_DEV_TYPE_LEN];
+
+	/**
+	 * config_methods - Config Methods
+	 *
+	 * This is a space-separated list of supported WPS configuration
+	 * methods. For example, "label virtual_display virtual_push_button
+	 * keypad".
+	 * Available methods: usba ethernet label display ext_nfc_token
+	 * int_nfc_token nfc_interface push_button keypad
+	 * virtual_display physical_display
+	 * virtual_push_button physical_push_button.
+	 */
+	char *config_methods;
+
+	/**
+	 * os_version - OS Version (WPS)
+	 * 4-octet operating system version number
+	 */
+	u8 os_version[4];
+
+	/**
+	 * country - Country code
+	 *
+	 * This is the ISO/IEC alpha2 country code for which we are operating
+	 * in
+	 */
+	char country[2];
+
+	/**
+	 * wps_cred_processing - Credential processing
+	 *
+	 *   0 = process received credentials internally
+	 *   1 = do not process received credentials; just pass them over
+	 *	ctrl_iface to external program(s)
+	 *   2 = process received credentials internally and pass them over
+	 *	ctrl_iface to external program(s)
+	 */
+	int wps_cred_processing;
+
+#define MAX_SEC_DEVICE_TYPES 5
+	/**
+	 * sec_device_types - Secondary Device Types (P2P)
+	 */
+	u8 sec_device_type[MAX_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+	int num_sec_device_types;
+
+	int p2p_listen_reg_class;
+	int p2p_listen_channel;
+	int p2p_oper_reg_class;
+	int p2p_oper_channel;
+	int p2p_go_intent;
+	char *p2p_ssid_postfix;
+	int persistent_reconnect;
+	int p2p_intra_bss;
+	unsigned int num_p2p_pref_chan;
+	struct p2p_channel *p2p_pref_chan;
+
+	struct wpabuf *wps_vendor_ext_m1;
+
+#define MAX_WPS_VENDOR_EXT 10
+	/**
+	 * wps_vendor_ext - Vendor extension attributes in WPS
+	 */
+	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXT];
+
+	/**
+	 * p2p_group_idle - Maximum idle time in seconds for P2P group
+	 *
+	 * This value controls how long a P2P group is maintained after there
+	 * is no other members in the group. As a GO, this means no associated
+	 * stations in the group. As a P2P client, this means no GO seen in
+	 * scan results. The maximum idle time is specified in seconds with 0
+	 * indicating no time limit, i.e., the P2P group remains in active
+	 * state indefinitely until explicitly removed. As a P2P client, the
+	 * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
+	 * this parameter is mainly meant for GO use and for P2P client, it can
+	 * only be used to reduce the default timeout to smaller value. A
+	 * special value -1 can be used to configure immediate removal of the
+	 * group for P2P client role on any disconnection after the data
+	 * connection has been established.
+	 */
+	int p2p_group_idle;
+
+	/**
+	 * bss_max_count - Maximum number of BSS entries to keep in memory
+	 */
+	unsigned int bss_max_count;
+
+	/**
+	 * bss_expiration_age - BSS entry age after which it can be expired
+	 *
+	 * This value controls the time in seconds after which a BSS entry
+	 * gets removed if it has not been updated or is not in use.
+	 */
+	unsigned int bss_expiration_age;
+
+	/**
+	 * bss_expiration_scan_count - Expire BSS after number of scans
+	 *
+	 * If the BSS entry has not been seen in this many scans, it will be
+	 * removed. A value of 1 means that entry is removed after the first
+	 * scan in which the BSSID is not seen. Larger values can be used
+	 * to avoid BSS entries disappearing if they are not visible in
+	 * every scan (e.g., low signal quality or interference).
+	 */
+	unsigned int bss_expiration_scan_count;
+
+	/**
+	 * filter_ssids - SSID-based scan result filtering
+	 *
+	 *   0 = do not filter scan results
+	 *   1 = only include configured SSIDs in scan results/BSS table
+	 */
+	int filter_ssids;
+
+	/**
+	 * filter_rssi - RSSI-based scan result filtering
+	 *
+	 * 0 = do not filter scan results
+	 * -n = filter scan results below -n dBm
+	 */
+	int filter_rssi;
+
+	/**
+	 * max_num_sta - Maximum number of STAs in an AP/P2P GO
+	 */
+	unsigned int max_num_sta;
+
+	/**
+	 * changed_parameters - Bitmap of changed parameters since last update
+	 */
+	unsigned int changed_parameters;
+
+	/**
+	 * disassoc_low_ack - Disassocicate stations with massive packet loss
+	 */
+	int disassoc_low_ack;
+
+	/**
+	 * interworking - Whether Interworking (IEEE 802.11u) is enabled
+	 */
+	int interworking;
+
+	/**
+	 * access_network_type - Access Network Type
+	 *
+	 * When Interworking is enabled, scans will be limited to APs that
+	 * advertise the specified Access Network Type (0..15; with 15
+	 * indicating wildcard match).
+	 */
+	int access_network_type;
+
+	/**
+	 * hessid - Homogenous ESS identifier
+	 *
+	 * If this is set (any octet is non-zero), scans will be used to
+	 * request response only from BSSes belonging to the specified
+	 * Homogeneous ESS. This is used only if interworking is enabled.
+	 */
+	u8 hessid[ETH_ALEN];
+
+	/**
+	 * hs20 - Hotspot 2.0
+	 */
+	int hs20;
+
+	/**
+	 * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7
+	 *
+	 * Windows 7 uses incorrect way of figuring out AP's WPS capabilities
+	 * by acting as a Registrar and using M1 from the AP. The config
+	 * methods attribute in that message is supposed to indicate only the
+	 * configuration method supported by the AP in Enrollee role, i.e., to
+	 * add an external Registrar. For that case, PBC shall not be used and
+	 * as such, the PushButton config method is removed from M1 by default.
+	 * If pbc_in_m1=1 is included in the configuration file, the PushButton
+	 * config method is left in M1 (if included in config_methods
+	 * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from
+	 * a label in the AP).
+	 */
+	int pbc_in_m1;
+
+	/**
+	 * autoscan - Automatic scan parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for automatic scanning
+	 * within an interface in following format:
+	 * <autoscan module name>:<module parameters>
+	 */
+	char *autoscan;
+
+	/**
+	 * wps_nfc_dev_pw_id - NFC Device Password ID for password token
+	 */
+	int wps_nfc_dev_pw_id;
+
+	/**
+	 * wps_nfc_dh_pubkey - NFC DH Public Key for password token
+	 */
+	struct wpabuf *wps_nfc_dh_pubkey;
+
+	/**
+	 * wps_nfc_dh_privkey - NFC DH Private Key for password token
+	 */
+	struct wpabuf *wps_nfc_dh_privkey;
+
+	/**
+	 * wps_nfc_dev_pw - NFC Device Password for password token
+	 */
+	struct wpabuf *wps_nfc_dev_pw;
+
+	/**
+	 * ext_password_backend - External password backend or %NULL if none
+	 *
+	 * format: <backend name>[:<optional backend parameters>]
+	 */
+	char *ext_password_backend;
+
+	/*
+	 * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+	 *
+	 * This timeout value is used in P2P GO mode to clean up
+	 * inactive stations.
+	 * By default: 300 seconds.
+	 */
+	int p2p_go_max_inactivity;
+
+	struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+	/**
+	 * auto_interworking - Whether to use network selection automatically
+	 *
+	 * 0 = do not automatically go through Interworking network selection
+	 *     (i.e., require explicit interworking_select command for this)
+	 * 1 = perform Interworking network selection if one or more
+	 *     credentials have been configured and scan did not find a
+	 *     matching network block
+	 */
+	int auto_interworking;
+
+	/**
+	 * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_ht40;
+
+	/**
+	 * p2p_disabled - Whether P2P operations are disabled for this interface
+	 */
+	int p2p_disabled;
+
+	/**
+	 * p2p_no_group_iface - Whether group interfaces can be used
+	 *
+	 * By default, wpa_supplicant will create a separate interface for P2P
+	 * group operations if the driver supports this. This functionality can
+	 * be disabled by setting this parameter to 1. In that case, the same
+	 * interface that was used for the P2P management operations is used
+	 * also for the group operation.
+	 */
+	int p2p_no_group_iface;
+
+	/**
+	 * okc - Whether to enable opportunistic key caching by default
+	 *
+	 * By default, OKC is disabled unless enabled by the per-network
+	 * proactive_key_caching=1 parameter. okc=1 can be used to change this
+	 * default behavior.
+	 */
+	int okc;
+
+	/**
+	 * pmf - Whether to enable/require PMF by default
+	 *
+	 * 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.
+	 */
+	enum mfp_options pmf;
+};
+
+
+/* Prototypes for common functions from config.c */
+
+void wpa_config_free(struct wpa_config *ssid);
+void wpa_config_free_ssid(struct wpa_ssid *ssid);
+void wpa_config_foreach_network(struct wpa_config *config,
+				void (*func)(void *, struct wpa_ssid *),
+				void *arg);
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
+int wpa_config_remove_network(struct wpa_config *config, int id);
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+		   int line);
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value);
+char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
+char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
+void wpa_config_update_psk(struct wpa_ssid *ssid);
+int wpa_config_add_prio_network(struct wpa_config *config,
+				struct wpa_ssid *ssid);
+int wpa_config_update_prio_list(struct wpa_config *config);
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+						   const char *name);
+void wpa_config_set_blob(struct wpa_config *config,
+			 struct wpa_config_blob *blob);
+void wpa_config_free_blob(struct wpa_config_blob *blob);
+int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
+int wpa_config_remove_cred(struct wpa_config *config, int id);
+void wpa_config_free_cred(struct wpa_cred *cred);
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+			const char *value, int line);
+
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+					   const char *driver_param);
+#ifndef CONFIG_NO_STDOUT_DEBUG
+void wpa_config_debug_dump_networks(struct wpa_config *config);
+#else /* CONFIG_NO_STDOUT_DEBUG */
+#define wpa_config_debug_dump_networks(c) do { } while (0)
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+/* Prototypes for common functions from config.c */
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+
+
+/* Prototypes for backend specific functions from the selected config_*.c */
+
+/**
+ * wpa_config_read - Read and parse configuration database
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ *
+ * This function reads configuration data, parses its contents, and allocates
+ * data structures needed for storing configuration information. The allocated
+ * data can be freed with wpa_config_free().
+ *
+ * Each configuration backend needs to implement this function.
+ */
+struct wpa_config * wpa_config_read(const char *name);
+
+/**
+ * wpa_config_write - Write or update configuration data
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function write all configuration data into an external database (e.g.,
+ * a text file) in a format that can be read with wpa_config_read(). This can
+ * be used to allow wpa_supplicant to update its configuration, e.g., when a
+ * new network is added or a password is changed.
+ *
+ * Each configuration backend needs to implement this function.
+ */
+int wpa_config_write(const char *name, struct wpa_config *config);
+
+#endif /* CONFIG_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/config_file.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config_file.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config_file.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,947 +0,0 @@
-/*
- * WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements a configuration backend for text files. All the
- * configuration information is stored in a text file that uses a format
- * described in the sample configuration file, wpa_supplicant.conf.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "config.h"
-#include "base64.h"
-#include "uuid.h"
-#include "eap_peer/eap_methods.h"
-
-
-/**
- * wpa_config_get_line - Read the next configuration file line
- * @s: Buffer for the line
- * @size: The buffer length
- * @stream: File stream to read from
- * @line: Pointer to a variable storing the file line number
- * @_pos: Buffer for the pointer to the beginning of data on the text line or
- * %NULL if not needed (returned value used instead)
- * Returns: Pointer to the beginning of data on the text line or %NULL if no
- * more text lines are available.
- *
- * This function reads the next non-empty line from the configuration file and
- * removes comments. The returned string is guaranteed to be null-terminated.
- */
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
-				  char **_pos)
-{
-	char *pos, *end, *sstart;
-
-	while (fgets(s, size, stream)) {
-		(*line)++;
-		s[size - 1] = '\0';
-		pos = s;
-
-		/* Skip white space from the beginning of line. */
-		while (*pos == ' ' || *pos == '\t' || *pos == '\r')
-			pos++;
-
-		/* Skip comment lines and empty lines */
-		if (*pos == '#' || *pos == '\n' || *pos == '\0')
-			continue;
-
-		/*
-		 * Remove # comments unless they are within a double quoted
-		 * string.
-		 */
-		sstart = os_strchr(pos, '"');
-		if (sstart)
-			sstart = os_strrchr(sstart + 1, '"');
-		if (!sstart)
-			sstart = pos;
-		end = os_strchr(sstart, '#');
-		if (end)
-			*end-- = '\0';
-		else
-			end = pos + os_strlen(pos) - 1;
-
-		/* Remove trailing white space. */
-		while (end > pos &&
-		       (*end == '\n' || *end == ' ' || *end == '\t' ||
-			*end == '\r'))
-			*end-- = '\0';
-
-		if (*pos == '\0')
-			continue;
-
-		if (_pos)
-			*_pos = pos;
-		return pos;
-	}
-
-	if (_pos)
-		*_pos = NULL;
-	return NULL;
-}
-
-
-static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
-{
-	int errors = 0;
-
-	if (ssid->passphrase) {
-		if (ssid->psk_set) {
-			wpa_printf(MSG_ERROR, "Line %d: both PSK and "
-				   "passphrase configured.", line);
-			errors++;
-		}
-		wpa_config_update_psk(ssid);
-	}
-
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_PSK_SHA256)) &&
-	    !ssid->psk_set) {
-		wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
-			   "management, but no PSK configured.", line);
-		errors++;
-	}
-
-	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
-		/* Group cipher cannot be stronger than the pairwise cipher. */
-		wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
-			   " list since it was not allowed for pairwise "
-			   "cipher", line);
-		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
-	}
-
-	return errors;
-}
-
-
-static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
-{
-	struct wpa_ssid *ssid;
-	int errors = 0, end = 0;
-	char buf[256], *pos, *pos2;
-
-	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
-		   *line);
-	ssid = os_zalloc(sizeof(*ssid));
-	if (ssid == NULL)
-		return NULL;
-	ssid->id = id;
-
-	wpa_config_set_network_defaults(ssid);
-
-	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
-		if (os_strcmp(pos, "}") == 0) {
-			end = 1;
-			break;
-		}
-
-		pos2 = os_strchr(pos, '=');
-		if (pos2 == NULL) {
-			wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
-				   "'%s'.", *line, pos);
-			errors++;
-			continue;
-		}
-
-		*pos2++ = '\0';
-		if (*pos2 == '"') {
-			if (os_strchr(pos2 + 1, '"') == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: invalid "
-					   "quotation '%s'.", *line, pos2);
-				errors++;
-				continue;
-			}
-		}
-
-		if (wpa_config_set(ssid, pos, pos2, *line) < 0)
-			errors++;
-	}
-
-	if (!end) {
-		wpa_printf(MSG_ERROR, "Line %d: network block was not "
-			   "terminated properly.", *line);
-		errors++;
-	}
-
-	errors += wpa_config_validate_network(ssid, *line);
-
-	if (errors) {
-		wpa_config_free_ssid(ssid);
-		ssid = NULL;
-	}
-
-	return ssid;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
-						     const char *name)
-{
-	struct wpa_config_blob *blob;
-	char buf[256], *pos;
-	unsigned char *encoded = NULL, *nencoded;
-	int end = 0;
-	size_t encoded_len = 0, len;
-
-	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
-		   *line, name);
-
-	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
-		if (os_strcmp(pos, "}") == 0) {
-			end = 1;
-			break;
-		}
-
-		len = os_strlen(pos);
-		nencoded = os_realloc(encoded, encoded_len + len);
-		if (nencoded == NULL) {
-			wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
-				   "blob", *line);
-			os_free(encoded);
-			return NULL;
-		}
-		encoded = nencoded;
-		os_memcpy(encoded + encoded_len, pos, len);
-		encoded_len += len;
-	}
-
-	if (!end) {
-		wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
-			   "properly", *line);
-		os_free(encoded);
-		return NULL;
-	}
-
-	blob = os_zalloc(sizeof(*blob));
-	if (blob == NULL) {
-		os_free(encoded);
-		return NULL;
-	}
-	blob->name = os_strdup(name);
-	blob->data = base64_decode(encoded, encoded_len, &blob->len);
-	os_free(encoded);
-
-	if (blob->name == NULL || blob->data == NULL) {
-		wpa_config_free_blob(blob);
-		return NULL;
-	}
-
-	return blob;
-}
-
-
-static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
-				   int *line, char *bname)
-{
-	char *name_end;
-	struct wpa_config_blob *blob;
-
-	name_end = os_strchr(bname, '=');
-	if (name_end == NULL) {
-		wpa_printf(MSG_ERROR, "Line %d: no blob name terminator",
-			   *line);
-		return -1;
-	}
-	*name_end = '\0';
-
-	blob = wpa_config_read_blob(f, line, bname);
-	if (blob == NULL) {
-		wpa_printf(MSG_ERROR, "Line %d: failed to read blob %s",
-			   *line, bname);
-		return -1;
-	}
-	wpa_config_set_blob(config, blob);
-	return 0;
-}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-struct global_parse_data {
-	char *name;
-	int (*parser)(const struct global_parse_data *data,
-		      struct wpa_config *config, int line, const char *value);
-	void *param1, *param2, *param3;
-};
-
-
-static int wpa_config_parse_int(const struct global_parse_data *data,
-				struct wpa_config *config, int line,
-				const char *pos)
-{
-	int *dst;
-	dst = (int *) (((u8 *) config) + (long) data->param1);
-	*dst = atoi(pos);
-	wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
-
-	if (data->param2 && *dst < (long) data->param2) {
-		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
-			   "min_value=%ld)", line, data->name, *dst,
-			   (long) data->param2);
-		*dst = (long) data->param2;
-		return -1;
-	}
-
-	if (data->param3 && *dst > (long) data->param3) {
-		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
-			   "max_value=%ld)", line, data->name, *dst,
-			   (long) data->param3);
-		*dst = (long) data->param3;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_config_parse_str(const struct global_parse_data *data,
-				struct wpa_config *config, int line,
-				const char *pos)
-{
-	size_t len;
-	char **dst, *tmp;
-
-	len = os_strlen(pos);
-	if (data->param2 && len < (size_t) data->param2) {
-		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
-			   "min_len=%ld)", line, data->name,
-			   (unsigned long) len, (long) data->param2);
-		return -1;
-	}
-
-	if (data->param3 && len > (size_t) data->param3) {
-		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
-			   "max_len=%ld)", line, data->name,
-			   (unsigned long) len, (long) data->param3);
-		return -1;
-	}
-
-	tmp = os_strdup(pos);
-	if (tmp == NULL)
-		return -1;
-
-	dst = (char **) (((u8 *) config) + (long) data->param1);
-	os_free(*dst);
-	*dst = tmp;
-	wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
-
-	return 0;
-}
-
-
-static int wpa_config_process_country(const struct global_parse_data *data,
-				      struct wpa_config *config, int line,
-				      const char *pos)
-{
-	if (!pos[0] || !pos[1]) {
-		wpa_printf(MSG_DEBUG, "Invalid country set");
-		return -1;
-	}
-	config->country[0] = pos[0];
-	config->country[1] = pos[1];
-	wpa_printf(MSG_DEBUG, "country='%c%c'",
-		   config->country[0], config->country[1]);
-	return 0;
-}
-
-
-static int wpa_config_process_load_dynamic_eap(
-	const struct global_parse_data *data, struct wpa_config *config,
-	int line, const char *so)
-{
-	int ret;
-	wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
-	ret = eap_peer_method_load(so);
-	if (ret == -2) {
-		wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
-			   "reloading.");
-	} else if (ret) {
-		wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
-			   "method '%s'.", line, so);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS
-
-static int wpa_config_process_uuid(const struct global_parse_data *data,
-				   struct wpa_config *config, int line,
-				   const char *pos)
-{
-	char buf[40];
-	if (uuid_str2bin(pos, config->uuid)) {
-		wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
-		return -1;
-	}
-	uuid_bin2str(config->uuid, buf, sizeof(buf));
-	wpa_printf(MSG_DEBUG, "uuid=%s", buf);
-	return 0;
-}
-
-
-static int wpa_config_process_os_version(const struct global_parse_data *data,
-					 struct wpa_config *config, int line,
-					 const char *pos)
-{
-	if (hexstr2bin(pos, config->os_version, 4)) {
-		wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "os_version=%08x",
-		   WPA_GET_BE32(config->os_version));
-	return 0;
-}
-
-#endif /* CONFIG_WPS */
-
-
-#ifdef OFFSET
-#undef OFFSET
-#endif /* OFFSET */
-/* OFFSET: Get offset of a variable within the wpa_config structure */
-#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
-
-#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
-#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
-#define _INT(f) #f, wpa_config_parse_int, OFFSET(f)
-#define INT(f) _INT(f), NULL, NULL
-#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
-#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
-#define STR(f) _STR(f), NULL, NULL
-#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
-
-static const struct global_parse_data global_fields[] = {
-#ifdef CONFIG_CTRL_IFACE
-	{ STR(ctrl_interface) },
-	{ STR(ctrl_interface_group) } /* deprecated */,
-#endif /* CONFIG_CTRL_IFACE */
-	{ INT_RANGE(eapol_version, 1, 2) },
-	{ INT(ap_scan) },
-	{ INT(fast_reauth) },
-	{ STR(opensc_engine_path) },
-	{ STR(pkcs11_engine_path) },
-	{ STR(pkcs11_module_path) },
-	{ STR(driver_param) },
-	{ INT(dot11RSNAConfigPMKLifetime) },
-	{ INT(dot11RSNAConfigPMKReauthThreshold) },
-	{ INT(dot11RSNAConfigSATimeout) },
-#ifndef CONFIG_NO_CONFIG_WRITE
-	{ INT(update_config) },
-#endif /* CONFIG_NO_CONFIG_WRITE */
-	{ FUNC_NO_VAR(load_dynamic_eap) },
-#ifdef CONFIG_WPS
-	{ FUNC(uuid) },
-	{ STR_RANGE(device_name, 0, 32) },
-	{ STR_RANGE(manufacturer, 0, 64) },
-	{ STR_RANGE(model_name, 0, 32) },
-	{ STR_RANGE(model_number, 0, 32) },
-	{ STR_RANGE(serial_number, 0, 32) },
-	{ STR(device_type) },
-	{ FUNC(os_version) },
-	{ STR(config_methods) },
-	{ INT_RANGE(wps_cred_processing, 0, 2) },
-#endif /* CONFIG_WPS */
-	{ FUNC(country) },
-	{ INT(bss_max_count) },
-	{ INT_RANGE(filter_ssids, 0, 1) }
-};
-
-#undef FUNC
-#undef _INT
-#undef INT
-#undef INT_RANGE
-#undef _STR
-#undef STR
-#undef STR_RANGE
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
-
-
-static int wpa_config_process_global(struct wpa_config *config, char *pos,
-				     int line)
-{
-	size_t i;
-	int ret = 0;
-
-	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
-		const struct global_parse_data *field = &global_fields[i];
-		size_t flen = os_strlen(field->name);
-		if (os_strncmp(pos, field->name, flen) != 0 ||
-		    pos[flen] != '=')
-			continue;
-
-		if (field->parser(field, config, line, pos + flen + 1)) {
-			wpa_printf(MSG_ERROR, "Line %d: failed to "
-				   "parse '%s'.", line, pos);
-			ret = -1;
-		}
-		break;
-	}
-	if (i == NUM_GLOBAL_FIELDS) {
-		wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
-			   line, pos);
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-struct wpa_config * wpa_config_read(const char *name)
-{
-	FILE *f;
-	char buf[256], *pos;
-	int errors = 0, line = 0;
-	struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
-	struct wpa_config *config;
-	int id = 0;
-
-	config = wpa_config_alloc_empty(NULL, NULL);
-	if (config == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
-	f = fopen(name, "r");
-	if (f == NULL) {
-		os_free(config);
-		return NULL;
-	}
-
-	while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
-		if (os_strcmp(pos, "network={") == 0) {
-			ssid = wpa_config_read_network(f, &line, id++);
-			if (ssid == NULL) {
-				wpa_printf(MSG_ERROR, "Line %d: failed to "
-					   "parse network block.", line);
-				errors++;
-				continue;
-			}
-			if (head == NULL) {
-				head = tail = ssid;
-			} else {
-				tail->next = ssid;
-				tail = ssid;
-			}
-			if (wpa_config_add_prio_network(config, ssid)) {
-				wpa_printf(MSG_ERROR, "Line %d: failed to add "
-					   "network block to priority list.",
-					   line);
-				errors++;
-				continue;
-			}
-#ifndef CONFIG_NO_CONFIG_BLOBS
-		} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
-			if (wpa_config_process_blob(config, f, &line, pos + 12)
-			    < 0) {
-				errors++;
-				continue;
-			}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-		} else if (wpa_config_process_global(config, pos, line) < 0) {
-			wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
-				   "line '%s'.", line, pos);
-			errors++;
-			continue;
-		}
-	}
-
-	fclose(f);
-
-	config->ssid = head;
-	wpa_config_debug_dump_networks(config);
-
-	if (errors) {
-		wpa_config_free(config);
-		config = NULL;
-		head = NULL;
-	}
-
-	return config;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_WRITE
-
-static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, field);
-	if (value == NULL)
-		return;
-	fprintf(f, "\t%s=%s\n", field, value);
-	os_free(value);
-}
-
-
-static void write_int(FILE *f, const char *field, int value, int def)
-{
-	if (value == def)
-		return;
-	fprintf(f, "\t%s=%d\n", field, value);
-}
-
-
-static void write_bssid(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, "bssid");
-	if (value == NULL)
-		return;
-	fprintf(f, "\tbssid=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_psk(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, "psk");
-	if (value == NULL)
-		return;
-	fprintf(f, "\tpsk=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_proto(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->proto == DEFAULT_PROTO)
-		return;
-
-	value = wpa_config_get(ssid, "proto");
-	if (value == NULL)
-		return;
-	if (value[0])
-		fprintf(f, "\tproto=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
-		return;
-
-	value = wpa_config_get(ssid, "key_mgmt");
-	if (value == NULL)
-		return;
-	if (value[0])
-		fprintf(f, "\tkey_mgmt=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
-		return;
-
-	value = wpa_config_get(ssid, "pairwise");
-	if (value == NULL)
-		return;
-	if (value[0])
-		fprintf(f, "\tpairwise=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_group(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->group_cipher == DEFAULT_GROUP)
-		return;
-
-	value = wpa_config_get(ssid, "group");
-	if (value == NULL)
-		return;
-	if (value[0])
-		fprintf(f, "\tgroup=%s\n", value);
-	os_free(value);
-}
-
-
-static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->auth_alg == 0)
-		return;
-
-	value = wpa_config_get(ssid, "auth_alg");
-	if (value == NULL)
-		return;
-	if (value[0])
-		fprintf(f, "\tauth_alg=%s\n", value);
-	os_free(value);
-}
-
-
-#ifdef IEEE8021X_EAPOL
-static void write_eap(FILE *f, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	value = wpa_config_get(ssid, "eap");
-	if (value == NULL)
-		return;
-
-	if (value[0])
-		fprintf(f, "\teap=%s\n", value);
-	os_free(value);
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
-{
-	char field[20], *value;
-	int res;
-
-	res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
-	if (res < 0 || (size_t) res >= sizeof(field))
-		return;
-	value = wpa_config_get(ssid, field);
-	if (value) {
-		fprintf(f, "\t%s=%s\n", field, value);
-		os_free(value);
-	}
-}
-
-
-static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
-{
-	int i;
-
-#define STR(t) write_str(f, #t, ssid)
-#define INT(t) write_int(f, #t, ssid->t, 0)
-#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
-#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
-
-	STR(ssid);
-	INT(scan_ssid);
-	write_bssid(f, ssid);
-	write_psk(f, ssid);
-	write_proto(f, ssid);
-	write_key_mgmt(f, ssid);
-	write_pairwise(f, ssid);
-	write_group(f, ssid);
-	write_auth_alg(f, ssid);
-#ifdef IEEE8021X_EAPOL
-	write_eap(f, ssid);
-	STR(identity);
-	STR(anonymous_identity);
-	STR(password);
-	STR(ca_cert);
-	STR(ca_path);
-	STR(client_cert);
-	STR(private_key);
-	STR(private_key_passwd);
-	STR(dh_file);
-	STR(subject_match);
-	STR(altsubject_match);
-	STR(ca_cert2);
-	STR(ca_path2);
-	STR(client_cert2);
-	STR(private_key2);
-	STR(private_key2_passwd);
-	STR(dh_file2);
-	STR(subject_match2);
-	STR(altsubject_match2);
-	STR(phase1);
-	STR(phase2);
-	STR(pcsc);
-	STR(pin);
-	STR(engine_id);
-	STR(key_id);
-	STR(cert_id);
-	STR(ca_cert_id);
-	STR(key2_id);
-	STR(pin2);
-	STR(engine2_id);
-	STR(cert2_id);
-	STR(ca_cert2_id);
-	INTe(engine);
-	INTe(engine2);
-	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
-#endif /* IEEE8021X_EAPOL */
-	for (i = 0; i < 4; i++)
-		write_wep_key(f, i, ssid);
-	INT(wep_tx_keyidx);
-	INT(priority);
-#ifdef IEEE8021X_EAPOL
-	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
-	STR(pac_file);
-	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
-#endif /* IEEE8021X_EAPOL */
-	INT(mode);
-	INT(proactive_key_caching);
-	INT(disabled);
-	INT(peerkey);
-#ifdef CONFIG_IEEE80211W
-	INT(ieee80211w);
-#endif /* CONFIG_IEEE80211W */
-	STR(id_str);
-
-#undef STR
-#undef INT
-#undef INT_DEF
-}
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
-{
-	unsigned char *encoded;
-
-	encoded = base64_encode(blob->data, blob->len, NULL);
-	if (encoded == NULL)
-		return -1;
-
-	fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
-	os_free(encoded);
-	return 0;
-}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-static void wpa_config_write_global(FILE *f, struct wpa_config *config)
-{
-#ifdef CONFIG_CTRL_IFACE
-	if (config->ctrl_interface)
-		fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
-	if (config->ctrl_interface_group)
-		fprintf(f, "ctrl_interface_group=%s\n",
-			config->ctrl_interface_group);
-#endif /* CONFIG_CTRL_IFACE */
-	if (config->eapol_version != DEFAULT_EAPOL_VERSION)
-		fprintf(f, "eapol_version=%d\n", config->eapol_version);
-	if (config->ap_scan != DEFAULT_AP_SCAN)
-		fprintf(f, "ap_scan=%d\n", config->ap_scan);
-	if (config->fast_reauth != DEFAULT_FAST_REAUTH)
-		fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
-	if (config->opensc_engine_path)
-		fprintf(f, "opensc_engine_path=%s\n",
-			config->opensc_engine_path);
-	if (config->pkcs11_engine_path)
-		fprintf(f, "pkcs11_engine_path=%s\n",
-			config->pkcs11_engine_path);
-	if (config->pkcs11_module_path)
-		fprintf(f, "pkcs11_module_path=%s\n",
-			config->pkcs11_module_path);
-	if (config->driver_param)
-		fprintf(f, "driver_param=%s\n", config->driver_param);
-	if (config->dot11RSNAConfigPMKLifetime)
-		fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
-			config->dot11RSNAConfigPMKLifetime);
-	if (config->dot11RSNAConfigPMKReauthThreshold)
-		fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
-			config->dot11RSNAConfigPMKReauthThreshold);
-	if (config->dot11RSNAConfigSATimeout)
-		fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
-			config->dot11RSNAConfigSATimeout);
-	if (config->update_config)
-		fprintf(f, "update_config=%d\n", config->update_config);
-#ifdef CONFIG_WPS
-	if (!is_nil_uuid(config->uuid)) {
-		char buf[40];
-		uuid_bin2str(config->uuid, buf, sizeof(buf));
-		fprintf(f, "uuid=%s\n", buf);
-	}
-	if (config->device_name)
-		fprintf(f, "device_name=%s\n", config->device_name);
-	if (config->manufacturer)
-		fprintf(f, "manufacturer=%s\n", config->manufacturer);
-	if (config->model_name)
-		fprintf(f, "model_name=%s\n", config->model_name);
-	if (config->model_number)
-		fprintf(f, "model_number=%s\n", config->model_number);
-	if (config->serial_number)
-		fprintf(f, "serial_number=%s\n", config->serial_number);
-	if (config->device_type)
-		fprintf(f, "device_type=%s\n", config->device_type);
-	if (WPA_GET_BE32(config->os_version))
-		fprintf(f, "os_version=%08x\n",
-			WPA_GET_BE32(config->os_version));
-	if (config->config_methods)
-		fprintf(f, "config_methods=%s\n", config->config_methods);
-	if (config->wps_cred_processing)
-		fprintf(f, "wps_cred_processing=%d\n",
-			config->wps_cred_processing);
-#endif /* CONFIG_WPS */
-	if (config->country[0] && config->country[1]) {
-		fprintf(f, "country=%c%c\n",
-			config->country[0], config->country[1]);
-	}
-	if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT)
-		fprintf(f, "bss_max_count=%u\n", config->bss_max_count);
-	if (config->filter_ssids)
-		fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
-}
-
-#endif /* CONFIG_NO_CONFIG_WRITE */
-
-
-int wpa_config_write(const char *name, struct wpa_config *config)
-{
-#ifndef CONFIG_NO_CONFIG_WRITE
-	FILE *f;
-	struct wpa_ssid *ssid;
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	struct wpa_config_blob *blob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
-
-	f = fopen(name, "w");
-	if (f == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
-		return -1;
-	}
-
-	wpa_config_write_global(f, config);
-
-	for (ssid = config->ssid; ssid; ssid = ssid->next) {
-		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
-			continue; /* do not save temporary WPS networks */
-		fprintf(f, "\nnetwork={\n");
-		wpa_config_write_network(f, ssid);
-		fprintf(f, "}\n");
-	}
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	for (blob = config->blobs; blob; blob = blob->next) {
-		ret = wpa_config_write_blob(f, blob);
-		if (ret)
-			break;
-	}
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-	fclose(f);
-
-	wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
-		   name, ret ? "un" : "");
-	return ret;
-#else /* CONFIG_NO_CONFIG_WRITE */
-	return -1;
-#endif /* CONFIG_NO_CONFIG_WRITE */
-}

Copied: vendor/wpa/2.0/wpa_supplicant/config_file.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/config_file.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config_file.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config_file.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1032 @@
+/*
+ * WPA Supplicant / Configuration backend: text file
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements a configuration backend for text files. All the
+ * configuration information is stored in a text file that uses a format
+ * described in the sample configuration file, wpa_supplicant.conf.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "base64.h"
+#include "uuid.h"
+#include "p2p/p2p.h"
+#include "eap_peer/eap_methods.h"
+#include "eap_peer/eap.h"
+
+
+static int newline_terminated(const char *buf, size_t buflen)
+{
+	size_t len = os_strlen(buf);
+	if (len == 0)
+		return 0;
+	if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+	    buf[len - 1] != '\n')
+		return 0;
+	return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+	char buf[100];
+	while (fgets(buf, sizeof(buf), stream)) {
+		buf[sizeof(buf) - 1] = '\0';
+		if (newline_terminated(buf, sizeof(buf)))
+			return;
+	}
+}
+
+
+/**
+ * wpa_config_get_line - Read the next configuration file line
+ * @s: Buffer for the line
+ * @size: The buffer length
+ * @stream: File stream to read from
+ * @line: Pointer to a variable storing the file line number
+ * @_pos: Buffer for the pointer to the beginning of data on the text line or
+ * %NULL if not needed (returned value used instead)
+ * Returns: Pointer to the beginning of data on the text line or %NULL if no
+ * more text lines are available.
+ *
+ * This function reads the next non-empty line from the configuration file and
+ * removes comments. The returned string is guaranteed to be null-terminated.
+ */
+static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+				  char **_pos)
+{
+	char *pos, *end, *sstart;
+
+	while (fgets(s, size, stream)) {
+		(*line)++;
+		s[size - 1] = '\0';
+		if (!newline_terminated(s, size)) {
+			/*
+			 * The line was truncated - skip rest of it to avoid
+			 * confusing error messages.
+			 */
+			wpa_printf(MSG_INFO, "Long line in configuration file "
+				   "truncated");
+			skip_line_end(stream);
+		}
+		pos = s;
+
+		/* Skip white space from the beginning of line. */
+		while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+			pos++;
+
+		/* Skip comment lines and empty lines */
+		if (*pos == '#' || *pos == '\n' || *pos == '\0')
+			continue;
+
+		/*
+		 * Remove # comments unless they are within a double quoted
+		 * string.
+		 */
+		sstart = os_strchr(pos, '"');
+		if (sstart)
+			sstart = os_strrchr(sstart + 1, '"');
+		if (!sstart)
+			sstart = pos;
+		end = os_strchr(sstart, '#');
+		if (end)
+			*end-- = '\0';
+		else
+			end = pos + os_strlen(pos) - 1;
+
+		/* Remove trailing white space. */
+		while (end > pos &&
+		       (*end == '\n' || *end == ' ' || *end == '\t' ||
+			*end == '\r'))
+			*end-- = '\0';
+
+		if (*pos == '\0')
+			continue;
+
+		if (_pos)
+			*_pos = pos;
+		return pos;
+	}
+
+	if (_pos)
+		*_pos = NULL;
+	return NULL;
+}
+
+
+static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
+{
+	int errors = 0;
+
+	if (ssid->passphrase) {
+		if (ssid->psk_set) {
+			wpa_printf(MSG_ERROR, "Line %d: both PSK and "
+				   "passphrase configured.", line);
+			errors++;
+		}
+		wpa_config_update_psk(ssid);
+	}
+
+	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+		/* Group cipher cannot be stronger than the pairwise cipher. */
+		wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
+			   " list since it was not allowed for pairwise "
+			   "cipher", line);
+		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+	}
+
+	return errors;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
+{
+	struct wpa_ssid *ssid;
+	int errors = 0, end = 0;
+	char buf[2000], *pos, *pos2;
+
+	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
+		   *line);
+	ssid = os_zalloc(sizeof(*ssid));
+	if (ssid == NULL)
+		return NULL;
+	ssid->id = id;
+
+	wpa_config_set_network_defaults(ssid);
+
+	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (os_strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		}
+
+		pos2 = os_strchr(pos, '=');
+		if (pos2 == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
+				   "'%s'.", *line, pos);
+			errors++;
+			continue;
+		}
+
+		*pos2++ = '\0';
+		if (*pos2 == '"') {
+			if (os_strchr(pos2 + 1, '"') == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "quotation '%s'.", *line, pos2);
+				errors++;
+				continue;
+			}
+		}
+
+		if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+			errors++;
+	}
+
+	if (!end) {
+		wpa_printf(MSG_ERROR, "Line %d: network block was not "
+			   "terminated properly.", *line);
+		errors++;
+	}
+
+	errors += wpa_config_validate_network(ssid, *line);
+
+	if (errors) {
+		wpa_config_free_ssid(ssid);
+		ssid = NULL;
+	}
+
+	return ssid;
+}
+
+
+static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id)
+{
+	struct wpa_cred *cred;
+	int errors = 0, end = 0;
+	char buf[256], *pos, *pos2;
+
+	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new cred block", *line);
+	cred = os_zalloc(sizeof(*cred));
+	if (cred == NULL)
+		return NULL;
+	cred->id = id;
+
+	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (os_strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		}
+
+		pos2 = os_strchr(pos, '=');
+		if (pos2 == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid cred line "
+				   "'%s'.", *line, pos);
+			errors++;
+			continue;
+		}
+
+		*pos2++ = '\0';
+		if (*pos2 == '"') {
+			if (os_strchr(pos2 + 1, '"') == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "quotation '%s'.", *line, pos2);
+				errors++;
+				continue;
+			}
+		}
+
+		if (wpa_config_set_cred(cred, pos, pos2, *line) < 0)
+			errors++;
+	}
+
+	if (!end) {
+		wpa_printf(MSG_ERROR, "Line %d: cred block was not "
+			   "terminated properly.", *line);
+		errors++;
+	}
+
+	if (errors) {
+		wpa_config_free_cred(cred);
+		cred = NULL;
+	}
+
+	return cred;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
+						     const char *name)
+{
+	struct wpa_config_blob *blob;
+	char buf[256], *pos;
+	unsigned char *encoded = NULL, *nencoded;
+	int end = 0;
+	size_t encoded_len = 0, len;
+
+	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
+		   *line, name);
+
+	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (os_strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		}
+
+		len = os_strlen(pos);
+		nencoded = os_realloc(encoded, encoded_len + len);
+		if (nencoded == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
+				   "blob", *line);
+			os_free(encoded);
+			return NULL;
+		}
+		encoded = nencoded;
+		os_memcpy(encoded + encoded_len, pos, len);
+		encoded_len += len;
+	}
+
+	if (!end) {
+		wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
+			   "properly", *line);
+		os_free(encoded);
+		return NULL;
+	}
+
+	blob = os_zalloc(sizeof(*blob));
+	if (blob == NULL) {
+		os_free(encoded);
+		return NULL;
+	}
+	blob->name = os_strdup(name);
+	blob->data = base64_decode(encoded, encoded_len, &blob->len);
+	os_free(encoded);
+
+	if (blob->name == NULL || blob->data == NULL) {
+		wpa_config_free_blob(blob);
+		return NULL;
+	}
+
+	return blob;
+}
+
+
+static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
+				   int *line, char *bname)
+{
+	char *name_end;
+	struct wpa_config_blob *blob;
+
+	name_end = os_strchr(bname, '=');
+	if (name_end == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: no blob name terminator",
+			   *line);
+		return -1;
+	}
+	*name_end = '\0';
+
+	blob = wpa_config_read_blob(f, line, bname);
+	if (blob == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to read blob %s",
+			   *line, bname);
+		return -1;
+	}
+	wpa_config_set_blob(config, blob);
+	return 0;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+	FILE *f;
+	char buf[512], *pos;
+	int errors = 0, line = 0;
+	struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+	struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
+	struct wpa_config *config;
+	int id = 0;
+	int cred_id = 0;
+
+	config = wpa_config_alloc_empty(NULL, NULL);
+	if (config == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate config file "
+			   "structure");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+	f = fopen(name, "r");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+			   "error: %s", name, strerror(errno));
+		os_free(config);
+		return NULL;
+	}
+
+	while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+		if (os_strcmp(pos, "network={") == 0) {
+			ssid = wpa_config_read_network(f, &line, id++);
+			if (ssid == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "parse network block.", line);
+				errors++;
+				continue;
+			}
+			if (head == NULL) {
+				head = tail = ssid;
+			} else {
+				tail->next = ssid;
+				tail = ssid;
+			}
+			if (wpa_config_add_prio_network(config, ssid)) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to add "
+					   "network block to priority list.",
+					   line);
+				errors++;
+				continue;
+			}
+		} else if (os_strcmp(pos, "cred={") == 0) {
+			cred = wpa_config_read_cred(f, &line, cred_id++);
+			if (cred == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "parse cred block.", line);
+				errors++;
+				continue;
+			}
+			if (cred_head == NULL) {
+				cred_head = cred_tail = cred;
+			} else {
+				cred_tail->next = cred;
+				cred_tail = cred;
+			}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+		} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
+			if (wpa_config_process_blob(config, f, &line, pos + 12)
+			    < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "process blob.", line);
+				errors++;
+				continue;
+			}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+		} else if (wpa_config_process_global(config, pos, line) < 0) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
+				   "line '%s'.", line, pos);
+			errors++;
+			continue;
+		}
+	}
+
+	fclose(f);
+
+	config->ssid = head;
+	wpa_config_debug_dump_networks(config);
+	config->cred = cred_head;
+
+#ifndef WPA_IGNORE_CONFIG_ERRORS
+	if (errors) {
+		wpa_config_free(config);
+		config = NULL;
+		head = NULL;
+	}
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
+
+	return config;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+
+static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, field);
+	if (value == NULL)
+		return;
+	fprintf(f, "\t%s=%s\n", field, value);
+	os_free(value);
+}
+
+
+static void write_int(FILE *f, const char *field, int value, int def)
+{
+	if (value == def)
+		return;
+	fprintf(f, "\t%s=%d\n", field, value);
+}
+
+
+static void write_bssid(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "bssid");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tbssid=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_psk(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "psk");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tpsk=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_proto(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->proto == DEFAULT_PROTO)
+		return;
+
+	value = wpa_config_get(ssid, "proto");
+	if (value == NULL)
+		return;
+	if (value[0])
+		fprintf(f, "\tproto=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+		return;
+
+	value = wpa_config_get(ssid, "key_mgmt");
+	if (value == NULL)
+		return;
+	if (value[0])
+		fprintf(f, "\tkey_mgmt=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
+		return;
+
+	value = wpa_config_get(ssid, "pairwise");
+	if (value == NULL)
+		return;
+	if (value[0])
+		fprintf(f, "\tpairwise=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_group(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->group_cipher == DEFAULT_GROUP)
+		return;
+
+	value = wpa_config_get(ssid, "group");
+	if (value == NULL)
+		return;
+	if (value[0])
+		fprintf(f, "\tgroup=%s\n", value);
+	os_free(value);
+}
+
+
+static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->auth_alg == 0)
+		return;
+
+	value = wpa_config_get(ssid, "auth_alg");
+	if (value == NULL)
+		return;
+	if (value[0])
+		fprintf(f, "\tauth_alg=%s\n", value);
+	os_free(value);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void write_eap(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	value = wpa_config_get(ssid, "eap");
+	if (value == NULL)
+		return;
+
+	if (value[0])
+		fprintf(f, "\teap=%s\n", value);
+	os_free(value);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
+{
+	char field[20], *value;
+	int res;
+
+	res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
+	if (res < 0 || (size_t) res >= sizeof(field))
+		return;
+	value = wpa_config_get(ssid, field);
+	if (value) {
+		fprintf(f, "\t%s=%s\n", field, value);
+		os_free(value);
+	}
+}
+
+
+#ifdef CONFIG_P2P
+static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "p2p_client_list");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tp2p_client_list=%s\n", value);
+	os_free(value);
+}
+#endif /* CONFIG_P2P */
+
+
+static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
+{
+	int i;
+
+#define STR(t) write_str(f, #t, ssid)
+#define INT(t) write_int(f, #t, ssid->t, 0)
+#define INTe(t) write_int(f, #t, ssid->eap.t, 0)
+#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
+#define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
+
+	STR(ssid);
+	INT(scan_ssid);
+	write_bssid(f, ssid);
+	write_psk(f, ssid);
+	write_proto(f, ssid);
+	write_key_mgmt(f, ssid);
+	INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
+	write_pairwise(f, ssid);
+	write_group(f, ssid);
+	write_auth_alg(f, ssid);
+	STR(bgscan);
+	STR(autoscan);
+#ifdef IEEE8021X_EAPOL
+	write_eap(f, ssid);
+	STR(identity);
+	STR(anonymous_identity);
+	STR(password);
+	STR(ca_cert);
+	STR(ca_path);
+	STR(client_cert);
+	STR(private_key);
+	STR(private_key_passwd);
+	STR(dh_file);
+	STR(subject_match);
+	STR(altsubject_match);
+	STR(ca_cert2);
+	STR(ca_path2);
+	STR(client_cert2);
+	STR(private_key2);
+	STR(private_key2_passwd);
+	STR(dh_file2);
+	STR(subject_match2);
+	STR(altsubject_match2);
+	STR(phase1);
+	STR(phase2);
+	STR(pcsc);
+	STR(pin);
+	STR(engine_id);
+	STR(key_id);
+	STR(cert_id);
+	STR(ca_cert_id);
+	STR(key2_id);
+	STR(pin2);
+	STR(engine2_id);
+	STR(cert2_id);
+	STR(ca_cert2_id);
+	INTe(engine);
+	INTe(engine2);
+	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
+	for (i = 0; i < 4; i++)
+		write_wep_key(f, i, ssid);
+	INT(wep_tx_keyidx);
+	INT(priority);
+#ifdef IEEE8021X_EAPOL
+	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+	STR(pac_file);
+	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
+	INT(mode);
+	INT(frequency);
+	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
+	INT(disabled);
+	INT(peerkey);
+#ifdef CONFIG_IEEE80211W
+	write_int(f, "ieee80211w", ssid->ieee80211w,
+		  MGMT_FRAME_PROTECTION_DEFAULT);
+#endif /* CONFIG_IEEE80211W */
+	STR(id_str);
+#ifdef CONFIG_P2P
+	write_p2p_client_list(f, ssid);
+#endif /* CONFIG_P2P */
+
+#undef STR
+#undef INT
+#undef INT_DEF
+}
+
+
+static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred)
+{
+	if (cred->priority)
+		fprintf(f, "\tpriority=%d\n", cred->priority);
+	if (cred->pcsc)
+		fprintf(f, "\tpcsc=%d\n", cred->pcsc);
+	if (cred->realm)
+		fprintf(f, "\trealm=\"%s\"\n", cred->realm);
+	if (cred->username)
+		fprintf(f, "\tusername=\"%s\"\n", cred->username);
+	if (cred->password && cred->ext_password)
+		fprintf(f, "\tpassword=ext:%s\n", cred->password);
+	else if (cred->password)
+		fprintf(f, "\tpassword=\"%s\"\n", cred->password);
+	if (cred->ca_cert)
+		fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+	if (cred->client_cert)
+		fprintf(f, "\tclient_cert=\"%s\"\n", cred->client_cert);
+	if (cred->private_key)
+		fprintf(f, "\tprivate_key=\"%s\"\n", cred->private_key);
+	if (cred->private_key_passwd)
+		fprintf(f, "\tprivate_key_passwd=\"%s\"\n",
+			cred->private_key_passwd);
+	if (cred->imsi)
+		fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
+	if (cred->milenage)
+		fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
+	if (cred->domain)
+		fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+	if (cred->roaming_consortium_len) {
+		size_t i;
+		fprintf(f, "\troaming_consortium=");
+		for (i = 0; i < cred->roaming_consortium_len; i++)
+			fprintf(f, "%02x", cred->roaming_consortium[i]);
+		fprintf(f, "\n");
+	}
+	if (cred->eap_method) {
+		const char *name;
+		name = eap_get_name(cred->eap_method[0].vendor,
+				    cred->eap_method[0].method);
+		fprintf(f, "\teap=%s\n", name);
+	}
+	if (cred->phase1)
+		fprintf(f, "\tphase1=\"%s\"\n", cred->phase1);
+	if (cred->phase2)
+		fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
+	if (cred->excluded_ssid) {
+		size_t i, j;
+		for (i = 0; i < cred->num_excluded_ssid; i++) {
+			struct excluded_ssid *e = &cred->excluded_ssid[i];
+			fprintf(f, "\texcluded_ssid=");
+			for (j = 0; j < e->ssid_len; j++)
+				fprintf(f, "%02x", e->ssid[j]);
+			fprintf(f, "\n");
+		}
+	}
+}
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
+{
+	unsigned char *encoded;
+
+	encoded = base64_encode(blob->data, blob->len, NULL);
+	if (encoded == NULL)
+		return -1;
+
+	fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
+	os_free(encoded);
+	return 0;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+static void write_global_bin(FILE *f, const char *field,
+			     const struct wpabuf *val)
+{
+	size_t i;
+	const u8 *pos;
+
+	if (val == NULL)
+		return;
+
+	fprintf(f, "%s=", field);
+	pos = wpabuf_head(val);
+	for (i = 0; i < wpabuf_len(val); i++)
+		fprintf(f, "%02X", *pos++);
+	fprintf(f, "\n");
+}
+
+
+static void wpa_config_write_global(FILE *f, struct wpa_config *config)
+{
+#ifdef CONFIG_CTRL_IFACE
+	if (config->ctrl_interface)
+		fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
+	if (config->ctrl_interface_group)
+		fprintf(f, "ctrl_interface_group=%s\n",
+			config->ctrl_interface_group);
+#endif /* CONFIG_CTRL_IFACE */
+	if (config->eapol_version != DEFAULT_EAPOL_VERSION)
+		fprintf(f, "eapol_version=%d\n", config->eapol_version);
+	if (config->ap_scan != DEFAULT_AP_SCAN)
+		fprintf(f, "ap_scan=%d\n", config->ap_scan);
+	if (config->disable_scan_offload)
+		fprintf(f, "disable_scan_offload=%d\n",
+			config->disable_scan_offload);
+	if (config->fast_reauth != DEFAULT_FAST_REAUTH)
+		fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
+	if (config->opensc_engine_path)
+		fprintf(f, "opensc_engine_path=%s\n",
+			config->opensc_engine_path);
+	if (config->pkcs11_engine_path)
+		fprintf(f, "pkcs11_engine_path=%s\n",
+			config->pkcs11_engine_path);
+	if (config->pkcs11_module_path)
+		fprintf(f, "pkcs11_module_path=%s\n",
+			config->pkcs11_module_path);
+	if (config->pcsc_reader)
+		fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
+	if (config->pcsc_pin)
+		fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin);
+	if (config->driver_param)
+		fprintf(f, "driver_param=%s\n", config->driver_param);
+	if (config->dot11RSNAConfigPMKLifetime)
+		fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
+			config->dot11RSNAConfigPMKLifetime);
+	if (config->dot11RSNAConfigPMKReauthThreshold)
+		fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
+			config->dot11RSNAConfigPMKReauthThreshold);
+	if (config->dot11RSNAConfigSATimeout)
+		fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
+			config->dot11RSNAConfigSATimeout);
+	if (config->update_config)
+		fprintf(f, "update_config=%d\n", config->update_config);
+#ifdef CONFIG_WPS
+	if (!is_nil_uuid(config->uuid)) {
+		char buf[40];
+		uuid_bin2str(config->uuid, buf, sizeof(buf));
+		fprintf(f, "uuid=%s\n", buf);
+	}
+	if (config->device_name)
+		fprintf(f, "device_name=%s\n", config->device_name);
+	if (config->manufacturer)
+		fprintf(f, "manufacturer=%s\n", config->manufacturer);
+	if (config->model_name)
+		fprintf(f, "model_name=%s\n", config->model_name);
+	if (config->model_number)
+		fprintf(f, "model_number=%s\n", config->model_number);
+	if (config->serial_number)
+		fprintf(f, "serial_number=%s\n", config->serial_number);
+	{
+		char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+		buf = wps_dev_type_bin2str(config->device_type,
+					   _buf, sizeof(_buf));
+		if (os_strcmp(buf, "0-00000000-0") != 0)
+			fprintf(f, "device_type=%s\n", buf);
+	}
+	if (WPA_GET_BE32(config->os_version))
+		fprintf(f, "os_version=%08x\n",
+			WPA_GET_BE32(config->os_version));
+	if (config->config_methods)
+		fprintf(f, "config_methods=%s\n", config->config_methods);
+	if (config->wps_cred_processing)
+		fprintf(f, "wps_cred_processing=%d\n",
+			config->wps_cred_processing);
+	if (config->wps_vendor_ext_m1) {
+		int i, len = wpabuf_len(config->wps_vendor_ext_m1);
+		const u8 *p = wpabuf_head_u8(config->wps_vendor_ext_m1);
+		if (len > 0) {
+			fprintf(f, "wps_vendor_ext_m1=");
+			for (i = 0; i < len; i++)
+				fprintf(f, "%02x", *p++);
+			fprintf(f, "\n");
+		}
+	}
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (config->p2p_listen_reg_class)
+		fprintf(f, "p2p_listen_reg_class=%u\n",
+			config->p2p_listen_reg_class);
+	if (config->p2p_listen_channel)
+		fprintf(f, "p2p_listen_channel=%u\n",
+			config->p2p_listen_channel);
+	if (config->p2p_oper_reg_class)
+		fprintf(f, "p2p_oper_reg_class=%u\n",
+			config->p2p_oper_reg_class);
+	if (config->p2p_oper_channel)
+		fprintf(f, "p2p_oper_channel=%u\n", config->p2p_oper_channel);
+	if (config->p2p_go_intent != DEFAULT_P2P_GO_INTENT)
+		fprintf(f, "p2p_go_intent=%u\n", config->p2p_go_intent);
+	if (config->p2p_ssid_postfix)
+		fprintf(f, "p2p_ssid_postfix=%s\n", config->p2p_ssid_postfix);
+	if (config->persistent_reconnect)
+		fprintf(f, "persistent_reconnect=%u\n",
+			config->persistent_reconnect);
+	if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS)
+		fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
+	if (config->p2p_group_idle)
+		fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
+	if (config->p2p_pref_chan) {
+		unsigned int i;
+		fprintf(f, "p2p_pref_chan=");
+		for (i = 0; i < config->num_p2p_pref_chan; i++) {
+			fprintf(f, "%s%u:%u", i > 0 ? "," : "",
+				config->p2p_pref_chan[i].op_class,
+				config->p2p_pref_chan[i].chan);
+		}
+		fprintf(f, "\n");
+	}
+	if (config->p2p_go_ht40)
+		fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+	if (config->p2p_disabled)
+		fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+	if (config->p2p_no_group_iface)
+		fprintf(f, "p2p_no_group_iface=%u\n",
+			config->p2p_no_group_iface);
+#endif /* CONFIG_P2P */
+	if (config->country[0] && config->country[1]) {
+		fprintf(f, "country=%c%c\n",
+			config->country[0], config->country[1]);
+	}
+	if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT)
+		fprintf(f, "bss_max_count=%u\n", config->bss_max_count);
+	if (config->bss_expiration_age != DEFAULT_BSS_EXPIRATION_AGE)
+		fprintf(f, "bss_expiration_age=%u\n",
+			config->bss_expiration_age);
+	if (config->bss_expiration_scan_count !=
+	    DEFAULT_BSS_EXPIRATION_SCAN_COUNT)
+		fprintf(f, "bss_expiration_scan_count=%u\n",
+			config->bss_expiration_scan_count);
+	if (config->filter_ssids)
+		fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+	if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
+		fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
+	if (config->disassoc_low_ack)
+		fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_HS20
+	if (config->hs20)
+		fprintf(f, "hs20=1\n");
+#endif /* CONFIG_HS20 */
+#ifdef CONFIG_INTERWORKING
+	if (config->interworking)
+		fprintf(f, "interworking=%u\n", config->interworking);
+	if (!is_zero_ether_addr(config->hessid))
+		fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid));
+	if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE)
+		fprintf(f, "access_network_type=%d\n",
+			config->access_network_type);
+#endif /* CONFIG_INTERWORKING */
+	if (config->pbc_in_m1)
+		fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
+	if (config->wps_nfc_dev_pw_id)
+		fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+			config->wps_nfc_dev_pw_id);
+	write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
+	write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
+	write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+
+	if (config->ext_password_backend)
+		fprintf(f, "ext_password_backend=%s\n",
+			config->ext_password_backend);
+	if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY)
+		fprintf(f, "p2p_go_max_inactivity=%d\n",
+			config->p2p_go_max_inactivity);
+	if (config->auto_interworking)
+		fprintf(f, "auto_interworking=%d\n",
+			config->auto_interworking);
+	if (config->okc)
+		fprintf(f, "okc=%d\n", config->okc);
+	if (config->pmf)
+		fprintf(f, "pmf=%d\n", config->pmf);
+}
+
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_WRITE
+	FILE *f;
+	struct wpa_ssid *ssid;
+	struct wpa_cred *cred;
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct wpa_config_blob *blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+	f = fopen(name, "w");
+	if (f == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
+		return -1;
+	}
+
+	wpa_config_write_global(f, config);
+
+	for (cred = config->cred; cred; cred = cred->next) {
+		fprintf(f, "\ncred={\n");
+		wpa_config_write_cred(f, cred);
+		fprintf(f, "}\n");
+	}
+
+	for (ssid = config->ssid; ssid; ssid = ssid->next) {
+		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
+			continue; /* do not save temporary networks */
+		if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+		    !ssid->passphrase)
+			continue; /* do not save invalid network */
+		fprintf(f, "\nnetwork={\n");
+		wpa_config_write_network(f, ssid);
+		fprintf(f, "}\n");
+	}
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	for (blob = config->blobs; blob; blob = blob->next) {
+		ret = wpa_config_write_blob(f, blob);
+		if (ret)
+			break;
+	}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+	fclose(f);
+
+	wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
+		   name, ret ? "un" : "");
+	return ret;
+#else /* CONFIG_NO_CONFIG_WRITE */
+	return -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/config_none.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,57 +0,0 @@
-/*
- * WPA Supplicant / Configuration backend: empty starting point
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements dummy example of a configuration backend. None of the
- * functions are actually implemented so this can be used as a simple
- * compilation test or a starting point for a new configuration backend.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "config.h"
-#include "base64.h"
-
-
-struct wpa_config * wpa_config_read(const char *name)
-{
-	struct wpa_config *config;
-
-	config = wpa_config_alloc_empty(NULL, NULL);
-	if (config == NULL)
-		return NULL;
-	/* TODO: fill in configuration data */
-	return config;
-}
-
-
-int wpa_config_write(const char *name, struct wpa_config *config)
-{
-	struct wpa_ssid *ssid;
-	struct wpa_config_blob *blob;
-
-	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
-
-	/* TODO: write global config parameters */
-
-
-	for (ssid = config->ssid; ssid; ssid = ssid->next) {
-		/* TODO: write networks */
-	}
-
-	for (blob = config->blobs; blob; blob = blob->next) {
-		/* TODO: write blobs */
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/config_none.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/config_none.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config_none.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,51 @@
+/*
+ * WPA Supplicant / Configuration backend: empty starting point
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements dummy example of a configuration backend. None of the
+ * functions are actually implemented so this can be used as a simple
+ * compilation test or a starting point for a new configuration backend.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "base64.h"
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+	struct wpa_config *config;
+
+	config = wpa_config_alloc_empty(NULL, NULL);
+	if (config == NULL)
+		return NULL;
+	/* TODO: fill in configuration data */
+	return config;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+	struct wpa_ssid *ssid;
+	struct wpa_config_blob *blob;
+
+	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+	/* TODO: write global config parameters */
+
+
+	for (ssid = config->ssid; ssid; ssid = ssid->next) {
+		/* TODO: write networks */
+	}
+
+	for (blob = config->blobs; blob; blob = blob->next) {
+		/* TODO: write blobs */
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/config_ssid.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config_ssid.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config_ssid.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,378 +0,0 @@
-/*
- * WPA Supplicant / Network configuration structures
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CONFIG_SSID_H
-#define CONFIG_SSID_H
-
-#include "common/defs.h"
-#include "eap_peer/eap_config.h"
-
-#define MAX_SSID_LEN 32
-
-
-#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
-#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
-			     EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
-#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
-#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
-#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
-#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
-		       WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
-#define DEFAULT_FRAGMENT_SIZE 1398
-
-/**
- * struct wpa_ssid - Network configuration data
- *
- * This structure includes all the configuration variables for a network. This
- * data is included in the per-interface configuration data as an element of
- * the network list, struct wpa_config::ssid. Each network block in the
- * configuration is mapped to a struct wpa_ssid instance.
- */
-struct wpa_ssid {
-	/**
-	 * next - Next network in global list
-	 *
-	 * This pointer can be used to iterate over all networks. The head of
-	 * this list is stored in the ssid field of struct wpa_config.
-	 */
-	struct wpa_ssid *next;
-
-	/**
-	 * pnext - Next network in per-priority list
-	 *
-	 * This pointer can be used to iterate over all networks in the same
-	 * priority class. The heads of these list are stored in the pssid
-	 * fields of struct wpa_config.
-	 */
-	struct wpa_ssid *pnext;
-
-	/**
-	 * id - Unique id for the network
-	 *
-	 * This identifier is used as a unique identifier for each network
-	 * block when using the control interface. Each network is allocated an
-	 * id when it is being created, either when reading the configuration
-	 * file or when a new network is added through the control interface.
-	 */
-	int id;
-
-	/**
-	 * priority - Priority group
-	 *
-	 * By default, all networks will get same priority group (0). If some
-	 * of the networks are more desirable, this field can be used to change
-	 * the order in which wpa_supplicant goes through the networks when
-	 * selecting a BSS. The priority groups will be iterated in decreasing
-	 * priority (i.e., the larger the priority value, the sooner the
-	 * network is matched against the scan results). Within each priority
-	 * group, networks will be selected based on security policy, signal
-	 * strength, etc.
-	 *
-	 * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are
-	 * not using this priority to select the order for scanning. Instead,
-	 * they try the networks in the order that used in the configuration
-	 * file.
-	 */
-	int priority;
-
-	/**
-	 * ssid - Service set identifier (network name)
-	 *
-	 * This is the SSID for the network. For wireless interfaces, this is
-	 * used to select which network will be used. If set to %NULL (or
-	 * ssid_len=0), any SSID can be used. For wired interfaces, this must
-	 * be set to %NULL. Note: SSID may contain any characters, even nul
-	 * (ASCII 0) and as such, this should not be assumed to be a nul
-	 * terminated string. ssid_len defines how many characters are valid
-	 * and the ssid field is not guaranteed to be nul terminated.
-	 */
-	u8 *ssid;
-
-	/**
-	 * ssid_len - Length of the SSID
-	 */
-	size_t ssid_len;
-
-	/**
-	 * bssid - BSSID
-	 *
-	 * If set, this network block is used only when associating with the AP
-	 * using the configured BSSID
-	 */
-	u8 bssid[ETH_ALEN];
-
-	/**
-	 * bssid_set - Whether BSSID is configured for this network
-	 */
-	int bssid_set;
-
-	/**
-	 * psk - WPA pre-shared key (256 bits)
-	 */
-	u8 psk[32];
-
-	/**
-	 * psk_set - Whether PSK field is configured
-	 */
-	int psk_set;
-
-	/**
-	 * passphrase - WPA ASCII passphrase
-	 *
-	 * If this is set, psk will be generated using the SSID and passphrase
-	 * configured for the network. ASCII passphrase must be between 8 and
-	 * 63 characters (inclusive).
-	 */
-	char *passphrase;
-
-	/**
-	 * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
-	 */
-	int pairwise_cipher;
-
-	/**
-	 * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_*
-	 */
-	int group_cipher;
-
-	/**
-	 * key_mgmt - Bitfield of allowed key management protocols
-	 *
-	 * WPA_KEY_MGMT_*
-	 */
-	int key_mgmt;
-
-	/**
-	 * proto - Bitfield of allowed protocols, WPA_PROTO_*
-	 */
-	int proto;
-
-	/**
-	 * auth_alg -  Bitfield of allowed authentication algorithms
-	 *
-	 * WPA_AUTH_ALG_*
-	 */
-	int auth_alg;
-
-	/**
-	 * scan_ssid - Scan this SSID with Probe Requests
-	 *
-	 * scan_ssid can be used to scan for APs using hidden SSIDs.
-	 * Note: Many drivers do not support this. ap_mode=2 can be used with
-	 * such drivers to use hidden SSIDs.
-	 */
-	int scan_ssid;
-
-#ifdef IEEE8021X_EAPOL
-#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
-#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
-	/**
-	 * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*)
-	 */
-	int eapol_flags;
-
-	/**
-	 * eap - EAP peer configuration for this network
-	 */
-	struct eap_peer_config eap;
-#endif /* IEEE8021X_EAPOL */
-
-#define NUM_WEP_KEYS 4
-#define MAX_WEP_KEY_LEN 16
-	/**
-	 * wep_key - WEP keys
-	 */
-	u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
-
-	/**
-	 * wep_key_len - WEP key lengths
-	 */
-	size_t wep_key_len[NUM_WEP_KEYS];
-
-	/**
-	 * wep_tx_keyidx - Default key index for TX frames using WEP
-	 */
-	int wep_tx_keyidx;
-
-	/**
-	 * proactive_key_caching - Enable proactive key caching
-	 *
-	 * This field can be used to enable proactive key caching which is also
-	 * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
-	 * by default. Enable by setting this to 1.
-	 *
-	 * Proactive key caching is used to make supplicant assume that the APs
-	 * are using the same PMK and generate PMKSA cache entries without
-	 * doing RSN pre-authentication. This requires support from the AP side
-	 * and is normally used with wireless switches that co-locate the
-	 * authenticator.
-	 */
-	int proactive_key_caching;
-
-	/**
-	 * mixed_cell - Whether mixed cells are allowed
-	 *
-	 * This option can be used to configure whether so called mixed cells,
-	 * i.e., networks that use both plaintext and encryption in the same
-	 * SSID, are allowed. This is disabled (0) by default. Enable by
-	 * setting this to 1.
-	 */
-	int mixed_cell;
-
-#ifdef IEEE8021X_EAPOL
-
-	/**
-	 * leap - Number of EAP methods using LEAP
-	 *
-	 * This field should be set to 1 if LEAP is enabled. This is used to
-	 * select IEEE 802.11 authentication algorithm.
-	 */
-	int leap;
-
-	/**
-	 * non_leap - Number of EAP methods not using LEAP
-	 *
-	 * This field should be set to >0 if any EAP method other than LEAP is
-	 * enabled. This is used to select IEEE 802.11 authentication
-	 * algorithm.
-	 */
-	int non_leap;
-
-	/**
-	 * eap_workaround - EAP workarounds enabled
-	 *
-	 * wpa_supplicant supports number of "EAP workarounds" to work around
-	 * interoperability issues with incorrectly behaving authentication
-	 * servers. This is recommended to be enabled by default because some
-	 * of the issues are present in large number of authentication servers.
-	 *
-	 * Strict EAP conformance mode can be configured by disabling
-	 * workarounds with eap_workaround = 0.
-	 */
-	unsigned int eap_workaround;
-
-#endif /* IEEE8021X_EAPOL */
-
-	/**
-	 * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
-	 *
-	 * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
-	 *
-	 * 1 = IBSS (ad-hoc, peer-to-peer)
-	 *
-	 * 2 = AP (access point)
-	 *
-	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and
-	 * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
-	 * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
-	 * following network block options: proto=WPA, key_mgmt=WPA-NONE,
-	 * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
-	 * be set (either directly or using ASCII passphrase).
-	 */
-	enum wpas_mode {
-		WPAS_MODE_INFRA = 0,
-		WPAS_MODE_IBSS = 1,
-		WPAS_MODE_AP = 2,
-	} mode;
-
-	/**
-	 * disabled - Whether this network is currently disabled
-	 *
-	 * 0 = this network can be used (default).
-	 * 1 = this network block is disabled (can be enabled through
-	 * ctrl_iface, e.g., with wpa_cli or wpa_gui).
-	 */
-	int disabled;
-
-	/**
-	 * peerkey -  Whether PeerKey handshake for direct links is allowed
-	 *
-	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
-	 * enabled.
-	 *
-	 * 0 = disabled (default)
-	 * 1 = enabled
-	 */
-	int peerkey;
-
-	/**
-	 * id_str - Network identifier string for external scripts
-	 *
-	 * This value is passed to external ctrl_iface monitors in
-	 * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR
-	 * environment variable for action scripts.
-	 */
-	char *id_str;
-
-#ifdef CONFIG_IEEE80211W
-	/**
-	 * ieee80211w - Whether management frame protection is enabled
-	 *
-	 * This value is used to configure policy for management frame
-	 * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
-	 */
-	enum mfp_options ieee80211w;
-#endif /* CONFIG_IEEE80211W */
-
-	/**
-	 * frequency - Channel frequency in megahertz (MHz) for IBSS
-	 *
-	 * This value is used to configure the initial channel for IBSS (adhoc)
-	 * networks, e.g., 2412 = IEEE 802.11b/g channel 1. It is ignored in
-	 * the infrastructure mode. In addition, this value is only used by the
-	 * station that creates the IBSS. If an IBSS network with the
-	 * configured SSID is already present, the frequency of the network
-	 * will be used instead of this configured value.
-	 */
-	int frequency;
-
-	/**
-	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
-	 *
-	 * This value can be used to enforce rekeying of PTK to mitigate some
-	 * attacks against TKIP deficiencies.
-	 */
-	int wpa_ptk_rekey;
-
-	/**
-	 * scan_freq - Array of frequencies to scan or %NULL for all
-	 *
-	 * This is an optional zero-terminated array of frequencies in
-	 * megahertz (MHz) to include in scan requests when searching for this
-	 * network. This can be used to speed up scanning when the network is
-	 * known to not use all possible channels.
-	 */
-	int *scan_freq;
-
-	/**
-	 * bgscan - Background scan and roaming parameters or %NULL if none
-	 *
-	 * This is an optional set of parameters for background scanning and
-	 * roaming within a network (ESS) in following format:
-	 * <bgscan module name>:<module parameters>
-	 */
-	char *bgscan;
-
-	/**
-	 * freq_list - Array of allowed frequencies or %NULL for all
-	 *
-	 * This is an optional zero-terminated array of frequencies in
-	 * megahertz (MHz) to allow for selecting the BSS. If set, scan results
-	 * that do not match any of the specified frequencies are not
-	 * considered when selecting a BSS.
-	 */
-	int *freq_list;
-};
-
-#endif /* CONFIG_SSID_H */

Copied: vendor/wpa/2.0/wpa_supplicant/config_ssid.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/config_ssid.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config_ssid.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config_ssid.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,571 @@
+/*
+ * WPA Supplicant / Network configuration structures
+ * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_SSID_H
+#define CONFIG_SSID_H
+
+#include "common/defs.h"
+#include "eap_peer/eap_config.h"
+
+#define MAX_SSID_LEN 32
+
+
+#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
+#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
+			     EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
+#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
+#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
+		       WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
+#define DEFAULT_FRAGMENT_SIZE 1398
+
+#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_DISABLE_HT 0
+#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_SGI 0
+#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
+#define DEFAULT_AMPDU_FACTOR -1 /* no change */
+#define DEFAULT_AMPDU_DENSITY -1 /* no change */
+
+/**
+ * struct wpa_ssid - Network configuration data
+ *
+ * This structure includes all the configuration variables for a network. This
+ * data is included in the per-interface configuration data as an element of
+ * the network list, struct wpa_config::ssid. Each network block in the
+ * configuration is mapped to a struct wpa_ssid instance.
+ */
+struct wpa_ssid {
+	/**
+	 * next - Next network in global list
+	 *
+	 * This pointer can be used to iterate over all networks. The head of
+	 * this list is stored in the ssid field of struct wpa_config.
+	 */
+	struct wpa_ssid *next;
+
+	/**
+	 * pnext - Next network in per-priority list
+	 *
+	 * This pointer can be used to iterate over all networks in the same
+	 * priority class. The heads of these list are stored in the pssid
+	 * fields of struct wpa_config.
+	 */
+	struct wpa_ssid *pnext;
+
+	/**
+	 * id - Unique id for the network
+	 *
+	 * This identifier is used as a unique identifier for each network
+	 * block when using the control interface. Each network is allocated an
+	 * id when it is being created, either when reading the configuration
+	 * file or when a new network is added through the control interface.
+	 */
+	int id;
+
+	/**
+	 * priority - Priority group
+	 *
+	 * By default, all networks will get same priority group (0). If some
+	 * of the networks are more desirable, this field can be used to change
+	 * the order in which wpa_supplicant goes through the networks when
+	 * selecting a BSS. The priority groups will be iterated in decreasing
+	 * priority (i.e., the larger the priority value, the sooner the
+	 * network is matched against the scan results). Within each priority
+	 * group, networks will be selected based on security policy, signal
+	 * strength, etc.
+	 *
+	 * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are
+	 * not using this priority to select the order for scanning. Instead,
+	 * they try the networks in the order that used in the configuration
+	 * file.
+	 */
+	int priority;
+
+	/**
+	 * ssid - Service set identifier (network name)
+	 *
+	 * This is the SSID for the network. For wireless interfaces, this is
+	 * used to select which network will be used. If set to %NULL (or
+	 * ssid_len=0), any SSID can be used. For wired interfaces, this must
+	 * be set to %NULL. Note: SSID may contain any characters, even nul
+	 * (ASCII 0) and as such, this should not be assumed to be a nul
+	 * terminated string. ssid_len defines how many characters are valid
+	 * and the ssid field is not guaranteed to be nul terminated.
+	 */
+	u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID
+	 */
+	size_t ssid_len;
+
+	/**
+	 * bssid - BSSID
+	 *
+	 * If set, this network block is used only when associating with the AP
+	 * using the configured BSSID
+	 *
+	 * If this is a persistent P2P group (disabled == 2), this is the GO
+	 * Device Address.
+	 */
+	u8 bssid[ETH_ALEN];
+
+	/**
+	 * bssid_set - Whether BSSID is configured for this network
+	 */
+	int bssid_set;
+
+	/**
+	 * psk - WPA pre-shared key (256 bits)
+	 */
+	u8 psk[32];
+
+	/**
+	 * psk_set - Whether PSK field is configured
+	 */
+	int psk_set;
+
+	/**
+	 * passphrase - WPA ASCII passphrase
+	 *
+	 * If this is set, psk will be generated using the SSID and passphrase
+	 * configured for the network. ASCII passphrase must be between 8 and
+	 * 63 characters (inclusive).
+	 */
+	char *passphrase;
+
+	/**
+	 * ext_psk - PSK/passphrase name in external storage
+	 *
+	 * If this is set, PSK/passphrase will be fetched from external storage
+	 * when requesting association with the network.
+	 */
+	char *ext_psk;
+
+	/**
+	 * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
+	 */
+	int pairwise_cipher;
+
+	/**
+	 * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_*
+	 */
+	int group_cipher;
+
+	/**
+	 * key_mgmt - Bitfield of allowed key management protocols
+	 *
+	 * WPA_KEY_MGMT_*
+	 */
+	int key_mgmt;
+
+	/**
+	 * bg_scan_period - Background scan period in seconds, 0 to disable, or
+	 * -1 to indicate no change to default driver configuration
+	 */
+	int bg_scan_period;
+
+	/**
+	 * proto - Bitfield of allowed protocols, WPA_PROTO_*
+	 */
+	int proto;
+
+	/**
+	 * auth_alg -  Bitfield of allowed authentication algorithms
+	 *
+	 * WPA_AUTH_ALG_*
+	 */
+	int auth_alg;
+
+	/**
+	 * scan_ssid - Scan this SSID with Probe Requests
+	 *
+	 * scan_ssid can be used to scan for APs using hidden SSIDs.
+	 * Note: Many drivers do not support this. ap_mode=2 can be used with
+	 * such drivers to use hidden SSIDs.
+	 */
+	int scan_ssid;
+
+#ifdef IEEE8021X_EAPOL
+#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
+#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
+	/**
+	 * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*)
+	 */
+	int eapol_flags;
+
+	/**
+	 * eap - EAP peer configuration for this network
+	 */
+	struct eap_peer_config eap;
+#endif /* IEEE8021X_EAPOL */
+
+#define NUM_WEP_KEYS 4
+#define MAX_WEP_KEY_LEN 16
+	/**
+	 * wep_key - WEP keys
+	 */
+	u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
+
+	/**
+	 * wep_key_len - WEP key lengths
+	 */
+	size_t wep_key_len[NUM_WEP_KEYS];
+
+	/**
+	 * wep_tx_keyidx - Default key index for TX frames using WEP
+	 */
+	int wep_tx_keyidx;
+
+	/**
+	 * proactive_key_caching - Enable proactive key caching
+	 *
+	 * This field can be used to enable proactive key caching which is also
+	 * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
+	 * by default unless default value is changed with the global okc=1
+	 * parameter. Enable by setting this to 1.
+	 *
+	 * Proactive key caching is used to make supplicant assume that the APs
+	 * are using the same PMK and generate PMKSA cache entries without
+	 * doing RSN pre-authentication. This requires support from the AP side
+	 * and is normally used with wireless switches that co-locate the
+	 * authenticator.
+	 *
+	 * Internally, special value -1 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
+	 */
+	int proactive_key_caching;
+
+	/**
+	 * mixed_cell - Whether mixed cells are allowed
+	 *
+	 * This option can be used to configure whether so called mixed cells,
+	 * i.e., networks that use both plaintext and encryption in the same
+	 * SSID, are allowed. This is disabled (0) by default. Enable by
+	 * setting this to 1.
+	 */
+	int mixed_cell;
+
+#ifdef IEEE8021X_EAPOL
+
+	/**
+	 * leap - Number of EAP methods using LEAP
+	 *
+	 * This field should be set to 1 if LEAP is enabled. This is used to
+	 * select IEEE 802.11 authentication algorithm.
+	 */
+	int leap;
+
+	/**
+	 * non_leap - Number of EAP methods not using LEAP
+	 *
+	 * This field should be set to >0 if any EAP method other than LEAP is
+	 * enabled. This is used to select IEEE 802.11 authentication
+	 * algorithm.
+	 */
+	int non_leap;
+
+	/**
+	 * eap_workaround - EAP workarounds enabled
+	 *
+	 * wpa_supplicant supports number of "EAP workarounds" to work around
+	 * interoperability issues with incorrectly behaving authentication
+	 * servers. This is recommended to be enabled by default because some
+	 * of the issues are present in large number of authentication servers.
+	 *
+	 * Strict EAP conformance mode can be configured by disabling
+	 * workarounds with eap_workaround = 0.
+	 */
+	unsigned int eap_workaround;
+
+#endif /* IEEE8021X_EAPOL */
+
+	/**
+	 * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
+	 *
+	 * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
+	 *
+	 * 1 = IBSS (ad-hoc, peer-to-peer)
+	 *
+	 * 2 = AP (access point)
+	 *
+	 * 3 = P2P Group Owner (can be set in the configuration file)
+	 *
+	 * 4 = P2P Group Formation (used internally; not in configuration
+	 * files)
+	 *
+	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and
+	 * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
+	 * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
+	 * following network block options: proto=WPA, key_mgmt=WPA-NONE,
+	 * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
+	 * be set (either directly or using ASCII passphrase).
+	 */
+	enum wpas_mode {
+		WPAS_MODE_INFRA = 0,
+		WPAS_MODE_IBSS = 1,
+		WPAS_MODE_AP = 2,
+		WPAS_MODE_P2P_GO = 3,
+		WPAS_MODE_P2P_GROUP_FORMATION = 4,
+	} mode;
+
+	/**
+	 * disabled - Whether this network is currently disabled
+	 *
+	 * 0 = this network can be used (default).
+	 * 1 = this network block is disabled (can be enabled through
+	 * ctrl_iface, e.g., with wpa_cli or wpa_gui).
+	 * 2 = this network block includes parameters for a persistent P2P
+	 * group (can be used with P2P ctrl_iface commands)
+	 */
+	int disabled;
+
+	/**
+	 * disabled_for_connect - Whether this network was temporarily disabled
+	 *
+	 * This flag is used to reenable all the temporarily disabled networks
+	 * after either the success or failure of a WPS connection.
+	 */
+	int disabled_for_connect;
+
+	/**
+	 * peerkey -  Whether PeerKey handshake for direct links is allowed
+	 *
+	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
+	 * enabled.
+	 *
+	 * 0 = disabled (default)
+	 * 1 = enabled
+	 */
+	int peerkey;
+
+	/**
+	 * id_str - Network identifier string for external scripts
+	 *
+	 * This value is passed to external ctrl_iface monitors in
+	 * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR
+	 * environment variable for action scripts.
+	 */
+	char *id_str;
+
+#ifdef CONFIG_IEEE80211W
+	/**
+	 * ieee80211w - Whether management frame protection is enabled
+	 *
+	 * This value is used to configure policy for management frame
+	 * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+	 * This is disabled by default unless the default value has been changed
+	 * with the global pmf=1/2 parameter.
+	 *
+	 * Internally, special value 3 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
+	 */
+	enum mfp_options ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+
+	/**
+	 * frequency - Channel frequency in megahertz (MHz) for IBSS
+	 *
+	 * This value is used to configure the initial channel for IBSS (adhoc)
+	 * networks, e.g., 2412 = IEEE 802.11b/g channel 1. It is ignored in
+	 * the infrastructure mode. In addition, this value is only used by the
+	 * station that creates the IBSS. If an IBSS network with the
+	 * configured SSID is already present, the frequency of the network
+	 * will be used instead of this configured value.
+	 */
+	int frequency;
+
+	int ht40;
+
+	/**
+	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
+	 *
+	 * This value can be used to enforce rekeying of PTK to mitigate some
+	 * attacks against TKIP deficiencies.
+	 */
+	int wpa_ptk_rekey;
+
+	/**
+	 * scan_freq - Array of frequencies to scan or %NULL for all
+	 *
+	 * This is an optional zero-terminated array of frequencies in
+	 * megahertz (MHz) to include in scan requests when searching for this
+	 * network. This can be used to speed up scanning when the network is
+	 * known to not use all possible channels.
+	 */
+	int *scan_freq;
+
+	/**
+	 * bgscan - Background scan and roaming parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for background scanning and
+	 * roaming within a network (ESS) in following format:
+	 * <bgscan module name>:<module parameters>
+	 */
+	char *bgscan;
+
+	/**
+	 * ignore_broadcast_ssid - Hide SSID in AP mode
+	 *
+	 * Send empty SSID in beacons and ignore probe request frames that do
+	 * not specify full SSID, i.e., require stations to know SSID.
+	 * default: disabled (0)
+	 * 1 = send empty (length=0) SSID in beacon and ignore probe request
+	 * for broadcast SSID
+	 * 2 = clear SSID (ASCII 0), but keep the original length (this may be
+	 * required with some clients that do not support empty SSID) and
+	 * ignore probe requests for broadcast SSID
+	 */
+	int ignore_broadcast_ssid;
+
+	/**
+	 * freq_list - Array of allowed frequencies or %NULL for all
+	 *
+	 * This is an optional zero-terminated array of frequencies in
+	 * megahertz (MHz) to allow for selecting the BSS. If set, scan results
+	 * that do not match any of the specified frequencies are not
+	 * considered when selecting a BSS.
+	 */
+	int *freq_list;
+
+	/**
+	 * p2p_client_list - List of P2P Clients in a persistent group (GO)
+	 *
+	 * This is a list of P2P Clients (P2P Device Address) that have joined
+	 * the persistent group. This is maintained on the GO for persistent
+	 * group entries (disabled == 2).
+	 */
+	u8 *p2p_client_list;
+
+	/**
+	 * num_p2p_clients - Number of entries in p2p_client_list
+	 */
+	size_t num_p2p_clients;
+
+#ifndef P2P_MAX_STORED_CLIENTS
+#define P2P_MAX_STORED_CLIENTS 100
+#endif /* P2P_MAX_STORED_CLIENTS */
+
+	/**
+	 * p2p_group - Network generated as a P2P group (used internally)
+	 */
+	int p2p_group;
+
+	/**
+	 * p2p_persistent_group - Whether this is a persistent group
+	 */
+	int p2p_persistent_group;
+
+	/**
+	 * temporary - Whether this network is temporary and not to be saved
+	 */
+	int temporary;
+
+	/**
+	 * export_keys - Whether keys may be exported
+	 *
+	 * This attribute will be set when keys are determined through
+	 * WPS or similar so that they may be exported.
+	 */
+	int export_keys;
+
+#ifdef CONFIG_HT_OVERRIDES
+	/**
+	 * disable_ht - Disable HT (IEEE 802.11n) for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_ht;
+
+	/**
+	 * disable_ht40 - Disable HT40 for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_ht40;
+
+	/**
+	 * disable_sgi - Disable SGI (Short Guard Interval) for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_sgi;
+
+	/**
+	 * disable_max_amsdu - Disable MAX A-MSDU
+	 *
+	 * A-MDSU will be 3839 bytes when disabled, or 7935
+	 * when enabled (assuming it is otherwise supported)
+	 * -1 (default) means do not apply any settings to the kernel.
+	 */
+	int disable_max_amsdu;
+
+	/**
+	 * ampdu_factor - Maximum A-MPDU Length Exponent
+	 *
+	 * Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+	 */
+	int ampdu_factor;
+
+	/**
+	 * ampdu_density - Minimum A-MPDU Start Spacing
+	 *
+	 * Value: 0-7, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+	 */
+	int ampdu_density;
+
+	/**
+	 * ht_mcs - Allowed HT-MCS rates, in ASCII hex: ffff0000...
+	 *
+	 * By default (empty string): Use whatever the OS has configured.
+	 */
+	char *ht_mcs;
+#endif /* CONFIG_HT_OVERRIDES */
+
+	/**
+	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+	 *
+	 * This timeout value is used in AP mode to clean up inactive stations.
+	 * By default: 300 seconds.
+	 */
+	int ap_max_inactivity;
+
+	/**
+	 * dtim_period - DTIM period in Beacon intervals
+	 * By default: 2
+	 */
+	int dtim_period;
+
+	/**
+	 * auth_failures - Number of consecutive authentication failures
+	 */
+	unsigned int auth_failures;
+
+	/**
+	 * disabled_until - Network block disabled until this time if non-zero
+	 */
+	struct os_time disabled_until;
+
+	/**
+	 * parent_cred - Pointer to parent wpa_cred entry
+	 *
+	 * This pointer can be used to delete temporary networks when a wpa_cred
+	 * that was used to create them is removed. This pointer should not be
+	 * dereferences since it may not be updated in all cases.
+	 */
+	void *parent_cred;
+};
+
+#endif /* CONFIG_SSID_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/config_winreg.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/config_winreg.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/config_winreg.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,995 +0,0 @@
-/*
- * WPA Supplicant / Configuration backend: Windows registry
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements a configuration backend for Windows registry. All the
- * configuration information is stored in the registry and the format for
- * network configuration fields is same as described in the sample
- * configuration file, wpa_supplicant.conf.
- *
- * Configuration data is in
- * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
- * key. Each configuration profile has its own key under this. In terms of text
- * files, each profile would map to a separate text file with possibly multiple
- * networks. Under each profile, there is a networks key that lists all
- * networks as a subkey. Each network has set of values in the same way as
- * network block in the configuration file. In addition, blobs subkey has
- * possible blobs as values.
- *
- * Example network configuration block:
- * \verbatim
-HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
-   ssid="example"
-   key_mgmt=WPA-PSK
-\endverbatim
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "uuid.h"
-#include "config.h"
-
-#ifndef WPA_KEY_ROOT
-#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
-#endif
-#ifndef WPA_KEY_PREFIX
-#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
-#endif
-
-#ifdef UNICODE
-#define TSTR "%S"
-#else /* UNICODE */
-#define TSTR "%s"
-#endif /* UNICODE */
-
-
-static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
-{
-	struct wpa_config_blob *blob;
-	int errors = 0;
-	HKEY bhk;
-	LONG ret;
-	DWORD i;
-
-	ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
-			   "blobs key");
-		return 0; /* assume no blobs */
-	}
-
-	for (i = 0; ; i++) {
-#define TNAMELEN 255
-		TCHAR name[TNAMELEN];
-		char data[4096];
-		DWORD namelen, datalen, type;
-
-		namelen = TNAMELEN;
-		datalen = sizeof(data);
-		ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
-				   (LPBYTE) data, &datalen);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
-				   (unsigned int) ret);
-			break;
-		}
-
-		if (namelen >= TNAMELEN)
-			namelen = TNAMELEN - 1;
-		name[namelen] = TEXT('\0');
-		wpa_unicode2ascii_inplace(name);
-
-		if (datalen >= sizeof(data))
-			datalen = sizeof(data) - 1;
-
-		wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
-			   (int) i, name, (int) datalen);
-
-		blob = os_zalloc(sizeof(*blob));
-		if (blob == NULL) {
-			errors++;
-			break;
-		}
-		blob->name = os_strdup((char *) name);
-		blob->data = os_malloc(datalen);
-		if (blob->name == NULL || blob->data == NULL) {
-			wpa_config_free_blob(blob);
-			errors++;
-			break;
-		}
-		os_memcpy(blob->data, data, datalen);
-		blob->len = datalen;
-
-		wpa_config_set_blob(config, blob);
-	}
-
-	RegCloseKey(bhk);
-
-	return errors ? -1 : 0;
-}
-
-
-static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
-{
-	DWORD val, buflen;
-	LONG ret;
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
-		wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
-		*_val = val;
-		return 0;
-	}
-
-	return -1;
-}
-
-
-static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
-{
-	DWORD buflen;
-	LONG ret;
-	TCHAR *val;
-
-	buflen = 0;
-	ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
-	if (ret != ERROR_SUCCESS)
-		return NULL;
-	val = os_malloc(buflen);
-	if (val == NULL)
-		return NULL;
-
-	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
-	if (ret != ERROR_SUCCESS) {
-		os_free(val);
-		return NULL;
-	}
-
-	wpa_unicode2ascii_inplace(val);
-	wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
-	return (char *) val;
-}
-
-
-#ifdef CONFIG_WPS
-static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
-{
-	char *str;
-	int ret = 0;
-
-	str = wpa_config_read_reg_string(hk, TEXT("uuid"));
-	if (str == NULL)
-		return 0;
-
-	if (uuid_str2bin(str, config->uuid))
-		ret = -1;
-
-	os_free(str);
-
-	return ret;
-}
-
-
-static int wpa_config_read_global_os_version(struct wpa_config *config,
-					     HKEY hk)
-{
-	char *str;
-	int ret = 0;
-
-	str = wpa_config_read_reg_string(hk, TEXT("os_version"));
-	if (str == NULL)
-		return 0;
-
-	if (hexstr2bin(str, config->os_version, 4))
-		ret = -1;
-
-	os_free(str);
-
-	return ret;
-}
-#endif /* CONFIG_WPS */
-
-
-static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
-{
-	int errors = 0;
-
-	wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
-	wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
-				  &config->fast_reauth);
-	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
-				  (int *) &config->dot11RSNAConfigPMKLifetime);
-	wpa_config_read_reg_dword(hk,
-				  TEXT("dot11RSNAConfigPMKReauthThreshold"),
-				  (int *)
-				  &config->dot11RSNAConfigPMKReauthThreshold);
-	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
-				  (int *) &config->dot11RSNAConfigSATimeout);
-	wpa_config_read_reg_dword(hk, TEXT("update_config"),
-				  &config->update_config);
-
-	if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
-				      &config->eapol_version) == 0) {
-		if (config->eapol_version < 1 ||
-		    config->eapol_version > 2) {
-			wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
-				   config->eapol_version);
-			errors++;
-		}
-	}
-
-	config->ctrl_interface = wpa_config_read_reg_string(
-		hk, TEXT("ctrl_interface"));
-
-#ifdef CONFIG_WPS
-	if (wpa_config_read_global_uuid(config, hk))
-		errors++;
-	config->device_name = wpa_config_read_reg_string(
-		hk, TEXT("device_name"));
-	config->manufacturer = wpa_config_read_reg_string(
-		hk, TEXT("manufacturer"));
-	config->model_name = wpa_config_read_reg_string(
-		hk, TEXT("model_name"));
-	config->serial_number = wpa_config_read_reg_string(
-		hk, TEXT("serial_number"));
-	config->device_type = wpa_config_read_reg_string(
-		hk, TEXT("device_type"));
-	config->config_methods = wpa_config_read_reg_string(
-		hk, TEXT("config_methods"));
-	if (wpa_config_read_global_os_version(config, hk))
-		errors++;
-	wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
-				  &config->wps_cred_processing);
-#endif /* CONFIG_WPS */
-
-	wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
-				  (int *) &config->bss_max_count);
-	wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
-				  &config->filter_ssids);
-
-	return errors ? -1 : 0;
-}
-
-
-static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
-						 int id)
-{
-	HKEY nhk;
-	LONG ret;
-	DWORD i;
-	struct wpa_ssid *ssid;
-	int errors = 0;
-
-	ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
-			   "network '" TSTR "'", netw);
-		return NULL;
-	}
-
-	wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
-	ssid = os_zalloc(sizeof(*ssid));
-	if (ssid == NULL) {
-		RegCloseKey(nhk);
-		return NULL;
-	}
-	ssid->id = id;
-
-	wpa_config_set_network_defaults(ssid);
-
-	for (i = 0; ; i++) {
-		TCHAR name[255], data[1024];
-		DWORD namelen, datalen, type;
-
-		namelen = 255;
-		datalen = sizeof(data);
-		ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
-				   (LPBYTE) data, &datalen);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
-				   (unsigned int) ret);
-			break;
-		}
-
-		if (namelen >= 255)
-			namelen = 255 - 1;
-		name[namelen] = TEXT('\0');
-
-		if (datalen >= 1024)
-			datalen = 1024 - 1;
-		data[datalen] = TEXT('\0');
-
-		wpa_unicode2ascii_inplace(name);
-		wpa_unicode2ascii_inplace(data);
-		if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
-			errors++;
-	}
-
-	RegCloseKey(nhk);
-
-	if (ssid->passphrase) {
-		if (ssid->psk_set) {
-			wpa_printf(MSG_ERROR, "Both PSK and passphrase "
-				   "configured for network '" TSTR "'.", netw);
-			errors++;
-		}
-		wpa_config_update_psk(ssid);
-	}
-
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_PSK_SHA256)) &&
-	    !ssid->psk_set) {
-		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
-			   "but no PSK configured for network '" TSTR "'.",
-			   netw);
-		errors++;
-	}
-
-	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
-	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
-		/* Group cipher cannot be stronger than the pairwise cipher. */
-		wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
-			   "list since it was not allowed for pairwise "
-			   "cipher for network '" TSTR "'.", netw);
-		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
-	}
-
-	if (errors) {
-		wpa_config_free_ssid(ssid);
-		ssid = NULL;
-	}
-
-	return ssid;
-}
-
-
-static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
-{
-	HKEY nhk;
-	struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
-	int errors = 0;
-	LONG ret;
-	DWORD i;
-
-	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
-			   &nhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
-			   "registry key");
-		return -1;
-	}
-
-	for (i = 0; ; i++) {
-		TCHAR name[255];
-		DWORD namelen;
-
-		namelen = 255;
-		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
-				   NULL);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
-				   (unsigned int) ret);
-			break;
-		}
-
-		if (namelen >= 255)
-			namelen = 255 - 1;
-		name[namelen] = '\0';
-
-		ssid = wpa_config_read_network(nhk, name, i);
-		if (ssid == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to parse network "
-				   "profile '%s'.", name);
-			errors++;
-			continue;
-		}
-		if (head == NULL) {
-			head = tail = ssid;
-		} else {
-			tail->next = ssid;
-			tail = ssid;
-		}
-		if (wpa_config_add_prio_network(config, ssid)) {
-			wpa_printf(MSG_ERROR, "Failed to add network profile "
-				   "'%s' to priority list.", name);
-			errors++;
-			continue;
-		}
-	}
-
-	RegCloseKey(nhk);
-
-	config->ssid = head;
-
-	return errors ? -1 : 0;
-}
-
-
-struct wpa_config * wpa_config_read(const char *name)
-{
-	TCHAR buf[256];
-	int errors = 0;
-	struct wpa_config *config;
-	HKEY hk;
-	LONG ret;
-
-	config = wpa_config_alloc_empty(NULL, NULL);
-	if (config == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
-
-#ifdef UNICODE
-	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
-#else /* UNICODE */
-	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
-#endif /* UNICODE */
-
-	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
-			   "configuration registry HKLM\\" TSTR, buf);
-		os_free(config);
-		return NULL;
-	}
-
-	if (wpa_config_read_global(config, hk))
-		errors++;
-
-	if (wpa_config_read_networks(config, hk))
-		errors++;
-
-	if (wpa_config_read_blobs(config, hk))
-		errors++;
-
-	wpa_config_debug_dump_networks(config);
-
-	RegCloseKey(hk);
-
-	if (errors) {
-		wpa_config_free(config);
-		config = NULL;
-	}
-
-	return config;
-}
-
-
-static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
-				      int def)
-{
-	LONG ret;
-	DWORD _val = val;
-
-	if (val == def) {
-		RegDeleteValue(hk, name);
-		return 0;
-	}
-
-	ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
-			    sizeof(_val));
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
-			   name, val, (int) GetLastError());
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_config_write_reg_string(HKEY hk, const char *name,
-				       const char *val)
-{
-	LONG ret;
-	TCHAR *_name, *_val;
-
-	_name = wpa_strdup_tchar(name);
-	if (_name == NULL)
-		return -1;
-
-	if (val == NULL) {
-		RegDeleteValue(hk, _name);
-		os_free(_name);
-		return 0;
-	}
-
-	_val = wpa_strdup_tchar(val);
-	if (_val == NULL) {
-		os_free(_name);
-		return -1;
-	}
-	ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
-			    (os_strlen(val) + 1) * sizeof(TCHAR));
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
-			   "error %d", name, val, (int) GetLastError());
-		os_free(_name);
-		os_free(_val);
-		return -1;
-	}
-
-	os_free(_name);
-	os_free(_val);
-	return 0;
-}
-
-
-static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
-{
-#ifdef CONFIG_CTRL_IFACE
-	wpa_config_write_reg_string(hk, "ctrl_interface",
-				    config->ctrl_interface);
-#endif /* CONFIG_CTRL_IFACE */
-
-	wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
-				   config->eapol_version,
-				   DEFAULT_EAPOL_VERSION);
-	wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
-				   DEFAULT_AP_SCAN);
-	wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
-				   config->fast_reauth, DEFAULT_FAST_REAUTH);
-	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
-				   config->dot11RSNAConfigPMKLifetime, 0);
-	wpa_config_write_reg_dword(hk,
-				   TEXT("dot11RSNAConfigPMKReauthThreshold"),
-				   config->dot11RSNAConfigPMKReauthThreshold,
-				   0);
-	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
-				   config->dot11RSNAConfigSATimeout, 0);
-	wpa_config_write_reg_dword(hk, TEXT("update_config"),
-				   config->update_config,
-				   0);
-#ifdef CONFIG_WPS
-	if (!is_nil_uuid(config->uuid)) {
-		char buf[40];
-		uuid_bin2str(config->uuid, buf, sizeof(buf));
-		wpa_config_write_reg_string(hk, "uuid", buf);
-	}
-	wpa_config_write_reg_string(hk, "device_name", config->device_name);
-	wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
-	wpa_config_write_reg_string(hk, "model_name", config->model_name);
-	wpa_config_write_reg_string(hk, "model_number", config->model_number);
-	wpa_config_write_reg_string(hk, "serial_number",
-				    config->serial_number);
-	wpa_config_write_reg_string(hk, "device_type", config->device_type);
-	wpa_config_write_reg_string(hk, "config_methods",
-				    config->config_methods);
-	if (WPA_GET_BE32(config->os_version)) {
-		char vbuf[10];
-		os_snprintf(vbuf, sizeof(vbuf), "%08x",
-			    WPA_GET_BE32(config->os_version));
-		wpa_config_write_reg_string(hk, "os_version", vbuf);
-	}
-	wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
-				   config->wps_cred_processing, 0);
-#endif /* CONFIG_WPS */
-
-	wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
-				   config->bss_max_count,
-				   DEFAULT_BSS_MAX_COUNT);
-	wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
-				   config->filter_ssids, 0);
-
-	return 0;
-}
-
-
-static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
-{
-	HKEY nhk;
-	int i, errors = 0;
-	LONG ret;
-
-	ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
-			   "' for subkey deletion: error 0x%x (%d)", key,
-			   (unsigned int) ret, (int) GetLastError());
-		return 0;
-	}
-
-	for (i = 0; ; i++) {
-		TCHAR name[255];
-		DWORD namelen;
-
-		namelen = 255;
-		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
-				   NULL);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
-				   (unsigned int) ret, (int) GetLastError());
-			break;
-		}
-
-		if (namelen >= 255)
-			namelen = 255 - 1;
-		name[namelen] = TEXT('\0');
-
-		ret = RegDeleteKey(nhk, name);
-		if (ret != ERROR_SUCCESS) {
-			wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
-				   (unsigned int) ret, (int) GetLastError());
-			errors++;
-		}
-	}
-
-	RegCloseKey(nhk);
-
-	return errors ? -1 : 0;
-}
-
-
-static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, field);
-	if (value == NULL)
-		return;
-	wpa_config_write_reg_string(hk, field, value);
-	os_free(value);
-}
-
-
-static void write_int(HKEY hk, const char *field, int value, int def)
-{
-	char val[20];
-	if (value == def)
-		return;
-	os_snprintf(val, sizeof(val), "%d", value);
-	wpa_config_write_reg_string(hk, field, val);
-}
-
-
-static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, "bssid");
-	if (value == NULL)
-		return;
-	wpa_config_write_reg_string(hk, "bssid", value);
-	os_free(value);
-}
-
-
-static void write_psk(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value = wpa_config_get(ssid, "psk");
-	if (value == NULL)
-		return;
-	wpa_config_write_reg_string(hk, "psk", value);
-	os_free(value);
-}
-
-
-static void write_proto(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->proto == DEFAULT_PROTO)
-		return;
-
-	value = wpa_config_get(ssid, "proto");
-	if (value == NULL)
-		return;
-	if (value[0])
-		wpa_config_write_reg_string(hk, "proto", value);
-	os_free(value);
-}
-
-
-static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
-		return;
-
-	value = wpa_config_get(ssid, "key_mgmt");
-	if (value == NULL)
-		return;
-	if (value[0])
-		wpa_config_write_reg_string(hk, "key_mgmt", value);
-	os_free(value);
-}
-
-
-static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
-		return;
-
-	value = wpa_config_get(ssid, "pairwise");
-	if (value == NULL)
-		return;
-	if (value[0])
-		wpa_config_write_reg_string(hk, "pairwise", value);
-	os_free(value);
-}
-
-
-static void write_group(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->group_cipher == DEFAULT_GROUP)
-		return;
-
-	value = wpa_config_get(ssid, "group");
-	if (value == NULL)
-		return;
-	if (value[0])
-		wpa_config_write_reg_string(hk, "group", value);
-	os_free(value);
-}
-
-
-static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	if (ssid->auth_alg == 0)
-		return;
-
-	value = wpa_config_get(ssid, "auth_alg");
-	if (value == NULL)
-		return;
-	if (value[0])
-		wpa_config_write_reg_string(hk, "auth_alg", value);
-	os_free(value);
-}
-
-
-#ifdef IEEE8021X_EAPOL
-static void write_eap(HKEY hk, struct wpa_ssid *ssid)
-{
-	char *value;
-
-	value = wpa_config_get(ssid, "eap");
-	if (value == NULL)
-		return;
-
-	if (value[0])
-		wpa_config_write_reg_string(hk, "eap", value);
-	os_free(value);
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
-{
-	char field[20], *value;
-
-	os_snprintf(field, sizeof(field), "wep_key%d", idx);
-	value = wpa_config_get(ssid, field);
-	if (value) {
-		wpa_config_write_reg_string(hk, field, value);
-		os_free(value);
-	}
-}
-
-
-static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
-{
-	int i, errors = 0;
-	HKEY nhk, netw;
-	LONG ret;
-	TCHAR name[5];
-
-	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
-			   "for subkey addition: error 0x%x (%d)",
-			   (unsigned int) ret, (int) GetLastError());
-		return 0;
-	}
-
-#ifdef UNICODE
-	wsprintf(name, L"%04d", id);
-#else /* UNICODE */
-	os_snprintf(name, sizeof(name), "%04d", id);
-#endif /* UNICODE */
-	ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
-			     NULL);
-	RegCloseKey(nhk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
-			   " error 0x%x (%d)",
-			   name, (unsigned int) ret, (int) GetLastError());
-		return -1;
-	}
-
-#define STR(t) write_str(netw, #t, ssid)
-#define INT(t) write_int(netw, #t, ssid->t, 0)
-#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
-#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
-#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
-
-	STR(ssid);
-	INT(scan_ssid);
-	write_bssid(netw, ssid);
-	write_psk(netw, ssid);
-	write_proto(netw, ssid);
-	write_key_mgmt(netw, ssid);
-	write_pairwise(netw, ssid);
-	write_group(netw, ssid);
-	write_auth_alg(netw, ssid);
-#ifdef IEEE8021X_EAPOL
-	write_eap(netw, ssid);
-	STR(identity);
-	STR(anonymous_identity);
-	STR(password);
-	STR(ca_cert);
-	STR(ca_path);
-	STR(client_cert);
-	STR(private_key);
-	STR(private_key_passwd);
-	STR(dh_file);
-	STR(subject_match);
-	STR(altsubject_match);
-	STR(ca_cert2);
-	STR(ca_path2);
-	STR(client_cert2);
-	STR(private_key2);
-	STR(private_key2_passwd);
-	STR(dh_file2);
-	STR(subject_match2);
-	STR(altsubject_match2);
-	STR(phase1);
-	STR(phase2);
-	STR(pcsc);
-	STR(pin);
-	STR(engine_id);
-	STR(key_id);
-	STR(cert_id);
-	STR(ca_cert_id);
-	STR(key2_id);
-	STR(pin2);
-	STR(engine2_id);
-	STR(cert2_id);
-	STR(ca_cert2_id);
-	INTe(engine);
-	INTe(engine2);
-	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
-#endif /* IEEE8021X_EAPOL */
-	for (i = 0; i < 4; i++)
-		write_wep_key(netw, i, ssid);
-	INT(wep_tx_keyidx);
-	INT(priority);
-#ifdef IEEE8021X_EAPOL
-	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
-	STR(pac_file);
-	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
-#endif /* IEEE8021X_EAPOL */
-	INT(mode);
-	INT(proactive_key_caching);
-	INT(disabled);
-	INT(peerkey);
-#ifdef CONFIG_IEEE80211W
-	INT(ieee80211w);
-#endif /* CONFIG_IEEE80211W */
-	STR(id_str);
-
-#undef STR
-#undef INT
-#undef INT_DEF
-
-	RegCloseKey(netw);
-
-	return errors ? -1 : 0;
-}
-
-
-static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
-{
-	HKEY bhk;
-	LONG ret;
-	TCHAR *name;
-
-	ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
-			     &bhk, NULL);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
-			   "error 0x%x (%d)",
-			   (unsigned int) ret, (int) GetLastError());
-		return -1;
-	}
-
-	name = wpa_strdup_tchar(blob->name);
-	ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
-			    blob->len);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
-			   "error 0x%x (%d)", blob->name, (unsigned int) ret,
-			   (int) GetLastError());
-		RegCloseKey(bhk);
-		os_free(name);
-		return -1;
-	}
-	os_free(name);
-
-	RegCloseKey(bhk);
-
-	return 0;
-}
-
-
-int wpa_config_write(const char *name, struct wpa_config *config)
-{
-	TCHAR buf[256];
-	HKEY hk;
-	LONG ret;
-	int errors = 0;
-	struct wpa_ssid *ssid;
-	struct wpa_config_blob *blob;
-	int id;
-
-	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
-
-#ifdef UNICODE
-	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
-#else /* UNICODE */
-	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
-#endif /* UNICODE */
-
-	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
-	if (ret != ERROR_SUCCESS) {
-		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
-			   "configuration registry %s: error %d", buf,
-			   (int) GetLastError());
-		return -1;
-	}
-
-	if (wpa_config_write_global(config, hk)) {
-		wpa_printf(MSG_ERROR, "Failed to write global configuration "
-			   "data");
-		errors++;
-	}
-
-	wpa_config_delete_subkeys(hk, TEXT("networks"));
-	for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
-		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
-			continue; /* do not save temporary WPS networks */
-		if (wpa_config_write_network(hk, ssid, id))
-			errors++;
-	}
-
-	RegDeleteKey(hk, TEXT("blobs"));
-	for (blob = config->blobs; blob; blob = blob->next) {
-		if (wpa_config_write_blob(hk, blob))
-			errors++;
-	}
-
-	RegCloseKey(hk);
-
-	wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
-		   name, errors ? "un" : "");
-	return errors ? -1 : 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/config_winreg.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/config_winreg.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/config_winreg.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/config_winreg.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1020 @@
+/*
+ * WPA Supplicant / Configuration backend: Windows registry
+ * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements a configuration backend for Windows registry. All the
+ * configuration information is stored in the registry and the format for
+ * network configuration fields is same as described in the sample
+ * configuration file, wpa_supplicant.conf.
+ *
+ * Configuration data is in
+ * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
+ * key. Each configuration profile has its own key under this. In terms of text
+ * files, each profile would map to a separate text file with possibly multiple
+ * networks. Under each profile, there is a networks key that lists all
+ * networks as a subkey. Each network has set of values in the same way as
+ * network block in the configuration file. In addition, blobs subkey has
+ * possible blobs as values.
+ *
+ * Example network configuration block:
+ * \verbatim
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+   ssid="example"
+   key_mgmt=WPA-PSK
+\endverbatim
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "uuid.h"
+#include "config.h"
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
+{
+	struct wpa_config_blob *blob;
+	int errors = 0;
+	HKEY bhk;
+	LONG ret;
+	DWORD i;
+
+	ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+			   "blobs key");
+		return 0; /* assume no blobs */
+	}
+
+	for (i = 0; ; i++) {
+#define TNAMELEN 255
+		TCHAR name[TNAMELEN];
+		char data[4096];
+		DWORD namelen, datalen, type;
+
+		namelen = TNAMELEN;
+		datalen = sizeof(data);
+		ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
+				   (LPBYTE) data, &datalen);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
+				   (unsigned int) ret);
+			break;
+		}
+
+		if (namelen >= TNAMELEN)
+			namelen = TNAMELEN - 1;
+		name[namelen] = TEXT('\0');
+		wpa_unicode2ascii_inplace(name);
+
+		if (datalen >= sizeof(data))
+			datalen = sizeof(data) - 1;
+
+		wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
+			   (int) i, name, (int) datalen);
+
+		blob = os_zalloc(sizeof(*blob));
+		if (blob == NULL) {
+			errors++;
+			break;
+		}
+		blob->name = os_strdup((char *) name);
+		blob->data = os_malloc(datalen);
+		if (blob->name == NULL || blob->data == NULL) {
+			wpa_config_free_blob(blob);
+			errors++;
+			break;
+		}
+		os_memcpy(blob->data, data, datalen);
+		blob->len = datalen;
+
+		wpa_config_set_blob(config, blob);
+	}
+
+	RegCloseKey(bhk);
+
+	return errors ? -1 : 0;
+}
+
+
+static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
+{
+	DWORD val, buflen;
+	LONG ret;
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+		wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
+		*_val = val;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
+{
+	DWORD buflen;
+	LONG ret;
+	TCHAR *val;
+
+	buflen = 0;
+	ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
+	if (ret != ERROR_SUCCESS)
+		return NULL;
+	val = os_malloc(buflen);
+	if (val == NULL)
+		return NULL;
+
+	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
+	if (ret != ERROR_SUCCESS) {
+		os_free(val);
+		return NULL;
+	}
+
+	wpa_unicode2ascii_inplace(val);
+	wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
+	return (char *) val;
+}
+
+
+#ifdef CONFIG_WPS
+static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
+{
+	char *str;
+	int ret = 0;
+
+	str = wpa_config_read_reg_string(hk, TEXT("uuid"));
+	if (str == NULL)
+		return 0;
+
+	if (uuid_str2bin(str, config->uuid))
+		ret = -1;
+
+	os_free(str);
+
+	return ret;
+}
+
+
+static int wpa_config_read_global_os_version(struct wpa_config *config,
+					     HKEY hk)
+{
+	char *str;
+	int ret = 0;
+
+	str = wpa_config_read_reg_string(hk, TEXT("os_version"));
+	if (str == NULL)
+		return 0;
+
+	if (hexstr2bin(str, config->os_version, 4))
+		ret = -1;
+
+	os_free(str);
+
+	return ret;
+}
+#endif /* CONFIG_WPS */
+
+
+static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
+{
+	int errors = 0;
+	int val;
+
+	wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
+	wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
+				  &config->fast_reauth);
+	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+				  (int *) &config->dot11RSNAConfigPMKLifetime);
+	wpa_config_read_reg_dword(hk,
+				  TEXT("dot11RSNAConfigPMKReauthThreshold"),
+				  (int *)
+				  &config->dot11RSNAConfigPMKReauthThreshold);
+	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+				  (int *) &config->dot11RSNAConfigSATimeout);
+	wpa_config_read_reg_dword(hk, TEXT("update_config"),
+				  &config->update_config);
+
+	if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
+				      &config->eapol_version) == 0) {
+		if (config->eapol_version < 1 ||
+		    config->eapol_version > 2) {
+			wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
+				   config->eapol_version);
+			errors++;
+		}
+	}
+
+	config->ctrl_interface = wpa_config_read_reg_string(
+		hk, TEXT("ctrl_interface"));
+
+#ifdef CONFIG_WPS
+	if (wpa_config_read_global_uuid(config, hk))
+		errors++;
+	config->device_name = wpa_config_read_reg_string(
+		hk, TEXT("device_name"));
+	config->manufacturer = wpa_config_read_reg_string(
+		hk, TEXT("manufacturer"));
+	config->model_name = wpa_config_read_reg_string(
+		hk, TEXT("model_name"));
+	config->serial_number = wpa_config_read_reg_string(
+		hk, TEXT("serial_number"));
+	{
+		char *t = wpa_config_read_reg_string(
+			hk, TEXT("device_type"));
+		if (t && wps_dev_type_str2bin(t, config->device_type))
+			errors++;
+		os_free(t);
+	}
+	config->config_methods = wpa_config_read_reg_string(
+		hk, TEXT("config_methods"));
+	if (wpa_config_read_global_os_version(config, hk))
+		errors++;
+	wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
+				  &config->wps_cred_processing);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	config->p2p_ssid_postfix = wpa_config_read_reg_string(
+		hk, TEXT("p2p_ssid_postfix"));
+	wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
+				  (int *) &config->p2p_group_idle);
+#endif /* CONFIG_P2P */
+
+	wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
+				  (int *) &config->bss_max_count);
+	wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
+				  &config->filter_ssids);
+	wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
+				  (int *) &config->max_num_sta);
+	wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
+				  (int *) &config->disassoc_low_ack);
+
+	wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+	wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+	config->pmf = val;
+
+	return errors ? -1 : 0;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
+						 int id)
+{
+	HKEY nhk;
+	LONG ret;
+	DWORD i;
+	struct wpa_ssid *ssid;
+	int errors = 0;
+
+	ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+			   "network '" TSTR "'", netw);
+		return NULL;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
+	ssid = os_zalloc(sizeof(*ssid));
+	if (ssid == NULL) {
+		RegCloseKey(nhk);
+		return NULL;
+	}
+	ssid->id = id;
+
+	wpa_config_set_network_defaults(ssid);
+
+	for (i = 0; ; i++) {
+		TCHAR name[255], data[1024];
+		DWORD namelen, datalen, type;
+
+		namelen = 255;
+		datalen = sizeof(data);
+		ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
+				   (LPBYTE) data, &datalen);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
+				   (unsigned int) ret);
+			break;
+		}
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = TEXT('\0');
+
+		if (datalen >= 1024)
+			datalen = 1024 - 1;
+		data[datalen] = TEXT('\0');
+
+		wpa_unicode2ascii_inplace(name);
+		wpa_unicode2ascii_inplace(data);
+		if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
+			errors++;
+	}
+
+	RegCloseKey(nhk);
+
+	if (ssid->passphrase) {
+		if (ssid->psk_set) {
+			wpa_printf(MSG_ERROR, "Both PSK and passphrase "
+				   "configured for network '" TSTR "'.", netw);
+			errors++;
+		}
+		wpa_config_update_psk(ssid);
+	}
+
+	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+		/* Group cipher cannot be stronger than the pairwise cipher. */
+		wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
+			   "list since it was not allowed for pairwise "
+			   "cipher for network '" TSTR "'.", netw);
+		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+	}
+
+	if (errors) {
+		wpa_config_free_ssid(ssid);
+		ssid = NULL;
+	}
+
+	return ssid;
+}
+
+
+static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
+{
+	HKEY nhk;
+	struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+	int errors = 0;
+	LONG ret;
+	DWORD i;
+
+	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
+			   &nhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
+			   "registry key");
+		return -1;
+	}
+
+	for (i = 0; ; i++) {
+		TCHAR name[255];
+		DWORD namelen;
+
+		namelen = 255;
+		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+				   NULL);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
+				   (unsigned int) ret);
+			break;
+		}
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = '\0';
+
+		ssid = wpa_config_read_network(nhk, name, i);
+		if (ssid == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to parse network "
+				   "profile '%s'.", name);
+			errors++;
+			continue;
+		}
+		if (head == NULL) {
+			head = tail = ssid;
+		} else {
+			tail->next = ssid;
+			tail = ssid;
+		}
+		if (wpa_config_add_prio_network(config, ssid)) {
+			wpa_printf(MSG_ERROR, "Failed to add network profile "
+				   "'%s' to priority list.", name);
+			errors++;
+			continue;
+		}
+	}
+
+	RegCloseKey(nhk);
+
+	config->ssid = head;
+
+	return errors ? -1 : 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+	TCHAR buf[256];
+	int errors = 0;
+	struct wpa_config *config;
+	HKEY hk;
+	LONG ret;
+
+	config = wpa_config_alloc_empty(NULL, NULL);
+	if (config == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
+
+#ifdef UNICODE
+	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+			   "configuration registry HKLM\\" TSTR, buf);
+		os_free(config);
+		return NULL;
+	}
+
+	if (wpa_config_read_global(config, hk))
+		errors++;
+
+	if (wpa_config_read_networks(config, hk))
+		errors++;
+
+	if (wpa_config_read_blobs(config, hk))
+		errors++;
+
+	wpa_config_debug_dump_networks(config);
+
+	RegCloseKey(hk);
+
+	if (errors) {
+		wpa_config_free(config);
+		config = NULL;
+	}
+
+	return config;
+}
+
+
+static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
+				      int def)
+{
+	LONG ret;
+	DWORD _val = val;
+
+	if (val == def) {
+		RegDeleteValue(hk, name);
+		return 0;
+	}
+
+	ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
+			    sizeof(_val));
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
+			   name, val, (int) GetLastError());
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_config_write_reg_string(HKEY hk, const char *name,
+				       const char *val)
+{
+	LONG ret;
+	TCHAR *_name, *_val;
+
+	_name = wpa_strdup_tchar(name);
+	if (_name == NULL)
+		return -1;
+
+	if (val == NULL) {
+		RegDeleteValue(hk, _name);
+		os_free(_name);
+		return 0;
+	}
+
+	_val = wpa_strdup_tchar(val);
+	if (_val == NULL) {
+		os_free(_name);
+		return -1;
+	}
+	ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
+			    (os_strlen(val) + 1) * sizeof(TCHAR));
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
+			   "error %d", name, val, (int) GetLastError());
+		os_free(_name);
+		os_free(_val);
+		return -1;
+	}
+
+	os_free(_name);
+	os_free(_val);
+	return 0;
+}
+
+
+static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
+{
+#ifdef CONFIG_CTRL_IFACE
+	wpa_config_write_reg_string(hk, "ctrl_interface",
+				    config->ctrl_interface);
+#endif /* CONFIG_CTRL_IFACE */
+
+	wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
+				   config->eapol_version,
+				   DEFAULT_EAPOL_VERSION);
+	wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
+				   DEFAULT_AP_SCAN);
+	wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
+				   config->fast_reauth, DEFAULT_FAST_REAUTH);
+	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+				   config->dot11RSNAConfigPMKLifetime, 0);
+	wpa_config_write_reg_dword(hk,
+				   TEXT("dot11RSNAConfigPMKReauthThreshold"),
+				   config->dot11RSNAConfigPMKReauthThreshold,
+				   0);
+	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+				   config->dot11RSNAConfigSATimeout, 0);
+	wpa_config_write_reg_dword(hk, TEXT("update_config"),
+				   config->update_config,
+				   0);
+#ifdef CONFIG_WPS
+	if (!is_nil_uuid(config->uuid)) {
+		char buf[40];
+		uuid_bin2str(config->uuid, buf, sizeof(buf));
+		wpa_config_write_reg_string(hk, "uuid", buf);
+	}
+	wpa_config_write_reg_string(hk, "device_name", config->device_name);
+	wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
+	wpa_config_write_reg_string(hk, "model_name", config->model_name);
+	wpa_config_write_reg_string(hk, "model_number", config->model_number);
+	wpa_config_write_reg_string(hk, "serial_number",
+				    config->serial_number);
+	{
+		char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+		buf = wps_dev_type_bin2str(config->device_type,
+					   _buf, sizeof(_buf));
+		wpa_config_write_reg_string(hk, "device_type", buf);
+	}
+	wpa_config_write_reg_string(hk, "config_methods",
+				    config->config_methods);
+	if (WPA_GET_BE32(config->os_version)) {
+		char vbuf[10];
+		os_snprintf(vbuf, sizeof(vbuf), "%08x",
+			    WPA_GET_BE32(config->os_version));
+		wpa_config_write_reg_string(hk, "os_version", vbuf);
+	}
+	wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
+				   config->wps_cred_processing, 0);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
+				    config->p2p_ssid_postfix);
+	wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
+				   config->p2p_group_idle, 0);
+#endif /* CONFIG_P2P */
+
+	wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
+				   config->bss_max_count,
+				   DEFAULT_BSS_MAX_COUNT);
+	wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
+				   config->filter_ssids, 0);
+	wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
+				   config->max_num_sta, DEFAULT_MAX_NUM_STA);
+	wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
+				   config->disassoc_low_ack, 0);
+
+	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
+	return 0;
+}
+
+
+static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
+{
+	HKEY nhk;
+	int i, errors = 0;
+	LONG ret;
+
+	ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
+			   "' for subkey deletion: error 0x%x (%d)", key,
+			   (unsigned int) ret, (int) GetLastError());
+		return 0;
+	}
+
+	for (i = 0; ; i++) {
+		TCHAR name[255];
+		DWORD namelen;
+
+		namelen = 255;
+		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+				   NULL);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
+				   (unsigned int) ret, (int) GetLastError());
+			break;
+		}
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = TEXT('\0');
+
+		ret = RegDeleteKey(nhk, name);
+		if (ret != ERROR_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
+				   (unsigned int) ret, (int) GetLastError());
+			errors++;
+		}
+	}
+
+	RegCloseKey(nhk);
+
+	return errors ? -1 : 0;
+}
+
+
+static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, field);
+	if (value == NULL)
+		return;
+	wpa_config_write_reg_string(hk, field, value);
+	os_free(value);
+}
+
+
+static void write_int(HKEY hk, const char *field, int value, int def)
+{
+	char val[20];
+	if (value == def)
+		return;
+	os_snprintf(val, sizeof(val), "%d", value);
+	wpa_config_write_reg_string(hk, field, val);
+}
+
+
+static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "bssid");
+	if (value == NULL)
+		return;
+	wpa_config_write_reg_string(hk, "bssid", value);
+	os_free(value);
+}
+
+
+static void write_psk(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "psk");
+	if (value == NULL)
+		return;
+	wpa_config_write_reg_string(hk, "psk", value);
+	os_free(value);
+}
+
+
+static void write_proto(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->proto == DEFAULT_PROTO)
+		return;
+
+	value = wpa_config_get(ssid, "proto");
+	if (value == NULL)
+		return;
+	if (value[0])
+		wpa_config_write_reg_string(hk, "proto", value);
+	os_free(value);
+}
+
+
+static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+		return;
+
+	value = wpa_config_get(ssid, "key_mgmt");
+	if (value == NULL)
+		return;
+	if (value[0])
+		wpa_config_write_reg_string(hk, "key_mgmt", value);
+	os_free(value);
+}
+
+
+static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
+		return;
+
+	value = wpa_config_get(ssid, "pairwise");
+	if (value == NULL)
+		return;
+	if (value[0])
+		wpa_config_write_reg_string(hk, "pairwise", value);
+	os_free(value);
+}
+
+
+static void write_group(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->group_cipher == DEFAULT_GROUP)
+		return;
+
+	value = wpa_config_get(ssid, "group");
+	if (value == NULL)
+		return;
+	if (value[0])
+		wpa_config_write_reg_string(hk, "group", value);
+	os_free(value);
+}
+
+
+static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	if (ssid->auth_alg == 0)
+		return;
+
+	value = wpa_config_get(ssid, "auth_alg");
+	if (value == NULL)
+		return;
+	if (value[0])
+		wpa_config_write_reg_string(hk, "auth_alg", value);
+	os_free(value);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void write_eap(HKEY hk, struct wpa_ssid *ssid)
+{
+	char *value;
+
+	value = wpa_config_get(ssid, "eap");
+	if (value == NULL)
+		return;
+
+	if (value[0])
+		wpa_config_write_reg_string(hk, "eap", value);
+	os_free(value);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
+{
+	char field[20], *value;
+
+	os_snprintf(field, sizeof(field), "wep_key%d", idx);
+	value = wpa_config_get(ssid, field);
+	if (value) {
+		wpa_config_write_reg_string(hk, field, value);
+		os_free(value);
+	}
+}
+
+
+static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
+{
+	int i, errors = 0;
+	HKEY nhk, netw;
+	LONG ret;
+	TCHAR name[5];
+
+	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
+			   "for subkey addition: error 0x%x (%d)",
+			   (unsigned int) ret, (int) GetLastError());
+		return 0;
+	}
+
+#ifdef UNICODE
+	wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+	os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+	ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
+			     NULL);
+	RegCloseKey(nhk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
+			   " error 0x%x (%d)",
+			   name, (unsigned int) ret, (int) GetLastError());
+		return -1;
+	}
+
+#define STR(t) write_str(netw, #t, ssid)
+#define INT(t) write_int(netw, #t, ssid->t, 0)
+#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
+#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
+#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
+
+	STR(ssid);
+	INT(scan_ssid);
+	write_bssid(netw, ssid);
+	write_psk(netw, ssid);
+	write_proto(netw, ssid);
+	write_key_mgmt(netw, ssid);
+	write_pairwise(netw, ssid);
+	write_group(netw, ssid);
+	write_auth_alg(netw, ssid);
+#ifdef IEEE8021X_EAPOL
+	write_eap(netw, ssid);
+	STR(identity);
+	STR(anonymous_identity);
+	STR(password);
+	STR(ca_cert);
+	STR(ca_path);
+	STR(client_cert);
+	STR(private_key);
+	STR(private_key_passwd);
+	STR(dh_file);
+	STR(subject_match);
+	STR(altsubject_match);
+	STR(ca_cert2);
+	STR(ca_path2);
+	STR(client_cert2);
+	STR(private_key2);
+	STR(private_key2_passwd);
+	STR(dh_file2);
+	STR(subject_match2);
+	STR(altsubject_match2);
+	STR(phase1);
+	STR(phase2);
+	STR(pcsc);
+	STR(pin);
+	STR(engine_id);
+	STR(key_id);
+	STR(cert_id);
+	STR(ca_cert_id);
+	STR(key2_id);
+	STR(pin2);
+	STR(engine2_id);
+	STR(cert2_id);
+	STR(ca_cert2_id);
+	INTe(engine);
+	INTe(engine2);
+	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
+	for (i = 0; i < 4; i++)
+		write_wep_key(netw, i, ssid);
+	INT(wep_tx_keyidx);
+	INT(priority);
+#ifdef IEEE8021X_EAPOL
+	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+	STR(pac_file);
+	INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
+	INT(mode);
+	write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+		  -1);
+	INT(disabled);
+	INT(peerkey);
+#ifdef CONFIG_IEEE80211W
+	write_int(netw, "ieee80211w", ssid->ieee80211w,
+		  MGMT_FRAME_PROTECTION_DEFAULT);
+#endif /* CONFIG_IEEE80211W */
+	STR(id_str);
+
+#undef STR
+#undef INT
+#undef INT_DEF
+
+	RegCloseKey(netw);
+
+	return errors ? -1 : 0;
+}
+
+
+static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
+{
+	HKEY bhk;
+	LONG ret;
+	TCHAR *name;
+
+	ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
+			     &bhk, NULL);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
+			   "error 0x%x (%d)",
+			   (unsigned int) ret, (int) GetLastError());
+		return -1;
+	}
+
+	name = wpa_strdup_tchar(blob->name);
+	ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
+			    blob->len);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
+			   "error 0x%x (%d)", blob->name, (unsigned int) ret,
+			   (int) GetLastError());
+		RegCloseKey(bhk);
+		os_free(name);
+		return -1;
+	}
+	os_free(name);
+
+	RegCloseKey(bhk);
+
+	return 0;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+	TCHAR buf[256];
+	HKEY hk;
+	LONG ret;
+	int errors = 0;
+	struct wpa_ssid *ssid;
+	struct wpa_config_blob *blob;
+	int id;
+
+	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+#ifdef UNICODE
+	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
+	if (ret != ERROR_SUCCESS) {
+		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+			   "configuration registry %s: error %d", buf,
+			   (int) GetLastError());
+		return -1;
+	}
+
+	if (wpa_config_write_global(config, hk)) {
+		wpa_printf(MSG_ERROR, "Failed to write global configuration "
+			   "data");
+		errors++;
+	}
+
+	wpa_config_delete_subkeys(hk, TEXT("networks"));
+	for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+			continue; /* do not save temporary WPS networks */
+		if (wpa_config_write_network(hk, ssid, id))
+			errors++;
+	}
+
+	RegDeleteKey(hk, TEXT("blobs"));
+	for (blob = config->blobs; blob; blob = blob->next) {
+		if (wpa_config_write_blob(hk, blob))
+			errors++;
+	}
+
+	RegCloseKey(hk);
+
+	wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
+		   name, errors ? "un" : "");
+	return errors ? -1 : 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ctrl_iface.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2142 +0,0 @@
-/*
- * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
-#include "eap_peer/eap.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/preauth.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "l2_packet/l2_packet.h"
-#include "wps/wps.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "wps_supplicant.h"
-#include "ibss_rsn.h"
-#include "ap.h"
-#include "notify.h"
-#include "bss.h"
-#include "scan.h"
-#include "ctrl_iface.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-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,
-						  char *buf, int len);
-
-
-static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
-					 char *cmd)
-{
-	char *value;
-	int ret = 0;
-
-	value = os_strchr(cmd, ' ');
-	if (value == NULL)
-		return -1;
-	*value++ = '\0';
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
-	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
-		eapol_sm_configure(wpa_s->eapol,
-				   atoi(value), -1, -1, -1);
-	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
-		eapol_sm_configure(wpa_s->eapol,
-				   -1, atoi(value), -1, -1);
-	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
-		eapol_sm_configure(wpa_s->eapol,
-				   -1, -1, atoi(value), -1);
-	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
-		eapol_sm_configure(wpa_s->eapol,
-				   -1, -1, -1, atoi(value));
-	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
-		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
-				     atoi(value)))
-			ret = -1;
-	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
-		   0) {
-		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
-				     atoi(value)))
-			ret = -1;
-	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
-		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
-			ret = -1;
-	} else
-		ret = -1;
-
-	return ret;
-}
-
-
-#ifdef IEEE8021X_EAPOL
-static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
-					     char *addr)
-{
-	u8 bssid[ETH_ALEN];
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	if (hwaddr_aton(addr, bssid)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
-			   "'%s'", addr);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
-	rsn_preauth_deinit(wpa_s->wpa);
-	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
-		return -1;
-
-	return 0;
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-#ifdef CONFIG_PEERKEY
-/* MLME-STKSTART.request(peer) */
-static int wpa_supplicant_ctrl_iface_stkstart(
-	struct wpa_supplicant *wpa_s, char *addr)
-{
-	u8 peer[ETH_ALEN];
-
-	if (hwaddr_aton(addr, peer)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
-			   "address '%s'", addr);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
-		   MAC2STR(peer));
-
-	return wpa_sm_stkstart(wpa_s->wpa, peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
-#ifdef CONFIG_IEEE80211R
-static int wpa_supplicant_ctrl_iface_ft_ds(
-	struct wpa_supplicant *wpa_s, char *addr)
-{
-	u8 target_ap[ETH_ALEN];
-	struct wpa_bss *bss;
-	const u8 *mdie;
-
-	if (hwaddr_aton(addr, target_ap)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
-			   "address '%s'", addr);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
-
-	bss = wpa_bss_get_bssid(wpa_s, target_ap);
-	if (bss)
-		mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
-	else
-		mdie = NULL;
-
-	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_WPS
-static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
-					     char *cmd)
-{
-	u8 bssid[ETH_ALEN], *_bssid = bssid;
-
-	if (cmd == NULL || os_strcmp(cmd, "any") == 0)
-		_bssid = NULL;
-	else if (hwaddr_aton(cmd, bssid)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
-			   cmd);
-		return -1;
-	}
-
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface)
-		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
-#endif /* CONFIG_AP */
-
-	return wpas_wps_start_pbc(wpa_s, _bssid);
-}
-
-
-static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
-					     char *cmd, char *buf,
-					     size_t buflen)
-{
-	u8 bssid[ETH_ALEN], *_bssid = bssid;
-	char *pin;
-	int ret;
-
-	pin = os_strchr(cmd, ' ');
-	if (pin)
-		*pin++ = '\0';
-
-	if (os_strcmp(cmd, "any") == 0)
-		_bssid = NULL;
-	else if (hwaddr_aton(cmd, bssid)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
-			   cmd);
-		return -1;
-	}
-
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface)
-		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
-						 buf, buflen);
-#endif /* CONFIG_AP */
-
-	if (pin) {
-		ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
-		if (ret < 0)
-			return -1;
-		ret = os_snprintf(buf, buflen, "%s", pin);
-		if (ret < 0 || (size_t) ret >= buflen)
-			return -1;
-		return ret;
-	}
-
-	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
-	if (ret < 0)
-		return -1;
-
-	/* Return the generated PIN */
-	ret = os_snprintf(buf, buflen, "%08d", ret);
-	if (ret < 0 || (size_t) ret >= buflen)
-		return -1;
-	return ret;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
-					     char *cmd)
-{
-	char *path, *method, *name;
-
-	path = os_strchr(cmd, ' ');
-	if (path == NULL)
-		return -1;
-	*path++ = '\0';
-
-	method = os_strchr(path, ' ');
-	if (method == NULL)
-		return -1;
-	*method++ = '\0';
-
-	name = os_strchr(method, ' ');
-	if (name != NULL)
-		*name++ = '\0';
-
-	return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
-					     char *cmd)
-{
-	u8 bssid[ETH_ALEN], *_bssid = bssid;
-	char *pin;
-	char *new_ssid;
-	char *new_auth;
-	char *new_encr;
-	char *new_key;
-	struct wps_new_ap_settings ap;
-
-	pin = os_strchr(cmd, ' ');
-	if (pin == NULL)
-		return -1;
-	*pin++ = '\0';
-
-	if (os_strcmp(cmd, "any") == 0)
-		_bssid = NULL;
-	else if (hwaddr_aton(cmd, bssid)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
-			   cmd);
-		return -1;
-	}
-
-	new_ssid = os_strchr(pin, ' ');
-	if (new_ssid == NULL)
-		return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
-	*new_ssid++ = '\0';
-
-	new_auth = os_strchr(new_ssid, ' ');
-	if (new_auth == NULL)
-		return -1;
-	*new_auth++ = '\0';
-
-	new_encr = os_strchr(new_auth, ' ');
-	if (new_encr == NULL)
-		return -1;
-	*new_encr++ = '\0';
-
-	new_key = os_strchr(new_encr, ' ');
-	if (new_key == NULL)
-		return -1;
-	*new_key++ = '\0';
-
-	os_memset(&ap, 0, sizeof(ap));
-	ap.ssid_hex = new_ssid;
-	ap.auth = new_auth;
-	ap.encr = new_encr;
-	ap.key_hex = new_key;
-	return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
-}
-
-
-#ifdef CONFIG_WPS_ER
-static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
-						char *cmd)
-{
-	char *uuid = cmd, *pin;
-	pin = os_strchr(uuid, ' ');
-	if (pin == NULL)
-		return -1;
-	*pin++ = '\0';
-	return wpas_wps_er_add_pin(wpa_s, uuid, pin);
-}
-
-
-static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
-						  char *cmd)
-{
-	char *uuid = cmd, *pin;
-	pin = os_strchr(uuid, ' ');
-	if (pin == NULL)
-		return -1;
-	*pin++ = '\0';
-	return wpas_wps_er_learn(wpa_s, uuid, pin);
-}
-#endif /* CONFIG_WPS_ER */
-
-#endif /* CONFIG_WPS */
-
-
-#ifdef CONFIG_IBSS_RSN
-static int wpa_supplicant_ctrl_iface_ibss_rsn(
-	struct wpa_supplicant *wpa_s, char *addr)
-{
-	u8 peer[ETH_ALEN];
-
-	if (hwaddr_aton(addr, peer)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
-			   "address '%s'", addr);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
-		   MAC2STR(peer));
-
-	return ibss_rsn_start(wpa_s->ibss_rsn, peer);
-}
-#endif /* CONFIG_IBSS_RSN */
-
-
-static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
-					      char *rsp)
-{
-#ifdef IEEE8021X_EAPOL
-	char *pos, *id_pos;
-	int id;
-	struct wpa_ssid *ssid;
-	struct eap_peer_config *eap;
-
-	pos = os_strchr(rsp, '-');
-	if (pos == NULL)
-		return -1;
-	*pos++ = '\0';
-	id_pos = pos;
-	pos = os_strchr(pos, ':');
-	if (pos == NULL)
-		return -1;
-	*pos++ = '\0';
-	id = atoi(id_pos);
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
-			      (u8 *) pos, os_strlen(pos));
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
-			   "to update", id);
-		return -1;
-	}
-	eap = &ssid->eap;
-
-	if (os_strcmp(rsp, "IDENTITY") == 0) {
-		os_free(eap->identity);
-		eap->identity = (u8 *) os_strdup(pos);
-		eap->identity_len = os_strlen(pos);
-		eap->pending_req_identity = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "PASSWORD") == 0) {
-		os_free(eap->password);
-		eap->password = (u8 *) os_strdup(pos);
-		eap->password_len = os_strlen(pos);
-		eap->pending_req_password = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
-		os_free(eap->new_password);
-		eap->new_password = (u8 *) os_strdup(pos);
-		eap->new_password_len = os_strlen(pos);
-		eap->pending_req_new_password = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "PIN") == 0) {
-		os_free(eap->pin);
-		eap->pin = os_strdup(pos);
-		eap->pending_req_pin = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "OTP") == 0) {
-		os_free(eap->otp);
-		eap->otp = (u8 *) os_strdup(pos);
-		eap->otp_len = os_strlen(pos);
-		os_free(eap->pending_req_otp);
-		eap->pending_req_otp = NULL;
-		eap->pending_req_otp_len = 0;
-	} else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
-		os_free(eap->private_key_passwd);
-		eap->private_key_passwd = (u8 *) os_strdup(pos);
-		eap->pending_req_passphrase = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
-		return -1;
-	}
-
-	return 0;
-#else /* IEEE8021X_EAPOL */
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
-	return -1;
-#endif /* IEEE8021X_EAPOL */
-}
-
-
-static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
-					    const char *params,
-					    char *buf, size_t buflen)
-{
-	char *pos, *end, tmp[30];
-	int res, verbose, ret;
-
-	verbose = os_strcmp(params, "-VERBOSE") == 0;
-	pos = buf;
-	end = buf + buflen;
-	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
-		struct wpa_ssid *ssid = wpa_s->current_ssid;
-		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
-				  MAC2STR(wpa_s->bssid));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		if (ssid) {
-			u8 *_ssid = ssid->ssid;
-			size_t ssid_len = ssid->ssid_len;
-			u8 ssid_buf[MAX_SSID_LEN];
-			if (ssid_len == 0) {
-				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
-				if (_res < 0)
-					ssid_len = 0;
-				else
-					ssid_len = _res;
-				_ssid = ssid_buf;
-			}
-			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
-					  wpa_ssid_txt(_ssid, ssid_len),
-					  ssid->id);
-			if (ret < 0 || ret >= end - pos)
-				return pos - buf;
-			pos += ret;
-
-			if (ssid->id_str) {
-				ret = os_snprintf(pos, end - pos,
-						  "id_str=%s\n",
-						  ssid->id_str);
-				if (ret < 0 || ret >= end - pos)
-					return pos - buf;
-				pos += ret;
-			}
-
-			switch (ssid->mode) {
-			case WPAS_MODE_INFRA:
-				ret = os_snprintf(pos, end - pos,
-						  "mode=station\n");
-				break;
-			case WPAS_MODE_IBSS:
-				ret = os_snprintf(pos, end - pos,
-						  "mode=IBSS\n");
-				break;
-			case WPAS_MODE_AP:
-				ret = os_snprintf(pos, end - pos,
-						  "mode=AP\n");
-				break;
-			default:
-				ret = 0;
-				break;
-			}
-			if (ret < 0 || ret >= end - pos)
-				return pos - buf;
-			pos += ret;
-		}
-
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface) {
-			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
-							    end - pos,
-							    verbose);
-		} else
-#endif /* CONFIG_AP */
-		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
-	}
-	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
-			  wpa_supplicant_state_txt(wpa_s->wpa_state));
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	if (wpa_s->l2 &&
-	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
-		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
-					  verbose);
-		if (res >= 0)
-			pos += res;
-	}
-
-	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
-	if (res >= 0)
-		pos += res;
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
-					   char *cmd)
-{
-	char *pos;
-	int id;
-	struct wpa_ssid *ssid;
-	u8 bssid[ETH_ALEN];
-
-	/* cmd: "<network id> <BSSID>" */
-	pos = os_strchr(cmd, ' ');
-	if (pos == NULL)
-		return -1;
-	*pos++ = '\0';
-	id = atoi(cmd);
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
-	if (hwaddr_aton(pos, bssid)) {
-		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
-		return -1;
-	}
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
-			   "to update", id);
-		return -1;
-	}
-
-	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
-	ssid->bssid_set = !is_zero_ether_addr(bssid);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_list_networks(
-	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
-{
-	char *pos, *end;
-	struct wpa_ssid *ssid;
-	int ret;
-
-	pos = buf;
-	end = buf + buflen;
-	ret = os_snprintf(pos, end - pos,
-			  "network id / ssid / bssid / flags\n");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ssid = wpa_s->conf->ssid;
-	while (ssid) {
-		ret = os_snprintf(pos, end - pos, "%d\t%s",
-				  ssid->id,
-				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		if (ssid->bssid_set) {
-			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
-					  MAC2STR(ssid->bssid));
-		} else {
-			ret = os_snprintf(pos, end - pos, "\tany");
-		}
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		ret = os_snprintf(pos, end - pos, "\t%s%s",
-				  ssid == wpa_s->current_ssid ?
-				  "[CURRENT]" : "",
-				  ssid->disabled ? "[DISABLED]" : "");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-
-		ssid = ssid->next;
-	}
-
-	return pos - buf;
-}
-
-
-static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
-{
-	int first = 1, ret;
-	ret = os_snprintf(pos, end - pos, "-");
-	if (ret < 0 || ret >= end - pos)
-		return pos;
-	pos += ret;
-	if (cipher & WPA_CIPHER_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (cipher & WPA_CIPHER_WEP40) {
-		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (cipher & WPA_CIPHER_WEP104) {
-		ret = os_snprintf(pos, end - pos, "%sWEP104",
-				  first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (cipher & WPA_CIPHER_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (cipher & WPA_CIPHER_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	return pos;
-}
-
-
-static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
-				    const u8 *ie, size_t ie_len)
-{
-	struct wpa_ie_data data;
-	int first, ret;
-
-	ret = os_snprintf(pos, end - pos, "[%s-", proto);
-	if (ret < 0 || ret >= end - pos)
-		return pos;
-	pos += ret;
-
-	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
-		ret = os_snprintf(pos, end - pos, "?]");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		return pos;
-	}
-
-	first = 1;
-	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
-		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
-		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-#ifdef CONFIG_IEEE80211R
-	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
-		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
-				  first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
-		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
-				  first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
-		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
-				  first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
-		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
-				  first ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-		first = 0;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
-
-	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
-		ret = os_snprintf(pos, end - pos, "-preauth");
-		if (ret < 0 || ret >= end - pos)
-			return pos;
-		pos += ret;
-	}
-
-	ret = os_snprintf(pos, end - pos, "]");
-	if (ret < 0 || ret >= end - pos)
-		return pos;
-	pos += ret;
-
-	return pos;
-}
-
-
-#ifdef CONFIG_WPS
-static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
-					    struct wpabuf *wps_ie)
-{
-	int ret;
-	const char *txt;
-
-	if (wps_ie == NULL)
-		return pos;
-	if (wps_is_selected_pbc_registrar(wps_ie))
-		txt = "[WPS-PBC]";
-	else if (wps_is_selected_pin_registrar(wps_ie))
-		txt = "[WPS-PIN]";
-	else
-		txt = "[WPS]";
-
-	ret = os_snprintf(pos, end - pos, "%s", txt);
-	if (ret >= 0 && ret < end - pos)
-		pos += ret;
-	wpabuf_free(wps_ie);
-	return pos;
-}
-#endif /* CONFIG_WPS */
-
-
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
-					const struct wpa_bss *bss)
-{
-#ifdef CONFIG_WPS
-	struct wpabuf *wps_ie;
-	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-	return wpa_supplicant_wps_ie_txt_buf(pos, end, wps_ie);
-#else /* CONFIG_WPS */
-	return pos;
-#endif /* CONFIG_WPS */
-}
-
-
-/* Format one result on one text line into a buffer. */
-static int wpa_supplicant_ctrl_iface_scan_result(
-	const struct wpa_bss *bss, char *buf, size_t buflen)
-{
-	char *pos, *end;
-	int ret;
-	const u8 *ie, *ie2;
-
-	pos = buf;
-	end = buf + buflen;
-
-	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
-			  MAC2STR(bss->bssid), bss->freq, bss->level);
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	if (ie)
-		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
-	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie2)
-		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-	pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
-	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
-		ret = os_snprintf(pos, end - pos, "[WEP]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-	if (bss->caps & IEEE80211_CAP_IBSS) {
-		ret = os_snprintf(pos, end - pos, "[IBSS]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-	if (bss->caps & IEEE80211_CAP_ESS) {
-		ret = os_snprintf(pos, end - pos, "[ESS]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	ret = os_snprintf(pos, end - pos, "\t%s",
-			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ret = os_snprintf(pos, end - pos, "\n");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_ctrl_iface_scan_results(
-	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
-{
-	char *pos, *end;
-	struct wpa_bss *bss;
-	int ret;
-
-	pos = buf;
-	end = buf + buflen;
-	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
-			  "flags / ssid\n");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
-		ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
-							    end - pos);
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_ctrl_iface_select_network(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int id;
-	struct wpa_ssid *ssid;
-
-	/* cmd: "<network id>" or "any" */
-	if (os_strcmp(cmd, "any") == 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
-		ssid = NULL;
-	} else {
-		id = atoi(cmd);
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
-
-		ssid = wpa_config_get_network(wpa_s->conf, id);
-		if (ssid == NULL) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
-				   "network id=%d", id);
-			return -1;
-		}
-	}
-
-	wpa_supplicant_select_network(wpa_s, ssid);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_enable_network(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int id;
-	struct wpa_ssid *ssid;
-
-	/* cmd: "<network id>" or "all" */
-	if (os_strcmp(cmd, "all") == 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
-		ssid = NULL;
-	} else {
-		id = atoi(cmd);
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
-
-		ssid = wpa_config_get_network(wpa_s->conf, id);
-		if (ssid == NULL) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
-				   "network id=%d", id);
-			return -1;
-		}
-	}
-	wpa_supplicant_enable_network(wpa_s, ssid);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_disable_network(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int id;
-	struct wpa_ssid *ssid;
-
-	/* cmd: "<network id>" or "all" */
-	if (os_strcmp(cmd, "all") == 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
-		ssid = NULL;
-	} else {
-		id = atoi(cmd);
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
-
-		ssid = wpa_config_get_network(wpa_s->conf, id);
-		if (ssid == NULL) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
-				   "network id=%d", id);
-			return -1;
-		}
-	}
-	wpa_supplicant_disable_network(wpa_s, ssid);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_add_network(
-	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
-{
-	struct wpa_ssid *ssid;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
-
-	ssid = wpa_config_add_network(wpa_s->conf);
-	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 (ret < 0 || (size_t) ret >= buflen)
-		return -1;
-	return ret;
-}
-
-
-static int wpa_supplicant_ctrl_iface_remove_network(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int id;
-	struct wpa_ssid *ssid;
-
-	/* cmd: "<network id>" or "all" */
-	if (os_strcmp(cmd, "all") == 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
-		ssid = wpa_s->conf->ssid;
-		while (ssid) {
-			struct wpa_ssid *remove_ssid = ssid;
-			id = ssid->id;
-			ssid = ssid->next;
-			wpas_notify_network_removed(wpa_s, remove_ssid);
-			wpa_config_remove_network(wpa_s->conf, id);
-		}
-		if (wpa_s->current_ssid) {
-			eapol_sm_invalidate_cached_session(wpa_s->eapol);
-			wpa_supplicant_disassociate(wpa_s,
-				                    WLAN_REASON_DEAUTH_LEAVING);
-		}
-		return 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 == NULL ||
-	    wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-			   "id=%d", id);
-		return -1;
-	}
-
-	if (ssid == wpa_s->current_ssid) {
-		/*
-		 * Invalidate the EAP session cache if the current network is
-		 * removed.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-
-		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_set_network(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int id;
-	struct wpa_ssid *ssid;
-	char *name, *value;
-
-	/* cmd: "<network id> <variable name> <value>" */
-	name = os_strchr(cmd, ' ');
-	if (name == NULL)
-		return -1;
-	*name++ = '\0';
-
-	value = os_strchr(name, ' ');
-	if (value == NULL)
-		return -1;
-	*value++ = '\0';
-
-	id = atoi(cmd);
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
-		   id, name);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
-			      (u8 *) value, os_strlen(value));
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-			   "id=%d", id);
-		return -1;
-	}
-
-	if (wpa_config_set(ssid, name, value, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
-			   "variable '%s'", name);
-		return -1;
-	}
-
-	if (wpa_s->current_ssid == ssid) {
-		/*
-		 * Invalidate the EAP session cache if anything in the current
-		 * configuration changes.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	}
-
-	if ((os_strcmp(name, "psk") == 0 &&
-	     value[0] == '"' && ssid->ssid_len) ||
-	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
-		wpa_config_update_psk(ssid);
-	else if (os_strcmp(name, "priority") == 0)
-		wpa_config_update_prio_list(wpa_s->conf);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_get_network(
-	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
-{
-	int id;
-	size_t res;
-	struct wpa_ssid *ssid;
-	char *name, *value;
-
-	/* cmd: "<network id> <variable name>" */
-	name = os_strchr(cmd, ' ');
-	if (name == NULL || buflen == 0)
-		return -1;
-	*name++ = '\0';
-
-	id = atoi(cmd);
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
-		   id, name);
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-			   "id=%d", id);
-		return -1;
-	}
-
-	value = wpa_config_get_no_key(ssid, name);
-	if (value == NULL) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
-			   "variable '%s'", name);
-		return -1;
-	}
-
-	res = os_strlcpy(buf, value, buflen);
-	if (res >= buflen) {
-		os_free(value);
-		return -1;
-	}
-
-	os_free(value);
-
-	return res;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_WRITE
-static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
-{
-	int ret;
-
-	if (!wpa_s->conf->update_config) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
-			   "to update configuration (update_config=0)");
-		return -1;
-	}
-
-	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
-			   "update configuration");
-	} else {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
-			   " updated");
-	}
-
-	return ret;
-}
-#endif /* CONFIG_NO_CONFIG_WRITE */
-
-
-static int ctrl_iface_get_capability_pairwise(int res, char *strict,
-					      struct wpa_driver_capa *capa,
-					      char *buf, size_t buflen)
-{
-	int ret, first = 1;
-	char *pos, *end;
-	size_t len;
-
-	pos = buf;
-	end = pos + buflen;
-
-	if (res < 0) {
-		if (strict)
-			return 0;
-		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
-		if (len >= buflen)
-			return -1;
-		return len;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	return pos - buf;
-}
-
-
-static int ctrl_iface_get_capability_group(int res, char *strict,
-					   struct wpa_driver_capa *capa,
-					   char *buf, size_t buflen)
-{
-	int ret, first = 1;
-	char *pos, *end;
-	size_t len;
-
-	pos = buf;
-	end = pos + buflen;
-
-	if (res < 0) {
-		if (strict)
-			return 0;
-		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
-		if (len >= buflen)
-			return -1;
-		return len;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-		ret = os_snprintf(pos, end - pos, "%sWEP104",
-				  first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	return pos - buf;
-}
-
-
-static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
-					      struct wpa_driver_capa *capa,
-					      char *buf, size_t buflen)
-{
-	int ret;
-	char *pos, *end;
-	size_t len;
-
-	pos = buf;
-	end = pos + buflen;
-
-	if (res < 0) {
-		if (strict)
-			return 0;
-		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
-				 "NONE", buflen);
-		if (len >= buflen)
-			return -1;
-		return len;
-	}
-
-	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
-		ret = os_snprintf(pos, end - pos, " WPA-EAP");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-		ret = os_snprintf(pos, end - pos, " WPA-PSK");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-		ret = os_snprintf(pos, end - pos, " WPA-NONE");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	return pos - buf;
-}
-
-
-static int ctrl_iface_get_capability_proto(int res, char *strict,
-					   struct wpa_driver_capa *capa,
-					   char *buf, size_t buflen)
-{
-	int ret, first = 1;
-	char *pos, *end;
-	size_t len;
-
-	pos = buf;
-	end = pos + buflen;
-
-	if (res < 0) {
-		if (strict)
-			return 0;
-		len = os_strlcpy(buf, "RSN WPA", buflen);
-		if (len >= buflen)
-			return -1;
-		return len;
-	}
-
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	return pos - buf;
-}
-
-
-static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
-					      struct wpa_driver_capa *capa,
-					      char *buf, size_t buflen)
-{
-	int ret, first = 1;
-	char *pos, *end;
-	size_t len;
-
-	pos = buf;
-	end = pos + buflen;
-
-	if (res < 0) {
-		if (strict)
-			return 0;
-		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
-		if (len >= buflen)
-			return -1;
-		return len;
-	}
-
-	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
-		ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
-		ret = os_snprintf(pos, end - pos, "%sSHARED",
-				  first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
-		ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-		first = 0;
-	}
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_ctrl_iface_get_capability(
-	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
-	size_t buflen)
-{
-	struct wpa_driver_capa capa;
-	int res;
-	char *strict;
-	char field[30];
-	size_t len;
-
-	/* Determine whether or not strict checking was requested */
-	len = os_strlcpy(field, _field, sizeof(field));
-	if (len >= sizeof(field))
-		return -1;
-	strict = os_strchr(field, ' ');
-	if (strict != NULL) {
-		*strict++ = '\0';
-		if (os_strcmp(strict, "strict") != 0)
-			return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
-		field, strict ? strict : "");
-
-	if (os_strcmp(field, "eap") == 0) {
-		return eap_get_names(buf, buflen);
-	}
-
-	res = wpa_drv_get_capa(wpa_s, &capa);
-
-	if (os_strcmp(field, "pairwise") == 0)
-		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
-							  buf, buflen);
-
-	if (os_strcmp(field, "group") == 0)
-		return ctrl_iface_get_capability_group(res, strict, &capa,
-						       buf, buflen);
-
-	if (os_strcmp(field, "key_mgmt") == 0)
-		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
-							  buf, buflen);
-
-	if (os_strcmp(field, "proto") == 0)
-		return ctrl_iface_get_capability_proto(res, strict, &capa,
-						       buf, buflen);
-
-	if (os_strcmp(field, "auth_alg") == 0)
-		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
-							  buf, buflen);
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
-		   field);
-
-	return -1;
-}
-
-
-static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
-					 const char *cmd, char *buf,
-					 size_t buflen)
-{
-	u8 bssid[ETH_ALEN];
-	size_t i;
-	struct wpa_bss *bss;
-	int ret;
-	char *pos, *end;
-	const u8 *ie, *ie2;
-
-	if (os_strcmp(cmd, "FIRST") == 0)
-		bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
-	else if (os_strncmp(cmd, "ID-", 3) == 0) {
-		i = atoi(cmd + 3);
-		bss = wpa_bss_get_id(wpa_s, i);
-	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
-		i = atoi(cmd + 5);
-		bss = wpa_bss_get_id(wpa_s, i);
-		if (bss) {
-			struct dl_list *next = bss->list_id.next;
-			if (next == &wpa_s->bss_id)
-				bss = NULL;
-			else
-				bss = dl_list_entry(next, struct wpa_bss,
-						    list_id);
-		}
-	} else if (hwaddr_aton(cmd, bssid) == 0)
-		bss = wpa_bss_get_bssid(wpa_s, bssid);
-	else {
-		struct wpa_bss *tmp;
-		i = atoi(cmd);
-		bss = NULL;
-		dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
-		{
-			if (i-- == 0) {
-				bss = tmp;
-				break;
-			}
-		}
-	}
-
-	if (bss == NULL)
-		return 0;
-
-	pos = buf;
-	end = buf + buflen;
-	ret = os_snprintf(pos, end - pos,
-			  "id=%u\n"
-			  "bssid=" MACSTR "\n"
-			  "freq=%d\n"
-			  "beacon_int=%d\n"
-			  "capabilities=0x%04x\n"
-			  "qual=%d\n"
-			  "noise=%d\n"
-			  "level=%d\n"
-			  "tsf=%016llu\n"
-			  "ie=",
-			  bss->id,
-			  MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
-			  bss->caps, bss->qual, bss->noise, bss->level,
-			  (unsigned long long) bss->tsf);
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ie = (const u8 *) (bss + 1);
-	for (i = 0; i < bss->ie_len; i++) {
-		ret = os_snprintf(pos, end - pos, "%02x", *ie++);
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	ret = os_snprintf(pos, end - pos, "\n");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ret = os_snprintf(pos, end - pos, "flags=");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	if (ie)
-		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
-	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie2)
-		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-	pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
-	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
-		ret = os_snprintf(pos, end - pos, "[WEP]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-	if (bss->caps & IEEE80211_CAP_IBSS) {
-		ret = os_snprintf(pos, end - pos, "[IBSS]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-	if (bss->caps & IEEE80211_CAP_ESS) {
-		ret = os_snprintf(pos, end - pos, "[ESS]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
-
-	ret = os_snprintf(pos, end - pos, "\n");
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-	ret = os_snprintf(pos, end - pos, "ssid=%s\n",
-			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-
-#ifdef CONFIG_WPS
-	ie = (const u8 *) (bss + 1);
-	ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
-	if (ret < 0 || ret >= end - pos)
-		return pos - buf;
-	pos += ret;
-#endif /* CONFIG_WPS */
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_ctrl_iface_ap_scan(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	int ap_scan = atoi(cmd);
-	return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
-}
-
-
-static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
-{
-	u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
-
-	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
-	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
-
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
-			0);
-	/* MLME-SETPROTECTION.request(None) */
-	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
-				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
-				   MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
-	wpa_sm_drop_sa(wpa_s->wpa);
-}
-
-
-static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
-					  char *addr)
-{
-	u8 bssid[ETH_ALEN];
-	struct wpa_bss *bss;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	if (hwaddr_aton(addr, bssid)) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
-			   "address '%s'", addr);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
-
-	bss = wpa_bss_get_bssid(wpa_s, bssid);
-	if (!bss) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
-			   "from BSS table");
-		return -1;
-	}
-
-	/*
-	 * TODO: Find best network configuration block from configuration to
-	 * allow roaming to other networks
-	 */
-
-	if (!ssid) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
-			   "configuration known for the target AP");
-		return -1;
-	}
-
-	wpa_s->reassociate = 1;
-	wpa_supplicant_connect(wpa_s, bss, ssid);
-
-	return 0;
-}
-
-
-char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
-					 char *buf, size_t *resp_len)
-{
-	char *reply;
-	const int reply_size = 2048;
-	int ctrl_rsp = 0;
-	int reply_len;
-
-	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
-	    os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
-		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
-				      (const u8 *) buf, os_strlen(buf));
-	} else {
-		wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
-				  (const u8 *) buf, os_strlen(buf));
-	}
-
-	reply = os_malloc(reply_size);
-	if (reply == NULL) {
-		*resp_len = 1;
-		return NULL;
-	}
-
-	os_memcpy(reply, "OK\n", 3);
-	reply_len = 3;
-
-	if (os_strcmp(buf, "PING") == 0) {
-		os_memcpy(reply, "PONG\n", 5);
-		reply_len = 5;
-	} else if (os_strcmp(buf, "MIB") == 0) {
-		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
-		if (reply_len >= 0) {
-			int res;
-			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
-					       reply_size - reply_len);
-			if (res < 0)
-				reply_len = -1;
-			else
-				reply_len += res;
-		}
-	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
-		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);
-	} else if (os_strncmp(buf, "SET ", 4) == 0) {
-		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "LOGON") == 0) {
-		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
-	} else if (os_strcmp(buf, "LOGOFF") == 0) {
-		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
-	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
-		wpa_s->disconnected = 0;
-		wpa_s->reassociate = 1;
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-	} else if (os_strcmp(buf, "RECONNECT") == 0) {
-		if (wpa_s->disconnected) {
-			wpa_s->disconnected = 0;
-			wpa_s->reassociate = 1;
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-		}
-#ifdef IEEE8021X_EAPOL
-	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
-			reply_len = -1;
-#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_PEERKEY
-	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
-		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
-			reply_len = -1;
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
-	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
-		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
-			reply_len = -1;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_WPS
-	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
-							      reply,
-							      reply_size);
-#ifdef CONFIG_WPS_OOB
-	} else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
-			reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
-	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
-			reply_len = -1;
-#ifdef CONFIG_WPS_ER
-	} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
-		if (wpas_wps_er_start(wpa_s))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
-		if (wpas_wps_er_stop(wpa_s))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
-		if (wpas_wps_er_pbc(wpa_s, buf + 11))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
-		if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
-			reply_len = -1;
-#endif /* CONFIG_WPS_ER */
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_IBSS_RSN
-	} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
-		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
-			reply_len = -1;
-#endif /* CONFIG_IBSS_RSN */
-	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
-	{
-		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
-			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
-			reply_len = -1;
-		else
-			ctrl_rsp = 1;
-	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
-		if (wpa_supplicant_reload_configuration(wpa_s))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "TERMINATE") == 0) {
-		wpa_supplicant_terminate_proc(wpa_s->global);
-	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
-		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_list_networks(
-			wpa_s, reply, reply_size);
-	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
-		wpa_s->reassociate = 0;
-		wpa_s->disconnected = 1;
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-	} else if (os_strcmp(buf, "SCAN") == 0) {
-		wpa_s->scan_req = 2;
-		wpa_supplicant_req_scan(wpa_s, 0, 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_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
-		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
-		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
-		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
-			reply_len = -1;
-	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_add_network(
-			wpa_s, reply, reply_size);
-	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
-		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
-		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_get_network(
-			wpa_s, buf + 12, reply, reply_size);
-#ifndef CONFIG_NO_CONFIG_WRITE
-	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
-		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
-			reply_len = -1;
-#endif /* CONFIG_NO_CONFIG_WRITE */
-	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_get_capability(
-			wpa_s, buf + 15, reply, reply_size);
-	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
-		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
-			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) {
-		reply_len = wpa_supplicant_global_iface_interfaces(
-			wpa_s->global, 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);
-#ifdef CONFIG_AP
-	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
-		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
-	} else if (os_strncmp(buf, "STA ", 4) == 0) {
-		reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
-					      reply_size);
-	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
-		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
-						   reply_size);
-#endif /* CONFIG_AP */
-	} else if (os_strcmp(buf, "SUSPEND") == 0) {
-		wpas_notify_suspend(wpa_s->global);
-	} else if (os_strcmp(buf, "RESUME") == 0) {
-		wpas_notify_resume(wpa_s->global);
-	} else if (os_strcmp(buf, "DROP_SA") == 0) {
-		wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
-	} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
-		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
-			reply_len = -1;
-	} else {
-		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
-		reply_len = 16;
-	}
-
-	if (reply_len < 0) {
-		os_memcpy(reply, "FAIL\n", 5);
-		reply_len = 5;
-	}
-
-	if (ctrl_rsp)
-		eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
-	*resp_len = reply_len;
-	return reply;
-}
-
-
-static int wpa_supplicant_global_iface_add(struct wpa_global *global,
-					   char *cmd)
-{
-	struct wpa_interface iface;
-	char *pos;
-
-	/*
-	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
-	 * TAB<bridge_ifname>
-	 */
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
-
-	os_memset(&iface, 0, sizeof(iface));
-
-	do {
-		iface.ifname = pos = cmd;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.ifname[0] == '\0')
-			return -1;
-		if (pos == NULL)
-			break;
-
-		iface.confname = pos;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.confname[0] == '\0')
-			iface.confname = NULL;
-		if (pos == NULL)
-			break;
-
-		iface.driver = pos;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.driver[0] == '\0')
-			iface.driver = NULL;
-		if (pos == NULL)
-			break;
-
-		iface.ctrl_interface = pos;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.ctrl_interface[0] == '\0')
-			iface.ctrl_interface = NULL;
-		if (pos == NULL)
-			break;
-
-		iface.driver_param = pos;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.driver_param[0] == '\0')
-			iface.driver_param = NULL;
-		if (pos == NULL)
-			break;
-
-		iface.bridge_ifname = pos;
-		pos = os_strchr(pos, '\t');
-		if (pos)
-			*pos++ = '\0';
-		if (iface.bridge_ifname[0] == '\0')
-			iface.bridge_ifname = NULL;
-		if (pos == NULL)
-			break;
-	} while (0);
-
-	if (wpa_supplicant_get_iface(global, iface.ifname))
-		return -1;
-
-	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
-}
-
-
-static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
-					      char *cmd)
-{
-	struct wpa_supplicant *wpa_s;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
-
-	wpa_s = wpa_supplicant_get_iface(global, cmd);
-	if (wpa_s == NULL)
-		return -1;
-	return wpa_supplicant_remove_iface(global, wpa_s);
-}
-
-
-static void wpa_free_iface_info(struct wpa_interface_info *iface)
-{
-	struct wpa_interface_info *prev;
-
-	while (iface) {
-		prev = iface;
-		iface = iface->next;
-
-		os_free(prev->ifname);
-		os_free(prev->desc);
-		os_free(prev);
-	}
-}
-
-
-static int wpa_supplicant_global_iface_list(struct wpa_global *global,
-					    char *buf, int len)
-{
-	int i, res;
-	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
-	char *pos, *end;
-
-	for (i = 0; wpa_drivers[i]; i++) {
-		struct wpa_driver_ops *drv = wpa_drivers[i];
-		if (drv->get_interfaces == NULL)
-			continue;
-		tmp = drv->get_interfaces(global->drv_priv[i]);
-		if (tmp == NULL)
-			continue;
-
-		if (last == NULL)
-			iface = last = tmp;
-		else
-			last->next = tmp;
-		while (last->next)
-			last = last->next;
-	}
-
-	pos = buf;
-	end = buf + len;
-	for (tmp = iface; tmp; tmp = tmp->next) {
-		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
-				  tmp->drv_name, tmp->ifname,
-				  tmp->desc ? tmp->desc : "");
-		if (res < 0 || res >= end - pos) {
-			*pos = '\0';
-			break;
-		}
-		pos += res;
-	}
-
-	wpa_free_iface_info(iface);
-
-	return pos - buf;
-}
-
-
-static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
-						  char *buf, int len)
-{
-	int res;
-	char *pos, *end;
-	struct wpa_supplicant *wpa_s;
-
-	wpa_s = global->ifaces;
-	pos = buf;
-	end = buf + len;
-
-	while (wpa_s) {
-		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
-		if (res < 0 || res >= end - pos) {
-			*pos = '\0';
-			break;
-		}
-		pos += res;
-		wpa_s = wpa_s->next;
-	}
-	return pos - buf;
-}
-
-
-char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
-						char *buf, size_t *resp_len)
-{
-	char *reply;
-	const int reply_size = 2048;
-	int reply_len;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
-			  (const u8 *) buf, os_strlen(buf));
-
-	reply = os_malloc(reply_size);
-	if (reply == NULL) {
-		*resp_len = 1;
-		return NULL;
-	}
-
-	os_memcpy(reply, "OK\n", 3);
-	reply_len = 3;
-
-	if (os_strcmp(buf, "PING") == 0) {
-		os_memcpy(reply, "PONG\n", 5);
-		reply_len = 5;
-	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
-		if (wpa_supplicant_global_iface_add(global, buf + 14))
-			reply_len = -1;
-	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
-		if (wpa_supplicant_global_iface_remove(global, buf + 17))
-			reply_len = -1;
-	} 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) {
-		reply_len = wpa_supplicant_global_iface_interfaces(
-			global, reply, reply_size);
-	} else if (os_strcmp(buf, "TERMINATE") == 0) {
-		wpa_supplicant_terminate_proc(global);
-	} else if (os_strcmp(buf, "SUSPEND") == 0) {
-		wpas_notify_suspend(global);
-	} else if (os_strcmp(buf, "RESUME") == 0) {
-		wpas_notify_resume(global);
-	} else {
-		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
-		reply_len = 16;
-	}
-
-	if (reply_len < 0) {
-		os_memcpy(reply, "FAIL\n", 5);
-		reply_len = 5;
-	}
-
-	*resp_len = reply_len;
-	return reply;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ctrl_iface.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,5545 @@
+/*
+ * WPA Supplicant / Control interface (shared code for all backends)
+ * Copyright (c) 2004-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "eap_peer/eap.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "l2_packet/l2_packet.h"
+#include "wps/wps.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "ap.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "wifi_display.h"
+#include "notify.h"
+#include "bss.h"
+#include "scan.h"
+#include "ctrl_iface.h"
+#include "interworking.h"
+#include "blacklist.h"
+#include "autoscan.h"
+#include "wnm_sta.h"
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+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,
+						  char *buf, int len);
+
+
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+	size_t i, num_ssid;
+	struct wpa_ssid *ssid;
+	struct wpa_driver_scan_params params;
+
+	if (wpa_s->pno)
+		return 0;
+
+	if (wpa_s->wpa_state == WPA_SCANNING) {
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_cancel_scan(wpa_s);
+	}
+
+	os_memset(&params, 0, sizeof(params));
+
+	num_ssid = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			num_ssid++;
+		ssid = ssid->next;
+	}
+	if (num_ssid > WPAS_MAX_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;
+	}
+
+	if (num_ssid == 0) {
+		wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+		return -1;
+	}
+
+	params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+					num_ssid);
+	if (params.filter_ssids == NULL)
+		return -1;
+	i = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid)) {
+			params.ssids[i].ssid = ssid->ssid;
+			params.ssids[i].ssid_len = ssid->ssid_len;
+			params.num_ssids++;
+			os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+				  ssid->ssid_len);
+			params.filter_ssids[i].ssid_len = ssid->ssid_len;
+			params.num_filter_ssids++;
+			i++;
+			if (i == num_ssid)
+				break;
+		}
+		ssid = ssid->next;
+	}
+
+	if (wpa_s->conf->filter_rssi)
+		params.filter_rssi = wpa_s->conf->filter_rssi;
+
+	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+	os_free(params.filter_ssids);
+	if (ret == 0)
+		wpa_s->pno = 1;
+	return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+	int ret = 0;
+
+	if (wpa_s->pno) {
+		wpa_s->pno = 0;
+		ret = wpa_drv_stop_sched_scan(wpa_s);
+	}
+
+	if (wpa_s->wpa_state == WPA_SCANNING)
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return ret;
+}
+
+
+static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
+{
+	char *pos;
+	u8 addr[ETH_ALEN], *filter = NULL, *n;
+	size_t count = 0;
+
+	pos = val;
+	while (pos) {
+		if (*pos == '\0')
+			break;
+		if (hwaddr_aton(pos, addr)) {
+			os_free(filter);
+			return -1;
+		}
+		n = os_realloc_array(filter, count + 1, ETH_ALEN);
+		if (n == NULL) {
+			os_free(filter);
+			return -1;
+		}
+		filter = n;
+		os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
+		count++;
+
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
+	os_free(wpa_s->bssid_filter);
+	wpa_s->bssid_filter = filter;
+	wpa_s->bssid_filter_count = count;
+
+	return 0;
+}
+
+
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+	char *pos;
+	u8 addr[ETH_ALEN], *bssid = NULL, *n;
+	struct wpa_ssid_value *ssid = NULL, *ns;
+	size_t count = 0, ssid_count = 0;
+	struct wpa_ssid *c;
+
+	/*
+	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+	 * SSID_SPEC ::= ssid <SSID_HEX>
+	 * BSSID_SPEC ::= bssid <BSSID_HEX>
+	 */
+
+	pos = val;
+	while (pos) {
+		if (*pos == '\0')
+			break;
+		if (os_strncmp(pos, "bssid ", 6) == 0) {
+			int res;
+			pos += 6;
+			res = hwaddr_aton2(pos, addr);
+			if (res < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "BSSID value '%s'", pos);
+				return -1;
+			}
+			pos += res;
+			n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+			if (n == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			bssid = n;
+			os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+			count++;
+		} else if (os_strncmp(pos, "ssid ", 5) == 0) {
+			char *end;
+			pos += 5;
+
+			end = pos;
+			while (*end) {
+				if (*end == '\0' || *end == ' ')
+					break;
+				end++;
+			}
+
+			ns = os_realloc_array(ssid, ssid_count + 1,
+					      sizeof(struct wpa_ssid_value));
+			if (ns == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			ssid = ns;
+
+			if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+			    hexstr2bin(pos, ssid[ssid_count].ssid,
+				       (end - pos) / 2) < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "SSID value '%s'", pos);
+				return -1;
+			}
+			ssid[ssid_count].ssid_len = (end - pos) / 2;
+			wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+					  ssid[ssid_count].ssid,
+					  ssid[ssid_count].ssid_len);
+			ssid_count++;
+			pos = end;
+		} else {
+			wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+				   "'%s'", pos);
+			os_free(ssid);
+			os_free(bssid);
+			return -1;
+		}
+
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = bssid;
+	wpa_s->disallow_aps_bssid_count = count;
+
+	wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = ssid;
+	wpa_s->disallow_aps_ssid_count = ssid_count;
+
+	if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+		return 0;
+
+	c = wpa_s->current_ssid;
+	if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+		return 0;
+
+	if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+	    !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+		   "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+	wpa_s->reassociate = 1;
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	char *value;
+	int ret = 0;
+
+	value = os_strchr(cmd, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   atoi(value), -1, -1, -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, atoi(value), -1, -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, -1, atoi(value), -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, -1, -1, atoi(value));
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
+				     atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
+		   0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+				     atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
+		wpa_s->wps_fragment_size = atoi(value);
+#ifdef CONFIG_WPS_TESTING
+	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+		long int val;
+		val = strtol(value, NULL, 0);
+		if (val < 0 || val > 0xff) {
+			ret = -1;
+			wpa_printf(MSG_DEBUG, "WPS: Invalid "
+				   "wps_version_number %ld", val);
+		} else {
+			wps_version_number = val;
+			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+				   "version %u.%u",
+				   (wps_version_number & 0xf0) >> 4,
+				   wps_version_number & 0x0f);
+		}
+	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+		wps_testing_dummy_cred = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+			   wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+	} else if (os_strcasecmp(cmd, "ampdu") == 0) {
+		if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
+			ret = -1;
+#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 */
+#ifdef CONFIG_TDLS
+	} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
+		int disabled = atoi(value);
+		wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
+		if (disabled) {
+			if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
+				ret = -1;
+		} else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
+			ret = -1;
+		wpa_tdls_enable(wpa_s->wpa, !disabled);
+#endif /* CONFIG_TDLS */
+	} else if (os_strcasecmp(cmd, "pno") == 0) {
+		if (atoi(value))
+			ret = pno_start(wpa_s);
+		else
+			ret = pno_stop(wpa_s);
+	} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
+		int disabled = atoi(value);
+		if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
+			ret = -1;
+		else if (disabled)
+			wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+	} else if (os_strcasecmp(cmd, "uapsd") == 0) {
+		if (os_strcmp(value, "disable") == 0)
+			wpa_s->set_sta_uapsd = 0;
+		else {
+			int be, bk, vi, vo;
+			char *pos;
+			/* format: BE,BK,VI,VO;max SP Length */
+			be = atoi(value);
+			pos = os_strchr(value, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			bk = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vi = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vo = atoi(pos);
+			/* ignore max SP Length for now */
+
+			wpa_s->set_sta_uapsd = 1;
+			wpa_s->sta_uapsd = 0;
+			if (be)
+				wpa_s->sta_uapsd |= BIT(0);
+			if (bk)
+				wpa_s->sta_uapsd |= BIT(1);
+			if (vi)
+				wpa_s->sta_uapsd |= BIT(2);
+			if (vo)
+				wpa_s->sta_uapsd |= BIT(3);
+		}
+	} else if (os_strcasecmp(cmd, "ps") == 0) {
+		ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+		wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
+	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+		ret = set_bssid_filter(wpa_s, value);
+	} else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+		ret = set_disallow_aps(wpa_s, value);
+	} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
+		wpa_s->no_keep_alive = !!atoi(value);
+	} else {
+		value[-1] = '=';
+		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
+		if (ret == 0)
+			wpa_supplicant_update_config(wpa_s);
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
+					 char *cmd, char *buf, size_t buflen)
+{
+	int res = -1;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+	if (os_strcmp(cmd, "version") == 0) {
+		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+	} else if (os_strcasecmp(cmd, "country") == 0) {
+		if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
+			res = os_snprintf(buf, buflen, "%c%c",
+					  wpa_s->conf->country[0],
+					  wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+		res = os_snprintf(buf, buflen, "%d",
+				  wpa_s->global->wifi_display);
+		if (res < 0 || (unsigned int) res >= buflen)
+			return -1;
+		return res;
+#endif /* CONFIG_WIFI_DISPLAY */
+	}
+
+	if (res < 0 || (unsigned int) res >= buflen)
+		return -1;
+	return res;
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
+					     char *addr)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (hwaddr_aton(addr, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
+			   "'%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
+	rsn_preauth_deinit(wpa_s->wpa);
+	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
+		return -1;
+
+	return 0;
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifdef CONFIG_PEERKEY
+/* MLME-STKSTART.request(peer) */
+static int wpa_supplicant_ctrl_iface_stkstart(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_sm_stkstart(wpa_s->wpa, peer);
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_ctrl_iface_tdls_discover(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
+		   MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_setup(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
+		   MAC2STR(peer));
+
+	ret = wpa_tdls_reneg(wpa_s->wpa, peer);
+	if (ret) {
+		if (wpa_tdls_is_external_setup(wpa_s->wpa))
+			ret = wpa_tdls_start(wpa_s->wpa, peer);
+		else
+			ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_teardown(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_tdls_teardown_link(wpa_s->wpa, peer,
+				      WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+}
+
+#endif /* CONFIG_TDLS */
+
+
+#ifdef CONFIG_IEEE80211R
+static int wpa_supplicant_ctrl_iface_ft_ds(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 target_ap[ETH_ALEN];
+	struct wpa_bss *bss;
+	const u8 *mdie;
+
+	if (hwaddr_aton(addr, target_ap)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
+
+	bss = wpa_bss_get_bssid(wpa_s, target_ap);
+	if (bss)
+		mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+	else
+		mdie = NULL;
+
+	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_WPS
+static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+#ifdef CONFIG_P2P
+	u8 p2p_dev_addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+	u8 *_p2p_dev_addr = NULL;
+#endif /* CONFIG_AP */
+
+	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+		_bssid = NULL;
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+		if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
+				   "P2P Device Address '%s'",
+				   cmd + 13);
+			return -1;
+		}
+		_p2p_dev_addr = p2p_dev_addr;
+#endif /* CONFIG_P2P */
+	} else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface)
+		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
+#endif /* CONFIG_AP */
+
+	return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
+					     char *cmd, char *buf,
+					     size_t buflen)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+	char *pin;
+	int ret;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin)
+		*pin++ = '\0';
+
+	if (os_strcmp(cmd, "any") == 0)
+		_bssid = NULL;
+	else if (os_strcmp(cmd, "get") == 0) {
+		ret = wps_generate_pin();
+		goto done;
+	} else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		int timeout = 0;
+		char *pos;
+
+		if (pin) {
+			pos = os_strchr(pin, ' ');
+			if (pos) {
+				*pos++ = '\0';
+				timeout = atoi(pos);
+			}
+		}
+
+		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
+						 buf, buflen, timeout);
+	}
+#endif /* CONFIG_AP */
+
+	if (pin) {
+		ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+					 DEV_PW_DEFAULT);
+		if (ret < 0)
+			return -1;
+		ret = os_snprintf(buf, buflen, "%s", pin);
+		if (ret < 0 || (size_t) ret >= buflen)
+			return -1;
+		return ret;
+	}
+
+	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
+	if (ret < 0)
+		return -1;
+
+done:
+	/* Return the generated PIN */
+	ret = os_snprintf(buf, buflen, "%08d", ret);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_check_pin(
+	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+	char pin[9];
+	size_t len;
+	char *pos;
+	int ret;
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+			      (u8 *) cmd, os_strlen(cmd));
+	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+		if (*pos < '0' || *pos > '9')
+			continue;
+		pin[len++] = *pos;
+		if (len == 9) {
+			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+			return -1;
+		}
+	}
+	if (len != 4 && len != 8) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+		return -1;
+	}
+	pin[len] = '\0';
+
+	if (len == 8) {
+		unsigned int pin_val;
+		pin_val = atoi(pin);
+		if (!wps_pin_valid(pin_val)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+			if (ret < 0 || (size_t) ret >= buflen)
+				return -1;
+			return ret;
+		}
+	}
+
+	ret = os_snprintf(buf, buflen, "%s", pin);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+
+	return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+	if (cmd == NULL || cmd[0] == '\0')
+		_bssid = NULL;
+	else if (hwaddr_aton(cmd, bssid))
+		return -1;
+
+	return wpas_wps_start_nfc(wpa_s, _bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = wpas_wps_nfc_token(wpa_s, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
+	struct wpa_supplicant *wpa_s, char *pos)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_req(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_sel(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+					 char *cmd, char *reply,
+					 size_t max_len)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN];
+	char *pin;
+	char *new_ssid;
+	char *new_auth;
+	char *new_encr;
+	char *new_key;
+	struct wps_new_ap_settings ap;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+	new_ssid = os_strchr(pin, ' ');
+	if (new_ssid == NULL)
+		return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
+	*new_ssid++ = '\0';
+
+	new_auth = os_strchr(new_ssid, ' ');
+	if (new_auth == NULL)
+		return -1;
+	*new_auth++ = '\0';
+
+	new_encr = os_strchr(new_auth, ' ');
+	if (new_encr == NULL)
+		return -1;
+	*new_encr++ = '\0';
+
+	new_key = os_strchr(new_encr, ' ');
+	if (new_key == NULL)
+		return -1;
+	*new_key++ = '\0';
+
+	os_memset(&ap, 0, sizeof(ap));
+	ap.ssid_hex = new_ssid;
+	ap.auth = new_auth;
+	ap.encr = new_encr;
+	ap.key_hex = new_key;
+	return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
+}
+
+
+#ifdef CONFIG_AP
+static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
+						char *cmd, char *buf,
+						size_t buflen)
+{
+	int timeout = 300;
+	char *pos;
+	const char *pin_txt;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos)
+		*pos++ = '\0';
+
+	if (os_strcmp(cmd, "disable") == 0) {
+		wpas_wps_ap_pin_disable(wpa_s);
+		return os_snprintf(buf, buflen, "OK\n");
+	}
+
+	if (os_strcmp(cmd, "random") == 0) {
+		if (pos)
+			timeout = atoi(pos);
+		pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(cmd, "get") == 0) {
+		pin_txt = wpas_wps_ap_pin_get(wpa_s);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(cmd, "set") == 0) {
+		char *pin;
+		if (pos == NULL)
+			return -1;
+		pin = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			timeout = atoi(pos);
+		}
+		if (os_strlen(pin) > buflen)
+			return -1;
+		if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin);
+	}
+
+	return -1;
+}
+#endif /* CONFIG_AP */
+
+
+#ifdef CONFIG_WPS_ER
+static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
+						char *cmd)
+{
+	char *uuid = cmd, *pin, *pos;
+	u8 addr_buf[ETH_ALEN], *addr = NULL;
+	pin = os_strchr(uuid, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+	pos = os_strchr(pin, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		if (hwaddr_aton(pos, addr_buf) == 0)
+			addr = addr_buf;
+	}
+	return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
+						  char *cmd)
+{
+	char *uuid = cmd, *pin;
+	pin = os_strchr(uuid, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+	return wpas_wps_er_learn(wpa_s, uuid, pin);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_set_config(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *uuid = cmd, *id;
+	id = os_strchr(uuid, ' ');
+	if (id == NULL)
+		return -1;
+	*id++ = '\0';
+	return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_config(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pin;
+	char *new_ssid;
+	char *new_auth;
+	char *new_encr;
+	char *new_key;
+	struct wps_new_ap_settings ap;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	new_ssid = os_strchr(pin, ' ');
+	if (new_ssid == NULL)
+		return -1;
+	*new_ssid++ = '\0';
+
+	new_auth = os_strchr(new_ssid, ' ');
+	if (new_auth == NULL)
+		return -1;
+	*new_auth++ = '\0';
+
+	new_encr = os_strchr(new_auth, ' ');
+	if (new_encr == NULL)
+		return -1;
+	*new_encr++ = '\0';
+
+	new_key = os_strchr(new_encr, ' ');
+	if (new_key == NULL)
+		return -1;
+	*new_key++ = '\0';
+
+	os_memset(&ap, 0, sizeof(ap));
+	ap.ssid_hex = new_ssid;
+	ap.auth = new_auth;
+	ap.encr = new_encr;
+	ap.key_hex = new_key;
+	return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+	char *uuid;
+
+	uuid = os_strchr(cmd, ' ');
+	if (uuid == NULL)
+		return -1;
+	*uuid++ = '\0';
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS_ER */
+
+#endif /* CONFIG_WPS */
+
+
+#ifdef CONFIG_IBSS_RSN
+static int wpa_supplicant_ctrl_iface_ibss_rsn(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
+		   MAC2STR(peer));
+
+	return ibss_rsn_start(wpa_s->ibss_rsn, peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
+static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
+					      char *rsp)
+{
+#ifdef IEEE8021X_EAPOL
+	char *pos, *id_pos;
+	int id;
+	struct wpa_ssid *ssid;
+
+	pos = os_strchr(rsp, '-');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id_pos = pos;
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id = atoi(id_pos);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) pos, os_strlen(pos));
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "to update", id);
+		return -1;
+	}
+
+	return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
+							 pos);
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+	return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
+					    const char *params,
+					    char *buf, size_t buflen)
+{
+	char *pos, *end, tmp[30];
+	int res, verbose, wps, ret;
+
+	verbose = os_strcmp(params, "-VERBOSE") == 0;
+	wps = os_strcmp(params, "-WPS") == 0;
+	pos = buf;
+	end = buf + buflen;
+	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+				  MAC2STR(wpa_s->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		if (ssid) {
+			u8 *_ssid = ssid->ssid;
+			size_t ssid_len = ssid->ssid_len;
+			u8 ssid_buf[MAX_SSID_LEN];
+			if (ssid_len == 0) {
+				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
+				if (_res < 0)
+					ssid_len = 0;
+				else
+					ssid_len = _res;
+				_ssid = ssid_buf;
+			}
+			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
+					  wpa_ssid_txt(_ssid, ssid_len),
+					  ssid->id);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			if (wps && ssid->passphrase &&
+			    wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+			    (ssid->mode == WPAS_MODE_AP ||
+			     ssid->mode == WPAS_MODE_P2P_GO)) {
+				ret = os_snprintf(pos, end - pos,
+						  "passphrase=%s\n",
+						  ssid->passphrase);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
+			if (ssid->id_str) {
+				ret = os_snprintf(pos, end - pos,
+						  "id_str=%s\n",
+						  ssid->id_str);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
+
+			switch (ssid->mode) {
+			case WPAS_MODE_INFRA:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=station\n");
+				break;
+			case WPAS_MODE_IBSS:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=IBSS\n");
+				break;
+			case WPAS_MODE_AP:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=AP\n");
+				break;
+			case WPAS_MODE_P2P_GO:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=P2P GO\n");
+				break;
+			case WPAS_MODE_P2P_GROUP_FORMATION:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=P2P GO - group "
+						  "formation\n");
+				break;
+			default:
+				ret = 0;
+				break;
+			}
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface) {
+			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
+							    end - pos,
+							    verbose);
+		} else
+#endif /* CONFIG_AP */
+		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
+	}
+	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
+			  wpa_supplicant_state_txt(wpa_s->wpa_state));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (wpa_s->l2 &&
+	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
+		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p) {
+		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+				  "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_P2P */
+
+	ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
+			  MAC2STR(wpa_s->own_addr));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+#ifdef CONFIG_HS20
+	if (wpa_s->current_bss &&
+	    wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+	    wpa_s->wpa_proto == WPA_PROTO_RSN &&
+	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		ret = os_snprintf(pos, end - pos, "hs20=1\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (wpa_s->current_ssid) {
+		struct wpa_cred *cred;
+		char *type;
+
+		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			if (wpa_s->current_ssid->parent_cred != cred)
+				continue;
+			if (!cred->domain)
+				continue;
+
+			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+					  cred->domain);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			if (wpa_s->current_bss == NULL ||
+			    wpa_s->current_bss->anqp == NULL)
+				res = -1;
+			else
+				res = interworking_home_sp_cred(
+					wpa_s, cred,
+					wpa_s->current_bss->anqp->domain_name);
+			if (res > 0)
+				type = "home";
+			else if (res == 0)
+				type = "roaming";
+			else
+				type = "unknown";
+
+			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			break;
+		}
+	}
+#endif /* CONFIG_HS20 */
+
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
+					  verbose);
+		if (res >= 0)
+			pos += res;
+	}
+
+	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
+	if (res >= 0)
+		pos += res;
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
+					   char *cmd)
+{
+	char *pos;
+	int id;
+	struct wpa_ssid *ssid;
+	u8 bssid[ETH_ALEN];
+
+	/* cmd: "<network id> <BSSID>" */
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
+	if (hwaddr_aton(pos, bssid)) {
+		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
+		return -1;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "to update", id);
+		return -1;
+	}
+
+	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
+	ssid->bssid_set = !is_zero_ether_addr(bssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
+					       char *cmd, char *buf,
+					       size_t buflen)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_blacklist *e;
+	char *pos, *end;
+	int ret;
+
+	/* cmd: "BLACKLIST [<BSSID>]" */
+	if (*cmd == '\0') {
+		pos = buf;
+		end = buf + buflen;
+		e = wpa_s->blacklist;
+		while (e) {
+			ret = os_snprintf(pos, end - pos, MACSTR "\n",
+					  MAC2STR(e->bssid));
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+			e = e->next;
+		}
+		return pos - buf;
+	}
+
+	cmd++;
+	if (os_strncmp(cmd, "clear", 5) == 0) {
+		wpa_blacklist_clear(wpa_s);
+		os_memcpy(buf, "OK\n", 3);
+		return 3;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+	if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
+		return -1;
+	}
+
+	/*
+	 * Add the BSSID twice, so its count will be 2, causing it to be
+	 * skipped when processing scan results.
+	 */
+	ret = wpa_blacklist_add(wpa_s, bssid);
+	if (ret != 0)
+		return -1;
+	ret = wpa_blacklist_add(wpa_s, bssid);
+	if (ret != 0)
+		return -1;
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_timestamp;
+
+static 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 "?";
+	}
+}
+
+
+static 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;
+}
+
+
+static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
+					       char *cmd, char *buf,
+					       size_t buflen)
+{
+	char *pos, *end, *stamp;
+	int ret;
+
+	if (cmd == NULL) {
+		return -1;
+	}
+
+	/* cmd: "LOG_LEVEL [<level>]" */
+	if (*cmd == '\0') {
+		pos = buf;
+		end = buf + buflen;
+		ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+				  "Timestamp: %d\n",
+				  debug_level_str(wpa_debug_level),
+				  wpa_debug_timestamp);
+		if (ret < 0 || ret >= end - pos)
+			ret = 0;
+
+		return ret;
+	}
+
+	while (*cmd == ' ')
+		cmd++;
+
+	stamp = os_strchr(cmd, ' ');
+	if (stamp) {
+		*stamp++ = '\0';
+		while (*stamp == ' ') {
+			stamp++;
+		}
+	}
+
+	if (cmd && os_strlen(cmd)) {
+		int level = str_to_debug_level(cmd);
+		if (level < 0)
+			return -1;
+		wpa_debug_level = level;
+	}
+
+	if (stamp && os_strlen(stamp))
+		wpa_debug_timestamp = atoi(stamp);
+
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+static int wpa_supplicant_ctrl_iface_list_networks(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_ssid *ssid;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos,
+			  "network id / ssid / bssid / flags\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		ret = os_snprintf(pos, end - pos, "%d\t%s",
+				  ssid->id,
+				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		if (ssid->bssid_set) {
+			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
+					  MAC2STR(ssid->bssid));
+		} else {
+			ret = os_snprintf(pos, end - pos, "\tany");
+		}
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
+				  ssid == wpa_s->current_ssid ?
+				  "[CURRENT]" : "",
+				  ssid->disabled ? "[DISABLED]" : "",
+				  ssid->disabled_until.sec ?
+				  "[TEMP-DISABLED]" : "",
+				  ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
+				  "");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		ssid = ssid->next;
+	}
+
+	return pos - buf;
+}
+
+
+static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
+{
+	int first = 1, ret;
+	ret = os_snprintf(pos, end - pos, "-");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+	if (cipher & WPA_CIPHER_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	return pos;
+}
+
+
+static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
+				    const u8 *ie, size_t ie_len)
+{
+	struct wpa_ie_data data;
+	int first, ret;
+
+	ret = os_snprintf(pos, end - pos, "[%s-", proto);
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
+		ret = os_snprintf(pos, end - pos, "?]");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		return pos;
+	}
+
+	first = 1;
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
+
+	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
+		ret = os_snprintf(pos, end - pos, "-preauth");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+	}
+
+	ret = os_snprintf(pos, end - pos, "]");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	return pos;
+}
+
+
+#ifdef CONFIG_WPS
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+					    char *pos, char *end,
+					    struct wpabuf *wps_ie)
+{
+	int ret;
+	const char *txt;
+
+	if (wps_ie == NULL)
+		return pos;
+	if (wps_is_selected_pbc_registrar(wps_ie))
+		txt = "[WPS-PBC]";
+#ifdef CONFIG_WPS2
+	else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+		txt = "[WPS-AUTH]";
+#endif /* CONFIG_WPS2 */
+	else if (wps_is_selected_pin_registrar(wps_ie))
+		txt = "[WPS-PIN]";
+	else
+		txt = "[WPS]";
+
+	ret = os_snprintf(pos, end - pos, "%s", txt);
+	if (ret >= 0 && ret < end - pos)
+		pos += ret;
+	wpabuf_free(wps_ie);
+	return pos;
+}
+#endif /* CONFIG_WPS */
+
+
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+					char *pos, char *end,
+					const struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+	struct wpabuf *wps_ie;
+	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+	return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
+#else /* CONFIG_WPS */
+	return pos;
+#endif /* CONFIG_WPS */
+}
+
+
+/* Format one result on one text line into a buffer. */
+static int wpa_supplicant_ctrl_iface_scan_result(
+	struct wpa_supplicant *wpa_s,
+	const struct wpa_bss *bss, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	int ret;
+	const u8 *ie, *ie2, *p2p;
+
+	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
+	    0)
+		return 0; /* Do not show P2P listen discovery results here */
+
+	pos = buf;
+	end = buf + buflen;
+
+	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
+			  MAC2STR(bss->bssid), bss->freq, bss->level);
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	if (ie)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
+	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	if (ie2)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+		ret = os_snprintf(pos, end - pos, "[WEP]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (bss->caps & IEEE80211_CAP_IBSS) {
+		ret = os_snprintf(pos, end - pos, "[IBSS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (bss->caps & IEEE80211_CAP_ESS) {
+		ret = os_snprintf(pos, end - pos, "[ESS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (p2p) {
+		ret = os_snprintf(pos, end - pos, "[P2P]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+#ifdef CONFIG_HS20
+	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
+		ret = os_snprintf(pos, end - pos, "[HS20]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+#endif /* CONFIG_HS20 */
+
+	ret = os_snprintf(pos, end - pos, "\t%s",
+			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+
+	ret = os_snprintf(pos, end - pos, "\n");
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_scan_results(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_bss *bss;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
+			  "flags / ssid\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+		ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
+							    end - pos);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_select_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "any" */
+	if (os_strcmp(cmd, "any") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "SELECT_NETWORK with persistent P2P group");
+			return -1;
+		}
+	}
+
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_enable_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "ENABLE_NETWORK with persistent P2P group");
+			return -1;
+		}
+
+		if (os_strstr(cmd, " no-connect")) {
+			ssid->disabled = 0;
+			return 0;
+		}
+	}
+	wpa_supplicant_enable_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_disable_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "DISABLE_NETWORK with persistent P2P "
+				   "group");
+			return -1;
+		}
+	}
+	wpa_supplicant_disable_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_network(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	struct wpa_ssid *ssid;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	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 (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
+		ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			struct wpa_ssid *remove_ssid = ssid;
+			id = ssid->id;
+			ssid = ssid->next;
+			wpas_notify_network_removed(wpa_s, remove_ssid);
+			wpa_config_remove_network(wpa_s->conf, id);
+		}
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+			wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+			wpa_sm_set_config(wpa_s->wpa, NULL);
+			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		}
+		return 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) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	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);
+
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
+			   "network id=%d", id);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+	char *name, *value;
+
+	/* cmd: "<network id> <variable name> <value>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL)
+		return -1;
+	*name++ = '\0';
+
+	value = os_strchr(name, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
+		   id, name);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) value, os_strlen(value));
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	if (wpa_config_set(ssid, name, value, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	if (os_strcmp(name, "bssid") != 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 ((os_strcmp(name, "psk") == 0 &&
+	     value[0] == '"' && ssid->ssid_len) ||
+	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
+		wpa_config_update_psk(ssid);
+	else if (os_strcmp(name, "priority") == 0)
+		wpa_config_update_prio_list(wpa_s->conf);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_network(
+	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+	int id;
+	size_t res;
+	struct wpa_ssid *ssid;
+	char *name, *value;
+
+	/* cmd: "<network id> <variable name>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL || buflen == 0)
+		return -1;
+	*name++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
+		   id, name);
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	value = wpa_config_get_no_key(ssid, name);
+	if (value == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	res = os_strlcpy(buf, value, buflen);
+	if (res >= buflen) {
+		os_free(value);
+		return -1;
+	}
+
+	os_free(value);
+
+	return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
+						char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_cred *cred;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos,
+			  "cred id / realm / username / domain / imsi\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	cred = wpa_s->conf->cred;
+	while (cred) {
+		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
+				  cred->id, cred->realm ? cred->realm : "",
+				  cred->username ? cred->username : "",
+				  cred->domain ? cred->domain : "",
+				  cred->imsi ? cred->imsi : "");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		cred = cred->next;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
+					      char *buf, size_t buflen)
+{
+	struct wpa_cred *cred;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
+
+	cred = wpa_config_add_cred(wpa_s->conf);
+	if (cred == NULL)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "%d\n", cred->id);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+				 struct wpa_cred *cred)
+{
+	struct wpa_ssid *ssid;
+	char str[20];
+
+	if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+		return -1;
+	}
+
+	/* Remove any network entry created based on the removed credential */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (ssid->parent_cred == cred) {
+			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+				   "used the removed credential", ssid->id);
+			os_snprintf(str, sizeof(str), "%d", ssid->id);
+			ssid = ssid->next;
+			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+		} else
+			ssid = ssid->next;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+						 char *cmd)
+{
+	int id;
+	struct wpa_cred *cred, *prev;
+
+	/* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+		cred = wpa_s->conf->cred;
+		while (cred) {
+			prev = cred;
+			cred = cred->next;
+			wpas_ctrl_remove_cred(wpa_s, prev);
+		}
+		return 0;
+	}
+
+	if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+			   cmd + 8);
+		cred = wpa_s->conf->cred;
+		while (cred) {
+			prev = cred;
+			cred = cred->next;
+			if (prev->domain &&
+			    os_strcmp(prev->domain, cmd + 8) == 0)
+				wpas_ctrl_remove_cred(wpa_s, prev);
+		}
+		return 0;
+	}
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
+
+	cred = wpa_config_get_cred(wpa_s->conf, id);
+	return wpas_ctrl_remove_cred(wpa_s, cred);
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
+					      char *cmd)
+{
+	int id;
+	struct wpa_cred *cred;
+	char *name, *value;
+
+	/* cmd: "<cred id> <variable name> <value>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL)
+		return -1;
+	*name++ = '\0';
+
+	value = os_strchr(name, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
+		   id, name);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) value, os_strlen(value));
+
+	cred = wpa_config_get_cred(wpa_s->conf, id);
+	if (cred == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+			   id);
+		return -1;
+	}
+
+	if (wpa_config_set_cred(cred, name, value, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+
+	if (!wpa_s->conf->update_config) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
+			   "to update configuration (update_config=0)");
+		return -1;
+	}
+
+	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
+			   "update configuration");
+	} else {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
+			   " updated");
+	}
+
+	return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int ctrl_iface_get_capability_pairwise(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_group(int res, char *strict,
+					   struct wpa_driver_capa *capa,
+					   char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
+				 "NONE", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+		ret = os_snprintf(pos, end - pos, " WPA-EAP");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		ret = os_snprintf(pos, end - pos, " WPA-PSK");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, " WPA-NONE");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_proto(int res, char *strict,
+					   struct wpa_driver_capa *capa,
+					   char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "RSN WPA", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
+		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
+		ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
+		ret = os_snprintf(pos, end - pos, "%sSHARED",
+				  first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
+		ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
+					      char *buf, size_t buflen)
+{
+	struct hostapd_channel_data *chnl;
+	int ret, i, j;
+	char *pos, *end, *hmode;
+
+	pos = buf;
+	end = pos + buflen;
+
+	for (j = 0; j < wpa_s->hw.num_modes; j++) {
+		switch (wpa_s->hw.modes[j].mode) {
+		case HOSTAPD_MODE_IEEE80211B:
+			hmode = "B";
+			break;
+		case HOSTAPD_MODE_IEEE80211G:
+			hmode = "G";
+			break;
+		case HOSTAPD_MODE_IEEE80211A:
+			hmode = "A";
+			break;
+		case HOSTAPD_MODE_IEEE80211AD:
+			hmode = "AD";
+			break;
+		default:
+			continue;
+		}
+		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		chnl = wpa_s->hw.modes[j].channels;
+		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_capability(
+	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
+	size_t buflen)
+{
+	struct wpa_driver_capa capa;
+	int res;
+	char *strict;
+	char field[30];
+	size_t len;
+
+	/* Determine whether or not strict checking was requested */
+	len = os_strlcpy(field, _field, sizeof(field));
+	if (len >= sizeof(field))
+		return -1;
+	strict = os_strchr(field, ' ');
+	if (strict != NULL) {
+		*strict++ = '\0';
+		if (os_strcmp(strict, "strict") != 0)
+			return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
+		field, strict ? strict : "");
+
+	if (os_strcmp(field, "eap") == 0) {
+		return eap_get_names(buf, buflen);
+	}
+
+	res = wpa_drv_get_capa(wpa_s, &capa);
+
+	if (os_strcmp(field, "pairwise") == 0)
+		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "group") == 0)
+		return ctrl_iface_get_capability_group(res, strict, &capa,
+						       buf, buflen);
+
+	if (os_strcmp(field, "key_mgmt") == 0)
+		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "proto") == 0)
+		return ctrl_iface_get_capability_proto(res, strict, &capa,
+						       buf, buflen);
+
+	if (os_strcmp(field, "auth_alg") == 0)
+		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "channels") == 0)
+		return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
+		   field);
+
+	return -1;
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static char * anqp_add_hex(char *pos, char *end, const char *title,
+			   struct wpabuf *data)
+{
+	char *start = pos;
+	size_t i;
+	int ret;
+	const u8 *d;
+
+	if (data == NULL)
+		return start;
+
+	ret = os_snprintf(pos, end - pos, "%s=", title);
+	if (ret < 0 || ret >= end - pos)
+		return start;
+	pos += ret;
+
+	d = wpabuf_head_u8(data);
+	for (i = 0; i < wpabuf_len(data); i++) {
+		ret = os_snprintf(pos, end - pos, "%02x", *d++);
+		if (ret < 0 || ret >= end - pos)
+			return start;
+		pos += ret;
+	}
+
+	ret = os_snprintf(pos, end - pos, "\n");
+	if (ret < 0 || ret >= end - pos)
+		return start;
+	pos += ret;
+
+	return pos;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			  unsigned long mask, char *buf, size_t buflen)
+{
+	size_t i;
+	int ret;
+	char *pos, *end;
+	const u8 *ie, *ie2;
+
+	pos = buf;
+	end = buf + buflen;
+
+	if (mask & WPA_BSS_MASK_ID) {
+		ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_BSSID) {
+		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+				  MAC2STR(bss->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_FREQ) {
+		ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_BEACON_INT) {
+		ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
+				  bss->beacon_int);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_CAPABILITIES) {
+		ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
+				  bss->caps);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_QUAL) {
+		ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_NOISE) {
+		ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_LEVEL) {
+		ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_TSF) {
+		ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
+				  (unsigned long long) bss->tsf);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_AGE) {
+		struct os_time now;
+
+		os_get_time(&now);
+		ret = os_snprintf(pos, end - pos, "age=%d\n",
+				  (int) (now.sec - bss->last_update.sec));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_IE) {
+		ret = os_snprintf(pos, end - pos, "ie=");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+
+		ie = (const u8 *) (bss + 1);
+		for (i = 0; i < bss->ie_len; i++) {
+			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_FLAGS) {
+		ret = os_snprintf(pos, end - pos, "flags=");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+
+		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+		if (ie)
+			pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
+						    2 + ie[1]);
+		ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (ie2)
+			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+						    2 + ie2[1]);
+		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+			ret = os_snprintf(pos, end - pos, "[WEP]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (bss->caps & IEEE80211_CAP_IBSS) {
+			ret = os_snprintf(pos, end - pos, "[IBSS]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (bss->caps & IEEE80211_CAP_ESS) {
+			ret = os_snprintf(pos, end - pos, "[ESS]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+			ret = os_snprintf(pos, end - pos, "[P2P]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+#ifdef CONFIG_HS20
+		if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+			ret = os_snprintf(pos, end - pos, "[HS20]");
+			if (ret < 0 || ret >= end - pos)
+				return -1;
+			pos += ret;
+		}
+#endif /* CONFIG_HS20 */
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_SSID) {
+		ret = os_snprintf(pos, end - pos, "ssid=%s\n",
+				  wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+#ifdef CONFIG_WPS
+	if (mask & WPA_BSS_MASK_WPS_SCAN) {
+		ie = (const u8 *) (bss + 1);
+		ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	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)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+		struct wpabuf *wfd;
+		ie = (const u8 *) (bss + 1);
+		wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+						  WFD_IE_VENDOR_TYPE);
+		if (wfd) {
+			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			pos += wpa_snprintf_hex(pos, end - pos,
+						wpabuf_head(wfd),
+						wpabuf_len(wfd));
+			wpabuf_free(wfd);
+
+			ret = os_snprintf(pos, end - pos, "\n");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_INTERWORKING
+	if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+		struct wpa_bss_anqp *anqp = bss->anqp;
+		pos = anqp_add_hex(pos, end, "anqp_venue_name",
+				   anqp->venue_name);
+		pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
+				   anqp->network_auth_type);
+		pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
+				   anqp->roaming_consortium);
+		pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
+				   anqp->ip_addr_type_availability);
+		pos = anqp_add_hex(pos, end, "anqp_nai_realm",
+				   anqp->nai_realm);
+		pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
+		pos = anqp_add_hex(pos, end, "anqp_domain_name",
+				   anqp->domain_name);
+#ifdef CONFIG_HS20
+		pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+				   anqp->hs20_operator_friendly_name);
+		pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+				   anqp->hs20_wan_metrics);
+		pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+				   anqp->hs20_connection_capability);
+#endif /* CONFIG_HS20 */
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
+					 const char *cmd, char *buf,
+					 size_t buflen)
+{
+	u8 bssid[ETH_ALEN];
+	size_t i;
+	struct wpa_bss *bss;
+	struct wpa_bss *bsslast = NULL;
+	struct dl_list *next;
+	int ret = 0;
+	int len;
+	char *ctmp;
+	unsigned long mask = WPA_BSS_MASK_ALL;
+
+	if (os_strncmp(cmd, "RANGE=", 6) == 0) {
+		if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
+			bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
+					    list_id);
+			bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
+					       list_id);
+		} else { /* N1-N2 */
+			unsigned int id1, id2;
+
+			if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+				wpa_printf(MSG_INFO, "Wrong BSS range "
+					   "format");
+				return 0;
+			}
+
+			id1 = atoi(cmd + 6);
+			bss = wpa_bss_get_id(wpa_s, id1);
+			id2 = atoi(ctmp + 1);
+			if (id2 == 0)
+				bsslast = dl_list_last(&wpa_s->bss_id,
+						       struct wpa_bss,
+						       list_id);
+			else {
+				bsslast = wpa_bss_get_id(wpa_s, id2);
+				if (bsslast == NULL && bss && id2 > id1) {
+					struct wpa_bss *tmp = bss;
+					for (;;) {
+						next = tmp->list_id.next;
+						if (next == &wpa_s->bss_id)
+							break;
+						tmp = dl_list_entry(
+							next, struct wpa_bss,
+							list_id);
+						if (tmp->id > id2)
+							break;
+						bsslast = tmp;
+					}
+				}
+			}
+		}
+	} else if (os_strcmp(cmd, "FIRST") == 0)
+		bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+	else if (os_strncmp(cmd, "ID-", 3) == 0) {
+		i = atoi(cmd + 3);
+		bss = wpa_bss_get_id(wpa_s, i);
+	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+		i = atoi(cmd + 5);
+		bss = wpa_bss_get_id(wpa_s, i);
+		if (bss) {
+			next = bss->list_id.next;
+			if (next == &wpa_s->bss_id)
+				bss = NULL;
+			else
+				bss = dl_list_entry(next, struct wpa_bss,
+						    list_id);
+		}
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+		if (hwaddr_aton(cmd + 13, bssid) == 0)
+			bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
+		else
+			bss = NULL;
+#endif /* CONFIG_P2P */
+	} else if (hwaddr_aton(cmd, bssid) == 0)
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+	else {
+		struct wpa_bss *tmp;
+		i = atoi(cmd);
+		bss = NULL;
+		dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
+		{
+			if (i-- == 0) {
+				bss = tmp;
+				break;
+			}
+		}
+	}
+
+	if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
+		mask = strtoul(ctmp + 5, NULL, 0x10);
+		if (mask == 0)
+			mask = WPA_BSS_MASK_ALL;
+	}
+
+	if (bss == NULL)
+		return 0;
+
+	if (bsslast == NULL)
+		bsslast = bss;
+	do {
+		len = print_bss_info(wpa_s, bss, mask, buf, buflen);
+		ret += len;
+		buf += len;
+		buflen -= len;
+		if (bss == bsslast)
+			break;
+		next = bss->list_id.next;
+		if (next == &wpa_s->bss_id)
+			break;
+		bss = dl_list_entry(next, struct wpa_bss, list_id);
+	} while (bss && len);
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_ap_scan(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int ap_scan = atoi(cmd);
+	return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
+}
+
+
+static int wpa_supplicant_ctrl_iface_scan_interval(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int scan_int = atoi(cmd);
+	return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_age(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int expire_age = atoi(cmd);
+	return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_count(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int expire_count = atoi(cmd);
+	return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_flush(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int flush_age = atoi(cmd);
+
+	if (flush_age == 0)
+		wpa_bss_flush(wpa_s);
+	else
+		wpa_bss_flush_by_age(wpa_s, flush_age);
+	return 0;
+}
+
+
+static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
+	/* MLME-DELETEKEYS.request */
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
+			0);
+	/* MLME-SETPROTECTION.request(None) */
+	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
+				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+				   MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+	wpa_sm_drop_sa(wpa_s->wpa);
+}
+
+
+static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
+					  char *addr)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+	return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (hwaddr_aton(addr, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
+			   "from BSS table");
+		return -1;
+	}
+
+	/*
+	 * TODO: Find best network configuration block from configuration to
+	 * allow roaming to other networks
+	 */
+
+	if (!ssid) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+			   "configuration known for the target AP");
+		return -1;
+	}
+
+	wpa_s->reassociate = 1;
+	wpa_supplicant_connect(wpa_s, bss, ssid);
+
+	return 0;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
+
+#ifdef CONFIG_P2P
+static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	unsigned int timeout = atoi(cmd);
+	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
+	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+	char *pos;
+	unsigned int search_delay;
+
+	if (os_strstr(cmd, "type=social"))
+		type = P2P_FIND_ONLY_SOCIAL;
+	else if (os_strstr(cmd, "type=progressive"))
+		type = P2P_FIND_PROGRESSIVE;
+
+	pos = os_strstr(cmd, "dev_id=");
+	if (pos) {
+		pos += 7;
+		if (hwaddr_aton(pos, dev_id))
+			return -1;
+		_dev_id = dev_id;
+	}
+
+	pos = os_strstr(cmd, "delay=");
+	if (pos) {
+		pos += 6;
+		search_delay = atoi(pos);
+	} else
+		search_delay = wpas_p2p_search_delay(wpa_s);
+
+	return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
+			     search_delay);
+}
+
+
+static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
+			    char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	char *pos, *pos2;
+	char *pin = NULL;
+	enum p2p_wps_method wps_method;
+	int new_pin;
+	int ret;
+	int persistent_group, persistent_id = -1;
+	int join;
+	int auth;
+	int automatic;
+	int go_intent = -1;
+	int freq = 0;
+	int pd;
+	int ht40;
+
+	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+	 * [persistent|persistent=<network id>]
+	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+	 * [ht40] */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	persistent_group = os_strstr(pos, " persistent") != NULL;
+	pos2 = os_strstr(pos, " persistent=");
+	if (pos2) {
+		struct wpa_ssid *ssid;
+		persistent_id = atoi(pos2 + 12);
+		ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+		if (ssid == NULL || ssid->disabled != 2 ||
+		    ssid->mode != WPAS_MODE_P2P_GO) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "SSID id=%d for persistent P2P group (GO)",
+				   persistent_id);
+			return -1;
+		}
+	}
+	join = os_strstr(pos, " join") != NULL;
+	auth = os_strstr(pos, " auth") != NULL;
+	automatic = os_strstr(pos, " auto") != NULL;
+	pd = os_strstr(pos, " provdisc") != NULL;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	pos2 = os_strstr(pos, " go_intent=");
+	if (pos2) {
+		pos2 += 11;
+		go_intent = atoi(pos2);
+		if (go_intent < 0 || go_intent > 15)
+			return -1;
+	}
+
+	pos2 = os_strstr(pos, " freq=");
+	if (pos2) {
+		pos2 += 6;
+		freq = atoi(pos2);
+		if (freq <= 0)
+			return -1;
+	}
+
+	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 {
+		pin = pos;
+		pos = os_strchr(pin, ' ');
+		wps_method = WPS_PIN_KEYPAD;
+		if (pos) {
+			*pos++ = '\0';
+			if (os_strncmp(pos, "display", 7) == 0)
+				wps_method = WPS_PIN_DISPLAY;
+		}
+		if (!wps_pin_str_valid(pin)) {
+			os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
+			return 17;
+		}
+	}
+
+	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+				   persistent_group, automatic, join,
+				   auth, go_intent, freq, persistent_id, pd,
+				   ht40);
+	if (new_pin == -2) {
+		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
+		return 25;
+	}
+	if (new_pin == -3) {
+		os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
+		return 25;
+	}
+	if (new_pin < 0)
+		return -1;
+	if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
+		ret = os_snprintf(buf, buflen, "%08d", new_pin);
+		if (ret < 0 || (size_t) ret >= buflen)
+			return -1;
+		return ret;
+	}
+
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	unsigned int timeout = atoi(cmd);
+	return wpas_p2p_listen(wpa_s, timeout);
+}
+
+
+static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	char *pos;
+	enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
+
+	/* <addr> <config method> [join|auto] */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	if (os_strstr(pos, " join") != NULL)
+		use = WPAS_P2P_PD_FOR_JOIN;
+	else if (os_strstr(pos, " auto") != NULL)
+		use = WPAS_P2P_PD_AUTO;
+
+	return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+}
+
+
+static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
+			      size_t buflen)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+	    ssid->passphrase == NULL)
+		return -1;
+
+	os_strlcpy(buf, ssid->passphrase, buflen);
+	return os_strlen(buf);
+}
+
+
+static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
+				  char *buf, size_t buflen)
+{
+	u64 ref;
+	int res;
+	u8 dst_buf[ETH_ALEN], *dst;
+	struct wpabuf *tlvs;
+	char *pos;
+	size_t len;
+
+	if (hwaddr_aton(cmd, dst_buf))
+		return -1;
+	dst = dst_buf;
+	if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
+	    dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
+		dst = NULL;
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	if (os_strncmp(pos, "upnp ", 5) == 0) {
+		u8 version;
+		pos += 5;
+		if (hexstr2bin(pos, &version, 1) < 0)
+			return -1;
+		pos += 2;
+		if (*pos != ' ')
+			return -1;
+		pos++;
+		ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+		ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
+	} else {
+		len = os_strlen(pos);
+		if (len & 1)
+			return -1;
+		len /= 2;
+		tlvs = wpabuf_alloc(len);
+		if (tlvs == NULL)
+			return -1;
+		if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
+			wpabuf_free(tlvs);
+			return -1;
+		}
+
+		ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+		wpabuf_free(tlvs);
+	}
+	if (ref == 0)
+		return -1;
+	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
+	if (res < 0 || (unsigned) res >= buflen)
+		return -1;
+	return res;
+}
+
+
+static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	long long unsigned val;
+	u64 req;
+	if (sscanf(cmd, "%llx", &val) != 1)
+		return -1;
+	req = val;
+	return wpas_p2p_sd_cancel_request(wpa_s, req);
+}
+
+
+static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int freq;
+	u8 dst[ETH_ALEN];
+	u8 dialog_token;
+	struct wpabuf *resp_tlvs;
+	char *pos, *pos2;
+	size_t len;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	freq = atoi(cmd);
+	if (freq == 0)
+		return -1;
+
+	if (hwaddr_aton(pos, dst))
+		return -1;
+	pos += 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL)
+		return -1;
+	*pos2++ = '\0';
+	dialog_token = atoi(pos);
+
+	len = os_strlen(pos2);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	resp_tlvs = wpabuf_alloc(len);
+	if (resp_tlvs == NULL)
+		return -1;
+	if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
+		wpabuf_free(resp_tlvs);
+		return -1;
+	}
+
+	wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
+	wpabuf_free(resp_tlvs);
+	return 0;
+}
+
+
+static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
+				       char *cmd)
+{
+	if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
+		return -1;
+	wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
+	return 0;
+}
+
+
+static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
+					char *cmd)
+{
+	char *pos;
+	size_t len;
+	struct wpabuf *query, *resp;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	len = os_strlen(cmd);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	query = wpabuf_alloc(len);
+	if (query == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+		wpabuf_free(query);
+		return -1;
+	}
+
+	len = os_strlen(pos);
+	if (len & 1) {
+		wpabuf_free(query);
+		return -1;
+	}
+	len /= 2;
+	resp = wpabuf_alloc(len);
+	if (resp == NULL) {
+		wpabuf_free(query);
+		return -1;
+	}
+	if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
+		wpabuf_free(query);
+		wpabuf_free(resp);
+		return -1;
+	}
+
+	if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+		wpabuf_free(query);
+		wpabuf_free(resp);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 version;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (hexstr2bin(cmd, &version, 1) < 0)
+		return -1;
+
+	return wpas_p2p_service_add_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "bonjour") == 0)
+		return p2p_ctrl_service_add_bonjour(wpa_s, pos);
+	if (os_strcmp(cmd, "upnp") == 0)
+		return p2p_ctrl_service_add_upnp(wpa_s, pos);
+	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
+					char *cmd)
+{
+	size_t len;
+	struct wpabuf *query;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	query = wpabuf_alloc(len);
+	if (query == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+		wpabuf_free(query);
+		return -1;
+	}
+
+	ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+	wpabuf_free(query);
+	return ret;
+}
+
+
+static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 version;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (hexstr2bin(cmd, &version, 1) < 0)
+		return -1;
+
+	return wpas_p2p_service_del_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "bonjour") == 0)
+		return p2p_ctrl_service_del_bonjour(wpa_s, pos);
+	if (os_strcmp(cmd, "upnp") == 0)
+		return p2p_ctrl_service_del_upnp(wpa_s, pos);
+	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+
+	/* <addr> */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	return wpas_p2p_reject(wpa_s, addr);
+}
+
+
+static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	int id;
+	struct wpa_ssid *ssid;
+	u8 *_peer = NULL, peer[ETH_ALEN];
+	int freq = 0;
+	int ht40;
+
+	id = atoi(cmd);
+	pos = os_strstr(cmd, " peer=");
+	if (pos) {
+		pos += 6;
+		if (hwaddr_aton(pos, peer))
+			return -1;
+		_peer = peer;
+	}
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL || ssid->disabled != 2) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "for persistent P2P group",
+			   id);
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " freq=");
+	if (pos) {
+		pos += 6;
+		freq = atoi(pos);
+		if (freq <= 0)
+			return -1;
+	}
+
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+}
+
+
+static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
+
+	pos = os_strstr(cmd, " peer=");
+	if (!pos)
+		return -1;
+
+	*pos = '\0';
+	pos += 6;
+	if (hwaddr_aton(pos, peer)) {
+		wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
+		return -1;
+	}
+
+	pos = os_strstr(pos, " go_dev_addr=");
+	if (pos) {
+		pos += 13;
+		if (hwaddr_aton(pos, go_dev_addr)) {
+			wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
+				   pos);
+			return -1;
+		}
+		go_dev = go_dev_addr;
+	}
+
+	return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
+}
+
+
+static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	if (os_strncmp(cmd, "persistent=", 11) == 0)
+		return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
+	if (os_strncmp(cmd, "group=", 6) == 0)
+		return p2p_ctrl_invite_group(wpa_s, cmd + 6);
+
+	return -1;
+}
+
+
+static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
+					 char *cmd, int freq, int ht40)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	id = atoi(cmd);
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL || ssid->disabled != 2) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "for persistent P2P group",
+			   id);
+		return -1;
+	}
+
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
+}
+
+
+static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int freq = 0, ht40;
+	char *pos;
+
+	pos = os_strstr(cmd, "freq=");
+	if (pos)
+		freq = atoi(pos + 5);
+
+	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	if (os_strncmp(cmd, "persistent=", 11) == 0)
+		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+						     ht40);
+	if (os_strcmp(cmd, "persistent") == 0 ||
+	    os_strncmp(cmd, "persistent ", 11) == 0)
+		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+	if (os_strncmp(cmd, "freq=", 5) == 0)
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+	if (ht40)
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+
+	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
+		   cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
+			 char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN], *addr_ptr;
+	int next, res;
+	const struct p2p_peer_info *info;
+	char *pos, *end;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	struct wpa_ssid *ssid;
+	size_t i;
+
+	if (!wpa_s->global->p2p)
+		return -1;
+
+	if (os_strcmp(cmd, "FIRST") == 0) {
+		addr_ptr = NULL;
+		next = 0;
+	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+		if (hwaddr_aton(cmd + 5, addr) < 0)
+			return -1;
+		addr_ptr = addr;
+		next = 1;
+	} else {
+		if (hwaddr_aton(cmd, addr) < 0)
+			return -1;
+		addr_ptr = addr;
+		next = 0;
+	}
+
+	info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
+	if (info == NULL)
+		return -1;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos, MACSTR "\n"
+			  "pri_dev_type=%s\n"
+			  "device_name=%s\n"
+			  "manufacturer=%s\n"
+			  "model_name=%s\n"
+			  "model_number=%s\n"
+			  "serial_number=%s\n"
+			  "config_methods=0x%x\n"
+			  "dev_capab=0x%x\n"
+			  "group_capab=0x%x\n"
+			  "level=%d\n",
+			  MAC2STR(info->p2p_device_addr),
+			  wps_dev_type_bin2str(info->pri_dev_type,
+					       devtype, sizeof(devtype)),
+			  info->device_name,
+			  info->manufacturer,
+			  info->model_name,
+			  info->model_number,
+			  info->serial_number,
+			  info->config_methods,
+			  info->dev_capab,
+			  info->group_capab,
+			  info->level);
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+	{
+		const u8 *t;
+		t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+				  wps_dev_type_bin2str(t, devtype,
+						       sizeof(devtype)));
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
+	if (ssid) {
+		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	res = p2p_get_peer_info_txt(info, pos, end - pos);
+	if (res < 0)
+		return pos - buf;
+	pos += res;
+
+	return pos - buf;
+}
+
+
+static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
+				  const char *param)
+{
+	struct wpa_freq_range *freq = NULL, *n;
+	unsigned int count = 0, i;
+	const char *pos, *pos2, *pos3;
+
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+
+	/*
+	 * param includes comma separated frequency range.
+	 * For example: 2412-2432,2462,5000-6000
+	 */
+	pos = param;
+	while (pos && pos[0]) {
+		n = os_realloc_array(freq, count + 1,
+				     sizeof(struct wpa_freq_range));
+		if (n == NULL) {
+			os_free(freq);
+			return -1;
+		}
+		freq = n;
+		freq[count].min = atoi(pos);
+		pos2 = os_strchr(pos, '-');
+		pos3 = os_strchr(pos, ',');
+		if (pos2 && (!pos3 || pos2 < pos3)) {
+			pos2++;
+			freq[count].max = atoi(pos2);
+		} else
+			freq[count].max = freq[count].min;
+		pos = pos3;
+		if (pos)
+			pos++;
+		count++;
+	}
+
+	for (i = 0; i < count; i++) {
+		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
+			   freq[i].min, freq[i].max);
+	}
+
+	os_free(wpa_s->global->p2p_disallow_freq);
+	wpa_s->global->p2p_disallow_freq = freq;
+	wpa_s->global->num_p2p_disallow_freq = count;
+	wpas_p2p_update_channel_list(wpa_s);
+	return 0;
+}
+
+
+static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *param;
+
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+
+	param = os_strchr(cmd, ' ');
+	if (param == NULL)
+		return -1;
+	*param++ = '\0';
+
+	if (os_strcmp(cmd, "discoverability") == 0) {
+		p2p_set_client_discoverability(wpa_s->global->p2p,
+					       atoi(param));
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "managed") == 0) {
+		p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "listen_channel") == 0) {
+		return p2p_set_listen_channel(wpa_s->global->p2p, 81,
+					      atoi(param));
+	}
+
+	if (os_strcmp(cmd, "ssid_postfix") == 0) {
+		return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
+					    os_strlen(param));
+	}
+
+	if (os_strcmp(cmd, "noa") == 0) {
+		char *pos;
+		int count, start, duration;
+		/* GO NoA parameters: count,start_offset(ms),duration(ms) */
+		count = atoi(param);
+		pos = os_strchr(param, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		start = atoi(pos);
+		pos = os_strchr(pos, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		duration = atoi(pos);
+		if (count < 0 || count > 255 || start < 0 || duration < 0)
+			return -1;
+		if (count == 0 && duration > 0)
+			return -1;
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
+			   "start=%d duration=%d", count, start, duration);
+		return wpas_p2p_set_noa(wpa_s, count, start, duration);
+	}
+
+	if (os_strcmp(cmd, "ps") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
+
+	if (os_strcmp(cmd, "oppps") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
+
+	if (os_strcmp(cmd, "ctwindow") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
+
+	if (os_strcmp(cmd, "disabled") == 0) {
+		wpa_s->global->p2p_disabled = atoi(param);
+		wpa_printf(MSG_DEBUG, "P2P functionality %s",
+			   wpa_s->global->p2p_disabled ?
+			   "disabled" : "enabled");
+		if (wpa_s->global->p2p_disabled) {
+			wpas_p2p_stop_find(wpa_s);
+			os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+			p2p_flush(wpa_s->global->p2p);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "conc_pref") == 0) {
+		if (os_strcmp(param, "sta") == 0)
+			wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
+		else if (os_strcmp(param, "p2p") == 0)
+			wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
+		else {
+			wpa_printf(MSG_INFO, "Invalid conc_pref value");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
+			   "%s", param);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "force_long_sd") == 0) {
+		wpa_s->force_long_sd = atoi(param);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "peer_filter") == 0) {
+		u8 addr[ETH_ALEN];
+		if (hwaddr_aton(param, addr))
+			return -1;
+		p2p_set_peer_filter(wpa_s->global->p2p, addr);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "cross_connect") == 0)
+		return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
+
+	if (os_strcmp(cmd, "go_apsd") == 0) {
+		if (os_strcmp(param, "disable") == 0)
+			wpa_s->set_ap_uapsd = 0;
+		else {
+			wpa_s->set_ap_uapsd = 1;
+			wpa_s->ap_uapsd = atoi(param);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "client_apsd") == 0) {
+		if (os_strcmp(param, "disable") == 0)
+			wpa_s->set_sta_uapsd = 0;
+		else {
+			int be, bk, vi, vo;
+			char *pos;
+			/* format: BE,BK,VI,VO;max SP Length */
+			be = atoi(param);
+			pos = os_strchr(param, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			bk = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vi = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vo = atoi(pos);
+			/* ignore max SP Length for now */
+
+			wpa_s->set_sta_uapsd = 1;
+			wpa_s->sta_uapsd = 0;
+			if (be)
+				wpa_s->sta_uapsd |= BIT(0);
+			if (bk)
+				wpa_s->sta_uapsd |= BIT(1);
+			if (vi)
+				wpa_s->sta_uapsd |= BIT(2);
+			if (vo)
+				wpa_s->sta_uapsd |= BIT(3);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "disallow_freq") == 0)
+		return p2p_ctrl_disallow_freq(wpa_s, param);
+
+	if (os_strcmp(cmd, "disc_int") == 0) {
+		int min_disc_int, max_disc_int, max_disc_tu;
+		char *pos;
+
+		pos = param;
+
+		min_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_tu = atoi(pos);
+
+		return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+					max_disc_int, max_disc_tu);
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
+		   cmd);
+
+	return -1;
+}
+
+
+static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos, *pos2;
+	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+
+	if (cmd[0]) {
+		pos = os_strchr(cmd, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		dur1 = atoi(cmd);
+
+		pos2 = os_strchr(pos, ' ');
+		if (pos2)
+			*pos2++ = '\0';
+		int1 = atoi(pos);
+	} else
+		pos2 = NULL;
+
+	if (pos2) {
+		pos = os_strchr(pos2, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		dur2 = atoi(pos2);
+		int2 = atoi(pos);
+	}
+
+	return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
+}
+
+
+static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	unsigned int period = 0, interval = 0;
+
+	if (cmd[0]) {
+		pos = os_strchr(cmd, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		period = atoi(cmd);
+		interval = atoi(pos);
+	}
+
+	return wpas_p2p_ext_listen(wpa_s, period, interval);
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_INTERWORKING
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+
+	if (hwaddr_aton(dst, bssid)) {
+		wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+		return -1;
+	}
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
+			   MAC2STR(bssid));
+		return -1;
+	}
+
+	return interworking_connect(wpa_s, bss);
+}
+
+
+static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *pos;
+#define MAX_ANQP_INFO_ID 100
+	u16 id[MAX_ANQP_INFO_ID];
+	size_t num_id = 0;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+	pos = dst + used;
+	while (num_id < MAX_ANQP_INFO_ID) {
+		id[num_id] = atoi(pos);
+		if (id[num_id])
+			num_id++;
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	if (num_id == 0)
+		return -1;
+
+	return anqp_send_req(wpa_s, dst_addr, id, num_id);
+}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 dst_addr[ETH_ALEN];
+	struct wpabuf *advproto, *query = NULL;
+	int used, ret = -1;
+	char *pos, *end;
+	size_t len;
+
+	used = hwaddr_aton2(cmd, dst_addr);
+	if (used < 0)
+		return -1;
+
+	pos = cmd + used;
+	while (*pos == ' ')
+		pos++;
+
+	/* Advertisement Protocol ID */
+	end = os_strchr(pos, ' ');
+	if (end)
+		len = end - pos;
+	else
+		len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+	if (len == 0)
+		return -1;
+	advproto = wpabuf_alloc(len);
+	if (advproto == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+		goto fail;
+
+	if (end) {
+		/* Optional Query Request */
+		pos = end + 1;
+		while (*pos == ' ')
+			pos++;
+
+		len = os_strlen(pos);
+		if (len) {
+			if (len & 0x01)
+				goto fail;
+			len /= 2;
+			if (len == 0)
+				goto fail;
+			query = wpabuf_alloc(len);
+			if (query == NULL)
+				goto fail;
+			if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+				goto fail;
+		}
+	}
+
+	ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+	wpabuf_free(advproto);
+	wpabuf_free(query);
+
+	return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+			    size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	int dialog_token;
+	int used;
+	char *pos;
+	size_t resp_len, start, requested_len;
+
+	if (!wpa_s->last_gas_resp)
+		return -1;
+
+	used = hwaddr_aton2(cmd, addr);
+	if (used < 0)
+		return -1;
+
+	pos = cmd + used;
+	while (*pos == ' ')
+		pos++;
+	dialog_token = atoi(pos);
+
+	if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
+	    dialog_token != wpa_s->last_gas_dialog_token)
+		return -1;
+
+	resp_len = wpabuf_len(wpa_s->last_gas_resp);
+	start = 0;
+	requested_len = resp_len;
+
+	pos = os_strchr(pos, ' ');
+	if (pos) {
+		start = atoi(pos);
+		if (start > resp_len)
+			return os_snprintf(buf, buflen, "FAIL-Invalid range");
+		pos = os_strchr(pos, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		requested_len = atoi(pos);
+		if (start + requested_len > resp_len)
+			return os_snprintf(buf, buflen, "FAIL-Invalid range");
+	}
+
+	if (requested_len * 2 + 1 > buflen)
+		return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+	return wpa_snprintf_hex(buf, buflen,
+				wpabuf_head_u8(wpa_s->last_gas_resp) + start,
+				requested_len);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *pos;
+	u32 subtypes = 0;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+	pos = dst + used;
+	for (;;) {
+		int num = atoi(pos);
+		if (num <= 0 || num > 31)
+			return -1;
+		subtypes |= BIT(num);
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	if (subtypes == 0)
+		return -1;
+
+	return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
+
+
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+				    const u8 *addr, const char *realm)
+{
+	u8 *buf;
+	size_t rlen, len;
+	int ret;
+
+	rlen = os_strlen(realm);
+	len = 3 + rlen;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+	buf[0] = 1; /* NAI Home Realm Count */
+	buf[1] = 0; /* Formatted in accordance with RFC 4282 */
+	buf[2] = rlen;
+	os_memcpy(buf + 3, realm, rlen);
+
+	ret = hs20_anqp_send_req(wpa_s, addr,
+				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+				 buf, len);
+
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+					char *dst)
+{
+	struct wpa_cred *cred = wpa_s->conf->cred;
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	u8 *buf;
+	size_t len;
+	int ret;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+
+	while (dst[used] == ' ')
+		used++;
+	if (os_strncmp(dst + used, "realm=", 6) == 0)
+		return hs20_nai_home_realm_list(wpa_s, dst_addr,
+						dst + used + 6);
+
+	len = os_strlen(dst + used);
+
+	if (len == 0 && cred && cred->realm)
+		return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
+
+	if (len % 1)
+		return -1;
+	len /= 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(dst + used, buf, len) < 0) {
+		os_free(buf);
+		return -1;
+	}
+
+	ret = hs20_anqp_send_req(wpa_s, dst_addr,
+				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+				 buf, len);
+	os_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static int wpa_supplicant_ctrl_iface_sta_autoconnect(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
+	return 0;
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
+					      char *cmd)
+{
+	enum wpa_states state = wpa_s->wpa_state;
+	char *new_params = NULL;
+
+	if (os_strlen(cmd) > 0) {
+		new_params = os_strdup(cmd);
+		if (new_params == NULL)
+			return -1;
+	}
+
+	os_free(wpa_s->conf->autoscan);
+	wpa_s->conf->autoscan = new_params;
+
+	if (wpa_s->conf->autoscan == NULL)
+		autoscan_deinit(wpa_s);
+	else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+		autoscan_init(wpa_s, 1);
+	else if (state == WPA_SCANNING)
+		wpa_supplicant_reinit_autoscan(wpa_s);
+
+	return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int enter;
+	int intval = 0;
+	char *pos;
+	int ret;
+	struct wpabuf *tfs_req = NULL;
+
+	if (os_strncmp(cmd, "enter", 5) == 0)
+		enter = 1;
+	else if (os_strncmp(cmd, "exit", 4) == 0)
+		enter = 0;
+	else
+		return -1;
+
+	pos = os_strstr(cmd, " interval=");
+	if (pos)
+		intval = atoi(pos + 10);
+
+	pos = os_strstr(cmd, " tfs_req=");
+	if (pos) {
+		char *end;
+		size_t len;
+		pos += 9;
+		end = os_strchr(pos, ' ');
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (len & 1)
+			return -1;
+		len /= 2;
+		tfs_req = wpabuf_alloc(len);
+		if (tfs_req == NULL)
+			return -1;
+		if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
+			wpabuf_free(tfs_req);
+			return -1;
+		}
+	}
+
+	ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
+					   WNM_SLEEP_MODE_EXIT, intval,
+					   tfs_req);
+	wpabuf_free(tfs_req);
+
+	return ret;
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
+				      size_t buflen)
+{
+	struct wpa_signal_info si;
+	int ret;
+
+	ret = wpa_drv_signal_poll(wpa_s, &si);
+	if (ret)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+			  "NOISE=%d\nFREQUENCY=%u\n",
+			  si.current_signal, si.current_txrate / 1000,
+			  si.current_noise, si.frequency);
+	if (ret < 0 || (unsigned int) ret > buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
+				      size_t buflen)
+{
+	struct hostap_sta_driver_data sta;
+	int ret;
+
+	ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
+	if (ret)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
+			  sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
+	if (ret < 0 || (size_t) ret > buflen)
+		return -1;
+	return ret;
+}
+
+
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+					 char *buf, size_t *resp_len)
+{
+	char *reply;
+	const int reply_size = 4096;
+	int ctrl_rsp = 0;
+	int reply_len;
+
+	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
+	    os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+	    os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+	    os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
+				      (const u8 *) buf, os_strlen(buf));
+	} else {
+		int level = MSG_DEBUG;
+		if (os_strcmp(buf, "PING") == 0)
+			level = MSG_EXCESSIVE;
+		wpa_hexdump_ascii(level, "RX ctrl_iface",
+				  (const u8 *) buf, os_strlen(buf));
+		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
+	}
+
+	reply = os_malloc(reply_size);
+	if (reply == NULL) {
+		*resp_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strcmp(buf, "IFNAME") == 0) {
+		reply_len = os_strlen(wpa_s->ifname);
+		os_memcpy(reply, wpa_s->ifname, reply_len);
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
+	} else if (os_strcmp(buf, "MIB") == 0) {
+		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
+		if (reply_len >= 0) {
+			int res;
+			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
+					       reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
+		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);
+	} else if (os_strncmp(buf, "SET ", 4) == 0) {
+		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET ", 4) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
+							  reply, reply_size);
+	} else if (os_strcmp(buf, "LOGON") == 0) {
+		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+	} else if (os_strcmp(buf, "LOGOFF") == 0) {
+		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else
+			wpas_request_connection(wpa_s);
+	} else if (os_strcmp(buf, "RECONNECT") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else if (wpa_s->disconnected)
+			wpas_request_connection(wpa_s);
+#ifdef IEEE8021X_EAPOL
+	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
+			reply_len = -1;
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_PEERKEY
+	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
+			reply_len = -1;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
+		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
+		if (res == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (res)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
+		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
+		if (res == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (res)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
+							      reply,
+							      reply_size);
+	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
+			wpa_s, buf + 14, reply, reply_size);
+	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+		if (wpas_wps_cancel(wpa_s))
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strcmp(buf, "WPS_NFC") == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+			wpa_s, buf + 14, reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_req(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_sel(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+		reply_len = wpas_ctrl_nfc_rx_handover_req(
+			wpa_s, buf + 20, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+		if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+			reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
+	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
+			reply_len = -1;
+#ifdef CONFIG_AP
+	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
+			wpa_s, buf + 11, reply, reply_size);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_WPS_ER
+	} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
+		if (wpas_wps_er_start(wpa_s, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
+		if (wpas_wps_er_start(wpa_s, buf + 13))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
+		if (wpas_wps_er_stop(wpa_s))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
+		int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
+		if (ret == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (ret == -3) {
+			os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
+			reply_len = 18;
+		} else if (ret == -4) {
+			os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
+			reply_len = 20;
+		} else if (ret)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
+								buf + 18))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+			wpa_s, buf + 24, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS_ER */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IBSS_RSN
+	} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
+		if (p2p_ctrl_find(wpa_s, buf + 9))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_FIND") == 0) {
+		if (p2p_ctrl_find(wpa_s, ""))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
+		wpas_p2p_stop_find(wpa_s);
+	} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
+		reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
+					     reply_size);
+	} else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
+		if (p2p_ctrl_listen(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
+		if (p2p_ctrl_listen(wpa_s, ""))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
+		if (wpas_p2p_group_remove(wpa_s, buf + 17))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
+		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+			reply_len = -1;
+	} 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_PROV_DISC ", 14) == 0) {
+		if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
+		reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
+		reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
+		if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
+		if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
+		wpas_p2p_sd_service_update(wpa_s);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
+		if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
+		wpas_p2p_service_flush(wpa_s);
+	} else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
+		if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
+		if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
+		if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
+		if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
+		reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
+					      reply_size);
+	} else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
+		if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
+		os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+		wpa_s->force_long_sd = 0;
+		if (wpa_s->global->p2p)
+			p2p_flush(wpa_s->global->p2p);
+	} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
+		if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
+		if (wpas_p2p_cancel(wpa_s))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
+		if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
+		if (p2p_ctrl_presence_req(wpa_s, "") < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
+		if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
+		if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
+			reply_len = -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+		if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+		reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+						     reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
+		if (interworking_fetch_anqp(wpa_s) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
+		interworking_stop_fetch_anqp(wpa_s);
+	} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
+		if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
+					NULL) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
+		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
+		if (get_anqp(wpa_s, buf + 9) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+		if (gas_request(wpa_s, buf + 12) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+		reply_len = gas_response_get(wpa_s, buf + 17, reply,
+					     reply_size);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
+		if (get_hs20_anqp(wpa_s, buf + 14) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
+		if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
+			reply_len = -1;
+#endif /* CONFIG_HS20 */
+	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
+	{
+		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
+			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
+			reply_len = -1;
+		else
+			ctrl_rsp = 1;
+	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
+		if (wpa_supplicant_reload_configuration(wpa_s))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "TERMINATE") == 0) {
+		wpa_supplicant_terminate_proc(wpa_s->global);
+	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_blacklist(
+			wpa_s, buf + 9, reply, reply_size);
+	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_log_level(
+			wpa_s, buf + 9, reply, reply_size);
+	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_list_networks(
+			wpa_s, 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);
+	} else if (os_strcmp(buf, "SCAN") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else {
+			if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
+			     (wpa_s->wpa_state == WPA_COMPLETED))) {
+				wpa_s->normal_scans = 0;
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else if (wpa_s->sched_scanning) {
+				wpa_printf(MSG_DEBUG, "Stop ongoing "
+					   "sched_scan to allow requested "
+					   "full scan to proceed");
+				wpa_supplicant_cancel_sched_scan(wpa_s);
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else {
+				wpa_printf(MSG_DEBUG, "Ongoing scan action - "
+					   "reject new request");
+				reply_len = os_snprintf(reply, reply_size,
+							"FAIL-BUSY\n");
+			}
+		}
+	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_scan_results(
+			wpa_s, reply, reply_size);
+	} 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_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
+		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_add_network(
+			wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get_network(
+			wpa_s, buf + 12, reply, reply_size);
+	} else if (os_strcmp(buf, "LIST_CREDS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_list_creds(
+			wpa_s, reply, reply_size);
+	} else if (os_strcmp(buf, "ADD_CRED") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_add_cred(
+			wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
+		if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
+			reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
+			reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get_capability(
+			wpa_s, buf + 15, reply, reply_size);
+	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
+			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) {
+		reply_len = wpa_supplicant_global_iface_interfaces(
+			wpa_s->global, 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);
+#ifdef CONFIG_AP
+	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
+		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "STA ", 4) == 0) {
+		reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
+					      reply_size);
+	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+		if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+			reply_len = -1;
+#endif /* CONFIG_AP */
+	} else if (os_strcmp(buf, "SUSPEND") == 0) {
+		wpas_notify_suspend(wpa_s->global);
+	} else if (os_strcmp(buf, "RESUME") == 0) {
+		wpas_notify_resume(wpa_s->global);
+	} else if (os_strcmp(buf, "DROP_SA") == 0) {
+		wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
+	} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
+		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
+		if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
+			reply_len = -1;
+#ifdef CONFIG_TDLS
+	} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
+			reply_len = -1;
+#endif /* CONFIG_TDLS */
+	} 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, "PKTCNT_POLL", 11) == 0) {
+		reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
+						       reply_size);
+#ifdef CONFIG_AUTOSCAN
+	} else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_AUTOSCAN */
+	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+		pmksa_cache_clear_current(wpa_s->wpa);
+		eapol_sm_request_reauth(wpa_s->eapol);
+#ifdef CONFIG_WNM
+	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
+		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
+			reply_len = -1;
+#endif /* CONFIG_WNM */
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	if (ctrl_rsp)
+		eapol_sm_notify_ctrl_response(wpa_s->eapol);
+
+	*resp_len = reply_len;
+	return reply;
+}
+
+
+static int wpa_supplicant_global_iface_add(struct wpa_global *global,
+					   char *cmd)
+{
+	struct wpa_interface iface;
+	char *pos;
+
+	/*
+	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
+	 * TAB<bridge_ifname>
+	 */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
+
+	os_memset(&iface, 0, sizeof(iface));
+
+	do {
+		iface.ifname = pos = cmd;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.ifname[0] == '\0')
+			return -1;
+		if (pos == NULL)
+			break;
+
+		iface.confname = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.confname[0] == '\0')
+			iface.confname = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.driver = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.driver[0] == '\0')
+			iface.driver = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.ctrl_interface = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.ctrl_interface[0] == '\0')
+			iface.ctrl_interface = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.driver_param = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.driver_param[0] == '\0')
+			iface.driver_param = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.bridge_ifname = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.bridge_ifname[0] == '\0')
+			iface.bridge_ifname = NULL;
+		if (pos == NULL)
+			break;
+	} while (0);
+
+	if (wpa_supplicant_get_iface(global, iface.ifname))
+		return -1;
+
+	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+}
+
+
+static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
+					      char *cmd)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
+
+	wpa_s = wpa_supplicant_get_iface(global, cmd);
+	if (wpa_s == NULL)
+		return -1;
+	return wpa_supplicant_remove_iface(global, wpa_s, 0);
+}
+
+
+static void wpa_free_iface_info(struct wpa_interface_info *iface)
+{
+	struct wpa_interface_info *prev;
+
+	while (iface) {
+		prev = iface;
+		iface = iface->next;
+
+		os_free(prev->ifname);
+		os_free(prev->desc);
+		os_free(prev);
+	}
+}
+
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+					    char *buf, int len)
+{
+	int i, res;
+	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
+	char *pos, *end;
+
+	for (i = 0; wpa_drivers[i]; i++) {
+		struct wpa_driver_ops *drv = wpa_drivers[i];
+		if (drv->get_interfaces == NULL)
+			continue;
+		tmp = drv->get_interfaces(global->drv_priv[i]);
+		if (tmp == NULL)
+			continue;
+
+		if (last == NULL)
+			iface = last = tmp;
+		else
+			last->next = tmp;
+		while (last->next)
+			last = last->next;
+	}
+
+	pos = buf;
+	end = buf + len;
+	for (tmp = iface; tmp; tmp = tmp->next) {
+		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
+				  tmp->drv_name, tmp->ifname,
+				  tmp->desc ? tmp->desc : "");
+		if (res < 0 || res >= end - pos) {
+			*pos = '\0';
+			break;
+		}
+		pos += res;
+	}
+
+	wpa_free_iface_info(iface);
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+						  char *buf, int len)
+{
+	int res;
+	char *pos, *end;
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = global->ifaces;
+	pos = buf;
+	end = buf + len;
+
+	while (wpa_s) {
+		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+		if (res < 0 || res >= end - pos) {
+			*pos = '\0';
+			break;
+		}
+		pos += res;
+		wpa_s = wpa_s->next;
+	}
+	return pos - buf;
+}
+
+
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+						char *buf, size_t *resp_len)
+{
+	char *reply;
+	const int reply_size = 2048;
+	int reply_len;
+	int level = MSG_DEBUG;
+
+	if (os_strcmp(buf, "PING") == 0)
+		level = MSG_EXCESSIVE;
+	wpa_hexdump_ascii(level, "RX global ctrl_iface",
+			  (const u8 *) buf, os_strlen(buf));
+
+	reply = os_malloc(reply_size);
+	if (reply == NULL) {
+		*resp_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
+		if (wpa_supplicant_global_iface_add(global, buf + 14))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
+		if (wpa_supplicant_global_iface_remove(global, buf + 17))
+			reply_len = -1;
+	} 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) {
+		reply_len = wpa_supplicant_global_iface_interfaces(
+			global, reply, reply_size);
+	} else if (os_strcmp(buf, "TERMINATE") == 0) {
+		wpa_supplicant_terminate_proc(global);
+	} else if (os_strcmp(buf, "SUSPEND") == 0) {
+		wpas_notify_suspend(global);
+	} else if (os_strcmp(buf, "RESUME") == 0) {
+		wpas_notify_resume(global);
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	*resp_len = reply_len;
+	return reply;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ctrl_iface.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,159 +0,0 @@
-/*
- * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_H
-#define CTRL_IFACE_H
-
-#ifdef CONFIG_CTRL_IFACE
-
-/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
-
-/**
- * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command
- * @wpa_s: Pointer to wpa_supplicant data
- * @buf: Received command buffer (nul terminated string)
- * @resp_len: Variable to be set to the response length
- * Returns: Response (*resp_len bytes) or %NULL on failure
- *
- * Control interface backends call this function when receiving a message that
- * they do not process internally, i.e., anything else than ATTACH, DETACH,
- * and LEVEL. The return response value is then sent to the external program
- * that sent the command. Caller is responsible for freeing the buffer after
- * this. If %NULL is returned, *resp_len can be set to two special values:
- * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any
- * other value, no response is sent.
- */
-char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
-					 char *buf, size_t *resp_len);
-
-/**
- * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command
- * @global: Pointer to global data from wpa_supplicant_init()
- * @buf: Received command buffer (nul terminated string)
- * @resp_len: Variable to be set to the response length
- * Returns: Response (*resp_len bytes) or %NULL on failure
- *
- * Control interface backends call this function when receiving a message from
- * the global ctrl_iface connection. The return response value is then sent to
- * the external program that sent the command. Caller is responsible for
- * freeing the buffer after this. If %NULL is returned, *resp_len can be set to
- * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If
- * *resp_len has any other value, no response is sent.
- */
-char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
-						char *buf, size_t *resp_len);
-
-
-/* Functions that each ctrl_iface backend must implement */
-
-/**
- * wpa_supplicant_ctrl_iface_init - Initialize control interface
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: Pointer to private data on success, %NULL on failure
- *
- * Initialize the control interface and start receiving commands from external
- * programs.
- *
- * Required to be implemented in each control interface backend.
- */
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
-
-/**
- * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
- *
- * Deinitialize the control interface that was initialized with
- * wpa_supplicant_ctrl_iface_init().
- *
- * Required to be implemented in each control interface backend.
- */
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
-
-/**
- * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
- *
- * Wait until the first message from an external program using the control
- * interface is received. This function can be used to delay normal startup
- * processing to allow control interface programs to attach with
- * %wpa_supplicant before normal operations are started.
- *
- * Required to be implemented in each control interface backend.
- */
-void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
-
-/**
- * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: Pointer to private data on success, %NULL on failure
- *
- * Initialize the global control interface and start receiving commands from
- * external programs.
- *
- * Required to be implemented in each control interface backend.
- */
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
-
-/**
- * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface
- * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init()
- *
- * Deinitialize the global control interface that was initialized with
- * wpa_supplicant_global_ctrl_iface_init().
- *
- * Required to be implemented in each control interface backend.
- */
-void wpa_supplicant_global_ctrl_iface_deinit(
-	struct ctrl_iface_global_priv *priv);
-
-#else /* CONFIG_CTRL_IFACE */
-
-static inline struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
-{
-	return (void *) -1;
-}
-
-static inline void
-wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
-{
-}
-
-static inline void
-wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level,
-			       char *buf, size_t len)
-{
-}
-
-static inline void
-wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
-{
-}
-
-static inline struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
-{
-	return (void *) 1;
-}
-
-static inline void
-wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
-{
-}
-
-#endif /* CONFIG_CTRL_IFACE */
-
-#endif /* CTRL_IFACE_H */

Copied: vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/ctrl_iface.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifdef CONFIG_CTRL_IFACE
+
+/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message that
+ * they do not process internally, i.e., anything else than ATTACH, DETACH,
+ * and LEVEL. The return response value is then sent to the external program
+ * that sent the command. Caller is responsible for freeing the buffer after
+ * this. If %NULL is returned, *resp_len can be set to two special values:
+ * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any
+ * other value, no response is sent.
+ */
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+					 char *buf, size_t *resp_len);
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message from
+ * the global ctrl_iface connection. The return response value is then sent to
+ * the external program that sent the command. Caller is responsible for
+ * freeing the buffer after this. If %NULL is returned, *resp_len can be set to
+ * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If
+ * *resp_len has any other value, no response is sent.
+ */
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+						char *buf, size_t *resp_len);
+
+
+/* Functions that each ctrl_iface backend must implement */
+
+/**
+ * wpa_supplicant_ctrl_iface_init - Initialize control interface
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the control interface and start receiving commands from external
+ * programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
+
+/**
+ * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Deinitialize the control interface that was initialized with
+ * wpa_supplicant_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Wait until the first message from an external program using the control
+ * interface is received. This function can be used to delay normal startup
+ * processing to allow control interface programs to attach with
+ * %wpa_supplicant before normal operations are started.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the global control interface and start receiving commands from
+ * external programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface
+ * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init()
+ *
+ * Deinitialize the global control interface that was initialized with
+ * wpa_supplicant_global_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_global_ctrl_iface_deinit(
+	struct ctrl_iface_global_priv *priv);
+
+#else /* CONFIG_CTRL_IFACE */
+
+static inline struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	return (void *) -1;
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level,
+			       char *buf, size_t len)
+{
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+}
+
+static inline struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	return (void *) 1;
+}
+
+static inline void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+}
+
+#endif /* CONFIG_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ctrl_iface_named_pipe.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,835 +0,0 @@
-/*
- * WPA Supplicant / Windows Named Pipe -based control interface
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "config.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "wpa_supplicant_i.h"
-#include "ctrl_iface.h"
-#include "common/wpa_ctrl.h"
-
-#ifdef __MINGW32_VERSION
-/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
- */
-#define SDDL_REVISION_1 1
-BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
-	LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
-BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
-	LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
-#ifdef UNICODE
-#define ConvertStringSecurityDescriptorToSecurityDescriptor \
-ConvertStringSecurityDescriptorToSecurityDescriptorW
-#else
-#define ConvertStringSecurityDescriptorToSecurityDescriptor \
-ConvertStringSecurityDescriptorToSecurityDescriptorA
-#endif
-#else /* __MINGW32_VERSION */
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0500
-#endif
-#include <sddl.h>
-#endif /* __MINGW32_VERSION */
-
-#ifndef WPA_SUPPLICANT_NAMED_PIPE
-#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
-#endif
-#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
-
-/* Per-interface ctrl_iface */
-
-#define REQUEST_BUFSIZE 256
-#define REPLY_BUFSIZE 4096
-
-struct ctrl_iface_priv;
-
-/**
- * struct wpa_ctrl_dst - Internal data structure of control interface clients
- *
- * This structure is used to store information about registered control
- * interface monitors into struct wpa_supplicant. This data is private to
- * ctrl_iface_named_pipe.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
-	/* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
-	OVERLAPPED overlap;
-	struct wpa_ctrl_dst *next, *prev;
-	struct ctrl_iface_priv *priv;
-	HANDLE pipe;
-	int attached;
-	int debug_level;
-	int errors;
-	char req_buf[REQUEST_BUFSIZE];
-	char *rsp_buf;
-	int used;
-};
-
-
-struct ctrl_iface_priv {
-	struct wpa_supplicant *wpa_s;
-	struct wpa_ctrl_dst *ctrl_dst;
-	SECURITY_ATTRIBUTES attr;
-	int sec_attr_set;
-};
-
-
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len);
-
-static void ctrl_close_pipe(struct wpa_ctrl_dst *dst);
-static void wpa_supplicant_ctrl_iface_receive(void *, void *);
-static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
-					     LPOVERLAPPED overlap);
-
-struct wpa_global_dst;
-static void global_close_pipe(struct wpa_global_dst *dst);
-static void wpa_supplicant_global_iface_receive(void *eloop_data,
-						void *user_ctx);
-static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
-					       LPOVERLAPPED overlap);
-
-
-static int ctrl_broken_pipe(HANDLE pipe, int used)
-{
-	DWORD err;
-
-	if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL))
-		return 0;
-
-	err = GetLastError();
-	if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used))
-		return 1;
-	return 0;
-}
-
-
-static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv)
-{
-	struct wpa_ctrl_dst *dst, *next;
-
-	dst = priv->ctrl_dst;
-
-	while (dst) {
-		next = dst->next;
-		if (ctrl_broken_pipe(dst->pipe, dst->used)) {
-			wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
-				   dst);
-			ctrl_close_pipe(dst);
-		}
-		dst = next;
-	}
-}
-
-
-static int ctrl_open_pipe(struct ctrl_iface_priv *priv)
-{
-	struct wpa_ctrl_dst *dst;
-	DWORD err;
-	TCHAR name[256];
-
-	dst = os_zalloc(sizeof(*dst));
-	if (dst == NULL)
-		return -1;
-	wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
-
-	dst->priv = priv;
-	dst->debug_level = MSG_INFO;
-	dst->pipe = INVALID_HANDLE_VALUE;
-
-	dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
-	if (dst->overlap.hEvent == NULL) {
-		wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
-			   (int) GetLastError());
-		goto fail;
-	}
-
-	eloop_register_event(dst->overlap.hEvent,
-			     sizeof(dst->overlap.hEvent),
-			     wpa_supplicant_ctrl_iface_receive, dst, NULL);
-
-#ifdef UNICODE
-	_snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
-		   priv->wpa_s->ifname);
-#else /* UNICODE */
-	os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
-		    priv->wpa_s->ifname);
-#endif /* UNICODE */
-
-	/* TODO: add support for configuring access list for the pipe */
-	dst->pipe = CreateNamedPipe(name,
-				    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-				    PIPE_TYPE_MESSAGE |
-				    PIPE_READMODE_MESSAGE |
-				    PIPE_WAIT,
-				    15, REPLY_BUFSIZE, REQUEST_BUFSIZE,
-				    1000,
-				    priv->sec_attr_set ? &priv->attr : NULL);
-	if (dst->pipe == INVALID_HANDLE_VALUE) {
-		wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
-			   (int) GetLastError());
-		goto fail;
-	}
-
-	if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
-		wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
-			   (int) GetLastError());
-		CloseHandle(dst->pipe);
-		os_free(dst);
-		return -1;
-	}
-
-	err = GetLastError();
-	switch (err) {
-	case ERROR_IO_PENDING:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
-			   "progress");
-		break;
-	case ERROR_PIPE_CONNECTED:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
-			   "connected");
-		if (SetEvent(dst->overlap.hEvent))
-			break;
-		/* fall through */
-	default:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
-			   (int) err);
-		CloseHandle(dst->pipe);
-		os_free(dst);
-		return -1;
-	}
-
-	dst->next = priv->ctrl_dst;
-	if (dst->next)
-		dst->next->prev = dst;
-	priv->ctrl_dst = dst;
-
-	return 0;
-
-fail:
-	ctrl_close_pipe(dst);
-	return -1;
-}
-
-
-static void ctrl_close_pipe(struct wpa_ctrl_dst *dst)
-{
-	wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
-
-	if (dst->overlap.hEvent) {
-		eloop_unregister_event(dst->overlap.hEvent,
-				       sizeof(dst->overlap.hEvent));
-		CloseHandle(dst->overlap.hEvent);
-	}
-
-	if (dst->pipe != INVALID_HANDLE_VALUE) {
-		/*
-		 * Could use FlushFileBuffers() here to guarantee that all data
-		 * gets delivered to the client, but that can block, so let's
-		 * not do this for now.
-		 * FlushFileBuffers(dst->pipe);
-		 */
-		CloseHandle(dst->pipe);
-	}
-
-	if (dst->prev)
-		dst->prev->next = dst->next;
-	else
-		dst->priv->ctrl_dst = dst->next;
-	if (dst->next)
-		dst->next->prev = dst->prev;
-
-	os_free(dst->rsp_buf);
-	os_free(dst);
-}
-
-
-static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes,
-					      LPOVERLAPPED overlap)
-{
-	struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
-		   "err=%d bytes=%d", dst, (int) err, (int) bytes);
-	if (err) {
-		ctrl_close_pipe(dst);
-		return;
-	}
-
-	os_free(dst->rsp_buf);
-	dst->rsp_buf = NULL;
-
-	if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
-			&dst->overlap, ctrl_iface_read_completed)) {
-		wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
-			   (int) GetLastError());
-		ctrl_close_pipe(dst);
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
-}
-
-
-static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
-{
-	struct wpa_supplicant *wpa_s = dst->priv->wpa_s;
-	char *reply = NULL, *send_buf;
-	size_t reply_len = 0, send_len;
-	int new_attached = 0;
-	char *buf = dst->req_buf;
-
-	dst->used = 1;
-	if (len >= REQUEST_BUFSIZE)
-		len = REQUEST_BUFSIZE - 1;
-	buf[len] = '\0';
-
-	if (os_strcmp(buf, "ATTACH") == 0) {
-		dst->attached = 1;
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached");
-		new_attached = 1;
-		reply_len = 2;
-	} else if (os_strcmp(buf, "DETACH") == 0) {
-		dst->attached = 0;
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached");
-		reply_len = 2;
-	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6);
-		dst->debug_level = atoi(buf + 6);
-		reply_len = 2;
-	} else {
-		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
-							  &reply_len);
-	}
-
-	if (reply) {
-		send_buf = reply;
-		send_len = reply_len;
-	} else if (reply_len == 2) {
-		send_buf = "OK\n";
-		send_len = 3;
-	} else {
-		send_buf = "FAIL\n";
-		send_len = 5;
-	}
-
-	os_free(dst->rsp_buf);
-	dst->rsp_buf = os_malloc(send_len);
-	if (dst->rsp_buf == NULL) {
-		ctrl_close_pipe(dst);
-		os_free(reply);
-		return;
-	}
-	os_memcpy(dst->rsp_buf, send_buf, send_len);
-	os_free(reply);
-
-	if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
-			 ctrl_iface_write_completed)) {
-		wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
-			   (int) GetLastError());
-		ctrl_close_pipe(dst);
-	} else {
-		wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
-			   dst);
-	}
-
-	if (new_attached)
-		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
-}
-
-
-static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
-					     LPOVERLAPPED overlap)
-{
-	struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
-		   "bytes=%d", dst, (int) err, (int) bytes);
-	if (err == 0 && bytes > 0)
-		wpa_supplicant_ctrl_iface_rx(dst, bytes);
-}
-
-
-static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx)
-{
-	struct wpa_ctrl_dst *dst = eloop_data;
-	struct ctrl_iface_priv *priv = dst->priv;
-	DWORD bytes;
-
-	wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive");
-	ResetEvent(dst->overlap.hEvent);
-
-	if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
-		wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
-			   (int) GetLastError());
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
-		   "connected");
-
-	/* Open a new named pipe for the next client. */
-	ctrl_open_pipe(priv);
-
-	/* Use write completion function to start reading a command */
-	ctrl_iface_write_completed(0, 0, &dst->overlap);
-
-	ctrl_flush_broken_pipes(priv);
-}
-
-
-static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
-{
-	const char *sddl = NULL;
-	TCHAR *t_sddl;
-
-	if (os_strncmp(params, "SDDL=", 5) == 0)
-		sddl = params + 5;
-	if (!sddl) {
-		sddl = os_strstr(params, " SDDL=");
-		if (sddl)
-			sddl += 6;
-	}
-
-	if (!sddl)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl);
-	os_memset(&priv->attr, 0, sizeof(priv->attr));
-	priv->attr.nLength = sizeof(priv->attr);
-	priv->attr.bInheritHandle = FALSE;
-	t_sddl = wpa_strdup_tchar(sddl);
-	if (t_sddl == NULL)
-		return -1;
-	if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
-		    t_sddl, SDDL_REVISION_1,
-		    (PSECURITY_DESCRIPTOR *) (void *)
-		    &priv->attr.lpSecurityDescriptor,
-		    NULL)) {
-		os_free(t_sddl);
-		wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "
-			   "security descriptor: %d",
-			   sddl, (int) GetLastError());
-		return -1;
-	}
-	os_free(t_sddl);
-
-	priv->sec_attr_set = 1;
-
-	return 0;
-}
-
-
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
-					     const char *txt, size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
-		return;
-	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
-}
-
-
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
-{
-	struct ctrl_iface_priv *priv;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->wpa_s = wpa_s;
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return priv;
-
-	if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) {
-		os_free(priv);
-		return NULL;
-	}
-
-	if (ctrl_open_pipe(priv) < 0) {
-		os_free(priv);
-		return NULL;
-	}
-
-	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
-
-	return priv;
-}
-
-
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
-{
-	while (priv->ctrl_dst)
-		ctrl_close_pipe(priv->ctrl_dst);
-	if (priv->sec_attr_set)
-		LocalFree(priv->attr.lpSecurityDescriptor);
-	os_free(priv);
-}
-
-
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len)
-{
-	struct wpa_ctrl_dst *dst, *next;
-	char levelstr[10];
-	int idx;
-	char *sbuf;
-	int llen;
-	DWORD written;
-
-	dst = priv->ctrl_dst;
-	if (dst == NULL)
-		return;
-
-	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-
-	llen = os_strlen(levelstr);
-	sbuf = os_malloc(llen + len);
-	if (sbuf == NULL)
-		return;
-
-	os_memcpy(sbuf, levelstr, llen);
-	os_memcpy(sbuf + llen, buf, len);
-
-	idx = 0;
-	while (dst) {
-		next = dst->next;
-		if (dst->attached && level >= dst->debug_level) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p",
-				   dst);
-			if (!WriteFile(dst->pipe, sbuf, llen + len, &written,
-				       NULL)) {
-				wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst "
-					   "%p failed: %d",
-					   dst, (int) GetLastError());
-				dst->errors++;
-				if (dst->errors > 10)
-					ctrl_close_pipe(dst);
-			} else
-				dst->errors = 0;
-		}
-		idx++;
-		dst = next;
-	}
-	os_free(sbuf);
-}
-
-
-void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
-{
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
-		   priv->wpa_s->ifname);
-	if (priv->ctrl_dst == NULL)
-		return;
-	WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE);
-}
-
-
-/* Global ctrl_iface */
-
-struct ctrl_iface_global_priv;
-
-struct wpa_global_dst {
-	/* Note: OVERLAPPED must be the first member of struct wpa_global_dst
-	 */
-	OVERLAPPED overlap;
-	struct wpa_global_dst *next, *prev;
-	struct ctrl_iface_global_priv *priv;
-	HANDLE pipe;
-	char req_buf[REQUEST_BUFSIZE];
-	char *rsp_buf;
-	int used;
-};
-
-struct ctrl_iface_global_priv {
-	struct wpa_global *global;
-	struct wpa_global_dst *ctrl_dst;
-};
-
-
-static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv)
-{
-	struct wpa_global_dst *dst, *next;
-
-	dst = priv->ctrl_dst;
-
-	while (dst) {
-		next = dst->next;
-		if (ctrl_broken_pipe(dst->pipe, dst->used)) {
-			wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
-				   dst);
-			global_close_pipe(dst);
-		}
-		dst = next;
-	}
-}
-
-
-static int global_open_pipe(struct ctrl_iface_global_priv *priv)
-{
-	struct wpa_global_dst *dst;
-	DWORD err;
-
-	dst = os_zalloc(sizeof(*dst));
-	if (dst == NULL)
-		return -1;
-	wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
-
-	dst->priv = priv;
-	dst->pipe = INVALID_HANDLE_VALUE;
-
-	dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
-	if (dst->overlap.hEvent == NULL) {
-		wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
-			   (int) GetLastError());
-		goto fail;
-	}
-
-	eloop_register_event(dst->overlap.hEvent,
-			     sizeof(dst->overlap.hEvent),
-			     wpa_supplicant_global_iface_receive, dst, NULL);
-
-	/* TODO: add support for configuring access list for the pipe */
-	dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX,
-				    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-				    PIPE_TYPE_MESSAGE |
-				    PIPE_READMODE_MESSAGE |
-				    PIPE_WAIT,
-				    10, REPLY_BUFSIZE, REQUEST_BUFSIZE,
-				    1000, NULL);
-	if (dst->pipe == INVALID_HANDLE_VALUE) {
-		wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
-			   (int) GetLastError());
-		goto fail;
-	}
-
-	if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
-		wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
-			   (int) GetLastError());
-		CloseHandle(dst->pipe);
-		os_free(dst);
-		return -1;
-	}
-
-	err = GetLastError();
-	switch (err) {
-	case ERROR_IO_PENDING:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
-			   "progress");
-		break;
-	case ERROR_PIPE_CONNECTED:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
-			   "connected");
-		if (SetEvent(dst->overlap.hEvent))
-			break;
-		/* fall through */
-	default:
-		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
-			   (int) err);
-		CloseHandle(dst->pipe);
-		os_free(dst);
-		return -1;
-	}
-
-	dst->next = priv->ctrl_dst;
-	if (dst->next)
-		dst->next->prev = dst;
-	priv->ctrl_dst = dst;
-
-	return 0;
-
-fail:
-	global_close_pipe(dst);
-	return -1;
-}
-
-
-static void global_close_pipe(struct wpa_global_dst *dst)
-{
-	wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
-
-	if (dst->overlap.hEvent) {
-		eloop_unregister_event(dst->overlap.hEvent,
-				       sizeof(dst->overlap.hEvent));
-		CloseHandle(dst->overlap.hEvent);
-	}
-
-	if (dst->pipe != INVALID_HANDLE_VALUE) {
-		/*
-		 * Could use FlushFileBuffers() here to guarantee that all data
-		 * gets delivered to the client, but that can block, so let's
-		 * not do this for now.
-		 * FlushFileBuffers(dst->pipe);
-		 */
-		CloseHandle(dst->pipe);
-	}
-
-	if (dst->prev)
-		dst->prev->next = dst->next;
-	else
-		dst->priv->ctrl_dst = dst->next;
-	if (dst->next)
-		dst->next->prev = dst->prev;
-
-	os_free(dst->rsp_buf);
-	os_free(dst);
-}
-
-
-static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes,
-						LPOVERLAPPED overlap)
-{
-	struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
-		   "err=%d bytes=%d", dst, (int) err, (int) bytes);
-	if (err) {
-		global_close_pipe(dst);
-		return;
-	}
-
-	os_free(dst->rsp_buf);
-	dst->rsp_buf = NULL;
-
-	if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
-			&dst->overlap, global_iface_read_completed)) {
-		wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
-			   (int) GetLastError());
-		global_close_pipe(dst);
-		/* FIX: if this was the pipe waiting for new global
-		 * connections, at this point there are no open global pipes..
-		 * Should try to open a new pipe.. */
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
-}
-
-
-static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
-					   size_t len)
-{
-	struct wpa_global *global = dst->priv->global;
-	char *reply = NULL, *send_buf;
-	size_t reply_len = 0, send_len;
-	char *buf = dst->req_buf;
-
-	dst->used = 1;
-	if (len >= REQUEST_BUFSIZE)
-		len = REQUEST_BUFSIZE - 1;
-	buf[len] = '\0';
-
-	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-							 &reply_len);
-	if (reply) {
-		send_buf = reply;
-		send_len = reply_len;
-	} else if (reply_len) {
-		send_buf = "FAIL\n";
-		send_len = 5;
-	} else {
-		os_free(dst->rsp_buf);
-		dst->rsp_buf = NULL;
-		return;
-	}
-
-	os_free(dst->rsp_buf);
-	dst->rsp_buf = os_malloc(send_len);
-	if (dst->rsp_buf == NULL) {
-		global_close_pipe(dst);
-		os_free(reply);
-		return;
-	}
-	os_memcpy(dst->rsp_buf, send_buf, send_len);
-	os_free(reply);
-
-	if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
-			 global_iface_write_completed)) {
-		wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
-			   (int) GetLastError());
-		global_close_pipe(dst);
-	} else {
-		wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
-			   dst);
-	}
-}
-
-
-static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
-					       LPOVERLAPPED overlap)
-{
-	struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
-	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
-		   "bytes=%d", dst, (int) err, (int) bytes);
-	if (err == 0 && bytes > 0)
-		wpa_supplicant_global_iface_rx(dst, bytes);
-}
-
-
-static void wpa_supplicant_global_iface_receive(void *eloop_data,
-						void *user_ctx)
-{
-	struct wpa_global_dst *dst = eloop_data;
-	struct ctrl_iface_global_priv *priv = dst->priv;
-	DWORD bytes;
-
-	wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive");
-	ResetEvent(dst->overlap.hEvent);
-
-	if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
-		wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
-			   (int) GetLastError());
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
-		   "connected");
-
-	/* Open a new named pipe for the next client. */
-	if (global_open_pipe(priv) < 0) {
-		wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed");
-		return;
-	}
-
-	/* Use write completion function to start reading a command */
-	global_iface_write_completed(0, 0, &dst->overlap);
-
-	global_flush_broken_pipes(priv);
-}
-
-
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
-{
-	struct ctrl_iface_global_priv *priv;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->global = global;
-
-	if (global_open_pipe(priv) < 0) {
-		os_free(priv);
-		return NULL;
-	}
-
-	return priv;
-}
-
-
-void
-wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
-{
-	while (priv->ctrl_dst)
-		global_close_pipe(priv->ctrl_dst);
-	os_free(priv);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ctrl_iface_named_pipe.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_named_pipe.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,829 @@
+/*
+ * WPA Supplicant / Windows Named Pipe -based control interface
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "common/wpa_ctrl.h"
+
+#ifdef __MINGW32_VERSION
+/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
+ */
+#define SDDL_REVISION_1 1
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
+	LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
+	LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+#ifdef UNICODE
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorW
+#else
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorA
+#endif
+#else /* __MINGW32_VERSION */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <sddl.h>
+#endif /* __MINGW32_VERSION */
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+/* Per-interface ctrl_iface */
+
+#define REQUEST_BUFSIZE 256
+#define REPLY_BUFSIZE 4096
+
+struct ctrl_iface_priv;
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface clients
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_named_pipe.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+	/* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
+	OVERLAPPED overlap;
+	struct wpa_ctrl_dst *next, *prev;
+	struct ctrl_iface_priv *priv;
+	HANDLE pipe;
+	int attached;
+	int debug_level;
+	int errors;
+	char req_buf[REQUEST_BUFSIZE];
+	char *rsp_buf;
+	int used;
+};
+
+
+struct ctrl_iface_priv {
+	struct wpa_supplicant *wpa_s;
+	struct wpa_ctrl_dst *ctrl_dst;
+	SECURITY_ATTRIBUTES attr;
+	int sec_attr_set;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len);
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst);
+static void wpa_supplicant_ctrl_iface_receive(void *, void *);
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+					     LPOVERLAPPED overlap);
+
+struct wpa_global_dst;
+static void global_close_pipe(struct wpa_global_dst *dst);
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+						void *user_ctx);
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+					       LPOVERLAPPED overlap);
+
+
+static int ctrl_broken_pipe(HANDLE pipe, int used)
+{
+	DWORD err;
+
+	if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL))
+		return 0;
+
+	err = GetLastError();
+	if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used))
+		return 1;
+	return 0;
+}
+
+
+static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv)
+{
+	struct wpa_ctrl_dst *dst, *next;
+
+	dst = priv->ctrl_dst;
+
+	while (dst) {
+		next = dst->next;
+		if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+			wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+				   dst);
+			ctrl_close_pipe(dst);
+		}
+		dst = next;
+	}
+}
+
+
+static int ctrl_open_pipe(struct ctrl_iface_priv *priv)
+{
+	struct wpa_ctrl_dst *dst;
+	DWORD err;
+	TCHAR name[256];
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+	dst->priv = priv;
+	dst->debug_level = MSG_INFO;
+	dst->pipe = INVALID_HANDLE_VALUE;
+
+	dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	if (dst->overlap.hEvent == NULL) {
+		wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+			   (int) GetLastError());
+		goto fail;
+	}
+
+	eloop_register_event(dst->overlap.hEvent,
+			     sizeof(dst->overlap.hEvent),
+			     wpa_supplicant_ctrl_iface_receive, dst, NULL);
+
+#ifdef UNICODE
+	_snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+		   priv->wpa_s->ifname);
+#else /* UNICODE */
+	os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+		    priv->wpa_s->ifname);
+#endif /* UNICODE */
+
+	/* TODO: add support for configuring access list for the pipe */
+	dst->pipe = CreateNamedPipe(name,
+				    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+				    PIPE_TYPE_MESSAGE |
+				    PIPE_READMODE_MESSAGE |
+				    PIPE_WAIT,
+				    15, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+				    1000,
+				    priv->sec_attr_set ? &priv->attr : NULL);
+	if (dst->pipe == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+			   (int) GetLastError());
+		goto fail;
+	}
+
+	if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+		wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+			   (int) GetLastError());
+		CloseHandle(dst->pipe);
+		os_free(dst);
+		return -1;
+	}
+
+	err = GetLastError();
+	switch (err) {
+	case ERROR_IO_PENDING:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+			   "progress");
+		break;
+	case ERROR_PIPE_CONNECTED:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+			   "connected");
+		if (SetEvent(dst->overlap.hEvent))
+			break;
+		/* fall through */
+	default:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+			   (int) err);
+		CloseHandle(dst->pipe);
+		os_free(dst);
+		return -1;
+	}
+
+	dst->next = priv->ctrl_dst;
+	if (dst->next)
+		dst->next->prev = dst;
+	priv->ctrl_dst = dst;
+
+	return 0;
+
+fail:
+	ctrl_close_pipe(dst);
+	return -1;
+}
+
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst)
+{
+	wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+	if (dst->overlap.hEvent) {
+		eloop_unregister_event(dst->overlap.hEvent,
+				       sizeof(dst->overlap.hEvent));
+		CloseHandle(dst->overlap.hEvent);
+	}
+
+	if (dst->pipe != INVALID_HANDLE_VALUE) {
+		/*
+		 * Could use FlushFileBuffers() here to guarantee that all data
+		 * gets delivered to the client, but that can block, so let's
+		 * not do this for now.
+		 * FlushFileBuffers(dst->pipe);
+		 */
+		CloseHandle(dst->pipe);
+	}
+
+	if (dst->prev)
+		dst->prev->next = dst->next;
+	else
+		dst->priv->ctrl_dst = dst->next;
+	if (dst->next)
+		dst->next->prev = dst->prev;
+
+	os_free(dst->rsp_buf);
+	os_free(dst);
+}
+
+
+static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes,
+					      LPOVERLAPPED overlap)
+{
+	struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+		   "err=%d bytes=%d", dst, (int) err, (int) bytes);
+	if (err) {
+		ctrl_close_pipe(dst);
+		return;
+	}
+
+	os_free(dst->rsp_buf);
+	dst->rsp_buf = NULL;
+
+	if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+			&dst->overlap, ctrl_iface_read_completed)) {
+		wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+			   (int) GetLastError());
+		ctrl_close_pipe(dst);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
+{
+	struct wpa_supplicant *wpa_s = dst->priv->wpa_s;
+	char *reply = NULL, *send_buf;
+	size_t reply_len = 0, send_len;
+	int new_attached = 0;
+	char *buf = dst->req_buf;
+
+	dst->used = 1;
+	if (len >= REQUEST_BUFSIZE)
+		len = REQUEST_BUFSIZE - 1;
+	buf[len] = '\0';
+
+	if (os_strcmp(buf, "ATTACH") == 0) {
+		dst->attached = 1;
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached");
+		new_attached = 1;
+		reply_len = 2;
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		dst->attached = 0;
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached");
+		reply_len = 2;
+	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6);
+		dst->debug_level = atoi(buf + 6);
+		reply_len = 2;
+	} else {
+		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+							  &reply_len);
+	}
+
+	if (reply) {
+		send_buf = reply;
+		send_len = reply_len;
+	} else if (reply_len == 2) {
+		send_buf = "OK\n";
+		send_len = 3;
+	} else {
+		send_buf = "FAIL\n";
+		send_len = 5;
+	}
+
+	os_free(dst->rsp_buf);
+	dst->rsp_buf = os_malloc(send_len);
+	if (dst->rsp_buf == NULL) {
+		ctrl_close_pipe(dst);
+		os_free(reply);
+		return;
+	}
+	os_memcpy(dst->rsp_buf, send_buf, send_len);
+	os_free(reply);
+
+	if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+			 ctrl_iface_write_completed)) {
+		wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+			   (int) GetLastError());
+		ctrl_close_pipe(dst);
+	} else {
+		wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+			   dst);
+	}
+
+	if (new_attached)
+		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+					     LPOVERLAPPED overlap)
+{
+	struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+		   "bytes=%d", dst, (int) err, (int) bytes);
+	if (err == 0 && bytes > 0)
+		wpa_supplicant_ctrl_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx)
+{
+	struct wpa_ctrl_dst *dst = eloop_data;
+	struct ctrl_iface_priv *priv = dst->priv;
+	DWORD bytes;
+
+	wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive");
+	ResetEvent(dst->overlap.hEvent);
+
+	if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+		wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+			   (int) GetLastError());
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+		   "connected");
+
+	/* Open a new named pipe for the next client. */
+	ctrl_open_pipe(priv);
+
+	/* Use write completion function to start reading a command */
+	ctrl_iface_write_completed(0, 0, &dst->overlap);
+
+	ctrl_flush_broken_pipes(priv);
+}
+
+
+static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
+{
+	const char *sddl = NULL;
+	TCHAR *t_sddl;
+
+	if (os_strncmp(params, "SDDL=", 5) == 0)
+		sddl = params + 5;
+	if (!sddl) {
+		sddl = os_strstr(params, " SDDL=");
+		if (sddl)
+			sddl += 6;
+	}
+
+	if (!sddl)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl);
+	os_memset(&priv->attr, 0, sizeof(priv->attr));
+	priv->attr.nLength = sizeof(priv->attr);
+	priv->attr.bInheritHandle = FALSE;
+	t_sddl = wpa_strdup_tchar(sddl);
+	if (t_sddl == NULL)
+		return -1;
+	if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
+		    t_sddl, SDDL_REVISION_1,
+		    (PSECURITY_DESCRIPTOR *) (void *)
+		    &priv->attr.lpSecurityDescriptor,
+		    NULL)) {
+		os_free(t_sddl);
+		wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "
+			   "security descriptor: %d",
+			   sddl, (int) GetLastError());
+		return -1;
+	}
+	os_free(t_sddl);
+
+	priv->sec_attr_set = 1;
+
+	return 0;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+					     const char *txt, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+		return;
+	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->wpa_s = wpa_s;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	if (ctrl_open_pipe(priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	return priv;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+	while (priv->ctrl_dst)
+		ctrl_close_pipe(priv->ctrl_dst);
+	if (priv->sec_attr_set)
+		LocalFree(priv->attr.lpSecurityDescriptor);
+	os_free(priv);
+}
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	char levelstr[10];
+	int idx;
+	char *sbuf;
+	int llen;
+	DWORD written;
+
+	dst = priv->ctrl_dst;
+	if (dst == NULL)
+		return;
+
+	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+	llen = os_strlen(levelstr);
+	sbuf = os_malloc(llen + len);
+	if (sbuf == NULL)
+		return;
+
+	os_memcpy(sbuf, levelstr, llen);
+	os_memcpy(sbuf + llen, buf, len);
+
+	idx = 0;
+	while (dst) {
+		next = dst->next;
+		if (dst->attached && level >= dst->debug_level) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p",
+				   dst);
+			if (!WriteFile(dst->pipe, sbuf, llen + len, &written,
+				       NULL)) {
+				wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst "
+					   "%p failed: %d",
+					   dst, (int) GetLastError());
+				dst->errors++;
+				if (dst->errors > 10)
+					ctrl_close_pipe(dst);
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+		dst = next;
+	}
+	os_free(sbuf);
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+		   priv->wpa_s->ifname);
+	if (priv->ctrl_dst == NULL)
+		return;
+	WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE);
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv;
+
+struct wpa_global_dst {
+	/* Note: OVERLAPPED must be the first member of struct wpa_global_dst
+	 */
+	OVERLAPPED overlap;
+	struct wpa_global_dst *next, *prev;
+	struct ctrl_iface_global_priv *priv;
+	HANDLE pipe;
+	char req_buf[REQUEST_BUFSIZE];
+	char *rsp_buf;
+	int used;
+};
+
+struct ctrl_iface_global_priv {
+	struct wpa_global *global;
+	struct wpa_global_dst *ctrl_dst;
+};
+
+
+static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv)
+{
+	struct wpa_global_dst *dst, *next;
+
+	dst = priv->ctrl_dst;
+
+	while (dst) {
+		next = dst->next;
+		if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+			wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+				   dst);
+			global_close_pipe(dst);
+		}
+		dst = next;
+	}
+}
+
+
+static int global_open_pipe(struct ctrl_iface_global_priv *priv)
+{
+	struct wpa_global_dst *dst;
+	DWORD err;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+	dst->priv = priv;
+	dst->pipe = INVALID_HANDLE_VALUE;
+
+	dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	if (dst->overlap.hEvent == NULL) {
+		wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+			   (int) GetLastError());
+		goto fail;
+	}
+
+	eloop_register_event(dst->overlap.hEvent,
+			     sizeof(dst->overlap.hEvent),
+			     wpa_supplicant_global_iface_receive, dst, NULL);
+
+	/* TODO: add support for configuring access list for the pipe */
+	dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX,
+				    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+				    PIPE_TYPE_MESSAGE |
+				    PIPE_READMODE_MESSAGE |
+				    PIPE_WAIT,
+				    10, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+				    1000, NULL);
+	if (dst->pipe == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+			   (int) GetLastError());
+		goto fail;
+	}
+
+	if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+		wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+			   (int) GetLastError());
+		CloseHandle(dst->pipe);
+		os_free(dst);
+		return -1;
+	}
+
+	err = GetLastError();
+	switch (err) {
+	case ERROR_IO_PENDING:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+			   "progress");
+		break;
+	case ERROR_PIPE_CONNECTED:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+			   "connected");
+		if (SetEvent(dst->overlap.hEvent))
+			break;
+		/* fall through */
+	default:
+		wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+			   (int) err);
+		CloseHandle(dst->pipe);
+		os_free(dst);
+		return -1;
+	}
+
+	dst->next = priv->ctrl_dst;
+	if (dst->next)
+		dst->next->prev = dst;
+	priv->ctrl_dst = dst;
+
+	return 0;
+
+fail:
+	global_close_pipe(dst);
+	return -1;
+}
+
+
+static void global_close_pipe(struct wpa_global_dst *dst)
+{
+	wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+	if (dst->overlap.hEvent) {
+		eloop_unregister_event(dst->overlap.hEvent,
+				       sizeof(dst->overlap.hEvent));
+		CloseHandle(dst->overlap.hEvent);
+	}
+
+	if (dst->pipe != INVALID_HANDLE_VALUE) {
+		/*
+		 * Could use FlushFileBuffers() here to guarantee that all data
+		 * gets delivered to the client, but that can block, so let's
+		 * not do this for now.
+		 * FlushFileBuffers(dst->pipe);
+		 */
+		CloseHandle(dst->pipe);
+	}
+
+	if (dst->prev)
+		dst->prev->next = dst->next;
+	else
+		dst->priv->ctrl_dst = dst->next;
+	if (dst->next)
+		dst->next->prev = dst->prev;
+
+	os_free(dst->rsp_buf);
+	os_free(dst);
+}
+
+
+static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes,
+						LPOVERLAPPED overlap)
+{
+	struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+		   "err=%d bytes=%d", dst, (int) err, (int) bytes);
+	if (err) {
+		global_close_pipe(dst);
+		return;
+	}
+
+	os_free(dst->rsp_buf);
+	dst->rsp_buf = NULL;
+
+	if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+			&dst->overlap, global_iface_read_completed)) {
+		wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+			   (int) GetLastError());
+		global_close_pipe(dst);
+		/* FIX: if this was the pipe waiting for new global
+		 * connections, at this point there are no open global pipes..
+		 * Should try to open a new pipe.. */
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
+					   size_t len)
+{
+	struct wpa_global *global = dst->priv->global;
+	char *reply = NULL, *send_buf;
+	size_t reply_len = 0, send_len;
+	char *buf = dst->req_buf;
+
+	dst->used = 1;
+	if (len >= REQUEST_BUFSIZE)
+		len = REQUEST_BUFSIZE - 1;
+	buf[len] = '\0';
+
+	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+							 &reply_len);
+	if (reply) {
+		send_buf = reply;
+		send_len = reply_len;
+	} else if (reply_len) {
+		send_buf = "FAIL\n";
+		send_len = 5;
+	} else {
+		os_free(dst->rsp_buf);
+		dst->rsp_buf = NULL;
+		return;
+	}
+
+	os_free(dst->rsp_buf);
+	dst->rsp_buf = os_malloc(send_len);
+	if (dst->rsp_buf == NULL) {
+		global_close_pipe(dst);
+		os_free(reply);
+		return;
+	}
+	os_memcpy(dst->rsp_buf, send_buf, send_len);
+	os_free(reply);
+
+	if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+			 global_iface_write_completed)) {
+		wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+			   (int) GetLastError());
+		global_close_pipe(dst);
+	} else {
+		wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+			   dst);
+	}
+}
+
+
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+					       LPOVERLAPPED overlap)
+{
+	struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+	wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+		   "bytes=%d", dst, (int) err, (int) bytes);
+	if (err == 0 && bytes > 0)
+		wpa_supplicant_global_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+						void *user_ctx)
+{
+	struct wpa_global_dst *dst = eloop_data;
+	struct ctrl_iface_global_priv *priv = dst->priv;
+	DWORD bytes;
+
+	wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive");
+	ResetEvent(dst->overlap.hEvent);
+
+	if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+		wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+			   (int) GetLastError());
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+		   "connected");
+
+	/* Open a new named pipe for the next client. */
+	if (global_open_pipe(priv) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed");
+		return;
+	}
+
+	/* Use write completion function to start reading a command */
+	global_iface_write_completed(0, 0, &dst->overlap);
+
+	global_flush_broken_pipes(priv);
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->global = global;
+
+	if (global_open_pipe(priv) < 0) {
+		os_free(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+	while (priv->ctrl_dst)
+		global_close_pipe(priv->ctrl_dst);
+	os_free(priv);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ctrl_iface_udp.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,561 +0,0 @@
-/*
- * WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "config.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "wpa_supplicant_i.h"
-#include "ctrl_iface.h"
-#include "common/wpa_ctrl.h"
-
-
-#define COOKIE_LEN 8
-
-/* 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_udp.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
-	struct wpa_ctrl_dst *next;
-	struct sockaddr_in addr;
-	socklen_t addrlen;
-	int debug_level;
-	int errors;
-};
-
-
-struct ctrl_iface_priv {
-	struct wpa_supplicant *wpa_s;
-	int sock;
-	struct wpa_ctrl_dst *ctrl_dst;
-	u8 cookie[COOKIE_LEN];
-};
-
-
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len);
-
-
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
-					    struct sockaddr_in *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_in));
-	dst->addrlen = fromlen;
-	dst->debug_level = MSG_INFO;
-	dst->next = priv->ctrl_dst;
-	priv->ctrl_dst = dst;
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
-		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
-					    struct sockaddr_in *from,
-					    socklen_t fromlen)
-{
-	struct wpa_ctrl_dst *dst, *prev = NULL;
-
-	dst = priv->ctrl_dst;
-	while (dst) {
-		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
-		    from->sin_port == dst->addr.sin_port) {
-			if (prev == NULL)
-				priv->ctrl_dst = dst->next;
-			else
-				prev->next = dst->next;
-			os_free(dst);
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
-				   "%s:%d", inet_ntoa(from->sin_addr),
-				   ntohs(from->sin_port));
-			return 0;
-		}
-		prev = dst;
-		dst = dst->next;
-	}
-	return -1;
-}
-
-
-static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
-					   struct sockaddr_in *from,
-					   socklen_t fromlen,
-					   char *level)
-{
-	struct wpa_ctrl_dst *dst;
-
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
-
-	dst = priv->ctrl_dst;
-	while (dst) {
-		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
-		    from->sin_port == dst->addr.sin_port) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
-				   "level %s:%d", inet_ntoa(from->sin_addr),
-				   ntohs(from->sin_port));
-			dst->debug_level = atoi(level);
-			return 0;
-		}
-		dst = dst->next;
-	}
-
-	return -1;
-}
-
-
-static char *
-wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
-				     size_t *reply_len)
-{
-	char *reply;
-	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
-	if (reply == NULL) {
-		*reply_len = 1;
-		return NULL;
-	}
-
-	os_memcpy(reply, "COOKIE=", 7);
-	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
-			 priv->cookie, COOKIE_LEN);
-
-	*reply_len = 7 + 2 * COOKIE_LEN;
-	return reply;
-}
-
-
-static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
-					      void *sock_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct ctrl_iface_priv *priv = sock_ctx;
-	char buf[256], *pos;
-	int res;
-	struct sockaddr_in from;
-	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
-	size_t reply_len = 0;
-	int new_attached = 0;
-	u8 cookie[COOKIE_LEN];
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
-		return;
-	}
-	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
-		/*
-		 * The OS networking stack is expected to drop this kind of
-		 * frames since the socket is bound to only localhost address.
-		 * Just in case, drop the frame if it is coming from any other
-		 * address.
-		 */
-		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
-			   "source %s", inet_ntoa(from.sin_addr));
-		return;
-	}
-	buf[res] = '\0';
-
-	if (os_strcmp(buf, "GET_COOKIE") == 0) {
-		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
-		goto done;
-	}
-
-	/*
-	 * Require that the client includes a prefix with the 'cookie' value
-	 * fetched with GET_COOKIE command. This is used to verify that the
-	 * client has access to a bidirectional link over UDP in order to
-	 * avoid attacks using forged localhost IP address even if the OS does
-	 * not block such frames from remote destinations.
-	 */
-	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
-			   "drop request");
-		return;
-	}
-
-	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
-			   "request - drop request");
-		return;
-	}
-
-	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
-			   "drop request");
-		return;
-	}
-
-	pos = buf + 7 + 2 * COOKIE_LEN;
-	while (*pos == ' ')
-		pos++;
-
-	if (os_strcmp(pos, "ATTACH") == 0) {
-		if (wpa_supplicant_ctrl_iface_attach(priv, &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))
-			reply_len = 1;
-		else
-			reply_len = 2;
-	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
-		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
-						    pos + 6))
-			reply_len = 1;
-		else
-			reply_len = 2;
-	} else {
-		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
-							  &reply_len);
-	}
-
- done:
-	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} 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);
-	}
-
-	if (new_attached)
-		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
-}
-
-
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
-					     const char *txt, size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
-		return;
-	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
-}
-
-
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
-{
-	struct ctrl_iface_priv *priv;
-	struct sockaddr_in addr;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->wpa_s = wpa_s;
-	priv->sock = -1;
-	os_get_random(priv->cookie, COOKIE_LEN);
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return priv;
-
-	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (priv->sock < 0) {
-		perror("socket(PF_INET)");
-		goto fail;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
-	addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
-	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(AF_INET)");
-		goto fail;
-	}
-
-	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
-				 wpa_s, priv);
-	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
-
-	return priv;
-
-fail:
-	if (priv->sock >= 0)
-		close(priv->sock);
-	os_free(priv);
-	return NULL;
-}
-
-
-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) {
-			/*
-			 * Wait a second before closing the control socket if
-			 * there are any attached monitors in order to allow
-			 * them to receive any pending messages.
-			 */
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
-				   "monitors to receive messages");
-			os_sleep(1, 0);
-		}
-		close(priv->sock);
-		priv->sock = -1;
-	}
-
-	dst = priv->ctrl_dst;
-	while (dst) {
-		prev = dst;
-		dst = dst->next;
-		os_free(prev);
-	}
-	os_free(priv);
-}
-
-
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len)
-{
-	struct wpa_ctrl_dst *dst, *next;
-	char levelstr[10];
-	int idx;
-	char *sbuf;
-	int llen;
-
-	dst = priv->ctrl_dst;
-	if (priv->sock < 0 || dst == NULL)
-		return;
-
-	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-
-	llen = os_strlen(levelstr);
-	sbuf = os_malloc(llen + len);
-	if (sbuf == NULL)
-		return;
-
-	os_memcpy(sbuf, levelstr, llen);
-	os_memcpy(sbuf + llen, buf, len);
-
-	idx = 0;
-	while (dst) {
-		next = dst->next;
-		if (level >= dst->debug_level) {
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
-				   inet_ntoa(dst->addr.sin_addr),
-				   ntohs(dst->addr.sin_port));
-			if (sendto(priv->sock, sbuf, llen + len, 0,
-				   (struct sockaddr *) &dst->addr,
-				   sizeof(dst->addr)) < 0) {
-				perror("sendto(CTRL_IFACE monitor)");
-				dst->errors++;
-				if (dst->errors > 10) {
-					wpa_supplicant_ctrl_iface_detach(
-						priv, &dst->addr,
-						dst->addrlen);
-				}
-			} else
-				dst->errors = 0;
-		}
-		idx++;
-		dst = next;
-	}
-	os_free(sbuf);
-}
-
-
-void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
-{
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
-		   priv->wpa_s->ifname);
-	eloop_wait_for_read_sock(priv->sock);
-}
-
-
-/* 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)
-{
-	char *reply;
-	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
-	if (reply == NULL) {
-		*reply_len = 1;
-		return NULL;
-	}
-
-	os_memcpy(reply, "COOKIE=", 7);
-	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
-			 priv->cookie, COOKIE_LEN);
-
-	*reply_len = 7 + 2 * COOKIE_LEN;
-	return reply;
-}
-
-
-static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
-						     void *sock_ctx)
-{
-	struct wpa_global *global = eloop_ctx;
-	struct ctrl_iface_global_priv *priv = sock_ctx;
-	char buf[256], *pos;
-	int res;
-	struct sockaddr_in from;
-	socklen_t fromlen = sizeof(from);
-	char *reply;
-	size_t reply_len;
-	u8 cookie[COOKIE_LEN];
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
-		return;
-	}
-	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
-		/*
-		 * The OS networking stack is expected to drop this kind of
-		 * frames since the socket is bound to only localhost address.
-		 * Just in case, drop the frame if it is coming from any other
-		 * address.
-		 */
-		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
-			   "source %s", inet_ntoa(from.sin_addr));
-		return;
-	}
-	buf[res] = '\0';
-
-	if (os_strcmp(buf, "GET_COOKIE") == 0) {
-		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
-		goto done;
-	}
-
-	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
-			   "drop request");
-		return;
-	}
-
-	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
-			   "request - drop request");
-		return;
-	}
-
-	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
-			   "drop request");
-		return;
-	}
-
-	pos = buf + 7 + 2 * COOKIE_LEN;
-	while (*pos == ' ')
-		pos++;
-
-	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) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	}
-}
-
-
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
-{
-	struct ctrl_iface_global_priv *priv;
-	struct sockaddr_in addr;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->sock = -1;
-	os_get_random(priv->cookie, COOKIE_LEN);
-
-	if (global->params.ctrl_interface == NULL)
-		return priv;
-
-	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
-		   global->params.ctrl_interface);
-
-	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (priv->sock < 0) {
-		perror("socket(PF_INET)");
-		goto fail;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
-	addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
-	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(AF_INET)");
-		goto fail;
-	}
-
-	eloop_register_read_sock(priv->sock,
-				 wpa_supplicant_global_ctrl_iface_receive,
-				 global, priv);
-
-	return priv;
-
-fail:
-	if (priv->sock >= 0)
-		close(priv->sock);
-	os_free(priv);
-	return NULL;
-}
-
-
-void
-wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
-{
-	if (priv->sock >= 0) {
-		eloop_unregister_read_sock(priv->sock);
-		close(priv->sock);
-	}
-	os_free(priv);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ctrl_iface_udp.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_udp.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,590 @@
+/*
+ * WPA Supplicant / UDP socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "common/wpa_ctrl.h"
+
+
+#define COOKIE_LEN 8
+
+/* 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_udp.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+	struct wpa_ctrl_dst *next;
+	struct sockaddr_in addr;
+	socklen_t addrlen;
+	int debug_level;
+	int errors;
+};
+
+
+struct ctrl_iface_priv {
+	struct wpa_supplicant *wpa_s;
+	int sock;
+	struct wpa_ctrl_dst *ctrl_dst;
+	u8 cookie[COOKIE_LEN];
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len);
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_in *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_in));
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dst->next = priv->ctrl_dst;
+	priv->ctrl_dst = dst;
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
+		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_in *from,
+					    socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst, *prev = NULL;
+
+	dst = priv->ctrl_dst;
+	while (dst) {
+		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+		    from->sin_port == dst->addr.sin_port) {
+			if (prev == NULL)
+				priv->ctrl_dst = dst->next;
+			else
+				prev->next = dst->next;
+			os_free(dst);
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+				   "%s:%d", inet_ntoa(from->sin_addr),
+				   ntohs(from->sin_port));
+			return 0;
+		}
+		prev = dst;
+		dst = dst->next;
+	}
+	return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+					   struct sockaddr_in *from,
+					   socklen_t fromlen,
+					   char *level)
+{
+	struct wpa_ctrl_dst *dst;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+	dst = priv->ctrl_dst;
+	while (dst) {
+		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+		    from->sin_port == dst->addr.sin_port) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
+				   "level %s:%d", inet_ntoa(from->sin_addr),
+				   ntohs(from->sin_port));
+			dst->debug_level = atoi(level);
+			return 0;
+		}
+		dst = dst->next;
+	}
+
+	return -1;
+}
+
+
+static char *
+wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
+				     size_t *reply_len)
+{
+	char *reply;
+	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
+	if (reply == NULL) {
+		*reply_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "COOKIE=", 7);
+	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+			 priv->cookie, COOKIE_LEN);
+
+	*reply_len = 7 + 2 * COOKIE_LEN;
+	return reply;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+					      void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct ctrl_iface_priv *priv = sock_ctx;
+	char buf[256], *pos;
+	int res;
+	struct sockaddr_in from;
+	socklen_t fromlen = sizeof(from);
+	char *reply = NULL;
+	size_t reply_len = 0;
+	int new_attached = 0;
+	u8 cookie[COOKIE_LEN];
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
+		/*
+		 * The OS networking stack is expected to drop this kind of
+		 * frames since the socket is bound to only localhost address.
+		 * Just in case, drop the frame if it is coming from any other
+		 * address.
+		 */
+		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
+			   "source %s", inet_ntoa(from.sin_addr));
+		return;
+	}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	buf[res] = '\0';
+
+	if (os_strcmp(buf, "GET_COOKIE") == 0) {
+		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
+		goto done;
+	}
+
+	/*
+	 * Require that the client includes a prefix with the 'cookie' value
+	 * fetched with GET_COOKIE command. This is used to verify that the
+	 * client has access to a bidirectional link over UDP in order to
+	 * avoid attacks using forged localhost IP address even if the OS does
+	 * not block such frames from remote destinations.
+	 */
+	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+			   "drop request");
+		return;
+	}
+
+	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+			   "request - drop request");
+		return;
+	}
+
+	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+			   "drop request");
+		return;
+	}
+
+	pos = buf + 7 + 2 * COOKIE_LEN;
+	while (*pos == ' ')
+		pos++;
+
+	if (os_strcmp(pos, "ATTACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_attach(priv, &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))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
+						    pos + 6))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else {
+		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
+							  &reply_len);
+	}
+
+ done:
+	if (reply) {
+		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		       fromlen);
+		os_free(reply);
+	} 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);
+	}
+
+	if (new_attached)
+		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+					     const char *txt, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+		return;
+	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+	struct sockaddr_in addr;
+	int port = WPA_CTRL_IFACE_PORT;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->wpa_s = wpa_s;
+	priv->sock = -1;
+	os_get_random(priv->cookie, COOKIE_LEN);
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_INET)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+	addr.sin_port = htons(port);
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		port--;
+		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
+			goto try_again;
+		perror("bind(AF_INET)");
+		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 */
+
+	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
+				 wpa_s, priv);
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	return NULL;
+}
+
+
+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) {
+			/*
+			 * Wait a second before closing the control socket if
+			 * there are any attached monitors in order to allow
+			 * them to receive any pending messages.
+			 */
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+				   "monitors to receive messages");
+			os_sleep(1, 0);
+		}
+		close(priv->sock);
+		priv->sock = -1;
+	}
+
+	dst = priv->ctrl_dst;
+	while (dst) {
+		prev = dst;
+		dst = dst->next;
+		os_free(prev);
+	}
+	os_free(priv);
+}
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	char levelstr[10];
+	int idx;
+	char *sbuf;
+	int llen;
+
+	dst = priv->ctrl_dst;
+	if (priv->sock < 0 || dst == NULL)
+		return;
+
+	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+	llen = os_strlen(levelstr);
+	sbuf = os_malloc(llen + len);
+	if (sbuf == NULL)
+		return;
+
+	os_memcpy(sbuf, levelstr, llen);
+	os_memcpy(sbuf + llen, buf, len);
+
+	idx = 0;
+	while (dst) {
+		next = dst->next;
+		if (level >= dst->debug_level) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
+				   inet_ntoa(dst->addr.sin_addr),
+				   ntohs(dst->addr.sin_port));
+			if (sendto(priv->sock, sbuf, llen + len, 0,
+				   (struct sockaddr *) &dst->addr,
+				   sizeof(dst->addr)) < 0) {
+				perror("sendto(CTRL_IFACE monitor)");
+				dst->errors++;
+				if (dst->errors > 10) {
+					wpa_supplicant_ctrl_iface_detach(
+						priv, &dst->addr,
+						dst->addrlen);
+				}
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+		dst = next;
+	}
+	os_free(sbuf);
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+		   priv->wpa_s->ifname);
+	eloop_wait_for_read_sock(priv->sock);
+}
+
+
+/* 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)
+{
+	char *reply;
+	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
+	if (reply == NULL) {
+		*reply_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "COOKIE=", 7);
+	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+			 priv->cookie, COOKIE_LEN);
+
+	*reply_len = 7 + 2 * COOKIE_LEN;
+	return reply;
+}
+
+
+static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+						     void *sock_ctx)
+{
+	struct wpa_global *global = eloop_ctx;
+	struct ctrl_iface_global_priv *priv = sock_ctx;
+	char buf[256], *pos;
+	int res;
+	struct sockaddr_in from;
+	socklen_t fromlen = sizeof(from);
+	char *reply;
+	size_t reply_len;
+	u8 cookie[COOKIE_LEN];
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
+		/*
+		 * The OS networking stack is expected to drop this kind of
+		 * frames since the socket is bound to only localhost address.
+		 * Just in case, drop the frame if it is coming from any other
+		 * address.
+		 */
+		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
+			   "source %s", inet_ntoa(from.sin_addr));
+		return;
+	}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	buf[res] = '\0';
+
+	if (os_strcmp(buf, "GET_COOKIE") == 0) {
+		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
+		goto done;
+	}
+
+	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+			   "drop request");
+		return;
+	}
+
+	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+			   "request - drop request");
+		return;
+	}
+
+	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+			   "drop request");
+		return;
+	}
+
+	pos = buf + 7 + 2 * COOKIE_LEN;
+	while (*pos == ' ')
+		pos++;
+
+	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) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+	}
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+	struct sockaddr_in addr;
+	int port = WPA_GLOBAL_CTRL_IFACE_PORT;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->sock = -1;
+	os_get_random(priv->cookie, COOKIE_LEN);
+
+	if (global->params.ctrl_interface == NULL)
+		return priv;
+
+	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
+		   global->params.ctrl_interface);
+
+	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_INET)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+	addr.sin_port = htons(port);
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		port++;
+		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
+		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+			goto try_again;
+		perror("bind(AF_INET)");
+		goto fail;
+	}
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	eloop_register_read_sock(priv->sock,
+				 wpa_supplicant_global_ctrl_iface_receive,
+				 global, priv);
+
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	return NULL;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+	if (priv->sock >= 0) {
+		eloop_unregister_read_sock(priv->sock);
+		close(priv->sock);
+	}
+	os_free(priv);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ctrl_iface_unix.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,712 +0,0 @@
-/*
- * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <stddef.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/list.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "ctrl_iface.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;
-};
-
-
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len);
-
-
-static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
-					    struct sockaddr_un *from,
-					    socklen_t fromlen)
-{
-	struct wpa_ctrl_dst *dst;
-
-	dst = os_zalloc(sizeof(*dst));
-	if (dst == NULL)
-		return -1;
-	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
-	dst->addrlen = fromlen;
-	dst->debug_level = MSG_INFO;
-	dl_list_add(&priv->ctrl_dst, &dst->list);
-	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
-		    (u8 *) from->sun_path,
-		    fromlen - offsetof(struct sockaddr_un, sun_path));
-	return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
-					    struct sockaddr_un *from,
-					    socklen_t fromlen)
-{
-	struct wpa_ctrl_dst *dst;
-
-	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) {
-			dl_list_del(&dst->list);
-			os_free(dst);
-			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
-				    (u8 *) from->sun_path,
-				    fromlen -
-				    offsetof(struct sockaddr_un, sun_path));
-			return 0;
-		}
-	}
-	return -1;
-}
-
-
-static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
-					   struct sockaddr_un *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) {
-			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;
-		}
-	}
-
-	return -1;
-}
-
-
-static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
-					      void *sock_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct ctrl_iface_priv *priv = sock_ctx;
-	char buf[256];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-	char *reply = NULL;
-	size_t reply_len = 0;
-	int new_attached = 0;
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
-		return;
-	}
-	buf[res] = '\0';
-
-	if (os_strcmp(buf, "ATTACH") == 0) {
-		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
-			reply_len = 1;
-		else {
-			new_attached = 1;
-			reply_len = 2;
-		}
-	} else if (os_strcmp(buf, "DETACH") == 0) {
-		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
-			reply_len = 1;
-		else
-			reply_len = 2;
-	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
-		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
-						    buf + 6))
-			reply_len = 1;
-		else
-			reply_len = 2;
-	} else {
-		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
-							  &reply_len);
-	}
-
-	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} 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);
-	}
-
-	if (new_attached)
-		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
-}
-
-
-static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
-{
-	char *buf;
-	size_t len;
-	char *pbuf, *dir = NULL, *gid_str = NULL;
-	int res;
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return NULL;
-
-	pbuf = os_strdup(wpa_s->conf->ctrl_interface);
-	if (pbuf == NULL)
-		return NULL;
-	if (os_strncmp(pbuf, "DIR=", 4) == 0) {
-		dir = pbuf + 4;
-		gid_str = os_strstr(dir, " GROUP=");
-		if (gid_str) {
-			*gid_str = '\0';
-			gid_str += 7;
-		}
-	} else
-		dir = pbuf;
-
-	len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
-	buf = os_malloc(len);
-	if (buf == NULL) {
-		os_free(pbuf);
-		return NULL;
-	}
-
-	res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
-	if (res < 0 || (size_t) res >= len) {
-		os_free(pbuf);
-		os_free(buf);
-		return NULL;
-	}
-#ifdef __CYGWIN__
-	{
-		/* Windows/WinPcap uses interface names that are not suitable
-		 * as a file name - convert invalid chars to underscores */
-		char *pos = buf;
-		while (*pos) {
-			if (*pos == '\\')
-				*pos = '_';
-			pos++;
-		}
-	}
-#endif /* __CYGWIN__ */
-	os_free(pbuf);
-	return buf;
-}
-
-
-static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
-					     const char *txt, size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
-		return;
-	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
-}
-
-
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
-{
-	struct ctrl_iface_priv *priv;
-	struct sockaddr_un addr;
-	char *fname = NULL;
-	gid_t gid = 0;
-	int gid_set = 0;
-	char *buf, *dir = NULL, *gid_str = NULL;
-	struct group *grp;
-	char *endp;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	dl_list_init(&priv->ctrl_dst);
-	priv->wpa_s = wpa_s;
-	priv->sock = -1;
-
-	if (wpa_s->conf->ctrl_interface == NULL)
-		return priv;
-
-	buf = os_strdup(wpa_s->conf->ctrl_interface);
-	if (buf == NULL)
-		goto fail;
-	if (os_strncmp(buf, "DIR=", 4) == 0) {
-		dir = buf + 4;
-		gid_str = os_strstr(dir, " GROUP=");
-		if (gid_str) {
-			*gid_str = '\0';
-			gid_str += 7;
-		}
-	} else {
-		dir = buf;
-		gid_str = wpa_s->conf->ctrl_interface_group;
-	}
-
-	if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
-		if (errno == EEXIST) {
-			wpa_printf(MSG_DEBUG, "Using existing control "
-				   "interface directory.");
-		} else {
-			perror("mkdir[ctrl_interface]");
-			goto fail;
-		}
-	}
-
-	if (gid_str) {
-		grp = getgrnam(gid_str);
-		if (grp) {
-			gid = grp->gr_gid;
-			gid_set = 1;
-			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
-				   " (from group name '%s')",
-				   (int) gid, gid_str);
-		} else {
-			/* Group name not found - try to parse this as gid */
-			gid = strtol(gid_str, &endp, 10);
-			if (*gid_str == '\0' || *endp != '\0') {
-				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
-					   "'%s'", gid_str);
-				goto fail;
-			}
-			gid_set = 1;
-			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
-				   (int) gid);
-		}
-	}
-
-	if (gid_set && chown(dir, -1, gid) < 0) {
-		perror("chown[ctrl_interface]");
-		goto fail;
-	}
-
-	/* Make sure the group can enter and read the directory */
-	if (gid_set &&
-	    chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
-		wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
-			   strerror(errno));
-		goto fail;
-	}
-
-	if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
-	    sizeof(addr.sun_path)) {
-		wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
-		goto fail;
-	}
-
-	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (priv->sock < 0) {
-		perror("socket(PF_UNIX)");
-		goto fail;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-	addr.sun_len = sizeof(addr);
-#endif /* __FreeBSD__ */
-	addr.sun_family = AF_UNIX;
-	fname = wpa_supplicant_ctrl_iface_path(wpa_s);
-	if (fname == NULL)
-		goto fail;
-	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
-	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
-			   strerror(errno));
-		if (connect(priv->sock, (struct sockaddr *) &addr,
-			    sizeof(addr)) < 0) {
-			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
-				   " allow connections - assuming it was left"
-				   "over from forced program termination");
-			if (unlink(fname) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   fname);
-				goto fail;
-			}
-			if (bind(priv->sock, (struct sockaddr *) &addr,
-				 sizeof(addr)) < 0) {
-				perror("bind(PF_UNIX)");
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
-				   "ctrl_iface socket '%s'", fname);
-		} else {
-			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
-				   "be in use - cannot override it");
-			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
-				   "not used anymore", fname);
-			os_free(fname);
-			fname = NULL;
-			goto fail;
-		}
-	}
-
-	if (gid_set && chown(fname, -1, gid) < 0) {
-		perror("chown[ctrl_interface/ifname]");
-		goto fail;
-	}
-
-	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-		perror("chmod[ctrl_interface/ifname]");
-		goto fail;
-	}
-	os_free(fname);
-
-	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
-				 wpa_s, priv);
-	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
-
-	os_free(buf);
-	return priv;
-
-fail:
-	if (priv->sock >= 0)
-		close(priv->sock);
-	os_free(priv);
-	if (fname) {
-		unlink(fname);
-		os_free(fname);
-	}
-	os_free(buf);
-	return NULL;
-}
-
-
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
-{
-	struct wpa_ctrl_dst *dst, *prev;
-
-	if (priv->sock > -1) {
-		char *fname;
-		char *buf, *dir = NULL, *gid_str = NULL;
-		eloop_unregister_read_sock(priv->sock);
-		if (!dl_list_empty(&priv->ctrl_dst)) {
-			/*
-			 * Wait a second before closing the control socket if
-			 * there are any attached monitors in order to allow
-			 * them to receive any pending messages.
-			 */
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
-				   "monitors to receive messages");
-			os_sleep(1, 0);
-		}
-		close(priv->sock);
-		priv->sock = -1;
-		fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
-		if (fname) {
-			unlink(fname);
-			os_free(fname);
-		}
-
-		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
-		if (buf == NULL)
-			goto free_dst;
-		if (os_strncmp(buf, "DIR=", 4) == 0) {
-			dir = buf + 4;
-			gid_str = os_strstr(dir, " GROUP=");
-			if (gid_str) {
-				*gid_str = '\0';
-				gid_str += 7;
-			}
-		} else
-			dir = buf;
-
-		if (rmdir(dir) < 0) {
-			if (errno == ENOTEMPTY) {
-				wpa_printf(MSG_DEBUG, "Control interface "
-					   "directory not empty - leaving it "
-					   "behind");
-			} else {
-				perror("rmdir[ctrl_interface]");
-			}
-		}
-		os_free(buf);
-	}
-
-free_dst:
-	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
-			      list)
-		os_free(dst);
-	os_free(priv);
-}
-
-
-/**
- * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
- * @level: Priority level of the message
- * @buf: Message data
- * @len: Message length
- *
- * Send a packet to all monitor programs attached to the control interface.
- */
-static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
-					   int level, const char *buf,
-					   size_t len)
-{
-	struct wpa_ctrl_dst *dst, *next;
-	char levelstr[10];
-	int idx, res;
-	struct msghdr msg;
-	struct iovec io[2];
-
-	if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
-		return;
-
-	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-	if (res < 0 || (size_t) res >= sizeof(levelstr))
-		return;
-	io[0].iov_base = levelstr;
-	io[0].iov_len = os_strlen(levelstr);
-	io[1].iov_base = (char *) buf;
-	io[1].iov_len = len;
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
-
-	idx = 0;
-	dl_list_for_each_safe(dst, next, &priv->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));
-			msg.msg_name = (void *) &dst->addr;
-			msg.msg_namelen = dst->addrlen;
-			if (sendmsg(priv->sock, &msg, 0) < 0) {
-				int _errno = errno;
-				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
-					   "%d - %s",
-					   idx, errno, strerror(errno));
-				dst->errors++;
-				if (dst->errors > 1000 ||
-				    (_errno != ENOBUFS && dst->errors > 10) ||
-				    _errno == ENOENT) {
-					wpa_supplicant_ctrl_iface_detach(
-						priv, &dst->addr,
-						dst->addrlen);
-				}
-			} else
-				dst->errors = 0;
-		}
-		idx++;
-	}
-}
-
-
-void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
-{
-	char buf[256];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-
-	for (;;) {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
-			   "attach", priv->wpa_s->ifname);
-		eloop_wait_for_read_sock(priv->sock);
-
-		res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
-			       (struct sockaddr *) &from, &fromlen);
-		if (res < 0) {
-			perror("recvfrom(ctrl_iface)");
-			continue;
-		}
-		buf[res] = '\0';
-
-		if (os_strcmp(buf, "ATTACH") == 0) {
-			/* handle ATTACH signal of first monitor interface */
-			if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
-							      fromlen)) {
-				sendto(priv->sock, "OK\n", 3, 0,
-				       (struct sockaddr *) &from, fromlen);
-				/* OK to continue */
-				return;
-			} else {
-				sendto(priv->sock, "FAIL\n", 5, 0,
-				       (struct sockaddr *) &from, fromlen);
-			}
-		} else {
-			/* return FAIL for all other signals */
-			sendto(priv->sock, "FAIL\n", 5, 0,
-			       (struct sockaddr *) &from, fromlen);
-		}
-	}
-}
-
-
-/* Global ctrl_iface */
-
-struct ctrl_iface_global_priv {
-	struct wpa_global *global;
-	int sock;
-};
-
-
-static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
-						     void *sock_ctx)
-{
-	struct wpa_global *global = eloop_ctx;
-	char buf[256];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-	char *reply;
-	size_t reply_len;
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
-		return;
-	}
-	buf[res] = '\0';
-
-	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
-							 &reply_len);
-
-	if (reply) {
-		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
-		       fromlen);
-		os_free(reply);
-	} else if (reply_len) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
-	}
-}
-
-
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
-{
-	struct ctrl_iface_global_priv *priv;
-	struct sockaddr_un addr;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->global = global;
-	priv->sock = -1;
-
-	if (global->params.ctrl_interface == NULL)
-		return priv;
-
-	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
-		   global->params.ctrl_interface);
-
-	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (priv->sock < 0) {
-		perror("socket(PF_UNIX)");
-		goto fail;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-	addr.sun_len = sizeof(addr);
-#endif /* __FreeBSD__ */
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, global->params.ctrl_interface,
-		   sizeof(addr.sun_path));
-	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind(PF_UNIX)");
-		if (connect(priv->sock, (struct sockaddr *) &addr,
-			    sizeof(addr)) < 0) {
-			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
-				   " allow connections - assuming it was left"
-				   "over from forced program termination");
-			if (unlink(global->params.ctrl_interface) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   global->params.ctrl_interface);
-				goto fail;
-			}
-			if (bind(priv->sock, (struct sockaddr *) &addr,
-				 sizeof(addr)) < 0) {
-				perror("bind(PF_UNIX)");
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
-				   "ctrl_iface socket '%s'",
-				   global->params.ctrl_interface);
-		} else {
-			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
-				   "be in use - cannot override it");
-			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
-				   "not used anymore",
-				   global->params.ctrl_interface);
-			goto fail;
-		}
-	}
-
-	eloop_register_read_sock(priv->sock,
-				 wpa_supplicant_global_ctrl_iface_receive,
-				 global, NULL);
-
-	return priv;
-
-fail:
-	if (priv->sock >= 0)
-		close(priv->sock);
-	os_free(priv);
-	return NULL;
-}
-
-
-void
-wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
-{
-	if (priv->sock >= 0) {
-		eloop_unregister_read_sock(priv->sock);
-		close(priv->sock);
-	}
-	if (priv->global->params.ctrl_interface)
-		unlink(priv->global->params.ctrl_interface);
-	os_free(priv);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ctrl_iface_unix.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ctrl_iface_unix.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,762 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif /* ANDROID */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.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;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len);
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_un *from,
+					    socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dl_list_add(&priv->ctrl_dst, &dst->list);
+	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+		    (u8 *) from->sun_path,
+		    fromlen - offsetof(struct sockaddr_un, sun_path));
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_un *from,
+					    socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	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) {
+			dl_list_del(&dst->list);
+			os_free(dst);
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			return 0;
+		}
+	}
+	return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+					   struct sockaddr_un *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) {
+			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;
+		}
+	}
+
+	return -1;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+					      void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct ctrl_iface_priv *priv = sock_ctx;
+	char buf[4096];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply = NULL;
+	size_t reply_len = 0;
+	int new_attached = 0;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	if (os_strcmp(buf, "ATTACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+			reply_len = 1;
+		else {
+			new_attached = 1;
+			reply_len = 2;
+		}
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
+						    buf + 6))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else {
+		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+							  &reply_len);
+	}
+
+	if (reply) {
+		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		       fromlen);
+		os_free(reply);
+	} 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);
+	}
+
+	if (new_attached)
+		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
+{
+	char *buf;
+	size_t len;
+	char *pbuf, *dir = NULL, *gid_str = NULL;
+	int res;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return NULL;
+
+	pbuf = os_strdup(wpa_s->conf->ctrl_interface);
+	if (pbuf == NULL)
+		return NULL;
+	if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+		dir = pbuf + 4;
+		gid_str = os_strstr(dir, " GROUP=");
+		if (gid_str) {
+			*gid_str = '\0';
+			gid_str += 7;
+		}
+	} else
+		dir = pbuf;
+
+	len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		os_free(pbuf);
+		return NULL;
+	}
+
+	res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
+	if (res < 0 || (size_t) res >= len) {
+		os_free(pbuf);
+		os_free(buf);
+		return NULL;
+	}
+#ifdef __CYGWIN__
+	{
+		/* Windows/WinPcap uses interface names that are not suitable
+		 * as a file name - convert invalid chars to underscores */
+		char *pos = buf;
+		while (*pos) {
+			if (*pos == '\\')
+				*pos = '_';
+			pos++;
+		}
+	}
+#endif /* __CYGWIN__ */
+	os_free(pbuf);
+	return buf;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+					     const char *txt, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+		return;
+	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+	struct sockaddr_un addr;
+	char *fname = NULL;
+	gid_t gid = 0;
+	int gid_set = 0;
+	char *buf, *dir = NULL, *gid_str = NULL;
+	struct group *grp;
+	char *endp;
+	int flags;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->wpa_s = wpa_s;
+	priv->sock = -1;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	buf = os_strdup(wpa_s->conf->ctrl_interface);
+	if (buf == NULL)
+		goto fail;
+#ifdef ANDROID
+	os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
+		    wpa_s->conf->ctrl_interface);
+	priv->sock = android_get_control_socket(addr.sun_path);
+	if (priv->sock >= 0)
+		goto havesock;
+#endif /* ANDROID */
+	if (os_strncmp(buf, "DIR=", 4) == 0) {
+		dir = buf + 4;
+		gid_str = os_strstr(dir, " GROUP=");
+		if (gid_str) {
+			*gid_str = '\0';
+			gid_str += 7;
+		}
+	} else {
+		dir = buf;
+		gid_str = wpa_s->conf->ctrl_interface_group;
+	}
+
+	if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+#ifdef ANDROID
+	/*
+	 * wpa_supplicant is started from /init.*.rc on Android and that seems
+	 * to be using umask 0077 which would leave the control interface
+	 * directory without group access. This breaks things since Wi-Fi
+	 * framework assumes that this directory can be accessed by other
+	 * applications in the wifi group. Fix this by adding group access even
+	 * if umask value would prevent this.
+	 */
+	if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+#endif /* ANDROID */
+
+	if (gid_str) {
+		grp = getgrnam(gid_str);
+		if (grp) {
+			gid = grp->gr_gid;
+			gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+				   " (from group name '%s')",
+				   (int) gid, gid_str);
+		} else {
+			/* Group name not found - try to parse this as gid */
+			gid = strtol(gid_str, &endp, 10);
+			if (*gid_str == '\0' || *endp != '\0') {
+				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+					   "'%s'", gid_str);
+				goto fail;
+			}
+			gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+				   (int) gid);
+		}
+	}
+
+	if (gid_set && chown(dir, -1, gid) < 0) {
+		perror("chown[ctrl_interface]");
+		goto fail;
+	}
+
+	/* Make sure the group can enter and read the directory */
+	if (gid_set &&
+	    chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
+			   strerror(errno));
+		goto fail;
+	}
+
+	if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
+	    sizeof(addr.sun_path)) {
+		wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
+		goto fail;
+	}
+
+	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = wpa_supplicant_ctrl_iface_path(wpa_s);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(priv->sock, (struct sockaddr *) &addr,
+			    sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(priv->sock, (struct sockaddr *) &addr,
+				 sizeof(addr)) < 0) {
+				perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (gid_set && chown(fname, -1, gid) < 0) {
+		perror("chown[ctrl_interface/ifname]");
+		goto fail;
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+
+	/*
+	 * Make socket non-blocking so that we don't hang forever if
+	 * target dies unexpectedly.
+	 */
+	flags = fcntl(priv->sock, F_GETFL);
+	if (flags >= 0) {
+		flags |= O_NONBLOCK;
+		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+			perror("fcntl(ctrl, O_NONBLOCK)");
+			/* Not fatal, continue on.*/
+		}
+	}
+
+	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
+				 wpa_s, priv);
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	os_free(buf);
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	os_free(buf);
+	return NULL;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (priv->sock > -1) {
+		char *fname;
+		char *buf, *dir = NULL, *gid_str = NULL;
+		eloop_unregister_read_sock(priv->sock);
+		if (!dl_list_empty(&priv->ctrl_dst)) {
+			/*
+			 * Wait a second before closing the control socket if
+			 * there are any attached monitors in order to allow
+			 * them to receive any pending messages.
+			 */
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+				   "monitors to receive messages");
+			os_sleep(1, 0);
+		}
+		close(priv->sock);
+		priv->sock = -1;
+		fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
+		if (fname) {
+			unlink(fname);
+			os_free(fname);
+		}
+
+		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
+		if (buf == NULL)
+			goto free_dst;
+		if (os_strncmp(buf, "DIR=", 4) == 0) {
+			dir = buf + 4;
+			gid_str = os_strstr(dir, " GROUP=");
+			if (gid_str) {
+				*gid_str = '\0';
+				gid_str += 7;
+			}
+		} else
+			dir = buf;
+
+		if (rmdir(dir) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+		os_free(buf);
+	}
+
+free_dst:
+	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
+			      list)
+		os_free(dst);
+	os_free(priv);
+}
+
+
+/**
+ * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @level: Priority level of the message
+ * @buf: Message data
+ * @len: Message length
+ *
+ * Send a packet to all monitor programs attached to the control interface.
+ */
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	char levelstr[10];
+	int idx, res;
+	struct msghdr msg;
+	struct iovec io[2];
+
+	if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+		return;
+
+	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+	if (res < 0 || (size_t) res >= sizeof(levelstr))
+		return;
+	io[0].iov_base = levelstr;
+	io[0].iov_len = os_strlen(levelstr);
+	io[1].iov_base = (char *) buf;
+	io[1].iov_len = len;
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+	idx = 0;
+	dl_list_for_each_safe(dst, next, &priv->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));
+			msg.msg_name = (void *) &dst->addr;
+			msg.msg_namelen = dst->addrlen;
+			if (sendmsg(priv->sock, &msg, 0) < 0) {
+				int _errno = errno;
+				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+					   "%d - %s",
+					   idx, errno, strerror(errno));
+				dst->errors++;
+				if (dst->errors > 1000 ||
+				    (_errno != ENOBUFS && dst->errors > 10) ||
+				    _errno == ENOENT) {
+					wpa_supplicant_ctrl_iface_detach(
+						priv, &dst->addr,
+						dst->addrlen);
+				}
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+	}
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+
+	for (;;) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
+			   "attach", priv->wpa_s->ifname);
+		eloop_wait_for_read_sock(priv->sock);
+
+		res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
+			       (struct sockaddr *) &from, &fromlen);
+		if (res < 0) {
+			perror("recvfrom(ctrl_iface)");
+			continue;
+		}
+		buf[res] = '\0';
+
+		if (os_strcmp(buf, "ATTACH") == 0) {
+			/* handle ATTACH signal of first monitor interface */
+			if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
+							      fromlen)) {
+				sendto(priv->sock, "OK\n", 3, 0,
+				       (struct sockaddr *) &from, fromlen);
+				/* OK to continue */
+				return;
+			} else {
+				sendto(priv->sock, "FAIL\n", 5, 0,
+				       (struct sockaddr *) &from, fromlen);
+			}
+		} else {
+			/* return FAIL for all other signals */
+			sendto(priv->sock, "FAIL\n", 5, 0,
+			       (struct sockaddr *) &from, fromlen);
+		}
+	}
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv {
+	struct wpa_global *global;
+	int sock;
+};
+
+
+static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+						     void *sock_ctx)
+{
+	struct wpa_global *global = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply;
+	size_t reply_len;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+							 &reply_len);
+
+	if (reply) {
+		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		       fromlen);
+		os_free(reply);
+	} else if (reply_len) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+	}
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+	struct sockaddr_un addr;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->global = global;
+	priv->sock = -1;
+
+	if (global->params.ctrl_interface == NULL)
+		return priv;
+
+#ifdef ANDROID
+	priv->sock = android_get_control_socket(global->params.ctrl_interface);
+	if (priv->sock >= 0)
+		goto havesock;
+#endif /* ANDROID */
+
+	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
+		   global->params.ctrl_interface);
+
+	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, global->params.ctrl_interface,
+		   sizeof(addr.sun_path));
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("supp-global-ctrl-iface-init (will try fixup): "
+		       "bind(PF_UNIX)");
+		if (connect(priv->sock, (struct sockaddr *) &addr,
+			    sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(global->params.ctrl_interface) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   global->params.ctrl_interface);
+				goto fail;
+			}
+			if (bind(priv->sock, (struct sockaddr *) &addr,
+				 sizeof(addr)) < 0) {
+				perror("supp-glb-iface-init: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'",
+				   global->params.ctrl_interface);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore",
+				   global->params.ctrl_interface);
+			goto fail;
+		}
+	}
+
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+	eloop_register_read_sock(priv->sock,
+				 wpa_supplicant_global_ctrl_iface_receive,
+				 global, NULL);
+
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	return NULL;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+	if (priv->sock >= 0) {
+		eloop_unregister_read_sock(priv->sock);
+		close(priv->sock);
+	}
+	if (priv->global->params.ctrl_interface)
+		unlink(priv->global->params.ctrl_interface);
+	os_free(priv);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/Makefile
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/Makefile	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,84 +0,0 @@
-all: libwpadbus.a
-
-clean:
-	rm -f *~ *.o *.d
-	rm -f libwpadbus.a
-
-install:
-	@echo Nothing to be made.
-
-ifndef CC
-CC=gcc
-endif
-
-ifndef CFLAGS
-CFLAGS = -MMD -O2 -Wall -g
-endif
-
-CFLAGS += -I../../src -I../../src/utils
-
-
-Q=@
-E=echo
-ifeq ($(V), 1)
-Q=
-E=true
-endif
-
-%.o: %.c
-	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
-	@$(E) "  CC " $<
-
-
-ifdef CONFIG_WPS
-CFLAGS += -DCONFIG_WPS
-endif
-
-CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
-CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
-
-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
-CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
-DBUS_INCLUDE += $(shell xml2-config --cflags)
-DBUS_LIBS += $(shell xml2-config --libs)
-endif
-
-dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1))
-DBUS_VERSION_MAJOR=$(word 1,$(dbus_version))
-DBUS_VERSION_MINOR=$(word 2,$(dbus_version))
-ifeq ($(DBUS_VERSION_MAJOR),)
-DBUS_VERSION_MAJOR=0
-endif
-ifeq ($(DBUS_VERSION_MINOR),)
-DBUS_VERSION_MINOR=0
-endif
-DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR)
-DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR)
-
-CFLAGS += $(DBUS_INCLUDE)
-
-LIB_OBJS= \
-	dbus_common.o \
-	dbus_old.o \
-	dbus_old_handlers.o \
-	dbus_new.o \
-	dbus_new_handlers.o \
-	dbus_new_helpers.o \
-	dbus_new_introspect.o \
-	dbus_dict_helpers.o
-
-ifdef CONFIG_WPS
-LIB_OBJS += dbus_old_handlers_wps.o
-LIB_OBJS += dbus_new_handlers_wps.o
-endif
-
-libwpadbus.a: $(LIB_OBJS)
-	$(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/Makefile (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/Makefile)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/Makefile	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/Makefile	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,73 @@
+all: libwpadbus.a
+
+clean:
+	rm -f *~ *.o *.d
+	rm -f libwpadbus.a
+
+install:
+	@echo Nothing to be made.
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+PKG_CONFIG ?= pkg-config
+CFLAGS += -I../../src -I../../src/utils
+
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+
+ifdef CONFIG_WPS
+CFLAGS += -DCONFIG_WPS
+endif
+
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS
+
+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
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
+DBUS_INCLUDE += $(shell xml2-config --cflags)
+DBUS_LIBS += $(shell xml2-config --libs)
+endif
+
+CFLAGS += $(DBUS_INCLUDE)
+
+LIB_OBJS= \
+	dbus_common.o \
+	dbus_old.o \
+	dbus_old_handlers.o \
+	dbus_new.o \
+	dbus_new_handlers.o \
+	dbus_new_helpers.o \
+	dbus_new_introspect.o \
+	dbus_dict_helpers.o
+
+ifdef CONFIG_WPS
+LIB_OBJS += dbus_old_handlers_wps.o
+LIB_OBJS += dbus_new_handlers_wps.o
+endif
+
+libwpadbus.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,371 +0,0 @@
-/*
- * wpa_supplicant D-Bus control interface - common functionality
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-#include <dbus/dbus.h>
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "dbus_common.h"
-#include "dbus_common_i.h"
-#include "dbus_new.h"
-#include "dbus_old.h"
-
-
-#ifndef SIGPOLL
-#ifdef SIGIO
-/*
- * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
- * FreeBSD.
- */
-#define SIGPOLL SIGIO
-#endif
-#endif
-
-
-static void dispatch_data(DBusConnection *con)
-{
-	while (dbus_connection_get_dispatch_status(con) ==
-	       DBUS_DISPATCH_DATA_REMAINS)
-		dbus_connection_dispatch(con);
-}
-
-
-/**
- * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
- *     claiming bus name
- * @eloop_ctx: the DBusConnection to dispatch on
- * @timeout_ctx: unused
- *
- * If clients are quick to notice that service claimed its bus name,
- * there may have been messages that came in before initialization was
- * all finished.  Dispatch those here.
- */
-static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
-{
-	DBusConnection *con = eloop_ctx;
-	dispatch_data(con);
-}
-
-
-static void process_watch(struct wpas_dbus_priv *priv,
-			  DBusWatch *watch, eloop_event_type type)
-{
-	dbus_connection_ref(priv->con);
-
-	priv->should_dispatch = 0;
-
-	if (type == EVENT_TYPE_READ)
-		dbus_watch_handle(watch, DBUS_WATCH_READABLE);
-	else if (type == EVENT_TYPE_WRITE)
-		dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
-	else if (type == EVENT_TYPE_EXCEPTION)
-		dbus_watch_handle(watch, DBUS_WATCH_ERROR);
-
-	if (priv->should_dispatch) {
-		dispatch_data(priv->con);
-		priv->should_dispatch = 0;
-	}
-
-	dbus_connection_unref(priv->con);
-}
-
-
-static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
-}
-
-
-static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
-}
-
-
-static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
-}
-
-
-static dbus_bool_t add_watch(DBusWatch *watch, void *data)
-{
-	struct wpas_dbus_priv *priv = data;
-	unsigned int flags;
-	int fd;
-
-	if (!dbus_watch_get_enabled(watch))
-		return TRUE;
-
-	flags = dbus_watch_get_flags(watch);
-	fd = dbus_watch_get_unix_fd(watch);
-
-	eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
-			    priv, watch);
-
-	if (flags & DBUS_WATCH_READABLE) {
-		eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
-				    priv, watch);
-	}
-	if (flags & DBUS_WATCH_WRITABLE) {
-		eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
-				    priv, watch);
-	}
-
-	dbus_watch_set_data(watch, priv, NULL);
-
-	return TRUE;
-}
-
-
-static void remove_watch(DBusWatch *watch, void *data)
-{
-	unsigned int flags;
-	int fd;
-
-	flags = dbus_watch_get_flags(watch);
-	fd = dbus_watch_get_unix_fd(watch);
-
-	eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
-
-	if (flags & DBUS_WATCH_READABLE)
-		eloop_unregister_sock(fd, EVENT_TYPE_READ);
-	if (flags & DBUS_WATCH_WRITABLE)
-		eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
-
-	dbus_watch_set_data(watch, NULL, NULL);
-}
-
-
-static void watch_toggled(DBusWatch *watch, void *data)
-{
-	if (dbus_watch_get_enabled(watch))
-		add_watch(watch, data);
-	else
-		remove_watch(watch, data);
-}
-
-
-static void process_timeout(void *eloop_ctx, void *sock_ctx)
-{
-	DBusTimeout *timeout = sock_ctx;
-	dbus_timeout_handle(timeout);
-}
-
-
-static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
-{
-	struct wpas_dbus_priv *priv = data;
-	if (!dbus_timeout_get_enabled(timeout))
-		return TRUE;
-
-	eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
-			       process_timeout, priv, timeout);
-
-	dbus_timeout_set_data(timeout, priv, NULL);
-
-	return TRUE;
-}
-
-
-static void remove_timeout(DBusTimeout *timeout, void *data)
-{
-	struct wpas_dbus_priv *priv = data;
-	eloop_cancel_timeout(process_timeout, priv, timeout);
-	dbus_timeout_set_data(timeout, NULL, NULL);
-}
-
-
-static void timeout_toggled(DBusTimeout *timeout, void *data)
-{
-	if (dbus_timeout_get_enabled(timeout))
-		add_timeout(timeout, data);
-	else
-		remove_timeout(timeout, data);
-}
-
-
-static void process_wakeup_main(int sig, void *signal_ctx)
-{
-	struct wpas_dbus_priv *priv = signal_ctx;
-
-	if (sig != SIGPOLL || !priv->con)
-		return;
-
-	if (dbus_connection_get_dispatch_status(priv->con) !=
-	    DBUS_DISPATCH_DATA_REMAINS)
-		return;
-
-	/* Only dispatch once - we do not want to starve other events */
-	dbus_connection_ref(priv->con);
-	dbus_connection_dispatch(priv->con);
-	dbus_connection_unref(priv->con);
-}
-
-
-/**
- * wakeup_main - Attempt to wake our mainloop up
- * @data: dbus control interface private data
- *
- * Try to wake up the main eloop so it will process
- * dbus events that may have happened.
- */
-static void wakeup_main(void *data)
-{
-	struct wpas_dbus_priv *priv = data;
-
-	/* Use SIGPOLL to break out of the eloop select() */
-	raise(SIGPOLL);
-	priv->should_dispatch = 1;
-}
-
-
-/**
- * integrate_with_eloop - Register our mainloop integration with dbus
- * @connection: connection to the system message bus
- * @priv: a dbus control interface data structure
- * Returns: 0 on success, -1 on failure
- */
-static int integrate_with_eloop(struct wpas_dbus_priv *priv)
-{
-	if (!dbus_connection_set_watch_functions(priv->con, add_watch,
-						 remove_watch, watch_toggled,
-						 priv, NULL) ||
-	    !dbus_connection_set_timeout_functions(priv->con, add_timeout,
-						   remove_timeout,
-						   timeout_toggled, priv,
-						   NULL)) {
-		wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
-			   "functions");
-		return -1;
-	}
-
-	if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
-		return -1;
-	dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
-						 priv, NULL);
-
-	return 0;
-}
-
-
-static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
-{
-	DBusError error;
-	int ret = 0;
-
-	/* Get a reference to the system bus */
-	dbus_error_init(&error);
-	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
-	if (!priv->con) {
-		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
-			   "bus: %s - %s", error.name, error.message);
-		ret = -1;
-	}
-	dbus_error_free(&error);
-
-	return ret;
-}
-
-
-static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
-{
-	/* Tell dbus about our mainloop integration functions */
-	integrate_with_eloop(priv);
-
-	/*
-	 * Dispatch initial DBus messages that may have come in since the bus
-	 * name was claimed above. Happens when clients are quick to notice the
-	 * service.
-	 *
-	 * FIXME: is there a better solution to this problem?
-	 */
-	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
-	                       priv->con, NULL);
-
-	return 0;
-}
-
-
-static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
-{
-	if (priv->con) {
-		eloop_cancel_timeout(dispatch_initial_dbus_messages,
-				     priv->con, NULL);
-		dbus_connection_set_watch_functions(priv->con, NULL, NULL,
-						    NULL, NULL, NULL);
-		dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
-						      NULL, NULL, NULL);
-		dbus_connection_unref(priv->con);
-	}
-
-	os_free(priv);
-}
-
-
-struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
-{
-	struct wpas_dbus_priv *priv;
-
-	priv = os_zalloc(sizeof(*priv));
-	if (priv == NULL)
-		return NULL;
-	priv->global = global;
-
-	if (wpas_dbus_init_common(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-
-#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-	if (wpas_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
-#ifdef CONFIG_CTRL_IFACE_DBUS
-	if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
-	if (wpas_dbus_init_common_finish(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-
-	return priv;
-}
-
-
-void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
-{
-	if (priv == NULL)
-		return;
-
-#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-	wpas_dbus_ctrl_iface_deinit(priv);
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
-#ifdef CONFIG_CTRL_IFACE_DBUS
-	/* TODO: is any deinit needed? */
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
-	wpas_dbus_deinit_common(priv);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_common.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,365 @@
+/*
+ * wpa_supplicant D-Bus control interface - common functionality
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <dbus/dbus.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "dbus_common.h"
+#include "dbus_common_i.h"
+#include "dbus_new.h"
+#include "dbus_old.h"
+
+
+#ifndef SIGPOLL
+#ifdef SIGIO
+/*
+ * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
+ * FreeBSD.
+ */
+#define SIGPOLL SIGIO
+#endif
+#endif
+
+
+static void dispatch_data(DBusConnection *con)
+{
+	while (dbus_connection_get_dispatch_status(con) ==
+	       DBUS_DISPATCH_DATA_REMAINS)
+		dbus_connection_dispatch(con);
+}
+
+
+/**
+ * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
+ *     claiming bus name
+ * @eloop_ctx: the DBusConnection to dispatch on
+ * @timeout_ctx: unused
+ *
+ * If clients are quick to notice that service claimed its bus name,
+ * there may have been messages that came in before initialization was
+ * all finished.  Dispatch those here.
+ */
+static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
+{
+	DBusConnection *con = eloop_ctx;
+	dispatch_data(con);
+}
+
+
+static void process_watch(struct wpas_dbus_priv *priv,
+			  DBusWatch *watch, eloop_event_type type)
+{
+	dbus_connection_ref(priv->con);
+
+	priv->should_dispatch = 0;
+
+	if (type == EVENT_TYPE_READ)
+		dbus_watch_handle(watch, DBUS_WATCH_READABLE);
+	else if (type == EVENT_TYPE_WRITE)
+		dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
+	else if (type == EVENT_TYPE_EXCEPTION)
+		dbus_watch_handle(watch, DBUS_WATCH_ERROR);
+
+	if (priv->should_dispatch) {
+		dispatch_data(priv->con);
+		priv->should_dispatch = 0;
+	}
+
+	dbus_connection_unref(priv->con);
+}
+
+
+static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
+}
+
+
+static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
+}
+
+
+static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
+}
+
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+	unsigned int flags;
+	int fd;
+
+	if (!dbus_watch_get_enabled(watch))
+		return TRUE;
+
+	flags = dbus_watch_get_flags(watch);
+	fd = dbus_watch_get_unix_fd(watch);
+
+	eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
+			    priv, watch);
+
+	if (flags & DBUS_WATCH_READABLE) {
+		eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
+				    priv, watch);
+	}
+	if (flags & DBUS_WATCH_WRITABLE) {
+		eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
+				    priv, watch);
+	}
+
+	dbus_watch_set_data(watch, priv, NULL);
+
+	return TRUE;
+}
+
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+	unsigned int flags;
+	int fd;
+
+	flags = dbus_watch_get_flags(watch);
+	fd = dbus_watch_get_unix_fd(watch);
+
+	eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
+
+	if (flags & DBUS_WATCH_READABLE)
+		eloop_unregister_sock(fd, EVENT_TYPE_READ);
+	if (flags & DBUS_WATCH_WRITABLE)
+		eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
+
+	dbus_watch_set_data(watch, NULL, NULL);
+}
+
+
+static void watch_toggled(DBusWatch *watch, void *data)
+{
+	if (dbus_watch_get_enabled(watch))
+		add_watch(watch, data);
+	else
+		remove_watch(watch, data);
+}
+
+
+static void process_timeout(void *eloop_ctx, void *sock_ctx)
+{
+	DBusTimeout *timeout = sock_ctx;
+	dbus_timeout_handle(timeout);
+}
+
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+	if (!dbus_timeout_get_enabled(timeout))
+		return TRUE;
+
+	eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
+			       process_timeout, priv, timeout);
+
+	dbus_timeout_set_data(timeout, priv, NULL);
+
+	return TRUE;
+}
+
+
+static void remove_timeout(DBusTimeout *timeout, void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+	eloop_cancel_timeout(process_timeout, priv, timeout);
+	dbus_timeout_set_data(timeout, NULL, NULL);
+}
+
+
+static void timeout_toggled(DBusTimeout *timeout, void *data)
+{
+	if (dbus_timeout_get_enabled(timeout))
+		add_timeout(timeout, data);
+	else
+		remove_timeout(timeout, data);
+}
+
+
+static void process_wakeup_main(int sig, void *signal_ctx)
+{
+	struct wpas_dbus_priv *priv = signal_ctx;
+
+	if (sig != SIGPOLL || !priv->con)
+		return;
+
+	if (dbus_connection_get_dispatch_status(priv->con) !=
+	    DBUS_DISPATCH_DATA_REMAINS)
+		return;
+
+	/* Only dispatch once - we do not want to starve other events */
+	dbus_connection_ref(priv->con);
+	dbus_connection_dispatch(priv->con);
+	dbus_connection_unref(priv->con);
+}
+
+
+/**
+ * wakeup_main - Attempt to wake our mainloop up
+ * @data: dbus control interface private data
+ *
+ * Try to wake up the main eloop so it will process
+ * dbus events that may have happened.
+ */
+static void wakeup_main(void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+
+	/* Use SIGPOLL to break out of the eloop select() */
+	raise(SIGPOLL);
+	priv->should_dispatch = 1;
+}
+
+
+/**
+ * integrate_with_eloop - Register our mainloop integration with dbus
+ * @connection: connection to the system message bus
+ * @priv: a dbus control interface data structure
+ * Returns: 0 on success, -1 on failure
+ */
+static int integrate_with_eloop(struct wpas_dbus_priv *priv)
+{
+	if (!dbus_connection_set_watch_functions(priv->con, add_watch,
+						 remove_watch, watch_toggled,
+						 priv, NULL) ||
+	    !dbus_connection_set_timeout_functions(priv->con, add_timeout,
+						   remove_timeout,
+						   timeout_toggled, priv,
+						   NULL)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
+			   "functions");
+		return -1;
+	}
+
+	if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
+		return -1;
+	dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
+						 priv, NULL);
+
+	return 0;
+}
+
+
+static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
+{
+	DBusError error;
+	int ret = 0;
+
+	/* Get a reference to the system bus */
+	dbus_error_init(&error);
+	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+	if (!priv->con) {
+		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
+			   "bus: %s - %s", error.name, error.message);
+		ret = -1;
+	}
+	dbus_error_free(&error);
+
+	return ret;
+}
+
+
+static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
+{
+	/* Tell dbus about our mainloop integration functions */
+	integrate_with_eloop(priv);
+
+	/*
+	 * Dispatch initial DBus messages that may have come in since the bus
+	 * name was claimed above. Happens when clients are quick to notice the
+	 * service.
+	 *
+	 * FIXME: is there a better solution to this problem?
+	 */
+	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
+	                       priv->con, NULL);
+
+	return 0;
+}
+
+
+static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
+{
+	if (priv->con) {
+		eloop_cancel_timeout(dispatch_initial_dbus_messages,
+				     priv->con, NULL);
+		dbus_connection_set_watch_functions(priv->con, NULL, NULL,
+						    NULL, NULL, NULL);
+		dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
+						      NULL, NULL, NULL);
+		dbus_connection_unref(priv->con);
+	}
+
+	os_free(priv);
+}
+
+
+struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
+{
+	struct wpas_dbus_priv *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->global = global;
+
+	if (wpas_dbus_init_common(priv) < 0) {
+		wpas_dbus_deinit(priv);
+		return NULL;
+	}
+
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+	if (wpas_dbus_ctrl_iface_init(priv) < 0) {
+		wpas_dbus_deinit(priv);
+		return NULL;
+	}
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+	if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
+		wpas_dbus_deinit(priv);
+		return NULL;
+	}
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+	if (wpas_dbus_init_common_finish(priv) < 0) {
+		wpas_dbus_deinit(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
+{
+	if (priv == NULL)
+		return;
+
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+	wpas_dbus_ctrl_iface_deinit(priv);
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+	/* TODO: is any deinit needed? */
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+	wpas_dbus_deinit_common(priv);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_common.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,26 +0,0 @@
-/*
- * wpa_supplicant D-Bus control interface - common definitions
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DBUS_COMMON_H
-#define DBUS_COMMON_H
-
-struct wpas_dbus_priv;
-struct wpa_global;
-
-struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global);
-void wpas_dbus_deinit(struct wpas_dbus_priv *priv);
-
-#endif /* DBUS_COMMON_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_common.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant D-Bus control interface - common definitions
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DBUS_COMMON_H
+#define DBUS_COMMON_H
+
+struct wpas_dbus_priv;
+struct wpa_global;
+
+struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global);
+void wpas_dbus_deinit(struct wpas_dbus_priv *priv);
+
+#endif /* DBUS_COMMON_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_common_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,30 +0,0 @@
-/*
- * wpa_supplicant D-Bus control interface - internal definitions
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DBUS_COMMON_I_H
-#define DBUS_COMMON_I_H
-
-#include <dbus/dbus.h>
-
-struct wpas_dbus_priv {
-	DBusConnection *con;
-	int should_dispatch;
-	struct wpa_global *global;
-	u32 next_objid;
-	int dbus_new_initialized;
-};
-
-#endif /* DBUS_COMMON_I_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_common_i.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_common_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,28 @@
+/*
+ * wpa_supplicant D-Bus control interface - internal definitions
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DBUS_COMMON_I_H
+#define DBUS_COMMON_I_H
+
+#include <dbus/dbus.h>
+
+struct wpas_dbus_priv {
+	DBusConnection *con;
+	int should_dispatch;
+	struct wpa_global *global;
+	u32 next_objid;
+	int dbus_new_initialized;
+
+#if defined(CONFIG_CTRL_IFACE_DBUS_NEW) && defined(CONFIG_AP)
+	int dbus_noc_refcnt;
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW && CONFIG_AP */
+};
+
+#endif /* DBUS_COMMON_I_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_dict_helpers.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,923 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "dbus_dict_helpers.h"
-
-
-/**
- * Start a dict in a dbus message.  Should be paired with a call to
- * wpa_dbus_dict_close_write().
- *
- * @param iter A valid dbus message iterator
- * @param iter_dict (out) A dict iterator to pass to further dict functions
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
-				     DBusMessageIter *iter_dict)
-{
-	dbus_bool_t result;
-
-	if (!iter || !iter_dict)
-		return FALSE;
-
-	result = dbus_message_iter_open_container(
-		iter,
-		DBUS_TYPE_ARRAY,
-		DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-		DBUS_TYPE_STRING_AS_STRING
-		DBUS_TYPE_VARIANT_AS_STRING
-		DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-		iter_dict);
-	return result;
-}
-
-
-/**
- * End a dict element in a dbus message.  Should be paired with
- * a call to wpa_dbus_dict_open_write().
- *
- * @param iter valid dbus message iterator, same as passed to
- *    wpa_dbus_dict_open_write()
- * @param iter_dict a dbus dict iterator returned from
- *    wpa_dbus_dict_open_write()
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
-				      DBusMessageIter *iter_dict)
-{
-	if (!iter || !iter_dict)
-		return FALSE;
-
-	return dbus_message_iter_close_container(iter, iter_dict);
-}
-
-
-const char * wpa_dbus_type_as_string(const int type)
-{
-	switch(type) {
-	case DBUS_TYPE_BYTE:
-		return DBUS_TYPE_BYTE_AS_STRING;
-	case DBUS_TYPE_BOOLEAN:
-		return DBUS_TYPE_BOOLEAN_AS_STRING;
-	case DBUS_TYPE_INT16:
-		return DBUS_TYPE_INT16_AS_STRING;
-	case DBUS_TYPE_UINT16:
-		return DBUS_TYPE_UINT16_AS_STRING;
-	case DBUS_TYPE_INT32:
-		return DBUS_TYPE_INT32_AS_STRING;
-	case DBUS_TYPE_UINT32:
-		return DBUS_TYPE_UINT32_AS_STRING;
-	case DBUS_TYPE_INT64:
-		return DBUS_TYPE_INT64_AS_STRING;
-	case DBUS_TYPE_UINT64:
-		return DBUS_TYPE_UINT64_AS_STRING;
-	case DBUS_TYPE_DOUBLE:
-		return DBUS_TYPE_DOUBLE_AS_STRING;
-	case DBUS_TYPE_STRING:
-		return DBUS_TYPE_STRING_AS_STRING;
-	case DBUS_TYPE_OBJECT_PATH:
-		return DBUS_TYPE_OBJECT_PATH_AS_STRING;
-	case DBUS_TYPE_ARRAY:
-		return DBUS_TYPE_ARRAY_AS_STRING;
-	default:
-		return NULL;
-	}
-}
-
-
-static dbus_bool_t _wpa_dbus_add_dict_entry_start(
-	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
-	const char *key, const int value_type)
-{
-	if (!dbus_message_iter_open_container(iter_dict,
-					      DBUS_TYPE_DICT_ENTRY, NULL,
-					      iter_dict_entry))
-		return FALSE;
-
-	if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
-					    &key))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-static dbus_bool_t _wpa_dbus_add_dict_entry_end(
-	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
-	DBusMessageIter *iter_dict_val)
-{
-	if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
-		return FALSE;
-	if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
-						  const char *key,
-						  const int value_type,
-						  const void *value)
-{
-	DBusMessageIter iter_dict_entry, iter_dict_val;
-	const char *type_as_string = NULL;
-
-	if (key == NULL)
-		return FALSE;
-
-	type_as_string = wpa_dbus_type_as_string(value_type);
-	if (!type_as_string)
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, value_type))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
-					      DBUS_TYPE_VARIANT,
-					      type_as_string, &iter_dict_val))
-		return FALSE;
-
-	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
-	DBusMessageIter *iter_dict, const char *key,
-	const char *value, const dbus_uint32_t value_len)
-{
-	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
-	dbus_uint32_t i;
-
-	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
-					      DBUS_TYPE_VARIANT,
-					      DBUS_TYPE_ARRAY_AS_STRING
-					      DBUS_TYPE_BYTE_AS_STRING,
-					      &iter_dict_val))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
-					      DBUS_TYPE_BYTE_AS_STRING,
-					      &iter_array))
-		return FALSE;
-
-	for (i = 0; i < value_len; i++) {
-		if (!dbus_message_iter_append_basic(&iter_array,
-						    DBUS_TYPE_BYTE,
-						    &(value[i])))
-			return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/**
- * Add a string 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 string value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
-					const char *key, const char *value)
-{
-	if (!value)
-		return FALSE;
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
-					      &value);
-}
-
-
-/**
- * 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
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The boolean value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
-				      const char *key, const dbus_bool_t value)
-{
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
-					      DBUS_TYPE_BOOLEAN, &value);
-}
-
-
-/**
- * Add a 16-bit signed 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 16-bit signed integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
-				       const char *key,
-				       const dbus_int16_t value)
-{
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
-					      &value);
-}
-
-
-/**
- * Add a 16-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 16-bit unsigned integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
-					const char *key,
-					const dbus_uint16_t value)
-{
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
-					      &value);
-}
-
-
-/**
- * Add a 32-bit signed integer 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 32-bit signed integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
-				       const char *key,
-				       const dbus_int32_t value)
-{
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
-					      &value);
-}
-
-
-/**
- * Add a 32-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 32-bit unsigned integer value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
-					const char *key,
-					const dbus_uint32_t value)
-{
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
-					      &value);
-}
-
-
-/**
- * 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
- *    wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param value The DBus object path value
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
-					     const char *key,
-					     const char *value)
-{
-	if (!value)
-		return FALSE;
-	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
-					      DBUS_TYPE_OBJECT_PATH, &value);
-}
-
-
-/**
- * Add a byte array 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 array
- * @param value_len The length of the byte array, in bytes
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
-					    const char *key,
-					    const char *value,
-					    const dbus_uint32_t value_len)
-{
-	if (!key)
-		return FALSE;
-	if (!value && (value_len != 0))
-		return FALSE;
-	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
-						   value_len);
-}
-
-
-/**
- * Begin a string array entry in the dict
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *                  wpa_dbus_dict_open_write()
- * @param key The key of the dict item
- * @param iter_dict_entry A private DBusMessageIter provided by the caller to
- *                        be passed to wpa_dbus_dict_end_string_array()
- * @param iter_dict_val A private DBusMessageIter provided by the caller to
- *                      be passed to wpa_dbus_dict_end_string_array()
- * @param iter_array On return, the DBusMessageIter to be passed to
- *                   wpa_dbus_dict_string_array_add_element()
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-					     const char *key,
-					     DBusMessageIter *iter_dict_entry,
-					     DBusMessageIter *iter_dict_val,
-					     DBusMessageIter *iter_array)
-{
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_dict_entry,
-					      DBUS_TYPE_VARIANT,
-					      DBUS_TYPE_ARRAY_AS_STRING
-					      DBUS_TYPE_STRING_AS_STRING,
-					      iter_dict_val))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
-					      DBUS_TYPE_BYTE_AS_STRING,
-					      iter_array))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/**
- * Add a single string element to a string array dict entry
- *
- * @param iter_array A valid DBusMessageIter returned from
- *                   wpa_dbus_dict_begin_string_array()'s
- *                   iter_array parameter
- * @param elem The string element to be added to the dict entry's string array
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
-						   const char *elem)
-{
-	if (!iter_array || !elem)
-		return FALSE;
-
-	return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
-					      &elem);
-}
-
-
-/**
- * End a string array dict entry
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *                  wpa_dbus_dict_open_write()
- * @param iter_dict_entry A private DBusMessageIter returned from
- *                        wpa_dbus_dict_end_string_array()
- * @param iter_dict_val A private DBusMessageIter returned from
- *                      wpa_dbus_dict_end_string_array()
- * @param iter_array A DBusMessageIter returned from
- *                   wpa_dbus_dict_end_string_array()
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-					   DBusMessageIter *iter_dict_entry,
-					   DBusMessageIter *iter_dict_val,
-					   DBusMessageIter *iter_array)
-{
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
-		return FALSE;
-
-	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
-					  iter_dict_val))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/**
- * Convenience function to add an entire string array 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 items The array of strings
- * @param num_items The number of strings in the array
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
-					      const char *key,
-					      const char **items,
-					      const dbus_uint32_t num_items)
-{
-	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
-	dbus_uint32_t i;
-
-	if (!key)
-		return FALSE;
-	if (!items && (num_items != 0))
-		return FALSE;
-
-	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
-					      &iter_dict_entry, &iter_dict_val,
-					      &iter_array))
-		return FALSE;
-
-	for (i = 0; i < num_items; i++) {
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    items[i]))
-			return FALSE;
-	}
-
-	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
-					    &iter_dict_val, &iter_array))
-		return FALSE;
-
-	return TRUE;
-}
-
-
-/*****************************************************/
-/* Stuff for reading dicts                           */
-/*****************************************************/
-
-/**
- * Start reading from a dbus dict.
- *
- * @param iter A valid DBusMessageIter pointing to the start of the dict
- * @param iter_dict (out) A DBusMessageIter to be passed to
- *    wpa_dbus_dict_read_next_entry()
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-				    DBusMessageIter *iter_dict)
-{
-	if (!iter || !iter_dict)
-		return FALSE;
-
-	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
-		return FALSE;
-
-	dbus_message_iter_recurse(iter, iter_dict);
-	return TRUE;
-}
-
-
-#define BYTE_ARRAY_CHUNK_SIZE 34
-#define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
-
-static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
-	DBusMessageIter *iter, int array_type,
-	struct wpa_dbus_dict_entry *entry)
-{
-	dbus_uint32_t count = 0;
-	dbus_bool_t success = FALSE;
-	char *buffer, *nbuffer;;
-
-	entry->bytearray_value = NULL;
-	entry->array_type = DBUS_TYPE_BYTE;
-
-	buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
-	if (!buffer)
-		return FALSE;
-
-	entry->bytearray_value = buffer;
-	entry->array_len = 0;
-	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
-		char byte;
-
-		if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
-			nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
-					     (count + BYTE_ARRAY_CHUNK_SIZE));
-			if (nbuffer == NULL) {
-				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_byte_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
-				goto done;
-			}
-			buffer = nbuffer;
-		}
-		entry->bytearray_value = buffer;
-
-		dbus_message_iter_get_basic(iter, &byte);
-		entry->bytearray_value[count] = byte;
-		entry->array_len = ++count;
-		dbus_message_iter_next(iter);
-	}
-
-	/* Zero-length arrays are valid. */
-	if (entry->array_len == 0) {
-		os_free(entry->bytearray_value);
-		entry->bytearray_value = NULL;
-	}
-
-	success = TRUE;
-
-done:
-	return success;
-}
-
-
-#define STR_ARRAY_CHUNK_SIZE 8
-#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
-
-static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
-	DBusMessageIter *iter, int array_type,
-	struct wpa_dbus_dict_entry *entry)
-{
-	dbus_uint32_t count = 0;
-	dbus_bool_t success = FALSE;
-	char **buffer, **nbuffer;
-
-	entry->strarray_value = NULL;
-	entry->array_type = DBUS_TYPE_STRING;
-
-	buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
-	if (buffer == NULL)
-		return FALSE;
-
-	entry->strarray_value = buffer;
-	entry->array_len = 0;
-	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
-		const char *value;
-		char *str;
-
-		if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
-			nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
-					     (count + STR_ARRAY_CHUNK_SIZE));
-			if (nbuffer == NULL) {
-				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_string_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
-				goto done;
-			}
-			buffer = nbuffer;
-		}
-		entry->strarray_value = buffer;
-
-		dbus_message_iter_get_basic(iter, &value);
-		str = os_strdup(value);
-		if (str == NULL) {
-			wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
-				   "string_array out of memory trying to "
-				   "duplicate the string array");
-			goto done;
-		}
-		entry->strarray_value[count] = str;
-		entry->array_len = ++count;
-		dbus_message_iter_next(iter);
-	}
-
-	/* Zero-length arrays are valid. */
-	if (entry->array_len == 0) {
-		os_free(entry->strarray_value);
-		entry->strarray_value = NULL;
-	}
-
-	success = TRUE;
-
-done:
-	return success;
-}
-
-
-static dbus_bool_t _wpa_dbus_dict_entry_get_array(
-	DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
-{
-	int array_type = dbus_message_iter_get_element_type(iter_dict_val);
-	dbus_bool_t success = FALSE;
-	DBusMessageIter iter_array;
-
-	if (!entry)
-		return FALSE;
-
-	dbus_message_iter_recurse(iter_dict_val, &iter_array);
-
- 	switch (array_type) {
-	case DBUS_TYPE_BYTE:
-		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
-							      array_type,
-							      entry);
-		break;
-	case DBUS_TYPE_STRING:
-		success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
-								array_type,
-								entry);
-		break;
-	default:
-		break;
-	}
-
-	return success;
-}
-
-
-static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
-	struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
-{
-	const char *v;
-
-	switch (entry->type) {
-	case DBUS_TYPE_OBJECT_PATH:
-	case DBUS_TYPE_STRING:
-		dbus_message_iter_get_basic(iter, &v);
-		entry->str_value = os_strdup(v);
-		if (entry->str_value == NULL)
-			return FALSE;
-		break;
-	case DBUS_TYPE_BOOLEAN:
-		dbus_message_iter_get_basic(iter, &entry->bool_value);
-		break;
-	case DBUS_TYPE_BYTE:
-		dbus_message_iter_get_basic(iter, &entry->byte_value);
-		break;
-	case DBUS_TYPE_INT16:
-		dbus_message_iter_get_basic(iter, &entry->int16_value);
-		break;
-	case DBUS_TYPE_UINT16:
-		dbus_message_iter_get_basic(iter, &entry->uint16_value);
-		break;
-	case DBUS_TYPE_INT32:
-		dbus_message_iter_get_basic(iter, &entry->int32_value);
-		break;
-	case DBUS_TYPE_UINT32:
-		dbus_message_iter_get_basic(iter, &entry->uint32_value);
-		break;
-	case DBUS_TYPE_INT64:
-		dbus_message_iter_get_basic(iter, &entry->int64_value);
-		break;
-	case DBUS_TYPE_UINT64:
-		dbus_message_iter_get_basic(iter, &entry->uint64_value);
-		break;
-	case DBUS_TYPE_DOUBLE:
-		dbus_message_iter_get_basic(iter, &entry->double_value);
-		break;
-	case DBUS_TYPE_ARRAY:
-		return _wpa_dbus_dict_entry_get_array(iter, entry);
-	default:
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-
-/**
- * Read the current key/value entry from the dict.  Entries are dynamically
- * allocated when needed and must be freed after use with the
- * wpa_dbus_dict_entry_clear() function.
- *
- * The returned entry object will be filled with the type and value of the next
- * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
- * occurred.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_read()
- * @param entry A valid dict entry object into which the dict key and value
- *    will be placed
- * @return TRUE on success, FALSE on failure
- *
- */
-dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
-				    struct wpa_dbus_dict_entry * entry)
-{
-	DBusMessageIter iter_dict_entry, iter_dict_val;
-	int type;
-	const char *key;
-
-	if (!iter_dict || !entry)
-		goto error;
-
-	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
-		goto error;
-
-	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
-	dbus_message_iter_get_basic(&iter_dict_entry, &key);
-	entry->key = key;
-
-	if (!dbus_message_iter_next(&iter_dict_entry))
-		goto error;
-	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
-	if (type != DBUS_TYPE_VARIANT)
-		goto error;
-
-	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
-	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
-	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
-		goto error;
-
-	dbus_message_iter_next(iter_dict);
-	return TRUE;
-
-error:
-	if (entry) {
-		wpa_dbus_dict_entry_clear(entry);
-		entry->type = DBUS_TYPE_INVALID;
-		entry->array_type = DBUS_TYPE_INVALID;
-	}
-
-	return FALSE;
-}
-
-
-/**
- * Return whether or not there are additional dictionary entries.
- *
- * @param iter_dict A valid DBusMessageIter returned from
- *    wpa_dbus_dict_open_read()
- * @return TRUE if more dict entries exists, FALSE if no more dict entries
- * exist
- */
-dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
-{
-	if (!iter_dict)
-		return FALSE;
-	return dbus_message_iter_get_arg_type(iter_dict) ==
-		DBUS_TYPE_DICT_ENTRY;
-}
-
-
-/**
- * Free any memory used by the entry object.
- *
- * @param entry The entry object
- */
-void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
-{
-	unsigned int i;
-
-	if (!entry)
-		return;
-	switch (entry->type) {
-	case DBUS_TYPE_OBJECT_PATH:
-	case DBUS_TYPE_STRING:
-		os_free(entry->str_value);
-		break;
-	case DBUS_TYPE_ARRAY:
-		switch (entry->array_type) {
-		case DBUS_TYPE_BYTE:
-			os_free(entry->bytearray_value);
-			break;
-		case DBUS_TYPE_STRING:
-			for (i = 0; i < entry->array_len; i++)
-				os_free(entry->strarray_value[i]);
-			os_free(entry->strarray_value);
-			break;
-		}
-		break;
-	}
-
-	memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_dict_helpers.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1104 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "wpabuf.h"
+#include "dbus_dict_helpers.h"
+
+
+/**
+ * Start a dict in a dbus message.  Should be paired with a call to
+ * wpa_dbus_dict_close_write().
+ *
+ * @param iter A valid dbus message iterator
+ * @param iter_dict (out) A dict iterator to pass to further dict functions
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
+				     DBusMessageIter *iter_dict)
+{
+	dbus_bool_t result;
+
+	if (!iter || !iter_dict)
+		return FALSE;
+
+	result = dbus_message_iter_open_container(
+		iter,
+		DBUS_TYPE_ARRAY,
+		DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+		DBUS_TYPE_STRING_AS_STRING
+		DBUS_TYPE_VARIANT_AS_STRING
+		DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+		iter_dict);
+	return result;
+}
+
+
+/**
+ * End a dict element in a dbus message.  Should be paired with
+ * a call to wpa_dbus_dict_open_write().
+ *
+ * @param iter valid dbus message iterator, same as passed to
+ *    wpa_dbus_dict_open_write()
+ * @param iter_dict a dbus dict iterator returned from
+ *    wpa_dbus_dict_open_write()
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
+				      DBusMessageIter *iter_dict)
+{
+	if (!iter || !iter_dict)
+		return FALSE;
+
+	return dbus_message_iter_close_container(iter, iter_dict);
+}
+
+
+const char * wpa_dbus_type_as_string(const int type)
+{
+	switch(type) {
+	case DBUS_TYPE_BYTE:
+		return DBUS_TYPE_BYTE_AS_STRING;
+	case DBUS_TYPE_BOOLEAN:
+		return DBUS_TYPE_BOOLEAN_AS_STRING;
+	case DBUS_TYPE_INT16:
+		return DBUS_TYPE_INT16_AS_STRING;
+	case DBUS_TYPE_UINT16:
+		return DBUS_TYPE_UINT16_AS_STRING;
+	case DBUS_TYPE_INT32:
+		return DBUS_TYPE_INT32_AS_STRING;
+	case DBUS_TYPE_UINT32:
+		return DBUS_TYPE_UINT32_AS_STRING;
+	case DBUS_TYPE_INT64:
+		return DBUS_TYPE_INT64_AS_STRING;
+	case DBUS_TYPE_UINT64:
+		return DBUS_TYPE_UINT64_AS_STRING;
+	case DBUS_TYPE_DOUBLE:
+		return DBUS_TYPE_DOUBLE_AS_STRING;
+	case DBUS_TYPE_STRING:
+		return DBUS_TYPE_STRING_AS_STRING;
+	case DBUS_TYPE_OBJECT_PATH:
+		return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+	case DBUS_TYPE_ARRAY:
+		return DBUS_TYPE_ARRAY_AS_STRING;
+	default:
+		return NULL;
+	}
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_start(
+	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
+	const char *key, const int value_type)
+{
+	if (!dbus_message_iter_open_container(iter_dict,
+					      DBUS_TYPE_DICT_ENTRY, NULL,
+					      iter_dict_entry))
+		return FALSE;
+
+	if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+					    &key))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_end(
+	DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
+	DBusMessageIter *iter_dict_val)
+{
+	if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
+		return FALSE;
+	if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
+						  const char *key,
+						  const int value_type,
+						  const void *value)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val;
+	const char *type_as_string = NULL;
+
+	if (key == NULL)
+		return FALSE;
+
+	type_as_string = wpa_dbus_type_as_string(value_type);
+	if (!type_as_string)
+		return FALSE;
+
+	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
+					    key, value_type))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					      DBUS_TYPE_VARIANT,
+					      type_as_string, &iter_dict_val))
+		return FALSE;
+
+	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
+		return FALSE;
+
+	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					  &iter_dict_val))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
+	DBusMessageIter *iter_dict, const char *key,
+	const char *value, const dbus_uint32_t value_len)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+	dbus_uint32_t i;
+
+	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					      DBUS_TYPE_VARIANT,
+					      DBUS_TYPE_ARRAY_AS_STRING
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &iter_dict_val))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &iter_array))
+		return FALSE;
+
+	for (i = 0; i < value_len; i++) {
+		if (!dbus_message_iter_append_basic(&iter_array,
+						    DBUS_TYPE_BYTE,
+						    &(value[i])))
+			return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
+		return FALSE;
+
+	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					  &iter_dict_val))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * Add a string 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 string value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
+					const char *key, const char *value)
+{
+	if (!value)
+		return FALSE;
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
+					      &value);
+}
+
+
+/**
+ * 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
+ *    wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param value The boolean value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
+				      const char *key, const dbus_bool_t value)
+{
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
+					      DBUS_TYPE_BOOLEAN, &value);
+}
+
+
+/**
+ * Add a 16-bit signed 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 16-bit signed integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
+				       const char *key,
+				       const dbus_int16_t value)
+{
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
+					      &value);
+}
+
+
+/**
+ * Add a 16-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 16-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
+					const char *key,
+					const dbus_uint16_t value)
+{
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
+					      &value);
+}
+
+
+/**
+ * Add a 32-bit signed integer 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 32-bit signed integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
+				       const char *key,
+				       const dbus_int32_t value)
+{
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
+					      &value);
+}
+
+
+/**
+ * Add a 32-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 32-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
+					const char *key,
+					const dbus_uint32_t value)
+{
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
+					      &value);
+}
+
+
+/**
+ * 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
+ *    wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param value The DBus object path value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
+					     const char *key,
+					     const char *value)
+{
+	if (!value)
+		return FALSE;
+	return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
+					      DBUS_TYPE_OBJECT_PATH, &value);
+}
+
+
+/**
+ * Add a byte array 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 array
+ * @param value_len The length of the byte array, in bytes
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
+					    const char *key,
+					    const char *value,
+					    const dbus_uint32_t value_len)
+{
+	if (!key)
+		return FALSE;
+	if (!value && (value_len != 0))
+		return FALSE;
+	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
+						   value_len);
+}
+
+
+/**
+ * Begin an array entry in the dict
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *                  wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param type The type of the contained data
+ * @param iter_dict_entry A private DBusMessageIter provided by the caller to
+ *                        be passed to wpa_dbus_dict_end_string_array()
+ * @param iter_dict_val A private DBusMessageIter provided by the caller to
+ *                      be passed to wpa_dbus_dict_end_string_array()
+ * @param iter_array On return, the DBusMessageIter to be passed to
+ *                   wpa_dbus_dict_string_array_add_element()
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+				      const char *key, const char *type,
+				      DBusMessageIter *iter_dict_entry,
+				      DBusMessageIter *iter_dict_val,
+				      DBusMessageIter *iter_array)
+{
+	char array_type[10];
+	int err;
+
+	err = os_snprintf(array_type, sizeof(array_type),
+			  DBUS_TYPE_ARRAY_AS_STRING "%s",
+			  type);
+	if (err < 0 || err > (int) sizeof(array_type))
+		return FALSE;
+
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+		return FALSE;
+
+	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter_dict_entry,
+					      DBUS_TYPE_VARIANT,
+					      array_type,
+					      iter_dict_val))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+					      type, iter_array))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+					     const char *key,
+					     DBusMessageIter *iter_dict_entry,
+					     DBusMessageIter *iter_dict_val,
+					     DBusMessageIter *iter_array)
+{
+	return wpa_dbus_dict_begin_array(
+		iter_dict, key,
+		DBUS_TYPE_STRING_AS_STRING,
+		iter_dict_entry, iter_dict_val, iter_array);
+}
+
+
+/**
+ * Add a single string element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ *                   wpa_dbus_dict_begin_string_array()'s
+ *                   iter_array parameter
+ * @param elem The string element to be added to the dict entry's string array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
+						   const char *elem)
+{
+	if (!iter_array || !elem)
+		return FALSE;
+
+	return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
+					      &elem);
+}
+
+
+/**
+ * Add a single byte array element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ *                   wpa_dbus_dict_begin_array()'s iter_array
+ *                   parameter -- note that wpa_dbus_dict_begin_array()
+ *                   must have been called with "ay" as the type
+ * @param value The data to be added to the dict entry's array
+ * @param value_len The length of the data
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+						const u8 *value,
+						size_t value_len)
+{
+	DBusMessageIter iter_bytes;
+	size_t i;
+
+	if (!iter_array || !value)
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &iter_bytes))
+		return FALSE;
+
+	for (i = 0; i < value_len; i++) {
+		if (!dbus_message_iter_append_basic(&iter_bytes,
+						    DBUS_TYPE_BYTE,
+						    &(value[i])))
+			return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * End an array dict entry
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *                  wpa_dbus_dict_open_write()
+ * @param iter_dict_entry A private DBusMessageIter returned from
+ *                        wpa_dbus_dict_begin_string_array() or
+ *			  wpa_dbus_dict_begin_array()
+ * @param iter_dict_val A private DBusMessageIter returned from
+ *                      wpa_dbus_dict_begin_string_array() or
+ *			wpa_dbus_dict_begin_array()
+ * @param iter_array A DBusMessageIter returned from
+ *                   wpa_dbus_dict_begin_string_array() or
+ *		     wpa_dbus_dict_begin_array()
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+				    DBusMessageIter *iter_dict_entry,
+				    DBusMessageIter *iter_dict_val,
+				    DBusMessageIter *iter_array)
+{
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+		return FALSE;
+
+	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
+		return FALSE;
+
+	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+					  iter_dict_val))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * Convenience function to add an entire string array 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 items The array of strings
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const char **items,
+					      const dbus_uint32_t num_items)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+	dbus_uint32_t i;
+
+	if (!key)
+		return FALSE;
+	if (!items && (num_items != 0))
+		return FALSE;
+
+	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+					      &iter_dict_entry, &iter_dict_val,
+					      &iter_array))
+		return FALSE;
+
+	for (i = 0; i < num_items; i++) {
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    items[i]))
+			return FALSE;
+	}
+
+	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+					    &iter_dict_val, &iter_array))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/**
+ * Convenience function to add an wpabuf binary array 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 items The array of wpabuf structures
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const struct wpabuf **items,
+					      const dbus_uint32_t num_items)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+	dbus_uint32_t i;
+
+	if (!key)
+		return FALSE;
+	if (!items && (num_items != 0))
+		return FALSE;
+
+	if (!wpa_dbus_dict_begin_array(iter_dict, key,
+				       DBUS_TYPE_ARRAY_AS_STRING
+				       DBUS_TYPE_BYTE_AS_STRING,
+				       &iter_dict_entry, &iter_dict_val,
+				       &iter_array))
+		return FALSE;
+
+	for (i = 0; i < num_items; i++) {
+		if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
+							 wpabuf_head(items[i]),
+							 wpabuf_len(items[i])))
+			return FALSE;
+	}
+
+	if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+				     &iter_dict_val, &iter_array))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+/*****************************************************/
+/* Stuff for reading dicts                           */
+/*****************************************************/
+
+/**
+ * Start reading from a dbus dict.
+ *
+ * @param iter A valid DBusMessageIter pointing to the start of the dict
+ * @param iter_dict (out) A DBusMessageIter to be passed to
+ *    wpa_dbus_dict_read_next_entry()
+ * @error on failure a descriptive error
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
+				    DBusMessageIter *iter_dict,
+				    DBusError *error)
+{
+	if (!iter || !iter_dict) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+		                     "[internal] missing message iterators");
+		return FALSE;
+	}
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+		                     "unexpected message argument types");
+		return FALSE;
+	}
+
+	dbus_message_iter_recurse(iter, iter_dict);
+	return TRUE;
+}
+
+
+#define BYTE_ARRAY_CHUNK_SIZE 34
+#define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
+	DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+	dbus_uint32_t count = 0;
+	dbus_bool_t success = FALSE;
+	char *buffer, *nbuffer;
+
+	entry->bytearray_value = NULL;
+	entry->array_type = DBUS_TYPE_BYTE;
+
+	buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
+	if (!buffer)
+		return FALSE;
+
+	entry->bytearray_value = buffer;
+	entry->array_len = 0;
+	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
+		char byte;
+
+		if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
+			nbuffer = os_realloc_array(
+				buffer, count + BYTE_ARRAY_CHUNK_SIZE,
+				BYTE_ARRAY_ITEM_SIZE);
+			if (nbuffer == NULL) {
+				os_free(buffer);
+				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
+					   "entry_get_byte_array out of "
+					   "memory trying to retrieve the "
+					   "string array");
+				goto done;
+			}
+			buffer = nbuffer;
+		}
+		entry->bytearray_value = buffer;
+
+		dbus_message_iter_get_basic(iter, &byte);
+		entry->bytearray_value[count] = byte;
+		entry->array_len = ++count;
+		dbus_message_iter_next(iter);
+	}
+
+	/* Zero-length arrays are valid. */
+	if (entry->array_len == 0) {
+		os_free(entry->bytearray_value);
+		entry->bytearray_value = NULL;
+	}
+
+	success = TRUE;
+
+done:
+	return success;
+}
+
+
+#define STR_ARRAY_CHUNK_SIZE 8
+#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
+	DBusMessageIter *iter, int array_type,
+	struct wpa_dbus_dict_entry *entry)
+{
+	dbus_uint32_t count = 0;
+	dbus_bool_t success = FALSE;
+	char **buffer, **nbuffer;
+
+	entry->strarray_value = NULL;
+	entry->array_type = DBUS_TYPE_STRING;
+
+	buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
+	if (buffer == NULL)
+		return FALSE;
+
+	entry->strarray_value = buffer;
+	entry->array_len = 0;
+	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+		const char *value;
+		char *str;
+
+		if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
+			nbuffer = os_realloc_array(
+				buffer, count + STR_ARRAY_CHUNK_SIZE,
+				STR_ARRAY_ITEM_SIZE);
+			if (nbuffer == NULL) {
+				os_free(buffer);
+				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
+					   "entry_get_string_array out of "
+					   "memory trying to retrieve the "
+					   "string array");
+				goto done;
+			}
+			buffer = nbuffer;
+		}
+		entry->strarray_value = buffer;
+
+		dbus_message_iter_get_basic(iter, &value);
+		str = os_strdup(value);
+		if (str == NULL) {
+			wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
+				   "string_array out of memory trying to "
+				   "duplicate the string array");
+			goto done;
+		}
+		entry->strarray_value[count] = str;
+		entry->array_len = ++count;
+		dbus_message_iter_next(iter);
+	}
+
+	/* Zero-length arrays are valid. */
+	if (entry->array_len == 0) {
+		os_free(entry->strarray_value);
+		entry->strarray_value = NULL;
+	}
+
+	success = TRUE;
+
+done:
+	return success;
+}
+
+
+#define BIN_ARRAY_CHUNK_SIZE 10
+#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
+	DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+	struct wpa_dbus_dict_entry tmpentry;
+	size_t buflen = 0;
+	int i;
+
+	if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
+		return FALSE;
+
+	entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
+	entry->array_len = 0;
+	entry->binarray_value = NULL;
+
+	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
+		DBusMessageIter iter_array;
+
+		if (entry->array_len == buflen) {
+			struct wpabuf **newbuf;
+
+			buflen += BIN_ARRAY_CHUNK_SIZE;
+
+			newbuf = os_realloc_array(entry->binarray_value,
+						  buflen, BIN_ARRAY_ITEM_SIZE);
+			if (!newbuf)
+				goto cleanup;
+			entry->binarray_value = newbuf;
+		}
+
+		dbus_message_iter_recurse(iter, &iter_array);
+		if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
+					== FALSE)
+			goto cleanup;
+
+		entry->binarray_value[entry->array_len] =
+			wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
+					      tmpentry.array_len);
+		if (entry->binarray_value[entry->array_len] == NULL) {
+			wpa_dbus_dict_entry_clear(&tmpentry);
+			goto cleanup;
+		}
+		entry->array_len++;
+		dbus_message_iter_next(iter);
+	}
+
+	return TRUE;
+
+ cleanup:
+	for (i = 0; i < (int) entry->array_len; i++)
+		wpabuf_free(entry->binarray_value[i]);
+	os_free(entry->binarray_value);
+	entry->array_len = 0;
+	entry->binarray_value = NULL;
+	return FALSE;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_array(
+	DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
+{
+	int array_type = dbus_message_iter_get_element_type(iter_dict_val);
+	dbus_bool_t success = FALSE;
+	DBusMessageIter iter_array;
+
+	if (!entry)
+		return FALSE;
+
+	dbus_message_iter_recurse(iter_dict_val, &iter_array);
+
+ 	switch (array_type) {
+	case DBUS_TYPE_BYTE:
+		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
+							      entry);
+		break;
+	case DBUS_TYPE_STRING:
+		success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
+								array_type,
+								entry);
+		break;
+	case DBUS_TYPE_ARRAY:
+		success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
+	default:
+		break;
+	}
+
+	return success;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
+	struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
+{
+	const char *v;
+
+	switch (entry->type) {
+	case DBUS_TYPE_OBJECT_PATH:
+	case DBUS_TYPE_STRING:
+		dbus_message_iter_get_basic(iter, &v);
+		entry->str_value = os_strdup(v);
+		if (entry->str_value == NULL)
+			return FALSE;
+		break;
+	case DBUS_TYPE_BOOLEAN:
+		dbus_message_iter_get_basic(iter, &entry->bool_value);
+		break;
+	case DBUS_TYPE_BYTE:
+		dbus_message_iter_get_basic(iter, &entry->byte_value);
+		break;
+	case DBUS_TYPE_INT16:
+		dbus_message_iter_get_basic(iter, &entry->int16_value);
+		break;
+	case DBUS_TYPE_UINT16:
+		dbus_message_iter_get_basic(iter, &entry->uint16_value);
+		break;
+	case DBUS_TYPE_INT32:
+		dbus_message_iter_get_basic(iter, &entry->int32_value);
+		break;
+	case DBUS_TYPE_UINT32:
+		dbus_message_iter_get_basic(iter, &entry->uint32_value);
+		break;
+	case DBUS_TYPE_INT64:
+		dbus_message_iter_get_basic(iter, &entry->int64_value);
+		break;
+	case DBUS_TYPE_UINT64:
+		dbus_message_iter_get_basic(iter, &entry->uint64_value);
+		break;
+	case DBUS_TYPE_DOUBLE:
+		dbus_message_iter_get_basic(iter, &entry->double_value);
+		break;
+	case DBUS_TYPE_ARRAY:
+		return _wpa_dbus_dict_entry_get_array(iter, entry);
+	default:
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * Read the current key/value entry from the dict.  Entries are dynamically
+ * allocated when needed and must be freed after use with the
+ * wpa_dbus_dict_entry_clear() function.
+ *
+ * The returned entry object will be filled with the type and value of the next
+ * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
+ * occurred.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *    wpa_dbus_dict_open_read()
+ * @param entry A valid dict entry object into which the dict key and value
+ *    will be placed
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
+				    struct wpa_dbus_dict_entry * entry)
+{
+	DBusMessageIter iter_dict_entry, iter_dict_val;
+	int type;
+	const char *key;
+
+	if (!iter_dict || !entry)
+		goto error;
+
+	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
+		goto error;
+
+	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
+	dbus_message_iter_get_basic(&iter_dict_entry, &key);
+	entry->key = key;
+
+	if (!dbus_message_iter_next(&iter_dict_entry))
+		goto error;
+	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
+	if (type != DBUS_TYPE_VARIANT)
+		goto error;
+
+	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
+	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
+	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+		goto error;
+
+	dbus_message_iter_next(iter_dict);
+	return TRUE;
+
+error:
+	if (entry) {
+		wpa_dbus_dict_entry_clear(entry);
+		entry->type = DBUS_TYPE_INVALID;
+		entry->array_type = DBUS_TYPE_INVALID;
+	}
+
+	return FALSE;
+}
+
+
+/**
+ * Return whether or not there are additional dictionary entries.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ *    wpa_dbus_dict_open_read()
+ * @return TRUE if more dict entries exists, FALSE if no more dict entries
+ * exist
+ */
+dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
+{
+	if (!iter_dict)
+		return FALSE;
+	return dbus_message_iter_get_arg_type(iter_dict) ==
+		DBUS_TYPE_DICT_ENTRY;
+}
+
+
+/**
+ * Free any memory used by the entry object.
+ *
+ * @param entry The entry object
+ */
+void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
+{
+	unsigned int i;
+
+	if (!entry)
+		return;
+	switch (entry->type) {
+	case DBUS_TYPE_OBJECT_PATH:
+	case DBUS_TYPE_STRING:
+		os_free(entry->str_value);
+		break;
+	case DBUS_TYPE_ARRAY:
+		switch (entry->array_type) {
+		case DBUS_TYPE_BYTE:
+			os_free(entry->bytearray_value);
+			break;
+		case DBUS_TYPE_STRING:
+			for (i = 0; i < entry->array_len; i++)
+				os_free(entry->strarray_value[i]);
+			os_free(entry->strarray_value);
+			break;
+		case WPAS_DBUS_TYPE_BINARRAY:
+			for (i = 0; i < entry->array_len; i++)
+				wpabuf_free(entry->binarray_value[i]);
+			os_free(entry->binarray_value);
+			break;
+		}
+		break;
+	}
+
+	os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_dict_helpers.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,137 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DBUS_DICT_HELPERS_H
-#define DBUS_DICT_HELPERS_H
-
-/*
- * Adding a dict to a DBusMessage
- */
-
-dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
-				     DBusMessageIter *iter_dict);
-
-dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
-				      DBusMessageIter *iter_dict);
-
-const char * wpa_dbus_type_as_string(const int type);
-
-dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
-					const char *key, const char *value);
-
-dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
-				      const char *key, const char value);
-
-dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
-				      const char *key,
-				      const dbus_bool_t value);
-
-dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
-				       const char *key,
-				       const dbus_int16_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
-					const char *key,
-					const dbus_uint16_t value);
-
-dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
-				       const char *key,
-				       const dbus_int32_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
-					const char *key,
-					const dbus_uint32_t value);
-
-dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
-				       const char *key,
-				       const dbus_int64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
-					const char *key,
-					const dbus_uint64_t value);
-
-dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
-					const char *key,
-					const double value);
-
-dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
-					     const char *key,
-					     const char *value);
-
-dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
-					    const char *key,
-					    const char *value,
-					    const dbus_uint32_t value_len);
-
-/* Manual construction and addition of string array elements */
-dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-                                             const char *key,
-                                             DBusMessageIter *iter_dict_entry,
-                                             DBusMessageIter *iter_dict_val,
-                                             DBusMessageIter *iter_array);
-
-dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
-                                             const char *elem);
-
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
-                                           DBusMessageIter *iter_dict_entry,
-                                           DBusMessageIter *iter_dict_val,
-                                           DBusMessageIter *iter_array);
-
-/* Convenience function to add a whole string list */
-dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
-					      const char *key,
-					      const char **items,
-					      const dbus_uint32_t num_items);
-
-/*
- * Reading a dict from a DBusMessage
- */
-
-struct wpa_dbus_dict_entry {
-	int type;         /** the dbus type of the dict entry's value */
-	int array_type;   /** the dbus type of the array elements if the dict
-			      entry value contains an array */
-	const char *key;  /** key of the dict entry */
-
-	/** Possible values of the property */
-	union {
-		char *str_value;
-		char byte_value;
-		dbus_bool_t bool_value;
-		dbus_int16_t int16_value;
-		dbus_uint16_t uint16_value;
-		dbus_int32_t int32_value;
-		dbus_uint32_t uint32_value;
-		dbus_int64_t int64_value;
-		dbus_uint64_t uint64_value;
-		double double_value;
-		char *bytearray_value;
-		char **strarray_value;
-	};
-	dbus_uint32_t array_len; /** length of the array if the dict entry's
-				     value contains an array */
-};
-
-dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-				    DBusMessageIter *iter_dict);
-
-dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
-				    struct wpa_dbus_dict_entry *entry);
-
-dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict);
-
-void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry);
-
-#endif  /* DBUS_DICT_HELPERS_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_dict_helpers.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_dict_helpers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,163 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DBUS_DICT_HELPERS_H
+#define DBUS_DICT_HELPERS_H
+
+#include "wpabuf.h"
+
+/*
+ * Adding a dict to a DBusMessage
+ */
+
+dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
+				     DBusMessageIter *iter_dict);
+
+dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
+				      DBusMessageIter *iter_dict);
+
+const char * wpa_dbus_type_as_string(const int type);
+
+dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
+					const char *key, const char *value);
+
+dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
+				      const char *key, const char value);
+
+dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
+				      const char *key,
+				      const dbus_bool_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
+				       const char *key,
+				       const dbus_int16_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
+					const char *key,
+					const dbus_uint16_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
+				       const char *key,
+				       const dbus_int32_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
+					const char *key,
+					const dbus_uint32_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
+				       const char *key,
+				       const dbus_int64_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
+					const char *key,
+					const dbus_uint64_t value);
+
+dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
+					const char *key,
+					const double value);
+
+dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
+					     const char *key,
+					     const char *value);
+
+dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
+					    const char *key,
+					    const char *value,
+					    const dbus_uint32_t value_len);
+
+/* Manual construction and addition of array elements */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+                                      const char *key, const char *type,
+                                      DBusMessageIter *iter_dict_entry,
+                                      DBusMessageIter *iter_dict_val,
+                                      DBusMessageIter *iter_array);
+
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+                                             const char *key,
+                                             DBusMessageIter *iter_dict_entry,
+                                             DBusMessageIter *iter_dict_val,
+                                             DBusMessageIter *iter_array);
+
+dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
+                                             const char *elem);
+
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+						const u8 *value,
+						size_t value_len);
+
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+                                    DBusMessageIter *iter_dict_entry,
+                                    DBusMessageIter *iter_dict_val,
+                                    DBusMessageIter *iter_array);
+
+static inline dbus_bool_t
+wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+			       DBusMessageIter *iter_dict_entry,
+			       DBusMessageIter *iter_dict_val,
+			       DBusMessageIter *iter_array)
+{
+	return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry,
+				       iter_dict_val, iter_array);
+}
+
+/* Convenience function to add a whole string list */
+dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const char **items,
+					      const dbus_uint32_t num_items);
+
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+					      const char *key,
+					      const struct wpabuf **items,
+					      const dbus_uint32_t num_items);
+
+/*
+ * Reading a dict from a DBusMessage
+ */
+
+#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+
+struct wpa_dbus_dict_entry {
+	int type;         /** the dbus type of the dict entry's value */
+	int array_type;   /** the dbus type of the array elements if the dict
+			      entry value contains an array, or the special
+			      WPAS_DBUS_TYPE_BINARRAY */
+	const char *key;  /** key of the dict entry */
+
+	/** Possible values of the property */
+	union {
+		char *str_value;
+		char byte_value;
+		dbus_bool_t bool_value;
+		dbus_int16_t int16_value;
+		dbus_uint16_t uint16_value;
+		dbus_int32_t int32_value;
+		dbus_uint32_t uint32_value;
+		dbus_int64_t int64_value;
+		dbus_uint64_t uint64_value;
+		double double_value;
+		char *bytearray_value;
+		char **strarray_value;
+		struct wpabuf **binarray_value;
+	};
+	dbus_uint32_t array_len; /** length of the array if the dict entry's
+				     value contains an array */
+};
+
+dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
+				    DBusMessageIter *iter_dict,
+				    DBusError *error);
+
+dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
+				    struct wpa_dbus_dict_entry *entry);
+
+dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict);
+
+void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry);
+
+#endif  /* DBUS_DICT_HELPERS_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1562 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wps/wps.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../bss.h"
-#include "dbus_new_helpers.h"
-#include "dbus_dict_helpers.h"
-#include "dbus_new.h"
-#include "dbus_new_handlers.h"
-#include "dbus_common.h"
-#include "dbus_common_i.h"
-
-
-/**
- * wpas_dbus_signal_interface - Send a interface related event signal
- * @wpa_s: %wpa_supplicant network interface data
- * @sig_name: signal name - InterfaceAdded or InterfaceRemoved
- * @properties: Whether to add second argument with object properties
- *
- * Notify listeners about event related with interface
- */
-static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
-				       const char *sig_name, int properties)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH,
-				      WPAS_DBUS_NEW_INTERFACE, sig_name);
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &wpa_s->dbus_new_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, wpa_s->dbus_new_path,
-					       WPAS_DBUS_NEW_IFACE_INTERFACE,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_interface_added - Send a interface created signal
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Notify listeners about creating new interface
- */
-static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s)
-{
-	wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE);
-}
-
-
-/**
- * wpas_dbus_signal_interface_removed - Send a interface removed signal
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Notify listeners about removing interface
- */
-static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s)
-{
-	wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE);
-
-}
-
-
-/**
- * wpas_dbus_signal_scan_done - send scan done signal
- * @wpa_s: %wpa_supplicant network interface data
- * @success: indicates if scanning succeed or failed
- *
- * Notify listeners about finishing a scan
- */
-void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *msg;
-	dbus_bool_t succ;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_INTERFACE,
-				      "ScanDone");
-	if (msg == NULL)
-		return;
-
-	succ = success ? TRUE : FALSE;
-	if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ,
-				     DBUS_TYPE_INVALID))
-		dbus_connection_send(iface->con, msg, NULL);
-	else
-		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_blob - Send a BSS related event signal
- * @wpa_s: %wpa_supplicant network interface data
- * @bss_obj_path: BSS object path
- * @sig_name: signal name - BSSAdded or BSSRemoved
- * @properties: Whether to add second argument with object properties
- *
- * Notify listeners about event related with BSS
- */
-static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
-				 const char *bss_obj_path,
-				 const char *sig_name, int properties)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_INTERFACE,
-				      sig_name);
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &bss_obj_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, bss_obj_path,
-					       WPAS_DBUS_NEW_IFACE_BSS,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_bss_added - Send a BSS added signal
- * @wpa_s: %wpa_supplicant network interface data
- * @bss_obj_path: new BSS object path
- *
- * Notify listeners about adding new BSS
- */
-static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s,
-				       const char *bss_obj_path)
-{
-	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE);
-}
-
-
-/**
- * wpas_dbus_signal_bss_removed - Send a BSS removed signal
- * @wpa_s: %wpa_supplicant network interface data
- * @bss_obj_path: BSS object path
- *
- * Notify listeners about removing BSS
- */
-static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s,
-					 const char *bss_obj_path)
-{
-	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE);
-}
-
-
-/**
- * wpas_dbus_signal_blob - Send a blob related event signal
- * @wpa_s: %wpa_supplicant network interface data
- * @name: blob name
- * @sig_name: signal name - BlobAdded or BlobRemoved
- *
- * Notify listeners about event related with blob
- */
-static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s,
-				  const char *name, const char *sig_name)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *msg;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_INTERFACE,
-				      sig_name);
-	if (msg == NULL)
-		return;
-
-	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
-				     DBUS_TYPE_INVALID))
-		dbus_connection_send(iface->con, msg, NULL);
-	else
-		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_blob_added - Send a blob added signal
- * @wpa_s: %wpa_supplicant network interface data
- * @name: blob name
- *
- * Notify listeners about adding a new blob
- */
-void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
-				 const char *name)
-{
-	wpas_dbus_signal_blob(wpa_s, name, "BlobAdded");
-}
-
-
-/**
- * wpas_dbus_signal_blob_removed - Send a blob removed signal
- * @wpa_s: %wpa_supplicant network interface data
- * @name: blob name
- *
- * Notify listeners about removing blob
- */
-void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
-				   const char *name)
-{
-	wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved");
-}
-
-
-/**
- * wpas_dbus_signal_network - Send a network related event signal
- * @wpa_s: %wpa_supplicant network interface data
- * @id: new network id
- * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
- * @properties: determines if add second argument with object properties
- *
- * Notify listeners about event related with configured network
- */
-static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
-				     int id, const char *sig_name,
-				     int properties)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
-	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-		    wpa_s->dbus_new_path, id);
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_INTERFACE,
-				      sig_name);
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-	path = net_obj_path;
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, net_obj_path,
-					       WPAS_DBUS_NEW_IFACE_NETWORK,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_network_added - Send a network added signal
- * @wpa_s: %wpa_supplicant network interface data
- * @id: new network id
- *
- * Notify listeners about adding new network
- */
-static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s,
-					   int id)
-{
-	wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE);
-}
-
-
-/**
- * wpas_dbus_signal_network_removed - Send a network removed signal
- * @wpa_s: %wpa_supplicant network interface data
- * @id: network id
- *
- * Notify listeners about removing a network
- */
-static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s,
-					     int id)
-{
-	wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE);
-}
-
-
-/**
- * wpas_dbus_signal_network_selected - Send a network selected signal
- * @wpa_s: %wpa_supplicant network interface data
- * @id: network id
- *
- * Notify listeners about selecting a network
- */
-void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
-{
-	wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE);
-}
-
-
-/**
- * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
- * @wpa_s: %wpa_supplicant network interface data
- * @ssid: configured network which Enabled property has changed
- *
- * Sends PropertyChanged signals containing new value of Enabled property
- * for specified network
- */
-void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
-					      struct wpa_ssid *ssid)
-{
-
-	char path[WPAS_DBUS_OBJECT_PATH_MAX];
-	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
-		    wpa_s->dbus_new_path, ssid->id);
-
-	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
-				       WPAS_DBUS_NEW_IFACE_NETWORK, "Enabled");
-}
-
-
-#ifdef CONFIG_WPS
-
-/**
- * wpas_dbus_signal_wps_event_success - Signals Success WPS event
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Sends Event dbus signal with name "success" and empty dict as arguments
- */
-void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
-{
-
-	DBusMessage *msg;
-	DBusMessageIter iter, dict_iter;
-	struct wpas_dbus_priv *iface;
-	char *key = "success";
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
-	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
-	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	else
-		dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Sends Event dbus signal with name "fail" and dictionary containing
- * "msg field with fail message number (int32) as arguments
- */
-void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
-				     struct wps_event_fail *fail)
-{
-
-	DBusMessage *msg;
-	DBusMessageIter iter, dict_iter;
-	struct wpas_dbus_priv *iface;
-	char *key = "fail";
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
-	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
-	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
-	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	else
-		dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Sends Event dbus signal with name "m2d" and dictionary containing
- * fields of wps_event_m2d structure.
- */
-void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
-				    struct wps_event_m2d *m2d)
-{
-
-	DBusMessage *msg;
-	DBusMessageIter iter, dict_iter;
-	struct wpas_dbus_priv *iface;
-	char *key = "m2d";
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
-	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
-	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_methods",
-					 m2d->config_methods) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer",
-					     (const char *) m2d->manufacturer,
-					     m2d->manufacturer_len) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_name",
-					     (const char *) m2d->model_name,
-					     m2d->model_name_len) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_number",
-					     (const char *) m2d->model_number,
-					     m2d->model_number_len) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number",
-					     (const char *)
-					     m2d->serial_number,
-					     m2d->serial_number_len) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name",
-					     (const char *) m2d->dev_name,
-					     m2d->dev_name_len) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type",
-					     (const char *)
-					     m2d->primary_dev_type, 8) ||
-	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_error",
-					 m2d->config_error) ||
-	    !wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id",
-					 m2d->dev_password_id) ||
-	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
-	else
-		dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-}
-
-
-/**
- * wpas_dbus_signal_wps_cred - Signals new credentials
- * @wpa_s: %wpa_supplicant network interface data
- *
- * Sends signal with credentials in directory argument
- */
-void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
-			       const struct wps_credential *cred)
-{
-	DBusMessage *msg;
-	DBusMessageIter iter, dict_iter;
-	struct wpas_dbus_priv *iface;
-	char *auth_type[6]; /* we have six possible authorization types */
-	int at_num = 0;
-	char *encr_type[4]; /* we have four possible encryption types */
-	int et_num = 0;
-
-	iface = wpa_s->global->dbus;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_WPS,
-				      "Credentials");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (cred->auth_type & WPS_AUTH_OPEN)
-		auth_type[at_num++] = "open";
-	if (cred->auth_type & WPS_AUTH_WPAPSK)
-		auth_type[at_num++] = "wpa-psk";
-	if (cred->auth_type & WPS_AUTH_SHARED)
-		auth_type[at_num++] = "shared";
-	if (cred->auth_type & WPS_AUTH_WPA)
-		auth_type[at_num++] = "wpa-eap";
-	if (cred->auth_type & WPS_AUTH_WPA2)
-		auth_type[at_num++] = "wpa2-eap";
-	if (cred->auth_type & WPS_AUTH_WPA2PSK)
-		auth_type[at_num++] =
-		"wpa2-psk";
-
-	if (cred->encr_type & WPS_ENCR_NONE)
-		encr_type[et_num++] = "none";
-	if (cred->encr_type & WPS_ENCR_WEP)
-		encr_type[et_num++] = "wep";
-	if (cred->encr_type & WPS_ENCR_TKIP)
-		encr_type[et_num++] = "tkip";
-	if (cred->encr_type & WPS_ENCR_AES)
-		encr_type[et_num++] = "aes";
-
-	if (wpa_s->current_ssid) {
-		if (!wpa_dbus_dict_append_byte_array(
-			    &dict_iter, "BSSID",
-			    (const char *) wpa_s->current_ssid->bssid,
-			    ETH_ALEN))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
-					     (const char *) cred->ssid,
-					     cred->ssid_len) ||
-	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
-					       (const char **) auth_type,
-					       at_num) ||
-	    !wpa_dbus_dict_append_string_array(&dict_iter, "EncrType",
-					       (const char **) encr_type,
-					       et_num) ||
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "Key",
-					     (const char *) cred->key,
-					     cred->key_len) ||
-	    !wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex",
-					 cred->key_idx) ||
-	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
-	dbus_message_unref(msg);
-}
-
-#endif /* CONFIG_WPS */
-
-
-/**
- * wpas_dbus_signal_prop_changed - Signals change of property
- * @wpa_s: %wpa_supplicant network interface data
- * @property: indicates which property has changed
- *
- * Sends ProertyChanged signals with path, interface and arguments
- * depending on which property has changed.
- */
-void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
-				   enum wpas_dbus_prop property)
-{
-	WPADBusPropertyAccessor getter;
-	char *prop;
-
-	if (wpa_s->dbus_new_path == NULL)
-		return; /* Skip signal since D-Bus setup is not yet ready */
-
-	switch (property) {
-	case WPAS_DBUS_PROP_AP_SCAN:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan;
-		prop = "ApScan";
-		break;
-	case WPAS_DBUS_PROP_SCANNING:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning;
-		prop = "Scanning";
-		break;
-	case WPAS_DBUS_PROP_STATE:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_state;
-		prop = "State";
-		break;
-	case WPAS_DBUS_PROP_CURRENT_BSS:
-		getter = (WPADBusPropertyAccessor)
-			wpas_dbus_getter_current_bss;
-		prop = "CurrentBSS";
-		break;
-	case WPAS_DBUS_PROP_CURRENT_NETWORK:
-		getter = (WPADBusPropertyAccessor)
-			wpas_dbus_getter_current_network;
-		prop = "CurrentNetwork";
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
-			   __func__, property);
-		return;
-	}
-
-	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
-				       wpa_s->dbus_new_path,
-				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
-}
-
-
-/**
- * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
- * @wpa_s: %wpa_supplicant network interface data
- * @property: indicates which property has changed
- * @id: unique BSS identifier
- *
- * Sends PropertyChanged signals with path, interface, and arguments depending
- * on which property has changed.
- */
-void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
-				       enum wpas_dbus_bss_prop property,
-				       unsigned int id)
-{
-	char path[WPAS_DBUS_OBJECT_PATH_MAX];
-	char *prop;
-
-	switch (property) {
-	case WPAS_DBUS_BSS_PROP_SIGNAL:
-		prop = "Signal";
-		break;
-	case WPAS_DBUS_BSS_PROP_FREQ:
-		prop = "Frequency";
-		break;
-	case WPAS_DBUS_BSS_PROP_MODE:
-		prop = "Mode";
-		break;
-	case WPAS_DBUS_BSS_PROP_PRIVACY:
-		prop = "Privacy";
-		break;
-	case WPAS_DBUS_BSS_PROP_RATES:
-		prop = "Rates";
-		break;
-	case WPAS_DBUS_BSS_PROP_WPA:
-		prop = "WPA";
-		break;
-	case WPAS_DBUS_BSS_PROP_RSN:
-		prop = "RSN";
-		break;
-	case WPAS_DBUS_BSS_PROP_IES:
-		prop = "IEs";
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
-			   __func__, property);
-		return;
-	}
-
-	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-		    wpa_s->dbus_new_path, id);
-
-	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
-				       WPAS_DBUS_NEW_IFACE_BSS, prop);
-}
-
-
-/**
- * wpas_dbus_signal_debug_level_changed - Signals change of debug param
- * @global: wpa_global structure
- *
- * Sends ProertyChanged signals informing that debug level has changed.
- */
-void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
-{
-	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-				       WPAS_DBUS_NEW_INTERFACE,
-				       "DebugLevel");
-}
-
-
-/**
- * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
- * @global: wpa_global structure
- *
- * Sends ProertyChanged signals informing that debug timestamp has changed.
- */
-void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
-{
-	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-				       WPAS_DBUS_NEW_INTERFACE,
-				       "DebugTimestamp");
-}
-
-
-/**
- * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
- * @global: wpa_global structure
- *
- * Sends ProertyChanged signals informing that debug show_keys has changed.
- */
-void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
-{
-	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
-				       WPAS_DBUS_NEW_INTERFACE,
-				       "DebugShowKeys");
-}
-
-
-static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
-			       void *priv,
-			       WPADBusArgumentFreeFunction priv_free,
-			       const struct wpa_dbus_method_desc *methods,
-			       const struct wpa_dbus_property_desc *properties,
-			       const struct wpa_dbus_signal_desc *signals)
-{
-	int n;
-
-	obj_desc->user_data = priv;
-	obj_desc->user_data_free_func = priv_free;
-	obj_desc->methods = methods;
-	obj_desc->properties = properties;
-	obj_desc->signals = signals;
-
-	for (n = 0; properties && properties->dbus_property; properties++)
-		n++;
-
-	obj_desc->prop_changed_flags = os_zalloc(n);
-	if (!obj_desc->prop_changed_flags)
-		wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
-			   __func__);
-}
-
-
-static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
-	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
-	  {
-		  { "args", "a{sv}", ARG_IN },
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
-	  {
-		  { "path", "o", ARG_IN },
-		  END_ARGS
-	  }
-	},
-	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
-	  {
-		  { "ifname", "s", ARG_IN },
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ NULL, NULL, NULL, { END_ARGS } }
-};
-
-static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
-	{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level,
-	  RW
-	},
-	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp,
-	  RW
-	},
-	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys,
-	  RW
-	},
-	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces,
-	  NULL,
-	  R
-	},
-	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods,
-	  NULL,
-	  R
-	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
-	{ "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
-	  {
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ NULL, NULL, { END_ARGS } }
-};
-
-
-/**
- * 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
- * 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;
-
-	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;
-	}
-
-	wpas_dbus_register(obj_desc, priv->global, NULL,
-			   wpas_dbus_global_methods,
-			   wpas_dbus_global_properties,
-			   wpas_dbus_global_signals);
-
-	wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
-		   WPAS_DBUS_NEW_PATH);
-	ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
-				       WPAS_DBUS_NEW_SERVICE,
-				       obj_desc);
-	if (ret < 0)
-		free_dbus_object_desc(obj_desc);
-	else
-		priv->dbus_new_initialized = 1;
-
-	return ret;
-}
-
-
-/**
- * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
- * wpa_supplicant
- * @iface: 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)
-{
-	if (!iface->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);
-}
-
-
-static void wpa_dbus_free(void *ptr)
-{
-	os_free(ptr);
-}
-
-
-static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
-	{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties,
-	  RW
-	},
-	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_enabled,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_enabled,
-	  RW
-	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-
-static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
-	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
-	  {
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ NULL, NULL, { END_ARGS } }
-};
-
-
-/**
- * wpas_dbus_register_network - Register a configured network with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @ssid: network configuration data
- * Returns: 0 on success, -1 on failure
- *
- * Registers network representing object with dbus
- */
-int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-	struct wpa_dbus_object_desc *obj_desc;
-	struct network_handler_args *arg;
-	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-		    wpa_s->dbus_new_path, ssid->id);
-
-	wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
-		   net_obj_path);
-	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
-		goto err;
-	}
-
-	/* allocate memory for handlers arguments */
-	arg = os_zalloc(sizeof(struct network_handler_args));
-	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for method");
-		goto err;
-	}
-
-	arg->wpa_s = wpa_s;
-	arg->ssid = ssid;
-
-	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
-			   wpas_dbus_network_properties,
-			   wpas_dbus_network_signals);
-
-	if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
-					       wpa_s->ifname, obj_desc))
-		goto err;
-
-	wpas_dbus_signal_network_added(wpa_s, ssid->id);
-
-	return 0;
-
-err:
-	free_dbus_object_desc(obj_desc);
-	return -1;
-}
-
-
-/**
- * wpas_dbus_unregister_network - Unregister a configured network from dbus
- * @wpa_s: wpa_supplicant interface structure
- * @nid: network id
- * Returns: 0 on success, -1 on failure
- *
- * Unregisters network representing object from dbus
- */
-int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-	int ret;
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL ||
-	    wpa_s->dbus_new_path == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-		    wpa_s->dbus_new_path, nid);
-
-	wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
-		   net_obj_path);
-	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
-
-	if (!ret)
-		wpas_dbus_signal_network_removed(wpa_s, nid);
-
-	return ret;
-}
-
-
-static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
-	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid,
-	  NULL,
-	  R
-	},
-	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid,
-	  NULL,
-	  R
-	},
-	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy,
-	  NULL,
-	  R
-	},
-	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode,
-	  NULL,
-	  R
-	},
-	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal,
-	  NULL,
-	  R
-	},
-	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency,
-	  NULL,
-	  R
-	},
-	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rates,
-	  NULL,
-	  R
-	},
-	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpa,
-	  NULL,
-	  R
-	},
-	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsn,
-	  NULL,
-	  R
-	},
-	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ies,
-	  NULL,
-	  R
-	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-
-static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
-	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
-	  {
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ NULL, NULL, { END_ARGS } }
-};
-
-
-/**
- * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
- * @wpa_s: wpa_supplicant interface structure
- * @bssid: scanned network bssid
- * @id: unique BSS identifier
- * Returns: 0 on success, -1 on failure
- *
- * Unregisters BSS representing object from dbus
- */
-int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
-			     u8 bssid[ETH_ALEN], unsigned int id)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-		    wpa_s->dbus_new_path, id);
-
-	wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
-		   bss_obj_path);
-	if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
-		wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
-			   bss_obj_path);
-		return -1;
-	}
-
-	wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
-
-	return 0;
-}
-
-
-/**
- * wpas_dbus_register_bss - Register a scanned BSS with dbus
- * @wpa_s: wpa_supplicant interface structure
- * @bssid: scanned network bssid
- * @id: unique BSS identifier
- * Returns: 0 on success, -1 on failure
- *
- * Registers BSS representing object with dbus
- */
-int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
-			   u8 bssid[ETH_ALEN], unsigned int id)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-	struct wpa_dbus_object_desc *obj_desc;
-	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-	struct bss_handler_args *arg;
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-		    wpa_s->dbus_new_path, id);
-
-	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
-		goto err;
-	}
-
-	arg = os_zalloc(sizeof(struct bss_handler_args));
-	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for handler");
-		goto err;
-	}
-	arg->wpa_s = wpa_s;
-	arg->id = id;
-
-	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
-			   wpas_dbus_bss_properties,
-			   wpas_dbus_bss_signals);
-
-	wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
-		   bss_obj_path);
-	if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
-					       wpa_s->ifname, obj_desc)) {
-		wpa_printf(MSG_ERROR,
-			   "Cannot register BSSID dbus object %s.",
-			   bss_obj_path);
-		goto err;
-	}
-
-	wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
-
-	return 0;
-
-err:
-	free_dbus_object_desc(obj_desc);
-	return -1;
-}
-
-
-static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
-	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_scan,
-	  {
-		  { "args", "a{sv}", ARG_IN },
-		  END_ARGS
-	  }
-	},
-	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
-	  {
-		  END_ARGS
-	  }
-	},
-	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
-	  {
-		  { "args", "a{sv}", ARG_IN },
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
-	  {
-		  { "path", "o", ARG_IN },
-		  END_ARGS
-	  }
-	},
-	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
-	  {
-		  { "path", "o", ARG_IN },
-		  END_ARGS
-	  }
-	},
-	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
-	  {
-		  { "name", "s", ARG_IN },
-		  { "data", "ay", ARG_IN },
-		  END_ARGS
-	  }
-	},
-	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
-	  {
-		  { "name", "s", ARG_IN },
-		  { "data", "ay", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
-	  {
-		  { "name", "s", ARG_IN },
-		  END_ARGS
-	  }
-	},
-#ifdef CONFIG_WPS
-	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
-	  {
-		  { "args", "a{sv}", ARG_IN },
-		  { "output", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-#endif /* CONFIG_WPS */
-	{ NULL, NULL, NULL, { END_ARGS } }
-};
-
-static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
-	{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities,
-	  NULL, R
-	},
-	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_state,
-	  NULL, R
-	},
-	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_scanning,
-	  NULL, R
-	},
-	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan,
-	  RW
-	},
-	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_ifname,
-	  NULL, R
-	},
-	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_driver,
-	  NULL, R
-	},
-	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname,
-	  NULL, R
-	},
-	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss,
-	  NULL, R
-	},
-	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_current_network,
-	  NULL, R
-	},
-	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_blobs,
-	  NULL, R
-	},
-	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bsss,
-	  NULL, R
-	},
-	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_networks,
-	  NULL, R
-	},
-#ifdef CONFIG_WPS
-	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials,
-	  RW
-	},
-#endif /* CONFIG_WPS */
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
-	{ "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "success", "b", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "name", "s", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "name", "s", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-#ifdef CONFIG_WPS
-	{ "Event", WPAS_DBUS_NEW_IFACE_WPS,
-	  {
-		  { "name", "s", ARG_OUT },
-		  { "args", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
-	  {
-		  { "credentials", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
-	  {
-		  { "properties", "a{sv}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
-#endif /* CONFIG_WPS */
-	{ NULL, NULL, { END_ARGS } }
-};
-
-
-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;
-
-	/* Do nothing if the control interface is not turned on */
-	if (ctrl_iface == NULL)
-		return 0;
-
-	/* Create and set the interface's object path */
-	wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
-	if (wpa_s->dbus_new_path == NULL)
-		return -1;
-	next = ctrl_iface->next_objid++;
-	os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
-		    next);
-
-	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
-		goto err;
-	}
-
-	wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
-			   wpas_dbus_interface_properties,
-			   wpas_dbus_interface_signals);
-
-	wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
-		   wpa_s->dbus_new_path);
-	if (wpa_dbus_register_object_per_iface(ctrl_iface,
-					       wpa_s->dbus_new_path,
-					       wpa_s->ifname, obj_desc))
-		goto err;
-
-	wpas_dbus_signal_interface_added(wpa_s);
-
-	return 0;
-
-err:
-	os_free(wpa_s->dbus_new_path);
-	wpa_s->dbus_new_path = NULL;
-	free_dbus_object_desc(obj_desc);
-	return -1;
-}
-
-
-int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
-		   wpa_s->dbus_new_path);
-	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
-						 wpa_s->dbus_new_path))
-		return -1;
-
-	wpas_dbus_signal_interface_removed(wpa_s);
-
-	os_free(wpa_s->dbus_new_path);
-	wpa_s->dbus_new_path = NULL;
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3710 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "wps/wps.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../bss.h"
+#include "../wpas_glue.h"
+#include "dbus_new_helpers.h"
+#include "dbus_dict_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_common_i.h"
+#include "dbus_new_handlers_p2p.h"
+#include "p2p/p2p.h"
+
+#ifdef CONFIG_AP /* until needed by something else */
+
+/*
+ * NameOwnerChanged handling
+ *
+ * Some services we provide allow an application to register for
+ * a signal that it needs. While it can also unregister, we must
+ * be prepared for the case where the application simply crashes
+ * and thus doesn't clean up properly. The way to handle this in
+ * DBus is to register for the NameOwnerChanged signal which will
+ * signal an owner change to NULL if the peer closes the socket
+ * for whatever reason.
+ *
+ * Handle this signal via a filter function whenever necessary.
+ * The code below also handles refcounting in case in the future
+ * there will be multiple instances of this subscription scheme.
+ */
+static const char wpas_dbus_noc_filter_str[] =
+	"interface=org.freedesktop.DBus,member=NameOwnerChanged";
+
+
+static DBusHandlerResult noc_filter(DBusConnection *conn,
+				    DBusMessage *message, void *data)
+{
+	struct wpas_dbus_priv *priv = data;
+
+	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+				   "NameOwnerChanged")) {
+		const char *name;
+		const char *prev_owner;
+		const char *new_owner;
+		DBusError derr;
+		struct wpa_supplicant *wpa_s;
+
+		dbus_error_init(&derr);
+
+		if (!dbus_message_get_args(message, &derr,
+					   DBUS_TYPE_STRING, &name,
+					   DBUS_TYPE_STRING, &prev_owner,
+					   DBUS_TYPE_STRING, &new_owner,
+					   DBUS_TYPE_INVALID)) {
+			/* Ignore this error */
+			dbus_error_free(&derr);
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+		}
+
+		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		{
+			if (wpa_s->preq_notify_peer != NULL &&
+			    os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
+			    (new_owner == NULL || os_strlen(new_owner) == 0)) {
+				/* probe request owner disconnected */
+				os_free(wpa_s->preq_notify_peer);
+				wpa_s->preq_notify_peer = NULL;
+				wpas_dbus_unsubscribe_noc(priv);
+			}
+		}
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv)
+{
+	priv->dbus_noc_refcnt++;
+	if (priv->dbus_noc_refcnt > 1)
+		return;
+
+	if (!dbus_connection_add_filter(priv->con, noc_filter, priv, NULL)) {
+		wpa_printf(MSG_ERROR, "dbus: failed to add filter");
+		return;
+	}
+
+	dbus_bus_add_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+}
+
+
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv)
+{
+	priv->dbus_noc_refcnt--;
+	if (priv->dbus_noc_refcnt > 0)
+		return;
+
+	dbus_bus_remove_match(priv->con, wpas_dbus_noc_filter_str, NULL);
+	dbus_connection_remove_filter(priv->con, noc_filter, priv);
+}
+
+#endif /* CONFIG_AP */
+
+
+/**
+ * wpas_dbus_signal_interface - Send a interface related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sig_name: signal name - InterfaceAdded or InterfaceRemoved
+ * @properties: Whether to add second argument with object properties
+ *
+ * Notify listeners about event related with interface
+ */
+static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
+				       const char *sig_name, int properties)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(WPAS_DBUS_NEW_PATH,
+				      WPAS_DBUS_NEW_INTERFACE, sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &wpa_s->dbus_new_path))
+		goto err;
+
+	if (properties) {
+		if (!wpa_dbus_get_object_properties(
+			    iface, wpa_s->dbus_new_path,
+			    WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
+			goto err;
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_interface_added - Send a interface created signal
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Notify listeners about creating new interface
+ */
+static void wpas_dbus_signal_interface_added(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_interface(wpa_s, "InterfaceAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_interface_removed - Send a interface removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Notify listeners about removing interface
+ */
+static void wpas_dbus_signal_interface_removed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_interface(wpa_s, "InterfaceRemoved", FALSE);
+
+}
+
+
+/**
+ * wpas_dbus_signal_scan_done - send scan done signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @success: indicates if scanning succeed or failed
+ *
+ * Notify listeners about finishing a scan
+ */
+void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	dbus_bool_t succ;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "ScanDone");
+	if (msg == NULL)
+		return;
+
+	succ = success ? TRUE : FALSE;
+	if (dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &succ,
+				     DBUS_TYPE_INVALID))
+		dbus_connection_send(iface->con, msg, NULL);
+	else
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_blob - Send a BSS related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @bss_obj_path: BSS object path
+ * @sig_name: signal name - BSSAdded or BSSRemoved
+ * @properties: Whether to add second argument with object properties
+ *
+ * Notify listeners about event related with BSS
+ */
+static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
+				 const char *bss_obj_path,
+				 const char *sig_name, int properties)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &bss_obj_path))
+		goto err;
+
+	if (properties) {
+		if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
+						    WPAS_DBUS_NEW_IFACE_BSS,
+						    &iter))
+			goto err;
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_bss_added - Send a BSS added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @bss_obj_path: new BSS object path
+ *
+ * Notify listeners about adding new BSS
+ */
+static void wpas_dbus_signal_bss_added(struct wpa_supplicant *wpa_s,
+				       const char *bss_obj_path)
+{
+	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_bss_removed - Send a BSS removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @bss_obj_path: BSS object path
+ *
+ * Notify listeners about removing BSS
+ */
+static void wpas_dbus_signal_bss_removed(struct wpa_supplicant *wpa_s,
+					 const char *bss_obj_path)
+{
+	wpas_dbus_signal_bss(wpa_s, bss_obj_path, "BSSRemoved", FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_blob - Send a blob related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @name: blob name
+ * @sig_name: signal name - BlobAdded or BlobRemoved
+ *
+ * Notify listeners about event related with blob
+ */
+static void wpas_dbus_signal_blob(struct wpa_supplicant *wpa_s,
+				  const char *name, const char *sig_name)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
+				     DBUS_TYPE_INVALID))
+		dbus_connection_send(iface->con, msg, NULL);
+	else
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_blob_added - Send a blob added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @name: blob name
+ *
+ * Notify listeners about adding a new blob
+ */
+void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
+				 const char *name)
+{
+	wpas_dbus_signal_blob(wpa_s, name, "BlobAdded");
+}
+
+
+/**
+ * wpas_dbus_signal_blob_removed - Send a blob removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @name: blob name
+ *
+ * Notify listeners about removing blob
+ */
+void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
+				   const char *name)
+{
+	wpas_dbus_signal_blob(wpa_s, name, "BlobRemoved");
+}
+
+
+/**
+ * wpas_dbus_signal_network - Send a network related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new network id
+ * @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
+ * @properties: determines if add second argument with object properties
+ *
+ * Notify listeners about event related with configured network
+ */
+static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
+				     int id, const char *sig_name,
+				     int properties)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = net_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	if (properties) {
+		if (!wpa_dbus_get_object_properties(
+			    iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+			    &iter))
+			goto err;
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_network_added - Send a network added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new network id
+ *
+ * Notify listeners about adding new network
+ */
+static void wpas_dbus_signal_network_added(struct wpa_supplicant *wpa_s,
+					   int id)
+{
+	wpas_dbus_signal_network(wpa_s, id, "NetworkAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_network_removed - Send a network removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: network id
+ *
+ * Notify listeners about removing a network
+ */
+static void wpas_dbus_signal_network_removed(struct wpa_supplicant *wpa_s,
+					     int id)
+{
+	wpas_dbus_signal_network(wpa_s, id, "NetworkRemoved", FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_network_selected - Send a network selected signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: network id
+ *
+ * Notify listeners about selecting a network
+ */
+void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
+{
+	wpas_dbus_signal_network(wpa_s, id, "NetworkSelected", FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_network_request - Indicate that additional information
+ * (EAP password, etc.) is required to complete the association to this SSID
+ * @wpa_s: %wpa_supplicant network interface data
+ * @rtype: The specific additional information required
+ * @default_text: Optional description of required information
+ *
+ * Request additional information or passwords to complete an association
+ * request.
+ */
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid,
+				      enum wpa_ctrl_req_type rtype,
+				      const char *default_txt)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	const char *field, *txt = NULL, *net_ptr;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
+	if (field == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "NetworkRequest");
+	if (msg == NULL)
+		return;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->dbus_new_path, ssid->id);
+	net_ptr = &net_obj_path[0];
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &net_ptr))
+		goto err;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
+		goto err;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: configured network which Enabled property has changed
+ *
+ * Sends PropertyChanged signals containing new value of Enabled property
+ * for specified network
+ */
+void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid)
+{
+
+	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
+				       WPAS_DBUS_NEW_IFACE_NETWORK, "Enabled");
+}
+
+
+#ifdef CONFIG_WPS
+
+/**
+ * wpas_dbus_signal_wps_event_success - Signals Success WPS event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "success" and empty dict as arguments
+ */
+void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *key = "success";
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *key = "fail";
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "m2d" and dictionary containing
+ * fields of wps_event_m2d structure.
+ */
+void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
+				    struct wps_event_m2d *m2d)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *key = "m2d";
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_WPS, "Event");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_methods",
+					 m2d->config_methods) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "manufacturer",
+					     (const char *) m2d->manufacturer,
+					     m2d->manufacturer_len) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_name",
+					     (const char *) m2d->model_name,
+					     m2d->model_name_len) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "model_number",
+					     (const char *) m2d->model_number,
+					     m2d->model_number_len) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "serial_number",
+					     (const char *)
+					     m2d->serial_number,
+					     m2d->serial_number_len) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "dev_name",
+					     (const char *) m2d->dev_name,
+					     m2d->dev_name_len) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "primary_dev_type",
+					     (const char *)
+					     m2d->primary_dev_type, 8) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "config_error",
+					 m2d->config_error) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "dev_password_id",
+					 m2d->dev_password_id) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_wps_cred - Signals new credentials
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends signal with credentials in directory argument
+ */
+void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
+			       const struct wps_credential *cred)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *auth_type[6]; /* we have six possible authorization types */
+	int at_num = 0;
+	char *encr_type[4]; /* we have four possible encryption types */
+	int et_num = 0;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_WPS,
+				      "Credentials");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (cred->auth_type & WPS_AUTH_OPEN)
+		auth_type[at_num++] = "open";
+	if (cred->auth_type & WPS_AUTH_WPAPSK)
+		auth_type[at_num++] = "wpa-psk";
+	if (cred->auth_type & WPS_AUTH_SHARED)
+		auth_type[at_num++] = "shared";
+	if (cred->auth_type & WPS_AUTH_WPA)
+		auth_type[at_num++] = "wpa-eap";
+	if (cred->auth_type & WPS_AUTH_WPA2)
+		auth_type[at_num++] = "wpa2-eap";
+	if (cred->auth_type & WPS_AUTH_WPA2PSK)
+		auth_type[at_num++] =
+		"wpa2-psk";
+
+	if (cred->encr_type & WPS_ENCR_NONE)
+		encr_type[et_num++] = "none";
+	if (cred->encr_type & WPS_ENCR_WEP)
+		encr_type[et_num++] = "wep";
+	if (cred->encr_type & WPS_ENCR_TKIP)
+		encr_type[et_num++] = "tkip";
+	if (cred->encr_type & WPS_ENCR_AES)
+		encr_type[et_num++] = "aes";
+
+	if (wpa_s->current_ssid) {
+		if (!wpa_dbus_dict_append_byte_array(
+			    &dict_iter, "BSSID",
+			    (const char *) wpa_s->current_ssid->bssid,
+			    ETH_ALEN))
+			goto nomem;
+	}
+
+	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+					     (const char *) cred->ssid,
+					     cred->ssid_len) ||
+	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
+					       (const char **) auth_type,
+					       at_num) ||
+	    !wpa_dbus_dict_append_string_array(&dict_iter, "EncrType",
+					       (const char **) encr_type,
+					       et_num) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "Key",
+					     (const char *) cred->key,
+					     cred->key_len) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "KeyIndex",
+					 cred->key_idx) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_WPS */
+
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+				    int depth, const char *subject,
+				    const char *cert_hash,
+				    const struct wpabuf *cert)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "Certification");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
+		goto nomem;
+
+	if (cert_hash &&
+	    !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
+		goto nomem;
+
+	if (cert &&
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+					     wpabuf_head(cert),
+					     wpabuf_len(cert)))
+		goto nomem;
+
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+				 const char *status, const char *parameter)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "EAP");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
+	    ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+					    &parameter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+#ifdef CONFIG_P2P
+
+/**
+ * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
+ * @wpa_s: %wpa_supplicant network interface data
+ * @role: role of this device (client or GO)
+ * Sends signal with i/f name and role as string arguments
+ */
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+					const char *role)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+	char *ifname = wpa_s->ifname;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GroupFinished");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+				      "signal -not enough memory for ifname ");
+		goto err;
+	}
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+				      "signal -not enough memory for role ");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+err:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
+ *
+ * @dev_addr - who sent the request or responded to our request.
+ * @request - Will be 1 if request, 0 for response.
+ * @status - valid only in case of response
+ * @config_methods - wps config methods
+ * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * Sends following provision discovery related events:
+ *	ProvisionDiscoveryRequestDisplayPin
+ *	ProvisionDiscoveryResponseDisplayPin
+ *	ProvisionDiscoveryRequestEnterPin
+ *	ProvisionDiscoveryResponseEnterPin
+ *	ProvisionDiscoveryPBCRequest
+ *	ProvisionDiscoveryPBCResponse
+ *
+ *	TODO::
+ *	ProvisionDiscoveryFailure (timeout case)
+ */
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					      const u8 *dev_addr, int request,
+					      enum p2p_prov_disc_status status,
+					      u16 config_methods,
+					      unsigned int generated_pin)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface;
+	char *_signal;
+	int add_pin = 0;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	int error_ret = 1;
+	char pin[9], *p_pin = NULL;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (request || !status) {
+		if (config_methods & WPS_CONFIG_DISPLAY)
+			_signal = request ?
+				 "ProvisionDiscoveryRequestDisplayPin" :
+				 "ProvisionDiscoveryResponseEnterPin";
+		else if (config_methods & WPS_CONFIG_KEYPAD)
+			_signal = request ?
+				 "ProvisionDiscoveryRequestEnterPin" :
+				 "ProvisionDiscoveryResponseDisplayPin";
+		else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+			_signal = request ? "ProvisionDiscoveryPBCRequest" :
+				   "ProvisionDiscoveryPBCResponse";
+		else
+			return; /* Unknown or un-supported method */
+	} else if (!request && status)
+		/* Explicit check for failure response */
+		_signal = "ProvisionDiscoveryFailure";
+
+	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
+		   (!request && !status &&
+			(config_methods & WPS_CONFIG_KEYPAD)));
+
+	if (add_pin) {
+		os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
+		p_pin = pin;
+	}
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter,
+					    DBUS_TYPE_OBJECT_PATH,
+					    &path))
+			goto error;
+
+	if (!request && status)
+		/* Attach status to ProvisionDiscoveryFailure */
+		error_ret = !dbus_message_iter_append_basic(&iter,
+						    DBUS_TYPE_INT32,
+						    &status);
+	else
+		error_ret = (add_pin &&
+				 !dbus_message_iter_append_basic(&iter,
+							DBUS_TYPE_STRING,
+							&p_pin));
+
+error:
+	if (!error_ret)
+		dbus_connection_send(iface->con, msg, NULL);
+	else
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+
+	dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				     const u8 *src, u16 dev_passwd_id)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(src));
+	path = peer_obj_path;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GONegotiationRequest");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+					    &dev_passwd_id))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+
+static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					char *group_obj_path)
+{
+	char group_name[3];
+
+	if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
+		return -1;
+
+	os_memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+	group_name[2] = '\0';
+
+	os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
+		    wpa_s->dbus_new_path, group_name);
+
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_group_started - Signals P2P group has
+ * started. Emitted when a group is successfully started
+ * 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
+ */
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					int client, int network_id)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	iface = wpa_s->parent->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+		return;
+
+	/* New interface has been created for this group */
+	msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "GroupStarted");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	/*
+	 * In case the device supports creating a separate interface the
+	 * DBus client will need to know the object path for the interface
+	 * object this group was created on, so include it here.
+	 */
+	if (!wpa_dbus_dict_append_object_path(&dict_iter,
+					"interface_object",
+					wpa_s->dbus_new_path))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_string(&dict_iter, "role",
+					 client ? "client" : "GO"))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+					     group_obj_path) ||
+	   !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit GONeogtiation Success or Failure signals based
+ * on status.
+ * @status: Status of the GO neg request. 0 for success, other for errors.
+ */
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	dbus_int32_t freqs[P2P_MAX_CHANNELS];
+	dbus_int32_t *f_array = freqs;
+
+
+	iface = wpa_s->global->dbus;
+
+	os_memset(freqs, 0, sizeof(freqs));
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(res->peer_device_addr));
+	path = peer_obj_path;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      res->status ? "GONegotiationFailure" :
+						    "GONegotiationSuccess");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto err;
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+					      path) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
+		goto err;
+
+	if (!res->status) {
+		int i = 0;
+		int freq_list_num = 0;
+
+		if (res->role_go) {
+			if (!wpa_dbus_dict_append_byte_array(
+				    &dict_iter, "passphrase",
+				    (const char *) res->passphrase,
+				    sizeof(res->passphrase)))
+				goto err;
+		}
+
+		if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+						 res->role_go ? "GO" :
+						 "client") ||
+		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
+						res->freq) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
+						     (const char *) res->ssid,
+						     res->ssid_len) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter,
+						     "peer_device_addr",
+						     (const char *)
+						     res->peer_device_addr,
+						     ETH_ALEN) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter,
+						     "peer_interface_addr",
+						     (const char *)
+						     res->peer_interface_addr,
+						     ETH_ALEN) ||
+		    !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
+						 p2p_wps_method_text(
+							 res->wps_method)))
+			goto err;
+
+		for (i = 0; i < P2P_MAX_CHANNELS; i++) {
+			if (res->freq_list[i]) {
+				freqs[i] = res->freq_list[i];
+				freq_list_num++;
+			}
+		}
+
+		if (!wpa_dbus_dict_begin_array(&dict_iter,
+					       "frequency_list",
+					       DBUS_TYPE_INT32_AS_STRING,
+					       &iter_dict_entry,
+					       &iter_dict_val,
+					       &iter_dict_array))
+			goto err;
+
+		if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+							  DBUS_TYPE_INT32,
+							  &f_array,
+							  freq_list_num))
+			goto err;
+
+		if (!wpa_dbus_dict_end_array(&dict_iter,
+					     &iter_dict_entry,
+					     &iter_dict_val,
+					     &iter_dict_array))
+			goto err;
+
+		if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+						res->persistent_group) ||
+		    !wpa_dbus_dict_append_uint32(&dict_iter,
+						 "peer_config_timeout",
+						 res->peer_config_timeout))
+			goto err;
+	}
+
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+err:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit Invitation Result signal based on status and
+ * bssid
+ * @status: Status of the Invite request. 0 for success, other
+ * for errors
+ * @bssid : Basic Service Set Identifier
+ */
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+					    int status, const u8 *bssid)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+
+	wpa_printf(MSG_INFO, "%s\n", __func__);
+
+	iface = wpa_s->global->dbus;
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "InvitationResult");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
+		goto nomem;
+	if (bssid) {
+		if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+						     (const char *) bssid,
+						     ETH_ALEN))
+			goto nomem;
+	}
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer joining the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				      const u8 *member)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+				      "PeerJoined");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = groupmember_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer disconnecting the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+				      const u8 *member)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			"%s/"  WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+			COMPACT_MACSTR,
+			wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+				      "PeerDisconnected");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = groupmember_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
+			      "signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery request.
+ * The signal will carry station address, frequency, dialog token,
+ * update indicator and it tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @dialog_token: service discovery request dialog token
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				     int freq, const u8 *sa, u8 dialog_token,
+				     u16 update_indic, const u8 *tlvs,
+				     size_t tlvs_len)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "ServiceDiscoveryRequest");
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto error;
+
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+					      path) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
+					dialog_token) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+					 update_indic) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+					     (const char *) tlvs,
+					     tlvs_len) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto error;
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+error:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery response.
+ * The signal will carry station address, update indicator and it
+ * tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				      const u8 *sa, u16 update_indic,
+				      const u8 *tlvs, size_t tlvs_len)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				"ServiceDiscoveryResponse");
+	if (msg == NULL)
+		return;
+
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
+		goto error;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+	path = peer_obj_path;
+
+	dbus_message_iter_init_append(msg, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto error;
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+					      path) ||
+	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+					 update_indic) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+					     (const char *) tlvs,
+					     tlvs_len) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto error;
+
+
+	dbus_connection_send(iface->con, msg, NULL);
+	dbus_message_unref(msg);
+	return;
+error:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+/**
+ * wpas_dbus_signal_persistent_group - Send a persistent group related
+ *	event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
+ * @properties: determines if add second argument with object properties
+ *
+ * Notify listeners about an event related to persistent groups.
+ */
+static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
+					      int id, const char *sig_name,
+					      int properties)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = pgrp_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	if (properties) {
+		if (!wpa_dbus_get_object_properties(
+			    iface, pgrp_obj_path,
+			    WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
+			goto err;
+	}
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_added - Send a persistent_group
+ *	added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ *
+ * Notify listeners about addition of a new persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_added(
+	struct wpa_supplicant *wpa_s, int id)
+{
+	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
+					  TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
+ *	removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: persistent group id
+ *
+ * Notify listeners about removal of a persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_removed(
+	struct wpa_supplicant *wpa_s, int id)
+{
+	wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
+					  FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg" field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail)
+{
+
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *iface;
+	char *key = "fail";
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "WpsFailed");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+	    !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+	    !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
+					fail->config_error) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+}
+
+#endif /*CONFIG_P2P*/
+
+
+/**
+ * wpas_dbus_signal_prop_changed - Signals change of property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ *
+ * Sends PropertyChanged signals with path, interface and arguments
+ * depending on which property has changed.
+ */
+void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				   enum wpas_dbus_prop property)
+{
+	char *prop;
+	dbus_bool_t flush;
+
+	if (wpa_s->dbus_new_path == NULL)
+		return; /* Skip signal since D-Bus setup is not yet ready */
+
+	flush = FALSE;
+	switch (property) {
+	case WPAS_DBUS_PROP_AP_SCAN:
+		prop = "ApScan";
+		break;
+	case WPAS_DBUS_PROP_SCANNING:
+		prop = "Scanning";
+		break;
+	case WPAS_DBUS_PROP_STATE:
+		prop = "State";
+		break;
+	case WPAS_DBUS_PROP_CURRENT_BSS:
+		prop = "CurrentBSS";
+		break;
+	case WPAS_DBUS_PROP_CURRENT_NETWORK:
+		prop = "CurrentNetwork";
+		break;
+	case WPAS_DBUS_PROP_BSSS:
+		prop = "BSSs";
+		break;
+	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
+		prop = "CurrentAuthMode";
+		break;
+	case WPAS_DBUS_PROP_DISCONNECT_REASON:
+		prop = "DisconnectReason";
+		flush = TRUE;
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+			   __func__, property);
+		return;
+	}
+
+	wpa_dbus_mark_property_changed(wpa_s->global->dbus,
+				       wpa_s->dbus_new_path,
+				       WPAS_DBUS_NEW_IFACE_INTERFACE, prop);
+	if (flush) {
+		wpa_dbus_flush_object_changed_properties(
+			wpa_s->global->dbus->con, wpa_s->dbus_new_path);
+	}
+}
+
+
+/**
+ * wpas_dbus_bss_signal_prop_changed - Signals change of BSS property
+ * @wpa_s: %wpa_supplicant network interface data
+ * @property: indicates which property has changed
+ * @id: unique BSS identifier
+ *
+ * Sends PropertyChanged signals with path, interface, and arguments depending
+ * on which property has changed.
+ */
+void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				       enum wpas_dbus_bss_prop property,
+				       unsigned int id)
+{
+	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+	char *prop;
+
+	switch (property) {
+	case WPAS_DBUS_BSS_PROP_SIGNAL:
+		prop = "Signal";
+		break;
+	case WPAS_DBUS_BSS_PROP_FREQ:
+		prop = "Frequency";
+		break;
+	case WPAS_DBUS_BSS_PROP_MODE:
+		prop = "Mode";
+		break;
+	case WPAS_DBUS_BSS_PROP_PRIVACY:
+		prop = "Privacy";
+		break;
+	case WPAS_DBUS_BSS_PROP_RATES:
+		prop = "Rates";
+		break;
+	case WPAS_DBUS_BSS_PROP_WPA:
+		prop = "WPA";
+		break;
+	case WPAS_DBUS_BSS_PROP_RSN:
+		prop = "RSN";
+		break;
+	case WPAS_DBUS_BSS_PROP_IES:
+		prop = "IEs";
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
+			   __func__, property);
+		return;
+	}
+
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
+				       WPAS_DBUS_NEW_IFACE_BSS, prop);
+}
+
+
+/**
+ * wpas_dbus_signal_debug_level_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug level has changed.
+ */
+void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
+{
+	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+				       WPAS_DBUS_NEW_INTERFACE,
+				       "DebugLevel");
+}
+
+
+/**
+ * wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug timestamp has changed.
+ */
+void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
+{
+	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+				       WPAS_DBUS_NEW_INTERFACE,
+				       "DebugTimestamp");
+}
+
+
+/**
+ * wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
+ * @global: wpa_global structure
+ *
+ * Sends PropertyChanged signals informing that debug show_keys has changed.
+ */
+void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
+{
+	wpa_dbus_mark_property_changed(global->dbus, WPAS_DBUS_NEW_PATH,
+				       WPAS_DBUS_NEW_INTERFACE,
+				       "DebugShowKeys");
+}
+
+
+static void wpas_dbus_register(struct wpa_dbus_object_desc *obj_desc,
+			       void *priv,
+			       WPADBusArgumentFreeFunction priv_free,
+			       const struct wpa_dbus_method_desc *methods,
+			       const struct wpa_dbus_property_desc *properties,
+			       const struct wpa_dbus_signal_desc *signals)
+{
+	int n;
+
+	obj_desc->user_data = priv;
+	obj_desc->user_data_free_func = priv_free;
+	obj_desc->methods = methods;
+	obj_desc->properties = properties;
+	obj_desc->signals = signals;
+
+	for (n = 0; properties && properties->dbus_property; properties++)
+		n++;
+
+	obj_desc->prop_changed_flags = os_zalloc(n);
+	if (!obj_desc->prop_changed_flags)
+		wpa_printf(MSG_DEBUG, "dbus: %s: can't register handlers",
+			   __func__);
+}
+
+
+static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
+	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+	  {
+		  { "ifname", "s", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#ifdef CONFIG_AUTOSCAN
+	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+	  {
+		  { "arg", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_AUTOSCAN */
+	{ 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
+	},
+	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
+	  wpas_dbus_getter_debug_timestamp,
+	  wpas_dbus_setter_debug_timestamp
+	},
+	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
+	  wpas_dbus_getter_debug_show_keys,
+	  wpas_dbus_setter_debug_show_keys
+	},
+	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
+	  wpas_dbus_getter_interfaces,
+	  NULL
+	},
+	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
+	  wpas_dbus_getter_eap_methods,
+	  NULL
+	},
+	{ "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+	  wpas_dbus_getter_global_capabilities,
+	  NULL
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
+	{ "InterfaceAdded", WPAS_DBUS_NEW_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "InterfaceRemoved", WPAS_DBUS_NEW_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "field", "s", ARG_OUT },
+		  { "text", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * 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
+ * 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;
+
+	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;
+	}
+
+	wpas_dbus_register(obj_desc, priv->global, NULL,
+			   wpas_dbus_global_methods,
+			   wpas_dbus_global_properties,
+			   wpas_dbus_global_signals);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register D-Bus object '%s'",
+		   WPAS_DBUS_NEW_PATH);
+	ret = wpa_dbus_ctrl_iface_init(priv, WPAS_DBUS_NEW_PATH,
+				       WPAS_DBUS_NEW_SERVICE,
+				       obj_desc);
+	if (ret < 0)
+		free_dbus_object_desc(obj_desc);
+	else
+		priv->dbus_new_initialized = 1;
+
+	return ret;
+}
+
+
+/**
+ * wpas_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface for
+ * wpa_supplicant
+ * @iface: 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)
+{
+	if (!iface->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);
+}
+
+
+static void wpa_dbus_free(void *ptr)
+{
+	os_free(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
+	},
+	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
+	  wpas_dbus_getter_enabled,
+	  wpas_dbus_setter_enabled
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_register_network - Register a configured network with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	struct network_handler_args *arg;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+#ifdef CONFIG_P2P
+	/*
+	 * If it is a persistent group register it as such.
+	 * This is to handle cases where an interface is being initialized
+	 * with a list of networks read from config.
+	 */
+	if (network_is_persistent_group(ssid))
+		return wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register network object '%s'",
+		   net_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct network_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	arg->ssid = ssid;
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_network_properties,
+			   wpas_dbus_network_signals);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, net_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpas_dbus_signal_network_added(wpa_s, ssid->id);
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_network - Unregister a configured network from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters network representing object from dbus
+ */
+int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int ret;
+#ifdef CONFIG_P2P
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_get_network(wpa_s->conf, nid);
+
+	/* If it is a persistent group unregister it as such */
+	if (ssid && network_is_persistent_group(ssid))
+		return wpas_dbus_unregister_persistent_group(wpa_s, nid);
+#endif /* CONFIG_P2P */
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->dbus_new_path, nid);
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister network object '%s'",
+		   net_obj_path);
+	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, net_obj_path);
+
+	if (!ret)
+		wpas_dbus_signal_network_removed(wpa_s, nid);
+
+	return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
+	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+	  wpas_dbus_getter_bss_ssid,
+	  NULL
+	},
+	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+	  wpas_dbus_getter_bss_bssid,
+	  NULL
+	},
+	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
+	  wpas_dbus_getter_bss_privacy,
+	  NULL
+	},
+	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
+	  wpas_dbus_getter_bss_mode,
+	  NULL
+	},
+	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
+	  wpas_dbus_getter_bss_signal,
+	  NULL
+	},
+	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
+	  wpas_dbus_getter_bss_frequency,
+	  NULL
+	},
+	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
+	  wpas_dbus_getter_bss_rates,
+	  NULL
+	},
+	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+	  wpas_dbus_getter_bss_wpa,
+	  NULL
+	},
+	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+	  wpas_dbus_getter_bss_rsn,
+	  NULL
+	},
+	{ "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+	  wpas_dbus_getter_bss_wps,
+	  NULL
+	},
+	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
+	  wpas_dbus_getter_bss_ies,
+	  NULL
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_unregister_bss - Unregister a scanned BSS from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @bssid: scanned network bssid
+ * @id: unique BSS identifier
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters BSS representing object from dbus
+ */
+int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+			     u8 bssid[ETH_ALEN], unsigned int id)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister BSS object '%s'",
+		   bss_obj_path);
+	if (wpa_dbus_unregister_object_per_iface(ctrl_iface, bss_obj_path)) {
+		wpa_printf(MSG_ERROR, "dbus: Cannot unregister BSS object %s",
+			   bss_obj_path);
+		return -1;
+	}
+
+	wpas_dbus_signal_bss_removed(wpa_s, bss_obj_path);
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
+
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_register_bss - Register a scanned BSS with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @bssid: scanned network bssid
+ * @id: unique BSS identifier
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers BSS representing object with dbus
+ */
+int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+			   u8 bssid[ETH_ALEN], unsigned int id)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	char bss_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	struct bss_handler_args *arg;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+		    wpa_s->dbus_new_path, id);
+
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	arg = os_zalloc(sizeof(struct bss_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for handler");
+		goto err;
+	}
+	arg->wpa_s = wpa_s;
+	arg->id = id;
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_bss_properties,
+			   wpas_dbus_bss_signals);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register BSS object '%s'",
+		   bss_obj_path);
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, bss_obj_path,
+					       wpa_s->ifname, obj_desc)) {
+		wpa_printf(MSG_ERROR,
+			   "Cannot register BSSID dbus object %s.",
+			   bss_obj_path);
+		goto err;
+	}
+
+	wpas_dbus_signal_bss_added(wpa_s, bss_obj_path);
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSSS);
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+
+static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
+	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+	  {
+		  { "path", "o", ARG_IN },
+		  { "field", "s", ARG_IN },
+		  { "value", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+	  {
+		  { "name", "s", ARG_IN },
+		  { "data", "ay", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+	  {
+		  { "name", "s", ARG_IN },
+		  { "data", "ay", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+	  {
+		  { "name", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#ifdef CONFIG_WPS
+	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "output", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+	  {
+		  { "timeout", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+	  {
+		  { "peer", "o", ARG_IN },
+		  { "config_method", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "generated_pin", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+	  {
+		  { "peer", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+	  {
+		  { "args", "t", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  {
+		  { "arg", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  {
+		  { "arg", "i", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
+	  {
+		  { "args", "a{sv}", ARG_IN },
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
+	  {
+		  { "path", "o", ARG_IN },
+		  END_ARGS
+	  }
+	},
+	{ "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  (WPADBusMethodHandler)
+	  wpas_dbus_handler_remove_all_persistent_groups,
+	  {
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_P2P */
+	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+	  {
+		  { "age", "u", ARG_IN },
+		  END_ARGS
+	  }
+	},
+#ifdef CONFIG_AP
+	{ "SubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_subscribe_preq,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "UnsubscribeProbeReq", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) wpas_dbus_handler_unsubscribe_preq,
+	  {
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_AP */
+	{ 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
+	},
+	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_state,
+	  NULL
+	},
+	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+	  wpas_dbus_getter_scanning,
+	  NULL
+	},
+	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_ap_scan,
+	  wpas_dbus_setter_ap_scan
+	},
+	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_bss_expire_age,
+	  wpas_dbus_setter_bss_expire_age
+	},
+	{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+	  wpas_dbus_getter_bss_expire_count,
+	  wpas_dbus_setter_bss_expire_count
+	},
+	{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_country,
+	  wpas_dbus_setter_country
+	},
+	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_ifname,
+	  NULL
+	},
+	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_driver,
+	  NULL
+	},
+	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_bridge_ifname,
+	  NULL
+	},
+	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
+	  wpas_dbus_getter_current_bss,
+	  NULL
+	},
+	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
+	  wpas_dbus_getter_current_network,
+	  NULL
+	},
+	{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+	  wpas_dbus_getter_current_auth_mode,
+	  NULL
+	},
+	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
+	  wpas_dbus_getter_blobs,
+	  NULL
+	},
+	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+	  wpas_dbus_getter_bsss,
+	  NULL
+	},
+	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+	  wpas_dbus_getter_networks,
+	  NULL
+	},
+	{ "FastReauth", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+	  wpas_dbus_getter_fast_reauth,
+	  wpas_dbus_setter_fast_reauth
+	},
+	{ "ScanInterval", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+	  wpas_dbus_getter_scan_interval,
+	  wpas_dbus_setter_scan_interval
+	},
+#ifdef CONFIG_WPS
+	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
+	  wpas_dbus_getter_process_credentials,
+	  wpas_dbus_setter_process_credentials
+	},
+#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
+	},
+	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+	  wpas_dbus_getter_p2p_peers,
+	  NULL
+	},
+	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
+	  wpas_dbus_getter_p2p_role,
+	  NULL
+	},
+	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+	  wpas_dbus_getter_p2p_group,
+	  NULL
+	},
+	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+	  wpas_dbus_getter_p2p_peergo,
+	  NULL
+	},
+	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+	  wpas_dbus_getter_persistent_groups,
+	  NULL
+	},
+#endif /* CONFIG_P2P */
+	{ "DisconnectReason", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+	  wpas_dbus_getter_disconnect_reason,
+	  NULL
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
+	{ "ScanDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "success", "b", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "BSSRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "BlobAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "BlobRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkSelected", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#ifdef CONFIG_WPS
+	{ "Event", WPAS_DBUS_NEW_IFACE_WPS,
+	  {
+		  { "name", "s", ARG_OUT },
+		  { "args", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "Credentials", WPAS_DBUS_NEW_IFACE_WPS,
+	  {
+		  { "credentials", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "states", "a{ss}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "DeviceFound", 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 },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "pin", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "pin", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "peer_object", "o", ARG_OUT },
+		  { "status", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "status", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "dev_passwd_id", "i", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "invite_result", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "ifname", "s", ARG_OUT },
+		  { "role", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "sd_request", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "sd_response", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "PersistentGroupRemoved", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+	  {
+		  { "name", "s", ARG_OUT },
+		  { "args", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+	{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "args", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+#endif /* CONFIG_AP */
+	{ "Certification", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "certification", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "EAP", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "status", "s", ARG_OUT },
+		  { "parameter", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+
+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;
+
+	/* Do nothing if the control interface is not turned on */
+	if (ctrl_iface == NULL)
+		return 0;
+
+	/* Create and set the interface's object path */
+	wpa_s->dbus_new_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+	if (wpa_s->dbus_new_path == NULL)
+		return -1;
+	next = ctrl_iface->next_objid++;
+	os_snprintf(wpa_s->dbus_new_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    WPAS_DBUS_NEW_PATH_INTERFACES "/%u",
+		    next);
+
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	wpas_dbus_register(obj_desc, wpa_s, NULL, wpas_dbus_interface_methods,
+			   wpas_dbus_interface_properties,
+			   wpas_dbus_interface_signals);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register interface object '%s'",
+		   wpa_s->dbus_new_path);
+	if (wpa_dbus_register_object_per_iface(ctrl_iface,
+					       wpa_s->dbus_new_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpas_dbus_signal_interface_added(wpa_s);
+
+	return 0;
+
+err:
+	os_free(wpa_s->dbus_new_path);
+	wpa_s->dbus_new_path = NULL;
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+
+int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
+		   wpa_s->dbus_new_path);
+
+#ifdef CONFIG_AP
+	if (wpa_s->preq_notify_peer) {
+		wpas_dbus_unsubscribe_noc(ctrl_iface);
+		os_free(wpa_s->preq_notify_peer);
+		wpa_s->preq_notify_peer = NULL;
+	}
+#endif /* CONFIG_AP */
+
+	if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
+						 wpa_s->dbus_new_path))
+		return -1;
+
+	wpas_dbus_signal_interface_removed(wpa_s);
+
+	os_free(wpa_s->dbus_new_path);
+	wpa_s->dbus_new_path = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_P2P
+
+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
+	},
+	{ "PrimaryDeviceType", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+	  wpas_dbus_getter_p2p_peer_primary_device_type,
+	  NULL
+	},
+	{ "config_method", WPAS_DBUS_NEW_IFACE_P2P_PEER, "q",
+	  wpas_dbus_getter_p2p_peer_config_method,
+	  NULL
+	},
+	{ "level", WPAS_DBUS_NEW_IFACE_P2P_PEER, "i",
+	  wpas_dbus_getter_p2p_peer_level,
+	  NULL
+	},
+	{ "devicecapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+	  wpas_dbus_getter_p2p_peer_device_capability,
+	  NULL
+	},
+	{ "groupcapability", WPAS_DBUS_NEW_IFACE_P2P_PEER, "y",
+	  wpas_dbus_getter_p2p_peer_group_capability,
+	  NULL
+	},
+	{ "SecondaryDeviceTypes", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+	  wpas_dbus_getter_p2p_peer_secondary_device_types,
+	  NULL
+	},
+	{ "VendorExtension", WPAS_DBUS_NEW_IFACE_P2P_PEER, "aay",
+	  wpas_dbus_getter_p2p_peer_vendor_extension,
+	  NULL
+	},
+	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+	  wpas_dbus_getter_p2p_peer_ies,
+	  NULL
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
+
+	{ NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_signal_peer - Send a peer related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ * @interface: name of the interface emitting this signal.
+ *	In case of peer objects, it would be emitted by either
+ *	the "interface object" or by "peer objects"
+ * @sig_name: signal name - DeviceFound
+ *
+ * Notify listeners about event related with newly found 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)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
+				      sig_name);
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+	path = peer_obj_path;
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+					    &path))
+		goto err;
+
+	dbus_connection_send(iface->con, msg, NULL);
+
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_peer_found - Send a peer found signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about find a p2p peer device found
+ */
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+					const u8 *dev_addr)
+{
+	wpas_dbus_signal_peer(wpa_s, dev_addr,
+			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+			      "DeviceFound");
+}
+
+/**
+ * wpas_dbus_signal_peer_lost - Send a peer lost signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about lost a p2p peer device
+ */
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+				       const u8 *dev_addr)
+{
+	wpas_dbus_signal_peer(wpa_s, dev_addr,
+			      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+			      "DeviceLost");
+}
+
+/**
+ * wpas_dbus_register_peer - Register a discovered peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	struct peer_handler_args *arg;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
+		   peer_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct peer_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
+			   NULL,
+			   wpas_dbus_p2p_peer_properties,
+			   wpas_dbus_p2p_peer_signals);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+/**
+ * wpas_dbus_unregister_peer - Unregister a peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @dev_addr: p2p device addr
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int ret;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL ||
+	    wpa_s->dbus_new_path == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+	wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
+		   peer_obj_path);
+	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
+
+	return ret;
+}
+
+
+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
+	},
+	{ "Group", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "o",
+	  wpas_dbus_getter_p2p_group,
+	  NULL
+	},
+	{ "Role", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+	  wpas_dbus_getter_p2p_role,
+	  NULL
+	},
+	{ "SSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+	  wpas_dbus_getter_p2p_group_ssid,
+	  NULL
+	},
+	{ "BSSID", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+	  wpas_dbus_getter_p2p_group_bssid,
+	  NULL
+	},
+	{ "Frequency", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "q",
+	  wpas_dbus_getter_p2p_group_frequency,
+	  NULL
+	},
+	{ "Passphrase", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "s",
+	  wpas_dbus_getter_p2p_group_passphrase,
+	  NULL
+	},
+	{ "PSK", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ay",
+	  wpas_dbus_getter_p2p_group_psk,
+	  NULL
+	},
+	{ "WPSVendorExtensions", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "aay",
+	  wpas_dbus_getter_p2p_group_vendor_ext,
+	  wpas_dbus_setter_p2p_group_vendor_ext
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
+	{ "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+	  {
+		  { "peer", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+	  {
+		  { "peer", "o", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: SSID struct
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers p2p group representing object with dbus
+ */
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (wpa_s->dbus_groupobj_path) {
+		wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
+			   __func__, wpa_s->dbus_groupobj_path);
+		return;
+	}
+
+	if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+		return;
+
+	wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
+	if (wpa_s->dbus_groupobj_path == NULL)
+		return;
+
+	wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
+		   group_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
+			   wpas_dbus_p2p_group_properties,
+			   wpas_dbus_p2p_group_signals);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	return;
+
+err:
+	if (wpa_s->dbus_groupobj_path) {
+		os_free(wpa_s->dbus_groupobj_path);
+		wpa_s->dbus_groupobj_path = NULL;
+	}
+
+	free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network name of the p2p group started
+ */
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+				    const struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Group object '%s' already unregistered",
+			   __func__, wpa_s->dbus_groupobj_path);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
+		   wpa_s->dbus_groupobj_path);
+
+	wpa_dbus_unregister_object_per_iface(ctrl_iface,
+					     wpa_s->dbus_groupobj_path);
+
+	os_free(wpa_s->dbus_groupobj_path);
+	wpa_s->dbus_groupobj_path = NULL;
+}
+
+static const struct wpa_dbus_property_desc
+wpas_dbus_p2p_groupmember_properties[] = {
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+/**
+ * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Registers p2p groupmember representing object with dbus
+ */
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					const u8 *p2p_if_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+	struct groupmember_handler_args *arg;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create object description");
+		goto err;
+	}
+
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct groupmember_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "Not enough memory "
+			   "to create arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_p2p_groupmember_properties, NULL);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpa_printf(MSG_INFO,
+		   "dbus: Registered group member object '%s' successfully",
+		   groupmember_obj_path);
+	return;
+
+err:
+	free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Unregisters p2p groupmember representing object with dbus
+ */
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					  const u8 *p2p_if_addr)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return;
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return;
+
+	if (!wpa_s->dbus_groupobj_path)
+		return;
+
+	os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		"%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+		wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+	wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
+}
+
+
+static const struct wpa_dbus_property_desc
+	wpas_dbus_persistent_group_properties[] = {
+	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
+	  wpas_dbus_getter_persistent_group_properties,
+	  wpas_dbus_setter_persistent_group_properties
+	},
+	{ NULL, NULL, NULL, NULL, NULL }
+};
+
+/* No signals intended for persistent group objects */
+
+/**
+ * wpas_dbus_register_persistent_group - Register a configured(saved)
+ *	persistent group with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: persistent group (still represented as a network within wpa)
+ *	  configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers a persistent group representing object with dbus.
+ */
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	struct wpa_dbus_object_desc *obj_desc;
+	struct network_handler_args *arg;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+
+	/* Make sure ssid is a persistent group */
+	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
+		return -1; /* should we return w/o complaining? */
+
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	/*
+	 * Intentionally not coming up with different numbering scheme
+	 * for persistent groups.
+	 */
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
+		   pgrp_obj_path);
+	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+			   "object description");
+		goto err;
+	}
+
+	/*
+	 * Reusing the same context structure as that for networks
+	 * since these are represented using same data structure.
+	 */
+	/* allocate memory for handlers arguments */
+	arg = os_zalloc(sizeof(struct network_handler_args));
+	if (!arg) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+			   "arguments for method");
+		goto err;
+	}
+
+	arg->wpa_s = wpa_s;
+	arg->ssid = ssid;
+
+	wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+			   wpas_dbus_persistent_group_properties,
+			   NULL);
+
+	if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
+					       wpa_s->ifname, obj_desc))
+		goto err;
+
+	wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
+
+	return 0;
+
+err:
+	free_dbus_object_desc(obj_desc);
+	return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
+ *	from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters persistent group representing object from dbus
+ *
+ * NOTE: There is a slight issue with the semantics here. While the
+ * implementation simply means the persistent group is unloaded from memory,
+ * it should not get interpreted as the group is actually being erased/removed
+ * from persistent storage as well.
+ */
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+					  int nid)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int ret;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL ||
+	    wpa_s->dbus_new_path == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+		    wpa_s->dbus_new_path, nid);
+
+	wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
+		   pgrp_obj_path);
+	ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
+
+	if (!ret)
+		wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
+
+	return ret;
+}
+
+#endif /* CONFIG_P2P */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,234 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_NEW_H
-#define CTRL_IFACE_DBUS_NEW_H
-
-struct wpa_global;
-struct wpa_supplicant;
-struct wpa_ssid;
-struct wps_event_m2d;
-struct wps_event_fail;
-struct wps_credential;
-enum wpa_states;
-
-enum wpas_dbus_prop {
-	WPAS_DBUS_PROP_AP_SCAN,
-	WPAS_DBUS_PROP_SCANNING,
-	WPAS_DBUS_PROP_STATE,
-	WPAS_DBUS_PROP_CURRENT_BSS,
-	WPAS_DBUS_PROP_CURRENT_NETWORK,
-};
-
-enum wpas_dbus_bss_prop {
-	WPAS_DBUS_BSS_PROP_SIGNAL,
-	WPAS_DBUS_BSS_PROP_FREQ,
-	WPAS_DBUS_BSS_PROP_MODE,
-	WPAS_DBUS_BSS_PROP_PRIVACY,
-	WPAS_DBUS_BSS_PROP_RATES,
-	WPAS_DBUS_BSS_PROP_WPA,
-	WPAS_DBUS_BSS_PROP_RSN,
-	WPAS_DBUS_BSS_PROP_IES,
-};
-
-#define WPAS_DBUS_OBJECT_PATH_MAX 150
-
-#define WPAS_DBUS_NEW_SERVICE		"fi.w1.wpa_supplicant1"
-#define WPAS_DBUS_NEW_PATH		"/fi/w1/wpa_supplicant1"
-#define WPAS_DBUS_NEW_INTERFACE		"fi.w1.wpa_supplicant1"
-
-#define WPAS_DBUS_NEW_PATH_INTERFACES	WPAS_DBUS_NEW_PATH "/Interfaces"
-#define WPAS_DBUS_NEW_IFACE_INTERFACE	WPAS_DBUS_NEW_INTERFACE ".Interface"
-#define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS"
-
-#define WPAS_DBUS_NEW_NETWORKS_PART "Networks"
-#define WPAS_DBUS_NEW_IFACE_NETWORK WPAS_DBUS_NEW_INTERFACE ".Network"
-
-#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
-#define WPAS_DBUS_NEW_IFACE_BSS	WPAS_DBUS_NEW_INTERFACE ".BSS"
-
-
-/* Errors */
-#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
-	WPAS_DBUS_NEW_INTERFACE ".UnknownError"
-#define WPAS_DBUS_ERROR_INVALID_ARGS \
-	WPAS_DBUS_NEW_INTERFACE ".InvalidArgs"
-
-#define WPAS_DBUS_ERROR_IFACE_EXISTS \
-	WPAS_DBUS_NEW_INTERFACE ".InterfaceExists"
-#define WPAS_DBUS_ERROR_IFACE_UNKNOWN \
-	WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown"
-
-#define WPAS_DBUS_ERROR_NOT_CONNECTED \
-	WPAS_DBUS_NEW_INTERFACE ".NotConnected"
-#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
-	WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
-
-#define WPAS_DBUS_ERROR_BLOB_EXISTS \
-	WPAS_DBUS_NEW_INTERFACE ".BlobExists"
-#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
-	WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
-
-
-#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-
-int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv);
-void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface);
-
-int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s);
-void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
-				   enum wpas_dbus_prop property);
-void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
-				       enum wpas_dbus_bss_prop property,
-				       unsigned int id);
-void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
-					      struct wpa_ssid *ssid);
-void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
-void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
-void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
-			       const struct wps_credential *cred);
-void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
-				    struct wps_event_m2d *m2d);
-void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
-				     struct wps_event_fail *fail);
-void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s);
-int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid);
-int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid);
-int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
-			     u8 bssid[ETH_ALEN], unsigned int id);
-int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
-			   u8 bssid[ETH_ALEN], unsigned int id);
-void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
-				 const char *name);
-void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
-				   const char *name);
-void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
-void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
-void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
-
-#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
-static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-#define wpas_dbus_signal_state_changed(w, n, o) do { } while (0)
-
-static inline void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
-						 enum wpas_dbus_prop property)
-{
-}
-
-static inline void wpas_dbus_bss_signal_prop_changed(
-	struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property,
-	unsigned int id)
-{
-}
-
-static inline void wpas_dbus_signal_network_enabled_changed(
-	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-}
-
-static inline void wpas_dbus_signal_network_selected(
-	struct wpa_supplicant *wpa_s, int id)
-{
-}
-
-static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
-					      int success)
-{
-}
-
-static inline void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
-					     const struct wps_credential *cred)
-{
-}
-
-static inline void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
-						  struct wps_event_m2d *m2d)
-{
-}
-
-static inline void wpas_dbus_signal_wps_event_fail(
-	struct wpa_supplicant *wpa_s, struct wps_event_fail *fail)
-{
-}
-
-static inline void wpas_dbus_signal_wps_event_success(
-	struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
-					     struct wpa_ssid *ssid)
-{
-	return 0;
-}
-
-static inline int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s,
-					       int nid)
-{
-	return 0;
-}
-
-static inline int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
-					   u8 bssid[ETH_ALEN], unsigned int id)
-{
-	return 0;
-}
-
-static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
-					 u8 bssid[ETH_ALEN], unsigned int id)
-{
-	return 0;
-}
-
-static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
-					       const char *name)
-{
-}
-
-static inline void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
-						 const char *name)
-{
-}
-
-static inline void wpas_dbus_signal_debug_level_changed(
-	struct wpa_global *global)
-{
-}
-
-static inline void wpas_dbus_signal_debug_timestamp_changed(
-	struct wpa_global *global)
-{
-}
-
-static inline void wpas_dbus_signal_debug_show_keys_changed(
-	struct wpa_global *global)
-{
-}
-
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
-#endif /* CTRL_IFACE_DBUS_H_NEW */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,498 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_NEW_H
+#define CTRL_IFACE_DBUS_NEW_H
+
+#include "common/defs.h"
+#include "p2p/p2p.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+struct wpa_ssid;
+struct wps_event_m2d;
+struct wps_event_fail;
+struct wps_credential;
+
+enum wpas_dbus_prop {
+	WPAS_DBUS_PROP_AP_SCAN,
+	WPAS_DBUS_PROP_SCANNING,
+	WPAS_DBUS_PROP_STATE,
+	WPAS_DBUS_PROP_CURRENT_BSS,
+	WPAS_DBUS_PROP_CURRENT_NETWORK,
+	WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
+	WPAS_DBUS_PROP_BSSS,
+	WPAS_DBUS_PROP_DISCONNECT_REASON,
+};
+
+enum wpas_dbus_bss_prop {
+	WPAS_DBUS_BSS_PROP_SIGNAL,
+	WPAS_DBUS_BSS_PROP_FREQ,
+	WPAS_DBUS_BSS_PROP_MODE,
+	WPAS_DBUS_BSS_PROP_PRIVACY,
+	WPAS_DBUS_BSS_PROP_RATES,
+	WPAS_DBUS_BSS_PROP_WPA,
+	WPAS_DBUS_BSS_PROP_RSN,
+	WPAS_DBUS_BSS_PROP_WPS,
+	WPAS_DBUS_BSS_PROP_IES,
+};
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+
+#define WPAS_DBUS_NEW_SERVICE		"fi.w1.wpa_supplicant1"
+#define WPAS_DBUS_NEW_PATH		"/fi/w1/wpa_supplicant1"
+#define WPAS_DBUS_NEW_INTERFACE		"fi.w1.wpa_supplicant1"
+
+#define WPAS_DBUS_NEW_PATH_INTERFACES	WPAS_DBUS_NEW_PATH "/Interfaces"
+#define WPAS_DBUS_NEW_IFACE_INTERFACE	WPAS_DBUS_NEW_INTERFACE ".Interface"
+#define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS"
+
+#define WPAS_DBUS_NEW_NETWORKS_PART "Networks"
+#define WPAS_DBUS_NEW_IFACE_NETWORK WPAS_DBUS_NEW_INTERFACE ".Network"
+
+#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
+#define WPAS_DBUS_NEW_IFACE_BSS	WPAS_DBUS_NEW_INTERFACE ".BSS"
+
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE	\
+		WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART	"Groups"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+	WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART	"Peers"
+#define	WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART	"Members"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+	WPAS_DBUS_NEW_INTERFACE ".GroupMember"
+
+/* Errors */
+#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
+	WPAS_DBUS_NEW_INTERFACE ".UnknownError"
+#define WPAS_DBUS_ERROR_INVALID_ARGS \
+	WPAS_DBUS_NEW_INTERFACE ".InvalidArgs"
+
+#define WPAS_DBUS_ERROR_IFACE_EXISTS \
+	WPAS_DBUS_NEW_INTERFACE ".InterfaceExists"
+#define WPAS_DBUS_ERROR_IFACE_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown"
+
+#define WPAS_DBUS_ERROR_NOT_CONNECTED \
+	WPAS_DBUS_NEW_INTERFACE ".NotConnected"
+#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
+
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
+#define WPAS_DBUS_ERROR_BLOB_EXISTS \
+	WPAS_DBUS_NEW_INTERFACE ".BlobExists"
+#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
+
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
+	WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
+#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
+	WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
+	WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
+
+
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+
+int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv);
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface);
+
+int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s);
+void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				   enum wpas_dbus_prop property);
+void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				       enum wpas_dbus_bss_prop property,
+				       unsigned int id);
+void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid);
+void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid,
+				      enum wpa_ctrl_req_type rtype,
+				      const char *default_text);
+void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
+void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
+			       const struct wps_credential *cred);
+void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
+				    struct wps_event_m2d *m2d);
+void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail);
+void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s);
+int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid);
+int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid);
+int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+			     u8 bssid[ETH_ALEN], unsigned int id);
+int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+			   u8 bssid[ETH_ALEN], unsigned int id);
+void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
+				 const char *name);
+void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
+				   const char *name);
+void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
+void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
+void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
+
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+					const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					      const u8 *dev_addr, int request,
+					      enum p2p_prov_disc_status status,
+					      u16 config_methods,
+					      unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				     const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+				    const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+					  int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+					    int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					  const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+					    const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				     int freq, const u8 *sa, u8 dialog_token,
+				     u16 update_indic, const u8 *tlvs,
+				     size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				      const u8 *sa, u16 update_indic,
+				      const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail);
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+				    int depth, const char *subject,
+				    const char *cert_hash,
+				    const struct wpabuf *cert);
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+			   const u8 *addr, const u8 *dst, const u8 *bssid,
+			   const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+				 const char *status, const char *parameter);
+
+#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+#define wpas_dbus_signal_state_changed(w, n, o) do { } while (0)
+
+static inline void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+						 enum wpas_dbus_prop property)
+{
+}
+
+static inline void wpas_dbus_bss_signal_prop_changed(
+	struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property,
+	unsigned int id)
+{
+}
+
+static inline void wpas_dbus_signal_network_enabled_changed(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_network_selected(
+	struct wpa_supplicant *wpa_s, int id)
+{
+}
+
+static inline void wpas_dbus_signal_network_request(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+}
+
+static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
+					      int success)
+{
+}
+
+static inline void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
+					     const struct wps_credential *cred)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
+						  struct wps_event_m2d *m2d)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_fail(
+	struct wpa_supplicant *wpa_s, struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_success(
+	struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+					     struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s,
+					       int nid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+					   u8 bssid[ETH_ALEN], unsigned int id)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+					 u8 bssid[ETH_ALEN], unsigned int id)
+{
+	return 0;
+}
+
+static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
+					       const char *name)
+{
+}
+
+static inline void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
+						 const char *name)
+{
+}
+
+static inline void wpas_dbus_signal_debug_level_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline void wpas_dbus_signal_debug_timestamp_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline void wpas_dbus_signal_debug_show_keys_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+					    const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+				struct wpa_supplicant *wpa_s,
+				const u8 *src,
+				u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+	struct wpa_supplicant *wpa_s, int nid)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				 struct p2p_go_neg_results *res)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+			       const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+				struct wpa_supplicant *wpa_s, int status,
+				const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				   const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+				const u8 *sa, u8 dialog_token, u16 update_indic,
+				const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				     const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				 const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+				   const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+				       const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+						  int depth,
+						  const char *subject,
+						  const char *cert_hash,
+						  const struct wpabuf *cert)
+{
+}
+
+static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+					 const u8 *addr, const u8 *dst,
+					 const u8 *bssid,
+					 const u8 *ie, size_t ie_len,
+					 u32 ssi_signal)
+{
+}
+
+static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+					       const char *status,
+					       const char *parameter)
+{
+}
+
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#endif /* CTRL_IFACE_DBUS_H_NEW */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2957 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "common/ieee802_11_defs.h"
-#include "eap_peer/eap_methods.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../driver_i.h"
-#include "../notify.h"
-#include "../wpas_glue.h"
-#include "../bss.h"
-#include "../scan.h"
-#include "dbus_new_helpers.h"
-#include "dbus_new.h"
-#include "dbus_new_handlers.h"
-#include "dbus_dict_helpers.h"
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-static const char *debug_strings[] = {
-	"msgdump", "debug", "info", "warning", "error", NULL
-};
-
-
-/**
- * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
-						  char **network,
-						  char **bssid)
-{
-	const unsigned int dev_path_prefix_len =
-		strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
-	char *obj_path_only;
-	char *next_sep;
-
-	/* Be a bit paranoid about path */
-	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-				dev_path_prefix_len))
-		return NULL;
-
-	/* Ensure there's something at the end of the path */
-	if ((path + dev_path_prefix_len)[0] == '\0')
-		return NULL;
-
-	obj_path_only = os_strdup(path);
-	if (obj_path_only == NULL)
-		return NULL;
-
-	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-	if (next_sep != NULL) {
-		const char *net_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
-		const char *bssid_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
-		if (network && net_part) {
-			/* Deal with a request for a configured network */
-			const char *net_name = net_part +
-				os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
-			*network = NULL;
-			if (os_strlen(net_name))
-				*network = os_strdup(net_name);
-		} else if (bssid && bssid_part) {
-			/* Deal with a request for a scanned BSSID */
-			const char *bssid_name = bssid_part +
-				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-			if (strlen(bssid_name))
-				*bssid = os_strdup(bssid_name);
-			else
-				*bssid = NULL;
-		}
-
-		/* Cut off interface object path before "/" */
-		*next_sep = '\0';
-	}
-
-	return obj_path_only;
-}
-
-
-/**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
- * @message: Pointer to incoming dbus message this error refers to
- * @arg: Optional string appended to error message
- * Returns: a dbus error message
- *
- * Convenience function to create and return an UnknownError
- */
-DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
-					    const char *arg)
-{
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
-				      arg);
-}
-
-
-/**
- * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: A dbus error message
- *
- * Convenience function to create and return an invalid interface error
- */
-static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
-{
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
-}
-
-
-/**
- * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid network error
- */
-static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
-{
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
-				      "There is no such a network in this "
-				      "interface.");
-}
-
-
-/**
- * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid options error
- */
-DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
-					  const char *arg)
-{
-	DBusMessage *reply;
-
-	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
-				       "Did not receive correct message "
-				       "arguments.");
-	if (arg != NULL)
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
-					 DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
-
-static const char *dont_quote[] = {
-	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
-	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-	"bssid", NULL
-};
-
-static dbus_bool_t should_quote_opt(const char *key)
-{
-	int i = 0;
-	while (dont_quote[i] != NULL) {
-		if (os_strcmp(key, dont_quote[i]) == 0)
-			return FALSE;
-		i++;
-	}
-	return TRUE;
-}
-
-/**
- * get_iface_by_dbus_path - Get a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @path: Pointer to a dbus object path representing an interface
- * Returns: Pointer to the interface or %NULL if not found
- */
-static struct wpa_supplicant * get_iface_by_dbus_path(
-	struct wpa_global *global, const char *path)
-{
-	struct wpa_supplicant *wpa_s;
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		if (os_strcmp(wpa_s->dbus_new_path, path) == 0)
-			return wpa_s;
-	}
-	return NULL;
-}
-
-
-/**
- * set_network_properties - Set properties of a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * @iter: DBus message iterator containing dictionary of network
- * properties to set.
- * Returns: NULL when succeed or DBus error on failure
- *
- * Sets network configuration with parameters given id DBus dictionary
- */
-static DBusMessage * set_network_properties(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s,
-					    struct wpa_ssid *ssid,
-					    DBusMessageIter *iter)
-{
-
-	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter_dict;
-
-	if (!wpa_dbus_dict_open_read(iter, &iter_dict))
-		return wpas_dbus_error_invalid_args(message, NULL);
-
-	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		char *value = NULL;
-		size_t size = 50;
-		int ret;
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-			reply = wpas_dbus_error_invalid_args(message, NULL);
-			break;
-		}
-		if (entry.type == DBUS_TYPE_ARRAY &&
-		    entry.array_type == DBUS_TYPE_BYTE) {
-			if (entry.array_len <= 0)
-				goto error;
-
-			size = entry.array_len * 2 + 1;
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-
-			ret = wpa_snprintf_hex(value, size,
-					       (u8 *) entry.bytearray_value,
-					       entry.array_len);
-			if (ret <= 0)
-				goto error;
-		} else if (entry.type == DBUS_TYPE_STRING) {
-			if (should_quote_opt(entry.key)) {
-				size = os_strlen(entry.str_value);
-				if (size <= 0)
-					goto error;
-
-				size += 3;
-				value = os_zalloc(size);
-				if (value == NULL)
-					goto error;
-
-				ret = os_snprintf(value, size, "\"%s\"",
-						  entry.str_value);
-				if (ret < 0 || (size_t) ret != (size - 1))
-					goto error;
-			} else {
-				value = os_strdup(entry.str_value);
-				if (value == NULL)
-					goto error;
-			}
-		} else if (entry.type == DBUS_TYPE_UINT32) {
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-
-			ret = os_snprintf(value, size, "%u",
-					  entry.uint32_value);
-			if (ret <= 0)
-				goto error;
-		} else if (entry.type == DBUS_TYPE_INT32) {
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-
-			ret = os_snprintf(value, size, "%d",
-					  entry.int32_value);
-			if (ret <= 0)
-				goto error;
-		} else
-			goto error;
-
-		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
-			goto error;
-
-		if ((os_strcmp(entry.key, "psk") == 0 &&
-		     value[0] == '"' && ssid->ssid_len) ||
-		    (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
-			wpa_config_update_psk(ssid);
-		else if (os_strcmp(entry.key, "priority") == 0)
-			wpa_config_update_prio_list(wpa_s->conf);
-
-		os_free(value);
-		wpa_dbus_dict_entry_clear(&entry);
-		continue;
-
-	error:
-		os_free(value);
-		reply = wpas_dbus_error_invalid_args(message, entry.key);
-		wpa_dbus_dict_entry_clear(&entry);
-		break;
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_simple_property_getter - Get basic type property
- * @message: Pointer to incoming dbus message
- * @type: DBus type of property (must be basic type)
- * @val: pointer to place holding property value
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
- *
- * Generic getter for basic type properties. Type is required to be basic.
- */
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-					       const int type, const void *val)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter;
-
-	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-			   " given type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-
-	if (reply != NULL) {
-		dbus_message_iter_init_append(reply, &iter);
-		if (!dbus_message_iter_open_container(
-			    &iter, DBUS_TYPE_VARIANT,
-			    wpa_dbus_type_as_string(type), &variant_iter) ||
-		    !dbus_message_iter_append_basic(&variant_iter, type,
-						    val) ||
-		    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-			wpa_printf(MSG_ERROR, "dbus: "
-				   "wpas_dbus_simple_property_getter: out of "
-				   "memory to put property value into "
-				   "message");
-			dbus_message_unref(reply);
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
-		}
-	} else {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-			   " out of memory to return property value");
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_simple_property_setter - Set basic type property
- * @message: Pointer to incoming dbus message
- * @type: DBus type of property (must be basic type)
- * @val: pointer to place where value being set will be stored
- * Returns: NULL or DBus error message if error occurred.
- *
- * Generic setter for basic type properties. Type is required to be basic.
- */
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-					       const int type, void *val)
-{
-	DBusMessageIter iter, variant_iter;
-
-	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-			   " given type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	if (!dbus_message_iter_init(message, &iter)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-			   " out of memory to return scanning state");
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	/* omit first and second argument and get value from third */
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
-	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
-		wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:"
-			   " wrong property type");
-		return wpas_dbus_error_invalid_args(message,
-						    "wrong property type");
-	}
-	dbus_message_iter_get_basic(&variant_iter, val);
-
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_simple_array_property_getter - Get array type property
- * @message: Pointer to incoming dbus message
- * @type: DBus type of property array elements (must be basic type)
- * @array: pointer to array of elements to put into response message
- * @array_len: length of above array
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
- *
- * Generic getter for array type properties. Array elements type is
- * required to be basic.
- */
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-						     const int type,
-						     const void *array,
-						     size_t array_len)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, array_iter;
-	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
-	const char *sub_type_str;
-	size_t element_size, i;
-
-	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: given "
-			   "type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	sub_type_str = wpa_dbus_type_as_string(type);
-	type_str[1] = sub_type_str[0];
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (reply == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to create return message");
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter) ||
-	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
-					      sub_type_str, &array_iter)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to open container");
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	switch(type) {
-	case DBUS_TYPE_BYTE:
-	case DBUS_TYPE_BOOLEAN:
-		element_size = 1;
-		break;
-	case DBUS_TYPE_INT16:
-	case DBUS_TYPE_UINT16:
-		element_size = sizeof(uint16_t);
-		break;
-	case DBUS_TYPE_INT32:
-	case DBUS_TYPE_UINT32:
-		element_size = sizeof(uint32_t);
-		break;
-	case DBUS_TYPE_INT64:
-	case DBUS_TYPE_UINT64:
-		element_size = sizeof(uint64_t);
-		break;
-	case DBUS_TYPE_DOUBLE:
-		element_size = sizeof(double);
-		break;
-	case DBUS_TYPE_STRING:
-	case DBUS_TYPE_OBJECT_PATH:
-		element_size = sizeof(char *);
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: "
-			   "fatal: unknown element type");
-		element_size = 1;
-		break;
-	}
-
-	for (i = 0; i < array_len; i++) {
-		dbus_message_iter_append_basic(&array_iter, type,
-					       array + i * element_size);
-	}
-
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to close container");
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_create_interface - Request registration of a network iface
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the new interface object,
- *          or a dbus error message with more information
- *
- * Handler function for "CreateInterface" method call. Handles requests
- * by dbus clients to register a network interface that wpa_supplicant
- * will manage.
- */
-DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
-						 struct wpa_global *global)
-{
-	DBusMessageIter iter_dict;
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter;
-	struct wpa_dbus_dict_entry entry;
-	char *driver = NULL;
-	char *ifname = NULL;
-	char *bridge_ifname = NULL;
-
-	dbus_message_iter_init(message, &iter);
-
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
-		goto error;
-	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-			goto error;
-		if (!strcmp(entry.key, "Driver") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			driver = os_strdup(entry.str_value);
-			wpa_dbus_dict_entry_clear(&entry);
-			if (driver == NULL)
-				goto error;
-		} else if (!strcmp(entry.key, "Ifname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			ifname = os_strdup(entry.str_value);
-			wpa_dbus_dict_entry_clear(&entry);
-			if (ifname == NULL)
-				goto error;
-		} else if (!strcmp(entry.key, "BridgeIfname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			bridge_ifname = os_strdup(entry.str_value);
-			wpa_dbus_dict_entry_clear(&entry);
-			if (bridge_ifname == NULL)
-				goto error;
-		} else {
-			wpa_dbus_dict_entry_clear(&entry);
-			goto error;
-		}
-	}
-
-	if (ifname == NULL)
-		goto error; /* Required Ifname argument missing */
-
-	/*
-	 * Try to get the wpa_supplicant record for this iface, return
-	 * an error if we already control it.
-	 */
-	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_DBUS_ERROR_IFACE_EXISTS,
-					       "wpa_supplicant already "
-					       "controls this interface.");
-	} else {
-		struct wpa_supplicant *wpa_s;
-		struct wpa_interface iface;
-		os_memset(&iface, 0, sizeof(iface));
-		iface.driver = driver;
-		iface.ifname = ifname;
-		iface.bridge_ifname = bridge_ifname;
-		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
-			const char *path = wpa_s->dbus_new_path;
-			reply = dbus_message_new_method_return(message);
-			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
-		} else {
-			reply = wpas_dbus_error_unknown_error(
-				message, "wpa_supplicant couldn't grab this "
-				"interface.");
-		}
-	}
-
-out:
-	os_free(driver);
-	os_free(ifname);
-	os_free(bridge_ifname);
-	return reply;
-
-error:
-	reply = wpas_dbus_error_invalid_args(message, NULL);
-	goto out;
-}
-
-
-/**
- * wpas_dbus_handler_remove_interface - Request deregistration of an interface
- * @message: Pointer to incoming dbus message
- * @global: wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- *          failure (0), or returns a dbus error message with more information
- *
- * Handler function for "removeInterface" method call.  Handles requests
- * by dbus clients to deregister a network interface that wpa_supplicant
- * currently manages.
- */
-DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
-						 struct wpa_global *global)
-{
-	struct wpa_supplicant *wpa_s;
-	char *path;
-	DBusMessage *reply = NULL;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-			      DBUS_TYPE_INVALID);
-
-	wpa_s = get_iface_by_dbus_path(global, path);
-	if (wpa_s == NULL)
-		reply = wpas_dbus_error_iface_unknown(message);
-	else if (wpa_supplicant_remove_iface(global, wpa_s)) {
-		reply = wpas_dbus_error_unknown_error(
-			message, "wpa_supplicant couldn't remove this "
-			"interface.");
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_get_interface - Get the object path for an interface name
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the interface object,
- *          or a dbus error message with more information
- *
- * Handler function for "getInterface" method call.
- */
-DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
-					      struct wpa_global *global)
-{
-	DBusMessage *reply = NULL;
-	const char *ifname;
-	const char *path;
-	struct wpa_supplicant *wpa_s;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
-			      DBUS_TYPE_INVALID);
-
-	wpa_s = wpa_supplicant_get_iface(global, ifname);
-	if (wpa_s == NULL)
-		return wpas_dbus_error_iface_unknown(message);
-
-	path = wpa_s->dbus_new_path;
-	reply = dbus_message_new_method_return(message);
-	if (reply == NULL)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
-				      DBUS_TYPE_INVALID)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_debug_level - Get debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug level
- *
- * Getter for "DebugLevel" property.
- */
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-					   struct wpa_global *global)
-{
-	const char *str;
-	int idx = wpa_debug_level;
-	if (idx < 0)
-		idx = 0;
-	if (idx > 4)
-		idx = 4;
-	str = debug_strings[idx];
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&str);
-}
-
-
-/**
- * wpas_dbus_getter_debug_timestamp - Get debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug timestamp
- *
- * Getter for "DebugTimestamp" property.
- */
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global)
-{
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&wpa_debug_timestamp);
-
-}
-
-
-/**
- * wpas_dbus_getter_debug_show_keys - Get debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug show_keys
- *
- * Getter for "DebugShowKeys" property.
- */
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global)
-{
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&wpa_debug_show_keys);
-
-}
-
-/**
- * wpas_dbus_setter_debug_level - Set debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
- *
- * Setter for "DebugLevel" property.
- */
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-					   struct wpa_global *global)
-{
-	DBusMessage *reply;
-	const char *str = NULL;
-	int i, val = -1;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING,
-						 &str);
-	if (reply)
-		return reply;
-
-	for (i = 0; debug_strings[i]; i++)
-		if (os_strcmp(debug_strings[i], str) == 0) {
-			val = i;
-			break;
-		}
-
-	if (val < 0 ||
-	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
-					    wpa_debug_show_keys)) {
-		dbus_message_unref(reply);
-		return wpas_dbus_error_invalid_args(
-			message, "Wrong debug level value");
-	}
-
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_setter_debug_timestamp - Set debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
- *
- * Setter for "DebugTimestamp" property.
- */
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global)
-{
-	DBusMessage *reply;
-	dbus_bool_t val;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &val);
-	if (reply)
-		return reply;
-
-	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
-					wpa_debug_show_keys);
-
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_setter_debug_show_keys - Set debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
- *
- * Setter for "DebugShowKeys" property.
- */
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global)
-{
-	DBusMessage *reply;
-	dbus_bool_t val;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &val);
-	if (reply)
-		return reply;
-
-	wpa_supplicant_set_debug_params(global, wpa_debug_level,
-					wpa_debug_timestamp,
-					val ? 1 : 0);
-
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_getter_interfaces - Request registered interfaces list
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object paths array containing registered interfaces
- * objects paths or DBus error on failure
- *
- * Getter for "Interfaces" property. Handles requests
- * by dbus clients to return list of registered interfaces objects
- * paths
- */
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-					  struct wpa_global *global)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_supplicant *wpa_s;
-	const char **paths;
-	unsigned int i = 0, num = 0;
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-		num++;
-
-	paths = os_zalloc(num * sizeof(char*));
-	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-		paths[i] = wpa_s->dbus_new_path;
-
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num);
-
-	os_free(paths);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_eap_methods - Request supported EAP methods list
- * @message: Pointer to incoming dbus message
- * @nothing: not used argument. may be NULL or anything else
- * Returns: The object paths array containing supported EAP methods
- * represented by strings or DBus error on failure
- *
- * Getter for "EapMethods" property. Handles requests
- * by dbus clients to return list of strings with supported EAP methods
- */
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing)
-{
-	DBusMessage *reply = NULL;
-	char **eap_methods;
-	size_t num_items = 0;
-
-	eap_methods = eap_get_names_as_string_array(&num_items);
-	if (!eap_methods) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_STRING,
-						       eap_methods, num_items);
-
-	while (num_items)
-		os_free(eap_methods[--num_items]);
-	os_free(eap_methods);
-	return reply;
-}
-
-
-static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
-				   char **type, DBusMessage **reply)
-{
-	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Type must be a string");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Type value type. String required");
-		return -1;
-	}
-	dbus_message_iter_get_basic(var, type);
-	return 0;
-}
-
-
-static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
-				    struct wpa_driver_scan_params *params,
-				    DBusMessage **reply)
-{
-	struct wpa_driver_scan_ssid *ssids = params->ssids;
-	size_t ssids_num = 0;
-	u8 *ssid;
-	DBusMessageIter array_iter, sub_array_iter;
-	char *val;
-	int len;
-
-	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
-		return -1;
-	}
-
-	dbus_message_iter_recurse(var, &array_iter);
-
-	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
-		return -1;
-	}
-
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
-		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Too many ssids specified on scan dbus "
-				   "call");
-			*reply = wpas_dbus_error_invalid_args(
-				message, "Too many ssids specified. Specify "
-				"at most four");
-			return -1;
-		}
-
-		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
-
-		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
-		if (len == 0) {
-			dbus_message_iter_next(&array_iter);
-			continue;
-		}
-
-		ssid = os_malloc(len);
-		if (ssid == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. Cannot allocate memory for "
-				   "SSID");
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
-			return -1;
-		}
-		os_memcpy(ssid, val, len);
-		ssids[ssids_num].ssid = ssid;
-		ssids[ssids_num].ssid_len = len;
-
-		dbus_message_iter_next(&array_iter);
-		ssids_num++;
-	}
-
-	params->num_ssids = ssids_num;
-	return 0;
-}
-
-
-static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
-				  struct wpa_driver_scan_params *params,
-				  DBusMessage **reply)
-{
-	u8 *ies = NULL, *nies;
-	int ies_len = 0;
-	DBusMessageIter array_iter, sub_array_iter;
-	char *val;
-	int len;
-
-	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong IEs value type. Array of arrays of "
-			"bytes required");
-		return -1;
-	}
-
-	dbus_message_iter_recurse(var, &array_iter);
-
-	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong IEs value type. Array required");
-		return -1;
-	}
-
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
-		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
-
-		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
-		if (len == 0) {
-			dbus_message_iter_next(&array_iter);
-			continue;
-		}
-
-		nies = os_realloc(ies, ies_len + len);
-		if (nies == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. Cannot allocate memory for "
-				   "IE");
-			os_free(ies);
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
-			return -1;
-		}
-		ies = nies;
-		os_memcpy(ies + ies_len, val, len);
-		ies_len += len;
-
-		dbus_message_iter_next(&array_iter);
-	}
-
-	params->extra_ies = ies;
-	params->extra_ies_len = ies_len;
-	return 0;
-}
-
-
-static int wpas_dbus_get_scan_channels(DBusMessage *message,
-				       DBusMessageIter *var,
-				       struct wpa_driver_scan_params *params,
-				       DBusMessage **reply)
-{
-	DBusMessageIter array_iter, sub_array_iter;
-	int *freqs = NULL, *nfreqs;
-	int freqs_num = 0;
-
-	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Channels must be an array of structs");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
-		return -1;
-	}
-
-	dbus_message_iter_recurse(var, &array_iter);
-
-	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
-		wpa_printf(MSG_DEBUG,
-			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
-			   "array of structs");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
-		return -1;
-	}
-
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
-	{
-		int freq, width;
-
-		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
-
-		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
-		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s %c",
-				   dbus_message_iter_get_arg_type(
-					   &sub_array_iter));
-			*reply = wpas_dbus_error_invalid_args(
-				message, "Wrong Channel struct. Two UINT32s "
-				"required");
-			os_free(freqs);
-			return -1;
-		}
-		dbus_message_iter_get_basic(&sub_array_iter, &freq);
-
-		if (!dbus_message_iter_next(&sub_array_iter) ||
-		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
-		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s");
-			*reply = wpas_dbus_error_invalid_args(
-				message,
-				"Wrong Channel struct. Two UINT32s required");
-			os_free(freqs);
-			return -1;
-		}
-
-		dbus_message_iter_get_basic(&sub_array_iter, &width);
-
-#define FREQS_ALLOC_CHUNK 32
-		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
-			nfreqs = os_realloc(freqs, sizeof(int) *
-					    (freqs_num + FREQS_ALLOC_CHUNK));
-			if (nfreqs == NULL)
-				os_free(freqs);
-			freqs = nfreqs;
-		}
-		if (freqs == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. can't allocate memory for "
-				   "freqs");
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
-			return -1;
-		}
-
-		freqs[freqs_num] = freq;
-
-		freqs_num++;
-		dbus_message_iter_next(&array_iter);
-	}
-
-	nfreqs = os_realloc(freqs,
-			    sizeof(int) * (freqs_num + 1));
-	if (nfreqs == NULL)
-		os_free(freqs);
-	freqs = nfreqs;
-	if (freqs == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "out of memory. Can't allocate memory for freqs");
-		*reply = dbus_message_new_error(
-			message, DBUS_ERROR_NO_MEMORY, NULL);
-		return -1;
-	}
-	freqs[freqs_num] = 0;
-
-	params->freqs = freqs;
-	return 0;
-}
-
-
-/**
- * wpas_dbus_handler_scan - Request a wireless scan on an interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL indicating success or DBus error message on failure
- *
- * Handler function for "Scan" method call of a network device. Requests
- * that wpa_supplicant perform a wireless scan as soon as possible
- * on a particular wireless interface.
- */
-DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
-	char *key = NULL, *type = NULL;
-	struct wpa_driver_scan_params params;
-	size_t i;
-
-	os_memset(&params, 0, sizeof(params));
-
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_recurse(&iter, &dict_iter);
-
-	while (dbus_message_iter_get_arg_type(&dict_iter) ==
-			DBUS_TYPE_DICT_ENTRY) {
-		dbus_message_iter_recurse(&dict_iter, &entry_iter);
-		dbus_message_iter_get_basic(&entry_iter, &key);
-		dbus_message_iter_next(&entry_iter);
-		dbus_message_iter_recurse(&entry_iter, &variant_iter);
-
-		if (os_strcmp(key, "Type") == 0) {
-			if (wpas_dbus_get_scan_type(message, &variant_iter,
-						    &type, &reply) < 0)
-				goto out;
-		} else if (os_strcmp(key, "SSIDs") == 0) {
-			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
-						     &params, &reply) < 0)
-				goto out;
-		} else if (os_strcmp(key, "IEs") == 0) {
-			if (wpas_dbus_get_scan_ies(message, &variant_iter,
-						   &params, &reply) < 0)
-				goto out;
-		} else if (os_strcmp(key, "Channels") == 0) {
-			if (wpas_dbus_get_scan_channels(message, &variant_iter,
-							&params, &reply) < 0)
-				goto out;
-		} else {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Unknown argument %s", key);
-			reply = wpas_dbus_error_invalid_args(message, key);
-			goto out;
-		}
-
-		dbus_message_iter_next(&dict_iter);
-	}
-
-	if (!type) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Scan type not specified");
-		reply = wpas_dbus_error_invalid_args(message, key);
-		goto out;
-	}
-
-	if (!os_strcmp(type, "passive")) {
-		if (params.num_ssids || params.extra_ies_len) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "SSIDs or IEs specified for passive scan.");
-			reply = wpas_dbus_error_invalid_args(
-				message, "You can specify only Channels in "
-				"passive scan");
-			goto out;
-		} else if (params.freqs && params.freqs[0]) {
-			/* wildcard ssid */
-			params.num_ssids++;
-			wpa_supplicant_trigger_scan(wpa_s, &params);
-		} else {
-			wpa_s->scan_req = 2;
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-		}
-	} else if (!os_strcmp(type, "active")) {
-		wpa_supplicant_trigger_scan(wpa_s, &params);
-	} else {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Unknown scan type: %s", type);
-		reply = wpas_dbus_error_invalid_args(message,
-						     "Wrong scan type");
-		goto out;
-	}
-
-out:
-	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
-		os_free((u8 *) params.ssids[i].ssid);
-	os_free((u8 *) params.extra_ies);
-	os_free(params.freqs);
-	return reply;
-}
-
-
-/*
- * wpas_dbus_handler_disconnect - Terminate the current connection
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NotConnected DBus error message if already not connected
- * or NULL otherwise.
- *
- * Handler function for "Disconnect" method call of network interface.
- */
-DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->current_ssid != NULL) {
-		wpa_s->disconnected = 1;
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-
-		return NULL;
-	}
-
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
-				      "This interface is not connected");
-}
-
-
-/**
- * wpas_dbus_new_iface_add_network - Add a new configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing the object path of the new network
- *
- * Handler function for "AddNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter;
-	struct wpa_ssid *ssid = NULL;
-	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
-
-	dbus_message_iter_init(message, &iter);
-
-	ssid = wpa_config_add_network(wpa_s->conf);
-	if (ssid == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
-			   "can't add new interface.");
-		reply = wpas_dbus_error_unknown_error(
-			message,
-			"wpa_supplicant could not add "
-			"a network on this interface.");
-		goto err;
-	}
-	wpas_notify_network_added(wpa_s, ssid);
-	ssid->disabled = 1;
-	wpa_config_set_network_defaults(ssid);
-
-	reply = set_network_properties(message, wpa_s, ssid, &iter);
-	if (reply) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
-			   "control interface couldn't set network "
-			   "properties");
-		goto err;
-	}
-
-	/* Construct the object path for this network. */
-	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
-		    wpa_s->dbus_new_path, ssid->id);
-
-	reply = dbus_message_new_method_return(message);
-	if (reply == NULL) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
-	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
-				      DBUS_TYPE_INVALID)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
-
-	return reply;
-
-err:
-	if (ssid) {
-		wpas_notify_network_removed(wpa_s, ssid);
-		wpa_config_remove_network(wpa_s->conf, ssid->id);
-	}
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_remove_network - Remove a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL on success or dbus error on failure
- *
- * Handler function for "RemoveNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *op;
-	char *iface = NULL, *net_id = NULL;
-	int id;
-	struct wpa_ssid *ssid;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
-			      DBUS_TYPE_INVALID);
-
-	/* Extract the network ID and ensure the network */
-	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
-		reply = wpas_dbus_error_invalid_args(message, op);
-		goto out;
-	}
-
-	id = strtoul(net_id, NULL, 10);
-	if (errno == EINVAL) {
-		reply = wpas_dbus_error_invalid_args(message, op);
-		goto out;
-	}
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		reply = wpas_dbus_error_network_unknown(message);
-		goto out;
-	}
-
-	wpas_notify_network_removed(wpa_s, ssid);
-
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_handler_remove_network[dbus]: "
-			   "error occurred when removing network %d", id);
-		reply = wpas_dbus_error_unknown_error(
-			message, "error removing the specified network on "
-			"this interface.");
-		goto out;
-	}
-
-	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-
-out:
-	os_free(iface);
-	os_free(net_id);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_select_network - Attempt association with a network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL on success or dbus error on failure
- *
- * Handler function for "SelectNetwork" method call of network interface.
- */
-DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *op;
-	char *iface = NULL, *net_id = NULL;
-	int id;
-	struct wpa_ssid *ssid;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
-			      DBUS_TYPE_INVALID);
-
-	/* Extract the network ID and ensure the network */
-	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
-		reply = wpas_dbus_error_invalid_args(message, op);
-		goto out;
-	}
-
-	id = strtoul(net_id, NULL, 10);
-	if (errno == EINVAL) {
-		reply = wpas_dbus_error_invalid_args(message, op);
-		goto out;
-	}
-
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		reply = wpas_dbus_error_network_unknown(message);
-		goto out;
-	}
-
-	/* Finally, associate with the network */
-	wpa_supplicant_select_network(wpa_s, ssid);
-
-out:
-	os_free(iface);
-	os_free(net_id);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing an error on failure or NULL on success
- *
- * Asks wpa_supplicant to internally store a binary blobs.
- */
-DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, array_iter;
-
-	char *blob_name;
-	u8 *blob_data;
-	int blob_len;
-	struct wpa_config_blob *blob = NULL;
-
-	dbus_message_iter_init(message, &iter);
-	dbus_message_iter_get_basic(&iter, &blob_name);
-
-	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
-		return dbus_message_new_error(message,
-					      WPAS_DBUS_ERROR_BLOB_EXISTS,
-					      NULL);
-	}
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &array_iter);
-
-	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
-
-	blob = os_zalloc(sizeof(*blob));
-	if (!blob) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
-
-	blob->data = os_malloc(blob_len);
-	if (!blob->data) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
-	os_memcpy(blob->data, blob_data, blob_len);
-
-	blob->len = blob_len;
-	blob->name = os_strdup(blob_name);
-	if (!blob->name) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
-
-	wpa_config_set_blob(wpa_s->conf, blob);
-	wpas_notify_blob_added(wpa_s, blob->name);
-
-	return reply;
-
-err:
-	if (blob) {
-		os_free(blob->name);
-		os_free(blob->data);
-		os_free(blob);
-	}
-	return reply;
-}
-
-
-/**
- * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing array of bytes (blob)
- *
- * Gets one wpa_supplicant's binary blobs.
- */
-DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, array_iter;
-
-	char *blob_name;
-	const struct wpa_config_blob *blob;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
-			      DBUS_TYPE_INVALID);
-
-	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
-	if (!blob) {
-		return dbus_message_new_error(message,
-					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
-					      "Blob id not set");
-	}
-
-	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-					      DBUS_TYPE_BYTE_AS_STRING,
-					      &array_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
-						  &(blob->data), blob->len)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_remove_handler_remove_blob - Remove named binary blob
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: NULL on success or dbus error
- *
- * Asks wpa_supplicant to internally remove a binary blobs.
- */
-DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	char *blob_name;
-
-	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
-			      DBUS_TYPE_INVALID);
-
-	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
-		return dbus_message_new_error(message,
-					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
-					      "Blob id not set");
-	}
-	wpas_notify_blob_removed(wpa_s, blob_name);
-
-	return reply;
-
-}
-
-
-/**
- * wpas_dbus_getter_capabilities - Return interface capabilities
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
- *
- * Getter for "Capabilities" property of an interface.
- */
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_driver_capa capa;
-	int res;
-	DBusMessageIter iter, iter_dict;
-	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
-		variant_iter;
-	const char *scans[] = { "active", "passive", "ssid" };
-	const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
-	int n = sizeof(modes) / sizeof(char *);
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		goto nomem;
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
-		goto nomem;
-
-	res = wpa_drv_get_capa(wpa_s, &capa);
-
-	/***** pairwise cipher */
-	if (res < 0) {
-		const char *args[] = {"ccmp", "tkip", "none"};
-		if (!wpa_dbus_dict_append_string_array(
-			    &iter_dict, "Pairwise", args,
-			    sizeof(args) / sizeof(char*)))
-			goto nomem;
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "none"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto nomem;
-	}
-
-	/***** group cipher */
-	if (res < 0) {
-		const char *args[] = {
-			"ccmp", "tkip", "wep104", "wep40"
-		};
-		if (!wpa_dbus_dict_append_string_array(
-			    &iter_dict, "Group", args,
-			    sizeof(args) / sizeof(char*)))
-			goto nomem;
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep104"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep40"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto nomem;
-	}
-
-	/***** key management */
-	if (res < 0) {
-		const char *args[] = {
-			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
-#ifdef CONFIG_WPS
-			"wps",
-#endif /* CONFIG_WPS */
-			"none"
-		};
-		if (!wpa_dbus_dict_append_string_array(
-			    &iter_dict, "KeyMgmt", args,
-			    sizeof(args) / sizeof(char*)))
-			goto nomem;
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "none"))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "ieee8021x"))
-			goto nomem;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-eap"))
-				goto nomem;
-
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-eap"))
-					goto nomem;
-
-/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-eap-sha256"))
-				goto nomem;
-#endif /* CONFIG_IEEE80211W */
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-psk"))
-				goto nomem;
-
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-psk"))
-					goto nomem;
-
-/* TODO: Ensure that driver actually supports sha256 encryption. */
-#ifdef CONFIG_IEEE80211W
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-psk-sha256"))
-				goto nomem;
-#endif /* CONFIG_IEEE80211W */
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-none"))
-				goto nomem;
-		}
-
-
-#ifdef CONFIG_WPS
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "wps"))
-			goto nomem;
-#endif /* CONFIG_WPS */
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto nomem;
-	}
-
-	/***** WPA protocol */
-	if (res < 0) {
-		const char *args[] = { "rsn", "wpa" };
-		if (!wpa_dbus_dict_append_string_array(
-			    &iter_dict, "Protocol", args,
-			    sizeof(args) / sizeof(char*)))
-			goto nomem;
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "rsn"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto nomem;
-	}
-
-	/***** auth alg */
-	if (res < 0) {
-		const char *args[] = { "open", "shared", "leap" };
-		if (!wpa_dbus_dict_append_string_array(
-			    &iter_dict, "AuthAlg", args,
-			    sizeof(args) / sizeof(char*)))
-			goto nomem;
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "open"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "shared"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "leap"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto nomem;
-	}
-
-	/***** Scan */
-	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
-					       sizeof(scans) / sizeof(char *)))
-		goto nomem;
-
-	/***** Modes */
-	if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
-		n--; /* exclude ap mode if it is not supported by the driver */
-	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
-		goto nomem;
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
-		goto nomem;
-
-	return reply;
-
-nomem:
-	if (reply)
-		dbus_message_unref(reply);
-
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
-}
-
-
-/**
- * wpas_dbus_getter_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- *          interface state
- *
- * Getter for "State" property.
- */
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *str_state;
-	char *state_ls, *tmp;
-
-	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
-
-	/* make state string lowercase to fit new DBus API convention
-	 */
-	state_ls = tmp = os_strdup(str_state);
-	if (!tmp) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-	while (*tmp) {
-		*tmp = tolower(*tmp);
-		tmp++;
-	}
-
-	reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						 &state_ls);
-
-	os_free(state_ls);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_new_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
- *
- * Getter for "scanning" property.
- */
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
-{
-	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&scanning);
-}
-
-
-/**
- * wpas_dbus_getter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containong value of ap_scan variable
- *
- * Getter function for "ApScan" property.
- */
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
-{
-	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
-						&ap_scan);
-}
-
-
-/**
- * wpas_dbus_setter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
- *
- * Setter function for "ApScan" property.
- */
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	dbus_uint32_t ap_scan;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-						 &ap_scan);
-	if (reply)
-		return reply;
-
-	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
-		return wpas_dbus_error_invalid_args(
-			message, "ap_scan must equal 0, 1 or 2");
-	}
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_getter_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * associated with with wpa_s
- *
- * Getter for "Ifname" property.
- */
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
-{
-	const char *ifname = wpa_s->ifname;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&ifname);
-}
-
-
-/**
- * wpas_dbus_getter_driver - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * driver associated with with wpa_s
- *
- * Getter for "Driver" property.
- */
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
-{
-	const char *driver;
-
-	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
-			   "wpa_s has no driver set");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	driver = wpa_s->driver->name;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&driver);
-}
-
-
-/**
- * wpas_dbus_getter_current_bss - Get current bss object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current BSS
- *
- * Getter for "CurrentBSS" property.
- */
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply;
-	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
-
-	if (wpa_s->current_bss)
-		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
-	else
-		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
-
-	reply = wpas_dbus_simple_property_getter(message,
-						 DBUS_TYPE_OBJECT_PATH,
-						 &bss_obj_path);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_current_network - Get current network object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current network
- *
- * Getter for "CurrentNetwork" property.
- */
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply;
-	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
-
-	if (wpa_s->current_ssid)
-		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
-			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
-	else
-		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
-
-	reply = wpas_dbus_simple_property_getter(message,
-						 DBUS_TYPE_OBJECT_PATH,
-						 &net_obj_path);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_bridge_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of bridge network
- * interface associated with with wpa_s
- *
- * Getter for "BridgeIfname" property.
- */
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s)
-{
-	const char *bridge_ifname = NULL;
-
-	bridge_ifname = wpa_s->bridge_ifname;
-	if (bridge_ifname == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: "
-			   "wpa_s has no bridge interface name set");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&bridge_ifname);
-}
-
-
-/**
- * wpas_dbus_getter_bsss - Get array of BSSs objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all known BSS objects
- * dbus paths
- *
- * Getter for "BSSs" property.
- */
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-				    struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_bss *bss;
-	char **paths;
-	unsigned int i = 0;
-
-	paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
-	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	/* Loop through scan results and append each result's object path */
-	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
-		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
-		if (paths[i] == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
-			goto out;
-		}
-		/* Construct the object path for this BSS. */
-		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
-			    wpa_s->dbus_new_path, bss->id);
-	}
-
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, wpa_s->num_bss);
-
-out:
-	while (i)
-		os_free(paths[--i]);
-	os_free(paths);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_networks - Get array of networks objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all configured
- * networks dbus object paths.
- *
- * Getter for "Networks" property.
- */
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_ssid *ssid;
-	char **paths;
-	unsigned int i = 0, num = 0;
-
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: "
-			   "An error occurred getting networks list.");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-		num++;
-
-	paths = os_zalloc(num * sizeof(char *));
-	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	/* Loop through configured networks and append object path of each */
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
-		if (paths[i] == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
-			goto out;
-		}
-
-		/* Construct the object path for this network. */
-		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
-			    wpa_s->dbus_new_path, ssid->id);
-	}
-
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num);
-
-out:
-	while (i)
-		os_free(paths[--i]);
-	os_free(paths);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_blobs - Get all blobs defined for this interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dictionary of pairs (blob_name, blob)
- *
- * Getter for "Blobs" property.
- */
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter;
-	struct wpa_config_blob *blob;
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      "a{say}", &variant_iter) ||
-	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
-					      "{say}", &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	blob = wpa_s->conf->blobs;
-	while (blob) {
-		if (!dbus_message_iter_open_container(&dict_iter,
-						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter) ||
-		    !dbus_message_iter_append_basic(&entry_iter,
-						    DBUS_TYPE_STRING,
-						    &(blob->name)) ||
-		    !dbus_message_iter_open_container(&entry_iter,
-						      DBUS_TYPE_ARRAY,
-						      DBUS_TYPE_BYTE_AS_STRING,
-						      &array_iter) ||
-		    !dbus_message_iter_append_fixed_array(&array_iter,
-							  DBUS_TYPE_BYTE,
-							  &(blob->data),
-							  blob->len) ||
-		    !dbus_message_iter_close_container(&entry_iter,
-						       &array_iter) ||
-		    !dbus_message_iter_close_container(&dict_iter,
-						       &entry_iter)) {
-			dbus_message_unref(reply);
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_NO_MEMORY,
-						      NULL);
-		}
-
-		blob = blob->next;
-	}
-
-	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the bssid for the requested bss
- *
- * Getter for "BSSID" property.
- */
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-					 struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res->bssid, ETH_ALEN);
-}
-
-
-/**
- * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the ssid for the requested bss
- *
- * Getter for "SSID" property.
- */
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-					      struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res->ssid,
-						      res->ssid_len);
-}
-
-
-/**
- * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the privacy flag value of requested bss
- *
- * Getter for "Privacy" property.
- */
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-					   struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-	dbus_bool_t privacy;
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&privacy);
-}
-
-
-/**
- * wpas_dbus_getter_bss_mode - Return the mode of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the mode of requested bss
- *
- * Getter for "Mode" property.
- */
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-					struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-	const char *mode;
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	if (res->caps & IEEE80211_CAP_IBSS)
-		mode = "ad-hoc";
-	else
-		mode = "infrastructure";
-
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&mode);
-}
-
-
-/**
- * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the signal strength of requested bss
- *
- * Getter for "Level" property.
- */
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-					  struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16,
-						&res->level);
-}
-
-
-/**
- * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the frequency of requested bss
- *
- * Getter for "Frequency" property.
- */
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-					     struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: "
-			   "no bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16,
-						&res->freq);
-}
-
-
-static int cmp_u8s_desc(const void *a, const void *b)
-{
-	return (*(u8 *) b - *(u8 *) a);
-}
-
-
-/**
- * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing sorted array of bit rates
- *
- * Getter for "Rates" property.
- */
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-					    struct bss_handler_args *bss)
-{
-	DBusMessage *reply;
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-	u8 *ie_rates = NULL;
-	u32 *real_rates;
-	int rates_num, i;
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: "
-			   "no bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
-	if (rates_num < 0)
-		return NULL;
-
-	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
-
-	real_rates = os_malloc(sizeof(u32) * rates_num);
-	if (!real_rates) {
-		os_free(ie_rates);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	for (i = 0; i < rates_num; i++)
-		real_rates[i] = ie_rates[i] * 500000;
-
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_UINT32,
-						       real_rates, rates_num);
-
-	os_free(ie_rates);
-	os_free(real_rates);
-	return reply;
-}
-
-
-static DBusMessage * wpas_dbus_get_bss_security_prop(
-	DBusMessage *message, struct wpa_ie_data *ie_data)
-{
-	DBusMessage *reply;
-	DBusMessageIter iter, iter_dict, variant_iter;
-	const char *group;
-	const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
-	const char *key_mgmt[7]; /* max 7 key managements may be supported */
-	int n;
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		goto nomem;
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
-		goto nomem;
-
-	/* KeyMgmt */
-	n = 0;
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
-		key_mgmt[n++] = "wpa-psk";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
-		key_mgmt[n++] = "wpa-ft-psk";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-		key_mgmt[n++] = "wpa-psk-sha256";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-		key_mgmt[n++] = "wpa-eap";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-		key_mgmt[n++] = "wpa-ft-eap";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-		key_mgmt[n++] = "wpa-eap-sha256";
-	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
-		key_mgmt[n++] = "wpa-none";
-
-	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
-					       key_mgmt, n))
-		goto nomem;
-
-	/* Group */
-	switch (ie_data->group_cipher) {
-	case WPA_CIPHER_WEP40:
-		group = "wep40";
-		break;
-	case WPA_CIPHER_TKIP:
-		group = "tkip";
-		break;
-	case WPA_CIPHER_CCMP:
-		group = "ccmp";
-		break;
-	case WPA_CIPHER_WEP104:
-		group = "wep104";
-		break;
-	default:
-		group = "";
-		break;
-	}
-
-	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
-		goto nomem;
-
-	/* Pairwise */
-	n = 0;
-	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
-		pairwise[n++] = "tkip";
-	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
-		pairwise[n++] = "ccmp";
-
-	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
-					       pairwise, n))
-		goto nomem;
-
-	/* Management group (RSN only) */
-	if (ie_data->proto == WPA_PROTO_RSN) {
-		switch (ie_data->mgmt_group_cipher) {
-#ifdef CONFIG_IEEE80211W
-		case WPA_CIPHER_AES_128_CMAC:
-			group = "aes128cmac";
-			break;
-#endif /* CONFIG_IEEE80211W */
-		default:
-			group = "";
-			break;
-		}
-
-		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
-						 group))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
-		goto nomem;
-
-	return reply;
-
-nomem:
-	if (reply)
-		dbus_message_unref(reply);
-
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
-}
-
-
-/**
- * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the WPA options of requested bss
- *
- * Getter for "WPA" property.
- */
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-				       struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-	struct wpa_ie_data wpa_data;
-	const u8 *ie;
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	os_memset(&wpa_data, 0, sizeof(wpa_data));
-	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0)
-			return wpas_dbus_error_unknown_error(message,
-							     "invalid WPA IE");
-	}
-
-	return wpas_dbus_get_bss_security_prop(message, &wpa_data);
-}
-
-
-/**
- * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the RSN options of requested bss
- *
- * Getter for "RSN" property.
- */
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-				       struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-	struct wpa_ie_data wpa_data;
-	const u8 *ie;
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	os_memset(&wpa_data, 0, sizeof(wpa_data));
-	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0)
-			return wpas_dbus_error_unknown_error(message,
-							     "invalid RSN IE");
-	}
-
-	return wpas_dbus_get_bss_security_prop(message, &wpa_data);
-}
-
-
-/**
- * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing IEs byte array
- *
- * Getter for "IEs" property.
- */
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-				       struct bss_handler_args *bss)
-{
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
-
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
-
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res + 1, res->ie_len);
-}
-
-
-/**
- * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: DBus message with boolean indicating state of configured network
- * or DBus error on failure
- *
- * Getter for "enabled" property of a configured network.
- */
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-				       struct network_handler_args *net)
-{
-	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&enabled);
-}
-
-
-/**
- * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
- *
- * Setter for "Enabled" property of a configured network.
- */
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-				       struct network_handler_args *net)
-{
-	DBusMessage *reply = NULL;
-
-	struct wpa_supplicant *wpa_s;
-	struct wpa_ssid *ssid;
-
-	dbus_bool_t enable;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &enable);
-
-	if (reply)
-		return reply;
-
-	wpa_s = net->wpa_s;
-	ssid = net->ssid;
-
-	if (enable)
-		wpa_supplicant_enable_network(wpa_s, ssid);
-	else
-		wpa_supplicant_disable_network(wpa_s, ssid);
-
-	return NULL;
-}
-
-
-/**
- * wpas_dbus_getter_network_properties - Get options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: DBus message with network properties or DBus error on failure
- *
- * Getter for "Properties" property of a configured network.
- */
-DBusMessage * wpas_dbus_getter_network_properties(
-	DBusMessage *message, struct network_handler_args *net)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, variant_iter, dict_iter;
-	char **iterator;
-	char **props = wpa_config_get_all(net->ssid, 0);
-	if (!props)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-			"a{sv}", &variant_iter) ||
-	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	iterator = props;
-	while (*iterator) {
-		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
-						 *(iterator + 1))) {
-			dbus_message_unref(reply);
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
-			goto out;
-		}
-		iterator += 2;
-	}
-
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-out:
-	iterator = props;
-	while (*iterator) {
-		os_free(*iterator);
-		iterator++;
-	}
-	os_free(props);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_setter_network_properties - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
- *
- * Setter for "Properties" property of a configured network.
- */
-DBusMessage * wpas_dbus_setter_network_properties(
-	DBusMessage *message, struct network_handler_args *net)
-{
-	struct wpa_ssid *ssid = net->ssid;
-
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, variant_iter;
-
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
-	reply = set_network_properties(message, net->wpa_s, ssid,
-				       &variant_iter);
-	if (reply)
-		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
-			   "network properties");
-
-	return reply;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3759 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "common/ieee802_11_defs.h"
+#include "eap_peer/eap_methods.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../driver_i.h"
+#include "../notify.h"
+#include "../bss.h"
+#include "../scan.h"
+#include "../autoscan.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_dict_helpers.h"
+#include "dbus_common_i.h"
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+static const char *debug_strings[] = {
+	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
+};
+
+
+/**
+ * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @arg: Optional string appended to error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an UnknownError
+ */
+DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
+					    const char *arg)
+{
+	/*
+	 * This function can be called as a result of a failure
+	 * within internal getter calls, which will call this function
+	 * with a NULL message parameter.  However, dbus_message_new_error
+	 * looks very unkindly (i.e, abort()) on a NULL message, so
+	 * in this case, we should not call it.
+	 */
+	if (message == NULL) {
+		wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
+			   "called with NULL message (arg=%s)",
+			   arg ? arg : "N/A");
+		return NULL;
+	}
+
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+				      arg);
+}
+
+
+/**
+ * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: A dbus error message
+ *
+ * Convenience function to create and return an invalid interface error
+ */
+static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+				      "wpa_supplicant knows nothing about "
+				      "this interface.");
+}
+
+
+/**
+ * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid network error
+ */
+static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+				      "There is no such a network in this "
+				      "interface.");
+}
+
+
+/**
+ * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid options error
+ */
+DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
+					  const char *arg)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
+				       "Did not receive correct message "
+				       "arguments.");
+	if (arg != NULL)
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
+					 DBUS_TYPE_INVALID);
+
+	return reply;
+}
+
+
+static const char *dont_quote[] = {
+	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
+	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
+	"bssid", "scan_freq", "freq_list", NULL
+};
+
+static dbus_bool_t should_quote_opt(const char *key)
+{
+	int i = 0;
+	while (dont_quote[i] != NULL) {
+		if (os_strcmp(key, dont_quote[i]) == 0)
+			return FALSE;
+		i++;
+	}
+	return TRUE;
+}
+
+/**
+ * get_iface_by_dbus_path - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @path: Pointer to a dbus object path representing an interface
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+static struct wpa_supplicant * get_iface_by_dbus_path(
+	struct wpa_global *global, const char *path)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->dbus_new_path, path) == 0)
+			return wpa_s;
+	}
+	return NULL;
+}
+
+
+/**
+ * set_network_properties - Set properties of a configured network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * @iter: DBus message iterator containing dictionary of network
+ * properties to set.
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
+ *
+ * Sets network configuration with parameters given id DBus dictionary
+ */
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid,
+				   DBusMessageIter *iter,
+				   DBusError *error)
+{
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	DBusMessageIter	iter_dict;
+	char *value = NULL;
+
+	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+		return FALSE;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		size_t size = 50;
+		int ret;
+
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		value = NULL;
+		if (entry.type == DBUS_TYPE_ARRAY &&
+		    entry.array_type == DBUS_TYPE_BYTE) {
+			if (entry.array_len <= 0)
+				goto error;
+
+			size = entry.array_len * 2 + 1;
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = wpa_snprintf_hex(value, size,
+					       (u8 *) entry.bytearray_value,
+					       entry.array_len);
+			if (ret <= 0)
+				goto error;
+		} else if (entry.type == DBUS_TYPE_STRING) {
+			if (should_quote_opt(entry.key)) {
+				size = os_strlen(entry.str_value);
+				if (size <= 0)
+					goto error;
+
+				size += 3;
+				value = os_zalloc(size);
+				if (value == NULL)
+					goto error;
+
+				ret = os_snprintf(value, size, "\"%s\"",
+						  entry.str_value);
+				if (ret < 0 || (size_t) ret != (size - 1))
+					goto error;
+			} else {
+				value = os_strdup(entry.str_value);
+				if (value == NULL)
+					goto error;
+			}
+		} else if (entry.type == DBUS_TYPE_UINT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = os_snprintf(value, size, "%u",
+					  entry.uint32_value);
+			if (ret <= 0)
+				goto error;
+		} else if (entry.type == DBUS_TYPE_INT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+
+			ret = os_snprintf(value, size, "%d",
+					  entry.int32_value);
+			if (ret <= 0)
+				goto error;
+		} else
+			goto error;
+
+		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+			goto error;
+
+		if ((os_strcmp(entry.key, "psk") == 0 &&
+		     value[0] == '"' && ssid->ssid_len) ||
+		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+			wpa_config_update_psk(ssid);
+		else if (os_strcmp(entry.key, "priority") == 0)
+			wpa_config_update_prio_list(wpa_s->conf);
+
+		os_free(value);
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	return TRUE;
+
+error:
+	os_free(value);
+	wpa_dbus_dict_entry_clear(&entry);
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	return FALSE;
+}
+
+
+/**
+ * wpas_dbus_simple_property_getter - Get basic type property
+ * @iter: Message iter to use when appending arguments
+ * @type: DBus type of property (must be basic type)
+ * @val: pointer to place holding property value
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ *
+ * Generic getter for basic type properties. Type is required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+					     const int type,
+					     const void *val,
+					     DBusError *error)
+{
+	DBusMessageIter variant_iter;
+
+	if (!dbus_type_is_basic(type)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: given type is not basic", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+	                                      wpa_dbus_type_as_string(type),
+	                                      &variant_iter))
+		goto error;
+
+	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
+		goto error;
+
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto error;
+
+	return TRUE;
+
+error:
+	dbus_set_error(error, DBUS_ERROR_FAILED,
+	               "%s: error constructing reply", __func__);
+	return FALSE;
+}
+
+
+/**
+ * wpas_dbus_simple_property_setter - Set basic type property
+ * @message: Pointer to incoming dbus message
+ * @type: DBus type of property (must be basic type)
+ * @val: pointer to place where value being set will be stored
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ *
+ * Generic setter for basic type properties. Type is required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+					     DBusError *error,
+					     const int type, void *val)
+{
+	DBusMessageIter variant_iter;
+
+	if (!dbus_type_is_basic(type)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: given type is not basic", __func__);
+		return FALSE;
+	}
+
+	/* Look at the new value */
+	dbus_message_iter_recurse(iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "wrong property type");
+		return FALSE;
+	}
+	dbus_message_iter_get_basic(&variant_iter, val);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_simple_array_property_getter - Get array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+						   const int type,
+						   const void *array,
+						   size_t array_len,
+						   DBusError *error)
+{
+	DBusMessageIter variant_iter, array_iter;
+	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
+	const char *sub_type_str;
+	size_t element_size, i;
+
+	if (!dbus_type_is_basic(type)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: given type is not basic", __func__);
+		return FALSE;
+	}
+
+	sub_type_str = wpa_dbus_type_as_string(type);
+	type_str[1] = sub_type_str[0];
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      type_str, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 1", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      sub_type_str, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 2", __func__);
+		return FALSE;
+	}
+
+	switch(type) {
+	case DBUS_TYPE_BYTE:
+	case DBUS_TYPE_BOOLEAN:
+		element_size = 1;
+		break;
+	case DBUS_TYPE_INT16:
+	case DBUS_TYPE_UINT16:
+		element_size = sizeof(uint16_t);
+		break;
+	case DBUS_TYPE_INT32:
+	case DBUS_TYPE_UINT32:
+		element_size = sizeof(uint32_t);
+		break;
+	case DBUS_TYPE_INT64:
+	case DBUS_TYPE_UINT64:
+		element_size = sizeof(uint64_t);
+		break;
+	case DBUS_TYPE_DOUBLE:
+		element_size = sizeof(double);
+		break;
+	case DBUS_TYPE_STRING:
+	case DBUS_TYPE_OBJECT_PATH:
+		element_size = sizeof(char *);
+		break;
+	default:
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: unknown element type %d", __func__, type);
+		return FALSE;
+	}
+
+	for (i = 0; i < array_len; i++) {
+		dbus_message_iter_append_basic(&array_iter, type,
+					       array + i * element_size);
+	}
+
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 3", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 4", __func__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_simple_array_array_property_getter - Get array array type property
+ * @iter: Pointer to incoming dbus message iterator
+ * @type: DBus type of property array elements (must be basic type)
+ * @array: pointer to array of elements to put into response message
+ * @array_len: length of above array
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
+ *
+ * Generic getter for array type properties. Array elements type is
+ * required to be basic.
+ */
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+							 const int type,
+							 struct wpabuf **array,
+							 size_t array_len,
+							 DBusError *error)
+{
+	DBusMessageIter variant_iter, array_iter;
+	char type_str[] = "aa?";
+	char inner_type_str[] = "a?";
+	const char *sub_type_str;
+	size_t i;
+
+	if (!dbus_type_is_basic(type)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: given type is not basic", __func__);
+		return FALSE;
+	}
+
+	sub_type_str = wpa_dbus_type_as_string(type);
+	type_str[2] = sub_type_str[0];
+	inner_type_str[1] = sub_type_str[0];
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      type_str, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: failed to construct message 1", __func__);
+		return FALSE;
+	}
+	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      inner_type_str, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: failed to construct message 2", __func__);
+		return FALSE;
+	}
+
+	for (i = 0; i < array_len; i++) {
+		wpa_dbus_dict_bin_array_add_element(&array_iter,
+						    wpabuf_head(array[i]),
+						    wpabuf_len(array[i]));
+
+	}
+
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: failed to close message 2", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: failed to close message 1", __func__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_handler_create_interface - Request registration of a network iface
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the new interface object,
+ *          or a dbus error message with more information
+ *
+ * Handler function for "CreateInterface" method call. Handles requests
+ * by dbus clients to register a network interface that wpa_supplicant
+ * will manage.
+ */
+DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
+						 struct wpa_global *global)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *driver = NULL;
+	char *ifname = NULL;
+	char *confname = NULL;
+	char *bridge_ifname = NULL;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+		if (!os_strcmp(entry.key, "Driver") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			driver = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+			if (driver == NULL)
+				goto error;
+		} else if (!os_strcmp(entry.key, "Ifname") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			ifname = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+			if (ifname == NULL)
+				goto error;
+		} else if (!os_strcmp(entry.key, "ConfigFile") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			confname = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+			if (confname == NULL)
+				goto error;
+		} else if (!os_strcmp(entry.key, "BridgeIfname") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			bridge_ifname = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+			if (bridge_ifname == NULL)
+				goto error;
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto error;
+		}
+	}
+
+	if (ifname == NULL)
+		goto error; /* Required Ifname argument missing */
+
+	/*
+	 * Try to get the wpa_supplicant record for this iface, return
+	 * an error if we already control it.
+	 */
+	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
+		reply = dbus_message_new_error(message,
+					       WPAS_DBUS_ERROR_IFACE_EXISTS,
+					       "wpa_supplicant already "
+					       "controls this interface.");
+	} else {
+		struct wpa_supplicant *wpa_s;
+		struct wpa_interface iface;
+		os_memset(&iface, 0, sizeof(iface));
+		iface.driver = driver;
+		iface.ifname = ifname;
+		iface.confname = confname;
+		iface.bridge_ifname = bridge_ifname;
+		/* Otherwise, have wpa_supplicant attach to it. */
+		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+			const char *path = wpa_s->dbus_new_path;
+			reply = dbus_message_new_method_return(message);
+			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+			                         &path, DBUS_TYPE_INVALID);
+		} else {
+			reply = wpas_dbus_error_unknown_error(
+				message, "wpa_supplicant couldn't grab this "
+				"interface.");
+		}
+	}
+
+out:
+	os_free(driver);
+	os_free(ifname);
+	os_free(confname);
+	os_free(bridge_ifname);
+	return reply;
+
+error:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_interface - Request deregistration of an interface
+ * @message: Pointer to incoming dbus message
+ * @global: wpa_supplicant global data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "removeInterface" method call.  Handles requests
+ * by dbus clients to deregister a network interface that wpa_supplicant
+ * currently manages.
+ */
+DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
+						 struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+	char *path;
+	DBusMessage *reply = NULL;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+			      DBUS_TYPE_INVALID);
+
+	wpa_s = get_iface_by_dbus_path(global, path);
+	if (wpa_s == NULL)
+		reply = wpas_dbus_error_iface_unknown(message);
+	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
+		reply = wpas_dbus_error_unknown_error(
+			message, "wpa_supplicant couldn't remove this "
+			"interface.");
+	}
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_get_interface - Get the object path for an interface name
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the interface object,
+ *          or a dbus error message with more information
+ *
+ * Handler function for "getInterface" method call.
+ */
+DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
+					      struct wpa_global *global)
+{
+	DBusMessage *reply = NULL;
+	const char *ifname;
+	const char *path;
+	struct wpa_supplicant *wpa_s;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
+			      DBUS_TYPE_INVALID);
+
+	wpa_s = wpa_supplicant_get_iface(global, ifname);
+	if (wpa_s == NULL)
+		return wpas_dbus_error_iface_unknown(message);
+
+	path = wpa_s->dbus_new_path;
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+				      DBUS_TYPE_INVALID)) {
+		dbus_message_unref(reply);
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	}
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_getter_debug_level - Get debug level
+ * @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 "DebugLevel" property.
+ */
+dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
+					 DBusError *error,
+					 void *user_data)
+{
+	const char *str;
+	int idx = wpa_debug_level;
+
+	if (idx < 0)
+		idx = 0;
+	if (idx > 5)
+		idx = 5;
+	str = debug_strings[idx];
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&str, error);
+}
+
+
+/**
+ * wpas_dbus_getter_debug_timestamp - Get debug timestamp
+ * @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 "DebugTimestamp" property.
+ */
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data)
+{
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&wpa_debug_timestamp, error);
+
+}
+
+
+/**
+ * wpas_dbus_getter_debug_show_keys - Get debug show keys
+ * @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 "DebugShowKeys" property.
+ */
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
+{
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&wpa_debug_show_keys, error);
+
+}
+
+/**
+ * wpas_dbus_setter_debug_level - Set debug level
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DebugLevel" property.
+ */
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+					 DBusError *error, void *user_data)
+{
+	struct wpa_global *global = user_data;
+	const char *str = NULL;
+	int i, val = -1;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &str))
+		return FALSE;
+
+	for (i = 0; debug_strings[i]; i++)
+		if (os_strcmp(debug_strings[i], str) == 0) {
+			val = i;
+			break;
+		}
+
+	if (val < 0 ||
+	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
+					    wpa_debug_show_keys)) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
+				     "level value");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_setter_debug_timestamp - Set debug timestamp
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DebugTimestamp" property.
+ */
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
+{
+	struct wpa_global *global = user_data;
+	dbus_bool_t val;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &val))
+		return FALSE;
+
+	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
+					wpa_debug_show_keys);
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_setter_debug_show_keys - Set debug show keys
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "DebugShowKeys" property.
+ */
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
+{
+	struct wpa_global *global = user_data;
+	dbus_bool_t val;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &val))
+		return FALSE;
+
+	wpa_supplicant_set_debug_params(global, wpa_debug_level,
+					wpa_debug_timestamp,
+					val ? 1 : 0);
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_interfaces - Request registered interfaces list
+ * @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 "Interfaces" property. Handles requests
+ * 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)
+{
+	struct wpa_global *global = user_data;
+	struct wpa_supplicant *wpa_s;
+	const char **paths;
+	unsigned int i = 0, num = 0;
+	dbus_bool_t success;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		num++;
+
+	paths = os_calloc(num, sizeof(char *));
+	if (!paths) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		paths[i++] = wpa_s->dbus_new_path;
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
+
+	os_free(paths);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_eap_methods - Request supported EAP methods list
+ * @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 "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)
+{
+	char **eap_methods;
+	size_t num_items = 0;
+	dbus_bool_t success;
+
+	eap_methods = eap_get_names_as_string_array(&num_items);
+	if (!eap_methods) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_STRING,
+							 eap_methods,
+							 num_items, error);
+
+	while (num_items)
+		os_free(eap_methods[--num_items]);
+	os_free(eap_methods);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_global_capabilities - Request supported global capabilities
+ * @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 "Capabilities" property. Handles requests by dbus clients to
+ * 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)
+{
+	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+	size_t num_items = 0;
+
+#ifdef CONFIG_AP
+	capabilities[num_items++] = "ap";
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IBSS_RSN
+	capabilities[num_items++] = "ibss-rsn";
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+	capabilities[num_items++] = "p2p";
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	capabilities[num_items++] = "interworking";
+#endif /* CONFIG_INTERWORKING */
+
+	return wpas_dbus_simple_array_property_getter(iter,
+						      DBUS_TYPE_STRING,
+						      capabilities,
+						      num_items, error);
+}
+
+
+static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
+				   char **type, DBusMessage **reply)
+{
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Type must be a string");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Type value type. String required");
+		return -1;
+	}
+	dbus_message_iter_get_basic(var, type);
+	return 0;
+}
+
+
+static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
+				    struct wpa_driver_scan_params *params,
+				    DBusMessage **reply)
+{
+	struct wpa_driver_scan_ssid *ssids = params->ssids;
+	size_t ssids_num = 0;
+	u8 *ssid;
+	DBusMessageIter array_iter, sub_array_iter;
+	char *val;
+	int len;
+
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
+			   "must be an array of arrays of bytes");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong SSIDs value type. Array of arrays of "
+			"bytes required");
+		return -1;
+	}
+
+	dbus_message_iter_recurse(var, &array_iter);
+
+	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
+	{
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
+			   "must be an array of arrays of bytes");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong SSIDs value type. Array of arrays of "
+			"bytes required");
+		return -1;
+	}
+
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
+	{
+		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "Too many ssids specified on scan dbus "
+				   "call");
+			*reply = wpas_dbus_error_invalid_args(
+				message, "Too many ssids specified. Specify "
+				"at most four");
+			return -1;
+		}
+
+		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
+
+		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
+
+		if (len > MAX_SSID_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "wpas_dbus_handler_scan[dbus]: "
+				   "SSID too long (len=%d max_len=%d)",
+				   len, MAX_SSID_LEN);
+			*reply = wpas_dbus_error_invalid_args(
+				message, "Invalid SSID: too long");
+			return -1;
+		}
+
+		if (len != 0) {
+			ssid = os_malloc(len);
+			if (ssid == NULL) {
+				wpa_printf(MSG_DEBUG,
+					   "wpas_dbus_handler_scan[dbus]: "
+					   "out of memory. Cannot allocate "
+					   "memory for SSID");
+				*reply = dbus_message_new_error(
+					message, DBUS_ERROR_NO_MEMORY, NULL);
+				return -1;
+			}
+			os_memcpy(ssid, val, len);
+		} else {
+			/* Allow zero-length SSIDs */
+			ssid = NULL;
+		}
+
+		ssids[ssids_num].ssid = ssid;
+		ssids[ssids_num].ssid_len = len;
+
+		dbus_message_iter_next(&array_iter);
+		ssids_num++;
+	}
+
+	params->num_ssids = ssids_num;
+	return 0;
+}
+
+
+static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
+				  struct wpa_driver_scan_params *params,
+				  DBusMessage **reply)
+{
+	u8 *ies = NULL, *nies;
+	int ies_len = 0;
+	DBusMessageIter array_iter, sub_array_iter;
+	char *val;
+	int len;
+
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
+			   "be an array of arrays of bytes");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong IEs value type. Array of arrays of "
+			"bytes required");
+		return -1;
+	}
+
+	dbus_message_iter_recurse(var, &array_iter);
+
+	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
+	{
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
+			   "be an array of arrays of bytes");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong IEs value type. Array required");
+		return -1;
+	}
+
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
+	{
+		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
+
+		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
+		if (len == 0) {
+			dbus_message_iter_next(&array_iter);
+			continue;
+		}
+
+		nies = os_realloc(ies, ies_len + len);
+		if (nies == NULL) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "out of memory. Cannot allocate memory for "
+				   "IE");
+			os_free(ies);
+			*reply = dbus_message_new_error(
+				message, DBUS_ERROR_NO_MEMORY, NULL);
+			return -1;
+		}
+		ies = nies;
+		os_memcpy(ies + ies_len, val, len);
+		ies_len += len;
+
+		dbus_message_iter_next(&array_iter);
+	}
+
+	params->extra_ies = ies;
+	params->extra_ies_len = ies_len;
+	return 0;
+}
+
+
+static int wpas_dbus_get_scan_channels(DBusMessage *message,
+				       DBusMessageIter *var,
+				       struct wpa_driver_scan_params *params,
+				       DBusMessage **reply)
+{
+	DBusMessageIter array_iter, sub_array_iter;
+	int *freqs = NULL, *nfreqs;
+	int freqs_num = 0;
+
+	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Channels must be an array of structs");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Channels value type. Array of structs "
+			"required");
+		return -1;
+	}
+
+	dbus_message_iter_recurse(var, &array_iter);
+
+	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
+		wpa_printf(MSG_DEBUG,
+			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
+			   "array of structs");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Wrong Channels value type. Array of structs "
+			"required");
+		return -1;
+	}
+
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
+	{
+		int freq, width;
+
+		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
+
+		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
+		    DBUS_TYPE_UINT32) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "Channel must by specified by struct of "
+				   "two UINT32s %c",
+				   dbus_message_iter_get_arg_type(
+					   &sub_array_iter));
+			*reply = wpas_dbus_error_invalid_args(
+				message, "Wrong Channel struct. Two UINT32s "
+				"required");
+			os_free(freqs);
+			return -1;
+		}
+		dbus_message_iter_get_basic(&sub_array_iter, &freq);
+
+		if (!dbus_message_iter_next(&sub_array_iter) ||
+		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
+		    DBUS_TYPE_UINT32) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "Channel must by specified by struct of "
+				   "two UINT32s");
+			*reply = wpas_dbus_error_invalid_args(
+				message,
+				"Wrong Channel struct. Two UINT32s required");
+			os_free(freqs);
+			return -1;
+		}
+
+		dbus_message_iter_get_basic(&sub_array_iter, &width);
+
+#define FREQS_ALLOC_CHUNK 32
+		if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
+			nfreqs = os_realloc_array(
+				freqs, freqs_num + FREQS_ALLOC_CHUNK,
+				sizeof(int));
+			if (nfreqs == NULL)
+				os_free(freqs);
+			freqs = nfreqs;
+		}
+		if (freqs == NULL) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "out of memory. can't allocate memory for "
+				   "freqs");
+			*reply = dbus_message_new_error(
+				message, DBUS_ERROR_NO_MEMORY, NULL);
+			return -1;
+		}
+
+		freqs[freqs_num] = freq;
+
+		freqs_num++;
+		dbus_message_iter_next(&array_iter);
+	}
+
+	nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
+	if (nfreqs == NULL)
+		os_free(freqs);
+	freqs = nfreqs;
+	if (freqs == NULL) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "out of memory. Can't allocate memory for freqs");
+		*reply = dbus_message_new_error(
+			message, DBUS_ERROR_NO_MEMORY, NULL);
+		return -1;
+	}
+	freqs[freqs_num] = 0;
+
+	params->freqs = freqs;
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_handler_scan - Request a wireless scan on an interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "Scan" method call of a network device. Requests
+ * that wpa_supplicant perform a wireless scan as soon as possible
+ * on a particular wireless interface.
+ */
+DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
+	char *key = NULL, *type = NULL;
+	struct wpa_driver_scan_params params;
+	size_t i;
+
+	os_memset(&params, 0, sizeof(params));
+
+	dbus_message_iter_init(message, &iter);
+
+	dbus_message_iter_recurse(&iter, &dict_iter);
+
+	while (dbus_message_iter_get_arg_type(&dict_iter) ==
+			DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(&dict_iter, &entry_iter);
+		dbus_message_iter_get_basic(&entry_iter, &key);
+		dbus_message_iter_next(&entry_iter);
+		dbus_message_iter_recurse(&entry_iter, &variant_iter);
+
+		if (os_strcmp(key, "Type") == 0) {
+			if (wpas_dbus_get_scan_type(message, &variant_iter,
+						    &type, &reply) < 0)
+				goto out;
+		} else if (os_strcmp(key, "SSIDs") == 0) {
+			if (wpas_dbus_get_scan_ssids(message, &variant_iter,
+						     &params, &reply) < 0)
+				goto out;
+		} else if (os_strcmp(key, "IEs") == 0) {
+			if (wpas_dbus_get_scan_ies(message, &variant_iter,
+						   &params, &reply) < 0)
+				goto out;
+		} else if (os_strcmp(key, "Channels") == 0) {
+			if (wpas_dbus_get_scan_channels(message, &variant_iter,
+							&params, &reply) < 0)
+				goto out;
+		} else {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "Unknown argument %s", key);
+			reply = wpas_dbus_error_invalid_args(message, key);
+			goto out;
+		}
+
+		dbus_message_iter_next(&dict_iter);
+	}
+
+	if (!type) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Scan type not specified");
+		reply = wpas_dbus_error_invalid_args(message, key);
+		goto out;
+	}
+
+	if (!os_strcmp(type, "passive")) {
+		if (params.num_ssids || params.extra_ies_len) {
+			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+				   "SSIDs or IEs specified for passive scan.");
+			reply = wpas_dbus_error_invalid_args(
+				message, "You can specify only Channels in "
+				"passive scan");
+			goto out;
+		} else if (params.freqs && params.freqs[0]) {
+			wpa_supplicant_trigger_scan(wpa_s, &params);
+		} else {
+			wpa_s->scan_req = MANUAL_SCAN_REQ;
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
+	} else if (!os_strcmp(type, "active")) {
+		if (!params.num_ssids) {
+			/* Add wildcard ssid */
+			params.num_ssids++;
+		}
+#ifdef CONFIG_AUTOSCAN
+		autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
+		wpa_supplicant_trigger_scan(wpa_s, &params);
+	} else {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
+			   "Unknown scan type: %s", type);
+		reply = wpas_dbus_error_invalid_args(message,
+						     "Wrong scan type");
+		goto out;
+	}
+
+out:
+	for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
+		os_free((u8 *) params.ssids[i].ssid);
+	os_free((u8 *) params.extra_ies);
+	os_free(params.freqs);
+	return reply;
+}
+
+
+/*
+ * wpas_dbus_handler_disconnect - Terminate the current connection
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if already not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Disconnect" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->current_ssid != NULL) {
+		wpa_s->disconnected = 1;
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+
+		return NULL;
+	}
+
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+				      "This interface is not connected");
+}
+
+
+/**
+ * wpas_dbus_new_iface_add_network - Add a new configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new network
+ *
+ * Handler function for "AddNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter;
+	struct wpa_ssid *ssid = NULL;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+	DBusError error;
+
+	dbus_message_iter_init(message, &iter);
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
+			   "can't add new interface.");
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"wpa_supplicant could not add "
+			"a network on this interface.");
+		goto err;
+	}
+	wpas_notify_network_added(wpa_s, ssid);
+	ssid->disabled = 1;
+	wpa_config_set_network_defaults(ssid);
+
+	dbus_error_init(&error);
+	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
+			   "control interface couldn't set network "
+			   "properties");
+		reply = wpas_dbus_reply_new_from_error(message, &error,
+						       DBUS_ERROR_INVALID_ARGS,
+						       "Failed to add network");
+		dbus_error_free(&error);
+		goto err;
+	}
+
+	/* Construct the object path for this network. */
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+				      DBUS_TYPE_INVALID)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+
+	return reply;
+
+err:
+	if (ssid) {
+		wpas_notify_network_removed(wpa_s, ssid);
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+	}
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reassociate" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->current_ssid != NULL) {
+		wpas_request_connection(wpa_s);
+		return NULL;
+	}
+
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+				      "This interface is not connected");
+}
+
+
+/**
+ * wpas_dbus_handler_remove_network - Remove a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface = NULL, *net_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+			      DBUS_TYPE_INVALID);
+
+	/* Extract the network ID and ensure the network */
+	/* is actually a child of this interface */
+	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	errno = 0;
+	id = strtoul(net_id, NULL, 10);
+	if (errno != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_network_unknown(message);
+		goto out;
+	}
+
+	wpas_notify_network_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "wpas_dbus_handler_remove_network[dbus]: "
+			   "error occurred when removing network %d", id);
+		reply = wpas_dbus_error_unknown_error(
+			message, "error removing the specified network on "
+			"this interface.");
+		goto out;
+	}
+
+	if (ssid == wpa_s->current_ssid)
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+
+out:
+	os_free(iface);
+	os_free(net_id);
+	return reply;
+}
+
+
+static void remove_network(void *arg, struct wpa_ssid *ssid)
+{
+	struct wpa_supplicant *wpa_s = arg;
+
+	wpas_notify_network_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "wpas_dbus_handler_remove_all_networks[dbus]: "
+			   "error occurred when removing network %d",
+			   ssid->id);
+		return;
+	}
+
+	if (ssid == wpa_s->current_ssid)
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_networks - Remove all configured networks
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllNetworks" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_networks(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	/* NB: could check for failure and return an error */
+	wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
+	return NULL;
+}
+
+
+/**
+ * wpas_dbus_handler_select_network - Attempt association with a network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "SelectNetwork" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface = NULL, *net_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+			      DBUS_TYPE_INVALID);
+
+	/* Extract the network ID and ensure the network */
+	/* is actually a child of this interface */
+	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	errno = 0;
+	id = strtoul(net_id, NULL, 10);
+	if (errno != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_network_unknown(message);
+		goto out;
+	}
+
+	/* Finally, associate with the network */
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+out:
+	os_free(iface);
+	os_free(net_id);
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "NetworkReply" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	DBusMessage *reply = NULL;
+	const char *op, *field, *value;
+	char *iface = NULL, *net_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	if (!dbus_message_get_args(message, NULL,
+	                           DBUS_TYPE_OBJECT_PATH, &op,
+	                           DBUS_TYPE_STRING, &field,
+	                           DBUS_TYPE_STRING, &value,
+			           DBUS_TYPE_INVALID))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	/* Extract the network ID and ensure the network */
+	/* is actually a child of this interface */
+	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	if (iface == NULL || net_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	errno = 0;
+	id = strtoul(net_id, NULL, 10);
+	if (errno != 0) {
+		reply = wpas_dbus_error_invalid_args(message, net_id);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_network_unknown(message);
+		goto out;
+	}
+
+	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
+						      field, value) < 0)
+		reply = wpas_dbus_error_invalid_args(message, field);
+	else {
+		/* Tell EAP to retry immediately */
+		eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	}
+
+out:
+	os_free(iface);
+	os_free(net_id);
+	return reply;
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+	return wpas_dbus_error_unknown_error(message, "802.1X not included");
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+/**
+ * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing an error on failure or NULL on success
+ *
+ * Asks wpa_supplicant to internally store a binary blobs.
+ */
+DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter, array_iter;
+
+	char *blob_name;
+	u8 *blob_data;
+	int blob_len;
+	struct wpa_config_blob *blob = NULL;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &blob_name);
+
+	if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_BLOB_EXISTS,
+					      NULL);
+	}
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &array_iter);
+
+	dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
+
+	blob = os_zalloc(sizeof(*blob));
+	if (!blob) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+
+	blob->data = os_malloc(blob_len);
+	if (!blob->data) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+	os_memcpy(blob->data, blob_data, blob_len);
+
+	blob->len = blob_len;
+	blob->name = os_strdup(blob_name);
+	if (!blob->name) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+
+	wpa_config_set_blob(wpa_s->conf, blob);
+	wpas_notify_blob_added(wpa_s, blob->name);
+
+	return reply;
+
+err:
+	if (blob) {
+		os_free(blob->name);
+		os_free(blob->data);
+		os_free(blob);
+	}
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing array of bytes (blob)
+ *
+ * Gets one wpa_supplicant's binary blobs.
+ */
+DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter, array_iter;
+
+	char *blob_name;
+	const struct wpa_config_blob *blob;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
+			      DBUS_TYPE_INVALID);
+
+	blob = wpa_config_get_blob(wpa_s->conf, blob_name);
+	if (!blob) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
+					      "Blob id not set");
+	}
+
+	reply = dbus_message_new_method_return(message);
+	if (!reply) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto out;
+	}
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &array_iter)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto out;
+	}
+
+	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+						  &(blob->data), blob->len)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto out;
+	}
+
+	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto out;
+	}
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_remove_handler_remove_blob - Remove named binary blob
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: NULL on success or dbus error
+ *
+ * Asks wpa_supplicant to internally remove a binary blobs.
+ */
+DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	char *blob_name;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
+			      DBUS_TYPE_INVALID);
+
+	if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_BLOB_UNKNOWN,
+					      "Blob id not set");
+	}
+	wpas_notify_blob_removed(wpa_s, blob_name);
+
+	return reply;
+
+}
+
+/*
+ * wpas_dbus_handler_flush_bss - Flush the BSS cache
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "FlushBSS" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	dbus_uint32_t age;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
+			      DBUS_TYPE_INVALID);
+
+	if (age == 0)
+		wpa_bss_flush(wpa_s);
+	else
+		wpa_bss_flush_by_age(wpa_s, age);
+
+	return NULL;
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+/**
+ * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL
+ *
+ * Handler function for "AutoScan" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	enum wpa_states state = wpa_s->wpa_state;
+	char *arg;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
+			      DBUS_TYPE_INVALID);
+
+	if (arg != NULL && os_strlen(arg) > 0) {
+		char *tmp;
+		tmp = os_strdup(arg);
+		if (tmp == NULL) {
+			reply = dbus_message_new_error(message,
+						       DBUS_ERROR_NO_MEMORY,
+						       NULL);
+		} else {
+			os_free(wpa_s->conf->autoscan);
+			wpa_s->conf->autoscan = tmp;
+			if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+				autoscan_init(wpa_s, 1);
+			else if (state == WPA_SCANNING)
+				wpa_supplicant_reinit_autoscan(wpa_s);
+		}
+	} else if (arg != NULL && os_strlen(arg) == 0) {
+		os_free(wpa_s->conf->autoscan);
+		wpa_s->conf->autoscan = NULL;
+		autoscan_deinit(wpa_s);
+	} else
+		reply = dbus_message_new_error(message,
+					       DBUS_ERROR_INVALID_ARGS,
+					       NULL);
+
+	return reply;
+}
+#endif /* CONFIG_AUTOSCAN */
+
+
+/**
+ * wpas_dbus_getter_capabilities - Return interface capabilities
+ * @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 "Capabilities" property of an interface.
+ */
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+					  DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct wpa_driver_capa capa;
+	int res;
+	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
+		variant_iter;
+	const char *scans[] = { "active", "passive", "ssid" };
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+		goto nomem;
+
+	res = wpa_drv_get_capa(wpa_s, &capa);
+
+	/***** pairwise cipher */
+	if (res < 0) {
+		const char *args[] = {"ccmp", "tkip", "none"};
+		if (!wpa_dbus_dict_append_string_array(
+			    &iter_dict, "Pairwise", args,
+			    sizeof(args) / sizeof(char*)))
+			goto nomem;
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto nomem;
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "ccmp"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "gcmp"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "tkip"))
+				goto nomem;
+		}
+
+		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "none"))
+				goto nomem;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto nomem;
+	}
+
+	/***** group cipher */
+	if (res < 0) {
+		const char *args[] = {
+			"ccmp", "tkip", "wep104", "wep40"
+		};
+		if (!wpa_dbus_dict_append_string_array(
+			    &iter_dict, "Group", args,
+			    sizeof(args) / sizeof(char*)))
+			goto nomem;
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto nomem;
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "ccmp"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "gcmp"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "tkip"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wep104"))
+				goto nomem;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wep40"))
+				goto nomem;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto nomem;
+	}
+
+	/***** key management */
+	if (res < 0) {
+		const char *args[] = {
+			"wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
+#ifdef CONFIG_WPS
+			"wps",
+#endif /* CONFIG_WPS */
+			"none"
+		};
+		if (!wpa_dbus_dict_append_string_array(
+			    &iter_dict, "KeyMgmt", args,
+			    sizeof(args) / sizeof(char*)))
+			goto nomem;
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto nomem;
+
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "none"))
+			goto nomem;
+
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "ieee8021x"))
+			goto nomem;
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa-eap"))
+				goto nomem;
+
+			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
+				if (!wpa_dbus_dict_string_array_add_element(
+					    &iter_array, "wpa-ft-eap"))
+					goto nomem;
+
+/* TODO: Ensure that driver actually supports sha256 encryption. */
+#ifdef CONFIG_IEEE80211W
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa-eap-sha256"))
+				goto nomem;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa-psk"))
+				goto nomem;
+
+			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
+				if (!wpa_dbus_dict_string_array_add_element(
+					    &iter_array, "wpa-ft-psk"))
+					goto nomem;
+
+/* TODO: Ensure that driver actually supports sha256 encryption. */
+#ifdef CONFIG_IEEE80211W
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa-psk-sha256"))
+				goto nomem;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa-none"))
+				goto nomem;
+		}
+
+
+#ifdef CONFIG_WPS
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "wps"))
+			goto nomem;
+#endif /* CONFIG_WPS */
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto nomem;
+	}
+
+	/***** WPA protocol */
+	if (res < 0) {
+		const char *args[] = { "rsn", "wpa" };
+		if (!wpa_dbus_dict_append_string_array(
+			    &iter_dict, "Protocol", args,
+			    sizeof(args) / sizeof(char*)))
+			goto nomem;
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto nomem;
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "rsn"))
+				goto nomem;
+		}
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "wpa"))
+				goto nomem;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto nomem;
+	}
+
+	/***** auth alg */
+	if (res < 0) {
+		const char *args[] = { "open", "shared", "leap" };
+		if (!wpa_dbus_dict_append_string_array(
+			    &iter_dict, "AuthAlg", args,
+			    sizeof(args) / sizeof(char*)))
+			goto nomem;
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto nomem;
+
+		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "open"))
+				goto nomem;
+		}
+
+		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "shared"))
+				goto nomem;
+		}
+
+		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "leap"))
+				goto nomem;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto nomem;
+	}
+
+	/***** Scan */
+	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
+					       sizeof(scans) / sizeof(char *)))
+		goto nomem;
+
+	/***** Modes */
+	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
+					      &iter_dict_entry,
+					      &iter_dict_val,
+					      &iter_array))
+		goto nomem;
+
+	if (!wpa_dbus_dict_string_array_add_element(
+			    &iter_array, "infrastructure"))
+		goto nomem;
+
+	if (!wpa_dbus_dict_string_array_add_element(
+			    &iter_array, "ad-hoc"))
+		goto nomem;
+
+	if (res >= 0) {
+		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "ap"))
+				goto nomem;
+		}
+
+		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "p2p"))
+				goto nomem;
+		}
+	}
+
+	if (!wpa_dbus_dict_end_string_array(&iter_dict,
+					    &iter_dict_entry,
+					    &iter_dict_val,
+					    &iter_array))
+		goto nomem;
+	/***** Modes end */
+
+	if (res >= 0) {
+		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
+
+		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
+						max_scan_ssid))
+			goto nomem;
+	}
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+		goto nomem;
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto nomem;
+
+	return TRUE;
+
+nomem:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
+}
+
+
+/**
+ * wpas_dbus_getter_state - Get interface state
+ * @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 "State" property.
+ */
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+				   void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *str_state;
+	char *state_ls, *tmp;
+	dbus_bool_t success = FALSE;
+
+	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
+
+	/* make state string lowercase to fit new DBus API convention
+	 */
+	state_ls = tmp = os_strdup(str_state);
+	if (!tmp) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+	while (*tmp) {
+		*tmp = tolower(*tmp);
+		tmp++;
+	}
+
+	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						   &state_ls, error);
+
+	os_free(state_ls);
+
+	return success;
+}
+
+
+/**
+ * wpas_dbus_new_iface_get_scanning - Get interface scanning state
+ * @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 "scanning" property.
+ */
+dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&scanning, error);
+}
+
+
+/**
+ * wpas_dbus_getter_ap_scan - Control roaming mode
+ * @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 function for "ApScan" property.
+ */
+dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&ap_scan, error);
+}
+
+
+/**
+ * wpas_dbus_setter_ap_scan - Control roaming mode
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "ApScan" property.
+ */
+dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t ap_scan;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &ap_scan))
+		return FALSE;
+
+	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "ap_scan must be 0, 1, or 2");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_fast_reauth - Control fast
+ * reauthentication (TLS session resumption)
+ * @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 function for "FastReauth" property.
+ */
+dbus_bool_t wpas_dbus_getter_fast_reauth(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;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&fast_reauth, error);
+}
+
+
+/**
+ * wpas_dbus_setter_fast_reauth - Control fast
+ * reauthentication (TLS session resumption)
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "FastReauth" property.
+ */
+dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter,
+				     DBusError *error,
+				     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_bool_t fast_reauth;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &fast_reauth))
+		return FALSE;
+
+	wpa_s->conf->fast_reauth = fast_reauth;
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
+ * @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 "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)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_int32_t reason = wpa_s->disconnect_reason;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+						&reason, 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
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter function for "BSSExpireAge" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_expire_age(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;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&expire_age, error);
+}
+
+
+/**
+ * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "BSSExpireAge" property.
+ */
+dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
+					    DBusError *error,
+					    void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t expire_age;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &expire_age))
+		return FALSE;
+
+	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "BSSExpireAge must be >= 10");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
+ * @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 function for "BSSExpireCount" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_expire_count(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;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&expire_count, error);
+}
+
+
+/**
+ * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "BSSExpireCount" property.
+ */
+dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
+					      DBusError *error,
+					      void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_uint32_t expire_count;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &expire_count))
+		return FALSE;
+
+	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "BSSExpireCount must be > 0");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_country - Control country 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 function for "Country" property.
+ */
+dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char country[3];
+	char *str = country;
+
+	country[0] = wpa_s->conf->country[0];
+	country[1] = wpa_s->conf->country[1];
+	country[2] = '\0';
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&str, error);
+}
+
+
+/**
+ * wpas_dbus_setter_country - Control country 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
+ *
+ * Setter function for "Country" property.
+ */
+dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *country;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &country))
+		return FALSE;
+
+	if (!country[0] || !country[1]) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "invalid country code");
+		return FALSE;
+	}
+
+	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
+		wpa_printf(MSG_DEBUG, "Failed to set country");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to set country code");
+		return FALSE;
+	}
+
+	wpa_s->conf->country[0] = country[0];
+	wpa_s->conf->country[1] = country[1];
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_scan_interval - Get scan interval
+ * @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 function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_getter_scan_interval(DBusMessageIter *iter,
+					   DBusError *error,
+					   void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_int32_t scan_interval = wpa_s->scan_interval;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+						&scan_interval, error);
+}
+
+
+/**
+ * wpas_dbus_setter_scan_interval - Control scan interval
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter function for "ScanInterval" property.
+ */
+dbus_bool_t wpas_dbus_setter_scan_interval(DBusMessageIter *iter,
+					   DBusError *error,
+					   void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_int32_t scan_interval;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
+					      &scan_interval))
+		return FALSE;
+
+	if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "scan_interval must be >= 0");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_ifname - Get interface name
+ * @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 "Ifname" property.
+ */
+dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
+				    void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *ifname = wpa_s->ifname;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&ifname, error);
+}
+
+
+/**
+ * wpas_dbus_getter_driver - Get interface name
+ * @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 "Driver" property.
+ */
+dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
+				    void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *driver;
+
+	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
+		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
+			   "wpa_s has no driver set");
+		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
+			       __func__);
+		return FALSE;
+	}
+
+	driver = wpa_s->driver->name;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&driver, error);
+}
+
+
+/**
+ * wpas_dbus_getter_current_bss - Get current bss object 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 "CurrentBSS" property.
+ */
+dbus_bool_t wpas_dbus_getter_current_bss(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;
+
+	if (wpa_s->current_bss)
+		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+			    wpa_s->dbus_new_path, wpa_s->current_bss->id);
+	else
+		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&bss_obj_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_current_network - Get current network object 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 "CurrentNetwork" property.
+ */
+dbus_bool_t wpas_dbus_getter_current_network(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;
+
+	if (wpa_s->current_ssid)
+		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+			    wpa_s->dbus_new_path, wpa_s->current_ssid->id);
+	else
+		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&net_obj_path, error);
+}
+
+
+/**
+ * wpas_dbus_getter_current_auth_mode - Get current authentication type
+ * @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 "CurrentAuthMode" property.
+ */
+dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *eap_mode;
+	const char *auth_mode;
+	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
+
+	if (wpa_s->wpa_state != WPA_COMPLETED) {
+		auth_mode = "INACTIVE";
+	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
+		os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
+			    "EAP-%s", eap_mode);
+		auth_mode = eap_mode_buf;
+
+	} else {
+		auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
+					     wpa_s->current_ssid->proto);
+	}
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&auth_mode, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bridge_ifname - Get interface name
+ * @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 "BridgeIfname" property.
+ */
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+					   DBusError *error,
+					   void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *bridge_ifname = wpa_s->bridge_ifname;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&bridge_ifname, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bsss - Get array of BSSs objects
+ * @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 "BSSs" property.
+ */
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+				  void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct wpa_bss *bss;
+	char **paths;
+	unsigned int i = 0;
+	dbus_bool_t success = FALSE;
+
+	paths = os_calloc(wpa_s->num_bss, sizeof(char *));
+	if (!paths) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	/* Loop through scan results and append each result's object path */
+	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (paths[i] == NULL) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			goto out;
+		}
+		/* Construct the object path for this BSS. */
+		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
+			    wpa_s->dbus_new_path, bss->id);
+	}
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, wpa_s->num_bss,
+							 error);
+
+out:
+	while (i)
+		os_free(paths[--i]);
+	os_free(paths);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_networks - Get array of networks objects
+ * @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 "Networks" property.
+ */
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct wpa_ssid *ssid;
+	char **paths;
+	unsigned int i = 0, num = 0;
+	dbus_bool_t success = FALSE;
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
+			   "networks list.", __func__);
+		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
+			       "occurred getting the networks list", __func__);
+		return FALSE;
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+		if (!network_is_persistent_group(ssid))
+			num++;
+
+	paths = os_calloc(num, sizeof(char *));
+	if (!paths) {
+		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	/* Loop through configured networks and append object path of each */
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (network_is_persistent_group(ssid))
+			continue;
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (paths[i] == NULL) {
+			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+			goto out;
+		}
+
+		/* Construct the object path for this network. */
+		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
+			    wpa_s->dbus_new_path, ssid->id);
+	}
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
+
+out:
+	while (i)
+		os_free(paths[--i]);
+	os_free(paths);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_blobs - Get all blobs defined for this interface
+ * @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 "Blobs" property.
+ */
+dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
+				   void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+	struct wpa_config_blob *blob;
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{say}", &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      "{say}", &dict_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	blob = wpa_s->conf->blobs;
+	while (blob) {
+		if (!dbus_message_iter_open_container(&dict_iter,
+						      DBUS_TYPE_DICT_ENTRY,
+						      NULL, &entry_iter) ||
+		    !dbus_message_iter_append_basic(&entry_iter,
+						    DBUS_TYPE_STRING,
+						    &(blob->name)) ||
+		    !dbus_message_iter_open_container(&entry_iter,
+						      DBUS_TYPE_ARRAY,
+						      DBUS_TYPE_BYTE_AS_STRING,
+						      &array_iter) ||
+		    !dbus_message_iter_append_fixed_array(&array_iter,
+							  DBUS_TYPE_BYTE,
+							  &(blob->data),
+							  blob->len) ||
+		    !dbus_message_iter_close_container(&entry_iter,
+						       &array_iter) ||
+		    !dbus_message_iter_close_container(&dict_iter,
+						       &entry_iter)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			return FALSE;
+		}
+
+		blob = blob->next;
+	}
+
+	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
+				       DBusError *error, const char *func_name)
+{
+	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
+
+	if (!res) {
+		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
+		           func_name, args->id);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: BSS %d not found",
+			       func_name, args->id);
+	}
+
+	return res;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
+ * @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 "BSSID" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res->bssid, ETH_ALEN,
+						      error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
+ * @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 "SSID" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res->ssid, res->ssid_len,
+						      error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
+ * @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 "Privacy" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+					 DBusError *error, void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	dbus_bool_t privacy;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&privacy, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_mode - Return the mode of a BSS
+ * @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 "Mode" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	const char *mode;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	if (res->caps & IEEE80211_CAP_IBSS)
+		mode = "ad-hoc";
+	else
+		mode = "infrastructure";
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&mode, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
+ * @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 "Level" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+					DBusError *error, void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	s16 level;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	level = (s16) res->level;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
+						&level, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
+ * @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 "Frequency" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+					   DBusError *error, void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	u16 freq;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	freq = (u16) res->freq;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+						&freq, error);
+}
+
+
+static int cmp_u8s_desc(const void *a, const void *b)
+{
+	return (*(u8 *) b - *(u8 *) a);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
+ * @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 "Rates" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+				       DBusError *error, void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	u8 *ie_rates = NULL;
+	u32 *real_rates;
+	int rates_num, i;
+	dbus_bool_t success = FALSE;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
+	if (rates_num < 0)
+		return FALSE;
+
+	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
+
+	real_rates = os_malloc(sizeof(u32) * rates_num);
+	if (!real_rates) {
+		os_free(ie_rates);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	for (i = 0; i < rates_num; i++)
+		real_rates[i] = ie_rates[i] * 500000;
+
+	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
+							 real_rates, rates_num,
+							 error);
+
+	os_free(ie_rates);
+	os_free(real_rates);
+	return success;
+}
+
+
+static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
+						   struct wpa_ie_data *ie_data,
+						   DBusError *error)
+{
+	DBusMessageIter iter_dict, variant_iter;
+	const char *group;
+	const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
+	const char *key_mgmt[7]; /* max 7 key managements may be supported */
+	int n;
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+		goto nomem;
+
+	/* KeyMgmt */
+	n = 0;
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
+		key_mgmt[n++] = "wpa-psk";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
+		key_mgmt[n++] = "wpa-ft-psk";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		key_mgmt[n++] = "wpa-psk-sha256";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+		key_mgmt[n++] = "wpa-eap";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+		key_mgmt[n++] = "wpa-ft-eap";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		key_mgmt[n++] = "wpa-eap-sha256";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
+		key_mgmt[n++] = "wpa-none";
+
+	if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
+					       key_mgmt, n))
+		goto nomem;
+
+	/* Group */
+	switch (ie_data->group_cipher) {
+	case WPA_CIPHER_WEP40:
+		group = "wep40";
+		break;
+	case WPA_CIPHER_TKIP:
+		group = "tkip";
+		break;
+	case WPA_CIPHER_CCMP:
+		group = "ccmp";
+		break;
+	case WPA_CIPHER_GCMP:
+		group = "gcmp";
+		break;
+	case WPA_CIPHER_WEP104:
+		group = "wep104";
+		break;
+	default:
+		group = "";
+		break;
+	}
+
+	if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
+		goto nomem;
+
+	/* Pairwise */
+	n = 0;
+	if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
+		pairwise[n++] = "tkip";
+	if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
+		pairwise[n++] = "ccmp";
+	if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
+		pairwise[n++] = "gcmp";
+
+	if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
+					       pairwise, n))
+		goto nomem;
+
+	/* Management group (RSN only) */
+	if (ie_data->proto == WPA_PROTO_RSN) {
+		switch (ie_data->mgmt_group_cipher) {
+#ifdef CONFIG_IEEE80211W
+		case WPA_CIPHER_AES_128_CMAC:
+			group = "aes128cmac";
+			break;
+#endif /* CONFIG_IEEE80211W */
+		default:
+			group = "";
+			break;
+		}
+
+		if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
+						 group))
+			goto nomem;
+	}
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+		goto nomem;
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto nomem;
+
+	return TRUE;
+
+nomem:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
+ * @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 "WPA" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	struct wpa_ie_data wpa_data;
+	const u8 *ie;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	os_memset(&wpa_data, 0, sizeof(wpa_data));
+	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
+	if (ie) {
+		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+			dbus_set_error_const(error, DBUS_ERROR_FAILED,
+					     "failed to parse WPA IE");
+			return FALSE;
+		}
+	}
+
+	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
+ * @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 "RSN" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+	struct wpa_ie_data wpa_data;
+	const u8 *ie;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	os_memset(&wpa_data, 0, sizeof(wpa_data));
+	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
+	if (ie) {
+		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+			dbus_set_error_const(error, DBUS_ERROR_FAILED,
+					     "failed to parse RSN IE");
+			return FALSE;
+		}
+	}
+
+	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @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 "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+#ifdef CONFIG_WPS
+	struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+	DBusMessageIter iter_dict, variant_iter;
+	const char *type = "";
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+		goto nomem;
+
+#ifdef CONFIG_WPS
+	wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+	if (wps_ie) {
+		if (wps_is_selected_pbc_registrar(wps_ie))
+			type = "pbc";
+		else if (wps_is_selected_pin_registrar(wps_ie))
+			type = "pin";
+	}
+#endif /* CONFIG_WPS */
+
+	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
+		goto nomem;
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
+		goto nomem;
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto nomem;
+
+	return TRUE;
+
+nomem:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
+}
+
+
+/**
+ * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
+ * @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 "IEs" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
+
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
+
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res + 1, res->ie_len,
+						      error);
+}
+
+
+/**
+ * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
+ * @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 "enabled" property of a configured network.
+ */
+dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct network_handler_args *net = user_data;
+	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&enabled, error);
+}
+
+
+/**
+ * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Enabled" property of a configured network.
+ */
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
+{
+	struct network_handler_args *net = user_data;
+	struct wpa_supplicant *wpa_s;
+	struct wpa_ssid *ssid;
+	dbus_bool_t enable;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &enable))
+		return FALSE;
+
+	wpa_s = net->wpa_s;
+	ssid = net->ssid;
+
+	if (enable)
+		wpa_supplicant_enable_network(wpa_s, ssid);
+	else
+		wpa_supplicant_disable_network(wpa_s, ssid);
+
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_network_properties - Get options for a configured network
+ * @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 "Properties" property of a configured network.
+ */
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
+{
+	struct network_handler_args *net = user_data;
+	DBusMessageIter	variant_iter, dict_iter;
+	char **iterator;
+	char **props = wpa_config_get_all(net->ssid, 1);
+	dbus_bool_t success = FALSE;
+
+	if (!props) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
+					      &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		goto out;
+	}
+
+	iterator = props;
+	while (*iterator) {
+		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
+						 *(iterator + 1))) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			goto out;
+		}
+		iterator += 2;
+	}
+
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		goto out;
+	}
+
+	success = TRUE;
+
+out:
+	iterator = props;
+	while (*iterator) {
+		os_free(*iterator);
+		iterator++;
+	}
+	os_free(props);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_setter_network_properties - Set options for a configured network
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Properties" property of a configured network.
+ */
+dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
+{
+	struct network_handler_args *net = user_data;
+	struct wpa_ssid *ssid = net->ssid;
+	DBusMessageIter	variant_iter;
+
+	dbus_message_iter_recurse(iter, &variant_iter);
+	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
+}
+
+
+#ifdef CONFIG_AP
+
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+	char *name;
+
+	if (wpa_s->preq_notify_peer != NULL) {
+		if (os_strcmp(dbus_message_get_sender(message),
+			      wpa_s->preq_notify_peer) == 0)
+			return NULL;
+
+		return dbus_message_new_error(message,
+			WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
+			"Another application is already subscribed");
+	}
+
+	name = os_strdup(dbus_message_get_sender(message));
+	if (!name)
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      "out of memory");
+
+	wpa_s->preq_notify_peer = name;
+
+	/* Subscribe to clean up if application closes socket */
+	wpas_dbus_subscribe_noc(priv);
+
+	/*
+	 * Double-check it's still alive to make sure that we didn't
+	 * miss the NameOwnerChanged signal, e.g. while strdup'ing.
+	 */
+	if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
+		/*
+		 * Application no longer exists, clean up.
+		 * The return value is irrelevant now.
+		 *
+		 * Need to check if the NameOwnerChanged handling
+		 * already cleaned up because we have processed
+		 * DBus messages while checking if the name still
+		 * has an owner.
+		 */
+		if (!wpa_s->preq_notify_peer)
+			return NULL;
+		os_free(wpa_s->preq_notify_peer);
+		wpa_s->preq_notify_peer = NULL;
+		wpas_dbus_unsubscribe_noc(priv);
+	}
+
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+	if (!wpa_s->preq_notify_peer)
+		return dbus_message_new_error(message,
+			WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
+			"Not subscribed");
+
+	if (os_strcmp(wpa_s->preq_notify_peer,
+		      dbus_message_get_sender(message)))
+		return dbus_message_new_error(message,
+			WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
+			"Can't unsubscribe others");
+
+	os_free(wpa_s->preq_notify_peer);
+	wpa_s->preq_notify_peer = NULL;
+	wpas_dbus_unsubscribe_noc(priv);
+	return NULL;
+}
+
+
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+			   const u8 *addr, const u8 *dst, const u8 *bssid,
+			   const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	struct wpas_dbus_priv *priv = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (priv == NULL)
+		return;
+
+	if (wpa_s->preq_notify_peer == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "ProbeRequest");
+	if (msg == NULL)
+		return;
+
+	dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto fail;
+	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+						     (const char *) addr,
+						     ETH_ALEN))
+		goto fail;
+	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+						    (const char *) dst,
+						    ETH_ALEN))
+		goto fail;
+	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+						      (const char *) bssid,
+						      ETH_ALEN))
+		goto fail;
+	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+							     (const char *) ie,
+							     ie_len))
+		goto fail;
+	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+						      ssi_signal))
+		goto fail;
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto fail;
+
+	dbus_connection_send(priv->con, msg, NULL);
+	goto out;
+fail:
+	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+out:
+	dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_AP */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,196 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
-#define CTRL_IFACE_DBUS_NEW_HANDLERS_H
-
-struct network_handler_args {
-	struct wpa_supplicant *wpa_s;
-	struct wpa_ssid *ssid;
-};
-
-struct bss_handler_args {
-	struct wpa_supplicant *wpa_s;
-	unsigned int id;
-};
-
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-					       const int type,
-					       const void *val);
-
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-					       const int type, void *val);
-
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-						     const int type,
-						     const void *array,
-						     size_t array_len);
-
-DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
-						 struct wpa_global *global);
-
-DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
-						 struct wpa_global *global);
-
-DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
-					      struct wpa_global *global);
-
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-					   struct wpa_global *global);
-
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global);
-
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global);
-
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-					   struct wpa_global *global);
-
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global);
-
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global);
-
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-					  struct wpa_global *global);
-
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message,
-					   void *nothing);
-
-DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-					struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-				    struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-					struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-				     struct wpa_supplicant *bss);
-
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-					 struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-					struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-					   struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-					struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-					  struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-					     struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-					 struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-				       struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-				       struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-				       struct bss_handler_args *bss);
-
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-				       struct network_handler_args *net);
-
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-				       struct network_handler_args *net);
-
-DBusMessage * wpas_dbus_getter_network_properties(
-	DBusMessage *message, struct network_handler_args *net);
-
-DBusMessage * wpas_dbus_setter_network_properties(
-	DBusMessage *message, struct network_handler_args *net);
-
-DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_setter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_credentials(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,
-					    const char *arg);
-
-#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,285 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009-2010, Witold Sowa <witold.sowa at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_NEW_HANDLERS_H
+#define CTRL_IFACE_DBUS_NEW_HANDLERS_H
+
+struct network_handler_args {
+	struct wpa_supplicant *wpa_s;
+	struct wpa_ssid *ssid;
+};
+
+struct bss_handler_args {
+	struct wpa_supplicant *wpa_s;
+	unsigned int id;
+};
+
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+					     const int type,
+					     const void *val,
+					     DBusError *error);
+
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+					     DBusError *error,
+					     const int type, void *val);
+
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+						   const int type,
+						   const void *array,
+						   size_t array_len,
+						   DBusError *error);
+
+dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
+							 const int type,
+							 struct wpabuf **array,
+							 size_t array_len,
+							 DBusError *error);
+
+DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
+						 struct wpa_global *global);
+
+DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
+						 struct wpa_global *global);
+
+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_scan(DBusMessage *message,
+				     struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid,
+				   DBusMessageIter *iter,
+				   DBusError *error);
+
+DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_networks(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_autoscan(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_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_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);
+
+DBusMessage * wpas_dbus_handler_wps_start(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);
+
+DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
+					   const char *arg);
+DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
+					    const char *arg);
+
+DBusMessage * wpas_dbus_handler_subscribe_preq(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_unsubscribe_preq(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers_p2p.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2438 @@
+/*
+ * WPA Supplicant / dbus-based control interface (P2P)
+ * Copyright (c) 2011-2012, Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/includes.h"
+#include "common.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "../notify.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_new_handlers_p2p.h"
+#include "dbus_dict_helpers.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/wps_hostapd.h"
+
+#include "../p2p_supplicant.h"
+
+/**
+ * Parses out the mac address from the peer object path.
+ * @peer_path - object path of the form
+ *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
+ * @addr - out param must be of ETH_ALEN size
+ * Returns 0 if valid (including MAC), -1 otherwise
+ */
+static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+{
+	char *p;
+
+	if (!peer_path)
+		return -1;
+	p = os_strrchr(peer_path, '/');
+	if (!p)
+		return -1;
+	p++;
+	return hwaddr_compact_aton(p, addr);
+}
+
+
+/**
+ * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
+ * error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid persistent group error.
+ */
+static DBusMessage * wpas_dbus_error_persistent_group_unknown(
+	DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+				      "There is no such persistent group in "
+				      "this P2P device.");
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
+{
+	struct wpa_dbus_dict_entry entry;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+	unsigned int timeout = 0;
+	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+	int num_req_dev_types = 0;
+	unsigned int i;
+	u8 *req_dev_types = NULL;
+
+	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "Timeout") &&
+		    (entry.type == DBUS_TYPE_INT32)) {
+			timeout = entry.uint32_value;
+		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+				goto error_clear;
+
+			os_free(req_dev_types);
+			req_dev_types =
+				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
+			if (!req_dev_types)
+				goto error_clear;
+
+			for (i = 0; i < entry.array_len; i++) {
+				if (wpabuf_len(entry.binarray_value[i]) !=
+							WPS_DEV_TYPE_LEN)
+					goto error_clear;
+				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
+					  wpabuf_head(entry.binarray_value[i]),
+					  WPS_DEV_TYPE_LEN);
+			}
+			num_req_dev_types = entry.array_len;
+		} else if (!os_strcmp(entry.key, "DiscoveryType") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			if (!os_strcmp(entry.str_value, "start_with_full"))
+				type = P2P_FIND_START_WITH_FULL;
+			else if (!os_strcmp(entry.str_value, "social"))
+				type = P2P_FIND_ONLY_SOCIAL;
+			else if (!os_strcmp(entry.str_value, "progressive"))
+				type = P2P_FIND_PROGRESSIVE;
+			else
+				goto error_clear;
+		} else
+			goto error_clear;
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
+		      NULL, 0);
+	os_free(req_dev_types);
+	return reply;
+
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	os_free(req_dev_types);
+	reply = wpas_dbus_error_invalid_args(message, entry.key);
+	return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	wpas_p2p_stop_find(wpa_s);
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	char *peer_object_path = NULL;
+	u8 peer_addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to call wpas_p2p_reject method.");
+
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	dbus_int32_t timeout = 0;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
+				   DBUS_TYPE_INVALID))
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+
+	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	unsigned int period = 0, interval = 0;
+	struct wpa_dbus_dict_entry entry;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "period") &&
+		    (entry.type == DBUS_TYPE_INT32))
+			period = entry.uint32_value;
+		else if (!os_strcmp(entry.key, "interval") &&
+			 (entry.type == DBUS_TYPE_INT32))
+			interval = entry.uint32_value;
+		else
+			goto error_clear;
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (wpas_p2p_ext_listen(wpa_s, period, interval))
+		return wpas_dbus_error_unknown_error(
+			message, "failed to initiate a p2p_ext_listen.");
+
+	return NULL;
+
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_presence_request(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+	struct wpa_dbus_dict_entry entry;
+	DBusMessageIter iter;
+	DBusMessageIter iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "duration1") &&
+		    (entry.type == DBUS_TYPE_INT32))
+			dur1 = entry.uint32_value;
+		else if (!os_strcmp(entry.key, "interval1") &&
+			 entry.type == DBUS_TYPE_INT32)
+			int1 = entry.uint32_value;
+		else if (!os_strcmp(entry.key, "duration2") &&
+			 entry.type == DBUS_TYPE_INT32)
+			dur2 = entry.uint32_value;
+		else if (!os_strcmp(entry.key, "interval2") &&
+			 entry.type == DBUS_TYPE_INT32)
+			int2 = entry.uint32_value;
+		else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to invoke presence request.");
+
+	return NULL;
+
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *pg_object_path = NULL;
+	int persistent_group = 0;
+	int freq = 0;
+	char *iface = NULL;
+	char *net_id_str = NULL;
+	unsigned int group_id = 0;
+	struct wpa_ssid *ssid;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto inv_args;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto inv_args;
+
+		if (!os_strcmp(entry.key, "persistent") &&
+		    (entry.type == DBUS_TYPE_BOOLEAN)) {
+			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!os_strcmp(entry.key, "frequency") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			freq = entry.int32_value;
+			if (freq <= 0)
+				goto inv_args_clear;
+		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
+			   entry.type == DBUS_TYPE_OBJECT_PATH)
+			pg_object_path = os_strdup(entry.str_value);
+		else
+			goto inv_args_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (pg_object_path != NULL) {
+		/*
+		 * A persistent group Object Path is defined meaning we want
+		 * to re-invoke a persistent group.
+		 */
+
+		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+							    &net_id_str, NULL);
+		if (iface == NULL ||
+		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+			reply =
+			    wpas_dbus_error_invalid_args(message,
+							 pg_object_path);
+			goto out;
+		}
+
+		group_id = strtoul(net_id_str, NULL, 10);
+		if (errno == EINVAL) {
+			reply = wpas_dbus_error_invalid_args(
+						message, pg_object_path);
+			goto out;
+		}
+
+		/* Get the SSID structure from the persistent group id */
+		ssid = wpa_config_get_network(wpa_s->conf, group_id);
+		if (ssid == NULL || ssid->disabled != 2)
+			goto inv_args;
+
+		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 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))
+		goto inv_args;
+
+out:
+	os_free(pg_object_path);
+	os_free(net_id_str);
+	os_free(iface);
+	return reply;
+inv_args_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
+{
+	if (wpas_p2p_disconnect(wpa_s))
+		return wpas_dbus_error_unknown_error(message,
+						"failed to disconnect");
+
+	return NULL;
+}
+
+
+static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
+					      DBusMessage *message,
+					      DBusMessage **out_reply,
+					      DBusError *error)
+{
+	/* Return an error message or an error if P2P isn't available */
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+		if (out_reply) {
+			*out_reply = dbus_message_new_error(
+				message, DBUS_ERROR_FAILED,
+				"P2P is not available for this interface");
+		}
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "P2P is not available for this "
+				     "interface");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
+	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+	wpa_s->force_long_sd = 0;
+	p2p_flush(wpa_s->global->p2p);
+
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *peer_object_path = NULL;
+	int persistent_group = 0;
+	int join = 0;
+	int authorize_only = 0;
+	int go_intent = -1;
+	int freq = 0;
+	u8 addr[ETH_ALEN];
+	char *pin = NULL;
+	enum p2p_wps_method wps_method = WPS_NOT_READY;
+	int new_pin;
+	char *err_msg = NULL;
+	char *iface = NULL;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto inv_args;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto inv_args;
+
+		if (!os_strcmp(entry.key, "peer") &&
+		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!os_strcmp(entry.key, "persistent") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!os_strcmp(entry.key, "join") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			join = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!os_strcmp(entry.key, "authorize_only") &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
+		} else if (!os_strcmp(entry.key, "frequency") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			freq = entry.int32_value;
+			if (freq <= 0)
+				goto inv_args_clear;
+		} else if (!os_strcmp(entry.key, "go_intent") &&
+			   (entry.type == DBUS_TYPE_INT32)) {
+			go_intent = entry.int32_value;
+			if ((go_intent < 0) || (go_intent > 15))
+				goto inv_args_clear;
+		} else if (!os_strcmp(entry.key, "wps_method") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			if (!os_strcmp(entry.str_value, "pbc"))
+				wps_method = WPS_PBC;
+			else if (!os_strcmp(entry.str_value, "pin"))
+				wps_method = WPS_PIN_DISPLAY;
+			else if (!os_strcmp(entry.str_value, "display"))
+				wps_method = WPS_PIN_DISPLAY;
+			else if (!os_strcmp(entry.str_value, "keypad"))
+				wps_method = WPS_PIN_KEYPAD;
+			else
+				goto inv_args_clear;
+		} else if (!os_strcmp(entry.key, "pin") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			pin = os_strdup(entry.str_value);
+		} else
+			goto inv_args_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
+	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	    !p2p_peer_known(wpa_s->global->p2p, addr))
+		goto inv_args;
+
+	/*
+	 * Validate the wps_method specified and the pin value.
+	 */
+	if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+		goto inv_args;
+
+	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+				   persistent_group, 0, join, authorize_only,
+				   go_intent, freq, -1, 0, 0);
+
+	if (new_pin >= 0) {
+		char npin[9];
+		char *generated_pin;
+		os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+		generated_pin = npin;
+		reply = dbus_message_new_method_return(message);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING,
+					 &generated_pin, DBUS_TYPE_INVALID);
+	} else {
+		switch (new_pin) {
+		case -2:
+			err_msg = "connect failed due to channel "
+				"unavailability.";
+			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
+			break;
+
+		case -3:
+			err_msg = "connect failed due to unsupported channel.";
+			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
+			break;
+
+		default:
+			err_msg = "connect failed due to unspecified error.";
+			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
+			break;
+		}
+
+		/*
+		 * TODO:
+		 * Do we need specialized errors corresponding to above
+		 * error conditions as against just returning a different
+		 * error message?
+		 */
+		reply = dbus_message_new_error(message, iface, err_msg);
+	}
+
+out:
+	os_free(peer_object_path);
+	os_free(pin);
+	return reply;
+inv_args_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *peer_object_path = NULL;
+	char *pg_object_path = NULL;
+	char *iface = NULL;
+	char *net_id_str = NULL;
+	u8 peer_addr[ETH_ALEN];
+	unsigned int group_id = 0;
+	int persistent = 0;
+	struct wpa_ssid *ssid;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto err;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto err;
+
+		if (!os_strcmp(entry.key, "peer") &&
+		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			peer_object_path = os_strdup(entry.str_value);
+			wpa_dbus_dict_entry_clear(&entry);
+		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
+			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+			pg_object_path = os_strdup(entry.str_value);
+			persistent = 1;
+			wpa_dbus_dict_entry_clear(&entry);
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto err;
+		}
+	}
+
+	if (!peer_object_path ||
+	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
+	    !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
+		goto err;
+	}
+
+	if (persistent) {
+		/*
+		 * A group ID is defined meaning we want to re-invoke a
+		 * persistent group
+		 */
+
+		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+							    &net_id_str, NULL);
+		if (iface == NULL ||
+		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+			reply = wpas_dbus_error_invalid_args(message,
+							     pg_object_path);
+			goto out;
+		}
+
+		group_id = strtoul(net_id_str, NULL, 10);
+		if (errno == EINVAL) {
+			reply = wpas_dbus_error_invalid_args(
+				message, pg_object_path);
+			goto out;
+		}
+
+		/* Get the SSID structure from the persistent group id */
+		ssid = wpa_config_get_network(wpa_s->conf, group_id);
+		if (ssid == NULL || ssid->disabled != 2)
+			goto err;
+
+		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) {
+			reply = wpas_dbus_error_unknown_error(
+				message,
+				"Failed to reinvoke a persistent group");
+			goto out;
+		}
+	} else {
+		/*
+		 * No group ID means propose to a peer to join my active group
+		 */
+		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
+					  peer_addr, NULL)) {
+			reply = wpas_dbus_error_unknown_error(
+				message, "Failed to join to an active group");
+			goto out;
+		}
+	}
+
+out:
+	os_free(pg_object_path);
+	os_free(peer_object_path);
+	return reply;
+
+err:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	char *peer_object_path = NULL;
+	char *config_method = NULL;
+	u8 peer_addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_get_basic(&iter, &config_method);
+
+	/*
+	 * Validation checks on config_method are being duplicated here
+	 * to be able to return invalid args reply since the error code
+	 * from p2p module are not granular enough (yet).
+	 */
+	if (os_strcmp(config_method, "display") &&
+	    os_strcmp(config_method, "keypad") &&
+	    os_strcmp(config_method, "pbc") &&
+	    os_strcmp(config_method, "pushbutton"))
+		return wpas_dbus_error_invalid_args(message, NULL);
+
+	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
+			       WPAS_P2P_PD_FOR_GO_NEG) < 0)
+		return wpas_dbus_error_unknown_error(message,
+				"Failed to send provision discovery request");
+
+	return NULL;
+}
+
+
+/*
+ * P2P Device property accessor methods.
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter;
+	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
+		iter_secdev_dict_array;
+	const char *dev_name;
+	int num_vendor_extensions = 0;
+	int i;
+	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+		goto err_no_mem;
+
+	/* DeviceName */
+	dev_name = wpa_s->conf->device_name;
+	if (dev_name &&
+	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
+		goto err_no_mem;
+
+	/* Primary device type */
+	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
+	    				     (char *)wpa_s->conf->device_type,
+	    				     WPS_DEV_TYPE_LEN))
+		goto err_no_mem;
+
+	/* Secondary device types */
+	if (wpa_s->conf->num_sec_device_types) {
+		if (!wpa_dbus_dict_begin_array(&dict_iter,
+					       "SecondaryDeviceTypes",
+					       DBUS_TYPE_ARRAY_AS_STRING
+					       DBUS_TYPE_BYTE_AS_STRING,
+					       &iter_secdev_dict_entry,
+					       &iter_secdev_dict_val,
+					       &iter_secdev_dict_array))
+			goto err_no_mem;
+
+		for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
+			wpa_dbus_dict_bin_array_add_element(
+				&iter_secdev_dict_array,
+				wpa_s->conf->sec_device_type[i],
+				WPS_DEV_TYPE_LEN);
+
+		if (!wpa_dbus_dict_end_array(&dict_iter,
+					     &iter_secdev_dict_entry,
+					     &iter_secdev_dict_val,
+					     &iter_secdev_dict_array))
+			goto err_no_mem;
+	}
+
+	/* Vendor Extensions */
+	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+			continue;
+		vendor_ext[num_vendor_extensions++] =
+			wpa_s->conf->wps_vendor_ext[i];
+	}
+
+	if (num_vendor_extensions &&
+	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+					       "VendorExtension",
+					       vendor_ext,
+					       num_vendor_extensions))
+		goto err_no_mem;
+
+	/* GO Intent */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+					 wpa_s->conf->p2p_go_intent))
+		goto err_no_mem;
+
+	/* Persistent Reconnect */
+	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
+				       wpa_s->conf->persistent_reconnect))
+		goto err_no_mem;
+
+	/* Listen Reg Class */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+					 wpa_s->conf->p2p_listen_reg_class))
+		goto err_no_mem;
+
+	/* Listen Channel */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+					 wpa_s->conf->p2p_listen_channel))
+		goto err_no_mem;
+
+	/* Oper Reg Class */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+					 wpa_s->conf->p2p_oper_reg_class))
+		goto err_no_mem;
+
+	/* Oper Channel */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+					 wpa_s->conf->p2p_oper_channel))
+		goto err_no_mem;
+
+	/* SSID Postfix */
+	if (wpa_s->conf->p2p_ssid_postfix &&
+	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+					 wpa_s->conf->p2p_ssid_postfix))
+		goto err_no_mem;
+
+	/* Intra Bss */
+	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+				       wpa_s->conf->p2p_intra_bss))
+		goto err_no_mem;
+
+	/* Group Idle */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+					 wpa_s->conf->p2p_group_idle))
+		goto err_no_mem;
+
+	/* Dissasociation low ack */
+	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+					 wpa_s->conf->disassoc_low_ack))
+		goto err_no_mem;
+
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
+		goto err_no_mem;
+
+	return TRUE;
+
+err_no_mem:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, iter_dict;
+	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+	unsigned int i;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
+
+	dbus_message_iter_recurse(iter, &variant_iter);
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+		return FALSE;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+					     "invalid message format");
+			return FALSE;
+		}
+
+		if (os_strcmp(entry.key, "DeviceName") == 0) {
+			char *devname;
+
+			if (entry.type != DBUS_TYPE_STRING)
+				goto error;
+
+			devname = os_strdup(entry.str_value);
+			if (devname == NULL)
+				goto err_no_mem_clear;
+
+			os_free(wpa_s->conf->device_name);
+			wpa_s->conf->device_name = devname;
+
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_DEVICE_NAME;
+		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE ||
+			    entry.array_len != WPS_DEV_TYPE_LEN)
+				goto error;
+
+			os_memcpy(wpa_s->conf->device_type,
+				  entry.bytearray_value,
+				  WPS_DEV_TYPE_LEN);
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_DEVICE_TYPE;
+		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+			    entry.array_len > MAX_SEC_DEVICE_TYPES)
+				goto error;
+
+			for (i = 0; i < entry.array_len; i++)
+				if (wpabuf_len(entry.binarray_value[i]) !=
+				    WPS_DEV_TYPE_LEN)
+					goto err_no_mem_clear;
+			for (i = 0; i < entry.array_len; i++)
+				os_memcpy(wpa_s->conf->sec_device_type[i],
+					  wpabuf_head(entry.binarray_value[i]),
+					  WPS_DEV_TYPE_LEN);
+			wpa_s->conf->num_sec_device_types = entry.array_len;
+			wpa_s->conf->changed_parameters |=
+					CFG_CHANGED_SEC_DEVICE_TYPE;
+		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
+				goto error;
+
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_VENDOR_EXTENSION;
+
+			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
+				if (i < entry.array_len) {
+					wpa_s->conf->wps_vendor_ext[i] =
+						entry.binarray_value[i];
+					entry.binarray_value[i] = NULL;
+				} else
+					wpa_s->conf->wps_vendor_ext[i] = NULL;
+			}
+		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32) &&
+			   (entry.uint32_value <= 15))
+			wpa_s->conf->p2p_go_intent = entry.uint32_value;
+		else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
+			 (entry.type == DBUS_TYPE_BOOLEAN))
+			wpa_s->conf->persistent_reconnect = entry.bool_value;
+		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
+			 (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_LISTEN_CHANNEL;
+		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_LISTEN_CHANNEL;
+		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_OPER_CHANNEL;
+		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32)) {
+			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_OPER_CHANNEL;
+		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
+			char *postfix;
+
+			if (entry.type != DBUS_TYPE_STRING)
+				goto error;
+
+			postfix = os_strdup(entry.str_value);
+			if (!postfix)
+				goto err_no_mem_clear;
+
+			os_free(wpa_s->conf->p2p_ssid_postfix);
+			wpa_s->conf->p2p_ssid_postfix = postfix;
+
+			wpa_s->conf->changed_parameters |=
+					CFG_CHANGED_P2P_SSID_POSTFIX;
+		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
+			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+			wpa_s->conf->p2p_intra_bss = entry.bool_value;
+			wpa_s->conf->changed_parameters |=
+				CFG_CHANGED_P2P_INTRA_BSS;
+		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
+			   (entry.type == DBUS_TYPE_UINT32))
+			wpa_s->conf->p2p_group_idle = entry.uint32_value;
+		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
+			 entry.type == DBUS_TYPE_UINT32)
+			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
+		else
+			goto error;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (wpa_s->conf->changed_parameters) {
+		/* Some changed parameters requires to update config*/
+		wpa_supplicant_update_config(wpa_s);
+	}
+
+	return TRUE;
+
+ error:
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	wpa_dbus_dict_entry_clear(&entry);
+	return FALSE;
+
+ err_no_mem_clear:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	wpa_dbus_dict_entry_clear(&entry);
+	return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+	int next = 0, i = 0;
+	int num = 0, out_of_mem = 0;
+	const u8 *addr;
+	const struct p2p_peer_info *peer_info = NULL;
+	dbus_bool_t success = FALSE;
+
+	struct dl_list peer_objpath_list;
+	struct peer_objpath_node {
+		struct dl_list list;
+		char path[WPAS_DBUS_OBJECT_PATH_MAX];
+	} *node, *tmp;
+
+	char **peer_obj_paths = NULL;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
+
+	dl_list_init(&peer_objpath_list);
+
+	/* Get the first peer info */
+	peer_info = p2p_get_peer_found(p2p, NULL, next);
+
+	/* Get next and accumulate them */
+	next = 1;
+	while (peer_info != NULL) {
+		node = os_zalloc(sizeof(struct peer_objpath_node));
+		if (!node) {
+			out_of_mem = 1;
+			goto error;
+		}
+
+		addr = peer_info->p2p_device_addr;
+		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
+			    "/" COMPACT_MACSTR,
+			    wpa_s->dbus_new_path, MAC2STR(addr));
+		dl_list_add_tail(&peer_objpath_list, &node->list);
+		num++;
+
+		peer_info = p2p_get_peer_found(p2p, addr, next);
+	}
+
+	/*
+	 * Now construct the peer object paths in a form suitable for
+	 * array_property_getter helper below.
+	 */
+	peer_obj_paths = os_calloc(num, sizeof(char *));
+
+	if (!peer_obj_paths) {
+		out_of_mem = 1;
+		goto error;
+	}
+
+	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+			      struct peer_objpath_node, list)
+		peer_obj_paths[i++] = node->path;
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 peer_obj_paths, num,
+							 error);
+
+error:
+	if (peer_obj_paths)
+		os_free(peer_obj_paths);
+
+	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+			      struct peer_objpath_node, list) {
+		dl_list_del(&node->list);
+		os_free(node);
+	}
+	if (out_of_mem)
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+
+	return success;
+}
+
+
+enum wpas_p2p_role {
+	WPAS_P2P_ROLE_DEVICE,
+	WPAS_P2P_ROLE_GO,
+	WPAS_P2P_ROLE_CLIENT,
+};
+
+static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (!ssid)
+		return WPAS_P2P_ROLE_DEVICE;
+	if (wpa_s->wpa_state != WPA_COMPLETED)
+		return WPAS_P2P_ROLE_DEVICE;
+
+	switch (ssid->mode) {
+	case WPAS_MODE_P2P_GO:
+	case WPAS_MODE_P2P_GROUP_FORMATION:
+		return WPAS_P2P_ROLE_GO;
+	case WPAS_MODE_INFRA:
+		if (ssid->p2p_group)
+			return WPAS_P2P_ROLE_CLIENT;
+		return WPAS_P2P_ROLE_DEVICE;
+	default:
+		return WPAS_P2P_ROLE_DEVICE;
+	}
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char *str;
+
+	switch (wpas_get_p2p_role(wpa_s)) {
+	case WPAS_P2P_ROLE_GO:
+		str = "GO";
+		break;
+	case WPAS_P2P_ROLE_CLIENT:
+		str = "client";
+		break;
+	default:
+		str = "device";
+	}
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
+						error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
+	char *dbus_groupobj_path = path_buf;
+
+	if (wpa_s->dbus_groupobj_path == NULL)
+		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "/");
+	else
+		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s", wpa_s->dbus_groupobj_path);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&dbus_groupobj_path, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peergo(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;
+
+	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
+		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
+	else
+		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+			    COMPACT_MACSTR,
+			    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
+
+	path = go_peer_obj_path;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&path, error);
+}
+
+
+/*
+ * Peer object properties accessor methods
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+	char *tmp;
+
+	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
+		return FALSE;
+
+	/* get the peer info */
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	tmp = os_strdup(info->device_name);
+	if (!tmp) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
+					      error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		os_free(tmp);
+		return FALSE;
+	}
+
+	os_free(tmp);
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						    (char *)
+						    info->pri_dev_type,
+						    WPS_DEV_TYPE_LEN, error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
+                                                    DBusError *error,
+                                                    void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+					      &info->config_methods, error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
+                                            DBusError *error,
+                                            void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+					      &info->level, error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
+                                                        DBusError *error,
+                                                        void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
+					      &info->dev_capab, error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
+						       DBusError *error,
+						       void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
+					      &info->group_capab, error)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
+	DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+	DBusMessageIter variant_iter, array_iter;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+					      DBUS_TYPE_ARRAY_AS_STRING
+					      DBUS_TYPE_ARRAY_AS_STRING
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 1", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      DBUS_TYPE_ARRAY_AS_STRING
+					      DBUS_TYPE_BYTE_AS_STRING,
+					      &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 2", __func__);
+		return FALSE;
+	}
+
+	if (info->wps_sec_dev_type_list_len) {
+		const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
+		int num_sec_device_types =
+			info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
+		int i;
+		DBusMessageIter inner_array_iter;
+
+		for (i = 0; i < num_sec_device_types; i++) {
+			if (!dbus_message_iter_open_container(
+				    &array_iter, DBUS_TYPE_ARRAY,
+				    DBUS_TYPE_BYTE_AS_STRING,
+				    &inner_array_iter)) {
+				dbus_set_error(error, DBUS_ERROR_FAILED,
+					       "%s: failed to construct "
+					       "message 3 (%d)",
+					       __func__, i);
+				return FALSE;
+			}
+
+			if (!dbus_message_iter_append_fixed_array(
+				    &inner_array_iter, DBUS_TYPE_BYTE,
+				    &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
+				dbus_set_error(error, DBUS_ERROR_FAILED,
+					       "%s: failed to construct "
+					       "message 4 (%d)",
+					       __func__, i);
+				return FALSE;
+			}
+
+			if (!dbus_message_iter_close_container(
+				    &array_iter, &inner_array_iter)) {
+				dbus_set_error(error, DBUS_ERROR_FAILED,
+					       "%s: failed to construct "
+					       "message 5 (%d)",
+					       __func__, i);
+				return FALSE;
+			}
+
+			sec_dev_type_list += WPS_DEV_TYPE_LEN;
+		}
+	}
+
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 6", __func__);
+		return FALSE;
+	}
+
+	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 7", __func__);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
+						       DBusError *error,
+						       void *user_data)
+{
+	struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+	int i, num;
+	struct peer_handler_args *peer_args = user_data;
+	const struct p2p_peer_info *info;
+
+	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+				  peer_args->p2p_device_addr, 0);
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "failed to find peer");
+		return FALSE;
+	}
+
+	/* Add WPS vendor extensions attribute */
+	for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+		if (info->wps_vendor_ext[i] == NULL)
+			continue;
+		vendor_extension[num] = info->wps_vendor_ext[i];
+		num++;
+	}
+
+	if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
+							  vendor_extension,
+							  num, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
+					  DBusError *error, void *user_data)
+{
+	dbus_bool_t success;
+	/* struct peer_handler_args *peer_args = user_data; */
+
+	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+							 NULL, 0, error);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
+ * @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 "PersistentGroups" property.
+ */
+dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct wpa_ssid *ssid;
+	char **paths;
+	unsigned int i = 0, num = 0;
+	dbus_bool_t success = FALSE;
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "An error occurred getting persistent groups list",
+			   __func__);
+		dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
+				     "occurred getting persistent groups list");
+		return FALSE;
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+		if (network_is_persistent_group(ssid))
+			num++;
+
+	paths = os_calloc(num, sizeof(char *));
+	if (!paths) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
+	}
+
+	/* Loop through configured networks and append object path of each */
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!network_is_persistent_group(ssid))
+			continue;
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (paths[i] == NULL) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			goto out;
+		}
+		/* Construct the object path for this network. */
+		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+			    wpa_s->dbus_new_path, ssid->id);
+	}
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
+
+out:
+	while (i)
+		os_free(paths[--i]);
+	os_free(paths);
+	return success;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
+ *	group
+ * @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 "Properties" property of a persistent group.
+ */
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(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);
+}
+
+
+/**
+ * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
+ *	group
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "Properties" property of a persistent group.
+ */
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
+							 DBusError *error,
+							 void *user_data)
+{
+	struct network_handler_args *net = user_data;
+	struct wpa_ssid *ssid = net->ssid;
+	DBusMessageIter	variant_iter;
+
+	/*
+	 * Leveraging the fact that persistent group object is still
+	 * represented in same manner as network within.
+	 */
+	dbus_message_iter_recurse(iter, &variant_iter);
+	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
+}
+
+
+/**
+ * wpas_dbus_new_iface_add_persistent_group - Add a new configured
+ *	persistent_group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new
+ * persistent group
+ *
+ * Handler function for "AddPersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter	iter;
+	struct wpa_ssid *ssid = NULL;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+	DBusError error;
+
+	dbus_message_iter_init(message, &iter);
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "Cannot add new persistent group", __func__);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"wpa_supplicant could not add "
+			"a persistent group on this interface.");
+		goto err;
+	}
+
+	/* Mark the ssid as being a persistent group before the notification */
+	ssid->disabled = 2;
+	ssid->p2p_persistent_group = 1;
+	wpas_notify_persistent_group_added(wpa_s, ssid);
+
+	wpa_config_set_network_defaults(ssid);
+
+	dbus_error_init(&error);
+	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: "
+			   "Control interface could not set persistent group "
+			   "properties", __func__);
+		reply = wpas_dbus_reply_new_from_error(message, &error,
+						       DBUS_ERROR_INVALID_ARGS,
+						       "Failed to set network "
+						       "properties");
+		dbus_error_free(&error);
+		goto err;
+	}
+
+	/* Construct the object path for this network. */
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+				      DBUS_TYPE_INVALID)) {
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       NULL);
+		goto err;
+	}
+
+	return reply;
+
+err:
+	if (ssid) {
+		wpas_notify_persistent_group_removed(wpa_s, ssid);
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+	}
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
+ *	group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemovePersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface = NULL, *persistent_group_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+			      DBUS_TYPE_INVALID);
+
+	/*
+	 * Extract the network ID and ensure the network is actually a child of
+	 * this interface.
+	 */
+	iface = wpas_dbus_new_decompose_object_path(op, 1,
+						    &persistent_group_id,
+						    NULL);
+	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	id = strtoul(persistent_group_id, NULL, 10);
+	if (errno == EINVAL) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_persistent_group_unknown(message);
+		goto out;
+	}
+
+	wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "error occurred when removing persistent group %d",
+			   __func__, id);
+		reply = wpas_dbus_error_unknown_error(
+			message,
+			"error removing the specified persistent group on "
+			"this interface.");
+		goto out;
+	}
+
+out:
+	os_free(iface);
+	os_free(persistent_group_id);
+	return reply;
+}
+
+
+static void remove_persistent_group(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
+{
+	wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+		wpa_printf(MSG_ERROR, "dbus: %s: "
+			   "error occurred when removing persistent group %d",
+			   __func__, ssid->id);
+		return;
+	}
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
+ * persistent groups
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllPersistentGroups" method call of a
+ * P2P Device interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid, *next;
+	struct wpa_config *config;
+
+	config = wpa_s->conf;
+	ssid = config->ssid;
+	while (ssid) {
+		next = ssid->next;
+		if (network_is_persistent_group(ssid))
+			remove_persistent_group(wpa_s, ssid);
+		ssid = next;
+	}
+	return NULL;
+}
+
+
+/*
+ * Group object properties accessor methods
+ */
+
+dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct wpa_ssid *ssid;
+	unsigned int num_members;
+	char **paths;
+	unsigned int i;
+	void *next = NULL;
+	const u8 *addr;
+	dbus_bool_t success = FALSE;
+
+	/* Verify correct role for this property */
+	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
+		return wpas_dbus_simple_array_property_getter(
+			iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
+	}
+
+	ssid = wpa_s->conf->ssid;
+	/* At present WPAS P2P_GO mode only applicable for p2p_go */
+	if (ssid->mode != WPAS_MODE_P2P_GO &&
+	    ssid->mode != WPAS_MODE_AP &&
+	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+		return FALSE;
+
+	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
+
+	paths = os_calloc(num_members, sizeof(char *));
+	if (!paths)
+		goto out_of_memory;
+
+	i = 0;
+	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
+		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+		if (!paths[i])
+			goto out_of_memory;
+		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
+			    "/" COMPACT_MACSTR,
+			    wpa_s->dbus_groupobj_path, MAC2STR(addr));
+		i++;
+	}
+
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num_members,
+							 error);
+
+	for (i = 0; i < num_members; i++)
+		os_free(paths[i]);
+	os_free(paths);
+	return success;
+
+out_of_memory:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	if (paths) {
+		for (i = 0; i < num_members; i++)
+			os_free(paths[i]);
+		os_free(paths);
+	}
+	return FALSE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
+					    DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	if (wpa_s->current_ssid == NULL)
+		return FALSE;
+	return wpas_dbus_simple_array_property_getter(
+		iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
+		wpa_s->current_ssid->ssid_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	u8 role = wpas_get_p2p_role(wpa_s);
+	u8 *p_bssid;
+
+	if (role == WPAS_P2P_ROLE_CLIENT) {
+		if (wpa_s->current_ssid == NULL)
+			return FALSE;
+		p_bssid = wpa_s->current_ssid->bssid;
+	} else {
+		if (wpa_s->ap_iface == NULL)
+			return FALSE;
+		p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
+	}
+
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      p_bssid, ETH_ALEN,
+						      error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	u16 op_freq;
+	u8 role = wpas_get_p2p_role(wpa_s);
+
+	if (role == WPAS_P2P_ROLE_CLIENT) {
+		if (wpa_s->go_params == NULL)
+			return FALSE;
+		op_freq = wpa_s->go_params->freq;
+	} else {
+		if (wpa_s->ap_iface == NULL)
+			return FALSE;
+		op_freq = wpa_s->ap_iface->freq;
+	}
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+						&op_freq, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	u8 role = wpas_get_p2p_role(wpa_s);
+	char *p_pass = NULL;
+
+	/* Verify correct role for this property */
+	if (role == WPAS_P2P_ROLE_GO) {
+		if (wpa_s->current_ssid == NULL)
+			return FALSE;
+		p_pass = wpa_s->current_ssid->passphrase;
+	} else
+		p_pass = "";
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&p_pass, error);
+
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
+					   DBusError *error, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	u8 role = wpas_get_p2p_role(wpa_s);
+	u8 *p_psk = NULL;
+	u8 psk_len = 0;
+
+	/* Verify correct role for this property */
+	if (role == WPAS_P2P_ROLE_CLIENT) {
+		if (wpa_s->current_ssid == NULL)
+			return FALSE;
+		p_psk = wpa_s->current_ssid->psk;
+		psk_len = 32;
+	}
+
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      &p_psk, psk_len, error);
+}
+
+
+dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	struct hostapd_data *hapd;
+	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	int num_vendor_ext = 0;
+	int i;
+
+	/* Verify correct role for this property */
+	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
+		if (wpa_s->ap_iface == NULL)
+			return FALSE;
+		hapd = wpa_s->ap_iface->bss[0];
+
+		/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
+		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+			if (hapd->conf->wps_vendor_ext[i] == NULL)
+				vendor_ext[i] = NULL;
+			else {
+				vendor_ext[num_vendor_ext++] =
+					hapd->conf->wps_vendor_ext[i];
+			}
+		}
+	}
+
+	/* Return vendor extensions or no data */
+	return wpas_dbus_simple_array_array_property_getter(iter,
+							    DBUS_TYPE_BYTE,
+							    vendor_ext,
+							    num_vendor_ext,
+						 error);
+}
+
+
+dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, iter_dict;
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	unsigned int i;
+	struct hostapd_data *hapd = NULL;
+
+	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
+	    wpa_s->ap_iface != NULL)
+		hapd = wpa_s->ap_iface->bss[0];
+	else
+		return FALSE;
+
+	dbus_message_iter_recurse(iter, &variant_iter);
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+		return FALSE;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+					     "invalid message format");
+			return FALSE;
+		}
+
+		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
+				goto error;
+
+			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+				if (i < entry.array_len) {
+					hapd->conf->wps_vendor_ext[i] =
+						entry.binarray_value[i];
+					entry.binarray_value[i] = NULL;
+				} else
+					hapd->conf->wps_vendor_ext[i] = NULL;
+			}
+
+			hostapd_update_wps(hapd);
+		} else
+			goto error;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	return TRUE;
+
+error:
+	wpa_dbus_dict_entry_clear(&entry);
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	return FALSE;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
+						struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	int bonjour = 0;
+	char *service = NULL;
+	struct wpabuf *query = NULL;
+	struct wpabuf *resp = NULL;
+	u8 version = 0;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "service_type") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			if (!os_strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else if (!os_strcmp(entry.str_value, "bonjour"))
+				bonjour = 1;
+			else
+				goto error_clear;
+		} else if (!os_strcmp(entry.key, "version") &&
+		           entry.type == DBUS_TYPE_INT32) {
+			version = entry.uint32_value;
+		} else if (!os_strcmp(entry.key, "service") &&
+			     (entry.type == DBUS_TYPE_STRING)) {
+			service = os_strdup(entry.str_value);
+		} else if (!os_strcmp(entry.key, "query")) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != DBUS_TYPE_BYTE))
+				goto error_clear;
+			query = wpabuf_alloc_copy(
+				entry.bytearray_value,
+				entry.array_len);
+		} else if (!os_strcmp(entry.key, "response")) {
+			if ((entry.type != DBUS_TYPE_ARRAY) ||
+			    (entry.array_type != DBUS_TYPE_BYTE))
+				goto error_clear;
+			resp = wpabuf_alloc_copy(entry.bytearray_value,
+						 entry.array_len);
+		}
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (upnp == 1) {
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
+			goto error;
+
+		os_free(service);
+		service = NULL;
+	} else if (bonjour == 1) {
+		if (query == NULL || resp == NULL)
+			goto error;
+
+		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
+			goto error;
+		query = NULL;
+		resp = NULL;
+	} else
+		goto error;
+
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	os_free(service);
+	wpabuf_free(query);
+	wpabuf_free(resp);
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_delete_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	int bonjour = 0;
+	int ret = 0;
+	char *service = NULL;
+	struct wpabuf *query = NULL;
+	u8 version = 0;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "service_type") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			if (!os_strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else if (!os_strcmp(entry.str_value, "bonjour"))
+				bonjour = 1;
+			else
+				goto error_clear;
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+	}
+	if (upnp == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+			if (!os_strcmp(entry.key, "version") &&
+			    entry.type == DBUS_TYPE_INT32)
+				version = entry.uint32_value;
+			else if (!os_strcmp(entry.key, "service") &&
+				 entry.type == DBUS_TYPE_STRING)
+				service = os_strdup(entry.str_value);
+			else
+				goto error_clear;
+
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
+		os_free(service);
+		if (ret != 0)
+			goto error;
+	} else if (bonjour == 1) {
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+
+			if (!os_strcmp(entry.key, "query")) {
+				if ((entry.type != DBUS_TYPE_ARRAY) ||
+				    (entry.array_type != DBUS_TYPE_BYTE))
+					goto error_clear;
+				query = wpabuf_alloc_copy(
+					entry.bytearray_value,
+					entry.array_len);
+			} else
+				goto error_clear;
+
+			wpa_dbus_dict_entry_clear(&entry);
+		}
+
+		if (query == NULL)
+			goto error;
+
+		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+		if (ret != 0)
+			goto error;
+		wpabuf_free(query);
+	} else
+		goto error;
+
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s)
+{
+	wpas_p2p_service_flush(wpa_s);
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	int upnp = 0;
+	char *service = NULL;
+	char *peer_object_path = NULL;
+	struct wpabuf *tlv = NULL;
+	u8 version = 0;
+	u64 ref = 0;
+	u8 addr_buf[ETH_ALEN], *addr;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+		if (!os_strcmp(entry.key, "peer_object") &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!os_strcmp(entry.key, "service_type") &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (!os_strcmp(entry.str_value, "upnp"))
+				upnp = 1;
+			else
+				goto error_clear;
+		} else if (!os_strcmp(entry.key, "version") &&
+			   entry.type == DBUS_TYPE_INT32) {
+			version = entry.uint32_value;
+		} else if (!os_strcmp(entry.key, "service") &&
+			   entry.type == DBUS_TYPE_STRING) {
+			service = os_strdup(entry.str_value);
+		} else if (!os_strcmp(entry.key, "tlv")) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
+				goto error_clear;
+			tlv = wpabuf_alloc_copy(entry.bytearray_value,
+						entry.array_len);
+		} else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	if (!peer_object_path) {
+		addr = NULL;
+	} else {
+		if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
+		    !p2p_peer_known(wpa_s->global->p2p, addr_buf))
+			goto error;
+
+		addr = addr_buf;
+	}
+
+	if (upnp == 1) {
+		if (version <= 0 || service == NULL)
+			goto error;
+
+		ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
+	} else {
+		if (tlv == NULL)
+			goto error;
+		ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
+		wpabuf_free(tlv);
+	}
+
+	if (ref != 0) {
+		reply = dbus_message_new_method_return(message);
+		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
+					 &ref, DBUS_TYPE_INVALID);
+	} else {
+		reply = wpas_dbus_error_unknown_error(
+			message, "Unable to send SD request");
+	}
+out:
+	os_free(service);
+	os_free(peer_object_path);
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	if (tlv)
+		wpabuf_free(tlv);
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter_dict;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	struct wpa_dbus_dict_entry entry;
+	char *peer_object_path = NULL;
+	struct wpabuf *tlv = NULL;
+	int freq = 0;
+	int dlg_tok = 0;
+	u8 addr[ETH_ALEN];
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		if (!os_strcmp(entry.key, "peer_object") &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
+			peer_object_path = os_strdup(entry.str_value);
+		} else if (!os_strcmp(entry.key, "frequency") &&
+			   entry.type == DBUS_TYPE_INT32) {
+			freq = entry.uint32_value;
+		} else if (!os_strcmp(entry.key, "dialog_token") &&
+			   entry.type == DBUS_TYPE_UINT32) {
+			dlg_tok = entry.uint32_value;
+		} else if (!os_strcmp(entry.key, "tlvs")) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
+				goto error_clear;
+			tlv = wpabuf_alloc_copy(entry.bytearray_value,
+						entry.array_len);
+		} else
+			goto error_clear;
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+	if (!peer_object_path ||
+	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	    !p2p_peer_known(wpa_s->global->p2p, addr))
+		goto error;
+
+	if (tlv == NULL)
+		goto error;
+
+	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
+	wpabuf_free(tlv);
+out:
+	os_free(peer_object_path);
+	return reply;
+error_clear:
+	wpa_dbus_dict_entry_clear(&entry);
+error:
+	reply = wpas_dbus_error_invalid_args(message, NULL);
+	goto out;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	u64 req = 0;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &req);
+
+	if (req == 0)
+		goto error;
+
+	if (!wpas_p2p_sd_cancel_request(wpa_s, req))
+		goto error;
+
+	return NULL;
+error:
+	return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_service_update(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	wpas_p2p_sd_service_update(wpa_s);
+	return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter;
+	int ext = 0;
+
+	dbus_message_iter_init(message, &iter);
+	dbus_message_iter_get_basic(&iter, &ext);
+
+	wpa_s->p2p_sd_over_ctrl_iface = ext;
+
+	return NULL;
+
+}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers_p2p.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_p2p.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,211 @@
+/*
+ * WPA Supplicant / dbus-based control interface for p2p
+ * Copyright (c) 2011-2012, Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DBUS_NEW_HANDLERS_P2P_H
+#define DBUS_NEW_HANDLERS_P2P_H
+
+struct peer_handler_args {
+	struct wpa_supplicant *wpa_s;
+	u8 p2p_device_addr[ETH_ALEN];
+};
+
+struct groupmember_handler_args {
+	struct wpa_supplicant *wpa_s;
+	u8 member_addr[ETH_ALEN];
+};
+
+/*
+ * P2P Device methods
+ */
+
+DBusMessage *wpas_dbus_handler_p2p_find(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_listen(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_connect(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_invite(
+		DBusMessage *message,
+		struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+/*
+ * 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);
+
+/*
+ * 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_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);
+
+/*
+ * 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);
+
+/*
+ * 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);
+
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+
+#endif /* DBUS_NEW_HANDLERS_P2P_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers_wps.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,331 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface (WPS)
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../wps_supplicant.h"
-#include "dbus_new_helpers.h"
-#include "dbus_new.h"
-#include "dbus_new_handlers.h"
-#include "dbus_dict_helpers.h"
-
-
-struct wps_start_params {
-	int role; /* 0 - not set, 1 - enrollee, 2 - registrar */
-	int type; /* 0 - not set, 1 - pin,      2 - pbc       */
-	u8 *bssid;
-	char *pin;
-};
-
-
-static int wpas_dbus_handler_wps_role(DBusMessage *message,
-				      DBusMessageIter *entry_iter,
-				      struct wps_start_params *params,
-				      DBusMessage **reply)
-{
-	DBusMessageIter variant_iter;
-	char *val;
-
-	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
-			   "string required");
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "Role must be a string");
-		return -1;
-	}
-	dbus_message_iter_get_basic(&variant_iter, &val);
-	if (os_strcmp(val, "enrollee") == 0)
-		params->role = 1;
-	else if (os_strcmp(val, "registrar") == 0)
-		params->role = 2;
-	else {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val);
-		*reply = wpas_dbus_error_invalid_args(message, val);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpas_dbus_handler_wps_type(DBusMessage *message,
-				      DBusMessageIter *entry_iter,
-				      struct wps_start_params *params,
-				      DBusMessage **reply)
-{
-	DBusMessageIter variant_iter;
-	char *val;
-
-	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
-			   "string required");
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "Type must be a string");
-		return -1;
-	}
-	dbus_message_iter_get_basic(&variant_iter, &val);
-	if (os_strcmp(val, "pin") == 0)
-		params->type = 1;
-	else if (os_strcmp(val, "pbc") == 0)
-		params->type = 2;
-	else {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s",
-			   val);
-		*reply = wpas_dbus_error_invalid_args(message, val);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
-				       DBusMessageIter *entry_iter,
-				       struct wps_start_params *params,
-				       DBusMessage **reply)
-{
-	DBusMessageIter variant_iter, array_iter;
-	int len;
-
-	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&variant_iter) !=
-	    DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
-			   "byte array required");
-		*reply = wpas_dbus_error_invalid_args(
-			message, "Bssid must be a byte array");
-		return -1;
-	}
-	dbus_message_iter_recurse(&variant_iter, &array_iter);
-	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
-	if (len != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
-			   "%d", len);
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "Bssid is wrong length");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpas_dbus_handler_wps_pin(DBusMessage *message,
-				     DBusMessageIter *entry_iter,
-				     struct wps_start_params *params,
-				     DBusMessage **reply)
-{
-	DBusMessageIter variant_iter;
-
-	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
-			   "string required");
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "Pin must be a string");
-		return -1;
-	}
-	dbus_message_iter_get_basic(&variant_iter, &params->pin);
-	return 0;
-}
-
-
-static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
-					     DBusMessageIter *entry_iter,
-					     struct wps_start_params *params,
-					     DBusMessage **reply)
-{
-	if (os_strcmp(key, "Role") == 0)
-		return wpas_dbus_handler_wps_role(message, entry_iter,
-						  params, reply);
-	else if (os_strcmp(key, "Type") == 0)
-		return wpas_dbus_handler_wps_type(message, entry_iter,
-						  params, reply);
-	else if (os_strcmp(key, "Bssid") == 0)
-		return wpas_dbus_handler_wps_bssid(message, entry_iter,
-						   params, reply);
-	else if (os_strcmp(key, "Pin") == 0)
-		return wpas_dbus_handler_wps_pin(message, entry_iter,
-						 params, reply);
-
-	wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
-	*reply = wpas_dbus_error_invalid_args(message, key);
-	return -1;
-}
-
-
-/**
- * wpas_dbus_handler_wps_start - Start WPS configuration
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: DBus message dictionary on success or DBus error on failure
- *
- * Handler for "Start" method call. DBus dictionary argument contains
- * information about role (enrollee or registrar), authorization method
- * (pin or push button) and optionally pin and bssid. Returned message
- * has a dictionary argument which may contain newly generated pin (optional).
- */
-DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, dict_iter, entry_iter;
-	struct wps_start_params params;
-	char *key;
-	char npin[9] = { '\0' };
-	int ret;
-
-	os_memset(&params, 0, sizeof(params));
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_recurse(&iter, &dict_iter);
-	while (dbus_message_iter_get_arg_type(&dict_iter) ==
-	       DBUS_TYPE_DICT_ENTRY) {
-		dbus_message_iter_recurse(&dict_iter, &entry_iter);
-
-		dbus_message_iter_get_basic(&entry_iter, &key);
-		dbus_message_iter_next(&entry_iter);
-
-		if (wpas_dbus_handler_wps_start_entry(message, key,
-						      &entry_iter,
-						      &params, &reply))
-			return reply;
-
-		dbus_message_iter_next(&dict_iter);
-	}
-
-	if (params.role == 0) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
-		return wpas_dbus_error_invalid_args(message,
-						    "Role not specified");
-	} else if (params.role == 1 && params.type == 0) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
-		return wpas_dbus_error_invalid_args(message,
-						    "Type not specified");
-	} else if (params.role == 2 && params.pin == NULL) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
-			   "registrar role");
-		return wpas_dbus_error_invalid_args(
-			message, "Pin required for registrar role.");
-	}
-
-	if (params.role == 2)
-		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
-					 NULL);
-	else if (params.type == 1) {
-		ret = wpas_wps_start_pin(wpa_s, params.bssid, params.pin);
-		if (ret > 0)
-			os_snprintf(npin, sizeof(npin), "%08d", ret);
-	} else
-		ret = wpas_wps_start_pbc(wpa_s, params.bssid);
-
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
-			   "role %s and key %s",
-			   (params.role == 1 ? "enrollee" : "registrar"),
-			   (params.type == 0 ? "" :
-			    (params.type == 1 ? "pin" : "pbc")));
-		return wpas_dbus_error_unknown_error(message,
-						     "WPS start failed");
-	}
-
-	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	if (os_strlen(npin) > 0) {
-		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
-			dbus_message_unref(reply);
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_NO_MEMORY,
-						      NULL);
-		}
-	}
-
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_getter_process_credentials - Check if credentials are processed
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: DBus message with a boolean on success or DBus error on failure
- *
- * Getter for "ProcessCredentials" property. Returns returned boolean will be
- * true if wps_cred_processing configuration field is not equal to 1 or false
- * if otherwise.
- */
-DBusMessage * wpas_dbus_getter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s)
-{
-	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&process);
-}
-
-
-/**
- * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: NULL on success or DBus error on failure
- *
- * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
- * if boolean argument is true or on 1 if otherwise.
- */
-DBusMessage * wpas_dbus_setter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	dbus_bool_t process_credentials, old_pc;
-
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &process_credentials);
-	if (reply)
-		return reply;
-
-	old_pc = (wpa_s->conf->wps_cred_processing != 1);
-	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
-
-	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
-		wpa_dbus_mark_property_changed(wpa_s->global->dbus,
-					       wpa_s->dbus_new_path,
-					       WPAS_DBUS_NEW_IFACE_WPS,
-					       "ProcessCredentials");
-
-	return NULL;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_handlers_wps.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_handlers_wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,391 @@
+/*
+ * WPA Supplicant / dbus-based control interface (WPS)
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at 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 "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "../driver_i.h"
+#include "../ap.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_dict_helpers.h"
+
+
+struct wps_start_params {
+	int role; /* 0 - not set, 1 - enrollee, 2 - registrar */
+	int type; /* 0 - not set, 1 - pin,      2 - pbc       */
+	u8 *bssid;
+	char *pin;
+	u8 *p2p_dev_addr;
+};
+
+
+static int wpas_dbus_handler_wps_role(DBusMessage *message,
+				      DBusMessageIter *entry_iter,
+				      struct wps_start_params *params,
+				      DBusMessage **reply)
+{
+	DBusMessageIter variant_iter;
+	char *val;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) !=
+	    DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
+			   "string required");
+		*reply = wpas_dbus_error_invalid_args(message,
+						      "Role must be a string");
+		return -1;
+	}
+	dbus_message_iter_get_basic(&variant_iter, &val);
+	if (os_strcmp(val, "enrollee") == 0)
+		params->role = 1;
+	else if (os_strcmp(val, "registrar") == 0)
+		params->role = 2;
+	else {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val);
+		*reply = wpas_dbus_error_invalid_args(message, val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpas_dbus_handler_wps_type(DBusMessage *message,
+				      DBusMessageIter *entry_iter,
+				      struct wps_start_params *params,
+				      DBusMessage **reply)
+{
+	DBusMessageIter variant_iter;
+	char *val;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) !=
+	    DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
+			   "string required");
+		*reply = wpas_dbus_error_invalid_args(message,
+						      "Type must be a string");
+		return -1;
+	}
+	dbus_message_iter_get_basic(&variant_iter, &val);
+	if (os_strcmp(val, "pin") == 0)
+		params->type = 1;
+	else if (os_strcmp(val, "pbc") == 0)
+		params->type = 2;
+	else {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s",
+			   val);
+		*reply = wpas_dbus_error_invalid_args(message, val);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
+				       DBusMessageIter *entry_iter,
+				       struct wps_start_params *params,
+				       DBusMessage **reply)
+{
+	DBusMessageIter variant_iter, array_iter;
+	int len;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&variant_iter) !=
+	    DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
+			   "byte array required");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "Bssid must be a byte array");
+		return -1;
+	}
+	dbus_message_iter_recurse(&variant_iter, &array_iter);
+	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
+	if (len != ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
+			   "%d", len);
+		*reply = wpas_dbus_error_invalid_args(message,
+						      "Bssid is wrong length");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int wpas_dbus_handler_wps_pin(DBusMessage *message,
+				     DBusMessageIter *entry_iter,
+				     struct wps_start_params *params,
+				     DBusMessage **reply)
+{
+	DBusMessageIter variant_iter;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) !=
+	    DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
+			   "string required");
+		*reply = wpas_dbus_error_invalid_args(message,
+						      "Pin must be a string");
+		return -1;
+	}
+	dbus_message_iter_get_basic(&variant_iter, &params->pin);
+	return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
+					      DBusMessageIter *entry_iter,
+					      struct wps_start_params *params,
+					      DBusMessage **reply)
+{
+	DBusMessageIter variant_iter, array_iter;
+	int len;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&variant_iter) !=
+	    DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
+			   "P2PDeviceAddress type, byte array required");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "P2PDeviceAddress must be a byte array");
+		return -1;
+	}
+	dbus_message_iter_recurse(&variant_iter, &array_iter);
+	dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
+					  &len);
+	if (len != ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
+			   "P2PDeviceAddress length %d", len);
+		*reply = wpas_dbus_error_invalid_args(message,
+						      "P2PDeviceAddress "
+						      "has wrong length");
+		return -1;
+	}
+	return 0;
+}
+#endif /* CONFIG_P2P */
+
+
+static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
+					     DBusMessageIter *entry_iter,
+					     struct wps_start_params *params,
+					     DBusMessage **reply)
+{
+	if (os_strcmp(key, "Role") == 0)
+		return wpas_dbus_handler_wps_role(message, entry_iter,
+						  params, reply);
+	else if (os_strcmp(key, "Type") == 0)
+		return wpas_dbus_handler_wps_type(message, entry_iter,
+						  params, reply);
+	else if (os_strcmp(key, "Bssid") == 0)
+		return wpas_dbus_handler_wps_bssid(message, entry_iter,
+						   params, reply);
+	else if (os_strcmp(key, "Pin") == 0)
+		return wpas_dbus_handler_wps_pin(message, entry_iter,
+						 params, reply);
+#ifdef CONFIG_P2P
+	else if (os_strcmp(key, "P2PDeviceAddress") == 0)
+		return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter,
+							  params, reply);
+#endif /* CONFIG_P2P */
+
+	wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
+	*reply = wpas_dbus_error_invalid_args(message, key);
+	return -1;
+}
+
+
+/**
+ * wpas_dbus_handler_wps_start - Start WPS configuration
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: DBus message dictionary on success or DBus error on failure
+ *
+ * Handler for "Start" method call. DBus dictionary argument contains
+ * information about role (enrollee or registrar), authorization method
+ * (pin or push button) and optionally pin and bssid. Returned message
+ * has a dictionary argument which may contain newly generated pin (optional).
+ */
+DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter, dict_iter, entry_iter;
+	struct wps_start_params params;
+	char *key;
+	char npin[9] = { '\0' };
+	int ret;
+
+	os_memset(&params, 0, sizeof(params));
+	dbus_message_iter_init(message, &iter);
+
+	dbus_message_iter_recurse(&iter, &dict_iter);
+	while (dbus_message_iter_get_arg_type(&dict_iter) ==
+	       DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(&dict_iter, &entry_iter);
+
+		dbus_message_iter_get_basic(&entry_iter, &key);
+		dbus_message_iter_next(&entry_iter);
+
+		if (wpas_dbus_handler_wps_start_entry(message, key,
+						      &entry_iter,
+						      &params, &reply))
+			return reply;
+
+		dbus_message_iter_next(&dict_iter);
+	}
+
+	if (params.role == 0) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
+		return wpas_dbus_error_invalid_args(message,
+						    "Role not specified");
+	} else if (params.role == 1 && params.type == 0) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
+		return wpas_dbus_error_invalid_args(message,
+						    "Type not specified");
+	} else if (params.role == 2 && params.pin == NULL) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
+			   "registrar role");
+		return wpas_dbus_error_invalid_args(
+			message, "Pin required for registrar role.");
+	}
+
+	if (params.role == 2)
+		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
+					 NULL);
+	else if (params.type == 1) {
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface)
+			ret = wpa_supplicant_ap_wps_pin(wpa_s,
+							params.bssid,
+							params.pin,
+							npin, sizeof(npin), 0);
+		else
+#endif /* CONFIG_AP */
+		{
+			ret = wpas_wps_start_pin(wpa_s, params.bssid,
+						 params.pin, 0,
+						 DEV_PW_DEFAULT);
+			if (ret > 0)
+				os_snprintf(npin, sizeof(npin), "%08d", ret);
+		}
+	} else {
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface)
+			ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+							params.bssid,
+							params.p2p_dev_addr);
+		else
+#endif /* CONFIG_AP */
+		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
+	}
+
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
+			   "role %s and key %s",
+			   (params.role == 1 ? "enrollee" : "registrar"),
+			   (params.type == 0 ? "" :
+			    (params.type == 1 ? "pin" : "pbc")));
+		return wpas_dbus_error_unknown_error(message,
+						     "WPS start failed");
+	}
+
+	reply = dbus_message_new_method_return(message);
+	if (!reply) {
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	}
+
+	dbus_message_iter_init_append(reply, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+		dbus_message_unref(reply);
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	}
+
+	if (os_strlen(npin) > 0) {
+		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
+			dbus_message_unref(reply);
+			return dbus_message_new_error(message,
+						      DBUS_ERROR_NO_MEMORY,
+						      NULL);
+		}
+	}
+
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+		dbus_message_unref(reply);
+		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					      NULL);
+	}
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_getter_process_credentials - Check if credentials are processed
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ProcessCredentials" property. Returns returned boolean will be
+ * 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)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&process, error);
+}
+
+
+/**
+ * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "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)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	dbus_bool_t process_credentials, old_pc;
+
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &process_credentials))
+		return FALSE;
+
+	old_pc = (wpa_s->conf->wps_cred_processing != 1);
+	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
+
+	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
+		wpa_dbus_mark_property_changed(wpa_s->global->dbus,
+					       wpa_s->dbus_new_path,
+					       WPAS_DBUS_NEW_IFACE_WPS,
+					       "ProcessCredentials");
+
+	return TRUE;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_helpers.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,875 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "dbus_common.h"
-#include "dbus_common_i.h"
-#include "dbus_new.h"
-#include "dbus_new_helpers.h"
-
-
-/**
- * recursive_iter_copy - Reads arguments from one iterator and
- * writes to another recursively
- * @from: iterator to read from
- * @to: iterator to write to
- *
- * Copies one iterator's elements to another. If any element in
- * iterator is of container type, its content is copied recursively
- */
-static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
-{
-
-	char *subtype = NULL;
-	int type;
-
-	/* iterate over iterator to copy */
-	while ((type = dbus_message_iter_get_arg_type(from)) !=
-	       DBUS_TYPE_INVALID) {
-
-		/* simply copy basic type entries */
-		if (dbus_type_is_basic(type)) {
-			if (dbus_type_is_fixed(type)) {
-				/*
-				 * According to DBus documentation all
-				 * fixed-length types are guaranteed to fit
-				 * 8 bytes
-				 */
-				dbus_uint64_t v;
-				dbus_message_iter_get_basic(from, &v);
-				dbus_message_iter_append_basic(to, type, &v);
-			} else {
-				char *v;
-				dbus_message_iter_get_basic(from, &v);
-				dbus_message_iter_append_basic(to, type, &v);
-			}
-		} else {
-			/* recursively copy container type entries */
-			DBusMessageIter write_subiter, read_subiter;
-
-			dbus_message_iter_recurse(from, &read_subiter);
-
-			if (type == DBUS_TYPE_VARIANT ||
-			    type == DBUS_TYPE_ARRAY) {
-				subtype = dbus_message_iter_get_signature(
-					&read_subiter);
-			}
-
-			dbus_message_iter_open_container(to, type, subtype,
-							 &write_subiter);
-
-			recursive_iter_copy(&read_subiter, &write_subiter);
-
-			dbus_message_iter_close_container(to, &write_subiter);
-			if (subtype)
-				dbus_free(subtype);
-		}
-
-		dbus_message_iter_next(from);
-	}
-}
-
-
-static unsigned int fill_dict_with_properties(
-	DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props,
-	const char *interface, const void *user_data)
-{
-	DBusMessage *reply;
-	DBusMessageIter entry_iter, ret_iter;
-	unsigned int counter = 0;
-	const struct wpa_dbus_property_desc *dsc;
-
-	for (dsc = props; dsc && dsc->dbus_property; dsc++) {
-		if (!os_strncmp(dsc->dbus_interface, interface,
-				WPAS_DBUS_INTERFACE_MAX) &&
-		    dsc->access != W && dsc->getter) {
-			reply = dsc->getter(NULL, user_data);
-			if (!reply)
-				continue;
-
-			if (dbus_message_get_type(reply) ==
-			    DBUS_MESSAGE_TYPE_ERROR) {
-				dbus_message_unref(reply);
-				continue;
-			}
-
-			dbus_message_iter_init(reply, &ret_iter);
-
-			dbus_message_iter_open_container(dict_iter,
-							 DBUS_TYPE_DICT_ENTRY,
-							 NULL, &entry_iter);
-			dbus_message_iter_append_basic(
-				&entry_iter, DBUS_TYPE_STRING,
-				&dsc->dbus_property);
-
-			recursive_iter_copy(&ret_iter, &entry_iter);
-
-			dbus_message_iter_close_container(dict_iter,
-							  &entry_iter);
-			dbus_message_unref(reply);
-			counter++;
-		}
-	}
-
-	return counter;
-}
-
-
-/**
- * get_all_properties - Responds for GetAll properties calls on object
- * @message: Message with GetAll call
- * @interface: interface name which properties will be returned
- * @property_dsc: list of object's properties
- * Returns: Message with dict of variants as argument with properties values
- *
- * Iterates over all properties registered with object and execute getters
- * of those, which are readable and which interface matches interface
- * specified as argument. Returned message contains one dict argument
- * with properties names as keys and theirs values as values.
- */
-static DBusMessage * get_all_properties(
-	DBusMessage *message, char *interface,
-	struct wpa_dbus_object_desc *obj_dsc)
-{
-	/* Create and initialize the return message */
-	DBusMessage *reply = dbus_message_new_method_return(message);
-	DBusMessageIter iter, dict_iter;
-	int props_num;
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-					 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-					 DBUS_TYPE_STRING_AS_STRING
-					 DBUS_TYPE_VARIANT_AS_STRING
-					 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-					 &dict_iter);
-
-	props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties,
-					      interface, obj_dsc->user_data);
-
-	dbus_message_iter_close_container(&iter, &dict_iter);
-
-	if (props_num == 0) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message,
-					       DBUS_ERROR_INVALID_ARGS,
-					       "No readable properties in "
-					       "this interface");
-	}
-
-	return reply;
-}
-
-
-static int is_signature_correct(DBusMessage *message,
-				const struct wpa_dbus_method_desc *method_dsc)
-{
-	/* According to DBus documentation max length of signature is 255 */
-#define MAX_SIG_LEN 256
-	char registered_sig[MAX_SIG_LEN], *pos;
-	const char *sig = dbus_message_get_signature(message);
-	int ret;
-	const struct wpa_dbus_argument *arg;
-
-	pos = registered_sig;
-	*pos = '\0';
-
-	for (arg = method_dsc->args; arg && arg->name; arg++) {
-		if (arg->dir == ARG_IN) {
-			size_t blen = registered_sig + MAX_SIG_LEN - pos;
-			ret = os_snprintf(pos, blen, "%s", arg->type);
-			if (ret < 0 || (size_t) ret >= blen)
-				return 0;
-			pos += ret;
-		}
-	}
-
-	return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
-}
-
-
-static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
-					struct wpa_dbus_object_desc *obj_dsc)
-{
-	if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      NULL);
-
-	return get_all_properties(message, interface, obj_dsc);
-}
-
-
-static DBusMessage * properties_get(DBusMessage *message,
-				    const struct wpa_dbus_property_desc *dsc,
-				    void *user_data)
-{
-	if (os_strcmp(dbus_message_get_signature(message), "ss"))
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      NULL);
-
-	if (dsc->access != W && dsc->getter)
-		return dsc->getter(message, user_data);
-
-	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-				      "Property is write-only");
-}
-
-
-static DBusMessage * properties_set(DBusMessage *message,
-				    const struct wpa_dbus_property_desc *dsc,
-				    void *user_data)
-{
-	if (os_strcmp(dbus_message_get_signature(message), "ssv"))
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      NULL);
-
-	if (dsc->access != R && dsc->setter)
-		return dsc->setter(message, user_data);
-
-	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-				      "Property is read-only");
-}
-
-
-static DBusMessage *
-properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
-		      char *interface,
-		      struct wpa_dbus_object_desc *obj_dsc)
-{
-	const struct wpa_dbus_property_desc *property_dsc;
-	char *property;
-	const char *method;
-
-	method = dbus_message_get_member(message);
-	property_dsc = obj_dsc->properties;
-
-	/* Second argument: property name (DBUS_TYPE_STRING) */
-	if (!dbus_message_iter_next(iter) ||
-	    dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      NULL);
-	}
-	dbus_message_iter_get_basic(iter, &property);
-
-	while (property_dsc && property_dsc->dbus_property) {
-		/* compare property names and
-		 * interfaces */
-		if (!os_strncmp(property_dsc->dbus_property, property,
-				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
-		    !os_strncmp(property_dsc->dbus_interface, interface,
-				WPAS_DBUS_INTERFACE_MAX))
-			break;
-
-		property_dsc++;
-	}
-	if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
-		wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
-			   interface, property,
-			   dbus_message_get_path(message));
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      "No such property");
-	}
-
-	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
-		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
-		return properties_get(message, property_dsc,
-				      obj_dsc->user_data);
-
-	return properties_set(message, property_dsc, obj_dsc->user_data);
-}
-
-
-static DBusMessage * properties_handler(DBusMessage *message,
-					struct wpa_dbus_object_desc *obj_dsc)
-{
-	DBusMessageIter iter;
-	char *interface;
-	const char *method;
-
-	method = dbus_message_get_member(message);
-	dbus_message_iter_init(message, &iter);
-
-	if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
-			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
-	    !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
-			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
-	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
-			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
-		/* First argument: interface name (DBUS_TYPE_STRING) */
-		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		{
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_INVALID_ARGS,
-						      NULL);
-		}
-
-		dbus_message_iter_get_basic(&iter, &interface);
-
-		if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
-				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
-			/* GetAll */
-			return properties_get_all(message, interface, obj_dsc);
-		}
-		/* Get or Set */
-		return properties_get_or_set(message, &iter, interface,
-					     obj_dsc);
-	}
-	return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
-				      NULL);
-}
-
-
-static DBusMessage * msg_method_handler(DBusMessage *message,
-					struct wpa_dbus_object_desc *obj_dsc)
-{
-	const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
-	const char *method;
-	const char *msg_interface;
-
-	method = dbus_message_get_member(message);
-	msg_interface = dbus_message_get_interface(message);
-
-	/* try match call to any registered method */
-	while (method_dsc && method_dsc->dbus_method) {
-		/* compare method names and interfaces */
-		if (!os_strncmp(method_dsc->dbus_method, method,
-				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
-		    !os_strncmp(method_dsc->dbus_interface, msg_interface,
-				WPAS_DBUS_INTERFACE_MAX))
-			break;
-
-		method_dsc++;
-	}
-	if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
-		wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
-			   msg_interface, method,
-			   dbus_message_get_path(message));
-		return dbus_message_new_error(message,
-					      DBUS_ERROR_UNKNOWN_METHOD, NULL);
-	}
-
-	if (!is_signature_correct(message, method_dsc)) {
-		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-					      NULL);
-	}
-
-	return method_dsc->method_handler(message,
-					  obj_dsc->user_data);
-}
-
-
-/**
- * message_handler - Handles incoming DBus messages
- * @connection: DBus connection on which message was received
- * @message: Received message
- * @user_data: pointer to description of object to which message was sent
- * Returns: Returns information whether message was handled or not
- *
- * Reads message interface and method name, then checks if they matches one
- * of the special cases i.e. introspection call or properties get/getall/set
- * methods and handles it. Else it iterates over registered methods list
- * and tries to match method's name and interface to those read from message
- * If appropriate method was found its handler function is called and
- * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
- * will be sent.
- */
-static DBusHandlerResult message_handler(DBusConnection *connection,
-					 DBusMessage *message, void *user_data)
-{
-	struct wpa_dbus_object_desc *obj_dsc = user_data;
-	const char *method;
-	const char *path;
-	const char *msg_interface;
-	DBusMessage *reply;
-
-	/* get method, interface and path the message is addressed to */
-	method = dbus_message_get_member(message);
-	path = dbus_message_get_path(message);
-	msg_interface = dbus_message_get_interface(message);
-	if (!method || !path || !msg_interface)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
-		   msg_interface, method, path);
-
-	/* if message is introspection method call */
-	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
-			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
-	    !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
-			WPAS_DBUS_INTERFACE_MAX)) {
-#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
-		reply = wpa_dbus_introspect(message, obj_dsc);
-#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
-		reply = dbus_message_new_error(
-			message, DBUS_ERROR_UNKNOWN_METHOD,
-			"wpa_supplicant was compiled without "
-			"introspection support.");
-#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
-	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
-			     WPAS_DBUS_INTERFACE_MAX)) {
-		/* if message is properties method call */
-		reply = properties_handler(message, obj_dsc);
-	} else {
-		reply = msg_method_handler(message, obj_dsc);
-	}
-
-	/* If handler succeed returning NULL, reply empty message */
-	if (!reply)
-		reply = dbus_message_new_method_return(message);
-	if (reply) {
-		if (!dbus_message_get_no_reply(message))
-			dbus_connection_send(connection, reply, NULL);
-		dbus_message_unref(reply);
-	}
-
-	wpa_dbus_flush_all_changed_properties(connection);
-
-	return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-
-/**
- * free_dbus_object_desc - Frees object description data structure
- * @connection: DBus connection
- * @obj_dsc: Object description to free
- *
- * Frees each of properties, methods and signals description lists and
- * the object description structure itself.
- */
-void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
-{
-	if (!obj_dsc)
-		return;
-
-	/* free handler's argument */
-	if (obj_dsc->user_data_free_func)
-		obj_dsc->user_data_free_func(obj_dsc->user_data);
-
-	os_free(obj_dsc->path);
-	os_free(obj_dsc->prop_changed_flags);
-	os_free(obj_dsc);
-}
-
-
-static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
-{
-	free_dbus_object_desc(obj_dsc);
-}
-
-/**
- * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
- * @application_data: Pointer to application specific data structure
- * @dbus_path: DBus path to interface object
- * @dbus_service: DBus service name to register with
- * @messageHandler: a pointer to function which will handle dbus messages
- * coming on interface
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the dbus control interface and start receiving commands from
- * external programs over the bus.
- */
-int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
-			     char *dbus_path, char *dbus_service,
-			     struct wpa_dbus_object_desc *obj_desc)
-{
-	DBusError error;
-	int ret = -1;
-	DBusObjectPathVTable wpa_vtable = {
-		&free_dbus_object_desc_cb, &message_handler,
-		NULL, NULL, NULL, NULL
-	};
-
-	obj_desc->connection = iface->con;
-	obj_desc->path = os_strdup(dbus_path);
-
-	/* Register the message handler for the global dbus interface */
-	if (!dbus_connection_register_object_path(iface->con,
-						  dbus_path, &wpa_vtable,
-						  obj_desc)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
-		return -1;
-	}
-
-	/* Register our service with the message bus */
-	dbus_error_init(&error);
-	switch (dbus_bus_request_name(iface->con, dbus_service,
-				      0, &error)) {
-	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
-		ret = 0;
-		break;
-	case DBUS_REQUEST_NAME_REPLY_EXISTS:
-	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
-	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
-		break;
-	}
-	dbus_error_free(&error);
-
-	if (ret != 0)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
-
-	return 0;
-}
-
-
-/**
- * wpa_dbus_register_object_per_iface - Register a new object with dbus
- * @ctrl_iface: pointer to dbus private data
- * @path: DBus path to object
- * @ifname: interface name
- * @obj_desc: description of object's methods, signals and properties
- * Returns: 0 on success, -1 on error
- *
- * Registers a new interface with dbus and assigns it a dbus object path.
- */
-int wpa_dbus_register_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface,
-	const char *path, const char *ifname,
-	struct wpa_dbus_object_desc *obj_desc)
-{
-	DBusConnection *con;
-
-	DBusObjectPathVTable vtable = {
-		&free_dbus_object_desc_cb, &message_handler,
-		NULL, NULL, NULL, NULL
-	};
-
-	/* Do nothing if the control interface is not turned on */
-	if (ctrl_iface == NULL)
-		return 0;
-
-	con = ctrl_iface->con;
-	obj_desc->connection = con;
-	obj_desc->path = os_strdup(path);
-
-	/* Register the message handler for the interface functions */
-	if (!dbus_connection_register_object_path(con, path, &vtable,
-						  obj_desc)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler for interface %s object %s", ifname, path);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx);
-
-
-/**
- * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
- * @ctrl_iface: Pointer to dbus private data
- * @path: DBus path to object which will be unregistered
- * Returns: Zero on success and -1 on failure
- *
- * Unregisters DBus object given by its path
- */
-int wpa_dbus_unregister_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface, const char *path)
-{
-	DBusConnection *con = ctrl_iface->con;
-	struct wpa_dbus_object_desc *obj_desc = NULL;
-
-	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
-			   "private data: %s", __func__, path);
-	} else {
-		eloop_cancel_timeout(flush_object_timeout_handler, con,
-				     obj_desc);
-	}
-
-	if (!dbus_connection_unregister_object_path(con, path))
-		return -1;
-
-	return 0;
-}
-
-
-static void put_changed_properties(const struct wpa_dbus_object_desc *obj_dsc,
-				   const char *interface,
-				   DBusMessageIter *dict_iter)
-{
-	DBusMessage *getter_reply;
-	DBusMessageIter prop_iter, entry_iter;
-	const struct wpa_dbus_property_desc *dsc;
-	int i;
-
-	for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
-	     dsc++, i++) {
-		if (obj_dsc->prop_changed_flags == NULL ||
-		    !obj_dsc->prop_changed_flags[i])
-			continue;
-		if (os_strcmp(dsc->dbus_interface, interface) != 0)
-			continue;
-		obj_dsc->prop_changed_flags[i] = 0;
-
-		getter_reply = dsc->getter(NULL, obj_dsc->user_data);
-		if (!getter_reply ||
-		    dbus_message_get_type(getter_reply) ==
-		    DBUS_MESSAGE_TYPE_ERROR) {
-			wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value "
-				   "of property %s", __func__,
-				   dsc->dbus_property);
-			continue;
-		}
-
-		if (!dbus_message_iter_init(getter_reply, &prop_iter) ||
-		    !dbus_message_iter_open_container(dict_iter,
-						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter) ||
-		    !dbus_message_iter_append_basic(&entry_iter,
-						    DBUS_TYPE_STRING,
-						    &dsc->dbus_property))
-			goto err;
-
-		recursive_iter_copy(&prop_iter, &entry_iter);
-
-		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
-			goto err;
-
-		dbus_message_unref(getter_reply);
-	}
-
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: %s: Cannot construct signal", __func__);
-}
-
-
-static void send_prop_changed_signal(
-	DBusConnection *con, const char *path, const char *interface,
-	const struct wpa_dbus_object_desc *obj_dsc)
-{
-	DBusMessage *msg;
-	DBusMessageIter signal_iter, dict_iter;
-
-	msg = dbus_message_new_signal(path, interface, "PropertiesChanged");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &signal_iter);
-
-	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "{sv}", &dict_iter))
-		goto err;
-
-	put_changed_properties(obj_dsc, interface, &dict_iter);
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	dbus_connection_send(con, msg, NULL);
-
-out:
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
-		   __func__);
-	goto out;
-}
-
-
-static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
-{
-	DBusConnection *con = eloop_ctx;
-	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
-
-	wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
-		   "of object %s", __func__, obj_desc->path);
-	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
-}
-
-
-static void recursive_flush_changed_properties(DBusConnection *con,
-					       const char *path)
-{
-	char **objects = NULL;
-	char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX];
-	int i;
-
-	wpa_dbus_flush_object_changed_properties(con, path);
-
-	if (!dbus_connection_list_registered(con, path, &objects))
-		goto out;
-
-	for (i = 0; objects[i]; i++) {
-		os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/%s", path, objects[i]);
-		recursive_flush_changed_properties(con, subobj_path);
-	}
-
-out:
-	dbus_free_string_array(objects);
-}
-
-
-/**
- * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
- * @con: DBus connection
- *
- * Traverses through all registered objects and sends PropertiesChanged for
- * each properties.
- */
-void wpa_dbus_flush_all_changed_properties(DBusConnection *con)
-{
-	recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH);
-}
-
-
-/**
- * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
- * @con: DBus connection
- * @path: path to a DBus object for which PropertiesChanged will be sent.
- *
- * Iterates over all properties registered with object and for each interface
- * containing properties marked as changed, sends a PropertiesChanged signal
- * containing names and new values of properties that have changed.
- *
- * You need to call this function after wpa_dbus_mark_property_changed()
- * if you want to send PropertiesChanged signal immediately (i.e., without
- * waiting timeout to expire). PropertiesChanged signal for an object is sent
- * automatically short time after first marking property as changed. All
- * PropertiesChanged signals are sent automatically after responding on DBus
- * message, so if you marked a property changed as a result of DBus call
- * (e.g., param setter), you usually do not need to call this function.
- */
-void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
-					      const char *path)
-{
-	struct wpa_dbus_object_desc *obj_desc = NULL;
-	const struct wpa_dbus_property_desc *dsc;
-	int i;
-
-	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
-	if (!obj_desc)
-		return;
-	eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
-
-	dsc = obj_desc->properties;
-	for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property;
-	     dsc++, i++) {
-		if (obj_desc->prop_changed_flags == NULL ||
-		    !obj_desc->prop_changed_flags[i])
-			continue;
-		send_prop_changed_signal(con, path, dsc->dbus_interface,
-					 obj_desc);
-	}
-}
-
-
-#define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
-
-
-/**
- * wpa_dbus_mark_property_changed - Mark a property as changed and
- * @iface: dbus priv struct
- * @path: path to DBus object which property has changed
- * @interface: interface containing changed property
- * @property: property name which has changed
- *
- * Iterates over all properties registered with an object and marks the one
- * given in parameters as changed. All parameters registered for an object
- * within a single interface will be aggregated together and sent in one
- * PropertiesChanged signal when function
- * wpa_dbus_flush_object_changed_properties() is called.
- */
-void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    const char *property)
-{
-	struct wpa_dbus_object_desc *obj_desc = NULL;
-	const struct wpa_dbus_property_desc *dsc;
-	int i = 0;
-
-	if (iface == NULL)
-		return;
-
-	dbus_connection_get_object_path_data(iface->con, path,
-					     (void **) &obj_desc);
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "could not obtain object's private data: %s", path);
-		return;
-	}
-
-	for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++)
-		if (os_strcmp(property, dsc->dbus_property) == 0 &&
-		    os_strcmp(interface, dsc->dbus_interface) == 0) {
-			if (obj_desc->prop_changed_flags)
-				obj_desc->prop_changed_flags[i] = 1;
-			break;
-		}
-
-	if (!dsc || !dsc->dbus_property) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "no property %s in object %s", property, path);
-		return;
-	}
-
-	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
-					 iface->con, obj_desc->path)) {
-		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
-				       flush_object_timeout_handler,
-				       iface->con, obj_desc);
-	}
-}
-
-
-/**
- * wpa_dbus_get_object_properties - Put object's properties into dictionary
- * @iface: dbus priv struct
- * @path: path to DBus object which properties will be obtained
- * @interface: interface name which properties will be obtained
- * @dict_iter: correct, open DBus dictionary iterator.
- *
- * Iterates over all properties registered with object and execute getters
- * of those, which are readable and which interface matches interface
- * specified as argument. Obtained properties values are stored in
- * dict_iter dictionary.
- */
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    DBusMessageIter *dict_iter)
-{
-	struct wpa_dbus_object_desc *obj_desc = NULL;
-
-	dbus_connection_get_object_path_data(iface->con, path,
-					     (void **) &obj_desc);
-	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
-			   "could not obtain object's private data: %s", path);
-		return;
-	}
-
-	fill_dict_with_properties(dict_iter, obj_desc->properties,
-				  interface, obj_desc->user_data);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_helpers.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1061 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "dbus_common.h"
+#include "dbus_common_i.h"
+#include "dbus_new.h"
+#include "dbus_new_helpers.h"
+#include "dbus_dict_helpers.h"
+
+
+static dbus_bool_t fill_dict_with_properties(
+	DBusMessageIter *dict_iter,
+	const struct wpa_dbus_property_desc *props,
+	const char *interface, void *user_data, DBusError *error)
+{
+	DBusMessageIter entry_iter;
+	const struct wpa_dbus_property_desc *dsc;
+
+	for (dsc = props; dsc && dsc->dbus_property; dsc++) {
+		/* Only return properties for the requested D-Bus interface */
+		if (os_strncmp(dsc->dbus_interface, interface,
+			       WPAS_DBUS_INTERFACE_MAX) != 0)
+			continue;
+
+		/* Skip write-only properties */
+		if (dsc->getter == NULL)
+			continue;
+
+		if (!dbus_message_iter_open_container(dict_iter,
+						      DBUS_TYPE_DICT_ENTRY,
+						      NULL, &entry_iter)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+			                     "no memory");
+			return FALSE;
+		}
+		if (!dbus_message_iter_append_basic(&entry_iter,
+						    DBUS_TYPE_STRING,
+						    &dsc->dbus_property)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+			                     "no memory");
+			return FALSE;
+		}
+
+		/* An error getting a property fails the request entirely */
+		if (!dsc->getter(&entry_iter, error, user_data))
+			return FALSE;
+
+		dbus_message_iter_close_container(dict_iter, &entry_iter);
+	}
+
+	return TRUE;
+}
+
+
+/**
+ * get_all_properties - Responds for GetAll properties calls on object
+ * @message: Message with GetAll call
+ * @interface: interface name which properties will be returned
+ * @property_dsc: list of object's properties
+ * Returns: Message with dict of variants as argument with properties values
+ *
+ * Iterates over all properties registered with object and execute getters
+ * of those, which are readable and which interface matches interface
+ * specified as argument. Returned message contains one dict argument
+ * with properties names as keys and theirs values as values.
+ */
+static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
+				        struct wpa_dbus_object_desc *obj_dsc)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter, dict_iter;
+	DBusError error;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
+			   __func__);
+		return NULL;
+	}
+
+	dbus_message_iter_init_append(reply, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+		wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
+			   __func__);
+		dbus_message_unref(reply);
+		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+					       "out of memory");
+		return reply;
+	}
+
+	dbus_error_init(&error);
+	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
+				       interface, obj_dsc->user_data, &error))
+	{
+		dbus_message_unref(reply);
+		reply = wpas_dbus_reply_new_from_error(message, &error,
+						       DBUS_ERROR_INVALID_ARGS,
+						       "No readable properties"
+						       " in this interface");
+		dbus_error_free(&error);
+		return reply;
+	}
+
+	wpa_dbus_dict_close_write(&iter, &dict_iter);
+	return reply;
+}
+
+
+static int is_signature_correct(DBusMessage *message,
+				const struct wpa_dbus_method_desc *method_dsc)
+{
+	/* According to DBus documentation max length of signature is 255 */
+#define MAX_SIG_LEN 256
+	char registered_sig[MAX_SIG_LEN], *pos;
+	const char *sig = dbus_message_get_signature(message);
+	int ret;
+	const struct wpa_dbus_argument *arg;
+
+	pos = registered_sig;
+	*pos = '\0';
+
+	for (arg = method_dsc->args; arg && arg->name; arg++) {
+		if (arg->dir == ARG_IN) {
+			size_t blen = registered_sig + MAX_SIG_LEN - pos;
+			ret = os_snprintf(pos, blen, "%s", arg->type);
+			if (ret < 0 || (size_t) ret >= blen)
+				return 0;
+			pos += ret;
+		}
+	}
+
+	return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
+}
+
+
+static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
+					struct wpa_dbus_object_desc *obj_dsc)
+{
+	if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      NULL);
+
+	return get_all_properties(message, interface, obj_dsc);
+}
+
+
+static DBusMessage * properties_get(DBusMessage *message,
+				    const struct wpa_dbus_property_desc *dsc,
+				    void *user_data)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusError error;
+
+	if (os_strcmp(dbus_message_get_signature(message), "ss")) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      NULL);
+	}
+
+	if (dsc->getter == NULL) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      "Property is write-only");
+	}
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_error_init(&error);
+	if (dsc->getter(&iter, &error, user_data) == FALSE) {
+		dbus_message_unref(reply);
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_FAILED,
+			"Failed to read property");
+		dbus_error_free(&error);
+	}
+
+	return reply;
+}
+
+
+static DBusMessage * properties_set(DBusMessage *message,
+				    const struct wpa_dbus_property_desc *dsc,
+				    void *user_data)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusError error;
+
+	if (os_strcmp(dbus_message_get_signature(message), "ssv")) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      NULL);
+	}
+
+	if (dsc->setter == NULL) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      "Property is read-only");
+	}
+
+	dbus_message_iter_init(message, &iter);
+	/* Skip the interface name and the property name */
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_next(&iter);
+
+	/* Iter will now point to the property's new value */
+	dbus_error_init(&error);
+	if (dsc->setter(&iter, &error, user_data) == TRUE) {
+		/* Success */
+		reply = dbus_message_new_method_return(message);
+	} else {
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_FAILED,
+			"Failed to set property");
+		dbus_error_free(&error);
+	}
+
+	return reply;
+}
+
+
+static DBusMessage *
+properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
+		      char *interface,
+		      struct wpa_dbus_object_desc *obj_dsc)
+{
+	const struct wpa_dbus_property_desc *property_dsc;
+	char *property;
+	const char *method;
+
+	method = dbus_message_get_member(message);
+	property_dsc = obj_dsc->properties;
+
+	/* Second argument: property name (DBUS_TYPE_STRING) */
+	if (!dbus_message_iter_next(iter) ||
+	    dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      NULL);
+	}
+	dbus_message_iter_get_basic(iter, &property);
+
+	while (property_dsc && property_dsc->dbus_property) {
+		/* compare property names and
+		 * interfaces */
+		if (!os_strncmp(property_dsc->dbus_property, property,
+				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
+		    !os_strncmp(property_dsc->dbus_interface, interface,
+				WPAS_DBUS_INTERFACE_MAX))
+			break;
+
+		property_dsc++;
+	}
+	if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
+		wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
+			   interface, property,
+			   dbus_message_get_path(message));
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      "No such property");
+	}
+
+	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
+		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
+		return properties_get(message, property_dsc,
+				      obj_dsc->user_data);
+
+	return properties_set(message, property_dsc, obj_dsc->user_data);
+}
+
+
+static DBusMessage * properties_handler(DBusMessage *message,
+					struct wpa_dbus_object_desc *obj_dsc)
+{
+	DBusMessageIter iter;
+	char *interface;
+	const char *method;
+
+	method = dbus_message_get_member(message);
+	dbus_message_iter_init(message, &iter);
+
+	if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
+			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
+	    !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
+			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
+	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
+			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
+		/* First argument: interface name (DBUS_TYPE_STRING) */
+		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		{
+			return dbus_message_new_error(message,
+						      DBUS_ERROR_INVALID_ARGS,
+						      NULL);
+		}
+
+		dbus_message_iter_get_basic(&iter, &interface);
+
+		if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
+				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
+			/* GetAll */
+			return properties_get_all(message, interface, obj_dsc);
+		}
+		/* Get or Set */
+		return properties_get_or_set(message, &iter, interface,
+					     obj_dsc);
+	}
+	return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
+				      NULL);
+}
+
+
+static DBusMessage * msg_method_handler(DBusMessage *message,
+					struct wpa_dbus_object_desc *obj_dsc)
+{
+	const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
+	const char *method;
+	const char *msg_interface;
+
+	method = dbus_message_get_member(message);
+	msg_interface = dbus_message_get_interface(message);
+
+	/* try match call to any registered method */
+	while (method_dsc && method_dsc->dbus_method) {
+		/* compare method names and interfaces */
+		if (!os_strncmp(method_dsc->dbus_method, method,
+				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
+		    !os_strncmp(method_dsc->dbus_interface, msg_interface,
+				WPAS_DBUS_INTERFACE_MAX))
+			break;
+
+		method_dsc++;
+	}
+	if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
+		wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
+			   msg_interface, method,
+			   dbus_message_get_path(message));
+		return dbus_message_new_error(message,
+					      DBUS_ERROR_UNKNOWN_METHOD, NULL);
+	}
+
+	if (!is_signature_correct(message, method_dsc)) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      NULL);
+	}
+
+	return method_dsc->method_handler(message,
+					  obj_dsc->user_data);
+}
+
+
+/**
+ * message_handler - Handles incoming DBus messages
+ * @connection: DBus connection on which message was received
+ * @message: Received message
+ * @user_data: pointer to description of object to which message was sent
+ * Returns: Returns information whether message was handled or not
+ *
+ * Reads message interface and method name, then checks if they matches one
+ * of the special cases i.e. introspection call or properties get/getall/set
+ * methods and handles it. Else it iterates over registered methods list
+ * and tries to match method's name and interface to those read from message
+ * If appropriate method was found its handler function is called and
+ * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
+ * will be sent.
+ */
+static DBusHandlerResult message_handler(DBusConnection *connection,
+					 DBusMessage *message, void *user_data)
+{
+	struct wpa_dbus_object_desc *obj_dsc = user_data;
+	const char *method;
+	const char *path;
+	const char *msg_interface;
+	DBusMessage *reply;
+
+	/* get method, interface and path the message is addressed to */
+	method = dbus_message_get_member(message);
+	path = dbus_message_get_path(message);
+	msg_interface = dbus_message_get_interface(message);
+	if (!method || !path || !msg_interface)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
+		   msg_interface, method, path);
+
+	/* if message is introspection method call */
+	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
+			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
+	    !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
+			WPAS_DBUS_INTERFACE_MAX)) {
+#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
+		reply = wpa_dbus_introspect(message, obj_dsc);
+#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
+		reply = dbus_message_new_error(
+			message, DBUS_ERROR_UNKNOWN_METHOD,
+			"wpa_supplicant was compiled without "
+			"introspection support.");
+#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
+	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
+			     WPAS_DBUS_INTERFACE_MAX)) {
+		/* if message is properties method call */
+		reply = properties_handler(message, obj_dsc);
+	} else {
+		reply = msg_method_handler(message, obj_dsc);
+	}
+
+	/* If handler succeed returning NULL, reply empty message */
+	if (!reply)
+		reply = dbus_message_new_method_return(message);
+	if (reply) {
+		if (!dbus_message_get_no_reply(message))
+			dbus_connection_send(connection, reply, NULL);
+		dbus_message_unref(reply);
+	}
+
+	wpa_dbus_flush_all_changed_properties(connection);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+
+/**
+ * free_dbus_object_desc - Frees object description data structure
+ * @connection: DBus connection
+ * @obj_dsc: Object description to free
+ *
+ * Frees each of properties, methods and signals description lists and
+ * the object description structure itself.
+ */
+void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
+{
+	if (!obj_dsc)
+		return;
+
+	/* free handler's argument */
+	if (obj_dsc->user_data_free_func)
+		obj_dsc->user_data_free_func(obj_dsc->user_data);
+
+	os_free(obj_dsc->path);
+	os_free(obj_dsc->prop_changed_flags);
+	os_free(obj_dsc);
+}
+
+
+static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
+{
+	free_dbus_object_desc(obj_dsc);
+}
+
+/**
+ * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
+ * @application_data: Pointer to application specific data structure
+ * @dbus_path: DBus path to interface object
+ * @dbus_service: DBus service name to register with
+ * @messageHandler: a pointer to function which will handle dbus messages
+ * coming on interface
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initialize the dbus control interface and start receiving commands from
+ * external programs over the bus.
+ */
+int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
+			     char *dbus_path, char *dbus_service,
+			     struct wpa_dbus_object_desc *obj_desc)
+{
+	DBusError error;
+	int ret = -1;
+	DBusObjectPathVTable wpa_vtable = {
+		&free_dbus_object_desc_cb, &message_handler,
+		NULL, NULL, NULL, NULL
+	};
+
+	obj_desc->connection = iface->con;
+	obj_desc->path = os_strdup(dbus_path);
+
+	/* Register the message handler for the global dbus interface */
+	if (!dbus_connection_register_object_path(iface->con,
+						  dbus_path, &wpa_vtable,
+						  obj_desc)) {
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
+			   "handler");
+		return -1;
+	}
+
+	/* Register our service with the message bus */
+	dbus_error_init(&error);
+	switch (dbus_bus_request_name(iface->con, dbus_service,
+				      0, &error)) {
+	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+		ret = 0;
+		break;
+	case DBUS_REQUEST_NAME_REPLY_EXISTS:
+	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
+			   "already registered");
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
+			   "%s %s", error.name, error.message);
+		break;
+	}
+	dbus_error_free(&error);
+
+	if (ret != 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
+
+	return 0;
+}
+
+
+/**
+ * wpa_dbus_register_object_per_iface - Register a new object with dbus
+ * @ctrl_iface: pointer to dbus private data
+ * @path: DBus path to object
+ * @ifname: interface name
+ * @obj_desc: description of object's methods, signals and properties
+ * Returns: 0 on success, -1 on error
+ *
+ * Registers a new interface with dbus and assigns it a dbus object path.
+ */
+int wpa_dbus_register_object_per_iface(
+	struct wpas_dbus_priv *ctrl_iface,
+	const char *path, const char *ifname,
+	struct wpa_dbus_object_desc *obj_desc)
+{
+	DBusConnection *con;
+	DBusError error;
+
+	DBusObjectPathVTable vtable = {
+		&free_dbus_object_desc_cb, &message_handler,
+		NULL, NULL, NULL, NULL
+	};
+
+	/* Do nothing if the control interface is not turned on */
+	if (ctrl_iface == NULL)
+		return 0;
+
+	con = ctrl_iface->con;
+	obj_desc->connection = con;
+	obj_desc->path = os_strdup(path);
+
+	dbus_error_init(&error);
+	/* Register the message handler for the interface functions */
+	if (!dbus_connection_try_register_object_path(con, path, &vtable,
+						      obj_desc, &error)) {
+		if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+			wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
+		} else {
+			wpa_printf(MSG_ERROR, "dbus: Could not set up message "
+				   "handler for interface %s object %s",
+				   ifname, path);
+			wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
+			wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+		}
+		dbus_error_free(&error);
+		return -1;
+	}
+
+	dbus_error_free(&error);
+	return 0;
+}
+
+
+static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx);
+
+
+/**
+ * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
+ * @ctrl_iface: Pointer to dbus private data
+ * @path: DBus path to object which will be unregistered
+ * Returns: Zero on success and -1 on failure
+ *
+ * Unregisters DBus object given by its path
+ */
+int wpa_dbus_unregister_object_per_iface(
+	struct wpas_dbus_priv *ctrl_iface, const char *path)
+{
+	DBusConnection *con = ctrl_iface->con;
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+
+	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
+			   "private data: %s", __func__, path);
+	} else {
+		eloop_cancel_timeout(flush_object_timeout_handler, con,
+				     obj_desc);
+	}
+
+	if (!dbus_connection_unregister_object_path(con, path))
+		return -1;
+
+	return 0;
+}
+
+
+static dbus_bool_t put_changed_properties(
+	const struct wpa_dbus_object_desc *obj_dsc, const char *interface,
+	DBusMessageIter *dict_iter, int clear_changed)
+{
+	DBusMessageIter entry_iter;
+	const struct wpa_dbus_property_desc *dsc;
+	int i;
+	DBusError error;
+
+	for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
+	     dsc++, i++) {
+		if (obj_dsc->prop_changed_flags == NULL ||
+		    !obj_dsc->prop_changed_flags[i])
+			continue;
+		if (os_strcmp(dsc->dbus_interface, interface) != 0)
+			continue;
+		if (clear_changed)
+			obj_dsc->prop_changed_flags[i] = 0;
+
+		if (!dbus_message_iter_open_container(dict_iter,
+						      DBUS_TYPE_DICT_ENTRY,
+						      NULL, &entry_iter))
+			return FALSE;
+
+		if (!dbus_message_iter_append_basic(&entry_iter,
+						    DBUS_TYPE_STRING,
+						    &dsc->dbus_property))
+			return FALSE;
+
+		dbus_error_init(&error);
+		if (!dsc->getter(&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",
+				           __func__, dsc->dbus_property,
+				           error.name, error.message);
+			} else {
+				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
+					   "new value of property %s",
+					   __func__, dsc->dbus_property);
+			}
+			dbus_error_free(&error);
+			return FALSE;
+		}
+
+		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+static void do_send_prop_changed_signal(
+	DBusConnection *con, const char *path, const char *interface,
+	const struct wpa_dbus_object_desc *obj_dsc)
+{
+	DBusMessage *msg;
+	DBusMessageIter signal_iter, dict_iter;
+
+	msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES,
+				      "PropertiesChanged");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &signal_iter);
+
+	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
+					    &interface))
+		goto err;
+
+	/* Changed properties dict */
+	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "{sv}", &dict_iter))
+		goto err;
+
+	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
+		goto err;
+
+	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
+		goto err;
+
+	/* Invalidated properties array (empty) */
+	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "s", &dict_iter))
+		goto err;
+
+	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
+		goto err;
+
+	dbus_connection_send(con, msg, NULL);
+
+out:
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+		   __func__);
+	goto out;
+}
+
+
+static void do_send_deprecated_prop_changed_signal(
+	DBusConnection *con, const char *path, const char *interface,
+	const struct wpa_dbus_object_desc *obj_dsc)
+{
+	DBusMessage *msg;
+	DBusMessageIter signal_iter, dict_iter;
+
+	msg = dbus_message_new_signal(path, interface, "PropertiesChanged");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &signal_iter);
+
+	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "{sv}", &dict_iter))
+		goto err;
+
+	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
+		goto err;
+
+	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
+		goto err;
+
+	dbus_connection_send(con, msg, NULL);
+
+out:
+	dbus_message_unref(msg);
+	return;
+
+err:
+	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+		   __func__);
+	goto out;
+}
+
+
+static void send_prop_changed_signal(
+	DBusConnection *con, const char *path, const char *interface,
+	const struct wpa_dbus_object_desc *obj_dsc)
+{
+	/*
+	 * First, send property change notification on the standardized
+	 * org.freedesktop.DBus.Properties interface. This call will not
+	 * clear the property change bits, so that they are preserved for
+	 * the call that follows.
+	 */
+	do_send_prop_changed_signal(con, path, interface, obj_dsc);
+
+	/*
+	 * Now send PropertiesChanged on our own interface for backwards
+	 * compatibility. This is deprecated and will be removed in a future
+	 * release.
+	 */
+	do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc);
+
+	/* Property change bits have now been cleared. */
+}
+
+
+static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
+{
+	DBusConnection *con = eloop_ctx;
+	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
+
+	wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
+		   "of object %s", __func__, obj_desc->path);
+	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
+}
+
+
+static void recursive_flush_changed_properties(DBusConnection *con,
+					       const char *path)
+{
+	char **objects = NULL;
+	char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	int i;
+
+	wpa_dbus_flush_object_changed_properties(con, path);
+
+	if (!dbus_connection_list_registered(con, path, &objects))
+		goto out;
+
+	for (i = 0; objects[i]; i++) {
+		os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/%s", path, objects[i]);
+		recursive_flush_changed_properties(con, subobj_path);
+	}
+
+out:
+	dbus_free_string_array(objects);
+}
+
+
+/**
+ * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
+ * @con: DBus connection
+ *
+ * Traverses through all registered objects and sends PropertiesChanged for
+ * each properties.
+ */
+void wpa_dbus_flush_all_changed_properties(DBusConnection *con)
+{
+	recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH);
+}
+
+
+/**
+ * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
+ * @con: DBus connection
+ * @path: path to a DBus object for which PropertiesChanged will be sent.
+ *
+ * Iterates over all properties registered with object and for each interface
+ * containing properties marked as changed, sends a PropertiesChanged signal
+ * containing names and new values of properties that have changed.
+ *
+ * You need to call this function after wpa_dbus_mark_property_changed()
+ * if you want to send PropertiesChanged signal immediately (i.e., without
+ * waiting timeout to expire). PropertiesChanged signal for an object is sent
+ * automatically short time after first marking property as changed. All
+ * PropertiesChanged signals are sent automatically after responding on DBus
+ * message, so if you marked a property changed as a result of DBus call
+ * (e.g., param setter), you usually do not need to call this function.
+ */
+void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
+					      const char *path)
+{
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+	const struct wpa_dbus_property_desc *dsc;
+	int i;
+
+	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
+	if (!obj_desc)
+		return;
+	eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
+
+	dsc = obj_desc->properties;
+	for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property;
+	     dsc++, i++) {
+		if (obj_desc->prop_changed_flags == NULL ||
+		    !obj_desc->prop_changed_flags[i])
+			continue;
+		send_prop_changed_signal(con, path, dsc->dbus_interface,
+					 obj_desc);
+	}
+}
+
+
+#define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
+
+
+/**
+ * wpa_dbus_mark_property_changed - Mark a property as changed and
+ * @iface: dbus priv struct
+ * @path: path to DBus object which property has changed
+ * @interface: interface containing changed property
+ * @property: property name which has changed
+ *
+ * Iterates over all properties registered with an object and marks the one
+ * given in parameters as changed. All parameters registered for an object
+ * within a single interface will be aggregated together and sent in one
+ * PropertiesChanged signal when function
+ * wpa_dbus_flush_object_changed_properties() is called.
+ */
+void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
+				    const char *path, const char *interface,
+				    const char *property)
+{
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+	const struct wpa_dbus_property_desc *dsc;
+	int i = 0;
+
+	if (iface == NULL)
+		return;
+
+	dbus_connection_get_object_path_data(iface->con, path,
+					     (void **) &obj_desc);
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
+			   "could not obtain object's private data: %s", path);
+		return;
+	}
+
+	for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++)
+		if (os_strcmp(property, dsc->dbus_property) == 0 &&
+		    os_strcmp(interface, dsc->dbus_interface) == 0) {
+			if (obj_desc->prop_changed_flags)
+				obj_desc->prop_changed_flags[i] = 1;
+			break;
+		}
+
+	if (!dsc || !dsc->dbus_property) {
+		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
+			   "no property %s in object %s", property, path);
+		return;
+	}
+
+	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
+					 iface->con, obj_desc->path)) {
+		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
+				       flush_object_timeout_handler,
+				       iface->con, obj_desc);
+	}
+}
+
+
+/**
+ * wpa_dbus_get_object_properties - Put object's properties into dictionary
+ * @iface: dbus priv struct
+ * @path: path to DBus object which properties will be obtained
+ * @interface: interface name which properties will be obtained
+ * @iter: DBus message iter at which to append property dictionary.
+ *
+ * Iterates over all properties registered with object and execute getters
+ * of those, which are readable and which interface matches interface
+ * specified as argument. Obtained properties values are stored in
+ * dict_iter dictionary.
+ */
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+					   const char *path,
+					   const char *interface,
+					   DBusMessageIter *iter)
+{
+	struct wpa_dbus_object_desc *obj_desc = NULL;
+	DBusMessageIter dict_iter;
+	DBusError error;
+
+	dbus_connection_get_object_path_data(iface->con, path,
+					     (void **) &obj_desc);
+	if (!obj_desc) {
+		wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
+		           "private data: %s", __func__, path);
+		return FALSE;
+	}
+
+	if (!wpa_dbus_dict_open_write(iter, &dict_iter)) {
+		wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict",
+			   __func__);
+		return FALSE;
+	}
+
+	dbus_error_init(&error);
+	if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
+				       interface, obj_desc->user_data,
+				       &error)) {
+		wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
+		           " properties: (%s) %s", __func__,
+		           dbus_error_is_set(&error) ? error.name : "none",
+		           dbus_error_is_set(&error) ? error.message : "none");
+		dbus_error_free(&error);
+		return FALSE;
+	}
+
+	return wpa_dbus_dict_close_write(iter, &dict_iter);
+}
+
+/**
+ * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @p2p_persistent_group: indicates whether to parse the path as a P2P
+ *                        persistent group object
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char *wpas_dbus_new_decompose_object_path(const char *path,
+					   int p2p_persistent_group,
+					   char **network,
+					   char **bssid)
+{
+	const unsigned int dev_path_prefix_len =
+		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
+	char *obj_path_only;
+	char *next_sep;
+
+	/* Be a bit paranoid about path */
+	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+				dev_path_prefix_len))
+		return NULL;
+
+	/* Ensure there's something at the end of the path */
+	if ((path + dev_path_prefix_len)[0] == '\0')
+		return NULL;
+
+	obj_path_only = os_strdup(path);
+	if (obj_path_only == NULL)
+		return NULL;
+
+	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
+	if (next_sep != NULL) {
+		const char *net_part = os_strstr(
+			next_sep, p2p_persistent_group ?
+			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
+			WPAS_DBUS_NEW_NETWORKS_PART "/");
+		const char *bssid_part = os_strstr(
+			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+
+		if (network && net_part) {
+			/* Deal with a request for a configured network */
+			const char *net_name = net_part +
+				os_strlen(p2p_persistent_group ?
+					  WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
+					  "/" :
+					  WPAS_DBUS_NEW_NETWORKS_PART "/");
+			*network = NULL;
+			if (os_strlen(net_name))
+				*network = os_strdup(net_name);
+		} else if (bssid && bssid_part) {
+			/* Deal with a request for a scanned BSSID */
+			const char *bssid_name = bssid_part +
+				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
+			if (os_strlen(bssid_name))
+				*bssid = os_strdup(bssid_name);
+			else
+				*bssid = NULL;
+		}
+
+		/* Cut off interface object path before "/" */
+		*next_sep = '\0';
+	}
+
+	return obj_path_only;
+}
+
+
+/**
+ * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
+ *   dbus error structure
+ * @message: The original request message for which the error is a reply
+ * @error: The error containing a name and a descriptive error cause
+ * @fallback_name: A generic error name if @error was not set
+ * @fallback_string: A generic error string if @error was not set
+ * Returns: A new D-Bus error message
+ *
+ * Given a DBusMessage structure, creates a new D-Bus error message using
+ * the error name and string contained in that structure.
+ */
+DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message,
+					     DBusError *error,
+					     const char *fallback_name,
+					     const char *fallback_string)
+{
+	if (error && error->name && error->message) {
+		return dbus_message_new_error(message, error->name,
+					      error->message);
+	}
+	if (fallback_name && fallback_string) {
+		return dbus_message_new_error(message, fallback_name,
+					      fallback_string);
+	}
+	return NULL;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_helpers.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,147 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_DBUS_CTRL_H
-#define WPA_DBUS_CTRL_H
-
-#include <dbus/dbus.h>
-
-typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
-					       void *user_data);
-typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
-
-typedef DBusMessage * (* WPADBusPropertyAccessor)(DBusMessage *message,
-						  const void *user_data);
-
-struct wpa_dbus_object_desc {
-	DBusConnection *connection;
-	char *path;
-
-	/* list of methods, properties and signals registered with object */
-	const struct wpa_dbus_method_desc *methods;
-	const struct wpa_dbus_signal_desc *signals;
-	const struct wpa_dbus_property_desc *properties;
-
-	/* property changed flags */
-	u8 *prop_changed_flags;
-
-	/* argument for method handlers and properties
-	 * getter and setter functions */
-	void *user_data;
-	/* function used to free above argument */
-	WPADBusArgumentFreeFunction user_data_free_func;
-};
-
-enum dbus_prop_access { R, W, RW };
-
-enum dbus_arg_direction { ARG_IN, ARG_OUT };
-
-struct wpa_dbus_argument {
-	char *name;
-	char *type;
-	enum dbus_arg_direction dir;
-};
-
-#define END_ARGS { NULL, NULL, ARG_IN }
-
-/**
- * struct wpa_dbus_method_desc - DBus method description
- */
-struct wpa_dbus_method_desc {
-	/* method name */
-	const char *dbus_method;
-	/* method interface */
-	const char *dbus_interface;
-	/* method handling function */
-	WPADBusMethodHandler method_handler;
-	/* array of arguments */
-	struct wpa_dbus_argument args[3];
-};
-
-/**
- * struct wpa_dbus_signal_desc - DBus signal description
- */
-struct wpa_dbus_signal_desc {
-	/* signal name */
-	const char *dbus_signal;
-	/* signal interface */
-	const char *dbus_interface;
-	/* array of arguments */
-	struct wpa_dbus_argument args[3];
-};
-
-/**
- * struct wpa_dbus_property_desc - DBus property description
- */
-struct wpa_dbus_property_desc {
-	/* property name */
-	const char *dbus_property;
-	/* property interface */
-	const char *dbus_interface;
-	/* property type signature in DBus type notation */
-	const char *type;
-	/* property getter function */
-	WPADBusPropertyAccessor getter;
-	/* property setter function */
-	WPADBusPropertyAccessor setter;
-	/* property access permissions */
-	enum dbus_prop_access access;
-};
-
-
-#define WPAS_DBUS_OBJECT_PATH_MAX 150
-#define WPAS_DBUS_INTERFACE_MAX 150
-#define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50
-
-#define WPA_DBUS_INTROSPECTION_INTERFACE "org.freedesktop.DBus.Introspectable"
-#define WPA_DBUS_INTROSPECTION_METHOD "Introspect"
-#define WPA_DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
-#define WPA_DBUS_PROPERTIES_GET "Get"
-#define WPA_DBUS_PROPERTIES_SET "Set"
-#define WPA_DBUS_PROPERTIES_GETALL "GetAll"
-
-void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc);
-
-int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path,
-			     char *dbus_service,
-			     struct wpa_dbus_object_desc *obj_desc);
-
-int wpa_dbus_register_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface,
-	const char *path, const char *ifname,
-	struct wpa_dbus_object_desc *obj_desc);
-
-int wpa_dbus_unregister_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface,
-	const char *path);
-
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    DBusMessageIter *dict_iter);
-
-
-void wpa_dbus_flush_all_changed_properties(DBusConnection *con);
-
-void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
-					      const char *path);
-
-void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    const char *property);
-
-DBusMessage * wpa_dbus_introspect(DBusMessage *message,
-				  struct wpa_dbus_object_desc *obj_dsc);
-
-#endif /* WPA_DBUS_CTRL_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_helpers.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_helpers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,150 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_DBUS_CTRL_H
+#define WPA_DBUS_CTRL_H
+
+#include <dbus/dbus.h>
+
+typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
+					       void *user_data);
+typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
+
+typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
+                                                DBusError *error,
+						void *user_data);
+
+struct wpa_dbus_object_desc {
+	DBusConnection *connection;
+	char *path;
+
+	/* list of methods, properties and signals registered with object */
+	const struct wpa_dbus_method_desc *methods;
+	const struct wpa_dbus_signal_desc *signals;
+	const struct wpa_dbus_property_desc *properties;
+
+	/* property changed flags */
+	u8 *prop_changed_flags;
+
+	/* argument for method handlers and properties
+	 * getter and setter functions */
+	void *user_data;
+	/* function used to free above argument */
+	WPADBusArgumentFreeFunction user_data_free_func;
+};
+
+enum dbus_arg_direction { ARG_IN, ARG_OUT };
+
+struct wpa_dbus_argument {
+	char *name;
+	char *type;
+	enum dbus_arg_direction dir;
+};
+
+#define END_ARGS { NULL, NULL, ARG_IN }
+
+/**
+ * struct wpa_dbus_method_desc - DBus method description
+ */
+struct wpa_dbus_method_desc {
+	/* method name */
+	const char *dbus_method;
+	/* method interface */
+	const char *dbus_interface;
+	/* method handling function */
+	WPADBusMethodHandler method_handler;
+	/* array of arguments */
+	struct wpa_dbus_argument args[4];
+};
+
+/**
+ * struct wpa_dbus_signal_desc - DBus signal description
+ */
+struct wpa_dbus_signal_desc {
+	/* signal name */
+	const char *dbus_signal;
+	/* signal interface */
+	const char *dbus_interface;
+	/* array of arguments */
+	struct wpa_dbus_argument args[4];
+};
+
+/**
+ * struct wpa_dbus_property_desc - DBus property description
+ */
+struct wpa_dbus_property_desc {
+	/* property name */
+	const char *dbus_property;
+	/* property interface */
+	const char *dbus_interface;
+	/* property type signature in DBus type notation */
+	const char *type;
+	/* property getter function */
+	WPADBusPropertyAccessor getter;
+	/* property setter function */
+	WPADBusPropertyAccessor setter;
+};
+
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+#define WPAS_DBUS_INTERFACE_MAX 150
+#define WPAS_DBUS_METHOD_SIGNAL_PROP_MAX 50
+#define WPAS_DBUS_AUTH_MODE_MAX 64
+
+#define WPA_DBUS_INTROSPECTION_INTERFACE "org.freedesktop.DBus.Introspectable"
+#define WPA_DBUS_INTROSPECTION_METHOD "Introspect"
+#define WPA_DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define WPA_DBUS_PROPERTIES_GET "Get"
+#define WPA_DBUS_PROPERTIES_SET "Set"
+#define WPA_DBUS_PROPERTIES_GETALL "GetAll"
+
+void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc);
+
+int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path,
+			     char *dbus_service,
+			     struct wpa_dbus_object_desc *obj_desc);
+
+int wpa_dbus_register_object_per_iface(
+	struct wpas_dbus_priv *ctrl_iface,
+	const char *path, const char *ifname,
+	struct wpa_dbus_object_desc *obj_desc);
+
+int wpa_dbus_unregister_object_per_iface(
+	struct wpas_dbus_priv *ctrl_iface,
+	const char *path);
+
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+					   const char *path,
+					   const char *interface,
+					   DBusMessageIter *iter);
+
+
+void wpa_dbus_flush_all_changed_properties(DBusConnection *con);
+
+void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
+					      const char *path);
+
+void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
+				    const char *path, const char *interface,
+				    const char *property);
+
+DBusMessage * wpa_dbus_introspect(DBusMessage *message,
+				  struct wpa_dbus_object_desc *obj_dsc);
+
+char *wpas_dbus_new_decompose_object_path(const char *path,
+					   int p2p_persistent_group,
+					   char **network,
+					   char **bssid);
+
+DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
+					    DBusError *error,
+					    const char *fallback_name,
+					    const char *fallback_string);
+
+#endif /* WPA_DBUS_CTRL_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_introspect.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,278 +0,0 @@
-/*
- * wpa_supplicant - D-Bus introspection
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
- * Copyright (c) 2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/list.h"
-#include "utils/wpabuf.h"
-#include "dbus_common_i.h"
-#include "dbus_new_helpers.h"
-
-
-struct interfaces {
-	struct dl_list list;
-	char *dbus_interface;
-	struct wpabuf *xml;
-};
-
-
-static struct interfaces * add_interface(struct dl_list *list,
-					 const char *dbus_interface)
-{
-	struct interfaces *iface;
-
-	dl_list_for_each(iface, list, struct interfaces, list) {
-		if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
-			return iface; /* already in the list */
-	}
-
-	iface = os_zalloc(sizeof(struct interfaces));
-	if (!iface)
-		return NULL;
-	iface->xml = wpabuf_alloc(3000);
-	if (iface->xml == NULL) {
-		os_free(iface);
-		return NULL;
-	}
-	wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
-	dl_list_add_tail(list, &iface->list);
-	iface->dbus_interface = os_strdup(dbus_interface);
-	return iface;
-}
-
-
-static void add_arg(struct wpabuf *xml, const char *name, const char *type,
-		    const char *direction)
-{
-	wpabuf_printf(xml, "<arg name=\"%s\"", name);
-	if (type)
-		wpabuf_printf(xml, " type=\"%s\"", type);
-	if (direction)
-		wpabuf_printf(xml, " direction=\"%s\"", direction);
-	wpabuf_put_str(xml, "/>");
-}
-
-
-static void add_entry(struct wpabuf *xml, const char *type, const char *name,
-		      const struct wpa_dbus_argument *args, int include_dir)
-{
-	const struct wpa_dbus_argument *arg;
-
-	if (args == NULL || args->name == NULL) {
-		wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name);
-		return;
-	}
-	wpabuf_printf(xml, "<%s name=\"%s\">", type, name);
-	for (arg = args; arg && arg->name; arg++) {
-		add_arg(xml, arg->name, arg->type,
-			include_dir ? (arg->dir == ARG_IN ? "in" : "out") :
-			NULL);
-	}
-	wpabuf_printf(xml, "</%s>", type);
-}
-
-
-static void add_property(struct wpabuf *xml,
-			 const struct wpa_dbus_property_desc *dsc)
-{
-	wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
-		      dsc->dbus_property, dsc->type,
-		      (dsc->access == R ? "read" :
-		       (dsc->access == W ? "write" : "readwrite")));
-}
-
-
-static void extract_interfaces_methods(
-	struct dl_list *list, const struct wpa_dbus_method_desc *methods)
-{
-	const struct wpa_dbus_method_desc *dsc;
-	struct interfaces *iface;
-	for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
-		iface = add_interface(list, dsc->dbus_interface);
-		if (iface)
-			add_entry(iface->xml, "method", dsc->dbus_method,
-				  dsc->args, 1);
-	}
-}
-
-
-static void extract_interfaces_signals(
-	struct dl_list *list, const struct wpa_dbus_signal_desc *signals)
-{
-	const struct wpa_dbus_signal_desc *dsc;
-	struct interfaces *iface;
-	for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
-		iface = add_interface(list, dsc->dbus_interface);
-		if (iface)
-			add_entry(iface->xml, "signal", dsc->dbus_signal,
-				  dsc->args, 0);
-	}
-}
-
-
-static void extract_interfaces_properties(
-	struct dl_list *list, const struct wpa_dbus_property_desc *properties)
-{
-	const struct wpa_dbus_property_desc *dsc;
-	struct interfaces *iface;
-	for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
-		iface = add_interface(list, dsc->dbus_interface);
-		if (iface)
-			add_property(iface->xml, dsc);
-	}
-}
-
-
-/**
- * extract_interfaces - Extract interfaces from methods, signals and props
- * @list: Interface list to be filled
- * @obj_dsc: Description of object from which interfaces will be extracted
- *
- * Iterates over all methods, signals, and properties registered with an
- * object and collects all declared DBus interfaces and create interfaces'
- * node in XML root node for each. Returned list elements contain interface
- * name and XML node of corresponding interface.
- */
-static void extract_interfaces(struct dl_list *list,
-			       struct wpa_dbus_object_desc *obj_dsc)
-{
-	extract_interfaces_methods(list, obj_dsc->methods);
-	extract_interfaces_signals(list, obj_dsc->signals);
-	extract_interfaces_properties(list, obj_dsc->properties);
-}
-
-
-static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
-{
-	struct interfaces *iface, *n;
-	dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
-		if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
-			wpabuf_put_buf(xml, iface->xml);
-			wpabuf_put_str(xml, "</interface>");
-		}
-		dl_list_del(&iface->list);
-		wpabuf_free(iface->xml);
-		os_free(iface->dbus_interface);
-		os_free(iface);
-	}
-}
-
-
-static void add_child_nodes(struct wpabuf *xml, DBusConnection *con,
-			    const char *path)
-{
-	char **children;
-	int i;
-
-	/* add child nodes to introspection tree */
-	dbus_connection_list_registered(con, path, &children);
-	for (i = 0; children[i]; i++)
-		wpabuf_printf(xml, "<node name=\"%s\"/>", children[i]);
-	dbus_free_string_array(children);
-}
-
-
-static void add_introspectable_interface(struct wpabuf *xml)
-{
-	wpabuf_printf(xml, "<interface name=\"%s\">"
-		      "<method name=\"%s\">"
-		      "<arg name=\"data\" type=\"s\" direction=\"out\"/>"
-		      "</method>"
-		      "</interface>",
-		      WPA_DBUS_INTROSPECTION_INTERFACE,
-		      WPA_DBUS_INTROSPECTION_METHOD);
-}
-
-
-static void add_properties_interface(struct wpabuf *xml)
-{
-	wpabuf_printf(xml, "<interface name=\"%s\">",
-		      WPA_DBUS_PROPERTIES_INTERFACE);
-
-	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GET);
-	add_arg(xml, "interface", "s", "in");
-	add_arg(xml, "propname", "s", "in");
-	add_arg(xml, "value", "v", "out");
-	wpabuf_put_str(xml, "</method>");
-
-	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GETALL);
-	add_arg(xml, "interface", "s", "in");
-	add_arg(xml, "props", "a{sv}", "out");
-	wpabuf_put_str(xml, "</method>");
-
-	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_SET);
-	add_arg(xml, "interface", "s", "in");
-	add_arg(xml, "propname", "s", "in");
-	add_arg(xml, "value", "v", "in");
-	wpabuf_put_str(xml, "</method>");
-
-	wpabuf_put_str(xml, "</interface>");
-}
-
-
-static void add_wpas_interfaces(struct wpabuf *xml,
-				struct wpa_dbus_object_desc *obj_dsc)
-{
-	struct dl_list ifaces;
-	dl_list_init(&ifaces);
-	extract_interfaces(&ifaces, obj_dsc);
-	add_interfaces(&ifaces, xml);
-}
-
-
-/**
- * wpa_dbus_introspect - Responds for Introspect calls on object
- * @message: Message with Introspect call
- * @obj_dsc: Object description on which Introspect was called
- * Returns: Message with introspection result XML string as only argument
- *
- * Iterates over all methods, signals and properties registered with
- * object and generates introspection data for the object as XML string.
- */
-DBusMessage * wpa_dbus_introspect(DBusMessage *message,
-				  struct wpa_dbus_object_desc *obj_dsc)
-{
-
-	DBusMessage *reply;
-	struct wpabuf *xml;
-
-	xml = wpabuf_alloc(4000);
-	if (xml == NULL)
-		return NULL;
-
-	wpabuf_put_str(xml, "<?xml version=\"1.0\"?>\n");
-	wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
-	wpabuf_put_str(xml, "<node>");
-
-	add_introspectable_interface(xml);
-	add_properties_interface(xml);
-	add_wpas_interfaces(xml, obj_dsc);
-	add_child_nodes(xml, obj_dsc->connection,
-			dbus_message_get_path(message));
-
-	wpabuf_put_str(xml, "</node>\n");
-
-	reply = dbus_message_new_method_return(message);
-	if (reply) {
-		const char *intro_str = wpabuf_head(xml);
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
-					 DBUS_TYPE_INVALID);
-	}
-	wpabuf_free(xml);
-
-	return reply;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_new_introspect.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_new_introspect.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,279 @@
+/*
+ * wpa_supplicant - D-Bus introspection
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa at gmail.com>
+ * Copyright (c) 2010, Jouni Malinen <j at 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 "utils/list.h"
+#include "utils/wpabuf.h"
+#include "dbus_common_i.h"
+#include "dbus_new_helpers.h"
+
+
+struct interfaces {
+	struct dl_list list;
+	char *dbus_interface;
+	struct wpabuf *xml;
+};
+
+
+static struct interfaces * add_interface(struct dl_list *list,
+					 const char *dbus_interface)
+{
+	struct interfaces *iface;
+
+	dl_list_for_each(iface, list, struct interfaces, list) {
+		if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
+			return iface; /* already in the list */
+	}
+
+	iface = os_zalloc(sizeof(struct interfaces));
+	if (!iface)
+		return NULL;
+	iface->xml = wpabuf_alloc(6000);
+	if (iface->xml == NULL) {
+		os_free(iface);
+		return NULL;
+	}
+	wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
+	dl_list_add_tail(list, &iface->list);
+	iface->dbus_interface = os_strdup(dbus_interface);
+	return iface;
+}
+
+
+static void add_arg(struct wpabuf *xml, const char *name, const char *type,
+		    const char *direction)
+{
+	wpabuf_printf(xml, "<arg name=\"%s\"", name);
+	if (type)
+		wpabuf_printf(xml, " type=\"%s\"", type);
+	if (direction)
+		wpabuf_printf(xml, " direction=\"%s\"", direction);
+	wpabuf_put_str(xml, "/>");
+}
+
+
+static void add_entry(struct wpabuf *xml, const char *type, const char *name,
+		      const struct wpa_dbus_argument *args, int include_dir)
+{
+	const struct wpa_dbus_argument *arg;
+
+	if (args == NULL || args->name == NULL) {
+		wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name);
+		return;
+	}
+	wpabuf_printf(xml, "<%s name=\"%s\">", type, name);
+	for (arg = args; arg && arg->name; arg++) {
+		add_arg(xml, arg->name, arg->type,
+			include_dir ? (arg->dir == ARG_IN ? "in" : "out") :
+			NULL);
+	}
+	wpabuf_printf(xml, "</%s>", type);
+}
+
+
+static void add_property(struct wpabuf *xml,
+			 const struct wpa_dbus_property_desc *dsc)
+{
+	wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" "
+		      "access=\"%s%s\"/>",
+		      dsc->dbus_property, dsc->type,
+		      dsc->getter ? "read" : "",
+		      dsc->setter ? "write" : "");
+}
+
+
+static void extract_interfaces_methods(
+	struct dl_list *list, const struct wpa_dbus_method_desc *methods)
+{
+	const struct wpa_dbus_method_desc *dsc;
+	struct interfaces *iface;
+	for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
+		iface = add_interface(list, dsc->dbus_interface);
+		if (iface)
+			add_entry(iface->xml, "method", dsc->dbus_method,
+				  dsc->args, 1);
+	}
+}
+
+
+static void extract_interfaces_signals(
+	struct dl_list *list, const struct wpa_dbus_signal_desc *signals)
+{
+	const struct wpa_dbus_signal_desc *dsc;
+	struct interfaces *iface;
+	for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
+		iface = add_interface(list, dsc->dbus_interface);
+		if (iface)
+			add_entry(iface->xml, "signal", dsc->dbus_signal,
+				  dsc->args, 0);
+	}
+}
+
+
+static void extract_interfaces_properties(
+	struct dl_list *list, const struct wpa_dbus_property_desc *properties)
+{
+	const struct wpa_dbus_property_desc *dsc;
+	struct interfaces *iface;
+	for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
+		iface = add_interface(list, dsc->dbus_interface);
+		if (iface)
+			add_property(iface->xml, dsc);
+	}
+}
+
+
+/**
+ * extract_interfaces - Extract interfaces from methods, signals and props
+ * @list: Interface list to be filled
+ * @obj_dsc: Description of object from which interfaces will be extracted
+ *
+ * Iterates over all methods, signals, and properties registered with an
+ * object and collects all declared DBus interfaces and create interfaces'
+ * node in XML root node for each. Returned list elements contain interface
+ * name and XML node of corresponding interface.
+ */
+static void extract_interfaces(struct dl_list *list,
+			       struct wpa_dbus_object_desc *obj_dsc)
+{
+	extract_interfaces_methods(list, obj_dsc->methods);
+	extract_interfaces_signals(list, obj_dsc->signals);
+	extract_interfaces_properties(list, obj_dsc->properties);
+}
+
+
+static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
+{
+	struct interfaces *iface, *n;
+	dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
+		if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
+			wpabuf_put_buf(xml, iface->xml);
+			wpabuf_put_str(xml, "</interface>");
+		} else {
+			wpa_printf(MSG_DEBUG, "dbus: Not enough room for "
+				   "add_interfaces inspect data: tailroom %u, "
+				   "add %u",
+				   (unsigned int) wpabuf_tailroom(xml),
+				   (unsigned int) wpabuf_len(iface->xml));
+		}
+		dl_list_del(&iface->list);
+		wpabuf_free(iface->xml);
+		os_free(iface->dbus_interface);
+		os_free(iface);
+	}
+}
+
+
+static void add_child_nodes(struct wpabuf *xml, DBusConnection *con,
+			    const char *path)
+{
+	char **children;
+	int i;
+
+	/* add child nodes to introspection tree */
+	dbus_connection_list_registered(con, path, &children);
+	for (i = 0; children[i]; i++)
+		wpabuf_printf(xml, "<node name=\"%s\"/>", children[i]);
+	dbus_free_string_array(children);
+}
+
+
+static void add_introspectable_interface(struct wpabuf *xml)
+{
+	wpabuf_printf(xml, "<interface name=\"%s\">"
+		      "<method name=\"%s\">"
+		      "<arg name=\"data\" type=\"s\" direction=\"out\"/>"
+		      "</method>"
+		      "</interface>",
+		      WPA_DBUS_INTROSPECTION_INTERFACE,
+		      WPA_DBUS_INTROSPECTION_METHOD);
+}
+
+
+static void add_properties_interface(struct wpabuf *xml)
+{
+	wpabuf_printf(xml, "<interface name=\"%s\">",
+		      WPA_DBUS_PROPERTIES_INTERFACE);
+
+	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GET);
+	add_arg(xml, "interface", "s", "in");
+	add_arg(xml, "propname", "s", "in");
+	add_arg(xml, "value", "v", "out");
+	wpabuf_put_str(xml, "</method>");
+
+	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GETALL);
+	add_arg(xml, "interface", "s", "in");
+	add_arg(xml, "props", "a{sv}", "out");
+	wpabuf_put_str(xml, "</method>");
+
+	wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_SET);
+	add_arg(xml, "interface", "s", "in");
+	add_arg(xml, "propname", "s", "in");
+	add_arg(xml, "value", "v", "in");
+	wpabuf_put_str(xml, "</method>");
+
+	wpabuf_put_str(xml, "</interface>");
+}
+
+
+static void add_wpas_interfaces(struct wpabuf *xml,
+				struct wpa_dbus_object_desc *obj_dsc)
+{
+	struct dl_list ifaces;
+	dl_list_init(&ifaces);
+	extract_interfaces(&ifaces, obj_dsc);
+	add_interfaces(&ifaces, xml);
+}
+
+
+/**
+ * wpa_dbus_introspect - Responds for Introspect calls on object
+ * @message: Message with Introspect call
+ * @obj_dsc: Object description on which Introspect was called
+ * Returns: Message with introspection result XML string as only argument
+ *
+ * Iterates over all methods, signals and properties registered with
+ * object and generates introspection data for the object as XML string.
+ */
+DBusMessage * wpa_dbus_introspect(DBusMessage *message,
+				  struct wpa_dbus_object_desc *obj_dsc)
+{
+
+	DBusMessage *reply;
+	struct wpabuf *xml;
+
+	xml = wpabuf_alloc(10000);
+	if (xml == NULL)
+		return NULL;
+
+	wpabuf_put_str(xml, "<?xml version=\"1.0\"?>\n");
+	wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
+	wpabuf_put_str(xml, "<node>");
+
+	add_introspectable_interface(xml);
+	add_properties_interface(xml);
+	add_wpas_interfaces(xml, obj_dsc);
+	add_child_nodes(xml, obj_dsc->connection,
+			dbus_message_get_path(message));
+
+	wpabuf_put_str(xml, "</node>\n");
+
+	reply = dbus_message_new_method_return(message);
+	if (reply) {
+		const char *intro_str = wpabuf_head(xml);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
+					 DBUS_TYPE_INVALID);
+	}
+	wpabuf_free(xml);
+
+	return reply;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_old.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,695 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "wps/wps.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../bss.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_common.h"
-#include "dbus_common_i.h"
-
-
-/**
- * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
-				       char **bssid)
-{
-	const unsigned int dev_path_prefix_len =
-		strlen(WPAS_DBUS_PATH_INTERFACES "/");
-	char *obj_path_only;
-	char *next_sep;
-
-	/* Be a bit paranoid about path */
-	if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
-			     dev_path_prefix_len))
-		return NULL;
-
-	/* Ensure there's something at the end of the path */
-	if ((path + dev_path_prefix_len)[0] == '\0')
-		return NULL;
-
-	obj_path_only = os_strdup(path);
-	if (obj_path_only == NULL)
-		return NULL;
-
-	next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
-	if (next_sep != NULL) {
-		const char *net_part = strstr(next_sep,
-					      WPAS_DBUS_NETWORKS_PART "/");
-		const char *bssid_part = strstr(next_sep,
-						WPAS_DBUS_BSSIDS_PART "/");
-
-		if (network && net_part) {
-			/* Deal with a request for a configured network */
-			const char *net_name = net_part +
-				strlen(WPAS_DBUS_NETWORKS_PART "/");
-			*network = NULL;
-			if (strlen(net_name))
-				*network = os_strdup(net_name);
-		} else if (bssid && bssid_part) {
-			/* Deal with a request for a scanned BSSID */
-			const char *bssid_name = bssid_part +
-				strlen(WPAS_DBUS_BSSIDS_PART "/");
-			if (strlen(bssid_name))
-				*bssid = os_strdup(bssid_name);
-			else
-				*bssid = NULL;
-		}
-
-		/* Cut off interface object path before "/" */
-		*next_sep = '\0';
-	}
-
-	return obj_path_only;
-}
-
-
-/**
- * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: A dbus error message
- *
- * Convenience function to create and return an invalid interface error
- */
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
-{
-	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid network error
- */
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
-{
-	return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
-				      "The requested network does not exist.");
-}
-
-
-/**
- * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid bssid error
- */
-static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
-{
-	return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
-				      "The BSSID requested was invalid.");
-}
-
-
-/**
- * wpas_dispatch_network_method - dispatch messages for configured networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @network_id: id of the configured network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for configured networks.
- */
-static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
-						  struct wpa_supplicant *wpa_s,
-						  int network_id)
-{
-	DBusMessage *reply = NULL;
-	const char *method = dbus_message_get_member(message);
-	struct wpa_ssid *ssid;
-
-	ssid = wpa_config_get_network(wpa_s->conf, network_id);
-	if (ssid == NULL)
-		return wpas_dbus_new_invalid_network_error(message);
-
-	if (!strcmp(method, "set"))
-		reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
-	else if (!strcmp(method, "enable"))
-		reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
-	else if (!strcmp(method, "disable"))
-		reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
-
-	return reply;
-}
-
-
-/**
- * wpas_dispatch_bssid_method - dispatch messages for scanned networks
- * @message: the incoming dbus message
- * @wpa_s: a network interface's data
- * @bssid: bssid of the scanned network we're interested in
- * Returns: a reply dbus message, or a dbus error message
- *
- * This function dispatches all incoming dbus messages for scanned networks.
- */
-static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
-						struct wpa_supplicant *wpa_s,
-						const char *bssid_txt)
-{
-	u8 bssid[ETH_ALEN];
-	struct wpa_bss *bss;
-
-	if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
-		return wpas_dbus_new_invalid_bssid_error(message);
-
-	bss = wpa_bss_get_bssid(wpa_s, bssid);
-	if (bss == NULL)
-		return wpas_dbus_new_invalid_bssid_error(message);
-
-	/* Dispatch the method call against the scanned bssid */
-	if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
-		return wpas_dbus_bssid_properties(message, wpa_s, bss);
-
-	return NULL;
-}
-
-
-/**
- * wpas_iface_message_handler - Dispatch messages for interfaces or networks
- * @connection: Connection to the system message bus
- * @message: An incoming dbus message
- * @user_data: A pointer to a dbus control interface data structure
- * Returns: Whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages for network interfaces,
- * or objects owned by them, such as scanned BSSIDs and configured networks.
- */
-static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
-						    DBusMessage *message,
-						    void *user_data)
-{
-	struct wpa_supplicant *wpa_s = user_data;
-	const char *method = dbus_message_get_member(message);
-	const char *path = dbus_message_get_path(message);
-	const char *msg_interface = dbus_message_get_interface(message);
-	char *iface_obj_path = NULL;
-	char *network = NULL;
-	char *bssid = NULL;
-	DBusMessage *reply = NULL;
-
-	/* Caller must specify a message interface */
-	if (!msg_interface)
-		goto out;
-
-	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
-	                                                 &bssid);
-	if (iface_obj_path == NULL) {
-		reply = wpas_dbus_new_invalid_iface_error(message);
-		goto out;
-	}
-
-	/* Make sure the message's object path actually refers to the
-	 * wpa_supplicant structure it's supposed to (which is wpa_s)
-	 */
-	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
-	                                          iface_obj_path) != wpa_s) {
-		reply = wpas_dbus_new_invalid_iface_error(message);
-		goto out;
-	}
-
-	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
-		/* A method for one of this interface's configured networks */
-		int nid = strtoul(network, NULL, 10);
-		if (errno != EINVAL)
-			reply = wpas_dispatch_network_method(message, wpa_s,
-							     nid);
-		else
-			reply = wpas_dbus_new_invalid_network_error(message);
-	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
-		/* A method for one of this interface's scanned BSSIDs */
-		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
-	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
-		/* A method for an interface only. */
-		if (!strcmp(method, "scan"))
-			reply = wpas_dbus_iface_scan(message, wpa_s);
-		else if (!strcmp(method, "scanResults"))
-			reply = wpas_dbus_iface_scan_results(message, wpa_s);
-		else if (!strcmp(method, "addNetwork"))
-			reply = wpas_dbus_iface_add_network(message, wpa_s);
-		else if (!strcmp(method, "removeNetwork"))
-			reply = wpas_dbus_iface_remove_network(message, wpa_s);
-		else if (!strcmp(method, "selectNetwork"))
-			reply = wpas_dbus_iface_select_network(message, wpa_s);
-		else if (!strcmp(method, "capabilities"))
-			reply = wpas_dbus_iface_capabilities(message, wpa_s);
-		else if (!strcmp(method, "disconnect"))
-			reply = wpas_dbus_iface_disconnect(message, wpa_s);
-		else if (!strcmp(method, "setAPScan"))
-			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
-		else if (!strcmp(method, "setSmartcardModules"))
-			reply = wpas_dbus_iface_set_smartcard_modules(message,
-								      wpa_s);
-		else if (!strcmp(method, "state"))
-			reply = wpas_dbus_iface_get_state(message, wpa_s);
-		else if (!strcmp(method, "scanning"))
-			reply = wpas_dbus_iface_get_scanning(message, wpa_s);
-		else if (!strcmp(method, "setBlobs"))
-			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
-		else if (!strcmp(method, "removeBlobs"))
-			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
-#ifdef CONFIG_WPS
-		else if (!os_strcmp(method, "wpsPbc"))
-			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
-		else if (!os_strcmp(method, "wpsPin"))
-			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
-		else if (!os_strcmp(method, "wpsReg"))
-			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
-#endif /* CONFIG_WPS */
-	}
-
-	/* If the message was handled, send back the reply */
-	if (reply) {
-		if (!dbus_message_get_no_reply(message))
-			dbus_connection_send(connection, reply, NULL);
-		dbus_message_unref(reply);
-	}
-
-out:
-	os_free(iface_obj_path);
-	os_free(network);
-	os_free(bssid);
-	return reply ? DBUS_HANDLER_RESULT_HANDLED :
-		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpas_message_handler - dispatch incoming dbus messages
- * @connection: connection to the system message bus
- * @message: an incoming dbus message
- * @user_data: a pointer to a dbus control interface data structure
- * Returns: whether or not the message was handled
- *
- * This function dispatches all incoming dbus messages to the correct
- * handlers, depending on what the message's target object path is,
- * and what the method call is.
- */
-static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
-	DBusMessage *message, void *user_data)
-{
-	struct wpas_dbus_priv *ctrl_iface = user_data;
-	const char *method;
-	const char *path;
-	const char *msg_interface;
-	DBusMessage *reply = NULL;
-
-	method = dbus_message_get_member(message);
-	path = dbus_message_get_path(message);
-	msg_interface = dbus_message_get_interface(message);
-	if (!method || !path || !ctrl_iface || !msg_interface)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	/* Validate the method interface */
-	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	if (!strcmp(path, WPAS_DBUS_PATH)) {
-		/* dispatch methods against our global dbus interface here */
-		if (!strcmp(method, "addInterface")) {
-			reply = wpas_dbus_global_add_interface(
-				message, ctrl_iface->global);
-		} else if (!strcmp(method, "removeInterface")) {
-			reply = wpas_dbus_global_remove_interface(
-				message, ctrl_iface->global);
-		} else if (!strcmp(method, "getInterface")) {
-			reply = wpas_dbus_global_get_interface(
-				message, ctrl_iface->global);
-		} else if (!strcmp(method, "setDebugParams")) {
-			reply = wpas_dbus_global_set_debugparams(
-				message, ctrl_iface->global);
-		}
-	}
-
-	/* If the message was handled, send back the reply */
-	if (reply) {
-		if (!dbus_message_get_no_reply(message))
-			dbus_connection_send(connection, reply, NULL);
-		dbus_message_unref(reply);
-	}
-
-	return reply ? DBUS_HANDLER_RESULT_HANDLED :
-		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that this interface has updated scan results.
- */
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
-	DBusMessage *_signal;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	_signal = dbus_message_new_signal(wpa_s->dbus_path,
-					  WPAS_DBUS_IFACE_INTERFACE,
-					  "ScanResultsAvailable");
-	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
-		return;
-	}
-	dbus_connection_send(iface->con, _signal, NULL);
-	dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_state_change - Send a state change signal
- * @wpa_s: %wpa_supplicant network interface data
- * @new_state: new state wpa_supplicant is entering
- * @old_state: old state wpa_supplicant is leaving
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners that wpa_supplicant has changed state
- */
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
-					     enum wpa_states new_state,
-					     enum wpa_states old_state)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *_signal = NULL;
-	const char *new_state_str, *old_state_str;
-
-	if (wpa_s->dbus_path == NULL)
-		return; /* Skip signal since D-Bus setup is not yet ready */
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s->global == NULL)
-		return;
-	iface = wpa_s->global->dbus;
-	if (iface == NULL)
-		return;
-
-	/* Only send signal if state really changed */
-	if (new_state == old_state)
-		return;
-
-	_signal = dbus_message_new_signal(wpa_s->dbus_path,
-					  WPAS_DBUS_IFACE_INTERFACE,
-					  "StateChange");
-	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "could not create dbus signal; likely out of "
-		           "memory");
-		return;
-	}
-
-	new_state_str = wpa_supplicant_state_txt(new_state);
-	old_state_str = wpa_supplicant_state_txt(old_state);
-	if (new_state_str == NULL || old_state_str == NULL) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "Could not convert state strings");
-		goto out;
-	}
-
-	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_STRING, &new_state_str,
-	                              DBUS_TYPE_STRING, &old_state_str,
-	                              DBUS_TYPE_INVALID)) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "Not enough memory to construct state change "
-		           "signal");
-		goto out;
-	}
-
-	dbus_connection_send(iface->con, _signal, NULL);
-
-out:
-	dbus_message_unref(_signal);
-}
-
-
-/**
- * wpa_supplicant_dbus_notify_scanning - send scanning status
- * @wpa_s: %wpa_supplicant network interface data
- * Returns: 0 on success, -1 on failure
- *
- * Notify listeners of interface scanning state changes
- */
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
-	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
-	DBusMessage *_signal;
-	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
-	/* Do nothing if the control interface is not turned on */
-	if (iface == NULL)
-		return;
-
-	_signal = dbus_message_new_signal(wpa_s->dbus_path,
-					  WPAS_DBUS_IFACE_INTERFACE,
-					  "Scanning");
-	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
-		return;
-	}
-
-	if (dbus_message_append_args(_signal,
-	                             DBUS_TYPE_BOOLEAN, &scanning,
-	                             DBUS_TYPE_INVALID)) {
-		dbus_connection_send(iface->con, _signal, NULL);
-	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
-			   "signal");
-	}
-	dbus_message_unref(_signal);
-}
-
-
-#ifdef CONFIG_WPS
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
-					 const struct wps_credential *cred)
-{
-	struct wpas_dbus_priv *iface;
-	DBusMessage *_signal = NULL;
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s->global == NULL)
-		return;
-	iface = wpa_s->global->dbus;
-	if (iface == NULL)
-		return;
-
-	_signal = dbus_message_new_signal(wpa_s->dbus_path,
-					  WPAS_DBUS_IFACE_INTERFACE,
-					  "WpsCred");
-	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Could not create dbus signal; likely out of "
-		           "memory");
-		return;
-	}
-
-	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
-				      &cred->cred_attr, cred->cred_attr_len,
-	                              DBUS_TYPE_INVALID)) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Not enough memory to construct signal");
-		goto out;
-	}
-
-	dbus_connection_send(iface->con, _signal, NULL);
-
-out:
-	dbus_message_unref(_signal);
-}
-#else /* CONFIG_WPS */
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
-					 const struct wps_credential *cred)
-{
-}
-#endif /* CONFIG_WPS */
-
-
-/**
- * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the dbus control interface and start receiving commands from
- * external programs over the bus.
- */
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
-{
-	DBusError error;
-	int ret = -1;
-	DBusObjectPathVTable wpas_vtable = {
-		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
-	};
-
-	/* Register the message handler for the global dbus interface */
-	if (!dbus_connection_register_object_path(iface->con,
-						  WPAS_DBUS_PATH, &wpas_vtable,
-						  iface)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
-		return -1;
-	}
-
-	/* Register our service with the message bus */
-	dbus_error_init(&error);
-	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
-				      0, &error)) {
-	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
-		ret = 0;
-		break;
-	case DBUS_REQUEST_NAME_REPLY_EXISTS:
-	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
-	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
-		break;
-	}
-	dbus_error_free(&error);
-
-	if (ret != 0)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
-		   "'.");
-
-	return 0;
-}
-
-
-/**
- * wpas_dbus_register_new_iface - Register a new interface with dbus
- * @wpa_s: %wpa_supplicant interface description structure to register
- * Returns: 0 on success, -1 on error
- *
- * Registers a new interface with dbus and assigns it a dbus object path.
- */
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
-	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
-	DBusConnection * con;
-	u32 next;
-	DBusObjectPathVTable vtable = {
-		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
-	};
-
-	/* Do nothing if the control interface is not turned on */
-	if (ctrl_iface == NULL)
-		return 0;
-
-	con = ctrl_iface->con;
-	next = ctrl_iface->next_objid++;
-
-	/* Create and set the interface's object path */
-	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
-	if (wpa_s->dbus_path == NULL)
-		return -1;
-	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
-		    WPAS_DBUS_PATH_INTERFACES "/%u",
-		    next);
-
-	/* Register the message handler for the interface functions */
-	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
-					       wpa_s)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler for interface %s", wpa_s->ifname);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * wpas_dbus_unregister_iface - Unregister an interface from dbus
- * @wpa_s: wpa_supplicant interface structure
- * Returns: 0 on success, -1 on failure
- *
- * Unregisters the interface with dbus
- */
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
-	struct wpas_dbus_priv *ctrl_iface;
-	DBusConnection *con;
-
-	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL)
-		return 0;
-	ctrl_iface = wpa_s->global->dbus;
-	if (ctrl_iface == NULL)
-		return 0;
-
-	con = ctrl_iface->con;
-	if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
-		return -1;
-
-	os_free(wpa_s->dbus_path);
-	wpa_s->dbus_path = NULL;
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @path: Pointer to a dbus object path representing an interface
- * Returns: Pointer to the interface or %NULL if not found
- */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
-	struct wpa_global *global, const char *path)
-{
-	struct wpa_supplicant *wpa_s;
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		if (strcmp(wpa_s->dbus_path, path) == 0)
-			return wpa_s;
-	}
-	return NULL;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_old.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,743 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "wps/wps.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../bss.h"
+#include "dbus_old.h"
+#include "dbus_old_handlers.h"
+#include "dbus_common_i.h"
+
+
+/**
+ * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char * wpas_dbus_decompose_object_path(const char *path, char **network,
+				       char **bssid)
+{
+	const unsigned int dev_path_prefix_len =
+		strlen(WPAS_DBUS_PATH_INTERFACES "/");
+	char *obj_path_only;
+	char *next_sep;
+
+	/* Be a bit paranoid about path */
+	if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
+			     dev_path_prefix_len))
+		return NULL;
+
+	/* Ensure there's something at the end of the path */
+	if ((path + dev_path_prefix_len)[0] == '\0')
+		return NULL;
+
+	obj_path_only = os_strdup(path);
+	if (obj_path_only == NULL)
+		return NULL;
+
+	next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
+	if (next_sep != NULL) {
+		const char *net_part = strstr(next_sep,
+					      WPAS_DBUS_NETWORKS_PART "/");
+		const char *bssid_part = strstr(next_sep,
+						WPAS_DBUS_BSSIDS_PART "/");
+
+		if (network && net_part) {
+			/* Deal with a request for a configured network */
+			const char *net_name = net_part +
+				strlen(WPAS_DBUS_NETWORKS_PART "/");
+			*network = NULL;
+			if (strlen(net_name))
+				*network = os_strdup(net_name);
+		} else if (bssid && bssid_part) {
+			/* Deal with a request for a scanned BSSID */
+			const char *bssid_name = bssid_part +
+				strlen(WPAS_DBUS_BSSIDS_PART "/");
+			if (strlen(bssid_name))
+				*bssid = os_strdup(bssid_name);
+			else
+				*bssid = NULL;
+		}
+
+		/* Cut off interface object path before "/" */
+		*next_sep = '\0';
+	}
+
+	return obj_path_only;
+}
+
+
+/**
+ * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: A dbus error message
+ *
+ * Convenience function to create and return an invalid interface error
+ */
+DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
+				      "wpa_supplicant knows nothing about "
+				      "this interface.");
+}
+
+
+/**
+ * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid network error
+ */
+DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
+				      "The requested network does not exist.");
+}
+
+
+/**
+ * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid bssid error
+ */
+static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
+{
+	return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
+				      "The BSSID requested was invalid.");
+}
+
+
+/**
+ * wpas_dispatch_network_method - dispatch messages for configured networks
+ * @message: the incoming dbus message
+ * @wpa_s: a network interface's data
+ * @network_id: id of the configured network we're interested in
+ * Returns: a reply dbus message, or a dbus error message
+ *
+ * This function dispatches all incoming dbus messages for configured networks.
+ */
+static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s,
+						  int network_id)
+{
+	DBusMessage *reply = NULL;
+	const char *method = dbus_message_get_member(message);
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_get_network(wpa_s->conf, network_id);
+	if (ssid == NULL)
+		return wpas_dbus_new_invalid_network_error(message);
+
+	if (!strcmp(method, "set"))
+		reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
+	else if (!strcmp(method, "enable"))
+		reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
+	else if (!strcmp(method, "disable"))
+		reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
+
+	return reply;
+}
+
+
+/**
+ * wpas_dispatch_bssid_method - dispatch messages for scanned networks
+ * @message: the incoming dbus message
+ * @wpa_s: a network interface's data
+ * @bssid: bssid of the scanned network we're interested in
+ * Returns: a reply dbus message, or a dbus error message
+ *
+ * This function dispatches all incoming dbus messages for scanned networks.
+ */
+static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
+						struct wpa_supplicant *wpa_s,
+						const char *bssid_txt)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+
+	if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
+		return wpas_dbus_new_invalid_bssid_error(message);
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (bss == NULL)
+		return wpas_dbus_new_invalid_bssid_error(message);
+
+	/* Dispatch the method call against the scanned bssid */
+	if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
+		return wpas_dbus_bssid_properties(message, wpa_s, bss);
+
+	return NULL;
+}
+
+
+/**
+ * wpas_iface_message_handler - Dispatch messages for interfaces or networks
+ * @connection: Connection to the system message bus
+ * @message: An incoming dbus message
+ * @user_data: A pointer to a dbus control interface data structure
+ * Returns: Whether or not the message was handled
+ *
+ * This function dispatches all incoming dbus messages for network interfaces,
+ * or objects owned by them, such as scanned BSSIDs and configured networks.
+ */
+static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
+						    DBusMessage *message,
+						    void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	const char *method = dbus_message_get_member(message);
+	const char *path = dbus_message_get_path(message);
+	const char *msg_interface = dbus_message_get_interface(message);
+	char *iface_obj_path = NULL;
+	char *network = NULL;
+	char *bssid = NULL;
+	DBusMessage *reply = NULL;
+
+	/* Caller must specify a message interface */
+	if (!msg_interface)
+		goto out;
+
+	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
+	                                                 &bssid);
+	if (iface_obj_path == NULL) {
+		reply = wpas_dbus_new_invalid_iface_error(message);
+		goto out;
+	}
+
+	/* Make sure the message's object path actually refers to the
+	 * wpa_supplicant structure it's supposed to (which is wpa_s)
+	 */
+	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
+	                                          iface_obj_path) != wpa_s) {
+		reply = wpas_dbus_new_invalid_iface_error(message);
+		goto out;
+	}
+
+	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
+		/* A method for one of this interface's configured networks */
+		int nid = strtoul(network, NULL, 10);
+		if (errno != EINVAL)
+			reply = wpas_dispatch_network_method(message, wpa_s,
+							     nid);
+		else
+			reply = wpas_dbus_new_invalid_network_error(message);
+	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
+		/* A method for one of this interface's scanned BSSIDs */
+		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
+	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
+		/* A method for an interface only. */
+		if (!strcmp(method, "scan"))
+			reply = wpas_dbus_iface_scan(message, wpa_s);
+		else if (!strcmp(method, "scanResults"))
+			reply = wpas_dbus_iface_scan_results(message, wpa_s);
+		else if (!strcmp(method, "addNetwork"))
+			reply = wpas_dbus_iface_add_network(message, wpa_s);
+		else if (!strcmp(method, "removeNetwork"))
+			reply = wpas_dbus_iface_remove_network(message, wpa_s);
+		else if (!strcmp(method, "selectNetwork"))
+			reply = wpas_dbus_iface_select_network(message, wpa_s);
+		else if (!strcmp(method, "capabilities"))
+			reply = wpas_dbus_iface_capabilities(message, wpa_s);
+		else if (!strcmp(method, "disconnect"))
+			reply = wpas_dbus_iface_disconnect(message, wpa_s);
+		else if (!strcmp(method, "setAPScan"))
+			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
+		else if (!strcmp(method, "setSmartcardModules"))
+			reply = wpas_dbus_iface_set_smartcard_modules(message,
+								      wpa_s);
+		else if (!strcmp(method, "state"))
+			reply = wpas_dbus_iface_get_state(message, wpa_s);
+		else if (!strcmp(method, "scanning"))
+			reply = wpas_dbus_iface_get_scanning(message, wpa_s);
+		else if (!strcmp(method, "setBlobs"))
+			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
+		else if (!strcmp(method, "removeBlobs"))
+			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
+#ifdef CONFIG_WPS
+		else if (!os_strcmp(method, "wpsPbc"))
+			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
+		else if (!os_strcmp(method, "wpsPin"))
+			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
+		else if (!os_strcmp(method, "wpsReg"))
+			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
+#endif /* CONFIG_WPS */
+		else if (!os_strcmp(method, "flush"))
+			reply = wpas_dbus_iface_flush(message, wpa_s);
+	}
+
+	/* If the message was handled, send back the reply */
+	if (reply) {
+		if (!dbus_message_get_no_reply(message))
+			dbus_connection_send(connection, reply, NULL);
+		dbus_message_unref(reply);
+	}
+
+out:
+	os_free(iface_obj_path);
+	os_free(network);
+	os_free(bssid);
+	return reply ? DBUS_HANDLER_RESULT_HANDLED :
+		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+/**
+ * wpas_message_handler - dispatch incoming dbus messages
+ * @connection: connection to the system message bus
+ * @message: an incoming dbus message
+ * @user_data: a pointer to a dbus control interface data structure
+ * Returns: whether or not the message was handled
+ *
+ * This function dispatches all incoming dbus messages to the correct
+ * handlers, depending on what the message's target object path is,
+ * and what the method call is.
+ */
+static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
+	DBusMessage *message, void *user_data)
+{
+	struct wpas_dbus_priv *ctrl_iface = user_data;
+	const char *method;
+	const char *path;
+	const char *msg_interface;
+	DBusMessage *reply = NULL;
+
+	method = dbus_message_get_member(message);
+	path = dbus_message_get_path(message);
+	msg_interface = dbus_message_get_interface(message);
+	if (!method || !path || !ctrl_iface || !msg_interface)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	/* Validate the method interface */
+	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (!strcmp(path, WPAS_DBUS_PATH)) {
+		/* dispatch methods against our global dbus interface here */
+		if (!strcmp(method, "addInterface")) {
+			reply = wpas_dbus_global_add_interface(
+				message, ctrl_iface->global);
+		} else if (!strcmp(method, "removeInterface")) {
+			reply = wpas_dbus_global_remove_interface(
+				message, ctrl_iface->global);
+		} else if (!strcmp(method, "getInterface")) {
+			reply = wpas_dbus_global_get_interface(
+				message, ctrl_iface->global);
+		} else if (!strcmp(method, "setDebugParams")) {
+			reply = wpas_dbus_global_set_debugparams(
+				message, ctrl_iface->global);
+		}
+	}
+
+	/* If the message was handled, send back the reply */
+	if (reply) {
+		if (!dbus_message_get_no_reply(message))
+			dbus_connection_send(connection, reply, NULL);
+		dbus_message_unref(reply);
+	}
+
+	return reply ? DBUS_HANDLER_RESULT_HANDLED :
+		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+/**
+ * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners that this interface has updated scan results.
+ */
+void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+	DBusMessage *_signal;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	_signal = dbus_message_new_signal(wpa_s->dbus_path,
+					  WPAS_DBUS_IFACE_INTERFACE,
+					  "ScanResultsAvailable");
+	if (_signal == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
+			   "results signal");
+		return;
+	}
+	dbus_connection_send(iface->con, _signal, NULL);
+	dbus_message_unref(_signal);
+}
+
+
+/**
+ * wpa_supplicant_dbus_notify_state_change - Send a state change signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @new_state: new state wpa_supplicant is entering
+ * @old_state: old state wpa_supplicant is leaving
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners that wpa_supplicant has changed state
+ */
+void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+					     enum wpa_states new_state,
+					     enum wpa_states old_state)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *_signal = NULL;
+	const char *new_state_str, *old_state_str;
+
+	if (wpa_s->dbus_path == NULL)
+		return; /* Skip signal since D-Bus setup is not yet ready */
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s->global == NULL)
+		return;
+	iface = wpa_s->global->dbus;
+	if (iface == NULL)
+		return;
+
+	/* Only send signal if state really changed */
+	if (new_state == old_state)
+		return;
+
+	_signal = dbus_message_new_signal(wpa_s->dbus_path,
+					  WPAS_DBUS_IFACE_INTERFACE,
+					  "StateChange");
+	if (_signal == NULL) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_state_change: "
+		           "could not create dbus signal; likely out of "
+		           "memory");
+		return;
+	}
+
+	new_state_str = wpa_supplicant_state_txt(new_state);
+	old_state_str = wpa_supplicant_state_txt(old_state);
+	if (new_state_str == NULL || old_state_str == NULL) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_state_change: "
+		           "Could not convert state strings");
+		goto out;
+	}
+
+	if (!dbus_message_append_args(_signal,
+	                              DBUS_TYPE_STRING, &new_state_str,
+	                              DBUS_TYPE_STRING, &old_state_str,
+	                              DBUS_TYPE_INVALID)) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_state_change: "
+		           "Not enough memory to construct state change "
+		           "signal");
+		goto out;
+	}
+
+	dbus_connection_send(iface->con, _signal, NULL);
+
+out:
+	dbus_message_unref(_signal);
+}
+
+
+/**
+ * wpa_supplicant_dbus_notify_scanning - send scanning status
+ * @wpa_s: %wpa_supplicant network interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners of interface scanning state changes
+ */
+void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+	DBusMessage *_signal;
+	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	_signal = dbus_message_new_signal(wpa_s->dbus_path,
+					  WPAS_DBUS_IFACE_INTERFACE,
+					  "Scanning");
+	if (_signal == NULL) {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
+			   "results signal");
+		return;
+	}
+
+	if (dbus_message_append_args(_signal,
+	                             DBUS_TYPE_BOOLEAN, &scanning,
+	                             DBUS_TYPE_INVALID)) {
+		dbus_connection_send(iface->con, _signal, NULL);
+	} else {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
+			   "signal");
+	}
+	dbus_message_unref(_signal);
+}
+
+
+#ifdef CONFIG_WPS
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+					 const struct wps_credential *cred)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *_signal = NULL;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s->global == NULL)
+		return;
+	iface = wpa_s->global->dbus;
+	if (iface == NULL)
+		return;
+
+	_signal = dbus_message_new_signal(wpa_s->dbus_path,
+					  WPAS_DBUS_IFACE_INTERFACE,
+					  "WpsCred");
+	if (_signal == NULL) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
+		           "Could not create dbus signal; likely out of "
+		           "memory");
+		return;
+	}
+
+	if (!dbus_message_append_args(_signal,
+	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      &cred->cred_attr, cred->cred_attr_len,
+	                              DBUS_TYPE_INVALID)) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
+		           "Not enough memory to construct signal");
+		goto out;
+	}
+
+	dbus_connection_send(iface->con, _signal, NULL);
+
+out:
+	dbus_message_unref(_signal);
+}
+#else /* CONFIG_WPS */
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+					 const struct wps_credential *cred)
+{
+}
+#endif /* CONFIG_WPS */
+
+void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+					      int depth, const char *subject,
+					      const char *cert_hash,
+					      const struct wpabuf *cert)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *_signal = NULL;
+	const char *hash;
+	const char *cert_hex;
+	int cert_hex_len;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s->global == NULL)
+		return;
+	iface = wpa_s->global->dbus;
+	if (iface == NULL)
+		return;
+
+	_signal = dbus_message_new_signal(wpa_s->dbus_path,
+					  WPAS_DBUS_IFACE_INTERFACE,
+					  "Certification");
+	if (_signal == NULL) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_certification: "
+		           "Could not create dbus signal; likely out of "
+		           "memory");
+		return;
+	}
+
+	hash = cert_hash ? cert_hash : "";
+	cert_hex = cert ? wpabuf_head(cert) : "";
+	cert_hex_len = cert ? wpabuf_len(cert) : 0;
+
+	if (!dbus_message_append_args(_signal,
+				      DBUS_TYPE_INT32,&depth,
+				      DBUS_TYPE_STRING, &subject,
+	                              DBUS_TYPE_STRING, &hash,
+	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      &cert_hex, cert_hex_len,
+	                              DBUS_TYPE_INVALID)) {
+		wpa_printf(MSG_ERROR,
+		           "dbus: wpa_supplicant_dbus_notify_certification: "
+		           "Not enough memory to construct signal");
+		goto out;
+	}
+
+	dbus_connection_send(iface->con, _signal, NULL);
+
+out:
+	dbus_message_unref(_signal);
+
+}
+
+
+/**
+ * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initialize the dbus control interface and start receiving commands from
+ * external programs over the bus.
+ */
+int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
+{
+	DBusError error;
+	int ret = -1;
+	DBusObjectPathVTable wpas_vtable = {
+		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
+	};
+
+	/* Register the message handler for the global dbus interface */
+	if (!dbus_connection_register_object_path(iface->con,
+						  WPAS_DBUS_PATH, &wpas_vtable,
+						  iface)) {
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
+			   "handler");
+		return -1;
+	}
+
+	/* Register our service with the message bus */
+	dbus_error_init(&error);
+	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
+				      0, &error)) {
+	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+		ret = 0;
+		break;
+	case DBUS_REQUEST_NAME_REPLY_EXISTS:
+	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
+			   "already registered");
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
+			   "%s %s", error.name, error.message);
+		break;
+	}
+	dbus_error_free(&error);
+
+	if (ret != 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
+		   "'.");
+
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_register_new_iface - Register a new interface with dbus
+ * @wpa_s: %wpa_supplicant interface description structure to register
+ * Returns: 0 on success, -1 on error
+ *
+ * Registers a new interface with dbus and assigns it a dbus object path.
+ */
+int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
+	DBusConnection * con;
+	u32 next;
+	DBusObjectPathVTable vtable = {
+		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
+	};
+
+	/* Do nothing if the control interface is not turned on */
+	if (ctrl_iface == NULL)
+		return 0;
+
+	con = ctrl_iface->con;
+	next = ctrl_iface->next_objid++;
+
+	/* Create and set the interface's object path */
+	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+	if (wpa_s->dbus_path == NULL)
+		return -1;
+	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    WPAS_DBUS_PATH_INTERFACES "/%u",
+		    next);
+
+	/* Register the message handler for the interface functions */
+	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
+					       wpa_s)) {
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
+			   "handler for interface %s", wpa_s->ifname);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_dbus_unregister_iface - Unregister an interface from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters the interface with dbus
+ */
+int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
+{
+	struct wpas_dbus_priv *ctrl_iface;
+	DBusConnection *con;
+
+	/* Do nothing if the control interface is not turned on */
+	if (wpa_s == NULL || wpa_s->global == NULL)
+		return 0;
+	ctrl_iface = wpa_s->global->dbus;
+	if (ctrl_iface == NULL)
+		return 0;
+
+	con = ctrl_iface->con;
+	if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
+		return -1;
+
+	os_free(wpa_s->dbus_path);
+	wpa_s->dbus_path = NULL;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @path: Pointer to a dbus object path representing an interface
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
+	struct wpa_global *global, const char *path)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (strcmp(wpa_s->dbus_path, path) == 0)
+			return wpa_s;
+	}
+	return NULL;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_old.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,131 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_H
-#define CTRL_IFACE_DBUS_H
-
-struct wps_credential;
-
-#ifdef CONFIG_CTRL_IFACE_DBUS
-
-#define WPAS_DBUS_OBJECT_PATH_MAX 150
-
-#define WPAS_DBUS_SERVICE	"fi.epitest.hostap.WPASupplicant"
-#define WPAS_DBUS_PATH		"/fi/epitest/hostap/WPASupplicant"
-#define WPAS_DBUS_INTERFACE	"fi.epitest.hostap.WPASupplicant"
-
-#define WPAS_DBUS_PATH_INTERFACES	WPAS_DBUS_PATH "/Interfaces"
-#define WPAS_DBUS_IFACE_INTERFACE	WPAS_DBUS_INTERFACE ".Interface"
-
-#define WPAS_DBUS_NETWORKS_PART "Networks"
-#define WPAS_DBUS_IFACE_NETWORK	WPAS_DBUS_INTERFACE ".Network"
-
-#define WPAS_DBUS_BSSIDS_PART	"BSSIDs"
-#define WPAS_DBUS_IFACE_BSSID	WPAS_DBUS_INTERFACE ".BSSID"
-
-
-/* Errors */
-#define WPAS_ERROR_INVALID_NETWORK \
-	WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
-#define WPAS_ERROR_INVALID_BSSID \
-	WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
-
-#define WPAS_ERROR_INVALID_OPTS \
-	WPAS_DBUS_INTERFACE ".InvalidOptions"
-#define WPAS_ERROR_INVALID_IFACE \
-	WPAS_DBUS_INTERFACE ".InvalidInterface"
-
-#define WPAS_ERROR_ADD_ERROR \
-	WPAS_DBUS_INTERFACE ".AddError"
-#define WPAS_ERROR_EXISTS_ERROR \
-	WPAS_DBUS_INTERFACE ".ExistsError"
-#define WPAS_ERROR_REMOVE_ERROR \
-	WPAS_DBUS_INTERFACE ".RemoveError"
-
-#define WPAS_ERROR_SCAN_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".ScanError"
-#define WPAS_ERROR_ADD_NETWORK_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
-#define WPAS_ERROR_INTERNAL_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".InternalError"
-#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
-
-#define WPAS_ERROR_WPS_PBC_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError"
-#define WPAS_ERROR_WPS_PIN_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".WpsPinError"
-#define WPAS_ERROR_WPS_REG_ERROR \
-	WPAS_DBUS_IFACE_INTERFACE ".WpsRegError"
-
-#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
-
-struct wpa_global;
-struct wpa_supplicant;
-
-int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface);
-void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
-					     enum wpa_states new_state,
-					     enum wpa_states old_state);
-void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
-					 const struct wps_credential *cred);
-
-char * wpas_dbus_decompose_object_path(const char *path, char **network,
-                                       char **bssid);
-
-int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
-int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
-
-
-/* Methods internal to the dbus control interface */
-struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
-	struct wpa_global *global, const char *path);
-
-#else /* CONFIG_CTRL_IFACE_DBUS */
-
-static inline void
-wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline void
-wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
-{
-}
-
-#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
-
-static inline void
-wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
-				    const struct wps_credential *cred)
-{
-}
-
-static inline int
-wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline int
-wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-
-#endif /* CTRL_IFACE_DBUS_H */

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_old.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,137 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_H
+#define CTRL_IFACE_DBUS_H
+
+struct wps_credential;
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+
+#define WPAS_DBUS_SERVICE	"fi.epitest.hostap.WPASupplicant"
+#define WPAS_DBUS_PATH		"/fi/epitest/hostap/WPASupplicant"
+#define WPAS_DBUS_INTERFACE	"fi.epitest.hostap.WPASupplicant"
+
+#define WPAS_DBUS_PATH_INTERFACES	WPAS_DBUS_PATH "/Interfaces"
+#define WPAS_DBUS_IFACE_INTERFACE	WPAS_DBUS_INTERFACE ".Interface"
+
+#define WPAS_DBUS_NETWORKS_PART "Networks"
+#define WPAS_DBUS_IFACE_NETWORK	WPAS_DBUS_INTERFACE ".Network"
+
+#define WPAS_DBUS_BSSIDS_PART	"BSSIDs"
+#define WPAS_DBUS_IFACE_BSSID	WPAS_DBUS_INTERFACE ".BSSID"
+
+
+/* Errors */
+#define WPAS_ERROR_INVALID_NETWORK \
+	WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
+#define WPAS_ERROR_INVALID_BSSID \
+	WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
+
+#define WPAS_ERROR_INVALID_OPTS \
+	WPAS_DBUS_INTERFACE ".InvalidOptions"
+#define WPAS_ERROR_INVALID_IFACE \
+	WPAS_DBUS_INTERFACE ".InvalidInterface"
+
+#define WPAS_ERROR_ADD_ERROR \
+	WPAS_DBUS_INTERFACE ".AddError"
+#define WPAS_ERROR_EXISTS_ERROR \
+	WPAS_DBUS_INTERFACE ".ExistsError"
+#define WPAS_ERROR_REMOVE_ERROR \
+	WPAS_DBUS_INTERFACE ".RemoveError"
+
+#define WPAS_ERROR_SCAN_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".ScanError"
+#define WPAS_ERROR_ADD_NETWORK_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
+#define WPAS_ERROR_INTERNAL_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".InternalError"
+#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
+
+#define WPAS_ERROR_WPS_PBC_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError"
+#define WPAS_ERROR_WPS_PIN_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsPinError"
+#define WPAS_ERROR_WPS_REG_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsRegError"
+
+#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface);
+void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+					     enum wpa_states new_state,
+					     enum wpa_states old_state);
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+					 const struct wps_credential *cred);
+void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+					      int depth, const char *subject,
+					      const char *cert_hash,
+					      const struct wpabuf *cert);
+
+char * wpas_dbus_decompose_object_path(const char *path, char **network,
+                                       char **bssid);
+
+int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
+int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
+
+
+/* Methods internal to the dbus control interface */
+struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
+	struct wpa_global *global, const char *path);
+
+#else /* CONFIG_CTRL_IFACE_DBUS */
+
+static inline void
+wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+}
+
+#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+
+static inline void
+wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+				    const struct wps_credential *cred)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+					      int depth, const char *subject,
+					      const char *cert_hash,
+					      const struct wpabuf *cert)
+{
+}
+
+static inline int
+wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline int
+wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+#endif /* CTRL_IFACE_DBUS_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1436 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "eap_peer/eap_methods.h"
-#include "common/ieee802_11_defs.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../driver_i.h"
-#include "../notify.h"
-#include "../wpas_glue.h"
-#include "../bss.h"
-#include "../scan.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-#include "dbus_dict_helpers.h"
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-/**
- * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
- * @message: Pointer to incoming dbus message this error refers to
- * Returns: a dbus error message
- *
- * Convenience function to create and return an invalid options error
- */
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
-					       const char *arg)
-{
-	DBusMessage *reply;
-
-	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
-				       "Did not receive correct message "
-				       "arguments.");
-	if (arg != NULL)
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
-					 DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_new_success_reply - Return a new success reply message
- * @message: Pointer to incoming dbus message this reply refers to
- * Returns: a dbus message containing a single UINT32 that indicates
- *          success (ie, a value of 1)
- *
- * Convenience function to create and return a success reply message
- */
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
-{
-	DBusMessage *reply;
-	unsigned int success = 1;
-
-	reply = dbus_message_new_method_return(message);
-	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
-				 DBUS_TYPE_INVALID);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_global_add_interface - Request registration of a network interface
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the new interface object,
- *          or a dbus error message with more information
- *
- * Handler function for "addInterface" method call. Handles requests
- * by dbus clients to register a network interface that wpa_supplicant
- * will manage.
- */
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
-					     struct wpa_global *global)
-{
-	char *ifname = NULL;
-	char *driver = NULL;
-	char *driver_param = NULL;
-	char *confname = NULL;
-	char *bridge_ifname = NULL;
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter;
-
-	dbus_message_iter_init(message, &iter);
-
-	/* First argument: interface name (DBUS_TYPE_STRING)
-	 *    Required; must be non-zero length
-	 */
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		goto error;
-	dbus_message_iter_get_basic(&iter, &ifname);
-	if (!os_strlen(ifname))
-		goto error;
-
-	/* Second argument: dict of options */
-	if (dbus_message_iter_next(&iter)) {
-		DBusMessageIter iter_dict;
-		struct wpa_dbus_dict_entry entry;
-
-		if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
-			goto error;
-		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-				goto error;
-			if (!strcmp(entry.key, "driver") &&
-			    (entry.type == DBUS_TYPE_STRING)) {
-				driver = os_strdup(entry.str_value);
-				wpa_dbus_dict_entry_clear(&entry);
-				if (driver == NULL)
-					goto error;
-			} else if (!strcmp(entry.key, "driver-params") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
-				driver_param = os_strdup(entry.str_value);
-				wpa_dbus_dict_entry_clear(&entry);
-				if (driver_param == NULL)
-					goto error;
-			} else if (!strcmp(entry.key, "config-file") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
-				confname = os_strdup(entry.str_value);
-				wpa_dbus_dict_entry_clear(&entry);
-				if (confname == NULL)
-					goto error;
-			} else if (!strcmp(entry.key, "bridge-ifname") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
-				bridge_ifname = os_strdup(entry.str_value);
-				wpa_dbus_dict_entry_clear(&entry);
-				if (bridge_ifname == NULL)
-					goto error;
-			} else {
-				wpa_dbus_dict_entry_clear(&entry);
-				goto error;
-			}
-		}
-	}
-
-	/*
-	 * Try to get the wpa_supplicant record for this iface, return
-	 * an error if we already control it.
-	 */
-	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_EXISTS_ERROR,
-					       "wpa_supplicant already "
-					       "controls this interface.");
-	} else {
-		struct wpa_supplicant *wpa_s;
-		struct wpa_interface iface;
-		os_memset(&iface, 0, sizeof(iface));
-		iface.ifname = ifname;
-		iface.driver = driver;
-		iface.driver_param = driver_param;
-		iface.confname = confname;
-		iface.bridge_ifname = bridge_ifname;
-		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
-			const char *path = wpa_s->dbus_path;
-			reply = dbus_message_new_method_return(message);
-			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
-		} else {
-			reply = dbus_message_new_error(message,
-						       WPAS_ERROR_ADD_ERROR,
-						       "wpa_supplicant "
-						       "couldn't grab this "
-						       "interface.");
-		}
-	}
-
-out:
-	os_free(driver);
-	os_free(driver_param);
-	os_free(confname);
-	os_free(bridge_ifname);
-	return reply;
-
-error:
-	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-	goto out;
-}
-
-
-/**
- * wpas_dbus_global_remove_interface - Request deregistration of an interface
- * @message: Pointer to incoming dbus message
- * @global: wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- *          failure (0), or returns a dbus error message with more information
- *
- * Handler function for "removeInterface" method call.  Handles requests
- * by dbus clients to deregister a network interface that wpa_supplicant
- * currently manages.
- */
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
-						struct wpa_global *global)
-{
-	struct wpa_supplicant *wpa_s;
-	char *path;
-	DBusMessage *reply = NULL;
-
-	if (!dbus_message_get_args(message, NULL,
-				   DBUS_TYPE_OBJECT_PATH, &path,
-				   DBUS_TYPE_INVALID)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
-	if (wpa_s == NULL) {
-		reply = wpas_dbus_new_invalid_iface_error(message);
-		goto out;
-	}
-
-	if (!wpa_supplicant_remove_iface(global, wpa_s)) {
-		reply = wpas_dbus_new_success_reply(message);
-	} else {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_ERROR,
-					       "wpa_supplicant couldn't "
-					       "remove this interface.");
-	}
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_dbus_global_get_interface - Get the object path for an interface name
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object path of the interface object,
- *          or a dbus error message with more information
- *
- * Handler function for "getInterface" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
-					     struct wpa_global *global)
-{
-	DBusMessage *reply = NULL;
-	const char *ifname;
-	const char *path;
-	struct wpa_supplicant *wpa_s;
-
-	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_STRING, &ifname,
-	                           DBUS_TYPE_INVALID)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	wpa_s = wpa_supplicant_get_iface(global, ifname);
-	if (wpa_s == NULL) {
-		reply = wpas_dbus_new_invalid_iface_error(message);
-		goto out;
-	}
-
-	path = wpa_s->dbus_path;
-	reply = dbus_message_new_method_return(message);
-	dbus_message_append_args(reply,
-	                         DBUS_TYPE_OBJECT_PATH, &path,
-	                         DBUS_TYPE_INVALID);
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_dbus_global_set_debugparams- Set the debug params
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- *          failure (0), or returns a dbus error message with more information
- *
- * Handler function for "setDebugParams" method call. Handles requests
- * by dbus clients for the object path of an specific network interface.
- */
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
-					       struct wpa_global *global)
-{
-	DBusMessage *reply = NULL;
-	int debug_level;
-	dbus_bool_t debug_timestamp;
-	dbus_bool_t debug_show_keys;
-
-	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_INT32, &debug_level,
-	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
-	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
-	                           DBUS_TYPE_INVALID)) {
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-	}
-
-	if (wpa_supplicant_set_debug_params(global, debug_level,
-					    debug_timestamp ? 1 : 0,
-					    debug_show_keys ? 1 : 0)) {
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-	}
-
-	reply = wpas_dbus_new_success_reply(message);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_scan - Request a wireless scan on an interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "scan" method call of a network device. Requests
- * that wpa_supplicant perform a wireless scan as soon as possible
- * on a particular wireless interface.
- */
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
-				   struct wpa_supplicant *wpa_s)
-{
-	wpa_s->scan_req = 2;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-	return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_scan_results - Get the results of a recent scan request
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dbus array of objects paths, or returns
- *          a dbus error message if not scan results could be found
- *
- * Handler function for "scanResults" method call of a network device. Returns
- * a dbus message containing the object paths of wireless networks found.
- */
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter;
-	DBusMessageIter sub_iter;
-	struct wpa_bss *bss;
-
-	/* Create and initialize the return message */
-	reply = dbus_message_new_method_return(message);
-	dbus_message_iter_init_append(reply, &iter);
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
-					 &sub_iter);
-
-	/* Loop through scan results and append each result's object path */
-	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
-		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
-		char *path = path_buf;
-
-		/* Construct the object path for this network.  Note that ':'
-		 * is not a valid character in dbus object paths.
-		 */
-		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
-			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
-			    WPAS_DBUS_BSSID_FORMAT,
-			    wpa_s->dbus_path, MAC2STR(bss->bssid));
-		dbus_message_iter_append_basic(&sub_iter,
-					       DBUS_TYPE_OBJECT_PATH, &path);
-	}
-
-	dbus_message_iter_close_container(&iter, &sub_iter);
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_bssid_properties - Return the properties of a scanned network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @res: wpa_supplicant scan result for which to get properties
- * Returns: a dbus message containing the properties for the requested network
- *
- * Handler function for "properties" method call of a scanned network.
- * Returns a dbus message containing the the properties.
- */
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s,
-					 struct wpa_bss *bss)
-{
-	DBusMessage *reply;
-	DBusMessageIter iter, iter_dict;
-	const u8 *ie;
-
-	/* Dump the properties into a dbus message */
-	reply = dbus_message_new_method_return(message);
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-		goto error;
-
-	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
-					     (const char *) bss->bssid,
-					     ETH_ALEN))
-		goto error;
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
-						     (const char *) (ie + 2),
-						     ie[1]))
-		goto error;
-	}
-
-	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	if (bss->freq) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
-						bss->freq))
-			goto error;
-	}
-	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
-					 bss->caps))
-		goto error;
-	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
-		goto error;
-	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
-		goto error;
-	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
-		goto error;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
-					wpa_bss_get_max_rate(bss) * 500000))
-		goto error;
-
-	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-		goto error;
-
-	return reply;
-
-error:
-	if (reply)
-		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "BSSID properties.");
-}
-
-
-/**
- * wpas_dbus_iface_capabilities - Return interface capabilities
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
- *
- * Handler function for "capabilities" method call of an interface.
- */
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_driver_capa capa;
-	int res;
-	DBusMessageIter iter, iter_dict;
-	char **eap_methods;
-	size_t num_items;
-	dbus_bool_t strict = FALSE;
-	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
-
-	if (!dbus_message_get_args(message, NULL,
-				   DBUS_TYPE_BOOLEAN, &strict,
-				   DBUS_TYPE_INVALID))
-		strict = FALSE;
-
-	reply = dbus_message_new_method_return(message);
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-		goto error;
-
-	/* EAP methods */
-	eap_methods = eap_get_names_as_string_array(&num_items);
-	if (eap_methods) {
-		dbus_bool_t success = FALSE;
-		size_t i = 0;
-
-		success = wpa_dbus_dict_append_string_array(
-			&iter_dict, "eap", (const char **) eap_methods,
-			num_items);
-
-		/* free returned method array */
-		while (eap_methods[i])
-			os_free(eap_methods[i++]);
-		os_free(eap_methods);
-
-		if (!success)
-			goto error;
-	}
-
-	res = wpa_drv_get_capa(wpa_s, &capa);
-
-	/***** pairwise cipher */
-	if (res < 0) {
-		if (!strict) {
-			const char *args[] = {"CCMP", "TKIP", "NONE"};
-			if (!wpa_dbus_dict_append_string_array(
-				    &iter_dict, "pairwise", args,
-				    sizeof(args) / sizeof(char*)))
-				goto error;
-		}
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto error;
-	}
-
-	/***** group cipher */
-	if (res < 0) {
-		if (!strict) {
-			const char *args[] = {
-				"CCMP", "TKIP", "WEP104", "WEP40"
-			};
-			if (!wpa_dbus_dict_append_string_array(
-				    &iter_dict, "group", args,
-				    sizeof(args) / sizeof(char*)))
-				goto error;
-		}
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP104"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP40"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto error;
-	}
-
-	/***** key management */
-	if (res < 0) {
-		if (!strict) {
-			const char *args[] = {
-				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
-				"NONE"
-			};
-			if (!wpa_dbus_dict_append_string_array(
-				    &iter_dict, "key_mgmt", args,
-				    sizeof(args) / sizeof(char*)))
-				goto error;
-		}
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "NONE"))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "IEEE8021X"))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-EAP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-PSK"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto error;
-	}
-
-	/***** WPA protocol */
-	if (res < 0) {
-		if (!strict) {
-			const char *args[] = { "RSN", "WPA" };
-			if (!wpa_dbus_dict_append_string_array(
-				    &iter_dict, "proto", args,
-				    sizeof(args) / sizeof(char*)))
-				goto error;
-		}
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "RSN"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto error;
-	}
-
-	/***** auth alg */
-	if (res < 0) {
-		if (!strict) {
-			const char *args[] = { "OPEN", "SHARED", "LEAP" };
-			if (!wpa_dbus_dict_append_string_array(
-				    &iter_dict, "auth_alg", args,
-				    sizeof(args) / sizeof(char*)))
-				goto error;
-		}
-	} else {
-		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
-						      &iter_dict_entry,
-						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "OPEN"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "SHARED"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "LEAP"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
-						    &iter_dict_entry,
-						    &iter_dict_val,
-						    &iter_array))
-			goto error;
-	}
-
-	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-		goto error;
-
-	return reply;
-
-error:
-	if (reply)
-		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "interface capabilities.");
-}
-
-
-/**
- * wpas_dbus_iface_add_network - Add a new configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing the object path of the new network
- *
- * Handler function for "addNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_ssid *ssid;
-	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
-
-	ssid = wpa_config_add_network(wpa_s->conf);
-	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,
-		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
-		    wpa_s->dbus_path, ssid->id);
-
-	reply = dbus_message_new_method_return(message);
-	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-				 &path, DBUS_TYPE_INVALID);
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_remove_network - Remove a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "removeNetwork" method call of a network interface.
- */
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *op;
-	char *iface = NULL, *net_id = NULL;
-	int id;
-	struct wpa_ssid *ssid;
-
-	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_OBJECT_PATH, &op,
-	                           DBUS_TYPE_INVALID)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	/* Extract the network ID */
-	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
-	if (iface == NULL) {
-		reply = wpas_dbus_new_invalid_network_error(message);
-		goto out;
-	}
-
-	/* Ensure the network is actually a child of this interface */
-	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
-		reply = wpas_dbus_new_invalid_network_error(message);
-		goto out;
-	}
-
-	id = strtoul(net_id, NULL, 10);
-	ssid = wpa_config_get_network(wpa_s->conf, id);
-	if (ssid == NULL) {
-		reply = wpas_dbus_new_invalid_network_error(message);
-		goto out;
-	}
-
-	wpas_notify_network_removed(wpa_s, ssid);
-
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
-					       "error removing the specified "
-					       "on this interface.");
-		goto out;
-	}
-
-	if (ssid == wpa_s->current_ssid)
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-	reply = wpas_dbus_new_success_reply(message);
-
-out:
-	os_free(iface);
-	os_free(net_id);
-	return reply;
-}
-
-
-static const char *dont_quote[] = {
-	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
-	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
-	"bssid", NULL
-};
-
-
-static dbus_bool_t should_quote_opt(const char *key)
-{
-	int i = 0;
-	while (dont_quote[i] != NULL) {
-		if (strcmp(key, dont_quote[i]) == 0)
-			return FALSE;
-		i++;
-	}
-	return TRUE;
-}
-
-
-/**
- * wpas_dbus_iface_set_network - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: a dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "set" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s,
-					  struct wpa_ssid *ssid)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
-	DBusMessageIter	iter, iter_dict;
-
-	dbus_message_iter_init(message, &iter);
-
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		char *value = NULL;
-		size_t size = 50;
-		int ret;
-
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-			reply = wpas_dbus_new_invalid_opts_error(message,
-								 NULL);
-			goto out;
-		}
-
-		/* Type conversions, since wpa_supplicant wants strings */
-		if (entry.type == DBUS_TYPE_ARRAY &&
-		    entry.array_type == DBUS_TYPE_BYTE) {
-			if (entry.array_len <= 0)
-				goto error;
-
-			size = entry.array_len * 2 + 1;
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-			ret = wpa_snprintf_hex(value, size,
-					       (u8 *) entry.bytearray_value,
-					       entry.array_len);
-			if (ret <= 0)
-				goto error;
-		} else if (entry.type == DBUS_TYPE_STRING) {
-			if (should_quote_opt(entry.key)) {
-				size = os_strlen(entry.str_value);
-				/* Zero-length option check */
-				if (size <= 0)
-					goto error;
-				size += 3;  /* For quotes and terminator */
-				value = os_zalloc(size);
-				if (value == NULL)
-					goto error;
-				ret = os_snprintf(value, size, "\"%s\"",
-						  entry.str_value);
-				if (ret < 0 || (size_t) ret != (size - 1))
-					goto error;
-			} else {
-				value = os_strdup(entry.str_value);
-				if (value == NULL)
-					goto error;
-			}
-		} else if (entry.type == DBUS_TYPE_UINT32) {
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-			ret = os_snprintf(value, size, "%u",
-					  entry.uint32_value);
-			if (ret <= 0)
-				goto error;
-		} else if (entry.type == DBUS_TYPE_INT32) {
-			value = os_zalloc(size);
-			if (value == NULL)
-				goto error;
-			ret = os_snprintf(value, size, "%d",
-					  entry.int32_value);
-			if (ret <= 0)
-				goto error;
-		} else
-			goto error;
-
-		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
-			goto error;
-
-		if ((os_strcmp(entry.key, "psk") == 0 &&
-		     value[0] == '"' && ssid->ssid_len) ||
-		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
-			wpa_config_update_psk(ssid);
-		else if (os_strcmp(entry.key, "priority") == 0)
-			wpa_config_update_prio_list(wpa_s->conf);
-
-		os_free(value);
-		wpa_dbus_dict_entry_clear(&entry);
-		continue;
-
-	error:
-		os_free(value);
-		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
-		wpa_dbus_dict_entry_clear(&entry);
-		break;
-	}
-
-	if (!reply)
-		reply = wpas_dbus_new_success_reply(message);
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_enable_network - Mark a configured network as enabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "enable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s,
-					     struct wpa_ssid *ssid)
-{
-	wpa_supplicant_enable_network(wpa_s, ssid);
-	return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_disable_network - Mark a configured network as disabled
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "disable" method call of a configured network.
- */
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s,
-					      struct wpa_ssid *ssid)
-{
-	wpa_supplicant_disable_network(wpa_s, ssid);
-	return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_select_network - Attempt association with a configured network
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "selectNetwork" method call of network interface.
- */
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *op;
-	struct wpa_ssid *ssid;
-	char *iface_obj_path = NULL;
-	char *network = NULL;
-
-	if (os_strlen(dbus_message_get_signature(message)) == 0) {
-		/* Any network */
-		ssid = NULL;
-	} else {
-		int nid;
-
-		if (!dbus_message_get_args(message, NULL,
-					   DBUS_TYPE_OBJECT_PATH, &op,
-					   DBUS_TYPE_INVALID)) {
-			reply = wpas_dbus_new_invalid_opts_error(message,
-								 NULL);
-			goto out;
-		}
-
-		/* Extract the network number */
-		iface_obj_path = wpas_dbus_decompose_object_path(op,
-								 &network,
-								 NULL);
-		if (iface_obj_path == NULL) {
-			reply = wpas_dbus_new_invalid_iface_error(message);
-			goto out;
-		}
-		/* Ensure the object path really points to this interface */
-		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
-			reply = wpas_dbus_new_invalid_network_error(message);
-			goto out;
-		}
-
-		nid = strtoul(network, NULL, 10);
-		if (errno == EINVAL) {
-			reply = wpas_dbus_new_invalid_network_error(message);
-			goto out;
-		}
-
-		ssid = wpa_config_get_network(wpa_s->conf, nid);
-		if (ssid == NULL) {
-			reply = wpas_dbus_new_invalid_network_error(message);
-			goto out;
-		}
-	}
-
-	/* Finally, associate with the network */
-	wpa_supplicant_select_network(wpa_s, ssid);
-
-	reply = wpas_dbus_new_success_reply(message);
-
-out:
-	os_free(iface_obj_path);
-	os_free(network);
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_disconnect - Terminate the current connection
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "disconnect" method call of network interface.
- */
-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);
-
-	return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_set_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "setAPScan" method call.
- */
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	dbus_uint32_t ap_scan = 1;
-
-	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
-				   DBUS_TYPE_INVALID)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
-		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
-		goto out;
-	}
-
-	reply = wpas_dbus_new_success_reply(message);
-
-out:
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "setSmartcardModules" method call.
- */
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
-	DBusMessage *message, struct wpa_supplicant *wpa_s)
-{
-	DBusMessageIter iter, iter_dict;
-	char *opensc_engine_path = NULL;
-	char *pkcs11_engine_path = NULL;
-	char *pkcs11_module_path = NULL;
-	struct wpa_dbus_dict_entry entry;
-
-	if (!dbus_message_iter_init(message, &iter))
-		goto error;
-
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
-		goto error;
-
-	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-			goto error;
-		if (!strcmp(entry.key, "opensc_engine_path") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			opensc_engine_path = os_strdup(entry.str_value);
-			if (opensc_engine_path == NULL)
-				goto error;
-		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			pkcs11_engine_path = os_strdup(entry.str_value);
-			if (pkcs11_engine_path == NULL)
-				goto error;
-		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
-				 (entry.type == DBUS_TYPE_STRING)) {
-			pkcs11_module_path = os_strdup(entry.str_value);
-			if (pkcs11_module_path == NULL)
-				goto error;
-		} else {
-			wpa_dbus_dict_entry_clear(&entry);
-			goto error;
-		}
-		wpa_dbus_dict_entry_clear(&entry);
-	}
-
-	os_free(wpa_s->conf->opensc_engine_path);
-	wpa_s->conf->opensc_engine_path = opensc_engine_path;
-	os_free(wpa_s->conf->pkcs11_engine_path);
-	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
-	os_free(wpa_s->conf->pkcs11_module_path);
-	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
-
-	wpa_sm_set_eapol(wpa_s->wpa, NULL);
-	eapol_sm_deinit(wpa_s->eapol);
-	wpa_s->eapol = NULL;
-	wpa_supplicant_init_eapol(wpa_s);
-	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
-
-	return wpas_dbus_new_success_reply(message);
-
-error:
-	os_free(opensc_engine_path);
-	os_free(pkcs11_engine_path);
-	os_free(pkcs11_module_path);
-	return wpas_dbus_new_invalid_opts_error(message, NULL);
-}
-
-
-/**
- * wpas_dbus_iface_get_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- *          interface state
- *
- * Handler function for "state" method call.
- */
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	const char *str_state;
-
-	reply = dbus_message_new_method_return(message);
-	if (reply != NULL) {
-		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
-					 DBUS_TYPE_INVALID);
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
- *
- * Handler function for "scanning" method call.
- */
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-
-	reply = dbus_message_new_method_return(message);
-	if (reply != NULL) {
-		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
-					 DBUS_TYPE_INVALID);
-	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
-			   "scanning state");
-	}
-
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Asks wpa_supplicant to internally store a one or more binary blobs.
- */
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
-	DBusMessageIter	iter, iter_dict;
-
-	dbus_message_iter_init(message, &iter);
-
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-
-	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		struct wpa_config_blob *blob;
-
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-			reply = wpas_dbus_new_invalid_opts_error(message,
-								 NULL);
-			break;
-		}
-
-		if (entry.type != DBUS_TYPE_ARRAY ||
-		    entry.array_type != DBUS_TYPE_BYTE) {
-			reply = wpas_dbus_new_invalid_opts_error(
-				message, "Byte array expected.");
-			break;
-		}
-
-		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
-		    !strlen(entry.key)) {
-			reply = wpas_dbus_new_invalid_opts_error(
-				message, "Invalid array size.");
-			break;
-		}
-
-		blob = os_zalloc(sizeof(*blob));
-		if (blob == NULL) {
-			reply = dbus_message_new_error(
-				message, WPAS_ERROR_ADD_ERROR,
-				"Not enough memory to add blob.");
-			break;
-		}
-		blob->data = os_zalloc(entry.array_len);
-		if (blob->data == NULL) {
-			reply = dbus_message_new_error(
-				message, WPAS_ERROR_ADD_ERROR,
-				"Not enough memory to add blob data.");
-			os_free(blob);
-			break;
-		}
-
-		blob->name = os_strdup(entry.key);
-		blob->len = entry.array_len;
-		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
-				entry.array_len);
-		if (blob->name == NULL || blob->data == NULL) {
-			wpa_config_free_blob(blob);
-			reply = dbus_message_new_error(
-				message, WPAS_ERROR_ADD_ERROR,
-				"Error adding blob.");
-			break;
-		}
-
-		/* Success */
-		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
-			wpas_notify_blob_removed(wpa_s, blob->name);
-		wpa_config_set_blob(wpa_s->conf, blob);
-		wpas_notify_blob_added(wpa_s, blob->name);
-
-		wpa_dbus_dict_entry_clear(&entry);
-	}
-	wpa_dbus_dict_entry_clear(&entry);
-
-	return reply ? reply : wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_remove_blob - Remove named binary blobs
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Asks wpa_supplicant to remove one or more previously stored binary blobs.
- */
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
-{
-	DBusMessageIter iter, array;
-	char *err_msg = NULL;
-
-	dbus_message_iter_init(message, &iter);
-
-	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
-	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-
-	dbus_message_iter_recurse(&iter, &array);
-	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
-		const char *name;
-
-		dbus_message_iter_get_basic(&array, &name);
-		if (!os_strlen(name))
-			err_msg = "Invalid blob name.";
-
-		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
-			err_msg = "Error removing blob.";
-		else
-			wpas_notify_blob_removed(wpa_s, name);
-		dbus_message_iter_next(&array);
-	}
-
-	if (err_msg)
-		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
-					      err_msg);
-
-	return wpas_dbus_new_success_reply(message);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1462 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "eap_peer/eap_methods.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../driver_i.h"
+#include "../notify.h"
+#include "../wpas_glue.h"
+#include "../bss.h"
+#include "../scan.h"
+#include "dbus_old.h"
+#include "dbus_old_handlers.h"
+#include "dbus_dict_helpers.h"
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+/**
+ * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid options error
+ */
+DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
+					       const char *arg)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
+				       "Did not receive correct message "
+				       "arguments.");
+	if (arg != NULL)
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
+					 DBUS_TYPE_INVALID);
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_new_success_reply - Return a new success reply message
+ * @message: Pointer to incoming dbus message this reply refers to
+ * Returns: a dbus message containing a single UINT32 that indicates
+ *          success (ie, a value of 1)
+ *
+ * Convenience function to create and return a success reply message
+ */
+DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
+{
+	DBusMessage *reply;
+	unsigned int success = 1;
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
+				 DBUS_TYPE_INVALID);
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_global_add_interface - Request registration of a network interface
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the new interface object,
+ *          or a dbus error message with more information
+ *
+ * Handler function for "addInterface" method call. Handles requests
+ * by dbus clients to register a network interface that wpa_supplicant
+ * will manage.
+ */
+DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
+					     struct wpa_global *global)
+{
+	char *ifname = NULL;
+	char *driver = NULL;
+	char *driver_param = NULL;
+	char *confname = NULL;
+	char *bridge_ifname = NULL;
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+
+	dbus_message_iter_init(message, &iter);
+
+	/* First argument: interface name (DBUS_TYPE_STRING)
+	 *    Required; must be non-zero length
+	 */
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		goto error;
+	dbus_message_iter_get_basic(&iter, &ifname);
+	if (!os_strlen(ifname))
+		goto error;
+
+	/* Second argument: dict of options */
+	if (dbus_message_iter_next(&iter)) {
+		DBusMessageIter iter_dict;
+		struct wpa_dbus_dict_entry entry;
+
+		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+			goto error;
+		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+				goto error;
+			if (!strcmp(entry.key, "driver") &&
+			    (entry.type == DBUS_TYPE_STRING)) {
+				driver = os_strdup(entry.str_value);
+				wpa_dbus_dict_entry_clear(&entry);
+				if (driver == NULL)
+					goto error;
+			} else if (!strcmp(entry.key, "driver-params") &&
+				   (entry.type == DBUS_TYPE_STRING)) {
+				driver_param = os_strdup(entry.str_value);
+				wpa_dbus_dict_entry_clear(&entry);
+				if (driver_param == NULL)
+					goto error;
+			} else if (!strcmp(entry.key, "config-file") &&
+				   (entry.type == DBUS_TYPE_STRING)) {
+				confname = os_strdup(entry.str_value);
+				wpa_dbus_dict_entry_clear(&entry);
+				if (confname == NULL)
+					goto error;
+			} else if (!strcmp(entry.key, "bridge-ifname") &&
+				   (entry.type == DBUS_TYPE_STRING)) {
+				bridge_ifname = os_strdup(entry.str_value);
+				wpa_dbus_dict_entry_clear(&entry);
+				if (bridge_ifname == NULL)
+					goto error;
+			} else {
+				wpa_dbus_dict_entry_clear(&entry);
+				goto error;
+			}
+		}
+	}
+
+	/*
+	 * Try to get the wpa_supplicant record for this iface, return
+	 * an error if we already control it.
+	 */
+	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
+		reply = dbus_message_new_error(message,
+					       WPAS_ERROR_EXISTS_ERROR,
+					       "wpa_supplicant already "
+					       "controls this interface.");
+	} else {
+		struct wpa_supplicant *wpa_s;
+		struct wpa_interface iface;
+		os_memset(&iface, 0, sizeof(iface));
+		iface.ifname = ifname;
+		iface.driver = driver;
+		iface.driver_param = driver_param;
+		iface.confname = confname;
+		iface.bridge_ifname = bridge_ifname;
+		/* Otherwise, have wpa_supplicant attach to it. */
+		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+			const char *path = wpa_s->dbus_path;
+			reply = dbus_message_new_method_return(message);
+			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+			                         &path, DBUS_TYPE_INVALID);
+		} else {
+			reply = dbus_message_new_error(message,
+						       WPAS_ERROR_ADD_ERROR,
+						       "wpa_supplicant "
+						       "couldn't grab this "
+						       "interface.");
+		}
+	}
+
+out:
+	os_free(driver);
+	os_free(driver_param);
+	os_free(confname);
+	os_free(bridge_ifname);
+	return reply;
+
+error:
+	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+	goto out;
+}
+
+
+/**
+ * wpas_dbus_global_remove_interface - Request deregistration of an interface
+ * @message: Pointer to incoming dbus message
+ * @global: wpa_supplicant global data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "removeInterface" method call.  Handles requests
+ * by dbus clients to deregister a network interface that wpa_supplicant
+ * currently manages.
+ */
+DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
+						struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+	char *path;
+	DBusMessage *reply = NULL;
+
+	if (!dbus_message_get_args(message, NULL,
+				   DBUS_TYPE_OBJECT_PATH, &path,
+				   DBUS_TYPE_INVALID)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
+	if (wpa_s == NULL) {
+		reply = wpas_dbus_new_invalid_iface_error(message);
+		goto out;
+	}
+
+	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
+		reply = wpas_dbus_new_success_reply(message);
+	} else {
+		reply = dbus_message_new_error(message,
+					       WPAS_ERROR_REMOVE_ERROR,
+					       "wpa_supplicant couldn't "
+					       "remove this interface.");
+	}
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_global_get_interface - Get the object path for an interface name
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the interface object,
+ *          or a dbus error message with more information
+ *
+ * Handler function for "getInterface" method call. Handles requests
+ * by dbus clients for the object path of an specific network interface.
+ */
+DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
+					     struct wpa_global *global)
+{
+	DBusMessage *reply = NULL;
+	const char *ifname;
+	const char *path;
+	struct wpa_supplicant *wpa_s;
+
+	if (!dbus_message_get_args(message, NULL,
+	                           DBUS_TYPE_STRING, &ifname,
+	                           DBUS_TYPE_INVALID)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	wpa_s = wpa_supplicant_get_iface(global, ifname);
+	if (wpa_s == NULL) {
+		reply = wpas_dbus_new_invalid_iface_error(message);
+		goto out;
+	}
+
+	path = wpa_s->dbus_path;
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply,
+	                         DBUS_TYPE_OBJECT_PATH, &path,
+	                         DBUS_TYPE_INVALID);
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_global_set_debugparams- Set the debug params
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "setDebugParams" method call. Handles requests
+ * by dbus clients for the object path of an specific network interface.
+ */
+DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
+					       struct wpa_global *global)
+{
+	DBusMessage *reply = NULL;
+	int debug_level;
+	dbus_bool_t debug_timestamp;
+	dbus_bool_t debug_show_keys;
+
+	if (!dbus_message_get_args(message, NULL,
+	                           DBUS_TYPE_INT32, &debug_level,
+	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
+	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
+	                           DBUS_TYPE_INVALID)) {
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+	}
+
+	if (wpa_supplicant_set_debug_params(global, debug_level,
+					    debug_timestamp ? 1 : 0,
+					    debug_show_keys ? 1 : 0)) {
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+	}
+
+	reply = wpas_dbus_new_success_reply(message);
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_scan - Request a wireless scan on an interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "scan" method call of a network device. Requests
+ * that wpa_supplicant perform a wireless scan as soon as possible
+ * on a particular wireless interface.
+ */
+DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
+				   struct wpa_supplicant *wpa_s)
+{
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_scan_results - Get the results of a recent scan request
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing a dbus array of objects paths, or returns
+ *          a dbus error message if not scan results could be found
+ *
+ * Handler function for "scanResults" method call of a network device. Returns
+ * a dbus message containing the object paths of wireless networks found.
+ */
+DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	DBusMessageIter iter;
+	DBusMessageIter sub_iter;
+	struct wpa_bss *bss;
+
+	/* Create and initialize the return message */
+	reply = dbus_message_new_method_return(message);
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+					 DBUS_TYPE_OBJECT_PATH_AS_STRING,
+					 &sub_iter);
+
+	/* Loop through scan results and append each result's object path */
+	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
+		char *path = path_buf;
+
+		/* Construct the object path for this network.  Note that ':'
+		 * is not a valid character in dbus object paths.
+		 */
+		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
+			    WPAS_DBUS_BSSID_FORMAT,
+			    wpa_s->dbus_path, MAC2STR(bss->bssid));
+		dbus_message_iter_append_basic(&sub_iter,
+					       DBUS_TYPE_OBJECT_PATH, &path);
+	}
+
+	dbus_message_iter_close_container(&iter, &sub_iter);
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_bssid_properties - Return the properties of a scanned network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @res: wpa_supplicant scan result for which to get properties
+ * Returns: a dbus message containing the properties for the requested network
+ *
+ * Handler function for "properties" method call of a scanned network.
+ * Returns a dbus message containing the the properties.
+ */
+DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s,
+					 struct wpa_bss *bss)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter, iter_dict;
+	const u8 *ie;
+
+	/* Dump the properties into a dbus message */
+	reply = dbus_message_new_method_return(message);
+
+	dbus_message_iter_init_append(reply, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+		goto error;
+
+	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+					     (const char *) bss->bssid,
+					     ETH_ALEN))
+		goto error;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ie) {
+		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
+						     (const char *) (ie + 2),
+						     ie[1]))
+		goto error;
+	}
+
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	if (ie) {
+		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
+						     (const char *) ie,
+						     ie[1] + 2))
+			goto error;
+	}
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	if (ie) {
+		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+						     (const char *) ie,
+						     ie[1] + 2))
+			goto error;
+	}
+
+	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+	if (ie) {
+		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
+						     (const char *) ie,
+						     ie[1] + 2))
+			goto error;
+	}
+
+	if (bss->freq) {
+		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
+						bss->freq))
+			goto error;
+	}
+	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
+					 bss->caps))
+		goto error;
+	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
+	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
+		goto error;
+	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
+	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
+		goto error;
+	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
+	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
+		goto error;
+	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
+					wpa_bss_get_max_rate(bss) * 500000))
+		goto error;
+
+	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		goto error;
+
+	return reply;
+
+error:
+	if (reply)
+		dbus_message_unref(reply);
+	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
+				      "an internal error occurred returning "
+				      "BSSID properties.");
+}
+
+
+/**
+ * wpas_dbus_iface_capabilities - Return interface capabilities
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a dict of strings
+ *
+ * Handler function for "capabilities" method call of an interface.
+ */
+DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_driver_capa capa;
+	int res;
+	DBusMessageIter iter, iter_dict;
+	char **eap_methods;
+	size_t num_items;
+	dbus_bool_t strict = FALSE;
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+
+	if (!dbus_message_get_args(message, NULL,
+				   DBUS_TYPE_BOOLEAN, &strict,
+				   DBUS_TYPE_INVALID))
+		strict = FALSE;
+
+	reply = dbus_message_new_method_return(message);
+
+	dbus_message_iter_init_append(reply, &iter);
+	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+		goto error;
+
+	/* EAP methods */
+	eap_methods = eap_get_names_as_string_array(&num_items);
+	if (eap_methods) {
+		dbus_bool_t success = FALSE;
+		size_t i = 0;
+
+		success = wpa_dbus_dict_append_string_array(
+			&iter_dict, "eap", (const char **) eap_methods,
+			num_items);
+
+		/* free returned method array */
+		while (eap_methods[i])
+			os_free(eap_methods[i++]);
+		os_free(eap_methods);
+
+		if (!success)
+			goto error;
+	}
+
+	res = wpa_drv_get_capa(wpa_s, &capa);
+
+	/***** pairwise cipher */
+	if (res < 0) {
+		if (!strict) {
+			const char *args[] = {"CCMP", "TKIP", "NONE"};
+			if (!wpa_dbus_dict_append_string_array(
+				    &iter_dict, "pairwise", args,
+				    sizeof(args) / sizeof(char*)))
+				goto error;
+		}
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto error;
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "CCMP"))
+				goto error;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "TKIP"))
+				goto error;
+		}
+
+		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "NONE"))
+				goto error;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto error;
+	}
+
+	/***** group cipher */
+	if (res < 0) {
+		if (!strict) {
+			const char *args[] = {
+				"CCMP", "TKIP", "WEP104", "WEP40"
+			};
+			if (!wpa_dbus_dict_append_string_array(
+				    &iter_dict, "group", args,
+				    sizeof(args) / sizeof(char*)))
+				goto error;
+		}
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto error;
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "CCMP"))
+				goto error;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "TKIP"))
+				goto error;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WEP104"))
+				goto error;
+		}
+
+		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WEP40"))
+				goto error;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto error;
+	}
+
+	/***** key management */
+	if (res < 0) {
+		if (!strict) {
+			const char *args[] = {
+				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
+				"NONE"
+			};
+			if (!wpa_dbus_dict_append_string_array(
+				    &iter_dict, "key_mgmt", args,
+				    sizeof(args) / sizeof(char*)))
+				goto error;
+		}
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto error;
+
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "NONE"))
+			goto error;
+
+		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "IEEE8021X"))
+			goto error;
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WPA-EAP"))
+				goto error;
+		}
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WPA-PSK"))
+				goto error;
+		}
+
+		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WPA-NONE"))
+				goto error;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto error;
+	}
+
+	/***** WPA protocol */
+	if (res < 0) {
+		if (!strict) {
+			const char *args[] = { "RSN", "WPA" };
+			if (!wpa_dbus_dict_append_string_array(
+				    &iter_dict, "proto", args,
+				    sizeof(args) / sizeof(char*)))
+				goto error;
+		}
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto error;
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "RSN"))
+				goto error;
+		}
+
+		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "WPA"))
+				goto error;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto error;
+	}
+
+	/***** auth alg */
+	if (res < 0) {
+		if (!strict) {
+			const char *args[] = { "OPEN", "SHARED", "LEAP" };
+			if (!wpa_dbus_dict_append_string_array(
+				    &iter_dict, "auth_alg", args,
+				    sizeof(args) / sizeof(char*)))
+				goto error;
+		}
+	} else {
+		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
+						      &iter_dict_entry,
+						      &iter_dict_val,
+						      &iter_array))
+			goto error;
+
+		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "OPEN"))
+				goto error;
+		}
+
+		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "SHARED"))
+				goto error;
+		}
+
+		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
+			if (!wpa_dbus_dict_string_array_add_element(
+				    &iter_array, "LEAP"))
+				goto error;
+		}
+
+		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						    &iter_dict_entry,
+						    &iter_dict_val,
+						    &iter_array))
+			goto error;
+	}
+
+	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		goto error;
+
+	return reply;
+
+error:
+	if (reply)
+		dbus_message_unref(reply);
+	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
+				      "an internal error occurred returning "
+				      "interface capabilities.");
+}
+
+
+/**
+ * wpas_dbus_iface_add_network - Add a new configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new network
+ *
+ * Handler function for "addNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_ssid *ssid;
+	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	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,
+		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
+		    wpa_s->dbus_path, ssid->id);
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+				 &path, DBUS_TYPE_INVALID);
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_remove_network - Remove a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "removeNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
+					     struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	char *iface = NULL, *net_id = NULL;
+	int id;
+	struct wpa_ssid *ssid;
+
+	if (!dbus_message_get_args(message, NULL,
+	                           DBUS_TYPE_OBJECT_PATH, &op,
+	                           DBUS_TYPE_INVALID)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	/* Extract the network ID */
+	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
+	if (iface == NULL) {
+		reply = wpas_dbus_new_invalid_network_error(message);
+		goto out;
+	}
+
+	/* Ensure the network is actually a child of this interface */
+	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
+		reply = wpas_dbus_new_invalid_network_error(message);
+		goto out;
+	}
+
+	id = strtoul(net_id, NULL, 10);
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_new_invalid_network_error(message);
+		goto out;
+	}
+
+	wpas_notify_network_removed(wpa_s, ssid);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		reply = dbus_message_new_error(message,
+					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
+					       "error removing the specified "
+					       "on this interface.");
+		goto out;
+	}
+
+	if (ssid == wpa_s->current_ssid)
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	reply = wpas_dbus_new_success_reply(message);
+
+out:
+	os_free(iface);
+	os_free(net_id);
+	return reply;
+}
+
+
+static const char *dont_quote[] = {
+	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
+	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
+	"bssid", NULL
+};
+
+
+static dbus_bool_t should_quote_opt(const char *key)
+{
+	int i = 0;
+	while (dont_quote[i] != NULL) {
+		if (strcmp(key, dont_quote[i]) == 0)
+			return FALSE;
+		i++;
+	}
+	return TRUE;
+}
+
+
+/**
+ * wpas_dbus_iface_set_network - Set options for a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "set" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	DBusMessageIter	iter, iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		char *value = NULL;
+		size_t size = 50;
+		int ret;
+
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			reply = wpas_dbus_new_invalid_opts_error(message,
+								 NULL);
+			goto out;
+		}
+
+		/* Type conversions, since wpa_supplicant wants strings */
+		if (entry.type == DBUS_TYPE_ARRAY &&
+		    entry.array_type == DBUS_TYPE_BYTE) {
+			if (entry.array_len <= 0)
+				goto error;
+
+			size = entry.array_len * 2 + 1;
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+			ret = wpa_snprintf_hex(value, size,
+					       (u8 *) entry.bytearray_value,
+					       entry.array_len);
+			if (ret <= 0)
+				goto error;
+		} else if (entry.type == DBUS_TYPE_STRING) {
+			if (should_quote_opt(entry.key)) {
+				size = os_strlen(entry.str_value);
+				/* Zero-length option check */
+				if (size <= 0)
+					goto error;
+				size += 3;  /* For quotes and terminator */
+				value = os_zalloc(size);
+				if (value == NULL)
+					goto error;
+				ret = os_snprintf(value, size, "\"%s\"",
+						  entry.str_value);
+				if (ret < 0 || (size_t) ret != (size - 1))
+					goto error;
+			} else {
+				value = os_strdup(entry.str_value);
+				if (value == NULL)
+					goto error;
+			}
+		} else if (entry.type == DBUS_TYPE_UINT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+			ret = os_snprintf(value, size, "%u",
+					  entry.uint32_value);
+			if (ret <= 0)
+				goto error;
+		} else if (entry.type == DBUS_TYPE_INT32) {
+			value = os_zalloc(size);
+			if (value == NULL)
+				goto error;
+			ret = os_snprintf(value, size, "%d",
+					  entry.int32_value);
+			if (ret <= 0)
+				goto error;
+		} else
+			goto error;
+
+		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+			goto error;
+
+		if ((os_strcmp(entry.key, "psk") == 0 &&
+		     value[0] == '"' && ssid->ssid_len) ||
+		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+			wpa_config_update_psk(ssid);
+		else if (os_strcmp(entry.key, "priority") == 0)
+			wpa_config_update_prio_list(wpa_s->conf);
+
+		os_free(value);
+		wpa_dbus_dict_entry_clear(&entry);
+		continue;
+
+	error:
+		os_free(value);
+		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
+		wpa_dbus_dict_entry_clear(&entry);
+		break;
+	}
+
+	if (!reply)
+		reply = wpas_dbus_new_success_reply(message);
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_enable_network - Mark a configured network as enabled
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "enable" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
+					     struct wpa_supplicant *wpa_s,
+					     struct wpa_ssid *ssid)
+{
+	wpa_supplicant_enable_network(wpa_s, ssid);
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_disable_network - Mark a configured network as disabled
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "disable" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid)
+{
+	wpa_supplicant_disable_network(wpa_s, ssid);
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_select_network - Attempt association with a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "selectNetwork" method call of network interface.
+ */
+DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
+					     struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *op;
+	struct wpa_ssid *ssid;
+	char *iface_obj_path = NULL;
+	char *network = NULL;
+
+	if (os_strlen(dbus_message_get_signature(message)) == 0) {
+		/* Any network */
+		ssid = NULL;
+	} else {
+		int nid;
+
+		if (!dbus_message_get_args(message, NULL,
+					   DBUS_TYPE_OBJECT_PATH, &op,
+					   DBUS_TYPE_INVALID)) {
+			reply = wpas_dbus_new_invalid_opts_error(message,
+								 NULL);
+			goto out;
+		}
+
+		/* Extract the network number */
+		iface_obj_path = wpas_dbus_decompose_object_path(op,
+								 &network,
+								 NULL);
+		if (iface_obj_path == NULL) {
+			reply = wpas_dbus_new_invalid_iface_error(message);
+			goto out;
+		}
+		/* Ensure the object path really points to this interface */
+		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
+			reply = wpas_dbus_new_invalid_network_error(message);
+			goto out;
+		}
+
+		nid = strtoul(network, NULL, 10);
+		if (errno == EINVAL) {
+			reply = wpas_dbus_new_invalid_network_error(message);
+			goto out;
+		}
+
+		ssid = wpa_config_get_network(wpa_s->conf, nid);
+		if (ssid == NULL) {
+			reply = wpas_dbus_new_invalid_network_error(message);
+			goto out;
+		}
+	}
+
+	/* Finally, associate with the network */
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	reply = wpas_dbus_new_success_reply(message);
+
+out:
+	os_free(iface_obj_path);
+	os_free(network);
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_disconnect - Terminate the current connection
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "disconnect" method call of network interface.
+ */
+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);
+
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_set_ap_scan - Control roaming mode
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "setAPScan" method call.
+ */
+DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	dbus_uint32_t ap_scan = 1;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
+				   DBUS_TYPE_INVALID)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
+		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+		goto out;
+	}
+
+	reply = wpas_dbus_new_success_reply(message);
+
+out:
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "setSmartcardModules" method call.
+ */
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter, iter_dict;
+	char *opensc_engine_path = NULL;
+	char *pkcs11_engine_path = NULL;
+	char *pkcs11_module_path = NULL;
+	struct wpa_dbus_dict_entry entry;
+
+	if (!dbus_message_iter_init(message, &iter))
+		goto error;
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+		if (!strcmp(entry.key, "opensc_engine_path") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			opensc_engine_path = os_strdup(entry.str_value);
+			if (opensc_engine_path == NULL)
+				goto error;
+		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			pkcs11_engine_path = os_strdup(entry.str_value);
+			if (pkcs11_engine_path == NULL)
+				goto error;
+		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
+				 (entry.type == DBUS_TYPE_STRING)) {
+			pkcs11_module_path = os_strdup(entry.str_value);
+			if (pkcs11_module_path == NULL)
+				goto error;
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto error;
+		}
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+	os_free(wpa_s->conf->opensc_engine_path);
+	wpa_s->conf->opensc_engine_path = opensc_engine_path;
+	os_free(wpa_s->conf->pkcs11_engine_path);
+	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
+	os_free(wpa_s->conf->pkcs11_module_path);
+	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
+
+	wpa_sm_set_eapol(wpa_s->wpa, NULL);
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_s->eapol = NULL;
+	wpa_supplicant_init_eapol(wpa_s);
+	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+	return wpas_dbus_new_success_reply(message);
+
+error:
+	os_free(opensc_engine_path);
+	os_free(pkcs11_engine_path);
+	os_free(pkcs11_module_path);
+	return wpas_dbus_new_invalid_opts_error(message, NULL);
+}
+
+
+/**
+ * wpas_dbus_iface_get_state - Get interface state
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a STRING representing the current
+ *          interface state
+ *
+ * Handler function for "state" method call.
+ */
+DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
+					struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	const char *str_state;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply != NULL) {
+		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
+					 DBUS_TYPE_INVALID);
+	}
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_get_scanning - Get interface scanning state
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing whether the interface is scanning
+ *
+ * Handler function for "scanning" method call.
+ */
+DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply != NULL) {
+		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
+					 DBUS_TYPE_INVALID);
+	} else {
+		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
+			   "scanning state");
+	}
+
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Asks wpa_supplicant to internally store a one or more binary blobs.
+ */
+DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
+					struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	DBusMessageIter	iter, iter_dict;
+
+	dbus_message_iter_init(message, &iter);
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		struct wpa_config_blob *blob;
+
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			reply = wpas_dbus_new_invalid_opts_error(message,
+								 NULL);
+			break;
+		}
+
+		if (entry.type != DBUS_TYPE_ARRAY ||
+		    entry.array_type != DBUS_TYPE_BYTE) {
+			reply = wpas_dbus_new_invalid_opts_error(
+				message, "Byte array expected.");
+			break;
+		}
+
+		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
+		    !strlen(entry.key)) {
+			reply = wpas_dbus_new_invalid_opts_error(
+				message, "Invalid array size.");
+			break;
+		}
+
+		blob = os_zalloc(sizeof(*blob));
+		if (blob == NULL) {
+			reply = dbus_message_new_error(
+				message, WPAS_ERROR_ADD_ERROR,
+				"Not enough memory to add blob.");
+			break;
+		}
+		blob->data = os_zalloc(entry.array_len);
+		if (blob->data == NULL) {
+			reply = dbus_message_new_error(
+				message, WPAS_ERROR_ADD_ERROR,
+				"Not enough memory to add blob data.");
+			os_free(blob);
+			break;
+		}
+
+		blob->name = os_strdup(entry.key);
+		blob->len = entry.array_len;
+		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
+				entry.array_len);
+		if (blob->name == NULL || blob->data == NULL) {
+			wpa_config_free_blob(blob);
+			reply = dbus_message_new_error(
+				message, WPAS_ERROR_ADD_ERROR,
+				"Error adding blob.");
+			break;
+		}
+
+		/* Success */
+		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
+			wpas_notify_blob_removed(wpa_s, blob->name);
+		wpa_config_set_blob(wpa_s->conf, blob);
+		wpas_notify_blob_added(wpa_s, blob->name);
+
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+	wpa_dbus_dict_entry_clear(&entry);
+
+	return reply ? reply : wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_remove_blob - Remove named binary blobs
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Asks wpa_supplicant to remove one or more previously stored binary blobs.
+ */
+DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter, array;
+	char *err_msg = NULL;
+
+	dbus_message_iter_init(message, &iter);
+
+	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
+	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+
+	dbus_message_iter_recurse(&iter, &array);
+	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+		const char *name;
+
+		dbus_message_iter_get_basic(&array, &name);
+		if (!os_strlen(name))
+			err_msg = "Invalid blob name.";
+
+		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
+			err_msg = "Error removing blob.";
+		else
+			wpas_notify_blob_removed(wpa_s, name);
+		dbus_message_iter_next(&array);
+	}
+
+	if (err_msg)
+		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
+					      err_msg);
+
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ *          failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "flush" method call. Handles requests for an
+ * interface with an optional "age" parameter that specifies the minimum
+ * age of a BSS to be flushed.
+ */
+DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
+				    struct wpa_supplicant *wpa_s)
+{
+	int flush_age = 0;
+
+	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
+	    !dbus_message_get_args(message, NULL,
+				   DBUS_TYPE_INT32, &flush_age,
+				   DBUS_TYPE_INVALID)) {
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+	}
+
+	if (flush_age == 0)
+		wpa_bss_flush(wpa_s);
+	else
+		wpa_bss_flush_by_age(wpa_s, flush_age);
+
+	return wpas_dbus_new_success_reply(message);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,104 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef CTRL_IFACE_DBUS_HANDLERS_H
-#define CTRL_IFACE_DBUS_HANDLERS_H
-
-struct wpa_bss;
-
-DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message);
-
-DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
-					     struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
-						struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
-					     struct wpa_global *global);
-
-DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
-					       struct wpa_global *global);
-
-DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
-				   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s,
-					 struct wpa_bss *bss);
-
-DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s,
-					  struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s,
-					     struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s,
-					      struct wpa_ssid *ssid);
-
-DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
-                                             struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
-					 struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_smartcard_modules(
-	DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
-					struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
-				        struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message);
-DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
-					       const char *arg);
-
-#endif /* CTRL_IFACE_DBUS_HANDLERS_H */
-

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,101 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_HANDLERS_H
+#define CTRL_IFACE_DBUS_HANDLERS_H
+
+struct wpa_bss;
+
+DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
+DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message);
+
+DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
+					     struct wpa_global *global);
+
+DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
+						struct wpa_global *global);
+
+DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
+					     struct wpa_global *global);
+
+DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
+					       struct wpa_global *global);
+
+DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
+				   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s,
+					 struct wpa_bss *bss);
+
+DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
+					     struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
+					     struct wpa_supplicant *wpa_s,
+					     struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
+                                             struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
+                                          struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
+					struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
+				        struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
+				    struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message);
+DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
+					       const char *arg);
+
+#endif /* CTRL_IFACE_DBUS_HANDLERS_H */
+

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers_wps.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,161 +0,0 @@
-/*
- * WPA Supplicant / dbus-based control interface (WPS)
- * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#include <dbus/dbus.h>
-
-#include "common.h"
-#include "../config.h"
-#include "../wpa_supplicant_i.h"
-#include "../wps_supplicant.h"
-#include "dbus_old.h"
-#include "dbus_old_handlers.h"
-
-/**
- * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "wpsPbc" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
-{
-	char *arg_bssid = NULL;
-	u8 bssid[ETH_ALEN];
-	int ret = 0;
-
-	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
-				   DBUS_TYPE_INVALID))
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-
-	if (!os_strcmp(arg_bssid, "any"))
-		ret = wpas_wps_start_pbc(wpa_s, NULL);
-	else if (!hwaddr_aton(arg_bssid, bssid))
-		ret = wpas_wps_start_pbc(wpa_s, bssid);
-	else {
-		return wpas_dbus_new_invalid_opts_error(message,
-							"Invalid BSSID");
-	}
-
-	if (ret < 0) {
-		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PBC_ERROR,
-					      "Could not start PBC "
-					      "negotiation");
-	}
-
-	return wpas_dbus_new_success_reply(message);
-}
-
-
-/**
- * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "wpsPin" method call
- */
-DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	char *arg_bssid;
-	char *pin = NULL;
-	u8 bssid[ETH_ALEN], *_bssid = NULL;
-	int ret = 0;
-
-	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
-				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-
-	if (!os_strcmp(arg_bssid, "any"))
-		_bssid = NULL;
-	else if (!hwaddr_aton(arg_bssid, bssid))
-		_bssid = bssid;
-	else {
-		return wpas_dbus_new_invalid_opts_error(message,
-							"Invalid BSSID");
-	}
-
-	if (os_strlen(pin) > 0)
-		ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
-	else
-		ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
-
-	if (ret < 0) {
-		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PIN_ERROR,
-					      "Could not init PIN");
-	}
-
-	reply = dbus_message_new_method_return(message);
-	if (reply == NULL)
-		return NULL;
-
-	if (ret == 0) {
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
-					 DBUS_TYPE_INVALID);
-	} else {
-		char npin[9];
-		os_snprintf(npin, sizeof(npin), "%08d", ret);
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin,
-					 DBUS_TYPE_INVALID);
-	}
-	return reply;
-}
-
-
-/**
- * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: A dbus message containing a UINT32 indicating success (1) or
- *          failure (0)
- *
- * Handler function for "wpsReg" method call
- */
-DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
-{
-	char *arg_bssid;
-	char *pin = NULL;
-	u8 bssid[ETH_ALEN];
-	int ret = 0;
-
-	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
-				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
-		return wpas_dbus_new_invalid_opts_error(message, NULL);
-
-	if (!os_strcmp(arg_bssid, "any"))
-		ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
-	else if (!hwaddr_aton(arg_bssid, bssid))
-		ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
-	else {
-		return wpas_dbus_new_invalid_opts_error(message,
-							"Invalid BSSID");
-	}
-
-	if (ret < 0) {
-		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PBC_ERROR,
-					      "Could not request credentials");
-	}
-
-	return wpas_dbus_new_success_reply(message);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/dbus_old_handlers_wps.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/dbus_old_handlers_wps.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,157 @@
+/*
+ * WPA Supplicant / dbus-based control interface (WPS)
+ * Copyright (c) 2006, Dan Williams <dcbw at redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "dbus_old.h"
+#include "dbus_old_handlers.h"
+
+/**
+ * wpas_dbus_iface_wps_pbc - Request credentials using WPS PBC method
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "wpsPbc" method call
+ */
+DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s)
+{
+	char *arg_bssid = NULL;
+	u8 bssid[ETH_ALEN];
+	int ret = 0;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
+				   DBUS_TYPE_INVALID))
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+
+	if (!os_strcmp(arg_bssid, "any"))
+		ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
+	else if (!hwaddr_aton(arg_bssid, bssid))
+		ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
+	else {
+		return wpas_dbus_new_invalid_opts_error(message,
+							"Invalid BSSID");
+	}
+
+	if (ret < 0) {
+		return dbus_message_new_error(message,
+					      WPAS_ERROR_WPS_PBC_ERROR,
+					      "Could not start PBC "
+					      "negotiation");
+	}
+
+	return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_wps_pin - Establish the PIN number of the enrollee
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "wpsPin" method call
+ */
+DBusMessage * wpas_dbus_iface_wps_pin(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+	char *arg_bssid;
+	char *pin = NULL;
+	u8 bssid[ETH_ALEN], *_bssid = NULL;
+	int ret = 0;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
+				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+
+	if (!os_strcmp(arg_bssid, "any"))
+		_bssid = NULL;
+	else if (!hwaddr_aton(arg_bssid, bssid))
+		_bssid = bssid;
+	else {
+		return wpas_dbus_new_invalid_opts_error(message,
+							"Invalid BSSID");
+	}
+
+	if (os_strlen(pin) > 0)
+		ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+					 DEV_PW_DEFAULT);
+	else
+		ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0,
+					 DEV_PW_DEFAULT);
+
+	if (ret < 0) {
+		return dbus_message_new_error(message,
+					      WPAS_ERROR_WPS_PIN_ERROR,
+					      "Could not init PIN");
+	}
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	if (ret == 0) {
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
+					 DBUS_TYPE_INVALID);
+	} else {
+		char npin[9];
+		os_snprintf(npin, sizeof(npin), "%08d", ret);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin,
+					 DBUS_TYPE_INVALID);
+	}
+	return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_wps_reg - Request credentials using the PIN of the AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: %wpa_supplicant data structure
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "wpsReg" method call
+ */
+DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
+				      struct wpa_supplicant *wpa_s)
+{
+	char *arg_bssid;
+	char *pin = NULL;
+	u8 bssid[ETH_ALEN];
+	int ret = 0;
+
+	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
+				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
+		return wpas_dbus_new_invalid_opts_error(message, NULL);
+
+	if (!os_strcmp(arg_bssid, "any"))
+		ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
+	else if (!hwaddr_aton(arg_bssid, bssid))
+		ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
+	else {
+		return wpas_dbus_new_invalid_opts_error(message,
+							"Invalid BSSID");
+	}
+
+	if (ret < 0) {
+		return dbus_message_new_error(message,
+					      WPAS_ERROR_WPS_PBC_ERROR,
+					      "Could not request credentials");
+	}
+
+	return wpas_dbus_new_success_reply(message);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.epitest.hostap.WPASupplicant
-Exec=/sbin/wpa_supplicant -u
-User=root

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=fi.epitest.hostap.WPASupplicant
+Exec=@BINDIR@/wpa_supplicant -u
+User=root
+SystemdService=wpa_supplicant.service

Deleted: vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service
===================================================================
--- vendor/wpa/dist/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.w1.wpa_supplicant1
-Exec=/sbin/wpa_supplicant -u
-User=root

Copied: vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in (from rev 9639, vendor/wpa/dist/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=fi.w1.wpa_supplicant1
+Exec=@BINDIR@/wpa_supplicant -u
+User=root
+SystemdService=wpa_supplicant.service

Deleted: vendor/wpa/2.0/wpa_supplicant/defconfig
===================================================================
--- vendor/wpa/dist/wpa_supplicant/defconfig	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/defconfig	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,404 +0,0 @@
-# Example wpa_supplicant build time configuration
-#
-# This file lists the configuration options that are used when building the
-# hostapd binary. All lines starting with # are ignored. Configuration option
-# lines must be commented out complete, if they are not to be included, i.e.,
-# just setting VARIABLE=n is not disabling that variable.
-#
-# This file is included in Makefile, so variables like CFLAGS and LIBS can also
-# be modified from here. In most cases, these lines should use += in order not
-# to override previous values of the variables.
-
-
-# Uncomment following two lines and fix the paths if you have installed OpenSSL
-# or GnuTLS in non-default location
-#CFLAGS += -I/usr/local/openssl/include
-#LIBS += -L/usr/local/openssl/lib
-
-# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
-# the kerberos files are not in the default include path. Following line can be
-# used to fix build issues on such systems (krb5.h not found).
-#CFLAGS += -I/usr/include/kerberos
-
-# Example configuration for various cross-compilation platforms
-
-#### sveasoft (e.g., for Linksys WRT54G) ######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
-#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
-###############################################################################
-
-#### openwrt (e.g., for Linksys WRT54G) #######################################
-#CC=mipsel-uclibc-gcc
-#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
-#CFLAGS += -Os
-#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
-#	-I../WRT54GS/release/src/include
-#LIBS = -lssl
-###############################################################################
-
-
-# Driver interface for Host AP driver
-CONFIG_DRIVER_HOSTAP=y
-
-# Driver interface for Agere driver
-#CONFIG_DRIVER_HERMES=y
-# Change include directories to match with the local setup
-#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
-#CFLAGS += -I../../include/wireless
-
-# Driver interface for madwifi driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_MADWIFI=y
-# Set include directory to the madwifi source tree
-#CFLAGS += -I../../madwifi
-
-# Driver interface for ndiswrapper
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_NDISWRAPPER=y
-
-# Driver interface for Atmel driver
-CONFIG_DRIVER_ATMEL=y
-
-# Driver interface for old Broadcom driver
-# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
-# Linux wireless extensions and does not need (or even work) with the old
-# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
-#CONFIG_DRIVER_BROADCOM=y
-# Example path for wlioctl.h; change to match your configuration
-#CFLAGS += -I/opt/WRT54GS/release/src/include
-
-# Driver interface for Intel ipw2100/2200 driver
-# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
-#CONFIG_DRIVER_IPW=y
-
-# Driver interface for Ralink driver
-#CONFIG_DRIVER_RALINK=y
-
-# Driver interface for generic Linux wireless extensions
-CONFIG_DRIVER_WEXT=y
-
-# Driver interface for Linux drivers using the nl80211 kernel interface
-#CONFIG_DRIVER_NL80211=y
-
-# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
-#CONFIG_DRIVER_BSD=y
-#CFLAGS += -I/usr/local/include
-#LIBS += -L/usr/local/lib
-#LIBS_p += -L/usr/local/lib
-#LIBS_c += -L/usr/local/lib
-
-# Driver interface for Windows NDIS
-#CONFIG_DRIVER_NDIS=y
-#CFLAGS += -I/usr/include/w32api/ddk
-#LIBS += -L/usr/local/lib
-# For native build using mingw
-#CONFIG_NATIVE_WINDOWS=y
-# Additional directories for cross-compilation on Linux host for mingw target
-#CFLAGS += -I/opt/mingw/mingw32/include/ddk
-#LIBS += -L/opt/mingw/mingw32/lib
-#CC=mingw32-gcc
-# By default, driver_ndis uses WinPcap for low-level operations. This can be
-# replaced with the following option which replaces WinPcap calls with NDISUIO.
-# However, this requires that WZC is disabled (net stop wzcsvc) before starting
-# wpa_supplicant.
-# CONFIG_USE_NDISUIO=y
-
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
-# Include client MLME (management frame processing) for test driver
-# This can be used to test MLME operations in hostapd with the test interface.
-# space.
-#CONFIG_CLIENT_MLME=y
-
-# Driver interface for wired Ethernet drivers
-CONFIG_DRIVER_WIRED=y
-
-# Driver interface for the Broadcom RoboSwitch family
-#CONFIG_DRIVER_ROBOSWITCH=y
-
-# Driver interface for no driver (e.g., WPS ER only)
-#CONFIG_DRIVER_NONE=y
-
-# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
-# included)
-CONFIG_IEEE8021X_EAPOL=y
-
-# EAP-MD5
-CONFIG_EAP_MD5=y
-
-# EAP-MSCHAPv2
-CONFIG_EAP_MSCHAPV2=y
-
-# EAP-TLS
-CONFIG_EAP_TLS=y
-
-# EAL-PEAP
-CONFIG_EAP_PEAP=y
-
-# EAP-TTLS
-CONFIG_EAP_TTLS=y
-
-# EAP-FAST
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
-# to add the needed functions.
-#CONFIG_EAP_FAST=y
-
-# EAP-GTC
-CONFIG_EAP_GTC=y
-
-# EAP-OTP
-CONFIG_EAP_OTP=y
-
-# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
-#CONFIG_EAP_SIM=y
-
-# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
-#CONFIG_EAP_PSK=y
-
-# EAP-PAX
-#CONFIG_EAP_PAX=y
-
-# LEAP
-CONFIG_EAP_LEAP=y
-
-# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
-#CONFIG_EAP_AKA=y
-
-# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
-# This requires CONFIG_EAP_AKA to be enabled, too.
-#CONFIG_EAP_AKA_PRIME=y
-
-# Enable USIM simulator (Milenage) for EAP-AKA
-#CONFIG_USIM_SIMULATOR=y
-
-# EAP-SAKE
-#CONFIG_EAP_SAKE=y
-
-# EAP-GPSK
-#CONFIG_EAP_GPSK=y
-# Include support for optional SHA256 cipher suite in EAP-GPSK
-#CONFIG_EAP_GPSK_SHA256=y
-
-# EAP-TNC and related Trusted Network Connect support (experimental)
-#CONFIG_EAP_TNC=y
-
-# Wi-Fi Protected Setup (WPS)
-#CONFIG_WPS=y
-
-# EAP-IKEv2
-#CONFIG_EAP_IKEV2=y
-
-# PKCS#12 (PFX) support (used to read private key and certificate file from
-# a file that usually has extension .p12 or .pfx)
-CONFIG_PKCS12=y
-
-# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
-# engine.
-CONFIG_SMARTCARD=y
-
-# PC/SC interface for smartcards (USIM, GSM SIM)
-# Enable this if EAP-SIM or EAP-AKA is included
-#CONFIG_PCSC=y
-
-# Development testing
-#CONFIG_EAPOL_TEST=y
-
-# Select control interface backend for external programs, e.g, wpa_cli:
-# unix = UNIX domain sockets (default for Linux/*BSD)
-# udp = UDP sockets using localhost (127.0.0.1)
-# named_pipe = Windows Named Pipe (default for Windows)
-# y = use default (backwards compatibility)
-# If this option is commented out, control interface is not included in the
-# build.
-CONFIG_CTRL_IFACE=y
-
-# Include support for GNU Readline and History Libraries in wpa_cli.
-# When building a wpa_cli binary for distribution, please note that these
-# libraries are licensed under GPL and as such, BSD license may not apply for
-# the resulting binary.
-#CONFIG_READLINE=y
-
-# Remove debugging code that is printing out debug message to stdout.
-# This can be used to reduce the size of the wpa_supplicant considerably
-# if debugging code is not needed. The size reduction can be around 35%
-# (e.g., 90 kB).
-#CONFIG_NO_STDOUT_DEBUG=y
-
-# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
-# 35-50 kB in code size.
-#CONFIG_NO_WPA=y
-
-# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
-# save about 1 kB in code size when building only WPA-Personal (no EAP support)
-# or 6 kB if building for WPA-Enterprise.
-#CONFIG_NO_WPA2=y
-
-# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
-# This option can be used to reduce code size by removing support for
-# converting ASCII passphrases into PSK. If this functionality is removed, the
-# PSK can only be configured as the 64-octet hexstring (e.g., from
-# wpa_passphrase). This saves about 0.5 kB in code size.
-#CONFIG_NO_WPA_PASSPHRASE=y
-
-# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
-# This can be used if ap_scan=1 mode is never enabled.
-#CONFIG_NO_SCAN_PROCESSING=y
-
-# Select configuration backend:
-# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
-#	path is given on command line, not here; this option is just used to
-#	select the backend that allows configuration files to be used)
-# winreg = Windows registry (see win_example.reg for an example)
-CONFIG_BACKEND=file
-
-# Remove configuration write functionality (i.e., to allow the configuration
-# file to be updated based on runtime configuration changes). The runtime
-# configuration can still be changed, the changes are just not going to be
-# persistent over restarts. This option can be used to reduce code size by
-# about 3.5 kB.
-#CONFIG_NO_CONFIG_WRITE=y
-
-# Remove support for configuration blobs to reduce code size by about 1.5 kB.
-#CONFIG_NO_CONFIG_BLOBS=y
-
-# Select program entry point implementation:
-# main = UNIX/POSIX like main() function (default)
-# main_winsvc = Windows service (read parameters from registry)
-# main_none = Very basic example (development use only)
-#CONFIG_MAIN=main
-
-# Select wrapper for operatins system and C library specific functions
-# unix = UNIX/POSIX like systems (default)
-# win32 = Windows systems
-# none = Empty template
-#CONFIG_OS=unix
-
-# Select event loop implementation
-# eloop = select() loop (default)
-# eloop_win = Windows events and WaitForMultipleObject() loop
-# eloop_none = Empty template
-#CONFIG_ELOOP=eloop
-
-# Select layer 2 packet implementation
-# linux = Linux packet socket (default)
-# pcap = libpcap/libdnet/WinPcap
-# freebsd = FreeBSD libpcap
-# winpcap = WinPcap with receive thread
-# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
-# none = Empty template
-#CONFIG_L2_PACKET=linux
-
-# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
-CONFIG_PEERKEY=y
-
-# IEEE 802.11w (management frame protection)
-# This version is an experimental implementation based on IEEE 802.11w/D1.0
-# draft and is subject to change since the standard has not yet been finalized.
-# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
-
-# Select TLS implementation
-# openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
-# internal = Internal TLSv1 implementation (experimental)
-# none = Empty template
-#CONFIG_TLS=openssl
-
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
-
-# If CONFIG_TLS=internal is used, additional library and include paths are
-# needed for LibTomMath. Alternatively, an integrated, minimal version of
-# LibTomMath can be used. See beginning of libtommath.c for details on benefits
-# and drawbacks of this option.
-#CONFIG_INTERNAL_LIBTOMMATH=y
-#ifndef CONFIG_INTERNAL_LIBTOMMATH
-#LTM_PATH=/usr/src/libtommath-0.39
-#CFLAGS += -I$(LTM_PATH)
-#LIBS += -L$(LTM_PATH)
-#LIBS_p += -L$(LTM_PATH)
-#endif
-# At the cost of about 4 kB of additional binary size, the internal LibTomMath
-# can be configured to include faster routines for exptmod, sqr, and div to
-# speed up DH and RSA calculation considerably
-#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
-
-# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
-# This is only for Windows builds and requires WMI-related header files and
-# WbemUuid.Lib from Platform SDK even when building with MinGW.
-#CONFIG_NDIS_EVENTS_INTEGRATED=y
-#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
-
-# Add support for old DBus control interface
-# (fi.epitest.hostap.WPASupplicant)
-#CONFIG_CTRL_IFACE_DBUS=y
-
-# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
-#CONFIG_CTRL_IFACE_DBUS_NEW=y
-
-# Add introspection support for new DBus control interface
-#CONFIG_CTRL_IFACE_DBUS_INTRO=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).
-# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
-# be loaded in the beginning of the wpa_supplicant configuration file
-# (see load_dynamic_eap parameter in the example file) before being used in
-# the network blocks.
-#
-# Note that some shared parts of EAP methods are included in the main program
-# and in order to be able to use dynamic EAP methods using these parts, the
-# main program must have been build with the EAP method enabled (=y or =dyn).
-# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
-# unless at least one of them was included in the main build to force inclusion
-# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
-# in the main build to be able to load these methods dynamically.
-#
-# Please also note that using dynamic libraries will increase the total binary
-# size. Thus, it may not be the best option for targets that have limited
-# amount of memory/flash.
-#CONFIG_DYNAMIC_EAP_METHODS=y
-
-# IEEE Std 802.11r-2008 (Fast BSS Transition)
-#CONFIG_IEEE80211R=y
-
-# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
-#CONFIG_DEBUG_FILE=y
-
-# Enable privilege separation (see README 'Privilege separation' for details)
-#CONFIG_PRIVSEP=y
-
-# Enable mitigation against certain attacks against TKIP by delaying Michael
-# MIC error reports by a random amount of time between 0 and 60 seconds
-#CONFIG_DELAYED_MIC_ERROR_REPORT=y
-
-# Enable tracing code for developer debugging
-# This tracks use of memory allocations and other registrations and reports
-# incorrect use with a backtrace of call (or allocation) location.
-#CONFIG_WPA_TRACE=y
-# For BSD, comment out these.
-#LIBS += -lexecinfo
-#LIBS_p += -lexecinfo
-#LIBS_c += -lexecinfo
-
-# Use libbfd to get more details for developer debugging
-# This enables use of libbfd to get more detailed symbols for the backtraces
-# generated by CONFIG_WPA_TRACE=y.
-#CONFIG_WPA_TRACE_BFD=y
-# For BSD, comment out these.
-#LIBS += -lbfd -liberty -lz
-#LIBS_p += -lbfd -liberty -lz
-#LIBS_c += -lbfd -liberty -lz

Copied: vendor/wpa/2.0/wpa_supplicant/defconfig (from rev 9639, vendor/wpa/dist/wpa_supplicant/defconfig)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/defconfig	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/defconfig	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,523 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+#	-I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+#CONFIG_EAP_PWD=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WSC 2.0 support
+#CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#	path is given on command line, not here; this option is just used to
+#	select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+#CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=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).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+#CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_background.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,84 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_BACKGROUND" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
-.SH "WPA"
-.PP
-The original security mechanism of IEEE 802.11 standard was
-not designed to be strong and has proven to be insufficient for
-most networks that require some kind of security. Task group I
-(Security) of IEEE 802.11 working group
-(http://www.ieee802.org/11/) has worked to address the flaws of
-the base standard and has in practice completed its work in May
-2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
-approved in June 2004 and published in July 2004.
-.PP
-Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
-of the IEEE 802.11i work (draft 3.0) to define a subset of the
-security enhancements that can be implemented with existing wlan
-hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
-has now become a mandatory component of interoperability testing
-and certification done by Wi-Fi Alliance. Wi-Fi provides
-information about WPA at its web site
-(http://www.wi-fi.org/OpenSection/protected_access.asp).
-.PP
-IEEE 802.11 standard defined wired equivalent privacy (WEP)
-algorithm for protecting wireless networks. WEP uses RC4 with
-40-bit keys, 24-bit initialization vector (IV), and CRC32 to
-protect against packet forgery. All these choices have proven to
-be insufficient: key space is too small against current attacks,
-RC4 key scheduling is insufficient (beginning of the pseudorandom
-stream should be skipped), IV space is too small and IV reuse
-makes attacks easier, there is no replay protection, and non-keyed
-authentication does not protect against bit flipping packet
-data.
-.PP
-WPA is an intermediate solution for the security issues. It
-uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
-is a compromise on strong security and possibility to use existing
-hardware. It still uses RC4 for the encryption like WEP, but with
-per-packet RC4 keys. In addition, it implements replay protection,
-keyed packet authentication mechanism (Michael MIC).
-.PP
-Keys can be managed using two different mechanisms. WPA can
-either use an external authentication server (e.g., RADIUS) and
-EAP just like IEEE 802.1X is using or pre-shared keys without need
-for additional servers. Wi-Fi calls these "WPA-Enterprise" and
-"WPA-Personal", respectively. Both mechanisms will generate a
-master session key for the Authenticator (AP) and Supplicant
-(client station).
-.PP
-WPA implements a new key handshake (4-Way Handshake and
-Group Key Handshake) for generating and exchanging data encryption
-keys between the Authenticator and Supplicant. This handshake is
-also used to verify that both Authenticator and Supplicant know
-the master session key. These handshakes are identical regardless
-of the selected key management mechanism (only the method for
-generating master session key changes).
-.SH "IEEE 802.11I / WPA2"
-.PP
-The design for parts of IEEE 802.11i that were not included
-in WPA has finished (May 2004) and this amendment to IEEE 802.11
-was approved in June 2004. Wi-Fi Alliance is using the final IEEE
-802.11i as a new version of WPA called WPA2. This includes, e.g.,
-support for more robust encryption algorithm (CCMP: AES in Counter
-mode with CBC-MAC) to replace TKIP and optimizations for handoff
-(reduced number of messages in initial key handshake,
-pre-authentication, and PMKSA caching).
-.SH "SEE ALSO"
-.PP
-\fBwpa_supplicant\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_background.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,84 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_BACKGROUND" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
+.SH "WPA"
+.PP
+The original security mechanism of IEEE 802.11 standard was
+not designed to be strong and has proven to be insufficient for
+most networks that require some kind of security. Task group I
+(Security) of IEEE 802.11 working group
+(http://www.ieee802.org/11/) has worked to address the flaws of
+the base standard and has in practice completed its work in May
+2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
+approved in June 2004 and published in July 2004.
+.PP
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
+of the IEEE 802.11i work (draft 3.0) to define a subset of the
+security enhancements that can be implemented with existing wlan
+hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
+has now become a mandatory component of interoperability testing
+and certification done by Wi-Fi Alliance. Wi-Fi provides
+information about WPA at its web site
+(http://www.wi-fi.org/OpenSection/protected_access.asp).
+.PP
+IEEE 802.11 standard defined wired equivalent privacy (WEP)
+algorithm for protecting wireless networks. WEP uses RC4 with
+40-bit keys, 24-bit initialization vector (IV), and CRC32 to
+protect against packet forgery. All these choices have proven to
+be insufficient: key space is too small against current attacks,
+RC4 key scheduling is insufficient (beginning of the pseudorandom
+stream should be skipped), IV space is too small and IV reuse
+makes attacks easier, there is no replay protection, and non-keyed
+authentication does not protect against bit flipping packet
+data.
+.PP
+WPA is an intermediate solution for the security issues. It
+uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
+is a compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+.PP
+Keys can be managed using two different mechanisms. WPA can
+either use an external authentication server (e.g., RADIUS) and
+EAP just like IEEE 802.1X is using or pre-shared keys without need
+for additional servers. Wi-Fi calls these "WPA-Enterprise" and
+"WPA-Personal", respectively. Both mechanisms will generate a
+master session key for the Authenticator (AP) and Supplicant
+(client station).
+.PP
+WPA implements a new key handshake (4-Way Handshake and
+Group Key Handshake) for generating and exchanging data encryption
+keys between the Authenticator and Supplicant. This handshake is
+also used to verify that both Authenticator and Supplicant know
+the master session key. These handshakes are identical regardless
+of the selected key management mechanism (only the method for
+generating master session key changes).
+.SH "IEEE 802.11I / WPA2"
+.PP
+The design for parts of IEEE 802.11i that were not included
+in WPA has finished (May 2004) and this amendment to IEEE 802.11
+was approved in June 2004. Wi-Fi Alliance is using the final IEEE
+802.11i as a new version of WPA called WPA2. This includes, e.g.,
+support for more robust encryption algorithm (CCMP: AES in Counter
+mode with CBC-MAC) to replace TKIP and optimizations for handoff
+(reduced number of messages in initial key handshake,
+pre-authentication, and PMKSA caching).
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_background.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,101 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_background</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_background</refname>
-    <refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>WPA</title>
-
-    <para>The original security mechanism of IEEE 802.11 standard was
-    not designed to be strong and has proven to be insufficient for
-    most networks that require some kind of security. Task group I
-    (Security) of IEEE 802.11 working group
-    (http://www.ieee802.org/11/) has worked to address the flaws of
-    the base standard and has in practice completed its work in May
-    2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
-    approved in June 2004 and published in July 2004.</para>
-
-    <para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
-    of the IEEE 802.11i work (draft 3.0) to define a subset of the
-    security enhancements that can be implemented with existing wlan
-    hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
-    has now become a mandatory component of interoperability testing
-    and certification done by Wi-Fi Alliance. Wi-Fi provides
-    information about WPA at its web site
-    (http://www.wi-fi.org/OpenSection/protected_access.asp).</para>
-
-    <para>IEEE 802.11 standard defined wired equivalent privacy (WEP)
-    algorithm for protecting wireless networks. WEP uses RC4 with
-    40-bit keys, 24-bit initialization vector (IV), and CRC32 to
-    protect against packet forgery. All these choices have proven to
-    be insufficient: key space is too small against current attacks,
-    RC4 key scheduling is insufficient (beginning of the pseudorandom
-    stream should be skipped), IV space is too small and IV reuse
-    makes attacks easier, there is no replay protection, and non-keyed
-    authentication does not protect against bit flipping packet
-    data.</para>
-
-    <para>WPA is an intermediate solution for the security issues. It
-    uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
-    is a compromise on strong security and possibility to use existing
-    hardware. It still uses RC4 for the encryption like WEP, but with
-    per-packet RC4 keys. In addition, it implements replay protection,
-    keyed packet authentication mechanism (Michael MIC).</para>
-
-    <para>Keys can be managed using two different mechanisms. WPA can
-    either use an external authentication server (e.g., RADIUS) and
-    EAP just like IEEE 802.1X is using or pre-shared keys without need
-    for additional servers. Wi-Fi calls these "WPA-Enterprise" and
-    "WPA-Personal", respectively. Both mechanisms will generate a
-    master session key for the Authenticator (AP) and Supplicant
-    (client station).</para>
-
-    <para>WPA implements a new key handshake (4-Way Handshake and
-    Group Key Handshake) for generating and exchanging data encryption
-    keys between the Authenticator and Supplicant. This handshake is
-    also used to verify that both Authenticator and Supplicant know
-    the master session key. These handshakes are identical regardless
-    of the selected key management mechanism (only the method for
-    generating master session key changes).</para>
-  </refsect1>
-
-  <refsect1>
-    <title>IEEE 802.11i / WPA2</title>
-
-    <para>The design for parts of IEEE 802.11i that were not included
-    in WPA has finished (May 2004) and this amendment to IEEE 802.11
-    was approved in June 2004. Wi-Fi Alliance is using the final IEEE
-    802.11i as a new version of WPA called WPA2. This includes, e.g.,
-    support for more robust encryption algorithm (CCMP: AES in Counter
-    mode with CBC-MAC) to replace TKIP and optimizations for handoff
-    (reduced number of messages in initial key handshake,
-    pre-authentication, and PMKSA caching).</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-  </refsect1>
-
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_background.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_background.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,101 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_background</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_background</refname>
+    <refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>WPA</title>
+
+    <para>The original security mechanism of IEEE 802.11 standard was
+    not designed to be strong and has proven to be insufficient for
+    most networks that require some kind of security. Task group I
+    (Security) of IEEE 802.11 working group
+    (http://www.ieee802.org/11/) has worked to address the flaws of
+    the base standard and has in practice completed its work in May
+    2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
+    approved in June 2004 and published in July 2004.</para>
+
+    <para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
+    of the IEEE 802.11i work (draft 3.0) to define a subset of the
+    security enhancements that can be implemented with existing wlan
+    hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
+    has now become a mandatory component of interoperability testing
+    and certification done by Wi-Fi Alliance. Wi-Fi provides
+    information about WPA at its web site
+    (http://www.wi-fi.org/OpenSection/protected_access.asp).</para>
+
+    <para>IEEE 802.11 standard defined wired equivalent privacy (WEP)
+    algorithm for protecting wireless networks. WEP uses RC4 with
+    40-bit keys, 24-bit initialization vector (IV), and CRC32 to
+    protect against packet forgery. All these choices have proven to
+    be insufficient: key space is too small against current attacks,
+    RC4 key scheduling is insufficient (beginning of the pseudorandom
+    stream should be skipped), IV space is too small and IV reuse
+    makes attacks easier, there is no replay protection, and non-keyed
+    authentication does not protect against bit flipping packet
+    data.</para>
+
+    <para>WPA is an intermediate solution for the security issues. It
+    uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
+    is a compromise on strong security and possibility to use existing
+    hardware. It still uses RC4 for the encryption like WEP, but with
+    per-packet RC4 keys. In addition, it implements replay protection,
+    keyed packet authentication mechanism (Michael MIC).</para>
+
+    <para>Keys can be managed using two different mechanisms. WPA can
+    either use an external authentication server (e.g., RADIUS) and
+    EAP just like IEEE 802.1X is using or pre-shared keys without need
+    for additional servers. Wi-Fi calls these "WPA-Enterprise" and
+    "WPA-Personal", respectively. Both mechanisms will generate a
+    master session key for the Authenticator (AP) and Supplicant
+    (client station).</para>
+
+    <para>WPA implements a new key handshake (4-Way Handshake and
+    Group Key Handshake) for generating and exchanging data encryption
+    keys between the Authenticator and Supplicant. This handshake is
+    also used to verify that both Authenticator and Supplicant know
+    the master session key. These handshakes are identical regardless
+    of the selected key management mechanism (only the method for
+    generating master session key changes).</para>
+  </refsect1>
+
+  <refsect1>
+    <title>IEEE 802.11i / WPA2</title>
+
+    <para>The design for parts of IEEE 802.11i that were not included
+    in WPA has finished (May 2004) and this amendment to IEEE 802.11
+    was approved in June 2004. Wi-Fi Alliance is using the final IEEE
+    802.11i as a new version of WPA called WPA2. This includes, e.g.,
+    support for more robust encryption algorithm (CCMP: AES in Counter
+    mode with CBC-MAC) to replace TKIP and optimizations for handoff
+    (reduced number of messages in initial key handshake,
+    pre-authentication, and PMKSA caching).</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_cli.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,210 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_CLI" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_cli \- WPA command line client
-.SH SYNOPSIS
-
-\fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB\fIcommand ...\fB\fR ]
-
-.SH "OVERVIEW"
-.PP
-wpa_cli is a text-based frontend program for interacting
-with wpa_supplicant. It is used to query current status, change
-configuration, trigger events, and request interactive user
-input.
-.PP
-wpa_cli can show the current authentication status, selected
-security mode, dot11 and dot1x MIBs, etc. In addition, it can
-configure some variables like EAPOL state machine parameters and
-trigger events like reassociation and IEEE 802.1X
-logoff/logon. wpa_cli provides a user interface to request
-authentication information, like username and password, if these
-are not included in the configuration. This can be used to
-implement, e.g., one-time-passwords or generic token card
-authentication where the authentication is based on a
-challenge-response that uses an external device for generating the
-response.
-.PP
-The control interface of wpa_supplicant can be configured to
-allow non-root user access (ctrl_interface GROUP= parameter in the
-configuration file). This makes it possible to run wpa_cli with a
-normal user account.
-.PP
-wpa_cli supports two modes: interactive and command
-line. Both modes share the same command set and the main
-difference is in interactive mode providing access to unsolicited
-messages (event messages, username/password requests).
-.PP
-Interactive mode is started when wpa_cli is executed without
-including the command as a command line parameter. Commands are
-then entered on the wpa_cli prompt. In command line mode, the same
-commands are entered as command line arguments for wpa_cli.
-.SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST"
-.PP
-When wpa_supplicant need authentication parameters, like
-username and password, which are not present in the configuration
-file, it sends a request message to all attached frontend programs,
-e.g., wpa_cli in interactive mode. wpa_cli shows these requests
-with "CTRL-REQ-<type>-<id>:<text>"
-prefix. <type> is IDENTITY, PASSWORD, or OTP
-(one-time-password). <id> is a unique identifier for the
-current network. <text> is description of the request. In
-case of OTP request, it includes the challenge from the
-authentication server.
-.PP
-The reply to these requests can be given with
-\fBidentity\fR, \fBpassword\fR, and
-\fBotp\fR commands. <id> needs to be copied from
-the matching request. \fBpassword\fR and
-\fBotp\fR commands can be used regardless of whether
-the request was for PASSWORD or OTP. The main difference between these
-two commands is that values given with \fBpassword\fR are
-remembered as long as wpa_supplicant is running whereas values given
-with \fBotp\fR are used only once and then forgotten,
-i.e., wpa_supplicant will ask frontend for a new value for every use.
-This can be used to implement one-time-password lists and generic token
-card -based authentication.
-.PP
-Example request for password and a matching reply:
-.sp
-.RS
-
-.nf
-CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
-> password 1 mysecretpassword
-.fi
-.RE
-.PP
-Example request for generic token card challenge-response:
-.sp
-.RS
-
-.nf
-CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
-> otp 2 9876
-.fi
-.RE
-.SH "COMMAND ARGUMENTS"
-.TP
-\fB-p path\fR
-Change the path where control sockets should
-be found.
-.TP
-\fB-i ifname\fR
-Specify the interface that is being
-configured.  By default, choose the first interface found with
-a control socket in the socket path.
-.TP
-\fB-h\fR
-Help.  Show a usage message.
-.TP
-\fB-v\fR
-Show version information.
-.TP
-\fB-B\fR
-Run as a daemon in the background.
-.TP
-\fB-a file\fR
-Run in daemon mode executing the action file
-based on events from wpa_supplicant.  The specified file will
-be executed with the first argument set to interface name and
-second to "CONNECTED" or "DISCONNECTED" depending on the event.
-This can be used to execute networking tools required to configure
-the interface.
-
-Additionally, three environmental variables are available to
-the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
-contains the absolute path to the ctrl_interface socket. WPA_ID
-contains the unique network_id identifier assigned to the active
-network, and WPA_ID_STR contains the content of the id_str option.
-.TP
-\fB-P file\fR
-Set the location of the PID
-file.
-.TP
-\fBcommand\fR
-Run a command.  The available commands are
-listed in the next section.
-.SH "COMMANDS"
-.PP
-The following commands are available:
-.TP
-\fBstatus\fR
-get current WPA/EAPOL/EAP status
-.TP
-\fBmib\fR
-get MIB variables (dot1x, dot11)
-.TP
-\fBhelp\fR
-show this usage help
-.TP
-\fBinterface [ifname]\fR
-show interfaces/select interface
-.TP
-\fBlevel <debug level>\fR
-change debug level
-.TP
-\fBlicense\fR
-show full wpa_cli license
-.TP
-\fBlogoff\fR
-IEEE 802.1X EAPOL state machine logoff
-.TP
-\fBlogon\fR
-IEEE 802.1X EAPOL state machine logon
-.TP
-\fBset\fR
-set variables (shows list of variables when run without arguments)
-.TP
-\fBpmksa\fR
-show PMKSA cache
-.TP
-\fBreassociate\fR
-force reassociation
-.TP
-\fBreconfigure\fR
-force wpa_supplicant to re-read its configuration file
-.TP
-\fBpreauthenticate <BSSID>\fR
-force preauthentication
-.TP
-\fBidentity <network id> <identity>\fR
-configure identity for an SSID
-.TP
-\fBpassword <network id> <password>\fR
-configure password for an SSID
-.TP
-\fBpin <network id> <pin>\fR
-configure pin for an SSID
-.TP
-\fBotp <network id> <password>\fR
-configure one-time-password for an SSID
-.TP
-\fBbssid <network id> <BSSID>\fR
-set preferred BSSID for an SSID
-.TP
-\fBlist_networks\fR
-list configured networks
-.TP
-\fBterminate\fR
-terminate \fBwpa_supplicant\fR
-.TP
-\fBquit\fR
-exit wpa_cli
-.SH "SEE ALSO"
-.PP
-\fBwpa_supplicant\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_cli.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,210 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_CLI" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_cli \- WPA command line client
+.SH SYNOPSIS
+
+\fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB\fIcommand ...\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+wpa_cli is a text-based frontend program for interacting
+with wpa_supplicant. It is used to query current status, change
+configuration, trigger events, and request interactive user
+input.
+.PP
+wpa_cli can show the current authentication status, selected
+security mode, dot11 and dot1x MIBs, etc. In addition, it can
+configure some variables like EAPOL state machine parameters and
+trigger events like reassociation and IEEE 802.1X
+logoff/logon. wpa_cli provides a user interface to request
+authentication information, like username and password, if these
+are not included in the configuration. This can be used to
+implement, e.g., one-time-passwords or generic token card
+authentication where the authentication is based on a
+challenge-response that uses an external device for generating the
+response.
+.PP
+The control interface of wpa_supplicant can be configured to
+allow non-root user access (ctrl_interface GROUP= parameter in the
+configuration file). This makes it possible to run wpa_cli with a
+normal user account.
+.PP
+wpa_cli supports two modes: interactive and command
+line. Both modes share the same command set and the main
+difference is in interactive mode providing access to unsolicited
+messages (event messages, username/password requests).
+.PP
+Interactive mode is started when wpa_cli is executed without
+including the command as a command line parameter. Commands are
+then entered on the wpa_cli prompt. In command line mode, the same
+commands are entered as command line arguments for wpa_cli.
+.SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST"
+.PP
+When wpa_supplicant need authentication parameters, like
+username and password, which are not present in the configuration
+file, it sends a request message to all attached frontend programs,
+e.g., wpa_cli in interactive mode. wpa_cli shows these requests
+with "CTRL-REQ-<type>-<id>:<text>"
+prefix. <type> is IDENTITY, PASSWORD, or OTP
+(one-time-password). <id> is a unique identifier for the
+current network. <text> is description of the request. In
+case of OTP request, it includes the challenge from the
+authentication server.
+.PP
+The reply to these requests can be given with
+\fBidentity\fR, \fBpassword\fR, and
+\fBotp\fR commands. <id> needs to be copied from
+the matching request. \fBpassword\fR and
+\fBotp\fR commands can be used regardless of whether
+the request was for PASSWORD or OTP. The main difference between these
+two commands is that values given with \fBpassword\fR are
+remembered as long as wpa_supplicant is running whereas values given
+with \fBotp\fR are used only once and then forgotten,
+i.e., wpa_supplicant will ask frontend for a new value for every use.
+This can be used to implement one-time-password lists and generic token
+card -based authentication.
+.PP
+Example request for password and a matching reply:
+.sp
+.RS
+
+.nf
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+.fi
+.RE
+.PP
+Example request for generic token card challenge-response:
+.sp
+.RS
+
+.nf
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+.fi
+.RE
+.SH "COMMAND ARGUMENTS"
+.TP
+\fB-p path\fR
+Change the path where control sockets should
+be found.
+.TP
+\fB-i ifname\fR
+Specify the interface that is being
+configured.  By default, choose the first interface found with
+a control socket in the socket path.
+.TP
+\fB-h\fR
+Help.  Show a usage message.
+.TP
+\fB-v\fR
+Show version information.
+.TP
+\fB-B\fR
+Run as a daemon in the background.
+.TP
+\fB-a file\fR
+Run in daemon mode executing the action file
+based on events from wpa_supplicant.  The specified file will
+be executed with the first argument set to interface name and
+second to "CONNECTED" or "DISCONNECTED" depending on the event.
+This can be used to execute networking tools required to configure
+the interface.
+
+Additionally, three environmental variables are available to
+the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
+contains the absolute path to the ctrl_interface socket. WPA_ID
+contains the unique network_id identifier assigned to the active
+network, and WPA_ID_STR contains the content of the id_str option.
+.TP
+\fB-P file\fR
+Set the location of the PID
+file.
+.TP
+\fBcommand\fR
+Run a command.  The available commands are
+listed in the next section.
+.SH "COMMANDS"
+.PP
+The following commands are available:
+.TP
+\fBstatus\fR
+get current WPA/EAPOL/EAP status
+.TP
+\fBmib\fR
+get MIB variables (dot1x, dot11)
+.TP
+\fBhelp\fR
+show this usage help
+.TP
+\fBinterface [ifname]\fR
+show interfaces/select interface
+.TP
+\fBlevel <debug level>\fR
+change debug level
+.TP
+\fBlicense\fR
+show full wpa_cli license
+.TP
+\fBlogoff\fR
+IEEE 802.1X EAPOL state machine logoff
+.TP
+\fBlogon\fR
+IEEE 802.1X EAPOL state machine logon
+.TP
+\fBset\fR
+set variables (shows list of variables when run without arguments)
+.TP
+\fBpmksa\fR
+show PMKSA cache
+.TP
+\fBreassociate\fR
+force reassociation
+.TP
+\fBreconfigure\fR
+force wpa_supplicant to re-read its configuration file
+.TP
+\fBpreauthenticate <BSSID>\fR
+force preauthentication
+.TP
+\fBidentity <network id> <identity>\fR
+configure identity for an SSID
+.TP
+\fBpassword <network id> <password>\fR
+configure password for an SSID
+.TP
+\fBpin <network id> <pin>\fR
+configure pin for an SSID
+.TP
+\fBotp <network id> <password>\fR
+configure one-time-password for an SSID
+.TP
+\fBbssid <network id> <BSSID>\fR
+set preferred BSSID for an SSID
+.TP
+\fBlist_networks\fR
+list configured networks
+.TP
+\fBterminate\fR
+terminate \fBwpa_supplicant\fR
+.TP
+\fBquit\fR
+exit wpa_cli
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_cli.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,339 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_cli</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_cli</refname>
-
-    <refpurpose>WPA command line client</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>wpa_cli</command>
-      <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
-      <arg>-i <replaceable>ifname</replaceable></arg>
-      <arg>-hvB</arg>
-      <arg>-a <replaceable>action file</replaceable></arg>
-      <arg>-P <replaceable>pid file</replaceable></arg>
-      <arg><replaceable>command ...</replaceable></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Overview</title>
-
-    <para>wpa_cli is a text-based frontend program for interacting
-    with wpa_supplicant. It is used to query current status, change
-    configuration, trigger events, and request interactive user
-    input.</para>
-
-    <para>wpa_cli can show the current authentication status, selected
-    security mode, dot11 and dot1x MIBs, etc. In addition, it can
-    configure some variables like EAPOL state machine parameters and
-    trigger events like reassociation and IEEE 802.1X
-    logoff/logon. wpa_cli provides a user interface to request
-    authentication information, like username and password, if these
-    are not included in the configuration. This can be used to
-    implement, e.g., one-time-passwords or generic token card
-    authentication where the authentication is based on a
-    challenge-response that uses an external device for generating the
-    response.</para>
-
-    <para>The control interface of wpa_supplicant can be configured to
-    allow non-root user access (ctrl_interface GROUP= parameter in the
-    configuration file). This makes it possible to run wpa_cli with a
-    normal user account.</para>
-
-    <para>wpa_cli supports two modes: interactive and command
-    line. Both modes share the same command set and the main
-    difference is in interactive mode providing access to unsolicited
-    messages (event messages, username/password requests).</para>
-
-    <para>Interactive mode is started when wpa_cli is executed without
-    including the command as a command line parameter. Commands are
-    then entered on the wpa_cli prompt. In command line mode, the same
-    commands are entered as command line arguments for wpa_cli.</para>
- </refsect1>
- <refsect1>
-   <title>Interactive authentication parameters request</title>
-
-   <para>When wpa_supplicant need authentication parameters, like
-   username and password, which are not present in the configuration
-   file, it sends a request message to all attached frontend programs,
-   e.g., wpa_cli in interactive mode. wpa_cli shows these requests
-   with "CTRL-REQ-<type>-<id>:<text>"
-   prefix. <type> is IDENTITY, PASSWORD, or OTP
-   (one-time-password). <id> is a unique identifier for the
-   current network. <text> is description of the request. In
-   case of OTP request, it includes the challenge from the
-   authentication server.</para>
-
-    <para>The reply to these requests can be given with
-    <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and
-    <emphasis>otp</emphasis> commands. <id> needs to be copied from
-    the matching request. <emphasis>password</emphasis> and
-    <emphasis>otp</emphasis> commands can be used regardless of whether
-    the request was for PASSWORD or OTP. The main difference between these
-    two commands is that values given with <emphasis>password</emphasis> are
-    remembered as long as wpa_supplicant is running whereas values given
-    with <emphasis>otp</emphasis> are used only once and then forgotten,
-    i.e., wpa_supplicant will ask frontend for a new value for every use.
-    This can be used to implement one-time-password lists and generic token
-    card -based authentication.</para>
-
-    <para>Example request for password and a matching reply:</para>
-
-<blockquote><programlisting>
-CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
-> password 1 mysecretpassword
-</programlisting></blockquote>
-
-    <para>Example request for generic token card challenge-response:</para>
-
-<blockquote><programlisting>
-CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
-> otp 2 9876
-</programlisting></blockquote>
-
-  </refsect1>
-  <refsect1>
-    <title>Command Arguments</title>
-    <variablelist>
-      <varlistentry>
-	<term>-p path</term>
-
-	<listitem><para>Change the path where control sockets should
-	be found.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-i ifname</term>
-
-        <listitem><para>Specify the interface that is being
-	configured.  By default, choose the first interface found with
-	a control socket in the socket path.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-h</term>
-	<listitem><para>Help.  Show a usage message.</para></listitem>
-      </varlistentry>
-
-
-      <varlistentry>
-	<term>-v</term>
-	<listitem><para>Show version information.</para></listitem>
-      </varlistentry>
-
-
-      <varlistentry>
-	<term>-B</term>
-	<listitem><para>Run as a daemon in the background.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-a file</term>
-
-	<listitem><para>Run in daemon mode executing the action file
-        based on events from wpa_supplicant.  The specified file will
-	be executed with the first argument set to interface name and
-	second to "CONNECTED" or "DISCONNECTED" depending on the event.
-	This can be used to execute networking tools required to configure
-	the interface.</para>
-
-	<para>Additionally, three environmental variables are available to
-	the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
-	contains the absolute path to the ctrl_interface socket. WPA_ID
-	contains the unique network_id identifier assigned to the active
-	network, and WPA_ID_STR contains the content of the id_str option.
-	</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-P file</term>
-
-	<listitem><para>Set the location of the PID
-	file.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>command</term>
-
-	<listitem><para>Run a command.  The available commands are
-	listed in the next section.</para></listitem>
-
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Commands</title>
-    <para>The following commands are available:</para>
-
-    <variablelist>
-      <varlistentry>
-	<term>status</term>
-	<listitem>
-	  <para>get current WPA/EAPOL/EAP status</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>mib</term>
-	<listitem>
-	  <para>get MIB variables (dot1x, dot11)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>help</term>
-	<listitem>
-	  <para>show this usage help</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>interface [ifname]</term>
-	<listitem>
-	  <para>show interfaces/select interface</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>level <debug level></term>
-	<listitem>
-	  <para>change debug level</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>license</term>
-	<listitem>
-	  <para>show full wpa_cli license</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>logoff</term>
-	<listitem>
-	  <para>IEEE 802.1X EAPOL state machine logoff</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>logon</term>
-	<listitem>
-	  <para>IEEE 802.1X EAPOL state machine logon</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>set</term>
-	<listitem>
-	  <para>set variables (shows list of variables when run without arguments)</para>
-	</listitem>
-      </varlistentry>
-      <varlistentry>
-	<term>pmksa</term>
-	<listitem>
-	  <para>show PMKSA cache</para>
-	</listitem>
-      </varlistentry>
-      <varlistentry>
-	<term>reassociate</term>
-	<listitem>
-	  <para>force reassociation</para>
-	</listitem>
-      </varlistentry>
-      <varlistentry>
-	<term>reconfigure</term>
-	<listitem>
-	  <para>force wpa_supplicant to re-read its configuration file</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>preauthenticate <BSSID></term>
-	<listitem>
-	  <para>force preauthentication</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>identity <network id> <identity></term>
-	<listitem>
-	  <para>configure identity for an SSID</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>password <network id> <password></term>
-	<listitem>
-	  <para>configure password for an SSID</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>pin <network id> <pin></term>
-	<listitem>
-	  <para>configure pin for an SSID</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>otp <network id> <password></term>
-	<listitem>
-	  <para>configure one-time-password for an SSID</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>bssid <network id> <BSSID></term>
-	<listitem>
-	  <para>set preferred BSSID for an SSID</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>list_networks</term>
-	<listitem>
-	  <para>list configured networks</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>terminate</term>
-	<listitem>
-	  <para>terminate <command>wpa_supplicant</command></para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>quit</term>
-	<listitem><para>exit wpa_cli</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-  </refsect1>
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_cli.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_cli.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,339 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_cli</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_cli</refname>
+
+    <refpurpose>WPA command line client</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>wpa_cli</command>
+      <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+      <arg>-i <replaceable>ifname</replaceable></arg>
+      <arg>-hvB</arg>
+      <arg>-a <replaceable>action file</replaceable></arg>
+      <arg>-P <replaceable>pid file</replaceable></arg>
+      <arg><replaceable>command ...</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Overview</title>
+
+    <para>wpa_cli is a text-based frontend program for interacting
+    with wpa_supplicant. It is used to query current status, change
+    configuration, trigger events, and request interactive user
+    input.</para>
+
+    <para>wpa_cli can show the current authentication status, selected
+    security mode, dot11 and dot1x MIBs, etc. In addition, it can
+    configure some variables like EAPOL state machine parameters and
+    trigger events like reassociation and IEEE 802.1X
+    logoff/logon. wpa_cli provides a user interface to request
+    authentication information, like username and password, if these
+    are not included in the configuration. This can be used to
+    implement, e.g., one-time-passwords or generic token card
+    authentication where the authentication is based on a
+    challenge-response that uses an external device for generating the
+    response.</para>
+
+    <para>The control interface of wpa_supplicant can be configured to
+    allow non-root user access (ctrl_interface GROUP= parameter in the
+    configuration file). This makes it possible to run wpa_cli with a
+    normal user account.</para>
+
+    <para>wpa_cli supports two modes: interactive and command
+    line. Both modes share the same command set and the main
+    difference is in interactive mode providing access to unsolicited
+    messages (event messages, username/password requests).</para>
+
+    <para>Interactive mode is started when wpa_cli is executed without
+    including the command as a command line parameter. Commands are
+    then entered on the wpa_cli prompt. In command line mode, the same
+    commands are entered as command line arguments for wpa_cli.</para>
+ </refsect1>
+ <refsect1>
+   <title>Interactive authentication parameters request</title>
+
+   <para>When wpa_supplicant need authentication parameters, like
+   username and password, which are not present in the configuration
+   file, it sends a request message to all attached frontend programs,
+   e.g., wpa_cli in interactive mode. wpa_cli shows these requests
+   with "CTRL-REQ-<type>-<id>:<text>"
+   prefix. <type> is IDENTITY, PASSWORD, or OTP
+   (one-time-password). <id> is a unique identifier for the
+   current network. <text> is description of the request. In
+   case of OTP request, it includes the challenge from the
+   authentication server.</para>
+
+    <para>The reply to these requests can be given with
+    <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and
+    <emphasis>otp</emphasis> commands. <id> needs to be copied from
+    the matching request. <emphasis>password</emphasis> and
+    <emphasis>otp</emphasis> commands can be used regardless of whether
+    the request was for PASSWORD or OTP. The main difference between these
+    two commands is that values given with <emphasis>password</emphasis> are
+    remembered as long as wpa_supplicant is running whereas values given
+    with <emphasis>otp</emphasis> are used only once and then forgotten,
+    i.e., wpa_supplicant will ask frontend for a new value for every use.
+    This can be used to implement one-time-password lists and generic token
+    card -based authentication.</para>
+
+    <para>Example request for password and a matching reply:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+</programlisting></blockquote>
+
+    <para>Example request for generic token card challenge-response:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+</programlisting></blockquote>
+
+  </refsect1>
+  <refsect1>
+    <title>Command Arguments</title>
+    <variablelist>
+      <varlistentry>
+	<term>-p path</term>
+
+	<listitem><para>Change the path where control sockets should
+	be found.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-i ifname</term>
+
+        <listitem><para>Specify the interface that is being
+	configured.  By default, choose the first interface found with
+	a control socket in the socket path.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-h</term>
+	<listitem><para>Help.  Show a usage message.</para></listitem>
+      </varlistentry>
+
+
+      <varlistentry>
+	<term>-v</term>
+	<listitem><para>Show version information.</para></listitem>
+      </varlistentry>
+
+
+      <varlistentry>
+	<term>-B</term>
+	<listitem><para>Run as a daemon in the background.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-a file</term>
+
+	<listitem><para>Run in daemon mode executing the action file
+        based on events from wpa_supplicant.  The specified file will
+	be executed with the first argument set to interface name and
+	second to "CONNECTED" or "DISCONNECTED" depending on the event.
+	This can be used to execute networking tools required to configure
+	the interface.</para>
+
+	<para>Additionally, three environmental variables are available to
+	the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
+	contains the absolute path to the ctrl_interface socket. WPA_ID
+	contains the unique network_id identifier assigned to the active
+	network, and WPA_ID_STR contains the content of the id_str option.
+	</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-P file</term>
+
+	<listitem><para>Set the location of the PID
+	file.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>command</term>
+
+	<listitem><para>Run a command.  The available commands are
+	listed in the next section.</para></listitem>
+
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>Commands</title>
+    <para>The following commands are available:</para>
+
+    <variablelist>
+      <varlistentry>
+	<term>status</term>
+	<listitem>
+	  <para>get current WPA/EAPOL/EAP status</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>mib</term>
+	<listitem>
+	  <para>get MIB variables (dot1x, dot11)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>help</term>
+	<listitem>
+	  <para>show this usage help</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>interface [ifname]</term>
+	<listitem>
+	  <para>show interfaces/select interface</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>level <debug level></term>
+	<listitem>
+	  <para>change debug level</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>license</term>
+	<listitem>
+	  <para>show full wpa_cli license</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>logoff</term>
+	<listitem>
+	  <para>IEEE 802.1X EAPOL state machine logoff</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>logon</term>
+	<listitem>
+	  <para>IEEE 802.1X EAPOL state machine logon</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>set</term>
+	<listitem>
+	  <para>set variables (shows list of variables when run without arguments)</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term>pmksa</term>
+	<listitem>
+	  <para>show PMKSA cache</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term>reassociate</term>
+	<listitem>
+	  <para>force reassociation</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term>reconfigure</term>
+	<listitem>
+	  <para>force wpa_supplicant to re-read its configuration file</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>preauthenticate <BSSID></term>
+	<listitem>
+	  <para>force preauthentication</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>identity <network id> <identity></term>
+	<listitem>
+	  <para>configure identity for an SSID</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>password <network id> <password></term>
+	<listitem>
+	  <para>configure password for an SSID</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>pin <network id> <pin></term>
+	<listitem>
+	  <para>configure pin for an SSID</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>otp <network id> <password></term>
+	<listitem>
+	  <para>configure one-time-password for an SSID</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>bssid <network id> <BSSID></term>
+	<listitem>
+	  <para>set preferred BSSID for an SSID</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>list_networks</term>
+	<listitem>
+	  <para>list configured networks</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>terminate</term>
+	<listitem>
+	  <para>terminate <command>wpa_supplicant</command></para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>quit</term>
+	<listitem><para>exit wpa_cli</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_gui.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,51 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_GUI" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_gui \- WPA Graphical User Interface
-.SH SYNOPSIS
-
-\fBwpa_gui\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-t\fR ]
-
-.SH "OVERVIEW"
-.PP
-wpa_gui is a QT graphical frontend program for interacting
-with wpa_supplicant. It is used to query current status, change
-configuration and request interactive user input.
-.PP
-wpa_gui supports (almost) all of the interactive status and
-configuration features of the command line client, wpa_cli. Refer
-to the wpa_cli manpage for a comprehensive list of the
-interactive mode features.
-.SH "COMMAND ARGUMENTS"
-.TP
-\fB-p path\fR
-Change the path where control sockets should
-be found.
-.TP
-\fB-i ifname\fR
-Specify the interface that is being
-configured. By default, choose the first interface found with
-a control socket in the socket path.
-.TP
-\fB-t\fR
-Start program in the system tray only (if the window
-manager supports it). By default the main status window is
-shown.
-.SH "SEE ALSO"
-.PP
-\fBwpa_cli\fR(8)
-\fBwpa_supplicant\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_gui.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,51 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_GUI" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_gui \- WPA Graphical User Interface
+.SH SYNOPSIS
+
+\fBwpa_gui\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-t\fR ]
+
+.SH "OVERVIEW"
+.PP
+wpa_gui is a QT graphical frontend program for interacting
+with wpa_supplicant. It is used to query current status, change
+configuration and request interactive user input.
+.PP
+wpa_gui supports (almost) all of the interactive status and
+configuration features of the command line client, wpa_cli. Refer
+to the wpa_cli manpage for a comprehensive list of the
+interactive mode features.
+.SH "COMMAND ARGUMENTS"
+.TP
+\fB-p path\fR
+Change the path where control sockets should
+be found.
+.TP
+\fB-i ifname\fR
+Specify the interface that is being
+configured. By default, choose the first interface found with
+a control socket in the socket path.
+.TP
+\fB-t\fR
+Start program in the system tray only (if the window
+manager supports it). By default the main status window is
+shown.
+.SH "SEE ALSO"
+.PP
+\fBwpa_cli\fR(8)
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_gui.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,85 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_gui</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_gui</refname>
-
-    <refpurpose>WPA Graphical User Interface</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>wpa_gui</command>
-      <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
-      <arg>-i <replaceable>ifname</replaceable></arg>
-      <arg>-t</arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Overview</title>
-
-    <para>wpa_gui is a QT graphical frontend program for interacting
-    with wpa_supplicant. It is used to query current status, change
-    configuration and request interactive user input.</para>
-
-    <para>wpa_gui supports (almost) all of the interactive status and
-    configuration features of the command line client, wpa_cli. Refer
-    to the wpa_cli manpage for a comprehensive list of the
-    interactive mode features.</para>
-  </refsect1>
-  <refsect1>
-    <title>Command Arguments</title>
-    <variablelist>
-      <varlistentry>
-	<term>-p path</term>
-
-	<listitem><para>Change the path where control sockets should
-	be found.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-i ifname</term>
-
-        <listitem><para>Specify the interface that is being
-	configured. By default, choose the first interface found with
-	a control socket in the socket path.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-t</term>
-
-        <listitem><para>Start program in the system tray only (if the window
-	manager supports it). By default the main status window is
-	shown.</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_cli</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-  </refsect1>
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_gui.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_gui.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,85 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_gui</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_gui</refname>
+
+    <refpurpose>WPA Graphical User Interface</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>wpa_gui</command>
+      <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+      <arg>-i <replaceable>ifname</replaceable></arg>
+      <arg>-t</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Overview</title>
+
+    <para>wpa_gui is a QT graphical frontend program for interacting
+    with wpa_supplicant. It is used to query current status, change
+    configuration and request interactive user input.</para>
+
+    <para>wpa_gui supports (almost) all of the interactive status and
+    configuration features of the command line client, wpa_cli. Refer
+    to the wpa_cli manpage for a comprehensive list of the
+    interactive mode features.</para>
+  </refsect1>
+  <refsect1>
+    <title>Command Arguments</title>
+    <variablelist>
+      <varlistentry>
+	<term>-p path</term>
+
+	<listitem><para>Change the path where control sockets should
+	be found.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-i ifname</term>
+
+        <listitem><para>Specify the interface that is being
+	configured. By default, choose the first interface found with
+	a control socket in the socket path.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-t</term>
+
+        <listitem><para>Start program in the system tray only (if the window
+	manager supports it). By default the main status window is
+	shown.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_cli</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_passphrase.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,40 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PASSPHRASE" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID
-.SH SYNOPSIS
-
-\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ]
-
-.SH "OVERVIEW"
-.PP
-\fBwpa_passphrase\fR pre-computes PSK entries for
-network configuration blocks of a
-\fIwpa_supplicant.conf\fR file. An ASCII passphrase
-and SSID are used to generate a 256-bit PSK.
-.SH "OPTIONS"
-.TP
-\fBssid\fR
-The SSID whose passphrase should be derived.
-.TP
-\fBpassphrase\fR
-The passphrase to use. If not included on the command line,
-passphrase will be read from standard input.
-.SH "SEE ALSO"
-.PP
-\fBwpa_supplicant.conf\fR(5)
-\fBwpa_supplicant\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_passphrase.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,40 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_PASSPHRASE" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID
+.SH SYNOPSIS
+
+\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+\fBwpa_passphrase\fR pre-computes PSK entries for
+network configuration blocks of a
+\fIwpa_supplicant.conf\fR file. An ASCII passphrase
+and SSID are used to generate a 256-bit PSK.
+.SH "OPTIONS"
+.TP
+\fBssid\fR
+The SSID whose passphrase should be derived.
+.TP
+\fBpassphrase\fR
+The passphrase to use. If not included on the command line,
+passphrase will be read from standard input.
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant.conf\fR(5)
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_passphrase.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,73 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_passphrase</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_passphrase</refname>
-    <refpurpose>Generate a WPA PSK from an ASCII passphrase for a SSID</refpurpose>
-  </refnamediv>
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>wpa_passphrase</command>
-      <arg><replaceable>ssid</replaceable></arg>
-      <arg><replaceable>passphrase</replaceable></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Overview</title> 
-
-    <para><command>wpa_passphrase</command> pre-computes PSK entries for
-    network configuration blocks of a
-    <filename>wpa_supplicant.conf</filename> file. An ASCII passphrase
-    and SSID are used to generate a 256-bit PSK.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Options</title>
-    <variablelist>
-      <varlistentry>
-	<term>ssid</term>
-	<listitem>
-	  <para>The SSID whose passphrase should be derived.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>passphrase</term>
-	<listitem>
-	  <para>The passphrase to use. If not included on the command line,
-	  passphrase will be read from standard input.</para>
-	</listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant.conf</refentrytitle>
-	<manvolnum>5</manvolnum>
-      </citerefentry>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-
-  </refsect1>
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_passphrase.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_passphrase.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,73 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_passphrase</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_passphrase</refname>
+    <refpurpose>Generate a WPA PSK from an ASCII passphrase for a SSID</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>wpa_passphrase</command>
+      <arg><replaceable>ssid</replaceable></arg>
+      <arg><replaceable>passphrase</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Overview</title> 
+
+    <para><command>wpa_passphrase</command> pre-computes PSK entries for
+    network configuration blocks of a
+    <filename>wpa_supplicant.conf</filename> file. An ASCII passphrase
+    and SSID are used to generate a 256-bit PSK.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+    <variablelist>
+      <varlistentry>
+	<term>ssid</term>
+	<listitem>
+	  <para>The SSID whose passphrase should be derived.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>passphrase</term>
+	<listitem>
+	  <para>The passphrase to use. If not included on the command line,
+	  passphrase will be read from standard input.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant.conf</refentrytitle>
+	<manvolnum>5</manvolnum>
+      </citerefentry>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_priv.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,120 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PRIV" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_priv \- wpa_supplicant privilege separation helper
-.SH SYNOPSIS
-
-\fBwpa_priv\fR [ \fB-c \fIctrl path\fB\fR ] [ \fB-Bdd\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fBdriver:ifname \fI[driver:ifname ...]\fB\fR ]
-
-.SH "OVERVIEW"
-.PP
-\fBwpa_priv\fR is a privilege separation helper that
-minimizes the size of \fBwpa_supplicant\fR code that needs
-to be run with root privileges.
-.PP
-If enabled, privileged operations are done in the wpa_priv process
-while leaving rest of the code (e.g., EAP authentication and WPA
-handshakes) to operate in an unprivileged process (wpa_supplicant) that
-can be run as non-root user. Privilege separation restricts the effects
-of potential software errors by containing the majority of the code in an
-unprivileged process to avoid the possibility of a full system
-compromise.
-.PP
-\fBwpa_priv\fR needs to be run with network admin
-privileges (usually, root user). It opens a UNIX domain socket for each
-interface that is included on the command line; any other interface will
-be off limits for \fBwpa_supplicant\fR in this kind of
-configuration. After this, \fBwpa_supplicant\fR can be run as
-a non-root user (e.g., all standard users on a laptop or as a special
-non-privileged user account created just for this purpose to limit access
-to user files even further).
-.SH "EXAMPLE CONFIGURATION"
-.PP
-The following steps are an example of how to configure
-\fBwpa_priv\fR to allow users in the
-\fBwpapriv\fR group to communicate with
-\fBwpa_supplicant\fR with privilege separation:
-.PP
-Create user group (e.g., wpapriv) and assign users that
-should be able to use wpa_supplicant into that group.
-.PP
-Create /var/run/wpa_priv directory for UNIX domain sockets and
-control user access by setting it accessible only for the wpapriv
-group:
-.sp
-.RS
-
-.nf
-mkdir /var/run/wpa_priv
-chown root:wpapriv /var/run/wpa_priv
-chmod 0750 /var/run/wpa_priv
-.fi
-.RE
-.PP
-Start \fBwpa_priv\fR as root (e.g., from system
-startup scripts) with the enabled interfaces configured on the
-command line:
-.sp
-.RS
-
-.nf
-wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
-.fi
-.RE
-.PP
-Run \fBwpa_supplicant\fR as non-root with a user
-that is in the wpapriv group:
-.sp
-.RS
-
-.nf
-wpa_supplicant -i ath0 -c wpa_supplicant.conf
-.fi
-.RE
-.SH "COMMAND ARGUMENTS"
-.TP
-\fB-c ctrl path\fR
-Specify the path to wpa_priv control directory
-(Default: /var/run/wpa_priv/).
-.TP
-\fB-B\fR
-Run as a daemon in the background.
-.TP
-\fB-P file\fR
-Set the location of the PID
-file.
-.TP
-\fBdriver:ifname [driver:ifname ...]\fR
-The <driver> string dictates which of the
-supported \fBwpa_supplicant\fR driver backends is to be
-used. To get a list of supported driver types see wpa_supplicant help
-(e.g, wpa_supplicant -h). The driver backend supported by most good
-drivers is \fBwext\fR\&.
-
-The <ifname> string specifies which network
-interface is to be managed by \fBwpa_supplicant\fR
-(e.g., wlan0 or ath0).
-
-\fBwpa_priv\fR does not use the network interface
-before \fBwpa_supplicant\fR is started, so it is fine to
-include network interfaces that are not available at the time wpa_priv
-is started. wpa_priv can control multiple interfaces with one process,
-but it is also possible to run multiple \fBwpa_priv\fR
-processes at the same time, if desired.
-.SH "SEE ALSO"
-.PP
-\fBwpa_supplicant\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_priv.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,120 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_PRIV" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_priv \- wpa_supplicant privilege separation helper
+.SH SYNOPSIS
+
+\fBwpa_priv\fR [ \fB-c \fIctrl path\fB\fR ] [ \fB-Bdd\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fBdriver:ifname \fI[driver:ifname ...]\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+\fBwpa_priv\fR is a privilege separation helper that
+minimizes the size of \fBwpa_supplicant\fR code that needs
+to be run with root privileges.
+.PP
+If enabled, privileged operations are done in the wpa_priv process
+while leaving rest of the code (e.g., EAP authentication and WPA
+handshakes) to operate in an unprivileged process (wpa_supplicant) that
+can be run as non-root user. Privilege separation restricts the effects
+of potential software errors by containing the majority of the code in an
+unprivileged process to avoid the possibility of a full system
+compromise.
+.PP
+\fBwpa_priv\fR needs to be run with network admin
+privileges (usually, root user). It opens a UNIX domain socket for each
+interface that is included on the command line; any other interface will
+be off limits for \fBwpa_supplicant\fR in this kind of
+configuration. After this, \fBwpa_supplicant\fR can be run as
+a non-root user (e.g., all standard users on a laptop or as a special
+non-privileged user account created just for this purpose to limit access
+to user files even further).
+.SH "EXAMPLE CONFIGURATION"
+.PP
+The following steps are an example of how to configure
+\fBwpa_priv\fR to allow users in the
+\fBwpapriv\fR group to communicate with
+\fBwpa_supplicant\fR with privilege separation:
+.PP
+Create user group (e.g., wpapriv) and assign users that
+should be able to use wpa_supplicant into that group.
+.PP
+Create /var/run/wpa_priv directory for UNIX domain sockets and
+control user access by setting it accessible only for the wpapriv
+group:
+.sp
+.RS
+
+.nf
+mkdir /var/run/wpa_priv
+chown root:wpapriv /var/run/wpa_priv
+chmod 0750 /var/run/wpa_priv
+.fi
+.RE
+.PP
+Start \fBwpa_priv\fR as root (e.g., from system
+startup scripts) with the enabled interfaces configured on the
+command line:
+.sp
+.RS
+
+.nf
+wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
+.fi
+.RE
+.PP
+Run \fBwpa_supplicant\fR as non-root with a user
+that is in the wpapriv group:
+.sp
+.RS
+
+.nf
+wpa_supplicant -i ath0 -c wpa_supplicant.conf
+.fi
+.RE
+.SH "COMMAND ARGUMENTS"
+.TP
+\fB-c ctrl path\fR
+Specify the path to wpa_priv control directory
+(Default: /var/run/wpa_priv/).
+.TP
+\fB-B\fR
+Run as a daemon in the background.
+.TP
+\fB-P file\fR
+Set the location of the PID
+file.
+.TP
+\fBdriver:ifname [driver:ifname ...]\fR
+The <driver> string dictates which of the
+supported \fBwpa_supplicant\fR driver backends is to be
+used. To get a list of supported driver types see wpa_supplicant help
+(e.g, wpa_supplicant -h). The driver backend supported by most good
+drivers is \fBwext\fR\&.
+
+The <ifname> string specifies which network
+interface is to be managed by \fBwpa_supplicant\fR
+(e.g., wlan0 or ath0).
+
+\fBwpa_priv\fR does not use the network interface
+before \fBwpa_supplicant\fR is started, so it is fine to
+include network interfaces that are not available at the time wpa_priv
+is started. wpa_priv can control multiple interfaces with one process,
+but it is also possible to run multiple \fBwpa_priv\fR
+processes at the same time, if desired.
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_priv.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,148 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_priv</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_priv</refname>
-
-    <refpurpose>wpa_supplicant privilege separation helper</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>wpa_priv</command>
-      <arg>-c <replaceable>ctrl path</replaceable></arg>
-      <arg>-Bdd</arg>
-      <arg>-P <replaceable>pid file</replaceable></arg>
-      <arg>driver:ifname <replaceable>[driver:ifname ...]</replaceable></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Overview</title>
-
-    <para><command>wpa_priv</command> is a privilege separation helper that
-    minimizes the size of <command>wpa_supplicant</command> code that needs
-    to be run with root privileges.</para>
-
-    <para>If enabled, privileged operations are done in the wpa_priv process
-    while leaving rest of the code (e.g., EAP authentication and WPA
-    handshakes) to operate in an unprivileged process (wpa_supplicant) that
-    can be run as non-root user. Privilege separation restricts the effects
-    of potential software errors by containing the majority of the code in an
-    unprivileged process to avoid the possibility of a full system
-    compromise.</para>
-
-    <para><command>wpa_priv</command> needs to be run with network admin
-    privileges (usually, root user). It opens a UNIX domain socket for each
-    interface that is included on the command line; any other interface will
-    be off limits for <command>wpa_supplicant</command> in this kind of
-    configuration. After this, <command>wpa_supplicant</command> can be run as
-    a non-root user (e.g., all standard users on a laptop or as a special
-    non-privileged user account created just for this purpose to limit access
-    to user files even further).</para>
-  </refsect1>
-  <refsect1>
-    <title>Example configuration</title>
-
-    <para>The following steps are an example of how to configure
-    <command>wpa_priv</command> to allow users in the
-    <emphasis>wpapriv</emphasis> group to communicate with
-    <command>wpa_supplicant</command> with privilege separation:</para>
-
-    <para>Create user group (e.g., wpapriv) and assign users that
-    should be able to use wpa_supplicant into that group.</para>
-
-    <para>Create /var/run/wpa_priv directory for UNIX domain sockets and
-    control user access by setting it accessible only for the wpapriv
-    group:</para>
-
-<blockquote><programlisting>
-mkdir /var/run/wpa_priv
-chown root:wpapriv /var/run/wpa_priv
-chmod 0750 /var/run/wpa_priv
-</programlisting></blockquote>
-
-    <para>Start <command>wpa_priv</command> as root (e.g., from system
-    startup scripts) with the enabled interfaces configured on the
-    command line:</para>
-
-<blockquote><programlisting>
-wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
-</programlisting></blockquote>
-
-    <para>Run <command>wpa_supplicant</command> as non-root with a user
-    that is in the wpapriv group:</para>
-
-<blockquote><programlisting>
-wpa_supplicant -i ath0 -c wpa_supplicant.conf
-</programlisting></blockquote>
-
-  </refsect1>
-  <refsect1>
-    <title>Command Arguments</title>
-    <variablelist>
-      <varlistentry>
-	<term>-c ctrl path</term>
-
-	<listitem><para>Specify the path to wpa_priv control directory
-	(Default: /var/run/wpa_priv/).</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-B</term>
-	<listitem><para>Run as a daemon in the background.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-P file</term>
-
-	<listitem><para>Set the location of the PID
-	file.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>driver:ifname [driver:ifname ...]</term>
-
-	<listitem><para>The <driver> string dictates which of the
-	supported <command>wpa_supplicant</command> driver backends is to be
-	used. To get a list of supported driver types see wpa_supplicant help
-	(e.g, wpa_supplicant -h). The driver backend supported by most good
-	drivers is <emphasis>wext</emphasis>.</para>
-
-	<para>The <ifname> string specifies which network
-	interface is to be managed by <command>wpa_supplicant</command>
-	(e.g., wlan0 or ath0).</para>
-
-	<para><command>wpa_priv</command> does not use the network interface
-	before <command>wpa_supplicant</command> is started, so it is fine to
-	include network interfaces that are not available at the time wpa_priv
-	is started. wpa_priv can control multiple interfaces with one process,
-	but it is also possible to run multiple <command>wpa_priv</command>
-	processes at the same time, if desired.</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-  </refsect1>
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_priv.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_priv.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,148 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_priv</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_priv</refname>
+
+    <refpurpose>wpa_supplicant privilege separation helper</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>wpa_priv</command>
+      <arg>-c <replaceable>ctrl path</replaceable></arg>
+      <arg>-Bdd</arg>
+      <arg>-P <replaceable>pid file</replaceable></arg>
+      <arg>driver:ifname <replaceable>[driver:ifname ...]</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Overview</title>
+
+    <para><command>wpa_priv</command> is a privilege separation helper that
+    minimizes the size of <command>wpa_supplicant</command> code that needs
+    to be run with root privileges.</para>
+
+    <para>If enabled, privileged operations are done in the wpa_priv process
+    while leaving rest of the code (e.g., EAP authentication and WPA
+    handshakes) to operate in an unprivileged process (wpa_supplicant) that
+    can be run as non-root user. Privilege separation restricts the effects
+    of potential software errors by containing the majority of the code in an
+    unprivileged process to avoid the possibility of a full system
+    compromise.</para>
+
+    <para><command>wpa_priv</command> needs to be run with network admin
+    privileges (usually, root user). It opens a UNIX domain socket for each
+    interface that is included on the command line; any other interface will
+    be off limits for <command>wpa_supplicant</command> in this kind of
+    configuration. After this, <command>wpa_supplicant</command> can be run as
+    a non-root user (e.g., all standard users on a laptop or as a special
+    non-privileged user account created just for this purpose to limit access
+    to user files even further).</para>
+  </refsect1>
+  <refsect1>
+    <title>Example configuration</title>
+
+    <para>The following steps are an example of how to configure
+    <command>wpa_priv</command> to allow users in the
+    <emphasis>wpapriv</emphasis> group to communicate with
+    <command>wpa_supplicant</command> with privilege separation:</para>
+
+    <para>Create user group (e.g., wpapriv) and assign users that
+    should be able to use wpa_supplicant into that group.</para>
+
+    <para>Create /var/run/wpa_priv directory for UNIX domain sockets and
+    control user access by setting it accessible only for the wpapriv
+    group:</para>
+
+<blockquote><programlisting>
+mkdir /var/run/wpa_priv
+chown root:wpapriv /var/run/wpa_priv
+chmod 0750 /var/run/wpa_priv
+</programlisting></blockquote>
+
+    <para>Start <command>wpa_priv</command> as root (e.g., from system
+    startup scripts) with the enabled interfaces configured on the
+    command line:</para>
+
+<blockquote><programlisting>
+wpa_priv -B -c /var/run/wpa_priv -P /var/run/wpa_priv.pid wext:wlan0
+</programlisting></blockquote>
+
+    <para>Run <command>wpa_supplicant</command> as non-root with a user
+    that is in the wpapriv group:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -i ath0 -c wpa_supplicant.conf
+</programlisting></blockquote>
+
+  </refsect1>
+  <refsect1>
+    <title>Command Arguments</title>
+    <variablelist>
+      <varlistentry>
+	<term>-c ctrl path</term>
+
+	<listitem><para>Specify the path to wpa_priv control directory
+	(Default: /var/run/wpa_priv/).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-B</term>
+	<listitem><para>Run as a daemon in the background.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-P file</term>
+
+	<listitem><para>Set the location of the PID
+	file.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>driver:ifname [driver:ifname ...]</term>
+
+	<listitem><para>The <driver> string dictates which of the
+	supported <command>wpa_supplicant</command> driver backends is to be
+	used. To get a list of supported driver types see wpa_supplicant help
+	(e.g, wpa_supplicant -h). The driver backend supported by most good
+	drivers is <emphasis>wext</emphasis>.</para>
+
+	<para>The <ifname> string specifies which network
+	interface is to be managed by <command>wpa_supplicant</command>
+	(e.g., wlan0 or ath0).</para>
+
+	<para><command>wpa_priv</command> does not use the network interface
+	before <command>wpa_supplicant</command> is started, so it is fine to
+	include network interfaces that are not available at the time wpa_priv
+	is started. wpa_priv can control multiple interfaces with one process,
+	but it is also possible to run multiple <command>wpa_priv</command>
+	processes at the same time, if desired.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.8	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,583 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT" "8" "07 September 2010" "" ""
-
-.SH NAME
-wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
-.SH SYNOPSIS
-
-\fBwpa_supplicant\fR [ \fB-BddfhKLqqtuvW\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ] [ \fB-P\fIPID_file\fB\fR ] [ \fB-f\fIoutput file\fB\fR ]
-
-.SH "OVERVIEW"
-.PP
-Wireless networks do not require physical access to the network equipment
-in the same way as wired networks. This makes it easier for unauthorized
-users to passively monitor a network and capture all transmitted frames.
-In addition, unauthorized use of the network is much easier. In many cases,
-this can happen even without user's explicit knowledge since the wireless
-LAN adapter may have been configured to automatically join any available
-network.
-.PP
-Link-layer encryption can be used to provide a layer of security for
-wireless networks. The original wireless LAN standard, IEEE 802.11,
-included a simple encryption mechanism, WEP. However, that proved to
-be flawed in many areas and network protected with WEP cannot be consider
-secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
-can be used to improve the network security, but even that has inherited
-security issues due to the use of WEP for encryption. Wi-Fi Protected
-Access and IEEE 802.11i amendment to the wireless LAN standard introduce
-a much improvement mechanism for securing wireless networks. IEEE 802.11i
-enabled networks that are using CCMP (encryption mechanism based on strong
-cryptographic algorithm AES) can finally be called secure used for
-applications which require efficient protection against unauthorized
-access.
-.PP
-\fBwpa_supplicant\fR is an implementation of
-the WPA Supplicant component, i.e., the part that runs in the
-client stations. It implements WPA key negotiation with a WPA
-Authenticator and EAP authentication with Authentication
-Server. In addition, it controls the roaming and IEEE 802.11
-authentication/association of the wireless LAN driver.
-.PP
-\fBwpa_supplicant\fR is designed to be a
-"daemon" program that runs in the background and acts as the
-backend component controlling the wireless
-connection. \fBwpa_supplicant\fR supports separate
-frontend programs and an example text-based frontend,
-\fBwpa_cli\fR, is included with
-wpa_supplicant.
-.PP
-Before wpa_supplicant can do its work, the network interface
-must be available.  That means that the physical device must be
-present and enabled, and the driver for the device must be
-loaded. The daemon will exit immediately if the device is not already
-available.
-.PP
-After \fBwpa_supplicant\fR has configured the
-network device, higher level configuration such as DHCP may
-proceed.  There are a variety of ways to integrate wpa_supplicant
-into a machine's networking scripts, a few of which are described
-in sections below.
-.PP
-The following steps are used when associating with an AP
-using WPA:
-.TP 0.2i
-\(bu
-\fBwpa_supplicant\fR requests the kernel
-driver to scan neighboring BSSes
-.TP 0.2i
-\(bu
-\fBwpa_supplicant\fR selects a BSS based on
-its configuration
-.TP 0.2i
-\(bu
-\fBwpa_supplicant\fR requests the kernel
-driver to associate with the chosen BSS
-.TP 0.2i
-\(bu
-If WPA-EAP: integrated IEEE 802.1X Supplicant
-completes EAP authentication with the
-authentication server (proxied by the Authenticator in the
-AP)
-.TP 0.2i
-\(bu
-If WPA-EAP: master key is received from the IEEE 802.1X
-Supplicant
-.TP 0.2i
-\(bu
-If WPA-PSK: \fBwpa_supplicant\fR uses PSK
-as the master session key
-.TP 0.2i
-\(bu
-\fBwpa_supplicant\fR completes WPA 4-Way
-Handshake and Group Key Handshake with the Authenticator
-(AP)
-.TP 0.2i
-\(bu
-\fBwpa_supplicant\fR configures encryption
-keys for unicast and broadcast
-.TP 0.2i
-\(bu
-normal data packets can be transmitted and received
-.SH "SUPPORTED FEATURES"
-.PP
-Supported WPA/IEEE 802.11i features:
-.TP 0.2i
-\(bu
-WPA-PSK ("WPA-Personal")
-.TP 0.2i
-\(bu
-WPA with EAP (e.g., with RADIUS authentication server)
-("WPA-Enterprise") Following authentication methods are
-supported with an integrate IEEE 802.1X Supplicant:
-.RS
-.TP 0.2i
-\(bu
-EAP-TLS
-.RE
-.RS
-.TP 0.2i
-\(bu
-EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
-.TP 0.2i
-\(bu
-EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
-.TP 0.2i
-\(bu
-EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
-.TP 0.2i
-\(bu
-EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
-.TP 0.2i
-\(bu
-EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
-.TP 0.2i
-\(bu
-EAP-TTLS/EAP-MD5-Challenge
-.TP 0.2i
-\(bu
-EAP-TTLS/EAP-GTC
-.TP 0.2i
-\(bu
-EAP-TTLS/EAP-OTP
-.TP 0.2i
-\(bu
-EAP-TTLS/EAP-MSCHAPv2
-.TP 0.2i
-\(bu
-EAP-TTLS/EAP-TLS
-.TP 0.2i
-\(bu
-EAP-TTLS/MSCHAPv2
-.TP 0.2i
-\(bu
-EAP-TTLS/MSCHAP
-.TP 0.2i
-\(bu
-EAP-TTLS/PAP
-.TP 0.2i
-\(bu
-EAP-TTLS/CHAP
-.TP 0.2i
-\(bu
-EAP-SIM
-.TP 0.2i
-\(bu
-EAP-AKA
-.TP 0.2i
-\(bu
-EAP-PSK
-.TP 0.2i
-\(bu
-EAP-PAX
-.TP 0.2i
-\(bu
-LEAP (note: requires special support from
-the driver for IEEE 802.11 authentication)
-.TP 0.2i
-\(bu
-(following methods are supported, but since
-they do not generate keying material, they cannot be used
-with WPA or IEEE 802.1X WEP keying)
-.TP 0.2i
-\(bu
-EAP-MD5-Challenge 
-.TP 0.2i
-\(bu
-EAP-MSCHAPv2
-.TP 0.2i
-\(bu
-EAP-GTC
-.TP 0.2i
-\(bu
-EAP-OTP
-.RE
-.TP 0.2i
-\(bu
-key management for CCMP, TKIP, WEP104, WEP40
-.TP 0.2i
-\(bu
-RSN/WPA2 (IEEE 802.11i)
-.RS
-.TP 0.2i
-\(bu
-pre-authentication
-.TP 0.2i
-\(bu
-PMKSA caching
-.RE
-.SH "AVAILABLE DRIVERS"
-.PP
-A summary of available driver backends is below. Support for each
-of the driver backends is chosen at wpa_supplicant compile time. For a
-list of supported driver backends that may be used with the -D option on
-your system, refer to the help output of wpa_supplicant
-(\fBwpa_supplicant -h\fR).
-.TP
-\fBhostap\fR
-(default) Host AP driver (Intersil Prism2/2.5/3).
-(this can also be used with Linuxant DriverLoader).
-.TP
-\fBhermes\fR
-Agere Systems Inc. driver (Hermes-I/Hermes-II).
-.TP
-\fBmadwifi\fR
-MADWIFI 802.11 support (Atheros, etc.).
-.TP
-\fBatmel\fR
-ATMEL AT76C5XXx (USB, PCMCIA).
-.TP
-\fBwext\fR
-Linux wireless extensions (generic).
-.TP
-\fBndiswrapper\fR
-Linux ndiswrapper.
-.TP
-\fBbroadcom\fR
-Broadcom wl.o driver.
-.TP
-\fBipw\fR
-Intel ipw2100/2200 driver.
-.TP
-\fBwired\fR
-wpa_supplicant wired Ethernet driver
-.TP
-\fBroboswitch\fR
-wpa_supplicant Broadcom switch driver
-.TP
-\fBbsd\fR
-BSD 802.11 support (Atheros, etc.).
-.TP
-\fBndis\fR
-Windows NDIS driver.
-.SH "COMMAND LINE OPTIONS"
-.PP
-Most command line options have global scope. Some are given per
-interface, and are only valid if at least one \fB-i\fR option
-is specified, otherwise they're ignored. Option groups for different
-interfaces must be separated by \fB-N\fR option.
-.TP
-\fB-b br_ifname\fR
-Optional bridge interface name. (Per interface)
-.TP
-\fB-B\fR
-Run daemon in the background.
-.TP
-\fB-c filename\fR
-Path to configuration file. (Per interface)
-.TP
-\fB-C ctrl_interface\fR
-Path to ctrl_interface socket (Per interface. Only used if
-\fB-c\fR is not).
-.TP
-\fB-i ifname\fR
-Interface to listen on. Multiple instances of this option can
-be present, one per interface, separated by \fB-N\fR
-option (see below).
-.TP
-\fB-d\fR
-Increase debugging verbosity (\fB-dd\fR even
-more).
-.TP
-\fB-D driver\fR
-Driver to use (can be multiple drivers: nl80211,wext).
-(Per interface, see the available options below.)
-.TP
-\fB-f output file\fR
-Log output to specified file instead of stdout.
-.TP
-\fB-g global ctrl_interface\fR
-Path to global ctrl_interface socket. If specified, interface
-definitions may be omitted.
-.TP
-\fB-K\fR
-Include keys (passwords, etc.) in debug output.
-.TP
-\fB-t\fR
-Include timestamp in debug messages.
-.TP
-\fB-h\fR
-Help.  Show a usage message.
-.TP
-\fB-L\fR
-Show license (GPL and BSD).
-.TP
-\fB-p\fR
-Driver parameters. (Per interface)
-.TP
-\fB-P PID_file\fR
-Path to PID file.
-.TP
-\fB-q\fR
-Decrease debugging verbosity (\fB-qq\fR even
-less).
-.TP
-\fB-u\fR
-Enabled DBus control interface. If enabled, interface
-definitions may be omitted.
-.TP
-\fB-v\fR
-Show version.
-.TP
-\fB-W\fR
-Wait for a control interface monitor before starting.
-.TP
-\fB-N\fR
-Start describing new interface.
-.SH "EXAMPLES"
-.PP
-In most common cases, \fBwpa_supplicant\fR is
-started with:
-.sp
-.RS
-
-.nf
-wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
-.fi
-.RE
-.PP
-This makes the process fork into background.
-.PP
-The easiest way to debug problems, and to get debug log for
-bug reports, is to start \fBwpa_supplicant\fR on
-foreground with debugging enabled:
-.sp
-.RS
-
-.nf
-wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
-.fi
-.RE
-.PP
-If the specific driver wrapper is not known beforehand, it is
-possible to specify multiple comma separated driver wrappers on the command
-line. \fBwpa_supplicant\fR will use the first driver
-wrapper that is able to initialize the interface.
-.sp
-.RS
-
-.nf
-wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
-.fi
-.RE
-.PP
-\fBwpa_supplicant\fR can control multiple
-interfaces (radios) either by running one process for each
-interface separately or by running just one process and list of
-options at command line. Each interface is separated with -N
-argument. As an example, following command would start
-wpa_supplicant for two interfaces:
-.sp
-.RS
-
-.nf
-wpa_supplicant \\
-	-c wpa1.conf -i wlan0 -D hostap -N \\
-	-c wpa2.conf -i ath0 -D madwifi
-.fi
-.RE
-.SH "OS REQUIREMENTS"
-.PP
-Current hardware/software requirements:
-.TP 0.2i
-\(bu
-Linux kernel 2.4.x or 2.6.x with Linux Wireless
-Extensions v15 or newer
-.TP 0.2i
-\(bu
-FreeBSD 6-CURRENT
-.TP 0.2i
-\(bu
-Microsoft Windows with WinPcap (at least WinXP, may work
-with other versions)
-.SH "SUPPORTED DRIVERS"
-.TP
-\fBHost AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)\fR
-(http://hostap.epitest.fi/) Driver needs to be set in
-Managed mode (\fBiwconfig wlan0 mode managed\fR).
-Please note that station firmware version needs to be 1.7.0 or
-newer to work in WPA mode.
-.TP
-\fBLinuxant DriverLoader\fR
-(http://www.linuxant.com/driverloader/)
-with Windows NDIS driver for your wlan card supporting WPA.
-.TP
-\fBAgere Systems Inc. Linux Driver\fR
-(http://www.agere.com/support/drivers/) Please note
-that the driver interface file (driver_hermes.c) and hardware
-specific include files are not included in the wpa_supplicant
-distribution. You will need to copy these from the source
-package of the Agere driver.
-.TP
-\fBmadwifi driver for cards based on Atheros chip set (ar521x)\fR
-(http://sourceforge.net/projects/madwifi/) Please
-note that you will need to modify the wpa_supplicant .config
-file to use the correct path for the madwifi driver root
-directory (CFLAGS += -I../madwifi/wpa line in example
-defconfig).
-.TP
-\fBATMEL AT76C5XXx driver for USB and PCMCIA cards\fR
-(http://atmelwlandriver.sourceforge.net/).
-.TP
-\fBLinux ndiswrapper\fR
-(http://ndiswrapper.sourceforge.net/) with Windows
-NDIS driver.
-.TP
-\fBBroadcom wl.o driver\fR
-This is a generic Linux driver for Broadcom IEEE
-802.11a/g cards.  However, it is proprietary driver that is
-not publicly available except for couple of exceptions, mainly
-Broadcom-based APs/wireless routers that use Linux. The driver
-binary can be downloaded, e.g., from Linksys support site
-(http://www.linksys.com/support/gpl.asp) for Linksys
-WRT54G. The GPL tarball includes cross-compiler and the needed
-header file, wlioctl.h, for compiling wpa_supplicant.  This
-driver support in wpa_supplicant is expected to work also with
-other devices based on Broadcom driver (assuming the driver
-includes client mode support).
-.TP
-\fB Intel ipw2100 driver\fR
-(http://sourceforge.net/projects/ipw2100/)
-.TP
-\fBIntel ipw2200 driver\fR
-(http://sourceforge.net/projects/ipw2200/)
-.TP
-\fBLinux wireless extensions\fR
-In theory, any driver that supports Linux wireless
-extensions can be used with IEEE 802.1X (i.e., not WPA) when
-using ap_scan=0 option in configuration file.
-.TP
-\fBWired Ethernet drivers\fR
-Use ap_scan=0.
-.TP
-\fBBSD net80211 layer (e.g., Atheros driver)\fR
-At the moment, this is for FreeBSD 6-CURRENT branch.
-.TP
-\fBWindows NDIS\fR
-The current Windows port requires WinPcap
-(http://winpcap.polito.it/).  See README-Windows.txt for more
-information.
-.PP
-wpa_supplicant was designed to be portable for different
-drivers and operating systems. Hopefully, support for more wlan
-cards and OSes will be added in the future. See developer.txt for
-more information about the design of wpa_supplicant and porting to
-other drivers. One main goal is to add full WPA/WPA2 support to
-Linux wireless extensions to allow new drivers to be supported
-without having to implement new driver-specific interface code in
-wpa_supplicant.
-.SH "ARCHITECTURE"
-.PP
-The
-\fBwpa_supplicant\fR system consists of the following
-components:
-.TP
-\fB\fIwpa_supplicant.conf\fB \fR
-the configuration file describing all networks that the
-user wants the computer to connect to.  
-.TP
-\fBwpa_supplicant\fR
-the program that directly interacts with the
-network interface.  
-.TP
-\fBwpa_cli\fR
-the
-client program that provides a high-level interface to the
-functionality of the daemon.  
-.TP
-\fBwpa_passphrase\fR
-a utility needed to construct
-\fIwpa_supplicant.conf\fR files that include
-encrypted passwords.
-.SH "QUICK START"
-.PP
-First, make a configuration file, e.g.
-\fI/etc/wpa_supplicant.conf\fR, that describes the networks
-you are interested in.  See \fBwpa_supplicant.conf\fR(5)
-for details.
-.PP
-Once the configuration is ready, you can test whether the
-configuration works by running \fBwpa_supplicant\fR
-with following command to start it on foreground with debugging
-enabled:
-.sp
-.RS
-
-.nf
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
-    
-.fi
-.RE
-.PP
-Assuming everything goes fine, you can start using following
-command to start \fBwpa_supplicant\fR on background
-without debugging:
-.sp
-.RS
-
-.nf
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
-    
-.fi
-.RE
-.PP
-Please note that if you included more than one driver
-interface in the build time configuration (.config), you may need
-to specify which interface to use by including -D<driver
-name> option on the command line.
-.SH "INTERFACE TO PCMCIA-CS/CARDMRG"
-.PP
-For example, following small changes to pcmcia-cs scripts
-can be used to enable WPA support:
-.PP
-Add MODE="Managed" and WPA="y" to the network scheme in
-\fI/etc/pcmcia/wireless.opts\fR\&.
-.PP
-Add the following block to the end of \fBstart\fR
-action handler in \fI/etc/pcmcia/wireless\fR:
-.sp
-.RS
-
-.nf
-if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-    /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE
-fi
-    
-.fi
-.RE
-.PP
-Add the following block to the end of \fBstop\fR
-action handler (may need to be separated from other actions) in
-\fI/etc/pcmcia/wireless\fR:
-.sp
-.RS
-
-.nf
-if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-    killall wpa_supplicant
-fi
-    
-.fi
-.RE
-.PP
-This will make \fBcardmgr\fR start
-\fBwpa_supplicant\fR when the card is plugged
-in.
-.SH "SEE ALSO"
-.PP
-\fBwpa_background\fR(8)
-\fBwpa_supplicant.conf\fR(5)
-\fBwpa_cli\fR(8)
-\fBwpa_passphrase\fR(8)
-.SH "LEGAL"
-.PP
-wpa_supplicant is copyright (c) 2003-2007,
-Jouni Malinen <j at w1.fi> and
-contributors.
-All Rights Reserved.
-.PP
-This program is dual-licensed under both the GPL version 2
-and BSD license. Either license may be used at your option.

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.8)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.8	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,511 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_SUPPLICANT" "8" "12 January 2013" "" ""
+
+.SH NAME
+wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
+.SH SYNOPSIS
+
+\fBwpa_supplicant\fR [ \fB-BddfhKLqqtuvW\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ] [ \fB-P\fIPID_file\fB\fR ] [ \fB-f\fIoutput file\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+Wireless networks do not require physical access to the network equipment
+in the same way as wired networks. This makes it easier for unauthorized
+users to passively monitor a network and capture all transmitted frames.
+In addition, unauthorized use of the network is much easier. In many cases,
+this can happen even without user's explicit knowledge since the wireless
+LAN adapter may have been configured to automatically join any available
+network.
+.PP
+Link-layer encryption can be used to provide a layer of security for
+wireless networks. The original wireless LAN standard, IEEE 802.11,
+included a simple encryption mechanism, WEP. However, that proved to
+be flawed in many areas and network protected with WEP cannot be consider
+secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
+can be used to improve the network security, but even that has inherited
+security issues due to the use of WEP for encryption. Wi-Fi Protected
+Access and IEEE 802.11i amendment to the wireless LAN standard introduce
+a much improvement mechanism for securing wireless networks. IEEE 802.11i
+enabled networks that are using CCMP (encryption mechanism based on strong
+cryptographic algorithm AES) can finally be called secure used for
+applications which require efficient protection against unauthorized
+access.
+.PP
+\fBwpa_supplicant\fR is an implementation of
+the WPA Supplicant component, i.e., the part that runs in the
+client stations. It implements WPA key negotiation with a WPA
+Authenticator and EAP authentication with Authentication
+Server. In addition, it controls the roaming and IEEE 802.11
+authentication/association of the wireless LAN driver.
+.PP
+\fBwpa_supplicant\fR is designed to be a
+"daemon" program that runs in the background and acts as the
+backend component controlling the wireless
+connection. \fBwpa_supplicant\fR supports separate
+frontend programs and an example text-based frontend,
+\fBwpa_cli\fR, is included with
+wpa_supplicant.
+.PP
+Before wpa_supplicant can do its work, the network interface
+must be available.  That means that the physical device must be
+present and enabled, and the driver for the device must be
+loaded. The daemon will exit immediately if the device is not already
+available.
+.PP
+After \fBwpa_supplicant\fR has configured the
+network device, higher level configuration such as DHCP may
+proceed.  There are a variety of ways to integrate wpa_supplicant
+into a machine's networking scripts, a few of which are described
+in sections below.
+.PP
+The following steps are used when associating with an AP
+using WPA:
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR requests the kernel
+driver to scan neighboring BSSes
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR selects a BSS based on
+its configuration
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR requests the kernel
+driver to associate with the chosen BSS
+.TP 0.2i
+\(bu
+If WPA-EAP: integrated IEEE 802.1X Supplicant
+completes EAP authentication with the
+authentication server (proxied by the Authenticator in the
+AP)
+.TP 0.2i
+\(bu
+If WPA-EAP: master key is received from the IEEE 802.1X
+Supplicant
+.TP 0.2i
+\(bu
+If WPA-PSK: \fBwpa_supplicant\fR uses PSK
+as the master session key
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR completes WPA 4-Way
+Handshake and Group Key Handshake with the Authenticator
+(AP)
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR configures encryption
+keys for unicast and broadcast
+.TP 0.2i
+\(bu
+normal data packets can be transmitted and received
+.SH "SUPPORTED FEATURES"
+.PP
+Supported WPA/IEEE 802.11i features:
+.TP 0.2i
+\(bu
+WPA-PSK ("WPA-Personal")
+.TP 0.2i
+\(bu
+WPA with EAP (e.g., with RADIUS authentication server)
+("WPA-Enterprise") Following authentication methods are
+supported with an integrate IEEE 802.1X Supplicant:
+.RS
+.TP 0.2i
+\(bu
+EAP-TLS
+.RE
+.RS
+.TP 0.2i
+\(bu
+EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-MD5-Challenge
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-GTC
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-OTP
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-TLS
+.TP 0.2i
+\(bu
+EAP-TTLS/MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-TTLS/MSCHAP
+.TP 0.2i
+\(bu
+EAP-TTLS/PAP
+.TP 0.2i
+\(bu
+EAP-TTLS/CHAP
+.TP 0.2i
+\(bu
+EAP-SIM
+.TP 0.2i
+\(bu
+EAP-AKA
+.TP 0.2i
+\(bu
+EAP-PSK
+.TP 0.2i
+\(bu
+EAP-PAX
+.TP 0.2i
+\(bu
+LEAP (note: requires special support from
+the driver for IEEE 802.11 authentication)
+.TP 0.2i
+\(bu
+(following methods are supported, but since
+they do not generate keying material, they cannot be used
+with WPA or IEEE 802.1X WEP keying)
+.TP 0.2i
+\(bu
+EAP-MD5-Challenge 
+.TP 0.2i
+\(bu
+EAP-MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-GTC
+.TP 0.2i
+\(bu
+EAP-OTP
+.RE
+.TP 0.2i
+\(bu
+key management for CCMP, TKIP, WEP104, WEP40
+.TP 0.2i
+\(bu
+RSN/WPA2 (IEEE 802.11i)
+.RS
+.TP 0.2i
+\(bu
+pre-authentication
+.TP 0.2i
+\(bu
+PMKSA caching
+.RE
+.SH "AVAILABLE DRIVERS"
+.PP
+A summary of available driver backends is below. Support for each
+of the driver backends is chosen at wpa_supplicant compile time. For a
+list of supported driver backends that may be used with the -D option on
+your system, refer to the help output of wpa_supplicant
+(\fBwpa_supplicant -h\fR).
+.TP
+\fBwext\fR
+Linux wireless extensions (generic).
+.TP
+\fBwired\fR
+wpa_supplicant wired Ethernet driver
+.TP
+\fBroboswitch\fR
+wpa_supplicant Broadcom switch driver
+.TP
+\fBbsd\fR
+BSD 802.11 support (Atheros, etc.).
+.TP
+\fBndis\fR
+Windows NDIS driver.
+.SH "COMMAND LINE OPTIONS"
+.PP
+Most command line options have global scope. Some are given per
+interface, and are only valid if at least one \fB-i\fR option
+is specified, otherwise they're ignored. Option groups for different
+interfaces must be separated by \fB-N\fR option.
+.TP
+\fB-b br_ifname\fR
+Optional bridge interface name. (Per interface)
+.TP
+\fB-B\fR
+Run daemon in the background.
+.TP
+\fB-c filename\fR
+Path to configuration file. (Per interface)
+.TP
+\fB-C ctrl_interface\fR
+Path to ctrl_interface socket (Per interface. Only used if
+\fB-c\fR is not).
+.TP
+\fB-i ifname\fR
+Interface to listen on. Multiple instances of this option can
+be present, one per interface, separated by \fB-N\fR
+option (see below).
+.TP
+\fB-d\fR
+Increase debugging verbosity (\fB-dd\fR even
+more).
+.TP
+\fB-D driver\fR
+Driver to use (can be multiple drivers: nl80211,wext).
+(Per interface, see the available options below.)
+.TP
+\fB-f output file\fR
+Log output to specified file instead of stdout.
+.TP
+\fB-g global ctrl_interface\fR
+Path to global ctrl_interface socket. If specified, interface
+definitions may be omitted.
+.TP
+\fB-K\fR
+Include keys (passwords, etc.) in debug output.
+.TP
+\fB-t\fR
+Include timestamp in debug messages.
+.TP
+\fB-h\fR
+Help.  Show a usage message.
+.TP
+\fB-L\fR
+Show license (BSD).
+.TP
+\fB-p\fR
+Driver parameters. (Per interface)
+.TP
+\fB-P PID_file\fR
+Path to PID file.
+.TP
+\fB-q\fR
+Decrease debugging verbosity (\fB-qq\fR even
+less).
+.TP
+\fB-u\fR
+Enabled DBus control interface. If enabled, interface
+definitions may be omitted.
+.TP
+\fB-v\fR
+Show version.
+.TP
+\fB-W\fR
+Wait for a control interface monitor before starting.
+.TP
+\fB-N\fR
+Start describing new interface.
+.SH "EXAMPLES"
+.PP
+In most common cases, \fBwpa_supplicant\fR is
+started with:
+.sp
+.RS
+
+.nf
+wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
+.fi
+.RE
+.PP
+This makes the process fork into background.
+.PP
+The easiest way to debug problems, and to get debug log for
+bug reports, is to start \fBwpa_supplicant\fR on
+foreground with debugging enabled:
+.sp
+.RS
+
+.nf
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+.fi
+.RE
+.PP
+If the specific driver wrapper is not known beforehand, it is
+possible to specify multiple comma separated driver wrappers on the command
+line. \fBwpa_supplicant\fR will use the first driver
+wrapper that is able to initialize the interface.
+.sp
+.RS
+
+.nf
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+.fi
+.RE
+.PP
+\fBwpa_supplicant\fR can control multiple
+interfaces (radios) either by running one process for each
+interface separately or by running just one process and list of
+options at command line. Each interface is separated with -N
+argument. As an example, following command would start
+wpa_supplicant for two interfaces:
+.sp
+.RS
+
+.nf
+wpa_supplicant \\
+	-c wpa1.conf -i wlan0 -D nl80211 -N \\
+	-c wpa2.conf -i ath0 -D wext
+.fi
+.RE
+.SH "OS REQUIREMENTS"
+.PP
+Current hardware/software requirements:
+.TP 0.2i
+\(bu
+Linux kernel 2.4.x or 2.6.x with Linux Wireless
+Extensions v15 or newer
+.TP 0.2i
+\(bu
+FreeBSD 6-CURRENT
+.TP 0.2i
+\(bu
+Microsoft Windows with WinPcap (at least WinXP, may work
+with other versions)
+.SH "SUPPORTED DRIVERS"
+.TP
+\fBLinux wireless extensions\fR
+In theory, any driver that supports Linux wireless
+extensions can be used with IEEE 802.1X (i.e., not WPA) when
+using ap_scan=0 option in configuration file.
+.TP
+\fBWired Ethernet drivers\fR
+Use ap_scan=0.
+.TP
+\fBBSD net80211 layer (e.g., Atheros driver)\fR
+At the moment, this is for FreeBSD 6-CURRENT branch.
+.TP
+\fBWindows NDIS\fR
+The current Windows port requires WinPcap
+(http://winpcap.polito.it/).  See README-Windows.txt for more
+information.
+.PP
+wpa_supplicant was designed to be portable for different
+drivers and operating systems. Hopefully, support for more wlan
+cards and OSes will be added in the future. See developer.txt for
+more information about the design of wpa_supplicant and porting to
+other drivers. One main goal is to add full WPA/WPA2 support to
+Linux wireless extensions to allow new drivers to be supported
+without having to implement new driver-specific interface code in
+wpa_supplicant.
+.SH "ARCHITECTURE"
+.PP
+The
+\fBwpa_supplicant\fR system consists of the following
+components:
+.TP
+\fB\fIwpa_supplicant.conf\fB \fR
+the configuration file describing all networks that the
+user wants the computer to connect to.  
+.TP
+\fBwpa_supplicant\fR
+the program that directly interacts with the
+network interface.  
+.TP
+\fBwpa_cli\fR
+the
+client program that provides a high-level interface to the
+functionality of the daemon.  
+.TP
+\fBwpa_passphrase\fR
+a utility needed to construct
+\fIwpa_supplicant.conf\fR files that include
+encrypted passwords.
+.SH "QUICK START"
+.PP
+First, make a configuration file, e.g.
+\fI/etc/wpa_supplicant.conf\fR, that describes the networks
+you are interested in.  See \fBwpa_supplicant.conf\fR(5)
+for details.
+.PP
+Once the configuration is ready, you can test whether the
+configuration works by running \fBwpa_supplicant\fR
+with following command to start it on foreground with debugging
+enabled:
+.sp
+.RS
+
+.nf
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+    
+.fi
+.RE
+.PP
+Assuming everything goes fine, you can start using following
+command to start \fBwpa_supplicant\fR on background
+without debugging:
+.sp
+.RS
+
+.nf
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+    
+.fi
+.RE
+.PP
+Please note that if you included more than one driver
+interface in the build time configuration (.config), you may need
+to specify which interface to use by including -D<driver
+name> option on the command line.
+.SH "INTERFACE TO PCMCIA-CS/CARDMRG"
+.PP
+For example, following small changes to pcmcia-cs scripts
+can be used to enable WPA support:
+.PP
+Add MODE="Managed" and WPA="y" to the network scheme in
+\fI/etc/pcmcia/wireless.opts\fR\&.
+.PP
+Add the following block to the end of \fBstart\fR
+action handler in \fI/etc/pcmcia/wireless\fR:
+.sp
+.RS
+
+.nf
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+    /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE
+fi
+    
+.fi
+.RE
+.PP
+Add the following block to the end of \fBstop\fR
+action handler (may need to be separated from other actions) in
+\fI/etc/pcmcia/wireless\fR:
+.sp
+.RS
+
+.nf
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+    killall wpa_supplicant
+fi
+    
+.fi
+.RE
+.PP
+This will make \fBcardmgr\fR start
+\fBwpa_supplicant\fR when the card is plugged
+in.
+.SH "SEE ALSO"
+.PP
+\fBwpa_background\fR(8)
+\fBwpa_supplicant.conf\fR(5)
+\fBwpa_cli\fR(8)
+\fBwpa_passphrase\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2012,
+Jouni Malinen <j at w1.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is licensed under the BSD license (the one with
+advertisement clause removed).

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,225 +0,0 @@
-.\" This manpage has been automatically generated by docbook2man 
-.\" from a DocBook document.  This tool can be found at:
-.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
-.\" Please send any bug reports, improvements, comments, patches, 
-.\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT.CONF" "5" "07 September 2010" "" ""
-
-.SH NAME
-wpa_supplicant.conf \- configuration file for wpa_supplicant
-.SH "OVERVIEW"
-.PP
-\fBwpa_supplicant\fR is configured using a text
-file that lists all accepted networks and security policies,
-including pre-shared keys. See the example configuration file,
-probably in \fB/usr/share/doc/wpa_supplicant/\fR, for
-detailed information about the configuration format and supported
-fields.
-.PP
-All file paths in this configuration file should use full
-(absolute, not relative to working directory) path in order to allow
-working directory to be changed. This can happen if wpa_supplicant is
-run in the background.
-.PP
-Changes to configuration file can be reloaded be sending
-SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP
-wpa_supplicant'). Similarly, reloading can be triggered with
-the \fBwpa_cli reconfigure\fR command.
-.PP
-Configuration file can include one or more network blocks,
-e.g., one for each used SSID. wpa_supplicant will automatically
-select the best network based on the order of network blocks in
-the configuration file, network security level (WPA/WPA2 is
-preferred), and signal strength.
-.SH "QUICK EXAMPLES"
-.TP 3
-1. 
-WPA-Personal (PSK) as home network and WPA-Enterprise with
-EAP-TLS as work network.
-.sp
-.RS
-
-.nf
-# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-#
-# home network; allow all valid ciphers
-network={
-	ssid="home"
-	scan_ssid=1
-	key_mgmt=WPA-PSK
-	psk="very secret passphrase"
-}
-#
-# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
-network={
-	ssid="work"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	pairwise=CCMP TKIP
-	group=CCMP TKIP
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-}
-.fi
-.RE
-.TP 3
-2. 
-WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
-use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
-Aegis, Interlink RAD-Series)
-.sp
-.RS
-
-.nf
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=PEAP
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase1="peaplabel=0"
-	phase2="auth=MSCHAPV2"
-}
-.fi
-.RE
-.TP 3
-3. 
-EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
-identity for the unencrypted use. Real identity is sent only
-within an encrypted TLS tunnel.
-.sp
-.RS
-
-.nf
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user at example.com"
-	anonymous_identity="anonymous at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase2="auth=MD5"
-}
-.fi
-.RE
-.TP 3
-4. 
-IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
-(require both unicast and broadcast); use EAP-TLS for
-authentication
-.sp
-.RS
-
-.nf
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-network={
-	ssid="1x-test"
-	scan_ssid=1
-	key_mgmt=IEEE8021X
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	eapol_flags=3
-}
-.fi
-.RE
-.TP 3
-5. 
-Catch all example that allows more or less all
-configuration modes. The configuration options are used based
-on what security policy is used in the selected SSID. This is
-mostly for testing and is not recommended for normal
-use.
-.sp
-.RS
-
-.nf
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
-	pairwise=CCMP TKIP
-	group=CCMP TKIP WEP104 WEP40
-	psk="very secret passphrase"
-	eap=TTLS PEAP TLS
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	phase1="peaplabel=0"
-	ca_cert2="/etc/cert/ca2.pem"
-	client_cert2="/etc/cer/user.pem"
-	private_key2="/etc/cer/user.prv"
-	private_key2_passwd="password"
-}
-.fi
-.RE
-.TP 3
-6. 
-Authentication for wired Ethernet. This can be used with
-\fBwired\fR or \fBroboswitch\fR interface
-(-Dwired or -Droboswitch on command line).
-.sp
-.RS
-
-.nf
-ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
-ap_scan=0
-network={
-	key_mgmt=IEEE8021X
-	eap=MD5
-	identity="user"
-	password="password"
-	eapol_flags=0
-}
-.fi
-.RE
-.SH "CERTIFICATES"
-.PP
-Some EAP authentication methods require use of
-certificates. EAP-TLS uses both server side and client
-certificates whereas EAP-PEAP and EAP-TTLS only require the server
-side certificate. When client certificate is used, a matching
-private key file has to also be included in configuration. If the
-private key uses a passphrase, this has to be configured in
-wpa_supplicant.conf ("private_key_passwd").
-.PP
-wpa_supplicant supports X.509 certificates in PEM and DER
-formats. User certificate and private key can be included in the
-same file.
-.PP
-If the user certificate and private key is received in
-PKCS#12/PFX format, they need to be converted to suitable PEM/DER
-format for wpa_supplicant. This can be done, e.g., with following
-commands:
-.sp
-.RS
-
-.nf
-# convert client certificate and private key to PEM format
-openssl pkcs12 -in example.pfx -out user.pem -clcerts
-# convert CA certificate (if included in PFX file) to PEM format
-openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
-.fi
-.RE
-.SH "SEE ALSO"
-.PP
-\fBwpa_supplicant\fR(8)
-\fBopenssl\fR(1)

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,225 @@
+.\" This manpage has been automatically generated by docbook2man 
+.\" from a DocBook document.  This tool can be found at:
+.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
+.\" Please send any bug reports, improvements, comments, patches, 
+.\" etc. to Steve Cheng <steve at ggi-project.org>.
+.TH "WPA_SUPPLICANT.CONF" "5" "12 January 2013" "" ""
+
+.SH NAME
+wpa_supplicant.conf \- configuration file for wpa_supplicant
+.SH "OVERVIEW"
+.PP
+\fBwpa_supplicant\fR is configured using a text
+file that lists all accepted networks and security policies,
+including pre-shared keys. See the example configuration file,
+probably in \fB/usr/share/doc/wpa_supplicant/\fR, for
+detailed information about the configuration format and supported
+fields.
+.PP
+All file paths in this configuration file should use full
+(absolute, not relative to working directory) path in order to allow
+working directory to be changed. This can happen if wpa_supplicant is
+run in the background.
+.PP
+Changes to configuration file can be reloaded be sending
+SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP
+wpa_supplicant'). Similarly, reloading can be triggered with
+the \fBwpa_cli reconfigure\fR command.
+.PP
+Configuration file can include one or more network blocks,
+e.g., one for each used SSID. wpa_supplicant will automatically
+select the best network based on the order of network blocks in
+the configuration file, network security level (WPA/WPA2 is
+preferred), and signal strength.
+.SH "QUICK EXAMPLES"
+.TP 3
+1. 
+WPA-Personal (PSK) as home network and WPA-Enterprise with
+EAP-TLS as work network.
+.sp
+.RS
+
+.nf
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+#
+# home network; allow all valid ciphers
+network={
+	ssid="home"
+	scan_ssid=1
+	key_mgmt=WPA-PSK
+	psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+	ssid="work"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	pairwise=CCMP TKIP
+	group=CCMP TKIP
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+}
+.fi
+.RE
+.TP 3
+2. 
+WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
+use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
+Aegis, Interlink RAD-Series)
+.sp
+.RS
+
+.nf
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	eap=PEAP
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase1="peaplabel=0"
+	phase2="auth=MSCHAPV2"
+}
+.fi
+.RE
+.TP 3
+3. 
+EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
+identity for the unencrypted use. Real identity is sent only
+within an encrypted TLS tunnel.
+.sp
+.RS
+
+.nf
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user at example.com"
+	anonymous_identity="anonymous at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase2="auth=MD5"
+}
+.fi
+.RE
+.TP 3
+4. 
+IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
+(require both unicast and broadcast); use EAP-TLS for
+authentication
+.sp
+.RS
+
+.nf
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+	ssid="1x-test"
+	scan_ssid=1
+	key_mgmt=IEEE8021X
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	eapol_flags=3
+}
+.fi
+.RE
+.TP 3
+5. 
+Catch all example that allows more or less all
+configuration modes. The configuration options are used based
+on what security policy is used in the selected SSID. This is
+mostly for testing and is not recommended for normal
+use.
+.sp
+.RS
+
+.nf
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+	pairwise=CCMP TKIP
+	group=CCMP TKIP WEP104 WEP40
+	psk="very secret passphrase"
+	eap=TTLS PEAP TLS
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	phase1="peaplabel=0"
+	ca_cert2="/etc/cert/ca2.pem"
+	client_cert2="/etc/cer/user.pem"
+	private_key2="/etc/cer/user.prv"
+	private_key2_passwd="password"
+}
+.fi
+.RE
+.TP 3
+6. 
+Authentication for wired Ethernet. This can be used with
+\fBwired\fR or \fBroboswitch\fR interface
+(-Dwired or -Droboswitch on command line).
+.sp
+.RS
+
+.nf
+ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
+ap_scan=0
+network={
+	key_mgmt=IEEE8021X
+	eap=MD5
+	identity="user"
+	password="password"
+	eapol_flags=0
+}
+.fi
+.RE
+.SH "CERTIFICATES"
+.PP
+Some EAP authentication methods require use of
+certificates. EAP-TLS uses both server side and client
+certificates whereas EAP-PEAP and EAP-TTLS only require the server
+side certificate. When client certificate is used, a matching
+private key file has to also be included in configuration. If the
+private key uses a passphrase, this has to be configured in
+wpa_supplicant.conf ("private_key_passwd").
+.PP
+wpa_supplicant supports X.509 certificates in PEM and DER
+formats. User certificate and private key can be included in the
+same file.
+.PP
+If the user certificate and private key is received in
+PKCS#12/PFX format, they need to be converted to suitable PEM/DER
+format for wpa_supplicant. This can be done, e.g., with following
+commands:
+.sp
+.RS
+
+.nf
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+.fi
+.RE
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+\fBopenssl\fR(1)

Deleted: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
===================================================================
--- vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.sgml	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,827 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
-<refentry>
-  <refmeta>
-    <refentrytitle>wpa_supplicant</refentrytitle>
-    <manvolnum>8</manvolnum>
-  </refmeta>
-  <refnamediv>
-    <refname>wpa_supplicant</refname>
-    <refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose>
-  </refnamediv>
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>wpa_supplicant</command>
-      <arg>-BddfhKLqqtuvW</arg>
-      <arg>-i<replaceable>ifname</replaceable></arg>
-      <arg>-c<replaceable>config file</replaceable></arg>
-      <arg>-D<replaceable>driver</replaceable></arg>
-      <arg>-P<replaceable>PID_file</replaceable></arg>
-      <arg>-f<replaceable>output file</replaceable></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>Overview</title>
-
-    <para>
-    Wireless networks do not require physical access to the network equipment
-    in the same way as wired networks. This makes it easier for unauthorized
-    users to passively monitor a network and capture all transmitted frames.
-    In addition, unauthorized use of the network is much easier. In many cases,
-    this can happen even without user's explicit knowledge since the wireless
-    LAN adapter may have been configured to automatically join any available
-    network.
-    </para>
-
-    <para>
-    Link-layer encryption can be used to provide a layer of security for
-    wireless networks. The original wireless LAN standard, IEEE 802.11,
-    included a simple encryption mechanism, WEP. However, that proved to
-    be flawed in many areas and network protected with WEP cannot be consider
-    secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
-    can be used to improve the network security, but even that has inherited
-    security issues due to the use of WEP for encryption. Wi-Fi Protected
-    Access and IEEE 802.11i amendment to the wireless LAN standard introduce
-    a much improvement mechanism for securing wireless networks. IEEE 802.11i
-    enabled networks that are using CCMP (encryption mechanism based on strong
-    cryptographic algorithm AES) can finally be called secure used for
-    applications which require efficient protection against unauthorized
-    access.
-    </para>
-
-    <para><command>wpa_supplicant</command> is an implementation of
-    the WPA Supplicant component, i.e., the part that runs in the
-    client stations. It implements WPA key negotiation with a WPA
-    Authenticator and EAP authentication with Authentication
-    Server. In addition, it controls the roaming and IEEE 802.11
-    authentication/association of the wireless LAN driver.</para>
-
-    <para><command>wpa_supplicant</command> is designed to be a
-    "daemon" program that runs in the background and acts as the
-    backend component controlling the wireless
-    connection. <command>wpa_supplicant</command> supports separate
-    frontend programs and an example text-based frontend,
-    <command>wpa_cli</command>, is included with
-    wpa_supplicant.</para>
-
-    <para>Before wpa_supplicant can do its work, the network interface
-    must be available.  That means that the physical device must be
-    present and enabled, and the driver for the device must be
-    loaded. The daemon will exit immediately if the device is not already
-    available.</para>
-
-    <para>After <command>wpa_supplicant</command> has configured the
-    network device, higher level configuration such as DHCP may
-    proceed.  There are a variety of ways to integrate wpa_supplicant
-    into a machine's networking scripts, a few of which are described
-    in sections below.</para>
-
-    <para>The following steps are used when associating with an AP
-    using WPA:</para>
-
-    <itemizedlist>
-      <listitem>
-	<para><command>wpa_supplicant</command> requests the kernel
-	driver to scan neighboring BSSes</para>
-      </listitem>
-
-      <listitem>
-	<para><command>wpa_supplicant</command> selects a BSS based on
-	its configuration</para>
-      </listitem>
-
-      <listitem>
-	<para><command>wpa_supplicant</command> requests the kernel
-        driver to associate with the chosen BSS</para>
-      </listitem>
-
-      <listitem>
-	<para>If WPA-EAP: integrated IEEE 802.1X Supplicant
-        completes EAP authentication with the
-        authentication server (proxied by the Authenticator in the
-        AP)</para>
-      </listitem>
-
-      <listitem>
-	<para>If WPA-EAP: master key is received from the IEEE 802.1X
-	Supplicant</para>
-      </listitem>
-
-      <listitem>
-	<para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK
-	as the master session key</para>
-      </listitem>
-
-      <listitem>
-	<para><command>wpa_supplicant</command> completes WPA 4-Way
-        Handshake and Group Key Handshake with the Authenticator
-        (AP)</para>
-      </listitem>
-
-      <listitem>
-	<para><command>wpa_supplicant</command> configures encryption
-	keys for unicast and broadcast</para>
-      </listitem>
-
-      <listitem>
-	<para>normal data packets can be transmitted and received</para>
-      </listitem>
-    </itemizedlist>
-  </refsect1>
-
-  <refsect1>
-    <title>Supported Features</title>
-    <para>Supported WPA/IEEE 802.11i features:</para>
-    <itemizedlist>
-      <listitem>
-	<para>WPA-PSK ("WPA-Personal")</para>
-      </listitem>
-
-      <listitem>
-	<para>WPA with EAP (e.g., with RADIUS authentication server)
-       ("WPA-Enterprise") Following authentication methods are
-       supported with an integrate IEEE 802.1X Supplicant:</para>
-
-	<itemizedlist>
-	  <listitem>
-	    <para>EAP-TLS</para>
-	  </listitem>
-	</itemizedlist>
-
-	<itemizedlist>
-	  <listitem>
-	    <para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para>
-	  </listitem>
-
-
-	  <listitem>
-	    <para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>EAP-TTLS/EAP-MD5-Challenge</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>EAP-TTLS/EAP-GTC</para>
-	  </listitem>
-
-          <listitem><para>EAP-TTLS/EAP-OTP</para></listitem>
-
-          <listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem>
-
-          <listitem><para>EAP-TTLS/EAP-TLS</para></listitem>
-
-          <listitem><para>EAP-TTLS/MSCHAPv2</para></listitem>
-
-          <listitem><para>EAP-TTLS/MSCHAP</para></listitem>
-
-          <listitem><para>EAP-TTLS/PAP</para></listitem>
-
-          <listitem><para>EAP-TTLS/CHAP</para></listitem>
-
-          <listitem><para>EAP-SIM</para></listitem>
-
-          <listitem><para>EAP-AKA</para></listitem>
-
-          <listitem><para>EAP-PSK</para></listitem>
-
-          <listitem><para>EAP-PAX</para></listitem>
-
-          <listitem><para>LEAP (note: requires special support from
-          the driver for IEEE 802.11 authentication)</para></listitem>
-
-          <listitem><para>(following methods are supported, but since
-          they do not generate keying material, they cannot be used
-          with WPA or IEEE 802.1X WEP keying)</para></listitem>
-
-          <listitem><para>EAP-MD5-Challenge </para></listitem>
-
-          <listitem><para>EAP-MSCHAPv2</para></listitem>
-
-          <listitem><para>EAP-GTC</para></listitem>
-
-          <listitem><para>EAP-OTP</para></listitem>
-	</itemizedlist>
-      </listitem>
-
-      <listitem>
-	<para>key management for CCMP, TKIP, WEP104, WEP40</para>
-      </listitem>
-
-      <listitem>
-	<para>RSN/WPA2 (IEEE 802.11i)</para>
-	<itemizedlist>
-	  <listitem>
-	    <para>pre-authentication</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>PMKSA caching</para>
-	  </listitem>
-	</itemizedlist>
-      </listitem>
-    </itemizedlist>
-  </refsect1>
-
-  <refsect1>
-    <title>Available Drivers</title>
-    <para>A summary of available driver backends is below. Support for each
-    of the driver backends is chosen at wpa_supplicant compile time. For a
-    list of supported driver backends that may be used with the -D option on
-    your system, refer to the help output of wpa_supplicant
-    (<emphasis>wpa_supplicant -h</emphasis>).</para>
-
-    <variablelist>
-      <varlistentry>
-	<term>hostap</term>
-	<listitem>
-	  <para>(default) Host AP driver (Intersil Prism2/2.5/3).
-  	  (this can also be used with Linuxant DriverLoader).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>hermes</term>
-	<listitem>
-	  <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>madwifi</term>
-	<listitem>
-	  <para>MADWIFI 802.11 support (Atheros, etc.).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>atmel</term>
-	<listitem>
-	  <para>ATMEL AT76C5XXx (USB, PCMCIA).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>wext</term>
-	<listitem>
-	  <para>Linux wireless extensions (generic).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>ndiswrapper</term>
-	<listitem>
-	  <para>Linux ndiswrapper.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>broadcom</term>
-	<listitem>
-	  <para>Broadcom wl.o driver.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>ipw</term>
-	<listitem>
-	  <para>Intel ipw2100/2200 driver.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>wired</term>
-	<listitem>
-	  <para>wpa_supplicant wired Ethernet driver</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>roboswitch</term>
-	<listitem>
-	  <para>wpa_supplicant Broadcom switch driver</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>bsd</term>
-	<listitem>
-	  <para>BSD 802.11 support (Atheros, etc.).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>ndis</term>
-	<listitem>
-	  <para>Windows NDIS driver.</para>
-	</listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Command Line Options</title>
-    <para>Most command line options have global scope. Some are given per
-    interface, and are only valid if at least one <option>-i</option> option
-    is specified, otherwise they're ignored. Option groups for different
-    interfaces must be separated by <option>-N</option> option.</para>
-    <variablelist>
-      <varlistentry>
-	<term>-b br_ifname</term>
-	<listitem>
-	  <para>Optional bridge interface name. (Per interface)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-B</term>
-	<listitem>
-	  <para>Run daemon in the background.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-c filename</term>
-	<listitem>
-	  <para>Path to configuration file. (Per interface)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-C ctrl_interface</term>
-	<listitem>
-	  <para>Path to ctrl_interface socket (Per interface. Only used if
-		  <option>-c</option> is not).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-i ifname</term>
-	<listitem>
-	  <para>Interface to listen on. Multiple instances of this option can
-	  be present, one per interface, separated by <option>-N</option>
-	  option (see below).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-d</term>
-	<listitem>
-	  <para>Increase debugging verbosity (<option>-dd</option> even
-		  more).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-D driver</term>
-	<listitem>
-	  <para>Driver to use (can be multiple drivers: nl80211,wext).
-		  (Per interface, see the available options below.)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-f output file</term>
-	<listitem>
-	  <para>Log output to specified file instead of stdout.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-g global ctrl_interface</term>
-	<listitem>
-	  <para>Path to global ctrl_interface socket. If specified, interface
-	  definitions may be omitted.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-K</term>
-	<listitem>
-	  <para>Include keys (passwords, etc.) in debug output.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-t</term>
-	<listitem>
-	  <para>Include timestamp in debug messages.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-h</term>
-	<listitem>
-	  <para>Help.  Show a usage message.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-L</term>
-	<listitem>
-	  <para>Show license (GPL and BSD).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-p</term>
-	<listitem>
-	  <para>Driver parameters. (Per interface)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-P PID_file</term>
-	<listitem>
-	  <para>Path to PID file.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-q</term>
-	<listitem>
-	  <para>Decrease debugging verbosity (<option>-qq</option> even
-		  less).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-u</term>
-	<listitem>
-	  <para>Enabled DBus control interface. If enabled, interface
-	  definitions may be omitted.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-v</term>
-	<listitem>
-	  <para>Show version.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-W</term>
-	<listitem>
-	  <para>Wait for a control interface monitor before starting.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>-N</term>
-	<listitem>
-	  <para>Start describing new interface.</para>
-	</listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Examples</title>
-
-    <para>In most common cases, <command>wpa_supplicant</command> is
-    started with:</para>
-
-<blockquote><programlisting>
-wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
-</programlisting></blockquote>
-
-    <para>This makes the process fork into background.</para>
-
-    <para>The easiest way to debug problems, and to get debug log for
-    bug reports, is to start <command>wpa_supplicant</command> on
-    foreground with debugging enabled:</para>
-
-<blockquote><programlisting>
-wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
-</programlisting></blockquote>
-
-    <para>If the specific driver wrapper is not known beforehand, it is
-    possible to specify multiple comma separated driver wrappers on the command
-    line. <command>wpa_supplicant</command> will use the first driver
-    wrapper that is able to initialize the interface.</para>
-
-<blockquote><programlisting>
-wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
-</programlisting></blockquote>
-
-    <para><command>wpa_supplicant</command> can control multiple
-    interfaces (radios) either by running one process for each
-    interface separately or by running just one process and list of
-    options at command line. Each interface is separated with -N
-    argument. As an example, following command would start
-    wpa_supplicant for two interfaces:</para>
-
-<blockquote><programlisting>
-wpa_supplicant \
-	-c wpa1.conf -i wlan0 -D hostap -N \
-	-c wpa2.conf -i ath0 -D madwifi
-</programlisting></blockquote>
-  </refsect1>
-
-  <refsect1>
-    <title>OS Requirements</title>
-    <para>Current hardware/software requirements:</para>
-
-    <itemizedlist>
-      <listitem>
-	<para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
-	Extensions v15 or newer</para>
-      </listitem>
-
-
-      <listitem>
-	<para>FreeBSD 6-CURRENT</para>
-      </listitem>
-
-      <listitem>
-	<para>Microsoft Windows with WinPcap (at least WinXP, may work
-	with other versions)</para>
-      </listitem>
-    </itemizedlist>
-  </refsect1>
-
-  <refsect1>
-    <title>Supported Drivers</title>
-    <variablelist>
-      <varlistentry>
-	<term>Host AP driver for Prism2/2.5/3 (development
-	snapshot/v0.2.x)</term>
-	<listitem>
-	  <para> (http://hostap.epitest.fi/) Driver needs to be set in
-	  Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
-	  Please note that station firmware version needs to be 1.7.0 or
-	  newer to work in WPA mode.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Linuxant DriverLoader</term>
-	<listitem>
-	  <para>(http://www.linuxant.com/driverloader/)
-	with Windows NDIS driver for your wlan card supporting WPA.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Agere Systems Inc. Linux Driver</term>
-	<listitem>
-	  <para> (http://www.agere.com/support/drivers/) Please note
-	that the driver interface file (driver_hermes.c) and hardware
-	specific include files are not included in the wpa_supplicant
-	distribution. You will need to copy these from the source
-	package of the Agere driver.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
-	<listitem>
-	  <para> (http://sourceforge.net/projects/madwifi/) Please
-	note that you will need to modify the wpa_supplicant .config
-	file to use the correct path for the madwifi driver root
-	directory (CFLAGS += -I../madwifi/wpa line in example
-	defconfig).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>ATMEL AT76C5XXx driver for USB and PCMCIA cards</term>
-	<listitem>
-	  <para> (http://atmelwlandriver.sourceforge.net/).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Linux ndiswrapper</term>
-	<listitem>
-	  <para> (http://ndiswrapper.sourceforge.net/) with Windows
-	NDIS driver.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Broadcom wl.o driver</term>
-	<listitem>
-	  <para> This is a generic Linux driver for Broadcom IEEE
-	802.11a/g cards.  However, it is proprietary driver that is
-	not publicly available except for couple of exceptions, mainly
-	Broadcom-based APs/wireless routers that use Linux. The driver
-	binary can be downloaded, e.g., from Linksys support site
-	(http://www.linksys.com/support/gpl.asp) for Linksys
-	WRT54G. The GPL tarball includes cross-compiler and the needed
-	header file, wlioctl.h, for compiling wpa_supplicant.  This
-	driver support in wpa_supplicant is expected to work also with
-	other devices based on Broadcom driver (assuming the driver
-	includes client mode support).</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term> Intel ipw2100 driver</term>
-	<listitem>
-	  <para> (http://sourceforge.net/projects/ipw2100/)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Intel ipw2200 driver</term>
-	<listitem>
-	  <para> (http://sourceforge.net/projects/ipw2200/)</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Linux wireless extensions</term>
-	<listitem>
-	  <para>In theory, any driver that supports Linux wireless
-	extensions can be used with IEEE 802.1X (i.e., not WPA) when
-	using ap_scan=0 option in configuration file.</para>
-	</listitem>
-      </varlistentry>
-      
-      <varlistentry>
-	<term>Wired Ethernet drivers</term>
-	<listitem>
-	  <para>Use ap_scan=0.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>BSD net80211 layer (e.g., Atheros driver)</term>
-	<listitem>
-	  <para>At the moment, this is for FreeBSD 6-CURRENT branch.</para>
-	</listitem>
-      </varlistentry>
-
-      <varlistentry>
-	<term>Windows NDIS</term>
-	<listitem>
-	  <para>The current Windows port requires WinPcap
-	(http://winpcap.polito.it/).  See README-Windows.txt for more
-	information.</para>
-	</listitem>
-      </varlistentry>
-    </variablelist>
-
-	
-    <para>wpa_supplicant was designed to be portable for different
-    drivers and operating systems. Hopefully, support for more wlan
-    cards and OSes will be added in the future. See developer.txt for
-    more information about the design of wpa_supplicant and porting to
-    other drivers. One main goal is to add full WPA/WPA2 support to
-    Linux wireless extensions to allow new drivers to be supported
-    without having to implement new driver-specific interface code in
-    wpa_supplicant.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Architecture</title> <para>The
-    <command>wpa_supplicant</command> system consists of the following
-    components:</para>
-
-    <variablelist>
-      <varlistentry>
-	<term><filename>wpa_supplicant.conf</filename> </term>
-	<listitem>
-        <para>the configuration file describing all networks that the
-        user wants the computer to connect to.  </para>
-	</listitem>
-      </varlistentry>
-      <varlistentry>
-	<term><command>wpa_supplicant</command></term>
-        <listitem><para>the program that directly interacts with the
-        network interface.  </para></listitem>
-      </varlistentry>
-      <varlistentry>
-	<term><command>wpa_cli</command></term> <listitem><para> the
-	client program that provides a high-level interface to the
-	functionality of the daemon.  </para></listitem>
-      </varlistentry>
-      <varlistentry>
-	<term><command>wpa_passphrase</command></term>
-        <listitem><para>a utility needed to construct
-        <filename>wpa_supplicant.conf</filename> files that include
-        encrypted passwords.</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Quick Start</title>
-
-    <para>First, make a configuration file, e.g.
-    <filename>/etc/wpa_supplicant.conf</filename>, that describes the networks
-    you are interested in.  See <citerefentry>
-	<refentrytitle>wpa_supplicant.conf</refentrytitle>
-	<manvolnum>5</manvolnum>
-      </citerefentry>
-    for details.</para>
-
-    <para>Once the configuration is ready, you can test whether the
-    configuration works by running <command>wpa_supplicant</command>
-    with following command to start it on foreground with debugging
-    enabled:</para>
-
-    <blockquote><programlisting>
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
-    </programlisting></blockquote>
-
-    <para>Assuming everything goes fine, you can start using following
-    command to start <command>wpa_supplicant</command> on background
-    without debugging:</para>
-
-    <blockquote><programlisting>
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
-    </programlisting></blockquote>
-
-    <para>Please note that if you included more than one driver
-    interface in the build time configuration (.config), you may need
-    to specify which interface to use by including -D<driver
-    name> option on the command line.</para>
-
-    <!-- XXX at this point, the page could include a little script
-         based on wpa_cli to wait for a connection and then run
-         dhclient -->
-
-  </refsect1>
-
-  <refsect1>
-    <title>Interface to pcmcia-cs/cardmrg</title>
-
-    <para>For example, following small changes to pcmcia-cs scripts
-    can be used to enable WPA support:</para>
-
-    <para>Add MODE="Managed" and WPA="y" to the network scheme in
-    <filename>/etc/pcmcia/wireless.opts</filename>.</para>
-
-    <para>Add the following block to the end of <emphasis>start</emphasis>
-    action handler in <filename>/etc/pcmcia/wireless</filename>:</para>
-
-    <blockquote><programlisting>
-if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-    /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE
-fi
-    </programlisting></blockquote>
-
-
-    <para>Add the following block to the end of <emphasis>stop</emphasis>
-    action handler (may need to be separated from other actions) in
-    <filename>/etc/pcmcia/wireless</filename>:</para>
-
-    <blockquote><programlisting>
-if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-    killall wpa_supplicant
-fi
-    </programlisting></blockquote>
-
-    <para>This will make <command>cardmgr</command> start
-    <command>wpa_supplicant</command> when the card is plugged
-    in.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry>
-	<refentrytitle>wpa_background</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-      <citerefentry>
-	<refentrytitle>wpa_supplicant.conf</refentrytitle>
-	<manvolnum>5</manvolnum>
-      </citerefentry>
-      <citerefentry>
-	<refentrytitle>wpa_cli</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-      <citerefentry>
-	<refentrytitle>wpa_passphrase</refentrytitle>
-	<manvolnum>8</manvolnum>
-      </citerefentry>
-    </para>
-  </refsect1>
-  <refsect1>
-    <title>Legal</title>
-    <para>wpa_supplicant is copyright (c) 2003-2007,
-    Jouni Malinen <email>j at w1.fi</email> and
-    contributors.
-    All Rights Reserved.</para>
-
-    <para>This program is dual-licensed under both the GPL version 2
-    and BSD license. Either license may be used at your option.</para>
-  </refsect1>
-</refentry>

Copied: vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml (from rev 9639, vendor/wpa/dist/wpa_supplicant/doc/docbook/wpa_supplicant.sgml)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/doc/docbook/wpa_supplicant.sgml	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,690 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+  <refmeta>
+    <refentrytitle>wpa_supplicant</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>wpa_supplicant</refname>
+    <refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>wpa_supplicant</command>
+      <arg>-BddfhKLqqtuvW</arg>
+      <arg>-i<replaceable>ifname</replaceable></arg>
+      <arg>-c<replaceable>config file</replaceable></arg>
+      <arg>-D<replaceable>driver</replaceable></arg>
+      <arg>-P<replaceable>PID_file</replaceable></arg>
+      <arg>-f<replaceable>output file</replaceable></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>Overview</title>
+
+    <para>
+    Wireless networks do not require physical access to the network equipment
+    in the same way as wired networks. This makes it easier for unauthorized
+    users to passively monitor a network and capture all transmitted frames.
+    In addition, unauthorized use of the network is much easier. In many cases,
+    this can happen even without user's explicit knowledge since the wireless
+    LAN adapter may have been configured to automatically join any available
+    network.
+    </para>
+
+    <para>
+    Link-layer encryption can be used to provide a layer of security for
+    wireless networks. The original wireless LAN standard, IEEE 802.11,
+    included a simple encryption mechanism, WEP. However, that proved to
+    be flawed in many areas and network protected with WEP cannot be consider
+    secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
+    can be used to improve the network security, but even that has inherited
+    security issues due to the use of WEP for encryption. Wi-Fi Protected
+    Access and IEEE 802.11i amendment to the wireless LAN standard introduce
+    a much improvement mechanism for securing wireless networks. IEEE 802.11i
+    enabled networks that are using CCMP (encryption mechanism based on strong
+    cryptographic algorithm AES) can finally be called secure used for
+    applications which require efficient protection against unauthorized
+    access.
+    </para>
+
+    <para><command>wpa_supplicant</command> is an implementation of
+    the WPA Supplicant component, i.e., the part that runs in the
+    client stations. It implements WPA key negotiation with a WPA
+    Authenticator and EAP authentication with Authentication
+    Server. In addition, it controls the roaming and IEEE 802.11
+    authentication/association of the wireless LAN driver.</para>
+
+    <para><command>wpa_supplicant</command> is designed to be a
+    "daemon" program that runs in the background and acts as the
+    backend component controlling the wireless
+    connection. <command>wpa_supplicant</command> supports separate
+    frontend programs and an example text-based frontend,
+    <command>wpa_cli</command>, is included with
+    wpa_supplicant.</para>
+
+    <para>Before wpa_supplicant can do its work, the network interface
+    must be available.  That means that the physical device must be
+    present and enabled, and the driver for the device must be
+    loaded. The daemon will exit immediately if the device is not already
+    available.</para>
+
+    <para>After <command>wpa_supplicant</command> has configured the
+    network device, higher level configuration such as DHCP may
+    proceed.  There are a variety of ways to integrate wpa_supplicant
+    into a machine's networking scripts, a few of which are described
+    in sections below.</para>
+
+    <para>The following steps are used when associating with an AP
+    using WPA:</para>
+
+    <itemizedlist>
+      <listitem>
+	<para><command>wpa_supplicant</command> requests the kernel
+	driver to scan neighboring BSSes</para>
+      </listitem>
+
+      <listitem>
+	<para><command>wpa_supplicant</command> selects a BSS based on
+	its configuration</para>
+      </listitem>
+
+      <listitem>
+	<para><command>wpa_supplicant</command> requests the kernel
+        driver to associate with the chosen BSS</para>
+      </listitem>
+
+      <listitem>
+	<para>If WPA-EAP: integrated IEEE 802.1X Supplicant
+        completes EAP authentication with the
+        authentication server (proxied by the Authenticator in the
+        AP)</para>
+      </listitem>
+
+      <listitem>
+	<para>If WPA-EAP: master key is received from the IEEE 802.1X
+	Supplicant</para>
+      </listitem>
+
+      <listitem>
+	<para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK
+	as the master session key</para>
+      </listitem>
+
+      <listitem>
+	<para><command>wpa_supplicant</command> completes WPA 4-Way
+        Handshake and Group Key Handshake with the Authenticator
+        (AP)</para>
+      </listitem>
+
+      <listitem>
+	<para><command>wpa_supplicant</command> configures encryption
+	keys for unicast and broadcast</para>
+      </listitem>
+
+      <listitem>
+	<para>normal data packets can be transmitted and received</para>
+      </listitem>
+    </itemizedlist>
+  </refsect1>
+
+  <refsect1>
+    <title>Supported Features</title>
+    <para>Supported WPA/IEEE 802.11i features:</para>
+    <itemizedlist>
+      <listitem>
+	<para>WPA-PSK ("WPA-Personal")</para>
+      </listitem>
+
+      <listitem>
+	<para>WPA with EAP (e.g., with RADIUS authentication server)
+       ("WPA-Enterprise") Following authentication methods are
+       supported with an integrate IEEE 802.1X Supplicant:</para>
+
+	<itemizedlist>
+	  <listitem>
+	    <para>EAP-TLS</para>
+	  </listitem>
+	</itemizedlist>
+
+	<itemizedlist>
+	  <listitem>
+	    <para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para>
+	  </listitem>
+
+
+	  <listitem>
+	    <para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>EAP-TTLS/EAP-MD5-Challenge</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>EAP-TTLS/EAP-GTC</para>
+	  </listitem>
+
+          <listitem><para>EAP-TTLS/EAP-OTP</para></listitem>
+
+          <listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem>
+
+          <listitem><para>EAP-TTLS/EAP-TLS</para></listitem>
+
+          <listitem><para>EAP-TTLS/MSCHAPv2</para></listitem>
+
+          <listitem><para>EAP-TTLS/MSCHAP</para></listitem>
+
+          <listitem><para>EAP-TTLS/PAP</para></listitem>
+
+          <listitem><para>EAP-TTLS/CHAP</para></listitem>
+
+          <listitem><para>EAP-SIM</para></listitem>
+
+          <listitem><para>EAP-AKA</para></listitem>
+
+          <listitem><para>EAP-PSK</para></listitem>
+
+          <listitem><para>EAP-PAX</para></listitem>
+
+          <listitem><para>LEAP (note: requires special support from
+          the driver for IEEE 802.11 authentication)</para></listitem>
+
+          <listitem><para>(following methods are supported, but since
+          they do not generate keying material, they cannot be used
+          with WPA or IEEE 802.1X WEP keying)</para></listitem>
+
+          <listitem><para>EAP-MD5-Challenge </para></listitem>
+
+          <listitem><para>EAP-MSCHAPv2</para></listitem>
+
+          <listitem><para>EAP-GTC</para></listitem>
+
+          <listitem><para>EAP-OTP</para></listitem>
+	</itemizedlist>
+      </listitem>
+
+      <listitem>
+	<para>key management for CCMP, TKIP, WEP104, WEP40</para>
+      </listitem>
+
+      <listitem>
+	<para>RSN/WPA2 (IEEE 802.11i)</para>
+	<itemizedlist>
+	  <listitem>
+	    <para>pre-authentication</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>PMKSA caching</para>
+	  </listitem>
+	</itemizedlist>
+      </listitem>
+    </itemizedlist>
+  </refsect1>
+
+  <refsect1>
+    <title>Available Drivers</title>
+    <para>A summary of available driver backends is below. Support for each
+    of the driver backends is chosen at wpa_supplicant compile time. For a
+    list of supported driver backends that may be used with the -D option on
+    your system, refer to the help output of wpa_supplicant
+    (<emphasis>wpa_supplicant -h</emphasis>).</para>
+
+    <variablelist>
+      <varlistentry>
+	<term>wext</term>
+	<listitem>
+	  <para>Linux wireless extensions (generic).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>wired</term>
+	<listitem>
+	  <para>wpa_supplicant wired Ethernet driver</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>roboswitch</term>
+	<listitem>
+	  <para>wpa_supplicant Broadcom switch driver</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>bsd</term>
+	<listitem>
+	  <para>BSD 802.11 support (Atheros, etc.).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>ndis</term>
+	<listitem>
+	  <para>Windows NDIS driver.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Command Line Options</title>
+    <para>Most command line options have global scope. Some are given per
+    interface, and are only valid if at least one <option>-i</option> option
+    is specified, otherwise they're ignored. Option groups for different
+    interfaces must be separated by <option>-N</option> option.</para>
+    <variablelist>
+      <varlistentry>
+	<term>-b br_ifname</term>
+	<listitem>
+	  <para>Optional bridge interface name. (Per interface)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-B</term>
+	<listitem>
+	  <para>Run daemon in the background.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-c filename</term>
+	<listitem>
+	  <para>Path to configuration file. (Per interface)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-C ctrl_interface</term>
+	<listitem>
+	  <para>Path to ctrl_interface socket (Per interface. Only used if
+		  <option>-c</option> is not).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-i ifname</term>
+	<listitem>
+	  <para>Interface to listen on. Multiple instances of this option can
+	  be present, one per interface, separated by <option>-N</option>
+	  option (see below).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-d</term>
+	<listitem>
+	  <para>Increase debugging verbosity (<option>-dd</option> even
+		  more).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-D driver</term>
+	<listitem>
+	  <para>Driver to use (can be multiple drivers: nl80211,wext).
+		  (Per interface, see the available options below.)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-f output file</term>
+	<listitem>
+	  <para>Log output to specified file instead of stdout.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-g global ctrl_interface</term>
+	<listitem>
+	  <para>Path to global ctrl_interface socket. If specified, interface
+	  definitions may be omitted.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-K</term>
+	<listitem>
+	  <para>Include keys (passwords, etc.) in debug output.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-t</term>
+	<listitem>
+	  <para>Include timestamp in debug messages.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-h</term>
+	<listitem>
+	  <para>Help.  Show a usage message.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-L</term>
+	<listitem>
+	  <para>Show license (BSD).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-p</term>
+	<listitem>
+	  <para>Driver parameters. (Per interface)</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-P PID_file</term>
+	<listitem>
+	  <para>Path to PID file.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-q</term>
+	<listitem>
+	  <para>Decrease debugging verbosity (<option>-qq</option> even
+		  less).</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-u</term>
+	<listitem>
+	  <para>Enabled DBus control interface. If enabled, interface
+	  definitions may be omitted.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-v</term>
+	<listitem>
+	  <para>Show version.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-W</term>
+	<listitem>
+	  <para>Wait for a control interface monitor before starting.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>-N</term>
+	<listitem>
+	  <para>Start describing new interface.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Examples</title>
+
+    <para>In most common cases, <command>wpa_supplicant</command> is
+    started with:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
+    <para>This makes the process fork into background.</para>
+
+    <para>The easiest way to debug problems, and to get debug log for
+    bug reports, is to start <command>wpa_supplicant</command> on
+    foreground with debugging enabled:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+</programlisting></blockquote>
+
+    <para>If the specific driver wrapper is not known beforehand, it is
+    possible to specify multiple comma separated driver wrappers on the command
+    line. <command>wpa_supplicant</command> will use the first driver
+    wrapper that is able to initialize the interface.</para>
+
+<blockquote><programlisting>
+wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
+    <para><command>wpa_supplicant</command> can control multiple
+    interfaces (radios) either by running one process for each
+    interface separately or by running just one process and list of
+    options at command line. Each interface is separated with -N
+    argument. As an example, following command would start
+    wpa_supplicant for two interfaces:</para>
+
+<blockquote><programlisting>
+wpa_supplicant \
+	-c wpa1.conf -i wlan0 -D nl80211 -N \
+	-c wpa2.conf -i ath0 -D wext
+</programlisting></blockquote>
+  </refsect1>
+
+  <refsect1>
+    <title>OS Requirements</title>
+    <para>Current hardware/software requirements:</para>
+
+    <itemizedlist>
+      <listitem>
+	<para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
+	Extensions v15 or newer</para>
+      </listitem>
+
+
+      <listitem>
+	<para>FreeBSD 6-CURRENT</para>
+      </listitem>
+
+      <listitem>
+	<para>Microsoft Windows with WinPcap (at least WinXP, may work
+	with other versions)</para>
+      </listitem>
+    </itemizedlist>
+  </refsect1>
+
+  <refsect1>
+    <title>Supported Drivers</title>
+    <variablelist>
+      <varlistentry>
+	<term>Linux wireless extensions</term>
+	<listitem>
+	  <para>In theory, any driver that supports Linux wireless
+	extensions can be used with IEEE 802.1X (i.e., not WPA) when
+	using ap_scan=0 option in configuration file.</para>
+	</listitem>
+      </varlistentry>
+      
+      <varlistentry>
+	<term>Wired Ethernet drivers</term>
+	<listitem>
+	  <para>Use ap_scan=0.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>BSD net80211 layer (e.g., Atheros driver)</term>
+	<listitem>
+	  <para>At the moment, this is for FreeBSD 6-CURRENT branch.</para>
+	</listitem>
+      </varlistentry>
+
+      <varlistentry>
+	<term>Windows NDIS</term>
+	<listitem>
+	  <para>The current Windows port requires WinPcap
+	(http://winpcap.polito.it/).  See README-Windows.txt for more
+	information.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+
+	
+    <para>wpa_supplicant was designed to be portable for different
+    drivers and operating systems. Hopefully, support for more wlan
+    cards and OSes will be added in the future. See developer.txt for
+    more information about the design of wpa_supplicant and porting to
+    other drivers. One main goal is to add full WPA/WPA2 support to
+    Linux wireless extensions to allow new drivers to be supported
+    without having to implement new driver-specific interface code in
+    wpa_supplicant.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Architecture</title> <para>The
+    <command>wpa_supplicant</command> system consists of the following
+    components:</para>
+
+    <variablelist>
+      <varlistentry>
+	<term><filename>wpa_supplicant.conf</filename> </term>
+	<listitem>
+        <para>the configuration file describing all networks that the
+        user wants the computer to connect to.  </para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><command>wpa_supplicant</command></term>
+        <listitem><para>the program that directly interacts with the
+        network interface.  </para></listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><command>wpa_cli</command></term> <listitem><para> the
+	client program that provides a high-level interface to the
+	functionality of the daemon.  </para></listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><command>wpa_passphrase</command></term>
+        <listitem><para>a utility needed to construct
+        <filename>wpa_supplicant.conf</filename> files that include
+        encrypted passwords.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Quick Start</title>
+
+    <para>First, make a configuration file, e.g.
+    <filename>/etc/wpa_supplicant.conf</filename>, that describes the networks
+    you are interested in.  See <citerefentry>
+	<refentrytitle>wpa_supplicant.conf</refentrytitle>
+	<manvolnum>5</manvolnum>
+      </citerefentry>
+    for details.</para>
+
+    <para>Once the configuration is ready, you can test whether the
+    configuration works by running <command>wpa_supplicant</command>
+    with following command to start it on foreground with debugging
+    enabled:</para>
+
+    <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+    </programlisting></blockquote>
+
+    <para>Assuming everything goes fine, you can start using following
+    command to start <command>wpa_supplicant</command> on background
+    without debugging:</para>
+
+    <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+    </programlisting></blockquote>
+
+    <para>Please note that if you included more than one driver
+    interface in the build time configuration (.config), you may need
+    to specify which interface to use by including -D<driver
+    name> option on the command line.</para>
+
+    <!-- XXX at this point, the page could include a little script
+         based on wpa_cli to wait for a connection and then run
+         dhclient -->
+
+  </refsect1>
+
+  <refsect1>
+    <title>Interface to pcmcia-cs/cardmrg</title>
+
+    <para>For example, following small changes to pcmcia-cs scripts
+    can be used to enable WPA support:</para>
+
+    <para>Add MODE="Managed" and WPA="y" to the network scheme in
+    <filename>/etc/pcmcia/wireless.opts</filename>.</para>
+
+    <para>Add the following block to the end of <emphasis>start</emphasis>
+    action handler in <filename>/etc/pcmcia/wireless</filename>:</para>
+
+    <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+    /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf -i$DEVICE
+fi
+    </programlisting></blockquote>
+
+
+    <para>Add the following block to the end of <emphasis>stop</emphasis>
+    action handler (may need to be separated from other actions) in
+    <filename>/etc/pcmcia/wireless</filename>:</para>
+
+    <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+    killall wpa_supplicant
+fi
+    </programlisting></blockquote>
+
+    <para>This will make <command>cardmgr</command> start
+    <command>wpa_supplicant</command> when the card is plugged
+    in.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>See Also</title>
+    <para>
+      <citerefentry>
+	<refentrytitle>wpa_background</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+      <citerefentry>
+	<refentrytitle>wpa_supplicant.conf</refentrytitle>
+	<manvolnum>5</manvolnum>
+      </citerefentry>
+      <citerefentry>
+	<refentrytitle>wpa_cli</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+      <citerefentry>
+	<refentrytitle>wpa_passphrase</refentrytitle>
+	<manvolnum>8</manvolnum>
+      </citerefentry>
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>Legal</title>
+    <para>wpa_supplicant is copyright (c) 2003-2012,
+    Jouni Malinen <email>j at w1.fi</email> and
+    contributors.
+    All Rights Reserved.</para>
+
+    <para>This program is licensed under the BSD license (the one with
+    advertisement clause removed).</para>
+  </refsect1>
+</refentry>

Deleted: vendor/wpa/2.0/wpa_supplicant/driver_i.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/driver_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/driver_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,494 +0,0 @@
-/*
- * wpa_supplicant - Internal driver interface wrappers
- * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef DRIVER_I_H
-#define DRIVER_I_H
-
-#include "drivers/driver.h"
-
-/* driver_ops */
-static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
-				  const char *ifname)
-{
-	if (wpa_s->driver->init2)
-		return wpa_s->driver->init2(wpa_s, ifname,
-					    wpa_s->global_drv_priv);
-	if (wpa_s->driver->init) {
-		return wpa_s->driver->init(wpa_s, ifname);
-	}
-	return NULL;
-}
-
-static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->deinit)
-		wpa_s->driver->deinit(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s,
-				    const char *param)
-{
-	if (wpa_s->driver->set_param)
-		return wpa_s->driver->set_param(wpa_s->drv_priv, param);
-	return 0;
-}
-
-static inline int wpa_drv_set_countermeasures(struct wpa_supplicant *wpa_s,
-					      int enabled)
-{
-	if (wpa_s->driver->set_countermeasures) {
-		return wpa_s->driver->set_countermeasures(wpa_s->drv_priv,
-							  enabled);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_authenticate(struct wpa_supplicant *wpa_s,
-				       struct wpa_driver_auth_params *params)
-{
-	if (wpa_s->driver->authenticate)
-		return wpa_s->driver->authenticate(wpa_s->drv_priv, params);
-	return -1;
-}
-
-static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
-				    struct wpa_driver_associate_params *params)
-{
-	if (wpa_s->driver->associate) {
-		return wpa_s->driver->associate(wpa_s->drv_priv, params);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
-			       struct wpa_driver_scan_params *params)
-{
-	if (wpa_s->driver->scan2)
-		return wpa_s->driver->scan2(wpa_s->drv_priv, params);
-	return -1;
-}
-
-static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
-	struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->get_scan_results2)
-		return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
-	return NULL;
-}
-
-static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
-{
-	if (wpa_s->driver->get_bssid) {
-		return wpa_s->driver->get_bssid(wpa_s->drv_priv, bssid);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
-{
-	if (wpa_s->driver->get_ssid) {
-		return wpa_s->driver->get_ssid(wpa_s->drv_priv, ssid);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
-				  enum wpa_alg alg, const u8 *addr,
-				  int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
-{
-	if (wpa_s->driver->set_key) {
-		wpa_s->keys_cleared = 0;
-		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
-					      alg, addr, key_idx, set_tx,
-					      seq, seq_len, key, key_len);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
-					 const u8 *addr, int reason_code)
-{
-	if (wpa_s->driver->deauthenticate) {
-		return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
-						     reason_code);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
-				       const u8 *addr, int reason_code)
-{
-	if (wpa_s->driver->disassociate) {
-		return wpa_s->driver->disassociate(wpa_s->drv_priv, addr,
-						   reason_code);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
-				    const u8 *bssid, const u8 *pmkid)
-{
-	if (wpa_s->driver->add_pmkid) {
-		return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s,
-				       const u8 *bssid, const u8 *pmkid)
-{
-	if (wpa_s->driver->remove_pmkid) {
-		return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid,
-						   pmkid);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_flush_pmkid(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->flush_pmkid) {
-		return wpa_s->driver->flush_pmkid(wpa_s->drv_priv);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_get_capa(struct wpa_supplicant *wpa_s,
-				   struct wpa_driver_capa *capa)
-{
-	if (wpa_s->driver->get_capa) {
-		return wpa_s->driver->get_capa(wpa_s->drv_priv, capa);
-	}
-	return -1;
-}
-
-static inline void wpa_drv_poll(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->poll) {
-		wpa_s->driver->poll(wpa_s->drv_priv);
-	}
-}
-
-static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->get_ifname) {
-		return wpa_s->driver->get_ifname(wpa_s->drv_priv);
-	}
-	return NULL;
-}
-
-static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->get_mac_addr) {
-		return wpa_s->driver->get_mac_addr(wpa_s->drv_priv);
-	}
-	return NULL;
-}
-
-static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
-				     const u8 *dst, u16 proto,
-				     const u8 *data, size_t data_len)
-{
-	if (wpa_s->driver->send_eapol)
-		return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
-						 data, data_len);
-	return -1;
-}
-
-static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
-					int state)
-{
-	if (wpa_s->driver->set_operstate)
-		return wpa_s->driver->set_operstate(wpa_s->drv_priv, state);
-	return 0;
-}
-
-static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s,
-					     const u8 *addr, int protect_type,
-					     int key_type)
-{
-	if (wpa_s->driver->mlme_setprotection)
-		return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr,
-							 protect_type,
-							 key_type);
-	return 0;
-}
-
-static inline struct hostapd_hw_modes *
-wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
-			    u16 *flags)
-{
-	if (wpa_s->driver->get_hw_feature_data)
-		return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
-							  num_modes, flags);
-	return NULL;
-}
-
-static inline int wpa_drv_set_channel(struct wpa_supplicant *wpa_s,
-				      enum hostapd_hw_mode phymode, int chan,
-				      int freq)
-{
-	if (wpa_s->driver->set_channel)
-		return wpa_s->driver->set_channel(wpa_s->drv_priv, phymode,
-						  chan, freq);
-	return -1;
-}
-
-static inline int wpa_drv_set_ssid(struct wpa_supplicant *wpa_s,
-				   const u8 *ssid, size_t ssid_len)
-{
-	if (wpa_s->driver->set_ssid) {
-		return wpa_s->driver->set_ssid(wpa_s->drv_priv, ssid,
-					       ssid_len);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_set_bssid(struct wpa_supplicant *wpa_s,
-				    const u8 *bssid)
-{
-	if (wpa_s->driver->set_bssid) {
-		return wpa_s->driver->set_bssid(wpa_s->drv_priv, bssid);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
-				      const char *alpha2)
-{
-	if (wpa_s->driver->set_country)
-		return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2);
-	return 0;
-}
-
-static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
-				    const u8 *data, size_t data_len)
-{
-	if (wpa_s->driver->send_mlme)
-		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
-						data, data_len);
-	return -1;
-}
-
-static inline int wpa_drv_mlme_add_sta(struct wpa_supplicant *wpa_s,
-				       const u8 *addr, const u8 *supp_rates,
-				       size_t supp_rates_len)
-{
-	if (wpa_s->driver->mlme_add_sta)
-		return wpa_s->driver->mlme_add_sta(wpa_s->drv_priv, addr,
-						   supp_rates, supp_rates_len);
-	return -1;
-}
-
-static inline int wpa_drv_mlme_remove_sta(struct wpa_supplicant *wpa_s,
-					  const u8 *addr)
-{
-	if (wpa_s->driver->mlme_remove_sta)
-		return wpa_s->driver->mlme_remove_sta(wpa_s->drv_priv, addr);
-	return -1;
-}
-
-static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s,
-					const u8 *md,
-					const u8 *ies, size_t ies_len)
-{
-	if (wpa_s->driver->update_ft_ies)
-		return wpa_s->driver->update_ft_ies(wpa_s->drv_priv, md,
-						    ies, ies_len);
-	return -1;
-}
-
-static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
-					 u8 action, const u8 *target_ap,
-					 const u8 *ies, size_t ies_len)
-{
-	if (wpa_s->driver->send_ft_action)
-		return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
-						     target_ap, ies, ies_len);
-	return -1;
-}
-
-static inline int wpa_drv_set_beacon(struct wpa_supplicant *wpa_s,
-				     const u8 *head, size_t head_len,
-				     const u8 *tail, size_t tail_len,
-				     int dtim_period, int beacon_int)
-{
-	if (wpa_s->driver->set_beacon)
-		return wpa_s->driver->set_beacon(wpa_s->drv_priv, head,
-						 head_len, tail, tail_len,
-						 dtim_period, beacon_int);
-	return -1;
-}
-
-static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s,
-				  struct hostapd_sta_add_params *params)
-{
-	if (wpa_s->driver->sta_add)
-		return wpa_s->driver->sta_add(wpa_s->drv_priv, params);
-	return -1;
-}
-
-static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
-				     const u8 *addr)
-{
-	if (wpa_s->driver->sta_remove)
-		return wpa_s->driver->sta_remove(wpa_s->drv_priv, addr);
-	return -1;
-}
-
-static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
-					  const u8 *addr, const u8 *data,
-					  size_t data_len, int encrypt,
-					  const u8 *own_addr)
-{
-	if (wpa_s->driver->hapd_send_eapol)
-		return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
-						      data, data_len, encrypt,
-						      own_addr);
-	return -1;
-}
-
-static inline int wpa_drv_sta_set_flags(struct wpa_supplicant *wpa_s,
-					const u8 *addr, int total_flags,
-					int flags_or, int flags_and)
-{
-	if (wpa_s->driver->sta_set_flags)
-		return wpa_s->driver->sta_set_flags(wpa_s->drv_priv, addr,
-						    total_flags, flags_or,
-						    flags_and);
-	return -1;
-}
-
-static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
-					int authorized)
-{
-	if (wpa_s->driver->set_supp_port) {
-		return wpa_s->driver->set_supp_port(wpa_s->drv_priv,
-						    authorized);
-	}
-	return 0;
-}
-
-static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
-				      unsigned int freq,
-				      const u8 *dst, const u8 *src,
-				      const u8 *bssid,
-				      const u8 *data, size_t data_len)
-{
-	if (wpa_s->driver->send_action)
-		return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
-						  dst, src, bssid, data,
-						  data_len);
-	return -1;
-}
-
-static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
-				 enum wpa_driver_if_type type,
-				 const char *ifname, const u8 *addr,
-				 void *bss_ctx, char *force_ifname,
-				 u8 *if_addr)
-{
-	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);
-	return -1;
-}
-
-static inline int wpa_drv_if_remove(struct wpa_supplicant *wpa_s,
-				    enum wpa_driver_if_type type,
-				    const char *ifname)
-{
-	if (wpa_s->driver->if_remove)
-		return wpa_s->driver->if_remove(wpa_s->drv_priv, type, ifname);
-	return -1;
-}
-
-static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s,
-					    unsigned int freq,
-					    unsigned int duration)
-{
-	if (wpa_s->driver->remain_on_channel)
-		return wpa_s->driver->remain_on_channel(wpa_s->drv_priv, freq,
-							duration);
-	return -1;
-}
-
-static inline int wpa_drv_cancel_remain_on_channel(
-	struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->cancel_remain_on_channel)
-		return wpa_s->driver->cancel_remain_on_channel(
-			wpa_s->drv_priv);
-	return -1;
-}
-
-static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s,
-					   int report)
-{
-	if (wpa_s->driver->probe_req_report)
-		return wpa_s->driver->probe_req_report(wpa_s->drv_priv,
-						       report);
-	return -1;
-}
-
-static inline int wpa_drv_disable_11b_rates(struct wpa_supplicant *wpa_s,
-					    int disabled)
-{
-	if (wpa_s->driver->disable_11b_rates)
-		return wpa_s->driver->disable_11b_rates(wpa_s->drv_priv,
-							disabled);
-	return -1;
-}
-
-static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->deinit_ap)
-		return wpa_s->driver->deinit_ap(wpa_s->drv_priv);
-	return 0;
-}
-
-static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->suspend)
-		wpa_s->driver->suspend(wpa_s->drv_priv);
-}
-
-static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->driver->resume)
-		wpa_s->driver->resume(wpa_s->drv_priv);
-}
-
-static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
-					 int threshold, int hysteresis)
-{
-	if (wpa_s->driver->signal_monitor)
-		return wpa_s->driver->signal_monitor(wpa_s->drv_priv,
-						     threshold, hysteresis);
-	return -1;
-}
-
-static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s,
-					const struct wpabuf *beacon,
-					const struct wpabuf *proberesp)
-{
-	if (!wpa_s->driver->set_ap_wps_ie)
-		return -1;
-	return wpa_s->driver->set_ap_wps_ie(wpa_s->drv_priv, beacon,
-					    proberesp);
-}
-
-#endif /* DRIVER_I_H */

Copied: vendor/wpa/2.0/wpa_supplicant/driver_i.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/driver_i.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/driver_i.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/driver_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,692 @@
+/*
+ * wpa_supplicant - Internal driver interface wrappers
+ * Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_I_H
+#define DRIVER_I_H
+
+#include "drivers/driver.h"
+
+/* driver_ops */
+static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
+				  const char *ifname)
+{
+	if (wpa_s->driver->init2)
+		return wpa_s->driver->init2(wpa_s, ifname,
+					    wpa_s->global_drv_priv);
+	if (wpa_s->driver->init) {
+		return wpa_s->driver->init(wpa_s, ifname);
+	}
+	return NULL;
+}
+
+static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit)
+		wpa_s->driver->deinit(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s,
+				    const char *param)
+{
+	if (wpa_s->driver->set_param)
+		return wpa_s->driver->set_param(wpa_s->drv_priv, param);
+	return 0;
+}
+
+static inline int wpa_drv_set_countermeasures(struct wpa_supplicant *wpa_s,
+					      int enabled)
+{
+	if (wpa_s->driver->set_countermeasures) {
+		return wpa_s->driver->set_countermeasures(wpa_s->drv_priv,
+							  enabled);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_authenticate(struct wpa_supplicant *wpa_s,
+				       struct wpa_driver_auth_params *params)
+{
+	if (wpa_s->driver->authenticate)
+		return wpa_s->driver->authenticate(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_associate_params *params)
+{
+	if (wpa_s->driver->associate) {
+		return wpa_s->driver->associate(wpa_s->drv_priv, params);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
+			       struct wpa_driver_scan_params *params)
+{
+	if (wpa_s->driver->scan2)
+		return wpa_s->driver->scan2(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_driver_scan_params *params,
+				     u32 interval)
+{
+	if (wpa_s->driver->sched_scan)
+		return wpa_s->driver->sched_scan(wpa_s->drv_priv,
+						 params, interval);
+	return -1;
+}
+
+static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->stop_sched_scan)
+		return wpa_s->driver->stop_sched_scan(wpa_s->drv_priv);
+	return -1;
+}
+
+static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
+	struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_scan_results2)
+		return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+	return NULL;
+}
+
+static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
+{
+	if (wpa_s->driver->get_bssid) {
+		return wpa_s->driver->get_bssid(wpa_s->drv_priv, bssid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
+{
+	if (wpa_s->driver->get_ssid) {
+		return wpa_s->driver->get_ssid(wpa_s->drv_priv, ssid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
+				  enum wpa_alg alg, const u8 *addr,
+				  int key_idx, int set_tx,
+				   const u8 *seq, size_t seq_len,
+				   const u8 *key, size_t key_len)
+{
+	if (wpa_s->driver->set_key) {
+		wpa_s->keys_cleared = 0;
+		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
+					      alg, addr, key_idx, set_tx,
+					      seq, seq_len, key, key_len);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
+					 const u8 *addr, int reason_code)
+{
+	if (wpa_s->driver->deauthenticate) {
+		return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
+						     reason_code);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
+				    const u8 *bssid, const u8 *pmkid)
+{
+	if (wpa_s->driver->add_pmkid) {
+		return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s,
+				       const u8 *bssid, const u8 *pmkid)
+{
+	if (wpa_s->driver->remove_pmkid) {
+		return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid,
+						   pmkid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_flush_pmkid(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->flush_pmkid) {
+		return wpa_s->driver->flush_pmkid(wpa_s->drv_priv);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_get_capa(struct wpa_supplicant *wpa_s,
+				   struct wpa_driver_capa *capa)
+{
+	if (wpa_s->driver->get_capa) {
+		return wpa_s->driver->get_capa(wpa_s->drv_priv, capa);
+	}
+	return -1;
+}
+
+static inline void wpa_drv_poll(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->poll) {
+		wpa_s->driver->poll(wpa_s->drv_priv);
+	}
+}
+
+static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_ifname) {
+		return wpa_s->driver->get_ifname(wpa_s->drv_priv);
+	}
+	return NULL;
+}
+
+static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_mac_addr) {
+		return wpa_s->driver->get_mac_addr(wpa_s->drv_priv);
+	}
+	return NULL;
+}
+
+static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, u16 proto,
+				     const u8 *data, size_t data_len)
+{
+	if (wpa_s->driver->send_eapol)
+		return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
+						 data, data_len);
+	return -1;
+}
+
+static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
+					int state)
+{
+	if (wpa_s->driver->set_operstate)
+		return wpa_s->driver->set_operstate(wpa_s->drv_priv, state);
+	return 0;
+}
+
+static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s,
+					     const u8 *addr, int protect_type,
+					     int key_type)
+{
+	if (wpa_s->driver->mlme_setprotection)
+		return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr,
+							 protect_type,
+							 key_type);
+	return 0;
+}
+
+static inline struct hostapd_hw_modes *
+wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
+			    u16 *flags)
+{
+	if (wpa_s->driver->get_hw_feature_data)
+		return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
+							  num_modes, flags);
+	return NULL;
+}
+
+static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
+				      const char *alpha2)
+{
+	if (wpa_s->driver->set_country)
+		return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2);
+	return 0;
+}
+
+static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
+				    const u8 *data, size_t data_len, int noack)
+{
+	if (wpa_s->driver->send_mlme)
+		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
+						data, data_len, noack);
+	return -1;
+}
+
+static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s,
+					const u8 *md,
+					const u8 *ies, size_t ies_len)
+{
+	if (wpa_s->driver->update_ft_ies)
+		return wpa_s->driver->update_ft_ies(wpa_s->drv_priv, md,
+						    ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
+					 u8 action, const u8 *target_ap,
+					 const u8 *ies, size_t ies_len)
+{
+	if (wpa_s->driver->send_ft_action)
+		return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
+						     target_ap, ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
+				 struct wpa_driver_ap_params *params)
+{
+	if (wpa_s->driver->set_ap)
+		return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s,
+				  struct hostapd_sta_add_params *params)
+{
+	if (wpa_s->driver->sta_add)
+		return wpa_s->driver->sta_add(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
+				     const u8 *addr)
+{
+	if (wpa_s->driver->sta_remove)
+		return wpa_s->driver->sta_remove(wpa_s->drv_priv, addr);
+	return -1;
+}
+
+static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
+					  const u8 *addr, const u8 *data,
+					  size_t data_len, int encrypt,
+					  const u8 *own_addr, u32 flags)
+{
+	if (wpa_s->driver->hapd_send_eapol)
+		return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
+						      data, data_len, encrypt,
+						      own_addr, flags);
+	return -1;
+}
+
+static inline int wpa_drv_sta_set_flags(struct wpa_supplicant *wpa_s,
+					const u8 *addr, int total_flags,
+					int flags_or, int flags_and)
+{
+	if (wpa_s->driver->sta_set_flags)
+		return wpa_s->driver->sta_set_flags(wpa_s->drv_priv, addr,
+						    total_flags, flags_or,
+						    flags_and);
+	return -1;
+}
+
+static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
+					int authorized)
+{
+	if (wpa_s->driver->set_supp_port) {
+		return wpa_s->driver->set_supp_port(wpa_s->drv_priv,
+						    authorized);
+	}
+	return 0;
+}
+
+static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
+				      unsigned int freq,
+				      unsigned int wait,
+				      const u8 *dst, const u8 *src,
+				      const u8 *bssid,
+				      const u8 *data, size_t data_len,
+				      int no_cck)
+{
+	if (wpa_s->driver->send_action)
+		return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
+						  wait, dst, src, bssid,
+						  data, data_len, no_cck);
+	return -1;
+}
+
+static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->send_action_cancel_wait)
+		wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
+				   struct hostapd_freq_params *freq)
+{
+	if (wpa_s->driver->set_freq)
+		return wpa_s->driver->set_freq(wpa_s->drv_priv, freq);
+	return -1;
+}
+
+static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
+				 enum wpa_driver_if_type type,
+				 const char *ifname, const u8 *addr,
+				 void *bss_ctx, char *force_ifname,
+				 u8 *if_addr, const char *bridge)
+{
+	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);
+	return -1;
+}
+
+static inline int wpa_drv_if_remove(struct wpa_supplicant *wpa_s,
+				    enum wpa_driver_if_type type,
+				    const char *ifname)
+{
+	if (wpa_s->driver->if_remove)
+		return wpa_s->driver->if_remove(wpa_s->drv_priv, type, ifname);
+	return -1;
+}
+
+static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s,
+					    unsigned int freq,
+					    unsigned int duration)
+{
+	if (wpa_s->driver->remain_on_channel)
+		return wpa_s->driver->remain_on_channel(wpa_s->drv_priv, freq,
+							duration);
+	return -1;
+}
+
+static inline int wpa_drv_cancel_remain_on_channel(
+	struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->cancel_remain_on_channel)
+		return wpa_s->driver->cancel_remain_on_channel(
+			wpa_s->drv_priv);
+	return -1;
+}
+
+static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s,
+					   int report)
+{
+	if (wpa_s->driver->probe_req_report)
+		return wpa_s->driver->probe_req_report(wpa_s->drv_priv,
+						       report);
+	return -1;
+}
+
+static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit_ap)
+		return wpa_s->driver->deinit_ap(wpa_s->drv_priv);
+	return 0;
+}
+
+static inline int wpa_drv_deinit_p2p_cli(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit_p2p_cli)
+		return wpa_s->driver->deinit_p2p_cli(wpa_s->drv_priv);
+	return 0;
+}
+
+static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->suspend)
+		wpa_s->driver->suspend(wpa_s->drv_priv);
+}
+
+static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->resume)
+		wpa_s->driver->resume(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
+					 int threshold, int hysteresis)
+{
+	if (wpa_s->driver->signal_monitor)
+		return wpa_s->driver->signal_monitor(wpa_s->drv_priv,
+						     threshold, hysteresis);
+	return -1;
+}
+
+static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+				      struct wpa_signal_info *si)
+{
+	if (wpa_s->driver->signal_poll)
+		return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+	return -1;
+}
+
+static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
+				      struct hostap_sta_driver_data *sta)
+{
+	if (wpa_s->driver->read_sta_data)
+		return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta,
+						    wpa_s->bssid);
+	return -1;
+}
+
+static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s,
+					const struct wpabuf *beacon,
+					const struct wpabuf *proberesp,
+					const struct wpabuf *assocresp)
+{
+	if (!wpa_s->driver->set_ap_wps_ie)
+		return -1;
+	return wpa_s->driver->set_ap_wps_ie(wpa_s->drv_priv, beacon,
+					    proberesp, assocresp);
+}
+
+static inline int wpa_drv_shared_freq(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->shared_freq)
+		return -1;
+	return wpa_s->driver->shared_freq(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s,
+				  u8 *buf, size_t buf_len)
+{
+	if (!wpa_s->driver->get_noa)
+		return -1;
+	return wpa_s->driver->get_noa(wpa_s->drv_priv, buf, buf_len);
+}
+
+static inline int wpa_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s,
+					    int legacy_ps, int opp_ps,
+					    int ctwindow)
+{
+	if (!wpa_s->driver->set_p2p_powersave)
+		return -1;
+	return wpa_s->driver->set_p2p_powersave(wpa_s->drv_priv, legacy_ps,
+						opp_ps, ctwindow);
+}
+
+static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
+{
+	if (!wpa_s->driver->ampdu)
+		return -1;
+	return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
+}
+
+static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
+				   unsigned int timeout, int type)
+{
+	if (!wpa_s->driver->p2p_find)
+		return -1;
+	return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
+}
+
+static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_stop_find)
+		return -1;
+	return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
+				     unsigned int timeout)
+{
+	if (!wpa_s->driver->p2p_listen)
+		return -1;
+	return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
+}
+
+static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
+				      const u8 *peer_addr, int wps_method,
+				      int go_intent,
+				      const u8 *own_interface_addr,
+				      unsigned int force_freq,
+				      int persistent_group)
+{
+	if (!wpa_s->driver->p2p_connect)
+		return -1;
+	return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
+					  wps_method, go_intent,
+					  own_interface_addr, force_freq,
+					  persistent_group);
+}
+
+static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
+					 const u8 *peer_addr)
+{
+	if (!wpa_s->driver->wps_success_cb)
+		return -1;
+	return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
+}
+
+static inline int
+wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_group_formation_failed)
+		return -1;
+	return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
+					 const struct p2p_params *params)
+{
+	if (!wpa_s->driver->p2p_set_params)
+		return -1;
+	return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
+}
+
+static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
+					    const u8 *peer_addr,
+					    u16 config_methods, int join)
+{
+	if (!wpa_s->driver->p2p_prov_disc_req)
+		return -1;
+	return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
+						config_methods, join);
+}
+
+static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
+					 const u8 *dst,
+					 const struct wpabuf *tlvs)
+{
+	if (!wpa_s->driver->p2p_sd_request)
+		return 0;
+	return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
+}
+
+static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
+						u64 req)
+{
+	if (!wpa_s->driver->p2p_sd_cancel_request)
+		return -1;
+	return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
+}
+
+static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
+					  int freq, const u8 *dst,
+					  u8 dialog_token,
+					  const struct wpabuf *resp_tlvs)
+{
+	if (!wpa_s->driver->p2p_sd_response)
+		return -1;
+	return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
+					      dialog_token, resp_tlvs);
+}
+
+static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_service_update)
+		return -1;
+	return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
+				     const u8 *addr)
+{
+	if (!wpa_s->driver->p2p_reject)
+		return -1;
+	return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
+}
+
+static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
+				     const u8 *peer, int role, const u8 *bssid,
+				     const u8 *ssid, size_t ssid_len,
+				     const u8 *go_dev_addr,
+				     int persistent_group)
+{
+	if (!wpa_s->driver->p2p_invite)
+		return -1;
+	return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
+					 ssid, ssid_len, go_dev_addr,
+					 persistent_group);
+}
+
+static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
+					 const u8 *dst, u8 action_code,
+					 u8 dialog_token, u16 status_code,
+					 const u8 *buf, size_t len)
+{
+	if (wpa_s->driver->send_tdls_mgmt) {
+		return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
+						     action_code, dialog_token,
+						     status_code, buf, len);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
+				    enum tdls_oper oper, const u8 *peer)
+{
+	if (!wpa_s->driver->tdls_oper)
+		return -1;
+	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
+}
+
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+					  const u8 *kek, const u8 *kck,
+					  const u8 *replay_ctr)
+{
+	if (!wpa_s->driver->set_rekey_info)
+		return;
+	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+}
+
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+					int disabled)
+{
+	if (!wpa_s->driver->radio_disable)
+		return -1;
+	return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
+}
+
+static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
+					 unsigned int freq)
+{
+	if (!wpa_s->driver->switch_channel)
+		return -1;
+	return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+}
+
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+				   enum wnm_oper oper, const u8 *peer,
+				   u8 *buf, u16 *buf_len)
+{
+	if (!wpa_s->driver->wnm_oper)
+		return -1;
+	return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+				       buf_len);
+}
+
+#endif /* DRIVER_I_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/eap_register.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/eap_register.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/eap_register.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,235 +0,0 @@
-/*
- * EAP method registration
- * Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_peer/eap_methods.h"
-#include "eap_server/eap_methods.h"
-
-
-/**
- * eap_register_methods - Register statically linked EAP methods
- * Returns: 0 on success, -1 or -2 on failure
- *
- * This function is called at program initialization to register all EAP
- * methods that were linked in statically.
- */
-int eap_register_methods(void)
-{
-	int ret = 0;
-
-#ifdef EAP_MD5
-	if (ret == 0)
-		ret = eap_peer_md5_register();
-#endif /* EAP_MD5 */
-
-#ifdef EAP_TLS
-	if (ret == 0)
-		ret = eap_peer_tls_register();
-#endif /* EAP_TLS */
-
-#ifdef EAP_MSCHAPv2
-	if (ret == 0)
-		ret = eap_peer_mschapv2_register();
-#endif /* EAP_MSCHAPv2 */
-
-#ifdef EAP_PEAP
-	if (ret == 0)
-		ret = eap_peer_peap_register();
-#endif /* EAP_PEAP */
-
-#ifdef EAP_TTLS
-	if (ret == 0)
-		ret = eap_peer_ttls_register();
-#endif /* EAP_TTLS */
-
-#ifdef EAP_GTC
-	if (ret == 0)
-		ret = eap_peer_gtc_register();
-#endif /* EAP_GTC */
-
-#ifdef EAP_OTP
-	if (ret == 0)
-		ret = eap_peer_otp_register();
-#endif /* EAP_OTP */
-
-#ifdef EAP_SIM
-	if (ret == 0)
-		ret = eap_peer_sim_register();
-#endif /* EAP_SIM */
-
-#ifdef EAP_LEAP
-	if (ret == 0)
-		ret = eap_peer_leap_register();
-#endif /* EAP_LEAP */
-
-#ifdef EAP_PSK
-	if (ret == 0)
-		ret = eap_peer_psk_register();
-#endif /* EAP_PSK */
-
-#ifdef EAP_AKA
-	if (ret == 0)
-		ret = eap_peer_aka_register();
-#endif /* EAP_AKA */
-
-#ifdef EAP_AKA_PRIME
-	if (ret == 0)
-		ret = eap_peer_aka_prime_register();
-#endif /* EAP_AKA_PRIME */
-
-#ifdef EAP_FAST
-	if (ret == 0)
-		ret = eap_peer_fast_register();
-#endif /* EAP_FAST */
-
-#ifdef EAP_PAX
-	if (ret == 0)
-		ret = eap_peer_pax_register();
-#endif /* EAP_PAX */
-
-#ifdef EAP_SAKE
-	if (ret == 0)
-		ret = eap_peer_sake_register();
-#endif /* EAP_SAKE */
-
-#ifdef EAP_GPSK
-	if (ret == 0)
-		ret = eap_peer_gpsk_register();
-#endif /* EAP_GPSK */
-
-#ifdef EAP_WSC
-	if (ret == 0)
-		ret = eap_peer_wsc_register();
-#endif /* EAP_WSC */
-
-#ifdef EAP_IKEV2
-	if (ret == 0)
-		ret = eap_peer_ikev2_register();
-#endif /* EAP_IKEV2 */
-
-#ifdef EAP_VENDOR_TEST
-	if (ret == 0)
-		ret = eap_peer_vendor_test_register();
-#endif /* EAP_VENDOR_TEST */
-
-#ifdef EAP_TNC
-	if (ret == 0)
-		ret = eap_peer_tnc_register();
-#endif /* EAP_TNC */
-
-
-#ifdef EAP_SERVER_IDENTITY
-	if (ret == 0)
-		ret = eap_server_identity_register();
-#endif /* EAP_SERVER_IDENTITY */
-
-#ifdef EAP_SERVER_MD5
-	if (ret == 0)
-		ret = eap_server_md5_register();
-#endif /* EAP_SERVER_MD5 */
-
-#ifdef EAP_SERVER_TLS
-	if (ret == 0)
-		ret = eap_server_tls_register();
-#endif /* EAP_SERVER_TLS */
-
-#ifdef EAP_SERVER_MSCHAPV2
-	if (ret == 0)
-		ret = eap_server_mschapv2_register();
-#endif /* EAP_SERVER_MSCHAPV2 */
-
-#ifdef EAP_SERVER_PEAP
-	if (ret == 0)
-		ret = eap_server_peap_register();
-#endif /* EAP_SERVER_PEAP */
-
-#ifdef EAP_SERVER_TLV
-	if (ret == 0)
-		ret = eap_server_tlv_register();
-#endif /* EAP_SERVER_TLV */
-
-#ifdef EAP_SERVER_GTC
-	if (ret == 0)
-		ret = eap_server_gtc_register();
-#endif /* EAP_SERVER_GTC */
-
-#ifdef EAP_SERVER_TTLS
-	if (ret == 0)
-		ret = eap_server_ttls_register();
-#endif /* EAP_SERVER_TTLS */
-
-#ifdef EAP_SERVER_SIM
-	if (ret == 0)
-		ret = eap_server_sim_register();
-#endif /* EAP_SERVER_SIM */
-
-#ifdef EAP_SERVER_AKA
-	if (ret == 0)
-		ret = eap_server_aka_register();
-#endif /* EAP_SERVER_AKA */
-
-#ifdef EAP_SERVER_AKA_PRIME
-	if (ret == 0)
-		ret = eap_server_aka_prime_register();
-#endif /* EAP_SERVER_AKA_PRIME */
-
-#ifdef EAP_SERVER_PAX
-	if (ret == 0)
-		ret = eap_server_pax_register();
-#endif /* EAP_SERVER_PAX */
-
-#ifdef EAP_SERVER_PSK
-	if (ret == 0)
-		ret = eap_server_psk_register();
-#endif /* EAP_SERVER_PSK */
-
-#ifdef EAP_SERVER_SAKE
-	if (ret == 0)
-		ret = eap_server_sake_register();
-#endif /* EAP_SERVER_SAKE */
-
-#ifdef EAP_SERVER_GPSK
-	if (ret == 0)
-		ret = eap_server_gpsk_register();
-#endif /* EAP_SERVER_GPSK */
-
-#ifdef EAP_SERVER_VENDOR_TEST
-	if (ret == 0)
-		ret = eap_server_vendor_test_register();
-#endif /* EAP_SERVER_VENDOR_TEST */
-
-#ifdef EAP_SERVER_FAST
-	if (ret == 0)
-		ret = eap_server_fast_register();
-#endif /* EAP_SERVER_FAST */
-
-#ifdef EAP_SERVER_WSC
-	if (ret == 0)
-		ret = eap_server_wsc_register();
-#endif /* EAP_SERVER_WSC */
-
-#ifdef EAP_SERVER_IKEV2
-	if (ret == 0)
-		ret = eap_server_ikev2_register();
-#endif /* EAP_SERVER_IKEV2 */
-
-#ifdef EAP_SERVER_TNC
-	if (ret == 0)
-		ret = eap_server_tnc_register();
-#endif /* EAP_SERVER_TNC */
-
-	return ret;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/eap_register.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/eap_register.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/eap_register.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/eap_register.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,249 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j at 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 "eap_peer/eap_methods.h"
+#include "eap_server/eap_methods.h"
+#include "wpa_supplicant_i.h"
+
+
+/**
+ * eap_register_methods - Register statically linked EAP methods
+ * Returns: 0 on success, -1 or -2 on failure
+ *
+ * This function is called at program initialization to register all EAP
+ * methods that were linked in statically.
+ */
+int eap_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_MD5
+	if (ret == 0)
+		ret = eap_peer_md5_register();
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+	if (ret == 0)
+		ret = eap_peer_tls_register();
+#endif /* EAP_TLS */
+
+#ifdef EAP_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_peer_unauth_tls_register();
+#endif /* EAP_UNAUTH_TLS */
+
+#ifdef EAP_MSCHAPv2
+	if (ret == 0)
+		ret = eap_peer_mschapv2_register();
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+	if (ret == 0)
+		ret = eap_peer_peap_register();
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+	if (ret == 0)
+		ret = eap_peer_ttls_register();
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+	if (ret == 0)
+		ret = eap_peer_gtc_register();
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+	if (ret == 0)
+		ret = eap_peer_otp_register();
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+	if (ret == 0)
+		ret = eap_peer_sim_register();
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+	if (ret == 0)
+		ret = eap_peer_leap_register();
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+	if (ret == 0)
+		ret = eap_peer_psk_register();
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+	if (ret == 0)
+		ret = eap_peer_aka_register();
+#endif /* EAP_AKA */
+
+#ifdef EAP_AKA_PRIME
+	if (ret == 0)
+		ret = eap_peer_aka_prime_register();
+#endif /* EAP_AKA_PRIME */
+
+#ifdef EAP_FAST
+	if (ret == 0)
+		ret = eap_peer_fast_register();
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+	if (ret == 0)
+		ret = eap_peer_pax_register();
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+	if (ret == 0)
+		ret = eap_peer_sake_register();
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+	if (ret == 0)
+		ret = eap_peer_gpsk_register();
+#endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+	if (ret == 0)
+		ret = eap_peer_wsc_register();
+#endif /* EAP_WSC */
+
+#ifdef EAP_IKEV2
+	if (ret == 0)
+		ret = eap_peer_ikev2_register();
+#endif /* EAP_IKEV2 */
+
+#ifdef EAP_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_peer_vendor_test_register();
+#endif /* EAP_VENDOR_TEST */
+
+#ifdef EAP_TNC
+	if (ret == 0)
+		ret = eap_peer_tnc_register();
+#endif /* EAP_TNC */
+
+#ifdef EAP_PWD
+	if (ret == 0)
+		ret = eap_peer_pwd_register();
+#endif /* EAP_PWD */
+
+#ifdef EAP_SERVER_IDENTITY
+	if (ret == 0)
+		ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+	if (ret == 0)
+		ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+	if (ret == 0)
+		ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+	if (ret == 0)
+		ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+	if (ret == 0)
+		ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+	if (ret == 0)
+		ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+	if (ret == 0)
+		ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+	if (ret == 0)
+		ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+	if (ret == 0)
+		ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+	if (ret == 0)
+		ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (ret == 0)
+		ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+	if (ret == 0)
+		ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+	if (ret == 0)
+		ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+	if (ret == 0)
+		ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+	if (ret == 0)
+		ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+	if (ret == 0)
+		ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+	if (ret == 0)
+		ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+	if (ret == 0)
+		ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+	if (ret == 0)
+		ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+#ifdef EAP_SERVER_PWD
+	if (ret == 0)
+		ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/eapol_test.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/eapol_test.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/eapol_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1209 +0,0 @@
-/*
- * WPA Supplicant - test code
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
- * Not used in production version.
- */
-
-#include "includes.h"
-#include <assert.h>
-
-#include "common.h"
-#include "config.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "eap_peer/eap.h"
-#include "eloop.h"
-#include "rsn_supp/wpa.h"
-#include "eap_peer/eap_i.h"
-#include "wpa_supplicant_i.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "ctrl_iface.h"
-#include "pcsc_funcs.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
-struct wpa_driver_ops *wpa_drivers[] = { NULL };
-
-
-struct extra_radius_attr {
-	u8 type;
-	char syntax;
-	char *data;
-	struct extra_radius_attr *next;
-};
-
-struct eapol_test_data {
-	struct wpa_supplicant *wpa_s;
-
-	int eapol_test_num_reauths;
-	int no_mppe_keys;
-	int num_mppe_ok, num_mppe_mismatch;
-
-	u8 radius_identifier;
-	struct radius_msg *last_recv_radius;
-	struct in_addr own_ip_addr;
-	struct radius_client_data *radius;
-	struct hostapd_radius_servers *radius_conf;
-
-	u8 *last_eap_radius; /* last received EAP Response from Authentication
-			      * Server */
-	size_t last_eap_radius_len;
-
-	u8 authenticator_pmk[PMK_LEN];
-	size_t authenticator_pmk_len;
-	int radius_access_accept_received;
-	int radius_access_reject_received;
-	int auth_timed_out;
-
-	u8 *eap_identity;
-	size_t eap_identity_len;
-
-	char *connect_info;
-	u8 own_addr[ETH_ALEN];
-	struct extra_radius_attr *extra_attrs;
-};
-
-static struct eapol_test_data eapol_test;
-
-
-static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
-
-
-static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
-			      int level, const char *txt, size_t len)
-{
-	if (addr)
-		wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n",
-			   MAC2STR(addr), txt);
-	else
-		wpa_printf(MSG_DEBUG, "%s", txt);
-}
-
-
-static int add_extra_attr(struct radius_msg *msg,
-			  struct extra_radius_attr *attr)
-{
-	size_t len;
-	char *pos;
-	u32 val;
-	char buf[128];
-
-	switch (attr->syntax) {
-	case 's':
-		os_snprintf(buf, sizeof(buf), "%s", attr->data);
-		len = os_strlen(buf);
-		break;
-	case 'n':
-		buf[0] = '\0';
-		len = 1;
-		break;
-	case 'x':
-		pos = attr->data;
-		if (pos[0] == '0' && pos[1] == 'x')
-			pos += 2;
-		len = os_strlen(pos);
-		if ((len & 1) || (len / 2) > sizeof(buf)) {
-			printf("Invalid extra attribute hexstring\n");
-			return -1;
-		}
-		len /= 2;
-		if (hexstr2bin(pos, (u8 *) buf, len) < 0) {
-			printf("Invalid extra attribute hexstring\n");
-			return -1;
-		}
-		break;
-	case 'd':
-		val = htonl(atoi(attr->data));
-		os_memcpy(buf, &val, 4);
-		len = 4;
-		break;
-	default:
-		printf("Incorrect extra attribute syntax specification\n");
-		return -1;
-	}
-
-	if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) {
-		printf("Could not add attribute %d\n", attr->type);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int add_extra_attrs(struct radius_msg *msg,
-			   struct extra_radius_attr *attrs)
-{
-	struct extra_radius_attr *p;
-	for (p = attrs; p; p = p->next) {
-		if (add_extra_attr(msg, p) < 0)
-			return -1;
-	}
-	return 0;
-}
-
-
-static struct extra_radius_attr *
-find_extra_attr(struct extra_radius_attr *attrs, u8 type)
-{
-	struct extra_radius_attr *p;
-	for (p = attrs; p; p = p->next) {
-		if (p->type == type)
-			return p;
-	}
-	return NULL;
-}
-
-
-static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
-					  const u8 *eap, size_t len)
-{
-	struct radius_msg *msg;
-	char buf[128];
-	const struct eap_hdr *hdr;
-	const u8 *pos;
-
-	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
-		   "packet");
-
-	e->radius_identifier = radius_client_get_id(e->radius);
-	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
-			     e->radius_identifier);
-	if (msg == NULL) {
-		printf("Could not create net RADIUS packet\n");
-		return;
-	}
-
-	radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
-
-	hdr = (const struct eap_hdr *) eap;
-	pos = (const u8 *) (hdr + 1);
-	if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
-	    pos[0] == EAP_TYPE_IDENTITY) {
-		pos++;
-		os_free(e->eap_identity);
-		e->eap_identity_len = len - sizeof(*hdr) - 1;
-		e->eap_identity = os_malloc(e->eap_identity_len);
-		if (e->eap_identity) {
-			os_memcpy(e->eap_identity, pos, e->eap_identity_len);
-			wpa_hexdump(MSG_DEBUG, "Learned identity from "
-				    "EAP-Response-Identity",
-				    e->eap_identity, e->eap_identity_len);
-		}
-	}
-
-	if (e->eap_identity &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
-				 e->eap_identity, e->eap_identity_len)) {
-		printf("Could not add User-Name\n");
-		goto fail;
-	}
-
-	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
-				 (u8 *) &e->own_ip_addr, 4)) {
-		printf("Could not add NAS-IP-Address\n");
-		goto fail;
-	}
-
-	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
-		    MAC2STR(e->wpa_s->own_addr));
-	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID)
-	    &&
-	    !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Calling-Station-Id\n");
-		goto fail;
-	}
-
-	/* TODO: should probably check MTU from driver config; 2304 is max for
-	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
-	 */
-	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) &&
-	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
-		printf("Could not add Framed-MTU\n");
-		goto fail;
-	}
-
-	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) &&
-	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
-				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
-		printf("Could not add NAS-Port-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,
-				 (u8 *) buf, os_strlen(buf))) {
-		printf("Could not add Connect-Info\n");
-		goto fail;
-	}
-
-	if (add_extra_attrs(msg, e->extra_attrs) < 0)
-		goto fail;
-
-	if (eap && !radius_msg_add_eap(msg, eap, len)) {
-		printf("Could not add EAP-Message\n");
-		goto fail;
-	}
-
-	/* State attribute must be copied if and only if this packet is
-	 * Access-Request reply to the previous Access-Challenge */
-	if (e->last_recv_radius &&
-	    radius_msg_get_hdr(e->last_recv_radius)->code ==
-	    RADIUS_CODE_ACCESS_CHALLENGE) {
-		int res = radius_msg_copy_attr(msg, e->last_recv_radius,
-					       RADIUS_ATTR_STATE);
-		if (res < 0) {
-			printf("Could not copy State attribute from previous "
-			       "Access-Challenge\n");
-			goto fail;
-		}
-		if (res > 0) {
-			wpa_printf(MSG_DEBUG, "  Copied RADIUS State "
-				   "Attribute");
-		}
-	}
-
-	radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
-	return;
-
- fail:
-	radius_msg_free(msg);
-}
-
-
-static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
-				 size_t len)
-{
-	/* struct wpa_supplicant *wpa_s = ctx; */
-	printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
-	       type, (unsigned long) len);
-	if (type == IEEE802_1X_TYPE_EAP_PACKET) {
-		wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
-		ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
-	}
-	return 0;
-}
-
-
-static void eapol_test_set_config_blob(void *ctx,
-				       struct wpa_config_blob *blob)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_config_set_blob(wpa_s->conf, blob);
-}
-
-
-static const struct wpa_config_blob *
-eapol_test_get_config_blob(void *ctx, const char *name)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_config_get_blob(wpa_s->conf, name);
-}
-
-
-static void eapol_test_eapol_done_cb(void *ctx)
-{
-	printf("WPA: EAPOL processing complete\n");
-}
-
-
-static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eapol_test_data *e = eloop_ctx;
-	printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n");
-	e->radius_access_accept_received = 0;
-	send_eap_request_identity(e->wpa_s, NULL);
-}
-
-
-static int eapol_test_compare_pmk(struct eapol_test_data *e)
-{
-	u8 pmk[PMK_LEN];
-	int ret = 1;
-
-	if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
-		wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
-		if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) {
-			printf("WARNING: PMK mismatch\n");
-			wpa_hexdump(MSG_DEBUG, "PMK from AS",
-				    e->authenticator_pmk, PMK_LEN);
-		} else if (e->radius_access_accept_received)
-			ret = 0;
-	} else if (e->authenticator_pmk_len == 16 &&
-		   eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) {
-		wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16);
-		if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) {
-			printf("WARNING: PMK mismatch\n");
-			wpa_hexdump(MSG_DEBUG, "PMK from AS",
-				    e->authenticator_pmk, 16);
-		} else if (e->radius_access_accept_received)
-			ret = 0;
-	} else if (e->radius_access_accept_received && e->no_mppe_keys) {
-		/* No keying material expected */
-		ret = 0;
-	}
-
-	if (ret && !e->no_mppe_keys)
-		e->num_mppe_mismatch++;
-	else if (!e->no_mppe_keys)
-		e->num_mppe_ok++;
-
-	return ret;
-}
-
-
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
-{
-	struct eapol_test_data *e = ctx;
-	printf("eapol_sm_cb: success=%d\n", success);
-	e->eapol_test_num_reauths--;
-	if (e->eapol_test_num_reauths < 0)
-		eloop_terminate();
-	else {
-		eapol_test_compare_pmk(e);
-		eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL);
-	}
-}
-
-
-static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
-		      struct wpa_ssid *ssid)
-{
-	struct eapol_config eapol_conf;
-	struct eapol_ctx *ctx;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL) {
-		printf("Failed to allocate EAPOL context.\n");
-		return -1;
-	}
-	ctx->ctx = wpa_s;
-	ctx->msg_ctx = wpa_s;
-	ctx->scard_ctx = wpa_s->scard;
-	ctx->cb = eapol_sm_cb;
-	ctx->cb_ctx = e;
-	ctx->eapol_send_ctx = wpa_s;
-	ctx->preauth = 0;
-	ctx->eapol_done_cb = eapol_test_eapol_done_cb;
-	ctx->eapol_send = eapol_test_eapol_send;
-	ctx->set_config_blob = eapol_test_set_config_blob;
-	ctx->get_config_blob = eapol_test_get_config_blob;
-	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
-	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
-	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
-
-	wpa_s->eapol = eapol_sm_init(ctx);
-	if (wpa_s->eapol == NULL) {
-		os_free(ctx);
-		printf("Failed to initialize EAPOL state machines.\n");
-		return -1;
-	}
-
-	wpa_s->current_ssid = ssid;
-	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
-	eapol_conf.accept_802_1x_keys = 1;
-	eapol_conf.required_keys = 0;
-	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
-	eapol_conf.workaround = ssid->eap_workaround;
-	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
-
-
-	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
-	/* 802.1X::portControl = Auto */
-	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
-
-	return 0;
-}
-
-
-static void test_eapol_clean(struct eapol_test_data *e,
-			     struct wpa_supplicant *wpa_s)
-{
-	struct extra_radius_attr *p, *prev;
-
-	radius_client_deinit(e->radius);
-	os_free(e->last_eap_radius);
-	radius_msg_free(e->last_recv_radius);
-	e->last_recv_radius = NULL;
-	os_free(e->eap_identity);
-	e->eap_identity = NULL;
-	eapol_sm_deinit(wpa_s->eapol);
-	wpa_s->eapol = NULL;
-	if (e->radius_conf && e->radius_conf->auth_server) {
-		os_free(e->radius_conf->auth_server->shared_secret);
-		os_free(e->radius_conf->auth_server);
-	}
-	os_free(e->radius_conf);
-	e->radius_conf = NULL;
-	scard_deinit(wpa_s->scard);
-	if (wpa_s->ctrl_iface) {
-		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-		wpa_s->ctrl_iface = NULL;
-	}
-	wpa_config_free(wpa_s->conf);
-
-	p = e->extra_attrs;
-	while (p) {
-		prev = p;
-		p = p->next;
-		os_free(prev);
-	}
-}
-
-
-static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	u8 buf[100], *pos;
-	struct ieee802_1x_hdr *hdr;
-	struct eap_hdr *eap;
-
-	hdr = (struct ieee802_1x_hdr *) buf;
-	hdr->version = EAPOL_VERSION;
-	hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
-	hdr->length = htons(5);
-
-	eap = (struct eap_hdr *) (hdr + 1);
-	eap->code = EAP_CODE_REQUEST;
-	eap->identifier = 0;
-	eap->length = htons(5);
-	pos = (u8 *) (eap + 1);
-	*pos = EAP_TYPE_IDENTITY;
-
-	printf("Sending fake EAP-Request-Identity\n");
-	eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf,
-			  sizeof(*hdr) + 5);
-}
-
-
-static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct eapol_test_data *e = eloop_ctx;
-	printf("EAPOL test timed out\n");
-	e->auth_timed_out = 1;
-	eloop_terminate();
-}
-
-
-static char *eap_type_text(u8 type)
-{
-	switch (type) {
-	case EAP_TYPE_IDENTITY: return "Identity";
-	case EAP_TYPE_NOTIFICATION: return "Notification";
-	case EAP_TYPE_NAK: return "Nak";
-	case EAP_TYPE_TLS: return "TLS";
-	case EAP_TYPE_TTLS: return "TTLS";
-	case EAP_TYPE_PEAP: return "PEAP";
-	case EAP_TYPE_SIM: return "SIM";
-	case EAP_TYPE_GTC: return "GTC";
-	case EAP_TYPE_MD5: return "MD5";
-	case EAP_TYPE_OTP: return "OTP";
-	case EAP_TYPE_FAST: return "FAST";
-	case EAP_TYPE_SAKE: return "SAKE";
-	case EAP_TYPE_PSK: return "PSK";
-	default: return "Unknown";
-	}
-}
-
-
-static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
-{
-	u8 *eap;
-	size_t len;
-	struct eap_hdr *hdr;
-	int eap_type = -1;
-	char buf[64];
-	struct radius_msg *msg;
-
-	if (e->last_recv_radius == NULL)
-		return;
-
-	msg = e->last_recv_radius;
-
-	eap = radius_msg_get_eap(msg, &len);
-	if (eap == NULL) {
-		/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
-		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
-		 * attribute */
-		wpa_printf(MSG_DEBUG, "could not extract "
-			       "EAP-Message from RADIUS message");
-		os_free(e->last_eap_radius);
-		e->last_eap_radius = NULL;
-		e->last_eap_radius_len = 0;
-		return;
-	}
-
-	if (len < sizeof(*hdr)) {
-		wpa_printf(MSG_DEBUG, "too short EAP packet "
-			       "received from authentication server");
-		os_free(eap);
-		return;
-	}
-
-	if (len > sizeof(*hdr))
-		eap_type = eap[sizeof(*hdr)];
-
-	hdr = (struct eap_hdr *) eap;
-	switch (hdr->code) {
-	case EAP_CODE_REQUEST:
-		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
-			    eap_type >= 0 ? eap_type_text(eap_type) : "??",
-			    eap_type);
-		break;
-	case EAP_CODE_RESPONSE:
-		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
-			    eap_type >= 0 ? eap_type_text(eap_type) : "??",
-			    eap_type);
-		break;
-	case EAP_CODE_SUCCESS:
-		os_strlcpy(buf, "EAP Success", sizeof(buf));
-		/* LEAP uses EAP Success within an authentication, so must not
-		 * stop here with eloop_terminate(); */
-		break;
-	case EAP_CODE_FAILURE:
-		os_strlcpy(buf, "EAP Failure", sizeof(buf));
-		eloop_terminate();
-		break;
-	default:
-		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
-		wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
-		break;
-	}
-	wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
-		       "id=%d len=%d) from RADIUS server: %s",
-		      hdr->code, hdr->identifier, ntohs(hdr->length), buf);
-
-	/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
-
-	os_free(e->last_eap_radius);
-	e->last_eap_radius = eap;
-	e->last_eap_radius_len = len;
-
-	{
-		struct ieee802_1x_hdr *dot1x;
-		dot1x = os_malloc(sizeof(*dot1x) + len);
-		assert(dot1x != NULL);
-		dot1x->version = EAPOL_VERSION;
-		dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
-		dot1x->length = htons(len);
-		os_memcpy((u8 *) (dot1x + 1), eap, len);
-		eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
-				  (u8 *) dot1x, sizeof(*dot1x) + len);
-		os_free(dot1x);
-	}
-}
-
-
-static void ieee802_1x_get_keys(struct eapol_test_data *e,
-				struct radius_msg *msg, struct radius_msg *req,
-				const u8 *shared_secret,
-				size_t shared_secret_len)
-{
-	struct radius_ms_mppe_keys *keys;
-
-	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
-				      shared_secret_len);
-	if (keys && keys->send == NULL && keys->recv == NULL) {
-		os_free(keys);
-		keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
-						 shared_secret_len);
-	}
-
-	if (keys) {
-		if (keys->send) {
-			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)",
-				    keys->send, keys->send_len);
-		}
-		if (keys->recv) {
-			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
-				    keys->recv, keys->recv_len);
-			e->authenticator_pmk_len =
-				keys->recv_len > PMK_LEN ? PMK_LEN :
-				keys->recv_len;
-			os_memcpy(e->authenticator_pmk, keys->recv,
-				  e->authenticator_pmk_len);
-			if (e->authenticator_pmk_len == 16 && keys->send &&
-			    keys->send_len == 16) {
-				/* MS-CHAP-v2 derives 16 octet keys */
-				wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
-					   "to extend PMK to 32 octets");
-				os_memcpy(e->authenticator_pmk +
-					  e->authenticator_pmk_len,
-					  keys->send, keys->send_len);
-				e->authenticator_pmk_len += keys->send_len;
-			}
-		}
-
-		os_free(keys->send);
-		os_free(keys->recv);
-		os_free(keys);
-	}
-}
-
-
-/* Process the RADIUS frames from Authentication Server */
-static RadiusRxResult
-ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
-			const u8 *shared_secret, size_t shared_secret_len,
-			void *data)
-{
-	struct eapol_test_data *e = data;
-	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-
-	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
-	 * present when packet contains an EAP-Message attribute */
-	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
-	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
-				0) < 0 &&
-	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "Allowing RADIUS "
-			      "Access-Reject without Message-Authenticator "
-			      "since it does not include EAP-Message\n");
-	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
-				     req, 1)) {
-		printf("Incoming RADIUS packet did not have correct "
-		       "Message-Authenticator - dropped\n");
-		return RADIUS_RX_UNKNOWN;
-	}
-
-	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
-	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
-	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
-		printf("Unknown RADIUS message code\n");
-		return RADIUS_RX_UNKNOWN;
-	}
-
-	e->radius_identifier = -1;
-	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");
-
-	radius_msg_free(e->last_recv_radius);
-	e->last_recv_radius = msg;
-
-	switch (hdr->code) {
-	case RADIUS_CODE_ACCESS_ACCEPT:
-		e->radius_access_accept_received = 1;
-		ieee802_1x_get_keys(e, msg, req, shared_secret,
-				    shared_secret_len);
-		break;
-	case RADIUS_CODE_ACCESS_REJECT:
-		e->radius_access_reject_received = 1;
-		break;
-	}
-
-	ieee802_1x_decapsulate_radius(e);
-
-	if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
-	     e->eapol_test_num_reauths < 0) ||
-	    hdr->code == RADIUS_CODE_ACCESS_REJECT) {
-		eloop_terminate();
-	}
-
-	return RADIUS_RX_QUEUED;
-}
-
-
-static void wpa_init_conf(struct eapol_test_data *e,
-			  struct wpa_supplicant *wpa_s, const char *authsrv,
-			  int port, const char *secret,
-			  const char *cli_addr)
-{
-	struct hostapd_radius_server *as;
-	int res;
-
-	wpa_s->bssid[5] = 1;
-	os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN);
-	e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
-	os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
-
-	e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers));
-	assert(e->radius_conf != NULL);
-	e->radius_conf->num_auth_servers = 1;
-	as = os_zalloc(sizeof(struct hostapd_radius_server));
-	assert(as != NULL);
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
-	{
-		int a[4];
-		u8 *pos;
-		sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
-		pos = (u8 *) &as->addr.u.v4;
-		*pos++ = a[0];
-		*pos++ = a[1];
-		*pos++ = a[2];
-		*pos++ = a[3];
-	}
-#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	inet_aton(authsrv, &as->addr.u.v4);
-#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	as->addr.af = AF_INET;
-	as->port = port;
-	as->shared_secret = (u8 *) os_strdup(secret);
-	as->shared_secret_len = os_strlen(secret);
-	e->radius_conf->auth_server = as;
-	e->radius_conf->auth_servers = as;
-	e->radius_conf->msg_dumps = 1;
-	if (cli_addr) {
-		if (hostapd_parse_ip_addr(cli_addr,
-					  &e->radius_conf->client_addr) == 0)
-			e->radius_conf->force_client_addr = 1;
-		else {
-			wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
-				   cli_addr);
-			assert(0);
-		}
-	}
-
-	e->radius = radius_client_init(wpa_s, e->radius_conf);
-	assert(e->radius != NULL);
-
-	res = radius_client_register(e->radius, RADIUS_AUTH,
-				     ieee802_1x_receive_auth, e);
-	assert(res == 0);
-}
-
-
-static int scard_test(void)
-{
-	struct scard_data *scard;
-	size_t len;
-	char imsi[20];
-	unsigned char _rand[16];
-#ifdef PCSC_FUNCS
-	unsigned char sres[4];
-	unsigned char kc[8];
-#endif /* PCSC_FUNCS */
-#define num_triplets 5
-	unsigned char rand_[num_triplets][16];
-	unsigned char sres_[num_triplets][4];
-	unsigned char kc_[num_triplets][8];
-	int i, res;
-	size_t j;
-
-#define AKA_RAND_LEN 16
-#define AKA_AUTN_LEN 16
-#define AKA_AUTS_LEN 14
-#define RES_MAX_LEN 16
-#define IK_LEN 16
-#define CK_LEN 16
-	unsigned char aka_rand[AKA_RAND_LEN];
-	unsigned char aka_autn[AKA_AUTN_LEN];
-	unsigned char aka_auts[AKA_AUTS_LEN];
-	unsigned char aka_res[RES_MAX_LEN];
-	size_t aka_res_len;
-	unsigned char aka_ik[IK_LEN];
-	unsigned char aka_ck[CK_LEN];
-
-	scard = scard_init(SCARD_TRY_BOTH);
-	if (scard == NULL)
-		return -1;
-	if (scard_set_pin(scard, "1234")) {
-		wpa_printf(MSG_WARNING, "PIN validation failed");
-		scard_deinit(scard);
-		return -1;
-	}
-
-	len = sizeof(imsi);
-	if (scard_get_imsi(scard, imsi, &len))
-		goto failed;
-	wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len);
-	/* NOTE: Permanent Username: 1 | IMSI */
-
-	os_memset(_rand, 0, sizeof(_rand));
-	if (scard_gsm_auth(scard, _rand, sres, kc))
-		goto failed;
-
-	os_memset(_rand, 0xff, sizeof(_rand));
-	if (scard_gsm_auth(scard, _rand, sres, kc))
-		goto failed;
-
-	for (i = 0; i < num_triplets; i++) {
-		os_memset(rand_[i], i, sizeof(rand_[i]));
-		if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i]))
-			goto failed;
-	}
-
-	for (i = 0; i < num_triplets; i++) {
-		printf("1");
-		for (j = 0; j < len; j++)
-			printf("%c", imsi[j]);
-		printf(",");
-		for (j = 0; j < 16; j++)
-			printf("%02X", rand_[i][j]);
-		printf(",");
-		for (j = 0; j < 4; j++)
-			printf("%02X", sres_[i][j]);
-		printf(",");
-		for (j = 0; j < 8; j++)
-			printf("%02X", kc_[i][j]);
-		printf("\n");
-	}
-
-	wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication");
-
-	/* seq 39 (0x28) */
-	os_memset(aka_rand, 0xaa, 16);
-	os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf"
-		  "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16);
-
-	res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len,
-			      aka_ik, aka_ck, aka_auts);
-	if (res == 0) {
-		wpa_printf(MSG_DEBUG, "UMTS auth completed successfully");
-		wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len);
-		wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN);
-		wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN);
-	} else if (res == -2) {
-		wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization "
-			   "failure");
-		wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "UMTS auth failed");
-	}
-
-failed:
-	scard_deinit(scard);
-
-	return 0;
-#undef num_triplets
-}
-
-
-static int scard_get_triplets(int argc, char *argv[])
-{
-	struct scard_data *scard;
-	size_t len;
-	char imsi[20];
-	unsigned char _rand[16];
-	unsigned char sres[4];
-	unsigned char kc[8];
-	int num_triplets;
-	int i;
-	size_t j;
-
-	if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) {
-		printf("invalid parameters for sim command\n");
-		return -1;
-	}
-
-	if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) {
-		/* disable debug output */
-		wpa_debug_level = 99;
-	}
-
-	scard = scard_init(SCARD_GSM_SIM_ONLY);
-	if (scard == NULL) {
-		printf("Failed to open smartcard connection\n");
-		return -1;
-	}
-	if (scard_set_pin(scard, argv[0])) {
-		wpa_printf(MSG_WARNING, "PIN validation failed");
-		scard_deinit(scard);
-		return -1;
-	}
-
-	len = sizeof(imsi);
-	if (scard_get_imsi(scard, imsi, &len)) {
-		scard_deinit(scard);
-		return -1;
-	}
-
-	for (i = 0; i < num_triplets; i++) {
-		os_memset(_rand, i, sizeof(_rand));
-		if (scard_gsm_auth(scard, _rand, sres, kc))
-			break;
-
-		/* IMSI:Kc:SRES:RAND */
-		for (j = 0; j < len; j++)
-			printf("%c", imsi[j]);
-		printf(":");
-		for (j = 0; j < 8; j++)
-			printf("%02X", kc[j]);
-		printf(":");
-		for (j = 0; j < 4; j++)
-			printf("%02X", sres[j]);
-		printf(":");
-		for (j = 0; j < 16; j++)
-			printf("%02X", _rand[j]);
-		printf("\n");
-	}
-
-	scard_deinit(scard);
-
-	return 0;
-}
-
-
-static void eapol_test_terminate(int sig, void *signal_ctx)
-{
-	struct wpa_supplicant *wpa_s = signal_ctx;
-	wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig);
-	eloop_terminate();
-}
-
-
-static void usage(void)
-{
-	printf("usage:\n"
-	       "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
-	       "[-s<AS secret>]\\\n"
-	       "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
-	       "           [-M<client MAC address>] \\\n"
-	       "           [-N<attr spec>] \\\n"
-	       "           [-A<client IP>]\n"
-	       "eapol_test scard\n"
-	       "eapol_test sim <PIN> <num triplets> [debug]\n"
-	       "\n");
-	printf("options:\n"
-	       "  -c<conf> = configuration file\n"
-	       "  -a<AS IP> = IP address of the authentication server, "
-	       "default 127.0.0.1\n"
-	       "  -p<AS port> = UDP port of the authentication server, "
-	       "default 1812\n"
-	       "  -s<AS secret> = shared secret with the authentication "
-	       "server, default 'radius'\n"
-	       "  -A<client IP> = IP address of the client, default: select "
-	       "automatically\n"
-	       "  -r<count> = number of re-authentications\n"
-	       "  -W = wait for a control interface monitor before starting\n"
-	       "  -S = save configuration after authentication\n"
-	       "  -n = no MPPE keys expected\n"
-	       "  -t<timeout> = sets timeout in seconds (default: 30 s)\n"
-	       "  -C<Connect-Info> = RADIUS Connect-Info (default: "
-	       "CONNECT 11Mbps 802.11b)\n"
-	       "  -M<client MAC address> = Set own MAC address "
-	       "(Calling-Station-Id,\n"
-	       "                           default: 02:00:00:00:00:01)\n"
-	       "  -N<attr spec> = send arbitrary attribute specified by:\n"
-	       "                  attr_id:syntax:value or attr_id\n"
-	       "                  attr_id - number id of the attribute\n"
-	       "                  syntax - one of: s, d, x\n"
-	       "                     s = string\n"
-	       "                     d = integer\n"
-	       "                     x = octet string\n"
-	       "                  value - attribute value.\n"
-	       "       When only attr_id is specified, NULL will be used as "
-	       "value.\n"
-	       "       Multiple attributes can be specified by using the "
-	       "option several times.\n");
-}
-
-
-int main(int argc, char *argv[])
-{
-	struct wpa_supplicant wpa_s;
-	int c, ret = 1, wait_for_monitor = 0, save_config = 0;
-	char *as_addr = "127.0.0.1";
-	int as_port = 1812;
-	char *as_secret = "radius";
-	char *cli_addr = NULL;
-	char *conf = NULL;
-	int timeout = 30;
-	char *pos;
-	struct extra_radius_attr *p = NULL, *p1;
-
-	if (os_program_init())
-		return -1;
-
-	hostapd_logger_register_cb(hostapd_logger_cb);
-
-	os_memset(&eapol_test, 0, sizeof(eapol_test));
-	eapol_test.connect_info = "CONNECT 11Mbps 802.11b";
-	os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN);
-
-	wpa_debug_level = 0;
-	wpa_debug_show_keys = 1;
-
-	for (;;) {
-		c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'a':
-			as_addr = optarg;
-			break;
-		case 'A':
-			cli_addr = optarg;
-			break;
-		case 'c':
-			conf = optarg;
-			break;
-		case 'C':
-			eapol_test.connect_info = optarg;
-			break;
-		case 'M':
-			if (hwaddr_aton(optarg, eapol_test.own_addr)) {
-				usage();
-				return -1;
-			}
-			break;
-		case 'n':
-			eapol_test.no_mppe_keys++;
-			break;
-		case 'p':
-			as_port = atoi(optarg);
-			break;
-		case 'r':
-			eapol_test.eapol_test_num_reauths = atoi(optarg);
-			break;
-		case 's':
-			as_secret = optarg;
-			break;
-		case 'S':
-			save_config++;
-			break;
-		case 't':
-			timeout = atoi(optarg);
-			break;
-		case 'W':
-			wait_for_monitor++;
-			break;
-		case 'N':
-			p1 = os_zalloc(sizeof(p1));
-			if (p1 == NULL)
-				break;
-			if (!p)
-				eapol_test.extra_attrs = p1;
-			else
-				p->next = p1;
-			p = p1;
-
-			p->type = atoi(optarg);
-			pos = os_strchr(optarg, ':');
-			if (pos == NULL) {
-				p->syntax = 'n';
-				p->data = NULL;
-				break;
-			}
-
-			pos++;
-			if (pos[0] == '\0' || pos[1] != ':') {
-				printf("Incorrect format of attribute "
-				       "specification\n");
-				break;
-			}
-
-			p->syntax = pos[0];
-			p->data = pos + 2;
-			break;
-		default:
-			usage();
-			return -1;
-		}
-	}
-
-	if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
-		return scard_test();
-	}
-
-	if (argc > optind && os_strcmp(argv[optind], "sim") == 0) {
-		return scard_get_triplets(argc - optind - 1,
-					  &argv[optind + 1]);
-	}
-
-	if (conf == NULL) {
-		usage();
-		printf("Configuration file is required.\n");
-		return -1;
-	}
-
-	if (eap_register_methods()) {
-		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
-		return -1;
-	}
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		return -1;
-	}
-
-	os_memset(&wpa_s, 0, sizeof(wpa_s));
-	eapol_test.wpa_s = &wpa_s;
-	wpa_s.conf = wpa_config_read(conf);
-	if (wpa_s.conf == NULL) {
-		printf("Failed to parse configuration file '%s'.\n", conf);
-		return -1;
-	}
-	if (wpa_s.conf->ssid == NULL) {
-		printf("No networks defined.\n");
-		return -1;
-	}
-
-	wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
-		      cli_addr);
-	wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
-	if (wpa_s.ctrl_iface == NULL) {
-		printf("Failed to initialize control interface '%s'.\n"
-		       "You may have another eapol_test process already "
-		       "running or the file was\n"
-		       "left by an unclean termination of eapol_test in "
-		       "which case you will need\n"
-		       "to manually remove this file before starting "
-		       "eapol_test again.\n",
-		       wpa_s.conf->ctrl_interface);
-		return -1;
-	}
-	if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
-		return -1;
-
-	if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
-		return -1;
-
-	if (wait_for_monitor)
-		wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
-
-	eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test,
-			       NULL);
-	eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL);
-	eloop_register_signal_terminate(eapol_test_terminate, &wpa_s);
-	eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s);
-	eloop_run();
-
-	eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL);
-	eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL);
-
-	if (eapol_test_compare_pmk(&eapol_test) == 0 ||
-	    eapol_test.no_mppe_keys)
-		ret = 0;
-	if (eapol_test.auth_timed_out)
-		ret = -2;
-	if (eapol_test.radius_access_reject_received)
-		ret = -3;
-
-	if (save_config)
-		wpa_config_write(conf, wpa_s.conf);
-
-	test_eapol_clean(&eapol_test, &wpa_s);
-
-	eap_peer_unregister_methods();
-
-	eloop_destroy();
-
-	printf("MPPE keys OK: %d  mismatch: %d\n",
-	       eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
-	if (eapol_test.num_mppe_mismatch)
-		ret = -4;
-	if (ret)
-		printf("FAILURE\n");
-	else
-		printf("SUCCESS\n");
-
-	os_program_deinit();
-
-	return ret;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/eapol_test.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/eapol_test.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/eapol_test.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/eapol_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1317 @@
+/*
+ * WPA Supplicant - test code
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
+ * Not used in production version.
+ */
+
+#include "includes.h"
+#include <assert.h>
+
+#include "common.h"
+#include "utils/ext_password.h"
+#include "config.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
+#include "eap_server/eap_methods.h"
+#include "eloop.h"
+#include "utils/base64.h"
+#include "rsn_supp/wpa.h"
+#include "eap_peer/eap_i.h"
+#include "wpa_supplicant_i.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "common/wpa_ctrl.h"
+#include "ctrl_iface.h"
+#include "pcsc_funcs.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+
+struct wpa_driver_ops *wpa_drivers[] = { NULL };
+
+
+struct extra_radius_attr {
+	u8 type;
+	char syntax;
+	char *data;
+	struct extra_radius_attr *next;
+};
+
+struct eapol_test_data {
+	struct wpa_supplicant *wpa_s;
+
+	int eapol_test_num_reauths;
+	int no_mppe_keys;
+	int num_mppe_ok, num_mppe_mismatch;
+
+	u8 radius_identifier;
+	struct radius_msg *last_recv_radius;
+	struct in_addr own_ip_addr;
+	struct radius_client_data *radius;
+	struct hostapd_radius_servers *radius_conf;
+
+	 /* last received EAP Response from Authentication Server */
+	struct wpabuf *last_eap_radius;
+
+	u8 authenticator_pmk[PMK_LEN];
+	size_t authenticator_pmk_len;
+	int radius_access_accept_received;
+	int radius_access_reject_received;
+	int auth_timed_out;
+
+	u8 *eap_identity;
+	size_t eap_identity_len;
+
+	char *connect_info;
+	u8 own_addr[ETH_ALEN];
+	struct extra_radius_attr *extra_attrs;
+
+	FILE *server_cert_file;
+};
+
+static struct eapol_test_data eapol_test;
+
+
+static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
+
+
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+			      int level, const char *txt, size_t len)
+{
+	if (addr)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR ": %s\n",
+			   MAC2STR(addr), txt);
+	else
+		wpa_printf(MSG_DEBUG, "%s", txt);
+}
+
+
+static int add_extra_attr(struct radius_msg *msg,
+			  struct extra_radius_attr *attr)
+{
+	size_t len;
+	char *pos;
+	u32 val;
+	char buf[RADIUS_MAX_ATTR_LEN + 1];
+
+	switch (attr->syntax) {
+	case 's':
+		os_snprintf(buf, sizeof(buf), "%s", attr->data);
+		len = os_strlen(buf);
+		break;
+	case 'n':
+		buf[0] = '\0';
+		len = 1;
+		break;
+	case 'x':
+		pos = attr->data;
+		if (pos[0] == '0' && pos[1] == 'x')
+			pos += 2;
+		len = os_strlen(pos);
+		if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) {
+			printf("Invalid extra attribute hexstring\n");
+			return -1;
+		}
+		len /= 2;
+		if (hexstr2bin(pos, (u8 *) buf, len) < 0) {
+			printf("Invalid extra attribute hexstring\n");
+			return -1;
+		}
+		break;
+	case 'd':
+		val = htonl(atoi(attr->data));
+		os_memcpy(buf, &val, 4);
+		len = 4;
+		break;
+	default:
+		printf("Incorrect extra attribute syntax specification\n");
+		return -1;
+	}
+
+	if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) {
+		printf("Could not add attribute %d\n", attr->type);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int add_extra_attrs(struct radius_msg *msg,
+			   struct extra_radius_attr *attrs)
+{
+	struct extra_radius_attr *p;
+	for (p = attrs; p; p = p->next) {
+		if (add_extra_attr(msg, p) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+
+static struct extra_radius_attr *
+find_extra_attr(struct extra_radius_attr *attrs, u8 type)
+{
+	struct extra_radius_attr *p;
+	for (p = attrs; p; p = p->next) {
+		if (p->type == type)
+			return p;
+	}
+	return NULL;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
+					  const u8 *eap, size_t len)
+{
+	struct radius_msg *msg;
+	char buf[RADIUS_MAX_ATTR_LEN + 1];
+	const struct eap_hdr *hdr;
+	const u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
+		   "packet");
+
+	e->radius_identifier = radius_client_get_id(e->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+			     e->radius_identifier);
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return;
+	}
+
+	radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
+
+	hdr = (const struct eap_hdr *) eap;
+	pos = (const u8 *) (hdr + 1);
+	if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
+	    pos[0] == EAP_TYPE_IDENTITY) {
+		pos++;
+		os_free(e->eap_identity);
+		e->eap_identity_len = len - sizeof(*hdr) - 1;
+		e->eap_identity = os_malloc(e->eap_identity_len);
+		if (e->eap_identity) {
+			os_memcpy(e->eap_identity, pos, e->eap_identity_len);
+			wpa_hexdump(MSG_DEBUG, "Learned identity from "
+				    "EAP-Response-Identity",
+				    e->eap_identity, e->eap_identity_len);
+		}
+	}
+
+	if (e->eap_identity &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+				 e->eap_identity, e->eap_identity_len)) {
+		printf("Could not add User-Name\n");
+		goto fail;
+	}
+
+	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				 (u8 *) &e->own_ip_addr, 4)) {
+		printf("Could not add NAS-IP-Address\n");
+		goto fail;
+	}
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(e->wpa_s->own_addr));
+	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID)
+	    &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		printf("Could not add Calling-Station-Id\n");
+		goto fail;
+	}
+
+	/* TODO: should probably check MTU from driver config; 2304 is max for
+	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
+	 */
+	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+		printf("Could not add Framed-MTU\n");
+		goto fail;
+	}
+
+	if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+		printf("Could not add NAS-Port-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,
+				 (u8 *) buf, os_strlen(buf))) {
+		printf("Could not add Connect-Info\n");
+		goto fail;
+	}
+
+	if (add_extra_attrs(msg, e->extra_attrs) < 0)
+		goto fail;
+
+	if (eap && !radius_msg_add_eap(msg, eap, len)) {
+		printf("Could not add EAP-Message\n");
+		goto fail;
+	}
+
+	/* State attribute must be copied if and only if this packet is
+	 * Access-Request reply to the previous Access-Challenge */
+	if (e->last_recv_radius &&
+	    radius_msg_get_hdr(e->last_recv_radius)->code ==
+	    RADIUS_CODE_ACCESS_CHALLENGE) {
+		int res = radius_msg_copy_attr(msg, e->last_recv_radius,
+					       RADIUS_ATTR_STATE);
+		if (res < 0) {
+			printf("Could not copy State attribute from previous "
+			       "Access-Challenge\n");
+			goto fail;
+		}
+		if (res > 0) {
+			wpa_printf(MSG_DEBUG, "  Copied RADIUS State "
+				   "Attribute");
+		}
+	}
+
+	if (radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr)
+	    < 0)
+		goto fail;
+	return;
+
+ fail:
+	radius_msg_free(msg);
+}
+
+
+static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
+				 size_t len)
+{
+	printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
+	       type, (unsigned long) len);
+	if (type == IEEE802_1X_TYPE_EAP_PACKET) {
+		wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
+		ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
+	}
+	return 0;
+}
+
+
+static void eapol_test_set_config_blob(void *ctx,
+				       struct wpa_config_blob *blob)
+{
+	struct eapol_test_data *e = ctx;
+	wpa_config_set_blob(e->wpa_s->conf, blob);
+}
+
+
+static const struct wpa_config_blob *
+eapol_test_get_config_blob(void *ctx, const char *name)
+{
+	struct eapol_test_data *e = ctx;
+	return wpa_config_get_blob(e->wpa_s->conf, name);
+}
+
+
+static void eapol_test_eapol_done_cb(void *ctx)
+{
+	printf("WPA: EAPOL processing complete\n");
+}
+
+
+static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_test_data *e = eloop_ctx;
+	printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n");
+	e->radius_access_accept_received = 0;
+	send_eap_request_identity(e->wpa_s, NULL);
+}
+
+
+static int eapol_test_compare_pmk(struct eapol_test_data *e)
+{
+	u8 pmk[PMK_LEN];
+	int ret = 1;
+
+	if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
+		wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
+		if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) {
+			printf("WARNING: PMK mismatch\n");
+			wpa_hexdump(MSG_DEBUG, "PMK from AS",
+				    e->authenticator_pmk, PMK_LEN);
+		} else if (e->radius_access_accept_received)
+			ret = 0;
+	} else if (e->authenticator_pmk_len == 16 &&
+		   eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) {
+		wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16);
+		if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) {
+			printf("WARNING: PMK mismatch\n");
+			wpa_hexdump(MSG_DEBUG, "PMK from AS",
+				    e->authenticator_pmk, 16);
+		} else if (e->radius_access_accept_received)
+			ret = 0;
+	} else if (e->radius_access_accept_received && e->no_mppe_keys) {
+		/* No keying material expected */
+		ret = 0;
+	}
+
+	if (ret && !e->no_mppe_keys)
+		e->num_mppe_mismatch++;
+	else if (!e->no_mppe_keys)
+		e->num_mppe_ok++;
+
+	return ret;
+}
+
+
+static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+{
+	struct eapol_test_data *e = ctx;
+	printf("eapol_sm_cb: success=%d\n", success);
+	e->eapol_test_num_reauths--;
+	if (e->eapol_test_num_reauths < 0)
+		eloop_terminate();
+	else {
+		eapol_test_compare_pmk(e);
+		eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL);
+	}
+}
+
+
+static void eapol_test_write_cert(FILE *f, const char *subject,
+				  const struct wpabuf *cert)
+{
+	unsigned char *encoded;
+
+	encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
+	if (encoded == NULL)
+		return;
+	fprintf(f, "%s\n-----BEGIN CERTIFICATE-----\n%s"
+		"-----END CERTIFICATE-----\n\n", subject, encoded);
+	os_free(encoded);
+}
+
+
+static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+			       const char *cert_hash,
+			       const struct wpabuf *cert)
+{
+	struct eapol_test_data *e = ctx;
+
+	wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+		"depth=%d subject='%s'%s%s",
+		depth, subject,
+		cert_hash ? " hash=" : "",
+		cert_hash ? cert_hash : "");
+
+	if (cert) {
+		char *cert_hex;
+		size_t len = wpabuf_len(cert) * 2 + 1;
+		cert_hex = os_malloc(len);
+		if (cert_hex) {
+			wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
+					 wpabuf_len(cert));
+			wpa_msg_ctrl(e->wpa_s, MSG_INFO,
+				     WPA_EVENT_EAP_PEER_CERT
+				     "depth=%d subject='%s' cert=%s",
+				     depth, subject, cert_hex);
+			os_free(cert_hex);
+		}
+
+		if (e->server_cert_file)
+			eapol_test_write_cert(e->server_cert_file,
+					      subject, cert);
+	}
+}
+
+
+static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+	struct eapol_test_data *e = ctx;
+	struct wpa_supplicant *wpa_s = e->wpa_s;
+	char *str;
+	int res;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+			  id, len);
+
+	if (wpa_s->current_ssid == NULL)
+		return;
+
+	if (id == NULL) {
+		if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				   "NULL", 0) < 0)
+			return;
+	} else {
+		str = os_malloc(len * 2 + 1);
+		if (str == NULL)
+			return;
+		wpa_snprintf_hex(str, len * 2 + 1, id, len);
+		res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				     str, 0);
+		os_free(str);
+		if (res < 0)
+			return;
+	}
+}
+
+
+static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
+		      struct wpa_ssid *ssid)
+{
+	struct eapol_config eapol_conf;
+	struct eapol_ctx *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		printf("Failed to allocate EAPOL context.\n");
+		return -1;
+	}
+	ctx->ctx = e;
+	ctx->msg_ctx = wpa_s;
+	ctx->scard_ctx = wpa_s->scard;
+	ctx->cb = eapol_sm_cb;
+	ctx->cb_ctx = e;
+	ctx->eapol_send_ctx = wpa_s;
+	ctx->preauth = 0;
+	ctx->eapol_done_cb = eapol_test_eapol_done_cb;
+	ctx->eapol_send = eapol_test_eapol_send;
+	ctx->set_config_blob = eapol_test_set_config_blob;
+	ctx->get_config_blob = eapol_test_get_config_blob;
+	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
+	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->cert_cb = eapol_test_cert_cb;
+	ctx->cert_in_cb = 1;
+	ctx->set_anon_id = eapol_test_set_anon_id;
+
+	wpa_s->eapol = eapol_sm_init(ctx);
+	if (wpa_s->eapol == NULL) {
+		os_free(ctx);
+		printf("Failed to initialize EAPOL state machines.\n");
+		return -1;
+	}
+
+	wpa_s->current_ssid = ssid;
+	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+	eapol_conf.accept_802_1x_keys = 1;
+	eapol_conf.required_keys = 0;
+	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+
+
+	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+	/* 802.1X::portControl = Auto */
+	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+
+	return 0;
+}
+
+
+static void test_eapol_clean(struct eapol_test_data *e,
+			     struct wpa_supplicant *wpa_s)
+{
+	struct extra_radius_attr *p, *prev;
+
+	radius_client_deinit(e->radius);
+	wpabuf_free(e->last_eap_radius);
+	radius_msg_free(e->last_recv_radius);
+	e->last_recv_radius = NULL;
+	os_free(e->eap_identity);
+	e->eap_identity = NULL;
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_s->eapol = NULL;
+	if (e->radius_conf && e->radius_conf->auth_server) {
+		os_free(e->radius_conf->auth_server->shared_secret);
+		os_free(e->radius_conf->auth_server);
+	}
+	os_free(e->radius_conf);
+	e->radius_conf = NULL;
+	scard_deinit(wpa_s->scard);
+	if (wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+
+	ext_password_deinit(wpa_s->ext_pw);
+	wpa_s->ext_pw = NULL;
+
+	wpa_config_free(wpa_s->conf);
+
+	p = e->extra_attrs;
+	while (p) {
+		prev = p;
+		p = p->next;
+		os_free(prev);
+	}
+}
+
+
+static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	u8 buf[100], *pos;
+	struct ieee802_1x_hdr *hdr;
+	struct eap_hdr *eap;
+
+	hdr = (struct ieee802_1x_hdr *) buf;
+	hdr->version = EAPOL_VERSION;
+	hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
+	hdr->length = htons(5);
+
+	eap = (struct eap_hdr *) (hdr + 1);
+	eap->code = EAP_CODE_REQUEST;
+	eap->identifier = 0;
+	eap->length = htons(5);
+	pos = (u8 *) (eap + 1);
+	*pos = EAP_TYPE_IDENTITY;
+
+	printf("Sending fake EAP-Request-Identity\n");
+	eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf,
+			  sizeof(*hdr) + 5);
+}
+
+
+static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_test_data *e = eloop_ctx;
+	printf("EAPOL test timed out\n");
+	e->auth_timed_out = 1;
+	eloop_terminate();
+}
+
+
+static char *eap_type_text(u8 type)
+{
+	switch (type) {
+	case EAP_TYPE_IDENTITY: return "Identity";
+	case EAP_TYPE_NOTIFICATION: return "Notification";
+	case EAP_TYPE_NAK: return "Nak";
+	case EAP_TYPE_TLS: return "TLS";
+	case EAP_TYPE_TTLS: return "TTLS";
+	case EAP_TYPE_PEAP: return "PEAP";
+	case EAP_TYPE_SIM: return "SIM";
+	case EAP_TYPE_GTC: return "GTC";
+	case EAP_TYPE_MD5: return "MD5";
+	case EAP_TYPE_OTP: return "OTP";
+	case EAP_TYPE_FAST: return "FAST";
+	case EAP_TYPE_SAKE: return "SAKE";
+	case EAP_TYPE_PSK: return "PSK";
+	default: return "Unknown";
+	}
+}
+
+
+static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
+{
+	struct wpabuf *eap;
+	const struct eap_hdr *hdr;
+	int eap_type = -1;
+	char buf[64];
+	struct radius_msg *msg;
+
+	if (e->last_recv_radius == NULL)
+		return;
+
+	msg = e->last_recv_radius;
+
+	eap = radius_msg_get_eap(msg);
+	if (eap == NULL) {
+		/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
+		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
+		 * attribute */
+		wpa_printf(MSG_DEBUG, "could not extract "
+			       "EAP-Message from RADIUS message");
+		wpabuf_free(e->last_eap_radius);
+		e->last_eap_radius = NULL;
+		return;
+	}
+
+	if (wpabuf_len(eap) < sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "too short EAP packet "
+			       "received from authentication server");
+		wpabuf_free(eap);
+		return;
+	}
+
+	if (wpabuf_len(eap) > sizeof(*hdr))
+		eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
+
+	hdr = wpabuf_head(eap);
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
+			    eap_type >= 0 ? eap_type_text(eap_type) : "??",
+			    eap_type);
+		break;
+	case EAP_CODE_RESPONSE:
+		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
+			    eap_type >= 0 ? eap_type_text(eap_type) : "??",
+			    eap_type);
+		break;
+	case EAP_CODE_SUCCESS:
+		os_strlcpy(buf, "EAP Success", sizeof(buf));
+		/* LEAP uses EAP Success within an authentication, so must not
+		 * stop here with eloop_terminate(); */
+		break;
+	case EAP_CODE_FAILURE:
+		os_strlcpy(buf, "EAP Failure", sizeof(buf));
+		eloop_terminate();
+		break;
+	default:
+		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
+		wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
+		break;
+	}
+	wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
+		       "id=%d len=%d) from RADIUS server: %s",
+		      hdr->code, hdr->identifier, ntohs(hdr->length), buf);
+
+	/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
+
+	wpabuf_free(e->last_eap_radius);
+	e->last_eap_radius = eap;
+
+	{
+		struct ieee802_1x_hdr *dot1x;
+		dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap));
+		assert(dot1x != NULL);
+		dot1x->version = EAPOL_VERSION;
+		dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
+		dot1x->length = htons(wpabuf_len(eap));
+		os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap),
+			  wpabuf_len(eap));
+		eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
+				  (u8 *) dot1x,
+				  sizeof(*dot1x) + wpabuf_len(eap));
+		os_free(dot1x);
+	}
+}
+
+
+static void ieee802_1x_get_keys(struct eapol_test_data *e,
+				struct radius_msg *msg, struct radius_msg *req,
+				const u8 *shared_secret,
+				size_t shared_secret_len)
+{
+	struct radius_ms_mppe_keys *keys;
+
+	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
+				      shared_secret_len);
+	if (keys && keys->send == NULL && keys->recv == NULL) {
+		os_free(keys);
+		keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
+						 shared_secret_len);
+	}
+
+	if (keys) {
+		if (keys->send) {
+			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)",
+				    keys->send, keys->send_len);
+		}
+		if (keys->recv) {
+			wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
+				    keys->recv, keys->recv_len);
+			e->authenticator_pmk_len =
+				keys->recv_len > PMK_LEN ? PMK_LEN :
+				keys->recv_len;
+			os_memcpy(e->authenticator_pmk, keys->recv,
+				  e->authenticator_pmk_len);
+			if (e->authenticator_pmk_len == 16 && keys->send &&
+			    keys->send_len == 16) {
+				/* MS-CHAP-v2 derives 16 octet keys */
+				wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
+					   "to extend PMK to 32 octets");
+				os_memcpy(e->authenticator_pmk +
+					  e->authenticator_pmk_len,
+					  keys->send, keys->send_len);
+				e->authenticator_pmk_len += keys->send_len;
+			}
+		}
+
+		os_free(keys->send);
+		os_free(keys->recv);
+		os_free(keys);
+	}
+}
+
+
+/* Process the RADIUS frames from Authentication Server */
+static RadiusRxResult
+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
+			const u8 *shared_secret, size_t shared_secret_len,
+			void *data)
+{
+	struct eapol_test_data *e = data;
+	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+
+	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
+	 * present when packet contains an EAP-Message attribute */
+	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
+				0) < 0 &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Allowing RADIUS "
+			      "Access-Reject without Message-Authenticator "
+			      "since it does not include EAP-Message\n");
+	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
+				     req, 1)) {
+		printf("Incoming RADIUS packet did not have correct "
+		       "Message-Authenticator - dropped\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
+		printf("Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	e->radius_identifier = -1;
+	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");
+
+	radius_msg_free(e->last_recv_radius);
+	e->last_recv_radius = msg;
+
+	switch (hdr->code) {
+	case RADIUS_CODE_ACCESS_ACCEPT:
+		e->radius_access_accept_received = 1;
+		ieee802_1x_get_keys(e, msg, req, shared_secret,
+				    shared_secret_len);
+		break;
+	case RADIUS_CODE_ACCESS_REJECT:
+		e->radius_access_reject_received = 1;
+		break;
+	}
+
+	ieee802_1x_decapsulate_radius(e);
+
+	if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
+	     e->eapol_test_num_reauths < 0) ||
+	    hdr->code == RADIUS_CODE_ACCESS_REJECT) {
+		eloop_terminate();
+	}
+
+	return RADIUS_RX_QUEUED;
+}
+
+
+static void wpa_init_conf(struct eapol_test_data *e,
+			  struct wpa_supplicant *wpa_s, const char *authsrv,
+			  int port, const char *secret,
+			  const char *cli_addr)
+{
+	struct hostapd_radius_server *as;
+	int res;
+
+	wpa_s->bssid[5] = 1;
+	os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN);
+	e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
+	os_strlcpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
+
+	e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers));
+	assert(e->radius_conf != NULL);
+	e->radius_conf->num_auth_servers = 1;
+	as = os_zalloc(sizeof(struct hostapd_radius_server));
+	assert(as != NULL);
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+	{
+		int a[4];
+		u8 *pos;
+		sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+		pos = (u8 *) &as->addr.u.v4;
+		*pos++ = a[0];
+		*pos++ = a[1];
+		*pos++ = a[2];
+		*pos++ = a[3];
+	}
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	inet_aton(authsrv, &as->addr.u.v4);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	as->addr.af = AF_INET;
+	as->port = port;
+	as->shared_secret = (u8 *) os_strdup(secret);
+	as->shared_secret_len = os_strlen(secret);
+	e->radius_conf->auth_server = as;
+	e->radius_conf->auth_servers = as;
+	e->radius_conf->msg_dumps = 1;
+	if (cli_addr) {
+		if (hostapd_parse_ip_addr(cli_addr,
+					  &e->radius_conf->client_addr) == 0)
+			e->radius_conf->force_client_addr = 1;
+		else {
+			wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+				   cli_addr);
+			assert(0);
+		}
+	}
+
+	e->radius = radius_client_init(wpa_s, e->radius_conf);
+	assert(e->radius != NULL);
+
+	res = radius_client_register(e->radius, RADIUS_AUTH,
+				     ieee802_1x_receive_auth, e);
+	assert(res == 0);
+}
+
+
+static int scard_test(void)
+{
+	struct scard_data *scard;
+	size_t len;
+	char imsi[20];
+	unsigned char _rand[16];
+#ifdef PCSC_FUNCS
+	unsigned char sres[4];
+	unsigned char kc[8];
+#endif /* PCSC_FUNCS */
+#define num_triplets 5
+	unsigned char rand_[num_triplets][16];
+	unsigned char sres_[num_triplets][4];
+	unsigned char kc_[num_triplets][8];
+	int i, res;
+	size_t j;
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+#define AKA_AUTS_LEN 14
+#define RES_MAX_LEN 16
+#define IK_LEN 16
+#define CK_LEN 16
+	unsigned char aka_rand[AKA_RAND_LEN];
+	unsigned char aka_autn[AKA_AUTN_LEN];
+	unsigned char aka_auts[AKA_AUTS_LEN];
+	unsigned char aka_res[RES_MAX_LEN];
+	size_t aka_res_len;
+	unsigned char aka_ik[IK_LEN];
+	unsigned char aka_ck[CK_LEN];
+
+	scard = scard_init(SCARD_TRY_BOTH, NULL);
+	if (scard == NULL)
+		return -1;
+	if (scard_set_pin(scard, "1234")) {
+		wpa_printf(MSG_WARNING, "PIN validation failed");
+		scard_deinit(scard);
+		return -1;
+	}
+
+	len = sizeof(imsi);
+	if (scard_get_imsi(scard, imsi, &len))
+		goto failed;
+	wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len);
+	/* NOTE: Permanent Username: 1 | IMSI */
+
+	wpa_printf(MSG_DEBUG, "SCARD: MNC length %d",
+		   scard_get_mnc_len(scard));
+
+	os_memset(_rand, 0, sizeof(_rand));
+	if (scard_gsm_auth(scard, _rand, sres, kc))
+		goto failed;
+
+	os_memset(_rand, 0xff, sizeof(_rand));
+	if (scard_gsm_auth(scard, _rand, sres, kc))
+		goto failed;
+
+	for (i = 0; i < num_triplets; i++) {
+		os_memset(rand_[i], i, sizeof(rand_[i]));
+		if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i]))
+			goto failed;
+	}
+
+	for (i = 0; i < num_triplets; i++) {
+		printf("1");
+		for (j = 0; j < len; j++)
+			printf("%c", imsi[j]);
+		printf(",");
+		for (j = 0; j < 16; j++)
+			printf("%02X", rand_[i][j]);
+		printf(",");
+		for (j = 0; j < 4; j++)
+			printf("%02X", sres_[i][j]);
+		printf(",");
+		for (j = 0; j < 8; j++)
+			printf("%02X", kc_[i][j]);
+		printf("\n");
+	}
+
+	wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication");
+
+	/* seq 39 (0x28) */
+	os_memset(aka_rand, 0xaa, 16);
+	os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf"
+		  "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16);
+
+	res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len,
+			      aka_ik, aka_ck, aka_auts);
+	if (res == 0) {
+		wpa_printf(MSG_DEBUG, "UMTS auth completed successfully");
+		wpa_hexdump(MSG_DEBUG, "RES", aka_res, aka_res_len);
+		wpa_hexdump(MSG_DEBUG, "IK", aka_ik, IK_LEN);
+		wpa_hexdump(MSG_DEBUG, "CK", aka_ck, CK_LEN);
+	} else if (res == -2) {
+		wpa_printf(MSG_DEBUG, "UMTS auth resulted in synchronization "
+			   "failure");
+		wpa_hexdump(MSG_DEBUG, "AUTS", aka_auts, AKA_AUTS_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "UMTS auth failed");
+	}
+
+failed:
+	scard_deinit(scard);
+
+	return 0;
+#undef num_triplets
+}
+
+
+static int scard_get_triplets(int argc, char *argv[])
+{
+	struct scard_data *scard;
+	size_t len;
+	char imsi[20];
+	unsigned char _rand[16];
+	unsigned char sres[4];
+	unsigned char kc[8];
+	int num_triplets;
+	int i;
+	size_t j;
+
+	if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) {
+		printf("invalid parameters for sim command\n");
+		return -1;
+	}
+
+	if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) {
+		/* disable debug output */
+		wpa_debug_level = 99;
+	}
+
+	scard = scard_init(SCARD_GSM_SIM_ONLY, NULL);
+	if (scard == NULL) {
+		printf("Failed to open smartcard connection\n");
+		return -1;
+	}
+	if (scard_set_pin(scard, argv[0])) {
+		wpa_printf(MSG_WARNING, "PIN validation failed");
+		scard_deinit(scard);
+		return -1;
+	}
+
+	len = sizeof(imsi);
+	if (scard_get_imsi(scard, imsi, &len)) {
+		scard_deinit(scard);
+		return -1;
+	}
+
+	for (i = 0; i < num_triplets; i++) {
+		os_memset(_rand, i, sizeof(_rand));
+		if (scard_gsm_auth(scard, _rand, sres, kc))
+			break;
+
+		/* IMSI:Kc:SRES:RAND */
+		for (j = 0; j < len; j++)
+			printf("%c", imsi[j]);
+		printf(":");
+		for (j = 0; j < 8; j++)
+			printf("%02X", kc[j]);
+		printf(":");
+		for (j = 0; j < 4; j++)
+			printf("%02X", sres[j]);
+		printf(":");
+		for (j = 0; j < 16; j++)
+			printf("%02X", _rand[j]);
+		printf("\n");
+	}
+
+	scard_deinit(scard);
+
+	return 0;
+}
+
+
+static void eapol_test_terminate(int sig, void *signal_ctx)
+{
+	struct wpa_supplicant *wpa_s = signal_ctx;
+	wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig);
+	eloop_terminate();
+}
+
+
+static void usage(void)
+{
+	printf("usage:\n"
+	       "eapol_test [-nWS] -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"
+	       "           [-N<attr spec>] \\\n"
+	       "           [-A<client IP>]\n"
+	       "eapol_test scard\n"
+	       "eapol_test sim <PIN> <num triplets> [debug]\n"
+	       "\n");
+	printf("options:\n"
+	       "  -c<conf> = configuration file\n"
+	       "  -a<AS IP> = IP address of the authentication server, "
+	       "default 127.0.0.1\n"
+	       "  -p<AS port> = UDP port of the authentication server, "
+	       "default 1812\n"
+	       "  -s<AS secret> = shared secret with the authentication "
+	       "server, default 'radius'\n"
+	       "  -A<client IP> = IP address of the client, default: select "
+	       "automatically\n"
+	       "  -r<count> = number of re-authentications\n"
+	       "  -W = wait for a control interface monitor before starting\n"
+	       "  -S = save configuration after authentication\n"
+	       "  -n = no MPPE keys expected\n"
+	       "  -t<timeout> = sets timeout in seconds (default: 30 s)\n"
+	       "  -C<Connect-Info> = RADIUS Connect-Info (default: "
+	       "CONNECT 11Mbps 802.11b)\n"
+	       "  -M<client MAC address> = Set own MAC address "
+	       "(Calling-Station-Id,\n"
+	       "                           default: 02:00:00:00:00:01)\n"
+	       "  -o<server cert file> = Write received server certificate\n"
+	       "                         chain to the specified file\n"
+	       "  -N<attr spec> = send arbitrary attribute specified by:\n"
+	       "                  attr_id:syntax:value or attr_id\n"
+	       "                  attr_id - number id of the attribute\n"
+	       "                  syntax - one of: s, d, x\n"
+	       "                     s = string\n"
+	       "                     d = integer\n"
+	       "                     x = octet string\n"
+	       "                  value - attribute value.\n"
+	       "       When only attr_id is specified, NULL will be used as "
+	       "value.\n"
+	       "       Multiple attributes can be specified by using the "
+	       "option several times.\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct wpa_supplicant wpa_s;
+	int c, ret = 1, wait_for_monitor = 0, save_config = 0;
+	char *as_addr = "127.0.0.1";
+	int as_port = 1812;
+	char *as_secret = "radius";
+	char *cli_addr = NULL;
+	char *conf = NULL;
+	int timeout = 30;
+	char *pos;
+	struct extra_radius_attr *p = NULL, *p1;
+
+	if (os_program_init())
+		return -1;
+
+	hostapd_logger_register_cb(hostapd_logger_cb);
+
+	os_memset(&eapol_test, 0, sizeof(eapol_test));
+	eapol_test.connect_info = "CONNECT 11Mbps 802.11b";
+	os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN);
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	for (;;) {
+		c = getopt(argc, argv, "a:A:c:C:M:nN:o:p:r:s:St:W");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'a':
+			as_addr = optarg;
+			break;
+		case 'A':
+			cli_addr = optarg;
+			break;
+		case 'c':
+			conf = optarg;
+			break;
+		case 'C':
+			eapol_test.connect_info = optarg;
+			break;
+		case 'M':
+			if (hwaddr_aton(optarg, eapol_test.own_addr)) {
+				usage();
+				return -1;
+			}
+			break;
+		case 'n':
+			eapol_test.no_mppe_keys++;
+			break;
+		case 'o':
+			if (eapol_test.server_cert_file)
+				fclose(eapol_test.server_cert_file);
+			eapol_test.server_cert_file = fopen(optarg, "w");
+			if (eapol_test.server_cert_file == NULL) {
+				printf("Could not open '%s' for writing\n",
+				       optarg);
+				return -1;
+			}
+			break;
+		case 'p':
+			as_port = atoi(optarg);
+			break;
+		case 'r':
+			eapol_test.eapol_test_num_reauths = atoi(optarg);
+			break;
+		case 's':
+			as_secret = optarg;
+			break;
+		case 'S':
+			save_config++;
+			break;
+		case 't':
+			timeout = atoi(optarg);
+			break;
+		case 'W':
+			wait_for_monitor++;
+			break;
+		case 'N':
+			p1 = os_zalloc(sizeof(*p1));
+			if (p1 == NULL)
+				break;
+			if (!p)
+				eapol_test.extra_attrs = p1;
+			else
+				p->next = p1;
+			p = p1;
+
+			p->type = atoi(optarg);
+			pos = os_strchr(optarg, ':');
+			if (pos == NULL) {
+				p->syntax = 'n';
+				p->data = NULL;
+				break;
+			}
+
+			pos++;
+			if (pos[0] == '\0' || pos[1] != ':') {
+				printf("Incorrect format of attribute "
+				       "specification\n");
+				break;
+			}
+
+			p->syntax = pos[0];
+			p->data = pos + 2;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
+		return scard_test();
+	}
+
+	if (argc > optind && os_strcmp(argv[optind], "sim") == 0) {
+		return scard_get_triplets(argc - optind - 1,
+					  &argv[optind + 1]);
+	}
+
+	if (conf == NULL) {
+		usage();
+		printf("Configuration file is required.\n");
+		return -1;
+	}
+
+	if (eap_register_methods()) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		return -1;
+	}
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	eapol_test.wpa_s = &wpa_s;
+	wpa_s.conf = wpa_config_read(conf);
+	if (wpa_s.conf == NULL) {
+		printf("Failed to parse configuration file '%s'.\n", conf);
+		return -1;
+	}
+	if (wpa_s.conf->ssid == NULL) {
+		printf("No networks defined.\n");
+		return -1;
+	}
+
+	wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
+		      cli_addr);
+	wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
+	if (wpa_s.ctrl_iface == NULL) {
+		printf("Failed to initialize control interface '%s'.\n"
+		       "You may have another eapol_test process already "
+		       "running or the file was\n"
+		       "left by an unclean termination of eapol_test in "
+		       "which case you will need\n"
+		       "to manually remove this file before starting "
+		       "eapol_test again.\n",
+		       wpa_s.conf->ctrl_interface);
+		return -1;
+	}
+	if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
+		return -1;
+
+	if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
+		return -1;
+
+	if (wpas_init_ext_pw(&wpa_s) < 0)
+		return -1;
+
+	if (wait_for_monitor)
+		wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
+
+	eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test,
+			       NULL);
+	eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL);
+	eloop_register_signal_terminate(eapol_test_terminate, &wpa_s);
+	eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s);
+	eloop_run();
+
+	eloop_cancel_timeout(eapol_test_timeout, &eapol_test, NULL);
+	eloop_cancel_timeout(eapol_sm_reauth, &eapol_test, NULL);
+
+	if (eapol_test_compare_pmk(&eapol_test) == 0 ||
+	    eapol_test.no_mppe_keys)
+		ret = 0;
+	if (eapol_test.auth_timed_out)
+		ret = -2;
+	if (eapol_test.radius_access_reject_received)
+		ret = -3;
+
+	if (save_config)
+		wpa_config_write(conf, wpa_s.conf);
+
+	test_eapol_clean(&eapol_test, &wpa_s);
+
+	eap_peer_unregister_methods();
+#ifdef CONFIG_AP
+	eap_server_unregister_methods();
+#endif /* CONFIG_AP */
+
+	eloop_destroy();
+
+	if (eapol_test.server_cert_file)
+		fclose(eapol_test.server_cert_file);
+
+	printf("MPPE keys OK: %d  mismatch: %d\n",
+	       eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
+	if (eapol_test.num_mppe_mismatch)
+		ret = -4;
+	if (ret)
+		printf("FAILURE\n");
+	else
+		printf("SUCCESS\n");
+
+	os_program_deinit();
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/events.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/events.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/events.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1729 +0,0 @@
-/*
- * WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "eloop.h"
-#include "config.h"
-#include "l2_packet/l2_packet.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "pcsc_funcs.h"
-#include "rsn_supp/preauth.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "common/wpa_ctrl.h"
-#include "eap_peer/eap.h"
-#include "ap/hostapd.h"
-#include "notify.h"
-#include "common/ieee802_11_defs.h"
-#include "blacklist.h"
-#include "wpas_glue.h"
-#include "wps_supplicant.h"
-#include "ibss_rsn.h"
-#include "sme.h"
-#include "bgscan.h"
-#include "ap.h"
-#include "bss.h"
-#include "mlme.h"
-#include "scan.h"
-
-
-static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid, *old_ssid;
-
-	if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "Select network based on association "
-		   "information");
-	ssid = wpa_supplicant_get_ssid(wpa_s);
-	if (ssid == NULL) {
-		wpa_printf(MSG_INFO, "No network configuration found for the "
-			   "current AP");
-		return -1;
-	}
-
-	if (ssid->disabled) {
-		wpa_printf(MSG_DEBUG, "Selected network is disabled");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "Network configuration found for the current "
-		   "AP");
-	if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-			      WPA_KEY_MGMT_WPA_NONE |
-			      WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
-			      WPA_KEY_MGMT_PSK_SHA256 |
-			      WPA_KEY_MGMT_IEEE8021X_SHA256)) {
-		u8 wpa_ie[80];
-		size_t wpa_ie_len = sizeof(wpa_ie);
-		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
-					  wpa_ie, &wpa_ie_len);
-	} else {
-		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
-	}
-
-	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid)
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = ssid;
-	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)
-		wpas_notify_network_changed(wpa_s);
-
-	return 0;
-}
-
-
-static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
-						void *sock_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-
-	if (wpa_s->countermeasures) {
-		wpa_s->countermeasures = 0;
-		wpa_drv_set_countermeasures(wpa_s, 0);
-		wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-	}
-}
-
-
-void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
-{
-	int bssid_changed;
-
-	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-	os_memset(wpa_s->bssid, 0, ETH_ALEN);
-	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-	wpa_s->current_bss = NULL;
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
-
-	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
-	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
-	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
-		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-	wpa_s->ap_ies_from_associnfo = 0;
-}
-
-
-static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ie_data ie;
-	int pmksa_set = -1;
-	size_t i;
-
-	if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
-	    ie.pmkid == NULL)
-		return;
-
-	for (i = 0; i < ie.num_pmkid; i++) {
-		pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
-						    ie.pmkid + i * PMKID_LEN,
-						    NULL, NULL, 0);
-		if (pmksa_set == 0) {
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
-			break;
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
-		   "cache", pmksa_set == 0 ? "" : "not ");
-}
-
-
-static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
-						 union wpa_event_data *data)
-{
-	if (data == NULL) {
-		wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
-		return;
-	}
-	wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
-		   " index=%d preauth=%d",
-		   MAC2STR(data->pmkid_candidate.bssid),
-		   data->pmkid_candidate.index,
-		   data->pmkid_candidate.preauth);
-
-	pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
-			    data->pmkid_candidate.index,
-			    data->pmkid_candidate.preauth);
-}
-
-
-static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
-{
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
-		return 0;
-
-#ifdef IEEE8021X_EAPOL
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
-	    wpa_s->current_ssid &&
-	    !(wpa_s->current_ssid->eapol_flags &
-	      (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
-	       EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
-		/* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
-		 * plaintext or static WEP keys). */
-		return 0;
-	}
-#endif /* IEEE8021X_EAPOL */
-
-	return 1;
-}
-
-
-/**
- * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
- * @wpa_s: pointer to wpa_supplicant data
- * @ssid: Configuration data for the network
- * Returns: 0 on success, -1 on failure
- *
- * This function is called when starting authentication with a network that is
- * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
- */
-int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid)
-{
-#ifdef IEEE8021X_EAPOL
-	int aka = 0, sim = 0, type;
-
-	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
-		return 0;
-
-	if (ssid->eap.eap_methods == NULL) {
-		sim = 1;
-		aka = 1;
-	} else {
-		struct eap_method_type *eap = ssid->eap.eap_methods;
-		while (eap->vendor != EAP_VENDOR_IETF ||
-		       eap->method != EAP_TYPE_NONE) {
-			if (eap->vendor == EAP_VENDOR_IETF) {
-				if (eap->method == EAP_TYPE_SIM)
-					sim = 1;
-				else if (eap->method == EAP_TYPE_AKA)
-					aka = 1;
-			}
-			eap++;
-		}
-	}
-
-	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
-		sim = 0;
-	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL)
-		aka = 0;
-
-	if (!sim && !aka) {
-		wpa_printf(MSG_DEBUG, "Selected network is configured to use "
-			   "SIM, but neither EAP-SIM nor EAP-AKA are enabled");
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM "
-		   "(sim=%d aka=%d) - initialize PCSC", sim, aka);
-	if (sim && aka)
-		type = SCARD_TRY_BOTH;
-	else if (aka)
-		type = SCARD_USIM_ONLY;
-	else
-		type = SCARD_GSM_SIM_ONLY;
-
-	wpa_s->scard = scard_init(type);
-	if (wpa_s->scard == NULL) {
-		wpa_printf(MSG_WARNING, "Failed to initialize SIM "
-			   "(pcsc-lite)");
-		return -1;
-	}
-	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
-	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
-#endif /* IEEE8021X_EAPOL */
-
-	return 0;
-}
-
-
-#ifndef CONFIG_NO_SCAN_PROCESSING
-static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
-					struct wpa_ssid *ssid)
-{
-	int i, privacy = 0;
-
-	if (ssid->mixed_cell)
-		return 1;
-
-#ifdef CONFIG_WPS
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-		return 1;
-#endif /* CONFIG_WPS */
-
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i]) {
-			privacy = 1;
-			break;
-		}
-	}
-#ifdef IEEE8021X_EAPOL
-	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
-	    ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
-				 EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
-		privacy = 1;
-#endif /* IEEE8021X_EAPOL */
-
-	if (bss->caps & IEEE80211_CAP_PRIVACY)
-		return privacy;
-	return !privacy;
-}
-
-
-static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
-					 struct wpa_ssid *ssid,
-					 struct wpa_scan_res *bss)
-{
-	struct wpa_ie_data ie;
-	int proto_match = 0;
-	const u8 *rsn_ie, *wpa_ie;
-	int ret;
-
-	ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
-	if (ret >= 0)
-		return ret;
-
-	rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
-	while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
-		proto_match++;
-
-		if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - parse failed");
-			break;
-		}
-		if (!(ie.proto & ssid->proto)) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - proto "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - PTK cipher "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.group_cipher & ssid->group_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - GTK cipher "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.key_mgmt & ssid->key_mgmt)) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - key mgmt "
-				   "mismatch");
-			break;
-		}
-
-#ifdef CONFIG_IEEE80211W
-		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
-		    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
-			wpa_printf(MSG_DEBUG, "   skip RSN IE - no mgmt frame "
-				   "protection");
-			break;
-		}
-#endif /* CONFIG_IEEE80211W */
-
-		wpa_printf(MSG_DEBUG, "   selected based on RSN IE");
-		return 1;
-	}
-
-	wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
-		proto_match++;
-
-		if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
-			wpa_printf(MSG_DEBUG, "   skip WPA IE - parse failed");
-			break;
-		}
-		if (!(ie.proto & ssid->proto)) {
-			wpa_printf(MSG_DEBUG, "   skip WPA IE - proto "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip WPA IE - PTK cipher "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.group_cipher & ssid->group_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip WPA IE - GTK cipher "
-				   "mismatch");
-			break;
-		}
-
-		if (!(ie.key_mgmt & ssid->key_mgmt)) {
-			wpa_printf(MSG_DEBUG, "   skip WPA IE - key mgmt "
-				   "mismatch");
-			break;
-		}
-
-		wpa_printf(MSG_DEBUG, "   selected based on WPA IE");
-		return 1;
-	}
-
-	if (proto_match == 0)
-		wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN proto match");
-
-	return 0;
-}
-
-
-static int freq_allowed(int *freqs, int freq)
-{
-	int i;
-
-	if (freqs == NULL)
-		return 1;
-
-	for (i = 0; freqs[i]; i++)
-		if (freqs[i] == freq)
-			return 1;
-	return 0;
-}
-
-
-static struct wpa_bss *
-wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
-			      struct wpa_scan_results *scan_res,
-			      struct wpa_ssid *group,
-			      struct wpa_ssid **selected_ssid)
-{
-	struct wpa_ssid *ssid;
-	struct wpa_scan_res *bss;
-	size_t i;
-	struct wpa_blacklist *e;
-	const u8 *ie;
-
-	wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP");
-	for (i = 0; i < scan_res->num; i++) {
-		const u8 *ssid_;
-		u8 wpa_ie_len, rsn_ie_len, ssid_len;
-		bss = scan_res->res[i];
-
-		ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
-		ssid_ = ie ? ie + 2 : (u8 *) "";
-		ssid_len = ie ? ie[1] : 0;
-
-		ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-		wpa_ie_len = ie ? ie[1] : 0;
-
-		ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
-		rsn_ie_len = ie ? ie[1] : 0;
-
-		wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-			   "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x",
-			   (int) i, MAC2STR(bss->bssid),
-			   wpa_ssid_txt(ssid_, ssid_len),
-			   wpa_ie_len, rsn_ie_len, bss->caps);
-
-		e = wpa_blacklist_get(wpa_s, bss->bssid);
-		if (e && e->count > 1) {
-			wpa_printf(MSG_DEBUG, "   skip - blacklisted");
-			continue;
-		}
-
-		if (ssid_len == 0) {
-			wpa_printf(MSG_DEBUG, "   skip - SSID not known");
-			continue;
-		}
-
-		if (wpa_ie_len == 0 && rsn_ie_len == 0) {
-			wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN IE");
-			continue;
-		}
-
-		for (ssid = group; ssid; ssid = ssid->pnext) {
-			int check_ssid = 1;
-
-			if (ssid->disabled) {
-				wpa_printf(MSG_DEBUG, "   skip - disabled");
-				continue;
-			}
-
-#ifdef CONFIG_WPS
-			if (ssid->ssid_len == 0 &&
-			    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
-				check_ssid = 0;
-#endif /* CONFIG_WPS */
-
-			if (check_ssid &&
-			    (ssid_len != ssid->ssid_len ||
-			     os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "SSID mismatch");
-				continue;
-			}
-
-			if (ssid->bssid_set &&
-			    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0)
-			{
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "BSSID mismatch");
-				continue;
-			}
-
-			if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
-				continue;
-
-			if (!freq_allowed(ssid->freq_list, bss->freq)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "frequency not allowed");
-				continue;
-			}
-
-			wpa_printf(MSG_DEBUG, "   selected WPA AP "
-				   MACSTR " ssid='%s'",
-				   MAC2STR(bss->bssid),
-				   wpa_ssid_txt(ssid_, ssid_len));
-			*selected_ssid = ssid;
-			return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len);
-		}
-	}
-
-	return NULL;
-}
-
-
-static struct wpa_bss *
-wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
-				  struct wpa_scan_results *scan_res,
-				  struct wpa_ssid *group,
-				  struct wpa_ssid **selected_ssid)
-{
-	struct wpa_ssid *ssid;
-	struct wpa_scan_res *bss;
-	size_t i;
-	struct wpa_blacklist *e;
-	const u8 *ie;
-
-	wpa_printf(MSG_DEBUG, "Try to find non-WPA AP");
-	for (i = 0; i < scan_res->num; i++) {
-		const u8 *ssid_;
-		u8 wpa_ie_len, rsn_ie_len, ssid_len;
-		bss = scan_res->res[i];
-
-		ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
-		ssid_ = ie ? ie + 2 : (u8 *) "";
-		ssid_len = ie ? ie[1] : 0;
-
-		ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-		wpa_ie_len = ie ? ie[1] : 0;
-
-		ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
-		rsn_ie_len = ie ? ie[1] : 0;
-
-		wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-			   "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x",
-			   (int) i, MAC2STR(bss->bssid),
-			   wpa_ssid_txt(ssid_, ssid_len),
-			   wpa_ie_len, rsn_ie_len, bss->caps);
-
-		e = wpa_blacklist_get(wpa_s, bss->bssid);
-		if (e && e->count > 1) {
-			wpa_printf(MSG_DEBUG, "   skip - blacklisted");
-			continue;
-		}
-
-		if (ssid_len == 0) {
-			wpa_printf(MSG_DEBUG, "   skip - SSID not known");
-			continue;
-		}
-
-		for (ssid = group; ssid; ssid = ssid->pnext) {
-			int check_ssid = ssid->ssid_len != 0;
-
-			if (ssid->disabled) {
-				wpa_printf(MSG_DEBUG, "   skip - disabled");
-				continue;
-			}
-
-#ifdef CONFIG_WPS
-			if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-				/* Only allow wildcard SSID match if an AP
-				 * advertises active WPS operation that matches
-				 * with our mode. */
-				check_ssid = 1;
-				if (ssid->ssid_len == 0 &&
-				    wpas_wps_ssid_wildcard_ok(wpa_s, ssid,
-							      bss))
-					check_ssid = 0;
-			}
-#endif /* CONFIG_WPS */
-
-			if (check_ssid &&
-			    (ssid_len != ssid->ssid_len ||
-			     os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "SSID mismatch");
-				continue;
-			}
-
-			if (ssid->bssid_set &&
-			    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0)
-			{
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "BSSID mismatch");
-				continue;
-			}
-
-			if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
-			    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
-			    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
-			{
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "non-WPA network not allowed");
-				continue;
-			}
-
-			if ((ssid->key_mgmt &
-			     (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-			      WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK |
-			      WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			      WPA_KEY_MGMT_PSK_SHA256)) &&
-			    (wpa_ie_len != 0 || rsn_ie_len != 0)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "WPA network");
-				continue;
-			}
-
-			if (!wpa_supplicant_match_privacy(bss, ssid)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "privacy mismatch");
-				continue;
-			}
-
-			if (bss->caps & IEEE80211_CAP_IBSS) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "IBSS (adhoc) network");
-				continue;
-			}
-
-			if (!freq_allowed(ssid->freq_list, bss->freq)) {
-				wpa_printf(MSG_DEBUG, "   skip - "
-					   "frequency not allowed");
-				continue;
-			}
-
-			wpa_printf(MSG_DEBUG, "   selected non-WPA AP "
-				   MACSTR " ssid='%s'",
-				   MAC2STR(bss->bssid),
-				   wpa_ssid_txt(ssid_, ssid_len));
-			*selected_ssid = ssid;
-			return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len);
-		}
-	}
-
-	return NULL;
-}
-
-
-static struct wpa_bss *
-wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
-			  struct wpa_scan_results *scan_res,
-			  struct wpa_ssid *group,
-			  struct wpa_ssid **selected_ssid)
-{
-	struct wpa_bss *selected;
-
-	wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
-		   group->priority);
-
-	/* First, try to find WPA-enabled AP */
-	selected = wpa_supplicant_select_bss_wpa(wpa_s, scan_res, group,
-						 selected_ssid);
-	if (selected)
-		return selected;
-
-	/* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
-	 * allows this. */
-	return wpa_supplicant_select_bss_non_wpa(wpa_s, scan_res, group,
-						 selected_ssid);
-}
-
-
-static struct wpa_bss *
-wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
-			    struct wpa_scan_results *scan_res,
-			    struct wpa_ssid **selected_ssid)
-{
-	struct wpa_bss *selected = NULL;
-	int prio;
-
-	while (selected == NULL) {
-		for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
-			selected = wpa_supplicant_select_bss(
-				wpa_s, scan_res, wpa_s->conf->pssid[prio],
-				selected_ssid);
-			if (selected)
-				break;
-		}
-
-		if (selected == NULL && wpa_s->blacklist) {
-			wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
-				   "and try again");
-			wpa_blacklist_clear(wpa_s);
-			wpa_s->blacklist_cleared++;
-		} else if (selected == NULL)
-			break;
-	}
-
-	return selected;
-}
-
-
-static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
-					int timeout_sec, int timeout_usec)
-{
-	if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
-		/*
-		 * No networks are enabled; short-circuit request so
-		 * we don't wait timeout seconds before transitioning
-		 * to INACTIVE state.
-		 */
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-		return;
-	}
-	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
-}
-
-
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-			    struct wpa_bss *selected,
-			    struct wpa_ssid *ssid)
-{
-	if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
-		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
-			"PBC session overlap");
-		wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-		return;
-	}
-
-	/*
-	 * Do not trigger new association unless the BSSID has changed or if
-	 * reassociation is requested. If we are in process of associating with
-	 * the selected BSSID, do not trigger new attempt.
-	 */
-	if (wpa_s->reassociate ||
-	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
-	     (wpa_s->wpa_state != WPA_ASSOCIATING ||
-	      os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
-	      0))) {
-		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
-			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-			return;
-		}
-		wpa_supplicant_associate(wpa_s, selected, ssid);
-	} else {
-		wpa_printf(MSG_DEBUG, "Already associated with the selected "
-			   "AP");
-	}
-}
-
-
-static struct wpa_ssid *
-wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
-{
-	int prio;
-	struct wpa_ssid *ssid;
-
-	for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
-		for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
-		{
-			if (ssid->disabled)
-				continue;
-			if (ssid->mode == IEEE80211_MODE_IBSS ||
-			    ssid->mode == IEEE80211_MODE_AP)
-				return ssid;
-		}
-	}
-	return NULL;
-}
-
-
-/* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based
- * on BSS added and BSS changed events */
-static void wpa_supplicant_rsn_preauth_scan_results(
-	struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res)
-{
-	int i;
-
-	if (rsn_preauth_scan_results(wpa_s->wpa) < 0)
-		return;
-
-	for (i = scan_res->num - 1; i >= 0; i--) {
-		const u8 *ssid, *rsn;
-		struct wpa_scan_res *r;
-
-		r = scan_res->res[i];
-
-		ssid = wpa_scan_get_ie(r, WLAN_EID_SSID);
-		if (ssid == NULL)
-			continue;
-
-		rsn = wpa_scan_get_ie(r, WLAN_EID_RSN);
-		if (rsn == NULL)
-			continue;
-
-		rsn_preauth_scan_result(wpa_s->wpa, r->bssid, ssid, rsn);
-	}
-
-}
-
-
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
-				       struct wpa_bss *selected,
-				       struct wpa_ssid *ssid,
-				       struct wpa_scan_results *scan_res)
-{
-	size_t i;
-	struct wpa_scan_res *current_bss = NULL;
-	int min_diff;
-
-	if (wpa_s->reassociate)
-		return 1; /* explicit request to reassociate */
-	if (wpa_s->wpa_state < WPA_ASSOCIATED)
-		return 1; /* we are not associated; continue */
-	if (wpa_s->current_ssid == NULL)
-		return 1; /* unknown current SSID */
-	if (wpa_s->current_ssid != ssid)
-		return 1; /* different network block */
-
-	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *res = scan_res->res[i];
-		const u8 *ie;
-		if (os_memcmp(res->bssid, wpa_s->bssid, ETH_ALEN) != 0)
-			continue;
-
-		ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
-		if (ie == NULL)
-			continue;
-		if (ie[1] != wpa_s->current_ssid->ssid_len ||
-		    os_memcmp(ie + 2, wpa_s->current_ssid->ssid, ie[1]) != 0)
-			continue;
-		current_bss = res;
-		break;
-	}
-
-	if (!current_bss)
-		return 1; /* current BSS not seen in scan results */
-
-	wpa_printf(MSG_DEBUG, "Considering within-ESS reassociation");
-	wpa_printf(MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
-		   MAC2STR(current_bss->bssid), current_bss->level);
-	wpa_printf(MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
-		   MAC2STR(selected->bssid), selected->level);
-
-	if (wpa_s->current_ssid->bssid_set &&
-	    os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
-	    0) {
-		wpa_printf(MSG_DEBUG, "Allow reassociation - selected BSS has "
-			   "preferred BSSID");
-		return 1;
-	}
-
-	min_diff = 2;
-	if (current_bss->level < 0) {
-		if (current_bss->level < -85)
-			min_diff = 1;
-		else if (current_bss->level < -80)
-			min_diff = 2;
-		else if (current_bss->level < -75)
-			min_diff = 3;
-		else if (current_bss->level < -70)
-			min_diff = 4;
-		else
-			min_diff = 5;
-	}
-	if (abs(current_bss->level - selected->level) < min_diff) {
-		wpa_printf(MSG_DEBUG, "Skip roam - too small difference in "
-			   "signal level");
-		return 0;
-	}
-
-	return 1;
-}
-
-
-static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
-					      union wpa_event_data *data)
-{
-	struct wpa_bss *selected;
-	struct wpa_ssid *ssid = NULL;
-	struct wpa_scan_results *scan_res;
-	int ap = 0;
-
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface)
-		ap = 1;
-#endif /* CONFIG_AP */
-
-	wpa_supplicant_notify_scanning(wpa_s, 0);
-
-	scan_res = wpa_supplicant_get_scan_results(wpa_s,
-						   data ? &data->scan_info :
-						   NULL, 1);
-	if (scan_res == NULL) {
-		if (wpa_s->conf->ap_scan == 2 || ap)
-			return;
-		wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
-			   "scanning again");
-		wpa_supplicant_req_new_scan(wpa_s, 1, 0);
-		return;
-	}
-
-	if (wpa_s->scan_res_handler) {
-		wpa_s->scan_res_handler(wpa_s, scan_res);
-		wpa_s->scan_res_handler = NULL;
-		wpa_scan_results_free(scan_res);
-		return;
-	}
-
-	if (ap) {
-		wpa_printf(MSG_DEBUG, "Ignore scan results in AP mode");
-		wpa_scan_results_free(scan_res);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "New scan results available");
-	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
-	wpas_notify_scan_results(wpa_s);
-
-	wpas_notify_scan_done(wpa_s, 1);
-
-	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
-		wpa_scan_results_free(scan_res);
-		return;
-	}
-
-	if (wpa_s->disconnected) {
-		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-		wpa_scan_results_free(scan_res);
-		return;
-	}
-
-	if (bgscan_notify_scan(wpa_s) == 1) {
-		wpa_scan_results_free(scan_res);
-		return;
-	}
-
-	wpa_supplicant_rsn_preauth_scan_results(wpa_s, scan_res);
-
-	selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
-
-	if (selected) {
-		int skip;
-		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
-						    scan_res);
-		wpa_scan_results_free(scan_res);
-		if (skip)
-			return;
-		wpa_supplicant_connect(wpa_s, selected, ssid);
-	} else {
-		wpa_scan_results_free(scan_res);
-		wpa_printf(MSG_DEBUG, "No suitable network found");
-		ssid = wpa_supplicant_pick_new_network(wpa_s);
-		if (ssid) {
-			wpa_printf(MSG_DEBUG, "Setup a new network");
-			wpa_supplicant_associate(wpa_s, NULL, ssid);
-		} else {
-			int timeout_sec = 5;
-			int timeout_usec = 0;
-			wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
-						    timeout_usec);
-		}
-	}
-}
-#endif /* CONFIG_NO_SCAN_PROCESSING */
-
-
-static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
-					  union wpa_event_data *data)
-{
-	int l, len, found = 0, wpa_found, rsn_found;
-	const u8 *p;
-
-	wpa_printf(MSG_DEBUG, "Association info event");
-	if (data->assoc_info.req_ies)
-		wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
-			    data->assoc_info.req_ies_len);
-	if (data->assoc_info.resp_ies)
-		wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
-			    data->assoc_info.resp_ies_len);
-	if (data->assoc_info.beacon_ies)
-		wpa_hexdump(MSG_DEBUG, "beacon_ies",
-			    data->assoc_info.beacon_ies,
-			    data->assoc_info.beacon_ies_len);
-	if (data->assoc_info.freq)
-		wpa_printf(MSG_DEBUG, "freq=%u MHz", data->assoc_info.freq);
-
-	p = data->assoc_info.req_ies;
-	l = data->assoc_info.req_ies_len;
-
-	/* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
-	while (p && l >= 2) {
-		len = p[1] + 2;
-		if (len > l) {
-			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
-				    p, l);
-			break;
-		}
-		if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
-		     (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
-		    (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
-			if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
-				break;
-			found = 1;
-			wpa_find_assoc_pmkid(wpa_s);
-			break;
-		}
-		l -= len;
-		p += len;
-	}
-	if (!found && data->assoc_info.req_ies)
-		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-
-#ifdef CONFIG_IEEE80211R
-#ifdef CONFIG_SME
-	if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
-		u8 bssid[ETH_ALEN];
-		if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
-		    wpa_ft_validate_reassoc_resp(wpa_s->wpa,
-						 data->assoc_info.resp_ies,
-						 data->assoc_info.resp_ies_len,
-						 bssid) < 0) {
-			wpa_printf(MSG_DEBUG, "FT: Validation of "
-				   "Reassociation Response failed");
-			wpa_supplicant_deauthenticate(
-				wpa_s, WLAN_REASON_INVALID_IE);
-			return -1;
-		}
-	}
-
-	p = data->assoc_info.resp_ies;
-	l = data->assoc_info.resp_ies_len;
-
-	/* Go through the IEs and make a copy of the MDIE, if present. */
-	while (p && l >= 2) {
-		len = p[1] + 2;
-		if (len > l) {
-			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
-				    p, l);
-			break;
-		}
-		if (p[0] == WLAN_EID_MOBILITY_DOMAIN &&
-		    p[1] >= MOBILITY_DOMAIN_ID_LEN) {
-			wpa_s->sme.ft_used = 1;
-			os_memcpy(wpa_s->sme.mobility_domain, p + 2,
-				  MOBILITY_DOMAIN_ID_LEN);
-			break;
-		}
-		l -= len;
-		p += len;
-	}
-#endif /* CONFIG_SME */
-
-	wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
-			     data->assoc_info.resp_ies_len);
-#endif /* CONFIG_IEEE80211R */
-
-	/* WPA/RSN IE from Beacon/ProbeResp */
-	p = data->assoc_info.beacon_ies;
-	l = data->assoc_info.beacon_ies_len;
-
-	/* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
-	 */
-	wpa_found = rsn_found = 0;
-	while (p && l >= 2) {
-		len = p[1] + 2;
-		if (len > l) {
-			wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
-				    p, l);
-			break;
-		}
-		if (!wpa_found &&
-		    p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
-		    os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
-			wpa_found = 1;
-			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
-		}
-
-		if (!rsn_found &&
-		    p[0] == WLAN_EID_RSN && p[1] >= 2) {
-			rsn_found = 1;
-			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
-		}
-
-		l -= len;
-		p += len;
-	}
-
-	if (!wpa_found && data->assoc_info.beacon_ies)
-		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
-	if (!rsn_found && data->assoc_info.beacon_ies)
-		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
-	if (wpa_found || rsn_found)
-		wpa_s->ap_ies_from_associnfo = 1;
-
-	wpa_s->assoc_freq = data->assoc_info.freq;
-
-	return 0;
-}
-
-
-static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
-				       union wpa_event_data *data)
-{
-	u8 bssid[ETH_ALEN];
-	int ft_completed;
-	int bssid_changed;
-	struct wpa_driver_capa capa;
-
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface) {
-		hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
-				    data->assoc_info.addr,
-				    data->assoc_info.req_ies,
-				    data->assoc_info.req_ies_len);
-		return;
-	}
-#endif /* CONFIG_AP */
-
-	ft_completed = wpa_ft_is_completed(wpa_s->wpa);
-	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
-		return;
-
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-	    (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
-	     os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) {
-		wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
-			MACSTR, MAC2STR(bssid));
-		bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN);
-		os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
-		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-		if (bssid_changed)
-			wpas_notify_bssid_changed(wpa_s);
-
-		if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
-			wpa_clear_keys(wpa_s, bssid);
-		}
-		if (wpa_supplicant_select_config(wpa_s) < 0) {
-			wpa_supplicant_disassociate(
-				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-			return;
-		}
-		if (wpa_s->current_ssid) {
-			struct wpa_bss *bss = NULL;
-			struct wpa_ssid *ssid = wpa_s->current_ssid;
-			if (ssid->ssid_len > 0)
-				bss = wpa_bss_get(wpa_s, bssid,
-						  ssid->ssid, ssid->ssid_len);
-			if (!bss)
-				bss = wpa_bss_get_bssid(wpa_s, bssid);
-			if (bss)
-				wpa_s->current_bss = bss;
-		}
-	}
-
-#ifdef CONFIG_SME
-	os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
-	wpa_s->sme.prev_bssid_set = 1;
-#endif /* CONFIG_SME */
-
-	wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
-	if (wpa_s->current_ssid) {
-		/* When using scanning (ap_scan=1), SIM PC/SC interface can be
-		 * initialized before association, but for other modes,
-		 * initialize PC/SC here, if the current configuration needs
-		 * smartcard or SIM/USIM. */
-		wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
-	}
-	wpa_sm_notify_assoc(wpa_s->wpa, bssid);
-	if (wpa_s->l2)
-		l2_packet_notify_auth_start(wpa_s->l2);
-
-	/*
-	 * Set portEnabled first to FALSE in order to get EAP state machine out
-	 * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
-	 * state machine may transit to AUTHENTICATING state based on obsolete
-	 * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
-	 * AUTHENTICATED without ever giving chance to EAP state machine to
-	 * reset the state.
-	 */
-	if (!ft_completed) {
-		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)
-		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-	/* 802.1X::portControl = Auto */
-	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
-	wpa_s->eapol_received = 0;
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
-	    (wpa_s->current_ssid &&
-	     wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-	} else if (!ft_completed) {
-		/* Timeout for receiving the first EAPOL packet */
-		wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
-	}
-	wpa_supplicant_cancel_scan(wpa_s);
-
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
-	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		/*
-		 * We are done; the driver will take care of RSN 4-way
-		 * handshake.
-		 */
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
-		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
-	}
-
-	if (wpa_s->pending_eapol_rx) {
-		struct os_time now, age;
-		os_get_time(&now);
-		os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
-		if (age.sec == 0 && age.usec < 100000 &&
-		    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
-		    0) {
-			wpa_printf(MSG_DEBUG, "Process pending EAPOL frame "
-				   "that was received just before association "
-				   "notification");
-			wpa_supplicant_rx_eapol(
-				wpa_s, wpa_s->pending_eapol_rx_src,
-				wpabuf_head(wpa_s->pending_eapol_rx),
-				wpabuf_len(wpa_s->pending_eapol_rx));
-		}
-		wpabuf_free(wpa_s->pending_eapol_rx);
-		wpa_s->pending_eapol_rx = NULL;
-	}
-
-#ifdef CONFIG_BGSCAN
-	if (wpa_s->current_ssid != wpa_s->bgscan_ssid) {
-		bgscan_deinit(wpa_s);
-		if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
-			if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
-				wpa_printf(MSG_DEBUG, "Failed to initialize "
-					   "bgscan");
-				/*
-				 * Live without bgscan; it is only used as a
-				 * roaming optimization, so the initial
-				 * connection is not affected.
-				 */
-			} else
-				wpa_s->bgscan_ssid = wpa_s->current_ssid;
-		} else
-			wpa_s->bgscan_ssid = NULL;
-	}
-#endif /* CONFIG_BGSCAN */
-
-	if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
-	     wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
-	    wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
-	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
-		/* Set static WEP keys again */
-		wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
-	}
-}
-
-
-static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
-					  u16 reason_code)
-{
-	const u8 *bssid;
-#ifdef CONFIG_SME
-	int authenticating;
-	u8 prev_pending_bssid[ETH_ALEN];
-
-	authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
-	os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
-#endif /* CONFIG_SME */
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
-		/*
-		 * At least Host AP driver and a Prism3 card seemed to be
-		 * generating streams of disconnected events when configuring
-		 * IBSS for WPA-None. Ignore them for now.
-		 */
-		wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
-			   "IBSS/WPA-None mode");
-		return;
-	}
-
-	if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
-			"pre-shared key may be incorrect");
-	}
-	if (wpa_s->wpa_state >= WPA_ASSOCIATED)
-		wpa_supplicant_req_scan(wpa_s, 0, 100000);
-	bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid))
-		bssid = wpa_s->pending_bssid;
-	wpa_blacklist_add(wpa_s, bssid);
-	wpa_sm_notify_disassoc(wpa_s->wpa);
-	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
-		" reason=%d",
-		MAC2STR(bssid), reason_code);
-	if (wpa_supplicant_dynamic_keys(wpa_s)) {
-		wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
-		wpa_s->keys_cleared = 0;
-		wpa_clear_keys(wpa_s, wpa_s->bssid);
-	}
-	wpa_supplicant_mark_disassoc(wpa_s);
-	bgscan_deinit(wpa_s);
-	wpa_s->bgscan_ssid = NULL;
-#ifdef CONFIG_SME
-	if (authenticating &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
-		/*
-		 * mac80211-workaround to force deauth on failed auth cmd,
-		 * requires us to remain in authenticating state to allow the
-		 * second authentication attempt to be continued properly.
-		 */
-		wpa_printf(MSG_DEBUG, "SME: Allow pending authentication to "
-			   "proceed after disconnection event");
-		wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
-		os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
-	}
-#endif /* CONFIG_SME */
-}
-
-
-#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
-static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
-						    void *sock_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-
-	if (!wpa_s->pending_mic_error_report)
-		return;
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending pending MIC error report");
-	wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
-	wpa_s->pending_mic_error_report = 0;
-}
-#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
-
-
-static void
-wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
-					 union wpa_event_data *data)
-{
-	int pairwise;
-	struct os_time t;
-
-	wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
-	pairwise = (data && data->michael_mic_failure.unicast);
-	os_get_time(&t);
-	if ((wpa_s->last_michael_mic_error &&
-	     t.sec - wpa_s->last_michael_mic_error <= 60) ||
-	    wpa_s->pending_mic_error_report) {
-		if (wpa_s->pending_mic_error_report) {
-			/*
-			 * Send the pending MIC error report immediately since
-			 * we are going to start countermeasures and AP better
-			 * do the same.
-			 */
-			wpa_sm_key_request(wpa_s->wpa, 1,
-					   wpa_s->pending_mic_error_pairwise);
-		}
-
-		/* Send the new MIC error report immediately since we are going
-		 * to start countermeasures and AP better do the same.
-		 */
-		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
-
-		/* initialize countermeasures */
-		wpa_s->countermeasures = 1;
-		wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
-
-		/*
-		 * Need to wait for completion of request frame. We do not get
-		 * any callback for the message completion, so just wait a
-		 * short while and hope for the best. */
-		os_sleep(0, 10000);
-
-		wpa_drv_set_countermeasures(wpa_s, 1);
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_MICHAEL_MIC_FAILURE);
-		eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
-				     wpa_s, NULL);
-		eloop_register_timeout(60, 0,
-				       wpa_supplicant_stop_countermeasures,
-				       wpa_s, NULL);
-		/* TODO: mark the AP rejected for 60 second. STA is
-		 * allowed to associate with another AP.. */
-	} else {
-#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
-		if (wpa_s->mic_errors_seen) {
-			/*
-			 * Reduce the effectiveness of Michael MIC error
-			 * reports as a means for attacking against TKIP if
-			 * more than one MIC failure is noticed with the same
-			 * PTK. We delay the transmission of the reports by a
-			 * random time between 0 and 60 seconds in order to
-			 * force the attacker wait 60 seconds before getting
-			 * the information on whether a frame resulted in a MIC
-			 * failure.
-			 */
-			u8 rval[4];
-			int sec;
-
-			if (os_get_random(rval, sizeof(rval)) < 0)
-				sec = os_random() % 60;
-			else
-				sec = WPA_GET_BE32(rval) % 60;
-			wpa_printf(MSG_DEBUG, "WPA: Delay MIC error report %d "
-				   "seconds", sec);
-			wpa_s->pending_mic_error_report = 1;
-			wpa_s->pending_mic_error_pairwise = pairwise;
-			eloop_cancel_timeout(
-				wpa_supplicant_delayed_mic_error_report,
-				wpa_s, NULL);
-			eloop_register_timeout(
-				sec, os_random() % 1000000,
-				wpa_supplicant_delayed_mic_error_report,
-				wpa_s, NULL);
-		} else {
-			wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
-		}
-#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
-		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
-#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
-	}
-	wpa_s->last_michael_mic_error = t.sec;
-	wpa_s->mic_errors_seen++;
-}
-
-
-#ifdef CONFIG_TERMINATE_ONLASTIF
-static int any_interfaces(struct wpa_supplicant *head)
-{
-	struct wpa_supplicant *wpa_s;
-
-	for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next)
-		if (!wpa_s->interface_removed)
-			return 1;
-	return 0;
-}
-#endif /* CONFIG_TERMINATE_ONLASTIF */
-
-
-static void
-wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
-				      union wpa_event_data *data)
-{
-	if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
-		return;
-
-	switch (data->interface_status.ievent) {
-	case EVENT_INTERFACE_ADDED:
-		if (!wpa_s->interface_removed)
-			break;
-		wpa_s->interface_removed = 0;
-		wpa_printf(MSG_DEBUG, "Configured interface was added.");
-		if (wpa_supplicant_driver_init(wpa_s) < 0) {
-			wpa_printf(MSG_INFO, "Failed to initialize the driver "
-				   "after interface was added.");
-		}
-		break;
-	case EVENT_INTERFACE_REMOVED:
-		wpa_printf(MSG_DEBUG, "Configured interface was removed.");
-		wpa_s->interface_removed = 1;
-		wpa_supplicant_mark_disassoc(wpa_s);
-		l2_packet_deinit(wpa_s->l2);
-		wpa_s->l2 = NULL;
-#ifdef CONFIG_TERMINATE_ONLASTIF
-		/* check if last interface */
-		if (!any_interfaces(wpa_s->global->ifaces))
-			eloop_terminate();
-#endif /* CONFIG_TERMINATE_ONLASTIF */
-		break;
-	}
-}
-
-
-#ifdef CONFIG_PEERKEY
-static void
-wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
-			      union wpa_event_data *data)
-{
-	if (data == NULL)
-		return;
-	wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
-}
-#endif /* CONFIG_PEERKEY */
-
-
-#ifdef CONFIG_IEEE80211R
-static void
-wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
-				 union wpa_event_data *data)
-{
-	if (data == NULL)
-		return;
-
-	if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies,
-				    data->ft_ies.ies_len,
-				    data->ft_ies.ft_action,
-				    data->ft_ies.target_ap,
-				    data->ft_ies.ric_ies,
-				    data->ft_ies.ric_ies_len) < 0) {
-		/* TODO: prevent MLME/driver from trying to associate? */
-	}
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_IBSS_RSN
-static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
-						union wpa_event_data *data)
-{
-	if (data == NULL)
-		return;
-	ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
-}
-#endif /* CONFIG_IBSS_RSN */
-
-
-#ifdef CONFIG_IEEE80211R
-static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
-			 size_t len)
-{
-	const u8 *sta_addr, *target_ap_addr;
-	u16 status;
-
-	wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len);
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
-		return; /* only SME case supported for now */
-	if (len < 1 + 2 * ETH_ALEN + 2)
-		return;
-	if (data[0] != 2)
-		return; /* Only FT Action Response is supported for now */
-	sta_addr = data + 1;
-	target_ap_addr = data + 1 + ETH_ALEN;
-	status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN);
-	wpa_printf(MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR
-		   " TargetAP " MACSTR " status %u",
-		   MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
-
-	if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FT: Foreign STA Address " MACSTR
-			   " in FT Action Response", MAC2STR(sta_addr));
-		return;
-	}
-
-	if (status) {
-		wpa_printf(MSG_DEBUG, "FT: FT Action Response indicates "
-			   "failure (status code %d)", status);
-		/* TODO: report error to FT code(?) */
-		return;
-	}
-
-	if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2,
-				    len - (1 + 2 * ETH_ALEN + 2), 1,
-				    target_ap_addr, NULL, 0) < 0)
-		return;
-
-#ifdef CONFIG_SME
-	{
-		struct wpa_bss *bss;
-		bss = wpa_bss_get_bssid(wpa_s, target_ap_addr);
-		if (bss)
-			wpa_s->sme.freq = bss->freq;
-		wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT;
-		sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr,
-			      WLAN_AUTH_FT);
-	}
-#endif /* CONFIG_SME */
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
-			  union wpa_event_data *data)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	u16 reason_code = 0;
-
-	switch (event) {
-	case EVENT_AUTH:
-		sme_event_auth(wpa_s, data);
-		break;
-	case EVENT_ASSOC:
-		wpa_supplicant_event_assoc(wpa_s, data);
-		break;
-	case EVENT_DISASSOC:
-		wpa_printf(MSG_DEBUG, "Disassociation notification");
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
-			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
-					       data->disassoc_info.addr);
-			break;
-		}
-#endif /* CONFIG_AP */
-		if (data)
-			reason_code = data->deauth_info.reason_code;
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-			sme_event_disassoc(wpa_s, data);
-		/* fall through */
-	case EVENT_DEAUTH:
-		if (event == EVENT_DEAUTH) {
-			wpa_printf(MSG_DEBUG, "Deauthentication notification");
-			if (data)
-				reason_code = data->deauth_info.reason_code;
-		}
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface && data && data->deauth_info.addr) {
-			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
-					       data->deauth_info.addr);
-			break;
-		}
-#endif /* CONFIG_AP */
-		wpa_supplicant_event_disassoc(wpa_s, reason_code);
-		break;
-	case EVENT_MICHAEL_MIC_FAILURE:
-		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
-		break;
-#ifndef CONFIG_NO_SCAN_PROCESSING
-	case EVENT_SCAN_RESULTS:
-		wpa_supplicant_event_scan_results(wpa_s, data);
-		break;
-#endif /* CONFIG_NO_SCAN_PROCESSING */
-	case EVENT_ASSOCINFO:
-		wpa_supplicant_event_associnfo(wpa_s, data);
-		break;
-	case EVENT_INTERFACE_STATUS:
-		wpa_supplicant_event_interface_status(wpa_s, data);
-		break;
-	case EVENT_PMKID_CANDIDATE:
-		wpa_supplicant_event_pmkid_candidate(wpa_s, data);
-		break;
-#ifdef CONFIG_PEERKEY
-	case EVENT_STKSTART:
-		wpa_supplicant_event_stkstart(wpa_s, data);
-		break;
-#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
-	case EVENT_FT_RESPONSE:
-		wpa_supplicant_event_ft_response(wpa_s, data);
-		break;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IBSS_RSN
-	case EVENT_IBSS_RSN_START:
-		wpa_supplicant_event_ibss_rsn_start(wpa_s, data);
-		break;
-#endif /* CONFIG_IBSS_RSN */
-	case EVENT_ASSOC_REJECT:
-		sme_event_assoc_reject(wpa_s, data);
-		break;
-	case EVENT_AUTH_TIMED_OUT:
-		sme_event_auth_timed_out(wpa_s, data);
-		break;
-	case EVENT_ASSOC_TIMED_OUT:
-		sme_event_assoc_timed_out(wpa_s, data);
-		break;
-#ifdef CONFIG_AP
-	case EVENT_TX_STATUS:
-		if (wpa_s->ap_iface == NULL)
-			break;
-		switch (data->tx_status.type) {
-		case WLAN_FC_TYPE_MGMT:
-			ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
-				      data->tx_status.data_len,
-				      data->tx_status.stype,
-				      data->tx_status.ack);
-			break;
-		case WLAN_FC_TYPE_DATA:
-			ap_tx_status(wpa_s, data->tx_status.dst,
-				     data->tx_status.data,
-				     data->tx_status.data_len,
-				     data->tx_status.ack);
-			break;
-		}
-		break;
-	case EVENT_RX_FROM_UNKNOWN:
-		if (wpa_s->ap_iface == NULL)
-			break;
-		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.frame,
-				       data->rx_from_unknown.len);
-		break;
-	case EVENT_RX_MGMT:
-		if (wpa_s->ap_iface == NULL)
-			break;
-		ap_mgmt_rx(wpa_s, &data->rx_mgmt);
-		break;
-#endif /* CONFIG_AP */
-	case EVENT_RX_ACTION:
-		wpa_printf(MSG_DEBUG, "Received Action frame: SA=" MACSTR
-			   " Category=%u DataLen=%d freq=%d MHz",
-			   MAC2STR(data->rx_action.sa),
-			   data->rx_action.category, (int) data->rx_action.len,
-			   data->rx_action.freq);
-#ifdef CONFIG_IEEE80211R
-		if (data->rx_action.category == WLAN_ACTION_FT) {
-			ft_rx_action(wpa_s, data->rx_action.data,
-				     data->rx_action.len);
-			break;
-		}
-#endif /* CONFIG_IEEE80211R */
-		break;
-#ifdef CONFIG_CLIENT_MLME
-	case EVENT_MLME_RX: {
-		struct ieee80211_rx_status rx_status;
-		os_memset(&rx_status, 0, sizeof(rx_status));
-		rx_status.freq = data->mlme_rx.freq;
-		rx_status.channel = data->mlme_rx.channel;
-		rx_status.ssi = data->mlme_rx.ssi;
-		ieee80211_sta_rx(wpa_s, data->mlme_rx.buf, data->mlme_rx.len,
-				 &rx_status);
-		break;
-	}
-#endif /* CONFIG_CLIENT_MLME */
-	case EVENT_EAPOL_RX:
-		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
-					data->eapol_rx.data,
-					data->eapol_rx.data_len);
-		break;
-	case EVENT_SIGNAL_CHANGE:
-		bgscan_notify_signal_change(
-			wpa_s, data->signal_change.above_threshold);
-		break;
-	default:
-		wpa_printf(MSG_INFO, "Unknown event %d", event);
-		break;
-	}
-}

Copied: vendor/wpa/2.0/wpa_supplicant/events.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/events.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/events.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/events.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2941 @@
+/*
+ * WPA Supplicant - Driver event processing
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "l2_packet/l2_packet.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "pcsc_funcs.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "common/wpa_ctrl.h"
+#include "eap_peer/eap.h"
+#include "ap/hostapd.h"
+#include "p2p/p2p.h"
+#include "wnm_sta.h"
+#include "notify.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/random.h"
+#include "blacklist.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "sme.h"
+#include "gas_query.h"
+#include "p2p_supplicant.h"
+#include "bgscan.h"
+#include "autoscan.h"
+#include "ap.h"
+#include "bss.h"
+#include "scan.h"
+#include "offchannel.h"
+#include "interworking.h"
+
+
+static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+	struct os_time now;
+
+	if (ssid == NULL || ssid->disabled_until.sec == 0)
+		return 0;
+
+	os_get_time(&now);
+	if (ssid->disabled_until.sec > now.sec)
+		return ssid->disabled_until.sec - now.sec;
+
+	wpas_clear_temp_disabled(wpa_s, ssid, 0);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid, *old_ssid;
+	int res;
+
+	if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
+		return 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
+		"information");
+	ssid = wpa_supplicant_get_ssid(wpa_s);
+	if (ssid == NULL) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"No network configuration found for the current AP");
+		return -1;
+	}
+
+	if (wpas_network_disabled(wpa_s, ssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
+		return -1;
+	}
+
+	if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+	    disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+		return -1;
+	}
+
+	res = wpas_temp_disabled(wpa_s, ssid);
+	if (res > 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
+			"disabled for %d second(s)", res);
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
+		"current AP");
+	if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
+		u8 wpa_ie[80];
+		size_t wpa_ie_len = sizeof(wpa_ie);
+		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+					  wpa_ie, &wpa_ie_len);
+	} else {
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+	}
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid)
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+	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)
+		wpas_notify_network_changed(wpa_s);
+
+	return 0;
+}
+
+
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->countermeasures) {
+		wpa_s->countermeasures = 0;
+		wpa_drv_set_countermeasures(wpa_s, 0);
+		wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+}
+
+
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
+{
+	int bssid_changed;
+
+	wnm_bss_keep_alive_deinit(wpa_s);
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_AP
+	wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+		return;
+
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+	os_memset(wpa_s->bssid, 0, ETH_ALEN);
+	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+#ifdef CONFIG_P2P
+	os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+#endif /* CONFIG_P2P */
+	wpa_s->current_bss = NULL;
+	wpa_s->assoc_freq = 0;
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SME
+	if (wpa_s->sme.ft_ies)
+		sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211R */
+
+	if (bssid_changed)
+		wpas_notify_bssid_changed(wpa_s);
+
+	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	wpa_s->ap_ies_from_associnfo = 0;
+	wpa_s->current_ssid = NULL;
+	wpa_s->key_mgmt = 0;
+}
+
+
+static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ie_data ie;
+	int pmksa_set = -1;
+	size_t i;
+
+	if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
+	    ie.pmkid == NULL)
+		return;
+
+	for (i = 0; i < ie.num_pmkid; i++) {
+		pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
+						    ie.pmkid + i * PMKID_LEN,
+						    NULL, NULL, 0);
+		if (pmksa_set == 0) {
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+			break;
+		}
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from "
+		"PMKSA cache", pmksa_set == 0 ? "" : "not ");
+}
+
+
+static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
+						 union wpa_event_data *data)
+{
+	if (data == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: No data in PMKID candidate "
+			"event");
+		return;
+	}
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
+		" index=%d preauth=%d",
+		MAC2STR(data->pmkid_candidate.bssid),
+		data->pmkid_candidate.index,
+		data->pmkid_candidate.preauth);
+
+	pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
+			    data->pmkid_candidate.index,
+			    data->pmkid_candidate.preauth);
+}
+
+
+static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
+		return 0;
+
+#ifdef IEEE8021X_EAPOL
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+	    wpa_s->current_ssid &&
+	    !(wpa_s->current_ssid->eapol_flags &
+	      (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+	       EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
+		/* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
+		 * plaintext or static WEP keys). */
+		return 0;
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	return 1;
+}
+
+
+/**
+ * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
+ * @wpa_s: pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when starting authentication with a network that is
+ * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
+ */
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+#ifdef IEEE8021X_EAPOL
+#ifdef PCSC_FUNCS
+	int aka = 0, sim = 0, type;
+
+	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+		return 0;
+
+	if (ssid->eap.eap_methods == NULL) {
+		sim = 1;
+		aka = 1;
+	} else {
+		struct eap_method_type *eap = ssid->eap.eap_methods;
+		while (eap->vendor != EAP_VENDOR_IETF ||
+		       eap->method != EAP_TYPE_NONE) {
+			if (eap->vendor == EAP_VENDOR_IETF) {
+				if (eap->method == EAP_TYPE_SIM)
+					sim = 1;
+				else if (eap->method == EAP_TYPE_AKA ||
+					 eap->method == EAP_TYPE_AKA_PRIME)
+					aka = 1;
+			}
+			eap++;
+		}
+	}
+
+	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
+		sim = 0;
+	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL &&
+	    eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME) ==
+	    NULL)
+		aka = 0;
+
+	if (!sim && !aka) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to "
+			"use SIM, but neither EAP-SIM nor EAP-AKA are "
+			"enabled");
+		return 0;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
+		"(sim=%d aka=%d) - initialize PCSC", sim, aka);
+	if (sim && aka)
+		type = SCARD_TRY_BOTH;
+	else if (aka)
+		type = SCARD_USIM_ONLY;
+	else
+		type = SCARD_GSM_SIM_ONLY;
+
+	wpa_s->scard = scard_init(type, NULL);
+	if (wpa_s->scard == NULL) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
+			"(pcsc-lite)");
+		return -1;
+	}
+	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+#endif /* IEEE8021X_EAPOL */
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
+					struct wpa_ssid *ssid)
+{
+	int i, privacy = 0;
+
+	if (ssid->mixed_cell)
+		return 1;
+
+#ifdef CONFIG_WPS
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		return 1;
+#endif /* CONFIG_WPS */
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i]) {
+			privacy = 1;
+			break;
+		}
+	}
+#ifdef IEEE8021X_EAPOL
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+	    ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+				 EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
+		privacy = 1;
+#endif /* IEEE8021X_EAPOL */
+
+	if (wpa_key_mgmt_wpa(ssid->key_mgmt))
+		privacy = 1;
+
+	if (bss->caps & IEEE80211_CAP_PRIVACY)
+		return privacy;
+	return !privacy;
+}
+
+
+static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid,
+					 struct wpa_bss *bss)
+{
+	struct wpa_ie_data ie;
+	int proto_match = 0;
+	const u8 *rsn_ie, *wpa_ie;
+	int ret;
+	int wep_ok;
+
+	ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
+	if (ret >= 0)
+		return ret;
+
+	/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
+	wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+		(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+		  ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
+		 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+
+	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+		proto_match++;
+
+		if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - parse "
+				"failed");
+			break;
+		}
+
+		if (wep_ok &&
+		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+				"in RSN IE");
+			return 1;
+		}
+
+		if (!(ie.proto & ssid->proto)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - proto "
+				"mismatch");
+			break;
+		}
+
+		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - PTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.group_cipher & ssid->group_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - GTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.key_mgmt & ssid->key_mgmt)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - key mgmt "
+				"mismatch");
+			break;
+		}
+
+#ifdef CONFIG_IEEE80211W
+		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+		    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		     wpa_s->conf->pmf : ssid->ieee80211w) ==
+		    MGMT_FRAME_PROTECTION_REQUIRED) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
+				"frame protection");
+			break;
+		}
+#endif /* CONFIG_IEEE80211W */
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on RSN IE");
+		return 1;
+	}
+
+	wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
+		proto_match++;
+
+		if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - parse "
+				"failed");
+			break;
+		}
+
+		if (wep_ok &&
+		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+				"in WPA IE");
+			return 1;
+		}
+
+		if (!(ie.proto & ssid->proto)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - proto "
+				"mismatch");
+			break;
+		}
+
+		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - PTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.group_cipher & ssid->group_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - GTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.key_mgmt & ssid->key_mgmt)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - key mgmt "
+				"mismatch");
+			break;
+		}
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on WPA IE");
+		return 1;
+	}
+
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
+	    !rsn_ie) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   allow for non-WPA IEEE 802.1X");
+		return 1;
+	}
+
+	if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
+	    wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no WPA/RSN proto match");
+		return 0;
+	}
+
+	if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   allow in non-WPA/WPA2");
+		return 1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "   reject due to mismatch with "
+		"WPA/WPA2");
+
+	return 0;
+}
+
+
+static int freq_allowed(int *freqs, int freq)
+{
+	int i;
+
+	if (freqs == NULL)
+		return 1;
+
+	for (i = 0; freqs[i]; i++)
+		if (freqs[i] == freq)
+			return 1;
+	return 0;
+}
+
+
+static int ht_supported(const struct hostapd_hw_modes *mode)
+{
+	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+		/*
+		 * The driver did not indicate whether it supports HT. Assume
+		 * it does to avoid connection issues.
+		 */
+		return 1;
+	}
+
+	/*
+	 * IEEE Std 802.11n-2009 20.1.1:
+	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
+	 */
+	return mode->mcs_set[0] == 0xff;
+}
+
+
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	const struct hostapd_hw_modes *mode = NULL, *modes;
+	const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
+	const u8 *rate_ie;
+	int i, j, k;
+
+	if (bss->freq == 0)
+		return 1; /* Cannot do matching without knowing band */
+
+	modes = wpa_s->hw.modes;
+	if (modes == NULL) {
+		/*
+		 * The driver does not provide any additional information
+		 * about the utilized hardware, so allow the connection attempt
+		 * to continue.
+		 */
+		return 1;
+	}
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			int freq = modes[i].channels[j].freq;
+			if (freq == bss->freq) {
+				if (mode &&
+				    mode->mode == HOSTAPD_MODE_IEEE80211G)
+					break; /* do not allow 802.11b replace
+						* 802.11g */
+				mode = &modes[i];
+				break;
+			}
+		}
+	}
+
+	if (mode == NULL)
+		return 0;
+
+	for (i = 0; i < (int) sizeof(scan_ie); i++) {
+		rate_ie = wpa_bss_get_ie(bss, scan_ie[i]);
+		if (rate_ie == NULL)
+			continue;
+
+		for (j = 2; j < rate_ie[1] + 2; j++) {
+			int flagged = !!(rate_ie[j] & 0x80);
+			int r = (rate_ie[j] & 0x7f) * 5;
+
+			/*
+			 * IEEE Std 802.11n-2009 7.3.2.2:
+			 * The new BSS Membership selector value is encoded
+			 * like a legacy basic rate, but it is not a rate and
+			 * only indicates if the BSS members are required to
+			 * support the mandatory features of Clause 20 [HT PHY]
+			 * in order to join the BSS.
+			 */
+			if (flagged && ((rate_ie[j] & 0x7f) ==
+					BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
+				if (!ht_supported(mode)) {
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   hardware does not support "
+						"HT PHY");
+					return 0;
+				}
+				continue;
+			}
+
+			if (!flagged)
+				continue;
+
+			/* check for legacy basic rates */
+			for (k = 0; k < mode->num_rates; k++) {
+				if (mode->rates[k] == r)
+					break;
+			}
+			if (k == mode->num_rates) {
+				/*
+				 * IEEE Std 802.11-2007 7.3.2.2 demands that in
+				 * order to join a BSS all required rates
+				 * have to be supported by the hardware.
+				 */
+				wpa_dbg(wpa_s, MSG_DEBUG, "   hardware does "
+					"not support required rate %d.%d Mbps",
+					r / 10, r % 10);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+					    int i, struct wpa_bss *bss,
+					    struct wpa_ssid *group)
+{
+	u8 wpa_ie_len, rsn_ie_len;
+	int wpa;
+	struct wpa_blacklist *e;
+	const u8 *ie;
+	struct wpa_ssid *ssid;
+
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	wpa_ie_len = ie ? ie[1] : 0;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	rsn_ie_len = ie ? ie[1] : 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
+		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
+		i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
+		wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+
+	e = wpa_blacklist_get(wpa_s, bss->bssid);
+	if (e) {
+		int limit = 1;
+		if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
+			/*
+			 * When only a single network is enabled, we can
+			 * trigger blacklisting on the first failure. This
+			 * should not be done with multiple enabled networks to
+			 * avoid getting forced to move into a worse ESS on
+			 * single error if there are no other BSSes of the
+			 * current ESS.
+			 */
+			limit = 0;
+		}
+		if (e->count > limit) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+				"(count=%d limit=%d)", e->count, limit);
+			return NULL;
+		}
+	}
+
+	if (bss->ssid_len == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
+		return NULL;
+	}
+
+	if (disallowed_bssid(wpa_s, bss->bssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
+		return NULL;
+	}
+
+	if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
+		return NULL;
+	}
+
+	wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
+
+	for (ssid = group; ssid; ssid = ssid->pnext) {
+		int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
+		int res;
+
+		if (wpas_network_disabled(wpa_s, ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
+			continue;
+		}
+
+		res = wpas_temp_disabled(wpa_s, ssid);
+		if (res > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled "
+				"temporarily for %d second(s)", res);
+			continue;
+		}
+
+#ifdef CONFIG_WPS
+		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+				"(WPS)");
+			continue;
+		}
+
+		if (wpa && ssid->ssid_len == 0 &&
+		    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+			check_ssid = 0;
+
+		if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+			/* Only allow wildcard SSID match if an AP
+			 * advertises active WPS operation that matches
+			 * with our mode. */
+			check_ssid = 1;
+			if (ssid->ssid_len == 0 &&
+			    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+				check_ssid = 0;
+		}
+#endif /* CONFIG_WPS */
+
+		if (ssid->bssid_set && ssid->ssid_len == 0 &&
+		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+			check_ssid = 0;
+
+		if (check_ssid &&
+		    (bss->ssid_len != ssid->ssid_len ||
+		     os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID mismatch");
+			continue;
+		}
+
+		if (ssid->bssid_set &&
+		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID mismatch");
+			continue;
+		}
+
+		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+			continue;
+
+		if (!wpa &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - non-WPA network "
+				"not allowed");
+			continue;
+		}
+
+		if (!wpa_supplicant_match_privacy(bss, ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
+				"mismatch");
+			continue;
+		}
+
+		if (bss->caps & IEEE80211_CAP_IBSS) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "
+				"network");
+			continue;
+		}
+
+		if (!freq_allowed(ssid->freq_list, bss->freq)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not "
+				"allowed");
+			continue;
+		}
+
+		if (!rate_match(wpa_s, bss)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
+				"not match");
+			continue;
+		}
+
+#ifdef CONFIG_P2P
+		/*
+		 * TODO: skip the AP if its P2P IE has Group Formation
+		 * bit set in the P2P Group Capability Bitmap and we
+		 * are not in Group Formation with that device.
+		 */
+#endif /* CONFIG_P2P */
+
+		/* Matching configuration found */
+		return ssid;
+	}
+
+	/* No matching configuration found */
+	return NULL;
+}
+
+
+static struct wpa_bss *
+wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
+			  struct wpa_ssid *group,
+			  struct wpa_ssid **selected_ssid)
+{
+	unsigned int i;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
+		group->priority);
+
+	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+		struct wpa_bss *bss = wpa_s->last_scan_res[i];
+		*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group);
+		if (!*selected_ssid)
+			continue;
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
+			" ssid='%s'",
+			MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		return bss;
+	}
+
+	return NULL;
+}
+
+
+static struct wpa_bss *
+wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+			    struct wpa_ssid **selected_ssid)
+{
+	struct wpa_bss *selected = NULL;
+	int prio;
+
+	if (wpa_s->last_scan_res == NULL ||
+	    wpa_s->last_scan_res_used == 0)
+		return NULL; /* no scan results from last update */
+
+	while (selected == NULL) {
+		for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+			selected = wpa_supplicant_select_bss(
+				wpa_s, wpa_s->conf->pssid[prio],
+				selected_ssid);
+			if (selected)
+				break;
+		}
+
+		if (selected == NULL && wpa_s->blacklist &&
+		    !wpa_s->countermeasures) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
+				"blacklist and try again");
+			wpa_blacklist_clear(wpa_s);
+			wpa_s->blacklist_cleared++;
+		} else if (selected == NULL)
+			break;
+	}
+
+	return selected;
+}
+
+
+static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
+					int timeout_sec, int timeout_usec)
+{
+	if (!wpa_supplicant_enabled_networks(wpa_s)) {
+		/*
+		 * No networks are enabled; short-circuit request so
+		 * we don't wait timeout seconds before transitioning
+		 * to INACTIVE state.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
+			"since there are no enabled networks");
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+#ifdef CONFIG_P2P
+		wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+		return;
+	}
+
+	wpa_s->scan_for_connection = 1;
+	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
+}
+
+
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid)
+{
+	if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
+			"PBC session overlap");
+#ifdef CONFIG_P2P
+		if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
+			return -1;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+		wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+		return -1;
+	}
+
+	/*
+	 * Do not trigger new association unless the BSSID has changed or if
+	 * reassociation is requested. If we are in process of associating with
+	 * the selected BSSID, do not trigger new attempt.
+	 */
+	if (wpa_s->reassociate ||
+	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
+	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
+	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
+	      os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+	      0))) {
+		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
+			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
+			return 0;
+		}
+		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
+			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
+			"  pending: " MACSTR "  wpa_state: %s",
+			wpa_s->reassociate, MAC2STR(selected->bssid),
+			MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+			wpa_supplicant_state_txt(wpa_s->wpa_state));
+		wpa_supplicant_associate(wpa_s, selected, ssid);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
+			"selected AP");
+	}
+
+	return 0;
+}
+
+
+static struct wpa_ssid *
+wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
+{
+	int prio;
+	struct wpa_ssid *ssid;
+
+	for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+		for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
+		{
+			if (wpas_network_disabled(wpa_s, ssid))
+				continue;
+			if (ssid->mode == IEEE80211_MODE_IBSS ||
+			    ssid->mode == IEEE80211_MODE_AP)
+				return ssid;
+		}
+	}
+	return NULL;
+}
+
+
+/* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based
+ * on BSS added and BSS changed events */
+static void wpa_supplicant_rsn_preauth_scan_results(
+	struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	if (rsn_preauth_scan_results(wpa_s->wpa) < 0)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		const u8 *ssid, *rsn;
+
+		ssid = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+		if (ssid == NULL)
+			continue;
+
+		rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (rsn == NULL)
+			continue;
+
+		rsn_preauth_scan_result(wpa_s->wpa, bss->bssid, ssid, rsn);
+	}
+
+}
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+				       struct wpa_bss *selected,
+				       struct wpa_ssid *ssid)
+{
+	struct wpa_bss *current_bss = NULL;
+	int min_diff;
+
+	if (wpa_s->reassociate)
+		return 1; /* explicit request to reassociate */
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return 1; /* we are not associated; continue */
+	if (wpa_s->current_ssid == NULL)
+		return 1; /* unknown current SSID */
+	if (wpa_s->current_ssid != ssid)
+		return 1; /* different network block */
+
+	if (wpas_driver_bss_selection(wpa_s))
+		return 0; /* Driver-based roaming */
+
+	if (wpa_s->current_ssid->ssid)
+		current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+					  wpa_s->current_ssid->ssid,
+					  wpa_s->current_ssid->ssid_len);
+	if (!current_bss)
+		current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+	if (!current_bss)
+		return 1; /* current BSS not seen in scan results */
+
+	if (current_bss == selected)
+		return 0;
+
+	if (selected->last_update_idx > current_bss->last_update_idx)
+		return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+	wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
+	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
+		MAC2STR(current_bss->bssid), current_bss->level);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
+		MAC2STR(selected->bssid), selected->level);
+
+	if (wpa_s->current_ssid->bssid_set &&
+	    os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
+	    0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS "
+			"has preferred BSSID");
+		return 1;
+	}
+
+	if (current_bss->level < 0 && current_bss->level > selected->level) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+			"signal level");
+		return 0;
+	}
+
+	min_diff = 2;
+	if (current_bss->level < 0) {
+		if (current_bss->level < -85)
+			min_diff = 1;
+		else if (current_bss->level < -80)
+			min_diff = 2;
+		else if (current_bss->level < -75)
+			min_diff = 3;
+		else if (current_bss->level < -70)
+			min_diff = 4;
+		else
+			min_diff = 5;
+	}
+	if (abs(current_bss->level - selected->level) < min_diff) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
+			"in signal level");
+		return 0;
+	}
+
+	return 1;
+#else /* CONFIG_NO_ROAMING */
+	return 0;
+#endif /* CONFIG_NO_ROAMING */
+}
+
+
+/* Return != 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
+static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+					      union wpa_event_data *data)
+{
+	struct wpa_scan_results *scan_res;
+	int ap = 0;
+#ifndef CONFIG_NO_RANDOM_POOL
+	size_t i, num;
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface)
+		ap = 1;
+#endif /* CONFIG_AP */
+
+	wpa_supplicant_notify_scanning(wpa_s, 0);
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete &&
+	    !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
+	    !wpa_s->scan_res_handler) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"stopped scan processing");
+			wpa_s->sta_scan_pending = 1;
+			wpa_supplicant_req_scan(wpa_s, 5, 0);
+			return -1;
+		}
+	}
+	wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+
+	scan_res = wpa_supplicant_get_scan_results(wpa_s,
+						   data ? &data->scan_info :
+						   NULL, 1);
+	if (scan_res == NULL) {
+		if (wpa_s->conf->ap_scan == 2 || ap)
+			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);
+		return -1;
+	}
+
+#ifndef CONFIG_NO_RANDOM_POOL
+	num = scan_res->num;
+	if (num > 10)
+		num = 10;
+	for (i = 0; i < num; i++) {
+		u8 buf[5];
+		struct wpa_scan_res *res = scan_res->res[i];
+		buf[0] = res->bssid[5];
+		buf[1] = res->qual & 0xff;
+		buf[2] = res->noise & 0xff;
+		buf[3] = res->level & 0xff;
+		buf[4] = res->tsf & 0xff;
+		random_add_randomness(buf, sizeof(buf));
+	}
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+	if (wpa_s->scan_res_handler) {
+		void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+					 struct wpa_scan_results *scan_res);
+
+		scan_res_handler = wpa_s->scan_res_handler;
+		wpa_s->scan_res_handler = NULL;
+		scan_res_handler(wpa_s, scan_res);
+
+		wpa_scan_results_free(scan_res);
+		return -2;
+	}
+
+	if (ap) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface->scan_cb)
+			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	wpas_notify_scan_results(wpa_s);
+
+	wpas_notify_scan_done(wpa_s, 1);
+
+	if (sme_proc_obss_scan(wpa_s) > 0) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (autoscan_notify_scan(wpa_s, scan_res)) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (wpa_s->disconnected) {
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (!wpas_driver_bss_selection(wpa_s) &&
+	    bgscan_notify_scan(wpa_s, scan_res) == 1) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	wpas_wps_update_ap_info(wpa_s, scan_res);
+
+	wpa_scan_results_free(scan_res);
+
+	return wpas_select_network_from_last_scan(wpa_s);
+}
+
+
+int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *selected;
+	struct wpa_ssid *ssid = NULL;
+
+	selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+
+	if (selected) {
+		int skip;
+		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
+		if (skip) {
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+			return 0;
+		}
+
+		if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
+			return -1;
+		}
+		wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+		/*
+		 * Do not notify other virtual radios of scan results since we do not
+		 * want them to start other associations at the same time.
+		 */
+		return 1;
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
+		ssid = wpa_supplicant_pick_new_network(wpa_s);
+		if (ssid) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+		} else {
+			int timeout_sec = wpa_s->scan_interval;
+			int timeout_usec = 0;
+#ifdef CONFIG_P2P
+			if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+				return 0;
+
+			if (wpa_s->p2p_in_provisioning) {
+				/*
+				 * Use shorter wait during P2P Provisioning
+				 * state to speed up group formation.
+				 */
+				timeout_sec = 0;
+				timeout_usec = 250000;
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+				return 0;
+			}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+			if (wpa_s->conf->auto_interworking &&
+			    wpa_s->conf->interworking &&
+			    wpa_s->conf->cred) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
+					"start ANQP fetch since no matching "
+					"networks found");
+				wpa_s->network_select = 1;
+				wpa_s->auto_network_select = 1;
+				interworking_start_fetch_anqp(wpa_s);
+				return 1;
+			}
+#endif /* CONFIG_INTERWORKING */
+			if (wpa_supplicant_req_sched_scan(wpa_s))
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+		}
+	}
+	return 0;
+}
+
+
+static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+					      union wpa_event_data *data)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+
+	if (_wpa_supplicant_event_scan_results(wpa_s, data) != 0) {
+		/*
+		 * If no scan results could be fetched, then no need to
+		 * notify those interfaces that did not actually request
+		 * this scan. Similarly, if scan results started a new operation on this
+		 * interface, do not notify other interfaces to avoid concurrent
+		 * operations during a connection attempt.
+		 */
+		return;
+	}
+
+	/*
+	 * Check other interfaces to see if they have the same radio-name. If
+	 * so, they get updated with this same scan info.
+	 */
+	if (!wpa_s->driver->get_radio_name)
+		return;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
+		"sharing same radio (%s) in event_scan_results", rn);
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (rn2 && os_strcmp(rn, rn2) == 0) {
+			wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
+				   "sibling", ifs->ifname);
+			_wpa_supplicant_event_scan_results(ifs, data);
+		}
+	}
+}
+
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+
+
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return;
+
+	if (!wpa_s->no_keep_alive) {
+		wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+			   MAC2STR(wpa_s->bssid));
+		/* TODO: could skip this if normal data traffic has been sent */
+		/* TODO: Consider using some more appropriate data frame for
+		 * this */
+		if (wpa_s->l2)
+			l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800,
+				       (u8 *) "", 0);
+	}
+
+#ifdef CONFIG_SME
+	if (wpa_s->sme.bss_max_idle_period) {
+		unsigned int msec;
+		msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+		if (msec > 100)
+			msec -= 100;
+		eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+				       wnm_bss_keep_alive, wpa_s, NULL);
+	}
+#endif /* CONFIG_SME */
+}
+
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+				   const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return;
+
+#ifdef CONFIG_SME
+	if (elems.bss_max_idle_period) {
+		unsigned int msec;
+		wpa_s->sme.bss_max_idle_period =
+			WPA_GET_LE16(elems.bss_max_idle_period);
+		wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+			   "TU)%s", wpa_s->sme.bss_max_idle_period,
+			   (elems.bss_max_idle_period[2] & 0x01) ?
+			   " (protected keep-live required)" : "");
+		if (wpa_s->sme.bss_max_idle_period == 0)
+			wpa_s->sme.bss_max_idle_period = 1;
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+			eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+			 /* msec times 1000 */
+			msec = wpa_s->sme.bss_max_idle_period * 1024;
+			if (msec > 100)
+				msec -= 100;
+			eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+					       wnm_bss_keep_alive, wpa_s,
+					       NULL);
+		}
+	}
+#endif /* CONFIG_SME */
+}
+
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+	eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
+static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
+					  union wpa_event_data *data)
+{
+	int l, len, found = 0, wpa_found, rsn_found;
+	const u8 *p;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+	if (data->assoc_info.req_ies)
+		wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
+			    data->assoc_info.req_ies_len);
+	if (data->assoc_info.resp_ies) {
+		wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
+			    data->assoc_info.resp_ies_len);
+#ifdef CONFIG_TDLS
+		wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
+					data->assoc_info.resp_ies_len);
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+		wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+				       data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
+	}
+	if (data->assoc_info.beacon_ies)
+		wpa_hexdump(MSG_DEBUG, "beacon_ies",
+			    data->assoc_info.beacon_ies,
+			    data->assoc_info.beacon_ies_len);
+	if (data->assoc_info.freq)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
+			data->assoc_info.freq);
+
+	p = data->assoc_info.req_ies;
+	l = data->assoc_info.req_ies_len;
+
+	/* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+				    p, l);
+			break;
+		}
+		if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+		     (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+		    (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+			if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
+				break;
+			found = 1;
+			wpa_find_assoc_pmkid(wpa_s);
+			break;
+		}
+		l -= len;
+		p += len;
+	}
+	if (!found && data->assoc_info.req_ies)
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SME
+	if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
+		u8 bssid[ETH_ALEN];
+		if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+		    wpa_ft_validate_reassoc_resp(wpa_s->wpa,
+						 data->assoc_info.resp_ies,
+						 data->assoc_info.resp_ies_len,
+						 bssid) < 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+				"Reassociation Response failed");
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_INVALID_IE);
+			return -1;
+		}
+	}
+
+	p = data->assoc_info.resp_ies;
+	l = data->assoc_info.resp_ies_len;
+
+#ifdef CONFIG_WPS_STRICT
+	if (p && wpa_s->current_ssid &&
+	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps;
+		wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE);
+		if (wps == NULL) {
+			wpa_msg(wpa_s, MSG_INFO, "WPS-STRICT: AP did not "
+				"include WPS IE in (Re)Association Response");
+			return -1;
+		}
+
+		if (wps_validate_assoc_resp(wps) < 0) {
+			wpabuf_free(wps);
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_INVALID_IE);
+			return -1;
+		}
+		wpabuf_free(wps);
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+	/* Go through the IEs and make a copy of the MDIE, if present. */
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+				    p, l);
+			break;
+		}
+		if (p[0] == WLAN_EID_MOBILITY_DOMAIN &&
+		    p[1] >= MOBILITY_DOMAIN_ID_LEN) {
+			wpa_s->sme.ft_used = 1;
+			os_memcpy(wpa_s->sme.mobility_domain, p + 2,
+				  MOBILITY_DOMAIN_ID_LEN);
+			break;
+		}
+		l -= len;
+		p += len;
+	}
+#endif /* CONFIG_SME */
+
+	wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
+			     data->assoc_info.resp_ies_len);
+#endif /* CONFIG_IEEE80211R */
+
+	/* WPA/RSN IE from Beacon/ProbeResp */
+	p = data->assoc_info.beacon_ies;
+	l = data->assoc_info.beacon_ies_len;
+
+	/* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
+	 */
+	wpa_found = rsn_found = 0;
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
+				    p, l);
+			break;
+		}
+		if (!wpa_found &&
+		    p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+		    os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
+			wpa_found = 1;
+			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
+		}
+
+		if (!rsn_found &&
+		    p[0] == WLAN_EID_RSN && p[1] >= 2) {
+			rsn_found = 1;
+			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+		}
+
+		l -= len;
+		p += len;
+	}
+
+	if (!wpa_found && data->assoc_info.beacon_ies)
+		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+	if (!rsn_found && data->assoc_info.beacon_ies)
+		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+	if (wpa_found || rsn_found)
+		wpa_s->ap_ies_from_associnfo = 1;
+
+	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 "
+			   "%u to %u MHz",
+			   wpa_s->assoc_freq, data->assoc_info.freq);
+		wpa_supplicant_update_scan_results(wpa_s);
+	}
+
+	wpa_s->assoc_freq = data->assoc_info.freq;
+
+	return 0;
+}
+
+
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+	struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_bss *bss = NULL;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid->ssid_len > 0)
+		bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+	if (!bss)
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+	return bss;
+}
+
+
+static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+{
+	const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+
+	if (!wpa_s->current_bss || !wpa_s->current_ssid)
+		return -1;
+
+	if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
+		return 0;
+
+	bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+					WPA_IE_VENDOR_TYPE);
+	bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+
+	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+				 bss_wpa ? 2 + bss_wpa[1] : 0) ||
+	    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+				 bss_rsn ? 2 + bss_rsn[1] : 0))
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
+				       union wpa_event_data *data)
+{
+	u8 bssid[ETH_ALEN];
+	int ft_completed;
+	struct wpa_driver_capa capa;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
+				    data->assoc_info.addr,
+				    data->assoc_info.req_ies,
+				    data->assoc_info.req_ies_len,
+				    data->assoc_info.reassoc);
+		return;
+	}
+#endif /* CONFIG_AP */
+
+	ft_completed = wpa_ft_is_completed(wpa_s->wpa);
+	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
+		return;
+
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+		wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		return;
+	}
+
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
+	if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
+			MACSTR, MAC2STR(bssid));
+		random_add_randomness(bssid, ETH_ALEN);
+		os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+		wpas_notify_bssid_changed(wpa_s);
+
+		if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
+			wpa_clear_keys(wpa_s, bssid);
+		}
+		if (wpa_supplicant_select_config(wpa_s) < 0) {
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+			return;
+		}
+		if (wpa_s->current_ssid) {
+			struct wpa_bss *bss = NULL;
+
+			bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+			if (!bss) {
+				wpa_supplicant_update_scan_results(wpa_s);
+
+				/* Get the BSS from the new scan results */
+				bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+			}
+
+			if (bss)
+				wpa_s->current_bss = bss;
+		}
+
+		if (wpa_s->conf->ap_scan == 1 &&
+		    wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
+			if (wpa_supplicant_assoc_update_ie(wpa_s) < 0)
+				wpa_msg(wpa_s, MSG_WARNING,
+					"WPA/RSN IEs not updated");
+		}
+	}
+
+#ifdef CONFIG_SME
+	os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
+	wpa_s->sme.prev_bssid_set = 1;
+#endif /* CONFIG_SME */
+
+	wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
+	if (wpa_s->current_ssid) {
+		/* When using scanning (ap_scan=1), SIM PC/SC interface can be
+		 * initialized before association, but for other modes,
+		 * initialize PC/SC here, if the current configuration needs
+		 * smartcard or SIM/USIM. */
+		wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
+	}
+	wpa_sm_notify_assoc(wpa_s->wpa, bssid);
+	if (wpa_s->l2)
+		l2_packet_notify_auth_start(wpa_s->l2);
+
+	/*
+	 * Set portEnabled first to FALSE in order to get EAP state machine out
+	 * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
+	 * state machine may transit to AUTHENTICATING state based on obsolete
+	 * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
+	 * AUTHENTICATED without ever giving chance to EAP state machine to
+	 * reset the state.
+	 */
+	if (!ft_completed) {
+		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)
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	/* 802.1X::portControl = Auto */
+	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+	wpa_s->eapol_received = 0;
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
+	    (wpa_s->current_ssid &&
+	     wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	} else if (!ft_completed) {
+		/* Timeout for receiving the first EAPOL packet */
+		wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
+	}
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+		/*
+		 * We are done; the driver will take care of RSN 4-way
+		 * handshake.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+		   wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		/*
+		 * The driver will take care of RSN 4-way handshake, so we need
+		 * to allow EAPOL supplicant to complete its work without
+		 * waiting for WPA supplicant.
+		 */
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+	} else if (ft_completed) {
+		/*
+		 * FT protocol completed - make sure EAPOL state machine ends
+		 * up in authenticated.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	}
+
+	wpa_s->last_eapol_matches_bssid = 0;
+
+	if (wpa_s->pending_eapol_rx) {
+		struct os_time now, age;
+		os_get_time(&now);
+		os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+		if (age.sec == 0 && age.usec < 100000 &&
+		    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
+		    0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
+				"frame that was received just before "
+				"association notification");
+			wpa_supplicant_rx_eapol(
+				wpa_s, wpa_s->pending_eapol_rx_src,
+				wpabuf_head(wpa_s->pending_eapol_rx),
+				wpabuf_len(wpa_s->pending_eapol_rx));
+		}
+		wpabuf_free(wpa_s->pending_eapol_rx);
+		wpa_s->pending_eapol_rx = NULL;
+	}
+
+	if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	     wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+	    wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
+	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
+		/* Set static WEP keys again */
+		wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
+	}
+
+#ifdef CONFIG_IBSS_RSN
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+	    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);
+		if (!wpa_s->ibss_rsn) {
+			wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+			return;
+		}
+
+		ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	wpas_wps_notify_assoc(wpa_s, bssid);
+}
+
+
+static int disconnect_reason_recoverable(u16 reason_code)
+{
+	return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY ||
+		reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
+		reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+}
+
+
+static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
+					  u16 reason_code,
+					  int locally_generated)
+{
+	const u8 *bssid;
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * At least Host AP driver and a Prism3 card seemed to be
+		 * generating streams of disconnected events when configuring
+		 * IBSS for WPA-None. Ignore them for now.
+		 */
+		return;
+	}
+
+	bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+
+	if (!is_zero_ether_addr(bssid) ||
+	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+			" reason=%d%s",
+			MAC2STR(bssid), reason_code,
+			locally_generated ? " locally_generated=1" : "");
+	}
+}
+
+
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+				 int locally_generated)
+{
+	if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+	    !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+		return 0; /* Not in 4-way handshake with PSK */
+
+	/*
+	 * It looks like connection was lost while trying to go through PSK
+	 * 4-way handshake. Filter out known disconnection cases that are caused
+	 * by something else than PSK mismatch to avoid confusing reports.
+	 */
+
+	if (locally_generated) {
+		if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
+						 u16 reason_code,
+						 int locally_generated)
+{
+	const u8 *bssid;
+	int authenticating;
+	u8 prev_pending_bssid[ETH_ALEN];
+	struct wpa_bss *fast_reconnect = NULL;
+	struct wpa_ssid *fast_reconnect_ssid = NULL;
+	struct wpa_ssid *last_ssid;
+
+	authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
+	os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * At least Host AP driver and a Prism3 card seemed to be
+		 * generating streams of disconnected events when configuring
+		 * IBSS for WPA-None. Ignore them for now.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - ignore in "
+			"IBSS/WPA-None mode");
+		return;
+	}
+
+	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");
+		wpas_auth_failed(wpa_s);
+	}
+	if (!wpa_s->auto_reconnect_disabled ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
+			"reconnect (wps=%d wpa_state=%d)",
+			wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+			wpa_s->wpa_state);
+		if (wpa_s->wpa_state == WPA_COMPLETED &&
+		    wpa_s->current_ssid &&
+		    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+		    !locally_generated &&
+		    disconnect_reason_recoverable(reason_code)) {
+			/*
+			 * It looks like the AP has dropped association with
+			 * us, but could allow us to get back in. Try to
+			 * reconnect to the same BSS without full scan to save
+			 * time for some common cases.
+			 */
+			fast_reconnect = wpa_s->current_bss;
+			fast_reconnect_ssid = wpa_s->current_ssid;
+		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		else
+			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
+				"immediate scan");
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
+			"try to re-connect");
+		wpa_s->reassociate = 0;
+		wpa_s->disconnected = 1;
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+	}
+	bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+		wpas_connection_failed(wpa_s, bssid);
+	wpa_sm_notify_disassoc(wpa_s->wpa);
+	if (locally_generated)
+		wpa_s->disconnect_reason = -reason_code;
+	else
+		wpa_s->disconnect_reason = reason_code;
+	wpas_notify_disconnect_reason(wpa_s);
+	if (wpa_supplicant_dynamic_keys(wpa_s)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
+		wpa_s->keys_cleared = 0;
+		wpa_clear_keys(wpa_s, wpa_s->bssid);
+	}
+	last_ssid = wpa_s->current_ssid;
+	wpa_supplicant_mark_disassoc(wpa_s);
+
+	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;
+	}
+
+	if (fast_reconnect) {
+#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,
+					   fast_reconnect_ssid) < 0) {
+			/* Recover through full scan */
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		}
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+	}
+}
+
+
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (!wpa_s->pending_mic_error_report)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Sending pending MIC error report");
+	wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
+	wpa_s->pending_mic_error_report = 0;
+}
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+
+
+static void
+wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
+					 union wpa_event_data *data)
+{
+	int pairwise;
+	struct os_time t;
+
+	wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
+	pairwise = (data && data->michael_mic_failure.unicast);
+	os_get_time(&t);
+	if ((wpa_s->last_michael_mic_error &&
+	     t.sec - wpa_s->last_michael_mic_error <= 60) ||
+	    wpa_s->pending_mic_error_report) {
+		if (wpa_s->pending_mic_error_report) {
+			/*
+			 * Send the pending MIC error report immediately since
+			 * we are going to start countermeasures and AP better
+			 * do the same.
+			 */
+			wpa_sm_key_request(wpa_s->wpa, 1,
+					   wpa_s->pending_mic_error_pairwise);
+		}
+
+		/* Send the new MIC error report immediately since we are going
+		 * to start countermeasures and AP better do the same.
+		 */
+		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+
+		/* initialize countermeasures */
+		wpa_s->countermeasures = 1;
+
+		wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
+		wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
+
+		/*
+		 * Need to wait for completion of request frame. We do not get
+		 * any callback for the message completion, so just wait a
+		 * short while and hope for the best. */
+		os_sleep(0, 10000);
+
+		wpa_drv_set_countermeasures(wpa_s, 1);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_MICHAEL_MIC_FAILURE);
+		eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
+				     wpa_s, NULL);
+		eloop_register_timeout(60, 0,
+				       wpa_supplicant_stop_countermeasures,
+				       wpa_s, NULL);
+		/* TODO: mark the AP rejected for 60 second. STA is
+		 * allowed to associate with another AP.. */
+	} else {
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+		if (wpa_s->mic_errors_seen) {
+			/*
+			 * Reduce the effectiveness of Michael MIC error
+			 * reports as a means for attacking against TKIP if
+			 * more than one MIC failure is noticed with the same
+			 * PTK. We delay the transmission of the reports by a
+			 * random time between 0 and 60 seconds in order to
+			 * force the attacker wait 60 seconds before getting
+			 * the information on whether a frame resulted in a MIC
+			 * failure.
+			 */
+			u8 rval[4];
+			int sec;
+
+			if (os_get_random(rval, sizeof(rval)) < 0)
+				sec = os_random() % 60;
+			else
+				sec = WPA_GET_BE32(rval) % 60;
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Delay MIC error "
+				"report %d seconds", sec);
+			wpa_s->pending_mic_error_report = 1;
+			wpa_s->pending_mic_error_pairwise = pairwise;
+			eloop_cancel_timeout(
+				wpa_supplicant_delayed_mic_error_report,
+				wpa_s, NULL);
+			eloop_register_timeout(
+				sec, os_random() % 1000000,
+				wpa_supplicant_delayed_mic_error_report,
+				wpa_s, NULL);
+		} else {
+			wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+		}
+#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+	}
+	wpa_s->last_michael_mic_error = t.sec;
+	wpa_s->mic_errors_seen++;
+}
+
+
+#ifdef CONFIG_TERMINATE_ONLASTIF
+static int any_interfaces(struct wpa_supplicant *head)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next)
+		if (!wpa_s->interface_removed)
+			return 1;
+	return 0;
+}
+#endif /* CONFIG_TERMINATE_ONLASTIF */
+
+
+static void
+wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+	if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
+		return;
+
+	switch (data->interface_status.ievent) {
+	case EVENT_INTERFACE_ADDED:
+		if (!wpa_s->interface_removed)
+			break;
+		wpa_s->interface_removed = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was added");
+		if (wpa_supplicant_driver_init(wpa_s) < 0) {
+			wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
+				"driver after interface was added");
+		}
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		break;
+	case EVENT_INTERFACE_REMOVED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
+		wpa_s->interface_removed = 1;
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+		l2_packet_deinit(wpa_s->l2);
+		wpa_s->l2 = NULL;
+#ifdef CONFIG_IBSS_RSN
+		ibss_rsn_deinit(wpa_s->ibss_rsn);
+		wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_TERMINATE_ONLASTIF
+		/* check if last interface */
+		if (!any_interfaces(wpa_s->global->ifaces))
+			eloop_terminate();
+#endif /* CONFIG_TERMINATE_ONLASTIF */
+		break;
+	}
+}
+
+
+#ifdef CONFIG_PEERKEY
+static void
+wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
+			      union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_TDLS
+static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	switch (data->tdls.oper) {
+	case TDLS_REQUEST_SETUP:
+		wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+		break;
+	case TDLS_REQUEST_TEARDOWN:
+		wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+				       data->tdls.reason_code);
+		break;
+	}
+}
+#endif /* CONFIG_TDLS */
+
+
+#ifdef CONFIG_WNM
+static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
+				     union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	switch (data->wnm.oper) {
+	case WNM_OPER_SLEEP:
+		wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request "
+			   "(action=%d, intval=%d)",
+			   data->wnm.sleep_action, data->wnm.sleep_intval);
+		ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
+					     data->wnm.sleep_intval, NULL);
+		break;
+	}
+}
+#endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_IEEE80211R
+static void
+wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
+				 union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+
+	if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies,
+				    data->ft_ies.ies_len,
+				    data->ft_ies.ft_action,
+				    data->ft_ies.target_ap,
+				    data->ft_ies.ric_ies,
+				    data->ft_ies.ric_ies_len) < 0) {
+		/* TODO: prevent MLME/driver from trying to associate? */
+	}
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IBSS_RSN
+static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
+						union wpa_event_data *data)
+{
+	struct wpa_ssid *ssid;
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return;
+	if (data == NULL)
+		return;
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL)
+		return;
+	if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+		return;
+
+	ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
+#ifdef CONFIG_IEEE80211R
+static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
+			 size_t len)
+{
+	const u8 *sta_addr, *target_ap_addr;
+	u16 status;
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len);
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+		return; /* only SME case supported for now */
+	if (len < 1 + 2 * ETH_ALEN + 2)
+		return;
+	if (data[0] != 2)
+		return; /* Only FT Action Response is supported for now */
+	sta_addr = data + 1;
+	target_ap_addr = data + 1 + ETH_ALEN;
+	status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN);
+	wpa_dbg(wpa_s, MSG_DEBUG, "FT: Received FT Action Response: STA "
+		MACSTR " TargetAP " MACSTR " status %u",
+		MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
+
+	if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR
+			" in FT Action Response", MAC2STR(sta_addr));
+		return;
+	}
+
+	if (status) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "FT: FT Action Response indicates "
+			"failure (status code %d)", status);
+		/* TODO: report error to FT code(?) */
+		return;
+	}
+
+	if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2,
+				    len - (1 + 2 * ETH_ALEN + 2), 1,
+				    target_ap_addr, NULL, 0) < 0)
+		return;
+
+#ifdef CONFIG_SME
+	{
+		struct wpa_bss *bss;
+		bss = wpa_bss_get_bssid(wpa_s, target_ap_addr);
+		if (bss)
+			wpa_s->sme.freq = bss->freq;
+		wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT;
+		sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr,
+			      WLAN_AUTH_FT);
+	}
+#endif /* CONFIG_SME */
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
+					       struct unprot_deauth *e)
+{
+#ifdef CONFIG_IEEE80211W
+	wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
+		   "dropped: " MACSTR " -> " MACSTR
+		   " (reason code %u)",
+		   MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+	sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
+						 struct unprot_disassoc *e)
+{
+#ifdef CONFIG_IEEE80211W
+	wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
+		   "dropped: " MACSTR " -> " MACSTR
+		   " (reason code %u)",
+		   MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+	sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	u16 reason_code = 0;
+	int locally_generated = 0;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
+	    event != EVENT_INTERFACE_ENABLED &&
+	    event != EVENT_INTERFACE_STATUS &&
+	    event != EVENT_SCHED_SCAN_STOPPED) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Ignore event %s (%d) while interface is disabled",
+			event_to_string(event), event);
+		return;
+	}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(wpa_s, level, "Event %s (%d) received",
+		event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	switch (event) {
+	case EVENT_AUTH:
+		sme_event_auth(wpa_s, data);
+		break;
+	case EVENT_ASSOC:
+		wpa_supplicant_event_assoc(wpa_s, data);
+		break;
+	case EVENT_DISASSOC:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+		if (data) {
+			wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+				data->disassoc_info.reason_code,
+				data->disassoc_info.locally_generated ?
+				" (locally generated)" : "");
+			if (data->disassoc_info.addr)
+				wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+					MAC2STR(data->disassoc_info.addr));
+		}
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
+			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
+					       data->disassoc_info.addr);
+			break;
+		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
+				"AP mode");
+			break;
+		}
+#endif /* CONFIG_AP */
+		if (data) {
+			reason_code = data->disassoc_info.reason_code;
+			locally_generated =
+				data->disassoc_info.locally_generated;
+			wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+				    data->disassoc_info.ie,
+				    data->disassoc_info.ie_len);
+#ifdef CONFIG_P2P
+			wpas_p2p_disassoc_notif(
+				wpa_s, data->disassoc_info.addr, reason_code,
+				data->disassoc_info.ie,
+				data->disassoc_info.ie_len,
+				locally_generated);
+#endif /* CONFIG_P2P */
+		}
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_disassoc(wpa_s, data);
+		/* fall through */
+	case EVENT_DEAUTH:
+		if (event == EVENT_DEAUTH) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Deauthentication notification");
+			if (data) {
+				reason_code = data->deauth_info.reason_code;
+				locally_generated =
+					data->deauth_info.locally_generated;
+				wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+					data->deauth_info.reason_code,
+					data->deauth_info.locally_generated ?
+					" (locally generated)" : "");
+				if (data->deauth_info.addr) {
+					wpa_dbg(wpa_s, MSG_DEBUG, " * address "
+						MACSTR,
+						MAC2STR(data->deauth_info.
+							addr));
+				}
+				wpa_hexdump(MSG_DEBUG,
+					    "Deauthentication frame IE(s)",
+					    data->deauth_info.ie,
+					    data->deauth_info.ie_len);
+			}
+		}
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data && data->deauth_info.addr) {
+			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
+					       data->deauth_info.addr);
+			break;
+		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
+				"AP mode");
+			break;
+		}
+#endif /* CONFIG_AP */
+		wpa_supplicant_event_disassoc(wpa_s, reason_code,
+					      locally_generated);
+		if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+		    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+		      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+		     eapol_sm_failed(wpa_s->eapol)))
+			wpas_auth_failed(wpa_s);
+#ifdef CONFIG_P2P
+		if (event == EVENT_DEAUTH && data) {
+			if (wpas_p2p_deauth_notif(wpa_s,
+						  data->deauth_info.addr,
+						  reason_code,
+						  data->deauth_info.ie,
+						  data->deauth_info.ie_len,
+						  locally_generated) > 0) {
+				/*
+				 * The interface was removed, so cannot
+				 * continue processing any additional
+				 * operations after this.
+				 */
+				break;
+			}
+		}
+#endif /* CONFIG_P2P */
+		wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+						     locally_generated);
+		break;
+	case EVENT_MICHAEL_MIC_FAILURE:
+		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
+		break;
+#ifndef CONFIG_NO_SCAN_PROCESSING
+	case EVENT_SCAN_RESULTS:
+		wpa_supplicant_event_scan_results(wpa_s, data);
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL &&
+	    wpa_s->wpa_state != WPA_AUTHENTICATING &&
+	    wpa_s->wpa_state != WPA_ASSOCIATING) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after scan result processing");
+		}
+	}
+#endif /* CONFIG_P2P */
+		break;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+	case EVENT_ASSOCINFO:
+		wpa_supplicant_event_associnfo(wpa_s, data);
+		break;
+	case EVENT_INTERFACE_STATUS:
+		wpa_supplicant_event_interface_status(wpa_s, data);
+		break;
+	case EVENT_PMKID_CANDIDATE:
+		wpa_supplicant_event_pmkid_candidate(wpa_s, data);
+		break;
+#ifdef CONFIG_PEERKEY
+	case EVENT_STKSTART:
+		wpa_supplicant_event_stkstart(wpa_s, data);
+		break;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+	case EVENT_TDLS:
+		wpa_supplicant_event_tdls(wpa_s, data);
+		break;
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+	case EVENT_WNM:
+		wpa_supplicant_event_wnm(wpa_s, data);
+		break;
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_IEEE80211R
+	case EVENT_FT_RESPONSE:
+		wpa_supplicant_event_ft_response(wpa_s, data);
+		break;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IBSS_RSN
+	case EVENT_IBSS_RSN_START:
+		wpa_supplicant_event_ibss_rsn_start(wpa_s, data);
+		break;
+#endif /* CONFIG_IBSS_RSN */
+	case EVENT_ASSOC_REJECT:
+		if (data->assoc_reject.bssid)
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+				"bssid=" MACSTR	" status_code=%u",
+				MAC2STR(data->assoc_reject.bssid),
+				data->assoc_reject.status_code);
+		else
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+				"status_code=%u",
+				data->assoc_reject.status_code);
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_assoc_reject(wpa_s, data);
+		else {
+			const u8 *bssid = data->assoc_reject.bssid;
+			if (bssid == NULL || is_zero_ether_addr(bssid))
+				bssid = wpa_s->pending_bssid;
+			wpas_connection_failed(wpa_s, bssid);
+			wpa_supplicant_mark_disassoc(wpa_s);
+		}
+		break;
+	case EVENT_AUTH_TIMED_OUT:
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_auth_timed_out(wpa_s, data);
+		break;
+	case EVENT_ASSOC_TIMED_OUT:
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_assoc_timed_out(wpa_s, data);
+		break;
+	case EVENT_TX_STATUS:
+		wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
+			" type=%d stype=%d",
+			MAC2STR(data->tx_status.dst),
+			data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface == NULL) {
+#ifdef CONFIG_OFFCHANNEL
+			if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+			    data->tx_status.stype == WLAN_FC_STYPE_ACTION)
+				offchannel_send_action_tx_status(
+					wpa_s, data->tx_status.dst,
+					data->tx_status.data,
+					data->tx_status.data_len,
+					data->tx_status.ack ?
+					OFFCHANNEL_SEND_ACTION_SUCCESS :
+					OFFCHANNEL_SEND_ACTION_NO_ACK);
+#endif /* CONFIG_OFFCHANNEL */
+			break;
+		}
+#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));
+		/*
+		 * Catch TX status events for Action frames we sent via group
+		 * interface in GO mode.
+		 */
+		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,
+			      data->tx_status.dst, ETH_ALEN) == 0) {
+			offchannel_send_action_tx_status(
+				wpa_s->parent, data->tx_status.dst,
+				data->tx_status.data,
+				data->tx_status.data_len,
+				data->tx_status.ack ?
+				OFFCHANNEL_SEND_ACTION_SUCCESS :
+				OFFCHANNEL_SEND_ACTION_NO_ACK);
+			break;
+		}
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_AP
+		switch (data->tx_status.type) {
+		case WLAN_FC_TYPE_MGMT:
+			ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
+				      data->tx_status.data_len,
+				      data->tx_status.stype,
+				      data->tx_status.ack);
+			break;
+		case WLAN_FC_TYPE_DATA:
+			ap_tx_status(wpa_s, data->tx_status.dst,
+				     data->tx_status.data,
+				     data->tx_status.data_len,
+				     data->tx_status.ack);
+			break;
+		}
+#endif /* CONFIG_AP */
+		break;
+#ifdef CONFIG_AP
+	case EVENT_EAPOL_TX_STATUS:
+		ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst,
+				   data->eapol_tx_status.data,
+				   data->eapol_tx_status.data_len,
+				   data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		ap_client_poll_ok(wpa_s, data->client_poll.addr);
+		break;
+	case EVENT_RX_FROM_UNKNOWN:
+		if (wpa_s->ap_iface == NULL)
+			break;
+		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
+				       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");
+			break;
+		}
+
+#ifdef CONFIG_AP
+		wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+				  data->ch_switch.ht_enabled,
+				  data->ch_switch.ch_offset);
+#endif /* CONFIG_AP */
+		break;
+	case EVENT_RX_MGMT: {
+		u16 fc, stype;
+		const struct ieee80211_mgmt *mgmt;
+
+		mgmt = (const struct ieee80211_mgmt *)
+			data->rx_mgmt.frame;
+		fc = le_to_host16(mgmt->frame_control);
+		stype = WLAN_FC_GET_STYPE(fc);
+
+		if (wpa_s->ap_iface == NULL) {
+#ifdef CONFIG_P2P
+			if (stype == WLAN_FC_STYPE_PROBE_REQ &&
+			    data->rx_mgmt.frame_len > 24) {
+				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);
+				wpas_p2p_probe_req_rx(
+					wpa_s, src, mgmt->da,
+					mgmt->bssid, ie, ie_len,
+					data->rx_mgmt.ssi_signal);
+				break;
+			}
+#endif /* CONFIG_P2P */
+			wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
+				"management frame in non-AP mode");
+			break;
+		}
+
+		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);
+
+			wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
+					 mgmt->bssid, ie, ie_len,
+					 data->rx_mgmt.ssi_signal);
+		}
+
+		ap_mgmt_rx(wpa_s, &data->rx_mgmt);
+		break;
+		}
+#endif /* CONFIG_AP */
+	case EVENT_RX_ACTION:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+			" Category=%u DataLen=%d freq=%d MHz",
+			MAC2STR(data->rx_action.sa),
+			data->rx_action.category, (int) data->rx_action.len,
+			data->rx_action.freq);
+#ifdef CONFIG_IEEE80211R
+		if (data->rx_action.category == WLAN_ACTION_FT) {
+			ft_rx_action(wpa_s, data->rx_action.data,
+				     data->rx_action.len);
+			break;
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+		if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
+			sme_sa_query_rx(wpa_s, data->rx_action.sa,
+					data->rx_action.data,
+					data->rx_action.len);
+			break;
+		}
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+		if (data->rx_action.category == WLAN_ACTION_WNM) {
+			ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
+			break;
+		}
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_GAS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    gas_query_rx(wpa_s->gas, data->rx_action.da,
+				 data->rx_action.sa, data->rx_action.bssid,
+				 data->rx_action.data, data->rx_action.len,
+				 data->rx_action.freq) == 0)
+			break;
+#endif /* CONFIG_GAS */
+#ifdef CONFIG_TDLS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    data->rx_action.len >= 4 &&
+		    data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
+				"Response from " MACSTR,
+				MAC2STR(data->rx_action.sa));
+			break;
+		}
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_P2P
+		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
+				   data->rx_action.sa,
+				   data->rx_action.bssid,
+				   data->rx_action.category,
+				   data->rx_action.data,
+				   data->rx_action.len, data->rx_action.freq);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_RX_PROBE_REQ:
+		if (data->rx_probe_req.sa == NULL ||
+		    data->rx_probe_req.ie == NULL)
+			break;
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface) {
+			hostapd_probe_req_rx(wpa_s->ap_iface->bss[0],
+					     data->rx_probe_req.sa,
+					     data->rx_probe_req.da,
+					     data->rx_probe_req.bssid,
+					     data->rx_probe_req.ie,
+					     data->rx_probe_req.ie_len,
+					     data->rx_probe_req.ssi_signal);
+			break;
+		}
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+		wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
+				      data->rx_probe_req.da,
+				      data->rx_probe_req.bssid,
+				      data->rx_probe_req.ie,
+				      data->rx_probe_req.ie_len,
+				      data->rx_probe_req.ssi_signal);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+		wpas_p2p_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_CANCEL_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_cancel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+		wpas_p2p_cancel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_P2P */
+		break;
+#ifdef CONFIG_P2P
+	case EVENT_P2P_DEV_FOUND: {
+		struct p2p_peer_info peer_info;
+
+		os_memset(&peer_info, 0, sizeof(peer_info));
+		if (data->p2p_dev_found.dev_addr)
+			os_memcpy(peer_info.p2p_device_addr,
+				  data->p2p_dev_found.dev_addr, ETH_ALEN);
+		if (data->p2p_dev_found.pri_dev_type)
+			os_memcpy(peer_info.pri_dev_type,
+				  data->p2p_dev_found.pri_dev_type,
+				  sizeof(peer_info.pri_dev_type));
+		if (data->p2p_dev_found.dev_name)
+			os_strlcpy(peer_info.device_name,
+				   data->p2p_dev_found.dev_name,
+				   sizeof(peer_info.device_name));
+		peer_info.config_methods = data->p2p_dev_found.config_methods;
+		peer_info.dev_capab = data->p2p_dev_found.dev_capab;
+		peer_info.group_capab = data->p2p_dev_found.group_capab;
+
+		/*
+		 * FIX: new_device=1 is not necessarily correct. We should
+		 * maintain a P2P peer database in wpa_supplicant and update
+		 * this information based on whether the peer is truly new.
+		 */
+		wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
+		break;
+		}
+	case EVENT_P2P_GO_NEG_REQ_RX:
+		wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
+				   data->p2p_go_neg_req_rx.dev_passwd_id);
+		break;
+	case EVENT_P2P_GO_NEG_COMPLETED:
+		wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
+		break;
+	case EVENT_P2P_PROV_DISC_REQUEST:
+		wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
+				   data->p2p_prov_disc_req.config_methods,
+				   data->p2p_prov_disc_req.dev_addr,
+				   data->p2p_prov_disc_req.pri_dev_type,
+				   data->p2p_prov_disc_req.dev_name,
+				   data->p2p_prov_disc_req.supp_config_methods,
+				   data->p2p_prov_disc_req.dev_capab,
+				   data->p2p_prov_disc_req.group_capab,
+				   NULL, 0);
+		break;
+	case EVENT_P2P_PROV_DISC_RESPONSE:
+		wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
+				    data->p2p_prov_disc_resp.config_methods);
+		break;
+	case EVENT_P2P_SD_REQUEST:
+		wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
+				data->p2p_sd_req.sa,
+				data->p2p_sd_req.dialog_token,
+				data->p2p_sd_req.update_indic,
+				data->p2p_sd_req.tlvs,
+				data->p2p_sd_req.tlvs_len);
+		break;
+	case EVENT_P2P_SD_RESPONSE:
+		wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
+				 data->p2p_sd_resp.update_indic,
+				 data->p2p_sd_resp.tlvs,
+				 data->p2p_sd_resp.tlvs_len);
+		break;
+#endif /* CONFIG_P2P */
+	case EVENT_EAPOL_RX:
+		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
+					data->eapol_rx.data,
+					data->eapol_rx.data_len);
+		break;
+	case EVENT_SIGNAL_CHANGE:
+		bgscan_notify_signal_change(
+			wpa_s, data->signal_change.above_threshold,
+			data->signal_change.current_signal,
+			data->signal_change.current_noise,
+			data->signal_change.current_txrate);
+		break;
+	case EVENT_INTERFACE_ENABLED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+			wpa_supplicant_update_mac_addr(wpa_s);
+#ifdef CONFIG_AP
+			if (!wpa_s->ap_iface) {
+				wpa_supplicant_set_state(wpa_s,
+							 WPA_DISCONNECTED);
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else
+				wpa_supplicant_set_state(wpa_s,
+							 WPA_COMPLETED);
+#else /* CONFIG_AP */
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+#endif /* CONFIG_AP */
+		}
+		break;
+	case EVENT_INTERFACE_DISABLED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+		break;
+	case EVENT_CHANNEL_LIST_CHANGED:
+		if (wpa_s->drv_priv == NULL)
+			break; /* Ignore event during drv initialization */
+
+		free_hw_features(wpa_s);
+		wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+			wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+		wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_INTERFACE_UNAVAILABLE:
+#ifdef CONFIG_P2P
+		wpas_p2p_interface_unavailable(wpa_s);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_BEST_CHANNEL:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
+			"(%d %d %d)",
+			data->best_chan.freq_24, data->best_chan.freq_5,
+			data->best_chan.freq_overall);
+		wpa_s->best_24_freq = data->best_chan.freq_24;
+		wpa_s->best_5_freq = data->best_chan.freq_5;
+		wpa_s->best_overall_freq = data->best_chan.freq_overall;
+#ifdef CONFIG_P2P
+		wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
+					      data->best_chan.freq_5,
+					      data->best_chan.freq_overall);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_UNPROT_DEAUTH:
+		wpa_supplicant_event_unprot_deauth(wpa_s,
+						   &data->unprot_deauth);
+		break;
+	case EVENT_UNPROT_DISASSOC:
+		wpa_supplicant_event_unprot_disassoc(wpa_s,
+						     &data->unprot_disassoc);
+		break;
+	case EVENT_STATION_LOW_ACK:
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data)
+			hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
+						  data->low_ack.addr);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_TDLS
+		if (data)
+			wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+#endif /* CONFIG_TDLS */
+		break;
+	case EVENT_IBSS_PEER_LOST:
+#ifdef CONFIG_IBSS_RSN
+		ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
+#endif /* CONFIG_IBSS_RSN */
+		break;
+	case EVENT_DRIVER_GTK_REKEY:
+		if (os_memcmp(data->driver_gtk_rekey.bssid,
+			      wpa_s->bssid, ETH_ALEN))
+			break;
+		if (!wpa_s->wpa)
+			break;
+		wpa_sm_update_replay_ctr(wpa_s->wpa,
+					 data->driver_gtk_rekey.replay_ctr);
+		break;
+	case EVENT_SCHED_SCAN_STOPPED:
+		wpa_s->sched_scanning = 0;
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			break;
+
+		/*
+		 * If we timed out, start a new sched scan to continue
+		 * searching for more SSIDs.
+		 */
+		if (wpa_s->sched_scan_timed_out)
+			wpa_supplicant_req_sched_scan(wpa_s);
+		break;
+	case EVENT_WPS_BUTTON_PUSHED:
+#ifdef CONFIG_WPS
+		wpas_wps_start_pbc(wpa_s, NULL, 0);
+#endif /* CONFIG_WPS */
+		break;
+	default:
+		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
+		break;
+	}
+}

Copied: vendor/wpa/2.0/wpa_supplicant/examples/dbus-listen-preq.py (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/dbus-listen-preq.py)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/dbus-listen-preq.py	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/dbus-listen-preq.py	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+import time
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
+WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
+
+def usage():
+	print "Usage: %s <ifname>" % sys.argv[0]
+	print "Press Ctrl-C to stop"
+
+def ProbeRequest(args):
+	if 'addr' in args:
+		print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+	if 'dst' in args:
+		print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+	if 'bssid' in args:
+		print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+	if 'signal' in args:
+		print 'signal:%d' % args['signal'],
+	if 'ies' in args:
+		print 'have IEs (%d bytes)' % len(args['ies']),
+        print ''
+
+if __name__ == "__main__":
+	global bus
+	global wpas_obj
+	global if_obj
+	global p2p_iface
+
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+	wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
+
+	# Print list of i/f if no one is specified
+	if (len(sys.argv) < 2)  :
+		usage()
+		sys.exit(0)
+
+	wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
+
+	ifname = sys.argv[1]
+
+	path = wpas.GetInterface(ifname)
+
+	if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+	iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
+
+	bus.add_signal_receiver(ProbeRequest,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="ProbeRequest")
+
+	iface.SubscribeProbeReq()
+
+	gobject.MainLoop().run()

Copied: vendor/wpa/2.0/wpa_supplicant/examples/p2p-action-udhcp.sh (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/p2p-action-udhcp.sh)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/p2p-action-udhcp.sh	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/p2p-action-udhcp.sh	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+kill_daemon() {
+    NAME=$1
+    PF=$2
+
+    if [ ! -r $PF ]; then
+	return
+    fi
+
+    PID=`cat $PF`
+    if [ $PID -gt 0 ]; then
+	if ps $PID | grep -q $NAME; then
+	    kill $PID
+	fi
+    fi
+    rm $PF
+}
+
+if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+	kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+	ifconfig $GIFNAME 192.168.42.1 up
+	udhcpd /etc/udhcpd-p2p.conf
+    fi
+    if [ "$4" = "client" ]; then
+	kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+	kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+	udhcpc -i $GIFNAME -p /var/run/udhcpc-$GIFNAME.pid \
+		-s /etc/udhcpc.script
+    fi
+fi
+
+if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+	kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+	ifconfig $GIFNAME 0.0.0.0
+    fi
+    if [ "$4" = "client" ]; then
+	kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+	ifconfig $GIFNAME 0.0.0.0
+    fi
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # enable NAT/masquarade $GIFNAME -> $UPLINK
+    iptables -P FORWARD DROP
+    iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+    sysctl net.ipv4.ip_forward=1
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # disable NAT/masquarade $GIFNAME -> $UPLINK
+    sysctl net.ipv4.ip_forward=0
+    iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+fi

Copied: vendor/wpa/2.0/wpa_supplicant/examples/p2p-action.sh (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/p2p-action.sh)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/p2p-action.sh	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/p2p-action.sh	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+kill_daemon() {
+    NAME=$1
+    PF=$2
+
+    if [ ! -r $PF ]; then
+	return
+    fi
+
+    PID=`cat $PF`
+    if [ $PID -gt 0 ]; then
+	if ps $PID | grep -q $NAME; then
+	    kill $PID
+	fi
+    fi
+    rm $PF
+}
+
+if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+	kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+	rm /var/run/dhclient.leases-$GIFNAME
+	kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+	ifconfig $GIFNAME 192.168.42.1 up
+	if ! dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
+	    -i $GIFNAME \
+	    -F192.168.42.11,192.168.42.99; then
+	    # another dnsmasq instance may be running and blocking us; try to
+	    # start with -z to avoid that
+	    dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \
+		-i $GIFNAME \
+		-F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z
+	fi
+    fi
+    if [ "$4" = "client" ]; then
+	kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+	rm /var/run/dhclient.leases-$GIFNAME
+	kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+	dhclient -pf /var/run/dhclient-$GIFNAME.pid \
+	    -lf /var/run/dhclient.leases-$GIFNAME \
+	    -nw \
+	    $GIFNAME
+    fi
+fi
+
+if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then
+    GIFNAME=$3
+    if [ "$4" = "GO" ]; then
+	kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME
+	ifconfig $GIFNAME 0.0.0.0
+    fi
+    if [ "$4" = "client" ]; then
+	kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid
+	rm /var/run/dhclient.leases-$GIFNAME
+	ifconfig $GIFNAME 0.0.0.0
+    fi
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # enable NAT/masquarade $GIFNAME -> $UPLINK
+    iptables -P FORWARD DROP
+    iptables -t nat -A POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -A FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+    sysctl net.ipv4.ip_forward=1
+fi
+
+if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then
+    GIFNAME=$3
+    UPLINK=$4
+    # disable NAT/masquarade $GIFNAME -> $UPLINK
+    sysctl net.ipv4.ip_forward=0
+    iptables -t nat -D POSTROUTING -o $UPLINK -j MASQUERADE
+    iptables -D FORWARD -i $UPLINK -o $GIFNAME -m state --state RELATED,ESTABLISHED -j ACCEPT
+    iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT
+fi

Copied: vendor/wpa/2.0/wpa_supplicant/examples/udhcpd-p2p.conf (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/udhcpd-p2p.conf)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/udhcpd-p2p.conf	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/udhcpd-p2p.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,120 @@
+# Sample udhcpd configuration file (/etc/udhcpd.conf)
+
+# The start and end of the IP lease block
+
+start 		192.168.42.20	#default: 192.168.0.20
+end		192.168.42.254	#default: 192.168.0.254
+
+
+# The interface that udhcpd will use
+
+interface	wlan2		#default: eth0
+
+
+# The maximim number of leases (includes addressesd reserved
+# by OFFER's, DECLINE's, and ARP conficts
+
+#max_leases	254		#default: 254
+
+
+# If remaining is true (default), udhcpd will store the time
+# remaining for each lease in the udhcpd leases file. This is
+# for embedded systems that cannot keep time between reboots.
+# If you set remaining to no, the absolute time that the lease
+# expires at will be stored in the dhcpd.leases file.
+
+#remaining	yes		#default: yes
+
+
+# The time period at which udhcpd will write out a dhcpd.leases
+# file. If this is 0, udhcpd will never automatically write a
+# lease file. (specified in seconds)
+
+#auto_time	7200		#default: 7200 (2 hours)
+
+
+# The amount of time that an IP will be reserved (leased) for if a
+# DHCP decline message is received (seconds).
+
+#decline_time	3600		#default: 3600 (1 hour)
+
+
+# The amount of time that an IP will be reserved (leased) for if an
+# ARP conflct occurs. (seconds
+
+#conflict_time	3600		#default: 3600 (1 hour)
+
+
+# How long an offered address is reserved (leased) in seconds
+
+#offer_time	60		#default: 60 (1 minute)
+
+# If a lease to be given is below this value, the full lease time is
+# instead used (seconds).
+
+#min_lease	60		#defult: 60
+
+
+# The location of the leases file
+
+#lease_file	/var/lib/misc/udhcpd.leases	#defualt: /var/lib/misc/udhcpd.leases
+
+# The location of the pid file
+pidfile	/var/run/udhcpd-wlan2.pid	#default: /var/run/udhcpd.pid
+
+# Every time udhcpd writes a leases file, the below script will be called.
+# Useful for writing the lease file to flash every few hours.
+
+#notify_file				#default: (no script)
+
+#notify_file	dumpleases 	# <--- useful for debugging
+
+# The following are bootp specific options, setable by udhcpd.
+
+#siaddr		192.168.0.22		#default: 0.0.0.0
+
+#sname		zorak			#default: (none)
+
+#boot_file	/var/nfs_root		#default: (none)
+
+# The remainer of options are DHCP options and can be specifed with the
+# keyword 'opt' or 'option'. If an option can take multiple items, such
+# as the dns option, they can be listed on the same line, or multiple
+# lines. The only option with a default is 'lease'.
+
+#Examles
+opt	dns	192.168.2.1
+option	subnet	255.255.255.0
+option	domain	atherosowl.com
+option	lease	864000		# 10 days of seconds
+
+
+# Currently supported options, for more info, see options.c
+#opt subnet
+#opt timezone
+#opt router
+#opt timesvr
+#opt namesvr
+#opt dns
+#opt logsvr
+#opt cookiesvr
+#opt lprsvr
+#opt bootsize
+#opt domain
+#opt swapsvr
+#opt rootpath
+#opt ipttl
+#opt mtu
+#opt broadcast
+#opt wins
+#opt lease
+#opt ntpsrv
+#opt tftp
+#opt bootfile
+
+
+# Static leases map
+#static_lease 00:60:08:11:CE:4E 192.168.0.54
+#static_lease 00:60:08:11:CE:3E 192.168.0.44
+
+

Deleted: vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py
===================================================================
--- vendor/wpa/dist/wpa_supplicant/examples/wpas-dbus-new-signals.py	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,203 +0,0 @@
-#!/usr/bin/python
-
-import dbus
-import sys, os
-import time
-import gobject
-from dbus.mainloop.glib import DBusGMainLoop
-
-WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
-WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
-WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
-
-WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
-WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces"
-WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS"
-WPAS_DBUS_NETWORK_INTERFACE = "fi.w1.wpa_supplicant1.Network"
-
-def byte_array_to_string(s):
-	import urllib
-	r = ""    
-	for c in s:
-		if c >= 32 and c < 127:
-			r += "%c" % c
-		else:
-			r += urllib.quote(chr(c))
-	return r
-
-def list_interfaces(wpas_obj):
-	ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces',
-			      dbus_interface=dbus.PROPERTIES_IFACE)
-	for path in ifaces:
-		if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
-		ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
-			      dbus_interface=dbus.PROPERTIES_IFACE)
-		print ifname
-
-def interfaceAdded(interface, properties):
-	print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])
-
-def interfaceRemoved(interface):
-	print "InterfaceRemoved(%s)" % (interface)
-
-def propertiesChanged(properties):
-	for i in properties:
-		print "PropertiesChanged: %s=%s" % (i, properties[i])
-
-def showBss(bss):
-	net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
-	net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE)
-
-	# Convert the byte-array for SSID and BSSID to printable strings
-	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID',
-			  dbus_interface=dbus.PROPERTIES_IFACE)
-	bssid = ""
-	for item in val:
-		bssid = bssid + ":%02x" % item
-	bssid = bssid[1:]
-	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID',
-			  dbus_interface=dbus.PROPERTIES_IFACE)
-	ssid = byte_array_to_string(val)
-
-	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPAIE',
-			  dbus_interface=dbus.PROPERTIES_IFACE)
-	wpa = "no"
-	if val != None:
-		wpa = "yes"
-	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSNIE',
-			  dbus_interface=dbus.PROPERTIES_IFACE)
-	wpa2 = "no"
-	if val != None:
-		wpa2 = "yes"
-	freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency',
-			   dbus_interface=dbus.PROPERTIES_IFACE)
-	signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal',
-			     dbus_interface=dbus.PROPERTIES_IFACE)
-	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates',
-			  dbus_interface=dbus.PROPERTIES_IFACE)
-	if len(val) > 0:
-		maxrate = val[0] / 1000000
-	else:
-		maxrate = 0
-
-	print "  %s  ::  ssid='%s'  wpa=%s  wpa2=%s  signal=%d  rate=%d  freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
-
-def scanDone(success):
-	gobject.MainLoop().quit()
-	print "Scan done: success=%s" % success
-
-def scanDone2(success, path=None):
-	print "Scan done: success=%s [path=%s]" % (success, path)
-
-def bssAdded(bss, properties):
-	print "BSS added: %s" % (bss)
-	showBss(bss)
-
-def bssRemoved(bss):
-	print "BSS removed: %s" % (bss)
-
-def blobAdded(blob):
-	print "BlobAdded(%s)" % (blob)
-
-def blobRemoved(blob):
-	print "BlobRemoved(%s)" % (blob)
-
-def networkAdded(network, properties):
-	print "NetworkAdded(%s)" % (network)
-
-def networkRemoved(network):
-	print "NetworkRemoved(%s)" % (network)
-
-def networkSelected(network):
-	print "NetworkSelected(%s)" % (network)
-
-def propertiesChangedInterface(properties):
-	for i in properties:
-		print "PropertiesChanged(interface): %s=%s" % (i, properties[i])
-
-def propertiesChangedBss(properties):
-	for i in properties:
-		print "PropertiesChanged(BSS): %s=%s" % (i, properties[i])
-
-def propertiesChangedNetwork(properties):
-	for i in properties:
-		print "PropertiesChanged(Network): %s=%s" % (i, properties[i])
-
-def main():
-	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-	global bus
-	bus = dbus.SystemBus()
-	wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
-
-	if len(sys.argv) != 2:
-		list_interfaces(wpas_obj)
-		os._exit(1)
-
-	wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
-	bus.add_signal_receiver(interfaceAdded,
-				dbus_interface=WPAS_DBUS_INTERFACE,
-				signal_name="InterfaceAdded")
-	bus.add_signal_receiver(interfaceRemoved,
-				dbus_interface=WPAS_DBUS_INTERFACE,
-				signal_name="InterfaceRemoved")
-	bus.add_signal_receiver(propertiesChanged,
-				dbus_interface=WPAS_DBUS_INTERFACE,
-				signal_name="PropertiesChanged")
-
-	ifname = sys.argv[1]
-	path = wpas.GetInterface(ifname)
-	if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
-	iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
-	iface.connect_to_signal("ScanDone", scanDone2,
-				path_keyword='path')
-
-	bus.add_signal_receiver(scanDone,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="ScanDone",
-				path=path)
-	bus.add_signal_receiver(bssAdded,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="BSSAdded",
-				path=path)
-	bus.add_signal_receiver(bssRemoved,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="BSSRemoved",
-				path=path)
-	bus.add_signal_receiver(blobAdded,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="BlobAdded",
-				path=path)
-	bus.add_signal_receiver(blobRemoved,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="BlobRemoved",
-				path=path)
-	bus.add_signal_receiver(networkAdded,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="NetworkAdded",
-				path=path)
-	bus.add_signal_receiver(networkRemoved,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="NetworkRemoved",
-				path=path)
-	bus.add_signal_receiver(networkSelected,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="NetworkSelected",
-				path=path)
-	bus.add_signal_receiver(propertiesChangedInterface,
-				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
-				signal_name="PropertiesChanged",
-				path=path)
-
-	bus.add_signal_receiver(propertiesChangedBss,
-				dbus_interface=WPAS_DBUS_BSS_INTERFACE,
-				signal_name="PropertiesChanged")
-
-	bus.add_signal_receiver(propertiesChangedNetwork,
-				dbus_interface=WPAS_DBUS_NETWORK_INTERFACE,
-				signal_name="PropertiesChanged")
-
-	gobject.MainLoop().run()
-
-if __name__ == "__main__":
-	main()
-

Copied: vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/wpas-dbus-new-signals.py)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/wpas-dbus-new-signals.py	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,203 @@
+#!/usr/bin/python
+
+import dbus
+import sys, os
+import time
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+
+WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1"
+WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1"
+
+WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
+WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces"
+WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS"
+WPAS_DBUS_NETWORK_INTERFACE = "fi.w1.wpa_supplicant1.Network"
+
+def byte_array_to_string(s):
+	import urllib
+	r = ""    
+	for c in s:
+		if c >= 32 and c < 127:
+			r += "%c" % c
+		else:
+			r += urllib.quote(chr(c))
+	return r
+
+def list_interfaces(wpas_obj):
+	ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces',
+			      dbus_interface=dbus.PROPERTIES_IFACE)
+	for path in ifaces:
+		if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+		ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
+			      dbus_interface=dbus.PROPERTIES_IFACE)
+		print ifname
+
+def interfaceAdded(interface, properties):
+	print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])
+
+def interfaceRemoved(interface):
+	print "InterfaceRemoved(%s)" % (interface)
+
+def propertiesChanged(properties):
+	for i in properties:
+		print "PropertiesChanged: %s=%s" % (i, properties[i])
+
+def showBss(bss):
+	net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
+	net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE)
+
+	# Convert the byte-array for SSID and BSSID to printable strings
+	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID',
+			  dbus_interface=dbus.PROPERTIES_IFACE)
+	bssid = ""
+	for item in val:
+		bssid = bssid + ":%02x" % item
+	bssid = bssid[1:]
+	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID',
+			  dbus_interface=dbus.PROPERTIES_IFACE)
+	ssid = byte_array_to_string(val)
+
+	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPA',
+			  dbus_interface=dbus.PROPERTIES_IFACE)
+	wpa = "no"
+	if val != None:
+		wpa = "yes"
+	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN',
+			  dbus_interface=dbus.PROPERTIES_IFACE)
+	wpa2 = "no"
+	if val != None:
+		wpa2 = "yes"
+	freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency',
+			   dbus_interface=dbus.PROPERTIES_IFACE)
+	signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal',
+			     dbus_interface=dbus.PROPERTIES_IFACE)
+	val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates',
+			  dbus_interface=dbus.PROPERTIES_IFACE)
+	if len(val) > 0:
+		maxrate = val[0] / 1000000
+	else:
+		maxrate = 0
+
+	print "  %s  ::  ssid='%s'  wpa=%s  wpa2=%s  signal=%d  rate=%d  freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+
+def scanDone(success):
+	gobject.MainLoop().quit()
+	print "Scan done: success=%s" % success
+
+def scanDone2(success, path=None):
+	print "Scan done: success=%s [path=%s]" % (success, path)
+
+def bssAdded(bss, properties):
+	print "BSS added: %s" % (bss)
+	showBss(bss)
+
+def bssRemoved(bss):
+	print "BSS removed: %s" % (bss)
+
+def blobAdded(blob):
+	print "BlobAdded(%s)" % (blob)
+
+def blobRemoved(blob):
+	print "BlobRemoved(%s)" % (blob)
+
+def networkAdded(network, properties):
+	print "NetworkAdded(%s)" % (network)
+
+def networkRemoved(network):
+	print "NetworkRemoved(%s)" % (network)
+
+def networkSelected(network):
+	print "NetworkSelected(%s)" % (network)
+
+def propertiesChangedInterface(properties):
+	for i in properties:
+		print "PropertiesChanged(interface): %s=%s" % (i, properties[i])
+
+def propertiesChangedBss(properties):
+	for i in properties:
+		print "PropertiesChanged(BSS): %s=%s" % (i, properties[i])
+
+def propertiesChangedNetwork(properties):
+	for i in properties:
+		print "PropertiesChanged(Network): %s=%s" % (i, properties[i])
+
+def main():
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+	global bus
+	bus = dbus.SystemBus()
+	wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
+
+	if len(sys.argv) != 2:
+		list_interfaces(wpas_obj)
+		os._exit(1)
+
+	wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
+	bus.add_signal_receiver(interfaceAdded,
+				dbus_interface=WPAS_DBUS_INTERFACE,
+				signal_name="InterfaceAdded")
+	bus.add_signal_receiver(interfaceRemoved,
+				dbus_interface=WPAS_DBUS_INTERFACE,
+				signal_name="InterfaceRemoved")
+	bus.add_signal_receiver(propertiesChanged,
+				dbus_interface=WPAS_DBUS_INTERFACE,
+				signal_name="PropertiesChanged")
+
+	ifname = sys.argv[1]
+	path = wpas.GetInterface(ifname)
+	if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
+	iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE)
+	iface.connect_to_signal("ScanDone", scanDone2,
+				path_keyword='path')
+
+	bus.add_signal_receiver(scanDone,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="ScanDone",
+				path=path)
+	bus.add_signal_receiver(bssAdded,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="BSSAdded",
+				path=path)
+	bus.add_signal_receiver(bssRemoved,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="BSSRemoved",
+				path=path)
+	bus.add_signal_receiver(blobAdded,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="BlobAdded",
+				path=path)
+	bus.add_signal_receiver(blobRemoved,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="BlobRemoved",
+				path=path)
+	bus.add_signal_receiver(networkAdded,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="NetworkAdded",
+				path=path)
+	bus.add_signal_receiver(networkRemoved,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="NetworkRemoved",
+				path=path)
+	bus.add_signal_receiver(networkSelected,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="NetworkSelected",
+				path=path)
+	bus.add_signal_receiver(propertiesChangedInterface,
+				dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE,
+				signal_name="PropertiesChanged",
+				path=path)
+
+	bus.add_signal_receiver(propertiesChangedBss,
+				dbus_interface=WPAS_DBUS_BSS_INTERFACE,
+				signal_name="PropertiesChanged")
+
+	bus.add_signal_receiver(propertiesChangedNetwork,
+				dbus_interface=WPAS_DBUS_NETWORK_INTERFACE,
+				signal_name="PropertiesChanged")
+
+	gobject.MainLoop().run()
+
+if __name__ == "__main__":
+	main()
+

Copied: vendor/wpa/2.0/wpa_supplicant/examples/wps-ap-cli (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/wps-ap-cli)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/wps-ap-cli	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/wps-ap-cli	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+CLI=wpa_cli
+
+pbc()
+{
+	echo "Starting PBC mode"
+	echo "Push button on the station within two minutes"
+	if ! $CLI wps_pbc | grep -q OK; then
+		echo "Failed to enable PBC mode"
+	fi
+}
+
+enter_pin()
+{
+	echo "Enter a PIN from a station to be enrolled to the network."
+	read -p "Enrollee PIN: " pin
+	cpin=`$CLI wps_check_pin "$pin" | tail -1`
+	if [ "$cpin" = "FAIL-CHECKSUM" ]; then
+		echo "Checksum digit is not valid"
+		read -p "Do you want to use this PIN (y/n)? " resp
+		case "$resp" in
+			y*)
+				cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
+				;;
+			*)
+				return 1
+				;;
+		esac
+	fi
+	if [ "$cpin" = "FAIL" ]; then
+		echo "Invalid PIN: $pin"
+		return 1
+	fi
+	echo "Enabling Enrollee PIN: $cpin"
+	$CLI wps_pin any "$cpin"
+}
+
+show_config()
+{
+	$CLI status wps
+}
+
+main_menu()
+{
+	echo "WPS AP"
+	echo "------"
+	echo "1: Push button (activate PBC)"
+	echo "2: Enter Enrollee PIN"
+	echo "3: Show current configuration"
+	echo "0: Exit wps-ap-cli"
+
+	read -p "Command: " cmd
+
+	case "$cmd" in
+		1)
+			pbc
+			;;
+		2)
+			enter_pin
+			;;
+		3)
+			show_config
+			;;
+		0)
+			exit 0
+			;;
+		*)
+			echo "Unknown command: $cmd"
+			;;
+	esac
+
+	echo
+	main_menu
+}
+
+
+main_menu

Copied: vendor/wpa/2.0/wpa_supplicant/examples/wps-nfc.py (from rev 9639, vendor/wpa/dist/wpa_supplicant/examples/wps-nfc.py)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/examples/wps-nfc.py	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/examples/wps-nfc.py	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# Copyright (c) 2012, Jouni Malinen <j at w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import wpactrl
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError, error:
+            print "Could not find wpa_supplicant: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No wpa_supplicant control interface found"
+        return None
+
+    for ctrl in ifaces:
+        try:
+            wpas = wpactrl.WPACtrl(ctrl)
+            return wpas
+        except wpactrl.error, error:
+            print "Error: ", error
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_handover_req():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+
+
+def wpas_put_handover_sel(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
+
+
+def wps_handover_init(peer):
+    print "Trying to initiate WPS handover"
+
+    data = wpas_get_handover_req()
+    if (data == None):
+        print "Could not get handover request message from wpa_supplicant"
+        return
+    print "Handover request from wpa_supplicant: " + data.encode("hex")
+    message = nfc.ndef.Message(data)
+    print "Parsed handover request: " + message.pretty()
+
+    nfc.llcp.activate(peer);
+    time.sleep(0.5)
+
+    client = nfc.handover.HandoverClient()
+    try:
+        print "Trying handover";
+        client.connect()
+        print "Connected for handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        client.close()
+        return
+
+    print "Sending handover request"
+
+    if not client.send(message):
+        print "Failed to send handover request"
+
+    print "Receiving handover response"
+    message = client._recv()
+    print "Handover select received"
+    print message.pretty()
+    wpas_put_handover_sel(message)
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    client.close()
+    print "Done with handover"
+
+
+def wps_tag_read(tag):
+    if len(tag.ndef.message):
+        message = nfc.ndef.Message(tag.ndef.message)
+        print "message type " + message.type
+
+        for record in message:
+            print "record type " + record.type
+            if record.type == "application/vnd.wfa.wsc":
+                print "WPS tag - send to wpa_supplicant"
+                wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    print "Remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            while True:
+                general_bytes = nfc.llcp.startup({})
+                tag = clf.poll(general_bytes)
+                if tag == None:
+                    continue
+
+                if isinstance(tag, nfc.DEP):
+                    wps_handover_init(tag)
+                    break
+
+                if tag.ndef:
+                    wps_tag_read(tag)
+                    break
+
+                if tag:
+                    print "Not an NDEF tag - remove tag"
+                    while tag.is_present:
+                        time.sleep(0.1)
+                    break
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()

Copied: vendor/wpa/2.0/wpa_supplicant/gas_query.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/gas_query.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/gas_query.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/gas_query.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,519 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+#include "gas_query.h"
+
+
+/** GAS query timeout in seconds */
+#define GAS_QUERY_TIMEOUT_PERIOD 5
+
+
+/**
+ * struct gas_query_pending - Pending GAS query
+ */
+struct gas_query_pending {
+	struct dl_list list;
+	u8 addr[ETH_ALEN];
+	u8 dialog_token;
+	u8 next_frag_id;
+	unsigned int wait_comeback:1;
+	unsigned int offchannel_tx_started:1;
+	int freq;
+	u16 status_code;
+	struct wpabuf *adv_proto;
+	struct wpabuf *resp;
+	void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+		   enum gas_query_result result,
+		   const struct wpabuf *adv_proto,
+		   const struct wpabuf *resp, u16 status_code);
+	void *ctx;
+};
+
+/**
+ * struct gas_query - Internal GAS query data
+ */
+struct gas_query {
+	struct wpa_supplicant *wpa_s;
+	struct dl_list pending; /* struct gas_query_pending */
+};
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_timeout(void *eloop_data, void *user_ctx);
+
+
+/**
+ * gas_query_init - Initialize GAS query component
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to GAS query data or %NULL on failure
+ */
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+	struct gas_query *gas;
+
+	gas = os_zalloc(sizeof(*gas));
+	if (gas == NULL)
+		return NULL;
+
+	gas->wpa_s = wpa_s;
+	dl_list_init(&gas->pending);
+
+	return gas;
+}
+
+
+static void gas_query_done(struct gas_query *gas,
+			   struct gas_query_pending *query,
+			   enum gas_query_result result)
+{
+	if (query->offchannel_tx_started)
+		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);
+	dl_list_del(&query->list);
+	query->cb(query->ctx, query->addr, query->dialog_token, result,
+		  query->adv_proto, query->resp, query->status_code);
+	wpabuf_free(query->adv_proto);
+	wpabuf_free(query->resp);
+	os_free(query);
+}
+
+
+/**
+ * gas_query_deinit - Deinitialize GAS query component
+ * @gas: GAS query data from gas_query_init()
+ */
+void gas_query_deinit(struct gas_query *gas)
+{
+	struct gas_query_pending *query, *next;
+
+	if (gas == NULL)
+		return;
+
+	dl_list_for_each_safe(query, next, &gas->pending,
+			      struct gas_query_pending, list)
+		gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
+
+	os_free(gas);
+}
+
+
+static struct gas_query_pending *
+gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
+{
+	struct gas_query_pending *q;
+	dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+		if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
+		    q->dialog_token == dialog_token)
+			return q;
+	}
+	return NULL;
+}
+
+
+static int gas_query_append(struct gas_query_pending *query, const u8 *data,
+			    size_t len)
+{
+	if (wpabuf_resize(&query->resp, len) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
+		return -1;
+	}
+	wpabuf_put_data(query->resp, data, len);
+	return 0;
+}
+
+
+static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
+			struct wpabuf *req)
+{
+	int res;
+	wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
+		   "freq=%d", MAC2STR(query->addr),
+		   (unsigned int) wpabuf_len(req), query->freq);
+	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
+				     gas->wpa_s->own_addr, query->addr,
+				     wpabuf_head(req), wpabuf_len(req), 1000,
+				     NULL, 0);
+	if (res == 0)
+		query->offchannel_tx_started = 1;
+	return res;
+}
+
+
+static void gas_query_tx_comeback_req(struct gas_query *gas,
+				      struct gas_query_pending *query)
+{
+	struct wpabuf *req;
+
+	req = gas_build_comeback_req(query->dialog_token);
+	if (req == NULL) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (gas_query_tx(gas, query, req) < 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);
+	}
+
+	wpabuf_free(req);
+}
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct gas_query_pending *query = user_ctx;
+
+	wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
+		   MAC2STR(query->addr));
+	gas_query_tx_comeback_req(gas, query);
+}
+
+
+static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
+					    struct gas_query_pending *query,
+					    u16 comeback_delay)
+{
+	unsigned int secs, usecs;
+
+	secs = (comeback_delay * 1024) / 1000000;
+	usecs = comeback_delay * 1024 - secs * 1000000;
+	wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
+		   " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
+	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+	eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
+			       gas, query);
+}
+
+
+static void gas_query_rx_initial(struct gas_query *gas,
+				 struct gas_query_pending *query,
+				 const u8 *adv_proto, const u8 *resp,
+				 size_t len, u16 comeback_delay)
+{
+	wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
+		   MACSTR " (dialog_token=%u comeback_delay=%u)",
+		   MAC2STR(query->addr), query->dialog_token, comeback_delay);
+
+	query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
+	if (query->adv_proto == NULL) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (comeback_delay) {
+		query->wait_comeback = 1;
+		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+		return;
+	}
+
+	/* Query was completed without comeback mechanism */
+	if (gas_query_append(query, resp, len) < 0) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+static void gas_query_rx_comeback(struct gas_query *gas,
+				  struct gas_query_pending *query,
+				  const u8 *adv_proto, const u8 *resp,
+				  size_t len, u8 frag_id, u8 more_frags,
+				  u16 comeback_delay)
+{
+	wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
+		   MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
+		   "comeback_delay=%u)",
+		   MAC2STR(query->addr), query->dialog_token, frag_id,
+		   more_frags, comeback_delay);
+
+	if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
+	    os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
+		      wpabuf_len(query->adv_proto)) != 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
+			   "between initial and comeback response from "
+			   MACSTR, MAC2STR(query->addr));
+		gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+		return;
+	}
+
+	if (comeback_delay) {
+		if (frag_id) {
+			wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
+				   "with non-zero frag_id and comeback_delay "
+				   "from " MACSTR, MAC2STR(query->addr));
+			gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+			return;
+		}
+		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+		return;
+	}
+
+	if (frag_id != query->next_frag_id) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
+			   "from " MACSTR, MAC2STR(query->addr));
+		gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+		return;
+	}
+	query->next_frag_id++;
+
+	if (gas_query_append(query, resp, len) < 0) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (more_frags) {
+		gas_query_tx_comeback_req(gas, query);
+		return;
+	}
+
+	gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+/**
+ * gas_query_rx - Indicate reception of a Public Action frame
+ * @gas: GAS query data from gas_query_init()
+ * @da: Destination MAC address of the Action frame
+ * @sa: Source MAC address of the Action frame
+ * @bssid: BSSID of the Action frame
+ * @data: Payload of the Action frame
+ * @len: Length of @data
+ * @freq: Frequency (in MHz) on which the frame was received
+ * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
+ */
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+		 const u8 *bssid, const u8 *data, size_t len, int freq)
+{
+	struct gas_query_pending *query;
+	u8 action, dialog_token, frag_id = 0, more_frags = 0;
+	u16 comeback_delay, resp_len;
+	const u8 *pos, *adv_proto;
+
+	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 */
+
+	query = gas_query_get_pending(gas, sa, dialog_token);
+	if (query == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
+			   " dialog token %u", MAC2STR(sa), dialog_token);
+		return -1;
+	}
+
+	if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
+			   MACSTR " dialog token %u when waiting for comeback "
+			   "response", MAC2STR(sa), dialog_token);
+		return 0;
+	}
+
+	if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
+			   MACSTR " dialog token %u when waiting for initial "
+			   "response", MAC2STR(sa), dialog_token);
+		return 0;
+	}
+
+	query->status_code = WPA_GET_LE16(pos);
+	pos += 2;
+
+	if (query->status_code != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
+			   "%u failed - status code %u",
+			   MAC2STR(sa), dialog_token, query->status_code);
+		gas_query_done(gas, query, GAS_QUERY_FAILURE);
+		return 0;
+	}
+
+	if (action == WLAN_PA_GAS_COMEBACK_RESP) {
+		if (pos + 1 > data + len)
+			return 0;
+		frag_id = *pos & 0x7f;
+		more_frags = (*pos & 0x80) >> 7;
+		pos++;
+	}
+
+	/* Comeback Delay */
+	if (pos + 2 > data + len)
+		return 0;
+	comeback_delay = WPA_GET_LE16(pos);
+	pos += 2;
+
+	/* Advertisement Protocol element */
+	if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
+			   "Protocol element in the response from " MACSTR,
+			   MAC2STR(sa));
+		return 0;
+	}
+
+	if (*pos != WLAN_EID_ADV_PROTO) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
+			   "Protocol element ID %u in response from " MACSTR,
+			   *pos, MAC2STR(sa));
+		return 0;
+	}
+
+	adv_proto = pos;
+	pos += 2 + pos[1];
+
+	/* Query Response Length */
+	if (pos + 2 > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
+		return 0;
+	}
+	resp_len = WPA_GET_LE16(pos);
+	pos += 2;
+
+	if (pos + resp_len > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
+			   "response from " MACSTR, MAC2STR(sa));
+		return 0;
+	}
+
+	if (pos + resp_len < data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
+			   "after Query Response from " MACSTR,
+			   (unsigned int) (data + len - pos - resp_len),
+			   MAC2STR(sa));
+	}
+
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
+				      frag_id, more_frags, comeback_delay);
+	else
+		gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
+				     comeback_delay);
+
+	return 0;
+}
+
+
+static void gas_query_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct gas_query_pending *query = user_ctx;
+
+	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
+		   MAC2STR(query->addr));
+	gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
+}
+
+
+static int gas_query_dialog_token_available(struct gas_query *gas,
+					    const u8 *dst, u8 dialog_token)
+{
+	struct gas_query_pending *q;
+	dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+		if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
+		    dialog_token == q->dialog_token)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/**
+ * gas_query_req - Request a GAS query
+ * @gas: GAS query data from gas_query_init()
+ * @dst: Destination MAC address for the query
+ * @freq: Frequency (in MHz) for the channel on which to send the query
+ * @req: GAS query payload
+ * @cb: Callback function for reporting GAS query result and response
+ * @ctx: Context pointer to use with the @cb call
+ * Returns: dialog token (>= 0) on success or -1 on failure
+ */
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+		  struct wpabuf *req,
+		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+			     enum gas_query_result result,
+			     const struct wpabuf *adv_proto,
+			     const struct wpabuf *resp, u16 status_code),
+		  void *ctx)
+{
+	struct gas_query_pending *query;
+	int dialog_token;
+
+	if (wpabuf_len(req) < 3)
+		return -1;
+
+	for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+		if (gas_query_dialog_token_available(gas, dst, dialog_token))
+			break;
+	}
+	if (dialog_token == 256)
+		return -1; /* Too many pending queries */
+
+	query = os_zalloc(sizeof(*query));
+	if (query == NULL)
+		return -1;
+
+	os_memcpy(query->addr, dst, ETH_ALEN);
+	query->dialog_token = dialog_token;
+	query->freq = freq;
+	query->cb = cb;
+	query->ctx = ctx;
+	dl_list_add(&gas->pending, &query->list);
+
+	*(wpabuf_mhead_u8(req) + 2) = dialog_token;
+
+	wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
+		   " dialog_token %u", MAC2STR(dst), dialog_token);
+	if (gas_query_tx(gas, query, req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		dl_list_del(&query->list);
+		os_free(query);
+		return -1;
+	}
+
+	eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
+			       gas, query);
+
+	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);
+
+}

Copied: vendor/wpa/2.0/wpa_supplicant/gas_query.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/gas_query.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/gas_query.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/gas_query.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,58 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_QUERY_H
+#define GAS_QUERY_H
+
+struct gas_query;
+
+#ifdef CONFIG_GAS
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
+void gas_query_deinit(struct gas_query *gas);
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+		 const u8 *bssid, const u8 *data, size_t len, int freq);
+
+/**
+ * enum gas_query_result - GAS query result
+ */
+enum gas_query_result {
+	GAS_QUERY_SUCCESS,
+	GAS_QUERY_FAILURE,
+	GAS_QUERY_TIMEOUT,
+	GAS_QUERY_PEER_ERROR,
+	GAS_QUERY_INTERNAL_ERROR,
+	GAS_QUERY_CANCELLED,
+	GAS_QUERY_DELETED_AT_DEINIT
+};
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+		  struct wpabuf *req,
+		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+			     enum gas_query_result result,
+			     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 */
+
+static inline struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+	return (void *) 1;
+}
+
+static inline void gas_query_deinit(struct gas_query *gas)
+{
+}
+
+#endif /* CONFIG_GAS */
+
+
+#endif /* GAS_QUERY_H */

Copied: vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/hs20_supplicant.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "config.h"
+#include "bss.h"
+#include "gas_query.h"
+#include "interworking.h"
+#include "hs20_supplicant.h"
+
+
+void wpas_hs20_add_indication(struct wpabuf *buf)
+{
+	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+	wpabuf_put_u8(buf, 5);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
+	wpabuf_put_u8(buf, 0x00); /* Hotspot Configuration */
+}
+
+
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+				    size_t payload_len)
+{
+	struct wpabuf *buf;
+	u8 *len_pos;
+
+	buf = gas_anqp_build_initial_req(0, 100 + payload_len);
+	if (buf == NULL)
+		return NULL;
+
+	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+	if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) {
+		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		if (payload)
+			wpabuf_put_data(buf, payload, payload_len);
+	} else {
+		u8 i;
+		wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		for (i = 0; i < 32; i++) {
+			if (stypes & BIT(i))
+				wpabuf_put_u8(buf, i);
+		}
+	}
+	gas_anqp_set_element_len(buf, len_pos);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+		       const u8 *payload, size_t payload_len)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int freq;
+	struct wpa_bss *bss;
+	int res;
+
+	freq = wpa_s->assoc_freq;
+	bss = wpa_bss_get_bssid(wpa_s, dst);
+	if (bss) {
+		wpa_bss_anqp_unshare_alloc(bss);
+		freq = bss->freq;
+	}
+	if (freq <= 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for "
+		   "subtypes 0x%x", MAC2STR(dst), stypes);
+
+	buf = hs20_build_anqp_req(stypes, payload, payload_len);
+	if (buf == NULL)
+		return -1;
+
+	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		ret = -1;
+	} else
+		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+				  const u8 *sa, const u8 *data, size_t slen)
+{
+	const u8 *pos = data;
+	u8 subtype;
+	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+	struct wpa_bss_anqp *anqp = NULL;
+
+	if (slen < 2)
+		return;
+
+	if (bss)
+		anqp = bss->anqp;
+
+	subtype = *pos++;
+	slen--;
+
+	pos++; /* Reserved */
+	slen--;
+
+	switch (subtype) {
+	case HS20_STYPE_CAPABILITY_LIST:
+		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);
+		break;
+	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+		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) {
+			wpabuf_free(anqp->hs20_operator_friendly_name);
+			anqp->hs20_operator_friendly_name =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case HS20_STYPE_WAN_METRICS:
+		wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
+		if (slen < 13) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
+				"Metrics value from " MACSTR, MAC2STR(sa));
+			break;
+		}
+		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));
+		if (anqp) {
+			wpabuf_free(anqp->hs20_wan_metrics);
+			anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case HS20_STYPE_CONNECTION_CAPABILITY:
+		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) {
+			wpabuf_free(anqp->hs20_connection_capability);
+			anqp->hs20_connection_capability =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case HS20_STYPE_OPERATING_CLASS:
+		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) {
+			wpabuf_free(anqp->hs20_operating_class);
+			anqp->hs20_operating_class =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
+		break;
+	}
+}

Copied: vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/hs20_supplicant.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/hs20_supplicant.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_SUPPLICANT_H
+#define HS20_SUPPLICANT_H
+
+void wpas_hs20_add_indication(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);
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+				    size_t payload_len);
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+				  const u8 *sa, const u8 *data, size_t slen);
+
+#endif /* HS20_SUPPLICANT_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ibss_rsn.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,510 +0,0 @@
-/*
- * wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "l2_packet/l2_packet.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/wpa_ie.h"
-#include "ap/wpa_auth.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "ibss_rsn.h"
-
-
-static void ibss_rsn_free(struct ibss_rsn_peer *peer)
-{
-	wpa_auth_sta_deinit(peer->auth);
-	wpa_sm_deinit(peer->supp);
-	os_free(peer);
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
-	struct ibss_rsn_peer *peer = ctx;
-	peer->supp_state = state;
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
-			   size_t len)
-{
-	struct ibss_rsn_peer *peer = ctx;
-	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
-		   "len=%lu)",
-		   __func__, MAC2STR(dest), proto, (unsigned long) len);
-
-	if (wpa_s->l2)
-		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
-
-	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
-			     u16 data_len, size_t *msg_len, void **data_pos)
-{
-	struct ieee802_1x_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
-		   __func__, type, data_len);
-
-	*msg_len = sizeof(*hdr) + data_len;
-	hdr = os_malloc(*msg_len);
-	if (hdr == NULL)
-		return NULL;
-
-	hdr->version = 2;
-	hdr->type = type;
-	hdr->length = host_to_be16(data_len);
-
-	if (data)
-		os_memcpy(hdr + 1, data, data_len);
-	else
-		os_memset(hdr + 1, 0, data_len);
-
-	if (data_pos)
-		*data_pos = hdr + 1;
-
-	return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
-	struct ibss_rsn_peer *peer = ctx;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-	/* TODO: get correct RSN IE */
-	return wpa_sm_set_ap_rsn_ie(peer->supp,
-				    (u8 *) "\x30\x14\x01\x00"
-				    "\x00\x0f\xac\x04"
-				    "\x01\x00\x00\x0f\xac\x04"
-				    "\x01\x00\x00\x0f\xac\x02"
-				    "\x00\x00", 22);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
-			const u8 *addr, int key_idx, int set_tx,
-			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
-{
-	struct ibss_rsn_peer *peer = ctx;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
-		   "set_tx=%d)",
-		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
-	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
-	wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
-
-	if (key_idx == 0) {
-		/*
-		 * In IBSS RSN, the pairwise key from the 4-way handshake
-		 * initiated by the peer with highest MAC address is used.
-		 */
-		if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr,
-			      ETH_ALEN) > 0) {
-			wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK");
-			return 0;
-		}
-	}
-
-	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
-			       set_tx, seq, seq_len, key, key_len);
-}
-
-
-static void * supp_get_network_ctx(void *ctx)
-{
-	struct ibss_rsn_peer *peer = ctx;
-	return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s);
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
-				   int protection_type, int key_type)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
-		   "key_type=%d)",
-		   __func__, MAC2STR(addr), protection_type, key_type);
-	return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
-		       const u8 *psk)
-{
-	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return -1;
-
-	ctx->ctx = peer;
-	ctx->msg_ctx = peer->ibss_rsn->wpa_s;
-	ctx->set_state = supp_set_state;
-	ctx->ether_send = supp_ether_send;
-	ctx->get_beacon_ie = supp_get_beacon_ie;
-	ctx->alloc_eapol = supp_alloc_eapol;
-	ctx->set_key = supp_set_key;
-	ctx->get_network_ctx = supp_get_network_ctx;
-	ctx->mlme_setprotection = supp_mlme_setprotection;
-	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
-	peer->supp = wpa_sm_init(ctx);
-	if (peer->supp == NULL) {
-		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
-		return -1;
-	}
-
-	wpa_sm_set_own_addr(peer->supp, own_addr);
-	wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1);
-	wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
-	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);
-
-	peer->supp_ie_len = sizeof(peer->supp_ie);
-	if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
-					    &peer->supp_ie_len) < 0) {
-		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
-			   " failed");
-		return -1;
-	}
-
-	wpa_sm_notify_assoc(peer->supp, peer->addr);
-
-	return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
-			const char *txt)
-{
-	if (addr)
-		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
-			   MAC2STR(addr), txt);
-	else
-		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
-{
-	struct ibss_rsn *ibss_rsn = ctx;
-	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
-		   __func__, MAC2STR(addr), prev_psk);
-	if (prev_psk)
-		return NULL;
-	return ibss_rsn->psk;
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
-			   size_t data_len, int encrypt)
-{
-	struct ibss_rsn *ibss_rsn = ctx;
-	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
-
-	wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
-		   "encrypt=%d)",
-		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
-
-	if (wpa_s->l2)
-		return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
-				      data_len);
-
-	return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
-}
-
-
-static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
-{
-	struct ibss_rsn *ibss_rsn = ctx;
-	u8 seq[6];
-
-	os_memset(seq, 0, sizeof(seq));
-
-	if (addr) {
-		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
-			   " key_idx=%d)",
-			   __func__, alg, MAC2STR(addr), idx);
-	} else {
-		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
-			   __func__, alg, idx);
-	}
-	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
-
-	if (idx == 0) {
-		/*
-		 * In IBSS RSN, the pairwise key from the 4-way handshake
-		 * initiated by the peer with highest MAC address is used.
-		 */
-		if (addr == NULL ||
-		    os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) {
-			wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK");
-			return 0;
-		}
-	}
-
-	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
-}
-
-
-static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
-				    const u8 *own_addr)
-{
-	struct wpa_auth_config conf;
-	struct wpa_auth_callbacks cb;
-
-	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
-	os_memset(&conf, 0, sizeof(conf));
-	conf.wpa = 2;
-	conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-	conf.wpa_pairwise = WPA_CIPHER_CCMP;
-	conf.rsn_pairwise = WPA_CIPHER_CCMP;
-	conf.wpa_group = WPA_CIPHER_CCMP;
-	conf.eapol_version = 2;
-
-	os_memset(&cb, 0, sizeof(cb));
-	cb.ctx = ibss_rsn;
-	cb.logger = auth_logger;
-	cb.send_eapol = auth_send_eapol;
-	cb.get_psk = auth_get_psk;
-	cb.set_key = auth_set_key;
-
-	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
-	if (ibss_rsn->auth_group == NULL) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
-			      struct ibss_rsn_peer *peer)
-{
-	peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr);
-	if (peer->auth == NULL) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
-		return -1;
-	}
-
-	/* TODO: get peer RSN IE with Probe Request */
-	if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth,
-				(u8 *) "\x30\x14\x01\x00"
-				"\x00\x0f\xac\x04"
-				"\x01\x00\x00\x0f\xac\x04"
-				"\x01\x00\x00\x0f\xac\x02"
-				"\x00\x00", 22, NULL, 0) !=
-	    WPA_IE_OK) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
-		return -1;
-	}
-
-	if (wpa_auth_sm_event(peer->auth, WPA_ASSOC))
-		return -1;
-
-	if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth))
-		return -1;
-
-	return 0;
-}
-
-
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
-{
-	struct ibss_rsn_peer *peer;
-
-	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
-		   "Supplicant for peer " MACSTR, MAC2STR(addr));
-
-	peer = os_zalloc(sizeof(*peer));
-	if (peer == NULL)
-		return -1;
-
-	peer->ibss_rsn = ibss_rsn;
-	os_memcpy(peer->addr, addr, ETH_ALEN);
-
-	if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
-	    < 0) {
-		ibss_rsn_free(peer);
-		return -1;
-	}
-
-	if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
-		ibss_rsn_free(peer);
-		return -1;
-	}
-
-	peer->next = ibss_rsn->peers;
-	ibss_rsn->peers = peer;
-
-	return 0;
-}
-
-
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
-{
-	struct ibss_rsn *ibss_rsn;
-
-	ibss_rsn = os_zalloc(sizeof(*ibss_rsn));
-	if (ibss_rsn == NULL)
-		return NULL;
-	ibss_rsn->wpa_s = wpa_s;
-
-	if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
-		ibss_rsn_deinit(ibss_rsn);
-		return NULL;
-	}
-
-	return ibss_rsn;
-}
-
-
-void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn)
-{
-	struct ibss_rsn_peer *peer, *prev;
-
-	if (ibss_rsn == NULL)
-		return;
-
-	peer = ibss_rsn->peers;
-	while (peer) {
-		prev = peer;
-		peer = peer->next;
-		ibss_rsn_free(prev);
-	}
-
-	wpa_deinit(ibss_rsn->auth_group);
-	os_free(ibss_rsn);
-
-}
-
-
-static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len)
-{
-	const struct ieee802_1x_hdr *hdr;
-	const struct wpa_eapol_key *key;
-	u16 key_info;
-	size_t plen;
-
-	/* TODO: Support other EAPOL packets than just EAPOL-Key */
-
-	if (len < sizeof(*hdr) + sizeof(*key))
-		return -1;
-
-	hdr = (const struct ieee802_1x_hdr *) buf;
-	key = (const struct wpa_eapol_key *) (hdr + 1);
-	plen = be_to_host16(hdr->length);
-
-	if (hdr->version < EAPOL_VERSION) {
-		/* TODO: backwards compatibility */
-	}
-	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
-		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, "
-			"not a Key frame", hdr->type);
-		return -1;
-	}
-	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
-		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu "
-			   "invalid (frame size %lu)",
-			   (unsigned long) plen, (unsigned long) len);
-		return -1;
-	}
-
-	if (key->type != EAPOL_KEY_TYPE_RSN) {
-		wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, "
-			   "discarded", key->type);
-		return -1;
-	}
-
-	key_info = WPA_GET_BE16(key->key_info);
-
-	return !!(key_info & WPA_KEY_INFO_ACK);
-}
-
-
-static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
-				     struct ibss_rsn_peer *peer,
-				     const u8 *buf, size_t len)
-{
-	int supp;
-	u8 *tmp;
-
-	supp = ibss_rsn_eapol_dst_supp(buf, len);
-	if (supp < 0)
-		return -1;
-
-	tmp = os_malloc(len);
-	if (tmp == NULL)
-		return -1;
-	os_memcpy(tmp, buf, len);
-	if (supp) {
-		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
-		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
-	} else {
-		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
-		wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
-	}
-	os_free(tmp);
-
-	return 1;
-}
-
-
-int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
-		      const u8 *buf, size_t len)
-{
-	struct ibss_rsn_peer *peer;
-
-	for (peer = ibss_rsn->peers; peer; peer = peer->next) {
-		if (os_memcmp(src_addr, peer->addr, ETH_ALEN) == 0)
-			return ibss_rsn_process_rx_eapol(ibss_rsn, peer,
-							 buf, len);
-	}
-
-	if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
-		/*
-		 * Create new IBSS peer based on an EAPOL message from the peer
-		 * Authenticator.
-		 */
-		if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
-			return -1;
-		return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
-						 buf, len);
-	}
-
-	return 0;
-}
-
-
-void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
-{
-	os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/ibss_rsn.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ibss_rsn.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,656 @@
+/*
+ * wpa_supplicant - IBSS RSN
+ * Copyright (c) 2009, Jouni Malinen <j at 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 "l2_packet/l2_packet.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_ie.h"
+#include "ap/wpa_auth.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ibss_rsn.h"
+
+
+static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
+						const u8 *addr)
+{
+	struct ibss_rsn_peer *peer;
+
+	for (peer = ibss_rsn->peers; peer; peer = peer->next)
+		if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0)
+			break;
+	return peer;
+}
+
+
+static void ibss_rsn_free(struct ibss_rsn_peer *peer)
+{
+	wpa_auth_sta_deinit(peer->auth);
+	wpa_sm_deinit(peer->supp);
+	os_free(peer);
+}
+
+
+static void supp_set_state(void *ctx, enum wpa_states state)
+{
+	struct ibss_rsn_peer *peer = ctx;
+	peer->supp_state = state;
+}
+
+
+static enum wpa_states supp_get_state(void *ctx)
+{
+	struct ibss_rsn_peer *peer = ctx;
+	return peer->supp_state;
+}
+
+
+static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+			   size_t len)
+{
+	struct ibss_rsn_peer *peer = ctx;
+	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
+		   "len=%lu)",
+		   __func__, MAC2STR(dest), proto, (unsigned long) len);
+
+	if (wpa_s->l2)
+		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
+
+	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+}
+
+
+static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
+			     u16 data_len, size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
+		   __func__, type, data_len);
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = 2;
+	hdr->type = type;
+	hdr->length = host_to_be16(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+static int supp_get_beacon_ie(void *ctx)
+{
+	struct ibss_rsn_peer *peer = ctx;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+	/* TODO: get correct RSN IE */
+	return wpa_sm_set_ap_rsn_ie(peer->supp,
+				    (u8 *) "\x30\x14\x01\x00"
+				    "\x00\x0f\xac\x04"
+				    "\x01\x00\x00\x0f\xac\x04"
+				    "\x01\x00\x00\x0f\xac\x02"
+				    "\x00\x00", 22);
+}
+
+
+static int supp_set_key(void *ctx, enum wpa_alg alg,
+			const u8 *addr, int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			const u8 *key, size_t key_len)
+{
+	struct ibss_rsn_peer *peer = ctx;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
+		   "set_tx=%d)",
+		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
+	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
+	wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
+
+	if (key_idx == 0) {
+		/*
+		 * In IBSS RSN, the pairwise key from the 4-way handshake
+		 * initiated by the peer with highest MAC address is used.
+		 */
+		if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr,
+			      ETH_ALEN) > 0) {
+			wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK");
+			return 0;
+		}
+	}
+
+	if (is_broadcast_ether_addr(addr))
+		addr = peer->addr;
+	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
+			       set_tx, seq, seq_len, key, key_len);
+}
+
+
+static void * supp_get_network_ctx(void *ctx)
+{
+	struct ibss_rsn_peer *peer = ctx;
+	return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s);
+}
+
+
+static int supp_mlme_setprotection(void *ctx, const u8 *addr,
+				   int protection_type, int key_type)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
+		   "key_type=%d)",
+		   __func__, MAC2STR(addr), protection_type, key_type);
+	return 0;
+}
+
+
+static void supp_cancel_auth_timeout(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+}
+
+
+static void supp_deauthenticate(void * ctx, int reason_code)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__);
+}
+
+
+static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
+			      const u8 *psk)
+{
+	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return -1;
+
+	ctx->ctx = peer;
+	ctx->msg_ctx = peer->ibss_rsn->wpa_s;
+	ctx->set_state = supp_set_state;
+	ctx->get_state = supp_get_state;
+	ctx->ether_send = supp_ether_send;
+	ctx->get_beacon_ie = supp_get_beacon_ie;
+	ctx->alloc_eapol = supp_alloc_eapol;
+	ctx->set_key = supp_set_key;
+	ctx->get_network_ctx = supp_get_network_ctx;
+	ctx->mlme_setprotection = supp_mlme_setprotection;
+	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
+	ctx->deauthenticate = supp_deauthenticate;
+	peer->supp = wpa_sm_init(ctx);
+	if (peer->supp == NULL) {
+		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+		return -1;
+	}
+
+	wpa_sm_set_own_addr(peer->supp, own_addr);
+	wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1);
+	wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+	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);
+
+	peer->supp_ie_len = sizeof(peer->supp_ie);
+	if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
+					    &peer->supp_ie_len) < 0) {
+		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
+			   " failed");
+		return -1;
+	}
+
+	wpa_sm_notify_assoc(peer->supp, peer->addr);
+
+	return 0;
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+			const char *txt)
+{
+	if (addr)
+		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+			   MAC2STR(addr), txt);
+	else
+		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+		   __func__, MAC2STR(addr), prev_psk);
+	if (prev_psk)
+		return NULL;
+	return ibss_rsn->psk;
+}
+
+
+static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
+			   size_t data_len, int encrypt)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
+
+	wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
+		   "encrypt=%d)",
+		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+
+	if (wpa_s->l2)
+		return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
+				      data_len);
+
+	return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+			const u8 *addr, int idx, u8 *key, size_t key_len)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	u8 seq[6];
+
+	os_memset(seq, 0, sizeof(seq));
+
+	if (addr) {
+		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
+			   " key_idx=%d)",
+			   __func__, alg, MAC2STR(addr), idx);
+	} else {
+		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
+			   __func__, alg, idx);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
+
+	if (idx == 0) {
+		/*
+		 * In IBSS RSN, the pairwise key from the 4-way handshake
+		 * initiated by the peer with highest MAC address is used.
+		 */
+		if (addr == NULL ||
+		    os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) {
+			wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK");
+			return 0;
+		}
+	}
+
+	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
+			       1, seq, 6, key, key_len);
+}
+
+
+static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+						  void *ctx),
+			     void *cb_ctx)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	struct ibss_rsn_peer *peer;
+
+	wpa_printf(MSG_DEBUG, "AUTH: for_each_sta");
+
+	for (peer = ibss_rsn->peers; peer; peer = peer->next) {
+		if (peer->auth && cb(peer->auth, cb_ctx))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn,
+				    struct ibss_rsn_peer *peer, int authorized)
+{
+	int res;
+
+	if (authorized) {
+		res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
+					    WPA_STA_AUTHORIZED,
+					    WPA_STA_AUTHORIZED, ~0);
+		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port",
+			   MAC2STR(peer->addr));
+	} else {
+		res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr,
+					    0, 0, ~WPA_STA_AUTHORIZED);
+		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port",
+			   MAC2STR(peer->addr));
+	}
+
+	if (res && errno != ENOENT) {
+		wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags "
+			   "for kernel driver (errno=%d)",
+			   MAC2STR(peer->addr), errno);
+	}
+}
+
+
+static void auth_set_eapol(void *ctx, const u8 *addr,
+				       wpa_eapol_variable var, int value)
+{
+	struct ibss_rsn *ibss_rsn = ctx;
+	struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr);
+
+	if (peer == NULL)
+		return;
+
+	switch (var) {
+	case WPA_EAPOL_authorized:
+		ibss_set_sta_authorized(ibss_rsn, peer, value);
+		break;
+	default:
+		/* do not handle any other event */
+		wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var);
+		break;
+	}
+}
+
+
+static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
+				    const u8 *own_addr)
+{
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+
+	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.wpa = 2;
+	conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+	conf.wpa_pairwise = WPA_CIPHER_CCMP;
+	conf.rsn_pairwise = WPA_CIPHER_CCMP;
+	conf.wpa_group = WPA_CIPHER_CCMP;
+	conf.eapol_version = 2;
+	conf.wpa_group_rekey = 600;
+
+	os_memset(&cb, 0, sizeof(cb));
+	cb.ctx = ibss_rsn;
+	cb.logger = auth_logger;
+	cb.set_eapol = auth_set_eapol;
+	cb.send_eapol = auth_send_eapol;
+	cb.get_psk = auth_get_psk;
+	cb.set_key = auth_set_key;
+	cb.for_each_sta = auth_for_each_sta;
+
+	ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
+	if (ibss_rsn->auth_group == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+		return -1;
+	}
+
+	wpa_init_keys(ibss_rsn->auth_group);
+
+	return 0;
+}
+
+
+static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
+			      struct ibss_rsn_peer *peer)
+{
+	peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr);
+	if (peer->auth == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
+		return -1;
+	}
+
+	/* TODO: get peer RSN IE with Probe Request */
+	if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth,
+				(u8 *) "\x30\x14\x01\x00"
+				"\x00\x0f\xac\x04"
+				"\x01\x00\x00\x0f\xac\x04"
+				"\x01\x00\x00\x0f\xac\x02"
+				"\x00\x00", 22, NULL, 0) !=
+	    WPA_IE_OK) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
+		return -1;
+	}
+
+	if (wpa_auth_sm_event(peer->auth, WPA_ASSOC))
+		return -1;
+
+	if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth))
+		return -1;
+
+	return 0;
+}
+
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+	struct ibss_rsn_peer *peer;
+
+	if (ibss_rsn == NULL)
+		return -1;
+
+	if (ibss_rsn_get_peer(ibss_rsn, addr)) {
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant "
+			   "for peer " MACSTR " already running",
+			   MAC2STR(addr));
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
+		   "Supplicant for peer " MACSTR, MAC2STR(addr));
+
+	peer = os_zalloc(sizeof(*peer));
+	if (peer == NULL)
+		return -1;
+
+	peer->ibss_rsn = ibss_rsn;
+	os_memcpy(peer->addr, addr, ETH_ALEN);
+
+	if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
+	    < 0) {
+		ibss_rsn_free(peer);
+		return -1;
+	}
+
+	if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
+		ibss_rsn_free(peer);
+		return -1;
+	}
+
+	peer->next = ibss_rsn->peers;
+	ibss_rsn->peers = peer;
+
+	return 0;
+}
+
+
+void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
+{
+	struct ibss_rsn_peer *peer, *prev;
+
+	if (ibss_rsn == NULL)
+		return;
+
+	if (peermac == NULL) {
+		/* remove all peers */
+		wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__);
+		peer = ibss_rsn->peers;
+		while (peer) {
+			prev = peer;
+			peer = peer->next;
+			ibss_rsn_free(prev);
+			ibss_rsn->peers = peer;
+		}
+	} else {
+		/* remove specific peer */
+		wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR,
+			   __func__, MAC2STR(peermac));
+
+		for (prev = NULL, peer = ibss_rsn->peers; peer != NULL;
+		     prev = peer, peer = peer->next) {
+			if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) {
+				if (prev == NULL)
+					ibss_rsn->peers = peer->next;
+				else
+					prev->next = peer->next;
+				ibss_rsn_free(peer);
+				wpa_printf(MSG_DEBUG, "%s: Successfully "
+					   "removed a specific peer",
+					   __func__);
+				break;
+			}
+		}
+	}
+}
+
+
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+{
+	struct ibss_rsn *ibss_rsn;
+
+	ibss_rsn = os_zalloc(sizeof(*ibss_rsn));
+	if (ibss_rsn == NULL)
+		return NULL;
+	ibss_rsn->wpa_s = wpa_s;
+
+	if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+		ibss_rsn_deinit(ibss_rsn);
+		return NULL;
+	}
+
+	return ibss_rsn;
+}
+
+
+void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn)
+{
+	struct ibss_rsn_peer *peer, *prev;
+
+	if (ibss_rsn == NULL)
+		return;
+
+	peer = ibss_rsn->peers;
+	while (peer) {
+		prev = peer;
+		peer = peer->next;
+		ibss_rsn_free(prev);
+	}
+
+	wpa_deinit(ibss_rsn->auth_group);
+	os_free(ibss_rsn);
+
+}
+
+
+static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len)
+{
+	const struct ieee802_1x_hdr *hdr;
+	const struct wpa_eapol_key *key;
+	u16 key_info;
+	size_t plen;
+
+	/* TODO: Support other EAPOL packets than just EAPOL-Key */
+
+	if (len < sizeof(*hdr) + sizeof(*key))
+		return -1;
+
+	hdr = (const struct ieee802_1x_hdr *) buf;
+	key = (const struct wpa_eapol_key *) (hdr + 1);
+	plen = be_to_host16(hdr->length);
+
+	if (hdr->version < EAPOL_VERSION) {
+		/* TODO: backwards compatibility */
+	}
+	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
+		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, "
+			"not a Key frame", hdr->type);
+		return -1;
+	}
+	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+		wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu "
+			   "invalid (frame size %lu)",
+			   (unsigned long) plen, (unsigned long) len);
+		return -1;
+	}
+
+	if (key->type != EAPOL_KEY_TYPE_RSN) {
+		wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, "
+			   "discarded", key->type);
+		return -1;
+	}
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	return !!(key_info & WPA_KEY_INFO_ACK);
+}
+
+
+static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
+				     struct ibss_rsn_peer *peer,
+				     const u8 *buf, size_t len)
+{
+	int supp;
+	u8 *tmp;
+
+	supp = ibss_rsn_eapol_dst_supp(buf, len);
+	if (supp < 0)
+		return -1;
+
+	tmp = os_malloc(len);
+	if (tmp == NULL)
+		return -1;
+	os_memcpy(tmp, buf, len);
+	if (supp) {
+		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
+		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
+	} else {
+		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
+		wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
+	}
+	os_free(tmp);
+
+	return 1;
+}
+
+
+int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
+		      const u8 *buf, size_t len)
+{
+	struct ibss_rsn_peer *peer;
+
+	if (ibss_rsn == NULL)
+		return -1;
+
+	peer = ibss_rsn_get_peer(ibss_rsn, src_addr);
+	if (peer)
+		return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len);
+
+	if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
+		/*
+		 * Create new IBSS peer based on an EAPOL message from the peer
+		 * Authenticator.
+		 */
+		if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
+			return -1;
+		return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
+						 buf, len);
+	}
+
+	return 0;
+}
+
+
+void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
+{
+	if (ibss_rsn == NULL)
+		return;
+	os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/ibss_rsn.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,49 +0,0 @@
-/*
- * wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef IBSS_RSN_H
-#define IBSS_RSN_H
-
-struct ibss_rsn;
-
-struct ibss_rsn_peer {
-	struct ibss_rsn_peer *next;
-	struct ibss_rsn *ibss_rsn;
-
-	u8 addr[ETH_ALEN];
-
-	struct wpa_sm *supp;
-	enum wpa_states supp_state;
-	u8 supp_ie[80];
-	size_t supp_ie_len;
-
-	struct wpa_state_machine *auth;
-};
-
-struct ibss_rsn {
-	struct wpa_supplicant *wpa_s;
-	struct wpa_authenticator *auth_group;
-	struct ibss_rsn_peer *peers;
-	u8 psk[PMK_LEN];
-};
-
-
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
-void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
-int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
-		      const u8 *buf, size_t len);
-void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
-
-#endif /* IBSS_RSN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/ibss_rsn.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/ibss_rsn.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,44 @@
+/*
+ * wpa_supplicant - IBSS RSN
+ * Copyright (c) 2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IBSS_RSN_H
+#define IBSS_RSN_H
+
+struct ibss_rsn;
+
+struct ibss_rsn_peer {
+	struct ibss_rsn_peer *next;
+	struct ibss_rsn *ibss_rsn;
+
+	u8 addr[ETH_ALEN];
+
+	struct wpa_sm *supp;
+	enum wpa_states supp_state;
+	u8 supp_ie[80];
+	size_t supp_ie_len;
+
+	struct wpa_state_machine *auth;
+};
+
+struct ibss_rsn {
+	struct wpa_supplicant *wpa_s;
+	struct wpa_authenticator *auth_group;
+	struct ibss_rsn_peer *peers;
+	u8 psk[PMK_LEN];
+};
+
+
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+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);
+int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
+		      const u8 *buf, size_t len);
+void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+
+#endif /* IBSS_RSN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/interworking.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/interworking.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/interworking.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/interworking.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2107 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "utils/pcsc_funcs.h"
+#include "utils/eloop.h"
+#include "drivers/driver.h"
+#include "eap_common/eap_defs.h"
+#include "eap_peer/eap.h"
+#include "eap_peer/eap_methods.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "config_ssid.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+#include "gas_query.h"
+#include "hs20_supplicant.h"
+#include "interworking.h"
+
+
+#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
+#define INTERWORKING_3GPP
+#endif
+#endif
+#endif
+
+static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+
+
+static void interworking_reconnect(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+
+	if (wpa_s->last_scan_res_used > 0) {
+		struct os_time now;
+		os_get_time(&now);
+		if (now.sec - wpa_s->last_scan.sec <= 5) {
+			wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
+				   "are fresh - connect without new scan");
+			if (wpas_select_network_from_last_scan(wpa_s) >= 0)
+				return;
+		}
+	}
+
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
+				      struct wpabuf *extra)
+{
+	struct wpabuf *buf;
+	size_t i;
+	u8 *len_pos;
+
+	buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
+					 (extra ? wpabuf_len(extra) : 0));
+	if (buf == NULL)
+		return NULL;
+
+	len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
+	for (i = 0; i < num_ids; i++)
+		wpabuf_put_le16(buf, info_ids[i]);
+	gas_anqp_set_element_len(buf, len_pos);
+	if (extra)
+		wpabuf_put_buf(buf, extra);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
+				      u8 dialog_token,
+				      enum gas_query_result result,
+				      const struct wpabuf *adv_proto,
+				      const struct wpabuf *resp,
+				      u16 status_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
+		     status_code);
+	interworking_next_anqp_fetch(wpa_s);
+}
+
+
+static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_cred *cred;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->roaming_consortium_len)
+			return 1;
+	}
+	return 0;
+}
+
+
+static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_cred *cred;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->pcsc || cred->imsi)
+			return 1;
+	}
+	return 0;
+}
+
+
+static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_cred *cred;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->pcsc || cred->imsi)
+			continue;
+		if (!cred->eap_method)
+			return 1;
+		if (cred->realm && cred->roaming_consortium_len == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
+static int cred_with_domain(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_cred *cred;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->domain || cred->pcsc || cred->imsi)
+			return 1;
+	}
+	return 0;
+}
+
+
+static int additional_roaming_consortiums(struct wpa_bss *bss)
+{
+	const u8 *ie;
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+	if (ie == NULL || ie[1] == 0)
+		return 0;
+	return ie[2]; /* Number of ANQP OIs */
+}
+
+
+static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	interworking_next_anqp_fetch(wpa_s);
+}
+
+
+static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
+				      struct wpa_bss *bss)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int res;
+	u16 info_ids[8];
+	size_t num_info_ids = 0;
+	struct wpabuf *extra = NULL;
+	int all = wpa_s->fetch_all_anqp;
+
+	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+		   MAC2STR(bss->bssid));
+
+	info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
+	if (all) {
+		info_ids[num_info_ids++] = ANQP_VENUE_NAME;
+		info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
+	}
+	if (all || (cred_with_roaming_consortium(wpa_s) &&
+		    additional_roaming_consortiums(bss)))
+		info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
+	if (all)
+		info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
+	if (all || cred_with_nai_realm(wpa_s))
+		info_ids[num_info_ids++] = ANQP_NAI_REALM;
+	if (all || cred_with_3gpp(wpa_s))
+		info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+	if (all || cred_with_domain(wpa_s))
+		info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
+	wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
+		    (u8 *) info_ids, num_info_ids * 2);
+
+#ifdef CONFIG_HS20
+	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+		u8 *len_pos;
+
+		extra = wpabuf_alloc(100);
+		if (!extra)
+			return -1;
+
+		len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(extra, OUI_WFA);
+		wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
+		wpabuf_put_u8(extra, 0); /* Reserved */
+		wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
+		if (all) {
+			wpabuf_put_u8(extra,
+				      HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+			wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+			wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+			wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+		}
+		gas_anqp_set_element_len(extra, len_pos);
+	}
+#endif /* CONFIG_HS20 */
+
+	buf = anqp_build_req(info_ids, num_info_ids, extra);
+	wpabuf_free(extra);
+	if (buf == NULL)
+		return -1;
+
+	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+			    interworking_anqp_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		ret = -1;
+		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
+				       NULL);
+	} else
+		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+struct nai_realm_eap {
+	u8 method;
+	u8 inner_method;
+	enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
+	u8 cred_type;
+	u8 tunneled_cred_type;
+};
+
+struct nai_realm {
+	u8 encoding;
+	char *realm;
+	u8 eap_count;
+	struct nai_realm_eap *eap;
+};
+
+
+static void nai_realm_free(struct nai_realm *realms, u16 count)
+{
+	u16 i;
+
+	if (realms == NULL)
+		return;
+	for (i = 0; i < count; i++) {
+		os_free(realms[i].eap);
+		os_free(realms[i].realm);
+	}
+	os_free(realms);
+}
+
+
+static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
+				      const u8 *end)
+{
+	u8 elen, auth_count, a;
+	const u8 *e_end;
+
+	if (pos + 3 > end) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
+		return NULL;
+	}
+
+	elen = *pos++;
+	if (pos + elen > end || elen < 2) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
+		return NULL;
+	}
+	e_end = pos + elen;
+	e->method = *pos++;
+	auth_count = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
+		   elen, e->method, auth_count);
+
+	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");
+			return NULL;
+		}
+
+		id = *pos++;
+		len = *pos++;
+
+		switch (id) {
+		case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
+			if (len < 1)
+				break;
+			e->inner_non_eap = *pos;
+			if (e->method != EAP_TYPE_TTLS)
+				break;
+			switch (*pos) {
+			case NAI_REALM_INNER_NON_EAP_PAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_CHAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_MSCHAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
+				break;
+			}
+			break;
+		case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
+			if (len < 1)
+				break;
+			e->inner_method = *pos;
+			wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
+				   e->inner_method);
+			break;
+		case NAI_REALM_EAP_AUTH_CRED_TYPE:
+			if (len < 1)
+				break;
+			e->cred_type = *pos;
+			wpa_printf(MSG_DEBUG, "Credential Type: %u",
+				   e->cred_type);
+			break;
+		case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
+			if (len < 1)
+				break;
+			e->tunneled_cred_type = *pos;
+			wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
+				   "Type: %u", e->tunneled_cred_type);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "Unsupported Authentication "
+				   "Parameter: id=%u len=%u", id, len);
+			wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
+				    "Value", pos, len);
+			break;
+		}
+
+		pos += len;
+	}
+
+	return e_end;
+}
+
+
+static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
+					const u8 *end)
+{
+	u16 len;
+	const u8 *f_end;
+	u8 realm_len, e;
+
+	if (end - pos < 4) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+			   "fixed fields");
+		return NULL;
+	}
+
+	len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
+	pos += 2;
+	if (pos + len > end || len < 3) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+			   "(len=%u; left=%u)",
+			   len, (unsigned int) (end - pos));
+		return NULL;
+	}
+	f_end = pos + len;
+
+	r->encoding = *pos++;
+	realm_len = *pos++;
+	if (pos + realm_len > f_end) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm "
+			   "(len=%u; left=%u)",
+			   realm_len, (unsigned int) (f_end - pos));
+		return NULL;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
+	r->realm = os_malloc(realm_len + 1);
+	if (r->realm == NULL)
+		return NULL;
+	os_memcpy(r->realm, pos, realm_len);
+	r->realm[realm_len] = '\0';
+	pos += realm_len;
+
+	if (pos + 1 > f_end) {
+		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) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Methods");
+		return NULL;
+	}
+	r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
+	if (r->eap == NULL)
+		return NULL;
+
+	for (e = 0; e < r->eap_count; e++) {
+		pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
+		if (pos == NULL)
+			return NULL;
+	}
+
+	return f_end;
+}
+
+
+static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
+{
+	struct nai_realm *realm;
+	const u8 *pos, *end;
+	u16 i, num;
+
+	if (anqp == NULL || wpabuf_len(anqp) < 2)
+		return NULL;
+
+	pos = wpabuf_head_u8(anqp);
+	end = pos + wpabuf_len(anqp);
+	num = WPA_GET_LE16(pos);
+	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
+	pos += 2;
+
+	if (num * 5 > end - pos) {
+		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
+			   "enough data (%u octets) for that many realms",
+			   num, (unsigned int) (end - pos));
+		return NULL;
+	}
+
+	realm = os_calloc(num, sizeof(struct nai_realm));
+	if (realm == NULL)
+		return NULL;
+
+	for (i = 0; i < num; i++) {
+		pos = nai_realm_parse_realm(&realm[i], pos, end);
+		if (pos == NULL) {
+			nai_realm_free(realm, num);
+			return NULL;
+		}
+	}
+
+	*count = num;
+	return realm;
+}
+
+
+static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
+{
+	char *tmp, *pos, *end;
+	int match = 0;
+
+	if (realm->realm == NULL || home_realm == NULL)
+		return 0;
+
+	if (os_strchr(realm->realm, ';') == NULL)
+		return os_strcasecmp(realm->realm, home_realm) == 0;
+
+	tmp = os_strdup(realm->realm);
+	if (tmp == NULL)
+		return 0;
+
+	pos = tmp;
+	while (*pos) {
+		end = os_strchr(pos, ';');
+		if (end)
+			*end = '\0';
+		if (os_strcasecmp(pos, home_realm) == 0) {
+			match = 1;
+			break;
+		}
+		if (end == NULL)
+			break;
+		pos = end + 1;
+	}
+
+	os_free(tmp);
+
+	return match;
+}
+
+
+static int nai_realm_cred_username(struct nai_realm_eap *eap)
+{
+	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+		return 0; /* method not supported */
+
+	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+		/* Only tunneled methods with username/password supported */
+		return 0;
+	}
+
+	if (eap->method == EAP_TYPE_PEAP) {
+		if (eap->inner_method &&
+		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+			return 0;
+		if (!eap->inner_method &&
+		    eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+			return 0;
+	}
+
+	if (eap->method == EAP_TYPE_TTLS) {
+		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
+			return 1; /* Assume TTLS/MSCHAPv2 is used */
+		if (eap->inner_method &&
+		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+			return 0;
+		if (eap->inner_non_eap &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+			return 0;
+	}
+
+	if (eap->inner_method &&
+	    eap->inner_method != EAP_TYPE_GTC &&
+	    eap->inner_method != EAP_TYPE_MSCHAPV2)
+		return 0;
+
+	return 1;
+}
+
+
+static int nai_realm_cred_cert(struct nai_realm_eap *eap)
+{
+	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+		return 0; /* method not supported */
+
+	if (eap->method != EAP_TYPE_TLS) {
+		/* Only EAP-TLS supported for credential authentication */
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
+						 struct nai_realm *realm)
+{
+	u8 e;
+
+	if (cred == NULL ||
+	    cred->username == NULL ||
+	    cred->username[0] == '\0' ||
+	    ((cred->password == NULL ||
+	      cred->password[0] == '\0') &&
+	     (cred->private_key == NULL ||
+	      cred->private_key[0] == '\0')))
+		return NULL;
+
+	for (e = 0; e < realm->eap_count; e++) {
+		struct nai_realm_eap *eap = &realm->eap[e];
+		if (cred->password && cred->password[0] &&
+		    nai_realm_cred_username(eap))
+			return eap;
+		if (cred->private_key && cred->private_key[0] &&
+		    nai_realm_cred_cert(eap))
+			return eap;
+	}
+
+	return NULL;
+}
+
+
+#ifdef INTERWORKING_3GPP
+
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
+{
+	u8 plmn[3];
+	const u8 *pos, *end;
+	u8 udhl;
+
+	/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+	plmn[1] = imsi[2] - '0';
+	/* default to MNC length 3 if unknown */
+	if (mnc_len != 2)
+		plmn[1] |= (imsi[5] - '0') << 4;
+	else
+		plmn[1] |= 0xf0;
+	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+
+	if (anqp == NULL)
+		return 0;
+	pos = wpabuf_head_u8(anqp);
+	end = pos + wpabuf_len(anqp);
+	if (pos + 2 > end)
+		return 0;
+	if (*pos != 0) {
+		wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
+		return 0;
+	}
+	pos++;
+	udhl = *pos++;
+	if (pos + udhl > end) {
+		wpa_printf(MSG_DEBUG, "Invalid UDHL");
+		return 0;
+	}
+	end = pos + udhl;
+
+	while (pos + 2 <= end) {
+		u8 iei, len;
+		const u8 *l_end;
+		iei = *pos++;
+		len = *pos++ & 0x7f;
+		if (pos + len > end)
+			break;
+		l_end = pos + len;
+
+		if (iei == 0 && len > 0) {
+			/* PLMN List */
+			u8 num, i;
+			num = *pos++;
+			for (i = 0; i < num; i++) {
+				if (pos + 3 > end)
+					break;
+				if (os_memcmp(pos, plmn, 3) == 0)
+					return 1; /* Found matching PLMN */
+				pos += 3;
+			}
+		}
+
+		pos = l_end;
+	}
+
+	return 0;
+}
+
+
+static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
+			  size_t mnc_len, char prefix)
+{
+	const char *sep, *msin;
+	char *end, *pos;
+	size_t msin_len, plmn_len;
+
+	/*
+	 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
+	 * Root NAI:
+	 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
+	 * <MNC> is zero-padded to three digits in case two-digit MNC is used
+	 */
+
+	if (imsi == NULL || os_strlen(imsi) > 16) {
+		wpa_printf(MSG_DEBUG, "No valid IMSI available");
+		return -1;
+	}
+	sep = os_strchr(imsi, '-');
+	if (sep) {
+		plmn_len = sep - imsi;
+		msin = sep + 1;
+	} else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
+		plmn_len = 3 + mnc_len;
+		msin = imsi + plmn_len;
+	} else
+		return -1;
+	if (plmn_len != 5 && plmn_len != 6)
+		return -1;
+	msin_len = os_strlen(msin);
+
+	pos = nai;
+	end = nai + nai_len;
+	if (prefix)
+		*pos++ = prefix;
+	os_memcpy(pos, imsi, plmn_len);
+	pos += plmn_len;
+	os_memcpy(pos, msin, msin_len);
+	pos += msin_len;
+	pos += os_snprintf(pos, end - pos, "@wlan.mnc");
+	if (plmn_len == 5) {
+		*pos++ = '0';
+		*pos++ = imsi[3];
+		*pos++ = imsi[4];
+	} else {
+		*pos++ = imsi[3];
+		*pos++ = imsi[4];
+		*pos++ = imsi[5];
+	}
+	pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
+			   imsi[0], imsi[1], imsi[2]);
+
+	return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+	char nai[100];
+	if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
+		return -1;
+	return wpa_config_set_quoted(ssid, "identity", nai);
+}
+
+#endif /* INTERWORKING_3GPP */
+
+
+static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	if (wpa_config_set(ssid, "key_mgmt",
+			   wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+			   "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
+		return -1;
+	if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
+		return -1;
+	if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+		return -1;
+	return 0;
+}
+
+
+static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+				     struct wpa_bss *bss)
+{
+#ifdef INTERWORKING_3GPP
+	struct wpa_cred *cred;
+	struct wpa_ssid *ssid;
+	const u8 *ie;
+	int eap_type;
+	int res;
+	char prefix;
+
+	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+		return -1;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		char *sep;
+		const char *imsi;
+		int mnc_len;
+
+#ifdef PCSC_FUNCS
+		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+		    wpa_s->imsi[0]) {
+			imsi = wpa_s->imsi;
+			mnc_len = wpa_s->mnc_len;
+			goto compare;
+		}
+#endif /* PCSC_FUNCS */
+
+		if (cred->imsi == NULL || !cred->imsi[0] ||
+		    cred->milenage == NULL || !cred->milenage[0])
+			continue;
+
+		sep = os_strchr(cred->imsi, '-');
+		if (sep == NULL ||
+		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+			continue;
+		mnc_len = sep - cred->imsi - 3;
+		imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+	compare:
+#endif /* PCSC_FUNCS */
+		if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
+			break;
+	}
+	if (cred == NULL)
+		return -1;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ie == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
+		   MAC2STR(bss->bssid));
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return -1;
+	ssid->parent_cred = cred;
+
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->priority = cred->priority;
+	ssid->temporary = 1;
+	ssid->ssid = os_zalloc(ie[1] + 1);
+	if (ssid->ssid == NULL)
+		goto fail;
+	os_memcpy(ssid->ssid, ie + 2, ie[1]);
+	ssid->ssid_len = ie[1];
+
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
+		goto fail;
+
+	eap_type = EAP_TYPE_SIM;
+	if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+		eap_type = EAP_TYPE_AKA;
+	if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
+		if (cred->eap_method[0].method == EAP_TYPE_SIM ||
+		    cred->eap_method[0].method == EAP_TYPE_AKA ||
+		    cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
+			eap_type = cred->eap_method[0].method;
+	}
+
+	switch (eap_type) {
+	case EAP_TYPE_SIM:
+		prefix = '1';
+		res = wpa_config_set(ssid, "eap", "SIM", 0);
+		break;
+	case EAP_TYPE_AKA:
+		prefix = '0';
+		res = wpa_config_set(ssid, "eap", "AKA", 0);
+		break;
+	case EAP_TYPE_AKA_PRIME:
+		prefix = '6';
+		res = wpa_config_set(ssid, "eap", "AKA'", 0);
+		break;
+	default:
+		res = -1;
+		break;
+	}
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
+			   eap_type);
+		goto fail;
+	}
+
+	if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
+		goto fail;
+	}
+
+	if (cred->milenage && cred->milenage[0]) {
+		if (wpa_config_set_quoted(ssid, "password",
+					  cred->milenage) < 0)
+			goto fail;
+	} else if (cred->pcsc) {
+		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
+			goto fail;
+		if (wpa_s->conf->pcsc_pin &&
+		    wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
+		    < 0)
+			goto fail;
+	}
+
+	if (cred->password && cred->password[0] &&
+	    wpa_config_set_quoted(ssid, "password", cred->password) < 0)
+		goto fail;
+
+	wpa_config_update_prio_list(wpa_s->conf);
+	interworking_reconnect(wpa_s);
+
+	return 0;
+
+fail:
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+#endif /* INTERWORKING_3GPP */
+	return -1;
+}
+
+
+static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
+					    size_t rc_len)
+{
+	const u8 *pos, *end;
+	u8 lens;
+
+	if (ie == NULL)
+		return 0;
+
+	pos = ie + 2;
+	end = ie + 2 + ie[1];
+
+	/* Roaming Consortium element:
+	 * Number of ANQP OIs
+	 * OI #1 and #2 lengths
+	 * OI #1, [OI #2], [OI #3]
+	 */
+
+	if (pos + 2 > end)
+		return 0;
+
+	pos++; /* skip Number of ANQP OIs */
+	lens = *pos++;
+	if (pos + (lens & 0x0f) + (lens >> 4) > end)
+		return 0;
+
+	if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+		return 1;
+	pos += lens & 0x0f;
+
+	if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+		return 1;
+	pos += lens >> 4;
+
+	if (pos < end && (size_t) (end - pos) == rc_len &&
+	    os_memcmp(pos, rc_id, rc_len) == 0)
+		return 1;
+
+	return 0;
+}
+
+
+static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
+					 const u8 *rc_id, size_t rc_len)
+{
+	const u8 *pos, *end;
+	u8 len;
+
+	if (anqp == NULL)
+		return 0;
+
+	pos = wpabuf_head(anqp);
+	end = pos + wpabuf_len(anqp);
+
+	/* Set of <OI Length, OI> duples */
+	while (pos < end) {
+		len = *pos++;
+		if (pos + len > end)
+			break;
+		if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+			return 1;
+		pos += len;
+	}
+
+	return 0;
+}
+
+
+static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
+				    const u8 *rc_id, size_t rc_len)
+{
+	return roaming_consortium_element_match(ie, rc_id, rc_len) ||
+		roaming_consortium_anqp_match(anqp, rc_id, rc_len);
+}
+
+
+static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+	size_t i;
+
+	if (!cred->excluded_ssid)
+		return 0;
+
+	for (i = 0; i < cred->num_excluded_ssid; i++) {
+		struct excluded_ssid *e = &cred->excluded_ssid[i];
+		if (bss->ssid_len == e->ssid_len &&
+		    os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static struct wpa_cred * interworking_credentials_available_roaming_consortium(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_cred *cred, *selected = NULL;
+	const u8 *ie;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+	if (ie == NULL &&
+	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+		return NULL;
+
+	if (wpa_s->conf->cred == NULL)
+		return NULL;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->roaming_consortium_len == 0)
+			continue;
+
+		if (!roaming_consortium_match(ie,
+					      bss->anqp ?
+					      bss->anqp->roaming_consortium :
+					      NULL,
+					      cred->roaming_consortium,
+					      cred->roaming_consortium_len))
+			continue;
+
+		if (cred_excluded_ssid(cred, bss))
+			continue;
+
+		if (selected == NULL ||
+		    selected->priority < cred->priority)
+			selected = cred;
+	}
+
+	return selected;
+}
+
+
+static int interworking_set_eap_params(struct wpa_ssid *ssid,
+				       struct wpa_cred *cred, int ttls)
+{
+	if (cred->eap_method) {
+		ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
+			cred->eap_method->method == EAP_TYPE_TTLS;
+
+		os_free(ssid->eap.eap_methods);
+		ssid->eap.eap_methods =
+			os_malloc(sizeof(struct eap_method_type) * 2);
+		if (ssid->eap.eap_methods == NULL)
+			return -1;
+		os_memcpy(ssid->eap.eap_methods, cred->eap_method,
+			  sizeof(*cred->eap_method));
+		ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
+		ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
+	}
+
+	if (ttls && cred->username && cred->username[0]) {
+		const char *pos;
+		char *anon;
+		/* Use anonymous NAI in Phase 1 */
+		pos = os_strchr(cred->username, '@');
+		if (pos) {
+			size_t buflen = 9 + os_strlen(pos) + 1;
+			anon = os_malloc(buflen);
+			if (anon == NULL)
+				return -1;
+			os_snprintf(anon, buflen, "anonymous%s", pos);
+		} else if (cred->realm) {
+			size_t buflen = 10 + os_strlen(cred->realm) + 1;
+			anon = os_malloc(buflen);
+			if (anon == NULL)
+				return -1;
+			os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+		} else {
+			anon = os_strdup("anonymous");
+			if (anon == NULL)
+				return -1;
+		}
+		if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+		    0) {
+			os_free(anon);
+			return -1;
+		}
+		os_free(anon);
+	}
+
+	if (cred->username && cred->username[0] &&
+	    wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
+		return -1;
+
+	if (cred->password && cred->password[0]) {
+		if (cred->ext_password &&
+		    wpa_config_set(ssid, "password", cred->password, 0) < 0)
+			return -1;
+		if (!cred->ext_password &&
+		    wpa_config_set_quoted(ssid, "password", cred->password) <
+		    0)
+			return -1;
+	}
+
+	if (cred->client_cert && cred->client_cert[0] &&
+	    wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
+		return -1;
+
+#ifdef ANDROID
+	if (cred->private_key &&
+	    os_strncmp(cred->private_key, "keystore://", 11) == 0) {
+		/* Use OpenSSL engine configuration for Android keystore */
+		if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
+		    wpa_config_set_quoted(ssid, "key_id",
+					  cred->private_key + 11) < 0 ||
+		    wpa_config_set(ssid, "engine", "1", 0) < 0)
+			return -1;
+	} else
+#endif /* ANDROID */
+	if (cred->private_key && cred->private_key[0] &&
+	    wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+		return -1;
+
+	if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+	    wpa_config_set_quoted(ssid, "private_key_passwd",
+				  cred->private_key_passwd) < 0)
+		return -1;
+
+	if (cred->phase1) {
+		os_free(ssid->eap.phase1);
+		ssid->eap.phase1 = os_strdup(cred->phase1);
+	}
+	if (cred->phase2) {
+		os_free(ssid->eap.phase2);
+		ssid->eap.phase2 = os_strdup(cred->phase2);
+	}
+
+	if (cred->ca_cert && cred->ca_cert[0] &&
+	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int interworking_connect_roaming_consortium(
+	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
+	struct wpa_bss *bss, const u8 *ssid_ie)
+{
+	struct wpa_ssid *ssid;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
+		   "roaming consortium match", MAC2STR(bss->bssid));
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return -1;
+	ssid->parent_cred = cred;
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->priority = cred->priority;
+	ssid->temporary = 1;
+	ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+	if (ssid->ssid == NULL)
+		goto fail;
+	os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
+	ssid->ssid_len = ssid_ie[1];
+
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
+		goto fail;
+
+	if (cred->eap_method == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
+			   "credential using roaming consortium");
+		goto fail;
+	}
+
+	if (interworking_set_eap_params(
+		    ssid, cred,
+		    cred->eap_method->vendor == EAP_VENDOR_IETF &&
+		    cred->eap_method->method == EAP_TYPE_TTLS) < 0)
+		goto fail;
+
+	wpa_config_update_prio_list(wpa_s->conf);
+	interworking_reconnect(wpa_s);
+
+	return 0;
+
+fail:
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+	return -1;
+}
+
+
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_cred *cred;
+	struct wpa_ssid *ssid;
+	struct nai_realm *realm;
+	struct nai_realm_eap *eap = NULL;
+	u16 count, i;
+	char buf[100];
+	const u8 *ie;
+
+	if (wpa_s->conf->cred == NULL || bss == NULL)
+		return -1;
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ie == NULL || ie[1] == 0) {
+		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+			   MACSTR, MAC2STR(bss->bssid));
+		return -1;
+	}
+
+	if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+		/*
+		 * We currently support only HS 2.0 networks and those are
+		 * required to use WPA2-Enterprise.
+		 */
+		wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
+			   "RSN");
+		return -1;
+	}
+
+	cred = interworking_credentials_available_roaming_consortium(wpa_s,
+								     bss);
+	if (cred)
+		return interworking_connect_roaming_consortium(wpa_s, cred,
+							       bss, ie);
+
+	realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
+				&count);
+	if (realm == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
+			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		count = 0;
+	}
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		for (i = 0; i < count; i++) {
+			if (!nai_realm_match(&realm[i], cred->realm))
+				continue;
+			eap = nai_realm_find_eap(cred, &realm[i]);
+			if (eap)
+				break;
+		}
+		if (eap)
+			break;
+	}
+
+	if (!eap) {
+		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
+			if (realm)
+				nai_realm_free(realm, count);
+			return 0;
+		}
+
+		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+			   "and EAP method found for " MACSTR,
+			   MAC2STR(bss->bssid));
+		nai_realm_free(realm, count);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
+		   MAC2STR(bss->bssid));
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		nai_realm_free(realm, count);
+		return -1;
+	}
+	ssid->parent_cred = cred;
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->priority = cred->priority;
+	ssid->temporary = 1;
+	ssid->ssid = os_zalloc(ie[1] + 1);
+	if (ssid->ssid == NULL)
+		goto fail;
+	os_memcpy(ssid->ssid, ie + 2, ie[1]);
+	ssid->ssid_len = ie[1];
+
+	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
+		goto fail;
+
+	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
+						     eap->method), 0) < 0)
+		goto fail;
+
+	switch (eap->method) {
+	case EAP_TYPE_TTLS:
+		if (eap->inner_method) {
+			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
+				    eap_get_name(EAP_VENDOR_IETF,
+						 eap->inner_method));
+			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+				goto fail;
+			break;
+		}
+		switch (eap->inner_non_eap) {
+		case NAI_REALM_INNER_NON_EAP_PAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
+			    0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_CHAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
+			    < 0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_MSCHAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
+					   0) < 0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+					   0) < 0)
+				goto fail;
+			break;
+		default:
+			/* EAP params were not set - assume TTLS/MSCHAPv2 */
+			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+					   0) < 0)
+				goto fail;
+			break;
+		}
+		break;
+	case EAP_TYPE_PEAP:
+		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
+			    eap_get_name(EAP_VENDOR_IETF,
+					 eap->inner_method ?
+					 eap->inner_method :
+					 EAP_TYPE_MSCHAPV2));
+		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+			goto fail;
+		break;
+	case EAP_TYPE_TLS:
+		break;
+	}
+
+	if (interworking_set_eap_params(ssid, cred,
+					eap->method == EAP_TYPE_TTLS) < 0)
+		goto fail;
+
+	nai_realm_free(realm, count);
+
+	wpa_config_update_prio_list(wpa_s->conf);
+	interworking_reconnect(wpa_s);
+
+	return 0;
+
+fail:
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+	nai_realm_free(realm, count);
+	return -1;
+}
+
+
+static struct wpa_cred * interworking_credentials_available_3gpp(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_cred *cred, *selected = NULL;
+	int ret;
+
+#ifdef INTERWORKING_3GPP
+	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+		return NULL;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		char *sep;
+		const char *imsi;
+		int mnc_len;
+
+#ifdef PCSC_FUNCS
+		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
+		    wpa_s->imsi[0]) {
+			imsi = wpa_s->imsi;
+			mnc_len = wpa_s->mnc_len;
+			goto compare;
+		}
+#endif /* PCSC_FUNCS */
+
+		if (cred->imsi == NULL || !cred->imsi[0] ||
+		    cred->milenage == NULL || !cred->milenage[0])
+			continue;
+
+		sep = os_strchr(cred->imsi, '-');
+		if (sep == NULL ||
+		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
+			continue;
+		mnc_len = sep - cred->imsi - 3;
+		imsi = cred->imsi;
+
+#ifdef PCSC_FUNCS
+	compare:
+#endif /* PCSC_FUNCS */
+		wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
+			   MACSTR, MAC2STR(bss->bssid));
+		ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
+		wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+		if (ret) {
+			if (cred_excluded_ssid(cred, bss))
+				continue;
+			if (selected == NULL ||
+			    selected->priority < cred->priority)
+				selected = cred;
+		}
+	}
+#endif /* INTERWORKING_3GPP */
+	return selected;
+}
+
+
+static struct wpa_cred * interworking_credentials_available_realm(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_cred *cred, *selected = NULL;
+	struct nai_realm *realm;
+	u16 count, i;
+
+	if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
+		return NULL;
+
+	if (wpa_s->conf->cred == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+		   MACSTR, MAC2STR(bss->bssid));
+	realm = nai_realm_parse(bss->anqp->nai_realm, &count);
+	if (realm == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
+			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		return NULL;
+	}
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		if (cred->realm == NULL)
+			continue;
+
+		for (i = 0; i < count; i++) {
+			if (!nai_realm_match(&realm[i], cred->realm))
+				continue;
+			if (nai_realm_find_eap(cred, &realm[i])) {
+				if (cred_excluded_ssid(cred, bss))
+					continue;
+				if (selected == NULL ||
+				    selected->priority < cred->priority)
+					selected = cred;
+				break;
+			}
+		}
+	}
+
+	nai_realm_free(realm, count);
+
+	return selected;
+}
+
+
+static struct wpa_cred * interworking_credentials_available(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_cred *cred, *cred2;
+
+	cred = interworking_credentials_available_realm(wpa_s, bss);
+	cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
+	if (cred && cred2 && cred2->priority >= cred->priority)
+		cred = cred2;
+	if (!cred)
+		cred = cred2;
+
+	cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
+								      bss);
+	if (cred && cred2 && cred2->priority >= cred->priority)
+		cred = cred2;
+	if (!cred)
+		cred = cred2;
+
+	return cred;
+}
+
+
+static int domain_name_list_contains(struct wpabuf *domain_names,
+				     const char *domain)
+{
+	const u8 *pos, *end;
+	size_t len;
+
+	len = os_strlen(domain);
+	pos = wpabuf_head(domain_names);
+	end = pos + wpabuf_len(domain_names);
+
+	while (pos + 1 < end) {
+		if (pos + 1 + pos[0] > end)
+			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)
+			return 1;
+
+		pos += 1 + pos[0];
+	}
+
+	return 0;
+}
+
+
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+			      struct wpa_cred *cred,
+			      struct wpabuf *domain_names)
+{
+#ifdef INTERWORKING_3GPP
+	char nai[100], *realm;
+
+	char *imsi = NULL;
+	int mnc_len = 0;
+	if (cred->imsi)
+		imsi = cred->imsi;
+#ifdef CONFIG_PCSC
+	else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+		 wpa_s->scard && wpa_s->imsi[0]) {
+		imsi = wpa_s->imsi;
+		mnc_len = wpa_s->mnc_len;
+	}
+#endif /* CONFIG_PCSC */
+	if (domain_names &&
+	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
+		realm = os_strchr(nai, '@');
+		if (realm)
+			realm++;
+		wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+			   "with SIM/USIM domain %s", realm);
+		if (realm &&
+		    domain_name_list_contains(domain_names, realm))
+			return 1;
+	}
+#endif /* INTERWORKING_3GPP */
+
+	if (domain_names == NULL || cred->domain == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+		   "home SP FQDN %s", cred->domain);
+	if (domain_name_list_contains(domain_names, cred->domain))
+		return 1;
+
+	return 0;
+}
+
+
+static int interworking_home_sp(struct wpa_supplicant *wpa_s,
+				struct wpabuf *domain_names)
+{
+	struct wpa_cred *cred;
+
+	if (domain_names == NULL || wpa_s->conf->cred == NULL)
+		return -1;
+
+	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+		int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+
+static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (wpas_network_disabled(wpa_s, ssid) ||
+			    ssid->mode != WPAS_MODE_INFRA)
+				continue;
+			if (ssid->ssid_len != bss->ssid_len ||
+			    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
+			    0)
+				continue;
+			/*
+			 * TODO: Consider more accurate matching of security
+			 * configuration similarly to what is done in events.c
+			 */
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void interworking_select_network(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
+	int selected_prio = -999999, selected_home_prio = -999999;
+	unsigned int count = 0;
+	const char *type;
+	int res;
+	struct wpa_cred *cred;
+
+	wpa_s->network_select = 0;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		cred = interworking_credentials_available(wpa_s, bss);
+		if (!cred)
+			continue;
+		if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+			/*
+			 * We currently support only HS 2.0 networks and those
+			 * are required to use WPA2-Enterprise.
+			 */
+			wpa_printf(MSG_DEBUG, "Interworking: Credential match "
+				   "with " MACSTR " but network does not use "
+				   "RSN", MAC2STR(bss->bssid));
+			continue;
+		}
+		count++;
+		res = interworking_home_sp(wpa_s, bss->anqp ?
+					   bss->anqp->domain_name : NULL);
+		if (res > 0)
+			type = "home";
+		else if (res == 0)
+			type = "roaming";
+		else
+			type = "unknown";
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
+			MAC2STR(bss->bssid), type);
+		if (wpa_s->auto_select ||
+		    (wpa_s->conf->auto_interworking &&
+		     wpa_s->auto_network_select)) {
+			if (selected == NULL ||
+			    cred->priority > selected_prio) {
+				selected = bss;
+				selected_prio = cred->priority;
+			}
+			if (res > 0 &&
+			    (selected_home == NULL ||
+			     cred->priority > selected_home_prio)) {
+				selected_home = bss;
+				selected_home_prio = cred->priority;
+			}
+		}
+	}
+
+	if (selected_home && selected_home != selected &&
+	    selected_home_prio >= selected_prio) {
+		/* Prefer network operated by the Home SP */
+		selected = selected_home;
+	}
+
+	if (count == 0) {
+		/*
+		 * No matching network was found based on configured
+		 * credentials. Check whether any of the enabled network blocks
+		 * have matching APs.
+		 */
+		if (interworking_find_network_match(wpa_s)) {
+			wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
+				   "match for enabled network configurations");
+			if (wpa_s->auto_select)
+				interworking_reconnect(wpa_s);
+			return;
+		}
+
+		if (wpa_s->auto_network_select) {
+			wpa_printf(MSG_DEBUG, "Interworking: Continue "
+				   "scanning after ANQP fetch");
+			wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
+						0);
+			return;
+		}
+
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
+			"with matching credentials found");
+	}
+
+	if (selected)
+		interworking_connect(wpa_s, selected);
+}
+
+
+static struct wpa_bss_anqp *
+interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_bss *other;
+
+	if (is_zero_ether_addr(bss->hessid))
+		return NULL; /* Cannot be in the same homegenous ESS */
+
+	dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
+		if (other == bss)
+			continue;
+		if (other->anqp == NULL)
+			continue;
+		if (other->anqp->roaming_consortium == NULL &&
+		    other->anqp->nai_realm == NULL &&
+		    other->anqp->anqp_3gpp == NULL &&
+		    other->anqp->domain_name == NULL)
+			continue;
+		if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
+			continue;
+		if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
+			continue;
+		if (bss->ssid_len != other->ssid_len ||
+		    os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
+			   "already fetched BSSID " MACSTR " and " MACSTR,
+			   MAC2STR(other->bssid), MAC2STR(bss->bssid));
+		other->anqp->users++;
+		return other->anqp;
+	}
+
+	return NULL;
+}
+
+
+static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	int found = 0;
+	const u8 *ie;
+
+	if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!(bss->caps & IEEE80211_CAP_ESS))
+			continue;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+			continue; /* AP does not support Interworking */
+
+		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+			if (bss->anqp == NULL) {
+				bss->anqp = interworking_match_anqp_info(wpa_s,
+									 bss);
+				if (bss->anqp) {
+					/* Shared data already fetched */
+					continue;
+				}
+				bss->anqp = wpa_bss_anqp_alloc();
+				if (bss->anqp == NULL)
+					break;
+			}
+			found++;
+			bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
+			wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
+				MACSTR, MAC2STR(bss->bssid));
+			interworking_anqp_send_req(wpa_s, bss);
+			break;
+		}
+	}
+
+	if (found == 0) {
+		wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
+		wpa_s->fetch_anqp_in_progress = 0;
+		if (wpa_s->network_select)
+			interworking_select_network(wpa_s);
+	}
+}
+
+
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
+		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
+
+	wpa_s->fetch_anqp_in_progress = 1;
+	interworking_next_anqp_fetch(wpa_s);
+}
+
+
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
+		return 0;
+
+	wpa_s->network_select = 0;
+	wpa_s->fetch_all_anqp = 1;
+
+	interworking_start_fetch_anqp(wpa_s);
+
+	return 0;
+}
+
+
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->fetch_anqp_in_progress)
+		return;
+
+	wpa_s->fetch_anqp_in_progress = 0;
+}
+
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+		  u16 info_ids[], size_t num_ids)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int freq;
+	struct wpa_bss *bss;
+	int res;
+
+	freq = wpa_s->assoc_freq;
+	bss = wpa_bss_get_bssid(wpa_s, dst);
+	if (bss) {
+		wpa_bss_anqp_unshare_alloc(bss);
+		freq = bss->freq;
+	}
+	if (freq <= 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
+		   MAC2STR(dst), (unsigned int) num_ids);
+
+	buf = anqp_build_req(info_ids, num_ids, NULL);
+	if (buf == NULL)
+		return -1;
+
+	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		ret = -1;
+	} else
+		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *sa, u16 info_id,
+					    const u8 *data, size_t slen)
+{
+	const u8 *pos = data;
+	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+	struct wpa_bss_anqp *anqp = NULL;
+#ifdef CONFIG_HS20
+	u8 type;
+#endif /* CONFIG_HS20 */
+
+	if (bss)
+		anqp = bss->anqp;
+
+	switch (info_id) {
+	case ANQP_CAPABILITY_LIST:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" ANQP Capability list", MAC2STR(sa));
+		break;
+	case ANQP_VENUE_NAME:
+		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) {
+			wpabuf_free(anqp->venue_name);
+			anqp->venue_name = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_NETWORK_AUTH_TYPE:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Network Authentication Type information",
+			MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
+				  "Type", pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->network_auth_type);
+			anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_ROAMING_CONSORTIUM:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Roaming Consortium list", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
+				  pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->roaming_consortium);
+			anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" IP Address Type Availability information",
+			MAC2STR(sa));
+		wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
+			    pos, slen);
+		if (anqp) {
+			wpabuf_free(anqp->ip_addr_type_availability);
+			anqp->ip_addr_type_availability =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_NAI_REALM:
+		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) {
+			wpabuf_free(anqp->nai_realm);
+			anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_3GPP_CELLULAR_NETWORK:
+		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);
+		if (anqp) {
+			wpabuf_free(anqp->anqp_3gpp);
+			anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_DOMAIN_NAME:
+		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) {
+			wpabuf_free(anqp->domain_name);
+			anqp->domain_name = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_VENDOR_SPECIFIC:
+		if (slen < 3)
+			return;
+
+		switch (WPA_GET_BE24(pos)) {
+#ifdef CONFIG_HS20
+		case OUI_WFA:
+			pos += 3;
+			slen -= 3;
+
+			if (slen < 1)
+				return;
+			type = *pos++;
+			slen--;
+
+			switch (type) {
+			case HS20_ANQP_OUI_TYPE:
+				hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
+							     slen);
+				break;
+			default:
+				wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
+					   "vendor type %u", type);
+				break;
+			}
+			break;
+#endif /* CONFIG_HS20 */
+		default:
+			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
+				   "vendor-specific ANQP OUI %06x",
+				   WPA_GET_BE24(pos));
+			return;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
+			   "%u", info_id);
+		break;
+	}
+}
+
+
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+		  enum gas_query_result result,
+		  const struct wpabuf *adv_proto,
+		  const struct wpabuf *resp, u16 status_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos;
+	const u8 *end;
+	u16 info_id;
+	u16 slen;
+
+	if (result != GAS_QUERY_SUCCESS)
+		return;
+
+	pos = wpabuf_head(adv_proto);
+	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
+	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
+			   "Protocol in response");
+		return;
+	}
+
+	pos = wpabuf_head(resp);
+	end = pos + wpabuf_len(resp);
+
+	while (pos < end) {
+		if (pos + 4 > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
+			break;
+		}
+		info_id = WPA_GET_LE16(pos);
+		pos += 2;
+		slen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (pos + slen > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
+				   "for Info ID %u", info_id);
+			break;
+		}
+		interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+						slen);
+		pos += slen;
+	}
+}
+
+
+static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
+					  struct wpa_scan_results *scan_res)
+{
+	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
+		   "ANQP fetch");
+	interworking_start_fetch_anqp(wpa_s);
+}
+
+
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+{
+	interworking_stop_fetch_anqp(wpa_s);
+	wpa_s->network_select = 1;
+	wpa_s->auto_network_select = 0;
+	wpa_s->auto_select = !!auto_select;
+	wpa_s->fetch_all_anqp = 0;
+	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
+		   "selection");
+	wpa_s->scan_res_handler = interworking_scan_res_handler;
+	wpa_s->scan_req = MANUAL_SCAN_REQ;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
+
+
+static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+			enum gas_query_result result,
+			const struct wpabuf *adv_proto,
+			const struct wpabuf *resp, u16 status_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
+		" dialog_token=%d status_code=%d resp_len=%d",
+		MAC2STR(addr), dialog_token, status_code,
+		resp ? (int) wpabuf_len(resp) : -1);
+	if (!resp)
+		return;
+
+	wpabuf_free(wpa_s->last_gas_resp);
+	wpa_s->last_gas_resp = wpabuf_dup(resp);
+	if (wpa_s->last_gas_resp == NULL)
+		return;
+	os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
+	wpa_s->last_gas_dialog_token = dialog_token;
+}
+
+
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+		     const struct wpabuf *adv_proto,
+		     const struct wpabuf *query)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int freq;
+	struct wpa_bss *bss;
+	int res;
+	size_t len;
+	u8 query_resp_len_limit = 0, pame_bi = 0;
+
+	freq = wpa_s->assoc_freq;
+	bss = wpa_bss_get_bssid(wpa_s, dst);
+	if (bss)
+		freq = bss->freq;
+	if (freq <= 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+		   MAC2STR(dst), freq);
+	wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
+	wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
+
+	len = 3 + wpabuf_len(adv_proto) + 2;
+	if (query)
+		len += wpabuf_len(query);
+	buf = gas_build_initial_req(0, len);
+	if (buf == NULL)
+		return -1;
+
+	/* Advertisement Protocol IE */
+	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+	wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
+	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+		      (pame_bi ? 0x80 : 0));
+	wpabuf_put_buf(buf, adv_proto);
+
+	/* GAS Query */
+	if (query) {
+		wpabuf_put_le16(buf, wpabuf_len(query));
+		wpabuf_put_buf(buf, query);
+	} else
+		wpabuf_put_le16(buf, 0);
+
+	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+		ret = -1;
+	} else
+		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}

Copied: vendor/wpa/2.0/wpa_supplicant/interworking.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/interworking.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/interworking.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/interworking.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,32 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef INTERWORKING_H
+#define INTERWORKING_H
+
+enum gas_query_result;
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+		  u16 info_ids[], size_t num_ids);
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+		  enum gas_query_result result,
+		  const struct wpabuf *adv_proto,
+		  const struct wpabuf *resp, u16 status_code);
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+		     const struct wpabuf *adv_proto,
+		     const struct wpabuf *query);
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+			      struct wpa_cred *cred,
+			      struct wpabuf *domain_names);
+
+#endif /* INTERWORKING_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/main.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/main.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/main.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,285 +0,0 @@
-/*
- * WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#ifdef __linux__
-#include <fcntl.h>
-#endif /* __linux__ */
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-
-static void usage(void)
-{
-	int i;
-	printf("%s\n\n%s\n"
-	       "usage:\n"
-	       "  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
-	       "[-g<global ctrl>] \\\n"
-	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
-	       "[-p<driver_param>] \\\n"
-	       "        [-b<br_ifname>] [-f<debug file>] \\\n"
-	       "        [-o<override driver>] [-O<override ctrl>] \\\n"
-	       "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
-	       "[-D<driver>] \\\n"
-	       "        [-p<driver_param>] [-b<br_ifname>] ...]\n"
-	       "\n"
-	       "drivers:\n",
-	       wpa_supplicant_version, wpa_supplicant_license);
-
-	for (i = 0; wpa_drivers[i]; i++) {
-		printf("  %s = %s\n",
-		       wpa_drivers[i]->name,
-		       wpa_drivers[i]->desc);
-	}
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	printf("options:\n"
-	       "  -b = optional bridge interface name\n"
-	       "  -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"
-	       "  -d = increase debugging verbosity (-dd even more)\n"
-	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n");
-#ifdef CONFIG_DEBUG_FILE
-	printf("  -f = log output to debug file instead of stdout\n");
-#endif /* CONFIG_DEBUG_FILE */
-	printf("  -g = global ctrl_interface\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 */
-	printf("  -t = include timestamp in debug messages\n"
-	       "  -h = show this help text\n"
-	       "  -L = show license (GPL and BSD)\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");
-#ifdef CONFIG_DBUS
-	printf("  -u = enable DBus control interface\n");
-#endif /* CONFIG_DBUS */
-	printf("  -v = show version\n"
-	       "  -W = wait for a control interface monitor before starting\n"
-	       "  -N = start describing new interface\n");
-
-	printf("example:\n"
-	       "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
-	       wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static void license(void)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	printf("%s\n\n%s%s%s%s%s\n",
-	       wpa_supplicant_version,
-	       wpa_supplicant_full_license1,
-	       wpa_supplicant_full_license2,
-	       wpa_supplicant_full_license3,
-	       wpa_supplicant_full_license4,
-	       wpa_supplicant_full_license5);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static void wpa_supplicant_fd_workaround(void)
-{
-#ifdef __linux__
-	int s, i;
-	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
-	 * fd 0, 1, and 2 closed. This will cause some issues because many
-	 * places in wpa_supplicant are still printing out to stdout. As a
-	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
-	 * sockets. */
-	for (i = 0; i < 3; i++) {
-		s = open("/dev/null", O_RDWR);
-		if (s > 2) {
-			close(s);
-			break;
-		}
-	}
-#endif /* __linux__ */
-}
-
-
-int main(int argc, char *argv[])
-{
-	int c, i;
-	struct wpa_interface *ifaces, *iface;
-	int iface_count, exitcode = -1;
-	struct wpa_params params;
-	struct wpa_global *global;
-
-	if (os_program_init())
-		return -1;
-
-	os_memset(&params, 0, sizeof(params));
-	params.wpa_debug_level = MSG_INFO;
-
-	iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
-	if (ifaces == NULL)
-		return -1;
-	iface_count = 1;
-
-	wpa_supplicant_fd_workaround();
-
-	for (;;) {
-		c = getopt(argc, argv, "b:Bc:C:D:df:g:hi:KLNo:O:p:P:qstuvW");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'b':
-			iface->bridge_ifname = optarg;
-			break;
-		case 'B':
-			params.daemonize++;
-			break;
-		case 'c':
-			iface->confname = optarg;
-			break;
-		case 'C':
-			iface->ctrl_interface = optarg;
-			break;
-		case 'D':
-			iface->driver = optarg;
-			break;
-		case 'd':
-#ifdef CONFIG_NO_STDOUT_DEBUG
-			printf("Debugging disabled with "
-			       "CONFIG_NO_STDOUT_DEBUG=y build time "
-			       "option.\n");
-			goto out;
-#else /* CONFIG_NO_STDOUT_DEBUG */
-			params.wpa_debug_level--;
-			break;
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-#ifdef CONFIG_DEBUG_FILE
-		case 'f':
-			params.wpa_debug_file_path = optarg;
-			break;
-#endif /* CONFIG_DEBUG_FILE */
-		case 'g':
-			params.ctrl_interface = optarg;
-			break;
-		case 'h':
-			usage();
-			exitcode = 0;
-			goto out;
-		case 'i':
-			iface->ifname = optarg;
-			break;
-		case 'K':
-			params.wpa_debug_show_keys++;
-			break;
-		case 'L':
-			license();
-			exitcode = 0;
-			goto out;
-		case 'o':
-			params.override_driver = optarg;
-			break;
-		case 'O':
-			params.override_ctrl_interface = optarg;
-			break;
-		case 'p':
-			iface->driver_param = optarg;
-			break;
-		case 'P':
-			os_free(params.pid_file);
-			params.pid_file = os_rel2abs_path(optarg);
-			break;
-		case 'q':
-			params.wpa_debug_level++;
-			break;
-#ifdef CONFIG_DEBUG_SYSLOG
-		case 's':
-			params.wpa_debug_syslog++;
-			break;
-#endif /* CONFIG_DEBUG_SYSLOG */
-		case 't':
-			params.wpa_debug_timestamp++;
-			break;
-#ifdef CONFIG_DBUS
-		case 'u':
-			params.dbus_ctrl_interface = 1;
-			break;
-#endif /* CONFIG_DBUS */
-		case 'v':
-			printf("%s\n", wpa_supplicant_version);
-			exitcode = 0;
-			goto out;
-		case 'W':
-			params.wait_for_monitor++;
-			break;
-		case 'N':
-			iface_count++;
-			iface = os_realloc(ifaces, iface_count *
-					   sizeof(struct wpa_interface));
-			if (iface == NULL)
-				goto out;
-			ifaces = iface;
-			iface = &ifaces[iface_count - 1]; 
-			os_memset(iface, 0, sizeof(*iface));
-			break;
-		default:
-			usage();
-			exitcode = 0;
-			goto out;
-		}
-	}
-
-	exitcode = 0;
-	global = wpa_supplicant_init(&params);
-	if (global == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
-		exitcode = -1;
-		goto out;
-	}
-
-	for (i = 0; exitcode == 0 && i < iface_count; i++) {
-		if ((ifaces[i].confname == NULL &&
-		     ifaces[i].ctrl_interface == NULL) ||
-		    ifaces[i].ifname == NULL) {
-			if (iface_count == 1 && (params.ctrl_interface ||
-						 params.dbus_ctrl_interface))
-				break;
-			usage();
-			exitcode = -1;
-			break;
-		}
-		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
-			exitcode = -1;
-	}
-
-	if (exitcode == 0)
-		exitcode = wpa_supplicant_run(global);
-
-	wpa_supplicant_deinit(global);
-
-out:
-	os_free(ifaces);
-	os_free(params.pid_file);
-
-	os_program_deinit();
-
-	return exitcode;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/main.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/main.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/main.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/main.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,309 @@
+/*
+ * WPA Supplicant / main() function for UNIX like OSes and MinGW
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+static void usage(void)
+{
+	int i;
+	printf("%s\n\n%s\n"
+	       "usage:\n"
+	       "  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+	       "[-g<global ctrl>] \\\n"
+	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
+	       "[-p<driver_param>] \\\n"
+	       "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
+	       "\\\n"
+	       "        [-o<override driver>] [-O<override ctrl>] \\\n"
+	       "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
+	       "[-D<driver>] \\\n"
+	       "        [-p<driver_param>] [-b<br_ifname>] ...]\n"
+	       "\n"
+	       "drivers:\n",
+	       wpa_supplicant_version, wpa_supplicant_license);
+
+	for (i = 0; wpa_drivers[i]; i++) {
+		printf("  %s = %s\n",
+		       wpa_drivers[i]->name,
+		       wpa_drivers[i]->desc);
+	}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	printf("options:\n"
+	       "  -b = optional bridge interface name\n"
+	       "  -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"
+	       "  -d = increase debugging verbosity (-dd even more)\n"
+	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
+	       "  -e = entropy file\n");
+#ifdef CONFIG_DEBUG_FILE
+	printf("  -f = log output to debug file instead of stdout\n");
+#endif /* CONFIG_DEBUG_FILE */
+	printf("  -g = global ctrl_interface\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"
+	       "  -L = show license (BSD)\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");
+#ifdef CONFIG_DBUS
+	printf("  -u = enable DBus control interface\n");
+#endif /* CONFIG_DBUS */
+	printf("  -v = show version\n"
+	       "  -W = wait for a control interface monitor before starting\n"
+	       "  -N = start describing new interface\n");
+
+	printf("example:\n"
+	       "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
+	       wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void license(void)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	printf("%s\n\n%s%s%s%s%s\n",
+	       wpa_supplicant_version,
+	       wpa_supplicant_full_license1,
+	       wpa_supplicant_full_license2,
+	       wpa_supplicant_full_license3,
+	       wpa_supplicant_full_license4,
+	       wpa_supplicant_full_license5);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void wpa_supplicant_fd_workaround(int start)
+{
+#ifdef __linux__
+	static int fd[3] = { -1, -1, -1 };
+	int i;
+	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
+	 * fd 0, 1, and 2 closed. This will cause some issues because many
+	 * places in wpa_supplicant are still printing out to stdout. As a
+	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
+	 * sockets. */
+	if (start) {
+		for (i = 0; i < 3; i++) {
+			fd[i] = open("/dev/null", O_RDWR);
+			if (fd[i] > 2) {
+				close(fd[i]);
+				fd[i] = -1;
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < 3; i++) {
+			if (fd[i] >= 0) {
+				close(fd[i]);
+				fd[i] = -1;
+			}
+		}
+	}
+#endif /* __linux__ */
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c, i;
+	struct wpa_interface *ifaces, *iface;
+	int iface_count, exitcode = -1;
+	struct wpa_params params;
+	struct wpa_global *global;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.wpa_debug_level = MSG_INFO;
+
+	iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
+	if (ifaces == NULL)
+		return -1;
+	iface_count = 1;
+
+	wpa_supplicant_fd_workaround(1);
+
+	for (;;) {
+		c = getopt(argc, argv,
+			   "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			iface->bridge_ifname = optarg;
+			break;
+		case 'B':
+			params.daemonize++;
+			break;
+		case 'c':
+			iface->confname = optarg;
+			break;
+		case 'C':
+			iface->ctrl_interface = optarg;
+			break;
+		case 'D':
+			iface->driver = optarg;
+			break;
+		case 'd':
+#ifdef CONFIG_NO_STDOUT_DEBUG
+			printf("Debugging disabled with "
+			       "CONFIG_NO_STDOUT_DEBUG=y build time "
+			       "option.\n");
+			goto out;
+#else /* CONFIG_NO_STDOUT_DEBUG */
+			params.wpa_debug_level--;
+			break;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		case 'e':
+			params.entropy_file = optarg;
+			break;
+#ifdef CONFIG_DEBUG_FILE
+		case 'f':
+			params.wpa_debug_file_path = optarg;
+			break;
+#endif /* CONFIG_DEBUG_FILE */
+		case 'g':
+			params.ctrl_interface = optarg;
+			break;
+		case 'h':
+			usage();
+			exitcode = 0;
+			goto out;
+		case 'i':
+			iface->ifname = optarg;
+			break;
+		case 'K':
+			params.wpa_debug_show_keys++;
+			break;
+		case 'L':
+			license();
+			exitcode = 0;
+			goto out;
+		case 'o':
+			params.override_driver = optarg;
+			break;
+		case 'O':
+			params.override_ctrl_interface = optarg;
+			break;
+		case 'p':
+			iface->driver_param = optarg;
+			break;
+		case 'P':
+			os_free(params.pid_file);
+			params.pid_file = os_rel2abs_path(optarg);
+			break;
+		case 'q':
+			params.wpa_debug_level++;
+			break;
+#ifdef CONFIG_DEBUG_SYSLOG
+		case 's':
+			params.wpa_debug_syslog++;
+			break;
+#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		case 'T':
+			params.wpa_debug_tracing++;
+			break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+		case 't':
+			params.wpa_debug_timestamp++;
+			break;
+#ifdef CONFIG_DBUS
+		case 'u':
+			params.dbus_ctrl_interface = 1;
+			break;
+#endif /* CONFIG_DBUS */
+		case 'v':
+			printf("%s\n", wpa_supplicant_version);
+			exitcode = 0;
+			goto out;
+		case 'W':
+			params.wait_for_monitor++;
+			break;
+		case 'N':
+			iface_count++;
+			iface = os_realloc_array(ifaces, iface_count,
+						 sizeof(struct wpa_interface));
+			if (iface == NULL)
+				goto out;
+			ifaces = iface;
+			iface = &ifaces[iface_count - 1]; 
+			os_memset(iface, 0, sizeof(*iface));
+			break;
+		default:
+			usage();
+			exitcode = 0;
+			goto out;
+		}
+	}
+
+	exitcode = 0;
+	global = wpa_supplicant_init(&params);
+	if (global == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
+		exitcode = -1;
+		goto out;
+	} else {
+		wpa_printf(MSG_INFO, "Successfully initialized "
+			   "wpa_supplicant");
+	}
+
+	for (i = 0; exitcode == 0 && i < iface_count; i++) {
+		if ((ifaces[i].confname == NULL &&
+		     ifaces[i].ctrl_interface == NULL) ||
+		    ifaces[i].ifname == NULL) {
+			if (iface_count == 1 && (params.ctrl_interface ||
+						 params.dbus_ctrl_interface))
+				break;
+			usage();
+			exitcode = -1;
+			break;
+		}
+		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+			exitcode = -1;
+	}
+
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_run(global);
+
+	wpa_supplicant_deinit(global);
+
+out:
+	wpa_supplicant_fd_workaround(0);
+	os_free(ifaces);
+	os_free(params.pid_file);
+
+	os_program_deinit();
+
+	return exitcode;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/main_none.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/main_none.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/main_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,46 +0,0 @@
-/*
- * WPA Supplicant / Example program entrypoint
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-
-int main(int argc, char *argv[])
-{
-	struct wpa_interface iface;
-	int exitcode = 0;
-	struct wpa_params params;
-	struct wpa_global *global;
-
-	memset(&params, 0, sizeof(params));
-	params.wpa_debug_level = MSG_INFO;
-
-	global = wpa_supplicant_init(&params);
-	if (global == NULL)
-		return -1;
-
-	memset(&iface, 0, sizeof(iface));
-	/* TODO: set interface parameters */
-
-	if (wpa_supplicant_add_iface(global, &iface) == NULL)
-		exitcode = -1;
-
-	if (exitcode == 0)
-		exitcode = wpa_supplicant_run(global);
-
-	wpa_supplicant_deinit(global);
-
-	return exitcode;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/main_none.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/main_none.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/main_none.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/main_none.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,40 @@
+/*
+ * WPA Supplicant / Example program entrypoint
+ * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+
+int main(int argc, char *argv[])
+{
+	struct wpa_interface iface;
+	int exitcode = 0;
+	struct wpa_params params;
+	struct wpa_global *global;
+
+	memset(&params, 0, sizeof(params));
+	params.wpa_debug_level = MSG_INFO;
+
+	global = wpa_supplicant_init(&params);
+	if (global == NULL)
+		return -1;
+
+	memset(&iface, 0, sizeof(iface));
+	/* TODO: set interface parameters */
+
+	if (wpa_supplicant_add_iface(global, &iface) == NULL)
+		exitcode = -1;
+
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_run(global);
+
+	wpa_supplicant_deinit(global);
+
+	return exitcode;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/main_symbian.cpp
===================================================================
--- vendor/wpa/dist/wpa_supplicant/main_symbian.cpp	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/main_symbian.cpp	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,48 +0,0 @@
-/*
- * WPA Supplicant / Program entrypoint for Symbian
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-extern "C" {
-#include "common.h"
-#include "wpa_supplicant_i.h"
-}
-
-GLDEF_C TInt E32Main(void)
-{
-	struct wpa_interface iface;
-	int exitcode = 0;
-	struct wpa_params params;
-	struct wpa_global *global;
-
-	memset(&params, 0, sizeof(params));
-	params.wpa_debug_level = MSG_INFO;
-
-	global = wpa_supplicant_init(&params);
-	if (global == NULL)
-		return -1;
-
-	memset(&iface, 0, sizeof(iface));
-	/* TODO: set interface parameters */
-
-	if (wpa_supplicant_add_iface(global, &iface) == NULL)
-		exitcode = -1;
-
-	if (exitcode == 0)
-		exitcode = wpa_supplicant_run(global);
-
-	wpa_supplicant_deinit(global);
-
-	return exitcode;
-}

Deleted: vendor/wpa/2.0/wpa_supplicant/main_winmain.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/main_winmain.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/main_winmain.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,84 +0,0 @@
-/*
- * WPA Supplicant / WinMain() function for Windows-based applications
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-
-#ifdef _WIN32_WCE
-#define CMDLINE LPWSTR
-#else /* _WIN32_WCE */
-#define CMDLINE LPSTR
-#endif /* _WIN32_WCE */
-
-
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
-		   CMDLINE lpCmdLine, int nShowCmd)
-{
-	int i;
-	struct wpa_interface *ifaces, *iface;
-	int iface_count, exitcode = -1;
-	struct wpa_params params;
-	struct wpa_global *global;
-
-	if (os_program_init())
-		return -1;
-
-	os_memset(&params, 0, sizeof(params));
-	params.wpa_debug_level = MSG_MSGDUMP;
-	params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
-	params.wpa_debug_show_keys = 1;
-
-	iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
-	if (ifaces == NULL)
-		return -1;
-	iface_count = 1;
-
-	iface->confname = "default";
-	iface->driver = "ndis";
-	iface->ifname = "";
-
-	exitcode = 0;
-	global = wpa_supplicant_init(&params);
-	if (global == NULL) {
-		printf("Failed to initialize wpa_supplicant\n");
-		exitcode = -1;
-	}
-
-	for (i = 0; exitcode == 0 && i < iface_count; i++) {
-		if ((ifaces[i].confname == NULL &&
-		     ifaces[i].ctrl_interface == NULL) ||
-		    ifaces[i].ifname == NULL) {
-			if (iface_count == 1 && (params.ctrl_interface ||
-						 params.dbus_ctrl_interface))
-				break;
-			exitcode = -1;
-			break;
-		}
-		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
-			exitcode = -1;
-	}
-
-	if (exitcode == 0)
-		exitcode = wpa_supplicant_run(global);
-
-	wpa_supplicant_deinit(global);
-
-	os_free(ifaces);
-
-	os_program_deinit();
-
-	return exitcode;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/main_winmain.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/main_winmain.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/main_winmain.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/main_winmain.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,78 @@
+/*
+ * WPA Supplicant / WinMain() function for Windows-based applications
+ * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+
+#ifdef _WIN32_WCE
+#define CMDLINE LPWSTR
+#else /* _WIN32_WCE */
+#define CMDLINE LPSTR
+#endif /* _WIN32_WCE */
+
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+		   CMDLINE lpCmdLine, int nShowCmd)
+{
+	int i;
+	struct wpa_interface *ifaces, *iface;
+	int iface_count, exitcode = -1;
+	struct wpa_params params;
+	struct wpa_global *global;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.wpa_debug_level = MSG_MSGDUMP;
+	params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+	params.wpa_debug_show_keys = 1;
+
+	iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
+	if (ifaces == NULL)
+		return -1;
+	iface_count = 1;
+
+	iface->confname = "default";
+	iface->driver = "ndis";
+	iface->ifname = "";
+
+	exitcode = 0;
+	global = wpa_supplicant_init(&params);
+	if (global == NULL) {
+		printf("Failed to initialize wpa_supplicant\n");
+		exitcode = -1;
+	}
+
+	for (i = 0; exitcode == 0 && i < iface_count; i++) {
+		if ((ifaces[i].confname == NULL &&
+		     ifaces[i].ctrl_interface == NULL) ||
+		    ifaces[i].ifname == NULL) {
+			if (iface_count == 1 && (params.ctrl_interface ||
+						 params.dbus_ctrl_interface))
+				break;
+			exitcode = -1;
+			break;
+		}
+		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+			exitcode = -1;
+	}
+
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_run(global);
+
+	wpa_supplicant_deinit(global);
+
+	os_free(ifaces);
+
+	os_program_deinit();
+
+	return exitcode;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/main_winsvc.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/main_winsvc.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/main_winsvc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,464 +0,0 @@
-/*
- * WPA Supplicant / main() function for Win32 service
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * The root of wpa_supplicant configuration in registry is
- * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
- * parameters and a 'interfaces' subkey with all the interface configuration
- * (adapter to confname mapping). Each such mapping is a subkey that has
- * 'adapter' and 'config' values.
- *
- * This program can be run either as a normal command line application, e.g.,
- * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need
- * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After
- * this, it can be started like any other Windows service (e.g., 'net start
- * wpasvc') or it can be configured to start automatically through the Services
- * tool in administrative tasks. The service can be unregistered with
- * 'wpasvc.exe unreg'.
- */
-
-#include "includes.h"
-#include <windows.h>
-
-#include "common.h"
-#include "wpa_supplicant_i.h"
-#include "eloop.h"
-
-#ifndef WPASVC_NAME
-#define WPASVC_NAME TEXT("wpasvc")
-#endif
-#ifndef WPASVC_DISPLAY_NAME
-#define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service")
-#endif
-#ifndef WPASVC_DESCRIPTION
-#define WPASVC_DESCRIPTION \
-TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality")
-#endif
-
-static HANDLE kill_svc;
-
-static SERVICE_STATUS_HANDLE svc_status_handle;
-static SERVICE_STATUS svc_status;
-
-
-#ifndef WPA_KEY_ROOT
-#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
-#endif
-#ifndef WPA_KEY_PREFIX
-#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
-#endif
-
-#ifdef UNICODE
-#define TSTR "%S"
-#else /* UNICODE */
-#define TSTR "%s"
-#endif /* UNICODE */
-
-
-static int read_interface(struct wpa_global *global, HKEY _hk,
-			  const TCHAR *name)
-{
-	HKEY hk;
-#define TBUFLEN 255
-	TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
-	DWORD buflen, val;
-	LONG ret;
-	struct wpa_interface iface;
-	int skip_on_error = 0;
-
-	ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
-	if (ret != ERROR_SUCCESS) {
-		printf("Could not open wpa_supplicant interface key\n");
-		return -1;
-	}
-
-	os_memset(&iface, 0, sizeof(iface));
-	iface.driver = "ndis";
-
-	buflen = sizeof(ctrl_interface);
-	ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
-			      (LPBYTE) ctrl_interface, &buflen);
-	if (ret == ERROR_SUCCESS) {
-		ctrl_interface[TBUFLEN - 1] = TEXT('\0');
-		wpa_unicode2ascii_inplace(ctrl_interface);
-		printf("ctrl_interface[len=%d] '%s'\n",
-		       (int) buflen, (char *) ctrl_interface);
-		iface.ctrl_interface = (char *) ctrl_interface;
-	}
-
-	buflen = sizeof(adapter);
-	ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
-			      (LPBYTE) adapter, &buflen);
-	if (ret == ERROR_SUCCESS) {
-		adapter[TBUFLEN - 1] = TEXT('\0');
-		wpa_unicode2ascii_inplace(adapter);
-		printf("adapter[len=%d] '%s'\n",
-		       (int) buflen, (char *) adapter);
-		iface.ifname = (char *) adapter;
-	}
-
-	buflen = sizeof(config);
-	ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
-			      (LPBYTE) config, &buflen);
-	if (ret == ERROR_SUCCESS) {
-		config[sizeof(config) - 1] = '\0';
-		wpa_unicode2ascii_inplace(config);
-		printf("config[len=%d] '%s'\n",
-		       (int) buflen, (char *) config);
-		iface.confname = (char *) config;
-	}
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
-			      (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val))
-		skip_on_error = val;
-
-	RegCloseKey(hk);
-
-	if (wpa_supplicant_add_iface(global, &iface) == NULL) {
-		if (skip_on_error)
-			wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
-				   "initialization failure", iface.ifname);
-		else
-			return -1;
-	}
-
-	return 0;
-}
-
-
-static int wpa_supplicant_thread(void)
-{
-	int exitcode;
-	struct wpa_params params;
-	struct wpa_global *global;
-	HKEY hk, ihk;
-	DWORD val, buflen, i;
-	LONG ret;
-
-	if (os_program_init())
-		return -1;
-
-	os_memset(&params, 0, sizeof(params));
-	params.wpa_debug_level = MSG_INFO;
-
-	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
-			   0, KEY_QUERY_VALUE, &hk);
-	if (ret != ERROR_SUCCESS) {
-		printf("Could not open wpa_supplicant registry key\n");
-		return -1;
-	}
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
-			      (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
-		params.wpa_debug_level = val;
-	}
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
-			      (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
-		params.wpa_debug_show_keys = val;
-	}
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
-			      (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
-		params.wpa_debug_timestamp = val;
-	}
-
-	buflen = sizeof(val);
-	ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
-			      (LPBYTE) &val, &buflen);
-	if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
-		params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
-	}
-
-	exitcode = 0;
-	global = wpa_supplicant_init(&params);
-	if (global == NULL) {
-		printf("Failed to initialize wpa_supplicant\n");
-		exitcode = -1;
-	}
-
-	ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
-			   &ihk);
-	RegCloseKey(hk);
-	if (ret != ERROR_SUCCESS) {
-		printf("Could not open wpa_supplicant interfaces registry "
-		       "key\n");
-		return -1;
-	}
-
-	for (i = 0; ; i++) {
-		TCHAR name[255];
-		DWORD namelen;
-
-		namelen = 255;
-		ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
-				   NULL);
-
-		if (ret == ERROR_NO_MORE_ITEMS)
-			break;
-
-		if (ret != ERROR_SUCCESS) {
-			printf("RegEnumKeyEx failed: 0x%x\n",
-			       (unsigned int) ret);
-			break;
-		}
-
-		if (namelen >= 255)
-			namelen = 255 - 1;
-		name[namelen] = '\0';
-
-		wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
-		if (read_interface(global, ihk, name) < 0)
-			exitcode = -1;
-	}
-
-	RegCloseKey(ihk);
-
-	if (exitcode == 0)
-		exitcode = wpa_supplicant_run(global);
-
-	wpa_supplicant_deinit(global);
-
-	os_program_deinit();
-
-	return exitcode;
-}
-
-
-static DWORD svc_thread(LPDWORD param)
-{
-	int ret = wpa_supplicant_thread();
-
-	svc_status.dwCurrentState = SERVICE_STOPPED;
-	svc_status.dwWaitHint = 0;
-	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
-		printf("SetServiceStatus() failed: %d\n",
-		       (int) GetLastError());
-	}
-
-	return ret;
-}
-
-
-static int register_service(const TCHAR *exe)
-{
-	SC_HANDLE svc, scm;
-	SERVICE_DESCRIPTION sd;
-
-	printf("Registering service: " TSTR "\n", WPASVC_NAME);
-
-	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
-	if (!scm) {
-		printf("OpenSCManager failed: %d\n", (int) GetLastError());
-		return -1;
-	}
-
-	svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
-			    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
-			    SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
-			    exe, NULL, NULL, NULL, NULL, NULL);
-
-	if (!svc) {
-		printf("CreateService failed: %d\n\n", (int) GetLastError());
-		CloseServiceHandle(scm);
-		return -1;
-	}
-
-	os_memset(&sd, 0, sizeof(sd));
-	sd.lpDescription = WPASVC_DESCRIPTION;
-	if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
-		printf("ChangeServiceConfig2 failed: %d\n",
-		       (int) GetLastError());
-		/* This is not a fatal error, so continue anyway. */
-	}
-
-	CloseServiceHandle(svc);
-	CloseServiceHandle(scm);
-
-	printf("Service registered successfully.\n");
-
-	return 0;
-}
-
-
-static int unregister_service(void)
-{
-	SC_HANDLE svc, scm;
-	SERVICE_STATUS status;
-
-	printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
-
-	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
-	if (!scm) {
-		printf("OpenSCManager failed: %d\n", (int) GetLastError());
-		return -1;
-	}
-
-	svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
-	if (!svc) {
-		printf("OpenService failed: %d\n\n", (int) GetLastError());
-		CloseServiceHandle(scm);
-		return -1;
-	}
-
-	if (QueryServiceStatus(svc, &status)) {
-		if (status.dwCurrentState != SERVICE_STOPPED) {
-			printf("Service currently active - stopping "
-			       "service...\n");
-			if (!ControlService(svc, SERVICE_CONTROL_STOP,
-					    &status)) {
-				printf("ControlService failed: %d\n",
-				       (int) GetLastError());
-			}
-			Sleep(500);
-		}
-	}
-
-	if (DeleteService(svc)) {
-		printf("Service unregistered successfully.\n");
-	} else {
-		printf("DeleteService failed: %d\n", (int) GetLastError());
-	}
-
-	CloseServiceHandle(svc);
-	CloseServiceHandle(scm);
-
-	return 0;
-}
-
-
-static void WINAPI service_ctrl_handler(DWORD control_code)
-{
-	switch (control_code) {
-	case SERVICE_CONTROL_INTERROGATE:
-		break;
-	case SERVICE_CONTROL_SHUTDOWN:
-	case SERVICE_CONTROL_STOP:
-		svc_status.dwCurrentState = SERVICE_STOP_PENDING;
-		svc_status.dwWaitHint = 2000;
-		eloop_terminate();
-		SetEvent(kill_svc);
-		break;
-	}
-
-	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
-		printf("SetServiceStatus() failed: %d\n",
-		       (int) GetLastError());
-	}
-}
-
-
-static void WINAPI service_start(DWORD argc, LPTSTR *argv)
-{
-	DWORD id;
-
-	svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
-						       service_ctrl_handler);
-	if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
-		printf("RegisterServiceCtrlHandler failed: %d\n",
-		       (int) GetLastError());
-		return;
-	}
-
-	os_memset(&svc_status, 0, sizeof(svc_status));
-	svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
-	svc_status.dwCurrentState = SERVICE_START_PENDING;
-	svc_status.dwWaitHint = 1000;
-
-	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
-		printf("SetServiceStatus() failed: %d\n",
-		       (int) GetLastError());
-		return;
-	}
-
-	kill_svc = CreateEvent(0, TRUE, FALSE, 0);
-	if (!kill_svc) {
-		printf("CreateEvent failed: %d\n", (int) GetLastError());
-		return;
-	}
-
-	if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
-	    == 0) {
-		printf("CreateThread failed: %d\n", (int) GetLastError());
-		return;
-	}
-
-	if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
-		svc_status.dwCurrentState = SERVICE_RUNNING;
-		svc_status.dwWaitHint = 0;
-		svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
-			SERVICE_ACCEPT_SHUTDOWN;
-	}
-
-	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
-		printf("SetServiceStatus() failed: %d\n",
-		       (int) GetLastError());
-		return;
-	}
-
-	/* wait until service gets killed */
-	WaitForSingleObject(kill_svc, INFINITE);
-}
-
-
-int main(int argc, char *argv[])
-{
-	SERVICE_TABLE_ENTRY dt[] = {
-		{ WPASVC_NAME, service_start },
-		{ NULL, NULL }
-	};
-
-	if (argc > 1) {
-		if (os_strcmp(argv[1], "reg") == 0) {
-			TCHAR *path;
-			int ret;
-
-			if (argc < 3) {
-				path = os_malloc(MAX_PATH * sizeof(TCHAR));
-				if (path == NULL)
-					return -1;
-				if (!GetModuleFileName(NULL, path, MAX_PATH)) {
-					printf("GetModuleFileName failed: "
-					       "%d\n", (int) GetLastError());
-					os_free(path);
-					return -1;
-				}
-			} else {
-				path = wpa_strdup_tchar(argv[2]);
-				if (path == NULL)
-					return -1;
-			}
-			ret = register_service(path);
-			os_free(path);
-			return ret;
-		} else if (os_strcmp(argv[1], "unreg") == 0) {
-			return unregister_service();
-		} else if (os_strcmp(argv[1], "app") == 0) {
-			return wpa_supplicant_thread();
-		}
-	}
-
-	if (!StartServiceCtrlDispatcher(dt)) {
-		printf("StartServiceCtrlDispatcher failed: %d\n",
-		       (int) GetLastError());
-	}
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/main_winsvc.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/main_winsvc.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/main_winsvc.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/main_winsvc.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,458 @@
+/*
+ * WPA Supplicant / main() function for Win32 service
+ * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * The root of wpa_supplicant configuration in registry is
+ * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
+ * parameters and a 'interfaces' subkey with all the interface configuration
+ * (adapter to confname mapping). Each such mapping is a subkey that has
+ * 'adapter' and 'config' values.
+ *
+ * This program can be run either as a normal command line application, e.g.,
+ * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need
+ * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After
+ * this, it can be started like any other Windows service (e.g., 'net start
+ * wpasvc') or it can be configured to start automatically through the Services
+ * tool in administrative tasks. The service can be unregistered with
+ * 'wpasvc.exe unreg'.
+ */
+
+#include "includes.h"
+#include <windows.h>
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "eloop.h"
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+#ifndef WPASVC_DISPLAY_NAME
+#define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service")
+#endif
+#ifndef WPASVC_DESCRIPTION
+#define WPASVC_DESCRIPTION \
+TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality")
+#endif
+
+static HANDLE kill_svc;
+
+static SERVICE_STATUS_HANDLE svc_status_handle;
+static SERVICE_STATUS svc_status;
+
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int read_interface(struct wpa_global *global, HKEY _hk,
+			  const TCHAR *name)
+{
+	HKEY hk;
+#define TBUFLEN 255
+	TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
+	DWORD buflen, val;
+	LONG ret;
+	struct wpa_interface iface;
+	int skip_on_error = 0;
+
+	ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
+	if (ret != ERROR_SUCCESS) {
+		printf("Could not open wpa_supplicant interface key\n");
+		return -1;
+	}
+
+	os_memset(&iface, 0, sizeof(iface));
+	iface.driver = "ndis";
+
+	buflen = sizeof(ctrl_interface);
+	ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
+			      (LPBYTE) ctrl_interface, &buflen);
+	if (ret == ERROR_SUCCESS) {
+		ctrl_interface[TBUFLEN - 1] = TEXT('\0');
+		wpa_unicode2ascii_inplace(ctrl_interface);
+		printf("ctrl_interface[len=%d] '%s'\n",
+		       (int) buflen, (char *) ctrl_interface);
+		iface.ctrl_interface = (char *) ctrl_interface;
+	}
+
+	buflen = sizeof(adapter);
+	ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
+			      (LPBYTE) adapter, &buflen);
+	if (ret == ERROR_SUCCESS) {
+		adapter[TBUFLEN - 1] = TEXT('\0');
+		wpa_unicode2ascii_inplace(adapter);
+		printf("adapter[len=%d] '%s'\n",
+		       (int) buflen, (char *) adapter);
+		iface.ifname = (char *) adapter;
+	}
+
+	buflen = sizeof(config);
+	ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
+			      (LPBYTE) config, &buflen);
+	if (ret == ERROR_SUCCESS) {
+		config[sizeof(config) - 1] = '\0';
+		wpa_unicode2ascii_inplace(config);
+		printf("config[len=%d] '%s'\n",
+		       (int) buflen, (char *) config);
+		iface.confname = (char *) config;
+	}
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val))
+		skip_on_error = val;
+
+	RegCloseKey(hk);
+
+	if (wpa_supplicant_add_iface(global, &iface) == NULL) {
+		if (skip_on_error)
+			wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
+				   "initialization failure", iface.ifname);
+		else
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_thread(void)
+{
+	int exitcode;
+	struct wpa_params params;
+	struct wpa_global *global;
+	HKEY hk, ihk;
+	DWORD val, buflen, i;
+	LONG ret;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.wpa_debug_level = MSG_INFO;
+
+	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
+			   0, KEY_QUERY_VALUE, &hk);
+	if (ret != ERROR_SUCCESS) {
+		printf("Could not open wpa_supplicant registry key\n");
+		return -1;
+	}
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+		params.wpa_debug_level = val;
+	}
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+		params.wpa_debug_show_keys = val;
+	}
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+		params.wpa_debug_timestamp = val;
+	}
+
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
+		params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+	}
+
+	exitcode = 0;
+	global = wpa_supplicant_init(&params);
+	if (global == NULL) {
+		printf("Failed to initialize wpa_supplicant\n");
+		exitcode = -1;
+	}
+
+	ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
+			   &ihk);
+	RegCloseKey(hk);
+	if (ret != ERROR_SUCCESS) {
+		printf("Could not open wpa_supplicant interfaces registry "
+		       "key\n");
+		return -1;
+	}
+
+	for (i = 0; ; i++) {
+		TCHAR name[255];
+		DWORD namelen;
+
+		namelen = 255;
+		ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
+				   NULL);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS) {
+			printf("RegEnumKeyEx failed: 0x%x\n",
+			       (unsigned int) ret);
+			break;
+		}
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = '\0';
+
+		wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
+		if (read_interface(global, ihk, name) < 0)
+			exitcode = -1;
+	}
+
+	RegCloseKey(ihk);
+
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_run(global);
+
+	wpa_supplicant_deinit(global);
+
+	os_program_deinit();
+
+	return exitcode;
+}
+
+
+static DWORD svc_thread(LPDWORD param)
+{
+	int ret = wpa_supplicant_thread();
+
+	svc_status.dwCurrentState = SERVICE_STOPPED;
+	svc_status.dwWaitHint = 0;
+	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+		printf("SetServiceStatus() failed: %d\n",
+		       (int) GetLastError());
+	}
+
+	return ret;
+}
+
+
+static int register_service(const TCHAR *exe)
+{
+	SC_HANDLE svc, scm;
+	SERVICE_DESCRIPTION sd;
+
+	printf("Registering service: " TSTR "\n", WPASVC_NAME);
+
+	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+	if (!scm) {
+		printf("OpenSCManager failed: %d\n", (int) GetLastError());
+		return -1;
+	}
+
+	svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
+			    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+			    SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
+			    exe, NULL, NULL, NULL, NULL, NULL);
+
+	if (!svc) {
+		printf("CreateService failed: %d\n\n", (int) GetLastError());
+		CloseServiceHandle(scm);
+		return -1;
+	}
+
+	os_memset(&sd, 0, sizeof(sd));
+	sd.lpDescription = WPASVC_DESCRIPTION;
+	if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
+		printf("ChangeServiceConfig2 failed: %d\n",
+		       (int) GetLastError());
+		/* This is not a fatal error, so continue anyway. */
+	}
+
+	CloseServiceHandle(svc);
+	CloseServiceHandle(scm);
+
+	printf("Service registered successfully.\n");
+
+	return 0;
+}
+
+
+static int unregister_service(void)
+{
+	SC_HANDLE svc, scm;
+	SERVICE_STATUS status;
+
+	printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
+
+	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+	if (!scm) {
+		printf("OpenSCManager failed: %d\n", (int) GetLastError());
+		return -1;
+	}
+
+	svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
+	if (!svc) {
+		printf("OpenService failed: %d\n\n", (int) GetLastError());
+		CloseServiceHandle(scm);
+		return -1;
+	}
+
+	if (QueryServiceStatus(svc, &status)) {
+		if (status.dwCurrentState != SERVICE_STOPPED) {
+			printf("Service currently active - stopping "
+			       "service...\n");
+			if (!ControlService(svc, SERVICE_CONTROL_STOP,
+					    &status)) {
+				printf("ControlService failed: %d\n",
+				       (int) GetLastError());
+			}
+			Sleep(500);
+		}
+	}
+
+	if (DeleteService(svc)) {
+		printf("Service unregistered successfully.\n");
+	} else {
+		printf("DeleteService failed: %d\n", (int) GetLastError());
+	}
+
+	CloseServiceHandle(svc);
+	CloseServiceHandle(scm);
+
+	return 0;
+}
+
+
+static void WINAPI service_ctrl_handler(DWORD control_code)
+{
+	switch (control_code) {
+	case SERVICE_CONTROL_INTERROGATE:
+		break;
+	case SERVICE_CONTROL_SHUTDOWN:
+	case SERVICE_CONTROL_STOP:
+		svc_status.dwCurrentState = SERVICE_STOP_PENDING;
+		svc_status.dwWaitHint = 2000;
+		eloop_terminate();
+		SetEvent(kill_svc);
+		break;
+	}
+
+	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+		printf("SetServiceStatus() failed: %d\n",
+		       (int) GetLastError());
+	}
+}
+
+
+static void WINAPI service_start(DWORD argc, LPTSTR *argv)
+{
+	DWORD id;
+
+	svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
+						       service_ctrl_handler);
+	if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
+		printf("RegisterServiceCtrlHandler failed: %d\n",
+		       (int) GetLastError());
+		return;
+	}
+
+	os_memset(&svc_status, 0, sizeof(svc_status));
+	svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+	svc_status.dwCurrentState = SERVICE_START_PENDING;
+	svc_status.dwWaitHint = 1000;
+
+	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+		printf("SetServiceStatus() failed: %d\n",
+		       (int) GetLastError());
+		return;
+	}
+
+	kill_svc = CreateEvent(0, TRUE, FALSE, 0);
+	if (!kill_svc) {
+		printf("CreateEvent failed: %d\n", (int) GetLastError());
+		return;
+	}
+
+	if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
+	    == 0) {
+		printf("CreateThread failed: %d\n", (int) GetLastError());
+		return;
+	}
+
+	if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
+		svc_status.dwCurrentState = SERVICE_RUNNING;
+		svc_status.dwWaitHint = 0;
+		svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+			SERVICE_ACCEPT_SHUTDOWN;
+	}
+
+	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+		printf("SetServiceStatus() failed: %d\n",
+		       (int) GetLastError());
+		return;
+	}
+
+	/* wait until service gets killed */
+	WaitForSingleObject(kill_svc, INFINITE);
+}
+
+
+int main(int argc, char *argv[])
+{
+	SERVICE_TABLE_ENTRY dt[] = {
+		{ WPASVC_NAME, service_start },
+		{ NULL, NULL }
+	};
+
+	if (argc > 1) {
+		if (os_strcmp(argv[1], "reg") == 0) {
+			TCHAR *path;
+			int ret;
+
+			if (argc < 3) {
+				path = os_malloc(MAX_PATH * sizeof(TCHAR));
+				if (path == NULL)
+					return -1;
+				if (!GetModuleFileName(NULL, path, MAX_PATH)) {
+					printf("GetModuleFileName failed: "
+					       "%d\n", (int) GetLastError());
+					os_free(path);
+					return -1;
+				}
+			} else {
+				path = wpa_strdup_tchar(argv[2]);
+				if (path == NULL)
+					return -1;
+			}
+			ret = register_service(path);
+			os_free(path);
+			return ret;
+		} else if (os_strcmp(argv[1], "unreg") == 0) {
+			return unregister_service();
+		} else if (os_strcmp(argv[1], "app") == 0) {
+			return wpa_supplicant_thread();
+		}
+	}
+
+	if (!StartServiceCtrlDispatcher(dt)) {
+		printf("StartServiceCtrlDispatcher failed: %d\n",
+		       (int) GetLastError());
+	}
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/mlme.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/mlme.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/mlme.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,3198 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "config_ssid.h"
-#include "wpa_supplicant_i.h"
-#include "notify.h"
-#include "driver_i.h"
-#include "rsn_supp/wpa.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "mlme.h"
-
-
-/* Timeouts and intervals in milliseconds */
-#define IEEE80211_AUTH_TIMEOUT (200)
-#define IEEE80211_AUTH_MAX_TRIES 3
-#define IEEE80211_ASSOC_TIMEOUT (200)
-#define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2000)
-#define IEEE80211_PROBE_INTERVAL (60000)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1000)
-#define IEEE80211_SCAN_INTERVAL (2000)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15000)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20000)
-
-#define IEEE80211_PROBE_DELAY (33)
-#define IEEE80211_CHANNEL_TIME (33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (200)
-#define IEEE80211_SCAN_RESULT_EXPIRE (10000)
-#define IEEE80211_IBSS_MERGE_INTERVAL (30000)
-#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000)
-
-#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-
-
-#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
-
-
-struct ieee80211_sta_bss {
-	struct ieee80211_sta_bss *next;
-	struct ieee80211_sta_bss *hnext;
-
-	u8 bssid[ETH_ALEN];
-	u8 ssid[MAX_SSID_LEN];
-	size_t ssid_len;
-	u16 capability; /* host byte order */
-	int hw_mode;
-	int channel;
-	int freq;
-	int rssi;
-	u8 *ie;
-	size_t ie_len;
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
-	u8 *rsn_ie;
-	size_t rsn_ie_len;
-	u8 *wmm_ie;
-	size_t wmm_ie_len;
-	u8 *mdie;
-	size_t mdie_len;
-#define IEEE80211_MAX_SUPP_RATES 32
-	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
-	size_t supp_rates_len;
-	int beacon_int;
-	u64 timestamp;
-
-	int probe_resp;
-	struct os_time last_update;
-};
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-				     const u8 *dst,
-				     const u8 *ssid, size_t ssid_len);
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid);
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_build_tspec(struct wpabuf *buf);
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-					  const u8 *ies, size_t ies_len);
-
-
-static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
-				     enum hostapd_hw_mode phymode, int chan,
-				     int freq)
-{
-	size_t i;
-	struct hostapd_hw_modes *mode;
-
-	for (i = 0; i < wpa_s->mlme.num_modes; i++) {
-		mode = &wpa_s->mlme.modes[i];
-		if (mode->mode == phymode) {
-			wpa_s->mlme.curr_rates = mode->rates;
-			wpa_s->mlme.num_curr_rates = mode->num_rates;
-			break;
-		}
-	}
-
-	return wpa_drv_set_channel(wpa_s, phymode, chan, freq);
-}
-
-
-static int ecw2cw(int ecw)
-{
-	int cw = 1;
-	while (ecw > 0) {
-		cw <<= 1;
-		ecw--;
-	}
-	return cw - 1;
-}
-
-
-static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
-				     const u8 *wmm_param, size_t wmm_param_len)
-{
-	size_t left;
-	int count;
-	const u8 *pos;
-	u8 wmm_acm;
-
-	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
-		return;
-	count = wmm_param[6] & 0x0f;
-	if (count == wpa_s->mlme.wmm_last_param_set)
-		return;
-	wpa_s->mlme.wmm_last_param_set = count;
-
-	pos = wmm_param + 8;
-	left = wmm_param_len - 8;
-
-	wmm_acm = 0;
-	for (; left >= 4; left -= 4, pos += 4) {
-		int aci = (pos[0] >> 5) & 0x03;
-		int acm = (pos[0] >> 4) & 0x01;
-		int aifs, cw_max, cw_min, burst_time;
-
-		switch (aci) {
-		case 1: /* AC_BK */
-			if (acm)
-				wmm_acm |= BIT(1) | BIT(2); /* BK/- */
-			break;
-		case 2: /* AC_VI */
-			if (acm)
-				wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
-			break;
-		case 3: /* AC_VO */
-			if (acm)
-				wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
-			break;
-		case 0: /* AC_BE */
-		default:
-			if (acm)
-				wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
-			break;
-		}
-
-		aifs = pos[0] & 0x0f;
-		cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
-		cw_min = ecw2cw(pos[1] & 0x0f);
-		/* TXOP is in units of 32 usec; burst_time in 0.1 ms */
-		burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
-		wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d "
-			   "cWmin=%d cWmax=%d burst=%d",
-			   aci, acm, aifs, cw_min, cw_max, burst_time);
-		/* TODO: driver configuration */
-	}
-}
-
-
-static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
-{
-	if (wpa_s->mlme.associated == assoc && !assoc)
-		return;
-
-	wpa_s->mlme.associated = assoc;
-
-	if (assoc) {
-		union wpa_event_data data;
-		os_memset(&data, 0, sizeof(data));
-		wpa_s->mlme.prev_bssid_set = 1;
-		os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-		data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies;
-		data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len;
-		data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies;
-		data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len;
-		data.assoc_info.freq = wpa_s->mlme.freq;
-		wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
-	} else {
-		wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-	}
-	os_get_time(&wpa_s->mlme.last_probe);
-}
-
-
-static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf,
-			    size_t len)
-{
-	return wpa_drv_send_mlme(wpa_s, buf, len);
-}
-
-
-static void ieee80211_send_auth(struct wpa_supplicant *wpa_s,
-				int transaction, const u8 *extra,
-				size_t extra_len, int encrypt)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_malloc(sizeof(*mgmt) + 6 + extra_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "auth frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24 + 6;
-	os_memset(mgmt, 0, 24 + 6);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg);
-	mgmt->u.auth.auth_transaction = host_to_le16(transaction);
-	wpa_s->mlme.auth_transaction = transaction + 1;
-	mgmt->u.auth.status_code = host_to_le16(0);
-	if (extra) {
-		os_memcpy(buf + len, extra, extra_len);
-		len += extra_len;
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms)
-{
-	eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-	eloop_register_timeout(ms / 1000, 1000 * (ms % 1000),
-			       ieee80211_sta_timer, wpa_s, NULL);
-}
-
-
-static void ieee80211_authenticate(struct wpa_supplicant *wpa_s)
-{
-	u8 *extra;
-	size_t extra_len;
-
-	wpa_s->mlme.auth_tries++;
-	if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR
-			   " timed out", MAC2STR(wpa_s->bssid));
-		return;
-	}
-
-	wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-	wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR,
-		   MAC2STR(wpa_s->bssid));
-
-	extra = NULL;
-	extra_len = 0;
-
-#ifdef CONFIG_IEEE80211R
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.ft_ies) {
-		struct ieee80211_sta_bss *bss;
-		struct rsn_mdie *mdie = NULL;
-		bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-		if (bss && bss->mdie_len >= 2 + sizeof(*mdie))
-			mdie = (struct rsn_mdie *) (bss->mdie + 2);
-		if (mdie &&
-		    os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md,
-			      MOBILITY_DOMAIN_ID_LEN) == 0) {
-			wpa_printf(MSG_DEBUG, "MLME: Trying to use FT "
-				   "over-the-air");
-			wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-			extra = wpa_s->mlme.ft_ies;
-			extra_len = wpa_s->mlme.ft_ies_len;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0);
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT);
-}
-
-
-static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *ies, *buf;
-	int i, len;
-	u16 capab;
-	struct ieee80211_sta_bss *bss;
-	int wmm = 0;
-	size_t blen, buflen;
-
-	if (wpa_s->mlme.curr_rates == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc");
-		return;
-	}
-
-	buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len +
-		wpa_s->mlme.ssid_len;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_s->mlme.ft_ies)
-		buflen += wpa_s->mlme.ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-	buf = os_malloc(buflen);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "assoc frame");
-		return;
-	}
-	blen = 0;
-
-	capab = wpa_s->mlme.capab;
-	if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) {
-		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-			WLAN_CAPABILITY_SHORT_PREAMBLE;
-	}
-	bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-	if (bss) {
-		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-			capab |= WLAN_CAPABILITY_PRIVACY;
-		if (bss->wmm_ie) {
-			wmm = 1;
-		}
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	blen += 24;
-	os_memset(mgmt, 0, 24);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-
-	if (wpa_s->mlme.prev_bssid_set) {
-		blen += 10;
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_REASSOC_REQ);
-		mgmt->u.reassoc_req.capab_info = host_to_le16(capab);
-		mgmt->u.reassoc_req.listen_interval = host_to_le16(1);
-		os_memcpy(mgmt->u.reassoc_req.current_ap,
-			  wpa_s->mlme.prev_bssid,
-			  ETH_ALEN);
-	} else {
-		blen += 4;
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_ASSOC_REQ);
-		mgmt->u.assoc_req.capab_info = host_to_le16(capab);
-		mgmt->u.assoc_req.listen_interval = host_to_le16(1);
-	}
-
-	/* SSID */
-	ies = pos = buf + blen;
-	blen += 2 + wpa_s->mlme.ssid_len;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = wpa_s->mlme.ssid_len;
-	os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-	len = wpa_s->mlme.num_curr_rates;
-	if (len > 8)
-		len = 8;
-	pos = buf + blen;
-	blen += len + 2;
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = len;
-	for (i = 0; i < len; i++)
-		*pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-
-	if (wpa_s->mlme.num_curr_rates > len) {
-		pos = buf + blen;
-		blen += wpa_s->mlme.num_curr_rates - len + 2;
-		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = wpa_s->mlme.num_curr_rates - len;
-		for (i = len; i < wpa_s->mlme.num_curr_rates; i++)
-			*pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-	}
-
-	if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) {
-		pos = buf + blen;
-		blen += wpa_s->mlme.extra_ie_len;
-		os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len);
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-	    bss && bss->mdie &&
-	    bss->mdie_len >= 2 + sizeof(struct rsn_mdie) &&
-	    bss->mdie[1] >= sizeof(struct rsn_mdie)) {
-		pos = buf + blen;
-		blen += 2 + sizeof(struct rsn_mdie);
-		*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-		*pos++ = sizeof(struct rsn_mdie);
-		os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN);
-		pos += MOBILITY_DOMAIN_ID_LEN;
-		*pos++ = 0; /* FIX: copy from the target AP's MDIE */
-	}
-
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) {
-		pos = buf + blen;
-		os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len);
-		pos += wpa_s->mlme.ft_ies_len;
-		blen += wpa_s->mlme.ft_ies_len;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (wmm && wpa_s->mlme.wmm_enabled) {
-		pos = buf + blen;
-		blen += 9;
-		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-		*pos++ = 7; /* len */
-		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
-		*pos++ = 0x50;
-		*pos++ = 0xf2;
-		*pos++ = 2; /* WMM */
-		*pos++ = 0; /* WMM info */
-		*pos++ = 1; /* WMM ver */
-		*pos++ = 0;
-	}
-
-	os_free(wpa_s->mlme.assocreq_ies);
-	wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies;
-	wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len);
-	if (wpa_s->mlme.assocreq_ies) {
-		os_memcpy(wpa_s->mlme.assocreq_ies, ies,
-			  wpa_s->mlme.assocreq_ies_len);
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, blen);
-	os_free(buf);
-}
-
-
-static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_zalloc(sizeof(*mgmt));
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "deauth frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_DEAUTH);
-	len += 2;
-	mgmt->u.deauth.reason_code = host_to_le16(reason);
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_zalloc(sizeof(*mgmt));
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "disassoc frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_DISASSOC);
-	len += 2;
-	mgmt->u.disassoc.reason_code = host_to_le16(reason);
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	int res = 0;
-
-	if (wpa_s->mlme.mixed_cell ||
-	    wpa_s->mlme.key_mgmt != KEY_MGMT_NONE)
-		return 0;
-
-	bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-	if (bss == NULL)
-		return 0;
-
-	if (ieee80211_sta_wep_configured(wpa_s) !=
-	    !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
-		res = 1;
-
-	return res;
-}
-
-
-static void ieee80211_associate(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.assoc_tries++;
-	if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-		wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR
-			   " timed out", MAC2STR(wpa_s->bssid));
-		return;
-	}
-
-	wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-	wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR,
-		   MAC2STR(wpa_s->bssid));
-	if (ieee80211_privacy_mismatch(wpa_s)) {
-		wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy "
-			   "configuration and mixed-cell disabled - abort "
-			   "association");
-		return;
-	}
-
-	ieee80211_send_assoc(wpa_s);
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT);
-}
-
-
-static void ieee80211_associated(struct wpa_supplicant *wpa_s)
-{
-	int disassoc;
-
-	/* TODO: start monitoring current AP signal quality and number of
-	 * missed beacons. Scan other channels every now and then and search
-	 * for better APs. */
-	/* TODO: remove expired BSSes */
-
-	wpa_s->mlme.state = IEEE80211_ASSOCIATED;
-
-#if 0 /* FIX */
-	sta = sta_info_get(local, wpa_s->bssid);
-	if (sta == NULL) {
-		wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR,
-			   MAC2STR(wpa_s->bssid));
-		disassoc = 1;
-	} else {
-		disassoc = 0;
-		if (time_after(jiffies,
-			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
-			if (wpa_s->mlme.probereq_poll) {
-				wpa_printf(MSG_DEBUG "MLME: No ProbeResp from "
-					   "current AP " MACSTR " - assume "
-					   "out of range",
-					   MAC2STR(wpa_s->bssid));
-				disassoc = 1;
-			} else {
-				ieee80211_send_probe_req(
-					wpa_s->bssid,
-					wpa_s->mlme.scan_ssid,
-					wpa_s->mlme.scan_ssid_len);
-				wpa_s->mlme.probereq_poll = 1;
-			}
-		} else {
-			wpa_s->mlme.probereq_poll = 0;
-			if (time_after(jiffies, wpa_s->mlme.last_probe +
-				       IEEE80211_PROBE_INTERVAL)) {
-				wpa_s->mlme.last_probe = jiffies;
-				ieee80211_send_probe_req(wpa_s->bssid,
-							 wpa_s->mlme.ssid,
-							 wpa_s->mlme.ssid_len);
-			}
-		}
-		sta_info_release(local, sta);
-	}
-#else
-	disassoc = 0;
-#endif
-	if (disassoc) {
-		wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_MONITORING_INTERVAL +
-					   30000);
-	} else {
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_MONITORING_INTERVAL);
-	}
-}
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-				     const u8 *dst,
-				     const u8 *ssid, size_t ssid_len)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *supp_rates;
-	u8 *esupp_rates = NULL;
-	int i;
-
-	buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "probe request");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memset(mgmt, 0, 24);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_PROBE_REQ);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	if (dst) {
-		os_memcpy(mgmt->da, dst, ETH_ALEN);
-		os_memcpy(mgmt->bssid, dst, ETH_ALEN);
-	} else {
-		os_memset(mgmt->da, 0xff, ETH_ALEN);
-		os_memset(mgmt->bssid, 0xff, ETH_ALEN);
-	}
-	pos = buf + len;
-	len += 2 + ssid_len;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-
-	supp_rates = buf + len;
-	len += 2;
-	supp_rates[0] = WLAN_EID_SUPP_RATES;
-	supp_rates[1] = 0;
-	for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
-		if (esupp_rates) {
-			pos = buf + len;
-			len++;
-			esupp_rates[1]++;
-		} else if (supp_rates[1] == 8) {
-			esupp_rates = pos;
-			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-			esupp_rates[1] = 1;
-			pos = &esupp_rates[2];
-			len += 3;
-		} else {
-			pos = buf + len;
-			len++;
-			supp_rates[1]++;
-		}
-		*pos++ = wpa_s->mlme.curr_rates[i] / 5;
-	}
-
-	if (wpa_s->mlme.extra_probe_ie) {
-		os_memcpy(pos, wpa_s->mlme.extra_probe_ie,
-			  wpa_s->mlme.extra_probe_ie_len);
-		len += wpa_s->mlme.extra_probe_ie_len;
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	if (sdata == NULL || sdata->default_key == NULL ||
-	    sdata->default_key->alg != ALG_WEP)
-		return 0;
-	return 1;
-#else
-	return 0;
-#endif
-}
-
-
-static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s)
-{
-	wpa_printf(MSG_DEBUG, "MLME: authenticated");
-	wpa_s->mlme.authenticated = 1;
-	ieee80211_associate(wpa_s);
-}
-
-
-static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	u8 *pos;
-	struct ieee802_11_elems elems;
-
-	wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge");
-	pos = mgmt->u.auth.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-	    == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)");
-		return;
-	}
-	if (elems.challenge == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key "
-			   "auth frame");
-		return;
-	}
-	ieee80211_send_auth(wpa_s, 3, elems.challenge - 2,
-			    elems.challenge_len + 2, 1);
-}
-
-
-static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
-				   struct ieee80211_mgmt *mgmt,
-				   size_t len,
-				   struct ieee80211_rx_status *rx_status)
-{
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	u16 auth_alg, auth_transaction, status_code;
-	int adhoc;
-
-	adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-	if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from " MACSTR ", but not in authenticate state - "
-			   "ignored", MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (len < 24 + 6) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		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);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR
-		   " (alg=%d transaction=%d status=%d)",
-		   MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code);
-
-	if (adhoc) {
-		/* IEEE 802.11 standard does not require authentication in IBSS
-		 * networks and most implementations do not seem to use it.
-		 * However, try to reply to authentication attempts if someone
-		 * has actually implemented this.
-		 * TODO: Could implement shared key authentication. */
-		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
-			wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS "
-				   "authentication frame (alg=%d "
-				   "transaction=%d)",
-				   auth_alg, auth_transaction);
-			return;
-		}
-		ieee80211_send_auth(wpa_s, 2, NULL, 0, 0);
-	}
-
-	if (auth_alg != wpa_s->mlme.auth_alg ||
-	    auth_transaction != wpa_s->mlme.auth_transaction) {
-		wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame "
-			   "(alg=%d transaction=%d)",
-			   auth_alg, auth_transaction);
-		return;
-	}
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "MLME: AP denied authentication "
-			   "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg,
-			   status_code);
-		if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
-			const int num_algs = 3;
-			u8 algs[num_algs];
-			int i, pos;
-			algs[0] = algs[1] = algs[2] = 0xff;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-				algs[0] = WLAN_AUTH_OPEN;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-				algs[1] = WLAN_AUTH_SHARED_KEY;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-				algs[2] = WLAN_AUTH_LEAP;
-			if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN)
-				pos = 0;
-			else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY)
-				pos = 1;
-			else
-				pos = 2;
-			for (i = 0; i < num_algs; i++) {
-				pos++;
-				if (pos >= num_algs)
-					pos = 0;
-				if (algs[pos] == wpa_s->mlme.auth_alg ||
-				    algs[pos] == 0xff)
-					continue;
-				if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
-				    !ieee80211_sta_wep_configured(wpa_s))
-					continue;
-				wpa_s->mlme.auth_alg = algs[pos];
-				wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d "
-					   "for next try",
-					   wpa_s->mlme.auth_alg);
-				break;
-			}
-		}
-		return;
-	}
-
-	switch (wpa_s->mlme.auth_alg) {
-	case WLAN_AUTH_OPEN:
-	case WLAN_AUTH_LEAP:
-		ieee80211_auth_completed(wpa_s);
-		break;
-	case WLAN_AUTH_SHARED_KEY:
-		if (wpa_s->mlme.auth_transaction == 4)
-			ieee80211_auth_completed(wpa_s);
-		else
-			ieee80211_auth_challenge(wpa_s, mgmt, len,
-						 rx_status);
-		break;
-#ifdef CONFIG_IEEE80211R
-	case WLAN_AUTH_FT:
-	{
-		union wpa_event_data data;
-		struct wpabuf *ric = NULL;
-		os_memset(&data, 0, sizeof(data));
-		data.ft_ies.ies = mgmt->u.auth.variable;
-		data.ft_ies.ies_len = len -
-			(mgmt->u.auth.variable - (u8 *) mgmt);
-		os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
-		if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
-		    wpa_s->mlme.wmm_enabled) {
-			ric = wpabuf_alloc(200);
-			if (ric) {
-				/* Build simple RIC-Request: RDIE | TSPEC */
-
-				/* RIC Data (RDIE) */
-				wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
-				wpabuf_put_u8(ric, 4);
-				wpabuf_put_u8(ric, 0); /* RDIE Identifier */
-				wpabuf_put_u8(ric, 1); /* Resource Descriptor
-							* Count */
-				wpabuf_put_le16(ric, 0); /* Status Code */
-
-				/* WMM TSPEC */
-				ieee80211_build_tspec(ric);
-
-				data.ft_ies.ric_ies = wpabuf_head(ric);
-				data.ft_ies.ric_ies_len = wpabuf_len(ric);
-			}
-		}
-
-		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-		wpabuf_free(ric);
-		ieee80211_auth_completed(wpa_s);
-		break;
-	}
-#endif /* CONFIG_IEEE80211R */
-	}
-}
-
-
-static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	u16 reason_code;
-
-	if (len < 24 + 2) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR
-		   " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-	if (wpa_s->mlme.authenticated)
-		wpa_printf(MSG_DEBUG, "MLME: deauthenticated");
-
-	if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE ||
-	    wpa_s->mlme.state == IEEE80211_ASSOCIATE ||
-	    wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-		wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_RETRY_AUTH_INTERVAL);
-	}
-
-	ieee80211_set_associated(wpa_s, 0);
-	wpa_s->mlme.authenticated = 0;
-}
-
-
-static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
-				       struct ieee80211_mgmt *mgmt,
-				       size_t len,
-				       struct ieee80211_rx_status *rx_status)
-{
-	u16 reason_code;
-
-	if (len < 24 + 2) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: disassociation frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	reason_code = le_to_host16(mgmt->u.disassoc.reason_code);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR
-		   " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-	if (wpa_s->mlme.associated)
-		wpa_printf(MSG_DEBUG, "MLME: disassociated");
-
-	if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-		wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_RETRY_AUTH_INTERVAL);
-	}
-
-	ieee80211_set_associated(wpa_s, 0);
-}
-
-
-static void ieee80211_build_tspec(struct wpabuf *buf)
-{
-	struct wmm_tspec_element *tspec;
-	int tid, up;
-
-	tspec = wpabuf_put(buf, sizeof(*tspec));
-	tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
-	tspec->length = sizeof(*tspec) - 2;
-	tspec->oui[0] = 0x00;
-	tspec->oui[1] = 0x50;
-	tspec->oui[2] = 0xf2;
-	tspec->oui_type = 2;
-	tspec->oui_subtype = 2;
-	tspec->version = 1;
-
-	tid = 1;
-	up = 6; /* Voice */
-	tspec->ts_info[0] = (tid << 1) |
-		(WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) |
-		BIT(7);
-	tspec->ts_info[1] = up << 3;
-	tspec->nominal_msdu_size = host_to_le16(1530);
-	tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
-	tspec->minimum_phy_rate = host_to_le32(6000000);
-	tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
-}
-
-
-static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
-{
-	struct wpabuf *buf;
-	struct ieee80211_mgmt *mgmt;
-	size_t alen;
-
-	wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
-	mgmt = NULL;
-	alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-
-	buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
-	if (buf == NULL)
-		return;
-
-	mgmt = wpabuf_put(buf, alen);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_WMM;
-	mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
-	mgmt->u.action.u.wmm_action.dialog_token = 1;
-	mgmt->u.action.u.wmm_action.status_code = 0;
-
-	ieee80211_build_tspec(buf);
-
-	ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
-	wpabuf_free(buf);
-}
-
-
-static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
-					 struct ieee80211_rx_status *rx_status,
-					 int reassoc)
-{
-	u8 rates[32];
-	size_t rates_len;
-	u16 capab_info, status_code, aid;
-	struct ieee802_11_elems elems;
-	u8 *pos;
-
-	/* AssocResp and ReassocResp have identical structure, so process both
-	 * of them in this function. */
-
-	if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) {
-		wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-			   MACSTR ", but not in associate state - ignored",
-			   MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (len < 24 + 6) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-			   "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - "
-			   "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info);
-	status_code = le_to_host16(mgmt->u.assoc_resp.status_code);
-	aid = le_to_host16(mgmt->u.assoc_resp.aid);
-	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-		wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 "
-			   "not set", aid);
-	aid &= ~(BIT(15) | BIT(14));
-
-	wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR
-		   " (capab=0x%x status=%d aid=%d)",
-		   reassoc ? "Rea" : "A", MAC2STR(mgmt->sa),
-		   capab_info, status_code, aid);
-
-	pos = mgmt->u.assoc_resp.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-	    == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp");
-		return;
-	}
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)",
-			   status_code);
-#ifdef CONFIG_IEEE80211W
-		if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-		    elems.timeout_int && elems.timeout_int_len == 5 &&
-		    elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
-			u32 tu, ms;
-			tu = WPA_GET_LE32(elems.timeout_int + 1);
-			ms = tu * 1024 / 1000;
-			wpa_printf(MSG_DEBUG, "MLME: AP rejected association "
-				   "temporarily; comeback duration %u TU "
-				   "(%u ms)", tu, ms);
-			if (ms > IEEE80211_ASSOC_TIMEOUT) {
-				wpa_printf(MSG_DEBUG, "MLME: Update timer "
-					   "based on comeback duration");
-				ieee80211_reschedule_timer(wpa_s, ms);
-			}
-		}
-#endif /* CONFIG_IEEE80211W */
-		return;
-	}
-
-	if (elems.supp_rates == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in "
-			   "AssocResp");
-		return;
-	}
-
-	if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) {
-		if (!reassoc) {
-			wpa_printf(MSG_DEBUG, "MLME: AP tried to use "
-				   "association, not reassociation, response "
-				   "with FT");
-			return;
-		}
-		if (wpa_ft_validate_reassoc_resp(
-			    wpa_s->wpa, pos, len - (pos - (u8 *) mgmt),
-			    mgmt->sa) < 0) {
-			wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc"
-				   "Resp failed");
-			return;
-		}
-	} else if (wpa_sm_set_ft_params(wpa_s->wpa, pos,
-					len - (pos - (u8 *) mgmt)) < 0)
-		return;
-
-	wpa_printf(MSG_DEBUG, "MLME: associated");
-	wpa_s->mlme.aid = aid;
-	wpa_s->mlme.ap_capab = capab_info;
-
-	os_free(wpa_s->mlme.assocresp_ies);
-	wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt);
-	wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len);
-	if (wpa_s->mlme.assocresp_ies) {
-		os_memcpy(wpa_s->mlme.assocresp_ies, pos,
-			  wpa_s->mlme.assocresp_ies_len);
-	}
-
-	ieee80211_set_associated(wpa_s, 1);
-
-	rates_len = elems.supp_rates_len;
-	if (rates_len > sizeof(rates))
-		rates_len = sizeof(rates);
-	os_memcpy(rates, elems.supp_rates, rates_len);
-	if (elems.ext_supp_rates) {
-		size_t _len = elems.ext_supp_rates_len;
-		if (_len > sizeof(rates) - rates_len)
-			_len = sizeof(rates) - rates_len;
-		os_memcpy(rates + rates_len, elems.ext_supp_rates, _len);
-		rates_len += _len;
-	}
-
-	if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the "
-			   "netstack");
-	}
-	if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) <
-	    0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the "
-			   "netstack");
-	}
-
-	/* Remove STA entry before adding a new one just in case to avoid
-	 * problems with existing configuration (e.g., keys). */
-	wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid);
-	if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the "
-			   "netstack");
-	}
-
-	if (elems.wmm && wpa_s->mlme.wmm_enabled)
-		ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
-
-	ieee80211_associated(wpa_s);
-
-	if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-	    os_strcmp(wpa_s->driver->name, "test") == 0 &&
-	    elems.wmm && wpa_s->mlme.wmm_enabled) {
-		/* Test WMM-AC - send ADDTS for WMM TSPEC */
-		ieee80211_tx_addts(wpa_s);
-	}
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_sta_bss *bss)
-{
-	bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-	wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss;
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_sta_bss *bss)
-{
-	struct ieee80211_sta_bss *b, *prev = NULL;
-	b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-	while (b) {
-		if (b == bss) {
-			if (prev == NULL) {
-				wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]
-					= bss->hnext;
-			} else {
-				prev->hnext = bss->hnext;
-			}
-			break;
-		}
-		prev = b;
-		b = b->hnext;
-	}
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct ieee80211_sta_bss *bss;
-
-	bss = os_zalloc(sizeof(*bss));
-	if (bss == NULL)
-		return NULL;
-	os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
-	/* TODO: order by RSSI? */
-	bss->next = wpa_s->mlme.sta_bss_list;
-	wpa_s->mlme.sta_bss_list = bss;
-	__ieee80211_bss_hash_add(wpa_s, bss);
-	return bss;
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct ieee80211_sta_bss *bss;
-
-	bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)];
-	while (bss) {
-		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		bss = bss->hnext;
-	}
-	return bss;
-}
-
-
-static void ieee80211_bss_free(struct wpa_supplicant *wpa_s,
-			       struct ieee80211_sta_bss *bss)
-{
-	__ieee80211_bss_hash_del(wpa_s, bss);
-	os_free(bss->ie);
-	os_free(bss->wpa_ie);
-	os_free(bss->rsn_ie);
-	os_free(bss->wmm_ie);
-	os_free(bss->mdie);
-	os_free(bss);
-}
-
-
-static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss, *prev;
-
-	bss = wpa_s->mlme.sta_bss_list;
-	wpa_s->mlme.sta_bss_list = NULL;
-	while (bss) {
-		prev = bss;
-		bss = bss->next;
-		ieee80211_bss_free(wpa_s, prev);
-	}
-}
-
-
-static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
-			       struct ieee80211_mgmt *mgmt,
-			       size_t len,
-			       struct ieee80211_rx_status *rx_status,
-			       int beacon)
-{
-	struct ieee802_11_elems elems;
-	size_t baselen;
-	int channel, invalid = 0, clen;
-	struct ieee80211_sta_bss *bss;
-	u64 timestamp;
-	u8 *pos, *ie_pos;
-	size_t ie_len;
-
-	if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN))
-		return; /* ignore ProbeResp to foreign address */
-
-#if 0
-	wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR,
-		   beacon ? "Beacon" : "Probe Response",
-		   MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
-#endif
-
-	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-	if (baselen > len)
-		return;
-
-	pos = mgmt->u.beacon.timestamp;
-	timestamp = WPA_GET_LE64(pos);
-
-#if 0 /* FIX */
-	if (local->conf.mode == IW_MODE_ADHOC && beacon &&
-	    os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) {
-#ifdef IEEE80211_IBSS_DEBUG
-		static unsigned long last_tsf_debug = 0;
-		u64 tsf;
-		if (local->hw->get_tsf)
-			tsf = local->hw->get_tsf(local->mdev);
-		else
-			tsf = -1LLU;
-		if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-			wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID="
-				   MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld "
-				   "@%ld",
-				   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
-				   tsf, timestamp, tsf - timestamp, jiffies);
-			last_tsf_debug = jiffies;
-		}
-#endif /* IEEE80211_IBSS_DEBUG */
-	}
-#endif
-
-	ie_pos = mgmt->u.beacon.variable;
-	ie_len = len - baselen;
-	if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed)
-		invalid = 1;
-
-#if 0 /* FIX */
-	if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates &&
-	    os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 &&
-	    (sta = sta_info_get(local, mgmt->sa))) {
-		struct ieee80211_rate *rates;
-		size_t num_rates;
-		u32 supp_rates, prev_rates;
-		int i, j, oper_mode;
-
-		rates = local->curr_rates;
-		num_rates = local->num_curr_rates;
-		oper_mode = wpa_s->mlme.sta_scanning ?
-			local->scan_oper_phymode : local->conf.phymode;
-		for (i = 0; i < local->hw->num_modes; i++) {
-			struct ieee80211_hw_modes *mode = &local->hw->modes[i];
-			if (oper_mode == mode->mode) {
-				rates = mode->rates;
-				num_rates = mode->num_rates;
-				break;
-			}
-		}
-
-		supp_rates = 0;
-		for (i = 0; i < elems.supp_rates_len +
-			     elems.ext_supp_rates_len; i++) {
-			u8 rate = 0;
-			int own_rate;
-			if (i < elems.supp_rates_len)
-				rate = elems.supp_rates[i];
-			else if (elems.ext_supp_rates)
-				rate = elems.ext_supp_rates
-					[i - elems.supp_rates_len];
-			own_rate = 5 * (rate & 0x7f);
-			if (oper_mode == MODE_ATHEROS_TURBO)
-				own_rate *= 2;
-			for (j = 0; j < num_rates; j++)
-				if (rates[j].rate == own_rate)
-					supp_rates |= BIT(j);
-		}
-
-		prev_rates = sta->supp_rates;
-		sta->supp_rates &= supp_rates;
-		if (sta->supp_rates == 0) {
-			/* No matching rates - this should not really happen.
-			 * Make sure that at least one rate is marked
-			 * supported to avoid issues with TX rate ctrl. */
-			sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-		}
-		if (sta->supp_rates != prev_rates) {
-			wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set "
-				   "for " MACSTR " based on beacon info "
-				   "(0x%x & 0x%x -> 0x%x)",
-				   MAC2STR(sta->addr), prev_rates,
-				   supp_rates, sta->supp_rates);
-		}
-		sta_info_release(local, sta);
-	}
-#endif
-
-	if (elems.ssid == NULL)
-		return;
-
-	if (elems.ds_params && elems.ds_params_len == 1)
-		channel = elems.ds_params[0];
-	else
-		channel = rx_status->channel;
-
-	bss = ieee80211_bss_get(wpa_s, mgmt->bssid);
-	if (bss == NULL) {
-		bss = ieee80211_bss_add(wpa_s, mgmt->bssid);
-		if (bss == NULL)
-			return;
-	} else {
-#if 0
-		/* TODO: order by RSSI? */
-		spin_lock_bh(&local->sta_bss_lock);
-		list_move_tail(&bss->list, &local->sta_bss_list);
-		spin_unlock_bh(&local->sta_bss_lock);
-#endif
-	}
-
-	if (bss->probe_resp && beacon) {
-		/* Do not allow beacon to override data from Probe Response. */
-		return;
-	}
-
-	bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
-	bss->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
-	if (bss->ie == NULL || bss->ie_len < ie_len) {
-		os_free(bss->ie);
-		bss->ie = os_malloc(ie_len);
-	}
-	if (bss->ie) {
-		os_memcpy(bss->ie, ie_pos, ie_len);
-		bss->ie_len = ie_len;
-	}
-
-	if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) {
-		os_memcpy(bss->ssid, elems.ssid, elems.ssid_len);
-		bss->ssid_len = elems.ssid_len;
-	}
-
-	bss->supp_rates_len = 0;
-	if (elems.supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems.supp_rates_len)
-			clen = elems.supp_rates_len;
-		os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-			  elems.supp_rates, clen);
-		bss->supp_rates_len += clen;
-	}
-	if (elems.ext_supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems.ext_supp_rates_len)
-			clen = elems.ext_supp_rates_len;
-		os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-			  elems.ext_supp_rates, clen);
-		bss->supp_rates_len += clen;
-	}
-
-	if (elems.wpa_ie &&
-	    (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len ||
-	     os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) {
-		os_free(bss->wpa_ie);
-		bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2);
-		if (bss->wpa_ie) {
-			os_memcpy(bss->wpa_ie, elems.wpa_ie - 2,
-				  elems.wpa_ie_len + 2);
-			bss->wpa_ie_len = elems.wpa_ie_len + 2;
-		} else
-			bss->wpa_ie_len = 0;
-	} else if (!elems.wpa_ie && bss->wpa_ie) {
-		os_free(bss->wpa_ie);
-		bss->wpa_ie = NULL;
-		bss->wpa_ie_len = 0;
-	}
-
-	if (elems.rsn_ie &&
-	    (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len ||
-	     os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) {
-		os_free(bss->rsn_ie);
-		bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2);
-		if (bss->rsn_ie) {
-			os_memcpy(bss->rsn_ie, elems.rsn_ie - 2,
-				  elems.rsn_ie_len + 2);
-			bss->rsn_ie_len = elems.rsn_ie_len + 2;
-		} else
-			bss->rsn_ie_len = 0;
-	} else if (!elems.rsn_ie && bss->rsn_ie) {
-		os_free(bss->rsn_ie);
-		bss->rsn_ie = NULL;
-		bss->rsn_ie_len = 0;
-	}
-
-	if (elems.wmm &&
-	    (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len ||
-	     os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) {
-		os_free(bss->wmm_ie);
-		bss->wmm_ie = os_malloc(elems.wmm_len + 2);
-		if (bss->wmm_ie) {
-			os_memcpy(bss->wmm_ie, elems.wmm - 2,
-				  elems.wmm_len + 2);
-			bss->wmm_ie_len = elems.wmm_len + 2;
-		} else
-			bss->wmm_ie_len = 0;
-	} else if (!elems.wmm && bss->wmm_ie) {
-		os_free(bss->wmm_ie);
-		bss->wmm_ie = NULL;
-		bss->wmm_ie_len = 0;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (elems.mdie &&
-	    (bss->mdie == NULL || bss->mdie_len != elems.mdie_len ||
-	     os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) {
-		os_free(bss->mdie);
-		bss->mdie = os_malloc(elems.mdie_len + 2);
-		if (bss->mdie) {
-			os_memcpy(bss->mdie, elems.mdie - 2,
-				  elems.mdie_len + 2);
-			bss->mdie_len = elems.mdie_len + 2;
-		} else
-			bss->mdie_len = 0;
-	} else if (!elems.mdie && bss->mdie) {
-		os_free(bss->mdie);
-		bss->mdie = NULL;
-		bss->mdie_len = 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	bss->hw_mode = wpa_s->mlme.phymode;
-	bss->channel = channel;
-	bss->freq = wpa_s->mlme.freq;
-	if (channel != wpa_s->mlme.channel &&
-	    (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G ||
-	     wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) &&
-	    channel >= 1 && channel <= 14) {
-		static const int freq_list[] = {
-			2412, 2417, 2422, 2427, 2432, 2437, 2442,
-			2447, 2452, 2457, 2462, 2467, 2472, 2484
-		};
-		/* IEEE 802.11g/b mode can receive packets from neighboring
-		 * channels, so map the channel into frequency. */
-		bss->freq = freq_list[channel - 1];
-	}
-	bss->timestamp = timestamp;
-	os_get_time(&bss->last_update);
-	bss->rssi = rx_status->ssi;
-	if (!beacon)
-		bss->probe_resp++;
-}
-
-
-static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
-					 struct ieee80211_rx_status *rx_status)
-{
-	ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0);
-}
-
-
-static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	int use_protection;
-	size_t baselen;
-	struct ieee802_11_elems elems;
-
-	ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1);
-
-	if (!wpa_s->mlme.associated ||
-	    os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0)
-		return;
-
-	/* Process beacon from the current BSS */
-	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-	if (baselen > len)
-		return;
-
-	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-				   &elems, 0) == ParseFailed)
-		return;
-
-	use_protection = 0;
-	if (elems.erp_info && elems.erp_info_len >= 1) {
-		use_protection =
-			(elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
-	}
-
-	if (use_protection != !!wpa_s->mlme.use_protection) {
-		wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR
-			   ")",
-			   use_protection ? "enabled" : "disabled",
-			   MAC2STR(wpa_s->bssid));
-		wpa_s->mlme.use_protection = use_protection ? 1 : 0;
-		wpa_s->mlme.cts_protect_erp_frames = use_protection;
-	}
-
-	if (elems.wmm && wpa_s->mlme.wmm_enabled) {
-		ieee80211_sta_wmm_params(wpa_s, elems.wmm,
-					 elems.wmm_len);
-	}
-}
-
-
-static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s,
-					struct ieee80211_mgmt *mgmt,
-					size_t len,
-					struct ieee80211_rx_status *rx_status)
-{
-	int tx_last_beacon, adhoc;
-#if 0 /* FIX */
-	struct ieee80211_mgmt *resp;
-#endif
-	u8 *pos, *end;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-	if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED ||
-	    len < 24 + 2 || wpa_s->mlme.probe_resp == NULL)
-		return;
-
-#if 0 /* FIX */
-	if (local->hw->tx_last_beacon)
-		tx_last_beacon = local->hw->tx_last_beacon(local->mdev);
-	else
-#endif
-		tx_last_beacon = 1;
-
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR
-		   " BSSID=" MACSTR " (tx_last_beacon=%d)",
-		   MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
-		   MAC2STR(mgmt->bssid), tx_last_beacon);
-#endif /* IEEE80211_IBSS_DEBUG */
-
-	if (!tx_last_beacon)
-		return;
-
-	if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
-	    os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-		return;
-
-	end = ((u8 *) mgmt) + len;
-	pos = mgmt->u.probe_req.variable;
-	if (pos[0] != WLAN_EID_SSID ||
-	    pos + 2 + pos[1] > end) {
-		wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from "
-			   MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-	if (pos[1] != 0 &&
-	    (pos[1] != wpa_s->mlme.ssid_len ||
-	     os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0))
-	{
-		/* Ignore ProbeReq for foreign SSID */
-		return;
-	}
-
-#if 0 /* FIX */
-	/* Reply with ProbeResp */
-	skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC);
-	if (skb == NULL)
-		return;
-
-	resp = (struct ieee80211_mgmt *) skb->data;
-	os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR,
-		   MAC2STR(resp->da));
-#endif /* IEEE80211_IBSS_DEBUG */
-	ieee80211_sta_tx(wpa_s, skb, 0, 1);
-#endif
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
-					struct ieee80211_mgmt *mgmt,
-					size_t len,
-					struct ieee80211_rx_status *rx_status)
-{
-	union wpa_event_data data;
-	u16 status;
-	u8 *sta_addr, *target_ap_addr;
-
-	if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) {
-		wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame");
-		return;
-	}
-
-	/*
-	 * Only FT Action Response is needed for now since reservation
-	 * protocol is not supported.
-	 */
-	if (mgmt->u.action.u.ft_action_resp.action != 2) {
-		wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d",
-			   mgmt->u.action.u.ft_action_resp.action);
-		return;
-	}
-
-	status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code);
-	sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr;
-	target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr;
-	wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR
-		   " TargetAP " MACSTR " Status Code %d",
-		   MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
-	if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR
-			   " in FT Action Response", MAC2STR(sta_addr));
-		return;
-	}
-
-	if (status) {
-		wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates "
-			   "failure (status code %d)", status);
-		/* TODO: report error to FT code(?) */
-		return;
-	}
-
-	os_memset(&data, 0, sizeof(data));
-	data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable;
-	data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable -
-				     (u8 *) mgmt);
-	data.ft_ies.ft_action = 1;
-	os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN);
-	wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-	/* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed
-	 * successfully */
-	wpa_s->mlme.prev_bssid_set = 1;
-	wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-	os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN);
-	ieee80211_associate(wpa_s);
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_IEEE80211W
-
-/* MLME-SAQuery.response */
-static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s,
-					    const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt *mgmt;
-	int res;
-	size_t len;
-
-	mgmt = os_zalloc(sizeof(*mgmt));
-	if (mgmt == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-			   "SA Query action frame");
-		return -1;
-	}
-
-	len = 24;
-	os_memcpy(mgmt->da, addr, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	len += 1 + sizeof(mgmt->u.action.u.sa_query_resp);
-
-	res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len);
-	os_free(mgmt);
-
-	return res;
-}
-
-
-static void ieee80211_rx_mgmt_sa_query_action(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	struct ieee80211_rx_status *rx_status)
-{
-	if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) {
-		wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame");
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) {
-		wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d",
-			   mgmt->u.action.u.sa_query_req.action);
-		return;
-	}
-
-	if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown "
-			   "source " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during "
-			   "association process");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request");
-	ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u.
-					 sa_query_req.trans_id);
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
-static void dump_tspec(struct wmm_tspec_element *tspec)
-{
-	int up, psb, dir, tid;
-	u16 val;
-
-	up = (tspec->ts_info[1] >> 3) & 0x07;
-	psb = (tspec->ts_info[1] >> 2) & 0x01;
-	dir = (tspec->ts_info[0] >> 5) & 0x03;
-	tid = (tspec->ts_info[0] >> 1) & 0x0f;
-	wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
-		   up, psb, dir, tid);
-	val = le_to_host16(tspec->nominal_msdu_size);
-	wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
-		   val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
-	wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
-		   le_to_host32(tspec->mean_data_rate));
-	wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
-		   le_to_host32(tspec->minimum_phy_rate));
-	val = le_to_host16(tspec->surplus_bandwidth_allowance);
-	wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
-		   val >> 13, 10000 * (val & 0x1fff) / 0x2000);
-	val = le_to_host16(tspec->medium_time);
-	wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)",
-		   val, 32 * val);
-}
-
-
-static int is_wmm_tspec(const u8 *ie, size_t len)
-{
-	const struct wmm_tspec_element *tspec;
-
-	if (len < sizeof(*tspec))
-		return 0;
-
-	tspec = (const struct wmm_tspec_element *) ie;
-	if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC ||
-	    tspec->length < sizeof(*tspec) - 2 ||
-	    tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 ||
-	    tspec->oui[2] != 0xf2 || tspec->oui_type != 2 ||
-	    tspec->oui_subtype != 2 || tspec->version != 1)
-		return 0;
-
-	return 1;
-}
-
-
-static void ieee80211_rx_addts_resp(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	size_t var_len)
-{
-	struct wmm_tspec_element *tspec;
-
-	wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response");
-	wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)",
-		    mgmt->u.action.u.wmm_action.variable, var_len);
-	if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-		return;
-	tspec = (struct wmm_tspec_element *)
-		mgmt->u.action.u.wmm_action.variable;
-	dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_delts(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	size_t var_len)
-{
-	struct wmm_tspec_element *tspec;
-
-	wpa_printf(MSG_DEBUG, "WMM: Received DELTS");
-	wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)",
-		    mgmt->u.action.u.wmm_action.variable, var_len);
-	if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-		return;
-	tspec = (struct wmm_tspec_element *)
-		mgmt->u.action.u.wmm_action.variable;
-	dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_mgmt_wmm_action(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	struct ieee80211_rx_status *rx_status)
-{
-	size_t alen;
-
-	alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-	if (len < alen) {
-		wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, "
-		   "Dialog Token %d, Status Code %d",
-		   mgmt->u.action.u.wmm_action.action_code,
-		   mgmt->u.action.u.wmm_action.dialog_token,
-		   mgmt->u.action.u.wmm_action.status_code);
-
-	switch (mgmt->u.action.u.wmm_action.action_code) {
-	case WMM_ACTION_CODE_ADDTS_RESP:
-		ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen);
-		break;
-	case WMM_ACTION_CODE_DELTS:
-		ieee80211_rx_delts(wpa_s, mgmt, len, len - alen);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d",
-			   mgmt->u.action.u.wmm_action.action_code);
-		break;
-	}
-}
-
-
-static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	wpa_printf(MSG_DEBUG, "MLME: received Action frame");
-
-	if (len < 25)
-		return;
-
-	switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
-	case WLAN_ACTION_FT:
-		ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status);
-		break;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	case WLAN_ACTION_SA_QUERY:
-		ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
-		break;
-#endif /* CONFIG_IEEE80211W */
-	case WLAN_ACTION_WMM:
-		ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_ACTION_PUBLIC:
-		if (wpa_s->mlme.public_action_cb) {
-			wpa_s->mlme.public_action_cb(
-				wpa_s->mlme.public_action_cb_ctx,
-				(u8 *) mgmt, len, rx_status->freq);
-			return;
-		}
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d",
-			   mgmt->u.action.category);
-		break;
-	}
-}
-
-
-static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s,
-				  const u8 *buf, size_t len,
-				  struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	switch (WLAN_FC_GET_STYPE(fc)) {
-	case WLAN_FC_STYPE_PROBE_REQ:
-		ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_PROBE_RESP:
-		ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_BEACON:
-		ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_AUTH:
-		ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_ASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0);
-		break;
-	case WLAN_FC_STYPE_REASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1);
-		break;
-	case WLAN_FC_STYPE_DEAUTH:
-		ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_DISASSOC:
-		ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_ACTION:
-		ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "MLME: received unknown management "
-			   "frame - stype=%d", WLAN_FC_GET_STYPE(fc));
-		break;
-	}
-}
-
-
-static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s,
-				  const u8 *buf, size_t len,
-				  struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) {
-		if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
-			ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt,
-						     len, rx_status);
-		} else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
-			ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-		}
-	}
-}
-
-
-static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s)
-{
-	int active = 0;
-
-#if 0 /* FIX */
-	list_for_each(ptr, &local->sta_list) {
-		sta = list_entry(ptr, struct sta_info, list);
-		if (sta->dev == dev &&
-		    time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
-			       jiffies)) {
-			active++;
-			break;
-		}
-	}
-#endif
-
-	return active;
-}
-
-
-static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	list_for_each_safe(ptr, n, &local->sta_list) {
-		sta = list_entry(ptr, struct sta_info, list);
-		if (time_after(jiffies, sta->last_rx +
-			       IEEE80211_IBSS_INACTIVITY_LIMIT)) {
-			wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA "
-				   MACSTR, MAC2STR(sta->addr));
-			sta_info_free(local, sta, 1);
-		}
-	}
-#endif
-}
-
-
-static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_driver_scan_params params;
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-	ieee80211_sta_expire(wpa_s);
-	if (ieee80211_sta_active_ibss(wpa_s))
-		return;
-
-	wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for "
-		   "other IBSS networks with same SSID (merge)");
-	os_memset(&params, 0, sizeof(params));
-	params.ssids[0].ssid = wpa_s->mlme.ssid;
-	params.ssids[0].ssid_len = wpa_s->mlme.ssid_len;
-	params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0;
-	ieee80211_sta_req_scan(wpa_s, &params);
-}
-
-
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-
-	switch (wpa_s->mlme.state) {
-	case IEEE80211_DISABLED:
-		break;
-	case IEEE80211_AUTHENTICATE:
-		ieee80211_authenticate(wpa_s);
-		break;
-	case IEEE80211_ASSOCIATE:
-		ieee80211_associate(wpa_s);
-		break;
-	case IEEE80211_ASSOCIATED:
-		ieee80211_associated(wpa_s);
-		break;
-	case IEEE80211_IBSS_SEARCH:
-		ieee80211_sta_find_ibss(wpa_s);
-		break;
-	case IEEE80211_IBSS_JOINED:
-		ieee80211_sta_merge_ibss(wpa_s);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d",
-			   wpa_s->mlme.state);
-		break;
-	}
-
-	if (ieee80211_privacy_mismatch(wpa_s)) {
-		wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch "
-			   "and mixed-cell disabled - disassociate");
-
-		ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED);
-		ieee80211_set_associated(wpa_s, 0);
-	}
-}
-
-
-static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	if (ssid && ssid->mode != WPAS_MODE_INFRA)
-		return;
-
-#if 0 /* FIX */
-	if (local->hw->reset_tsf) {
-		/* Reset own TSF to allow time synchronization work. */
-		local->hw->reset_tsf(local->mdev);
-	}
-#endif
-
-	wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */
-
-
-	if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-	else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY;
-	else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP;
-	else
-		wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-	wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d",
-		   wpa_s->mlme.auth_alg);
-	wpa_s->mlme.auth_transaction = -1;
-	wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0;
-	ieee80211_authenticate(wpa_s);
-}
-
-
-static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	int m, c;
-
-	for (m = 0; m < local->hw->num_modes; m++) {
-		struct ieee80211_hw_modes *mode = &local->hw->modes[m];
-		if (mode->mode != local->conf.phymode)
-			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct ieee80211_channel *chan = &mode->channels[c];
-			if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-			    chan->chan == local->conf.channel) {
-				if (chan->flag & IEEE80211_CHAN_W_IBSS)
-					return 1;
-				break;
-			}
-		}
-	}
-#endif
-
-	return 0;
-}
-
-
-static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
-				   struct ieee80211_sta_bss *bss)
-{
-	int res = 0, rates, done = 0, bssid_changed;
-	struct ieee80211_mgmt *mgmt;
-#if 0 /* FIX */
-	struct ieee80211_tx_control control;
-	struct ieee80211_rate *rate;
-	struct rate_control_extra extra;
-#endif
-	u8 *pos, *buf;
-	size_t len;
-
-	/* Remove possible STA entries from other IBSS networks. */
-#if 0 /* FIX */
-	sta_info_flush(local, NULL);
-
-	if (local->hw->reset_tsf) {
-		/* Reset own TSF to allow time synchronization work. */
-		local->hw->reset_tsf(local->mdev);
-	}
-#endif
-	bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN);
-	os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN);
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
-
-#if 0 /* FIX */
-	local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
-	sdata->drop_unencrypted = bss->capability &
-		host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0;
-#endif
-
-#if 0 /* FIX */
-	os_memset(&rq, 0, sizeof(rq));
-	rq.m = bss->freq * 100000;
-	rq.e = 1;
-	res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL);
-#endif
-
-	if (!ieee80211_ibss_allowed(wpa_s)) {
-#if 0 /* FIX */
-		wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d "
-			   "(%d MHz)", local->conf.channel,
-			   local->conf.freq);
-#endif
-		return -1;
-	}
-
-	/* Set beacon template based on scan results */
-	buf = os_malloc(400);
-	len = 0;
-	do {
-		if (buf == NULL)
-			break;
-
-		mgmt = (struct ieee80211_mgmt *) buf;
-		len += 24 + sizeof(mgmt->u.beacon);
-		os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_BEACON);
-		os_memset(mgmt->da, 0xff, ETH_ALEN);
-		os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-		os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-#if 0 /* FIX */
-		mgmt->u.beacon.beacon_int =
-			host_to_le16(local->conf.beacon_int);
-#endif
-		mgmt->u.beacon.capab_info = host_to_le16(bss->capability);
-
-		pos = buf + len;
-		len += 2 + wpa_s->mlme.ssid_len;
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = wpa_s->mlme.ssid_len;
-		os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-		rates = bss->supp_rates_len;
-		if (rates > 8)
-			rates = 8;
-		pos = buf + len;
-		len += 2 + rates;
-		*pos++ = WLAN_EID_SUPP_RATES;
-		*pos++ = rates;
-		os_memcpy(pos, bss->supp_rates, rates);
-
-		pos = buf + len;
-		len += 2 + 1;
-		*pos++ = WLAN_EID_DS_PARAMS;
-		*pos++ = 1;
-		*pos++ = bss->channel;
-
-		pos = buf + len;
-		len += 2 + 2;
-		*pos++ = WLAN_EID_IBSS_PARAMS;
-		*pos++ = 2;
-		/* FIX: set ATIM window based on scan results */
-		*pos++ = 0;
-		*pos++ = 0;
-
-		if (bss->supp_rates_len > 8) {
-			rates = bss->supp_rates_len - 8;
-			pos = buf + len;
-			len += 2 + rates;
-			*pos++ = WLAN_EID_EXT_SUPP_RATES;
-			*pos++ = rates;
-			os_memcpy(pos, &bss->supp_rates[8], rates);
-		}
-
-#if 0 /* FIX */
-		os_memset(&control, 0, sizeof(control));
-		control.pkt_type = PKT_PROBE_RESP;
-		os_memset(&extra, 0, sizeof(extra));
-		extra.endidx = local->num_curr_rates;
-		rate = rate_control_get_rate(wpa_s, skb, &extra);
-		if (rate == NULL) {
-			wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX "
-				   "rate for IBSS beacon");
-			break;
-		}
-		control.tx_rate = (wpa_s->mlme.short_preamble &&
-				   (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			rate->val2 : rate->val;
-		control.antenna_sel = local->conf.antenna_sel;
-		control.power_level = local->conf.power_level;
-		control.no_ack = 1;
-		control.retry_limit = 1;
-		control.rts_cts_duration = 0;
-#endif
-
-#if 0 /* FIX */
-		wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC);
-		if (wpa_s->mlme.probe_resp) {
-			mgmt = (struct ieee80211_mgmt *)
-				wpa_s->mlme.probe_resp->data;
-			mgmt->frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					     WLAN_FC_STYPE_PROBE_RESP);
-		} else {
-			wpa_printf(MSG_DEBUG, "MLME: Could not allocate "
-				   "ProbeResp template for IBSS");
-		}
-
-		if (local->hw->beacon_update &&
-		    local->hw->beacon_update(wpa_s, skb, &control) == 0) {
-			wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon "
-				   "template based on scan results");
-			skb = NULL;
-		}
-
-		rates = 0;
-		for (i = 0; i < bss->supp_rates_len; i++) {
-			int rate = (bss->supp_rates[i] & 0x7f) * 5;
-			if (local->conf.phymode == MODE_ATHEROS_TURBO)
-				rate *= 2;
-			for (j = 0; j < local->num_curr_rates; j++)
-				if (local->curr_rates[j] == rate)
-					rates |= BIT(j);
-		}
-		wpa_s->mlme.supp_rates_bits = rates;
-#endif
-		done = 1;
-	} while (0);
-
-	os_free(buf);
-	if (!done) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon "
-			   "template");
-	}
-
-	wpa_s->mlme.state = IEEE80211_IBSS_JOINED;
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-	return res;
-}
-
-
-#if 0 /* FIX */
-static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	u8 bssid[ETH_ALEN], *pos;
-	int i;
-
-#if 0
-	/* Easier testing, use fixed BSSID. */
-	os_memset(bssid, 0xfe, ETH_ALEN);
-#else
-	/* Generate random, not broadcast, locally administered BSSID. Mix in
-	 * own MAC address to make sure that devices that do not have proper
-	 * random number generator get different BSSID. */
-	os_get_random(bssid, ETH_ALEN);
-	for (i = 0; i < ETH_ALEN; i++)
-		bssid[i] ^= wpa_s->own_addr[i];
-	bssid[0] &= ~0x01;
-	bssid[0] |= 0x02;
-#endif
-
-	wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID "
-		   MACSTR "", MAC2STR(bssid));
-
-	bss = ieee80211_bss_add(wpa_s, bssid);
-	if (bss == NULL)
-		return -ENOMEM;
-
-#if 0 /* FIX */
-	if (local->conf.beacon_int == 0)
-		local->conf.beacon_int = 100;
-	bss->beacon_int = local->conf.beacon_int;
-	bss->hw_mode = local->conf.phymode;
-	bss->channel = local->conf.channel;
-	bss->freq = local->conf.freq;
-#endif
-	os_get_time(&bss->last_update);
-	bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS);
-#if 0 /* FIX */
-	if (sdata->default_key) {
-		bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY);
-	} else
-		sdata->drop_unencrypted = 0;
-	bss->supp_rates_len = local->num_curr_rates;
-#endif
-	pos = bss->supp_rates;
-#if 0 /* FIX */
-	for (i = 0; i < local->num_curr_rates; i++) {
-		int rate = local->curr_rates[i];
-		if (local->conf.phymode == MODE_ATHEROS_TURBO)
-			rate /= 2;
-		*pos++ = (u8) (rate / 5);
-	}
-#endif
-
-	return ieee80211_sta_join_ibss(wpa_s, bss);
-}
-#endif
-
-
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	int found = 0;
-	u8 bssid[ETH_ALEN];
-	int active_ibss;
-	struct os_time now;
-
-	if (wpa_s->mlme.ssid_len == 0)
-		return -EINVAL;
-
-	active_ibss = ieee80211_sta_active_ibss(wpa_s);
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)",
-		   active_ibss);
-#endif /* IEEE80211_IBSS_DEBUG */
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-		if (wpa_s->mlme.ssid_len != bss->ssid_len ||
-		    os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0
-		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
-			continue;
-#ifdef IEEE80211_IBSS_DEBUG
-		wpa_printf(MSG_DEBUG, "   bssid=" MACSTR " found",
-			   MAC2STR(bss->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-		os_memcpy(bssid, bss->bssid, ETH_ALEN);
-		found = 1;
-		if (active_ibss ||
-		    os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)
-			break;
-	}
-
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "   sta_find_ibss: selected " MACSTR " current "
-		   MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-	if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 &&
-	    (bss = ieee80211_bss_get(wpa_s, bssid))) {
-		wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR
-			   " based on configured SSID",
-			   MAC2STR(bssid));
-		return ieee80211_sta_join_ibss(wpa_s, bss);
-	}
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "   did not try to join ibss");
-#endif /* IEEE80211_IBSS_DEBUG */
-
-	/* Selected IBSS not found in current scan results - try to scan */
-	os_get_time(&now);
-#if 0 /* FIX */
-	if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED &&
-	    !ieee80211_sta_active_ibss(wpa_s)) {
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_IBSS_MERGE_INTERVAL);
-	} else if (time_after(jiffies, wpa_s->mlme.last_scan_completed +
-			      IEEE80211_SCAN_INTERVAL)) {
-		wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS "
-			   "to join");
-		return ieee80211_sta_req_scan(wpa_s->mlme.ssid,
-					      wpa_s->mlme.ssid_len);
-	} else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) {
-		int interval = IEEE80211_SCAN_INTERVAL;
-
-		if (time_after(jiffies, wpa_s->mlme.ibss_join_req +
-			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
-			if (wpa_s->mlme.create_ibss &&
-			    ieee80211_ibss_allowed(wpa_s))
-				return ieee80211_sta_create_ibss(wpa_s);
-			if (wpa_s->mlme.create_ibss) {
-				wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed "
-					   "on the configured channel %d "
-					   "(%d MHz)",
-					   local->conf.channel,
-					   local->conf.freq);
-			}
-
-			/* No IBSS found - decrease scan interval and continue
-			 * scanning. */
-			interval = IEEE80211_SCAN_INTERVAL_SLOW;
-		}
-
-		wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-		ieee80211_reschedule_timer(wpa_s, interval);
-		return 0;
-	}
-#endif
-
-	return 0;
-}
-
-
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-			   size_t *len)
-{
-	os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-	*len = wpa_s->mlme.ssid_len;
-	return 0;
-}
-
-
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			    struct wpa_driver_associate_params *params)
-{
-	struct ieee80211_sta_bss *bss;
-	int bssid_changed;
-
-	wpa_s->mlme.bssid_set = 0;
-	wpa_s->mlme.freq = params->freq;
-	if (params->bssid) {
-		bssid_changed = os_memcmp(wpa_s->bssid, params->bssid,
-					  ETH_ALEN);
-		os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
-		if (bssid_changed)
-			wpas_notify_bssid_changed(wpa_s);
-
-		if (!is_zero_ether_addr(params->bssid))
-			wpa_s->mlme.bssid_set = 1;
-		bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-		if (bss) {
-			wpa_s->mlme.phymode = bss->hw_mode;
-			wpa_s->mlme.channel = bss->channel;
-			wpa_s->mlme.freq = bss->freq;
-		}
-	}
-
-#if 0 /* FIX */
-	/* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
-	 * not defined. */
-	if (local->hw->conf_tx) {
-		struct ieee80211_tx_queue_params qparam;
-		int i;
-
-		os_memset(&qparam, 0, sizeof(qparam));
-		/* TODO: are these ok defaults for all hw_modes? */
-		qparam.aifs = 2;
-		qparam.cw_min =
-			local->conf.phymode == MODE_IEEE80211B ? 31 : 15;
-		qparam.cw_max = 1023;
-		qparam.burst_time = 0;
-		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-		{
-			local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0,
-					   &qparam);
-		}
-		/* IBSS uses different parameters for Beacon sending */
-		qparam.cw_min++;
-		qparam.cw_min *= 2;
-		qparam.cw_min--;
-		local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam);
-	}
-#endif
-
-	if (wpa_s->mlme.ssid_len != params->ssid_len ||
-	    os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0)
-		wpa_s->mlme.prev_bssid_set = 0;
-	os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len);
-	os_memset(wpa_s->mlme.ssid + params->ssid_len, 0,
-		  MAX_SSID_LEN - params->ssid_len);
-	wpa_s->mlme.ssid_len = params->ssid_len;
-	wpa_s->mlme.ssid_set = 1;
-
-	os_free(wpa_s->mlme.extra_ie);
-	if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-		wpa_s->mlme.extra_ie = NULL;
-		wpa_s->mlme.extra_ie_len = 0;
-	} else {
-		wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len);
-		if (wpa_s->mlme.extra_ie == NULL) {
-			wpa_s->mlme.extra_ie_len = 0;
-			return -1;
-		}
-		os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie,
-			  params->wpa_ie_len);
-		wpa_s->mlme.extra_ie_len = params->wpa_ie_len;
-	}
-
-	wpa_s->mlme.key_mgmt = params->key_mgmt_suite;
-
-	ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-				  wpa_s->mlme.channel, wpa_s->mlme.freq);
-
-	if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) {
-		os_get_time(&wpa_s->mlme.ibss_join_req);
-		wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-		return ieee80211_sta_find_ibss(wpa_s);
-	}
-
-	if (wpa_s->mlme.bssid_set)
-		ieee80211_sta_new_auth(wpa_s);
-
-	return 0;
-}
-
-
-static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel;
-	wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq;
-	wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode;
-}
-
-
-static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel;
-	wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq;
-	wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode;
-	if (wpa_s->mlme.freq == 0)
-		return 0;
-	return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-					 wpa_s->mlme.channel,
-					 wpa_s->mlme.freq);
-}
-
-
-static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
-{
-	size_t m;
-	int c;
-
-	for (m = 0; m < wpa_s->mlme.num_modes; m++) {
-		struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m];
-		if ((int) mode->mode != (int) wpa_s->mlme.phymode)
-			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct hostapd_channel_data *chan = &mode->channels[c];
-			if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-			    chan->chan == wpa_s->mlme.channel) {
-				if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN))
-					return 1;
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
-
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct hostapd_hw_modes *mode;
-	struct hostapd_channel_data *chan;
-	int skip = 0;
-	int timeout = 0;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	int adhoc;
-
-	if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL)
-		return;
-
-	adhoc = ssid && ssid->mode == 1;
-
-	switch (wpa_s->mlme.scan_state) {
-	case SCAN_SET_CHANNEL:
-		mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx];
-		if (wpa_s->mlme.scan_hw_mode_idx >=
-		    (int) wpa_s->mlme.num_modes ||
-		    (wpa_s->mlme.scan_hw_mode_idx + 1 ==
-		     (int) wpa_s->mlme.num_modes
-		     && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) {
-			if (ieee80211_sta_restore_oper_chan(wpa_s)) {
-				wpa_printf(MSG_DEBUG, "MLME: failed to "
-					   "restore operational channel after "
-					   "scan");
-			}
-			wpa_printf(MSG_DEBUG, "MLME: scan completed");
-			wpa_s->mlme.sta_scanning = 0;
-			os_get_time(&wpa_s->mlme.last_scan_completed);
-			wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
-			if (adhoc) {
-				if (!wpa_s->mlme.bssid_set ||
-				    (wpa_s->mlme.state ==
-				     IEEE80211_IBSS_JOINED &&
-				     !ieee80211_sta_active_ibss(wpa_s)))
-					ieee80211_sta_find_ibss(wpa_s);
-			}
-			return;
-		}
-		skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
-		chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
-		if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
-		    (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) ||
-		    (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) &&
-		     mode->mode == HOSTAPD_MODE_IEEE80211B &&
-		     wpa_s->mlme.scan_skip_11b))
-			skip = 1;
-		if (!skip && wpa_s->mlme.scan_freqs) {
-			int i, found = 0;
-			for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) {
-				if (wpa_s->mlme.scan_freqs[i] == chan->freq) {
-					found = 1;
-					break;
-				}
-			}
-			if (!found)
-				skip = 1;
-		}
-
-		if (!skip) {
-			wpa_printf(MSG_MSGDUMP,
-				   "MLME: scan channel %d (%d MHz)",
-				   chan->chan, chan->freq);
-
-			wpa_s->mlme.channel = chan->chan;
-			wpa_s->mlme.freq = chan->freq;
-			wpa_s->mlme.phymode = mode->mode;
-			if (ieee80211_sta_set_channel(wpa_s, mode->mode,
-						      chan->chan, chan->freq))
-			{
-				wpa_printf(MSG_DEBUG, "MLME: failed to set "
-					   "channel %d (%d MHz) for scan",
-					   chan->chan, chan->freq);
-				skip = 1;
-			}
-		}
-
-		wpa_s->mlme.scan_channel_idx++;
-		if (wpa_s->mlme.scan_channel_idx >=
-		    wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx].
-		    num_channels) {
-			wpa_s->mlme.scan_hw_mode_idx++;
-			wpa_s->mlme.scan_channel_idx = 0;
-		}
-
-		if (skip) {
-			timeout = 0;
-			break;
-		}
-
-		timeout = IEEE80211_PROBE_DELAY;
-		wpa_s->mlme.scan_state = SCAN_SEND_PROBE;
-		break;
-	case SCAN_SEND_PROBE:
-		if (ieee80211_active_scan(wpa_s)) {
-			ieee80211_send_probe_req(wpa_s, NULL,
-						 wpa_s->mlme.scan_ssid,
-						 wpa_s->mlme.scan_ssid_len);
-			timeout = IEEE80211_CHANNEL_TIME;
-		} else {
-			timeout = IEEE80211_PASSIVE_CHANNEL_TIME;
-		}
-		wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-		break;
-	}
-
-	eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000),
-			       ieee80211_sta_scan_timer, wpa_s, NULL);
-}
-
-
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-			   struct wpa_driver_scan_params *params)
-{
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid_len > MAX_SSID_LEN)
-		return -1;
-
-	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
-	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
-	 * BSSID: MACAddress
-	 * SSID
-	 * ScanType: ACTIVE, PASSIVE
-	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
-	 *    a Probe frame during active scanning
-	 * ChannelList
-	 * MinChannelTime (>= ProbeDelay), in TU
-	 * MaxChannelTime: (>= MinChannelTime), in TU
-	 */
-
-	 /* MLME-SCAN.confirm
-	  * BSSDescriptionSet
-	  * ResultCode: SUCCESS, INVALID_PARAMETERS
-	 */
-
-	/* TODO: if assoc, move to power save mode for the duration of the
-	 * scan */
-
-	if (wpa_s->mlme.sta_scanning)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "MLME: starting scan");
-
-	ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies,
-				       params->extra_ies_len);
-
-	os_free(wpa_s->mlme.scan_freqs);
-	if (params->freqs) {
-		int i;
-		for (i = 0; params->freqs[i]; i++)
-			;
-		wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int));
-		if (wpa_s->mlme.scan_freqs)
-			os_memcpy(wpa_s->mlme.scan_freqs, params->freqs,
-				  (i + 1) * sizeof(int));
-	} else
-		wpa_s->mlme.scan_freqs = NULL;
-
-	ieee80211_sta_save_oper_chan(wpa_s);
-
-	wpa_s->mlme.sta_scanning = 1;
-	/* TODO: stop TX queue? */
-
-	if (ssid) {
-		wpa_s->mlme.scan_ssid_len = ssid_len;
-		os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len);
-	} else
-		wpa_s->mlme.scan_ssid_len = 0;
-	wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not
-					* supported */
-	wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-	wpa_s->mlme.scan_hw_mode_idx = 0;
-	wpa_s->mlme.scan_channel_idx = 0;
-	eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL);
-
-	return 0;
-}
-
-
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-	size_t ap_num = 0;
-	struct wpa_scan_results *res;
-	struct wpa_scan_res *r;
-	struct ieee80211_sta_bss *bss;
-
-	res = os_zalloc(sizeof(*res));
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next)
-		ap_num++;
-	res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		return NULL;
-	}
-
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-		r = os_zalloc(sizeof(*r) + bss->ie_len);
-		if (r == NULL)
-			break;
-		os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
-		r->freq = bss->freq;
-		r->beacon_int = bss->beacon_int;
-		r->caps = bss->capability;
-		r->level = bss->rssi;
-		r->tsf = bss->timestamp;
-		if (bss->ie) {
-			r->ie_len = bss->ie_len;
-			os_memcpy(r + 1, bss->ie, bss->ie_len);
-		}
-
-		res->res[res->num++] = r;
-	}
-
-	return res;
-}
-
-
-#if 0 /* FIX */
-struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s,
-					 struct sk_buff *skb, u8 *bssid,
-					 u8 *addr)
-{
-	struct ieee80211_local *local = dev->priv;
-	struct list_head *ptr;
-	struct sta_info *sta;
-	struct wpa_supplicant *sta_dev = NULL;
-
-	/* TODO: Could consider removing the least recently used entry and
-	 * allow new one to be added. */
-	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-		if (net_ratelimit()) {
-			wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS "
-				   "STA entry " MACSTR, MAC2STR(addr));
-		}
-		return NULL;
-	}
-
-	spin_lock_bh(&local->sub_if_lock);
-	list_for_each(ptr, &local->sub_if_list) {
-		sdata = list_entry(ptr, struct ieee80211_sub_if_data, list);
-		if (sdata->type == IEEE80211_SUB_IF_TYPE_STA &&
-		    os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-			sta_dev = sdata->dev;
-			break;
-		}
-	}
-	spin_unlock_bh(&local->sub_if_lock);
-
-	if (sta_dev == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR
-		   " (dev=%s)", MAC2STR(addr), sta_dev->name);
-
-	sta = sta_info_add(wpa_s, addr);
-	if (sta == NULL) {
-		return NULL;
-	}
-
-	sta->dev = sta_dev;
-	sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-
-	rate_control_rate_init(local, sta);
-
-	return sta; /* caller will call sta_info_release() */
-}
-#endif
-
-
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason);
-
-	ieee80211_send_deauth(wpa_s, reason);
-	ieee80211_set_associated(wpa_s, 0);
-	return 0;
-}
-
-
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason);
-
-	if (!wpa_s->mlme.associated)
-		return -1;
-
-	ieee80211_send_disassoc(wpa_s, reason);
-	ieee80211_set_associated(wpa_s, 0);
-	return 0;
-}
-
-
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		      struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	const u8 *pos;
-
-	/* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */
-
-	if (wpa_s->mlme.sta_scanning) {
-		ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status);
-		return;
-	}
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
-		ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status);
-	else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
-		if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) !=
-		    WLAN_FC_FROMDS)
-			return;
-		/* mgmt->sa is actually BSSID for FromDS data frames */
-		if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0)
-			return;
-		/* Skip IEEE 802.11 and LLC headers */
-		pos = buf + 24 + 6;
-		if (WPA_GET_BE16(pos) != ETH_P_EAPOL)
-			return;
-		pos += 2;
-		/* mgmt->bssid is actually BSSID for SA data frames */
-		wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid,
-					pos, buf + len - pos);
-	}
-}
-
-
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-				    size_t num_hw_features)
-{
-	size_t i;
-
-	if (hw_features == NULL)
-		return;
-
-	for (i = 0; i < num_hw_features; i++) {
-		os_free(hw_features[i].channels);
-		os_free(hw_features[i].rates);
-	}
-
-	os_free(hw_features);
-}
-
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-	u16 num_modes, flags;
-
-	wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes,
-							&flags);
-	if (wpa_s->mlme.modes == NULL) {
-		wpa_printf(MSG_ERROR, "MLME: Failed to read supported "
-			   "channels and rates from the driver");
-		return -1;
-	}
-
-	wpa_s->mlme.num_modes = num_modes;
-
-	wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A;
-	wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B;
-	wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G;
-
-	wpa_s->mlme.wmm_enabled = 1;
-
-	return 0;
-}
-
-
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-	eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-	eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL);
-	os_free(wpa_s->mlme.extra_ie);
-	wpa_s->mlme.extra_ie = NULL;
-	os_free(wpa_s->mlme.extra_probe_ie);
-	wpa_s->mlme.extra_probe_ie = NULL;
-	os_free(wpa_s->mlme.assocreq_ies);
-	wpa_s->mlme.assocreq_ies = NULL;
-	os_free(wpa_s->mlme.assocresp_ies);
-	wpa_s->mlme.assocresp_ies = NULL;
-	ieee80211_bss_list_deinit(wpa_s);
-	ieee80211_sta_free_hw_features(wpa_s->mlme.modes,
-				       wpa_s->mlme.num_modes);
-#ifdef CONFIG_IEEE80211R
-	os_free(wpa_s->mlme.ft_ies);
-	wpa_s->mlme.ft_ies = NULL;
-	wpa_s->mlme.ft_ies_len = 0;
-#endif /* CONFIG_IEEE80211R */
-
-	os_free(wpa_s->mlme.scan_freqs);
-	wpa_s->mlme.scan_freqs = NULL;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-				const u8 *ies, size_t ies_len)
-{
-	if (md == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain");
-		os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR,
-			   MAC2STR(md));
-		os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN);
-	}
-
-	wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len);
-	os_free(wpa_s->mlme.ft_ies);
-	wpa_s->mlme.ft_ies = os_malloc(ies_len);
-	if (wpa_s->mlme.ft_ies == NULL)
-		return -1;
-	os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len);
-	wpa_s->mlme.ft_ies_len = ies_len;
-
-	return 0;
-}
-
-
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-				 const u8 *target_ap,
-				 const u8 *ies, size_t ies_len)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-	int res;
-
-	/*
-	 * Action frame payload:
-	 * Category[1] = 6 (Fast BSS Transition)
-	 * Action[1] = 1 (Fast BSS Transition Request)
-	 * STA Address
-	 * Target AP Address
-	 * FT IEs
-	 */
-
-	buf = os_zalloc(sizeof(*mgmt) + ies_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-			   "FT action frame");
-		return -1;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_FT;
-	mgmt->u.action.u.ft_action_req.action = action;
-	os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr,
-		  ETH_ALEN);
-	os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap,
-		  ETH_ALEN);
-	os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len);
-	len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len;
-
-	wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d "
-		   "Target AP=" MACSTR " body_len=%lu",
-		   action, MAC2STR(target_ap), (unsigned long) ies_len);
-
-	res = ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-
-	return res;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-					  const u8 *ies, size_t ies_len)
-{
-	os_free(wpa_s->mlme.extra_probe_ie);
-	wpa_s->mlme.extra_probe_ie = NULL;
-	wpa_s->mlme.extra_probe_ie_len = 0;
-
-	if (ies == NULL)
-		return 0;
-
-	wpa_s->mlme.extra_probe_ie = os_malloc(ies_len);
-	if (wpa_s->mlme.extra_probe_ie == NULL)
-		return -1;
-
-	os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len);
-	wpa_s->mlme.extra_probe_ie_len = ies_len;
-
-	return 0;
-}

Deleted: vendor/wpa/2.0/wpa_supplicant/mlme.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/mlme.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/mlme.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,129 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MLME_H
-#define MLME_H
-
-struct wpa_supplicant;
-
-struct ieee80211_rx_status {
-	int freq;
-        int channel;
-        int ssi;
-};
-
-#ifdef CONFIG_CLIENT_MLME
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s);
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-			   struct wpa_driver_scan_params *params);
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			    struct wpa_driver_associate_params *params);
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-			   size_t *len);
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-				    size_t num_hw_features);
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		      struct ieee80211_rx_status *rx_status);
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-				const u8 *ies, size_t ies_len);
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-				 const u8 *target_ap,
-				 const u8 *ies, size_t ies_len);
-
-#else /* CONFIG_CLIENT_MLME */
-
-static inline int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-					 struct wpa_driver_scan_params *params)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s,
-					       u16 reason)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s,
-					     u16 reason)
-{
-	return -1;
-}
-
-static inline int
-ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			struct wpa_driver_associate_params *params)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s,
-					 u8 *ssid, size_t *len)
-{
-	return -1;
-}
-
-static inline void
-ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-			       size_t num_hw_features)
-{
-}
-
-static inline void
-ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		 struct ieee80211_rx_status *rx_status)
-{
-}
-
-static inline struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-	return NULL;
-}
-
-static inline int
-ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-			    const u8 *ies, size_t ies_len)
-{
-	return -1;
-}
-
-static inline int
-ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-			     const u8 *target_ap,
-			     const u8 *ies, size_t ies_len)
-{
-	return -1;
-}
-
-#endif /* CONFIG_CLIENT_MLME */
-
-#endif /* MLME_H */

Copied: vendor/wpa/2.0/wpa_supplicant/nfc_pw_token.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/nfc_pw_token.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/nfc_pw_token.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/nfc_pw_token.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,83 @@
+/*
+ * nfc_pw_token - Tool for building NFC password tokens for WPS
+ * Copyright (c) 2012, Jouni Malinen <j at 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 "crypto/random.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "wps_supplicant.h"
+
+
+static void print_bin(const char *title, const struct wpabuf *buf)
+{
+	size_t i, len;
+	const u8 *pos;
+
+	if (buf == NULL)
+		return;
+
+	printf("%s=", title);
+
+	pos = wpabuf_head(buf);
+	len = wpabuf_len(buf);
+	for (i = 0; i < len; i++)
+		printf("%02X", *pos++);
+
+	printf("\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct wpa_supplicant wpa_s;
+	int ret = -1;
+	struct wpabuf *buf = NULL, *ndef = NULL;
+	char txt[1000];
+
+	if (os_program_init())
+		return -1;
+	random_init(NULL);
+
+	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	wpa_s.conf = os_zalloc(sizeof(*wpa_s.conf));
+	if (wpa_s.conf == NULL)
+		goto fail;
+
+	buf = wpas_wps_nfc_token(&wpa_s, 0);
+	if (buf == NULL)
+		goto fail;
+
+	ndef = ndef_build_wifi(buf);
+	if (ndef == NULL)
+		goto fail;
+
+	wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(buf),
+				   wpabuf_len(buf));
+	printf("#WPS=%s\n", txt);
+
+	wpa_snprintf_hex_uppercase(txt, sizeof(txt), wpabuf_head(ndef),
+				   wpabuf_len(ndef));
+	printf("#NDEF=%s\n", txt);
+
+	printf("wps_nfc_dev_pw_id=%d\n", wpa_s.conf->wps_nfc_dev_pw_id);
+	print_bin("wps_nfc_dh_pubkey", wpa_s.conf->wps_nfc_dh_pubkey);
+	print_bin("wps_nfc_dh_privkey", wpa_s.conf->wps_nfc_dh_privkey);
+	print_bin("wps_nfc_dev_pw", wpa_s.conf->wps_nfc_dev_pw);
+
+	ret = 0;
+fail:
+	wpabuf_free(ndef);
+	wpabuf_free(buf);
+	wpa_config_free(wpa_s.conf);
+	random_deinit();
+	os_program_deinit();
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/notify.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/notify.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/notify.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,339 +0,0 @@
-/*
- * wpa_supplicant - Event notifications
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "common/wpa_ctrl.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "wps_supplicant.h"
-#include "dbus/dbus_common.h"
-#include "dbus/dbus_old.h"
-#include "dbus/dbus_new.h"
-#include "driver_i.h"
-#include "scan.h"
-#include "notify.h"
-
-int wpas_notify_supplicant_initialized(struct wpa_global *global)
-{
-#ifdef CONFIG_DBUS
-	if (global->params.dbus_ctrl_interface) {
-		global->dbus = wpas_dbus_init(global);
-		if (global->dbus == NULL)
-			return -1;
-	}
-#endif /* CONFIG_DBUS */
-
-	return 0;
-}
-
-
-void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
-{
-#ifdef CONFIG_DBUS
-	if (global->dbus)
-		wpas_dbus_deinit(global->dbus);
-#endif /* CONFIG_DBUS */
-}
-
-
-int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
-{
-	if (wpas_dbus_register_iface(wpa_s))
-		return -1;
-
-	if (wpas_dbus_register_interface(wpa_s))
-		return -1;
-
-	return 0;
-}
-
-
-void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
-{
-	/* unregister interface in old DBus ctrl iface */
-	wpas_dbus_unregister_iface(wpa_s);
-
-	/* unregister interface in new DBus ctrl iface */
-	wpas_dbus_unregister_interface(wpa_s);
-}
-
-
-void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
-			       enum wpa_states new_state,
-			       enum wpa_states old_state)
-{
-	/* notify the old DBus API */
-	wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
-						old_state);
-
-	/* notify the new DBus API */
-	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
-}
-
-
-void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
-{
-	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
-}
-
-
-void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
-{
-	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
-}
-
-
-void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
-{
-	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
-}
-
-
-void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
-					 struct wpa_ssid *ssid)
-{
-	wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
-}
-
-
-void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
-				  struct wpa_ssid *ssid)
-{
-	wpas_dbus_signal_network_selected(wpa_s, ssid->id);
-}
-
-
-void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
-{
-	/* notify the old DBus API */
-	wpa_supplicant_dbus_notify_scanning(wpa_s);
-
-	/* notify the new DBus API */
-	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING);
-}
-
-
-void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
-{
-	wpas_dbus_signal_scan_done(wpa_s, success);
-}
-
-
-void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-	/* notify the old DBus API */
-	wpa_supplicant_dbus_notify_scan_results(wpa_s);
-
-	wpas_wps_notify_scan_results(wpa_s);
-}
-
-
-void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
-				const struct wps_credential *cred)
-{
-#ifdef CONFIG_WPS
-	/* notify the old DBus API */
-	wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
-	/* notify the new DBus API */
-	wpas_dbus_signal_wps_cred(wpa_s, cred);
-#endif /* CONFIG_WPS */
-}
-
-
-void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
-			       struct wps_event_m2d *m2d)
-{
-#ifdef CONFIG_WPS
-	wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
-#endif /* CONFIG_WPS */
-}
-
-
-void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
-				struct wps_event_fail *fail)
-{
-#ifdef CONFIG_WPS
-	wpas_dbus_signal_wps_event_fail(wpa_s, fail);
-#endif /* CONFIG_WPS */
-}
-
-
-void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
-{
-#ifdef CONFIG_WPS
-	wpas_dbus_signal_wps_event_success(wpa_s);
-#endif /* CONFIG_WPS */
-}
-
-
-void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid)
-{
-	wpas_dbus_register_network(wpa_s, ssid);
-}
-
-
-void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
-				 struct wpa_ssid *ssid)
-{
-	wpas_dbus_unregister_network(wpa_s, ssid->id);
-}
-
-
-void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
-			   u8 bssid[], unsigned int id)
-{
-	wpas_dbus_register_bss(wpa_s, bssid, id);
-	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
-		     id, MAC2STR(bssid));
-}
-
-
-void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
-			     u8 bssid[], unsigned int id)
-{
-	wpas_dbus_unregister_bss(wpa_s, bssid, id);
-	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
-		     id, MAC2STR(bssid));
-}
-
-
-void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
-				  unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
-}
-
-
-void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
-				    unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
-					  id);
-}
-
-
-void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
-				     unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
-					  id);
-}
-
-
-void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
-				  unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
-}
-
-
-void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
-}
-
-
-void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
-}
-
-
-void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
-				 unsigned int id)
-{
-}
-
-
-void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
-}
-
-
-void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id)
-{
-	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
-}
-
-
-void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
-{
-	wpas_dbus_signal_blob_added(wpa_s, name);
-}
-
-
-void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
-{
-	wpas_dbus_signal_blob_removed(wpa_s, name);
-}
-
-
-void wpas_notify_debug_level_changed(struct wpa_global *global)
-{
-	wpas_dbus_signal_debug_level_changed(global);
-}
-
-
-void wpas_notify_debug_timestamp_changed(struct wpa_global *global)
-{
-	wpas_dbus_signal_debug_timestamp_changed(global);
-}
-
-
-void wpas_notify_debug_show_keys_changed(struct wpa_global *global)
-{
-	wpas_dbus_signal_debug_show_keys_changed(global);
-}
-
-
-void wpas_notify_suspend(struct wpa_global *global)
-{
-	struct wpa_supplicant *wpa_s;
-
-	os_get_time(&global->suspend_time);
-	wpa_printf(MSG_DEBUG, "System suspend notification");
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-		wpa_drv_suspend(wpa_s);
-}
-
-
-void wpas_notify_resume(struct wpa_global *global)
-{
-	struct os_time now;
-	int slept;
-	struct wpa_supplicant *wpa_s;
-
-	if (global->suspend_time.sec == 0)
-		slept = -1;
-	else {
-		os_get_time(&now);
-		slept = now.sec - global->suspend_time.sec;
-	}
-	wpa_printf(MSG_DEBUG, "System resume notification (slept %d seconds)",
-		   slept);
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		wpa_drv_resume(wpa_s);
-		if (wpa_s->wpa_state == WPA_DISCONNECTED)
-			wpa_supplicant_req_scan(wpa_s, 0, 100000);
-	}
-}

Copied: vendor/wpa/2.0/wpa_supplicant/notify.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/notify.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/notify.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/notify.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,630 @@
+/*
+ * wpa_supplicant - Event notifications
+ * Copyright (c) 2009-2010, Jouni Malinen <j at 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 "common/wpa_ctrl.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "dbus/dbus_common.h"
+#include "dbus/dbus_old.h"
+#include "dbus/dbus_new.h"
+#include "rsn_supp/wpa.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+#include "sme.h"
+#include "notify.h"
+
+int wpas_notify_supplicant_initialized(struct wpa_global *global)
+{
+#ifdef CONFIG_DBUS
+	if (global->params.dbus_ctrl_interface) {
+		global->dbus = wpas_dbus_init(global);
+		if (global->dbus == NULL)
+			return -1;
+	}
+#endif /* CONFIG_DBUS */
+
+	return 0;
+}
+
+
+void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
+{
+#ifdef CONFIG_DBUS
+	if (global->dbus)
+		wpas_dbus_deinit(global->dbus);
+#endif /* CONFIG_DBUS */
+}
+
+
+int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_dbus_register_iface(wpa_s))
+		return -1;
+
+	if (wpas_dbus_register_interface(wpa_s))
+		return -1;
+
+	return 0;
+}
+
+
+void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
+{
+	/* unregister interface in old DBus ctrl iface */
+	wpas_dbus_unregister_iface(wpa_s);
+
+	/* unregister interface in new DBus ctrl iface */
+	wpas_dbus_unregister_interface(wpa_s);
+}
+
+
+void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
+			       enum wpa_states new_state,
+			       enum wpa_states old_state)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
+						old_state);
+
+	/* notify the new DBus API */
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
+
+#ifdef CONFIG_P2P
+	if (new_state == WPA_COMPLETED)
+		wpas_p2p_notif_connected(wpa_s);
+	else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
+		wpas_p2p_notif_disconnected(wpa_s);
+#endif /* CONFIG_P2P */
+
+	sme_state_changed(wpa_s);
+
+#ifdef ANDROID
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+		     "id=%d state=%d BSSID=" MACSTR,
+		     wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+		     new_state, MAC2STR(wpa_s->pending_bssid));
+#endif /* ANDROID */
+}
+
+
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
+void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
+}
+
+
+void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
+}
+
+
+void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
+}
+
+
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
+}
+
+
+void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid)
+{
+	wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
+}
+
+
+void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid)
+{
+	wpas_dbus_signal_network_selected(wpa_s, ssid->id);
+}
+
+
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt)
+{
+	wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+}
+
+
+void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_scanning(wpa_s);
+
+	/* notify the new DBus API */
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING);
+}
+
+
+void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
+{
+	wpas_dbus_signal_scan_done(wpa_s, success);
+}
+
+
+void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_scan_results(wpa_s);
+
+	wpas_wps_notify_scan_results(wpa_s);
+}
+
+
+void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
+				const struct wps_credential *cred)
+{
+#ifdef CONFIG_WPS
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
+	/* notify the new DBus API */
+	wpas_dbus_signal_wps_cred(wpa_s, cred);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
+			       struct wps_event_m2d *m2d)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_fail(wpa_s, fail);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_success(wpa_s);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid)
+{
+	/*
+	 * Networks objects created during any P2P activities should not be
+	 * exposed out. They might/will confuse certain non-P2P aware
+	 * applications since these network objects won't behave like
+	 * regular ones.
+	 */
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_register_network(wpa_s, ssid);
+}
+
+
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+	wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+	wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid)
+{
+	if (wpa_s->wpa)
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_unregister_network(wpa_s, ssid->id);
+#ifdef CONFIG_P2P
+	wpas_p2p_network_removed(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
+			   u8 bssid[], unsigned int id)
+{
+	wpas_dbus_register_bss(wpa_s, bssid, id);
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
+		     id, MAC2STR(bssid));
+}
+
+
+void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
+			     u8 bssid[], unsigned int id)
+{
+	wpas_dbus_unregister_bss(wpa_s, bssid, id);
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
+		     id, MAC2STR(bssid));
+}
+
+
+void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
+}
+
+
+void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
+				    unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
+					  id);
+}
+
+
+void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
+				     unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
+					  id);
+}
+
+
+void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
+}
+
+
+void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
+}
+
+
+void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
+}
+
+
+void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
+}
+
+
+void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
+}
+
+
+void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
+{
+	wpas_dbus_signal_blob_added(wpa_s, name);
+}
+
+
+void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
+{
+	wpas_dbus_signal_blob_removed(wpa_s, name);
+}
+
+
+void wpas_notify_debug_level_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_level_changed(global);
+}
+
+
+void wpas_notify_debug_timestamp_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_timestamp_changed(global);
+}
+
+
+void wpas_notify_debug_show_keys_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_show_keys_changed(global);
+}
+
+
+void wpas_notify_suspend(struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+
+	os_get_time(&global->suspend_time);
+	wpa_printf(MSG_DEBUG, "System suspend notification");
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		wpa_drv_suspend(wpa_s);
+}
+
+
+void wpas_notify_resume(struct wpa_global *global)
+{
+	struct os_time now;
+	int slept;
+	struct wpa_supplicant *wpa_s;
+
+	if (global->suspend_time.sec == 0)
+		slept = -1;
+	else {
+		os_get_time(&now);
+		slept = now.sec - global->suspend_time.sec;
+	}
+	wpa_printf(MSG_DEBUG, "System resume notification (slept %d seconds)",
+		   slept);
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		wpa_drv_resume(wpa_s);
+		if (wpa_s->wpa_state == WPA_DISCONNECTED)
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+	}
+}
+
+
+#ifdef CONFIG_P2P
+
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr, int new_device)
+{
+	if (new_device) {
+		/* Create the new peer object */
+		wpas_dbus_register_peer(wpa_s, dev_addr);
+	}
+
+	/* Notify a new peer has been detected*/
+	wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr)
+{
+	wpas_dbus_unregister_peer(wpa_s, dev_addr);
+
+	/* Create signal on interface object*/
+	wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   const char *role)
+{
+	wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+	wpas_dbus_signal_p2p_group_removed(wpa_s, role);
+}
+
+
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				const u8 *src, u16 dev_passwd_id)
+{
+	wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+}
+
+
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res)
+{
+	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
+}
+
+
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+				       int status, const u8 *bssid)
+{
+	wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
+}
+
+
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				int freq, const u8 *sa, u8 dialog_token,
+				u16 update_indic, const u8 *tlvs,
+				size_t tlvs_len)
+{
+	wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					update_indic, tlvs, tlvs_len);
+}
+
+
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len)
+{
+	wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
+					 tlvs, tlvs_len);
+}
+
+
+/**
+ * wpas_notify_p2p_provision_discovery - Notification of provision discovery
+ * @dev_addr: Who sent the request or responded to our request.
+ * @request: Will be 1 if request, 0 for response.
+ * @status: Valid only in case of response (0 in case of success)
+ * @config_methods: WPS config methods
+ * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * This can be used to notify:
+ * - Requests or responses
+ * - Various config methods
+ * - Failure condition in case of response
+ */
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+	wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
+						 status, config_methods,
+						 generated_pin);
+}
+
+
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid, int network_id,
+				   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);
+}
+
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+	wpas_dbus_signal_p2p_wps_failed(wpa_s, fail);
+}
+
+#endif /* CONFIG_P2P */
+
+
+static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+					  const u8 *sta,
+					  const u8 *p2p_dev_addr)
+{
+#ifdef CONFIG_P2P
+	wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr);
+
+	/*
+	 * Register a group member object corresponding to this peer and
+	 * emit a PeerJoined signal. This will check if it really is a
+	 * P2P group.
+	 */
+	wpas_dbus_register_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-joined' signal on group object -- will also
+	 * check P2P itself.
+	 */
+	wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
+					    const u8 *sta)
+{
+#ifdef CONFIG_P2P
+	/*
+	 * Unregister a group member object corresponding to this peer
+	 * if this is a P2P group.
+	 */
+	wpas_dbus_unregister_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-disconnected' signal on group object if this
+	 * is a P2P group.
+	 */
+	wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr)
+{
+	if (authorized)
+		wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
+	else
+		wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
+}
+
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+			       const char *subject, const char *cert_hash,
+			       const struct wpabuf *cert)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+		"depth=%d subject='%s'%s%s",
+		depth, subject,
+		cert_hash ? " hash=" : "",
+		cert_hash ? cert_hash : "");
+
+	if (cert) {
+		char *cert_hex;
+		size_t len = wpabuf_len(cert) * 2 + 1;
+		cert_hex = os_malloc(len);
+		if (cert_hex) {
+			wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
+					 wpabuf_len(cert));
+			wpa_msg_ctrl(wpa_s, MSG_INFO,
+				     WPA_EVENT_EAP_PEER_CERT
+				     "depth=%d subject='%s' cert=%s",
+				     depth, subject, cert_hex);
+			os_free(cert_hex);
+		}
+	}
+
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
+						 cert_hash, cert);
+	/* notify the new DBus API */
+	wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+}
+
+
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+		      const u8 *addr, const u8 *dst, const u8 *bssid,
+		      const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+#ifdef CONFIG_AP
+	wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
+#endif /* CONFIG_AP */
+}
+
+
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+			    const char *parameter)
+{
+	wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/notify.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/notify.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/notify.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,81 +0,0 @@
-/*
- * wpa_supplicant - Event notifications
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef NOTIFY_H
-#define NOTIFY_H
-
-struct wps_credential;
-struct wps_event_m2d;
-struct wps_event_fail;
-
-int wpas_notify_supplicant_initialized(struct wpa_global *global);
-void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
-int wpas_notify_iface_added(struct wpa_supplicant *wpa_s);
-void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
-void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
-			       enum wpa_states new_state,
-			       enum wpa_states old_state);
-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);
-void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
-					 struct wpa_ssid *ssid);
-void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
-				  struct wpa_ssid *ssid);
-void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
-void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
-void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
-void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
-				const struct wps_credential *cred);
-void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
-			       struct wps_event_m2d *m2d);
-void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
-				struct wps_event_fail *fail);
-void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s);
-void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
-			       struct wpa_ssid *ssid);
-void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
-				 struct wpa_ssid *ssid);
-void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, u8 bssid[],
-			   unsigned int id);
-void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s, u8 bssid[],
-			     unsigned int id);
-void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
-				  unsigned int id);
-void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
-				    unsigned int id);
-void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
-				     unsigned int id);
-void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
-				  unsigned int id);
-void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id);
-void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id);
-void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
-				 unsigned int id);
-void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
-				 unsigned int id);
-void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
-				   unsigned int id);
-void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
-void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
-
-void wpas_notify_debug_level_changed(struct wpa_global *global);
-void wpas_notify_debug_timestamp_changed(struct wpa_global *global);
-void wpas_notify_debug_show_keys_changed(struct wpa_global *global);
-void wpas_notify_suspend(struct wpa_global *global);
-void wpas_notify_resume(struct wpa_global *global);
-
-#endif /* NOTIFY_H */

Copied: vendor/wpa/2.0/wpa_supplicant/notify.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/notify.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/notify.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/notify.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,131 @@
+/*
+ * wpa_supplicant - Event notifications
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NOTIFY_H
+#define NOTIFY_H
+
+#include "p2p/p2p.h"
+
+struct wps_credential;
+struct wps_event_m2d;
+struct wps_event_fail;
+
+int wpas_notify_supplicant_initialized(struct wpa_global *global);
+void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
+int wpas_notify_iface_added(struct wpa_supplicant *wpa_s);
+void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
+void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
+			       enum wpa_states new_state,
+			       enum wpa_states old_state);
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_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);
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid);
+void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid);
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt);
+void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
+void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
+void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
+void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
+				const struct wps_credential *cred);
+void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
+			       struct wps_event_m2d *m2d);
+void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail);
+void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s);
+void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid);
+void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid);
+void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, u8 bssid[],
+			   unsigned int id);
+void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s, u8 bssid[],
+			     unsigned int id);
+void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id);
+void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
+				    unsigned int id);
+void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
+				     unsigned int id);
+void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id);
+void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id);
+void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id);
+void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
+void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
+
+void wpas_notify_debug_level_changed(struct wpa_global *global);
+void wpas_notify_debug_timestamp_changed(struct wpa_global *global);
+void wpas_notify_debug_show_keys_changed(struct wpa_global *global);
+void wpas_notify_suspend(struct wpa_global *global);
+void wpas_notify_resume(struct wpa_global *global);
+
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr);
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr, int new_device);
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr);
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   const char *role);
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				const u8 *src, u16 dev_passwd_id);
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res);
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+				       int status, const u8 *bssid);
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				int freq, const u8 *sa, u8 dialog_token,
+				u16 update_indic, const u8 *tlvs,
+				size_t tlvs_len);
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len);
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 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,
+				   int client);
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid);
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail);
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+			       const char *subject, const char *cert_hash,
+			       const struct wpabuf *cert);
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+		      const u8 *addr, const u8 *dst, const u8 *bssid,
+		      const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+			    const char *parameter);
+
+#endif /* NOTIFY_H */

Copied: vendor/wpa/2.0/wpa_supplicant/offchannel.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/offchannel.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/offchannel.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/offchannel.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,397 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+
+
+
+static struct wpa_supplicant *
+wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
+{
+	struct wpa_supplicant *iface;
+
+	if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+		return wpa_s;
+
+	/*
+	 * Try to find a group interface that matches with the source address.
+	 */
+	iface = wpa_s->global->ifaces;
+	while (iface) {
+		if (os_memcmp(wpa_s->pending_action_src,
+			      iface->own_addr, ETH_ALEN) == 0)
+			break;
+		iface = iface->next;
+	}
+	if (iface) {
+		wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
+			   "instead of interface %s for Action TX",
+			   iface->ifname, wpa_s->ifname);
+		return iface;
+	}
+
+	return wpa_s;
+}
+
+
+static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_supplicant *iface;
+	int res;
+	int without_roc;
+
+	without_roc = wpa_s->pending_action_without_roc;
+	wpa_s->pending_action_without_roc = 0;
+	wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
+		   "(without_roc=%d pending_action_tx=%p)",
+		   without_roc, wpa_s->pending_action_tx);
+
+	if (wpa_s->pending_action_tx == NULL)
+		return;
+
+	/*
+	 * This call is likely going to be on the P2P device instance if the
+	 * driver uses a separate interface for that purpose. However, some
+	 * Action frames are actually sent within a P2P Group and when that is
+	 * the case, we need to follow power saving (e.g., GO buffering the
+	 * frame for a client in PS mode or a client following the advertised
+	 * NoA from its GO). To make that easier for the driver, select the
+	 * correct group interface here.
+	 */
+	iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+
+	if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
+	    wpa_s->pending_action_freq != 0 &&
+	    wpa_s->pending_action_freq != iface->assoc_freq) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
+			   "waiting for another freq=%u (off_channel_freq=%u "
+			   "assoc_freq=%u)",
+			   wpa_s->pending_action_freq,
+			   wpa_s->off_channel_freq,
+			   iface->assoc_freq);
+		if (without_roc && wpa_s->off_channel_freq == 0) {
+			/*
+			 * We may get here if wpas_send_action() found us to be
+			 * on the correct channel, but remain-on-channel cancel
+			 * event was received before getting here.
+			 */
+			wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
+				   "remain-on-channel to send Action frame");
+			if (wpa_drv_remain_on_channel(
+				    wpa_s, wpa_s->pending_action_freq, 200) <
+			    0) {
+				wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
+					   "request driver to remain on "
+					   "channel (%u MHz) for Action Frame "
+					   "TX", wpa_s->pending_action_freq);
+			} else {
+				wpa_s->off_channel_freq = 0;
+				wpa_s->roc_waiting_drv_freq =
+					wpa_s->pending_action_freq;
+			}
+		}
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
+		   MACSTR " using interface %s",
+		   MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+	res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
+				  wpa_s->pending_action_dst,
+				  wpa_s->pending_action_src,
+				  wpa_s->pending_action_bssid,
+				  wpabuf_head(wpa_s->pending_action_tx),
+				  wpabuf_len(wpa_s->pending_action_tx),
+				  wpa_s->pending_action_no_cck);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
+			   "pending Action frame");
+		/*
+		 * Use fake TX status event to allow state machines to
+		 * continue.
+		 */
+		offchannel_send_action_tx_status(
+			wpa_s, wpa_s->pending_action_dst,
+			wpabuf_head(wpa_s->pending_action_tx),
+			wpabuf_len(wpa_s->pending_action_tx),
+			OFFCHANNEL_SEND_ACTION_FAILED);
+	}
+}
+
+
+/**
+ * offchannel_send_action_tx_status - TX status callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dst: Destination MAC address of the transmitted Action frame
+ * @data: Transmitted frame payload
+ * @data_len: Length of @data in bytes
+ * @result: TX status
+ *
+ * This function is called whenever the driver indicates a TX status event for
+ * a frame sent by offchannel_send_action() using wpa_drv_send_action().
+ */
+void offchannel_send_action_tx_status(
+	struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+	size_t data_len, enum offchannel_send_action_result result)
+{
+	if (wpa_s->pending_action_tx == NULL) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+			   "no pending operation");
+		return;
+	}
+
+	if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+			   "unknown destination address");
+		return;
+	}
+
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+
+	wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
+		   result, wpa_s->pending_action_tx_status_cb);
+
+	if (wpa_s->pending_action_tx_status_cb) {
+		wpa_s->pending_action_tx_status_cb(
+			wpa_s, wpa_s->pending_action_freq,
+			wpa_s->pending_action_dst, wpa_s->pending_action_src,
+			wpa_s->pending_action_bssid,
+			data, data_len, result);
+	}
+}
+
+
+/**
+ * offchannel_send_action - Request off-channel Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: The frequency in MHz indicating the channel on which the frame is to
+ *	transmitted or 0 for the current channel (only if associated)
+ * @dst: Action frame destination MAC address
+ * @src: Action frame source MAC address
+ * @bssid: Action frame BSSID
+ * @buf: Frame to transmit starting from the Category field
+ * @len: Length of @buf in bytes
+ * @wait_time: Wait time for response in milliseconds
+ * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @no_cck: Whether CCK rates are to be disallowed for TX rate selection
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to request an Action frame to be transmitted on the
+ * current operating channel or on another channel (off-channel). The actual
+ * frame transmission will be delayed until the driver is ready on the specified
+ * channel. The @wait_time parameter can be used to request the driver to remain
+ * awake on the channel to wait for a response.
+ */
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *buf, size_t len, unsigned int wait_time,
+			   void (*tx_cb)(struct wpa_supplicant *wpa_s,
+					 unsigned int freq, const u8 *dst,
+					 const u8 *src, const u8 *bssid,
+					 const u8 *data, size_t data_len,
+					 enum offchannel_send_action_result
+					 result),
+			   int no_cck)
+{
+	wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
+		   MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
+		   freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+		   (int) len);
+
+	wpa_s->pending_action_tx_status_cb = tx_cb;
+
+	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));
+		wpabuf_free(wpa_s->pending_action_tx);
+	}
+	wpa_s->pending_action_tx = wpabuf_alloc(len);
+	if (wpa_s->pending_action_tx == NULL) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
+			   "frame TX buffer (len=%llu)",
+			   (unsigned long long) len);
+		return -1;
+	}
+	wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
+	os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
+	os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
+	os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
+	wpa_s->pending_action_freq = freq;
+	wpa_s->pending_action_no_cck = no_cck;
+
+	if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+		struct wpa_supplicant *iface;
+
+		iface = wpas_get_tx_interface(wpa_s,
+					      wpa_s->pending_action_src);
+		wpa_s->action_tx_wait_time = wait_time;
+
+		return wpa_drv_send_action(
+			iface, wpa_s->pending_action_freq,
+			wait_time, wpa_s->pending_action_dst,
+			wpa_s->pending_action_src, wpa_s->pending_action_bssid,
+			wpabuf_head(wpa_s->pending_action_tx),
+			wpabuf_len(wpa_s->pending_action_tx),
+			wpa_s->pending_action_no_cck);
+	}
+
+	if (freq) {
+		struct wpa_supplicant *tx_iface;
+		tx_iface = wpas_get_tx_interface(wpa_s, src);
+		if (tx_iface->assoc_freq == freq) {
+			wpa_printf(MSG_DEBUG, "Off-channel: Already on "
+				   "requested channel (TX interface operating "
+				   "channel)");
+			freq = 0;
+		}
+	}
+
+	if (wpa_s->off_channel_freq == freq || freq == 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
+			   "channel; send Action frame immediately");
+		/* TODO: Would there ever be need to extend the current
+		 * duration on the channel? */
+		wpa_s->pending_action_without_roc = 1;
+		eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+		eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
+		return 0;
+	}
+	wpa_s->pending_action_without_roc = 0;
+
+	if (wpa_s->roc_waiting_drv_freq == freq) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
+			   "driver to get to frequency %u MHz; continue "
+			   "waiting to send the Action frame", freq);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
+		   "transmitted once the driver gets to the requested "
+		   "channel");
+	if (wait_time > wpa_s->max_remain_on_chan)
+		wait_time = wpa_s->max_remain_on_chan;
+	if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
+			   "to remain on channel (%u MHz) for Action "
+			   "Frame TX", freq);
+		return -1;
+	}
+	wpa_s->off_channel_freq = 0;
+	wpa_s->roc_waiting_drv_freq = freq;
+
+	return 0;
+}
+
+
+/**
+ * offchannel_send_send_action_done - Notify completion of Action frame sequence
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function can be used to cancel a wait for additional response frames on
+ * the channel that was used with offchannel_send_action().
+ */
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
+		   "notification");
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
+	    wpa_s->action_tx_wait_time)
+		wpa_drv_send_action_cancel_wait(wpa_s);
+
+	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+		wpa_drv_cancel_remain_on_channel(wpa_s);
+		wpa_s->off_channel_freq = 0;
+		wpa_s->roc_waiting_drv_freq = 0;
+	}
+}
+
+
+/**
+ * offchannel_remain_on_channel_cb - Remain-on-channel callback function
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ * @duration: Duration of the remain-on-channel operation in milliseconds
+ *
+ * This function is called whenever the driver notifies beginning of a
+ * remain-on-channel operation.
+ */
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, unsigned int duration)
+{
+	wpa_s->roc_waiting_drv_freq = 0;
+	wpa_s->off_channel_freq = freq;
+	wpas_send_action_cb(wpa_s, NULL);
+}
+
+
+/**
+ * offchannel_cancel_remain_on_channel_cb - Remain-on-channel stopped callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ *
+ * This function is called whenever the driver notifies termination of a
+ * remain-on-channel operation.
+ */
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					    unsigned int freq)
+{
+	wpa_s->off_channel_freq = 0;
+}
+
+
+/**
+ * offchannel_pending_action_tx - Check whether there is a pending Action TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to pending frame or %NULL if no pending operation
+ *
+ * This function can be used to check whether there is a pending Action frame TX
+ * operation. The returned pointer should be used only for checking whether it
+ * is %NULL (no pending frame) or to print the pointer value in debug
+ * information (i.e., the pointer should not be dereferenced).
+ */
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->pending_action_tx;
+}
+
+
+/**
+ * offchannel_clear_pending_action_tx - Clear pending Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+}
+
+
+/**
+ * offchannel_deinit - Deinit off-channel operations
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to free up any allocated resources for off-channel
+ * operations.
+ */
+void offchannel_deinit(struct wpa_supplicant *wpa_s)
+{
+	offchannel_clear_pending_action_tx(wpa_s);
+	eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+}

Copied: vendor/wpa/2.0/wpa_supplicant/offchannel.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/offchannel.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/offchannel.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/offchannel.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,35 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OFFCHANNEL_H
+#define OFFCHANNEL_H
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *buf, size_t len, unsigned int wait_time,
+			   void (*tx_cb)(struct wpa_supplicant *wpa_s,
+					 unsigned int freq, const u8 *dst,
+					 const u8 *src, const u8 *bssid,
+					 const u8 *data, size_t data_len,
+					 enum offchannel_send_action_result
+					 result),
+			   int no_cck);
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s);
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, unsigned int duration);
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					    unsigned int freq);
+void offchannel_deinit(struct wpa_supplicant *wpa_s);
+void offchannel_send_action_tx_status(
+	struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+	size_t data_len, enum offchannel_send_action_result result);
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s);
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s);
+
+#endif /* OFFCHANNEL_H */

Copied: vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/p2p_supplicant.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,5484 @@
+/*
+ * wpa_supplicant - P2P
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "wps/wps_i.h"
+#include "p2p/p2p.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/p2p_hostapd.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ap.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "notify.h"
+#include "scan.h"
+#include "bss.h"
+#include "offchannel.h"
+#include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+
+
+/*
+ * How many times to try to scan to find the GO before giving up on join
+ * request.
+ */
+#define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
+
+#define P2P_AUTO_PD_SCAN_ATTEMPTS 5
+
+#ifndef P2P_MAX_CLIENT_IDLE
+/*
+ * How many seconds to try to reconnect to the GO when connection in P2P client
+ * role has been lost.
+ */
+#define P2P_MAX_CLIENT_IDLE 10
+#endif /* P2P_MAX_CLIENT_IDLE */
+
+#ifndef P2P_MAX_INITIAL_CONN_WAIT
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+
+#ifndef P2P_CONCURRENT_SEARCH_DELAY
+#define P2P_CONCURRENT_SEARCH_DELAY 500
+#endif /* P2P_CONCURRENT_SEARCH_DELAY */
+
+enum p2p_group_removal_reason {
+	P2P_GROUP_REMOVAL_UNKNOWN,
+	P2P_GROUP_REMOVAL_SILENT,
+	P2P_GROUP_REMOVAL_FORMATION_FAILED,
+	P2P_GROUP_REMOVAL_REQUESTED,
+	P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
+	P2P_GROUP_REMOVAL_UNAVAILABLE,
+	P2P_GROUP_REMOVAL_GO_ENDING_SESSION
+};
+
+
+static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
+static struct wpa_supplicant *
+wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
+			 int go);
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq);
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx);
+static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
+			 const u8 *dev_addr, enum p2p_wps_method wps_method,
+			 int auto_join);
+static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+					int group_added);
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+
+
+static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
+				      struct wpa_scan_results *scan_res)
+{
+	size_t i;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS)",
+		   (int) scan_res->num);
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
+					 bss->freq, bss->age, bss->level,
+					 (const u8 *) (bss + 1),
+					 bss->ie_len) > 0)
+			break;
+	}
+
+	p2p_scan_res_handled(wpa_s->global->p2p);
+}
+
+
+static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
+			 unsigned int num_req_dev_types,
+			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_supplicant *ifs;
+	struct wpa_driver_scan_params params;
+	int ret;
+	struct wpabuf *wps_ie, *ies;
+	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+	size_t ielen;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs->sta_scan_pending &&
+		    wpas_p2p_in_progress(wpa_s) == 2) {
+			wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
+				   "pending station mode scan to be "
+				   "completed on interface %s", ifs->ifname);
+			wpa_s->global->p2p_cb_on_scan_complete = 1;
+			wpa_supplicant_req_scan(ifs, 0, 0);
+			return 1;
+		}
+	}
+
+	os_memset(&params, 0, sizeof(params));
+
+	/* P2P Wildcard SSID */
+	params.num_ssids = 1;
+	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+	wpa_s->wps->dev.p2p = 1;
+	wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
+					wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
+					num_req_dev_types, req_dev_types);
+	if (wps_ie == NULL)
+		return -1;
+
+	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);
+		return -1;
+	}
+	wpabuf_put_buf(ies, wps_ie);
+	wpabuf_free(wps_ie);
+
+	p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
+
+	params.p2p_probe = 1;
+	params.extra_ies = wpabuf_head(ies);
+	params.extra_ies_len = wpabuf_len(ies);
+
+	switch (type) {
+	case P2P_SCAN_SOCIAL:
+		params.freqs = social_channels;
+		break;
+	case P2P_SCAN_FULL:
+		break;
+	case P2P_SCAN_SOCIAL_PLUS_ONE:
+		social_channels[3] = freq;
+		params.freqs = social_channels;
+		break;
+	}
+
+	ret = wpa_drv_scan(wpa_s, &params);
+
+	wpabuf_free(ies);
+
+	if (ret) {
+		for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+			if (ifs->scanning ||
+			    ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
+				wpa_s->global->p2p_cb_on_scan_complete = 1;
+				ret = 1;
+				break;
+			}
+		}
+	} else
+		wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+
+	return ret;
+}
+
+
+static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
+{
+	switch (p2p_group_interface) {
+	case P2P_GROUP_INTERFACE_PENDING:
+		return WPA_IF_P2P_GROUP;
+	case P2P_GROUP_INTERFACE_GO:
+		return WPA_IF_P2P_GO;
+	case P2P_GROUP_INTERFACE_CLIENT:
+		return WPA_IF_P2P_CLIENT;
+	}
+
+	return WPA_IF_P2P_GROUP;
+}
+
+
+static struct wpa_supplicant * wpas_get_p2p_group(struct wpa_supplicant *wpa_s,
+						  const u8 *ssid,
+						  size_t ssid_len, int *go)
+{
+	struct wpa_ssid *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 != 0 || !s->p2p_group ||
+			    s->ssid_len != ssid_len ||
+			    os_memcmp(ssid, s->ssid, ssid_len) != 0)
+				continue;
+			if (s->mode == WPAS_MODE_P2P_GO &&
+			    s != wpa_s->current_ssid)
+				continue;
+			if (go)
+				*go = s->mode == WPAS_MODE_P2P_GO;
+			return wpa_s;
+		}
+	}
+
+	return NULL;
+}
+
+
+static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
+				 enum p2p_group_removal_reason removal_reason)
+{
+	struct wpa_ssid *ssid;
+	char *gtype;
+	const char *reason;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL) {
+		/*
+		 * The current SSID was not known, but there may still be a
+		 * pending P2P group interface waiting for provisioning or a
+		 * P2P group that is trying to reconnect.
+		 */
+		ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			if (ssid->p2p_group && ssid->disabled != 2)
+				break;
+			ssid = ssid->next;
+		}
+		if (ssid == NULL &&
+			wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
+		{
+			wpa_printf(MSG_ERROR, "P2P: P2P group interface "
+				   "not found");
+			return -1;
+		}
+	}
+	if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
+		gtype = "GO";
+	else if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
+		 (ssid && ssid->mode == WPAS_MODE_INFRA)) {
+		wpa_s->reassociate = 0;
+		wpa_s->disconnected = 1;
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		gtype = "client";
+	} else
+		gtype = "GO";
+	if (wpa_s->cross_connect_in_use) {
+		wpa_s->cross_connect_in_use = 0;
+		wpa_msg(wpa_s->parent, MSG_INFO,
+			P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+			wpa_s->ifname, wpa_s->cross_connect_uplink);
+	}
+	switch (removal_reason) {
+	case P2P_GROUP_REMOVAL_REQUESTED:
+		reason = " reason=REQUESTED";
+		break;
+	case P2P_GROUP_REMOVAL_FORMATION_FAILED:
+		reason = " reason=FORMATION_FAILED";
+		break;
+	case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
+		reason = " reason=IDLE";
+		break;
+	case P2P_GROUP_REMOVAL_UNAVAILABLE:
+		reason = " reason=UNAVAILABLE";
+		break;
+	case P2P_GROUP_REMOVAL_GO_ENDING_SESSION:
+		reason = " reason=GO_ENDING_SESSION";
+		break;
+	default:
+		reason = "";
+		break;
+	}
+	if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
+		wpa_msg(wpa_s->parent, 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 (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
+		wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
+
+	if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+		struct wpa_global *global;
+		char *ifname;
+		enum wpa_driver_if_type type;
+		wpa_printf(MSG_DEBUG, "P2P: Remove group interface %s",
+			wpa_s->ifname);
+		global = wpa_s->global;
+		ifname = os_strdup(wpa_s->ifname);
+		type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+		wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+		wpa_s = global->ifaces;
+		if (wpa_s && ifname)
+			wpa_drv_if_remove(wpa_s, type, ifname);
+		os_free(ifname);
+		return 1;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
+	if (ssid && (ssid->p2p_group ||
+		     ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION ||
+		     (ssid->key_mgmt & WPA_KEY_MGMT_WPS))) {
+		int id = ssid->id;
+		if (ssid == wpa_s->current_ssid) {
+			wpa_sm_set_config(wpa_s->wpa, NULL);
+			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+			wpa_s->current_ssid = NULL;
+		}
+		/*
+		 * Networks objects created during any P2P activities are not
+		 * exposed out as they might/will confuse certain non-P2P aware
+		 * applications since these network objects won't behave like
+		 * regular ones.
+		 *
+		 * Likewise, we don't send out network removed signals for such
+		 * network objects.
+		 */
+		wpa_config_remove_network(wpa_s->conf, id);
+		wpa_supplicant_clear_status(wpa_s);
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_s->sta_scan_pending = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
+			   "found");
+	}
+	if (wpa_s->ap_iface)
+		wpa_supplicant_ap_deinit(wpa_s);
+	else
+		wpa_drv_deinit_p2p_cli(wpa_s);
+
+	return 0;
+}
+
+
+static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s,
+				     u8 *go_dev_addr,
+				     const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	const u8 *bssid;
+	struct wpabuf *p2p;
+	u8 group_capab;
+	const u8 *addr;
+
+	if (wpa_s->go_params)
+		bssid = wpa_s->go_params->peer_interface_addr;
+	else
+		bssid = wpa_s->bssid;
+
+	bss = wpa_bss_get(wpa_s, bssid, ssid, ssid_len);
+	if (bss == NULL) {
+		u8 iface_addr[ETH_ALEN];
+		if (p2p_get_interface_addr(wpa_s->global->p2p, bssid,
+					   iface_addr) == 0)
+			bss = wpa_bss_get(wpa_s, iface_addr, ssid, ssid_len);
+	}
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
+			   "group is persistent - BSS " MACSTR " not found",
+			   MAC2STR(bssid));
+		return 0;
+	}
+
+	p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+	if (p2p == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Could not figure out whether "
+			   "group is persistent - BSS " MACSTR
+			   " did not include P2P IE", MAC2STR(bssid));
+		wpa_hexdump(MSG_DEBUG, "P2P: Probe Response IEs",
+			    (u8 *) (bss + 1), bss->ie_len);
+		wpa_hexdump(MSG_DEBUG, "P2P: Beacon IEs",
+			    ((u8 *) bss + 1) + bss->ie_len,
+			    bss->beacon_ie_len);
+		return 0;
+	}
+
+	group_capab = p2p_get_group_capab(p2p);
+	addr = p2p_get_go_dev_addr(p2p);
+	wpa_printf(MSG_DEBUG, "P2P: Checking whether group is persistent: "
+		   "group_capab=0x%x", group_capab);
+	if (addr) {
+		os_memcpy(go_dev_addr, addr, ETH_ALEN);
+		wpa_printf(MSG_DEBUG, "P2P: GO Device Address " MACSTR,
+			   MAC2STR(addr));
+	} else
+		os_memset(go_dev_addr, 0, ETH_ALEN);
+	wpabuf_free(p2p);
+
+	wpa_printf(MSG_DEBUG, "P2P: BSS " MACSTR " group_capab=0x%x "
+		   "go_dev_addr=" MACSTR,
+		   MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
+
+	return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+}
+
+
+static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
+					   struct wpa_ssid *ssid,
+					   const u8 *go_dev_addr)
+{
+	struct wpa_ssid *s;
+	int changed = 0;
+
+	wpa_printf(MSG_DEBUG, "P2P: Storing credentials for a persistent "
+		   "group (GO Dev Addr " MACSTR ")", MAC2STR(go_dev_addr));
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled == 2 &&
+		    os_memcmp(go_dev_addr, s->bssid, ETH_ALEN) == 0 &&
+		    s->ssid_len == ssid->ssid_len &&
+		    os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0)
+			break;
+	}
+
+	if (s) {
+		wpa_printf(MSG_DEBUG, "P2P: Update existing persistent group "
+			   "entry");
+		if (ssid->passphrase && !s->passphrase)
+			changed = 1;
+		else if (ssid->passphrase && s->passphrase &&
+			 os_strcmp(ssid->passphrase, s->passphrase) != 0)
+			changed = 1;
+	} else {
+		wpa_printf(MSG_DEBUG, "P2P: Create a new persistent group "
+			   "entry");
+		changed = 1;
+		s = wpa_config_add_network(wpa_s->conf);
+		if (s == NULL)
+			return -1;
+
+		/*
+		 * Instead of network_added we emit persistent_group_added
+		 * notification. Also to keep the defense checks in
+		 * persistent_group obj registration method, we set the
+		 * relevant flags in s to designate it as a persistent group.
+		 */
+		s->p2p_group = 1;
+		s->p2p_persistent_group = 1;
+		wpas_notify_persistent_group_added(wpa_s, s);
+		wpa_config_set_network_defaults(s);
+	}
+
+	s->p2p_group = 1;
+	s->p2p_persistent_group = 1;
+	s->disabled = 2;
+	s->bssid_set = 1;
+	os_memcpy(s->bssid, go_dev_addr, ETH_ALEN);
+	s->mode = ssid->mode;
+	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->export_keys = 1;
+	if (ssid->passphrase) {
+		os_free(s->passphrase);
+		s->passphrase = os_strdup(ssid->passphrase);
+	}
+	if (ssid->psk_set) {
+		s->psk_set = 1;
+		os_memcpy(s->psk, ssid->psk, 32);
+	}
+	if (s->passphrase && !s->psk_set)
+		wpa_config_update_psk(s);
+	if (s->ssid == NULL || s->ssid_len < ssid->ssid_len) {
+		os_free(s->ssid);
+		s->ssid = os_malloc(ssid->ssid_len);
+	}
+	if (s->ssid) {
+		s->ssid_len = ssid->ssid_len;
+		os_memcpy(s->ssid, ssid->ssid, s->ssid_len);
+	}
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (changed && wpa_s->conf->update_config &&
+	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+	}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+	return s->id;
+}
+
+
+static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
+						 const u8 *addr)
+{
+	struct wpa_ssid *ssid, *s;
+	u8 *n;
+	size_t i;
+	int found = 0;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+	    !ssid->p2p_persistent_group)
+		return;
+
+	for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+		if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
+			continue;
+
+		if (s->ssid_len == ssid->ssid_len &&
+		    os_memcmp(s->ssid, ssid->ssid, s->ssid_len) == 0)
+			break;
+	}
+
+	if (s == NULL)
+		return;
+
+	for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
+		if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+			      ETH_ALEN) != 0)
+			continue;
+
+		if (i == s->num_p2p_clients - 1)
+			return; /* already the most recent entry */
+
+		/* move the entry to mark it most recent */
+		os_memmove(s->p2p_client_list + i * ETH_ALEN,
+			   s->p2p_client_list + (i + 1) * ETH_ALEN,
+			   (s->num_p2p_clients - i - 1) * ETH_ALEN);
+		os_memcpy(s->p2p_client_list +
+			  (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+		found = 1;
+		break;
+	}
+
+	if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
+		n = os_realloc_array(s->p2p_client_list,
+				     s->num_p2p_clients + 1, ETH_ALEN);
+		if (n == NULL)
+			return;
+		os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+		s->p2p_client_list = n;
+		s->num_p2p_clients++;
+	} else if (!found) {
+		/* Not enough room for an additional entry - drop the oldest
+		 * entry */
+		os_memmove(s->p2p_client_list,
+			   s->p2p_client_list + ETH_ALEN,
+			   (s->num_p2p_clients - 1) * ETH_ALEN);
+		os_memcpy(s->p2p_client_list +
+			  (s->num_p2p_clients - 1) * ETH_ALEN,
+			  addr, ETH_ALEN);
+	}
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->parent->conf->update_config &&
+	    wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+		wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
+					   int success)
+{
+	struct wpa_ssid *ssid;
+	const char *ssid_txt;
+	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
+	 * to use the group interface if a new interface was created for the
+	 * group.
+	 */
+	if (wpa_s->global->p2p_group_formation)
+		wpa_s = wpa_s->global->p2p_group_formation;
+	wpa_s->global->p2p_group_formation = NULL;
+	wpa_s->p2p_in_provisioning = 0;
+
+	if (!success) {
+		wpa_msg(wpa_s->parent, MSG_INFO,
+			P2P_EVENT_GROUP_FORMATION_FAILURE);
+		wpas_p2p_group_delete(wpa_s,
+				      P2P_GROUP_REMOVAL_FORMATION_FAILED);
+		return;
+	}
+
+	wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_FORMATION_SUCCESS);
+
+	ssid = wpa_s->current_ssid;
+	if (ssid && ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+		ssid->mode = WPAS_MODE_P2P_GO;
+		p2p_group_notif_formation_done(wpa_s->p2p_group);
+		wpa_supplicant_ap_mac_addr_filter(wpa_s, NULL);
+	}
+
+	persistent = 0;
+	if (ssid) {
+		ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+		client = ssid->mode == WPAS_MODE_INFRA;
+		if (ssid->mode == WPAS_MODE_P2P_GO) {
+			persistent = ssid->p2p_persistent_group;
+			os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr,
+				  ETH_ALEN);
+		} else
+			persistent = wpas_p2p_persistent_group(wpa_s,
+							       go_dev_addr,
+							       ssid->ssid,
+							       ssid->ssid_len);
+	} else {
+		ssid_txt = "";
+		client = wpa_s->p2p_group_interface ==
+			P2P_GROUP_INTERFACE_CLIENT;
+		os_memset(go_dev_addr, 0, ETH_ALEN);
+	}
+
+	wpa_s->show_group_started = 0;
+	if (client) {
+		/*
+		 * Indicate event only after successfully completed 4-way
+		 * handshake, i.e., when the interface is ready for data
+		 * packets.
+		 */
+		wpa_s->show_group_started = 1;
+	} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
+		char psk[65];
+		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
+		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			"%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
+			"%s",
+			wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+			MAC2STR(go_dev_addr),
+			persistent ? " [PERSISTENT]" : "");
+		wpas_p2p_cross_connect_setup(wpa_s);
+		wpas_p2p_set_group_idle_timeout(wpa_s);
+	} else {
+		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+			"go_dev_addr=" MACSTR "%s",
+			wpa_s->ifname, ssid_txt, ssid ? ssid->frequency : 0,
+			ssid && ssid->passphrase ? ssid->passphrase : "",
+			MAC2STR(go_dev_addr),
+			persistent ? " [PERSISTENT]" : "");
+		wpas_p2p_cross_connect_setup(wpa_s);
+		wpas_p2p_set_group_idle_timeout(wpa_s);
+	}
+
+	if (persistent)
+		network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
+							     ssid, go_dev_addr);
+	if (network_id < 0 && ssid)
+		network_id = ssid->id;
+	if (!client)
+		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+}
+
+
+static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
+					   unsigned int freq,
+					   const u8 *dst, const u8 *src,
+					   const u8 *bssid,
+					   const u8 *data, size_t data_len,
+					   enum offchannel_send_action_result
+					   result)
+{
+	enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
+
+	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+		return;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return;
+
+	switch (result) {
+	case OFFCHANNEL_SEND_ACTION_SUCCESS:
+		res = P2P_SEND_ACTION_SUCCESS;
+		break;
+	case OFFCHANNEL_SEND_ACTION_NO_ACK:
+		res = P2P_SEND_ACTION_NO_ACK;
+		break;
+	case OFFCHANNEL_SEND_ACTION_FAILED:
+		res = P2P_SEND_ACTION_FAILED;
+		break;
+	}
+
+	p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
+
+	if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
+	    wpa_s->pending_pd_before_join &&
+	    (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+	     os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+	    wpa_s->p2p_fallback_to_go_neg) {
+		wpa_s->pending_pd_before_join = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+			"during p2p_connect-auto");
+		wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+		return;
+	}
+}
+
+
+static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
+			    const u8 *src, const u8 *bssid, const u8 *buf,
+			    size_t len, unsigned int wait_time)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
+				      wait_time,
+				      wpas_p2p_send_action_tx_status, 1);
+}
+
+
+static void wpas_send_action_done(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	offchannel_send_action_done(wpa_s);
+}
+
+
+static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
+				    struct p2p_go_neg_results *params)
+{
+	if (wpa_s->go_params == NULL) {
+		wpa_s->go_params = os_malloc(sizeof(*params));
+		if (wpa_s->go_params == NULL)
+			return -1;
+	}
+	os_memcpy(wpa_s->go_params, params, sizeof(*params));
+	return 0;
+}
+
+
+static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
+				    struct p2p_go_neg_results *res)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
+		   MAC2STR(res->peer_interface_addr));
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
+			  res->ssid, res->ssid_len);
+	wpa_supplicant_ap_deinit(wpa_s);
+	wpas_copy_go_neg_results(wpa_s, res);
+	if (res->wps_method == WPS_PBC)
+		wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+	else {
+		u16 dev_pw_id = DEV_PW_DEFAULT;
+		if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
+			dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
+		wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
+				   wpa_s->p2p_pin, 1, dev_pw_id);
+	}
+}
+
+
+static void p2p_go_configured(void *ctx, void *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct p2p_go_neg_results *params = data;
+	struct wpa_ssid *ssid;
+	int network_id = -1;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
+		wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
+		if (wpa_s->global->p2p_group_formation == wpa_s)
+			wpa_s->global->p2p_group_formation = NULL;
+		if (os_strlen(params->passphrase) > 0) {
+			wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+				"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+				"go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+				ssid->frequency, params->passphrase,
+				MAC2STR(wpa_s->global->p2p_dev_addr),
+				params->persistent_group ? " [PERSISTENT]" :
+				"");
+		} else {
+			char psk[65];
+			wpa_snprintf_hex(psk, sizeof(psk), params->psk,
+					 sizeof(params->psk));
+			wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+				"%s GO ssid=\"%s\" freq=%d psk=%s "
+				"go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+				ssid->frequency, psk,
+				MAC2STR(wpa_s->global->p2p_dev_addr),
+				params->persistent_group ? " [PERSISTENT]" :
+				"");
+		}
+
+		if (params->persistent_group)
+			network_id = wpas_p2p_store_persistent_group(
+				wpa_s->parent, ssid,
+				wpa_s->global->p2p_dev_addr);
+		if (network_id < 0)
+			network_id = ssid->id;
+		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+		wpas_p2p_cross_connect_setup(wpa_s);
+		wpas_p2p_set_group_idle_timeout(wpa_s);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
+	if (wpa_supplicant_ap_mac_addr_filter(wpa_s,
+					      params->peer_interface_addr)) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address "
+			   "filtering");
+		return;
+	}
+	if (params->wps_method == WPS_PBC)
+		wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
+					  params->peer_device_addr);
+	else if (wpa_s->p2p_pin[0])
+		wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
+					  wpa_s->p2p_pin, NULL, 0, 0);
+	os_free(wpa_s->go_params);
+	wpa_s->go_params = NULL;
+}
+
+
+static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
+			      struct p2p_go_neg_results *params,
+			      int group_formation)
+{
+	struct wpa_ssid *ssid;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Starting GO");
+	if (wpas_copy_go_neg_results(wpa_s, params) < 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not copy GO Negotiation "
+			"results");
+		return;
+	}
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for GO");
+		return;
+	}
+
+	wpa_s->show_group_started = 0;
+
+	wpa_config_set_network_defaults(ssid);
+	ssid->temporary = 1;
+	ssid->p2p_group = 1;
+	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->ssid = os_zalloc(params->ssid_len + 1);
+	if (ssid->ssid) {
+		os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
+		ssid->ssid_len = params->ssid_len;
+	}
+	ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+	ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+	ssid->proto = WPA_PROTO_RSN;
+	ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+	if (os_strlen(params->passphrase) > 0) {
+		ssid->passphrase = os_strdup(params->passphrase);
+		if (ssid->passphrase == NULL) {
+			wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
+				"passphrase for GO");
+			wpa_config_remove_network(wpa_s->conf, ssid->id);
+			return;
+		}
+	} else
+		ssid->passphrase = NULL;
+	ssid->psk_set = params->psk_set;
+	if (ssid->psk_set)
+		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;
+
+	wpa_s->ap_configured_cb = p2p_go_configured;
+	wpa_s->ap_configured_cb_ctx = wpa_s;
+	wpa_s->ap_configured_cb_data = wpa_s->go_params;
+	wpa_s->connect_without_scan = ssid;
+	wpa_s->reassociate = 1;
+	wpa_s->disconnected = 0;
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Request scan (that will be skipped) to "
+		"start GO)");
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
+				  const struct wpa_supplicant *src)
+{
+	struct wpa_config *d;
+	const struct wpa_config *s;
+
+	d = dst->conf;
+	s = src->conf;
+
+#define C(n) if (s->n) d->n = os_strdup(s->n)
+	C(device_name);
+	C(manufacturer);
+	C(model_name);
+	C(model_number);
+	C(serial_number);
+	C(config_methods);
+#undef C
+
+	os_memcpy(d->device_type, s->device_type, WPS_DEV_TYPE_LEN);
+	os_memcpy(d->sec_device_type, s->sec_device_type,
+		  sizeof(d->sec_device_type));
+	d->num_sec_device_types = s->num_sec_device_types;
+
+	d->p2p_group_idle = s->p2p_group_idle;
+	d->p2p_intra_bss = s->p2p_intra_bss;
+	d->persistent_reconnect = s->persistent_reconnect;
+	d->max_num_sta = s->max_num_sta;
+	d->pbc_in_m1 = s->pbc_in_m1;
+}
+
+
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+					enum wpa_driver_if_type type)
+{
+	char ifname[120], force_ifname[120];
+
+	if (wpa_s->pending_interface_name[0]) {
+		wpa_printf(MSG_DEBUG, "P2P: Pending virtual interface exists "
+			   "- skip creation of a new one");
+		if (is_zero_ether_addr(wpa_s->pending_interface_addr)) {
+			wpa_printf(MSG_DEBUG, "P2P: Pending virtual address "
+				   "unknown?! ifname='%s'",
+				   wpa_s->pending_interface_name);
+			return -1;
+		}
+		return 0;
+	}
+
+	os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
+		    wpa_s->p2p_group_idx);
+	if (os_strlen(ifname) >= IFNAMSIZ &&
+	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+		/* Try to avoid going over the IFNAMSIZ length limit */
+		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
+			    wpa_s->p2p_group_idx);
+	}
+	force_ifname[0] = '\0';
+
+	wpa_printf(MSG_DEBUG, "P2P: Create a new interface %s for the group",
+		   ifname);
+	wpa_s->p2p_group_idx++;
+
+	wpa_s->pending_interface_type = type;
+	if (wpa_drv_if_add(wpa_s, type, ifname, NULL, NULL, force_ifname,
+			   wpa_s->pending_interface_addr, NULL) < 0) {
+		wpa_printf(MSG_ERROR, "P2P: Failed to create new group "
+			   "interface");
+		return -1;
+	}
+
+	if (force_ifname[0]) {
+		wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
+			   force_ifname);
+		os_strlcpy(wpa_s->pending_interface_name, force_ifname,
+			   sizeof(wpa_s->pending_interface_name));
+	} else
+		os_strlcpy(wpa_s->pending_interface_name, ifname,
+			   sizeof(wpa_s->pending_interface_name));
+	wpa_printf(MSG_DEBUG, "P2P: Created pending virtual interface %s addr "
+		   MACSTR, wpa_s->pending_interface_name,
+		   MAC2STR(wpa_s->pending_interface_addr));
+
+	return 0;
+}
+
+
+static void wpas_p2p_remove_pending_group_interface(
+	struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->pending_interface_name[0] ||
+	    is_zero_ether_addr(wpa_s->pending_interface_addr))
+		return; /* No pending virtual interface */
+
+	wpa_printf(MSG_DEBUG, "P2P: Removing pending group interface %s",
+		   wpa_s->pending_interface_name);
+	wpa_drv_if_remove(wpa_s, wpa_s->pending_interface_type,
+			  wpa_s->pending_interface_name);
+	os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
+	wpa_s->pending_interface_name[0] = '\0';
+}
+
+
+static struct wpa_supplicant *
+wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go)
+{
+	struct wpa_interface iface;
+	struct wpa_supplicant *group_wpa_s;
+
+	if (!wpa_s->pending_interface_name[0]) {
+		wpa_printf(MSG_ERROR, "P2P: No pending group interface");
+		if (!wpas_p2p_create_iface(wpa_s))
+			return NULL;
+		/*
+		 * Something has forced us to remove the pending interface; try
+		 * to create a new one and hope for the best that we will get
+		 * the same local address.
+		 */
+		if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
+						 WPA_IF_P2P_CLIENT) < 0)
+			return NULL;
+	}
+
+	os_memset(&iface, 0, sizeof(iface));
+	iface.ifname = wpa_s->pending_interface_name;
+	iface.driver = wpa_s->driver->name;
+	iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+	iface.driver_param = wpa_s->conf->driver_param;
+	group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	if (group_wpa_s == NULL) {
+		wpa_printf(MSG_ERROR, "P2P: Failed to create new "
+			   "wpa_supplicant interface");
+		return NULL;
+	}
+	wpa_s->pending_interface_name[0] = '\0';
+	group_wpa_s->parent = wpa_s;
+	group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
+		P2P_GROUP_INTERFACE_CLIENT;
+	wpa_s->global->p2p_group_formation = group_wpa_s;
+
+	wpas_p2p_clone_config(group_wpa_s, wpa_s);
+
+	return group_wpa_s;
+}
+
+
+static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
+					     void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
+	if (wpa_s->global->p2p)
+		p2p_group_formation_failed(wpa_s->global->p2p);
+	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		wpa_drv_p2p_group_formation_failed(wpa_s);
+	wpas_group_formation_completed(wpa_s, 0);
+}
+
+
+void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+		wpa_drv_cancel_remain_on_channel(wpa_s);
+		wpa_s->off_channel_freq = 0;
+		wpa_s->roc_waiting_drv_freq = 0;
+	}
+
+	if (res->status) {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
+			res->status);
+		wpas_notify_p2p_go_neg_completed(wpa_s, res);
+		wpas_p2p_remove_pending_group_interface(wpa_s);
+		return;
+	}
+
+	if (wpa_s->p2p_go_ht40)
+		res->ht40 = 1;
+
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+	wpas_notify_p2p_go_neg_completed(wpa_s, res);
+
+	if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
+		struct wpa_ssid *ssid;
+		ssid = wpa_config_get_network(wpa_s->conf,
+					      wpa_s->p2p_persistent_id);
+		if (ssid && ssid->disabled == 2 &&
+		    ssid->mode == WPAS_MODE_P2P_GO && ssid->passphrase) {
+			size_t len = os_strlen(ssid->passphrase);
+			wpa_printf(MSG_DEBUG, "P2P: Override passphrase based "
+				   "on requested persistent group");
+			os_memcpy(res->passphrase, ssid->passphrase, len);
+			res->passphrase[len] = '\0';
+		}
+	}
+
+	if (wpa_s->create_p2p_iface) {
+		struct wpa_supplicant *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);
+			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
+			wpas_start_wps_enrollee(group_wpa_s, res);
+	} else {
+		wpa_s->p2p_in_provisioning = 1;
+		wpa_s->global->p2p_group_formation = wpa_s;
+
+		if (res->role_go)
+			wpas_start_wps_go(wpa_s, res, 1);
+		else
+			wpas_start_wps_enrollee(ctx, res);
+	}
+
+	wpa_s->p2p_long_listen = 0;
+	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+	eloop_register_timeout(15 + res->peer_config_timeout / 100,
+			       (res->peer_config_timeout % 100) * 10000,
+			       wpas_p2p_group_formation_timeout, wpa_s, NULL);
+}
+
+
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_REQUEST MACSTR
+		" dev_passwd_id=%u", MAC2STR(src), dev_passwd_id);
+
+	wpas_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+}
+
+
+void wpas_dev_found(void *ctx, const u8 *addr,
+		    const struct p2p_peer_info *info,
+		    int new_device)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	struct wpa_supplicant *wpa_s = ctx;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
+		" p2p_dev_addr=" MACSTR
+		" pri_dev_type=%s name='%s' config_methods=0x%x "
+		"dev_capab=0x%x group_capab=0x%x",
+		MAC2STR(addr), MAC2STR(info->p2p_device_addr),
+		wps_dev_type_bin2str(info->pri_dev_type, devtype,
+				     sizeof(devtype)),
+		info->device_name, info->config_methods,
+		info->dev_capab, info->group_capab);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
+}
+
+
+static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
+		"p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
+
+	wpas_notify_p2p_device_lost(wpa_s, dev_addr);
+}
+
+
+static int wpas_start_listen(void *ctx, unsigned int freq,
+			     unsigned int duration,
+			     const struct wpabuf *probe_resp_ie)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
+
+	if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
+			   "report received Probe Request frames");
+		return -1;
+	}
+
+	wpa_s->pending_listen_freq = freq;
+	wpa_s->pending_listen_duration = duration;
+
+	if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
+			   "to remain on channel (%u MHz) for Listen "
+			   "state", freq);
+		wpa_s->pending_listen_freq = 0;
+		return -1;
+	}
+	wpa_s->off_channel_freq = 0;
+	wpa_s->roc_waiting_drv_freq = freq;
+
+	return 0;
+}
+
+
+static void wpas_stop_listen(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+		wpa_drv_cancel_remain_on_channel(wpa_s);
+		wpa_s->off_channel_freq = 0;
+		wpa_s->roc_waiting_drv_freq = 0;
+	}
+	wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
+	wpa_drv_probe_req_report(wpa_s, 0);
+}
+
+
+static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+}
+
+
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+				       u8 **spos, const u8 *end)
+{
+	while (*spos < end) {
+		u8 val = ((*spos)[0] & 0xc0) >> 6;
+		int len;
+
+		if (val == 1 || val == 2) {
+			/* These are reserved values in RFC 1035 */
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence starting with 0x%x", val);
+			return -1;
+		}
+
+		if (val == 3) {
+			u16 offset;
+			u8 *spos_tmp;
+
+			/* Offset */
+			if (*spos + 2 > end) {
+				wpa_printf(MSG_DEBUG, "P2P: No room for full "
+					   "DNS offset field");
+				return -1;
+			}
+
+			offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+			if (offset >= *spos - start) {
+				wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+					   "pointer offset %u", offset);
+				return -1;
+			}
+
+			(*spos) += 2;
+			spos_tmp = start + offset;
+			return p2p_sd_dns_uncompress_label(upos, uend, start,
+							   &spos_tmp,
+							   *spos - 2);
+		}
+
+		/* Label */
+		len = (*spos)[0] & 0x3f;
+		if (len == 0)
+			return 0;
+
+		(*spos)++;
+		if (*spos + len > end) {
+			wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+				   "sequence - no room for label with length "
+				   "%u", len);
+			return -1;
+		}
+
+		if (*upos + len + 2 > uend)
+			return -2;
+
+		os_memcpy(*upos, *spos, len);
+		*spos += len;
+		*upos += len;
+		(*upos)[0] = '.';
+		(*upos)++;
+		(*upos)[0] = '\0';
+	}
+
+	return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+				 size_t msg_len, size_t offset)
+{
+	/* 27-octet in-memory packet from P2P specification */
+	const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+		"\x04_udp\xC0\x11\x00\x0C\x00\x01";
+	u8 *tmp, *end, *spos;
+	char *upos, *uend;
+	int ret = 0;
+
+	if (buf_len < 2)
+		return -1;
+	if (offset > msg_len)
+		return -1;
+
+	tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+	if (tmp == NULL)
+		return -1;
+	spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+	end = spos + msg_len;
+	spos += offset;
+
+	os_memset(tmp, 0, DNS_HEADER_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+	os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+	upos = buf;
+	uend = buf + buf_len;
+
+	ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+	if (ret) {
+		os_free(tmp);
+		return ret;
+	}
+
+	if (upos == buf) {
+		upos[0] = '.';
+		upos[1] = '\0';
+	} else if (upos[-1] == '.')
+		upos[-1] = '\0';
+
+	os_free(tmp);
+	return 0;
+}
+
+
+static struct p2p_srv_bonjour *
+wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
+			     const struct wpabuf *query)
+{
+	struct p2p_srv_bonjour *bsrv;
+	size_t len;
+
+	len = wpabuf_len(query);
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (len == wpabuf_len(bsrv->query) &&
+		    os_memcmp(wpabuf_head(query), wpabuf_head(bsrv->query),
+			      len) == 0)
+			return bsrv;
+	}
+	return NULL;
+}
+
+
+static struct p2p_srv_upnp *
+wpas_p2p_service_get_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			  const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (version == usrv->version &&
+		    os_strcmp(service, usrv->service) == 0)
+			return usrv;
+	}
+	return NULL;
+}
+
+
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+					u8 srv_trans_id)
+{
+	u8 *len_pos;
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, srv_proto);
+	wpabuf_put_u8(resp, srv_trans_id);
+	/* Status Code */
+	wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
+	/* Response Data: empty */
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
+				struct wpabuf *resp, u8 srv_trans_id)
+{
+	struct p2p_srv_bonjour *bsrv;
+	u8 *len_pos;
+
+	wpa_printf(MSG_DEBUG, "P2P: SD Request for all Bonjour services");
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+		return;
+	}
+
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (wpabuf_tailroom(resp) <
+		    5 + wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp))
+			return;
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+				  wpabuf_head(bsrv->resp),
+				  wpabuf_len(bsrv->resp));
+		/* Response Data */
+		wpabuf_put_buf(resp, bsrv->query); /* Key */
+		wpabuf_put_buf(resp, bsrv->resp); /* Value */
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+			       size_t query_len)
+{
+	char str_rx[256], str_srv[256];
+
+	if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+		return 0; /* Too short to include DNS Type and Version */
+	if (os_memcmp(query + query_len - 3,
+		      wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+		      3) != 0)
+		return 0; /* Mismatch in DNS Type or Version */
+	if (query_len == wpabuf_len(bsrv->query) &&
+	    os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+		return 1; /* Binary match */
+
+	if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+				  0))
+		return 0; /* Failed to uncompress query */
+	if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+				  wpabuf_head(bsrv->query),
+				  wpabuf_len(bsrv->query) - 3, 0))
+		return 0; /* Failed to uncompress service */
+
+	return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
+static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
+				struct wpabuf *resp, u8 srv_trans_id,
+				const u8 *query, size_t query_len)
+{
+	struct p2p_srv_bonjour *bsrv;
+	u8 *len_pos;
+	int matches = 0;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
+			  query, query_len);
+	if (dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+		wpa_printf(MSG_DEBUG, "P2P: Bonjour protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_BONJOUR,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len == 0) {
+		wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+		return;
+	}
+
+	dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+			 struct p2p_srv_bonjour, list) {
+		if (!match_bonjour_query(bsrv, query, query_len))
+			continue;
+
+		if (wpabuf_tailroom(resp) <
+		    5 + query_len + wpabuf_len(bsrv->resp))
+			return;
+
+		matches++;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+				  wpabuf_head(bsrv->resp),
+				  wpabuf_len(bsrv->resp));
+
+		/* Response Data */
+		wpabuf_put_data(resp, query, query_len); /* Key */
+		wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+	}
+
+	if (matches == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
+			   "available");
+		if (wpabuf_tailroom(resp) < 5)
+			return;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+		/* Response Data: empty */
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static void wpas_sd_all_upnp(struct wpa_supplicant *wpa_s,
+			     struct wpabuf *resp, u8 srv_trans_id)
+{
+	struct p2p_srv_upnp *usrv;
+	u8 *len_pos;
+
+	wpa_printf(MSG_DEBUG, "P2P: SD Request for all UPnP services");
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+		return;
+	}
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (wpabuf_tailroom(resp) < 5 + 1 + os_strlen(usrv->service))
+			return;
+
+		/* Length (to be filled) */
+		len_pos = wpabuf_put(resp, 2);
+		wpabuf_put_u8(resp, P2P_SERV_UPNP);
+		wpabuf_put_u8(resp, srv_trans_id);
+
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+		/* Response Data */
+		wpabuf_put_u8(resp, usrv->version);
+		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+			   usrv->service);
+		wpabuf_put_str(resp, usrv->service);
+		WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
+			     2);
+	}
+}
+
+
+static void wpas_sd_req_upnp(struct wpa_supplicant *wpa_s,
+			     struct wpabuf *resp, u8 srv_trans_id,
+			     const u8 *query, size_t query_len)
+{
+	struct p2p_srv_upnp *usrv;
+	u8 *len_pos;
+	u8 version;
+	char *str;
+	int count = 0;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for UPnP",
+			  query, query_len);
+
+	if (dl_list_empty(&wpa_s->global->p2p_srv_upnp)) {
+		wpa_printf(MSG_DEBUG, "P2P: UPnP protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_UPNP,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len == 0) {
+		wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+		return;
+	}
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, P2P_SERV_UPNP);
+	wpabuf_put_u8(resp, srv_trans_id);
+
+	version = query[0];
+	str = os_malloc(query_len);
+	if (str == NULL)
+		return;
+	os_memcpy(str, query + 1, query_len - 1);
+	str[query_len - 1] = '\0';
+
+	dl_list_for_each(usrv, &wpa_s->global->p2p_srv_upnp,
+			 struct p2p_srv_upnp, list) {
+		if (version != usrv->version)
+			continue;
+
+		if (os_strcmp(str, "ssdp:all") != 0 &&
+		    os_strstr(usrv->service, str) == NULL)
+			continue;
+
+		if (wpabuf_tailroom(resp) < 2)
+			break;
+		if (count == 0) {
+			/* Status Code */
+			wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+			/* Response Data */
+			wpabuf_put_u8(resp, version);
+		} else
+			wpabuf_put_u8(resp, ',');
+
+		count++;
+
+		wpa_printf(MSG_DEBUG, "P2P: Matching UPnP Service: %s",
+			   usrv->service);
+		if (wpabuf_tailroom(resp) < os_strlen(usrv->service))
+			break;
+		wpabuf_put_str(resp, usrv->service);
+	}
+	os_free(str);
+
+	if (count == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Requested UPnP service not "
+			   "available");
+		/* Status Code */
+		wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+		/* Response Data: empty */
+	}
+
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
+			    struct wpabuf *resp, u8 srv_trans_id,
+			    const u8 *query, size_t query_len)
+{
+	const u8 *pos;
+	u8 role;
+	u8 *len_pos;
+
+	wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
+
+	if (!wpa_s->global->wifi_display) {
+		wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
+		wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
+					    srv_trans_id);
+		return;
+	}
+
+	if (query_len < 1) {
+		wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
+			   "Role");
+		return;
+	}
+
+	if (wpabuf_tailroom(resp) < 5)
+		return;
+
+	pos = query;
+	role = *pos++;
+	wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
+
+	/* TODO: role specific handling */
+
+	/* Length (to be filled) */
+	len_pos = wpabuf_put(resp, 2);
+	wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
+	wpabuf_put_u8(resp, srv_trans_id);
+	wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
+
+	while (pos < query + query_len) {
+		if (*pos < MAX_WFD_SUBELEMS &&
+		    wpa_s->global->wfd_subelem[*pos] &&
+		    wpabuf_tailroom(resp) >=
+		    wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
+			wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
+				   "subelement %u", *pos);
+			wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
+		}
+		pos++;
+	}
+
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+		     u16 update_indic, const u8 *tlvs, size_t tlvs_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos = tlvs;
+	const u8 *end = tlvs + tlvs_len;
+	const u8 *tlv_end;
+	u16 slen;
+	struct wpabuf *resp;
+	u8 srv_proto, srv_trans_id;
+	size_t buf_len;
+	char *buf;
+
+	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Request TLVs",
+		    tlvs, tlvs_len);
+	buf_len = 2 * tlvs_len + 1;
+	buf = os_malloc(buf_len);
+	if (buf) {
+		wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+		wpa_msg_ctrl(wpa_s, MSG_INFO, P2P_EVENT_SERV_DISC_REQ "%d "
+			     MACSTR " %u %u %s",
+			     freq, MAC2STR(sa), dialog_token, update_indic,
+			     buf);
+		os_free(buf);
+	}
+
+	if (wpa_s->p2p_sd_over_ctrl_iface) {
+		wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					   update_indic, tlvs, tlvs_len);
+		return; /* to be processed by an external program */
+	}
+
+	resp = wpabuf_alloc(10000);
+	if (resp == NULL)
+		return;
+
+	while (pos + 1 < end) {
+		wpa_printf(MSG_DEBUG, "P2P: Service Request TLV");
+		slen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (pos + slen > end || slen < 2) {
+			wpa_printf(MSG_DEBUG, "P2P: Unexpected Query Data "
+				   "length");
+			wpabuf_free(resp);
+			return;
+		}
+		tlv_end = pos + slen;
+
+		srv_proto = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+			   srv_proto);
+		srv_trans_id = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+			   srv_trans_id);
+
+		wpa_hexdump(MSG_MSGDUMP, "P2P: Query Data",
+			    pos, tlv_end - pos);
+
+
+		if (wpa_s->force_long_sd) {
+			wpa_printf(MSG_DEBUG, "P2P: SD test - force long "
+				   "response");
+			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+			goto done;
+		}
+
+		switch (srv_proto) {
+		case P2P_SERV_ALL_SERVICES:
+			wpa_printf(MSG_DEBUG, "P2P: Service Discovery Request "
+				   "for all services");
+			if (dl_list_empty(&wpa_s->global->p2p_srv_upnp) &&
+			    dl_list_empty(&wpa_s->global->p2p_srv_bonjour)) {
+				wpa_printf(MSG_DEBUG, "P2P: No service "
+					   "discovery protocols available");
+				wpas_sd_add_proto_not_avail(
+					resp, P2P_SERV_ALL_SERVICES,
+					srv_trans_id);
+				break;
+			}
+			wpas_sd_all_bonjour(wpa_s, resp, srv_trans_id);
+			wpas_sd_all_upnp(wpa_s, resp, srv_trans_id);
+			break;
+		case P2P_SERV_BONJOUR:
+			wpas_sd_req_bonjour(wpa_s, resp, srv_trans_id,
+					    pos, tlv_end - pos);
+			break;
+		case P2P_SERV_UPNP:
+			wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
+					 pos, tlv_end - pos);
+			break;
+#ifdef CONFIG_WIFI_DISPLAY
+		case P2P_SERV_WIFI_DISPLAY:
+			wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
+					pos, tlv_end - pos);
+			break;
+#endif /* CONFIG_WIFI_DISPLAY */
+		default:
+			wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
+				   "protocol %u", srv_proto);
+			wpas_sd_add_proto_not_avail(resp, srv_proto,
+						    srv_trans_id);
+			break;
+		}
+
+		pos = tlv_end;
+	}
+
+done:
+	wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+				   update_indic, tlvs, tlvs_len);
+
+	wpas_p2p_sd_response(wpa_s, freq, sa, dialog_token, resp);
+
+	wpabuf_free(resp);
+}
+
+
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+		      const u8 *tlvs, size_t tlvs_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos = tlvs;
+	const u8 *end = tlvs + tlvs_len;
+	const u8 *tlv_end;
+	u16 slen;
+	size_t buf_len;
+	char *buf;
+
+	wpa_hexdump(MSG_MSGDUMP, "P2P: Service Discovery Response TLVs",
+		    tlvs, tlvs_len);
+	if (tlvs_len > 1500) {
+		/* TODO: better way for handling this */
+		wpa_msg_ctrl(wpa_s, MSG_INFO,
+			     P2P_EVENT_SERV_DISC_RESP MACSTR
+			     " %u <long response: %u bytes>",
+			     MAC2STR(sa), update_indic,
+			     (unsigned int) tlvs_len);
+	} else {
+		buf_len = 2 * tlvs_len + 1;
+		buf = os_malloc(buf_len);
+		if (buf) {
+			wpa_snprintf_hex(buf, buf_len, tlvs, tlvs_len);
+			wpa_msg_ctrl(wpa_s, MSG_INFO,
+				     P2P_EVENT_SERV_DISC_RESP MACSTR " %u %s",
+				     MAC2STR(sa), update_indic, buf);
+			os_free(buf);
+		}
+	}
+
+	while (pos < end) {
+		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) {
+			wpa_printf(MSG_DEBUG, "P2P: Unexpected Response Data "
+				   "length");
+			return;
+		}
+		tlv_end = pos + slen;
+
+		srv_proto = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Protocol Type %u",
+			   srv_proto);
+		srv_trans_id = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Service Transaction ID %u",
+			   srv_trans_id);
+		status = *pos++;
+		wpa_printf(MSG_DEBUG, "P2P: Status Code ID %u",
+			   status);
+
+		wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
+			    pos, tlv_end - pos);
+
+		pos = tlv_end;
+	}
+
+	wpas_notify_p2p_sd_response(wpa_s, sa, update_indic, tlvs, tlvs_len);
+}
+
+
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+	return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query)
+{
+	struct wpabuf *tlvs;
+	u64 ret;
+
+	tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
+	if (tlvs == NULL)
+		return 0;
+	wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
+	wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
+	wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
+	wpabuf_put_u8(tlvs, version);
+	wpabuf_put_str(tlvs, query);
+	ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+	wpabuf_free(tlvs);
+	return ret;
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
+				   const struct wpabuf *tlvs)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return 0;
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+	return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+				const char *subelems)
+{
+	u8 *len;
+	const char *pos;
+	int val;
+	int count = 0;
+
+	len = wpabuf_put(tlvs, 2);
+	wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
+	wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+
+	wpabuf_put_u8(tlvs, role);
+
+	pos = subelems;
+	while (*pos) {
+		val = atoi(pos);
+		if (val >= 0 && val < 256) {
+			wpabuf_put_u8(tlvs, val);
+			count++;
+			if (count == MAX_WFD_SD_SUBELEMS)
+				break;
+		}
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
+}
+
+
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, const char *role)
+{
+	struct wpabuf *tlvs;
+	u64 ret;
+	const char *subelems;
+	u8 id = 1;
+
+	subelems = os_strchr(role, ' ');
+	if (subelems == NULL)
+		return 0;
+	subelems++;
+
+	tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
+	if (tlvs == NULL)
+		return 0;
+
+	if (os_strstr(role, "[source]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
+	if (os_strstr(role, "[pri-sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
+	if (os_strstr(role, "[sec-sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
+	if (os_strstr(role, "[source+sink]"))
+		wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
+
+	ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
+	wpabuf_free(tlvs);
+	return ret;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+	return p2p_sd_cancel_request(wpa_s->global->p2p,
+				     (void *) (uintptr_t) req);
+}
+
+
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+			  const u8 *dst, u8 dialog_token,
+			  const struct wpabuf *resp_tlvs)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token,
+					resp_tlvs);
+		return;
+	}
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+	p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token,
+			resp_tlvs);
+}
+
+
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		wpa_drv_p2p_service_update(wpa_s);
+		return;
+	}
+	if (wpa_s->global->p2p)
+		p2p_sd_service_update(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_srv_bonjour_free(struct p2p_srv_bonjour *bsrv)
+{
+	dl_list_del(&bsrv->list);
+	wpabuf_free(bsrv->query);
+	wpabuf_free(bsrv->resp);
+	os_free(bsrv);
+}
+
+
+static void wpas_p2p_srv_upnp_free(struct p2p_srv_upnp *usrv)
+{
+	dl_list_del(&usrv->list);
+	os_free(usrv->service);
+	os_free(usrv);
+}
+
+
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s)
+{
+	struct p2p_srv_bonjour *bsrv, *bn;
+	struct p2p_srv_upnp *usrv, *un;
+
+	dl_list_for_each_safe(bsrv, bn, &wpa_s->global->p2p_srv_bonjour,
+			      struct p2p_srv_bonjour, list)
+		wpas_p2p_srv_bonjour_free(bsrv);
+
+	dl_list_for_each_safe(usrv, un, &wpa_s->global->p2p_srv_upnp,
+			      struct p2p_srv_upnp, list)
+		wpas_p2p_srv_upnp_free(usrv);
+
+	wpas_p2p_sd_service_update(wpa_s);
+}
+
+
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+				 struct wpabuf *query, struct wpabuf *resp)
+{
+	struct p2p_srv_bonjour *bsrv;
+
+	bsrv = os_zalloc(sizeof(*bsrv));
+	if (bsrv == NULL)
+		return -1;
+	bsrv->query = query;
+	bsrv->resp = resp;
+	dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list);
+
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *query)
+{
+	struct p2p_srv_bonjour *bsrv;
+
+	bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
+	if (bsrv == NULL)
+		return -1;
+	wpas_p2p_srv_bonjour_free(bsrv);
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	if (wpas_p2p_service_get_upnp(wpa_s, version, service))
+		return 0; /* Already listed */
+	usrv = os_zalloc(sizeof(*usrv));
+	if (usrv == NULL)
+		return -1;
+	usrv->version = version;
+	usrv->service = os_strdup(service);
+	if (usrv->service == NULL) {
+		os_free(usrv);
+		return -1;
+	}
+	dl_list_add(&wpa_s->global->p2p_srv_upnp, &usrv->list);
+
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service)
+{
+	struct p2p_srv_upnp *usrv;
+
+	usrv = wpas_p2p_service_get_upnp(wpa_s, version, service);
+	if (usrv == NULL)
+		return -1;
+	wpas_p2p_srv_upnp_free(usrv);
+	wpas_p2p_sd_service_update(wpa_s);
+	return 0;
+}
+
+
+static void wpas_prov_disc_local_display(struct wpa_supplicant *wpa_s,
+					 const u8 *peer, const char *params,
+					 unsigned int generated_pin)
+{
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_SHOW_PIN MACSTR " %08d%s",
+		MAC2STR(peer), generated_pin, params);
+}
+
+
+static void wpas_prov_disc_local_keypad(struct wpa_supplicant *wpa_s,
+					const u8 *peer, const char *params)
+{
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_ENTER_PIN MACSTR "%s",
+		MAC2STR(peer), params);
+}
+
+
+void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+			const u8 *dev_addr, const u8 *pri_dev_type,
+			const char *dev_name, u16 supp_config_methods,
+			u8 dev_capab, u8 group_capab, const u8 *group_id,
+			size_t group_id_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	char params[300];
+	u8 empty_dev_type[8];
+	unsigned int generated_pin = 0;
+	struct wpa_supplicant *group = NULL;
+
+	if (group_id) {
+		for (group = wpa_s->global->ifaces; group; group = group->next)
+		{
+			struct wpa_ssid *s = group->current_ssid;
+			if (s != NULL &&
+			    s->mode == WPAS_MODE_P2P_GO &&
+			    group_id_len - ETH_ALEN == s->ssid_len &&
+			    os_memcmp(group_id + ETH_ALEN, s->ssid,
+				      s->ssid_len) == 0)
+				break;
+		}
+	}
+
+	if (pri_dev_type == NULL) {
+		os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
+		pri_dev_type = empty_dev_type;
+	}
+	os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
+		    " pri_dev_type=%s name='%s' config_methods=0x%x "
+		    "dev_capab=0x%x group_capab=0x%x%s%s",
+		    MAC2STR(dev_addr),
+		    wps_dev_type_bin2str(pri_dev_type, devtype,
+					 sizeof(devtype)),
+		    dev_name, supp_config_methods, dev_capab, group_capab,
+		    group ? " group=" : "",
+		    group ? group->ifname : "");
+	params[sizeof(params) - 1] = '\0';
+
+	if (config_methods & WPS_CONFIG_DISPLAY) {
+		generated_pin = wps_generate_pin();
+		wpas_prov_disc_local_display(wpa_s, peer, params,
+					     generated_pin);
+	} else if (config_methods & WPS_CONFIG_KEYPAD)
+		wpas_prov_disc_local_keypad(wpa_s, peer, params);
+	else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_REQ MACSTR
+			"%s", MAC2STR(peer), params);
+
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 1 /* request */,
+					    P2P_PROV_DISC_SUCCESS,
+					    config_methods, generated_pin);
+}
+
+
+void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	unsigned int generated_pin = 0;
+	char params[20];
+
+	if (wpa_s->pending_pd_before_join &&
+	    (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+	     os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+		wpa_s->pending_pd_before_join = 0;
+		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+			   "join-existing-group operation");
+		wpas_p2p_join_start(wpa_s);
+		return;
+	}
+
+	if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
+	    wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
+		os_snprintf(params, sizeof(params), " peer_go=%d",
+			    wpa_s->pending_pd_use == AUTO_PD_JOIN);
+	else
+		params[0] = '\0';
+
+	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();
+		wpas_prov_disc_local_display(wpa_s, peer, params,
+					     generated_pin);
+	} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR
+			"%s", MAC2STR(peer), params);
+
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+					    P2P_PROV_DISC_SUCCESS,
+					    config_methods, generated_pin);
+}
+
+
+static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+				enum p2p_prov_disc_status status)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	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");
+		wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+		return;
+	}
+
+	if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
+		wpa_s->pending_pd_before_join = 0;
+		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+			   "join-existing-group operation (no ACK for PD "
+			   "Req attempts)");
+		wpas_p2p_join_start(wpa_s);
+		return;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+		" p2p_dev_addr=" MACSTR " status=%d",
+		MAC2STR(peer), status);
+
+	wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
+					    status, 0, 0);
+}
+
+
+static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
+				  const u8 *go_dev_addr, const u8 *ssid,
+				  size_t ssid_len, int *go, u8 *group_bssid,
+				  int *force_freq, int persistent_group)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *s;
+	u8 cur_bssid[ETH_ALEN];
+	int res;
+	struct wpa_supplicant *grp;
+
+	if (!persistent_group) {
+		wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
+			   " to join an active group", MAC2STR(sa));
+		if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+		    (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN)
+		     == 0 ||
+		     os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) {
+			wpa_printf(MSG_DEBUG, "P2P: Accept previously "
+				   "authorized invitation");
+			goto accept_inv;
+		}
+		/*
+		 * Do not accept the invitation automatically; notify user and
+		 * request approval.
+		 */
+		return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+	}
+
+	grp = wpas_get_p2p_group(wpa_s, ssid, ssid_len, go);
+	if (grp) {
+		wpa_printf(MSG_DEBUG, "P2P: Accept invitation to already "
+			   "running persistent group");
+		if (*go)
+			os_memcpy(group_bssid, grp->own_addr, ETH_ALEN);
+		goto accept_inv;
+	}
+
+	if (!wpa_s->conf->persistent_reconnect)
+		return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
+
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled == 2 &&
+		    os_memcmp(s->bssid, go_dev_addr, ETH_ALEN) == 0 &&
+		    s->ssid_len == ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			break;
+	}
+
+	if (!s) {
+		wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
+			   " requested reinvocation of an unknown group",
+			   MAC2STR(sa));
+		return P2P_SC_FAIL_UNKNOWN_GROUP;
+	}
+
+	if (s->mode == WPAS_MODE_P2P_GO && !wpas_p2p_create_iface(wpa_s)) {
+		*go = 1;
+		if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+			wpa_printf(MSG_DEBUG, "P2P: The only available "
+				   "interface is already in use - reject "
+				   "invitation");
+			return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+		}
+		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)
+		{
+			wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+				   "interface address for the group");
+			return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+		}
+		os_memcpy(group_bssid, wpa_s->pending_interface_addr,
+			  ETH_ALEN);
+	}
+
+accept_inv:
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
+	    wpa_s->assoc_freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
+			   "the channel we are already using");
+		*force_freq = wpa_s->assoc_freq;
+	}
+
+	res = wpa_drv_shared_freq(wpa_s);
+	if (res > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
+			   "with the channel we are already using on a "
+			   "shared interface");
+		*force_freq = res;
+	}
+
+	return P2P_SC_SUCCESS;
+}
+
+
+static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
+				     const u8 *ssid, size_t ssid_len,
+				     const u8 *go_dev_addr, u8 status,
+				     int op_freq)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *s;
+
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled == 2 &&
+		    s->ssid_len == ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			break;
+	}
+
+	if (status == P2P_SC_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
+			   " was accepted; op_freq=%d MHz",
+			   MAC2STR(sa), op_freq);
+		if (s) {
+			int go = s->mode == WPAS_MODE_P2P_GO;
+			wpas_p2p_group_add_persistent(
+				wpa_s, s, go, go ? op_freq : 0, 0);
+		} else if (bssid) {
+			wpa_s->user_initiated_pd = 0;
+			wpas_p2p_join(wpa_s, bssid, go_dev_addr,
+				      wpa_s->p2p_wps_method, 0);
+		}
+		return;
+	}
+
+	if (status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+		wpa_printf(MSG_DEBUG, "P2P: Invitation from peer " MACSTR
+			   " was rejected (status %u)", MAC2STR(sa), status);
+		return;
+	}
+
+	if (!s) {
+		if (bssid) {
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+				"sa=" MACSTR " go_dev_addr=" MACSTR
+				" bssid=" MACSTR " unknown-network",
+				MAC2STR(sa), MAC2STR(go_dev_addr),
+				MAC2STR(bssid));
+		} else {
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED
+				"sa=" MACSTR " go_dev_addr=" MACSTR
+				" unknown-network",
+				MAC2STR(sa), MAC2STR(go_dev_addr));
+		}
+		return;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
+		" persistent=%d", MAC2STR(sa), s->id);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *ssid;
+
+	if (bssid) {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+			"status=%d " MACSTR,
+			status, MAC2STR(bssid));
+	} else {
+		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
+			"status=%d ", status);
+	}
+	wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
+
+	if (wpa_s->pending_invite_ssid_id == -1)
+		return; /* Invitation to active group */
+
+	if (status != P2P_SC_SUCCESS) {
+		wpas_p2p_remove_pending_group_interface(wpa_s);
+		return;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf,
+				      wpa_s->pending_invite_ssid_id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_ERROR, "P2P: Could not find persistent group "
+			   "data matching with invitation");
+		return;
+	}
+
+	/*
+	 * The peer could have missed our ctrl::ack frame for Invitation
+	 * Response and continue retransmitting the frame. To reduce the
+	 * likelihood of the peer not getting successful TX status for the
+	 * Invitation Response frame, wait a short time here before starting
+	 * the persistent group so that we will remain on the current channel to
+	 * acknowledge any possible retransmission from the peer.
+	 */
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: 50 ms wait on current channel before "
+		"starting persistent group");
+	os_sleep(0, 50000);
+
+	wpas_p2p_group_add_persistent(wpa_s, ssid,
+				      ssid->mode == WPAS_MODE_P2P_GO,
+				      wpa_s->p2p_persistent_go_freq,
+				      wpa_s->p2p_go_ht40);
+}
+
+
+static int wpas_p2p_disallowed_freq(struct wpa_global *global,
+				    unsigned int freq)
+{
+	unsigned int i;
+
+	if (global->p2p_disallow_freq == NULL)
+		return 0;
+
+	for (i = 0; i < global->num_p2p_disallow_freq; i++) {
+		if (freq >= global->p2p_disallow_freq[i].min &&
+		    freq <= global->p2p_disallow_freq[i].max)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
+{
+	reg->channel[reg->channels] = chan;
+	reg->channels++;
+}
+
+
+static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
+				     struct p2p_channels *chan)
+{
+	int i, cla = 0;
+
+	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
+		   "band");
+
+	/* Operating class 81 - 2.4 GHz band channels 1..13 */
+	chan->reg_class[cla].reg_class = 81;
+	chan->reg_class[cla].channels = 0;
+	for (i = 0; i < 11; i++) {
+		if (!wpas_p2p_disallowed_freq(wpa_s->global, 2412 + i * 5))
+			wpas_p2p_add_chan(&chan->reg_class[cla], i + 1);
+	}
+	if (chan->reg_class[cla].channels)
+		cla++;
+
+	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
+		   "band");
+
+	/* Operating class 115 - 5 GHz, channels 36-48 */
+	chan->reg_class[cla].reg_class = 115;
+	chan->reg_class[cla].channels = 0;
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 36 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 36);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 40 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 40);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 44 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 44);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 48 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 48);
+	if (chan->reg_class[cla].channels)
+		cla++;
+
+	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
+		   "band");
+
+	/* Operating class 124 - 5 GHz, channels 149,153,157,161 */
+	chan->reg_class[cla].reg_class = 124;
+	chan->reg_class[cla].channels = 0;
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 149 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 149);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 153 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 153);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 156 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 157);
+	if (!wpas_p2p_disallowed_freq(wpa_s->global, 5000 + 161 * 5))
+		wpas_p2p_add_chan(&chan->reg_class[cla], 161);
+	if (chan->reg_class[cla].channels)
+		cla++;
+
+	chan->reg_classes = cla;
+	return 0;
+}
+
+
+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 int has_channel(struct wpa_global *global,
+		       struct hostapd_hw_modes *mode, u8 chan, int *flags)
+{
+	int i;
+	unsigned int freq;
+
+	freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
+		chan * 5;
+	if (wpas_p2p_disallowed_freq(global, freq))
+		return 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].chan == chan) {
+			if (flags)
+				*flags = mode->channels[i].flag;
+			return !(mode->channels[i].flag &
+				 (HOSTAPD_CHAN_DISABLED |
+				  HOSTAPD_CHAN_PASSIVE_SCAN |
+				  HOSTAPD_CHAN_NO_IBSS |
+				  HOSTAPD_CHAN_RADAR));
+		}
+	}
+
+	return 0;
+}
+
+
+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 } bw;
+};
+
+static 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, 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 },
+	{ -1, 0, 0, 0, 0, BW20 }
+};
+
+
+static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+				   struct hostapd_hw_modes *mode,
+				   u8 channel, u8 bw)
+{
+	int flag;
+
+	if (!has_channel(wpa_s->global, mode, channel, &flag))
+		return -1;
+	if (bw == BW40MINUS &&
+	    (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
+	     !has_channel(wpa_s->global, mode, channel - 4, NULL)))
+		return 0;
+	if (bw == BW40PLUS &&
+	    (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
+	     !has_channel(wpa_s->global, mode, channel + 4, NULL)))
+		return 0;
+	return 1;
+}
+
+
+static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
+				   struct p2p_channels *chan)
+{
+	struct hostapd_hw_modes *mode;
+	int cla, op;
+
+	if (wpa_s->hw.modes == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
+			   "of all supported channels; assume dualband "
+			   "support");
+		return wpas_p2p_default_channels(wpa_s, chan);
+	}
+
+	cla = 0;
+
+	for (op = 0; op_class[op].op_class; op++) {
+		struct p2p_oper_class_map *o = &op_class[op];
+		u8 ch;
+		struct p2p_reg_class *reg = NULL;
+
+		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
+		if (mode == NULL)
+			continue;
+		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+			if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
+				continue;
+			if (reg == NULL) {
+				wpa_printf(MSG_DEBUG, "P2P: Add operating "
+					   "class %u", o->op_class);
+				reg = &chan->reg_class[cla];
+				cla++;
+				reg->reg_class = o->op_class;
+			}
+			reg->channel[reg->channels] = ch;
+			reg->channels++;
+		}
+		if (reg) {
+			wpa_hexdump(MSG_DEBUG, "P2P: Channels",
+				    reg->channel, reg->channels);
+		}
+	}
+
+	chan->reg_classes = cla;
+
+	return 0;
+}
+
+
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+			   struct hostapd_hw_modes *mode, u8 channel)
+{
+	int op, ret;
+
+	for (op = 0; op_class[op].op_class; op++) {
+		struct p2p_oper_class_map *o = &op_class[op];
+		u8 ch;
+
+		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+			if (o->mode != HOSTAPD_MODE_IEEE80211A ||
+			    o->bw == BW20 || ch != channel)
+				continue;
+			ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+			if (ret < 0)
+				continue;
+			else if (ret > 0)
+				return (o->bw == BW40MINUS) ? -1 : 1;
+			else
+				return 0;
+		}
+	}
+	return 0;
+}
+
+
+static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
+			size_t buf_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_memcmp(wpa_s->own_addr, interface_addr, ETH_ALEN) == 0)
+			break;
+	}
+	if (wpa_s == NULL)
+		return -1;
+
+	return wpa_drv_get_noa(wpa_s, buf, buf_len);
+}
+
+
+static int wpas_go_connected(void *ctx, const u8 *dev_addr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		if (ssid == NULL)
+			continue;
+		if (ssid->mode != WPAS_MODE_INFRA)
+			continue;
+		if (wpa_s->wpa_state != WPA_COMPLETED &&
+		    wpa_s->wpa_state != WPA_GROUP_HANDSHAKE)
+			continue;
+		if (os_memcmp(wpa_s->go_dev_addr, dev_addr, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_p2p_init - Initialize P2P module for %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * Returns: 0 on success, -1 on failure
+ */
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
+{
+	struct p2p_config p2p;
+	unsigned int r;
+	int i;
+
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+		return 0;
+
+	if (global->p2p)
+		return 0;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		struct p2p_params params;
+
+		wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management");
+		os_memset(&params, 0, sizeof(params));
+		params.dev_name = wpa_s->conf->device_name;
+		os_memcpy(params.pri_dev_type, wpa_s->conf->device_type,
+			  WPS_DEV_TYPE_LEN);
+		params.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+		os_memcpy(params.sec_dev_type,
+			  wpa_s->conf->sec_device_type,
+			  params.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+
+		if (wpa_drv_p2p_set_params(wpa_s, &params) < 0)
+			return -1;
+
+		return 0;
+	}
+
+	os_memset(&p2p, 0, sizeof(p2p));
+	p2p.msg_ctx = wpa_s;
+	p2p.cb_ctx = wpa_s;
+	p2p.p2p_scan = wpas_p2p_scan;
+	p2p.send_action = wpas_send_action;
+	p2p.send_action_done = wpas_send_action_done;
+	p2p.go_neg_completed = wpas_go_neg_completed;
+	p2p.go_neg_req_rx = wpas_go_neg_req_rx;
+	p2p.dev_found = wpas_dev_found;
+	p2p.dev_lost = wpas_dev_lost;
+	p2p.start_listen = wpas_start_listen;
+	p2p.stop_listen = wpas_stop_listen;
+	p2p.send_probe_resp = wpas_send_probe_resp;
+	p2p.sd_request = wpas_sd_request;
+	p2p.sd_response = wpas_sd_response;
+	p2p.prov_disc_req = wpas_prov_disc_req;
+	p2p.prov_disc_resp = wpas_prov_disc_resp;
+	p2p.prov_disc_fail = wpas_prov_disc_fail;
+	p2p.invitation_process = wpas_invitation_process;
+	p2p.invitation_received = wpas_invitation_received;
+	p2p.invitation_result = wpas_invitation_result;
+	p2p.get_noa = wpas_get_noa;
+	p2p.go_connected = wpas_go_connected;
+
+	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
+	p2p.dev_name = wpa_s->conf->device_name;
+	p2p.manufacturer = wpa_s->conf->manufacturer;
+	p2p.model_name = wpa_s->conf->model_name;
+	p2p.model_number = wpa_s->conf->model_number;
+	p2p.serial_number = wpa_s->conf->serial_number;
+	if (wpa_s->wps) {
+		os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
+		p2p.config_methods = wpa_s->wps->config_methods;
+	}
+
+	if (wpa_s->conf->p2p_listen_reg_class &&
+	    wpa_s->conf->p2p_listen_channel) {
+		p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
+		p2p.channel = wpa_s->conf->p2p_listen_channel;
+	} else {
+		p2p.reg_class = 81;
+		/*
+		 * Pick one of the social channels randomly as the listen
+		 * channel.
+		 */
+		os_get_random((u8 *) &r, sizeof(r));
+		p2p.channel = 1 + (r % 3) * 5;
+	}
+	wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
+
+	if (wpa_s->conf->p2p_oper_reg_class &&
+	    wpa_s->conf->p2p_oper_channel) {
+		p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+		p2p.op_channel = wpa_s->conf->p2p_oper_channel;
+		p2p.cfg_op_channel = 1;
+		wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: "
+			   "%d:%d", p2p.op_reg_class, p2p.op_channel);
+
+	} else {
+		p2p.op_reg_class = 81;
+		/*
+		 * Use random operation channel from (1, 6, 11) if no other
+		 * preference is indicated.
+		 */
+		os_get_random((u8 *) &r, sizeof(r));
+		p2p.op_channel = 1 + (r % 3) * 5;
+		p2p.cfg_op_channel = 0;
+		wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
+			   "%d:%d", p2p.op_reg_class, p2p.op_channel);
+	}
+	if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+		os_memcpy(p2p.country, wpa_s->conf->country, 2);
+		p2p.country[2] = 0x04;
+	} else
+		os_memcpy(p2p.country, "XX\x04", 3);
+
+	if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+		wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
+			   "channel list");
+		return -1;
+	}
+
+	os_memcpy(p2p.pri_dev_type, wpa_s->conf->device_type,
+		  WPS_DEV_TYPE_LEN);
+
+	p2p.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+	os_memcpy(p2p.sec_dev_type, wpa_s->conf->sec_device_type,
+		  p2p.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+
+	p2p.concurrent_operations = !!(wpa_s->drv_flags &
+				       WPA_DRIVER_FLAGS_P2P_CONCURRENT);
+
+	p2p.max_peers = 100;
+
+	if (wpa_s->conf->p2p_ssid_postfix) {
+		p2p.ssid_postfix_len =
+			os_strlen(wpa_s->conf->p2p_ssid_postfix);
+		if (p2p.ssid_postfix_len > sizeof(p2p.ssid_postfix))
+			p2p.ssid_postfix_len = sizeof(p2p.ssid_postfix);
+		os_memcpy(p2p.ssid_postfix, wpa_s->conf->p2p_ssid_postfix,
+			  p2p.ssid_postfix_len);
+	}
+
+	p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+
+	p2p.max_listen = wpa_s->max_remain_on_chan;
+
+	global->p2p = p2p_init(&p2p);
+	if (global->p2p == NULL)
+		return -1;
+	global->p2p_init_wpa_s = wpa_s;
+
+	for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+			continue;
+		p2p_add_wps_vendor_extension(
+			global->p2p, wpa_s->conf->wps_vendor_ext[i]);
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_p2p_deinit - Deinitialize per-interface P2P data
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ *
+ * This function deinitialize per-interface P2P data.
+ */
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver && wpa_s->drv_priv)
+		wpa_drv_probe_req_report(wpa_s, 0);
+
+	if (wpa_s->go_params) {
+		/* Clear any stored provisioning info */
+		p2p_clear_provisioning_info(
+			wpa_s->global->p2p,
+			wpa_s->go_params->peer_device_addr);
+	}
+
+	os_free(wpa_s->go_params);
+	wpa_s->go_params = NULL;
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+	wpa_s->p2p_long_listen = 0;
+	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+	wpas_p2p_remove_pending_group_interface(wpa_s);
+
+	/* TODO: remove group interface from the driver if this wpa_s instance
+	 * is on top of a P2P group interface */
+}
+
+
+/**
+ * wpas_p2p_deinit_global - Deinitialize global P2P module
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function deinitializes the global (per device) P2P module.
+ */
+void wpas_p2p_deinit_global(struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s, *tmp;
+
+	wpa_s = global->ifaces;
+	if (wpa_s)
+		wpas_p2p_service_flush(wpa_s);
+
+	if (global->p2p == NULL)
+		return;
+
+	/* Remove remaining P2P group interfaces */
+	while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+		wpa_s = wpa_s->next;
+	while (wpa_s) {
+		tmp = global->ifaces;
+		while (tmp &&
+		       (tmp == wpa_s ||
+			tmp->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)) {
+			tmp = tmp->next;
+		}
+		if (tmp == NULL)
+			break;
+		/* Disconnect from the P2P group and deinit the interface */
+		wpas_p2p_disconnect(tmp);
+	}
+
+	/*
+	 * Deinit GO data on any possibly remaining interface (if main
+	 * interface is used as GO).
+	 */
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (wpa_s->ap_iface)
+			wpas_p2p_group_deinit(wpa_s);
+	}
+
+	p2p_deinit(global->p2p);
+	global->p2p = NULL;
+	global->p2p_init_wpa_s = NULL;
+}
+
+
+static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
+{
+	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 |
+	     WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
+		return 1; /* P2P group requires a new interface in every case
+			   */
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CONCURRENT))
+		return 0; /* driver does not support concurrent operations */
+	if (wpa_s->global->ifaces->next)
+		return 1; /* more that one interface already in use */
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+		return 1; /* this interface is already in use */
+	return 0;
+}
+
+
+static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
+				 const u8 *peer_addr,
+				 enum p2p_wps_method wps_method,
+				 int go_intent, const u8 *own_interface_addr,
+				 unsigned int force_freq, int persistent_group,
+				 struct wpa_ssid *ssid, unsigned int pref_freq)
+{
+	if (persistent_group && wpa_s->conf->persistent_reconnect)
+		persistent_group = 2;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
+					   go_intent, own_interface_addr,
+					   force_freq, persistent_group);
+	}
+
+	/*
+	 * Increase GO config timeout if HT40 is used since it takes some time
+	 * to scan channels for coex purposes before the BSS can be started.
+	 */
+	p2p_set_config_timeout(wpa_s->global->p2p,
+			       wpa_s->p2p_go_ht40 ? 255 : 100, 20);
+
+	return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
+			   go_intent, own_interface_addr, force_freq,
+			   persistent_group, ssid ? ssid->ssid : NULL,
+			   ssid ? ssid->ssid_len : 0,
+			   wpa_s->p2p_pd_before_go_neg, pref_freq);
+}
+
+
+static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
+				const u8 *peer_addr,
+				enum p2p_wps_method wps_method,
+				int go_intent, const u8 *own_interface_addr,
+				unsigned int force_freq, int persistent_group,
+				struct wpa_ssid *ssid, unsigned int pref_freq)
+{
+	if (persistent_group && wpa_s->conf->persistent_reconnect)
+		persistent_group = 2;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return -1;
+
+	return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
+			     go_intent, own_interface_addr, force_freq,
+			     persistent_group, ssid ? ssid->ssid : NULL,
+			     ssid ? ssid->ssid_len : 0, pref_freq);
+}
+
+
+static void wpas_p2p_check_join_scan_limit(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->p2p_join_scan_count++;
+	wpa_printf(MSG_DEBUG, "P2P: Join scan attempt %d",
+		   wpa_s->p2p_join_scan_count);
+	if (wpa_s->p2p_join_scan_count > P2P_MAX_JOIN_SCAN_ATTEMPTS) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to find GO " MACSTR
+			   " for join operationg - stop join attempt",
+			   MAC2STR(wpa_s->pending_join_iface_addr));
+		eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+		if (wpa_s->p2p_auto_pd) {
+			wpa_s->p2p_auto_pd = 0;
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+				" p2p_dev_addr=" MACSTR " status=N/A",
+				MAC2STR(wpa_s->pending_join_dev_addr));
+			return;
+		}
+		wpa_msg(wpa_s->parent, MSG_INFO,
+			P2P_EVENT_GROUP_FORMATION_FAILURE);
+	}
+}
+
+
+static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
+{
+	struct wpa_supplicant *iface;
+	int shared_freq;
+	u8 bssid[ETH_ALEN];
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+		return 0;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
+			continue;
+		if (iface->current_ssid == NULL || iface->assoc_freq == 0)
+			continue;
+		if (iface->current_ssid->mode == WPAS_MODE_AP ||
+		    iface->current_ssid->mode == WPAS_MODE_P2P_GO)
+			shared_freq = iface->current_ssid->frequency;
+		else if (wpa_drv_get_bssid(iface, bssid) == 0)
+			shared_freq = iface->assoc_freq;
+		else
+			shared_freq = 0;
+
+		if (shared_freq && freq != shared_freq) {
+			wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
+				   "connected on %d MHz - new connection on "
+				   "%d MHz", iface->ifname, shared_freq, freq);
+			return 1;
+		}
+	}
+
+	shared_freq = wpa_drv_shared_freq(wpa_s);
+	if (shared_freq > 0 && shared_freq != freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
+			   "virtual interface connected on %d MHz - new "
+			   "connection on %d MHz", shared_freq, freq);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpas_p2p_peer_go(struct wpa_supplicant *wpa_s,
+			    const u8 *peer_dev_addr)
+{
+	struct wpa_bss *bss;
+	int updated;
+
+	bss = wpa_bss_get_p2p_dev_addr(wpa_s, peer_dev_addr);
+	if (bss == NULL)
+		return -1;
+	if (bss->last_update_idx < wpa_s->bss_update_idx) {
+		wpa_printf(MSG_DEBUG, "P2P: Peer BSS entry not updated in the "
+			   "last scan");
+		return 0;
+	}
+
+	updated = os_time_before(&wpa_s->p2p_auto_started, &bss->last_update);
+	wpa_printf(MSG_DEBUG, "P2P: Current BSS entry for peer updated at "
+		   "%ld.%06ld (%supdated in last scan)",
+		   bss->last_update.sec, bss->last_update.usec,
+		   updated ? "": "not ");
+
+	return updated;
+}
+
+
+static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
+				   struct wpa_scan_results *scan_res)
+{
+	struct wpa_bss *bss;
+	int freq;
+	u8 iface_addr[ETH_ALEN];
+
+	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+
+	if (wpa_s->global->p2p_disabled)
+		return;
+
+	wpa_printf(MSG_DEBUG, "P2P: Scan results received (%d BSS) for %sjoin",
+		   scan_res ? (int) scan_res->num : -1,
+		   wpa_s->p2p_auto_join ? "auto_" : "");
+
+	if (scan_res)
+		wpas_p2p_scan_res_handler(wpa_s, scan_res);
+
+	if (wpa_s->p2p_auto_pd) {
+		int join = wpas_p2p_peer_go(wpa_s,
+					    wpa_s->pending_join_dev_addr);
+		if (join == 0 &&
+		    wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
+			wpa_s->auto_pd_scan_retry++;
+			bss = wpa_bss_get_bssid(wpa_s,
+						wpa_s->pending_join_dev_addr);
+			if (bss) {
+				freq = bss->freq;
+				wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
+					   "the peer " MACSTR " at %d MHz",
+					   wpa_s->auto_pd_scan_retry,
+					   MAC2STR(wpa_s->
+						   pending_join_dev_addr),
+					   freq);
+				wpas_p2p_join_scan_req(wpa_s, freq);
+				return;
+			}
+		}
+
+		if (join < 0)
+			join = 0;
+
+		wpa_s->p2p_auto_pd = 0;
+		wpa_s->pending_pd_use = join ? AUTO_PD_JOIN : AUTO_PD_GO_NEG;
+		wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
+			   MAC2STR(wpa_s->pending_join_dev_addr), join);
+		if (p2p_prov_disc_req(wpa_s->global->p2p,
+				      wpa_s->pending_join_dev_addr,
+				      wpa_s->pending_pd_config_methods, join,
+				      0, wpa_s->user_initiated_pd) < 0) {
+			wpa_s->p2p_auto_pd = 0;
+			wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+				" p2p_dev_addr=" MACSTR " status=N/A",
+				MAC2STR(wpa_s->pending_join_dev_addr));
+		}
+		return;
+	}
+
+	if (wpa_s->p2p_auto_join) {
+		int join = wpas_p2p_peer_go(wpa_s,
+					    wpa_s->pending_join_dev_addr);
+		if (join < 0) {
+			wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
+				   "running a GO -> use GO Negotiation");
+			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_persistent_id,
+					 wpa_s->p2p_pd_before_go_neg,
+					 wpa_s->p2p_go_ht40);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> "
+			   "try to join the group", join ? "" :
+			   " in older scan");
+		if (!join)
+			wpa_s->p2p_fallback_to_go_neg = 1;
+	}
+
+	freq = p2p_get_oper_freq(wpa_s->global->p2p,
+				 wpa_s->pending_join_iface_addr);
+	if (freq < 0 &&
+	    p2p_get_interface_addr(wpa_s->global->p2p,
+				   wpa_s->pending_join_dev_addr,
+				   iface_addr) == 0 &&
+	    os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface "
+			   "address for join from " MACSTR " to " MACSTR
+			   " based on newly discovered P2P peer entry",
+			   MAC2STR(wpa_s->pending_join_iface_addr),
+			   MAC2STR(iface_addr));
+		os_memcpy(wpa_s->pending_join_iface_addr, iface_addr,
+			  ETH_ALEN);
+
+		freq = p2p_get_oper_freq(wpa_s->global->p2p,
+					 wpa_s->pending_join_iface_addr);
+	}
+	if (freq >= 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+			   "from P2P peer table: %d MHz", freq);
+	}
+	bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+	if (bss) {
+		freq = bss->freq;
+		wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+			   "from BSS table: %d MHz", freq);
+	}
+	if (freq > 0) {
+		u16 method;
+
+		if (wpas_check_freq_conflict(wpa_s, freq) > 0) {
+			wpa_msg(wpa_s->parent, MSG_INFO,
+				P2P_EVENT_GROUP_FORMATION_FAILURE
+				"reason=FREQ_CONFLICT");
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
+			   "prior to joining an existing group (GO " MACSTR
+			   " freq=%u MHz)",
+			   MAC2STR(wpa_s->pending_join_dev_addr), freq);
+		wpa_s->pending_pd_before_join = 1;
+
+		switch (wpa_s->pending_join_wps_method) {
+		case WPS_PIN_DISPLAY:
+			method = WPS_CONFIG_KEYPAD;
+			break;
+		case WPS_PIN_KEYPAD:
+			method = WPS_CONFIG_DISPLAY;
+			break;
+		case WPS_PBC:
+			method = WPS_CONFIG_PUSHBUTTON;
+			break;
+		default:
+			method = 0;
+			break;
+		}
+
+		if ((p2p_get_provisioning_info(wpa_s->global->p2p,
+					       wpa_s->pending_join_dev_addr) ==
+		     method)) {
+			/*
+			 * We have already performed provision discovery for
+			 * joining the group. Proceed directly to join
+			 * operation without duplicated provision discovery. */
+			wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
+				   "with " MACSTR " already done - proceed to "
+				   "join",
+				   MAC2STR(wpa_s->pending_join_dev_addr));
+			wpa_s->pending_pd_before_join = 0;
+			goto start;
+		}
+
+		if (p2p_prov_disc_req(wpa_s->global->p2p,
+				      wpa_s->pending_join_dev_addr, method, 1,
+				      freq, wpa_s->user_initiated_pd) < 0) {
+			wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
+				   "Discovery Request before joining an "
+				   "existing group");
+			wpa_s->pending_pd_before_join = 0;
+			goto start;
+		}
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Failed to find BSS/GO - try again later");
+	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+	eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+	wpas_p2p_check_join_scan_limit(wpa_s);
+	return;
+
+start:
+	/* Start join operation immediately */
+	wpas_p2p_join_start(wpa_s);
+}
+
+
+static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq)
+{
+	int ret;
+	struct wpa_driver_scan_params params;
+	struct wpabuf *wps_ie, *ies;
+	size_t ielen;
+	int freqs[2] = { 0, 0 };
+
+	os_memset(&params, 0, sizeof(params));
+
+	/* P2P Wildcard SSID */
+	params.num_ssids = 1;
+	params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
+	params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
+
+	wpa_s->wps->dev.p2p = 1;
+	wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
+					wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
+					NULL);
+	if (wps_ie == NULL) {
+		wpas_p2p_scan_res_join(wpa_s, NULL);
+		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 > 0) {
+		freqs[0] = freq;
+		params.freqs = freqs;
+	}
+
+	/*
+	 * Run a scan to update BSS table and start Provision Discovery once
+	 * the new scan results become available.
+	 */
+	ret = wpa_drv_scan(wpa_s, &params);
+	if (!ret)
+		wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+
+	wpabuf_free(ies);
+
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to start scan for join - "
+			   "try again later");
+		eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+		eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
+		wpas_p2p_check_join_scan_limit(wpa_s);
+	}
+}
+
+
+static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpas_p2p_join_scan_req(wpa_s, 0);
+}
+
+
+static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
+			 const u8 *dev_addr, enum p2p_wps_method wps_method,
+			 int auto_join)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Request to join existing group (iface "
+		   MACSTR " dev " MACSTR ")%s",
+		   MAC2STR(iface_addr), MAC2STR(dev_addr),
+		   auto_join ? " (auto_join)" : "");
+
+	wpa_s->p2p_auto_pd = 0;
+	wpa_s->p2p_auto_join = !!auto_join;
+	os_memcpy(wpa_s->pending_join_iface_addr, iface_addr, ETH_ALEN);
+	os_memcpy(wpa_s->pending_join_dev_addr, dev_addr, ETH_ALEN);
+	wpa_s->pending_join_wps_method = wps_method;
+
+	/* Make sure we are not running find during connection establishment */
+	wpas_p2p_stop_find(wpa_s);
+
+	wpa_s->p2p_join_scan_count = 0;
+	wpas_p2p_join_scan(wpa_s, NULL);
+	return 0;
+}
+
+
+static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_supplicant *group;
+	struct p2p_go_neg_results res;
+	struct wpa_bss *bss;
+
+	group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
+	if (group == NULL)
+		return -1;
+	if (group != wpa_s) {
+		os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
+			  sizeof(group->p2p_pin));
+		group->p2p_wps_method = wpa_s->p2p_wps_method;
+	}
+
+	group->p2p_in_provisioning = 1;
+	wpa_s->global->p2p_group_formation = wpa_s;
+	group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
+
+	os_memset(&res, 0, sizeof(res));
+	os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
+		  ETH_ALEN);
+	res.wps_method = wpa_s->pending_join_wps_method;
+	bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+	if (bss) {
+		res.freq = bss->freq;
+		res.ssid_len = bss->ssid_len;
+		os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+	}
+
+	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel prior to "
+			   "starting client");
+		wpa_drv_cancel_remain_on_channel(wpa_s);
+		wpa_s->off_channel_freq = 0;
+		wpa_s->roc_waiting_drv_freq = 0;
+	}
+	wpas_start_wps_enrollee(group, &res);
+
+	/*
+	 * Allow a longer timeout for join-a-running-group than normal 15
+	 * second group formation timeout since the GO may not have authorized
+	 * our connection yet.
+	 */
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+	eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
+			       wpa_s, NULL);
+
+	return 0;
+}
+
+
+/**
+ * wpas_p2p_connect - Request P2P Group Formation to be started
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @peer_addr: Address of the peer P2P Device
+ * @pin: PIN to use during provisioning or %NULL to indicate PBC mode
+ * @persistent_group: Whether to create a persistent group
+ * @auto_join: Whether to select join vs. GO Negotiation automatically
+ * @join: Whether to join an existing group (as a client) instead of starting
+ *	Group Owner negotiation; @peer_addr is BSSID in that case
+ * @auth: Whether to only authorize the connection instead of doing that and
+ *	initiating Group Owner negotiation
+ * @go_intent: GO Intent or -1 to use default
+ * @freq: Frequency for the group or 0 for auto-selection
+ * @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
+ * 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 force_freq = 0, pref_freq = 0, oper_freq = 0;
+	u8 bssid[ETH_ALEN];
+	int ret = 0;
+	enum wpa_driver_if_type iftype;
+	const u8 *if_addr;
+	struct wpa_ssid *ssid = NULL;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	if (persistent_id >= 0) {
+		ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+		if (ssid == NULL || ssid->disabled != 2 ||
+		    ssid->mode != WPAS_MODE_P2P_GO)
+			return -1;
+	}
+
+	if (go_intent < 0)
+		go_intent = wpa_s->conf->p2p_go_intent;
+
+	if (!auth)
+		wpa_s->p2p_long_listen = 0;
+
+	wpa_s->p2p_wps_method = wps_method;
+	wpa_s->p2p_persistent_group = !!persistent_group;
+	wpa_s->p2p_persistent_id = persistent_id;
+	wpa_s->p2p_go_intent = go_intent;
+	wpa_s->p2p_connect_freq = freq;
+	wpa_s->p2p_fallback_to_go_neg = 0;
+	wpa_s->p2p_pd_before_go_neg = !!pd;
+	wpa_s->p2p_go_ht40 = !!ht40;
+
+	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();
+		os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
+			    ret);
+		wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
+			   wpa_s->p2p_pin);
+	} else
+		wpa_s->p2p_pin[0] = '\0';
+
+	if (join || auto_join) {
+		u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
+		if (auth) {
+			wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
+				   "connect a running group from " MACSTR,
+				   MAC2STR(peer_addr));
+			os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+			return ret;
+		}
+		os_memcpy(dev_addr, peer_addr, ETH_ALEN);
+		if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
+					   iface_addr) < 0) {
+			os_memcpy(iface_addr, peer_addr, ETH_ALEN);
+			p2p_get_dev_addr(wpa_s->global->p2p, peer_addr,
+					 dev_addr);
+		}
+		if (auto_join) {
+			os_get_time(&wpa_s->p2p_auto_started);
+			wpa_printf(MSG_DEBUG, "P2P: Auto join started at "
+				   "%ld.%06ld",
+				   wpa_s->p2p_auto_started.sec,
+				   wpa_s->p2p_auto_started.usec);
+		}
+		wpa_s->user_initiated_pd = 1;
+		if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
+				  auto_join) < 0)
+			return -1;
+		return ret;
+	}
+
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+	    wpa_s->assoc_freq)
+		oper_freq = wpa_s->assoc_freq;
+	else {
+		oper_freq = wpa_drv_shared_freq(wpa_s);
+		if (oper_freq < 0)
+			oper_freq = 0;
+	}
+
+	if (freq > 0) {
+		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+				   "(%u MHz) is not supported for P2P uses",
+				   freq);
+			return -3;
+		}
+
+		if (oper_freq > 0 && freq != oper_freq &&
+		    !(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "on %u MHz while connected on another "
+				   "channel (%u MHz)", freq, oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+			   "requested channel (%u MHz)", freq);
+		force_freq = freq;
+	} else if (oper_freq > 0 &&
+		   !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
+		if (!(wpa_s->drv_flags &
+		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+				   "while connected on non-P2P supported "
+				   "channel (%u MHz)", oper_freq);
+			return -2;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+			   "(%u MHz) not available for P2P - try to use "
+			   "another channel", oper_freq);
+		force_freq = 0;
+	} else if (oper_freq > 0 &&
+		   (wpa_s->drv_flags &
+		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+			   "are already using (%u MHz) on another interface",
+			   oper_freq);
+		pref_freq = oper_freq;
+	} else if (oper_freq > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+			   "channel we are already using (%u MHz) on another "
+			   "interface", oper_freq);
+		force_freq = oper_freq;
+	}
+
+	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+
+	if (wpa_s->create_p2p_iface) {
+		/* Prepare to add a new interface for the group */
+		iftype = WPA_IF_P2P_GROUP;
+		if (go_intent == 15)
+			iftype = WPA_IF_P2P_GO;
+		if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+				   "interface for the group");
+			return -1;
+		}
+
+		if_addr = wpa_s->pending_interface_addr;
+	} else
+		if_addr = wpa_s->own_addr;
+
+	if (auth) {
+		if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
+					 go_intent, if_addr,
+					 force_freq, persistent_group, ssid,
+					 pref_freq) < 0)
+			return -1;
+		return ret;
+	}
+
+	if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
+				  go_intent, if_addr, force_freq,
+				  persistent_group, ssid, pref_freq) < 0) {
+		if (wpa_s->create_p2p_iface)
+			wpas_p2p_remove_pending_group_interface(wpa_s);
+		return -1;
+	}
+	return ret;
+}
+
+
+/**
+ * wpas_p2p_remain_on_channel_cb - Indication of remain-on-channel start
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @freq: Frequency of the channel in MHz
+ * @duration: Duration of the stay on the channel in milliseconds
+ *
+ * This callback is called when the driver indicates that it has started the
+ * requested remain-on-channel duration.
+ */
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+	if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+		p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
+			      wpa_s->pending_listen_duration);
+		wpa_s->pending_listen_freq = 0;
+	}
+}
+
+
+static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s,
+				 unsigned int timeout)
+{
+	/* Limit maximum Listen state time based on driver limitation. */
+	if (timeout > wpa_s->max_remain_on_chan)
+		timeout = wpa_s->max_remain_on_chan;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_listen(wpa_s, timeout);
+
+	return p2p_listen(wpa_s->global->p2p, timeout);
+}
+
+
+/**
+ * wpas_p2p_cancel_remain_on_channel_cb - Remain-on-channel timeout
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @freq: Frequency of the channel in MHz
+ *
+ * This callback is called when the driver indicates that a remain-on-channel
+ * operation has been completed, i.e., the duration on the requested channel
+ * has timed out.
+ */
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					  unsigned int freq)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
+		   "(p2p_long_listen=%d ms pending_action_tx=%p)",
+		   wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+	if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
+		return; /* P2P module started a new operation */
+	if (offchannel_pending_action_tx(wpa_s))
+		return;
+	if (wpa_s->p2p_long_listen > 0)
+		wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
+	if (wpa_s->p2p_long_listen > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
+		wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+	}
+}
+
+
+/**
+ * wpas_p2p_group_remove - Remove a P2P group
+ * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
+ * @ifname: Network interface name of the group interface or "*" to remove all
+ *	groups
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to remove a P2P group. This can be used to disconnect
+ * from a group in which the local end is a P2P Client or to end a P2P Group in
+ * case the local end is the Group Owner. If a virtual network interface was
+ * created for this group, that interface will be removed. Otherwise, only the
+ * configured P2P group network will be removed from the interface.
+ */
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
+{
+	struct wpa_global *global = wpa_s->global;
+
+	if (os_strcmp(ifname, "*") == 0) {
+		struct wpa_supplicant *prev;
+		wpa_s = global->ifaces;
+		while (wpa_s) {
+			prev = wpa_s;
+			wpa_s = wpa_s->next;
+			wpas_p2p_disconnect(prev);
+		}
+		return 0;
+	}
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->ifname, ifname) == 0)
+			break;
+	}
+
+	return wpas_p2p_disconnect(wpa_s);
+}
+
+
+static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
+				   struct p2p_go_neg_results *params,
+				   int freq, int ht40)
+{
+	u8 bssid[ETH_ALEN];
+	int res;
+
+	os_memset(params, 0, sizeof(*params));
+	params->role_go = 1;
+	params->ht40 = ht40;
+	if (freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
+			   "frequency %d MHz", freq);
+		params->freq = freq;
+	} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
+		   wpa_s->conf->p2p_oper_channel >= 1 &&
+		   wpa_s->conf->p2p_oper_channel <= 11) {
+		params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+			   "frequency %d MHz", params->freq);
+	} else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
+		   wpa_s->conf->p2p_oper_reg_class == 124) {
+		params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+			   "frequency %d MHz", params->freq);
+	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
+		   wpa_s->best_overall_freq > 0 &&
+		   p2p_supported_freq(wpa_s->global->p2p,
+				      wpa_s->best_overall_freq)) {
+		params->freq = wpa_s->best_overall_freq;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
+			   "channel %d MHz", params->freq);
+	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
+		   wpa_s->best_24_freq > 0 &&
+		   p2p_supported_freq(wpa_s->global->p2p,
+				      wpa_s->best_24_freq)) {
+		params->freq = wpa_s->best_24_freq;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
+			   "channel %d MHz", params->freq);
+	} else if (wpa_s->conf->p2p_oper_channel == 0 &&
+		   wpa_s->best_5_freq > 0 &&
+		   p2p_supported_freq(wpa_s->global->p2p,
+				      wpa_s->best_5_freq)) {
+		params->freq = wpa_s->best_5_freq;
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
+			   "channel %d MHz", params->freq);
+	} else {
+		int chan;
+		for (chan = 0; chan < 11; chan++) {
+			params->freq = 2412 + chan * 5;
+			if (!wpas_p2p_disallowed_freq(wpa_s->global,
+						      params->freq))
+				break;
+		}
+		if (chan == 11) {
+			wpa_printf(MSG_DEBUG, "P2P: No 2.4 GHz channel "
+				   "allowed");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
+			   "known)", params->freq);
+	}
+
+	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+	    wpa_s->assoc_freq && !freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
+			   "already using");
+		params->freq = wpa_s->assoc_freq;
+	}
+
+	res = wpa_drv_shared_freq(wpa_s);
+	if (res > 0 && !freq) {
+		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
+			   "already using on a shared interface");
+		params->freq = res;
+	} else if (res > 0 && freq != res &&
+		   !(wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
+			   "while connected on another channel (%u MHz)",
+			   freq, res);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpa_supplicant *
+wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
+			 int go)
+{
+	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");
+		return wpa_s;
+	}
+
+	if (wpas_p2p_add_group_interface(wpa_s, go ? WPA_IF_P2P_GO :
+					 WPA_IF_P2P_CLIENT) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to add group interface");
+		return NULL;
+	}
+	group_wpa_s = wpas_p2p_init_group_interface(wpa_s, go);
+	if (group_wpa_s == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to initialize group "
+			"interface");
+		wpas_p2p_remove_pending_group_interface(wpa_s);
+		return NULL;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
+		group_wpa_s->ifname);
+	return group_wpa_s;
+}
+
+
+/**
+ * wpas_p2p_group_add - Add a new P2P group with local end as Group Owner
+ * @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
+ * 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)
+{
+	struct p2p_go_neg_results params;
+	unsigned int r;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	/* Make sure we are not running find during connection establishment */
+	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
+	wpas_p2p_stop_find_oper(wpa_s);
+
+	if (freq == 2) {
+		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+			   "band");
+		if (wpa_s->best_24_freq > 0 &&
+		    p2p_supported_freq(wpa_s->global->p2p,
+				       wpa_s->best_24_freq)) {
+			freq = wpa_s->best_24_freq;
+			wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+				   "channel: %d MHz", freq);
+		} else {
+			os_get_random((u8 *) &r, sizeof(r));
+			freq = 2412 + (r % 3) * 25;
+			wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+				   "channel: %d MHz", freq);
+		}
+	}
+
+	if (freq == 5) {
+		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+			   "band");
+		if (wpa_s->best_5_freq > 0 &&
+		    p2p_supported_freq(wpa_s->global->p2p,
+				       wpa_s->best_5_freq)) {
+			freq = wpa_s->best_5_freq;
+			wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+				   "channel: %d MHz", freq);
+		} else {
+			os_get_random((u8 *) &r, sizeof(r));
+			freq = 5180 + (r % 4) * 20;
+			if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+				wpa_printf(MSG_DEBUG, "P2P: Could not select "
+					   "5 GHz channel for P2P group");
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+				   "channel: %d MHz", freq);
+		}
+	}
+
+	if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+		wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+			   "(%u MHz) is not supported for P2P uses",
+			   freq);
+		return -1;
+	}
+
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
+		return -1;
+	if (params.freq &&
+	    !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+		wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
+			   "(%u MHz) is not supported for P2P uses",
+			   params.freq);
+		return -1;
+	}
+	p2p_go_params(wpa_s->global->p2p, &params);
+	params.persistent_group = persistent_group;
+
+	wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1);
+	if (wpa_s == NULL)
+		return -1;
+	wpas_start_wps_go(wpa_s, &params, 0);
+
+	return 0;
+}
+
+
+static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *params, int addr_allocated)
+{
+	struct wpa_ssid *ssid;
+
+	wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
+	if (wpa_s == NULL)
+		return -1;
+
+	wpa_supplicant_ap_deinit(wpa_s);
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return -1;
+	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->key_mgmt = WPA_KEY_MGMT_PSK;
+	ssid->ssid = os_malloc(params->ssid_len);
+	if (ssid->ssid == NULL) {
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+		return -1;
+	}
+	os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
+	ssid->ssid_len = params->ssid_len;
+	ssid->p2p_group = 1;
+	ssid->export_keys = 1;
+	if (params->psk_set) {
+		os_memcpy(ssid->psk, params->psk, 32);
+		ssid->psk_set = 1;
+	}
+	if (params->passphrase)
+		ssid->passphrase = os_strdup(params->passphrase);
+
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	wpa_s->show_group_started = 1;
+
+	return 0;
+}
+
+
+int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid, int addr_allocated,
+				  int freq, int ht40)
+{
+	struct p2p_go_neg_results params;
+	int go = 0;
+
+	if (ssid->disabled != 2 || ssid->ssid == NULL)
+		return -1;
+
+	if (wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go) &&
+	    go == (ssid->mode == WPAS_MODE_P2P_GO)) {
+		wpa_printf(MSG_DEBUG, "P2P: Requested persistent group is "
+			   "already running");
+		return 0;
+	}
+
+	/* Make sure we are not running find during connection establishment */
+	wpas_p2p_stop_find_oper(wpa_s);
+
+	wpa_s->p2p_fallback_to_go_neg = 0;
+
+	if (ssid->mode == WPAS_MODE_INFRA)
+		return wpas_start_p2p_client(wpa_s, ssid, addr_allocated);
+
+	if (ssid->mode != WPAS_MODE_P2P_GO)
+		return -1;
+
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40))
+		return -1;
+
+	params.role_go = 1;
+	params.psk_set = ssid->psk_set;
+	if (params.psk_set)
+		os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
+	if (ssid->passphrase) {
+		if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
+			wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
+				   "persistent group");
+			return -1;
+		}
+		os_strlcpy(params.passphrase, ssid->passphrase,
+			   sizeof(params.passphrase));
+	}
+	os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
+	params.ssid_len = ssid->ssid_len;
+	params.persistent_group = 1;
+
+	wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1);
+	if (wpa_s == NULL)
+		return -1;
+
+	wpas_start_wps_go(wpa_s, &params, 0);
+
+	return 0;
+}
+
+
+static void wpas_p2p_ie_update(void *ctx, struct wpabuf *beacon_ies,
+			       struct wpabuf *proberesp_ies)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->ap_iface) {
+		struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+		if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) {
+			wpabuf_free(beacon_ies);
+			wpabuf_free(proberesp_ies);
+			return;
+		}
+		if (beacon_ies) {
+			wpabuf_free(hapd->p2p_beacon_ie);
+			hapd->p2p_beacon_ie = beacon_ies;
+		}
+		wpabuf_free(hapd->p2p_probe_resp_ie);
+		hapd->p2p_probe_resp_ie = proberesp_ies;
+	} else {
+		wpabuf_free(beacon_ies);
+		wpabuf_free(proberesp_ies);
+	}
+	wpa_supplicant_ap_update_beacon(wpa_s);
+}
+
+
+static void wpas_p2p_idle_update(void *ctx, int idle)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (!wpa_s->ap_iface)
+		return;
+	wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
+	if (idle)
+		wpas_p2p_set_group_idle_timeout(wpa_s);
+	else
+		eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
+}
+
+
+struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid)
+{
+	struct p2p_group *group;
+	struct p2p_group_config *cfg;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return NULL;
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return NULL;
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		return NULL;
+
+	if (ssid->p2p_persistent_group && wpa_s->conf->persistent_reconnect)
+		cfg->persistent_group = 2;
+	else if (ssid->p2p_persistent_group)
+		cfg->persistent_group = 1;
+	os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
+	if (wpa_s->max_stations &&
+	    wpa_s->max_stations < wpa_s->conf->max_num_sta)
+		cfg->max_clients = wpa_s->max_stations;
+	else
+		cfg->max_clients = wpa_s->conf->max_num_sta;
+	os_memcpy(cfg->ssid, ssid->ssid, ssid->ssid_len);
+	cfg->ssid_len = ssid->ssid_len;
+	cfg->cb_ctx = wpa_s;
+	cfg->ie_update = wpas_p2p_ie_update;
+	cfg->idle_update = wpas_p2p_idle_update;
+
+	group = p2p_group_init(wpa_s->global->p2p, cfg);
+	if (group == NULL)
+		os_free(cfg);
+	if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+		p2p_group_notif_formation_done(group);
+	wpa_s->p2p_group = group;
+	return group;
+}
+
+
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+			  int registrar)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (!wpa_s->p2p_in_provisioning) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore WPS success event - P2P "
+			   "provisioning not in progress");
+		return;
+	}
+
+	if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+		u8 go_dev_addr[ETH_ALEN];
+		os_memcpy(go_dev_addr, wpa_s->bssid, ETH_ALEN);
+		wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+					  ssid->ssid_len);
+		/* Clear any stored provisioning info */
+		p2p_clear_provisioning_info(wpa_s->global->p2p, go_dev_addr);
+	}
+
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
+			     NULL);
+	if (ssid && ssid->mode == WPAS_MODE_INFRA) {
+		/*
+		 * Use a separate timeout for initial data connection to
+		 * complete to allow the group to be removed automatically if
+		 * something goes wrong in this step before the P2P group idle
+		 * timeout mechanism is taken into use.
+		 */
+		eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+				       wpas_p2p_group_formation_timeout,
+				       wpa_s->parent, NULL);
+	}
+	if (wpa_s->global->p2p)
+		p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
+	else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		wpa_drv_wps_success_cb(wpa_s, peer_addr);
+	wpas_group_formation_completed(wpa_s, 1);
+}
+
+
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail)
+{
+	if (!wpa_s->p2p_in_provisioning) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore WPS fail event - P2P "
+			   "provisioning not in progress");
+		return;
+	}
+
+	if (wpa_s->go_params) {
+		p2p_clear_provisioning_info(
+			wpa_s->global->p2p,
+			wpa_s->go_params->peer_device_addr);
+	}
+
+	wpas_notify_p2p_wps_failed(wpa_s, fail);
+}
+
+
+int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		       const char *config_method,
+		       enum wpas_p2p_prov_disc_use use)
+{
+	u16 config_methods;
+
+	wpa_s->p2p_fallback_to_go_neg = 0;
+	wpa_s->pending_pd_use = NORMAL_PD;
+	if (os_strncmp(config_method, "display", 7) == 0)
+		config_methods = WPS_CONFIG_DISPLAY;
+	else if (os_strncmp(config_method, "keypad", 6) == 0)
+		config_methods = WPS_CONFIG_KEYPAD;
+	else if (os_strncmp(config_method, "pbc", 3) == 0 ||
+		 os_strncmp(config_method, "pushbutton", 10) == 0)
+		config_methods = WPS_CONFIG_PUSHBUTTON;
+	else {
+		wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+		return -1;
+	}
+
+	if (use == WPAS_P2P_PD_AUTO) {
+		os_memcpy(wpa_s->pending_join_dev_addr, peer_addr, ETH_ALEN);
+		wpa_s->pending_pd_config_methods = config_methods;
+		wpa_s->p2p_auto_pd = 1;
+		wpa_s->p2p_auto_join = 0;
+		wpa_s->pending_pd_before_join = 0;
+		wpa_s->auto_pd_scan_retry = 0;
+		wpas_p2p_stop_find(wpa_s);
+		wpa_s->p2p_join_scan_count = 0;
+		os_get_time(&wpa_s->p2p_auto_started);
+		wpa_printf(MSG_DEBUG, "P2P: Auto PD started at %ld.%06ld",
+			   wpa_s->p2p_auto_started.sec,
+			   wpa_s->p2p_auto_started.usec);
+		wpas_p2p_join_scan(wpa_s, NULL);
+		return 0;
+	}
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
+						 config_methods,
+						 use == WPAS_P2P_PD_FOR_JOIN);
+	}
+
+	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+		return -1;
+
+	return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
+				 config_methods, use == WPAS_P2P_PD_FOR_JOIN,
+				 0, 1);
+}
+
+
+int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			      char *end)
+{
+	return p2p_scan_result_text(ies, ies_len, buf, end);
+}
+
+
+static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+	if (!offchannel_pending_action_tx(wpa_s))
+		return;
+
+	wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
+		   "operation request");
+	offchannel_clear_pending_action_tx(wpa_s);
+}
+
+
+int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
+		  enum p2p_discovery_type type,
+		  unsigned int num_req_dev_types, const u8 *req_dev_types,
+		  const u8 *dev_id, unsigned int search_delay)
+{
+	wpas_p2p_clear_pending_action_tx(wpa_s);
+	wpa_s->p2p_long_listen = 0;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_find(wpa_s, timeout, type);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+	    wpa_s->p2p_in_provisioning)
+		return -1;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+
+	return p2p_find(wpa_s->global->p2p, timeout, type,
+			num_req_dev_types, req_dev_types, dev_id,
+			search_delay);
+}
+
+
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+{
+	wpas_p2p_clear_pending_action_tx(wpa_s);
+	wpa_s->p2p_long_listen = 0;
+	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+	wpa_s->global->p2p_cb_on_scan_complete = 0;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
+		wpa_drv_p2p_stop_find(wpa_s);
+		return 1;
+	}
+
+	if (wpa_s->global->p2p)
+		p2p_stop_find(wpa_s->global->p2p);
+
+	return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+		return;
+	wpas_p2p_remove_pending_group_interface(wpa_s);
+}
+
+
+static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_s->p2p_long_listen = 0;
+}
+
+
+int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout)
+{
+	int res;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpas_p2p_clear_pending_action_tx(wpa_s);
+
+	if (timeout == 0) {
+		/*
+		 * This is a request for unlimited Listen state. However, at
+		 * least for now, this is mapped to a Listen state for one
+		 * hour.
+		 */
+		timeout = 3600;
+	}
+	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
+	wpa_s->p2p_long_listen = 0;
+
+	/*
+	 * Stop previous find/listen operation to avoid trying to request a new
+	 * remain-on-channel operation while the driver is still running the
+	 * previous one.
+	 */
+	if (wpa_s->global->p2p)
+		p2p_stop_find(wpa_s->global->p2p);
+
+	res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
+	if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
+		wpa_s->p2p_long_listen = timeout * 1000;
+		eloop_register_timeout(timeout, 0,
+				       wpas_p2p_long_listen_timeout,
+				       wpa_s, NULL);
+	}
+
+	return res;
+}
+
+
+int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			  u8 *buf, size_t len, int p2p_group)
+{
+	struct wpabuf *p2p_ie;
+	int ret;
+
+	if (wpa_s->global->p2p_disabled)
+		return -1;
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+	if (bss == NULL)
+		return -1;
+
+	p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+	ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
+			       p2p_group, p2p_ie);
+	wpabuf_free(p2p_ie);
+
+	return ret;
+}
+
+
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
+			  const u8 *ie, size_t ie_len, int ssi_signal)
+{
+	if (wpa_s->global->p2p_disabled)
+		return 0;
+	if (wpa_s->global->p2p == NULL)
+		return 0;
+
+	switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+				 ie, ie_len)) {
+	case P2P_PREQ_NOT_P2P:
+		wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
+				 ssi_signal);
+		/* fall through */
+	case P2P_PREQ_MALFORMED:
+	case P2P_PREQ_NOT_LISTEN:
+	case P2P_PREQ_NOT_PROCESSED:
+	default: /* make gcc happy */
+		return 0;
+	case P2P_PREQ_PROCESSED:
+		return 1;
+	}
+}
+
+
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *bssid,
+			u8 category, const u8 *data, size_t len, int freq)
+{
+	if (wpa_s->global->p2p_disabled)
+		return;
+	if (wpa_s->global->p2p == NULL)
+		return;
+
+	p2p_rx_action(wpa_s->global->p2p, da, sa, bssid, category, data, len,
+		      freq);
+}
+
+
+void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies)
+{
+	if (wpa_s->global->p2p_disabled)
+		return;
+	if (wpa_s->global->p2p == NULL)
+		return;
+
+	p2p_scan_ie(wpa_s->global->p2p, ies, NULL);
+}
+
+
+void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s)
+{
+	p2p_group_deinit(wpa_s->p2p_group);
+	wpa_s->p2p_group = NULL;
+
+	wpa_s->ap_configured_cb = NULL;
+	wpa_s->ap_configured_cb_ctx = NULL;
+	wpa_s->ap_configured_cb_data = NULL;
+	wpa_s->connect_without_scan = NULL;
+}
+
+
+int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	wpa_s->p2p_long_listen = 0;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_reject(wpa_s, addr);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	return p2p_reject(wpa_s->global->p2p, addr);
+}
+
+
+/* Invite to reinvoke a persistent group */
+int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+		    int ht40)
+{
+	enum p2p_invite_role role;
+	u8 *bssid = NULL;
+
+	wpa_s->p2p_persistent_go_freq = freq;
+	wpa_s->p2p_go_ht40 = !!ht40;
+	if (ssid->mode == WPAS_MODE_P2P_GO) {
+		role = P2P_INVITE_ROLE_GO;
+		if (peer_addr == NULL) {
+			wpa_printf(MSG_DEBUG, "P2P: Missing peer "
+				   "address in invitation command");
+			return -1;
+		}
+		if (wpas_p2p_create_iface(wpa_s)) {
+			if (wpas_p2p_add_group_interface(wpa_s,
+							 WPA_IF_P2P_GO) < 0) {
+				wpa_printf(MSG_ERROR, "P2P: Failed to "
+					   "allocate a new interface for the "
+					   "group");
+				return -1;
+			}
+			bssid = wpa_s->pending_interface_addr;
+		} else
+			bssid = wpa_s->own_addr;
+	} else {
+		role = P2P_INVITE_ROLE_CLIENT;
+		peer_addr = ssid->bssid;
+	}
+	wpa_s->pending_invite_ssid_id = ssid->id;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+					  ssid->ssid, ssid->ssid_len,
+					  go_dev_addr, 1);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+			  ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+}
+
+
+/* Invite to join an active group */
+int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
+			  const u8 *peer_addr, const u8 *go_dev_addr)
+{
+	struct wpa_global *global = wpa_s->global;
+	enum p2p_invite_role role;
+	u8 *bssid = NULL;
+	struct wpa_ssid *ssid;
+	int persistent;
+
+	wpa_s->p2p_persistent_go_freq = 0;
+	wpa_s->p2p_go_ht40 = 0;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->ifname, ifname) == 0)
+			break;
+	}
+	if (wpa_s == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: Interface '%s' not found", ifname);
+		return -1;
+	}
+
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "P2P: No current SSID to use for "
+			   "invitation");
+		return -1;
+	}
+
+	persistent = ssid->p2p_persistent_group &&
+		wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
+					ssid->ssid, ssid->ssid_len);
+
+	if (ssid->mode == WPAS_MODE_P2P_GO) {
+		role = P2P_INVITE_ROLE_ACTIVE_GO;
+		bssid = wpa_s->own_addr;
+		if (go_dev_addr == NULL)
+			go_dev_addr = wpa_s->global->p2p_dev_addr;
+	} else {
+		role = P2P_INVITE_ROLE_CLIENT;
+		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+			wpa_printf(MSG_DEBUG, "P2P: Not associated - cannot "
+				   "invite to current group");
+			return -1;
+		}
+		bssid = wpa_s->bssid;
+		if (go_dev_addr == NULL &&
+		    !is_zero_ether_addr(wpa_s->go_dev_addr))
+			go_dev_addr = wpa_s->go_dev_addr;
+	}
+	wpa_s->parent->pending_invite_ssid_id = -1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
+					  ssid->ssid, ssid->ssid_len,
+					  go_dev_addr, persistent);
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
+			  ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
+			  go_dev_addr, persistent);
+}
+
+
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *ssid_txt;
+	u8 go_dev_addr[ETH_ALEN];
+	int network_id = -1;
+	int persistent;
+	int freq;
+
+	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) {
+		eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+				     wpa_s->parent, NULL);
+	}
+
+	if (!wpa_s->show_group_started || !ssid)
+		goto done;
+
+	wpa_s->show_group_started = 0;
+
+	ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+	os_memset(go_dev_addr, 0, ETH_ALEN);
+	if (ssid->bssid_set)
+		os_memcpy(go_dev_addr, ssid->bssid, ETH_ALEN);
+	persistent = wpas_p2p_persistent_group(wpa_s, go_dev_addr, ssid->ssid,
+					       ssid->ssid_len);
+	os_memcpy(wpa_s->go_dev_addr, go_dev_addr, ETH_ALEN);
+
+	if (wpa_s->global->p2p_group_formation == wpa_s)
+		wpa_s->global->p2p_group_formation = NULL;
+
+	freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+		(int) wpa_s->assoc_freq;
+	if (ssid->passphrase == NULL && ssid->psk_set) {
+		char psk[65];
+		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
+		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			"%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+			MACSTR "%s",
+			wpa_s->ifname, ssid_txt, freq, psk,
+			MAC2STR(go_dev_addr),
+			persistent ? " [PERSISTENT]" : "");
+	} else {
+		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+			"%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
+			"go_dev_addr=" MACSTR "%s",
+			wpa_s->ifname, ssid_txt, freq,
+			ssid->passphrase ? ssid->passphrase : "",
+			MAC2STR(go_dev_addr),
+			persistent ? " [PERSISTENT]" : "");
+	}
+
+	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);
+
+done:
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after successful connection");
+			p2p_increase_search_delay(
+				wpa_s->global->p2p,
+				wpas_p2p_search_delay(wpa_s));
+		}
+	}
+}
+
+
+int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
+			  u32 interval1, u32 duration2, u32 interval2)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return -1;
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+	    wpa_s->current_ssid == NULL ||
+	    wpa_s->current_ssid->mode != WPAS_MODE_INFRA)
+		return -1;
+
+	return p2p_presence_req(wpa_s->global->p2p, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->assoc_freq,
+				duration1, interval1, duration2, interval2);
+}
+
+
+int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
+			unsigned int interval)
+{
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return -1;
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+
+	return p2p_ext_listen(wpa_s->global->p2p, period, interval);
+}
+
+
+static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->current_ssid == NULL) {
+		/*
+		 * current_ssid can be cleared when P2P client interface gets
+		 * disconnected, so assume this interface was used as P2P
+		 * client.
+		 */
+		return 1;
+	}
+	return wpa_s->current_ssid->p2p_group &&
+		wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
+
+
+static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) {
+		wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
+			   "disabled");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
+		   "group");
+	wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
+}
+
+
+static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
+{
+	int timeout;
+
+	if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+
+	if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
+		return;
+
+	timeout = wpa_s->conf->p2p_group_idle;
+	if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+	    (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE))
+	    timeout = P2P_MAX_CLIENT_IDLE;
+
+	if (timeout == 0)
+		return;
+
+	if (timeout < 0) {
+		if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA)
+			timeout = 0; /* special client mode no-timeout */
+		else
+			return;
+	}
+
+	if (wpa_s->p2p_in_provisioning) {
+		/*
+		 * Use the normal group formation timeout during the
+		 * provisioning phase to avoid terminating this process too
+		 * early due to group idle timeout.
+		 */
+		wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+			   "during provisioning");
+		return;
+	}
+
+	if (wpa_s->show_group_started) {
+		/*
+		 * Use the normal group formation timeout between the end of
+		 * the provisioning phase and completion of 4-way handshake to
+		 * avoid terminating this process too early due to group idle
+		 * timeout.
+		 */
+		wpa_printf(MSG_DEBUG, "P2P: Do not use P2P group idle timeout "
+			   "while waiting for initial 4-way handshake to "
+			   "complete");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
+		   timeout);
+	eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
+			       wpa_s, NULL);
+}
+
+
+/* Returns 1 if the interface was removed */
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			  u16 reason_code, const u8 *ie, size_t ie_len,
+			  int locally_generated)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return 0;
+
+	if (!locally_generated)
+		p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+				 ie_len);
+
+	if (reason_code == WLAN_REASON_DEAUTH_LEAVING && !locally_generated &&
+	    wpa_s->current_ssid &&
+	    wpa_s->current_ssid->p2p_group &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
+		wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
+			   "session is ending");
+		if (wpas_p2p_group_delete(wpa_s,
+					  P2P_GROUP_REMOVAL_GO_ENDING_SESSION)
+		    > 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     u16 reason_code, const u8 *ie, size_t ie_len,
+			     int locally_generated)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return;
+
+	if (!locally_generated)
+		p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie,
+				   ie_len);
+}
+
+
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
+{
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	if (p2p == NULL)
+		return;
+
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+		return;
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
+		p2p_set_dev_name(p2p, wpa_s->conf->device_name);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
+		p2p_set_pri_dev_type(p2p, wpa_s->conf->device_type);
+
+	if (wpa_s->wps &&
+	    (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS))
+		p2p_set_config_methods(p2p, wpa_s->wps->config_methods);
+
+	if (wpa_s->wps && (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID))
+		p2p_set_uuid(p2p, wpa_s->wps->uuid);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_WPS_STRING) {
+		p2p_set_manufacturer(p2p, wpa_s->conf->manufacturer);
+		p2p_set_model_name(p2p, wpa_s->conf->model_name);
+		p2p_set_model_number(p2p, wpa_s->conf->model_number);
+		p2p_set_serial_number(p2p, wpa_s->conf->serial_number);
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE)
+		p2p_set_sec_dev_types(p2p,
+				      (void *) wpa_s->conf->sec_device_type,
+				      wpa_s->conf->num_sec_device_types);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) {
+		int i;
+		p2p_remove_wps_vendor_extensions(p2p);
+		for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
+			if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+				continue;
+			p2p_add_wps_vendor_extension(
+				p2p, wpa_s->conf->wps_vendor_ext[i]);
+		}
+	}
+
+	if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+	    wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+		char country[3];
+		country[0] = wpa_s->conf->country[0];
+		country[1] = wpa_s->conf->country[1];
+		country[2] = 0x04;
+		p2p_set_country(p2p, country);
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_SSID_POSTFIX) {
+		p2p_set_ssid_postfix(p2p, (u8 *) wpa_s->conf->p2p_ssid_postfix,
+				     wpa_s->conf->p2p_ssid_postfix ?
+				     os_strlen(wpa_s->conf->p2p_ssid_postfix) :
+				     0);
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
+		p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_LISTEN_CHANNEL) {
+		u8 reg_class, channel;
+		int ret;
+		unsigned int r;
+		if (wpa_s->conf->p2p_listen_reg_class &&
+		    wpa_s->conf->p2p_listen_channel) {
+			reg_class = wpa_s->conf->p2p_listen_reg_class;
+			channel = wpa_s->conf->p2p_listen_channel;
+		} else {
+			reg_class = 81;
+			/*
+			 * Pick one of the social channels randomly as the
+			 * listen channel.
+			 */
+			os_get_random((u8 *) &r, sizeof(r));
+			channel = 1 + (r % 3) * 5;
+		}
+		ret = p2p_set_listen_channel(p2p, reg_class, channel);
+		if (ret)
+			wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
+				   "failed: %d", ret);
+	}
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_OPER_CHANNEL) {
+		u8 op_reg_class, op_channel, cfg_op_channel;
+		int ret = 0;
+		unsigned int r;
+		if (wpa_s->conf->p2p_oper_reg_class &&
+		    wpa_s->conf->p2p_oper_channel) {
+			op_reg_class = wpa_s->conf->p2p_oper_reg_class;
+			op_channel = wpa_s->conf->p2p_oper_channel;
+			cfg_op_channel = 1;
+		} else {
+			op_reg_class = 81;
+			/*
+			 * Use random operation channel from (1, 6, 11)
+			 *if no other preference is indicated.
+			 */
+			os_get_random((u8 *) &r, sizeof(r));
+			op_channel = 1 + (r % 3) * 5;
+			cfg_op_channel = 0;
+		}
+		ret = p2p_set_oper_channel(p2p, op_reg_class, op_channel,
+					   cfg_op_channel);
+		if (ret)
+			wpa_printf(MSG_ERROR, "P2P: Own oper channel update "
+				   "failed: %d", ret);
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_PREF_CHAN) {
+		if (p2p_set_pref_chan(p2p, wpa_s->conf->num_p2p_pref_chan,
+				      wpa_s->conf->p2p_pref_chan) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
+				   "update failed");
+		}
+	}
+}
+
+
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+		     int duration)
+{
+	if (!wpa_s->ap_iface)
+		return -1;
+	return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
+				   duration);
+}
+
+
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return -1;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+		return -1;
+
+	wpa_s->global->cross_connection = enabled;
+	p2p_set_cross_connect(wpa_s->global->p2p, enabled);
+
+	if (!enabled) {
+		struct wpa_supplicant *iface;
+
+		for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
+		{
+			if (iface->cross_connect_enabled == 0)
+				continue;
+
+			iface->cross_connect_enabled = 0;
+			iface->cross_connect_in_use = 0;
+			wpa_msg(iface->parent, MSG_INFO,
+				P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+				iface->ifname, iface->cross_connect_uplink);
+		}
+	}
+
+	return 0;
+}
+
+
+static void wpas_p2p_enable_cross_connect(struct wpa_supplicant *uplink)
+{
+	struct wpa_supplicant *iface;
+
+	if (!uplink->global->cross_connection)
+		return;
+
+	for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+		if (!iface->cross_connect_enabled)
+			continue;
+		if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+		    0)
+			continue;
+		if (iface->ap_iface == NULL)
+			continue;
+		if (iface->cross_connect_in_use)
+			continue;
+
+		iface->cross_connect_in_use = 1;
+		wpa_msg(iface->parent, MSG_INFO,
+			P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+			iface->ifname, iface->cross_connect_uplink);
+	}
+}
+
+
+static void wpas_p2p_disable_cross_connect(struct wpa_supplicant *uplink)
+{
+	struct wpa_supplicant *iface;
+
+	for (iface = uplink->global->ifaces; iface; iface = iface->next) {
+		if (!iface->cross_connect_enabled)
+			continue;
+		if (os_strcmp(uplink->ifname, iface->cross_connect_uplink) !=
+		    0)
+			continue;
+		if (!iface->cross_connect_in_use)
+			continue;
+
+		wpa_msg(iface->parent, MSG_INFO,
+			P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
+			iface->ifname, iface->cross_connect_uplink);
+		iface->cross_connect_in_use = 0;
+	}
+}
+
+
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->ap_iface || wpa_s->current_ssid == NULL ||
+	    wpa_s->current_ssid->mode != WPAS_MODE_INFRA ||
+	    wpa_s->cross_connect_disallowed)
+		wpas_p2p_disable_cross_connect(wpa_s);
+	else
+		wpas_p2p_enable_cross_connect(wpa_s);
+	if (!wpa_s->ap_iface &&
+	    eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
+		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+}
+
+
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
+{
+	wpas_p2p_disable_cross_connect(wpa_s);
+	if (!wpa_s->ap_iface &&
+	    !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
+					 wpa_s, NULL))
+		wpas_p2p_set_group_idle_timeout(wpa_s);
+}
+
+
+static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_supplicant *iface;
+
+	if (!wpa_s->global->cross_connection)
+		return;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		if (iface == wpa_s)
+			continue;
+		if (iface->drv_flags &
+		    WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
+			continue;
+		if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+			continue;
+
+		wpa_s->cross_connect_enabled = 1;
+		os_strlcpy(wpa_s->cross_connect_uplink, iface->ifname,
+			   sizeof(wpa_s->cross_connect_uplink));
+		wpa_printf(MSG_DEBUG, "P2P: Enable cross connection from "
+			   "%s to %s whenever uplink is available",
+			   wpa_s->ifname, wpa_s->cross_connect_uplink);
+
+		if (iface->ap_iface || iface->current_ssid == NULL ||
+		    iface->current_ssid->mode != WPAS_MODE_INFRA ||
+		    iface->cross_connect_disallowed ||
+		    iface->wpa_state != WPA_COMPLETED)
+			break;
+
+		wpa_s->cross_connect_in_use = 1;
+		wpa_msg(wpa_s->parent, MSG_INFO,
+			P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s",
+			wpa_s->ifname, wpa_s->cross_connect_uplink);
+		break;
+	}
+}
+
+
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
+	    !wpa_s->p2p_in_provisioning)
+		return 0; /* not P2P client operation */
+
+	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->global->p2p)
+		p2p_group_formation_failed(wpa_s->global->p2p);
+
+	eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+			     wpa_s->parent, NULL);
+
+	wpas_group_formation_completed(wpa_s, 0);
+	return 1;
+}
+
+
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+	struct p2p_channels chan;
+
+	if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
+		return;
+
+	os_memset(&chan, 0, sizeof(chan));
+	if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+		wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
+			   "channel list");
+		return;
+	}
+
+	p2p_update_channel_list(wpa_s->global->p2p, &chan);
+}
+
+
+static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
+				     struct wpa_scan_results *scan_res)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+}
+
+
+int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_global *global = wpa_s->global;
+	int found = 0;
+	const u8 *peer;
+
+	if (global->p2p == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "P2P: Request to cancel group formation");
+
+	if (wpa_s->pending_interface_name[0] &&
+	    !is_zero_ether_addr(wpa_s->pending_interface_addr))
+		found = 1;
+
+	peer = p2p_get_go_neg_peer(global->p2p);
+	if (peer) {
+		wpa_printf(MSG_DEBUG, "P2P: Unauthorize pending GO Neg peer "
+			   MACSTR, MAC2STR(peer));
+		p2p_unauthorize(global->p2p, peer);
+		found = 1;
+	}
+
+	if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
+		wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
+		wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
+		found = 1;
+	}
+
+	if (wpa_s->pending_pd_before_join) {
+		wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
+		wpa_s->pending_pd_before_join = 0;
+		found = 1;
+	}
+
+	wpas_p2p_stop_find(wpa_s);
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (wpa_s == global->p2p_group_formation &&
+		    (wpa_s->p2p_in_provisioning ||
+		     wpa_s->parent->pending_interface_type ==
+		     WPA_IF_P2P_CLIENT)) {
+			wpa_printf(MSG_DEBUG, "P2P: Interface %s in group "
+				   "formation found - cancelling",
+				   wpa_s->ifname);
+			found = 1;
+			eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+					     wpa_s->parent, NULL);
+			if (wpa_s->p2p_in_provisioning) {
+				wpas_group_formation_completed(wpa_s, 0);
+				break;
+			}
+			wpas_p2p_group_delete(wpa_s,
+					      P2P_GROUP_REMOVAL_REQUESTED);
+			break;
+		}
+	}
+
+	if (!found) {
+		wpa_printf(MSG_DEBUG, "P2P: No ongoing group formation found");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
+		return;
+
+	wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
+		   "being available anymore");
+	wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
+}
+
+
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+				   int freq_24, int freq_5, int freq_overall)
+{
+	struct p2p_data *p2p = wpa_s->global->p2p;
+	if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+		return;
+	p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
+}
+
+
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr)
+{
+	u8 peer[ETH_ALEN];
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+		return -1;
+
+	if (hwaddr_aton(addr, peer))
+		return -1;
+
+	return p2p_unauthorize(p2p, peer);
+}
+
+
+/**
+ * wpas_p2p_disconnect - Disconnect from a P2P Group
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to disconnect from a group in which the local end is a P2P
+ * Client or to end a P2P Group in case the local end is the Group Owner. If a
+ * virtual network interface was created for this group, that interface will be
+ * removed. Otherwise, only the configured P2P group network will be removed
+ * from the interface.
+ */
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s)
+{
+
+	if (wpa_s == NULL)
+		return -1;
+
+	return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ?
+		-1 : 0;
+}
+
+
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+
+	return p2p_in_progress(wpa_s->global->p2p);
+}
+
+
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+	if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
+	    eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+				 wpa_s->parent, NULL) > 0) {
+		/**
+		 * Remove the network by scheduling the group formation
+		 * timeout to happen immediately. The teardown code
+		 * needs to be scheduled to run asynch later so that we
+		 * don't delete data from under ourselves unexpectedly.
+		 * Calling wpas_p2p_group_formation_timeout directly
+		 * causes a series of crashes in WPS failure scenarios.
+		 */
+		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);
+	}
+}
+
+
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+					  const u8 *addr, const u8 *ssid,
+					  size_t ssid_len)
+{
+	struct wpa_ssid *s;
+	size_t i;
+
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled != 2)
+			continue;
+		if (ssid &&
+		    (ssid_len != s->ssid_len ||
+		     os_memcmp(ssid, s->ssid, ssid_len) != 0))
+			continue;
+		if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
+			return s; /* peer is GO in the persistent group */
+		if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
+			continue;
+		for (i = 0; i < s->num_p2p_clients; i++) {
+			if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+				      addr, ETH_ALEN) == 0)
+				return s; /* peer is P2P client in persistent
+					   * group */
+		}
+	}
+
+	return NULL;
+}
+
+
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+				       const u8 *addr)
+{
+	if (addr == NULL)
+		return;
+	wpas_p2p_add_persistent_group_client(wpa_s, addr);
+}
+
+
+static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
+					int group_added)
+{
+	struct wpa_supplicant *group = wpa_s;
+	if (wpa_s->global->p2p_group_formation)
+		group = wpa_s->global->p2p_group_formation;
+	wpa_s = wpa_s->parent;
+	offchannel_send_action_done(wpa_s);
+	if (group_added)
+		wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
+	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_persistent_id,
+			 wpa_s->p2p_pd_before_go_neg,
+			 wpa_s->p2p_go_ht40);
+}
+
+
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->p2p_fallback_to_go_neg ||
+	    wpa_s->p2p_in_provisioning <= 5)
+		return 0;
+
+	if (wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr) > 0)
+		return 0; /* peer operating as a GO */
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - "
+		"fallback to GO Negotiation");
+	wpas_p2p_fallback_to_go_neg(wpa_s, 1);
+
+	return 1;
+}
+
+
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+
+	if (wpa_s->wpa_state > WPA_SCANNING) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
+			"concurrent operation",
+			P2P_CONCURRENT_SEARCH_DELAY);
+		return P2P_CONCURRENT_SEARCH_DELAY;
+	}
+
+	if (!wpa_s->driver->get_radio_name)
+		return 0;
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return 0;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+		if (ifs->wpa_state > WPA_SCANNING) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
+				"delay due to concurrent operation on "
+				"interface %s",
+				P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
+			return P2P_CONCURRENT_SEARCH_DELAY;
+		}
+	}
+
+	return 0;
+}

Copied: vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/p2p_supplicant.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/p2p_supplicant.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,151 @@
+/*
+ * wpa_supplicant - P2P
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef P2P_SUPPLICANT_H
+#define P2P_SUPPLICANT_H
+
+enum p2p_wps_method;
+struct p2p_go_neg_results;
+enum p2p_send_action_result;
+struct p2p_peer_info;
+
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit_global(struct wpa_global *global);
+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);
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration);
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					  unsigned int freq);
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
+		       int freq, int ht40);
+int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid, int addr_allocated,
+				  int freq, int ht40);
+struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid);
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+			  int registrar);
+enum wpas_p2p_prov_disc_use {
+	WPAS_P2P_PD_FOR_GO_NEG,
+	WPAS_P2P_PD_FOR_JOIN,
+	WPAS_P2P_PD_AUTO
+};
+int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		       const char *config_method,
+		       enum wpas_p2p_prov_disc_use use);
+void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
+				const u8 *data, size_t data_len,
+				enum p2p_send_action_result result);
+int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			      char *end);
+enum p2p_discovery_type;
+int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
+		  enum p2p_discovery_type type,
+		  unsigned int num_req_dev_types, const u8 *req_dev_types,
+		  const u8 *dev_id, unsigned int search_delay);
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
+int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
+int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			  u8 *buf, size_t len, int p2p_group);
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
+			  const u8 *ie, size_t ie_len,
+			  int ssi_signal);
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *bssid,
+			u8 category, const u8 *data, size_t len, int freq);
+void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
+void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+void wpas_dev_found(void *ctx, const u8 *addr,
+		    const struct p2p_peer_info *info,
+		    int new_device);
+void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
+void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+			const u8 *dev_addr, const u8 *pri_dev_type,
+			const char *dev_name, u16 supp_config_methods,
+			u8 dev_capab, u8 group_capab, const u8 *group_id,
+			size_t group_id_len);
+void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+		     u16 update_indic, const u8 *tlvs, size_t tlvs_len);
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+		      const u8 *tlvs, size_t tlvs_len);
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query);
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, const char *role);
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+			  const u8 *dst, u8 dialog_token,
+			  const struct wpabuf *resp_tlvs);
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s);
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s);
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+				 struct wpabuf *query, struct wpabuf *resp);
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *query);
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service);
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service);
+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 wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
+			  const u8 *peer_addr, const u8 *go_dev_addr);
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
+int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
+			  u32 interval1, u32 duration2, u32 interval2);
+int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
+			unsigned int interval);
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			  u16 reason_code, const u8 *ie, size_t ie_len,
+			  int locally_generated);
+void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     u16 reason_code, const u8 *ie, size_t ie_len,
+			     int locally_generated);
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+		     int duration);
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled);
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
+int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+				   int freq_24, int freq_5, int freq_overall);
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+					  const u8 *addr, const u8 *ssid,
+					  size_t ssid_len);
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+				       const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+			   struct hostapd_hw_modes *mode, u8 channel);
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
+
+#endif /* P2P_SUPPLICANT_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/preauth_test.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/preauth_test.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/preauth_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,376 +0,0 @@
-/*
- * WPA Supplicant - test code for pre-authentication
- * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
- * Not used in production version.
- */
-
-#include "includes.h"
-#include <assert.h>
-
-#include "common.h"
-#include "config.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "eloop.h"
-#include "rsn_supp/wpa.h"
-#include "eap_peer/eap.h"
-#include "wpa_supplicant_i.h"
-#include "l2_packet/l2_packet.h"
-#include "ctrl_iface.h"
-#include "pcsc_funcs.h"
-#include "rsn_supp/preauth.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "drivers/driver.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
-struct wpa_driver_ops *wpa_drivers[] = { NULL };
-
-
-struct preauth_test_data {
-	int auth_timed_out;
-};
-
-
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_disassociate(wpa_s, reason_code);
-}
-
-
-static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_deauthenticate(wpa_s, reason_code);
-}
-
-
-static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
-			    const void *data, u16 data_len,
-			    size_t *msg_len, void **data_pos)
-{
-	struct ieee802_1x_hdr *hdr;
-
-	*msg_len = sizeof(*hdr) + data_len;
-	hdr = os_malloc(*msg_len);
-	if (hdr == NULL)
-		return NULL;
-
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = type;
-	hdr->length = htons(data_len);
-
-	if (data)
-		os_memcpy(hdr + 1, data, data_len);
-	else
-		os_memset(hdr + 1, 0, data_len);
-
-	if (data_pos)
-		*data_pos = hdr + 1;
-
-	return (u8 *) hdr;
-}
-
-
-static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
-			     const void *data, u16 data_len,
-			     size_t *msg_len, void **data_pos)
-{
-	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
-}
-
-
-static void _wpa_supplicant_set_state(void *ctx, enum wpa_states state)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_s->wpa_state = state;
-}
-
-
-static enum wpa_states _wpa_supplicant_get_state(void *ctx)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_s->wpa_state;
-}
-
-
-static int wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
-			  const u8 *buf, size_t len)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static void * wpa_supplicant_get_network_ctx(void *wpa_s)
-{
-	return wpa_supplicant_get_ssid(wpa_s);
-}
-
-
-static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
-{
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-}
-
-
-static int wpa_supplicant_get_beacon_ie(void *wpa_s)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg,
-				  const u8 *addr, int key_idx, int set_tx,
-				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
-					     int protection_type,
-					     int key_type)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static int wpa_supplicant_add_pmkid(void *wpa_s,
-				    const u8 *bssid, const u8 *pmkid)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
-				       const u8 *bssid, const u8 *pmkid)
-{
-	printf("%s - not implemented\n", __func__);
-	return -1;
-}
-
-
-static void wpa_supplicant_set_config_blob(void *ctx,
-					   struct wpa_config_blob *blob)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_config_set_blob(wpa_s->conf, blob);
-}
-
-
-static const struct wpa_config_blob *
-wpa_supplicant_get_config_blob(void *ctx, const char *name)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_config_get_blob(wpa_s->conf, name);
-}
-
-
-static void test_eapol_clean(struct wpa_supplicant *wpa_s)
-{
-	rsn_preauth_deinit(wpa_s->wpa);
-	pmksa_candidate_free(wpa_s->wpa);
-	wpa_sm_deinit(wpa_s->wpa);
-	scard_deinit(wpa_s->scard);
-	if (wpa_s->ctrl_iface) {
-		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-		wpa_s->ctrl_iface = NULL;
-	}
-	wpa_config_free(wpa_s->conf);
-}
-
-
-static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct preauth_test_data *p = eloop_ctx;
-	printf("EAPOL test timed out\n");
-	p->auth_timed_out = 1;
-	eloop_terminate();
-}
-
-
-static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	if (!rsn_preauth_in_progress(wpa_s->wpa))
-		eloop_terminate();
-	else {
-		eloop_register_timeout(0, 100000, eapol_test_poll, eloop_ctx,
-				       timeout_ctx);
-	}
-}
-
-
-static struct wpa_driver_ops dummy_driver;
-
-
-static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
-{
-	struct l2_packet_data *l2;
-	struct wpa_sm_ctx *ctx;
-
-	os_memset(&dummy_driver, 0, sizeof(dummy_driver));
-	wpa_s->driver = &dummy_driver;
-
-	ctx = os_zalloc(sizeof(*ctx));
-	assert(ctx != NULL);
-
-	ctx->ctx = wpa_s;
-	ctx->msg_ctx = wpa_s;
-	ctx->set_state = _wpa_supplicant_set_state;
-	ctx->get_state = _wpa_supplicant_get_state;
-	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-	ctx->disassociate = _wpa_supplicant_disassociate;
-	ctx->set_key = wpa_supplicant_set_key;
-	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
-	ctx->get_bssid = wpa_supplicant_get_bssid;
-	ctx->ether_send = wpa_ether_send;
-	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
-	ctx->alloc_eapol = _wpa_alloc_eapol;
-	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
-	ctx->add_pmkid = wpa_supplicant_add_pmkid;
-	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
-	ctx->set_config_blob = wpa_supplicant_set_config_blob;
-	ctx->get_config_blob = wpa_supplicant_get_config_blob;
-	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
-
-	wpa_s->wpa = wpa_sm_init(ctx);
-	assert(wpa_s->wpa != NULL);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN);
-
-	os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
-	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, NULL);
-
-	l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL,
-			    NULL, 0);
-	assert(l2 != NULL);
-	if (l2_packet_get_own_addr(l2, wpa_s->own_addr)) {
-		wpa_printf(MSG_WARNING, "Failed to get own L2 address\n");
-		exit(-1);
-	}
-	l2_packet_deinit(l2);
-	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-}
-
-
-static void eapol_test_terminate(int sig, void *signal_ctx)
-{
-	struct wpa_supplicant *wpa_s = signal_ctx;
-	wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig);
-	eloop_terminate();
-}
-
-
-int main(int argc, char *argv[])
-{
-	struct wpa_supplicant wpa_s;
-	int ret = 1;
-	u8 bssid[ETH_ALEN];
-	struct preauth_test_data preauth_test;
-
-	if (os_program_init())
-		return -1;
-
-	os_memset(&preauth_test, 0, sizeof(preauth_test));
-
-	wpa_debug_level = 0;
-	wpa_debug_show_keys = 1;
-
-	if (argc != 4) {
-		printf("usage: preauth_test <conf> <target MAC address> "
-		       "<ifname>\n");
-		return -1;
-	}
-
-	if (hwaddr_aton(argv[2], bssid)) {
-		printf("Failed to parse target address '%s'.\n", argv[2]);
-		return -1;
-	}
-
-	if (eap_register_methods()) {
-		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
-		return -1;
-	}
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		return -1;
-	}
-
-	os_memset(&wpa_s, 0, sizeof(wpa_s));
-	wpa_s.conf = wpa_config_read(argv[1]);
-	if (wpa_s.conf == NULL) {
-		printf("Failed to parse configuration file '%s'.\n", argv[1]);
-		return -1;
-	}
-	if (wpa_s.conf->ssid == NULL) {
-		printf("No networks defined.\n");
-		return -1;
-	}
-
-	wpa_init_conf(&wpa_s, argv[3]);
-	wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
-	if (wpa_s.ctrl_iface == NULL) {
-		printf("Failed to initialize control interface '%s'.\n"
-		       "You may have another preauth_test process already "
-		       "running or the file was\n"
-		       "left by an unclean termination of preauth_test in "
-		       "which case you will need\n"
-		       "to manually remove this file before starting "
-		       "preauth_test again.\n",
-		       wpa_s.conf->ctrl_interface);
-		return -1;
-	}
-	if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
-		return -1;
-
-	if (rsn_preauth_init(wpa_s.wpa, bssid, &wpa_s.conf->ssid->eap))
-		return -1;
-
-	eloop_register_timeout(30, 0, eapol_test_timeout, &preauth_test, NULL);
-	eloop_register_timeout(0, 100000, eapol_test_poll, &wpa_s, NULL);
-	eloop_register_signal_terminate(eapol_test_terminate, &wpa_s);
-	eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s);
-	eloop_run();
-
-	if (preauth_test.auth_timed_out)
-		ret = -2;
-	else {
-		ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0)
-			? 0 : -3;
-	}
-
-	test_eapol_clean(&wpa_s);
-
-	eap_peer_unregister_methods();
-
-	eloop_destroy();
-
-	os_program_deinit();
-
-	return ret;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/preauth_test.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/preauth_test.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/preauth_test.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/preauth_test.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,363 @@
+/*
+ * WPA Supplicant - test code for pre-authentication
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
+ * Not used in production version.
+ */
+
+#include "includes.h"
+#include <assert.h>
+
+#include "common.h"
+#include "config.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "eloop.h"
+#include "rsn_supp/wpa.h"
+#include "eap_peer/eap.h"
+#include "wpa_supplicant_i.h"
+#include "l2_packet/l2_packet.h"
+#include "ctrl_iface.h"
+#include "pcsc_funcs.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "drivers/driver.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+
+struct wpa_driver_ops *wpa_drivers[] = { NULL };
+
+
+struct preauth_test_data {
+	int auth_timed_out;
+};
+
+
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+{
+	wpa_supplicant_deauthenticate(wpa_s, reason_code);
+}
+
+
+static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
+			    const void *data, u16 data_len,
+			    size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = wpa_s->conf->eapol_version;
+	hdr->type = type;
+	hdr->length = htons(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+			     const void *data, u16 data_len,
+			     size_t *msg_len, void **data_pos)
+{
+	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
+}
+
+
+static void _wpa_supplicant_set_state(void *ctx, enum wpa_states state)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_s->wpa_state = state;
+}
+
+
+static enum wpa_states _wpa_supplicant_get_state(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_s->wpa_state;
+}
+
+
+static int wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+			  const u8 *buf, size_t len)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static void * wpa_supplicant_get_network_ctx(void *wpa_s)
+{
+	return wpa_supplicant_get_ssid(wpa_s);
+}
+
+
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
+
+
+static int wpa_supplicant_get_beacon_ie(void *wpa_s)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg,
+				  const u8 *addr, int key_idx, int set_tx,
+				  const u8 *seq, size_t seq_len,
+				  const u8 *key, size_t key_len)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
+					     int protection_type,
+					     int key_type)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+				    const u8 *bssid, const u8 *pmkid)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+				       const u8 *bssid, const u8 *pmkid)
+{
+	printf("%s - not implemented\n", __func__);
+	return -1;
+}
+
+
+static void wpa_supplicant_set_config_blob(void *ctx,
+					   struct wpa_config_blob *blob)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_config_set_blob(wpa_s->conf, blob);
+}
+
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_config_get_blob(wpa_s->conf, name);
+}
+
+
+static void test_eapol_clean(struct wpa_supplicant *wpa_s)
+{
+	rsn_preauth_deinit(wpa_s->wpa);
+	pmksa_candidate_free(wpa_s->wpa);
+	wpa_sm_deinit(wpa_s->wpa);
+	scard_deinit(wpa_s->scard);
+	if (wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+	wpa_config_free(wpa_s->conf);
+}
+
+
+static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct preauth_test_data *p = eloop_ctx;
+	printf("EAPOL test timed out\n");
+	p->auth_timed_out = 1;
+	eloop_terminate();
+}
+
+
+static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	if (!rsn_preauth_in_progress(wpa_s->wpa))
+		eloop_terminate();
+	else {
+		eloop_register_timeout(0, 100000, eapol_test_poll, eloop_ctx,
+				       timeout_ctx);
+	}
+}
+
+
+static struct wpa_driver_ops dummy_driver;
+
+
+static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
+{
+	struct l2_packet_data *l2;
+	struct wpa_sm_ctx *ctx;
+
+	os_memset(&dummy_driver, 0, sizeof(dummy_driver));
+	wpa_s->driver = &dummy_driver;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	assert(ctx != NULL);
+
+	ctx->ctx = wpa_s;
+	ctx->msg_ctx = wpa_s;
+	ctx->set_state = _wpa_supplicant_set_state;
+	ctx->get_state = _wpa_supplicant_get_state;
+	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+	ctx->set_key = wpa_supplicant_set_key;
+	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
+	ctx->get_bssid = wpa_supplicant_get_bssid;
+	ctx->ether_send = wpa_ether_send;
+	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+	ctx->alloc_eapol = _wpa_alloc_eapol;
+	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+	ctx->add_pmkid = wpa_supplicant_add_pmkid;
+	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
+	ctx->set_config_blob = wpa_supplicant_set_config_blob;
+	ctx->get_config_blob = wpa_supplicant_get_config_blob;
+	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+
+	wpa_s->wpa = wpa_sm_init(ctx);
+	assert(wpa_s->wpa != NULL);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+
+	os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, NULL);
+
+	l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL,
+			    NULL, 0);
+	assert(l2 != NULL);
+	if (l2_packet_get_own_addr(l2, wpa_s->own_addr)) {
+		wpa_printf(MSG_WARNING, "Failed to get own L2 address\n");
+		exit(-1);
+	}
+	l2_packet_deinit(l2);
+	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+}
+
+
+static void eapol_test_terminate(int sig, void *signal_ctx)
+{
+	struct wpa_supplicant *wpa_s = signal_ctx;
+	wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating", sig);
+	eloop_terminate();
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct wpa_supplicant wpa_s;
+	int ret = 1;
+	u8 bssid[ETH_ALEN];
+	struct preauth_test_data preauth_test;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&preauth_test, 0, sizeof(preauth_test));
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (argc != 4) {
+		printf("usage: preauth_test <conf> <target MAC address> "
+		       "<ifname>\n");
+		return -1;
+	}
+
+	if (hwaddr_aton(argv[2], bssid)) {
+		printf("Failed to parse target address '%s'.\n", argv[2]);
+		return -1;
+	}
+
+	if (eap_register_methods()) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		return -1;
+	}
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	os_memset(&wpa_s, 0, sizeof(wpa_s));
+	wpa_s.conf = wpa_config_read(argv[1]);
+	if (wpa_s.conf == NULL) {
+		printf("Failed to parse configuration file '%s'.\n", argv[1]);
+		return -1;
+	}
+	if (wpa_s.conf->ssid == NULL) {
+		printf("No networks defined.\n");
+		return -1;
+	}
+
+	wpa_init_conf(&wpa_s, argv[3]);
+	wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
+	if (wpa_s.ctrl_iface == NULL) {
+		printf("Failed to initialize control interface '%s'.\n"
+		       "You may have another preauth_test process already "
+		       "running or the file was\n"
+		       "left by an unclean termination of preauth_test in "
+		       "which case you will need\n"
+		       "to manually remove this file before starting "
+		       "preauth_test again.\n",
+		       wpa_s.conf->ctrl_interface);
+		return -1;
+	}
+	if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
+		return -1;
+
+	if (rsn_preauth_init(wpa_s.wpa, bssid, &wpa_s.conf->ssid->eap))
+		return -1;
+
+	eloop_register_timeout(30, 0, eapol_test_timeout, &preauth_test, NULL);
+	eloop_register_timeout(0, 100000, eapol_test_poll, &wpa_s, NULL);
+	eloop_register_signal_terminate(eapol_test_terminate, &wpa_s);
+	eloop_register_signal_reconfig(eapol_test_terminate, &wpa_s);
+	eloop_run();
+
+	if (preauth_test.auth_timed_out)
+		ret = -2;
+	else {
+		ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0)
+			? 0 : -3;
+	}
+
+	test_eapol_clean(&wpa_s);
+
+	eap_peer_unregister_methods();
+
+	eloop_destroy();
+
+	os_program_deinit();
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/scan.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/scan.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/scan.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,689 +0,0 @@
-/*
- * WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "utils/includes.h"
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "mlme.h"
-#include "wps_supplicant.h"
-#include "notify.h"
-#include "bss.h"
-#include "scan.h"
-
-
-static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid;
-	union wpa_event_data data;
-
-	ssid = wpa_supplicant_get_ssid(wpa_s);
-	if (ssid == NULL)
-		return;
-
-	if (wpa_s->current_ssid == NULL) {
-		wpa_s->current_ssid = ssid;
-		if (wpa_s->current_ssid != NULL)
-			wpas_notify_network_changed(wpa_s);
-	}
-	wpa_supplicant_initiate_eapol(wpa_s);
-	wpa_printf(MSG_DEBUG, "Already associated with a configured network - "
-		   "generating associated event");
-	os_memset(&data, 0, sizeof(data));
-	wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
-}
-
-
-#ifdef CONFIG_WPS
-static int wpas_wps_in_use(struct wpa_config *conf,
-			   enum wps_request_type *req_type)
-{
-	struct wpa_ssid *ssid;
-	int wps = 0;
-
-	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
-		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
-			continue;
-
-		wps = 1;
-		*req_type = wpas_wps_get_req_type(ssid);
-		if (!ssid->eap.phase1)
-			continue;
-
-		if (os_strstr(ssid->eap.phase1, "pbc=1"))
-			return 2;
-	}
-
-	return wps;
-}
-#endif /* CONFIG_WPS */
-
-
-int wpa_supplicant_enabled_networks(struct wpa_config *conf)
-{
-	struct wpa_ssid *ssid = conf->ssid;
-	while (ssid) {
-		if (!ssid->disabled)
-			return 1;
-		ssid = ssid->next;
-	}
-	return 0;
-}
-
-
-static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
-				     struct wpa_ssid *ssid)
-{
-	while (ssid) {
-		if (!ssid->disabled)
-			break;
-		ssid = ssid->next;
-	}
-
-	/* ap_scan=2 mode - try to associate with each SSID. */
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached "
-			   "end of scan list - go back to beginning");
-		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-		return;
-	}
-	if (ssid->next) {
-		/* Continue from the next SSID on the next attempt. */
-		wpa_s->prev_scan_ssid = ssid;
-	} else {
-		/* Start from the beginning of the SSID list. */
-		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-	}
-	wpa_supplicant_associate(wpa_s, NULL, ssid);
-}
-
-
-static int int_array_len(const int *a)
-{
-	int i;
-	for (i = 0; a && a[i]; i++)
-		;
-	return i;
-}
-
-
-static void int_array_concat(int **res, const int *a)
-{
-	int reslen, alen, i;
-	int *n;
-
-	reslen = int_array_len(*res);
-	alen = int_array_len(a);
-
-	n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
-	if (n == NULL) {
-		os_free(*res);
-		*res = NULL;
-		return;
-	}
-	for (i = 0; i <= alen; i++)
-		n[reslen + i] = a[i];
-	*res = n;
-}
-
-
-static int freq_cmp(const void *a, const void *b)
-{
-	int _a = *(int *) a;
-	int _b = *(int *) b;
-
-	if (_a == 0)
-		return 1;
-	if (_b == 0)
-		return -1;
-	return _a - _b;
-}
-
-
-static void int_array_sort_unique(int *a)
-{
-	int alen;
-	int i, j;
-
-	if (a == NULL)
-		return;
-
-	alen = int_array_len(a);
-	qsort(a, alen, sizeof(int), freq_cmp);
-
-	i = 0;
-	j = 1;
-	while (a[i] && a[j]) {
-		if (a[i] == a[j]) {
-			j++;
-			continue;
-		}
-		a[++i] = a[j++];
-	}
-	if (a[i])
-		i++;
-	a[i] = 0;
-}
-
-
-int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params)
-{
-	int ret;
-
-	wpa_supplicant_notify_scanning(wpa_s, 1);
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_req_scan(wpa_s, params);
-	else
-		ret = wpa_drv_scan(wpa_s, params);
-
-	if (ret) {
-		wpa_supplicant_notify_scanning(wpa_s, 0);
-		wpas_notify_scan_done(wpa_s, 0);
-	} else
-		wpa_s->scan_runs++;
-
-	return ret;
-}
-
-
-static struct wpa_driver_scan_filter *
-wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
-{
-	struct wpa_driver_scan_filter *ssids;
-	struct wpa_ssid *ssid;
-	size_t count;
-
-	*num_ssids = 0;
-	if (!conf->filter_ssids)
-		return NULL;
-
-	for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
-		if (ssid->ssid && ssid->ssid_len)
-			count++;
-	}
-	if (count == 0)
-		return NULL;
-	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
-	if (ssids == NULL)
-		return NULL;
-
-	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
-		if (!ssid->ssid || !ssid->ssid_len)
-			continue;
-		os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
-		ssids[*num_ssids].ssid_len = ssid->ssid_len;
-		(*num_ssids)++;
-	}
-
-	return ssids;
-}
-
-
-static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct wpa_ssid *ssid;
-	int scan_req = 0, ret;
-	struct wpabuf *wps_ie = NULL;
-#ifdef CONFIG_WPS
-	int wps = 0;
-	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
-#endif /* CONFIG_WPS */
-	struct wpa_driver_scan_params params;
-	size_t max_ssids;
-	enum wpa_states prev_state;
-
-	if (wpa_s->disconnected && !wpa_s->scan_req) {
-		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-		return;
-	}
-
-	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
-	    !wpa_s->scan_req) {
-		wpa_printf(MSG_DEBUG, "No enabled networks - do not scan");
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-		return;
-	}
-
-	if (wpa_s->conf->ap_scan != 0 &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
-		wpa_printf(MSG_DEBUG, "Using wired authentication - "
-			   "overriding ap_scan configuration");
-		wpa_s->conf->ap_scan = 0;
-		wpas_notify_ap_scan_changed(wpa_s);
-	}
-
-	if (wpa_s->conf->ap_scan == 0) {
-		wpa_supplicant_gen_assoc_event(wpa_s);
-		return;
-	}
-
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-	    wpa_s->conf->ap_scan == 2)
-		max_ssids = 1;
-	else {
-		max_ssids = wpa_s->max_scan_ssids;
-		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
-			max_ssids = WPAS_MAX_SCAN_SSIDS;
-	}
-
-#ifdef CONFIG_WPS
-	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
-#endif /* CONFIG_WPS */
-
-	scan_req = wpa_s->scan_req;
-	wpa_s->scan_req = 0;
-
-	os_memset(&params, 0, sizeof(params));
-
-	prev_state = wpa_s->wpa_state;
-	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
-	    wpa_s->wpa_state == WPA_INACTIVE)
-		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
-
-	/* Find the starting point from which to continue scanning */
-	ssid = wpa_s->conf->ssid;
-	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
-		while (ssid) {
-			if (ssid == wpa_s->prev_scan_ssid) {
-				ssid = ssid->next;
-				break;
-			}
-			ssid = ssid->next;
-		}
-	}
-
-	if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 ||
-			      wpa_s->connect_without_scan)) {
-		wpa_s->connect_without_scan = 0;
-		wpa_supplicant_assoc_try(wpa_s, ssid);
-		return;
-	} else if (wpa_s->conf->ap_scan == 2) {
-		/*
-		 * User-initiated scan request in ap_scan == 2; scan with
-		 * wildcard SSID.
-		 */
-		ssid = NULL;
-	} else {
-		struct wpa_ssid *start = ssid, *tssid;
-		int freqs_set = 0;
-		if (ssid == NULL && max_ssids > 1)
-			ssid = wpa_s->conf->ssid;
-		while (ssid) {
-			if (!ssid->disabled && ssid->scan_ssid) {
-				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
-						  ssid->ssid, ssid->ssid_len);
-				params.ssids[params.num_ssids].ssid =
-					ssid->ssid;
-				params.ssids[params.num_ssids].ssid_len =
-					ssid->ssid_len;
-				params.num_ssids++;
-				if (params.num_ssids + 1 >= max_ssids)
-					break;
-			}
-			ssid = ssid->next;
-			if (ssid == start)
-				break;
-			if (ssid == NULL && max_ssids > 1 &&
-			    start != wpa_s->conf->ssid)
-				ssid = wpa_s->conf->ssid;
-		}
-
-		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
-			if (tssid->disabled)
-				continue;
-			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
-				int_array_concat(&params.freqs,
-						 tssid->scan_freq);
-			} else {
-				os_free(params.freqs);
-				params.freqs = NULL;
-			}
-			freqs_set = 1;
-		}
-		int_array_sort_unique(params.freqs);
-	}
-
-	if (ssid) {
-		wpa_s->prev_scan_ssid = ssid;
-		if (max_ssids > 1) {
-			wpa_printf(MSG_DEBUG, "Include wildcard SSID in the "
-				   "scan request");
-			params.num_ssids++;
-		}
-		wpa_printf(MSG_DEBUG, "Starting AP scan for specific SSID(s)");
-	} else {
-		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-		params.num_ssids++;
-		wpa_printf(MSG_DEBUG, "Starting AP scan for wildcard SSID");
-	}
-
-#ifdef CONFIG_WPS
-	if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
-		/*
-		 * Optimize post-provisioning scan based on channel used
-		 * during provisioning.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: Scan only frequency %u MHz that "
-			   "was used during provisioning", wpa_s->wps_freq);
-		params.freqs = os_zalloc(2 * sizeof(int));
-		if (params.freqs)
-			params.freqs[0] = wpa_s->wps_freq;
-		wpa_s->after_wps--;
-	}
-
-	if (wps) {
-		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
-						wpa_s->wps->uuid, req_type);
-		if (wps_ie) {
-			params.extra_ies = wpabuf_head(wps_ie);
-			params.extra_ies_len = wpabuf_len(wps_ie);
-		}
-	}
-#endif /* CONFIG_WPS */
-
-	params.filter_ssids = wpa_supplicant_build_filter_ssids(
-		wpa_s->conf, &params.num_filter_ssids);
-
-	ret = wpa_supplicant_trigger_scan(wpa_s, &params);
-
-	wpabuf_free(wps_ie);
-	os_free(params.freqs);
-	os_free(params.filter_ssids);
-
-	if (ret) {
-		wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
-		if (prev_state != wpa_s->wpa_state)
-			wpa_supplicant_set_state(wpa_s, prev_state);
-		wpa_supplicant_req_scan(wpa_s, 1, 0);
-	}
-}
-
-
-/**
- * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
- * @wpa_s: Pointer to wpa_supplicant data
- * @sec: Number of seconds after which to scan
- * @usec: Number of microseconds after which to scan
- *
- * This function is used to schedule a scan for neighboring access points after
- * the specified time.
- */
-void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
-{
-	/* If there's at least one network that should be specifically scanned
-	 * then don't cancel the scan and reschedule.  Some drivers do
-	 * background scanning which generates frequent scan results, and that
-	 * causes the specific SSID scan to get continually pushed back and
-	 * never happen, which causes hidden APs to never get probe-scanned.
-	 */
-	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
-	    wpa_s->conf->ap_scan == 1) {
-		struct wpa_ssid *ssid = wpa_s->conf->ssid;
-
-		while (ssid) {
-			if (!ssid->disabled && ssid->scan_ssid)
-				break;
-			ssid = ssid->next;
-		}
-		if (ssid) {
-			wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
-			        "ensure that specific SSID scans occur");
-			return;
-		}
-	}
-
-	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
-		sec, usec);
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
-}
-
-
-/**
- * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * This function is used to cancel a scan request scheduled with
- * wpa_supplicant_req_scan().
- */
-void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
-{
-	wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request");
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-}
-
-
-void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
-				    int scanning)
-{
-	if (wpa_s->scanning != scanning) {
-		wpa_s->scanning = scanning;
-		wpas_notify_scanning(wpa_s);
-	}
-}
-
-
-static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
-{
-	int rate = 0;
-	const u8 *ie;
-	int i;
-
-	ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
-	for (i = 0; ie && i < ie[1]; i++) {
-		if ((ie[i + 2] & 0x7f) > rate)
-			rate = ie[i + 2] & 0x7f;
-	}
-
-	ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
-	for (i = 0; ie && i < ie[1]; i++) {
-		if ((ie[i + 2] & 0x7f) > rate)
-			rate = ie[i + 2] & 0x7f;
-	}
-
-	return rate;
-}
-
-
-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;
-}
-
-
-const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
-				  u32 vendor_type)
-{
-	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] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    vendor_type == WPA_GET_BE32(&pos[2]))
-			return pos;
-		pos += 2 + pos[1];
-	}
-
-	return NULL;
-}
-
-
-struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
-					     u32 vendor_type)
-{
-	struct wpabuf *buf;
-	const u8 *end, *pos;
-
-	buf = wpabuf_alloc(res->ie_len);
-	if (buf == NULL)
-		return NULL;
-
-	pos = (const u8 *) (res + 1);
-	end = pos + res->ie_len;
-
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
-		    vendor_type == WPA_GET_BE32(&pos[2]))
-			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
-		pos += 2 + pos[1];
-	}
-
-	if (wpabuf_len(buf) == 0) {
-		wpabuf_free(buf);
-		buf = NULL;
-	}
-
-	return buf;
-}
-
-
-/* Compare function for sorting scan results. Return >0 if @b is considered
- * better. */
-static int wpa_scan_result_compar(const void *a, const void *b)
-{
-	struct wpa_scan_res **_wa = (void *) a;
-	struct wpa_scan_res **_wb = (void *) b;
-	struct wpa_scan_res *wa = *_wa;
-	struct wpa_scan_res *wb = *_wb;
-	int wpa_a, wpa_b, maxrate_a, maxrate_b;
-
-	/* WPA/WPA2 support preferred */
-	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
-		wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
-	wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
-		wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
-
-	if (wpa_b && !wpa_a)
-		return 1;
-	if (!wpa_b && wpa_a)
-		return -1;
-
-	/* privacy support preferred */
-	if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
-	    (wb->caps & IEEE80211_CAP_PRIVACY))
-		return 1;
-	if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
-	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
-		return -1;
-
-	/* best/max rate preferred if signal level close enough XXX */
-	if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
-	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
-		maxrate_a = wpa_scan_get_max_rate(wa);
-		maxrate_b = wpa_scan_get_max_rate(wb);
-		if (maxrate_a != maxrate_b)
-			return maxrate_b - maxrate_a;
-	}
-
-	/* use freq for channel preference */
-
-	/* all things being equal, use signal level; if signal levels are
-	 * identical, use quality values since some drivers may only report
-	 * that value and leave the signal level zero */
-	if (wb->level == wa->level)
-		return wb->qual - wa->qual;
-	return wb->level - wa->level;
-}
-
-
-/**
- * wpa_supplicant_get_scan_results - Get scan results
- * @wpa_s: Pointer to wpa_supplicant data
- * @info: Information about what was scanned or %NULL if not available
- * @new_scan: Whether a new scan was performed
- * Returns: Scan results, %NULL on failure
- *
- * This function request the current scan results from the driver and updates
- * the local BSS list wpa_s->bss. The caller is responsible for freeing the
- * results with wpa_scan_results_free().
- */
-struct wpa_scan_results *
-wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
-				struct scan_info *info, int new_scan)
-{
-	struct wpa_scan_results *scan_res;
-	size_t i;
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		scan_res = ieee80211_sta_get_scan_results(wpa_s);
-	else
-		scan_res = wpa_drv_get_scan_results2(wpa_s);
-	if (scan_res == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to get scan results");
-		return NULL;
-	}
-
-	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
-	      wpa_scan_result_compar);
-
-	wpa_bss_update_start(wpa_s);
-	for (i = 0; i < scan_res->num; i++)
-		wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
-	wpa_bss_update_end(wpa_s, info, new_scan);
-
-	return scan_res;
-}
-
-
-int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_scan_results *scan_res;
-	scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
-	if (scan_res == NULL)
-		return -1;
-	wpa_scan_results_free(scan_res);
-
-	return 0;
-}
-
-
-void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/scan.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/scan.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/scan.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/scan.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1561 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "notify.h"
+#include "bss.h"
+#include "scan.h"
+
+
+static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+	union wpa_event_data data;
+
+	ssid = wpa_supplicant_get_ssid(wpa_s);
+	if (ssid == NULL)
+		return;
+
+	if (wpa_s->current_ssid == NULL) {
+		wpa_s->current_ssid = ssid;
+		if (wpa_s->current_ssid != NULL)
+			wpas_notify_network_changed(wpa_s);
+	}
+	wpa_supplicant_initiate_eapol(wpa_s);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
+		"network - generating associated event");
+	os_memset(&data, 0, sizeof(data));
+	wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
+}
+
+
+#ifdef CONFIG_WPS
+static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
+			   enum wps_request_type *req_type)
+{
+	struct wpa_ssid *ssid;
+	int wps = 0;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+			continue;
+
+		wps = 1;
+		*req_type = wpas_wps_get_req_type(ssid);
+		if (!ssid->eap.phase1)
+			continue;
+
+		if (os_strstr(ssid->eap.phase1, "pbc=1"))
+			return 2;
+	}
+
+#ifdef CONFIG_P2P
+	if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+	    !wpa_s->conf->p2p_disabled) {
+		wpa_s->wps->dev.p2p = 1;
+		if (!wps) {
+			wps = 1;
+			*req_type = WPS_REQ_ENROLLEE_INFO;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	return wps;
+}
+#endif /* CONFIG_WPS */
+
+
+/**
+ * wpa_supplicant_enabled_networks - Check whether there are enabled networks
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 if no networks are enabled, >0 if networks are enabled
+ *
+ * This function is used to figure out whether any networks (or Interworking
+ * with enabled credentials and auto_interworking) are present in the current
+ * configuration.
+ */
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->conf->ssid;
+	int count = 0, disabled = 0;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			count++;
+		else
+			disabled++;
+		ssid = ssid->next;
+	}
+	if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+	    wpa_s->conf->auto_interworking)
+		count++;
+	if (count == 0 && disabled > 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled "
+			"networks)", disabled);
+	}
+	return count;
+}
+
+
+static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid)
+{
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			break;
+		ssid = ssid->next;
+	}
+
+	/* ap_scan=2 mode - try to associate with each SSID. */
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
+			"end of scan list - go back to beginning");
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return;
+	}
+	if (ssid->next) {
+		/* Continue from the next SSID on the next attempt. */
+		wpa_s->prev_scan_ssid = ssid;
+	} else {
+		/* Start from the beginning of the SSID list. */
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+	}
+	wpa_supplicant_associate(wpa_s, NULL, ssid);
+}
+
+
+static int int_array_len(const int *a)
+{
+	int i;
+	for (i = 0; a && a[i]; i++)
+		;
+	return i;
+}
+
+
+static void int_array_concat(int **res, const int *a)
+{
+	int reslen, alen, i;
+	int *n;
+
+	reslen = int_array_len(*res);
+	alen = int_array_len(a);
+
+	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
+	if (n == NULL) {
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
+	for (i = 0; i <= alen; i++)
+		n[reslen + i] = a[i];
+	*res = n;
+}
+
+
+static int freq_cmp(const void *a, const void *b)
+{
+	int _a = *(int *) a;
+	int _b = *(int *) b;
+
+	if (_a == 0)
+		return 1;
+	if (_b == 0)
+		return -1;
+	return _a - _b;
+}
+
+
+static void int_array_sort_unique(int *a)
+{
+	int alen;
+	int i, j;
+
+	if (a == NULL)
+		return;
+
+	alen = int_array_len(a);
+	qsort(a, alen, sizeof(int), freq_cmp);
+
+	i = 0;
+	j = 1;
+	while (a[i] && a[j]) {
+		if (a[i] == a[j]) {
+			j++;
+			continue;
+		}
+		a[++i] = a[j++];
+	}
+	if (a[i])
+		i++;
+	a[i] = 0;
+}
+
+
+/**
+ * wpa_supplicant_trigger_scan - Request driver to start a scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params)
+{
+	int ret;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+
+	ret = wpa_drv_scan(wpa_s, params);
+	if (ret) {
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+		wpas_notify_scan_done(wpa_s, 0);
+	} else {
+		wpa_s->scan_runs++;
+		wpa_s->normal_scans++;
+	}
+
+	return ret;
+}
+
+
+static void
+wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
+
+	if (wpa_supplicant_req_sched_scan(wpa_s))
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void
+wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
+
+	wpa_s->sched_scan_timed_out = 1;
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+}
+
+
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params,
+				int interval)
+{
+	int ret;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+	if (ret)
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+	else
+		wpa_s->sched_scanning = 1;
+
+	return ret;
+}
+
+
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+
+	ret = wpa_drv_stop_sched_scan(wpa_s);
+	if (ret) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
+		/* TODO: what to do if stopping fails? */
+		return -1;
+	}
+
+	return ret;
+}
+
+
+static struct wpa_driver_scan_filter *
+wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
+{
+	struct wpa_driver_scan_filter *ssids;
+	struct wpa_ssid *ssid;
+	size_t count;
+
+	*num_ssids = 0;
+	if (!conf->filter_ssids)
+		return NULL;
+
+	for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->ssid && ssid->ssid_len)
+			count++;
+	}
+	if (count == 0)
+		return NULL;
+	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
+	if (ssids == NULL)
+		return NULL;
+
+	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+		if (!ssid->ssid || !ssid->ssid_len)
+			continue;
+		os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
+		ssids[*num_ssids].ssid_len = ssid->ssid_len;
+		(*num_ssids)++;
+	}
+
+	return ssids;
+}
+
+
+static void wpa_supplicant_optimize_freqs(
+	struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
+{
+#ifdef CONFIG_P2P
+	if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
+	    wpa_s->go_params) {
+		/* Optimize provisioning state scan based on GO information */
+		if (wpa_s->p2p_in_provisioning < 5 &&
+		    wpa_s->go_params->freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
+				"preferred frequency %d MHz",
+				wpa_s->go_params->freq);
+			params->freqs = os_zalloc(2 * sizeof(int));
+			if (params->freqs)
+				params->freqs[0] = wpa_s->go_params->freq;
+		} else if (wpa_s->p2p_in_provisioning < 8 &&
+			   wpa_s->go_params->freq_list[0]) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
+				"channels");
+			int_array_concat(&params->freqs,
+					 wpa_s->go_params->freq_list);
+			if (params->freqs)
+				int_array_sort_unique(params->freqs);
+		}
+		wpa_s->p2p_in_provisioning++;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+	if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
+		/*
+		 * Optimize post-provisioning scan based on channel used
+		 * during provisioning.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
+			"that was used during provisioning", wpa_s->wps_freq);
+		params->freqs = os_zalloc(2 * sizeof(int));
+		if (params->freqs)
+			params->freqs[0] = wpa_s->wps_freq;
+		wpa_s->after_wps--;
+	}
+
+	if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
+	{
+		/* Optimize provisioning scan based on already known channel */
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
+			wpa_s->wps_freq);
+		params->freqs = os_zalloc(2 * sizeof(int));
+		if (params->freqs)
+			params->freqs[0] = wpa_s->wps_freq;
+		wpa_s->known_wps_freq = 0; /* only do this once */
+	}
+#endif /* CONFIG_WPS */
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
+					   struct wpabuf *buf)
+{
+	if (wpa_s->conf->interworking == 0)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
+	wpabuf_put_u8(buf, 4);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+
+	wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
+	wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
+		      1 + ETH_ALEN);
+	wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
+	/* No Venue Info */
+	if (!is_zero_ether_addr(wpa_s->conf->hessid))
+		wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *extra_ie = NULL;
+#ifdef CONFIG_WPS
+	int wps = 0;
+	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking &&
+	    wpabuf_resize(&extra_ie, 100) == 0)
+		wpas_add_interworking_elements(wpa_s, extra_ie);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WPS
+	wps = wpas_wps_in_use(wpa_s, &req_type);
+
+	if (wps) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
+						DEV_PW_DEFAULT,
+						&wpa_s->wps->dev,
+						wpa_s->wps->uuid, req_type,
+						0, NULL);
+		if (wps_ie) {
+			if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
+				wpabuf_put_buf(extra_ie, wps_ie);
+			wpabuf_free(wps_ie);
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if (wps) {
+		size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+		if (wpabuf_resize(&extra_ie, ielen) == 0)
+			wpas_p2p_scan_ie(wpa_s, extra_ie);
+	}
+#endif /* CONFIG_P2P */
+
+#endif /* CONFIG_WPS */
+
+	return extra_ie;
+}
+
+
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (wpas_network_disabled(wpa_s, ssid))
+			continue;
+		if (!ssid->p2p_group)
+			return 1;
+	}
+
+	if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+	    wpa_s->conf->auto_interworking)
+		return 1;
+
+	return 0;
+}
+
+
+/*
+ * Find the operating frequency of any other virtual interface that is using
+ * the same radio concurrently.
+ */
+static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+	u8 bssid[ETH_ALEN];
+
+	if (!wpa_s->driver->get_radio_name)
+		return -1;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return -1;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+
+		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+			continue;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+			return ifs->current_ssid->frequency;
+		if (wpa_drv_get_bssid(ifs, bssid) == 0)
+			return ifs->assoc_freq;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_ssid *ssid;
+	enum scan_req_type scan_req = NORMAL_SCAN_REQ;
+	int ret;
+	struct wpabuf *extra_ie = NULL;
+	struct wpa_driver_scan_params params;
+	struct wpa_driver_scan_params *scan_params;
+	size_t max_ssids;
+	enum wpa_states prev_state;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
+		return;
+	}
+
+	if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		return;
+	}
+
+	if (!wpa_supplicant_enabled_networks(wpa_s) &&
+	    wpa_s->scan_req == NORMAL_SCAN_REQ) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+#ifdef CONFIG_P2P
+		wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+		return;
+	}
+
+	if (wpa_s->conf->ap_scan != 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
+			"overriding ap_scan configuration");
+		wpa_s->conf->ap_scan = 0;
+		wpas_notify_ap_scan_changed(wpa_s);
+	}
+
+	if (wpa_s->conf->ap_scan == 0) {
+		wpa_supplicant_gen_assoc_event(wpa_s);
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpas_p2p_in_progress(wpa_s)) {
+		if (wpa_s->sta_scan_pending &&
+		    wpas_p2p_in_progress(wpa_s) == 2 &&
+		    wpa_s->global->p2p_cb_on_scan_complete) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
+				"mode scan during P2P search");
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
+				"while P2P operation is in progress");
+			wpa_s->sta_scan_pending = 1;
+			wpa_supplicant_req_scan(wpa_s, 5, 0);
+			return;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->conf->ap_scan == 2)
+		max_ssids = 1;
+	else {
+		max_ssids = wpa_s->max_scan_ssids;
+		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
+			max_ssids = WPAS_MAX_SCAN_SSIDS;
+	}
+
+	scan_req = wpa_s->scan_req;
+	wpa_s->scan_req = NORMAL_SCAN_REQ;
+
+	os_memset(&params, 0, sizeof(params));
+
+	prev_state = wpa_s->wpa_state;
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_INACTIVE)
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+	/*
+	 * If autoscan has set its own scanning parameters
+	 */
+	if (wpa_s->autoscan_params != NULL) {
+		scan_params = wpa_s->autoscan_params;
+		goto scan;
+	}
+
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (ssid == wpa_s->connect_without_scan)
+				break;
+		}
+		wpa_s->connect_without_scan = NULL;
+		if (ssid) {
+			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+				   "without scan step");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			return;
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
+	    wpa_s->go_params) {
+		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
+			   "P2P group formation");
+		params.ssids[0].ssid = wpa_s->go_params->ssid;
+		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
+		params.num_ssids = 1;
+		goto ssid_list_set;
+	}
+#endif /* CONFIG_P2P */
+
+	/* Find the starting point from which to continue scanning */
+	ssid = wpa_s->conf->ssid;
+	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
+		while (ssid) {
+			if (ssid == wpa_s->prev_scan_ssid) {
+				ssid = ssid->next;
+				break;
+			}
+			ssid = ssid->next;
+		}
+	}
+
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
+		wpa_s->connect_without_scan = NULL;
+		wpa_s->prev_scan_wildcard = 0;
+		wpa_supplicant_assoc_try(wpa_s, ssid);
+		return;
+	} else if (wpa_s->conf->ap_scan == 2) {
+		/*
+		 * User-initiated scan request in ap_scan == 2; scan with
+		 * wildcard SSID.
+		 */
+		ssid = NULL;
+	} else {
+		struct wpa_ssid *start = ssid, *tssid;
+		int freqs_set = 0;
+		if (ssid == NULL && max_ssids > 1)
+			ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			if (!wpas_network_disabled(wpa_s, ssid) &&
+			    ssid->scan_ssid) {
+				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
+						  ssid->ssid, ssid->ssid_len);
+				params.ssids[params.num_ssids].ssid =
+					ssid->ssid;
+				params.ssids[params.num_ssids].ssid_len =
+					ssid->ssid_len;
+				params.num_ssids++;
+				if (params.num_ssids + 1 >= max_ssids)
+					break;
+			}
+			ssid = ssid->next;
+			if (ssid == start)
+				break;
+			if (ssid == NULL && max_ssids > 1 &&
+			    start != wpa_s->conf->ssid)
+				ssid = wpa_s->conf->ssid;
+		}
+
+		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
+			if (wpas_network_disabled(wpa_s, tssid))
+				continue;
+			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+				int_array_concat(&params.freqs,
+						 tssid->scan_freq);
+			} else {
+				os_free(params.freqs);
+				params.freqs = NULL;
+			}
+			freqs_set = 1;
+		}
+		int_array_sort_unique(params.freqs);
+	}
+
+	if (ssid && max_ssids == 1) {
+		/*
+		 * If the driver is limited to 1 SSID at a time interleave
+		 * wildcard SSID scans with specific SSID scans to avoid
+		 * waiting a long time for a wildcard scan.
+		 */
+		if (!wpa_s->prev_scan_wildcard) {
+			params.ssids[0].ssid = NULL;
+			params.ssids[0].ssid_len = 0;
+			wpa_s->prev_scan_wildcard = 1;
+			wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
+				"wildcard SSID (Interleave with specific)");
+		} else {
+			wpa_s->prev_scan_ssid = ssid;
+			wpa_s->prev_scan_wildcard = 0;
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Starting AP scan for specific SSID: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+		}
+	} else if (ssid) {
+		/* max_ssids > 1 */
+
+		wpa_s->prev_scan_ssid = ssid;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
+			"the scan request");
+		params.num_ssids++;
+	} else {
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+		params.num_ssids++;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
+			"SSID");
+	}
+#ifdef CONFIG_P2P
+ssid_list_set:
+#endif /* CONFIG_P2P */
+
+	wpa_supplicant_optimize_freqs(wpa_s, &params);
+	extra_ie = wpa_supplicant_extra_ies(wpa_s);
+
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+		wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
+	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
+			"generated frequency list");
+		params.freqs = wpa_s->next_scan_freqs;
+	} else
+		os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
+
+	params.filter_ssids = wpa_supplicant_build_filter_ssids(
+		wpa_s->conf, &params.num_filter_ssids);
+	if (extra_ie) {
+		params.extra_ies = wpabuf_head(extra_ie);
+		params.extra_ies_len = wpabuf_len(extra_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_in_provisioning ||
+	    (wpa_s->show_group_started && wpa_s->go_params)) {
+		/*
+		 * The interface may not yet be in P2P mode, so we have to
+		 * explicitly request P2P probe to disable CCK rates.
+		 */
+		params.p2p_probe = 1;
+	}
+#endif /* CONFIG_P2P */
+
+	scan_params = ¶ms;
+
+scan:
+#ifdef CONFIG_P2P
+	/*
+	 * If the driver does not support multi-channel concurrency and a
+	 * virtual interface that shares the same radio with the wpa_s interface
+	 * is operating there may not be need to scan other channels apart from
+	 * the current operating channel on the other virtual interface. Filter
+	 * out other channels in case we are trying to find a connection for a
+	 * station interface when we are not configured to prefer station
+	 * connection and a concurrent operation is already in process.
+	 */
+	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+	    !scan_params->freqs && !params.freqs &&
+	    wpas_is_p2p_prioritized(wpa_s) &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+	    non_p2p_network_enabled(wpa_s)) {
+		int freq = shared_vif_oper_freq(wpa_s);
+		if (freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
+				"operating channel (%d MHz) since driver does "
+				"not support multi-channel concurrency", freq);
+			params.freqs = os_zalloc(sizeof(int) * 2);
+			if (params.freqs)
+				params.freqs[0] = freq;
+			scan_params->freqs = params.freqs;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+
+	wpabuf_free(extra_ie);
+	os_free(params.freqs);
+	os_free(params.filter_ssids);
+
+	if (ret) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
+		if (prev_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s, prev_state);
+		/* Restore scan_req since we will try to scan again */
+		wpa_s->scan_req = scan_req;
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
+	} else {
+		wpa_s->scan_for_connection = 0;
+	}
+}
+
+
+/**
+ * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule a scan for neighboring access points after
+ * the specified time.
+ */
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
+{
+	/* If there's at least one network that should be specifically scanned
+	 * then don't cancel the scan and reschedule.  Some drivers do
+	 * background scanning which generates frequent scan results, and that
+	 * causes the specific SSID scan to get continually pushed back and
+	 * never happen, which causes hidden APs to never get probe-scanned.
+	 */
+	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
+	    wpa_s->conf->ap_scan == 1) {
+		struct wpa_ssid *ssid = wpa_s->conf->ssid;
+
+		while (ssid) {
+			if (!wpas_network_disabled(wpa_s, ssid) &&
+			    ssid->scan_ssid)
+				break;
+			ssid = ssid->next;
+		}
+		if (ssid) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
+			        "ensure that specific SSID scans occur");
+			return;
+		}
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
+		sec, usec);
+	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ * Returns: 0 on success or -1 otherwise
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points after the specified time.
+ */
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec)
+{
+	if (!wpa_s->sched_scan_supported)
+		return -1;
+
+	eloop_register_timeout(sec, usec,
+			       wpa_supplicant_delayed_sched_scan_timeout,
+			       wpa_s, NULL);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 is sched_scan was started or -1 otherwise
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points repeating the scan continuously.
+ */
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_driver_scan_params params;
+	struct wpa_driver_scan_params *scan_params;
+	enum wpa_states prev_state;
+	struct wpa_ssid *ssid = NULL;
+	struct wpabuf *extra_ie = NULL;
+	int ret;
+	unsigned int max_sched_scan_ssids;
+	int wildcard = 0;
+	int need_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 || wpa_s->conf->disable_scan_offload)
+		return -1;
+
+	if (wpa_s->sched_scanning) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
+		return 0;
+	}
+
+	need_ssids = 0;
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
+			/* Use wildcard SSID to find this network */
+			wildcard = 1;
+		} else if (!wpas_network_disabled(wpa_s, ssid) &&
+			   ssid->ssid_len)
+			need_ssids++;
+
+#ifdef CONFIG_WPS
+		if (!wpas_network_disabled(wpa_s, ssid) &&
+		    ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+			/*
+			 * Normal scan is more reliable and faster for WPS
+			 * operations and since these are for short periods of
+			 * time, the benefit of trying to use sched_scan would
+			 * be limited.
+			 */
+			wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+				"sched_scan for WPS");
+			return -1;
+		}
+#endif /* CONFIG_WPS */
+	}
+	if (wildcard)
+		need_ssids++;
+
+	if (wpa_s->normal_scans < 3 &&
+	    (need_ssids <= wpa_s->max_scan_ssids ||
+	     wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
+		/*
+		 * When normal scan can speed up operations, use that for the
+		 * first operations before starting the sched_scan to allow
+		 * user space sleep more. We do this only if the normal scan
+		 * has functionality that is suitable for this or if the
+		 * sched_scan does not have better support for multiple SSIDs.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+			"sched_scan for initial scans (normal_scans=%d)",
+			wpa_s->normal_scans);
+		return -1;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+
+	/* If we can't allocate space for the filters, we just don't filter */
+	params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+					sizeof(struct wpa_driver_scan_filter));
+
+	prev_state = wpa_s->wpa_state;
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_INACTIVE)
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+	if (wpa_s->autoscan_params != NULL) {
+		scan_params = wpa_s->autoscan_params;
+		goto scan;
+	}
+
+	/* Find the starting point from which to continue scanning */
+	ssid = wpa_s->conf->ssid;
+	if (wpa_s->prev_sched_ssid) {
+		while (ssid) {
+			if (ssid == wpa_s->prev_sched_ssid) {
+				ssid = ssid->next;
+				break;
+			}
+			ssid = ssid->next;
+		}
+	}
+
+	if (!ssid || !wpa_s->prev_sched_ssid) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
+
+		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;
+		wpa_s->prev_sched_ssid = ssid;
+	}
+
+	if (wildcard) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
+		params.num_ssids++;
+	}
+
+	while (ssid) {
+		if (wpas_network_disabled(wpa_s, ssid))
+			goto next;
+
+		if (params.num_filter_ssids < wpa_s->max_match_sets &&
+		    params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
+				  ssid->ssid, ssid->ssid_len);
+			params.filter_ssids[params.num_filter_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_filter_ssids++;
+		} else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
+				"filter for sched_scan - drop filter");
+			os_free(params.filter_ssids);
+			params.filter_ssids = NULL;
+			params.num_filter_ssids = 0;
+		}
+
+		if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
+			if (params.num_ssids == max_sched_scan_ssids)
+				break; /* only room for broadcast SSID */
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"add to active scan ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			params.ssids[params.num_ssids].ssid =
+				ssid->ssid;
+			params.ssids[params.num_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_ssids++;
+			if (params.num_ssids >= max_sched_scan_ssids) {
+				wpa_s->prev_sched_ssid = ssid;
+				do {
+					ssid = ssid->next;
+				} while (ssid &&
+					 (wpas_network_disabled(wpa_s, ssid) ||
+					  !ssid->scan_ssid));
+				break;
+			}
+		}
+
+	next:
+		wpa_s->prev_sched_ssid = ssid;
+		ssid = ssid->next;
+	}
+
+	if (params.num_filter_ssids == 0) {
+		os_free(params.filter_ssids);
+		params.filter_ssids = NULL;
+	}
+
+	extra_ie = wpa_supplicant_extra_ies(wpa_s);
+	if (extra_ie) {
+		params.extra_ies = wpabuf_head(extra_ie);
+		params.extra_ies_len = wpabuf_len(extra_ie);
+	}
+
+	scan_params = ¶ms;
+
+scan:
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d timeout %d",
+			wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d (no timeout)",
+			wpa_s->sched_scan_interval);
+	}
+
+	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
+					      wpa_s->sched_scan_interval);
+	wpabuf_free(extra_ie);
+	os_free(params.filter_ssids);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
+		if (prev_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s, prev_state);
+		return ret;
+	}
+
+	/* If we have more SSIDs to scan, add a timeout so we scan them too */
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_s->sched_scan_timed_out = 0;
+		eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
+				       wpa_supplicant_sched_scan_timeout,
+				       wpa_s, NULL);
+		wpa_s->first_sched_scan = 0;
+		wpa_s->sched_scan_timeout /= 2;
+		wpa_s->sched_scan_interval *= 2;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a scan request scheduled with
+ * wpa_supplicant_req_scan().
+ */
+void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
+	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a periodic scheduled scan.
+ */
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->sched_scanning)
+		return;
+
+	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);
+}
+
+
+/**
+ * wpa_supplicant_notify_scanning - Indicate possible scan state change
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @scanning: Whether scanning is currently in progress
+ *
+ * This function is to generate scanning notifycations. It is called whenever
+ * there may have been a change in scanning (scan started, completed, stopped).
+ * wpas_notify_scanning() is called whenever the scanning state changed from the
+ * previously notified state.
+ */
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+				    int scanning)
+{
+	if (wpa_s->scanning != scanning) {
+		wpa_s->scanning = scanning;
+		wpas_notify_scanning(wpa_s);
+	}
+}
+
+
+static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
+{
+	int rate = 0;
+	const u8 *ie;
+	int i;
+
+	ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	return rate;
+}
+
+
+/**
+ * wpa_scan_get_ie - Fetch a specified information element from a scan result
+ * @res: Scan result entry
+ * @ie: Information element identitifier (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 scan
+ * result.
+ */
+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;
+}
+
+
+/**
+ * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
+const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
+				  u32 vendor_type)
+{
+	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] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the scan result. The caller is responsible
+ * for freeing the returned buffer.
+ */
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(res->ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (res + 1);
+	end = pos + res->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
+ * conservative value.
+ */
+#define GREAT_SNR 30
+
+/* Compare function for sorting scan results. Return >0 if @b is considered
+ * better. */
+static int wpa_scan_result_compar(const void *a, const void *b)
+{
+#define IS_5GHZ(n) (n > 4000)
+#define MIN(a,b) a < b ? a : b
+	struct wpa_scan_res **_wa = (void *) a;
+	struct wpa_scan_res **_wb = (void *) b;
+	struct wpa_scan_res *wa = *_wa;
+	struct wpa_scan_res *wb = *_wb;
+	int wpa_a, wpa_b, maxrate_a, maxrate_b;
+	int snr_a, snr_b;
+
+	/* WPA/WPA2 support preferred */
+	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
+		wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
+	wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
+		wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
+
+	if (wpa_b && !wpa_a)
+		return 1;
+	if (!wpa_b && wpa_a)
+		return -1;
+
+	/* privacy support preferred */
+	if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
+	    (wb->caps & IEEE80211_CAP_PRIVACY))
+		return 1;
+	if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
+	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
+		return -1;
+
+	if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
+	    !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
+		snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
+		snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+	} else {
+		/* Not suitable information to calculate SNR, so use level */
+		snr_a = wa->level;
+		snr_b = wb->level;
+	}
+
+	/* best/max rate preferred if SNR close enough */
+        if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
+		maxrate_a = wpa_scan_get_max_rate(wa);
+		maxrate_b = wpa_scan_get_max_rate(wb);
+		if (maxrate_a != maxrate_b)
+			return maxrate_b - maxrate_a;
+		if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
+			return IS_5GHZ(wa->freq) ? -1 : 1;
+	}
+
+	/* use freq for channel preference */
+
+	/* all things being equal, use SNR; if SNRs are
+	 * identical, use quality values since some drivers may only report
+	 * that value and leave the signal level zero */
+	if (snr_b == snr_a)
+		return wb->qual - wa->qual;
+	return snr_b - snr_a;
+#undef MIN
+#undef IS_5GHZ
+}
+
+
+#ifdef CONFIG_WPS
+/* Compare function for sorting scan results when searching a WPS AP for
+ * provisioning. Return >0 if @b is considered better. */
+static int wpa_scan_result_wps_compar(const void *a, const void *b)
+{
+	struct wpa_scan_res **_wa = (void *) a;
+	struct wpa_scan_res **_wb = (void *) b;
+	struct wpa_scan_res *wa = *_wa;
+	struct wpa_scan_res *wb = *_wb;
+	int uses_wps_a, uses_wps_b;
+	struct wpabuf *wps_a, *wps_b;
+	int res;
+
+	/* Optimization - check WPS IE existence before allocated memory and
+	 * doing full reassembly. */
+	uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
+	uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
+	if (uses_wps_a && !uses_wps_b)
+		return -1;
+	if (!uses_wps_a && uses_wps_b)
+		return 1;
+
+	if (uses_wps_a && uses_wps_b) {
+		wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
+		wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
+		res = wps_ap_priority_compar(wps_a, wps_b);
+		wpabuf_free(wps_a);
+		wpabuf_free(wps_b);
+		if (res)
+			return res;
+	}
+
+	/*
+	 * Do not use current AP security policy as a sorting criteria during
+	 * WPS provisioning step since the AP may get reconfigured at the
+	 * completion of provisioning.
+	 */
+
+	/* all things being equal, use signal level; if signal levels are
+	 * identical, use quality values since some drivers may only report
+	 * that value and leave the signal level zero */
+	if (wb->level == wa->level)
+		return wb->qual - wa->qual;
+	return wb->level - wa->level;
+}
+#endif /* CONFIG_WPS */
+
+
+static void dump_scan_res(struct wpa_scan_results *scan_res)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	size_t i;
+
+	if (scan_res->res == NULL || scan_res->num == 0)
+		return;
+
+	wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *r = scan_res->res[i];
+		u8 *pos;
+		if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
+		    == WPA_SCAN_LEVEL_DBM) {
+			int snr = r->level - r->noise;
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d snr=%d%s flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, snr,
+				   snr >= GREAT_SNR ? "*" : "", r->flags);
+		} else {
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, r->flags);
+		}
+		pos = (u8 *) (r + 1);
+		if (r->ie_len)
+			wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
+		pos += r->ie_len;
+		if (r->beacon_ie_len)
+			wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
+				    pos, r->beacon_ie_len);
+	}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
+ * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to check
+ * Returns: 0 if the BSSID is filtered or 1 if not
+ *
+ * This function is used to filter out specific BSSIDs from scan reslts mainly
+ * for testing purposes (SET bssid_filter ctrl_iface command).
+ */
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+				      const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->bssid_filter == NULL)
+		return 1;
+
+	for (i = 0; i < wpa_s->bssid_filter_count; i++) {
+		if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
+			      ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+			    struct wpa_scan_results *res)
+{
+	size_t i, j;
+
+	if (wpa_s->bssid_filter == NULL)
+		return;
+
+	for (i = 0, j = 0; i < res->num; i++) {
+		if (wpa_supplicant_filter_bssid_match(wpa_s,
+						      res->res[i]->bssid)) {
+			res->res[j++] = res->res[i];
+		} else {
+			os_free(res->res[i]);
+			res->res[i] = NULL;
+		}
+	}
+
+	if (res->num != j) {
+		wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
+			   (int) (res->num - j));
+		res->num = j;
+	}
+}
+
+
+/**
+ * wpa_supplicant_get_scan_results - Get scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about what was scanned or %NULL if not available
+ * @new_scan: Whether a new scan was performed
+ * Returns: Scan results, %NULL on failure
+ *
+ * This function request the current scan results from the driver and updates
+ * the local BSS list wpa_s->bss. The caller is responsible for freeing the
+ * results with wpa_scan_results_free().
+ */
+struct wpa_scan_results *
+wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
+				struct scan_info *info, int new_scan)
+{
+	struct wpa_scan_results *scan_res;
+	size_t i;
+	int (*compar)(const void *, const void *) = wpa_scan_result_compar;
+
+	scan_res = wpa_drv_get_scan_results2(wpa_s);
+	if (scan_res == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
+		return NULL;
+	}
+	filter_scan_res(wpa_s, scan_res);
+
+#ifdef CONFIG_WPS
+	if (wpas_wps_in_progress(wpa_s)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
+			"provisioning rules");
+		compar = wpa_scan_result_wps_compar;
+	}
+#endif /* CONFIG_WPS */
+
+	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
+	      compar);
+	dump_scan_res(scan_res);
+
+	wpa_bss_update_start(wpa_s);
+	for (i = 0; i < scan_res->num; i++)
+		wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
+	wpa_bss_update_end(wpa_s, info, new_scan);
+
+	return scan_res;
+}
+
+
+/**
+ * wpa_supplicant_update_scan_results - Update scan results from the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function updates the BSS table within wpa_supplicant based on the
+ * currently available scan results from the driver without requesting a new
+ * scan. This is used in cases where the driver indicates an association
+ * (including roaming within ESS) and wpa_supplicant does not yet have the
+ * needed information to complete the connection (e.g., to perform validation
+ * steps in 4-way handshake).
+ */
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_scan_results *scan_res;
+	scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+	if (scan_res == NULL)
+		return -1;
+	wpa_scan_results_free(scan_res);
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/scan.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/scan.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/scan.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,37 +0,0 @@
-/*
- * WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef SCAN_H
-#define SCAN_H
-
-int wpa_supplicant_enabled_networks(struct wpa_config *conf);
-void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
-void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
-				    int scanning);
-struct wpa_driver_scan_params;
-int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params);
-struct wpa_scan_results *
-wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
-				struct scan_info *info, int new_scan);
-int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
-const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
-const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
-				  u32 vendor_type);
-struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
-					     u32 vendor_type);
-void wpa_scan_results_free(struct wpa_scan_results *res);
-
-#endif /* SCAN_H */

Copied: vendor/wpa/2.0/wpa_supplicant/scan.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/scan.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/scan.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/scan.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SCAN_H
+#define SCAN_H
+
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec);
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+				    int scanning);
+struct wpa_driver_scan_params;
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params);
+struct wpa_scan_results *
+wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
+				struct scan_info *info, int new_scan);
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
+const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
+const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
+				  u32 vendor_type);
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+				      const u8 *bssid);
+
+#endif /* SCAN_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/sme.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/sme.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/sme.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,490 +0,0 @@
-/*
- * wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "common/wpa_common.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "wpas_glue.h"
-#include "wps_supplicant.h"
-#include "notify.h"
-#include "blacklist.h"
-#include "bss.h"
-#include "scan.h"
-#include "sme.h"
-
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-		      struct wpa_bss *bss, struct wpa_ssid *ssid)
-{
-	struct wpa_driver_auth_params params;
-	struct wpa_ssid *old_ssid;
-#ifdef CONFIG_IEEE80211R
-	const u8 *ie;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211R
-	const u8 *md = NULL;
-#endif /* CONFIG_IEEE80211R */
-	int i, bssid_changed;
-
-	if (bss == NULL) {
-		wpa_printf(MSG_ERROR, "SME: No scan result available for the "
-			   "network");
-		return;
-	}
-
-	wpa_s->current_bss = bss;
-
-	os_memset(&params, 0, sizeof(params));
-	wpa_s->reassociate = 0;
-
-	params.freq = bss->freq;
-	params.bssid = bss->bssid;
-	params.ssid = bss->ssid;
-	params.ssid_len = bss->ssid_len;
-
-	if (wpa_s->sme.ssid_len != params.ssid_len ||
-	    os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
-		wpa_s->sme.prev_bssid_set = 0;
-
-	wpa_s->sme.freq = params.freq;
-	os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
-	wpa_s->sme.ssid_len = params.ssid_len;
-
-	params.auth_alg = WPA_AUTH_ALG_OPEN;
-#ifdef IEEE8021X_EAPOL
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		if (ssid->leap) {
-			if (ssid->non_leap == 0)
-				params.auth_alg = WPA_AUTH_ALG_LEAP;
-			else
-				params.auth_alg |= WPA_AUTH_ALG_LEAP;
-		}
-	}
-#endif /* IEEE8021X_EAPOL */
-	wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
-		   params.auth_alg);
-	if (ssid->auth_alg) {
-		params.auth_alg = ssid->auth_alg;
-		wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
-			   params.auth_alg);
-	}
-
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i])
-			params.wep_key[i] = ssid->wep_key[i];
-		params.wep_key_len[i] = ssid->wep_key_len[i];
-	}
-	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
-
-	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-	os_memset(wpa_s->bssid, 0, ETH_ALEN);
-	os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
-
-	if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
-	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-			       WPA_KEY_MGMT_FT_IEEE8021X |
-			       WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			       WPA_KEY_MGMT_PSK_SHA256))) {
-		int try_opportunistic;
-		try_opportunistic = ssid->proactive_key_caching &&
-			(ssid->proto & WPA_PROTO_RSN);
-		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-					    wpa_s->current_ssid,
-					    try_opportunistic) == 0)
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
-		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
-		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
-					      wpa_s->sme.assoc_req_ie,
-					      &wpa_s->sme.assoc_req_ie_len)) {
-			wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-				   "management and encryption suites");
-			return;
-		}
-	} else if (ssid->key_mgmt &
-		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
-		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
-		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
-					      wpa_s->sme.assoc_req_ie,
-					      &wpa_s->sme.assoc_req_ie_len)) {
-			wpa_printf(MSG_WARNING, "SME: Failed to set WPA key "
-				   "management and encryption suites (no scan "
-				   "results)");
-			return;
-		}
-#ifdef CONFIG_WPS
-	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-		struct wpabuf *wps_ie;
-		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
-		if (wps_ie && wpabuf_len(wps_ie) <=
-		    sizeof(wpa_s->sme.assoc_req_ie)) {
-			wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
-			os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
-				  wpa_s->sme.assoc_req_ie_len);
-		} else
-			wpa_s->sme.assoc_req_ie_len = 0;
-		wpabuf_free(wps_ie);
-		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
-#endif /* CONFIG_WPS */
-	} else {
-		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
-		wpa_s->sme.assoc_req_ie_len = 0;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
-	if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
-		md = ie + 2;
-	wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
-	if (md) {
-		/* Prepare for the next transition */
-		wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
-	}
-
-	if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
-				    WPA_KEY_MGMT_FT_IEEE8021X)) {
-		if (wpa_s->sme.assoc_req_ie_len + 5 <
-		    sizeof(wpa_s->sme.assoc_req_ie)) {
-			struct rsn_mdie *mdie;
-			u8 *pos = wpa_s->sme.assoc_req_ie +
-				wpa_s->sme.assoc_req_ie_len;
-			*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-			*pos++ = sizeof(*mdie);
-			mdie = (struct rsn_mdie *) pos;
-			os_memcpy(mdie->mobility_domain, md,
-				  MOBILITY_DOMAIN_ID_LEN);
-			mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN];
-			wpa_s->sme.assoc_req_ie_len += 5;
-		}
-
-		if (wpa_s->sme.ft_used &&
-		    os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
-		    wpa_sm_has_ptk(wpa_s->wpa)) {
-			wpa_printf(MSG_DEBUG, "SME: Trying to use FT "
-				   "over-the-air");
-			params.auth_alg = WPA_AUTH_ALG_FT;
-			params.ie = wpa_s->sme.ft_ies;
-			params.ie_len = wpa_s->sme.ft_ies_len;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
-	wpa_s->sme.mfp = ssid->ieee80211w;
-	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
-		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-		struct wpa_ie_data _ie;
-		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
-		    _ie.capabilities &
-		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
-			wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
-				   "require MFP");
-			wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
-		}
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	wpa_supplicant_cancel_scan(wpa_s);
-
-	wpa_msg(wpa_s, MSG_INFO, "Trying to authenticate with " MACSTR
-		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
-		wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
-
-	wpa_clear_keys(wpa_s, bss->bssid);
-	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = ssid;
-	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)
-		wpas_notify_network_changed(wpa_s);
-
-	wpa_s->sme.auth_alg = params.auth_alg;
-	if (wpa_drv_authenticate(wpa_s, &params) < 0) {
-		wpa_msg(wpa_s, MSG_INFO, "Authentication request to the "
-			"driver failed");
-		wpa_supplicant_req_scan(wpa_s, 1, 0);
-		return;
-	}
-
-	/* TODO: add timeout on authentication */
-
-	/*
-	 * Association will be started based on the authentication event from
-	 * the driver.
-	 */
-}
-
-
-void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
-{
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-			   "network is not selected");
-		return;
-	}
-
-	if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
-		wpa_printf(MSG_DEBUG, "SME: Ignore authentication event when "
-			   "not in authenticating state");
-		return;
-	}
-
-	if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "SME: Ignore authentication with "
-			   "unexpected peer " MACSTR,
-			   MAC2STR(data->auth.peer));
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
-		   " auth_type=%d status_code=%d",
-		   MAC2STR(data->auth.peer), data->auth.auth_type,
-		   data->auth.status_code);
-	wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
-		    data->auth.ies, data->auth.ies_len);
-
-	if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "SME: Authentication failed (status "
-			   "code %d)", data->auth.status_code);
-
-		if (data->auth.status_code !=
-		    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
-		    wpa_s->sme.auth_alg == data->auth.auth_type ||
-		    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP)
-			return;
-
-		switch (data->auth.auth_type) {
-		case WLAN_AUTH_OPEN:
-			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
-
-			wpa_printf(MSG_DEBUG, "SME: Trying SHARED auth");
-			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
-						 wpa_s->current_ssid);
-			return;
-
-		case WLAN_AUTH_SHARED_KEY:
-			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
-
-			wpa_printf(MSG_DEBUG, "SME: Trying LEAP auth");
-			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
-						 wpa_s->current_ssid);
-			return;
-
-		default:
-			return;
-		}
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (data->auth.auth_type == WLAN_AUTH_FT) {
-		union wpa_event_data edata;
-		os_memset(&edata, 0, sizeof(edata));
-		edata.ft_ies.ies = data->auth.ies;
-		edata.ft_ies.ies_len = data->auth.ies_len;
-		os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN);
-		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata);
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	sme_associate(wpa_s, ssid->mode, data->auth.peer,
-		      data->auth.auth_type);
-}
-
-
-void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
-		   const u8 *bssid, u16 auth_type)
-{
-	struct wpa_driver_associate_params params;
-	struct ieee802_11_elems elems;
-
-	os_memset(&params, 0, sizeof(params));
-	params.bssid = bssid;
-	params.ssid = wpa_s->sme.ssid;
-	params.ssid_len = wpa_s->sme.ssid_len;
-	params.freq = wpa_s->sme.freq;
-	params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
-		wpa_s->sme.assoc_req_ie : NULL;
-	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
-#ifdef CONFIG_IEEE80211R
-	if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
-		params.wpa_ie = wpa_s->sme.ft_ies;
-		params.wpa_ie_len = wpa_s->sme.ft_ies_len;
-	}
-#endif /* CONFIG_IEEE80211R */
-	params.mode = mode;
-	params.mgmt_frame_protection = wpa_s->sme.mfp;
-	if (wpa_s->sme.prev_bssid_set)
-		params.prev_bssid = wpa_s->sme.prev_bssid;
-
-	wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
-		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
-		params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
-		params.freq);
-
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
-
-	if (params.wpa_ie == NULL ||
-	    ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
-	    < 0) {
-		wpa_printf(MSG_DEBUG, "SME: Could not parse own IEs?!");
-		os_memset(&elems, 0, sizeof(elems));
-	}
-	if (elems.rsn_ie)
-		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
-					elems.rsn_ie_len + 2);
-	else if (elems.wpa_ie)
-		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
-					elems.wpa_ie_len + 2);
-	else
-		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-
-	if (wpa_drv_associate(wpa_s, &params) < 0) {
-		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
-			"failed");
-		wpa_supplicant_req_scan(wpa_s, 5, 0);
-		return;
-	}
-
-	/* TODO: add timeout on association */
-}
-
-
-int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-		      const u8 *ies, size_t ies_len)
-{
-	if (md == NULL || ies == NULL) {
-		wpa_printf(MSG_DEBUG, "SME: Remove mobility domain");
-		os_free(wpa_s->sme.ft_ies);
-		wpa_s->sme.ft_ies = NULL;
-		wpa_s->sme.ft_ies_len = 0;
-		wpa_s->sme.ft_used = 0;
-		return 0;
-	}
-
-	os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
-	wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
-	os_free(wpa_s->sme.ft_ies);
-	wpa_s->sme.ft_ies = os_malloc(ies_len);
-	if (wpa_s->sme.ft_ies == NULL)
-		return -1;
-	os_memcpy(wpa_s->sme.ft_ies, ies, ies_len);
-	wpa_s->sme.ft_ies_len = ies_len;
-	return 0;
-}
-
-
-void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-			    union wpa_event_data *data)
-{
-	int bssid_changed;
-	int timeout = 5000;
-
-	wpa_printf(MSG_DEBUG, "SME: Association with " MACSTR " failed: "
-		   "status code %d", MAC2STR(wpa_s->pending_bssid),
-		   data->assoc_reject.status_code);
-
-	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-
-	/*
-	 * For now, unconditionally terminate the previous authentication. In
-	 * theory, this should not be needed, but mac80211 gets quite confused
-	 * if the authentication is left pending.. Some roaming cases might
-	 * benefit from using the previous authentication, so this could be
-	 * optimized in the future.
-	 */
-	if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
-				   WLAN_REASON_DEAUTH_LEAVING) < 0) {
-		wpa_msg(wpa_s, MSG_INFO,
-			"Deauth request to the driver failed");
-	}
-	wpa_s->sme.prev_bssid_set = 0;
-
-	if (wpa_blacklist_add(wpa_s, wpa_s->pending_bssid) == 0) {
-		struct wpa_blacklist *b;
-		b = wpa_blacklist_get(wpa_s, wpa_s->pending_bssid);
-		if (b && b->count < 3) {
-			/*
-			 * Speed up next attempt if there could be other APs
-			 * that could accept association.
-			 */
-			timeout = 100;
-		}
-	}
-	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-	os_memset(wpa_s->bssid, 0, ETH_ALEN);
-	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
-
-	/*
-	 * TODO: if more than one possible AP is available in scan results,
-	 * could try the other ones before requesting a new scan.
-	 */
-	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
-				1000 * (timeout % 1000));
-}
-
-
-void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
-			      union wpa_event_data *data)
-{
-	wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
-	wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
-void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
-			       union wpa_event_data *data)
-{
-	wpa_printf(MSG_DEBUG, "SME: Association timed out");
-	wpa_supplicant_mark_disassoc(wpa_s);
-	wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
-void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-			union wpa_event_data *data)
-{
-	wpa_printf(MSG_DEBUG, "SME: Disassociation event received");
-	if (wpa_s->sme.prev_bssid_set &&
-	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
-		/*
-		 * cfg80211/mac80211 can get into somewhat confused state if
-		 * the AP only disassociates us and leaves us in authenticated
-		 * state. For now, force the state to be cleared to avoid
-		 * confusing errors if we try to associate with the AP again.
-		 */
-		wpa_printf(MSG_DEBUG, "SME: Deauthenticate to clear driver "
-			   "state");
-		wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
-				       WLAN_REASON_DEAUTH_LEAVING);
-	}
-}

Copied: vendor/wpa/2.0/wpa_supplicant/sme.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/sme.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/sme.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/sme.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1241 @@
+/*
+ * wpa_supplicant - SME
+ * Copyright (c) 2009-2010, Jouni Malinen <j at 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "common/wpa_common.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+#include "notify.h"
+#include "bss.h"
+#include "scan.h"
+#include "sme.h"
+#include "hs20_supplicant.h"
+
+#define SME_AUTH_TIMEOUT 5
+#define SME_ASSOC_TIMEOUT 5
+
+static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx);
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_IEEE80211W
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_SAE
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(4 + 2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 1); /* Transaction seq# */
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+	/* TODO: Anti-Clogging Token (if requested) */
+	/* TODO: Scalar */
+	/* TODO: Element */
+
+	return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(4 + 2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 2); /* Transaction seq# */
+	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+	wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm);
+	wpa_s->sme.sae_send_confirm++;
+	/* TODO: Confirm */
+
+	return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+static void sme_send_authentication(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss, struct wpa_ssid *ssid,
+				    int start)
+{
+	struct wpa_driver_auth_params params;
+	struct wpa_ssid *old_ssid;
+#ifdef CONFIG_IEEE80211R
+	const u8 *ie;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211R
+	const u8 *md = NULL;
+#endif /* CONFIG_IEEE80211R */
+	int i, bssid_changed;
+	struct wpabuf *resp = NULL;
+	u8 ext_capab[10];
+	int ext_capab_len;
+
+	if (bss == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
+			"the network");
+		return;
+	}
+
+	wpa_s->current_bss = bss;
+
+	os_memset(&params, 0, sizeof(params));
+	wpa_s->reassociate = 0;
+
+	params.freq = bss->freq;
+	params.bssid = bss->bssid;
+	params.ssid = bss->ssid;
+	params.ssid_len = bss->ssid_len;
+	params.p2p = ssid->p2p_group;
+
+	if (wpa_s->sme.ssid_len != params.ssid_len ||
+	    os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
+		wpa_s->sme.prev_bssid_set = 0;
+
+	wpa_s->sme.freq = params.freq;
+	os_memcpy(wpa_s->sme.ssid, params.ssid, params.ssid_len);
+	wpa_s->sme.ssid_len = params.ssid_len;
+
+	params.auth_alg = WPA_AUTH_ALG_OPEN;
+#ifdef IEEE8021X_EAPOL
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if (ssid->leap) {
+			if (ssid->non_leap == 0)
+				params.auth_alg = WPA_AUTH_ALG_LEAP;
+			else
+				params.auth_alg |= WPA_AUTH_ALG_LEAP;
+		}
+	}
+#endif /* IEEE8021X_EAPOL */
+	wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x",
+		params.auth_alg);
+	if (ssid->auth_alg) {
+		params.auth_alg = ssid->auth_alg;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+			"0x%x", params.auth_alg);
+	}
+#ifdef CONFIG_SAE
+	if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
+		const u8 *rsn;
+		struct wpa_ie_data ied;
+
+		rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (rsn &&
+		    wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
+			if (wpa_key_mgmt_sae(ied.key_mgmt)) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+				params.auth_alg = WPA_AUTH_ALG_SAE;
+			}
+		}
+	}
+#endif /* CONFIG_SAE */
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i])
+			params.wep_key[i] = ssid->wep_key[i];
+		params.wep_key_len[i] = ssid->wep_key_len[i];
+	}
+	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+
+	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+	os_memset(wpa_s->bssid, 0, ETH_ALEN);
+	os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+	if (bssid_changed)
+		wpas_notify_bssid_changed(wpa_s);
+
+	if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
+	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
+	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+		int try_opportunistic;
+		try_opportunistic = (ssid->proactive_key_caching < 0 ?
+				     wpa_s->conf->okc :
+				     ssid->proactive_key_caching) &&
+			(ssid->proto & WPA_PROTO_RSN);
+		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+					    wpa_s->current_ssid,
+					    try_opportunistic) == 0)
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+					      wpa_s->sme.assoc_req_ie,
+					      &wpa_s->sme.assoc_req_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+				"key management and encryption suites");
+			return;
+		}
+	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+		   wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+		/*
+		 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+		 * use non-WPA since the scan results did not indicate that the
+		 * AP is using WPA or WPA2.
+		 */
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_s->sme.assoc_req_ie_len = 0;
+	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
+		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+					      wpa_s->sme.assoc_req_ie,
+					      &wpa_s->sme.assoc_req_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
+				"key management and encryption suites (no "
+				"scan results)");
+			return;
+		}
+#ifdef CONFIG_WPS
+	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+		if (wps_ie && wpabuf_len(wps_ie) <=
+		    sizeof(wpa_s->sme.assoc_req_ie)) {
+			wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
+			os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
+				  wpa_s->sme.assoc_req_ie_len);
+		} else
+			wpa_s->sme.assoc_req_ie_len = 0;
+		wpabuf_free(wps_ie);
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+#endif /* CONFIG_WPS */
+	} else {
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_s->sme.assoc_req_ie_len = 0;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+	if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+		md = ie + 2;
+	wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+	if (md) {
+		/* Prepare for the next transition */
+		wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+	}
+
+	if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
+		if (wpa_s->sme.assoc_req_ie_len + 5 <
+		    sizeof(wpa_s->sme.assoc_req_ie)) {
+			struct rsn_mdie *mdie;
+			u8 *pos = wpa_s->sme.assoc_req_ie +
+				wpa_s->sme.assoc_req_ie_len;
+			*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+			*pos++ = sizeof(*mdie);
+			mdie = (struct rsn_mdie *) pos;
+			os_memcpy(mdie->mobility_domain, md,
+				  MOBILITY_DOMAIN_ID_LEN);
+			mdie->ft_capab = md[MOBILITY_DOMAIN_ID_LEN];
+			wpa_s->sme.assoc_req_ie_len += 5;
+		}
+
+		if (wpa_s->sme.ft_used &&
+		    os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
+		    wpa_sm_has_ptk(wpa_s->wpa)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
+				"over-the-air");
+			params.auth_alg = WPA_AUTH_ALG_FT;
+			params.ie = wpa_s->sme.ft_ies;
+			params.ie_len = wpa_s->sme.ft_ies_len;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		wpa_s->conf->pmf : ssid->ieee80211w;
+	if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
+		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		struct wpa_ie_data _ie;
+		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
+		    _ie.capabilities &
+		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected AP supports "
+				"MFP: require MFP");
+			wpa_s->sme.mfp = MGMT_FRAME_PROTECTION_REQUIRED;
+		}
+	}
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p) {
+		u8 *pos;
+		size_t len;
+		int res;
+		pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+		len = sizeof(wpa_s->sme.assoc_req_ie) -
+			wpa_s->sme.assoc_req_ie_len;
+		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+					    ssid->p2p_group);
+		if (res >= 0)
+			wpa_s->sme.assoc_req_ie_len += res;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20) {
+		struct wpabuf *hs20;
+		hs20 = wpabuf_alloc(20);
+		if (hs20) {
+			wpas_hs20_add_indication(hs20);
+			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 */
+
+	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+	if (ext_capab_len > 0) {
+		u8 *pos = wpa_s->sme.assoc_req_ie;
+		if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+			pos += 2 + pos[1];
+		os_memmove(pos + ext_capab_len, pos,
+			   wpa_s->sme.assoc_req_ie_len -
+			   (pos - wpa_s->sme.assoc_req_ie));
+		wpa_s->sme.assoc_req_ie_len += ext_capab_len;
+		os_memcpy(pos, ext_capab, ext_capab_len);
+	}
+
+#ifdef CONFIG_SAE
+	if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+		if (start)
+			resp = sme_auth_build_sae_commit(wpa_s);
+		else
+			resp = sme_auth_build_sae_confirm(wpa_s);
+		if (resp == NULL)
+			return;
+		params.sae_data = wpabuf_head(resp);
+		params.sae_data_len = wpabuf_len(resp);
+		wpa_s->sme.sae_state = start ? SME_SAE_COMMIT : SME_SAE_CONFIRM;
+	}
+#endif /* CONFIG_SAE */
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
+		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
+		wpa_ssid_txt(params.ssid, params.ssid_len), params.freq);
+
+	wpa_clear_keys(wpa_s, bss->bssid);
+	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+	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)
+		wpas_notify_network_changed(wpa_s);
+
+	wpa_s->sme.auth_alg = params.auth_alg;
+	if (wpa_drv_authenticate(wpa_s, &params) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
+			"driver failed");
+		wpas_connection_failed(wpa_s, bss->bssid);
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpabuf_free(resp);
+		return;
+	}
+
+	eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+			       NULL);
+
+	/*
+	 * Association will be started based on the authentication event from
+	 * the driver.
+	 */
+
+	wpabuf_free(resp);
+}
+
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+		      struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+	wpa_s->sme.sae_state = SME_SAE_INIT;
+	wpa_s->sme.sae_send_confirm = 0;
+	sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+
+static int sme_sae_process_commit(struct wpa_supplicant *wpa_s, const u8 *data,
+				  size_t len)
+{
+	/* Check Finite Cyclic Group */
+	if (len < 2)
+		return -1;
+	if (WPA_GET_LE16(data) != 19) {
+		wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+			   WPA_GET_LE16(data));
+		return -1;
+	}
+
+	/* TODO */
+
+	return 0;
+}
+
+
+static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data,
+				   size_t len)
+{
+	u16 rc;
+
+	if (len < 2)
+		return -1;
+	rc = WPA_GET_LE16(data);
+	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+	/* TODO */
+	return 0;
+}
+
+
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+			u16 status_code, const u8 *data, size_t len)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+		"status code %u", auth_transaction, status_code);
+	wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+	if (status_code != WLAN_STATUS_SUCCESS)
+		return -1;
+
+	if (auth_transaction == 1) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+		if (wpa_s->current_bss == NULL ||
+		    wpa_s->current_ssid == NULL)
+			return -1;
+		if (wpa_s->sme.sae_state != SME_SAE_COMMIT)
+			return -1;
+		if (sme_sae_process_commit(wpa_s, data, len) < 0)
+			return -1;
+		sme_send_authentication(wpa_s, wpa_s->current_bss,
+					wpa_s->current_ssid, 0);
+		return 0;
+	} else if (auth_transaction == 2) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
+		if (wpa_s->sme.sae_state != SME_SAE_CONFIRM)
+			return -1;
+		if (sme_sae_process_confirm(wpa_s, data, len) < 0)
+			return -1;
+		return 1;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_SAE */
+
+
+void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+			"when network is not selected");
+		return;
+	}
+
+	if (wpa_s->wpa_state != WPA_AUTHENTICATING) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
+			"when not in authenticating state");
+		return;
+	}
+
+	if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with "
+			"unexpected peer " MACSTR,
+			MAC2STR(data->auth.peer));
+		return;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
+		" auth_type=%d auth_transaction=%d status_code=%d",
+		MAC2STR(data->auth.peer), data->auth.auth_type,
+		data->auth.auth_transaction, data->auth.status_code);
+	wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
+		    data->auth.ies, data->auth.ies_len);
+
+	eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+
+#ifdef CONFIG_SAE
+	if (data->auth.auth_type == WLAN_AUTH_SAE) {
+		int res;
+		res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
+				   data->auth.status_code, data->auth.ies,
+				   data->auth.ies_len);
+		if (res < 0) {
+			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+		}
+		if (res != 1)
+			return;
+	}
+#endif /* CONFIG_SAE */
+
+	if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
+			"code %d)", data->auth.status_code);
+
+		if (data->auth.status_code !=
+		    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
+		    wpa_s->sme.auth_alg == data->auth.auth_type ||
+		    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
+			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			return;
+		}
+
+		switch (data->auth.auth_type) {
+		case WLAN_AUTH_OPEN:
+			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_SHARED;
+
+			wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying SHARED auth");
+			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
+						 wpa_s->current_ssid);
+			return;
+
+		case WLAN_AUTH_SHARED_KEY:
+			wpa_s->current_ssid->auth_alg = WPA_AUTH_ALG_LEAP;
+
+			wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying LEAP auth");
+			wpa_supplicant_associate(wpa_s, wpa_s->current_bss,
+						 wpa_s->current_ssid);
+			return;
+
+		default:
+			return;
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (data->auth.auth_type == WLAN_AUTH_FT) {
+		union wpa_event_data edata;
+		os_memset(&edata, 0, sizeof(edata));
+		edata.ft_ies.ies = data->auth.ies;
+		edata.ft_ies.ies_len = data->auth.ies_len;
+		os_memcpy(edata.ft_ies.target_ap, data->auth.peer, ETH_ALEN);
+		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &edata);
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	sme_associate(wpa_s, ssid->mode, data->auth.peer,
+		      data->auth.auth_type);
+}
+
+
+void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
+		   const u8 *bssid, u16 auth_type)
+{
+	struct wpa_driver_associate_params params;
+	struct ieee802_11_elems elems;
+#ifdef CONFIG_HT_OVERRIDES
+	struct ieee80211_ht_capabilities htcaps;
+	struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+
+	os_memset(&params, 0, sizeof(params));
+	params.bssid = bssid;
+	params.ssid = wpa_s->sme.ssid;
+	params.ssid_len = wpa_s->sme.ssid_len;
+	params.freq = wpa_s->sme.freq;
+	params.bg_scan_period = wpa_s->current_ssid ?
+		wpa_s->current_ssid->bg_scan_period : -1;
+	params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
+		wpa_s->sme.assoc_req_ie : NULL;
+	params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+	params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+	params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+#ifdef CONFIG_HT_OVERRIDES
+	os_memset(&htcaps, 0, sizeof(htcaps));
+	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+	params.htcaps = (u8 *) &htcaps;
+	params.htcaps_mask = (u8 *) &htcaps_mask;
+	wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_IEEE80211R
+	if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+		params.wpa_ie = wpa_s->sme.ft_ies;
+		params.wpa_ie_len = wpa_s->sme.ft_ies_len;
+	}
+#endif /* CONFIG_IEEE80211R */
+	params.mode = mode;
+	params.mgmt_frame_protection = wpa_s->sme.mfp;
+	if (wpa_s->sme.prev_bssid_set)
+		params.prev_bssid = wpa_s->sme.prev_bssid;
+
+	wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
+		" (SSID='%s' freq=%d MHz)", MAC2STR(params.bssid),
+		params.ssid ? wpa_ssid_txt(params.ssid, params.ssid_len) : "",
+		params.freq);
+
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+
+	if (params.wpa_ie == NULL ||
+	    ieee802_11_parse_elems(params.wpa_ie, params.wpa_ie_len, &elems, 0)
+	    < 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!");
+		os_memset(&elems, 0, sizeof(elems));
+	}
+	if (elems.rsn_ie) {
+		params.wpa_proto = WPA_PROTO_RSN;
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
+					elems.rsn_ie_len + 2);
+	} else if (elems.wpa_ie) {
+		params.wpa_proto = WPA_PROTO_WPA;
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
+					elems.wpa_ie_len + 2);
+	} else
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+	if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
+		params.p2p = 1;
+
+	if (wpa_s->parent->set_sta_uapsd)
+		params.uapsd = wpa_s->parent->sta_uapsd;
+	else
+		params.uapsd = -1;
+
+	if (wpa_drv_associate(wpa_s, &params) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
+			"driver failed");
+		wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+		return;
+	}
+
+	eloop_register_timeout(SME_ASSOC_TIMEOUT, 0, sme_assoc_timer, wpa_s,
+			       NULL);
+}
+
+
+int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
+		      const u8 *ies, size_t ies_len)
+{
+	if (md == NULL || ies == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Remove mobility domain");
+		os_free(wpa_s->sme.ft_ies);
+		wpa_s->sme.ft_ies = NULL;
+		wpa_s->sme.ft_ies_len = 0;
+		wpa_s->sme.ft_used = 0;
+		return 0;
+	}
+
+	os_memcpy(wpa_s->sme.mobility_domain, md, MOBILITY_DOMAIN_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "SME: FT IEs", ies, ies_len);
+	os_free(wpa_s->sme.ft_ies);
+	wpa_s->sme.ft_ies = os_malloc(ies_len);
+	if (wpa_s->sme.ft_ies == NULL)
+		return -1;
+	os_memcpy(wpa_s->sme.ft_ies, ies, ies_len);
+	wpa_s->sme.ft_ies_len = ies_len;
+	return 0;
+}
+
+
+static void sme_deauth(struct wpa_supplicant *wpa_s)
+{
+	int bssid_changed;
+
+	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+
+	if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
+				   WLAN_REASON_DEAUTH_LEAVING) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "SME: Deauth request to the driver "
+			"failed");
+	}
+	wpa_s->sme.prev_bssid_set = 0;
+
+	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+	os_memset(wpa_s->bssid, 0, ETH_ALEN);
+	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+	if (bssid_changed)
+		wpas_notify_bssid_changed(wpa_s);
+}
+
+
+void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+			    union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: "
+		"status code %d", MAC2STR(wpa_s->pending_bssid),
+		data->assoc_reject.status_code);
+
+	eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+
+	/*
+	 * For now, unconditionally terminate the previous authentication. In
+	 * theory, this should not be needed, but mac80211 gets quite confused
+	 * if the authentication is left pending.. Some roaming cases might
+	 * benefit from using the previous authentication, so this could be
+	 * optimized in the future.
+	 */
+	sme_deauth(wpa_s);
+}
+
+
+void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
+			      union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out");
+	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+	wpa_supplicant_mark_disassoc(wpa_s);
+}
+
+
+void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
+			       union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out");
+	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+	wpa_supplicant_mark_disassoc(wpa_s);
+}
+
+
+void sme_event_disassoc(struct wpa_supplicant *wpa_s,
+			union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
+	if (wpa_s->sme.prev_bssid_set) {
+		/*
+		 * cfg80211/mac80211 can get into somewhat confused state if
+		 * the AP only disassociates us and leaves us in authenticated
+		 * state. For now, force the state to be cleared to avoid
+		 * confusing errors if we try to associate with the AP again.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Deauthenticate to clear "
+			"driver state");
+		wpa_drv_deauthenticate(wpa_s, wpa_s->sme.prev_bssid,
+				       WLAN_REASON_DEAUTH_LEAVING);
+	}
+}
+
+
+static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	if (wpa_s->wpa_state == WPA_AUTHENTICATING) {
+		wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout");
+		sme_deauth(wpa_s);
+	}
+}
+
+
+static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+		wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout");
+		sme_deauth(wpa_s);
+	}
+}
+
+
+void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+	/* Make sure timers are cleaned up appropriately. */
+	if (wpa_s->wpa_state != WPA_ASSOCIATING)
+		eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+	if (wpa_s->wpa_state != WPA_AUTHENTICATING)
+		eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+}
+
+
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+				       const u8 *prev_pending_bssid)
+{
+	/*
+	 * mac80211-workaround to force deauth on failed auth cmd,
+	 * requires us to remain in authenticating state to allow the
+	 * second authentication attempt to be continued properly.
+	 */
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Allow pending authentication "
+		"to proceed after disconnection event");
+	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+	os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN);
+
+	/*
+	 * Re-arm authentication timer in case auth fails for whatever reason.
+	 */
+	eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+	eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s,
+			       NULL);
+}
+
+
+void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+	os_free(wpa_s->sme.ft_ies);
+	wpa_s->sme.ft_ies = NULL;
+	wpa_s->sme.ft_ies_len = 0;
+#ifdef CONFIG_IEEE80211W
+	sme_stop_sa_query(wpa_s);
+#endif /* CONFIG_IEEE80211W */
+
+	eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+	eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+	eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+				   const u8 *chan_list, u8 num_channels,
+				   u8 num_intol)
+{
+	struct ieee80211_2040_bss_coex_ie *bc_ie;
+	struct ieee80211_2040_intol_chan_report *ic_report;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+		   MAC2STR(wpa_s->bssid));
+
+	buf = wpabuf_alloc(2 + /* action.category + action_code */
+			   sizeof(struct ieee80211_2040_bss_coex_ie) +
+			   sizeof(struct ieee80211_2040_intol_chan_report) +
+			   num_channels);
+	if (buf == NULL)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+	bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+	bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+	bc_ie->length = 1;
+	if (num_intol)
+		bc_ie->coex_param |= WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+	if (num_channels > 0) {
+		ic_report = wpabuf_put(buf, sizeof(*ic_report));
+		ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+		ic_report->length = num_channels + 1;
+		ic_report->op_class = 0;
+		os_memcpy(wpabuf_put(buf, num_channels), chan_list,
+			  num_channels);
+	}
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"SME: Failed to send 20/40 BSS Coexistence frame");
+	}
+
+	wpabuf_free(buf);
+}
+
+
+/**
+ * enum wpas_band - Frequency band
+ * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
+ * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum wpas_band {
+	WPAS_BAND_2GHZ,
+	WPAS_BAND_5GHZ,
+	WPAS_BAND_INVALID
+};
+
+/**
+ * freq_to_channel - Convert frequency into channel info
+ * @channel: Buffer for returning channel number
+ * Returns: Band (2 or 5 GHz)
+ */
+static enum wpas_band freq_to_channel(int freq, u8 *channel)
+{
+	enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
+	u8 chan = 0;
+
+	if (freq >= 2412 && freq <= 2472)
+		chan = (freq - 2407) / 5;
+	else if (freq == 2484)
+		chan = 14;
+	else if (freq >= 5180 && freq <= 5805)
+		chan = (freq - 5000) / 5;
+
+	*channel = chan;
+	return band;
+}
+
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	const u8 *ie;
+	u16 ht_cap;
+	u8 chan_list[P2P_MAX_CHANNELS], channel;
+	u8 num_channels = 0, num_intol = 0, i;
+
+	if (!wpa_s->sme.sched_obss_scan)
+		return 0;
+
+	wpa_s->sme.sched_obss_scan = 0;
+	if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+		return 1;
+
+	/*
+	 * Check whether AP uses regulatory triplet or channel triplet in
+	 * country info. Right now the operating class of the BSS channel
+	 * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12),
+	 * based on the assumption that operating class triplet is not used in
+	 * beacon frame. If the First Channel Number/Operating Extension
+	 * Identifier octet has a positive integer value of 201 or greater,
+	 * then its operating class triplet.
+	 *
+	 * TODO: If Supported Operating Classes element is present in beacon
+	 * frame, have to lookup operating class in Annex E and fill them in
+	 * 2040 coex frame.
+	 */
+	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+	if (ie && (ie[1] >= 6) && (ie[5] >= 201))
+		return 1;
+
+	os_memset(chan_list, 0, sizeof(chan_list));
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		/* Skip other band bss */
+		if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ)
+			continue;
+
+		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+		ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+		if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+			/* Check whether the channel is already considered */
+			for (i = 0; i < num_channels; i++) {
+				if (channel == chan_list[i])
+					break;
+			}
+			if (i != num_channels)
+				continue;
+
+			if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
+				num_intol++;
+
+			chan_list[num_channels++] = channel;
+		}
+	}
+
+	sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol);
+	return 1;
+}
+
+
+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)
+{
+	/* Include only supported channels for the specified band */
+	struct hostapd_hw_modes *mode;
+	int count, i;
+
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+	if (mode == NULL) {
+		/* No channels supported in this band - use empty list */
+		params->freqs = os_zalloc(sizeof(int));
+		return;
+	}
+
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	for (count = 0, i = 0; i < mode->num_channels; i++) {
+		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		params->freqs[count++] = mode->channels[i].freq;
+	}
+}
+
+
+static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_driver_scan_params params;
+
+	if (!wpa_s->current_bss) {
+		wpa_printf(MSG_DEBUG, "SME OBSS: Ignore scan request");
+		return;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+	wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+	wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
+
+	if (wpa_supplicant_trigger_scan(wpa_s, &params))
+		wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
+	else
+		wpa_s->sme.sched_obss_scan = 1;
+	os_free(params.freqs);
+
+	eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+			       sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
+{
+	const u8 *ie;
+	struct wpa_bss *bss = wpa_s->current_bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct hostapd_hw_modes *hw_mode = NULL;
+	int i;
+
+	eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
+	wpa_s->sme.sched_obss_scan = 0;
+	if (!enable)
+		return;
+
+	/*
+	 * Schedule OBSS scan if driver is using station SME in wpa_supplicant
+	 * or it expects OBSS scan to be performed by wpa_supplicant.
+	 */
+	if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+	      (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
+	    ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+		return;
+
+	if (!wpa_s->hw.modes)
+		return;
+
+	/* only HT caps in 11g mode are relevant */
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		hw_mode = &wpa_s->hw.modes[i];
+		if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G)
+			break;
+	}
+
+	/* Driver does not support HT40 for 11g or doesn't have 11g. */
+	if (i == wpa_s->hw.num_modes || !hw_mode ||
+	    !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+		return;
+
+	if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
+		return; /* Not associated on 2.4 GHz band */
+
+	/* Check whether AP supports HT40 */
+	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP);
+	if (!ie || ie[1] < 2 ||
+	    !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+		return; /* AP does not support HT40 */
+
+	ie = wpa_bss_get_ie(wpa_s->current_bss,
+			    WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS);
+	if (!ie || ie[1] < 14)
+		return; /* AP does not request OBSS scans */
+
+	wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6);
+	if (wpa_s->sme.obss_scan_int < 10) {
+		wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u "
+			   "replaced with the minimum 10 sec",
+			   wpa_s->sme.obss_scan_int);
+		wpa_s->sme.obss_scan_int = 10;
+	}
+	wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec",
+		   wpa_s->sme.obss_scan_int);
+	eloop_register_timeout(wpa_s->sme.obss_scan_int, 0,
+			       sme_obss_scan_timeout, wpa_s, NULL);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static const unsigned int sa_query_max_timeout = 1000;
+static const unsigned int sa_query_retry_timeout = 201;
+
+static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
+{
+	u32 tu;
+	struct os_time now, passed;
+	os_get_time(&now);
+	os_time_sub(&now, &wpa_s->sme.sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (sa_query_max_timeout < tu) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: SA Query timed out");
+		sme_stop_sa_query(wpa_s);
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_PREV_AUTH_NOT_VALID);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
+				  const u8 *trans_id)
+{
+	u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
+		MACSTR, MAC2STR(wpa_s->bssid));
+	wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+	req[0] = WLAN_ACTION_SA_QUERY;
+	req[1] = WLAN_SA_QUERY_REQUEST;
+	os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				req, sizeof(req), 0) < 0)
+		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
+			"Request");
+}
+
+
+static void sme_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	unsigned int timeout, sec, usec;
+	u8 *trans_id, *nbuf;
+
+	if (wpa_s->sme.sa_query_count > 0 &&
+	    sme_check_sa_query_timeout(wpa_s))
+		return;
+
+	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)
+		return;
+	if (wpa_s->sme.sa_query_count == 0) {
+		/* Starting a new SA Query procedure */
+		os_get_time(&wpa_s->sme.sa_query_start);
+	}
+	trans_id = nbuf + wpa_s->sme.sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+	wpa_s->sme.sa_query_trans_id = nbuf;
+	wpa_s->sme.sa_query_count++;
+
+	os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	timeout = sa_query_retry_timeout;
+	sec = ((timeout / 1000) * 1024) / 1000;
+	usec = (timeout % 1000) * 1024;
+	eloop_register_timeout(sec, usec, sme_sa_query_timer, wpa_s, NULL);
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association SA Query attempt %d",
+		wpa_s->sme.sa_query_count);
+
+	sme_send_sa_query_req(wpa_s, trans_id);
+}
+
+
+static void sme_start_sa_query(struct wpa_supplicant *wpa_s)
+{
+	sme_sa_query_timer(wpa_s, NULL);
+}
+
+
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
+	os_free(wpa_s->sme.sa_query_trans_id);
+	wpa_s->sme.sa_query_trans_id = NULL;
+	wpa_s->sme.sa_query_count = 0;
+}
+
+
+void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
+				 const u8 *da, u16 reason_code)
+{
+	struct wpa_ssid *ssid;
+
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+		return;
+	if (wpa_s->wpa_state != WPA_COMPLETED)
+		return;
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL ||
+	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
+		return;
+	if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
+		return;
+	if (reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA &&
+	    reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)
+		return;
+	if (wpa_s->sme.sa_query_count > 0)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - "
+		"possible AP/STA state mismatch - trigger SA Query");
+	sme_start_sa_query(wpa_s);
+}
+
+
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+		     const u8 *data, size_t len)
+{
+	int i;
+
+	if (wpa_s->sme.sa_query_trans_id == NULL ||
+	    len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
+	    data[0] != WLAN_SA_QUERY_RESPONSE)
+		return;
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
+		MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
+
+	if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
+		return;
+
+	for (i = 0; i < wpa_s->sme.sa_query_count; i++) {
+		if (os_memcmp(wpa_s->sme.sa_query_trans_id +
+			      i * WLAN_SA_QUERY_TR_ID_LEN,
+			      data + 1, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+			break;
+	}
+
+	if (i >= wpa_s->sme.sa_query_count) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "SME: No matching SA Query "
+			"transaction identifier found");
+		return;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reply to pending SA Query received "
+		"from " MACSTR, MAC2STR(sa));
+	sme_stop_sa_query(wpa_s);
+}
+
+#endif /* CONFIG_IEEE80211W */

Deleted: vendor/wpa/2.0/wpa_supplicant/sme.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/sme.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/sme.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,78 +0,0 @@
-/*
- * wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef SME_H
-#define SME_H
-
-#ifdef CONFIG_SME
-
-void sme_authenticate(struct wpa_supplicant *wpa_s,
-		      struct wpa_bss *bss, struct wpa_ssid *ssid);
-void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
-		   const u8 *bssid, u16 auth_type);
-void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data);
-int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-		      const u8 *ies, size_t ies_len);
-void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-			    union wpa_event_data *data);
-void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
-			      union wpa_event_data *data);
-void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
-			       union wpa_event_data *data);
-void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-			union wpa_event_data *data);
-
-#else /* CONFIG_SME */
-
-static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
-				    struct wpa_bss *bss,
-				    struct wpa_ssid *ssid)
-{
-}
-
-static inline void sme_event_auth(struct wpa_supplicant *wpa_s,
-				  union wpa_event_data *data)
-{
-}
-
-static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-				    const u8 *ies, size_t ies_len)
-{
-	return -1;
-}
-
-
-static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
-					  union wpa_event_data *data)
-{
-}
-
-static inline void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
-					    union wpa_event_data *data)
-{
-}
-
-static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
-					     union wpa_event_data *data)
-{
-}
-
-static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-				      union wpa_event_data *data)
-{
-}
-
-#endif /* CONFIG_SME */
-
-#endif /* SME_H */

Copied: vendor/wpa/2.0/wpa_supplicant/sme.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/sme.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/sme.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/sme.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,113 @@
+/*
+ * wpa_supplicant - SME
+ * Copyright (c) 2009-2010, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SME_H
+#define SME_H
+
+#ifdef CONFIG_SME
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+		      struct wpa_bss *bss, struct wpa_ssid *ssid);
+void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
+		   const u8 *bssid, u16 auth_type);
+void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data);
+int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
+		      const u8 *ies, size_t ies_len);
+void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+			    union wpa_event_data *data);
+void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
+			      union wpa_event_data *data);
+void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
+			       union wpa_event_data *data);
+void sme_event_disassoc(struct wpa_supplicant *wpa_s,
+			union wpa_event_data *data);
+void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
+				 const u8 *da, u16 reason_code);
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+		     const u8 *data, size_t len);
+void sme_state_changed(struct wpa_supplicant *wpa_s);
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+				       const u8 *prev_pending_bssid);
+void sme_deinit(struct wpa_supplicant *wpa_s);
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+
+#else /* CONFIG_SME */
+
+static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss,
+				    struct wpa_ssid *ssid)
+{
+}
+
+static inline void sme_event_auth(struct wpa_supplicant *wpa_s,
+				  union wpa_event_data *data)
+{
+}
+
+static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
+				    const u8 *ies, size_t ies_len)
+{
+	return -1;
+}
+
+
+static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+					  union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
+					    union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
+					     union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s,
+					       const u8 *sa, const u8 *da,
+					       u16 reason_code)
+{
+}
+
+static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+				  const u8 *prev_pending_bssid)
+{
+}
+
+static inline void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
+				       int enable)
+{
+}
+
+#endif /* CONFIG_SME */
+
+#endif /* SME_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/tests/test_eap_sim_common.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,53 +0,0 @@
-/*
- * Test program for EAP-SIM PRF
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "eap_common/eap_sim_common.c"
-
-
-static int test_eap_sim_prf(void)
-{
-	/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
-	u8 xkey[] = {
-		0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
-		0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
-		0xeb, 0x5a, 0x38, 0xb6
-	};
-	u8 w[] = {
-		0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
-		0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
-		0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
-		0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
-		0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
-	};
-	u8 buf[40];
-
-	printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
-	eap_sim_prf(xkey, buf, sizeof(buf));
-	if (memcmp(w, buf, sizeof(w) != 0)) {
-		printf("eap_sim_prf failed\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
-	int errors = 0;
-
-	errors += test_eap_sim_prf();
-
-	return errors;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/tests/test_eap_sim_common.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/tests/test_eap_sim_common.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,47 @@
+/*
+ * Test program for EAP-SIM PRF
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "eap_common/eap_sim_common.c"
+
+
+static int test_eap_sim_prf(void)
+{
+	/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+	u8 xkey[] = {
+		0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+		0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+		0xeb, 0x5a, 0x38, 0xb6
+	};
+	u8 w[] = {
+		0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+		0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+		0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+		0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+		0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+	};
+	u8 buf[40];
+
+	printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
+	eap_sim_prf(xkey, buf, sizeof(buf));
+	if (memcmp(w, buf, sizeof(w)) != 0) {
+		printf("eap_sim_prf failed\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int errors = 0;
+
+	errors += test_eap_sim_prf();
+
+	return errors;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/tests/test_wpa.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,379 +0,0 @@
-/*
- * Test program for combined WPA authenticator/supplicant
- * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "../config.h"
-#include "rsn_supp/wpa.h"
-#include "rsn_supp/wpa_ie.h"
-#include "../hostapd/wpa.h"
-
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-
-
-struct wpa {
-	u8 auth_addr[ETH_ALEN];
-	u8 supp_addr[ETH_ALEN];
-	u8 psk[PMK_LEN];
-
-	/* from authenticator */
-	u8 auth_eapol_dst[ETH_ALEN];
-	u8 *auth_eapol;
-	size_t auth_eapol_len;
-
-	/* from supplicant */
-	u8 *supp_eapol;
-	size_t supp_eapol_len;
-
-	struct wpa_sm *supp;
-	struct wpa_authenticator *auth_group;
-	struct wpa_state_machine *auth;
-
-	struct wpa_ssid ssid;
-	u8 supp_ie[80];
-	size_t supp_ie_len;
-};
-
-
-static int supp_get_bssid(void *ctx, u8 *bssid)
-{
-	struct wpa *wpa = ctx;
-	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-	os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
-	return 0;
-}
-
-
-static void supp_set_state(void *ctx, enum wpa_states state)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
-}
-
-
-static void auth_eapol_rx(void *eloop_data, void *user_ctx)
-{
-	struct wpa *wpa = eloop_data;
-
-	wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
-	wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
-		    wpa->supp_eapol_len);
-}
-
-
-static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
-			   size_t len)
-{
-	struct wpa *wpa = ctx;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
-		   "len=%lu)",
-		   __func__, MAC2STR(dest), proto, (unsigned long) len);
-
-	os_free(wpa->supp_eapol);
-	wpa->supp_eapol = os_malloc(len);
-	if (wpa->supp_eapol == NULL)
-		return -1;
-	os_memcpy(wpa->supp_eapol, buf, len);
-	wpa->supp_eapol_len = len;
-	eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
-
-	return 0;
-}
-
-
-static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
-			     u16 data_len, size_t *msg_len, void **data_pos)
-{
-	struct ieee802_1x_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
-		   __func__, type, data_len);
-
-	*msg_len = sizeof(*hdr) + data_len;
-	hdr = os_malloc(*msg_len);
-	if (hdr == NULL)
-		return NULL;
-
-	hdr->version = 2;
-	hdr->type = type;
-	hdr->length = host_to_be16(data_len);
-
-	if (data)
-		os_memcpy(hdr + 1, data, data_len);
-	else
-		os_memset(hdr + 1, 0, data_len);
-
-	if (data_pos)
-		*data_pos = hdr + 1;
-
-	return (u8 *) hdr;
-}
-
-
-static int supp_get_beacon_ie(void *ctx)
-{
-	struct wpa *wpa = ctx;
-	const u8 *ie;
-	size_t ielen;
-
-	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-
-	ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
-	if (ie == NULL || ielen < 1)
-		return -1;
-	if (ie[0] == WLAN_EID_RSN)
-		return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
-	return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
-}
-
-
-static int supp_set_key(void *ctx, enum wpa_alg alg,
-			const u8 *addr, int key_idx, int set_tx,
-			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
-		   "set_tx=%d)",
-		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
-	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
-	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
-	return 0;
-}
-
-
-static int supp_mlme_setprotection(void *ctx, const u8 *addr,
-				   int protection_type, int key_type)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
-		   "key_type=%d)",
-		   __func__, MAC2STR(addr), protection_type, key_type);
-	return 0;
-}
-
-
-static void supp_cancel_auth_timeout(void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
-}
-
-
-static int supp_init(struct wpa *wpa)
-{
-	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL)
-		return -1;
-
-	ctx->ctx = wpa;
-	ctx->msg_ctx = wpa;
-	ctx->set_state = supp_set_state;
-	ctx->get_bssid = supp_get_bssid;
-	ctx->ether_send = supp_ether_send;
-	ctx->get_beacon_ie = supp_get_beacon_ie;
-	ctx->alloc_eapol = supp_alloc_eapol;
-	ctx->set_key = supp_set_key;
-	ctx->mlme_setprotection = supp_mlme_setprotection;
-	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
-	wpa->supp = wpa_sm_init(ctx);
-	if (wpa->supp == NULL) {
-		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
-		return -1;
-	}
-
-	wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
-	wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
-	wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
-	wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
-	wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
-	wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-	wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN);
-
-	wpa->supp_ie_len = sizeof(wpa->supp_ie);
-	if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
-					    &wpa->supp_ie_len) < 0) {
-		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
-			   " failed");
-		return -1;
-	}
-
-	wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
-
-	return 0;
-}
-
-
-static void auth_logger(void *ctx, const u8 *addr, logger_level level,
-			const char *txt)
-{
-	if (addr)
-		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
-			   MAC2STR(addr), txt);
-	else
-		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
-}
-
-
-static void supp_eapol_rx(void *eloop_data, void *user_ctx)
-{
-	struct wpa *wpa = eloop_data;
-
-	wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
-	wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
-			wpa->auth_eapol_len);
-}
-
-
-static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
-			   size_t data_len, int encrypt)
-{
-	struct wpa *wpa = ctx;
-
-	wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
-		   "encrypt=%d)",
-		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
-
-	os_free(wpa->auth_eapol);
-	wpa->auth_eapol = os_malloc(data_len);
-	if (wpa->auth_eapol == NULL)
-		return -1;
-	os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN);
-	os_memcpy(wpa->auth_eapol, data, data_len);
-	wpa->auth_eapol_len = data_len;
-	eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
-
-	return 0;
-}
-
-
-static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
-{
-	struct wpa *wpa = ctx;
-	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
-		   __func__, MAC2STR(addr), prev_psk);
-	if (prev_psk)
-		return NULL;
-	return wpa->psk;
-}
-
-
-static int auth_init_group(struct wpa *wpa)
-{
-	struct wpa_auth_config conf;
-	struct wpa_auth_callbacks cb;
-
-	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
-
-	os_memset(&conf, 0, sizeof(conf));
-	conf.wpa = 2;
-	conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-	conf.wpa_pairwise = WPA_CIPHER_CCMP;
-	conf.rsn_pairwise = WPA_CIPHER_CCMP;
-	conf.wpa_group = WPA_CIPHER_CCMP;
-	conf.eapol_version = 2;
-
-	os_memset(&cb, 0, sizeof(cb));
-	cb.ctx = wpa;
-	cb.logger = auth_logger;
-	cb.send_eapol = auth_send_eapol;
-	cb.get_psk = auth_get_psk;
-
-	wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb);
-	if (wpa->auth_group == NULL) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int auth_init(struct wpa *wpa)
-{
-	wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr);
-	if (wpa->auth == NULL) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
-		return -1;
-	}
-
-	if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
-				wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) {
-		wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
-		return -1;
-	}
-
-	wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
-
-	wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
-
-	return 0;
-}
-
-
-static void deinit(struct wpa *wpa)
-{
-	wpa_auth_sta_deinit(wpa->auth);
-	wpa_sm_deinit(wpa->supp);
-	wpa_deinit(wpa->auth_group);
-	os_free(wpa->auth_eapol);
-	wpa->auth_eapol = NULL;
-	os_free(wpa->supp_eapol);
-	wpa->supp_eapol = NULL;
-}
-
-
-int main(int argc, char *argv[])
-{
-	struct wpa wpa;
-
-	if (os_program_init())
-		return -1;
-
-	os_memset(&wpa, 0, sizeof(wpa));
-	os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
-	os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
-	os_memset(wpa.psk, 0x44, PMK_LEN);
-
-	wpa_debug_level = 0;
-	wpa_debug_show_keys = 1;
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		return -1;
-	}
-
-	if (auth_init_group(&wpa) < 0)
-		return -1;
-
-	if (supp_init(&wpa) < 0)
-		return -1;
-
-	if (auth_init(&wpa) < 0)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "Starting eloop");
-	eloop_run();
-	wpa_printf(MSG_DEBUG, "eloop done");
-
-	deinit(&wpa);
-
-	eloop_destroy();
-
-	os_program_deinit();
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/tests/test_wpa.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/tests/test_wpa.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,373 @@
+/*
+ * Test program for combined WPA authenticator/supplicant
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "../config.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_ie.h"
+#include "../hostapd/wpa.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+
+
+struct wpa {
+	u8 auth_addr[ETH_ALEN];
+	u8 supp_addr[ETH_ALEN];
+	u8 psk[PMK_LEN];
+
+	/* from authenticator */
+	u8 auth_eapol_dst[ETH_ALEN];
+	u8 *auth_eapol;
+	size_t auth_eapol_len;
+
+	/* from supplicant */
+	u8 *supp_eapol;
+	size_t supp_eapol_len;
+
+	struct wpa_sm *supp;
+	struct wpa_authenticator *auth_group;
+	struct wpa_state_machine *auth;
+
+	struct wpa_ssid ssid;
+	u8 supp_ie[80];
+	size_t supp_ie_len;
+};
+
+
+static int supp_get_bssid(void *ctx, u8 *bssid)
+{
+	struct wpa *wpa = ctx;
+	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+	os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static void supp_set_state(void *ctx, enum wpa_states state)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
+}
+
+
+static void auth_eapol_rx(void *eloop_data, void *user_ctx)
+{
+	struct wpa *wpa = eloop_data;
+
+	wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
+	wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
+		    wpa->supp_eapol_len);
+}
+
+
+static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+			   size_t len)
+{
+	struct wpa *wpa = ctx;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
+		   "len=%lu)",
+		   __func__, MAC2STR(dest), proto, (unsigned long) len);
+
+	os_free(wpa->supp_eapol);
+	wpa->supp_eapol = os_malloc(len);
+	if (wpa->supp_eapol == NULL)
+		return -1;
+	os_memcpy(wpa->supp_eapol, buf, len);
+	wpa->supp_eapol_len = len;
+	eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
+
+	return 0;
+}
+
+
+static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
+			     u16 data_len, size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
+		   __func__, type, data_len);
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = 2;
+	hdr->type = type;
+	hdr->length = host_to_be16(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+static int supp_get_beacon_ie(void *ctx)
+{
+	struct wpa *wpa = ctx;
+	const u8 *ie;
+	size_t ielen;
+
+	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+
+	ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
+	if (ie == NULL || ielen < 1)
+		return -1;
+	if (ie[0] == WLAN_EID_RSN)
+		return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
+	return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
+}
+
+
+static int supp_set_key(void *ctx, enum wpa_alg alg,
+			const u8 *addr, int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			const u8 *key, size_t key_len)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
+		   "set_tx=%d)",
+		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
+	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
+	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
+	return 0;
+}
+
+
+static int supp_mlme_setprotection(void *ctx, const u8 *addr,
+				   int protection_type, int key_type)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
+		   "key_type=%d)",
+		   __func__, MAC2STR(addr), protection_type, key_type);
+	return 0;
+}
+
+
+static void supp_cancel_auth_timeout(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+}
+
+
+static int supp_init(struct wpa *wpa)
+{
+	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return -1;
+
+	ctx->ctx = wpa;
+	ctx->msg_ctx = wpa;
+	ctx->set_state = supp_set_state;
+	ctx->get_bssid = supp_get_bssid;
+	ctx->ether_send = supp_ether_send;
+	ctx->get_beacon_ie = supp_get_beacon_ie;
+	ctx->alloc_eapol = supp_alloc_eapol;
+	ctx->set_key = supp_set_key;
+	ctx->mlme_setprotection = supp_mlme_setprotection;
+	ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
+	wpa->supp = wpa_sm_init(ctx);
+	if (wpa->supp == NULL) {
+		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+		return -1;
+	}
+
+	wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
+	wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
+	wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+	wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
+	wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
+	wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
+	wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN);
+
+	wpa->supp_ie_len = sizeof(wpa->supp_ie);
+	if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
+					    &wpa->supp_ie_len) < 0) {
+		wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
+			   " failed");
+		return -1;
+	}
+
+	wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
+
+	return 0;
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+			const char *txt)
+{
+	if (addr)
+		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+			   MAC2STR(addr), txt);
+	else
+		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static void supp_eapol_rx(void *eloop_data, void *user_ctx)
+{
+	struct wpa *wpa = eloop_data;
+
+	wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
+	wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
+			wpa->auth_eapol_len);
+}
+
+
+static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
+			   size_t data_len, int encrypt)
+{
+	struct wpa *wpa = ctx;
+
+	wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
+		   "encrypt=%d)",
+		   __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+
+	os_free(wpa->auth_eapol);
+	wpa->auth_eapol = os_malloc(data_len);
+	if (wpa->auth_eapol == NULL)
+		return -1;
+	os_memcpy(wpa->auth_eapol_dst, addr, ETH_ALEN);
+	os_memcpy(wpa->auth_eapol, data, data_len);
+	wpa->auth_eapol_len = data_len;
+	eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
+
+	return 0;
+}
+
+
+static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk)
+{
+	struct wpa *wpa = ctx;
+	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+		   __func__, MAC2STR(addr), prev_psk);
+	if (prev_psk)
+		return NULL;
+	return wpa->psk;
+}
+
+
+static int auth_init_group(struct wpa *wpa)
+{
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+
+	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.wpa = 2;
+	conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+	conf.wpa_pairwise = WPA_CIPHER_CCMP;
+	conf.rsn_pairwise = WPA_CIPHER_CCMP;
+	conf.wpa_group = WPA_CIPHER_CCMP;
+	conf.eapol_version = 2;
+
+	os_memset(&cb, 0, sizeof(cb));
+	cb.ctx = wpa;
+	cb.logger = auth_logger;
+	cb.send_eapol = auth_send_eapol;
+	cb.get_psk = auth_get_psk;
+
+	wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb);
+	if (wpa->auth_group == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int auth_init(struct wpa *wpa)
+{
+	wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr);
+	if (wpa->auth == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
+		return -1;
+	}
+
+	if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
+				wpa->supp_ie_len, NULL, 0) != WPA_IE_OK) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
+		return -1;
+	}
+
+	wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
+
+	wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
+
+	return 0;
+}
+
+
+static void deinit(struct wpa *wpa)
+{
+	wpa_auth_sta_deinit(wpa->auth);
+	wpa_sm_deinit(wpa->supp);
+	wpa_deinit(wpa->auth_group);
+	os_free(wpa->auth_eapol);
+	wpa->auth_eapol = NULL;
+	os_free(wpa->supp_eapol);
+	wpa->supp_eapol = NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct wpa wpa;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&wpa, 0, sizeof(wpa));
+	os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
+	os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
+	os_memset(wpa.psk, 0x44, PMK_LEN);
+
+	wpa_debug_level = 0;
+	wpa_debug_show_keys = 1;
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	if (auth_init_group(&wpa) < 0)
+		return -1;
+
+	if (supp_init(&wpa) < 0)
+		return -1;
+
+	if (auth_init(&wpa) < 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "Starting eloop");
+	eloop_run();
+	wpa_printf(MSG_DEBUG, "eloop done");
+
+	deinit(&wpa);
+
+	eloop_destroy();
+
+	os_program_deinit();
+
+	return 0;
+}

Copied: vendor/wpa/2.0/wpa_supplicant/wifi_display.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wifi_display.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wifi_display.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wifi_display.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,251 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wifi_display.h"
+
+
+int wifi_display_init(struct wpa_global *global)
+{
+	global->wifi_display = 1;
+	return 0;
+}
+
+
+void wifi_display_deinit(struct wpa_global *global)
+{
+	int i;
+	for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+		wpabuf_free(global->wfd_subelem[i]);
+		global->wfd_subelem[i] = NULL;
+	}
+}
+
+
+static int wifi_display_update_wfd_ie(struct wpa_global *global)
+{
+	struct wpabuf *ie, *buf;
+	size_t len, plen;
+
+	wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
+
+	if (!global->wifi_display) {
+		wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
+			   "include WFD IE");
+		p2p_set_wfd_ie_beacon(global->p2p, NULL);
+		p2p_set_wfd_ie_probe_req(global->p2p, NULL);
+		p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
+		p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
+		p2p_set_wfd_ie_invitation(global->p2p, NULL);
+		p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
+		p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
+		p2p_set_wfd_ie_go_neg(global->p2p, NULL);
+		p2p_set_wfd_dev_info(global->p2p, NULL);
+		p2p_set_wfd_assoc_bssid(global->p2p, NULL);
+		p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
+		return 0;
+	}
+
+	p2p_set_wfd_dev_info(global->p2p,
+			     global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+	p2p_set_wfd_assoc_bssid(
+		global->p2p,
+		global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
+	p2p_set_wfd_coupled_sink_info(
+		global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+	/*
+	 * WFD IE is included in number of management frames. Two different
+	 * sets of subelements are included depending on the frame:
+	 *
+	 * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
+	 * Provision Discovery Req:
+	 * WFD Device Info
+	 * [Associated BSSID]
+	 * [Coupled Sink Info]
+	 *
+	 * Probe Request:
+	 * WFD Device Info
+	 * [Associated BSSID]
+	 * [Coupled Sink Info]
+	 * [WFD Extended Capability]
+	 *
+	 * Probe Response:
+	 * WFD Device Info
+	 * [Associated BSSID]
+	 * [Coupled Sink Info]
+	 * [WFD Extended Capability]
+	 * [WFD Session Info]
+	 *
+	 * (Re)Association Response, P2P Invitation Req/Resp,
+	 * Provision Discovery Resp:
+	 * WFD Device Info
+	 * [Associated BSSID]
+	 * [Coupled Sink Info]
+	 * [WFD Session Info]
+	 */
+	len = 0;
+	if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+		len += wpabuf_len(global->wfd_subelem[
+					  WFD_SUBELEM_DEVICE_INFO]);
+	if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+		len += wpabuf_len(global->wfd_subelem[
+					  WFD_SUBELEM_ASSOCIATED_BSSID]);
+	if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+		len += wpabuf_len(global->wfd_subelem[
+					  WFD_SUBELEM_COUPLED_SINK]);
+	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+		len += wpabuf_len(global->wfd_subelem[
+					  WFD_SUBELEM_SESSION_INFO]);
+	if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+		len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+		wpabuf_put_buf(buf,
+			       global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+	if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+		wpabuf_put_buf(buf, global->wfd_subelem[
+				       WFD_SUBELEM_ASSOCIATED_BSSID]);
+	if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+		wpabuf_put_buf(buf,
+			       global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
+	p2p_set_wfd_ie_beacon(global->p2p, ie);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
+			ie);
+	p2p_set_wfd_ie_assoc_req(global->p2p, ie);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
+	p2p_set_wfd_ie_go_neg(global->p2p, ie);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+			"Request", ie);
+	p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
+
+	plen = buf->used;
+	if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+		wpabuf_put_buf(buf,
+			       global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
+	p2p_set_wfd_ie_probe_req(global->p2p, ie);
+
+	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+		wpabuf_put_buf(buf,
+			       global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
+	p2p_set_wfd_ie_probe_resp(global->p2p, ie);
+
+	/* Remove WFD Extended Capability from buffer */
+	buf->used = plen;
+	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+		wpabuf_put_buf(buf,
+			       global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
+	p2p_set_wfd_ie_invitation(global->p2p, ie);
+
+	ie = wifi_display_encaps(buf);
+	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+			"Response", ie);
+	p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
+
+	wpabuf_free(buf);
+
+	return 0;
+}
+
+
+void wifi_display_enable(struct wpa_global *global, int enabled)
+{
+	wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
+		   enabled ? "enabled" : "disabled");
+	global->wifi_display = enabled;
+	wifi_display_update_wfd_ie(global);
+}
+
+
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
+{
+	char *pos;
+	int subelem;
+	size_t len;
+	struct wpabuf *e;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	subelem = atoi(cmd);
+	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+		return -1;
+
+	len = os_strlen(pos);
+	if (len & 1)
+		return -1;
+	len /= 2;
+
+	if (len == 0) {
+		/* Clear subelement */
+		e = NULL;
+		wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
+	} else {
+		e = wpabuf_alloc(1 + len);
+		if (e == NULL)
+			return -1;
+		wpabuf_put_u8(e, subelem);
+		if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+			wpabuf_free(e);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
+	}
+
+	wpabuf_free(global->wfd_subelem[subelem]);
+	global->wfd_subelem[subelem] = e;
+	wifi_display_update_wfd_ie(global);
+
+	return 0;
+}
+
+
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+			     char *buf, size_t buflen)
+{
+	int subelem;
+
+	subelem = atoi(cmd);
+	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+		return -1;
+
+	if (global->wfd_subelem[subelem] == NULL)
+		return 0;
+
+	return wpa_snprintf_hex(buf, buflen,
+				wpabuf_head_u8(global->wfd_subelem[subelem]) +
+				1,
+				wpabuf_len(global->wfd_subelem[subelem]) - 1);
+}

Copied: vendor/wpa/2.0/wpa_supplicant/wifi_display.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/wifi_display.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wifi_display.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wifi_display.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WIFI_DISPLAY_H
+#define WIFI_DISPLAY_H
+
+int wifi_display_init(struct wpa_global *global);
+void wifi_display_deinit(struct wpa_global *global);
+void wifi_display_enable(struct wpa_global *global, int enabled);
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+			     char *buf, size_t buflen);
+
+#endif /* WIFI_DISPLAY_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/win_if_list.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/win_if_list.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/win_if_list.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,179 +0,0 @@
-/*
- * win_if_list - Display network interfaces with description (for Windows)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This small tool is for the Windows build to provide an easy way of fetching
- * a list of available network interfaces.
- */
-
-#include "includes.h"
-#include <stdio.h>
-#ifdef CONFIG_USE_NDISUIO
-#include <winsock2.h>
-#include <ntddndis.h>
-#else /* CONFIG_USE_NDISUIO */
-#include "pcap.h"
-#include <winsock.h>
-#endif /* CONFIG_USE_NDISUIO */
-
-#ifdef CONFIG_USE_NDISUIO
-
-/* from nuiouser.h */
-#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
-
-#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
-	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
-
-#define IOCTL_NDISUIO_QUERY_BINDING \
-	_NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-#define IOCTL_NDISUIO_BIND_WAIT \
-	_NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
-			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
-typedef struct _NDISUIO_QUERY_BINDING
-{
-	ULONG BindingIndex;
-	ULONG DeviceNameOffset;
-	ULONG DeviceNameLength;
-	ULONG DeviceDescrOffset;
-	ULONG DeviceDescrLength;
-} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
-
-
-static HANDLE ndisuio_open(void)
-{
-	DWORD written;
-	HANDLE h;
-
-	h = CreateFile(TEXT("\\\\.\\\\Ndisuio"),
-		       GENERIC_READ | GENERIC_WRITE, 0, NULL,
-		       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
-		       INVALID_HANDLE_VALUE);
-	if (h == INVALID_HANDLE_VALUE)
-		return h;
-
-#ifndef _WIN32_WCE
-	if (!DeviceIoControl(h, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0,
-			     &written, NULL)) {
-		printf("IOCTL_NDISUIO_BIND_WAIT failed: %d",
-		       (int) GetLastError());
-		CloseHandle(h);
-		return INVALID_HANDLE_VALUE;
-	}
-#endif /* _WIN32_WCE */
-
-	return h;
-}
-
-
-static void ndisuio_query_bindings(HANDLE ndisuio)
-{
-	NDISUIO_QUERY_BINDING *b;
-	size_t blen = sizeof(*b) + 1024;
-	int i, error;
-	DWORD written;
-	char name[256], desc[256];
-	WCHAR *pos;
-	size_t j, len;
-
-	b = malloc(blen);
-	if (b == NULL)
-		return;
-
-	for (i = 0; ; i++) {
-		memset(b, 0, blen);
-		b->BindingIndex = i;
-		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
-				     b, sizeof(NDISUIO_QUERY_BINDING), b,
-				     (DWORD) blen, &written, NULL)) {
-			error = (int) GetLastError();
-			if (error == ERROR_NO_MORE_ITEMS)
-				break;
-			printf("IOCTL_NDISUIO_QUERY_BINDING failed: %d",
-			       error);
-			break;
-		}
-
-		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
-		len = b->DeviceNameLength;
-		if (len >= sizeof(name))
-			len = sizeof(name) - 1;
-		for (j = 0; j < len; j++)
-			name[j] = (char) pos[j];
-		name[len] = '\0';
-
-		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
-		len = b->DeviceDescrLength;
-		if (len >= sizeof(desc))
-			len = sizeof(desc) - 1;
-		for (j = 0; j < len; j++)
-			desc[j] = (char) pos[j];
-		desc[len] = '\0';
-
-		printf("ifname: %s\ndescription: %s\n\n", name, desc);
-	}
-
-	free(b);
-}
-
-
-static void ndisuio_enum_bindings(void)
-{
-	HANDLE ndisuio = ndisuio_open();
-	if (ndisuio == INVALID_HANDLE_VALUE)
-		return;
-
-	ndisuio_query_bindings(ndisuio);
-	CloseHandle(ndisuio);
-}
-
-#else /* CONFIG_USE_NDISUIO */
-
-static void show_dev(pcap_if_t *dev)
-{
-	printf("ifname: %s\ndescription: %s\n\n",
-	       dev->name, dev->description);
-}
-
-
-static void pcap_enum_devs(void)
-{
-	pcap_if_t *devs, *dev;
-	char err[PCAP_ERRBUF_SIZE + 1];
-
-	if (pcap_findalldevs(&devs, err) < 0) {
-		fprintf(stderr, "Error - pcap_findalldevs: %s\n", err);
-		return;
-	}
-
-	for (dev = devs; dev; dev = dev->next) {
-		show_dev(dev);
-	}
-
-	pcap_freealldevs(devs);
-}
-
-#endif /* CONFIG_USE_NDISUIO */
-
-
-int main(int argc, char *argv[])
-{
-#ifdef CONFIG_USE_NDISUIO
-	ndisuio_enum_bindings();
-#else /* CONFIG_USE_NDISUIO */
-	pcap_enum_devs();
-#endif /* CONFIG_USE_NDISUIO */
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/win_if_list.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/win_if_list.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/win_if_list.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/win_if_list.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,173 @@
+/*
+ * win_if_list - Display network interfaces with description (for Windows)
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This small tool is for the Windows build to provide an easy way of fetching
+ * a list of available network interfaces.
+ */
+
+#include "includes.h"
+#include <stdio.h>
+#ifdef CONFIG_USE_NDISUIO
+#include <winsock2.h>
+#include <ntddndis.h>
+#else /* CONFIG_USE_NDISUIO */
+#include "pcap.h"
+#include <winsock.h>
+#endif /* CONFIG_USE_NDISUIO */
+
+#ifdef CONFIG_USE_NDISUIO
+
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
+
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+	CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISUIO_QUERY_BINDING \
+	_NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_BIND_WAIT \
+	_NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
+			  FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _NDISUIO_QUERY_BINDING
+{
+	ULONG BindingIndex;
+	ULONG DeviceNameOffset;
+	ULONG DeviceNameLength;
+	ULONG DeviceDescrOffset;
+	ULONG DeviceDescrLength;
+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
+
+
+static HANDLE ndisuio_open(void)
+{
+	DWORD written;
+	HANDLE h;
+
+	h = CreateFile(TEXT("\\\\.\\\\Ndisuio"),
+		       GENERIC_READ | GENERIC_WRITE, 0, NULL,
+		       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+		       INVALID_HANDLE_VALUE);
+	if (h == INVALID_HANDLE_VALUE)
+		return h;
+
+#ifndef _WIN32_WCE
+	if (!DeviceIoControl(h, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0,
+			     &written, NULL)) {
+		printf("IOCTL_NDISUIO_BIND_WAIT failed: %d",
+		       (int) GetLastError());
+		CloseHandle(h);
+		return INVALID_HANDLE_VALUE;
+	}
+#endif /* _WIN32_WCE */
+
+	return h;
+}
+
+
+static void ndisuio_query_bindings(HANDLE ndisuio)
+{
+	NDISUIO_QUERY_BINDING *b;
+	size_t blen = sizeof(*b) + 1024;
+	int i, error;
+	DWORD written;
+	char name[256], desc[256];
+	WCHAR *pos;
+	size_t j, len;
+
+	b = malloc(blen);
+	if (b == NULL)
+		return;
+
+	for (i = 0; ; i++) {
+		memset(b, 0, blen);
+		b->BindingIndex = i;
+		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+				     b, sizeof(NDISUIO_QUERY_BINDING), b,
+				     (DWORD) blen, &written, NULL)) {
+			error = (int) GetLastError();
+			if (error == ERROR_NO_MORE_ITEMS)
+				break;
+			printf("IOCTL_NDISUIO_QUERY_BINDING failed: %d",
+			       error);
+			break;
+		}
+
+		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+		len = b->DeviceNameLength;
+		if (len >= sizeof(name))
+			len = sizeof(name) - 1;
+		for (j = 0; j < len; j++)
+			name[j] = (char) pos[j];
+		name[len] = '\0';
+
+		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+		len = b->DeviceDescrLength;
+		if (len >= sizeof(desc))
+			len = sizeof(desc) - 1;
+		for (j = 0; j < len; j++)
+			desc[j] = (char) pos[j];
+		desc[len] = '\0';
+
+		printf("ifname: %s\ndescription: %s\n\n", name, desc);
+	}
+
+	free(b);
+}
+
+
+static void ndisuio_enum_bindings(void)
+{
+	HANDLE ndisuio = ndisuio_open();
+	if (ndisuio == INVALID_HANDLE_VALUE)
+		return;
+
+	ndisuio_query_bindings(ndisuio);
+	CloseHandle(ndisuio);
+}
+
+#else /* CONFIG_USE_NDISUIO */
+
+static void show_dev(pcap_if_t *dev)
+{
+	printf("ifname: %s\ndescription: %s\n\n",
+	       dev->name, dev->description);
+}
+
+
+static void pcap_enum_devs(void)
+{
+	pcap_if_t *devs, *dev;
+	char err[PCAP_ERRBUF_SIZE + 1];
+
+	if (pcap_findalldevs(&devs, err) < 0) {
+		fprintf(stderr, "Error - pcap_findalldevs: %s\n", err);
+		return;
+	}
+
+	for (dev = devs; dev; dev = dev->next) {
+		show_dev(dev);
+	}
+
+	pcap_freealldevs(devs);
+}
+
+#endif /* CONFIG_USE_NDISUIO */
+
+
+int main(int argc, char *argv[])
+{
+#ifdef CONFIG_USE_NDISUIO
+	ndisuio_enum_bindings();
+#else /* CONFIG_USE_NDISUIO */
+	pcap_enum_devs();
+#endif /* CONFIG_USE_NDISUIO */
+
+	return 0;
+}

Copied: vendor/wpa/2.0/wpa_supplicant/wnm_sta.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wnm_sta.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wnm_sta.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wnm_sta.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,423 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2012, 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 "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
+
+#define MAX_TFS_IE_LEN  1024
+
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
+				   u16 *buf_len, enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+	return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
+}
+
+
+/* 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,
+				   enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+	return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.request */
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+				 u8 action, u16 intval, struct wpabuf *tfs_req)
+{
+	struct ieee80211_mgmt *mgmt;
+	int res;
+	size_t len;
+	struct wnm_sleep_element *wnmsleep_ie;
+	u8 *wnmtfs_ie;
+	u8 wnmsleep_ie_len;
+	u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
+	enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
+		WNM_SLEEP_TFS_REQ_IE_NONE;
+
+	wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
+		   "action=%s to " MACSTR,
+		   action == 0 ? "enter" : "exit",
+		   MAC2STR(wpa_s->bssid));
+
+	/* WNM-Sleep Mode IE */
+	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+	wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
+	if (wnmsleep_ie == NULL)
+		return -1;
+	wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
+	wnmsleep_ie->len = wnmsleep_ie_len - 2;
+	wnmsleep_ie->action_type = action;
+	wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
+	wnmsleep_ie->intval = host_to_le16(intval);
+	wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
+		    (u8 *) wnmsleep_ie, wnmsleep_ie_len);
+
+	/* TFS IE(s) */
+	if (tfs_req) {
+		wnmtfs_ie_len = wpabuf_len(tfs_req);
+		wnmtfs_ie = os_malloc(wnmtfs_ie_len);
+		if (wnmtfs_ie == NULL) {
+			os_free(wnmsleep_ie);
+			return -1;
+		}
+		os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
+	} else {
+		wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+		if (wnmtfs_ie == NULL) {
+			os_free(wnmsleep_ie);
+			return -1;
+		}
+		if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
+					    tfs_oper)) {
+			wnmtfs_ie_len = 0;
+			os_free(wnmtfs_ie);
+			wnmtfs_ie = NULL;
+		}
+	}
+	wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
+		    (u8 *) wnmtfs_ie, wnmtfs_ie_len);
+
+	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+	if (mgmt == NULL) {
+		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+			   "WNM-Sleep Request action frame");
+		os_free(wnmsleep_ie);
+		os_free(wnmtfs_ie);
+		return -1;
+	}
+
+	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
+	mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
+	os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
+		  wnmsleep_ie_len);
+	/* copy TFS IE here */
+	if (wnmtfs_ie_len > 0) {
+		os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+			  wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
+	}
+
+	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
+		wnmtfs_ie_len;
+
+	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  &mgmt->u.action.category, len, 0);
+	if (res < 0)
+		wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
+			   "(action=%d, intval=%d)", action, intval);
+
+	os_free(wnmsleep_ie);
+	os_free(wnmtfs_ie);
+	os_free(mgmt);
+
+	return res;
+}
+
+
+static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
+					 u8 *tfsresp_ie_start,
+					 u8 *tfsresp_ie_end)
+{
+	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
+			 wpa_s->bssid, NULL, NULL);
+	/* remove GTK/IGTK ?? */
+
+	/* set the TFS Resp IE(s) */
+	if (tfsresp_ie_start && tfsresp_ie_end &&
+	    tfsresp_ie_end - tfsresp_ie_start >= 0) {
+		u16 tfsresp_ie_len;
+		tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
+			tfsresp_ie_start;
+		wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
+		/* 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,
+					    WNM_SLEEP_TFS_RESP_IE_SET))
+			wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
+	}
+}
+
+
+static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
+					const u8 *frm, u16 key_len_total)
+{
+	u8 *ptr, *end;
+	u8 gtk_len;
+
+	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,  wpa_s->bssid,
+			 NULL, NULL);
+
+	/* Install GTK/IGTK */
+
+	/* point to key data field */
+	ptr = (u8 *) frm + 1 + 1 + 2;
+	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) {
+			wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
+				   "length");
+			if (end > ptr) {
+				wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
+					    ptr, end - ptr);
+			}
+			break;
+		}
+		if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
+			if (ptr[1] < 11 + 5) {
+				wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
+					   "subelem");
+				break;
+			}
+			gtk_len = *(ptr + 4);
+			if (ptr[1] < 11 + gtk_len ||
+			    gtk_len < 5 || gtk_len > 32) {
+				wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
+					   "subelem");
+				break;
+			}
+			wpa_wnmsleep_install_key(
+				wpa_s->wpa,
+				WNM_SLEEP_SUBELEM_GTK,
+				ptr);
+			ptr += 13 + gtk_len;
+#ifdef CONFIG_IEEE80211W
+		} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
+			if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
+				wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
+					   "subelem");
+				break;
+			}
+			wpa_wnmsleep_install_key(wpa_s->wpa,
+						 WNM_SLEEP_SUBELEM_IGTK, ptr);
+			ptr += 10 + WPA_IGTK_LEN;
+#endif /* CONFIG_IEEE80211W */
+		} else
+			break; /* skip the loop */
+	}
+}
+
+
+static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
+					const u8 *frm, int len)
+{
+	/*
+	 * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
+	 * WNM-Sleep Mode IE | TFS Response IE
+	 */
+	u8 *pos = (u8 *) frm; /* point to action field */
+	u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
+	struct wnm_sleep_element *wnmsleep_ie = NULL;
+	/* multiple TFS Resp IE (assuming consecutive) */
+	u8 *tfsresp_ie_start = NULL;
+	u8 *tfsresp_ie_end = NULL;
+
+	wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
+		   frm[0], frm[1], key_len_total);
+	pos += 4 + key_len_total;
+	if (pos > frm + len) {
+		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
+		return;
+	}
+	while (pos - frm < len) {
+		u8 ie_len = *(pos + 1);
+		if (pos + 2 + ie_len > frm + len) {
+			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)
+			wnmsleep_ie = (struct wnm_sleep_element *) pos;
+		else if (*pos == WLAN_EID_TFS_RESP) {
+			if (!tfsresp_ie_start)
+				tfsresp_ie_start = pos;
+			tfsresp_ie_end = pos;
+		} else
+			wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+		pos += ie_len + 2;
+	}
+
+	if (!wnmsleep_ie) {
+		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+		return;
+	}
+
+	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
+	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
+		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
+			   "frame (action=%d, intval=%d)",
+			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
+		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
+			wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
+						     tfsresp_ie_end);
+		} else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
+			wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
+			   "(action=%d, intval=%d)",
+			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
+		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
+			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
+					 wpa_s->bssid, NULL, NULL);
+		else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
+			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
+					 wpa_s->bssid, NULL, NULL);
+	}
+}
+
+
+static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
+					      u8 dialog_token, u8 status,
+					      u8 delay, const u8 *target_bssid)
+{
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
+		   "to " MACSTR " dialog_token=%u status=%u delay=%d",
+		   MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+
+	mgmt = (struct ieee80211_mgmt *) buf;
+	os_memset(&buf, 0, sizeof(buf));
+	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
+	mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
+	mgmt->u.action.u.bss_tm_resp.status_code = status;
+	mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
+	pos = mgmt->u.action.u.bss_tm_resp.variable;
+	if (target_bssid) {
+		os_memcpy(pos, target_bssid, ETH_ALEN);
+		pos += ETH_ALEN;
+	}
+
+	len = pos - (u8 *) &mgmt->u.action.category;
+
+	wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+			    wpa_s->own_addr, wpa_s->bssid,
+			    &mgmt->u.action.category, len, 0);
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+					     const u8 *pos, const u8 *end,
+					     int reply)
+{
+	u8 dialog_token;
+	u8 mode;
+	u16 disassoc_timer;
+
+	if (pos + 5 > end)
+		return;
+
+	dialog_token = pos[0];
+	mode = pos[1];
+	disassoc_timer = WPA_GET_LE16(pos + 2);
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+		   "dialog_token=%u request_mode=0x%x "
+		   "disassoc_timer=%u validity_interval=%u",
+		   dialog_token, mode, disassoc_timer, pos[4]);
+	pos += 5;
+	if (mode & 0x08)
+		pos += 12; /* BSS Termination Duration */
+	if (mode & 0x10) {
+		char url[256];
+		if (pos + 1 > end || pos + 1 + pos[0] > end) {
+			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
+				   "Management Request (URL)");
+			return;
+		}
+		os_memcpy(url, pos + 1, pos[0]);
+		url[pos[0]] = '\0';
+		wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
+			"session_info_url=%s", url);
+	}
+
+	if (mode & 0x04) {
+		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
+			"Disassociation Timer %u", disassoc_timer);
+		if (disassoc_timer && !wpa_s->scanning) {
+			/* TODO: mark current BSS less preferred for
+			 * selection */
+			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
+	}
+
+	if (reply) {
+		/* TODO: add support for reporting Accept */
+		wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
+						  1 /* Reject - unspecified */,
+						  0, NULL);
+	}
+}
+
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+			      struct rx_action *action)
+{
+	const u8 *pos, *end;
+	u8 act;
+
+	if (action->data == NULL || action->len == 0)
+		return;
+
+	pos = action->data;
+	end = pos + action->len;
+	act = *pos++;
+
+	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+		   act, MAC2STR(action->sa));
+	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+	    os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
+			   "frame");
+		return;
+	}
+
+	switch (act) {
+	case WNM_BSS_TRANS_MGMT_REQ:
+		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
+						 !(action->da[0] & 0x01));
+		break;
+	case WNM_SLEEP_MODE_RESP:
+		ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
+		break;
+	default:
+		break;
+	}
+}

Copied: vendor/wpa/2.0/wpa_supplicant/wnm_sta.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/wnm_sta.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wnm_sta.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wnm_sta.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,21 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct rx_action;
+struct wpa_supplicant;
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+				 u8 action, u16 intval, struct wpabuf *tfs_req);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+			      struct rx_action *action);
+
+#endif /* WNM_STA_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_cli.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_cli.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_cli.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2407 +0,0 @@
-/*
- * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#ifdef CONFIG_CTRL_IFACE
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-#include <dirent.h>
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_READLINE
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif /* CONFIG_READLINE */
-#ifdef CONFIG_WPA_CLI_FORK
-#include <sys/wait.h>
-#endif /* CONFIG_WPA_CLI_FORK */
-
-#include "common/wpa_ctrl.h"
-#include "common.h"
-#include "common/version.h"
-
-
-static const char *wpa_cli_version =
-"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2010, Jouni Malinen <j at w1.fi> and contributors";
-
-
-static const char *wpa_cli_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n";
-
-static const char *wpa_cli_full_license =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-"GNU General Public License for more details.\n"
-"\n"
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"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 struct wpa_ctrl *ctrl_conn;
-static struct wpa_ctrl *mon_conn;
-#ifdef CONFIG_WPA_CLI_FORK
-static pid_t mon_pid = 0;
-#endif /* CONFIG_WPA_CLI_FORK */
-static int wpa_cli_quit = 0;
-static int wpa_cli_attached = 0;
-static int wpa_cli_connected = 0;
-static int wpa_cli_last_id = 0;
-static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
-static char *ctrl_ifname = NULL;
-static const char *pid_file = NULL;
-static const char *action_file = NULL;
-static int ping_interval = 5;
-static int interactive = 0;
-
-
-static void print_help();
-
-
-static void usage(void)
-{
-	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
-	       "[-a<action file>] \\\n"
-	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>]  "
-	       "[command..]\n"
-	       "  -h = help (show this usage text)\n"
-	       "  -v = shown version information\n"
-	       "  -a = run in daemon mode executing the action file based on "
-	       "events from\n"
-	       "       wpa_supplicant\n"
-	       "  -B = run a daemon in the background\n"
-	       "  default path: /var/run/wpa_supplicant\n"
-	       "  default interface: first interface found in socket path\n");
-	print_help();
-}
-
-
-#ifdef CONFIG_WPA_CLI_FORK
-static int in_query = 0;
-
-static void wpa_cli_monitor_sig(int sig)
-{
-	if (sig == SIGUSR1)
-		in_query = 1;
-	else if (sig == SIGUSR2)
-		in_query = 0;
-}
-
-static void wpa_cli_monitor(void)
-{
-	char buf[256];
-	size_t len = sizeof(buf) - 1;
-	struct timeval tv;
-	fd_set rfds;
-
-	signal(SIGUSR1, wpa_cli_monitor_sig);
-	signal(SIGUSR2, wpa_cli_monitor_sig);
-
-	while (mon_conn) {
-		int s = wpa_ctrl_get_fd(mon_conn);
-		tv.tv_sec = 5;
-		tv.tv_usec = 0;
-		FD_ZERO(&rfds);
-		FD_SET(s, &rfds);
-		if (select(s + 1, &rfds, NULL, NULL, &tv) < 0) {
-			if (errno == EINTR)
-				continue;
-			perror("select");
-			break;
-		}
-		if (mon_conn == NULL)
-			break;
-		if (FD_ISSET(s, &rfds)) {
-			len = sizeof(buf) - 1;
-			int res = wpa_ctrl_recv(mon_conn, buf, &len);
-			if (res < 0) {
-				perror("wpa_ctrl_recv");
-				break;
-			}
-			buf[len] = '\0';
-			if (in_query)
-				printf("\r");
-			printf("%s\n", buf);
-			kill(getppid(), SIGUSR1);
-		}
-	}
-}
-#endif /* CONFIG_WPA_CLI_FORK */
-
-
-static int wpa_cli_open_connection(const char *ifname, int attach)
-{
-#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
-	ctrl_conn = wpa_ctrl_open(ifname);
-	if (ctrl_conn == NULL)
-		return -1;
-
-	if (attach && interactive)
-		mon_conn = wpa_ctrl_open(ifname);
-	else
-		mon_conn = NULL;
-#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
-	char *cfile;
-	int flen, res;
-
-	if (ifname == NULL)
-		return -1;
-
-	flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
-	cfile = os_malloc(flen);
-	if (cfile == NULL)
-		return -1L;
-	res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
-	if (res < 0 || res >= flen) {
-		os_free(cfile);
-		return -1;
-	}
-
-	ctrl_conn = wpa_ctrl_open(cfile);
-	if (ctrl_conn == NULL) {
-		os_free(cfile);
-		return -1;
-	}
-
-	if (attach && interactive)
-		mon_conn = wpa_ctrl_open(cfile);
-	else
-		mon_conn = NULL;
-	os_free(cfile);
-#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
-
-	if (mon_conn) {
-		if (wpa_ctrl_attach(mon_conn) == 0) {
-			wpa_cli_attached = 1;
-		} else {
-			printf("Warning: Failed to attach to "
-			       "wpa_supplicant.\n");
-			return -1;
-		}
-
-#ifdef CONFIG_WPA_CLI_FORK
-		{
-			pid_t p = fork();
-			if (p < 0) {
-				perror("fork");
-				return -1;
-			}
-			if (p == 0) {
-				wpa_cli_monitor();
-				exit(0);
-			} else
-				mon_pid = p;
-		}
-#endif /* CONFIG_WPA_CLI_FORK */
-	}
-
-	return 0;
-}
-
-
-static void wpa_cli_close_connection(void)
-{
-	if (ctrl_conn == NULL)
-		return;
-
-#ifdef CONFIG_WPA_CLI_FORK
-	if (mon_pid) {
-		int status;
-		kill(mon_pid, SIGPIPE);
-		wait(&status);
-		mon_pid = 0;
-	}
-#endif /* CONFIG_WPA_CLI_FORK */
-
-	if (wpa_cli_attached) {
-		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
-		wpa_cli_attached = 0;
-	}
-	wpa_ctrl_close(ctrl_conn);
-	ctrl_conn = NULL;
-	if (mon_conn) {
-		wpa_ctrl_close(mon_conn);
-		mon_conn = NULL;
-	}
-}
-
-
-static void wpa_cli_msg_cb(char *msg, size_t len)
-{
-	printf("%s\n", msg);
-}
-
-
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
-{
-	char buf[2048];
-	size_t len;
-	int ret;
-
-	if (ctrl_conn == NULL) {
-		printf("Not connected to wpa_supplicant - command dropped.\n");
-		return -1;
-	}
-	len = sizeof(buf) - 1;
-	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
-			       wpa_cli_msg_cb);
-	if (ret == -2) {
-		printf("'%s' command timed out.\n", cmd);
-		return -2;
-	} else if (ret < 0) {
-		printf("'%s' command failed.\n", cmd);
-		return -1;
-	}
-	if (print) {
-		buf[len] = '\0';
-		printf("%s", buf);
-	}
-	return 0;
-}
-
-
-static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
-{
-	return _wpa_ctrl_command(ctrl, cmd, 1);
-}
-
-
-static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
-	return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
-}
-
-
-static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "PING");
-}
-
-
-static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "MIB");
-}
-
-
-static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "PMKSA");
-}
-
-
-static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	print_help();
-	return 0;
-}
-
-
-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);
-	return 0;
-}
-
-
-static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	wpa_cli_quit = 1;
-	return 0;
-}
-
-
-static void wpa_cli_show_variables(void)
-{
-	printf("set variables:\n"
-	       "  EAPOL::heldPeriod (EAPOL state machine held period, "
-	       "in seconds)\n"
-	       "  EAPOL::authPeriod (EAPOL state machine authentication "
-	       "period, in seconds)\n"
-	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
-	       "seconds)\n"
-	       "  EAPOL::maxStart (EAPOL state machine maximum start "
-	       "attempts)\n");
-	printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
-	       "seconds)\n"
-	       "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
-	       " threshold\n\tpercentage)\n"
-	       "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
-	       "security\n\tassociation in seconds)\n");
-}
-
-
-static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 0) {
-		wpa_cli_show_variables();
-		return 0;
-	}
-
-	if (argc != 2) {
-		printf("Invalid SET command: needs two arguments (variable "
-		       "name and value)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long SET command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "LOGOFF");
-}
-
-
-static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "LOGON");
-}
-
-
-static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "REASSOCIATE");
-}
-
-
-static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
-				       char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid PREAUTH command: needs one argument "
-		       "(BSSID)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long PREAUTH command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid AP_SCAN command: needs one argument (ap_scan "
-		       "value)\n");
-		return -1;
-	}
-	res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long AP_SCAN command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
-				char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid STKSTART command: needs one argument "
-		       "(Peer STA MAC address)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long STKSTART command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid FT_DS command: needs one argument "
-		       "(Target AP MAC address)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long FT_DS command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 0) {
-		/* Any BSSID */
-		return wpa_ctrl_command(ctrl, "WPS_PBC");
-	}
-
-	/* Specific BSSID */
-	res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_PBC command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 0) {
-		printf("Invalid WPS_PIN command: need one or two arguments:\n"
-		       "- BSSID: use 'any' to select any\n"
-		       "- PIN: optional, used only with devices that have no "
-		       "display\n");
-		return -1;
-	}
-
-	if (argc == 1) {
-		/* Use dynamically generated PIN (returned as reply) */
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
-		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-			printf("Too long WPS_PIN command.\n");
-			return -1;
-		}
-		return wpa_ctrl_command(ctrl, cmd);
-	}
-
-	/* Use hardcoded PIN from a label */
-	res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_PIN command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 3 && argc != 4) {
-		printf("Invalid WPS_OOB command: need three or four "
-		       "arguments:\n"
-		       "- DEV_TYPE: use 'ufd' or 'nfc'\n"
-		       "- PATH: path of OOB device like '/mnt'\n"
-		       "- METHOD: OOB method 'pin-e' or 'pin-r', "
-		       "'cred'\n"
-		       "- DEV_NAME: (only for NFC) device name like "
-		       "'pn531'\n");
-		return -1;
-	}
-
-	if (argc == 3)
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
-				  argv[0], argv[1], argv[2]);
-	else
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
-				  argv[0], argv[1], argv[2], argv[3]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_OOB command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 2)
-		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
-				  argv[0], argv[1]);
-	else if (argc == 6) {
-		char ssid_hex[2 * 32 + 1];
-		char key_hex[2 * 64 + 1];
-		int i;
-
-		ssid_hex[0] = '\0';
-		for (i = 0; i < 32; i++) {
-			if (argv[2][i] == '\0')
-				break;
-			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
-		}
-
-		key_hex[0] = '\0';
-		for (i = 0; i < 64; i++) {
-			if (argv[5][i] == '\0')
-				break;
-			os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
-		}
-
-		res = os_snprintf(cmd, sizeof(cmd),
-				  "WPS_REG %s %s %s %s %s %s",
-				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
-				  key_hex);
-	} else {
-		printf("Invalid WPS_REG command: need two arguments:\n"
-		       "- BSSID: use 'any' to select any\n"
-		       "- AP PIN\n");
-		printf("Alternatively, six arguments can be used to "
-		       "reconfigure the AP:\n"
-		       "- BSSID: use 'any' to select any\n"
-		       "- AP PIN\n"
-		       "- new SSID\n"
-		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
-		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
-		       "- new key\n");
-		return -1;
-	}
-
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_REG command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
-				    char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "WPS_ER_START");
-
-}
-
-
-static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
-
-}
-
-
-static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
-				  char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 2) {
-		printf("Invalid WPS_ER_PIN command: need two arguments:\n"
-		       "- UUID: use 'any' to select any\n"
-		       "- PIN: Enrollee PIN\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
-			  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_ER_PIN command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
-				  char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid WPS_ER_PBC command: need one argument:\n"
-		       "- UUID: Specify the Enrollee\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
-			  argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_ER_PBC command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
-				    char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 2) {
-		printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
-		       "- UUID: specify which AP to use\n"
-		       "- PIN: AP PIN\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
-			  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long WPS_ER_LEARN command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid IBSS_RSN command: needs one argument "
-		       "(Peer STA MAC address)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long IBSS_RSN command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid LEVEL command: needs one argument (debug "
-		       "level)\n");
-		return -1;
-	}
-	res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long LEVEL command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid IDENTITY command: needs two arguments "
-		       "(network id and identity)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long IDENTITY command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long IDENTITY command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid PASSWORD command: needs two arguments "
-		       "(network id and password)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long PASSWORD command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long PASSWORD command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
-				    char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid NEW_PASSWORD command: needs two arguments "
-		       "(network id and password)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long NEW_PASSWORD command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long NEW_PASSWORD command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid PIN command: needs two arguments "
-		       "(network id and pin)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long PIN command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long PIN command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid OTP command: needs two arguments (network "
-		       "id and password)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long OTP command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long OTP command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
-				  char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid PASSPHRASE command: needs two arguments "
-		       "(network id and passphrase)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
-			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long PASSPHRASE command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 2; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long PASSPHRASE command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[256], *pos, *end;
-	int i, ret;
-
-	if (argc < 2) {
-		printf("Invalid BSSID command: needs two arguments (network "
-		       "id and BSSID)\n");
-		return -1;
-	}
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, "BSSID");
-	if (ret < 0 || ret >= end - pos) {
-		printf("Too long BSSID command.\n");
-		return -1;
-	}
-	pos += ret;
-	for (i = 0; i < argc; i++) {
-		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
-			printf("Too long BSSID command.\n");
-			return -1;
-		}
-		pos += ret;
-	}
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
-				     char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
-}
-
-
-static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	char cmd[32];
-	int res;
-
-	if (argc < 1) {
-		printf("Invalid SELECT_NETWORK command: needs one argument "
-		       "(network id)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	char cmd[32];
-	int res;
-
-	if (argc < 1) {
-		printf("Invalid ENABLE_NETWORK command: needs one argument "
-		       "(network id)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
-				       char *argv[])
-{
-	char cmd[32];
-	int res;
-
-	if (argc < 1) {
-		printf("Invalid DISABLE_NETWORK command: needs one argument "
-		       "(network id)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
-}
-
-
-static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	char cmd[32];
-	int res;
-
-	if (argc < 1) {
-		printf("Invalid REMOVE_NETWORK command: needs one argument "
-		       "(network id)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static void wpa_cli_show_network_variables(void)
-{
-	printf("set_network variables:\n"
-	       "  ssid (network name, SSID)\n"
-	       "  psk (WPA passphrase or pre-shared key)\n"
-	       "  key_mgmt (key management protocol)\n"
-	       "  identity (EAP identity)\n"
-	       "  password (EAP password)\n"
-	       "  ...\n"
-	       "\n"
-	       "Note: Values are entered in the same format as the "
-	       "configuration file is using,\n"
-	       "i.e., strings values need to be inside double quotation "
-	       "marks.\n"
-	       "For example: set_network 1 ssid \"network name\"\n"
-	       "\n"
-	       "Please see wpa_supplicant.conf documentation for full list "
-	       "of\navailable variables.\n");
-}
-
-
-static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 0) {
-		wpa_cli_show_network_variables();
-		return 0;
-	}
-
-	if (argc != 3) {
-		printf("Invalid SET_NETWORK command: needs three arguments\n"
-		       "(network id, variable name, and value)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
-			  argv[0], argv[1], argv[2]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long SET_NETWORK command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc == 0) {
-		wpa_cli_show_network_variables();
-		return 0;
-	}
-
-	if (argc != 2) {
-		printf("Invalid GET_NETWORK command: needs two arguments\n"
-		       "(network id and variable name)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
-			  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long GET_NETWORK command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
-				  char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "DISCONNECT");
-}
-
-
-static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
-				  char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "RECONNECT");
-}
-
-
-static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
-}
-
-
-static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "SCAN");
-}
-
-
-static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
-				    char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
-}
-
-
-static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[64];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid BSS command: need one argument (index or "
-		       "BSSID)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "BSS %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	char cmd[64];
-	int res;
-
-	if (argc < 1 || argc > 2) {
-		printf("Invalid GET_CAPABILITY command: need either one or "
-		       "two arguments\n");
-		return -1;
-	}
-
-	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
-		printf("Invalid GET_CAPABILITY command: second argument, "
-		       "if any, must be 'strict'\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
-			  (argc == 2) ? " strict" : "");
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
-{
-	printf("Available interfaces:\n");
-	return wpa_ctrl_command(ctrl, "INTERFACES");
-}
-
-
-static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	if (argc < 1) {
-		wpa_cli_list_interfaces(ctrl);
-		return 0;
-	}
-
-	wpa_cli_close_connection();
-	os_free(ctrl_ifname);
-	ctrl_ifname = os_strdup(argv[0]);
-
-	if (wpa_cli_open_connection(ctrl_ifname, 1)) {
-		printf("Connected to interface '%s.\n", ctrl_ifname);
-	} else {
-		printf("Could not connect to interface '%s' - re-trying\n",
-		       ctrl_ifname);
-	}
-	return 0;
-}
-
-
-static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
-				   char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "RECONFIGURE");
-}
-
-
-static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
-				 char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "TERMINATE");
-}
-
-
-static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
-				     char *argv[])
-{
-	char cmd[256];
-	int res;
-
-	if (argc < 1) {
-		printf("Invalid INTERFACE_ADD command: needs at least one "
-		       "argument (interface name)\n"
-		       "All arguments: ifname confname driver ctrl_interface "
-		       "driver_param bridge_name\n");
-		return -1;
-	}
-
-	/*
-	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
-	 * <driver_param>TAB<bridge_name>
-	 */
-	res = os_snprintf(cmd, sizeof(cmd),
-			  "INTERFACE_ADD %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] : "");
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
-					char *argv[])
-{
-	char cmd[128];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid INTERFACE_REMOVE command: needs one argument "
-		       "(interface name)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
-		return -1;
-	cmd[sizeof(cmd) - 1] = '\0';
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
-				      char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
-}
-
-
-#ifdef CONFIG_AP
-static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char buf[64];
-	if (argc != 1) {
-		printf("Invalid 'sta' command - exactly one argument, STA "
-		       "address, is required.\n");
-		return -1;
-	}
-	os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
-	return wpa_ctrl_command(ctrl, buf);
-}
-
-
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
-				char *addr, size_t addr_len)
-{
-	char buf[4096], *pos;
-	size_t len;
-	int ret;
-
-	if (ctrl_conn == NULL) {
-		printf("Not connected to hostapd - command dropped.\n");
-		return -1;
-	}
-	len = sizeof(buf) - 1;
-	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
-			       wpa_cli_msg_cb);
-	if (ret == -2) {
-		printf("'%s' command timed out.\n", cmd);
-		return -2;
-	} else if (ret < 0) {
-		printf("'%s' command failed.\n", cmd);
-		return -1;
-	}
-
-	buf[len] = '\0';
-	if (memcmp(buf, "FAIL", 4) == 0)
-		return -1;
-	printf("%s", buf);
-
-	pos = buf;
-	while (*pos != '\0' && *pos != '\n')
-		pos++;
-	*pos = '\0';
-	os_strlcpy(addr, buf, addr_len);
-	return 0;
-}
-
-
-static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char addr[32], cmd[64];
-
-	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
-		return 0;
-	do {
-		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
-	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
-
-	return -1;
-}
-#endif /* CONFIG_AP */
-
-
-static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "SUSPEND");
-}
-
-
-static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "RESUME");
-}
-
-
-static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	return wpa_ctrl_command(ctrl, "DROP_SA");
-}
-
-
-static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	char cmd[128];
-	int res;
-
-	if (argc != 1) {
-		printf("Invalid ROAM command: needs one argument "
-		       "(target AP's BSSID)\n");
-		return -1;
-	}
-
-	res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
-		printf("Too long ROAM command.\n");
-		return -1;
-	}
-	return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-enum wpa_cli_cmd_flags {
-	cli_cmd_flag_none		= 0x00,
-	cli_cmd_flag_sensitive		= 0x01
-};
-
-struct wpa_cli_cmd {
-	const char *cmd;
-	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
-	enum wpa_cli_cmd_flags flags;
-	const char *usage;
-};
-
-static struct wpa_cli_cmd wpa_cli_commands[] = {
-	{ "status", wpa_cli_cmd_status,
-	  cli_cmd_flag_none,
-	  "[verbose] = get current WPA/EAPOL/EAP status" },
-	{ "ping", wpa_cli_cmd_ping,
-	  cli_cmd_flag_none,
-	  "= pings wpa_supplicant" },
-	{ "mib", wpa_cli_cmd_mib,
-	  cli_cmd_flag_none,
-	  "= get MIB variables (dot1x, dot11)" },
-	{ "help", wpa_cli_cmd_help,
-	  cli_cmd_flag_none,
-	  "= show this usage help" },
-	{ "interface", wpa_cli_cmd_interface,
-	  cli_cmd_flag_none,
-	  "[ifname] = show interfaces/select interface" },
-	{ "level", wpa_cli_cmd_level,
-	  cli_cmd_flag_none,
-	  "<debug level> = change debug level" },
-	{ "license", wpa_cli_cmd_license,
-	  cli_cmd_flag_none,
-	  "= show full wpa_cli license" },
-	{ "quit", wpa_cli_cmd_quit,
-	  cli_cmd_flag_none,
-	  "= exit wpa_cli" },
-	{ "set", wpa_cli_cmd_set,
-	  cli_cmd_flag_none,
-	  "= set variables (shows list of variables when run without "
-	  "arguments)" },
-	{ "logon", wpa_cli_cmd_logon,
-	  cli_cmd_flag_none,
-	  "= IEEE 802.1X EAPOL state machine logon" },
-	{ "logoff", wpa_cli_cmd_logoff,
-	  cli_cmd_flag_none,
-	  "= IEEE 802.1X EAPOL state machine logoff" },
-	{ "pmksa", wpa_cli_cmd_pmksa,
-	  cli_cmd_flag_none,
-	  "= show PMKSA cache" },
-	{ "reassociate", wpa_cli_cmd_reassociate,
-	  cli_cmd_flag_none,
-	  "= force reassociation" },
-	{ "preauthenticate", wpa_cli_cmd_preauthenticate,
-	  cli_cmd_flag_none,
-	  "<BSSID> = force preauthentication" },
-	{ "identity", wpa_cli_cmd_identity,
-	  cli_cmd_flag_none,
-	  "<network id> <identity> = configure identity for an SSID" },
-	{ "password", wpa_cli_cmd_password,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <password> = configure password for an SSID" },
-	{ "new_password", wpa_cli_cmd_new_password,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <password> = change password for an SSID" },
-	{ "pin", wpa_cli_cmd_pin,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <pin> = configure pin for an SSID" },
-	{ "otp", wpa_cli_cmd_otp,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <password> = configure one-time-password for an SSID"
-	},
-	{ "passphrase", wpa_cli_cmd_passphrase,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <passphrase> = configure private key passphrase\n"
-	  "  for an SSID" },
-	{ "bssid", wpa_cli_cmd_bssid,
-	  cli_cmd_flag_none,
-	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
-	{ "list_networks", wpa_cli_cmd_list_networks,
-	  cli_cmd_flag_none,
-	  "= list configured networks" },
-	{ "select_network", wpa_cli_cmd_select_network,
-	  cli_cmd_flag_none,
-	  "<network id> = select a network (disable others)" },
-	{ "enable_network", wpa_cli_cmd_enable_network,
-	  cli_cmd_flag_none,
-	  "<network id> = enable a network" },
-	{ "disable_network", wpa_cli_cmd_disable_network,
-	  cli_cmd_flag_none,
-	  "<network id> = disable a network" },
-	{ "add_network", wpa_cli_cmd_add_network,
-	  cli_cmd_flag_none,
-	  "= add a network" },
-	{ "remove_network", wpa_cli_cmd_remove_network,
-	  cli_cmd_flag_none,
-	  "<network id> = remove a network" },
-	{ "set_network", wpa_cli_cmd_set_network,
-	  cli_cmd_flag_sensitive,
-	  "<network id> <variable> <value> = set network variables (shows\n"
-	  "  list of variables when run without arguments)" },
-	{ "get_network", wpa_cli_cmd_get_network,
-	  cli_cmd_flag_none,
-	  "<network id> <variable> = get network variables" },
-	{ "save_config", wpa_cli_cmd_save_config,
-	  cli_cmd_flag_none,
-	  "= save the current configuration" },
-	{ "disconnect", wpa_cli_cmd_disconnect,
-	  cli_cmd_flag_none,
-	  "= disconnect and wait for reassociate/reconnect command before\n"
-	  "  connecting" },
-	{ "reconnect", wpa_cli_cmd_reconnect,
-	  cli_cmd_flag_none,
-	  "= like reassociate, but only takes effect if already disconnected"
-	},
-	{ "scan", wpa_cli_cmd_scan,
-	  cli_cmd_flag_none,
-	  "= request new BSS scan" },
-	{ "scan_results", wpa_cli_cmd_scan_results,
-	  cli_cmd_flag_none,
-	  "= get latest scan results" },
-	{ "bss", wpa_cli_cmd_bss,
-	  cli_cmd_flag_none,
-	  "<<idx> | <bssid>> = get detailed scan result info" },
-	{ "get_capability", wpa_cli_cmd_get_capability,
-	  cli_cmd_flag_none,
-	  "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
-	{ "reconfigure", wpa_cli_cmd_reconfigure,
-	  cli_cmd_flag_none,
-	  "= force wpa_supplicant to re-read its configuration file" },
-	{ "terminate", wpa_cli_cmd_terminate,
-	  cli_cmd_flag_none,
-	  "= terminate wpa_supplicant" },
-	{ "interface_add", wpa_cli_cmd_interface_add,
-	  cli_cmd_flag_none,
-	  "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
-	  "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
-	  "  are optional" },
-	{ "interface_remove", wpa_cli_cmd_interface_remove,
-	  cli_cmd_flag_none,
-	  "<ifname> = removes the interface" },
-	{ "interface_list", wpa_cli_cmd_interface_list,
-	  cli_cmd_flag_none,
-	  "= list available interfaces" },
-	{ "ap_scan", wpa_cli_cmd_ap_scan,
-	  cli_cmd_flag_none,
-	  "<value> = set ap_scan parameter" },
-	{ "stkstart", wpa_cli_cmd_stkstart,
-	  cli_cmd_flag_none,
-	  "<addr> = request STK negotiation with <addr>" },
-	{ "ft_ds", wpa_cli_cmd_ft_ds,
-	  cli_cmd_flag_none,
-	  "<addr> = request over-the-DS FT with <addr>" },
-	{ "wps_pbc", wpa_cli_cmd_wps_pbc,
-	  cli_cmd_flag_none,
-	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
-	{ "wps_pin", wpa_cli_cmd_wps_pin,
-	  cli_cmd_flag_sensitive,
-	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
-	  "hardcoded)" },
-#ifdef CONFIG_WPS_OOB
-	{ "wps_oob", wpa_cli_cmd_wps_oob,
-	  cli_cmd_flag_sensitive,
-	  "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
-	{ "wps_reg", wpa_cli_cmd_wps_reg,
-	  cli_cmd_flag_sensitive,
-	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
-	{ "wps_er_start", wpa_cli_cmd_wps_er_start,
-	  cli_cmd_flag_none,
-	  "= start Wi-Fi Protected Setup External Registrar" },
-	{ "wps_er_stop", wpa_cli_cmd_wps_er_stop,
-	  cli_cmd_flag_none,
-	  "= stop Wi-Fi Protected Setup External Registrar" },
-	{ "wps_er_pin", wpa_cli_cmd_wps_er_pin,
-	  cli_cmd_flag_sensitive,
-	  "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
-	{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
-	  cli_cmd_flag_none,
-	  "<UUID> = accept an Enrollee PBC using External Registrar" },
-	{ "wps_er_learn", wpa_cli_cmd_wps_er_learn,
-	  cli_cmd_flag_sensitive,
-	  "<UUID> <PIN> = learn AP configuration" },
-	{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
-	  cli_cmd_flag_none,
-	  "<addr> = request RSN authentication with <addr> in IBSS" },
-#ifdef CONFIG_AP
-	{ "sta", wpa_cli_cmd_sta,
-	  cli_cmd_flag_none,
-	  "<addr> = get information about an associated station (AP)" },
-	{ "all_sta", wpa_cli_cmd_all_sta,
-	  cli_cmd_flag_none,
-	  "= get information about all associated stations (AP)" },
-#endif /* CONFIG_AP */
-	{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
-	  "= notification of suspend/hibernate" },
-	{ "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
-	  "= notification of resume/thaw" },
-	{ "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
-	  "= drop SA without deauth/disassoc (test command)" },
-	{ "roam", wpa_cli_cmd_roam,
-	  cli_cmd_flag_none,
-	  "<addr> = roam to the specified BSS" },
-	{ NULL, NULL, cli_cmd_flag_none, NULL }
-};
-
-
-/*
- * Prints command usage, lines are padded with the specified string.
- */
-static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
-{
-	char c;
-	size_t n;
-
-	printf("%s%s ", pad, cmd->cmd);
-	for (n = 0; (c = cmd->usage[n]); n++) {
-		printf("%c", c);
-		if (c == '\n')
-			printf("%s", pad);
-	}
-	printf("\n");
-}
-
-
-static void print_help(void)
-{
-	int n;
-	printf("commands:\n");
-	for (n = 0; wpa_cli_commands[n].cmd; n++)
-		print_cmd_help(&wpa_cli_commands[n], "  ");
-}
-
-
-#ifdef CONFIG_READLINE
-static int cmd_has_sensitive_data(const char *cmd)
-{
-	const char *c, *delim;
-	int n;
-	size_t len;
-
-	delim = os_strchr(cmd, ' ');
-	if (delim)
-		len = delim - cmd;
-	else
-		len = os_strlen(cmd);
-
-	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
-		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
-			return (wpa_cli_commands[n].flags &
-				cli_cmd_flag_sensitive);
-	}
-	return 0;
-}
-#endif /* CONFIG_READLINE */
-
-
-static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
-	struct wpa_cli_cmd *cmd, *match = NULL;
-	int count;
-	int ret = 0;
-
-	count = 0;
-	cmd = wpa_cli_commands;
-	while (cmd->cmd) {
-		if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
-		{
-			match = cmd;
-			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
-				/* we have an exact match */
-				count = 1;
-				break;
-			}
-			count++;
-		}
-		cmd++;
-	}
-
-	if (count > 1) {
-		printf("Ambiguous command '%s'; possible commands:", argv[0]);
-		cmd = wpa_cli_commands;
-		while (cmd->cmd) {
-			if (os_strncasecmp(cmd->cmd, argv[0],
-					   os_strlen(argv[0])) == 0) {
-				printf(" %s", cmd->cmd);
-			}
-			cmd++;
-		}
-		printf("\n");
-		ret = 1;
-	} else if (count == 0) {
-		printf("Unknown command '%s'\n", argv[0]);
-		ret = 1;
-	} else {
-		ret = match->handler(ctrl, argc - 1, &argv[1]);
-	}
-
-	return ret;
-}
-
-
-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)
-{
-	char *cmd;
-	size_t len;
-	int res;
-	int ret = 0;
-
-	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
-	cmd = os_malloc(len);
-	if (cmd == NULL)
-		return -1;
-	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
-	if (res < 0 || (size_t) res >= len) {
-		os_free(cmd);
-		return -1;
-	}
-	cmd[len - 1] = '\0';
-#ifndef _WIN32_WCE
-	if (system(cmd) < 0)
-		ret = -1;
-#endif /* _WIN32_WCE */
-	os_free(cmd);
-
-	return ret;
-}
-
-
-static void wpa_cli_action_process(const char *msg)
-{
-	const char *pos;
-	char *copy = NULL, *id, *pos2;
-
-	pos = msg;
-	if (*pos == '<') {
-		/* skip priority */
-		pos = os_strchr(pos, '>');
-		if (pos)
-			pos++;
-		else
-			pos = msg;
-	}
-
-	if (str_match(pos, WPA_EVENT_CONNECTED)) {
-		int new_id = -1;
-		os_unsetenv("WPA_ID");
-		os_unsetenv("WPA_ID_STR");
-		os_unsetenv("WPA_CTRL_DIR");
-
-		pos = os_strstr(pos, "[id=");
-		if (pos)
-			copy = os_strdup(pos + 4);
-
-		if (copy) {
-			pos2 = id = copy;
-			while (*pos2 && *pos2 != ' ')
-				pos2++;
-			*pos2++ = '\0';
-			new_id = atoi(id);
-			os_setenv("WPA_ID", id, 1);
-			while (*pos2 && *pos2 != '=')
-				pos2++;
-			if (*pos2 == '=')
-				pos2++;
-			id = pos2;
-			while (*pos2 && *pos2 != ']')
-				pos2++;
-			*pos2 = '\0';
-			os_setenv("WPA_ID_STR", id, 1);
-			os_free(copy);
-		}
-
-		os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
-
-		if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
-			wpa_cli_connected = 1;
-			wpa_cli_last_id = new_id;
-			wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
-		}
-	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
-		if (wpa_cli_connected) {
-			wpa_cli_connected = 0;
-			wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
-		}
-	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
-		printf("wpa_supplicant is terminating - stop monitoring\n");
-		wpa_cli_quit = 1;
-	}
-}
-
-
-#ifndef CONFIG_ANSI_C_EXTRA
-static void wpa_cli_action_cb(char *msg, size_t len)
-{
-	wpa_cli_action_process(msg);
-}
-#endif /* CONFIG_ANSI_C_EXTRA */
-
-
-static void wpa_cli_reconnect(void)
-{
-	wpa_cli_close_connection();
-	wpa_cli_open_connection(ctrl_ifname, 1);
-}
-
-
-static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
-				 int action_monitor)
-{
-	int first = 1;
-	if (ctrl_conn == NULL) {
-		wpa_cli_reconnect();
-		return;
-	}
-	while (wpa_ctrl_pending(ctrl) > 0) {
-		char buf[256];
-		size_t len = sizeof(buf) - 1;
-		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
-			buf[len] = '\0';
-			if (action_monitor)
-				wpa_cli_action_process(buf);
-			else {
-				if (in_read && first)
-					printf("\r");
-				first = 0;
-				printf("%s\n", buf);
-#ifdef CONFIG_READLINE
-				rl_on_new_line();
-				rl_redisplay();
-#endif /* CONFIG_READLINE */
-			}
-		} else {
-			printf("Could not read pending message.\n");
-			break;
-		}
-	}
-
-	if (wpa_ctrl_pending(ctrl) < 0) {
-		printf("Connection to wpa_supplicant lost - trying to "
-		       "reconnect\n");
-		wpa_cli_reconnect();
-	}
-}
-
-
-#ifdef CONFIG_READLINE
-static char * wpa_cli_cmd_gen(const char *text, int state)
-{
-	static int i, len;
-	const char *cmd;
-
-	if (state == 0) {
-		i = 0;
-		len = os_strlen(text);
-	}
-
-	while ((cmd = wpa_cli_commands[i].cmd)) {
-		i++;
-		if (os_strncasecmp(cmd, text, len) == 0)
-			return strdup(cmd);
-	}
-
-	return NULL;
-}
-
-
-static char * wpa_cli_dummy_gen(const char *text, int state)
-{
-	int i;
-
-	for (i = 0; wpa_cli_commands[i].cmd; i++) {
-		const char *cmd = wpa_cli_commands[i].cmd;
-		size_t len = os_strlen(cmd);
-		if (os_strncasecmp(rl_line_buffer, cmd, len) == 0 &&
-		    rl_line_buffer[len] == ' ') {
-			printf("\n%s\n", wpa_cli_commands[i].usage);
-			rl_on_new_line();
-			rl_redisplay();
-			break;
-		}
-	}
-
-	rl_attempted_completion_over = 1;
-	return NULL;
-}
-
-
-static char * wpa_cli_status_gen(const char *text, int state)
-{
-	static int i, len;
-	char *options[] = {
-		"verbose", NULL
-	};
-	char *t;
-
-	if (state == 0) {
-		i = 0;
-		len = os_strlen(text);
-	}
-
-	while ((t = options[i])) {
-		i++;
-		if (os_strncasecmp(t, text, len) == 0)
-			return strdup(t);
-	}
-
-	rl_attempted_completion_over = 1;
-	return NULL;
-}
-
-
-static char ** wpa_cli_completion(const char *text, int start, int end)
-{
-	char * (*func)(const char *text, int state);
-
-	if (start == 0)
-		func = wpa_cli_cmd_gen;
-	else if (os_strncasecmp(rl_line_buffer, "status ", 7) == 0)
-		func = wpa_cli_status_gen;
-	else
-		func = wpa_cli_dummy_gen;
-	return rl_completion_matches(text, func);
-}
-#endif /* CONFIG_READLINE */
-
-
-static void wpa_cli_interactive(void)
-{
-#define max_args 10
-	char cmdbuf[256], *cmd, *argv[max_args], *pos;
-	int argc;
-#ifdef CONFIG_READLINE
-	char *home, *hfile = NULL;
-#endif /* CONFIG_READLINE */
-
-	printf("\nInteractive mode\n\n");
-
-#ifdef CONFIG_READLINE
-	rl_attempted_completion_function = wpa_cli_completion;
-	home = getenv("HOME");
-	if (home) {
-		const char *fname = ".wpa_cli_history";
-		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
-		hfile = os_malloc(hfile_len);
-		if (hfile) {
-			int res;
-			res = os_snprintf(hfile, hfile_len, "%s/%s", home,
-					  fname);
-			if (res >= 0 && res < hfile_len) {
-				hfile[hfile_len - 1] = '\0';
-				read_history(hfile);
-				stifle_history(100);
-			}
-		}
-	}
-#endif /* CONFIG_READLINE */
-
-	do {
-		wpa_cli_recv_pending(mon_conn, 0, 0);
-#ifndef CONFIG_NATIVE_WINDOWS
-		alarm(ping_interval);
-#endif /* CONFIG_NATIVE_WINDOWS */
-#ifdef CONFIG_WPA_CLI_FORK
-		if (mon_pid)
-			kill(mon_pid, SIGUSR1);
-#endif /* CONFIG_WPA_CLI_FORK */
-#ifdef CONFIG_READLINE
-		cmd = readline("> ");
-		if (cmd && *cmd) {
-			HIST_ENTRY *h;
-			while (next_history())
-				;
-			h = previous_history();
-			if (h == NULL || os_strcmp(cmd, h->line) != 0)
-				add_history(cmd);
-			next_history();
-		}
-#else /* CONFIG_READLINE */
-		printf("> ");
-		cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin);
-#endif /* CONFIG_READLINE */
-#ifndef CONFIG_NATIVE_WINDOWS
-		alarm(0);
-#endif /* CONFIG_NATIVE_WINDOWS */
-		if (cmd == NULL)
-			break;
-		wpa_cli_recv_pending(mon_conn, 0, 0);
-		pos = cmd;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		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';
-		}
-		if (argc)
-			wpa_request(ctrl_conn, argc, argv);
-
-		if (cmd != cmdbuf)
-			free(cmd);
-#ifdef CONFIG_WPA_CLI_FORK
-		if (mon_pid)
-			kill(mon_pid, SIGUSR2);
-#endif /* CONFIG_WPA_CLI_FORK */
-	} while (!wpa_cli_quit);
-
-#ifdef CONFIG_READLINE
-	if (hfile) {
-		/* Save command history, excluding lines that may contain
-		 * passwords. */
-		HIST_ENTRY *h;
-		history_set_pos(0);
-		while ((h = current_history())) {
-			char *p = h->line;
-			while (*p == ' ' || *p == '\t')
-				p++;
-			if (cmd_has_sensitive_data(p)) {
-				h = remove_history(where_history());
-				if (h) {
-					os_free(h->line);
-					os_free(h->data);
-					os_free(h);
-				} else
-					next_history();
-			} else
-				next_history();
-		}
-		write_history(hfile);
-		os_free(hfile);
-	}
-#endif /* CONFIG_READLINE */
-}
-
-
-static void wpa_cli_action(struct wpa_ctrl *ctrl)
-{
-#ifdef CONFIG_ANSI_C_EXTRA
-	/* TODO: ANSI C version(?) */
-	printf("Action processing not supported in ANSI C build.\n");
-#else /* CONFIG_ANSI_C_EXTRA */
-	fd_set rfds;
-	int fd, res;
-	struct timeval tv;
-	char buf[256]; /* note: large enough to fit in unsolicited messages */
-	size_t len;
-
-	fd = wpa_ctrl_get_fd(ctrl);
-
-	while (!wpa_cli_quit) {
-		FD_ZERO(&rfds);
-		FD_SET(fd, &rfds);
-		tv.tv_sec = ping_interval;
-		tv.tv_usec = 0;
-		res = select(fd + 1, &rfds, NULL, NULL, &tv);
-		if (res < 0 && errno != EINTR) {
-			perror("select");
-			break;
-		}
-
-		if (FD_ISSET(fd, &rfds))
-			wpa_cli_recv_pending(ctrl, 0, 1);
-		else {
-			/* verify that connection is still working */
-			len = sizeof(buf) - 1;
-			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
-					     wpa_cli_action_cb) < 0 ||
-			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
-				printf("wpa_supplicant did not reply to PING "
-				       "command - exiting\n");
-				break;
-			}
-		}
-	}
-#endif /* CONFIG_ANSI_C_EXTRA */
-}
-
-
-static void wpa_cli_cleanup(void)
-{
-	wpa_cli_close_connection();
-	if (pid_file)
-		os_daemonize_terminate(pid_file);
-
-	os_program_deinit();
-}
-
-static void wpa_cli_terminate(int sig)
-{
-	wpa_cli_cleanup();
-	exit(0);
-}
-
-
-#ifdef CONFIG_WPA_CLI_FORK
-static void wpa_cli_usr1(int sig)
-{
-#ifdef CONFIG_READLINE
-	rl_on_new_line();
-	rl_redisplay();
-#endif /* CONFIG_READLINE */
-}
-#endif /* CONFIG_WPA_CLI_FORK */
-
-
-#ifndef CONFIG_NATIVE_WINDOWS
-static void wpa_cli_alarm(int sig)
-{
-	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
-		printf("Connection to wpa_supplicant lost - trying to "
-		       "reconnect\n");
-		wpa_cli_close_connection();
-	}
-	if (!ctrl_conn)
-		wpa_cli_reconnect();
-	if (mon_conn)
-		wpa_cli_recv_pending(mon_conn, 1, 0);
-	alarm(ping_interval);
-}
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-static char * wpa_cli_get_default_ifname(void)
-{
-	char *ifname = NULL;
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-	struct dirent *dent;
-	DIR *dir = opendir(ctrl_iface_dir);
-	if (!dir)
-		return NULL;
-	while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-		/*
-		 * Skip the file if it is not a socket. Also accept
-		 * DT_UNKNOWN (0) in case the C library or underlying
-		 * file system does not support d_type.
-		 */
-		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
-			continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-		if (os_strcmp(dent->d_name, ".") == 0 ||
-		    os_strcmp(dent->d_name, "..") == 0)
-			continue;
-		printf("Selected interface '%s'\n", dent->d_name);
-		ifname = os_strdup(dent->d_name);
-		break;
-	}
-	closedir(dir);
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-	char buf[2048], *pos;
-	size_t len;
-	struct wpa_ctrl *ctrl;
-	int ret;
-
-	ctrl = wpa_ctrl_open(NULL);
-	if (ctrl == NULL)
-		return NULL;
-
-	len = sizeof(buf) - 1;
-	ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
-	if (ret >= 0) {
-		buf[len] = '\0';
-		pos = os_strchr(buf, '\n');
-		if (pos)
-			*pos = '\0';
-		ifname = os_strdup(buf);
-	}
-	wpa_ctrl_close(ctrl);
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-
-	return ifname;
-}
-
-
-int main(int argc, char *argv[])
-{
-	int warning_displayed = 0;
-	int c;
-	int daemonize = 0;
-	int ret = 0;
-	const char *global = NULL;
-
-	if (os_program_init())
-		return -1;
-
-	for (;;) {
-		c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'a':
-			action_file = optarg;
-			break;
-		case 'B':
-			daemonize = 1;
-			break;
-		case 'g':
-			global = optarg;
-			break;
-		case 'G':
-			ping_interval = atoi(optarg);
-			break;
-		case 'h':
-			usage();
-			return 0;
-		case 'v':
-			printf("%s\n", wpa_cli_version);
-			return 0;
-		case 'i':
-			os_free(ctrl_ifname);
-			ctrl_ifname = os_strdup(optarg);
-			break;
-		case 'p':
-			ctrl_iface_dir = optarg;
-			break;
-		case 'P':
-			pid_file = optarg;
-			break;
-		default:
-			usage();
-			return -1;
-		}
-	}
-
-	interactive = (argc == optind) && (action_file == NULL);
-
-	if (interactive)
-		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
-
-	if (global) {
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-		ctrl_conn = wpa_ctrl_open(NULL);
-#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-		ctrl_conn = wpa_ctrl_open(global);
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-		if (ctrl_conn == NULL) {
-			perror("Failed to connect to wpa_supplicant - "
-			       "wpa_ctrl_open");
-			return -1;
-		}
-	}
-
-#ifndef _WIN32_WCE
-	signal(SIGINT, wpa_cli_terminate);
-	signal(SIGTERM, wpa_cli_terminate);
-#endif /* _WIN32_WCE */
-#ifndef CONFIG_NATIVE_WINDOWS
-	signal(SIGALRM, wpa_cli_alarm);
-#endif /* CONFIG_NATIVE_WINDOWS */
-#ifdef CONFIG_WPA_CLI_FORK
-	signal(SIGUSR1, wpa_cli_usr1);
-#endif /* CONFIG_WPA_CLI_FORK */
-
-	if (ctrl_ifname == NULL)
-		ctrl_ifname = wpa_cli_get_default_ifname();
-
-	if (interactive) {
-		for (; !global;) {
-			if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
-				if (warning_displayed)
-					printf("Connection established.\n");
-				break;
-			}
-
-			if (!warning_displayed) {
-				printf("Could not connect to wpa_supplicant - "
-				       "re-trying\n");
-				warning_displayed = 1;
-			}
-			os_sleep(1, 0);
-			continue;
-		}
-	} else {
-		if (!global &&
-		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
-			perror("Failed to connect to wpa_supplicant - "
-			       "wpa_ctrl_open");
-			return -1;
-		}
-
-		if (action_file) {
-			if (wpa_ctrl_attach(ctrl_conn) == 0) {
-				wpa_cli_attached = 1;
-			} else {
-				printf("Warning: Failed to attach to "
-				       "wpa_supplicant.\n");
-				return -1;
-			}
-		}
-	}
-
-	if (daemonize && os_daemonize(pid_file))
-		return -1;
-
-	if (interactive)
-		wpa_cli_interactive();
-	else if (action_file)
-		wpa_cli_action(ctrl_conn);
-	else
-		ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
-
-	os_free(ctrl_ifname);
-	wpa_cli_cleanup();
-
-	return ret;
-}
-
-#else /* CONFIG_CTRL_IFACE */
-int main(int argc, char *argv[])
-{
-	printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
-	return -1;
-}
-#endif /* CONFIG_CTRL_IFACE */

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_cli.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_cli.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_cli.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_cli.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3522 @@
+/*
+ * WPA Supplicant - command line interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <dirent.h>
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+#include "common/wpa_ctrl.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "utils/list.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#ifdef ANDROID
+#include <cutils/properties.h>
+#endif /* ANDROID */
+
+
+static const char *wpa_cli_version =
+"wpa_cli v" VERSION_STR "\n"
+"Copyright (c) 2004-2012, Jouni Malinen <j at w1.fi> and contributors";
+
+
+static const char *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 *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";
+
+static struct wpa_ctrl *ctrl_conn;
+static struct wpa_ctrl *mon_conn;
+static int wpa_cli_quit = 0;
+static int wpa_cli_attached = 0;
+static int wpa_cli_connected = 0;
+static int wpa_cli_last_id = 0;
+#ifndef CONFIG_CTRL_IFACE_DIR
+#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
+#endif /* CONFIG_CTRL_IFACE_DIR */
+static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+static char *ctrl_ifname = NULL;
+static const char *pid_file = NULL;
+static const char *action_file = NULL;
+static int ping_interval = 5;
+static int interactive = 0;
+
+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 */
+
+
+static void print_help(const char *cmd);
+static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void wpa_cli_close_connection(void);
+static char * wpa_cli_get_default_ifname(void);
+static char ** wpa_list_cmd_list(void);
+
+
+static void usage(void)
+{
+	printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+	       "[-a<action file>] \\\n"
+	       "        [-P<pid file>] [-g<global ctrl>] [-G<ping interval>]  "
+	       "[command..]\n"
+	       "  -h = help (show this usage text)\n"
+	       "  -v = shown version information\n"
+	       "  -a = run in daemon mode executing the action file based on "
+	       "events from\n"
+	       "       wpa_supplicant\n"
+	       "  -B = run a daemon in the background\n"
+	       "  default path: " CONFIG_CTRL_IFACE_DIR "\n"
+	       "  default interface: first interface found in socket path\n");
+	print_help(NULL);
+}
+
+
+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)
+{
+	const char *end;
+	char *buf;
+	end = os_strchr(txt, ' ');
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = os_malloc(end - txt + 1);
+	if (buf == NULL)
+		return;
+	os_memcpy(buf, txt, end - txt);
+	buf[end - txt] = '\0';
+	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);
+}
+
+
+static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
+{
+	const char *end;
+	char *buf;
+	int ret;
+	end = os_strchr(txt, ' ');
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = os_malloc(end - txt + 1);
+	if (buf == NULL)
+		return -1;
+	os_memcpy(buf, txt, end - txt);
+	buf[end - txt] = '\0';
+	ret = cli_txt_list_add(txt_list, buf);
+	os_free(buf);
+	return ret;
+}
+#endif /* CONFIG_P2P */
+
+
+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;
+
+	start = os_strchr(event, '>');
+	if (start == NULL)
+		return 1;
+
+	start++;
+	/*
+	 * Skip BSS added/removed events since they can be relatively frequent
+	 * and are likely of not much use for an interactive user.
+	 */
+	if (str_starts(start, WPA_EVENT_BSS_ADDED) ||
+	    str_starts(start, WPA_EVENT_BSS_REMOVED))
+		return 0;
+
+	return 1;
+}
+
+
+static int wpa_cli_open_connection(const char *ifname, int attach)
+{
+#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
+	ctrl_conn = wpa_ctrl_open(ifname);
+	if (ctrl_conn == NULL)
+		return -1;
+
+	if (attach && interactive)
+		mon_conn = wpa_ctrl_open(ifname);
+	else
+		mon_conn = NULL;
+#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
+	char *cfile = NULL;
+	int flen, res;
+
+	if (ifname == NULL)
+		return -1;
+
+#ifdef ANDROID
+	if (access(ctrl_iface_dir, F_OK) < 0) {
+		cfile = os_strdup(ifname);
+		if (cfile == NULL)
+			return -1;
+	}
+#endif /* ANDROID */
+
+	if (cfile == NULL) {
+		flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
+		cfile = os_malloc(flen);
+		if (cfile == NULL)
+			return -1;
+		res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
+				  ifname);
+		if (res < 0 || res >= flen) {
+			os_free(cfile);
+			return -1;
+		}
+	}
+
+	ctrl_conn = wpa_ctrl_open(cfile);
+	if (ctrl_conn == NULL) {
+		os_free(cfile);
+		return -1;
+	}
+
+	if (attach && interactive)
+		mon_conn = wpa_ctrl_open(cfile);
+	else
+		mon_conn = NULL;
+	os_free(cfile);
+#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+	if (mon_conn) {
+		if (wpa_ctrl_attach(mon_conn) == 0) {
+			wpa_cli_attached = 1;
+			if (interactive)
+				eloop_register_read_sock(
+					wpa_ctrl_get_fd(mon_conn),
+					wpa_cli_mon_receive, NULL, NULL);
+		} else {
+			printf("Warning: Failed to attach to "
+			       "wpa_supplicant.\n");
+			wpa_cli_close_connection();
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void wpa_cli_close_connection(void)
+{
+	if (ctrl_conn == NULL)
+		return;
+
+	if (wpa_cli_attached) {
+		wpa_ctrl_detach(interactive ? mon_conn : ctrl_conn);
+		wpa_cli_attached = 0;
+	}
+	wpa_ctrl_close(ctrl_conn);
+	ctrl_conn = NULL;
+	if (mon_conn) {
+		eloop_unregister_read_sock(wpa_ctrl_get_fd(mon_conn));
+		wpa_ctrl_close(mon_conn);
+		mon_conn = NULL;
+	}
+}
+
+
+static void wpa_cli_msg_cb(char *msg, size_t len)
+{
+	printf("%s\n", msg);
+}
+
+
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+{
+	char buf[2048];
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to wpa_supplicant - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+			       wpa_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+	if (print) {
+		buf[len] = '\0';
+		printf("%s", buf);
+		if (interactive && len > 0 && buf[len - 1] != '\n')
+			printf("\n");
+	}
+	return 0;
+}
+
+
+static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+{
+	return _wpa_ctrl_command(ctrl, cmd, 1);
+}
+
+
+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 (res < 0 || res >= end - pos)
+		goto fail;
+	pos += res;
+
+	for (i = 0; i < argc; i++) {
+		res = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (res < 0 || res >= end - pos)
+			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[])
+{
+	char buf[256];
+	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 wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "IFNAME");
+}
+
+
+static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
+	if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-WPS");
+	return wpa_ctrl_command(ctrl, "STATUS");
+}
+
+
+static int wpa_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "PING");
+}
+
+
+static int wpa_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RELOG");
+}
+
+
+static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "MIB");
+}
+
+
+static int wpa_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "PMKSA");
+}
+
+
+static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	print_help(argc > 0 ? argv[0] : NULL);
+	return 0;
+}
+
+
+static char ** wpa_cli_complete_help(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = wpa_list_cmd_list();
+		break;
+	}
+
+	return res;
+}
+
+
+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);
+	return 0;
+}
+
+
+static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	wpa_cli_quit = 1;
+	if (interactive)
+		eloop_terminate();
+	return 0;
+}
+
+
+static void wpa_cli_show_variables(void)
+{
+	printf("set variables:\n"
+	       "  EAPOL::heldPeriod (EAPOL state machine held period, "
+	       "in seconds)\n"
+	       "  EAPOL::authPeriod (EAPOL state machine authentication "
+	       "period, in seconds)\n"
+	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
+	       "seconds)\n"
+	       "  EAPOL::maxStart (EAPOL state machine maximum start "
+	       "attempts)\n");
+	printf("  dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
+	       "seconds)\n"
+	       "  dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
+	       " threshold\n\tpercentage)\n"
+	       "  dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
+	       "security\n\tassociation in seconds)\n");
+}
+
+
+static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc == 0) {
+		wpa_cli_show_variables();
+		return 0;
+	}
+
+	if (argc != 1 && argc != 2) {
+		printf("Invalid SET command: needs two arguments (variable "
+		       "name and value)\n");
+		return -1;
+	}
+
+	if (argc == 1)
+		res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
+				  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long SET command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "LOGOFF");
+}
+
+
+static int wpa_cli_cmd_logon(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "LOGON");
+}
+
+
+static int wpa_cli_cmd_reassociate(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "REASSOCIATE");
+}
+
+
+static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
+				        char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc < 1)
+		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long BSS_FLUSH command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
+				char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc == 0) {
+		printf("Invalid WPS_PIN command: need one or two arguments:\n"
+		       "- BSSID: use 'any' to select any\n"
+		       "- PIN: optional, used only with devices that have no "
+		       "display\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_tag_read' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 18 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'nfc_rx_handover_req' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 21 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 21 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc == 2)
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
+				  argv[0], argv[1]);
+	else if (argc == 5 || argc == 6) {
+		char ssid_hex[2 * 32 + 1];
+		char key_hex[2 * 64 + 1];
+		int i;
+
+		ssid_hex[0] = '\0';
+		for (i = 0; i < 32; i++) {
+			if (argv[2][i] == '\0')
+				break;
+			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
+		}
+
+		key_hex[0] = '\0';
+		if (argc == 6) {
+			for (i = 0; i < 64; i++) {
+				if (argv[5][i] == '\0')
+					break;
+				os_snprintf(&key_hex[i * 2], 3, "%02x",
+					    argv[5][i]);
+			}
+		}
+
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "WPS_REG %s %s %s %s %s %s",
+				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
+				  key_hex);
+	} else {
+		printf("Invalid WPS_REG command: need two arguments:\n"
+		       "- BSSID of the target AP\n"
+		       "- AP PIN\n");
+		printf("Alternatively, six arguments can be used to "
+		       "reconfigure the AP:\n"
+		       "- BSSID of the target AP\n"
+		       "- AP PIN\n"
+		       "- new SSID\n"
+		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
+		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
+		       "- new key\n");
+		return -1;
+	}
+
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_REG command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_stop(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_ER_STOP");
+
+}
+
+
+static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	if (argc < 2) {
+		printf("Invalid WPS_ER_PIN command: need at least two "
+		       "arguments:\n"
+		       "- UUID: use 'any' to select any\n"
+		       "- PIN: Enrollee PIN\n"
+		       "optional: - Enrollee MAC address\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	if (argc != 2) {
+		printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
+		       "- UUID: specify which AP to use\n"
+		       "- PIN: AP PIN\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	if (argc != 2) {
+		printf("Invalid WPS_ER_SET_CONFIG command: need two "
+		       "arguments:\n"
+		       "- UUID: specify which AP to use\n"
+		       "- Network configuration id\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wps_er_config(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc == 5 || argc == 6) {
+		char ssid_hex[2 * 32 + 1];
+		char key_hex[2 * 64 + 1];
+		int i;
+
+		ssid_hex[0] = '\0';
+		for (i = 0; i < 32; i++) {
+			if (argv[2][i] == '\0')
+				break;
+			os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
+		}
+
+		key_hex[0] = '\0';
+		if (argc == 6) {
+			for (i = 0; i < 64; i++) {
+				if (argv[5][i] == '\0')
+					break;
+				os_snprintf(&key_hex[i * 2], 3, "%02x",
+					    argv[5][i]);
+			}
+		}
+
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "WPS_ER_CONFIG %s %s %s %s %s %s",
+				  argv[0], argv[1], ssid_hex, argv[3], argv[4],
+				  key_hex);
+	} else {
+		printf("Invalid WPS_ER_CONFIG command: need six arguments:\n"
+		       "- AP UUID\n"
+		       "- AP PIN\n"
+		       "- new SSID\n"
+		       "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
+		       "- new encr (NONE, WEP, TKIP, CCMP)\n"
+		       "- new key\n");
+		return -1;
+	}
+
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_ER_CONFIG command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+					       char *argv[])
+{
+	if (argc != 2) {
+		printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
+		       "arguments:\n"
+		       "- WPS/NDEF: token format\n"
+		       "- UUID: specify which AP to use\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid IDENTITY command: needs two arguments "
+		       "(network id and identity)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long IDENTITY command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long IDENTITY command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid PASSWORD command: needs two arguments "
+		       "(network id and password)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long PASSWORD command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long PASSWORD command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid NEW_PASSWORD command: needs two arguments "
+		       "(network id and password)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long NEW_PASSWORD command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long NEW_PASSWORD command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid PIN command: needs two arguments "
+		       "(network id and pin)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long PIN command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long PIN command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid OTP command: needs two arguments (network "
+		       "id and password)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long OTP command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long OTP command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	char cmd[256], *pos, *end;
+	int i, ret;
+
+	if (argc < 2) {
+		printf("Invalid PASSPHRASE command: needs two arguments "
+		       "(network id and passphrase)\n");
+		return -1;
+	}
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
+			  argv[0], argv[1]);
+	if (ret < 0 || ret >= end - pos) {
+		printf("Too long PASSPHRASE command.\n");
+		return -1;
+	}
+	pos += ret;
+	for (i = 2; i < argc; i++) {
+		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+		if (ret < 0 || ret >= end - pos) {
+			printf("Too long PASSPHRASE command.\n");
+			return -1;
+		}
+		pos += ret;
+	}
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc < 2) {
+		printf("Invalid BSSID command: needs two arguments (network "
+		       "id and BSSID)\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+}
+
+
+static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "ADD_NETWORK");
+}
+
+
+static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
+}
+
+
+static void wpa_cli_show_network_variables(void)
+{
+	printf("set_network variables:\n"
+	       "  ssid (network name, SSID)\n"
+	       "  psk (WPA passphrase or pre-shared key)\n"
+	       "  key_mgmt (key management protocol)\n"
+	       "  identity (EAP identity)\n"
+	       "  password (EAP password)\n"
+	       "  ...\n"
+	       "\n"
+	       "Note: Values are entered in the same format as the "
+	       "configuration file is using,\n"
+	       "i.e., strings values need to be inside double quotation "
+	       "marks.\n"
+	       "For example: set_network 1 ssid \"network name\"\n"
+	       "\n"
+	       "Please see wpa_supplicant.conf documentation for full list "
+	       "of\navailable variables.\n");
+}
+
+
+static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	if (argc == 0) {
+		wpa_cli_show_network_variables();
+		return 0;
+	}
+
+	if (argc < 3) {
+		printf("Invalid SET_NETWORK command: needs three arguments\n"
+		       "(network id, variable name, and value)\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	if (argc == 0) {
+		wpa_cli_show_network_variables();
+		return 0;
+	}
+
+	if (argc != 2) {
+		printf("Invalid GET_NETWORK command: needs two arguments\n"
+		       "(network id and variable name)\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "LIST_CREDS");
+}
+
+
+static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "ADD_CRED");
+}
+
+
+static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc != 3) {
+		printf("Invalid SET_CRED command: needs three arguments\n"
+		       "(cred id, variable name, and value)\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DISCONNECT");
+}
+
+
+static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RECONNECT");
+}
+
+
+static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
+}
+
+
+static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "SCAN");
+}
+
+
+static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
+}
+
+
+static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_bss(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(&bsses);
+		break;
+	}
+
+	return res;
+}
+
+
+static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	if (argc < 1 || argc > 2) {
+		printf("Invalid GET_CAPABILITY command: need either one or "
+		       "two arguments\n");
+		return -1;
+	}
+
+	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
+		printf("Invalid GET_CAPABILITY command: second argument, "
+		       "if any, must be 'strict'\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
+}
+
+
+static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
+{
+	printf("Available interfaces:\n");
+	return wpa_ctrl_command(ctrl, "INTERFACES");
+}
+
+
+static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc < 1) {
+		wpa_cli_list_interfaces(ctrl);
+		return 0;
+	}
+
+	wpa_cli_close_connection();
+	os_free(ctrl_ifname);
+	ctrl_ifname = os_strdup(argv[0]);
+
+	if (wpa_cli_open_connection(ctrl_ifname, 1)) {
+		printf("Connected to interface '%s.\n", ctrl_ifname);
+	} else {
+		printf("Could not connect to interface '%s' - re-trying\n",
+		       ctrl_ifname);
+	}
+	return 0;
+}
+
+
+static int wpa_cli_cmd_reconfigure(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RECONFIGURE");
+}
+
+
+static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
+				 char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "TERMINATE");
+}
+
+
+static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc < 1) {
+		printf("Invalid INTERFACE_ADD command: needs at least one "
+		       "argument (interface name)\n"
+		       "All arguments: ifname confname driver ctrl_interface "
+		       "driver_param bridge_name\n");
+		return -1;
+	}
+
+	/*
+	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
+	 * <driver_param>TAB<bridge_name>
+	 */
+	res = os_snprintf(cmd, sizeof(cmd),
+			  "INTERFACE_ADD %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] : "");
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
+}
+
+
+#ifdef CONFIG_AP
+static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
+				char *addr, size_t addr_len)
+{
+	char buf[4096], *pos;
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to hostapd - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+			       wpa_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (os_memcmp(buf, "FAIL", 4) == 0)
+		return -1;
+	printf("%s", buf);
+
+	pos = buf;
+	while (*pos != '\0' && *pos != '\n')
+		pos++;
+	*pos = '\0';
+	os_strlcpy(addr, buf, addr_len);
+	return 0;
+}
+
+
+static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char addr[32], cmd[64];
+
+	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+		return 0;
+	do {
+		os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+	return -1;
+}
+
+
+static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
+}
+#endif /* CONFIG_AP */
+
+
+static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "SUSPEND");
+}
+
+
+static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RESUME");
+}
+
+
+static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DROP_SA");
+}
+
+
+static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
+}
+
+
+#ifdef CONFIG_P2P
+
+static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
+{
+	char **res = NULL;
+	int arg = get_cmd_arg_num(str, pos);
+
+	res = os_calloc(6, sizeof(char *));
+	if (res == NULL)
+		return NULL;
+	res[0] = os_strdup("type=social");
+	if (res[0] == NULL) {
+		os_free(res);
+		return NULL;
+	}
+	res[1] = os_strdup("type=progressive");
+	if (res[1] == NULL)
+		return res;
+	res[2] = os_strdup("delay=");
+	if (res[2] == NULL)
+		return res;
+	res[3] = os_strdup("dev_id=");
+	if (res[3] == NULL)
+		return res;
+	if (arg == 1)
+		res[4] = os_strdup("[timeout]");
+
+	return res;
+}
+
+
+static int wpa_cli_cmd_p2p_stop_find(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_STOP_FIND");
+}
+
+
+static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_p2p_connect(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(&p2p_peers);
+		break;
+	}
+
+	return res;
+}
+
+
+static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_p2p_group_remove(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(&p2p_groups);
+		break;
+	}
+
+	return res;
+}
+
+
+static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	if (argc != 2 && argc != 3) {
+		printf("Invalid P2P_PROV_DISC command: needs at least "
+		       "two arguments, address and config method\n"
+		       "(display, keypad, or pbc) and an optional join\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_get_passphrase(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_GET_PASSPHRASE");
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_req(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	char cmd[4096];
+
+	if (argc != 2 && argc != 4) {
+		printf("Invalid P2P_SERV_DISC_REQ command: needs two "
+		       "arguments (address and TLVs) or four arguments "
+		       "(address, \"upnp\", version, search target "
+		       "(SSDP ST:)\n");
+		return -1;
+	}
+
+	if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
+		return -1;
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
+						int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_resp(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	char cmd[4096];
+	int res;
+
+	if (argc != 4) {
+		printf("Invalid P2P_SERV_DISC_RESP command: needs four "
+		       "arguments (freq, address, dialog token, and TLVs)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
+			  argv[0], argv[1], argv[2], argv[3]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_service_update(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_SERVICE_UPDATE");
+}
+
+
+static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
+					      int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_service_flush(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_SERVICE_FLUSH");
+}
+
+
+static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	char cmd[4096];
+	int res;
+
+	if (argc != 3 && argc != 4) {
+		printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+		       "arguments\n");
+		return -1;
+	}
+
+	if (argc == 4)
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "P2P_SERVICE_ADD %s %s %s %s",
+				  argv[0], argv[1], argv[2], argv[3]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "P2P_SERVICE_ADD %s %s %s",
+				  argv[0], argv[1], argv[2]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_service_del(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	char cmd[4096];
+	int res;
+
+	if (argc != 2 && argc != 3) {
+		printf("Invalid P2P_SERVICE_DEL command: needs two or three "
+		       "arguments\n");
+		return -1;
+	}
+
+	if (argc == 3)
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "P2P_SERVICE_DEL %s %s %s",
+				  argv[0], argv[1], argv[2]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd),
+				  "P2P_SERVICE_DEL %s %s",
+				  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
+				  int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
+				  int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
+}
+
+
+static char ** wpa_cli_complete_p2p_peer(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(&p2p_peers);
+		break;
+	}
+
+	return res;
+}
+
+
+static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
+				     char *addr, size_t addr_len,
+				     int discovered)
+{
+	char buf[4096], *pos;
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL)
+		return -1;
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+			       wpa_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (os_memcmp(buf, "FAIL", 4) == 0)
+		return -1;
+
+	pos = buf;
+	while (*pos != '\0' && *pos != '\n')
+		pos++;
+	*pos++ = '\0';
+	os_strlcpy(addr, buf, addr_len);
+	if (!discovered || os_strstr(pos, "[PROBE_REQ_ONLY]") == NULL)
+		printf("%s\n", addr);
+	return 0;
+}
+
+
+static int wpa_cli_cmd_p2p_peers(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char addr[32], cmd[64];
+	int discovered;
+
+	discovered = argc > 0 && os_strcmp(argv[0], "discovered") == 0;
+
+	if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
+				      addr, sizeof(addr), discovered))
+		return -1;
+	do {
+		os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
+	} while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
+			 discovered) == 0);
+
+	return 0;
+}
+
+
+static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_FLUSH");
+}
+
+
+static int wpa_cli_cmd_p2p_cancel(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "P2P_CANCEL");
+}
+
+
+static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	if (argc != 0 && argc != 2 && argc != 4) {
+		printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
+		       "(preferred duration, interval; in microsecods).\n"
+		       "Optional second pair can be used to provide "
+		       "acceptable values.\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	if (argc != 0 && argc != 2) {
+		printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
+		       "(availability period, availability interval; in "
+		       "millisecods).\n"
+		       "Extended Listen Timing can be cancelled with this "
+		       "command when used without parameters.\n");
+		return -1;
+	}
+
+	return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
+}
+
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	char cmd[100];
+	int res;
+
+	if (argc != 1 && argc != 2) {
+		printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+		       "arguments (subelem, hexdump)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
+			  argv[0], argc > 1 ? argv[1] : "");
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	char cmd[100];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid WFD_SUBELEM_GET command: needs one "
+		       "argument (subelem)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
+			  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
+#ifdef CONFIG_INTERWORKING
+static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+
+static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
+					       char *argv[])
+{
+	char cmd[512];
+
+	if (argc == 0) {
+		printf("Command needs one or two arguments (dst mac addr and "
+		       "optional home realm)\n");
+		return -1;
+	}
+
+	if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
+		      argc, argv) < 0)
+		return -1;
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "SIGNAL_POLL");
+}
+
+
+static int wpa_cli_cmd_pktcnt_poll(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "PKTCNT_POLL");
+}
+
+
+static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc == 0)
+		return wpa_ctrl_command(ctrl, "AUTOSCAN ");
+
+	return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	if (argc == 0)
+		return -1;
+	return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
+enum wpa_cli_cmd_flags {
+	cli_cmd_flag_none		= 0x00,
+	cli_cmd_flag_sensitive		= 0x01
+};
+
+struct wpa_cli_cmd {
+	const char *cmd;
+	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+	char ** (*completion)(const char *str, int pos);
+	enum wpa_cli_cmd_flags flags;
+	const char *usage;
+};
+
+static struct wpa_cli_cmd wpa_cli_commands[] = {
+	{ "status", wpa_cli_cmd_status, NULL,
+	  cli_cmd_flag_none,
+	  "[verbose] = get current WPA/EAPOL/EAP status" },
+	{ "ifname", wpa_cli_cmd_ifname, NULL,
+	  cli_cmd_flag_none,
+	  "= get current interface name" },
+	{ "ping", wpa_cli_cmd_ping, NULL,
+	  cli_cmd_flag_none,
+	  "= pings wpa_supplicant" },
+	{ "relog", wpa_cli_cmd_relog, NULL,
+	  cli_cmd_flag_none,
+	  "= re-open log-file (allow rolling logs)" },
+	{ "note", wpa_cli_cmd_note, NULL,
+	  cli_cmd_flag_none,
+	  "<text> = add a note to wpa_supplicant debug log" },
+	{ "mib", wpa_cli_cmd_mib, NULL,
+	  cli_cmd_flag_none,
+	  "= get MIB variables (dot1x, dot11)" },
+	{ "help", wpa_cli_cmd_help, wpa_cli_complete_help,
+	  cli_cmd_flag_none,
+	  "[command] = show usage help" },
+	{ "interface", wpa_cli_cmd_interface, NULL,
+	  cli_cmd_flag_none,
+	  "[ifname] = show interfaces/select interface" },
+	{ "level", wpa_cli_cmd_level, NULL,
+	  cli_cmd_flag_none,
+	  "<debug level> = change debug level" },
+	{ "license", wpa_cli_cmd_license, NULL,
+	  cli_cmd_flag_none,
+	  "= show full wpa_cli license" },
+	{ "quit", wpa_cli_cmd_quit, NULL,
+	  cli_cmd_flag_none,
+	  "= exit wpa_cli" },
+	{ "set", wpa_cli_cmd_set, NULL,
+	  cli_cmd_flag_none,
+	  "= set variables (shows list of variables when run without "
+	  "arguments)" },
+	{ "get", wpa_cli_cmd_get, NULL,
+	  cli_cmd_flag_none,
+	  "<name> = get information" },
+	{ "logon", wpa_cli_cmd_logon, NULL,
+	  cli_cmd_flag_none,
+	  "= IEEE 802.1X EAPOL state machine logon" },
+	{ "logoff", wpa_cli_cmd_logoff, NULL,
+	  cli_cmd_flag_none,
+	  "= IEEE 802.1X EAPOL state machine logoff" },
+	{ "pmksa", wpa_cli_cmd_pmksa, NULL,
+	  cli_cmd_flag_none,
+	  "= show PMKSA cache" },
+	{ "reassociate", wpa_cli_cmd_reassociate, NULL,
+	  cli_cmd_flag_none,
+	  "= force reassociation" },
+	{ "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<BSSID> = force preauthentication" },
+	{ "identity", wpa_cli_cmd_identity, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> <identity> = configure identity for an SSID" },
+	{ "password", wpa_cli_cmd_password, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = configure password for an SSID" },
+	{ "new_password", wpa_cli_cmd_new_password, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = change password for an SSID" },
+	{ "pin", wpa_cli_cmd_pin, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <pin> = configure pin for an SSID" },
+	{ "otp", wpa_cli_cmd_otp, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = configure one-time-password for an SSID"
+	},
+	{ "passphrase", wpa_cli_cmd_passphrase, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <passphrase> = configure private key passphrase\n"
+	  "  for an SSID" },
+	{ "bssid", wpa_cli_cmd_bssid, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
+	{ "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<BSSID> = add a BSSID to the blacklist\n"
+	  "blacklist clear = clear the blacklist\n"
+	  "blacklist = display the blacklist" },
+	{ "log_level", wpa_cli_cmd_log_level, NULL,
+	  cli_cmd_flag_none,
+	  "<level> [<timestamp>] = update the log level/timestamp\n"
+	  "log_level = display the current log level and log options" },
+	{ "list_networks", wpa_cli_cmd_list_networks, NULL,
+	  cli_cmd_flag_none,
+	  "= list configured networks" },
+	{ "select_network", wpa_cli_cmd_select_network, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> = select a network (disable others)" },
+	{ "enable_network", wpa_cli_cmd_enable_network, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> = enable a network" },
+	{ "disable_network", wpa_cli_cmd_disable_network, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> = disable a network" },
+	{ "add_network", wpa_cli_cmd_add_network, NULL,
+	  cli_cmd_flag_none,
+	  "= add a network" },
+	{ "remove_network", wpa_cli_cmd_remove_network, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> = remove a network" },
+	{ "set_network", wpa_cli_cmd_set_network, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <variable> <value> = set network variables (shows\n"
+	  "  list of variables when run without arguments)" },
+	{ "get_network", wpa_cli_cmd_get_network, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> <variable> = get network variables" },
+	{ "list_creds", wpa_cli_cmd_list_creds, NULL,
+	  cli_cmd_flag_none,
+	  "= list configured credentials" },
+	{ "add_cred", wpa_cli_cmd_add_cred, NULL,
+	  cli_cmd_flag_none,
+	  "= add a credential" },
+	{ "remove_cred", wpa_cli_cmd_remove_cred, NULL,
+	  cli_cmd_flag_none,
+	  "<cred id> = remove a credential" },
+	{ "set_cred", wpa_cli_cmd_set_cred, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<cred id> <variable> <value> = set credential variables" },
+	{ "save_config", wpa_cli_cmd_save_config, NULL,
+	  cli_cmd_flag_none,
+	  "= save the current configuration" },
+	{ "disconnect", wpa_cli_cmd_disconnect, NULL,
+	  cli_cmd_flag_none,
+	  "= disconnect and wait for reassociate/reconnect command before\n"
+	  "  connecting" },
+	{ "reconnect", wpa_cli_cmd_reconnect, NULL,
+	  cli_cmd_flag_none,
+	  "= like reassociate, but only takes effect if already disconnected"
+	},
+	{ "scan", wpa_cli_cmd_scan, NULL,
+	  cli_cmd_flag_none,
+	  "= request new BSS scan" },
+	{ "scan_results", wpa_cli_cmd_scan_results, NULL,
+	  cli_cmd_flag_none,
+	  "= get latest scan results" },
+	{ "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,
+	  "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
+	  "= get capabilies" },
+	{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
+	  cli_cmd_flag_none,
+	  "= force wpa_supplicant to re-read its configuration file" },
+	{ "terminate", wpa_cli_cmd_terminate, NULL,
+	  cli_cmd_flag_none,
+	  "= terminate wpa_supplicant" },
+	{ "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" },
+	{ "interface_remove", wpa_cli_cmd_interface_remove, NULL,
+	  cli_cmd_flag_none,
+	  "<ifname> = removes the interface" },
+	{ "interface_list", wpa_cli_cmd_interface_list, NULL,
+	  cli_cmd_flag_none,
+	  "= list available interfaces" },
+	{ "ap_scan", wpa_cli_cmd_ap_scan, NULL,
+	  cli_cmd_flag_none,
+	  "<value> = set ap_scan parameter" },
+	{ "scan_interval", wpa_cli_cmd_scan_interval, NULL,
+	  cli_cmd_flag_none,
+	  "<value> = set scan_interval parameter (in seconds)" },
+	{ "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
+	  cli_cmd_flag_none,
+	  "<value> = set BSS expiration age parameter" },
+	{ "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
+	  cli_cmd_flag_none,
+	  "<value> = set BSS expiration scan count parameter" },
+	{ "bss_flush", wpa_cli_cmd_bss_flush, NULL,
+	  cli_cmd_flag_none,
+	  "<value> = set BSS flush age (0 by default)" },
+	{ "stkstart", wpa_cli_cmd_stkstart, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = request STK negotiation with <addr>" },
+	{ "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<addr> = request over-the-DS FT with <addr>" },
+	{ "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
+	{ "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
+	  cli_cmd_flag_sensitive,
+	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
+	  "hardcoded)" },
+	{ "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<PIN> = verify PIN checksum" },
+	{ "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
+	  "Cancels the pending WPS operation" },
+#ifdef CONFIG_WPS_NFC
+	{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "[BSSID] = start Wi-Fi Protected Setup: NFC" },
+	{ "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
+	  cli_cmd_flag_none,
+	  "<WPS|NDEF> = create password token" },
+	{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<hexdump of payload> = report read NFC tag with WPS data" },
+	{ "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+	  cli_cmd_flag_none,
+	  "<NDEF> <WPS> = create NFC handover request" },
+	{ "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+	  cli_cmd_flag_none,
+	  "<NDEF> <WPS> = create NFC handover select" },
+	{ "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+	  cli_cmd_flag_none,
+	  "<hexdump of payload> = report received NFC handover request" },
+	{ "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+	  cli_cmd_flag_none,
+	  "<hexdump of payload> = report received NFC handover select" },
+#endif /* CONFIG_WPS_NFC */
+	{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
+	  cli_cmd_flag_sensitive,
+	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
+	{ "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
+	  cli_cmd_flag_sensitive,
+	  "[params..] = enable/disable AP PIN" },
+	{ "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
+	  cli_cmd_flag_none,
+	  "[IP address] = start Wi-Fi Protected Setup External Registrar" },
+	{ "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
+	  cli_cmd_flag_none,
+	  "= stop Wi-Fi Protected Setup External Registrar" },
+	{ "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
+	{ "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
+	  cli_cmd_flag_none,
+	  "<UUID> = accept an Enrollee PBC using External Registrar" },
+	{ "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<UUID> <PIN> = learn AP configuration" },
+	{ "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
+	  cli_cmd_flag_none,
+	  "<UUID> <network id> = set AP configuration for enrolling" },
+	{ "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
+	  cli_cmd_flag_sensitive,
+	  "<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
+#ifdef CONFIG_WPS_NFC
+	{ "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
+	  cli_cmd_flag_none,
+	  "<WPS/NDEF> <UUID> = build NFC configuration token" },
+#endif /* CONFIG_WPS_NFC */
+	{ "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = request RSN authentication with <addr> in IBSS" },
+#ifdef CONFIG_AP
+	{ "sta", wpa_cli_cmd_sta, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = get information about an associated station (AP)" },
+	{ "all_sta", wpa_cli_cmd_all_sta, NULL,
+	  cli_cmd_flag_none,
+	  "= get information about all associated stations (AP)" },
+	{ "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = deauthenticate a station" },
+	{ "disassociate", wpa_cli_cmd_disassociate, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = disassociate a station" },
+#endif /* CONFIG_AP */
+	{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
+	  "= notification of suspend/hibernate" },
+	{ "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
+	  "= notification of resume/thaw" },
+	{ "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
+	  "= drop SA without deauth/disassoc (test command)" },
+	{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<addr> = roam to the specified BSS" },
+#ifdef CONFIG_P2P
+	{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
+	  cli_cmd_flag_none,
+	  "[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
+	{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
+	  "= stop P2P Devices search" },
+	{ "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
+	  cli_cmd_flag_none,
+	  "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
+	{ "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
+	  "[timeout] = listen for P2P Devices for up-to timeout seconds" },
+	{ "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
+	  wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
+	  "<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_prov_disc", wpa_cli_cmd_p2p_prov_disc,
+	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
+	  "<addr> <method> = request provisioning discovery" },
+	{ "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
+	  cli_cmd_flag_none,
+	  "= get the passphrase for a group (GO only)" },
+	{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
+	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
+	  "<addr> <TLVs> = schedule service discovery request" },
+	{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
+	  NULL, cli_cmd_flag_none,
+	  "<id> = cancel pending service discovery request" },
+	{ "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
+	  cli_cmd_flag_none,
+	  "<freq> <addr> <dialog token> <TLVs> = service discovery response" },
+	{ "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
+	  cli_cmd_flag_none,
+	  "= indicate change in local services" },
+	{ "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
+	  cli_cmd_flag_none,
+	  "<external> = set external processing of service discovery" },
+	{ "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
+	  cli_cmd_flag_none,
+	  "= remove all stored service entries" },
+	{ "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
+	  cli_cmd_flag_none,
+	  "<bonjour|upnp> <query|version> <response|service> = add a local "
+	  "service" },
+	{ "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
+	  cli_cmd_flag_none,
+	  "<bonjour|upnp> <query|version> [|service] = remove a local "
+	  "service" },
+	{ "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
+	  cli_cmd_flag_none,
+	  "<addr> = reject connection attempts from a specific peer" },
+	{ "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
+	  cli_cmd_flag_none,
+	  "<cmd> [peer=addr] = invite peer" },
+	{ "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
+	  "[discovered] = list known (optionally, only fully discovered) P2P "
+	  "peers" },
+	{ "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
+	  cli_cmd_flag_none,
+	  "<address> = show information about known P2P peer" },
+	{ "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
+	  "<field> <value> = set a P2P parameter" },
+	{ "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
+	  "= flush P2P state" },
+	{ "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
+	  "= cancel P2P group formation" },
+	{ "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
+	  wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
+	  "<address> = unauthorize a peer" },
+	{ "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
+	  cli_cmd_flag_none,
+	  "[<duration> <interval>] [<duration> <interval>] = request GO "
+	  "presence" },
+	{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
+	  cli_cmd_flag_none,
+	  "[<period> <interval>] = set extended listen timing" },
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+	{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
+	  cli_cmd_flag_none,
+	  "<subelem> [contents] = set Wi-Fi Display subelement" },
+	{ "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
+	  cli_cmd_flag_none,
+	  "<subelem> = get Wi-Fi Display subelement" },
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_INTERWORKING
+	{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
+	  "= fetch ANQP information for all APs" },
+	{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
+	  cli_cmd_flag_none,
+	  "= stop fetch_anqp operation" },
+	{ "interworking_select", wpa_cli_cmd_interworking_select, NULL,
+	  cli_cmd_flag_none,
+	  "[auto] = perform Interworking network selection" },
+	{ "interworking_connect", wpa_cli_cmd_interworking_connect,
+	  wpa_cli_complete_bss, cli_cmd_flag_none,
+	  "<BSSID> = connect using Interworking credentials" },
+	{ "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<addr> <info id>[,<info id>]... = request ANQP information" },
+	{ "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<addr> <AdvProtoID> [QueryReq] = GAS request" },
+	{ "gas_response_get", wpa_cli_cmd_gas_response_get,
+	  wpa_cli_complete_bss, cli_cmd_flag_none,
+	  "<addr> <dialog token> [start,len] = Fetch last GAS response" },
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	{ "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
+	  cli_cmd_flag_none,
+	  "<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
+	},
+	{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
+	  wpa_cli_complete_bss, cli_cmd_flag_none,
+	  "<addr> <home realm> = get HS20 nai home realm list" },
+#endif /* CONFIG_HS20 */
+	{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
+	  cli_cmd_flag_none,
+	  "<0/1> = disable/enable automatic reconnection" },
+	{ "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = request TDLS discovery with <addr>" },
+	{ "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = request TDLS setup with <addr>" },
+	{ "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = tear down TDLS with <addr>" },
+	{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
+	  cli_cmd_flag_none,
+	  "= get signal parameters" },
+	{ "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
+	  cli_cmd_flag_none,
+	  "= get TX/RX packet counters" },
+	{ "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
+	  cli_cmd_flag_none,
+	  "= trigger IEEE 802.1X/EAPOL reauthentication" },
+#ifdef CONFIG_AUTOSCAN
+	{ "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
+	  "[params] = Set or unset (if none) autoscan parameters" },
+#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_WNM
+	{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
+	  "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
+#endif /* CONFIG_WNM */
+	{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
+	  "<params..> = Sent unprocessed command" },
+	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
+};
+
+
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
+{
+	char c;
+	size_t n;
+
+	printf("%s%s ", pad, cmd->cmd);
+	for (n = 0; (c = cmd->usage[n]); n++) {
+		printf("%c", c);
+		if (c == '\n')
+			printf("%s", pad);
+	}
+	printf("\n");
+}
+
+
+static void print_help(const char *cmd)
+{
+	int n;
+	printf("commands:\n");
+	for (n = 0; wpa_cli_commands[n].cmd; n++) {
+		if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
+			print_cmd_help(&wpa_cli_commands[n], "  ");
+	}
+}
+
+
+static int wpa_cli_edit_filter_history_cb(void *ctx, const char *cmd)
+{
+	const char *c, *delim;
+	int n;
+	size_t len;
+
+	delim = os_strchr(cmd, ' ');
+	if (delim)
+		len = delim - cmd;
+	else
+		len = os_strlen(cmd);
+
+	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
+		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
+			return (wpa_cli_commands[n].flags &
+				cli_cmd_flag_sensitive);
+	}
+	return 0;
+}
+
+
+static char ** wpa_list_cmd_list(void)
+{
+	char **res;
+	int i, count;
+
+	count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+	res = os_calloc(count, sizeof(char *));
+	if (res == NULL)
+		return NULL;
+
+	for (i = 0; wpa_cli_commands[i].cmd; i++) {
+		res[i] = os_strdup(wpa_cli_commands[i].cmd);
+		if (res[i] == NULL)
+			break;
+	}
+
+	return res;
+}
+
+
+static char ** wpa_cli_cmd_completion(const char *cmd, const char *str,
+				      int pos)
+{
+	int i;
+
+	for (i = 0; wpa_cli_commands[i].cmd; i++) {
+		if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+			if (wpa_cli_commands[i].completion)
+				return wpa_cli_commands[i].completion(str,
+								      pos);
+			edit_clear_line();
+			printf("\r%s\n", wpa_cli_commands[i].usage);
+			edit_redraw();
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+
+static char ** wpa_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 wpa_list_cmd_list();
+
+	cmd = os_malloc(pos + 1);
+	if (cmd == NULL)
+		return NULL;
+	os_memcpy(cmd, str, pos);
+	cmd[end - str] = '\0';
+	res = wpa_cli_cmd_completion(cmd, str, pos);
+	os_free(cmd);
+	return res;
+}
+
+
+static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	struct wpa_cli_cmd *cmd, *match = NULL;
+	int count;
+	int ret = 0;
+
+	count = 0;
+	cmd = wpa_cli_commands;
+	while (cmd->cmd) {
+		if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
+		{
+			match = cmd;
+			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
+				/* we have an exact match */
+				count = 1;
+				break;
+			}
+			count++;
+		}
+		cmd++;
+	}
+
+	if (count > 1) {
+		printf("Ambiguous command '%s'; possible commands:", argv[0]);
+		cmd = wpa_cli_commands;
+		while (cmd->cmd) {
+			if (os_strncasecmp(cmd->cmd, argv[0],
+					   os_strlen(argv[0])) == 0) {
+				printf(" %s", cmd->cmd);
+			}
+			cmd++;
+		}
+		printf("\n");
+		ret = 1;
+	} else if (count == 0) {
+		printf("Unknown command '%s'\n", argv[0]);
+		ret = 1;
+	} else {
+		ret = match->handler(ctrl, argc - 1, &argv[1]);
+	}
+
+	return ret;
+}
+
+
+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)
+{
+	char *cmd;
+	size_t len;
+	int res;
+	int ret = 0;
+
+	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
+	cmd = os_malloc(len);
+	if (cmd == NULL)
+		return -1;
+	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+	if (res < 0 || (size_t) res >= len) {
+		os_free(cmd);
+		return -1;
+	}
+	cmd[len - 1] = '\0';
+#ifndef _WIN32_WCE
+	if (system(cmd) < 0)
+		ret = -1;
+#endif /* _WIN32_WCE */
+	os_free(cmd);
+
+	return ret;
+}
+
+
+static void wpa_cli_action_process(const char *msg)
+{
+	const char *pos;
+	char *copy = NULL, *id, *pos2;
+
+	pos = msg;
+	if (*pos == '<') {
+		/* skip priority */
+		pos = os_strchr(pos, '>');
+		if (pos)
+			pos++;
+		else
+			pos = msg;
+	}
+
+	if (str_match(pos, WPA_EVENT_CONNECTED)) {
+		int new_id = -1;
+		os_unsetenv("WPA_ID");
+		os_unsetenv("WPA_ID_STR");
+		os_unsetenv("WPA_CTRL_DIR");
+
+		pos = os_strstr(pos, "[id=");
+		if (pos)
+			copy = os_strdup(pos + 4);
+
+		if (copy) {
+			pos2 = id = copy;
+			while (*pos2 && *pos2 != ' ')
+				pos2++;
+			*pos2++ = '\0';
+			new_id = atoi(id);
+			os_setenv("WPA_ID", id, 1);
+			while (*pos2 && *pos2 != '=')
+				pos2++;
+			if (*pos2 == '=')
+				pos2++;
+			id = pos2;
+			while (*pos2 && *pos2 != ']')
+				pos2++;
+			*pos2 = '\0';
+			os_setenv("WPA_ID_STR", id, 1);
+			os_free(copy);
+		}
+
+		os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
+
+		if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
+			wpa_cli_connected = 1;
+			wpa_cli_last_id = new_id;
+			wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+		}
+	} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+		if (wpa_cli_connected) {
+			wpa_cli_connected = 0;
+			wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
+		}
+	} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, WPS_EVENT_FAIL)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, AP_STA_CONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+		printf("wpa_supplicant is terminating - stop monitoring\n");
+		wpa_cli_quit = 1;
+	}
+}
+
+
+#ifndef CONFIG_ANSI_C_EXTRA
+static void wpa_cli_action_cb(char *msg, size_t len)
+{
+	wpa_cli_action_process(msg);
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+static void wpa_cli_reconnect(void)
+{
+	wpa_cli_close_connection();
+	if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+		return;
+
+	if (interactive) {
+		edit_clear_line();
+		printf("\rConnection to wpa_supplicant re-established\n");
+		edit_redraw();
+	}
+}
+
+
+static void cli_event(const char *str)
+{
+	const char *start, *s;
+
+	start = os_strchr(str, '>');
+	if (start == NULL)
+		return;
+
+	start++;
+
+	if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		s = os_strchr(s + 1, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_add(&bsses, s + 1);
+		return;
+	}
+
+	if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		s = os_strchr(s + 1, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_del_addr(&bsses, s + 1);
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
+		s = os_strstr(start, " p2p_dev_addr=");
+		if (s == NULL)
+			return;
+		cli_txt_list_add_addr(&p2p_peers, s + 14);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
+		s = os_strstr(start, " p2p_dev_addr=");
+		if (s == NULL)
+			return;
+		cli_txt_list_del_addr(&p2p_peers, s + 14);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_add_word(&p2p_groups, s + 1);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_del_word(&p2p_groups, s + 1);
+		return;
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+static int check_terminating(const char *msg)
+{
+	const char *pos = msg;
+
+	if (*pos == '<') {
+		/* skip priority */
+		pos = os_strchr(pos, '>');
+		if (pos)
+			pos++;
+		else
+			pos = msg;
+	}
+
+	if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+		edit_clear_line();
+		printf("\rConnection to wpa_supplicant lost - trying to "
+		       "reconnect\n");
+		edit_redraw();
+		wpa_cli_attached = 0;
+		wpa_cli_close_connection();
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
+{
+	if (ctrl_conn == NULL) {
+		wpa_cli_reconnect();
+		return;
+	}
+	while (wpa_ctrl_pending(ctrl) > 0) {
+		char buf[256];
+		size_t len = sizeof(buf) - 1;
+		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
+			buf[len] = '\0';
+			if (action_monitor)
+				wpa_cli_action_process(buf);
+			else {
+				cli_event(buf);
+				if (wpa_cli_show_event(buf)) {
+					edit_clear_line();
+					printf("\r%s\n", buf);
+					edit_redraw();
+				}
+
+				if (interactive && check_terminating(buf) > 0)
+					return;
+			}
+		} else {
+			printf("Could not read pending message.\n");
+			break;
+		}
+	}
+
+	if (wpa_ctrl_pending(ctrl) < 0) {
+		printf("Connection to wpa_supplicant lost - trying to "
+		       "reconnect\n");
+		wpa_cli_reconnect();
+	}
+}
+
+#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)
+{
+	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
+		printf("Connection to wpa_supplicant lost - trying to "
+		       "reconnect\n");
+		wpa_cli_close_connection();
+	}
+	if (!ctrl_conn)
+		wpa_cli_reconnect();
+	eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+}
+
+
+static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	wpa_cli_recv_pending(mon_conn, 0);
+}
+
+
+static void wpa_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+	char *argv[max_args];
+	int argc;
+	argc = tokenize_cmd(cmd, argv);
+	if (argc)
+		wpa_request(ctrl_conn, argc, argv);
+}
+
+
+static void wpa_cli_edit_eof_cb(void *ctx)
+{
+	eloop_terminate();
+}
+
+
+static int warning_displayed = 0;
+static char *hfile = NULL;
+static int edit_started = 0;
+
+static void start_edit(void)
+{
+	char *home;
+	char *ps = NULL;
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	home = getenv("HOME");
+	if (home) {
+		const char *fname = ".wpa_cli_history";
+		int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+		hfile = os_malloc(hfile_len);
+		if (hfile)
+			os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
+	}
+
+	if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
+		      wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
+		eloop_terminate();
+		return;
+	}
+
+	edit_started = 1;
+	eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+}
+
+
+static void try_connection(void *eloop_ctx, void *timeout_ctx)
+{
+	if (ctrl_ifname == NULL)
+		ctrl_ifname = wpa_cli_get_default_ifname();
+
+	if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+		if (!warning_displayed) {
+			printf("Could not connect to wpa_supplicant: "
+			       "%s - re-trying\n", ctrl_ifname);
+			warning_displayed = 1;
+		}
+		eloop_register_timeout(1, 0, try_connection, NULL, NULL);
+		return;
+	}
+
+	if (warning_displayed)
+		printf("Connection established.\n");
+
+	start_edit();
+}
+
+
+static void wpa_cli_interactive(void)
+{
+	printf("\nInteractive mode\n\n");
+
+	eloop_register_timeout(0, 0, try_connection, NULL, NULL);
+	eloop_run();
+	eloop_cancel_timeout(try_connection, NULL, NULL);
+
+	cli_txt_list_flush(&p2p_peers);
+	cli_txt_list_flush(&p2p_groups);
+	cli_txt_list_flush(&bsses);
+	if (edit_started)
+		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
+	os_free(hfile);
+	eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
+	wpa_cli_close_connection();
+}
+
+
+static void wpa_cli_action(struct wpa_ctrl *ctrl)
+{
+#ifdef CONFIG_ANSI_C_EXTRA
+	/* TODO: ANSI C version(?) */
+	printf("Action processing not supported in ANSI C build.\n");
+#else /* CONFIG_ANSI_C_EXTRA */
+	fd_set rfds;
+	int fd, res;
+	struct timeval tv;
+	char buf[256]; /* note: large enough to fit in unsolicited messages */
+	size_t len;
+
+	fd = wpa_ctrl_get_fd(ctrl);
+
+	while (!wpa_cli_quit) {
+		FD_ZERO(&rfds);
+		FD_SET(fd, &rfds);
+		tv.tv_sec = ping_interval;
+		tv.tv_usec = 0;
+		res = select(fd + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0 && errno != EINTR) {
+			perror("select");
+			break;
+		}
+
+		if (FD_ISSET(fd, &rfds))
+			wpa_cli_recv_pending(ctrl, 1);
+		else {
+			/* verify that connection is still working */
+			len = sizeof(buf) - 1;
+			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+					     wpa_cli_action_cb) < 0 ||
+			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+				printf("wpa_supplicant did not reply to PING "
+				       "command - exiting\n");
+				break;
+			}
+		}
+	}
+#endif /* CONFIG_ANSI_C_EXTRA */
+}
+
+
+static void wpa_cli_cleanup(void)
+{
+	wpa_cli_close_connection();
+	if (pid_file)
+		os_daemonize_terminate(pid_file);
+
+	os_program_deinit();
+}
+
+
+static void wpa_cli_terminate(int sig, void *ctx)
+{
+	eloop_terminate();
+}
+
+
+static char * wpa_cli_get_default_ifname(void)
+{
+	char *ifname = NULL;
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+	struct dirent *dent;
+	DIR *dir = opendir(ctrl_iface_dir);
+	if (!dir) {
+#ifdef ANDROID
+		char ifprop[PROPERTY_VALUE_MAX];
+		if (property_get("wifi.interface", ifprop, NULL) != 0) {
+			ifname = os_strdup(ifprop);
+			printf("Using interface '%s'\n", ifname);
+			return ifname;
+		}
+#endif /* ANDROID */
+		return NULL;
+	}
+	while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		/*
+		 * Skip the file if it is not a socket. Also accept
+		 * DT_UNKNOWN (0) in case the C library or underlying
+		 * file system does not support d_type.
+		 */
+		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+			continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+		if (os_strcmp(dent->d_name, ".") == 0 ||
+		    os_strcmp(dent->d_name, "..") == 0)
+			continue;
+		printf("Selected interface '%s'\n", dent->d_name);
+		ifname = os_strdup(dent->d_name);
+		break;
+	}
+	closedir(dir);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	char buf[2048], *pos;
+	size_t len;
+	struct wpa_ctrl *ctrl;
+	int ret;
+
+	ctrl = wpa_ctrl_open(NULL);
+	if (ctrl == NULL)
+		return NULL;
+
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
+	if (ret >= 0) {
+		buf[len] = '\0';
+		pos = os_strchr(buf, '\n');
+		if (pos)
+			*pos = '\0';
+		ifname = os_strdup(buf);
+	}
+	wpa_ctrl_close(ctrl);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+	return ifname;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c;
+	int daemonize = 0;
+	int ret = 0;
+	const char *global = NULL;
+
+	if (os_program_init())
+		return -1;
+
+	for (;;) {
+		c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'a':
+			action_file = optarg;
+			break;
+		case 'B':
+			daemonize = 1;
+			break;
+		case 'g':
+			global = optarg;
+			break;
+		case 'G':
+			ping_interval = atoi(optarg);
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'v':
+			printf("%s\n", wpa_cli_version);
+			return 0;
+		case 'i':
+			os_free(ctrl_ifname);
+			ctrl_ifname = os_strdup(optarg);
+			break;
+		case 'p':
+			ctrl_iface_dir = optarg;
+			break;
+		case 'P':
+			pid_file = optarg;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	interactive = (argc == optind) && (action_file == NULL);
+
+	if (interactive)
+		printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+
+	if (eloop_init())
+		return -1;
+
+	if (global) {
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+		ctrl_conn = wpa_ctrl_open(NULL);
+#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+		ctrl_conn = wpa_ctrl_open(global);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+		if (ctrl_conn == NULL) {
+			fprintf(stderr, "Failed to connect to wpa_supplicant "
+				"global interface: %s  error: %s\n",
+				global, strerror(errno));
+			return -1;
+		}
+	}
+
+	eloop_register_signal_terminate(wpa_cli_terminate, NULL);
+
+	if (ctrl_ifname == NULL)
+		ctrl_ifname = wpa_cli_get_default_ifname();
+
+	if (interactive) {
+		wpa_cli_interactive();
+	} else {
+		if (!global &&
+		    wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
+			fprintf(stderr, "Failed to connect to non-global "
+				"ctrl_ifname: %s  error: %s\n",
+				ctrl_ifname, strerror(errno));
+			return -1;
+		}
+
+		if (action_file) {
+			if (wpa_ctrl_attach(ctrl_conn) == 0) {
+				wpa_cli_attached = 1;
+			} else {
+				printf("Warning: Failed to attach to "
+				       "wpa_supplicant.\n");
+				return -1;
+			}
+		}
+
+		if (daemonize && os_daemonize(pid_file))
+			return -1;
+
+		if (action_file)
+			wpa_cli_action(ctrl_conn);
+		else
+			ret = wpa_request(ctrl_conn, argc - optind,
+					  &argv[optind]);
+	}
+
+	os_free(ctrl_ifname);
+	eloop_destroy();
+	wpa_cli_cleanup();
+
+	return ret;
+}
+
+#else /* CONFIG_CTRL_IFACE */
+int main(int argc, char *argv[])
+{
+	printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
+	return -1;
+}
+#endif /* CONFIG_CTRL_IFACE */

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_passphrase.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,73 +0,0 @@
-/*
- * WPA Supplicant - ASCII passphrase to WPA PSK tool
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "crypto/sha1.h"
-
-
-int main(int argc, char *argv[])
-{
-	unsigned char psk[32];
-	int i;
-	char *ssid, *passphrase, buf[64], *pos;
-
-	if (argc < 2) {
-		printf("usage: wpa_passphrase <ssid> [passphrase]\n"
-			"\nIf passphrase is left out, it will be read from "
-			"stdin\n");
-		return 1;
-	}
-
-	ssid = argv[1];
-
-	if (argc > 2) {
-		passphrase = argv[2];
-	} else {
-		printf("# reading passphrase from stdin\n");
-		if (fgets(buf, sizeof(buf), stdin) == NULL) {
-			printf("Failed to read passphrase\n");
-			return 1;
-		}
-		buf[sizeof(buf) - 1] = '\0';
-		pos = buf;
-		while (*pos != '\0') {
-			if (*pos == '\r' || *pos == '\n') {
-				*pos = '\0';
-				break;
-			}
-			pos++;
-		}
-		passphrase = buf;
-	}
-
-	if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
-		printf("Passphrase must be 8..63 characters\n");
-		return 1;
-	}
-
-	pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
-
-	printf("network={\n");
-	printf("\tssid=\"%s\"\n", ssid);
-	printf("\t#psk=\"%s\"\n", passphrase);
-	printf("\tpsk=");
-	for (i = 0; i < 32; i++)
-		printf("%02x", psk[i]);
-	printf("\n");
-	printf("}\n");
-
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_passphrase.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_passphrase.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,67 @@
+/*
+ * WPA Supplicant - ASCII passphrase to WPA PSK tool
+ * Copyright (c) 2003-2005, Jouni Malinen <j at 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"
+
+
+int main(int argc, char *argv[])
+{
+	unsigned char psk[32];
+	int i;
+	char *ssid, *passphrase, buf[64], *pos;
+
+	if (argc < 2) {
+		printf("usage: wpa_passphrase <ssid> [passphrase]\n"
+			"\nIf passphrase is left out, it will be read from "
+			"stdin\n");
+		return 1;
+	}
+
+	ssid = argv[1];
+
+	if (argc > 2) {
+		passphrase = argv[2];
+	} else {
+		printf("# reading passphrase from stdin\n");
+		if (fgets(buf, sizeof(buf), stdin) == NULL) {
+			printf("Failed to read passphrase\n");
+			return 1;
+		}
+		buf[sizeof(buf) - 1] = '\0';
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\r' || *pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		passphrase = buf;
+	}
+
+	if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
+		printf("Passphrase must be 8..63 characters\n");
+		return 1;
+	}
+
+	pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
+
+	printf("network={\n");
+	printf("\tssid=\"%s\"\n", ssid);
+	printf("\t#psk=\"%s\"\n", passphrase);
+	printf("\tpsk=");
+	for (i = 0; i < 32; i++)
+		printf("%02x", psk[i]);
+	printf("\n");
+	printf("}\n");
+
+	return 0;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_priv.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_priv.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_priv.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1040 +0,0 @@
-/*
- * WPA Supplicant / privileged helper program
- * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#ifdef __linux__
-#include <fcntl.h>
-#endif /* __linux__ */
-#include <sys/un.h>
-#include <sys/stat.h>
-
-#include "common.h"
-#include "eloop.h"
-#include "common/version.h"
-#include "drivers/driver.h"
-#include "l2_packet/l2_packet.h"
-#include "common/privsep_commands.h"
-#include "common/ieee802_11_defs.h"
-
-
-struct wpa_priv_interface {
-	struct wpa_priv_interface *next;
-	char *driver_name;
-	char *ifname;
-	char *sock_name;
-	int fd;
-
-	struct wpa_driver_ops *driver;
-	void *drv_priv;
-	struct sockaddr_un drv_addr;
-	int wpas_registered;
-
-	/* TODO: add support for multiple l2 connections */
-	struct l2_packet_data *l2;
-	struct sockaddr_un l2_addr;
-};
-
-
-static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
-{
-	if (iface->drv_priv) {
-		wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
-		if (iface->driver->deinit)
-			iface->driver->deinit(iface->drv_priv);
-		iface->drv_priv = NULL;
-		iface->wpas_registered = 0;
-	}
-
-	if (iface->l2) {
-		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
-			   "instance");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
-	}
-
-	if (iface->driver->init == NULL)
-		return;
-
-	iface->drv_priv = iface->driver->init(iface, iface->ifname);
-	if (iface->drv_priv == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
-		   "'%s'", iface->driver_name, iface->ifname);
-
-	os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
-	iface->wpas_registered = 1;
-
-	if (iface->driver->set_param &&
-	    iface->driver->set_param(iface->drv_priv, NULL) < 0) {
-		wpa_printf(MSG_ERROR, "Driver interface rejected param");
-	}
-}
-
-
-static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface,
-				    struct sockaddr_un *from)
-{
-	if (iface->drv_priv) {
-		if (iface->driver->deinit)
-			iface->driver->deinit(iface->drv_priv);
-		iface->drv_priv = NULL;
-		iface->wpas_registered = 0;
-	}
-}
-
-
-static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
-			      char *buf, size_t len)
-{
-	struct wpa_driver_scan_params params;
-
-	if (iface->drv_priv == NULL)
-		return;
-
-	os_memset(&params, 0, sizeof(params));
-	if (len) {
-		params.ssids[0].ssid = (u8 *) buf;
-		params.ssids[0].ssid_len = len;
-		params.num_ssids = 1;
-	}
-
-	if (iface->driver->scan2)
-		iface->driver->scan2(iface->drv_priv, &params);
-}
-
-
-static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
-				       struct sockaddr_un *from)
-{
-	struct wpa_scan_results *res;
-	u8 *buf = NULL, *pos, *end;
-	int val;
-	size_t i;
-
-	res = iface->driver->get_scan_results2(iface->drv_priv);
-	if (res == NULL)
-		goto fail;
-
-	buf = os_malloc(60000);
-	if (buf == NULL)
-		goto fail;
-	pos = buf;
-	end = buf + 60000;
-	val = res->num;
-	os_memcpy(pos, &val, sizeof(int));
-	pos += sizeof(int);
-
-	for (i = 0; i < res->num; i++) {
-		struct wpa_scan_res *r = res->res[i];
-		val = sizeof(*r) + r->ie_len;
-		if (end - pos < (int) sizeof(int) + val)
-			break;
-		os_memcpy(pos, &val, sizeof(int));
-		pos += sizeof(int);
-		os_memcpy(pos, r, val);
-		pos += val;
-	}
-
-	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
-	       sizeof(*from));
-
-	os_free(buf);
-	wpa_scan_results_free(res);
-	return;
-
-fail:
-	os_free(buf);
-	wpa_scan_results_free(res);
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
-}
-
-
-static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
-					  struct sockaddr_un *from)
-{
-	if (iface->drv_priv == NULL)
-		return;
-
-	if (iface->driver->get_scan_results2)
-		wpa_priv_get_scan_results2(iface, from);
-	else
-		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
-		       sizeof(*from));
-}
-
-
-static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
-				   void *buf, size_t len)
-{
-	struct wpa_driver_associate_params params;
-	struct privsep_cmd_associate *assoc;
-	u8 *bssid;
-	int res;
-
-	if (iface->drv_priv == NULL || iface->driver->associate == NULL)
-		return;
-
-	if (len < sizeof(*assoc)) {
-		wpa_printf(MSG_DEBUG, "Invalid association request");
-		return;
-	}
-
-	assoc = buf;
-	if (sizeof(*assoc) + assoc->wpa_ie_len > len) {
-		wpa_printf(MSG_DEBUG, "Association request overflow");
-		return;
-	}
-
-	os_memset(&params, 0, sizeof(params));
-	bssid = assoc->bssid;
-	if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])
-		params.bssid = bssid;
-	params.ssid = assoc->ssid;
-	if (assoc->ssid_len > 32)
-		return;
-	params.ssid_len = assoc->ssid_len;
-	params.freq = assoc->freq;
-	if (assoc->wpa_ie_len) {
-		params.wpa_ie = (u8 *) (assoc + 1);
-		params.wpa_ie_len = assoc->wpa_ie_len;
-	}
-	params.pairwise_suite = assoc->pairwise_suite;
-	params.group_suite = assoc->group_suite;
-	params.key_mgmt_suite = assoc->key_mgmt_suite;
-	params.auth_alg = assoc->auth_alg;
-	params.mode = assoc->mode;
-
-	res = iface->driver->associate(iface->drv_priv, &params);
-	wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res);
-}
-
-
-static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
-				   struct sockaddr_un *from)
-{
-	u8 bssid[ETH_ALEN];
-
-	if (iface->drv_priv == NULL)
-		goto fail;
-
-	if (iface->driver->get_bssid == NULL ||
-	    iface->driver->get_bssid(iface->drv_priv, bssid) < 0)
-		goto fail;
-
-	sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
-	       sizeof(*from));
-	return;
-
-fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
-}
-
-
-static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
-{
-	u8 ssid[sizeof(int) + 32];
-	int res;
-
-	if (iface->drv_priv == NULL)
-		goto fail;
-
-	if (iface->driver->get_ssid == NULL)
-		goto fail;
-
-	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
-	if (res < 0 || res > 32)
-		goto fail;
-	os_memcpy(ssid, &res, sizeof(int));
-
-	sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
-	       sizeof(*from));
-	return;
-
-fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
-}
-
-
-static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
-				 void *buf, size_t len)
-{
-	struct privsep_cmd_set_key *params;
-	int res;
-
-	if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
-		return;
-
-	if (len != sizeof(*params)) {
-		wpa_printf(MSG_DEBUG, "Invalid set_key request");
-		return;
-	}
-
-	params = buf;
-
-	res = iface->driver->set_key(iface->ifname, iface->drv_priv,
-				     params->alg,
-				     params->addr, params->key_idx,
-				     params->set_tx,
-				     params->seq_len ? params->seq : NULL,
-				     params->seq_len,
-				     params->key_len ? params->key : NULL,
-				     params->key_len);
-	wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
-}
-
-
-static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
-				  struct sockaddr_un *from)
-{
-	struct wpa_driver_capa capa;
-
-	if (iface->drv_priv == NULL)
-		goto fail;
-
-	if (iface->driver->get_capa == NULL ||
-	    iface->driver->get_capa(iface->drv_priv, &capa) < 0)
-		goto fail;
-
-	sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
-	       sizeof(*from));
-	return;
-
-fail:
-	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
-}
-
-
-static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
-			   size_t len)
-{
-	struct wpa_priv_interface *iface = ctx;
-	struct msghdr msg;
-	struct iovec io[2];
-
-	io[0].iov_base = (u8 *) src_addr;
-	io[0].iov_len = ETH_ALEN;
-	io[1].iov_base = (u8 *) buf;
-	io[1].iov_len = len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
-	msg.msg_name = &iface->l2_addr;
-	msg.msg_namelen = sizeof(iface->l2_addr);
-
-	if (sendmsg(iface->fd, &msg, 0) < 0) {
-		perror("sendmsg(l2 rx)");
-	}
-}
-
-
-static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
-				     struct sockaddr_un *from,
-				     void *buf, size_t len)
-{
-	int *reg_cmd = buf;
-	u8 own_addr[ETH_ALEN];
-	int res;
-	u16 proto;
-
-	if (len != 2 * sizeof(int)) {
-		wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
-			   (unsigned long) len);
-		return;
-	}
-
-	proto = reg_cmd[0];
-	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
-		wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
-			   "ethertype 0x%x", proto);
-		return;
-	}
-
-	if (iface->l2) {
-		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
-			   "instance");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
-	}
-
-	os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
-
-	iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
-				   wpa_priv_l2_rx, iface, reg_cmd[1]);
-	if (iface->l2 == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
-			   "instance for protocol %d", proto);
-		return;
-	}
-
-	if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
-		wpa_printf(MSG_DEBUG, "Failed to get own address from "
-			   "l2_packet");
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
-		return;
-	}
-
-	res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
-		     (struct sockaddr *) from, sizeof(*from));
-	wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
-}
-
-
-static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
-				       struct sockaddr_un *from)
-{
-	if (iface->l2) {
-		l2_packet_deinit(iface->l2);
-		iface->l2 = NULL;
-	}
-}
-
-
-static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
-					      struct sockaddr_un *from)
-{
-	if (iface->l2)
-		l2_packet_notify_auth_start(iface->l2);
-}
-
-
-static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
-				 struct sockaddr_un *from,
-				 void *buf, size_t len)
-{
-	u8 *dst_addr;
-	u16 proto;
-	int res;
-
-	if (iface->l2 == NULL)
-		return;
-
-	if (len < ETH_ALEN + 2) {
-		wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)",
-			   (unsigned long) len);
-		return;
-	}
-
-	dst_addr = buf;
-	os_memcpy(&proto, buf + ETH_ALEN, 2);
-
-	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
-		wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
-			   "0x%x", proto);
-		return;
-	}
-
-	res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
-			     len - ETH_ALEN - 2);
-	wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
-}
-
-
-static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface,
-				     char *buf)
-{
-	if (iface->drv_priv == NULL || iface->driver->set_country == NULL ||
-	    *buf == '\0')
-		return;
-
-	iface->driver->set_country(iface->drv_priv, buf);
-}
-
-
-static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_priv_interface *iface = eloop_ctx;
-	char buf[2000], *pos;
-	void *cmd_buf;
-	size_t cmd_len;
-	int res, cmd;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-
-	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
-		       &fromlen);
-	if (res < 0) {
-		perror("recvfrom");
-		return;
-	}
-
-	if (res < (int) sizeof(int)) {
-		wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res);
-		return;
-	}
-
-	os_memcpy(&cmd, buf, sizeof(int));
-	wpa_printf(MSG_DEBUG, "Command %d for interface %s",
-		   cmd, iface->ifname);
-	cmd_buf = &buf[sizeof(int)];
-	cmd_len = res - sizeof(int);
-
-	switch (cmd) {
-	case PRIVSEP_CMD_REGISTER:
-		wpa_priv_cmd_register(iface, &from);
-		break;
-	case PRIVSEP_CMD_UNREGISTER:
-		wpa_priv_cmd_unregister(iface, &from);
-		break;
-	case PRIVSEP_CMD_SCAN:
-		wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
-		break;
-	case PRIVSEP_CMD_GET_SCAN_RESULTS:
-		wpa_priv_cmd_get_scan_results(iface, &from);
-		break;
-	case PRIVSEP_CMD_ASSOCIATE:
-		wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
-		break;
-	case PRIVSEP_CMD_GET_BSSID:
-		wpa_priv_cmd_get_bssid(iface, &from);
-		break;
-	case PRIVSEP_CMD_GET_SSID:
-		wpa_priv_cmd_get_ssid(iface, &from);
-		break;
-	case PRIVSEP_CMD_SET_KEY:
-		wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
-		break;
-	case PRIVSEP_CMD_GET_CAPA:
-		wpa_priv_cmd_get_capa(iface, &from);
-		break;
-	case PRIVSEP_CMD_L2_REGISTER:
-		wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
-		break;
-	case PRIVSEP_CMD_L2_UNREGISTER:
-		wpa_priv_cmd_l2_unregister(iface, &from);
-		break;
-	case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
-		wpa_priv_cmd_l2_notify_auth_start(iface, &from);
-		break;
-	case PRIVSEP_CMD_L2_SEND:
-		wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
-		break;
-	case PRIVSEP_CMD_SET_COUNTRY:
-		pos = cmd_buf;
-		if (pos + cmd_len >= buf + sizeof(buf))
-			break;
-		pos[cmd_len] = '\0';
-		wpa_priv_cmd_set_country(iface, pos);
-		break;
-	}
-}
-
-
-static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
-{
-	if (iface->drv_priv && iface->driver->deinit)
-		iface->driver->deinit(iface->drv_priv);
-
-	if (iface->fd >= 0) {
-		eloop_unregister_read_sock(iface->fd);
-		close(iface->fd);
-		unlink(iface->sock_name);
-	}
-
-	if (iface->l2)
-		l2_packet_deinit(iface->l2);
-
-	os_free(iface->ifname);
-	os_free(iface->driver_name);
-	os_free(iface->sock_name);
-	os_free(iface);
-}
-
-
-extern struct wpa_driver_ops *wpa_drivers[];
-
-static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
-{
-	struct wpa_priv_interface *iface;
-	char *pos;
-	size_t len;
-	struct sockaddr_un addr;
-	int i;
-
-	pos = os_strchr(params, ':');
-	if (pos == NULL)
-		return NULL;
-
-	iface = os_zalloc(sizeof(*iface));
-	if (iface == NULL)
-		return NULL;
-	iface->fd = -1;
-
-	len = pos - params;
-	iface->driver_name = os_malloc(len + 1);
-	if (iface->driver_name == NULL) {
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-	os_memcpy(iface->driver_name, params, len);
-	iface->driver_name[len] = '\0';
-
-	for (i = 0; wpa_drivers[i]; i++) {
-		if (os_strcmp(iface->driver_name,
-			      wpa_drivers[i]->name) == 0) {
-			iface->driver = wpa_drivers[i];
-			break;
-		}
-	}
-	if (iface->driver == NULL) {
-		wpa_printf(MSG_ERROR, "Unsupported driver '%s'",
-			   iface->driver_name);
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-
-	pos++;
-	iface->ifname = os_strdup(pos);
-	if (iface->ifname == NULL) {
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-
-	len = os_strlen(dir) + 1 + os_strlen(iface->ifname);
-	iface->sock_name = os_malloc(len + 1);
-	if (iface->sock_name == NULL) {
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-
-	os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname);
-	if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) {
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-
-	iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (iface->fd < 0) {
-		perror("socket(PF_UNIX)");
-		wpa_priv_interface_deinit(iface);
-		return NULL;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path));
-
-	if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s",
-			   strerror(errno));
-		if (connect(iface->fd, (struct sockaddr *) &addr,
-			    sizeof(addr)) < 0) {
-			wpa_printf(MSG_DEBUG, "Socket exists, but does not "
-				   "allow connections - assuming it was "
-				   "leftover from forced program termination");
-			if (unlink(iface->sock_name) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   iface->sock_name);
-				goto fail;
-			}
-			if (bind(iface->fd, (struct sockaddr *) &addr,
-				 sizeof(addr)) < 0) {
-				perror("bind(PF_UNIX)");
-				goto fail;
-			}
-			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
-				   "socket '%s'", iface->sock_name);
-		} else {
-			wpa_printf(MSG_INFO, "Socket exists and seems to be "
-				   "in use - cannot override it");
-			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
-				   "not used anymore", iface->sock_name);
-			goto fail;
-		}
-	}
-
-	if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
-		perror("chmod");
-		goto fail;
-	}
-
-	eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL);
-
-	return iface;
-
-fail:
-	wpa_priv_interface_deinit(iface);
-	return NULL;
-}
-
-
-static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
-			       const void *data, size_t data_len)
-{
-	struct msghdr msg;
-	struct iovec io[2];
-
-	io[0].iov_base = &event;
-	io[0].iov_len = sizeof(event);
-	io[1].iov_base = (u8 *) data;
-	io[1].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = data ? 2 : 1;
-	msg.msg_name = &iface->drv_addr;
-	msg.msg_namelen = sizeof(iface->drv_addr);
-
-	if (sendmsg(iface->fd, &msg, 0) < 0) {
-		perror("sendmsg(wpas_socket)");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event,
-				union wpa_event_data *data)
-{
-	size_t buflen = 3 * sizeof(int);
-	u8 *buf, *pos;
-	int len;
-
-	if (data) {
-		buflen += data->assoc_info.req_ies_len +
-			data->assoc_info.resp_ies_len +
-			data->assoc_info.beacon_ies_len;
-	}
-
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-
-	pos = buf;
-
-	if (data && data->assoc_info.req_ies) {
-		len = data->assoc_info.req_ies_len;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-		os_memcpy(pos, data->assoc_info.req_ies, len);
-		pos += len;
-	} else {
-		len = 0;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-	}
-
-	if (data && data->assoc_info.resp_ies) {
-		len = data->assoc_info.resp_ies_len;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-		os_memcpy(pos, data->assoc_info.resp_ies, len);
-		pos += len;
-	} else {
-		len = 0;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-	}
-
-	if (data && data->assoc_info.beacon_ies) {
-		len = data->assoc_info.beacon_ies_len;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-		os_memcpy(pos, data->assoc_info.beacon_ies, len);
-		pos += len;
-	} else {
-		len = 0;
-		os_memcpy(pos, &len, sizeof(int));
-		pos += sizeof(int);
-	}
-
-	wpa_priv_send_event(iface, event, buf, buflen);
-
-	os_free(buf);
-}
-
-
-static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface,
-					   union wpa_event_data *data)
-{
-	int ievent;
-	size_t len, maxlen;
-	u8 *buf;
-	char *ifname;
-
-	if (data == NULL)
-		return;
-
-	ievent = data->interface_status.ievent;
-	maxlen = sizeof(data->interface_status.ifname);
-	ifname = data->interface_status.ifname;
-	for (len = 0; len < maxlen && ifname[len]; len++)
-		;
-
-	buf = os_malloc(sizeof(int) + len);
-	if (buf == NULL)
-		return;
-
-	os_memcpy(buf, &ievent, sizeof(int));
-	os_memcpy(buf + sizeof(int), ifname, len);
-
-	wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS,
-			    buf, sizeof(int) + len);
-
-	os_free(buf);
-
-}
-
-
-static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface,
-				      union wpa_event_data *data)
-{
-	size_t len;
-	u8 *buf, *pos;
-
-	if (data == NULL || data->ft_ies.ies == NULL)
-		return;
-
-	len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len;
-	buf = os_malloc(len);
-	if (buf == NULL)
-		return;
-
-	pos = buf;
-	os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int));
-	pos += sizeof(int);
-	os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len);
-
-	wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len);
-
-	os_free(buf);
-
-}
-
-
-void wpa_supplicant_event(void *ctx, wpa_event_type event,
-			  union wpa_event_data *data)
-{
-	struct wpa_priv_interface *iface = ctx;
-
-	wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event);
-
-	if (!iface->wpas_registered) {
-		wpa_printf(MSG_DEBUG, "Driver event received, but "
-			   "wpa_supplicant not registered");
-		return;
-	}
-
-	switch (event) {
-	case EVENT_ASSOC:
-		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data);
-		break;
-	case EVENT_DISASSOC:
-		wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0);
-		break;
-	case EVENT_ASSOCINFO:
-		if (data == NULL)
-			return;
-		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data);
-		break;
-	case EVENT_MICHAEL_MIC_FAILURE:
-		if (data == NULL)
-			return;
-		wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
-				    &data->michael_mic_failure.unicast,
-				    sizeof(int));
-		break;
-	case EVENT_SCAN_RESULTS:
-		wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL,
-				    0);
-		break;
-	case EVENT_INTERFACE_STATUS:
-		wpa_priv_send_interface_status(iface, data);
-		break;
-	case EVENT_PMKID_CANDIDATE:
-		if (data == NULL)
-			return;
-		wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE,
-				    &data->pmkid_candidate,
-				    sizeof(struct pmkid_candidate));
-		break;
-	case EVENT_STKSTART:
-		if (data == NULL)
-			return;
-		wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
-				    &data->stkstart.peer, ETH_ALEN);
-		break;
-	case EVENT_FT_RESPONSE:
-		wpa_priv_send_ft_response(iface, data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO",
-			   event);
-		break;
-	}
-}
-
-
-void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len)
-{
-	struct wpa_priv_interface *iface = ctx;
-	struct msghdr msg;
-	struct iovec io[3];
-	int event = PRIVSEP_EVENT_RX_EAPOL;
-
-	wpa_printf(MSG_DEBUG, "RX EAPOL from driver");
-	io[0].iov_base = &event;
-	io[0].iov_len = sizeof(event);
-	io[1].iov_base = (u8 *) src_addr;
-	io[1].iov_len = ETH_ALEN;
-	io[2].iov_base = (u8 *) buf;
-	io[2].iov_len = len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
-	msg.msg_name = &iface->drv_addr;
-	msg.msg_namelen = sizeof(iface->drv_addr);
-
-	if (sendmsg(iface->fd, &msg, 0) < 0)
-		perror("sendmsg(wpas_socket)");
-}
-
-
-static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx)
-{
-	wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
-	eloop_terminate();
-}
-
-
-static void wpa_priv_fd_workaround(void)
-{
-#ifdef __linux__
-	int s, i;
-	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
-	 * fd 0, 1, and 2 closed. This will cause some issues because many
-	 * places in wpa_supplicant are still printing out to stdout. As a
-	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
-	 * sockets. */
-	for (i = 0; i < 3; i++) {
-		s = open("/dev/null", O_RDWR);
-		if (s > 2) {
-			close(s);
-			break;
-		}
-	}
-#endif /* __linux__ */
-}
-
-
-static void usage(void)
-{
-	printf("wpa_priv v" VERSION_STR "\n"
-	       "Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi> and "
-	       "contributors\n"
-	       "\n"
-	       "usage:\n"
-	       "  wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> "
-	       "[driver:ifname ...]\n");
-}
-
-
-extern int wpa_debug_level;
-
-int main(int argc, char *argv[])
-{
-	int c, i;
-	int ret = -1;
-	char *pid_file = NULL;
-	int daemonize = 0;
-	char *ctrl_dir = "/var/run/wpa_priv";
-	struct wpa_priv_interface *interfaces = NULL, *iface;
-
-	if (os_program_init())
-		return -1;
-
-	wpa_priv_fd_workaround();
-
-	for (;;) {
-		c = getopt(argc, argv, "Bc:dP:");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'B':
-			daemonize++;
-			break;
-		case 'c':
-			ctrl_dir = optarg;
-			break;
-		case 'd':
-			wpa_debug_level--;
-			break;
-		case 'P':
-			pid_file = os_rel2abs_path(optarg);
-			break;
-		default:
-			usage();
-			goto out;
-		}
-	}
-
-	if (optind >= argc) {
-		usage();
-		goto out;
-	}
-
-	wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir);
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		goto out;
-	}
-
-	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]);
-		if (iface == NULL)
-			goto out;
-		iface->next = interfaces;
-		interfaces = iface;
-	}
-
-	if (daemonize && os_daemonize(pid_file))
-		goto out;
-
-	eloop_register_signal_terminate(wpa_priv_terminate, NULL);
-	eloop_run();
-
-	ret = 0;
-
-out:
-	iface = interfaces;
-	while (iface) {
-		struct wpa_priv_interface *prev = iface;
-		iface = iface->next;
-		wpa_priv_interface_deinit(prev);
-	}
-
-	eloop_destroy();
-
-	os_daemonize_terminate(pid_file);
-	os_free(pid_file);
-	os_program_deinit();
-
-	return ret;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_priv.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_priv.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_priv.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_priv.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1034 @@
+/*
+ * WPA Supplicant / privileged helper program
+ * Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "common/version.h"
+#include "drivers/driver.h"
+#include "l2_packet/l2_packet.h"
+#include "common/privsep_commands.h"
+#include "common/ieee802_11_defs.h"
+
+
+struct wpa_priv_interface {
+	struct wpa_priv_interface *next;
+	char *driver_name;
+	char *ifname;
+	char *sock_name;
+	int fd;
+
+	struct wpa_driver_ops *driver;
+	void *drv_priv;
+	struct sockaddr_un drv_addr;
+	int wpas_registered;
+
+	/* TODO: add support for multiple l2 connections */
+	struct l2_packet_data *l2;
+	struct sockaddr_un l2_addr;
+};
+
+
+static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
+				  struct sockaddr_un *from)
+{
+	if (iface->drv_priv) {
+		wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
+		if (iface->driver->deinit)
+			iface->driver->deinit(iface->drv_priv);
+		iface->drv_priv = NULL;
+		iface->wpas_registered = 0;
+	}
+
+	if (iface->l2) {
+		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
+			   "instance");
+		l2_packet_deinit(iface->l2);
+		iface->l2 = NULL;
+	}
+
+	if (iface->driver->init == NULL)
+		return;
+
+	iface->drv_priv = iface->driver->init(iface, iface->ifname);
+	if (iface->drv_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to initialize driver wrapper");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
+		   "'%s'", iface->driver_name, iface->ifname);
+
+	os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
+	iface->wpas_registered = 1;
+
+	if (iface->driver->set_param &&
+	    iface->driver->set_param(iface->drv_priv, NULL) < 0) {
+		wpa_printf(MSG_ERROR, "Driver interface rejected param");
+	}
+}
+
+
+static void wpa_priv_cmd_unregister(struct wpa_priv_interface *iface,
+				    struct sockaddr_un *from)
+{
+	if (iface->drv_priv) {
+		if (iface->driver->deinit)
+			iface->driver->deinit(iface->drv_priv);
+		iface->drv_priv = NULL;
+		iface->wpas_registered = 0;
+	}
+}
+
+
+static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
+			      char *buf, size_t len)
+{
+	struct wpa_driver_scan_params params;
+
+	if (iface->drv_priv == NULL)
+		return;
+
+	os_memset(&params, 0, sizeof(params));
+	if (len) {
+		params.ssids[0].ssid = (u8 *) buf;
+		params.ssids[0].ssid_len = len;
+		params.num_ssids = 1;
+	}
+
+	if (iface->driver->scan2)
+		iface->driver->scan2(iface->drv_priv, &params);
+}
+
+
+static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
+				       struct sockaddr_un *from)
+{
+	struct wpa_scan_results *res;
+	u8 *buf = NULL, *pos, *end;
+	int val;
+	size_t i;
+
+	res = iface->driver->get_scan_results2(iface->drv_priv);
+	if (res == NULL)
+		goto fail;
+
+	buf = os_malloc(60000);
+	if (buf == NULL)
+		goto fail;
+	pos = buf;
+	end = buf + 60000;
+	val = res->num;
+	os_memcpy(pos, &val, sizeof(int));
+	pos += sizeof(int);
+
+	for (i = 0; i < res->num; i++) {
+		struct wpa_scan_res *r = res->res[i];
+		val = sizeof(*r) + r->ie_len;
+		if (end - pos < (int) sizeof(int) + val)
+			break;
+		os_memcpy(pos, &val, sizeof(int));
+		pos += sizeof(int);
+		os_memcpy(pos, r, val);
+		pos += val;
+	}
+
+	sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
+	       sizeof(*from));
+
+	os_free(buf);
+	wpa_scan_results_free(res);
+	return;
+
+fail:
+	os_free(buf);
+	wpa_scan_results_free(res);
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+}
+
+
+static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
+					  struct sockaddr_un *from)
+{
+	if (iface->drv_priv == NULL)
+		return;
+
+	if (iface->driver->get_scan_results2)
+		wpa_priv_get_scan_results2(iface, from);
+	else
+		sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
+		       sizeof(*from));
+}
+
+
+static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface,
+				   void *buf, size_t len)
+{
+	struct wpa_driver_associate_params params;
+	struct privsep_cmd_associate *assoc;
+	u8 *bssid;
+	int res;
+
+	if (iface->drv_priv == NULL || iface->driver->associate == NULL)
+		return;
+
+	if (len < sizeof(*assoc)) {
+		wpa_printf(MSG_DEBUG, "Invalid association request");
+		return;
+	}
+
+	assoc = buf;
+	if (sizeof(*assoc) + assoc->wpa_ie_len > len) {
+		wpa_printf(MSG_DEBUG, "Association request overflow");
+		return;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+	bssid = assoc->bssid;
+	if (bssid[0] | bssid[1] | bssid[2] | bssid[3] | bssid[4] | bssid[5])
+		params.bssid = bssid;
+	params.ssid = assoc->ssid;
+	if (assoc->ssid_len > 32)
+		return;
+	params.ssid_len = assoc->ssid_len;
+	params.freq = assoc->freq;
+	if (assoc->wpa_ie_len) {
+		params.wpa_ie = (u8 *) (assoc + 1);
+		params.wpa_ie_len = assoc->wpa_ie_len;
+	}
+	params.pairwise_suite = assoc->pairwise_suite;
+	params.group_suite = assoc->group_suite;
+	params.key_mgmt_suite = assoc->key_mgmt_suite;
+	params.auth_alg = assoc->auth_alg;
+	params.mode = assoc->mode;
+
+	res = iface->driver->associate(iface->drv_priv, &params);
+	wpa_printf(MSG_DEBUG, "drv->associate: res=%d", res);
+}
+
+
+static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
+				   struct sockaddr_un *from)
+{
+	u8 bssid[ETH_ALEN];
+
+	if (iface->drv_priv == NULL)
+		goto fail;
+
+	if (iface->driver->get_bssid == NULL ||
+	    iface->driver->get_bssid(iface->drv_priv, bssid) < 0)
+		goto fail;
+
+	sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
+	       sizeof(*from));
+	return;
+
+fail:
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+}
+
+
+static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
+				  struct sockaddr_un *from)
+{
+	u8 ssid[sizeof(int) + 32];
+	int res;
+
+	if (iface->drv_priv == NULL)
+		goto fail;
+
+	if (iface->driver->get_ssid == NULL)
+		goto fail;
+
+	res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
+	if (res < 0 || res > 32)
+		goto fail;
+	os_memcpy(ssid, &res, sizeof(int));
+
+	sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
+	       sizeof(*from));
+	return;
+
+fail:
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+}
+
+
+static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface,
+				 void *buf, size_t len)
+{
+	struct privsep_cmd_set_key *params;
+	int res;
+
+	if (iface->drv_priv == NULL || iface->driver->set_key == NULL)
+		return;
+
+	if (len != sizeof(*params)) {
+		wpa_printf(MSG_DEBUG, "Invalid set_key request");
+		return;
+	}
+
+	params = buf;
+
+	res = iface->driver->set_key(iface->ifname, iface->drv_priv,
+				     params->alg,
+				     params->addr, params->key_idx,
+				     params->set_tx,
+				     params->seq_len ? params->seq : NULL,
+				     params->seq_len,
+				     params->key_len ? params->key : NULL,
+				     params->key_len);
+	wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
+}
+
+
+static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
+				  struct sockaddr_un *from)
+{
+	struct wpa_driver_capa capa;
+
+	if (iface->drv_priv == NULL)
+		goto fail;
+
+	if (iface->driver->get_capa == NULL ||
+	    iface->driver->get_capa(iface->drv_priv, &capa) < 0)
+		goto fail;
+
+	sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
+	       sizeof(*from));
+	return;
+
+fail:
+	sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+}
+
+
+static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+			   size_t len)
+{
+	struct wpa_priv_interface *iface = ctx;
+	struct msghdr msg;
+	struct iovec io[2];
+
+	io[0].iov_base = (u8 *) src_addr;
+	io[0].iov_len = ETH_ALEN;
+	io[1].iov_base = (u8 *) buf;
+	io[1].iov_len = len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+	msg.msg_name = &iface->l2_addr;
+	msg.msg_namelen = sizeof(iface->l2_addr);
+
+	if (sendmsg(iface->fd, &msg, 0) < 0) {
+		perror("sendmsg(l2 rx)");
+	}
+}
+
+
+static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
+				     struct sockaddr_un *from,
+				     void *buf, size_t len)
+{
+	int *reg_cmd = buf;
+	u8 own_addr[ETH_ALEN];
+	int res;
+	u16 proto;
+
+	if (len != 2 * sizeof(int)) {
+		wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
+			   (unsigned long) len);
+		return;
+	}
+
+	proto = reg_cmd[0];
+	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+		wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
+			   "ethertype 0x%x", proto);
+		return;
+	}
+
+	if (iface->l2) {
+		wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
+			   "instance");
+		l2_packet_deinit(iface->l2);
+		iface->l2 = NULL;
+	}
+
+	os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
+
+	iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
+				   wpa_priv_l2_rx, iface, reg_cmd[1]);
+	if (iface->l2 == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
+			   "instance for protocol %d", proto);
+		return;
+	}
+
+	if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to get own address from "
+			   "l2_packet");
+		l2_packet_deinit(iface->l2);
+		iface->l2 = NULL;
+		return;
+	}
+
+	res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
+		     (struct sockaddr *) from, sizeof(*from));
+	wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
+}
+
+
+static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
+				       struct sockaddr_un *from)
+{
+	if (iface->l2) {
+		l2_packet_deinit(iface->l2);
+		iface->l2 = NULL;
+	}
+}
+
+
+static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
+					      struct sockaddr_un *from)
+{
+	if (iface->l2)
+		l2_packet_notify_auth_start(iface->l2);
+}
+
+
+static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
+				 struct sockaddr_un *from,
+				 void *buf, size_t len)
+{
+	u8 *dst_addr;
+	u16 proto;
+	int res;
+
+	if (iface->l2 == NULL)
+		return;
+
+	if (len < ETH_ALEN + 2) {
+		wpa_printf(MSG_DEBUG, "Too short L2 send packet (len=%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	dst_addr = buf;
+	os_memcpy(&proto, buf + ETH_ALEN, 2);
+
+	if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+		wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
+			   "0x%x", proto);
+		return;
+	}
+
+	res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
+			     len - ETH_ALEN - 2);
+	wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
+}
+
+
+static void wpa_priv_cmd_set_country(struct wpa_priv_interface *iface,
+				     char *buf)
+{
+	if (iface->drv_priv == NULL || iface->driver->set_country == NULL ||
+	    *buf == '\0')
+		return;
+
+	iface->driver->set_country(iface->drv_priv, buf);
+}
+
+
+static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_priv_interface *iface = eloop_ctx;
+	char buf[2000], *pos;
+	void *cmd_buf;
+	size_t cmd_len;
+	int res, cmd;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+
+	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+		       &fromlen);
+	if (res < 0) {
+		perror("recvfrom");
+		return;
+	}
+
+	if (res < (int) sizeof(int)) {
+		wpa_printf(MSG_DEBUG, "Too short command (len=%d)", res);
+		return;
+	}
+
+	os_memcpy(&cmd, buf, sizeof(int));
+	wpa_printf(MSG_DEBUG, "Command %d for interface %s",
+		   cmd, iface->ifname);
+	cmd_buf = &buf[sizeof(int)];
+	cmd_len = res - sizeof(int);
+
+	switch (cmd) {
+	case PRIVSEP_CMD_REGISTER:
+		wpa_priv_cmd_register(iface, &from);
+		break;
+	case PRIVSEP_CMD_UNREGISTER:
+		wpa_priv_cmd_unregister(iface, &from);
+		break;
+	case PRIVSEP_CMD_SCAN:
+		wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
+		break;
+	case PRIVSEP_CMD_GET_SCAN_RESULTS:
+		wpa_priv_cmd_get_scan_results(iface, &from);
+		break;
+	case PRIVSEP_CMD_ASSOCIATE:
+		wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
+		break;
+	case PRIVSEP_CMD_GET_BSSID:
+		wpa_priv_cmd_get_bssid(iface, &from);
+		break;
+	case PRIVSEP_CMD_GET_SSID:
+		wpa_priv_cmd_get_ssid(iface, &from);
+		break;
+	case PRIVSEP_CMD_SET_KEY:
+		wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
+		break;
+	case PRIVSEP_CMD_GET_CAPA:
+		wpa_priv_cmd_get_capa(iface, &from);
+		break;
+	case PRIVSEP_CMD_L2_REGISTER:
+		wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
+		break;
+	case PRIVSEP_CMD_L2_UNREGISTER:
+		wpa_priv_cmd_l2_unregister(iface, &from);
+		break;
+	case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
+		wpa_priv_cmd_l2_notify_auth_start(iface, &from);
+		break;
+	case PRIVSEP_CMD_L2_SEND:
+		wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
+		break;
+	case PRIVSEP_CMD_SET_COUNTRY:
+		pos = cmd_buf;
+		if (pos + cmd_len >= buf + sizeof(buf))
+			break;
+		pos[cmd_len] = '\0';
+		wpa_priv_cmd_set_country(iface, pos);
+		break;
+	}
+}
+
+
+static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
+{
+	if (iface->drv_priv && iface->driver->deinit)
+		iface->driver->deinit(iface->drv_priv);
+
+	if (iface->fd >= 0) {
+		eloop_unregister_read_sock(iface->fd);
+		close(iface->fd);
+		unlink(iface->sock_name);
+	}
+
+	if (iface->l2)
+		l2_packet_deinit(iface->l2);
+
+	os_free(iface->ifname);
+	os_free(iface->driver_name);
+	os_free(iface->sock_name);
+	os_free(iface);
+}
+
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+static struct wpa_priv_interface *
+wpa_priv_interface_init(const char *dir, const char *params)
+{
+	struct wpa_priv_interface *iface;
+	char *pos;
+	size_t len;
+	struct sockaddr_un addr;
+	int i;
+
+	pos = os_strchr(params, ':');
+	if (pos == NULL)
+		return NULL;
+
+	iface = os_zalloc(sizeof(*iface));
+	if (iface == NULL)
+		return NULL;
+	iface->fd = -1;
+
+	len = pos - params;
+	iface->driver_name = os_malloc(len + 1);
+	if (iface->driver_name == NULL) {
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+	os_memcpy(iface->driver_name, params, len);
+	iface->driver_name[len] = '\0';
+
+	for (i = 0; wpa_drivers[i]; i++) {
+		if (os_strcmp(iface->driver_name,
+			      wpa_drivers[i]->name) == 0) {
+			iface->driver = wpa_drivers[i];
+			break;
+		}
+	}
+	if (iface->driver == NULL) {
+		wpa_printf(MSG_ERROR, "Unsupported driver '%s'",
+			   iface->driver_name);
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+
+	pos++;
+	iface->ifname = os_strdup(pos);
+	if (iface->ifname == NULL) {
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+
+	len = os_strlen(dir) + 1 + os_strlen(iface->ifname);
+	iface->sock_name = os_malloc(len + 1);
+	if (iface->sock_name == NULL) {
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+
+	os_snprintf(iface->sock_name, len + 1, "%s/%s", dir, iface->ifname);
+	if (os_strlen(iface->sock_name) >= sizeof(addr.sun_path)) {
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+
+	iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (iface->fd < 0) {
+		perror("socket(PF_UNIX)");
+		wpa_priv_interface_deinit(iface);
+		return NULL;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, iface->sock_name, sizeof(addr.sun_path));
+
+	if (bind(iface->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(iface->fd, (struct sockaddr *) &addr,
+			    sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "Socket exists, but does not "
+				   "allow connections - assuming it was "
+				   "leftover from forced program termination");
+			if (unlink(iface->sock_name) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   iface->sock_name);
+				goto fail;
+			}
+			if (bind(iface->fd, (struct sockaddr *) &addr,
+				 sizeof(addr)) < 0) {
+				perror("wpa-priv-iface-init: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "socket '%s'", iface->sock_name);
+		} else {
+			wpa_printf(MSG_INFO, "Socket exists and seems to be "
+				   "in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", iface->sock_name);
+			goto fail;
+		}
+	}
+
+	if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
+		perror("chmod");
+		goto fail;
+	}
+
+	eloop_register_read_sock(iface->fd, wpa_priv_receive, iface, NULL);
+
+	return iface;
+
+fail:
+	wpa_priv_interface_deinit(iface);
+	return NULL;
+}
+
+
+static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event,
+			       const void *data, size_t data_len)
+{
+	struct msghdr msg;
+	struct iovec io[2];
+
+	io[0].iov_base = &event;
+	io[0].iov_len = sizeof(event);
+	io[1].iov_base = (u8 *) data;
+	io[1].iov_len = data_len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = data ? 2 : 1;
+	msg.msg_name = &iface->drv_addr;
+	msg.msg_namelen = sizeof(iface->drv_addr);
+
+	if (sendmsg(iface->fd, &msg, 0) < 0) {
+		perror("sendmsg(wpas_socket)");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event,
+				union wpa_event_data *data)
+{
+	size_t buflen = 3 * sizeof(int);
+	u8 *buf, *pos;
+	int len;
+
+	if (data) {
+		buflen += data->assoc_info.req_ies_len +
+			data->assoc_info.resp_ies_len +
+			data->assoc_info.beacon_ies_len;
+	}
+
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+
+	pos = buf;
+
+	if (data && data->assoc_info.req_ies) {
+		len = data->assoc_info.req_ies_len;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+		os_memcpy(pos, data->assoc_info.req_ies, len);
+		pos += len;
+	} else {
+		len = 0;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+	}
+
+	if (data && data->assoc_info.resp_ies) {
+		len = data->assoc_info.resp_ies_len;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+		os_memcpy(pos, data->assoc_info.resp_ies, len);
+		pos += len;
+	} else {
+		len = 0;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+	}
+
+	if (data && data->assoc_info.beacon_ies) {
+		len = data->assoc_info.beacon_ies_len;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+		os_memcpy(pos, data->assoc_info.beacon_ies, len);
+		pos += len;
+	} else {
+		len = 0;
+		os_memcpy(pos, &len, sizeof(int));
+		pos += sizeof(int);
+	}
+
+	wpa_priv_send_event(iface, event, buf, buflen);
+
+	os_free(buf);
+}
+
+
+static void wpa_priv_send_interface_status(struct wpa_priv_interface *iface,
+					   union wpa_event_data *data)
+{
+	int ievent;
+	size_t len, maxlen;
+	u8 *buf;
+	char *ifname;
+
+	if (data == NULL)
+		return;
+
+	ievent = data->interface_status.ievent;
+	maxlen = sizeof(data->interface_status.ifname);
+	ifname = data->interface_status.ifname;
+	for (len = 0; len < maxlen && ifname[len]; len++)
+		;
+
+	buf = os_malloc(sizeof(int) + len);
+	if (buf == NULL)
+		return;
+
+	os_memcpy(buf, &ievent, sizeof(int));
+	os_memcpy(buf + sizeof(int), ifname, len);
+
+	wpa_priv_send_event(iface, PRIVSEP_EVENT_INTERFACE_STATUS,
+			    buf, sizeof(int) + len);
+
+	os_free(buf);
+
+}
+
+
+static void wpa_priv_send_ft_response(struct wpa_priv_interface *iface,
+				      union wpa_event_data *data)
+{
+	size_t len;
+	u8 *buf, *pos;
+
+	if (data == NULL || data->ft_ies.ies == NULL)
+		return;
+
+	len = sizeof(int) + ETH_ALEN + data->ft_ies.ies_len;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return;
+
+	pos = buf;
+	os_memcpy(pos, &data->ft_ies.ft_action, sizeof(int));
+	pos += sizeof(int);
+	os_memcpy(pos, data->ft_ies.target_ap, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, data->ft_ies.ies, data->ft_ies.ies_len);
+
+	wpa_priv_send_event(iface, PRIVSEP_EVENT_FT_RESPONSE, buf, len);
+
+	os_free(buf);
+
+}
+
+
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data)
+{
+	struct wpa_priv_interface *iface = ctx;
+
+	wpa_printf(MSG_DEBUG, "%s - event=%d", __func__, event);
+
+	if (!iface->wpas_registered) {
+		wpa_printf(MSG_DEBUG, "Driver event received, but "
+			   "wpa_supplicant not registered");
+		return;
+	}
+
+	switch (event) {
+	case EVENT_ASSOC:
+		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOC, data);
+		break;
+	case EVENT_DISASSOC:
+		wpa_priv_send_event(iface, PRIVSEP_EVENT_DISASSOC, NULL, 0);
+		break;
+	case EVENT_ASSOCINFO:
+		if (data == NULL)
+			return;
+		wpa_priv_send_assoc(iface, PRIVSEP_EVENT_ASSOCINFO, data);
+		break;
+	case EVENT_MICHAEL_MIC_FAILURE:
+		if (data == NULL)
+			return;
+		wpa_priv_send_event(iface, PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
+				    &data->michael_mic_failure.unicast,
+				    sizeof(int));
+		break;
+	case EVENT_SCAN_RESULTS:
+		wpa_priv_send_event(iface, PRIVSEP_EVENT_SCAN_RESULTS, NULL,
+				    0);
+		break;
+	case EVENT_INTERFACE_STATUS:
+		wpa_priv_send_interface_status(iface, data);
+		break;
+	case EVENT_PMKID_CANDIDATE:
+		if (data == NULL)
+			return;
+		wpa_priv_send_event(iface, PRIVSEP_EVENT_PMKID_CANDIDATE,
+				    &data->pmkid_candidate,
+				    sizeof(struct pmkid_candidate));
+		break;
+	case EVENT_STKSTART:
+		if (data == NULL)
+			return;
+		wpa_priv_send_event(iface, PRIVSEP_EVENT_STKSTART,
+				    &data->stkstart.peer, ETH_ALEN);
+		break;
+	case EVENT_FT_RESPONSE:
+		wpa_priv_send_ft_response(iface, data);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unsupported driver event %d - TODO",
+			   event);
+		break;
+	}
+}
+
+
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+			     const u8 *buf, size_t len)
+{
+	struct wpa_priv_interface *iface = ctx;
+	struct msghdr msg;
+	struct iovec io[3];
+	int event = PRIVSEP_EVENT_RX_EAPOL;
+
+	wpa_printf(MSG_DEBUG, "RX EAPOL from driver");
+	io[0].iov_base = &event;
+	io[0].iov_len = sizeof(event);
+	io[1].iov_base = (u8 *) src_addr;
+	io[1].iov_len = ETH_ALEN;
+	io[2].iov_base = (u8 *) buf;
+	io[2].iov_len = len;
+
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 3;
+	msg.msg_name = &iface->drv_addr;
+	msg.msg_namelen = sizeof(iface->drv_addr);
+
+	if (sendmsg(iface->fd, &msg, 0) < 0)
+		perror("sendmsg(wpas_socket)");
+}
+
+
+static void wpa_priv_terminate(int sig, void *signal_ctx)
+{
+	wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
+	eloop_terminate();
+}
+
+
+static void wpa_priv_fd_workaround(void)
+{
+#ifdef __linux__
+	int s, i;
+	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
+	 * fd 0, 1, and 2 closed. This will cause some issues because many
+	 * places in wpa_supplicant are still printing out to stdout. As a
+	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
+	 * sockets. */
+	for (i = 0; i < 3; i++) {
+		s = open("/dev/null", O_RDWR);
+		if (s > 2) {
+			close(s);
+			break;
+		}
+	}
+#endif /* __linux__ */
+}
+
+
+static void usage(void)
+{
+	printf("wpa_priv v" VERSION_STR "\n"
+	       "Copyright (c) 2007-2009, Jouni Malinen <j at w1.fi> and "
+	       "contributors\n"
+	       "\n"
+	       "usage:\n"
+	       "  wpa_priv [-Bdd] [-P<pid file>] <driver:ifname> "
+	       "[driver:ifname ...]\n");
+}
+
+
+extern int wpa_debug_level;
+
+int main(int argc, char *argv[])
+{
+	int c, i;
+	int ret = -1;
+	char *pid_file = NULL;
+	int daemonize = 0;
+	char *ctrl_dir = "/var/run/wpa_priv";
+	struct wpa_priv_interface *interfaces = NULL, *iface;
+
+	if (os_program_init())
+		return -1;
+
+	wpa_priv_fd_workaround();
+
+	for (;;) {
+		c = getopt(argc, argv, "Bc:dP:");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'B':
+			daemonize++;
+			break;
+		case 'c':
+			ctrl_dir = optarg;
+			break;
+		case 'd':
+			wpa_debug_level--;
+			break;
+		case 'P':
+			pid_file = os_rel2abs_path(optarg);
+			break;
+		default:
+			usage();
+			goto out;
+		}
+	}
+
+	if (optind >= argc) {
+		usage();
+		goto out;
+	}
+
+	wpa_printf(MSG_DEBUG, "wpa_priv control directory: '%s'", ctrl_dir);
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		goto out;
+	}
+
+	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]);
+		if (iface == NULL)
+			goto out;
+		iface->next = interfaces;
+		interfaces = iface;
+	}
+
+	if (daemonize && os_daemonize(pid_file))
+		goto out;
+
+	eloop_register_signal_terminate(wpa_priv_terminate, NULL);
+	eloop_run();
+
+	ret = 0;
+
+out:
+	iface = interfaces;
+	while (iface) {
+		struct wpa_priv_interface *prev = iface;
+		iface = iface->next;
+		wpa_priv_interface_deinit(prev);
+	}
+
+	eloop_destroy();
+
+	os_daemonize_terminate(pid_file);
+	os_free(pid_file);
+	os_program_deinit();
+
+	return ret;
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_supplicant.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,2410 +0,0 @@
-/*
- * WPA Supplicant
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * This file implements functions for registering and unregistering
- * %wpa_supplicant interfaces. In addition, this file contains number of
- * functions for managing network connections.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "eap_peer/eap.h"
-#include "eap_server/eap_methods.h"
-#include "rsn_supp/wpa.h"
-#include "eloop.h"
-#include "config.h"
-#include "l2_packet/l2_packet.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "ctrl_iface.h"
-#include "pcsc_funcs.h"
-#include "common/version.h"
-#include "rsn_supp/preauth.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "common/wpa_ctrl.h"
-#include "mlme.h"
-#include "common/ieee802_11_defs.h"
-#include "blacklist.h"
-#include "wpas_glue.h"
-#include "wps_supplicant.h"
-#include "ibss_rsn.h"
-#include "sme.h"
-#include "ap.h"
-#include "notify.h"
-#include "bgscan.h"
-#include "bss.h"
-#include "scan.h"
-
-const char *wpa_supplicant_version =
-"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi> and contributors";
-
-const char *wpa_supplicant_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n"
-#ifdef EAP_TLS_OPENSSL
-"\nThis product includes software developed by the OpenSSL Project\n"
-"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
-#endif /* EAP_TLS_OPENSSL */
-;
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-/* Long text divided into parts in order to fit in C89 strings size limits. */
-const char *wpa_supplicant_full_license1 =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-"GNU General Public License for more details.\n"
-"\n";
-const char *wpa_supplicant_full_license2 =
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"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";
-const char *wpa_supplicant_full_license3 =
-"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";
-const char *wpa_supplicant_full_license4 =
-"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";
-const char *wpa_supplicant_full_license5 =
-"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";
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-extern struct wpa_driver_ops *wpa_drivers[];
-
-/* Configure default/group WEP keys for static WEP */
-int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
-{
-	int i, set = 0;
-
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i] == 0)
-			continue;
-
-		set = 1;
-		wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
-				(u8 *) "\xff\xff\xff\xff\xff\xff",
-				i, i == ssid->wep_tx_keyidx, (u8 *) "", 0,
-				ssid->wep_key[i], ssid->wep_key_len[i]);
-	}
-
-	return set;
-}
-
-
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
-					   struct wpa_ssid *ssid)
-{
-	u8 key[32];
-	size_t keylen;
-	enum wpa_alg alg;
-	u8 seq[6] = { 0 };
-
-	/* IBSS/WPA-None uses only one key (Group) for both receiving and
-	 * sending unicast and multicast packets. */
-
-	if (ssid->mode != WPAS_MODE_IBSS) {
-		wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) "
-			   "for WPA-None", ssid->mode);
-		return -1;
-	}
-
-	if (!ssid->psk_set) {
-		wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None");
-		return -1;
-	}
-
-	switch (wpa_s->group_cipher) {
-	case WPA_CIPHER_CCMP:
-		os_memcpy(key, ssid->psk, 16);
-		keylen = 16;
-		alg = WPA_ALG_CCMP;
-		break;
-	case WPA_CIPHER_TKIP:
-		/* WPA-None uses the same Michael MIC key for both TX and RX */
-		os_memcpy(key, ssid->psk, 16 + 8);
-		os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
-		keylen = 32;
-		alg = WPA_ALG_TKIP;
-		break;
-	default:
-		wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for "
-			   "WPA-None", wpa_s->group_cipher);
-		return -1;
-	}
-
-	/* TODO: should actually remember the previously used seq#, both for TX
-	 * and RX from each STA.. */
-
-	return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
-			       0, 1, seq, 6, key, keylen);
-}
-
-
-static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	const u8 *bssid = wpa_s->bssid;
-	if (is_zero_ether_addr(bssid))
-		bssid = wpa_s->pending_bssid;
-	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
-		MAC2STR(bssid));
-	wpa_blacklist_add(wpa_s, bssid);
-	wpa_sm_notify_disassoc(wpa_s->wpa);
-	wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-	wpa_s->reassociate = 1;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-}
-
-
-/**
- * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
- * @wpa_s: Pointer to wpa_supplicant data
- * @sec: Number of seconds after which to time out authentication
- * @usec: Number of microseconds after which to time out authentication
- *
- * This function is used to schedule a timeout for the current authentication
- * attempt.
- */
-void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
-				     int sec, int usec)
-{
-	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
-		return;
-
-	wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
-		"%d usec", sec, usec);
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
-}
-
-
-/**
- * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * This function is used to cancel authentication timeout scheduled with
- * wpa_supplicant_req_auth_timeout() and it is called when authentication has
- * been completed.
- */
-void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
-{
-	wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-	wpa_blacklist_del(wpa_s, wpa_s->bssid);
-}
-
-
-/**
- * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * This function is used to configure EAPOL state machine based on the selected
- * authentication mode.
- */
-void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
-{
-#ifdef IEEE8021X_EAPOL
-	struct eapol_config eapol_conf;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-#ifdef CONFIG_IBSS_RSN
-	if (ssid->mode == WPAS_MODE_IBSS &&
-	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
-	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
-		/*
-		 * RSN IBSS authentication is per-STA and we can disable the
-		 * per-BSSID EAPOL authentication.
-		 */
-		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
-		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
-		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
-		return;
-	}
-#endif /* CONFIG_IBSS_RSN */
-
-	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
-		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
-	else
-		eapol_sm_notify_portControl(wpa_s->eapol, Auto);
-
-	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		eapol_conf.accept_802_1x_keys = 1;
-		eapol_conf.required_keys = 0;
-		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
-			eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
-		}
-		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
-			eapol_conf.required_keys |=
-				EAPOL_REQUIRE_KEY_BROADCAST;
-		}
-
-		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
-			eapol_conf.required_keys = 0;
-	}
-	if (wpa_s->conf)
-		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
-	eapol_conf.workaround = ssid->eap_workaround;
-	eapol_conf.eap_disabled =
-		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
-		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
-		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
-	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-#endif /* IEEE8021X_EAPOL */
-}
-
-
-/**
- * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
- * @wpa_s: Pointer to wpa_supplicant data
- * @ssid: Configuration data for the network
- *
- * This function is used to configure WPA state machine and related parameters
- * to a mode where WPA is not enabled. This is called as part of the
- * authentication configuration when the selected network does not use WPA.
- */
-void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
-				       struct wpa_ssid *ssid)
-{
-	int i;
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
-	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
-		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
-	else
-		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
-	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
-	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
-	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-	wpa_s->group_cipher = WPA_CIPHER_NONE;
-	wpa_s->mgmt_group_cipher = 0;
-
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i] > 5) {
-			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
-			wpa_s->group_cipher = WPA_CIPHER_WEP104;
-			break;
-		} else if (ssid->wep_key_len[i] > 0) {
-			wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
-			wpa_s->group_cipher = WPA_CIPHER_WEP40;
-			break;
-		}
-	}
-
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
-			 wpa_s->pairwise_cipher);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-#ifdef CONFIG_IEEE80211W
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
-			 wpa_s->mgmt_group_cipher);
-#endif /* CONFIG_IEEE80211W */
-
-	pmksa_cache_clear_current(wpa_s->wpa);
-}
-
-
-static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
-{
-	bgscan_deinit(wpa_s);
-	scard_deinit(wpa_s->scard);
-	wpa_s->scard = NULL;
-	wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
-	eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
-	l2_packet_deinit(wpa_s->l2);
-	wpa_s->l2 = NULL;
-	if (wpa_s->l2_br) {
-		l2_packet_deinit(wpa_s->l2_br);
-		wpa_s->l2_br = NULL;
-	}
-
-	if (wpa_s->ctrl_iface) {
-		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-		wpa_s->ctrl_iface = NULL;
-	}
-	if (wpa_s->conf != NULL) {
-		struct wpa_ssid *ssid;
-		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-			wpas_notify_network_removed(wpa_s, ssid);
-		wpa_config_free(wpa_s->conf);
-		wpa_s->conf = NULL;
-	}
-
-	os_free(wpa_s->confname);
-	wpa_s->confname = NULL;
-
-	wpa_sm_set_eapol(wpa_s->wpa, NULL);
-	eapol_sm_deinit(wpa_s->eapol);
-	wpa_s->eapol = NULL;
-
-	rsn_preauth_deinit(wpa_s->wpa);
-
-	pmksa_candidate_free(wpa_s->wpa);
-	wpa_sm_deinit(wpa_s->wpa);
-	wpa_s->wpa = NULL;
-	wpa_blacklist_clear(wpa_s);
-
-	wpa_bss_deinit(wpa_s);
-
-	wpa_supplicant_cancel_scan(wpa_s);
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-	ieee80211_sta_deinit(wpa_s);
-
-	wpas_wps_deinit(wpa_s);
-
-	wpabuf_free(wpa_s->pending_eapol_rx);
-	wpa_s->pending_eapol_rx = NULL;
-
-#ifdef CONFIG_IBSS_RSN
-	ibss_rsn_deinit(wpa_s->ibss_rsn);
-	wpa_s->ibss_rsn = NULL;
-#endif /* CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_SME
-	os_free(wpa_s->sme.ft_ies);
-	wpa_s->sme.ft_ies = NULL;
-	wpa_s->sme.ft_ies_len = 0;
-#endif /* CONFIG_SME */
-
-#ifdef CONFIG_AP
-	wpa_supplicant_ap_deinit(wpa_s);
-#endif /* CONFIG_AP */
-}
-
-
-/**
- * wpa_clear_keys - Clear keys configured for the driver
- * @wpa_s: Pointer to wpa_supplicant data
- * @addr: Previously used BSSID or %NULL if not available
- *
- * This function clears the encryption keys that has been previously configured
- * for the driver.
- */
-void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
-{
-	u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
-
-	if (wpa_s->keys_cleared) {
-		/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
-		 * timing issues with keys being cleared just before new keys
-		 * are set or just after association or something similar. This
-		 * shows up in group key handshake failing often because of the
-		 * client not receiving the first encrypted packets correctly.
-		 * Skipping some of the extra key clearing steps seems to help
-		 * in completing group key handshake more reliably. */
-		wpa_printf(MSG_DEBUG, "No keys have been configured - "
-			   "skip key clearing");
-		return;
-	}
-
-	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
-#ifdef CONFIG_IEEE80211W
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
-#endif /* CONFIG_IEEE80211W */
-	if (addr) {
-		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
-				0);
-		/* MLME-SETPROTECTION.request(None) */
-		wpa_drv_mlme_setprotection(
-			wpa_s, addr,
-			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
-			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
-	}
-	wpa_s->keys_cleared = 1;
-}
-
-
-/**
- * wpa_supplicant_state_txt - Get the connection state name as a text string
- * @state: State (wpa_state; WPA_*)
- * Returns: The state name as a printable text string
- */
-const char * wpa_supplicant_state_txt(enum wpa_states state)
-{
-	switch (state) {
-	case WPA_DISCONNECTED:
-		return "DISCONNECTED";
-	case WPA_INACTIVE:
-		return "INACTIVE";
-	case WPA_SCANNING:
-		return "SCANNING";
-	case WPA_AUTHENTICATING:
-		return "AUTHENTICATING";
-	case WPA_ASSOCIATING:
-		return "ASSOCIATING";
-	case WPA_ASSOCIATED:
-		return "ASSOCIATED";
-	case WPA_4WAY_HANDSHAKE:
-		return "4WAY_HANDSHAKE";
-	case WPA_GROUP_HANDSHAKE:
-		return "GROUP_HANDSHAKE";
-	case WPA_COMPLETED:
-		return "COMPLETED";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-
-/**
- * wpa_supplicant_set_state - Set current connection state
- * @wpa_s: Pointer to wpa_supplicant data
- * @state: The new connection state
- *
- * This function is called whenever the connection state changes, e.g.,
- * association is completed for WPA/WPA2 4-Way Handshake is started.
- */
-void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
-			      enum wpa_states state)
-{
-	enum wpa_states old_state = wpa_s->wpa_state;
-
-	wpa_printf(MSG_DEBUG, "State: %s -> %s",
-		   wpa_supplicant_state_txt(wpa_s->wpa_state),
-		   wpa_supplicant_state_txt(state));
-
-	if (state != WPA_SCANNING)
-		wpa_supplicant_notify_scanning(wpa_s, 0);
-
-	if (state == WPA_COMPLETED && wpa_s->new_connection) {
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-		struct wpa_ssid *ssid = wpa_s->current_ssid;
-		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
-			MACSTR " completed %s [id=%d id_str=%s]",
-			MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
-			"(reauth)" : "(auth)",
-			ssid ? ssid->id : -1,
-			ssid && ssid->id_str ? ssid->id_str : "");
-#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-		wpa_s->new_connection = 0;
-		wpa_s->reassociated_connection = 1;
-		wpa_drv_set_operstate(wpa_s, 1);
-		wpa_s->after_wps = 0;
-	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
-		   state == WPA_ASSOCIATED) {
-		wpa_s->new_connection = 1;
-		wpa_drv_set_operstate(wpa_s, 0);
-	}
-	wpa_s->wpa_state = state;
-
-	if (wpa_s->wpa_state != old_state)
-		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
-}
-
-
-void wpa_supplicant_terminate_proc(struct wpa_global *global)
-{
-	int pending = 0;
-#ifdef CONFIG_WPS
-	struct wpa_supplicant *wpa_s = global->ifaces;
-	while (wpa_s) {
-		if (wpas_wps_terminate_pending(wpa_s) == 1)
-			pending = 1;
-		wpa_s = wpa_s->next;
-	}
-#endif /* CONFIG_WPS */
-	if (pending)
-		return;
-	eloop_terminate();
-}
-
-
-static void wpa_supplicant_terminate(int sig, void *signal_ctx)
-{
-	struct wpa_global *global = signal_ctx;
-	struct wpa_supplicant *wpa_s;
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
-			"received", sig);
-	}
-	wpa_supplicant_terminate_proc(global);
-}
-
-
-static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
-{
-	enum wpa_states old_state = wpa_s->wpa_state;
-
-	wpa_s->pairwise_cipher = 0;
-	wpa_s->group_cipher = 0;
-	wpa_s->mgmt_group_cipher = 0;
-	wpa_s->key_mgmt = 0;
-	wpa_s->wpa_state = WPA_DISCONNECTED;
-
-	if (wpa_s->wpa_state != old_state)
-		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
-}
-
-
-/**
- * wpa_supplicant_reload_configuration - Reload configuration data
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success or -1 if configuration parsing failed
- *
- * This function can be used to request that the configuration data is reloaded
- * (e.g., after configuration file change). This function is reloading
- * configuration only for one interface, so this may need to be called multiple
- * times if %wpa_supplicant is controlling multiple interfaces and all
- * interfaces need reconfiguration.
- */
-int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_config *conf;
-	struct wpa_ssid *old_ssid;
-	int reconf_ctrl;
-	int old_ap_scan;
-
-	if (wpa_s->confname == NULL)
-		return -1;
-	conf = wpa_config_read(wpa_s->confname);
-	if (conf == NULL) {
-		wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
-			"file '%s' - exiting", wpa_s->confname);
-		return -1;
-	}
-
-	reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
-		|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
-		    os_strcmp(conf->ctrl_interface,
-			      wpa_s->conf->ctrl_interface) != 0);
-
-	if (reconf_ctrl && wpa_s->ctrl_iface) {
-		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-		wpa_s->ctrl_iface = NULL;
-	}
-
-	eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = NULL;
-	if (old_ssid != wpa_s->current_ssid)
-		wpas_notify_network_changed(wpa_s);
-
-	/*
-	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
-	 * pkcs11_engine_path, pkcs11_module_path.
-	 */
-	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		/*
-		 * Clear forced success to clear EAP state for next
-		 * authentication.
-		 */
-		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-	}
-	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-	wpa_sm_set_config(wpa_s->wpa, NULL);
-	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
-	rsn_preauth_deinit(wpa_s->wpa);
-
-	old_ap_scan = wpa_s->conf->ap_scan;
-	wpa_config_free(wpa_s->conf);
-	wpa_s->conf = conf;
-	if (old_ap_scan != wpa_s->conf->ap_scan)
-		wpas_notify_ap_scan_changed(wpa_s);
-
-	if (reconf_ctrl)
-		wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
-
-	wpa_supplicant_clear_status(wpa_s);
-	wpa_s->reassociate = 1;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-	wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
-	return 0;
-}
-
-
-static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
-{
-	struct wpa_global *global = signal_ctx;
-	struct wpa_supplicant *wpa_s;
-	wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
-			wpa_supplicant_terminate_proc(global);
-		}
-	}
-}
-
-
-enum wpa_cipher cipher_suite2driver(int cipher)
-{
-	switch (cipher) {
-	case WPA_CIPHER_NONE:
-		return CIPHER_NONE;
-	case WPA_CIPHER_WEP40:
-		return CIPHER_WEP40;
-	case WPA_CIPHER_WEP104:
-		return CIPHER_WEP104;
-	case WPA_CIPHER_CCMP:
-		return CIPHER_CCMP;
-	case WPA_CIPHER_TKIP:
-	default:
-		return CIPHER_TKIP;
-	}
-}
-
-
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
-{
-	switch (key_mgmt) {
-	case WPA_KEY_MGMT_NONE:
-		return KEY_MGMT_NONE;
-	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
-		return KEY_MGMT_802_1X_NO_WPA;
-	case WPA_KEY_MGMT_IEEE8021X:
-		return KEY_MGMT_802_1X;
-	case WPA_KEY_MGMT_WPA_NONE:
-		return KEY_MGMT_WPA_NONE;
-	case WPA_KEY_MGMT_FT_IEEE8021X:
-		return KEY_MGMT_FT_802_1X;
-	case WPA_KEY_MGMT_FT_PSK:
-		return KEY_MGMT_FT_PSK;
-	case WPA_KEY_MGMT_IEEE8021X_SHA256:
-		return KEY_MGMT_802_1X_SHA256;
-	case WPA_KEY_MGMT_PSK_SHA256:
-		return KEY_MGMT_PSK_SHA256;
-	case WPA_KEY_MGMT_WPS:
-		return KEY_MGMT_WPS;
-	case WPA_KEY_MGMT_PSK:
-	default:
-		return KEY_MGMT_PSK;
-	}
-}
-
-
-static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
-					 struct wpa_ssid *ssid,
-					 struct wpa_ie_data *ie)
-{
-	int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
-	if (ret) {
-		if (ret == -2) {
-			wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
-				"from association info");
-		}
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher "
-		   "suites");
-	if (!(ie->group_cipher & ssid->group_cipher)) {
-		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
-			"cipher 0x%x (mask 0x%x) - reject",
-			ie->group_cipher, ssid->group_cipher);
-		return -1;
-	}
-	if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
-		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
-			"cipher 0x%x (mask 0x%x) - reject",
-			ie->pairwise_cipher, ssid->pairwise_cipher);
-		return -1;
-	}
-	if (!(ie->key_mgmt & ssid->key_mgmt)) {
-		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
-			"management 0x%x (mask 0x%x) - reject",
-			ie->key_mgmt, ssid->key_mgmt);
-		return -1;
-	}
-
-#ifdef CONFIG_IEEE80211W
-	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
-	    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
-		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
-			"that does not support management frame protection - "
-			"reject");
-		return -1;
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_set_suites - Set authentication and encryption parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * @bss: Scan results for the selected BSS, or %NULL if not available
- * @ssid: Configuration data for the selected network
- * @wpa_ie: Buffer for the WPA/RSN IE
- * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
- * used buffer length in case the functions returns success.
- * Returns: 0 on success or -1 on failure
- *
- * This function is used to configure authentication and encryption parameters
- * based on the network configuration and scan result for the selected BSS (if
- * available).
- */
-int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *bss, struct wpa_ssid *ssid,
-			      u8 *wpa_ie, size_t *wpa_ie_len)
-{
-	struct wpa_ie_data ie;
-	int sel, proto;
-	const u8 *bss_wpa, *bss_rsn;
-
-	if (bss) {
-		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	} else
-		bss_wpa = bss_rsn = NULL;
-
-	if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
-	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
-	    (ie.group_cipher & ssid->group_cipher) &&
-	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
-	    (ie.key_mgmt & ssid->key_mgmt)) {
-		wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
-		proto = WPA_PROTO_RSN;
-	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
-		   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
-		   (ie.group_cipher & ssid->group_cipher) &&
-		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
-		   (ie.key_mgmt & ssid->key_mgmt)) {
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
-		proto = WPA_PROTO_WPA;
-	} else if (bss) {
-		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
-		return -1;
-	} else {
-		if (ssid->proto & WPA_PROTO_RSN)
-			proto = WPA_PROTO_RSN;
-		else
-			proto = WPA_PROTO_WPA;
-		if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
-			os_memset(&ie, 0, sizeof(ie));
-			ie.group_cipher = ssid->group_cipher;
-			ie.pairwise_cipher = ssid->pairwise_cipher;
-			ie.key_mgmt = ssid->key_mgmt;
-#ifdef CONFIG_IEEE80211W
-			ie.mgmt_group_cipher =
-				ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
-				WPA_CIPHER_AES_128_CMAC : 0;
-#endif /* CONFIG_IEEE80211W */
-			wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based "
-				   "on configuration");
-		} else
-			proto = ie.proto;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
-		   "pairwise %d key_mgmt %d proto %d",
-		   ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
-#ifdef CONFIG_IEEE80211W
-	if (ssid->ieee80211w) {
-		wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
-			   ie.mgmt_group_cipher);
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
-			 !!(ssid->proto & WPA_PROTO_RSN));
-
-	if (bss || !wpa_s->ap_ies_from_associnfo) {
-		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
-					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
-		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
-					 bss_rsn ? 2 + bss_rsn[1] : 0))
-			return -1;
-	}
-
-	sel = ie.group_cipher & ssid->group_cipher;
-	if (sel & WPA_CIPHER_CCMP) {
-		wpa_s->group_cipher = WPA_CIPHER_CCMP;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
-	} else if (sel & WPA_CIPHER_TKIP) {
-		wpa_s->group_cipher = WPA_CIPHER_TKIP;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
-	} else if (sel & WPA_CIPHER_WEP104) {
-		wpa_s->group_cipher = WPA_CIPHER_WEP104;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
-	} else if (sel & WPA_CIPHER_WEP40) {
-		wpa_s->group_cipher = WPA_CIPHER_WEP40;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
-		return -1;
-	}
-
-	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
-	if (sel & WPA_CIPHER_CCMP) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
-	} else if (sel & WPA_CIPHER_TKIP) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
-	} else if (sel & WPA_CIPHER_NONE) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
-			   "cipher.");
-		return -1;
-	}
-
-	sel = ie.key_mgmt & ssid->key_mgmt;
-	if (0) {
-#ifdef CONFIG_IEEE80211R
-	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
-	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
-		wpa_msg(wpa_s, MSG_DEBUG,
-			"WPA: using KEY_MGMT 802.1X with SHA256");
-	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
-		wpa_msg(wpa_s, MSG_DEBUG,
-			"WPA: using KEY_MGMT PSK with SHA256");
-#endif /* CONFIG_IEEE80211W */
-	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
-	} else if (sel & WPA_KEY_MGMT_PSK) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
-	} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
-			   "key management type.");
-		return -1;
-	}
-
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
-			 wpa_s->pairwise_cipher);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
-
-#ifdef CONFIG_IEEE80211W
-	sel = ie.mgmt_group_cipher;
-	if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
-	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
-		sel = 0;
-	if (sel & WPA_CIPHER_AES_128_CMAC) {
-		wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
-			"AES-128-CMAC");
-	} else {
-		wpa_s->mgmt_group_cipher = 0;
-		wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
-	}
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
-			 wpa_s->mgmt_group_cipher);
-	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
-#endif /* CONFIG_IEEE80211W */
-
-	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
-		return -1;
-	}
-
-	if (ssid->key_mgmt &
-	    (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
-		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
-	else
-		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_associate - Request association
- * @wpa_s: Pointer to wpa_supplicant data
- * @bss: Scan results for the selected BSS, or %NULL if not available
- * @ssid: Configuration data for the selected network
- *
- * This function is used to request %wpa_supplicant to associate with a BSS.
- */
-void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *bss, struct wpa_ssid *ssid)
-{
-	u8 wpa_ie[80];
-	size_t wpa_ie_len;
-	int use_crypt, ret, i, bssid_changed;
-	int algs = WPA_AUTH_ALG_OPEN;
-	enum wpa_cipher cipher_pairwise, cipher_group;
-	struct wpa_driver_associate_params params;
-	int wep_keys_set = 0;
-	struct wpa_driver_capa capa;
-	int assoc_failed = 0;
-	struct wpa_ssid *old_ssid;
-
-	if (ssid->mode == WPAS_MODE_AP) {
-#ifdef CONFIG_AP
-		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
-			wpa_printf(MSG_INFO, "Driver does not support AP "
-				   "mode");
-			return;
-		}
-		wpa_supplicant_create_ap(wpa_s, ssid);
-		wpa_s->current_bss = bss;
-#else /* CONFIG_AP */
-		wpa_printf(MSG_ERROR, "AP mode support not included in the "
-			   "build");
-#endif /* CONFIG_AP */
-		return;
-	}
-
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
-	    ssid->mode == IEEE80211_MODE_INFRA) {
-		sme_authenticate(wpa_s, bss, ssid);
-		return;
-	}
-
-	wpa_s->reassociate = 0;
-	if (bss) {
-#ifdef CONFIG_IEEE80211R
-		const u8 *ie, *md = NULL;
-#endif /* CONFIG_IEEE80211R */
-		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
-			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
-			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
-		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
-		os_memset(wpa_s->bssid, 0, ETH_ALEN);
-		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
-		if (bssid_changed)
-			wpas_notify_bssid_changed(wpa_s);
-#ifdef CONFIG_IEEE80211R
-		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
-		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
-			md = ie + 2;
-		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
-		if (md) {
-			/* Prepare for the next transition */
-			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
-		}
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_WPS
-	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
-		   wpa_s->conf->ap_scan == 2 &&
-		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
-		/* Use ap_scan==1 style network selection to find the network
-		 */
-		wpa_s->scan_req = 2;
-		wpa_s->reassociate = 1;
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-		return;
-#endif /* CONFIG_WPS */
-	} 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);
-	}
-	wpa_supplicant_cancel_scan(wpa_s);
-
-	/* Starting new association, so clear the possibly used WPA IE from the
-	 * previous association. */
-	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-
-#ifdef IEEE8021X_EAPOL
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		if (ssid->leap) {
-			if (ssid->non_leap == 0)
-				algs = WPA_AUTH_ALG_LEAP;
-			else
-				algs |= WPA_AUTH_ALG_LEAP;
-		}
-	}
-#endif /* IEEE8021X_EAPOL */
-	wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
-	if (ssid->auth_alg) {
-		algs = ssid->auth_alg;
-		wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
-			   algs);
-	}
-
-	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
-		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-			       WPA_KEY_MGMT_FT_IEEE8021X |
-			       WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			       WPA_KEY_MGMT_PSK_SHA256))) {
-		int try_opportunistic;
-		try_opportunistic = ssid->proactive_key_caching &&
-			(ssid->proto & WPA_PROTO_RSN);
-		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
-					    wpa_s->current_ssid,
-					    try_opportunistic) == 0)
-			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
-		wpa_ie_len = sizeof(wpa_ie);
-		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
-					      wpa_ie, &wpa_ie_len)) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
-				   "management and encryption suites");
-			return;
-		}
-	} else if (ssid->key_mgmt &
-		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
-		wpa_ie_len = sizeof(wpa_ie);
-		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
-					      wpa_ie, &wpa_ie_len)) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
-				   "management and encryption suites (no scan "
-				   "results)");
-			return;
-		}
-#ifdef CONFIG_WPS
-	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-		struct wpabuf *wps_ie;
-		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
-		if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
-			wpa_ie_len = wpabuf_len(wps_ie);
-			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
-		} else
-			wpa_ie_len = 0;
-		wpabuf_free(wps_ie);
-		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
-#endif /* CONFIG_WPS */
-	} else {
-		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
-		wpa_ie_len = 0;
-	}
-
-	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
-	use_crypt = 1;
-	cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
-	cipher_group = cipher_suite2driver(wpa_s->group_cipher);
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
-			use_crypt = 0;
-		if (wpa_set_wep_keys(wpa_s, ssid)) {
-			use_crypt = 1;
-			wep_keys_set = 1;
-		}
-	}
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
-		use_crypt = 0;
-
-#ifdef IEEE8021X_EAPOL
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		if ((ssid->eapol_flags &
-		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
-		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
-		    !wep_keys_set) {
-			use_crypt = 0;
-		} else {
-			/* Assume that dynamic WEP-104 keys will be used and
-			 * set cipher suites in order for drivers to expect
-			 * encryption. */
-			cipher_pairwise = cipher_group = CIPHER_WEP104;
-		}
-	}
-#endif /* IEEE8021X_EAPOL */
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
-		/* Set the key before (and later after) association */
-		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
-	}
-
-	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
-	os_memset(&params, 0, sizeof(params));
-	if (bss) {
-		params.bssid = bss->bssid;
-		params.ssid = bss->ssid;
-		params.ssid_len = bss->ssid_len;
-		params.freq = bss->freq;
-	} else {
-		params.ssid = ssid->ssid;
-		params.ssid_len = ssid->ssid_len;
-	}
-	if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
-	    params.freq == 0)
-		params.freq = ssid->frequency; /* Initial channel for IBSS */
-	params.wpa_ie = wpa_ie;
-	params.wpa_ie_len = wpa_ie_len;
-	params.pairwise_suite = cipher_pairwise;
-	params.group_suite = cipher_group;
-	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
-	params.auth_alg = algs;
-	params.mode = ssid->mode;
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i])
-			params.wep_key[i] = ssid->wep_key[i];
-		params.wep_key_len[i] = ssid->wep_key_len[i];
-	}
-	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
-
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
-	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
-	     params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
-		params.passphrase = ssid->passphrase;
-		if (ssid->psk_set)
-			params.psk = ssid->psk;
-	}
-
-	params.drop_unencrypted = use_crypt;
-
-#ifdef CONFIG_IEEE80211W
-	params.mgmt_frame_protection = ssid->ieee80211w;
-	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
-		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-		struct wpa_ie_data ie;
-		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
-		    ie.capabilities &
-		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
-			wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
-				   "require MFP");
-			params.mgmt_frame_protection =
-				MGMT_FRAME_PROTECTION_REQUIRED;
-		}
-	}
-#endif /* CONFIG_IEEE80211W */
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_associate(wpa_s, &params);
-	else
-		ret = wpa_drv_associate(wpa_s, &params);
-	if (ret < 0) {
-		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
-			"failed");
-		/* try to continue anyway; new association will be tried again
-		 * after timeout */
-		assoc_failed = 1;
-	}
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
-		/* Set the key after the association just in case association
-		 * cleared the previously configured key. */
-		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
-		/* No need to timeout authentication since there is no key
-		 * management. */
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-#ifdef CONFIG_IBSS_RSN
-	} else if (ssid->mode == WPAS_MODE_IBSS &&
-		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
-		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
-		ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
-		/*
-		 * RSN IBSS authentication is per-STA and we can disable the
-		 * per-BSSID authentication.
-		 */
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-#endif /* CONFIG_IBSS_RSN */
-	} else {
-		/* Timeout for IEEE 802.11 authentication and association */
-		int timeout = 60;
-
-		if (assoc_failed) {
-			/* give IBSS a bit more time */
-			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
-		} else if (wpa_s->conf->ap_scan == 1) {
-			/* give IBSS a bit more time */
-			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
-		}
-		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
-	}
-
-	if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
-	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
-		/* Set static WEP keys again */
-		wpa_set_wep_keys(wpa_s, ssid);
-	}
-
-	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
-		/*
-		 * Do not allow EAP session resumption between different
-		 * network configurations.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	}
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = ssid;
-	wpa_s->current_bss = bss;
-	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)
-		wpas_notify_network_changed(wpa_s);
-}
-
-
-/**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-				 int reason_code)
-{
-	struct wpa_ssid *old_ssid;
-	u8 *addr = NULL;
-
-	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-			ieee80211_sta_disassociate(wpa_s, reason_code);
-		else
-			wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
-		addr = wpa_s->bssid;
-	}
-	wpa_clear_keys(wpa_s, addr);
-	wpa_supplicant_mark_disassoc(wpa_s);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = NULL;
-	wpa_s->current_bss = NULL;
-	wpa_sm_set_config(wpa_s->wpa, NULL);
-	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-	if (old_ssid != wpa_s->current_ssid)
-		wpas_notify_network_changed(wpa_s);
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-}
-
-
-/**
- * wpa_supplicant_deauthenticate - Deauthenticate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
- *
- * This function is used to request %wpa_supplicant to deauthenticate from the
- * current AP.
- */
-void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
-				   int reason_code)
-{
-	struct wpa_ssid *old_ssid;
-	u8 *addr = NULL;
-
-	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-			ieee80211_sta_deauthenticate(wpa_s, reason_code);
-		else
-			wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-					       reason_code);
-		addr = wpa_s->bssid;
-	}
-	wpa_clear_keys(wpa_s, addr);
-	wpa_supplicant_mark_disassoc(wpa_s);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = NULL;
-	wpa_s->current_bss = NULL;
-	wpa_sm_set_config(wpa_s->wpa, NULL);
-	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-	if (old_ssid != wpa_s->current_ssid)
-		wpas_notify_network_changed(wpa_s);
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-}
-
-
-/**
- * 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
- *
- * Enables the specified network or all networks if no network specified.
- */
-void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid)
-{
-	struct wpa_ssid *other_ssid;
-	int was_disabled;
-
-	if (ssid == NULL) {
-		other_ssid = wpa_s->conf->ssid;
-		while (other_ssid) {
-			if (other_ssid == wpa_s->current_ssid &&
-			    other_ssid->disabled)
-				wpa_s->reassociate = 1;
-
-			was_disabled = other_ssid->disabled;
-
-			other_ssid->disabled = 0;
-
-			if (was_disabled != other_ssid->disabled)
-				wpas_notify_network_enabled_changed(
-					wpa_s, other_ssid);
-
-			other_ssid = other_ssid->next;
-		}
-		if (wpa_s->reassociate)
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-	} else if (ssid->disabled) {
-		if (wpa_s->current_ssid == NULL) {
-			/*
-			 * Try to reassociate since there is no current
-			 * configuration and a new network was made available.
-			 */
-			wpa_s->reassociate = 1;
-			wpa_supplicant_req_scan(wpa_s, 0, 0);
-		}
-
-		was_disabled = ssid->disabled;
-
-		ssid->disabled = 0;
-
-		if (was_disabled != ssid->disabled)
-			wpas_notify_network_enabled_changed(wpa_s, ssid);
-	}
-}
-
-
-/**
- * wpa_supplicant_disable_network - Mark a configured network as disabled
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network or %NULL
- *
- * Disables the specified network or all networks if no network specified.
- */
-void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
-				    struct wpa_ssid *ssid)
-{
-	struct wpa_ssid *other_ssid;
-	int was_disabled;
-
-	if (ssid == NULL) {
-		other_ssid = wpa_s->conf->ssid;
-		while (other_ssid) {
-			was_disabled = other_ssid->disabled;
-
-			other_ssid->disabled = 1;
-
-			if (was_disabled != other_ssid->disabled)
-				wpas_notify_network_enabled_changed(
-					wpa_s, other_ssid);
-
-			other_ssid = other_ssid->next;
-		}
-		if (wpa_s->current_ssid)
-			wpa_supplicant_disassociate(
-				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-	} else {
-		if (ssid == wpa_s->current_ssid)
-			wpa_supplicant_disassociate(
-				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
-		was_disabled = ssid->disabled;
-
-		ssid->disabled = 1;
-
-		if (was_disabled != ssid->disabled)
-			wpas_notify_network_enabled_changed(wpa_s, ssid);
-	}
-}
-
-
-/**
- * wpa_supplicant_select_network - Attempt association with a network
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ssid: wpa_ssid structure for a configured network or %NULL for any network
- */
-void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid)
-{
-
-	struct wpa_ssid *other_ssid;
-
-	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
-		wpa_supplicant_disassociate(
-			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
-	/*
-	 * Mark all other networks disabled or mark all networks enabled if no
-	 * network specified.
-	 */
-	other_ssid = wpa_s->conf->ssid;
-	while (other_ssid) {
-		int was_disabled = other_ssid->disabled;
-
-		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
-
-		if (was_disabled != other_ssid->disabled)
-			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
-
-		other_ssid = other_ssid->next;
-	}
-	wpa_s->disconnected = 0;
-	wpa_s->reassociate = 1;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-
-	if (ssid)
-		wpas_notify_network_selected(wpa_s, ssid);
-}
-
-
-/**
- * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
- * @wpa_s: wpa_supplicant structure for a network interface
- * @ap_scan: AP scan mode
- * Returns: 0 if succeed or -1 if ap_scan has an invalid value
- *
- */
-int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
-{
-
-	int old_ap_scan;
-
-	if (ap_scan < 0 || ap_scan > 2)
-		return -1;
-
-	old_ap_scan = wpa_s->conf->ap_scan;
-	wpa_s->conf->ap_scan = ap_scan;
-
-	if (old_ap_scan != wpa_s->conf->ap_scan)
-		wpas_notify_ap_scan_changed(wpa_s);
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_set_debug_params - Set global debug params
- * @global: wpa_global structure
- * @debug_level: debug level
- * @debug_timestamp: determines if show timestamp in debug data
- * @debug_show_keys: determines if show keys in debug data
- * Returns: 0 if succeed or -1 if debug_level has wrong value
- */
-int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
-				    int debug_timestamp, int debug_show_keys)
-{
-
-	int old_level, old_timestamp, old_show_keys;
-
-	/* check for allowed debuglevels */
-	if (debug_level != MSG_MSGDUMP &&
-	    debug_level != MSG_DEBUG &&
-	    debug_level != MSG_INFO &&
-	    debug_level != MSG_WARNING &&
-	    debug_level != MSG_ERROR)
-		return -1;
-
-	old_level = wpa_debug_level;
-	old_timestamp = wpa_debug_timestamp;
-	old_show_keys = wpa_debug_show_keys;
-
-	wpa_debug_level = debug_level;
-	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
-	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
-
-	if (wpa_debug_level != old_level)
-		wpas_notify_debug_level_changed(global);
-	if (wpa_debug_timestamp != old_timestamp)
-		wpas_notify_debug_timestamp_changed(global);
-	if (wpa_debug_show_keys != old_show_keys)
-		wpas_notify_debug_show_keys_changed(global);
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_get_ssid - Get a pointer to the current network structure
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: A pointer to the current network structure or %NULL on failure
- */
-struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *entry;
-	u8 ssid[MAX_SSID_LEN];
-	int res;
-	size_t ssid_len;
-	u8 bssid[ETH_ALEN];
-	int wired;
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-		if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
-			wpa_printf(MSG_WARNING, "Could not read SSID from "
-				   "MLME.");
-			return NULL;
-		}
-	} else {
-		res = wpa_drv_get_ssid(wpa_s, ssid);
-		if (res < 0) {
-			wpa_printf(MSG_WARNING, "Could not read SSID from "
-				   "driver.");
-			return NULL;
-		}
-		ssid_len = res;
-	}
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-	else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
-		wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
-		return NULL;
-	}
-
-	wired = wpa_s->conf->ap_scan == 0 &&
-		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
-
-	entry = wpa_s->conf->ssid;
-	while (entry) {
-		if (!entry->disabled &&
-		    ((ssid_len == entry->ssid_len &&
-		      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
-		    (!entry->bssid_set ||
-		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
-			return entry;
-#ifdef CONFIG_WPS
-		if (!entry->disabled &&
-		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
-		    (entry->ssid == NULL || entry->ssid_len == 0) &&
-		    (!entry->bssid_set ||
-		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
-			return entry;
-#endif /* CONFIG_WPS */
-		entry = entry->next;
-	}
-
-	return NULL;
-}
-
-
-static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
-				     const char *name)
-{
-	int i;
-	size_t len;
-	const char *pos;
-
-	if (wpa_s == NULL)
-		return -1;
-
-	if (wpa_drivers[0] == NULL) {
-		wpa_printf(MSG_ERROR, "No driver interfaces build into "
-			   "wpa_supplicant.");
-		return -1;
-	}
-
-	if (name == NULL) {
-		/* default to first driver in the list */
-		wpa_s->driver = wpa_drivers[0];
-		wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
-		return 0;
-	}
-
-	pos = os_strchr(name, ',');
-	if (pos)
-		len = pos - name;
-	else
-		len = os_strlen(name);
-	for (i = 0; wpa_drivers[i]; i++) {
-		if (os_strlen(wpa_drivers[i]->name) == len &&
-		    os_strncmp(name, wpa_drivers[i]->name, len) ==
-		    0) {
-			wpa_s->driver = wpa_drivers[i];
-			wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
-			return 0;
-		}
-	}
-
-	wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
-	return -1;
-}
-
-
-/**
- * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
- * @ctx: Context pointer (wpa_s); this is the ctx variable registered
- *	with struct wpa_driver_ops::init()
- * @src_addr: Source address of the EAPOL frame
- * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
- * @len: Length of the EAPOL data
- *
- * This function is called for each received EAPOL frame. Most driver
- * interfaces rely on more generic OS mechanism for receiving frames through
- * l2_packet, but if such a mechanism is not available, the driver wrapper may
- * take care of received EAPOL frames and deliver them to the core supplicant
- * code by calling this function.
- */
-void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-
-	wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
-	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
-
-	if (wpa_s->wpa_state < WPA_ASSOCIATED) {
-		/*
-		 * There is possible race condition between receiving the
-		 * association event and the EAPOL frame since they are coming
-		 * through different paths from the driver. In order to avoid
-		 * issues in trying to process the EAPOL frame before receiving
-		 * association information, lets queue it for processing until
-		 * the association event is received.
-		 */
-		wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
-			   "received EAPOL frame");
-		wpabuf_free(wpa_s->pending_eapol_rx);
-		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
-		if (wpa_s->pending_eapol_rx) {
-			os_get_time(&wpa_s->pending_eapol_rx_time);
-			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
-				  ETH_ALEN);
-		}
-		return;
-	}
-
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface) {
-		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
-		return;
-	}
-#endif /* CONFIG_AP */
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
-		wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
-			   "no key management is configured");
-		return;
-	}
-
-	if (wpa_s->eapol_received == 0 &&
-	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
-	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
-	     wpa_s->wpa_state != WPA_COMPLETED) &&
-	    (wpa_s->current_ssid == NULL ||
-	     wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
-		/* Timeout for completing IEEE 802.1X and WPA authentication */
-		wpa_supplicant_req_auth_timeout(
-			wpa_s,
-			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
-			 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
-			70 : 10, 0);
-	}
-	wpa_s->eapol_received++;
-
-	if (wpa_s->countermeasures) {
-		wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
-			   "packet");
-		return;
-	}
-
-#ifdef CONFIG_IBSS_RSN
-	if (wpa_s->current_ssid &&
-	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
-		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
-		return;
-	}
-#endif /* CONFIG_IBSS_RSN */
-
-	/* Source address of the incoming EAPOL frame could be compared to the
-	 * current BSSID. However, it is possible that a centralized
-	 * Authenticator could be using another MAC address than the BSSID of
-	 * an AP, so just allow any address to be used for now. The replies are
-	 * still sent to the current BSSID (if available), though. */
-
-	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
-	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
-	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
-		return;
-	wpa_drv_poll(wpa_s);
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
-		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
-	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
-		/*
-		 * Set portValid = TRUE here since we are going to skip 4-way
-		 * handshake processing which would normally set portValid. We
-		 * need this to allow the EAPOL state machines to be completed
-		 * without going through EAPOL-Key handshake.
-		 */
-		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
-	}
-}
-
-
-/**
- * wpa_supplicant_driver_init - Initialize driver interface parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to initialize driver interface parameters.
- * wpa_drv_init() must have been called before this function to initialize the
- * driver interface.
- */
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
-{
-	static int interface_count = 0;
-
-	if (wpa_s->driver->send_eapol) {
-		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
-		if (addr)
-			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-	} else {
-		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
-					   wpa_drv_get_mac_addr(wpa_s),
-					   ETH_P_EAPOL,
-					   wpa_supplicant_rx_eapol, wpa_s, 0);
-		if (wpa_s->l2 == NULL)
-			return -1;
-	}
-
-	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
-		wpa_printf(MSG_ERROR, "Failed to get own L2 address");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
-		   MAC2STR(wpa_s->own_addr));
-
-	if (wpa_s->bridge_ifname[0]) {
-		wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
-			   " '%s'", wpa_s->bridge_ifname);
-		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
-					      wpa_s->own_addr,
-					      ETH_P_EAPOL,
-					      wpa_supplicant_rx_eapol, wpa_s,
-					      0);
-		if (wpa_s->l2_br == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
-				   "connection for the bridge interface '%s'",
-				   wpa_s->bridge_ifname);
-			return -1;
-		}
-	}
-
-	wpa_clear_keys(wpa_s, NULL);
-
-	/* Make sure that TKIP countermeasures are not left enabled (could
-	 * happen if wpa_supplicant is killed during countermeasures. */
-	wpa_drv_set_countermeasures(wpa_s, 0);
-
-	wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
-	wpa_drv_flush_pmkid(wpa_s);
-
-	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
-	if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-		wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
-		interface_count++;
-	} else
-		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-
-	return 0;
-}
-
-
-static int wpa_supplicant_daemon(const char *pid_file)
-{
-	wpa_printf(MSG_DEBUG, "Daemonize..");
-	return os_daemonize(pid_file);
-}
-
-
-static struct wpa_supplicant * wpa_supplicant_alloc(void)
-{
-	struct wpa_supplicant *wpa_s;
-
-	wpa_s = os_zalloc(sizeof(*wpa_s));
-	if (wpa_s == NULL)
-		return NULL;
-	wpa_s->scan_req = 1;
-	wpa_s->new_connection = 1;
-
-	return wpa_s;
-}
-
-
-static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
-				     struct wpa_interface *iface)
-{
-	const char *ifname, *driver;
-	struct wpa_driver_capa capa;
-
-	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
-		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
-		   iface->confname ? iface->confname : "N/A",
-		   iface->driver ? iface->driver : "default",
-		   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
-		   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
-
-	if (iface->confname) {
-#ifdef CONFIG_BACKEND_FILE
-		wpa_s->confname = os_rel2abs_path(iface->confname);
-		if (wpa_s->confname == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to get absolute path "
-				   "for configuration file '%s'.",
-				   iface->confname);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
-			   iface->confname, wpa_s->confname);
-#else /* CONFIG_BACKEND_FILE */
-		wpa_s->confname = os_strdup(iface->confname);
-#endif /* CONFIG_BACKEND_FILE */
-		wpa_s->conf = wpa_config_read(wpa_s->confname);
-		if (wpa_s->conf == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to read or parse "
-				   "configuration '%s'.", wpa_s->confname);
-			return -1;
-		}
-
-		/*
-		 * Override ctrl_interface and driver_param if set on command
-		 * line.
-		 */
-		if (iface->ctrl_interface) {
-			os_free(wpa_s->conf->ctrl_interface);
-			wpa_s->conf->ctrl_interface =
-				os_strdup(iface->ctrl_interface);
-		}
-
-		if (iface->driver_param) {
-			os_free(wpa_s->conf->driver_param);
-			wpa_s->conf->driver_param =
-				os_strdup(iface->driver_param);
-		}
-	} else
-		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
-						     iface->driver_param);
-
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "\nNo configuration found.");
-		return -1;
-	}
-
-	if (iface->ifname == NULL) {
-		wpa_printf(MSG_ERROR, "\nInterface name is required.");
-		return -1;
-	}
-	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
-		wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
-			   iface->ifname);
-		return -1;
-	}
-	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
-
-	if (iface->bridge_ifname) {
-		if (os_strlen(iface->bridge_ifname) >=
-		    sizeof(wpa_s->bridge_ifname)) {
-			wpa_printf(MSG_ERROR, "\nToo long bridge interface "
-				   "name '%s'.", iface->bridge_ifname);
-			return -1;
-		}
-		os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
-			   sizeof(wpa_s->bridge_ifname));
-	}
-
-	/* RSNA Supplicant Key Management - INITIALIZE */
-	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
-	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
-
-	/* Initialize driver interface and register driver event handler before
-	 * L2 receive handler so that association events are processed before
-	 * EAPOL-Key packets if both become available for the same select()
-	 * call. */
-	driver = iface->driver;
-next_driver:
-	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
-		return -1;
-
-	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
-	if (wpa_s->drv_priv == NULL) {
-		const char *pos;
-		pos = driver ? os_strchr(driver, ',') : NULL;
-		if (pos) {
-			wpa_printf(MSG_DEBUG, "Failed to initialize driver "
-				   "interface - try next driver wrapper");
-			driver = pos + 1;
-			goto next_driver;
-		}
-		wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
-		return -1;
-	}
-	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
-		wpa_printf(MSG_ERROR, "Driver interface rejected "
-			   "driver_param '%s'", wpa_s->conf->driver_param);
-		return -1;
-	}
-
-	ifname = wpa_drv_get_ifname(wpa_s);
-	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
-		wpa_printf(MSG_DEBUG, "Driver interface replaced interface "
-			   "name with '%s'", ifname);
-		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
-	}
-
-	if (wpa_supplicant_init_wpa(wpa_s) < 0)
-		return -1;
-
-	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
-			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
-			  NULL);
-	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
-
-	if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
-	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
-			     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
-		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
-			   "dot11RSNAConfigPMKLifetime");
-		return -1;
-	}
-
-	if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
-	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
-			     wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
-		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
-			"dot11RSNAConfigPMKReauthThreshold");
-		return -1;
-	}
-
-	if (wpa_s->conf->dot11RSNAConfigSATimeout &&
-	    wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
-			     wpa_s->conf->dot11RSNAConfigSATimeout)) {
-		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
-			   "dot11RSNAConfigSATimeout");
-		return -1;
-	}
-
-	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
-		wpa_s->drv_flags = capa.flags;
-		if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-			if (ieee80211_sta_init(wpa_s))
-				return -1;
-		}
-		wpa_s->max_scan_ssids = capa.max_scan_ssids;
-		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
-	}
-	if (wpa_s->max_remain_on_chan == 0)
-		wpa_s->max_remain_on_chan = 1000;
-
-	if (wpa_supplicant_driver_init(wpa_s) < 0)
-		return -1;
-
-	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
-	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
-		wpa_printf(MSG_DEBUG, "Failed to set country");
-		return -1;
-	}
-
-	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
-	if (wpas_wps_init(wpa_s))
-		return -1;
-
-	if (wpa_supplicant_init_eapol(wpa_s) < 0)
-		return -1;
-	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
-
-	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
-	if (wpa_s->ctrl_iface == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "Failed to initialize control interface '%s'.\n"
-			   "You may have another wpa_supplicant process "
-			   "already running or the file was\n"
-			   "left by an unclean termination of wpa_supplicant "
-			   "in which case you will need\n"
-			   "to manually remove this file before starting "
-			   "wpa_supplicant again.\n",
-			   wpa_s->conf->ctrl_interface);
-		return -1;
-	}
-
-#ifdef CONFIG_IBSS_RSN
-	wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
-	if (!wpa_s->ibss_rsn) {
-		wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN");
-		return -1;
-	}
-#endif /* CONFIG_IBSS_RSN */
-
-	if (wpa_bss_init(wpa_s) < 0)
-		return -1;
-
-	return 0;
-}
-
-
-static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
-					int notify)
-{
-	if (wpa_s->drv_priv) {
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-
-		wpa_drv_set_countermeasures(wpa_s, 0);
-		wpa_clear_keys(wpa_s, NULL);
-	}
-
-	wpa_supplicant_cleanup(wpa_s);
-
-	if (notify)
-		wpas_notify_iface_removed(wpa_s);
-
-	if (wpa_s->drv_priv)
-		wpa_drv_deinit(wpa_s);
-}
-
-
-/**
- * wpa_supplicant_add_iface - Add a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @iface: Interface configuration options
- * Returns: Pointer to the created interface or %NULL on failure
- *
- * This function is used to add new network interfaces for %wpa_supplicant.
- * This can be called before wpa_supplicant_run() to add interfaces before the
- * main event loop has been started. In addition, new interfaces can be added
- * dynamically while %wpa_supplicant is already running. This could happen,
- * e.g., when a hotplug network adapter is inserted.
- */
-struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
-						 struct wpa_interface *iface)
-{
-	struct wpa_supplicant *wpa_s;
-	struct wpa_interface t_iface;
-	struct wpa_ssid *ssid;
-
-	if (global == NULL || iface == NULL)
-		return NULL;
-
-	wpa_s = wpa_supplicant_alloc();
-	if (wpa_s == NULL)
-		return NULL;
-
-	wpa_s->global = global;
-
-	t_iface = *iface;
-	if (global->params.override_driver) {
-		wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
-			   "('%s' -> '%s')",
-			   iface->driver, global->params.override_driver);
-		t_iface.driver = global->params.override_driver;
-	}
-	if (global->params.override_ctrl_interface) {
-		wpa_printf(MSG_DEBUG, "Override interface parameter: "
-			   "ctrl_interface ('%s' -> '%s')",
-			   iface->ctrl_interface,
-			   global->params.override_ctrl_interface);
-		t_iface.ctrl_interface =
-			global->params.override_ctrl_interface;
-	}
-	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
-		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
-			   iface->ifname);
-		wpa_supplicant_deinit_iface(wpa_s, 0);
-		os_free(wpa_s);
-		return NULL;
-	}
-
-	/* Notify the control interfaces about new iface */
-	if (wpas_notify_iface_added(wpa_s)) {
-		wpa_supplicant_deinit_iface(wpa_s, 1);
-		os_free(wpa_s);
-		return NULL;
-	}
-
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-		wpas_notify_network_added(wpa_s, ssid);
-
-	wpa_s->next = global->ifaces;
-	global->ifaces = wpa_s;
-
-	wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
-
-	return wpa_s;
-}
-
-
-/**
- * wpa_supplicant_remove_iface - Remove a network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @wpa_s: Pointer to the network interface to be removed
- * Returns: 0 if interface was removed, -1 if interface was not found
- *
- * This function can be used to dynamically remove network interfaces from
- * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
- * addition, this function is used to remove all remaining interfaces when
- * %wpa_supplicant is terminated.
- */
-int wpa_supplicant_remove_iface(struct wpa_global *global,
-				struct wpa_supplicant *wpa_s)
-{
-	struct wpa_supplicant *prev;
-
-	/* Remove interface from the global list of interfaces */
-	prev = global->ifaces;
-	if (prev == wpa_s) {
-		global->ifaces = wpa_s->next;
-	} else {
-		while (prev && prev->next != wpa_s)
-			prev = prev->next;
-		if (prev == NULL)
-			return -1;
-		prev->next = wpa_s->next;
-	}
-
-	wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
-
-	wpa_supplicant_deinit_iface(wpa_s, 1);
-	os_free(wpa_s);
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_get_iface - Get a new network interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * @ifname: Interface name
- * Returns: Pointer to the interface or %NULL if not found
- */
-struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
-						 const char *ifname)
-{
-	struct wpa_supplicant *wpa_s;
-
-	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
-		if (os_strcmp(wpa_s->ifname, ifname) == 0)
-			return wpa_s;
-	}
-	return NULL;
-}
-
-
-/**
- * wpa_supplicant_init - Initialize %wpa_supplicant
- * @params: Parameters for %wpa_supplicant
- * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
- *
- * This function is used to initialize %wpa_supplicant. After successful
- * initialization, the returned data pointer can be used to add and remove
- * network interfaces, and eventually, to deinitialize %wpa_supplicant.
- */
-struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
-{
-	struct wpa_global *global;
-	int ret, i;
-
-	if (params == NULL)
-		return NULL;
-
-	wpa_debug_open_file(params->wpa_debug_file_path);
-	if (params->wpa_debug_syslog)
-		wpa_debug_open_syslog();
-
-	ret = eap_register_methods();
-	if (ret) {
-		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
-		if (ret == -2)
-			wpa_printf(MSG_ERROR, "Two or more EAP methods used "
-				   "the same EAP type.");
-		return NULL;
-	}
-
-	global = os_zalloc(sizeof(*global));
-	if (global == NULL)
-		return NULL;
-	global->params.daemonize = params->daemonize;
-	global->params.wait_for_monitor = params->wait_for_monitor;
-	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
-	if (params->pid_file)
-		global->params.pid_file = os_strdup(params->pid_file);
-	if (params->ctrl_interface)
-		global->params.ctrl_interface =
-			os_strdup(params->ctrl_interface);
-	if (params->override_driver)
-		global->params.override_driver =
-			os_strdup(params->override_driver);
-	if (params->override_ctrl_interface)
-		global->params.override_ctrl_interface =
-			os_strdup(params->override_ctrl_interface);
-	wpa_debug_level = global->params.wpa_debug_level =
-		params->wpa_debug_level;
-	wpa_debug_show_keys = global->params.wpa_debug_show_keys =
-		params->wpa_debug_show_keys;
-	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
-		params->wpa_debug_timestamp;
-
-	if (eloop_init()) {
-		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
-		wpa_supplicant_deinit(global);
-		return NULL;
-	}
-
-	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
-	if (global->ctrl_iface == NULL) {
-		wpa_supplicant_deinit(global);
-		return NULL;
-	}
-
-	if (wpas_notify_supplicant_initialized(global)) {
-		wpa_supplicant_deinit(global);
-		return NULL;
-	}
-
-	for (i = 0; wpa_drivers[i]; i++)
-		global->drv_count++;
-	if (global->drv_count == 0) {
-		wpa_printf(MSG_ERROR, "No drivers enabled");
-		wpa_supplicant_deinit(global);
-		return NULL;
-	}
-	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
-	if (global->drv_priv == NULL) {
-		wpa_supplicant_deinit(global);
-		return NULL;
-	}
-	for (i = 0; wpa_drivers[i]; i++) {
-		if (!wpa_drivers[i]->global_init)
-			continue;
-		global->drv_priv[i] = wpa_drivers[i]->global_init();
-		if (global->drv_priv[i] == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to initialize driver "
-				   "'%s'", wpa_drivers[i]->name);
-			wpa_supplicant_deinit(global);
-			return NULL;
-		}
-	}
-
-	return global;
-}
-
-
-/**
- * wpa_supplicant_run - Run the %wpa_supplicant main event loop
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 after successful event loop run, -1 on failure
- *
- * This function starts the main event loop and continues running as long as
- * there are any remaining events. In most cases, this function is running as
- * long as the %wpa_supplicant process in still in use.
- */
-int wpa_supplicant_run(struct wpa_global *global)
-{
-	struct wpa_supplicant *wpa_s;
-
-	if (global->params.daemonize &&
-	    wpa_supplicant_daemon(global->params.pid_file))
-		return -1;
-
-	if (global->params.wait_for_monitor) {
-		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
-			if (wpa_s->ctrl_iface)
-				wpa_supplicant_ctrl_iface_wait(
-					wpa_s->ctrl_iface);
-	}
-
-	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
-	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
-
-	eloop_run();
-
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
- * @global: Pointer to global data from wpa_supplicant_init()
- *
- * This function is called to deinitialize %wpa_supplicant and to free all
- * allocated resources. Remaining network interfaces will also be removed.
- */
-void wpa_supplicant_deinit(struct wpa_global *global)
-{
-	int i;
-
-	if (global == NULL)
-		return;
-
-	while (global->ifaces)
-		wpa_supplicant_remove_iface(global, global->ifaces);
-
-	if (global->ctrl_iface)
-		wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
-
-	wpas_notify_supplicant_deinitialized(global);
-
-	eap_peer_unregister_methods();
-#ifdef CONFIG_AP
-	eap_server_unregister_methods();
-#endif /* CONFIG_AP */
-
-	for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
-		if (!global->drv_priv[i])
-			continue;
-		wpa_drivers[i]->global_deinit(global->drv_priv[i]);
-	}
-	os_free(global->drv_priv);
-
-	eloop_destroy();
-
-	if (global->params.pid_file) {
-		os_daemonize_terminate(global->params.pid_file);
-		os_free(global->params.pid_file);
-	}
-	os_free(global->params.ctrl_interface);
-	os_free(global->params.override_driver);
-	os_free(global->params.override_ctrl_interface);
-
-	os_free(global);
-	wpa_debug_close_syslog();
-	wpa_debug_close_file();
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,3796 @@
+/*
+ * WPA Supplicant
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements functions for registering and unregistering
+ * %wpa_supplicant interfaces. In addition, this file contains number of
+ * functions for managing network connections.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
+#include "eap_server/eap_methods.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "utils/ext_password.h"
+#include "l2_packet/l2_packet.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ctrl_iface.h"
+#include "pcsc_funcs.h"
+#include "common/version.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
+#include "blacklist.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "sme.h"
+#include "gas_query.h"
+#include "ap.h"
+#include "p2p_supplicant.h"
+#include "wifi_display.h"
+#include "notify.h"
+#include "bgscan.h"
+#include "autoscan.h"
+#include "bss.h"
+#include "scan.h"
+#include "offchannel.h"
+#include "hs20_supplicant.h"
+
+const char *wpa_supplicant_version =
+"wpa_supplicant v" VERSION_STR "\n"
+"Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi> and contributors";
+
+const char *wpa_supplicant_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n"
+#ifdef EAP_TLS_OPENSSL
+"\nThis product includes software developed by the OpenSSL Project\n"
+"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
+#endif /* EAP_TLS_OPENSSL */
+;
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+/* Long text divided into parts in order to fit in C89 strings size limits. */
+const char *wpa_supplicant_full_license1 =
+"";
+const char *wpa_supplicant_full_license2 =
+"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";
+const char *wpa_supplicant_full_license3 =
+"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";
+const char *wpa_supplicant_full_license4 =
+"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";
+const char *wpa_supplicant_full_license5 =
+"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";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+extern struct wpa_driver_ops *wpa_drivers[];
+
+/* Configure default/group WEP keys for static WEP */
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	int i, set = 0;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i] == 0)
+			continue;
+
+		set = 1;
+		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+				i, i == ssid->wep_tx_keyidx, NULL, 0,
+				ssid->wep_key[i], ssid->wep_key_len[i]);
+	}
+
+	return set;
+}
+
+
+static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+					   struct wpa_ssid *ssid)
+{
+	u8 key[32];
+	size_t keylen;
+	enum wpa_alg alg;
+	u8 seq[6] = { 0 };
+
+	/* IBSS/WPA-None uses only one key (Group) for both receiving and
+	 * sending unicast and multicast packets. */
+
+	if (ssid->mode != WPAS_MODE_IBSS) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
+			"IBSS/ad-hoc) for WPA-None", ssid->mode);
+		return -1;
+	}
+
+	if (!ssid->psk_set) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
+			"WPA-None");
+		return -1;
+	}
+
+	switch (wpa_s->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		os_memcpy(key, ssid->psk, 16);
+		keylen = 16;
+		alg = WPA_ALG_CCMP;
+		break;
+	case WPA_CIPHER_GCMP:
+		os_memcpy(key, ssid->psk, 16);
+		keylen = 16;
+		alg = WPA_ALG_GCMP;
+		break;
+	case WPA_CIPHER_TKIP:
+		/* WPA-None uses the same Michael MIC key for both TX and RX */
+		os_memcpy(key, ssid->psk, 16 + 8);
+		os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
+		keylen = 32;
+		alg = WPA_ALG_TKIP;
+		break;
+	default:
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
+			"WPA-None", wpa_s->group_cipher);
+		return -1;
+	}
+
+	/* TODO: should actually remember the previously used seq#, both for TX
+	 * and RX from each STA.. */
+
+	return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+}
+
+
+static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	const u8 *bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
+		MAC2STR(bssid));
+	wpa_blacklist_add(wpa_s, bssid);
+	wpa_sm_notify_disassoc(wpa_s->wpa);
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_s->reassociate = 1;
+
+	/*
+	 * If we timed out, the AP or the local radio may be busy.
+	 * So, wait a second until scanning again.
+	 */
+	wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after timed out authentication");
+		}
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+/**
+ * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to time out authentication
+ * @usec: Number of microseconds after which to time out authentication
+ *
+ * This function is used to schedule a timeout for the current authentication
+ * attempt.
+ */
+void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
+				     int sec, int usec)
+{
+	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
+		"%d usec", sec, usec);
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel authentication timeout scheduled with
+ * wpa_supplicant_req_auth_timeout() and it is called when authentication has
+ * been completed.
+ */
+void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+	wpa_blacklist_del(wpa_s, wpa_s->bssid);
+}
+
+
+/**
+ * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to configure EAPOL state machine based on the selected
+ * authentication mode.
+ */
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eapol_config eapol_conf;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+#ifdef CONFIG_IBSS_RSN
+	if (ssid->mode == WPAS_MODE_IBSS &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * RSN IBSS authentication is per-STA and we can disable the
+		 * per-BSSID EAPOL authentication.
+		 */
+		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+		return;
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
+		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
+	else
+		eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+
+	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		eapol_conf.accept_802_1x_keys = 1;
+		eapol_conf.required_keys = 0;
+		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
+			eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
+		}
+		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
+			eapol_conf.required_keys |=
+				EAPOL_REQUIRE_KEY_BROADCAST;
+		}
+
+		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+			eapol_conf.required_keys = 0;
+	}
+	if (wpa_s->conf)
+		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_conf.eap_disabled =
+		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+/**
+ * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ *
+ * This function is used to configure WPA state machine and related parameters
+ * to a mode where WPA is not enabled. This is called as part of the
+ * authentication configuration when the selected network does not use WPA.
+ */
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid)
+{
+	int i;
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
+	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+	else
+		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
+	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+	wpa_s->group_cipher = WPA_CIPHER_NONE;
+	wpa_s->mgmt_group_cipher = 0;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i] > 5) {
+			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
+			wpa_s->group_cipher = WPA_CIPHER_WEP104;
+			break;
+		} else if (ssid->wep_key_len[i] > 0) {
+			wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
+			wpa_s->group_cipher = WPA_CIPHER_WEP40;
+			break;
+		}
+	}
+
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+			 wpa_s->pairwise_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+#ifdef CONFIG_IEEE80211W
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+			 wpa_s->mgmt_group_cipher);
+#endif /* CONFIG_IEEE80211W */
+
+	pmksa_cache_clear_current(wpa_s->wpa);
+}
+
+
+void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+	int i;
+	if (wpa_s->hw.modes == NULL)
+		return;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		os_free(wpa_s->hw.modes[i].channels);
+		os_free(wpa_s->hw.modes[i].rates);
+	}
+
+	os_free(wpa_s->hw.modes);
+	wpa_s->hw.modes = NULL;
+}
+
+
+static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
+{
+	bgscan_deinit(wpa_s);
+	autoscan_deinit(wpa_s);
+	scard_deinit(wpa_s->scard);
+	wpa_s->scard = NULL;
+	wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
+	l2_packet_deinit(wpa_s->l2);
+	wpa_s->l2 = NULL;
+	if (wpa_s->l2_br) {
+		l2_packet_deinit(wpa_s->l2_br);
+		wpa_s->l2_br = NULL;
+	}
+
+	if (wpa_s->conf != NULL) {
+		struct wpa_ssid *ssid;
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+			wpas_notify_network_removed(wpa_s, ssid);
+	}
+
+	os_free(wpa_s->confname);
+	wpa_s->confname = NULL;
+
+	wpa_sm_set_eapol(wpa_s->wpa, NULL);
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_s->eapol = NULL;
+
+	rsn_preauth_deinit(wpa_s->wpa);
+
+#ifdef CONFIG_TDLS
+	wpa_tdls_deinit(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
+	pmksa_candidate_free(wpa_s->wpa);
+	wpa_sm_deinit(wpa_s->wpa);
+	wpa_s->wpa = NULL;
+	wpa_blacklist_clear(wpa_s);
+
+	wpa_bss_deinit(wpa_s);
+
+	wpa_supplicant_cancel_scan(wpa_s);
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+	eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+			     wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+
+	wpas_wps_deinit(wpa_s);
+
+	wpabuf_free(wpa_s->pending_eapol_rx);
+	wpa_s->pending_eapol_rx = NULL;
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+	sme_deinit(wpa_s);
+
+#ifdef CONFIG_AP
+	wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+	wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_OFFCHANNEL
+	offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+
+	os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
+
+	gas_query_deinit(wpa_s->gas);
+	wpa_s->gas = NULL;
+
+	free_hw_features(wpa_s);
+
+	os_free(wpa_s->bssid_filter);
+	wpa_s->bssid_filter = NULL;
+
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = NULL;
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = NULL;
+
+	wnm_bss_keep_alive_deinit(wpa_s);
+
+	ext_password_deinit(wpa_s->ext_pw);
+	wpa_s->ext_pw = NULL;
+
+	wpabuf_free(wpa_s->last_gas_resp);
+
+	os_free(wpa_s->last_scan_res);
+	wpa_s->last_scan_res = NULL;
+}
+
+
+/**
+ * wpa_clear_keys - Clear keys configured for the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @addr: Previously used BSSID or %NULL if not available
+ *
+ * This function clears the encryption keys that has been previously configured
+ * for the driver.
+ */
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	if (wpa_s->keys_cleared) {
+		/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
+		 * timing issues with keys being cleared just before new keys
+		 * are set or just after association or something similar. This
+		 * shows up in group key handshake failing often because of the
+		 * client not receiving the first encrypted packets correctly.
+		 * Skipping some of the extra key clearing steps seems to help
+		 * in completing group key handshake more reliably. */
+		wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
+			"skip key clearing");
+		return;
+	}
+
+	/* MLME-DELETEKEYS.request */
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
+	if (addr) {
+		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
+				0);
+		/* MLME-SETPROTECTION.request(None) */
+		wpa_drv_mlme_setprotection(
+			wpa_s, addr,
+			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+	}
+	wpa_s->keys_cleared = 1;
+}
+
+
+/**
+ * wpa_supplicant_state_txt - Get the connection state name as a text string
+ * @state: State (wpa_state; WPA_*)
+ * Returns: The state name as a printable text string
+ */
+const char * wpa_supplicant_state_txt(enum wpa_states state)
+{
+	switch (state) {
+	case WPA_DISCONNECTED:
+		return "DISCONNECTED";
+	case WPA_INACTIVE:
+		return "INACTIVE";
+	case WPA_INTERFACE_DISABLED:
+		return "INTERFACE_DISABLED";
+	case WPA_SCANNING:
+		return "SCANNING";
+	case WPA_AUTHENTICATING:
+		return "AUTHENTICATING";
+	case WPA_ASSOCIATING:
+		return "ASSOCIATING";
+	case WPA_ASSOCIATED:
+		return "ASSOCIATED";
+	case WPA_4WAY_HANDSHAKE:
+		return "4WAY_HANDSHAKE";
+	case WPA_GROUP_HANDSHAKE:
+		return "GROUP_HANDSHAKE";
+	case WPA_COMPLETED:
+		return "COMPLETED";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+#ifdef CONFIG_BGSCAN
+
+static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_driver_bss_selection(wpa_s))
+		return;
+	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
+		return;
+
+	bgscan_deinit(wpa_s);
+	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+		if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+				"bgscan");
+			/*
+			 * Live without bgscan; it is only used as a roaming
+			 * optimization, so the initial connection is not
+			 * affected.
+			 */
+		} else {
+			struct wpa_scan_results *scan_res;
+			wpa_s->bgscan_ssid = wpa_s->current_ssid;
+			scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+								   0);
+			if (scan_res) {
+				bgscan_notify_scan(wpa_s, scan_res);
+				wpa_scan_results_free(scan_res);
+			}
+		}
+	} else
+		wpa_s->bgscan_ssid = NULL;
+}
+
+
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->bgscan_ssid != NULL) {
+		bgscan_deinit(wpa_s);
+		wpa_s->bgscan_ssid = NULL;
+	}
+}
+
+#endif /* CONFIG_BGSCAN */
+
+
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+	if (autoscan_init(wpa_s, 0))
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+	autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_SCANNING) {
+		autoscan_deinit(wpa_s);
+		wpa_supplicant_start_autoscan(wpa_s);
+	}
+}
+
+
+/**
+ * wpa_supplicant_set_state - Set current connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @state: The new connection state
+ *
+ * This function is called whenever the connection state changes, e.g.,
+ * association is completed for WPA/WPA2 4-Way Handshake is started.
+ */
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
+			      enum wpa_states state)
+{
+	enum wpa_states old_state = wpa_s->wpa_state;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
+		wpa_supplicant_state_txt(wpa_s->wpa_state),
+		wpa_supplicant_state_txt(state));
+
+	if (state != WPA_SCANNING)
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+
+	if (state == WPA_COMPLETED && wpa_s->new_connection) {
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+			MACSTR " completed [id=%d id_str=%s]",
+			MAC2STR(wpa_s->bssid),
+			ssid ? ssid->id : -1,
+			ssid && ssid->id_str ? ssid->id_str : "");
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+		wpa_s->extra_blacklist_count = 0;
+		wpa_s->new_connection = 0;
+		wpa_drv_set_operstate(wpa_s, 1);
+#ifndef IEEE8021X_EAPOL
+		wpa_drv_set_supp_port(wpa_s, 1);
+#endif /* IEEE8021X_EAPOL */
+		wpa_s->after_wps = 0;
+#ifdef CONFIG_P2P
+		wpas_p2p_completed(wpa_s);
+#endif /* CONFIG_P2P */
+
+		sme_sched_obss_scan(wpa_s, 1);
+	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+		   state == WPA_ASSOCIATED) {
+		wpa_s->new_connection = 1;
+		wpa_drv_set_operstate(wpa_s, 0);
+#ifndef IEEE8021X_EAPOL
+		wpa_drv_set_supp_port(wpa_s, 0);
+#endif /* IEEE8021X_EAPOL */
+		sme_sched_obss_scan(wpa_s, 0);
+	}
+	wpa_s->wpa_state = state;
+
+#ifdef CONFIG_BGSCAN
+	if (state == WPA_COMPLETED)
+		wpa_supplicant_start_bgscan(wpa_s);
+	else
+		wpa_supplicant_stop_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
+	if (state == WPA_AUTHENTICATING)
+		wpa_supplicant_stop_autoscan(wpa_s);
+
+	if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+		wpa_supplicant_start_autoscan(wpa_s);
+
+	if (wpa_s->wpa_state != old_state) {
+		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+
+		if (wpa_s->wpa_state == WPA_COMPLETED ||
+		    old_state == WPA_COMPLETED)
+			wpas_notify_auth_changed(wpa_s);
+	}
+}
+
+
+void wpa_supplicant_terminate_proc(struct wpa_global *global)
+{
+	int pending = 0;
+#ifdef CONFIG_WPS
+	struct wpa_supplicant *wpa_s = global->ifaces;
+	while (wpa_s) {
+		if (wpas_wps_terminate_pending(wpa_s) == 1)
+			pending = 1;
+		wpa_s = wpa_s->next;
+	}
+#endif /* CONFIG_WPS */
+	if (pending)
+		return;
+	eloop_terminate();
+}
+
+
+static void wpa_supplicant_terminate(int sig, void *signal_ctx)
+{
+	struct wpa_global *global = signal_ctx;
+	wpa_supplicant_terminate_proc(global);
+}
+
+
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+{
+	enum wpa_states old_state = wpa_s->wpa_state;
+
+	wpa_s->pairwise_cipher = 0;
+	wpa_s->group_cipher = 0;
+	wpa_s->mgmt_group_cipher = 0;
+	wpa_s->key_mgmt = 0;
+	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+	if (wpa_s->wpa_state != old_state)
+		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+}
+
+
+/**
+ * wpa_supplicant_reload_configuration - Reload configuration data
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success or -1 if configuration parsing failed
+ *
+ * This function can be used to request that the configuration data is reloaded
+ * (e.g., after configuration file change). This function is reloading
+ * configuration only for one interface, so this may need to be called multiple
+ * times if %wpa_supplicant is controlling multiple interfaces and all
+ * interfaces need reconfiguration.
+ */
+int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_config *conf;
+	int reconf_ctrl;
+	int old_ap_scan;
+
+	if (wpa_s->confname == NULL)
+		return -1;
+	conf = wpa_config_read(wpa_s->confname);
+	if (conf == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
+			"file '%s' - exiting", wpa_s->confname);
+		return -1;
+	}
+	conf->changed_parameters = (unsigned int) -1;
+
+	reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
+		|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
+		    os_strcmp(conf->ctrl_interface,
+			      wpa_s->conf->ctrl_interface) != 0);
+
+	if (reconf_ctrl && wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+
+	eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	if (wpa_s->current_ssid) {
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	/*
+	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
+	 * pkcs11_engine_path, pkcs11_module_path.
+	 */
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+		/*
+		 * Clear forced success to clear EAP state for next
+		 * authentication.
+		 */
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	}
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	wpa_sm_set_config(wpa_s->wpa, NULL);
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+	rsn_preauth_deinit(wpa_s->wpa);
+
+	old_ap_scan = wpa_s->conf->ap_scan;
+	wpa_config_free(wpa_s->conf);
+	wpa_s->conf = conf;
+	if (old_ap_scan != wpa_s->conf->ap_scan)
+		wpas_notify_ap_scan_changed(wpa_s);
+
+	if (reconf_ctrl)
+		wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+
+	wpa_supplicant_update_config(wpa_s);
+
+	wpa_supplicant_clear_status(wpa_s);
+	if (wpa_supplicant_enabled_networks(wpa_s)) {
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+	wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
+	return 0;
+}
+
+
+static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
+{
+	struct wpa_global *global = signal_ctx;
+	struct wpa_supplicant *wpa_s;
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
+			sig);
+		if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
+			wpa_supplicant_terminate_proc(global);
+		}
+	}
+}
+
+
+enum wpa_cipher cipher_suite2driver(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_NONE:
+		return CIPHER_NONE;
+	case WPA_CIPHER_WEP40:
+		return CIPHER_WEP40;
+	case WPA_CIPHER_WEP104:
+		return CIPHER_WEP104;
+	case WPA_CIPHER_CCMP:
+		return CIPHER_CCMP;
+	case WPA_CIPHER_GCMP:
+		return CIPHER_GCMP;
+	case WPA_CIPHER_TKIP:
+	default:
+		return CIPHER_TKIP;
+	}
+}
+
+
+enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
+{
+	switch (key_mgmt) {
+	case WPA_KEY_MGMT_NONE:
+		return KEY_MGMT_NONE;
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+		return KEY_MGMT_802_1X_NO_WPA;
+	case WPA_KEY_MGMT_IEEE8021X:
+		return KEY_MGMT_802_1X;
+	case WPA_KEY_MGMT_WPA_NONE:
+		return KEY_MGMT_WPA_NONE;
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return KEY_MGMT_FT_802_1X;
+	case WPA_KEY_MGMT_FT_PSK:
+		return KEY_MGMT_FT_PSK;
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return KEY_MGMT_PSK_SHA256;
+	case WPA_KEY_MGMT_WPS:
+		return KEY_MGMT_WPS;
+	case WPA_KEY_MGMT_PSK:
+	default:
+		return KEY_MGMT_PSK;
+	}
+}
+
+
+static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid,
+					 struct wpa_ie_data *ie)
+{
+	int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
+	if (ret) {
+		if (ret == -2) {
+			wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
+				"from association info");
+		}
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
+		"cipher suites");
+	if (!(ie->group_cipher & ssid->group_cipher)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
+			"cipher 0x%x (mask 0x%x) - reject",
+			ie->group_cipher, ssid->group_cipher);
+		return -1;
+	}
+	if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
+			"cipher 0x%x (mask 0x%x) - reject",
+			ie->pairwise_cipher, ssid->pairwise_cipher);
+		return -1;
+	}
+	if (!(ie->key_mgmt & ssid->key_mgmt)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
+			"management 0x%x (mask 0x%x) - reject",
+			ie->key_mgmt, ssid->key_mgmt);
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
+	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) ==
+	    MGMT_FRAME_PROTECTION_REQUIRED) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
+			"that does not support management frame protection - "
+			"reject");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_suites - Set authentication and encryption parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ * @wpa_ie: Buffer for the WPA/RSN IE
+ * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
+ * used buffer length in case the functions returns success.
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to configure authentication and encryption parameters
+ * based on the network configuration and scan result for the selected BSS (if
+ * available).
+ */
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid,
+			      u8 *wpa_ie, size_t *wpa_ie_len)
+{
+	struct wpa_ie_data ie;
+	int sel, proto;
+	const u8 *bss_wpa, *bss_rsn;
+
+	if (bss) {
+		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	} else
+		bss_wpa = bss_rsn = NULL;
+
+	if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
+	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
+	    (ie.group_cipher & ssid->group_cipher) &&
+	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+	    (ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
+		proto = WPA_PROTO_RSN;
+	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
+		   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+		   (ie.group_cipher & ssid->group_cipher) &&
+		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+		   (ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
+		proto = WPA_PROTO_WPA;
+	} else if (bss) {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+		return -1;
+	} else {
+		if (ssid->proto & WPA_PROTO_RSN)
+			proto = WPA_PROTO_RSN;
+		else
+			proto = WPA_PROTO_WPA;
+		if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
+			os_memset(&ie, 0, sizeof(ie));
+			ie.group_cipher = ssid->group_cipher;
+			ie.pairwise_cipher = ssid->pairwise_cipher;
+			ie.key_mgmt = ssid->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+			ie.mgmt_group_cipher =
+				ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
+				WPA_CIPHER_AES_128_CMAC : 0;
+#endif /* CONFIG_IEEE80211W */
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
+				"based on configuration");
+		} else
+			proto = ie.proto;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
+		"pairwise %d key_mgmt %d proto %d",
+		ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
+#ifdef CONFIG_IEEE80211W
+	if (ssid->ieee80211w) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
+			ie.mgmt_group_cipher);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_s->wpa_proto = proto;
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
+			 !!(ssid->proto & WPA_PROTO_RSN));
+
+	if (bss || !wpa_s->ap_ies_from_associnfo) {
+		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
+		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+					 bss_rsn ? 2 + bss_rsn[1] : 0))
+			return -1;
+	}
+
+	sel = ie.group_cipher & ssid->group_cipher;
+	if (sel & WPA_CIPHER_CCMP) {
+		wpa_s->group_cipher = WPA_CIPHER_CCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+	} else if (sel & WPA_CIPHER_GCMP) {
+		wpa_s->group_cipher = WPA_CIPHER_GCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
+	} else if (sel & WPA_CIPHER_TKIP) {
+		wpa_s->group_cipher = WPA_CIPHER_TKIP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
+	} else if (sel & WPA_CIPHER_WEP104) {
+		wpa_s->group_cipher = WPA_CIPHER_WEP104;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
+	} else if (sel & WPA_CIPHER_WEP40) {
+		wpa_s->group_cipher = WPA_CIPHER_WEP40;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
+			"cipher");
+		return -1;
+	}
+
+	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
+	if (sel & WPA_CIPHER_CCMP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+	} else if (sel & WPA_CIPHER_GCMP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
+	} else if (sel & WPA_CIPHER_TKIP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
+	} else if (sel & WPA_CIPHER_NONE) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
+			"cipher");
+		return -1;
+	}
+
+	sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
+	if (0) {
+#ifdef CONFIG_IEEE80211R
+	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	} else if (sel & WPA_KEY_MGMT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+	} else if (sel & WPA_KEY_MGMT_FT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211W
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT 802.1X with SHA256");
+	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT PSK with SHA256");
+#endif /* CONFIG_IEEE80211W */
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
+	} else if (sel & WPA_KEY_MGMT_PSK) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
+	} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
+			"authenticated key management type");
+		return -1;
+	}
+
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+			 wpa_s->pairwise_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+
+#ifdef CONFIG_IEEE80211W
+	sel = ie.mgmt_group_cipher;
+	if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
+		sel = 0;
+	if (sel & WPA_CIPHER_AES_128_CMAC) {
+		wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+			"AES-128-CMAC");
+	} else {
+		wpa_s->mgmt_group_cipher = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+	}
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+			 wpa_s->mgmt_group_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+			 (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+			  wpa_s->conf->pmf : ssid->ieee80211w));
+#endif /* CONFIG_IEEE80211W */
+
+	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
+		return -1;
+	}
+
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+#ifndef CONFIG_NO_PBKDF2
+		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
+		    ssid->passphrase) {
+			u8 psk[PMK_LEN];
+		        pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+				    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);
+		}
+#endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+		if (ssid->ext_psk) {
+			struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+							     ssid->ext_psk);
+			char pw_str[64 + 1];
+			u8 psk[PMK_LEN];
+
+			if (pw == NULL) {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+					"found from external storage");
+				return -1;
+			}
+
+			if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+					"PSK length %d in external storage",
+					(int) wpabuf_len(pw));
+				ext_password_free(pw);
+				return -1;
+			}
+
+			os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+			pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+			if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+			{
+				pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+					    4096, psk, PMK_LEN);
+				os_memset(pw_str, 0, sizeof(pw_str));
+				wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+						"external passphrase)",
+						psk, PMK_LEN);
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+			} else
+#endif /* CONFIG_NO_PBKDF2 */
+			if (wpabuf_len(pw) == 2 * PMK_LEN) {
+				if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+					wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+						"Invalid PSK hex string");
+					os_memset(pw_str, 0, sizeof(pw_str));
+					ext_password_free(pw);
+					return -1;
+				}
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+			} else {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+					"PSK available");
+				os_memset(pw_str, 0, sizeof(pw_str));
+				ext_password_free(pw);
+				return -1;
+			}
+
+			os_memset(pw_str, 0, sizeof(pw_str));
+			ext_password_free(pw);
+		}
+#endif /* CONFIG_EXT_PASSWORD */
+	} else
+		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+
+	return 0;
+}
+
+
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+	u32 ext_capab = 0;
+	u8 *pos = buf;
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking)
+		ext_capab |= BIT(31); /* Interworking */
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WNM
+	ext_capab |= BIT(17); /* WNM-Sleep Mode */
+	ext_capab |= BIT(19); /* BSS Transition */
+#endif /* CONFIG_WNM */
+
+	if (!ext_capab)
+		return 0;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = 4;
+	WPA_PUT_LE32(pos, ext_capab);
+	pos += 4;
+
+	return pos - buf;
+}
+
+
+/**
+ * wpa_supplicant_associate - Request association
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ *
+ * This function is used to request %wpa_supplicant to associate with a BSS.
+ */
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+	u8 wpa_ie[200];
+	size_t wpa_ie_len;
+	int use_crypt, ret, i, bssid_changed;
+	int algs = WPA_AUTH_ALG_OPEN;
+	enum wpa_cipher cipher_pairwise, cipher_group;
+	struct wpa_driver_associate_params params;
+	int wep_keys_set = 0;
+	struct wpa_driver_capa capa;
+	int assoc_failed = 0;
+	struct wpa_ssid *old_ssid;
+	u8 ext_capab[10];
+	int ext_capab_len;
+#ifdef CONFIG_HT_OVERRIDES
+	struct ieee80211_ht_capabilities htcaps;
+	struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+	if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
+	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+#ifdef CONFIG_AP
+		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
+			wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
+				"mode");
+			return;
+		}
+		if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			return;
+		}
+		wpa_s->current_bss = bss;
+#else /* CONFIG_AP */
+		wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
+			"the build");
+#endif /* CONFIG_AP */
+		return;
+	}
+
+#ifdef CONFIG_TDLS
+	if (bss)
+		wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
+				bss->ie_len);
+#endif /* CONFIG_TDLS */
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+	    ssid->mode == IEEE80211_MODE_INFRA) {
+		sme_authenticate(wpa_s, bss, ssid);
+		return;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+	wpa_s->reassociate = 0;
+	if (bss && !wpas_driver_bss_selection(wpa_s)) {
+#ifdef CONFIG_IEEE80211R
+		const u8 *ie, *md = NULL;
+#endif /* CONFIG_IEEE80211R */
+		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
+			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
+		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+		os_memset(wpa_s->bssid, 0, ETH_ALEN);
+		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+		if (bssid_changed)
+			wpas_notify_bssid_changed(wpa_s);
+#ifdef CONFIG_IEEE80211R
+		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+			md = ie + 2;
+		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+		if (md) {
+			/* Prepare for the next transition */
+			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+		   wpa_s->conf->ap_scan == 2 &&
+		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		/* Use ap_scan==1 style network selection to find the network
+		 */
+		wpa_s->scan_req = MANUAL_SCAN_REQ;
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return;
+#endif /* CONFIG_WPS */
+	} 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);
+	}
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	/* Starting new association, so clear the possibly used WPA IE from the
+	 * previous association. */
+	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+#ifdef IEEE8021X_EAPOL
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if (ssid->leap) {
+			if (ssid->non_leap == 0)
+				algs = WPA_AUTH_ALG_LEAP;
+			else
+				algs |= WPA_AUTH_ALG_LEAP;
+		}
+	}
+#endif /* IEEE8021X_EAPOL */
+	wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+	if (ssid->auth_alg) {
+		algs = ssid->auth_alg;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+			"0x%x", algs);
+	}
+
+	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
+		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
+	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+		int try_opportunistic;
+		try_opportunistic = (ssid->proactive_key_caching < 0 ?
+				     wpa_s->conf->okc :
+				     ssid->proactive_key_caching) &&
+			(ssid->proto & WPA_PROTO_RSN);
+		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+					    wpa_s->current_ssid,
+					    try_opportunistic) == 0)
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+		wpa_ie_len = sizeof(wpa_ie);
+		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+					      wpa_ie, &wpa_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+				"key management and encryption suites");
+			return;
+		}
+	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+		   wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+		/*
+		 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+		 * use non-WPA since the scan results did not indicate that the
+		 * AP is using WPA or WPA2.
+		 */
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_ie_len = 0;
+		wpa_s->wpa_proto = 0;
+	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
+		wpa_ie_len = sizeof(wpa_ie);
+		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+					      wpa_ie, &wpa_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+				"key management and encryption suites (no "
+				"scan results)");
+			return;
+		}
+#ifdef CONFIG_WPS
+	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+		if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+			wpa_ie_len = wpabuf_len(wps_ie);
+			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
+		} else
+			wpa_ie_len = 0;
+		wpabuf_free(wps_ie);
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
+			params.wps = WPS_MODE_PRIVACY;
+		else
+			params.wps = WPS_MODE_OPEN;
+		wpa_s->wpa_proto = 0;
+#endif /* CONFIG_WPS */
+	} else {
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_ie_len = 0;
+		wpa_s->wpa_proto = 0;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p) {
+		u8 *pos;
+		size_t len;
+		int res;
+		pos = wpa_ie + wpa_ie_len;
+		len = sizeof(wpa_ie) - wpa_ie_len;
+		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+					    ssid->p2p_group);
+		if (res >= 0)
+			wpa_ie_len += res;
+	}
+
+	wpa_s->cross_connect_disallowed = 0;
+	if (bss) {
+		struct wpabuf *p2p;
+		p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+		if (p2p) {
+			wpa_s->cross_connect_disallowed =
+				p2p_get_cross_connect_disallowed(p2p);
+			wpabuf_free(p2p);
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
+				"connection",
+				wpa_s->cross_connect_disallowed ?
+				"disallows" : "allows");
+		}
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20) {
+		struct wpabuf *hs20;
+		hs20 = wpabuf_alloc(20);
+		if (hs20) {
+			wpas_hs20_add_indication(hs20);
+			os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+				  wpabuf_len(hs20));
+			wpa_ie_len += wpabuf_len(hs20);
+			wpabuf_free(hs20);
+		}
+	}
+#endif /* CONFIG_HS20 */
+
+	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+	if (ext_capab_len > 0) {
+		u8 *pos = wpa_ie;
+		if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+			pos += 2 + pos[1];
+		os_memmove(pos + ext_capab_len, pos,
+			   wpa_ie_len - (pos - wpa_ie));
+		wpa_ie_len += ext_capab_len;
+		os_memcpy(pos, ext_capab, ext_capab_len);
+	}
+
+	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
+	use_crypt = 1;
+	cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
+	cipher_group = cipher_suite2driver(wpa_s->group_cipher);
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
+			use_crypt = 0;
+		if (wpa_set_wep_keys(wpa_s, ssid)) {
+			use_crypt = 1;
+			wep_keys_set = 1;
+		}
+	}
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
+		use_crypt = 0;
+
+#ifdef IEEE8021X_EAPOL
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if ((ssid->eapol_flags &
+		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
+		    !wep_keys_set) {
+			use_crypt = 0;
+		} else {
+			/* Assume that dynamic WEP-104 keys will be used and
+			 * set cipher suites in order for drivers to expect
+			 * encryption. */
+			cipher_pairwise = cipher_group = CIPHER_WEP104;
+		}
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/* Set the key before (and later after) association */
+		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
+	}
+
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+	if (bss) {
+		params.ssid = bss->ssid;
+		params.ssid_len = bss->ssid_len;
+		if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+			wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+				   MACSTR " freq=%u MHz based on scan results "
+				   "(bssid_set=%d)",
+				   MAC2STR(bss->bssid), bss->freq,
+				   ssid->bssid_set);
+			params.bssid = bss->bssid;
+			params.freq = bss->freq;
+		}
+	} else {
+		params.ssid = ssid->ssid;
+		params.ssid_len = ssid->ssid_len;
+	}
+
+	if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+	    wpa_s->conf->ap_scan == 2) {
+		params.bssid = ssid->bssid;
+		params.fixed_bssid = 1;
+	}
+
+	if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
+	    params.freq == 0)
+		params.freq = ssid->frequency; /* Initial channel for IBSS */
+	params.wpa_ie = wpa_ie;
+	params.wpa_ie_len = wpa_ie_len;
+	params.pairwise_suite = cipher_pairwise;
+	params.group_suite = cipher_group;
+	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+	params.wpa_proto = wpa_s->wpa_proto;
+	params.auth_alg = algs;
+	params.mode = ssid->mode;
+	params.bg_scan_period = ssid->bg_scan_period;
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i])
+			params.wep_key[i] = ssid->wep_key[i];
+		params.wep_key_len[i] = ssid->wep_key_len[i];
+	}
+	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
+	     params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
+		params.passphrase = ssid->passphrase;
+		if (ssid->psk_set)
+			params.psk = ssid->psk;
+	}
+
+	params.drop_unencrypted = use_crypt;
+
+#ifdef CONFIG_IEEE80211W
+	params.mgmt_frame_protection =
+		ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		wpa_s->conf->pmf : ssid->ieee80211w;
+	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
+		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		struct wpa_ie_data ie;
+		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
+		    ie.capabilities &
+		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
+				"MFP: require MFP");
+			params.mgmt_frame_protection =
+				MGMT_FRAME_PROTECTION_REQUIRED;
+		}
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	params.p2p = ssid->p2p_group;
+
+	if (wpa_s->parent->set_sta_uapsd)
+		params.uapsd = wpa_s->parent->sta_uapsd;
+	else
+		params.uapsd = -1;
+
+#ifdef CONFIG_HT_OVERRIDES
+	os_memset(&htcaps, 0, sizeof(htcaps));
+	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+	params.htcaps = (u8 *) &htcaps;
+	params.htcaps_mask = (u8 *) &htcaps_mask;
+	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+
+	ret = wpa_drv_associate(wpa_s, &params);
+	if (ret < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
+			"failed");
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+			/*
+			 * The driver is known to mean what is saying, so we
+			 * can stop right here; the association will not
+			 * succeed.
+			 */
+			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+			return;
+		}
+		/* try to continue anyway; new association will be tried again
+		 * after timeout */
+		assoc_failed = 1;
+	}
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/* Set the key after the association just in case association
+		 * cleared the previously configured key. */
+		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
+		/* No need to timeout authentication since there is no key
+		 * management. */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+#ifdef CONFIG_IBSS_RSN
+	} else if (ssid->mode == WPAS_MODE_IBSS &&
+		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * RSN IBSS authentication is per-STA and we can disable the
+		 * per-BSSID authentication.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+#endif /* CONFIG_IBSS_RSN */
+	} else {
+		/* Timeout for IEEE 802.11 authentication and association */
+		int timeout = 60;
+
+		if (assoc_failed) {
+			/* give IBSS a bit more time */
+			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
+		} else if (wpa_s->conf->ap_scan == 1) {
+			/* give IBSS a bit more time */
+			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
+		}
+		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
+	}
+
+	if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
+	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
+		/* Set static WEP keys again */
+		wpa_set_wep_keys(wpa_s, ssid);
+	}
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+		/*
+		 * Do not allow EAP session resumption between different
+		 * network configurations.
+		 */
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+	wpa_s->current_bss = bss;
+	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)
+		wpas_notify_network_changed(wpa_s);
+}
+
+
+static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
+					    const u8 *addr)
+{
+	struct wpa_ssid *old_ssid;
+
+	wpa_clear_keys(wpa_s, addr);
+	old_ssid = wpa_s->current_ssid;
+	wpa_supplicant_mark_disassoc(wpa_s);
+	wpa_sm_set_config(wpa_s->wpa, NULL);
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	if (old_ssid != wpa_s->current_ssid)
+		wpas_notify_network_changed(wpa_s);
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_deauthenticate - Deauthenticate the current connection
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
+ *
+ * This function is used to request %wpa_supplicant to deauthenticate from the
+ * current AP.
+ */
+void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
+				   int reason_code)
+{
+	u8 *addr = NULL;
+	union wpa_event_data event;
+	int zero_addr = 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+		" pending_bssid=" MACSTR " reason=%d state=%s",
+		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+		reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+
+	if (!is_zero_ether_addr(wpa_s->bssid))
+		addr = wpa_s->bssid;
+	else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+		 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+		  wpa_s->wpa_state == WPA_ASSOCIATING))
+		addr = wpa_s->pending_bssid;
+	else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+		/*
+		 * When using driver-based BSS selection, we may not know the
+		 * BSSID with which we are currently trying to associate. We
+		 * need to notify the driver of this disconnection even in such
+		 * a case, so use the all zeros address here.
+		 */
+		addr = wpa_s->bssid;
+		zero_addr = 1;
+	}
+
+	if (addr) {
+		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
+		os_memset(&event, 0, sizeof(event));
+		event.deauth_info.reason_code = (u16) reason_code;
+		event.deauth_info.locally_generated = 1;
+		wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+		if (zero_addr)
+			addr = NULL;
+	}
+
+	wpa_supplicant_clear_connection(wpa_s, addr);
+}
+
+
+/**
+ * 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
+ *
+ * Enables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid)
+{
+	struct wpa_ssid *other_ssid;
+	int was_disabled;
+
+	if (ssid == NULL) {
+		for (other_ssid = wpa_s->conf->ssid; other_ssid;
+		     other_ssid = other_ssid->next) {
+			if (other_ssid->disabled == 2)
+				continue; /* do not change persistent P2P group
+					   * data */
+			if (other_ssid == wpa_s->current_ssid &&
+			    other_ssid->disabled)
+				wpa_s->reassociate = 1;
+
+			was_disabled = other_ssid->disabled;
+
+			other_ssid->disabled = 0;
+			if (was_disabled)
+				wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
+
+			if (was_disabled != other_ssid->disabled)
+				wpas_notify_network_enabled_changed(
+					wpa_s, other_ssid);
+		}
+		if (wpa_s->reassociate)
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+	} else if (ssid->disabled && ssid->disabled != 2) {
+		if (wpa_s->current_ssid == NULL) {
+			/*
+			 * Try to reassociate since there is no current
+			 * configuration and a new network was made available.
+			 */
+			wpa_s->reassociate = 1;
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
+
+		was_disabled = ssid->disabled;
+
+		ssid->disabled = 0;
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
+		if (was_disabled != ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+	}
+}
+
+
+/**
+ * wpa_supplicant_disable_network - Mark a configured network as disabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Disables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
+{
+	struct wpa_ssid *other_ssid;
+	int was_disabled;
+
+	if (ssid == NULL) {
+		for (other_ssid = wpa_s->conf->ssid; other_ssid;
+		     other_ssid = other_ssid->next) {
+			was_disabled = other_ssid->disabled;
+			if (was_disabled == 2)
+				continue; /* do not change persistent P2P group
+					   * data */
+
+			other_ssid->disabled = 1;
+
+			if (was_disabled != other_ssid->disabled)
+				wpas_notify_network_enabled_changed(
+					wpa_s, other_ssid);
+		}
+		if (wpa_s->current_ssid)
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	} else if (ssid->disabled != 2) {
+		if (ssid == wpa_s->current_ssid)
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+		was_disabled = ssid->disabled;
+
+		ssid->disabled = 1;
+
+		if (was_disabled != ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+	}
+}
+
+
+/**
+ * wpa_supplicant_select_network - Attempt association with a network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL for any network
+ */
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid)
+{
+
+	struct wpa_ssid *other_ssid;
+	int disconnected = 0;
+
+	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		disconnected = 1;
+	}
+
+	if (ssid)
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
+	/*
+	 * Mark all other networks disabled or mark all networks enabled if no
+	 * network specified.
+	 */
+	for (other_ssid = wpa_s->conf->ssid; other_ssid;
+	     other_ssid = other_ssid->next) {
+		int was_disabled = other_ssid->disabled;
+		if (was_disabled == 2)
+			continue; /* do not change persistent P2P group data */
+
+		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+		if (was_disabled && !other_ssid->disabled)
+			wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
+
+		if (was_disabled != other_ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+	}
+
+	if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+		/* We are already associated with the selected network */
+		wpa_printf(MSG_DEBUG, "Already associated with the "
+			   "selected network - do nothing");
+		return;
+	}
+
+	if (ssid)
+		wpa_s->current_ssid = ssid;
+	wpa_s->connect_without_scan = NULL;
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+	if (ssid)
+		wpas_notify_network_selected(wpa_s, ssid);
+}
+
+
+/**
+ * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ap_scan: AP scan mode
+ * Returns: 0 if succeed or -1 if ap_scan has an invalid value
+ *
+ */
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
+{
+
+	int old_ap_scan;
+
+	if (ap_scan < 0 || ap_scan > 2)
+		return -1;
+
+#ifdef ANDROID
+	if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+	    wpa_s->wpa_state >= WPA_ASSOCIATING &&
+	    wpa_s->wpa_state < WPA_COMPLETED) {
+		wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+			   "associating", wpa_s->conf->ap_scan, ap_scan);
+		return 0;
+	}
+#endif /* ANDROID */
+
+	old_ap_scan = wpa_s->conf->ap_scan;
+	wpa_s->conf->ap_scan = ap_scan;
+
+	if (old_ap_scan != wpa_s->conf->ap_scan)
+		wpas_notify_ap_scan_changed(wpa_s);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_age: Expiration age in seconds
+ * Returns: 0 if succeed or -1 if expire_age has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+					  unsigned int bss_expire_age)
+{
+	if (bss_expire_age < 10) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
+			bss_expire_age);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
+		bss_expire_age);
+	wpa_s->conf->bss_expiration_age = bss_expire_age;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_count: number of scans after which an unseen BSS is reclaimed
+ * Returns: 0 if succeed or -1 if expire_count has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+					    unsigned int bss_expire_count)
+{
+	if (bss_expire_count < 1) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
+			bss_expire_count);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
+		bss_expire_count);
+	wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+				     int scan_interval)
+{
+	if (scan_interval < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+			scan_interval);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+		scan_interval);
+	wpa_s->scan_interval = scan_interval;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_debug_params - Set global debug params
+ * @global: wpa_global structure
+ * @debug_level: debug level
+ * @debug_timestamp: determines if show timestamp in debug data
+ * @debug_show_keys: determines if show keys in debug data
+ * Returns: 0 if succeed or -1 if debug_level has wrong value
+ */
+int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
+				    int debug_timestamp, int debug_show_keys)
+{
+
+	int old_level, old_timestamp, old_show_keys;
+
+	/* check for allowed debuglevels */
+	if (debug_level != MSG_EXCESSIVE &&
+	    debug_level != MSG_MSGDUMP &&
+	    debug_level != MSG_DEBUG &&
+	    debug_level != MSG_INFO &&
+	    debug_level != MSG_WARNING &&
+	    debug_level != MSG_ERROR)
+		return -1;
+
+	old_level = wpa_debug_level;
+	old_timestamp = wpa_debug_timestamp;
+	old_show_keys = wpa_debug_show_keys;
+
+	wpa_debug_level = debug_level;
+	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
+	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
+
+	if (wpa_debug_level != old_level)
+		wpas_notify_debug_level_changed(global);
+	if (wpa_debug_timestamp != old_timestamp)
+		wpas_notify_debug_timestamp_changed(global);
+	if (wpa_debug_show_keys != old_show_keys)
+		wpas_notify_debug_show_keys_changed(global);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_ssid - Get a pointer to the current network structure
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: A pointer to the current network structure or %NULL on failure
+ */
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *entry;
+	u8 ssid[MAX_SSID_LEN];
+	int res;
+	size_t ssid_len;
+	u8 bssid[ETH_ALEN];
+	int wired;
+
+	res = wpa_drv_get_ssid(wpa_s, ssid);
+	if (res < 0) {
+		wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+			"driver");
+		return NULL;
+	}
+	ssid_len = res;
+
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+		wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
+			"driver");
+		return NULL;
+	}
+
+	wired = wpa_s->conf->ap_scan == 0 &&
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
+
+	entry = wpa_s->conf->ssid;
+	while (entry) {
+		if (!wpas_network_disabled(wpa_s, entry) &&
+		    ((ssid_len == entry->ssid_len &&
+		      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
+		    (!entry->bssid_set ||
+		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+			return entry;
+#ifdef CONFIG_WPS
+		if (!wpas_network_disabled(wpa_s, entry) &&
+		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    (entry->ssid == NULL || entry->ssid_len == 0) &&
+		    (!entry->bssid_set ||
+		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+			return entry;
+#endif /* CONFIG_WPS */
+
+		if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
+		    entry->ssid_len == 0 &&
+		    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+			return entry;
+
+		entry = entry->next;
+	}
+
+	return NULL;
+}
+
+
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+	struct wpa_global *global = wpa_s->global;
+
+	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+		global->drv_priv[i] = wpa_drivers[i]->global_init();
+		if (global->drv_priv[i] == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize driver "
+				   "'%s'", wpa_drivers[i]->name);
+			return -1;
+		}
+	}
+
+	wpa_s->driver = wpa_drivers[i];
+	wpa_s->global_drv_priv = global->drv_priv[i];
+
+	return 0;
+}
+
+
+static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
+				     const char *name)
+{
+	int i;
+	size_t len;
+	const char *pos, *driver = name;
+
+	if (wpa_s == NULL)
+		return -1;
+
+	if (wpa_drivers[0] == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
+			"wpa_supplicant");
+		return -1;
+	}
+
+	if (name == NULL) {
+		/* default to first driver in the list */
+		return select_driver(wpa_s, 0);
+	}
+
+	do {
+		pos = os_strchr(driver, ',');
+		if (pos)
+			len = pos - driver;
+		else
+			len = os_strlen(driver);
+
+		for (i = 0; wpa_drivers[i]; i++) {
+			if (os_strlen(wpa_drivers[i]->name) == len &&
+			    os_strncmp(driver, wpa_drivers[i]->name, len) ==
+			    0) {
+				/* First driver that succeeds wins */
+				if (select_driver(wpa_s, i) == 0)
+					return 0;
+			}
+		}
+
+		driver = pos + 1;
+	} while (pos);
+
+	wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
+	return -1;
+}
+
+
+/**
+ * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @src_addr: Source address of the EAPOL frame
+ * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
+ * @len: Length of the EAPOL data
+ *
+ * This function is called for each received EAPOL frame. Most driver
+ * interfaces rely on more generic OS mechanism for receiving frames through
+ * l2_packet, but if such a mechanism is not available, the driver wrapper may
+ * take care of received EAPOL frames and deliver them to the core supplicant
+ * code by calling this function.
+ */
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+			     const u8 *buf, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+	    (wpa_s->last_eapol_matches_bssid &&
+#ifdef CONFIG_AP
+	     !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+	     os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
+		/*
+		 * There is possible race condition between receiving the
+		 * association event and the EAPOL frame since they are coming
+		 * through different paths from the driver. In order to avoid
+		 * issues in trying to process the EAPOL frame before receiving
+		 * association information, lets queue it for processing until
+		 * the association event is received. This may also be needed in
+		 * driver-based roaming case, so also use src_addr != BSSID as a
+		 * trigger if we have previously confirmed that the
+		 * Authenticator uses BSSID as the src_addr (which is not the
+		 * case with wired IEEE 802.1X).
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
+			"of received EAPOL frame (state=%s bssid=" MACSTR ")",
+			wpa_supplicant_state_txt(wpa_s->wpa_state),
+			MAC2STR(wpa_s->bssid));
+		wpabuf_free(wpa_s->pending_eapol_rx);
+		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+		if (wpa_s->pending_eapol_rx) {
+			os_get_time(&wpa_s->pending_eapol_rx_time);
+			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
+				  ETH_ALEN);
+		}
+		return;
+	}
+
+	wpa_s->last_eapol_matches_bssid =
+		os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+		return;
+	}
+#endif /* CONFIG_AP */
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
+			"no key management is configured");
+		return;
+	}
+
+	if (wpa_s->eapol_received == 0 &&
+	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+	     wpa_s->wpa_state != WPA_COMPLETED) &&
+	    (wpa_s->current_ssid == NULL ||
+	     wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
+		/* Timeout for completing IEEE 802.1X and WPA authentication */
+		wpa_supplicant_req_auth_timeout(
+			wpa_s,
+			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
+			70 : 10, 0);
+	}
+	wpa_s->eapol_received++;
+
+	if (wpa_s->countermeasures) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
+			"EAPOL packet");
+		return;
+	}
+
+#ifdef CONFIG_IBSS_RSN
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
+		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+		return;
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	/* Source address of the incoming EAPOL frame could be compared to the
+	 * current BSSID. However, it is possible that a centralized
+	 * Authenticator could be using another MAC address than the BSSID of
+	 * an AP, so just allow any address to be used for now. The replies are
+	 * still sent to the current BSSID (if available), though. */
+
+	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
+	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
+	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+		return;
+	wpa_drv_poll(wpa_s);
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		/*
+		 * Set portValid = TRUE here since we are going to skip 4-way
+		 * handshake processing which would normally set portValid. We
+		 * need this to allow the EAPOL state machines to be completed
+		 * without going through EAPOL-Key handshake.
+		 */
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+	}
+}
+
+
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->send_eapol) {
+		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+		if (addr)
+			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+	} else if (!(wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+		l2_packet_deinit(wpa_s->l2);
+		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
+					   wpa_drv_get_mac_addr(wpa_s),
+					   ETH_P_EAPOL,
+					   wpa_supplicant_rx_eapol, wpa_s, 0);
+		if (wpa_s->l2 == NULL)
+			return -1;
+	} else {
+		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+		if (addr)
+			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+	}
+
+	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+		MAC2STR(wpa_s->own_addr));
+	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+					   const u8 *buf, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const struct l2_ethhdr *eth;
+
+	if (len < sizeof(*eth))
+		return;
+	eth = (const struct l2_ethhdr *) buf;
+
+	if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+	    !(eth->h_dest[0] & 0x01)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+			" (bridge - not for this interface - ignore)",
+			MAC2STR(src_addr), MAC2STR(eth->h_dest));
+		return;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+		" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+	wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+				len - sizeof(*eth));
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+	static int interface_count = 0;
+
+	if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+		return -1;
+
+	if (wpa_s->bridge_ifname[0]) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
+			"interface '%s'", wpa_s->bridge_ifname);
+		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
+					      wpa_s->own_addr,
+					      ETH_P_EAPOL,
+					      wpa_supplicant_rx_eapol_bridge,
+					      wpa_s, 1);
+		if (wpa_s->l2_br == NULL) {
+			wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
+				"connection for the bridge interface '%s'",
+				wpa_s->bridge_ifname);
+			return -1;
+		}
+	}
+
+	wpa_clear_keys(wpa_s, NULL);
+
+	/* Make sure that TKIP countermeasures are not left enabled (could
+	 * happen if wpa_supplicant is killed during countermeasures. */
+	wpa_drv_set_countermeasures(wpa_s, 0);
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
+	wpa_drv_flush_pmkid(wpa_s);
+
+	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+	wpa_s->prev_scan_wildcard = 0;
+
+	if (wpa_supplicant_enabled_networks(wpa_s)) {
+		if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+						      100000))
+			wpa_supplicant_req_scan(wpa_s, interface_count,
+						100000);
+		interface_count++;
+	} else
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_daemon(const char *pid_file)
+{
+	wpa_printf(MSG_DEBUG, "Daemonize..");
+	return os_daemonize(pid_file);
+}
+
+
+static struct wpa_supplicant * wpa_supplicant_alloc(void)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = os_zalloc(sizeof(*wpa_s));
+	if (wpa_s == NULL)
+		return NULL;
+	wpa_s->scan_req = INITIAL_SCAN_REQ;
+	wpa_s->scan_interval = 5;
+	wpa_s->new_connection = 1;
+	wpa_s->parent = wpa_s;
+	wpa_s->sched_scanning = 0;
+
+	return wpa_s;
+}
+
+
+#ifdef CONFIG_HT_OVERRIDES
+
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+			     struct ieee80211_ht_capabilities *htcaps,
+			     struct ieee80211_ht_capabilities *htcaps_mask,
+			     const char *ht_mcs)
+{
+	/* parse ht_mcs into hex array */
+	int i;
+	const char *tmp = ht_mcs;
+	char *end = NULL;
+
+	/* If ht_mcs is null, do not set anything */
+	if (!ht_mcs)
+		return 0;
+
+	/* This is what we are setting in the kernel */
+	os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
+
+	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+		errno = 0;
+		long v = strtol(tmp, &end, 16);
+		if (errno == 0) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"htcap value[%i]: %ld end: %p  tmp: %p",
+				i, v, end, tmp);
+			if (end == tmp)
+				break;
+
+			htcaps->supported_mcs_set[i] = v;
+			tmp = end;
+		} else {
+			wpa_msg(wpa_s, MSG_ERROR,
+				"Failed to parse ht-mcs: %s, error: %s\n",
+				ht_mcs, strerror(errno));
+			return -1;
+		}
+	}
+
+	/*
+	 * If we were able to parse any values, then set mask for the MCS set.
+	 */
+	if (i) {
+		os_memset(&htcaps_mask->supported_mcs_set, 0xff,
+			  IEEE80211_HT_MCS_MASK_LEN - 1);
+		/* skip the 3 reserved bits */
+		htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
+			0x1f;
+	}
+
+	return 0;
+}
+
+
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+				 struct ieee80211_ht_capabilities *htcaps,
+				 struct ieee80211_ht_capabilities *htcaps_mask,
+				 int disabled)
+{
+	u16 msk;
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
+	if (disabled == -1)
+		return 0;
+
+	msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+	htcaps_mask->ht_capabilities_info |= msk;
+	if (disabled)
+		htcaps->ht_capabilities_info &= msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+				struct ieee80211_ht_capabilities *htcaps,
+				struct ieee80211_ht_capabilities *htcaps_mask,
+				int factor)
+{
+	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
+	if (factor == -1)
+		return 0;
+
+	if (factor < 0 || factor > 3) {
+		wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
+			"Must be 0-3 or -1", factor);
+		return -EINVAL;
+	}
+
+	htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
+	htcaps->a_mpdu_params &= ~0x3;
+	htcaps->a_mpdu_params |= factor & 0x3;
+
+	return 0;
+}
+
+
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+				 struct ieee80211_ht_capabilities *htcaps,
+				 struct ieee80211_ht_capabilities *htcaps_mask,
+				 int density)
+{
+	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
+	if (density == -1)
+		return 0;
+
+	if (density < 0 || density > 7) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"ampdu_density: %d out of range. Must be 0-7 or -1.",
+			density);
+		return -EINVAL;
+	}
+
+	htcaps_mask->a_mpdu_params |= 0x1C;
+	htcaps->a_mpdu_params &= ~(0x1C);
+	htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+
+	return 0;
+}
+
+
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+				struct ieee80211_ht_capabilities *htcaps,
+				struct ieee80211_ht_capabilities *htcaps_mask,
+				int disabled)
+{
+	/* Masking these out disables HT40 */
+	u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+			       HT_CAP_INFO_SHORT_GI40MHZ);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+
+	if (disabled)
+		htcaps->ht_capabilities_info &= ~msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	htcaps_mask->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
+			       struct ieee80211_ht_capabilities *htcaps,
+			       struct ieee80211_ht_capabilities *htcaps_mask,
+			       int disabled)
+{
+	/* Masking these out disables SGI */
+	u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
+			       HT_CAP_INFO_SHORT_GI40MHZ);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+
+	if (disabled)
+		htcaps->ht_capabilities_info &= ~msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	htcaps_mask->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+void wpa_supplicant_apply_ht_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params)
+{
+	struct ieee80211_ht_capabilities *htcaps;
+	struct ieee80211_ht_capabilities *htcaps_mask;
+
+	if (!ssid)
+		return;
+
+	params->disable_ht = ssid->disable_ht;
+	if (!params->htcaps || !params->htcaps_mask)
+		return;
+
+	htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
+	htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
+	wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
+	wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
+			      ssid->disable_max_amsdu);
+	wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
+	wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
+	wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+	wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
+}
+
+#endif /* CONFIG_HT_OVERRIDES */
+
+
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+	size_t len;
+
+	if (!wpa_s->conf->pcsc_reader)
+		return 0;
+
+	wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+	if (!wpa_s->scard)
+		return 1;
+
+	if (wpa_s->conf->pcsc_pin &&
+	    scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+		scard_deinit(wpa_s->scard);
+		wpa_s->scard = NULL;
+		wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+		return -1;
+	}
+
+	len = sizeof(wpa_s->imsi) - 1;
+	if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+		scard_deinit(wpa_s->scard);
+		wpa_s->scard = NULL;
+		wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+		return -1;
+	}
+	wpa_s->imsi[len] = '\0';
+
+	wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+	wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+		   wpa_s->imsi, wpa_s->mnc_len);
+
+	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+	return 0;
+}
+
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+	char *val, *pos;
+
+	ext_password_deinit(wpa_s->ext_pw);
+	wpa_s->ext_pw = NULL;
+	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+	if (!wpa_s->conf->ext_password_backend)
+		return 0;
+
+	val = os_strdup(wpa_s->conf->ext_password_backend);
+	if (val == NULL)
+		return -1;
+	pos = os_strchr(val, ':');
+	if (pos)
+		*pos++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+	wpa_s->ext_pw = ext_password_init(val, pos);
+	os_free(val);
+	if (wpa_s->ext_pw == NULL) {
+		wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+		return -1;
+	}
+	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
+				     struct wpa_interface *iface)
+{
+	const char *ifname, *driver;
+	struct wpa_driver_capa capa;
+
+	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
+		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
+		   iface->confname ? iface->confname : "N/A",
+		   iface->driver ? iface->driver : "default",
+		   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
+		   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
+
+	if (iface->confname) {
+#ifdef CONFIG_BACKEND_FILE
+		wpa_s->confname = os_rel2abs_path(iface->confname);
+		if (wpa_s->confname == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to get absolute path "
+				   "for configuration file '%s'.",
+				   iface->confname);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
+			   iface->confname, wpa_s->confname);
+#else /* CONFIG_BACKEND_FILE */
+		wpa_s->confname = os_strdup(iface->confname);
+#endif /* CONFIG_BACKEND_FILE */
+		wpa_s->conf = wpa_config_read(wpa_s->confname);
+		if (wpa_s->conf == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to read or parse "
+				   "configuration '%s'.", wpa_s->confname);
+			return -1;
+		}
+
+		/*
+		 * Override ctrl_interface and driver_param if set on command
+		 * line.
+		 */
+		if (iface->ctrl_interface) {
+			os_free(wpa_s->conf->ctrl_interface);
+			wpa_s->conf->ctrl_interface =
+				os_strdup(iface->ctrl_interface);
+		}
+
+		if (iface->driver_param) {
+			os_free(wpa_s->conf->driver_param);
+			wpa_s->conf->driver_param =
+				os_strdup(iface->driver_param);
+		}
+	} else
+		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
+						     iface->driver_param);
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR, "\nNo configuration found.");
+		return -1;
+	}
+
+	if (iface->ifname == NULL) {
+		wpa_printf(MSG_ERROR, "\nInterface name is required.");
+		return -1;
+	}
+	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
+		wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
+			   iface->ifname);
+		return -1;
+	}
+	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+
+	if (iface->bridge_ifname) {
+		if (os_strlen(iface->bridge_ifname) >=
+		    sizeof(wpa_s->bridge_ifname)) {
+			wpa_printf(MSG_ERROR, "\nToo long bridge interface "
+				   "name '%s'.", iface->bridge_ifname);
+			return -1;
+		}
+		os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
+			   sizeof(wpa_s->bridge_ifname));
+	}
+
+	/* RSNA Supplicant Key Management - INITIALIZE */
+	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+
+	/* Initialize driver interface and register driver event handler before
+	 * L2 receive handler so that association events are processed before
+	 * EAPOL-Key packets if both become available for the same select()
+	 * call. */
+	driver = iface->driver;
+next_driver:
+	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+		return -1;
+
+	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
+	if (wpa_s->drv_priv == NULL) {
+		const char *pos;
+		pos = driver ? os_strchr(driver, ',') : NULL;
+		if (pos) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+				"driver interface - try next driver wrapper");
+			driver = pos + 1;
+			goto next_driver;
+		}
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+			"interface");
+		return -1;
+	}
+	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+			"driver_param '%s'", wpa_s->conf->driver_param);
+		return -1;
+	}
+
+	ifname = wpa_drv_get_ifname(wpa_s);
+	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+			"interface name with '%s'", ifname);
+		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+	}
+
+	if (wpa_supplicant_init_wpa(wpa_s) < 0)
+		return -1;
+
+	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
+			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
+			  NULL);
+	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+
+	if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
+			     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigPMKLifetime");
+		return -1;
+	}
+
+	if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+			     wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigPMKReauthThreshold");
+		return -1;
+	}
+
+	if (wpa_s->conf->dot11RSNAConfigSATimeout &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+			     wpa_s->conf->dot11RSNAConfigSATimeout)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigSATimeout");
+		return -1;
+	}
+
+	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+						      &wpa_s->hw.num_modes,
+						      &wpa_s->hw.flags);
+
+	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+		wpa_s->drv_capa_known = 1;
+		wpa_s->drv_flags = capa.flags;
+		wpa_s->drv_enc = capa.enc;
+		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->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;
+		wpa_s->max_stations = capa.max_stations;
+	}
+	if (wpa_s->max_remain_on_chan == 0)
+		wpa_s->max_remain_on_chan = 1000;
+
+	if (wpa_supplicant_driver_init(wpa_s) < 0)
+		return -1;
+
+#ifdef CONFIG_TDLS
+	if (wpa_tdls_init(wpa_s->wpa))
+		return -1;
+#endif /* CONFIG_TDLS */
+
+	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
+	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
+		return -1;
+	}
+
+	if (wpas_wps_init(wpa_s))
+		return -1;
+
+	if (wpa_supplicant_init_eapol(wpa_s) < 0)
+		return -1;
+	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+	if (wpa_s->ctrl_iface == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to initialize control interface '%s'.\n"
+			   "You may have another wpa_supplicant process "
+			   "already running or the file was\n"
+			   "left by an unclean termination of wpa_supplicant "
+			   "in which case you will need\n"
+			   "to manually remove this file before starting "
+			   "wpa_supplicant again.\n",
+			   wpa_s->conf->ctrl_interface);
+		return -1;
+	}
+
+	wpa_s->gas = gas_query_init(wpa_s);
+	if (wpa_s->gas == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
+		return -1;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
+		return -1;
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_bss_init(wpa_s) < 0)
+		return -1;
+
+	if (pcsc_reader_init(wpa_s) < 0)
+		return -1;
+
+	if (wpas_init_ext_pw(wpa_s) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
+					int notify, int terminate)
+{
+	if (wpa_s->drv_priv) {
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+
+		wpa_drv_set_countermeasures(wpa_s, 0);
+		wpa_clear_keys(wpa_s, NULL);
+	}
+
+	wpa_supplicant_cleanup(wpa_s);
+
+#ifdef CONFIG_P2P
+	if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+			"the management interface is being removed");
+		wpas_p2p_deinit_global(wpa_s->global);
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->drv_priv)
+		wpa_drv_deinit(wpa_s);
+
+	if (notify)
+		wpas_notify_iface_removed(wpa_s);
+
+	if (terminate)
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+
+	if (wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+
+	if (wpa_s->conf != NULL) {
+		wpa_config_free(wpa_s->conf);
+		wpa_s->conf = NULL;
+	}
+}
+
+
+/**
+ * wpa_supplicant_add_iface - Add a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @iface: Interface configuration options
+ * Returns: Pointer to the created interface or %NULL on failure
+ *
+ * This function is used to add new network interfaces for %wpa_supplicant.
+ * This can be called before wpa_supplicant_run() to add interfaces before the
+ * main event loop has been started. In addition, new interfaces can be added
+ * dynamically while %wpa_supplicant is already running. This could happen,
+ * e.g., when a hotplug network adapter is inserted.
+ */
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+						 struct wpa_interface *iface)
+{
+	struct wpa_supplicant *wpa_s;
+	struct wpa_interface t_iface;
+	struct wpa_ssid *ssid;
+
+	if (global == NULL || iface == NULL)
+		return NULL;
+
+	wpa_s = wpa_supplicant_alloc();
+	if (wpa_s == NULL)
+		return NULL;
+
+	wpa_s->global = global;
+
+	t_iface = *iface;
+	if (global->params.override_driver) {
+		wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
+			   "('%s' -> '%s')",
+			   iface->driver, global->params.override_driver);
+		t_iface.driver = global->params.override_driver;
+	}
+	if (global->params.override_ctrl_interface) {
+		wpa_printf(MSG_DEBUG, "Override interface parameter: "
+			   "ctrl_interface ('%s' -> '%s')",
+			   iface->ctrl_interface,
+			   global->params.override_ctrl_interface);
+		t_iface.ctrl_interface =
+			global->params.override_ctrl_interface;
+	}
+	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
+		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
+			   iface->ifname);
+		wpa_supplicant_deinit_iface(wpa_s, 0, 0);
+		os_free(wpa_s);
+		return NULL;
+	}
+
+	/* Notify the control interfaces about new iface */
+	if (wpas_notify_iface_added(wpa_s)) {
+		wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+		os_free(wpa_s);
+		return NULL;
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+		wpas_notify_network_added(wpa_s, ssid);
+
+	wpa_s->next = global->ifaces;
+	global->ifaces = wpa_s;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+	return wpa_s;
+}
+
+
+/**
+ * wpa_supplicant_remove_iface - Remove a network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to the network interface to be removed
+ * Returns: 0 if interface was removed, -1 if interface was not found
+ *
+ * This function can be used to dynamically remove network interfaces from
+ * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
+ * addition, this function is used to remove all remaining interfaces when
+ * %wpa_supplicant is terminated.
+ */
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+				struct wpa_supplicant *wpa_s,
+				int terminate)
+{
+	struct wpa_supplicant *prev;
+
+	/* Remove interface from the global list of interfaces */
+	prev = global->ifaces;
+	if (prev == wpa_s) {
+		global->ifaces = wpa_s->next;
+	} else {
+		while (prev && prev->next != wpa_s)
+			prev = prev->next;
+		if (prev == NULL)
+			return -1;
+		prev->next = wpa_s->next;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+
+	if (global->p2p_group_formation == wpa_s)
+		global->p2p_group_formation = NULL;
+	wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
+	os_free(wpa_s);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_eap_mode - Get the current EAP mode
+ * @wpa_s: Pointer to the network interface
+ * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
+ */
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
+{
+	const char *eapol_method;
+
+        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
+            wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		return "NO-EAP";
+	}
+
+	eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
+	if (eapol_method == NULL)
+		return "UNKNOWN-EAP";
+
+	return eapol_method;
+}
+
+
+/**
+ * wpa_supplicant_get_iface - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Interface name
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+						 const char *ifname)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->ifname, ifname) == 0)
+			return wpa_s;
+	}
+	return NULL;
+}
+
+
+#ifndef CONFIG_NO_WPA_MSG
+static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL)
+		return NULL;
+	return wpa_s->ifname;
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+/**
+ * wpa_supplicant_init - Initialize %wpa_supplicant
+ * @params: Parameters for %wpa_supplicant
+ * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
+ *
+ * This function is used to initialize %wpa_supplicant. After successful
+ * initialization, the returned data pointer can be used to add and remove
+ * network interfaces, and eventually, to deinitialize %wpa_supplicant.
+ */
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
+{
+	struct wpa_global *global;
+	int ret, i;
+
+	if (params == NULL)
+		return NULL;
+
+#ifdef CONFIG_DRIVER_NDIS
+	{
+		void driver_ndis_init_ops(void);
+		driver_ndis_init_ops();
+	}
+#endif /* CONFIG_DRIVER_NDIS */
+
+#ifndef CONFIG_NO_WPA_MSG
+	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+#endif /* CONFIG_NO_WPA_MSG */
+
+	wpa_debug_open_file(params->wpa_debug_file_path);
+	if (params->wpa_debug_syslog)
+		wpa_debug_open_syslog();
+	if (params->wpa_debug_tracing) {
+		ret = wpa_debug_open_linux_tracing();
+		if (ret) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to enable trace logging");
+			return NULL;
+		}
+	}
+
+	ret = eap_register_methods();
+	if (ret) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		if (ret == -2)
+			wpa_printf(MSG_ERROR, "Two or more EAP methods used "
+				   "the same EAP type.");
+		return NULL;
+	}
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+	dl_list_init(&global->p2p_srv_bonjour);
+	dl_list_init(&global->p2p_srv_upnp);
+	global->params.daemonize = params->daemonize;
+	global->params.wait_for_monitor = params->wait_for_monitor;
+	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
+	if (params->pid_file)
+		global->params.pid_file = os_strdup(params->pid_file);
+	if (params->ctrl_interface)
+		global->params.ctrl_interface =
+			os_strdup(params->ctrl_interface);
+	if (params->override_driver)
+		global->params.override_driver =
+			os_strdup(params->override_driver);
+	if (params->override_ctrl_interface)
+		global->params.override_ctrl_interface =
+			os_strdup(params->override_ctrl_interface);
+	wpa_debug_level = global->params.wpa_debug_level =
+		params->wpa_debug_level;
+	wpa_debug_show_keys = global->params.wpa_debug_show_keys =
+		params->wpa_debug_show_keys;
+	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
+		params->wpa_debug_timestamp;
+
+	wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	random_init(params->entropy_file);
+
+	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
+	if (global->ctrl_iface == NULL) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	if (wpas_notify_supplicant_initialized(global)) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	for (i = 0; wpa_drivers[i]; i++)
+		global->drv_count++;
+	if (global->drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+	if (global->drv_priv == NULL) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (wifi_display_init(global) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+	return global;
+}
+
+
+/**
+ * wpa_supplicant_run - Run the %wpa_supplicant main event loop
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 after successful event loop run, -1 on failure
+ *
+ * This function starts the main event loop and continues running as long as
+ * there are any remaining events. In most cases, this function is running as
+ * long as the %wpa_supplicant process in still in use.
+ */
+int wpa_supplicant_run(struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+
+	if (global->params.daemonize &&
+	    wpa_supplicant_daemon(global->params.pid_file))
+		return -1;
+
+	if (global->params.wait_for_monitor) {
+		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+			if (wpa_s->ctrl_iface)
+				wpa_supplicant_ctrl_iface_wait(
+					wpa_s->ctrl_iface);
+	}
+
+	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+
+	eloop_run();
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function is called to deinitialize %wpa_supplicant and to free all
+ * allocated resources. Remaining network interfaces will also be removed.
+ */
+void wpa_supplicant_deinit(struct wpa_global *global)
+{
+	int i;
+
+	if (global == NULL)
+		return;
+
+#ifdef CONFIG_WIFI_DISPLAY
+	wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_P2P
+	wpas_p2p_deinit_global(global);
+#endif /* CONFIG_P2P */
+
+	while (global->ifaces)
+		wpa_supplicant_remove_iface(global, global->ifaces, 1);
+
+	if (global->ctrl_iface)
+		wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
+
+	wpas_notify_supplicant_deinitialized(global);
+
+	eap_peer_unregister_methods();
+#ifdef CONFIG_AP
+	eap_server_unregister_methods();
+#endif /* CONFIG_AP */
+
+	for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
+		if (!global->drv_priv[i])
+			continue;
+		wpa_drivers[i]->global_deinit(global->drv_priv[i]);
+	}
+	os_free(global->drv_priv);
+
+	random_deinit();
+
+	eloop_destroy();
+
+	if (global->params.pid_file) {
+		os_daemonize_terminate(global->params.pid_file);
+		os_free(global->params.pid_file);
+	}
+	os_free(global->params.ctrl_interface);
+	os_free(global->params.override_driver);
+	os_free(global->params.override_ctrl_interface);
+
+	os_free(global->p2p_disallow_freq);
+
+	os_free(global);
+	wpa_debug_close_syslog();
+	wpa_debug_close_file();
+	wpa_debug_close_linux_tracing();
+}
+
+
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
+{
+	if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+	    wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+		char country[3];
+		country[0] = wpa_s->conf->country[0];
+		country[1] = wpa_s->conf->country[1];
+		country[2] = '\0';
+		if (wpa_drv_set_country(wpa_s, country) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to set country code "
+				   "'%s'", country);
+		}
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+		wpas_init_ext_pw(wpa_s);
+
+#ifdef CONFIG_WPS
+	wpas_wps_update_config(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	wpas_p2p_update_config(wpa_s);
+#endif /* CONFIG_P2P */
+
+	wpa_s->conf->changed_parameters = 0;
+}
+
+
+static void add_freq(int *freqs, int *num_freqs, int freq)
+{
+	int i;
+
+	for (i = 0; i < *num_freqs; i++) {
+		if (freqs[i] == freq)
+			return;
+	}
+
+	freqs[*num_freqs] = freq;
+	(*num_freqs)++;
+}
+
+
+static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *cbss;
+	const int max_freqs = 10;
+	int *freqs;
+	int num_freqs = 0;
+
+	freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+	if (freqs == NULL)
+		return NULL;
+
+	cbss = wpa_s->current_bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (bss == cbss)
+			continue;
+		if (bss->ssid_len == cbss->ssid_len &&
+		    os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
+		    wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+			add_freq(freqs, &num_freqs, bss->freq);
+			if (num_freqs == max_freqs)
+				break;
+		}
+	}
+
+	if (num_freqs == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
+
+	return freqs;
+}
+
+
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	int timeout;
+	int count;
+	int *freqs = NULL;
+
+	/*
+	 * Remove possible authentication timeout since the connection failed.
+	 */
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+	/*
+	 * Add the failed BSSID into the blacklist and speed up next scan
+	 * attempt if there could be other APs that could accept association.
+	 * The current blacklist count indicates how many times we have tried
+	 * connecting to this AP and multiple attempts mean that other APs are
+	 * either not available or has already been tried, so that we can start
+	 * increasing the delay here to avoid constant scanning.
+	 */
+	count = wpa_blacklist_add(wpa_s, bssid);
+	if (count == 1 && wpa_s->current_bss) {
+		/*
+		 * This BSS was not in the blacklist before. If there is
+		 * another BSS available for the same ESS, we should try that
+		 * next. Otherwise, we may as well try this one once more
+		 * before allowing other, likely worse, ESSes to be considered.
+		 */
+		freqs = get_bss_freqs_in_ess(wpa_s);
+		if (freqs) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
+				"has been seen; try it next");
+			wpa_blacklist_add(wpa_s, bssid);
+			/*
+			 * On the next scan, go through only the known channels
+			 * used in this ESS based on previous scans to speed up
+			 * common load balancing use case.
+			 */
+			os_free(wpa_s->next_scan_freqs);
+			wpa_s->next_scan_freqs = freqs;
+		}
+	}
+
+	/*
+	 * Add previous failure count in case the temporary blacklist was
+	 * cleared due to no other BSSes being available.
+	 */
+	count += wpa_s->extra_blacklist_count;
+
+	switch (count) {
+	case 1:
+		timeout = 100;
+		break;
+	case 2:
+		timeout = 500;
+		break;
+	case 3:
+		timeout = 1000;
+		break;
+	case 4:
+		timeout = 5000;
+		break;
+	default:
+		timeout = 10000;
+		break;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+		"ms", count, timeout);
+
+	/*
+	 * TODO: if more than one possible AP is available in scan results,
+	 * could try the other ones before requesting a new scan.
+	 */
+	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
+				1000 * (timeout % 1000));
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after failed association");
+		}
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->conf->ap_scan == 2 ||
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
+}
+
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eap_peer_config *eap = &ssid->eap;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+			      (const u8 *) value, os_strlen(value));
+
+	switch (wpa_supplicant_ctrl_req_from_string(field)) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		os_free(eap->identity);
+		eap->identity = (u8 *) os_strdup(value);
+		eap->identity_len = os_strlen(value);
+		eap->pending_req_identity = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		os_free(eap->password);
+		eap->password = (u8 *) os_strdup(value);
+		eap->password_len = os_strlen(value);
+		eap->pending_req_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		os_free(eap->new_password);
+		eap->new_password = (u8 *) os_strdup(value);
+		eap->new_password_len = os_strlen(value);
+		eap->pending_req_new_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		os_free(eap->pin);
+		eap->pin = os_strdup(value);
+		eap->pending_req_pin = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		os_free(eap->otp);
+		eap->otp = (u8 *) os_strdup(value);
+		eap->otp_len = os_strlen(value);
+		os_free(eap->pending_req_otp);
+		eap->pending_req_otp = NULL;
+		eap->pending_req_otp_len = 0;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		os_free(eap->private_key_passwd);
+		eap->private_key_passwd = (u8 *) os_strdup(value);
+		eap->pending_req_passphrase = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+		return -1;
+	}
+
+	return 0;
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+	return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	int i;
+	unsigned int drv_enc;
+
+	if (ssid == NULL)
+		return 1;
+
+	if (ssid->disabled)
+		return 1;
+
+	if (wpa_s && wpa_s->drv_capa_known)
+		drv_enc = wpa_s->drv_enc;
+	else
+		drv_enc = (unsigned int) -1;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		size_t len = ssid->wep_key_len[i];
+		if (len == 0)
+			continue;
+		if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+			continue;
+		if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+			continue;
+		if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+			continue;
+		return 1; /* invalid WEP key */
+	}
+
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+	    !ssid->ext_psk)
+		return 1;
+
+	return 0;
+}
+
+
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
+		return 1;
+	if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
+		return 0;
+	return -1;
+}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	int dur;
+	struct os_time now;
+
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+			   "SSID block");
+		return;
+	}
+
+	if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+		return;
+
+	ssid->auth_failures++;
+	if (ssid->auth_failures > 50)
+		dur = 300;
+	else if (ssid->auth_failures > 20)
+		dur = 120;
+	else if (ssid->auth_failures > 10)
+		dur = 60;
+	else if (ssid->auth_failures > 5)
+		dur = 30;
+	else if (ssid->auth_failures > 1)
+		dur = 20;
+	else
+		dur = 10;
+
+	os_get_time(&now);
+	if (now.sec + dur <= ssid->disabled_until.sec)
+		return;
+
+	ssid->disabled_until.sec = now.sec + dur;
+
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+		"id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+		ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, int clear_failures)
+{
+	if (ssid == NULL)
+		return;
+
+	if (ssid->disabled_until.sec) {
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+			"id=%d ssid=\"%s\"",
+			ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+	}
+	ssid->disabled_until.sec = 0;
+	ssid->disabled_until.usec = 0;
+	if (clear_failures)
+		ssid->auth_failures = 0;
+}
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_bssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+		if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+			      bssid, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+		struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+		if (ssid_len == s->ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->normal_scans = 0;
+	wpa_supplicant_reinit_autoscan(wpa_s);
+	wpa_s->extra_blacklist_count = 0;
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_supplicant.conf	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,888 +0,0 @@
-##### Example wpa_supplicant configuration file ###############################
-#
-# This file describes configuration file format and lists all available option.
-# Please also take a look at simpler configuration examples in 'examples'
-# subdirectory.
-#
-# Empty lines and lines starting with # are ignored
-
-# NOTE! This file may contain password information and should probably be made
-# readable only by root user on multiuser systems.
-
-# Note: All file paths in this configuration file should use full (absolute,
-# not relative to working directory) path in order to allow working directory
-# to be changed. This can happen if wpa_supplicant is run in the background.
-
-# Whether to allow wpa_supplicant to update (overwrite) configuration
-#
-# This option can be used to allow wpa_supplicant to overwrite configuration
-# file whenever configuration is changed (e.g., new network block is added with
-# wpa_cli or wpa_gui, or a password is changed). This is required for
-# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
-# Please note that overwriting configuration file will remove the comments from
-# it.
-#update_config=1
-
-# global configuration (shared by all network blocks)
-#
-# Parameters for the control interface. If this is specified, wpa_supplicant
-# will open a control interface that is available for external programs to
-# manage wpa_supplicant. The meaning of this string depends on which control
-# interface mechanism is used. For all cases, the existance of this parameter
-# in configuration is used to determine whether the control interface is
-# enabled.
-#
-# For UNIX domain sockets (default on Linux and BSD): This is a directory that
-# will be created for UNIX domain sockets for listening to requests from
-# external programs (CLI/GUI, etc.) for status information and configuration.
-# The socket file will be named based on the interface name, so multiple
-# wpa_supplicant processes can be run at the same time if more than one
-# interface is used.
-# /var/run/wpa_supplicant is the recommended directory for sockets and by
-# default, wpa_cli will use it when trying to connect with wpa_supplicant.
-#
-# Access control for the control interface can be configured by setting the
-# directory to allow only members of a group to use sockets. This way, it is
-# possible to run wpa_supplicant as root (since it needs to change network
-# configuration and open raw sockets) and still allow GUI/CLI components to be
-# run as non-root users. However, since the control interface can be used to
-# change the network configuration, this access needs to be protected in many
-# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
-# want to allow non-root users to use the control interface, add a new group
-# and change this value to match with that group. Add users that should have
-# control interface access to this group. If this variable is commented out or
-# not included in the configuration file, group will not be changed from the
-# value it got by default when the directory or socket was created.
-#
-# When configuring both the directory and group, use following format:
-# DIR=/var/run/wpa_supplicant GROUP=wheel
-# DIR=/var/run/wpa_supplicant GROUP=0
-# (group can be either group name or gid)
-#
-# For UDP connections (default on Windows): The value will be ignored. This
-# variable is just used to select that the control interface is to be created.
-# The value can be set to, e.g., udp (ctrl_interface=udp)
-#
-# For Windows Named Pipe: This value can be used to set the security descriptor
-# for controlling access to the control interface. Security descriptor can be
-# set using Security Descriptor String Format (see http://msdn.microsoft.com/
-# library/default.asp?url=/library/en-us/secauthz/security/
-# security_descriptor_string_format.asp). The descriptor string needs to be
-# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
-# DACL (which will reject all connections). See README-Windows.txt for more
-# information about SDDL string format.
-#
-ctrl_interface=/var/run/wpa_supplicant
-
-# IEEE 802.1X/EAPOL version
-# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
-# EAPOL version 2. However, there are many APs that do not handle the new
-# version number correctly (they seem to drop the frames completely). In order
-# to make wpa_supplicant interoperate with these APs, the version number is set
-# to 1 by default. This configuration value can be used to set it to the new
-# version (2).
-eapol_version=1
-
-# AP scanning/selection
-# By default, wpa_supplicant requests driver to perform AP scanning and then
-# uses the scan results to select a suitable AP. Another alternative is to
-# allow the driver to take care of AP scanning and selection and use
-# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association
-# information from the driver.
-# 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
-#    the currently enabled networks are found, a new network (IBSS or AP mode
-#    operation) may be initialized (if configured) (default)
-# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
-#    parameters (e.g., WPA IE generation); this mode can also be used with
-#    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-#    APs (i.e., external program needs to control association). This mode must
-#    also be used when using wired Ethernet drivers.
-# 2: like 0, but associate with APs using security policy and SSID (but not
-#    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
-#    enable operation with hidden SSIDs and optimized roaming; in this mode,
-#    the network blocks in the configuration file are tried one by one until
-#    the driver reports successful association; each network block should have
-#    explicit security policy (i.e., only one option in the lists) for
-#    key_mgmt, pairwise, group, proto variables
-# When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
-# created immediately regardless of scan results. ap_scan=1 mode will first try
-# to scan for existing networks and only if no matches with the enabled
-# networks are found, a new IBSS or AP mode network is created.
-ap_scan=1
-
-# EAP fast re-authentication
-# By default, fast re-authentication is enabled for all EAP methods that
-# support it. This variable can be used to disable fast re-authentication.
-# Normally, there is no need to disable this.
-fast_reauth=1
-
-# OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
-# 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.
-# make the opensc engine available
-#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
-# make the pkcs11 engine available
-#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
-# configure the path to the pkcs11 module required by the pkcs11 engine
-#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
-
-# Dynamic EAP methods
-# If EAP methods were built dynamically as shared object files, they need to be
-# loaded here before being used in the network blocks. By default, EAP methods
-# are included statically in the build, so these lines are not needed
-#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
-#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
-# format is specific to the selected driver interface. This field is not used
-# in most cases.
-#driver_param="field=value"
-
-# Country code
-# The ISO/IEC alpha2 country code for the country in which this device is
-# currently operating.
-#country=US
-
-# Maximum lifetime for PMKSA in seconds; default 43200
-#dot11RSNAConfigPMKLifetime=43200
-# Threshold for reauthentication (percentage of PMK lifetime); default 70
-#dot11RSNAConfigPMKReauthThreshold=70
-# Timeout for security association negotiation in seconds; default 60
-#dot11RSNAConfigSATimeout=60
-
-# Wi-Fi Protected Setup (WPS) parameters
-
-# Universally Unique IDentifier (UUID; see RFC 4122) of the device
-# If not configured, UUID will be generated based on the local MAC address.
-#uuid=12345678-9abc-def0-1234-56789abcdef0
-
-# Device Name
-# User-friendly description of device; up to 32 octets encoded in UTF-8
-#device_name=Wireless Client
-
-# Manufacturer
-# The manufacturer of the device (up to 64 ASCII characters)
-#manufacturer=Company
-
-# Model Name
-# Model of the device (up to 32 ASCII characters)
-#model_name=cmodel
-
-# Model Number
-# Additional device description (up to 32 ASCII characters)
-#model_number=123
-
-# Serial Number
-# Serial number of the device (up to 32 characters)
-#serial_number=12345
-
-# Primary Device Type
-# Used format: <categ>-<OUI>-<subcateg>
-# categ = Category as an integer value
-# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
-#       default WPS OUI
-# subcateg = OUI-specific Sub Category as an integer value
-# Examples:
-#   1-0050F204-1 (Computer / PC)
-#   1-0050F204-2 (Computer / Server)
-#   5-0050F204-1 (Storage / NAS)
-#   6-0050F204-1 (Network Infrastructure / AP)
-#device_type=1-0050F204-1
-
-# OS Version
-# 4-octet operating system version number (hex string)
-#os_version=01020300
-
-# Config Methods
-# List of the supported configuration methods
-# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
-#	nfc_interface push_button keypad
-#config_methods=label display push_button keypad
-
-# Credential processing
-#   0 = process received credentials internally (default)
-#   1 = do not process received credentials; just pass them over ctrl_iface to
-#	external program(s)
-#   2 = process received credentials internally and pass them over ctrl_iface
-#	to external program(s)
-#wps_cred_processing=0
-
-# Maximum number of BSS entries to keep in memory
-# Default: 200
-# This can be used to limit memory use on the BSS entries (cached scan
-# results). A larger value may be needed in environments that have huge number
-# of APs when using ap_scan=1 mode.
-#bss_max_count=200
-
-
-# filter_ssids - SSID-based scan result filtering
-# 0 = do not filter scan results (default)
-# 1 = only include configured SSIDs in scan results/BSS table
-#filter_ssids=0
-
-
-# network block
-#
-# Each network (usually AP's sharing the same SSID) is configured as a separate
-# block in this configuration file. The network blocks are in preference order
-# (the first match is used).
-#
-# network block fields:
-#
-# disabled:
-#	0 = this network can be used (default)
-#	1 = this network block is disabled (can be enabled through ctrl_iface,
-#	    e.g., with wpa_cli or wpa_gui)
-#
-# id_str: Network identifier string for external scripts. This value is passed
-#	to external action script through wpa_cli as WPA_ID_STR environment
-#	variable to make it easier to do network specific configuration.
-#
-# ssid: SSID (mandatory); either as an ASCII string with double quotation or
-#	as hex string; network name
-#
-# scan_ssid:
-#	0 = do not scan this SSID with specific Probe Request frames (default)
-#	1 = scan with SSID-specific Probe Request frames (this can be used to
-#	    find APs that do not accept broadcast SSID or use multiple SSIDs;
-#	    this will add latency to scanning, so enable this only when needed)
-#
-# bssid: BSSID (optional); if set, this network block is used only when
-#	associating with the AP using the configured BSSID
-#
-# priority: priority group (integer)
-# By default, all networks will get same priority group (0). If some of the
-# networks are more desirable, this field can be used to change the order in
-# which wpa_supplicant goes through the networks when selecting a BSS. The
-# priority groups will be iterated in decreasing priority (i.e., the larger the
-# priority value, the sooner the network is matched against the scan results).
-# Within each priority group, networks will be selected based on security
-# policy, signal strength, etc.
-# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
-# using this priority to select the order for scanning. Instead, they try the
-# networks in the order that used in the configuration file.
-#
-# mode: IEEE 802.11 operation mode
-# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
-# 1 = IBSS (ad-hoc, peer-to-peer)
-# 2 = AP (access point)
-# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
-# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires
-# following network block options:
-# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
-# both), and psk must also be set.
-#
-# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g.,
-# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial
-# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode.
-# In addition, this value is only used by the station that creates the IBSS. If
-# an IBSS network with the configured SSID is already present, the frequency of
-# the network will be used instead of this configured value.
-#
-# 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
-# be used to optimize scanning to not occur on channels that the network does
-# not use. Example: scan_freq=2412 2437 2462
-#
-# freq_list: Array of allowed frequencies
-# Space-separated list of frequencies in MHz to allow for selecting the BSS. If
-# set, scan results that do not match any of the specified frequencies are not
-# considered when selecting a BSS.
-#
-# proto: list of accepted protocols
-# WPA = WPA/IEEE 802.11i/D3.0
-# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
-# If not set, this defaults to: WPA RSN
-#
-# key_mgmt: list of accepted authenticated key management protocols
-# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
-# WPA-EAP = WPA using EAP authentication
-# 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-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
-# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
-# If not set, this defaults to: WPA-PSK WPA-EAP
-#
-# auth_alg: list of allowed IEEE 802.11 authentication algorithms
-# OPEN = Open System authentication (required for WPA/WPA2)
-# SHARED = Shared Key authentication (requires static WEP keys)
-# LEAP = LEAP/Network EAP (only used with LEAP)
-# If not set, automatic selection is used (Open System with LEAP enabled if
-# LEAP is allowed as one of the EAP methods).
-#
-# pairwise: list of accepted pairwise (unicast) ciphers for WPA
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
-# NONE = Use only Group Keys (deprecated, should not be included if APs support
-#	pairwise keys)
-# If not set, this defaults to: CCMP TKIP
-#
-# group: list of accepted group (broadcast/multicast) ciphers for WPA
-# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
-# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
-# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
-# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
-# If not set, this defaults to: CCMP TKIP WEP104 WEP40
-#
-# psk: WPA preshared key; 256-bit pre-shared key
-# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
-# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
-# generated using the passphrase and SSID). ASCII passphrase must be between
-# 8 and 63 characters (inclusive).
-# This field is not needed, if WPA-EAP is used.
-# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
-# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
-# startup and reconfiguration time can be optimized by generating the PSK only
-# only when the passphrase or SSID has actually changed.
-#
-# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
-# Dynamic WEP key required for non-WPA mode
-# bit0 (1): require dynamically generated unicast WEP key
-# bit1 (2): require dynamically generated broadcast WEP key
-# 	(3 = require both keys; default)
-# Note: When using wired authentication, eapol_flags must be set to 0 for the
-# authentication to be completed successfully.
-#
-# mixed_cell: This option can be used to configure whether so called mixed
-# cells, i.e., networks that use both plaintext and encryption in the same
-# SSID, are allowed when selecting a BSS form scan results.
-# 0 = disabled (default)
-# 1 = enabled
-#
-# proactive_key_caching:
-# Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
-# 1 = enabled
-#
-# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
-# hex without quotation, e.g., 0102030405)
-# wep_tx_keyidx: Default WEP key index (TX) (0..3)
-#
-# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
-# allowed. This is only used with RSN/WPA2.
-# 0 = disabled (default)
-# 1 = enabled
-#peerkey=1
-#
-# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
-# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
-#
-# 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 ->
-#			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
-#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
-#       OTP = EAP-OTP (cannot be used separately with WPA; to be used
-#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
-#       GTC = EAP-GTC (cannot be used separately with WPA; to be used
-#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
-#	TLS = EAP-TLS (client and server certificate)
-#	PEAP = EAP-PEAP (with tunnelled EAP authentication)
-#	TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2
-#			 authentication)
-#	If not set, all compiled in methods are allowed.
-#
-# identity: Identity string for EAP
-#	This field is also used to configure user NAI for
-#	EAP-PSK/PAX/SAKE/GPSK.
-# anonymous_identity: Anonymous identity string for EAP (to be used as the
-#	unencrypted identity with EAP types that support different tunnelled
-#	identity, e.g., EAP-TTLS)
-# password: Password string for EAP. This field can include either the
-#	plaintext password (using ASCII or hex string) or a NtPasswordHash
-#	(16-byte MD4 hash of password) in hash:<32 hex digits> format.
-#	NtPasswordHash can only be used when the password is for MSCHAPv2 or
-#	MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
-#	EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
-#	PSK) is also configured using this field. For EAP-GPSK, this is a
-#	variable length PSK.
-# 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 should be used since working directory may
-#	change when wpa_supplicant is run in the background.
-#
-#	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.
-# 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.
-# client_cert: File path to client certificate file (PEM/DER)
-#	Full path 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>.
-# 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 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>.
-# private_key_passwd: Password for private key file (if left out, this will be
-#	asked through control interface)
-# 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.
-# 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.
-#	The subject string is in following format:
-#	/C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as at example.com
-# 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
-#	contains one of the entries in an alternative subject name extension.
-#	altSubjectName string is in following format: TYPE:VALUE
-#	Example: EMAIL:server at example.com
-#	Example: DNS:server.example.com;DNS:server2.example.com
-#	Following types are supported: EMAIL, DNS, URI
-# phase1: Phase1 (outer authentication, i.e., TLS tunnel) 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.
-#	'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> or
-#	pbc=1.
-# 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)
-# Following certificate/private key fields are used in inner Phase2
-# authentication when using EAP-TTLS or EAP-PEAP.
-# ca_cert2: File path to CA certificate file. 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.
-# ca_path2: Directory path for CA certificate files (PEM)
-# client_cert2: File path to client certificate file
-# private_key2: File path to client private key file
-# private_key2_passwd: Password for private key file
-# dh_file2: File path to DH/DSA parameters file (in PEM format)
-# subject_match2: Substring to be matched against the subject of the
-#	authentication server certificate.
-# altsubject_match2: Substring to be matched against the alternative subject
-#	name of the authentication server certificate.
-#
-# 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.
-#
-# EAP-FAST variables:
-# pac_file: File path for the PAC entries. 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>
-# phase1: 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)
-#
-# wpa_supplicant supports number of "EAP workarounds" to work around
-# interoperability issues with incorrectly behaving authentication servers.
-# These are enabled by default because some of the issues are present in large
-# number of authentication servers. Strict EAP conformance mode can be
-# configured by disabling workarounds with eap_workaround=0.
-
-# Example blocks:
-
-# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
-network={
-	ssid="simple"
-	psk="very secret passphrase"
-	priority=5
-}
-
-# Same as previous, but request SSID-specific scanning (for APs that reject
-# broadcast SSID)
-network={
-	ssid="second ssid"
-	scan_ssid=1
-	psk="very secret passphrase"
-	priority=2
-}
-
-# Only WPA-PSK is used. Any valid cipher combination is accepted.
-network={
-	ssid="example"
-	proto=WPA
-	key_mgmt=WPA-PSK
-	pairwise=CCMP TKIP
-	group=CCMP TKIP WEP104 WEP40
-	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
-	priority=2
-}
-
-# WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying
-network={
-	ssid="example"
-	proto=WPA
-	key_mgmt=WPA-PSK
-	pairwise=TKIP
-	group=TKIP
-	psk="not so secure passphrase"
-	wpa_ptk_rekey=600
-}
-
-# Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104
-# or WEP40 as the group cipher will not be accepted.
-network={
-	ssid="example"
-	proto=RSN
-	key_mgmt=WPA-EAP
-	pairwise=CCMP TKIP
-	group=CCMP TKIP
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	priority=1
-}
-
-# EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel
-# (e.g., Radiator)
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=PEAP
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase1="peaplabel=1"
-	phase2="auth=MSCHAPV2"
-	priority=10
-}
-
-# EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
-# unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user at example.com"
-	anonymous_identity="anonymous at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	priority=2
-}
-
-# EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted
-# use. Real identity is sent only within an encrypted TLS tunnel.
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user at example.com"
-	anonymous_identity="anonymous at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase2="auth=MSCHAPV2"
-}
-
-# WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner
-# authentication.
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	# Phase1 / outer authentication
-	anonymous_identity="anonymous at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	# Phase 2 / inner authentication
-	phase2="autheap=TLS"
-	ca_cert2="/etc/cert/ca2.pem"
-	client_cert2="/etc/cer/user.pem"
-	private_key2="/etc/cer/user.prv"
-	private_key2_passwd="password"
-	priority=2
-}
-
-# Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
-# group cipher.
-network={
-	ssid="example"
-	bssid=00:11:22:33:44:55
-	proto=WPA RSN
-	key_mgmt=WPA-PSK WPA-EAP
-	pairwise=CCMP
-	group=CCMP
-	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
-}
-
-# Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP
-# and all valid ciphers.
-network={
-	ssid=00010203
-	psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
-}
-
-
-# EAP-SIM with a GSM SIM or USIM
-network={
-	ssid="eap-sim-test"
-	key_mgmt=WPA-EAP
-	eap=SIM
-	pin="1234"
-	pcsc=""
-}
-
-
-# EAP-PSK
-network={
-	ssid="eap-psk-test"
-	key_mgmt=WPA-EAP
-	eap=PSK
-	anonymous_identity="eap_psk_user"
-	password=06b4be19da289f475aa46a33cb793029
-	identity="eap_psk_user at example.com"
-}
-
-
-# IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using
-# EAP-TLS for authentication and key generation; require both unicast and
-# broadcast WEP keys.
-network={
-	ssid="1x-test"
-	key_mgmt=IEEE8021X
-	eap=TLS
-	identity="user at example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	eapol_flags=3
-}
-
-
-# LEAP with dynamic WEP keys
-network={
-	ssid="leap-example"
-	key_mgmt=IEEE8021X
-	eap=LEAP
-	identity="user"
-	password="foobar"
-}
-
-# EAP-IKEv2 using shared secrets for both server and peer authentication
-network={
-	ssid="ikev2-example"
-	key_mgmt=WPA-EAP
-	eap=IKEV2
-	identity="user"
-	password="foobar"
-}
-
-# EAP-FAST with WPA (WPA or WPA2)
-network={
-	ssid="eap-fast-test"
-	key_mgmt=WPA-EAP
-	eap=FAST
-	anonymous_identity="FAST-000102030405"
-	identity="username"
-	password="password"
-	phase1="fast_provisioning=1"
-	pac_file="/etc/wpa_supplicant.eap-fast-pac"
-}
-
-network={
-	ssid="eap-fast-test"
-	key_mgmt=WPA-EAP
-	eap=FAST
-	anonymous_identity="FAST-000102030405"
-	identity="username"
-	password="password"
-	phase1="fast_provisioning=1"
-	pac_file="blob://eap-fast-pac"
-}
-
-# Plaintext connection (no WPA, no IEEE 802.1X)
-network={
-	ssid="plaintext-test"
-	key_mgmt=NONE
-}
-
-
-# Shared WEP key connection (no WPA, no IEEE 802.1X)
-network={
-	ssid="static-wep-test"
-	key_mgmt=NONE
-	wep_key0="abcde"
-	wep_key1=0102030405
-	wep_key2="1234567890123"
-	wep_tx_keyidx=0
-	priority=5
-}
-
-
-# Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key
-# IEEE 802.11 authentication
-network={
-	ssid="static-wep-test2"
-	key_mgmt=NONE
-	wep_key0="abcde"
-	wep_key1=0102030405
-	wep_key2="1234567890123"
-	wep_tx_keyidx=0
-	priority=5
-	auth_alg=SHARED
-}
-
-
-# IBSS/ad-hoc network with WPA-None/TKIP.
-network={
-	ssid="test adhoc"
-	mode=1
-	frequency=2412
-	proto=WPA
-	key_mgmt=WPA-NONE
-	pairwise=NONE
-	group=TKIP
-	psk="secret passphrase"
-}
-
-
-# Catch all example that allows more or less all configuration modes
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
-	pairwise=CCMP TKIP
-	group=CCMP TKIP WEP104 WEP40
-	psk="very secret passphrase"
-	eap=TTLS PEAP TLS
-	identity="user at example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	phase1="peaplabel=0"
-}
-
-# Example of EAP-TLS with smartcard (openssl engine)
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=TLS
-	proto=RSN
-	pairwise=CCMP TKIP
-	group=CCMP TKIP
-	identity="user at 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"
-
-	# Optional PIN configuration; this can be left out and PIN will be
-	# asked through the control interface
-	pin="1234"
-}
-
-# Example configuration showing how to use an inlined blob as a CA certificate
-# data instead of using external file
-network={
-	ssid="example"
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user at example.com"
-	anonymous_identity="anonymous at example.com"
-	password="foobar"
-	ca_cert="blob://exampleblob"
-	priority=20
-}
-
-blob-base64-exampleblob={
-SGVsbG8gV29ybGQhCg==
-}
-
-
-# Wildcard match for SSID (plaintext APs only). This example select any
-# open AP regardless of its SSID.
-network={
-	key_mgmt=NONE
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant.conf)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,1186 @@
+##### Example wpa_supplicant configuration file ###############################
+#
+# This file describes configuration file format and lists all available option.
+# Please also take a look at simpler configuration examples in 'examples'
+# subdirectory.
+#
+# Empty lines and lines starting with # are ignored
+
+# NOTE! This file may contain password information and should probably be made
+# readable only by root user on multiuser systems.
+
+# Note: All file paths in this configuration file should use full (absolute,
+# not relative to working directory) path in order to allow working directory
+# to be changed. This can happen if wpa_supplicant is run in the background.
+
+# Whether to allow wpa_supplicant to update (overwrite) configuration
+#
+# This option can be used to allow wpa_supplicant to overwrite configuration
+# file whenever configuration is changed (e.g., new network block is added with
+# wpa_cli or wpa_gui, or a password is changed). This is required for
+# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
+# Please note that overwriting configuration file will remove the comments from
+# it.
+#update_config=1
+
+# global configuration (shared by all network blocks)
+#
+# Parameters for the control interface. If this is specified, wpa_supplicant
+# will open a control interface that is available for external programs to
+# manage wpa_supplicant. The meaning of this string depends on which control
+# interface mechanism is used. For all cases, the existence of this parameter
+# in configuration is used to determine whether the control interface is
+# enabled.
+#
+# For UNIX domain sockets (default on Linux and BSD): This is a directory that
+# will be created for UNIX domain sockets for listening to requests from
+# external programs (CLI/GUI, etc.) for status information and configuration.
+# The socket file will be named based on the interface name, so multiple
+# wpa_supplicant processes can be run at the same time if more than one
+# interface is used.
+# /var/run/wpa_supplicant is the recommended directory for sockets and by
+# default, wpa_cli will use it when trying to connect with wpa_supplicant.
+#
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run wpa_supplicant as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
+# want to allow non-root users to use the control interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group. If this variable is commented out or
+# not included in the configuration file, group will not be changed from the
+# value it got by default when the directory or socket was created.
+#
+# When configuring both the directory and group, use following format:
+# DIR=/var/run/wpa_supplicant GROUP=wheel
+# DIR=/var/run/wpa_supplicant GROUP=0
+# (group can be either group name or gid)
+#
+# For UDP connections (default on Windows): The value will be ignored. This
+# variable is just used to select that the control interface is to be created.
+# The value can be set to, e.g., udp (ctrl_interface=udp)
+#
+# For Windows Named Pipe: This value can be used to set the security descriptor
+# for controlling access to the control interface. Security descriptor can be
+# set using Security Descriptor String Format (see http://msdn.microsoft.com/
+# library/default.asp?url=/library/en-us/secauthz/security/
+# security_descriptor_string_format.asp). The descriptor string needs to be
+# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
+# DACL (which will reject all connections). See README-Windows.txt for more
+# information about SDDL string format.
+#
+ctrl_interface=/var/run/wpa_supplicant
+
+# IEEE 802.1X/EAPOL version
+# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
+# EAPOL version 2. However, there are many APs that do not handle the new
+# version number correctly (they seem to drop the frames completely). In order
+# to make wpa_supplicant interoperate with these APs, the version number is set
+# to 1 by default. This configuration value can be used to set it to the new
+# version (2).
+eapol_version=1
+
+# AP scanning/selection
+# By default, wpa_supplicant requests driver to perform AP scanning and then
+# uses the scan results to select a suitable AP. Another alternative is to
+# allow the driver to take care of AP scanning and selection and use
+# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association
+# information from the driver.
+# 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to
+#    the currently enabled networks are found, a new network (IBSS or AP mode
+#    operation) may be initialized (if configured) (default)
+# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
+#    parameters (e.g., WPA IE generation); this mode can also be used with
+#    non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
+#    APs (i.e., external program needs to control association). This mode must
+#    also be used when using wired Ethernet drivers.
+# 2: like 0, but associate with APs using security policy and SSID (but not
+#    BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
+#    enable operation with hidden SSIDs and optimized roaming; in this mode,
+#    the network blocks in the configuration file are tried one by one until
+#    the driver reports successful association; each network block should have
+#    explicit security policy (i.e., only one option in the lists) for
+#    key_mgmt, pairwise, group, proto variables
+# When using IBSS or AP mode, ap_scan=2 mode can force the new network to be
+# created immediately regardless of scan results. ap_scan=1 mode will first try
+# to scan for existing networks and only if no matches with the enabled
+# networks are found, a new IBSS or AP mode network is created.
+ap_scan=1
+
+# EAP fast re-authentication
+# By default, fast re-authentication is enabled for all EAP methods that
+# support it. This variable can be used to disable fast re-authentication.
+# Normally, there is no need to disable this.
+fast_reauth=1
+
+# OpenSSL Engine support
+# These options can be used to load OpenSSL engines.
+# 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.
+# make the opensc engine available
+#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
+# make the pkcs11 engine available
+#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
+# configure the path to the pkcs11 module required by the pkcs11 engine
+#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+
+# Dynamic EAP methods
+# If EAP methods were built dynamically as shared object files, they need to be
+# loaded here before being used in the network blocks. By default, EAP methods
+# are included statically in the build, so these lines are not needed
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
+#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
+# format is specific to the selected driver interface. This field is not used
+# in most cases.
+#driver_param="field=value"
+
+# Country code
+# The ISO/IEC alpha2 country code for the country in which this device is
+# currently operating.
+#country=US
+
+# Maximum lifetime for PMKSA in seconds; default 43200
+#dot11RSNAConfigPMKLifetime=43200
+# Threshold for reauthentication (percentage of PMK lifetime); default 70
+#dot11RSNAConfigPMKReauthThreshold=70
+# Timeout for security association negotiation in seconds; default 60
+#dot11RSNAConfigSATimeout=60
+
+# Wi-Fi Protected Setup (WPS) parameters
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless Client
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=cmodel
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=1-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+#	nfc_interface push_button keypad virtual_display physical_display
+#	virtual_push_button physical_push_button
+# For WSC 1.0:
+#config_methods=label display push_button keypad
+# For WSC 2.0:
+#config_methods=label virtual_display virtual_push_button keypad
+
+# Credential processing
+#   0 = process received credentials internally (default)
+#   1 = do not process received credentials; just pass them over ctrl_iface to
+#	external program(s)
+#   2 = process received credentials internally and pass them over ctrl_iface
+#	to external program(s)
+#wps_cred_processing=0
+
+# Vendor attribute in WPS M1, e.g., Windows 7 Vertical Pairing
+# The vendor attribute contents to be added in M1 (hex string)
+#wps_vendor_ext_m1=000137100100020001
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# station. This can be generated, e.g., with nfc_pw_token. When these
+# parameters are used, the station is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
+# Maximum number of BSS entries to keep in memory
+# Default: 200
+# This can be used to limit memory use on the BSS entries (cached scan
+# results). A larger value may be needed in environments that have huge number
+# of APs when using ap_scan=1 mode.
+#bss_max_count=200
+
+# Automatic scan
+# This is an optional set of parameters for automatic scanning
+# within an interface in following format:
+#autoscan=<autoscan module name>:<module parameters>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
+#autoscan=exponential:3:300
+# Which means a delay between scans on a base exponential of 3,
+# 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
+
+# filter_ssids - SSID-based scan result filtering
+# 0 = do not filter scan results (default)
+# 1 = only include configured SSIDs in scan results/BSS table
+#filter_ssids=0
+
+# Password (and passphrase, etc.) backend for external storage
+# format: <backend name>[:<optional backend parameters>]
+#ext_password_backend=test:pw1=password|pw2=testing
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in P2P GO mode to clean up
+# inactive stations.
+#p2p_go_max_inactivity=300
+
+# Opportunistic Key Caching (also known as Proactive Key Caching) default
+# This parameter can be used to set the default behavior for the
+# proactive_key_caching parameter. By default, OKC is disabled unless enabled
+# with the global okc=1 parameter or with the per-network
+# proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but
+# can be disabled with per-network proactive_key_caching=0 parameter.
+#okc=0
+
+# 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.
+#pmf=0
+
+# Interworking (IEEE 802.11u)
+
+# Enable Interworking
+# interworking=1
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+# hessid=00:11:22:33:44:55
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+#     (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+#     credentials have been configured and scan did not find a
+#     matching network block
+#auto_interworking=0
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# priority: Priority group
+#	By default, all networks and credentials get the same priority group
+#	(0). This field can be used to give higher priority for credentials
+#	(and similarly in struct wpa_ssid for network blocks) to change the
+#	Interworking automatic networking selection behavior. The matching
+#	network (based on either an enabled network block or a credential)
+#	with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+#	This field is used with Interworking networking selection for a case
+#	where client certificate/private key is used for authentication
+#	(EAP-TLS). 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.
+#
+# 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.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+#	format
+#
+# domain: Home service provider FQDN
+#	This is used to compare against the Domain Name List to figure out
+#	whether the AP is operated by the Home SP.
+#
+# roaming_consortium: Roaming Consortium OI
+#	If roaming_consortium_len is non-zero, this field contains the
+#	Roaming Consortium OI that can be used to determine which access
+#	points support authentication with this credential. This is an
+#	alternative to the use of the realm parameter. When using Roaming
+#	Consortium to match the network, the EAP parameters need to be
+#	pre-configured with the credential since the NAI Realm information
+#	may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+#	This optional field can be used to specify which EAP method will be
+#	used with this credential. If not set, the EAP method is selected
+#	automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+#	This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+#	This optional field is used with like the 'eap' parameter.
+#
+# excluded_ssid: Excluded SSID
+#	This optional field can be used to excluded specific SSID(s) from
+#	matching with the network. Multiple entries can be used to specify more
+#	than one SSID.
+#
+# for example:
+#
+#cred={
+#	realm="example.com"
+#	username="user at example.com"
+#	password="password"
+#	ca_cert="/etc/wpa_supplicant/ca.pem"
+#	domain="example.com"
+#}
+#
+#cred={
+#	imsi="310026-000000000"
+#	milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+#	realm="example.com"
+#	username="user"
+#	password="password"
+#	ca_cert="/etc/wpa_supplicant/ca.pem"
+#	domain="example.com"
+#	roaming_consortium=223344
+#	eap=TTLS
+#	phase2="auth=MSCHAPV2"
+#}
+
+# Hotspot 2.0
+# hs20=1
+
+# network block
+#
+# Each network (usually AP's sharing the same SSID) is configured as a separate
+# block in this configuration file. The network blocks are in preference order
+# (the first match is used).
+#
+# network block fields:
+#
+# disabled:
+#	0 = this network can be used (default)
+#	1 = this network block is disabled (can be enabled through ctrl_iface,
+#	    e.g., with wpa_cli or wpa_gui)
+#
+# id_str: Network identifier string for external scripts. This value is passed
+#	to external action script through wpa_cli as WPA_ID_STR environment
+#	variable to make it easier to do network specific configuration.
+#
+# ssid: SSID (mandatory); network name in one of the optional formats:
+#	- an ASCII string with double quotation
+#	- a hex string (two characters per octet of SSID)
+#	- a printf-escaped ASCII string P"<escaped string>"
+#
+# scan_ssid:
+#	0 = do not scan this SSID with specific Probe Request frames (default)
+#	1 = scan with SSID-specific Probe Request frames (this can be used to
+#	    find APs that do not accept broadcast SSID or use multiple SSIDs;
+#	    this will add latency to scanning, so enable this only when needed)
+#
+# bssid: BSSID (optional); if set, this network block is used only when
+#	associating with the AP using the configured BSSID
+#
+# priority: priority group (integer)
+# By default, all networks will get same priority group (0). If some of the
+# networks are more desirable, this field can be used to change the order in
+# which wpa_supplicant goes through the networks when selecting a BSS. The
+# priority groups will be iterated in decreasing priority (i.e., the larger the
+# priority value, the sooner the network is matched against the scan results).
+# Within each priority group, networks will be selected based on security
+# policy, signal strength, etc.
+# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
+# using this priority to select the order for scanning. Instead, they try the
+# networks in the order that used in the configuration file.
+#
+# mode: IEEE 802.11 operation mode
+# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
+# 1 = IBSS (ad-hoc, peer-to-peer)
+# 2 = AP (access point)
+# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
+# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). WPA-None requires
+# following network block options:
+# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
+# both), and psk must also be set.
+#
+# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g.,
+# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial
+# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode.
+# In addition, this value is only used by the station that creates the IBSS. If
+# an IBSS network with the configured SSID is already present, the frequency of
+# the network will be used instead of this configured value.
+#
+# 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
+# be used to optimize scanning to not occur on channels that the network does
+# not use. Example: scan_freq=2412 2437 2462
+#
+# freq_list: Array of allowed frequencies
+# Space-separated list of frequencies in MHz to allow for selecting the BSS. If
+# set, scan results that do not match any of the specified frequencies are not
+# considered when selecting a BSS.
+#
+# bgscan: Background scanning
+# wpa_supplicant behavior for background scanning can be specified by
+# configuring a bgscan module. These modules are responsible for requesting
+# background scans for the purpose of roaming within an ESS (i.e., within a
+# single network block with all the APs using the same SSID). The bgscan
+# parameter uses following format: "<bgscan module name>:<module parameters>"
+# Following bgscan modules are available:
+# simple - Periodic background scans based on signal strength
+# bgscan="simple:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>"
+# bgscan="simple:30:-45:300"
+# learn - Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+# bgscan="learn:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>[:<database file name>]"
+# bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
+#
+# proto: list of accepted protocols
+# WPA = WPA/IEEE 802.11i/D3.0
+# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
+# If not set, this defaults to: WPA RSN
+#
+# key_mgmt: list of accepted authenticated key management protocols
+# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
+# WPA-EAP = WPA using EAP authentication
+# 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-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
+# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# If not set, this defaults to: WPA-PSK WPA-EAP
+#
+# ieee80211w: whether management frame protection is enabled
+# 0 = disabled (default unless changed with the global pmf parameter)
+# 1 = optional
+# 2 = required
+# The most common configuration options for this based on the PMF (protected
+# management frames) certification program are:
+# PMF enabled: ieee80211w=1 and key_mgmt=WPA-EAP WPA-EAP-SHA256
+# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
+# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
+#
+# auth_alg: list of allowed IEEE 802.11 authentication algorithms
+# OPEN = Open System authentication (required for WPA/WPA2)
+# SHARED = Shared Key authentication (requires static WEP keys)
+# LEAP = LEAP/Network EAP (only used with LEAP)
+# If not set, automatic selection is used (Open System with LEAP enabled if
+# LEAP is allowed as one of the EAP methods).
+#
+# pairwise: list of accepted pairwise (unicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# NONE = Use only Group Keys (deprecated, should not be included if APs support
+#	pairwise keys)
+# If not set, this defaults to: CCMP TKIP
+#
+# group: list of accepted group (broadcast/multicast) ciphers for WPA
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
+# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
+# If not set, this defaults to: CCMP TKIP WEP104 WEP40
+#
+# psk: WPA preshared key; 256-bit pre-shared key
+# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
+# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
+# generated using the passphrase and SSID). ASCII passphrase must be between
+# 8 and 63 characters (inclusive). ext:<name of external PSK field> format can
+# be used to indicate that the PSK/passphrase is stored in external storage.
+# This field is not needed, if WPA-EAP is used.
+# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
+# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
+# startup and reconfiguration time can be optimized by generating the PSK only
+# only when the passphrase or SSID has actually changed.
+#
+# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
+# Dynamic WEP key required for non-WPA mode
+# bit0 (1): require dynamically generated unicast WEP key
+# bit1 (2): require dynamically generated broadcast WEP key
+# 	(3 = require both keys; default)
+# Note: When using wired authentication, eapol_flags must be set to 0 for the
+# authentication to be completed successfully.
+#
+# mixed_cell: This option can be used to configure whether so called mixed
+# cells, i.e., networks that use both plaintext and encryption in the same
+# SSID, are allowed when selecting a BSS from scan results.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# proactive_key_caching:
+# Enable/disable opportunistic PMKSA caching for WPA2.
+# 0 = disabled (default unless changed with the global okc parameter)
+# 1 = enabled
+#
+# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
+# hex without quotation, e.g., 0102030405)
+# wep_tx_keyidx: Default WEP key index (TX) (0..3)
+#
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+#
+# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
+# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
+#
+# 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 ->
+#			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
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       OTP = EAP-OTP (cannot be used separately with WPA; to be used
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#       GTC = EAP-GTC (cannot be used separately with WPA; to be used
+#		as a Phase 2 method with EAP-PEAP or EAP-TTLS)
+#	TLS = EAP-TLS (client and server certificate)
+#	PEAP = EAP-PEAP (with tunnelled EAP authentication)
+#	TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2
+#			 authentication)
+#	If not set, all compiled in methods are allowed.
+#
+# identity: Identity string for EAP
+#	This field is also used to configure user NAI for
+#	EAP-PSK/PAX/SAKE/GPSK.
+# anonymous_identity: Anonymous identity string for EAP (to be used as the
+#	unencrypted identity with EAP types that support different tunnelled
+#	identity, e.g., EAP-TTLS). This field can also be used with
+#	EAP-SIM/AKA/AKA' to store the pseudonym identity.
+# password: Password string for EAP. This field can include either the
+#	plaintext password (using ASCII or hex string) or a NtPasswordHash
+#	(16-byte MD4 hash of password) in hash:<32 hex digits> format.
+#	NtPasswordHash can only be used when the password is for MSCHAPv2 or
+#	MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+#	EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
+#	PSK) is also configured using this field. For EAP-GPSK, this is a
+#	variable length PSK. ext:<name of external password field> format can
+#	be used to indicate that the password is stored in external storage.
+# 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 should be used since working directory may
+#	change when wpa_supplicant is run in the background.
+#
+#	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.
+# 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.
+# client_cert: File path to client certificate file (PEM/DER)
+#	Full path 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>.
+# 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 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>.
+# private_key_passwd: Password for private key file (if left out, this will be
+#	asked through control interface)
+# 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.
+# 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.
+#	The subject string is in following format:
+#	/C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as at example.com
+# 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
+#	contains one of the entries in an alternative subject name extension.
+#	altSubjectName string is in following format: TYPE:VALUE
+#	Example: EMAIL:server at example.com
+#	Example: DNS:server.example.com;DNS:server2.example.com
+#	Following types are supported: EMAIL, DNS, URI
+# phase1: Phase1 (outer authentication, i.e., TLS tunnel) 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.
+#	'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> or
+#	pbc=1.
+# 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)
+#
+# TLS-based methods can use the following parameters to control TLS behavior
+# (these are normally in the phase1 parameter, but can be used also in the
+# phase2 parameter when EAP-TLS is used within the inner tunnel):
+# tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the
+#	TLS library, these may be disabled by default to enforce stronger
+#	security)
+# tls_disable_time_checks=1 - ignore certificate validity time (this requests
+#	the TLS library to accept certificates even if they are not currently
+#	valid, i.e., have expired or have not yet become valid; this should be
+#	used only for testing purposes)
+# tls_disable_session_ticket=1 - disable TLS Session Ticket extension
+# tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used
+#	Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS
+#	as a workaround for broken authentication server implementations unless
+#	EAP workarounds are disabled with eap_workarounds=0.
+#	For EAP-FAST, this must be set to 0 (or left unconfigured for the
+#	default value to be used automatically).
+#
+# Following certificate/private key fields are used in inner Phase2
+# authentication when using EAP-TTLS or EAP-PEAP.
+# ca_cert2: File path to CA certificate file. 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.
+# ca_path2: Directory path for CA certificate files (PEM)
+# client_cert2: File path to client certificate file
+# private_key2: File path to client private key file
+# private_key2_passwd: Password for private key file
+# dh_file2: File path to DH/DSA parameters file (in PEM format)
+# subject_match2: Substring to be matched against the subject of the
+#	authentication server certificate.
+# altsubject_match2: Substring to be matched against the alternative subject
+#	name of the authentication server certificate.
+#
+# 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.
+#
+# EAP-FAST variables:
+# pac_file: File path for the PAC entries. 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>
+# phase1: 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)
+#
+# wpa_supplicant supports number of "EAP workarounds" to work around
+# interoperability issues with incorrectly behaving authentication servers.
+# These are enabled by default because some of the issues are present in large
+# number of authentication servers. Strict EAP conformance mode can be
+# configured by disabling workarounds with eap_workaround=0.
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# DTIM period in Beacon intervals for AP mode (default: 2)
+#dtim_period=2
+
+# disable_ht: Whether HT (802.11n) should be disabled.
+# 0 = HT enabled (if AP supports it)
+# 1 = HT disabled
+#
+# disable_ht40: Whether HT-40 (802.11n) should be disabled.
+# 0 = HT-40 enabled (if AP supports it)
+# 1 = HT-40 disabled
+#
+# disable_sgi: Whether SGI (short guard interval) should be disabled.
+# 0 = SGI enabled (if AP supports it)
+# 1 = SGI disabled
+#
+# ht_mcs:  Configure allowed MCS rates.
+#  Parsed as an array of bytes, in base-16 (ascii-hex)
+# ht_mcs=""                                   // Use all available (default)
+# ht_mcs="0xff 00 00 00 00 00 00 00 00 00 "   // Use MCS 0-7 only
+# ht_mcs="0xff ff 00 00 00 00 00 00 00 00 "   // Use MCS 0-15 only
+#
+# disable_max_amsdu:  Whether MAX_AMSDU should be disabled.
+# -1 = Do not make any changes.
+# 0  = Enable MAX-AMSDU if hardware supports it.
+# 1  = Disable AMSDU
+#
+# ampdu_density:  Allow overriding AMPDU density configuration.
+#  Treated as hint by the kernel.
+# -1 = Do not make any changes.
+# 0-3 = Set AMPDU density (aka factor) to specified value.
+
+# Example blocks:
+
+# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
+network={
+	ssid="simple"
+	psk="very secret passphrase"
+	priority=5
+}
+
+# Same as previous, but request SSID-specific scanning (for APs that reject
+# broadcast SSID)
+network={
+	ssid="second ssid"
+	scan_ssid=1
+	psk="very secret passphrase"
+	priority=2
+}
+
+# Only WPA-PSK is used. Any valid cipher combination is accepted.
+network={
+	ssid="example"
+	proto=WPA
+	key_mgmt=WPA-PSK
+	pairwise=CCMP TKIP
+	group=CCMP TKIP WEP104 WEP40
+	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+	priority=2
+}
+
+# WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying
+network={
+	ssid="example"
+	proto=WPA
+	key_mgmt=WPA-PSK
+	pairwise=TKIP
+	group=TKIP
+	psk="not so secure passphrase"
+	wpa_ptk_rekey=600
+}
+
+# Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104
+# or WEP40 as the group cipher will not be accepted.
+network={
+	ssid="example"
+	proto=RSN
+	key_mgmt=WPA-EAP
+	pairwise=CCMP TKIP
+	group=CCMP TKIP
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	priority=1
+}
+
+# EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel
+# (e.g., Radiator)
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=PEAP
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase1="peaplabel=1"
+	phase2="auth=MSCHAPV2"
+	priority=10
+}
+
+# EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
+# unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user at example.com"
+	anonymous_identity="anonymous at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	priority=2
+}
+
+# EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted
+# use. Real identity is sent only within an encrypted TLS tunnel.
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user at example.com"
+	anonymous_identity="anonymous at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	phase2="auth=MSCHAPV2"
+}
+
+# WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner
+# authentication.
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	# Phase1 / outer authentication
+	anonymous_identity="anonymous at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	# Phase 2 / inner authentication
+	phase2="autheap=TLS"
+	ca_cert2="/etc/cert/ca2.pem"
+	client_cert2="/etc/cer/user.pem"
+	private_key2="/etc/cer/user.prv"
+	private_key2_passwd="password"
+	priority=2
+}
+
+# Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
+# group cipher.
+network={
+	ssid="example"
+	bssid=00:11:22:33:44:55
+	proto=WPA RSN
+	key_mgmt=WPA-PSK WPA-EAP
+	pairwise=CCMP
+	group=CCMP
+	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+}
+
+# Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP
+# and all valid ciphers.
+network={
+	ssid=00010203
+	psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+}
+
+
+# EAP-SIM with a GSM SIM or USIM
+network={
+	ssid="eap-sim-test"
+	key_mgmt=WPA-EAP
+	eap=SIM
+	pin="1234"
+	pcsc=""
+}
+
+
+# EAP-PSK
+network={
+	ssid="eap-psk-test"
+	key_mgmt=WPA-EAP
+	eap=PSK
+	anonymous_identity="eap_psk_user"
+	password=06b4be19da289f475aa46a33cb793029
+	identity="eap_psk_user at example.com"
+}
+
+
+# IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using
+# EAP-TLS for authentication and key generation; require both unicast and
+# broadcast WEP keys.
+network={
+	ssid="1x-test"
+	key_mgmt=IEEE8021X
+	eap=TLS
+	identity="user at example.com"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	eapol_flags=3
+}
+
+
+# LEAP with dynamic WEP keys
+network={
+	ssid="leap-example"
+	key_mgmt=IEEE8021X
+	eap=LEAP
+	identity="user"
+	password="foobar"
+}
+
+# EAP-IKEv2 using shared secrets for both server and peer authentication
+network={
+	ssid="ikev2-example"
+	key_mgmt=WPA-EAP
+	eap=IKEV2
+	identity="user"
+	password="foobar"
+}
+
+# EAP-FAST with WPA (WPA or WPA2)
+network={
+	ssid="eap-fast-test"
+	key_mgmt=WPA-EAP
+	eap=FAST
+	anonymous_identity="FAST-000102030405"
+	identity="username"
+	password="password"
+	phase1="fast_provisioning=1"
+	pac_file="/etc/wpa_supplicant.eap-fast-pac"
+}
+
+network={
+	ssid="eap-fast-test"
+	key_mgmt=WPA-EAP
+	eap=FAST
+	anonymous_identity="FAST-000102030405"
+	identity="username"
+	password="password"
+	phase1="fast_provisioning=1"
+	pac_file="blob://eap-fast-pac"
+}
+
+# Plaintext connection (no WPA, no IEEE 802.1X)
+network={
+	ssid="plaintext-test"
+	key_mgmt=NONE
+}
+
+
+# Shared WEP key connection (no WPA, no IEEE 802.1X)
+network={
+	ssid="static-wep-test"
+	key_mgmt=NONE
+	wep_key0="abcde"
+	wep_key1=0102030405
+	wep_key2="1234567890123"
+	wep_tx_keyidx=0
+	priority=5
+}
+
+
+# Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key
+# IEEE 802.11 authentication
+network={
+	ssid="static-wep-test2"
+	key_mgmt=NONE
+	wep_key0="abcde"
+	wep_key1=0102030405
+	wep_key2="1234567890123"
+	wep_tx_keyidx=0
+	priority=5
+	auth_alg=SHARED
+}
+
+
+# IBSS/ad-hoc network with WPA-None/TKIP.
+network={
+	ssid="test adhoc"
+	mode=1
+	frequency=2412
+	proto=WPA
+	key_mgmt=WPA-NONE
+	pairwise=NONE
+	group=TKIP
+	psk="secret passphrase"
+}
+
+
+# Catch all example that allows more or less all configuration modes
+network={
+	ssid="example"
+	scan_ssid=1
+	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+	pairwise=CCMP TKIP
+	group=CCMP TKIP WEP104 WEP40
+	psk="very secret passphrase"
+	eap=TTLS PEAP TLS
+	identity="user at example.com"
+	password="foobar"
+	ca_cert="/etc/cert/ca.pem"
+	client_cert="/etc/cert/user.pem"
+	private_key="/etc/cert/user.prv"
+	private_key_passwd="password"
+	phase1="peaplabel=0"
+}
+
+# Example of EAP-TLS with smartcard (openssl engine)
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=TLS
+	proto=RSN
+	pairwise=CCMP TKIP
+	group=CCMP TKIP
+	identity="user at 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"
+
+	# Optional PIN configuration; this can be left out and PIN will be
+	# asked through the control interface
+	pin="1234"
+}
+
+# Example configuration showing how to use an inlined blob as a CA certificate
+# data instead of using external file
+network={
+	ssid="example"
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user at example.com"
+	anonymous_identity="anonymous at example.com"
+	password="foobar"
+	ca_cert="blob://exampleblob"
+	priority=20
+}
+
+blob-base64-exampleblob={
+SGVsbG8gV29ybGQhCg==
+}
+
+
+# Wildcard match for SSID (plaintext APs only). This example select any
+# open AP regardless of its SSID.
+network={
+	key_mgmt=NONE
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.nsi
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_supplicant.nsi	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant.nsi	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,112 +0,0 @@
-!define PRODUCT_NAME "wpa_supplicant"
-!define PRODUCT_VERSION "@WPAVER@"
-!define PRODUCT_PUBLISHER "Jouni Malinen"
-
-Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
-outfile "../wpa_supplicant- at WPAVER@.exe"
-
-installDir "$PROGRAMFILES\wpa_supplicant"
-
-Page Directory
-Page InstFiles
-
-section -Prerequisites
-	SetOutPath $INSTDIR\Prerequisites
-	MessageBox MB_YESNO "Install WinPcap?" /SD IDYES IDNO endWinPcap
-		File "/opt/Qt-Win/files/WinPcap_4_1_2.exe"
-		ExecWait "$INSTDIR\Prerequisites\WinPcap_4_1_2.exe"
-		Goto endWinPcap
-	endWinPcap:
-sectionEnd
-
-
-section
-	setOutPath $INSTDIR
-
-	File wpa_gui.exe
-	File wpa_gui_de.qm
-	File wpa_cli.exe
-	File COPYING
-	File README
-	File README-Windows.txt
-	File win_example.reg
-	File win_if_list.exe
-	File wpa_passphrase.exe
-	File wpa_supplicant.conf
-	File wpa_supplicant.exe
-	File wpasvc.exe
-
-	File /opt/Qt-Win/files/mingwm10.dll
-	File /opt/Qt-Win/files/libgcc_s_dw2-1.dll
-	File /opt/Qt-Win/files/QtCore4.dll
-	File /opt/Qt-Win/files/QtGui4.dll
-
-	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_level" 0
-	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_show_keys" 0
-	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_timestamp" 0
-	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_use_file" 0
-
-	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "ap_scan" 2
-	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "update_config" 1
-	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default\networks" "dummy" 1
-	DeleteRegValue HKLM "Software\wpa_supplicant\configs\default\networks" "dummy"
-
-	WriteRegDWORD HKLM "Software\wpa_supplicant\interfaces" "dummy" 1
-	DeleteRegValue HKLM "Software\wpa_supplicant\interfaces" "dummy"
-
-	writeUninstaller "$INSTDIR\uninstall.exe"
-
-	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
-		"DisplayName" "wpa_supplicant"
-WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
-		"UninstallString" "$INSTDIR\uninstall.exe"
-
-	CreateDirectory "$SMPROGRAMS\wpa_supplicant"
-	CreateShortCut "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk" "$INSTDIR\wpa_gui.exe"
-	CreateShortCut "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk" "$INSTDIR\uninstall.exe"
-
-	ExecWait "$INSTDIR\wpasvc.exe reg"
-sectionEnd
-
-
-Function un.onInit
-	MessageBox MB_YESNO "This will uninstall wpa_supplicant. Continue?" IDYES NoAbort
-	Abort
-  NoAbort:
-FunctionEnd
-
-section "uninstall"
-	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant"
-	delete "$INSTDIR\uninstall.exe"
-
-	ExecWait "$INSTDIR\wpasvc.exe unreg"
-
-	DeleteRegKey HKLM "Software\wpa_supplicant"
-
-	delete "$INSTDIR\wpa_gui.exe"
-	delete "$INSTDIR\wpa_gui_de.qm"
-	delete "$INSTDIR\wpa_cli.exe"
-	delete "$INSTDIR\COPYING"
-	delete "$INSTDIR\README"
-	delete "$INSTDIR\README-Windows.txt"
-	delete "$INSTDIR\win_example.reg"
-	delete "$INSTDIR\win_if_list.exe"
-	delete "$INSTDIR\wpa_passphrase.exe"
-	delete "$INSTDIR\wpa_supplicant.conf"
-	delete "$INSTDIR\wpa_supplicant.exe"
-	delete "$INSTDIR\wpasvc.exe"
-
-	delete "$INSTDIR\mingwm10.dll"
-	delete "$INSTDIR\libgcc_s_dw2-1.dll"
-	delete "$INSTDIR\QtCore4.dll"
-	delete "$INSTDIR\QtGui4.dll"
-
-	delete "$INSTDIR\Prerequisites\WinPcap_4_1_2.exe"
-	rmdir "$INSTDIR\Prerequisites"
-
-	rmdir "$INSTDIR"
-
-	delete "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk"
-	delete "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk"
-	rmdir "$SMPROGRAMS\wpa_supplicant"
-sectionEnd

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.mk (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant_conf.mk)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.mk	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.mk	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+# Include this makefile to generate your hardware specific wpa_supplicant.conf
+# Requires: WIFI_DRIVER_SOCKET_IFACE
+
+LOCAL_PATH := $(call my-dir)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := wpa_supplicant.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+WPA_SUPPLICANT_CONF_TEMPLATE := $(LOCAL_PATH)/wpa_supplicant_template.conf
+WPA_SUPPLICANT_CONF_SCRIPT := $(LOCAL_PATH)/wpa_supplicant_conf.sh
+$(LOCAL_BUILT_MODULE): PRIVATE_WIFI_DRIVER_SOCKET_IFACE := $(WIFI_DRIVER_SOCKET_IFACE)
+$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE := $(WPA_SUPPLICANT_CONF_TEMPLATE)
+$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT := $(WPA_SUPPLICANT_CONF_SCRIPT)
+$(LOCAL_BUILT_MODULE) : $(WPA_SUPPLICANT_CONF_TEMPLATE) $(WPA_SUPPLICANT_CONF_SCRIPT)
+	@echo Target wpa_supplicant.conf: $@
+	@mkdir -p $(dir $@)
+	$(hide) WIFI_DRIVER_SOCKET_IFACE="$(PRIVATE_WIFI_DRIVER_SOCKET_IFACE)" \
+		bash $(PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT) $(PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE) > $@
+
+########################

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.sh (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant_conf.sh)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.sh	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_conf.sh	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+# Generate a wpa_supplicant.conf from the template.
+# $1: the template file name
+if [ -n "$WIFI_DRIVER_SOCKET_IFACE" ]
+then
+  sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1 | sed -e "s/wlan0/$WIFI_DRIVER_SOCKET_IFACE/"
+else
+  sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1
+fi

Deleted: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpa_supplicant_i.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,512 +0,0 @@
-/*
- * wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPA_SUPPLICANT_I_H
-#define WPA_SUPPLICANT_I_H
-
-#include "utils/list.h"
-#include "common/defs.h"
-
-extern const char *wpa_supplicant_version;
-extern const char *wpa_supplicant_license;
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern const char *wpa_supplicant_full_license1;
-extern const char *wpa_supplicant_full_license2;
-extern const char *wpa_supplicant_full_license3;
-extern const char *wpa_supplicant_full_license4;
-extern const char *wpa_supplicant_full_license5;
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-struct wpa_sm;
-struct wpa_supplicant;
-struct ibss_rsn;
-struct scan_info;
-struct wpa_bss;
-struct wpa_scan_results;
-
-/*
- * Forward declarations of private structures used within the ctrl_iface
- * backends. Other parts of wpa_supplicant do not have access to data stored in
- * these structures.
- */
-struct ctrl_iface_priv;
-struct ctrl_iface_global_priv;
-struct wpas_dbus_priv;
-
-/**
- * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
- */
-struct wpa_interface {
-	/**
-	 * confname - Configuration name (file or profile) name
-	 *
-	 * This can also be %NULL when a configuration file is not used. In
-	 * that case, ctrl_interface must be set to allow the interface to be
-	 * configured.
-	 */
-	const char *confname;
-
-	/**
-	 * ctrl_interface - Control interface parameter
-	 *
-	 * If a configuration file is not used, this variable can be used to
-	 * set the ctrl_interface parameter that would have otherwise been read
-	 * from the configuration file. If both confname and ctrl_interface are
-	 * set, ctrl_interface is used to override the value from configuration
-	 * file.
-	 */
-	const char *ctrl_interface;
-
-	/**
-	 * driver - Driver interface name, or %NULL to use the default driver
-	 */
-	const char *driver;
-
-	/**
-	 * driver_param - Driver interface parameters
-	 *
-	 * If a configuration file is not used, this variable can be used to
-	 * set the driver_param parameters that would have otherwise been read
-	 * from the configuration file. If both confname and driver_param are
-	 * set, driver_param is used to override the value from configuration
-	 * file.
-	 */
-	const char *driver_param;
-
-	/**
-	 * ifname - Interface name
-	 */
-	const char *ifname;
-
-	/**
-	 * bridge_ifname - Optional bridge interface name
-	 *
-	 * If the driver interface (ifname) is included in a Linux bridge
-	 * device, the bridge interface may need to be used for receiving EAPOL
-	 * frames. This can be enabled by setting this variable to enable
-	 * receiving of EAPOL frames from an additional interface.
-	 */
-	const char *bridge_ifname;
-};
-
-/**
- * struct wpa_params - Parameters for wpa_supplicant_init()
- */
-struct wpa_params {
-	/**
-	 * daemonize - Run %wpa_supplicant in the background
-	 */
-	int daemonize;
-
-	/**
-	 * wait_for_monitor - Wait for a monitor program before starting
-	 */
-	int wait_for_monitor;
-
-	/**
-	 * pid_file - Path to a PID (process ID) file
-	 *
-	 * If this and daemonize are set, process ID of the background process
-	 * will be written to the specified file.
-	 */
-	char *pid_file;
-
-	/**
-	 * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO)
-	 */
-	int wpa_debug_level;
-
-	/**
-	 * wpa_debug_show_keys - Whether keying material is included in debug
-	 *
-	 * This parameter can be used to allow keying material to be included
-	 * in debug messages. This is a security risk and this option should
-	 * not be enabled in normal configuration. If needed during
-	 * development or while troubleshooting, this option can provide more
-	 * details for figuring out what is happening.
-	 */
-	int wpa_debug_show_keys;
-
-	/**
-	 * wpa_debug_timestamp - Whether to include timestamp in debug messages
-	 */
-	int wpa_debug_timestamp;
-
-	/**
-	 * ctrl_interface - Global ctrl_iface path/parameter
-	 */
-	char *ctrl_interface;
-
-	/**
-	 * dbus_ctrl_interface - Enable the DBus control interface
-	 */
-	int dbus_ctrl_interface;
-
-	/**
-	 * wpa_debug_file_path - Path of debug file or %NULL to use stdout
-	 */
-	const char *wpa_debug_file_path;
-
-	/**
-	 * wpa_debug_syslog - Enable log output through syslog
-	 */
-	int wpa_debug_syslog;
-
-	/**
-	 * override_driver - Optional driver parameter override
-	 *
-	 * This parameter can be used to override the driver parameter in
-	 * dynamic interface addition to force a specific driver wrapper to be
-	 * used instead.
-	 */
-	char *override_driver;
-
-	/**
-	 * override_ctrl_interface - Optional ctrl_interface override
-	 *
-	 * This parameter can be used to override the ctrl_interface parameter
-	 * in dynamic interface addition to force a control interface to be
-	 * created.
-	 */
-	char *override_ctrl_interface;
-};
-
-/**
- * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
- *
- * This structure is initialized by calling wpa_supplicant_init() when starting
- * %wpa_supplicant.
- */
-struct wpa_global {
-	struct wpa_supplicant *ifaces;
-	struct wpa_params params;
-	struct ctrl_iface_global_priv *ctrl_iface;
-	struct wpas_dbus_priv *dbus;
-	void **drv_priv;
-	size_t drv_count;
-	struct os_time suspend_time;
-};
-
-
-struct wpa_client_mlme {
-#ifdef CONFIG_CLIENT_MLME
-	enum {
-		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
-		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
-	} state;
-	u8 prev_bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
-	u16 aid;
-	u16 ap_capab, capab;
-	u8 *extra_ie; /* to be added to the end of AssocReq */
-	size_t extra_ie_len;
-	u8 *extra_probe_ie; /* to be added to the end of ProbeReq */
-	size_t extra_probe_ie_len;
-	enum wpa_key_mgmt key_mgmt;
-
-	/* The last AssocReq/Resp IEs */
-	u8 *assocreq_ies, *assocresp_ies;
-	size_t assocreq_ies_len, assocresp_ies_len;
-
-	int auth_tries, assoc_tries;
-
-	unsigned int ssid_set:1;
-	unsigned int bssid_set:1;
-	unsigned int prev_bssid_set:1;
-	unsigned int authenticated:1;
-	unsigned int associated:1;
-	unsigned int probereq_poll:1;
-	unsigned int use_protection:1;
-	unsigned int create_ibss:1;
-	unsigned int mixed_cell:1;
-	unsigned int wmm_enabled:1;
-
-	struct os_time last_probe;
-
-	unsigned int auth_algs; /* bitfield of allowed auth algs
-				 * (WPA_AUTH_ALG_*) */
-	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-	int auth_transaction;
-
-	struct os_time ibss_join_req;
-	u8 *probe_resp; /* ProbeResp template for IBSS */
-	size_t probe_resp_len;
-	u32 supp_rates_bits;
-
-	int wmm_last_param_set;
-
-	int sta_scanning;
-	int scan_hw_mode_idx;
-	int scan_channel_idx;
-	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
-	struct os_time last_scan_completed;
-	int scan_oper_channel;
-	int scan_oper_freq;
-	int scan_oper_phymode;
-	u8 scan_ssid[32];
-	size_t scan_ssid_len;
-	int scan_skip_11b;
-	int *scan_freqs;
-
-	struct ieee80211_sta_bss *sta_bss_list;
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-	struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
-
-	int cts_protect_erp_frames;
-
-	enum hostapd_hw_mode phymode; /* current mode */
-	struct hostapd_hw_modes *modes;
-	size_t num_modes;
-	unsigned int hw_modes; /* bitfield of allowed hardware modes;
-				* (1 << HOSTAPD_MODE_*) */
-	int num_curr_rates;
-	int *curr_rates;
-	int freq; /* The current frequency in MHz */
-	int channel; /* The current IEEE 802.11 channel number */
-
-#ifdef CONFIG_IEEE80211R
-	u8 current_md[6];
-	u8 *ft_ies;
-	size_t ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-
-	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
-				 int freq);
-	void *public_action_cb_ctx;
-
-#else /* CONFIG_CLIENT_MLME */
-	int dummy; /* to keep MSVC happy */
-#endif /* CONFIG_CLIENT_MLME */
-};
-
-/**
- * struct wpa_supplicant - Internal data for wpa_supplicant interface
- *
- * This structure contains the internal data for core wpa_supplicant code. This
- * should be only used directly from the core code. However, a pointer to this
- * data is used from other files as an arbitrary context pointer in calls to
- * core functions.
- */
-struct wpa_supplicant {
-	struct wpa_global *global;
-	struct wpa_supplicant *next;
-	struct l2_packet_data *l2;
-	struct l2_packet_data *l2_br;
-	unsigned char own_addr[ETH_ALEN];
-	char ifname[100];
-#ifdef CONFIG_CTRL_IFACE_DBUS
-	char *dbus_path;
-#endif /* CONFIG_CTRL_IFACE_DBUS */
-#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-	char *dbus_new_path;
-#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-	char bridge_ifname[16];
-
-	char *confname;
-	struct wpa_config *conf;
-	int countermeasures;
-	os_time_t last_michael_mic_error;
-	u8 bssid[ETH_ALEN];
-	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
-				     * field contains the targer BSSID. */
-	int reassociate; /* reassociation requested */
-	int disconnected; /* all connections disabled; i.e., do no reassociate
-			   * before this has been cleared */
-	struct wpa_ssid *current_ssid;
-	struct wpa_bss *current_bss;
-	int ap_ies_from_associnfo;
-	unsigned int assoc_freq;
-
-	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
-	int pairwise_cipher;
-	int group_cipher;
-	int key_mgmt;
-	int mgmt_group_cipher;
-
-	void *drv_priv; /* private data used by driver_ops */
-	void *global_drv_priv;
-
-	struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID;
-					  * NULL = not yet initialized (start
-					  * with wildcard SSID)
-					  * WILDCARD_SSID_SCAN = wildcard
-					  * SSID was used in the previous scan
-					  */
-#define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1)
-
-	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
-				 struct wpa_scan_results *scan_res);
-	struct dl_list bss; /* struct wpa_bss::list */
-	struct dl_list bss_id; /* struct wpa_bss::list_id */
-	size_t num_bss;
-	unsigned int bss_update_idx;
-	unsigned int bss_next_id;
-
-	struct wpa_driver_ops *driver;
-	int interface_removed; /* whether the network interface has been
-				* removed */
-	struct wpa_sm *wpa;
-	struct eapol_sm *eapol;
-
-	struct ctrl_iface_priv *ctrl_iface;
-
-	enum wpa_states wpa_state;
-	int scanning;
-	int new_connection;
-	int reassociated_connection;
-
-	int eapol_received; /* number of EAPOL packets received after the
-			     * previous association event */
-
-	struct scard_data *scard;
-
-	unsigned char last_eapol_src[ETH_ALEN];
-
-	int keys_cleared;
-
-	struct wpa_blacklist *blacklist;
-
-	int scan_req; /* manual scan request; this forces a scan even if there
-		       * are no enabled networks in the configuration */
-	int scan_runs; /* number of scan runs since WPS was started */
-
-	struct wpa_client_mlme mlme;
-	unsigned int drv_flags;
-	int max_scan_ssids;
-	unsigned int max_remain_on_chan;
-
-	int pending_mic_error_report;
-	int pending_mic_error_pairwise;
-	int mic_errors_seen; /* Michael MIC errors with the current PTK */
-
-	struct wps_context *wps;
-	int wps_success; /* WPS success event received */
-	struct wps_er *wps_er;
-	int blacklist_cleared;
-
-	struct wpabuf *pending_eapol_rx;
-	struct os_time pending_eapol_rx_time;
-	u8 pending_eapol_rx_src[ETH_ALEN];
-
-	struct ibss_rsn *ibss_rsn;
-
-#ifdef CONFIG_SME
-	struct {
-		u8 ssid[32];
-		size_t ssid_len;
-		int freq;
-		u8 assoc_req_ie[80];
-		size_t assoc_req_ie_len;
-		int mfp;
-		int ft_used;
-		u8 mobility_domain[2];
-		u8 *ft_ies;
-		size_t ft_ies_len;
-		u8 prev_bssid[ETH_ALEN];
-		int prev_bssid_set;
-		int auth_alg;
-	} sme;
-#endif /* CONFIG_SME */
-
-#ifdef CONFIG_AP
-	struct hostapd_iface *ap_iface;
-	void (*ap_configured_cb)(void *ctx, void *data);
-	void *ap_configured_cb_ctx;
-	void *ap_configured_cb_data;
-#endif /* CONFIG_AP */
-
-	struct wpa_ssid *bgscan_ssid;
-	const struct bgscan_ops *bgscan;
-	void *bgscan_priv;
-
-	int connect_without_scan;
-
-	int after_wps;
-	unsigned int wps_freq;
-};
-
-
-/* wpa_supplicant.c */
-int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-
-int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
-
-const char * wpa_supplicant_state_txt(enum wpa_states state);
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *bss, struct wpa_ssid *ssid,
-			      u8 *wpa_ie, size_t *wpa_ie_len);
-void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *bss,
-			      struct wpa_ssid *ssid);
-void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
-				       struct wpa_ssid *ssid);
-void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
-void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
-void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
-				     int sec, int usec);
-void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
-			      enum wpa_states state);
-struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
-				   int reason_code);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
-				 int reason_code);
-
-void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid);
-void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
-				    struct wpa_ssid *ssid);
-void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
-				   struct wpa_ssid *ssid);
-int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
-			       int ap_scan);
-int wpa_supplicant_set_debug_params(struct wpa_global *global,
-				    int debug_level, int debug_timestamp,
-				    int debug_show_keys);
-
-void wpa_show_license(void);
-
-struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
-						 struct wpa_interface *iface);
-int wpa_supplicant_remove_iface(struct wpa_global *global,
-				struct wpa_supplicant *wpa_s);
-struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
-						 const char *ifname);
-struct wpa_global * wpa_supplicant_init(struct wpa_params *params);
-int wpa_supplicant_run(struct wpa_global *global);
-void wpa_supplicant_deinit(struct wpa_global *global);
-
-int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid);
-void wpa_supplicant_terminate_proc(struct wpa_global *global);
-void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
-			     const u8 *buf, size_t len);
-enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
-enum wpa_cipher cipher_suite2driver(int cipher);
-
-/* events.c */
-void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-			    struct wpa_bss *selected,
-			    struct wpa_ssid *ssid);
-
-/* eap_register.c */
-int eap_register_methods(void);
-
-#endif /* WPA_SUPPLICANT_I_H */

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant_i.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_i.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,808 @@
+/*
+ * wpa_supplicant - Internal definitions
+ * Copyright (c) 2003-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_I_H
+#define WPA_SUPPLICANT_I_H
+
+#include "utils/list.h"
+#include "common/defs.h"
+#include "config_ssid.h"
+
+extern const char *wpa_supplicant_version;
+extern const char *wpa_supplicant_license;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern const char *wpa_supplicant_full_license1;
+extern const char *wpa_supplicant_full_license2;
+extern const char *wpa_supplicant_full_license3;
+extern const char *wpa_supplicant_full_license4;
+extern const char *wpa_supplicant_full_license5;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+struct wpa_sm;
+struct wpa_supplicant;
+struct ibss_rsn;
+struct scan_info;
+struct wpa_bss;
+struct wpa_scan_results;
+struct hostapd_hw_modes;
+struct wpa_driver_associate_params;
+
+/*
+ * Forward declarations of private structures used within the ctrl_iface
+ * backends. Other parts of wpa_supplicant do not have access to data stored in
+ * these structures.
+ */
+struct ctrl_iface_priv;
+struct ctrl_iface_global_priv;
+struct wpas_dbus_priv;
+
+/**
+ * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
+ */
+struct wpa_interface {
+	/**
+	 * confname - Configuration name (file or profile) name
+	 *
+	 * This can also be %NULL when a configuration file is not used. In
+	 * that case, ctrl_interface must be set to allow the interface to be
+	 * configured.
+	 */
+	const char *confname;
+
+	/**
+	 * ctrl_interface - Control interface parameter
+	 *
+	 * If a configuration file is not used, this variable can be used to
+	 * set the ctrl_interface parameter that would have otherwise been read
+	 * from the configuration file. If both confname and ctrl_interface are
+	 * set, ctrl_interface is used to override the value from configuration
+	 * file.
+	 */
+	const char *ctrl_interface;
+
+	/**
+	 * driver - Driver interface name, or %NULL to use the default driver
+	 */
+	const char *driver;
+
+	/**
+	 * driver_param - Driver interface parameters
+	 *
+	 * If a configuration file is not used, this variable can be used to
+	 * set the driver_param parameters that would have otherwise been read
+	 * from the configuration file. If both confname and driver_param are
+	 * set, driver_param is used to override the value from configuration
+	 * file.
+	 */
+	const char *driver_param;
+
+	/**
+	 * ifname - Interface name
+	 */
+	const char *ifname;
+
+	/**
+	 * bridge_ifname - Optional bridge interface name
+	 *
+	 * If the driver interface (ifname) is included in a Linux bridge
+	 * device, the bridge interface may need to be used for receiving EAPOL
+	 * frames. This can be enabled by setting this variable to enable
+	 * receiving of EAPOL frames from an additional interface.
+	 */
+	const char *bridge_ifname;
+};
+
+/**
+ * struct wpa_params - Parameters for wpa_supplicant_init()
+ */
+struct wpa_params {
+	/**
+	 * daemonize - Run %wpa_supplicant in the background
+	 */
+	int daemonize;
+
+	/**
+	 * wait_for_monitor - Wait for a monitor program before starting
+	 */
+	int wait_for_monitor;
+
+	/**
+	 * pid_file - Path to a PID (process ID) file
+	 *
+	 * If this and daemonize are set, process ID of the background process
+	 * will be written to the specified file.
+	 */
+	char *pid_file;
+
+	/**
+	 * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO)
+	 */
+	int wpa_debug_level;
+
+	/**
+	 * wpa_debug_show_keys - Whether keying material is included in debug
+	 *
+	 * This parameter can be used to allow keying material to be included
+	 * in debug messages. This is a security risk and this option should
+	 * not be enabled in normal configuration. If needed during
+	 * development or while troubleshooting, this option can provide more
+	 * details for figuring out what is happening.
+	 */
+	int wpa_debug_show_keys;
+
+	/**
+	 * wpa_debug_timestamp - Whether to include timestamp in debug messages
+	 */
+	int wpa_debug_timestamp;
+
+	/**
+	 * ctrl_interface - Global ctrl_iface path/parameter
+	 */
+	char *ctrl_interface;
+
+	/**
+	 * dbus_ctrl_interface - Enable the DBus control interface
+	 */
+	int dbus_ctrl_interface;
+
+	/**
+	 * wpa_debug_file_path - Path of debug file or %NULL to use stdout
+	 */
+	const char *wpa_debug_file_path;
+
+	/**
+	 * wpa_debug_syslog - Enable log output through syslog
+	 */
+	int wpa_debug_syslog;
+
+	/**
+	 * wpa_debug_tracing - Enable log output through Linux tracing
+	 */
+	int wpa_debug_tracing;
+
+	/**
+	 * override_driver - Optional driver parameter override
+	 *
+	 * This parameter can be used to override the driver parameter in
+	 * dynamic interface addition to force a specific driver wrapper to be
+	 * used instead.
+	 */
+	char *override_driver;
+
+	/**
+	 * override_ctrl_interface - Optional ctrl_interface override
+	 *
+	 * This parameter can be used to override the ctrl_interface parameter
+	 * in dynamic interface addition to force a control interface to be
+	 * created.
+	 */
+	char *override_ctrl_interface;
+
+	/**
+	 * entropy_file - Optional entropy file
+	 *
+	 * This parameter can be used to configure wpa_supplicant to maintain
+	 * its internal entropy store over restarts.
+	 */
+	char *entropy_file;
+};
+
+struct p2p_srv_bonjour {
+	struct dl_list list;
+	struct wpabuf *query;
+	struct wpabuf *resp;
+};
+
+struct p2p_srv_upnp {
+	struct dl_list list;
+	u8 version;
+	char *service;
+};
+
+struct wpa_freq_range {
+	unsigned int min;
+	unsigned int max;
+};
+
+
+/**
+ * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
+ *
+ * This structure is initialized by calling wpa_supplicant_init() when starting
+ * %wpa_supplicant.
+ */
+struct wpa_global {
+	struct wpa_supplicant *ifaces;
+	struct wpa_params params;
+	struct ctrl_iface_global_priv *ctrl_iface;
+	struct wpas_dbus_priv *dbus;
+	void **drv_priv;
+	size_t drv_count;
+	struct os_time suspend_time;
+	struct p2p_data *p2p;
+	struct wpa_supplicant *p2p_init_wpa_s;
+	struct wpa_supplicant *p2p_group_formation;
+	u8 p2p_dev_addr[ETH_ALEN];
+	struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
+	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
+	int p2p_disabled;
+	int cross_connection;
+	struct wpa_freq_range *p2p_disallow_freq;
+	unsigned int num_p2p_disallow_freq;
+	enum wpa_conc_pref {
+		WPA_CONC_PREF_NOT_SET,
+		WPA_CONC_PREF_STA,
+		WPA_CONC_PREF_P2P
+	} conc_pref;
+	unsigned int p2p_cb_on_scan_complete:1;
+
+#ifdef CONFIG_WIFI_DISPLAY
+	int wifi_display;
+#define MAX_WFD_SUBELEMS 10
+	struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
+#endif /* CONFIG_WIFI_DISPLAY */
+};
+
+
+/**
+ * offchannel_send_action_result - Result of offchannel send Action frame
+ */
+enum offchannel_send_action_result {
+	OFFCHANNEL_SEND_ACTION_SUCCESS /**< Frame was send and acknowledged */,
+	OFFCHANNEL_SEND_ACTION_NO_ACK /**< Frame was sent, but not acknowledged
+				       */,
+	OFFCHANNEL_SEND_ACTION_FAILED /**< Frame was not sent due to a failure
+				       */
+};
+
+struct wps_ap_info {
+	u8 bssid[ETH_ALEN];
+	enum wps_ap_info_type {
+		WPS_AP_NOT_SEL_REG,
+		WPS_AP_SEL_REG,
+		WPS_AP_SEL_REG_OUR
+	} type;
+	unsigned int tries;
+	struct os_time last_attempt;
+};
+
+struct wpa_ssid_value {
+	u8 ssid[32];
+	size_t ssid_len;
+};
+
+/**
+ * struct wpa_supplicant - Internal data for wpa_supplicant interface
+ *
+ * This structure contains the internal data for core wpa_supplicant code. This
+ * should be only used directly from the core code. However, a pointer to this
+ * data is used from other files as an arbitrary context pointer in calls to
+ * core functions.
+ */
+struct wpa_supplicant {
+	struct wpa_global *global;
+	struct wpa_supplicant *parent;
+	struct wpa_supplicant *next;
+	struct l2_packet_data *l2;
+	struct l2_packet_data *l2_br;
+	unsigned char own_addr[ETH_ALEN];
+	char ifname[100];
+#ifdef CONFIG_CTRL_IFACE_DBUS
+	char *dbus_path;
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+	char *dbus_new_path;
+	char *dbus_groupobj_path;
+#ifdef CONFIG_AP
+	char *preq_notify_peer;
+#endif /* CONFIG_AP */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+	char bridge_ifname[16];
+
+	char *confname;
+	struct wpa_config *conf;
+	int countermeasures;
+	os_time_t last_michael_mic_error;
+	u8 bssid[ETH_ALEN];
+	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
+				     * field contains the target BSSID. */
+	int reassociate; /* reassociation requested */
+	int disconnected; /* all connections disabled; i.e., do no reassociate
+			   * before this has been cleared */
+	struct wpa_ssid *current_ssid;
+	struct wpa_bss *current_bss;
+	int ap_ies_from_associnfo;
+	unsigned int assoc_freq;
+
+	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int wpa_proto;
+	int mgmt_group_cipher;
+
+	void *drv_priv; /* private data used by driver_ops */
+	void *global_drv_priv;
+
+	u8 *bssid_filter;
+	size_t bssid_filter_count;
+
+	u8 *disallow_aps_bssid;
+	size_t disallow_aps_bssid_count;
+	struct wpa_ssid_value *disallow_aps_ssid;
+	size_t disallow_aps_ssid_count;
+
+	/* previous scan was wildcard when interleaving between
+	 * wildcard scans and specific SSID scan when max_ssids=1 */
+	int prev_scan_wildcard;
+	struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID;
+					  * NULL = not yet initialized (start
+					  * with wildcard SSID)
+					  * WILDCARD_SSID_SCAN = wildcard
+					  * SSID was used in the previous scan
+					  */
+#define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1)
+
+	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;
+
+	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+				 struct wpa_scan_results *scan_res);
+	struct dl_list bss; /* struct wpa_bss::list */
+	struct dl_list bss_id; /* struct wpa_bss::list_id */
+	size_t num_bss;
+	unsigned int bss_update_idx;
+	unsigned int bss_next_id;
+
+	 /*
+	  * Pointers to BSS entries in the order they were in the last scan
+	  * results.
+	  */
+	struct wpa_bss **last_scan_res;
+	unsigned int last_scan_res_used;
+	unsigned int last_scan_res_size;
+	int last_scan_full;
+	struct os_time last_scan;
+
+	struct wpa_driver_ops *driver;
+	int interface_removed; /* whether the network interface has been
+				* removed */
+	struct wpa_sm *wpa;
+	struct eapol_sm *eapol;
+
+	struct ctrl_iface_priv *ctrl_iface;
+
+	enum wpa_states wpa_state;
+	int scanning;
+	int sched_scanning;
+	int new_connection;
+
+	int eapol_received; /* number of EAPOL packets received after the
+			     * previous association event */
+
+	struct scard_data *scard;
+#ifdef PCSC_FUNCS
+	char imsi[20];
+	int mnc_len;
+#endif /* PCSC_FUNCS */
+
+	unsigned char last_eapol_src[ETH_ALEN];
+
+	int keys_cleared;
+
+	struct wpa_blacklist *blacklist;
+
+	/**
+	 * extra_blacklist_count - Sum of blacklist counts after last connection
+	 *
+	 * This variable is used to maintain a count of temporary blacklisting
+	 * failures (maximum number for any BSS) over blacklist clear
+	 * operations. This is needed for figuring out whether there has been
+	 * failures prior to the last blacklist clear operation which happens
+	 * whenever no other not-blacklisted BSS candidates are available. This
+	 * gets cleared whenever a connection has been established successfully.
+	 */
+	int extra_blacklist_count;
+
+	/**
+	 * scan_req - Type of the scan request
+	 */
+	enum scan_req_type {
+		/**
+		 * NORMAL_SCAN_REQ - Normal scan request
+		 *
+		 * This is used for scans initiated by wpa_supplicant to find an
+		 * AP for a connection.
+		 */
+		NORMAL_SCAN_REQ,
+
+		/**
+		 * INITIAL_SCAN_REQ - Initial scan request
+		 *
+		 * This is used for the first scan on an interface to force at
+		 * least one scan to be run even if the configuration does not
+		 * include any enabled networks.
+		 */
+		INITIAL_SCAN_REQ,
+
+		/**
+		 * MANUAL_SCAN_REQ - Manual scan request
+		 *
+		 * This is used for scans where the user request a scan or
+		 * a specific wpa_supplicant operation (e.g., WPS) requires scan
+		 * to be run.
+		 */
+		MANUAL_SCAN_REQ
+	} scan_req;
+	int scan_runs; /* number of scan runs since WPS was started */
+	int *next_scan_freqs;
+	int scan_interval; /* time in sec between scans to find suitable AP */
+	int normal_scans; /* normal scans run before sched_scan */
+	int scan_for_connection; /* whether the scan request was triggered for
+				  * finding a connection */
+
+	unsigned int drv_flags;
+	unsigned int drv_enc;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
+	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	unsigned int max_match_sets;
+	unsigned int max_remain_on_chan;
+	unsigned int max_stations;
+
+	int pending_mic_error_report;
+	int pending_mic_error_pairwise;
+	int mic_errors_seen; /* Michael MIC errors with the current PTK */
+
+	struct wps_context *wps;
+	int wps_success; /* WPS success event received */
+	struct wps_er *wps_er;
+	int blacklist_cleared;
+
+	struct wpabuf *pending_eapol_rx;
+	struct os_time pending_eapol_rx_time;
+	u8 pending_eapol_rx_src[ETH_ALEN];
+	unsigned int last_eapol_matches_bssid:1;
+
+	struct ibss_rsn *ibss_rsn;
+
+	int set_sta_uapsd;
+	int sta_uapsd;
+	int set_ap_uapsd;
+	int ap_uapsd;
+
+#ifdef CONFIG_SME
+	struct {
+		u8 ssid[32];
+		size_t ssid_len;
+		int freq;
+		u8 assoc_req_ie[200];
+		size_t assoc_req_ie_len;
+		int mfp;
+		int ft_used;
+		u8 mobility_domain[2];
+		u8 *ft_ies;
+		size_t ft_ies_len;
+		u8 prev_bssid[ETH_ALEN];
+		int prev_bssid_set;
+		int auth_alg;
+		int proto;
+
+		int sa_query_count; /* number of pending SA Query requests;
+				     * 0 = no SA Query in progress */
+		int sa_query_timed_out;
+		u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+					* sa_query_count octets of pending
+					* SA Query transaction identifiers */
+		struct os_time sa_query_start;
+		u8 sched_obss_scan;
+		u16 obss_scan_int;
+		u16 bss_max_idle_period;
+		enum {
+			SME_SAE_INIT,
+			SME_SAE_COMMIT,
+			SME_SAE_CONFIRM
+		} sae_state;
+		u16 sae_send_confirm;
+	} sme;
+#endif /* CONFIG_SME */
+
+#ifdef CONFIG_AP
+	struct hostapd_iface *ap_iface;
+	void (*ap_configured_cb)(void *ctx, void *data);
+	void *ap_configured_cb_ctx;
+	void *ap_configured_cb_data;
+#endif /* CONFIG_AP */
+
+	unsigned int off_channel_freq;
+	struct wpabuf *pending_action_tx;
+	u8 pending_action_src[ETH_ALEN];
+	u8 pending_action_dst[ETH_ALEN];
+	u8 pending_action_bssid[ETH_ALEN];
+	unsigned int pending_action_freq;
+	int pending_action_no_cck;
+	int pending_action_without_roc;
+	void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
+					    unsigned int freq, const u8 *dst,
+					    const u8 *src, const u8 *bssid,
+					    const u8 *data, size_t data_len,
+					    enum offchannel_send_action_result
+					    result);
+	unsigned int roc_waiting_drv_freq;
+	int action_tx_wait_time;
+
+#ifdef CONFIG_P2P
+	struct p2p_go_neg_results *go_params;
+	int create_p2p_iface;
+	u8 pending_interface_addr[ETH_ALEN];
+	char pending_interface_name[100];
+	int pending_interface_type;
+	int p2p_group_idx;
+	unsigned int pending_listen_freq;
+	unsigned int pending_listen_duration;
+	enum {
+		NOT_P2P_GROUP_INTERFACE,
+		P2P_GROUP_INTERFACE_PENDING,
+		P2P_GROUP_INTERFACE_GO,
+		P2P_GROUP_INTERFACE_CLIENT
+	} p2p_group_interface;
+	struct p2p_group *p2p_group;
+	int p2p_long_listen; /* remaining time in long Listen state in ms */
+	char p2p_pin[10];
+	int p2p_wps_method;
+	u8 p2p_auth_invite[ETH_ALEN];
+	int p2p_sd_over_ctrl_iface;
+	int p2p_in_provisioning;
+	int pending_invite_ssid_id;
+	int show_group_started;
+	u8 go_dev_addr[ETH_ALEN];
+	int pending_pd_before_join;
+	u8 pending_join_iface_addr[ETH_ALEN];
+	u8 pending_join_dev_addr[ETH_ALEN];
+	int pending_join_wps_method;
+	int p2p_join_scan_count;
+	int auto_pd_scan_retry;
+	int force_long_sd;
+	u16 pending_pd_config_methods;
+	enum {
+		NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+	} pending_pd_use;
+
+	/*
+	 * Whether cross connection is disallowed by the AP to which this
+	 * interface is associated (only valid if there is an association).
+	 */
+	int cross_connect_disallowed;
+
+	/*
+	 * Whether this P2P group is configured to use cross connection (only
+	 * valid if this is P2P GO interface). The actual cross connect packet
+	 * forwarding may not be configured depending on the uplink status.
+	 */
+	int cross_connect_enabled;
+
+	/* Whether cross connection forwarding is in use at the moment. */
+	int cross_connect_in_use;
+
+	/*
+	 * Uplink interface name for cross connection
+	 */
+	char cross_connect_uplink[100];
+
+	unsigned int sta_scan_pending:1;
+	unsigned int p2p_auto_join:1;
+	unsigned int p2p_auto_pd:1;
+	unsigned int p2p_persistent_group:1;
+	unsigned int p2p_fallback_to_go_neg:1;
+	unsigned int p2p_pd_before_go_neg:1;
+	unsigned int p2p_go_ht40:1;
+	unsigned int user_initiated_pd:1;
+	int p2p_persistent_go_freq;
+	int p2p_persistent_id;
+	int p2p_go_intent;
+	int p2p_connect_freq;
+	struct os_time p2p_auto_started;
+#endif /* CONFIG_P2P */
+
+	struct wpa_ssid *bgscan_ssid;
+	const struct bgscan_ops *bgscan;
+	void *bgscan_priv;
+
+	const struct autoscan_ops *autoscan;
+	struct wpa_driver_scan_params *autoscan_params;
+	void *autoscan_priv;
+
+	struct wpa_ssid *connect_without_scan;
+
+	struct wps_ap_info *wps_ap;
+	size_t num_wps_ap;
+	int wps_ap_iter;
+
+	int after_wps;
+	int known_wps_freq;
+	unsigned int wps_freq;
+	u16 wps_ap_channel;
+	int wps_fragment_size;
+	int auto_reconnect_disabled;
+
+	 /* Channel preferences for AP/P2P GO use */
+	int best_24_freq;
+	int best_5_freq;
+	int best_overall_freq;
+
+	struct gas_query *gas;
+
+#ifdef CONFIG_INTERWORKING
+	unsigned int fetch_anqp_in_progress:1;
+	unsigned int network_select:1;
+	unsigned int auto_select:1;
+	unsigned int auto_network_select:1;
+	unsigned int fetch_all_anqp:1;
+#endif /* CONFIG_INTERWORKING */
+	unsigned int drv_capa_known;
+
+	struct {
+		struct hostapd_hw_modes *modes;
+		u16 num_modes;
+		u16 flags;
+	} hw;
+
+	int pno;
+
+	/* WLAN_REASON_* reason codes. Negative if locally generated. */
+	int disconnect_reason;
+
+	struct ext_password_data *ext_pw;
+
+	struct wpabuf *last_gas_resp;
+	u8 last_gas_addr[ETH_ALEN];
+	u8 last_gas_dialog_token;
+
+	unsigned int no_keep_alive:1;
+};
+
+
+/* wpa_supplicant.c */
+void wpa_supplicant_apply_ht_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params);
+
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
+int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
+
+const char * wpa_supplicant_state_txt(enum wpa_states state);
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid,
+			      u8 *wpa_ie, size_t *wpa_ie_len);
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss,
+			      struct wpa_ssid *ssid);
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid);
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
+void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
+				     int sec, int usec);
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
+			      enum wpa_states state);
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
+				   int reason_code);
+
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid);
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid);
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid);
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
+			       int ap_scan);
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+					  unsigned int expire_age);
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+					    unsigned int expire_count);
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+				     int scan_interval);
+int wpa_supplicant_set_debug_params(struct wpa_global *global,
+				    int debug_level, int debug_timestamp,
+				    int debug_show_keys);
+void free_hw_features(struct wpa_supplicant *wpa_s);
+
+void wpa_show_license(void);
+
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+						 struct wpa_interface *iface);
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+				struct wpa_supplicant *wpa_s,
+				int terminate);
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+						 const char *ifname);
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params);
+int wpa_supplicant_run(struct wpa_global *global);
+void wpa_supplicant_deinit(struct wpa_global *global);
+
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+void wpa_supplicant_terminate_proc(struct wpa_global *global);
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+			     const u8 *buf, size_t len);
+enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
+enum wpa_cipher cipher_suite2driver(int cipher);
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s);
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, int clear_failures);
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len);
+void wpas_request_connection(struct wpa_supplicant *wpa_s);
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
+
+/**
+ * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value);
+
+/* events.c */
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid);
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
+int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+
+/* eap_register.c */
+int eap_register_methods(void);
+
+/**
+ * Utility method to tell if a given network is a persistent group
+ * @ssid: Network object
+ * Returns: 1 if network is a persistent group, 0 otherwise
+ */
+static inline int network_is_persistent_group(struct wpa_ssid *ssid)
+{
+	return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
+}
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
+#endif /* WPA_SUPPLICANT_I_H */

Copied: vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_template.conf (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpa_supplicant_template.conf)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_template.conf	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpa_supplicant_template.conf	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,6 @@
+##### wpa_supplicant configuration file template #####
+update_config=1
+ctrl_interface=wlan0
+eapol_version=1
+ap_scan=1
+fast_reauth=1

Deleted: vendor/wpa/2.0/wpa_supplicant/wpas_glue.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpas_glue.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpas_glue.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,685 +0,0 @@
-/*
- * WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eapol_supp/eapol_supp_sm.h"
-#include "rsn_supp/wpa.h"
-#include "eloop.h"
-#include "config.h"
-#include "l2_packet/l2_packet.h"
-#include "common/wpa_common.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "rsn_supp/pmksa_cache.h"
-#include "mlme.h"
-#include "sme.h"
-#include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
-#include "wpas_glue.h"
-#include "wps_supplicant.h"
-#include "bss.h"
-#include "scan.h"
-
-
-#ifndef CONFIG_NO_CONFIG_BLOBS
-#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
-static void wpa_supplicant_set_config_blob(void *ctx,
-					   struct wpa_config_blob *blob)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_config_set_blob(wpa_s->conf, blob);
-	if (wpa_s->conf->update_config) {
-		int ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
-		if (ret) {
-			wpa_printf(MSG_DEBUG, "Failed to update config after "
-				   "blob set");
-		}
-	}
-}
-
-
-static const struct wpa_config_blob *
-wpa_supplicant_get_config_blob(void *ctx, const char *name)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_config_get_blob(wpa_s->conf, name);
-}
-#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-
-
-#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
-static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
-			    const void *data, u16 data_len,
-			    size_t *msg_len, void **data_pos)
-{
-	struct ieee802_1x_hdr *hdr;
-
-	*msg_len = sizeof(*hdr) + data_len;
-	hdr = os_malloc(*msg_len);
-	if (hdr == NULL)
-		return NULL;
-
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = type;
-	hdr->length = host_to_be16(data_len);
-
-	if (data)
-		os_memcpy(hdr + 1, data, data_len);
-	else
-		os_memset(hdr + 1, 0, data_len);
-
-	if (data_pos)
-		*data_pos = hdr + 1;
-
-	return (u8 *) hdr;
-}
-
-
-/**
- * wpa_ether_send - Send Ethernet frame
- * @wpa_s: Pointer to wpa_supplicant data
- * @dest: Destination MAC address
- * @proto: Ethertype in host byte order
- * @buf: Frame payload starting from IEEE 802.1X header
- * @len: Frame payload length
- * Returns: >=0 on success, <0 on failure
- */
-static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
-			  u16 proto, const u8 *buf, size_t len)
-{
-	if (wpa_s->l2) {
-		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
-	}
-
-	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
-}
-#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
-
-
-#ifdef IEEE8021X_EAPOL
-
-/**
- * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
- * @ctx: Pointer to wpa_supplicant data (wpa_s)
- * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
- * @buf: EAPOL payload (after IEEE 802.1X header)
- * @len: EAPOL payload length
- * Returns: >=0 on success, <0 on failure
- *
- * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
- * to the current Authenticator.
- */
-static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
-				     size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	u8 *msg, *dst, bssid[ETH_ALEN];
-	size_t msglen;
-	int res;
-
-	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
-	 * extra copy here */
-
-	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
-		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
-		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
-		 * machines. */
-		wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X "
-			   "mode (type=%d len=%lu)", type,
-			   (unsigned long) len);
-		return -1;
-	}
-
-	if (pmksa_cache_get_current(wpa_s->wpa) &&
-	    type == IEEE802_1X_TYPE_EAPOL_START) {
-		/* Trying to use PMKSA caching - do not send EAPOL-Start frames
-		 * since they will trigger full EAPOL authentication. */
-		wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
-			   "EAPOL-Start");
-		return -1;
-	}
-
-	if (is_zero_ether_addr(wpa_s->bssid)) {
-		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
-			   "EAPOL frame");
-		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-		    !is_zero_ether_addr(bssid)) {
-			dst = bssid;
-			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
-				   " from the driver as the EAPOL destination",
-				   MAC2STR(dst));
-		} else {
-			dst = wpa_s->last_eapol_src;
-			wpa_printf(MSG_DEBUG, "Using the source address of the"
-				   " last received EAPOL frame " MACSTR " as "
-				   "the EAPOL destination",
-				   MAC2STR(dst));
-		}
-	} else {
-		/* BSSID was already set (from (Re)Assoc event, so use it as
-		 * the EAPOL destination. */
-		dst = wpa_s->bssid;
-	}
-
-	msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
-	if (msg == NULL)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
-	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
-	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
-	os_free(msg);
-	return res;
-}
-
-
-/**
- * wpa_eapol_set_wep_key - set WEP key for the driver
- * @ctx: Pointer to wpa_supplicant data (wpa_s)
- * @unicast: 1 = individual unicast key, 0 = broadcast key
- * @keyidx: WEP key index (0..3)
- * @key: Pointer to key data
- * @keylen: Key length in bytes
- * Returns: 0 on success or < 0 on error.
- */
-static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
-				 const u8 *key, size_t keylen)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-		int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
-			WPA_CIPHER_WEP104;
-		if (unicast)
-			wpa_s->pairwise_cipher = cipher;
-		else
-			wpa_s->group_cipher = cipher;
-	}
-	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
-			       unicast ? wpa_s->bssid :
-			       (u8 *) "\xff\xff\xff\xff\xff\xff",
-			       keyidx, unicast, (u8 *) "", 0, key, keylen);
-}
-
-
-static void wpa_supplicant_aborted_cached(void *ctx)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_sm_aborted_cached(wpa_s->wpa);
-}
-
-
-static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
-				    void *ctx)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	int res, pmk_len;
-	u8 pmk[PMK_LEN];
-
-	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
-		   success ? "" : "un");
-
-	if (wpas_wps_eapol_cb(wpa_s) > 0)
-		return;
-
-	if (!success) {
-		/*
-		 * Make sure we do not get stuck here waiting for long EAPOL
-		 * timeout if the AP does not disconnect in case of
-		 * authentication failure.
-		 */
-		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
-	}
-
-	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
-		return;
-
-	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
-		return;
-
-	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
-		   "handshake");
-
-	pmk_len = PMK_LEN;
-	res = eapol_sm_get_key(eapol, 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(eapol, pmk, 16);
-		pmk_len = 16;
-	}
-
-	if (res) {
-		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
-			   "machines");
-		return;
-	}
-
-	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
-			    pmk_len)) {
-		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
-	}
-
-	wpa_supplicant_cancel_scan(wpa_s);
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
-}
-
-
-static void wpa_supplicant_notify_eapol_done(void *ctx)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
-	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
-		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
-	} else {
-		wpa_supplicant_cancel_auth_timeout(wpa_s);
-		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-	}
-}
-
-#endif /* IEEE8021X_EAPOL */
-
-
-#ifndef CONFIG_NO_WPA
-
-static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
-{
-	int ret = 0;
-	struct wpa_bss *curr = NULL, *bss;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	const u8 *ie;
-
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0)
-			continue;
-		if (ssid == NULL ||
-		    ((bss->ssid_len == ssid->ssid_len &&
-		      os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) ||
-		     ssid->ssid_len == 0)) {
-			curr = bss;
-			break;
-		}
-	}
-
-	if (curr) {
-		ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
-		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
-			ret = -1;
-
-		ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
-		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
-			ret = -1;
-	} else {
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
-static int wpa_supplicant_get_beacon_ie(void *ctx)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_get_beacon_ie(wpa_s) == 0) {
-		return 0;
-	}
-
-	/* No WPA/RSN IE found in the cached scan results. Try to get updated
-	 * scan results from the driver. */
-	if (wpa_supplicant_update_scan_results(wpa_s) < 0)
-		return -1;
-
-	return wpa_get_beacon_ie(wpa_s);
-}
-
-
-static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
-			     const void *data, u16 data_len,
-			     size_t *msg_len, void **data_pos)
-{
-	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
-}
-
-
-static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
-			   const u8 *buf, size_t len)
-{
-	return wpa_ether_send(wpa_s, dest, proto, buf, len);
-}
-
-
-static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
-{
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-}
-
-
-static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state)
-{
-	wpa_supplicant_set_state(wpa_s, state);
-}
-
-
-/**
- * wpa_supplicant_get_state - Get the connection state
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: The current connection state (WPA_*)
- */
-static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
-{
-	return wpa_s->wpa_state;
-}
-
-
-static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
-{
-	return wpa_supplicant_get_state(wpa_s);
-}
-
-
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_disassociate(wpa_s, reason_code);
-	/* Schedule a scan to make sure we continue looking for networks */
-	wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
-static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
-{
-	wpa_supplicant_deauthenticate(wpa_s, reason_code);
-	/* Schedule a scan to make sure we continue looking for networks */
-	wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
-static void * wpa_supplicant_get_network_ctx(void *wpa_s)
-{
-	return wpa_supplicant_get_ssid(wpa_s);
-}
-
-
-static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-		return 0;
-	}
-	return wpa_drv_get_bssid(wpa_s, bssid);
-}
-
-
-static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
-				  const u8 *addr, int key_idx, int set_tx,
-				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
-{
-	struct wpa_supplicant *wpa_s = _wpa_s;
-	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
-		/* Clear the MIC error counter when setting a new PTK. */
-		wpa_s->mic_errors_seen = 0;
-	}
-	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
-			       key, key_len);
-}
-
-
-static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
-					     int protection_type,
-					     int key_type)
-{
-	return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
-					  key_type);
-}
-
-
-static int wpa_supplicant_add_pmkid(void *wpa_s,
-				    const u8 *bssid, const u8 *pmkid)
-{
-	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
-}
-
-
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
-				       const u8 *bssid, const u8 *pmkid)
-{
-	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
-					const u8 *ies, size_t ies_len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-		return sme_update_ft_ies(wpa_s, md, ies, ies_len);
-	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
-}
-
-
-static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
-					 const u8 *target_ap,
-					 const u8 *ies, size_t ies_len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return ieee80211_sta_send_ft_action(wpa_s, action, target_ap,
-						    ies, ies_len);
-	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
-}
-
-
-static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	struct wpa_driver_auth_params params;
-	struct wpa_bss *bss;
-
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return -1;
-
-	bss = wpa_bss_get_bssid(wpa_s, target_ap);
-	if (bss == NULL)
-		return -1;
-
-	os_memset(&params, 0, sizeof(params));
-	params.bssid = target_ap;
-	params.freq = bss->freq;
-	params.ssid = bss->ssid;
-	params.ssid_len = bss->ssid_len;
-	params.auth_alg = WPA_AUTH_ALG_FT;
-	params.local_state_change = 1;
-	return wpa_drv_authenticate(wpa_s, &params);
-}
-#endif /* CONFIG_IEEE80211R */
-
-#endif /* CONFIG_NO_WPA */
-
-
-#ifdef IEEE8021X_EAPOL
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
-					    const char *txt)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	char *buf;
-	size_t buflen;
-	int len;
-
-	if (ssid == NULL)
-		return;
-
-	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-	len = os_snprintf(buf, buflen,
-			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
-			  field, ssid->id, txt);
-	if (len < 0 || (size_t) len >= buflen) {
-		os_free(buf);
-		return;
-	}
-	if (ssid->ssid && buflen > len + ssid->ssid_len) {
-		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
-		len += ssid->ssid_len;
-		buf[len] = '\0';
-	}
-	buf[buflen - 1] = '\0';
-	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
-	os_free(buf);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define wpa_supplicant_eap_param_needed NULL
-#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_supplicant_port_cb(void *ctx, int authorized)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-#ifdef CONFIG_AP
-	if (wpa_s->ap_iface) {
-		wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant "
-			   "port status: %s",
-			   authorized ? "Authorized" : "Unauthorized");
-		return;
-	}
-#endif /* CONFIG_AP */
-	wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s",
-		   authorized ? "Authorized" : "Unauthorized");
-	wpa_drv_set_supp_port(wpa_s, authorized);
-}
-#endif /* IEEE8021X_EAPOL */
-
-
-int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
-{
-#ifdef IEEE8021X_EAPOL
-	struct eapol_ctx *ctx;
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
-		return -1;
-	}
-
-	ctx->ctx = wpa_s;
-	ctx->msg_ctx = wpa_s;
-	ctx->eapol_send_ctx = wpa_s;
-	ctx->preauth = 0;
-	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
-	ctx->eapol_send = wpa_supplicant_eapol_send;
-	ctx->set_wep_key = wpa_eapol_set_wep_key;
-	ctx->set_config_blob = wpa_supplicant_set_config_blob;
-	ctx->get_config_blob = wpa_supplicant_get_config_blob;
-	ctx->aborted_cached = wpa_supplicant_aborted_cached;
-	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
-	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
-	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
-	ctx->wps = wpa_s->wps;
-	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
-	ctx->port_cb = wpa_supplicant_port_cb;
-	ctx->cb = wpa_supplicant_eapol_cb;
-	ctx->cb_ctx = wpa_s;
-	wpa_s->eapol = eapol_sm_init(ctx);
-	if (wpa_s->eapol == NULL) {
-		os_free(ctx);
-		wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
-			   "machines.");
-		return -1;
-	}
-#endif /* IEEE8021X_EAPOL */
-
-	return 0;
-}
-
-
-int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
-{
-#ifndef CONFIG_NO_WPA
-	struct wpa_sm_ctx *ctx;
-	ctx = os_zalloc(sizeof(*ctx));
-	if (ctx == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
-		return -1;
-	}
-
-	ctx->ctx = wpa_s;
-	ctx->msg_ctx = wpa_s;
-	ctx->set_state = _wpa_supplicant_set_state;
-	ctx->get_state = _wpa_supplicant_get_state;
-	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
-	ctx->disassociate = _wpa_supplicant_disassociate;
-	ctx->set_key = wpa_supplicant_set_key;
-	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
-	ctx->get_bssid = wpa_supplicant_get_bssid;
-	ctx->ether_send = _wpa_ether_send;
-	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
-	ctx->alloc_eapol = _wpa_alloc_eapol;
-	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
-	ctx->add_pmkid = wpa_supplicant_add_pmkid;
-	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
-#ifndef CONFIG_NO_CONFIG_BLOBS
-	ctx->set_config_blob = wpa_supplicant_set_config_blob;
-	ctx->get_config_blob = wpa_supplicant_get_config_blob;
-#endif /* CONFIG_NO_CONFIG_BLOBS */
-	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
-#ifdef CONFIG_IEEE80211R
-	ctx->update_ft_ies = wpa_supplicant_update_ft_ies;
-	ctx->send_ft_action = wpa_supplicant_send_ft_action;
-	ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
-#endif /* CONFIG_IEEE80211R */
-
-	wpa_s->wpa = wpa_sm_init(ctx);
-	if (wpa_s->wpa == NULL) {
-		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
-			   "machine");
-		return -1;
-	}
-#endif /* CONFIG_NO_WPA */
-
-	return 0;
-}
-
-
-void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
-					struct wpa_ssid *ssid)
-{
-	struct rsn_supp_config conf;
-	if (ssid) {
-		os_memset(&conf, 0, sizeof(conf));
-		conf.network_ctx = ssid;
-		conf.peerkey_enabled = ssid->peerkey;
-		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
-#ifdef IEEE8021X_EAPOL
-		conf.eap_workaround = ssid->eap_workaround;
-		conf.eap_conf_ctx = &ssid->eap;
-#endif /* IEEE8021X_EAPOL */
-		conf.ssid = ssid->ssid;
-		conf.ssid_len = ssid->ssid_len;
-		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
-	}
-	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wpas_glue.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpas_glue.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpas_glue.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpas_glue.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,895 @@
+/*
+ * WPA Supplicant - Glue code to setup EAPOL and RSN modules
+ * Copyright (c) 2003-2012, Jouni Malinen <j at 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 "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "l2_packet/l2_packet.h"
+#include "common/wpa_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "sme.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static void wpa_supplicant_set_config_blob(void *ctx,
+					   struct wpa_config_blob *blob)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_config_set_blob(wpa_s->conf, blob);
+	if (wpa_s->conf->update_config) {
+		int ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+		if (ret) {
+			wpa_printf(MSG_DEBUG, "Failed to update config after "
+				   "blob set");
+		}
+	}
+}
+
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_config_get_blob(wpa_s->conf, name);
+}
+#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
+			    const void *data, u16 data_len,
+			    size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = wpa_s->conf->eapol_version;
+	hdr->type = type;
+	hdr->length = host_to_be16(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+/**
+ * wpa_ether_send - Send Ethernet frame
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dest: Destination MAC address
+ * @proto: Ethertype in host byte order
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ * Returns: >=0 on success, <0 on failure
+ */
+static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
+			  u16 proto, const u8 *buf, size_t len)
+{
+	if (wpa_s->l2) {
+		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
+	}
+
+	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+}
+#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
+
+
+#ifdef IEEE8021X_EAPOL
+
+/**
+ * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
+ * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
+ * @buf: EAPOL payload (after IEEE 802.1X header)
+ * @len: EAPOL payload length
+ * Returns: >=0 on success, <0 on failure
+ *
+ * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
+ * to the current Authenticator.
+ */
+static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
+				     size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	u8 *msg, *dst, bssid[ETH_ALEN];
+	size_t msglen;
+	int res;
+
+	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
+	 * extra copy here */
+
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
+		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
+		 * machines. */
+		wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X "
+			   "mode (type=%d len=%lu)", type,
+			   (unsigned long) len);
+		return -1;
+	}
+
+	if (pmksa_cache_get_current(wpa_s->wpa) &&
+	    type == IEEE802_1X_TYPE_EAPOL_START) {
+		/* Trying to use PMKSA caching - do not send EAPOL-Start frames
+		 * since they will trigger full EAPOL authentication. */
+		wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
+			   "EAPOL-Start");
+		return -1;
+	}
+
+	if (is_zero_ether_addr(wpa_s->bssid)) {
+		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
+			   "EAPOL frame");
+		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+		    !is_zero_ether_addr(bssid)) {
+			dst = bssid;
+			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
+				   " from the driver as the EAPOL destination",
+				   MAC2STR(dst));
+		} else {
+			dst = wpa_s->last_eapol_src;
+			wpa_printf(MSG_DEBUG, "Using the source address of the"
+				   " last received EAPOL frame " MACSTR " as "
+				   "the EAPOL destination",
+				   MAC2STR(dst));
+		}
+	} else {
+		/* BSSID was already set (from (Re)Assoc event, so use it as
+		 * the EAPOL destination. */
+		dst = wpa_s->bssid;
+	}
+
+	msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
+	if (msg == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
+	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
+	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
+	os_free(msg);
+	return res;
+}
+
+
+/**
+ * wpa_eapol_set_wep_key - set WEP key for the driver
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
+ * @unicast: 1 = individual unicast key, 0 = broadcast key
+ * @keyidx: WEP key index (0..3)
+ * @key: Pointer to key data
+ * @keylen: Key length in bytes
+ * Returns: 0 on success or < 0 on error.
+ */
+static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
+				 const u8 *key, size_t keylen)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
+			WPA_CIPHER_WEP104;
+		if (unicast)
+			wpa_s->pairwise_cipher = cipher;
+		else
+			wpa_s->group_cipher = cipher;
+	}
+	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
+			       unicast ? wpa_s->bssid : NULL,
+			       keyidx, unicast, NULL, 0, key, keylen);
+}
+
+
+static void wpa_supplicant_aborted_cached(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_sm_aborted_cached(wpa_s->wpa);
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+				    void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	int res, pmk_len;
+	u8 pmk[PMK_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
+		   success ? "" : "un");
+
+	if (wpas_wps_eapol_cb(wpa_s) > 0)
+		return;
+
+	if (!success) {
+		/*
+		 * Make sure we do not get stuck here waiting for long EAPOL
+		 * timeout if the AP does not disconnect in case of
+		 * authentication failure.
+		 */
+		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
+	}
+
+	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		return;
+
+	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
+		return;
+
+	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
+		   "handshake");
+
+	pmk_len = PMK_LEN;
+	if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
+#ifdef CONFIG_IEEE80211R
+		u8 buf[2 * PMK_LEN];
+		wpa_printf(MSG_DEBUG, "RSN: Use FT XXKey as PMK for "
+			   "driver-based 4-way hs and FT");
+		res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN);
+		if (res == 0) {
+			os_memcpy(pmk, buf + PMK_LEN, PMK_LEN);
+			os_memset(buf, 0, sizeof(buf));
+		}
+#else /* CONFIG_IEEE80211R */
+		res = -1;
+#endif /* CONFIG_IEEE80211R */
+	} else {
+		res = eapol_sm_get_key(eapol, 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(eapol, pmk, 16);
+			pmk_len = 16;
+		}
+	}
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
+			   "machines");
+		return;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
+			"handshake", pmk, pmk_len);
+
+	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
+			    pmk_len)) {
+		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
+	}
+
+	wpa_supplicant_cancel_scan(wpa_s);
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+}
+
+
+static void wpa_supplicant_notify_eapol_done(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
+	} else {
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	}
+}
+
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifndef CONFIG_NO_WPA
+
+static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
+{
+	int ret = 0;
+	struct wpa_bss *curr = NULL, *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const u8 *ie;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0)
+			continue;
+		if (ssid == NULL ||
+		    ((bss->ssid_len == ssid->ssid_len &&
+		      os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) ||
+		     ssid->ssid_len == 0)) {
+			curr = bss;
+			break;
+		}
+	}
+
+	if (curr) {
+		ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
+		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+			ret = -1;
+
+		ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
+		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+			ret = -1;
+	} else {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_get_beacon_ie(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_get_beacon_ie(wpa_s) == 0) {
+		return 0;
+	}
+
+	/* No WPA/RSN IE found in the cached scan results. Try to get updated
+	 * scan results from the driver. */
+	if (wpa_supplicant_update_scan_results(wpa_s) < 0)
+		return -1;
+
+	return wpa_get_beacon_ie(wpa_s);
+}
+
+
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+			     const void *data, u16 data_len,
+			     size_t *msg_len, void **data_pos)
+{
+	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
+}
+
+
+static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+			   const u8 *buf, size_t len)
+{
+	return wpa_ether_send(wpa_s, dest, proto, buf, len);
+}
+
+
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
+
+
+static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state)
+{
+	wpa_supplicant_set_state(wpa_s, state);
+}
+
+
+/**
+ * wpa_supplicant_get_state - Get the connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: The current connection state (WPA_*)
+ */
+static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->wpa_state;
+}
+
+
+static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
+{
+	return wpa_supplicant_get_state(wpa_s);
+}
+
+
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+{
+	wpa_supplicant_deauthenticate(wpa_s, reason_code);
+	/* Schedule a scan to make sure we continue looking for networks */
+	wpa_supplicant_req_scan(wpa_s, 5, 0);
+}
+
+
+static void * wpa_supplicant_get_network_ctx(void *wpa_s)
+{
+	return wpa_supplicant_get_ssid(wpa_s);
+}
+
+
+static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_get_bssid(wpa_s, bssid);
+}
+
+
+static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
+				  const u8 *addr, int key_idx, int set_tx,
+				  const u8 *seq, size_t seq_len,
+				  const u8 *key, size_t key_len)
+{
+	struct wpa_supplicant *wpa_s = _wpa_s;
+	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
+		/* Clear the MIC error counter when setting a new PTK. */
+		wpa_s->mic_errors_seen = 0;
+	}
+	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
+			       key, key_len);
+}
+
+
+static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
+					     int protection_type,
+					     int key_type)
+{
+	return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
+					  key_type);
+}
+
+
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+				    const u8 *bssid, const u8 *pmkid)
+{
+	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+				       const u8 *bssid, const u8 *pmkid)
+{
+	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
+					const u8 *ies, size_t ies_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+		return sme_update_ft_ies(wpa_s, md, ies, ies_len);
+	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
+}
+
+
+static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
+					 const u8 *target_ap,
+					 const u8 *ies, size_t ies_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+}
+
+
+static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_driver_auth_params params;
+	struct wpa_bss *bss;
+
+	bss = wpa_bss_get_bssid(wpa_s, target_ap);
+	if (bss == NULL)
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.bssid = target_ap;
+	params.freq = bss->freq;
+	params.ssid = bss->ssid;
+	params.ssid_len = bss->ssid_len;
+	params.auth_alg = WPA_AUTH_ALG_FT;
+	params.local_state_change = 1;
+	return wpa_drv_authenticate(wpa_s, &params);
+}
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* CONFIG_NO_WPA */
+
+
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
+					int *tdls_ext_setup)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	*tdls_supported = 0;
+	*tdls_ext_setup = 0;
+
+	if (!wpa_s->drv_capa_known)
+		return -1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)
+		*tdls_supported = 1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
+		*tdls_ext_setup = 1;
+
+	return 0;
+}
+
+
+static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
+					 u8 action_code, u8 dialog_token,
+					 u16 status_code, const u8 *buf,
+					 size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
+				      status_code, buf, len);
+}
+
+
+static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_tdls_oper(wpa_s, oper, peer);
+}
+
+
+static int wpa_supplicant_tdls_peer_addset(
+	void *ctx, const u8 *peer, int add, u16 capability,
+	const u8 *supp_rates, size_t supp_rates_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct hostapd_sta_add_params params;
+
+	params.addr = peer;
+	params.aid = 1;
+	params.capability = capability;
+	params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
+	params.ht_capabilities = NULL;
+	params.listen_interval = 0;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+	params.set = !add;
+
+	return wpa_drv_sta_add(wpa_s, &params);
+}
+
+#endif /* CONFIG_TDLS */
+
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
+{
+	if (os_strcmp(field, "IDENTITY") == 0)
+		return WPA_CTRL_REQ_EAP_IDENTITY;
+	else if (os_strcmp(field, "PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_PASSWORD;
+	else if (os_strcmp(field, "NEW_PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_NEW_PASSWORD;
+	else if (os_strcmp(field, "PIN") == 0)
+		return WPA_CTRL_REQ_EAP_PIN;
+	else if (os_strcmp(field, "OTP") == 0)
+		return WPA_CTRL_REQ_EAP_OTP;
+	else if (os_strcmp(field, "PASSPHRASE") == 0)
+		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	return WPA_CTRL_REQ_UNKNOWN;
+}
+
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt)
+{
+	const char *ret = NULL;
+
+	*txt = default_txt;
+
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		*txt = "Identity";
+		ret = "IDENTITY";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		*txt = "Password";
+		ret = "PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		*txt = "New Password";
+		ret = "NEW_PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		*txt = "PIN";
+		ret = "PIN";
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		ret = "OTP";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		*txt = "Private key passphrase";
+		ret = "PASSPHRASE";
+		break;
+	default:
+		break;
+	}
+
+	/* txt needs to be something */
+	if (*txt == NULL) {
+		wpa_printf(MSG_WARNING, "No message for request %d", field);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+#ifdef IEEE8021X_EAPOL
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void wpa_supplicant_eap_param_needed(void *ctx,
+					    enum wpa_ctrl_req_type field,
+					    const char *default_txt)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
+	char *buf;
+	size_t buflen;
+	int len;
+
+	if (ssid == NULL)
+		return;
+
+	wpas_notify_network_request(wpa_s, ssid, field, default_txt);
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen,
+			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (len < 0 || (size_t) len >= buflen) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+	os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define wpa_supplicant_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_supplicant_port_cb(void *ctx, int authorized)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant "
+			   "port status: %s",
+			   authorized ? "Authorized" : "Unauthorized");
+		return;
+	}
+#endif /* CONFIG_AP */
+	wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s",
+		   authorized ? "Authorized" : "Unauthorized");
+	wpa_drv_set_supp_port(wpa_s, authorized);
+}
+
+
+static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+				   const char *cert_hash,
+				   const struct wpabuf *cert)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+}
+
+
+static void wpa_supplicant_status_cb(void *ctx, const char *status,
+				     const char *parameter)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_eap_status(wpa_s, status, parameter);
+}
+
+
+static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	char *str;
+	int res;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+			  id, len);
+
+	if (wpa_s->current_ssid == NULL)
+		return;
+
+	if (id == NULL) {
+		if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				   "NULL", 0) < 0)
+			return;
+	} else {
+		str = os_malloc(len * 2 + 1);
+		if (str == NULL)
+			return;
+		wpa_snprintf_hex(str, len * 2 + 1, id, len);
+		res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				     str, 0);
+		os_free(str);
+		if (res < 0)
+			return;
+	}
+
+	if (wpa_s->conf->update_config) {
+		res = wpa_config_write(wpa_s->confname, wpa_s->conf);
+		if (res) {
+			wpa_printf(MSG_DEBUG, "Failed to update config after "
+				   "anonymous_id update");
+		}
+	}
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eapol_ctx *ctx;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
+		return -1;
+	}
+
+	ctx->ctx = wpa_s;
+	ctx->msg_ctx = wpa_s;
+	ctx->eapol_send_ctx = wpa_s;
+	ctx->preauth = 0;
+	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
+	ctx->eapol_send = wpa_supplicant_eapol_send;
+	ctx->set_wep_key = wpa_eapol_set_wep_key;
+	ctx->set_config_blob = wpa_supplicant_set_config_blob;
+	ctx->get_config_blob = wpa_supplicant_get_config_blob;
+	ctx->aborted_cached = wpa_supplicant_aborted_cached;
+	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
+	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->wps = wpa_s->wps;
+	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
+	ctx->port_cb = wpa_supplicant_port_cb;
+	ctx->cb = wpa_supplicant_eapol_cb;
+	ctx->cert_cb = wpa_supplicant_cert_cb;
+	ctx->status_cb = wpa_supplicant_status_cb;
+	ctx->set_anon_id = wpa_supplicant_set_anon_id;
+	ctx->cb_ctx = wpa_s;
+	wpa_s->eapol = eapol_sm_init(ctx);
+	if (wpa_s->eapol == NULL) {
+		os_free(ctx);
+		wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
+			   "machines.");
+		return -1;
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_WPA
+static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
+					     const u8 *kck,
+					     const u8 *replay_ctr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+}
+#endif /* CONFIG_NO_WPA */
+
+
+int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_WPA
+	struct wpa_sm_ctx *ctx;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
+		return -1;
+	}
+
+	ctx->ctx = wpa_s;
+	ctx->msg_ctx = wpa_s;
+	ctx->set_state = _wpa_supplicant_set_state;
+	ctx->get_state = _wpa_supplicant_get_state;
+	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+	ctx->set_key = wpa_supplicant_set_key;
+	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
+	ctx->get_bssid = wpa_supplicant_get_bssid;
+	ctx->ether_send = _wpa_ether_send;
+	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+	ctx->alloc_eapol = _wpa_alloc_eapol;
+	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+	ctx->add_pmkid = wpa_supplicant_add_pmkid;
+	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	ctx->set_config_blob = wpa_supplicant_set_config_blob;
+	ctx->get_config_blob = wpa_supplicant_get_config_blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+#ifdef CONFIG_IEEE80211R
+	ctx->update_ft_ies = wpa_supplicant_update_ft_ies;
+	ctx->send_ft_action = wpa_supplicant_send_ft_action;
+	ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TDLS
+	ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa;
+	ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
+	ctx->tdls_oper = wpa_supplicant_tdls_oper;
+	ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+#endif /* CONFIG_TDLS */
+	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+
+	wpa_s->wpa = wpa_sm_init(ctx);
+	if (wpa_s->wpa == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+			   "machine");
+		return -1;
+	}
+#endif /* CONFIG_NO_WPA */
+
+	return 0;
+}
+
+
+void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	struct rsn_supp_config conf;
+	if (ssid) {
+		os_memset(&conf, 0, sizeof(conf));
+		conf.network_ctx = ssid;
+		conf.peerkey_enabled = ssid->peerkey;
+		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
+#ifdef IEEE8021X_EAPOL
+		conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+			wpa_s->conf->okc : ssid->proactive_key_caching;
+		conf.eap_workaround = ssid->eap_workaround;
+		conf.eap_conf_ctx = &ssid->eap;
+#endif /* IEEE8021X_EAPOL */
+		conf.ssid = ssid->ssid;
+		conf.ssid_len = ssid->ssid_len;
+		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+	}
+	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wpas_glue.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wpas_glue.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wpas_glue.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,23 +0,0 @@
-/*
- * WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPAS_GLUE_H
-#define WPAS_GLUE_H
-
-int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
-					struct wpa_ssid *ssid);
-
-#endif /* WPAS_GLUE_H */

Copied: vendor/wpa/2.0/wpa_supplicant/wpas_glue.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/wpas_glue.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wpas_glue.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wpas_glue.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,25 @@
+/*
+ * WPA Supplicant - Glue code to setup EAPOL and RSN modules
+ * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPAS_GLUE_H
+#define WPAS_GLUE_H
+
+enum wpa_ctrl_req_type;
+
+int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt);
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
+
+#endif /* WPAS_GLUE_H */

Deleted: vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wps_supplicant.c	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,1185 +0,0 @@
-/*
- * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "uuid.h"
-#include "crypto/dh_group5.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "common/wpa_common.h"
-#include "common/wpa_ctrl.h"
-#include "eap_common/eap_wsc_common.h"
-#include "eap_peer/eap.h"
-#include "rsn_supp/wpa.h"
-#include "config.h"
-#include "wpa_supplicant_i.h"
-#include "driver_i.h"
-#include "notify.h"
-#include "blacklist.h"
-#include "bss.h"
-#include "scan.h"
-#include "wps_supplicant.h"
-
-
-#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
-
-static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
-static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
-
-
-int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
-{
-	if (!wpa_s->wps_success &&
-	    wpa_s->current_ssid &&
-	    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
-		const u8 *bssid = wpa_s->bssid;
-		if (is_zero_ether_addr(bssid))
-			bssid = wpa_s->pending_bssid;
-
-		wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
-			   " did not succeed - continue trying to find "
-			   "suitable AP", MAC2STR(bssid));
-		wpa_blacklist_add(wpa_s, bssid);
-
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-		wpa_s->reassociate = 1;
-		wpa_supplicant_req_scan(wpa_s,
-					wpa_s->blacklist_cleared ? 5 : 0, 0);
-		wpa_s->blacklist_cleared = 0;
-		return 1;
-	}
-
-	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
-	    !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
-		wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
-			   "try to associate with the received credential");
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-		wpa_s->after_wps = 5;
-		wpa_s->wps_freq = wpa_s->assoc_freq;
-		wpa_s->reassociate = 1;
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-		return 1;
-	}
-
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
-		wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
-			   "for external credential processing");
-		wpas_clear_wps(wpa_s);
-		wpa_supplicant_deauthenticate(wpa_s,
-					      WLAN_REASON_DEAUTH_LEAVING);
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
-					 struct wpa_ssid *ssid,
-					 const struct wps_credential *cred)
-{
-	struct wpa_driver_capa capa;
-	struct wpa_bss *bss;
-	const u8 *ie;
-	struct wpa_ie_data adv;
-	int wpa2 = 0, ccmp = 0;
-
-	/*
-	 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
-	 * case they are configured for mixed mode operation (WPA+WPA2 and
-	 * TKIP+CCMP). Try to use scan results to figure out whether the AP
-	 * actually supports stronger security and select that if the client
-	 * has support for it, too.
-	 */
-
-	if (wpa_drv_get_capa(wpa_s, &capa))
-		return; /* Unknown what driver supports */
-
-	bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
-			   "table - use credential as-is");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
-		wpa2 = 1;
-		if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
-			ccmp = 1;
-	} else {
-		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-		if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
-		    adv.pairwise_cipher & WPA_CIPHER_CCMP)
-			ccmp = 1;
-	}
-
-	if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
-	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
-		/*
-		 * TODO: This could be the initial AP configuration and the
-		 * Beacon contents could change shortly. Should request a new
-		 * scan and delay addition of the network until the updated
-		 * scan results are available.
-		 */
-		wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
-			   "support - use credential as-is");
-		return;
-	}
-
-	if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
-	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
-	    (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-		wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
-			   "based on scan results");
-		if (wpa_s->conf->ap_scan == 1)
-			ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
-		else
-			ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-	}
-
-	if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
-	    (ssid->proto & WPA_PROTO_WPA) &&
-	    (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
-		wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
-			   "based on scan results");
-		if (wpa_s->conf->ap_scan == 1)
-			ssid->proto |= WPA_PROTO_RSN;
-		else
-			ssid->proto = WPA_PROTO_RSN;
-	}
-}
-
-
-static int wpa_supplicant_wps_cred(void *ctx,
-				   const struct wps_credential *cred)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	u8 key_idx = 0;
-	u16 auth_type;
-
-	if ((wpa_s->conf->wps_cred_processing == 1 ||
-	     wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
-		size_t blen = cred->cred_attr_len * 2 + 1;
-		char *buf = os_malloc(blen);
-		if (buf) {
-			wpa_snprintf_hex(buf, blen,
-					 cred->cred_attr, cred->cred_attr_len);
-			wpa_msg(wpa_s, MSG_INFO, "%s%s",
-				WPS_EVENT_CRED_RECEIVED, buf);
-			os_free(buf);
-		}
-
-		wpas_notify_wps_credential(wpa_s, cred);
-	} else
-		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
-			cred->cred_attr, cred->cred_attr_len);
-
-	if (wpa_s->conf->wps_cred_processing == 1)
-		return 0;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
-	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
-		   cred->auth_type);
-	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
-	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
-			cred->key, cred->key_len);
-	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
-		   MAC2STR(cred->mac_addr));
-
-	auth_type = cred->auth_type;
-	if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
-		wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
-			   "auth_type into WPA2PSK");
-		auth_type = WPS_AUTH_WPA2PSK;
-	}
-
-	if (auth_type != WPS_AUTH_OPEN &&
-	    auth_type != WPS_AUTH_SHARED &&
-	    auth_type != WPS_AUTH_WPAPSK &&
-	    auth_type != WPS_AUTH_WPA2PSK) {
-		wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
-			   "unsupported authentication type 0x%x",
-			   auth_type);
-		return 0;
-	}
-
-	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
-		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
-			   "on the received credential");
-		os_free(ssid->eap.identity);
-		ssid->eap.identity = NULL;
-		ssid->eap.identity_len = 0;
-		os_free(ssid->eap.phase1);
-		ssid->eap.phase1 = NULL;
-		os_free(ssid->eap.eap_methods);
-		ssid->eap.eap_methods = NULL;
-	} else {
-		wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
-			   "received credential");
-		ssid = wpa_config_add_network(wpa_s->conf);
-		if (ssid == NULL)
-			return -1;
-		wpas_notify_network_added(wpa_s, ssid);
-	}
-
-	wpa_config_set_network_defaults(ssid);
-
-	os_free(ssid->ssid);
-	ssid->ssid = os_malloc(cred->ssid_len);
-	if (ssid->ssid) {
-		os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
-		ssid->ssid_len = cred->ssid_len;
-	}
-
-	switch (cred->encr_type) {
-	case WPS_ENCR_NONE:
-		break;
-	case WPS_ENCR_WEP:
-		if (cred->key_len <= 0)
-			break;
-		if (cred->key_len != 5 && cred->key_len != 13 &&
-		    cred->key_len != 10 && cred->key_len != 26) {
-			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
-				   "%lu", (unsigned long) cred->key_len);
-			return -1;
-		}
-		if (cred->key_idx > NUM_WEP_KEYS) {
-			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
-				   cred->key_idx);
-			return -1;
-		}
-		if (cred->key_idx)
-			key_idx = cred->key_idx - 1;
-		if (cred->key_len == 10 || cred->key_len == 26) {
-			if (hexstr2bin((char *) cred->key,
-				       ssid->wep_key[key_idx],
-				       cred->key_len / 2) < 0) {
-				wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
-					   "%d", key_idx);
-				return -1;
-			}
-			ssid->wep_key_len[key_idx] = cred->key_len / 2;
-		} else {
-			os_memcpy(ssid->wep_key[key_idx], cred->key,
-				  cred->key_len);
-			ssid->wep_key_len[key_idx] = cred->key_len;
-		}
-		ssid->wep_tx_keyidx = key_idx;
-		break;
-	case WPS_ENCR_TKIP:
-		ssid->pairwise_cipher = WPA_CIPHER_TKIP;
-		break;
-	case WPS_ENCR_AES:
-		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-		break;
-	}
-
-	switch (auth_type) {
-	case WPS_AUTH_OPEN:
-		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
-		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
-		ssid->proto = 0;
-		break;
-	case WPS_AUTH_SHARED:
-		ssid->auth_alg = WPA_AUTH_ALG_SHARED;
-		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
-		ssid->proto = 0;
-		break;
-	case WPS_AUTH_WPAPSK:
-		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
-		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
-		ssid->proto = WPA_PROTO_WPA;
-		break;
-	case WPS_AUTH_WPA:
-		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
-		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-		ssid->proto = WPA_PROTO_WPA;
-		break;
-	case WPS_AUTH_WPA2:
-		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
-		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-		ssid->proto = WPA_PROTO_RSN;
-		break;
-	case WPS_AUTH_WPA2PSK:
-		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
-		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
-		ssid->proto = WPA_PROTO_RSN;
-		break;
-	}
-
-	if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
-		if (cred->key_len == 2 * PMK_LEN) {
-			if (hexstr2bin((const char *) cred->key, ssid->psk,
-				       PMK_LEN)) {
-				wpa_printf(MSG_ERROR, "WPS: Invalid Network "
-					   "Key");
-				return -1;
-			}
-			ssid->psk_set = 1;
-		} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
-			os_free(ssid->passphrase);
-			ssid->passphrase = os_malloc(cred->key_len + 1);
-			if (ssid->passphrase == NULL)
-				return -1;
-			os_memcpy(ssid->passphrase, cred->key, cred->key_len);
-			ssid->passphrase[cred->key_len] = '\0';
-			wpa_config_update_psk(ssid);
-		} else {
-			wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
-				   "length %lu",
-				   (unsigned long) cred->key_len);
-			return -1;
-		}
-	}
-
-	wpas_wps_security_workaround(wpa_s, ssid, cred);
-
-#ifndef CONFIG_NO_CONFIG_WRITE
-	if (wpa_s->conf->update_config &&
-	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
-		return -1;
-	}
-#endif /* CONFIG_NO_CONFIG_WRITE */
-
-	return 0;
-}
-
-
-static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
-					 struct wps_event_m2d *m2d)
-{
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
-		"dev_password_id=%d config_error=%d",
-		m2d->dev_password_id, m2d->config_error);
-	wpas_notify_wps_event_m2d(wpa_s, m2d);
-}
-
-
-static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
-					  struct wps_event_fail *fail)
-{
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg);
-	wpas_clear_wps(wpa_s);
-	wpas_notify_wps_event_fail(wpa_s, fail);
-}
-
-
-static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
-{
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
-	wpa_s->wps_success = 1;
-	wpas_notify_wps_event_success(wpa_s);
-}
-
-
-static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
-					       struct wps_event_er_ap *ap)
-{
-	char uuid_str[100];
-	char dev_type[WPS_DEV_TYPE_BUFSIZE];
-
-	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
-	if (ap->pri_dev_type)
-		wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
-				     sizeof(dev_type));
-	else
-		dev_type[0] = '\0';
-
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
-		" pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
-		uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
-		ap->friendly_name ? ap->friendly_name : "",
-		ap->manufacturer ? ap->manufacturer : "",
-		ap->model_description ? ap->model_description : "",
-		ap->model_name ? ap->model_name : "",
-		ap->manufacturer_url ? ap->manufacturer_url : "",
-		ap->model_url ? ap->model_url : "");
-}
-
-
-static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
-						  struct wps_event_er_ap *ap)
-{
-	char uuid_str[100];
-	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
-}
-
-
-static void wpa_supplicant_wps_event_er_enrollee_add(
-	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
-{
-	char uuid_str[100];
-	char dev_type[WPS_DEV_TYPE_BUFSIZE];
-
-	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
-	if (enrollee->pri_dev_type)
-		wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
-				     sizeof(dev_type));
-	else
-		dev_type[0] = '\0';
-
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
-		" M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
-		"|%s|%s|%s|%s|%s|",
-		uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
-		enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
-		enrollee->dev_name ? enrollee->dev_name : "",
-		enrollee->manufacturer ? enrollee->manufacturer : "",
-		enrollee->model_name ? enrollee->model_name : "",
-		enrollee->model_number ? enrollee->model_number : "",
-		enrollee->serial_number ? enrollee->serial_number : "");
-}
-
-
-static void wpa_supplicant_wps_event_er_enrollee_remove(
-	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
-{
-	char uuid_str[100];
-	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
-	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
-		uuid_str, MAC2STR(enrollee->mac_addr));
-}
-
-
-static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
-				     union wps_event_data *data)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	switch (event) {
-	case WPS_EV_M2D:
-		wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
-		break;
-	case WPS_EV_FAIL:
-		wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
-		break;
-	case WPS_EV_SUCCESS:
-		wpa_supplicant_wps_event_success(wpa_s);
-		break;
-	case WPS_EV_PWD_AUTH_FAIL:
-		break;
-	case WPS_EV_PBC_OVERLAP:
-		break;
-	case WPS_EV_PBC_TIMEOUT:
-		break;
-	case WPS_EV_ER_AP_ADD:
-		wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
-		break;
-	case WPS_EV_ER_AP_REMOVE:
-		wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
-		break;
-	case WPS_EV_ER_ENROLLEE_ADD:
-		wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
-							 &data->enrollee);
-		break;
-	case WPS_EV_ER_ENROLLEE_REMOVE:
-		wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
-							    &data->enrollee);
-		break;
-	}
-}
-
-
-enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
-{
-	if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
-	    eap_is_wps_pin_enrollee(&ssid->eap))
-		return WPS_REQ_ENROLLEE;
-	else
-		return WPS_REQ_REGISTRAR;
-}
-
-
-static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
-{
-	int id;
-	struct wpa_ssid *ssid, *remove_ssid = NULL;
-
-	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
-
-	/* Remove any existing WPS network from configuration */
-	ssid = wpa_s->conf->ssid;
-	while (ssid) {
-		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
-			if (ssid == wpa_s->current_ssid) {
-				wpa_s->current_ssid = NULL;
-				if (ssid != NULL)
-					wpas_notify_network_changed(wpa_s);
-			}
-			id = ssid->id;
-			remove_ssid = ssid;
-		} else
-			id = -1;
-		ssid = ssid->next;
-		if (id >= 0) {
-			wpas_notify_network_removed(wpa_s, remove_ssid);
-			wpa_config_remove_network(wpa_s->conf, id);
-		}
-	}
-}
-
-
-static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	wpa_printf(MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
-		   "out");
-	wpas_clear_wps(wpa_s);
-}
-
-
-static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
-					      int registrar, const u8 *bssid)
-{
-	struct wpa_ssid *ssid;
-
-	ssid = wpa_config_add_network(wpa_s->conf);
-	if (ssid == NULL)
-		return NULL;
-	wpas_notify_network_added(wpa_s, ssid);
-	wpa_config_set_network_defaults(ssid);
-	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
-	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
-	    wpa_config_set(ssid, "identity", registrar ?
-			   "\"" WSC_ID_REGISTRAR "\"" :
-			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
-		wpas_notify_network_removed(wpa_s, ssid);
-		wpa_config_remove_network(wpa_s->conf, ssid->id);
-		return NULL;
-	}
-
-	if (bssid) {
-		struct wpa_bss *bss;
-		int count = 0;
-
-		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
-		ssid->bssid_set = 1;
-
-		dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-			if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
-				continue;
-
-			os_free(ssid->ssid);
-			ssid->ssid = os_malloc(bss->ssid_len);
-			if (ssid->ssid == NULL)
-				break;
-			os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
-			ssid->ssid_len = bss->ssid_len;
-			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
-					  "scan results",
-					  ssid->ssid, ssid->ssid_len);
-			count++;
-		}
-
-		if (count > 1) {
-			wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
-				   "for the AP; use wildcard");
-			os_free(ssid->ssid);
-			ssid->ssid = NULL;
-			ssid->ssid_len = 0;
-		}
-	}
-
-	return ssid;
-}
-
-
-static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
-			     struct wpa_ssid *selected)
-{
-	struct wpa_ssid *ssid;
-
-	/* Mark all other networks disabled and trigger reassociation */
-	ssid = wpa_s->conf->ssid;
-	while (ssid) {
-		int was_disabled = ssid->disabled;
-		ssid->disabled = ssid != selected;
-		if (was_disabled != ssid->disabled)
-			wpas_notify_network_enabled_changed(wpa_s, ssid);
-		ssid = ssid->next;
-	}
-	wpa_s->disconnected = 0;
-	wpa_s->reassociate = 1;
-	wpa_s->scan_runs = 0;
-	wpa_s->wps_success = 0;
-	wpa_s->blacklist_cleared = 0;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-}
-
-
-int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct wpa_ssid *ssid;
-	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
-	if (ssid == NULL)
-		return -1;
-	wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
-	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
-			       wpa_s, NULL);
-	wpas_wps_reassoc(wpa_s, ssid);
-	return 0;
-}
-
-
-int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-		       const char *pin)
-{
-	struct wpa_ssid *ssid;
-	char val[128];
-	unsigned int rpin = 0;
-
-	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
-	if (ssid == NULL)
-		return -1;
-	if (pin)
-		os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
-	else {
-		rpin = wps_generate_pin();
-		os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
-	}
-	wpa_config_set(ssid, "phase1", val, 0);
-	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
-			       wpa_s, NULL);
-	wpas_wps_reassoc(wpa_s, ssid);
-	return rpin;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-		       char *path, char *method, char *name)
-{
-	struct wps_context *wps = wpa_s->wps;
-	struct oob_device_data *oob_dev;
-
-	oob_dev = wps_get_oob_device(device_type);
-	if (oob_dev == NULL)
-		return -1;
-	oob_dev->device_path = path;
-	oob_dev->device_name = name;
-	wps->oob_conf.oob_method = wps_get_oob_method(method);
-
-	if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
-		/*
-		 * Use pre-configured DH keys in order to be able to write the
-		 * key hash into the OOB file.
-		 */
-		wpabuf_free(wps->dh_pubkey);
-		wpabuf_free(wps->dh_privkey);
-		wps->dh_privkey = NULL;
-		wps->dh_pubkey = NULL;
-		dh5_free(wps->dh_ctx);
-		wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
-		wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
-		if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
-			wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
-				   "Diffie-Hellman handshake");
-			return -1;
-		}
-	}
-
-	if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
-		wpas_clear_wps(wpa_s);
-
-	if (wps_process_oob(wps, oob_dev, 0) < 0)
-		return -1;
-
-	if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
-	     wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-	    wpas_wps_start_pin(wpa_s, NULL,
-			       wpabuf_head(wps->oob_conf.dev_password)) < 0)
-			return -1;
-
-	return 0;
-}
-#endif /* CONFIG_WPS_OOB */
-
-
-int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
-		       const char *pin, struct wps_new_ap_settings *settings)
-{
-	struct wpa_ssid *ssid;
-	char val[200];
-	char *pos, *end;
-	int res;
-
-	if (!pin)
-		return -1;
-	wpas_clear_wps(wpa_s);
-	ssid = wpas_wps_add_network(wpa_s, 1, bssid);
-	if (ssid == NULL)
-		return -1;
-	pos = val;
-	end = pos + sizeof(val);
-	res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
-	if (res < 0 || res >= end - pos)
-		return -1;
-	pos += res;
-	if (settings) {
-		res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
-				  "new_encr=%s new_key=%s",
-				  settings->ssid_hex, settings->auth,
-				  settings->encr, settings->key_hex);
-		if (res < 0 || res >= end - pos)
-			return -1;
-		pos += res;
-	}
-	res = os_snprintf(pos, end - pos, "\"");
-	if (res < 0 || res >= end - pos)
-		return -1;
-	wpa_config_set(ssid, "phase1", val, 0);
-	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
-			       wpa_s, NULL);
-	wpas_wps_reassoc(wpa_s, ssid);
-	return 0;
-}
-
-
-static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
-			       size_t psk_len)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
-		   "STA " MACSTR, MAC2STR(mac_addr));
-	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
-
-	/* TODO */
-
-	return 0;
-}
-
-
-static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
-				   const struct wps_device_data *dev)
-{
-	char uuid[40], txt[400];
-	int len;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
-	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
-		return;
-	wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
-	len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
-			  " [%s|%s|%s|%s|%s|%s]",
-			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
-			  dev->manufacturer, dev->model_name,
-			  dev->model_number, dev->serial_number,
-			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
-					       sizeof(devtype)));
-	if (len > 0 && len < (int) sizeof(txt))
-		wpa_printf(MSG_INFO, "%s", txt);
-}
-
-
-static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
-				    u16 sel_reg_config_methods)
-{
-#ifdef CONFIG_WPS_ER
-	struct wpa_supplicant *wpa_s = ctx;
-
-	if (wpa_s->wps_er == NULL)
-		return;
-	wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
-			   sel_reg_config_methods);
-#endif /* CONFIG_WPS_ER */
-}
-
-
-int wpas_wps_init(struct wpa_supplicant *wpa_s)
-{
-	struct wps_context *wps;
-	struct wps_registrar_config rcfg;
-
-	wps = os_zalloc(sizeof(*wps));
-	if (wps == NULL)
-		return -1;
-
-	wps->cred_cb = wpa_supplicant_wps_cred;
-	wps->event_cb = wpa_supplicant_wps_event;
-	wps->cb_ctx = wpa_s;
-
-	wps->dev.device_name = wpa_s->conf->device_name;
-	wps->dev.manufacturer = wpa_s->conf->manufacturer;
-	wps->dev.model_name = wpa_s->conf->model_name;
-	wps->dev.model_number = wpa_s->conf->model_number;
-	wps->dev.serial_number = wpa_s->conf->serial_number;
-	wps->config_methods =
-		wps_config_methods_str2bin(wpa_s->conf->config_methods);
-	if (wpa_s->conf->device_type &&
-	    wps_dev_type_str2bin(wpa_s->conf->device_type,
-				 wps->dev.pri_dev_type) < 0) {
-		wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
-		os_free(wps);
-		return -1;
-	}
-	wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
-	wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
-	os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
-	if (is_nil_uuid(wpa_s->conf->uuid)) {
-		uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
-		wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
-			    wps->uuid, WPS_UUID_LEN);
-	} else
-		os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
-
-	wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
-	wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
-
-	os_memset(&rcfg, 0, sizeof(rcfg));
-	rcfg.new_psk_cb = wpas_wps_new_psk_cb;
-	rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
-	rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
-	rcfg.cb_ctx = wpa_s;
-
-	wps->registrar = wps_registrar_init(wps, &rcfg);
-	if (wps->registrar == NULL) {
-		wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
-		os_free(wps);
-		return -1;
-	}
-
-	wpa_s->wps = wps;
-
-	return 0;
-}
-
-
-void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
-{
-	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
-
-	if (wpa_s->wps == NULL)
-		return;
-
-#ifdef CONFIG_WPS_ER
-	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
-	wpa_s->wps_er = NULL;
-#endif /* CONFIG_WPS_ER */
-
-	wps_registrar_deinit(wpa_s->wps->registrar);
-	wpabuf_free(wpa_s->wps->dh_pubkey);
-	wpabuf_free(wpa_s->wps->dh_privkey);
-	wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
-	wpabuf_free(wpa_s->wps->oob_conf.dev_password);
-	os_free(wpa_s->wps->network_key);
-	os_free(wpa_s->wps);
-	wpa_s->wps = NULL;
-}
-
-
-int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
-			    struct wpa_ssid *ssid, struct wpa_scan_res *bss)
-{
-	struct wpabuf *wps_ie;
-
-	if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
-		return -1;
-
-	wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
-		if (!wps_ie) {
-			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
-			return 0;
-		}
-
-		if (!wps_is_selected_pbc_registrar(wps_ie)) {
-			wpa_printf(MSG_DEBUG, "   skip - WPS AP "
-				   "without active PBC Registrar");
-			wpabuf_free(wps_ie);
-			return 0;
-		}
-
-		/* TODO: overlap detection */
-		wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
-			   "(Active PBC)");
-		wpabuf_free(wps_ie);
-		return 1;
-	}
-
-	if (eap_is_wps_pin_enrollee(&ssid->eap)) {
-		if (!wps_ie) {
-			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
-			return 0;
-		}
-
-		/*
-		 * Start with WPS APs that advertise active PIN Registrar and
-		 * allow any WPS AP after third scan since some APs do not set
-		 * Selected Registrar attribute properly when using external
-		 * Registrar.
-		 */
-		if (!wps_is_selected_pin_registrar(wps_ie)) {
-			if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
-				wpa_printf(MSG_DEBUG, "   skip - WPS AP "
-					   "without active PIN Registrar");
-				wpabuf_free(wps_ie);
-				return 0;
-			}
-			wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
-		} else {
-			wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
-				   "(Active PIN)");
-		}
-		wpabuf_free(wps_ie);
-		return 1;
-	}
-
-	if (wps_ie) {
-		wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
-		wpabuf_free(wps_ie);
-		return 1;
-	}
-
-	return -1;
-}
-
-
-int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid,
-			      struct wpa_scan_res *bss)
-{
-	struct wpabuf *wps_ie = NULL;
-	int ret = 0;
-
-	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
-		wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-		if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
-			/* allow wildcard SSID for WPS PBC */
-			ret = 1;
-		}
-	} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
-		wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-		if (wps_ie &&
-		    (wps_is_selected_pin_registrar(wps_ie) ||
-		     wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
-			/* allow wildcard SSID for WPS PIN */
-			ret = 1;
-		}
-	}
-
-	if (!ret && ssid->bssid_set &&
-	    os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) {
-		/* allow wildcard SSID due to hardcoded BSSID match */
-		ret = 1;
-	}
-
-	wpabuf_free(wps_ie);
-
-	return ret;
-}
-
-
-int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *selected, struct wpa_ssid *ssid)
-{
-	const u8 *sel_uuid, *uuid;
-	struct wpabuf *wps_ie;
-	int ret = 0;
-	struct wpa_bss *bss;
-
-	if (!eap_is_wps_pbc_enrollee(&ssid->eap))
-		return 0;
-
-	/* Make sure that only one AP is in active PBC mode */
-	wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
-	if (wps_ie)
-		sel_uuid = wps_get_uuid_e(wps_ie);
-	else
-		sel_uuid = NULL;
-
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		struct wpabuf *ie;
-		if (bss == selected)
-			continue;
-		ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-		if (!ie)
-			continue;
-		if (!wps_is_selected_pbc_registrar(ie)) {
-			wpabuf_free(ie);
-			continue;
-		}
-		uuid = wps_get_uuid_e(ie);
-		if (sel_uuid == NULL || uuid == NULL ||
-		    os_memcmp(sel_uuid, uuid, 16) != 0) {
-			ret = 1; /* PBC overlap */
-			wpabuf_free(ie);
-			break;
-		}
-
-		/* TODO: verify that this is reasonable dual-band situation */
-
-		wpabuf_free(ie);
-	}
-
-	wpabuf_free(wps_ie);
-
-	return ret;
-}
-
-
-void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_bss *bss;
-
-	if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
-		return;
-
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		struct wpabuf *ie;
-		ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-		if (!ie)
-			continue;
-		if (wps_is_selected_pbc_registrar(ie))
-			wpa_msg_ctrl(wpa_s, MSG_INFO,
-				     WPS_EVENT_AP_AVAILABLE_PBC);
-		else if (wps_is_selected_pin_registrar(ie))
-			wpa_msg_ctrl(wpa_s, MSG_INFO,
-				     WPS_EVENT_AP_AVAILABLE_PIN);
-		else
-			wpa_msg_ctrl(wpa_s, MSG_INFO,
-				     WPS_EVENT_AP_AVAILABLE);
-		wpabuf_free(ie);
-		break;
-	}
-}
-
-
-int wpas_wps_searching(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid;
-
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
-			return 1;
-	}
-
-	return 0;
-}
-
-
-int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
-			      char *end)
-{
-	struct wpabuf *wps_ie;
-	int ret;
-
-	wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
-	if (wps_ie == NULL)
-		return 0;
-
-	ret = wps_attr_text(wps_ie, buf, end);
-	wpabuf_free(wps_ie);
-	return ret;
-}
-
-
-int wpas_wps_er_start(struct wpa_supplicant *wpa_s)
-{
-#ifdef CONFIG_WPS_ER
-	if (wpa_s->wps_er) {
-		wps_er_refresh(wpa_s->wps_er);
-		return 0;
-	}
-	wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname);
-	if (wpa_s->wps_er == NULL)
-		return -1;
-	return 0;
-#else /* CONFIG_WPS_ER */
-	return 0;
-#endif /* CONFIG_WPS_ER */
-}
-
-
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
-{
-#ifdef CONFIG_WPS_ER
-	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
-	wpa_s->wps_er = NULL;
-#endif /* CONFIG_WPS_ER */
-	return 0;
-}
-
-
-#ifdef CONFIG_WPS_ER
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-			const char *pin)
-{
-	u8 u[UUID_LEN];
-	int any = 0;
-
-	if (os_strcmp(uuid, "any") == 0)
-		any = 1;
-	else if (uuid_str2bin(uuid, u))
-		return -1;
-	return wps_registrar_add_pin(wpa_s->wps->registrar, any ? NULL : u,
-				     (const u8 *) pin, os_strlen(pin), 300);
-}
-
-
-int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
-{
-	u8 u[UUID_LEN];
-
-	if (uuid_str2bin(uuid, u))
-		return -1;
-	return wps_er_pbc(wpa_s->wps_er, u);
-}
-
-
-int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
-		      const char *pin)
-{
-	u8 u[UUID_LEN];
-
-	if (uuid_str2bin(uuid, u))
-		return -1;
-	return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
-			    os_strlen(pin));
-}
-
-
-static void wpas_wps_terminate_cb(void *ctx)
-{
-	wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
-	eloop_terminate();
-}
-#endif /* CONFIG_WPS_ER */
-
-
-int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
-{
-#ifdef CONFIG_WPS_ER
-	if (wpa_s->wps_er) {
-		wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
-		wpa_s->wps_er = NULL;
-		return 1;
-	}
-#endif /* CONFIG_WPS_ER */
-	return 0;
-}

Copied: vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c (from rev 9639, vendor/wpa/dist/wpa_supplicant/wps_supplicant.c)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wps_supplicant.c	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,2142 @@
+/*
+ * wpa_supplicant / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "crypto/random.h"
+#include "crypto/dh_group5.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
+#include "common/wpa_ctrl.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_peer/eap.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "wps/wps_attr_parse.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "notify.h"
+#include "blacklist.h"
+#include "bss.h"
+#include "scan.h"
+#include "ap.h"
+#include "p2p/p2p.h"
+#include "p2p_supplicant.h"
+#include "wps_supplicant.h"
+
+
+#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
+#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
+#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
+
+static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
+
+
+static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
+{
+	os_free(wpa_s->wps_ap);
+	wpa_s->wps_ap = NULL;
+	wpa_s->num_wps_ap = 0;
+	wpa_s->wps_ap_iter = 0;
+}
+
+
+int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->wps_success &&
+	    wpa_s->current_ssid &&
+	    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
+		const u8 *bssid = wpa_s->bssid;
+		if (is_zero_ether_addr(bssid))
+			bssid = wpa_s->pending_bssid;
+
+		wpa_printf(MSG_DEBUG, "WPS: PIN registration with " MACSTR
+			   " did not succeed - continue trying to find "
+			   "suitable AP", MAC2STR(bssid));
+		wpa_blacklist_add(wpa_s, bssid);
+
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s,
+					wpa_s->blacklist_cleared ? 5 : 0, 0);
+		wpa_s->blacklist_cleared = 0;
+		return 1;
+	}
+
+	wpas_wps_clear_ap_info(wpa_s);
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
+	    !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		int disabled = wpa_s->current_ssid->disabled;
+		unsigned int freq = wpa_s->assoc_freq;
+		wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
+			   "try to associate with the received credential "
+			   "(freq=%u)", freq);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		if (disabled) {
+			wpa_printf(MSG_DEBUG, "WPS: Current network is "
+				   "disabled - wait for user to enable");
+			return 1;
+		}
+		wpa_s->after_wps = 5;
+		wpa_s->wps_freq = freq;
+		wpa_s->normal_scans = 0;
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return 1;
+	}
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) {
+		wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
+			   "for external credential processing");
+		wpas_clear_wps(wpa_s);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid,
+					 const struct wps_credential *cred)
+{
+	struct wpa_driver_capa capa;
+	struct wpa_bss *bss;
+	const u8 *ie;
+	struct wpa_ie_data adv;
+	int wpa2 = 0, ccmp = 0;
+
+	/*
+	 * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
+	 * case they are configured for mixed mode operation (WPA+WPA2 and
+	 * TKIP+CCMP). Try to use scan results to figure out whether the AP
+	 * actually supports stronger security and select that if the client
+	 * has support for it, too.
+	 */
+
+	if (wpa_drv_get_capa(wpa_s, &capa))
+		return; /* Unknown what driver supports */
+
+	if (ssid->ssid == NULL)
+		return;
+	bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
+			   "table - use credential as-is");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: AP found from BSS table");
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
+		wpa2 = 1;
+		if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
+			ccmp = 1;
+	} else {
+		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+		if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
+		    adv.pairwise_cipher & WPA_CIPHER_CCMP)
+			ccmp = 1;
+	}
+
+	if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
+	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
+		/*
+		 * TODO: This could be the initial AP configuration and the
+		 * Beacon contents could change shortly. Should request a new
+		 * scan and delay addition of the network until the updated
+		 * scan results are available.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
+			   "support - use credential as-is");
+		return;
+	}
+
+	if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+	    (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
+	    (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
+			   "based on scan results");
+		if (wpa_s->conf->ap_scan == 1)
+			ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
+		else
+			ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+	}
+
+	if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
+	    (ssid->proto & WPA_PROTO_WPA) &&
+	    (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
+		wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
+			   "based on scan results");
+		if (wpa_s->conf->ap_scan == 1)
+			ssid->proto |= WPA_PROTO_RSN;
+		else
+			ssid->proto = WPA_PROTO_RSN;
+	}
+}
+
+
+static int wpa_supplicant_wps_cred(void *ctx,
+				   const struct wps_credential *cred)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	u8 key_idx = 0;
+	u16 auth_type;
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+	int registrar = 0;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
+
+	if ((wpa_s->conf->wps_cred_processing == 1 ||
+	     wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
+		size_t blen = cred->cred_attr_len * 2 + 1;
+		char *buf = os_malloc(blen);
+		if (buf) {
+			wpa_snprintf_hex(buf, blen,
+					 cred->cred_attr, cred->cred_attr_len);
+			wpa_msg(wpa_s, MSG_INFO, "%s%s",
+				WPS_EVENT_CRED_RECEIVED, buf);
+			os_free(buf);
+		}
+
+		wpas_notify_wps_credential(wpa_s, cred);
+	} else
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+			cred->cred_attr, cred->cred_attr_len);
+
+	if (wpa_s->conf->wps_cred_processing == 1)
+		return 0;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
+		   cred->auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+			cred->key, cred->key_len);
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
+		   MAC2STR(cred->mac_addr));
+
+	auth_type = cred->auth_type;
+	if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+		wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
+			   "auth_type into WPA2PSK");
+		auth_type = WPS_AUTH_WPA2PSK;
+	}
+
+	if (auth_type != WPS_AUTH_OPEN &&
+	    auth_type != WPS_AUTH_SHARED &&
+	    auth_type != WPS_AUTH_WPAPSK &&
+	    auth_type != WPS_AUTH_WPA2PSK) {
+		wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+			   "unsupported authentication type 0x%x",
+			   auth_type);
+		return 0;
+	}
+
+	if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+		if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+			wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+				   "invalid Network Key length %lu",
+				   (unsigned long) cred->key_len);
+			return -1;
+		}
+	}
+
+	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
+			   "on the received credential");
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+		if (ssid->eap.identity &&
+		    ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
+		    os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
+			      WSC_ID_REGISTRAR_LEN) == 0)
+			registrar = 1;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
+		os_free(ssid->eap.identity);
+		ssid->eap.identity = NULL;
+		ssid->eap.identity_len = 0;
+		os_free(ssid->eap.phase1);
+		ssid->eap.phase1 = NULL;
+		os_free(ssid->eap.eap_methods);
+		ssid->eap.eap_methods = NULL;
+		if (!ssid->p2p_group) {
+			ssid->temporary = 0;
+			ssid->bssid_set = 0;
+		}
+		ssid->disabled_until.sec = 0;
+		ssid->disabled_until.usec = 0;
+		ssid->auth_failures = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
+			   "received credential");
+		ssid = wpa_config_add_network(wpa_s->conf);
+		if (ssid == NULL)
+			return -1;
+		wpas_notify_network_added(wpa_s, ssid);
+	}
+
+	wpa_config_set_network_defaults(ssid);
+
+	os_free(ssid->ssid);
+	ssid->ssid = os_malloc(cred->ssid_len);
+	if (ssid->ssid) {
+		os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
+		ssid->ssid_len = cred->ssid_len;
+	}
+
+	switch (cred->encr_type) {
+	case WPS_ENCR_NONE:
+		break;
+	case WPS_ENCR_WEP:
+		if (cred->key_len <= 0)
+			break;
+		if (cred->key_len != 5 && cred->key_len != 13 &&
+		    cred->key_len != 10 && cred->key_len != 26) {
+			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
+				   "%lu", (unsigned long) cred->key_len);
+			return -1;
+		}
+		if (cred->key_idx > NUM_WEP_KEYS) {
+			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
+				   cred->key_idx);
+			return -1;
+		}
+		if (cred->key_idx)
+			key_idx = cred->key_idx - 1;
+		if (cred->key_len == 10 || cred->key_len == 26) {
+			if (hexstr2bin((char *) cred->key,
+				       ssid->wep_key[key_idx],
+				       cred->key_len / 2) < 0) {
+				wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
+					   "%d", key_idx);
+				return -1;
+			}
+			ssid->wep_key_len[key_idx] = cred->key_len / 2;
+		} else {
+			os_memcpy(ssid->wep_key[key_idx], cred->key,
+				  cred->key_len);
+			ssid->wep_key_len[key_idx] = cred->key_len;
+		}
+		ssid->wep_tx_keyidx = key_idx;
+		break;
+	case WPS_ENCR_TKIP:
+		ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+		break;
+	case WPS_ENCR_AES:
+		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+		break;
+	}
+
+	switch (auth_type) {
+	case WPS_AUTH_OPEN:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+		ssid->proto = 0;
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
+		if (registrar) {
+			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OPEN_NETWORK
+				"id=%d - Credentials for an open "
+				"network disabled by default - use "
+				"'select_network %d' to enable",
+				ssid->id, ssid->id);
+			ssid->disabled = 1;
+		}
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
+		break;
+	case WPS_AUTH_SHARED:
+		ssid->auth_alg = WPA_AUTH_ALG_SHARED;
+		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+		ssid->proto = 0;
+		break;
+	case WPS_AUTH_WPAPSK:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+		ssid->proto = WPA_PROTO_WPA;
+		break;
+	case WPS_AUTH_WPA2PSK:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+		ssid->proto = WPA_PROTO_RSN;
+		break;
+	}
+
+	if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+		if (cred->key_len == 2 * PMK_LEN) {
+			if (hexstr2bin((const char *) cred->key, ssid->psk,
+				       PMK_LEN)) {
+				wpa_printf(MSG_ERROR, "WPS: Invalid Network "
+					   "Key");
+				return -1;
+			}
+			ssid->psk_set = 1;
+			ssid->export_keys = 1;
+		} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
+			os_free(ssid->passphrase);
+			ssid->passphrase = os_malloc(cred->key_len + 1);
+			if (ssid->passphrase == NULL)
+				return -1;
+			os_memcpy(ssid->passphrase, cred->key, cred->key_len);
+			ssid->passphrase[cred->key_len] = '\0';
+			wpa_config_update_psk(ssid);
+			ssid->export_keys = 1;
+		} else {
+			wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
+				   "length %lu",
+				   (unsigned long) cred->key_len);
+			return -1;
+		}
+	}
+
+	wpas_wps_security_workaround(wpa_s, ssid, cred);
+
+	if (cred->ap_channel)
+		wpa_s->wps_ap_channel = cred->ap_channel;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->conf->update_config &&
+	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
+		return -1;
+	}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+	/*
+	 * Optimize the post-WPS scan based on the channel used during
+	 * the provisioning in case EAP-Failure is not received.
+	 */
+	wpa_s->after_wps = 5;
+	wpa_s->wps_freq = wpa_s->assoc_freq;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static void wpas_wps_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpas_p2p_notif_pbc_overlap(wpa_s);
+}
+#endif /* CONFIG_P2P */
+
+
+static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
+					 struct wps_event_m2d *m2d)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
+		"dev_password_id=%d config_error=%d",
+		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
+			"dev_password_id=%d config_error=%d",
+			m2d->dev_password_id, m2d->config_error);
+	}
+	if (m2d->config_error == WPS_CFG_MULTIPLE_PBC_DETECTED) {
+		/*
+		 * Notify P2P from eloop timeout to avoid issues with the
+		 * interface getting removed while processing a message.
+		 */
+		eloop_register_timeout(0, 0, wpas_wps_pbc_overlap_cb, wpa_s,
+				       NULL);
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
+	"No Error", /* WPS_EI_NO_ERROR */
+	"TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
+	"WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
+};
+
+static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
+					  struct wps_event_fail *fail)
+{
+	if (fail->error_indication > 0 &&
+	    fail->error_indication < NUM_WPS_EI_VALUES) {
+		wpa_msg(wpa_s, MSG_INFO,
+			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
+			fail->msg, fail->config_error, fail->error_indication,
+			wps_event_fail_reason[fail->error_indication]);
+		if (wpa_s->parent && wpa_s->parent != wpa_s)
+			wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+				"msg=%d config_error=%d reason=%d (%s)",
+				fail->msg, fail->config_error,
+				fail->error_indication,
+				wps_event_fail_reason[fail->error_indication]);
+	} else {
+		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
+				"msg=%d config_error=%d",
+				fail->msg, fail->config_error);
+	}
+	wpas_clear_wps(wpa_s);
+	wpas_notify_wps_event_fail(wpa_s, fail);
+#ifdef CONFIG_P2P
+	wpas_p2p_wps_failed(wpa_s, fail);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+	int changed = 0;
+
+	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->disabled_for_connect && ssid->disabled) {
+			ssid->disabled_for_connect = 0;
+			ssid->disabled = 0;
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+			changed++;
+		}
+	}
+
+	if (changed) {
+#ifndef CONFIG_NO_CONFIG_WRITE
+		if (wpa_s->conf->update_config &&
+		    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to update "
+				   "configuration");
+		}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	}
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	/* Enable the networks disabled during wpas_wps_reassoc */
+	wpas_wps_reenable_networks(wpa_s);
+}
+
+
+static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
+	wpa_s->wps_success = 1;
+	wpas_notify_wps_event_success(wpa_s);
+
+	/*
+	 * Enable the networks disabled during wpas_wps_reassoc after 10
+	 * seconds. The 10 seconds timer is to allow the data connection to be
+	 * formed before allowing other networks to be selected.
+	 */
+	eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+			       NULL);
+
+#ifdef CONFIG_P2P
+	wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpa_supplicant_wps_event_er_ap_add(struct wpa_supplicant *wpa_s,
+					       struct wps_event_er_ap *ap)
+{
+	char uuid_str[100];
+	char dev_type[WPS_DEV_TYPE_BUFSIZE];
+
+	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
+	if (ap->pri_dev_type)
+		wps_dev_type_bin2str(ap->pri_dev_type, dev_type,
+				     sizeof(dev_type));
+	else
+		dev_type[0] = '\0';
+
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_ADD "%s " MACSTR
+		" pri_dev_type=%s wps_state=%d |%s|%s|%s|%s|%s|%s|",
+		uuid_str, MAC2STR(ap->mac_addr), dev_type, ap->wps_state,
+		ap->friendly_name ? ap->friendly_name : "",
+		ap->manufacturer ? ap->manufacturer : "",
+		ap->model_description ? ap->model_description : "",
+		ap->model_name ? ap->model_name : "",
+		ap->manufacturer_url ? ap->manufacturer_url : "",
+		ap->model_url ? ap->model_url : "");
+}
+
+
+static void wpa_supplicant_wps_event_er_ap_remove(struct wpa_supplicant *wpa_s,
+						  struct wps_event_er_ap *ap)
+{
+	char uuid_str[100];
+	uuid_bin2str(ap->uuid, uuid_str, sizeof(uuid_str));
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_REMOVE "%s", uuid_str);
+}
+
+
+static void wpa_supplicant_wps_event_er_enrollee_add(
+	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
+{
+	char uuid_str[100];
+	char dev_type[WPS_DEV_TYPE_BUFSIZE];
+
+	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
+	if (enrollee->pri_dev_type)
+		wps_dev_type_bin2str(enrollee->pri_dev_type, dev_type,
+				     sizeof(dev_type));
+	else
+		dev_type[0] = '\0';
+
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_ADD "%s " MACSTR
+		" M1=%d config_methods=0x%x dev_passwd_id=%d pri_dev_type=%s "
+		"|%s|%s|%s|%s|%s|",
+		uuid_str, MAC2STR(enrollee->mac_addr), enrollee->m1_received,
+		enrollee->config_methods, enrollee->dev_passwd_id, dev_type,
+		enrollee->dev_name ? enrollee->dev_name : "",
+		enrollee->manufacturer ? enrollee->manufacturer : "",
+		enrollee->model_name ? enrollee->model_name : "",
+		enrollee->model_number ? enrollee->model_number : "",
+		enrollee->serial_number ? enrollee->serial_number : "");
+}
+
+
+static void wpa_supplicant_wps_event_er_enrollee_remove(
+	struct wpa_supplicant *wpa_s, struct wps_event_er_enrollee *enrollee)
+{
+	char uuid_str[100];
+	uuid_bin2str(enrollee->uuid, uuid_str, sizeof(uuid_str));
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_ENROLLEE_REMOVE "%s " MACSTR,
+		uuid_str, MAC2STR(enrollee->mac_addr));
+}
+
+
+static void wpa_supplicant_wps_event_er_ap_settings(
+	struct wpa_supplicant *wpa_s,
+	struct wps_event_er_ap_settings *ap_settings)
+{
+	char uuid_str[100];
+	char key_str[65];
+	const struct wps_credential *cred = ap_settings->cred;
+
+	key_str[0] = '\0';
+	if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+		if (cred->key_len >= 8 && cred->key_len <= 64) {
+			os_memcpy(key_str, cred->key, cred->key_len);
+			key_str[cred->key_len] = '\0';
+		}
+	}
+
+	uuid_bin2str(ap_settings->uuid, uuid_str, sizeof(uuid_str));
+	/* Use wpa_msg_ctrl to avoid showing the key in debug log */
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_ER_AP_SETTINGS
+		     "uuid=%s ssid=%s auth_type=0x%04x encr_type=0x%04x "
+		     "key=%s",
+		     uuid_str, wpa_ssid_txt(cred->ssid, cred->ssid_len),
+		     cred->auth_type, cred->encr_type, key_str);
+}
+
+
+static void wpa_supplicant_wps_event_er_set_sel_reg(
+	struct wpa_supplicant *wpa_s,
+	struct wps_event_er_set_selected_registrar *ev)
+{
+	char uuid_str[100];
+
+	uuid_bin2str(ev->uuid, uuid_str, sizeof(uuid_str));
+	switch (ev->state) {
+	case WPS_ER_SET_SEL_REG_START:
+		wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
+			"uuid=%s state=START sel_reg=%d dev_passwd_id=%u "
+			"sel_reg_config_methods=0x%x",
+			uuid_str, ev->sel_reg, ev->dev_passwd_id,
+			ev->sel_reg_config_methods);
+		break;
+	case WPS_ER_SET_SEL_REG_DONE:
+		wpa_msg(wpa_s, MSG_DEBUG, WPS_EVENT_ER_SET_SEL_REG
+			"uuid=%s state=DONE", uuid_str);
+		break;
+	case WPS_ER_SET_SEL_REG_FAILED:
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ER_SET_SEL_REG
+			"uuid=%s state=FAILED", uuid_str);
+		break;
+	}
+}
+
+
+static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
+				     union wps_event_data *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	switch (event) {
+	case WPS_EV_M2D:
+		wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
+		break;
+	case WPS_EV_FAIL:
+		wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
+		break;
+	case WPS_EV_SUCCESS:
+		wpa_supplicant_wps_event_success(wpa_s);
+		break;
+	case WPS_EV_PWD_AUTH_FAIL:
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
+			wpa_supplicant_ap_pwd_auth_fail(wpa_s);
+#endif /* CONFIG_AP */
+		break;
+	case WPS_EV_PBC_OVERLAP:
+		break;
+	case WPS_EV_PBC_TIMEOUT:
+		break;
+	case WPS_EV_ER_AP_ADD:
+		wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
+		break;
+	case WPS_EV_ER_AP_REMOVE:
+		wpa_supplicant_wps_event_er_ap_remove(wpa_s, &data->ap);
+		break;
+	case WPS_EV_ER_ENROLLEE_ADD:
+		wpa_supplicant_wps_event_er_enrollee_add(wpa_s,
+							 &data->enrollee);
+		break;
+	case WPS_EV_ER_ENROLLEE_REMOVE:
+		wpa_supplicant_wps_event_er_enrollee_remove(wpa_s,
+							    &data->enrollee);
+		break;
+	case WPS_EV_ER_AP_SETTINGS:
+		wpa_supplicant_wps_event_er_ap_settings(wpa_s,
+							&data->ap_settings);
+		break;
+	case WPS_EV_ER_SET_SELECTED_REGISTRAR:
+		wpa_supplicant_wps_event_er_set_sel_reg(wpa_s,
+							&data->set_sel_reg);
+		break;
+	case WPS_EV_AP_PIN_SUCCESS:
+		break;
+	}
+}
+
+
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
+{
+	if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
+	    eap_is_wps_pin_enrollee(&ssid->eap))
+		return WPS_REQ_ENROLLEE;
+	else
+		return WPS_REQ_REGISTRAR;
+}
+
+
+static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
+{
+	int id;
+	struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
+
+	prev_current = wpa_s->current_ssid;
+
+	/* Enable the networks disabled during wpas_wps_reassoc */
+	wpas_wps_reenable_networks(wpa_s);
+
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+
+	/* Remove any existing WPS network from configuration */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+			if (ssid == wpa_s->current_ssid) {
+				wpa_s->current_ssid = NULL;
+				if (ssid != NULL)
+					wpas_notify_network_changed(wpa_s);
+			}
+			id = ssid->id;
+			remove_ssid = ssid;
+		} else
+			id = -1;
+		ssid = ssid->next;
+		if (id >= 0) {
+			if (prev_current == remove_ssid) {
+				wpa_sm_set_config(wpa_s->wpa, NULL);
+				eapol_sm_notify_config(wpa_s->eapol, NULL,
+						       NULL);
+			}
+			wpas_notify_network_removed(wpa_s, remove_ssid);
+			wpa_config_remove_network(wpa_s->conf, id);
+		}
+	}
+
+	wpas_wps_clear_ap_info(wpa_s);
+}
+
+
+static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_TIMEOUT "Requested operation timed "
+		"out");
+	wpas_clear_wps(wpa_s);
+}
+
+
+static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
+					      int registrar, const u8 *bssid)
+{
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return NULL;
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->temporary = 1;
+	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
+	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
+	    wpa_config_set(ssid, "identity", registrar ?
+			   "\"" WSC_ID_REGISTRAR "\"" :
+			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
+		wpas_notify_network_removed(wpa_s, ssid);
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+		return NULL;
+	}
+
+	if (bssid) {
+#ifndef CONFIG_P2P
+		struct wpa_bss *bss;
+		int count = 0;
+#endif /* CONFIG_P2P */
+
+		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
+		ssid->bssid_set = 1;
+
+		/*
+		 * Note: With P2P, the SSID may change at the time the WPS
+		 * provisioning is started, so better not filter the AP based
+		 * on the current SSID in the scan results.
+		 */
+#ifndef CONFIG_P2P
+		dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+			if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
+				continue;
+
+			os_free(ssid->ssid);
+			ssid->ssid = os_malloc(bss->ssid_len);
+			if (ssid->ssid == NULL)
+				break;
+			os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
+			ssid->ssid_len = bss->ssid_len;
+			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
+					  "scan results",
+					  ssid->ssid, ssid->ssid_len);
+			count++;
+		}
+
+		if (count > 1) {
+			wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
+				   "for the AP; use wildcard");
+			os_free(ssid->ssid);
+			ssid->ssid = NULL;
+			ssid->ssid_len = 0;
+		}
+#endif /* CONFIG_P2P */
+	}
+
+	return ssid;
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *selected, const u8 *bssid)
+{
+	struct wpa_ssid *ssid;
+	struct wpa_bss *bss;
+
+	wpa_s->known_wps_freq = 0;
+	if (bssid) {
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+		if (bss && bss->freq > 0) {
+			wpa_s->known_wps_freq = 1;
+			wpa_s->wps_freq = bss->freq;
+		}
+	}
+
+	if (wpa_s->current_ssid)
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+	/* Mark all other networks disabled and trigger reassociation */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		int was_disabled = ssid->disabled;
+		ssid->disabled_for_connect = 0;
+		/*
+		 * In case the network object corresponds to a persistent group
+		 * then do not send out network disabled signal. In addition,
+		 * do not change disabled status of persistent network objects
+		 * from 2 to 1 should we connect to another network.
+		 */
+		if (was_disabled != 2) {
+			ssid->disabled = ssid != selected;
+			if (was_disabled != ssid->disabled) {
+				if (ssid->disabled)
+					ssid->disabled_for_connect = 1;
+				wpas_notify_network_enabled_changed(wpa_s,
+								    ssid);
+			}
+		}
+		ssid = ssid->next;
+	}
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_s->scan_runs = 0;
+	wpa_s->normal_scans = 0;
+	wpa_s->wps_success = 0;
+	wpa_s->blacklist_cleared = 0;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       int p2p_group)
+{
+	struct wpa_ssid *ssid;
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	if (ssid == NULL)
+		return -1;
+	ssid->temporary = 1;
+	ssid->p2p_group = p2p_group;
+#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);
+		if (ssid->ssid) {
+			ssid->ssid_len = wpa_s->go_params->ssid_len;
+			os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+				  ssid->ssid_len);
+			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+					  "SSID", ssid->ssid, ssid->ssid_len);
+		}
+	}
+#endif /* CONFIG_P2P */
+	wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+	if (wpa_s->wps_fragment_size)
+		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	return 0;
+}
+
+
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, int p2p_group, u16 dev_pw_id)
+{
+	struct wpa_ssid *ssid;
+	char val[128];
+	unsigned int rpin = 0;
+
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	if (ssid == NULL)
+		return -1;
+	ssid->temporary = 1;
+	ssid->p2p_group = p2p_group;
+#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);
+		if (ssid->ssid) {
+			ssid->ssid_len = wpa_s->go_params->ssid_len;
+			os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+				  ssid->ssid_len);
+			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+					  "SSID", ssid->ssid, ssid->ssid_len);
+		}
+	}
+#endif /* CONFIG_P2P */
+	if (pin)
+		os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
+			    pin, dev_pw_id);
+	else {
+		rpin = wps_generate_pin();
+		os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
+			    rpin, dev_pw_id);
+	}
+	wpa_config_set(ssid, "phase1", val, 0);
+	if (wpa_s->wps_fragment_size)
+		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpa_s->wps_ap_iter = 1;
+	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	return rpin;
+}
+
+
+/* Cancel the wps pbc/pin requests */
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
+		return wpa_supplicant_ap_wps_cancel(wpa_s);
+	}
+#endif /* CONFIG_AP */
+
+	if (wpa_s->wpa_state == WPA_SCANNING ||
+	    wpa_s->wpa_state == WPA_DISCONNECTED) {
+		wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
+		wpa_supplicant_cancel_scan(wpa_s);
+		wpas_clear_wps(wpa_s);
+	} else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+		wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
+			   "deauthenticate");
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		wpas_clear_wps(wpa_s);
+	} else {
+		wpas_wps_reenable_networks(wpa_s);
+		wpas_wps_clear_ap_info(wpa_s);
+	}
+
+	return 0;
+}
+
+
+int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, struct wps_new_ap_settings *settings)
+{
+	struct wpa_ssid *ssid;
+	char val[200];
+	char *pos, *end;
+	int res;
+
+	if (!pin)
+		return -1;
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+	if (ssid == NULL)
+		return -1;
+	ssid->temporary = 1;
+	pos = val;
+	end = pos + sizeof(val);
+	res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
+	if (res < 0 || res >= end - pos)
+		return -1;
+	pos += res;
+	if (settings) {
+		res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
+				  "new_encr=%s new_key=%s",
+				  settings->ssid_hex, settings->auth,
+				  settings->encr, settings->key_hex);
+		if (res < 0 || res >= end - pos)
+			return -1;
+		pos += res;
+	}
+	res = os_snprintf(pos, end - pos, "\"");
+	if (res < 0 || res >= end - pos)
+		return -1;
+	wpa_config_set(ssid, "phase1", val, 0);
+	if (wpa_s->wps_fragment_size)
+		ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpas_wps_reassoc(wpa_s, ssid, bssid);
+	return 0;
+}
+
+
+static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+			       size_t psk_len)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
+		   "STA " MACSTR, MAC2STR(mac_addr));
+	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+	/* TODO */
+
+	return 0;
+}
+
+
+static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+				   const struct wps_device_data *dev)
+{
+	char uuid[40], txt[400];
+	int len;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
+	len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
+			  " [%s|%s|%s|%s|%s|%s]",
+			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			  dev->manufacturer, dev->model_name,
+			  dev->model_number, dev->serial_number,
+			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					       sizeof(devtype)));
+	if (len > 0 && len < (int) sizeof(txt))
+		wpa_printf(MSG_INFO, "%s", txt);
+}
+
+
+static void wpas_wps_set_sel_reg_cb(void *ctx, int sel_reg, u16 dev_passwd_id,
+				    u16 sel_reg_config_methods)
+{
+#ifdef CONFIG_WPS_ER
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (wpa_s->wps_er == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar - sel_reg=%d "
+		   "dev_password_id=%u sel_reg_config_methods=0x%x",
+		   sel_reg, dev_passwd_id, sel_reg_config_methods);
+	wps_er_set_sel_reg(wpa_s->wps_er, sel_reg, dev_passwd_id,
+			   sel_reg_config_methods);
+#endif /* CONFIG_WPS_ER */
+}
+
+
+static u16 wps_fix_config_methods(u16 config_methods)
+{
+#ifdef CONFIG_WPS2
+	if ((config_methods &
+	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
+	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
+		wpa_printf(MSG_INFO, "WPS: Converting display to "
+			   "virtual_display for WPS 2.0 compliance");
+		config_methods |= WPS_CONFIG_VIRT_DISPLAY;
+	}
+	if ((config_methods &
+	     (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
+	      WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
+		wpa_printf(MSG_INFO, "WPS: Converting push_button to "
+			   "virtual_push_button for WPS 2.0 compliance");
+		config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+	}
+#endif /* CONFIG_WPS2 */
+
+	return config_methods;
+}
+
+
+static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
+			      struct wps_context *wps)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Set UUID for interface %s", wpa_s->ifname);
+	if (is_nil_uuid(wpa_s->conf->uuid)) {
+		struct wpa_supplicant *first;
+		first = wpa_s->global->ifaces;
+		while (first && first->next)
+			first = first->next;
+		if (first && first != wpa_s) {
+			if (wps != wpa_s->global->ifaces->wps)
+				os_memcpy(wps->uuid,
+					  wpa_s->global->ifaces->wps->uuid,
+					  WPS_UUID_LEN);
+			wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
+				    "interface", wps->uuid, WPS_UUID_LEN);
+		} else {
+			uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
+			wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+				    "address", wps->uuid, WPS_UUID_LEN);
+		}
+	} else {
+		os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: UUID based on configuration",
+			    wps->uuid, WPS_UUID_LEN);
+	}
+}
+
+
+static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
+				       struct wps_context *wps)
+{
+	wpabuf_free(wps->dev.vendor_ext_m1);
+	wps->dev.vendor_ext_m1 = NULL;
+
+	if (wpa_s->conf->wps_vendor_ext_m1) {
+		wps->dev.vendor_ext_m1 =
+			wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
+		if (!wps->dev.vendor_ext_m1) {
+			wpa_printf(MSG_ERROR, "WPS: Cannot "
+				   "allocate memory for vendor_ext_m1");
+		}
+	}
+}
+
+
+int wpas_wps_init(struct wpa_supplicant *wpa_s)
+{
+	struct wps_context *wps;
+	struct wps_registrar_config rcfg;
+	struct hostapd_hw_modes *modes;
+	u16 m;
+
+	wps = os_zalloc(sizeof(*wps));
+	if (wps == NULL)
+		return -1;
+
+	wps->cred_cb = wpa_supplicant_wps_cred;
+	wps->event_cb = wpa_supplicant_wps_event;
+	wps->cb_ctx = wpa_s;
+
+	wps->dev.device_name = wpa_s->conf->device_name;
+	wps->dev.manufacturer = wpa_s->conf->manufacturer;
+	wps->dev.model_name = wpa_s->conf->model_name;
+	wps->dev.model_number = wpa_s->conf->model_number;
+	wps->dev.serial_number = wpa_s->conf->serial_number;
+	wps->config_methods =
+		wps_config_methods_str2bin(wpa_s->conf->config_methods);
+	if ((wps->config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
+	    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
+		wpa_printf(MSG_ERROR, "WPS: Both Label and Display config "
+			   "methods are not allowed at the same time");
+		os_free(wps);
+		return -1;
+	}
+	wps->config_methods = wps_fix_config_methods(wps->config_methods);
+	wps->dev.config_methods = wps->config_methods;
+	os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
+		  WPS_DEV_TYPE_LEN);
+
+	wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+	os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
+		  WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
+
+	wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
+	wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
+	modes = wpa_s->hw.modes;
+	if (modes) {
+		for (m = 0; m < wpa_s->hw.num_modes; m++) {
+			if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
+			    modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+				wps->dev.rf_bands |= WPS_RF_24GHZ;
+			else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
+				wps->dev.rf_bands |= WPS_RF_50GHZ;
+		}
+	}
+	if (wps->dev.rf_bands == 0) {
+		/*
+		 * Default to claiming support for both bands if the driver
+		 * does not provide support for fetching supported bands.
+		 */
+		wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
+	}
+	os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
+	wpas_wps_set_uuid(wpa_s, wps);
+
+	wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
+	wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+
+	os_memset(&rcfg, 0, sizeof(rcfg));
+	rcfg.new_psk_cb = wpas_wps_new_psk_cb;
+	rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
+	rcfg.set_sel_reg_cb = wpas_wps_set_sel_reg_cb;
+	rcfg.cb_ctx = wpa_s;
+
+	wps->registrar = wps_registrar_init(wps, &rcfg);
+	if (wps->registrar == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
+		os_free(wps);
+		return -1;
+	}
+
+	wpa_s->wps = wps;
+
+	return 0;
+}
+
+
+void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+	wpas_wps_clear_ap_info(wpa_s);
+
+	if (wpa_s->wps == NULL)
+		return;
+
+#ifdef CONFIG_WPS_ER
+	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
+	wpa_s->wps_er = NULL;
+#endif /* CONFIG_WPS_ER */
+
+	wps_registrar_deinit(wpa_s->wps->registrar);
+	wpabuf_free(wpa_s->wps->dh_pubkey);
+	wpabuf_free(wpa_s->wps->dh_privkey);
+	wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
+	os_free(wpa_s->wps->network_key);
+	os_free(wpa_s->wps);
+	wpa_s->wps = NULL;
+}
+
+
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+			    struct wpa_ssid *ssid, struct wpa_bss *bss)
+{
+	struct wpabuf *wps_ie;
+
+	if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+		return -1;
+
+	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+		if (!wps_ie) {
+			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
+			return 0;
+		}
+
+		if (!wps_is_selected_pbc_registrar(wps_ie)) {
+			wpa_printf(MSG_DEBUG, "   skip - WPS AP "
+				   "without active PBC Registrar");
+			wpabuf_free(wps_ie);
+			return 0;
+		}
+
+		/* TODO: overlap detection */
+		wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
+			   "(Active PBC)");
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+		if (!wps_ie) {
+			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
+			return 0;
+		}
+
+		/*
+		 * Start with WPS APs that advertise our address as an
+		 * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
+		 * allow any WPS AP after couple of scans since some APs do not
+		 * set Selected Registrar attribute properly when using
+		 * external Registrar.
+		 */
+		if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+			if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
+				wpa_printf(MSG_DEBUG, "   skip - WPS AP "
+					   "without active PIN Registrar");
+				wpabuf_free(wps_ie);
+				return 0;
+			}
+			wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
+		} else {
+			wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
+				   "(Authorized MAC or Active PIN)");
+		}
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	if (wps_ie) {
+		wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	return -1;
+}
+
+
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid,
+			      struct wpa_bss *bss)
+{
+	struct wpabuf *wps_ie = NULL;
+	int ret = 0;
+
+	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+		wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
+			/* allow wildcard SSID for WPS PBC */
+			ret = 1;
+		}
+	} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+		wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (wps_ie &&
+		    (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
+		     wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
+			/* allow wildcard SSID for WPS PIN */
+			ret = 1;
+		}
+	}
+
+	if (!ret && ssid->bssid_set &&
+	    os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) {
+		/* allow wildcard SSID due to hardcoded BSSID match */
+		ret = 1;
+	}
+
+#ifdef CONFIG_WPS_STRICT
+	if (wps_ie) {
+		if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
+						   0, bss->bssid) < 0)
+			ret = 0;
+		if (bss->beacon_ie_len) {
+			struct wpabuf *bcn_wps;
+			bcn_wps = wpa_bss_get_vendor_ie_multi_beacon(
+				bss, WPS_IE_VENDOR_TYPE);
+			if (bcn_wps == NULL) {
+				wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
+					   "missing from AP Beacon");
+				ret = 0;
+			} else {
+				if (wps_validate_beacon(wps_ie) < 0)
+					ret = 0;
+				wpabuf_free(bcn_wps);
+			}
+		}
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+	wpabuf_free(wps_ie);
+
+	return ret;
+}
+
+
+int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *selected, struct wpa_ssid *ssid)
+{
+	const u8 *sel_uuid, *uuid;
+	struct wpabuf *wps_ie;
+	int ret = 0;
+	struct wpa_bss *bss;
+
+	if (!eap_is_wps_pbc_enrollee(&ssid->eap))
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is "
+		   "present in scan results; selected BSSID " MACSTR,
+		   MAC2STR(selected->bssid));
+
+	/* Make sure that only one AP is in active PBC mode */
+	wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
+	if (wps_ie) {
+		sel_uuid = wps_get_uuid_e(wps_ie);
+		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the selected BSS",
+			    sel_uuid, UUID_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS: Selected BSS does not include "
+			   "WPS IE?!");
+		sel_uuid = NULL;
+	}
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		struct wpabuf *ie;
+		if (bss == selected)
+			continue;
+		ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (!ie)
+			continue;
+		if (!wps_is_selected_pbc_registrar(ie)) {
+			wpabuf_free(ie);
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
+			   MACSTR, MAC2STR(bss->bssid));
+		uuid = wps_get_uuid_e(ie);
+		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
+			    uuid, UUID_LEN);
+		if (sel_uuid == NULL || uuid == NULL ||
+		    os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
+			ret = 1; /* PBC overlap */
+			wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
+				MACSTR " and " MACSTR,
+				MAC2STR(selected->bssid),
+				MAC2STR(bss->bssid));
+			wpabuf_free(ie);
+			break;
+		}
+
+		/* TODO: verify that this is reasonable dual-band situation */
+
+		wpabuf_free(ie);
+	}
+
+	wpabuf_free(wps_ie);
+
+	return ret;
+}
+
+
+void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	unsigned int pbc = 0, auth = 0, pin = 0, wps = 0;
+
+	if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		struct wpabuf *ie;
+		ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (!ie)
+			continue;
+		if (wps_is_selected_pbc_registrar(ie))
+			pbc++;
+		else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
+			auth++;
+		else if (wps_is_selected_pin_registrar(ie))
+			pin++;
+		else
+			wps++;
+		wpabuf_free(ie);
+	}
+
+	if (pbc)
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
+	else if (auth)
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_AUTH);
+	else if (pin)
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
+	else if (wps)
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
+}
+
+
+int wpas_wps_searching(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			      char *end)
+{
+	struct wpabuf *wps_ie;
+	int ret;
+
+	wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_DEV_OUI_WFA);
+	if (wps_ie == NULL)
+		return 0;
+
+	ret = wps_attr_text(wps_ie, buf, end);
+	wpabuf_free(wps_ie);
+	return ret;
+}
+
+
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter)
+{
+#ifdef CONFIG_WPS_ER
+	if (wpa_s->wps_er) {
+		wps_er_refresh(wpa_s->wps_er);
+		return 0;
+	}
+	wpa_s->wps_er = wps_er_init(wpa_s->wps, wpa_s->ifname, filter);
+	if (wpa_s->wps_er == NULL)
+		return -1;
+	return 0;
+#else /* CONFIG_WPS_ER */
+	return 0;
+#endif /* CONFIG_WPS_ER */
+}
+
+
+int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS_ER
+	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
+	wpa_s->wps_er = NULL;
+#endif /* CONFIG_WPS_ER */
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_ER
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+			const char *uuid, const char *pin)
+{
+	u8 u[UUID_LEN];
+	int any = 0;
+
+	if (os_strcmp(uuid, "any") == 0)
+		any = 1;
+	else if (uuid_str2bin(uuid, u))
+		return -1;
+	return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
+				     any ? NULL : u,
+				     (const u8 *) pin, os_strlen(pin), 300);
+}
+
+
+int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
+{
+	u8 u[UUID_LEN];
+
+	if (uuid_str2bin(uuid, u))
+		return -1;
+	return wps_er_pbc(wpa_s->wps_er, u);
+}
+
+
+int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
+		      const char *pin)
+{
+	u8 u[UUID_LEN];
+
+	if (uuid_str2bin(uuid, u))
+		return -1;
+	return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+			    os_strlen(pin));
+}
+
+
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+			   int id)
+{
+	u8 u[UUID_LEN];
+	struct wpa_ssid *ssid;
+	struct wps_credential cred;
+
+	if (uuid_str2bin(uuid, u))
+		return -1;
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL || ssid->ssid == NULL)
+		return -1;
+
+	os_memset(&cred, 0, sizeof(cred));
+	if (ssid->ssid_len > 32)
+		return -1;
+	os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
+	cred.ssid_len = ssid->ssid_len;
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+		cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+			WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
+		if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
+			cred.encr_type = WPS_ENCR_AES;
+		else
+			cred.encr_type = WPS_ENCR_TKIP;
+		if (ssid->passphrase) {
+			cred.key_len = os_strlen(ssid->passphrase);
+			if (cred.key_len >= 64)
+				return -1;
+			os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+		} else if (ssid->psk_set) {
+			cred.key_len = 32;
+			os_memcpy(cred.key, ssid->psk, 32);
+		} else
+			return -1;
+	} else {
+		cred.auth_type = WPS_AUTH_OPEN;
+		cred.encr_type = WPS_ENCR_NONE;
+	}
+	return wps_er_set_config(wpa_s->wps_er, u, &cred);
+}
+
+
+int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
+		       const char *pin, struct wps_new_ap_settings *settings)
+{
+	u8 u[UUID_LEN];
+	struct wps_credential cred;
+	size_t len;
+
+	if (uuid_str2bin(uuid, u))
+		return -1;
+	if (settings->ssid_hex == NULL || settings->auth == NULL ||
+	    settings->encr == NULL || settings->key_hex == NULL)
+		return -1;
+
+	os_memset(&cred, 0, sizeof(cred));
+	len = os_strlen(settings->ssid_hex);
+	if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
+	    hexstr2bin(settings->ssid_hex, cred.ssid, len / 2))
+		return -1;
+	cred.ssid_len = len / 2;
+
+	len = os_strlen(settings->key_hex);
+	if ((len & 1) || len > 2 * sizeof(cred.key) ||
+	    hexstr2bin(settings->key_hex, cred.key, len / 2))
+		return -1;
+	cred.key_len = len / 2;
+
+	if (os_strcmp(settings->auth, "OPEN") == 0)
+		cred.auth_type = WPS_AUTH_OPEN;
+	else if (os_strcmp(settings->auth, "WPAPSK") == 0)
+		cred.auth_type = WPS_AUTH_WPAPSK;
+	else if (os_strcmp(settings->auth, "WPA2PSK") == 0)
+		cred.auth_type = WPS_AUTH_WPA2PSK;
+	else
+		return -1;
+
+	if (os_strcmp(settings->encr, "NONE") == 0)
+		cred.encr_type = WPS_ENCR_NONE;
+	else if (os_strcmp(settings->encr, "WEP") == 0)
+		cred.encr_type = WPS_ENCR_WEP;
+	else if (os_strcmp(settings->encr, "TKIP") == 0)
+		cred.encr_type = WPS_ENCR_TKIP;
+	else if (os_strcmp(settings->encr, "CCMP") == 0)
+		cred.encr_type = WPS_ENCR_AES;
+	else
+		return -1;
+
+	return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
+			     os_strlen(pin), &cred);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+					     int ndef, const char *uuid)
+{
+	struct wpabuf *ret;
+	u8 u[UUID_LEN];
+
+	if (!wpa_s->wps_er)
+		return NULL;
+
+	if (uuid_str2bin(uuid, u))
+		return NULL;
+
+	ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int callbacks_pending = 0;
+
+static void wpas_wps_terminate_cb(void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "WPS ER: Terminated");
+	if (--callbacks_pending <= 0)
+		eloop_terminate();
+}
+#endif /* CONFIG_WPS_ER */
+
+
+int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS_ER
+	if (wpa_s->wps_er) {
+		callbacks_pending++;
+		wps_er_deinit(wpa_s->wps_er, wpas_wps_terminate_cb, wpa_s);
+		wpa_s->wps_er = NULL;
+		return 1;
+	}
+#endif /* CONFIG_WPS_ER */
+	return 0;
+}
+
+
+int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!ssid->disabled && ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
+{
+	struct wps_context *wps = wpa_s->wps;
+
+	if (wps == NULL)
+		return;
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
+		wps->config_methods = wps_config_methods_str2bin(
+			wpa_s->conf->config_methods);
+		if ((wps->config_methods &
+		     (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
+		    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
+			wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
+				   "config methods are not allowed at the "
+				   "same time");
+			wps->config_methods &= ~WPS_CONFIG_LABEL;
+		}
+	}
+	wps->config_methods = wps_fix_config_methods(wps->config_methods);
+	wps->dev.config_methods = wps->config_methods;
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE)
+		os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
+			  WPS_DEV_TYPE_LEN);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_SEC_DEVICE_TYPE) {
+		wps->dev.num_sec_dev_types = wpa_s->conf->num_sec_device_types;
+		os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
+			  wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
+		wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
+		wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID)
+		wpas_wps_set_uuid(wpa_s, wps);
+
+	if (wpa_s->conf->changed_parameters &
+	    (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
+		/* Update pointers to make sure they refer current values */
+		wps->dev.device_name = wpa_s->conf->device_name;
+		wps->dev.manufacturer = wpa_s->conf->manufacturer;
+		wps->dev.model_name = wpa_s->conf->model_name;
+		wps->dev.model_number = wpa_s->conf->model_number;
+		wps->dev.serial_number = wpa_s->conf->serial_number;
+	}
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+	return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
+				 &wpa_s->conf->wps_nfc_dh_pubkey,
+				 &wpa_s->conf->wps_nfc_dh_privkey,
+				 &wpa_s->conf->wps_nfc_dev_pw);
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wps_context *wps = wpa_s->wps;
+	char pw[32 * 2 + 1];
+
+	if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+	    wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+	    wpa_s->conf->wps_nfc_dev_pw == NULL)
+		return -1;
+
+	dh5_free(wps->dh_ctx);
+	wpabuf_free(wps->dh_pubkey);
+	wpabuf_free(wps->dh_privkey);
+	wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+	wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+	if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+		wps->dh_ctx = NULL;
+		wpabuf_free(wps->dh_pubkey);
+		wps->dh_pubkey = NULL;
+		wpabuf_free(wps->dh_privkey);
+		wps->dh_privkey = NULL;
+		return -1;
+	}
+	wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+	if (wps->dh_ctx == NULL)
+		return -1;
+
+	wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+				   wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
+				   wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
+	return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
+				  wpa_s->conf->wps_nfc_dev_pw_id);
+}
+
+
+static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
+			     struct wps_parse_attr *attr)
+{
+	wpa_s->wps_ap_channel = 0;
+
+	if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
+		return -1;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+		   "based on the received credential added");
+	wpa_s->normal_scans = 0;
+	wpa_supplicant_reinit_autoscan(wpa_s);
+	if (wpa_s->wps_ap_channel) {
+		u16 chan = wpa_s->wps_ap_channel;
+		int freq = 0;
+
+		if (chan >= 1 && chan <= 13)
+			freq = 2407 + 5 * chan;
+		else if (chan == 14)
+			freq = 2484;
+		else if (chan >= 30)
+			freq = 5000 + 5 * chan;
+
+		if (freq) {
+			wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
+				   "AP channel %u -> %u MHz", chan, freq);
+			wpa_s->after_wps = 5;
+			wpa_s->wps_freq = freq;
+		}
+	}
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_ER
+static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
+					   struct wps_parse_attr *attr)
+{
+	return wps_registrar_add_nfc_password_token(
+		wpa_s->wps->registrar, attr->oob_dev_password,
+		attr->oob_dev_password_len);
+}
+#endif /* CONFIG_WPS_ER */
+
+
+static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
+				    const struct wpabuf *wps)
+{
+	struct wps_parse_attr attr;
+
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+	if (wps_parse_msg(wps, &attr)) {
+		wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+		return -1;
+	}
+
+	if (attr.num_cred)
+		return wpas_wps_use_cred(wpa_s, &attr);
+
+#ifdef CONFIG_WPS_ER
+	if (attr.oob_dev_password)
+		return wpas_wps_add_nfc_password_token(wpa_s, &attr);
+#endif /* CONFIG_WPS_ER */
+
+	wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+	return -1;
+}
+
+
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+			  const struct wpabuf *data)
+{
+	const struct wpabuf *wps = data;
+	struct wpabuf *tmp = NULL;
+	int ret;
+
+	if (wpabuf_len(data) < 4)
+		return -1;
+
+	if (*wpabuf_head_u8(data) != 0x10) {
+		/* Assume this contains full NDEF record */
+		tmp = ndef_parse_wifi(data);
+		if (tmp == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+			return -1;
+		}
+		wps = tmp;
+	}
+
+	ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+	wpabuf_free(tmp);
+	return ret;
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+{
+	return ndef_build_wifi_hr();
+}
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+{
+	return NULL;
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data)
+{
+	struct wpabuf *wps;
+	int ret;
+
+	wps = ndef_parse_wifi(data);
+	if (wps == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+		   "payload from NFC connection handover");
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
+	ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+	wpabuf_free(wps);
+
+	return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+extern int wpa_debug_level;
+
+static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
+{
+	size_t i;
+	struct os_time now;
+
+	if (wpa_debug_level > MSG_DEBUG)
+		return;
+
+	if (wpa_s->wps_ap == NULL)
+		return;
+
+	os_get_time(&now);
+
+	for (i = 0; i < wpa_s->num_wps_ap; i++) {
+		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+		struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+
+		wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
+			   "tries=%d last_attempt=%d sec ago blacklist=%d",
+			   (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
+			   ap->last_attempt.sec > 0 ?
+			   (int) now.sec - (int) ap->last_attempt.sec : -1,
+			   e ? e->count : 0);
+	}
+}
+
+
+static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
+						 const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->wps_ap == NULL)
+		return NULL;
+
+	for (i = 0; i < wpa_s->num_wps_ap; i++) {
+		struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+		if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
+			return ap;
+	}
+
+	return NULL;
+}
+
+
+static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
+					struct wpa_scan_res *res)
+{
+	struct wpabuf *wps;
+	enum wps_ap_info_type type;
+	struct wps_ap_info *ap;
+	int r;
+
+	if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
+		return;
+
+	wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+	if (wps == NULL)
+		return;
+
+	r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
+	if (r == 2)
+		type = WPS_AP_SEL_REG_OUR;
+	else if (r == 1)
+		type = WPS_AP_SEL_REG;
+	else
+		type = WPS_AP_NOT_SEL_REG;
+
+	wpabuf_free(wps);
+
+	ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
+	if (ap) {
+		if (ap->type != type) {
+			wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
+				   " changed type %d -> %d",
+				   MAC2STR(res->bssid), ap->type, type);
+			ap->type = type;
+			if (type != WPS_AP_NOT_SEL_REG)
+				wpa_blacklist_del(wpa_s, ap->bssid);
+		}
+		return;
+	}
+
+	ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
+			      sizeof(struct wps_ap_info));
+	if (ap == NULL)
+		return;
+
+	wpa_s->wps_ap = ap;
+	ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
+	wpa_s->num_wps_ap++;
+
+	os_memset(ap, 0, sizeof(*ap));
+	os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
+	ap->type = type;
+	wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
+		   MAC2STR(ap->bssid), ap->type);
+}
+
+
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_results *scan_res)
+{
+	size_t i;
+
+	for (i = 0; i < scan_res->num; i++)
+		wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
+
+	wpas_wps_dump_ap_info(wpa_s);
+}
+
+
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wps_ap_info *ap;
+	if (!wpa_s->wps_ap_iter)
+		return;
+	ap = wpas_wps_get_ap_info(wpa_s, bssid);
+	if (ap == NULL)
+		return;
+	ap->tries++;
+	os_get_time(&ap->last_attempt);
+}

Deleted: vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h
===================================================================
--- vendor/wpa/dist/wpa_supplicant/wps_supplicant.h	2017-10-22 18:04:47 UTC (rev 9637)
+++ vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -1,117 +0,0 @@
-/*
- * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j at w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef WPS_SUPPLICANT_H
-#define WPS_SUPPLICANT_H
-
-struct wpa_scan_res;
-
-#ifdef CONFIG_WPS
-
-#include "wps/wps.h"
-#include "wps/wps_defs.h"
-
-struct wpa_bss;
-
-struct wps_new_ap_settings {
-	const char *ssid_hex;
-	const char *auth;
-	const char *encr;
-	const char *key_hex;
-};
-
-int wpas_wps_init(struct wpa_supplicant *wpa_s);
-void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
-int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
-enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
-int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-		       const char *pin);
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
-		       char *path, char *method, char *name);
-int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
-		       const char *pin, struct wps_new_ap_settings *settings);
-int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
-			    struct wpa_ssid *ssid, struct wpa_scan_res *bss);
-int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
-			      struct wpa_ssid *ssid, struct wpa_scan_res *bss);
-int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
-			      struct wpa_bss *selected, struct wpa_ssid *ssid);
-void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
-int wpas_wps_searching(struct wpa_supplicant *wpa_s);
-int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
-			      char *end);
-int wpas_wps_er_start(struct wpa_supplicant *wpa_s);
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-			const char *pin);
-int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
-int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
-		      const char *pin);
-int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
-
-#else /* CONFIG_WPS */
-
-static inline int wpas_wps_init(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
-{
-	return 0;
-}
-
-static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
-					  struct wpa_ssid *ssid,
-					  struct wpa_scan_res *bss)
-{
-	return -1;
-}
-
-static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
-					    struct wpa_ssid *ssid,
-					    struct wpa_scan_res *bss)
-{
-	return 0;
-}
-
-static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
-					    struct wpa_bss *selected,
-					    struct wpa_ssid *ssid)
-{
-	return 0;
-}
-
-static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-#endif /* CONFIG_WPS */
-
-#endif /* WPS_SUPPLICANT_H */

Copied: vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h (from rev 9639, vendor/wpa/dist/wpa_supplicant/wps_supplicant.h)
===================================================================
--- vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h	                        (rev 0)
+++ vendor/wpa/2.0/wpa_supplicant/wps_supplicant.h	2017-10-22 18:12:33 UTC (rev 9640)
@@ -0,0 +1,142 @@
+/*
+ * wpa_supplicant / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_SUPPLICANT_H
+#define WPS_SUPPLICANT_H
+
+struct wpa_scan_results;
+
+#ifdef CONFIG_WPS
+
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+
+struct wpa_bss;
+
+struct wps_new_ap_settings {
+	const char *ssid_hex;
+	const char *auth;
+	const char *encr;
+	const char *key_hex;
+};
+
+int wpas_wps_init(struct wpa_supplicant *wpa_s);
+void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
+int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       int p2p_group);
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, int p2p_group, u16 dev_pw_id);
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
+int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, struct wps_new_ap_settings *settings);
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+			    struct wpa_ssid *ssid, struct wpa_bss *bss);
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, struct wpa_bss *bss);
+int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *selected, struct wpa_ssid *ssid);
+void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
+int wpas_wps_searching(struct wpa_supplicant *wpa_s);
+int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
+			      char *end);
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
+int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+			const char *uuid, const char *pin);
+int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
+int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
+		      const char *pin);
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+			   int id);
+int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
+		       const char *pin, struct wps_new_ap_settings *settings);
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+					     int ndef, const char *uuid);
+int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
+int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+			  const struct wpabuf *data);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
+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);
+
+#else /* CONFIG_WPS */
+
+static inline int wpas_wps_init(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid,
+					  struct wpa_bss *bss)
+{
+	return -1;
+}
+
+static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+					    struct wpa_ssid *ssid,
+					    struct wpa_bss *bss)
+{
+	return 0;
+}
+
+static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+					    struct wpa_bss *selected,
+					    struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+					   struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid)
+{
+}
+
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_SUPPLICANT_H */



More information about the Midnightbsd-cvs mailing list